[or-cvs] r10687: finished documentation for impl classes, unified rest of doc (in puppetor/trunk: doc src/de/uniba/wiai/lspi/puppetor src/de/uniba/wiai/lspi/puppetor/examples src/de/uniba/wiai/lspi/puppetor/impl)
kloesing at seul.org
kloesing at seul.org
Wed Jun 27 22:09:48 UTC 2007
Author: kloesing
Date: 2007-06-27 18:09:47 -0400 (Wed, 27 Jun 2007)
New Revision: 10687
Modified:
puppetor/trunk/doc/howto.aux
puppetor/trunk/doc/howto.pdf
puppetor/trunk/doc/howto.tex
puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/ClientApplication.java
puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/DirectoryNode.java
puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/Event.java
puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/EventManager.java
puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/Network.java
puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/NetworkFactory.java
puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/NetworkState.java
puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/NodeState.java
puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/ProxyNode.java
puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/RouterNode.java
puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/ServerApplication.java
puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/TorProcessException.java
puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/examples/AccessingPublicWebServerOverTor.java
puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/examples/AdvertisingAndAccessingHiddenServiceOverPrivateTorNetwork.java
puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/examples/AdvertisingAndAccessingHiddenServiceOverPublicTorNetwork.java
puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/examples/AdvertisingHiddenServiceToPublicTorNetwork.java
puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/impl/ClientApplicationImpl.java
puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/impl/DirectoryNodeImpl.java
puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/impl/EventManagerImpl.java
puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/impl/NetworkImpl.java
puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/impl/ProxyNodeImpl.java
puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/impl/RouterNodeImpl.java
puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/impl/ServerApplicationImpl.java
Log:
finished documentation for impl classes, unified rest of documentation, fine-tuned howto
Modified: puppetor/trunk/doc/howto.aux
===================================================================
--- puppetor/trunk/doc/howto.aux 2007-06-27 20:52:42 UTC (rev 10686)
+++ puppetor/trunk/doc/howto.aux 2007-06-27 22:09:47 UTC (rev 10687)
@@ -1,8 +1,9 @@
-\relax
-\@writefile{toc}{\contentsline {section}{\numberline {1}Introduction}{1}}
-\@writefile{toc}{\contentsline {section}{\numberline {2}Installation}{2}}
-\@writefile{toc}{\contentsline {section}{\numberline {3}Example 1: Accessing public Web server over Tor}{3}}
-\@writefile{toc}{\contentsline {section}{\numberline {4}Example 2: Advertising hidden service to public Tor network}{5}}
-\@writefile{toc}{\contentsline {section}{\numberline {5}Example 3: Advertising and accessing hidden service over public Tor network}{6}}
-\@writefile{toc}{\contentsline {section}{\numberline {6}Example 4: Advertising and accessing hidden service over private Tor network}{7}}
-\@writefile{toc}{\contentsline {section}{\numberline {7}Known issues}{9}}
+\relax
+\@writefile{toc}{\contentsline {section}{\numberline {1}Introduction}{1}}
+\@writefile{toc}{\contentsline {section}{\numberline {2}Installation}{2}}
+\@writefile{toc}{\contentsline {section}{\numberline {3}Example 1: Accessing public Web server over Tor}{3}}
+\@writefile{toc}{\contentsline {section}{\numberline {4}Example 2: Advertising hidden service to public Tor network}{5}}
+\@writefile{toc}{\contentsline {section}{\numberline {5}Example 3: Advertising and accessing hidden service over public Tor network}{6}}
+\@writefile{toc}{\contentsline {section}{\numberline {6}Example 4: Advertising and accessing hidden service over private Tor network}{8}}
+\@writefile{toc}{\contentsline {section}{\numberline {7}Architecture}{10}}
+\@writefile{toc}{\contentsline {section}{\numberline {8}Known issues}{10}}
Modified: puppetor/trunk/doc/howto.pdf
===================================================================
--- puppetor/trunk/doc/howto.pdf 2007-06-27 20:52:42 UTC (rev 10686)
+++ puppetor/trunk/doc/howto.pdf 2007-06-27 22:09:47 UTC (rev 10687)
@@ -1,1423 +1,1260 @@
-%PDF-1.2
-9 0 obj
-<<
-/Type/Font
-/Subtype/Type1
-/Name/F1
-/FontDescriptor 8 0 R
-/BaseFont/XEEAJR+CMR17
-/FirstChar 33
-/LastChar 196
-/Widths[249.6 458.6 772.1 458.6 772.1 719.8 249.6 354.1 354.1 458.6 719.8 249.6 301.9
-249.6 458.6 458.6 458.6 458.6 458.6 458.6 458.6 458.6 458.6 458.6 458.6 249.6 249.6
-249.6 719.8 432.5 432.5 719.8 693.3 654.3 667.6 706.6 628.2 602.1 726.3 693.3 327.6
-471.5 719.4 576 850 693.3 719.8 628.2 719.8 680.5 510.9 667.6 693.3 693.3 954.5 693.3
-693.3 563.1 249.6 458.6 249.6 458.6 249.6 249.6 458.6 510.9 406.4 510.9 406.4 275.8
-458.6 510.9 249.6 275.8 484.7 249.6 772.1 510.9 458.6 510.9 484.7 354.1 359.4 354.1
-510.9 484.7 667.6 484.7 484.7 406.4 458.6 917.2 458.6 458.6 458.6 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 0 576 772.1 719.8 641.1 615.3 693.3
-667.6 719.8 667.6 719.8 0 0 667.6 525.4 499.3 499.3 748.9 748.9 249.6 275.8 458.6
-458.6 458.6 458.6 458.6 693.3 406.4 458.6 667.6 719.8 458.6 837.2 941.7 719.8 249.6
-458.6]
+%PDF-1.4
+3 0 obj <<
+/Length 2577
+/Filter /FlateDecode
>>
+stream
+xÚÉrëÆñ®¯ÀÍ``»Oy.ÇuH9eåäø+u^¥¡.´÷ºýÍÿe>6Î|óºÉ¿ß(Øüþúâã8Ò^ UXª¼ ð/+¯ËÏßy ¤ÐQ)ÊsI?9ê§Q¨{YXæ K at Jÿ8O½8ÌTËñ7¤óPxÁ
+ªQó9¨>/ ÐÙê«:Ð>q³ÞygC5-`U@
+Úfª&#¤§áA-WVþ"ìg¢<5°Ûßïø+¢'Ø=Ñ)QªZ6Ò4%&9¨ÁZÜËJ*Ð+i¾KÂu$æó-
+ñáÔïZ7îewâ#ë3hÂpÃyc-·)"B#î+§ïÞzs9.Æ
_2Ö~[ÒüA0âåR4zsæýº4gµÚÉY¿ë'y\mIC\ÑyàØÇ+¨?cÞ¾EÛ7hàÉyûóJ¸è¤
ïÕ8Ó(Öh¥¿ÄêUZ¾bHYj#¦3VµM´wtߨ¡}ÓUKîx¶°BÅÑÊ;2Yü1¢íQ}®L'ã¹ÛØ2èt
+{øÙP"C ¹Ffev{LªðB®(ÎÝóⲧõµ-lC6 ñQ¼â8rq
+J!þ¶Ä
+á´°×P#K`\@q¨ ṟ²®(¹:L ÃØÏѽoÛµ@îø$ £ÚºUðoC<¤ØP©ce
+}wÄ=*´Ô^6ÖàxUVsaEgu³8¬Í4Û<J
+·a
ÝÏCcµODÍ(uDe;`Ö¶ì»(çÑìfÁ÷óug9:p7m{]ô_(C~4Û¸Q8q1ÐkBáÜÕ·*¸Úó#ë±°Á ¶«V endobj
-12 0 obj
-<<
-/Type/Font
-/Subtype/Type1
-/Name/F2
-/FontDescriptor 11 0 R
-/BaseFont/NJEYML+CMR12
-/FirstChar 33
-/LastChar 196
-/Widths[272 489.6 816 489.6 816 761.6 272 380.8 380.8 489.6 761.6 272 326.4 272 489.6
-489.6 489.6 489.6 489.6 489.6 489.6 489.6 489.6 489.6 489.6 272 272 272 761.6 462.4
-462.4 761.6 734 693.4 707.2 747.8 666.2 639 768.3 734 353.2 503 761.2 611.8 897.2
-734 761.6 666.2 761.6 720.6 544 707.2 734 734 1006 734 734 598.4 272 489.6 272 489.6
-272 272 489.6 544 435.2 544 435.2 299.2 489.6 544 272 299.2 516.8 272 816 544 489.6
-544 516.8 380.8 386.2 380.8 544 516.8 707.2 516.8 516.8 435.2 489.6 979.2 489.6 489.6
-489.6 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 0 611.8 816
-761.6 679.6 652.8 734 707.2 761.6 707.2 761.6 0 0 707.2 571.2 544 544 816 816 272
-299.2 489.6 489.6 489.6 489.6 489.6 734 435.2 489.6 707.2 761.6 489.6 883.8 992.6
-761.6 272 489.6]
+2 0 obj <<
+/Type /Page
+/Contents 3 0 R
+/Resources 1 0 R
+/MediaBox [0 0 595.2756 841.8898]
+/Parent 25 0 R
+>> endobj
+1 0 obj <<
+/Font << /F15 6 0 R /F16 9 0 R /F26 12 0 R /F8 15 0 R /F7 18 0 R /F18 21 0 R /F17 24 0 R >>
+/ProcSet [ /PDF /Text ]
+>> endobj
+28 0 obj <<
+/Length 2399
+/Filter /FlateDecode
>>
+stream
+xÚÅYIÛº¾ûW̪²h®åÛ¼]w]±ªR©$$d(áâñ¼_Þ+"
+L¿Ù¦Å>hÕ¸Iàeìq-q½Ê¶fÊÀ(¦jän³RµÙÆM+[T¸¢æFÛå0õ-Þ1Õ³mÅÁÄÕ×0,ìI½Abï?c
Â]7ÿ9þþ=lã8<äyBª3¥i0½fWä;¡Pu¯êIaø¯f²àL9^¨&®ÝI÷p9¹üØ£
¦~PQÜ°ß°{Ð ë`Ò誵¸^+b]õú4³ffrkùô2`Û:=Àa`.;/Zôy¶¾j¹ï¾dOlY8YzXZóífúçüçÁoÂ/ÉrVùáäÌÁU¤(
ÁÐ¥nq!JÄÐÏM£Í0Sy!qÞàÍ?7Ô½ôõÐí
ç¯|tYõßQ]&Òì¼$i¬eÅßì|{d4ï±ØÃgb'a¼ßåKÄ`©<'´Rþc¬®½ëp¯V³~(é÷½ì£=.jË &¨+2´ÈEÆÿ¼4²`hI9<K:ä¡!ñÐFñgòøÀÓÒiÄyO¬eaÜ* "aëúÖ5Ë4JÛäÅW´¦¤Gj¡ÿ Ô6¢¥É)ÀqNÅKg¸£`¸! «ÅÑwá nÈ@òÔ~O³qâü®ùÈÉjãù)Êb=è³FR*ÉÃÛlWGHji³ìùJ¦Z®-YK¶Ø=8ÚðòX·gá#·ªl?bxí1v9pÃßíL¦U<!äº8F¾¢>r¶QeÍt$)p©a¥1xä³ç÷Ñ+¯sM¥«Õ_Cc.<X>3Ù4#Þ»íûáBÙ·È:éaçëAÉ@åm2%R8DÐ p¾ë^õT)YÒ£8c²ï¹óÂò4Jê3b0¼GµD9ò!ôî°¿YÐ^®üAC&;âixèj 8Ë]`ý¿~3,¸$« L_Ï7E-¤Ï,tOUN=Z+ áÖ±pö¼¹R2P¿ÑCqÑ}G`ÂN¿³áÀd×ràWª¤P$«ÒÓï£ÔÇ7²B7hél÷ÚÅ+äÆÿ#b@õ~IH:Ô]¶ir^RýO]ÍÉ9- `y_ÓoP6ReÅiÌ6a®depÔ/_Iå&æALDÊð/UA<£FÊâìm¶gPÑ«¹á¶Ô
&VW÷<*ÛÃ$EærWYðtæC¡Iö«ÛdÏÈLR"}Ù2iÙªoùöÌËEñ3ËIÜÕ³¸ÕªÛ]<sK¹ÒÌF1º¸g!Ëä
ÎYظ(©ùYÏÙçü}k
+.ád_L#ç2.[Ká7q5½ñ\7y7ÃH5ÌäìJU¥I<xlQÑ+Iôì{UMciÃHѸo£daIÏ+V1ìÕ2yãB¶¿ÃÊy¡ä#v+iÚWüʹÅØö`N5àÐZPÖ²^<
ê*^úä4F?¸ÞÆÙÉoÄQȹ鰤~-4¿ÝøqÂÜTaÌïÉjÒ}<~F*Þh+òýzx1ßÓ<Á^s ÐiQâööÒ<
HᮦsÅ/,JC¤¦I©/¢ãgn*ø;iyaÊÊÜnË°hÛ÷«3¿<Nô$â¨Öôi´A¡§ÜÂè>îøË,K4î¾¾!\-®u¨Ç
+ú
+õOJñkmvÃid°OO ·Kª5aôàv×TãÇtïõ÷a¤9\÷á' Ææík
+h{!Ä~ºaøðÍ'º|æ˽ endobj
-15 0 obj
-<<
-/Type/Font
-/Subtype/Type1
-/Name/F3
-/FontDescriptor 14 0 R
-/BaseFont/SFIZFA+CMBX12
-/FirstChar 33
-/LastChar 196
-/Widths[342.6 581 937.5 562.5 937.5 875 312.5 437.5 437.5 562.5 875 312.5 375 312.5
-562.5 562.5 562.5 562.5 562.5 562.5 562.5 562.5 562.5 562.5 562.5 312.5 312.5 342.6
-875 531.3 531.3 875 849.5 799.8 812.5 862.3 738.4 707.2 884.3 879.6 419 581 880.8
-675.9 1067.1 879.6 844.9 768.5 844.9 839.1 625 782.4 864.6 849.5 1162 849.5 849.5
-687.5 312.5 581 312.5 562.5 312.5 312.5 546.9 625 500 625 513.3 343.8 562.5 625 312.5
-343.8 593.8 312.5 937.5 625 562.5 625 593.8 459.5 443.8 437.5 625 593.8 812.5 593.8
-593.8 500 562.5 1125 562.5 562.5 562.5 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 0 675.9 937.5 875 787 750 879.6 812.5 875 812.5 875 0 0 812.5
-656.3 625 625 937.5 937.5 312.5 343.8 562.5 562.5 562.5 562.5 562.5 849.5 500 574.1
-812.5 875 562.5 1018.5 1143.5 875 312.5 562.5]
+27 0 obj <<
+/Type /Page
+/Contents 28 0 R
+/Resources 26 0 R
+/MediaBox [0 0 595.2756 841.8898]
+/Parent 25 0 R
+>> endobj
+26 0 obj <<
+/Font << /F8 15 0 R /F26 12 0 R /F27 31 0 R >>
+/ProcSet [ /PDF /Text ]
+>> endobj
+34 0 obj <<
+/Length 2593
+/Filter /FlateDecode
>>
+stream
+xÚYKÛ8¾÷¯0ú²2ÐVDJ²¤,öÐ3Hf²H/ö0,Ñ6·eÉä~üû)Ùí6v,ɪ¯^ênÞ}ÔÙ¢µ^/¶&á:/²Ee¡Ò©Z<Ô÷õéG;ØvwßÖ÷Ue¤?Ùº6íÓ?ÙÊü,OÆV]ÿ»þqùçÃ/ÂB«x±R*,ÒTÈÿOårê4XUG&6¶}ïÆ®¯ÆæhûÅn¾PmÂSk7eølK6ÃÑÇÓñh`oh^Êñ1CHÛ£ócÿïôö©ÍùS at Wë
JÂ8YkTÖô²X.ÖtD¼á9à7 » a«8Nõ~¹Jò(ð'óô\¶âñE[T°Á$L£§e¬y¾gÆnÓ,гºPG
Wgaë®ô°,â ëù
+ùÌÜ+Ï®UÅì{¼St+3<ñ¼ÔYP.u¼âÆNKî0~Xæt"1Ù'sÙw×CwW¥ AøKþ9¢p+§<ï9þÒä2¤oXamÁæG)æ:6e%ë[Î+ï1·ï¯¼]>,é³RBoçð0|,+ÈÕ¯aÕH³2ù5J£[IßêFêïoUFK.Ne¿1Lª
f05ãgFÉ:a=÷Î+à>²¼6û|Ä[ïJ`?Cj~ºw4SDN),cEpÜâTàÉÕÜÏ-97Qo¾ÌaQ£qp8XG¥<@èhiZx] ݲmO§6ÂÞ@1-/Q¢¹yØ¡I`àËóìI®QÊoÅ Cvãî,¬Î22»ËkVÚðجä÷<2 )]Í*+x¸ü)n]18?ëйrZÀÇÞ}ÿîa À,aàó½%¯ÕkÄ0Ï^äpÏ°(Âß°IDËux?>Cëâ"2JE°»Äx길E.9~§¸Ê6øxIt·p¡'óTÒоz]I¦]êAxÿ®³W«B`ý+Ç|
+n%jK!´Æ^7\sÕz
+R×=÷s×n-·`!ÔûÄ~óPH»ô pîÂÆ8EÅq.ÖCâz)dÅ\t2®Þ/½'äk/xª·"¸!µ%¾t{â<²7O¶s!0u¥<vãW¦¾F%H
+v#q·SàdûwîÖ©æ[ïæ{,yv¼X[*)óì¼J
à»kÞr´Kg¶75æ²BSPGËBñ<Ⱥ3³Íq+UÙ² mi¡(Ì+© Gäi0¢q®ý8r͹5ܧK¹Ê²,cfVhpö4ëÁ_§Â2=,I ²ö( ¨ZÖK^-OÂÆÈsVv\Õ@Fgcum-ÁElÇYVÆPaVxí½ù>×â8)\Õ£Ò)ݹªfÖ¨Â4¥løÅ¥ÈÚIOÖv)xZ×ÀÈ+¿ÍnýFhNpo+y|4zË¥ç©
+®ybÔGoªpYß{Á"A3ú&.}-ÿ¨ÉÀ¥DÖÙ÷ nGùuöÉéüLìî\A;ºü½-*Õx7ã*i%9l&½OÎÌ]ë¾b½5\ß|x¸Qð h¡*Ãl'åa\dù¢:Ü|»ùãÏhQßD_n"
jÿQ¨B/7
+z$×±in¾ÜüË\y«¹Ððÿ<*_¤aeÎ0_Gx6i6&UÙ"ÎHÑ'ªPÞW:Ìü7áÃÓ,f¸òKÈ`\SÉú¸4ð*&.
+pWËCN)¦4¶9aoåòdõ>:p¹¡¡TPg¤øÁ3͸Cë¿ÚñÔÚªôY?Mä3u¿tðJ¾KáátÙ#Ìó¬ÿí
+ÿûOÒÐendstream
endobj
-18 0 obj
-<<
-/Type/Font
-/Subtype/Type1
-/Name/F4
-/FontDescriptor 17 0 R
-/BaseFont/XCHVXE+CMR10
-/FirstChar 33
-/LastChar 196
-/Widths[277.8 500 833.3 500 833.3 777.8 277.8 388.9 388.9 500 777.8 277.8 333.3 277.8
-500 500 500 500 500 500 500 500 500 500 500 277.8 277.8 277.8 777.8 472.2 472.2 777.8
-750 708.3 722.2 763.9 680.6 652.8 784.7 750 361.1 513.9 777.8 625 916.7 750 777.8
-680.6 777.8 736.1 555.6 722.2 750 750 1027.8 750 750 611.1 277.8 500 277.8 500 277.8
-277.8 500 555.6 444.4 555.6 444.4 305.6 500 555.6 277.8 305.6 527.8 277.8 833.3 555.6
-500 555.6 527.8 391.7 394.4 388.9 555.6 527.8 722.2 527.8 527.8 444.4 500 1000 500
-500 500 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 0 625 833.3
-777.8 694.4 666.7 750 722.2 777.8 722.2 777.8 0 0 722.2 583.3 555.6 555.6 833.3 833.3
-277.8 305.6 500 500 500 500 500 750 444.4 500 722.2 777.8 500 902.8 1013.9 777.8
-277.8 500]
+33 0 obj <<
+/Type /Page
+/Contents 34 0 R
+/Resources 32 0 R
+/MediaBox [0 0 595.2756 841.8898]
+/Parent 25 0 R
+>> endobj
+32 0 obj <<
+/Font << /F27 31 0 R /F26 12 0 R /F8 15 0 R /F14 37 0 R /F7 18 0 R /F18 21 0 R /F17 24 0 R >>
+/ProcSet [ /PDF /Text ]
+>> endobj
+40 0 obj <<
+/Length 2497
+/Filter /FlateDecode
>>
-endobj
-21 0 obj
-<<
-/Type/Font
-/Subtype/Type1
-/Name/F5
-/FontDescriptor 20 0 R
-/BaseFont/GCOOBE+CMR7
-/FirstChar 33
-/LastChar 196
-/Widths[323.4 569.4 938.5 569.4 938.5 877 323.4 446.4 446.4 569.4 877 323.4 384.9
-323.4 569.4 569.4 569.4 569.4 569.4 569.4 569.4 569.4 569.4 569.4 569.4 323.4 323.4
-323.4 877 538.7 538.7 877 843.3 798.6 815.5 860.1 767.9 737.1 883.9 843.3 412.7 583.3
-874 706.4 1027.8 843.3 877 767.9 877 829.4 631 815.5 843.3 843.3 1150.8 843.3 843.3
-692.5 323.4 569.4 323.4 569.4 323.4 323.4 569.4 631 507.9 631 507.9 354.2 569.4 631
-323.4 354.2 600.2 323.4 938.5 631 569.4 631 600.2 446.4 452.6 446.4 631 600.2 815.5
-600.2 600.2 507.9 569.4 1138.9 569.4 569.4 569.4 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 0 706.4 938.5 877 781.8 754 843.3 815.5 877 815.5
-877 0 0 815.5 677.6 646.8 646.8 970.2 970.2 323.4 354.2 569.4 569.4 569.4 569.4 569.4
-843.3 507.9 569.4 815.5 877 569.4 1013.9 1136.9 877 323.4 569.4]
->>
-endobj
-24 0 obj
-<<
-/Type/Font
-/Subtype/Type1
-/Name/F6
-/FontDescriptor 23 0 R
-/BaseFont/DMIVYN+CMR6
-/FirstChar 33
-/LastChar 196
-/Widths[351.8 611.1 1000 611.1 1000 935.2 351.8 481.5 481.5 611.1 935.2 351.8 416.7
-351.8 611.1 611.1 611.1 611.1 611.1 611.1 611.1 611.1 611.1 611.1 611.1 351.8 351.8
-351.8 935.2 578.7 578.7 935.2 896.3 850.9 870.4 915.7 818.5 786.1 941.7 896.3 442.6
-624.1 928.7 753.7 1090.7 896.3 935.2 818.5 935.2 883.3 675.9 870.4 896.3 896.3 1220.4
-896.3 896.3 740.7 351.8 611.1 351.8 611.1 351.8 351.8 611.1 675.9 546.3 675.9 546.3
-384.3 611.1 675.9 351.8 384.3 643.5 351.8 1000 675.9 611.1 675.9 643.5 481.5 488
-481.5 675.9 643.5 870.4 643.5 643.5 546.3 611.1 1222.2 611.1 611.1 611.1 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 0 753.7 1000 935.2 831.5
-805.5 896.3 870.4 935.2 870.4 935.2 0 0 870.4 736.1 703.7 703.7 1055.5 1055.5 351.8
-384.3 611.1 611.1 611.1 611.1 611.1 896.3 546.3 611.1 870.4 935.2 611.1 1077.8 1207.4
-935.2 351.8 611.1]
->>
-endobj
-27 0 obj
-<<
-/Type/Font
-/Subtype/Type1
-/Name/F7
-/FontDescriptor 26 0 R
-/BaseFont/MAMUVX+CMR8
-/FirstChar 33
-/LastChar 196
-/Widths[295.1 531.3 885.4 531.3 885.4 826.4 295.1 413.2 413.2 531.3 826.4 295.1 354.2
-295.1 531.3 531.3 531.3 531.3 531.3 531.3 531.3 531.3 531.3 531.3 531.3 295.1 295.1
-295.1 826.4 501.7 501.7 826.4 795.8 752.1 767.4 811.1 722.6 693.1 833.5 795.8 382.6
-545.5 825.4 663.6 972.9 795.8 826.4 722.6 826.4 781.6 590.3 767.4 795.8 795.8 1091
-795.8 795.8 649.3 295.1 531.3 295.1 531.3 295.1 295.1 531.3 590.3 472.2 590.3 472.2
-324.7 531.3 590.3 295.1 324.7 560.8 295.1 885.4 590.3 531.3 590.3 560.8 414.1 419.1
-413.2 590.3 560.8 767.4 560.8 560.8 472.2 531.3 1062.5 531.3 531.3 531.3 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 0 663.6 885.4 826.4 736.8
-708.3 795.8 767.4 826.4 767.4 826.4 0 0 767.4 619.8 590.3 590.3 885.4 885.4 295.1
-324.7 531.3 531.3 531.3 531.3 531.3 795.8 472.2 531.3 767.4 826.4 531.3 958.7 1076.8
-826.4 295.1 531.3]
->>
-endobj
-29 0 obj
-<<
-/Filter[/FlateDecode]
-/Length 2118
->>
stream
-xÚXK㶾çWðfªj%-ºí|Ëô¸&¿u'äZz7Ëy
QE¹>îßMÌþóÒµÙ>|2eÝêZ(Bêö|ÞyêÂ4ûAõ#=uÃá¯ÓW5øn2¥ÊaU¹e¹Ï¡ëáÇØ'T©É²ï³ÎÍù>[¨¢J¶¹Q|Þlµ}6V§s+áÛ.»¹Þ'jJÜvµYµB£ÖFúáSª©;·ÊÚĪÒÈMw§UJd{]ï&Ô¶L~*rB
N(R¦ûàNþ©cø̤ùèfYt»®ïf7û÷ÏGÏÝ8üaê°G:qÜ¿¹lòó^¥dú:ݹC¥ÈT^ùØq -èl)xèÝOÝ2º¡ÅA- ¾úÝ""¹
-y<h;óÄ;%ôY6Áa÷öRµÙæY>)ÈÐS7Y»aCÃÄalÁ·`Ä¿'÷ù¼¬ÎLõnê|àñ~Aë¿k?JwųÜàúË<O$>¾ÛÙÁY ¼5¼tspáò¨Æ?ìyE=(l¡ïfHÌ3LX4»-4Iß(°/Ä£g6!QúÝ<1}ßݼytÃÁO|x<E6ê¨\=.a''îF²DëÕ£Üdjä8ü
>±uÃ-<À=³yCwòì÷WvnXKVd/ì>à°yÚ,ù¿nàexî_ܼÃ+85Ób-vbèØÄZ±Z)ÒXC ¼7ø/\q}Þ!QhÉVÅæÍce,êZlGNãã)Ö:$Bxâh-©Ô
¸Óe`XãÐQ¢@"./´ñè·""é*ý/£þé[ÏíÛ@0Gno).Ü÷J ]»#§@ëo_µJ¸Â%¦Ô{ÐÂ02ö½@ç*+n at bïÐVihÉ55ÊÔê¤.º8¸ùzäÚG˹㠩Ëëúzìn5ÓJIÃÑ]ICma@YÜ/ý÷=FUÐÎk^ºlw¨1ßëÐlVPðs¦æf¾Ó/ɤ}ÆÕu§Ì{Ù,Î!«¦ÕÁ×3®}rsÄ>IöMcÖ$ðØÛäݹ1Ôbueí!MZÉ
-ÛW/ìzOk#tÔ×$ÃÉ%äÆOÔsõÿÕ>qPL#·OÜáP- 1ù/Ù-endstream
+xÚÙrÛFò]_ÁòX%1®låÁãØEoj+ÉDB$V @ iÕÖþ{ú²´ëA3£»§ïn¾=£¢I"P
ùíDj-¢06ÈTÌ¿{eÖªúN¬÷ÛOe¶øOg
+<éÃ,ÈLÿ¿}þ&îÂ3"1:Ìb÷¾ªØ;LgZ¯ÚO¥Wã\{ói¬½Ê~+omWÄàæ¸ (ñM³ü4Ê¢bÒÓ¼d*¼EЩ
¯M¬Ák¯ðÍÍí¶ÈiÐ)Ð$ö¢Hé9!ôë|x×ü¹HKì´np+*¥GfcÊzKªo´WT«Uª£!~ìkKÆ<Ç8ñxêUæ¥
+H±-ûþ$vÀXT$ê?I-èîíÍõW?_3,H²ñU·ý7±â£9wÿ-õû>b¨¦äkÈbÿÈsNж&ã{èñÙgçDòE¢¤î3üÙáp«ªZXfϬ?};|_=à×fH¢Èôi~IÂaÕ&U0¬Ú
+'Ä-2×o3gr(¼u Umç$xv5»`ï¬æE&
çÙÝßñúWªMª[Rë#<çRÖ;8ö¡#oçg:4i=á]´ü@÷|0µëìó>cE/B<Í©Ï K]¬Â·vÙ6Ax\C¯ ÷GTö&%w·ª)6hZçè½Á¢1x ÿÐÿ¼´(8¡÷5'ë®,V1jQm¶EöwS´PiøO|ÍÆGö2
+Óhíuâ+Þw1ºÑ$BJ-»/®®Þ]¾z1¿üðo]ÌÏð? I%21p2qÅæìóÙïúå?y{æÄÁä+È 3ÎòÙÅP>ùÈ®½ý&
VêèHa¾dg@Ë+*Ù4¼=6°W[ÁVnGXl®+ªqoy¥Mé&÷¶7OÈû²lü8÷ºzþÀgz×0ÔQ£ÿòðü9Büï©Ù°-½UØjÁäb¡QT*â:»
¬£\düY<ZSñ||¿×ô_Ò2]¥
+a$|?íÙNý(È4)Å+PHbUÁÛéî¾äj¦t"p'ù/ç¨
¨ÕÞ¶&FÓm=L·µ9ê0~Pbզױõf.æá©jãøCRÜt?N
+©UÖt/8µxjwÇÈÆÖ¥0ÑmçD¶+Àmó×\r=FÉ°9rçcÖ
+Ëíkð{RàZ=Æòn£çë+¼ÿdX>ADðùöü-îÝR,È穹 U¢ÛSÁ÷kb×èôµp<Nj¦Ð¡Êæ-F~Ú6¸Â¶fÖv`òvß
+´;/yäjh9È©ÝOV½ZYsÍæÅ¿Øt|rÄni|ÆYâ´ìTé]a
+ðrk[´Ú9vV,¹óô®¹SººU©C±¢M"F$PÃkP`T>ì
+(ª1Ø(H[ß5Ô¶§îupñKlb5/uªp²[ÞbÉ7.¡À½ôƵ2»îÆÂæζlØL+¬JÇMcZÅÀC»ý«F[ó´=_4"ÝÙcXìo2W($â
+M½ÏÄ1ÒØ3hmbØY"L=c{[²¤ÍGf©A+lÛ9âÿ?¬ùµUpêõU®çw\ÃèÄÁ¬}`c`ÜÇn´6!« »\çbrTwÒ6nH¼pÞÑ}¥&m¾Èâ·ÈÒü~»:>¾@'=¹[Ûn-Ge8]×.dKô*a§%ë¥%crù5ÂlkqÄÞóîTªîøÞHùìhÝ®6Ç59ûL n(ÈA$`
¥5²¾ÔÀôȶeÉ|ï,[d§Ò®u$¼õDï¤é%·grNlðPÊÛX
+ mÁÚ(é¶ÔÐÀi^<^@þRê(¥t§èP\tD½yêÐÓÅÇV)À[HÈOî9ÈçE³½7LAF ~
c¨\^k¨ý(#
úæï®â¬r¤tÕhn¡<bî´®%v$ïH§ø±´út^]||óáã/c56zÅáIÛ>w?ÿ}[)@ôëîo£ !%r&Bccb?$¬Æ1ò/Õç-endstream
endobj
-31 0 obj
-<<
-/F1 9 0 R
-/F2 12 0 R
-/F3 15 0 R
-/F4 18 0 R
-/F5 21 0 R
-/F6 24 0 R
-/F7 27 0 R
+39 0 obj <<
+/Type /Page
+/Contents 40 0 R
+/Resources 38 0 R
+/MediaBox [0 0 595.2756 841.8898]
+/Parent 25 0 R
+>> endobj
+38 0 obj <<
+/Font << /F27 31 0 R /F8 15 0 R >>
+/ProcSet [ /PDF /Text ]
+>> endobj
+43 0 obj <<
+/Length 2117
+/Filter /FlateDecode
>>
-endobj
-6 0 obj
-<<
-/ProcSet[/PDF/Text/ImageC]
-/Font 31 0 R
->>
-endobj
-36 0 obj
-<<
-/Type/Font
-/Subtype/Type1
-/Name/F8
-/FontDescriptor 35 0 R
-/BaseFont/PQEIII+CMTT10
-/FirstChar 33
-/LastChar 196
-/Widths[525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525
-525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525
-525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525
-525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525
-525 525 525 525 525 525 525 525 525 525 525 525 525 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 0 525 525 525 525 525 525 525 525 525 525 0 0 525
-525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525
-525 525]
->>
-endobj
-37 0 obj
-<<
-/Filter[/FlateDecode]
-/Length 2329
->>
stream
-xÚÍXKã6¾ï¯ÐQÚD½s :ÉÌîØd°c`¤÷ K´ÍmYòêÑίO½(ÉîÎ1ÀQÅb±XõÕòÞÑ£×ß½ïwß|½B©·;xyªÒÄÛ¦Ze·ûñ7·É#¿ë7Û(ÏüÖù×ÎöÌIJqûU×ÖS52õ²Ùé].ÛÊ0ËÙÃÔ³iQÎ8<l¶qøçr£SÿukR_XmËïåí˱B¦Óæ?»¼ÀÛ¡*XÅî- >Êgr
-0Î4B
L,Ü¡@Áu¿íùÒÌYe¯m
§¾kíïλ ×"±».±ù¾ÄnqèjúÓªÞÙkþØ;½a¼¤Dø@¢Y+34÷w})0;Âa'Vüj»v»Ø8Ödcáàx>UÙ> <°3MÙc8¨»Öà(A\öpæÚ§%¹ß²f^R
-×-A`ö,>X§çh%ÌRÿÃ|ätO?gtNHö¦±²#áÓÉ)Ò$ué#¥ôCßy4³§D@ɯiL%pnÁÙôGYÒtGHD´)vTü.Û÷A
-ÆÃó/*RXswèa.ÐúH
qª,!<_gXÊÊåN9Ú,
ʬã©y´aÒÊz¶ÇCäMnèÖb(ØR#}jSöÆ9Ð;Ð
-
-À䮯É!+Qùöð*kK(ð² 6-°UÖüiïíѶdgq2Å)9þ¦z"X¨zâÜeÖag°GÆ÷
-ë>)æ«+MÐrÆÉHr.}¿äl]ÓPïÓ¿ØJsùGº÷-)¿Ú"ðè8{LãB{üü
\OýÍt¨ÃoÍÌØé¸Wñ%NÜÚteÍ%P»¢ÅK}û2ífÔºJ»¨ÓÖ5tKuW Þà6tä/UEæĨÄTÚñ½? p´D%Ã#$¦¤r~£"rpbÎøKdCKB÷$°3µïâ;ß-Ëfî=c·Ú÷³#¶q¦%
ÇÙ]Ï$ÁFLQÿ¼á+'ñjÊt.w1e
-~SÖç)áiA,.M§X%Àn-Q¨<Y] £²!ö4ÐDÄþ8$Z¢ã/¹ß®PÜÁæùè·©ÇÄ)-×G©vÅ>8ߥ¸Ó9q"¥ä×m8"å_Ôò³p~hùzÀª1uðÅÉíµÿí µtÅ¢TdêÛ(Z²0ܹäp·-÷h¿'¹ãK,Ê6éÇ»ð6_K¼Ø·×6,ªæÝ+sÓpênYC6?ñÆ·÷ÐqÁ 1
-þ[¾iÈ¿Ûê½eS¡×ç©Z»/ÕÕV5ÃŪäbÃ(f½Õc
%¨òyÚCaú·ÙRnú_àÙ¹e%ú¯R£ýFüº¡/ÜPì:ÖTùÙW÷{¿\#¨³n´C#ýßëQ¸ÝÝ)øaç*ö®^âÁmBávö¢PÚ}6Þúz*rd¦UãtAÁRk2/ì«äiWý7º k&\=8ùÃàÜ-Á¯WkëºR.ßŪ|Ë7èg¬m3A~à?X¢¡_Ã+¼¢Ù÷D×åB®Ë0IÕbæß8ªP9ê©JÒ1^3âT9·¢¬9wÃtÃ!k¯4Ï0ÈIµÚPZÐ=LÏ
I»:¤Wõ|°ºæÕÔ.eòWý$²ü
-[ÄÀSß/fÎôʺðqg]é}æÎê*®¾ÿ,QÐëÒAw¦h¹$1[5w3 õ0±6+Í=QÇùÝÓFJ|Ç|,x±*2ß[iäÇÃ}À|Ç\PPQTZ¬+â;åþiÇÅD~îÀûØq²NâYÇ=Îw[þò,ëæÚu_Cè0¶/TKÍ!ú·?-endstream
+xÚXKsã6¾ëW¨æDU0ÀçlíÁöÈ'³¶cijI*ESÄ5EjHʲ³µÿ}ûP%Íd+{@£ÑèÇ×
+]ήU8E¨`8[¥Ö""oº¡ÊÃÙügÉ2«Å.ÉÛ몾(_ïÒt[geýêúnZäYÙ¾ý6ûq¨\+©c)EìûöOa]\Üß¾¹ºÝÜÝþþ0ùùËd:þ~?y¸¾{øÇäC®£Bc_Äaè
+Ç
+äÉ0"y#9íh¬µv¤¥íp%CÚsh~5R±³5«ó
+w%ÚÕHZÞM
+4¬ÎË+PYÓ¥'bOǪY»«ê'Ѭ¶í¼Ú·Õ<kÐ(gîsRÈ
Qµ{ÝäiRðDµm7 U¿Zð7{IÖÂh.yn/W}«T£1ª'3)ùSÏ6ý»/ª¢°·ßå%Ë?ÿìë6kàT_ùN[áHù*dbEÞq^_{Byîp¬Hôcä· à z.¨¨|×QGcOGÎÅüy¤ÎJ§nñ7oòrLàê|>§75|Eà|ÎñamÅüíãcÖÊÜ0±K£>ï
¾3Å`þº|¤%F£¡ü§qÛ kE@ÐÙ
+tð\å4¤XZsPrL7å8ÎÒhSäì\mÄ`¡Óq6« këÖ¬Zá:;ÇæYiÏ£¤«5rlP ½ÙýX À"msó-
Ta&=½SÉØyD)ÌVbæg`yQÕk^HJJ+ã7oÆEìÜ`JKßY$©9¤][h:iRòì£=gÛ6Ùb[ðþ¶3½9æÄe×Ä4ÛºÖÕ6¯eÀ¨9ohÓæpw½ÜòäÅj;êÙõ3º/5n%Ëh%s¶ªARzV]¹9VÚ¯à¬Úà⯮ô0õ·uBaTLI^v\MÎhÛD*×ClªÊcPTiµdX[UÎH¯9hn)_þ Wx^råþèM%iV'@7(m]xå@¬j¡ëJV<!§ðìôè+ÜþÓýÎC½å-°Y±ÆF·[üâNCx%t¤TdÜv9©+Mu!ÂA£=ü9ëNd±ú[v+Es»XçL,è ¨g[.©ýÁ1Õ Ú`WƤvhçÆtÉȽôjpJúº!X/1ëûF e°EêÈ·.öEÁ{êmÉÔÉTí§QQA»ªö#îB-ò"ã÷]3ÈRT( TL½ÔÜ+ù<rWdÒ§ZzSRoÂG
+5ñL(g+zdäå·ªP#s$5¸æuºÍÍYèª.W*+ÃÛn=ÐBêHÙq1~î;ã¾ÈË£?]<C½cCM¯n®¾ÜÌÔô=áê>ó_VÓJü~(dèjÞÝOn'ÓCKGÊ.3}É1¥á´0òÞüCD!äÎ}µïdhÒºxP§;°y³Êæ&øømf×ÓþaÞS&fº'/:¦¦kµóMËQ'Ïï
+yß$
+!ip!Ö endobj
-38 0 obj
-<<
-/F4 18 0 R
-/F3 15 0 R
-/F5 21 0 R
-/F8 36 0 R
-/F6 24 0 R
-/F7 27 0 R
+42 0 obj <<
+/Type /Page
+/Contents 43 0 R
+/Resources 41 0 R
+/MediaBox [0 0 595.2756 841.8898]
+/Parent 25 0 R
+>> endobj
+41 0 obj <<
+/Font << /F27 31 0 R /F8 15 0 R /F26 12 0 R /F14 37 0 R >>
+/ProcSet [ /PDF /Text ]
+>> endobj
+46 0 obj <<
+/Length 1692
+/Filter /FlateDecode
>>
-endobj
-33 0 obj
-<<
-/ProcSet[/PDF/Text/ImageC]
-/Font 38 0 R
->>
-endobj
-43 0 obj
-<<
-/Type/Font
-/Subtype/Type1
-/Name/F9
-/FontDescriptor 42 0 R
-/BaseFont/NENDNC+CMSY10
-/FirstChar 33
-/LastChar 196
-/Widths[1000 500 500 1000 1000 1000 777.8 1000 1000 611.1 611.1 1000 1000 1000 777.8
-275 1000 666.7 666.7 888.9 888.9 0 0 555.6 555.6 666.7 500 722.2 722.2 777.8 777.8
-611.1 798.5 656.8 526.5 771.4 527.8 718.7 594.9 844.5 544.5 677.8 762 689.7 1200.9
-820.5 796.1 695.6 816.7 847.5 605.6 544.6 625.8 612.8 987.8 713.3 668.3 724.7 666.7
-666.7 666.7 666.7 666.7 611.1 611.1 444.4 444.4 444.4 444.4 500 500 388.9 388.9 277.8
-500 500 611.1 500 277.8 833.3 750 833.3 416.7 666.7 666.7 777.8 777.8 444.4 444.4
-444.4 611.1 777.8 777.8 777.8 777.8 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 0 777.8 277.8 777.8 500 777.8 500 777.8 777.8 777.8 777.8 0 0 777.8
-777.8 777.8 1000 500 500 777.8 777.8 777.8 777.8 777.8 777.8 777.8 777.8 777.8 777.8
-777.8 777.8 1000 1000 777.8 777.8 1000 777.8]
->>
-endobj
-44 0 obj
-<<
-/Filter[/FlateDecode]
-/Length 2104
->>
stream
-xÚXKã6¾çW}´½³È!ÉÎ$Ù²¦s÷ ¶i[hYôT{üï·^Õê`.UU®"ëñUQAÅqpèñkðóò É£,öADU¬Ëÿü+ÌVë$IðýötîÕjey¼[ó:ÚnµÝp at rÇǾ۲ÈçUê_²Ð*ó¼ÊâPfêUÏøÿ>ü+Hó(
-ÖI5Y}X5Y¨÷Ã<h¢¦ÄÝY.M¢:a¹#î(Kíuø
UZ
í*Ã+sfÆh/V5é'ngÈRiØzX¥ex=éÑö¤" [:*¶üÿù¼ªå¸ðBÇ
-(ò¶ 6ð12v-Ùï\%§áN3Øgîèå7iQ+QÔC|nýbr¸£:E'&nõº£i]§h;ëÄȳ½§x°AжhÓ{¦ë'QÑwOä~Ãc¼ã¸6S\Ñ-°NiÏ´L§gLì?Fu_®ì¦KçÓÆÑ}ÎèYgÞq¬Ê¨©P[g¸Ê¢³¨\«¢ª Ö¿ãmLüø_þý73äN9ëµJçgûVxAñb¯ûÎs*ºGMÅi¹ïe
Ô¶â7w4z<Ú¶èúBÂtL,\aêàsPŹöÿó dçËDeßfKw×°?Ùksò11ê£òë$Á[æÝÀ#USö²I^ÒÞ>c1£
¦
-k)Mí3úѵÝÀ0Ã]OáN @y#ùõr¬EJäqTøì03lÅäåÛý1òXáCÃb«d;Ób^6exîÛðöq}pªfîqÕNZÁ NÜ>wËÄMòâ-eZ¥Ryb .ç3$|àW;ê6åWU
Ñ3
-É-ܶ³"½wØ9/ð|º;¼.XçwÔM_^Ijß+}<F-Ðäú<«ç®®Ox°Ä¿x+ ·z|>R{[
SµW}Íò-Ê[Iïj`Læ)`S!&îÛÚÂ<´ 8¿¥y}ÀÙËx6 ¥®øÞJO @Req|sJBV
-Ú±ªÞ
-©3Û±>ö=J0|áªÀÔêWXÍøìÛqàÄZV¤¼¡@,^qÆ:Óð½àl;À§ë ,ͯg£EñwjM at XO¸Á a+µJxè#ÔÑL1ÊÏiôëÚÞ(Ym¨Ò*ÞHöFÙ£¿T©Îðr\(Þ
-8RJ© r l[nk-¡æ\ÿãØõ")Ñ°XWiþ¦Àmo àM
Ü&þàP#³ùíÓwL²Ýaà»F¾¾Q±oÍD$6Þ²ÌÈdPx¥1M«¾c£<y'Uîu¹lc®T8OU at hù!Ò~*óSãïÄ%Ýä5Ý>TÄ·%Àçªg7YâY¨ÙóÎÿ®ÞKþvÄýI®^Ú_^õ±ù]÷¦{í'ùw¥ÂÛÅ9@O¨Û üxkÖyãùÓ-endstream
+xÚÅXKsÛ6¾çWhz¢:ÃøJ§4u¦Ó¦m¦V&¦X$)R)Ëî¯ï¾@Q¶ÒÄ3irH»}ïÿ0òìURLª°Ê|2_Mâ4
+¼T"*Â8ÉâÉ|ùgpqcþWÝèµqÓYdÁv¼ùÓZw®M?fxeü¿þ5ÿyMfqVYdêåx^Û®7
+3í\{{÷eÓú>|öª ÂJ¥ÕdÀ-qQÒ-óÎÒ4o{^é,vÓ8èøDãÞÁh ³[[k,è[&꽤÷Q¬ÖuÈÕ3I¼ÕÛ]ÍRâ ÎT殮òbÿÍ,E$t¦QþÞ};GdIÜÂâ|9er°tC`Òô4)»«é8I
+:ºõ Â4x§ê§·o¾á)aáëºÑuÇ,û)2¤ÞÖLe½*ØÀRáRÚºg"Í?/ÑÑHúcw}ÑiØ|Buàþ·vi:L,>Oe³ß½m@Ù·;b,#á}Lò¼+0lâ)üi³÷)æÓJ!bÂáAa<ü¿]?ì³Aè/%¬d`+gÂ?@=Ð8 iZá³W8."wZäZ@¬Ý1
+8¥ÂºñÁ)0µ<Ú
v£{^iw¼ä6fÁð=ç®ÁÐ=êú\1Ïq|GÔÀp@ÄõS9cÏ1
Ç3Â#zÁÂ TÉp.jä
+Bç@¡
Ò3¹²Ä>xðF÷q<ânÎ3Ø¡bÈýÚQÂÒMËfGØ8Nµ-¢¼8ñ05þÆøÖ¢c=ª#VÏئ£+^80+IõÞiRØ#ìcDøiÖyý<X;I8Ø
+ñ¢mÃvÀÉÒÛ¯GÏ¿Èu²ãl'p-V§°<]¥d'è_<ì¹²äÍ?ÄI¦y1½ùãSQR ÕÁöÁ
T ®l»£VØ:¬EÅò.õXþÔùýå/¢OÂ3fÏ
+FIQ|ëÏi}üHëãÏkýå¨]ªªu0ØÔôW7øø;Ò·W[jAUu¬â5ÊqfÉZ7n»á|;Ü~ëùyiÄbîYß) QêÓ}W°£îÏKÝ£6´âöÒ3ÿÞOî~ô÷n&ôtøÏ\x*÷
+b¥8Ç<ÑeV
Ê?Ò丱ßÀAyU 4Íò¬2úãÇ'ó'ÿ
+
Cendstream
endobj
-45 0 obj
-<<
-/F3 15 0 R
-/F4 18 0 R
-/F9 43 0 R
-/F5 21 0 R
-/F8 36 0 R
-/F6 24 0 R
-/F7 27 0 R
+45 0 obj <<
+/Type /Page
+/Contents 46 0 R
+/Resources 44 0 R
+/MediaBox [0 0 595.2756 841.8898]
+/Parent 25 0 R
+>> endobj
+44 0 obj <<
+/Font << /F27 31 0 R /F8 15 0 R /F26 12 0 R /F14 37 0 R >>
+/ProcSet [ /PDF /Text ]
+>> endobj
+49 0 obj <<
+/Length 2359
+/Filter /FlateDecode
>>
-endobj
-40 0 obj
-<<
-/ProcSet[/PDF/Text/ImageC]
-/Font 45 0 R
->>
-endobj
-48 0 obj
-<<
-/Filter[/FlateDecode]
-/Length 2186
->>
stream
-xÚXÝsã¸
-ï_áÙ'y&æJ$õÕÎ=ävm®{Ùtãö¦Swn±ÕÈOëÍtú¿ H}ÙéE/AAàG@¹îb·ÐͧÅ÷7r³8XlaÀx±
-8ýÅæã?»jÉCç´\ Áª«ÎfA¯&n©Ú%`÷L̼ÁV:uWy¹cËm~Z¸ç±ØHVßÛåJúBÏŶÝ+"Ò"W%îÛÚÄP§¼(:.W°ªªú@ZýÖ©¦5º¶%R«-}ék}ï/ËH8l¹\áÜwG:Ê
-5]yÅr¬nZFI^Â<ðg¾¿zãɹÓ?àÚëã±ÈÓ¤Ía±<X:ö/Íä´H-¬¸ÏSÜgO{¤IIü¦MêÈv_«$£imE¼©Qôºüp,9õçÍæîÉOë
-ñÈÈFÁÈM¨ÙåßP9¸èNeµj3¥Ì sVuö¹çüÖV$ÏÜÀ·<3¼¥ö·ûÑVS&uî4OÚé¤tj·ÓcWÓÉ«F5WÈÉppP;ZIéJRWS%9ÏÔíFY'±_>üå᢬êi¬w õî#§wÁ?νçGG¯¸Ò§Àhþ¾DKÁZEë¶Î;ùîJ«Â]ó±ßN'¶«ª]¡X¦`Nä^ÌÐuùvù§¹Ë®|Gc-Tpú"9(ÝoÍq'sBÐhðn°vKò5\²ËVÕÔ£BY×Ã
- L«ÙR8Ouu°¢¼Å=² sÀÙì5R+@¦à.IýBìÄâ¹úؽ{8//Í$juLj¸êÙ°ODk¹úc¢àyWW]]!Yx¤ð¤-ÞvRB;>©ÎN:æöªÝþÇT-ÆðU[çGJiKÁ-uKBÿÐüÿü`|£ÜàÂÀsRèÙ,Ù:-& ð°ÁÈå%7FÔãÒi+·ËzqAÎdɤØC-AToè³tb
-Blà;ÿVéïÑÁgþNqsõj½Å7y þ¤ËJÄcÑã-qÑ<ÛâñÒKÍ®fÃÇîªÉ45.?u8vÇFY IK¼äxÈÐ
ë<%y¡Ú3ëj¨²¬íÔðÄùëäVxf·ùJf Õ» Ò}ÌYg;¹[²ÎíÆÚmΠ̯ãP+QGÃ)´Ü¥-ÎæÒÁ=qI%=lêXÑHç
-%ÄMUm2!ïìaÀiúøz~ªÌ¥ìÂBL)9çÆ^Htã¼O/¸Ípû
-ÈÑ(Ê
¾#cnÏ:º~ÆÙè)8}t
-ÚÏl2µã¼rr#&å
-?f!T
->"÷± 8üaWúãZça^SøLÄIÒe&nÌ5âî×_o¾|ýù¼¦ÀHÑ?Gõqcñi¸¥i¦#¿[Ã[þ¶×øxSÕ×åË4ít&8<ȳ¬5¸lâ_m~íOõ_W×öϤdºö5
-p½þbF2ú^ÒXÚéßyÁ¥ßy«3ì³yZ³ïÚ¬:wU¦ËYZ3Ç«¸VÿÃÿ-endstream
+xÚYÝsã¶×_¡¹ÒGßíôÁwc§®íĺf:I&CÅDêHêd_&ÿ{÷ )ëÃî\_D`±»X+\ÇWvñPó6áý
z>
+â
+Äeøn6eõûÉ(PSô;ÿàa¸H§MY=ò5m¿¸û]tµÐÞ;èÉ¿ï3ñ®*oÊL³ÆvåÖ$fb£øI7³¾;e®Èue×T{æãc>ªMuÚd§MªÖ³
+"ͲË<¾GOjÒÝiÆîA
Ö<p¯F,Y>ÈJ_]¹n'±®ûúTóõêSÑäO+16J·/ûú^ôå
+Zm´Ï®RðÚ|µÐíUÏåºfúÅ!+C´µµ)C g¬à¨X×+ìi¦3&¤øvCõWÚÂ\þÈ´8Þá.QQW¾¢-©x<d´g at B9åP¶&F+éÀæø¶($(uij!¨¼IùW3ÆRÇTìËh&lXØ.r;
+1)ÉÙG]ö}Ô«V&í¨Àl
+¶*Dè:ÅpÛä¤L6[ôóÐ&Çb
+ÕîAAfmØãrºÍgA+ßËÉÉwØï`t<á:`?2Öaq íwwê/µ¢lZp/%è«tM£C(mÃe±:D+áîjEæ"îÃÿ½Iú£»ª-aO ²+<¡$z®+B?ñÓåàóàç_Ýa6pß\á%q0Ü@Ç2IÔp9ðôbeûÁýàVá¨Õ8ê«ü/AÛ¡ð=°´e£(ß_Ý|·cfâ0ê3³Vãkf&¡e(·Íüqüçñýd7P½D+/î3³Vãkf¾d½4óãøêßãó]òaUòw}
+}
+¿¶8k!¹A,ö U[¹§½ÎÁNi¡&Ó·Rþ ·h[#槾kæ,¢§ºlwJFP!lâ½Ê?b@(Èo>-«pÔ׸{X¾HxËÆuwý=%|4âÿg£Õø^ B/^yÈ£+!¸ñç±÷4ËvT²U§¯xð÷v¾ü/Úßðª{Sò>pFIWCÒoÝTëiÃöqËKö\íû*ÍÂíîÝÈèí?bô¯Ð»÷Ã^z¯yÌ8PÜÕ@<°ÄV)Ë÷^äÉ;»G]`Û({aùeÈXy"<ÒYý/E°endstream
endobj
-49 0 obj
-<<
-/F4 18 0 R
-/F8 36 0 R
+48 0 obj <<
+/Type /Page
+/Contents 49 0 R
+/Resources 47 0 R
+/MediaBox [0 0 595.2756 841.8898]
+/Parent 50 0 R
+>> endobj
+47 0 obj <<
+/Font << /F8 15 0 R /F27 31 0 R >>
+/ProcSet [ /PDF /Text ]
+>> endobj
+53 0 obj <<
+/Length 1738
+/Filter /FlateDecode
>>
-endobj
-47 0 obj
-<<
-/ProcSet[/PDF/Text/ImageC]
-/Font 49 0 R
->>
-endobj
-52 0 obj
-<<
-/Filter[/FlateDecode]
-/Length 1949
->>
stream
-xÚXKsÛ8¾ï¯PåDME ¯lí!gãLåÚÃj°K¡H
-=Sóß·
-Pe'>h4è¯à,da8ÛÌÌçß³·ËWÄ,LÈÙòvD,gãgùþ¿/¢ÇÁŽÚí+=_ð8øëùB4xSÜÍEè¶/»²ÞÀ¢ÌmYº&ÆN·wåÚîêúîÅüËg\2>[D)Ë
9«*×ó
Hã`9ÏEд8A{<ä0Ð~ǯ>ÈYÎòo¼ )<bYd¤,·p#8|ÝÔÅB«®Ô]4h§2ñbøU OIË¢èãtB®Q'\p[{:£rF
-\\Î3j ®!(±@Eà Ãg¨ÒKP4Ê¡ÇAÔì°îsÛ´;¢¨7>à$ZýÇ-Æýjò/úX]MûÀZÚWÁiøÕüçpÿð¹)4ÉÚãôDº=Ñ5ì Ôð½xI,èÇ!·çøçð¥"«Ô=&B#Ì):Äè¿ï5ZéÈ`pH0FÉ -JºAãÙ±"1uÂø:a¢M*ëÛtIöÁ)Kq#½Æ`ÆQïxkµÓSÛFqÂDfÃ])\2badY[Èâp¿-äT*@4¤FJÊàëJw¾lfB7媧Lä~kµñ¬
S+(U³Ù îvo¨é4$ÅEÈಧ5}OK ®#J¿U= ±5)
ÃTE$¯vAâ,+KnH`çGbb´FÕ¬UµmºþµÉGøRÁ¸ï%Å4AU×Í-Í®çïMG0`×êÓF_a8ÔY)£c¸Âòºªæa¨JË¥Ã,
-=v *ÓÒ|ÕUæ;ÇVýàÎcßë¡×lÌÿ®|ú³ã{8¸ÿCýáxÒbË-´+3-endstream
+xÚÅXKsÛ6¾çW¨7jÆd_éÉIä7MÚêôÐt2 [S¤
+Rüï»õ2íØdz°¸Ýoôëùg<dAóx2¿0!$Nå$ ñMæÅß^«ÍZ *ÛN×Â(?öëôùopâ3dQÄ-g^ºî6×Y^ê{Ývx":ú<
aèèÎôz+éåYº¯2)²ÏÃ@&°Âÿ¦ÒÓS_ém¦<ñT9e^G×@6iáuMD>õW!Fªòø§Ùci«j`êÜYUUDk
ÝjRõ+2Tã@³²Á¨;DñL³(:{
D¨P^Ñà¦>¤ð`½0{.µî6¹
+ÚEßͦþк=©G#:¢rw«2WN¯¦ïV Sï´o®é©¿*p°AkËòf±YÔܺWRÞâ¾;Õ-ÈVjM
û
+·±°Þ¼z²ý.'\4x!RL¤aJ䲬 Ó¾6Í(
+á=)/KÄ®iÄF®Á̱9H¦¯;¿3åÞU]8 ¡éI:êIºéI¥eöµìÊú&ÑãBÆ!fÁ8KRËC¬AQòfsÖ§H W¤ðä«©/!´OõTpKÓáoÙÂ
+È$É!¹§ò\·»õEYº¦l3j&A&x:T@´Æ°@"ÇKb@à*ü HboeJâ!_l-Åù4ÀѹJ
+ÜàíÝäòVÎ(«ÎÜ80ãPQmÂ
+u|Å4¨Ö¿È/6cõZ"¶±
+Ëf_ZÞÐ
+À©`Îù$ÏÀfÌ jíÒÆ]ê*î:Jºk̶à%¦\O£Øâ6Óó)pÛÏc¬#¶4aB=¡E{}¼ @Ëi[ɱ(ÍP»ò®1wNæý²æK{±³Ï(Ä¿¢½Nµ·Dµ²0·nc8ݪ¥¥RtÙH.¨\%
+1rf¡¢×eÓ;'ÂÚÖû®èD-ökÛá(lkZçîjè©#Ra×0a5q4ër@×)§î´z»^±½4ìƹP+r?u¼Ñ%8èî.çiLh`áiâåì¶Uu® Gjw
+Å7ÑKÁ®ä»uÛùrü]@wäYÉb
XU?¨è® '÷Vîß4fòa¸ÆJzÄzcüE× ÞÑ1°@mµ %*:Ⱥ<Ådd÷Ú¶<ز1ϼ¡aǨÖíXOGäé«ÿ¡SæþàWHÑÔå9ÊàØmj[#7O!ZUA+äçì´ÊvÏ;Úl¾Pà!«pq³PQ»HͺugjzÒ8â _Ëïâö0KCNì,òîæ{É>涢·Ui(\»ÙRzÛ²T¶ÑÌ"ÐÂZzíSÈ$ÞÖÕa¾¡±¸USý"À×Â0ÞÒ9Èbë¸ÑîcÐi×u¬m84ÐB K(åe6¸iAÊPöM!_÷FpY¼ºYtÔZz«´c[?mád{®zY¶=ECAüì¸a µÿk¹U\@ØïAHãÞ=Ó·Þ:ó¸zìË.r§¶Ã¡HÚ86n dòxE,Ó`ø¤o'÷¾£BäldÌ0%H±lì¾0±Ì±mJÈÇÐ%ª«N
ëCYnptÂ×$äë!´Þ«`{ÇÞqõ;wìqBÞOxÆQ|]4¢Á=Ú"»'+Äñ÷BÿP¯¶Í§Æñ
þ÷ØÒ๧¾BcJHw$J{"Û
+k7(ÇèN('>ÿ±k'פS¶ÿç$w#?!nÅq3.½nV þ(Ò4¡ü÷^Ìæ/þ¢ÉY·endstream
endobj
-53 0 obj
-<<
-/F3 15 0 R
-/F4 18 0 R
-/F9 43 0 R
-/F8 36 0 R
+52 0 obj <<
+/Type /Page
+/Contents 53 0 R
+/Resources 51 0 R
+/MediaBox [0 0 595.2756 841.8898]
+/Parent 50 0 R
+>> endobj
+51 0 obj <<
+/Font << /F27 31 0 R /F8 15 0 R /F26 12 0 R /F14 37 0 R >>
+/ProcSet [ /PDF /Text ]
+>> endobj
+56 0 obj <<
+/Length 2234
+/Filter /FlateDecode
>>
-endobj
-51 0 obj
-<<
-/ProcSet[/PDF/Text/ImageC]
-/Font 53 0 R
->>
-endobj
-56 0 obj
-<<
-/Filter[/FlateDecode]
-/Length 1880
->>
stream
-xÚµXYsÛ6~ï¯Ðä¥TÇbI¼ÒéC;I&Z>Ô,Â&©ò°ìüúîÅCδ/"°X,ö·Í?f·3ú¼=_þxÍBíGz¶¼%¡Æ³E¢ð³|ùÏa¨bïüÞlw;_DZyÑÓùBgÚ{VÜÍ£À³uëWÞò¢)¬V¶éé·vEaËùË_fJûj¶S?èÆÖwn
ÂÓØ«P$ÈU )ÚÛu×·âÕå<W^%¥mçQèíñ§ª?£ì/ô,÷óYð9*ô³ÎY®];³Ük×®F5sÐ~°&´ßùn̪eJ»+§u#ÔR÷kÐP¥Þz/nj³µ{\B
-i±ªÝ+ÍfóÀ,kÓ[ðIèçìøëùöXwݹMëÛ£Ì@UÂüÖ¶ì_¬ª²qMÛð¬ºáo'Ãñø»ºBÒ½³Äª¦å%SÛATiW-Dlmûs% ':/çYÄÁQ9g8»þ|T¬áEø\%b`%"-f¤A5³YHnQyuÕÅ¢ÝyZ·¥t½Ñ0M"=ú?ê¯mãN!¹>ÈCt Lo`xn»Ú´®*bÃ0£Æ³rÔCIÓÈ°Xô&0ÁÆME>«>÷ò
·á}Ê
±"®T¢A
¾-ÂH<ÙÀ£r?ê@×ûðXJ¤ý$½k×ùpuµCÉ°ªny=
--#ïò÷<<eVþ±yTûAø¿Ø¨þ+ÃccøØx9Á§ýMÏ3H¦µeÃLR\èdðsÌ#RNvÔöÔVèFèý%Âqst8}äéËþt
-ý(kNý¡a5úþx1A>¾(¦º@>&¢ù¢¦0%j¢vÆLηXÔ´öèFßÍIüI®e;×0ÌW¾:0)&%&MkjRÇnë6¦æ A~ûm»ÚÞ¹ªk"ù
-£à帢Ò~Ázà¤À $à.E¸ÓI0)´>¸.ÊöéCV%áØQéDq:Âw\JH`£<OT) ©2¥Å«ÁÀ#nÇÙ1ré'`°¯]Û2oÞ»$g;RmS ¬,vnÃ@³Ätª 16XvËKk3fS¨Wz´®-q×=äJáC=W2+Cw»ejËÒ¾¯K& äp²fÙh¶©SI´xÆ5¦¼O8ïq*Ǥ9éá¾(ø X¨$ñÞ`7½5Òí6)ð©$Å+ÄÚ
ýBe,¡=à\¾f±ÅÞ÷¡îH'õÁÕn¯K¯
-eâ~uÚ>3P»ÎðGª -Õ 4*Î`ú}À2ÚÔUҳĽø@ÎÝ;,ôÈ2E ¦ò4ìv×Ê]×:õ^/yôê|ñ¾ÎäH=i¾õ´ùþ¾á}Uéx\Ï¢¨<ÓÐÈBdÞð×ðçkð
¿Ë|5¼Qÿ<Öc-endstream
+xÚYKsã6¾Ï¯pÍÚ2àKÚçU³»³3©XsÚ¤RP¦H- ÙãüúíHJ¦ì$è÷×
+øÍêÕ¢äj,³8»Zm®¢¤ò(VWyQFW«ê¿Þ/a/~]ýëÅFùUH$ok£E\xvá«(óì®Ñaáǹ§~äuÈ۴ݾÇ>iþG7ê¬áL3ͺýòöß·8LéÔÂkñË;ò0¯q¸ôL
¨¥×¢H÷øGw¬H<ªçË §D×îÔSUUdQYW¾Ó`¹\W~qªØ.Aã4óʬx¼n0dÛcçÔ»Ô×8{¸«%
++Ýóaà°jÞ½Ùºìð#õl+lëÁÆ÷00í±çyú^î0[3kV*J%Q°LÅÿe*({»6Íp2zL%Nf¥·9_v`súfn0u¨É ` ¶ùû?Â+?¾Q^ßÏÚ>´ÝÝÂOãÔk¦ÿà!øP®mÛ=k´½É_Â4|QÇZ'¯á+úTn1ñø|þ¹4É1°Ör>ï ã
øõ5ÓåaÃxªq\ä.ñÈE\ÔÈE\ÔèpQ#dä\KòGuyg:M"FZ,¹¤#täþe.e#lä\²Ë'eU}4U¥[Ýݵ&6;Sáç$Rápâ))6
+õTJÆ+×1fiJ·<ê>ð¨ðà"ΰÕt²y©ÛYøKÉSúû¡Æl(+aÐ+o
»nß%áÖÈÔ+Iåh4éWÉ¿¹j$$éÀ»E;-¨¸´çÜÀÊÂ6¯ÇAªL·ÇNì/Í1!ft¥2ç&aqí8eWì¬.+˽vÿäv$:Ðy> 5-$ÎϲïÏðÝàr»ççâuüÞ4ë¹tX-
+
¬cqKÜî¨ðfÞ
+3äªÂ Ìà0£Ýc>(pûQ
í®¡ÔsÈ4+1s[CZc`ÌùqµÓä²Lö²HTvñÆZèh+±
+'RZÊ&qA~$&ÂÚE5ºCº%
+í
+IZ&+Ôá²»àx¶8{\÷üqì)~RnæârÁÐÝH|¿6½õ7°QwH¹®A¨Xv´KÆ]f"ÄÙ2;õßGÝ`T\Rа XÏÊr9#dQ&cÏ
+
`æ(R´`-p¬[æx*ä^+ý}çÐ
+I9þ2ûý+¹"ͽ8¬Su
ßè©$+HH¸YÍ C*D,ÏУÀXÊæåèzR!ÈÅ1ÜÃñÄÉTÕ{Ò\O+PLs÷r2p)ñ÷O^^¬,püã2~}ËC¬K;éòÜ-ÉÂðkÝ¡¶®9T ë2øØýRiçJ; íAc³f!eMÔ:Kèå+3Y|¬ã7;e+^~¹^&Úfcà¦oú:sú:õÜû@rzÞÍfî\v3ÕõÓ@¥ÒÄþæl/î°|ÏmõÐâ%^=4HBÒ½{¥÷EâÑõ|+½7¼×Rè^ûʽ»<×zîµÏÓÔYÚ«ßù¨êOlvé-n1øGäi/>
í¯5õ×n)äý&
+ç÷2»÷÷º±ÿ)rï(H¿~=nµnxV9'x(ýÐv7Íãõ"¨á'y!éÔàówïûùöÝo?}}óé·ß¿ã[O]t§Z«O¼õoü
§ß¨ö§Q8ÿì¼tws8Ôf-M.îíiú§SÞGgL;}7»h[è°mÛMUuãtÂȽҩ¿LhNé.Fý÷Â>ÑgMÓÏèÃûÓ:}¦b^Ϥx¶T,±ï"LI%¾z¿zõç1ñendstream
endobj
-57 0 obj
-<<
-/F3 15 0 R
-/F4 18 0 R
-/F9 43 0 R
-/F8 36 0 R
+55 0 obj <<
+/Type /Page
+/Contents 56 0 R
+/Resources 54 0 R
+/MediaBox [0 0 595.2756 841.8898]
+/Parent 50 0 R
+>> endobj
+54 0 obj <<
+/Font << /F14 37 0 R /F8 15 0 R /F27 31 0 R >>
+/ProcSet [ /PDF /Text ]
+>> endobj
+59 0 obj <<
+/Length 1361
+/Filter /FlateDecode
>>
-endobj
-55 0 obj
-<<
-/ProcSet[/PDF/Text/ImageC]
-/Font 57 0 R
->>
-endobj
-60 0 obj
-<<
-/Filter[/FlateDecode]
-/Length 1907
->>
stream
-xÚXÝoÛ6ß_aôIbE"õÙaiëlº$K¼Ã2ÄÄBeÉÓG`Øÿ¾û dÉr»<<ïx¿;Þ5slÇ=ÎèóãìÝêô<ÅvÌV³ÀµC¶~Vþ´nuõ¤«³í6ÏÕde1_ø·j"óøþºÙÕ;©´j4ﻳÞ0çf
-Ç¿?ÿkõóÌ-\צÊGf*Ðs¦®ëmU>¿¸ö£n®, d¥¨ðÍQÑïóLÍÄÈß0÷tæìLî´ ÇÅPcä¯æºÂéôÜëQ^øvÍ6¸´á|I«<%lJà"´æ"²tªÍ;$1Ç
-?à-¤ ÕfõÚ¬°ðÀ"Î
ã,<.Î_3Ï=^x½Yë¬brû^¶0mö|á¹±õi DtT4¬ÍÒà¸F§¼¼i฿*"F':Ĺ|-.7ÛÍÜȵ
y¶³
-<[Æ=!ÝÂ=Q=Á×byùáâòDZ88!<º¶cqCªw³üõ·åíê0el±1e·Î4<&ØÊ-¤í{Yj/ë8øÚPèF9ôA02ðUrDÜQðÃ`ÞB¿Ø³¿kUó`¸ÑÄJoóL_Ê ÿþT¢À. z(
-ûr»
-ÓaãÜpé:=bò¯xÖ¬éRCLV ½A]=}àé~cØm¬Ë¶Jt}ÂC$p«,Tax9ÃHáõ±?̾`)÷G8ú2¾ãÁåκ3ùþò׶mü;-U¨G8«JÓa|ÿ?ÚÑäër¹_z½ÜaX¼Gñ²D¬w}´o$ÄcQ7UwbÅa0̸
(2QÁ<&& 4I¹¡Ì,&¯Ô¼füÝ""DÑ]C³åÊQ
-GaÝö B©SôµøáÏ0Ú|ptý'0ºöuÝ°Ü;Ë7à{¾ã8f`é×-AÍ°¼·z#Ï:KæÒPl²ãÜë2Hw]ZðIÁ*tapÆ°S±Q5¡D Wð%=xÕ@!\ûy ¬æ±y
-À,û¹töe<+$"F~Eá¸ç
-«<to\Ä%]PjTÅM·ySv91EÆ>µøHͺ'Jh9¥eÕºi×n]ñ,
v-ÜÆÕþ
-Õ¹°êÕD·Ü+JTÜ
-¬¥TÔ¦¬^xm<Üð-endstream
+xÚ¥WmoÛ6þÞ_á}ZÕ»ìC%εK2ÛÛ0¬C¡HLDD]kìÏï^(¿4J3tÉãÝñî¹ô˯ÎÃl4õ¦i·£ ½t2ÍFyA£eù3ñ_ºã$LÌÃ~¼qÿ^þ<¾7
+h4o$!)ÏDcÞËÖFhÞVÔæNr!ôÐßó§TÀ£^yéòí÷N9ÂUÞäwB{yY>ÚÊÞ_>Êþdþñ¾f½%;ÿÇ:[ðjÒëÏúfèlÞ[}«ôj.>u¢5¸#±þãÄ÷ûZÝgO´É¥9Wú¤Ù^E§ESÃáΧì\_¿¿8=Y^\]~Ï~ým¶X.>^ÏæçWó_fgO
OÓ³QúÞk«ÎjÓ\ªR´Gçu>9ÄfìMãh
+ÖÀHMÈÈ;¢È1n8q¶kYä5O¨Î¬ÝÀéÞòW|ÎWëZà vb[É»
+·[ÕZ¹c©{;+ò×í.SÁoUëÊ
+3g#ï^sàG]5}Ñ
hÛÛ®®·\²ÖäÚÒö¦ã»¡â=ÞxÓÉÚXJ]tÒï<pIk¾8kYZw7¼Jß
+!nquÈîOySÖ²¹c=àxÍò!D³Ë³Ë{¨|»!k+%lZ´¸å¬ÂzÃãx76¿h¹å0x¾?È4/W¸««sô« £i
+jbJSZCØÊ°qhòö ˽=ÙJÙö
+þâ85)'Îuó4Sgg±óÔ$ø;HJ+Ás#é¹ã´¬$>'+ÙÖ#+;Ú8¦^"#½Eç¤Skä9ª ò´¼RåV°yH»¸àL\<+6qãJÉò£+r¤´éí*þnÐ)bDÈÎÆ0²àËàSÙ«M5
+í5;ô,M@ &iP¸ÞØ6Ðj]öl¯(±µ+ÂÐ8U\mTTöºX3çãÚ8¿:}·Øï¢oá:ÅvËÕü«Êl?±Êg¢éK6ïÒĤ2å·%wr#ßÙ À2¨+c~ðfxPü©eýÅc[+躨Bâ{N/(QÚ+ö £ÃG¾ï%pÛSlæ)ý\0÷õ`<IêEÁs [¡'À£Øj¾eÖ½ÚÓFï^Zw9àè j!%ë-&Y28 endobj
-61 0 obj
-<<
-/F8 36 0 R
-/F4 18 0 R
-/F3 15 0 R
+58 0 obj <<
+/Type /Page
+/Contents 59 0 R
+/Resources 57 0 R
+/MediaBox [0 0 595.2756 841.8898]
+/Parent 50 0 R
+>> endobj
+57 0 obj <<
+/Font << /F27 31 0 R /F8 15 0 R /F26 12 0 R /F14 37 0 R >>
+/ProcSet [ /PDF /Text ]
+>> endobj
+62 0 obj <<
+/Length 587
+/Filter /FlateDecode
>>
-endobj
-59 0 obj
-<<
-/ProcSet[/PDF/Text/ImageC]
-/Font 61 0 R
->>
-endobj
-64 0 obj
-<<
-/Filter[/FlateDecode]
-/Length 1744
->>
stream
-xÚ½WKsÛ6¾÷Whr¢fL@j§$migD·ºF,%R%);ίï¾(>$ÇNíÉ Àb±Ø]ì~»
Aήf4ü1{½|ùv1[;[®g
-ìbæ[$ñlùÛßÞ¥²jþÏòÏoÍƶ?VÖÕÌ4g8¢©½´pÜífî«$ôVU9W×ÖÕ {R¯ª[\F^ªèIÆûôáÍ_îcRÂôá##qèThæ'*ãEÁíÍÊ|îk½¼¨y2K8l¶¦wO?A=§ÛÔ3¹M?ÆmúA·é§¸Mÿ8·égryÛÌn3OqyºÛ~+j·j«únê9m8ÉQôpì6é±Ût¤F*G¨rnÓQÒ¹MGfè\&t;ӹͦÑßé¶ø¹M=ÛìcÜft=ã6ûX·Ù§»í«oÐRHTß,ÀâMÖâ,õ¶EÓº²á¸¶* à5æiBNÔî
-ÔNèÐ7E»çÍär¸zòxá0î+NPÅSwÄßã7ÛÂñÓãÅâY1ÝÕëªÞ5üªµû÷à¶aCSW<=Æ¿¸íH«Ð+ÝzáUx!xÅO= @Ã-P'a<4ÂÂÐòá?xvÝ
¥özlã=éò
-ÒøeeÐ86ÎÜm3ô<Îè§-úR£&Qmbô-endstream
+xÚT;0î÷WÐÅHmÀPE:å¶HkR$)¼,Ë¢°k&wù÷½äiðx<of¾á¡ÚÝïeq«<¨NLØH¥XªLÕñøH~«>Þï[LÉçs(EFR\ÃHËLô®m»k\xÇçänCÏ×nÂÓý¶îÂj¼Eê]¨
+ñz'°9Û+P¿Q*]Æ1Åóê|W7£e¬µÝaÐ27ÝC "ô"e¸ÌÊ"¤!SäT[ß9, ÁÊ@X¢*¡+ ñü:Íuت+Æwp¦?º~+bädÐû¼¯8B?·1L&ï&¾X¶(ç¡o´îôº4\Z8$ÖÂS! ¬Ó:å¶ d7÷GT)\ôå=óèÕEËZDé] }X¤0H@&ÐÓÉOÃ3¿ÕoÛ´(-xZ¶Þw}óÉy
+êf¤Ðññ¾Ì»Ác·¬hû¼V·®/*'oG¿.å?¿Éjq÷#Ì`K<®k(¿ª¿sWI@,ÍiÔ.þìÚs+àyzôoX&Y=}xZyyÎa endobj
-65 0 obj
-<<
-/F9 43 0 R
-/F4 18 0 R
-/F8 36 0 R
+61 0 obj <<
+/Type /Page
+/Contents 62 0 R
+/Resources 60 0 R
+/MediaBox [0 0 595.2756 841.8898]
+/Parent 50 0 R
+>> endobj
+60 0 obj <<
+/Font << /F14 37 0 R /F8 15 0 R /F27 31 0 R >>
+/ProcSet [ /PDF /Text ]
+>> endobj
+36 0 obj <<
+/Length1 750
+/Length2 576
+/Length3 532
+/Length 1110
+/Filter /FlateDecode
>>
-endobj
-63 0 obj
-<<
-/ProcSet[/PDF/Text/ImageC]
-/Font 65 0 R
->>
-endobj
-68 0 obj
-<<
-/Filter[/FlateDecode]
-/Length 1567
->>
stream
-xÚ¥WÝsÛ6ß_áëËä]¬ê[Öv»Øk6×Îçú0ïrDۼʢKQqrûç#µ×í À -´Z³×r.Y¦<ZUc¤^(ÉV|õþN[õ/5HËaoGýÇ×ðLm
ül"¾¬%T7?ÐÜ[óî/(âÕÒ«ÁB1¹ÕH¥2×Êù¾G¾ñ}k#QïUÚ¡~
µÄc\;ñøVÅ×¼H%NÀíLöÄEM¼ì9Õô󡽦ÞÁ[É»$«Ñq;S÷alNT*j"-?LþX?ú^SÂMÌé0¦ÄzþBªµ©ÔàkʵÄW <<lÝ/s$²ZâÔø¦j*¤$3
eräÞ*÷ diÞ,ä|U{wh½³=Ë%6;ë]S¨tO³Lß*}u ¥ÖbÍÊjEÖå*-l˵
-A7ºHãé'¢¶|kÓYè 嵦úÖèz2¤²\ÂÃHsªÈbÃXP-5¥v7}¢ÂyìÛ÷¨Sô´ñî(Î\·oá÷F@é ¦'
-ó>`¬ Ö
-i>ÒÑÐfo
-ýÝØ-Z߯«C&=vØ¡Kj at dðì%ßµý>qèàs
->¯GÅ vì~²WÉøMrLK&½&h¡Ù?dLqxäK$}|L1ijÞîÏ-Bñ
-¨¿oäS-æ
4Å5®~¬Òæ
;«HűªÍ_2cJá¹Ó²ZáÏO¯~ÇÏïþo"é;¹æñ5#Jì¯($mjꥧ#^°P#óê2>glá8¡µ5/@3_ cxÜõaªÏ¤Ê×ß~©Ý °èRÏî#YÎ~ø:YsÍ
-endstream
+xÚSUÖuLÉOJuËÏ+Ñ5Ô3´Rpö
+44P0Ô3àRUu.JM,ÉÌÏsI,IµR0´´4Tp,MW04U00·22°25çRUpÎ/¨,ÊLÏ(QÐpÖ)2WpÌM-ÊLNÌSðM,ÉHÍ£ZR©§à£ÒQ¬ZZT¢Çeh¨\¢Ç¥rg^Z¾9D8¥´+@'¦äçåT*¤¤¦qéûåíJºB7Ü4'Ç/1d<80äs3s*¡*òsJKR|óSRòЧBçY.ëYìª kh¢g`l
+È,vˬHM È,IÎPHKÌ)N§æ¥ ;|`èû
¹xkCã,WRYª`P
+æ"øÀP*ʬP6Ð300*B+Í2×¼äü̼t#S3
Ä¢¢ÄJ.`
+òLª
+2óRR+R+.Ö×ËË/jQ+¤¥$e~sû]F1ñÊ»Ï/ËÚQ?ý¸mò»³·|<ÄݺÔ/¦Ùq'}Iüö+6ìâEíÀg¯¼xT.òGÀ¿gtÅÙ¥vÕGU|íª®¾~ª]üRÇëÞ
_kü9¹öË:½{ápËñGúý
+îûd}dN<6Îø-uBÛoHºÁ=c¦MÏvHÎzºq½aûÿìRKë~,K̳}¬ËªÂå»m¿÷Öêyoù~ÉîÃÜ×v
+Û_¹éÜÿs>§ß¶.#ßÒߦíÈè{/þôÉkÜ<nÈeà[»«×?Ñí[ïÁ§÷ºÞâdÚeãHð1Îcê+öÍ_èeÍä7aÕ-<Ì
+{fýß_áþZ#MzîáUü.G?=¨=ãûp®Yõ'åǶ/¨Tñå}[}âWè:)ïÓ»ÚÕÎÖ0Ê3íÿ±:oÝ;K©æBÊû.l½ñcc«yEá2ÿ
+óî-ÆצÈWµýþdöä¡_Õ~Ò+ áiïsûs`ª¨C¸¾îuÞI^>öÉ\mü|¢Ðr¢úÿXöÑñßϾØadj|ïÇéÖR/ü,2 p0,HÎIM,*ÉÏM,Êæ endobj
-69 0 obj
-<<
-/F4 18 0 R
-/F8 36 0 R
-/F3 15 0 R
-/F9 43 0 R
->>
-endobj
-67 0 obj
-<<
-/ProcSet[/PDF/Text/ImageC]
-/Font 69 0 R
->>
-endobj
-8 0 obj
-<<
-/Type/FontDescriptor
-/CapHeight 850
-/Ascent 850
-/Descent -200
-/FontBBox[-33 -250 945 749]
-/FontName/XEEAJR+CMR17
-/ItalicAngle 0
-/StemV 53
-/FontFile 7 0 R
+37 0 obj <<
+/Type /Font
+/Subtype /Type1
+/Encoding 63 0 R
+/FirstChar 15
+/LastChar 15
+/Widths 64 0 R
+/BaseFont /NTVDHS+CMSY10
+/FontDescriptor 35 0 R
+>> endobj
+35 0 obj <<
+/Ascent 750
+/CapHeight 683
+/Descent -194
+/FontName /NTVDHS+CMSY10
+/ItalicAngle -14.035
+/StemV 85
+/XHeight 431
+/FontBBox [-29 -960 1116 775]
/Flags 4
->>
+/CharSet (/bullet)
+/FontFile 36 0 R
+>> endobj
+64 0 obj
+[500 ]
endobj
-7 0 obj
-<<
-/Filter[/FlateDecode]
-/Length1 1095
-/Length2 4446
-/Length3 533
-/Length 5179
+63 0 obj <<
+/Type /Encoding
+/Differences [ 0 /.notdef 15/bullet 16/.notdef]
+>> endobj
+30 0 obj <<
+/Length1 1884
+/Length2 12110
+/Length3 532
+/Length 13167
+/Filter /FlateDecode
>>
stream
-xÚígXmÇiRBïE©H½÷"M@HR0TC&
-RD@4¥wé"EºPP¤#°ÑgßG÷y÷Ë^ûm¯ù2¿sÎý¿ÿsæÌ-Äoa%¡À¹!õpX? iIi( mj)-Õù!¡´4 éï\¤å¡2в ó £<<ý-&GÁaXÀæçÄEà04`
£~A-D",P~pOÀöEþ#± öí®®¦%ø¯OúWÒÂúYùü-û³úKÿfb{ð¨@ÀQJRJJXH¼ÿõtùébá8
-K
-9y-ÇåÆVØû0
-ó½ã
-JÝhoר{[¤ÜÐÆoïVôºÈ0+N:dt5DMRIô3ýcJpm¤ÛWÁKÆQO¼R9[ØÍü:ºVº°ÀòDaQfä{t¼ ,KU°ÜÜðô¿»÷î÷õ'ùá#lÔÆa×êjgÊi>ÑÐÏ?Ç0¥Ò«yöY}ÄómE«CóX²d§æIæË5>¶Î~ȼ/nlBµîxȾ޺º)<´CY+f½¾%qÈoTxìRÌÖ ±sסmiS¸{8üä(pväÞ¡îD%?5lm7rbaâÝohúì¾\ã£ýÝ1ù]x.Õ=WÂÐcçã©Í åÛYá½ÚuU!AYÞô»V8ûI[ð-$âTpðÅ´¸´Öj)Y3#'aä²~iÞµd!Öäæ
-Þ+ÜY0a0,õ³Í
-è¬-nßÖFÁEË1FU½µã¼KÑ-C:±Ñ«3W#ÚEh?y>Ñ1 _ίzÊ#
-¾#<¿ð%jæ¦Ñ¼DÈsk¶w®býµz(8òòËw*¾m\¾ÃS"7èX[dÓ¯1)É]0X®åZläVÍü¾QÃ~¤÷XUÚx@Û»FE0!/`ÅÉĶ7©$ìçxÊ
-,/¸Æ}uob«ÅCìë§;y1þ#_ùl¨ãqk ¹|I».åíÁ©ç\¡m÷ÖRçæýàHsß^Ú>o°$®ÊÆ_[t*i7|£¥'8Q»TÙ!Ì~:¾ç¥=éqÍB~¶¾Z¦Ù$
Z)RnéShi:mÉLßÕÛdÖLjÿÎÕÜ»©Å¹ÂçOZI.«©² ¼
-|ÉçÌÄ!Lw¼mN)ñíÓñõ©yÄ©fJÂ2Ù¬KZrõç9<QR¸#Ú9sÝ«³¤ø¦4¦/½¿µ9ë|8ÑéáÛ'öñ÷¨ãÂÁ·|©OÓå´y.]²á9.^lçbù'}3K /~äá¸i©xª¸æ§i¥èd<ÌéмãNPPñU¥@ûV÷ÅM¾³åz_t{ܨOp·¿-°"{÷L²ÈHä
÷¨oØë¤úU,ªÞõR.}J?¼c±Hå
Zw^B²K>áÕ_ÐfЯÖ{í4¦yM²b×DÄõ²D¬r
-j88MA¿Ø¬Nݲե?=íóYÅäQ"{éÂ÷pn¡=ë¦7\äwlÍÔ>d÷u-Sú,Yô|_m]
-4a'yÕ"ÂaD¡8guKpqM±üöÕõª¼2%ÐïSÏ^º®ùå¦
¸pÍF(¶ýÁIwÉTÛÝjÆî3®»ÎwKìdFQH¤·!õÁéïQg¯LêQ#Ì-Àý&çoðpù<T˳¾¥(>A<§)º6æÎ\UðØ$³vP41ÝBh©si滿¦Z?Êð-Î}¾½ÄÜi|åâG:ZÜÓnsÈ{ͪ-r¾k±<Æú¹¬BM^ÛÅàdQ©ÃFk,ôÝ̸Ú,_ÏÖÝ´õÁù©Éå`aå¶tQñWöUEÆbÙ
-BV7_äÅöÌMgfp*í«é³/´¨'ul#'WTù<2÷I¬?>òï0x2c2q6^Ó õ#Dÿ%çvë®SgèNCWY2ò±¿u£ÑWPvfÏÒ\Ý;ÏtòR¥ÉþâU
-Ùu¦M5Ì£uñ± ÓÕ,姨y}ìÇÄ92(µ×õtòJ[UÒ¾ÉØ;Ci¥¾Eÿ»PEC^î»78])Z Ø 3BûAhÜßèÝØO«´ÐáÖæ2ßÍýö£ ßÂjÿn$P;*Îmäqdÿ;Ì-Êh_Te³bz5ÎÌÁN§¼è¼@t»aÌfÿ`CáÂç0¶RZóoº{ËÜÒ¾àxÇmWù3Ô6j;©¢ë;J!Q çNá÷ýZÝ×¾7?ÜÖB=YûÈv±pÞÚæ`] ×¥ÂÀüh\ßÇ_voã=þ'ÓM%²gm¹õcUÁ
÷F_jDÌ<æïVÆy6¶Nµ9
-v¯Oy&=Å&@4êd_
.×OxBÔÚÊA
-öåÇcÆ?¨¥y$(ót?]N«½,òqo®¿ùðÉædï´²
-X^RÀä,ÜoPÔe¡¼Y»½/Tò~ܦló`¤üãzHz¯³ñôWêk5[fjʼ¶L\q$×õúá½rH¢ñ>fúÒº:9²X½XÏý£mÜÍ[<váE¡Î&rÁiBuZÃNÝ¡×C
@Ëé§(é¾sù¨ñZ$I2»v /hq¼°kð5þ!ÄÆùú5,ù¹ëNB¤ºRn¬³°ìrnJècúÀÂÉ#ÿÞòPÖÀnïõüàqÍít<jIèËfwlÜV¼Ë¹Ã8éá
®Ï×V1ÉÝÂyêÅàF6áOÓ-,¢!ÓܯIYó[·wé*Í8رbææ]jÆWÙr)Ïz\&aÜeyQI
Lj³E>Ù=¸=kýêâuº·éÙ
ÅÎBT׫y1CÑÁMÎ&g$_¤^SXÌ"?õ^Z÷4`ÿð\U¬.w~̲jpź95FÍâ"4ó¥F'¸M$¡a·¸LÈiÄÓXÔÉÍÁBùÛ>ÔÎÞ;Ïâå>¿¦( EÒY%nb.´5MfÛ-ï!%ÚS¦E26°ÓðÔÉÀY»Ò+^ëM®!báM;ao0[ØÒ}²û RØû£9'1äôU¶M0âùdÐmuöűUjjtïé§|*}ɵv ;ÏFU,©´°
âJòñâVRñzÜi
®ÏCíJ\2j{»v÷ò/Íغ,:¹ö¤ð¼(§°]Ö¬h£¼ö¯t¼þÃÜóf×å9¨aw×0äo´Ú½UçÒ¿ÊrÔhswÝìË$½`w廬v?$¥âÝAçèw?ÿÈMS"âAiïíóªGe7]ßèJòx^-¹Ì#üüä˹.ôöPtâûnjgYoXk¡Oé¬×bmïDISÆZ¼'ô¼W³Úµ<7!°SdBnyÅS2úv?½mãýÍWUhàºçù!-ò2Ö¼² ¹òª7ÕEÕRÇnv¦ÐÒ¶üg3ßÂLJÑ·°
-L-endstream
+xÚí·UX̶h»k+²³3þa0Zz:Xíÿ8À Áë@fB+ÿy0þï·SDäáMÏ gae_LfðµbòýÓL]ÀË¿>Àïï³¹ø±=¦H«K SÞëôæ°
+?ñâJXH
oó]ÈÁ+¶ec²4[õZÏUYØh°¤î¯DÎQ>ÊW onFY^mDZ·Yòä?ÏÐ;îÏÙ!ç¶Æ+R´Ks¯Î
+¨ÄÔà7È zuÝ{³C88µ$²lÕÃCë?²©`d8VD°
oºc¤$ÁlNûY#´Ò®ß:]±
+ß!Lá¢XDòVZ¦ùÃ³è ¸6õÄ,6cô
+e=&Ù5½5Ñíö«?×zfvUÛëz=!^÷Mh& å¨àg¸5/à«$PU`ÎxÄ[¾ÈcØ8CWK
2±ßã§f+^+]y°;BÏ?KCvléçOQ"ÉPVãhØY9'ôj[JìôÂ1·ó%¶· {ìd+_yøñ¡Þ-SW¢é¸¾bz(&>Ëö ¤É&ä;¥«\Èxî¹)â]ç=ç»
Þ>@ù踫7 ¬¶ä5±fX¥UhËÕèáÈ¡¦©VÚxÕÓ*iYVÉSd¸YçÍ¢dn¿ÜqfpÒîJW¶»Ö\nî®ôXJññ}Â
+¨j#VL`a¨rÚ¥DrCÙøíOÓ3p§¡'×@ñÂÚ°×(0ú+»á"Ö~vÔGqXÕý9ÇkþؾY¤y+ÅÃýÝ#àÛhõé׬£Ø&)¬7?m!?'~tdC2°~ÜQ,eSÚ]ËðÐ),j°\J«ïþå°à7%h;+ÃÌgeQ{ n/%trTÉ4êî5óåUt4·¬ ÷mÔ§çcA»ø0l«0üÃd¡M«|ÕH4±î·aJ£e¼þÞ5LAWÄ\h§ÆÌÈl%ÌÑáC¬³Î±0¡
+É/Æ}»Ôßù<v[>$ã\«Eqb;'·:}
+Ô>¸ÿrÉòýÃí0«« À·%¿Ôk3 én+)aqëÿà°{Âýδ7ÕÆçS¦âÁHwç¦JéÙ9ÖËéRNß.»¿^10Þ&¼»û=¬ôkh¸D(Ûfé´$c=²þ³Ø{"\y4ÚèÀ<·Ti'Ð@o%e½ÐN9¡õL+5©ÝÀpÕQ ¸GßuѤ«;;-çWgóèp<>ËÝT¯p"aÞ-ÕjK|yÿ±ÜÖOÆt¸9ýüÕ.þÝÄ+µ¬<¬#èêlÞ`aÙò'`o.é(TÅA×ìö_ö.¬mXWÊ1ùAc"+Ó$ö6õ3ã\
+öÌ@¾Ü!rú;ã·ø{'É×'sª¦wFtqdÕÙgYçç+úäOâ*û¿7N:~~'¨1Õ§]Ñ®ïh{Ä'æù¹AÜ« \L¼ÖRd{JL:Eå+ù½Zo¼vO]léGHVî]º0ô=Üæ½MÂSåg?ÄÌÕì°ßUN¿ BÚÛì°ÈWIÂÊ++Ö$ºHD!ìÎq^`¨àh?úáà¹Î+`x÷@FCS5¿¯û¾ùr¨è°1ßN¼l¾èCx°`+uðË*VQµÖ»8ðàÀGXl2?ð-]Ây§KBÓ:y#¸ýw:Fö65«ÇÛÍvÃÏ$ÆÇt¶ÜnÎîè$â߸
½+Þ¢'À*MsrVAÌB ëHÁͬÛ)¿ ÊâÏåµC+²²Ê1÷UÛ®7_/¡R³ k&ÙàÍ®nûÂ#]· ƽÆkAµësn'Xza*
+ÏzÝîlm#ðyWIáO.êßQpϲ\!/øæÁp×Fì7¢Ù¼=|F[ä÷¬7YÅ&DÔ±ñ5m½6Î×ð3ªçªÞf¯¼c;PvNù^YÿZ¾{§pô©ê»Îñt[I£¢è¨÷uu"
+Ù¹Ûß,Ýlñ×î9k5äðµêFTðרßßm^zùôÙjs&
+RX×iÔ
+VD
ºCðÆráÊú/¨
+µÛ là·w%¨
s,JÝÊé>ÖzûµÃ糪È
!ÓOp(¨vn¬v²´øùØÛ»÷(2L¦mJýóæ}*qÓ?]2'Ngéiá»×1âMâª"-0Oɸtýörí}ñ¡½ùt%W k´)ó@ïÅni»ö|õàfÛ¹ßßóå7nubZ'U§àø+7ªfåµdKÌy¥WtЦ°`KCÏYËxWýØñÐN]ú\õ×°HQ®#ÛMõb[È°eÐÑWq¸EâjÅ÷iF'iY0°¤Ù-|*_\Ë?Ʀj°|Ñ®Î*h çt°çhÏú`¼?ï ¦¹Cî7EÿrôË¿%}Í}eMÜJXQAGSº2~Ä8D¹õ¾ËÿuÝouòh¡R&RmÑýsIDSb9¬¡¤ßªGöhÎF¡Ìüe»´B³0Oð+ÿGZ¦3H§vÚIµ»ve6&_¥/þç
+h¢
+5MÍ><EáFôë?JYÅ39NÝ!P{ðLd?n-üÈú0¥Ù
I$ÜÄ}óp+ÇÀèp4Å@«á#'3s
+¨(S4Jî'[ç¢gQ¹#ü-?ýv9LÄGqßÍYîD¢Ý!D®Á,O7ý6¾QÒü<ì·+±WÕûóØpÐ=±ÿ.{2z J¦Í!oß$(û xóÒ&W<
+qÜë1>4`U+qÔêjø!Áe§¾sp!o|K¯"Ãô!8±ô×9ÇÜûÿ±\Ü*#)5»^7vÛzB1Á{êq&:ùÑW1Fòh sE\C¥dG·h#
°Ò±P©þz{®iG?\\¿è¾:$2Ãõ£ìSõGN:Ò`lÇí¸\f5&͹n®õ¨Õô á?Ú¤5H×4?¦9·ZädÆê¡#òía¿FC?Á®]bFÊoÔa÷0|um¡×Ù%JG_í" Å¡D¦Ã~gxxÊçJ=8máQq¸äàÑéïø»`¨7&b÷\ø!íPZî$A'Þv¨ÚõpÇå%e9'å¬V¥ßÂÎÒÆÿûÐ7=ïF
0¯ì>µ-ø´~ïm¹y½¸2 rh
+ÊÎìÚSÙG¯rS °zLlÊJw ü×i¤~xxÉcÃ#ÉóÌôÖÑLk '_ÆînC°Ýu©]½1n|
+ÐøÛe9h¢þÊ:àú½Ó-ѤÉ36|ûyDik9Ävmå}â;OèñE *W~xdݽCReCÏÔc1nLq¤²|ÃéHH+gÍά9J=ÊÕÃññèR]îÁ¬èÂyBRKì0£5 ìxÕ2!'ͪ»«2zWLÎp=
+¦¤|êâÞWÁ"kæ¦n¼1Â'K7¤UÙìùÜÒ)aêW¨-»W6Þ]Ñ'C¹,<¸âho-ºóþb'aÛ# 2cÊÕß÷$<ÛÃÂ&nÙð¦KïÍã¥õu¬3èbSFÚ$Jzt¾Sû$ulC¾p8ñæ"òa2{%ñJ9£x±^É?4§¹-.£:PWúË{ÇÌ08U¦ð
+VL¸|#íõP>.*Y\õäQUPrA£úÅ.£ÂêÀa#:·ëãÔá4¿R¡ï@Ñw)ÅÂ;¿ÒG¬Ìé|¦F£ªy¿X8zvÑô:µxCS,þÆ0¤Ùý)ÊOM7B+ 06ªQ`+ÄYðââ\ü~òù W̹cбºà .£;ÎÉ\å ÈÛÝÛ;Ô/a*Ñ[æä[5<Ë»T÷iÁ`Zvt?þá H'Îå?ud
µ·©æîZ;ÓÔ¡Ýðø®Ï3éö'Óå/íÄîX2DÉm>Î`åÔ"
+ +
8`Ãê×[Æ Äßo}
+Ù}{k»;©Ø£nÜLÞ/Ô
yâ?Ö9ÖÛ×Å"¡"6äla¬0·Mm.
+ ¥:!Ú=>ngÞÍ»i#ÄGsWlÁ{¼/{Ëá
+ÏÍâ*b¼Û`Ú$Ø¥£Êc¡8ÕâO6¬TæóÕó+eq×ï[æ;»Ú+Åû
+åÖî¨buÛïéÈZËiz$>в¡çX*gK.£yIwú·[}OÐek¿¹QíǾv4¨dp0·FóY¼Â#]
+¨æAò{¶0íâY at -Q¾ixÞvJÚÅòYt3ØSà¡F¡{öVõ©
+×ý¸þÆ1Ĥú!?aziÁ(sÊçeú·Q5IW¥çÏáã¬WôÓâD.¤¦]³Áæ¹âkáé¡e5ý ÆÀFK:fö¶¬B±®kç"Åáñ®6äm\Jâ®zx¯+ýS"2$³noù=ºÕ¿a+¤¡Ç7l`-Ì4TVoöàÐ,Aìá³[ÏX ç(!a£ÿëÞp¨È ¿h(¬ø³¿ù©N¿G&/u[h7Õ´Q77ù &ñÊ ÜAìÍÛ¶mØuC!ûwÊ®4¨äÙK§*£¬`Nãó±Ç¡ø spøúø³ëcV-ÞtÊ÷ó¶Ôðäå8aÄáë°½Ip{_)[m¹än½Põ>hæ´ÜêÌg¶·LÓ5
°¾lð/y¡ul¤è-¡°éyu8F¸ÛmØVo2Å¿M[»aËUÙàê
+µLP-erWJ5æÛís-qô{²Û¸Õ <ÒjñÐíéM&·¸mFlßùzGK¨?¤\È
+*ìR$Ã@ê¶É´
+½QÃ×þb¹K{õÕ÷ý,É£Uкð¼§(7÷uc*¼®Î¿Ê¿=¿ùDæ*¡¢7Ï®Dç¬ÝËW¾ì?éW®Ñó^=\ׯ8Ó C«"] dbçÝsòOP|hÿ®y%
+ṟy]²+ÄNüéØ^Ä
+(¼ÔP¯#·xï¦\Æêh$ûôäÍänTá¦<Bß Fy3"e¼Íïñ{}FàX6QЯ
x´mµmàûØ?¸»/ÎQ9SÄv§²0Ø׳»h1¸çи§à
+â-N~v²%¦¡$ãg¬"exÙùnvßO ³aewÐò]pSÏÅåZ-ìjR4´^ Çã:b0²>ÈÑf¹Ã.§âõð`IºmLäÑÛ²YËó`¸8Æûî?îû`g."Ç.ÎYgð£~»¾÷;\Ñ£ÀàVL
éUò·Øã#Á
al5I|
¥á'áÉÿi»é\.]¿<¶¹,)¯Òwk_+Ço.îµ¹8Ý8£¸DÒx Ûp^úÅGÁnúsLSíªÍQªMr!¯ÒÐauªë@ì2T.tÕTi\µÛP½®½ÊzâqK=Ù¦¹Än~íSÌ»TÇø5rOë¿oW/s,bV9Æ@Qq6ýãò¼¿¢¾ÏûetËWõI©Æz}lò®î"xѼnÍô
+»óFÚ~`m£#ïfèöF u*ÌHyì"Éo×)Ï
+P"<Dîc ÑÅÙÇÔA±.>u®uût&lYÙë
+åÐs_VtfA¤^§:P+½¨ZD!Hj© l#ÎCú÷f2ÅÇåuíò~×Lñ+_¦ÀËõúwù÷×_?ßmÅbÙøùuÁÄ ´§,1*n¬/Û8´}OÎÓÊÚ|6êFuðÓ}Ü^´2+qÊ´ÂÁlãòü\i´a4öjÐʳn&6£
I`×^ö¿#r=È¡Þ÷TçÙNµÕÌèÐ=n~â}íí¾?1z&cË&
Dqm^ÖÐy01fïCóÜØ={u§<ÌjE+r÷+ã·&õf>kfB×®VH¿ÃãÜ?hXgh\«M§ÈEY`µÊ¤ñ 07%|Ó<¢nr-RõÙ÷X^ÎóʧmF±ì¢¾tXÄí?z6bùq¤+Ï¢;o4F%U´¶×Î2~ØÑ&×¾;ãdÈr=Â>Kô¡#ÐÃÆùÈä<áðù°ÃÏFöøeÂÙüaÇUIè#S9nº´QsÕ§Cö/ÙãñØ7£¡ûTjî¿ÈÝê92Þ-˳ï*CÆ¡´Â¿»Ñ|ÿxí"oe(¿Ûõ}CoÎ0%cíyð0
i+ÍK%éúæaYi8A?a¶ýNsRot*lÃïl©'Þg®Gñ¨hB½éÇ:Í@I²ÉK¬áïçBUÔ;:É+H7tNWR-D:µ´;`ôuFéÊämѵ:QÉ À+F»Á¨Ð÷÷y"Pèg7uitØÑu\:SÖ7 ñbÞ&é^êõ<³0Dx÷Ûd3"íqèD¤:Ó×Q
Hã·
+AO ÞiªRÇBuLWð5BGÚ%¢Öü©QpbÒDr~XÃÓ?S:én0Yüè}
g×gä4ãGwésN+´\ëÃ7bÆçÜã
+<Т,¾!¶Á-6Ãa¦F½y;bÆ>ÂÜ]ôD~Ĺ8ÕH@¹BáL÷"×}z]ò|O¢îÁ^cT÷\Ph¶ÀJزs½&zoàzçÌa=´ï·á+ÁFØíWI¢+Õq
¬¬VQãW¼O¤m»v¯\\hÝö¼<Ã!ü2üìf¸A[9«(γÔí?+Ï+Ió¸¾7-®scþ|4hòô@ÍËU^øx¿mªÏEßLòjÕå A»+Êw±åO)ÌS3cá4ónäγrèMÚ?ÛÓHil9#uò©Ü±Ó£49+W¿é÷}j±}ùòO2I%ö#z ¶¶v)øÅå^²Öí³ÕiÚd®.æÀ¬ÆK£G9¢Tª >ÑÃN9Ù_ÜèabI"áÎç3×÷»p¦×ùz¦ý¬U¥ÔrU¤¦~ØáAÏl8ÚÏ·E¸µa/
+P÷v¦¾¢ôù|'ýÆ{Ü¡yws'ë´ÚµGÉØtÆì36(\êû»T/"á³/2D©³[^¶åeZxÏXUóèµ4÷[G°ßûìÂ^r,ÖnTI¬]
+Bg¹Z ©QV2öXË¡?Ñ2{¬û¼8üÑ
p©``ieç<æfÇüUpÞmsbwdêw<·Ò¾vó|mE* 8|6$
~"uÿñå Óìk7Ó+ñØ@Y¡L½Z*h¬Ùó´«_Ï'ÔÅÎ%¹´¤+q'E õàOT%z×.¯ÛÆMÂô%yùèö¾áKq^'ò0«Ñ¿ÅD÷`ɦ<Ï*í÷ J8fÙå!@}¶ë4âl n$
ø¾¹öKû¬¨++f@ĤÀÆf{°©R²îAr±üµI.Ê;jè»þ%òTZIɤª|¼wéÉ°ºÿ}KWö_ü
+&nïûÂÅRÒ endobj
-11 0 obj
-<<
-/Type/FontDescriptor
-/CapHeight 850
-/Ascent 850
-/Descent -200
-/FontBBox[-34 -251 988 750]
-/FontName/NJEYML+CMR12
+31 0 obj <<
+/Type /Font
+/Subtype /Type1
+/Encoding 65 0 R
+/FirstChar 33
+/LastChar 125
+/Widths 66 0 R
+/BaseFont /NRYWIT+CMTT10
+/FontDescriptor 29 0 R
+>> endobj
+29 0 obj <<
+/Ascent 611
+/CapHeight 611
+/Descent -222
+/FontName /NRYWIT+CMTT10
/ItalicAngle 0
-/StemV 65
-/FontFile 10 0 R
+/StemV 69
+/XHeight 431
+/FontBBox [-4 -235 731 800]
/Flags 4
->>
+/CharSet (/exclam/quotedbl/parenleft/parenright/asterisk/comma/hyphen/period/slash/zero/one/two/three/four/five/six/seven/eight/nine/colon/semicolon/equal/A/B/C/D/E/F/G/H/I/L/M/N/O/P/Q/R/S/T/U/V/W/Y/underscore/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/braceleft/braceright)
+/FontFile 30 0 R
+>> endobj
+66 0 obj
+[525 525 0 0 0 0 0 525 525 525 0 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 0 525 0 0 0 525 525 525 525 525 525 525 525 525 0 0 525 525 525 525 525 525 525 525 525 525 525 525 0 525 0 0 0 0 0 525 0 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 0 525 0 525 ]
endobj
-10 0 obj
-<<
-/Filter[/FlateDecode]
-/Length1 1091
-/Length2 4694
-/Length3 533
-/Length 5429
+65 0 obj <<
+/Type /Encoding
+/Differences [ 0 /.notdef 33/exclam/quotedbl 35/.notdef 40/parenleft/parenright/asterisk 43/.notdef 44/comma/hyphen/period/slash/zero/one/two/three/four/five/six/seven/eight/nine/colon/semicolon 60/.notdef 61/equal 62/.notdef 65/A/B/C/D/E/F/G/H/I 74/.notdef 76/L/M/N/O/P/Q/R/S/T/U/V/W 88/.notdef 89/Y 90/.notdef 95/underscore 96/.notdef 97/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y 122/.notdef 123/braceleft 124/.notdef 125/braceright 126/.notdef]
+>> endobj
+23 0 obj <<
+/Length1 1140
+/Length2 5257
+/Length3 532
+/Length 5984
+/Filter /FlateDecode
>>
stream
-xÚíg8k·Çh£GÔ(#!º1J0$ºD1ÁÌ0F2z¢ H½A0z!"ÑÞKÂì}Þ½sö{¾ë|;×y/Ïﯵîÿ½îõðñèßU¢Â4PH(Xªê%`1q-(ó§õpý×Ò#Úà(@ð)$¸¢.@(Ì+xÚíw<Ûý·À©jµ£¶"bÕ¨ª½·Ú;"HÄÖRµWÚ V©ÒªYjS»ö*¥6Uô¦ýÝßóô>÷Ï{ÿº¯ü÷ùï9ïÏùr±ë
+Ê; í¡*H7OA°X¨¨m ¸¸ÑP;O8ÒMÉÎ*
+KIò^0 0,!-*%-M*"Q~h8ÌÉÈ«È÷+éPEÃ!vn at m;O'([bç
+4DBàPO?! ¼«+Ðà×@¨í
+uÁ@8Äh
ÁÝ+Z·ßæï#=;¸§ê¯¢¿r3øoÆÎ
+÷Z ±Øï¿Yý£²é+Az¶Ñ_½oÐߥ¤$ û¿ [ò
±eþ@0ýiþ¢@ìÄ6uúÅ øpù±® Vñ7±n Vùb5P ¶/úÄöõø±óü±^ VÃûÄjøü"ؾ~¿ñ¿/Ò÷¡ ¨PPD\ø×ßÞø//4êæùûÅ®ç¿Ù]f(Ô
+ÌL"!2¡ÎiuáeÊ
#åü¸
+°· :µm[HC¦q]÷kºó/ÖWdÒ¯¬³ù\0yD7?ÒTùöÄ=!}âjÝÛv=Ó¿Éô SÛo
+uë4d¢©nüè«8®îØâ²d³¢®½îí=^%£/Dóì8ï-¼_¿Ï
+¸cªéú "¬[Ý2ݽ,R,bÁ2ùþÂpH sqýí¹}d³õy!q~ÒåÑæØ}ºì +·¡)§I«]L¬Úm1¶Ø¸¬ÆóÊlÜhwBºÛ¸lvr=dzþeÆG¯s
çÇÃ>ø¬ÞjbATÂ, j%[8ðÒ¯,å÷Ør¼Â'Ô±&=kSå÷Ê?¦2¶k ¼#äw¶+
+h2Sï}·e©¯þ¨Ï _mï2ÎG'YݦîîvÐê§:{J~ÛU@èz'^ô¼¹½®y^)ñ-èC0òpU^¦Ï5>ó^§üy&!|ãÂØ£«è6ê<µ§N°/}õ`ûÇqpmDRý+Ç«heýNir!ÅÅ**ÌÆç¨|gOÊdõ{
+vÑ5+âNâòâ~ïpØdVºWFõ+Ñ
8ÑÒ3²Y¶G*/³t{bj~>ÒQÀáÎ&ñ
+DsÅî¹U7Úög>øüCð^øÈÔî¼~Óµ0Lê´Ñ=öÃü7\fmÍÉþùµ¾»Q¦ùèä
+éÙ{ë_ÚÓ»+|e«]ÃódÓWð®FmÝO°ü
ÖÙSÅÑWÁ§:¶{©¾Õªb´êÑ ³V*¾¸Gíxi=y¹52LGÖQdmÙorØ{jOÃMC_ý^OG~SÕ%Á°8Dqð+õIhêË#Û«ÄÏn Ì6µ¯©¤þ\Vë¿Â¡ Ù£íé#?
+¤º)ÛºxKkÂP»ÖÃ_@µpgÅpN~KjÅÞøßL!\ñ3&£OeÉnqíxÄãØî2²f±ãAUß?Óíb¨F2ôñ¾ê&Ãu³bËûº¤
+L=ù³ªOsOIè¡4¾à¶ùjé&÷ø$2×Ve
+Áð-ûr+ß=N>:¹Ö¨Pïy·X0ÄVVÙìÙËNKKíiP´Cô4³-ÁÄ~M)ú!~äü0W»w{m$&»fòÓMb~ßC71>V÷£ÌøNi^#µXí/³7rü»5¶
+ù´èt=çZW<ש޳ÍÞÙ¤YmYγJ(¢%öt¶G¢´6^ø#ROIhvH\¥6Ló#¤m%4§Ñ7hø,¤´w¸l/´eE=AÇàU%°Ë9 ·¼0B´Ú;Xlp$´è ÀÓD%-ÁoPpûu&[HÈvlh¢`û:½iYr[¶Úã÷N½÷p-£¬+`2ìÂÚi©fJUÛÙu Ö´6¨#û"²Íæ^ìÿPÖi%Ì]áãuäìù-Ë¢ïdø[FS´·Þ6üb;l_%;5
+ ½e+h¤ë*©ºÔÔM¬Mí²eÛÏsH[JMe¿Â÷_c|»!oÔê&?×ݤèc:©â<ÎMoÁYÞ=ìy7ülèåh$§Q
Ò뼧ÂñÀ\.1ÀÍ°&ò¨Þg:Éûq±2ÆEñüä^,ns@ï,R:|[ÄÕÿ$×n£ÓâëvêAÙåèç×"<IxÒ{ñv¾ñìKâóùZÀ̾:õõó¯q½¹[¿ÇïíÖòð
>;>|/Ôü2ð6ïTM¸éJÇë]ݬvåð¬¶XüDb±
+)%Õ1ZºÞãgÅÃCë2P.F¾£Ò»§ÕÕÏòíoi
-GBúжõ¦@Ò@o0°@à$Da)@BS|ö(4à×}JIAv(Âöü§rr%\
-ú·$yÁШ¿iq óø7Ø
-ýHAî°G0ä_Ê
-ÂN¶¿ üfô·0ᨠØo( 9üTøoHÈuþ
- f]~C9 ñ7 ο!a#Ôo(A8ûoH°þ
-é7$4êïó ?%ûþû4¨¨ °Þ¢R at Q B«äde2Òâ¾ÿ5Î wóÝQ#4W\\FNêÕÎ!1ü~AûÛà c aav´t&8±§ðþ½Ö«¦
-£ú¦ÜõéLæÁ-*R±1§°Pgý½qïúQÉGÜá~ºòqÖì%SÌBöý³ûÒè%Ñ5æ@-°¨zp¦´·5)Ýô4ãÚ¼ÝÅÃV{:Òí×<-1nîÇÍ?]ÀAìFÔk'¿´9¨ C¾W
3²zVH0ú"$CÏwDý?Uk:UåÔd¾»²7¹¤©© ?h5ïÓu-±²°ûð{'µ'§"óú³¯Æ,Ù<vK:MISVö;¹àJ
-~%
-Ư[fä-¢
¦Ó#BR·wÚö¡q\R×-¯(6õwwq¯Ï§³¦Þ;ZR ݺ7ö!¸eÅÚºQËá#{Æ*c:~ÏhÖÍo¦K
³{'ÛÜ;¿úaJ~Æk¥<kÇ$þm2ó&Iö'ªòô¶tz³Æ%&~ê32þ¢áZ-ë_<êÞ~iÖZ£èÓ"°X¢Ïj5Vôýí×¼ÏÍ2åÒbØoSn,óJ
å%§ÿôè[Í Øc(D@Äüà2X ÏT¸e踬ÀÙFûªÀSçâÓuvçÊtÑLûÑ©ÇL;òØ!Ù£f>§µ34äd» ùd{³6§¿1Ûä*Ø'Õ¼?ÖÝÔÉ9*3ø{¾_j4#ì!`*3nLµX¤í¤ò´Ún\ÝbJ^ò@$yÿpÓÕÞU>>\òNppìèûev>»téîLX=n·9ÐäõrçØ&4S[çñÀåÔñ¶ëêC´AR§Riin+ÕdÙsV®+LæEßþ/¾óHµæÉ-@(ÉdººÎÇ,§Â~içÌC{¬öºNpAÞɨÖÒ?ïÊе§o´Ê8zCUg½±w¥KàYî§lõ$ÏöØæ|33ÅxË.#TÄûübaâulÌþ;éWã_wk¸5²¯ÓZ¼²®¾ðhÛ^:çûgc½¥D®¬[JÐuìU¢`fBÄ'ÿ{îâ[R4/öîºðÇ>§ûÒ°Ïî=À[Û9GÉcóS_ÕMX/³¾Í£oqÜ©üÂUÏr² $Mü¢y¬òr%NÖ$ǵÔø~¹ýþdøÀôö`g¡Ê¥ùüÌVªÖ'ñp¡Í'²ÞhôÉo÷×ËòµüC{ÜâÄO8駹A]{,C®%x9ãRme95ÒZÕ.©ô±³xØXvÂm+¦2xñ~ØR©oS û(ß@
-Ñþ@9weÄ7û6sR)|ɦÈ(îÊàLhù:§¸tãùgµ}Pcî zò@æq¼;µ&«l.SIZf g Î
-¤ ®FnEnZ÷-?hÚbG½È%³Fw[ÿ¬U½¤+I~Oÿ<\Ö1·Ð2~ÕXÝÊ¥§rÑX^C¥×åi«+Þ·´þ4[2>¨,&Râæã
y
-Ù#i" u%óVP çNVâë-s¹'=ôW·4¾ºð-#
-}©å'KÔôß,xººZ
ó#è
-¢m+G§VÕ},ËÌ÷©Ôî²ß?Τ_ÂÞ-ÿGÛð)_%¶b¡]ÍnV°Ê#Z¥Ð¤¦vªï)|Y%ïÉÔÄ6GkÏÖO¼üØAb¤
K=ÑÁE2õÂz¿ïb§¹ÀÛ9æs/ï÷å¿~ýaêMÒ{["¥ùÎ7°âËøÔ² ËesQ]ëT¦
-Î!Fò4ªj?¾çªãü$ËÀlE¬bò÷ã³Há·
-ÙDL¶ÂqÁ|û¶y^̾ɷå¢Þºd&|QJ>í#³ò°Ên)
-¦hº¤¦È÷:½Üîz#^¯Þ-mØÔ4÷4&È´ûALc ûÊK½éfê3ßv%
-0ú¤n²îßò
-^.xÉ¿uSwéÜKJº=¥·<AD¯SÑ
-©#ªâ¿58sQækîZáCËë{¹qZ
-h,D¡ä?àB$;Ê/§ïÓÊ.^ÐЪ¤rð¼4£üïö4ÛìÏJÂÅãÌx¹DÍ{ zjâÜI¡Þ¯Ïk.7®q<W £ÓTM×d]¥ÞB31¸âI×
@E=-éAWT¯ìóPm~'ÖÒÔ+â\gnö<á³¾
-ä´þá£æpìý 5uÑÚ -ô
-çDòtÈJf<Øfüy&µFH(-ÜÉ,ºUG@ºÓÙ_:üva×àhì¢y¹A~'¶gýsê½ëscjü5 M¶í¯÷%»µPGLda\³
-
-<Búj:´í«Íjõ´È0é«ì¶Ûmùnߢ:[¥jf¤j+Ðñâ{04ÓT
-ºú³ Lzè2!|kS
YW2¦ÓµYÓ[VÓ-[\àÄüäÍÒKÞ)KõN«kµÐo 3Tê¼@â=éeêHÙíY÷v£}MK>©~MôTý´YôTÕ
-ùqÆbG]D$5ÜÔ¤»5æsò=ǹþ4ÆÈųͬ)ôÎd$Ô õw^ÊYê 6Õ§[÷Wù^Ë~©µ5oAnÆ
-ýÂæÅ_üîpéî0Æ®À[´öãsäIÅIm¯¼¬¡Ä¤åº~+`?/düüÔ½~nWº4ýÃl«nÑÐY$f
-ÖJV@¤×+ª¬wÚz¤ÝëáP>ÇÜZ!?¿
-¸ XÑ&9(Ö_WUÞJJëÆZD5¿«WUròª)RðwT$
-ó¹äçãZ|Ã|Z*~±äk¶?¯{üEuÔÇÅç#W\õä`¬3î$Hé2¡øÈ©ÓYí4©Â¸BêÉN+±·»gpÞ-W¨Þ{!ufâx>G9jÖ^¶Ì¸lÙ}~õµ}ÈâÒü+ÔòhbgjSÚeûâ|[»]bù/6AüfT1
æÄLv,»~By®oz)öñ5z4,9È.¯o>ýVÃêÐ&=»sb«o]aéöT©TÀ|G?{s at vÞ#ávíMçkÅGÙ¥s_èÃ*Ý«;w¢)r8'CîVjÆ]p²èÖfµ!G«ßq~j1¼ØtËÞ,·GðÆ@ñs¦»»4°êò»Ú#uÜÏ.ß8úµIlhå §¼-óiÃ/ióGü*V®bN
-0{QN¢´Øæè-ÈÒµQÕl¸áÚ¤aZÅgëé^ôT½Ü7NÚ\_;«Üß9ÐøDÿJ²å»µgý ¬ÚsX>ÒÃÈáy¦¹l£_×àQômc£äÊ®|âåÊscWHámóªôLí\È$̸/³·v)z#+G{uRûþ2]éx.CÌ¿Î9Ú.Qk/°²3h.fÓì)rõ¨¬oûÁæbê^^4ä}7ÿÚ»6±ì8ßõR¥ù¥6ëÇ_}Fr¦Û@gÑ*L¯]Ù¨Z/´RòL´Êö*©ð^(¾ÀYë²\Wþ±ýò# êÀå ßE,òL°Ù* "ÂÔÄÚ_ye''ÝÍ[üwçùÚ»íZz9Go\>\scïób
-M\_%.ñ3°Z»ÝÌNêÂqdº½0)ÿàuêE![ÂÕø<céÎIã>z9XÅ9®ý(})d}+[9¦)#æîBKç²À=ø|Ïp(8bĨut?¶ÐbµãqÒ
æ]SئðQ]¯4öOÉÍ®ëÿ
-ç8ôj>+q<áPÊËZ"U´HAs.æÍô)>Ù¯%¡j83L ³;çë¬Å
ú[ýü7óòçUQkÇ#@ïohã&ªÖcs§Ùòø$*±¤»=d,¦7ëúö{FF½A7?ºÚê=°Fø»Ùø©LÑùÈáoúÆÞFÃÉûW¤INôöN7©ÌSÖ2ÜZniYã÷)é~_PV&k-äN01æ/òg94Z#ÝêTéL
-6ìÕõN?BáÚnODvR
-¿_Ù¹õ8ÃÏD¯»øñ³2©ßv »`¨» ݵ7 ¡±P=± åõï÷p
>÷eÇFO3ïf®¨t)vS½3ÈQݼS¥á$Êáîê5õì"o5V^Ño£1JöÕòæl)çjÇJi»m[õ¥@Ø
-ÙÕýþî¢j©!ÕçÇ+I=>µÕ{ ¦îþZktý¥áÛ½7bàýÝcJ_MrH6òWJ±´·ëÛXýi\j69#¦´.x5¤õ᩺ÕLùú9}yõ\eD2vÝÀ¥}}eþtéDânòè~9#aÝ{mÃo1¶Ëò1%âÉ dÕöxQ ¿-'Ø¿ñcÊÞàÓÞ
ÝÔ?"¥¤íÄ%(Ì@ea÷£9C®Ô¶q¿å§ñ~Já~
¾q):$§¼Ü¬A«óyY:¬$õoÄÇ5-endstream
+H_Dy]Ì ïF\öGÖUÏgÕ>©Ûl8áë[Üí{É*NXäFÑáÝ0ÝqPaÌÍ+¾yWØ÷éá)½*òÊ×7¼ï {©á¸À"ݹDë)Fd/L6Ë_o·x1AmØ_D,~±HõïKyòRQ,ûXGëê轶A®nì:Ãó*ÝôóùUZ<XÓþZÅõ¼·JÝÊCN>`é.íúJPÈd½6ûDJ¤kÃùu´J&l'"Üjº= Z;j\/P\ë)ãbLþòCj=Ê¢ ê
+æ¢ù9붤ÙÑk`Üά:GMÐÇ9±ævXççDзܹ0¦§¼~MYÜL¸Ú2¤äùEo6/óνëy_ñúán¬z)UÞF{¢s>=hÓ-Î*äA°(.Fìå {-Ñêza|$©¡ësÍ+n®eC½%GaïºÝWæÍË3Æo¿Sâ+õ1em(GµådÜ?Cá8Ýî»)D2¯$5bÕ|}ȼM3
%ôÒ4é´
I> K,ã8HèÑ{ç6#D£KRµÿmKaâB$,Ë®|ÔÖ
íSúSà8¼]G{epEôí±X©áqT²TwÉÊÐ_æªxùW[½M¡Ðà {xõ<pÕ'(¹æM!ÝeÐXôÝ:Vn¿VÌêþh¤;!Og
ånQw5ª½Ñ¬§ÛHRä$¦Y`¥È
+Í8 ¹ùÁW&¡Ll3PéõÒõªsÛôÚ¾
x§¥H(Íé×ìV¥ùõþJùT|lÞ ëVAQo©Î¥@«ïüq6|»
+
+t0¥5Ä|{JBÛÐLHîߣúÁSþÑ×ÊÃttÉîÑëÓ
ÊøùÝ)>zä+q*Ø6ÚÈ(yëËvy;
+¼'~ÆäçV8HåÞÔì}N9+5úô.
+.{¤Ý%=ßökËmq]¡ÙÄllßïîCÔAð¬è¬Ö
+R+¿NâO\ïM´_²RFï>Ñi#ØË
+4^0*üJê~ÿÃV(n+-hï~>K¯aòê'£U5»È*ï z4ÄméÑ 4³y60qû_¬<Vz)u÷m±ü @lC1å|/Á*}P@þõý¹k(£5ÝZOô±ÀúX`[î¹ÇÊgz¾îÑÆxY«³£µ(ñ¶°<¤/wØÙçû£ª]+°õ]3oÖ=H¨Æ?g´ÌgtnPë?Û¹Þ¤ë $OÁieÙÓôF7ªï*ìÅ\9<ks¬ ®ýÞÈ{Dkè©ç%Øzk¡
+j<õ
+Xm=ÿÙ}X6$Ö¤ÅÑHhRËåó1]Lðãí ÕÇç.:ªùû¤³
+*T7»ó{ÆÙ)ì8I&ËLÙÆZ;(MÛv=Gº>e±$p¦@1aMô¤ëäûRËï°ç.¡úè»:edA
znçãsãÇYé[ÞtgSîD\ë$>y+2`.Ñ0³RSÑð ·S×'f8Ï|ÏlÂ$ÓÒ2öøF+,ѨÎú-]¡F¶n+Bg|6Ø]pgèL&gIÖ¶/Õ³êH¢è¿ézÁÙöè¥y»Ðã>@]}ÍO§$æ[9®ÇDAÝÊäõ¨'̪絰F͸ÏPþª÷¹Ôò*äøÁê[
÷|IKÆ,PF²7ûµ;Ul"ÅÌÕÂCã;à¥7V£R
ÿÀÿø?Q+µC{"vhÀ endobj
-14 0 obj
-<<
-/Type/FontDescriptor
-/CapHeight 850
-/Ascent 850
-/Descent -200
-/FontBBox[-53 -251 1139 750]
-/FontName/SFIZFA+CMBX12
+24 0 obj <<
+/Type /Font
+/Subtype /Type1
+/Encoding 67 0 R
+/FirstChar 12
+/LastChar 121
+/Widths 68 0 R
+/BaseFont /CPLBKL+CMR8
+/FontDescriptor 22 0 R
+>> endobj
+22 0 obj <<
+/Ascent 694
+/CapHeight 683
+/Descent -194
+/FontName /CPLBKL+CMR8
/ItalicAngle 0
-/StemV 109
-/FontFile 13 0 R
+/StemV 76
+/XHeight 431
+/FontBBox [-36 -250 1070 750]
/Flags 4
->>
+/CharSet (/fi/comma/period/E/P/T/a/b/c/d/e/f/g/h/i/k/l/m/n/o/p/r/s/t/u/v/w/y)
+/FontFile 23 0 R
+>> endobj
+68 0 obj
+[590 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 295 0 295 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 723 0 0 0 0 0 0 0 0 0 0 723 0 0 0 767 0 0 0 0 0 0 0 0 0 0 0 0 531 590 472 590 472 325 531 590 295 0 561 295 885 590 531 590 0 414 419 413 590 561 767 0 561 ]
endobj
-13 0 obj
-<<
-/Filter[/FlateDecode]
-/Length1 1300
-/Length2 6348
-/Length3 533
-/Length 7162
+67 0 obj <<
+/Type /Encoding
+/Differences [ 0 /.notdef 12/fi 13/.notdef 44/comma 45/.notdef 46/period 47/.notdef 69/E 70/.notdef 80/P 81/.notdef 84/T 85/.notdef 97/a/b/c/d/e/f/g/h/i 106/.notdef 107/k/l/m/n/o/p 113/.notdef 114/r/s/t/u/v/w 120/.notdef 121/y 122/.notdef]
+>> endobj
+20 0 obj <<
+/Length1 786
+/Length2 1538
+/Length3 532
+/Length 2114
+/Filter /FlateDecode
>>
stream
-xÚíeXm×ïI¥»%r:DºD ArfÈa¡¤A:¤CAIénnABºÞ¹û}nÝÏ»¿ìcÛÇëËüÖ¹®õÿk×u\ÜìzP¤5L@
e-ñ©F°¿Í=DÂÿ:Ú
-nQDØÂa-
²ò"¼
ö(Ì-öG-HX³mèÙ5ìÄ°ý1v ÆýQuü1²ð?£ëô
1º?£ü1vþ1º¨?ð¯¶þIýn Æû±áñ1ïÐßóú§ûáC¤§73d æ0JcF äû¿& ì]Ü`êÊó#$$ß_Q
-C ÿõ:Á<9ÿf{Ìsy D´öØ÷XN,[&8ê¾Lê5î¦æÐ
-õÃñ§ÂBõ§I/¶õ¢RÎyÙ^½Ðk95o÷òbú0GÇoÓß`º|"S½¡®2Á5ïÁ¢j-L+rĽÍñÉç@sÐÎMìÕÝ/f Lz§+V"Vë±d `Í,ÓO·JPj¯O"Ô¾N¢!×G~cjëq#'Í¥ÏØTkæe£}ÛwÓËõ)S*¨~
-úÝmÄ%¢¾eùÖ¤×yÎR½î¼æó(++s©%kÂ?*'J½ô+Ñ,6íMæº^©ãÕ籨2ÆYx:ÈØ#ý
Z£+¹g dÅÐÑ%|øg©E¹¸´sEÂÐc"»ÃO¸fÍ--%W¬òzñjÒßV'F«6Þ$Iî/«ó ë,7¦»Åò7¾¥pgØ;=ÆßäûsׯðÖKO¢^u¿`±¯$Ò<b^ö¡éÔĤÚWëý¡-oþ^ËqsðÞÝÈr~3³ü`¬z¡ÍìeUAãðtìùÏåëÙBÃeUñÜÜ5[o`c~Q¶Üz`¦! Ì$,uºêÕ*_h³éi±vÚ(¢Z§*Ðð~r~©¤¡ÀzçeL¨l¹a"÷{:e/U|òîAé½üP:2£[.Pµ%&²ëðcèRóüÌ& X3¨+
-ÿG\Xíç®ÃÈýÂjþz®ãZøüÇÍ÷1Jðr(ØÁRm.¤XÔ,]î|pge÷g¯Hg¤ÏòÄÞ-¬¥¬YHM÷g2ÞoùC÷©ï|âÇ5j°2yW${ù¤ôIfå/¿P$F_Oz,ìàw`»ÓYf÷Iô¶ÆôziãQ-ôV\{dZÆß»ßu]-¤0'EÈY{®CÞ¸ÝlÛTÚ¡â¨tø¶³<j\ðy¼W4IJÈñUÙIÀÜ1ÙUá~=o÷òw:9Å}Àj£±ÝÕ1[Ú«1¾*_y&g-sãéý2¡0¨®Ö7Dñ"·1¹þÖÙlÐóùÃýtëïl >ýØ\nß
-KE:3p£ÌDÌåN( ÜB°u®¹JÆGì5v;^û¨ñBúA/=&å°x«ãJæ¸!¼RwÔwú&Aú7¥[ªMôØx}*9BÈ´Ä°bn¯ùµh»ª+ÆH:]ÅǪ}A¦RÐó|«ly®*rØtsT«!ÇïNóÜ0PPyDK¼¢/¦>£©©ý Ç}Ý_»3Pp;´Y=¿ßp¾ÃààÒ´oMjÉ0®"=ªÃéúùWäâ±p'Ù¦ø(-û
-GùШËKf¤ fÆhXE.%¸Ã;hGÒööª8Ú¯yI{óúÖ£ÑÔo¬9 äMôø²·S?c7g¶å:ryëO¥0¡7
-ÚdBhOxOÎûY:)Eï2à*?J»UÎzÏtñâ\Lí9°DjoþµH[TÛ§©ÁxÙ§_óêdÒ`½åýw¢G%ÌJW,3R©Ø»eP:@¯åµîÇÆͯ-e³÷V¦ÝÃT£/£¯´YwÞ/Å(¨mJk[¾ªN`âéÅR5>²Vp'
tRëbéS=¹s_\
-]70Ô>å¤dw÷JßÇÅÏ¢iXK¶L-±k6¼°£7µïèIT×Ùm]ö-,EÏçíí¼xóÈ}Ñí@÷rËâ58ÌuTÏãkC['{æ;ê[Ú¨¹J6v9LàßGÄ=ëG¥!^FÒJÕ¯yyQG1|&ßæ[51OØrOcSÍ·]i¢½6DëÈ iÞ{¥WEhîÒ/%½Üÿ&cãïF,Ý)¹d ÆF?úºúMI{~B¡pñL}ÿðÂòÂ}"4[a"ò/1Ó8Û]Ùma&ýþ½õgE*´"HÒøÍH-MYám
-Öá(ð-|tÎòÑ4»ö:?fóëWò5ö£`w²Í":u:µ^M c[itÇJ×ÆÇ©èZª¿æo¡\'ÅfU`hrc
-ÝÇ:àH¦d;ßg@X®û½ùFÈÃ#þ÷®æG<\ñý¤üìÜ>¤4.aòd|ú~\×é¤ç]E®½5Þ÷.ôôzO¤Fõ4¯hÑT´¬}''¡µ[¥ßRïÔç±éjCåü²:Ê+ÖTñih×CÃÌyßñ&ZpÍ}9¬´o«¿GuP<s9àäa_ÎdUÖ1Ó
-Ïemk'-ãó1E°HÖD4 ׶·¸O`£z¬>;S[¿IvÿöÔcÈ
-¹C°G *·´i3|MLÎr[Z4/øt'o¨ääRðú²,iWÒôà
- ÐbÞíndϧ,ZÖíôj9±Øýeý¾?Ø 5qrhHÈ-¼«-Ac[ñêñצ$ûÛ!nÝ!ZZþÇ°W½úkª·y·'sܳÌ8öuºs5®ÓoîÝ6¸Í}¨å÷FõâeçnbÄÅGã$;ðÝ9ð¤Lë³ Eÿqɦð(ö
JÓþË(0{Î
-þbäÓàÑC¶§
Sð×0<iòNþçC-7Ë°(ÅôDdËÛèZÈA,9/S¥®Ç°ðëÂ#zF̧ªæ-iò«M×Å!c<ÀÊ$ICTÚÃd±z¢Tíu6u>¹Pó×VhÀRîJlͺ%<p@Ó²¨,brñ*óíëh³<Nà>á},ÚtáûÉóÄ3Gg®
t-î¶Éã(,à¥ïûúÁË_R¾æóäk<_
--çÀ?;#hnGõº?ìNÞæ·È,ò«=öylF
¬Z3ËH¼>âc+Éýª[¹æá
s1d²+QíÙKéY¥Ms¡T÷«±<S'¶K½5Ô^>kO`Ë](ÝoY®>ä¡5©Î][ùå@9{_)SâGUBN?¿â¶yõibȼ*&Hõ û/>Âõ2Ô¬}ÅÏ8éjµýr0-G¦Õêò=´cZ}Ü]$e%XÆ3Pç¾7¬!÷«.0mlNb×zÚE·ÜKÿSݪ̲è|Üg±kFYÅÝçô§ t¢*§|íøÝó»iKyúßäW¢kÐ[úP¶P1ôÔ&®¢õë¹ÿI¦Çóår§uN<_ø£&EVÈ!¤Ã{¶V¬}þþNBÙñVÔy_ýkå«ÅÊfT~Þ¹ÖÔ>Vh-H£]5{Neè³)i¨ÊÞE
-X:T3ÃjOkÎÀ'N"ëq».zúÊÔÈéîã7¶í¥£ãûhõuÞ¢Îk»ûpTD:ÈûÆ«9(fEtwÝ6R¼ôÅëxkÑÇF+ô¸!N½ýÓAoW Ò¶ÈëÒoÄòü\ñ½ÃZãhIVT{`9Lù¥EnÝäÎó7'Ĩ;®VÞ¦ ÛðÇ)Q¤V"bÄmåìÜrýåBWU¨ÍçK:G¥E=úHµ«óä¤þ²d5DôuRnõçbÒV¢÷r9$¡aÖÃ,ás1-Ur§hõ¤¯T+)GÖbï´þØ°ZËÐnhµzæÞï^/ÄÊXÙ"ЪßKÙò¿$éÝ»IiF[rª]î;=4»'ÿQÿ±iåv7u"ËÍöQ4ÿìàÚ«·Ä*Ýï(¿¶@4_¼bþy¡_áã_ÍùÄ!_ÂGÌÅA©JµFMhéúàð¼Ýô°³Úpõ¢Tüg¯JL»pßÞo¬l¿N at pÎÄwõ¤YZ^8µb¢(%üÙ-giû|
-ß鳿È.ÑG¯Ûl ç»OÎ%¿o)&@±,ò
-:ïlówN3´}
-ùj~§{q§§R§ý|RQkÛ~´·#
-
-Åó z=\ØÑ4mõÄ1s+¬7©#§»I£=ÄäÖ»é3cuéz÷èêWá®ÐCo»>Îpàcµ§Ã
-|×â(*»XÆIöæ ^
-ôâ:QGSä1G{õÚ³¶±Î®'4õC¶¼6y >ÚNÞD¹ø}Ãï2Z¡Tâ7su
z¢]pɶâì#èþÀsÐþaÓ´þ¯×±ÚYÈGf¦÷, ¼.ó±s¨!B§dFâÔ©+ÿ1ð3q$ºÞÄÉÆ4Zº¡Bêi MäÓVÞð@pt¾³ÔKQ|áól}jn
-;*-°MC5ý»Â«æÔPÑÔ[¥I[âYïö·z^9i¼;%Ü0¹dÄ50ìîù¬ýXQ¿íùbQ(YªD-t²B9ýDY$
-endstream
+xÚíRk<TëNØiTD©\Ú«l"13×Ê1î¹ÌÓ¦R»1³0ff
+kf0Ò$]Ø~Ĩ:¤Ê%íR¤Æe¶\cÒD(Õ¨DØC§³Ïi<çÓùw}yÿÿy÷YÏû×Û÷1¶§0@g&Ä6F m+'ôk+Y2S̤! ³HaBt.@H/¦ì.Pæä¿aê[qgîEb,ÊË2úKÄ Ò¹ÿè3¡6L
+CßR}Á/Ö<A
+Ãø¶ëÆ&Ñ©d{(¨/%*Ë RðT69$ÑYàR(ßŶdIðtt÷$-½æRO¢Bl"7ô¢Ü%þ˲©À
+
eß×ÝÁo®rÈL
+Æ Á0Í
a#h
+QÀH+ã2:¶³SMÊÍCøî^úvÆÝçRBÝ$ßÿãÝ2o´-þ·SÞèÌæêáÿVÄW£^ªº sä$J_,*9Ì/kU^ÐâÕ\Úæe%úæâÛ([>ĪàÞ|[¹©Û*â¿ÛWÌÒl¸;í¥d$áèrÚ*ÒsåmÄl'Ýd¡TD;×aVL50èÛ|©_ôLÉZár_p×uÛß÷ µ'5ÖjÕlh¢9d+ÒCL±Ê)àC-ÁÜm¹U¸ÍÚ£oE¢*=¿¾ÛSâ:E,^è!ÆÞ¾UykÀNwfLÇØ´oº'8ýáÚYòö©Òg\1/¾|kµ±jϬåyx÷yùª¼ú*$@wÎEýñÿ 2$Ál&Ó endobj
-17 0 obj
-<<
-/Type/FontDescriptor
-/CapHeight 850
-/Ascent 850
-/Descent -200
-/FontBBox[-251 -250 1009 969]
-/FontName/XCHVXE+CMR10
+21 0 obj <<
+/Type /Font
+/Subtype /Type1
+/Encoding 69 0 R
+/FirstChar 49
+/LastChar 52
+/Widths 70 0 R
+/BaseFont /RMDKMR+CMR6
+/FontDescriptor 19 0 R
+>> endobj
+19 0 obj <<
+/Ascent 694
+/CapHeight 683
+/Descent -194
+/FontName /RMDKMR+CMR6
/ItalicAngle 0
-/StemV 69
-/FontFile 16 0 R
+/StemV 83
+/XHeight 431
+/FontBBox [-20 -250 1193 750]
/Flags 4
->>
+/CharSet (/one/two/three/four)
+/FontFile 20 0 R
+>> endobj
+70 0 obj
+[611 611 611 611 ]
endobj
-16 0 obj
-<<
-/Filter[/FlateDecode]
-/Length1 1867
-/Length2 13928
-/Length3 533
-/Length 14981
+69 0 obj <<
+/Type /Encoding
+/Differences [ 0 /.notdef 49/one/two/three/four 53/.notdef]
+>> endobj
+17 0 obj <<
+/Length1 786
+/Length2 1532
+/Length3 532
+/Length 2109
+/Filter /FlateDecode
>>
stream
-xÚíµeT϶¸»N qww
-®ÁwwîNpÜÝÝ-wwà6üι÷$÷þçˬù6kÅêgW½{?µ«ÞjrbEezac[C¸=33@Tî3I\Ôt2·µ:x-þ³¿³ù_ÌùÏø-dòWù¿¢ÿkò{v#[kkàÈ»»ÈæOãýÙ÷*¶ÆB\-8ébïTÛ5tbÞI½Þ:x|bºàv$·44R@ò2@GÜwÏYªV/1ã/Ìl3.æ6g^îU'Nâtâ8JEögg»Zd´}PHüô¢yN·;;J¬Ù¬Ìé8jÖí`Öù1?#ŧ١mrk¯D²(Ëzíúq3·Ê#9ä#ªÅ·-ÈËrñ§/ a`à*¨*²üR.\Àñ¼FHÌ:¥>ÆÒ£Ö¬ ZcJX)(Ç.ó´âoñ¥b|pOáȧ-f²=|Ý·ß"Pù|bºúG~Þå±ì?¨RyL)gx=¨w*z¢!xN·,gíì@ì-ÑÛ1QÔ U®ÜúVü¬»ìUÉKbÑALÄÀïõÉ·)dL£0jéeº92"ídÐiQíÓ§áÅé¡×UnExª¢Ý4`/ç/H_×EraºN7Û2Õ
ÚND¨uÆge~né[f.<ö}æsÄvÝÜ+«ä,ÂBëÀ?3ÃÁ¼="Cô:¬V¬
"¶¥X¡¢|BjÛÔ(DÌmZ_ÜìCÉÆl0ôc$³ÒTsî
ÂSóÊwÈ(ßO|YäëÙæ1ô®Nðæã¾)m2ù_ç«OÃ^º*)ÓÌ£Ñ@ýàË-}¶ø
-ËLÑN¹`îTGñ;ìÍ°7ø*|ÞXevÓÂÀà:w5W«Q¨Ï¦
-æî~³nÝáù¼Ý©±æ>BÔ¤a@IÆK{¹ üC{ö]§t-Vfú?ÒÇ(B>[ÆÒÂMdûòCKZs§Yú¯¿|I¢ßÜ¡<ÚÀ,Xé]jû6P?½xgXQÐøì9SàF)ÝØ"#ú
2Dê;UE'è+kg¡ET#
-¿È¿ðò/ó7 at n¾è²,´G+zµ®
Z§Ì¾y¯uv?±1'l
-Ïç'®ôÌÁ@æ¹àkÕlTáphuå /7AZ#m+àCºª>A{\ß¹D\<0ß8ÝЩ1ðûSöo¹Võn
-ÜZé9r£³.ï¬t÷± îª6 KÇÐ$Ûd"pÓðw&à.ñø_©¾Â²äºSâÍ
-py4°Ý
-Iõ1üêò)ÉAú +&táLû¢'7ïÍ0C9ÒEd§h©»®4 e¾"hÌPJ
-ç\g]yÎé¥Í1 |©F2xÆ۲ʳü-OksØUªÝfWçË,ø}cúÓEdög«Þ~ʶ(¯ÑhùXîJ0½¶Úßí* ,û>²KU%t¸,,þ*{]N
-X¨¾5/³æ#3ýcíäü XEÁ¼ãÓûCèû¦%¶`bÒdáÚ³Ç2guÂ=ù*p%ÔÄ2ÌÊðFñäx®75úð£»îØDûâ¾ øêÑç<·vߣ§d»·»0±FYGåÖ"þ6 OHSÇe<åýJ6ªóRî12Ê7éáÎ÷½%j=Æåøôå&èêZl
-]^ dÞWì¬Í¯öG²ÚYªs;w{uðmëÊ°YDVç®Â¾®À
ðÐ[ø´£Ç§ù4Qu¹Á,hqîö«Ç9:·×DöVÒ±¸
-¡b ì¦ò¡)¢ÝµÎPÕ>r¹vsïøaL)Íuz;òÍ
-^[1õ¡qtºèÅâ8<Y³çWö*òKQD½uݵ%É!tBA4X½îJ>î« p9¬ìg¡«ì ñyÂ^ºóEâ¼GÖ9º¯
-xnØqÏ1ËÅYÍpâw^ìß(:X NPkYy³Ñwü¬Öð]æ&?eëãy
kÏü\ÞÛÛïè+VnÒsgìÞÐ#¢öÝèxö-ëZvïrg³Et(>åèì®^n":ºÙn(rÞÅføv¶OÞ4µ÷~|¡Îu¹+àj¦8»aË}Bè$k®Qݾ~èdÉâ6iH@/Ùk͸Q
-Áàj ¦×øÈþËù[KrGÕhÜ+E¤Ügµ/²)È%Ðpîñ>J¶±(%QG¡xbx«zì)«|óÛm¥îCTñäP¢iñ,´ÓÉØiÑ×þáMÕ®õB!^C|z·8òfGkà¡IÕ°LãD÷lîùl(Íkz·ºnYÚΩ2½w`Â.ûÝøà.rÀiv´¾«ÚÁSaÔ>ãìÄd÷Ö 8? ¨[#¬³ú¬ÃK
-1HÕðF#\Ý°&äæ`ÛÒê#ì¿Ý&ë].JÉLÏß,G8kÇ$9ÎÒ°×Xiã<"Bðîi±ßFÀ!Z
DªÔËu¸nIa];d¥h
·@66>R¼¥QÐö'¥VÌs×þÆ2ejóDÏõ{¬1<~¼¾=çÓÞg-涾ÆffÏDzüsH9åÓF4C ;:ÚÄÕ¯ôe\©.È9mí
Ù°µK0Â`¦Op+H§ÝÊNÐl1UëYG¼ìÚ*X+sé>v¨ÊTã§û³6Oû4´ÃòJûVÓkÍ
!9ª~mV½õÝ÷¨U
-wdÕ°X*ïÈÃ>÷Ôéä@\l'Ð`ªKü0öÐBó)§¢|÷£sßúz&öø´°Ïá
-Ts8ð{ÛàK°ú÷èo*& ¾¤éÉûEm:-®PwýIØ\Ja-ÈÇÔÍÞÅbVìHµe3bä!Ù(\[,UQpBRÈ?hÓmPZ¶&s.=·§Ë#¿ï@¶AÄx«F:×ìñ¥d©Üwë¼J¤c¹AwO^K«PE殤ȱ)>ÆñZç·ú( Ýbû=p²>ܹwAoÇÛoX(ÃzÈA+±1ç$Nt¾ÖüÒÁÏJ\$Ô»ùöyIf#v²æSf%ï;ü®ÒE2³VöóT3æîC¼9aÜÚ£çó.õ_ýO`0L´Õ¥u¸îC«
²Uó'$Zõý>ÙÓö²5Ïqn%OÒ±Ø>íi /þ«¸þ:oÁ_ïíâ5É-Í{¼Å¨?ø¥mº7)<¢Ü ¥ÚÆÞa79[Á÷ôâ:@ñò ymÚÀûvQø\òÈ9%_!6-$IÀJ[erX¥õaÝ
p£´àÐ! [
-Æï(/¾8³weuÕâ<fO͸ V¦þ©Ã&·³ìVñ-È«ÖÑtA¬½I?Af (kßF|ôiHd²NÍF¸G§¸"¸å{b/Ïñá¶Î·Û^o´¹.8`2Æý gºeÚR7S(oJ!KË·*ÇmsN(NýòUµYH.ܬZy_M-FÝ7?Ù×&®;{ülu
-ÎûQáL^ëiÓN>ÐX5ÖrNl.a£ÂáÆ}Ò#Û4ÖõÂq6·tÝ{ÆU@Ñ3;ÊD*¢;©,4ú03Ñå(dï¤'ì®Ñ
K´7¦né÷{ô3
nJ(´ú<OfB¨.·´5X%²\öLçïò¥ûÕÿ´âÉRê¨)ÙSéî67¯`t5Ô}´.ò-A:HÆöCmÔ*Ù*üfA¿¬$x{IJêñl5ê Ùéÿ¸JΫLF§?/.Eñ{SÙd³Õ¸£è©N{.ñÂ79?¹ã@Ö:åÕÅìTÆ=m´ÐÓvææñkñì3
Ì>C³êWVµô*Zb *CVnIffÖ-aôDK·ÈþíÀÝ4aï룶ü¬éqóNlàÙÆ/j
Ö è!ÌjÏJTÌÞñ+gQ\ëï ßÇ¿Ü¿C³¢Né +ÿ(hzQÚã5nGÏ7Gâ¬àÑM3)åÊ÷w7¼¢É?)§Á\ªcDºòòö£Ý©Ó|å×KîÐ F&+fÁ¬Ê||sILúJôúâ6CKëç8
-cât²F²²Å,È©mo'G]$ëµó¸Qc¥°¢6
ó(wü{æL¥¼òSNKkKxåÖ¥öÜ5ºSÙ,ÅW\â4É!\£úà'b¯Æ. \7`Ì(þVã%÷®Ozo?
÷x
-óÉKrÈN¬¹¾Ão?lzU+ÔIZ}ÐHdïÇÒVºKjy
-÷o}ûz:RLÐ<ùé fv&7a¼û¢nòG3¤{0Ù½í£×Áïá²YÎOaÛæ§]hþì
-v¥îÇø>3UðyÇq-£k-¾&É;¢ú±ØQ\G3yfÝ´µsE¸oªÓ`)Æ0TU¯zü DÝóÛ¾º+.GFgÓg IC[h~ FÁÔ²TY½{6@ôt ÜN?§@µX3Üö(ËÁ¥dÝï[`5Ù0¯'èÎ
ã+PÓêaà¼5KS4´X):Öá·yÍXn¶Kuäξ4çæ«åM1B_ÁYµß Ahµ¿}ÁÑÐô!92 7þÄ¡ÈcHY~çèêʳ±ñÃXiÈÅÚê3öÙK
¿gÿϪÂj¹Oì)ó)2H¨¯ µ eB}@õÞ
-2jùÍAÕm@eé¬-²(¤µ8>Û¯«}®ù<w6Ìq¤8:µwH~Ý-f#ð/QâpV5Àýr¶Z¹½UÕõUZ7A74·
-Àé?&g5bÅhñPÈËU1«*à(JobL4*8Ãà´Ðöé_µËZÖ ¥y[üRv>·±fÌ Oøº£R¶#Ös$ñ=|ÉNÀzBg>6Uzº~OIã"îæ/õímkýÀPǶ¼ªÒÜùTwQ6úêD«¹4ãðÂ*ù¤·måÀ-I]>#æGç)Ö[ºj!¸Ýßo¹§
-ã¤Ï~t
í0èXüöúy`o×*N]¥À»~iT½dÁrh¸¹nÓöæ'p²-ü-U
-ãw¡öæ!e²ëïÚ"ÂÏwZ³"z@@Ä DÔùWk(¸ fé íS+k^¡%QSMÇ
8WÝ/"ÃVßß~ɦ¸¿ZË1FR¨ÌÚzLâ©Vº2ïüF¦´Ç~2í5n¢
jsÜê¹PÎPsîÂN$)hÈ¿ö:GiKßå%`m H°PjjÀÝyg2Gr]+æ|ÀBqTåÀysíBìû.ò15ÍÖkÌÛÇVFéM=|û)ÄåIûßÑ5ëmã&á$,ä?ÓÏËt'
d¹Ç7vâf¡{ Ím¼ttW²µQ(¨xÑ&à{ô¹,B}]3°DË
-yOJÎï¯ðÿÌ-,%k¬äÏàw<{²¦é. @¥1 at MÉbó×òäo¼.PLÿºÌ:1VÐiÔ§ùù1VYÓ±bòºRNÚ¡3}pTÚ<*¦S)Ò"¡²´FéXW|æ¥Fn'Åeî
-©Õ£ÒtB¨FîV7ÝúYmÍ4_ÔØÉfÿ¡E#ZJr¡X[p·$pì*#`ÃçL÷¡JdBiS~ÛÌ®%{}: ì4:öÎ.'ßÀ;Ôöú
¹®yD¬=ätä6ÕWÔ@ ³:åZR¥ ÄòÓèó®!²Høi±8í§s>÷%ÈÍÈlZ&:©Sf>$'ñÍÚ5ÜC![H*âÀ˺`ËÇrRÓyq´Ø-?d#º'¨¯úqê\gLû2;dC¹ÒÔßÆ2¬?-DHý®[ÚõN Ø_b?ð¨øv'ê¬,´}ã¾8Øða»ÌâcÊá¸ÄQwHMÁ³±0õ
-)Qlí£ÎÂl$²,>¤õ¯ÜµÄÃíVq.®²Ù(åaʸ2¾»ïÏ¿ëW,åùnMÕù#ìk×õ(c²ÁêѦIí
-(©W¨F¿ëö¡Ê^î+IZv¬iýÔ¢é~"Á¶ºÃ"8¨ÍШ¤ZäN{G á-FÆÁ4<h!u½±k£tû7f?PÝÁ5ÁnÝ~²5ânF&,äÁÏï
ºóØ=Ëâ¡Jsû1/º à®sÌÌ,Ë&|>øH1äczæ
-s"KlÅ´ÇBfüFð´°Ô¿Z«´ÌßT%æÊNoç>e<©×?ÍAA¨ô¥¾DXÿB¢¤xÚê«-î?`ÔK]±u![¶}Ô»Äã¦W;¢Úvþþø¤X¿ÒHÃXê(Ix§'m÷4¦
-óPÑpN8,TúA76óÅvhñ¯¹ªÐtÚhø¾zÁdÉüo×éMaîfOd{u[ê^ð[¹áøºRBIIºw SäÈ=ÏKuÁÂpqPq%ð¬µ-J}êFNii|U1ËÑz#ò~p+§é¼¤véÌ's+l¢ç§2ÿÿ[©-nßÒ_Éy·U)umÏøRá1OÐta?´c\°ë3!G
jäb(¤UrN`·V»À»ßKãã5Øo$k%णòÅ»JòkvÜ'g¤LQe!ÃëöûOv°³ÓÛ5Qwrƾ¼Õ×n5¢ØÀý*.ªJOÛ¹ßÓ$¦3ÿ"TÓ°z ɨW%.º/ LÂÌ7¸×oØ6@èFqë%b½ìº$ !ÙÐòEøwPuÖË¿XÈ-Xpª2ãAÇ
¨8ãksKr5ܽ
~lpð&÷eU.Ædî-Þ§ïðãìkL7R=!0¥¥ó/F%mtL WZþ=@2LLQÉÏF縩Äþ¦W]:E
-Ìj(ØàTxòHmëðæn<Õ»ºeËohc]?uäå-þ\¶é
Ô¹§ÛÈYM,°ìÂeYiÏKÁ{Cú!.!p">ÒßïÐßK°pÉY+^©&¦9¥ÃÑÇúö¤÷C3"¤«BÊ\ÿNß©fo
íq"Ûÿû¹Ho7CÉQD
-ÄÔ5òUEHèÌ[ø§ìL«ë¹DÏR=¢½KB¥¢(|«*Ú¯¾W<îGQmð¼eµ+é2:
-µö'^K¸0ÕOofzÎJ#ÊÜ2¯"ÇTðW9&j¤_(L¤§RRÆBäª&¿®4X3ò$W/ÀJvþR¸;6Ð×3È(ÆöA«»J@¢®Iù(d ǪÐü©· ¬jX®í7 at fz²9ý2××òÙlò§í³êÇúÚ;¶x²æ\Ü3<BFÍÐï5C×x43ÇÅH.®A-Ê7¦Ã1bY§$·ß° ¢c}4N²z5íÇ"ûüHBå~<±l?7â,åkP$ß·YÉÓí ©µ'âñeaÍÕÚÕÖÎMÒÄÌùÁód0·ÒëAåàUßÀÝÒ%Úré>pÈËîöÞ®<°Õ¬pìÖ
-ï¦l
-·÷& YØyËËÎS;D~À x£×èr䣵·%Ásoz´£·Àåõí=dJë ®}»iª¿H¨$Ë3tNæ*[¼à[D
µ÷n
©Ö_é7VÁPzÕ0t¾~ü bÔ´#Ûþí6ı@1)aéK½=Ûáâb§àTÅòÕé1ìóÇÌF7Çce2½è¯r-åÕ
-á9ór5jLæ>ôÕ¿Ý=FÔ¿â)¹Å 8ÉWð}àcÿX*d¢ÖéĬeÚõªæ£{JË-ð½<¬·¬H¡ëìû¶v¦ù][[0§-ú¯P/ù5v!£»ù±©ÚVH ó]=ø®k.9¼(?(Cî®é`û+}Ähöj5{µ´&ùQIÜé5ÐU±(ý«o¶tø¬¾¡1O³¯Úé:UÍJJ
uµºY©óBÄ7îS(uA¡û,ÿ×@jT¼õ-=Åëq¥±eÏÓÓ'=S<·;¸'/©»0¾ú× Ñs«ªñü½$;BëK¨FÞÊ`Qw8µlmFÂä]¿SÏE/eÀlö¥ÐÈýÄx]ßÝñfÿjü·SåÇAáüÞ ¡çÌoç+FÁSqÿS
-ØøÔc~í_Õý]%viªÃ´´L'*ª{]rvB²R.äb(b¤ÑO×E+òRL5½jËGÇ'BýTÏ4ÚRï¥w0%p±Éàf a¬ª=±vE×e°í^ÚÕÍ2?§Þò¥Ý>Â÷l®¯Q»!ß|=Tùv KAQrÌpüóÔø-¤o âÍTM?}â¤ÞÄaت¥LöÈ4ÔÅwâ¨sãT[®µìhYþädgÞCàØ9¸ºo7 äNÞ[Á)8@»@Hû¡
-Ë/;ÔGþÄ
-Ñ4þÚÚ7A_O¿ý°ÄÓ(vxî¯ ä#ä¿ÊÃ5ÍÿàqÁ¢OR ³8oëL^hÈCw¥®´(Ñä<¡ÕÙ
-»uFÉ嫨Î/.Ú YÆpÕÙõ ZK¿ÂÉV@CöDÃÜÙSLô®7Yáë_ÙAl®¶Ý`!Úäãv´Û[¹²oh!²ÄÊc2·Ñ#©il~)Øq-J©ØÒyúÖùüZ%ç¤æÿãp
-·?¤
-л[^FÎîã(w^´<äõ-endstream
+xÚíR{<駥¡¡hsr{]&KÆDQFuMÑ6.cæF3ó1Ã÷KµY¹DjS"¹¤Ì(agÊ¢KIjZR4¡ÓÙsÚ?Ïùë|Îóþó|¿ïó}¾ï÷ù!½÷XhP(HØ<k
+ÆØáá06h±Rx½Â+ØQ OhLÀwéDàFÜhfÃ`+'ÿ
+S_ùL¦'
µ$¯ÈèO]
+Áþ£±8|È< ÈeIõ?Yó+¢âû¼üâ*W6¢1ØqÀÙ.")æBp@`°i +¿(6ÄSÄt[zL[{+|5ÓÉû|%³ÂÆLjØø¨ÒçÀ¾Ê3ë_ii+yÒÛÜ&ì7¹:Ù¯ÏBædl|À®0MûõãËW5ofõif£¹ÚoOsV¿ET:ôºìñÖ¹ª©kÎjæÒT¾eÊ/%¬1ÑE¾¼¸8l[i@6;ϧOÔc>Yl£8ïý²Á1á#aCn¡Äqת(ðбDztªo<`¸SÒ!é]ìÃ6Íðw±»wæ8fkE6z¸È$¢ÞÎ!ºO?YÒZG>+<©Ï~óÒp^qÑ(ýzÞÛãö5»âLiýWA²èuæÏ2ë.t`W×\ø!ÉÏî!Òö#¹}ÛüóÅåCJ;sï6ñÐ[o¯*~×mÅUGºÖ/òt
+ÆC¢úÇ4'/,>v^å=WÙRÔ19Pk®¯.^l^øènxÝt`cëå8qpà·>¿m¬#£Z+Êât¾ÿ^-¼þìÿÿT&Háò
{öwÜí\Ðendstream
endobj
-20 0 obj
-<<
-/Type/FontDescriptor
-/CapHeight 850
-/Ascent 850
-/Descent -200
-/FontBBox[-27 -250 1122 750]
-/FontName/GCOOBE+CMR7
+18 0 obj <<
+/Type /Font
+/Subtype /Type1
+/Encoding 71 0 R
+/FirstChar 49
+/LastChar 52
+/Widths 72 0 R
+/BaseFont /WRFXWO+CMR7
+/FontDescriptor 16 0 R
+>> endobj
+16 0 obj <<
+/Ascent 694
+/CapHeight 683
+/Descent -194
+/FontName /WRFXWO+CMR7
/ItalicAngle 0
/StemV 79
-/FontFile 19 0 R
+/XHeight 431
+/FontBBox [-27 -250 1122 750]
/Flags 4
->>
+/CharSet (/one/two/three/four)
+/FontFile 17 0 R
+>> endobj
+72 0 obj
+[569 569 569 569 ]
endobj
-19 0 obj
-<<
-/Filter[/FlateDecode]
-/Length1 845
-/Length2 2042
-/Length3 533
-/Length 2661
+71 0 obj <<
+/Type /Encoding
+/Differences [ 0 /.notdef 49/one/two/three/four 53/.notdef]
+>> endobj
+14 0 obj <<
+/Length1 1842
+/Length2 13515
+/Length3 532
+/Length 14535
+/Filter /FlateDecode
>>
stream
-xÚíy<ÔëÇDJv~YJd6Æ!ËB4¶&³hf,CÆÉ
-¡$Ò)-¶dÉ5¶ÂQJÊYêDö¥tFÝsϹûÏ}Ýÿîëþ~ï÷ó|÷ëó<Ú[ñ.údhà ³õP°rpF(¢mÅl
-nMdX-Èæ@ÀJ·°-[F²¥û2-íÊ üçÔeó7øSÂaRBO8G¢õÇ×gí¦d
-]ô$PF-ÀØ!?5B¤ýà_H-ýíK]$HV¶"e
÷ÎÍzÓG¦ð5V·¿ÀCjsË@Íä(=y4.Mv
-ÀOuË.¼Ç¹0§³Åüä®ÉÙ3G WI×·í§`[8¤ÿT¾Üc%ìþGðL·g©^* ±®oìûÔ´Uõî"ÿ!·®\à¡W×Ò]:pj°FKâï±OÕûÙ{¦x5ý±ÙC^
S EÄ.¹MZè»Evíõ?dÁ¼Dת[+Õ?\ÌÁ§M¸kÿSb×ú÷i4ì#³Ñå³4#ì¡m¹ÄLTÄÖÆ¡ðÑ
-ê%ökVF¨¦)&½IÙa1²éÙ'F©{lu%}'s~hKE"¡wÉvì
üwZSWON&påwíÓ i([²Øúæc¯6í(×ÌZ-9§¡)8ù$ïy¹ÌñM˥ª(íbÐhÿZõ*¶æ;(5ÜFÖ«Ï´I!Ø¥¢$³KT5xõÂ#eñ×\V~ÑøpÆ;4hOq°Wn
}E7gѺt;vhðöAÎ:Ìpª<åtè«BýöÑ[<áÛÆ×¥!ZÒý!/Z\d;*eomËXÐ \pèÆé+òa%K5k&JnË誤_ªS½~vMüÅîÂÎtD-EûëSâ¤ÝË-Üõ¢#Oêaß½¦&×¹9ª§L*cMrÑP|qd!£ÝqÊt5ØcaGoÔÙñÔD¬bì(¡@½í¬²©§æôB2ãRüRçN¹kfýeÊhµTððFVû«ÏÖ#Ù¹ÎÎ,LõÂl|
]¸ÉÄ
-?ÓïÔ¸ö÷ÖÈ¿?F¾}µöIHÒ±WªÂè¥Þ!AëY:-y©Jó ¯ïÔ'ÿrÖDÀ#ãµG¾Ô*£§ô Ù¡Åpïv:Å#ËÊ¥Nd;ªü1åÎï¯
-iò¨Zë±Ùùò¾±¶[fïo¡Wm8y¬q¬ ö¬¾¸`Ää¿ ¤f»éEÐ,êÐíÑSOò¸âq¤´Ìp|tFëªDðvJ6hã
-?÷7mt¸ÜÆziìZ÷f*Û£yëg6i>ÅÈîeWÄÒåã
-öiÂül½&°ííè¾¹!6'[ßk_g-ußÁÍ-Æ ?¾âfß$}õT··_czµ-}óüp[ýñÖ&êÅk%¦åÁãñÎôT?ò%eEg°pÃ×çÇ#ïNýòä«ÜA¥Âó;éEè$¹æä;&åµ9¶ÒÅv_NÓÁ¸Ú¦=W0jV̨n&ܰݾß3£! Y
-7Jè@ĬBZÒe´ÇúFË|',äo«*áüzß8ï]1wè£Â³ÓÛ.ÄîæÿnSîc¥mà|>7«OA¶©r_d±Y¼xrÙã}Ýü)÷m8']kéêáùWµ¹iÕ7&Õ¬ÃúíÔnÇÍÙ%ô¥'L;«©ß#rU0QKª9í+©W4Ej0Hó1Ô³uT×êT)ÏâE*Á7pGÅ?¤kÉɨWÌÉúÏT¥%Ö [zÉ
-³Ù¯¸)l#¡«iìã$E\9Þ-t£¹I}qîÉ
-é%7=#0Æ^}£é)Õk
PGÛÝØ©stV³Ò¼Ââºhï,ȯÑ-¾¸'ÓöØ»·÷:ÛW¨f^ܤ~¿Wsbz×DÍ÷VÓ¬ïtÞRpÿìdƧ¬>åóZa?5ySo©å^éÙMûåfuëÒ^T±ç+Ìu5ü¸J{yÃôÌõ¸ðîÞ/õh¹:øaæðq¤¹ÊpEÞs{äR¯?]õåc~ât·ÕÍá«û'$wmY¿·bó¦Vf¼£ðy¢LT²@ÝG_§Ø{ÉûÔ×y!ýÂOÁϨQL¹+ÐÏÜ6_
-( ¶/8ZÑ#ò&ÏÃÿËòÿÿHTÈd3hDf-endstream
+xÚíµeT]ͶhkpîîîîîÎÂÝ=¸»{Ðà.Á=xpwî®oïsvrÎýùÞ¯×Ðh«ª9F¯Q5k*(Ó
+ØÅìlié¹+åzö®tÜà
ÛÂ6¨¡+i°0æ#Ç5¸<ó¸OdÇ@z© ô ÷Û£]ÌëxF-1Ï/Å
+¡§xÎdÐ{BÃ@^=3ì#kREz¦ÉE½ýjñ.m;ËÉ¥]à¼â4±]?ÐÉgSRm6 3i¡ë÷r¨ÒlîúT§hÑ)N|²Õû!jd£ë]xxü
+30=ådùL»8V)ÑÝQO§ÔÙ}^bµYqsió®-Sa!æ¤øoEã¼qÀªôSxè^Áð8f1lÖÉgÏÌí¾Ó¬JwuÙ2ëåF嫦ì¸r}ê1ÃDzQãPq]âuH¢êÚ°û\Ör|r±ñd]ÃiGuà!VU̦àK¶çg¦M×b1g
§Bj¢_ÐêÖשÜuzÒÄÒ·áÄ£±¹>~%ýT
».¶Ìij¸ ü®[-Am5Î'ËZ®ÉB
+ÄÑ»ª^ȱâ'{~ĿǽÙ};I$«áÛ9/¦%L%}QZB¹²PY6ä!w¢ßìòmçìáÃÞãW0ÍYÌX¨æÃý¾èJ¹enðÔÖOæ·,ÐpÑ ZëÇÇcÏáÜ ²kÐ{øô.Ø¿-©nT©cn×ää÷ýü2w||H£==´µØàÁàjKúå)ºóFéóÄÛVoø]ßBê`Ä<
¼
+äªÎÊ´@¿#áI%ZÄ\CP.E±A(ú·ÌàÝ~yÏÌ"¢úoºzp=]vW>:D
/¸Ë»»j`G
[ãÞpç6üCÃ1ó¤O²¡ez2رt´6}\ù¹ÀN §kW5ªáÜçf@á*«mïÇZ²Õ"þ÷:ÿ1üÂôµ9#$UÜ#©}ÁF:.QüY@¬ôÆJIø Õ!À3©.¸£Kl<XVä. 5±Ä)ÿ8éL7¥wÑGpí¨÷üwµ¡Là®Én"6õçÕS°/+Ä;7WlV(&Éë
Ûãj2ï¬Óü¸Ï±..[E7Z»Õé>çÇ-rmk,ã>éhý/êÈå ¦{©Òð¼TãL£¬§1{InØ`dO&-iæùA=ºWÒõµ.Ç÷¦®ÛÏûà£ÚLëg.ìW½BÏ=^xëØ{X$´¢rqö³Q<äþ0í0®
+Û:»õpÂ¥Ç7:uW·1²[¨Ü{£{ôÕQ%C`V
+ØZiÆrÖçÁ,:Ä÷bå4®ß«]ÆæÄ?G|qï{A«8cJövNÓ{a|v,F2©Þ$è}/lPJêäÕ9£Ub£Q»ky1ôÑ[RðF¡ïF;òÉÓ½ja¤ß&|üy"9Ídoé[(ggìo¼âuâq´1ùÈÊÌ¥àf|vêR´ß#ìaâŲàïEGñþÜQßé3hÞLÐeÐô>£Xu(¿ù:Ù NüJ·=ánHOûÙDÛûõÈeü0ÏÆ`¥sY¨9ûj£}M z5Ï÷¯½'J!eÞnìlü~ ö#¹¶¿»ÍºT-ÁR¾üØé<z¯¯
+u¹ w©ú¦;éâ+ùTC¦Òþ0xBvÈ;&
+qʽË&½×¢&XTxe2îeÄ
LDð¹¯Þõ4|CÔæÒ"Õkeá(°$¥zà¶@¶YO7
+W1;Ì*3ZÁß¼4 Ä`t C[¡~$ú|lîõdY4:XªßvÀ¢F¬;tóiyç{ê㯬ãa 5µGç-¤$`ë%Jì³ðÞuùeÌÎÒÙn»ðr~é²ÅËÍÛðÛb
+m!õ.£ìè.}[¶4úD.#1mÓ¤°ý+º{ç¬iñN¹·JïàÈC:íðÛºyxÑÃd¦É[Ò²vM¡$^úZ5uÔ)üâ¢.e67ceåN+7d~;ú§×
E+å©tÝô"æüxúW^ç<ãásE
E)¶¨ÖeÊ.¢2å|ysK®líýO¤èëu´c,1)ÞMÜ|u½Ú-Á!r¦¯
+6à¬Ýãf)zTv$Ä
+á$?©É¦%¯æt#ضò#~´!ÉÜö[ñüü*ÕWøK~ÆF¾ou)½9ÈĬäj
+#,CNʤ.jZN!7XÜÎÎqN««df_æï<JOÿÑÞ¬Ã{[£¥/ *©oußûfÃlZ²K½Gôn#ov;¤Çó-;NãBlDX¦Ç Þ²~`S±ø<C*C/ÞzäÛîE$ó6~úÇõI}ØH,rP8rBmsdL¯ö½ÑÚÙtiý¦ÙvØ0ñúp×{é(V+ðã,6,zÑL»)Â'©Ë¦|LXØ0-ë2S<#ç!ÿn2reþÕÒYÔHB at gé+}©à;ÜXWøRAb%F-¯k(RÏÛÕ(E¡¿ÕA¤T¨Ð;k7ªKdÝ@ÆkÎÄÎz5õl-~2cÈØÀ/zÑÖcÖ88rì+Ê>!²»zzQ~p,¸ýÊluX3ßyfߺ
+Ké
<R¹)þuìÃdÍ˧ïßÃ~¦)¼·É½³ÝXÄ éÚì¶ÎÌ+N|¼<ìÓV¯ØbÁn5,Ò¸j¶yÀ0×Ý&ðÐ0Aiçf.¶ Pþ»Ì¢@åÐô_½~´?·\ÓRqÀãwZÎ
+wÎé¹~H8yä¬_¡Ðe)ÔõkÑ©¢4
§uÍ]Îsïl¾Ã×LÅeMª¶=TüÃ>TÅTUøRÁ)xª~Cê¸þÝBDí§£y("~ϧÌÎ,ü lLÚáÉ#W¾à¥ò,+´8çÈ«á.Æq%tqÒcШdã×+ãØü'6ð9¼uQ+{\tÿd£DqÅ¡pblfú'
+ì5d¯"&äµ ½r&!ô²§VØ.ÕñĶ¾òê,¨ëëØãûÐV§xØi"i$æï³v´B`äU¹ÒtW©0ð$KÔE"-)ÜG,5O²2(l¼×ÓâÖ=ûÇÕð¢;ÛàKåêE`
+õú¥z=Ü¡T1&¾ë³§F¶[v`Ö±Órè«×º<
+è~ò@u¯k×$.eäÓVa½Ø¢Ê¨øèÜÔÒr,å*\âÎ0¢GoWíøX¢- <Æ&º¿ßÿ E9o¶×;L&/xtÝVbú$tÈÞv@ì1cÅÓÛáÒM¼VÜcnNC)?ºû15qáÍ´ÖJÄ+=|?ë¹¢{Ê
èT]©1||mp,H§@-»ADDÉí«ðêÕ£¬ôõ³Z²ë|Í_E;þâP;Ö0üãA15{y\¶ZÐ^'õ`Â5
ÿÚÒyÐ|ò0\\LMl+ê-ßÜñLô®ú]öµÿ:±[á·Øï½°Ð)löø1kñ[²ðû6RB¸Þ"ÉØýj+>,Ì#ü¶Ö
+þqÌA±:×`)H<æÇáÜèWXÍ8ï\iìûéÔk{çäjVö !dj>]¼äMO
+Áãp!
W±¼ç3íñ_uÜÞÖ³í[QA%' LèHñGǺ'íËúJÜ¡zÇUW©Ö¥s%×°)l±Ùòþ72ÒÒÍ
+8ûS½øõ a@
+OÙ*ßáí÷»zá©Sp/ÅåØÓµ*ÞX`Ìkp¿ "uçÄwÚ9G.(~ß'føµöâä½à+59`@C+fÛ(1UË\ú`¯_*Úx¢++cÒÏY`_Z ²c9Böì^ªT> ØyþûüÞùâ!qÞb}´-üYÓÜ1Qa0à,*µÔC
#ë ã<_dI+xÃ<åD ³ôD«n7´ÁÇĨyBú½t8ó6oµÈ:n0iS Z^å¥Øqu¬ö»ÀÞ;5øb»Sûþ/AÐ 7 P4º±Â-U©É9X::8ÄÜÆz*ð^JÏ 'ÈH0>7i)/
+Êdü(élKD÷0r»@zöNiX¦M©öNfUöX°<Ôï^Üòe¸Ïµ¥-SËÝÇù^ÞâbéêðÀ\¦Lbzs}-MÄP'uð^>ý¤ÏOæA$r9ý¨-
%{UðÂà§s%4>¨´ãüqVÏ{2&¼]]Q?Àbd²±ÁNËq82Ý2æRÍRE/Ý
Xõ¿¤zYµºCó}2Å·ñöþ¹C¨¢÷2í Õ=ô&ÿ÷jä3y¤ÎKì7ü+Ðei`6TÍLNLØ3Û´D¼ù, <ñKÈ÷µI*,!~§Ò¨4ÈMèèÆFº"ÅB;é¯ÕF,d¿÷§),
+y)Vêo7ÅàÙåp|¡w2[Ê¢øLC at L'^ÈÆañÐÞ+ÜoåñÔƽ;K#Hy°³¾úËL8Ô¦LD~ÐÚòÈ,}U÷µS#°¬/¼Ë N³J[sa*Ö^ÍöMdfX
òfº0£ÖäòÊf¹¡SÒY
LdÃ_ê®ÌÛ¡)ï%¾2³J)[I|9µuì¤L7¶&zþVAJX_÷lã¬ÛvF3@â»mì3¢®â¶»Þv§Dtï!Üæ Cy÷j|¹ÖáCNWBû_C bò
+==GüÛ)T FDMº@chyuU/¹WêÏíäç2©ÚÀ]m/
+sbìP2í\íïkp
+Dãþý¶ËQN=ß2ÏÖvVôÁ½÷~S=½¸Ñß:b8`:ZíÝÍã.9®ñær=ãÖÛuHKbU5:#":%]tõVÕ2¤ùs)E¬ÃÕèñ¥+;»ë±8íPݲ>"®ºñq¼É0
+èÐT2ý`Eó×o¸!á N³Ù>v3pIµÍtÅY¤p®á¯WZ}
+dVÀ5Ö!²*Ñ
+Lð|)üÜüÜù¬.ÙzäøN<%¦ÊÚ"æ¡m1ùK~C¢*;hÌwñ7DÎ(F#Ãï»ßH Uê¬ð¿nØøﱤv²sC(ª×Gçcg
++¹\©ÆoÝf¹¹m·/nÊ^ÊôËFFuO²åàcUÀFI4ÛIº°
+û`#b«û/F
+È¡2vê²3ó%õ~À8ßa}:éôxË X,í~*Åû´ïµA)p1Döó£øôÌéÄ«TSbHøÐD»P¾Utâ
ï®JÁàS£¯á¤Ñ ÷¶»;{#Þ«HO+ø´ßAÎiì±oØ.n)UY"Q2l¥tq¦ú~®ÄË®W¼@¾*SzÜnGÍÀÅ׫ôA4<m³óÎóv¢dÎj<0)êQ1§~ºã6,Å_¿ë8é³ßÔÑy¾Jnõÿ2ÅãZñHë!10¾§üÎË¡8GQzÏåëø_+ÏÐÚ(BJlÄjÄæÀb·I×Î4Ú4º¥Ðý^ÃbÑpü¡Ugr??ÝP 8îGã2O ó{ì÷±@?9µ&FÑ=£¯*qh(¹j
+÷øzµGãmwâhà¥Õ&{¦¥|Ú"rwMòÍÛI×+Ã$Ýdì³$0Î9tBî/Uaí¯¡C®ý®¢?qVÄ45ÜÕÈÜôEÓG#û°Î²â:ØÈ-»)¡>³¿Ø¯l*Yú¤³û¤h6åÐ-.ÄÌ©ê8óJÓÓ[rÎæûêL"©WÒúåÎ05Æ
+,ej|öÞ¥Ëmû ùÕÛ{äè=5ÄAö¸0~×ý·wQå{E«wnéÃWÚñ
+ð½
+·:ÿÓÜKAÕGAwÁdÛ¾ôër_Ò/ÅOcÒ¢"î*Mp[
+7_³ ºïÛ\д֫îhÀ¢®\È¥ôj©ÊI±{¬
W8Tv7:ñY©½
óxëY[ËFÔ'å-Äm-¹èÔ¤þ»[±ºjõ#¨´£Ë- »dÌVá
+VÎÚÂI/òFÂJ(øv#c~ÂþÉê½0øbÉúqÐ~rú§£¥<°«ó;(De$k8âoµãà2MçH«z áe¿sù[Ê@ÚW
+å;¿¼úÑï7 êZyOkïº
+¥Zì4Åð_¡¢áXë\wc(ú«*8î²< Kt î
+æ
Ù¼ÏV̸jªáw1E<Üi°kæ2\LPÖl'¼:BA©DÕÒðî]ò`çý°5[MGö¶oÄNfå+T±u7Â0r."zÚveÄÆt¢Qrk¹ÚÜUDí*äØèK=²é
+ô*äsv®Ü£tÞúXÍl"öÔ}l(
ëÕÞr?Ci/YÃÒYKXMÊðØZ½íé*¿>KF.²Pñu°þ[7¶RBÝxôÙymp
+û
/ÝsÍÕSi4qGîk÷á¶Y;7¹M#(x§í|³wüKJîM¥ÂRõ£TW at sàjðjY%wNi°È/ϵº× TQpKäéÃA®Ü.çxna«)wĪÛD-ÃQµ0¯y³àûÌtPǤI¢Ê6µøÄ[N¨¶Î¢áXYå9E!¨¢¾ÞÒlýÚxª0ÑAdÿ÷ÁË;bUÝ°`Sí
+~ªít£bxiéÜ©sG; Úo 2w\füm¹ óÀµ§o?µæ_|)Té½ÎÕ ~7kêc}W
5[4'[?®î®×|9°ùÚÚnj{¿ {ÍÙbâ m«v¶<ê^qÛ ¤ÐÕ¼-ÿýVkÄMÊG¸ww
+UfE ÂðUvÞ@ýƯÆ{¨±ãcYÚß å_渲OþhÙì¯Gt-×,¬¿,ú+yL¼^,¸¥p²£kݪ¿Ó8´'ØJ®=¡ûF¸Ög<øoUE|tÈ
+y\W²FOmú
+?(æo·ì½S-Døìäì¿Árs«}ú9
+&}C3Óð®ÿÛi9lØäÛ`.¼áÛ;7O÷þ[V.ûÊ+·×øæïãÚ̳¤êIû+´Â+DÔ'=-oÞ/Båë²$tÐ?×{'æï"òx-úa¿·51ñeY
+ûEJ:lÑÑüXb~Sné+bÆåâ8aÖ9ÕÑ&ÕÓîÍ°0E
¡TÖ¼¸L|<F
++È1׫|4Óþjqä`1«öܽð+8}RËÆàXvd_Éí÷»{¨ [ÄG?":ËÖHAr8ê¼ãçÕÂÌ
+ÔM|Cþ-1$×#.¼oÒíÀ·wíYÀ>»?ÙµgáÈîAÔÏ%µÉßÆÆ#Û?Uût°C*>ü̬ÙjéÚîtÚ´°| P**_n5éPæcÃàz)mB¾x§×¨8<J~
+ä1ïÌ
+6Y§ý²× úܾÜ_üÙâ¹D 1\íiaè\d:<]µ§±Ú6ÐÎÈBp±Ã2¢5úºßö:Ú8à b¤è]¯(%
+Öw·DGoÌjækðr@]/ü&¾»ÔCjËèW£
Hyøu¸°î·Òø:Wi·G¤»;)hI7ò£IëhaxuÇöiSûZý¯l\òS_XLç¿â9 ,Aä<H¡NH]äæªÝ·«ÄÐþ}m¿jõHObøðPíÆaÃ'°Ãå_
¶ïSµ@sc¨LÐj9{ó¡~r§á¦©p o ÒùmVTb§Qþ>¿a«}hÉ--×ØÙÙëÑÃ4FÔûÝÖÍáýÈÍK_êo3ð¥Áa±t§S;Ñcð:¡bÞO´yñþdÎN¼NÎÌ¿Q`íE3£Tñöí¥ææÒ÷MTÝ·;ñ
©ªC
Vlàú{ü¤·Öhîúí(ÑXªsaÒdFã"í÷~¹v$êi>39Ü>~@ löÑ;ª/µ¾Ç½æn©D9þ×/å4q©Ø eZ +ï?IyÙìdc3hÍeìP|´`) Ô¨÷´røò¹Ï¦gü$AµÆù]69$Tß|y¡Þ+:,ÜhYfX«q,ز1úô1XOÕÊ-*λîÔ×S»Ë,zÓÄ(Þ [æÛa'ô/~úÔ#u¶mÈOjK¨R)ô<W U0ÎíЫ·átOùq]RQNÎ1ËNÒY/Jõ¶Þx
+.¢)ëgDÜY]ç .yL«¼xÓ¢¹ðÉg½fn6åÊ«Äûà_öòzcIÛ¬Äu³A¼ðôtâJ;ßû"õ6*¬aQ/+ÎRÒ[fYË;CZ)é<e"_ª]QxÞâ@·Uæ°÷
+YSà°rÛ£ÚÃ
½$UëésQµp0ím«W¦±3ÈNʾCEɾÁÈ {ãzW»§w"ÏÎ}ºGtÖ¨úqÓ%n1²vóÒMæMí½Sg1æpï}iïö+ÝÓïçñªÍët©C»õ¤¼²r2_n}³Sç.0,YM»Ô;i(â{&Ý ;]ÅÙ;ç¢O çECëM}¿tIO.WjxøåMáÅïÆÕ´ã¸e:e*XòjwK;]{²Ú7LMöã«Ø>,QÙ2Më¤ÂËAv¼Î~Ïúø¦«8#?ôRôÆ)ðåßé¾Á¥7NâùFó7Þ`ûa/}ögð¾Åa:Yûù e*e¡K®bGý)þÔØ'ÞFÄåõnnF8bJ(C³Â]§nêÞ±äÊÙ#ùå®ÝìLîS+ÕÑW¥<ô{tSü®À/EúcF³)R¯:¦øB;ù #ônâpÃgë8íÙÀW$òàLË`*¯æ1y[LÎ×ÜXªI#<gCºó[qÖwbá)g¾Å¨T>9EQ
>\Ký+´O¹õüC,TùQ4¯Ò>HýLÜ@WÖëøSìÝBLµ6zÍ·Óþ#sèdYKLЦ|£ BÒ'`Ôº¨æ+bèó$
+"2¡SÐ~Íá`×k´z=2À¢S¯ï 2OÐèøÈ£+¨*Ú§/mgDãÏ&Cø-(ã;ú¬pe0zõ<¨z'uå9L¨{ÞÄÒà=ã=PÀËvFµÛxTK*=ùJAKU²³{Ø/åðúO'⤳wЯ¸êDy¢;¹Õ
+ù?u9f¯@¡ðèV·=äøàQ¦ê~Xûvºë"0u\l1À7ôc==h)y@Èä`æ\¢ÿ¬Æp·).jgT-Uy>/OäñË ÙPXó[ì®~m/¢+f¡HQcØ&ë¶Øí&hõ;§Â`Bi¦êãmUýاàݺµÅ¬aOèâ÷/øU^ù¡5£ÄÚ/ec'Ý_tG1Púrüï7N,/*ÍýÒR`7vÅiÑlzG¡éèT®Mû7ÅX±kõù|ªJðk$C}¸>¸"F´\ÃNcXKjÍzÐÄ-e°zuئG
.pðÂ>|=jZ¿:³²<ʸx¥ÍÄ»,L[ÑÑÔ/®)ã³$kog<¡ryW°Ò8kÚÂ
vmÅjõÅKHÐÐå¡×ëüx¸sñTYSâ#Ü0èa+ÙÔmmûóÒ¥Ç@TÅÇÌÈäõV@F`ñ|Ô>M!¥{ t+qÛúpñ5eÿÞ ÊpXÜt¡yAAßâ}ËüÐ7ÌßaQHI¢ýÓ× ¸_[&¨ú]í4
FTTϳ3C±ke¶ã4xYýÙ¬¼`$©4®xÂ7%Âq¦hé¨ÈèÅwnjK¹ÁdÅŪ¬Úö$[©%}_.PÄþþÀýÿ þ?ÀØhèèlgcèh÷ endobj
-23 0 obj
-<<
-/Type/FontDescriptor
-/CapHeight 850
-/Ascent 850
-/Descent -200
-/FontBBox[-20 -250 1193 750]
-/FontName/DMIVYN+CMR6
+15 0 obj <<
+/Type /Font
+/Subtype /Type1
+/Encoding 73 0 R
+/FirstChar 11
+/LastChar 122
+/Widths 74 0 R
+/BaseFont /EWBXHF+CMR10
+/FontDescriptor 13 0 R
+>> endobj
+13 0 obj <<
+/Ascent 694
+/CapHeight 683
+/Descent -194
+/FontName /EWBXHF+CMR10
/ItalicAngle 0
-/StemV 83
-/FontFile 22 0 R
+/StemV 69
+/XHeight 431
+/FontBBox [-251 -250 1009 969]
/Flags 4
->>
+/CharSet (/ff/fi/ffi/quotedblright/quoteright/parenleft/parenright/comma/hyphen/period/slash/zero/one/two/three/four/five/six/seven/eight/nine/colon/question/A/B/C/D/E/F/G/H/I/J/K/N/O/P/R/S/T/U/W/Y/quotedblleft/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z)
+/FontFile 14 0 R
+>> endobj
+74 0 obj
+[583 556 0 833 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 500 0 0 0 0 278 389 389 0 0 278 333 278 500 500 500 500 500 500 500 500 500 500 500 278 0 0 0 0 472 0 750 708 722 764 681 653 785 750 361 514 778 0 0 750 778 681 0 736 556 722 750 0 1028 0 750 0 0 500 0 0 0 0 500 556 444 556 444 306 500 556 278 306 528 278 833 556 500 556 528 392 394 389 556 528 722 528 528 444 ]
endobj
-22 0 obj
-<<
-/Filter[/FlateDecode]
-/Length1 845
-/Length2 2056
-/Length3 533
-/Length 2671
+73 0 obj <<
+/Type /Encoding
+/Differences [ 0 /.notdef 11/ff/fi 13/.notdef 14/ffi 15/.notdef 34/quotedblright 35/.notdef 39/quoteright/parenleft/parenright 42/.notdef 44/comma/hyphen/period/slash/zero/one/two/three/four/five/six/seven/eight/nine/colon 59/.notdef 63/question 64/.notdef 65/A/B/C/D/E/F/G/H/I/J/K 76/.notdef 78/N/O/P 81/.notdef 82/R/S/T/U 86/.notdef 87/W 88/.notdef 89/Y 90/.notdef 92/quotedblleft 93/.notdef 97/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z 123/.notdef]
+>> endobj
+11 0 obj <<
+/Length1 1292
+/Length2 6411
+/Length3 532
+/Length 7207
+/Filter /FlateDecode
>>
stream
-xÚí{8TûÇÝF5%9DB[æ\wî·&w3³5c1C(¹%P±©%j#¢Ø
-FIR¹ÄP[.gèì³÷iÎsþ;ÏYëõý¾ßõþ>Ïû{]4M_ÐÑ5Ñ´`nç|-+æ*Fò ªæjë)]À4¤x°ÃÓÀ ^¸P$ÎB-iõØüó¸§÷äÛÜUìÁQÅÐÎÝ9ÉuÇ;§LOA·üI±nãðw6"ºb%úya[Èå%:l}N3@æOG¸<GV%
-§þfò,ó3ÄÚS·øø䧵lS}Ô³:ü9ÇÌ}Ú¦¹W¶[¤ö¿¯ìî;ü-F
¶©|³rÝÞn"¼úùiùûê¢þÅFÉjY>Ñä
ºT¶â£é
D^É ïôi:rLÂ`pjÕÌ·(¸Ê§q¶U±cï{D"¤) Û(B½C 5¡ï>C*ðêì-ÒÍ;îÝ4(X[ÉMïc¸È\ÎËRw
$
-ºUs°öS-¹ÐT¥OVË÷§:ÂE®[ J«<-<,w5M\iI*£km×hh at M<¡î6¶¿c¸äSëöÑZúZN©÷õÛZC#×cOÉ4n
dÀâ®I>Ì^N4nß
-U?¼§µ}ôDªHvÖÝàÂh%z¨ÿòÿ¿ÁÿDÄÓè <-ÿ;ü|ví
-endstream
+xÚíe\]÷ï¥;DJRz$¤»;e``¡»CJT:%
Q at BJDAJ$¥iAÀ3÷ýü[Ïó¼<çÕù¹ÞÌwíµ×ïwµ¯ÍÍnh"¤E9ÂÔQHo!0H ¢§l EH¹¹UÐ0°7
T{Ãd @ÉÇ *+üËÒ úWêãñï%_Úk
+À5ÉÀZ¢+ÔGaµ`X'ÿ7LýgquBìþWù¿»ô_ë`w8"à2Pî>Þ04@
¡ÿjû9eâ¿d´¼Á8D éDþ{©ÃýaPC¸7ÄàFxÁþÃÐÿ´mÛßjƦÿ3Ï¿
+Áp¤·iÇ?eÿÊþA¿Û4Ü`#","Â&bÿ³û15$
#±BB++JÏ
+oc4jKQÀZ߲ݨMá iZ(nsq°Ö?e*ù|ÇEGã×ëøÀ{ß¾4S¦´¾dsxw(kxsù¸~iéÄÌ<ú£vUÕÍêZK¹éª^VïôÃkr=VHkñõôî`úrT7©¤¼Kiª§ª9õw¹Uµ nïë1jO©õ±FO¶Æ©PÝà ÉÓÆ£Z)jÌç_ØjÌî¬PD;ë(ðð¡ðDmÍì¸,-~9tOݯQ{wDä~n'ÿL÷û÷s ïÒEa!;ý2BÓ0q&æ9¿4_ý*Ëîãbk\ªÂ¥ÉNëd¹SÅèì6PÓT5sù*¡JQîÓ¾P¦5ÏB²kK§ïgí»í¸ÆöK¸'Â4¤ [¹}µÔɶ/«.êM;g¹¦G"Ãy^X|RÑ^¥oÚ¡è¦M®¹×§½ªX/@h(ìåÜ|fÖOü Â4·%ùÅ* {þi62¹®îÊÉðáºt£ÊòâT&3ÙÇ5#ïÖe°S¤-àåÂ9¦+AîrRÚR
ÛÈÝ
6¹¯±ß8HÖ{8dß?ᦠ*
+Ù¨0£¿óqíå´øe
+mË~ÖZ;zÎwg7i;¿¡3M«ùj#6
+¸åo&I©ÖØú½S$N¹îYnÑÝø²¢T Î
»|J"ÁÀëF|d4lré3JëËÙu¼Zg§¨!B2ØH@XkÀ³¯ñHI}ÐhGCNlß/u-^öúv
§~áp¹*uD~^EQYÈô|e>í>¼_´æâ;]æI³CýÙ§Ã\ÿ3yùÉGLÖÉOÆE²|aÉ<Mv!w|hm ©¹=tJÕÏ·ðqO|ö¡WyµòñiíGrSOÛ2Ø>¸°$Ûî=ʾ+ðz9¥Y²`@÷åB8<ºrFÝg?×
+4¶åÆ%ï8!TR{ìwU>ZÄås&P±føaN='@O0dºþ :uL~$óxq£¬CBà°Öy×Ê\ì ~4¨Wñ×±úã¾±ÃøHY]ëRµ%0óªæþ)tùêµ1ÍzuQ&Æ îLäu#+S²Kjì=®³w¶\®1'Ú
+´sïe×tܵME, úl,«ËÂLó^ûñ5ǯ¸s]¶Ãfmæuæ
Ó.457Ù¡MXÀx·ê×½tJ6íÖ5Q/J®OtmvR*_7úu¦ÚÏT<¾þ¨õ<wLæÀÀ[GÏ_5/+
+5ËÏL&Ìd×CðRâÊÝÈÉ//ÒÞúÿÚû=ê+æÊ©&ä4·Ú»Ó
+:3lK\qà ¾kÞ1("Tû¶3ï¶Rí[=¦(ò¬°grþdñåÒ/§òõ°Xüy-ùV´±o²5¢2v
ZbùB~§îè
+~»Ü2B¿?åptyHª'¸¬Ã(
+npåU I«OjóÞ<Ñ+ÇôùÎ^:=À{xù9æ.²ØÞE±½#gsK#I8Ü¥#ÿv4ny<ÄuÜ2lxÐA<Áз¿ö2ߢ.s<Z¸ú§³S¦G~üæmåö\ÕmØ/*nGèÐì
+_
+ÉòkvnÜmÎI¸?s¨x at HÁÓ>ân}¶e
+ûGr(Ü+BB«s@©¯oo>ËÐq 75ÒÎn
+zj>?ãd{ëáÉw±1ÀZµR¿¯ÑRq)À>Óº8¦lfóóqí«]ǼG:Ø5_Û^2¤Ö°oã>ôS¦Jf^T±Û¨æðÉÆó£wؽr»ºEÔ¼hMCÚöÙó8-ÑîöÉ]*BË~É*Uõ_hÀÉ÷{3#DT¯2©ÊMúq¿i&NÐäiÌf,õaÀDB¿wl"OÍz³¹,ªb
+Bî:³z¸á.¼çwét*L½wFcÅÎyúîSÒÚÙõ(Uk)+ nÇYâæ1ÍÓ= ÕG6Ì=]ÃåÂ"ñÑ(ïeÈIuÕOl}dGQ0÷ííìX;øP|áòñj£_ÍË9È?½%Êî1»Hæèôf$õÚºËñ[±©=É-¼Àù¬öPj>W¯§ýÁ" éNÈq:ø£¢ËPæó½òÞd¼çQ}esA
+vGTø?ãÝáJ{Ñ ´êö0º»¸¢>PÈF_}öj±è&÷üÛBEWq0R
å{'û@h¢Õ̸ãÅF»{·g3yä¨õt^vÆ`®8¢^hÖ# {ô=Pr×ágyÀab57N¸Ç]HC'ÉÞ#qãuægÝwÙuÞ8¤Wöd,ÑMlXÕã±ieݵ^4½í
+ím@KMñÚMæ¢WÑßô ÑÓ>¹²Sj¨ÊÆZ:Fs·i¶y.öU·Mâ)Ò¤Avâ¡âIÏðË)]Âè²£ìÑUZ9¸8àh"5 ûpN±y81Q%±L÷³ùQûÂ7£:O:r¸¬Ã¬£"QóJÑÒ4*1%ú<?¬µîY.ýtUÛ|vlvÓNEÚãÇ<öº:öÙGG8Ì'(~ñcq{<Õóü[ä
+0¡*L·3¶ýÖÂø¢õñ#¾H¹!Gº½GÝ U4s°¡Èáò¦T¿X`¶4UéYz=±|ûô«m*Ú
+>S*aÏXþþhè0îO>¯§8räYH¦c8¶¼¦ QKõéSúO#t1´Õ¸É8gÃ×}|ªvíå4E¯T\ÌùUt¯Í§hÕ¥Ëo7øÌb>öÑ-R¿Iy`ú
+÷Ã>Ìè¯+ýèOHß3a¿Ð+u
+!·ù#ù:Wr°±¹l·k6O~`ðM+²?ò{¶HÝLU×éÕ¿X¡çÔ*ôºò
pJF
n©íÜ<äxBb¨ã´Á~ÆÁ¶>.6ß·®úu>çÓ¢{"&ëâîö·×Gò
+í¡p¡ÖâsKáÝÌE,Çwò`$[ÞeÖ¼c¿CÍ5.uÚõB
+âµ3xÓà±H®eùï÷X8RFØæ\Htt^=Ý44,llOÉxYsôë(*«³ð6å61ãÓ¸;aR¾Êèú3]Pjsu2QâþK
+|å¯!¶9vvÈ=ìx$Á¤pûC`È7ÁêÞ"¯&G76Gøï¶àn¶¬ÕåäýÅÂ%1¹¹ª/IðS* ô:ÚE¬Â¬¯
+y6EÏØbp1?²Ï®û(ÞDö&énGͧÐ
+ú~YOsåßÐëcFgCá¢ÁZ©Sñ9N|CßW@ÙH1üÒJ'ùTåý§gb¨rµ4Sò¥,ÔýÃ})5ýÝC»Áh§½ïH»q½k×]*ÐZn¹Y»lßÐ&a¯=ÉãÉ8KÍñÞ|éDc;ªcËgEà-NGÁïH<M`ïþ|óøK˯÷zæú[8N{*5*£oI7å?m
+êû±N=A¨ä>ï6YÙ±5|ìæC²d
+læhµÑ1ÅOñ'=^Þ#àút}'¢QÜÌÛwûÈàU_"fàOrOey¹ÿì¹í¿³8=q!'mEaÕ/òµð»¿:îgH§USË»¹dY8KHöÆtEÕØaHý³¿d"GÆôúe2oìñQ(ùvÀ5Àggc}WVÞcö4Ra¹¾#J#Zoì%ÇýË;Ty{8gZR~öXUë+IÊ?Ø71IÜ6^úpl®7ÿÎ`%×Èk÷õ¿%í(«äE82þqà¹
+¨+Õ7 Øm³Y1ó
÷Q¢O¾üWw[k×*¢&£ºb`¡à²q¡t¤|»Æ>15²öSýÀehóÃh«iæ§_b(§o¨eòyúsb9x¹hìZ»øß_ë
ÅݯüKϳ!YCÍñïoÆG²¥s|§]m¦ÿú¥ëJáõÂæXhfxÞÆ-7TK2ëq·³"ñIv©¦½»
IðËïæ|ÅÓ¼¬nöûÕ!¢òÒG_|Ôø+7ò©\ëWIY©ÿ#'[E¶ÔVÃСyê+)ÊË1̦K!¥ ùîMYZºÑÑ5Ü&7Éç©TÞ¶÷mKÈqÌ,OÖ8hk/tÿiÒ]·«"ÁµÒO¨ú½ZÀÉè»
+¿Z§â¬"»xWü!ÕëÞæS$O·ÐÁÌr±ÁÎó<1#úýWËo*thßÐ
Õï7j<~ßàv&bÒ³O#>UÕÇ\`Þä~V²I_Ñ¡8ÚZ'rÜæq.í¢5`ñÙ±
+èì_
++PË72ü¾ö;:òF
Ûc¤³Ú¦±oÇt?ÛÎH·Søûq¶ÒÎNÁ8è¨ÿñÞ#
îöO¯ÔXJª
+ZZ8
+ÑìÞc#×gTÁ×1|zɸplwg6°ª$è2+,]û-ÞÈK×<±êò'Fûä½/ÒïKºÕé9'@£ô%vÚn;CöwÝÏiQ«ÕÂwý0<Ãdø]2¨ï7ãR×nû}T\#ÊH"kïÍðú-ÍËÈQ=øÎÛǵäÃê:AH9Üã½ÛÄq mFÄ1ÏW`NµJl*sVbàÍmë{ÈvÓ¹áVÂsLÐìcõðÛCm"£ô_m,¹4ÚÁãæùgÃÁ±]%1S3ÙëCk§(̨þùs6!íGaÆQo MçºÐ©èêê%seæêÊ*òcµè6pÓËèòbªuCÆô
+(¾rÉ0®÷WÅUÙÎ3¥|uöû`¡wÒ48e3¾'HîFM$¨\ò¢äáN¼$EÀ`r¦Â¯F[E/ïÐpÚµ,uÊ;n"÷³âjtj7}_ÜÞøH¬°l?Tô¾9Dù=ËQÛT¤À/½2î§OL2v:X/ëè2Ö
+
Ô> »à+Xß¼ñh˼+βo3)ͽ»}[èW&v#»q×4(c£QìT¾á>lÒXZ
>\cA
+n-30Õ";ÛÂ
+]È!_7»§è-çq²Ü%PëøÐ f>êë:ʯÒ?íײÐfºlD_ù4üÃH~Ô.
~}TÃM}'@yÐãÉûxöuüîãWºU#ÊÏçßnï(+è÷Óëä\ÛÜ.µêØæ87sk0-[l·]åJº¦ð,yûE°±äì
+a%ŧu8¼múMéË2¼+¾¨}ºþáfd%§2¼Áë5roAZ.>®46°S&OÆZö¥Ü¸Þ»!Õj
+ Özc²d2Å·Ä®£K}²iµ±í¹«ÐEYÍàOîfN¡±4&QÔ6+Oýõx
¤SK|3å 5[zùW{ºL¿_ ¦wîx%uC;ý½ûâÒÙ! ãÒÁ×{M [{é%ÃT·L×ÈçlèT<?Pë)pë:t;v^¤ WüþHÿÿ'
+@00ÚåF»þ/
+ék~endstream
endobj
-26 0 obj
-<<
-/Type/FontDescriptor
-/CapHeight 850
-/Ascent 850
-/Descent -200
-/FontBBox[-36 -250 1070 750]
-/FontName/MAMUVX+CMR8
+12 0 obj <<
+/Type /Font
+/Subtype /Type1
+/Encoding 75 0 R
+/FirstChar 45
+/LastChar 120
+/Widths 76 0 R
+/BaseFont /PERPTG+CMBX12
+/FontDescriptor 10 0 R
+>> endobj
+10 0 obj <<
+/Ascent 694
+/CapHeight 686
+/Descent -194
+/FontName /PERPTG+CMBX12
/ItalicAngle 0
-/StemV 76
-/FontFile 25 0 R
+/StemV 109
+/XHeight 444
+/FontBBox [-53 -251 1139 750]
/Flags 4
->>
+/CharSet (/hyphen/one/two/three/four/five/six/seven/eight/colon/A/E/I/K/T/W/a/b/c/d/e/g/h/i/k/l/m/n/o/p/r/s/t/u/v/w/x)
+/FontFile 11 0 R
+>> endobj
+76 0 obj
+[375 0 0 0 562 562 562 562 562 562 562 562 0 312 0 0 0 0 0 0 850 0 0 0 738 0 0 0 419 0 881 0 0 0 0 0 0 0 0 782 0 0 1162 0 0 0 0 0 0 0 0 0 547 625 500 625 513 0 562 625 312 0 594 312 937 625 562 625 0 459 444 437 625 594 812 594 ]
endobj
-25 0 obj
-<<
-/Filter[/FlateDecode]
-/Length1 1289
-/Length2 6434
-/Length3 533
-/Length 7245
+75 0 obj <<
+/Type /Encoding
+/Differences [ 0 /.notdef 45/hyphen 46/.notdef 49/one/two/three/four/five/six/seven/eight 57/.notdef 58/colon 59/.notdef 65/A 66/.notdef 69/E 70/.notdef 73/I 74/.notdef 75/K 76/.notdef 84/T 85/.notdef 87/W 88/.notdef 97/a/b/c/d/e 102/.notdef 103/g/h/i 106/.notdef 107/k/l/m/n/o/p 113/.notdef 114/r/s/t/u/v/w/x 121/.notdef]
+>> endobj
+8 0 obj <<
+/Length1 1065
+/Length2 4472
+/Length3 532
+/Length 5179
+/Filter /FlateDecode
>>
stream
-xÚíe\TíרiAºka.º¥¡RR¥»»Qîn QZARD@)¥w|÷ÿèyÞóåüηó;³¿Ìµîµ×ºö}¯½9Xuõòöî¶0ew7PP at P
-- 98 H
pwS¢`R-}-¡7èDûÀÿ@tSÇ?ý\?-áü¢-\þ@´ëoDk¸ýh
-÷?áñ¢û"ÿ@t_¯?}¨?áý¢5|þ@´ïoB÷õÿÿçP+(¸û=
-B¢à_ÿ×DC7ú¼Õ¢`0X\òﱶóF¢Çõ×WýÂüè×óÙæäR!0ùøNmNzgï¿Ó%ìz¶)ú½zjôÛm\y§0gÝâ/º±gÜ,²õAZÒ½ßüýé«ÞSó:w¯JUÇ}¾¡h6ÃõÀbÛÍù
-EYá|8²/Dyt±Òµ\Îu/ÚWñu-4nFou`HÙÍ*ùj$óåY¯ÃsØQÐú× Qº>»6<¿mRu4i(m.|-Àp²^ZøIUõôåfÀ'¡Tz@GYyd3 Ïâ!'"%Öy¿ZYm×ãf Q
-"Öîh(É+í=ܱxÑÅnù¶ýÀØd¤l|?éZ÷f4ÛhÚïãôúm\¡+ͦöF¸ç¥Éõª´/
-ºk3Pò¶§§7°k[ª/§©ñ³Uó5\ò6AVþ»yç(È©å$MÕbzßéG¶±¢Øî½`6©ñðù
- úOÚªjV#z¸ÁÑqã÷Ûz+ç8bD8)2ïÀGê_W#P¼±9U¾£ÒjÂ}¹_
lÒÕbM¯À2!£lï7z0Q# oKQõ
-°HCæÇ+ûNô_=«Àm
Ò±¥ø{ê!DÑÕ£óVª¯¶XÅ?Z`Ã-_(/]Í XØ1øe¶½c䯢Ǽ[<ZVñ1ýÖÑÐQrJaN©dòî(\J½¨Ç¾Ëàmqfë`9`ãUºÎX¾3S~ÝË+Éîì« ÎRf8'Cãò¨â'÷JýûkÎã*¡+X-ñn}»PÒS!¼)ÆëR:c,»Ð®Dw!³môP¿ã^[ᯬ¬p
-Õìq
/\Í4»m¡IÎîPG³Ô8gx}gQÜ1C¿jݪòò³A¤yĵ¥åüÔg*¯Û1Ù>³6¼XØ
-&®fr+X Úò|uV%ø2KÚ®¼áÚeÄ9Ë2ëöÄpõû` ±æLb°´)ÉË%Ã>u!-#pcäupY¢ZjÛØR&Èq£Ì|Û&,/D¯{.®p[£¢7`
-sHõÇpúϽ¾ÚNâ&Ö¡¢;ío@o(¥¡¸û©ã><$óî/Î0ÎÕÔ/;GºoZxKÜ]a¦VUn¶)esÝ öy¸RJ"×õð|MuÞ×ÙeLÊ1ìDÖ¾Ù$Xki> ?~ÍÚ˹Tñåºò0
-¢er»Bg¯^±´ÑõÎ`æìë
-e-Û,KnNÖVC/ô<÷±*¦Bô&9Úµ,uÑ=ÏkÃÒg¹iq!¤KDر]åý`Í¥I°Á\l
³R^&Ï2føÎf4û"Äqg¦2ãû>z(J½»sØáÏ«±1¥pJ2ø-!]Üq
-ã^JfEx-oA?7ËÆRâÇQ1#1&Ax\
-/äÍ¡(aeÛiH_HðýÑfÙÊå©í]Ú#NïdÅ·&ÕõÞû¥Æ£¢¾<ñµ@ímÝ48RÁO{ïÕÙË$
KîX|luâº!c(ó¹oa¦³©ªjY9wV\¼U_÷ó?aÙbÀ.+Øpta.4î [NöÄZÑyÆ·I¥È°vFvtÎEGùðî*."ô"bc
-£ÕºJúuCȪg¿Ü=¨¶oBüÞ6~ÏcQzU%µÎ>ôË<
-«wÅö'¬gsIñ¹fWùD]·]x;çy<#O´Þlã>fábÖ×t«/öý¨oä)HÊ¡ÙH/
t öGâÝæG\>Æ.òªé;ú!|«Uîç/,-ô:ðõFÞ¯àx½Ë*aè°¼d6áò¼º>ÆñE²¡BÎ)S;Áþp©#XvRlSÜB*è§ëÙ3å*j£º7~:É-TÚ±=Çz©ðöÚ¨×ÕëÛ×/CP¬µç¢YÝ¥fkªR,T<EëÒ¶×UváHFòàºû®Àl|ÃêT_ü°Fbu'ÝL±ä¨
-àmj-²ÓÕ)êÑõ¹ÃÄðá³Üoî{¾ð&VÝÞQÈ%}+¤áOòMé¢Jïu{'q¦cS®kGÙ¹<ý©®JGÑTkÔÚ'z`d{NÁ^
-D©^´N0<~¼þ¹ØrY°ìt}ºx3Aà§ßµÉdÏtÉÉ|d¤1WÏܶÍ!Âs>G\NµÛϺ·xÍ:ÌþÃÛ4Ρr++ at .·á1À¿Pûµ¯ÃvÇÇÕés÷´I©cíº¸·V»Áç´-ß²m£V58ßÈÛJ
®Éüùͧ7|JZf<¾D¦Y¦ëðorlCÏÁâ^·æµÔ|ÓÌÇØ,<9Yc, "òH{,¡ßKµ/Cú3©ÿ<Q}b5×$Z5öB"z#¡VN¼¤mµôö]{Þ£ä+Oktat¢ÍÑüÐ=°x§éÐÓûð¢Hgf,ëV5¬5ÛÈOÒ¾û¶þ̽oUìE½³°(êFcV¾(!V§³QlºÊQ©Àã¿Sv»©W¨å¬»ý¸Wd!ÄL¥=YëâpUããÅ£ÅÒrЧûj9.¦8Kôæ·|7¬ÚLåÇ7 JìpÙ(µR;A;ÒÅf6knb>R=hk·Zò%Èo)éÈíâñ²¶l¸¥éõ"ÆSëµ#æ¨:ÙR'RAxMmúS[Ùß¿¦)m¨°-æZóI`úÊXÊïî è
-Câo9ê/(RÁemÃN÷î??¦Íp|W%¹µ°yÐÐÓíÄÙÆ= ¥qXg6÷Áñü&_5j¢dDcS µ`)K¨ÍÞ}¹Z=J³g÷
[:i%r,z[e
®°5µQþnþJѽqì/iåØÙx95Mõ9OàÌÛ·Wë$¼¯WÚý
-«¾`¶$lñ<;6"'PUKio)åÓÕoµmç6üMĬ-i_aÑ,ã´°¡(¬3®ÃÊÏX3êy=9¾R*/HnfR
«h×^¹bü½XñûÆVdw§¯Â±íý^ÚXàZ_ïtMîª8t£*ð|$ÙÊ5F¹µèÅ,õ·ÕLBé
-qÞF%«¼z@Aç[ísçIçÖ³¹k÷-µâ7Îódôóø;ZÓô\¥ÍXàÄ6ÚêÔáj^|¶O»J8¡ðfM]BàøØýÃÑaPªôʽQyÉpP Q£%.ý²¬+ª½ä¼Ó._X½AR´.µÈR¦~ͲéìÏÂXáàyÞïO³ÍáËýøhÓ¿½ecÙêZaHÊ¢ÇUx·B01µô½
þSùÕ«|L§¸¤Ï[8ÎP÷Mj.ÎwSÀ¯V°w½
-1FQ¡|ò3£-vÖVÝ¥*º?î_çU¿ôűR]f)¶#ÉÌÓNì³lç1?ùÚ~!ÆTûcððò(Y ÁQÿÊ`;ð
-àë¨Ûî´FóJ2Ã4í¬þ8Çé:È¡
-AIUí:3"sýTU÷NCÀù>öÄ ?hᵤy M
¥¡jj?AêHJÕt¹Ï<ç"·÷è7Ä NûbtÇâæZ3¡êÏ&y¦8}zúeȦUµ²,ô0æì%^Öa?;³ÞrêmÑ«ºëôx¡»4ieåÚÔgNáÜøS+ÿ½ñÍ{ÎotÖ±Á\Å}ÇúÚOær¨.^_½SÊ dÛÔ"¡QbeÖÎöm:ÛªIÌ+P&Qã¢üøfX6LÑ ²Ê%'çÓèN¡
-ÏG
-xZF¿*/Þ3Zæ/o¹ôiMé6åã
-ì Ô{ì/GÉ°å»·Ëæ0[m;pIQõá¾N³õpßÃ¥Þ f1¾âCò¥ß¨6¢{#¿['
-'éíá%(ª¿ _>ä'q3Ü6Vé®Ã.zàçmÊÂ¥´3»ØühIG%Ê/pÆçN?;**,4YÔ{¬KÔÖ]eÒãá:µ`ûÄ]-ñ FÞ),£¿eàð
-ÚXùÞ2(u¬öédrä7,WÖ3ñQ¢¸)ñ3MÁR̤»½~äw?µâôy¨lD¿ê"Oíú©qªÒc-y^É^GD³´/:
%ÌйêcFecLÝUA<ã¾¹kG {×ÐÈ;i½·~8Vx at 6Ôù!uñÀ0®²=òàµÚ:ÞØØJÔ®2Û/ao¢FUôÔqn}Ü5ÞÓN
-Êy¥ùªÒ¹PwôF¡5ÅÀ¸E¯âÕbGOÃÛ<\>êÛ¾s&Ϩ|½z]6=¥0 õ¶e|GÙ)ý©Æº¦gÉ:s!#RivTÿ§àô[Ú®q$À3é$néWðEîôÃÊ7ô"ÐqÙ4Ú×äåkûÁ;.úÚÌÒà (çêÖµ^åç?ÌViá-®º¥40%0°,¼Sqöù¾g&EèÞCß·úeÑÅ^ÚABR0ã4FH\ì¡Ö,Î[-N,G¬+å<_Uô®i1ý67§wdöq64äª×¹eÝ$9{yì|ÿ|å¡ù`ïòË,®ÜTXAðËPw+*ÃȬ\¿ûúA¶µÄøÕbi E)Ø8êRºûT
Wj2%ÛZmâ;±yÞ
?ÂÔEÂà-rça_<µout¾Y¤XS\×N)Ûù½ø©3Â5UÂ
ÁÈnjþÖ@=aÄÓwÓ¥E:/çY|çÔá§vy)uµQòúR1k&4W;KíØ&·hË´
-c#jwñ1û²¸éÉwíòÓÎ`ÅïR}û@õ¥yÏß«I¯¯%ªJöxèuÁ2]SÇ7¨4^7>H#ÆÊ©*ðÀÈÜom=¤tcÄ+<8Í:5[°õ .Å«ò&à}É P«øp&Òb_
-Ëy
-tMìè2s䳿ÅÛu²ìQ>LÌ[óe¹¿Û»ã¤Ù_æ+uDl>.U|rÑò¤
*¹k[´"^M¼5×y6¾#«kÄC^~qUÚÅ4n½×¸ØÒ&XCr8_®~´ÉT:n^;>þH$éokcSêOÛL×l83×äó´AIaµ_þëÕÝpd_5Æq02ÙÙ$IK»v¤%B.A]Õ:LwLkQfc.më[s'ûuõÈïµ[fVi3-h
Q¯oþ$¨>NlÒÇ%H½9¼.)»ËdU¢ ¼wJMVÏ¥´ÅÂ.R¶öx8ºLØz04³|r
-¸¼*á·öQ¥Ó¯Ð1VçC>ÀRY0îÂz
-Ý
-¼¸[oÆ´÷Çj+gRÅqK_êÒ5 dQW?¬¤¾lv[CTÉ«?8Åtνf9ñééZF%QÞÂtã'«âÚ§©c%¦Äãoïx_éUUGÍ-ÚIùúQ|õYéЫ¬qá°#-ã{ÏC-~È âKÝkn=!Ю5§ÿÑ=|{~¸æÛà¿`wÓòtùL9\
ÃÍÖbÏeÐ ôY*têáæ6qs5W8éfïJ§rc"γ\î®!íÛ @®0Ýe¢!Ò°TV.Zló}¿_/SOd°%Í
%v¥:qÀËã^ñ3
-HMƵÉØs§`~é1e+îâÖyòûb¡Cqó'È·½ î-[µôOÛÌù´r¨´ö½zï,E9V<!wãÕNÇôÞ ÕÉ)0wðÿåðÿø¢D¹»BÎÿ`9
-endstream
+xÚígXSÛ¶DzUTD`!EPHºÒ{"5 ¡
*Ei¡ i"%H&E
^¤+M:¸÷Ýg{÷ùyï¯ûÜäOÞo9Æ7Çk=01PCàÚ8¬·Q4Ì R+êÿ(£þÛrT0ò7À.¿!¥ê7¤ìuÿ
+)fÑ¿¡+;=(kíüäúv
ãt/ËðÇ$d56ìgU¤ëEÒ±®d§Àeµ»¦ÎÕÞ
~¸Ókè'z<WtßkÛئÈnÎÚ¯[aë¬Ã¨Ê¤ëærߺ~Ò»æÅÙRunÞI«HÓ;ÀèÓõ8qcÛýÆ2ho9²+²3¸b;¦LzÄWj{.ÒÅM9êäIÛ¾.1yGZ$o(ý¿XpãurÐêhs-wQH¤ «
+j4ûÉló3þ6µD÷Ëç H8_rj!F
+¦p:ÏÚÃäÅkc
+f¹uåúÒÖ¯»l³åå°Ý!8l&¹²{ü×w*¬·³_öۯإ[5¦g¥õö{
+~tضÝkvöR=Û4°Áo¼õòñÕO¡ Ô.±JüÈN·?VÍ]ý2¤ÿçÌ)FTÞQ¨k±a§ gQõ9vÅs2&·T\ÞäeÒÑO2ÄfGÏÙ£¤¢d#«¨Rbv¸Ò:Òù$WH ÇU,[-¯ÍißÒYúÅæ*«C³\°$<¯1*áfÈr¤µXìü"zÂfkå=ARNº+Ï«ù*\Û`D(òú¼ÿþI%ag{Û:VØ îãé Ba"£§£Zø÷ÆrBýÕ>´\ÅÂ</&Ñ÷FÆW²ÇXAáj=8whA÷/.xX½5².Km\½6nýçcwVc,¼i«$ÔÁ ©&ÆF5I¡X¾[9¸`°Vûz%²Nís¬¸&|5;ou¿í½>ÿ¬«Ã,¸â"ÇÍK¥ÏÊH!|Ìñ·üí»ûÚ«_Ý:K½xñóÂ%§øÞcY¼-ÙüIOúÔóÇ´s>iÂXÙ³¶×ã5$X2ï}©lþÆaÄ(ªq|æíéÈWåܸÁÚ6ÝåügÔà=!Äsr¿ÎNtqË ïV¸nBíÀÏysú4
^¼Ï¹m¬ü¸Ò½1¦6ÁäQ¡î}Êت=·Ý/÷ V
+Ìâl$p5³6?¿"²©N%
+w¡Ð¾µ¼a>xäD»ô 8=um2«G>·?B<ÂV£1u96uî@TUS4±n
+ÃúgØ¢mbHRð©¼Ê%djm._0îô'Þ)¢g³ý>ü ®zsÒs¨
+8ܮ᪵
+'9\²\üb¾>Ü¡×ATþT4U¬þp2¶ KÎ,8û©?þ¾låòð2p:2ÙºâÄñQ^Ù6Ô?r¢y]m½òÖí4obnñRëR
+R¨r&÷ôôö½d½ßÊ
+ÕµhÑ8${EÞ.ÚL}ã~ë±å£©Ó³Áåø²+»D¡ÍqF@]ø§!VkVÌ[51j§näTÑ+¯
+]-¸yi)°:DQ«=¢Õ»Vÿ4ºÊë²á\çá¡ÝpÛ.6Ïí-Ó©ç äµ#ãà>»håNÓ CCþ÷¼Üµ~À
+Ý-[b
+ÙAëzÅíd;¼vÚ«rø5Ðáî÷ÀE¿Eݲ@Åf|1 ±y)[¥
+óÖ&9¶ûU1ZÚSÏ
ãÙÖM¶¥·±zªtö"ν_¥@[l
+5â×Ü®Q7h~êÍQµÊËɶÃÙ<ÈÕ±Åh'ä?«ÓÛëÕ<ºm×ç¥ÝÿÚ5òÛ`ïã3p»y¢.;<ÂU£slÂõôù×,ÝÒSï´#ëÑ«P¡UZqé¬X9!æ+õ¼Né0ãÉüù8Ûï§Æâ9VIÀ1w¿Ð¥¡Ü
¹:óÐV?Yr^·ÛäsYý6¦jΧaü§áéSèTÎ]E9³Ø\¾[E:BFGg0UÌͬ5Û'Ú'¸¬;j>XvÁ°/~+ûÇ4ÈMå§Û®¥Âò`£®lL 4xév!CqôîSFâM¼Ý(?a9Tª&®ØÐÌ&ó§DDÆ¢n'½DÓ7Ìq˹3
ܯÒÉ|
Óëª6iv=Æ\xÉÓGa»tBH+SU${YÕõc~znR¦ÁÛ`5ªºðIMêßÞîÛ %\²g1<ª£¦åiÝKù'uKàéJóíêG¦7¢95Wk¶FVtßáÐæK «æ'É!){Fàê3fÖɹÓ&Öh¡
+ÆÒ
+ïÀ]§³R5O¥å^³k#5á°óܬ¼ÅTá>hoº#®}^ËÄ:+
+µgv,[ÏÞu®̵Íɽ¹ræÜÈH³mîñÊZDwÛ SÚ74cd¾a?Î@\:5hî¬*yTp{èOåØíJòÜÔ_|ÁßRÉy¤ðZbüTNh(mæÉVÍz½xªx@5ÊæB&¼ \ìþ½&V¦6Û`W%º6sU0+p<´&Ïq&³"Ëï1:Ä®ɧÉß|Яe5lÈ<+ãÎ$;©+:´9bPNïn}¿èK½ +ù D¶Ù²ÌNk½â¸#Ù\ÿ4T6µÂ¯¶?k¼*®c?4ê3KûÞ¤®º¤pñSÄ~ryä<ì!_Au½Ág#}§â'3\j©oöÞèñ5üî|?ÜQ0¬,ÁªÚ¹?ÑÜíQµRÏÈ1§81ù«ÇÂî/w½'+ק¢õI ÷ zâ9ó|EE:ý|ÒU¶æ¸3©E96¸eü¿¹¨Ì_%Ñýv6SäÇ.ÎsÂRÙøyü⥻1*îÆFÊ:336G=ý»yWÂñU-7ä§Ç?L|ý&=à{kú§Ln¢y®ºNa¾Ñ{ù¶oí_§-¾¼B at .BßU3Í´*ïtÛ¨Ïh´Û×ø]ô=¹Þå;=XjxvWÜéTBMç+~CWÍ·1;mÝÌ{µ Udzì&óBf{ÄarKºNà
Û©²únųî¯Ú-<ÝÄùþ½t[&ê~Ié\Ã㽨¡Â£aÄÊâl½>¾yxÓj:òx8«Ú²âIq½}?ýCë멸Ïg¢5˪z¼ßà³ÞÚoÜлÞ>Í-®G5øt*[K®-ª&i?ãçUÉÿáñÿüHàFÂñÞ8ïÎø/»sÝendstream
endobj
-35 0 obj
-<<
-/Type/FontDescriptor
-/CapHeight 850
-/Ascent 850
-/Descent -200
-/FontBBox[-4 -235 731 800]
-/FontName/PQEIII+CMTT10
+9 0 obj <<
+/Type /Font
+/Subtype /Type1
+/Encoding 77 0 R
+/FirstChar 44
+/LastChar 120
+/Widths 78 0 R
+/BaseFont /ZCHLIL+CMR12
+/FontDescriptor 7 0 R
+>> endobj
+7 0 obj <<
+/Ascent 694
+/CapHeight 683
+/Descent -194
+/FontName /ZCHLIL+CMR12
/ItalicAngle 0
-/StemV 69
-/FontFile 34 0 R
+/StemV 65
+/XHeight 431
+/FontBBox [-34 -251 988 750]
/Flags 4
->>
+/CharSet (/comma/period/zero/two/seven/eight/at/J/a/e/g/i/k/l/m/n/o/r/s/t/u/x)
+/FontFile 8 0 R
+>> endobj
+78 0 obj
+[272 0 272 0 490 0 490 0 0 0 0 490 490 0 0 0 0 0 0 0 762 0 0 0 0 0 0 0 0 0 503 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 490 0 0 0 435 0 490 0 272 0 517 272 816 544 490 0 0 381 386 381 544 0 0 517 ]
endobj
-34 0 obj
-<<
-/Filter[/FlateDecode]
-/Length1 1874
-/Length2 12070
-/Length3 533
-/Length 13138
+77 0 obj <<
+/Type /Encoding
+/Differences [ 0 /.notdef 44/comma 45/.notdef 46/period 47/.notdef 48/zero 49/.notdef 50/two 51/.notdef 55/seven/eight 57/.notdef 64/at 65/.notdef 74/J 75/.notdef 97/a 98/.notdef 101/e 102/.notdef 103/g 104/.notdef 105/i 106/.notdef 107/k/l/m/n/o 112/.notdef 114/r/s/t/u 118/.notdef 120/x 121/.notdef]
+>> endobj
+5 0 obj <<
+/Length1 1069
+/Length2 4336
+/Length3 532
+/Length 5041
+/Filter /FlateDecode
>>
stream
-xÚí·UXÜͶ¸»ChÜÝ îîîÖÆÝÝÝ%Xp÷àîÁ58 $¸3ýí}ÎNÎùÏÍ<s7Ï-æ@ýÿªü·ÐÜÊÕîʸØZزXþ²r´ò-ôþshÿB°Ë_¶rýÁVn!ØÊý²<þB°ç_Ö0ÿÇõÀÊÆù_á?÷Ãÿy1:xx3r-¨ü:¯OgûÍ@Ëj(F^âÊàð!P",5J<ÂçØ¥^Ó»?¯u-gyHÓ0.Ýß³t>cö¸4¬
-qì0±:tclùµêW
-þ ÙÕΪ1pzÑ×}:ãXYÿxÛJi¢l3p¼^øE7ì]RK"µám( ͺGè|<ä/çãÌÈöCºZFÜQ·û©a
£ÙËÿâ
<.w=µú:}ñ´ÇËkÅJEá£ôÞ¶nA@ÎMNbeË`s)+&(.²Be¨Ô5ßéoC¯í~éÒU'-Ë l6¼íj뿼õ`»OÎbg*QÂQ0S.õJ¤*ï·ÆG|U{1kCzQ³Í2Ë9Æí¤è
æ;mÌê\>c
-8pMëò|aZìJY!hZ»ëýÑi¥I¶M÷kBÑNþ¤&_bøfÄÌE8Õ.)dÁÙ²!C¹¡
M¸OvLZÝ¥öWÛP°Y¼ÜÆ
¥éGª¬ÍËg7çG/ÍÒ+3ûìLáT|HG%ߺE
-+w´TTþ>ÇÌ2Ù½},:{g
-ûà9Ö|\D5TdcÞË.à-,¹Ä%ITxîhÃ]®öàP³De?Ev2ÐÜ;Ù:7Ȫo¯N- Y64éwò²G§@HÖYpòÎx"íóq-Tõ7Ê iWëÄ:rµæîâÙ¿©¥º÷%ráè´ívfp;¯(Y¬ÈFXfi8ܽ]ÑC±?¸×Ý|4µàÿ£þ ß9ÍdÔ°Kùa)ÆYÏ\2b®"ÞÔKÒ=ÏÜ,ó8ETÔìGs¾I±¸ q¹.àéûGÒ¬9I°íöd±ÈÒnI
-Ë#Þfdu>¹±¼g6nyºçóÄgqäÎ@ÜC¦ÆM4$l7¦Ä$Ð{⯤FîGcÖ3þÌ.èûtC$?Êñlùñ59ß>,Éà¨)l8÷©?-=4½$`<klÑqÆìÂZ8B_i4þ0ôJi¦àC§*k±5À¿fʲêÊÈE;õõN.÷"ûlcl]\'
â ÈPs*ÁÍæÁþý¬ÿádwE¬ÃáïÇtF¶
-dzWTÛQ^ç§ötÆOHCãC3ÍúÛ¤)ÉÓ´5 ®°Ñuž?Gg\a>¾8G&ö´!ï->ÞçVãТG<úõ½GiÞh¡QÄ 9+t¥³ªc¨Îô>ÝìÆþæñqäAa»ß¼w¥øØÀå+êeÏôÒ%»m%VÞ°_` _Rô{Ϋ¨¸m-Ú²é x ¾"ß²79£¢ÔºWpUôI@X_ü®ÓdsâKÒ½áè;È)òa÷÷>¥zñðw¾ªFÔ½Âä0(Ô{M7©,%:û¡Y¶*t<Â]LSÅô{D[$²
-¸ ¹åxGÈbú1á³ÐÂÍ6Jï\u£zñÝ`Öóî¹Þ+ôàk]ü¸v+8ñ²mpÃ`°4}g+Ö¯ó¦yÏ'º²õC(
-Ë'ª Úïõâ¦úWSYqsq.]m2Yܦs²ÉRU²G0ÿ¥!D¿ÀàEê@<ØÔù¤éÀÖ£¡Ú:FêÐ#÷wÎã8ı¼n¦Úuízô2{½*~°°d>ïmBT,S
Ìfÿ}£^ò1QnËüµuGöv-×°Jö(ʧ(dSfÂÏZh¿ÜÞ5ÖåHÒKD0æ
-.gÑ6ZÐTìÅîVf¿)@%åoQñZ_ù3;xÇDîûL°U*ÎÙ/$J¶Ûi!²iJ¶¢gXR-(»&×ç_d·v;%±GEìUÏû>³#íÞ¦CíkîpÜOxNò>Ë;îÀ£¤éá½_A{ö´£Üm_à`pJ·fÒ-!£é%9íAâ
-ßÁ3ÉòÚÓ7-IÆð@Í#6f1UÐÈï8½ohm5¹Â®L%ó6:··Y¿þî2$O¤*µ"ÎÁ©é©(tÈ%¯ÊA¨!*1ðõC¡ÚÈôñåpÂøÓ¯vn]FeÁg4Qÿ6,£ºn¦ò^+¦¢Àßò]ØÏã ËÏ·é1-1§ü µ79É4R½0K{ÏÆü[îGÌÅÏ©iZÚÍófÄìlÛò'æåB÷wÈ~î¦:<ýBÖý}ÙTY(t(PÔ$o¯\XÜ®åú8ãËÕíÐåP1'ÄÍòHI©Måì§g'f¼8í3mHoóéNHÁ_¦îts0ì~7;ï>V[;6f@~ÿåÊ£4S!ã-ë¡l\#l zVH'¶
-É!]1í)Ëæ<²¨ÝÝÃ<>UÕÇÜ2¬A¹-z>@ÔÚêå"°QrõEZ˯?
´oêjֻʣ×
.å·þ¹
-HPÐ¥éß= ȾNºÃ¼°zsèuªÇw@>4"DÔ² vÀ´é%RW¤Ö¹
[®g|#Ú|S
-WýN8ïªòÝ`oÂ/`CI/ÖÓßÛ@$Ь`
@ö.àH¾`uàÎàWO.EPÏ ðXÏBÚ0êÌSñ;ùãz}»Z
]¦5¼|q¶gl8¡WÎÅû¼%ÆÑ»+jRÞ½ÖÎi/"§íö¤Ä£!.×QØŶÓÂDr¦[AëHzÉ-¯jÏ\äL¾8{zjËb,,×ÆûïQ2RÕ0L<åtúvä].dÁ
-÷;åß"S¢¥6"]¾ö£ÊK~oÌÏ´~ÏS`ôd<2 ·áH¿¥¿Ðr]éð^V%Ùû4À8ÍòãgÔ%ÿ~øz¨¬#òMzzcè¤.+iJ|®lm[îD6l¯]e!Cømú
-ù^J=ªHµòw4mÐÞB÷?ýǧÚ[óóTP®õº)yÎëy Ô3¶[Üï[vGêk?B©Hü¹¢÷KÅz¼bdÖûW³¡rg1Wqf¬#Ä©¼¢÷V×v.<Ýù;÷·hãØFä°vµ P)'_
¾Eúb2JFD¡6Ì«@¡à¶Ý$§@±J]WÍÊøXq7|b S²2ØgÒÒþó II·?ÜÁÙ^cQåÔ;Ê`ªk#áAY÷k&wáõ>ëA/=[EÃìmª¤>[-^+_¢Ï`òÄ(Ô¦ÂgÓ"ÂÆéæÕ*âñ]ddÜK³p¿ÏÁÓ8J%v(é®ÄW'í5¡«`¦ó;SO&ð¯¼:>âiÖ!#7Ó ÚZu´p=ß3`)öÄa?fVÙJa¤)6
>½ðÒ¡;
-ÝNíÕ-c
-ÓÅWVÑÎäFzÉën|&!áëÜ>þñ%,ÕSÉðBdØavÁð);Æl{!
-åkÃJWE470ýᾶ'ä*ÃZ5õ¬
6;#{<ÞpÐ!ÞKÞ3Çvd*Ëþ1Ø&þ¦É2h´Å§¨l;]W8Zí\Z¼Å²ÙgsÞoDô,u´§õ¨joÖ{¨Í t¿wÐ]Ø {ZÙ]8ù4&àÃq×&aÛç¤Ãe¾w®ó¤ÊÀtÒHÄM³-¢3ÓDͨubºÆªÍ<KDs¨[KNùÚR@ÙIJ|Þ;1N4pmLä,/ä*/°ª/þ)ÿ³^l7©à=,©W~õqÄ|-8êÃ_ÿËÚOýÔ±Üw0÷Ùdæç¶\<m"ö>ÜÉ»S8wI%öÅïßun¼FýÖÜ>z63ôÛ¶[~û¢Ê[Y
-Ëûà Öì0éÉõ^ÎCäL©ð§îY¶;bo«´Ø¤þ"és®
-?
©`±{³¹þÍR«¦Ü/ÖÂ1=<ï
-_&Ð Q¢¥VTÇà?'O±<²Ú´G¼Z¥¿;Ï´51Tz+s´ºÁÖèn"Yèno×àâF¦Ò>ìPX»#\¼m÷Ív S.3Ȧ¥ÐúÉÍ3Èø»
-÷³¬Q¦qhÑ\?/üg6Ôâ-tE²CY<4Z̤_Xй½¤·é-`*{¤®Óü*ûîbëõ¸²ÄìwNHZ¶OìѸU>ðÂ5ÖÛWrM.8 þÒÆX(«üÀâ Ãìï5;JèµFdÁ¡»ÀàHÑQ,Q}\ìÖg1á¨ìßÖ|jqÎaòÓ¬ç:(v»QV¶õÝ«úÆåaM3 ïv_jáNqé!Ù¼pÒÜ7<ã´i~
-[#2Hã-¥é×/³MånX-±tìc¯[Úßá ±7åLë;ò©%SEé8_ôÏÕ¨µCQ½ <"U~rä«Ð1øýÆ ¯?,XºXÎ ÖGBÊXuH}¾=Õ=
-O_`·mYÄXTåIÒ®j¢«y:FQÜ5{Ó¼
-¢õ¤íÅñÊêEeÔÐ1J}ôE´lT¢ ;ôÍß^%g3?ãõ`À9måñ}=¼KpÄÅ>=س4ÒSTUºÐRçO%2¬-RÍýB1DËöÕ3ÛIôµ<Iâô¥ûï
-vjxþÇ"6k¢/+,ÐJ®Å]ÇÂëá¡Ð×éäDÍnаÚÞV8Zº}Ùl+¯u5V /ÜF]¬xÝË÷»,òs
-Áï}§zP#4æÑÉùn¶Ñ#Ϊa¹ý?4(Q9Çnºgæi¸¥9WwBÀã =¬>wN ¨JEÄKæ§r1/.ãä¿~~y`².!ÚpBÓ?¨Ç|/N.ÓôCØ--ôÛI»4ÖÓ¡óøQ}è¨Yn?ËZ. pyìW½/ÿ̻޲t'Ü]µn©ðXý
ÑGSb¥Ùnºud½Ì£?r¸»´1¶)î@â@ë$¢f×Ö \¹ÍÞ(£È¹T6¤Ü§ÒjºÀ;w7~ÉBo »ZÏI¤Wìù¹ $(WpaüòY¡¦9ü¡ê¼JRùü>»¨®§ÝôãW,"JQl³òqÁå"k¤|9²3ùzÎHJGIF=ùTÑÌiöؼæùü´+ìÉ2Í=<tñÕ¸4_ÑÔnù¿tÁg)ï!úmj£ÎÌI°î/^IÐHÝU(FÛ-·7ùßÒnÙÞ·xüÌjêW%Ò (üj Y
-à¤|ÎÐöÖKÄöÙBáõE©8|èxµ-ý°0¦9W³È *TÔFÔ!N¹ËÛgd »±b{¿Z2»i¢a²ù1ìÄPÅ~ñb¯Ó7:åDªë*éÐãtLóä=
-Vø¥zHë¶s!TMDè=tIpï7D¿s¢Ì*´¶¡~·SEÞUDȨÓX5ÓüêèQò`¶EX§ÄF.O5øPØPþpDúÄêè^ÿ#ÀêºÇSê7vúh}ÿvÿi©¡gͦ³@±"n?_Ú<O½ûå§å{Z)ôðv¶´âONc+²ÐºlË΢®gn$?âZeó)
-Ä BÅFGB'¦OV.^ÒàèvV$Z$
-ɨÑA9K)ab¥©=Æ?2òút+#ûJ7ÇÞ+X¤Kô:À½§ÉäÃON'ÜTYÿ&¢RUûsÝ=Ú
[m3×,úzÄfJd
P¶ý}+·i/4EýÚéá¦ÍHPénáS
-ÚL"RÌ1é>ÊÅrßíÂ>6lºJ±ìDÖ¾ùHfÐhdª'ÝÄX³ûüå2EEùt|jtä÷ãURJº8b÷ö°®)ß^?'´ú'Á
-÷
C(]>09âr69LÕ³dØ£³
yâ)ìR5lÜY_QÜM¸âÄú )L¥ùÃ'ÔW}V@¤»úûòÓüæ æ{8ñ°¯þUNrta÷ñJõwVt(qëUS,aÖ.>-]¾GÞÜMm_½W+ÞÃç$kO»-ú6#Å}ÎÇZ>)¹K Û[GîZ6©áwñC_ne%j Æô[oK)Wÿ´³Tø¾Å®x±U"Ãá´
-¥{2uÏQ¼ZÑ÷¶4ú!E]13ÂÓñ>/Áº5SJ¡g«K[ýǶÄâHOZj&c9õ`uÜÔyÿB"GkHLòÁÓû
-³N3
-ù(~;¦þ
-k$÷Çû¯åTMÌh6IºÈ1«ÈÕ¿¥5z\Ú¼;v0e!^hs"óÞ¡\OõCV¬¥c×ãh"Ñg¯ñÄ|ˤ««7í&ò§9ÙÂÝw({>ÉÝtÁVM¬ì4¦ð
¹phähÍgÞǧÅâbÜ®äjò5Açü *@°9c»åOx?òR/Wà
-sG²<ä_/W-O¯
-adOõü4ßÝX¤MFä½îy®xÇ°Ök}*qÒ¹ÆôJ ?E `4½He®a9pðícñ+*áw¬.fÅ$¸´ÆçïFí²½ÇßÖ$0(H#v=Ò$dêÞ <ùÛd-%ÿn½ËÁíѾ-êØÐ[ªï-¿áÌÉ9ch¡7Êx_´©¿ C@\õü!Ýs©ü18-©(cùà
-Õèòýëy
I-N`» cz¹äûmêè~êð1×zEQ¹¼¯µÎ¼õ=F÷$ÖàÔI}I 1ÙÖê{òýk<3yD;ÝñxaÛ
-ð*¿HTòMc7a»¨Pý*å*Hºã/¼Â{¸Æ:]¨Ü'~LçF1
Î EVùÌK¹ýByv¥ïh,zÔá}\Æñ¾ùçyòÛ1×LêûÅfæ¾_vQ2ai»R\§ßäkÀðW%JØïXÑd-7H¤©®½9
-c¯Ì82Qôÿá6-endstream
+xÚígXk·¤JU@Ä¡#- %¡(Ò»4)R" I½7EA¥JÕ4Azo
+¢téé åîóm=ûûyίs?s¯µÞç}fÍkKßPT½TÃbÜD!bY@ù@ÄÀ4||Êx$Ü
+
ŨÀݲ+#ÜqÿNy ñ®DS ÑähÅ ½Ò¤%î
$:ùß0õOq5w4ZîüSþgþ#
+wF¡½ÿ«+C)(+îc;ìgßÔÝ÷NÕÑ'%Q9Ì®|¼Ë&_ض-¨·rÕV!¬JwâÐóôi¿±»;ïþÕ,Õë.×sK¾ =|Úz¾Àbfô1÷ü¥+>º%iÌÙ¬´öû¥M·ÅC7»_jx¥¥¼\(Ы*äYÙÎð¶4`QoÎÍ)'×tÇTÅl©jiúx_w^ëWÅÆ@ã-¾ë=yöd·]OóÞ¤NM'ün¿@jq2g0kRº<ÿ@&¤òÄw]Ò®`µó@wG þRÌ£<hünÓHVQ¾©îÂøÛ½awá¦MÉÍèJè'Ò(_±¾>¾æ'-6tªp.̺¥ôy¼r3s*½ILnÎ&6Áäǯ³ó)4¥z JÎ BçH;xÆ}bLfÞϧÀºú¹>¯x³)t¶úºåb¶<áÜm
/cÆÈvÙ
à;Ý -3|ö üü{>ѲÌyCmí.h^ç
+gÂÒ]süÑõneEA±Å{þâ_°7zx>}§òlv
.»Ê2Jw9ü¸s/;ÁSy7ëÆCBCónÉ9®>O]Á£Ô¿cÿظå{òÅúúüZH"}ýu$KÛM)®ÀÅ|)üÐ+þxð4åÔ-%^øù°CÓ:d2I¬á¢Óda»1º\nÓ?¾&Û+ géª,<P+E¦Ê6z6øÄAØÙ2ïËR~Ñ´kY!=v^=
+KG ÕIÓ¢Á¨×:l,áÝ)-ÉвHò(aÛ*Ë+/R²òÌvU ?/>ðGÌ¿°p8äÓ8,ìÒ`uÎ §2hOT¤Ð©;ÞÛô_R¶ü¼½³;'PËýÒn77ÒY¹'hy<¯~ð²×ÕQjÌÄþÅ°gá},ç¹aûêrIö"7ýqÆÂUís&ßù^úS·8f»8¼[n°ËÈÛm6î®/.péݼÿæúQ&Åüá¥nÏ[ÿáWuÚÒ9¤_§c%9®Ú
¥°wï,áÆ{·ÈÝ+o½Ùè.|\µuql¸YÞrnÑ~~(ønÔ¤0Ø5L§0xe¬É¸ì\¡õñ=æbÜÆ5 Çìå(Ñ5´ê¯GëwR*c=·RÁå9_O×Äúæð¶îóOp?ãúÕ¥¹ý´W¼¡'0<a+eDÚ8vÂ]F
+ó>-m¢íDÝH2^8)¾G{U¢;1÷Kßå[n^¹ã{úÔt?®50÷¬çø¬{øðqv2ÓJ~ZøÜýúA)¡{£n ôíd¤ìäÒX¢P<ã'ÒSaµÅL|'ÈùBûM©,/[TÚd^ú=HµGJ!ÕíyÑ5ú]DPXóÜÓ6ø±)¢lñ1_Rrêî±¥of)÷L>LÕ¬3`^³BÅT"é
+s2>>ÙçL6¿Þµësjµ×©ä¹+Ùu-cuª½eÖïQÚ¡§Ñ»Ú³Í··Ì$£gFB]Óh½)8¡ºÞ¡Õ¶ÎÕæëãë3 }4.û+TÈ=´Ð2~#2QSÙ#ÿ¤5GQVBú¬iS.OØ©¬Oó#:9ß×|{eG妮Äví¨B¹==Þq¯µ9ÂÊöÕÞ qSU/¸æh9¥ÎÉ:MµÓÕýµ¤L
+;bÐrWÿ@±¹yÌMãÿC¶h^:²~e®n\¦Òs¾ÎäööëúuDùã¥Ú:vBîôqG:Þsuì7Áý«'Í,¿}Ië1¡]¾fsüðñî´Ýto×\ZM=uWg^òm 3#}:oÃÊÞGU65^®oj%HÂw©<ÁâáÅ´/Y0»ùÛ$t£°fs²Jªö~§½
§F¤xn7Ë\8ÅýML¾þùXJ}×ÔÆâu
+Ù髪mºNÓf)L
+qvt <÷.VÞr±Jw÷ȽFz=Á6?bèiôñ«¦+Ç6(È^$âYkô2§1íÚá°¶.(g_ËãËY&¾Ñ8Í13 Í÷ÁÈuòyãáãÎ.÷àpãxÔÅqæ3]véÆxT5%}âEAÂÛÕp1Ð)æj¡N²0E#4°Üzü¨ºÒÉ>øf^}lÝ¢|4{ª¢ªÿ}Çàl^Æêöϲ}«·S¥ÀØ;Õ¬LÖEù9ö"oÀÍöö÷f{]bÀ½ÉäÚ2ïäJ¡àdÏRÅpT¯5Es¯ò Õk^þÀoUt¹ShÆïM¾_läeÈo'ª?yn.õz'íC+ç&ùe].}G¥W½îPZ8øu×JºH³f$KÅ-P¿ù$_®Øʶä$~ÏH|½íì{¬³ÁÌÙM^ü}
üÍÛ"æÍt,©ÚÇûp÷¦o¨Íftqä~Õo¤öéÛ=®»
H>S'XêýéRÈ:kyþܺ|+w¤HOZ¬pS©pµjµþ:Ç6ïÖ$1æç{|ð±´{Zêü]GæVòª/_;Ï»§r)Úµ>OÙØÙüÕ%YH,¢ÊÈ/j;6l_f]g>,t
+¼P\{°®9Z^¬ZÂ'h(Û5 3¶YÝÃÂFóéí3ý*ì
åÉìÙüË*kãëx¦<~.7O%ýCk)ñû#-äM-éÞ泌êxªí§ïG®àãÖÖª¬úØçî»*¸°S¶O^BíM^?סîxCUªXÒdîðVà`K£»ú[,æ:Ý¡Ôg,oÚHóñ¼P¯~Û/!Þ:XáÔÓ¯i7®ò>mRªFÌ%%ÀàåÞîöåØ×ëA»Q¹ÎZç:Ík®-hñ;OúÚ endobj
-42 0 obj
-<<
-/Type/FontDescriptor
-/CapHeight 850
-/Ascent 850
-/Descent -200
-/FontBBox[-29 -960 1116 775]
-/FontName/NENDNC+CMSY10
-/ItalicAngle -14.035
-/StemV 85
-/FontFile 41 0 R
-/Flags 68
->>
+6 0 obj <<
+/Type /Font
+/Subtype /Type1
+/Encoding 79 0 R
+/FirstChar 39
+/LastChar 118
+/Widths 80 0 R
+/BaseFont /NPUWBR+CMR17
+/FontDescriptor 4 0 R
+>> endobj
+4 0 obj <<
+/Ascent 694
+/CapHeight 683
+/Descent -195
+/FontName /NPUWBR+CMR17
+/ItalicAngle 0
+/StemV 53
+/XHeight 430
+/FontBBox [-33 -250 945 749]
+/Flags 4
+/CharSet (/quoteright/hyphen/A/G/J/P/S/T/U/a/b/d/e/i/l/m/o/p/r/s/t/u/v)
+/FontFile 5 0 R
+>> endobj
+80 0 obj
+[250 0 0 0 0 0 302 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 693 0 0 0 0 0 726 0 0 471 0 0 0 0 0 628 0 0 511 668 693 0 0 0 0 0 0 0 0 0 0 0 459 511 0 511 406 0 0 0 250 0 0 250 772 0 459 511 0 354 359 354 511 485 ]
endobj
-41 0 obj
-<<
-/Filter[/FlateDecode]
-/Length1 777
-/Length2 594
-/Length3 533
-/Length 1156
->>
-stream
-xÚSUÖuLÉOJuËÏ+Ñ5Ô3´Rpö
-44P0Ô3àRUu.JM,ÉÌÏsI,IµR0´´4Tp,MW04U00·22°25çâRUpÎ/¨,ÊLÏ(QÐpÖ©2WpÌM-ÊLNÌSðM,ÉHÍ£ZR©§ à£ÒR¬ZZT¢ÇÅeh¨\¢Ç¥rg^Z¾9D8¥´- at W¦äçåT*¤¤¦qéûåmKº
dgaqºán¥99~¹ ãÁ
!S U[PZZ¤àZ®4<â8ßÔÌÒ\tYÏÄÌdǼôT]C=cSDf±[fEjJ at fIrBZbNq*X<5/Ý)Àà;DßÏÕÏÅÏYµÙÄ̼ÊTr0ßÁSQf
B´!P!ÂX±h¶¹æ%ç§dæ¥+)$%VrSgªPm¨Z¡Zt²¾^^~ P0ljÒò¸@ñjhn¡ ÜÔ¦Wò+ªu,t-Í&)Ö¢*ÍË,,MõtQ0500°0x-¹´¨(5¯Áã§e65µ"5köÑLÆxYí¯ _\U
-ßuâÜÍ
-³Ô£6JúoÄÚï7=öܹãÚ:vÌ<sOþ¦é
¹Ö9ÇvØÜ÷WÞ¹wü̲5ÆFÉ'9î¼?»×§
é-Ãâ¼öd_ùW¢¾,î
-[â¨cͽþ×ëÂê÷æÿ®jIØï.±á¸M¸ 뵩EeÁ¬~¿?vâ[APE_:óî¸'SÛ¹OÉZÝ0¸:}Ó9NÖÕmï}^ê5QËÅþ¬Ë÷ÃËþYmX%WáµîؽëxÊnÍå²Û¾³+ÉøæË?ðÉÖɽÈêsç³ûÿýþ¾ÇzM='ûxÍSózÕi|_Þ6o͸£øó2ËsÃf§/hlÿÞzöÜÿË¿¦oüå[<»\¿7Ý/¬ÔäØÑÝÏ'íSØØRô}UľÅܽ÷Ïpµm»aس¬ÿN×GëëáùONEUýd[zÆïvåÕi}þo¼ë£æmýðä@ÇÙƾ3þ¯½Þt_!ýÉ8¡d3ãákûe»/[S·}ÎTeÿ¶¬×æw\¿ðÎ@ñ¸÷ïm\ê'Ïå[µ,úW$cïM¦ÉgÏ>6Vé|È)5]fkÚÓí"Y61|QÍÁ{BÁRÐIJçM¤}ÉmK®ñûk¾ØMW(úÄWÁ°,æ-¢éYÅ¿Ï-VÉeÐ==kÌnÏ
-:~§ö;]ê¸sææ÷Úν·WoÜÚ÷hetº7#[HÃ$ÆÒK±S¡ÆAßÇóZü
-þOåÛô¢ò×
-g
¼<þi@!à5`XXTXÍÅ-endstream
-endobj
-1 0 obj
-<<
-/Creator( TeX output 2007.04.23:1418)
-/Producer(dvipdfm 0.13.2c, Copyright \251 1998, by Mark A. Wicks)
-/CreationDate(D:20070423141904+01'00')
->>
-endobj
-5 0 obj
-<<
-/Type/Page
-/Resources 6 0 R
-/Contents[28 0 R 4 0 R 29 0 R 30 0 R]
-/Parent 70 0 R
->>
-endobj
-32 0 obj
-<<
-/Type/Page
-/Resources 33 0 R
-/Contents[28 0 R 4 0 R 37 0 R 30 0 R]
-/Parent 70 0 R
->>
-endobj
-70 0 obj
-<<
-/Type/Pages
-/Count 2
-/Kids[5 0 R 32 0 R]
-/Parent 3 0 R
->>
-endobj
-39 0 obj
-<<
-/Type/Page
-/Resources 40 0 R
-/Contents[28 0 R 4 0 R 44 0 R 30 0 R]
-/Parent 71 0 R
->>
-endobj
-46 0 obj
-<<
-/Type/Page
-/Resources 47 0 R
-/Contents[28 0 R 4 0 R 48 0 R 30 0 R]
-/Parent 71 0 R
->>
-endobj
-71 0 obj
-<<
-/Type/Pages
-/Count 2
-/Kids[39 0 R 46 0 R]
-/Parent 3 0 R
->>
-endobj
-50 0 obj
-<<
-/Type/Page
-/Resources 51 0 R
-/Contents[28 0 R 4 0 R 52 0 R 30 0 R]
-/Parent 72 0 R
->>
-endobj
-54 0 obj
-<<
-/Type/Page
-/Resources 55 0 R
-/Contents[28 0 R 4 0 R 56 0 R 30 0 R]
-/Parent 72 0 R
->>
-endobj
-72 0 obj
-<<
-/Type/Pages
-/Count 2
-/Kids[50 0 R 54 0 R]
-/Parent 3 0 R
->>
-endobj
-58 0 obj
-<<
-/Type/Page
-/Resources 59 0 R
-/Contents[28 0 R 4 0 R 60 0 R 30 0 R]
-/Parent 73 0 R
->>
-endobj
-62 0 obj
-<<
-/Type/Page
-/Resources 63 0 R
-/Contents[28 0 R 4 0 R 64 0 R 30 0 R]
-/Parent 73 0 R
->>
-endobj
-66 0 obj
-<<
-/Type/Page
-/Resources 67 0 R
-/Contents[28 0 R 4 0 R 68 0 R 30 0 R]
-/Parent 73 0 R
->>
-endobj
-73 0 obj
-<<
-/Type/Pages
-/Count 3
-/Kids[58 0 R 62 0 R 66 0 R]
-/Parent 3 0 R
->>
-endobj
-3 0 obj
-<<
-/Type/Pages
-/Count 9
-/Kids[70 0 R 71 0 R 72 0 R 73 0 R]
-/MediaBox[0 0 595 842]
->>
-endobj
-28 0 obj
-<<
-/Length 1
->>
-stream
-
-endstream
-endobj
-30 0 obj
-<<
-/Length 1
->>
-stream
-
-endstream
-endobj
-4 0 obj
-<<
-/Length 33
->>
-stream
-1.00028 0 0 1.00028 72 769.82 cm
-endstream
-endobj
-74 0 obj
-<<
->>
-endobj
-75 0 obj
-null
-endobj
-76 0 obj
-<<
->>
-endobj
-2 0 obj
-<<
-/Type/Catalog
-/Pages 3 0 R
-/Outlines 74 0 R
-/Threads 75 0 R
-/Names 76 0 R
->>
-endobj
+79 0 obj <<
+/Type /Encoding
+/Differences [ 0 /.notdef 39/quoteright 40/.notdef 45/hyphen 46/.notdef 65/A 66/.notdef 71/G 72/.notdef 74/J 75/.notdef 80/P 81/.notdef 83/S/T/U 86/.notdef 97/a/b 99/.notdef 100/d/e 102/.notdef 105/i 106/.notdef 108/l/m 110/.notdef 111/o/p 113/.notdef 114/r/s/t/u/v 119/.notdef]
+>> endobj
+25 0 obj <<
+/Type /Pages
+/Count 6
+/Parent 81 0 R
+/Kids [2 0 R 27 0 R 33 0 R 39 0 R 42 0 R 45 0 R]
+>> endobj
+50 0 obj <<
+/Type /Pages
+/Count 5
+/Parent 81 0 R
+/Kids [48 0 R 52 0 R 55 0 R 58 0 R 61 0 R]
+>> endobj
+81 0 obj <<
+/Type /Pages
+/Count 11
+/Kids [25 0 R 50 0 R]
+>> endobj
+82 0 obj <<
+/Type /Catalog
+/Pages 81 0 R
+>> endobj
+83 0 obj <<
+/Producer (pdfeTeX-1.21a)
+/Creator (TeX)
+/CreationDate (D:20070628000323+02'00')
+/PTEX.Fullbanner (This is pdfeTeX, Version 3.141592-1.21a-2.2 (Web2C 7.5.4) kpathsea version 3.5.4)
+>> endobj
xref
-0 77
+0 84
0000000000 65535 f
-0000090280 00000 n
-0000092043 00000 n
-0000091696 00000 n
-0000091896 00000 n
-0000090444 00000 n
-0000008923 00000 n
-0000028122 00000 n
-0000027938 00000 n
+0000002779 00000 n
+0000002664 00000 n
0000000009 00000 n
-0000033601 00000 n
-0000033415 00000 n
-0000000985 00000 n
-0000039334 00000 n
-0000039145 00000 n
-0000001886 00000 n
-0000046799 00000 n
-0000046611 00000 n
-0000002816 00000 n
-0000062083 00000 n
-0000061897 00000 n
-0000003717 00000 n
-0000065044 00000 n
-0000064858 00000 n
-0000004665 00000 n
-0000068015 00000 n
-0000067829 00000 n
-0000005649 00000 n
-0000091796 00000 n
-0000006633 00000 n
-0000091846 00000 n
-0000008825 00000 n
-0000090546 00000 n
-0000012202 00000 n
-0000075561 00000 n
-0000075375 00000 n
-0000008984 00000 n
-0000009711 00000 n
-0000012114 00000 n
-0000090727 00000 n
-0000015475 00000 n
-0000089011 00000 n
-0000088816 00000 n
-0000012264 00000 n
-0000013198 00000 n
-0000015376 00000 n
-0000090831 00000 n
-0000017841 00000 n
-0000015537 00000 n
-0000017797 00000 n
-0000091013 00000 n
-0000019992 00000 n
-0000017903 00000 n
-0000019926 00000 n
-0000091117 00000 n
-0000022074 00000 n
-0000020054 00000 n
-0000022008 00000 n
-0000091299 00000 n
-0000024172 00000 n
-0000022136 00000 n
-0000024117 00000 n
-0000091403 00000 n
-0000026107 00000 n
-0000024234 00000 n
-0000026052 00000 n
-0000091507 00000 n
-0000027876 00000 n
-0000026169 00000 n
-0000027810 00000 n
-0000090650 00000 n
-0000090935 00000 n
-0000091221 00000 n
-0000091611 00000 n
-0000091978 00000 n
-0000092000 00000 n
-0000092021 00000 n
+0000090585 00000 n
+0000085270 00000 n
+0000090430 00000 n
+0000084456 00000 n
+0000079003 00000 n
+0000084301 00000 n
+0000078094 00000 n
+0000070609 00000 n
+0000077936 00000 n
+0000069279 00000 n
+0000054466 00000 n
+0000069122 00000 n
+0000054122 00000 n
+0000051739 00000 n
+0000053967 00000 n
+0000051395 00000 n
+0000049007 00000 n
+0000051240 00000 n
+0000048176 00000 n
+0000041916 00000 n
+0000048020 00000 n
+0000091377 00000 n
+0000005512 00000 n
+0000005394 00000 n
+0000002916 00000 n
+0000040611 00000 n
+0000027165 00000 n
+0000040453 00000 n
+0000008395 00000 n
+0000008277 00000 n
+0000005605 00000 n
+0000026849 00000 n
+0000025464 00000 n
+0000026692 00000 n
+0000011229 00000 n
+0000011111 00000 n
+0000008535 00000 n
+0000013624 00000 n
+0000013506 00000 n
+0000011310 00000 n
+0000015618 00000 n
+0000015500 00000 n
+0000013729 00000 n
+0000018279 00000 n
+0000018161 00000 n
+0000015723 00000 n
+0000091485 00000 n
+0000020295 00000 n
+0000020177 00000 n
+0000018360 00000 n
+0000022831 00000 n
+0000022713 00000 n
+0000020400 00000 n
+0000024482 00000 n
+0000024364 00000 n
+0000022924 00000 n
+0000025371 00000 n
+0000025253 00000 n
+0000024587 00000 n
+0000027079 00000 n
+0000027056 00000 n
+0000041422 00000 n
+0000041073 00000 n
+0000048729 00000 n
+0000048434 00000 n
+0000051641 00000 n
+0000051606 00000 n
+0000054368 00000 n
+0000054333 00000 n
+0000070109 00000 n
+0000069725 00000 n
+0000078642 00000 n
+0000078396 00000 n
+0000084930 00000 n
+0000084713 00000 n
+0000091060 00000 n
+0000090835 00000 n
+0000091587 00000 n
+0000091654 00000 n
+0000091705 00000 n
trailer
<<
-/Size 77
-/Root 2 0 R
-/Info 1 0 R
+/Size 84
+/Root 82 0 R
+/Info 83 0 R
+/ID [<0005E6093B0F959C8EA0BF96414DD1C4> <0005E6093B0F959C8EA0BF96414DD1C4>]
>>
startxref
-92138
+91908
%%EOF
Modified: puppetor/trunk/doc/howto.tex
===================================================================
--- puppetor/trunk/doc/howto.tex 2007-06-27 20:52:42 UTC (rev 10686)
+++ puppetor/trunk/doc/howto.tex 2007-06-27 22:09:47 UTC (rev 10687)
@@ -74,22 +74,28 @@
homepage.
After downloading, you need to put the Tor executable to the base directory of
-this framework and make sure that it has the name \texttt{tor.exe} or
-\texttt{tor.sh}, respectively.\footnote{This is going to be configurable in the
-future.} Further, you need to have a Java Runtime Environment version 5 or
-higher installed on your machine.
+this framework or make sure that it is in the path. You also need to put the
+Tor Controller API classes somewhere. Further, you need to have a
+Java Runtime Environment version 5 or higher installed on your machine.
-You can then start the examples with one of the following commands:
+You can then start the examples with one of the following commands from the
+base directory of this framework, assuming that the Tor Controller API
+classes reside in directory \texttt{../torctl} (line break behind
+\texttt{examples.} included for layout reasons only):
\begin{verbatim}
-java -cp bin
- de.uniba.wiai.lspi.puppetor.examples.AccessingPublicWebServerOverTor
-java -cp bin
- de.uniba.wiai.lspi.puppetor.examples.AdvertisingHiddenServiceToPublicTorNetwork
-java -cp bin
- de.uniba.wiai.lspi.puppetor.examples.AdvertisingAndAccessingHiddenServiceOverPublicTorNetwork
-java -cp bin
- de.uniba.wiai.lspi.puppetor.examples.AdvertisingAndAccessingHiddenServiceOverPrivateTorNetwork
+java -cp bin:../torctl/bin
+ de.uniba.wiai.lspi.puppetor.examples.
+ AccessingPublicWebServerOverTor
+java -cp bin:../torctl/bin
+ de.uniba.wiai.lspi.puppetor.examples.
+ AdvertisingHiddenServiceToPublicTorNetwork
+java -cp bin:../torctl/bin
+ de.uniba.wiai.lspi.puppetor.examples.
+ AdvertisingAndAccessingHiddenServiceOverPublicTorNetwork
+java -cp bin:../torctl/bin
+ de.uniba.wiai.lspi.puppetor.examples.
+ AdvertisingAndAccessingHiddenServiceOverPrivateTorNetwork
\end{verbatim}
\section{Example 1: Accessing public Web server over Tor}
@@ -221,6 +227,12 @@
network.shutdownNodes();
\end{verbatim}
+A typical output of example 1 might look like the following:
+
+\begin{verbatim}
+Request took 527 millis
+\end{verbatim}
+
\section{Example 2: Advertising hidden service to public Tor network}
The second-easiest example is to advertise a hidden service to the public Tor
@@ -297,6 +309,19 @@
network.shutdownNodes();
\end{verbatim}
+A typical output of example 2 might look like the following:
+
+\begin{verbatim}
+Waiting for 2 minutes and observing RSD publications...
+RSD published 38514 millis after first circuit was opened
+RSD published 38514 millis after first circuit was opened
+RSD published 38779 millis after first circuit was opened
+RSD published 100074 millis after first circuit was opened
+RSD published 100567 millis after first circuit was opened
+RSD published 100568 millis after first circuit was opened
+Exiting...
+\end{verbatim}
+
\section{Example 3: Advertising and accessing hidden service over public Tor
network}
@@ -394,6 +419,14 @@
network.shutdownNodes();
\end{verbatim}
+A typical output of example 3 might look like the following:
+
+\begin{verbatim}
+Request took 13808 millis from client to server!
+Request took 14851 millis for the rount-trip and 1043 millis from server to client!
+Exiting...
+\end{verbatim}
+
\section{Example 4: Advertising and accessing hidden service over private Tor
network}
@@ -491,6 +524,19 @@
network.shutdownNodes();
\end{verbatim}
+A typical output of example 4 might look like the following:
+
+\begin{verbatim}
+Successfully started nodes!
+Successfully built circuits!
+All RSDs published!
+Started server
+Handling event: APPLICATION_SENDING_REQUEST
+Handling event: APPLICATION_REQUEST_RECEIVED
+Handling event: APPLICATION_REPLY_RECEIVED
+Handling event: APPLICATION_REQUESTS_PERFORMED
+\end{verbatim}
+
\section{Architecture}
Though the examples show how to use the simulator, they do not provide insights
@@ -526,8 +572,6 @@
private-network example.
\item Fight the TODOs\ldots
-
-\item Complete logging and documentation for the impl package.
\end{itemize}
\end{document}
\ No newline at end of file
Modified: puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/ClientApplication.java
===================================================================
--- puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/ClientApplication.java 2007-06-27 20:52:42 UTC (rev 10686)
+++ puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/ClientApplication.java 2007-06-27 22:09:47 UTC (rev 10687)
@@ -3,7 +3,7 @@
/**
* The <code>ClientApplication</code> can be used to simulate simple
* <code>HTTP GET</code> requests by a virtual local client. Therefore, an
- * address and a port are given wo which the client shall connect. Requests are
+ * address and a port are given to which the client shall connect. Requests are
* performed by a background thread, so that multiple requests could be
* performed at the same time.
*
@@ -13,9 +13,10 @@
/**
* <p>
- * Arranges for the requests being performed by a thread in the background
- * and returns immediately. This thread will try for <code>retries</code>
- * times to make the request with a timeout of
+ * Performs one or more HTTP requests to a previously provided address and
+ * port. All requests are performed by a thread in the background, so that
+ * this method may return immediately. That thread will try for
+ * <code>retries</code> times to make the request with a timeout of
* <code>timeoutForEachRetry</code> millis each. If an attempt is not
* successful, the thread nevertheless waits for the timeout to expire. If
* <code>stopOnSuccess</code> is set to <code>true</code>, the thread
@@ -32,6 +33,8 @@
* is fired.
* </p>
*
+ * TODO may this method only be invoked once?!
+ *
* @param retries
* The number of retries that this client will perform. Must be
* <code>1</code> or greater.
@@ -48,8 +51,14 @@
* Thrown if an invalid value is given for either of the
* parameters.
*/
- public void performRequest(int retries, long timeoutForEachRetry,
+ public abstract void performRequest(int retries, long timeoutForEachRetry,
boolean stopOnSuccess);
- // TODO we need some way to interrupt performing requests
+ /**
+ * Stops all requests that are currently running.
+ *
+ * @throws IllegalStateException
+ * Thrown if no requests have been started before.
+ */
+ public abstract void stopRequest();
}
Modified: puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/DirectoryNode.java
===================================================================
--- puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/DirectoryNode.java 2007-06-27 20:52:42 UTC (rev 10686)
+++ puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/DirectoryNode.java 2007-06-27 22:09:47 UTC (rev 10687)
@@ -3,37 +3,43 @@
import java.util.Set;
/**
- * A DirectoryNode represents a Tor process that acts as RouterNode and is
- * further a directory authoritative server for the (private) Tor network. It
- * inherits most of the configuration and behavior from RouterNode and adds some
- * directory-specific configurations and behavior.
+ * A <code>DirectoryNode</code> represents a Tor process that acts as
+ * <code>RouterNode</code> and which is further a directory authoritative
+ * server for the (private) Tor network. It inherits most of the configuration
+ * and behavior from <code>RouterNode</code> and adds some directory-specific
+ * configurations and behavior.
*
* @author kloesing
*/
public interface DirectoryNode extends RouterNode {
/**
- * Combines the node's fingerprint to a DirServer string that can be used to
- * configure this or other nodes to use this node as directory server.
+ * Combines the fingerprint of this node to a <code>DirServer</code>
+ * string that can be used to configure this or other nodes to use this node
+ * as directory server.
*
- * @return DirServer string to configure a node to use this node as
- * directory server.
+ * @return <code>DirServer</code> string to configure a node to use this
+ * node as directory server.
* @throws TorProcessException
- * Thrown if a problem occurs when determining the node's
- * fingerprint.
+ * Thrown if a problem occurs when determining the fingerprint
+ * of this node.
*/
public abstract String determineDirServerString()
throws TorProcessException;
/**
- * Writes the given set of routers (either directories or routers) to the
- * <code>approved-routers</code> file. This will confirm to directory
- * clients, that the given routers can be trusted.
+ * Writes the given (possibly empty) set of onion router fingerprints to the
+ * <code>approved-routers</code> file of this node. This will confirm to
+ * directory clients, that the given routers can be trusted.
*
* @param approvedRouters
- * The set of approved routers to be written.
+ * The set of approved routers to be written. Each provided
+ * string must be formatted as
+ * <code>nickname 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000</code>.
* @throws IllegalArgumentException
- * Thrown if <code>null</code> is passed as parameter.
+ * Thrown if <code>null</code> is passed as parameter;
+ * however, if an empty set is passed, an empty
+ * <code>approved-routers</code> file will be written.
* @throws TorProcessException
* Thrown if the <code>approved-routers</code> file cannot be
* written to disk.
Modified: puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/Event.java
===================================================================
--- puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/Event.java 2007-06-27 20:52:42 UTC (rev 10686)
+++ puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/Event.java 2007-06-27 22:09:47 UTC (rev 10687)
@@ -1,9 +1,9 @@
package de.uniba.wiai.lspi.puppetor;
/**
- * An Event is created for every state change of an asynchronous system
- * component, e.g. a Tor process or a client/server application running as
- * thread in the background. In contrast to <code>NodeState</code> or
+ * An <code>Event</code> is created for every state change of an asynchronous
+ * system component, e.g. a Tor process or a client/server application running
+ * as thread in the background. In contrast to <code>NodeState</code> or
* <code>NetworkState</code> an <code>Event</code> cannot be a pre- or
* postconditions for a method invocation. There is no prescribed order in which
* events are fired by a certain process or application. Some events can be
Modified: puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/EventManager.java
===================================================================
--- puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/EventManager.java 2007-06-27 20:52:42 UTC (rev 10686)
+++ puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/EventManager.java 2007-06-27 22:09:47 UTC (rev 10687)
@@ -3,11 +3,11 @@
import java.util.List;
/**
- * The EventManager is the central place for a test run to manage asynchronous
- * events by Tor processes and client/server applications running as threads in
- * the background. A test application can either register event listeners to be
- * notified asynchronously about events when they occur, or synchronize with an
- * event by being blocked until the certain event occurs.
+ * The <code>EventManager</code> is the central place for a test run to manage
+ * asynchronous events by Tor processes and client/server applications running
+ * as threads in the background. A test application can either register event
+ * listeners to be notified asynchronously about events when they occur, or
+ * synchronize with an event by being blocked until the certain event occurs.
*
* @author kloesing
*/
Modified: puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/Network.java
===================================================================
--- puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/Network.java 2007-06-27 20:52:42 UTC (rev 10686)
+++ puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/Network.java 2007-06-27 22:09:47 UTC (rev 10687)
@@ -16,7 +16,9 @@
* Configures the nodes in this network so that they can run in a private
* network and don't require public directory servers or onion routers from
* the Internet. This configuration should be done after configuring the
- * nodes and before writing configurations to disk.
+ * nodes and before writing configurations to disk. This operation can only
+ * be invoked, if network status is
+ * <code>NetworkState.CONFIGURING_NODES</code>.
* </p>
*
* <p>
@@ -55,8 +57,9 @@
* TODO check if we have enough directory and router nodes to build a
* private network? How many are required? 2 dirs and 3 routers?
*
- * TODO allow invocation of this method only in correct state
- *
+ * @throws IllegalStateException
+ * Thrown if network is not in state
+ * <code>NetworkState.CONFIGURING_NODES</code>.
* @throws TorProcessException
* Thrown if an I/O problem occurs while starting nodes with the
* <code>--list-fingerprint</code> option, reading files from
@@ -68,16 +71,14 @@
/**
* Creates a new client application, but does not yet perform a request.
*
- * TODO allow invocation of this method only in correct state
- *
* @param clientApplicationName
* The name for this client application, which is used for
- * logging purposes only. May neither be null or a zero-length
- * string.
+ * logging purposes only. May neither be <code>null</code> or a
+ * zero-length string.
* @param targetAddress
* The target for requests sent by this client application. Can
* be an IP address, a domain name, or an onion address. May
- * neither be null or a zero-length string.
+ * neither be <code>null</code> or a zero-length string.
* @param targetPort
* The TCP port for requests sent by this client application. If
* the target address is an onion address, this port is the
@@ -99,9 +100,9 @@
/**
* Creates a new directory node and adds it to the network, but does not yet
* write its configuration to disk or start the corresponding Tor process.
+ * This operation can only be invoked, if network status is
+ * <code>NetworkState.CONFIGURING_NODES</code>.
*
- * TODO allow invocation of this method only in correct state
- *
* @param nodeName
* The name for this node, which is used as name for the working
* directory, for logging purposes, and as node nickname. May
@@ -123,6 +124,9 @@
* for incoming directory requests. May not be negative or
* greater than 65535.
* @return Reference to the created directory node.
+ * @throws IllegalStateException
+ * Thrown if network is not in state
+ * <code>NetworkState.CONFIGURING_NODES</code>.
* @throws IllegalArgumentException
* Thrown if an invalid value is given for either of the
* parameters.
@@ -131,11 +135,11 @@
int controlPort, int socksPort, int orPort, int dirPort);
/**
- * Creates a new proxy node and adds it to the network, but does not yet
- * write its configuration to disk or start the corresponding Tor process.
+ * Creates a new <code>ProxyNode</code> and adds it to the
+ * <code>network</code>, but does not yet write its configuration to disk
+ * or start the corresponding Tor process. This operation can only be
+ * invoked, if network status is <code>NetworkState.CONFIGURING_NODES</code>.
*
- * TODO allow invocation of this method only in correct state
- *
* @param nodeName
* The name for this node, which is only used as name for the
* working directory and for logging purposes. May neither be
@@ -149,6 +153,9 @@
* for incoming SOCKS requests. May not be negative or greater
* than 65535.
* @return Reference to the created proxy node.
+ * @throws IllegalStateException
+ * Thrown if network is not in state
+ * <code>NetworkState.CONFIGURING_NODES</code>.
* @throws IllegalArgumentException
* Thrown if an invalid value is given for either of the
* parameters.
@@ -159,9 +166,9 @@
/**
* Creates a new router node and adds it to the network, but does not yet
* write its configuration to disk or start the corresponding Tor process.
+ * This operation can only be invoked, if network status is
+ * <code>NetworkState.CONFIGURING_NODES</code>.
*
- * TODO allow invocation of this method only in correct state
- *
* @param nodeName
* The name for this node, which is used as name for the working
* directory, for logging purposes, and as node nickname. May
@@ -184,6 +191,9 @@
* the mirrored directory. May not be negative or greater than
* 65535.
* @return Reference to the created router node.
+ * @throws IllegalStateException
+ * Thrown if network is not in state
+ * <code>NetworkState.CONFIGURING_NODES</code>.
* @throws IllegalArgumentException
* Thrown if an invalid value is given for either of the
* parameters.
@@ -195,12 +205,10 @@
* Creates a new server application, but does not start listening for
* incoming requests.
*
- * TODO allow invocation of this method only in correct state
- *
* @param serverApplicationName
* The name for this server application, which is used for
- * logging purposes only. May neither be null or a zero-length
- * string.
+ * logging purposes only. May neither be <code>null</code> or a
+ * zero-length string.
* @param serverPort
* The TCP port on which the server will wait for incoming
* requests. May not be negative or greater than 65535.
@@ -215,8 +223,6 @@
/**
* Returns a reference on the (single) event manager for this network.
*
- * TODO allow invocation of this method only in correct state
- *
* @return Reference on the (single) event manager for this network.
*/
public abstract EventManager getEventManager();
@@ -244,11 +250,10 @@
* with <code>false</code>. Thus, the maximum waiting time is
* <code>(tries + 1)</code> times <code>hupInterval</code>. As soon as
* all nodes have successfully opened circuits, the method returns with
- * <code>true</code>.
+ * <code>true</code>. This operation can only be invoked, if network
+ * status is <code>NetworkState.NODES_STARTED</code>.
* </p>
*
- * TODO allow invocation of this method only in correct state
- *
* @param tries
* The maximum number of HUP signals that are sent to the Tor
* processes. Negative values are not allowed. A value of zero
@@ -261,6 +266,9 @@
* HUP signals. Negative values are not allowed. Typically,
* values should not be smaller than 10 seconds to permit Tor to
* stabilize.
+ * @throws IllegalStateException
+ * Thrown if network is not in state
+ * <code>NetworkState.NODES_STARTED</code>.
* @throws IllegalArgumentException
* Thrown if a negative value is given for either
* <code>tries</code> or <code>hupInterval</code>.
@@ -276,10 +284,12 @@
* Attempts to shut down all nodes. The method blocks until all shutdown
* requests have been sent and either returns, or throws the first exception
* that has been observed when shutting down nodes. The method can be
- * assumed to return very quickly.
+ * assumed to return very quickly. This operation can only be invoked, if
+ * network status is <code>NetworkState.NODES_STARTED</code>.
*
- * TODO allow invocation of this method only in correct state
- *
+ * @throws IllegalStateException
+ * Thrown if network is not in state
+ * <code>NetworkState.NODES_STARTED</code>.
* @throws TorProcessException
* Thrown if an I/O problem occurs while shutting down the
* nodes.
@@ -291,10 +301,10 @@
* <code>maximumTimeToWaitInMillis</code> millis. The method returns as
* soon as all nodes have started and opened their control port so that we
* can connect to them. It returns a boolean that states whether the
- * operation was either successful or has timed out.
+ * operation was either successful or has timed out. This operation can only
+ * be invoked, if network status is
+ * <code>NetworkState.CONFIGURATIONS_WRITTEN</code>.
*
- * TODO allow invocation of this method only in correct state
- *
* @param maximumTimeToWaitInMillis
* The maximum time to wait in milliseconds. A positive value or
* zero restricts waiting to this time. Negative values are not
@@ -304,18 +314,26 @@
* @throws IllegalArgumentException
* Thrown if a negative value is given for
* <code>maximumTimeToWaitInMillis</code>.
+ * @throws IllegalStateException
+ * Thrown if network is not in state
+ * <code>NetworkState.CONFIGURATIONS_WRITTEN</code>.
* @throws TorProcessException
- * Thrown if an I/O problem occurs while startint the nodes.
+ * Thrown if an I/O problem occurs while starting the nodes.
*/
public abstract boolean startNodes(long maximumTimeToWaitInMillis)
throws TorProcessException;
/**
- * Writes the configurations of all nodes in this network to disk. This
- * method is assumed to return very quickly.
+ * Writes the configurations for all nodes in the network to disk, including
+ * <code>torrc</code> and <code>approved-routers</code> files. This
+ * method is assumed to return very quickly. In case of a private network,
+ * <code>configureAsPrivateNetwork</code> must be invoked in advance to
+ * this method! This operation can only be invoked, if network status is
+ * <code>NetworkState.CONFIGURING_NODES</code>.
*
- * TODO allow invocation of this method only in correct state
- *
+ * @throws IllegalStateException
+ * Thrown if network is not in state
+ * <code>NetworkState.CONFIGURING_NODES</code>.
* @throws TorProcessException
* Thrown if an I/O problem occurs while writing to the nodes'
* working directories.
Modified: puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/NetworkFactory.java
===================================================================
--- puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/NetworkFactory.java 2007-06-27 20:52:42 UTC (rev 10686)
+++ puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/NetworkFactory.java 2007-06-27 22:09:47 UTC (rev 10687)
@@ -13,7 +13,7 @@
* constructor using reflection. Currently, this is the only place where we
* reference a class from the impl package.
*
- * @author karsten
+ * @author kloesing
*/
public abstract class NetworkFactory {
Modified: puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/NetworkState.java
===================================================================
--- puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/NetworkState.java 2007-06-27 20:52:42 UTC (rev 10686)
+++ puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/NetworkState.java 2007-06-27 22:09:47 UTC (rev 10687)
@@ -13,6 +13,7 @@
* @author kloesing
*/
public enum NetworkState {
+
/**
* The configurations of the nodes in the network have not been written to
* disk and can be changed. This is the initial state of a
Modified: puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/NodeState.java
===================================================================
--- puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/NodeState.java 2007-06-27 20:52:42 UTC (rev 10686)
+++ puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/NodeState.java 2007-06-27 22:09:47 UTC (rev 10687)
@@ -14,16 +14,17 @@
public enum NodeState {
/**
- * The node's configuration has not been written to disk and can be changed.
- * This is the initial state of a <code>ProxyNode</code> or one of its
- * subclasses.
+ * The configuration of this node has not been written to disk and can be
+ * changed. This is the initial state of a <code>ProxyNode</code> or one
+ * of its subclasses.
*/
CONFIGURING,
/**
- * The node's configuration has been written to disk and cannot be changed
- * anymore, but the Tor process has not been started, yet. This state could
- * be useful to review the configuration that has been written to disk.
+ * The configuration of this node has been written to disk and cannot be
+ * changed anymore, but the Tor process has not been started, yet. This
+ * state could be useful to review the configuration that has been written
+ * to disk.
*/
CONFIGURATION_WRITTEN,
Modified: puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/ProxyNode.java
===================================================================
--- puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/ProxyNode.java 2007-06-27 20:52:42 UTC (rev 10686)
+++ puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/ProxyNode.java 2007-06-27 22:09:47 UTC (rev 10687)
@@ -3,31 +3,33 @@
import java.util.Set;
/**
- * A ProxyNode represents a Tor process that is configured as onion proxy, i.e.
- * to relay traffic from a local application to the Tor network and vice versa,
- * and does not route traffic on behalf of remote applications. It is the
- * superclass for other node types that extend the configuration of a ProxyNode.
+ * A <code>ProxyNode</code> represents a Tor process that is configured as
+ * onion proxy, i.e. to relay traffic from a local application to the Tor
+ * network and vice versa, and does not route traffic on behalf of remote
+ * applications. It is the superclass for other node types that extend the
+ * configuration of a </code>ProxyNode</code>.
*
* @author kloesing
*/
public interface ProxyNode extends EventSource {
/**
- * Adds hidden service entries to this node's configuration. This method can
- * only be invoked while the node is in state
- * <code>NodeState.CONFIGURING</code>. TODO Should this operation also be
- * possible while the process is running? We could easily change the
- * configuration via the controller.
+ * Adds the entries for a hidden service to the configuration of this node.
+ * This method can only be invoked while the node is in state
+ * <code>NodeState.CONFIGURING</code>.
*
+ * TODO Should this operation also be possible while the process is running?
+ * We could easily change the configuration via the controller.
+ *
* @param serviceName
* Name of the hidden service that will be used as name for the
* hidden service directory. May neither be <code>null</code>
* or a zero-length string.
* @param servicePort
* The TCP port on which the service will be available for
- * requests. This can be different for the virtual port that is
- * announced to clients. May not be negative or greater than
- * 65535.
+ * requests. This can, but need not be different from the virtual
+ * port that is announced to clients. May not be negative or
+ * greater than 65535.
* @param virtualPort
* The virtual TCP port that this hidden service runs on as it is
* announced to clients. May not be negative or greater than
@@ -43,17 +45,17 @@
int virtualPort);
/**
- * Adds the given set of DirServer configuration entries to this node's
- * configuration. Note that as soon as one DirServer is configured, the node
- * does not connect to an outside directory server of the public network any
- * more!
+ * Adds the given set of DirServer configuration entries to the
+ * configuration of this node. Note that as soon as one DirServer is
+ * configured, the node does not connect to an outside directory server of
+ * the public network any more!
*
* TODO allow invocation of this method only in correct state
*
* @param authorizedDirServerStrings
* A set of DirServer configuration entries that each contain one
* directory server that this node shall connect to. May not be
- * <code>null</code>.
+ * <code>null</code>, but may be an empty set.
* @throws IllegalArgumentException
* Thrown if <code>null</code> is passed as parameter.
*/
@@ -61,21 +63,35 @@
Set<String> authorizedDirServerStrings);
/**
- * Returns the node's name.
+ * Adds the given configuration string to the configuration of this node.
*
- * @return The node's name.
+ * @param configurationString
+ * The configuration string to be added.
+ * @throws IllegalArgumentException
+ * Thrown if the given configurationString is either
+ * <code>null</code> or a zero-length string.
+ * @throws IllegalStateException
+ * Thrown if not invoked in state
+ * <code>NodeState.CONFIGURING</code>.
*/
+ public abstract void addConfiguration(String configurationString);
+
+ /**
+ * Returns the name of this node.
+ *
+ * @return The name of this node.
+ */
public abstract String getNodeName();
/**
- * Returns the node's state.
+ * Returns the state of this node.
*
- * @return The node's state.
+ * @return The state of this node.
*/
public abstract NodeState getNodeState();
/**
- * Determines the onion address for the previously added hidden service with
+ * Determines the onion address for a previously added hidden service with
* name <code>serviceName</code>. Requires that the node has been
* started, i.e. is in state <code>NodeState.RUNNING</code>.
*
@@ -83,22 +99,29 @@
* Name of the hidden service that has been used before to add
* the hidden service. May neither be <code>null</code> or a
* zero-length string.
+ * @param version
+ * Hidden service version; can be either 0, 1, or 2. Note that
+ * version 2 may not be implemented in the regular Tor sources!
* @return The onion address string consisting of 16 base32 chars plus
- * ".onion".
+ * ".onion" for hidden service versions 0 and 1 or 16 base32 chars
+ * plus "." plus 24 base32 chars plus ".onion" for hidden service
+ * version 2.
* @throws IllegalArgumentException
* Thrown if <code>null</code> or a zero-length string is
* passed as parameter.
* @throws TorProcessException
* Thrown if either there does not exist a hidden service with
- * the given <code>serviceName</code> as directory or if the
+ * the given <code>serviceName</code> as directory, if the
+ * given <code>version</code> is invalid, or if the
* <code>hostname</code> file could not be read.
*/
- public abstract String getOnionAddress(String serviceName)
+ public abstract String getOnionAddress(String serviceName, int version)
throws TorProcessException;
/**
* Sends a HUP command to the process via its control port to restart it;
- * can only be done if node has already been started!
+ * can only be done if the node has already been started, i.e. is in state
+ * <code>NodeState.RUNNING</code>!
*
* @throws TorProcessException
* Thrown if an I/O problem occurs while sending the HUP signal.
@@ -108,13 +131,14 @@
public abstract void hup() throws TorProcessException;
/**
- * Shuts down Tor process corresponding to this node immediately. This is
- * done by sending the <code>SHUTDOWN</code> signal twice, so that nodes
- * extending ProxyNode and have opened their OR port shutdown immediately,
- * too.
+ * Shuts down the Tor process corresponding to this node immediately. This
+ * is done by sending the <code>SHUTDOWN</code> signal twice, so that
+ * those nodes extending <code>ProxyNode</code> which have opened their OR
+ * port shutdown immediately, too.
*
* @throws IllegalStateException
- * Thrown if node is not in state <code>NodeState.RUNNING</code>.
+ * Thrown if this node is not in state
+ * <code>NodeState.RUNNING</code>.
* @throws TorProcessException
* Thrown if an I/O problem occurs while sending the
* <code>SHUTDOWN</code> signal.
@@ -125,8 +149,8 @@
* Starts the Tor process for this node and connects to the control port as
* soon as it is opened. <b>In order for this method to succeed it is
* absolutely necessary, that logging on the console is not changed in the
- * node's configuration to a higher level than NOTICE, because the output is
- * parsed to see when the control port is opened.</b>
+ * configuration of this node to a higher level than NOTICE, because the
+ * output is parsed to see when the control port is opened.</b>
*
* @param maximumTimeToWaitInMillis
* Maximum time in millis we will wait for the Tor process to be
@@ -150,15 +174,29 @@
throws TorProcessException;
/**
- * Writes the node's configuration to the <code>torrc</code> file in the
- * node's working directory and changes the state to
+ * Writes the configuration of this node to the <code>torrc</code> file in
+ * its working directory and changes the state to
* <code>NodeState.CONFIGURATION_WRITTEN</code>.
*
* @throws IllegalStateException
* Thrown if not invoked in state
* <code>NodeState.CONFIGURING</code>.
* @throws TorProcessException
- * Thrown if the configuration file cannot be written to disk.
+ * Thrown if the configuration file <code>torrc</code> cannot
+ * be written to disk.
*/
public abstract void writeConfiguration() throws TorProcessException;
+
+ /**
+ * Copies all locally stored descriptors of this node to the data directory
+ * of the given <code>node</code>. Note that this method only makes sense
+ * when used with a modified Tor implementation!
+ *
+ * @param otherNode
+ * Node to which data directory the .rsd files shall be copied.
+ * @throws TorProcessException
+ * Thrown if copying files does not succeed.
+ */
+ public abstract void copyDescriptorTo(ProxyNode otherNode)
+ throws TorProcessException;
}
Modified: puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/RouterNode.java
===================================================================
--- puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/RouterNode.java 2007-06-27 20:52:42 UTC (rev 10686)
+++ puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/RouterNode.java 2007-06-27 22:09:47 UTC (rev 10687)
@@ -1,11 +1,11 @@
package de.uniba.wiai.lspi.puppetor;
/**
- * A RouterNode represents a Tor process that is configured to both, relay
- * traffic from a local application to the Tor network and to route traffic on
- * behalf of remote applications. It inherits most of its configuration and
- * behavior from its superclass ProxyNode and adds some router-specific
- * configurations and behavior.
+ * A <code>RouterNode</code> represents a Tor process that is configured to
+ * both, relay traffic from a local application to the Tor network and to route
+ * traffic on behalf of remote applications. It inherits most of its
+ * configuration and behavior from its superclass <code>ProxyNode</code> and
+ * adds some router-specific configurations and behavior.
*
* @author kloesing
*/
@@ -13,10 +13,11 @@
/**
* <p>
- * Determines the directory node's fingerprint. If the Tor process has not
- * been started before, it is started to determine the node's fingerprint.
- * This is done using a temporary configuration file and with the
- * command-line option <code>--list-fingerprint</code>. Tor then
+ * Determines the directory fingerprint of this node. If the Tor process has
+ * not been started before, it is started and immediately stopped
+ * afterwards, so that the Tor process creates a new onion key pair and
+ * fingerprint for it. This is done using a temporary configuration file and
+ * with the command-line option <code>--list-fingerprint</code>. Tor then
* generates a new onion key and writes its fingerprint to the
* <code>fingerprint</code> file in its working directory, but does not
* start routing traffic.
@@ -43,7 +44,7 @@
* before specifying directory servers for this node.
* </p>
*
- * @return The content of the node's fingerprint file.
+ * @return The content of the fingerprint file of this node.
* @throws TorProcessException
* Thrown if either the temporary <code>torrc</code>
* configuration file cannot be written, the Tor process cannot
Modified: puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/ServerApplication.java
===================================================================
--- puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/ServerApplication.java 2007-06-27 20:52:42 UTC (rev 10686)
+++ puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/ServerApplication.java 2007-06-27 22:09:47 UTC (rev 10687)
@@ -11,11 +11,21 @@
public interface ServerApplication extends EventSource {
/**
- * Starts listening for incoming <code>HTTP GET</code> requests by
+ * Starts listening for incoming <code>HTTP GET</code> requests from
* clients. Any incoming request is answered by an empty
- * <code>HTTP OK</code> reply.
+ * <code>HTTP OK</code> reply. This method may only be invoked once!
+ *
+ * @throws IllegalStateException
+ * Thrown if <code>listen</code> has already been invoked
+ * before.
*/
public abstract void listen();
- // TODO we need some way to interrupt listening for requests
+ /**
+ * Stops listening for requests.
+ *
+ * @throws IllegalStateException
+ * Thrown if <code>listen</code> has not been invoked before.
+ */
+ public abstract void stopListening();
}
Modified: puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/TorProcessException.java
===================================================================
--- puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/TorProcessException.java 2007-06-27 20:52:42 UTC (rev 10686)
+++ puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/TorProcessException.java 2007-06-27 22:09:47 UTC (rev 10687)
@@ -5,9 +5,10 @@
* exceptions that occur when interacting with the JVM-external Tor processes or
* with the local file system. Any occurence of this exception denotes either a
* configuration problem that can only be solved outside of the JVM, or an
- * unexpected problem. In contrast to this, all kinds of programming errors of a
- * test application (invoking a method with wrong parameter values, in wrong
- * state, etc.) will instead cause runtime exceptions from the Java API.
+ * unexpected problem. In contrast to this, all kinds of programming errors of
+ * an application using this API (invoking a method with wrong parameter values,
+ * in wrong state, etc.) will instead cause appropriate runtime exceptions from
+ * the Java API.
*
* @author kloesing
*/
@@ -15,15 +16,16 @@
public class TorProcessException extends Exception {
/**
- * Creates a TorProcessException without a detail message or cause.
+ * Creates a <code>TorProcessException</code> without detail message or
+ * cause.
*/
public TorProcessException() {
super();
}
/**
- * Creates a TorProcessException with the given detail <code>message</code>
- * and <code>cause</code>.
+ * Creates a <code>TorProcessException</code> with the given detail
+ * <code>message</code> and <code>cause</code>.
*
* @param message
* The detail message of this exception.
@@ -35,8 +37,8 @@
}
/**
- * Creates a TorProcessException with the given detail <code>message</code>,
- * but without a cause.
+ * Creates a <code>TorProcessException</code> with the given detail
+ * <code>message</code>, but without a <code>cause</code>.
*
* @param message
* The detail message of this exception.
@@ -46,8 +48,8 @@
}
/**
- * Creates a TorProcessException with the given <code>cause</code>, but
- * without a detail message.
+ * Creates a <code>TorProcessException</code> with the given
+ * <code>cause</code>, but without a detail message.
*
* @param cause
* The cause for this exception.
Modified: puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/examples/AccessingPublicWebServerOverTor.java
===================================================================
--- puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/examples/AccessingPublicWebServerOverTor.java 2007-06-27 20:52:42 UTC (rev 10686)
+++ puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/examples/AccessingPublicWebServerOverTor.java 2007-06-27 22:09:47 UTC (rev 10687)
@@ -9,8 +9,8 @@
import de.uniba.wiai.lspi.puppetor.TorProcessException;
/**
- * Example for accessing a public Web server (www.google.com) over Tor to
- * measure access times.
+ * Example for accessing a public Web server (here: <code>www.google.com</code>)
+ * over Tor to measure access times.
*
* @author kloesing
*/
@@ -20,16 +20,15 @@
* Sets up and runs the test.
*
* @param args
- * Command-line arguments are ignored.
- *
+ * Command-line arguments (ignored).
* @throws TorProcessException
* Thrown if there is a problem with the JVM-external Tor
* processes that we cannot handle.
*/
public static void main(String[] args) throws TorProcessException {
- // though we only need one proxy, we always need to create a network
- // to initialize a test case
+ // though we only need a single proxy, we always need to create a
+ // network to initialize a test case.
Network network = NetworkFactory.createNetwork("example1");
// create a single proxy node with name "proxy", control port 7001,
@@ -57,7 +56,7 @@
// create client application
ClientApplication client = network.createClient("client",
- "www.google.de", 80, 7002);
+ "www.google.com", 80, 7002);
// create event listener to listen for client application events
EventListener clientEventListener = new EventListener() {
@@ -92,9 +91,20 @@
manager.waitForAnyOccurence(client,
Event.APPLICATION_REQUESTS_PERFORMED);
+ // wait a second before shutting down the proxy
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ }
+
// shut down proxy
network.shutdownNodes();
- System.out.println("Exiting...");
+ // wait another second before exiting the application
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ }
+
}
}
Modified: puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/examples/AdvertisingAndAccessingHiddenServiceOverPrivateTorNetwork.java
===================================================================
--- puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/examples/AdvertisingAndAccessingHiddenServiceOverPrivateTorNetwork.java 2007-06-27 20:52:42 UTC (rev 10686)
+++ puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/examples/AdvertisingAndAccessingHiddenServiceOverPrivateTorNetwork.java 2007-06-27 22:09:47 UTC (rev 10687)
@@ -22,8 +22,7 @@
* Sets up and runs the test.
*
* @param args
- * Command-line arguments are ignored.
- *
+ * Command-line arguments (ignored).
* @throws TorProcessException
* Thrown if there is a problem with the JVM-external Tor
* processes that we cannot handle.
@@ -45,14 +44,15 @@
RouterNode router1 = network.createRouter("router1", 7021, 7022, 7023,
7024);
network.createRouter("router2", 7031, 7032, 7033, 7034);
- network.createRouter("router3", 7041, 7042, 7043, 7044);
+ network.createRouter("router3", 7041, 7042, 7043,
+ 7044);
// create two directory nodes with parameters (router name, control
// port, SOCKS port, OR port, dir port)
network.createDirectory("dir1", 7051, 7052, 7053, 7054);
network.createDirectory("dir2", 7061, 7062, 7063, 7064);
- // add hidden service to the configuration of proxy1
+ // add hidden service
router1.addHiddenService("hidServ", 7025, 80);
// configure nodes of this network to be part of a private network
@@ -62,93 +62,72 @@
network.writeConfigurations();
// start proxy node and wait until it has opened a circuit with a
- // timeout of 5 seconds
- if (!network.startNodes(5000)) {
+ // timeout of 15 seconds
+ if (!network.startNodes(15000)) {
// failed to start the proxy
System.out.println("Failed to start nodes!");
return;
}
+ System.out.println("Successfully started nodes!");
- // hup until proxy has built circuits (8 retries, 10 seconds timeout
+ // hup until proxy has built circuits (10 retries, 10 seconds timeout
// each)
- if (!network.hupUntilUp(8, 10000)) {
+ if (!network.hupUntilUp(10, 10000)) {
// failed to build circuits
System.out.println("Failed to build circuits!");
return;
}
+ System.out.println("Successfully built circuits!");
// obtain reference to event manager to be able to respond to events
EventManager manager = network.getEventManager();
// wait for 3 minutes that the proxy has published its first RSD
+
if (!manager.waitForAnyOccurence(router1, Event.NODE_RSD_PUBLISHED,
3L * 60L * 1000L)) {
-
// failed to publish an RSD
System.out.println("Failed to publish an RSD!");
return;
}
+ System.out.println("All RSDs published!");
// determine onion address for hidden service
- String onionAddress = router1.getOnionAddress("hidServ");
+ String onionAddress = router1.getOnionAddress("hidServ", 1);
// create server application
ServerApplication server = network.createServer("server", 7025);
+ // start server
+ server.listen();
+ System.out.println("Started server");
+
// create client application
ClientApplication client = network.createClient("client", onionAddress,
80, 7042);
- // create event listener to listen for client and server application
- // events
+ // register event listener
EventListener clientAndServerEventListener = new EventListener() {
- private long requestReceivedAtServer;
-
- // remember time when request was sent and when it was received
- private long requestSentFromClient;
-
public void handleEvent(Event event) {
- switch (event) {
- case APPLICATION_SENDING_REQUEST:
- requestSentFromClient = System.currentTimeMillis();
- break;
- case APPLICATION_REQUEST_RECEIVED:
- requestReceivedAtServer = System.currentTimeMillis();
- System.out.println("Request took "
- + (requestReceivedAtServer - requestSentFromClient)
- + " millis from client to server!");
- break;
- case APPLICATION_REPLY_RECEIVED:
- System.out
- .println("Request took "
- + (System.currentTimeMillis() - requestSentFromClient)
- + " millis for the rount-trip and "
- + (System.currentTimeMillis() - requestReceivedAtServer)
- + " millis from server to client!");
- }
+ System.out.println("Handling event: " + event);
+
}
};
-
- // register event handler for client and server application events
manager.addEventListener(client, clientAndServerEventListener);
manager.addEventListener(server, clientAndServerEventListener);
- // start server
- server.listen();
-
// perform at most five request with a timeout of 45 seconds each
client.performRequest(5, 45000, true);
- // block this thread as long as client requests are running
+ // wait for request to be performed
manager.waitForAnyOccurence(client,
Event.APPLICATION_REQUESTS_PERFORMED);
- // shut down proxy
+ // shut down nodes
network.shutdownNodes();
- System.out.println("Exiting...");
}
}
Modified: puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/examples/AdvertisingAndAccessingHiddenServiceOverPublicTorNetwork.java
===================================================================
--- puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/examples/AdvertisingAndAccessingHiddenServiceOverPublicTorNetwork.java 2007-06-27 20:52:42 UTC (rev 10686)
+++ puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/examples/AdvertisingAndAccessingHiddenServiceOverPublicTorNetwork.java 2007-06-27 22:09:47 UTC (rev 10687)
@@ -22,8 +22,7 @@
* Sets up and runs the test.
*
* @param args
- * Command-line arguments are ignored.
- *
+ * Command-line arguments (ignored).
* @throws TorProcessException
* Thrown if there is a problem with the JVM-external Tor
* processes that we cannot handle.
@@ -78,7 +77,7 @@
ServerApplication server = network.createServer("server", 7005);
// determine onion address for hidden service
- String onionAddress = proxy1.getOnionAddress("hidServ");
+ String onionAddress = proxy1.getOnionAddress("hidServ", 1);
// create client application
ClientApplication client = network.createClient("client", onionAddress,
Modified: puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/examples/AdvertisingHiddenServiceToPublicTorNetwork.java
===================================================================
--- puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/examples/AdvertisingHiddenServiceToPublicTorNetwork.java 2007-06-27 20:52:42 UTC (rev 10686)
+++ puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/examples/AdvertisingHiddenServiceToPublicTorNetwork.java 2007-06-27 22:09:47 UTC (rev 10687)
@@ -20,8 +20,7 @@
* Sets up and runs the test.
*
* @param args
- * Command-line arguments are ignored.
- *
+ * Command-line arguments (ignored).
* @throws TorProcessException
* Thrown if there is a problem with the JVM-external Tor
* processes that we cannot handle.
@@ -87,12 +86,12 @@
return;
}
- // let it run for 5 minutes and observe when RSDs are published...
+ // let it run for 2 minutes and observe when RSDs are published...
System.out
- .println("Waiting for 5 minutes and observing RSD publications...");
+ .println("Waiting for 2 minutes and observing RSD publications...");
try {
- Thread.sleep(5L * 60L * 1000L);
+ Thread.sleep(2L * 60L * 1000L);
} catch (InterruptedException e) {
// do nothing
}
Modified: puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/impl/ClientApplicationImpl.java
===================================================================
--- puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/impl/ClientApplicationImpl.java 2007-06-27 20:52:42 UTC (rev 10686)
+++ puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/impl/ClientApplicationImpl.java 2007-06-27 22:09:47 UTC (rev 10687)
@@ -1,8 +1,3 @@
-/*
- * NOTICE: This file is still work in progress. As you can see the Java
- * documentation is written partly in German and in English and logging and
- * documentation still need some work. Sorry for any inconvenience!
- */
package de.uniba.wiai.lspi.puppetor.impl;
import java.io.BufferedReader;
@@ -21,182 +16,51 @@
import de.uniba.wiai.lspi.puppetor.Event;
/**
- * Implementation of ClientApplication.
+ * Implementation of <code>ClientApplication</code>.
*
* @author kloesing
*/
public class ClientApplicationImpl implements ClientApplication {
/**
- * Thread that performs the requests in the background
+ * Internal thread class that is used to perform requests.
*/
- private RequestThread clientThread;
+ private class RequestThread extends Thread {
- /**
- * Logger for this client
- */
- private Logger logger;
+ /**
+ * Flag to remember whether requests are performed at the moment (<code>true</code>),
+ * or have been stopped (<code>false</code>).
+ */
+ private boolean connected;
- /**
- * Target address for requests; can be either a server address or an onion
- * address.
- */
- private String targetAddress;
+ /**
+ * Number of retries to be performed.
+ */
+ private int retries;
- /**
- * Target port for requests; can be either a server port or a virtual port
- * of a hidden service.
- */
- private int targetPort;
+ /**
+ * Flag that determines whether requests shall be stopped after the
+ * first successful reply (<code>true</code>), or not (<code>false</code>).
+ */
+ private boolean stopOnSuccess;
- /**
- * SOCKS port of the local Tor node.
- */
- private int socksPort;
-
- /**
- *
- */
- private EventManagerImpl eventManager;
-
- /**
- *
- */
- private String clientApplicationName;
-
- /**
- * (logging finished)
- *
- * erzeugt neue client app innerhalb der jvm, started aber noch keine
- * requests.
- *
- * @param network
- *
- * @param clientApplicationName
- * für logging
- * @param targetAddress
- * Target address for requests; can be either a server address or
- * an onion address.
- * @param targetPort
- * Target port for requests; can be either a server port or a
- * virtual port of a hidden service.
- * @param socksPort
- * SOCKS port of the local Tor node.
- */
- ClientApplicationImpl(NetworkImpl network, String clientApplicationName,
- String targetAddress, int targetPort, int socksPort) {
-
- // TODO make sure that name is loggable!!
-
- // create logger
- this.logger = Logger.getLogger("application." + clientApplicationName);
-
- // log entering
- this.logger.entering(this.getClass().getName(),
- "ClientApplicationImpl", new Object[] { clientApplicationName,
- targetAddress, targetPort, socksPort });
-
- // check parameters
- if (clientApplicationName == null
- || clientApplicationName.length() == 0 || targetAddress == null
- || targetAddress.length() == 0 || targetPort < 0
- || targetPort > 65535 || socksPort < 0 || socksPort > 65535) {
-
- IllegalArgumentException e = new IllegalArgumentException("bla");
- this.logger.throwing(this.getClass().getName(),
- "ClientApplicationImpl", e);
- throw e;
- }
-
- // remember parameters
- this.clientApplicationName = clientApplicationName;
- this.targetAddress = targetAddress;
- this.targetPort = targetPort;
- this.socksPort = socksPort;
-
- // obtain reference on event manager
- this.eventManager = network.getEventManagerImpl();
-
- // log exiting
- this.logger.exiting(this.getClass().getName(), "ClientApplicationImpl");
- }
-
- /**
- * bricht alle laufenden requests ab
- *
- */
- public void stopRequest() {
-
- // log entering
- this.logger.entering(this.getClass().getName(), "stopRequest");
-
- // check if a request is running
- if (this.clientThread == null) {
- throw new IllegalStateException("No request has been started!");
- }
-
- // log this event
- this.logger.log(Level.FINE, "Shutting down client");
-
- // interrupt thread
- this.clientThread.stopRequest();
-
- // log exiting
- this.logger.exiting(this.getClass().getName(), "stopRequest");
- }
-
- /**
- * (logging done)
- *
- * startet einen oder mehrere aufeinander folgende aufrufe an die im
- * konstruktor übergebene adresse und port.
- */
- public void performRequest(int retries, long timeoutForEachRetry,
- boolean stopOnSuccess) {
-
- // log entering
- this.logger.entering(this.getClass().getName(), "performRequest",
- new Object[] { retries, timeoutForEachRetry, stopOnSuccess });
-
- // check parameters
- if (retries <= 0 || timeoutForEachRetry < 0) {
- throw new IllegalArgumentException();
- }
-
- // check if we already have started a request (TODO change this to allow
- // multiple requests in parallel? would be possible)
- if (this.clientThread != null) {
- throw new IllegalStateException(
- "Another request has already been started!");
- }
-
- // create a thread that performs requests in the background
- this.clientThread = new RequestThread(retries, timeoutForEachRetry,
- stopOnSuccess);
- this.clientThread.setName("Request Thread");
- this.clientThread.setDaemon(true);
- this.clientThread.start();
-
- // log exiting
- this.logger.exiting(this.getClass().getName(), "performRequest");
- }
-
- /**
- * (logging done)
- *
- * @author kloesing
- *
- */
- private class RequestThread extends Thread {
-
- private int retries;
-
+ /**
+ * Timeout in milliseconds for each retry.
+ */
private long timeoutForEachRetry;
- private boolean connected;
-
- private boolean stopOnSuccess;
-
+ /**
+ * Creates a new thread, but does not start performing requests, yet.
+ *
+ * @param retries
+ * Number of retries to be performed.
+ * @param timeoutForEachRetry
+ * Timeout in milliseconds for each retry.
+ * @param stopOnSuccess
+ * Flag that determines whether requests shall be stopped
+ * after the first successful reply (<code>true</code>),
+ * or not (<code>false</code>).
+ */
RequestThread(int retries, long timeoutForEachRetry,
boolean stopOnSuccess) {
@@ -206,6 +70,13 @@
new Object[] { retries, timeoutForEachRetry,
stopOnSuccess });
+ // check parameters
+ if (retries < 0 || timeoutForEachRetry < 0) {
+ IllegalArgumentException e = new IllegalArgumentException();
+ logger.throwing(this.getClass().getName(), "RequestThread", e);
+ throw e;
+ }
+
// remember parameters
this.retries = retries;
this.timeoutForEachRetry = timeoutForEachRetry;
@@ -219,25 +90,8 @@
}
/**
- * stoppt diesen request egal wo er gerade steht
- *
+ * Perform one or more requests.
*/
- public void stopRequest() {
-
- // log entering
- logger.entering(this.getClass().getName(), "stopRequest");
-
- // change connected state to false and interrupt thread
- this.connected = false;
- this.interrupt();
-
- // log exiting
- logger.exiting(this.getClass().getName(), "stopRequest");
- }
-
- /**
- * (logging done)
- */
@Override
public void run() {
@@ -251,12 +105,12 @@
socksPort);
Proxy p = new Proxy(Type.SOCKS, isa);
- // create target address for socket -- don't resolve the target address
- // to an IP address!
- InetSocketAddress hs = InetSocketAddress.createUnresolved(targetAddress,
- targetPort);
+ // create target address for socket -- don't resolve the target
+ // name to an IP address!
+ InetSocketAddress hs = InetSocketAddress.createUnresolved(
+ targetName, targetPort);
- // start loop
+ // start retry loop
for (int i = 0; connected && i < retries; i++) {
// log this try
@@ -331,7 +185,7 @@
// wait for the rest of the timeout
long timeOfTimeoutLeft = timeBeforeConnectionAttempt
- + timeoutForEachRetry
+ + this.timeoutForEachRetry
- System.currentTimeMillis();
if (timeOfTimeoutLeft > 0) {
try {
@@ -379,13 +233,189 @@
logger.exiting(this.getClass().getName(), "run");
}
}
+
+ /**
+ * Immediately stops this and all possibly subsequent requests.
+ */
+ public void stopRequest() {
+
+ // log entering
+ logger.entering(this.getClass().getName(), "stopRequest");
+
+ // change connected state to false and interrupt thread
+ this.connected = false;
+ this.interrupt();
+
+ // log exiting
+ logger.exiting(this.getClass().getName(), "stopRequest");
+ }
}
+ /**
+ * Name of this client application that is used as logger name of this node.
+ */
+ private String clientApplicationName;
+
+ /**
+ * Thread that performs the requests in the background.
+ */
+ private RequestThread clientThread;
+
+ /**
+ * Event manager to which all events concerning this client application are
+ * notified.
+ */
+ private EventManagerImpl eventManager;
+
+ /**
+ * Logger for this client.
+ */
+ private Logger logger;
+
+ /**
+ * SOCKS port of the local Tor node to which requests are sent.
+ */
+ private int socksPort;
+
+ /**
+ * Target name for the requests sent by this client; can be either a server
+ * name/address or an onion address.
+ */
+ private String targetName;
+
+ /**
+ * Target port for the requests sent by this client; can be either a server
+ * port or a virtual port of a hidden service.
+ */
+ private int targetPort;
+
+ /**
+ * Creates a new HTTP client within this JVM, but does not start sending
+ * requests.
+ *
+ * @param network
+ * Network to which this HTTP client belongs; at the moment this
+ * is only used to determine the event manager instance.
+ * @param clientApplicationName
+ * Name of this client that is used as part of the logger name.
+ * @param targetName
+ * Target name for requests; can be either a server name/address
+ * or an onion address.
+ * @param targetPort
+ * Target port for requests; can be either a server port or a
+ * virtual port of a hidden service.
+ * @param socksPort
+ * SOCKS port of the local Tor node.
+ * @throws IllegalArgumentException
+ * If at least one of the parameters is <code>null</code> or has an invalid
+ * value.
+ */
+ ClientApplicationImpl(NetworkImpl network, String clientApplicationName,
+ String targetName, int targetPort, int socksPort) {
+
+ // check if clientApplicationName can be used as logger name
+ if (clientApplicationName == null
+ || clientApplicationName.length() == 0) {
+ throw new IllegalArgumentException(
+ "Invalid clientApplicationName: " + clientApplicationName);
+ }
+
+ // create logger
+ this.logger = Logger.getLogger("application." + clientApplicationName);
+
+ // log entering
+ this.logger.entering(this.getClass().getName(),
+ "ClientApplicationImpl", new Object[] { network,
+ clientApplicationName, targetName, targetPort,
+ socksPort });
+
+ // check parameters
+ if (network == null || targetName == null || targetName.length() == 0
+ || targetPort < 0 || targetPort > 65535 || socksPort < 0
+ || socksPort > 65535) {
+ IllegalArgumentException e = new IllegalArgumentException();
+ this.logger.throwing(this.getClass().getName(),
+ "ClientApplicationImpl", e);
+ throw e;
+ }
+
+ // remember parameters
+ this.clientApplicationName = clientApplicationName;
+ this.targetName = targetName;
+ this.targetPort = targetPort;
+ this.socksPort = socksPort;
+
+ // obtain and store reference on event manager
+ this.eventManager = network.getEventManagerImpl();
+
+ // log exiting
+ this.logger.exiting(this.getClass().getName(), "ClientApplicationImpl");
+ }
+
+ public synchronized void performRequest(int retries,
+ long timeoutForEachRetry, boolean stopOnSuccess) {
+
+ // log entering
+ this.logger.entering(this.getClass().getName(), "performRequest",
+ new Object[] { retries, timeoutForEachRetry, stopOnSuccess });
+
+ // check parameters
+ if (retries <= 0 || timeoutForEachRetry < 0) {
+ IllegalArgumentException e = new IllegalArgumentException();
+ this.logger
+ .throwing(this.getClass().getName(), "performRequest", e);
+ throw e;
+ }
+
+ // check if we already have started a request (TODO change this to allow
+ // multiple requests in parallel? would be possible)
+ if (this.clientThread != null) {
+ IllegalStateException e = new IllegalStateException(
+ "Another request has already been started!");
+ this.logger
+ .throwing(this.getClass().getName(), "performRequest", e);
+ throw e;
+ }
+
+ // create a thread that performs requests in the background
+ this.clientThread = new RequestThread(retries, timeoutForEachRetry,
+ stopOnSuccess);
+ this.clientThread.setName("Request Thread");
+ this.clientThread.setDaemon(true);
+ this.clientThread.start();
+
+ // log exiting
+ this.logger.exiting(this.getClass().getName(), "performRequest");
+ }
+
+ public synchronized void stopRequest() {
+
+ // log entering
+ this.logger.entering(this.getClass().getName(), "stopRequest");
+
+ // check if a request is running
+ if (this.clientThread == null) {
+ IllegalStateException e = new IllegalStateException("Cannot stop "
+ + "request, because no request has been started!");
+ this.logger.throwing(this.getClass().getName(), "stopRequest", e);
+ throw e;
+ }
+
+ // log this event
+ this.logger.log(Level.FINE, "Shutting down client");
+
+ // interrupt thread
+ this.clientThread.stopRequest();
+
+ // log exiting
+ this.logger.exiting(this.getClass().getName(), "stopRequest");
+ }
+
@Override
public String toString() {
return this.getClass().getSimpleName() + ": clientApplicationName=\""
+ this.clientApplicationName + "\", targetAddress=\""
- + this.targetAddress + "\", targetPort=" + this.targetPort
+ + this.targetName + "\", targetPort=" + this.targetPort
+ ", socksPort=" + this.socksPort;
}
}
Modified: puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/impl/DirectoryNodeImpl.java
===================================================================
--- puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/impl/DirectoryNodeImpl.java 2007-06-27 20:52:42 UTC (rev 10686)
+++ puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/impl/DirectoryNodeImpl.java 2007-06-27 22:09:47 UTC (rev 10687)
@@ -1,8 +1,3 @@
-/*
- * NOTICE: This file is still work in progress. As you can see the Java
- * documentation is written partly in German and in English and logging and
- * documentation still need some work. Sorry for any inconvenience!
- */
package de.uniba.wiai.lspi.puppetor.impl;
import java.io.BufferedWriter;
@@ -16,19 +11,59 @@
import de.uniba.wiai.lspi.puppetor.DirectoryNode;
import de.uniba.wiai.lspi.puppetor.TorProcessException;
+/**
+ * Implementation of <code>DirectoryNode</code>.
+ *
+ * @author karsten
+ */
public class DirectoryNodeImpl extends RouterNodeImpl implements DirectoryNode {
+
/**
- * Initializes this Tor node, but does not start it, yet.
+ * Creates a <code>DirectoryNodeImpl</code> and adds it to the given
+ * <code>network</code>, but does not yet write its configuration to disk
+ * or start the corresponding Tor process.
+ *
+ * @param network
+ * Network configuration to which this node belongs.
+ * @param nodeName
+ * The name of the new node which may only consist of between 1
+ * and 19 alpha-numeric characters.
+ * @param controlPort
+ * Port on which the Tor node will be listening for us as its
+ * controller. May not be negative or greater than 65535.
+ * @param socksPort
+ * Port on which the Tor node will be listening for SOCKS
+ * connection requests. May not be negative or greater than
+ * 65535.
+ * @param orPort
+ * Port on which the Tor node will be listening for onion
+ * requests by other Tor nodes. May not be negative or greater
+ * than 65535.
+ * @param dirPort
+ * Port on which the Tor node will be listening for directory
+ * requests from other Tor nodes. May not be negative or greater
+ * than 65535.
+ * @throws IllegalArgumentException
+ * If at least one of the parameters is <code>null</code> or
+ * has an invalid value.
*/
- public DirectoryNodeImpl(NetworkImpl network, String nodeName,
- int controlPort, int socksPort, int orPort, int dirPort) {
+ DirectoryNodeImpl(NetworkImpl network, String nodeName, int controlPort,
+ int socksPort, int orPort, int dirPort) {
+
+ // create superclass instance; parameter checking is done in super
+ // constructor
super(network, nodeName, controlPort, socksPort, orPort, dirPort);
+ // log entering
+ this.logger.entering(this.getClass().getName(), "DirectoryNodeImpl",
+ new Object[] { network, nodeName, controlPort, socksPort,
+ orPort, dirPort });
+
// configure this node as an authoritative directory
this.configuration.add("AuthoritativeDirectory 1");
// TODO make this a little bit more configurable---same as to
- // location of tor.exe?
+ // location of tor executable?
this.configuration
.add("RecommendedVersions 0.1.2.12-rc,0.1.2.7-alpha-dev,0.2.0.0-alpha-dev");
@@ -36,19 +71,61 @@
this.configuration.add("NamingAuthoritativeDirectory 1");
- this.configuration.add("V2AuthoritativeDirectory 1");
+ // TODO this requires version 0.2.x
+ //this.configuration.add("V2AuthoritativeDirectory 1");
this.configuration.add("V1AuthoritativeDirectory 1");
// TODO this only works since Tor 0.1.2.x!!!
this.configuration.add("HSAuthoritativeDir 1");
+ // TODO only in v0.2.x
+ //this.configuration.add("HSAuthorityRecordStats 1");
+
+ // log exiting
+ this.logger.exiting(this.getClass().getName(), "DirectoryNodeImpl");
}
- public void writeApprovedRouters(Set<String> approvedRouters)
+ public synchronized String determineDirServerString()
throws TorProcessException {
-
- // check param!
-
+
+ // log entering
+ this.logger.entering(this.getClass().getName(),
+ "determineDirServerString");
+
+ // determine fingerprint
+ String fingerprint = determineFingerprint();
+
+ // cut off router nickname
+ fingerprint = fingerprint.substring(fingerprint.indexOf(" ") + 1);
+
+ // put everything together
+ String dirServerString = "DirServer " + this.nodeName + " hs orport="
+ + this.orPort + " " + localIpAddress + ":" + this.dirPort + " "
+ + fingerprint;
+
+ // log exiting and return dir server string
+ this.logger.exiting(this.getClass().getName(),
+ "determineDirServerString", dirServerString);
+ return dirServerString;
+ }
+
+ public synchronized void writeApprovedRouters(Set<String> approvedRouters)
+ throws TorProcessException {
+
+ // log entering
+ this.logger.entering(this.getClass().getName(), "writeApprovedRouters",
+ approvedRouters);
+
+ // check parameter
+ if (approvedRouters == null) {
+ IllegalArgumentException e = new IllegalArgumentException();
+ this.logger.throwing(this.getClass().getName(),
+ "writeApprovedRouters", e);
+ throw e;
+ }
+
+ // sort the given approved router strings alphabetically and store them
+ // to file
try {
File approvedRoutersFile = new File(this.workingDir
.getAbsolutePath()
@@ -62,22 +139,13 @@
}
bw.close();
} catch (IOException e) {
- throw new TorProcessException(e);
+ TorProcessException ex = new TorProcessException(e);
+ this.logger.throwing(this.getClass().getName(),
+ "writeApprovedRouters", ex);
+ throw ex;
}
- }
- public synchronized String determineDirServerString()
- throws TorProcessException {
-
- // determine fingerprint
- String fingerprint = determineFingerprint();
-
- // cut off router nickname
- fingerprint = fingerprint.substring(fingerprint.indexOf(" ") + 1);
-
- // put together everything
- String dirServerString = "DirServer " + this.nodeName
- + " hs " + localIpAddress + ":" + this.dirPort + " " + fingerprint;
- return dirServerString;
+ // log exiting
+ this.logger.exiting(this.getClass().getName(), "writeApprovedRouters");
}
}
Modified: puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/impl/EventManagerImpl.java
===================================================================
--- puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/impl/EventManagerImpl.java 2007-06-27 20:52:42 UTC (rev 10686)
+++ puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/impl/EventManagerImpl.java 2007-06-27 22:09:47 UTC (rev 10687)
@@ -1,8 +1,3 @@
-/*
- * NOTICE: This file is still work in progress. As you can see the Java
- * documentation is written partly in German and in English and logging and
- * documentation still need some work. Sorry for any inconvenience!
- */
package de.uniba.wiai.lspi.puppetor.impl;
import java.util.ArrayList;
@@ -19,23 +14,61 @@
import de.uniba.wiai.lspi.puppetor.EventManager;
import de.uniba.wiai.lspi.puppetor.EventSource;
+/**
+ * Implementation of <code>EventManager</code>.
+ */
public class EventManagerImpl implements EventManager {
+ /**
+ * Registered event handlers.
+ */
+ private Map<EventSource, Set<EventListener>> eventHandlers;
+
+ /**
+ * Logger for this <code>EventManagerImpl</code> instance which is called
+ * "event." plus the name of the network.
+ */
private Logger logger;
+ /**
+ * Events observed so far.
+ */
+ private Map<EventSource, List<Event>> observedEvents;
+
+ /**
+ * Creates a new <code>EventManagerImpl</code> for the network with name
+ * <code>networkName</code> and initializes it.
+ *
+ * @param networkName
+ * Name of this event manager that is used as part of the logger
+ * name.
+ * @throws IllegalArgumentException
+ * Thrown if the given <code>networkName</code> is either
+ * <code>null</code> or a zero-length string.
+ */
EventManagerImpl(String networkName) {
-
-// TODO make sure that name is loggable!!
-
+
+ // check if networkName can be used as logger name
+ if (networkName == null || networkName.length() == 0) {
+ throw new IllegalArgumentException("Invalid networkName: "
+ + networkName);
+ }
+
+ // create logger
this.logger = Logger.getLogger("event." + networkName);
+
+ // log entering
+ this.logger.entering(this.getClass().getName(), "EventManagerImpl",
+ networkName);
+
+ // create data structures
this.observedEvents = new HashMap<EventSource, List<Event>>();
this.eventHandlers = new HashMap<EventSource, Set<EventListener>>();
+
+ // log exiting
+ this.logger.exiting(this.getClass().getName(), "EventManagerImpl");
}
- private Map<EventSource, List<Event>> observedEvents;
-
- private Map<EventSource, Set<EventListener>> eventHandlers;
-
public synchronized List<Event> addEventListener(EventSource source,
EventListener listener) {
@@ -45,7 +78,10 @@
// check parameters
if (source == null || listener == null) {
- throw new IllegalArgumentException();
+ IllegalArgumentException e = new IllegalArgumentException();
+ this.logger.throwing(this.getClass().getName(), "addEventListener",
+ e);
+ throw e;
}
// if necessary, create new event listener set for source
@@ -70,12 +106,15 @@
public synchronized List<Event> getEventHistory(EventSource source) {
// log entering
- this.logger.entering(this.getClass().getName(), "getNodeEventHistory",
+ this.logger.entering(this.getClass().getName(), "getEventHistory",
source);
// check parameter
if (source == null) {
- throw new IllegalArgumentException();
+ IllegalArgumentException e = new IllegalArgumentException();
+ this.logger.throwing(this.getClass().getName(), "getEventHistory",
+ e);
+ throw e;
}
// prepare result
@@ -88,10 +127,9 @@
}
// log exiting and return result
- this.logger.exiting(this.getClass().getName(), "getNodeEventHistory",
+ this.logger.exiting(this.getClass().getName(), "getEventHistory",
result);
return result;
-
}
public synchronized boolean hasEventOccured(EventSource source, Event event) {
@@ -102,7 +140,10 @@
// check parameters
if (source == null || event == null) {
- throw new IllegalArgumentException();
+ IllegalArgumentException e = new IllegalArgumentException();
+ this.logger.throwing(this.getClass().getName(), "hasEventOccured",
+ e);
+ throw e;
}
// determine result
@@ -115,6 +156,57 @@
return result;
}
+ /**
+ * Stores the given <code>event</code> from <code>source</code> to the
+ * event history and propagates its occurrence to all registered event
+ * handlers.
+ *
+ * @param source
+ * The source of the given event.
+ * @param event
+ * The event type.
+ */
+ synchronized void observeEvent(EventSource source, Event event) {
+
+ // log entering
+ this.logger.entering(this.getClass().getName(), "observeEvent",
+ new Object[] { source, event });
+
+ this.logger.log(Level.FINE, "Observed event " + event + " from source "
+ + source + "!");
+
+ // remember observed event
+ if (!this.observedEvents.containsKey(source)) {
+ this.observedEvents.put(source, new ArrayList<Event>());
+ }
+ this.observedEvents.get(source).add(event);
+
+ // notify waiting threads
+ notifyAll();
+
+ // inform event listeners
+ if (this.eventHandlers.containsKey(source)) {
+
+ // make a copy of the event handler set, because some event handlers
+ // might want to remove themselves from this set while handling the
+ // event
+
+ Set<EventListener> copyOfEventHandlers = new HashSet<EventListener>(
+ this.eventHandlers.get(source));
+
+ for (EventListener eventHandler : copyOfEventHandlers) {
+
+ this.logger.log(Level.FINE, "Informing event listener "
+ + eventHandler + " about recently observed event "
+ + event + " from source " + source + "!");
+ eventHandler.handleEvent(event);
+ }
+ }
+
+ // log exiting
+ this.logger.exiting(this.getClass().getName(), "observeEvent");
+ }
+
public synchronized void removeEventListener(EventListener eventListener) {
// log entering
@@ -123,7 +215,10 @@
// check parameters
if (eventListener == null) {
- throw new IllegalArgumentException();
+ IllegalArgumentException e = new IllegalArgumentException();
+ this.logger.throwing(this.getClass().getName(),
+ "removeEventListener", e);
+ throw e;
}
// don't know to which source this listener has been added (may to more
@@ -146,7 +241,10 @@
// check parameters
if (source == null || event == null) {
- throw new IllegalArgumentException();
+ IllegalArgumentException e = new IllegalArgumentException();
+ this.logger.throwing(this.getClass().getName(),
+ "waitForAnyOccurence", e);
+ throw e;
}
// invoke overloaded method with maximumTimeToWaitInMillis of -1L which
@@ -167,15 +265,16 @@
// check parameters
if (source == null || event == null) {
- throw new IllegalArgumentException();
+ IllegalArgumentException e = new IllegalArgumentException();
+ this.logger.throwing(this.getClass().getName(),
+ "waitForAnyOccurence", e);
+ throw e;
}
// check if we have already observed the event
if (this.hasEventOccured(source, event)) {
-
this.logger.log(Level.FINE, "Waiting for any occurence of event "
+ event + " returned immediately!");
-
this.logger.exiting(this.getClass().getName(),
"waitForAnyOccurence", true);
return true;
@@ -189,7 +288,6 @@
this.logger.exiting(this.getClass().getName(), "waitForAnyOccurence",
result);
return result;
-
}
public synchronized void waitForNextOccurence(EventSource source,
@@ -201,7 +299,10 @@
// check parameters
if (source == null || event == null) {
- throw new IllegalArgumentException();
+ IllegalArgumentException e = new IllegalArgumentException();
+ this.logger.throwing(this.getClass().getName(),
+ "waitForNextOccurence", e);
+ throw e;
}
// invoke overloaded method with maximumTimeToWaitInMillis of -1L which
@@ -210,7 +311,6 @@
// log exiting
this.logger.exiting(this.getClass().getName(), "waitForNextOccurence");
-
}
public synchronized boolean waitForNextOccurence(EventSource source,
@@ -222,7 +322,10 @@
// check parameters
if (source == null || event == null) {
- throw new IllegalArgumentException();
+ IllegalArgumentException e = new IllegalArgumentException();
+ this.logger.throwing(this.getClass().getName(),
+ "waitForNextOccurence", e);
+ throw e;
}
// distinguish between negative waiting time (wait forever) and zero or
@@ -299,50 +402,4 @@
}
}
- /**
- * wird lokal aufgerufen; speichert event in history und meldet es an alle
- * registrierten event handler weiter
- *
- */
- synchronized void observeEvent(EventSource source, Event event) {
-
- // log entering
- this.logger.entering(this.getClass().getName(), "observeEvent",
- new Object[] { source, event });
-
- this.logger.log(Level.FINE, "Observed event " + event + " from source "
- + source + "!");
-
- // remember observed event
- if (!this.observedEvents.containsKey(source)) {
- this.observedEvents.put(source, new ArrayList<Event>());
- }
- this.observedEvents.get(source).add(event);
-
- // notify waiting threads
- notifyAll();
-
- // inform event listeners
- if (this.eventHandlers.containsKey(source)) {
-
- // make a copy of the event handler set, because some event handlers
- // might want to remove itself from this set while handling the
- // event
-
- Set<EventListener> copyOfEventHandlers = new HashSet<EventListener>(
- this.eventHandlers.get(source));
-
- for (EventListener eventHandler : copyOfEventHandlers) {
-
- this.logger.log(Level.FINE, "Informing event listener "
- + eventHandler + " about recently observed event "
- + event + " from source " + source + "!");
- eventHandler.handleEvent(event);
- }
- }
-
- // log exiting
- this.logger.exiting(this.getClass().getName(), "observeEvent");
- }
-
-}
+}
Modified: puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/impl/NetworkImpl.java
===================================================================
--- puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/impl/NetworkImpl.java 2007-06-27 20:52:42 UTC (rev 10686)
+++ puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/impl/NetworkImpl.java 2007-06-27 22:09:47 UTC (rev 10687)
@@ -1,8 +1,3 @@
-/*
- * NOTICE: This file is still work in progress. As you can see the Java
- * documentation is written partly in German and in English and logging and
- * documentation still need some work. Sorry for any inconvenience!
- */
package de.uniba.wiai.lspi.puppetor.impl;
import java.io.File;
@@ -24,92 +19,526 @@
import de.uniba.wiai.lspi.puppetor.ServerApplication;
import de.uniba.wiai.lspi.puppetor.TorProcessException;
+/**
+ * Implementation of <code>Network</code>.
+ *
+ * @author kloesing
+ */
public class NetworkImpl implements Network {
- private EventManagerImpl eventManager;
+ /**
+ * Internal thread class that is used to determine fingerprints in parallel.
+ */
+ private class FingerprintThread extends Thread {
- @Override
- public String toString() {
- return this.getClass().getSimpleName() + ": networkName=\""
- + this.networkName + "\", networkState="
- + this.networkState.toString() + ", nodes.size()="
- + this.nodes.size();
+ /**
+ * The exception, if one is caught while trying to determine the
+ * fingerprint of the node.
+ */
+ private TorProcessException caughtException = null;
+
+ /**
+ * The node of which the fingerprint shall be determined.
+ */
+ private RouterNode node = null;
+
+ /**
+ * Creates a new thread to determine the fingerprint of
+ * <code>node</code>.
+ *
+ * @param node
+ * The node of which the fingerprint shall be determined.
+ */
+ FingerprintThread(RouterNode node) {
+
+ // log entering
+ logger.entering(this.getClass().getName(), "FingerprintThread");
+
+ // remember node reference
+ this.node = node;
+
+ // log exiting
+ logger.exiting(this.getClass().getName(), "FingerprintThread");
+ }
+
+ @Override
+ public void run() {
+
+ // log entering
+ logger.entering(this.getClass().getName(), "run");
+
+ // determine fingerprint
+ try {
+ node.determineFingerprint();
+ } catch (TorProcessException e) {
+ logger.log(Level.SEVERE,
+ "Caught an exception while determining fingerprint for "
+ + "node " + node.toString() + "!");
+ this.caughtException = e;
+ }
+
+ // log exiting
+ logger.exiting(this.getClass().getName(), "run");
+ }
}
+ /**
+ * Internal thread class that is used to start Tor processes in parallel.
+ */
+ private class NodeStarter extends Thread {
+
+ /**
+ * The exception, if one is caught while trying to start the node.
+ */
+ TorProcessException caughtException;
+
+ /**
+ * The maximum time to wait for the Tor process to start in
+ * milliseconds.
+ */
+ private long maximumTimeToWaitInMillis;
+
+ /**
+ * The node for which the Tor process shall be started.
+ */
+ private ProxyNode node;
+
+ /**
+ * Flag that denotes whether starting the Tor process was successful.
+ */
+ boolean success = false;
+
+ /**
+ * Creates a new <code>NodeStarter</code> for node <code>node</code>
+ * that will wait for <code>maximumTimeToWaitInMillis</code>
+ * milliseconds to start a Tor process, but that is not started, yet.
+ *
+ * @param node
+ * The node for which the Tor process shall be started.
+ * @param maximumTimeToWaitInMillis
+ * The maximum time to wait for the Tor process to start in
+ * milliseconds.
+ */
+ NodeStarter(ProxyNode node, long maximumTimeToWaitInMillis) {
+
+ // log entering
+ logger.entering(this.getClass().getName(), "NodeStarter",
+ new Object[] { node, maximumTimeToWaitInMillis });
+
+ // store parameters
+ this.node = node;
+ this.maximumTimeToWaitInMillis = maximumTimeToWaitInMillis;
+
+ // log exiting
+ logger.exiting(this.getClass().getName(), "NodeStarter");
+ }
+
+ @Override
+ public void run() {
+
+ // log entering
+ logger.entering(this.getClass().getName(), "run");
+
+ try {
+ // try to start node
+ this.success = this.node
+ .startNode(this.maximumTimeToWaitInMillis);
+ } catch (TorProcessException e) {
+ // if an exception is caught, store it, but don't throw it (the
+ // thread wouldn't care)
+ this.caughtException = e;
+ }
+
+ // log exiting
+ logger.exiting(this.getClass().getName(), "run");
+ }
+ }
+
+ /**
+ * The fingerprints of all approved routers in the network configuration.
+ */
+ private HashSet<String> approvedRoutersFingerprints;
+
+ /**
+ * The fingerprints of all authoritative directories in the network
+ * configuration.
+ */
+ private Set<String> authorizedDirectoriesFingerprints;
+
+ /**
+ * Event manager to which all events concerning this network are notified.
+ */
+ private EventManagerImpl eventManager;
+
+ /**
+ * Logger for this <code>NetworkImpl</code> instance which is called
+ * "network." plus the name of this network.
+ */
private Logger logger;
/**
- * Contains the name of this node configuration which is the String
- * conversion of System.currentTimeMillis().
+ * Contains the name of this network configuration which is the String
+ * conversion of System.currentTimeMillis() of the network creation time.
*/
- protected String networkName;
+ private String networkName;
/**
+ * The state of this network.
+ */
+ private NetworkState networkState = NetworkState.CONFIGURING_NODES;
+
+ /**
+ * All nodes contained in this network. It is important that we store and
+ * work only with interface types to assure that all operations could also
+ * be performed by the application itself.
+ */
+ private Set<ProxyNode> nodes = new HashSet<ProxyNode>();
+
+ /**
+ * Directory that contains status information of all nodes contained in this
+ * network.
+ */
+ private File workingDir;
+
+ /**
* Creates an initially unpopulated Tor network and creates a new working
* directory for it at test-env/randomTestID/.
*
* @param networkName
- * Name of this network configuration.
- * @param logToConsole
- * Whether logging statements shall be written to the console or
- * to a file.
+ * Name of this network configuration. May neither be
+ * <code>null</code> or a zero-length string.
+ * @throws IllegalArgumentException
+ * Thrown if the given <code>networkName</code> is either
+ * <code>null</code> or a zero-length string.
*/
public NetworkImpl(String networkName) {
-
-// TODO make sure that name is loggable!!
-
+
+ // check if networkName can be used as logger name
+ if (networkName == null || networkName.length() == 0) {
+ throw new IllegalArgumentException("Invalid networkName: "
+ + networkName);
+ }
+
+ // create logger
this.logger = Logger.getLogger("network." + networkName);
+
+ // log entering
+ this.logger.entering(this.getClass().getName(), "NetworkImpl",
+ networkName);
+
+ // TODO is this necessary?!
this.logger.setLevel(Level.ALL);
+
+ // remember parameter
this.networkName = networkName;
+
+ // create working directory
this.workingDir = new File("test-env/" + System.currentTimeMillis());
this.workingDir.mkdirs();
+ this.logger.log(Level.FINE, "Created working directory \""
+ + this.workingDir.getAbsolutePath() + "\"");
// TODO if we want to log to file, set this... somehow...
// this.logFile = new File(this.workingDir.getAbsolutePath()
// + "\\events.log");
+ // create event manager
this.eventManager = new EventManagerImpl(this.networkName);
- }
- public NetworkState getNetworkState() {
- // TODO Auto-generated method stub
- throw new UnsupportedOperationException(
- "Auto-generated method stub in NetworkImpl.getNetworkState");
+ // log exiting
+ this.logger.exiting(this.getClass().getName(), "NetworkImpl");
}
+ /**
+ * Returns whether all nodes in this network are up, or not.
+ *
+ * @return <code>true</code> if all nodes are up, <code>false</code> if
+ * at least one node is not up.
+ */
private boolean allNodesUp() {
- // check if all nodes are up
+ // log entering
+ this.logger.entering(this.getClass().getName(), "allNodesUp");
+
+ // nodes can only be up, when network is in state
+ // NetworkState.NODES_STARTED.
+ if (this.networkState != NetworkState.NODES_STARTED) {
+
+ // log exiting and return false
+ this.logger.exiting(this.getClass().getName(), "allNodesUp");
+ return false;
+ }
+
+ // fail on first node that is not up
for (ProxyNode node : this.nodes) {
if (!eventManager.hasEventOccured(node, Event.NODE_CIRCUIT_OPENED)) {
+
+ // log exiting and return false
+ this.logger.exiting(this.getClass().getName(), "allNodesUp");
return false;
}
}
+
+ // log exiting and return true
+ this.logger.exiting(this.getClass().getName(), "allNodesUp");
return true;
}
+ public void configureAsPrivateNetwork() throws TorProcessException {
+
+ // log entering
+ this.logger.entering(this.getClass().getName(),
+ "configureAsPrivateNetwork");
+
+ // start threads to determine fingerprints for all directories and
+ // routers in parallel
+ Set<FingerprintThread> fingerprintThreads = new HashSet<FingerprintThread>();
+ for (ProxyNode node : nodes) {
+ if (node instanceof RouterNode) {
+ RouterNode dirOrRouterNode = (RouterNode) node;
+ FingerprintThread fingerprintThread = new FingerprintThread(
+ dirOrRouterNode);
+ fingerprintThread.setName(node.getNodeName()
+ + " Fingerprint Resolver");
+ fingerprintThreads.add(fingerprintThread);
+ fingerprintThread.start();
+ }
+ }
+
+ // wait for all fingerprints have been determined
+ for (FingerprintThread fingerprintThread : fingerprintThreads) {
+
+ // join fingerprint determination one after the other
+ try {
+ fingerprintThread.join();
+ } catch (InterruptedException e) {
+ // ignore; TODO really?!
+ logger.log(Level.WARNING,
+ "Joining fingerprint thread was interrupted.");
+ }
+
+ // if any thread has caught an exception, throw that exception now
+ if (fingerprintThread.caughtException != null) {
+ this.logger.throwing(this.getClass().getName(),
+ "configureAsPrivateNetwork",
+ fingerprintThread.caughtException);
+ throw fingerprintThread.caughtException;
+ }
+ }
+
+ // read DirServer strings for all directories from memory; they should
+ // have been read from disk before, so that this will perform really
+ // fast
+ this.authorizedDirectoriesFingerprints = new HashSet<String>();
+ for (ProxyNode node : this.nodes) {
+ if (node instanceof DirectoryNode) {
+ DirectoryNode dirNode = (DirectoryNode) node;
+ this.authorizedDirectoriesFingerprints.add(dirNode
+ .determineDirServerString());
+ }
+
+ }
+
+ // configure nodes
+ for (ProxyNode node : this.nodes) {
+ if (node.getNodeState() == NodeState.CONFIGURING) {
+ node
+ .configureDirServers(this.authorizedDirectoriesFingerprints);
+ }
+ }
+
+ // read fingerprints for all directories and routers from memory; they
+ // should have been read from disk before, so that this will perform
+ // really fast
+ this.approvedRoutersFingerprints = new HashSet<String>();
+ for (ProxyNode node : this.nodes) {
+ if (node instanceof RouterNode) {
+ RouterNode routerOrDirNode = (RouterNode) node;
+ this.approvedRoutersFingerprints.add(routerOrDirNode
+ .determineFingerprint());
+ }
+ }
+
+ // write fingerprints for all directories and routers to
+ // approved-routers file
+ for (ProxyNode node : this.nodes) {
+ if (node instanceof DirectoryNode) {
+ DirectoryNode dirNode = (DirectoryNode) node;
+ dirNode.writeApprovedRouters(this.approvedRoutersFingerprints);
+ }
+ }
+
+ // log exiting
+ this.logger.exiting(this.getClass().getName(),
+ "configureAsPrivateNetwork");
+ }
+
+ public ClientApplication createClient(String clientApplicationName,
+ String targetAddress, int targetPort, int socksPort) {
+
+ // log entering
+ this.logger.entering(this.getClass().getName(), "createClient",
+ new Object[] { clientApplicationName, targetAddress,
+ targetPort, socksPort });
+
+ // create client; parameter checking is done in constructor
+ ClientApplicationImpl client = new ClientApplicationImpl(this,
+ clientApplicationName, targetAddress, targetPort, socksPort);
+
+ // log exiting and return client
+ this.logger.exiting(this.getClass().getName(), "createClient", client);
+ return client;
+ }
+
+ public DirectoryNode createDirectory(String nodeName, int controlPort,
+ int socksPort, int orPort, int dirPort) {
+
+ // log entering
+ this.logger.entering(this.getClass().getName(), "createDirectory",
+ new Object[] { nodeName, controlPort, socksPort, orPort,
+ dirPort });
+
+ // check state
+ if (this.networkState != NetworkState.CONFIGURING_NODES) {
+ IllegalStateException e = new IllegalStateException();
+ this.logger.throwing(this.getClass().getName(), "createDirectory",
+ e);
+ throw e;
+ }
+
+ // create directory node; parameter checking is done in constructor
+ DirectoryNode dir = new DirectoryNodeImpl(this, nodeName, controlPort,
+ socksPort, orPort, dirPort);
+
+ // add new directory node to nodes collection
+ this.nodes.add(dir);
+
+ // log exiting and return directory node
+ this.logger.exiting(this.getClass().getName(), "createDirectory", dir);
+ return dir;
+ }
+
+ public ProxyNode createProxy(String nodeName, int controlPort, int socksPort) {
+
+ // log entering
+ this.logger.entering(this.getClass().getName(), "createProxy",
+ new Object[] { nodeName, controlPort, socksPort });
+
+ // check state
+ if (this.networkState != NetworkState.CONFIGURING_NODES) {
+ IllegalStateException e = new IllegalStateException();
+ this.logger.throwing(this.getClass().getName(), "createProxy", e);
+ throw e;
+ }
+
+ // create proxy node; parameter checking is done in constructor
+ ProxyNodeImpl proxy = new ProxyNodeImpl(this, nodeName, controlPort,
+ socksPort);
+
+ // add new proxy node to nodes collection
+ this.nodes.add(proxy);
+
+ // log exiting and return proxy node
+ this.logger.exiting(this.getClass().getName(), "createProxy", proxy);
+ return proxy;
+ }
+
+ public RouterNode createRouter(String nodeName, int controlPort,
+ int socksPort, int orPort, int dirPort) {
+
+ // log entering
+ this.logger.entering(this.getClass().getName(), "createRouter",
+ new Object[] { nodeName, controlPort, socksPort, orPort,
+ dirPort });
+
+ // check state
+ if (this.networkState != NetworkState.CONFIGURING_NODES) {
+ IllegalStateException e = new IllegalStateException();
+ this.logger.throwing(this.getClass().getName(), "createRouter", e);
+ throw e;
+ }
+
+ // create router node; parameter checking is done in constructor
+ RouterNode router = new RouterNodeImpl(this, nodeName, controlPort,
+ socksPort, orPort, dirPort);
+
+ // add new router node to nodes collection
+ this.nodes.add(router);
+
+ // log exiting and return router node
+ this.logger.exiting(this.getClass().getName(), "createRouter", router);
+ return router;
+ }
+
+ public ServerApplication createServer(String serverApplicationName,
+ int serverPort) {
+
+ // log entering
+ this.logger.entering(this.getClass().getName(), "createServer",
+ new Object[] { serverApplicationName, serverPort });
+
+ // create server; parameter checking is done in constructor
+ ServerApplicationImpl server = new ServerApplicationImpl(this,
+ serverApplicationName, serverPort);
+
+ // log exiting and return server
+ this.logger.exiting(this.getClass().getName(), "createServer", server);
+ return server;
+ }
+
+ public EventManager getEventManager() {
+ return this.eventManager;
+ }
+
/**
- * check, (wait, check, hup)*
+ * Returns the implementation instance of the event manager of this network.
*
- * if all nodes get up during sleeping, we will wake up and return
- * immediately
+ * @return The implementation instance of the event manager of this network.
+ */
+ EventManagerImpl getEventManagerImpl() {
+ return this.eventManager;
+ }
+
+ public NetworkState getNetworkState() {
+ return this.networkState;
+ }
+
+ /**
+ * Returns the working directory of this network configuration which is in
+ * test-env/networkName/.
*
- * @param retries
- * @param hupInterval
- * @throws Exception
+ * @return Working directory of this network.
*/
- public boolean hupUntilUp(int retries, long hupInterval)
+ File getWorkingDir() {
+ return workingDir;
+ }
+
+ public boolean hupUntilUp(int tries, long hupInterval)
throws TorProcessException {
+ // log entering
+ this.logger.entering(this.getClass().getName(), "hupUntilUp",
+ new Object[] { tries, hupInterval });
+
+ // check state
+ if (this.networkState != NetworkState.NODES_STARTED) {
+ IllegalStateException e = new IllegalStateException();
+ this.logger.throwing(this.getClass().getName(), "hupUntilUp", e);
+ throw e;
+ }
+
+ // check if nodes are already up; if so, return immediately
if (allNodesUp()) {
+
+ // log exiting and return true
+ this.logger.exiting(this.getClass().getName(), "hupUntilUp", true);
return true;
}
- // register event handlers
+ // create and register a new event handler for each node
final Thread sleepingThread = Thread.currentThread();
for (ProxyNode node : this.nodes) {
eventManager.addEventListener(node, new EventListener() {
-
public void handleEvent(Event event) {
if (event == Event.NODE_CIRCUIT_OPENED) {
sleepingThread.interrupt();
@@ -119,22 +548,30 @@
});
}
- for (int i = 0; i < retries; i++) {
+ // walk through wait-check-hup loop until there are no tries left
+ for (int i = 0; i < tries; i++) {
// determine how long to sleep
long endOfSleeping = System.currentTimeMillis() + hupInterval;
long now;
+ // unless all nodes have reported to be up, wait for the given
+ // maximum time
while ((now = System.currentTimeMillis()) < endOfSleeping) {
// sleep
try {
Thread.sleep(endOfSleeping - now);
} catch (InterruptedException e) {
+ // do nothing about it
}
- // check
+ // check if nodes are up now
if (allNodesUp()) {
+
+ // log exiting and return true
+ this.logger.exiting(this.getClass().getName(),
+ "hupUntilUp", true);
return true;
}
}
@@ -147,15 +584,27 @@
// continue in loop
}
- // no retries left and not all nodes are up; return failure
+ // no retries left and not all nodes are up; log exiting and return
+ // failure
+ this.logger.exiting(this.getClass().getName(), "hupUntilUp", false);
return false;
-
}
public void shutdownNodes() throws TorProcessException {
+
+ // log entering
+ this.logger.entering(this.getClass().getName(), "shutdownNodes");
+
+ // check state
if (this.networkState != NetworkState.NODES_STARTED) {
- throw new IllegalStateException();
+ IllegalStateException e = new IllegalStateException();
+ this.logger.throwing(this.getClass().getName(), "shutdownNodes", e);
+ throw e;
}
+
+ // iteratively shut down all nodes; if an exception is caught, continue
+ // shutting down the other nodes and throw the first exception
+ // subsequently
TorProcessException firstCaughtException = null;
for (ProxyNode node : this.nodes) {
try {
@@ -166,46 +615,41 @@
}
}
}
+
+ // change network state
this.networkState = NetworkState.NODES_SHUT_DOWN;
+
+ // if an exception was caught during shutting down nodes, throw the
+ // first caught exception
if (firstCaughtException != null) {
+ this.logger.throwing(this.getClass().getName(), "shutdownNodes",
+ firstCaughtException);
throw firstCaughtException;
}
- }
- private static class NodeStarter extends Thread {
-
- TorProcessException caughtException;
-
- private long maximumTimeToWaitInMillis;
-
- private ProxyNode node;
-
- boolean success = false;
-
- NodeStarter(ProxyNode node, long maximumTimeToWaitInMillis) {
- this.node = node;
- this.maximumTimeToWaitInMillis = maximumTimeToWaitInMillis;
- }
-
- @Override
- public void run() {
- try {
- this.success = this.node
- .startNode(this.maximumTimeToWaitInMillis);
- } catch (TorProcessException e) {
- this.caughtException = e;
- }
- }
+ // log exiting
+ this.logger.exiting(this.getClass().getName(), "shutdownNodes");
}
public boolean startNodes(long maximumTimeToWaitInMillis)
throws TorProcessException {
+
+ // log entering
+ this.logger.entering(this.getClass().getName(), "startNodes",
+ maximumTimeToWaitInMillis);
+
+ // check state
if (this.networkState != NetworkState.CONFIGURATIONS_WRITTEN) {
- throw new IllegalStateException();
+ IllegalStateException e = new IllegalStateException();
+ this.logger.throwing(this.getClass().getName(), "startNodes", e);
+ throw e;
}
+ // check parameter
if (maximumTimeToWaitInMillis < 0) {
- throw new IllegalArgumentException();
+ IllegalArgumentException e = new IllegalArgumentException();
+ this.logger.throwing(this.getClass().getName(), "startNodes", e);
+ throw e;
}
// remember time when we begin starting the nodes
@@ -220,27 +664,45 @@
nodeStarter.start();
}
+ // wait for all node starts to complete
for (NodeStarter nodeStarter : allNodeStarters) {
+
+ // join node starts one after the other
try {
nodeStarter.join();
} catch (InterruptedException e) {
- // we have some kind of problem here!
+ // this happens?! we have some kind of problem here!
+ this.logger.log(Level.WARNING,
+ "Interrupt while joining node starter!");
+
+ // log exiting and return false
+ this.logger.exiting(this.getClass().getName(), "startNodes",
+ false);
return false;
}
+
+ // if node start threw an exception, throw that exception now
if (nodeStarter.caughtException != null) {
- this.networkState = NetworkState.NODES_SHUT_DOWN;
+ this.logger.throwing(this.getClass().getName(), "startNodes",
+ nodeStarter.caughtException);
throw nodeStarter.caughtException;
}
+
+ // if node start did not succeed in the given time, fail
if (!nodeStarter.success) {
this.logger.log(Level.WARNING,
"Starting nodes was not successful in "
+ (maximumTimeToWaitInMillis / 1000)
+ " seconds.", this.networkName);
+
+ // log exiting and return false
+ this.logger.exiting(this.getClass().getName(), "startNodes",
+ false);
return false;
}
}
- // check how long we took to start all nodes
+ // determine how long we took to start all nodes
long after = System.currentTimeMillis();
this.logger.log(Level.FINE, "Starting nodes was successful and took "
+ ((after - before) / 1000) + " seconds.", this.networkName);
@@ -248,88 +710,33 @@
// change state
this.networkState = NetworkState.NODES_STARTED;
+ // log exiting and return true
+ this.logger.exiting(this.getClass().getName(), "startNodes", true);
return true;
}
- public ClientApplication createClient(String clientApplicationName,
- String targetAddress, int targetPort, int socksPort) {
- return new ClientApplicationImpl(this, clientApplicationName,
- targetAddress, targetPort, socksPort);
+ @Override
+ public String toString() {
+ return this.getClass().getSimpleName() + ": networkName=\""
+ + this.networkName + "\", networkState="
+ + this.networkState.toString() + ", nodes.size()="
+ + this.nodes.size();
}
- public ProxyNode createProxy(String nodeName, int controlPort, int socksPort) {
+ public void writeConfigurations() throws TorProcessException {
- // TODO check parms
+ // log entering
+ this.logger.entering(this.getClass().getName(), "writeConfigurations");
- ProxyNodeImpl proxy = new ProxyNodeImpl(this, nodeName, controlPort,
- socksPort);
-
- // add to nodes
- this.nodes.add(proxy);
-
- return proxy;
- }
-
- public DirectoryNode createDirectory(String nodeName, int controlPort,
- int socksPort, int orPort, int dirPort) {
-
- DirectoryNode dir = new DirectoryNodeImpl(this, nodeName, controlPort,
- socksPort, orPort, dirPort);
-
- this.nodes.add(dir);
-
- return dir;
- }
-
- public RouterNode createRouter(String nodeName, int controlPort,
- int socksPort, int orPort, int dirPort) {
- RouterNode router = new RouterNodeImpl(this, nodeName, controlPort,
- socksPort, orPort, dirPort);
-
- this.nodes.add(router);
-
- return router;
- }
-
- public ServerApplication createServer(String serverApplicationName,
- int serverPort) {
- return new ServerApplicationImpl(this, serverApplicationName,
- serverPort);
- }
-
- public EventManager getEventManager() {
- return this.eventManager;
- }
-
- public EventManagerImpl getEventManagerImpl() {
- return this.eventManager;
- }
-
- private NetworkState networkState = NetworkState.CONFIGURING_NODES;
-
- /**
- * Writes configurations for all nodes in the network, including torrc and
- * approved-routers files. Directory nodes are configured first in order to
- * obtain their fingerprints for all torrc files. Next are routers to obtain
- * their fingerprints for the directories' approved-routers files. Proxies
- * are configured at the end.
- *
- * This operation can only be invoked, if network status is CONFIGURABLE.
- *
- * @throws IllegalStateException
- * If method is invoked in network status other than
- * CONFIGURABLE.
- */
- public void writeConfigurations() throws TorProcessException {
-
// check state
if (this.networkState != NetworkState.CONFIGURING_NODES) {
- throw new IllegalStateException();
+ IllegalStateException e = new IllegalStateException();
+ this.logger.throwing(this.getClass().getName(),
+ "writeConfigurations", e);
+ throw e;
}
- // TODO don't we need to configure the nodes as private nodes, if we
- // have a directory node here?!
-
+ // write configurations for all nodes
for (ProxyNode node : this.nodes) {
if (node.getNodeState() == NodeState.CONFIGURING) {
node.writeConfiguration();
@@ -338,124 +745,8 @@
// change state
this.networkState = NetworkState.CONFIGURATIONS_WRITTEN;
- }
- /**
- * Directory that contains status information of all nodes contained in this
- * network, plus the common log file, if one is created.
- */
- protected File workingDir;
-
- /**
- * Returns the working directory of this network configuration which is in
- * test-env/networkName/.
- *
- * @return Working directory of this network.
- */
- File getWorkingDir() {
- return workingDir;
+ // log exiting
+ this.logger.exiting(this.getClass().getName(), "writeConfigurations");
}
-
- /**
- * All nodes contained in this network. It is important that we store only
- * interface types to assure that all operations could also be performed by
- * the application itself.
- */
- protected Set<ProxyNode> nodes = new HashSet<ProxyNode>();
-
- /**
- * Internal class that is used to determine fingerprints in parallel.
- *
- *
- */
- private static class FingerprintThread extends Thread {
-
- private TorProcessException caughtException = null;
-
- private RouterNode node = null;
-
- FingerprintThread(RouterNode node) {
- this.node = node;
- }
-
- public void run() {
- try {
- node.determineFingerprint();
- } catch (TorProcessException e) {
- this.caughtException = e;
- }
- }
- }
-
- private HashSet<String> approvedRoutersFingerprints;
-
- Set<String> authorizedDirectoriesFingerprints = new HashSet<String>();
-
- public void configureAsPrivateNetwork() throws TorProcessException {
-
- // determine fingerprints for all directories and routers (can be done
- // in parallel)
- Set<FingerprintThread> fingerprintThreads = new HashSet<FingerprintThread>();
- for (ProxyNode node : nodes) {
- if (node instanceof RouterNode) {
- RouterNode dirOrRouterNode = (RouterNode) node;
- FingerprintThread fingerprintThread = new FingerprintThread(
- dirOrRouterNode);
- fingerprintThread.setName(node.getNodeName()
- + " Fingerprint Resolver");
- fingerprintThreads.add(fingerprintThread);
- fingerprintThread.start();
- }
- }
- for (FingerprintThread fingerprintThread : fingerprintThreads) {
- try {
- fingerprintThread.join();
- } catch (InterruptedException e) {
- // ignore
- logger.log(Level.WARNING, "fingerprint thread was interrupted.");
- }
- if (fingerprintThread.caughtException != null) {
- throw fingerprintThread.caughtException;
- }
- }
-
- // read DirServer strings for all directories from memory; they should
- // have been read from disk before, so that this will perform really
- // fast
- for (ProxyNode node : this.nodes) {
- if (node instanceof DirectoryNode) {
- DirectoryNode dirNode = (DirectoryNode) node;
- this.authorizedDirectoriesFingerprints.add(dirNode
- .determineDirServerString());
- }
-
- }
-
- // configure nodes
- for (ProxyNode node : this.nodes) {
- if (node.getNodeState() == NodeState.CONFIGURING) {
- node
- .configureDirServers(this.authorizedDirectoriesFingerprints);
- }
- }
-
- // read fingerprints for all directories and routers from memory and
- // write them to approved-routers file; they should have been read from
- // disk before, so that this will perform really fast
- this.approvedRoutersFingerprints = new HashSet<String>();
- for (ProxyNode node : this.nodes) {
- if (node instanceof RouterNode) {
- RouterNode routerOrDirNode = (RouterNode) node;
- this.approvedRoutersFingerprints.add(routerOrDirNode
- .determineFingerprint());
- }
-
- }
- for (ProxyNode node : this.nodes) {
- if (node instanceof DirectoryNode) {
- DirectoryNode dirNode = (DirectoryNode) node;
- dirNode.writeApprovedRouters(this.approvedRoutersFingerprints);
- }
- }
- }
}
Modified: puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/impl/ProxyNodeImpl.java
===================================================================
--- puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/impl/ProxyNodeImpl.java 2007-06-27 20:52:42 UTC (rev 10686)
+++ puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/impl/ProxyNodeImpl.java 2007-06-27 22:09:47 UTC (rev 10687)
@@ -1,19 +1,16 @@
-/*
- * NOTICE: This file is still work in progress. As you can see the Java
- * documentation is written partly in German and in English or needs some work
- * to refine it. This which will be the first thing to change in the next
- * version. Sorry for any inconvenience!
- */
package de.uniba.wiai.lspi.puppetor.impl;
-import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
+import java.io.InputStream;
import java.io.InputStreamReader;
+import java.io.OutputStream;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
@@ -29,21 +26,23 @@
import de.uniba.wiai.lspi.puppetor.TorProcessException;
/**
- * Abstract Java proxy that represents one Tor node (i.e. Tor process) in the
- * testbed network. Can be a Tor proxy, a Tor router, or a Tor directory.
+ * Implementation of <code>ProxyNode</code>.
*
* @author kloesing
*/
public class ProxyNodeImpl implements ProxyNode {
- // TODO make this configurable
+ /**
+ * Executable file containing Tor.
+ *
+ * TODO make this configurable!
+ */
protected static final File torExecutable = new File("tor");
/**
- * Logger for this Node instance which is called "node." plus the node's
- * name.
+ * The <code>torrc</code> configuration file of this Tor node.
*/
- protected Logger logger;
+ protected File configFile;
/**
* Collects all configuration strings for this node during configuration
@@ -51,51 +50,86 @@
*/
protected List<String> configuration;
- public synchronized NodeState getNodeState() {
- return this.nodeState;
- }
+ /**
+ * Connection via Tor controller.
+ */
+ protected TorControlConnection conn;
- @Override
- public String toString() {
- return this.getClass().getSimpleName() + ": nodeName=\""
- + this.nodeName + "\", controlPort=" + this.controlPort
- + ", socksPort=" + this.socksPort;
- }
+ /**
+ * Port on which the Tor node will be listening for us as its controller.
+ */
+ protected int controlPort;
/**
- * Port on which node will be listening for SOCKS connections.
+ * Event manager to which all events concerning this node are notified.
*/
+ private EventManagerImpl eventManager;
+
+ /**
+ * Logger for this <code>ProxyNodeImpl</code> instance which is called
+ * "node." plus the name of this node.
+ */
+ protected Logger logger;
+
+ /**
+ * Network to which this node belongs.
+ */
+ protected NetworkImpl network;
+
+ /**
+ * Name of this node that is used as part of the working directory and as
+ * logger name of this node.
+ */
+ protected String nodeName;
+
+ /**
+ * The state of this node.
+ */
+ protected NodeState nodeState = NodeState.CONFIGURING;
+
+ /**
+ * Port on which the Tor node will be listening for SOCKS connection
+ * requests.
+ */
protected int socksPort;
- private EventManagerImpl eventManager;
+ /**
+ * Handle on the running Tor process that belongs to this node.
+ */
+ protected Process torProcess;
/**
- * LOGGING OK
+ * Directory in which all information concerning this node is stored.
+ */
+ protected File workingDir;
+
+ /**
+ * Creates a new <code>ProxyNodeImpl</code> and adds it to the given
+ * <code>network</code>, but does not yet write its configuration to disk
+ * or start the corresponding Tor process.
*
- * Creates a new node and adds it to the given network. Does not yet create
- * a new Tor process.
- *
* @param network
* Network configuration to which this node belongs.
* @param nodeName
- * The node's name which may only consist of between 1 and 19
- * alpha-numeric characters.
+ * The name of the new node which may only consist of between 1
+ * and 19 alpha-numeric characters.
* @param controlPort
- * Port on which the Tor process will be listening for us as its
- * controller.
- *
+ * Port on which the Tor node will be listening for us as its
+ * controller. May not be negative or greater than 65535.
+ * @param socksPort
+ * Port on which the Tor node will be listening for SOCKS
+ * connection requests. May not be negative or greater than
+ * 65535.
* @throws IllegalArgumentException
- * If at least one of the parameters is null or has an invalid
- * value.
+ * If at least one of the parameters is <code>null</code> or
+ * has an invalid value.
*/
- public ProxyNodeImpl(NetworkImpl network, String nodeName, int controlPort,
+ ProxyNodeImpl(NetworkImpl network, String nodeName, int controlPort,
int socksPort) {
- // make sure that name is a valid logger name
+ // make sure that nodeName is a valid logger name
if (nodeName == null || nodeName.length() < 1 || nodeName.length() > 19
|| !nodeName.matches("[a-zA-Z0-9]*")) {
-
- // prepare and throw exception
String reason = "\"" + nodeName + "\" is not a valid node name!";
IllegalArgumentException e = new IllegalArgumentException(reason);
throw e;
@@ -112,13 +146,7 @@
// check remaining parameters
if (network == null || controlPort < 0 || controlPort > 65535
|| socksPort < 0 || socksPort > 65535) {
-
- // prepare and throw exception
- String reason = "Invalid parameter values: network=" + network
- + ", controlPort=" + controlPort + ", socksPort="
- + socksPort;
- IllegalArgumentException e = new IllegalArgumentException(reason);
- this.logger.log(Level.SEVERE, reason, e);
+ IllegalArgumentException e = new IllegalArgumentException();
this.logger.throwing(this.getClass().getName(), "ProxyNodeImpl", e);
throw e;
}
@@ -132,23 +160,19 @@
// obtain reference on event manager from network
this.eventManager = network.getEventManagerImpl();
- // determine working directory
+ // create working directory
this.workingDir = new File(this.network.getWorkingDir()
.getAbsolutePath()
+ File.separator + nodeName + File.separator);
-
- // create working directory
- this.logger.log(Level.FINER, "Creating working directory \""
- + this.workingDir + "\"...");
this.workingDir.mkdirs();
this.logger.log(Level.FINE, "Created working directory \""
- + this.workingDir + "\"!");
+ + this.workingDir.getAbsolutePath() + "\"");
// create reference on config file
this.configFile = new File(this.workingDir.getAbsolutePath()
+ File.separator + "torrc");
- // initialize configuration with general-purpose configurations
+ // initialize configuration with general-purpose configuration entries
this.configuration = new ArrayList<String>();
this.configuration.add("DataDirectory .");
this.configuration.add("SafeLogging 0");
@@ -176,6 +200,10 @@
this.configuration
.add("AllowInvalidNodes middle,rendezvous,exit,entry,introduction");
+ // tunnel dir connections
+ // this.configuration.add("TunnelDirConns 1");
+ // this.configuration.add("PreferTunneledDirConns 1");
+
// initialize state
this.nodeState = NodeState.CONFIGURING;
@@ -184,11 +212,180 @@
}
+ public void addConfiguration(String configurationString) {
+
+ // log entering
+ this.logger.entering(this.getClass().getName(), "addConfiguration");
+
+ // check state
+ if (this.nodeState != NodeState.CONFIGURING) {
+ IllegalStateException e = new IllegalStateException();
+ this.logger.throwing(this.getClass().getName(), "addConfiguration",
+ e);
+ throw e;
+ }
+
+ // check parameter
+ if (configurationString == null || configurationString.length() < 1) {
+ IllegalArgumentException e = new IllegalArgumentException();
+ this.logger.throwing(this.getClass().getName(), "addConfiguration",
+ e);
+ throw e;
+ }
+
+ // add configuration string
+ this.configuration.add(configurationString);
+
+ // log exiting
+ this.logger.exiting(this.getClass().getName(), "addConfiguration");
+ }
+
+ public synchronized void addHiddenService(String serviceName,
+ int servicePort, int virtualPort) {
+
+ // log entering
+ this.logger.entering(this.getClass().getName(), "addHiddenService",
+ new Object[] { serviceName, servicePort, virtualPort });
+
+ // check state
+ if (this.nodeState != NodeState.CONFIGURING) {
+ this.logger.log(Level.SEVERE,
+ "Hidden service can only be added when node is in state "
+ + "CONFIGURING!");
+ IllegalStateException e = new IllegalStateException(
+ "Hidden service can only be added when node is in state "
+ + "CONFIGURING!");
+ this.logger.throwing(this.getClass().getName(), "addHiddenService",
+ e);
+ throw e;
+ }
+
+ // check parameters
+ if (serviceName == null || serviceName.length() == 0 || servicePort < 0
+ || servicePort > 65535 || virtualPort < 0
+ || virtualPort > 65535) {
+ this.logger.log(Level.SEVERE,
+ "Illegal argument when adding hidden service!");
+ IllegalArgumentException e = new IllegalArgumentException();
+ this.logger.throwing(this.getClass().getName(), "addHiddenService",
+ e);
+ throw e;
+ }
+
+ // add hidden service using Tor controller
+ this.configuration.add("HiddenServiceDir "
+ + workingDir.getAbsolutePath() + File.separator + serviceName
+ + "\nHiddenServicePort " + virtualPort + " 127.0.0.1:"
+ + servicePort);
+
+ // log exiting
+ this.logger.exiting(this.getClass().getName(), "addHiddenService");
+ }
+
/**
- * LOGGING OK
+ * Adds a hidden service configuration to this node while the node is
+ * running.
*
- * @see de.uniba.wiai.lspi.puppetor.ProxyNode#configureDirServers(java.util.Set)
+ * TODO not fully implemented yet, but this should be possible both, during
+ * configuration and when running a network...
+ *
+ * @param serviceName
+ * Name of the hidden service that will be used as name for the
+ * hidden service directory. May neither be <code>null</code>
+ * or a zero-length string.
+ * @param servicePort
+ * The TCP port on which the service will be available for
+ * requests. This can, but need not be different from the virtual
+ * port that is announced to clients. May not be negative or
+ * greater than 65535.
+ * @param virtualPort
+ * The virtual TCP port that this hidden service runs on as it is
+ * announced to clients. May not be negative or greater than
+ * 65535.
+ * @return The onion address string consisting of 16 base32 chars plus
+ * ".onion" for hidden service versions 0 and 1 or 16 base32 chars
+ * plus "." plus 24 base32 chars plus ".onion" for hidden service
+ * version 2.
*/
+ synchronized String addHiddenServiceUsingController(String serviceName,
+ int servicePort, int virtualPort) {
+
+ // TODO this method is not supported yet!
+ if (1 != 2) {
+ UnsupportedOperationException e = new UnsupportedOperationException();
+ this.logger.throwing(this.getClass().getName(),
+ "addHiddenServiceUsingController", e);
+ throw e;
+ }
+
+ // log entering
+ this.logger.entering(this.getClass().getName(),
+ "addHiddenServiceUsingController", new Object[] { serviceName,
+ servicePort, virtualPort });
+
+ // TODO check state
+
+ // check parameters
+ if (serviceName == null || serviceName.length() == 0 || servicePort < 0
+ || servicePort > 65535 || virtualPort < 0
+ || virtualPort > 65535) {
+ IllegalArgumentException e = new IllegalArgumentException();
+ this.logger.throwing(this.getClass().getName(),
+ "addHiddenServiceUsingController", e);
+ throw e;
+ }
+
+ // String serverName = server.getServerName();
+ // int serverPort = server.getServerPort();
+
+ // add hidden service using Tor controller
+ this.logger.log(Level.FINE,
+ "Adding hidden service using Tor controller.");
+
+ List<String> configs = new ArrayList<String>();
+ configs.add("HiddenServiceDir " + workingDir.getAbsolutePath() + "/"
+ + serviceName);
+ configs.add("HiddenServicePort " + virtualPort + " 127.0.0.1:"
+ + servicePort);
+ try {
+ conn.setConf(configs);
+ } catch (IOException e) {
+ RuntimeException ex = new RuntimeException(
+ "IOException when trying to register a new "
+ + "hidden service", e);
+ this.logger.throwing(this.getClass().getName(),
+ "addHiddenServiceUsingController", ex);
+ throw ex;
+ }
+ this.logger.log(Level.FINE,
+ "Hidden service successfully registered at Tor proxy.");
+
+ //
+ File hiddenServiceFile = new File(workingDir.getAbsolutePath() + "\\"
+ + serviceName + "\\hostname");
+ if (!hiddenServiceFile.exists()) {
+ RuntimeException ex = new RuntimeException();
+ this.logger.throwing(this.getClass().getName(),
+ "addHiddenServiceUsingController", ex);
+ throw ex;
+ }
+ // read hostname from file
+ String address = null;
+ try {
+ BufferedReader br = new BufferedReader(new FileReader(
+ hiddenServiceFile));
+ address = br.readLine();
+ br.close();
+ } catch (IOException e) {
+ RuntimeException ex = new RuntimeException(e);
+ this.logger.throwing(this.getClass().getName(),
+ "addHiddenServiceUsingController", ex);
+ throw ex;
+ }
+
+ return address;
+ }
+
public synchronized void configureDirServers(
Set<String> authorizedDirServerStrings) {
@@ -198,55 +395,194 @@
// check parameter
if (authorizedDirServerStrings == null) {
-
- // prepare and throw exception
- String reason = "Parameter may not be null!";
- IllegalArgumentException e = new IllegalArgumentException(reason);
- this.logger.log(Level.SEVERE, reason, e);
+ IllegalArgumentException e = new IllegalArgumentException(
+ "Parameter may not be null!");
this.logger.throwing(this.getClass().getName(),
"configureDirServers", e);
throw e;
}
// add to configuration
+ int entriesBefore = this.configuration.size();
this.configuration.addAll(authorizedDirServerStrings);
this.logger.log(Level.FINE, "Added "
+ authorizedDirServerStrings.size()
- + " DirServer entries to configuration!");
+ + " DirServer entries to configuration, having "
+ + entriesBefore + " entries before and "
+ + this.configuration.size()
+ + " entries afterwards (duplicates possible)!");
// log exiting
this.logger.exiting(this.getClass().getName(), "configureDirServers");
+ }
+ public synchronized void copyDescriptorTo(ProxyNode otherNode)
+ throws TorProcessException {
+
+ // log entering
+ this.logger.entering(this.getClass().getName(), "copyDescriptorTo",
+ otherNode);
+
+ // copy files
+ try {
+ File otherWorkingDir = ((ProxyNodeImpl) otherNode).workingDir;
+ for (File f : workingDir.listFiles()) {
+ if (f.getName().contains(".rsd")) {
+ File dst = new File(otherWorkingDir.getAbsolutePath()
+ + File.separator + f.getName());
+ this.logger.log(Level.FINE, "Copying '"
+ + f.getAbsolutePath() + "' to '"
+ + dst.getAbsolutePath() + "'...");
+ InputStream in = new FileInputStream(f);
+ OutputStream out = new FileOutputStream(dst);
+ byte[] buf = new byte[1024];
+ int len;
+ while ((len = in.read(buf)) > 0) {
+ out.write(buf, 0, len);
+ }
+ in.close();
+ out.close();
+ }
+ }
+ } catch (IOException e) {
+ TorProcessException ex = new TorProcessException(
+ "Error copying descriptors");
+ this.logger.throwing(this.getClass().getName(), "copyDescriptorTo",
+ ex);
+ throw ex;
+ }
+
+ // log exiting
+ this.logger.exiting(this.getClass().getName(), "copyDescriptorTo");
}
- /**
- * Network to which this node belongs.
- */
- protected NetworkImpl network;
+ public synchronized String getNodeName() {
+ return this.nodeName;
+ }
- /**
- * Name of this node that is used as part of the node's working directory
- * and logger.
- */
- protected String nodeName;
+ public synchronized NodeState getNodeState() {
+ return this.nodeState;
+ }
- /**
- * Port on which the process will be listening for us as its controller.
- */
- protected int controlPort;
+ public synchronized String getOnionAddress(String serviceName, int version)
+ throws TorProcessException {
- /**
- * Directory in which all information concerning this node is stored.
- */
- protected File workingDir;
+ // log entering
+ this.logger.entering(this.getClass().getName(), "getOnionAddress",
+ new Object[] { serviceName, version });
- /**
- * LOGGING OK
- *
- * @param maximumTimeToWaitInMillis <
- * 0 bedeutet unendlich lange
- *
- */
+ // check parameter
+ if (serviceName == null || serviceName.length() == 0) {
+ IllegalArgumentException e = new IllegalArgumentException();
+ this.logger.throwing(this.getClass().getName(), "getOnionAddress",
+ e);
+ throw e;
+ }
+
+ // check if hidden service directory exists
+ File hiddenServiceFile = new File(workingDir.getAbsolutePath()
+ + File.separator + serviceName + File.separator + "hostname"
+ + ((version <= 1) ? "" : "2"));
+ if (!hiddenServiceFile.exists()) {
+ this.logger.log(Level.SEVERE,
+ "Hidden service directory or hostname file does not exist: "
+ + hiddenServiceFile.getAbsolutePath());
+
+ TorProcessException e = new TorProcessException(
+ "Hidden service directory or hostname file does not exist: "
+ + hiddenServiceFile.getAbsolutePath());
+ this.logger.throwing(this.getClass().getName(), "getOnionAddress",
+ e);
+ throw e;
+ }
+
+ // read hostname from file
+ String address = null;
+ try {
+ BufferedReader br = new BufferedReader(new FileReader(
+ hiddenServiceFile));
+ address = br.readLine();
+ br.close();
+ } catch (IOException e) {
+ TorProcessException ex = new TorProcessException(
+ "Could not read hostname file!", e);
+ this.logger.throwing(this.getClass().getName(), "getOnionAddress",
+ ex);
+ throw ex;
+ }
+
+ // log exiting and return address
+ this.logger.exiting(this.getClass().getName(), "getOnionAddress",
+ address);
+ return address;
+ }
+
+ public synchronized void hup() throws TorProcessException {
+
+ // log entering
+ this.logger.entering(this.getClass().getName(), "hup");
+
+ // check state
+ if (this.nodeState != NodeState.RUNNING) {
+ IllegalStateException e = new IllegalStateException(
+ "Cannot hup a process when it's not running!");
+ this.logger.throwing(this.getClass().getName(), "hup", e);
+ throw e;
+ }
+
+ // send HUP signal to Tor process
+ try {
+ this.conn.signal("HUP");
+ } catch (IOException e) {
+ TorProcessException ex = new TorProcessException(
+ "Could not send the command HUP to the Tor process!", e);
+ this.logger.throwing(this.getClass().getName(), "hup", ex);
+ throw ex;
+ } catch (NullPointerException e) {
+ // TODO sometimes, this throws a NullPointerException...
+ this.logger.log(Level.SEVERE,
+ "NullPointerException while sending HUP signal to node "
+ + this.toString());
+ throw e;
+ }
+
+ // log exiting
+ this.logger.exiting(this.getClass().getName(), "hup");
+ }
+
+ public synchronized void shutdown() throws TorProcessException {
+
+ // log entering
+ this.logger.entering(this.getClass().getName(), "shutdown");
+
+ // check state
+ if (this.nodeState != NodeState.RUNNING) {
+ IllegalStateException e = new IllegalStateException();
+ this.logger.throwing(this.getClass().getName(), "shutdown", e);
+ throw e;
+ }
+
+ // we cannot simply kill the Tor process, because we have established a
+ // controller connection to it which would interpret a closed socket as
+ // failure and throw a RuntimeException
+ // TODO who cares?!
+ try {
+ this.conn.shutdownTor("SHUTDOWN");
+ this.conn.shutdownTor("SHUTDOWN");
+ } catch (IOException e) {
+ TorProcessException ex = new TorProcessException(
+ "Could not send shutdown command to Tor process!", e);
+ this.logger.throwing(this.getClass().getName(), "shutdown", ex);
+ throw ex;
+ }
+
+ // change state
+ this.nodeState = NodeState.SHUT_DOWN;
+
+ // log exiting
+ this.logger.exiting(this.getClass().getName(), "shutdown");
+ }
+
public synchronized boolean startNode(long maximumTimeToWaitInMillis)
throws TorProcessException {
@@ -256,12 +592,9 @@
// check state
if (this.nodeState != NodeState.CONFIGURATION_WRITTEN) {
-
- // prepare and throw exception
String reason = "Node is not in state "
+ "NodeState.CONFIGURATION_WRITTEN!";
IllegalStateException e = new IllegalStateException(reason);
- this.logger.log(Level.SEVERE, reason, e);
this.logger.throwing(this.getClass().getName(), "startNode", e);
throw e;
}
@@ -275,13 +608,10 @@
this.torProcess = processBuilder.start();
this.logger.log(Level.FINE, "Started Tor process successfully!");
} catch (IOException e) {
-
- // prepare and throw exception
String reason = "Could not start Tor process!";
- TorProcessException e1 = new TorProcessException(reason, e);
- this.logger.log(Level.SEVERE, reason, e1);
- this.logger.throwing(this.getClass().getName(), "startNode", e1);
- throw e1;
+ TorProcessException ex = new TorProcessException(reason, e);
+ this.logger.throwing(this.getClass().getName(), "startNode", ex);
+ throw ex;
}
// start thread to parse output
@@ -294,10 +624,9 @@
// log entering
logger.entering(this.getClass().getName(), "run");
+ // read output from Tor to parse it
String line = null;
boolean waitingForControlPort = true;
-
- // read output from Tor
try {
while ((line = br.readLine()) != null) {
@@ -319,7 +648,7 @@
// don't throw this exception, nobody will catch it!
String reason = "IOException when reading output from Tor "
+ "process!";
- logger.log(Level.FINE, reason, e);
+ logger.log(Level.WARNING, reason, e);
}
// log exiting
@@ -372,11 +701,14 @@
// be sure that Tor is ready, especially if computer is very busy and
// many nodes are created
- try {
- Thread.sleep(1000);
- } catch (InterruptedException e2) {
- }
-
+ // TODO don't wait, because we could miss log messages while waiting
+ // TODO should we better only parse the process output instead of
+ // parsing log messages from the controller?!
+ // try {
+ // Thread.sleep(1000);
+ // } catch (InterruptedException e2) {
+ // }
+
// connect to the controller
this.logger.log(Level.FINER, "Connecting to control port...");
try {
@@ -384,13 +716,11 @@
this.conn = TorControlConnection.getConnection(controlSocket);
this.conn.authenticate(new byte[0]);
} catch (IOException e) {
-
- // prepare and throw exception
- String reason = "Could not connect to control port " + controlPort + "!";
- TorProcessException e1 = new TorProcessException(reason, e);
- this.logger.log(Level.SEVERE, reason, e1);
- this.logger.throwing(this.getClass().getName(), "startNode", e1);
- throw e1;
+ String reason = "Could not connect to control port " + controlPort
+ + "!";
+ TorProcessException ex = new TorProcessException(reason, e);
+ this.logger.throwing(this.getClass().getName(), "startNode", ex);
+ throw ex;
}
this.logger.log(Level.FINE, "Connected to control port successfully!");
@@ -398,14 +728,16 @@
EventHandler handler = new EventHandler() {
public void bandwidthUsed(long read, long written) {
- logger.log(Level.FINEST, "bandwidthUsed(read, written) = "
- + read + ", " + written);
+ // TODO do we need this information?
+ // logger.log(Level.FINEST, "bandwidthUsed(read, written) = "
+ // + read + ", " + written);
}
public void circuitStatus(String status, String circID, String path) {
- logger.log(Level.FINEST,
- "circuitStatus(status, circID, path) = " + status
- + ", " + circID + ", " + path);
+ // TODO do we need this information?
+ // logger.log(Level.FINEST,
+ // "circuitStatus(status, circID, path) = " + status
+ // + ", " + circID + ", " + path);
}
public void message(String severity, String msg) {
@@ -429,51 +761,50 @@
}
public void newDescriptors(List orList) {
- StringBuilder sb = new StringBuilder(
- "newDescriptors(orList) =\n");
- for (Object o : orList) {
- sb.append(o + "\n");
- }
- logger.log(Level.FINEST, sb.toString());
+ // TODO do we need this information?
+ // StringBuilder sb = new StringBuilder(
+ // "newDescriptors(orList) =\n");
+ // for (Object o : orList) {
+ // sb.append(o + "\n");
+ // }
+ // logger.log(Level.FINEST, sb.toString());
}
public void orConnStatus(String status, String orName) {
- logger.log(Level.FINEST, "orConnStatus(status, orName) = "
- + status + ", " + orName);
+ // TODO do we need this information?
+ // logger.log(Level.FINEST, "orConnStatus(status, orName) = "
+ // + status + ", " + orName);
}
public void streamStatus(String status, String streamID,
String target) {
- logger.log(Level.FINEST,
- "streamStatus(status, streamID, target) = " + status
- + ", " + streamID + ", " + target);
+ // TODO do we need this information?
+ // logger.log(Level.FINEST,
+ // "streamStatus(status, streamID, target) = " + status
+ // + ", " + streamID + ", " + target);
}
public void unrecognized(String type, String msg) {
- logger.log(Level.FINEST, "unrecognized(type, msg) = " + type
- + ", " + msg);
+ // TODO do we need this information?
+ // logger.log(Level.FINEST, "unrecognized(type, msg) = " + type
+ // + ", " + msg);
}
};
- conn.setEventHandler(handler);
-
- // register for logging events of level INFO and higher
+ this.conn.setEventHandler(handler);
+
+ // register for logging events of level INFO and higher using controller
List<String> events = new ArrayList<String>();
events.add("INFO");
events.add("NOTICE");
events.add("WARN");
events.add("ERR");
try {
-
- // register for events using controller
this.conn.setEvents(events);
} catch (IOException e) {
-
- // prepare and throw exception
String reason = "Could not register event handler at Tor process!";
- TorProcessException e1 = new TorProcessException(reason, e);
- this.logger.log(Level.SEVERE, reason, e1);
- this.logger.throwing(this.getClass().getName(), "startNode", e1);
- throw e1;
+ TorProcessException ex = new TorProcessException(reason, e);
+ this.logger.throwing(this.getClass().getName(), "startNode", ex);
+ throw ex;
}
this.logger.log(Level.FINE, "Registered event handler at Tor process!");
@@ -485,92 +816,24 @@
return true;
}
- /**
- * Handle on running Tor process.
- */
- protected Process torProcess;
-
- public synchronized void addHiddenService(String serviceName,
- int servicePort, int virtualPort) {
-
- // check state
- if (this.nodeState != NodeState.CONFIGURING) {
- this.logger.log(Level.SEVERE,
- "Hidden service can only be added when node is in state "
- + "CONFIGURING!");
- throw new IllegalStateException(
- "Hidden service can only be added when node is in state "
- + "CONFIGURING!");
- }
-
- // check params
- if (serviceName == null || serviceName.length() == 0 || servicePort < 0
- || servicePort > 65535 || virtualPort < 0
- || virtualPort > 65535) {
- this.logger.log(Level.SEVERE,
- "Illegal argument when adding hidden service!");
- throw new IllegalArgumentException();
- }
-
- // add hidden service using Tor controller
- this.configuration.add("HiddenServiceDir "
- + workingDir.getAbsolutePath() + File.separator + serviceName + "\nHiddenServicePort " + virtualPort
- + " 127.0.0.1:" + servicePort);
-
+ @Override
+ public String toString() {
+ return this.getClass().getSimpleName() + ": nodeName=\""
+ + this.nodeName + "\", controlPort=" + this.controlPort
+ + ", socksPort=" + this.socksPort;
}
- public synchronized String getOnionAddress(String serviceName)
- throws TorProcessException {
+ public synchronized void writeConfiguration() throws TorProcessException {
- // check parameter
- if (serviceName == null || serviceName.length() == 0) {
- this.logger.log(Level.SEVERE, "Illegal argument!");
- throw new IllegalArgumentException();
- }
+ // log entering
+ this.logger.entering(this.getClass().getName(), "writeConfiguration");
- // check if hidden service directory exists
- File hiddenServiceFile = new File(workingDir.getAbsolutePath()
- + File.separator + serviceName + File.separator + "hostname");
- if (!hiddenServiceFile.exists()) {
- this.logger.log(Level.SEVERE,
- "Hidden service directory does not exist: "
- + hiddenServiceFile.getAbsolutePath());
- throw new TorProcessException(
- "Hidden service directory does not exist: "
- + hiddenServiceFile.getAbsolutePath());
- }
-
- // read hostname from file
- String address = null;
- try {
- // TODO use FileReader
- FileInputStream fis = new FileInputStream(hiddenServiceFile);
- BufferedInputStream bis = new BufferedInputStream(fis);
- byte[] bytes = new byte[16];
- bis.read(bytes);
- address = new String(bytes) + ".onion";
- bis.close();
- } catch (IOException e) {
- throw new TorProcessException("Could not read hostname file!", e);
- }
-
- return address;
- }
-
- /**
- * Connection via Tor controller.
- */
- protected TorControlConnection conn;
-
- protected NodeState nodeState = NodeState.CONFIGURING;
-
- protected File configFile;
-
- public synchronized void writeConfiguration() throws TorProcessException {
-
// check state
if (this.nodeState != NodeState.CONFIGURING) {
- throw new IllegalStateException();
+ IllegalStateException e = new IllegalStateException();
+ this.logger.throwing(this.getClass().getName(),
+ "writeConfiguration", e);
+ throw e;
}
// write config file
@@ -581,159 +844,17 @@
}
bw.close();
} catch (IOException e) {
- throw new TorProcessException("Could not write configuration!", e);
+ TorProcessException ex = new TorProcessException(
+ "Could not write configuration!", e);
+ this.logger.throwing(this.getClass().getName(),
+ "writeConfiguration", ex);
+ throw ex;
}
// change state
this.nodeState = NodeState.CONFIGURATION_WRITTEN;
- }
- /**
- * @see de.uniba.wiai.lspi.puppetor.ProxyNode#shutdown()
- */
- public synchronized void shutdown() throws TorProcessException {
-
- // check state
- if (this.nodeState != NodeState.RUNNING) {
- throw new IllegalStateException();
- }
-
- // we cannot simply kill the tor.exe process, because we have
- // established a controller connection to it which would interpret a
- // closed socket as failure and throw a RuntimeException
- // TODO who cares?!
- try {
- this.conn.shutdownTor("SHUTDOWN");
- this.conn.shutdownTor("SHUTDOWN");
- } catch (IOException e) {
- this.logger.log(Level.SEVERE,
- "Could not send shutdown command to Tor process!", e);
- throw new TorProcessException(
- "Could not send shutdown command to Tor process!", e);
- }
-
- // change state
- this.nodeState = NodeState.SHUT_DOWN;
+ // log exiting
+ this.logger.exiting(this.getClass().getName(), "writeConfiguration");
}
-
- // /**
- // * Flags that denotes whether certain events have been observed in the
- // log.
- // * In general, this requires logging to be done at least on notice level!
- // */
- // protected Set<Event> observedEvents;
-
- // public synchronized boolean hasEventOccured(Event event) {
- // return observedEvents.contains(event);
- // }
-
- public synchronized void hup() throws TorProcessException {
-
- // check state
- if (this.nodeState != NodeState.RUNNING) {
- this.logger.log(Level.SEVERE,
- "Cannot hup a process when it's not running!");
- throw new IllegalStateException(
- "Cannot hup a process when it's not running!");
- }
-
- // should we check whether conn is null?
- if (this.conn == null) {
- this.logger.log(Level.WARNING, "WARNING! conn is null!");
- }
- try {
- // TODO sometimes, this throws a NullPointerException...
- this.conn.signal("HUP");
- } catch (IOException e) {
- this.logger.log(Level.SEVERE,
- "Could not send the command HUP to the Tor process!", e);
- throw new TorProcessException(
- "Could not send the command HUP to the Tor process!", e);
- }
- }
-
- // public synchronized void addConfig(String newConfiguration) {
- // if (this.nodeStatus != Status.CONFIGURING) {
- // throw new IllegalStateException();
- // }
- // // TODO should we check the new config?!
- // this.configuration.add(newConfiguration);
- // }
-
- // public String getConfiguration() {
- // StringBuilder result = new StringBuilder("Node configuration: ");
- // for (String next : this.configuration) {
- // result.append(next + "\n");
- // }
- // return result.toString();
- // }
-
- /**
- * Adds a hidden service configuration to this node while the node is
- * running.
- *
- * TODO this should be possible both, during configuration and when running
- * a network...
- */
- public synchronized String addHiddenServiceUsingController(
- String serviceName, int servicePort, int virtualPort) {
- if (1 != 2)
- throw new UnsupportedOperationException();
- // TODO check state
-
- // check params
- if (serviceName == null || serviceName.length() == 0 || servicePort < 0
- || servicePort > 65535 || virtualPort < 0
- || virtualPort > 65535) {
- throw new IllegalArgumentException();
- }
-
- // String serverName = server.getServerName();
- // int serverPort = server.getServerPort();
-
- // add hidden service using Tor controller
- this.logger.log(Level.FINE,
- "Adding hidden service using Tor controller.");
-
- List<String> configs = new ArrayList<String>();
- configs.add("HiddenServiceDir " + workingDir.getAbsolutePath() + "/"
- + serviceName);
- configs.add("HiddenServicePort " + virtualPort + " 127.0.0.1:"
- + servicePort);
- try {
- conn.setConf(configs);
- } catch (IOException e) {
- throw new RuntimeException(
- "IOException when trying to register a new "
- + "hidden service", e);
- }
- this.logger.log(Level.FINE,
- "Hidden service successfully registered at Tor proxy.");
-
- //
- File hiddenServiceFile = new File(workingDir.getAbsolutePath() + "\\"
- + serviceName + "\\hostname");
- if (!hiddenServiceFile.exists()) {
- throw new RuntimeException();
- }
- // read hostname from file
- String address = null;
- try {
- // TODO use FileReader
- FileInputStream fis = new FileInputStream(hiddenServiceFile);
- BufferedInputStream bis = new BufferedInputStream(fis);
- byte[] bytes = new byte[16];
- bis.read(bytes);
- address = new String(bytes) + ".onion";
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
-
- return address;
- }
-
- public synchronized String getNodeName() {
- return this.nodeName;
- }
-
}
Modified: puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/impl/RouterNodeImpl.java
===================================================================
--- puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/impl/RouterNodeImpl.java 2007-06-27 20:52:42 UTC (rev 10686)
+++ puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/impl/RouterNodeImpl.java 2007-06-27 22:09:47 UTC (rev 10687)
@@ -1,8 +1,3 @@
-/*
- * NOTICE: This file is still work in progress. As you can see the Java
- * documentation is written partly in German and in English and logging and
- * documentation still need some work. Sorry for any inconvenience!
- */
package de.uniba.wiai.lspi.puppetor.impl;
import java.io.BufferedReader;
@@ -19,34 +14,72 @@
import de.uniba.wiai.lspi.puppetor.RouterNode;
import de.uniba.wiai.lspi.puppetor.TorProcessException;
+/**
+ * Implementation of <code>RouterNode</code>.
+ *
+ * @author kloesing
+ *
+ */
public class RouterNodeImpl extends ProxyNodeImpl implements RouterNode {
- protected final String localIpAddress = "127.0.0.1";
-
/**
- * OR port of this router.
+ * Port on which the Tor node will be listening for directory requests from
+ * other Tor nodes.
*/
- protected int orPort;
+ protected int dirPort;
/**
- * Directory port of this router.
+ * The fingerprint of this node that is determined as hash value of its
+ * onion key.
*/
- protected int dirPort;
+ protected String fingerprint;
/**
- * This node's fingerprint that is determined as hash value of this node's
- * onion routing key.
+ * The IP address of local nodes (typically <code>localhost</code> or
+ * <code>127.0.0.1</code>).
*/
- protected String fingerprint;
+ protected final String localIpAddress = "127.0.0.1";
- @Override
- public String toString() {
- return super.toString() + ", orPort=" + this.orPort + ", dirPort="
- + this.dirPort;
- }
+ /**
+ * Port on which the Tor node will be listening for onion requests by other
+ * Tor nodes.
+ */
+ protected int orPort;
- public RouterNodeImpl(NetworkImpl network, String nodeName,
- int controlPort, int socksPort, int orPort, int dirPort) {
+ /**
+ * Creates a new <code>RouterNodeImpl</code> and adds it to the given
+ * <code>network</code>, but does not yet write its configuration to disk
+ * or start the corresponding Tor process.
+ *
+ * @param network
+ * Network configuration to which this node belongs.
+ * @param nodeName
+ * The name of the new node which may only consist of between 1
+ * and 19 alpha-numeric characters.
+ * @param controlPort
+ * Port on which the Tor node will be listening for us as its
+ * controller. May not be negative or greater than 65535.
+ * @param socksPort
+ * Port on which the Tor node will be listening for SOCKS
+ * connection requests. May not be negative or greater than
+ * 65535.
+ * @param orPort
+ * Port on which the Tor node will be listening for onion
+ * requests by other Tor nodes. May not be negative or greater
+ * than 65535.
+ * @param dirPort
+ * Port on which the Tor node will be listening for directory
+ * requests from other Tor nodes. May not be negative or greater
+ * than 65535.
+ * @throws IllegalArgumentException
+ * If at least one of the parameters is <code>null</code> or
+ * has an invalid value.
+ */
+ RouterNodeImpl(NetworkImpl network, String nodeName, int controlPort,
+ int socksPort, int orPort, int dirPort) {
+
+ // create superclass instance; parameter checking is done in super
+ // constructor
super(network, nodeName, controlPort, socksPort);
// log entering
@@ -56,7 +89,10 @@
// check parameters
if (orPort < 0 || orPort > 65535 || dirPort < 0 || dirPort > 65535) {
- throw new IllegalArgumentException();
+ IllegalArgumentException e = new IllegalArgumentException();
+ this.logger
+ .throwing(this.getClass().getName(), "RouterNodeImpl", e);
+ throw e;
}
// remember parameters
@@ -71,7 +107,7 @@
// all routers mirror the directory
this.configuration.add("DirPort " + dirPort);
- // this node's address should be localhost and not guessed by Tor
+ // the address of this node should be localhost and not guessed by Tor
this.configuration.add("Address " + localIpAddress);
// the OR port may only be contacted locally
@@ -88,24 +124,26 @@
// bypass testing if we are reachable
this.configuration.add("AssumeReachable 1");
-
+
// log exiting
this.logger.exiting(this.getClass().getName(), "RouterNodeImpl");
-
}
- /**
- * @see de.uniba.wiai.lspi.puppetor.RouterNode#determineFingerprint()
- */
public synchronized String determineFingerprint()
throws TorProcessException {
+
+ // log entering
+ this.logger.entering(this.getClass().getName(), "determineFingerprint");
+
+ // check if we can answer the request immediately
if (this.fingerprint != null) {
- // we can answer the request immediately
+ // log exiting and return fingerprint
+ this.logger.exiting(this.getClass().getName(),
+ "determineFingerprint", this.fingerprint);
return this.fingerprint;
}
-
// write modified config file, including a DirServer option with
// false fingerprint; this is necessary, because otherwise Tor
// would not accept that this router node has a private IP
@@ -125,8 +163,11 @@
}
bw.close();
} catch (IOException e) {
- throw new TorProcessException(
+ TorProcessException ex = new TorProcessException(
"Could not write temporary config file!", e);
+ this.logger.throwing(this.getClass().getName(),
+ "determineFingerprint", ex);
+ throw ex;
}
// start process with option --list-fingerprint
@@ -135,13 +176,15 @@
processBuilder.directory(this.workingDir);
processBuilder.redirectErrorStream(true);
Process tmpProcess = null;
-
try {
tmpProcess = processBuilder.start();
} catch (IOException e) {
- throw new TorProcessException(
+ TorProcessException ex = new TorProcessException(
"Could not start Tor process temporarily with "
+ "--list-fingerprint option!", e);
+ this.logger.throwing(this.getClass().getName(),
+ "determineFingerprint", ex);
+ throw ex;
}
// start thread to parse output
@@ -150,14 +193,17 @@
Thread outputThread = new Thread(new Runnable() {
public void run() {
try {
- // Read output from tor
+ // read output from tor
String line = null;
while ((line = br.readLine()) != null) {
// TODO discard output?
logger.log(Level.FINER, line);
}
} catch (IOException e) {
- // TODO handle?
+ // TODO how to handle?
+ logger.log(Level.SEVERE,
+ "I/O exception while parsing output of temporary "
+ + "Tor process!");
}
}
});
@@ -169,11 +215,12 @@
try {
tmpProcess.waitFor();
} catch (InterruptedException e) {
- // TODO handle?
+ // TODO how to handle?
+ this.logger.log(Level.WARNING,
+ "Temporary Tor process was interrupted!", e);
}
// read fingerprint from file
-
File fingerprintFile = new File(this.workingDir.getAbsolutePath()
+ File.separator + "fingerprint");
try {
@@ -182,10 +229,22 @@
this.fingerprint = br2.readLine();
br2.close();
} catch (IOException e) {
- throw new TorProcessException(
+ TorProcessException ex = new TorProcessException(
"Could not read fingerprint from file!", e);
+ this.logger.throwing(this.getClass().getName(),
+ "determineFingerprint", ex);
+ throw ex;
}
-
+
+ // log exiting and return fingerprint
+ this.logger.exiting(this.getClass().getName(), "determineFingerprint",
+ this.fingerprint);
return this.fingerprint;
}
+
+ @Override
+ public String toString() {
+ return super.toString() + ", orPort=" + this.orPort + ", dirPort="
+ + this.dirPort;
+ }
}
Modified: puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/impl/ServerApplicationImpl.java
===================================================================
--- puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/impl/ServerApplicationImpl.java 2007-06-27 20:52:42 UTC (rev 10686)
+++ puppetor/trunk/src/de/uniba/wiai/lspi/puppetor/impl/ServerApplicationImpl.java 2007-06-27 22:09:47 UTC (rev 10687)
@@ -1,8 +1,3 @@
-/*
- * NOTICE: This file is still work in progress. As you can see the Java
- * documentation is written partly in German and in English and logging and
- * documentation still need some work. Sorry for any inconvenience!
- */
package de.uniba.wiai.lspi.puppetor.impl;
import java.io.BufferedReader;
@@ -17,100 +12,109 @@
import de.uniba.wiai.lspi.puppetor.Event;
import de.uniba.wiai.lspi.puppetor.ServerApplication;
+/**
+ * Implementation of <code>ServerApplication</code>.
+ *
+ * @author kloesing
+ */
public class ServerApplicationImpl implements ServerApplication {
/**
- * logger für diesen server
+ * Internal thread class that is used to process an incoming request.
*/
- private Logger logger;
+ private class HandlerThread extends Thread {
- private EventManagerImpl eventManager;
+ /**
+ * Accepted socket on which the request came in.
+ */
+ private Socket handleSocket = null;
- private int serverPort;
+ /**
+ * Creates a new thread to handle the request coming in on
+ * <code>handleSocket</code>, but does not start handling it.
+ *
+ * @param handleSocket
+ * Accepted socket on which the request came in.
+ */
+ public HandlerThread(Socket handleSocket) {
- /**
- * erzeugt neue server app innerhalb der jvm, fängt aber noch nicht an mit
- * listening.
- *
- */
- ServerApplicationImpl(NetworkImpl network, String serverApplicationName,
- int serverPort) {
+ // log entering
+ logger.entering(this.getClass().getName(), "HandlerThread",
+ handleSocket);
- // TODO make sure that name is loggable!!
+ // remember parameter
+ this.handleSocket = handleSocket;
- // create logger
- this.logger = Logger.getLogger("application." + serverApplicationName);
-
- // log entering
- this.logger.entering(this.getClass().getName(),
- "ServerApplicationImpl", new Object[] { serverApplicationName,
- serverPort });
-
- // check parameters
- if (serverApplicationName == null
- || serverApplicationName.length() == 0 || serverPort < 0
- || serverPort > 65535) {
- throw new IllegalArgumentException();
+ // log exiting
+ logger.exiting(this.getClass().getName(), "HandlerThread");
}
- // remember parameters
- this.serverPort = serverPort;
+ @Override
+ public void run() {
- // obtain reference on event manager
- this.eventManager = network.getEventManagerImpl();
+ // log entering
+ logger.entering(this.getClass().getName(), "run");
- // log exiting
- this.logger.exiting(this.getClass().getName(), "ClientApplicationImpl");
- }
+ try {
- private Thread serverThread;
+ // wait for request (don't mind the content)
+ BufferedReader in = new BufferedReader(new InputStreamReader(
+ handleSocket.getInputStream()));
+ in.read();
- public void stopListening() {
+ // send event to event manager
+ eventManager.observeEvent(ServerApplicationImpl.this,
+ Event.APPLICATION_REQUEST_RECEIVED);
- // log entering
- this.logger.entering(this.getClass().getName(), "stopListening");
+ // write response
+ PrintStream out = new PrintStream(handleSocket
+ .getOutputStream());
+ out.print("HTTP/1.0 200 OK\r\n");
- // check if a request is running
- if (this.serverThread == null) {
- throw new IllegalStateException(
- "We did not start listening before!");
- }
+ } catch (IOException e) {
+ logger.log(Level.SEVERE,
+ "I/O exception while handling incoming request!");
+ // we can't do more, because nobody takes notice of this thread.
- // log this event
- this.logger.log(Level.FINE, "Shutting down server");
+ // log exiting
+ logger.exiting(this.getClass().getName(), "run");
+ return;
+ // TODO do we need more?
+ }
- // interrupt thread
- this.serverThread.interrupt();
+ // close socket
+ try {
+ handleSocket.close();
+ } catch (IOException e) {
+ logger
+ .log(Level.WARNING,
+ "I/O exception while closing socket!");
- // log exiting
- this.logger.exiting(this.getClass().getName(), "stopListening");
+ // log exiting
+ logger.exiting(this.getClass().getName(), "run");
+ return;
+ }
- }
-
- public void listen() {
-
- // log entering
- this.logger.entering(this.getClass().getName(), "listen");
-
- // check if we are already listening
- if (this.serverThread != null) {
- throw new IllegalStateException("We are already listening!");
+ // log exiting
+ logger.exiting(this.getClass().getName(), "run");
}
-
- // create a thread that listens in the background
- this.serverThread = new ListenThread();
- this.serverThread.setName("Reply Thread");
- this.serverThread.setDaemon(true);
- this.serverThread.start();
-
- // log exiting
- this.logger.exiting(this.getClass().getName(), "listen");
}
+ /**
+ * Internal thread class that is used to listen for requests.
+ */
private class ListenThread extends Thread {
+ /**
+ * Flag to remember whether this thread listens for requests at the
+ * moment (<code>true</code>), or has been stopped (<code>false</code>).
+ */
private boolean connected;
+ /**
+ * Creates a new thread to listen for requests, but does not start
+ * listening, yet.
+ */
ListenThread() {
// log entering
@@ -123,23 +127,6 @@
logger.exiting(this.getClass().getName(), "ListenThread");
}
- /**
- * stoppt listening
- *
- */
- public void stopListening() {
-
- // log entering
- logger.entering(this.getClass().getName(), "stopListening");
-
- // change connected state to false and interrupt thread
- this.connected = false;
- this.interrupt();
-
- // log exiting
- logger.exiting(this.getClass().getName(), "stopListening");
- }
-
@Override
public void run() {
@@ -148,75 +135,196 @@
try {
+ // create server socket
ServerSocket serverSocket = null;
-
try {
serverSocket = new ServerSocket(serverPort);
} catch (IOException ioe) {
- logger.log(Level.WARNING, "Can't open server socket on port "
- + serverPort + "!");
+ logger.log(Level.SEVERE,
+ "Can't open server socket on port " + serverPort
+ + "!");
+
+ // log exiting
+ logger.exiting(this.getClass().getName(), "run");
+ return;
}
- logger.log(Level.FINE, "Listening on port " + serverPort + "...");
+
+ // as long as we are connected, accept incoming requests
+ logger.log(Level.FINE, "Listening on port " + serverPort
+ + "...");
while (connected) {
+ Socket incomingConnection = null;
try {
- Socket incomingConnection = serverSocket.accept();
- HandlerThread handler = new HandlerThread(
- incomingConnection);
- new Thread(handler).start();
+ incomingConnection = serverSocket.accept();
} catch (Exception e) {
+ logger
+ .log(
+ Level.SEVERE,
+ "Exception while accepting socket requests! Stopping listening!",
+ e);
+ break;
}
+ new HandlerThread(incomingConnection).start();
}
} catch (Exception e) {
// log that we have been interrupted
logger.log(Level.WARNING, "Server has been interrupted!", e);
-
- // log exiting
- logger.exiting(this.getClass().getName(), "run");
}
+ // mark as disconnected
+ this.connected = false;
+
+ // log exiting
+ logger.exiting(this.getClass().getName(), "run");
}
+ /**
+ * Stops listening on server socket.
+ */
+ public void stopListening() {
+
+ // log entering
+ logger.entering(this.getClass().getName(), "stopListening");
+
+ // change connected state to false and interrupt thread
+ this.connected = false;
+ this.interrupt();
+
+ // log exiting
+ logger.exiting(this.getClass().getName(), "stopListening");
+ }
}
- private class HandlerThread implements Runnable {
+ /**
+ * Event manager to which all events concerning this server application are
+ * notified.
+ */
+ private EventManagerImpl eventManager;
- private Socket handleSocket = null;
+ /**
+ * Logger for this server.
+ */
+ private Logger logger;
- public HandlerThread(Socket requestSocket) {
- handleSocket = requestSocket;
+ /**
+ * Name of this server application that is used as logger name of this node.
+ */
+ private String serverApplicationName;
+
+ /**
+ * Port on which this server will listen for incoming requests.
+ */
+ private int serverPort;
+
+ /**
+ * Thread that listens for requests in the background.
+ */
+ private Thread serverThread;
+
+ /**
+ * Creates a new HTTP server application within this JVM, but does not yet
+ * listen for incoming requests.
+ *
+ * @param network
+ * Network to which this HTTP server belongs; at the moment this
+ * is only used to determine the event manager instance.
+ * @param serverApplicationName
+ * Name of this server that is used as part of the logger name.
+ * @param serverPort
+ * Port on which this server will listen for incoming requests.
+ * @throws IllegalArgumentException
+ * If at least one of the parameters is <code>null</code> or
+ * has an invalid value.
+ */
+ ServerApplicationImpl(NetworkImpl network, String serverApplicationName,
+ int serverPort) {
+
+ // check if serverApplicationName can be used as logger name
+ if (serverApplicationName == null
+ || serverApplicationName.length() == 0) {
+ throw new IllegalArgumentException(
+ "Invalid serverApplicationName: " + serverApplicationName);
}
- public void run() {
+ // create logger
+ this.logger = Logger.getLogger("application." + serverApplicationName);
- try {
+ // log entering
+ this.logger.entering(this.getClass().getName(),
+ "ServerApplicationImpl", new Object[] { network,
+ serverApplicationName, serverPort });
- // wait for request (don't mind content)
- BufferedReader in = new BufferedReader(new InputStreamReader(
- handleSocket.getInputStream()));
- in.read();
+ // check parameters
+ if (network == null || serverPort < 0 || serverPort > 65535) {
+ IllegalArgumentException e = new IllegalArgumentException();
+ this.logger.throwing(this.getClass().getName(),
+ "ServerApplicationImpl", e);
+ throw e;
+ }
- // send event to event manager
- eventManager.observeEvent(ServerApplicationImpl.this,
- Event.APPLICATION_REQUEST_RECEIVED);
+ // remember parameters
+ this.serverApplicationName = serverApplicationName;
+ this.serverPort = serverPort;
- // write response
- PrintStream out = new PrintStream(handleSocket
- .getOutputStream());
- out.print("HTTP/1.0 200 OK\r\n");
+ // obtain reference on event manager
+ this.eventManager = network.getEventManagerImpl();
- } catch (Exception e) {
- e.printStackTrace();
- }
+ // log exiting
+ this.logger.exiting(this.getClass().getName(), "ServerApplicationImpl");
+ }
- try {
- // handleSocket.getInputStream().close();
- // handleSocket.getOutputStream().flush();
- // handleSocket.getOutputStream().close();
- handleSocket.close();
- } catch (Exception e) {
- }
+ public synchronized void listen() {
+
+ // log entering
+ this.logger.entering(this.getClass().getName(), "listen");
+
+ // check if we are already listening
+ if (this.serverThread != null) {
+ IllegalStateException e = new IllegalStateException(
+ "We are already listening!");
+ this.logger.throwing(this.getClass().getName(), "listen", e);
+ throw e;
}
+
+ // create a thread that listens in the background
+ this.serverThread = new ListenThread();
+ this.serverThread.setName("Reply Thread");
+ this.serverThread.setDaemon(true);
+ this.serverThread.start();
+
+ // log exiting
+ this.logger.exiting(this.getClass().getName(), "listen");
}
+
+ public synchronized void stopListening() {
+
+ // log entering
+ this.logger.entering(this.getClass().getName(), "stopListening");
+
+ // check if a request is running
+ if (this.serverThread == null) {
+ IllegalStateException e = new IllegalStateException(
+ "We did not start listening before!");
+ this.logger.throwing(this.getClass().getName(), "stopListening", e);
+ throw e;
+ }
+
+ // log this event
+ this.logger.log(Level.FINE, "Shutting down server");
+
+ // interrupt thread
+ this.serverThread.interrupt();
+
+ // log exiting
+ this.logger.exiting(this.getClass().getName(), "stopListening");
+ }
+
+ @Override
+ public String toString() {
+ return this.getClass().getSimpleName() + ": serverApplicationName=\""
+ + this.serverApplicationName + "\", serverPort="
+ + this.serverPort;
+ }
}
More information about the tor-commits
mailing list