diff --git a/audits/2018-05_Status-Beta_Deja_Vu/18_DVS_Status_Case_Study_Short_Version_R2_WEB.pdf b/audits/2018-05_Status-Beta_Deja_Vu/18_DVS_Status_Case_Study_Short_Version_R2_WEB.pdf new file mode 100644 index 0000000..23aff41 --- /dev/null +++ b/audits/2018-05_Status-Beta_Deja_Vu/18_DVS_Status_Case_Study_Short_Version_R2_WEB.pdf @@ -0,0 +1,6986 @@ +%PDF-1.4 % +49 0 obj <> endobj xref +49 814 +0000000016 00000 n +0000018032 00000 n +0000018188 00000 n +0000029112 00000 n +0000029245 00000 n +0000029691 00000 n +0000030115 00000 n +0000030561 00000 n +0000030817 00000 n +0000031476 00000 n +0000031526 00000 n +0000031575 00000 n +0000031625 00000 n +0000031675 00000 n +0000031725 00000 n +0000031775 00000 n +0000031825 00000 n +0000031875 00000 n +0000031925 00000 n +0000031975 00000 n +0000032025 00000 n +0000032074 00000 n +0000032124 00000 n +0000032173 00000 n +0000032223 00000 n +0000032272 00000 n +0000032321 00000 n +0000032370 00000 n +0000032419 00000 n +0000032468 00000 n +0000032518 00000 n +0000032568 00000 n +0000032618 00000 n +0000032666 00000 n +0000032715 00000 n +0000032764 00000 n +0000032813 00000 n +0000032862 00000 n +0000032911 00000 n +0000032960 00000 n +0000033009 00000 n +0000033059 00000 n +0000033109 00000 n +0000033159 00000 n +0000033209 00000 n +0000033258 00000 n +0000033307 00000 n +0000033356 00000 n +0000033405 00000 n +0000033454 00000 n +0000033504 00000 n +0000033553 00000 n +0000033603 00000 n +0000033653 00000 n +0000033703 00000 n +0000033753 00000 n +0000033803 00000 n +0000033853 00000 n +0000033903 00000 n +0000033953 00000 n +0000034003 00000 n +0000034053 00000 n +0000034103 00000 n +0000034153 00000 n +0000034203 00000 n +0000034253 00000 n +0000034303 00000 n +0000034353 00000 n +0000034403 00000 n +0000034453 00000 n +0000034503 00000 n +0000034553 00000 n +0000034603 00000 n +0000034653 00000 n +0000034703 00000 n +0000034753 00000 n +0000034803 00000 n +0000034854 00000 n +0000034904 00000 n +0000034955 00000 n +0000035005 00000 n +0000035055 00000 n +0000035105 00000 n +0000035155 00000 n +0000035205 00000 n +0000035255 00000 n +0000035305 00000 n +0000035355 00000 n +0000035405 00000 n +0000035455 00000 n +0000035505 00000 n +0000035554 00000 n +0000035604 00000 n +0000035655 00000 n +0000035706 00000 n +0000035757 00000 n +0000035807 00000 n +0000035857 00000 n +0000035907 00000 n +0000035957 00000 n +0000036007 00000 n +0000036057 00000 n +0000036107 00000 n +0000036157 00000 n +0000036207 00000 n +0000036258 00000 n +0000036308 00000 n +0000036358 00000 n +0000036408 00000 n +0000036458 00000 n +0000036508 00000 n +0000036558 00000 n +0000036609 00000 n +0000036659 00000 n +0000036710 00000 n +0000036761 00000 n +0000036812 00000 n +0000036863 00000 n +0000036913 00000 n +0000036964 00000 n +0000037014 00000 n +0000037065 00000 n +0000037116 00000 n +0000037166 00000 n +0000037217 00000 n +0000037268 00000 n +0000037319 00000 n +0000037369 00000 n +0000037419 00000 n +0000037470 00000 n +0000037521 00000 n +0000037572 00000 n +0000037622 00000 n +0000037672 00000 n +0000037722 00000 n +0000037773 00000 n +0000037823 00000 n +0000037873 00000 n +0000037923 00000 n +0000037974 00000 n +0000038025 00000 n +0000038075 00000 n +0000038125 00000 n +0000038175 00000 n +0000038226 00000 n +0000038276 00000 n +0000038390 00000 n +0000038417 00000 n +0000053787 00000 n +0000071150 00000 n +0000088839 00000 n +0000104601 00000 n +0000120546 00000 n +0000136500 00000 n +0000136918 00000 n +0000137171 00000 n +0000137307 00000 n +0000137600 00000 n +0000138078 00000 n +0000138546 00000 n +0000138573 00000 n +0000154931 00000 n +0000171894 00000 n +0000172012 00000 n +0000185643 00000 n +0000185770 00000 n +0000186188 00000 n +0000186258 00000 n +0000186328 00000 n +0000203111 00000 n +0000203770 00000 n +0000204041 00000 n +0000220381 00000 n +0000238077 00000 n +0000238345 00000 n +0000238680 00000 n +0000239007 00000 n +0000239478 00000 n +0000240019 00000 n +0000240479 00000 n +0000240829 00000 n +0000241351 00000 n +0000241874 00000 n +0000242216 00000 n +0000242642 00000 n +0000243139 00000 n +0000243447 00000 n +0000243871 00000 n +0000244156 00000 n +0000244567 00000 n +0000244871 00000 n +0000245187 00000 n +0000245490 00000 n +0000245826 00000 n +0000246144 00000 n +0000246583 00000 n +0000247052 00000 n +0000247389 00000 n +0000247442 00000 n +0000247763 00000 n +0000248096 00000 n +0000248426 00000 n +0000248744 00000 n +0000249063 00000 n +0000249360 00000 n +0000249691 00000 n +0000250121 00000 n +0000250556 00000 n +0000250996 00000 n +0000251413 00000 n +0000251692 00000 n +0000251996 00000 n +0000252299 00000 n +0000252569 00000 n +0000252899 00000 n +0000253241 00000 n +0000253556 00000 n +0000253815 00000 n +0000254071 00000 n +0000254313 00000 n +0000254578 00000 n +0000254822 00000 n +0000255058 00000 n +0000255392 00000 n +0000255642 00000 n +0000255898 00000 n +0000256158 00000 n +0000256423 00000 n +0000256737 00000 n +0000257069 00000 n +0000257395 00000 n +0000257705 00000 n +0000258034 00000 n +0000258363 00000 n +0000258677 00000 n +0000258948 00000 n +0000259207 00000 n +0000259463 00000 n +0000259768 00000 n +0000260071 00000 n +0000260387 00000 n +0000260698 00000 n +0000261047 00000 n +0000261369 00000 n +0000261801 00000 n +0000262104 00000 n +0000262417 00000 n +0000262718 00000 n +0000262991 00000 n +0000263309 00000 n +0000263596 00000 n +0000263913 00000 n +0000264179 00000 n +0000264499 00000 n +0000264763 00000 n +0000265045 00000 n +0000265102 00000 n +0000265426 00000 n +0000265763 00000 n +0000266208 00000 n +0000266674 00000 n +0000266978 00000 n +0000267289 00000 n +0000267600 00000 n +0000267907 00000 n +0000268228 00000 n +0000268516 00000 n +0000268838 00000 n +0000269138 00000 n +0000269449 00000 n +0000269892 00000 n +0000270219 00000 n +0000270549 00000 n +0000270874 00000 n +0000271199 00000 n +0000271531 00000 n +0000271846 00000 n +0000272387 00000 n +0000272707 00000 n +0000273154 00000 n +0000273505 00000 n +0000274028 00000 n +0000274551 00000 n +0000274819 00000 n +0000275258 00000 n +0000275589 00000 n +0000276013 00000 n +0000276486 00000 n +0000276781 00000 n +0000277114 00000 n +0000277554 00000 n +0000277981 00000 n +0000278308 00000 n +0000278614 00000 n +0000279053 00000 n +0000279503 00000 n +0000279948 00000 n +0000280211 00000 n +0000280490 00000 n +0000280824 00000 n +0000281271 00000 n +0000281598 00000 n +0000281925 00000 n +0000282226 00000 n +0000282638 00000 n +0000283062 00000 n +0000283373 00000 n +0000283702 00000 n +0000284022 00000 n +0000284451 00000 n +0000284758 00000 n +0000300582 00000 n +0000300835 00000 n +0000301224 00000 n +0000314785 00000 n +0000315043 00000 n +0000315362 00000 n +0000351439 00000 n +0000351478 00000 n +0000388548 00000 n +0000388587 00000 n +0000389462 00000 n +0000390406 00000 n +0000391350 00000 n +0000392294 00000 n +0000393242 00000 n +0000394186 00000 n +0000395138 00000 n +0000396082 00000 n +0000397067 00000 n +0000397489 00000 n +0000398483 00000 n +0000399469 00000 n +0000399883 00000 n +0000400873 00000 n +0000401858 00000 n +0000402280 00000 n +0000403270 00000 n +0000404262 00000 n +0000404687 00000 n +0000405678 00000 n +0000406670 00000 n +0000407095 00000 n +0000408093 00000 n +0000408355 00000 n +0000409417 00000 n +0000409840 00000 n +0000410944 00000 n +0000412002 00000 n +0000412419 00000 n +0000413525 00000 n +0000413954 00000 n +0000414529 00000 n +0000415022 00000 n +0000415994 00000 n +0000416407 00000 n +0000417392 00000 n +0000418384 00000 n +0000419394 00000 n +0000420388 00000 n +0000421425 00000 n +0000422420 00000 n +0000422626 00000 n +0000423636 00000 n +0000424057 00000 n +0000425089 00000 n +0000426098 00000 n +0000426442 00000 n +0000427448 00000 n +0000427680 00000 n +0000427890 00000 n +0000428250 00000 n +0000429237 00000 n +0000429574 00000 n +0000430569 00000 n +0000431556 00000 n +0000431901 00000 n +0000432900 00000 n +0000433881 00000 n +0000434222 00000 n +0000435214 00000 n +0000436203 00000 n +0000436547 00000 n +0000437545 00000 n +0000437786 00000 n +0000438127 00000 n +0000438361 00000 n +0000438606 00000 n +0000438947 00000 n +0000439181 00000 n +0000439421 00000 n +0000439769 00000 n +0000440003 00000 n +0000440244 00000 n +0000440586 00000 n +0000440820 00000 n +0000441061 00000 n +0000441404 00000 n +0000441638 00000 n +0000441882 00000 n +0000442228 00000 n +0000442462 00000 n +0000443523 00000 n +0000443948 00000 n +0000445055 00000 n +0000446118 00000 n +0000446544 00000 n +0000447654 00000 n +0000448648 00000 n +0000449073 00000 n +0000450069 00000 n +0000451052 00000 n +0000451474 00000 n +0000452464 00000 n +0000453449 00000 n +0000453864 00000 n +0000454857 00000 n +0000455844 00000 n +0000456847 00000 n +0000457838 00000 n +0000458883 00000 n +0000459877 00000 n +0000460865 00000 n +0000461278 00000 n +0000462271 00000 n +0000463366 00000 n +0000463723 00000 n +0000464731 00000 n +0000465061 00000 n +0000466104 00000 n +0000467200 00000 n +0000468158 00000 n +0000468406 00000 n +0000468640 00000 n +0000468887 00000 n +0000469218 00000 n +0000470254 00000 n +0000470684 00000 n +0000471742 00000 n +0000472169 00000 n +0000473280 00000 n +0000474341 00000 n +0000474743 00000 n +0000475849 00000 n +0000476823 00000 n +0000477245 00000 n +0000478232 00000 n +0000479209 00000 n +0000479630 00000 n +0000479864 00000 n +0000480838 00000 n +0000481263 00000 n +0000481497 00000 n +0000482485 00000 n +0000482898 00000 n +0000483892 00000 n +0000484986 00000 n +0000485556 00000 n +0000486660 00000 n +0000487667 00000 n +0000488076 00000 n +0000489107 00000 n +0000490117 00000 n +0000491061 00000 n +0000491487 00000 n +0000492515 00000 n +0000492882 00000 n +0000493856 00000 n +0000494281 00000 n +0000495268 00000 n +0000496279 00000 n +0000496700 00000 n +0000497686 00000 n +0000498650 00000 n +0000499066 00000 n +0000500051 00000 n +0000501021 00000 n +0000501444 00000 n +0000502430 00000 n +0000503393 00000 n +0000503767 00000 n +0000504762 00000 n +0000505729 00000 n +0000506151 00000 n +0000507136 00000 n +0000508101 00000 n +0000508505 00000 n +0000509490 00000 n +0000510457 00000 n +0000510874 00000 n +0000511861 00000 n +0000512324 00000 n +0000513385 00000 n +0000513802 00000 n +0000514909 00000 n +0000515330 00000 n +0000515891 00000 n +0000516382 00000 n +0000517361 00000 n +0000517754 00000 n +0000517988 00000 n +0000518953 00000 n +0000519372 00000 n +0000520353 00000 n +0000521316 00000 n +0000521739 00000 n +0000522721 00000 n +0000522968 00000 n +0000524032 00000 n +0000524447 00000 n +0000525548 00000 n +0000526609 00000 n +0000527026 00000 n +0000528133 00000 n +0000529115 00000 n +0000529531 00000 n +0000530522 00000 n +0000531514 00000 n +0000531928 00000 n +0000532918 00000 n +0000533907 00000 n +0000534313 00000 n +0000535307 00000 n +0000536399 00000 n +0000536970 00000 n +0000538074 00000 n +0000539087 00000 n +0000539505 00000 n +0000540541 00000 n +0000541551 00000 n +0000541971 00000 n +0000543000 00000 n +0000543335 00000 n +0000544392 00000 n +0000544814 00000 n +0000545921 00000 n +0000546981 00000 n +0000547398 00000 n +0000548505 00000 n +0000549566 00000 n +0000549985 00000 n +0000551091 00000 n +0000552069 00000 n +0000553096 00000 n +0000553330 00000 n +0000554342 00000 n +0000554593 00000 n +0000554861 00000 n +0000555328 00000 n +0000556095 00000 n +0000556641 00000 n +0000557108 00000 n +0000557862 00000 n +0000558415 00000 n +0000559359 00000 n +0000560332 00000 n +0000560739 00000 n +0000561726 00000 n +0000562823 00000 n +0000563398 00000 n +0000564498 00000 n +0000564747 00000 n +0000565171 00000 n +0000565738 00000 n +0000566226 00000 n +0000566636 00000 n +0000567214 00000 n +0000567692 00000 n +0000568668 00000 n +0000569088 00000 n +0000570074 00000 n +0000571050 00000 n +0000571463 00000 n +0000572452 00000 n +0000573547 00000 n +0000574118 00000 n +0000575225 00000 n +0000576324 00000 n +0000576901 00000 n +0000577996 00000 n +0000579091 00000 n +0000579661 00000 n +0000580770 00000 n +0000581864 00000 n +0000582207 00000 n +0000583239 00000 n +0000583581 00000 n +0000584606 00000 n +0000585573 00000 n +0000586576 00000 n +0000587572 00000 n +0000588608 00000 n +0000588858 00000 n +0000589307 00000 n +0000590369 00000 n +0000590788 00000 n +0000591898 00000 n +0000592959 00000 n +0000593376 00000 n +0000594484 00000 n +0000595543 00000 n +0000595962 00000 n +0000597073 00000 n +0000597502 00000 n +0000598077 00000 n +0000598565 00000 n +0000599540 00000 n +0000599964 00000 n +0000600949 00000 n +0000601926 00000 n +0000602343 00000 n +0000603332 00000 n +0000604306 00000 n +0000604722 00000 n +0000605709 00000 n +0000606701 00000 n +0000607705 00000 n +0000608699 00000 n +0000609736 00000 n +0000610729 00000 n +0000611821 00000 n +0000612391 00000 n +0000613493 00000 n +0000614583 00000 n +0000614818 00000 n +0000615812 00000 n +0000616049 00000 n +0000616284 00000 n +0000617242 00000 n +0000618254 00000 n +0000618469 00000 n +0000618655 00000 n +0000618885 00000 n +0000619135 00000 n +0000619385 00000 n +0000620381 00000 n +0000620631 00000 n +0000620817 00000 n +0000621019 00000 n +0000622010 00000 n +0000622212 00000 n +0000622414 00000 n +0000622656 00000 n +0000622894 00000 n +0000623080 00000 n +0000623325 00000 n +0000623535 00000 n +0000624571 00000 n +0000625562 00000 n +0000625748 00000 n +0000625934 00000 n +0000626120 00000 n +0000626306 00000 n +0000626492 00000 n +0000626926 00000 n +0000627393 00000 n +0000628154 00000 n +0000628702 00000 n +0000629157 00000 n +0000629912 00000 n +0000630461 00000 n +0000630885 00000 n +0000631456 00000 n +0000631949 00000 n +0000632336 00000 n +0000632905 00000 n +0000633358 00000 n +0000634335 00000 n +0000634751 00000 n +0000635745 00000 n +0000636723 00000 n +0000637135 00000 n +0000638122 00000 n +0000639097 00000 n +0000639507 00000 n +0000640495 00000 n +0000641462 00000 n +0000641877 00000 n +0000642858 00000 n +0000643202 00000 n +0000643627 00000 n +0000644201 00000 n +0000644690 00000 n +0000645667 00000 n +0000646080 00000 n +0000647074 00000 n +0000647301 00000 n +0000647831 00000 n +0000648061 00000 n +0000648267 00000 n +0000648505 00000 n +0000648918 00000 n +0000649909 00000 n +0000650095 00000 n +0000651071 00000 n +0000652015 00000 n +0000652221 00000 n +0000652642 00000 n +0000653629 00000 n +0000654604 00000 n +0000654822 00000 n +0000655245 00000 n +0000656233 00000 n +0000656463 00000 n +0000656669 00000 n +0000656905 00000 n +0000657132 00000 n +0000657544 00000 n +0000658530 00000 n +0000658771 00000 n +0000658977 00000 n +0000659950 00000 n +0000660371 00000 n +0000661358 00000 n +0000662334 00000 n +0000662540 00000 n +0000662956 00000 n +0000663944 00000 n +0000665040 00000 n +0000666026 00000 n +0000666604 00000 n +0000667704 00000 n +0000668742 00000 n +0000669686 00000 n +0000670681 00000 n +0000671625 00000 n +0000672622 00000 n +0000673196 00000 n +0000674301 00000 n +0000675281 00000 n +0000676225 00000 n +0000677201 00000 n +0000678222 00000 n +0000678790 00000 n +0000679895 00000 n +0000680101 00000 n +0000681080 00000 n +0000682024 00000 n +0000683014 00000 n +0000684038 00000 n +0000684627 00000 n +0000684835 00000 n +0000685939 00000 n +0000686891 00000 n +0000687881 00000 n +0000688865 00000 n +0000689071 00000 n +0000690059 00000 n +0000690466 00000 n +0000691496 00000 n +0000692484 00000 n +0000693479 00000 n +0000693686 00000 n +0000694677 00000 n +0000695086 00000 n +0000696113 00000 n +0000696347 00000 n +0000696598 00000 n +0000696804 00000 n +0000697788 00000 n +0000698794 00000 n +0000698980 00000 n +0000700016 00000 n +0000701001 00000 n +0000701976 00000 n +0000702920 00000 n +0000703346 00000 n +0000704333 00000 n +0000705306 00000 n +0000705512 00000 n +0000705762 00000 n +0000705980 00000 n +0000706400 00000 n +0000707384 00000 n +0000707632 00000 n +0000708599 00000 n +0000708785 00000 n +0000709792 00000 n +0000709994 00000 n +0000711032 00000 n +0000712017 00000 n +0000712998 00000 n +0000713192 00000 n +0000714182 00000 n +0000715192 00000 n +0000715411 00000 n +0000716355 00000 n +0000716541 00000 n +0000717580 00000 n +0000718569 00000 n +0000718755 00000 n +0000719019 00000 n +0000719997 00000 n +0000720258 00000 n +0000720685 00000 n +0000721679 00000 n +0000721926 00000 n +0000722910 00000 n +0000723338 00000 n +0000724328 00000 n +0000724573 00000 n +0000724807 00000 n +0000725796 00000 n +0000726046 00000 n +0000726232 00000 n +0000726483 00000 n +0000726669 00000 n +0000727704 00000 n +0000728697 00000 n +0000735501 00000 n +0000751411 00000 n +0000752355 00000 n +0000017864 00000 n +0000016576 00000 n +trailer <]/Prev 812248/XRefStm 17864>> startxref 0 %%EOF 862 0 obj <>stream +hVkLe?< r()EK^ևXm~Ksέ6s$MS C%6/rF2碼!Zœ/==ywy޽x,+/SIVv"eΒWK!LGvc/%_ƅ0.#2 w䒜bA(9!}}.([ c'`Q&ퟣ|c0V1Uee/#"2C(ĻѤD`b]JkXdH~@DNOBqqcvh>Gn6iû喝` &a@f6ߏ)nv~99#5x]i!ͼ~$K :KH۬zoz,h}U5dJP>U+*%.v^_lGl&$#zx3>&&(UmzK7v >eθ*CL!09cDm2\3`"ѢՌ@Ym4,qfjmRt.^+.aq`}NV!gP&;Ԧg7 +Bb)!}yJߘa"/JmJҀiPjXm+=g\4" }XcBPΜSMY ľoJE Ƿ,?3[ĸZ # Cs{vAn9⩦DxǎvrmmT6>/Filter/FlateDecode/Index[10 39]/Length 20/Size 49/Type/XRef/W[1 1 1]>>stream +hbbbc`b`` (} endstream endobj 50 0 obj <>/Metadata 8 0 R/Pages 7 0 R/StructTreeRoot 10 0 R/Type/Catalog/ViewerPreferences<>>> endobj 51 0 obj <>/ExtGState<>/Font<>/ProcSet[/PDF/Text/ImageC/ImageI]/Properties<>/Shading<>/XObject<>>>/Rotate 0/StructParents 0/TrimBox[0.0 0.0 612.0 792.0]/Type/Page>> endobj 52 0 obj <> endobj 53 0 obj <>stream +H\ϊ@ >C5iAb[Xwj +(=LJv@&_f0Om'*h2MkkGcw+Zl"SՕClj6}$&qrYJ |s5++&,CɬM.ReG&U^y;+e|7jk"WɚWj 4 [;F*6w$s Oۍg̑rļy|T>2[5'&HMК 5A ZP-bXAXkW  AzG;Y,|QLP}P}D'OT(>Q}DiУ*(;{zk9C?V +0MZ endstream endobj 54 0 obj <> endobj 55 0 obj <> endobj 56 0 obj <> endobj 57 0 obj <>stream +H\ˮ0y +/YرHĢJBXuP Ϸa~Q߇k}p8]3>NݹLH᷾T}ˇmt}w&H8<۲{~7Y\Ezowq(fb;TD}ߎu;!gU톪;d>󟅘goqxUC8.q;[R 2,ʡ dT2b%5T@(B1x89N#NɛBQ&`ȄAdBBB"K&gkGj]-%'b4{I|؋ {ṿT +sZQZ4"#Wt>5Q4*tIb qsjmV ɐm*L@M@-o!$CsK7E[Ɠ*EKtkwu)s%)/pfi2jVA,ZSĸt\A\ϒ JBQ{I=}PEuWۗ3VTFӸSU> endobj 195 0 obj [218 0 R] endobj 196 0 obj <>stream +HWn$}W45/ f <) eWZd SEE{47@`cK.NU]ŋ˿5?~þ:^t6΍C˿cרBu ?vR;UQl~nh6o[??7ذ;l~m^0);S]4=xp{4U{ݮMz8<}w6ŏM `n6 v;Wyɳ'|n/~i zO2>0R/衉G[ټi; +^\”H+ C{=;<G~k{֭{Дwǧ ` +@[elEd#0pAb ;%9T;]!`K>F[B0.E]^[|([R8<9:`x=ݔR$0OFu8.@edD%=>RsKc +W_2yopLp  = +=8 5Cg_ςᇠ#.t,q'cB(-YLO^xDyC-D{e!E81bѡjSN4S.?n6c{MRct}ĀH"NLFE+%0 +SgB_b׭`Bpgg[/U$c?<t )Αu7I BBzQE>#&FRڽ$CbBf,0Xs$gh:k ^{˼|BB8di +- l01uVT%"]1eNV!lçM>O>[hp\@eCS'{].:ɫT(ˣvnGث*{gkvB36m+1  +!:H<6Vܹxf[ " Q ʂv,4zvYTx&'Rz84Ǟ.[I=s*C\.'/^ү*)s5_WW9Kȉޑ_8.ͅJt<8f2tE=5zxne C8Ў9 +ld^"ZjcPJ=4P4YE@xTxl6P&gQ*cr8OUc1MtTyzgDŪJ:Ӿx!MaĦ:xdzjk3}>$VBD#Gb/4([F%V@!҃Ҥ~)MZ8kHTqgx,VB7T+.%K`ˀǑ-DG³2L1w9jZKXJg>`b6+ˤQzLdfsYhAGtXɬMF:bg:: U*#_z6& ,?]k,YaXKYx f瘅۪TDwY{ 665]'f,QN%k;Z˔[F6T8Nl +߬?hG dM]8fL(y(37x9O#9v79&.arylmq 07]Y`!wܷͻ5wM%zm޶/m6g}W0ã_.772=7 ^"W~x!4E!c4b&.3Z3;.›0 Z(!Ux1=}2rDulkmZ$޸*AݚcUdLyOvGدsT>akͱ4z¶sQ;mW#ڼiO;,4Ep+M7!zǎ<亰T͡Ɉq;nYSK?< *$XA,D޿8t0-t4'*<'x%ؤҲfg)v9>电lpqK[P_)_"(1k`=y}Q48dτMr?*@'sR#oܩ2:6C(|l9 +yhR|sʔɘSenQ&%i#1o㜐uIWbf&Gq@MKb@&2 +S}Vɷor|R'n za=y7ܹx&9Sܔ]$I\5SC4uʐn8 ð[vܥW. SY5M+ؐ;b&9PL/Eu"@>d +2ȧ*{|PJ0CMLgOϹ}eJv8_#@r VSwÐmǰ?DDFB5>ʌ{/ PQHL|l8rּA1ER{b̙7ɔ֫94!TП=J~xoPAW[OxJk&>!s]$O!̐M,@J%(8-D0˜V6[ n;:|+u{V|pyŎ*]LfRW35G${.@P%ޑ=x +n)Ji(* F{UI$6`=!낄Ua3)u,iᱨh0&0\ k:? +>?_-lzy}:A)v[lC)xτdQ0¢OVW͈s555s烵!i8(gC O/ȦV¡n) ! +%6l,L;7Gm fQMQPף3-yXF9NԦi͸9R8khײD{m$ڡ&Fm:UecׄW!-Xc,T1Id( T4LjQg.8}Lj ÿZ[H,3EjS@x[9hyE(f?KO$I]v;QsmF`x֊*8R}"pcyW{3H\N;Y s^+(}1ktYǘ24[c! a5~Xnv(G$1vV5ZK&%.5I M3x}2e8Iʾ"y,z=Cn2֤` nA|_^Oװ7hIiiXg:ƎpR?A3l)ݫz-6b4HǭUE#xa٣f(rRRs[ nWUg$XnFSa}XρńAk)^.dLi 7cqJe&Lo[}|`~`o*d|+2dtՋE!>;3VN<\@ RG % L]Ҹ!\MeH5)akۚV%:.*7KlPŽ慖RBZ0Qc6ē@s; gՔoGGag[C Zn>NK=?`y9`BD _l8oHG1svwtc!O\4G{l?A +5# EyylLyZz84Ux~Uܨ2 QKYAb/8{ ZpŪ7K0_ω,D6MhS>4T?[jrfV+9m*{w +<#J?q(댬%fd/ߖ`5ƘMRnP]r >K6#sXӌGu}ӣN' z1C&@d=,pSɚ%U}k=Z]Tl)Gt;:(L4]St{H\=]ޚ\4fc y (WU}| bN?R$J|]w>AQ] Z(Gn20WmWQf@ zx.v,J(m6"v*!YB3܍l޽\df;EjbQkV0 +h7Hov:*V^(Hrﯸ?[@<]Ydp$UQ:vNfuEOW?~J?sk_zF>|\q7?Tj=ӮoJP !ltYvVZG]&n5rز؞w(7ovQw-} %=c}  RSMp'.ՅkGwK*=MjUY*C$W ;7!+ S6]m坛֔ιzȜ-_ |ѕU@<4[-oOsx?s|5ǧ"co{QBvx_`Ǚ:-y4z͏ݏ^~rOG0 O@RZH]aW`<޿ܑ'# +-q2>lCbp(C@:;”N`z?p"eVoHrhϧ"ރ`}ac.pAoBSsvhG"0+wWDv?lUrxuy>Z.j68<.Ǒ6(KG&ŸTgԸu"|FDOҀvC2.SH:̰;e3# ٟ-Vq@<|ho~289nHYg)I*f8PqB7&GyV]*$Li_uT gka,Gi 6Tv#@ӌζ*,Th[ze_Ȳ~p9#*9Qăr e[fT%2VHqF(g=t_#Fi>i| ]H\Um6^ia`#LtǙ k92CZ}v%ݭJʜo)<~e۲FZoe54CE !'#d㧦-f36fJOSJ>1x 5QYk>p\&”ZȽmAC $n ](L +G3WNH'p9$Vþj#agcc"{xT[<& +c kFe[+bYhWt/ySTX-܆{g8ZǙ9ig*#NeWL\k" W(8X J΍eV[]w$+Z)-QBNȫ3wpN:w">_*>'!ߒ)kf-5lʘPoԗ15rvkaN',CklcKJ+ltks|zumȔӒh'bBxy -1ny =\8reLCf;"ٶ8˭Gd8Gx*ۆjܢbe]6Ͷ0gqU_"7]~NkQ#`m<V^4#/aY65[i,8ZEj\mJͯZ=p[v+z[v2H#*-SVy&X!eibFgױ=I/yKkMEi|vU f{*ik,[D +Zg8!kjôv rY䰉6)<›0 d 6'\H Hk;m6eg!Gasn,u7i{h@xcG9\DI‰˸me '<?c9`.!2ٖ B=G۶rp+3S%p/!-.P]6+ZfJoJB;gc)& r4C-/ \.j(d.\s GЈ!nIdeۖ Z]|7u[vWSCA^66V=yHTaAVR0k]R8IVfTC,HvʅI4X8دWbwR50,Zw#{V)F}#?Ce͈T/vXiތL瓊2uD29AMX䳨P)UHa*GㆁNy(?5n \HBKLR z@JFz;2IԻ[v#L&"јē +߱q=Pz+HOe~;hr/ RX,@&c&mכ@NKwCZn ZZ9eϐ cIRi[4=G1-CRv*nMaTxйH!EE]^idt "LrϤⓦ9҉12gf!|{[MWsF3"yFW1(QOLMYEZ>Z }-mg-s)cʮ%y:vTevǖt#6h2}ؤ2LuAoh D-ٞB׌ٹT?{dM[n^R=y@G}2b ztiiyDSX~[ܠ흣}twzD! q6 Pz_Ep '򇩠C BxTMS\AEYE4,>rhh7\5I[.QNRpl!{6'O2!6=) 7Դd/d)\HW ,^)3gKoxLcӻ0x/aF_|EIY TY[NF߈w6~~;o־Z+{qRWg I>)w4:+>+xNv;v^!"U J\nU# υTs֤GCAݳ"36[V? 0.^Eo XE &`phAPhߨsr֯zXDi'n2G^]%sVyDnd#{fs!ȦÉl;_ rPwd YJ.ꂇOz3F;{8h' ՔOC^gsЧi :bfu<+EQ;y0U s)ȫ(DQ1S$GA/, 5D%5IH[xN= Lx9clʒւ]Y_%iԿw;K]{n<=n'ӡ2 O ,=% Zp6rpU"?/y^!}#Wo8T +e59 !LOڤBRz1onmկ5NWNQD 1w[6mCK}Di6: /M-C8:;x;8 MQ)I 78%zQ7+")@^/&zt0ҸZ@-P9<*6ؕqb@r>Vj:Fl[HҪ#̆nD*"H/?!U8O7oĎN"&K-[6yo-_dMrgDŽiK( ዐ`>|QVrs!N۶kcC.=PHܖGŊv/BWHjD`ɣ^1[q6఍ĉvDE9kvL]y9ˋly&X"$]Zoj2_ƴ"!.3N4=I#Bj )JKw~d0MVk'>WXlYXp_ ]@~KRYˏ/IJks--ׄ1d,zXNe-Ra?HYݲXl坙]7Bz]oDI@THUJ) +i*8R>_Cz MflQ{Y2HbE eHHB*=:!Wjvs|9"䠻s"#.)B{o&ɉV<" +҆D굝%Wd(zl웞E`*m60Mo#ްlڮkt5#p7 ߝ򤥤1XhhZRG2bΰʡjN{XDǝ=u*KBӿ;%,mi05Y`˱.-6l63ݰ F7l +dp!YTq! NW"`()8Ahy e'H8Zݗ(%Udm|4߰2-G%VJpPm=Qme_WNhM^F +{~ `7pdio ȮzF +=`+GW$8zc$7q?Qv +@i(&gX pLԜ#"aݳ,+خKZ6* +O'I? JFwQ?LAR(ZfjmΪOkޖj%~|~!<=;F$DADa!dg#nE׈!@1Ci&l_@@:g(4Re%:G/ )J/JU(9 *I:ycXu{MF9˞*pXOO}[{>fcl {E7n/ )݅ tsFGlUDKB8h;YLJ%2q~Jed)#YVͮFI7԰0K*Od=i(^q ޳5 GHnxdqjVwK0~n]gȨ(,mD=7԰0Mj:7#Ξu ʯ:47- ?_Dy԰68 s C /#I~C {%H}b:L Fv ͡"1%pNVQ JՐSb(`_! d?!~ڹ;21y# cWSr*vn&ؠ(j遲~)f7;GހX"l_]9~~B׳]jyHGfGx"lJm]g=?v[eY>sSk(K՜(c!CAy%*#o@bKPZj=W(qegֶP޳0"/Xv_ ++A#qd?yt#)0pƴ`xr0IM>:hfyA\EK ؼfL. b7W +{~9Жݙ_;+IV[`i=4kX(>B5D],M>F ۗ& GR +*39+.0+YYZㅰNU#5q[5t +\]KAps! 8 +-Vpa! +Gl(0Y3nHTxj2nϓ$̺$kWƝb~g(NDkj.!Td/E^ k/cmC9<Idmht\3fP8uڪ$_dNzߧEL+UeɩEX-bU/brmPx93é)Ȝw<"և#ޑ=}vSD^6؎$kӧیqr.뗮̐ ȣ;Yy pe>k0 [?!鱒vLg0ZbF=8k/U$@¾2O͡ЍV͑DE2lJ*DC8|Uy~.- p1qrld7EF7=^bcgO;kÌB8lezwCO- CZf)X0GZ cC~3lI=fqbbdǹv[v\D< W[uFߋb, ʊ}9;J`2ICm6B..K/1NL-tӇ yVaԿU"γUY-OùZoDm?K\JiּϨPlDd`j!E3ѱbX󝆾^a^_xj[`jj *cFVY6^m xNy!JܦQɍeIǟ?lL endstream endobj 197 0 obj <>stream +HW;% ggcQN^ x0࠯ {%UQMĘ`G%I㷖OLPmw~o)I8ɷ]E#O@dLS)ɗ[31gkIy*X3J1Q:êdl>d( $ɦG|\~] lcRƳLyO09´&p4r [}eam% gZGu,50 +^mstbZ; <j3 +c$o{ yE<)񵚟H`a%?ǴEmx\4fgy~'t*mtfAeGAa,Z3]Gݛ$ĩ:4"OD)H):k +BΎjkQ8pͫlszt~Cأb8/9mVo;NˉTGU!K]{rQ!cqFw)ʀi*OLFniipS49,~[!O@RC.XdjW;Uؿ2UάB,aySҀ(F{=' 5s!bgdDj%*\՗(l_@-OTJdLV\aJT(E2x 0Yn\jdw_9f5M\nTrזC$nV~y 0`[1zCjX%&s;TJ߫[7pnɳPٜ:[)곈XN>[g&eUO]"B*U+*ĊR^*j)2`gSZVlI-",$18>_J*4_K/d f$WWp ZNyF;$ɥGUlߜdGHA54. ~8}9S#L>jf8-US# }W'u]^+j]l:`N;U?녰;TÂ/(ٺKRML u)bX}56%& yT8%vsٕ8 "Ys"I| B/8X ,-o'+zX +G-|S5N"N{ڬK936D!Kwi 3#d8zJ~0]+ <8q]۷J ;taw}ŕbųZgY5g xlDU^1㨌pc7V8;oH-.Ux6S}Br0Lb ;G8lI*~aVBΜS9wr?p& 0l[| o5 +<)g}f=q1n&"v6"I-5fAv;!,:#e_y<1-W +[_1*exy2đ,PT 3{pTOpT5s4!(P_t>lj7C&WEGS+ʭxp=58ֳ9ؿz/"xpX<C@AXcӯxP @ JX\[vrh vmVs[\- t@yi _@nRn6下:16Bp)rR:l'gkU-mӹo&n;,03jgk!ȤVf]|ө/4[q-fEjk%e5{Vzj.A$u4U8"+{U_plCn !d;6/1KdD IRpf*ӕb{X ,]>S%ٰjh RlkW7Fl?b',չFPGE˼}]B-W_ |õ5~ي+W\y|ԩ(䈐Y G:cc}u{%6lvc88Jcmo[ޒ(jcZ%pfe0f~ &uc7&C [V̢UpUm'N5gp# 0ʰ8 kd"2Mj:}UFbXIO9da$V'mFܚ3} 4[#`C`|De'G>sУTC8ﶅ9r8/""'JpDFO>ǹXfy" !N+7 $J#K(6 'u#`i}Bb8$Lj`ܘs,Z +3x.tTu9<$J3;\&X+3zj̮ZD85~)ОW,aS^,"hXSY~ )z9B +-h+,p"m +[ʾYVZ9.e.]enex8(n\F#b',<[L +^JZ*R:;&C@QoJO!Nx벃Y#ODqP`)ǔ{>mP9?՘)HD+mڢioUp"Ͽ?cRi(kf]cTA(K̺~ P,*]5{gVCq7~{UGm3 y_j4Imҍv"wf2oq*$' TZ'GQ*!f.$;>CP[|,izXja]c,y,r,6“09Y^8jjQ?+l$䃀a(.X@gRx{Nѣ.o O He{%T<}pA +*+:Xk8TX.T"NmWfV+,ʰBZel($<\gYolE~tK$) Ds:Aύf}!zVeJ<@H.g`(>qp83XEU]*>a>)v PQg61x潃>IZ3NSvᲠ,fԓ.Y[=e(w!PknT)wV/BY4='{/BsL]ǤFNiNڲqHzrN"g-W|#rJi뀣4Rr֐Y7+~x0I}ab ! +qFصh5AGMkN ;ƈ!FFh}(μto*8+b/`)@\ij\dv/baGx4NKw<=:s!3ELi9kQR,նD${Mv @xčcpm}j, 5I 844-9Źgf|*i^jM+|d +|.dxF8LNqx J:m7i +ץG7ChKvšq5|.5]ߔBwAPk.S*Y(HU<4(󩕻|.$NLMHvc\3t"l Vh5ݱ o*Sɚ-ڥgsp.jXJ5Tm[u󺺶Qr}.=!1RF- +ӿHdg.&lׁ۩]s?reB3!.y2 t.E<35\l2l08 \Hpup + ȪO1 a򆰯x>-^(}~^@.G!2bz9MF @-(\j GF.@O֮VoތQxDP_Bl4sy5Ml#&'ID-5q ie6p: ,We#)"MHmXz<Es隧YB摇b) $yeV0iAz|#p3~)!9|a!dY)$E1en:#T=Ձ͑z#4g'YI81zY5ٓ +V;A#lʪV/V:Bqȣ=*ҫtVᾔf]7^oiõ?B*FI +*˨j8Z3><"fmÖO C`ZmWj55qxD#'&sE7;2#scy1,!"2"W!WR(fGDSqxs#]p23FCor2{(j]4 4*b{qp!Vȹ-TԭSTֶF=2vGfHfxLRȮGRl@Pvj$>bNbWZhk4R{cyښNZL<є }hHOΙk0V(8`"guc-.\_=cs5^CClRǵ%]< uMuw RCN4`l?ر*13G1mC20}Gd#u8{|k(n#8#55Ñ2\cqL:X ^4u4sR$`4xj=24{RmUB`DF;WMc!{΄q&}2;vb!Aךޱ^9rV/@1. +(p,㘧'L[u8'm5e tW;%7 >?ϳPMdyBSh ֊dK5>H"bŽ6lJKIX:ΒIrp W=V$R 돰ͱ:ׂ-:t]UĻ5uNeep !>wZ]9dh vA<7RPkbϪr"|f+e +{m[6 A) 4 c/83*%IpJ9M&p,7@(^$ݘs#,w!ESrhhm#P܏0+9 .e~8x0lg닰̕QϐaN}9s#Z6~0 T[O?"Vu۶'b[ݶd +O8C`RD¡]ؠ(lgSj[6ɍ jbl2{NpԚ/I<Aրؾ_:6H—yj*LS#/{gb:R $gA <^Ve@K:~9%U)"ª +.Zy.$6W-GԜ# TNW"}GtŞ]Ws{طd9M,2/' ^گISmeK?~3_f , o6!}ZF EcȷP/urY+Fa3*/8#ͧreeAmcz{F;|088 ?DDءBݞl=*"υ"6)Gr{RP= }_ XvW>9\HfnTAcplQ5Ez Wpq, w#"PSC,7-Հ0+.a;*M,҅)iaє-G&"‹11^*ftB9~,WI0~!; k"ZpGacvEg'q3]& e}BSxF෕ {' j+@O`E<Znۅ0"j*ٶ|)gyf/pMK!U +MBFɧI^L%ޞ^f΀6dxZ9훯S0$Mln:ӔCs ,<:~֟,hjk8b +g#2JerG?94 }bNྜw蹿B6R~"$7#MER6H.oΤHiSv7ZpDʫۑko0 h)Wm5kkx]ҴR#a .0.WRmzH'pe -?,"Iv݄߇n5nYnyw̅uEٖG("Plb)$gLk#"eҟ69AkD +lQn-Eyłt( !HLtDQ.$/*fxI-n#䌝Cg8Z e)"vGf>2ƫǩQD[T%c\hr`eRx;)i."'Kw~l+a:?'nݺEg~q4Zcc}ז""3 }3rf_"N?CAUmKi!1d"7N֒TOv~Ql?my3Ē5e\5"s!y70i!}QF,2օX@u?b2$b'ۧ.&p)F>GDV3 PsDN#Nl%-xcF\Tx xD3<,Ds"aU.nElSr!IҔh{35QjgX%vM pЗZEzvV\l5 pokzMZU/Ux{aNzRp>NC=O"2oeK;.9iIJճ'"u_s̫cyߢ[CN?_<ȗ/@Wm?_t-ER^1B9&Mn}!j k(1J ud9%-\꼸Mgj|;#BAM!VL}'Dy/ѪGu_3biB>i)'MϒϽRxZPSٌ۷.2Yt̥\Y+DBstI@b=BqKHW ƟkG:Jj{g>'rUklqFыs""bh kl_S|1TBsYwOש;}d!h "}bn4Dg6\ǥ9OĊ0 5!vM:Swrlx;>"lw sLec&ⰕA}U X\00Ad;#"FP[kͬ8ˮUu# ֛vAys}(Y`Fb6+k3" (Nah0<6ؚ8 n޷eĜ8~MФL'i8k@(ƨeҿ.ߏ a3I<ܕ4eX\LG@a0s`~՚SR˕Nў*%UKhL)ZIS6S|nn^Az쪜Sq8}Weޔ˖7(R nUfn-Jny#"L-Usc#"\gm]U;*^ C/3Mǚ9O-bM7!M^2f>8{5^c]-"p,=t0+q|ց1]Cc_gָ97KL}ȲL=υIUf&-s,>KPǐD.@ L$$oEAx|%vn=%wR+ xN}i^-2c~z(""lym6\efDf7M5=" p9D{rυ,AbS.77:eI2Mu%wߺoߍ|l8"QuO狀G_JY~HR6o%[:Sl_4ogVjg6_ޑ27µ\|PgsΓqvf@w"O -k{Ү>W_c8ݔp7򹑵t8*0 +ceTvc}r/zY!2z1jqw +)|udMU9 <\ΚZ$"dw%n B.Tل#6)S:4uf-tr-a-yõݻii{ۭBH=$={`Rٴ3{("uH}]1"Q =4LGc̄2=2YJcBҎrҾ"NRLuumψ6ˆ6MO692{ɴjiۻ X3=2৭汳c] 8ɋ!d7Wg^Hgu{]_!֞ ѐ"_8MqݐR1ŪvesϷitvSK?O3jk6(OkkwEZk?"%־خrdKnSZH-qA;z! M})nم_9"ЌLl+BXp7!eZظfGnjD +׭o[bㄋ!GiL#R?{ +rTGrpE +SYOR<[UWshSh^£d0lGN]GgO.Cc!"`ԌI鬔8lMgz]#NA:vj*"tL34 ռCY}8Wc++{j̈]&{D>#4;3 /̶=»p.2>r>kED@Qgά˓n8"RFfYxy8rrmZ/;QU6ξ#)Qv^SsNs#UL9DaRC<.W<0Bk16[sL fr; vPp\G07%4۸XFBg:p79쉕A 3 9oOJD1*R]v0{Eb<+a[ mXk⃐# V.{EN]3kE*bqYRR<0T@(Kh(oHQ!Bs<exC?eZ٣~X+%A]N9wS=n{>vyV.Q}6KDXKB\qLekCI[)l0uP22B7=``xWl0;+93*w;Q!^_ktDZF #,JPƍbhpھF!tNI~!џs5:;F#:SZ`ViZ߿v\[C*e,-Qfe<"QYe3YۘGDA(O6](X*%Hj+uD_F{V]&*9#"ϖFD ς2|yNF7ٞ'(*3S?F##"K=n1+@L.;k7eA 6zz@oFYQ~BP7&blͮ(:F~e(laxt8G@ȡKgxoٝE*pd7EVg,tFH n >1f쩇" O@Fyw1}hhBD :"BQfcd_KKX's4VhDi9k.&qZ  d_Kz?*#O`en\y|1; +#!OMYwЍx#2KzvnC*i;-^? Z7<ҘZ|E- KDH<,\۾v(*멧H?#؝ EhRሐUʒ*^y؃:Yux* ʑ%|_H= (4y8|*ꑏ9khzU㍀5O47ANU8f[s)Fl'kG' :ٞ-S@ꯧ>r`B?ʥJq\xbU#B}k⌯n{s HčH'hwrFC mE=e`uu*;"JapME܏IU\M9.ZQ$<j,愄9h{o5ѱIiR{[}f8Iʣ #~}AtflPD'4Qޒψ÷g*/fրsDGЬ*sTFmnD7\H&)hԏxR?aXZ=i4KV \[+!DrоeNk,jEB)ug&è(QȃD=s{)ٱ40>%H٫+`=h 6=MA?Bod F_Q6Z7"C52XMTؗ;[1V1`‐ +L^Ͷ)_)'"^+Ń/Ë K|BIv0 ͖4OM@7{یTj^00?9hC;RyQVr@uB 9 x5ҿ%jCgNAZsЗ,'Y-|C_.."fȹe|ĆŶmo".\tV7]õh7P +9]g&]"B5o.H_M-qo*A˿ 4 endstream endobj 198 0 obj <>stream +HtW=%' c@ Dġ#`=OLS%Z B?%!9!/M>d"9u m: v)M_?>pQ#d ؽ8~أn\Ϗ KM)R{:IgVkkm?~nd,eמkǁQ)DZo/}VM3VKKѿ_l9տ iv2뀕ƊzDgC@XfcS3Q*V!'J&GD!Α:SXҳؗYt۠(f3^d,%("\uj(?{oF @=z~G*eqLRg#B +}R`;Excs÷$ yo E)C(ƒta@@Q<#>l*JPbɅiD:rlELQ&K |2.h5%$5"ijŵQަk\?\~Q<\z"۩x+ݐ7oD YGpBwAD qaPaW͗٘[DwޞO 6`sPϞ)iWcJGe8G@apHΈE[ 6f!ED@`DFɠJ[e8DqF"۲kt9"j\ueBm㰥7rD +H̜-sRK;yڙ̈d#T,1#TF}Si-i٭Sp pκ!zD!.=='rd +So +񍀬G:k@Kf-( +08R#+Ӯ,"m4.ך{+ 3#]6GLWEUa79*El@暫l +%GN/3s u2g^-GH M=>6)$MH~D|p|qa/ID0o2 __4ϺoN}>ↃeN' tۛn g漟p_@Vv +ಗO{-ةÿR(~h q뼤t|%嶧X#BbA1fNt"K[7f7Pqd-"rDa]὇ :j$g O~g ;?mVKklg~57[+ߺ3%􉐢 B>O) +4Yͩ\ +mdRDrHelmpDؤ3_#7s8 tNTa%w]vRD:^ H;ˆ2R9}!o3 +9oSh뮘/ hj]u/ݶ, vkU.<aMg.k<`$m|Ȫ_%"׉d~1vKM9Nˆ3l/',~ixW],9svҝGFyW6s﷣=sD +Q,5 ElBI6=|ʗYX3`_ |z(kN:pDQ(inb\!Wis?j:ޤD2C&&c0ʩ Y +op(|Vc@@{=k@P5'qy9-F#5f 7A%`9(KisD:7myZ`5&3ʁBg61#TGDjc?" hjǙ]EU}6 zb^Ɗ9@ 2R'9L(v=U*HٷbE7PsupDmybwp'B0Q\OjO֦ҧVǾÛD̶Y!/l-"|0fFpPRsޅ}_)v)"~SliB%o+:EDX` f +{Ӵ=@N5|$0NhQN9\Om*vP &ǯJKJ0 G/b$X>$kU/t[G*A|4[_tai5R'zu1 qgcyfVj'P?v6WPS4vֹF ^ +.g%.g6&lp p]N y ހBZ2mꔼ8eAr_{Ӵ!HP!qpHݥ7"NȾƲQ5vc8*Wx?6FsDm@ģ[+۲N?r}ɎT_:|x2k{̨̊G1 LEijkGD +HٸqCoZy 9Йct\c2S,-$ۘ7vH cn$!ޣSliP}Ln +vD"@:^O1)p +s'PfC{/ZLHD7qMt}.-!ϑH\ɹ$Ł:wVyZ#"k3_ &`R՚=",HX 2Ӎt#tLNu|8∱WHX)sxeO]ˆ //Mg΋-0u,FcTϜeAƅٺlE3J2ǘ'/"ਬLӕfjA6pHq|˃ICm +±]Tw]vr?"^H.9.??~<RTpn~b\ ߭.yZ +y?b^C)9k8^ G8^GFIhͫ4 3e;VkP٢yod~ejemB3s/[ipdeHŁJ\ +G3sߓ4"_ln#_# o@A.9Fb^TdE&hp7;|0G a2 ]xӧyoDۤ,)_^/ !=o1B-DnP[u .JEQ_:/ ->jej"YmSRzP7ۑ^K|JIdwYΗn*F_=lz.~GWa#;_5awbcM9XҦͤ8-vr7"^Gޝeb"(&-`.9n\~(.$0[tZ׺b"Fqb)6p2cvI΀[#d +A?69CPgZ#Y]2)@ƾ7r(GCM9er*zpxd OghY N@_E'YLd83,Ƣ]wr@Xw]3i { rl.:ߛ_-"#17UDQ>|/Aȡl }dG喽V5/ +k-[Yx ˚h,An EqI0ͮ='z0Tؤh|aRڻoʽYS*"(D1%+gAI3EoN_ ^6V 4숰.ׯ51´7e+ֿ 7 +xe]Z'@7<>8?bj_2?1ՎZbM~jksn!s-d2=b[leAEޅ5<]; rDDg͞7xPD佐<#RZǏ>I?n«,u܇)cvvW8!۴?' ߿Ȼ4'Bdu,m! /_tUBD m)^mCq#DoJCt]\:sN9Euq#R:M/ Ay+/wia0zyј1!@ҕ>äfECMEsev(|GHa'F+̲7[fw e3$9u XvGRLD 71sSu>]9*KŊl}J+@_'ix +JhKǜ4t\iJv, g\gmBZNjXp\bq#O v9ѵ+!7B-!iN'FD A1N荐nx\}w-<*Ό¤63HIk{™Quv88jEdJ+tE_I^YT+=<%=y&5mdU]Zy94IGvFD#s8WqD)B +֩ ֏مn=9BqT)jr#٥"lBDk_% HV'}83)+߉9 +M h26G@ހj}'%+bO Β~f9ˎq.+UIޕ{PHfz JD*m2 zL~A{;".ܓ u0W":DϚcH7)T~/<_JY} S^kJrXe+BġmՖy»Ki1MWJl"LYj*?Q1^gZ.#̌X_wZn;Br,9iT_<׾ j2N+6}Gx״m{ N.eYg)O)M!L UԻ9i3„s\R:I(MziDD/Tz0+$35wʟ40eW{6oBI̶ymd8Gbn[=6 +v7{c]N/R,6 26faPkKhZOd!!{[.;=1:YlyDq[:g YoDŊ&.*jz8Z3Yac2oD-2gb6;h9d E:i@m6L\6G1"7+ʃS*(fFfLL,GVv9/x4_ᑟC)7jh0r W2JiAqu'訑:dJarPmh=N k3f})LE%޾bk8яeeQXtJ*ڿ 4^WX-.t25Y)M؃$qܟRVɱ>] +;_y4!bqn0x +|lQ#];lp8D)d}=6fǬ{6 +@9>؄"bȭ̙<%N]*!N#h'E6Vej/.SA8rXBb;Xr4겮|l"$v^0NV{fl$ǖ'ǎ\<8?ɥT_YL,fEa-6"C͉Olf߶;e ++GUC76fs3 t4ƣz̵x&OK˯~:f)o34W=,B6a1mC~gV ]6M-ejIfNBހ:~N7H@ FqZ_g +n76}tBQdCD8yx-Խڴ18'<E҂>nVg?~o *F΋|y!nO8N)bKcE]al\"" +cZ]= egzs!'["MɏR[X]zB|-.*Z4ӄ;}bܫA~%wo!5%i=6j88Zh:x۞R{q8}Bb2bCTvʩIPzQsMGQe޲3m借hq/؂,믪i}wy nx1yn֠M>QMwV[Gܯ{JpMoY@W2w\Ӹ!0 F$+iI}E#e8a0*Jx&~hG]Bys@噯[Eă*bS3 ۠'jۓ->9<* zG(0dgsc^) +n"L4uҟŭ$e7m2hB3a]VF8ti"Jw6 +m5M('IP"&N9- 'z3&(<A=i} e Npg7mxC,XݶmZğ C&6vg7BղPXYn#]Kv:He,M/5lK?6Ǜ鑩OkBaG CHsL"|0b!]#Q[(<"RLE:vUzD-3k8Dz^l8<"Q^5Q_Md wQU_ô:CD84i/~/_whȮ#$v+#CSV)t B6nz="|_OX,"^N8@Jhz% +H|q*;D1CI@EGl C ZuPr۾t8{1?^!T +#pHښ:YdM_Zb91{@Y3ۖ8E#3rf~P].9`]Vw{K]H0u>< +EXcFf5A.V6!:X2Y yO5;oD ",8yb%M#w5*tr~|6-QQV+D)Ckg8y `*6%t2/K NږHlcGxĊyfv60c!cΤMcn\%VFjZ $--ٸ߸¹{᭭w{둲JZ_Gͣo[y׸ɹDjqxvʷ1-qSȖŠUFi# F>2U[AW]^ iO3qۼ3lWkukCʘ㥦}(( +_cʹ?*~qz^URSV}mqxDGP{`/LEKp")ˉLVuv(<"Nm6QY};nV`8uecfʲuӭ!J: 0 \'2g FGNvo"B*,ȶg7CȌ|sg'5sO*!$8÷l7iR$pyE(𡎘dmJΘhǥzQƫzCg=TG}oHǦB$v}SyѲwW/em{]5Ӳe$-]wg[bH۬&5L/@5O. _- +#vڙmw&q h>:~%B1)MDV$tΔi*v6YUB^˺>75& ta3 ~W=9Q 6 +_]vNo(.%ؕYe|"{F9pǤ9\fA6׊G>bgzȽSC:QnͅrCq uuզ-5ϽXq~#p^Hk8*_?oD(g9Ez0x$4bIm7B{*ߏAqq\n{8ڀzvX- B4eἱ9vʿ}K7n8B*cKe'jb+f+#LdA0<"d1`Jfo/llS Yt^8EeiPM C@s6{h3|$$$|B8M +ŷN5C>Y)5 A#"gB3פ ;jvl 5h~/B¦ވ8rSu8w(`8JFW-K[zD@#(֒ʩVnn.l-v-KX}x*X\;- ޒ-#ܽ!GأUGD]TfX=ݎ) +0#܌#ů[xD#7t{ٱ/<sqw|]T|TՎlПxc^x|Něѥ aWVrdb]yTy (jX-Udi6NBZo= " +GmMc#feK[nDa!ֿAìEbZT_ +&@ǦKʗ=)sfpr!x<_HrubJ4q9r7eΰpn1{{]{,sYpxDyڤGJ b[ʥߍ֞ɦ@yD{D 1|,6;"nUs‚J^dһtsi ^R;$L 05N*l88.62<ۮ!H|!Бℕɞ WuvUnE>.b4ItM<""+Sv&"R# t}(q-Y֠kTq9+LpIH&/αN23>#-oDu̫ʶKGaG22mʺR' ͯ=jmDL%oiM6%G`kA gEx.|rWkvxͼn!]\tyb:/߭ v9p-l|8P>Zg]N9!:S-rsqrEѦ;]G>n{yb6Hk(tqKmi3`!҉bCmAO 6{4{+›ΰJ{RmM3}ګ}LY_v4>FJOS4? '׉h') !ALUHV_ۗ:Jt3tkJ&Mhhrz}:aO yo%. C(?NuƲ\tu ~NIğ'eC&OX^LRFM =촆4y& H2"`^~>hp iu>nI8K=])Myn=>'? r@7τۏlX;*/Sa[wq*kM3ʾK 9N%#dDC|tC޿"NpQt7Űm_ټp&vSntseOD%̑[i zN0BTJ'aQIY[։9Ktwv2qv8* )l3ɛ=S{ƴ.<:=iKDJZ/$ʦ^>1ZL&fɒ ǃ Ưs ̈́;::[j͆Espݺd}O!k3+mMD%vx_n ~;@ssUy7dpQm3>nVey`J/_0Z5؄[,L >.UFd;N}9SKVK +}bm+ŗpcߋA9B6{e33{ybD>3G20X?F+8h{1sWn MT| }&R;6 {k B@6灬?ašk ܶJ6E|P uE_GM/\x dkngҎJ4b_nޜY|ؿߐQoH2QnΫuʇS=[ ~y^81[CԂ 迈|jA!<Όec&YŜ8p>:1τ۫l7Fl<n77kuvQ3pq`M\X_+%~w6s\Ĺu:̶AXz ^ *h/#p q4=T,V/OSAlri5V?֣֛9V\>J5^뼋ވO&MH0W~&օݱG + !ǂ^Unћ8n>LO:<{6_Є?@2d%8=i2O'ɄEpB}umŁ}#U+(Wp<#•hƴQlm&ǜ!je#$ y=I.33@˨2Ʉ#ܦkoT^džme %6/])[e]xHpRB0-f6Xa!T +{*X =_c?=LbW@GUТ\s,.Dp7KE~/#b:ap޵.1hl +,'F,XPgTAs!޹0PZDj% $J?礞JP;"=BR#+_gz%I}{O@+/k$% F=&<;Z# dw7l=K ߄ۏfSþS.7*ݺWvi%՝i>3M(? 3^ֻϷϷˇM{qUW3V9DT|C_BCodeiznBt`P\Uy(|)ZA)]C&>j*UJB-n]ǥ[m*GtwV)8/L\clDtO0z@iTFh1P?@"at*5AVGoLw&P +DGԿ{Z4 +Q|d6.>ˮgNg\zp0:<)pRtMk&! Lx9\y-Xs2.my*uM>ző]W(5Zi">If +™3\эroB"z4aD!k߉0<*xDe]2Xa߳Dw@a< ڣ!x3*\h(eqo'Ziacӈ&0 Wb޸$F&QJl%mt^A pA_ Fk.qj`߰τ7\$!HtW=6 s=A>K( 6f=2`^-o!?O vņ3aO¬}ϽE0Vb#f덕ژ wz|%_OmWx ?Ĺ[BD"=3]_ n!^tvi'llFϳY,=n¤WTn,;EPeoQ}wo~7*f7#:Xv=4^Z%+.iyg*4&W[QK7x5y V>Fsۍb/_O%Nߟ׬-C(8 P%:㈻НxxvG\*.kc2J~9_lzí tiOy%B>Bϔ*\C}" ْ㺳j4.?b; c6ut=u7N&(ϛ-z^kKVQV֥7q tdINߕiQEz{MuNJ s0KbU+ϯD\H &FF[ șnXpUx:?9TrA'wÅ<퐦3 /lҐF'ju1W7DnM_+kHƻBsh3[@"A3x;[?srasg/ QVCv{Gm`+fҸfu9a+\p.@ .'}zr=ά*[ȿ )|aALl;nF?{# +r ~fV~/b~[t.L͓|C"ti%%\OziL\DT4K>ח|3/NJ+}^}` + +n@_Y9 8-X4-4 N57 +L}!>q? O俉eą?wi9:+̡(d{cѮbP*ŲHlx- 2'(X5=u7kEJ|.ag_99~6 篼C͕9ƥ{(]cr?%4D/]B%6gt ̪q ɤ +dz*|,zFFmOħ׊v&%do0 ;qEw ͰS F+%;̝atyz%B\f;}JL793xjħΧ8NW+}\'O/8Ml/8Ǘw×z=O"9Z>nLQb>ys=${5 eľnY|Q_2ld@"|dtăC +cLB ~+gZ=G\6J~0bsUh"ħ +_-eI Y3+=#98;P\-QvِDmfCCbZ_%P|1|M]( +ᒬ@@,6\N nOŽA]6D1X oDžnpW)wo;w>$/3SC&OM聜m鹲?~ӂEwVmKh&W'`zS~r9~ws# spmY~yS)9 +\BzO"r`31vqɆwo,o" =^ϯħuN2|B+}Nڸl<yW}&Ùe~7W"pCk+~խs2}Cp(G&z8Wn6F+0i$t|8Gg$*=C?I(3~L=Wp$rKC +8|9gRs;$WiQd.gnMujcμ*tU-Q[ d0/jt؂lR^1`-[\q/@fW0;LCbڼ'HLNHDo2o*DuXHN+M]PX$- `_G>Ķ=bW\CN>VM~:̰n:V&䕀qZ+aW"F}{?!nCoR^pΎseSM/=\^D~NN"Na82*Nb}/L,݅E?{08*?ܟ•0[d^9e~pNx"czpZHF7l4u&LB|* "5X87-M@O g\&!okt_%Bf.yGV푱+{3>+"|\Mv-m't/sivQ:y^PA\:ٟܶ|E"l|_ "9?Gh y%BߌdIBS &Tp,/,ĹQĥsH48ߚCeI> =|wsq܄סgPחx .٧pgJ:Ξ5vTE8o'3`$.Q%HK}yeJyKTxMܜ`D 錃]Xukc92!}weOܽxwH(S2*+!H̥.߅|?0#x@S\Fm!PI (mdL®DHHІhjl+".W67s!~AJdHaK&w nl;"2LAo‰ts< z&9=:$Gs)ð6Q(hdX2S>7Ү>n]} ڑ6arFI`mqmt g&mӞYQl['y\,w1E .OE! #7eǪ,YÍQ-SGdqTU`0jjv2U4(ѩ"2PQF0 Z\yPGd#wsr endstream endobj 199 0 obj <>stream +HlW; }HN:6豱`IUG ,kZQd!;}z}m۶u &k{|}"()okgJv[WrDCdg*>"Js4b(m-NZqlpD8*jلr$|tx߀tjQa @jf C@|_Yfe. 7B +#YxqٽgD@+Ц~ +L 6#&A%m3jPĶ2W9 + ^\8ƴBz^\ff}rh8SO[r'2"P%Ba/al[ZPرBB˸ÉLk#m@@=AS2"gDa ^,za]!ّT67N 1A-XgljjG8vY ~7a{olh=Aac3_ ,W0JJN]|w?_88g)A?_xϯ<,UgT T$v)<5{_]J z_ wP0;%2B +deGBѝ# (~?}A5*NP39R?|OO(f9%Gނx]~( |b/lDvqO[Yتl0]<m(B?S%GD^6ZhUo7:ނ)+>rT2vydO1ٰF=<` C3$6h:tbv.nN[f"yB`WU@Yf| 9Y,+ؼD\4Vo%\y,-ጩP\"${QGz ZX[>zZDX iTJMvsbs"q? +]bI1J_"_wۮm6o=;C@vJ bm8*{9oΕۏC.%pcHD}#\)e~#T^V@XP2tIF0Sބ%۹ɃB9 CFH76rm{Ornwi _n~#o F=֍zlnt#"{S,dZ{ +_@#Pp ͅF7r)_v0|f 98P'% LJv|ruF/yU%GD/ ʞOUF?Y3X=K=%$",aN)r' ]S߼G0ܷb7s K o|qFQ/2ov}Zj(6Iv*^x6%LX(F470YRq Ow:ŴQ: IFTjq!%u%?mwz((Q lG|+O5@!xS+dMl3un +h38S {ur!~1R\rxךrGZ7z|1БZe05`ǩgmy3ZNÛ-Tu{ +״4ml~a<st҈`M ?]΢3D[ۊ]:dd{-^ +H}- "=H>/7y@ z Ơ&;A81'k4wO6[{ND {RxMDb]4d`N~>Gc&>+Pf֒V{q|Ŏ| +qUˢ65]wy)5z7RYֵ3a>9 # gl{m=c3(iC:)9"W63i4턯fV͍cȗY܋#`{96kR W[|eX '[Uˈu_G-Y?o*t{=yѕ,7m@Oϙ"}G>er0Qw|JV +*D +BNrx0G] +kO]E'pwH@5ܤ]ֶw@@yj<@O==tSDIꧣ,mK*K!5̧>#.CHy7G7&l٫0q+@읝^$<џOk/uWv5e{!,Pי<WHP5"! J +nNimWyo>V(8 b>WBLAP.Vi:. }:OLjvc; yrpjFW/!I\$ L4k@⧝˾B8饄3.Տm< |2b߷9*~z/D\ƭr!RpXm\^-I pߧ *ǛYr#f6A_ +AѶc45:lɩzp^Z(oYR3 +b[8,"3cE}hIz7w4 ⧌_=3`7")׀cK"`@x*@Fq.&V $OPJ,ͥcG^+LQ@o⸻EQcpDZ:@OdQSrcc(IGBC*8p8 +FDW4JP lBVpPV`Y:pJu$vJ 6#k- ~amW` ~pK!YVg+^ƊצWNӫ!PB5U2K>y-$v}&ML3`(PJZv8$gaCer8tN!8t$1KipԵgp"Ba; +Ե?݈Pd}T,4ٮaᨪ+|p|pt}(w8," +TC<1OZ,"3ʉUCSE^&&JNN28BX,p +LB| +P j"p4,%7մ#<Io2ƢrN$7 rF4qԊXB)twX` gBĜkiX^7v@^5Mr(%PTD#7;AUmN^q੤ߴTgk"hΥl Ha b +-cDE^QA j5jp@`*kڑ\]iKOR i"FI4uwp2=Ur7M9m86P ̃ ;椝&Kp6RB_MmXqB &>$vClگe.]n.rE5\y=ϘCrk0 # l%08Įj(U)1i@6$pOfq,4P + R4³^ &4XJrJIVu*tIsceꥶ "Eh5m Eb`Zlh F#$j])gEO-MccQbUqm{8Ӧdc}ܵ/"zFebJ>OpQ;m%LE:^Dt~'Ic扰(LF 06f?'3FZ(,Gyi`nV>v9y_ZXB+H}É2 G67\pT(I_qēSD-F4dܒ^e~»8C9NjN9!!F ا\H; 9kGL۱(܃ěyoj1x[_~9Yv喧A !#WkZn5~G]sv{vgI2UYXڋ$36#i6sL k_[7*}KwY)WgC*=ń %,- \ƾC.(ʟ)H^ȹ +[f!4=OEX3%Yݎ!礆e4Hj (FnmCb~TF,1$R`J`;vt-pN Epv\enFuR%h!,Ǎ=`k} ?amv@|YVBJ$+egphemٟR~qXݙ`t_S[d+4U[#cM,VRvVVBF["$J +ʲLQ3-&#Fʜ4_8ID" $#>}3Wb&6oO7+<V \mFח])l5kb֒\Ai5\m%iQr0[D#^Og\p; T9g]{:\=X Kmv4x5F{6E,_Kz#> <ܗ|c#BtT E %A=={I +$zc ?ANPpqz9fS]sr,ZWhi= 2Yۄ^Y9#'"a_=7Զf)(e#BgtliӵՏ&45wTߵfQy.*0a݄Xu*)^b&J=Z6x:&S'4] 7׊zڍ7c9ƪv$ّu ͘ӷۋ ք+ӻi .ؚpG)yTdǰ"|M@S4f`2SMQv +n{ XCYR~`nDIރ\ǿxq`3EFF$ {F,$9ֱǢ\փ4~RԛxUҙ +#'p~{\iR4 T AV9) +ZļIq?Қhr\׊Xe=|1Hss療ԼxvhMS &Bjh]Qu9YRSѦt9r-0׊by>H0!9ji**+436_΅MbfN95 Еcþnl}b"No@#bbMϵ x.%>G+ 68+%7kXl2BU+eBzhRBcEi K}Zi +.jr7 E8(.2IUKQtHܫr@VE_R*~89a '_&Ed+GtߥM`0%V3Jx*FOBg+,Qs]!Cp}&ptqܼۼ%&Kejk*Q6Yv7k՞0kToi3XȟBk!P%spn:0ky3x(ݜ/v[VݓjT`ylU~d~R%$` {Zbd]MpאJ\=F&٠ԡw γ.@ wAq^Sx/q<*BR C(&Qx\y{o hM) bJ[rw +PARHh1I(oy= QTPk}4b HA1eQ~U␏̹ƻ.K [얫'QBTMN@E4OwaT%pOޡD_$_!uTv;s-C&FNva/ +h]ۭV7lJRZ&0 ~و +K0=;~_rh,fPA"Y82`9h;JMrt+Uw ʹ^%i:jmLM1@<`RKqk&M;Ft]wLVbzo7|0Ō3nW2!~?6v"OYyq6/&!\-qv@/ 9 +DXPX@W +>Dv \:@D%5>9B6ڪE/kC=ϐ,"'uFB go&( ʟPP!烤)V)iq! ɞkJ6>we6<ÃOBQ1-KR|U)- %KSR\-5VeXhɨ _s[ŞȾ*|-./?x* Q^9ߡ:X[ iB7胶"=W AL85  u߭Q5 Ym1.:~n*i$^\.gRz(u*@F`@خ)?َ53TD[YW9#}.v9P,U= Pk" ;oȸOiơf0U.y?N9vP~sRpU)C잱snG._$>zd_MQ30e/䢛(EN?uG˔#8d顛Hvy[xEp(uUԪ.ZȂy(H| +heY=7K:!2 ` h9·WXRb>%C+ Iyš~yS PdK~;22CL,=aPXHC=!02Z-^6;J}gϕ*lƊ  9FVR(8|^n2~.+^nctb(w~#p"m4R7qk!M hwZ5( +$"ŀS#XEQSTՊZ:踯jC`!ϻR;bH1y/x5dEyDߵ[UH?xgrlF7/Hd2{ZA7.~☐3ԉ Q Pp\ qwנ{.>v0^)p2IAZQ8hȣ +J_d)s4e:W=56/ҹ"J @|3^&¢"7T9 +[% ]g!(0ͦ%ش*Tlʊo;o?T6PDz抷J%/S(\.~qnšm*ޱ|Yw*R|OCrIa ewPCdAR_yT +L؂KNTI +}(u*oM4$Ð8#&H}Z22UVMF +d_wWm)x41y5ܺMOX dv+4T݁ѽml`[k0a2S6}_qлKc+>'r^cb?6Ki1Hܶחb/}fۜj/#ngVЪ&ʚqEZe %P\ŽbC&7r< ' iȚd9xuֵ=&O~\w +0b<"_uw~瓃mI/7691|}_91VWDE0B(@,6Zȡ2G +M 'f0^/vs-D {R@bΌ\(غS{!.ɡuC"}maPIdGr xӋoIJ*GN1B60Ήnt+ 9;UC.{h6NM~f +R]JC +?+KFG#9a'z1a)2fٝF̿Bѳ]n +m0]y4xD7٠S\F9V Qt OVlo; +Rvzփ +l vch +L_1\h/g⛉*M>/=P-%7^GZͯګ puWcu5'aw\qL2:ţבX`Džb]iUt}vI@ROEEb,ͽW)bq=1,#d04A#+ja{w+g|+iA[ @V)' +gVd=4YQCl!T@v@AB +)Ҥ:P#-)"H'QYYdxyE+NX&)~WQ^3U*J7UϺjxS `)8ȑ*Gښ9Г?wO01tyNcm)Zb}ADYػLhd IRx42"̻ *:ԗ"\uPY{sZUw젉`O +sA<9ʩy /0zP\ FfsZ!%L xgPQH`6B, ,^:HA(V\6Օ BE{yX IkƬ2q0h/Cx5 +% +c9W2:T́ALdERja'QcoEA|xAO܊=UnQ Ze%c?tUH 7W7KFG +f9ić-Eez0hv|"t09KyoO;ef˷i=`.I!xJY!~sLMv;͵k\oʁ!w-DL%Sϑצ \DJVcom[nn2󾅻Q2`: Aw&<-4=VӃ'+ N#tR4u'2yi?Smw +YEWEQc pV^Ly i!)8yRUh>/e]Yո`Z8{khìDsuPƽOПf|S-DVpF"r)(՘Le0Db(Zx_S"ql׹MAOx p*#eGֵ뢿 +N#֊DA( nA + ќF(4h. += eR(D]p"`u(3~<%Dfq9}dZKKDֹ y|Ruw$ٷYd* oH[^T 5ı 󎜃 5wCgZ5n<~Nj{ۻPOni}##ΨOPnLs̃a4H1-kNAC@Z|oJbatuNL\#MŊlg]|u4_W,ƴ4[TҌbrc#ܢ_Pm}ٗ RI#eL1qiU +$NjI\D mC @ru2j*p-@!7uC?Xu Ys f(RZxxg-Šnn06vػM㯋C1NI*8%bJdVaSJδLP R)*Kd֊O="[+G$%!1pjT稭pM_Gc&qmnr:-Nayp*arQ@~},E.xG)n⼍<7,rMqa3fZa'2PM}o5sus8""Q*`3~ +g0DMq!N7.00}c~޽13!4db$ flWm}",HǠ,ekaH>ֻ֡x03B[$#x" c_ ?$ArKsE墌'hUzVؚ@^%I t_ 2 [ɀU%/$B3|g;~&ΠkuMhɕN FROC]& Vb[dzkx/Z|aK'~!`&2t%jxKh-e׮1D1ˣZJ$E"c (eDl3ҧNt%Tx+$?, @q+#řZ#ũ-ɚY]^堬&>C'$ ̴eXZA Rrvx͂R)HbM1X4kjlQS'%GwBRTiCaǐԖa*B~fRYMHW]$@_@AkߖSe7Z>stream +HW9$ yWȔ3FpJb}ϘCq6.Fl"98>[@C?_b 5C3_ d<'4W>1o٧"j )b JQmg0.U'l}. 3xb8CI:Z!) 2P ]` rP1(VP_OQD tL,SX?`-BOQt)d>Ryg@GLQg)5$A E%P=4kOMy,QUq]` g)Kk'Ipjwr)]@_rp% ]]L( +J~JUhͿS & Wk򙫟_צּZ6.h-7Z,]Yp_Ry%NHMG8gL5($5p,45J<[MJO ~HMCj9w/鯇A]Q)cakWթI 폻; 7 oQ^{ PNh1<8$w!S$x,C{f3(6Ƶݞܞdx"hΡZ~8Z+7Z/_O3q{BV 1`G 8rl9Ե^?z?wn{sߦ|dp=PRR3j,-F^Oa3롲 bG6Pao޳]ݴ1 @6۬)h6tAYM**sdѳ4("&zw,jiXFS(֕C$e +VQܓq fvdPZbx`NFE`! .{Fk6~@uNL +`9U"|:B'˃T;ɺؼ A{sq@*eӈ<;J|qЫR%m=s[/L%*RpFm+"3!F'YQE[z5[~,ƅ)e&n^[M%6@u-*̄f<shۮ[n=j45Їu9O{s\ܦmCB._6_k߼3\pESګqgR %Kʐ>d⁢υŌ;/]9*JWorRr}YdH@2dx7FWRӗO ۇD_m:ǩ2Y{]3oN{sR%Rc?,=8!(o%|8_."/Z@Nb9^PS}VbD*#V=Q~o=á{a4eQu oL++XZZpXix"!kS3h-m&@"eQ 6V*@FQ%~ۻ/:Zb +7EFc + QHo.v5%}-: h@p >rR>\UgɅ\7mQ3xk!)Rɤ7-)K4iZb.G .rYqQȷQ[Qz4_S|]>M}}/@Hp!1Li~|Mn?~]ķMVVi~SzfrݼiXXߦ= +}#WߺjO=+F8J@qԶEZ|2kM9yoot! W!<- pXHM,mc5[@ Ђ죨GrϒD)I4H." ? =IȋGq IrɈ[1PHCޒj2+‹-TUj%ߺ.rpydOqΣ|mG`&H +$!0͛e1xb;b= PN_]rFsʔFQ:bp뱚l'K_eI^+=/׽&DW?UcDlnm֦y_qiy߹2΄'W!"L>Ib4&IB)Wi[|rW.1Z-(DZ.}y#;6ܱqإٷC؁;X$364 X=]/]=cqVF}0rgp8~f ~GI{_OY~ԀFށ?G܊_u%D>| gU:XWc7Vx.Hx;I*"_ګɑ>&hP믌V*}3RjO,Y :+0UU%{00E4Uey@U4oyS,x:{!h*h:GRwBk .4US)ӧ^l6+l&*X=& RMw*%y^2EdM_]bwb-?wG¿pfawŞs3 Pyۙrafis0f{>/8W,fs3XkJ=!ODAX{ +m>쏦(zjniQ.y?tviw`?c玕/})f YaJ}r~ůlVx8;< 3 +&R-2bNqNԈ~ֺgzh:;kS6K R5 :g%!6Z{18~(EW('}IMopx)I&po"E؇K}0M),@ +7&&@I쁏d^N1]~*LVFmH_RVq4 EXMf >qn5TsC%j +uXڳbʯ#"wGdš~촺{i!h_ +m%3+;vy}wL<1wŨv[$)n+)bQ 0bjю6-a™@LI@|U@oG8v L1ECFsgyeKlM }!i8QXG:MO9s}*2n\2h=彠G4>x-3$)PDShZ> QWm ̟Es޲4de`p%} QYЍ)`WM PT,`:2 @.z$pL.̗(Y*8ȵ#@14w V<)TSOT! j>J`2d=PܲEooswf Vid* +0# "ɓ X\|Rq L9D(n_ /|$%}{5f2ɪg@lĕΚ) %ʜ + S,i]T|ٖvMNYr]]^1{PZ0NpB$Ј2SC$96xDs RQM H8eh I)\b) {{he/+!M@"6UQ.&1d1P 3[jhs\ÊDho3\55aݛQJv$ȇg Qdn I.)(d#Wu%x٥&=tbPy1 u  CLlOK,O3bhpyT1*pqWc&|=s"Y&\,zβtz_c3蛌rRuKVze]]3N:zEw=ۜ \ COɯ~hIMUp)$m^72n`FAN@ǹ]<0!`@aGj +_3&eƜQheНYS\O(v)d}55StP+%KYA*^a#eosVo<_@JwHL]O+kn}z;/Xyx`L3UGPY\ +:iF8x)@$RlDi NɴVܳipH)1hM>݌u#mu@4{,h<ZCAf}L^diD,*U&x +6ׇGNaf[^@q@^Qr7^ml) ڄ7Ns2 "ɯK~GQ{iF(L 9%A':e"ɗC+1DCu&HӏFS-/ǀ:V$6v")LRU6Z_Gbj!JWHSX&DOdm^zW޶4>CӘynWNklL""2 ZboZt월.̓P)-jj/|~PN/Tגs|*Wl+m9-3~6}c2R6h.Y:}"qO?EalV[rO6zĖ-p`l<;t 5wzحf>WAYtLed⚉vtE!OhyUul娚G0x&Tϰ~ +i&<όq}σkbs*ڶdcs[ M/u:8銑˻s !IHqO^2ݹ ݐ"7U˯@E^'\:OTGeQG" x5dOE}"ojiKǕ!nF 0zRHtE F]-!iՂF! -undYzGl+sv F&gY͂1eL*ZqʸR#@u n֮"tX6rJ><Cf=p&4yz%b8)`~zWp2d*J,":Vju#_Sqg[aAZa(=0LZ"8dޮP!{*et%4-{z&$jTGl˸߷~4f]i[VX'|ӿw?Xr$9v:wi+ DU&Bߚ`N%uSQШ'.`A[4!Uԁ՟,[`1$+&8$zXYz% ^bGڞcSj +$64bs-ѫ߭qv'&׽<`χ;5O:SW]蔶nцUpϾ[uAm al9hCqR*"OrLpI>I7zOm=,wWc +'DhL FJ]R!0\{ GXzG,+wܾՎYMA*!X&U QR7>ĭ,7'zp|,QML!kj޼W3A7aQKG<)Y[fx%%ZR.A>-@#J2ͲTw,,y0LbLpTX  Q[vYGxo\>]ךNze2R$`w6 Us#8?Q_$IH5l@#b,ϊqgz(~yvEfD'K{l+e䢅;D#l~:yt٨8`t}᳧ zkԧEv1i}h ((.9o2"Iu#KГ20 AQ [+^OOs~Odb.EQ^}= +6hav8TĨC2q ڋ.AXb8;1UFw(hAdds-byu܎d*Sth?0&Dc]KZ塚dQ=K_y# T*(&ҾR7A/:X$ l@$mWjp$I"tfՈx޵N~EnR =ͪuiw3LR ХDjD [۩?jD,pwt!/?.pAƍˮp{f֬ CN􊢼g'%kka|8/F1xn:5Vֆ SdO**+ Q|h8ґ gE";&VnT*4}TA'l-Gᜟ!YQ?{hǻ{KkǿΡ]hD49W~tn_D! +: +-Ĺ,(T>&b=Dmf<ܠm_ނ#$5ݞi)tz*wRժ܃̶j̙:E="DchâY "[ +(Y$K. <]GeVۗQ:^f+7aSlEԤ|9W$C$dBdMKy].5e2lSTG*BOnwh>֝kgz"{]t'%&m休B;)#kHiMxˮp<3+atzvz b2_q}ЎA ^.ޏ2&"",LJ;鱈7boXtG'.~7Az"Fv +.ιfڙ^zsr0ϝKhv|'$Ul8 \~y.#78Be2#<'6@9WD]]KNв} bv!T}Q;MʵZH\B1Z,S~KYN_""2p@G;,+ a4yĪQ -yY<H5iIT`s{G u5<&FJ;]Z剈oXrG'O<р{`{u:-C 5"y9`#:V5Zcl[tqvo" =U?%U –xpEfǪk E@6>"$SAiW#FO)g -RV@D73Ч2Ҥ6v[Yo }[7>]/SBj,FÏ!2% yO Þ";'" !EʢtBjUd* = C|է98$b@WL,YTuuL$WYXEdSl""ҪcǬ=;yd%9"w1 n-R#Ų"%R2#+ύTACFtEhNo6217}C-Cܱ (@vh`A@i k:T*0&b&~\"D_G-BҶe +<@ U(@W&5Qfmwq~'-qJ,ޥ~L{mQϬs"A<ᐋХ'7mV>bV'( %;qf!:1eU!UK,y~d$ࣲ`ׁM;2Ss#K^8IwބNL3a9=H.Q'ڼnD8, ͣ;7!dkuQƅtIU'E#-:iegYRti.q{e&8O\{dD"6Ѿ'jk󓔢<#8pU}.=BBA7[UޏB_O +9?7A@n iQ{Hs\MW99.@%Iq#E*HL Wqo X?pEvYYf"LL!ҴNtF&o/ߟ$f@6#2J;~"u=wz9Pl=Qkbgs+5Y'nCu֩ aHs՛A Hi_ߐWF|Yw: +tYŪkr, g *IoE"J-\]m; +IyfPDx>R_7RzB㦞_}+=GƖz[o}:@v DGjmY*uDdUg+Ir|0D:AyI^o8@͎"E\z[$L%y\_ pxW'ΐZf掲'~l "MBHM7ju^~d:sdhcq<=(H#9 ~m<#nS|]X] ͻM83E䍓n~6 tM܂-GgCҙnt4yFKYxzIX d&T֤5k_@xr"V/ajb"8 /E sfk.d_+5Uu#l))hS[J??tN^N >bUOUF ZhXIU9~!^1/ +[ o@œ;|Nq>gAٌR3qz愷>F50p1 7%O%fڦ\d+MUk@>:ME^[+os}cCv#6Q̹ϓǎŎȥ9Yf.lD((u":/+c>8Nou;a/Ngpq;;Comᚄ0f[j4J!NK"m-EV>D^|͢խfeevI" _"ՐH"F;Bx`q,رXjj:' KZ$NU$RtJ[_1ewӮCYxV:ODv-/36MwI4$j$N]+^52Ep {5x`u[[c-343jZ%PܑJEWmi? Myu"@;K^ңQdH_1gϪ^i򍼎3bb4hk;`&Nٽ6{Hx=DL1\k園&[Ons~iTڴU|,jEc4JټȞQN)vN=vlEGP؀ؠRTy:uS97zz`:h}"? =/oG0` +s>ʹD=B8 f8{|w Ju𕋼zmP\H -jPͲdU/#mD#\p.3i*3Օ(M WV:e$%N 7ŶF["'ٳKW #CT"U+})T $w\S=P01jɤ^eDF߈eiM{5zĎcq$7ec2$RծW-6^X S-SpUsdm/DX}|jwsbϮHKk8x5j|hrJjRB{Dt)P4(|8L oX$WӠip*]rՄ ,}enJB-YU k/`U_Zߴ]*3[9$8IΊ4\dPUpz"K|\Yxj \>7\E=moHrGF0QdQNp<_GC&wԜ冄{9HATQt7.`N'<*.D`ޏ<˛B~ ĨSutI?>oJ:[SoՁ[Y[T"-ͯTPBu𚓭vG吩7]cZSvox$酃}0A3BNE z%. t>*V*ݰD;?WI1><ɢ}m@ L= 1T('쾓)Ri3V-Q!+Ib>nr +бZWOUl5Pxx'SCH0u~4CNwFh +д벹NJ38?kw[[]Ů݈ Tݟ]p]ȱQ<ՋDz ׻OPNe}jf٧GUFQcL m! 44h[ZgOvs;|S܋S_" 3 E8=->")!.&'_^]՟eT+~ kF C=ܖ_ٰ~ v9+qaw[ uz;[X=)[djpjCx'_8OHq[B!¢ YԈtFk}@M6ZzXOvpY#[(u@LM>J(J'Ǚ%5#|DR~Pze YN3l( !rI 5Ӻ9>c&-R0z+Y24倽_ȰϹٗ +MIUg +(Մ ݥ;l1W?uuUD& 5C]N_qIKf$#lq^Uڰ a_/Rq0E`zsrspCK/_)}5yR?Ve{8Yr:no;~(e endstream endobj 201 0 obj <>stream +HW;l)kl@H?Nci#k&zHH +nV׋H#C'.BI# }!Sm8ӡft 5#G8 +DzMQ>ꁌT?79.2ߑCq.~`d7u`[72Cz39*[q܏伫L>G~ `&M ZΜoǿ-_d;655CTSY&ІaHMm"@b/?ɣMXH&Rh8|6Nf*iLŐ^Tl%:¶ThEuUz ԪCs=JSБit|N54w)=e3\ÐlHi< GShID$!u8O_F5$v.ȃMw-S;A.5MK-MuDTeZ ^BYِ6SI58V4@T KoվaN;)ТǜNdAEA 'H/Ԏe]$P.jՍ)Y6!ūh9Uп<I]sN`AeF Lڋ'oU)iA&ܦh5.VviCe!0Zh`maJIg[I|4TG+VCu,߮_ +>&}\ CfYٵ^i<j"!Q,'"F™tM7tpNNPkn3I 9#\Cy)"eh!N+|11D#T^ΞބVn"iB`jd38HL|n-bcrBZTɎb$ 5˩ٕ"T'W:NV38i~7E-I Qٿh*.ټY Ǚ~i~Ɛ:NfZ7yahpmӮiEigy-/ΛD a4pː^8 į<.yeڨf)Gk{yfD!Nu68g@πoHh8s3^o +S ;5kL;rӯYg]ԯ[{>J |Sn@HE<Ҕ;/I돷6EfdD3oNe՝{-L=~.j.}@ݭ<¹KAl]sseN6~;Ǭk{2ܢ.)8ojtclTGO\_$Zl7Jct5/EtN"ϰdr5LH͘L.I '@]m陗?,4 Hu+rT1yi1ϚФ񻊗_ltLvi$eʨU$L y֘\E˘j }m: ]. J6ۈEQ-EN!*t*b|^gi.RF䵑D߶li䚱m)Mj|~* *JucŞrS@3Jr^9ʾ׈X-P‘Y慝$U *g]OݢȸU+Rhʃ*lzD|Mtq)tB[,B4TOc#b`U&p=VJ+48tmQia7?Uq4칬7_j n}1:` aӪ"ަR 1Rɋ>&kϠu +ݛaǦz;Z9kP[j TXqO(^?E[b +UNz }~Cٽ;v`5o77CVgsg"YY5]6,Z:\Z bz ȺO[Ցd& dp:H&d#4"~Dp{",Lo vQ8] LΥɩ1L"wټHrX>OvBl,Ĵ)措' H}U"W5 4;TLyv& u={HvqQqƞJwvwpsݐX?ȔFDl=crkYMR wqZLZkk".nMSki$!`{ "r;c Pqrd n@v]KkpzsP>yG\QTq6EӴj%|:/ Y  =* y]NJuOԥx&|m `eBˑ38]c:;ڜT;xoȵ%[[B)uuƵ9弻798uRnK gNB=#ah{]ĚnܧMHzވG\ V?/OQmlW"^j̘Q}@SlrɁhw ^T ('F1A zYrlGr)t=y!LLj// @`N(fPjd  ,fgK}m~cl0H [1_ӿJEwWKr4ú( +" <C$22Biʊ/29SsŢZYP + )>GKK[j^* Xxܑyf"֌[!#2+(M.HTr eȑ͈!j:Yt"M1_6GzkhmC{P{3ф%T#2&8r=` @DWZ)ja ;-u佣-γl҆7b露%rs  +t9b +OoQdL\Dd9Sw#0Lo>l_OCB*E +˞ PuMRqy*/<<~c5` T3VZp)ie2 ?&YJ,E\q1q!ɨʼؚXW;axh}A؊_j4 ٴup B:u<l,(OfLY#,c?,o@F hG"E-Vк! =:OaT!;$褍*E71ռRق] ϝDxCs'Lw2θ,/q$au<|.s"&$b_Gq +~CRתl^CoiR:gYC!S s}E/d9DKb[M0]r)+ ]xH@4#ȒpG^ ɄCN{?țF0f4o*-o]ed4q;P[M=}gMzyO Y5i(gђBN˵̽oIT)RH3BO.Oj8r]{ݒq/NC=r5 WI8 +=A$6  t(6]@DxzL;֑!z_U>3>BX({*sLnd?q|SJP?cx\ +.Yhb5\ۤ/(ⲥDgeM89oI4.kG8oK&6/ 5!a8!^~kGw\A~U'&v**4S7(" +ZS"aCUB&g1GA6'[1x';vD8JE$$VSj>'4fw].U*eݖ}kiM'(jEې*P$9oHZ3]Wz>L^&!uReX0.~65.q^*S`C%k(P [5[m}]O2EQNe2)^_LFʼnHgm̜{ȼiR: +z&Ȕ;',XufgĻ}w}蛵>z~dISdZ/hٍ>4=+8?t8WmP=OY?vn\ojPYe4VOGl4pÎ{vaưa4`q"a&nv] 2# +s{i J絣ZDp!;"G6Q=s8΢H͓!B224:>Pv78N5Z],/8H t[F߃QrPMw^+?ĻVg(O +-6_sѫrGv8^:Ƙ,6h}g(Y\:Qjfvd '-1zq˯s.l5=p'DF쏓s",h!cHӲJ{lUSE +M5"#u#ڕBFoM0%z-?/ex/痓,#"aRL9C(VtG:DuB^z}ZEK-bcٵjs\1y|1BL+(G:]@Ul::4arC +_;e$i!9xEUba%%o@@> 7Qh^ Hf$35TFh8{*;^h̤ č$2> DFHюFR*FWi%sy$ l"6jOıq>Ä>vdxa]sI%߲O>8Q"C#RFI#J}w=5 0愑odMm#J7 ChS6Q?z8Y"iZzjiרFj{5LNXxG+T).[BZ4ms5ۭɕ>yC!To{"-w +Ll-HFO4t\C@ʎ4jeXDxQ Au!_x' =,q0kG!!VLd?xϗ"mG8,! rS9s)e#ۈ9դR +BQ4A?| c vV%$R~yrs# YS~= +y~JҋtX.S5jHDкwFwI"0L> (J1ʥ_;%sXn\N]EX9srtL.ڂȺm%u[h%*m+_1#QsKFO<e8H=c#WbhS ڛ0ـ G*@C>0{F#lc2o%ϴ`}?lY*mը*gA\@ \|̎K*aGOcҍR2RqNg0NTG]{&וX[Y=lmַDd*|w?hFڅ "Urw*QIc4l#q흁'޶HrMV<] c}ba&Tʳ2f(6~: Rd_۪uu椬Z@1;"D K`P/b0 + /!68EA@V4L'y; # +d͜\O< Dl|%S((.%t[CB8'aD@S +'Ȅ'"0Yp_^\Pƺ~̞R撗MZiC xY 5!Xj) !x; ؝uR,txdqEX( "n?o[m=\'YPT/;JƉkN+3\W[ p^٭P:>PʆLssEƋ fȄhb8߰"܂;HSq?4)8\D ' "k ,̋qIa3*w m|&Hv¨xG,e򕐷$Qtv &^syIaaz (9)w$cԻ94%5 +K,Jpgi Ǘ, $k2,|+~qGWS32s60A&`̖I¡T=U''7{F $Sٿ9:X5aK5Xqr3bYx^-רaLL~9ɺ1U^U\nKfd@6fp#I[gk$Ͱ͚RV6Q E"Hq8KܸE{9n=XE[ +S}5W8>d@ZƶS˸=i:wfr5Z'X˭›vk(:tRĐ"d!Wix)oߤ鈔>Yw_̎Z=t>XoLLIY <^*4KP9fEOKM~$+OK2{.Ylr2' vSq$ɮ45)Eit֬Y5i̪{n^/V;p5oΖUdkBʄމ4sH>4OܿM=3쪳Ŕwn#ˬׄs9oCi|I o5;#7;ńzo<0V5o= qaEm'秤~ZߦyדVIs7|ͶL<i:/Xl[9Xl8'FtQ~*q*ṗmŇ,uޞ#16MK >^K'/ n `H" <#?x7" _^ ._*C4 ľhxDK`yljhDhHz,dR0cE)WI)HKG̳3ZB\ْKT 3H.Ra8Im˒MZtg>U oE\Rw+?֫#9r$~AGyR.\1{A 6a߈_/-cحN.el;psk8+DU0%_@n +ҝ֬<[#PbV&d6R]:s),ҍ"wo3mz3r}מ?fH75W[e|ܵm[u2ΦsګUm 0?PTDpch"t: KDnL]I "綀q+,zU&lOXe!Gv# hxHpZ"u)c.$oJ@wL_ )iP$˲΍ŽjSӅ~'\%.%˩3 *v:;"lctwU@ 2FJHEۦh;L|i3h^x+2F.$l IA),qр8b0} 2z~RgɆ{N3u >, lv1(XI /QtWC8 up +.-1? rjFjJ&{+Oď-%Jit|@LF8 }{b_8]*A-*j(;H*o"ѫL6`JArh8̡= 27(Fn>b +jnCӶL?%SM7(Dܥd:BTCNN]d3S7M&aMŏV%"iED+e4bϰx;Z ^ʹ_n2R؜p+M-wpU[Ek$ͰυsðlkA~<J^UD3##~?lYN[{ +2xD5~ (xu7sNAY63;|4lpM[5BQu '* #\36_-|"~o˶Z0Jyya]Dp㋓Tbs GELx1XnD*C(>>D4$nZUz!teQEF2z]wသ{`_jA^x%XJjČk-K +jtbZ3x2\T} 離-?4RUxU0J[p/5ݵX-?)RFVQxBTytU++&&ƺ6sC]㝝:2ܗot;1vged#+}U<ꉬ]"`~s<5ob ~8+L[Co>W1Uf7l~<:grz8 o3b-3 +y-XF}װMSKf |GH)IfOR6Wv^ 8eE.SDM]H Dj,k3sg|b"pK4fVxqI/.wEv" c%fa/tG-}Zu$$O8ml Edr%D0gئ̮;M3ML"rDVc]{3Zš}qJ~(/#'~OS;^2r2ezr^mY7fo/ªjN䬙/ԈoH3^ͬVpvg~>)3 +?_wH}d2F yxY~u,5؝rwy Ь0Wz$I r<5kKS}Vi}ȟY{:_oYYm=iX댾ڑGr3u*W +Td<" C \(4H’2û2{0+DbZu0:.䃐⊥qp I]ǖ<i%Oܦ1b@Ûa ~u<(JC*\TƾWaꝫx*Obޣvίjo/ĹFC["B[$q ^scsYm.RX%닡(=Jr/R9 Q x-kd˶^>xO"KԱ -`̛g 8Շ쬒YCvDɱVZxOyJ!w_䨴l 2G4]&f :BdMH_?i&C9}_tI=[@\|9ɕd=['k_{Ci(Ɓ ~6ԯl|Y}s?v@%Ξ,ţn=kx?Pw 8mΰxywl d t(wx_@18˕RE-ӨGehbKBd@jQ=JHG ~QIs nNBd6:sUW!%k$\_^+ABUAg)lT0gme$S]zML|1$@ߪC%yx񠌳g[_r~W4= b, *n6V +E3!6Iii#yjy#$w'Zg2oZ:~c>kEf:3BM +4J 3m|HDtr`gոyKP]*cѩP99ń'Ftj}]%Szgvg&A[0?ab#'Y4"%Ava7`d O:hAQυԔns4Wr"=Ѯ{|]|?Qt:Uo))l=Q7'Ji}7ZOX༐pOmɖ#$6C + BB !q B/REoI\B@O +GɐdX(%*̦!C'}0R +oCrilKEDz>æ8*oqq> 1nK9֗d;R4!Z2H]@ț^`s,nLOOFG$׻ĚNu>|/'|Sd,}}{vh~~Fq_> #a@H"A_`#sĀƈBD͉/LBF3mzJLϩ+k33jHq  rJ4_YC?|=tSD$ +sHE†Rzcd4%UZ:6gGJ;5&\RGcW_W,' 6Sa`g$$j'aڽ+)9ly-_B]LY=g\n53q^e^)#8" S!i3v8|rHȐ#ZyUWu`$ Yh|a^_ɪsdp IWST&!3pCe;3Ptݥ=p6oNՔZq̪ӣij[moQ^e3knB_ 5P Ey ~ P:އ~kgC]e^5L z\6픻)A&RD|<z P|x|l|9ɏ:nd,YU.VoXnP*S)f'# endstream endobj 202 0 obj <>stream +H\͊ >P$%m!aN;.3ͱ,w? ̲0wA^[z~_&_i(RF8~ћ7{{ `g˪:u2 +iz?/\4ѣɵ|ko [%3J5ӂӮn(S +ck|BζC,̟2瘜b$0v)sJ1Eɘ39'V̊xǼ#3bv.ȹ82٭ 7;(rPA"U0|s46\%g{,]x.fTEI̢O +0n endstream endobj 203 0 obj <> endobj 204 0 obj <> endobj 205 0 obj <> endobj 206 0 obj <>stream +H\j@}l.5/C>I*UVsf6 + +guU~#-<^MKD^{a$]m6/4{z!tn gRLI ڀ0"))vZ$C8Eya,Q2AۃDA$A;0CZm*hS*0T$ZbZ YJ<܃IS'$NBpf +nE­dNKAEIOa 0C\xČvq܆Wnxg{5Ʈ&m5=iͺޏň endstream endobj 207 0 obj <> endobj 208 0 obj [214 0 R] endobj 209 0 obj <>stream +HW9}~lŗMY:@;`K;Z g"^3 +ٽ߯ꑜ\;R4ė׹")Hap8W*ZjĶo Q>R׵op<-%b~9tS|1!!Ru-L:Q8u edGFY~ੵ\ڑFND;jfĎT2``!mSRhNP X`[;r`8|i9:FbDF>ŗE0~2c!ބSAjGd sP+5+zl-u.:$A +\uMajjVg{Թ#j-MnHo +j5zZKO5 F=#B=?] ( E(nͬ+㬱ɩP\"q>6':۵Ⱥua R_obyǪ׾9׌6[y] 15Ӗr(pCSԞ٣u}~=234q)wMyĞjS$" w _SeK_}. M붗 q~o +i fi$ZՇ(F7w h!&N\ބӶtq"}~+V(H*ߝQeڮ8c." +e' D}.^chX$3{~]2Ri{Q!y$u8%W˒I+1A ~GƄF~zUepN{O'9d`!#܅8ˑ,(XYކF>VK+ͳV6D&1d8% Eے{bE`/Kx,2l薂IGfM6]{Vۮy/$zx :|0ZyA"7hYwTXTyU֒Lɫs!F]>a80*g`fu|Ovgy]_yb]43rOmbVUVy+4vw]ڴJ{֓Eeɫr9G浏'^z&ms6\VMпִsqKDZs$ &_i{cCxs~br5ţtY̭eE&=g-OKbv*)w.},|/YDpt\Y9 'r8OXe 7Ca뚹UE+ڊh%Mi3|J/hz+ݤ]LTo2Vr*l2ɼq1cIˊ7sW7vH u>^ysN6.lޝHPڍS%72@T8wL3!>혱w%dčo +O7*wE/2OB!{ 2B5bi6 sgI%˴l9Gtr4*OߵBttJT{jt1븛;_*ތ3VAᠲ`MV4oތ5m[{dׯ[jKG= +v<: +~;r&*Pb20*An?x&uMŅ r(^&25*QDVzO8BO5_n`Z 7⭲X늟967}jXx$7|o4SL*L!1V]EZg[S]̱8! Jv~8RuI)ؔ$sat)4,XCdH4fKgYGPuiHN*gs[l4q76!9bΌ}q5hK#q>Ov3O>bj$(ljb]H-h5,H7\w֜ Z~H[2 Ϯ4әw&(=$-3胇%]S" W_'P8=X,Nm{j-Coh'=n{o}t횇{/L]4dOO&j~5;)_2F8L U&wd)@TMrOY6d)76`)lc F[}'v29JM=Vn^vA~ +_2(Z+w']lsNr t\w֜0ejXTsio憱[.s% +.%ZiVS!pr}?[i.'߶ +9얡؎2x 'Y{ܶ]h4Ǯ{ s6=*~|2pP}Y?7t߂-Q[Qv/ Gi ߭i 0묅]"I1.\5A."/aGORMmfP /oT<@B9mN&0oDN9b HOIj8Q Fj8451.Zi=WaO)tM$I5 䗷?5|i8$ټq/9#H)Ca+aǑ#92c,ǚ-g65NY\ڸ%W'JWšR ˻ d_CUQΛkbcӵG a6FO$Y繒_XýCVbUmK|n!'\ 'lMwpc%nOZns1JUŌȟKȳ/b ci?e3FN:< +ܐ$Tw\7 +OH ƣ3#lW2T|B~`M2Ϗq_eQ{Y<(l ꢈ4;ܭxsVbǕԾǕvX.hn: {: 18WM1<syhŪ 傟:#v֍Ͱu7גXk8\.4 T+YϱZwHMȮ*dfG߿?}ٌ;"fGx9nȄԿf,R6fhĭ^c㖠;.+U!k@) |% 3rQF}9z]ǹ_$-v;̴`4&,ZbM.>\CCW>''G[X<}oݐ tós/A!!O lUDR .3b 2V0]NsɟLbIxQB텢jJpuo%ʑ#u? :H74w?Vɪ)ybĚHYB4;*#j[Fܺ \tV:j|TdQ +hUD|2ݑx5woz9o*:"?;z1Xd8Y=KE3Ɨ[}EF{#wXwEHtk H=MfFML XH<7YȌ]%B{K9 +h\X F裊sv|m G+1 <;菠h-7e 8@зB%a:n{$[v v$9ӂr8qG,kyޮ}ч0' +*z3] fh{eQHQycVܝ P^8|%Xn}g߯ؼ?h{SZ +;s\EdKerٝ$UH@XJi 4`VYp筟~N;ޭ}VO6rn՘}`YE܆yuwgNpi|cj^g6=qHP ,a(fQjSh,b^;zditN335_Wfϕtu%a䇵B_ .\cy2=N7gwqeYztoqvg}NYcJws,e[b*HqstU5mA\jm-x~)S})ZO%m\epEwqXʴx_սD:6{|WeU٩6Y~yO^Q>zyr3Q2 +XTM!\nP0ͥAYҌ._8hU)<&a<1W ixy-s9sͪ CORkkN3pd3=YUds+#<^X=Ei#7g_roz3;K3 k<(2/֑x쭵'tP2X+YQTa$BoE?w׈?Hէ"}\V2s' *$J40`3707VgګpqiրGFHѮჵ +7 +eOo\-ܻOXzލOx0Ji8 f3sDXY'X'vtFVVvsX2eD"yRJ"\h njXa˙k˻g+[*g ~^|ꪃw L3\A?Y.E.TNH]yt!'-uu~m_BU0rV +Or# +T\\LhIhԐbR۰m;T!v[q~Ǔͩh?iY?)X9fK=Ģ/U[}-7~#84qlM!U\HCo=d /#UTZ> J.}|#p(8˺S\y ;w{J.d.jLYky w_hf{{ϰiiCj_C|(.sdFl=^,A[zFu+˅lN~5lj{ {E^RըAD2䙒{2o;us'8bSL9Y} )UNJ/u}77ȓV;}VBZPlX``X3rklq&F4]>SVg_:s4_nN!V/Prk̃A&̭v(ʺhAB JNҦk p4>āǼw#ON3GVæ9$=#A|#aAEP5 DmFx3HmHxC`"`/1We^*/%e޸S JPtsd"47Uv+F*c*=F +Oy:o 2"HM4.ĕ@2c窱xwTbR U%#Of RLI˱b_ꯡ^<͊ ɑ"+ 4{ +R[ @~nR xNi\\l`i#i`|ՇK6jqLE]˹0oE}lH1V¡5 +ddEX'Y|TA1aڣYR5k +;Y,̛p#\C%;$DrbK!GUV29/- 떔DxQpm +:]c +=FGk O=>)OidGZѐFhVZ\ur,bafG.#8]Y.[^82gl༺$&"ov \܌aHYҰSW%CL,2c6Ա RFYpd, H>nhn hǠ8V7CsB +LmIvv*NS.^NkvYFI| GI^Eeu8uY?" 2#APwy Iv\d=r +;ߋ3 # +zWs..f-+T~9WIr$! =}C%Tx<ԅL a<<]S,O6DTrzB釫vJʲk +#V'+G&_8!b HSIsiسHɮvvYH*a, isd2I-u?CL?xkPU9c[,z;( z+V5#5&y?\OjE&IA{2NƄQx=Wv{Rn-@by̚GwڹV91g<M=trZ~lWc,ݤw+ P&gR#>{=ȲfDy u|x'ya6쉲YFx=a Wi.5naI24eP2c$k.kQM,]Ƶ< 5 +_lbrgP B](ef!ĢƊ|xPpb@8FńHQZ\椯r;S{6VRY+$Ұao" +}JC͌M3ώ* 7Ao0$>BOrljR.tx TfTmd®T|uJ/,NCK\4qxڜf~(?,r(!?F줹d u"u`fs_3!'ogޏwdჹٖdlGޓ98OSOmzoc5k0t$υotZF塆.E̠,rw%۠}dD5Z}KG>L(Ns[0}شhXVljgnt'/1/FSP,A@1~#|]~\G wO@9|џpsbPs_lCϣ33ƢM7 .}ЈQQoE#zkÿ́NE"oGȊ(w/9IO +W; +RТji9GNj먒s_6%ϵeufIMuzapͩnF$t:ȹtYKFcihr'B=ڲ:JT>,SȤ;2yẍ́Lff!ϗu[%\u#Q˖ jZRM݂'Z[uG3Z`SϨ3VFB?,R{&3;O005Um,5qs춊kE- 1%K *#QD569VjΌ|];@Y'J-͍]c+ifD5ͭ~f\pX35I8"KogŤf1\o<ՂvϜy̓kl3 !u0X4ܿNwS6(gX7^Kgd媷S!:W6T 7gz1s 'X@4<#QER +0Ȍ®*6<sQ qB1\0LN&8Lq댛UdM=dxf&C tb9%|yޠ!_ʹ:Xfӈ)++H3Ƶ#OX ͎<+-cƍ dJ + jx;brݙlRt -$׶ F ?ɿlΨ5j5 >X\1e9N56qgܙ>x˓ORY`(:-͍dr; 5}$|V})oa=[O|=[se.;ZsʝXhPdF\^|ysk%]4oCߦ~q}k#==7y9gxtƃ8My[1mEBPS4DIq!9șcD9sFF (.: +v-BM5Lo]6[`9rnKLnԦ yʠi$n12J pS.jjTuOӨլ*v9aeS~u̹MLЃYՄB qa"Wj5KsNjF_ۆ< +JL%Juާ h? )UzvD31$@Pk7fx\M56醷Uάv1y߿yt+5–OS'sY}wZ03n5gқyWmUegmCj6sMxʁ꼌s1{qI*Ǒ-f05]}HM-ɑ썲}cӽD\}68wMaקl/;pmҚcaD\/>*8ߤ*ݾG$%KG4B*βAD&_+ |/{?)Q#}FElo1~E8{.ĠvSaM`+<Lf!c[MexadT*Xuct,7`r ]]WG)%k'u͍IOr_T3̲`0}_a=>,@ז6S>ϐqzSeץfOJ5J".1ĞS.y2kYu{ʶ6a.bo AFw0 CεBtp_S2y΂R4cgnjZf5/C ͟adۯ]ǤNLsm?t7x.6y8\?ʄLT`@u}:>pM2ZU[&Z D<(arG;&q /ݾ;LBq,*LoiyŝԸ!ver&pn_pTu3qM*c%UBv60-NF Ȏfi+Y9KƓFXYFҌˏ@[[qUeRǨ j8gF~N& >xtqL4L ae/8=g=a :iְD0uKCМ+˗Ӫ]L7w('A06u`E@\JlVGhg˯F3'WXIR̩^x lNNk7"9337|Ŵ4o7Ύ]+\uaœvqH0e0|m^!MŸÞ_'\QWT-%#:#S$r,yFjى%9$jj צ%PpX׭癸f?:In*k`rT2[X%lZy~R6oM+Ks~hW{mJ=Dž1f>̌#p㿍VF?ݰ.o *oB6~n ,yКf3˴JҮD8귬֢GQISTQa+ +}B ww:\-cOW6 ԜQ!Od4 ,)~R~2A (Q}?wL#;x M 1gHC /˨K.?rQY`23KϡHy Ӫ*xF9*]W0(0gr>:(I1MQa$u0%×TI.'C S$$ (+!i@I65$ 3x_f ")=ZqSd7KOa3J V3쑹΋FrJ&L[ @L41tBMau)1KL1qBd鑈"Z%bc/'noK$>7^/2|1xw$0{z8eRVw`n]66 +p^`2\Qqf=^L=>JЖ$ ",wY1ׁa^rNJf:<=6q/s^ a Wpowb%ຏrǿՑoRpP0es+?U yżk4(#t#@2l3(}!/5CH|ө@0D6an$[fI)HU*%VUd fkYS"N>Uid͗#V0AlN`kBiZAM;d\A,I-H"a qFG +2.0$>dJ,yCķg@dRH3&+KZLkE fr5ןƐ dT +9X직GLӷZk$(չ%}J^o@$gXr,S9ix)ѐZT#˓//dn,}zr+ ܓ)Dn/px|&J2֊")QnO|&)hzȰ(aI޴ Ku"5͡J7W F Gʁԏx#/C$,B1lZ` :U$s YVg}NJ +D0=ʣBD؅| BEAD% hT FshAFO֜kdUQ\C&&_D{b>";0".ȋ/^ZhZ%Z_1N䆀`fXLonriȦoߌ~ÜEer(ߞ|7S*;&y +#Ix/A%grU MI'/>M2d'iԹ.*فCvIK5[j#~ o6OLqwڧgZ.i>ȦcΔem3qߌ]>Q} ?tOt#}2B+$]|d-Xv"Jcgh߽Lg?'i* aHZu\q&j}Q5/fǴj~'HMuE;_V%@eQo"Bb9#lpE +tUG< +kfӻPW[" +PLQ켾*9E !}#%r+L!QZyOSNp0h+!^MdH}ר\^ݵGY:1G-qauHA92![%bAZ?zJyvh?X |郇X +_7sB)z gk!M :9SoHZˣi{ 3NoU&ogȟ_Ɖ1._O~]㚬_D)q$cǵ2EًF"EǞ dOEtu7G?B}zv-7 }C;& C=+g\tc v6XὌrv.7VQ2#$)#YA_ZȆd9|b,զ_]pd3Dii'ƢU vIk}4 endstream endobj 210 0 obj <>stream +HW9#y +͗#SPRTU65˥rmڳRkϟG W| R>Yl(/b(*zzy? VЧe;Fbz'՜TH%C:sZRʷLd}F䤿Y2``\ +hY㺆I~%F:heEE9 U<)Q<ժ|sFOM{2&9$pM$}L&yh8찐jG~J/RF˪&g: +VkEn쫲GxkOZ1"@%-6tϪӑI^֨5A)Ƅ,ڐAFzjv&TLW}e0WLӔys4W:d@"F8aNJ__1iGi}\i!z1]{I:hN XìMTiͣj չyk/犹۫!:BZئlTt- l:ZM4;pȒ&sN 0/-_m1sq ہ=vp, g1NHt +nJJ٬JJ)}گa;i8,OikUm"O-_Ix5K_2 W͚CO*O:9Dם{ mV[X3sͶ:;:kpfIܡlK뭽^HQ6e2LRkgil>k_u{ӹ4QWǵߕt":y)'.?j;N/Ard-G  } ]fYaXoQ92Xb5!o2Vdd kw^@km#*a԰6HߑgbswlA ֺ-; bK۹.fs?Ex8gIRVĞnz:D=kr)Q]n?Q\ rvjv<5qh͆Z]f?.hCred WL}Fxord:y@1J1UgXi &WQȓkF2ܕ:ԕd= i(L0ɛG>a z&.9S58( 7sS9&+YW i k]#ISza̟89PѪӓp{~`qDR [וZ5rZkZzZܢDFq9e%~b{4G4HYozLN$Uf8$gtp@[ +ٿ. i˻1CǶ=4y(枻à}Q1@RH{}^>||٢AnG;:*8}da%Ϻl_0ܼ2]r _v?6mŞK↥X|ZL/x]I`P2 +=QZp֤Fį⟞xͱ|kiҦP'Yd6T mJh1?:d3}#,L$&RNm= chvXIUh/1qlyh +تujb!V[HLnї<'4;[ܑ`CMhrv2"Rs#31n3iy-EC̎:l_&Gn!|S+sItYVP 03(weJVJqB&^7#^dAØ@M5l!$."j?d4\5['@~]v+-mihF _5}2nD.Wv31H1k Ìȳ+z%xi‘F+j| HNyVKZx~G-M ړ4:q5KeyJrs2}Z!W&*LCD~ +߇BJH ySץ{gBJS! +[tjF-/ =rvbȝXƧ`lj@@c<Vv\ADǠyjuv}nK3z#}ǝQ%B_ ݙmWd|<|Ŕ1w)m~"E )c{MfݞgzB'ZZP?!Li9 'S9@~>-E3V[}cq]E*n_r 7'wÓ,ιq'˖9ᣄG'j>y Qc(8^NEwSAZe4Qjz9?&% 1 |'ejbCg Tȓ90&q.FL!0*[4)gr9% +7JJX5ƍkXES]iAF}f}3I.R'Qa}x8;|񝏌F[F<܋DUڂC#j#,KìHj]}>담Q¨ ~7i\0x礢*I&:( |W:$$4I C +=rRRԥFBF檯?V#dL 27{~~Qg_[cA5s +ilٌH>C;Sץ1ٓ]ף{`GEoz?GJJ>=4Mq흣w!YeDcZHwpv\ G}MƎcK$4/'cXb!2:&<H +Pc]!Ӣ5qE'ϕ:ez$D`.}TII +ON~/=h+yxyxm8ߒ7v%}Ozby5sK0<еkXlaKU>wo"c J1E +/+5bK[OacdA &Ev~7I5. Z~xV}g&4y5z ( V.bjďS3=6մ(o^򍼛G@Ox[4G]hKF.J՘R 4\^{̠|J(A=+&{1xZP +zE&L3ԅb $UU%'To(iʃ}JzݦYfl )taTZY-a +O~+qFsuA ִ-yF܋aR5IYsqS& xG%W*w 1%Ф'pYxc"V1SV \SZ᙮#qfj29MΓq&jql=&R$%uMVWn59&Ӭ,TSe[dQ<|q-nSJ%MbBԳZ:%pBd /랭"q׮ܢ˴pSceyMΚ +/jͯ/z&"F֡>_**&Ԅ<>28&jԒR +[/Әbʚv[+~=n0#[5񻵵ImB =n8iA`}o Q\[]Dz+4+$MEJL"]\ך+&55Zh\`BUohlxQN*w-58ŬռjO RCR$O/T-lMgf0=)*Ilnlۊ<4*eLbjr6S{x:*4}>'Ao(T:Wra9/7|d}JF[Z|ILH}Cc5ZlN]oi)8\@A5kf}TsZj )8ʐռWZ(]Y3}Q:uyB="RԵ"Y^Z0K+n>O`&i:|C,uXYIؤj!r)<"F*FnK>Nhhߒ?̊ }k2&jiW{ԭ#"q8>ttUaR9vMYiKO~u}aM]_iGS9ԌnҖeΟ3l +q%oggzA:d!iD*ҥxS  zZ{n) +@Ex?HJMRcnXGnMjrAьL𔏯]DoZ/sZX P(˧0Ƣ&+LyT'6r7ee4X 2q!Uk} 䶓#]sf'6C}g?n6.{xB9Sh(֮m{ٳ611 ^k uϧ猦=v]>Äiv^-=qfR<0 t +ڀIx]Q=tҙG&8J;ئa|.*ƌFiYҔa>#M4DNIdcT_Y&hj8%Ȼvx + B,DMcٕx`œrS(sh8"şYȫ0j83)j8F19I5}#N+"/hT(ުS|7;5f'ixbR !_fF'XHi:F-cE-7xMTJ 墸R#tM sgWfU%$ksX孁5bT`኎ҺhbvŮIS.U֥@Zհ V6W *`)Ϧy91*>&C:E`%Z\F?O<25ev2@_4g`gΊzx6="7 x&ꦈ+S[f: M6fO0#hkR{?rPi9p ~-^ֽ.6f+-3wtr 5VùҢ8zZV~hՖggoC?2^8Αx&27Vi{?ﶃh掓fhKotq_ }&t,|Bt|@zӒXD2KKRjrŪ_͚.PMYYU +j~ޖQhHnTYl1 όD&YwI p8.jM[U{t~R.=ap.Tz}"'/KY*DG\d[IfHȾzY!g I!)b.*WJ^hWyD5/X`'֫}6mfw: R "3U(H:Ŀٴ.L~NzSSg&Rka3JKaJ=Lլ\Ad4uFa݀&OfOp 9WV: +€W$ ô&9 S!F<8*ˮ(E\6J +4:X/罁u} /z &g8H\;} ÝI֭hC<Į֭8S}voS 2LdD"'`)7stc\OEحA" 2dީcMr#MDFvq7'B\uLqqGt|W28uC~#3G+}+n# J1Ap%&ҪQ;*cie֕0FaŃl19kە&NO@ 岉0jb׍pY ,1ٟ3yOER,zE&lˉnT}ԇr{xn?o~,F# 10CbBU{Y9Q-J'?Ij߈DQ>BEYPo'T E[&UߚOc#\^:LHgI;]jv'+ֶ Md`81S {Hw[AJICŎedF$oF:c/2[١|w&C|cGm>D^Z=+-~n(~\w;̄xwmFvx}ϏoryyT|ʥ({I>tLSپ]vb*#/w O4;zֻ(kviן:in6X?6z9ieSΉ+aspxGg#:He 1 Cf@D>PiCBkM` ?( UzwH$Z'?\ע-8ؙ C>A|؊oI|*s+(]-]yx[ؓE.$,he=%W;WMZN5FUQډJy2_Ӛs_o\4JwSW0N*RGVӯ`H30kPQrrr!Nm-JUxW K@>5AmoccuCmd:G47nsx~O~9rYvG3w$F%헊j)İC\UvKWKCO*7MpyW|m`?ktmu-mnDfgunelƑWgʶXMpghBdL2^\΀W "%ϽmׯXќZe]m/i%Ȕ34Ӯ3ulB9vS:66Z zHVHӐ%gw?\}\ PI9۸4d[{eМ:XjZnbB3 1?: 2o@i͗?IX˟ 6 ~_-XmDc5~$Z9&TC4D %"H̽i~oDHdFr$>EHI ɝ OzƱ<]E y=,rjim!4 ej&P3f@&m |GR꧳/q*UEn;w.lG~:{@Džb]@F3'u +2*oDg6q9*s:RAmG(On^)? Jcɓt`+39cS*S#[9}}^̎L +"{ S#5^$"fd͹Uz9q2qK+`H$i=o(uܠ7]{Dz)pkVniH&إ#Jv8轿䡛/0(Ɇ I Mg$쬪ntDˋ i zO +`p³M2/+T*Up䭢4$ns_Cs$JەS +xhvћ87oɲ +'UN8JUrL4ǻXk䏂f׍!+3vLp.}\mmlkhYa-Vj暜l3!|ssWF߾Ol9q 쎑/fV{2VȻ4k$j醍Yg{[pήEx +N)cQD) k"t &1gP5F#M#|&{rӤ\UdZ4'纊 W0#-:Aj]-2̑Yq+Cκ&tkR2{5DꔀWzeE/.y&EcPv핍-ɫ)kɮTf4YyAS3ktG&~vyMPb;wִ)k٦mR^*뮛B1ho|NVMEԋ[s@M!\[[Q$/䑑$Noq^xHSɤ}5K_Ա\x>)f ӧEW mTNy䚇rqA۩^A؋Ѭُ$uzbh&5/z傖Д>[\i;XZm.ōK)G .s kfj-MSזL7 e?y]hXu C&r2P'H7`#zi~њ>Y h{Sb,Xd38M'[׵y9|eT\_tQcۣhbY3s)egx )ve+P +^_S7:VCJn" +D<6WGzH]e*q뚘[oU1Ep>l+EI\jګך%SbjEٍ!x+443nK̛m޸1AϿЛ/ iD."3Z/~>^} 88UJH޶_?7X{߽?/l ZM Vp?ev .9e ?Fq0.n32"rܣK흌 6zzY[Ob;^H ];T^&fyNatw8zg?7r}n5 r{$ +Ř ' 9A @ y؎SR; \tErPD+C +'NOvbWfo=:/, ( dвXOY FP1:m x8tu0 +W `+ +~Ճѿd)[se,SS +Zd>tq2'$smĠ+/΋Fg&a H\Es@qPCyA_eEPE|\) +RpR{"ȒoWX(35<5f Jx}ιdҐeNnmj^~8Tӡ\aӁtRD0 ('oN ANewo J1rRHHSӓN zYE+Z7Cb/$3 ̩ON#j x07.y:tCtK(#ؗtE!8D~Pb/ u{-upU:T]>#z\$WlכE8 }3ƢHtށ#]:yML~ka4$)Vd֟^b1Zho5ID^?j{D6KwU E0겍U-EZ̜HJdRQS| LTӌbX_WOqfn1\R Y`@%(n\{ڨxd]taXoT"-h.I%w75%U@M^ AzG]pbgP:/MJ +ޤDt5Kc!jD%^ƶ5NfZTXtz }ͪ 0}I[=iCW&),V^!?ix\.) PQ$"i3Rܠ"w+ F8d>?/7g ~GG 7!Eq}t'ɤDvX+K&5 +,t&jIeNHmRXM e~U f[,$KO Pl^Le>,y+ޓ 3gd@S( ixRׅ-nLi˚f#Vc %U"s,XmY:ۅĶ6^.VdBׄW}9$piHĤH>WQRR4$ ,$F\& +Ɖ"J2[WNd`&_ֽS؜96 ey@? qH4O Db0uȵu~h@.":ѳF'0P9BO6R54Itv "zV bF#g1  3|⠽`Ф"xNBcSG6I7ugB?Fklb=Ib9KpW,ڌС jlt;N jWNߋp@mğHt=xūHe YvDBT:;O@W39d0[uV"I aB,`k\7&1;!EwrΞ4E*u$|3ls#@ңIY_T ΃a!Cp +-ݣ(foZe"'U@ư5hXcB‘BpE<#ؚ%tٍM@=_ר +܅r+PD`Ԏ!H/7VXe +$DGo؋¿Rz0 A +qV*ԢFj:Nq\h?:Hx| +|^Sdf:& Y8wd{QMP. endstream endobj 211 0 obj <>stream +HZ rPUW8y00TU endstream endobj 212 0 obj <>stream +HW[l\G9։vx;gmߒl6=^&YIsN4g4 DkQ +ESJ_[| ƧѬk7+߆ǻD՚kD'V.I.q.VWESDYϒ*/ u߉k?9~ OVgJ{3jJ{<ޗ"2^W:?TW?nlm=6w5u.I䬝qLKy[eqY-H |τ CGB -7mJ*$sM6佬ԺίFi3md6k2儙F48X"feT8ߋ{Y킆\ A7:48\=8T}H ҭ-u>I]Sj]lϤΔǧL^-V`ػثGI͆s;0a*NO6.ߊ yCy:'yIpԻM hd2:HqG<#b_IL v`i,ea"H0FS0aT#<7R:)e'"Gm]T%ɁefmDCᒔ=|/ -dK lc(or~l<.7.'6e?O?Ez.mlO9bQxmiB`9qg@dxIdF) 8gs 3Ap9l pc8A,r\@(球"rACN r䑃`9<y$tɫ'`𼐇7ٟŁ~CȾ!. +ؤ^G!^R ydzsBꒇ,ThO I3{sb11! 9B24QB+)%d=yRQsϗ'!~H>ɻ[;XCR=׮45hJj]Fs0F198r*~tvsku/Ui-P/;~pprOU>յECɵק~_[uPp+rǁX4~(z Q='U׾9^wTG 7}C6AۨWRBDөD +uu >S2AɾH\[6"}I@_h/# vخ(oOoҎ='_yK7&8?ՙ +4G3^Vc!>97_?7;D/[WiGXrYEV0NUD*gɄ5:mT|7 їT߮k?i^ۉm 6 6`$%@c^!@Ӽ]^hKSiQ3FKUKj5MӴ7i&m0æ4Sa \cY}{ 7^e1Rߝn ~ﯗ'ͷ}z3q 71wPdjoA5x2a`SDѢa1 Κy+qVItzO˼ W$ZEi*N0v*TNt2D>z|D~}(o v%%78s }"X6+w.E"9lݿ*I}] uYS +@~=Dȅ.a0AFfF^*sC4"`Ll  ~*&b+/p"Զr贕N({H'x1OꆢJ@'93}YZSg=TJGV튤_\l{y[8%jg:ZیFFM#M$ +# 78p>!b#B֠L(lV1Ԝb|Q֍үyj - 7N8yu1.h5{䅥s+c-NAto>f |Tƃ +X=tO=%X !6oA ݇IQ˾d=S4TՕrnt"Xd/6,"Oc=bd"f`G'ӧD!b9Gn(>wyd?VoڏE+ͳ#B"TYU S;V);#k jX2et$$0 5jͥ)R Sf[46F3\d2虖cMo*{uKWv kO?/Dn[YFEvk_o&^~[L]hMInJ?sr&6e`8gaQi)F0!/8#* g{m:4 +b^*PU+ŗ +=t!U3k;mûlnp):؁J:i ۆ uk(*YPi G .\2pU!(h]2r7F!&`gij8"<<Ͼt} J{(w6g*+è,Qz:v75yLTX#ѾU(JK%*,A ,cUnS^|K⽾FTLTriRnk n_75p5 -|ZH#M騫~fҗt{tG#%En-D]]Q;tu}́V[QMj+p @ V 0f M>@`1!氙3 zt0HKSaPQ4c%Qel̗sKgml0[˫ço*x@xQ(Qء΍bp))S9(T)8ָI0:"4ɓr"Ԋt惱U:Ace"Ws/: ]ɣϟE{Έ@_m9G?UzBnmIpf烒AQOD7HV"'AO;\)Wa-Tjᩔ94,Jf*&qd%jߛ%ƅ^gL%F +sS=VN''mڵdɮ( -xpK!}^QF+d06j~mRQ8i#@nQW+Ikh'o7H-H(D%=VC!Δĭ4cuq?j#!aސZQ?/%7ݪĜBTS4`wy;0 +KUSZ+DSPҊc"cѲc7cI"6 أO%]錶+(]rCKj:'GhR$5Kk U%\ޔфKࣁݻ;u6S:L0Wpf(}o$`T눋(=k;^%ؕv$ae)&RM3tfu7s1tE:VB<=4SFWZ0n)p8و\뚖5E0X*Wfb]63iF{Qٿ dK5X3ܵs+o٬Du8ЦȽVH6 F/!e uĘHC2Z`ťw6$f!H:@fD)Qy'SхLjj&j]IMMiF~1yRc{t/^Z0)u-p+딄 Y_Ps%G>P'U~uXTbqxsEʜYX0"$1e[cb_; z-<۱K=mB&+X(|)Į1Xٝ;_.m]T-@8 7]*C5n[/B==&^ˑ?yTy 늍#gk<q{ܥs#zH%0]Eȳ&#w z`@ -FJQn$T\GRON8c;Dx|6}}M5IТeѐtex]#n،iďM Wņit?yYן@~'k{DJ\/d'_!}>#n6^ %8q bS+—N!-J#rS=8OL؃w C~$vv agA$'azy!"8 +DTHTN"iC"9EA&{i%bU ƎWE^BT⼃8n]"CZy!T"^r /&vq(5PD>o##@'C9PD6 +9UA#MC| + +.ApWALM 4J#B:W0cga&k:[b܀5Jmx6O +7jbh&˰Lb +)2a-9mdM`F؄sL!w|5F]FqNugUagBD% f + +AbeшlAVUD #N؉@Fl3H&VET\pw?”9{}{ruS_0X}2~ws ]BNYJ5O73K4Z}: V8G9biuLs#v(ե˸N c42%a d]Xɨ\/Ft[2E|eؚ&ԺÏu'7R\Z+*kiʛ*kֆ5+1pZޝX U~90X\_rmThVv*Lԅ]d,'2~Aq.ۓZу8Ft s͕"nka|Tȥp~:r.>яĥ'WF!j׫|2)5hE[Jm3l!2!jmM[4^Bj>- 03)VLpĦOy [/}\G_jGJ+u%lU߭60qHsʠAa!5t-㾳ۢRi=hG5|G)Ok={1b^>p3\_Cʠ|sJ-5sˍU;j 80 jyߢ"ړp>,h)@tk8u[4YhA{i\n a*P۠P&j ZiL#DOZjaVqRtФh[1~mOct^#Sz;Z-iyx;y*kɛ⾙9ky?umIPw*Kyx255Dw,rq[ÇaMU_ƻy3; 3yts8n>]`2֓ wd֣iGL2Bku4HDD*z-Nj13_ ]߀_]{Np!^ިFwMGҿ8:C]6N +oЦx)1=4i?VGS4 DL}:5of޿:iV(Ì{p܌9}D4&oМ(OD-X)!y_ +u%בk4s74* SihB|CxZ-M2#;ZޤJ39J5QZ] +ޏ.hJ̦&jC- ԅT?!ƤO]gtE!r1ѝ~x",rjy6zMF8Ϸ(EKFV`D@5bW8Mo;@wEX/͹"r: cL} lG^%19'|`sXcR< ށ=I{ͪ7#/qt:LdQ +2~ *`׭H# 0ˡslYf$ڎ"nA$04x&X ,筀$X oë5 gAeRˇ?سX ᡾sx`.$x렗~`_ a$,ɐ??szhjVO(&U\8,r(N5HhEW~F-ͬUMtzJ/:YHg2v +Zca 1y9H*,O|E2΂\ ͓FtOL [4SCobL.2n~=7yFZDc'2*qkt݃u8YG̕?I:0Ϊ!.Xnn5#/OA%W@:q8{3v?<2R9sk%(h7/s粷;=ܓ=,?7 u,̵ҟ\d BMzc8aV8r cOXOT:961d;ĆUN8]0H3 <K=$RyW~5`= C@n .ywd?mzJn ͜5_S(b+XpFy}:4/X&,P(T}[g.u3{VLM{`랇3ۚe= ѭa蚍zóa)yrSsuE"S-\소Kkt0xM06Q>'1UxϮ g>39K=+)I 꼯/a_?[1dx,yXKH>wFcl+AnY=w3prkB44h;8D9=aUiehvO}J;e5֙+-s^怘ѕ܀;cs4x DP>|)揫cc?2\ \ rGqM +j 6'}uy6Lo`_$Q2./tݜdr\hۼ۽8;9ck1S/$G_p[ A^})qHќ0иn΅b5e7gwF 'oa̽ؑrm#緎_Fu5'JO mV^FG I?KۜV JpJh>IS$-mmQc1~RBSmZf~ N]bgG>4j/Sm떍S:Ⱦ~.dtieu3t R#CQZUd%-O1%Ibo)(Qwхhk W4rP6Wi\O|'Tf9h̝]e]zë_7C߭`k>eE8=71O#S/Sd<%8YMW7cf.{1_S3~2̭|oͩsx-S(>u>60p[6)v'BP( +B +Bq]*>6U( +BP( +BP( +Bqh@x.q7 l0D.TIf2]9;A1.Z\,Msl O[Q6?.ciX"튅֢@UZ\RRȿ;.+uwjڛn; +v֢D"ӗ _ ZguMֺP<H[Zo Y95D$gՄ8ۂh +Yjh-XBx8fJ4D"ƢʚL\~h^Ϭ=7e/?+\omݾ:Z R=AHFʲZ2w6xPs=>stream +HrI+P^5N XwF + )ডTL Ld + endstream endobj 214 0 obj <> endobj 215 0 obj <> endobj 216 0 obj <> endobj 217 0 obj <>stream +HVyXT?3 +Q`M0*+*\@FdQQQwcqU&j~qKѸDmM3PƥMېt1HWw={kna ?.!2 +/9 &v`4@E.) gd5o-t`$k²33ę dϲeGS}_K*noDFNwŸ^ +j)Ay₦iμNxҧ`488 +0|:\o7*E b<'4irM~Aȕ-%+m tPAA8 t#1ݠ;r4H ي r!f\pA!BX+UXjL8HK@-)F?&ݠ'*BDh1A$b$80s0p,&щ3 ; xc^Zk"@)W +?`ExR< +sp48q*#18@Nq8+/^e~_" 0#3M 3 'wNC5T8J +gO@Ǧ6%l)vنBCaaMuee5jhl^ #j[ժƪcIj:EG '^m5uziZ6G+ʵJmW;NiwuZ5ݦz>VO՗[mަ:ۺF؜c`G=l^أz;ؙ=hoci?`fa3;;r#ߧбkų,W.l;hp܆waᦲRBbbc=mmw:BoƝVՋm{ Vwբ%@sinB{]ۥJ{wgp%f-%l͸l3|4qXsۯ<ȑpIA44/OL +$ + $8 eՏj]@̯{*U޾oQ煴:p@Z^C551_W6ǑzyNn ?xz$zj<5eţ{B=ji~d[B,Ke%W|oL0KOZ?v[Z6X65Gfz~O-#^\TavyIlL5-3JↃeqT+ cJRK>uH~TZɑ-+&/)Z1dkP)Uv ;%kGI]S RԆD2LP աʫ;@ϡ<|ytσ> }"/[| ݆1K->H@p+Bׄ?6h:E$z?0+z XhHRD119|j%H6bWmhXDzY,a5.VCGO#J[(Je4RyJh: +r;T&S9;Z/a+`M!l(X6X!Fl+bYԝ1P6hZoJ`>~^a X[Vj +fY$|dĒYԮEŧR6YKt5! + |E8"2eW(K\lqf2>X:Kew,5 j^K:G(,9O=iN'pat|=Lt 预lU4XJ-HQIfJl:tuasyY +aoDE CE=d؍(2e){콗2VHB $y/q_{R? `ZsUT%dQUBmhZ4 f`[|v͌fh6ޒ81F9  ʞhcɗ6F[Ѷh{#ɻ\+T(UEi(=y:?DQ8D1)|&.erVus0Inm S !-5:y3a}+*;`9BR@J `>,/a!|rKw~iCe~_WU{:T5CP7ԗClhh^IEcA-2kI-e|]VFE*!#4 qZUi*m`h5I E(M]5:Z/ !%t֢i%IQi},%5FDe68ʹ̯IjwKkO}ׁ:Dp#Cc|[L9cRL*u+}&e(ofǣf`6ysCcS7RWJ7yGƙ9eN39gΛ_Qh.j$h榹mI>>2VbXU= +?=,59=EkbKkb]|hדM |K/:|?Oacl>Ym N0桬7L&**a&҇Ȃu`ђ_[mQ:kⶄ%m)[Ɩ73Wle[Vm [ֲm,b3$Wgmi[9m̵l=up-\GurKp]\+UJi-oڊr]7uwm˺Ovu{|o1j"&Sa ܂pA2l;R`'O?]Ч/N3!v= a{샇Ȅ7eC8pr<㐋MZ}@[p݆&*ke}pYQ9LyrnmSNN!lpځp989`zBO=쟑a ޴Q*ㆾn<'<8h}%_Y.s5> C΁7M+ Hu$, rX^Gh#8۴G^ Ñ? Σ$Oq/&.[52 .kHEq]4^1 Cn83)fq3| d!w"܅Ru~jPR-F<ԂSK@<Bej3Ϣ<:s^HWԓN>BC(h|3>|h$FEŗo|>k4h?p& 2x؈ 6o%ZM;ؔa3ZiE'XN_q*"NK]tgU+Y.%C=ɖC9>d)4H=yAH}vcJ8z !b!a{m kg!h%`.׬$dv;Hpևs8q8$UqRI/U&JB\T~M߬:."'֋Zhu8&8`#lgYxX<*&a?셃>K<'^ϋyClwl_lo@lOl4ME輨 !>E pCp $̄Yp#$&0a)4@a lw;cw‡A8'2-h(6 Ol,zVa` +6=]8'/?OE |>_! szHACVXD]Sl|5oi vV%N[ۼ+/mnxxgxoGa(:} z2/'P /Ky| _/6)Vp9Dn"n&*@׳jbTS583 +ZuWc)~:,RMŤjvcś*o[\*) Wk@tzܠQQIjRlL0>*CD6<6Sxi'mX0д*(q1֪MvȬ*Ǧ-#}4iLe2E?,&0M1.#2~Z\ehFq!l\~|Ca;"NauG lhBZ&1bsϱQm~KS-,2ʁD Ɂ,*GVQa(jnJH(%2Z\-jImbg4>/q)SVi/t+ꦉI9͖jHNzhRKE4L͂^T +XfVO%)ׂCghŶW4_&qNx#>f)R s$#q܆!W.'VB_3MR9Z*[U6vQq XXo PGj:EI]!M=iF86Kq!86"JۈC'q2C8C`ym!ZhGOhNK-cEȾ=Dľ#DDR1[iRw{BDԽZ1FG?DD="N }S&ڂڸ9{$ @讕VIHK,`F\  H\M_wmb'dj׵񴍓4N&Lg:i'S;iII_m4CvsΞIGC +#8P-h-y_$A"0m sHd2arIPIJy6eC*Kϲii-5:T*`Uh(-]B +o*5+u oEŒ.mg]Ht664ڍV7fodɏ +"->K%PWpD]*S'V +uc}A">vV g%H,B*DYG)T\Ah016V!{__}~\G |c^;ۗ wcTK8]ܢS&!!MMo_ݓ>lf F1N $y̑Y[~[.ZI 6Z6Q'eT̓3Á}$[%% +}Uttێ5?~5JҬj59{k搠Xʡ_OEn {27<K@FzJW#DoȂyh~k6#^jy-/8qfe)R^(< 7'nj(Um]Y:).ߞéag=5 +/BkG%q BQBK- 3$fr0W6M9l"RR׫.J ^r(U:hZ(D䨯3MJ:4v?Jٚcmo_hP~+{bK7jmQʝ?]=ZW2Y_v~Y؇eZ>PdRQep ɀ 1J*!0b4ipF^oANg99 r.! a5Mgzxכ^aiՓDiof 'd땽U~pC$N'O|uv^#?+G`D.%(ԃ 0UƫADN)IRl/2Y%`Ŭ/}k]Muuc] 1 jD_VUxpD r} +-w4N*i)DzgG5pt _ 7Jojm<2cYY˭^?qif_c7}8iw8Gvgl2Rjl{=>@lZ$5mV_ǰ[|=㇆ž]cM\[Tjg~ tvz4ɋ? =]t +:7"{ǿ (+~'e!,+", ,h@|AAVm1ʨ1)N1;VJ:iL:LәR:&5m&5[ +9s; 3K*+W3;`PZ#ad%޹,h="F_KZLC1 Cvw r2q5yAE/ʇ6)KLgh_}LUЉ +~ >>eLη=l2Ƴ8f| +x9']kgL)kyK-•j/CU:4tV&aW&]-usX#E|\%*|A_,aTop3r%c?v-&5%L* äՖA+PLhJ,%C{O MՍM P8~}j;+W36ve|ln7F#7z^S8Q,Єhy҇e6 +#I_=" +3>jX + Ȗ] 5ʡS"JM?aFC ?(e1LdKMNņt̂?.[1jz{zWKk:Q NU/݁pî`S(Wqp{qYcYRTRE)*3FOكBlh?h+T.4Yq@Vb6uZx5x/%HTYEyf,$O 2i$~kU3M̴kOH֐8bZ + +Ş&;Ϧ1V!wK91p0 ϑDV8<(#"Űa.7+΋Hak큅%QַEa~xɯ|xKtr&²55lZ\z5$zzbsgbs`adQ5akNSRQ;;STXXt! cܨ˨ f* XaK#Bq7~Zv)ѵƈ"ר\ҫHL?,0]&T(eg$0D=fXaqy:y*\QM4Z'M`Զty?FRtFTu  VAq d-&!ZnI|~|Ę J넯q%?@;Ft_|GݒNQ4“(⋖3iF(<sEQK )7[s~7 irD'K+B(Z.L0Z&J2E9KyA(-*ɐّ ^J"l!!/%I U_LaLcGvo֫[FNoh?qYp]d5.;4vȞ}ͫG[Wm T=O}vo$hPtdz QۿtjXϑҽvIDd8տg)rfۯ)-t7f>oS~K]*.S.Ȓ)i%9P#0%c<)-g0qC@LU) h^~缠W_q'D\:B)@!4N@Uj8.:J8CVl; @'JovB]w@ji}w $ m*ͯy;,TA56YV8[! +#p(2\~CJ_EU&͸MqokY vMTϵHjzBӟBT !~ I~r<P.@賽@ Rx85@}I갍b#OiҵC+wtMe<݄y}T :ž| F 07Aa8[v:{>b?9)YQ_Lj!ϟa[o_&?oA6BGaC#p;B;~v7_|7l s 0N@?;>.rΪ8sΞ= +V)B@B "H0r+B \= B`bbbnS-8Zh)ڨt*oA3Ϝ={}}R1>Gyk!{[smJ;Ar㘃|=X5юQ{|IlJTL!Oϵߪv*zB߳AspD٬`>mi[]WD\ g|9jC9ʰ3k,(g(?Avtp}oBa-hw^OzֳZmTߦ*oV{@;˴Uiw6~zaWooUZ5^Q@e^#|Gۉ^6F[yajEأ.⮟;*яV-`L}<<7:ާ>&BW3A\@aN`\.E'n,KJ +|?O`%C}Jpp,e;XpP "0#YTe^Ƃawɩ-Lݣ25^AFOlgT1//- οVWg0Ϊɵ@m`yu5U'qIT}/Ⱦ* 98?uZ jb 0FUL +,|U V޻OG-w#_: $+û?Me*IGRC߀$TIw zZ<ŵK|-N}))Ka:yaCMzjߓK w[Zݧ +o=~Lt3s EqNHָ="OmFQ#En4xύ/ß!o1:.O0jZ5[˸5EwZB sëBc ם> ou5rɖ2| hO2Q9hMꇠ:㊝F04ߏo] 3Ӕoq=|LU"\SCNjmp: TC34ܥNN{ 5ц,'1YGssF!Wͣs풶jZ꒦B8mb^#so7I;;4`lǙݹ7[t%\EROo;zlLh]W|f{?Z1fSڝ< +4FAV^ $ϕT wi;܉6-u`ԉ|Vcwv17"7٣DZJ·U A%^/M7s7еh>3v0oe8@3g)BKun$6Yfu3ޚbl{?\TK~Wwm98V8κY_8_3c=q%ufjV+BV;/~i!Fq .fPK?q (B +l=>@KvbڛZt[ʧX7Lyٔ4\1q=Ic|ik:zY .w䍚콻wPi2竒9;x[x \/;ASǮkmgJXx hjqN5\oë~B4Y)+\J/Fb}s~z@ Q>puhN]]2 CU| WE(~t>hޡ|Sl2SJ':]ׇvy5:g9m_'=K;^k*|=7@5NBSw ?Χf6&>8V ECiK`ZMlO vbv6g t +;N N_[5W5c{v}tzg5Ll>=ڠX<1nGӿv +vXhXChHZw5&B={5> 8~4Wyx٧W3h7y%omHhڎkVACmD{#x'T ՂwzI=ىZ6iKSlo]]T+n%X`P:#|SDK`yF"ߒHg cWp-+܏;H9AR$SIŵy((Yeo߁o|R(H +w9e NwapRWy"1\` 7!EdqOOh| BJ~E0X?9G D4A?/ŵny]El +8vv& y}}u+d9)\]+7y_sJ)VyJF#EJF*F?s {>^1k?AS}kuh8y>ohCxs2&v&$޷"FPc|Cz{)Dqs5ETc~hF9dm7?N!b;i{#ݛw69G+ocS5d1.@Ma~s}'Vy^Op}B\je#(MBFHҞz,dO,M%d6#EogAigE5|oowYW JxzwRplZ5NPQ(`y!e2`|WaGC^Y=C'ŽE܇})o68wav<g^)wTo#oMx~2PO^>Coy^,#Ή m& ++z2wWyiWvKܢ{(,>ݲy0i.tGQxBw5A\g՗{W|S("̥y!~G0.^Pgnl0I>9B{ +2Rduf.⫆gPTP^#WUad7L{CޖWPo1Kޥ=2̓,SxNx!HB~s5l&ݍvBRz܅.Π~xD*6tW_f_$ŖO,җqlI/&϶2D l/c x Um z66˭: NC +_`hG76o1D3&m5>GW5ƜŎ On'}#pYzDVxu/D0 L5{,m^&r)S}-`%~ALCeAQ$Nט0X}ũ;IvWE)4}졽禟24%Έ(JIE}0Ե/cq=?ڛWS;!ô<$p =5![beKCxXAEPVb Euh%jE,`^,$ElmmQJEA|Aj`1SM@" +hxeJ;J[6qaf6m"U%mIA*b+mMMIlwɺvg +K^ +AC*D/,x"QAxhϻdSSU(;o>;>ƾ%Z.˃Up0o>'mha-ZI*:L+bph%zlEw DJ_w؀2D2poh N+Js$=>$q5q/=.1ec=ko#'Pi4~/Ѭ@ B]ϓˤ͆wBe_ryZrn]P( +BP( +BP( +BP( +BP( +Bрo5q8 .pYZT}Y!~O_ng ճ;ڶЦ7oP!C~m:}BtT:y#NUW9ꌧ,ROfd6-y^aoWW\JAYig+*YoL خ]t,S^]?OuKsVgpB$Gx&,$ZǡkӴó&L s}%۔2EֺH`RcZ6M5LE05]G)5#kצ_m~ sJte)mJpӎk۳ s:sLOST endstream endobj 218 0 obj <> endobj 219 0 obj <> endobj 220 0 obj <>stream +HViTTG5u[6vƨJtpCqEŀ , ]!fԨ3js[$jNiLL03Lty}}uzU_W׎y`20@ذph78z*FޞZКm^F̜32#VmMLOI}B7-~);{e8 +asRSgiWe<8'0),{ʸ2.o|GCXKo& 0(q@Bck"n8 ,023kǍr( ^}wX g [-^@hÞpp:cop8u7Fܤf`_'8^,\,ZB+6/A{tA@WWqT tI02 Sq@6ȇX+`% Xq8'4Áx1%%R%UЛmN3}!#&81ILEHgq2f`fc<pb*`|#5b5^ Pa C)J!VǬOȗ1 ?0ޕ/Xa.h01DܧR<Ca(qRƻ" _B-mLSi%@)*8A+oGy.l*b X![ʖ +71J o)+,>VekgkuR?mTU'TuZQϫ_zAlZ]jô$mVj&mv@;FkMCp}/+wmgkckgSmm]m#m)􎬣oG=h~àz;ؙkommob~/#gu* Y꿷^O X,McwĽUapI݆Jfk uuAީjH5wZS/7;5$0-\EH܉ZМZV۩}ЌsR}]3Kfɶ4n-(Y~}K.IqH{54/OL$+ x9 eχj]@ݳ=*wN0 _Qㅴ:Op7OZN5Q5=PȻG\g]gJ\W|6VԀ+ftW+su6_no&n3dx^GNK18T!dдE*52}>G|Ԕ3GKK%2ے-}=&Oy-Kk;-,,[]nivM|!*T_9O3ɒn8%ɖUrp\riHqɲ 8PQ"X)QJ%H~ TZɑŒ-&/ɗZQ@ LbP)UR6 ;$kK]QR2@? qR&Ie OC[Dyw-AAPEgx6Ts}%_B7R >Ks; / _:*lŸ?=+0 z!Hh (RD411\J$Pk1խ64@,Ab) KhxFHD@1ءS8GɢRy!>N9m*֋hxBD=,dyl"<6 cBņ3g#H6fl 3Ʊ"RbLlثl!eXȊMl3+aX)Y+ڵXtD(|++46}*L7/y_ɟH&ˇA~S*2(]|J)S\Y*[·!Ey*dIlW񎱖41{񼱚"/RKN>NPO8Azz7C~Kt_ED! hxf%Q&5~,eUs9)BC:afi%]e]Pi@FKPkf!g`v^엸ͯEF^фw4JFר8!J*XN~0IN|Bb8\1M'uz_0m6E-h/$\()DQQRuFҢtq #`$|#%.ErZfts,q0^]33kCbok|QI0';20MHH] +q0fL f!#\? $ǿb/r"eCP1TW!& +CP3THfƬ]sUQhy5t"ZT_bZIKP'ՒZJ˄YhYClh!zH C$%ZViyBp/ć3 ]PBZ`^jQAV@j̬ʹVFkGkgݴҾ:@L?/u:?)rě8F@}nGS.1{0&}F\ŘԁFCWs4J*Jte9j9eN3953^Es\Us0Ms6w=s_o0?u.%aYV`)lX*MWUqoq]5WUwua,]\I\Ga5~o96L-&C7N; =$w+c::a~,֡:QǞ&@#ڂn i/~A-~N7pęt 8/ +Ά+9;աx``2WÇ\r|u1a*Ǘ_q2ܔq[bnG4Lex ATSuN5+jc<Ԓ'S+By*iԖEԙN]>D0 #4>F)Og|s@_Eʗo|5lj4 ~F39sR|hci6֠_&h.֢yXcZui!֣EXcZ :<~G{?%.$*xQ^NT?܋ +qo*} G!ÃI8p- a:̀[! ! a7<uzh`Cd:^bp#6 -wooo9m|>'p/; jHB +B3,&X+DCM|%)`3lMM:/w=O_ ρJ U| _[y_[jgy;5|=V,Ŗz>ձ嬁/`V󜱟o2pE%ȿ@b:Ya4F&vmeXaG/_`Ce"5_?̾~~~~Ξg?a?f?e?ce{֘U|ﱿ" b}[x(r~P[?oG1Vٚi=4~A~PBԴK'S4 +~0勗aǑwqajEu@@:'BqCq;;Ϋ7Gi4K*ɸR&G͏Y7 ݎ+sτgFc1J!iN(f) $n~eQ34twbf,wfwRu]H~5 U+jh粎D'9 xZE=u]TZ $cT!ngʹ*2辫Pe_iI;Smy<ۯVe1]ܭtp+JA [N(n)aLJ4"\iSlsJP+^P’dwz%=(^cdŚIWF' +8`cĞ"Ȕl*E'GTJ3X0Q|L|J^ mC beXԌձ*|]Ϩ\cBM(d̴JhՁ\%T)3%H ]5dޓj2&-X]o73U i,(1ԗ,_+V,VqjRlݴ?JK +D2<6ꘉha'4ͨ_״2e+n1Ԫ|Mt9Lˌ*Ʀ--=4)LyϿ(ţ30MS1xB[>#Yy&9C$o|MIlE$/HbaZ~L*1+؝P-M߆l>$g$MLd%H +}$y;HrHҲd*hfxxvP>[RJMM,S 3Wk l-P}3! +p\=ג !e57lB*N:֟1?:<عڄZ`%jb!}DILS2o6;8q,^XT_S/[ISTZ|e[& g(DTv.C2zJ +iqlg_}f(#7Q1s8q܌!.'%|+_3M-S XjVZ*U66Q"\e A#b& д'8:C8Ӏ`-q#8\zC`=ql iB86G9@qK-M-T;֠pQ,t{{zRw"Qw,luO7@Dg7y;_k0`ob.&M \C`L1!ڤUQldIՒl ˏhZMԮ{̥RUaY>s>wd4>mpW%yEM:G)Ǖ:tMKԟ׼^jt)D0r٬SZjAS֞yX;\3~R KU՘) ҁ(ʲ19h$!(b1]:N)aP%5.- +̛0թZN/] "vHjM$ow?;GS1 PUԽ΅ᨕÎXqVj{嘲Ƭ,0tԣR@S(%%U=71r s@9Q=>FeʵG2YR(T#`Qv ~P?jtD:/jdGeB Pcx(-(p8,| kKfmZԽH ijeիk+ +^JN:^cp7P"8bCCv#W>(u4{* Ly8-'\Ѱޮ5EZtkgL&"ϋϿ( +-ȇ "524qmÄ$1 |Dom˔HYtrs gqX-!jj9Xo-#IXZ,Ԝj?|> ,M/%} ƒjeR#{BGf_ꊶ xy%XNZ<ٱ +;; *];r,0t3gכp^~ȗ\4R[f+ճӿ{ӵ`+`j| FFr[ s :) IY2,lÖrBTZVb3KE.I@P=[طQr{pc[;lBEvbٽ:׳4IMA(ɜTφXY&+@YLn,#N*N T[MeEzeItZP'(O6'Mъ7M㷎{qIg␧RAiGg4 ţAcA!4@"R T0)ʱTu$ *6e JD/J-$ˠe0o ʍ: b+r]yۖ ,ڮۮWk5J[SB+'X2. 9;Ot9:gw{6C0@ goOM}ho}bo菺3Awo\ʐDzCr#te$SF;Uqb-e:o[xvc}LRxw:*-3"73-rVw@(1NfF쓝m&xB7U.O.^^2=ž90F,4 bzԾ}<*tGĦ#M c/,@"QɥpcDWC)6- nFcv ^K}G} n^s=s+wN3C(*!(3cX˫qAlwUZs n\Atێ"/u ./Y\,* +.@|iRDPL2Rm'NڦIVP6ڧMLڇ&$M2*(f>=|sM1+Vd ++/30F?Ĥo"*]VʼܶM4[L(l,Ez9P A9RTfS^Sˌ1Q.+@VfUJAwXC\$>T{dao> GmJ9,+CZt| C.u^K4 h:\u +JT"B#rhDtP'~a2 ~ijǑ @`esG=j3#W7ٝeSBQ_Xo^/HKq':cZ_\K_KfDy:͕ޜMm~E۟`T/ح-EVwRpA#`vG~poOh~TX)hb:5\fYq|Гvhb7#7'?*⩜$,UFT7yꩡԫ5,!ѩr+)ɏL0dWxoftF5<9{gr㽭- bɛk"Si#g%|ku!'e$ZuTu[nfLjߕ"MGaX#Pfa+;]j<8F|\y(ݳʅ; 1|m,eqo6/v7k@aJ;=QGs ۡN KN#o0 V,!EW>yGQZ4ܤQF55+1SCrVs bD+A%,?Ĝic-GT7(^>K^uIBQu?h??GTOZdu;BW +{Z- FYd2HYJ.ȇ)KF҆d)KGHކws:eLX+.obm_M_n.N["v*;]GWFڭAO5\@f!/:x25+UrI )iI%R)sM~*-Lyο |7k݀} 2) -%ݢ H<f6ԮٳZ` :_k9~!>KeE\FX>O.Zvu%Gq"/UJp8w,E1-GΧqG*M+Jv'{f54\69uW{\^z*LF}h1W +bjTt8ZFc5{hTE4;G4gAΙ/+p7A/(B?~8pH݋e7.ڏs r282H5^VF\9UaOS!P}#\=yqaJ3~CM^ +!oځU~Og5j |nrCʥxx҈vbwGB>5v#TmI۩X.ZU$|Y:mTi|>9Z>KuNA2Ϊ:{~aѢ aaMdMBa [JIX`0Pe_:ġPBAAX@ZUqJ;LF}. 㙻sY-GL G;I҂4Xx.& ;R\qҨ۝ rq>|T3#k!9P^ƌw{od;$ɤ59(F@5TگI:TAnA.AʑA-Q0:uWS7jsu}RJ;đ52 +o}.eǰٝ'UOe0{YV\Go].#,TPxp5߹g]?hVM ?Z< Vn_8'ߢÇ@yHo, Y,a2@|)Ǐ'}E';%rsb|H:@I'RZEp.?`&՘02ɓNNx 5dsYiqєWWeE-% َv +Ź~(L7Z Eo4mb's.:IA[7zD,̔$=TR } ӻ8;3:]>]VWgt5t%Zo3^{y ?JE;[e2ژoᅞe_ sOʝ2@_* ya|e^>;ϥ]ぜ%Uul|Esc_o>?n߰OPe}pޗVN֚LwѪֻh!.뫜ޔ3 +-hro#{r8m_N%ճOMxd*ࡗM}+O?fHL߁219.]%gm?|ࣔMy9e[e +?DPLN5~^UhgewFh#q\7b+B:Tg>sɼBǼn1G,k!e#e朗MZA.xDĪx Mdn!iA5Jk TVE dN*ZvxHr< sKJw,A:ĸt#+j|eJ##Վzw)P5}V,q4\ ;@ʭ)>en/1tkz ߔn8UZiґcA;W}4NHko{Li˞CF%;,C빚8Xm iJ)nh&}w74:){wot8ci%}&_w7J[)s>Η#mN3Og[Z9MLzLDW51>e/G": ӟqE+?^mf>1D3|Y4</B'6J{_[? M,!-Q~0!4OG=rJ"9MiR'w5z׭BOJ^fyM=Tg+Mu/zgE@ޙZ@DGzWV]KS^Ot Mr)e-y^8k:KFbi4Mۈ{\f[r8<5WQ&}l UQ]D5>c~ʂvq 7m@*{h@+z858,S/3.<7׶wE6q}_j7ƩLbzHṧғ޽CL^a+/=Uu=M*))@ 7B( m:B@!*i؈+E*4mQR +F4&+T&{?l6#N;ǽ=[s!Ԑ<"[v]-"W*j-5<ﴊBR 231 +yN!d3/`Vpza=\~7l^Y4~?f+V]}"ay]mm}U||8'',ո3OYq>e6&(Q?v"-.91I!(Fqr:Zo38C,+\[یyf: dɰ'd7y͵O٘癀L%Y=7b%R,1m-8{d28ֵ[}Ԛ7w ށc2KQ2AyrTlbrINj;HMa}gݗc~^H~F~ %)qi7_u]"=`L2i661qz'&:#E/b4,E|W>p"+PQƀ +y\7 w>2*O"Ch#rdwGk\e^>!cId)?: rz9ei+ɗ0lTӷ;I9\kyrV^qd'I`SI$. +T_Lt,%Ύ褵[ubsZMXg&"-S<Y^iy$v>Iw$29r߄eax$ѫdUx]]7}ѻ%(t :ьZ,w* GӤ:X|Ϙ09/7] 5+3 GYļύrH8MC8#by^xqn Y2(Ʌe*wnEb[co+'_T1K;7"9Gȟ]_7*eߩ~t4DiwN~Cj?+^eou? )dv6Nɿ*$ ~C'7SAۦPk]7J5Ͷ4Y 'Vk3Ra^@t+,/(F57 @EdᛢFPD06v10c E2ҍxd+xdb1v7~bRDoDCLC ]$!)!ɳYTyԓerg'd=' ԧѓ&Lkvr] 0ZX[e=u&!/5H_@_;گ#5϶Qr 09alq_1j2fbbr_OtVXkwU@7Ğ|/sjmA.5b bBc97fQhk}a6{a,6!0-ff>81c8+4~$'Djwdby1׍|'D1YpVKjǪ}YPEZQCR+$p?9TЩ*⚾y<C;ھx: +3# +Pk}ǿ8MuGۏil>߳e[[A4p[u-sK)0t8Uk,[%N؝dfڞ#CAppqqsGvTI%%$3<-gk 6># +aav]Ϳ#aaaw 0 0 0 0 0 0 0o_=FpUt|~|,QĊNa'VtXk?zIVIo;X'0|$&:EX1Z#=!\M͟^rbz0EZODYe5Q4pQXbE|QWA9uC;aDs#qlbbFި!*e!5;QNUDշݕ8`R\\Q0 + VQhNzZ Q*N+LN 6fI-P" +̚6N8㰐q>X$ +wC &\ȩ&B,ҬDO6juy] U_Sɠhm;RvDsT-$Pu6\VZzU?M{2}O_n/ ( 2Wz endstream endobj 221 0 obj <>stream +HWKl[y~-J>Пy~8䐲(ŖӖg(Nʅn + "Emt5 R4\h6E*l>RO?A-sg̜Z yIӞg+Vr:dz.eJvL&.](+mnQ +Wf*RȸSy`sfPy#?p9BZ vTn ~> OCX˔ R,IT" *m'Kğ2\uaK>AdxL/VҶQMiE5_̨Q9L삧; ^F5c $`]p|QJ h"gN5c~RM j3ܙzcB{[оYXsҭ57; 9ME-6ѣ ; (xmҲ)ưU>x4Ouccm6(69r&Yij (ʘz+˿Y +U9V=S;֖ΨYd;g[dM'U d$]Bd&C"dwZ3Rd?Q\ɨtf.TSKh 0F4dmh$dl4F{"ZFb_8ȏToY2iICOd.t[J)wTEmp1&t۽݁ܦvpGOPVSG攓>A)C.f{ +9] pDA͊iG݁j*ǥ-)\9/[vkͥ'r&M?q҂TϦXj -YYRq(,I}I\ÿD)Nq˷54)[v#}my[Nq۲jgaF`f(jEULU#Q~E.x8*yRZp8fCq$!UpC#p8N׈C qN 8)@8C`Aka^$G AsA=yI57 D "ErkKԗD"[^%'~+@D] +Q;QC[THȂһJW)f>_{ͨh0]QƍKsLgZ̈aVX4X(TaHc|H2?H4__y؁]]Lq}ў03n f5{O޶Ύ[><1N )Z tk&wp"i -{gl_ڻv9:ۻ}Ԑ5۱e߉lVc7̃ێ;&bfE)u ~L+3è265Qӛ(^k?3ٙs|Fg8${) ,G6 $!1!|H4v6֎/ڈG&빱ȥVX_dtG U\"!Bĸӥ50 +##aayM ae'PݴtVDW9Cxx8L`#&n,ҏ'uQ^.Ǫ$脢2৙q2T'~,< X8ʑRL&Gt}%<cViYjs\>PiSJ +:O֍|sc(V/*pLȥ[$υ [ U~:e'#D$ x~'E4xbE^ [J2ДVPB_"kz6r4Ui +\S#)g/f3%eύq%t-4_&7IAwC4 Lh9t.@u D|/irkuJ2IJ5{6 qcfkIaghG +]k?s9ĂwjpK헾zÃo\ka0 R_ ;3qga1O`='Ѯ@Xt>#pNF m,^meQt"MN[+L{_|?s1s`+;*"9z%%䧌)!!nME3BRG7CqMrÚb[y Z쥼!/4` +(cZDrH)eW[7!shgYٮ&UW:e7-9>V513Vo]7NZtdwȚ@JҢ#U*%A{K_%}Kv䱲Q]8akY=01>+vX.,pr&bL&;p1ftv%؟蚅P +(+ ;0L ߽ V#?HO|J1Ù*sNcvcO,91 *o% #!D߫+3eI.iSponu76v:ΑϭXQ@=kESu6@A/t:|$~̫ #~h<+9Be+i(i궊 Fa2V6QbkmSd+',I){\WӦZb)r<ӿ8(ȵؙ/Ζe@L/W!W]fa(J-pcqptvݑINLr.&0EX>j<ʝy\"3Zuqg{&$.Xi-ͧѧR\oC-TLS[cG5?Cx<$ @f2ɌQ8T botAzBi>r3Z3Z9zL5/B6nZZ^/dZnW {S7M/TV w/vcI5g#V'-[m3=\G=7Zxᮞ&p}CHT,p:bT(,A~/9Di)v$ʎ/Lu~5sm HUj_HcXا<:@QMq5\&>NYbmQR* ".`z A-MĂZ3سbȥ҅_}8;Ӗޑc_\lB >7 + >;.zU:mkt'@ /Fw=cܡۚdžWNw6&]Kݎxsha"ޟ@>`:L2C&]A=訣LG%`\ß,e\^fپ|DžO¯yj53w]'Q-3jc4!Qm ]ɨiWG32Oݵ6e6W ⥗}N|f kpڙ(.~, y*RIE៉m\ۧ$5J걣w-JvǸ [UkcZxjnaiSY10`Nz(f7lŃ6)/F`Ҝ]7U&a. f`ҳEƍ?cc1GNpD208Ms +L#<{-vMEQVC@pa tvi`F]-gC!q,:H)皳T/xWɶKfIM E嬩.U۞Pv>$vBʿv=>?eu{}luY<31^ ` 15Z aMQ68"7"5T"pK"A$B(U" M{1DQVetgndkV[Ùa!"BV0%u3u,щ+g `z"&֝t66$X",8GN8󉱏Qr/=$Ou5t{ mz٩*Y!`!ҡ +J'ZW!+#a8bZ: PU6#;Ĩ&0{`mcd}'ѾB|I wvOCX0I}}QʮQ# + +-*oKcRZNr)P2pHxFJ!͘hUИ¢b d:H@|: 0N釛UQ*`ѿ&p zuGPf +%lpmoxpE#WzGJ뉹\1vGD]S uځ:哢dA# 3O@Z£>+@sZ17=vE/VSI-U] O*ڭ]~4U_6c٦1_Ȕ7' eVJK /Hя]E'g7W4UY#v vQrTdBi@*v%#&<9O桛HSu +O \N Joec%2aMz9RGB3_FW16$LdX5IsfLeՓB[$(7Xّxv^@8TO=Ɠ#Nf0/'ޛ(oYZYDehK_uƐ$K9>ß#9~GFU=џlݶv~}b;ڶ%M酁XvbӗcAvS? [$s9 dPC'؂rq@f;ՀQ՛U+>إT}ŧaoߖqMj^2'9w^D$,A̸,e0R ߕyyanOw0J"~ QIpe8Ļ%{G47!.!{2<LeWgS`{s- L]9|[ck6e6 ׯۯgAz-Uܔ=S:y ۏKҜ{SYU狋6ֻj׽dpU߿~Hަh-nx/bo9\K}Mj:yq2MavIȣ3F {5vlΖ,XW9Z+RoY& _(Xɒe&v'N(7_($r.ю:|;C iV ި 3p6*3۫v¯5n y +`g>N}=j5g_ׁշ0xW35/WA#B )8t`܁-k\JGk>֯.(àO7ZZn,"{\ ;+#)/ȸ FDQ.FHbRWB0x-oDsogv",^%> +$d,drԁASvWAK )6u,:xpK8mt kWn1W{P?} % 卺<vY܅]ax.!Q@"ADEm:1Zh5NF䏤;ij[)1N.3e7ܻsy;Mުt-GU@mvwܱlٺ|8.Vs/UܔxbΡy3N]_sχlk0x3ȲTѼx‹ J NQy/'JLE'y[V%*JG k Mel_ I/,tl_`[k顣ڼ~cؔDmd\dVT}X]F@P H +y{J.X ִIX(?͸`uxqo8dž=I,(@fnq Y47M]?Qvu3S#D$ls˜ǛN'=0h.뮬-)ulX^g+2uPutt53i}2ܢ3txħI]܆1Ƀ j4w(zc豹DF{:4A0AQAFz\PThg*,XCMcfXg~f!}<~}%2Y~#%|[{~n-yfS&rkQ⨨E[+잩2=d(_c~Xk^^{`h;\[֬ }\gSv=%y$-=M0TjA[A3@QBX\%LJI%DiL.t~|Q ?Az9eHIZz}96\-U]3 J?%RkFivSǝ5z}DuYONWSV]vCjorB.:[ϐ;)ݢY<Գڑ;ڰ耀P_PAôRa@XEb@NxY1҇T1/(}>% \vk'{Ш5aߋM>7;ƈY=u..5+_.Ϳɬ_^#?qN ER)/5LKkaP@´\_/@4f!L(BQ 7TP!e^q+ȧ@ !Ez*;C*Y? 󠚗vTh׺u*X<<`TQ yyd#)0(g@=x,WFq݊Gt`T2Np"0&W"*~!h\,`S^CZ :Gjd5Bvu>`@߆ $' %A.5h/]H +۰\ll/0’% &/d +h$`AK`!LAO+qC)ᮻT]oߐ1:ЗPC%c G>=, V 1H_ߠ I*RWM Brb b NK~a5CoInw B+ıQ(ݸw \Q#y'7y|yvRHVga,z-Ja;] +ų\7P^8dߺ s\q~@n & In;[]"0ƖB G~KOoޗa?lD[0T:SD1- cʿ)>_@"aL0|kaQ +-4[ aB!v%aZkk2ځb E`V: +:3Lg?yss~zy(^ *N1'{w]5wxcAwxFs8:K\qok9ϻh"p֔icf #.vualXKZyƹKYkmM۵ԋc*}a.̀` _( +  #J&C,5F]cvmzV'75?3;=\ 5By9^W7/Q}g9+".B\GvWsF)\VӢ9v|VƕПyAM\XCur{ Н\c-:=>nKvWG?"N غE&sg|+NZƾTՇ ᫈Zy/γToֳ~xVըMr|{,gvP'2-ʊk8JjݖN/cANu-SuTEԇ6YAN׸X{;yczf-nx/3栙o0Xw'UneCjB>+vk1,Ӧj_q?RNLrX{jϚkמC?62i_C5TOH^T}/%v";u:rY7d c8^MO}]_&.  +_sƘSxsWurYk<|,^ΪyeާZ;[mb~szSgao~ .p ,P=덐X 4{]]=Iqg@MKg*?Ƴ6RM;և0u:Ϳgk;kd .e_W6(mfY9 Aw4Ys^gEЬlgciz#Q?Bm49v)~:d +{{^=+zǯ6W~V'YR}3C@-?U}Ŭ3~:$?Գq3h{Pr~(|= Ϛ[WwbR.^OF[ʿ8hR<h4^>{!hL 6t=Fy/ݱ>畇OySv%̓\^cƵL+P[@BpjPs5s094YKb2mU;fsJ Cci'Q<CYFACjsU (K<~tChi:>9pSi([*&]ZSCmb!(L6f\S2v jζ&ry>9 5s]<! 䇊3rhX X3!' {iF(cB;ʷ̀oP@KTFm{Ѿ[2~k{ Syw~imgU mS8n;27yf@ J)HGwĺa0lKk2Z}ؘ';G-A16G/ awb.z̴rlB oIo[$Ax<{eN,jU2F9~ON, $̣8*QێcDq.un'x~2‘u}̸9G-k8 )ZMDɴcM恆qCpwԜX~>Pw3TXV'A6"i_o!v$iM;LR( FYsϑ!2'ͥW]@5`mZD!l,mA3+tkhVFe: ' iՉU__Wx)J 7~(y'm5]VO*sܐнwS:w~~83'| cA8eF_iQ2uHi +s߯e`~_Z/1юXMsmg!ϱ>CGm;ʨ%2%r5]Npx`q~sT{OXr 8Xfp%E$+E]48?Ҿ&濰wԥz5J$N3`*3?N%E_o_ہx$I$M峍+ƫn\ 1ry$m1Sy0 m%I4m9Vkt7c,c<ь-K~)'Hưln!膻1z;#J;^Vgt2_C+Oծ(t%^9K@R~v+504spz.aVcq٨OHEZ :.ߊg,YCg/!oArڼ͇$5~`thWG\mFI5lҊœ,23(vhYSՕ2npwǃxPw܋e_%F4N t+<j=|}TG(  @?vvP دtg:FkEO:U\x̲joƌ*8L#匿&B=Z7$:*b6U0*Ѫ8mCh+MG[T !T*-Jl9旝$xdx_,Cz^i1^{x#}_Fz&lgvXf[,<v5ޝg|d\Gw#ߥ=f)RO[FƱ S.뮺:p/Z{@&,ClS%@ecYXgfΦ>Q5Ώ7}苹8`vTd*U\v}^woHECh:V>ZOڴ{F9/W)4M8 nj,ZLҨ$LWwr ( CP t#N*BV ϧݻw~wpÛ#ݾBاm=?[{.?:cű[w +@b44=v mx%{D.y~&z)_d@*% +ns[c◧oc T{6O4c1cOZ.%:;c0c1cmG?0c=umRhfiDt#Wi>G5q,cc0)%vޏ$8Bx|Q80V(aͶmزHXlZM. pnUQZ7 (鞕Dɬ-VZU^W/D6ZAuX0)kZ-r;Ǵ=WserjrDX\|a!So ?+t9zhNCX7c.E6u!jT'Bilr2at-htjQPg.⬀INJX)-7MdICEMT3hЛ ݔ +*%{m +J`:r"M@Zٳ*]B2f{o\]-YH?CUsQXBeR]jr2]{у QGN b5spW)g@΢ fn^\|JGw$4u-U%a;L >Utd.Z-"ko/Y?Rg#VE|L'[}B/^-.t endstream endobj 222 0 obj <> endobj 223 0 obj <>stream +HN0mYEq<ѽo \2f(;SW8gFgSYnpN)%p}b]5vv.}?8@; GV +] FH#tYkIǞTcI;]I1PG;(]he_BC:!ȋ|%!UnwXZf3ikӬdz'k.FGZNI5{m=_F^" endstream endobj 224 0 obj <>stream +HN0Kp.\ +(U[?IMiZ(>g#W#WpDb ^X_ecs\z78 'zkt=3FWH3N-#uIn0x@N2L- ;i5T +J - +r + !/gYjM&ZOL7M/a\UۧfAd)U^$bvWWًq endstream endobj 225 0 obj <>stream +H$nAKX YĆMB !ݎk걪^Uv Yn\6.Cf=fwYw*8Г +npp밇=]U(ݶN]¦ 졃%[U]CoߐlZ@4X)m{Bǯ8,%zI0IYijgD 9-r\e0"Ã4 kXjdkXYN G 5T뻙0jQU%e, \E\~.OE?yŕS5'[x#䕐Kx-1p% Oy2:qtƗc~;xC𔉛猍d9[Fg"a endstream endobj 226 0 obj <>stream +HK0 BB`Ďŀ@skBo8Iitgܾ몿XCpݶ{wgӮ hVIr HY0[f\\a??!#e!#d2]mǂZlzr۞L2bS?`. d6j z#> ?\'i6>#Uߥ`R%cb( +t fe ܃6z~>Zb\lyz¥o L[v5qrTvyq,7rŷ]'z=RgpXzvX1WG[]~Nߚ07ڜK8y/d@ZP5U<~ώWGo endstream endobj 227 0 obj <>stream +HR@)_@XBaLKI'}; (>',?czczc,'7ir|g O86 itؑFc <ǞBVCtAMz:bTג-2PK"Awm@ThlYHb#nbȢ7/MD' Px$/kbbs +3ANhr/t@gx;dDŽwyywȼ{쐝ۯE5ҢԺ"ݯlfi +MS$0o=^ߌnMmed_2Rp͵ֻUn^*K9Q+!B_ur".?qsl1qc"=3W|Ɍe{Kޱmr/fk endstream endobj 228 0 obj <>stream +H$IR0Kb B2rˉ-K-Y3_= v}Nթ 1z woet!!awwL` E/a2- B'Osfd:p`;.]wFqiv.) hh-4ֈښk֢ wɺu>stream +H$Mo@W +8pBBBBāH $hR&;ڎ$MR/~gf6>{~Sjzܸp~wd8̅,)fŬ Sβ{0C=vŶua"Sۖ-Bi-7nTli!-&IuceI_Ss5> J[n 7agi<;TކYQzW;^{# ǍYvFj.F9s&j +PbWؒ!ȪX!y,lLu5M*b\h\&e4r!nryU˲Xb/EQ{oz~g_K0OY> >CM0~wI2:[)ox:ǃ#7^ q/Dt}&31|&b"FS1F +0( endstream endobj 230 0 obj <>stream +HYOQ511 D HH[hi;]f9̜3sY@]ɷwF/=z1`p{q׻|pq>99v:y @/ЋFtEnYwV]D`X4agfa˽wwzj +4(opcdWrJoh,tȜlX 5 +Bl͸14XM6f$Ƥ)AF0Y]%M]œJuI+W*jOKBݜks]JǗJ(:S[ge^e<-iQ$/YDe}\|r{x|l6cEO!] O}'GM_69$ s?%D'~1dAx, endstream endobj 231 0 obj <>stream +HN0GDEaZmgHbڱ(ьz_8^#) ~LKN{ 7(9!QT韉r"H%J#"G1: 20dH8wz@N+(i'nxvV:oEaӠ2IpM1gڙ֚zcMfjmjiݼ_vжc}4[ݬn^]K|~!⒳s>[< endstream endobj 232 0 obj <>stream +H;O0 l 0 0 UQiWB׎ 9/z_4лС|Cp"Oîs +®Ҿ#t6>a;H&:Ĉ[u$Cw>8&JCB ]`ehq"|KSEneBa@{ȧJ B;W[v^A 3$0F+0 4˭a+XZݦLի| +SSc5M٠ú^<2=CYݗxSrr+F+^/y6S:8b͟hp^M' om endstream endobj 233 0 obj <>stream +HKo@WĢBJH] *B@ᦵxfӦ gX|suxܺ|!߃+_[~rAat=6džD!my'<`"[漑7aӣdށ>&nn:L33;ÎiP]+3uȠv-W Uf 7;-mZ*jVZMєr v]LCVem)ZDc<~x(P:yI3S=Wo :}E1&/H='itD!I aL endstream endobj 234 0 obj <>stream +H=R0%(Q0(` X֟Xڕ-NB p7>ϼZMB )X^vIf)Kb-j.#ͳ9i f8/}1f E֨΍f Ea 3BHc}ϊ\ҹԓ +=I0R"Lf,{B; INbOP;rֻr;i˦>stream +H;O0; S PT.$c;Ic< o}Uv}͡;`la;F:ώѳj}t>`kzۆ?w;-u]˪mp}B]9: +=î*5']դ|\)r,*zBO)sZzgyRS:$wNLRK cNHK"&7X\4'+YMVT& wlp62XOR(EfƘѳ2󁒓T^H=\xx$֣3|>de endstream endobj 236 0 obj <>stream +H[N0u-HbhP q؞qb;-{ )sAé\ X`CƖ庉e!46E];l' U$$F3MC"l@ ! F ԫ<8 ʂvZj%^{wmٷ6UW7nk.hqchqi~34`Tʿ endstream endobj 237 0 obj <>stream +H$˹N@ Ф`MJBHiEHq%z dq{{3+LC *}M=Jܠ-h XOzQm; n*+sd\@ +¬ L)g١L5nЍ 8,!5ү%I#h2@$ %=\%(Qs'ĕܝJ +'TCD.]cAo.yIS5MIy'I$9x$d֎}OprknQA[@z9zԱ{t=c5?%$v'Q3DW endstream endobj 238 0 obj <>stream +HIR0eE(,rXdZر/Y؁hxտ[R3:^_L٩)aOa)9t _'/=[a-JH"z Y@"ipt8z'fEZfuNBIzɶ͑J;d{m*w1SvVZZJ^b,I#ۮl^tß endstream endobj 239 0 obj <>stream +HAN0q BbAUZHNĞIbMS(܍?Y<i$"8oVF"&{ +:L0cG~w2Cz{aivɈ= =i:@ב,Dadw[*\Kiс[lξ+cܪ$*3/ɕwy]&|}Y*֮뽮Jr~>stream +HMN0u ` w`"U"Q38 - +wћϓEE_8/PwgW|&P'1ǩٝqgb۲evfKfd3L5ӈw@ jddE##5 @* ^H!UtS9)ǩ- h4fbCb_W[zݝvZ\kQJmWm|_Qٚ endstream endobj 241 0 obj <>stream +H˻R!RjoggXXh'̺f/@,n,LA]'|^\g +Y|N##) {N G>D%S":^G8v08p~#E_N"E9g#wY$H$Q`6`9π;zj hOƻ΀k{c(vukMM*ٺt.YFmu5Y?*Z=tbywpۖYxiٟly endstream endobj 242 0 obj <>stream +H[N0!{!TQZ"?^7S78kC 1XdlS%9sf[2S-zp#w6]bKdr"cȓ#o*F&""x4pzXa4mI! ,)tR} Yt+$[ JZ`' ;! E$Wo`fϕ|,ֳ[mܴSӾ?6 A;Robv%Xͮ ,v endstream endobj 243 0 obj <>stream +Hn0$W+@tmQt`؉IcI:eZ,;_)4)ԧ7g0ק1g d: G<ސq:8' ِa!;Ž#|LT#}cU I{_Jό W)^DzgFM*qAʤ W&rE5>eWc :Y7Y:+oU%t0ȶDU%ҫP [jlpʱXaammf]lvvasv}lWuŧڬ.L3?7sgLS7j~Zͯ_g?Z endstream endobj 244 0 obj <>stream +HIo@$ BQX&e<{tm7o3ׇOUUw/|u?a?ߓ䪻ɉ` +͈̐/@F@wq?^7]`C/p&WEg;V Auw}|zѕ%pgtg޲H:Π3 f3T8C &r) + 7M2H.Rִ$1Mqm|u6Bmj| ٲE[gMMN4*^c[]_T|U*TIBG )s)wUuA :b{V}7Xyްhv60;5eWtxJ=BקN Y$ +/9ɗ~1`Gl endstream endobj 245 0 obj <>stream +HMN0q$Ď` +`(jiZױ4s;wizܰ*l`uN-āT +x!pŁ% ; R|ޓz@ֳt* Ɠr``ܰ-4$'՜Z+2bXQZ|nSmܶzWbz'[YNnj]Lk2 endstream endobj 246 0 obj <>stream +J endstream endobj 247 0 obj <>stream +H$N0Ga X"6 ʣI;N?nb; Mߘ+G3@ sNf߉;&sV|8FR3 ˯pS>+d5c?L]ΫRW# 9BN;=r$zWyp<^JG䪖\ZGT )+_LQ3Eؚ6Lei{{l̓n6JgwJeJn*z%ʗK~^rQfˋ? endstream endobj 248 0 obj <>stream +H̻N@K'PRQA HNYg&$q83wG;o/<`ɟ!z=Dwٟ8w8ed`qv'g?'tI:v# -fʜ#ټ 1i'={6Գo=^: P$6c@tˤ,pPR*괡NrZQEh/][]*jii_Ε7֗<_q糉Z?]rv/ endstream endobj 249 0 obj <>stream +HYN@8  DBddgggBn㩪gw< ls걡Oަwuq͡g]3e6G8YdV}&I^@mb+X)"[d# HX@*I1P I,:OHЅ;l'-ڀbWUlankAd5`zjG׮vڶj4G̟Aٽ6;-'JNn\E=]ӗN endstream endobj 250 0 obj <>stream +HR0c| |:lBCi~MMysI``<4JmJrЧ;'!ܟ56McTN0Š1}Ŀw8@:G.*FN2,]##IXh .).x3Sk#@ovV6}뛷cޫ[ϻۮ~7vu'V!}j.g_U endstream endobj 251 0 obj <>stream +H;R0q(PPP0$cc[/mɉ@nR|4o/\&qCʟ-^7w29GB'unX`^!8nD)8yZHWpi$˜;ta mHm%{oYne{ĺ+gҥ4ULYX5efVbuu[fmf,#,_߱|u˶7u` endstream endobj 252 0 obj <>stream +HMR@q;W 2E2=afA_xM))_NɡZqb&{Ε.Ij 6 +mG r_a9[%)Ԡr| ydFVq$G2 46Ҩ*$21ݪU`R;A9b(&;ho߆u?^ͣK皥6zsymVy\ endstream endobj 253 0 obj <>stream +HN0 ;iQCÏ$4I ѽsgt GW_":'5zwt:9EFO{p+3|1?Ʀ)]={g=+t<{N:xR @jHRωHL'ՃIJrCHtΊ&m%Ŧ +ED$Sd5tEf<3bu_v .fT7GY\ߋru+ޖW^s endstream endobj 254 0 obj <>stream +H$N0пCBH >f@veWUP/4vHcN +bq43w<j߅L~u`y'|D/!#dޓן v,1<%)ߒB=aOR")⟈E}#ޠx#Ћ\Ct2AD jl[+3@ NRpƒ\Zx ;&jР嚨=9ȕrf cJeA)3̝)f֬khj/dlY>7z uNg5Qjz WR.9/g|<<`)dt^ixPG' Xx endstream endobj 255 0 obj <>stream +HN0!6HH,vHHB,`Q(HIqc;/78;!!__}(gwo9+d8zޡwj_[x5:O[{X +;;5@߹Hu/{Y!+dŹ- MKqZh7.g!=.`<)`<-@*BG. Оߔ/:>+u|Z#NT9=@{r2ڐ7"xGD7"mex7{m 04w endstream endobj 256 0 obj <>stream +Hn@+ N@iU7gۻ3^MRHw>ξy}sy4R'߄wq&GH:L`':$4ψI1Gafz18s@) FA) Cױ;A*70n+RE3yses; r cE"% WZ0*beDPU((M6gdbeѭ)Rk;7}ݟm]j>|߶onK w/5,eFm~}PZ/ޫJ䭺MMr_`z endstream endobj 257 0 obj <>stream +HAN0!5쐐`,@lZڒ@6qlIPP,g{^" 1Y꽈vS|ap$_|6`N`'n$Bö b9SvaG;1CD1qw:[!@oWzciH4#!\bFеei-T0U,pgKp ق93g3M-r229l2k)$V`i:1&07z ԛ3֫W^+SFJ%U|-J\B \rtHǣ"(O' c endstream endobj 258 0 obj <>stream +HAN0!%;P3N3N  +w㹋OӤ ?}wQEpG>/nIiN HB$]U$(GqȔ)X,*lln{:r4 cb0M7ahV^}߯V=8>-._a endstream endobj 259 0 obj <>stream +H$˻R1 Am$ ⛓sC1X=gtr~`){=%l >ěG8o A7zLdv1#"Š=wdr$`ɃTp7Nzҡ'E $YSp5TB+$l+u)6K׊5,v޲cڴi]j9.+5FnnZΞG endstream endobj 260 0 obj <>stream +HʽR0k%TP$3$8q,d2x7V7sSonSh nɮ)52bf8i6:`c0)2eh=Gq 5RǁU>stream +HAN0!ST.@I{\)g +w OoM5]&[ {WMYݫM{VG;M"n+LYq +5Cd93ٕ"VyafvJg*>stream +HKN@qذdB A{~OqLH5YU]fNխ|[^F$/ a endstream endobj 263 0 obj <>stream +HN0 +~BH +UHJ(iibv:S7G ~ %'a9Kb379>F.pSd' #C_>stream +HN0߯O 8-U(x׉ +ƘçovfΡ98]3nPΕ-\ +>g %s +f8C*M,:{"~X G!dBAqLi`D˄ ĉ)$G6 d=&A1^X9"`dPw p{îgҺٹɹͣpOqghuF^j\ 0X endstream endobj 265 0 obj <>stream +HNA%ܰ5]$8]=TUT8A΃KņsU?t?w Spa!?e13Yh,uS $.&2ՈVMPn:Ko:@{xXޙm|k}>stream +H$Mn0zeXP"@"3cn|G ➃g]{,f8` ;\߱gs {jRBȊ"1RCi Ā=^Hu'^혔e_Ԛ"_Unn3swjrbԋ~|~f/v1 endstream endobj 267 0 obj <>stream +HK@3xCLOݬYTU.~_H؀~z6km{tlW@ 7x L+x;u ZI45IVН|z'4(rBR-*oȎVQ6i"^d_^( endstream endobj 268 0 obj <>stream +HKNA7CG&HbDIWW*7h<=7 .5й̥w)3LEcr0'8fpB(G-3$&'Bb*YRd#^z/-cʨQ?ts9 ٹ'׏Vfz__& endstream endobj 269 0 obj <>stream +H$K0+yK- +!3EluUHn$3G:G6|{L [p lnplBΞM @Qf +5+_;iTק%_ qY!*ڧl3lMaH1bHf>$5I?]{QG endstream endobj 270 0 obj <>stream +H$I0yz,;\1tNaѻ/oHVoXUk{\"'0Es  $R[<?ÆzG6'꘤֠ͽ=ZVCeh̭h̵h Y $]]6_ endstream endobj 271 0 obj <>stream +HN@#13&&xQnDD oS;v B}7rv_8"9CΟYlNd#،=4sy/8ݠCOf>;9@Y!U}~K!p H:ڎIߢCjI!)M /KV ;! "]C(}YfS٭g|Z=٪xx0vyoΨŭ)g}:镘NW- endstream endobj 272 0 obj <>stream +H=0y +`V8#@Qb{Ϊ9`Oj8h F Ȣ^0x'5:Hߡs$t;_ MC6F:h@'k5d +$(f{~U]Ueyh}\K%+.8?Ӽ endstream endobj 273 0 obj <>stream +Hj@%WRSl2I$;3$ZmֳLM<1{emwޒ6?I`$6&9 AhhJ0DK1H@BZ'V66$r6}E;,/ݹx뺯m=ٿZ_>_ endstream endobj 274 0 obj <>stream +HA0yo'` .HFhi!@_"*e&HozHr @2 bI0\a^> nZL Lt1BLn@b* sZ͵լ#ţkHQ2}TZRuk׶]:KdQG],= B endstream endobj 275 0 obj <>stream +H$kN0q8" +qKo>B܍13- |q>stream +HR0n(PB!‹۱G%w vlnЍ #6& 0*B;u0 @گX ZI'̀.[EtRjTW H*K Ȣ ʜd+>] st~>stream +HMN0!q 6,u -44Nl'wyi̛_XF0Ւzp2>w2$TsrrWD3|Ϙ\$v1A$9C,9d8PD?w=~zd]PO9wz+;n=2Ouioy)gk ơ& +$i5UiM3]Y=WfjgwORRR vf/7v}ŊMX endstream endobj 278 0 obj <>stream +HʻR0 T0CÄ&c.nX][ nfv ?(0Hiwh|lW,ʌ]$3Siv;@[E[-1]=l#nȑ H#M{lubZ:V##II]$ d.HЭՊWK&Ec@Po*߾/`۷f]ݭWrr=_Y mZ=)5;Uiz̧N endstream endobj 279 0 obj <>stream +H$YN0HHQThQ񐖤P7}k>gP;_f]+{U2.9gRst5%/ 7a_~H G8Dg"qc$YHe@.C q +N$7np);n=Y2M keܙ [gm٭m߬nͲޟGնo}}PW[.d}#ꚿ>stream +H$MN0u Xb+6H !B"%8cH<$vhBn>stream +HN0c /` kZԯ$ďNHBwq4}7Ni@?ùW)!B*:D1z5G/`O1HcCr ^a_[]!mIv*2eߓts2e#:' w@[Ya@{j%ȲDw,1gܚrcMYͶF-37/xE?jRewnnu<_+ U endstream endobj 282 0 obj <>stream +H;V0uPPPP@CCh obKO%9_Q{fg +_8O 9c?2ٛS)mp]]=?j9!} 0A^1 ;Riw#8x醒x$D$I蘝 +nc9@@CqB,k6β֯}W?o6S]k~VFkQ,^f|9|/߻ endstream endobj 283 0 obj <>stream +HN@x ^3[?-ewf?Eo9x|pŢOݶ;dPsJg>&6N>#6@ˮSd"IB %kȄJ5Oe#w83 +΀blƻwj׋q] ^zV[/vC[=6_/ endstream endobj 284 0 obj <>stream +HKN1+p,Y!(%Y{l5,>UY߬\Z^>Njg4;% Γ;'!l¦y1=D(&AL9P$M=sA}o: ێ}UA]܌XCb><Z/~?oO+ endstream endobj 285 0 obj <>stream +HKN1# +ٰ$DB(!<'=c{ +܍_RMMuRwPYWB%J/0's*OK¦9zb3(2Qh4iVAnY=+7g M'\ԅʰLz{_N=Y_5M]=.fa endstream endobj 286 0 obj <>stream +HMN0ɂ7@"HI>stream +HN0C<WH8 (((qMl-ލ1O3gg>stream +H$ʻV@B+ (.HIf\2@gB9qq ҜZ̐gC1b#] 8>zuiƏ67Am +] 'H@ؑ ma;RhK]L²5;Q0ʻ\@Nlp6zaUVWZ>m6YivFZ٥+<)Ӌ"N$^` endstream endobj 289 0 obj <>stream +H]V |z @$5V߹wf`totΣHy!O2w'8m=:npԿӾNSb TO[8xa[!x{`NR}Oꉣstq$ %׎N`Ĕ50%#$ft-}]kxiͳR'֏Y-\?"cn2fyv/J endstream endobj 290 0 obj <>stream +H˽N0D{0XTbOJS;u8-Px7OGL| &tɾΉ#ptu30a}YM#!IOp$:箏0EVH3EcHj C +"H@* Wn RhYĮ 9{O:Ta]UYŶ2l '$Y ^;:/-7/W/m{9t붯][mܴœi6Y~Pzy'?r6Xg 3z endstream endobj 291 0 obj <>stream +HMN0qX 6+HI'!q>stream +HKo@W X`ͶBPwm iP|q{曱N/!;,rf߼̾3/^y ig0s: xbVqnkN 1j C /S:t1.8G9!N-v~ܭ: Jس{nXUoxV1;_y@=g=HvSj.PQ<3e-(Q[sˎQ}votcH+UG鲏sCݢ=lF_}o|:UrtrYW??ex_.o/wErX߾.V77?V endstream endobj 293 0 obj <>stream +HR0E8?bZ alnheZ7o|8sNf p[mdfYa۬yKv^иixMJkD.QQ db܄w= ,'a@(I ڠMn?I? 8Rfŷ2,co~؜kJwj^ǡ>stream +HKR0q .@q6*p+ƒ|F+W=53737pF RL^ ":"CvW!m4FO?:]tj>ǀ_&䝞w{I=I7:iGR 4Db#ѳIN"項vCF2UEBAȬJk23kX }|ѵS}>cJ?(۝,o*^olq/ endstream endobj 295 0 obj <>stream +H]N0,B+Il'P>|ٱj^Po{)OVEЅ8epaSb@ǎ:&` oII5g(I A7%b]K%q3&M>u\`H|g{ž{ckhkصG}qc04Z@tk-=iߨf/ + endstream endobj 296 0 obj <>stream +HKR0EQ,&|6a2xR+U-[IŁx֛oN_ɣ^q~D*xREoZ + ,76?Ww 5Cd93ٕ $V&ybFvJ8r +!9>HIbX5Ё81tpB3 -o_gq̓5 WϤ endstream endobj 297 0 obj <>stream +HKR0'-T6$˒,,^uf4:7: u1Cɟ7(yNa%:vҿ])"n#n`q%'!G+(=AX$R2# ăxZ G0;nxVYV1 -#ݼݬ޼ͰYJzI}.gJfZ- k:bU x> endstream endobj 298 0 obj <>stream +HKR0&PŖYbfƑdFūnf;I$Oo]U}P[Ɩf8dv'7%G8 wpĮ†;B{yϮvNi&,djD! 5M/*pԕQYۖv3/M=m]|4v}alsgz}j'ҕ endstream endobj 299 0 obj <>stream +H$KR0`Xp"Uġ[Q, v p7Za[=}ν7HsNxC-]6W򔝒9&1zs!CPpC*oF19 UTJ]wA:)c +WaϕY#uN?-KnW8EbKZڲS% vfY9YvlmVynvӺ~{zHf@'*VWōe镚O' W endstream endobj 300 0 obj <>stream +HYN02l'hh4qlb1tzO8U׌ymU';Y\2SpO$Tn,pp[. )dt ɳ` σ$'4IOHX00;rv#6 ۵Y5v޷Ӿu>^T?k]o>)l_Wz߫{ 0¨t endstream endobj 301 0 obj <>stream +HN0E_Ċ{ D[(vPxƉ㴥¿q=s=&;&crHw.wAW;'UN8`!ρ i79];pHd6p7%2&'{S0שmbցI9Q\*Am(*Mq#  +VU1T>C~ +}]yuڗkpebjbZ٥z8Qɟ"Y endstream endobj 302 0 obj <>stream +H$Mn0q`@ThD$Ǧ(p7>ţ8IL<>"6?nQLvl1;pf bK} +36 b sHGըG&zV'yyjǾnd*U +rKr?\/vzaffSi]|N^  endstream endobj 303 0 obj <>stream +H[N0u3ATBTėq8qЖR<|:Oo\KtXwh񃺗钅 nZЀ6ŝ_#|&@Nb6'2aѐf23)Mb$zĦ +نXo6>%h$Aa8(ˡ{6o~?~;65=-QscY[۬J>6{w endstream endobj 304 0 obj <>stream +JI endstream endobj 305 0 obj <>stream +HN1EtaD.pa +0d;~ES_ι ~2EK 5 +rl߅͹BSf̬0 pȄ 'cbsJpHdP$H]3=y.ԓcRz:0:p(,(Mm A7E M*3ffۮ߶kzqnd7g|>stream +HN0 v`*-Aď(=v¿qѝ3Cg~_An. ;I w؜X# 0C31] wY`Xe1 zBO::=!SNHuKHQGfg׹\YOW[$J9R%"{!+sb +XV|mVf4_/.)tu1rN}%l2*o# 0~9 endstream endobj 307 0 obj <>stream +HN0සE[ݵ+$EXT) رIbkI蔾[Y|C:j?:7 o٤ϰہ3v68cM>3` Ә7WC`3z/)#^u=DCLcdU]$3DyI:AdRNJ6i TZe gQvN$ (dSY15(Yd'0f$' +x$gdEN+gK0sm1wm>޶϶}6ُY]eݬ{]/.~i=;UzIR,n>ȇ#y;9ͱMމɡ:( 0Wo endstream endobj 308 0 obj <>stream +HKOQ@X1Ƹq %Ntss}n7q..wϻP<H=bki=n~.} Ѓ1;,w@pEuK:7LH1o P + 0*(r~-I2${C,qʜaĜf5hmj:5:[NFmX4j*CTCd +U'W|[]oתﲪ֗e/eu(V2? r\,qr8_NON((5/(R<9$t ]F3El4zf/ 0q% endstream endobj 309 0 obj <>stream +H[N0 $~ +b Pi-NB=qh[?pn ͹Ò%jԟl*]f@Wa*+N +VH2nO0BY̙0'tR rJbHD* ,}H@2vT$} 8΂)d +B/^;<9qwo߷nnݬ^+|[]` endstream endobj 310 0 obj <>stream +HMN0u=+b- +DHII8ŧg\'on#:\wiR.0b.pt{RS`Ưf}p$͐ &13!uc{CF3k8Eu>%7ֳޡ;ek#N5j +qbW}rCzΖXC;x4 t~UuVo+mWu` endstream endobj 311 0 obj <>stream +HʻR0cx +J*IŁdHdl#i%8x7R|4o +/Q}*ءw]]kPnj[jA3+{ܼ¬˒I PO ;EH,w@e^H*G n$9I $Ԛ@zwgwmvK mK16β3leviͦ1sX?N͍ע}/ ,.5 endstream endobj 312 0 obj <>stream +HMN0&,d (B"{Ǝ$xfiޛ:{4׌J~۔^̦X35KBK + c+'9z:EE0C*GEXg@<X2J@zRΓ Nv]+e+ Nk"mב}o84~4ahpoL}u]i+Rnqӽl7 ]O endstream endobj 313 0 obj <>stream +HN1Hp΅M!o3B o9el.)ѹ>&RI?{%6`m {E6ȑu 7L3z,'!AIAXQޕN[q`)l i6LBqI/[h ɾa'4y\v=v5sv );|h.vq׶٭ғ%^_j|)ߞBLF /q endstream endobj 314 0 obj <>stream +HKR0' +6!e6%\XeɄOYt5km ַ?޺;%&t +T51ʏ8'.;]'XA^?VhU:-^=A^=-3l^b6&xau/=ܽ;;tpӼ=9}LaߞIOD#) B+QEu؉n # endstream endobj 315 0 obj <>stream +H$[N0b !"*4y8q8}PhwܱW,yq03H#\%N178rcs3WM%nr0τw XJr 0:BGͳd=R?:n<HU3{ *^H&ԧ Y MckҸomynn6OuXVlu?~RV%)D endstream endobj 316 0 obj <>stream +HN0E_Hl`͂J,AyƏ4qj;(Y3מ):؝ +nPSUH"TӜgfx:d)#S$! T&Xؖۼ*i0\Ȉ–G6q\6S;6Dt\Zt4IPFdP +tu\{x +n3,eֻ͍?\j/m.mεit{z/ Uߑ endstream endobj 317 0 obj <>stream +H$MN0q6g͊  HDh؎g{&Pei޼߅8/1y%4fnLȤO]dcIkAnRƏZ#` ր?',0RvC9=]L40y'70 ؉謴0Z=dZ4M ΙrkM֔w|}u>stream +HN0k.>B}*EwT, ԡ" رIs80wŧs9t9wo+:pt}x})0#H.$&g@W;xDʜɋ4''ž$2F߆=la$2g b$S):trۑTF@xcG"=Z?'|\63(8aZȩakG;[!*$rm7L,cdvav1iVP9S?X[[*k$K3ԷZZ?.^eoau WP]}gW]w[uR/ʟRݝq)_YUaY+ӻ4l endstream endobj 319 0 obj <>stream +HR1P]%TY P 30I(ovqvN:Dtׂ$ 9 +Ka+;\r3̲[و!))3R4?pc[@g(n$S"tds"{iRϺ'tiϚdIGeU%I#eVM eR[qPCakj6Ueh5`5բm>^}ۭv9~jۣ6gwZݪd^z1`1 endstream endobj 320 0 obj <>stream +H$˻R0(h) +J`4@2+ٖ'+(\pFSD_딟ѫct:9D3@/w{8Rбw +]n qğRW)70a$ sR€9'HԻw=PO)k=q _{kGL1,޶rA1U rE---r`ażiVOY>`onZ\ zūK>|v_ endstream endobj 321 0 obj <>stream +HNB1#1\W [XBmgziE*nrzf&K,^:ta]gdN\ +vp.:c{/,\ݠt},dd3P=t5R,3+ʙpG!ܐ.R]RUl!u5%RD)}20 QP 9niً-MAH +ۏ{7Mؿ=fn~pejb]37jyccnb>x$ endstream endobj 322 0 obj <>stream +H[N0U,+@#E J ibϸ^h)>:ci 5 S6S9cfsȬ )hP;|>FT6՘Hv1Mdmcb$l9JUq`9@tHҚ%IJkdHQ/X15-;k !_WA*}U*`w]Ԯm[Y[Z[[\KRŅa&Y 043{ endstream endobj 323 0 obj <>stream +HMN0q X V"Zc'ib8NBxf)g8M:'p*d%Ę<$1=F؃tۑ-vX7Cv@r; l@a'3F%M\>a凌d߳$.} E>stream +HKr@ 8 [NM*aXĀ=X=Cnie񪥖i~i~H ;h~'t鿫uJ\knj:;f:u_Ɲy.3)wAO!F $#8 dBq"t䦑ld$?,^XU Љvd4[e0-iPN#ԗЗПwsk?^}xX][vmj<[ 0Q endstream endobj 325 0 obj <>stream +HKo@ + U DĎE@$&-u\؞8mR.f-6] x_DZ{gGs V=1hv}?zns.ppMkvu-mtfכ.F CPdtq Ɓ^}YУ邬*{.}9IAya:?'# ^6 C;7Q]Ľ +Vҷ*X-ОwVV>ެP(-%{myÛ)el:_#qFΔ3%[S0+k߸&cf3scisӦ3yֶQۤӶYDjtg\%:*9NW]]~žҳOrQȳ"?}''{蕘M_8숳Nr6-EzH^Wӗ'S endstream endobj 326 0 obj <>stream +HQN0U&H'GhJ*6uu8Pc>fv)4Sh~6r~J0'Kty>Z`]'\Fl]b0{]&HQL6Fؘ8 L&B0hbpck߳\^#U'^:3)@wf)bw>ރ+]{zs׾oi6ea [ddvwƔk]]۬ endstream endobj 327 0 obj <>stream +HN@/PTe$8&ax. +-}4gTR6$vHC2?; +/'9d^~3< aCv)laO:#UE]һږ䨁F6R ԐHMmE(@1%N lR5Ea)=1BH +<1уs=sco=G̜p~pnÃs۹o5z;sfu~o7*oᦲmeoƔ_Yf}J2+WJ//H.|83!sgG"?b)/̎9zSrzŠl* r:/^ endstream endobj 328 0 obj <>stream +HiN0!p(H@Pfi2vۅlwfޛh; C_,O0!c0q9‡pwop3tl:a xgx 9S;1=rkc&Р,mtjFV׵1z֤]mN,I9jC +*פɪв\jYRU"S2Iy"b$z*}׭ꖷ okf1a|qUefUx^-ΪN endstream endobj 329 0 obj <>stream +H$KkQ B.\ "v1irLr.si4ŏcF&G{`{_˭2q`S9eNw!7&g \[IC3nMv7~ ?&u٤#}]g$Uʭl:Ï&iZٶզ5 5ѭNiiATinP7\k2Mj4N\%O*-JkjYY:av;Y^SID +iȑDبZ6ZE Z+]Hd5]KUᵪRUમ6 2`*7gUysRwe9.XŗmoW1.?̮%[IZ+!_p~$|XxS8 oofY{_{ctILh~_Äڞ endstream endobj 330 0 obj <>stream +HQo076&x!!!Mh< hjV5M۴ۉIvsӹm/4*muػF=f#7 ^a +=l;/r<=lwYb?[:BGH +a)BЬ7mB6-ZTۆBGC75,` eC\7?`G+./ r$1$[b,`T s- 2g,%swz1fq}k淵ɆY ৩}SAgAnLIojv][CNj^k=JUr(pJ%H>b\s!;!4Y.F[8GA>p1|g< 8a >glI%Kzle8K &( endstream endobj 331 0 obj <>stream +HAR0 qm l)LIbK&Աr7oWDwk|pɑ.YZeHtge*) RUgRM'AM0IL 6D0jjh[=V|x C3xxo^7Ho 5+cwkcU< 0fg endstream endobj 332 0 obj <>stream +Hn0ᷫ,"Q jйtZ؉㙉Kd.mŧslg e x3y8㌧!:%{0xE']}BcR8`y+z5D8`Nѕ}*﹋1sRFpGu C^*zE>stream +HN0 +3GN CjԒ?!;))»1>|x27 1X=  ~`3t7ǁ19R~p76 =_rN{#c:Az2 t책Գ!x ߤr@)|+ +,ۀ;PN< +{4"/Jjn ߔE۔kXzTWcUν;WUzy#˵,_bv&X._- endstream endobj 334 0 obj <>stream +HN@C] ]*E; +!$a{|'xfgBtԷoS߾N72y2fS>c7>stream +HYo0 +RA<hBf,IL5 )<|:\w?ps̈́ߓ+_d;ՈGsmy+8-7`;Na7Xe` ף1C[uz#ޠ7|7u3 0Tg +ifM֙BB Ӭu'-**khij*[MU(J@ $׊dZT-cd$Rfed3 e~Y5y\~kk\~s]#OU|CU2~'[Q_ y竗^0|^,ZDO)]<$zBM;4n씮S=#dl6O3w&狇f endstream endobj 336 0 obj <>stream +HIR0DI=a.lH*ʊ-UC7\@HtSnN5K0Ka8%cucgnT?%{tJ@Mt3Xk>stream +HʽN@CB&  ľݳ}g'N n̦4s7;o /ɟtsҿS"6`ܳN4y- 0i;6Fz$@7Y  HvkX ukH7=3ؗr[䋜$uyY۬^jxκ+ckjtge8`}S endstream endobj 338 0 obj <>stream +H$Mo@oW !đK?z@JBykhwv]MJZO3S[<44f{~d8,> y='d> G@n!q⿷14x=[1C_N{3Cob?G{M^t]ێ=ztsf̚Y3 ;Ѿ\Zv`YPb|+셝hJބjQ*0JewF;EU4o)q +/iҭ4ڹ5 +KWldjw󺾽U|r,ET\}vu}nt~3~^1;K7W)+ endstream endobj 339 0 obj <>stream +HRACn@o\7в/Ie&LLݙLXDwt.:?۰~}G@[CLyc]&q㏓񾅛 x !-`M|w"=l:'uu#y; +t;7!,w` +F`x=noc&fYC Igi Yv7CL@iFi51(fU,7`soD|j"U +TU^_y,Mv֠7nu3ViUg߫j_3 ɧKhL/HLL>{[*&oj|@_(jOW4`c5?v=~_?H endstream endobj 340 0 obj <>stream +HAN08Bbɖ RM[%&8M'vR +-w㻋Ǟyreg^gt*:\r\b!0n)t +]5Hީ{8xV  ޳>!I@ TIzp :G0=hV4lbSVP-dʂL&loM%\6OudB:{'Y\?b}/6˛2]ޕ endstream endobj 341 0 obj <>stream +H[N0!~uM))j&c'Y +{㚏;sg~~2G ;-S4׈i},=OtAg9?fSWauɜ 7 f1D:H! ! $C$P$,A*Br/) 3؄MCշkwi~r~{|}˝қRO )JT? endstream endobj 342 0 obj <>stream +HR1пKRl`dT%* ?cgf4/WY꫾!q N +xcK7A!+d<:]K7p=:@[xp.xԩ  -:HZ@/%lZBGmlexPCؑ Ʉbуd)H*D E.xHXP0ɕqi +1̢o$ +B5Yɲa\9[,nl/lu~om j3Z]OQYF~6ٕ6J-.Z\rG8=c3; (ӻ}rY endstream endobj 343 0 obj <>stream +H9SAء "́@* +$[؝cgdxCU7=} `/;`^eˀC=rܛg>9i`䌜y}/<q]3zFC:;v}cd ӘmUhC-ķoYcuܹ%}OX@#8g@YvRdTxI2Lb ;)─Nd6l '!ŠvI1bE6ۅ5"qM66豩70m׷U䪬Z*gQ.̋ߵ+B7g2}*9ɑXݟwbCV endstream endobj 344 0 obj <>stream +H9s1*tPSP" 3P0>#ZJK\|7=thCW<rɟCc6Vsh!A 3a&-p={q>3N8"'I3= B.&=;k[ ~JNc7M{>xT5b-[oYQE㳪i ޱa Y|BM I"R:U]%RxXby]?UVNUnt+7mmƅ[([}ˋ՗|k~ycufש}zIobrOF(Gj3}V?ߩu endstream endobj 345 0 obj <>stream +HMN0uC/#DRV DEZ%m왉B ӛ"oEtwWka{k ,#3>;[u3L$K '2UH)l ͤYHOBjIFP{G|A|vnɺGҬysha< 0`X endstream endobj 346 0 obj <>stream +HMR0 [fXAt(@۲Ɩ=Uvݏ8W\9 Wa S!8d)ӿ8l jFa>rB'aD'i--("Ĉ#ηgTqPpj Bkoѿoؿ]nxvZ^}^(QyU`а" endstream endobj 347 0 obj <>stream +H$̽N0#0‚耔P&vP׉i wO+O^L^y +#:J9zFR'8$2!ber9z1GҼ鞰'$?fYyR;q@LSC=q < ;pYzǁio1[jA)P05Tְ ԥ1eV+ɺkm~۽֯wRR7ɯ]y/l`A endstream endobj 348 0 obj <>stream +H;oA +D} +$ +:HH(Y>stream +HJ@+ׂ^*jc(Odwg/>Μafd\'[f B̟`L3>stream +H[N0UbXVI+ I>stream +HKN0!!.@ B@[ZqGp7,>cC1h>P`+}.ASjsP `cjI}$pCMljDʚ9տdxxt FR)eRq 遂} :?'x,7;.e,kgWپY}mf]v{˭7=]򊭗lx' endstream endobj 352 0 obj <>stream +HN1CBmAt K&Ǟ 6mߍ;q0tG8[,7C-A{yG7⥧f[>tWg{#tĖys4)GMbٖy@Őd΁[%S4DK*`;LE:1 fntQf]'Uo=6.]PmgVdm$-j A +R}^ijUhv=zX}z7I,of1nn]1ǟvvY׏Ņ?fMϭ~7[5>Qۯj>:SO7_zIMNɇGk endstream endobj 353 0 obj <>stream +HN@CDU,H,`**DIȅ홱+3,>9{/?,xAx:ay ^;n ;Bz +/Bf0@b׆+BZ ah\\4-`˚ucmnkF?{njڣ{Ior ᭼Ts&4BIc)֪ JJVZ% ⅖RKdϔLJS+*%e|/n*uYmnr,\_ p=ly'cJg#8Ƴ#ۣؐll$\: endstream endobj 354 0 obj <>stream +HMN0U\!~`AiGm +wŧ7f0a,^3v(Ζ+*.Y0=gpK^ e>&AT~"~7)12z٤PAjٳ;&0x9.x]LN7{Z@J*Ŭ4Z[wީ4uմYMnW;4OdG'S[բ_n; endstream endobj 355 0 obj <>stream +H$NAԣ>stream +H$IN@EH+.D`` zۿ{pQOUꉛ߉8MlѡwƖϛ-cfs~%i@SټKޠtnuNd!FvwP GB/N#1RPUH0 h$T%3I:򃰠Az'9!ɽooV}ymp4ҫks)X^j&ՅX=O endstream endobj 357 0 obj <>stream +HN#1пCH`Ċ +>stream +H$KV@y܈Lug 퐈C?8F쀷) F3dHT !NN;@II7wRxƻuz[?ޏu$GuFPivPVP~k?<RR?HZV?m# endstream endobj 359 0 obj <>stream +HUyXT?Λ{0*{30 TP(EAYFV46UEMjF Jb56Mg.QPqASScm @׿_|{9wOO_4&zҒVe%+6Rٻ}F}uVOw +OWmJSS k^EeGO3ҳE(19-X9ud%{ߑNNJe\Ds]ÿPkt!ҝ;@B_(u-ςX_=cL1];X-GY\űр]|NW f<w}g*-y:z3G1]||0 +'t܆5we%w*#q<&GudTD=jfjJtWb/DZv+"OpbL \qK1WBL!f^)~mxA! ƀ])S +$e|_40`|`u8`NpxΠzՀT_լPc85^]PFzI>P~U jjst-Q[kZV5hMZj[-,j ZY-ՖzVfkZ[UpHk5ٚZ:lF[?m anCpDpЊ̐>hG?nX},2%b{gXΡ+UK5 ̞ssĽOuQjl/DRmVϩP[C 4/{iwfZVmioiG㽸cYd_d ŝdMqւ$;AO>d;=&qCs-E4Q@c-vsț];mI5[f7hv{\O-_kv%e5EMݶ=s~lZcg3N.g^[9Us'u~W|ůk {v匔ܘzkkJ6hJߥi+c8SaE|a426%(J4H]1pF)TJJR&t(7KY'Õ!/icO7kQP"Uԅ& '$kJ]t+x R \j]CT6]CK :3zϥhBE̷^ aU 9`^OwGbX ~ZO! A2. oI-H!%EDyAb1k^khHN"C6|% +h(t ʼn/R:%)YPH+!MTbF%֋T*Pxj#cP75`=f a9l +l[wH6<6dXslgs,81ladbl[ovR<+co%,-e,UeR*V+|# + n7}uɇ|E(X+Jab#UT)nq6NwXOx"e{U3L1_IpQѠ??_;?+XK$Mdjt:Dtz WY4Q\7IܧU0G&o?uuh"-kq nE Z6Z)ҢB);! +ww ~<8c_0\GoHuy TB AL +&cH7(#LՍ4>/U1r`@|΋tl `;`wn½f(H 9xI7c #xdJ1.ť  aTzPIrc`zE fKhwM"g7NWv}7l=0WX))èa&faNX^%~__lg~_~òX+`&jxuFj1-thFie5Ej5{azZ?Z Bs!6҆X}ϴ>4y&X1b6B[i[,ZQ@ZS1/ӎ).]{i}mҁ:H/uѯ>Gpu:CgjO/$$dl.H mpo| >$6(/EeP[sM7 LZ Isʜ1g9s\0ehw5s17-s6wMg摿*x,Ͱ=a5kz:X]*ꮢ*ʮj6,t[ʅRg؀1`_WېL07L"\ۙT<1pynL;%ÃTdR;@~2ﭵ묷hɊUi?m6+m>F؂gu)h;[%lI[~l?mY[s[^n2+s=nn B\Q偐umVkVk6k+eym ܐgk>u]Sk:.zMomM]}7`3ܦN<<9a ܁pA`;܃pva7<=B2}O!VC*O`/<} AxeD'6Wp2(c P: IpwzQI#rV9I<N;\rI>˒MHv*pY&O 8\py.;+pY*PJPC) F14&𩔖rRB3ZB+h m#baB[h!hhbAGC|as tKtKr!\^ /J>:q>E%Q/s5S= ^DBo)*U!t. j +̏0 b!,3uatGy.t'-Bq*itKa< l0-nw3>\pY<.8 +sULF܎Bܞp4e箔QNN>TR7*_GԀLJ-=Dj1ԞhM=y1%/X>u4hr<}hoVѿx{0i,?qB9&i4_d~ES5ML74bhd%m\w[ɪy#]M+v߰3]J{'ؓJå.^JUWS&p}L*TQeNUxUTGQujJCYsh.Uͭ!C#8F=͢y54f]#h4O|i#N:J[ UU}!ؐ`;ZB@)K!y Yh'l}MS..9n,eqAkwl)Vg#mOݪIBA==&9w~D]bčb 5*X<.C1q6Ͱf' 8.NIx{nw}p|U'.*|%rwȽ;#39l)nonxw`< + ?0pO`:B +`̂0nEç vFvD}Cˡ AV@(I,mp|9 |A&Έ_ߊ7w x +~ 4< B! M0Z`1 KzN7zStn×V"|,xES| u<5q^uςn=| 7';hxO|<?( 4>7&>_ǯ9 9RrZ__WuCZfk֢-nݮm4->pn{m8Nq՟wΞF޻[wB܎[Cv̀8[B;<KiTB'J|PڬŎUc]K:JhlbJsfl/PRJ(ݒR)cδg-qbf,Zp團sRq]I5U=+&b9(*9j$Bh\׍*w]Si9u*dI<ǨʣC9i%4*%ay[ZN8}*eU:z[d'* r<1]ܭV걜PRa;ޭ\iSlJoR+^PaKC&UD'#Vwxfgձd50%SX]1bOf +f +dJR6^P/rh|J^CC !%1:PՑOaTC&zvU)W U R"1hW =YIKV7:ѪܖP[Ee4@keB/+˧UY[7RP+9>%Md:fc8ZܧGIb$Y?ځL}M+71[j+|PrK5=QefZfl--=4LϿBxtiVO +g$+1$GZ~- ysWY 0ɏX~G-HdRe U Ti1j<[$c#Q#I}$9}$Y>>8Hr,HҲd*hf{xvP>[RJMM1iGRBM+T}*2! +t{%'^<ްA^Q5k#ÃIVrd*7*6a;ҧbI*YB!kf;8q,⍞X_S/v4Liex2LdI}ku2$14NS3` x싯Gs8u0Uwn磈=A?Gp0 XC-4`\(+x F3c96T<" +\q]%N9czr`053呲̒1V*HГQm)|7=JI\T᪱۷X:2&xz8RZLRp0ܤd#S̶TM|CӖ/ajR%H:7\&z/Iz8?@+f_G|I8B;d@̞rC(^N|=,OIx\F߈3(W7Yj*fZ*U֛Q5#kuApFz@J y!08BF8n 8\XJˈӀ`9q 8I#h#v NKMKs-T-4 ʠpQU^M&@^ TuCzSR3hP7[Dԭ~0/O7Fvϙ3c  `lcc!lbK6]& 4m\iVaj+>$@\Ҥ}?33%b{sx2u 5Vԕ@gePQXHh**DY$RH"gX\[,[q56V$H0`TJ-ǜÞBv*8C +o`fc]sgvp 9]FyW+ꬩm+$jeN?1j @ +ߣFK梑NakŜxZ!ɚ\Ķ 3bxA{96N) B +c [HuW`Cp 5 +$p'iP|o'?J,:ESJCM[TTWˌK\}|TٕJ{ՓUrUo5[z[#bfsL?!N"7:Z 'vx= ljjBr75M /A4b)`6ջT> *e0"DF8j +%h%؛/nU|>lqlpg6`${]6Ҿ?:Q8v8t֙+&'w9rg6r{*?Z?0jAgw0A# rb &9X@/"MVuN*u& $l:^,䂚O`!a7V1OCzn~4c؇OO]egNs-hkǖoI?!\(v;~rڕmz=0Q 8~𢩤4CA3b&4JT9mԲ31ݹ]"R'g i ԜL\HW5XaA2< ț\I˲la[e.p,x:" +>|+swrZ}0=#"ڰ{ʏGŧ=Dx-{'-aʇ΃2ŕz)Cxcd5AI&& ԪMknh6ab 76XjU +$2TƼg)[TJQEC%^U}Y\EsɡC {zwrK‡Zu*jYmJ4vt͡c.ۡ"3*YD_#8PjMl.L1 SE *HD2*A jO|aO,c?ے7b,f9s.;U +1cy%O6XiN8dwb urV j7‘Rm^ 4!Jٱѹ^7~EpӪQ +ܱpcfx$<ޥJ>=MyMCOXpdld*Ugg-mP[3VghlͶdۧRK[Q7{zvK=槐dI'ԖqUq*SĄSK8؞oUWXƻ?1\^&7skԙ75Ȭ D.2s Ҡ͐\Jp X?zZ*?!,#UpDم-KyEz4ZUEVG8rJ%}J5`~v\UP6ʘZ -DBd+O((_l +.ԜfTH "Py:*{ -, R󩻯Vze{оSl|}_>r=؇_s׾z_KY8 #-tgc`oq/MOX8}rdHj"?Ǹ=%UYD#6)jvO:S<-^[`]O>fp pP. £΂<߄ytUƿ3B /{` Ą0S!#)T a " ("+ed!DVڊ (S)0N^Plhesg߷k?h蘇BWYy$K?pmC11-nй ^8d:dO2{ƺLnuK{QySbG?.ylE7DDt+\ĥw }q Q-3W;b}ވ9ϸU{?^v-":.d{)1gh}C,'JOuj7{HodMhū.FO(() X'p4="G4 o*<]$),%UHu-fn=ѧ;8{K-"<\w9z~g!K||tw]usb\vފr0 +Q:sT΋rK?ʥPj;9 ++\h(S^/S&^~ +,1X/ag{N`{NA:V &B3&NAh,1\b} ^C{8L&SS\BW$SbTG $lîT0H\Vd-Ȗ=!{R"E6,2ֺab&/ Rm(4Q)FGRB>  -Woݪ +}c|U)xbR8 +D8D $SBHt*0CFx8/nb|'na iD-ʗ&;"+uk5I d'UvoY˴;Cy,E/0ːK[шfUKGU?5\F&{Iz3 ԏW;P D< =}.jzN=Ќ@)CW5ӾK;=\U|sb֋hL] c6uŶZw<õ#r.JL<&Pj6P];Yۈdr߶1ւmf4&g;an<:;Ky[ws0~4ߘ#|ϵpΡ7%xz~*ё2 跥d3pޞO24j6$RzcZtA1Zk(*QnZʞRw1@SNAa܅)z M,hN+ do{@f̶5*JɘQ2C<ڎ(uŴq@SXE%$Zge22N$FxGb6空|nMT}:x)w1d.;Vg0r)#LQؓG;=MuD/0L c4Or/I'2lwJtmRϤb>"֐]ԫQwb*gs*\>$Ax1'&H,9Ey+w8"2l +הmqX㈪d#{cO6G9ƹvM52 HBF;Dn9@X9sc5ՓQf.s2s'1G8=S~5uk-{}ꍴ3^d1H3{ u%Y#ܧs=:u3 -XBltrB}AZ=+{Mw"EDh$$!]V\J\*ԥ(JXlHl1 VIRCXh(;+όݿvg7sysT8m%XGp*eJ,o^Aw1tXޞm>f$ڋܳH)r]8aHs=t5ݑe#Xs[_.ydFWHV&~6.|GSKWO\MƟgl[|7I™k?uv¥==2vmB1 ĎT8vKk8uZ2,^b}O_֞ +iUnIpVkvSRYQ$v*Y):VYCUf*iU~/IB'8#A's^:KG; awW[FU@,5g49lTie*en{(-FE3f +vИm9?/+^Eب }H|G&A~sW 6z6j#v.L_짗Igq=\%0Zɋ'kϖX'ڈ.EG.B t5:\B}7uvI֓99Sm){SZYe k;ͼ^])34d)ZWWs8U!/'MGP&O7Nl|t~hT2Wաi0oTu/M:1>n +ջʜGӄƚ:\T}к=;:!IV")(3XYb=$J1u2f=˛G9Q%;2jFް <5OlTاB;ryFI!5hM}]X +vk܂orEOfSUa=K,)Bwwy?AsyP4D: -~9+"$|}%seBO DCru }4FK6S;GB37)coWueX8 gE v89>Yr_W*i œӜ\sΩF{ȳ'n,wʙoC\<9Sz'_913&Yc܋=5_FK{~*^ݞ N:6;$CӁ;3hhJsnN9 _|1; Iso*wuV>ώoR$Y %{N }ݔoɑ}L 5ER|))`u+"fasT:ԾF=ʀjr 3Ȯ6:}MzN=>VA(`|l^(&ɯi;whi> Hg*0~SS@l?Kߟ) #N)Ns7[v7GĈ]i} X9Ow!ִ +|_F'ILwHu^o™/hı:*)+WwD}%9;ǽX{=dk-+ywJB_IOdPtn*-?>JHs]rܓ0;5=؃,{y͞%͝팕Ib;荽dOIk"ʹ_>UX +`?)"Hw#=`(#ix]ICb= Nm(9ev ]/\LX oC l2o1́`dw> k'0CiCm0+ԱRzO}?^_2Pf)VC:8}7>Co$+"$/Ey+MjъfF$z7}AqzׯH'bn!/LH:gy{Yb}"ꤗGP+RCnVFc;K*քΔG%BB!7ruϻ*͏q'Dx7Oƹ74uQ)+$ޏo@Ho<[XL_}mw6hGiwk}l]NoG2X|J|/n4Gp2-=*',nC{yڷtN'Yurao^[eY'h٬u:?FCi)HjĬwC=ѡޙ_ /DHٰF89TbsnՠJ;gZEB)C!7LwݑSԅ2])=Nl}: pY2zYюG5I갹 fUi)Uu;޻K 6!RyR8B$$mI2Rqj;8RJ@( +K  +<2R(=w#vNf~sη77wϽ^%Nk+aTcų¾%Q- V)jQsxrNS7[?cGs 8{:3cD%C\c +LC;-BkEhj>1Fl -QnV+l=l? 8P_sU$J~W?Vmc%pnc(ǺsdnE`F#֚O2%XyJWuӨ:ՅR(F({r +8|/j1H1 +mhaoiEqЎsG#~ěy?(F~vV" vo^g_h8ygOl%Vns\qޤTG1^xg;S7vNuPsVHcy082k7uz x4xΰGiX@ou}hs?)GroBѷ5,){N_`D8HQ8?#Ά#|b=jIM,5|o3w5ra':'_OxMxv;Ǻ.<;uTm!B_ZI!vFB1ZuLjC1u@AC.PݖtSbo{p(ߊҊo׭yOwe,PRR~֍x''Yv@c- Rl{MZ) g#ĥKaMD9ܓSd͡8&ӋXw$YZ6gm7oڇiu}%/އc]zJ3ОɮSրhz毼%~"ּ*јOy1<.Cg/ `)Qcصvm{o4-bDM=4؊ܳj_'}!B#ԗ FGjjK/zsNO}[T/~>ҴjJsIz7qs&͟~ +Q`⯜ +Y"hJ;Ss.qUWZu6&ẹl}n0 j$6R<ڀgU_| -fcM9glwAJ"ᜲy[Zpx3Xv4'g}q̙^!b3ȟGv90΢@nEhKeDq1 Rte~3ǥx S1xµ'sxlgCPMxD^@З刓`9m5`5jMD)jNؾ& cяŞD +wjĭP*b D rهPfהHZXw:h ֹ[x':hYij"ڍx {o4cFzD,_5D}jp fy~BXy :bKm:;8D5r_Y"e~f;akW,g\hO1.|,ԶH}C[Eb"s y%b3qo_NP֭-)ǙȞ{E_q-:؇[ νe`4/}y{< ٟYdJsl10̓y`ӔA?1 A$PyVr]r3 g.ZQΫ8G0a@s=/+ySM0s?S߀Pmy,69v/v)s vS;Ͱsrg 7mr/]ź't~Jʟ6"wB WҦLw 1={cV~~^] YErsƺ +\OeNɜ\Jʝz2-'J9q +*m]@VBi2H4K)븩Ķ.U9傔 |KrAC|QfHOϛ7$wChVƿ3Š +3%p;o,Js%U4I[my͒u묯uJ#QpDoE/C?d篇x)!B!pJ\qmrY| #FH{3Sxˬ{OM2MHPd':g?]}!Q%%IJwS=E6 SE'{RO"[ZO e'*驦9b5!4yJi1:X3T+~`< _O*;SF3ŻofqՓ?}b vݐ?$}v==ėPЙ>9pSصkeTyhk3+][XT;>:<8 ]:֧7 Iu6-}vF<΍E|X8~7Yx?= +0bx endstream endobj 360 0 obj <> endobj 361 0 obj <>stream +H\j0 l/JmL`-bR[c"o?*̐3/˿>֦!pjp74ޝB7"IAj~_ 74PnRBXk;77X]f Qs43P^[QmjlbҰO5jlеB~ ~O +];:!S:> dsʜo;yOuP| . ⊹">2O'3̹zޜ3挘T>8 ג~jZݝ6svU_02 endstream endobj 362 0 obj <>stream +HViTTG5u[\!jkiĉn(phDYDmMEF8FMLԨs *F$Ęqиdr&! Lu7It}uzU_w 2 ` ཾ-5=בw0B Br~3gg޸6IaeYroF\gi 37]wȵ'Jh(Z#_F' ˟<hpg4Js J +@"c;"{74223kGr,M>cJp-?4b6޽J= '{,|=/}0e! É88H|:\7* c?<S|;5ZAkh+wA6xAwxzB/ }a "O:'@.̅(RX+`%`5&(x8ed֔L[i Jm":}DOUtAB$ &b3,NLL% (+ig<*/M  +k}V'80a !^cFp8'PT򞼜J^/~,؁4S̄_Y8P0(md%|) lf Y[ʪ75 )ˍm-C~VYk7kurжAP۫V5ZU4uZQϫoFIlZK k#mVUhmv@;nFkM}W[7mѦںzF.=xAF;ؙoogfoj~7B"Cfw ]^͏.M͞X,Mg9wĽmePb ו7XVwwpn)kĽS5Pj\ R=^Po5HZ_|ͩhNumK-[K؂Zpfzpkp_~wahjSثIФyp{k_VL"+$ x8dE7 ᧿5<ؽOp oQcl9 +3e/Nl ;iuu뢾n}}3quINb~rmup%E +KKw:]_>!խo=35~rẼ~ݣQ^yģ;"x376IW_19||h tZb,s,93dY]ײ~Բn=-ΧԲ?Oy-[LegaDɮX#ٲF>K>+%p@lNZeTcR)JPɏaJ+9Le%J0I75Δad*J*lM*R{ 0@jCTR1ȗP =ދ~{vP gCgy\:@?^b/|)?1Cu |`|??8eB +t~ f"?79Ϳxm|(Ot9b )"k:BV$Q;1ͭ64H,!b) KhxFh2C90>qRE-9yJCWxTA֋FX0!6El8E,dNVFl  +8#u'ƳbJřD_"JYLl#+gY>YڵX D&,|3+22}ɶn^{?QK~"!UdR2e%PJŇlAx4tMaߊ>z,5Z^ċK(,9Gh'OGtc|=L䟋PE1D hXIs QMfj"?$Y7tuasyY +aoDE CE=d؍(2e){콗2VHB $y/q_{R? `ZsUT%dQUBmhZ4 f`[|v͌fh6ޒ81F9  ʞhcɗ6F[Ѷh{#ɻ\+T(UEi(=y:?DQ8D1)|&.erVus0Inm S !-5:y3a}+*;`9BR@J `>,/a!|rKw~iCe~_WU{:T5CP7ԗClhh^IEcA-2kI-e|]VFE*!#4 qZUi*m`h5I E(M]5:Z/ !%t֢i%IQi},%5FDe68ʹ̯IjwKkO}ׁ:Dp#Cc|[L9cRL*u+}&e(ofǣf`6ysCcS7RWJ7yGƙ9eN39gΛ_Qh.j$h榹mI>>2VbXU= +?=,59=EkbKkb]|hדM |K/:|?Oacl>Ym N0桬7L&**a&҇Ȃu`ђ_[mQ:kⶄ%m)[Ɩ73Wle[Vm [ֲm,b3$Wgmi[9m̵l=up-\GurKp]\+UJi-oڊr]7uwm˺Ovu{|o1j"&Sa ܂pA2l;R`'O?]Ч/N3!v= a{샇Ȅ7eC8pr<㐋MZ}@[p݆&*ke}pYQ9LyrnmSNN!lpځp989`zBO=쟑a ޴Q*ㆾn<'<8h}%_Y.s5> C΁7M+ Hu$, rX^Gh#8۴G^ Ñ? Σ$Oq/&.[52 .kHEq]4^1 Cn83)fq3| d!w"܅Ru~jPR-F<ԂSK@<Bej3Ϣ<:s^HWԓN>BC(h|3>|h$FEŗo|>k4h?p& 2x؈ 6o%ZM;ؔa3ZiE'XN_q*"NK]tgU+Y.%C=ɖC9>d)4H=yAH}vcJ8z !b!a{ eaXh%@V̈kV2v;1˹G`rb'}:b˩8ĉS2yoV$ +E~X':D^b5:`=:qHGqqXpaA/x6x\|I<&N'ėa=pv~ wyqNZ(^&h*:?xwCF8!8 +8\fl lX + y؝Ax X 4CNl'Wl}b+00pxR<-Έoķi|> Gsp$FH\PPih+*+zDx+_x# vV)&wû;me{;[ pF8|>_..Zu|_y_u|=NŻy_|~kgp5,&5l#s:^o.wfn=k=g=oz8j%/0GVYV5úںv=߲ͣg,ϲas~?ɟ/3g؏ُOطI=͞SV;O|]jǎ22o3#.yF?cy`Vax Z3/ZZE?5~3 O+{40ȃ8:7AىV]i %<)OS;uYw\^WQ#j DB6e`gS)-6L^[u}s8\&7a'EW|MPɠD* 깸5z>'晼+шbAjȻ>H:BK-yq͒gk#n(X4;yWs;,i槴lK?+餤~5s:R}GeZtBf]naI4A}+JD)#N2FZ#v +9СrDNxPi`%*$J8kqvURDbPK=T{X-]~kJIwݥxT`T:nPYhV$)n6B?Y f"Rw +z-bzIm}FqtN`ӎm;1UWH ]r4 sU0s=2˱(zJ?6m3l*Kl t**`$k0$g BjX$Q'y +HU H^(ə*Qɴf[R>{R:)=K"lmwKdm$9m$i$砍$kFuh#FsFJưR +N0>-t*SI2alcj꜋c\0>2/TrqhMc˕`M{njhOn/v!Ɣ^ߨXHSbʴlP.6v:E%UOG 8ejAH1'l,]K/tmȒڧ~t'Lf]Z/K30v+vsi+4JtA[G N!اt34 ݊9QC+"ԂM.M; cϱeQmhKS.L2^7CJE؋g.^#^()j9lWh:nGV A#^ p' $NAqt@qH.qxq&L[ӊ`+ql#8 +"'$J/ -t[BюpŭJ/cEȾ-Dľ=DDC1iRwCD=JEH"Q1x& /ب+ ތ3x/x<Ìw3 l1`bb.%$aJEEQ@DX6iCVH-j!).))ԔAYAӹ;s{׾|N)B/A%&#Mǜτ %4 z8V+qqF v6[9#\)4!ЬyE#v|@fÑLJKEJS%h^d}+]’ 36B!Ԫ{smϢF<Q>D7(gQjGPj!lc_ZK֣"U e:l,ZWc\ +g[cWq-\:_*u^t֋55hn$T" /L1fW 96 Zsbw" z-g6Y c نu I%wk)'Sm粝Apq(C +wUyOGF,D 7xYr!:7SnG;EG4nc's }r$?!|qNJGd|\ i$^cÊY}w@#T0aL7Q +ej3.TkKQ,ߤ.!LR'NY!]4aꆡNO^ElDڀ.OS,j 51B1#ԡG5*)PlQUpڇjߏS|aF C#Oʶ|~ +֭oĨ]+^ Y}~{<€M|:E"/K{z̷+-)a<:5e4BF!c4*ḨѠ~Ʋ_lG&}Lx3Z)X&Oy"̸-A )9v#b)R mSl!M4sL!s#`>&Xio3VL<#ôt,Ux?!daRU<7Ё6YüBdLv ܡ}Q^bhE_2s1HL<7\o;uqG0|fYLjGj> >!I5) b#%L%4n[G)%E!6FKoIY>!bv{\Ivsaщ(ӏpP.?>{7k^!!>ywU<%?Q,?7>F_!J÷Р`Yȳg}6a+V,qǭ^,Y8YTq)ch'sH.DZx'# '?vw=,d@&5 H la %D )H2 4,aA0*U:8 RH a9.aL7ͽ{se߽QZm;w("TdN?\p:|~<rSF`j UŒ S%O<f:)Cg'$M!ٌs So\VKc8u9!^}ܝ!Is7aW7]nX+fizJ7ŕgxz,'я6]%Ɉ ` )Z+1^3 +sAqgIx73^hNX0Qζ}\s6JgL8+b}R9,7tsCÝQ>^{5h }F$:4~ۛ!Y꾎Z9p)C9;d 塏YU֧Xow +|=^/xz/}Z.\ֱ\|BB}3J˫jku)tJєU٪Uc2뭺[e~7&in#SlCRnd;\N;ibI NR#$UXw4w'SxxΘin7i~RV*-1w,2U}o+9웯S]G>#e{*%|y/:%Œ6>G}ϳR9onoƷ3\K|tu"!28T t#ﶆxqfJ~5_ՂS&3V.`tg!f“}tPZQԋhO̩#ŴWkn=qQM+goaԗi6}8^A3 :V >YFyҚvQ%TF?JѴWku/&޹M->ڶ 7ZKk[~Ozi%:j'28tglqG<哴7t WfJ)9󮴶9rH;2 kO=9'7Ȝ5YR^dޟ57,Gŏ<;%GZۭn05pW%IN29C3 f,ٓU:\t^d"3\!u1`%Z7>7C +76`y}|$Kc(\G38xmi.0W݅ċ:,vzxxsǠ0+%Sg?^)rFSRyMy͹_ח~u0`h\ b}Y^N|/ex7KP,~'!}B-9Y8ļ>uqJ;/ |ɌL<9I3OY$1}qEYmʜ3Vk5ƧA#ZJsyPc%2 w<9") hsc}GP2=ߝ'%[Ur̽8c1Ju G>gR 8e,bb'풫r⹒IȆAO6!~:/r.g ѿ!m``8(6lZKmO%-i~^ /6<0 ,/`'/}$݂Ah  +m6Im [PO7dH +O=٧eTfruRGheLW[e(޲f48WJPZcj)13[~=moQgS$E2Y淐VEnPe2:'餦sƭoˁ,o:v}W_,^ld:}ȳB%Ȳ\uv4 ~.\mJS(P@(skˍz-tR-rJΐGKNGm~$DJ3|Vzih>,lxb7J (6͆g`nꃺsC{,{wmȽB~P~&Z 6nQDa/.wOs-s@ Ӳ"^p[6AWmxΗEP&[_ PT`Q AWtP"MPDFT"K` 5FmL2MLMMb)j'M3㤓fEVh|NӱM5{Nmg:Ws}s49UsUMYܷY؞o8Q)U}bxx^3[~]nb513cżkh#o9)؏Px0rVqu6.Ah!F̶NJ>c Fqq-Ebu-[ɧa^<O@)>  vn]GW_|WC=V_4bӄ|}A{V4ͥᆵ{7bLjyN8V8b;ԯ\kE/d\݁6[?Ę#1leºr#Njy A>VV>5댚Ϛf󿨙XfSpnvžFXDfRߐnSoGԥ|{.(5-a-ou876e8[Xt8;]3mLJ#I[K#>}VaC_Ymk[[އG[2WOQkPOQ\P*N(qB2 yֺu߇_g^bu A^wѝӣv‡h!|a/" 4!nmT+Q䈲Iyϰ'>|&̣";#3_mg +AFh{ֶՌoc)u-}?ڥkxlJ ӈol9/l|fsVta-Lw)iuZ745>.Yԁ[1l_g]%c _k-|%b+S(ӊ˞Y;ؽ 'Lǭ2ś_Glš{ 5ifRUVހEׅsX@ kV? +ciޅO&*=m@͈kz#EwoOmk/X9]>DFQYdIķ˱39d0H6_ jHU:C,xgTyms"`|7f&CjWV~N;ݩFrx54#1wi[HCMi@%{I\OwְuT0}t67ɫ84Q{JFm5=ZY(baOь*/HQޣhhƻ͡%,< jS{Vgsx"l}r?{)ToRz nײ)s'"4i]A#-rΪnW~"4H7[( Ak4L~)?w2|.! w%ҘF8c&,*"12h%ݯLkֈ{nu(GR񭏀uHD-Zɺ@duz`@~pB C9d@eV rmDf] G0ڏq6!HAFy&lфY8WpW2T}3,:G\!%eQ0l-UP=K"ghV6DB[V[ +yMN*F4Igi1bt&"hbDcS\d bL B89C-_!<˩aLdw+O9D)W@9R4R2 P@&Q +}zT6tJRC|`> V!TUbI7@Iḣp'q7M>l]OÚwsTnLkJ6wyp8p8p8p8p8p8QF-\ZLUDtfԏh-XLPr1k/< (J4v['%\ rFE.!k " +_qIP]:%z:7PZ˖V3k|^OH] g[UUVEIz/Xy+z=zVy` gJlZx+`WHS[E=[Q TwjE`WTNr3L/-,Z}JPVzeKS]ޱfPʩ*GTBAi4QxT#4-A[ TJ'ji-EjPfjZr +ZTDք-hLS(m'I8n8Uy̛{s?x37TȵEJ1% l` +:n#RQj>ݳ,x u⨣ÓUag:u탩(J4w\ {M!S}6[*]Z<,HKQ\\LV_Eo/LrϬ]OΕԀyt3akƩi-_ 3^$Ir! q݌Ў+c-VBԔC&.^$-Ќ3X `:D&Msdr&\6-WbwsXv̕9#r)j}y '(̧8 endstream endobj 363 0 obj <> endobj 364 0 obj <>stream +H\Pj0 +t=,NfeK!>hpl%54QCl{FH#%S]N`t.a%0(+Τ[o3($mI8w~ B)\\mpzaodu 5'(mȃ^t|3̲Kgva_,.Q$'hA=sWo0oMBU{oQ0U3xM}ˀJƲݰx_j X+Opxl endstream endobj 365 0 obj <>stream + + + + + application/postscript + + + wisaad + + + + + constellation in cosmos panorama background, group of star in galaxy, astronomy set, vector illustration + + + + + constellation + astro + star + symbol + sign + collection + space + panorama + auriga + perseus + cassiopeia + cepheus + cygnus + lura + ara + orion + canis minor + canis major + puppis + vela + carina + crux + triangulum australe + set + group + astrology + icon + element + galaxy + cosmos + astronomy + connection + vector + illustration + sky + shine + dot + bright + shine + illuminate + night + science + nebula + milky + atlas + geography + view + + + + + constellation panorama set + + + 2018-06-12T11:21:37-07:00 + 2018-06-12T11:21:37-07:00 + 2018-06-12T11:21:37-07:00 + Adobe Illustrator CC 22.1 (Windows) + xmp.iid:ad61e51b-3fa8-d44a-a211-39efe692e76a + xmp.did:ad61e51b-3fa8-d44a-a211-39efe692e76a + uuid:5D20892493BFDB11914A8590D31508C8 + proof:pdf + + xmp.iid:732fe992-5210-4b08-a823-8dc371b7dad9 + xmp.did:732fe992-5210-4b08-a823-8dc371b7dad9 + uuid:5D20892493BFDB11914A8590D31508C8 + proof:pdf + + + + + saved + xmp.iid:f7523d70-61a9-4c03-b0f1-18d800bdb131 + 2017-01-19T01:40:16+07:00 + Adobe Illustrator CC 2015.3 (Macintosh) + / + + + saved + xmp.iid:732fe992-5210-4b08-a823-8dc371b7dad9 + 2018-01-31T21:46:09+07:00 + Adobe Illustrator CC 22.0 (Macintosh) + / + + + converted + from application/postscript to application/vnd.adobe.illustrator + + + saved + xmp.iid:ad61e51b-3fa8-d44a-a211-39efe692e76a + 2018-06-12T11:21:37-07:00 + Adobe Illustrator CC 22.1 (Windows) + / + + + converted + from application/postscript to application/vnd.adobe.illustrator + + + converted + from application/postscript to application/vnd.adobe.illustrator + + + + Print + False + True + 1 + + 2927.160500 + 680.568183 + Pixels + + + + Cyan + Magenta + Yellow + Black + + + + + + Default Swatch Group + 0 + + + + White + RGB + PROCESS + 255 + 255 + 255 + + + Black + RGB + PROCESS + 35 + 31 + 32 + + + CMYK Red + RGB + PROCESS + 237 + 28 + 36 + + + CMYK Yellow + RGB + PROCESS + 255 + 242 + 0 + + + CMYK Green + RGB + PROCESS + 0 + 166 + 81 + + + CMYK Cyan + RGB + PROCESS + 0 + 174 + 239 + + + CMYK Blue + RGB + PROCESS + 46 + 49 + 146 + + + CMYK Magenta + RGB + PROCESS + 236 + 0 + 140 + + + C=15 M=100 Y=90 K=10 + RGB + PROCESS + 190 + 30 + 45 + + + C=0 M=90 Y=85 K=0 + RGB + PROCESS + 239 + 65 + 54 + + + C=0 M=80 Y=95 K=0 + RGB + PROCESS + 241 + 90 + 41 + + + C=0 M=50 Y=100 K=0 + RGB + PROCESS + 247 + 148 + 29 + + + C=0 M=35 Y=85 K=0 + RGB + PROCESS + 251 + 176 + 64 + + + C=5 M=0 Y=90 K=0 + RGB + PROCESS + 249 + 237 + 50 + + + C=20 M=0 Y=100 K=0 + RGB + PROCESS + 215 + 223 + 35 + + + C=50 M=0 Y=100 K=0 + RGB + PROCESS + 141 + 198 + 63 + + + C=75 M=0 Y=100 K=0 + RGB + PROCESS + 57 + 181 + 74 + + + C=85 M=10 Y=100 K=10 + RGB + PROCESS + 0 + 148 + 68 + + + C=90 M=30 Y=95 K=30 + RGB + PROCESS + 0 + 104 + 56 + + + C=75 M=0 Y=75 K=0 + RGB + PROCESS + 43 + 182 + 115 + + + C=80 M=10 Y=45 K=0 + RGB + PROCESS + 0 + 167 + 157 + + + C=70 M=15 Y=0 K=0 + RGB + PROCESS + 39 + 170 + 225 + + + C=85 M=50 Y=0 K=0 + RGB + PROCESS + 27 + 117 + 188 + + + C=100 M=95 Y=5 K=0 + RGB + PROCESS + 43 + 57 + 144 + + + C=100 M=100 Y=25 K=25 + RGB + PROCESS + 38 + 34 + 98 + + + C=75 M=100 Y=0 K=0 + RGB + PROCESS + 102 + 45 + 145 + + + C=50 M=100 Y=0 K=0 + RGB + PROCESS + 146 + 39 + 143 + + + C=35 M=100 Y=35 K=10 + RGB + PROCESS + 158 + 31 + 99 + + + C=10 M=100 Y=50 K=0 + RGB + PROCESS + 218 + 28 + 92 + + + C=0 M=95 Y=20 K=0 + RGB + PROCESS + 238 + 42 + 123 + + + C=25 M=25 Y=40 K=0 + RGB + PROCESS + 194 + 181 + 155 + + + C=40 M=45 Y=50 K=5 + RGB + PROCESS + 155 + 133 + 121 + + + C=50 M=50 Y=60 K=25 + RGB + PROCESS + 114 + 102 + 88 + + + C=55 M=60 Y=65 K=40 + RGB + PROCESS + 89 + 74 + 66 + + + C=25 M=40 Y=65 K=0 + RGB + PROCESS + 196 + 154 + 108 + + + C=30 M=50 Y=75 K=10 + RGB + PROCESS + 169 + 124 + 80 + + + C=35 M=60 Y=80 K=25 + RGB + PROCESS + 139 + 94 + 60 + + + C=40 M=65 Y=90 K=35 + RGB + PROCESS + 117 + 76 + 41 + + + C=40 M=70 Y=100 K=50 + RGB + PROCESS + 96 + 57 + 19 + + + C=50 M=70 Y=80 K=70 + RGB + PROCESS + 60 + 36 + 21 + + + R=184 G=134 B=11 1 + RGB + PROCESS + 184 + 134 + 11 + + + R=125 G=92 B=15 1 + RGB + PROCESS + 125 + 92 + 15 + + + R=145 G=111 B=32 1 + RGB + PROCESS + 145 + 111 + 32 + + + R=38 G=34 B=98 1 + RGB + PROCESS + 38 + 34 + 98 + + + R=35 G=31 B=32 1 + RGB + PROCESS + 35 + 31 + 32 + + + R=37 G=52 B=98 1 + RGB + PROCESS + 37 + 52 + 98 + + + C=0 M=0 Y=0 K=100 + RGB + PROCESS + 35 + 31 + 32 + + + C=0 M=0 Y=0 K=90 + RGB + PROCESS + 65 + 64 + 66 + + + C=0 M=0 Y=0 K=80 + RGB + PROCESS + 88 + 89 + 91 + + + C=0 M=0 Y=0 K=70 + RGB + PROCESS + 109 + 110 + 113 + + + C=0 M=0 Y=0 K=60 + RGB + PROCESS + 128 + 130 + 133 + + + C=0 M=0 Y=0 K=50 + RGB + PROCESS + 147 + 149 + 152 + + + C=0 M=0 Y=0 K=40 + RGB + PROCESS + 167 + 169 + 172 + + + C=0 M=0 Y=0 K=30 + RGB + PROCESS + 188 + 190 + 192 + + + C=0 M=0 Y=0 K=20 + RGB + PROCESS + 209 + 211 + 212 + + + C=0 M=0 Y=0 K=10 + RGB + PROCESS + 230 + 231 + 232 + + + C=0 M=0 Y=0 K=5 + RGB + PROCESS + 241 + 242 + 242 + + + C=0 M=100 Y=100 K=0 + RGB + PROCESS + 237 + 28 + 36 + + + C=0 M=75 Y=100 K=0 + RGB + PROCESS + 242 + 101 + 34 + + + C=0 M=10 Y=95 K=0 + RGB + PROCESS + 255 + 222 + 23 + + + C=85 M=10 Y=100 K=0 + RGB + PROCESS + 0 + 161 + 75 + + + C=100 M=90 Y=0 K=0 + RGB + PROCESS + 33 + 64 + 154 + + + C=60 M=90 Y=0 K=0 + RGB + PROCESS + 127 + 63 + 152 + + + + + + + Adobe PDF library 15.00 + + + + endstream endobj 366 0 obj <> endobj 367 0 obj <>stream + + + + + application/postscript + + + DejaVu_Vector_Logo + + + + + Anita Elder + + + 2018-06-12T11:15:18-07:00 + 2018-06-12T11:15:18-07:00 + 2018-06-12T11:15:18-07:00 + Adobe Illustrator CC 22.1 (Windows) + xmp.iid:5cf13117-3af1-0c45-b7d7-ac547a1ea5dd + xmp.did:5cf13117-3af1-0c45-b7d7-ac547a1ea5dd + uuid:5D20892493BFDB11914A8590D31508C8 + proof:pdf + + xmp.iid:03375135-0e19-4bec-b799-6da9b8675c55 + xmp.did:03375135-0e19-4bec-b799-6da9b8675c55 + uuid:5D20892493BFDB11914A8590D31508C8 + proof:pdf + + + + + saved + xmp.iid:b48ff162-4a38-4ed0-a4d1-55a6d9f1e278 + 2016-02-03T15:18-08:00 + Adobe Illustrator CC 2014 (Macintosh) + / + + + saved + xmp.iid:03375135-0e19-4bec-b799-6da9b8675c55 + 2016-02-03T20:50:50-08:00 + Adobe Illustrator CC 2015 (Macintosh) + / + + + converted + from application/postscript to application/vnd.adobe.illustrator + + + saved + xmp.iid:5cf13117-3af1-0c45-b7d7-ac547a1ea5dd + 2018-06-12T11:15:18-07:00 + Adobe Illustrator CC 22.1 (Windows) + / + + + + Print + False + False + 1 + + 515.069444 + 138.041667 + Pixels + + + + Cyan + Magenta + Yellow + Black + + + + + + Default Swatch Group + 0 + + + + White + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 0.000000 + + + Black + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 100.000000 + + + CMYK Red + CMYK + PROCESS + 0.000000 + 100.000000 + 100.000000 + 0.000000 + + + CMYK Yellow + CMYK + PROCESS + 0.000000 + 0.000000 + 100.000000 + 0.000000 + + + CMYK Green + CMYK + PROCESS + 100.000000 + 0.000000 + 100.000000 + 0.000000 + + + CMYK Cyan + CMYK + PROCESS + 100.000000 + 0.000000 + 0.000000 + 0.000000 + + + CMYK Blue + CMYK + PROCESS + 100.000000 + 100.000000 + 0.000000 + 0.000000 + + + CMYK Magenta + CMYK + PROCESS + 0.000000 + 100.000000 + 0.000000 + 0.000000 + + + C=15 M=100 Y=90 K=10 + CMYK + PROCESS + 15.000000 + 100.000000 + 90.000000 + 10.000000 + + + C=0 M=90 Y=85 K=0 + CMYK + PROCESS + 0.000000 + 90.000000 + 85.000000 + 0.000000 + + + C=0 M=80 Y=95 K=0 + CMYK + PROCESS + 0.000000 + 80.000000 + 95.000000 + 0.000000 + + + C=0 M=50 Y=100 K=0 + CMYK + PROCESS + 0.000000 + 50.000000 + 100.000000 + 0.000000 + + + C=0 M=35 Y=85 K=0 + CMYK + PROCESS + 0.000000 + 35.000000 + 85.000000 + 0.000000 + + + C=5 M=0 Y=90 K=0 + CMYK + PROCESS + 5.000000 + 0.000000 + 90.000000 + 0.000000 + + + C=20 M=0 Y=100 K=0 + CMYK + PROCESS + 20.000000 + 0.000000 + 100.000000 + 0.000000 + + + C=50 M=0 Y=100 K=0 + CMYK + PROCESS + 50.000000 + 0.000000 + 100.000000 + 0.000000 + + + C=75 M=0 Y=100 K=0 + CMYK + PROCESS + 75.000000 + 0.000000 + 100.000000 + 0.000000 + + + C=85 M=10 Y=100 K=10 + CMYK + PROCESS + 85.000000 + 10.000000 + 100.000000 + 10.000000 + + + C=90 M=30 Y=95 K=30 + CMYK + PROCESS + 90.000000 + 30.000000 + 95.000000 + 30.000000 + + + C=75 M=0 Y=75 K=0 + CMYK + PROCESS + 75.000000 + 0.000000 + 75.000000 + 0.000000 + + + C=80 M=10 Y=45 K=0 + CMYK + PROCESS + 80.000000 + 10.000000 + 45.000000 + 0.000000 + + + C=70 M=15 Y=0 K=0 + CMYK + PROCESS + 70.000000 + 15.000000 + 0.000000 + 0.000000 + + + C=85 M=50 Y=0 K=0 + CMYK + PROCESS + 85.000000 + 50.000000 + 0.000000 + 0.000000 + + + C=100 M=95 Y=5 K=0 + CMYK + PROCESS + 100.000000 + 95.000000 + 5.000000 + 0.000000 + + + C=100 M=100 Y=25 K=25 + CMYK + PROCESS + 100.000000 + 100.000000 + 25.000000 + 25.000000 + + + C=75 M=100 Y=0 K=0 + CMYK + PROCESS + 75.000000 + 100.000000 + 0.000000 + 0.000000 + + + C=50 M=100 Y=0 K=0 + CMYK + PROCESS + 50.000000 + 100.000000 + 0.000000 + 0.000000 + + + C=35 M=100 Y=35 K=10 + CMYK + PROCESS + 35.000000 + 100.000000 + 35.000000 + 10.000000 + + + C=10 M=100 Y=50 K=0 + CMYK + PROCESS + 10.000000 + 100.000000 + 50.000000 + 0.000000 + + + C=0 M=95 Y=20 K=0 + CMYK + PROCESS + 0.000000 + 95.000000 + 20.000000 + 0.000000 + + + C=25 M=25 Y=40 K=0 + CMYK + PROCESS + 25.000000 + 25.000000 + 40.000000 + 0.000000 + + + C=40 M=45 Y=50 K=5 + CMYK + PROCESS + 40.000000 + 45.000000 + 50.000000 + 5.000000 + + + C=50 M=50 Y=60 K=25 + CMYK + PROCESS + 50.000000 + 50.000000 + 60.000000 + 25.000000 + + + C=55 M=60 Y=65 K=40 + CMYK + PROCESS + 55.000000 + 60.000000 + 65.000000 + 40.000000 + + + C=25 M=40 Y=65 K=0 + CMYK + PROCESS + 25.000000 + 40.000000 + 65.000000 + 0.000000 + + + C=30 M=50 Y=75 K=10 + CMYK + PROCESS + 30.000000 + 50.000000 + 75.000000 + 10.000000 + + + C=35 M=60 Y=80 K=25 + CMYK + PROCESS + 35.000000 + 60.000000 + 80.000000 + 25.000000 + + + C=40 M=65 Y=90 K=35 + CMYK + PROCESS + 40.000000 + 65.000000 + 90.000000 + 35.000000 + + + C=40 M=70 Y=100 K=50 + CMYK + PROCESS + 40.000000 + 70.000000 + 100.000000 + 50.000000 + + + C=50 M=70 Y=80 K=70 + CMYK + PROCESS + 50.000000 + 70.000000 + 80.000000 + 70.000000 + + + C=71 M=18 Y=40 K=0 1 + CMYK + PROCESS + 70.999998 + 18.000001 + 40.000001 + 0.000000 + + + + + + Grays + 1 + + + + C=0 M=0 Y=0 K=100 + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 100.000000 + + + C=0 M=0 Y=0 K=90 + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 89.999400 + + + C=0 M=0 Y=0 K=80 + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 79.998800 + + + C=0 M=0 Y=0 K=70 + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 69.999700 + + + C=0 M=0 Y=0 K=60 + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 59.999100 + + + C=0 M=0 Y=0 K=50 + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 50.000000 + + + C=0 M=0 Y=0 K=40 + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 39.999400 + + + C=0 M=0 Y=0 K=30 + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 29.998800 + + + C=0 M=0 Y=0 K=20 + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 19.999700 + + + C=0 M=0 Y=0 K=10 + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 9.999100 + + + C=0 M=0 Y=0 K=5 + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 4.998800 + + + + + + Brights + 1 + + + + C=0 M=100 Y=100 K=0 + CMYK + PROCESS + 0.000000 + 100.000000 + 100.000000 + 0.000000 + + + C=0 M=75 Y=100 K=0 + CMYK + PROCESS + 0.000000 + 75.000000 + 100.000000 + 0.000000 + + + C=0 M=10 Y=95 K=0 + CMYK + PROCESS + 0.000000 + 10.000000 + 95.000000 + 0.000000 + + + C=85 M=10 Y=100 K=0 + CMYK + PROCESS + 85.000000 + 10.000000 + 100.000000 + 0.000000 + + + C=100 M=90 Y=0 K=0 + CMYK + PROCESS + 100.000000 + 90.000000 + 0.000000 + 0.000000 + + + C=60 M=90 Y=0 K=0 + CMYK + PROCESS + 60.000000 + 90.000000 + 0.003100 + 0.003100 + + + + + + + Adobe PDF library 11.00 + + + + endstream endobj 368 0 obj <> endobj 369 0 obj <>stream +HtkQO1u $ci`aA"Vi AErpLˆʊ3/ox~qy~])~ ?_u>;xs_Jd&'%Qy_~,"1"",!Fq沄[aP{PPPsТQ9JJI!c8>xa`E8s]BlO&,8CC]Bu oRsB΂?pgr|>LzOK7'3lO"",!Fq沄; F,jjbZ43GV U >)΂ -:4t>%d(\&>#t+] endstream endobj 370 0 obj <>stream +Adobed + + + +                +   + ZG +!"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyzVK +!"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?K@0Xx? endstream endobj 371 0 obj <>stream +Adobed + + + +                +   + ZG +!"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyzVK +!"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?K@0Xx? endstream endobj 372 0 obj <>stream +Adobed + + + +                +   + ZG +!"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyzVK +!"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?K@0Xx? endstream endobj 373 0 obj <>stream +Adobed + + + +                 +   + ZG +!"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyzVK +!"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?K@0Xx endstream endobj 374 0 obj <>stream +Adobed + + + +                +   + ZG +!"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyzVK +!"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?K@0Xx? endstream endobj 375 0 obj <>stream +Adobed + + + +                 +   + ZG +!"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyzVK +!"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?@@ endstream endobj 376 0 obj <>stream +Adobed + + + +                +   + ZG +!"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyzVK +!"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?K@0Xx? endstream endobj 377 0 obj <>stream +Adobed + + + +                +   + 9a!A +"#$%&'()*123456789:BCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz$s!1 +"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?I9  X`J0+a$8sa9OB endstream endobj 378 0 obj <>stream +Hb`0ˆ*%&* *Ō,&$.)'͊[BF[JIZ30P] nODLt.?; .%}(o{-q@aĤX'-e.!zqvZ\p+Yd4B=M儙Tprv2RBr8',TxP#09@.H0. endstream endobj 379 0 obj <>stream +Adobed + + + +                +   +  4c!1Aa +"#$%&'()*23456789:BCDEFGHIJQRSTUVWXYZbcdefghijqrstuvwxyz"s!"1B +#$%&'()*23456789:ACDEQFGHIJRSTUVWXYZabcdefghijqrstuvwxyz?M!#.`@TbD +b1|t(Lќ7yp 0Bq@ endstream endobj 380 0 obj <>stream +Adobed + + + +                +   + 5e! +"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYqZabcdefghijrstuvwxyz{! +"#$%&'()*1234567A89:BCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?Ix%Rb"~FءB2MBь endstream endobj 381 0 obj <>stream +Hb``dddd&FTANQ1Y91Q.d &!)uuMq6(3 B9W@'+\XR=$&6NMOE72!.A[E'">.AIER5(,>stream +Adobed + + + +                +   + 0g!"AQ +#$%&'()*123456789:BCDEFGHIJRSTUVWXYZabcdefghijqrstuvwxyz w!"Aa +#$%&'()*123456789B:CDEFGHIJQRSTUVWXYZbcdefghijqrstuvwxyz?M"C*8p -S +Ā:A( w3?( xD8! +  endstream endobj 383 0 obj <>stream +Adobed + + + +                +   + <_A +!"#$%&'()*123456789:BCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz&s! +"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?I9! &1X`J0f6BH"xCs  b endstream endobj 384 0 obj <>stream +Hb`0Ȋ*%*.((-Ł,%"!'+΍[FJ]J.$l頭"e0 +u``n&Ŋr OH@f0 qBX)ea$„p #2j*2>stream +Adobed + + + +                +   +  4c!AQa +"#$%&'()*123456789:BCDEFGHIJRSTUVWXYZbcdefghijqrstuvwxyz w!"$1 +#%&'()*23456789BQa:ACDEFGHIJRSTUVWXYZbcdefghijqrstuvwxyz?MAC.`H +(H'J^MPg%##H $$9!J endstream endobj 386 0 obj <>stream +Adobed + + + +                +   + 5e! +"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz!1 +"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?I@$C0 qG,%F Thh8 R38 endstream endobj 387 0 obj <>stream +Hb``fddT F^Qa~~aQ^daNn1e%UUuyan&$\b涶溒bpa&!y};/__wkC)A6(+g`Dd'ZfNM P7iNFOXtL4\5P'J KGW'c 9. LL4EFA98P3;'';#@  endstream endobj 388 0 obj <>stream +Adobed + + + +                +   + +m!AQ +"#$%&'()*123456789:BCDEFGHIJRSTUVWXYZabcdefghijqrstuvwxyz$s"AB +!#$%&'()*123456789:CDEaFGHIJQRSTUVWXYZbcdefghijqrstuvwxyz?NE%PP*̎h@\0!3A<(,%ax0 endstream endobj 389 0 obj <>stream +Adobed + + + +                +   + (s! +"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz{! +"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?IBp0XFD9Beee` H@cF њ1 endstream endobj 390 0 obj <>stream +Hb` `ecfc`bDdddCfWWbB2CXFMS_PCZa;\]XA+0HNG- "\IIX3$,< +Y]T/HU&+ehm"BFN1m=3MI1$+ɊpxCHXJP02C5!Ȉ%d) D endstream endobj 391 0 obj <>stream +Adobed + + + +                +   + -mA +!"#$%&'()*123456789:BCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz w!2A +"#$%&'()*13456789:BCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?Nq.1 $hD\!tDŽY){!/DD9Bcpa964 +B9@/ endstream endobj 392 0 obj <>stream +H1iHbX,bX,bX,Ų,#3 endstream endobj 393 0 obj <>stream +Adobed + + + +                 +  + )q"1 +!#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz +1 +aq!"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZbcdefghijrstuvwxyz?QPXPq(NbD D7 A$&aU+1(,) +PaUdäR)B(%4Jbs: endstream endobj 394 0 obj <>stream +Hb`5`acd`B`dggDPW@2qXZZʊspxz;rfӷ ѕ`ʘ:DEGEE$ bc >stream +Adobed + + + +                 +   + "w!1 +"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz1!Q +"#$%&'()*23456789:ABCDEFGHIJRSTUVWXYZabcdefghijqrstuvwxyz?ʒQb@@j8G[:SJ 9& !  f:*+*ja$2pdA!D 0&`' +}Y+)$% +bhB(pmWT& PHQrLA `G endstream endobj 396 0 obj <>stream +Adobed + + + +                 +  + &s"q +!#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijrstuvwxyz + +1a!"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZbcdefghijqrstuvwxyz?QPX %qFa 'TKhE Ht!ZX2Ձb +o +xL0 UC#NJt@dPB(%4LBqBAo endstream endobj 397 0 obj <>stream +Hb`8Ĉ")"+%ņKJFQSSQN ISJBE@KV.""mak$ǎ0CP9(,&BQn-;gh\ldx|l6?BIT)0"*FY&()nb''p!3G䤅Q 'jH12qZP%1)d endstream endobj 398 0 obj <>stream +Adobed + + + +                 +   + y!1 +"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz1!Q +"#$%&'()*23456789:ABCDEFGHIJRSTUVWXYZabcdefghijqrstuvwxyz?ʢQb<8FhBj38F[2& BYE̦@H"O dPE\Jd`UI" `\1$dA!08`O`a +L + c.giD8A,PO!9(p^T%P!WPb ? endstream endobj 399 0 obj <>stream +Hb`Y,\@rp +H*IrqB% 455eX@|F)ys;W{=5..f. uP_KU&.#ȄoSm~.VF!)+h?{ e.fGxRrrL"F.U=G +vQ C9a6LR֞nN + @{%ttd gdTbzK9" `0  endstream endobj 400 0 obj <>stream +HbfN$+`ᓖcc"''!+(Ƈi 3E5mm\= dxѬ`7s OLPUFu _Tj^Qnr8ݣK͔PɨX7vD)sȋ(eVw4{(s +dLl(qFQpͫmh* v1AuCdJIeuYV YX4,"22S]exP>>r21'milgaσ,<|JƦI_@XX@KzKHG$0k8D endstream endobj 401 0 obj <>stream +Hb``d`bf``cUTT`bdeѴ63Q`aҷ +6WQ +J+*-K qTPqNk9$5TNXD/qVWg礶dO= ˸ 05XG%vXsj$cbH{1q.bK$_nl JwUg|~So_GMF8wTfqeY~J0OXDD(73"&NJL "RRRL1H endstream endobj 402 0 obj <>stream +Adobed + + + +                +   + AY!"1 +#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz.k!1AQ +"#$%&'()*23456789:BCDEFGHIJRSTUVWXYZabcdefghijqrstuvwxyz?I`*:4hD +L<,0Œ$2ʙ$ endstream endobj 403 0 obj <>stream +H@EwؐE`þ{Gc@x2sg ϧ^Pk ,gsL ۰Oej,1a|u*i`9ݟ/ QpBgyq{/ԗW<6l{:m\B,VÚ''˼FRDn?hE|M$9gMwA endstream endobj 404 0 obj <>stream +Adobed + + + +                +   + :_!$a +"#%&'()*123456789:ABCDEFGHIJQRSTUVWXYZbcdefghijqrstuvwxyz'q! +"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?N èJ `A@G@$B,MњhⓀ@I$_ endstream endobj 405 0 obj <>stream +Adobed + + + +                +   + -m! +"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyzy" +!#$%&'()*123456789Q:ABCDEFGHIJRSTUVWXYZabcdefghijqrstuvwxyz?I@Y4Atb,,3PcB P0 !CGO endstream endobj 406 0 obj <>stream +Adobed + + + +                 +  + 4g! +"#$%&'()*123456789:ABCDEFGHIJQRSTUVWqXYZabcdefghijrstuvwxyz{! +"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?GhP$ +%r#ʃ'k25 %b" $JI?>stream +Adobed + + + +                +   + 3e!1a +"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZbcdefghijqrstuvwxyz{!1 +"#$%&'()*234567Q89:ABCDEFGHIJRSTUVWXYZabcdefghijqrstuvwxyz?M$L +‚A L) s#$ ^z՚8j0`!) R 0d endstream endobj 408 0 obj <>stream +Adobed + + + +                 +   + QM2 +!"#$%&'()*13456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz;a +!"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?IIbJQEd8 "b endstream endobj 409 0 obj <>stream +Adobed + + + +                +   + -m1 +!"#$%&'()*23456789:ABCDEFGHIJQqRSTUVWXYZabcdefghijrstuvwxyzy!1 +"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?@)j!`bJ"(NH$c\MYӏ1LRdFHa, endstream endobj 410 0 obj <>stream +H7k   endstream endobj 411 0 obj <>stream +Adobed + + + +                 +   + 8c1 +!"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz{!1 +"#$%&'()*23456Q789:ABCDEFGHIJRSTUVWXYZabcdefghijqrstuvwxyz?t(0 Q( +͌x0DfTh%a(B8"90>stream +Hb`0Ȃ*./+.Ǝ"%"+e722WgCR,,gfj'+efWж + +r 3+:FŇ!EubbܬUx2zAb; =\,ud9Y4s4PfGr8; 7عEDąؙP#0ٙ3## E 9 endstream endobj 413 0 obj <>stream +Adobed + + + +                 +  + /i!2A +"#$%&'()*13456789:BCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz +!"14A#$%&'()*2356789:BCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?"B\  (9H4XQ1q"fpEs2"UDJQm\#]T *o| 7z>3(1 endstream endobj 414 0 obj <>stream +Adobed + + + +                 +   + 2g!1Q +"#$%&'()*23456789:ABCDEFGHIJRSTUVWXYZabcdefghijqrstuvwxyz!1 +"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?t(0 Q( *1 EjR>RVRT")b#G1J '>stream +H@Й]J !zk@9E^^9Nwܭ'qykNZ?vV)>aڣz96 ѳ;l׋e̪eUtQThH]GT~/7 . endstream endobj 416 0 obj <>stream +Adobed + + + +                 +   + 1iA +!"#$%&'()*123456789:BCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz$sQ +!"#$%&'()*123456789:ABCDqEFGHIJRSTUVWXYZabcdefghijrstuvwxyz?M2*5 B $ @  +,M6BV$OBD')R + QN>'M endstream endobj 417 0 obj <>stream +HڴfMDkڸW/V/kW-XF0 endstream endobj 418 0 obj <>stream +xnJJJJ endstream endobj 419 0 obj <>stream +H1 Ϳi. +#Q?\&eR&eR&eR&eR&eR&eR&eR&eR&eR&eR&eR&eR&eR&eR&eR&eR&eR&eR&eR&eR&eR&eR&eR&eR&eR&eR&eR&eR&eR&eR&eR&eR&eR&eR&eR&eR&eR&eR?M7 endstream endobj 420 0 obj <>stream +Adobed + + + +                +   + 8c!A +"#$%&'()*123456789:BCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz!y! +"#$%&'()*12345678Aa9:BCDEFGHIJQRSTUVWXYZbcdefghijqrstuvwxyz?Ia X $$1")+?}+1fB endstream endobj 421 0 obj <>stream +Hb`032AY_@L .+"+`405֒`)54Аp+Z٘( qY[#0 jhIsRUWE q~{ـNfe   endstream endobj 422 0 obj <>stream +Adobed + + + +                +   + 4g! +"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyzy!Aa +"#$%&'()*1234567b89:BCDEFGHIJQRSTUVWXYZcdefghijqrstuvwxyz?LcD !* K@!- FucN8J8@!$F endstream endobj 423 0 obj <>stream +Adobed + + + +                +   + 3i! +"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz ! +1"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?Ia,,0X#1PDQKFN@4B"R +DI$J endstream endobj 424 0 obj <>stream +Hb`03ف!!"*!&bVP`gHkJk[ژDxLmDj$Ս,t`" s Uą`QWAX!"!.ŎDV6vvF$@ + endstream endobj 425 0 obj <>stream +Adobed + + + +                +   + ,k!1A +"#$%&'()*23456789:BCDEFGHIJQRSqTUVWXYZabcdefghijrstuvwxyz{!2Aa +"#$%&'()*13456789:BCDEFGHIJQRSTUVWXYZbcdefghijqrstuvwxyz?LN! 8\T`@G0%֘VKe$  + ` cP:P endstream endobj 426 0 obj <>stream +Adobed + + + +                +   + 4g1Q +!"#$%&'()*23456789:ABCDEFGHIJRSTUVWXYZabcdefghijqrstuvwxyz"w!A +"#$%&'()*123456789:BCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?IaA !#,A0J\>stream +Hb``FSG./$ (+U!gh*/ebma!71 +YYiʈA R12֑`J*(r1bC8.R@M + endstream endobj 428 0 obj <>stream +Adobed + + + +                +   + 2g!2 +"#$%&'()*13456789:ABCDEFGHIJQRSTUVWaXYZbcdefghijqrstuvwxyz w!"A +#$%&'()*123456789Qa:BCDEFGHIJRSTUVWXYZbcdefghijqrstuvwxyz?L0FCpBf@ @$Kqlͱp2h%Te/ endstream endobj 429 0 obj <>stream +Adobed + + + +                +   + <_!A +"#$%&'()*123456789:BCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz! +"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?I`p(AA1 H)dR--S Ѱ&D O!@ +P endstream endobj 430 0 obj <>stream +Hbd08 !+$."bSP qi +C V3V0I)[iqXژ먈4UaF%*SPZJɉL@7!   endstream endobj 431 0 obj <>stream +Adobed + + + +                +   + (o!1A +"#$%&'()*23456789:BCDEFGHIqJQRSTUVWXYZabcdefghijrstuvwxyz{!12Aa +"#$%&'()*3456789:BCDEFGHIJQRSTUVWXYZbcdefghijqrstuvwxyz?LP$A$!T B\aDLj1H KmdBHБ4 + ` cO:P endstream endobj 432 0 obj <>stream +HڴfMhxE׭zE;@| sŢW/܂f5+F endstream endobj 433 0 obj <>stream +Hb`03;BKPZF^C\US[WEB **,klf,aQ4S⇋([[IuIkku1)k+I',$*% Fv>N~vd 0} endstream endobj 434 0 obj <>stream +rJkeJ`h endstream endobj 435 0 obj <>stream +HڴfMxφ5 wl\ha͢h[jE{֯^( +K endstream endobj 436 0 obj <>stream +Hb`*`beeebDY9yYBBRrp!&!u-m I>A9-#KQ;L_^TGQWLYPSMf#+0zFV>QqN&$' d`"f endstream endobj 437 0 obj <>stream +ddJ__{ endstream endobj 438 0 obj <>stream +HڴfMhxE;׭rE; /]:cT DC+E endstream endobj 439 0 obj <>stream +Hb`*`bgggdAŸa, +r"|p!6^-]>60;D]XLCf8TUHFXPUVf#0ELb\>stream +jJr^Jig endstream endobj 441 0 obj <>stream +HڴfMhxŻ7^uEA| {۲3@4T~φՋ1+Q endstream endobj 442 0 obj <>stream +Hb`02فYOPL!-),+S& f`*%a74S`Z.lhem(W#mln%/ U/")KZAY^"FvA1AvI 1 endstream endobj 443 0 obj <>stream +xZ~]Jej endstream endobj 444 0 obj <>stream +HڴfMhxE׭ZaEMoYf=@]@=H+F endstream endobj 445 0 obj <>stream +Hb`022xxdťy +Z +0UVblP6.5S;'[3=i^\_X]f 26! %U9n9ʈ,@*0 + endstream endobj 446 0 obj <>stream +uMtbJas endstream endobj 447 0 obj <>stream +HڴfMhxE׭Z~E;A| cmW/UgÚE;7i+B endstream endobj 448 0 obj <>stream +Hb`0228ّdy*xutU`-UDء"Nvr0% G{3=)(?d.IM#CEaVeRj +ڲ|1pJ!;I  endstream endobj 449 0 obj <>stream +sKqcJ`d endstream endobj 450 0 obj <>stream +Adobed + + + +                 +  + &s12q +!"#$%&'()*3456789:ABCDEFGHIJQRSTUVWXYZabcdefghijrstuvwxyz!1 +a"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZbcdefghijqrstuvwxyz?QXƀXP 0`/;" +RX g@0Չb +rʫ%RF"63"PK )C!jt,7 endstream endobj 451 0 obj <>stream +Hb``fdddd&T FN~1qAAq1Nda.^E --Q^&(+3\IXV_Y KD=0"2BIKV;<**ZE .9=7K0P:+LORLSBFnayU#sSi1.$p K(*))J#;W-Xعh U$ endstream endobj 452 0 obj <>stream +Adobed + + + +                 +   + y#1A +!"$%&'()*23456789:BCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz!1Q +"#$%&'()*23456789:ABCDEFGHIJRSTUVWXYZabcdefghijqrstuvwxyz?ʢ%G (P` +:V)9$L0עCD$ +   g5pLaãdI" l!1@e и'0"e$Ua84R +BЄ(pEq-,$ endstream endobj 453 0 obj <>stream +Adobed + + + +                 +  + )qq +!"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijrstuvwxyz + +1a!"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZbcdefghijqrstuvwxyz?QPl,Qe 1@vN4J HpQ!ZĀg H` euR#PTZ +o +Ą 8a&UfӋ*S 3!A,&AD!P5Q endstream endobj 454 0 obj <>stream +Hb`0Ȇ*-#$((!͉,!*i`.'GR\AZ!!#on''eԴ +uPa.Vu OHR`E8D8[ a`Q6v u1RaA8WJPYp.~Y-mMM ) af$_1qIIp31F`Hqs32fF`~ endstream endobj 455 0 obj <>stream +Adobed + + + +                 +   + {!1 +"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz!1Q +"#$%&'()*23456789:ABCDEFGHIJRSTUVWXYZabcdefghijqrstuvwxyz?b#8BFq( (RV̶PThIesAHa"O&+˄rD+*I adA `x" 0&`a +~Y҆VR %>stream +Adobed + + + +                +   + 4g! +"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz! +"#$%&'()*123Q456789:ABCDEFGHIJRSTUVWXYZabcdefghijqrstuvwxyz?IJ( +U!bQ ZB̡C0%BXg <9 endstream endobj 457 0 obj <>stream +Hbd `cbbgeBPbET1PWWfApKʚXٙ)#Ĺ$T mኹbCUr);'{[s!#Q 5uM1 .3s(Kzh-;0Q +,Ć!H0F endstream endobj 458 0 obj <>stream +Adobed + + + +                +   + 7a!A +"#$%&'()*123456789:BCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz}"1A +!#$%&'()*234B56789:CDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?M8Ha5$*XA Jp +H% $Cha %)P 0@ endstream endobj 459 0 obj <>stream +Adobed + + + +                +   + 8cA +!"#$%&'()*123456789:BCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz w!1 +"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?I<x(A +|(Q u DςP2 # endstream endobj 460 0 obj <>stream +Hb`0ƈ&),/Ʉ,"(*#ņKJ@TWCYa7 L_/$^_nghd'3BX+,<>stream +Adobed + + + +                +   + 7a!Aa +"#$%&'()*123456789:BCDEFGHIJQRSTUVWXYZbcdefghijqrstuvwxyz s!"1AB +#$%&'()*23456789:CDQaEFGHIJRSTUVWXYZbcdefghijqrstuvwxyz?M!c.a2(@(( +U@_bBc R 4# endstream endobj 462 0 obj <>stream +Adobed + + + +                +   + 8cA +!"#$%&'()*123456789:BCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz! +"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?I<x(A +|8DQt244(TR!4ѡ@!c< endstream endobj 463 0 obj <>stream +Hb`0ˆ&)"/ˉ"-*)$%bdjcg)%Ƅ攖pq3ӗb̩dhjP)kiǎ$la$̩cjdo…lb&NzPbE< <0'o 6###3 e L| endstream endobj 464 0 obj <>stream +Adobed + + + +                +   + 7a!Q +"#$%&'()*123456789:ABCDEFGHIJRSTUVWXYZabcdefghijqrstuvwxyz w!ABQ +"#$%&'()*123456789:CDEFGHIJRSTUVWXYZabcdefghijqrstuvwxyz?MA!C.`J*Fpa @@  Tg%H$$!! + endstream endobj 465 0 obj <>stream +Adobed + + + +                +   + <_! +"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdeqfghijrstuvwxyz! +"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?I:!BBO|"CѠBJH & !C>stream +Adobed + + + +                 +  + 3e!1 +"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz+m!1 +"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?CP!8X s@[,K@LGMs !R,_>stream +Adobed + + + +                +   + 9a +!"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz +!"#$%&'1()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?LH +‚a )%c0r25iERiBBIJDDx< endstream endobj 468 0 obj <>stream +Adobed + + + +                 +   + TK1 +!"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz;a +!"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?>stream +Adobed + + + +                +   + 1i! +"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz w!A +"#$%&'()*123456789:BCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?@ +9H`a(,XAQ(%&%JjN1I4` ," endstream endobj 470 0 obj <>stream +Adobed + + + +                +   + 5e!A +"#$%&'()*123456789:BCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz#u! +"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?I<(.TQ G̓1 @'G,X#`P _ endstream endobj 471 0 obj <>stream +Hb`1`edddEdF1FN~9aYQdqFNQi5- UiQN(\)o$'3LOA/2:A[n2[hl\|spL\T4\-+WXxm*Fv*L XYZ+Jq1E95dE8P0pr@:\ endstream endobj 472 0 obj <>stream +Adobed + + + +                +   + :_! +"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz}!1A +"#$%&'()*234B56789:CDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?MA!`J*Fx&9aFH`Hlt4{zΊ0Bt L endstream endobj 473 0 obj <>stream +Adobed + + + +                +   + !1 +"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz +! +1"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?LK7, N< +̢*dC(t1G$XebPP %''0Th8RbO` oM0, DBL1")2*Br~HIKLcR'D3*_Pu$ endstream endobj 474 0 obj <>stream +Hrtt5ה`dGG{sMELH[EZ,`aai!+$3*K +0A$8 F0)H +@ BB">stream +Adobed + + + +                 +  + 5eA +!"#$%&'()*123456789:BCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz'q! +"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?7"@""J!1Hk"a#Pu` TQȜ p ( endstream endobj 476 0 obj <>stream +Hb`7`efbbC1qprq",܂p>\=")(!+,&#3sH*jLRP31U60 ʫXD l endstream endobj 477 0 obj <>stream +Adobed + + + +               +   +  +  +)m!1B +"#$%&'()*23456789:ACDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz A +3B!"#$%&'()*12456789:CDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?q.G;'\D +GI*S0EDH\ DuIF+$Dg0@Oh!2FQXBdJd'9I[ "&4 endstream endobj 478 0 obj <>stream +Adobed + + + +                +   + 'u!1 +"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz!1 +"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?AB0t&a%YReLe ($^"*HbCAF)ALa1@8RbO` QB(›@ta(̖e +Q Q"@WF,0F)c)ad&0Vi}@(1''@@C endstream endobj 479 0 obj <>stream +Adobed + + + +                 +   + TK +!"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyzMQ +!"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?x.#<Q endstream endobj 480 0 obj <>stream +H7k>stream +Hڰjknݰzkڴf ދ7m B@6~ endstream endobj 482 0 obj <>stream +H7k;+xɒV̞fռW/4M͜i]KLZbt?(q endstream endobj 483 0 obj <>stream +Hb`7`aabbB2spq lBp>;\]PXLRVAgdWTVUi嗗QQ҅*`V74)"gbf!'i`je QP120 D endstream endobj 484 0 obj <>stream +Adobed + + + +                 +  + :_3AQ +!"#$%&'()*12456789:BCDEFGHIJRSTUVWXYZabcqrdefghijstuvwxyz w!123A +"#$%&'()*456789r:BCDEFGHIJQRSTUVWXYZabcdefghijqstuvwxyz?Fx/6$!s.sb%NN|T 3Q6&`%/G`8E"L@2&1 +A$"! endstream endobj 485 0 obj <>stream +H ߿i\@2Zv_\bh5Fk1Zch5Fk1Zch5Fk1Zch5Fk1Zch5Fk1Zch5Fk1Zch5Fk1Zch5Fk1Zch5Fk1Zch5Fk1Zch5Fkh0jc endstream endobj 486 0 obj <>stream +Adobed + + + +                 +  + +m12Q +!"#$%&'()*3456789:ABCDEFGHIJqRSTUVWXYZabcdefghijrstuvwxyz ! +1q"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijrstuvwxyz?P@. bD<}6ܪfʋB|SE8 +p$LʊR \+@‡  +<G.a\rq$̌!$%]!2 ) ? endstream endobj 487 0 obj <>stream +Hb`0Ȍ")"* Ʉ,$$*,%ņKLI@SI."`dioaȃ0SP7 \ +Ny +Gc-YNfGhXX,pVN1]S`o{SQj&)kg7O{c=%a Y$e,Ԥ8YSRWUUWC8d '/灮''#:`fD ?@ endstream endobj 488 0 obj <>stream +Adobed + + + +                 +   + "w1 +!"#$%&'()*23456789:QaABCDEFGHIJRSTUVWXYZbcdefghijqrstuvwxyz!A1 +"#$%&'()*23456789:BCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?I>!X 5C a0a(L'Js SxÄ,HUMM!H !BhBUIr1Y5fMHI!aC)@Dlk(a J3Æ ln0>stream +Adobed + + + +                 +  + !y!1 +"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz 1 +aq!"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZbcdefghijrstuvwxyz?QD##l!0Q6:!UV,q3AY!@eROd,)ah00 EEω$N$x̌BtBkcBe6 ) 7 endstream endobj 490 0 obj <>stream +Hb``fd" ,(BB<,œ|BJJ\QFna MC#-I9Av +nbLpŜ&.> +HbږAv:|f`a{daV!^~Vz"pCTLl>8Ṕ B2 +bH)"(%ʼn\X +lK0 # endstream endobj 491 0 obj <>stream +Adobed + + + +                 +   + # +!"$%&'1()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz!1 +"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?ΓO,N%`/) 0 dN`ᎄ#9H 4&CIaA"@HH +5& `@SUirDL8 47ADJ  ($`8E\^*dH `ุaa!$L")0V PR"D endstream endobj 492 0 obj <>stream +Adobed + + + +                +   + DW!Q +"#$%&'()*123456789:ABCDEFGHIJRSTUVWXYZabcdefghijqrstuvwxyz-m!1Q +"#$%&'()*23456789:ABCDEFGHIJaRSTUVWXYZbcdefghijqrstuvwxyz?I`*xGTJhl`xeA$ ˙ 2" endstream endobj 493 0 obj <>stream +Hb``edddT F>11>daNnqe55 n&$\F涶R✬pa&aC;O7k#i!68yt"]͕9a2sjYyEFxبp2UiYyFEX 8ŔL|yvjZ::;;!\%gbb 0KXRQIIEzN~nnn!.N6@{`m endstream endobj 494 0 obj <>stream +Adobed + + + +                +   + 'q!1 +"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyzy!" +#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?NA `BBO#G4#p(p8i=(,% endstream endobj 495 0 obj <>stream +Adobed + + + +                +   + ?]1 +!"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz)q!1 +"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?I@t(0F>"SdDD2Ƅ(i@4tt% endstream endobj 496 0 obj <>stream +Hb`XYL@rps0XTD@|6M]CK3 M.FNe}[Go[=1aNVX'#{HTD?L-82<,)j`,4]XQB] . Y cs#miqNcٸEdTT%E8g99ٙ e{ endstream endobj 497 0 obj <>stream +||MJchJJQ_Yr endstream endobj 498 0 obj <>stream +Adobed + + + +                +   + DW!1 +"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz1i!"1 +#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?I`4 L|XŖAC$22 endstream endobj 499 0 obj <>stream +Hb`YL@pK()Ips@1ɪj(p -ltd8@C= ęrXDxYKK0 +򙹆%e%;i@“3Cy@"A)Ѿ6@ k?ce~v-l.&Z2, Jj +p2A>stream +y[J[JJQoYl endstream endobj 501 0 obj <>stream +Adobed + + + +                +   + 0k! +"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz{! +"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?Id(!0` @ĎH!`DQA}}(P!4Xa4!B1 endstream endobj 502 0 obj <>stream +Hb`5`adcbdcDcPDgSVSUDiXX[ +•r*xx9H`Ѳ vДC7t wG +:FD"rkٺykIr2ìQҷpuQaCxGLLOZL F^I))Q^`dB 1&`0a ; Nr endstream endobj 503 0 obj <>stream +Adobed + + + +                +   + (o!AQ +"#$%&'()*123456789:BCDEFGHIJRSTUVWXYZabcdefghijqrstuvwxyz{"A +!#$%&'()*12345BQ6789:CDEFGHIJRSTUVWXYZabcdefghijqrstuvwxyz?ME%TPP+sg1(YѠA BH8'##a %)P ) endstream endobj 504 0 obj <>stream +Adobed + + + +                +   + }!1 +"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz!1 +"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?Ln2(#!0ĂQ)3!V2A2ld#!!H H,PP(io-D1'BH CM`2 (D)L0 +Q)-!V@Ep3&5F"TR&bSMKe!9: Pho endstream endobj 505 0 obj <>stream +HbbFpɲprs`ff4_RJYN]_YI][HLV@D@ʆήV"<, (,|*&!ii AnƲ,Um*j2P* [T`,bFJ|Q+$j`%ȏUS7$~II~~>6ȁ ܬXT378@CA endstream endobj 506 0 obj <>stream +Adobed + + + +                +   + "{ +!"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz +! +1"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?̳,FH|) 9BLJ2@DYB7LAH |%3P-:#![W)EBQ"Bo̳PfxPx)&Q P,(tJ%l FE!H̚fA$ C!!9LH,:3P(-E + endstream endobj 507 0 obj <>stream +Adobed + + + +                 +   + 4g1Q +!"#$%&'()*23456789:ABCDEFGHIJRSTUVWXYZabcdefghijqrstuvwxyz{!1 +"#$%&'()*23456A789:BCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?)(0 `Ar@A$4HeaOB HIXI>stream +Hb``dddcdCa䗐dDQ4֗bAR,(dfhg*fWvp7QDja,0W)8<>stream +Adobed + + + +                 +  +  -i!2AQ +"#$%&'()*13456789:BCDEFGHIJRSTUVWXYZabcdefghijqrstuvwxyz +1 +!"4#$%&'()*2356789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?Bqō2@O*NpCEDA[BUCI +@@4Q2DNf2 endstream endobj 510 0 obj <>stream +Adobed + + + +                 +   + 1i!1Q +"#$%&'()*23456789:ABCDEFGHIJRSTUVWXYZabcdefghijqrstuvwxyz#u!A +"#$%&'()*123456789:BCqDEFGHIJQRSTUVWXYZabcdefghijrstuvwxyz?ĈбB s%H>stream +Adobed + + + +                +   + ZG +!"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyzVK +!"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?K@0Xx? endstream endobj 512 0 obj <>stream +Hbd0ʄ*-* ))ͅ,.$$#ĊGR@L_Ia83\[@S7$DU *ɭcoo)7[A+4<<I[B/(DC&,mfk"̎@Aycs++mY Ji(x[\BLLBC11aR $K endstream endobj 513 0 obj <>stream +Adobed + + + +                 +  + 0g!2A +"#$%&'()*13456789:BCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz!" +4A#$%&'()*12356789:BCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?B\KAC",Xأ( ) +|Ϲ2R)DDVJt@1FGud |K:d endstream endobj 514 0 obj <>stream +HA 144$W=S<.T ՅBuP].T ՅBuP].T ՅBuP].T ՅBuP].T ՅBuP].T ՅBuP].T ՅBuP].T ՅBuP].T+@ endstream endobj 515 0 obj <>stream +Adobed + + + +                +   + AY!"1 +#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz0k!1 +"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?I`*:<4H"H|EDH+W&8Dp`2.! endstream endobj 516 0 obj <>stream +HR@E3C`l* K(aUv5nʇ,oVyOW:}%_L^D0JbȠ8ײbQt~K# zw]!j=}C3lܯOj`"Bݝ?E9ln7Κ4p|x^ Z/wf9 %4$FUA馈)iL} +*Jb!.Seٿ,T endstream endobj 517 0 obj <>stream +Adobed + + + +                +   + -m!1 +"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz! +"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?N@54d +.\!@dJF4O #GhX +0@@8' endstream endobj 518 0 obj <>stream +Adobed + + + +                 +   + ;a1 +!"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyzy!1 +"#$%&'()*23456789A:BCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?LP !  ':1 ( +$$>stream +Hb` +X L0!f6.yE^N&'$X #$'+PIBIL_JO38"<\dC@L\\('H@?:>6( +"kd4T^[ d(Z1ek++KCYQNfCETU%X!>abySPɿ 3CQh endstream endobj 520 0 obj <>stream +Adobed + + + +                +   + 2g! +"#$%&'()*123456789:ABCDEFGHIJQRSTUVWaXYZbcdefghijqrstuvwxyz(o!" +#$%&'()*123456789:ABCDEFGHIaJQRSTUVWXYZbcdefghijqrstuvwxyz?Nd$J)T`"P&e@\p *o"Ą,#D89! endstream endobj 521 0 obj <>stream +Adobed + + + +                +   + KQ#B +!"$%&'()*123456789:ACDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz6c!%Ba +"#$&'()*123456789:ACDEFGHIJQRSTUVWXYZbcdefghijqrstuvwxyz?Iаt*X@Qz(9 endstream endobj 522 0 obj <>stream +H@E>,QPPk4.ij<1?>$b ޥ_PT*&9MU5,GXGƀ=͢SɊV FWP`me^' l]<%E:ݟQx6R=+ 56u82AqBQEx AI +U/|OaNw endstream endobj 523 0 obj <>stream +Adobed + + + +                +   + @[!Q +"#$%&'()*123456789:ABCDEFGHIJRSTUVWXYZabcdefghijqrstuvwxyzy!"2 +#$%&'()*1345678a9:ABCDEFGHIJQRSTUVWXYZbcdefghijqrstuvwxyz?M E #DB(ɔ $@PKB_ endstream endobj 524 0 obj <>stream +Adobed + + + +                +   + HS#1A +!"$%&'()*23456789:BCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz+m!1 +"#$%&'()*23456789:ABCDEFGHIJaqQRSTUVWXYZbcdefghijrstuvwxyz?I ؠ`Qc|EJHiR2 )di:D # endstream endobj 525 0 obj <>stream +Hb`0ƌ&%"( ń,%$&+͆[ZT_^U.$llhie4s7T炛knŁֲtRS9KZ/4D arzv6&:bHdPUPAW\TT\ kA5c= endstream endobj 526 0 obj <>stream +Adobed + + + +                +   + >[!Q +"#$%&'()*123456789:ABCDEFGHIJRSTUVWXYZabcdefghijqrstuvwxyz)m!"2 +#$%&'()*13456789:ABCDEFGHIRaJQSTUVWXYZbcdefghijqrstuvwxyz?M`"0>:!B1 GH,Oj(0- `4hr endstream endobj 527 0 obj <>stream +Adobed + + + +                +   + KQ#A +!"$%&'()*123456789:BCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz6c!$Ba +"#%&'()*123456789:ACDEFGHIJQRSTUVWXYZbcdefghijqrstuvwxyz?I1@>'򑐒4@ endstream endobj 528 0 obj <>stream +Hl{@kEvEKCE$3o_"A=JRdϔTTL V7PE=ʃɛU^Jdu5=qLlбrXcfVƲzc:ܮǥogi9\"g* 0 (]aAPlr_ + endstream endobj 529 0 obj <>stream +Adobed + + + +                +   + +m!" +#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz!"$ +#%&'(1Q)*23456789:ABCDEFGHIJRSTUVWXYZabcdefghijqrstuvwxyz?NRlj@(K 109!I! *T--;TĦ")O endstream endobj 530 0 obj <>stream +Adobed + + + +                +   + KQ#B +!"$%&'()*123456789:ACDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz6c!" +#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?IȰt*X@Q‡50&dP endstream endobj 531 0 obj <>stream +Hb` `ecdabgcDbCfRTSSFgW2467VB$dbke5 +r2g%nŁַ @f4 t[&"gj(̄6<8U555%P%!&**&Ā@-02b +R Y endstream endobj 532 0 obj <>stream +Adobed + + + +                +   + 7a!Q +"#$%&'()*123456789:ABCDEFGHIJRSTUVWXYZabcdefghijqrstuvwxyz w!" +#$%&'()*123456789Aa:BCDEFGHIJQRSTUVWXYZbcdefghijqrstuvwxyz?M,$h`P"^K${?D rp  QX%/ endstream endobj 533 0 obj <>stream +Adobed + + + +                +   + KQ#B +!"$%&'()*123456789:ACDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz6c!%Ba +"#$&'()*123456789:ACDEFGHIJQRSTUVWXYZbcdefghijqrstuvwxyz?IȰt*X@Qz(9 endstream endobj 534 0 obj <>stream +H0E1׊T]0wa_2バ7ggv]EGT?aJPKe8NfLr5uNc{ Q";Zl +fmNqYxwny;tj%|xǢև0Ox=J|{v!2U}& *ZPq%K#0H-R|}cQp endstream endobj 535 0 obj <>stream +Adobed + + + +                +   + 5e!Q +"#$%&'()*123456789:ABCDEFGHIJRSTUVWXYZabcdefghijqrstuvwxyz w!" +#$%&'()*123456789:aABCDEFGHIJQRSTUVWXYZbcdefghijqrstuvwxyz?M%`@4P%eF-%!$@KC_ endstream endobj 536 0 obj <>stream +Adobed + + + +                +   + KQ#B +!"$%&'()*123456789:ACDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz6c!" +#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?Iаt*X@QFBhiLȱA? endstream endobj 537 0 obj <>stream +H@E;g!Bm1b6$aYzuއ_`!Q [ʸ΋LqHnUg_b9iWs^ηS^ S-.w{?pԼ4T5NYpBY=a804rBkNzVÞdiT<`~􉀱%! endstream endobj 538 0 obj <>stream +Adobed + + + +                +   + :_1Q +!"#$%&'()*23456789:ABCDEFGHIJRSTUVWXYZabcdefghijqrstuvwxyz w!" +#$%&'()*123456789:aABCDEFGHIJQRSTUVWXYZbcdefghijqrstuvwxyz?M⢣, >L J".ZK&AogHCTp ` endstream endobj 539 0 obj <>stream +H 0 Ϳ8DA;7rM.7]ntrM.7]ntrM.7]ntrM.7]ntrM.7]ntrM.7]ntrM.7]ntrM.7]ntrM.7]ntrM.7]ntrM.7]ntrM.7]ntrM.7]U endstream endobj 540 0 obj <>stream +Adobed + + + +                 +  + #u!"1 +#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz1 +!a"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZbcdefghijqrstuvwxyz?ȄA`h) +a~|A%tЉ((PC!2Bh!Z:CR +ДaaHmVJ :: S2AdB&! 88NQ endstream endobj 541 0 obj <>stream +Hb` `cd&FTA6n1>Eq).6da.%]uM5Iin$qVnCKK3).9R6^NVʂ,p5=4xZ1.jb\>QA(¬\Қ&!~vfpC؄e<MV(-blnka@Nni5uMm )Afdo2qɉ q0V6,Ǎ endstream endobj 542 0 obj <>stream +Adobed + + + +                 +   + y#1 +!"$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz!AQ +"#$%&'()*123456789:BCDEFGHIJRSTUVWXYZabcdefghijqrstuvwxyz? +%#`Bg 1EqBeǖA)BYE`1M"H@@ha>stream +Hbd8yL\@sIJHHpCx$ՌT%A|n~ESK++k]E)...AYSW@[31&.yu[߈0wmq&.e}Є(O;u9kHbRRPK?2>. CJ;8ESd/4ZF.1i u QVO$ĸac`Ex  L endstream endobj 544 0 obj <>stream +HbfV$ +fc" VR0[D@NSAHMN ]+7$lJ*FNၾ>stream +Hb``daacbd``dQF&¼!!n‚l:V Yyy~|B*)%}Uq^&b"em= 1jBauM@Ue#'$eQ2 s %#K!r%d [zAL_=9AmԊ ,Y]W\"*Ҥ[%1Q c`'5aA&v!-KwCMa!vV! e=3cU !vfFVA! iEEIq \Dc endstream endobj 546 0 obj <>stream +Adobed + + + +                +   + 7e1 +!"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz%u!A +"#$%&'()*123456789:BCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?IAQ !# ##&>stream +Hb`Xyl윜,0>0$TWBTC[]CE g䔒մ1Tpj9x:Hs2(ꙹ""C| +HX9YJmUѴwpוcXihkjdGBFXMNTә8xy9DX & `# endstream endobj 548 0 obj <>stream +PJaoJJL^Wm endstream endobj 549 0 obj <>stream +Adobed + + + +                +   + KQ#A +!"$%&'()*123456789:BCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz6c! +"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?Ia1@>ł+% *h endstream endobj 550 0 obj <>stream +Hb`8ʈ*#+,),,/-Ą$!%kdabn(0_\TapX4Z6^cϐؘp_=a}(?m>0K@Dd43ՒVN~nֆlpJ˛Z("\PLUSCK]FZ; Lr( , ʀ1) endstream endobj 551 0 obj <>stream +Adobed + + + +                +   + 7a!%1 +"#$&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz+m!" +#$%&'()*123456789:ABCDEFGHQabIJRSTUVWXYZcdefghijqrstuvwxyz?M8 6F,0p$ xaC P +:@@ endstream endobj 552 0 obj <>stream +Adobed + + + +                +   + KQ#B +!"$%&'()*123456789:ACDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz6c!%Ba +"#$&'()*123456789:ACDEFGHIJQRSTUVWXYZbcdefghijqrstuvwxyz?IT@bI!R1\P endstream endobj 553 0 obj <>stream +Hb``LAN`B`VP@UWeB2sHkHp2Å<}}ݭ `":aaœpWzXjr\̩ef*0SL/0\n%  7\ŠFFҊœHePQUUFr6Vv~^^.vQۙٙYh ", endstream endobj 554 0 obj <>stream +Adobed + + + +                +   + 7a!1Q +"#$%&'()*23456789:ABCDEFGHIJRSTUVWXYZabcdefghijqrstuvwxyz!u!A +"#$%&'()*123456789:RaBCDEFGHIJQSTUVWXYZbcdefghijqrstuvwxyz?M` +!q0 Vp 1lbOA0@ endstream endobj 555 0 obj <>stream +Hʡ  `ZLhO} endstream endobj 556 0 obj <>stream +Adobed + + + +                 +  + )q12 +!"#$%&'()*3456789:ABCDEFGqHIJQRSTUVWXYZabcdefghijrstuvwxyz +!"#$%&'1Aa()*23456789:BCDEFGHIJQRSTUVWXYZbcdefghijqrstuvwxyz?ȄA`Y@J5a"nLX=0Nq9$&d&e$4Y7  %y#J)(\AMFFB a2 !_+  endstream endobj 557 0 obj <>stream +Hb``efddd&T FN)>iQda6Ai% UM-Yi^&$\z&&"ҜpaI%]k7O/Gkce!N0;_H'ZNqS WuiNFt@0B]J?D 6 M [w'gme!6$+Xh+Js"yM@JYNEEEF qɋ r21hP12`ff̀5D endstream endobj 558 0 obj <>stream +Adobed + + + +                 +   + # +!"$%&'1()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz! +AQ"#$%&'()*123456789:BCDEFGHIJRSTUVWXYZabcdefghijqrstuvwxyz?O,NY/)1EEFeBK(si12 + @\ CsIX+ @ADA`Lr.1 U fp^\X\XH$HQD"ccv%UIH endstream endobj 559 0 obj <>stream +Adobed + + + +                 +  + &s12 +!"#$%&'()*3456789:ABCDEqFGHIJQRSTUVWXYZabcdefghijrstuvwxyz !1 +a"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZbcdefghijqrstuvwxyz?QPX  `ȳ T?3eS@ +EjXGĦL $ bp*k3JI +z<alqM&ciT@AYB@B$ g((J endstream endobj 560 0 obj <>stream +Hb``e QF`B`cGUіfB2KHI@C\a?\9+GPdx2/6>QQ&ra5K'dafAucW@o{CY~6L*nvFb|0rʨk …XddE8PɆZLLll,AH`- endstream endobj 561 0 obj <>stream +Adobed + + + +                 +  + # +!"$%&1A'()*23456789:BCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz!1Q +"#$%&'()*23456789:ABCDEFGHIJRSTUVWXYZabcdefghijqrstuvwxyz?O,NY".(b3e +tALe"(Κm&6h,(DH 1g6Z%h9ژI(1$oII A`GaLς.R-  +a(P3D "dP"ieY U(D($ c endstream endobj 562 0 obj <>stream +Adobed + + + +                +   + <_!A +"#$%&'()*123456789:BCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz#u!A +"#$%&'()*123456789:BCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?It! C>"ǀ%e3A$H8#rł0 endstream endobj 563 0 obj <>stream +Hǚ0`b({86S,6#8K8H1!G$i4aQeip=uP^w+w :yk9m|@X3zYN* ȋ䎫Qirv߿ٰLo?ɉ!RڣѰiph8rY*;΢9T O'_Mt endstream endobj 564 0 obj <>stream +Adobed + + + +                +   + 6c!Q +"#$%&'()*123456789:ABCDEFGHIJRSTUVWXYZabcdefghijqrstuvwxyz w!"1A +#$%&'()*23456789:aBCDEFGHIJQRSTUVWXYZbcdefghijqrstuvwxyz?MBBD0(8  (Y1H GPUs.oE6226Ih J ID endstream endobj 565 0 obj <>stream +Adobed + + + +                +   + 8c! +"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz{!" +#$%&'()*1234567Q89:ABCDEFGHIJRSTUVWXYZabcdefghijqrstuvwxyz?I$C0%a@(8AD"(`:: +1zJa@ CF endstream endobj 566 0 obj <>stream +Hb``edddd&FTA!a))aAN6daN~M eu91$cet uD9氉Jظٛr3D9UM]|Ux9rJk[y:Z* q" 9T <V2 kY9s!\t ظ䔔DD)+)€A̘b endstream endobj 567 0 obj <>stream +Adobed + + + +                +   + .k!A +"#$%&'()*123456789:BCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz"s!"1AB +#$%&'()*23456789:CDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?N"%PP+̎h(@W+|DأS()` endstream endobj 568 0 obj <>stream +Adobed + + + +                +   + 9a! +"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz! +"#$%&'()1*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?IC0$ BF>q XEJ46A`"(bz!O) endstream endobj 569 0 obj <>stream +Hb`5`edcg`aDU. *,-,ŎW\U_CYU!-"mnb."7SXQPQf#wPH,#\/,A!)!n&j3$ endstream endobj 570 0 obj <>stream +Adobed + + + +                +   + 2g!A +"#$%&'()*123456789:BCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz w"A +!#$%&'()*123456789BQ:CDEFGHIJRSTUVWXYZabcdefghijqrstuvwxyz?M$4$,TPPPs b `$q|2006*|%POB$A0 endstream endobj 571 0 obj <>stream +Adobed + + + +                +   + }1 +!"#$%&'()*2345A6789:BCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz1 +!"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz? 7( N<*eS*c>>(AQ\QF% Q"x@Na1DhbCd1'E .M1( D!q*bJP)12Cr|J( +llQBQB|"sU4i}/RB@ endstream endobj 572 0 obj <>stream +HbfV$ +`fe`æU@P\^RCRXBVC PZ]THQ^D ]PZZD]\՝r*6.*Rڹ5Cb +S,UPlU0̮jjm΍v6S@v {FIK޶?Gm!dyVJy甾ݵ.")NtD&d쓘Pa $"*eRQ\Wd>`Hh8d%Eyi MP^540,\Q] Uh>0У_HXDD[Y^P#X\]\NPkae>Nb+58@G endstream endobj 573 0 obj <>stream +Adobed + + + +                +   + )q! +"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz1 +!"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?,b@aB@D1R(P8@B0C$1\ +0 ?! b UXDT#PG0E8 (R +DIN%1UPAD2Ic࣎(0C"jR%*t8DEI endstream endobj 574 0 obj <>stream +Adobed + + + +                 +   + @[1A +!"#$%&'()*23456789:BCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz w!1A +"#$%&'()*23456789:BCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?2"y + S`, Q%EL0dtFX.*@Hx (F? endstream endobj 575 0 obj <>stream +Hb``eddd6T FN~1Qyyq!~Nda.Q u--MI>A&$E ͜,ĹBҦN~Jp\6!n<\p b#}8ºQq ^¬\zaAVp+m]<],t$YW614UAr Г*2jj( l\<<<ܨ@sXع٘1  endstream endobj 576 0 obj <>stream +Adobed + + + +                 +  + ,k!12A +"#$%&'()*3456789:BCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz ! +14"#$%&'()*2356789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?Fp,.8(%!I :L!JKR:u;NudR +$)D@4$x"r>HA0i):"c( endstream endobj 577 0 obj <>stream +Adobed + + + +                 +   + 1i!1Q +"#$%&'()*23456789:ABCDEFGHIJRSTUVWXYZabcdefghijqrstuvwxyz{1 +!"#$%&'()*23456A789:BCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?)(0 `AA$4HeaPB8! HIXI>stream +Hb``dddd&FTA~I)iieQ.f$aN1U}##}%q&$\R2vvRsDU fX{Ćۨ)p)a!7(ga!0]T-8,>stream +Adobed + + + +                 +  + ,k!12 +"#$%&'()*3456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz!1 4 +"#$%&'()*2356789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?DiN 䤌&9 + .QZ"8z:9Q(D"Ji!h15۱ 7uF;"Ʊ endstream endobj 580 0 obj <>stream +H1 Ϳi#QO\jZVjZVjZVjZVjZVjZVjZVjZVjZVjZVjZVjZVjZu0 endstream endobj 581 0 obj <>stream +Adobed + + + +                 +  + +m!12 +"#$%&'()*3456789:ABCDEFGHIJQqRSTUVWXYZabcdefghijrstuvwxyz ! +1q"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijrstuvwxyz?R`YlP"@R$y"mP͕O@\PH + p4ԂIpxOċ %<G,YXrq$̌!" !W+&R%$' endstream endobj 582 0 obj <>stream +Hb`0Ĉ*%*&(("Ł,"$."#͊[ZYRMR.$he$K\7$2>stream +Adobed + + + +                 +   + 'q#1 +!"$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz!1AQ +"#$%&'()*23456789:BCDEFGHIJRSTUVWXYZabcdefghijqrstuvwxyz? I6!:LLBA'0X`be \-tALX h#AB! @U9Fj`Ha!D\AF 2Ze*  +a.//. qqpIBS"c>T&KP8QH$ endstream endobj 584 0 obj <>stream +Adobed + + + +                 +  +  w!12A +"#$%&'()*3456789:BCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz! +q"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijrstuvwxyz?A`lFbL8zh\ +P"+Ā 8!P("B&HM!yE)>S7 !%yL0 AEπDH x̄!dB& wHLJH.7 endstream endobj 585 0 obj <>stream +Hb``fdddd6T F>QAY1a>daN% 55U ^&$cD$uͭ,L9EUtmܽ=uY9ET ]C}y8rʨY{EF* s"5-B"Q9EL|lTV2 )9;ٛHs!|%``djj,@6>QE)ee%qaNfdopqa;#(M@w endstream endobj 586 0 obj <>stream +Adobed + + + +                 +   + 'q1 +!"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz!AQa +"#$%&'()*123456789:BCDEFGHIJRSTUVWXYZbcdefghijqrstuvwxyz?LI:&E&Z& >Q 1EqBBS,`0ZQ=h8@\CE\yc`T0 e.!KQ +pW2H)`Q⢅...YBSAʯ) `G endstream endobj 587 0 obj <>stream +Adobed + + + +                 +  + )q!1 +"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz!1 +"a#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZbcdefghijqrstuvwxyz?QPX`i`?ٌM@ +@!$ EtԜʛ R@  ؐa` 5PJR2(PE$g3$%PPO endstream endobj 588 0 obj <>stream +Hb``adddFdd`eA`DS37UTeER,,fb-fU5 pg;CL726!AC!a!O;,&>NMhoplN)YC{[G'35)dsJ KTY\\Hŗ sp +p2P2 R l endstream endobj 589 0 obj <>stream +Adobed + + + +                 +  + "w1 +!"#$%&'()*23456789:AaBCDEFGHIJQRSTUVWXYZbcdefghijqrstuvwxyz!1 +"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?ʒ%`>lHC r(@LL㱝 :"i@ҩɤ0 hM MW1I)3k 7I" l!0L2 +G :\I[03C(XFtLPºV"Vu$ endstream endobj 590 0 obj <>stream +Adobed + + + +                +   + B[!Q +"#$%&'()*123456789:ABCDEFGHIJRSTUVWXYZabcdefghijqrstuvwxyz,o!1 +"#$%&'()*23456789:ABCDEFGHIaJQRSTUVWXYZbcdefghijqrstuvwxyz?IAPT4#>"Sd$IG +@(i@(Ǚ endstream endobj 591 0 obj <>stream +Adobed + + + +                 +   + QM +!"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyzFW +!"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?BA(@SЈh# O*!"0AA GHTIz|bИ1htT: <Q`0T endstream endobj 592 0 obj <>stream +JJpJJ}KJ}q endstream endobj 593 0 obj <>stream +Adobed + + + +                 +  + 1i! +"#$%&'()*123456789:ABCDEFGHIJQRSTUaVWXYZbcdefghijqrstuvwxyz{! +"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?KAI8R" O"4HE"@2( A20H<) J "D endstream endobj 594 0 obj <>stream +HZ|gMX|+g^dj.Tb̾y:`xIE&d%# endstream endobj 595 0 obj <>stream +H1i  >VjZVjZVjZVjZ]Gd endstream endobj 596 0 obj <>stream +Hb` XYQlLLL.aqqq1.603XEPBY]X[JV [\VSU(&-ae"R$.h*.lb$ 10HEń$&mi+6)}kGW';3eQ.؅e4- MX a/LB<|B\,`afdd2 R endstream endobj 597 0 obj <>stream +HbbT, L@+///;+' N,\켼||@,IJ)/ ve|2FFF +r"|1L[E CVaY3Lo+YQA^ yT,b;z[K LXձ$WLx95ɞ6jB<,DTԝ²[޴u=yFb"3 +f-xh-K&5G9(cfQՉJnj{窂]Krcw޶|Z]x:"I qpü`3L{54˩2 &ؘ(scfW0/j1kfw}Z4z$ob_RܔkϋD%,gᛔoo(ɄY$ l=tMe06^>QE;3Gks3S5Q~IiWPUdU4Tx1< CB^>~eiei)>^ʘ ٍWRR_^NHƣ +l;3P5@/l{ endstream endobj 598 0 obj <>stream +H$?`q-a[Z"#ѥ$w)9'%"GydM\ B-QeLݪwAǚ"a8myƱ6?g5Sl(nGf@%`lx*}{ x *L`RH&нP#WX ;Y),)WZH?޲#=J}5\KTΜxԈ"gb]^!(Kz dϗ/b~&k e3ئ{Xץ(xHvwշlpSezd|Ԡc`3ш +V]؟)T endstream endobj 599 0 obj <>stream +Hb` XQ99ٙl\bl&Na)eueeqYaN'HEDJAJOEdD vN1e3ho#iQNFN)%K; ~vkdJFZ|2HSV>8.%1EFN',4Bl<#,;#ĩj kJK +[RNYAMYNR!F&.a~~aN&DA5a endstream endobj 600 0 obj <>stream +Hbb,`̀O 7????7+ e$bW'"* B|2 ST25R52ђO@]NR_KCRS!X`x\B_$?+urJ6>%y1ZffАq K+mk5f mLFi9sgNl)MrҖz8V~I-3کVZ:+]_C'lZAIe]Wn޲spSaI~Lu2@u݋7_nβ KMI*{غvMq! +<$, ;f-ݰi)<,h _RS6>oڂ&5eˎ2HjZj'~̌r&. UUUeq^NJX4,l=}RҒTԱ/0KHi[yFGG[[iH`MX,(mheeei JX>P '6ebBd3'14??+l3 ?0y endstream endobj 601 0 obj <>stream +Hb``bdfgbd`gSafbbS4t03ҔaR + +pԑV7K/i-΋T)0}JsV$sRE5˖^Y&%$mRоx.,ߒb 'k]9i-Xh|w1>9 B릖[͆ +m\j'_3i=TcO.PapNۢ \JlXdՌ{U S-ݒ+:fNؚ%-k\vauUQz 0 e<}c}]xYy5tmM-!#'%'##,",$` fK endstream endobj 602 0 obj <>stream +Adobed + + + +                +   + ZG +!"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyzVK +!"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?K@0Xx? endstream endobj 603 0 obj <>stream +Adobed + + + +                +   + DW!1 +"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz0k!A +"#$%&'()*123456789:BCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?I@ 4QHC Y"C , endstream endobj 604 0 obj <>stream +H0EK7u +]q_Ĩ%f}<93#$)1(axKQj&54Uĉ$80BY;ި`šeͲ+v|wmF"{s&]k&?!#O!w).-eUl| !0뫞rx endstream endobj 605 0 obj <>stream +Adobed + + + +                +   + 4g! +"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz"w!$ +"#%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?NaKĨ%B)PB8B8I$ !4F Ƨ'z,r@ +`  endstream endobj 606 0 obj <>stream +Adobed + + + +                +   + /mQ +!"#$%&'()*123456789:ABCDEFGHIJRSTUVWXYZabcdefghijqrstuvwxyz  +1A!"#$%&'()*23456789:BCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?HF&0, 1$eS +d==(DE #E,3(g%ȆZ`>9( +$] &I!0.G$T2Liu( -Bbaɇ# 0K!2SU3* I*5 endstream endobj 607 0 obj <>stream +HbfFpʲp񱲲bfaeG@SK[MMGREC#v~mKPߠO[kQq~T7rjxEgeDk˱(`aPpN/(HEgeԱ +Kohh,ˎגF6w,4$GC[ م"~yu=S'%˛EdWwM\fM\& 2'R L)EU幉Zʯo*ƃ@lB +J&^֊ +h)cac`k: |Z:::zZ>stream +Adobed + + + +                +   + )q!A +"#$%&'()*123456789:BCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz!"1 +#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?0r@p(LEBP(Ƽkh$V*j0(Ic#aGp0@FaF$&Dk!iH爊0@OȲLr>stream +Hʡ}A2^{ȶm۶m۶m۶G endstream endobj 610 0 obj <>stream +Hb` + ebd +1r +K'#)"il/-%`4tvuu6Ӗ*aP3w  s2am&4SH%(6>>^],lk.T +Y"dfreJ2jjR">'0' wL,<@*X endstream endobj 611 0 obj <>stream +HbbF, ; 3ViVnn!!n., +Y8xU䅸YY9xL5̴DYL`fS6p4֑FED^Q+"..BWBfV%cPOC>TYy%UBRj+ RtyXQw/lhlt7R`F7wM(nj+ +w7A7tϬmhHSD_h@Riu}y~6`Ĥed%`[X-86:2AW>stream +Hb``bceba``bTdgbbfRѱ45QB## "BF^Źqj"|b*6!i==uE)>\I555%N꒢zA5`P+.*c^5)ezkH*dT1FRbZQ55MU9&J>ymmeYFl"*&n ɉʒl +*F6..F2b|lL">stream +Hb`L0!fvN1q q1>vV/X=P+PW03P@P-(8BU$`0rv6PZ$&ndo%VJ@KFh&+H@-, 9f$232B֍ endstream endobj 614 0 obj <>stream +HbaNpJp1gf"/(+'!.όC@PNTSVM{?6^3hO7e U&6T\#b*-QyL< +kۛӢPѴ(o04>T_GU1 {rԎToGEAItyˀ̊)ZS-4yQ5= :{Zrc5PB]@78:/!R[] +R!)9Azj( T̝B}]Ï_T\BOC]U;>iY M] 5>2\l躡FIJۍPLbCvPJ endstream endobj 615 0 obj <>stream +Hbddefg^v6f&FFfv>Q1119>vfV';33;wTbzz\PoXv}UU^J>stream +Adobed + + + +                +   + ?]1Q +!"#$%&'()*23456789:ABCDEFGHIJRSTUVWXYZabcdefghijqrstuvwxyz,o!A +"#$%&'()*123456789:BCDEFGHIaJQRSTUVWXYZbcdefghijqrstuvwxyz?IAȨ@xH|EDH F@(`F\x endstream endobj 617 0 obj <>stream +Hb``LAN`B`@1TeB2[DTCJaO \9 ghLT/'ѱ޶Jra5pw+%!Nf!Zna!A.*lp+m-%YPе011Wbc 3r I**))Hq //?(3f} endstream endobj 618 0 obj <>stream +Adobed + + + +                +   + *o!1 +"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz#u!$1 +"#%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?N7l4@B2!! +R@"@#3lt>? :1 X endstream endobj 619 0 obj <>stream +Adobed + + + +                +   + ?]!Q +"#$%&'()*123456789:ABCDEFGHIJRSTUVWXYZabcdefghijqrstuvwxyz/m! +"#$%&'()*123456789:ABCDEFGHIJQaRSTUVWXYZbcdefghijqrstuvwxyz?IAE@P M %8p +(Hǖ/ endstream endobj 620 0 obj <>stream +HGPD0Q1sEZTw?@Y%Л4Ë':ʨcLR!NV +YZ p^nmLg}Uè!au0^^~\6h r};Wjk*)ޟSz&X} b\BQ=:gh@RqlcC?@$ `!  endstream endobj 621 0 obj <>stream +Adobed + + + +                +   + )q! +"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz!" +#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?N#p@ +$'B(%R "y a4@⠜pO endstream endobj 622 0 obj <>stream +Adobed + + + +                +   + !1 +"#$%&'()*23A456789:BCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz! +1"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz? Fn2("!S0 +E&TʅXRhH*"-@Cc O~) ACDSkI>9)RJ@B@oMb" (D$)x P50%2Cr|H "@Wjj#Qc)D!JSD"Ve@ endstream endobj 623 0 obj <>stream +HbfNpKrrqbf^.VLi,/#n Bv6"ʼhVr+zDD:*s8W\=4)3/#)\I v6>9}אĂ0{#>vd X̼#szk =mPdԌҊ[z;ZlU80;J#LT%A:T45Vf9G .iUu Բܸ@kCY>&Ts9'g%FpF _O0/ziY* +1 +4feǕ@ GJ,X0S A  DCn endstream endobj 624 0 obj <>stream +Adobed + + + +                +   + 1 +!"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz  +!"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?0@$I$` H&&RyNHQBQfg F0 +B4[;Vӂ J$R&oLL%P ``P$&Si Tum9$ +(I(Lq2#H A$9LH$z2j9DPQB"H endstream endobj 625 0 obj <>stream +Adobed + + + +                +   + ,oA +!"#$%&'()*123456789:BCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz  +1A!"#$%&'()*23456789:BCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?HG&Qa( ed!>>)BIDE #EPh%0IPK +ğ$APjI!0.L1%(ek!:>$LL90paWBD%]C,8H:o endstream endobj 626 0 obj <>stream +HbaNH1v%l2XT I˫ a(`W013V`g@3su2WgCg7sM TagD.i[Pd,!bgb^uKkCiZ<}PFU(KyANd/ HgvM8,KO]U^>cꔾW]ty>Y 9n&Tț8FW{[ 1+[DrfRjj@?80F[^M=8dDPd z/ ($$!$"ņ) d>>ni~> A #5I endstream endobj 627 0 obj <>stream +Adobed + + + +                +   + !1 +"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz1 +!"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?,<$I%(`%(/(鸛!@J&1! #,I(@, )`^rRkGtD+L%P0``\(RSi(u!Y! 3LIE e`(DSasG endstream endobj 628 0 obj <>stream +Adobed + + + +                +   + !1 +"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz1 +!"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz? n0("!$2L H*"+61Jx,00 ]L' Y +IЪH CMb" (D$)T0*E$ZbO$W2MDj"E)DR)JsU4k`ZPq endstream endobj 629 0 obj <>stream +HbfN,+`e`acbP_QH_LN ! ]CKS9A6t֦j<覫[:xŦ&z{h(`aӰv-(-JE5I@^7.<;VO xY 䒎 Z˓¬yXP卝"kzL]'&obS5} TyF6> 3x7+y^`a7sMjh/K v@gW JOO2A%N~kHW+~fT6wvqF _ |::|ܘi||>stream +Adobed + + + +                +   + ,o1 +!"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz! +"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?,$ +( &0\I +4Y!hpd##@L $@8"j2PQ"a +?HLr>stream +Adobed + + + +                +   + $w!1 +"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz +!1"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?&(F`|&T!4&*B~~R"e"1 4043(iu0ֺTP @Qtx +C(Y'GāDX HEJT`0BaLeL*50 endstream endobj 632 0 obj <>stream +Hb``bbbeFdbBbg  K +p1q唥Ex9٠ZZJ<0s t5TexY z +B|+ cuanN;K}5 )ANF +?L u endstream endobj 633 0 obj <>stream +Adobed + + + +                 +  + /i!4 +"#$%&'()*12356789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz{1 +!"#$%&'()*2346r5789:ABCDEFGHIJQRSTUVWXYZabcdefghijqstuvwxyz?MED +"aE8P8@(ALtk cX (%$DRH("'$KГ(  #U(Hܢ $K̲ endstream endobj 634 0 obj <>stream +He0F/J4 =1Li) >stream +Adobed + + + +                 +  + /i1A +!"#$%&'()*23456789:BCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz#u1A +!"#$%&'()*23456789:BCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?9022Èp JƳ&1EYU)! b e +҅B, Pn#41[$KB&ƁLA endstream endobj 636 0 obj <>stream +Adobed + + + +                +   + KQ#B +!"$%&'()*123456789:ACDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz6c! +"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?IȰt*X@QHT,$&dP endstream endobj 637 0 obj <>stream +Adobed + + + +                 +  + 1i!1 +"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz'q!1 +"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?ǣAEEB`0BB!OQnt4)q7$ĐI>($*E>stream +Adobed + + + +                +   + *o! +"#$%&'()*123456789:ABCDEFGHIaJQRSTUVWXYZbcdefghijqrstuvwxyz}!1 +"#$%&'()*2345Q6789:ABCDEFGHIJRSTUVWXYZabcdefghijqrstuvwxyz?MFS`(/ 9a# $LyF ,%* I8A}#,  %8 E endstream endobj 639 0 obj <>stream +Adobed + + + +                 +   + QM1 +!"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz>_ +!"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?>stream +jLKLJJ endstream endobj 641 0 obj <>stream +H10_c `F]wSMz7nԻwSMz7nԻwSMz7nԻwSMz7nԻwSMz7nԻwSMz7nԻwSMz7nԻwSMz7nԻwSMz7nԻwSMz7nԻwSMz7nԻwSMz7nԻw~ E endstream endobj 642 0 obj <>stream +Adobed + + + +                 +  + 'q12A +!"#$%&'()*3456789:BCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz! +"#$%&'1Qq()*23456789:ABCDEFGHIJRSTUVWXYZabcdefghijrstuvwxyz?Fac`-2 $ >R2 #}aCp +79.02H,6@ ċ $x0"leD*72!$&ʂH$g3@RPO endstream endobj 643 0 obj <>stream +Hb`0Ĉ&)*'*".".%Å$%fdfcj--ʄp +07Pb2sEGYÕ3r빆%$i##=Y9Ut"bcB% LƮ>lHi88X+ {SBVM[G[KNR,\<œH +FFFVtA@gT endstream endobj 644 0 obj <>stream +Adobed + + + +                 +   + }1!" +#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz!1 +A"#$%&'()*23456789:BCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?ʒ%İ  眉$` (LJ3sZDQ/9H 1M3A"G)\0CP`̐@SU(p~\$X5pdHA!08 )@@u>zO(1 +bhBhPqL TR*Do endstream endobj 645 0 obj <>stream +Adobed + + + +                 +  + &s!1q +"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijrstuvwxyz + +!1Aa"#$%&'()*23456789:BCDEFGHIJQRSTUVWXYZbcdefghijqrstuvwxyz?QPƀX`S e;'d[A!Ep,@D +2 CeR8CRP   ؐxaHg,URtS fE + )5 :t endstream endobj 646 0 obj <>stream +Hb`` AfVv `B`d㓐T`cAfTQbBR+ocoom$#Ɏ0IDA; @agHtL;tvQ]KH'5)`a߈p;5Y*fAa.*"p J:{9[#\."nlbj$@6v)Ue)$#qrq s++#3@\ endstream endobj 647 0 obj <>stream +Adobed + + + +                 +   + "w1 +!"#$%&'()*23456789:AaBCDEFGHIJQRSTUVWXYZbcdefghijqrstuvwxyz!1 +"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?ʢ%`>lHC q A*NqAt/X444(H"a93@:]+#4fMI!08 `qG)rȨI[T ||pxpPࠊ(&!9&a!4JJγ endstream endobj 648 0 obj <>stream +Adobed + + + +                 +  + &s12 +!"#$%&'()*3456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz + +!Aaq"#$%&'()*123456789:BCDEFGHIJQRSTUVWXYZbcdefghijrstuvwxyz?QAl(@@p@xL8򝐩m( +@#Sy 4(&ٕPQUƏ0Py!U(iQG +N*  endstream endobj 649 0 obj <>stream +Hb``dddd&FAf.Qii.6daN^q]-ME1~$u̬m 8pz;+ aT2ueG :%Gz٩r"b#|͑95m¢"\%VZyx#\ŧbbogg.! +ظEE9Q+Ŏ( ,b  endstream endobj 650 0 obj <>stream +Adobed + + + +                 +   +  w!#1 +"$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz !1Q +"#$%&'()*23456789:ABCDEFGHIJRSTUVWXYZabcdefghijqrstuvwxyz? I:!BlHј`(@"(| +!PGtPM$zAa"G +J,0@"H DIB0Vpa5HAPE @BPL0DsTAES +0A(Q'јΙ U(B8A@ endstream endobj 651 0 obj <>stream +HlPr@ ʢW}` ޠPFiz{zS,P + 8,Hd_9fݮ\`#P^Y{רRfv׮xKLҗ97U(FbDm˃?5Ĩڲ~]P(v54 ߂$=LP#]zQ$#1g@ Ɣ8a"H"~|,< endstream endobj 652 0 obj <>stream +HbdF p23sqq23cU+ " ÍM38/+fV~q C [ M q~ftymxP`b4uKHM2B1WJ> *387+^VEW#24#H f1U;([Iy4y5ݐ֞P%yy>U򆎮`[%L|&9u͵F|(ݯ]\Xcm(ˉy%cĸ`cET 3ruqr4aAfnaAIucss- e AQ+hd ˂%فQ,&Æ=777K8$'0'U=| endstream endobj 653 0 obj <>stream +Hb``ddecdd``dTPaeddeS53՗`geױqr1Wѱ OLOK ԑU/)sR5q ͪG9Qe=<0ȍrד4Hykj ^"ʦ ~YN8jai^^ia(kpJveEvJoHLD0#$3#(? #+ L!U>stream +Adobed + + + +                +   + <_!1 +"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz1i!1Q +"#$%&'()*23456789:ABCDEFGHIJRSTUVWXYZabcdefghijqrstuvwxyz?I@t(")1؁ņDAXRJ( endstream endobj 655 0 obj <>stream +Hb`0ƈ"%*/ņ,"$&&!-Ă[LIX[Y a(\]@'0DE +.q}SȈWku9)\ +av"ùĴ\BBLJzVN^2r ZhʊmN)Uuu-ei>3qIH=ĀX@ 5gdd0 endstream endobj 656 0 obj <>stream +Adobed + + + +                +   + 6c!a +"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZbcdefghijqrstuvwxyz#u! +"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?N;$P$CPB$ !,@<Cpzb endstream endobj 657 0 obj <>stream +Adobed + + + +                +   + ?]!1 +"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz(s! +"#$%&'()*123456789:ABCDEaFGHIJQRSTUVWXYZbcdefghijqrstuvwxyz?I`@F>"SDDII8y`@P +@P 4 endstream endobj 658 0 obj <>stream +Hb``eddddT F6N!QyyQ .f$aQEmu 5%1^&$c9EmL$90 Kk:zy9+ s…-]Cc¼T "cQM}#PY$-܂ãB\u$ŒR>fZJH.4ғAv  $YyEDx9P3;0X033E o endstream endobj 659 0 obj <>stream +Adobed + + + +                +   + *o!2 +"#$%&'()*13456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz&s! +"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?NE恠A!##H$R +Rb($$ffnO@vrPY@.) endstream endobj 660 0 obj <>stream +Adobed + + + +                +   + DW1Q +!"#$%&'()*23456789:ABCDEFGHIJRSTUVWXYZabcdefghijqrstuvwxyz(s!a +"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZbcdefghijqrstuvwxyz?I@ 4Q4Q)"QxBP +t% endstream endobj 661 0 obj <>stream +Hb``dddT Nna%AA q>Nda.^Q Cmm-e &$xDe-l$*&>F +\!1Anv\WDFx۪ +s"u"½Dl>stream +Adobed + + + +                +   + 2g! +"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz#u!"$ +#%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?NrF0(C`G$("#q;z7"H  endstream endobj 663 0 obj <>stream +Adobed + + + +                +   + 1i! +"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyzy!1 +"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?I@I- +BM dqA0(è>O1BBpB ŠE4_ endstream endobj 664 0 obj <>stream +Adobed + + + +                 +  + 6c!1 +"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz'q! +"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?h`! +@ z pkCܠHHT;>stream +Adobed + + + +                +   + *o1! +"#$%&'()*23456789:ABCDEFGHIqJQRSTUVWXYZabcdefghijrstuvwxyz! +"#$%&'()*123a456789:ABCDEFGHIJQRSTUVWXYZbcdefghijqrstuvwxyz?M&D†,lH٬LqF  Z$ hR\K#` ? endstream endobj 666 0 obj <>stream +Adobed + + + +                 +   + QM1 +!"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyzA] +!"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?>stream +Adobed + + + +                +   + 1iA +!"#$%&'()*123456789:BCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz}! +"#$%&'()*12345A6789:BCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?@KIfFBbCLAJ# D#yLzД9MTA@!1' endstream endobj 668 0 obj <>stream +Adobed + + + +                +   + "{ +!"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz  +1!"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?Ln0("!qR(ș9رe +DH0@2" Ou!Na0PKIꌝJa, +?Lb"(D!Hq$B(}/S26*TAAp!̈́Q R# eH^;!Gp21*T endstream endobj 669 0 obj <>stream +HbbNpJprr`Wܬ, XdYe$$%Ÿ91`ᓕV72TfES-klaob#!ɂf:WPxDH+fV%Gܼ {C9^n_*9'Uז$z[j)rgնN.lH3aC-iW^뢡./o[XRlS\!<*?)NWNaY%f"_Q/4&3@=xl>stream +Adobed + + + +                +   + )q!1 +"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz 1 +!"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?,r@a(@(BQ E=I(YK 98(G )I@P"c=$tDZHL` 6 F& J=MUJ%`BH.03 eH%P"( endstream endobj 671 0 obj <>stream +Adobed + + + +                +   + "{ +!"#$%&'()*1234567A89:BCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz  +1A!"#$%&'()*23456789:BCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz? n0("! S0 +D&d̆Xb$TD[ c +BPP(hcCt1'E Mb"(D!Hq& +P102C* F5D"XJR&bT,Yhp:: @ endstream endobj 672 0 obj <>stream +HZzu@aV/ܲqh'oZx%6y endstream endobj 673 0 obj <>stream +Adobed + + + +                 +  + :_!1 +"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz +"s!1A +"#$%&'()*23456789:BCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?!PH@!R"c!B4|2>6Dd'!6x>/ID1H endstream endobj 674 0 obj <>stream +HZz klٸfkܴf ދAmXh>u`6u endstream endobj 675 0 obj <>stream +H7kΜeK^9wκUWmX`>stream +Adobed + + + +                 +   + ZG +!"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyzPO1 +!"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?IP* |A( endstream endobj 677 0 obj <>stream +Adobed + + + +                 +   + 7a!A +"#$%&'()*123456789:BCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz!u!A +"#$%&'()*123456789:BCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?Mw`bh  R @Q FA<")t$k" `UI(RP{K p endstream endobj 678 0 obj <>stream +HڴfM q͢ ` 1M endstream endobj 679 0 obj <>stream +wJu endstream endobj 680 0 obj <>stream +T endstream endobj 681 0 obj <>stream +J{u endstream endobj 682 0 obj <>stream +k_ endstream endobj 683 0 obj <>stream +Adobed + + + +                +   + *o!A +"#$%&'()*123456789:BCDEFGHIaJQRSTUVWXYZbcdefghijqrstuvwxyz}! +"#$%&'()*1234AQ56789:BCDEFGHIJRSTUVWXYZabcdefghijqrstuvwxyz?JZBf(P@hI(R S:,Ba@BH endstream endobj 684 0 obj <>stream +b endstream endobj 685 0 obj <>stream + endstream endobj 686 0 obj <>stream + endstream endobj 687 0 obj <>stream +Adobed + + + +                +   + .k1A +!"#$%&'()*23456789:BCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz w!1 +"#$%&'()*23456789:AQBCDEFGHIJRSTUVWXYZabcdefghijqrstuvwxyz?JC`CpH q&0aa.싌#(0 $=C/ endstream endobj 688 0 obj <>stream + endstream endobj 689 0 obj <>stream + endstream endobj 690 0 obj <>stream + endstream endobj 691 0 obj <>stream +HZjފ_f֍kشfn ދ׬b*{0 endstream endobj 692 0 obj <>stream +JJJK endstream endobj 693 0 obj <>stream +H7kϟ?1k93׭fU+fO[j Y+W̝0|( endstream endobj 694 0 obj <>stream +JJJJSV} endstream endobj 695 0 obj <>stream +Adobed + + + +                 +   + QM1 +!"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyzCY +!"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?<QdP`0p%5 +gC $1,Qa(($( "">J-<@D` K!gǃ endstream endobj 696 0 obj <>stream +Adobed + + + +                +   + 9a +!"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz w1A +!"#$%&'()*23456789:BCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?AIy# 0ұ@D@̦qtGy6 p=b@ endstream endobj 697 0 obj <>stream +rm endstream endobj 698 0 obj <>stream + endstream endobj 699 0 obj <>stream + endstream endobj 700 0 obj <>stream +ue endstream endobj 701 0 obj <>stream +o] endstream endobj 702 0 obj <>stream +HΡ qxUEH"UT*REH"UT*REH"UT*REH"UT*REH"UT*REH"UT*REH"UT*REH"UT*REH"UT*REH"UT*REH"UT*REH"UT*REH"UT*REH"UT*REH"Ud0* endstream endobj 703 0 obj <>stream +Ht[WP9[@1Ie장IZjde7Ϣe=4O3k[Y{*d$0ѱ@ɤDձPbv#IGs8VN(>stream +HbdTL DH777 3N@Ul<<BB@̸21s ()73ve|JRz*¼^iGPUՕxy0< CB^>a%I%I ^vfnd6qqq.nN|Y8!9*L`@@հir endstream endobj 705 0 obj <>stream +H4;qq\$BBe${=GD<\5c:PA6l.b iPS4QeG MRz\ Z]`iZÀ(ǣ273%W>n-D>stream +Hb`I""b2b҂PA&AQeY-CmIX'3HK@DlL7P3OdRfFb:q{h;>vV|zVN +D;41-5!I_IJ7$*,LW d<@Gyz:r +?ԋJ*r¼0O22qʈIq2Â#p@ +A0#x endstream endobj 707 0 obj <>stream +HbaTlllllxq6_N^T^JV6>m!qEm-MJ +Yٸ$ ,-4$)deֱtrwp0b"+|TlD&?;u:V^q19Y AFZ@1BO@K;*{Bkm~Jl!)ŭSfΙ>!7ZYK@Vv~I# W^1&PKCUXzUۂM;vm_5>stream +Hb``bfg``VQPR1sJk[[)KsJGŅ9i H65&z)ʛ$WtN^0bKAclaӦ-ْa(%*o۾x̙ќ#. kY1aXhڒS9!Bk |-eBQU3 "VDUCKAteʉd5.̞T-(*]ܻzi+ftO|]ǔ&%9iʉ + 9{fUWdɈ0 {ȋGATMGSXDT\FAQB^ZL ,f> endstream endobj 709 0 obj <>stream +Hb`ؐyL,0.;';DG\Q]__UFKPBNECR/(YG SI;2.&H ( *($aoTֱ JRja5qrP#gn䢫)SXJPKFTF.A~~qQ.&8X8Xef  endstream endobj 710 0 obj <>stream +HbbV$3 `W/# ‚E(+( .i3?+v~MmskgCgs% 9>4+X4͜c#C,5eYQ0k[E&奥G[)I:GV9""+%@YG?%2+EUSES>(0WOSU_(ZY[gaGNK+6,3\S } +:Ie)f2в OI 0חC bf6 c gWOgsE!Flk`i$ƃ4115֔,l<ؒ3 +?0}`M ƍ+yA>DKB endstream endobj 711 0 obj <>stream +Hb``d`be``dS`b򅥔m,59X$=<TD88D\ +KBe9TۧOk)1h5gRgmmdE_oLn2Qu3 yd &BfjJ%TuLQjOoHЕSs+l=onWc^(kLNeuMqj[`pll(('# 3@ I endstream endobj 712 0 obj <>stream +Hb` +X +rHHJKsA8D$5UUD@|.!u# c]9qFqe{w/OGs=YF- ;CewHh3y-k7o[S^vq)}KgWc]Y>&f0kPPQRc8SXBBP P`G endstream endobj 713 0 obj <>stream +HRG[@DA݀HQQ`X{{j1~u;3 $B+(Vhel%ybfXPlUjrG,i#-R=BqG%D%󩾞h6*Ec"v A+8K׷rkT1zrt 7XG>}|}{tLy1(/}\m G\Zxx>J_9;?^ +؍mѹF={#~// mY]B~I9SF@bvb?0@&<b0G+w"~=[ endstream endobj 714 0 obj <>stream +Hb``c~>vfF&&!ieYyi1Av&FV>19C}uEi.>&V1=sG?ow+5iQN)a};ĴԸPw35^A~q5 0G}y)mtkMq)93|΍WW Ȩ 8 cHz'Հ9zJZ!u@~eARRz6A Q.F҂LbFnc`dRQz z= endstream endobj 715 0 obj <>stream +Adobed + + + +                +   + B[!Q +"#$%&'()*123456789:ABCDEFGHIJRSTUVWXYZabcdefghijqrstuvwxyz}! +"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?IAPT4#>BSf K " @p(I endstream endobj 716 0 obj <>stream +Hb`8ˆ*!"+SR\IQ]AFL ICRBCGHSN.#g`/-0CP/XA&Ϋhj,nʇ$,``co,KBT[FBFN)-cKs3m)~$J+(H xCDT[V@s9 -S"` endstream endobj 717 0 obj <>stream +Adobed + + + +                +   + 0k!R +"#$%&'()*123456789:ABCDEFGHIJQSaTUVWXYZbcdefghijqrstuvwxyz !1 +Q"#$%&'()*23456789:ABCDEFGHIJRSTUVWXYZabcdefghijqrstuvwxyz?NC Z@(d)DJBb$@E3s'QJibX $ +DETo endstream endobj 718 0 obj <>stream +Adobed + + + +                +   + ?]! +"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz,o!A +"#$%&'()*123456789:BCDEFGHIaJQRSTUVWXYZbcdefghijqrstuvwxyz?IaE@P 4$H|E F@(`F\x endstream endobj 719 0 obj <>stream +HPD]8w)!ZWdf3; +FiJMu`nw2w8)rQlVTe`.xanz) ~O t4mA@;Y' W701F|ƈSv +Yo&_毓^v,J&y 9MO} endstream endobj 720 0 obj <>stream +Adobed + + + +                +   + 6c! +"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyzy!1 +"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?N9lBZ*(%AAB`ЖBrİI(h򏆔0 endstream endobj 721 0 obj <>stream +Adobed + + + +                +   + ?]!Q +"#$%&'()*123456789:ABCDEFGHIJRSTUVWXYZabcdefghijqrstuvwxyz)q!1Q +"#$%&'()*23456789:ABCDEFGHIJRSTUVWXYZabcdefghijqrstuvwxyz?IA +@"!!!%J>stream +HW`+ϗh#-{׼99|/K7#Q@s1" g|N`(ܕ@GK5i>fjwLsSEcu]:Qn׋5ʐt47Ü=+4\t1L#B=YL8KIF]WN$"_px 0$/Od endstream endobj 723 0 obj <>stream +Adobed + + + +                +   + 2g!1 +"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz!$ +"#%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?Nh  PG `pF!HĠDŜQMC"XPN$ endstream endobj 724 0 obj <>stream +Adobed + + + +                +   + KQ#1 +!"$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz:_!2 +"#$%&'()*13456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?I0!a>Ă X!%#bg endstream endobj 725 0 obj <>stream +Hbd5``dbFWdB2qis!D%̜Md%xY5\M5ĸ`f3 (8E:p3JE$&Ň[ ''%y" +GF;eְv1WcFr,\2zF|H`daUVE fv`p11V& 1@M endstream endobj 726 0 obj <>stream +Adobed + + + +                +   +  ;]!1a +"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZbcdefghijqrstuvwxyz$s!2 +"#$%&'()*13456789:ABCRaDEFGHIJQSTUVWXYZbcdefghijqrstuvwxyz?M`q\ h#"QR +3 +H#e&QHC endstream endobj 727 0 obj <>stream +H v!B2AfzpA"[Vd+يlE"[Vd+يlE"[Vd+يlE"[Vd+يlE"[Vd+يlE"[Vd+يlE"[V>< endstream endobj 728 0 obj <>stream +HlOY[0lR[-EBi S]P唛$^ݙvv_ u?Eѡ|E , lLdlE;^t{ 2oҕj4ֽ;YWJ"zt8ةh>n RKj2b)3g881*/Hhu@`Wn[!͟6 H endstream endobj 729 0 obj <>stream +HbfFpʲrsrbf`fe_IYE^^EE C+(v>)c;g77'[ eQ>T7IZF&$8)H(`aֵ*((NTl+|N}kGcYV<]PfUׄIM%Ѯ*lbzvAٵݓ[C9L킲ۧLi*qіFVRղI*lhl 7gDusxrQM]Enl2jKɸǥdEx)7w+Z4(jZXY()?^~1euUCS`scI~>^taFpqraIPCvPE endstream endobj 730 0 obj <>stream +Hb``fcdggbd``bRT0I(kZIsq0)j{8 + I$fFy٩ +7xˉIh{&Oo.Q +DG}q%Т `t @XI D)DBL,0ouՓt(i򫲃Uxz|Kk:+y՜=#2RM%y8%T l]-yXń%Ռt t5yyXDDؘ vA endstream endobj 731 0 obj <>stream +Adobed + + + +                +   + B[!Q +"#$%&'()*123456789:ABCDEFGHIJRSTUVWXYZabcdefghijqrstuvwxyz,o!1 +"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?IAPT4#>"SD$IG B4d_ endstream endobj 732 0 obj <>stream +Hb`ƈ*%.# #Ή,.(!ˉeշ41B(VT +u1Qd#gd S'ej,'7LIN +wC2 IzDŽ:ZM`Pqp Q`GLZ@ Ni9Us#=Ei "((!Ŏl ʀ +W  endstream endobj 733 0 obj <>stream +Adobed + + + +                +   + *o!1 +"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz}!1 +"#$%&'()*234AQ56789:BCDEFGHIJRSTUVWXYZabcdefghijqrstuvwxyz?Nc# + &BpK)B# IП B !~B endstream endobj 734 0 obj <>stream +Hb``Q@`a endstream endobj 735 0 obj <>stream +H10_c `F]oKߖ-}[mҷoKߖ-}[mҷoKߖ-}[mҷoKߖ-}[mҷoKߖ-}[mҷoKߖ-}[mҷoKߖ-}[mҷoKߖ-}[mҷoKߖ-}[mҷoKߖ-}[mҷoKߖ-}[mҷoKߖ-}[mҷoKߖ-}[mҷoKߖ-}[mҷoKߖ-}[mҷoKߖ-}[mҷoKߖ-}[m~# endstream endobj 736 0 obj <>stream + endstream endobj 737 0 obj <>stream +H7k `Rg + endstream endobj 738 0 obj <>stream +HڴfMXՋv_p+ [je ֯Y55v(n endstream endobj 739 0 obj <>stream +Hb``ddddvFTlRRr<\*2R",H9%̬m %ل|E8XajVqn6j#cc촸Q=c"|%,!aApO1򈩙8{:XH !_\BO^?\b*JJR(gd`c@,LL  endstream endobj 740 0 obj <>stream +Adobed + + + +                +   + -m!2 +"#$%&'()*13456789:ABCDEFGHIJQaRSTUVWXYZbcdefghijqrstuvwxyz! +"#$%&'()1Q*23456789:ABCDEFGHIJRSTUVWXYZabcdefghijqrstuvwxyz?Nc-$$PPl ) 3\ R1p8H"p% endstream endobj 741 0 obj <>stream +JJJJ endstream endobj 742 0 obj <>stream +Adobed + + + +                +   + ?]Q +!"#$%&'()*123456789:ABCDEFGHIJRSTUVWXYZabcdefghijqrstuvwxyz$w!1 +"#$%&'()*23456789:AaBCDEFGHIJQRSTUVWXYZbcdefghijqrstuvwxyz?IahБ Mܹ` T@|Gv endstream endobj 743 0 obj <>stream +Adobed + + + +                +   + ZG +!"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyzVK +!"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?K@0Xx? endstream endobj 744 0 obj <>stream +H7k `l  endstream endobj 745 0 obj <>stream +Hbd8Ć"%*/,Ŋ,-&""͎KLB\FY XHJH.!aj#7C\?*!1^Cn +}P\||#0#whLl:FfQ)=[gme^ٸ% e%'(ɇ1\r(gddf&FtĄ~t endstream endobj 746 0 obj <>stream +Adobed + + + +                +   + +m!1 +"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz{!1 +"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?NbJ! A#1 +IJ@ȉ%BMGGJF` endstream endobj 747 0 obj <>stream +Adobed + + + +                +   + ?]1 +!"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz(s!A +"#$%&'()*123456789:BCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?I@t(D Dc,%4BDL4xG, +@0@YM endstream endobj 748 0 obj <>stream +z endstream endobj 749 0 obj <>stream +Hb``edddd&FTbB22Bœ<ª*jZr\lH&p KYۘ+ +r"aTҳr2Pc+5 7WaGkGDZ(p +FD*#T3sk8f`SԱqrsq4EK\\RDp.19ieeU AN$Q&NAA.vQk!Ά b endstream endobj 750 0 obj <>stream +Adobed + + + +                +   + *o! +"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz#u!"$ +#%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?Ncj PQL B"L@BX`nmLjq` % endstream endobj 751 0 obj <>stream + endstream endobj 752 0 obj <>stream +H7k `l  endstream endobj 753 0 obj <>stream +HڴfMHxE;֯^H׬lIV-X0  endstream endobj 754 0 obj <>stream +HڴfMXՋv_p gkϟT `" B endstream endobj 755 0 obj <>stream +Hb``edddEdd.&F\22J\\FFzLQ>iYsGG+Y)nN0(\93GPxX\ +:^!.j\&N psI;xY!<#elgcc+'7n}}CTwMD F...v k 3 e Z endstream endobj 756 0 obj <>stream +Adobed + + + +                +   + +m!1 +"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz{!$12 +"#%&'()*3456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?N +sX@B -#`gr<`  endstream endobj 757 0 obj <>stream +HڴfM@aMkV_ ߳vՂ N_m`|0o* endstream endobj 758 0 obj <>stream +H7k `  endstream endobj 759 0 obj <>stream +Adobed + + + +                +   + :c1 +!"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz0k!A +"#$%&'()*123456789:BCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?IAF rd`) Y!AEYA endstream endobj 760 0 obj <>stream +Hb``dddde&FT""Bl\bJ"LH&pI[iʊr!a4rvq3ӕ+gQ6u +pSBKX:+s"u,]QĴ<}mMV2 j;:s |-"kda&'@6~aY)yqcxP<4 R,Ab+ endstream endobj 761 0 obj <>stream +Adobed + + + +                +   + *o!1 +"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz#u!"$ +#%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?Na65drB"@pdnBniF$/ endstream endobj 762 0 obj <>stream +Adobed + + + +                +   + B[1 +!"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz(s!A +"#$%&'()*123456789:BCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?I@D + Qa)"a< ( gM4_ endstream endobj 763 0 obj <>stream +H7k   endstream endobj 764 0 obj <>stream +Hb``ddd&FAnAy9 NVdaN>QeU 1.f$Eeu M,5p ++8xxXI 0!ױ + p2WGҷ󍊎 q6TcC r6B6v 7S$nh%%#0 TPRRRD &N!>aa!.6ba+3`f + endstream endobj 765 0 obj <>stream +Adobed + + + +                +   + 1i! +"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz&s!$ +"#%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?NÉq)a P pa AJ!(D$%F##vdm`  b endstream endobj 766 0 obj <>stream +Adobed + + + +                +   + $w!1 +"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz!1 +"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?ȐAB0|&aDTʅPbI+̕$1! &3 +5@)($@IV B(„0 HDdS(R)`2TF!`Bcf ŠCrt +T47 endstream endobj 767 0 obj <>stream +Adobed + + + +                 +   + <_A +!"#$%&'()*123456789:BCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz+mQ +!"#$%&'()*123456789:ABCDEFGHIJRSTUVWXYZabcdefghijqrstuvwxyz?J"㰠A h/BDt2C B*ȿ endstream endobj 768 0 obj <>stream +HbbFp2pp`fb4ORYEAAUEY]OT\M*~~fJhV*ZƤ%E{h+jSQO)*H pPUEgar̭nl+ +s2WcG4 +ɬl/QAu! WrUDŽMF\(VA-=}*hbޱ5 Y|\h6q+)-ˊQE f^) 3>.HbR0psvr4VE"Ae5 CK }y%' ,˅% _RS~ɇK`ff%0BR endstream endobj 769 0 obj <>stream +Adobed + + + +                +   + } +!"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz! +"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?̳,FH)cJPoTP/fEHDA +Hia0 L AR5jLp*++̳Pg )(bPPX +4!0$ CA` JQRT)^1hqb? endstream endobj 770 0 obj <>stream +Adobed + + + +                 +  + 9a2Q +!"#$%&'()*13456789:ABCDEFGHIJRSTUVWXYZabcdefghijqrstuvwxyz(o!1 +"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?aAB`%@Ci <"5&#EHhE+[2H %mQfh/>stream +Adobed + + + +                +   + ZG +!"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyzVK +!"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?K@0Xx? endstream endobj 772 0 obj <>stream +Adobed + + + +                 +  + 9a4 +!"#$%&'()*12356789:ABCDEFGHIJQRSTUVWXYZabscdefghijqrtuvwxyz#u6A +!"#$%&'()*12345789:BrCDEFGHIJQRSTUVWXYZabcdefghijqstuvwxyz? +H(c 4ilp]aH1\:́gFPNXʆ endstream endobj 773 0 obj <>stream +Adobed + + + +                +   + ZG +!"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyzVK +!"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?K@0Xx? endstream endobj 774 0 obj <>stream +Adobed + + + +                 +  + =]4Q +!"#$%&'()*12356789:ABCDEFGHIJRSTUVWXYZabcdefghijqrstuvwxyz %q26 +!"#$%&'()*1345789:ABCDEQqFGHIJRSTUVWXYZabcdefghijrstuvwxyz?C,I!0FƔB%ò Ea1qcA endstream endobj 775 0 obj <>stream +HbbNp˲ppr0be`^NfLi,4/+̜"*F +2B|&J*XY)+gl,ɂr^yKLjœxw3a^TyV>9=̲ƺ ;#9T0x&w4DZ#˳pJhvuW%;Y ȳhz$5N\e"d}dvuKG[Mn< Ol~UMeA\+Z9xǤgX)rh/z3*;+Il|b*꺺r|`? KqcO@#8y$$$xذʂUS 3.A  @ endstream endobj 776 0 obj <>stream +Adobed + + + +                +   + (s1 +!"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz1q +!"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijrstuvwxyz?(r@a(@(`"R 7SrY !XcU d`x0@08A A7%\ Q)* 2Pp 0Dr0@q((ɲk@cLVAP$I`@"Nd¨ endstream endobj 777 0 obj <>stream +Adobed + + + +                +   + 7e +!"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYaZbcdefghijqrstuvwxyz-m +!"#$%&'()*123456789:ABCDEFGHIJQqRSTUVWXYZabcdefghijrstuvwxyz?J#a0I4@J B,@ycG E endstream endobj 778 0 obj <>stream +Adobed + + + +                +   + ZG +!"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyzVK +!"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?K@0Xx? endstream endobj 779 0 obj <>stream +Adobed + + + +                +   + <_1 +!"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz,o! +"#$%&'()*123456789:ABCDEFGHIQJRSTUVWXYZabcdefghijqrstuvwxyz?JX`0Hlj1EPB3#C0 ( endstream endobj 780 0 obj <>stream +Adobed + + + +                +   + /mA +!"#$%&'()*123456789:BCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz.k1 +!"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?IF`dDKIbK#hѠ2D#EPP-%ʱ,4B 4/ endstream endobj 781 0 obj <>stream +HbaV$+bfdǦMPHB^J]JDRVC+PZ^@HQMT] ;UlCCUԥPskXFgeGX'`VVP_`$ĉVva s;mQAdy6o\NĮ mi~ʪ򺾱E}z[*R4QR2άl*vVAgT״ I,.N + 0SCu0x$m#R2r5TQ@^)?$BQM U@bVN6Q&SCSm-YA^t& ($,&!'$ȉ5?Ċ/y N`I endstream endobj 782 0 obj <>stream +Adobed + + + +                +   + ,o! +"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz +!"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?,b@aB + cH@_ +@B(L`ypc1F()%0$5t *ְ#$&hPG0E9%9 +E.}Z Ħ*P 2IeÞ\q +a1@ +M]"X`q1)B endstream endobj 783 0 obj <>stream +H7k  S endstream endobj 784 0 obj <>stream +Adobed + + + +                +   + <_!a +"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZbcdefghijqrstuvwxyz1i2 +!"#$%&'()*13456789:ABCDEFGHIJQRSTUqVWXYZabcdefghijrstuvwxyz?Ja@a8(!&(2-r \$S( endstream endobj 785 0 obj <>stream +Adobed + + + +                +   + ZG +!"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyzVK +!"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?K@0Xx? endstream endobj 786 0 obj <>stream +Adobed + + + +                 +   + <_ +!"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdeqfghijrstuvwxyz!1 +"#$%&'()*A23456789:BCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?Jh`0I DHD .’ @Vjq5C80 endstream endobj 787 0 obj <>stream +Adobed + + + +                +   + 7e!1 +"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz+m!1 +"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?I (AHA*) D1sF#Ѡ:h!@ADNW!HR+K # 8`_ endstream endobj 788 0 obj <>stream +H̒WW@5]h"!hXcc^`{/9ow;w@@f$A 1F,@YE΂i*'3,o0"9KOMc]$c +sVCjT`:y j+w ĶO'"-hSC@񭋇۳odBg]8z~O~\.Yo +ӗd8/8Lo?%_/a`SM7V͕%:@;ܙkcʿ{gӱ@_8bUD|j,tZC]*93J/@D$Ti1p?"hFɬѬ/ DhHa 2~?K9: endstream endobj 789 0 obj <>stream +H7k1@a( endstream endobj 790 0 obj <>stream +Adobed + + + +                +   + } +!"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz!1Q +"#$%&'()*23456789:ABCDEFGHIJRSTUVWXYZabcdefghijqrstuvwxyz? ,FH) ahCN*^92!L*"`%k[Z]]1E`qj?̳Pg ),`DMQ+a ++(d4F@$@BCE  F*ShS´Di endstream endobj 791 0 obj <>stream +Adobed + + + +                 +   + ZG +!"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyzVK +!"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?@@ endstream endobj 792 0 obj <>stream +Adobed + + + +                 +   + @[12 +!"#$%&'()*3456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz%q!1A +"#$%&'()*23456789:BCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?I +(0`!: dM\H,2YXAΞF 2h : @ endstream endobj 793 0 obj <>stream +Adobed + + + +                +   + 8c +!"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz w!1A +"#$%&'()*23456789:QBCDEFGHIJRSTUVWXYZabcdefghijqrstuvwxyz?J0Q@rHÌ0  z9ٶM”B9!$ F@! endstream endobj 794 0 obj <>stream +H7k  endstream endobj 795 0 obj <>stream +Adobed + + + +                +   + /i1AQ +!"#$%&'()*23456789:BCDEFGHIJRSTUaVWXYZbcdefghijqrstuvwxyz(o!B +"#$%&'()*123456789:ACDEFGHQaIJRSTUVWXYZbcdefghijqrstuvwxyz?KQ`R` P1ˏ* H+P2iPZ" ,!GApq endstream endobj 796 0 obj <>stream +H@DwAQE1+"s7㫞Fb0X +z$J"kcZ1ՈojP^òNgi]χYGˌ}`{_׭,Zv̔=zc?&m]1rD5x7f> ^TUM) P.NHPօl:ѧhL` endstream endobj 797 0 obj <>stream +Adobed + + + +                 +  + ,k!2A +"#$%&'()*13456789:BCDEFGHIJQRSaTUVWXYZbcdefghijqrstuvwxyz  +!"14A#$%&'()*2356789:BCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?DBR  -ZF @cAN)3(%Ei)i)"λ+FH@5 86E22 endstream endobj 798 0 obj <>stream +Adobed + + + +                +   + 2g!1 +"#$%&'()*23456789:ABCDEFGHIJQRSTUVaqWXYZbcdefghijrstuvwxyzy1 +!"#$%&'()*23456789Q:ABCDEFGHIJRSTUVWXYZabcdefghijqrstuvwxyz?JbqiJ&X1. Qy>29(BK(2DB endstream endobj 799 0 obj <>stream +Adobed + + + +                 +   + ;aQ +!"#$%&'()*123456789:ABCDEFGHIJRSTUVWXYZabcdefghijqrstuvwxyz w!1 +"#$%&'()*23456789:AaBCDEFGHIJQRSTUVWXYZbcdefghijqrstuvwxyz?‰0pC&88$ 89i$0 |%(@FQg />stream +H7k1@a( endstream endobj 801 0 obj <>stream +Adobed + + + +                +   + 3eAQ +!"#$%&'()*123456789:BCDEFGHIJRSTUVWXYaZbcdefghijqrstuvwxyz(o!B +"#$%&'()*123456789:ACDEFGHQbIJRSTUVWXYZacdefghijqrstuvwxyz?KĸYL +(̀`cAUK]bd >50`: endstream endobj 802 0 obj <>stream +Hbd5`acdfBcdGgPVRR@r +Jh s3qڹ:Yj 1EDl}\49٠ Br!AnjRL(a!ȢLbr֞~FZœ00q +X9;i mLDHW2DŹّ}##)$̈1a  endstream endobj 803 0 obj <>stream +Adobed + + + +                 +  + ,k!2A +"#$%&'()*13456789:BCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz!" +#$%&4A'()*12356789:BCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?R @Zy#G!D\JɈl͑*dIX+)" ""/F0)$;$ '|Ӻ:"d endstream endobj 804 0 obj <>stream +gs endstream endobj 805 0 obj <>stream +Hڴfލk\j &ow[`EA| ޳amV_ 6^ a* endstream endobj 806 0 obj <>stream +H7k  S endstream endobj 807 0 obj <>stream +Adobed + + + +                +   + 4g! +"#$%&'()*123456789:ABCDEFGHIJQRSTUVqWXYZabcdefghijrstuvwxyz#u!A +"#$%&'()*123456789:BCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?J! Q#Ke0(xJɂ6@F"2Ж8ATD_ endstream endobj 808 0 obj <>stream +Adobed + + + +                 +  + .k!1 +"#$%&'()*23456789:ABCDEFGHIJQRSqTUVWXYZabcdefghijrstuvwxyz+m!1 +"#$%&'()*23456789:ABCDEFGHIJQqRSTUVWXYZabcdefghijrstuvwxyz?ǣQtX 8@CRD("XzzS+`%aNȊ +g>stream + endstream endobj 810 0 obj <>stream +Adobed + + + +                 +   + TK1 +!"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyzFW +!"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?<Q4A l@^C`ABx +tZ `0VJ%E``>  2 X&@0J`%";!`*J endstream endobj 811 0 obj <>stream +Adobed + + + +                +   + 7a!1 +"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcqdefghijrstuvwxyz!u!1A +"#$%&'()*23456789:BaCDEFGHIJQRSTUVWXYZbcdefghijqrstuvwxyz?M Z`⢊sĠXW3M D1t#$9( endstream endobj 812 0 obj <>stream +Adobed + + + +                +   + EU!#1A +"$%&'()*23456789:BCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz}!1 +"#$%&'()*2345A6789:BCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?I!ÁF0DR''< A ,hA + endstream endobj 813 0 obj <>stream +Adobed + + + +                +   + ZG +!"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyzVK +!"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?K@0Xx? endstream endobj 814 0 obj <>stream +H[SP9G2}@"hQhԛ3oϬ^j (@"zɹv2e87-5?FPP3HdUY^:-\.hgO^6˾^fviG~m#[ה +Cԍxz=^d4-ǶLުOAEEA P :=&| endstream endobj 815 0 obj <>stream +Adobed + + + +                +   + 3e!1 +"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz%q!"1 +#$%&'()*23456789:ABCDEQaFGHIJRSTUVWXYZbcdefghijqrstuvwxyz?M;pP". q`$ Q/c(1bMCp!Q endstream endobj 816 0 obj <>stream +Adobed + + + +                +   + AYQa +!"#$%&'()*123456789:ABCDEFGHIJRSTUVWXYZbcdefghijqrstuvwxyz*o2A +!"#$%&'()*13456789:BCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?IF`@,X">"(ʓ<]M endstream endobj 817 0 obj <>stream +H7k `  endstream endobj 818 0 obj <>stream +HڴfMHxE;7Y[` oXhHlIEKOk`~* endstream endobj 819 0 obj <>stream +HڴfMaV-`% endstream endobj 820 0 obj <>stream +Hb`Ȃ"## '!$-!&P*,abncm(ft uՒb+Ҳ 4Ue2蹇'&{[IrDyUu=#EE#c]La&0rȨ99[r\-`djaf.3s,L\JC +Pcfʕ% endstream endobj 821 0 obj <>stream +Adobed + + + +                +   + 7a1A +!"#$%&'()*23456789:BCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz u!12A +"#$%&'()*3456789:BaCDEFGHIJQRSTUVWXYZbcdefghijqrstuvwxyz?ME\ p$G($X2 F ` endstream endobj 822 0 obj <>stream +Hڴfލ\r%'nW-XdєZ0, +[C0^j* endstream endobj 823 0 obj <>stream +Adobed + + + +                +   + KQ#B +!"$%&'()*123456789:ACDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz6c!a +"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZbcdefghijqrstuvwxyz?I аt*X@QԚ:@\P endstream endobj 824 0 obj <>stream + endstream endobj 825 0 obj <>stream +Adobed + + + +                 +  + 6c!1 +"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZaqbcdefghijrstuvwxyz}!1 +"#$%&'()*2345q6789:ABCDEFGHIJQRSTUVWXYZabcdefghijrstuvwxyz?90|-42, +<=Az5 bX1KIx%$>stream + endstream endobj 827 0 obj <>stream +Adobed + + + +                 +   + QM1 +!"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyzA] +!"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?>stream +Adobed + + + +                +   + :_!Q +"#$%&'()*123456789:ABCDEFGHIJRSTUVWXYZabcdefghijqrstuvwxyz w!" +#$%&'()*123456789:aABCDEFGHIJQRSTUVWXYZbcdefghijqrstuvwxyz?M,#A" dRcTp ` endstream endobj 829 0 obj <>stream +Adobed + + + +                +   + 7e" +!#$%&'()*123456789:ABCDEFGHIJQRSTUVWXaYZbcdefghijqrstuvwxyz&s"1 +!#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?Ia& $!%0bĥf0< a<ʋ endstream endobj 830 0 obj <>stream + endstream endobj 831 0 obj <>stream +Adobed + + + +                +   + 1iQ +!"#$%&'()*123456789:ABCDEFGHIJRSTUVWXYZabcdefghijqrstuvwxyz#u! +"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?Ja (0>stream +Adobed + + + +                 +  + 4g! +"#$%&'()*123456789:ABCDEFGHIJQRSTUVWqXYZabcdefghijrstuvwxyz"w! +"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?GhPB!@DG00MXcrK)&~x >stream +HڴfMJٰzю n0iK endstream endobj 834 0 obj <>stream +Adobed + + + +                +   + ZG +!"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyzVK +!"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?K@0Xx? endstream endobj 835 0 obj <>stream +ob endstream endobj 836 0 obj <>stream +Adobed + + + +                 +   + QM2 +!"#$%&'()*13456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz;a +!"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?`$$2KZ+!E|CC$H endstream endobj 837 0 obj <>stream +Adobed + + + +                +   + 6c! +"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZaqbcdefghijrstuvwxyz $oA!12 +"#$%&'()*3456789:BCDEFGHqIJQRSTUVWXYZabcdefghijrstuvwxyz?ME%A8$ffQ \.R;lh@>stream +JJrj endstream endobj 839 0 obj <>stream +H\10@3x\,,*0z7qu3Q +2s.[瞀yc]%2  H5+ endstream endobj 840 0 obj <>stream +Adobed + + + +                +   + =]!Q +"#$%&'()*123456789:ABCDEFGHIJRSTUVWXYZabcdefghijqrstuvwxyz %q!12A +"#$%&'()*3456789:BCDEFGaHIJQRSTUVWXYZbcdefghijqrstuvwxyz?IGAB + A!)̜dʥR#Fa @: endstream endobj 841 0 obj <>stream +HڴfMX5vo\h=@=V/ܲfռekV_a 5V_h󧔭_p3@5L endstream endobj 842 0 obj <>stream +Hb` +Y\&N.A.N&(KW *).mff,/#V .b`j!`Pp + w1Wfa``ԳJH4Tq NJN tP``Tַ OKqАdZ§ea4MBHEV.yS+GGKCi L\BjB\2qJI K= =@Sf endstream endobj 843 0 obj <>stream +Adobed + + + +                +   + )q! +"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz}!" +#$%&'()*12345a6789:ABCDEFGHIJQRSTUVWXYZbcdefghijqrstuvwxyz?O4dI$$QFD@$r='8p(((@ endstream endobj 844 0 obj <>stream +Hڴfލk^fKlW-Xd*lXhA`1:fY* endstream endobj 845 0 obj <>stream +Adobed + + + +                +   + 9a"1A +!#$%&'()*23456789:BCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz&s!A +"#$%&'()*123456789:BCDEaFGHIJQRSTUVWXYZbcdefghijqrstuvwxyz?I +R`ApxsH,$$Q" endstream endobj 846 0 obj <>stream +Hb` `cdbgaDdbCfPVSSFgP25QB$bfge3 t6g%a*Ł6p􏎉  ++d5=\V;{+ +3Ye̬mlđ'*).}&.iqyyqa.& *.&Ԡ;C"`L endstream endobj 847 0 obj <>stream +Adobed + + + +                +   + 3e! +"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXaYZbcdefghijqrstuvwxyz }!"A +#$%&'()*1234a56789:BCDEFGHIJQRSTUVWXYZbcdefghijqrstuvwxyz?MEB9&PpJ0e1%8}ITlnAXB ," endstream endobj 848 0 obj <>stream +HڴfލkZjE'mw[`峧PV/ +C0d* endstream endobj 849 0 obj <>stream +n endstream endobj 850 0 obj <>stream +Adobed + + + +                +   + .k!Q +"#$%&'()*123456789:ABCDEFGHIJRSTUVWXYZabcdefghijqrstuvwxyz}! +"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?JA !,2:d0SEdp @h%00p< endstream endobj 851 0 obj <>stream +HZ|fe3{V]`U ֬_`U 7nXpF ޴fn(ދR5} endstream endobj 852 0 obj <>stream + endstream endobj 853 0 obj <>stream +HZlFתs[5 7m\h5wmZx/2^lFs]I" u`5e endstream endobj 854 0 obj <>stream + endstream endobj 855 0 obj <>stream +Adobed + + + +                 +   + TK1 +!"#$%&'()*23456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz;a +!"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?>stream +Adobed + + + +                +   + 3e!A +"#$%&'()*123456789:BCDEFGHIJQRSTUVWXaqYZbcdefghijrstuvwxyzy"A +!#$%&'()*123456abq789:BCDEFGHIJQRSTUVWXYZcdefghijrstuvwxyz?M!J@pKyy @Y2 !Q$xICO +( endstream endobj 857 0 obj <>/Filter/FlateDecode/Height 203/Intent/RelativeColorimetric/Length 6553/Name/X/Subtype/Image/Type/XObject/Width 530>>stream +Hy\GgΨܷF +^(jD֬jp\%|4VȺ+a?Yԍx'" (*"; =]LzW讖Lu^.Nڕ]QGE)lfM-#W~ң-R%LKiPs$%%L{#ʬ=sKelݠ'o7!AGᦱ!6p􃚪sK>|}vСʌw} n Uϗ<\ }( dۡCgPc  CpUU-J0༩R8Cƙ-!3}qY~[GhtVo5q\XuKP1#!ly%@b}p7@&hl|<w$ pjpwABOnа w#$t|R M\zw+$4,=7znL+ XqG ;A%=wKMH1nwS* MzJ`#SA^bбwgDeܓsܽ%4sG;",؍2wR37NqO pϜ -8BqH\ e]q7IL|{Qnx{P$q7J45$UB TG uwܭpO%'qϙqwK L=e6ܵݮ֏uSfE,~z̾=cvTݱ֎{1dv0[uݲ֍G f=npϗ=1֚X{[n[+f #Te?yڔ7 +kݶ֋o90p Mn}'wX֪Y)bl3ҾS"AY\NlsKfBIC1D+}x9®mdsƣQHr}FGDD|4mҍ>K@k59'Ng]77/#C}>vU3.K]P9VQ͉:}³I #X:h]h%;4agF)|OE{knBpvU-rM-q=lH@ð*9W!}Ha;Qe]$·Se5eSK<-ρܻyM\2{Dvj!\5N+x t>O؟ՃtĈ1Q֚AaQg@h6!* ^Dq>̲bgK4Ͻ_Y{͆Ϙ5h $k"EUlh+&}%)z, lLQ1.#: #bPycq$6dkXs!%ڜcΕ eTofvȺt?x`j[ʂΤ:Ye |'a&9b\%P8V۽&T9|Ag\ke, \ tf 40!^ʋՐR9" c,i1YDj. TE:F# 6]Vx7u9& H`(NqxiI3znMG"b'[V,#׀)w-O_d tH kJ GA(X8Gă8RE2Y 9J?PYlqk^N`VP~`#_ps<:N3Bov``Yt?^➺q-K#t5XN`e֚(Y'JCwu9³)Q*Ec7G'\زe>g3MH<y4ב1C(<1wNd|cYl?jͬVY-ĵQKY-"":bR *m BD{U~@f\H}R+#K'{"#SԊQO%$| bҰ~ގtz/ħѩpSjV`"Jgb\`p*~Ѷe7pjcEi 7LNT{:qG)X n*ȼ?Z)\f/IzNSvDԼ|ZI9oO`1t 1 9slkӝVPGG8Raa XA%#QlO.RڒRw.0El~pJG#vTI!Nsܔ`^oXYʬ'lOɸ#sgn L@G$t\[ۆe}Ш}ZkM %u"sfՍǸ#J @ͦ|o4V-Y5սe{Yiumߥϐig:8>>Y>hR\MqF4OSM'>ZmBH(Ik\⒊VF%.1.hEQkAEqgs{2)?|s朙s~o̊ KU;0L%htC)lED =c.:*w+VS=_NT+qCǚֿkQ-G . "'q; gb* y7emkT Wa1+hJwG(M`+b(2J ^U"GWuAo,*qQU Îm#1 +Ί&dqmlg"`!>,]_neC U҆gԺlwlE,G!| ]TDa',XL[syLV& +׹JQ'r][iVDhe#IP?׮j]ht>5 +؀ 4#ECԢzXQa2t$$]"|B}tSAc{yGJL8:*b#G/>3Lp۳A>k #."n7bGNՄÊXCyxO>_{"_B:r G]ȤXh},D=h MAXJYv3iŰ"h P4VE_¿IJ"Pvrԙ#$]G궟 : ئ3(SsiԵcG.],~aӃ\*<{"DPMDWhN,Q +FrL!JTF1:B8-jk&I+*JK\0u梯2'Aʼ-CbXLrrgq#(5 NCnӧ+SX]u ;#Rj']A\v"|ShJTA@%Ê@y[d3l1^uIUaQ|o~ ,Ց$kVD AwZ69-m{⃕Ě->_X7fp9\y_»M)VI"I \j I%o-hk,W1jQrVyE!u)%:vsSِZkHgrP3 =ޕSvEfWU/VajQX6Md3{=j#IhVD}-.D6-n+e]#"+D3+VuVE`%y9=TZc@:i"9=^0ʧͤJYwES+f@>ڬL@\"d9e>Xbn'V'L@K~Bἓ"|L+kU1 +x0eu?|óz#RX͸;4"= ЇKYr;+D +6UסOKMT,Vfu6!wJQf[X/#Sh->[f=Jɘ uE۶VpP$-XQmQn-Q{/eM`3xw+Wű^q0c:H4gԚj >q?2e!Mr|h+7 +Xz`R QM~U*t=D2, +),!oBYX<맪f-5=̣ 1I&'̘ +<} м*pMt9Y.:Sasѵjщ EӤ# ߋ.7CDgIW| ފl#+wDMN# ueΠ`N崯蓸_q8ѥ's5Dtbj'q7BtZta ]cX/Z(DD8-u9=DgE Vgց-E'3VDT`}h)T`L fh5Ho%:5T2J|/q$ 'X=`|SD +tccaHo'z( Lz;^/  Gn`k@{zl -&G!`'Ë( l"5О'tIڧX Yw.( жyg4= 9fh@{o$=̳ah2`_TNoC0tbz88>c,ghόՏ)K .hojNwGKa;>$51|2\p> +h*^|OBzxrpz@;{:;ƞBѦH:.󷟼ŧHw.Y34Rg9 +pɪ8@hr! B endstream endobj 858 0 obj <>/Filter/FlateDecode/Height 203/Intent/RelativeColorimetric/Length 15645/Name/X/SMask 857 0 R/Subtype/Image/Type/XObject/Width 530>>stream +Hn!sBBelȦȩ7eG6 pH YA.lZj8QwU_NqSCXE<3_Cj]}pNR+Ư޻,oWWfTn嵘I;7#ei~|-ja 5{N/7SKO OVof ͘7u[ bre|d2,tּ:,- S_2g'HB}m-mgݪN/ {_LX3h[ "`0dL&cB&)aQH +g2^܏_[؎1A\iV\F¸U-߻>`2zu+퟿>3hnUﶉMM5dvZ+uȕ#8~r])`uɔ~4v7܀sW6wWC}g_kwZ+Bǔm8N_Ǘ7}%8+VnڊN+:q{Qg~,-y?r{G\kgNL}N=1s>bqG nur뿛EA}3ÿ3Zjn'0~vzz+Yl0}7s斋p{&끻}Nϱw|Nʪ:sM#@讧'LC$\^0f2UkeQQ`f&yPW]w[)+a zVvr+~-ˤyq1*t=a7Z1?u?;arrܷKRX2ܮAxg=nSs'i{~FlʭB'*e~FoP':fx,1r+-p\ 7nԏkZ>Ã!bR?s/B#|Cz|=J!W=^z">2kCy`^edJEeܰv{u;??G]ߧs߽>+KKL&O'U kmwੈ+,$^ZU rӐ+d?.LF|4TUY!kQ5pEfLub֍tMJqeo􀩞iu=\ Ǐ\T>%oP`F ]bhZFA֢fGmytL&H+TI2O, 3Ȩt|-Oâ(H뿅*ʸ/n#]yEGs\0**ykpa5.o?Ύv/͗ۑ|Wo}5;˩io,S&ݢ)Bʅ_7htuڻ{I%\u#1د6+li~\"{"QeYl앫Dɖ-{C39 ld`$d@@|\C1z% 91-"դEV3߉hvib``8'&KâѤޔCXŊex?|@DP*Pԯ셜d2_!è`$'ԛNH L ^O[Y"M874_T +|0 dBW˸\8}붨F"Z,JCӇg( + u:y"~Qɐs(Zqp%(aK\YÜlY oJ* D}78M4 `s4FD)h͐j.oPͩ4l* +FDʶ: lHQXÂ}\v2Z + V0Iw!4.yJ޵?CXi+6m}QP!۴/ɒIHRw#:25!}ϋPA[!_kDwÒ̥$,i/JȁIhATE0Q +gߗNe$h׋Pg$hK;s@RoAR-c&Q("m㠯U¼QGhk<n 9ť< Fgd; _V-שkՅRO)kxsQ"AkRo>C&$F4h +ۄuCv+֑g*iKS0#㚨0.o>å֧xlv< vۡ/ZG1&9b5H ü8٢yIaӖ4P!ƔZm\c$0#0uSo;%[}*hk26'5ڻ1ا-\;k.屠6a\22RDM& _KFC[*?w0?={IEΰɎ (x%/PW3aw0?}V0ڴ{֦3aouy +mQК-\;k%`+AS=P0Ϸh Z՛~w N/kxs #@֤p$+zx +dlM& .Zs `s<|Rd+e g8tN[7 ȔC]îļZ $mNAt 45߲叾t^4G^JlO $J=F$6Ns1W(ϯW +f,cOpN?d'm)FOp2h>oAICa)Tx lo~j* +Jn3¢!WfghP3%h͈iu?MGjQ9 J8u>N_yv!CcZ${wQkrT'),M.#Nu +hMAH㽘D?|ZA:`G0JrKAսaoS܃7o>,rs v7x +kƺե¡2yA [H=uX6xB]V Zw` ``8f,$ܱ {JELmNBENjKNX!@gx+)K iW?Fh#+#4&.ZWMQ{*i <pyn:N۳YR7fqvr;HMԜx/;#^:q~ LYa#pè=`tt^3GXjP= Ld wkŶ=OǏkkx \چ-&EbWHX{?|>@_N#AںG 5F,j*BU* e͈Nf +Xr ,*PPI28 glnNx&YbjֱB+p+ﭣB/>N?)5U=tESZ1%6:/8+rA5,pF${HQba[prJl09# >ĀLꞅ'&f([͙=9]իtj\Ǣ3WbhqyI^|HHYvp{2b 4gtt?E]iFC_%[Zt$̠AE"E%敹)ngZu]^bDs=EjV +z2YBOKկZfGߑĐ R.R0#eBD3TOԝ?9> HgTx!nVa=A%F[?LL@[~x)RKZ=q6yžBǍR#SĒydRm#_j\7˸T #lbvKDy%Q=Zpǃ8etk.Έ.-F}Ӧj0J#R 1!AKSv&qDss:$e 1<^Igx}\?x վ+F5]ك4K6XupJhփF~5{t׫ilo7ޜd-DP7;$čGo}֚(z +^%jdqɬՒ@ՍϜ[.y̫.EE<:rAtFzLS0aËs(+^'@BS@4T_v촅;w(GQ0J hXq={,j|3QG[MZt~:ޱ2<&^t~+'LA7qҠQ./pbΪPё:މxƮMZvw{p~;2QC^E"6ca@<р&K$=p[j+0|=GRh4a4܆ՅI1x9ʗ}!'HAs@^j02}PS:z&myl< E@vjāE&j?Ifu:06㲓RQI: 5&u`0@18kk2jO3dSw_l- S*50 +LǫWKr["2 FZc69 죁WSy{:YXC!,Af QUO\G^\4q@Zq6Li'XTޝ,[dAАl)a5 U~vr9,%!Wqf?5`6~uPoxō+(426`Jqb F~A.r¢@b2 GPʯͫNY]k.RU ,,:PyGHQiA|9;,=UԸzmy̓tBƲ=HH@h62Y&KXA=FGSL2.ВOH߾:dr㊷WxbHQS:hu͎-܊Se7D{aO1v1 +}?) KvR-P԰*Зt 5pR^uȕ׭5yPCVR#$aha*LXDRjWSSj^ Aͷ9έEfIe7`ȗ#D XZfg Mݴ޾[.V+p.NcM\xqHu/͌8f{QjĔjWVW[j9fP)A4r"t˿>;{FvY5n@% Xz /5p]H|Sp:o#9-jMuՌҜ2Δp좽dn܂]Л@mvw@H (+;D2\詺u +Ǽʅ"[OFB;j -iqc:>Y"Cj[ԀĻ:Ek^w2\ JL\n-ǟ"<1 Ik5DCQ\qJlBƫO[m{j/c3D>yX JH/_fm\W} EY*ٲ$q5v")8) +8H6>OE }KSѢ4sg.YH<ZԐCs2F +>PNA1'O!I8f*i~&'"m5j6f -zGc]mAJd +;ZGoMYYB>ntE]]D +eOWQNf +51{u=&BH1/vR|(xں7妫8kh捫d5G;6dbތɛ$V \ƃg8̬>jxQhV fȠ +AKjmԘ$0)_M=GRIjb@ V7\e>D;>Jz_{Qg$+XƁRvZl%uByQe#5z&#qs%5h85aW,SʼBw|p`I[S13< +|Cq*i"mO>9FZjy:k{ڃ$'0>d| (\cqro5>m=H$85j璲'*f_aD+:4-Rov&.[1!NG厌uKŅ#)T! O㌤?>IK8ks%) D2-F7* + ;9H.5! +.EN5+z]RZ+Ygx֞Zv3XG0/[L>:jp2D)5AOg$m;=WQ/SDWSÖ4#seRO|i)5X=j %,΋Ɂ?}H[Q_?v^Tv:Ḏ:S״ PÐ+Z\P#)rĠ6Hƀ^Eϭe :jD EjzOfzPbn=H=0VhkxbJaS~Ή`($?u~P,)GUqy"6MAnv-Fxz _[.75"WTG(n1>É% ~s O?^ǁB7KǶt%fTw:X][UcvdYԷ-z$AD QC/{j ͓o-u'm]"R 'y)xb Ym}9amvL* *j 5N xڜN`73\NRM8/{|7Euا>{_7IYNbu5<МfCh2 6ie`}ƝmKk1V'l[Y1TNQC3iS!mـKg5W7Zu4iDؽ{&[t˨FʊӞBLfdnS5OZNq0 Gģ$#5\t6ۿtf4AgJl(YoOzʍWh5xL@azV/^9wJ7OS3kՉ,mLf1qX<@f(TyE},y`:O?v 1ՅvWC"оDJyqPc$M.B 8胀AǙR5Rw> ˬ1RCO TP z`TH +-H8qm:kCiW !LSz8$S+Y ֫n|44AFRTY8 u7h=,o~C:}Pz)qFt!ѥ ŞY2(:;LsM$cer b]'gJiu{<_\P +fgd(F$W㒌3ro- +Өqg(*& )aNS+0Py㇓KqT8SmtܲDƒ.ZXU;h55*j>xˤjKX:s>Fr,h1۸Պ\f +y2&}zX&/YI.=bbd +v?˞ȧeA#i&hZX~W%Hnm|2C+/MZVj6K붤RWZ% {3k9,:*ۯERhy^6.:3+ƀ5?$RBmQn YU"(pZO8xMcHU.іL*jy'ae3;!{T県E쑄,ӻKZ cY\P[B2e/eB iTw<[cI'3Xqqѓq_%mW\G99 IQ Fmrdɻ 75\p4) E{1 +K/r*PYH"-+K\f83 +Ã!7ooQ`b#! 9#(m%|JA6JŚ}X iijJwN޾9dA]֩UiÖjDJ;dC,,~f:KtbV;xCiiQeָuRJ4lc~OYEM{9+k`\X.j8v捙%snI5Þԩٵ|P=Q&Qk!+]NDY–4ocqMkTTbwk0*%8CKK)I9QD$C;9Ђ eq8?ӁcCNֲ_?}J<x`8`Ew{&vC X;ZwqfTaÜtEyäZTĄG URb9,HΡ YJ)P n`I Ċ5Vd_:4(nQ\Q;F;WLf5;y֖5,3FCpPրꈈ- +hwQ bçqXy`HC1iū5d?#%|Ӻ&;*ٙ! 9Kкp-Y~a(pMBb=FP"|y3mY\dkƉё!öeQr#{n;b"ӂnZq0b Ilj5K{P oL즙H$Ƹܛ+ŧ}*vى5uFt9hGӼR k g')%W:#QQao1t)S<ܽ5 GɈ[dXlmTI~RYH>uF=WTۘ˛o櫌WR-5g +ܞ51{v/4wf 2uZ~ +u[-"i LdMf/ +i&h'T臩,CM,ҭ&r ŗG.I(/Oen0T'sfzs~yʈ•rf9}ZS}Z?./9J\VWNdgѴBבwo O9yb씒X?Z3LKi!N'Fjuv^ +|FEgH`6g/VX[x!ެ |E:98~. +&aX9C%vuQLύ3yT*0peEQ'ɜ_e'ƿ,j@}J?ΌƯRL`Zn >HC^PF+WʶǶ]l&?l&5mVZo&0ի?)̐ώ*[]u +"sOSEQB{$~^m'fN3#B;\Bf'~.lvx)}K723ήadqǤc*.+d&"q=2:A}0`v㮈 +!)SRIi7䁶B[ !c#b3 1uk!a*c[a82ex'.*"IXvLL:Bmڝ#ceU7 rJ̗-iu\=L1FDŸK}+QW2tEtU錩ҥC0ԅy0>wPbN!T⯠䝆it"Wwh2#o6"r%ǻu:e*'/7 &sҶ1ScG}\)%Leiɋ9 eʭ4еWSCN+BL8,O,3&3C>>A4EnsK}< {L䥇|LxدGnYF} +ȫ=brmO\sKwM+Ғ tsHQUGz]P pX߳ɋQ!. +=ʭ12:RW"#cT1ԧ.Q##qU2`\o18f2&z3m쿢>)kE +=.I"m|]/|I}@px: 1)}["'z|>?sXl:eG^УzKYnZ[.ym^Hįc?~Љ" }^0s5SwmLhTJ^'<:_޶]wiLE4"s&]y} (]I<:*\*[ny^tθ9 S)7Ů'+[b =£"O ?7; "3=HK޺ WY*Kgk㞭4S=-a Be+tw={##&b?6LOjV\x[zиԬoBL ߈w>MZucFZJk]n>ȩ`F=|vt}?ͤ)6EQPo@ ,nص^-2lr랴(yq ' Κzߴ{ٕ[2?=u`*B^cW{jd2!ȗ-uD":]m?/_^fs'A&nr?CR)¿,r?L]I?5 +pu~;\VCho~2Ar&-txcR86yV O] Uۢ(¹4?wQڞ[nB&؏ 3 dR0?#E'UrQz.:?;6%WwfJӊwIo*2ɔV.lWi +8.֫A;"INNcLDtqtz5HVC oDnBg!ryeDu+0˾'AUU2^T82ϟ3Ǣ +[6zN% +v)=/3X4D/it2%沟v@rZk湓<[0nt7TFN=~-KSO4>}霪TD.f+k_ Z$YܖG2S2ӗW)ڥl|PƻHw endstream endobj 859 0 obj <>stream +Adobed + + + +                +   + ZG +!"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyzVK +!"#$%&'()*123456789:ABCDEFGHIJQRSTUVWXYZabcdefghijqrstuvwxyz?K@0Xx? endstream endobj 860 0 obj <> endobj 1 0 obj <>/Font<>/ProcSet[/PDF/Text]/Properties<>>>/Rotate 0/StructParents 1/TrimBox[0.0 0.0 612.0 792.0]/Type/Page>> endobj 2 0 obj <>stream +HWێܸ}УlD!`" A8kN2%*5^ %XSN}͋ln/y?8 M7^ͻO7}7oghj?ՇK{*hڟ: >?ͿË84ugo9;kڏD; pǦ7/K` !Fk5o׿<>zpzNEތma:s{;|/t;*9=`C{6~a95+ V‹`I{VM` +RcHr2kWV +/,V.wiom8<;:}[3=S/^4W=YV9ȹULMP<޸l}D\y9ObKW +Ⲕt"㨄{Ďnz<'X!] ȁòg^90QRw C:K& d/5"(<"!޴re1kJj+;I5BXȲg`@_Z9 "Y꓊sG.i3ecOA`*6zJޭ?m܄nAUt_6EC\jq:^@]W8VۇPM4idUEU=?v1S.>X@S!?;lҾ @5S߻POMx q&a ieo͛EO]AK˟ X6ū>/Mfbp,o?,~b@od [/u?RRWAe'6׳J)10NbBPx&4yqKXdzj@=U$˧6lb=ːd}D9-rZ@{{Zd|tc<[QToY#bMlD@JwNó9(q)oNH ˠMa/&&'l/(QJ?LoLOm4柝v&ߪolT).y)5-bM`i[YlF"yU>/E^N lVlCU[dESpN-g+*I>?e.4maRdaњc'=Oja* aKƻR"|Z "~oNu6n\R +]r% ]r=DjsD8]"|.qU:7HIVźwK q@z|g_ޢMvx{o0X_UTRMU)u`aC21G7H| 3tSuac0QI1(e +ɺ"܋;;gwq<^&EzRSW 5 OQZxoPPK@[.d{37aTI;J Qg8^ؼdjr&^@Ⱅ6܌{!gD*+*!.8ۂpb,H:jkVvb3gm ''W60I\ZY3xB=Ndžm:)ɐÿ@>}5u5Ɍp|lij +Ţ&E35E3rΫlw334g^l.X}7H +7azu~.^O-)"<ċM;!s·3d\}q F ik"G9S.=k8cHPむb2(/"Ƴآ\DdD}KW,J/9`z1R.AM殥sP$B AlGzcn-Gy &PʄJmi;ZeX.o=-CazEq. %XX 2:Jx7&L\5«MԄX*Hx0] +霧}mcRilw; =dIu#L BG PϤ^xR-f.n)&; +zZ96O)3Odg.v/&( &ׂDc>Ei'lMrTҽ2Me4kӯ.A2d_i=$0VOp9g7 *Ǒ$Gz"?P$C VZ`Uv'B`":5WYj]_ךF  \λ)%2(1 +N@,M6>4՜B\[qC3eyn6 t'Z/D,2f4h?K/z(ʜpt>(8_8J(5Y! h#;vQ`"Nbt̙RNVj>q 0FMliGƋ;lIN8pfWG$K{8.Rot٨Ss^4q8?(ڮ1ȆDhd^EB;vt9h!)άd1kIޒYK͖SyN`@|ꗛc2#iYCSRCQzo$fhhxEgeH< @/&M>Mb2"Ω^EaX09̓6Ÿ!p;bqAukV jo\Wo xd(Q;hbԔ7 +尽ypln==W&0y"wN,U%0-*!ݢ-4q/~qd` GҖ*p 8qU˼ka"+ʣ0wZ[Q*Ma6B/JwL߆y*Q{T`Y˅)tƪ W|z~*H^l6D=kĜ< V6AFMWc${ށBoM$>~=if\Gp3Iس'Rc'1熾)KfR6Җ$Dɳ/hktgquc\D +4>9Q5sN&aꛅ,%^zzԝ UN ̭ws ++ Elݗ:ʰP\:OЉ9P}l?jĩ}yfۖ+s0%j^/st4 rJvY;,R+:|Եx _^Q^^z.8hbRGʞ^I9:D%$PV4,P:CIň1 *u&YCIFTdK>ZbEQ3`Cq FoJR㦞)u*["}J+\ +ZvL*_F]|0ljv_ǽѤNm7tv&&u2L B04&HY 8~J)u~mQn{=G_^8u{_u/-am +ƐKG/@u-5sF_gOIK&S t }j.ٲ1-'G{U+8Qx2 +a&E0Y|u A]7I/hërc8ZfIX 9dD$v2u*WO FAhiWO$SY/k_+zm@=f*DPi%SkG5H dcgrk"2@I [25j >N(6 TD [u))cǍJmʀY { +Z0V>0D5ԍB}c.pIeŦփ(߫L@ toܬĝm:aFWTE}Xq9<틏xVG"}co0B)GyqK.:Z#eDVHP*/ԐFiE~R04[(Qvs3 2$ɭYa}vv9(MZ48)%q!.-o)'?P1#2v_pѧ*Equ6؜uq(tfώkߺ&vt04ӽvIBM ŒK]>`:̸z+w,V/[]<\l3zdl@#: ;?/|H|b6~^hʥmW[AlOngp+p7:w!h2vaNB{$q u:HS1*P[!r;zo(&$YqQD{6NhGF0X'P:H'iwvG1PAe+$pK˹1`7r0Y̳*D/fyǧ>iufZth +x3GP IY=G!foM%+.[ ]jtZ5S ioa9#ىe@Z{ȟ຿=<ly! 0j=:B]r +u=hZpӎadU +j0}Bs>fF:qRmF raوs$uWYCQm*~q[Ƅ+ +zq?w;ڍJOL;}M*RnQm*>MۣNHFTѨ%d A4fIym1b{\e9NBH,uXA +7cb70&GE.~S *( +5jom" mV7[LAaϱW0C`P|qΔ&FbsR*0?m߽odsΧǛ-efoV[=_>w|V].#Y ʁQ Fc+ӪXu[mmP 9z*ζ bWnɺXba#[;L;D#>GaN)oW@T&xftk&4@N7F5SebD_h +^ ȻwE 1%۬">"N]\.WVe:LW=eQ?͹YM;@Iu60A8 $euT\ufgn݅_3y@ GT S]̞v0̶Md溫W@ټ9qP gRvs!M{FVa~0ޅhm,X m:2;jra)W/DtGZeG!1 fT˃FHii@D{NSȭ><0ž|z{{e+P pKzy;,ijln|2&f"7k,BPѨA*X8&CT ʾm?5VVf*Vti=V+hJ! -KYtG7⒂z^*QJ^DFy[2Ŕ Mk] ~k-hL M3ѐªQ}{F-tD\׭il9GK$f͢H+HHto}ܺ*1\G=aPY{U$TNZhiXdŘʉH*"MrkmnN., W9'!:f+JN/!+2$ +&#V%7-ڦF#a7+99Hf u]mk>rn.Qڢg<+,{tJh'쥻,'VFPҏҗ06Rܔ0'?Y3#WLˊr<$ZI4=kT|yλٍF_tUS%JKh#Q?PL۞(R(弇->JS< 5\\a~KAM e/mO ۇ#;t& eܲk }:]!$665V cR6Ns2'jO@̀.Z+yP?ˋNm{1@pɱI}/ ۯ4.tԓzBT+&xUf ꓨ- VUO߽}'}p֮pe2ۓi\XB,v58 _@+L<Dsb]"CKuj]3qQX:M 4^ 5; \a Nȶ:8tߑ-^Pk'SdpD/Gx™3<g5߽mw4&44b52:0xj0#M5Gg!X| lt8E#f] +/ɦ +V'X!, Pxq2QA%DS05Uם ac]p C 9X%h)b@NmQeَB2p>&`[v@ȣIRʜ/ n%v(lwTKMCbMm]9A!OR $70Ŋ#H*UR2 q" +-<&M!nӰF312C|[ +C֔ ++;eD U(PFP6@l-~*@*pGBljyK G, +Vjȥ@n'p_"BEGSw.?:THMIp0yj ;QZ6\+N +9ꃗR*U7+83X0/i*g׏o~ݧj) C@X*Hx4y'2 +4`;m>J=S +\bL1n1^%+rA_G06h|2ƈA>{/2ȭ"^DF%mg.d_δ0Rh̴ /R:fŘl1:Q?>&WhiXK,jZ\@tHbEh'!dxC 2ɕ| aWe"ÙW&$K_e 2. "FI Q9፲Z#MLHGs*jCzfh&{LolHde/@6ϡxl˸v8ϼHOh*]Mi{=0&ͥVXY1N6lLVSmC'cũ4"&xe _7m{K6q!((g'gZ)Mzd-[25]1V6$V[%jm&!(Y4p*uqd2lȃ6e=Q $D( +c#oH+ IHEV**;U2SbӷUu}m CF- ߀H}d{D#oE=E'≡nMx\Ex o$Np[&8K։_2rjeզE/׉W2MZ5ޅ-*݉.0]t`It:L[a^\qVpeMpw!2..51!"ZOC9Օ1Ja:$03* v]64s }j^SE2·L+OG+d9g?ל.ڣ\|P%b\0 ZwQ؈˅XD5+R$tl mxf"+ q“ڙ+G0Wf&OF&\HAgy\G-Mёø!-Ge09炦&ڇEƮ>.whM6:8ڒm)>,A<ïM-y܊Rc5,L+`r(Rݐ6h) 層mArjZQ?7aݴ/sҮe *F`1|LC!i"}CiX\!``k~ fb4ƶ3 T6k €P5/qBV,NNW%J#8 5gQhz=LhHpn}:2Cvquq7@̄/3D RJ7Lp;a<@]JÄ. 7?B endstream endobj 3 0 obj <> endobj 4 0 obj <>stream + + + + + application/postscript + + + DejaVu_Vector_Logo + + + + + Anita Elder + + + 2018-06-12T11:26:55-07:00 + 2018-06-12T11:26:55-07:00 + 2018-06-12T11:26:55-07:00 + Adobe Illustrator CC 22.1 (Windows) + xmp.iid:a276dd2f-eb90-f942-9164-d588f14a29fb + xmp.did:a276dd2f-eb90-f942-9164-d588f14a29fb + uuid:5D20892493BFDB11914A8590D31508C8 + proof:pdf + + xmp.iid:5cf13117-3af1-0c45-b7d7-ac547a1ea5dd + xmp.did:5cf13117-3af1-0c45-b7d7-ac547a1ea5dd + uuid:5D20892493BFDB11914A8590D31508C8 + proof:pdf + + + + + saved + xmp.iid:b48ff162-4a38-4ed0-a4d1-55a6d9f1e278 + 2016-02-03T15:18-08:00 + Adobe Illustrator CC 2014 (Macintosh) + / + + + saved + xmp.iid:03375135-0e19-4bec-b799-6da9b8675c55 + 2016-02-03T20:50:50-08:00 + Adobe Illustrator CC 2015 (Macintosh) + / + + + converted + from application/postscript to application/vnd.adobe.illustrator + + + saved + xmp.iid:5cf13117-3af1-0c45-b7d7-ac547a1ea5dd + 2018-06-12T11:15:18-07:00 + Adobe Illustrator CC 22.1 (Windows) + / + + + converted + from application/postscript to application/vnd.adobe.illustrator + + + saved + xmp.iid:a276dd2f-eb90-f942-9164-d588f14a29fb + 2018-06-12T11:26:55-07:00 + Adobe Illustrator CC 22.1 (Windows) + / + + + + Print + False + False + 1 + + 515.069444 + 138.041667 + Pixels + + + + Cyan + Magenta + Yellow + + + + + + Default Swatch Group + 0 + + + + White + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 0.000000 + + + Black + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 100.000000 + + + CMYK Red + CMYK + PROCESS + 0.000000 + 100.000000 + 100.000000 + 0.000000 + + + CMYK Yellow + CMYK + PROCESS + 0.000000 + 0.000000 + 100.000000 + 0.000000 + + + CMYK Green + CMYK + PROCESS + 100.000000 + 0.000000 + 100.000000 + 0.000000 + + + CMYK Cyan + CMYK + PROCESS + 100.000000 + 0.000000 + 0.000000 + 0.000000 + + + CMYK Blue + CMYK + PROCESS + 100.000000 + 100.000000 + 0.000000 + 0.000000 + + + CMYK Magenta + CMYK + PROCESS + 0.000000 + 100.000000 + 0.000000 + 0.000000 + + + C=15 M=100 Y=90 K=10 + CMYK + PROCESS + 15.000000 + 100.000000 + 90.000000 + 10.000000 + + + C=0 M=90 Y=85 K=0 + CMYK + PROCESS + 0.000000 + 90.000000 + 85.000000 + 0.000000 + + + C=0 M=80 Y=95 K=0 + CMYK + PROCESS + 0.000000 + 80.000000 + 95.000000 + 0.000000 + + + C=0 M=50 Y=100 K=0 + CMYK + PROCESS + 0.000000 + 50.000000 + 100.000000 + 0.000000 + + + C=0 M=35 Y=85 K=0 + CMYK + PROCESS + 0.000000 + 35.000000 + 85.000000 + 0.000000 + + + C=5 M=0 Y=90 K=0 + CMYK + PROCESS + 5.000000 + 0.000000 + 90.000000 + 0.000000 + + + C=20 M=0 Y=100 K=0 + CMYK + PROCESS + 20.000000 + 0.000000 + 100.000000 + 0.000000 + + + C=50 M=0 Y=100 K=0 + CMYK + PROCESS + 50.000000 + 0.000000 + 100.000000 + 0.000000 + + + C=75 M=0 Y=100 K=0 + CMYK + PROCESS + 75.000000 + 0.000000 + 100.000000 + 0.000000 + + + C=85 M=10 Y=100 K=10 + CMYK + PROCESS + 85.000000 + 10.000000 + 100.000000 + 10.000000 + + + C=90 M=30 Y=95 K=30 + CMYK + PROCESS + 90.000000 + 30.000000 + 95.000000 + 30.000000 + + + C=75 M=0 Y=75 K=0 + CMYK + PROCESS + 75.000000 + 0.000000 + 75.000000 + 0.000000 + + + C=80 M=10 Y=45 K=0 + CMYK + PROCESS + 80.000000 + 10.000000 + 45.000000 + 0.000000 + + + C=70 M=15 Y=0 K=0 + CMYK + PROCESS + 70.000000 + 15.000000 + 0.000000 + 0.000000 + + + C=85 M=50 Y=0 K=0 + CMYK + PROCESS + 85.000000 + 50.000000 + 0.000000 + 0.000000 + + + C=100 M=95 Y=5 K=0 + CMYK + PROCESS + 100.000000 + 95.000000 + 5.000000 + 0.000000 + + + C=100 M=100 Y=25 K=25 + CMYK + PROCESS + 100.000000 + 100.000000 + 25.000000 + 25.000000 + + + C=75 M=100 Y=0 K=0 + CMYK + PROCESS + 75.000000 + 100.000000 + 0.000000 + 0.000000 + + + C=50 M=100 Y=0 K=0 + CMYK + PROCESS + 50.000000 + 100.000000 + 0.000000 + 0.000000 + + + C=35 M=100 Y=35 K=10 + CMYK + PROCESS + 35.000000 + 100.000000 + 35.000000 + 10.000000 + + + C=10 M=100 Y=50 K=0 + CMYK + PROCESS + 10.000000 + 100.000000 + 50.000000 + 0.000000 + + + C=0 M=95 Y=20 K=0 + CMYK + PROCESS + 0.000000 + 95.000000 + 20.000000 + 0.000000 + + + C=25 M=25 Y=40 K=0 + CMYK + PROCESS + 25.000000 + 25.000000 + 40.000000 + 0.000000 + + + C=40 M=45 Y=50 K=5 + CMYK + PROCESS + 40.000000 + 45.000000 + 50.000000 + 5.000000 + + + C=50 M=50 Y=60 K=25 + CMYK + PROCESS + 50.000000 + 50.000000 + 60.000000 + 25.000000 + + + C=55 M=60 Y=65 K=40 + CMYK + PROCESS + 55.000000 + 60.000000 + 65.000000 + 40.000000 + + + C=25 M=40 Y=65 K=0 + CMYK + PROCESS + 25.000000 + 40.000000 + 65.000000 + 0.000000 + + + C=30 M=50 Y=75 K=10 + CMYK + PROCESS + 30.000000 + 50.000000 + 75.000000 + 10.000000 + + + C=35 M=60 Y=80 K=25 + CMYK + PROCESS + 35.000000 + 60.000000 + 80.000000 + 25.000000 + + + C=40 M=65 Y=90 K=35 + CMYK + PROCESS + 40.000000 + 65.000000 + 90.000000 + 35.000000 + + + C=40 M=70 Y=100 K=50 + CMYK + PROCESS + 40.000000 + 70.000000 + 100.000000 + 50.000000 + + + C=50 M=70 Y=80 K=70 + CMYK + PROCESS + 50.000000 + 70.000000 + 80.000000 + 70.000000 + + + C=71 M=18 Y=40 K=0 1 + CMYK + PROCESS + 70.999998 + 18.000001 + 40.000001 + 0.000000 + + + + + + Grays + 1 + + + + C=0 M=0 Y=0 K=100 + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 100.000000 + + + C=0 M=0 Y=0 K=90 + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 89.999400 + + + C=0 M=0 Y=0 K=80 + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 79.998800 + + + C=0 M=0 Y=0 K=70 + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 69.999700 + + + C=0 M=0 Y=0 K=60 + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 59.999100 + + + C=0 M=0 Y=0 K=50 + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 50.000000 + + + C=0 M=0 Y=0 K=40 + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 39.999400 + + + C=0 M=0 Y=0 K=30 + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 29.998800 + + + C=0 M=0 Y=0 K=20 + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 19.999700 + + + C=0 M=0 Y=0 K=10 + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 9.999100 + + + C=0 M=0 Y=0 K=5 + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 4.998800 + + + + + + Brights + 1 + + + + C=0 M=100 Y=100 K=0 + CMYK + PROCESS + 0.000000 + 100.000000 + 100.000000 + 0.000000 + + + C=0 M=75 Y=100 K=0 + CMYK + PROCESS + 0.000000 + 75.000000 + 100.000000 + 0.000000 + + + C=0 M=10 Y=95 K=0 + CMYK + PROCESS + 0.000000 + 10.000000 + 95.000000 + 0.000000 + + + C=85 M=10 Y=100 K=0 + CMYK + PROCESS + 85.000000 + 10.000000 + 100.000000 + 0.000000 + + + C=100 M=90 Y=0 K=0 + CMYK + PROCESS + 100.000000 + 90.000000 + 0.000000 + 0.000000 + + + C=60 M=90 Y=0 K=0 + CMYK + PROCESS + 60.000000 + 90.000000 + 0.003100 + 0.003100 + + + + + + + Adobe PDF library 11.00 + + + + endstream endobj 5 0 obj <> endobj 6 0 obj <>stream +hXN#GzLVH( !}Yb \[,࢜iMZhuҴ7)4jG׃ ?λ}xM'c.Oۥ坈_VCݢ{WHB.d9LR!y|:IIV/ޕ?#ϪK־TB*T?HAiLAS0,GS ƕ{E(r}.K!j|Th(ZZb)&hILIS2,$O)PӶHPd +Y@4؂ı2d8b'kfo- dD:FX@7wS|t74 )< \9f~kIQ%J2`$#3>ٰi<8|t|z}/8z^tqS .ѴUir5ofV-{L;Ū}n7dxB2®WkY }&%T%X܈Iԓ^н=^ WkQu[`EI*, ٌzJ|hո_ߐ m9s_[FOOkwb=ǵ(DWׄ'qX>kO`kfxzC,ve-#Z\Bh 7PK{{7Ҵr'sn;zE Hiunzۀ_DL>ߣOpJ&gJb("l"ۚuȡHn&'ĺg`q endstream endobj 7 0 obj <> endobj 8 0 obj <>stream + + + + + 2018-07-09T10:52:21-07:00 + 2018-07-09T10:52:22-07:00 + 2018-07-09T10:52:22-07:00 + Adobe InDesign CC 13.1 (Macintosh) + uuid:efa7b6ac-b567-7e43-acda-ec2bd66a960b + xmp.did:6d594af4-798e-bb4c-83a5-95d352f5d45d + xmp.id:d63c1686-0bb1-483f-ad31-9617b1e88123 + proof:pdf + + xmp.iid:427e1296-0f0b-4e54-9f92-27b7554e3477 + xmp.did:c620fe00-27b1-ca44-b18a-a41135316593 + xmp.did:6d594af4-798e-bb4c-83a5-95d352f5d45d + default + + + + + converted + from application/x-indesign to application/pdf + Adobe InDesign CC 13.1 (Macintosh) + / + 2018-07-09T10:52:21-07:00 + + + + application/pdf + Adobe PDF Library 15.0 + False + + + + OpenType - TT + Agency FB + 0 + The Font Bureau + 1.01 + 0 + 523447529 + 523447529 + AgencyFB-Bold + + + OpenType - TT + Agency FB + 0 + The Font Bureau + 1.01 + 0 + 2403106829 + 2403106829 + AgencyFB-Reg + + + OpenType - TT + Lato + 0 + -- + 1.104 + 0 + 3680671707 + 3680671707 + Lato-Light + + + OpenType - TT + Lato + 0 + -- + 2.015 + 0 + 1903528725 + 1903528725 + Lato-Bold + + + OpenType - TT + Lato + 0 + -- + 2.015 + 0 + 104612236 + 104612236 + Lato-Regular + + + OpenType - TT + Lato + 0 + -- + 1.104 + 0 + 2547842625 + 2547842625 + Lato-Black + + + + + + + endstream endobj 9 0 obj <> endobj xref +0 49 +0000000000 65535 f +0000752417 00000 n +0000752797 00000 n +0000764811 00000 n +0000764921 00000 n +0000802646 00000 n +0000802681 00000 n +0000803970 00000 n +0000804028 00000 n +0000812064 00000 n +0000000000 65535 f +0000000000 65535 f +0000000000 65535 f +0000000000 65535 f +0000000000 65535 f +0000000000 65535 f +0000000000 65535 f +0000000000 65535 f +0000000000 65535 f +0000000000 65535 f +0000000000 65535 f +0000000000 65535 f +0000000000 65535 f +0000000000 65535 f +0000000000 65535 f +0000000000 65535 f +0000000000 65535 f +0000000000 65535 f +0000000000 65535 f +0000000000 65535 f +0000000000 65535 f +0000000000 65535 f +0000000000 65535 f +0000000000 65535 f +0000000000 65535 f +0000000000 65535 f +0000000000 65535 f +0000000000 65535 f +0000000000 65535 f +0000000000 65535 f +0000000000 65535 f +0000000000 65535 f +0000000000 65535 f +0000000000 65535 f +0000000000 65535 f +0000000000 65535 f +0000000000 65535 f +0000000000 65535 f +0000000000 65535 f +trailer <]>> startxref 116 %%EOF \ No newline at end of file diff --git a/audits/2018-05_Status-Beta_Deja_Vu/Deja_Vu-Status_Beta_Report_Finalized.pdf b/audits/2018-05_Status-Beta_Deja_Vu/Deja_Vu-Status_Beta_Report_Finalized.pdf new file mode 100644 index 0000000..663d6ea Binary files /dev/null and b/audits/2018-05_Status-Beta_Deja_Vu/Deja_Vu-Status_Beta_Report_Finalized.pdf differ diff --git a/audits/2018-05_Status-Beta_Deja_Vu/README.md b/audits/2018-05_Status-Beta_Deja_Vu/README.md new file mode 100644 index 0000000..bace2cb --- /dev/null +++ b/audits/2018-05_Status-Beta_Deja_Vu/README.md @@ -0,0 +1,6 @@ +# Status Mobile App Beta audit by Deja Vu + +## Resources +- [Summary Blog Post by Deja Vu](https://www.dejavusecurity.com/blog/status-case-study) +- [Deja Vu Complete Report](./Deja_Vu-Status_Beta_Report_Finalized.pdf) +- [Deja Vu Short Report](./18_DVS_Status_Case_Study_Short_Version_R2_WEB.pdf) \ No newline at end of file diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/README.md b/audits/2018-10_ENS-Usernames_Sigma-Prime/README.md new file mode 100644 index 0000000..a078903 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/README.md @@ -0,0 +1,6 @@ +## ENS Usernames Contract audit by Sigma Prime +Audit was performed on the ENS Username Contract at commit hash [eaefa92](https://github.com/status-im/ens-usernames/commit/eaefa92a258c784f1df4066e057e8170bcb6ef95#diff-dbff1e6b987cbb9a6b87ea8180c41e72) + +## Resources +- [Sigma Prime Blog Post](https://blog.sigmaprime.io/status-ens-review.html) +- \ No newline at end of file diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/Sigma_Prime-ENS_Usernames_Report-FInalized.pdf b/audits/2018-10_ENS-Usernames_Sigma-Prime/Sigma_Prime-ENS_Usernames_Report-FInalized.pdf new file mode 100644 index 0000000..66227c0 Binary files /dev/null and b/audits/2018-10_ENS-Usernames_Sigma-Prime/Sigma_Prime-ENS_Usernames_Report-FInalized.pdf differ diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/build-submodules-here b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/build-submodules-here new file mode 100644 index 0000000..e69de29 diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/README.md b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/README.md new file mode 100644 index 0000000..2e45814 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/README.md @@ -0,0 +1,44 @@ +# Status ENS Usernames + +DApp to register usernames for Status Network, using ENS subnodes as usernames and Public Resolver to configure public key and/or public address. + + +### Stateofus.eth Terms of name registration +- 100 SNT is deposited, not spent; the amount is locked up for 1 year; only user can control their deposited funds. +- After 1 year, the user can release the name for being registered again, and receive their deposit back. +- Usernames are created as a subdomain of `stateofus.eth` [ENS domain](https://ens.domains/). +- Usernames not allowed are less then 4 characters, or contained in this list (link to list), or starts with `0x` and more then 12 characters. +- Revealing a registered not allowed username will result in loss of deposit and removal of username. +- Users are free to own the subdomains, but they are property of Status Network, and might be subject of new terms. +- If terms of the contract change—e.g. Status Network makes contract upgrades—the user has the right to get their deposit back and release the username, or do nothing and keep using username as long new contract allows it. +- User's handle (name) is always secret to network until user reveals it to someone. +- User's address(es) when associated with a username will be publicly visible. + +Usernames eliminates the need to copy/scan - and worse, type - long hexadecimal addresses / public keys, by providing an ENS subdomain registry and recognition of ENS names in Status for interacting with other people in Status. + +Requires https://github.com/creationix/nvm +Usage: + ``` + nvm install v8.9.4 + nvm use v8.9.4 + npm install -g embark + git clone https://github.com/status-im/ens-usernames.git + cd ens-usernames + npm install + embark test + embark blockchain + embark run + ``` + + +## Deployment Details +| Contract | Ropsten Address | Mainnet Address | +| ---------------------------|------------------------------------------- | ------------------------------------------ | +| ens/ENSRegistry | 0x112234455c3a32fd11230c42e7bccd4a84e02010 | 0x314159265dd8dbb310642f98f50c066173c1259b | +| ens/PublicResolver | 0x29754bADB2640b98F6deF0f52D41418b0d2e0C51 | 0x5FfC014343cd971B7eb70732021E26C35B744cc4 | +| token/TestToken | 0xc55cF4B03948D7EBc8b9E8BAD92643703811d162 | 0x744d70fdbe2ba4cf95131626614a1763df805b9e | +| registry/UsernameRegistrar | 0x028F3Df706c5295Ba283c326F4692c375D14cb68 | 0xDBf9038cf5Aaa030890790dB87E746E00Fc352b3 | +| common/MerkleProof | 0x5df00E70AD165D50228DB6d8285fB6EAAc630FD7 | 0x713ED9846463235df08D92B886938651105D3940 | +| test/MerkleProofWrapper | 0x58E01078d14142E0370526dFdAE44E4f508c844B | 0x76E55E13C5891a90f7fCA2e1238a6B3463F564e2 | +| common/SafeMath | 0x0F9992f7737f9ba3aceD170D4D1259cb2CEcc050 | 0xA115a57952D3337e2a1aB3Cb82bA376EEcDDc469 | + diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/_babelrc b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/_babelrc new file mode 100644 index 0000000..eb62d26 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/_babelrc @@ -0,0 +1,24 @@ +{ + "plugins": [ + "@babel/plugin-proposal-object-rest-spread", + "@babel/plugin-syntax-dynamic-import", + "@babel/plugin-syntax-import-meta", + "@babel/plugin-proposal-class-properties", + "@babel/plugin-proposal-json-strings", + [ + "@babel/plugin-proposal-decorators", + { + "legacy": true + } + ], + "@babel/plugin-proposal-function-sent", + "@babel/plugin-proposal-export-namespace-from", + "@babel/plugin-proposal-numeric-separator", + "@babel/plugin-proposal-throw-expressions" + ], + "presets": [], + "ignore": [ + "config/", + "node_modules" + ] + } diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/_eslintrc.json b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/_eslintrc.json new file mode 100644 index 0000000..f8ab647 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/_eslintrc.json @@ -0,0 +1,9 @@ +{ + "extends": "airbnb", + "plugins": [ + "react" + ], + "rules": { + "react/prop-types": 0 + } +} diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/_git b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/_git new file mode 100644 index 0000000..06cf9d4 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/_git @@ -0,0 +1 @@ +gitdir: ../../.git/modules/code/ens-usernames diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/_gitattributes b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/_gitattributes new file mode 100644 index 0000000..7cc88f0 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/_gitattributes @@ -0,0 +1 @@ +*.sol linguist-language=Solidity \ No newline at end of file diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/_gitignore b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/_gitignore new file mode 100644 index 0000000..c55e7b8 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/_gitignore @@ -0,0 +1,44 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# embark +.embark/ +chains.json +config/production/password +config/livenet/password + +# egg-related +viper.egg-info/ +build/ +dist/ +.eggs/ + +# pyenv +.python-version + +# dotenv +.env + +# virtualenv +.venv/ +venv/ +ENV/ + +# Coverage tests +.coverage +.cache/ +coverage/ +coverageEnv/ +coverage.json + +# node +node_modules/ +npm-debug.log +package-lock.json + +# other +.vs/ +bin/ +.idea/ diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/actions/accounts.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/actions/accounts.js new file mode 100644 index 0000000..8fd8cd3 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/actions/accounts.js @@ -0,0 +1,51 @@ +import ERC20Token from 'Embark/contracts/ERC20Token' +import UsernameRegistrar from 'Embark/contracts/UsernameRegistrar' +import TestToken from 'Embark/contracts/TestToken' + +import { getDefaultAccount } from '../utils/web3Helpers' +import { actions as accountActions } from '../reducers/accounts' +import { isNil } from 'lodash' + +const { receiveAccounts, receiveStatusContactCode } = accountActions +const CONTACT_CODE = 'CONTACT_CODE' +const STATUS_API_REQUEST = 'STATUS_API_REQUEST' +const hasContactCode = () => !isNil(STATUS_API) && !isNil(STATUS_API[CONTACT_CODE]) +const statusApiSuccess = event => event.detail.permissions[0] === CONTACT_CODE +const getContactCode = event => event.detail.data[CONTACT_CODE] + +export const fetchAndDispatchAccountsWithBalances = (web3, dispatch) => { + web3.eth.getAccounts((err, addresses) => { + if (addresses) { + const defaultAccount = web3.eth.defaultAccount || addresses[0] + const accounts = addresses.map(async address => { + const balance = await web3.eth.getBalance(address, 'latest') + const SNTBalance = await ERC20Token.methods.balanceOf(address).call() + return { address, balance, SNTBalance } + }) + Promise.all(accounts).then(accounts => { + dispatch(receiveAccounts(defaultAccount, accounts)) + }) + } + }) +} +export const checkAndDispatchStatusContactCode = dispatch => { + window.addEventListener('statusapi', function (event) { + if (statusApiSuccess(event)) dispatch(receiveStatusContactCode(getContactCode(event))) + }); + + setTimeout( + () => { window.postMessage({ type: STATUS_API_REQUEST, permissions: ["CONTACT_CODE", "CONTACTS"] }, '*') }, + 1000 + ) +} + +export const fetchAndDispatchSNTAllowance = dispatch => { + const { methods: { allowance } } = TestToken; + const { receiveSntAllowance } = accountActions; + const spender = UsernameRegistrar._address; + allowance(getDefaultAccount(), spender) + .call() + .then(allowance => { + dispatch(receiveSntAllowance(allowance)) + }) +} diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/AdminMode.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/AdminMode.js new file mode 100644 index 0000000..f32e78b --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/AdminMode.js @@ -0,0 +1,30 @@ +import React, { Fragment } from 'react'; +import { Tabs, Tab } from 'react-bootstrap'; +import TopNavbar from './topnavbar'; +import TestTokenUI from './testtoken'; +import ERC20TokenUI from './erc20token'; +import ENSSubManagement from './ensSubManagement'; +import NameLookup from './ens/nameLookup'; + + +const AdminMode = () => ( + + + + + + + + + + + + + + + + + +); + +export default AdminMode; diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/accountList.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/accountList.js new file mode 100644 index 0000000..adcd873 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/accountList.js @@ -0,0 +1,66 @@ +import web3 from 'Embark/web3' +import React from 'react'; +import { connect } from 'react-redux'; +import { Nav, MenuItem, NavDropdown } from 'react-bootstrap'; +import Blockies from 'react-blockies'; +import { string, bool, func, arrayOf, shape } from 'prop-types'; +import { getAccounts, getDefaultAccount, accountsIsLoading, actions as accountActions } from '../reducers/accounts'; +import './accountlist.css'; + +const AccList = ({ + accounts, defaultAccount, changeAccount, isLoading, classNameNavDropdown, +}) => ( + + {!isLoading ? +
+
+ +
+
+ +
+
+ :
Loading...
} +
+); + +AccList.propTypes = { + accounts: arrayOf(shape({ address: string, balance: string })).isRequired, + defaultAccount: string, + changeAccount: func.isRequired, + isLoading: bool.isRequired, + classNameNavDropdown: string +} + +const mapStateToProps = state => ({ + accounts: getAccounts(state), + defaultAccount: getDefaultAccount(state), + isLoading: accountsIsLoading(state), +}); + +const mapDispatchToProps = dispatch => ({ + changeAccount(address) { + web3.eth.defaultAccount = address; + dispatch(accountActions.updateDefaultAccount(address)); + }, +}); + +export default connect(mapStateToProps, mapDispatchToProps)(AccList); diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/accountlist.css b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/accountlist.css new file mode 100644 index 0000000..35b9ddd --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/accountlist.css @@ -0,0 +1,37 @@ +.identicon { + border-radius: 50%; +} + +.selectedIdenticon { + border-radius: 50%; + overflow: hidden; + float: left; + margin: 7px 0; +} + +.accountHexString { + margin-left: 7px; + width: 267px; + overflow: hidden; + text-overflow: ellipsis; + display:inline-block; +} + +.accountBalance { + margin-left: 10px; + overflow: hidden; + display: inline-block; + width:77px; + text-align: center; + text-overflow: ellipsis; +} + +.accountList { + float: left; + margin-left: 10px; +} + +.account { + display: flex; + align-items: center; +} \ No newline at end of file diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/assets/ethereum-logo.svg b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/assets/ethereum-logo.svg new file mode 100644 index 0000000..8c93b16 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/assets/ethereum-logo.svg @@ -0,0 +1,36 @@ + + + + Group + Created with Sketch. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/assets/metamask-logo.svg b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/assets/metamask-logo.svg new file mode 100644 index 0000000..a6506e7 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/assets/metamask-logo.svg @@ -0,0 +1,11 @@ + + + diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/assets/mist-logo.svg b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/assets/mist-logo.svg new file mode 100644 index 0000000..71dbb86 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/assets/mist-logo.svg @@ -0,0 +1,18 @@ + + + + mist + Created with Sketch. + + + + + + + + + + + + + diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/ens/EditOptions.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/ens/EditOptions.js new file mode 100644 index 0000000..e5cddd6 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/ens/EditOptions.js @@ -0,0 +1,72 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { withStyles } from '@material-ui/core/styles'; +import Button from '@material-ui/core/Button'; +import List from '@material-ui/core/List'; +import ListItem from '@material-ui/core/ListItem'; +import ListItemIcon from '@material-ui/core/ListItemIcon'; +import ListItemText from '@material-ui/core/ListItemText'; +import DialogTitle from '@material-ui/core/DialogTitle'; +import Dialog from '@material-ui/core/Dialog'; +import PersonIcon from '@material-ui/icons/Person'; +import EditIcon from '@material-ui/icons/Edit'; +import DeleteOutline from '@material-ui/icons/Delete'; +import Typography from '@material-ui/core/Typography'; +import blue from '@material-ui/core/colors/blue'; + +const styles = { + paper: { + margin: 0, + maxWidth: '100%', + borderRadius: '6px 6px 0 0', + }, + list: { + width: '100%', + position: 'absolute', + bottom: 0, + margin: 0 + } +}; + +class SimpleDialog extends React.Component { + handleClose = () => { + this.props.onClose(this.props.selectedValue); + }; + + handleListItemClick = value => { + this.props.onClose(value); + }; + + render() { + const { classes, onClose, selectedValue, ...other } = this.props; + + return ( + + + this.handleListItemClick('edit')} key="edit"> + + + + + + this.handleListItemClick('release')}> + + + + + + + + ); + } +} + +SimpleDialog.propTypes = { + classes: PropTypes.object.isRequired, + onClose: PropTypes.func, + selectedValue: PropTypes.string, +}; + +const SimpleDialogWrapped = withStyles(styles)(SimpleDialog); +export default SimpleDialogWrapped; + diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/ens/ReleaseDomain.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/ens/ReleaseDomain.js new file mode 100644 index 0000000..50b71a2 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/ens/ReleaseDomain.js @@ -0,0 +1,69 @@ +import React from 'react'; +import { withStyles } from '@material-ui/core/styles'; +import Button from '@material-ui/core/Button'; +import Dialog from '@material-ui/core/Dialog'; +import DialogActions from '@material-ui/core/DialogActions'; +import DialogContent from '@material-ui/core/DialogContent'; +import DialogContentText from '@material-ui/core/DialogContentText'; +import DialogTitle from '@material-ui/core/DialogTitle'; +import Slide from '@material-ui/core/Slide'; +import classNames from "classnames"; + +function Transition(props) { + return ; +} + +const styles = theme => ({ + dialog: { + textAlign: 'center', + }, + actions: { + background: 'rgba(255, 255, 255, 0.8)', + margin: 0, + borderTop: 'solid 1px #ccc', + }, + button: { + margin: '0', + fontSize: '17px', + color: '#007AFF', + width: '50%', + borderRight: 'solid 1px #ccc', + borderRadius: 0, + padding: '15px', + } +}); + + +const ReleaseDomainAlert = ({ classes, open, handleClose }) => ( +
+ + + {"Release domain?"} + + + + Your SNT deposit will be returned and name will be available to other users. + + + + + + + +
+); + + +export default withStyles(styles)(ReleaseDomainAlert); \ No newline at end of file diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/ens/addDomain.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/ens/addDomain.js new file mode 100644 index 0000000..d256b29 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/ens/addDomain.js @@ -0,0 +1,92 @@ +import UsernameRegistrar from 'Embark/contracts/UsernameRegistrar'; +import web3 from 'web3'; +import ENSRegistry from 'Embark/contracts/ENSRegistry'; +import React from 'react'; +import { Button } from 'react-bootstrap'; +import FieldGroup from '../standard/FieldGroup'; +import { withFormik } from 'formik'; +import { hash } from 'eth-ens-namehash'; +import { debounce } from 'lodash/fp'; + +const { methods: { owner } } = ENSRegistry; + +const delay = debounce(500); +const getRegistry = (hashedRegistry, registrys) => registrys(hashedRegistry).call(); +const registryIsOwner = address => address == UsernameRegistrar._address; +const fetchOwner = registryName => owner(hash(registryName)).call(); +const debounceFetchOwner = delay(fetchOwner); +const getAndIsOwner = async registryName => { + const address = await debounceFetchOwner(registryName); + return registryIsOwner(address); +} +const fetchRegistry = delay(getRegistry); +const setPrice = (registryFn, price) => registryFn(price || 0).send(); + +const InnerForm = ({ + values, + errors, + touched, + handleChange, + handleBlur, + handleSubmit, + isSubmitting, +}) => ( +
+ + + + +) + +const AddRegistry = withFormik({ + mapPropsToValues: props => ({ registryName: '', registryPrice: '' }), + async validate(values) { + const { registryName } = values; + const errors = {}; + if (!registryName) errors.registryName = 'Required'; + if (registryName && !await getAndIsOwner(registryName)) errors.registryName = 'This registry is not owned by registry'; + if (Object.keys(errors).length) throw errors; + }, + async handleSubmit(values, { setSubmitting }) { + const { registryName, registryPrice } = values; + const { methods: { state, activate, updateRegistryPrice } } = UsernameRegistrar; + const { registryState } = await state(); + console.log( + 'Inputs for setPrice', + Number(registryState) ? 'updateRegistryPrice' : 'activate', + web3.utils.toWei(registryPrice.toString(), 'ether'), + ); + setPrice( + Number(registryState) ? updateRegistryPrice : activate, + web3.utils.toWei(registryPrice.toString(), 'ether'), + ) + .then(res => { + setSubmitting(false); + console.log(res); + }) + .catch(err => { + setSubmitting(false); + console.log(err); + }) + } +})(InnerForm); + +export default AddRegistry; diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/ens/copy.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/ens/copy.js new file mode 100644 index 0000000..bcd5a10 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/ens/copy.js @@ -0,0 +1,23 @@ +export default { + release: { + title: { + sub: 'Done!', + body: 'The released username will be available to other users' + }, + subheading: 'Follow the progress in the Transaction History section of your wallet.' + }, + registered: { + title: { + sub: 'Nice!', + body: 'The name is yours once the transaction is complete' + }, + subheading: 'Follow the progress in the Transaction History section of your wallet.' + }, + edit: { + title: { + sub: 'Done!', + body: 'Your changes will be saved when the transaction is complete' + }, + subheading: 'Follow the progress in the Transaction History section of your wallet.' + } +} diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/ens/moveDomain.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/ens/moveDomain.js new file mode 100644 index 0000000..b6bd7df --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/ens/moveDomain.js @@ -0,0 +1,61 @@ +import UsernameRegistrar from 'Embark/contracts/UsernameRegistrar'; +import web3 from 'web3'; +import React from 'react'; +import { Button } from 'react-bootstrap'; +import FieldGroup from '../standard/FieldGroup'; +import { withFormik } from 'formik'; + +const InnerForm = ({ + values, + errors, + handleChange, + handleBlur, + handleSubmit, + isSubmitting, +}) => ( +
+ + + +) + +const MoveDomain = withFormik({ + mapPropsToValues: props => ({ newAddress: '' }), + async validate(values) { + const { utils: { isAddress } } = web3; + const { newAddress } = values; + const errors = {}; + if (!isAddress(newAddress)) errors.newAddress = 'Please enter a valid address' + if (Object.keys(errors).length) throw errors; + }, + async handleSubmit(values, { setSubmitting }) { + const { newAddress } = values; + const { methods: { moveDomain } } = UsernameRegistrar; + console.log( + `inputs for moveDomain:}`, + newAddress + ); + + moveDomain(newAddress) + .send() + .then((res) => { + setSubmitting(false); + console.log(res); + }) + .catch((err) => { + setSubmitting(false); + console.log(err); + }) + } +})(InnerForm); + +export default MoveDomain; diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/ens/nameLookup.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/ens/nameLookup.js new file mode 100644 index 0000000..b2fdeec --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/ens/nameLookup.js @@ -0,0 +1,383 @@ +import React, { Fragment, PureComponent } from 'react'; +import web3 from 'web3'; +import EmbarkJS from 'Embark/EmbarkJS'; +import { connect } from 'react-redux'; +import { actions as accountActions, getDefaultAccount } from '../../reducers/accounts'; +import { hash } from 'eth-ens-namehash'; +import { isNil } from 'lodash'; +import Hidden from '@material-ui/core/Hidden'; +import Typography from '@material-ui/core/Typography'; +import UsernameRegistrar from 'Embark/contracts/UsernameRegistrar'; +import ENSRegistry from 'Embark/contracts/ENSRegistry'; +import { Button, Field, TextInput, MobileSearch, MobileButton, Card, Info, Text } from '../../ui/components' +import { IconCheck } from '../../ui/icons' +import { keyFromXY } from '../../utils/ecdsa'; +import EditOptions from './EditOptions'; +import ReleaseDomainAlert from './ReleaseDomain'; +import theme from '../../ui/theme' +import { withFormik } from 'formik'; +import PublicResolver from 'Embark/contracts/PublicResolver'; +import { CopyToClipboard } from 'react-copy-to-clipboard'; +import RegisterSubDomain from '../ens/registerSubDomain'; +import StatusLogo from '../../ui/icons/components/StatusLogo' +import EnsLogo from '../../ui/icons/logos/ens.png'; +import { formatPrice } from '../ens/utils'; +import CheckCircle from '../../ui/icons/components/baseline_check_circle_outline.png'; +import WarningIcon from '../../ui/icons/svg/warning.svg'; +const { getPrice, getReleaseTime, release } = UsernameRegistrar.methods; +import NotInterested from '@material-ui/icons/NotInterested'; +import Face from '@material-ui/icons/Face'; +import Copy from './copy'; +import IDNANormalizer from 'idna-normalize'; +import { nullAddress, getResolver } from './utils/domain'; + +const normalizer = new IDNANormalizer(); +const invalidSuffix = '0000000000000000000000000000000000000000' +const validAddress = address => address != nullAddress; +const validStatusAddress = address => !address.includes(invalidSuffix); +const formatName = domainName => domainName.includes('.') ? normalizer.normalize(domainName) : normalizer.normalize(`${domainName}.stateofus.eth`); +const getDomain = fullDomain => formatName(fullDomain).split('.').slice(1).join('.'); +const hashedDomain = domainName => hash(getDomain(domainName)); +const registryIsOwner = address => address == UsernameRegistrar._address; +const { soliditySha3, fromWei } = web3.utils; + + +const cardStyle = { + width: '100%', + padding: '30px', + height: '425px' +} + +const addressStyle = { + fontSize: '18px', + fontWeight: 400, + cursor: 'copy', + wordWrap: 'break-word', +} + +const backButton = { + fontSize: '40px', + color: theme.accent, + cursor: 'pointer' +} + +const validTimestamp = timestamp => Number(timestamp) > 99999999; +const generatePrettyDate = timestamp => new Date(timestamp * 1000).toDateString(); + +const DisplayBox = ({ displayType, pubKey }) => ( +
+
{displayType}
+
+
+ {pubKey} +
+
+
+); + +const MobileAddressDisplay = ({ domainName, address, statusAccount, releaseTime, defaultAccount, isOwner, edit, onSubmit, handleChange, values, handleSubmit }) => ( + + + + + {isOwner ? : } + {formatName(domainName)} +
+ {isOwner + ? edit ? 'Edit Contact Code' : 'You own this ENS name' + : 'unavailable'} + +
+
+
+ + Registered {validTimestamp(releaseTime)} + + + {edit + ? 'The contact code connects the domain with a unique Status account' + : validAddress(address) ? 'to the addresses below' : 'Click \'Edit\' to add a valid address and contact code'} + + {edit && } + {!edit && } + {!edit && validStatusAddress(statusAccount) && } +
+) + +class RenderAddresses extends PureComponent { + state = { copied: false, editMenu: false, editAction: false } + + render() { + const { domainName, address, statusAccount, releaseTime, defaultAccount, ownerAddress, setStatus, registryOwnsDomain } = this.props + const { copied, editMenu, editAction, submitted } = this.state + const markCopied = (v) => { this.setState({ copied: v }) } + const isCopied = address => address == copied; + const renderCopied = address => isCopied(address) && Copied!; + const onClose = value => { this.setState({ editAction: value, editMenu: false }) } + const onClickEdit = () => { validAddress(address) ? this.setState({ editMenu: true }) : this.setState({ editAction: 'edit' }) } + const isOwner = defaultAccount === ownerAddress; + const closeReleaseAlert = value => { + if (!isNil(value)) { + this.setState({ submitted: true }) + release( + soliditySha3(domainName) + ) + .send() + } else { + this.setState({ editAction: null }) + } + } + return ( + + +
+ {formatName(domainName)}{releaseTime && (Expires {generatePrettyDate(releaseTime)})} Resolves To: + {address && Ethereum Address {renderCopied(address)}} + +
{address}
+
+ {validStatusAddress(statusAccount) && Status Address {renderCopied(statusAccount)}} + {validStatusAddress(statusAccount) && +
{statusAccount}
+
} +
+
+ + {submitted ? : { this.setState({ submitted: true}) }}/>} + {isOwner && !editAction && } + + + +
+ ) + } +} + +const RegisterInfoCard = ({ formattedDomain, domainPrice, registryOwnsDomain }) => ( + + + + {formattedDomain.toLowerCase()} can be registered for {!!domainPrice && formatPrice(fromWei(domainPrice))} SNT + + + + + + + {formattedDomain.toLowerCase()} +
+ available +
+
+
+
+ + + {!!domainPrice && formatPrice(fromWei(domainPrice))} SNT to register + + + {registryOwnsDomain ? + 'Add your contact code to use your name in Status chat.' : + 'This domain is not owned by the registry'} + + +
+) + +const TransactionComplete = ({ type, setStatus }) => ( +
+ + {Copy[type]['title']['sub']}
+ {Copy[type]['title']['body']} +
+ + {Copy[type]['subheading']} + + { setStatus(null) } } /> +
+); + +class Register extends PureComponent { + state = { domainPrice: null }; + + componentDidMount() { + const { domainName } = this.props; + getPrice() + .call() + .then((res) => { this.setState({ domainPrice: res })}); + } + + onRegistered = (address, statusAccount) => { + const { domainPrice } = this.state; + const { subtractFromBalance } = this.props; + subtractFromBalance(domainPrice); + this.setState({ registered: { address, statusAccount } }); + } + + render() { + const { domainName, setStatus, style, registryOwnsDomain, ownerAddress, defaultAccount } = this.props; + const { domainPrice, registered, submitted } = this.state; + const formattedDomain = formatName(domainName); + const formattedDomainArray = formattedDomain.split('.'); + const isOwner = defaultAccount === ownerAddress; + return ( +
+ {!registered && !submitted ? + + + {registryOwnsDomain && + { this.setState({ submitted: true }) }} + registeredCallbackFn={this.onRegistered} />} + : + submitted && !registered ? : } +
+ ) + } +} + +const mapDispatchToProps = dispatch => ({ + subtractFromBalance(amount) { + dispatch(accountActions.subtractfromSntTokenBalance(amount)); + }, +}); + +const mapStateToProps = state => ({ + defaultAccount: getDefaultAccount(state) +}) + +const ConnectedRegister = connect(mapStateToProps, mapDispatchToProps)(Register); + +const DisplayAddress = connect(mapStateToProps)((props) => ( + + {validAddress(props.address) || props.defaultAccount === props.ownerAddress ? + + : + + + {props.domainName} + + + } + +)) + +const LookupForm = ({ handleSubmit, values, handleChange, justSearch }) => ( + +
+ + + + + + + + {!justSearch && +
+ + Names are made with
letters and numbers only +
+ } +
+ + + +
+
+) + +const InnerForm = ({ + values, + errors, + touched, + handleChange, + handleBlur, + handleSubmit, + isSubmitting, + status, + setStatus, + defaultAccount +}) => ( +
+ + + + Ens Logo + + + {!status + ? + : validAddress(status.address) || defaultAccount === status.ownerAddress ? + : +
+ + +
+ } +
+) + +const NameLookup = withFormik({ + mapPropsToValues: props => ({ domainName: '' }), + async handleSubmit(values, { status, setSubmitting, setStatus }) { + const { domainName } = values; + const { methods: { owner, resolver } } = ENSRegistry; + const lookupHash = hash(formatName(domainName)); + const resolverContract = await getResolver(lookupHash); + const { addr, pubkey } = resolverContract.methods; + const address = addr(lookupHash).call(); + const keys = pubkey(lookupHash).call(); + const ownerAddress = owner(lookupHash).call(); + const suffixOwner = owner(hash(getDomain(domainName))).call(); + const releaseTime = getReleaseTime(lookupHash).call(); + Promise.all([address, keys, ownerAddress, releaseTime, suffixOwner]) + .then(([ address, keys, ownerAddress, releaseTime, suffixOwner ]) => { + const statusAccount = keyFromXY(keys[0], keys[1]); + const registryOwnsDomain = registryIsOwner(suffixOwner) + const resolvedDomainName = domainName; + setStatus({ address, statusAccount, releaseTime, ownerAddress, registryOwnsDomain, resolvedDomainName }); + }) + } +})(InnerForm) + +export default connect(mapStateToProps)(NameLookup); diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/ens/registerSubDomain.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/ens/registerSubDomain.js new file mode 100644 index 0000000..f7ac411 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/ens/registerSubDomain.js @@ -0,0 +1,243 @@ +import web3 from "Embark/web3" +import UsernameRegistrar from 'Embark/contracts/UsernameRegistrar'; +import PublicResolver from 'Embark/contracts/PublicResolver'; +import TestToken from 'Embark/contracts/TestToken'; +import React from 'react'; +import { connect } from 'react-redux'; +import Hidden from '@material-ui/core/Hidden'; +import CircularProgress from '@material-ui/core/CircularProgress'; +import { Button, MobileSearch, MobileButton, Field } from '../../ui/components'; +import { withFormik } from 'formik'; +import { hash } from 'eth-ens-namehash'; +import { zeroAddress, zeroBytes32, formatPrice } from './utils'; +import { getStatusContactCode, getSNTAllowance, getCurrentAccount } from '../../reducers/accounts'; +import FieldGroup from '../standard/FieldGroup'; +import LinearProgress from '@material-ui/core/LinearProgress'; +import Typography from '@material-ui/core/Typography'; +import TokenPermissions from '../standard/TokenPermissionConnect'; +import Terms from './terms'; +import { generateXY } from '../../utils/ecdsa'; +import { getResolver } from './utils/domain'; + +const { soliditySha3, fromWei } = web3.utils; + + +const DisplayBox = ({ displayType, pubKey }) => ( +
+
{displayType}
+
+
+ {pubKey} +
+
+
+); + +const formRef = React.createRef(); +const displayTerms = status => status === 'terms'; +const InnerForm = ({ + values, + errors, + handleChange, + handleBlur, + handleSubmit, + isSubmitting, + setFieldValue, + subDomain, + domainName, + domainPrice, + editAccount, + setStatus, + status, + SNTAllowance, + SNTBalance, +}) => ( +
+
+ {!subDomain && + } + {!domainName && + { + UsernameRegistrar.methods.getPrice() + .call() + .then((res) => { setFieldValue('price', fromWei(res)); }); + }} + > + Get Price + + } + />} + {!domainPrice && + } + + + setFieldValue('address', web3.eth.defaultAccount)}>Use My Primary Address} + /> + {!isSubmitting ? : } + + + + + + + + {/*
Your contact code
*/} + {/*
*/} + {/*
*/} + {/* setFieldValue('statusAddress', '')} style={{ textAlign: 'center', padding: '30px 0', color: 'blue', cursor: 'pointer'}}>*/} + {/*Grant Access*/} + {/**/} + {/*
*/} + {/*
*/} + + {/**/} + {/* setFieldValue('address', '')}*/} + {/*required*/} + {/*wide />*/} + {/**/} + {/**/} + {/* setFieldValue('statusAddress', '')}*/} + {/*wide />*/} + {/**/} +
+ {!isSubmitting ? { setStatus('terms') }} text={`${editAccount ? 'Save' : 'Register'} with transaction`} style={{ width: '100%' }} /> : } + { setStatus(null); formRef.current.dispatchEvent(new Event('submit')) }} form={formRef} /> +
+
+
+
+); + +const RegisterSubDomain = withFormik({ + mapPropsToValues: props => ({ subDomain: '', domainName: '', price: '', statusAddress: props.statusContactCode || '', address: web3.eth.defaultAccount || '' }), + validate(values, props) { + const errors = {}; + const { address } = values; + const { subDomain } = props || values; + if (address && !web3.utils.isAddress(address)) errors.address = 'Not a valid address'; + if (!subDomain) errors.subDomain = 'Required'; + return errors; + }, + async handleSubmit(values, { setSubmitting, props }) { + const { editAccount, preRegisteredCallback } = props; + const { address, statusAddress } = values; + const { subDomain, domainName, domainPrice, registeredCallbackFn } = props || values; + const { methods: { register } } = UsernameRegistrar; + const { methods: { approveAndCall } } = TestToken; + const subdomainHash = soliditySha3(subDomain); + const domainNameHash = hash(domainName); + const resolveToAddr = address || zeroAddress; + const points = statusAddress ? generateXY(statusAddress) : null; + const node = hash(subDomain.includes('eth') ? subDomain : `${subDomain}.${domainName}`); + const { methods: { setAddr, setPubkey } } = await getResolver(node); + + const funcsToSend = []; + const args = [ + subdomainHash, + resolveToAddr, + points ? points.x : zeroBytes32, + points ? points.y : zeroBytes32, + ]; + if (editAccount) { + if (address !== web3.eth.defaultAccount) funcsToSend.push(setAddr(node, resolveToAddr)); + if (statusAddress && statusAddress !== props.statusContactCode) funcsToSend.push(setPubkey(node, args[3], args[4])); + } else { + funcsToSend.push( + approveAndCall(UsernameRegistrar.address, domainPrice, register(...args).encodeABI()) + ); + } + while (funcsToSend.length) { + const toSend = funcsToSend.pop(); + toSend.estimateGas().then((gasEstimated) => { + const gas = editAccount ? gasEstimated + 1000 : gasEstimated * 2; + console.log("Register would work. :D Gas estimated: " + gasEstimated, { gas }, gasEstimated + 1000); + console.log("Trying: register(\"" + subdomainHash + "\",\"" + domainNameHash + "\",\"" + resolveToAddr + "\",\"" + zeroBytes32 + "\",\"" + zeroBytes32 + "\")"); + if (preRegisteredCallback) preRegisteredCallback(); + toSend.send({ gas }).then((txId) => { + if (txId.status == "0x1" || txId.status == "0x01"){ + console.log("Register send success. :)"); + } else { + console.log("Register send errored. :( Out of gas? "); + } + console.dir(txId) + }).catch(err => { + console.log("Register send errored. :( Out of gas?"); + console.dir(err) + }).finally(() => { + // REQUIRED UNTIL THIS ISSUES IS RESOLVED: https://github.com/jaredpalmer/formik/issues/597 + setTimeout(() => { registeredCallbackFn(resolveToAddr, statusAddress || zeroBytes32); }, 200); + setSubmitting(false); + }); + }).catch(err => { + console.log("Register would error. :/ Already Registered? Have Token Balance? Is Allowance set?") + console.dir(err) + setSubmitting(false); + }); + } + } +})(InnerForm); + +const mapStateToProps = state => ({ + statusContactCode: getStatusContactCode(state), + SNTAllowance: getSNTAllowance(state), + SNTBalance: getCurrentAccount(state) && getCurrentAccount(state).SNTBalance, +}); + +export default connect(mapStateToProps)(RegisterSubDomain); diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/ens/setupENS.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/ens/setupENS.js new file mode 100644 index 0000000..8c160ca --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/ens/setupENS.js @@ -0,0 +1,28 @@ +import React, { Fragment } from 'react'; +import { Form, FormGroup, FormControl, HelpBlock, Button, ControlLabel } from 'react-bootstrap'; +import UsernameRegistrar from 'Embark/contracts/UsernameRegistrar'; +import web3Utils from 'web3-utils' +import { hash } from 'eth-ens-namehash' + +const zeroBytes32 = "0x0000000000000000000000000000000000000000000000000000000000000000"; +const getUserAddress = contract => contract._provider.publicConfigStore._state.selectedAddress; +const dispatchSetup = (ENSRegistry) => { + const { methods: { setSubnodeOwner } } = ENSRegistry; + const { sha3 } = web3Utils + setSubnodeOwner(zeroBytes32, sha3('eth'), getUserAddress(ENSRegistry)) + .send() + .then(res => { console.log(res) }) + setSubnodeOwner(hash('eth'), sha3('stateofus'), UsernameRegistrar._address) + .send() + .then(res => { console.log(res) }) + setSubnodeOwner(hash('eth'), sha3('stateofus'), UsernameRegistrar._address) + .send() + .then(res => { console.log(res) }) +} +const SetupEns = ({ ENSRegistry }) => ( + + + +) + +export default SetupEns; diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/ens/terms.css b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/ens/terms.css new file mode 100644 index 0000000..6a7dc8c --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/ens/terms.css @@ -0,0 +1,10 @@ +.ens-terms__title { + padding: 40px 24px; + background: #EEF2F5; + border-radius: 4px; + margin-bottom: 30px; +} + +.ens-terms li { + +} \ No newline at end of file diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/ens/terms.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/ens/terms.js new file mode 100644 index 0000000..153a21b --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/ens/terms.js @@ -0,0 +1,55 @@ +import React from 'react'; +import classNames from 'classnames'; +import { withStyles } from '@material-ui/core/styles'; +import Button from '@material-ui/core/Button'; +import Dialog from '@material-ui/core/Dialog'; + +import './terms.css'; + +const styles = theme => ({ + button: { + margin: theme.spacing.unit, + borderRadius: '4px', + backgroundColor: 'rgba(67, 96, 223, 0.1)', + } +}); + +const buttonText = { color: '#4360df', margin: '0 20px', fontWeight: 300 }; + + +const Terms = ({ classes, open, onSubmit }) => ( + +
+

Terms of name registration

+
    +
  • Funds are deposited for 1 year. Your SNT 
will be locked, but not spent.
  • +
  • After 1 year, you can release the name and get your deposit back, or take no action to keep the name.
  • +
  • If terms of the contract change — e.g. Status makes contract upgrades — user has the right to release the username regardless of time held.
  • +
  • The contract controller cannot access your deposited funds. They can only be moved back to the address that sent them.
  • +
  • Your address(es) will be publicly associated with your ENS name.
  • +
  • Usernames are created as subdomain nodes of stateofus.eth and are subject to the ENS smart contract terms.
  • +
  • You authorize the contract to transfer SNT on your behalf. This can only occur when you approve a transaction to authorize the transfer.
  • +
+ +

These terms are guaranteed by the smart contract logic at addresses:

+ +
    +
  • 0xb1C47B61CDaeee3fA85Fe8B93FcE6311165E6291 (ENSSubdomainRegistry — Status)
  • +
+ + +
    +
  • 0x112234455C3a32FD11230C42E7Bccd4A84e02010 (ENS).
  • +
+ + +
+
+); + +export default withStyles(styles)(Terms); diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/ens/updateController.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/ens/updateController.js new file mode 100644 index 0000000..8b6b6a5 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/ens/updateController.js @@ -0,0 +1,56 @@ +import UsernameRegistrar from 'Embark/contracts/UsernameRegistrar'; +import web3 from 'web3'; +import React from 'react'; +import { Button } from 'react-bootstrap'; +import FieldGroup from '../standard/FieldGroup'; +import { withFormik } from 'formik'; + +const InnerForm = ({ + values, + errors, + handleChange, + handleBlur, + handleSubmit, + isSubmitting, +}) => ( +
+ + + +) + +const UpdateController = withFormik({ + mapPropsToValues: props => ({ newAddress: '' }), + async validate(values) { + const { utils: { isAddress } } = web3; + const { newAddress } = values; + const errors = {}; + if (!isAddress(newAddress)) errors.newAddress = 'Please enter a valid address' + if (Object.keys(errors).length) throw errors; + }, + async handleSubmit(values, { setSubmitting }) { + const { newAddress } = values; + const { methods: { changeController } } = UsernameRegistrar; + changeController(newAddress) + .send() + .then((res) => { + setSubmitting(false); + console.log(res); + }) + .catch((err) => { + setSubmitting(false); + console.log(err); + }) + } +})(InnerForm); + +export default UpdateController; diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/ens/utils.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/ens/utils.js new file mode 100644 index 0000000..334c61c --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/ens/utils.js @@ -0,0 +1,3 @@ +export const zeroAddress = '0x0000000000000000000000000000000000000000'; +export const zeroBytes32 = "0x0000000000000000000000000000000000000000000000000000000000000000"; +export const formatPrice = price => price.includes('.') ? price : Number(price).toLocaleString(); diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/ens/utils/domain.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/ens/utils/domain.js new file mode 100644 index 0000000..d840317 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/ens/utils/domain.js @@ -0,0 +1,14 @@ +import EmbarkJS from 'Embark/EmbarkJS'; +import web3 from "Embark/web3"; +import ENSRegistry from 'Embark/contracts/ENSRegistry'; +import PublicResolver from 'Embark/contracts/PublicResolver'; + +const { methods: { owner, resolver } } = ENSRegistry; + +export const nullAddress = '0x0000000000000000000000000000000000000000'; +export const getResolver = async node => { + const resolverAddress = await resolver(node).call(); + return resolverAddress !== nullAddress + ? new EmbarkJS.Blockchain.Contract({ abi: PublicResolver._jsonInterface, address: resolverAddress, web3 }) + : PublicResolver +} diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/ens/welcome.css b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/ens/welcome.css new file mode 100644 index 0000000..529f77d --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/ens/welcome.css @@ -0,0 +1,90 @@ +.ens-welcome { + margin: 16px; + text-align: center; +} + +.ens-welcome__img { + margin: 20px 0 50px; +} + +.ens-welcome__title { + font-weight: bold; + font-size: 1.375rem; + line-height: 1.75rem; +} + +.ens-welcome__guide { + color: #adb5bd; + margin: 20px 0 30px; +} + +.ens-welcome__guide span { + position: relative; +} + +.ens-welcome__guide span:after, .ens-welcome__guide span:before { + content: ''; + border-bottom: solid 6px transparent; + display: block; + position: absolute; + border-top: solid 6px #fff; + border-left: solid 6px transparent; + border-right: solid 6px transparent; + top: 5px; + right: -20px; +} + +.ens-welcome__guide span:before { + border-top: solid 6px #adb5bd; + top: 7px; +} + +.ens-welcome__list { + margin-top: 20px; + counter-reset: ens-counter; + list-style: none; + text-align: left; + padding-left: 0; +} + +.ens-welcome__list li { + margin: 0 0 1rem 0; + padding-left: 80px; + counter-increment: ens-counter; + position: relative; + min-height: 60px; +} + +.ens-welcome__list li:before { + content: counter(ens-counter); + color: #4360DF; + font-size: 1.5rem; + font-weight: bold; + position: absolute; + left: 0; + line-height: 60px; + width: 60px; + height: 57px; + top: 0; + border-radius: 50%; + border: solid 3px #ECEFFC; + text-align: center; +} + +.ens-welcome__list .title { + font-weight: 500; + margin-bottom: 5px; +} + +.ens-welcome__list .text { + color: #adb5bd; + line-height: 1.313rem; +} + +.ens-welcome__info { + border-top: solid 1px #ccc; + border-bottom: solid 1px #ccc; + margin: 30px 0 20px; + padding: 15px 0; + text-align: center; +} diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/ens/welcome.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/ens/welcome.js new file mode 100644 index 0000000..5cee02b --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/ens/welcome.js @@ -0,0 +1,55 @@ +import React from 'react'; +import classNames from 'classnames'; +import { withStyles } from '@material-ui/core/styles'; +import Button from '@material-ui/core/Button'; +import StatusCards from '../../ui/icons/svg/intro_name.svg'; + +import './welcome.css'; + +const styles = theme => ({ + button: { + margin: theme.spacing.unit, + borderRadius: '4px', + backgroundColor: 'rgba(67, 96, 223, 0.1)', + } +}); + +const buttonText = { color: '#4360df', margin: '0 20px', fontWeight: 300 }; + +const WelcomeContent = () => ( +
+
How it works
+ +
    +
  1. +
    Simplify your ETH address
    +
    Your complex wallet address (0x...) becomes an easy to read, remember & share URL: myname.stateofus.eth
    +
  2. +
  3. +
    100 SNT to register
    +
    Register once to keep the name forever. After 1 year, you can release the name and get your SNT back.
    +
  4. +
  5. +
    Connect & get paid
    +
    Share your name to chat on Status or receive ETH and tokens.
    +
  6. +
+
Already have a Status subdomain? Manage it
+
Powered by Ethereum Name Services
+
+); + +const Welcome = ({ classes, toggleSearch }) => ( +
+ +

+ ENS names transform those crazy-long addresses into unique usernames +

+ + +
+); + +export default withStyles(styles)(Welcome); diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/ensSubManagement.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/ensSubManagement.js new file mode 100644 index 0000000..a91b524 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/ensSubManagement.js @@ -0,0 +1,44 @@ +import EmbarkJS from 'Embark/EmbarkJS'; +import ENSRegistry from 'Embark/contracts/ENSRegistry'; +import UsernameRegistrar from 'Embark/contracts/UsernameRegistrar'; +import TestToken from 'Embark/contracts/TestToken'; +import React, { Fragment } from 'react'; +import { Form, FormGroup, FormControl, HelpBlock, Button, ControlLabel } from 'react-bootstrap'; +import AddDomain from './ens/addDomain'; +import MoveDomain from './ens/moveDomain'; +import RegisterSubDomain from './ens/registerSubDomain'; +import TokenPermissions from './standard/TokenPermission'; +import SetupENS from './ens/setupENS'; +import UpdateController from './ens/updateController'; + +const FieldGroup = ({ id, label, help, ...props }) => ( + + {label} + + {help && {help}} + +) + +const ENSSubManagement = props => ( + +

Subdomain Management

+

Change Registry Controller

+ +

Activate Registry/Update Registry Price

+ +

Move Domain To Another Registry

+ +
+

Register Sub-Domain

+ +
+ +
+ +
+) + +export default ENSSubManagement; diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/erc20token.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/erc20token.js new file mode 100644 index 0000000..5753ebb --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/erc20token.js @@ -0,0 +1,132 @@ +import EmbarkJS from 'Embark/EmbarkJS'; +import ERC20Token from 'Embark/contracts/ERC20Token'; +import React from 'react'; +import { connect } from 'react-redux'; +import { Form, FormGroup, FormControl, HelpBlock, Button } from 'react-bootstrap'; +import { getCurrentAccount, accountsIsLoading } from '../reducers/accounts'; + +class ERC20TokenUI extends React.Component { + + constructor(props) { + super(props); + ERC20Token.options.address = props.address; + this.state = { + balanceOf: 0, + transferTo: "", + transferAmount: 0, + accountBalance: 0, + accountB: web3.eth.defaultAccount, + } + } + + update_transferTo(e){ + this.setState({transferTo: e.target.value}); + } + + update_transferAmount(e){ + this.setState({transferAmount: e.target.value}); + } + + transfer(e){ + var to = this.state.transferTo; + var amount = this.state.transferAmount; + var tx = ERC20Token.methods.transfer(to, amount).send({from: web3.eth.defaultAccount}); + this._addToLog(ERC20Token.options.address+".transfer(" + to + ", "+amount+")"); + } + + approve(e){ + var to = this.state.transferTo; + var amount = this.state.transferAmount; + var tx = ERC20Token.methods.approve(to, amount).send({from: web3.eth.defaultAccount}); + this._addToLog(ERC20Token.options.address+".approve(" + to + ", "+amount+")"); + } + + balanceOf(e){ + e.preventDefault(); + var who = e.target.value; + if (EmbarkJS.isNewWeb3()) { + ERC20Token.methods.balanceOf(who).call() + .then(_value => this.setState({balanceOf: _value})) + } else { + ERC20Token.balanceOf(who) + .then(_value => this.x({balanceOf: _value})); + } + this._addToLog(ERC20Token.options.address+".balanceOf(" + who + ")"); + } + + getDefaultAccountBalance(){ + if (EmbarkJS.isNewWeb3()) { + ERC20Token.methods.balanceOf(web3.eth.defaultAccount).call() + .then(_value => this.setState({accountBalance: _value})) + } else { + ERC20Token.balanceOf(web3.eth.defaultAccount) + .then(_value => this.x({valueGet: _value})) + } + this._addToLog(ERC20Token.options.address + ".balanceOf(" + web3.eth.defaultAccount + ")"); + } + + _addToLog(txt){ + console.log(txt); + } + + render() { + const { account, isLoading } = this.props; + return ( + +

Read your account token balance

+
+ + {!isLoading && Your test token balance is {account.SNTBalance}} + +
+ +

Read account token balance

+
+ + + + + +
+ +

Transfer/Approve token balance

+
+ + + + + + +
+ +
+ ); + } + } + +const mapStateToProps = state => ({ + account: getCurrentAccount(state), + isLoading: accountsIsLoading(state), +}); + +export default connect(mapStateToProps)(ERC20TokenUI); diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/standard/FieldGroup.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/standard/FieldGroup.js new file mode 100644 index 0000000..adf6b3a --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/standard/FieldGroup.js @@ -0,0 +1,46 @@ +import React from 'react'; +import styled from 'styled-components'; +import { FormGroup, FormControl, HelpBlock, InputGroup } from 'react-bootstrap'; +import { Field } from '../../ui/components'; +import theme from '../../ui/theme'; +import { font } from '../../ui/utils/styles/font'; + +const StyledFormControl = styled(FormControl)` + ${font({ size: 'small', weight: 'normal' })}; + width: ${({ wide }) => (wide ? '100%' : 'auto')}; + + padding: 5px 10px; + background: ${theme.contentBackground}; + border: 1px solid ${theme.contentBorder}; + border-radius: 3px; + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.06); + color: ${theme.textPrimary}; + appearance: none; + &:focus { + outline: none; + border-color: ${theme.contentBorderActive}; + } + &:read-only { + color: transparent; + text-shadow: 0 0 0 ${theme.textSecondary}; + } +`; + +const FieldGroup = ({ id, label, button, error, ...props }) => ( + + + {button ? + + + {button} + + + + : + } + {error && {error}} + + +); + +export default FieldGroup; diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/standard/NoConnection.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/standard/NoConnection.js new file mode 100644 index 0000000..50c65b5 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/standard/NoConnection.js @@ -0,0 +1,96 @@ +import React from 'react'; +import styles from './style.js'; +import EthereumLogo from './../assets/ethereum-logo.svg'; +import MetamaskLogo from './../assets/metamask-logo.svg'; + +function capitalize(string) { + return string.charAt(0).toUpperCase() + string.slice(1); +} + +const NoConnection = ({ network }) => console.log(network) || ( +
+ Status +
+ Ethereum +

NOT CONNECTED TO ETHEREUM {network.toUpperCase()}

+

+ This application requires an Ethereum client to be running and connected to {capitalize(network)}. A client + could not be detected which probably means it's not + installed, running or is misconfigured. +

+

+ Please use one of the following clients to connect to Ethereum: +

+
+
+ Metamask +

METAMASK

+

+ + 1 + Install + + {" "} + Metamask + +

+

+ + 2 + Use Chrome to browse + + {" "} + https://vote.status.im + +

+
+
+ Mist +

MIST

+

+ + 1 + Install and run + + {" "} + Mist + +

+

+ + 2 + + Use Mist to browse + + {" "} + https://vote.status.im + +

+
+
+
+); + +NoConnection.displayName = 'NoConnection'; + +export default NoConnection; diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/standard/StatusOptimized.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/standard/StatusOptimized.js new file mode 100644 index 0000000..61735af --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/standard/StatusOptimized.js @@ -0,0 +1,53 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { withStyles } from '@material-ui/core/styles'; +import AppBar from '@material-ui/core/AppBar'; +import Toolbar from '@material-ui/core/Toolbar'; +import Typography from '@material-ui/core/Typography'; +import IconButton from '@material-ui/core/IconButton'; +import IPhone from '@material-ui/icons/PhoneIphone'; +import Android from '@material-ui/icons/Android'; + +const styles = { + root: { + flexGrow: 1, + position: 'fixed', + top: 0, + width: '100%', + zIndex: 1, + }, + flex: { + flexGrow: 1, + }, + menuButton: { + marginLeft: -12, + marginRight: 20, + }, +}; + +function ButtonAppBar(props) { + const { classes } = props; + return ( +
+ + + + This site is optimized for Status. Get the App to enable all features and get the best experience. + + + + + + + + + +
+ ); +} + +ButtonAppBar.propTypes = { + classes: PropTypes.object.isRequired, +}; + +export default withStyles(styles)(ButtonAppBar); diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/standard/TokenPermission.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/standard/TokenPermission.js new file mode 100644 index 0000000..941248e --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/standard/TokenPermission.js @@ -0,0 +1,103 @@ +import React, { Fragment, PureComponent } from 'react'; +import { connect } from 'react-redux'; +import web3 from "Embark/web3" +import Toggle from 'react-toggle'; +import { BigNumber } from './utils' +import "react-toggle/style.css"; +import CircularProgress from '@material-ui/core/CircularProgress'; +import Tooltip from '@material-ui/core/Tooltip'; +import FormLabel from '@material-ui/core/FormLabel'; +import FormControl from '@material-ui/core/FormControl'; +import FormGroup from '@material-ui/core/FormGroup'; +import FormControlLabel from '@material-ui/core/FormControlLabel'; +import FormHelperText from '@material-ui/core/FormHelperText'; +import Switch from '@material-ui/core/Switch'; +import { actions, getSNTAllowance } from '../../reducers/accounts'; + +// We set an allowance to be "unlimited" by setting it to +// it's maximum possible value -- namely, 2^256 - 1. +const { fromWei } = web3.utils; +const unlimitedAllowance = new BigNumber(2).pow(256).sub(1); +const getDefaultAccount = () => web3.eth.defaultAccount; +const SUPPORTED_TOKENS = ['SNT', 'STT']; +const BALANCE_KEYS = { 'SNT': 'SNTBalance', 'STT': 'SNTBalance' }; + +class TokenHandle extends PureComponent { + constructor(props){ + super(props); + this.state = {}; + } + + toggleApproved = () => { + const { approved } = this.state; + const { methods: { approve }, spender, receiveSntAllowance } = this.props; + const isApproved = !!Number(approved); + let amountToApprove = isApproved ? 0 : unlimitedAllowance; + console.log("approve(\""+spender+"\",\"" +amountToApprove +"\")") + this.setState({ updating: true }); + approve( + spender, + amountToApprove + ) + .send() + .then(approval => { + const { events: { Approval: { returnValues: { _value } } } } = approval + receiveSntAllowance(_value) + this.setState({ ...this.state, updating: false }) + }).catch(err => { + console.log("Approve failed: " + err); + this.setState({ updating: false }); + }) + } + + render() { + const { symbol, account, isLoading, mobile, SNTAllowance } = this.props; + const { updating } = this.state; + return ( + + {!updating && !isLoading && !!account &&
+ + Token Permissions + + + } + label={`${Number(fromWei(account[BALANCE_KEYS[symbol]])).toLocaleString()} ${symbol}`} + /> + + Registry needs permission to transfer SNT from your account prior to registration + +
} + {isLoading || updating && } +
+ ) + } +} + +const TokenPermissions = (props) => ( + + {!props.mobile && + +

Token Permissions

+
+
+
} + +
+) + +const mapDispatchToProps = dispatch => ({ + receiveSntAllowance(amount) { + dispatch(actions.receiveSntAllowance(amount)); + }, +}); + +const mapStateToProps = state => ({ + SNTAllowance: getSNTAllowance(state), +}); +export default connect(mapStateToProps, mapDispatchToProps)(TokenPermissions); diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/standard/TokenPermissionConnect.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/standard/TokenPermissionConnect.js new file mode 100644 index 0000000..859d54c --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/standard/TokenPermissionConnect.js @@ -0,0 +1,9 @@ +import { connect } from 'react-redux'; +import TokenPermissions from './TokenPermission'; +import { getCurrentAccount, accountsIsLoading } from '../../reducers/accounts'; + +const mapStateToProps = state => ({ + account: getCurrentAccount(state), + isLoading: accountsIsLoading(state), +}); +export default connect(mapStateToProps)(TokenPermissions); diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/standard/Web3Render.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/standard/Web3Render.js new file mode 100644 index 0000000..a3c9c22 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/standard/Web3Render.js @@ -0,0 +1,10 @@ +import React, { Fragment } from 'react'; +import NoConnection from './NoConnection'; + +const Web3Render = ({ ready, children, network }) => ( + + {ready ? {children} : } + +); + +export default Web3Render; diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/standard/style.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/standard/style.js new file mode 100644 index 0000000..c730626 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/standard/style.js @@ -0,0 +1,68 @@ +export default { + NoEthereumSection: { + maxWidth: '980px', + margin: '0 auto', + textAlign: 'center', + fontSize: '24px' + }, + ImgHeaderLogo: { + width: '264px', + paddingBottom: '30px' + }, + ImgEthereumLogo: { + width: '61px', + paddingTop: '30px', + marginBottom: '40px' + }, + PNotFound: { + opacity: 0.50, + display: 'inline-block', + letterSpacing: '0.6px', + margin: 10 + }, + PUseClients: { + display: 'inline-block', + color: '#546979', + fontWeight: 700 + }, + DivClients: { + height: '360px', + display: 'flex', + justifyContent: 'center', + fontSize: '21px', + marginBottom: '50px', + marginTop: '50px' + }, + ImgLogo: { + width: '85px' + }, + AlignNumber: { + display: 'table-cell', + verticalAlign: 'middle', + paddingRight: '20px' + }, + NumberCircle: { + display: 'inline-block', + borderRadius: '50%', + height: '28px', + width: '28px', + lineHeight: '28px', + textAlign: 'center', + border: 'solid 1px #CFD8DC', + fontSize: '18px', + color: '#222228', + opacity: 0.68 + }, + DivSubClients: { + backgroundColor: 'white', + width: '340px', + height: '360px', + padding: '33px 10px 33px 27px', + opacity: 0.89, + border: '2px solid #EFF1F3', + boxShadow: '0px 2px 6px 0px rgba(0, 0, 0, 0.13)', + borderRadius: '4px', + margin: '0 20px' + } + +} diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/standard/utils.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/standard/utils.js new file mode 100644 index 0000000..0541bc4 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/standard/utils.js @@ -0,0 +1,9 @@ +import BigNumber from 'bignumber.js'; + +// By default BigNumber's `toString` method converts to exponential notation if the value has +// more then 20 digits. We want to avoid this behavior, so we set EXPONENTIAL_AT to a high number +BigNumber.config({ + EXPONENTIAL_AT: 1000, +}); + +export { BigNumber }; diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/testtoken.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/testtoken.js new file mode 100644 index 0000000..7c02bbd --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/testtoken.js @@ -0,0 +1,64 @@ +import EmbarkJS from 'Embark/EmbarkJS'; +import TestToken from 'Embark/contracts/TestToken'; +import React from 'react'; +import { Form, FormGroup, FormControl, HelpBlock, Button } from 'react-bootstrap'; +import ERC20TokenUI from './erc20token'; +import { connect } from 'react-redux'; +import { actions as accountActions } from '../reducers/accounts'; + +class TestTokenUI extends React.Component { + + constructor(props) { + super(props); + this.state = { + amountToMint: 100, + } + } + + handleMintAmountChange(e){ + this.setState({amountToMint: e.target.value}); + } + + mint(e){ + const { addToBalance } = this.props; + e.preventDefault(); + + var value = parseInt(this.state.amountToMint, 10); + + if (EmbarkJS.isNewWeb3()) { + TestToken.methods.mint(value).send({from: web3.eth.defaultAccount}) + .then(r => { addToBalance(value) }); + } else { + TestToken.mint(value).send({from: web3.eth.defaultAccount}) + .then(r => { addToBalance(value) }); + } + console.log(TestToken.options.address +".mint("+value+").send({from: " + web3.eth.defaultAccount + "})"); + } + + render(){ + return ( +

Mint Test Token

+
+ + this.handleMintAmountChange(e)} /> + + +
+ + + +
+ ); + } + } + +const mapDispatchToProps = dispatch => ({ + addToBalance(amount) { + dispatch(accountActions.addToSntTokenBalance(amount)); + }, +}); + +export default connect(null, mapDispatchToProps)(TestTokenUI); diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/topnavbar.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/topnavbar.js new file mode 100644 index 0000000..d8bc689 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/components/topnavbar.js @@ -0,0 +1,33 @@ +import EmbarkJS from 'Embark/EmbarkJS'; +import React from 'react'; +import { Navbar, NavItem, Nav, MenuItem , NavDropdown} from 'react-bootstrap'; +import AccountList from './accountList'; + +class TopNavbar extends React.Component { + + constructor(props) { + super(props); + this.state = { + + } + + } + + render(){ + + return ( + + + + + Status.im Demo + + + + + + ); + } + } + + export default TopNavbar; \ No newline at end of file diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/dapp.css b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/dapp.css new file mode 100644 index 0000000..e6ff7fe --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/dapp.css @@ -0,0 +1,64 @@ +body { + font-family: 'Roboto', sans-serif; + margin: 0; +} + +.accounts { + float: right; + margin-right: 17px; + font-family: monospace; +} + +.identicon { + border-radius: 50%; +} + + +.logs { + background-color: black; + font-size: 14px; + color: white; + font-weight: bold; + padding: 10px; + border-radius: 8px; +} + +.tab-content { + border-left: 1px solid #ddd; + border-right: 1px solid #ddd; + border-bottom: 1px solid #ddd; + padding: 10px; + margin: 0px; +} + +.nav-tabs { + margin-bottom: 0; +} + +.status-offline { + vertical-align: middle; + margin-left: 5px; + margin-top: 4px; + width: 12px; + height: 12px; + background: red; + -moz-border-radius: 10px; + -webkit-border-radius: 10px; + border-radius: 10px; +} + +.status-online { + vertical-align: middle; + margin-left: 5px; + margin-top: 4px; + width: 12px; + height: 12px; + background: mediumseagreen; + -moz-border-radius: 10px; + -webkit-border-radius: 10px; + border-radius: 10px; +} + +input.form-control { + margin: 5px; +} \ No newline at end of file diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/dapp.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/dapp.js new file mode 100644 index 0000000..38dcae5 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/dapp.js @@ -0,0 +1,90 @@ +import React, { Fragment } from 'react'; +import ReactDOM from 'react-dom'; +import 'typeface-roboto' +import CssBaseline from '@material-ui/core/CssBaseline'; +import { Tabs, Tab } from 'react-bootstrap'; +import Toggle from 'react-toggle'; +import EmbarkJS from 'Embark/EmbarkJS'; +import TopNavbar from './components/topnavbar'; +import TestTokenUI from './components/testtoken'; +import ERC20TokenUI from './components/erc20token'; +import TestToken from 'Embark/contracts/TestToken'; +import ENSSubManagement from './components/ensSubManagement'; +import UsernameRegistrar from 'Embark/contracts/UsernameRegistrar'; +import NameLookup from './components/ens/nameLookup'; +import AdminMode from './components/AdminMode'; +import TokenPermissions from './components/standard/TokenPermissionConnect'; +import web3 from "Embark/web3"; +import Paper from '@material-ui/core/Paper'; +import Typography from '@material-ui/core/Typography'; +import Welcome from './components/ens/welcome'; +import Fade from '@material-ui/core/Fade'; +import Hidden from '@material-ui/core/Hidden'; +import Web3Render from './components/standard/Web3Render'; +import StatusOptimized from './components/standard/StatusOptimized'; + +import './dapp.css'; + +const { getNetworkType } = web3.eth.net; + +const symbols = { + 'ropsten': 'STT', + 'private': 'SNT', + 'main': 'SNT' +} + +class App extends React.Component { + constructor(props) { + super(props) + } + state = { admin: false, searching: false }; + + componentDidMount(){ + EmbarkJS.onReady((err) => { + getNetworkType().then(network => { this.setState({ network })}); + }); + } + + render() { + const { admin, network, searching } = this.state; + const toggleSearch = () => { this.setState({ searching: !searching }) }; + const isRopsten = network === 'ropsten'; + const isMainnet = network === 'main'; + return ( +
+ + + +
+ +
+ {!searching && +
+ +
+
} + {searching && + +
+ + +
+ +
+ { this.setState({ admin: !admin })}} /> +
+ Admin Mode +
+
+
+
+
} +
+ ); + } +} + +export default App; diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/index.html b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/index.html new file mode 100644 index 0000000..40ae63e --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/index.html @@ -0,0 +1,11 @@ + + + Status.im Domain Registration + + + +
+
+ + + diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/index.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/index.js new file mode 100644 index 0000000..71ad7c2 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/index.js @@ -0,0 +1,16 @@ +import React from 'react'; +import { render } from 'react-dom'; +import { Provider } from 'react-redux'; +import store from './store/configureStore'; +import App from './dapp'; +import init from './store/init' +import './dapp.css'; + +init(); + +render( + + + , + document.getElementById('app') +); diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/reducers/accounts.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/reducers/accounts.js new file mode 100644 index 0000000..6b2d0da --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/reducers/accounts.js @@ -0,0 +1,81 @@ +import { createTypes, actionCreator } from 'redux-action-creator' +import { createSelector } from 'reselect' + +export const types = createTypes([ + 'RECEIVE_ACCOUNTS', + 'UPDATE_DEFAULT_ACCOUNT', + 'ADD_TO_SNT_TOKEN_BALANCE', + 'SUBTRACT_FROM_SNT_TOKEN_BALANCE', + 'RECEIVE_STATUS_CONTACT_CODE', + 'RECEIVE_SNT_ALLOWANCE' +], 'ACCOUNTS') +export const actions = { + receiveAccounts: actionCreator(types.RECEIVE_ACCOUNTS, 'defaultAccount','accounts'), + updateDefaultAccount: actionCreator(types.UPDATE_DEFAULT_ACCOUNT, 'defaultAccount'), + addToSntTokenBalance: actionCreator(types.ADD_TO_SNT_TOKEN_BALANCE, 'amount'), + subtractfromSntTokenBalance: actionCreator(types.SUBTRACT_FROM_SNT_TOKEN_BALANCE, 'amount'), + receiveStatusContactCode: actionCreator(types.RECEIVE_STATUS_CONTACT_CODE, 'statusContactCode'), + receiveSntAllowance: actionCreator(types.RECEIVE_SNT_ALLOWANCE, 'SNTAllowance') +} + +export default function(state = { loading: true, accounts: [] }, action) { + switch (action.type) { + case types.RECEIVE_ACCOUNTS: { + const { defaultAccount, accounts } = action.payload + return { + ...state, + loading: false, + defaultAccount, + accounts + } + } + case types.UPDATE_DEFAULT_ACCOUNT: { + const { defaultAccount } = action.payload + return { ...state, defaultAccount } + } + case types.ADD_TO_SNT_TOKEN_BALANCE: { + const currentAccount = { ...getCurrentAccount({accounts: state}) } + currentAccount.SNTBalance = Number(currentAccount.SNTBalance) + Number(action.payload.amount) + const accounts = [ ...state.accounts ] + const idx = accounts.findIndex(a => a.address === currentAccount.address) + accounts[idx] = currentAccount + return { + ...state, + accounts + } + } + case types.SUBTRACT_FROM_SNT_TOKEN_BALANCE: { + const currentAccount = { ...getCurrentAccount({accounts: state}) } + currentAccount.SNTBalance = Number(currentAccount.SNTBalance) - Number(action.payload.amount) + const accounts = [ ...state.accounts ] + const idx = accounts.findIndex(a => a.address === currentAccount.address) + accounts[idx] = currentAccount + return { + ...state, + accounts + } + } + case types.RECEIVE_STATUS_CONTACT_CODE: { + const { statusContactCode } = action.payload + return { ...state, statusContactCode } + } + case types.RECEIVE_SNT_ALLOWANCE: { + const { SNTAllowance } = action.payload + return { ...state, SNTAllowance } + } + default: + return state; + } +} + +export const getAccountState = state => state.acounts; +export const getAccounts = state => state.accounts.accounts; +export const getDefaultAccount = state => state.accounts.defaultAccount; +export const accountsIsLoading = state => state.accounts.loading; +export const getStatusContactCode = state => state.accounts.statusContactCode; +export const getSNTAllowance = state => state.accounts.SNTAllowance; +export const getCurrentAccount = createSelector( + getDefaultAccount, + getAccounts, + (defaultAccount, accounts) => accounts.find(a => a.address === defaultAccount) +) diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/reducers/rootReducer.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/reducers/rootReducer.js new file mode 100644 index 0000000..244ee3e --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/reducers/rootReducer.js @@ -0,0 +1,8 @@ +import { combineReducers } from 'redux'; +import accounts from './accounts' + +const rootReducer = combineReducers({ + accounts +}); + +export default rootReducer; diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/store/configureStore.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/store/configureStore.js new file mode 100644 index 0000000..d5ee806 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/store/configureStore.js @@ -0,0 +1,11 @@ +import { createStore, applyMiddleware } from 'redux'; +import rootReducer from '../reducers/rootReducer'; +import thunk from 'redux-thunk'; + +const store = createStore( + rootReducer, + window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__(), + applyMiddleware(thunk) +); + +export default store; diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/store/init.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/store/init.js new file mode 100644 index 0000000..2c9edee --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/store/init.js @@ -0,0 +1,14 @@ +import web3 from "Embark/web3" +import EmbarkJS from 'Embark/EmbarkJS' +import store from './configureStore' +import { fetchAndDispatchSNTAllowance, fetchAndDispatchAccountsWithBalances, checkAndDispatchStatusContactCode } from '../actions/accounts' + +const dispatch = action => store.dispatch(action) + +export default () => { + EmbarkJS.onReady(async (err) => { + fetchAndDispatchAccountsWithBalances(web3, dispatch) + checkAndDispatchStatusContactCode(dispatch) + fetchAndDispatchSNTAllowance(dispatch) + }) +} diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/components/Button/Button.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/components/Button/Button.js new file mode 100644 index 0000000..b475d5b --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/components/Button/Button.js @@ -0,0 +1,221 @@ +import styled, { css } from 'styled-components' +import SafeLink from '../SafeLink' +import theme from '../../theme' +import { font, unselectable } from '../../utils/styles' +import PublicUrl, { styledUrl } from '../../providers/PublicUrl' +import cross from './assets/cross.svg' +import check from './assets/check.svg' +import crossWhite from './assets/cross-white.svg' +import checkWhite from './assets/check-white.svg' + +const { + gradientStart, + gradientEnd, + gradientStartActive, + gradientEndActive, + gradientText, + contentBackground, + contentBorder, + contentBorderActive, + secondaryBackground, + textPrimary, + textSecondary, + disabled: disabledColor, + disabledText, +} = theme + +// Plain button = normal or strong +const plainButtonStyles = css` + position: relative; + overflow: hidden; + box-shadow: 0 1px 1px rgba(0, 0, 0, 0); + &:after { + content: ''; + opacity: 0; + position: absolute; + z-index: -1; + top: 0; + left: 0; + right: 0; + bottom: 0; + } + + ${({ disabled }) => + disabled + ? '' + : css` + &:hover, + &:focus { + box-shadow: ${({ disabled }) => + disabled ? 'none' : '0 1px 1px rgba(0, 0, 0, 0.2)'}; + } + &:active { + transform: translateY(1px); + box-shadow: 0 1px 1px rgba(0, 0, 0, 0); + &:after { + opacity: 1; + } + } + `}; +` + +const modeNormal = css` + ${plainButtonStyles}; + &:active { + color: ${textPrimary}; + } +` + +const modeSecondary = css` + ${plainButtonStyles}; + background: ${secondaryBackground}; + &:hover, + &:focus { + box-shadow: none; + } +` + +const modeStrong = css` + ${plainButtonStyles}; + ${font({ size: 'small', weight: 'bold' })}; + + ${({ disabled }) => + disabled + ? css` + color: ${disabledText}; + background-color: ${disabledColor}; + background-image: none; + ` + : css` + color: ${gradientText}; + background-color: transparent; + background-image: linear-gradient( + 130deg, + ${gradientStart}, + ${gradientEnd} + )}; + + &:after { + background-image: linear-gradient( + 130deg, + ${gradientStartActive}, + ${gradientEndActive} + ); + } + `}; +` + +const modeOutline = css` + background: transparent; + padding-top: 9px; + padding-bottom: 9px; + border: 1px solid ${contentBorder}; + &:hover, + &:focus { + border-color: ${contentBorderActive}; + } + &:active { + color: ${textPrimary}; + border-color: ${textPrimary}; + } +` + +const modeText = css` + padding: 10px; + background: transparent; + &:active, + &:focus { + color: ${textPrimary}; + } +` + +const compactStyle = css` + padding: ${({ mode }) => (mode === 'outline' ? '4px 14px' : '5px 15px')}; +` + +const positiveStyle = css` + padding-left: 34px; + background: url(${styledUrl(check)}) no-repeat 12px calc(50% - 1px); + ${({ mode }) => { + if (mode !== 'strong') return '' + return css` + &, + &:active { + background-image: url(${styledUrl(checkWhite)}); + background-color: ${theme.positive}; + } + &:after { + background: none; + } + ` + }}; +` + +const negativeStyle = css` + padding-left: 30px; + background: url(${styledUrl(cross)}) no-repeat 10px calc(50% - 1px); + ${({ mode }) => { + if (mode !== 'strong') return '' + return css` + &, + &:active { + background-image: url(${styledUrl(crossWhite)}); + background-color: ${theme.negative}; + } + &:after { + background: none; + } + ` + }}; +` + +const StyledButton = styled.button.attrs({ type: 'button' })` + width: ${({ wide }) => (wide ? '100%' : 'auto')}; + padding: 10px 15px; + white-space: nowrap; + ${font({ size: 'small', weight: 'normal' })}; + color: ${textSecondary}; + background: ${contentBackground}; + border: 0; + border-radius: 3px; + outline: 0; + cursor: ${({ disabled }) => (disabled ? 'default' : 'pointer')}; + &, + &:after { + transition-property: all; + transition-duration: 100ms; + transition-timing-function: ease-in-out; + } + &::-moz-focus-inner { + border: 0; + } + + ${({ mode }) => { + if (mode === 'secondary') return modeSecondary + if (mode === 'strong') return modeStrong + if (mode === 'outline') return modeOutline + if (mode === 'text') return modeText + return modeNormal + }}; + + ${({ compact }) => (compact ? compactStyle : '')}; + + ${({ emphasis }) => { + if (emphasis === 'positive') return positiveStyle + if (emphasis === 'negative') return negativeStyle + return '' + }}; +` + +const Button = PublicUrl.hocWrap(StyledButton) +const Anchor = PublicUrl.hocWrap( + StyledButton.withComponent(SafeLink).extend` + ${unselectable}; + display: inline-block; + text-decoration: none; + ` +) + +Button.Anchor = Anchor + +export default Button diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/components/Button/README.md b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/components/Button/README.md new file mode 100644 index 0000000..2fe8617 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/components/Button/README.md @@ -0,0 +1,97 @@ +# Button + +A simple Button component. + +## Usage + +```jsx +import { Button } from '@aragon/ui' + +const App = () => ( + +) +``` + +## Properties + +### `mode` + +- Type: `String` +- Values: `normal` (default), `secondary`, `outline`, `strong` or `text`. + +Set this property to the desired visual variant. + +#### Example: + +```jsx +const App = () => ( +
+ + +
+) +``` + +### `emphasis` + +- Type: `String` +- Values: `positive` or `negative`. + +Set this property to provide positive or negative visual cues. + +#### Example: + +```jsx +const App = () => ( +
+ + +
+) +``` + +### `compact` + +- Type: `Boolean` +- Default: `false` + +Set to true to obtain a button that contains less padding than normal buttons. + +#### Example: + +```jsx +const MyButton = () => ( + +) +``` + +### `wide` + +- Type: `Boolean` +- Default: `false` + +Set to true to obtain a button that expands horizontally. + +#### Example: + +```jsx +const MyButton = () => ( + +) +``` + +## Attached Components + +### `Anchor` + +An `` styled to be visually similar to Buttons, supporting the same properties. + +#### Example: + +```jsx +const LinkButton = () => ( + + Aragon + +) +``` diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/components/Button/assets/check-white.svg b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/components/Button/assets/check-white.svg new file mode 100644 index 0000000..6c1a3a7 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/components/Button/assets/check-white.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/components/Button/assets/check.svg b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/components/Button/assets/check.svg new file mode 100644 index 0000000..1dd408f --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/components/Button/assets/check.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/components/Button/assets/cross-white.svg b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/components/Button/assets/cross-white.svg new file mode 100644 index 0000000..039d0b5 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/components/Button/assets/cross-white.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/components/Button/assets/cross.svg b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/components/Button/assets/cross.svg new file mode 100644 index 0000000..5f08878 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/components/Button/assets/cross.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/components/Button/assets/index.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/components/Button/assets/index.js new file mode 100644 index 0000000..98e3c34 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/components/Button/assets/index.js @@ -0,0 +1,2 @@ +// @create-index + diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/components/Button/index.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/components/Button/index.js new file mode 100644 index 0000000..d4e7cd3 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/components/Button/index.js @@ -0,0 +1,5 @@ +// @create-index + +export { default as Button } from './Button.js'; +export { default as assets } from './assets'; + diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/components/Card.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/components/Card.js new file mode 100644 index 0000000..923f568 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/components/Card.js @@ -0,0 +1,19 @@ +import styled from 'styled-components' + +import { theme } from '../theme'; +import { media } from '../utils/media'; + +const StyledCard = styled.div` + width: ${({ width }) => width || '282px'}; + height: ${({ height }) => height || '322px'}; + background: ${theme.contentBackground}; + border: ${({ border }) => border || `1px solid ${theme.contentBorder}`}; + border-radius: 3px; + min-height: 30vh; + ${media.desktop`margin-top: 5%;`} + ${media.giant`margin-top: 5%;`} + ${media.tablet`margin-top: 25%;`} + ${media.phone`margin-top: 25%;`} +` + +export default StyledCard diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/components/Field.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/components/Field.js new file mode 100644 index 0000000..9409298 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/components/Field.js @@ -0,0 +1,46 @@ +import { node, string } from 'prop-types' +import React from 'react' +import styled from 'styled-components' +import Text from './Text' +import theme from '../theme' +import { unselectable } from '../utils/styles' + +const StyledField = styled.div` + margin-bottom: 20px; +` + +const StyledAsterisk = styled.span` + color: ${theme.accent}; + float: right; + padding-top: 3px; + font-size: 12px; +` + +const StyledTextBlock = styled(Text.Block)` + font-weight: 400; + ${unselectable()}; +` + +const Field = ({ children, label, wide, ...props }) => { + const isRequired = React.Children.toArray(children).some( + ({ props: childProps }) => childProps.required + ) + return ( + + + + ) +} + +Field.propTypes = { + children: node, + label: string, +} + +export default Field diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/components/IconInfo.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/components/IconInfo.js new file mode 100644 index 0000000..239fe7b --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/components/IconInfo.js @@ -0,0 +1,73 @@ +import React from 'react' +import PropTypes from 'prop-types' +import styled from 'styled-components' +import Attention from '../icons/components/Attention' +import Bylaw from '../icons/components/Bylaw' +import theme from '../theme' +import { font } from '../utils/styles' +import Info from './Info' + +const Icon = styled.span` + margin-right: 10px; +` + +const Title = styled.div` + color: ${theme.textSecondary}; + margin-bottom: 2px; + display: flex; + align-items: center; + ${font({ size: 'small' })}; +` + +const TitlelessBody = styled.div` + display: flex; + align-items: center; +` + +const IconInfo = ({ children, icon, title, ...props }) => { + let titleElm = title + let bodyElm = ( + + {icon && {icon}} + {children} + + ) + if (title) { + titleElm = ( + + {icon && <Icon>{icon}</Icon>} + {title} + + ) + bodyElm = children + } + return ( + + {bodyElm} + + ) +} +IconInfo.propTypes = { + children: PropTypes.node, + icon: PropTypes.node, + title: PropTypes.node, +} + +const Action = props => } {...props} /> + +const PermissionIconInfo = styled(IconInfo)` +${Icon} { + color: ${theme.infoPermissionsIcon}; +} +` + +const Permissions = props => ( +} + {...props} +/> +) + +export { Action, Permissions } +export default IconInfo diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/components/Info.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/components/Info.js new file mode 100644 index 0000000..fae1a47 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/components/Info.js @@ -0,0 +1,37 @@ +import React from 'react' +import styled from 'styled-components' +import PropTypes from 'prop-types' +import theme from '../theme' +import { Action, Permissions } from './IconInfo' + +const Info = ({ children, title, ...props }) => ( +
+ {title && {title}} + {children} +
+) +Info.propTypes = { + background: PropTypes.string, + children: PropTypes.node, + title: PropTypes.node, +} +Info.defaultProps = { + background: theme.infoBackground, +} + +const Main = styled.section` + background: ${({ background }) => background}; + padding: 15px; + border-radius: 4px; + word-wrap: break-word; +` + +const Title = styled.h1` + display: flex; + margin-top: 0px; // needed to overwrite bootstrap.css +` + +Info.Action = Action +Info.Permissions = Permissions + +export default Info diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/components/MobileButton.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/components/MobileButton.js new file mode 100644 index 0000000..e366b3c --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/components/MobileButton.js @@ -0,0 +1,21 @@ +import React, { Fragment } from 'react'; +import classNames from 'classnames'; +import { withStyles } from '@material-ui/core/styles'; +import Button from '@material-ui/core/Button'; + +const styles = theme => ({ + button: { + borderRadius: '4px', + backgroundColor: 'rgba(67, 96, 223, 0.1)', + } +}); +const buttonText = { color: '#4360df', margin: '0 20px', fontWeight: 300 }; +const MobileButton = ({ classes, text, type, style, ...props }) => ( + + + +); + +export default withStyles(styles)(MobileButton); diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/components/MobileSearch.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/components/MobileSearch.js new file mode 100644 index 0000000..6ef7f97 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/components/MobileSearch.js @@ -0,0 +1,54 @@ +import React from 'react'; +import styled, { css } from 'styled-components'; +import theme from '../theme'; +import SearchIcon from '@material-ui/icons/Search'; +import Button from '@material-ui/core/Button'; + +const searchWrapper = { + width: '100%', + height: '100%', + position: 'absolute', + pointerEvents: 'none', + display: 'flex', + alignItems: 'center', + justifyContent: 'flex-start', + paddingLeft: '11px', + boxSizing: 'border-box', +}; + +const pasteStyle = { + ...searchWrapper, + paddingLeft: '17em', + color: theme.accent +}; + +const MobileInput = styled.input` + display: block; + border-radius: 0; + background-color: #eef2f5; + font-size: 16px; + border: none; + height: 3.5em; + width: ${({ wide }) => (wide ? '100%' : 'auto')}; + appearance: none; + box-shadow: none; + padding-left: ${({ search }) => (search ? '45px' : '15px')}; + &:focus { + outline: none; + border-color: ${theme.contentBorderActive}; + } +`; + +const MobileSearch = props => ( +
+ {props.search &&
+ +
} +
+ + {!props.value && props.paste && } +
+
+); + +export default MobileSearch; diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/components/SafeLink.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/components/SafeLink.js new file mode 100644 index 0000000..25da85e --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/components/SafeLink.js @@ -0,0 +1,8 @@ +import styled from 'styled-components' + +const SafeLink = styled.a.attrs({ + // See https://mathiasbynens.github.io/rel-noopener + rel: 'noopener noreferrer', +})`` + +export default SafeLink diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/components/Text.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/components/Text.js new file mode 100644 index 0000000..936a6b3 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/components/Text.js @@ -0,0 +1,34 @@ +import React from 'react' +import styled from 'styled-components' +import { font } from '../utils/styles/font' + +const StyledText = styled.span` + ${({ size, weight, smallcaps }) => (font({ size, weight, smallcaps }))}; + ${({ color }) => (color ? `color: ${color}` : '')}; +` + +const Text = props => + +const createTextContainer = Element => { + const Container = ({ + children, + color, + size, + smallcaps, + weight, + ...props + }) => { + const textProps = { color, size, smallcaps, weight } + return ( + + {children} + + ) + } + return Container +} + +Text.Block = createTextContainer('div') +Text.Paragraph = createTextContainer('p') + +export default Text diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/components/TextInput.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/components/TextInput.js new file mode 100644 index 0000000..bfd830a --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/components/TextInput.js @@ -0,0 +1,69 @@ +import PropTypes from 'prop-types' +import React from 'react' +import styled, { css } from 'styled-components' +import theme from '../theme' +import { font } from '../utils/styles/font' + +const baseStyles = css` + ${font({ size: 'small', weight: 'normal' })}; + width: ${({ wide }) => (wide ? '100%' : 'auto')}; + + padding: 5px 10px; + background: ${theme.contentBackground}; + border: 1px solid ${theme.contentBorder}; + border-radius: 3px; + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.06); + color: ${theme.textPrimary}; + appearance: none; + &:focus { + outline: none; + border-color: ${theme.contentBorderActive}; + } + &:read-only { + color: transparent; + text-shadow: 0 0 0 ${theme.textSecondary}; + } +` + +// Simple input +const TextInput = styled.input` + ${baseStyles}; +` +TextInput.propTypes = { + required: PropTypes.bool, + type: PropTypes.oneOf([ + 'email', + 'number', + 'password', + 'search', + 'tel', + 'text', + 'url', + ]), +} +TextInput.defaultProps = { + required: false, + type: 'text', +} + +// (only for compat) +const TextInputNumber = styled.input.attrs({ type: 'number' })` + ${baseStyles}; +` + +// Multiline input (textarea element) +const TextInputMultiline = styled.textarea` + ${baseStyles}; + resize: vertical; +` +TextInputMultiline.propTypes = { + required: PropTypes.bool, +} +TextInputMultiline.defaultProps = { + required: false, +} + +TextInput.Number = TextInputNumber +TextInput.Multiline = TextInputMultiline + +export default TextInput diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/components/index.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/components/index.js new file mode 100644 index 0000000..779e841 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/components/index.js @@ -0,0 +1,11 @@ +// @create-index + +export * from './Button'; +export { default as Card } from './Card.js'; +export { default as Field } from './Field.js'; +export { default as Text } from './Text.js'; +export { default as TextInput } from './TextInput.js'; +export { default as MobileSearch } from './MobileSearch.js'; +export { default as MobileButton } from './MobileButton.js'; +export { default as Info } from './Info.js'; + diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/components/Add.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/components/Add.js new file mode 100644 index 0000000..b764d83 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/components/Add.js @@ -0,0 +1,19 @@ +import React from "react" + +const Add = props => ( + + + + + + + +) + +export default Add diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/components/Apps.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/components/Apps.js new file mode 100644 index 0000000..d30ecdc --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/components/Apps.js @@ -0,0 +1,16 @@ +import React from "react" + +const Apps = props => ( + + + + + + +) + +export default Apps diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/components/ArrowDown.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/components/ArrowDown.js new file mode 100644 index 0000000..a3f98b2 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/components/ArrowDown.js @@ -0,0 +1,9 @@ +import React from "react" + +const ArrowDown = props => ( + + + +) + +export default ArrowDown diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/components/Attention.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/components/Attention.js new file mode 100644 index 0000000..77dbd82 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/components/Attention.js @@ -0,0 +1,16 @@ +import React from "react" + +const Attention = props => ( + + + + + + +) + +export default Attention diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/components/Blank.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/components/Blank.js new file mode 100644 index 0000000..291b8ae --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/components/Blank.js @@ -0,0 +1,16 @@ +import React from "react" + +const Blank = props => ( + + + + + + +) + +export default Blank diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/components/Bylaw.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/components/Bylaw.js new file mode 100644 index 0000000..c45750e --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/components/Bylaw.js @@ -0,0 +1,19 @@ +import React from "react" + +const Bylaw = props => ( + + + + + + + + + +) + +export default Bylaw diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/components/Check.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/components/Check.js new file mode 100644 index 0000000..4572bb5 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/components/Check.js @@ -0,0 +1,13 @@ +import React from "react" + +const Check = props => ( + + + +) + +export default Check diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/components/Cross.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/components/Cross.js new file mode 100644 index 0000000..dec2e9f --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/components/Cross.js @@ -0,0 +1,13 @@ +import React from "react" + +const Cross = props => ( + + + +) + +export default Cross diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/components/Ellipsis.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/components/Ellipsis.js new file mode 100644 index 0000000..b23fc50 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/components/Ellipsis.js @@ -0,0 +1,13 @@ +import React from "react" + +const Ellipsis = props => ( + + + +) + +export default Ellipsis diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/components/Fundraising.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/components/Fundraising.js new file mode 100644 index 0000000..4dc5573 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/components/Fundraising.js @@ -0,0 +1,25 @@ +import React from "react" + +const Fundraising = props => ( + + + + + + + + + + + +) + +export default Fundraising diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/components/Groups.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/components/Groups.js new file mode 100644 index 0000000..d83da04 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/components/Groups.js @@ -0,0 +1,15 @@ +import React from "react" + +const Groups = props => ( + + + + + + +) + +export default Groups diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/components/Home.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/components/Home.js new file mode 100644 index 0000000..9130605 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/components/Home.js @@ -0,0 +1,12 @@ +import React from "react" + +const Home = props => ( + + + +) + +export default Home diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/components/Identity.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/components/Identity.js new file mode 100644 index 0000000..8d9fe01 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/components/Identity.js @@ -0,0 +1,15 @@ +import React from "react" + +const Identity = props => ( + + + + + + +) + +export default Identity diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/components/Notifications.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/components/Notifications.js new file mode 100644 index 0000000..cb0674d --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/components/Notifications.js @@ -0,0 +1,15 @@ +import React from "react" + +const Notifications = props => ( + + + + + + +) + +export default Notifications diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/components/Permissions.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/components/Permissions.js new file mode 100644 index 0000000..503330c --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/components/Permissions.js @@ -0,0 +1,19 @@ +import React from "react" + +const Permissions = props => ( + + + + + + + + + +) + +export default Permissions diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/components/Settings.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/components/Settings.js new file mode 100644 index 0000000..0579618 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/components/Settings.js @@ -0,0 +1,15 @@ +import React from "react" + +const Settings = props => ( + + + + + + +) + +export default Settings diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/components/Share.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/components/Share.js new file mode 100644 index 0000000..d2f67d2 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/components/Share.js @@ -0,0 +1,15 @@ +import React from "react" + +const Share = props => ( + + + + + + +) + +export default Share diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/components/StatusLogo.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/components/StatusLogo.js new file mode 100644 index 0000000..f77eee5 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/components/StatusLogo.js @@ -0,0 +1,12 @@ +import React from "react" + +const Status = props => ( + + + + + + +); + +export default Status; diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/components/Time.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/components/Time.js new file mode 100644 index 0000000..57d3be6 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/components/Time.js @@ -0,0 +1,14 @@ +import React from "react" + +const Time = props => ( + + + +) + +export default Time diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/components/Wallet.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/components/Wallet.js new file mode 100644 index 0000000..4e55ce7 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/components/Wallet.js @@ -0,0 +1,15 @@ +import React from "react" + +const Wallet = props => ( + + + + + + +) + +export default Wallet diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/components/baseline_check_circle_outline.png b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/components/baseline_check_circle_outline.png new file mode 100644 index 0000000..aa6010e Binary files /dev/null and b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/components/baseline_check_circle_outline.png differ diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/index.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/index.js new file mode 100644 index 0000000..b57c478 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/index.js @@ -0,0 +1,17 @@ +/* eslint-disable prettier/prettier */ + +export { default as IconAdd } from './components/Add' +export { default as IconApps } from './components/Apps' +export { default as IconBlank } from './components/Blank' +export { default as IconCheck } from './components/Check' +export { default as IconCross } from './components/Cross' +export { default as IconFundraising } from './components/Fundraising' +export { default as IconGroups } from './components/Groups' +export { default as IconHome } from './components/Home' +export { default as IconIdentity } from './components/Identity' +export { default as IconNotifications } from './components/Notifications' +export { default as IconPermissions } from './components/Permissions' +export { default as IconSettings } from './components/Settings' +export { default as IconShare } from './components/Share' +export { default as IconTime } from './components/Time' +export { default as IconWallet } from './components/Wallet' diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/logos/ens.png b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/logos/ens.png new file mode 100644 index 0000000..eb0b1ea Binary files /dev/null and b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/logos/ens.png differ diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/svg/add.svg b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/svg/add.svg new file mode 100644 index 0000000..b291f08 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/svg/add.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/svg/apps.svg b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/svg/apps.svg new file mode 100644 index 0000000..c951afa --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/svg/apps.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/svg/arrow-down.svg b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/svg/arrow-down.svg new file mode 100644 index 0000000..90e88b9 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/svg/arrow-down.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/svg/attention.svg b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/svg/attention.svg new file mode 100644 index 0000000..98c6507 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/svg/attention.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/svg/blank.svg b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/svg/blank.svg new file mode 100644 index 0000000..ded9128 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/svg/blank.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/svg/bylaw.svg b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/svg/bylaw.svg new file mode 100644 index 0000000..bc5fe7f --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/svg/bylaw.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/svg/check.svg b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/svg/check.svg new file mode 100644 index 0000000..1dd408f --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/svg/check.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/svg/cross.svg b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/svg/cross.svg new file mode 100644 index 0000000..5f08878 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/svg/cross.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/svg/ellipsis.svg b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/svg/ellipsis.svg new file mode 100644 index 0000000..839d216 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/svg/ellipsis.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/svg/fundraising.svg b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/svg/fundraising.svg new file mode 100644 index 0000000..473acd8 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/svg/fundraising.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/svg/groups.svg b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/svg/groups.svg new file mode 100644 index 0000000..24fbbf8 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/svg/groups.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/svg/home.svg b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/svg/home.svg new file mode 100644 index 0000000..1465565 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/svg/home.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/svg/identity.svg b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/svg/identity.svg new file mode 100644 index 0000000..b10343b --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/svg/identity.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/svg/intro_cards.svg b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/svg/intro_cards.svg new file mode 100644 index 0000000..2d0fe13 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/svg/intro_cards.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/svg/intro_name.svg b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/svg/intro_name.svg new file mode 100644 index 0000000..a01e56a --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/svg/intro_name.svg @@ -0,0 +1,184 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/svg/notifications.svg b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/svg/notifications.svg new file mode 100644 index 0000000..e4bf33e --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/svg/notifications.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/svg/permissions.svg b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/svg/permissions.svg new file mode 100644 index 0000000..628cc12 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/svg/permissions.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/svg/settings.svg b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/svg/settings.svg new file mode 100644 index 0000000..1fe25ac --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/svg/settings.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/svg/share.svg b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/svg/share.svg new file mode 100644 index 0000000..cb1fa4a --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/svg/share.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/svg/time.svg b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/svg/time.svg new file mode 100644 index 0000000..2f8b566 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/svg/time.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/svg/wallet.svg b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/svg/wallet.svg new file mode 100644 index 0000000..cb0e748 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/svg/wallet.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/svg/warning.svg b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/svg/warning.svg new file mode 100644 index 0000000..0fe1e1e --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/icons/svg/warning.svg @@ -0,0 +1,3 @@ + + + diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/index.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/index.js new file mode 100644 index 0000000..24ff7ab --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/index.js @@ -0,0 +1,7 @@ +// @create-index + +export { default as components } from './components'; +export { default as providers } from './providers'; +export { default as theme } from './theme'; +export { default as utils } from './utils'; + diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/providers/PublicUrl/PublicUrl.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/providers/PublicUrl/PublicUrl.js new file mode 100644 index 0000000..9e6c6fb --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/providers/PublicUrl/PublicUrl.js @@ -0,0 +1,32 @@ +import React from 'react' +import PropTypes from 'prop-types' +import { prefixUrl } from '../../utils/url' + +const DEFAULT_URL = '' + +const { Provider, Consumer: PublicUrl } = React.createContext(DEFAULT_URL) + +const PublicUrlProvider = ({ url, children }) => { + return {children} +} +PublicUrlProvider.propTypes = { + url: PropTypes.string, + children: PropTypes.node, +} + +// HOC wrapper +const hocWrap = Component => props => ( + + {publicUrl => } + +) + +// styled-components utility for URLs +const styledUrl = url => ({ publicUrl }) => prefixUrl(url, publicUrl) + +PublicUrl.Provider = PublicUrlProvider +PublicUrl.hocWrap = hocWrap +PublicUrl.styledUrl = styledUrl + +export { PublicUrl, Provider, hocWrap, styledUrl } +export default PublicUrl diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/providers/PublicUrl/index.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/providers/PublicUrl/index.js new file mode 100644 index 0000000..e798b73 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/providers/PublicUrl/index.js @@ -0,0 +1,2 @@ +export { default } from './PublicUrl' +export * from './PublicUrl' diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/providers/index.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/providers/index.js new file mode 100644 index 0000000..17dd339 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/providers/index.js @@ -0,0 +1,4 @@ +// @create-index + +export { default as PublicUrl } from './PublicUrl'; + diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/theme/Status.oco b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/theme/Status.oco new file mode 100644 index 0000000..db36299 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/theme/Status.oco @@ -0,0 +1,142 @@ +oct/ + defaultView: minimal + identityColorTop: =Status Brand.Primary + identityColorSide: =Status Brand.Secondary + identityColorBottom: =Status Brand.Black Ash +Grey: + Black Ash: hsl(0, 0%, 23%) + Dim Grey: hsl(0, 0%, 44%) + Dust Grey: hsl(0, 0%, 59%) + Light Grey: hsl(0, 0%, 70%) + Gainsboro: hsl(0, 0%, 90%) + Alabaster: hsl(0, 0%, 95%) +Rain: + Shark: hsl(180, 5%, 13%); + Atomic: hsl(194, 13%, 31%) + Slate: hsl(197, 11%, 48%) + Aqua Island: hsl(194, 46%, 74%) + Rain Sky: hsl(194, 36%, 90%) + Aqua Blue: hsl(194, 56%, 98%) +Blue: + Lochmara: hsl(200, 98%, 41%) + Danube: hsl(210, 57%, 68%) + Spindle: hsl(210, 57%, 81%) + Solitude: hsl(201, 89%, 96%) +Sea: + Light Sea: hsl(185, 71%, 45%) + Turquoise: hsl(167, 72%, 60%) + Blizzard Blue: hsl(176, 62%, 80%) + +Purple: + Indigo: hsl(252, 62%, 46%) + Portage: hsl(258, 85%, 74%) + Lavender: hsl(258, 100%, 95%) +Eagle: + Dark Cerulean: hsl(193, 100%, 41%) + Cerulean: hsl(193, 100%, 45%) + Dark Turquoise: hsl(187, 100%, 45%); + Dark Opal: hsl(176, 100%, 43%) + Opal: hsl(176, 100%, 47%) +Gold: + Brandy: hsl(40, 52%, 70%) + Beige: hsl(43, 100%, 96%) +Red: + Salmon Red: hsl(0, 94%, 73%) +Green: + Spring Green: hsl(157, 73%, 48%) +Black: + Black: hsl(0, 0%, 0%) +White: + White: hsl(0, 0%, 100%) +Status Brand: + oct/ + view: Fan + colorsPerRow: 5 + Primary: =Purple.Indigo + Secondary: =Sea.Turquoise + Black Ash: =Grey.Black Ash + Gradient Start: =Eagle.Cerulean + Gradient End: =Eagle.Opal +Status UI: + oct/ + view: List + swatchShape: SQUARE + gradientStart: =Eagle.Cerulean + gradientEnd: =Eagle.Opal + gradientStartActive: =Eagle.Dark Cerulean + gradientEndActive: =Eagle.Dark Opal + gradientText: =White.White + mainBackground: =Rain.Aqua Blue + mainBgGradientStart: =Rain.Rain Sky + mainBgGradientEnd: =Rain.Aqua Blue + secondaryBackground: =Rain.Rain Sky + contentBackground: =White.White + contentBackgroundActive: =Grey.Alabaster + contentBorder: =Grey.Gainsboro + contentBorderActive: =Grey.Light Grey + disabled: =Grey.Gainsboro + disabledText: =White.White + infoBackground: =Blue.Solitude + infoPermissionsBackground: =Gold.Beige + infoPermissionsIcon: =Gold.Brandy + shadow: =Grey.Alabaster + text: =Black.Black + textPrimary: =Status UI.text + textDimmed: =Grey.Black Ash + textSecondary: =Grey.Dim Grey + textTertiary: =Grey.Light Grey + accent: =Eagle.Dark Turquoise + positive: =Green.Spring Green + positiveText: =White.White + negative: =Red.Salmon Red + negativeText: =White.White + badgeAppBackground: =Purple.Lavender + badgeAppForeground: =Purple.Portage + badgeIdentityBackground: =Rain.Rain Sky + badgeIdentityForeground: =Rain.Slate + badgeNotificationBackground: =Status UI.positive + badgeNotificationForeground: =Status UI.positiveText + badgeInfoBackground: =Rain.Rain Sky + badgeInfoForeground: =Rain.Slate +Status UI Dark: + oct/ + view: List + swatchShape: SQUARE + gradientStart: =Eagle.Cerulean + gradientEnd: =Eagle.Opal + gradientStartActive: =Eagle.Dark Cerulean + gradientEndActive: =Eagle.Dark Opal + gradientText: =White.White + mainBackground: =Rain.Aqua Blue + mainBgGradientStart: =Rain.Rain Sky + mainBgGradientEnd: =Rain.Aqua Blue + secondaryBackground: =Rain.Rain Sky + contentBackground: =Rain.Shark + contentBackgroundActive: =Grey.Alabaster + contentBorder: =Grey.Gainsboro + contentBorderActive: =Grey.Light Grey + disabled: =Grey.Light Grey + disabledText: =Grey.Dim Grey + infoBackground: =Blue.Solitude + infoPermissionsBackground: =Gold.Beige + infoPermissionsIcon: =Gold.Brandy + shadow: =Grey.Alabaster + text: =White.White + textPrimary: =Status UI Dark.text + textDimmed: =Grey.Alabaster + textSecondary: =Grey.Dust Grey + textTertiary: =Grey.Dim Grey + accent: =Eagle.Dark Turquoise + positive: =Green.Spring Green + positiveText: =White.White + negative: =Red.Salmon Red + negativeText: =White.White + badgeAppBackground: =Purple.Lavender + badgeAppForeground: =Purple.Portage + badgeIdentityBackground: =Rain.Rain Sky + badgeIdentityForeground: =Rain.Slate + badgeNotificationBackground: =Status UI Dark.positive + badgeNotificationForeground: =Status UI Dark.positiveText + badgeInfoBackground: =Rain.Rain Sky + badgeInfoForeground: =Rain.Slate + diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/theme/index.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/theme/index.js new file mode 100644 index 0000000..c6e2461 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/theme/index.js @@ -0,0 +1 @@ +export { theme as default, theme, themeDark, brand, colors } from './palettes' diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/theme/palettes.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/theme/palettes.js new file mode 100644 index 0000000..ce573e5 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/theme/palettes.js @@ -0,0 +1,66 @@ +/* @flow */ +import status from './status.json' + +// These need to match the names in the Open Color palettes +const THEME_NAME = 'Status UI' +const THEME_DARK_NAME = 'Status UI Dark' +const BRAND_NAME = 'Status Brand' + +// Name of the group a given palette belong to +const getGroupName = (name) => { + if (name === THEME_NAME) return 'theme' + if (name === THEME_DARK_NAME) return 'themeDark' + if (name === BRAND_NAME) return 'brand' + return 'colors' +} + +// Resolve a single color +const resolveColor = (value, palettes) => { + // already resolved color + if (!value.startsWith('=')) { + return value + } + + const [paletteName, key] = value.slice(1).split('.') + const color = palettes[paletteName] && palettes[paletteName][key] + + if (!color) { + throw new Error(`resolveColor: ${value} doesn’t seem to exist`) + } + + // follow the references until we find one + if (color.startsWith('=')) { + return resolveColor(color, palettes) + } + return color +} + +// Resolve all the colors in a palette +const resolveColors = (palette, palettes) => + Object.entries(palette).reduce((pal, [name, value]) => { + if (typeof value === 'string') { + pal[name] = resolveColor(value, palettes) + } + return pal + }, {}) + +// Prepare groups from the palettes: theme, themeDark, brand and colors. +const groups = (palettes) => + Object.entries(palettes).reduce( + (groups, [paletteName, palette]) => { + const groupName = getGroupName(paletteName) + + if (groupName === 'colors') { + groups.colors[paletteName] = resolveColors(palette, palettes) + } else { + groups[groupName] = resolveColors(palette, palettes) + } + + return groups + }, + { colors: {} } + ) + +const { themeDark, theme, brand, colors } = groups(status) + +export { themeDark, theme, brand, colors } diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/theme/status.json b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/theme/status.json new file mode 100644 index 0000000..25a58fd --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/theme/status.json @@ -0,0 +1,145 @@ +{ + "Grey": { + "Black Ash": "#3B3B3B", + "Dim Grey": "#707070", + "Dust Grey": "#969696", + "Light Grey": "#939ba1", + "Gainsboro": "#E6E6E6", + "Alabaster": "#F2F2F2" + }, + "Rain": { + "Shark": "#1F2323", + "Atomic": "#455559", + "Slate": "#6D8088", + "Aqua Island": "#9ECDDB", + "Rain Sky": "#DCEAEF", + "Aqua Blue": "#F7FBFD" + }, + "Blue": { + "Main": "#4360DF", + "Light": "#95A8F8", + "Lochmara": "#028BCF", + "Danube": "#7FADDC", + "Spindle": "#B3CFEA", + "Solitude": "#ECF8FE" + }, + "Sea": { + "Light Sea": "#21B7C4", + "Turquoise": "#50E2C3", + "Blizzard Blue": "#ACECE7" + }, + "Purple": { + "Indigo": "#4A2DBE", + "Portage": "#A684F5", + "Lavender": "#EDE5FF" + }, + "Eagle": { + "Dark Cerulean": "#00A4D1", + "Cerulean": "#00B4E6", + "Dark Turquoise": "#00CBE6", + "Dark Opal": "#00DBCD", + "Opal": "#00F0E0" + }, + "Gold": { + "Brandy": "#DAC08B", + "Beige": "#FFF9EB" + }, + "Red": { + "Salmon Red": "#FB7979" + }, + "Green": { + "Spring Green": "#21D48F" + }, + "Black": { + "Black": "#000000" + }, + "White": { + "White": "#FFFFFF" + }, + "Status Brand": { + "Primary": "=Blue.Main", + "Secondary": "=Sea.Turquoise", + "Black Ash": "=Grey.Black Ash", + "Gradient Start": "=Eagle.Cerulean", + "Gradient End": "=Eagle.Opal", + "SubText": "=Grey.Light Grey" + }, + "Status UI": { + "gradientStart": "=Blue.Main", + "gradientEnd": "=Blue.Light", + "gradientStartActive": "=Eagle.Dark Cerulean", + "gradientEndActive": "=Eagle.Dark Opal", + "gradientText": "=White.White", + "mainBackground": "=Rain.Aqua Blue", + "mainBgGradientStart": "=Rain.Rain Sky", + "mainBgGradientEnd": "=Rain.Aqua Blue", + "secondaryBackground": "=Rain.Rain Sky", + "contentBackground": "=White.White", + "contentBackgroundActive": "=Grey.Alabaster", + "contentBorder": "=Grey.Gainsboro", + "contentBorderActive": "=Grey.Light Grey", + "disabled": "=Grey.Gainsboro", + "disabledText": "=White.White", + "infoBackground": "=Blue.Solitude", + "infoPermissionsBackground": "=Gold.Beige", + "infoPermissionsIcon": "=Gold.Brandy", + "shadow": "=Grey.Alabaster", + "text": "=Black.Black", + "textPrimary": "=Status UI.text", + "textDimmed": "=Grey.Black Ash", + "textSecondary": "=Grey.Dim Grey", + "textTertiary": "=Grey.Light Grey", + "accent": "=Blue.Main", + "positive": "=Green.Spring Green", + "positiveText": "=White.White", + "negative": "=Red.Salmon Red", + "negativeText": "=White.White", + "badgeAppBackground": "=Purple.Lavender", + "badgeAppForeground": "=Purple.Portage", + "badgeIdentityBackground": "=Rain.Rain Sky", + "badgeIdentityForeground": "=Rain.Slate", + "badgeNotificationBackground": "=Status UI.positive", + "badgeNotificationForeground": "=Status UI.positiveText", + "badgeInfoBackground": "=Rain.Rain Sky", + "badgeInfoForeground": "=Rain.Slate" + }, + "Status UI Dark": { + "gradientStart": "=Eagle.Cerulean", + "gradientEnd": "=Eagle.Opal", + "gradientStartActive": "=Eagle.Dark Cerulean", + "gradientEndActive": "=Eagle.Dark Opal", + "gradientText": "=White.White", + "mainBackground": "=Rain.Aqua Blue", + "mainBgGradientStart": "=Rain.Rain Sky", + "mainBgGradientEnd": "=Rain.Aqua Blue", + "secondaryBackground": "=Rain.Rain Sky", + "contentBackground": "=Rain.Shark", + "contentBackgroundActive": "=Grey.Alabaster", + "contentBorder": "=Grey.Gainsboro", + "contentBorderActive": "=Grey.Light Grey", + "disabled": "=Grey.Light Grey", + "disabledText": "=Grey.Dim Grey", + "infoBackground": "=Blue.Solitude", + "infoPermissionsBackground": "=Gold.Beige", + "infoPermissionsIcon": "=Gold.Brandy", + "shadow": "=Grey.Alabaster", + "text": "=White.White", + "textPrimary": "=Status UI Dark.text", + "textDimmed": "=Grey.Alabaster", + "textSecondary": "=Grey.Dust Grey", + "textTertiary": "=Grey.Dim Grey", + "accent": "=Eagle.Dark Turquoise", + "positive": "=Green.Spring Green", + "positiveText": "=White.White", + "negative": "=Red.Salmon Red", + "negativeText": "=White.White", + "badgeAppBackground": "=Purple.Lavender", + "badgeAppForeground": "=Purple.Portage", + "badgeIdentityBackground": "=Rain.Rain Sky", + "badgeIdentityForeground": "=Rain.Slate", + "badgeNotificationBackground": "=Status UI Dark.positive", + "badgeNotificationForeground": "=Status UI Dark.positiveText", + "badgeInfoBackground": "=Rain.Rain Sky", + "badgeInfoForeground": "=Rain.Slate" + } +} diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/utils/index.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/utils/index.js new file mode 100644 index 0000000..0cea639 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/utils/index.js @@ -0,0 +1,6 @@ +// @create-index + +export { default as styles } from './styles'; +export { default as url } from './url.js'; +export { default as media } from './media.js'; + diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/utils/media.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/utils/media.js new file mode 100644 index 0000000..367f0a2 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/utils/media.js @@ -0,0 +1,21 @@ +import { css } from 'styled-components' + +const sizes = { + giant: 3170, + desktop: 992, + tablet: 768, + phone: 414 +} + +// iterate through the sizes and create a media template +export const media = Object.keys(sizes).reduce((accumulator, label) => { + // use em in breakpoints to work properly cross-browser and support users + // changing their browsers font-size: https://zellwk.com/blog/media-query-units/ + const emSize = sizes[label] / 16 + accumulator[label] = (...args) => css` + @media (max-width: ${emSize}em) { + ${css(...args)} + } + ` + return accumulator +}, {}) diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/utils/styles/font.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/utils/styles/font.js new file mode 100644 index 0000000..4057065 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/utils/styles/font.js @@ -0,0 +1,47 @@ +const FONT_SIZES = { + xxsmall: '11px', + xsmall: '12px', + small: '14px', + normal: '15px', + large: '16px', + xlarge: '20px', + xxlarge: '22px', + great: '37px', +} + +const FONT_WEIGHTS = { + normal: '400', + bold: '600', + bolder: '800', +} + +const fontSizeCss = size => { + const fontSize = FONT_SIZES[size] + return fontSize !== undefined + ? ` + line-height: 1.5; + font-size: ${fontSize} + ` + : '' +} + +const weightCss = weight => { + const fontWeight = FONT_WEIGHTS[weight] + return fontWeight !== undefined ? `font-weight: ${fontWeight}` : '' +} + +const smallcapsCss = smallcaps => + smallcaps + ? ` + text-transform: lowercase; + font-variant: small-caps; + ` + : '' + +export const font = ({ size, weight, smallcaps = false, inherit = false }) => { + return ` + ${fontSizeCss(size, inherit)}; + ${weightCss(weight, inherit)}; + ${smallcapsCss(smallcaps, inherit)}; + ` +} diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/utils/styles/index.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/utils/styles/index.js new file mode 100644 index 0000000..87a3784 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/utils/styles/index.js @@ -0,0 +1,8 @@ +export * from './font' +export const unselectable = () => ` + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +` diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/utils/url.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/utils/url.js new file mode 100644 index 0000000..232c630 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/ui/utils/url.js @@ -0,0 +1,5 @@ +// prefix helper +const prefixUrl = (url, publicUrl) => + url.startsWith('data:') ? url : publicUrl + url + +export { prefixUrl } diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/utils/ecdsa.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/utils/ecdsa.js new file mode 100644 index 0000000..84359b2 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/utils/ecdsa.js @@ -0,0 +1,19 @@ +import { ec } from 'elliptic'; + +const EC = new ec('secp256k1'); + +export const generateXY = pub => { + const stripped = pub.slice(2); + const key = EC.keyFromPublic(stripped, 'hex'); + const pubPoint = key.getPublic(); + const x = '0x' + pubPoint.getX().toString(16); + const y = '0x'+ pubPoint.getY().toString(16); + return { x, y }; +} + +export const keyFromXY = (X, Y) => { + const x = Buffer.from(X.substring(2), 'hex'); + const y = Buffer.from(Y.substring(2), 'hex'); + const keys = EC.keyFromPublic({ x, y }, 'hex'); + return `0x${keys.getPublic().encode('hex')}`; +} diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/utils/web3Helpers.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/utils/web3Helpers.js new file mode 100644 index 0000000..ae234aa --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/app/utils/web3Helpers.js @@ -0,0 +1,17 @@ +import web3 from "Embark/web3" +import BigNumber from 'bignumber.js'; + +// By default BigNumber's `toString` method converts to exponential notation if the value has +// more then 20 digits. We want to avoid this behavior, so we set EXPONENTIAL_AT to a high number +BigNumber.config({ + EXPONENTIAL_AT: 1000, +}); +const unlimitedAllowance = new BigNumber(2).pow(256).sub(1); +export const getDefaultAccount = () => web3.eth.defaultAccount; +export const toggleApproved = (token, spender, approved, onlyApprove = false) => { + const isApproved = !!Number(approved); + if (isApproved && onlyApprove) return; + const { approve } = token.methods; + const amountToApprove = isApproved ? 0 : unlimitedAllowance; + return approve(spender,amountToApprove).send(); +} diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/config/blockchain.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/config/blockchain.js new file mode 100644 index 0000000..af0808f --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/config/blockchain.js @@ -0,0 +1,62 @@ +module.exports = { + development: { + enabled: true, + networkType: "custom", // Can be: testnet, rinkeby, livenet or custom, in which case, it will use the specified networkId + networkId: "1337", // Network id used when networkType is custom + isDev: true, // Uses and ephemeral proof-of-authority network with a pre-funded developer account, mining enabled + genesisBlock: "config/development/genesis.json", // Genesis block to initiate on first creation of a development node + datadir: ".embark/development/datadir", // Data directory for the databases and keystore + mineWhenNeeded: true, // Uses our custom script (if isDev is false) to mine only when needed + nodiscover: true, // Disables the peer discovery mechanism (manual peer addition) + maxpeers: 0, // Maximum number of network peers (network disabled if set to 0) (default: 25) + rpcHost: "localhost", // HTTP-RPC server listening interface (default: "localhost") + rpcPort: 8545, // HTTP-RPC server listening port (default: 8545) + rpcCorsDomain: "auto", // Comma separated list of domains from which to accept cross origin requests (browser enforced) + // When set to "auto", Embark will automatically set the cors to the address of the webserver + proxy: true, // Proxy is used to present meaningful information about transactions + account: { + // "address": "", // When specified, uses that address instead of the default one for the network + password: "config/development/password" // Password to unlock the account + }, + targetGasLimit: 8000000, // Target gas limit sets the artificial target gas floor for the blocks to mine + wsRPC: true, // Enable the WS-RPC server + wsOrigins: "auto", // Origins from which to accept websockets requests + // When set to "auto", Embark will automatically set the cors to the address of the webserver + wsHost: "localhost", // WS-RPC server listening interface (default: "localhost") + wsPort: 8546, // WS-RPC server listening port (default: 8546) + simulatorMnemonic: "example exile argue silk regular smile grass bomb merge arm assist farm", // Mnemonic used by the simulator to generate a wallet + simulatorBlocktime: 0 // Specify blockTime in seconds for automatic mining. Default is 0 and no auto-mining. + }, + testnet: { + enabled: true, + networkType: "testnet", + syncMode: "light", + rpcHost: "localhost", + rpcPort: 8545, + rpcCorsDomain: "http://localhost:8000", + account: { + password: "config/testnet/password" + } + }, + livenet: { + enabled: true, + networkType: "livenet", + syncMode: "light", + rpcHost: "localhost", + rpcPort: 8545, + rpcCorsDomain: "http://localhost:8000", + account: { + password: "config/livenet/password" + } + }, + privatenet: { + enabled: true, + networkType: "custom", + rpcHost: "localhost", + rpcPort: 8545, + rpcCorsDomain: "http://localhost:8000", + datadir: "yourdatadir", + networkId: "123", + bootnodes: "" + } +}; diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/config/communication.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/config/communication.js new file mode 100644 index 0000000..8c4d1f9 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/config/communication.js @@ -0,0 +1,12 @@ +module.exports = { + default: { + enabled: true, + provider: "whisper", // Communication provider. Currently, Embark only supports whisper + available_providers: ["whisper"], // Array of available providers + connection: { + host: "localhost", // Host of the blockchain node + port: 8546, // Port of the blockchain node + type: "ws" // Type of connection (ws or rpc) + } + } +}; diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/config/contracts.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/config/contracts.js new file mode 100644 index 0000000..26814cd --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/config/contracts.js @@ -0,0 +1,127 @@ +const { MerkleTree } = require('../utils/merkleTree.js'); +const { ReservedUsernames } = require('./ens-usernames/reservedNames.js'); + +const merkleTree = new MerkleTree(ReservedUsernames); + +module.exports = { + "default": { + "deployment": { + "host": "localhost", + "port": 8545, + "type": "rpc" + }, + "dappConnection": [ + "$WEB3", + "http://localhost:8545" + ], + "gas": "auto", + "contracts": { + "TestToken": {}, + "MerkleProofWrapper": { + "deploy": false + }, + "ERC20Receiver": { + "deploy": false + }, + "ENSRegistry": {}, + "PublicResolver": { + "args": ["$ENSRegistry"] + }, + "UsernameRegistrar": { + "args": [ + "$TestToken", + "$ENSRegistry", + "$PublicResolver", + "0x5f7791d31ca0493e9ca7c9ca16695ecd9d5044768674d14d31ab5d8277518fff", + 3, + merkleTree.getHexRoot(), + "0x11d9F481effd20D76cEE832559bd9Aca25405841" + ] + } + } + }, + "development": { + "contracts": { + "TestToken": { + "deploy": true + }, + "ENSRegistry": { + "deploy": true, + "onDeploy": [ + "ENSRegistry.methods.setSubnodeOwner('0x0000000000000000000000000000000000000000000000000000000000000000', '0x4f5b812789fc606be1b3b16908db13fc7a9adf7ca72641f84d75b47069d3d7f0', web3.eth.defaultAccount).send()" + ] + }, + "PublicResolver": { + "deploy": true, + "args": [ + "$ENSRegistry" + ] + }, + "UsernameRegistrar": { + "onDeploy": [ + "ENSRegistry.methods.setSubnodeOwner('0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae', '0xbd99f8d5e7f81d2d7c1da34b67a2bb3a94dd8c9b0ab40ddc077621b98405983b', UsernameRegistrar.address).send()" + ] + } + } + }, + "livenet":{ + "contracts": { + "ENSRegistry": { + "address": "0x314159265dd8dbb310642f98f50c066173c1259b" + }, + "PublicResolver": { + "address": "0x5FfC014343cd971B7eb70732021E26C35B744cc4" + }, + "TestToken": { + "address": "0x744d70fdbe2ba4cf95131626614a1763df805b9e" + }, + "UsernameRegistrar": { + "address": "0xDBf9038cf5Aaa030890790dB87E746E00Fc352b3" + }, + "MerkleProof": { + "address": "0x713ED9846463235df08D92B886938651105D3940" + }, + "MerkleProofWrapper": { + "address": "0x76E55E13C5891a90f7fCA2e1238a6B3463F564e2" + }, + "SafeMath": { + "address": "0xA115a57952D3337e2a1aB3Cb82bA376EEcDDc469" + } + } + }, + "testnet":{ + "contracts": { + "ENSRegistry": { + "address": "0x112234455c3a32fd11230c42e7bccd4a84e02010" + }, + "PublicResolver": { + "address": "0x29754bADB2640b98F6deF0f52D41418b0d2e0C51" + }, + "TestToken": { + "address": "0xc55cF4B03948D7EBc8b9E8BAD92643703811d162" + }, + "SafeMath": { + "address": "0x0F9992f7737f9ba3aceD170D4D1259cb2CEcc050" + }, + "MerkleProof": { + "address": "0x5df00E70AD165D50228DB6d8285fB6EAAc630FD7" + }, + "MerkleProofWrapper": { + "address": "0x58E01078d14142E0370526dFdAE44E4f508c844B" + }, + "UsernameRegistrar": { + "address": "0x1f1CD0569cfDE5E63Bb2108574eeb15e5bBE6efa" + } + } + }, + "rinkeby":{ + "contracts": { + "ENSRegistry": { + "address": "0xe7410170f87102DF0055eB195163A03B7F2Bff4A" + }, + "PublicResolver": { + "address": "0x5d20cf83cb385e06d2f2a892f9322cd4933eacdc" + } + } + } +} diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/config/development/genesis.json b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/config/development/genesis.json new file mode 100644 index 0000000..1a9501b --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/config/development/genesis.json @@ -0,0 +1,18 @@ +{ + "config": { + "homesteadBlock": 1, + "byzantiumBlock": 1, + "daoForkSupport": true + }, + "nonce": "0x0000000000000042", + "difficulty": "0x0", + "alloc": { + "0x3333333333333333333333333333333333333333": {"balance": "15000000000000000000"} + }, + "mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "coinbase": "0x3333333333333333333333333333333333333333", + "timestamp": "0x00", + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "extraData": "0x", + "gasLimit": "0x7a1200" +} diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/config/development/password b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/config/development/password new file mode 100644 index 0000000..c747d67 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/config/development/password @@ -0,0 +1 @@ +dev_password diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/config/ens-usernames/reservedNames.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/config/ens-usernames/reservedNames.js new file mode 100644 index 0000000..c925153 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/config/ens-usernames/reservedNames.js @@ -0,0 +1,286 @@ +exports.ReservedUsernames = [ + //Ethereum reserved words + 'eth', + 'ether', + 'ethereum', + 'etherium', + 'smartcontract', + 'smartcontracts', + 'validator', + 'ethalert', + 'ethinfo', + 'ethpromo', + 'ethnode', + 'ethnotice', + 'etheralert', + 'etherinfo', + 'etherpromo', + 'ethernode', + 'ethernotice', + 'ethereumalert', + 'ethereuminfo', + 'ethereumpromo', + 'ethereumnode', + 'ethereumnotice', + + //Ethereum ecossystem + 'mew', + 'myetherwallet', + 'etherscan', + + //Status reserved words + 'snt', + 'status', + 'stateofus', + 'statusnetwork', + 'statusnetworktoken', + + 'openbounty', + 'embark', + 'tellernetwork', + 'pushnotification', + 'notification', + 'notifications', + 'usernames', + 'names', + 'statusteller', + 'teller', + 'tellernetwork', + 'statustellernetwork', + 'registry', + 'ens', + 'group', + 'groups', + 'governance', + 'democracy', + 'delegate', + 'tribute', + 'tributetotalk', + 'tribute2talk', + 'curation', + 'curator', + 'curators', + 'sticker', + 'stickers', + 'stickermarket', + 'stickersmarket', + 'event', + 'events', + + // Crypto community reserved words + 'dex', + 'exchange', + 'token', + 'airdrop', + 'ico', + 'plasma', + 'network', + 'market', + 'reputation', + 'wallet', + 'node', + 'miner', + 'blockchain', + 'explorer', + 'giveaway', + 'crypto', + 'satoshi', + + + + // Generic reserved words + 'about', + 'account', + 'activate', + 'add', + 'admin', + 'administrator', + 'api', + 'app', + 'apps', + 'archive', + 'archives', + 'auth', + 'blog', + 'cache', + 'cancel', + 'careers', + 'cart', + 'changelog', + 'checkout', + 'codereview', + 'compare', + 'config', + 'configuration', + 'connect', + 'contact', + 'create', + 'delete', + 'direct_messages', + 'documentation', + 'download', + 'downloads', + 'edit', + 'email', + 'employment', + 'enterprise', + 'faq', + 'favorites', + 'feed', + 'feedback', + 'feeds', + 'fleet', + 'fleets', + 'follow', + 'followers', + 'following', + 'friend', + 'friends', + 'gist', + 'group', + 'groups', + 'help', + 'home', + 'hosting', + 'hostmaster', + 'idea', + 'ideas', + 'index', + 'info', + 'invitations', + 'invite', + 'is', + 'it', + 'job', + 'jobs', + 'json', + 'language', + 'languages', + 'lists', + 'login', + 'logout', + 'logs', + 'mail', + 'map', + 'maps', + 'mine', + 'mis', + 'news', + 'oauth', + 'oauth_clients', + 'offers', + 'openid', + 'order', + 'orders', + 'organization', + 'organizations', + 'plans', + 'popular', + 'post', + 'postmaster', + 'privacy', + 'projects', + 'put', + 'recruitment', + 'register', + 'remove', + 'replies', + 'root', + 'rss', + 'sales', + 'save', + 'search', + 'security', + 'sessions', + 'settings', + 'shop', + 'signup', + 'sitemap', + 'ssl', + 'ssladmin', + 'ssladministrator', + 'sslwebmaster', + 'stories', + 'styleguide', + 'subscribe', + 'subscriptions', + 'support', + 'sysadmin', + 'sysadministrator', + 'system', + 'terms', + 'tour', + 'translations', + 'trends', + 'unfollow', + 'unsubscribe', + 'update', + 'url', + 'user', + 'weather', + 'webmaster', + 'widget', + 'widgets', + 'wiki', + 'ww', + 'www', + 'wwww', + 'xfn', + 'xml', + 'xmpp', + 'yaml', + 'yml', + + // Top 50 languages by speaking population + 'chinese', + 'mandarin', + 'spanish', + 'english', + 'bengali', + 'hindi', + 'portuguese', + 'russian', + 'japanese', + 'german', + 'wu', + 'javanese', + 'korean', + 'french', + 'vietnamese', + 'telugu', + 'chinese', + 'marathi', + 'tamil', + 'turkish', + 'urdu', + 'min-nan', + 'jinyu', + 'gujarati', + 'polish', + 'arabic', + 'ukrainian', + 'italian', + 'xiang', + 'malayalam', + 'hakka', + 'kannada', + 'oriya', + 'panjabi', + 'sunda', + 'panjabi', + 'romanian', + 'bhojpuri', + 'azerbaijani', + 'farsi', + 'maithili', + 'hausa', + 'arabic', + 'burmese', + 'serbocroatian', + 'gan', + 'awadhi', + 'thai', + 'dutch', + 'yoruba', + 'sindhi', +] diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/config/namesystem.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/config/namesystem.js new file mode 100644 index 0000000..10e20d6 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/config/namesystem.js @@ -0,0 +1,6 @@ +module.exports = { + default: { + available_providers: ["ens"], + provider: "ens" + } +}; diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/config/storage.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/config/storage.js new file mode 100644 index 0000000..59ef12b --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/config/storage.js @@ -0,0 +1,35 @@ +module.exports = { + default: { + enabled: true, + ipfs_bin: "ipfs", + provider: "ipfs", + available_providers: ["ipfs"], + upload: { + host: "localhost", + port: 5001 + }, + dappConnection: [ + { + provider:"ipfs", + host: "localhost", + port: 5001, + getUrl: "http://localhost:8080/ipfs/" + } + ] + // Configuration to start Swarm in the same terminal as `embark run` + /*,account: { + address: "YOUR_ACCOUNT_ADDRESS", // Address of account accessing Swarm + password: "PATH/TO/PASSWORD/FILE" // File containing the password of the account + }, + swarmPath: "PATH/TO/SWARM/EXECUTABLE" // Path to swarm executable (default: swarm)*/ + }, + development: { + enabled: true, + provider: "ipfs", + upload: { + host: "localhost", + port: 5001, + getUrl: "http://localhost:8080/ipfs/" + } + } +}; diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/config/testnet/password b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/config/testnet/password new file mode 100644 index 0000000..414f849 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/config/testnet/password @@ -0,0 +1 @@ +test_password diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/config/webserver.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/config/webserver.js new file mode 100644 index 0000000..1814065 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/config/webserver.js @@ -0,0 +1,5 @@ +module.exports = { + enabled: true, + host: "localhost", + port: 8000 +}; diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/contracts/common/Controlled.sol b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/contracts/common/Controlled.sol new file mode 100644 index 0000000..1080223 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/contracts/common/Controlled.sol @@ -0,0 +1,22 @@ +pragma solidity ^0.4.24; + +contract Controlled { + /// @notice The address of the controller is the only address that can call + /// a function with this modifier + modifier onlyController { + require(msg.sender == controller); + _; + } + + address public controller; + + constructor() internal { + controller = msg.sender; + } + + /// @notice Changes the controller of the contract + /// @param _newController The new controller of the contract + function changeController(address _newController) public onlyController { + controller = _newController; + } +} diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/contracts/common/MerkleProof.sol b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/contracts/common/MerkleProof.sol new file mode 100644 index 0000000..9bb6ef4 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/contracts/common/MerkleProof.sol @@ -0,0 +1,43 @@ +pragma solidity ^0.4.24; + + +/** + * @title MerkleProof + * @dev Merkle proof verification based on + * https://github.com/ameensol/merkle-tree-solidity/blob/master/src/MerkleProof.sol + */ +library MerkleProof { + /** + * @dev Verifies a Merkle proof proving the existence of a leaf in a Merkle tree. Assumes that each pair of leaves + * and each pair of pre-images are sorted. + * @param _proof Merkle proof containing sibling hashes on the branch from the leaf to the root of the Merkle tree + * @param _root Merkle root + * @param _leaf Leaf of Merkle tree + */ + function verifyProof( + bytes32[] _proof, + bytes32 _root, + bytes32 _leaf + ) + internal + pure + returns (bool) + { + bytes32 computedHash = _leaf; + + for (uint256 i = 0; i < _proof.length; i++) { + bytes32 proofElement = _proof[i]; + + if (computedHash < proofElement) { + // Hash(current computed hash + current element of the proof) + computedHash = keccak256(abi.encodePacked(computedHash, proofElement)); + } else { + // Hash(current element of the proof + current computed hash) + computedHash = keccak256(abi.encodePacked(proofElement, computedHash)); + } + } + + // Check if the computed hash (root) is equal to the provided root + return computedHash == _root; + } +} diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/contracts/common/MessageSigned.sol b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/contracts/common/MessageSigned.sol new file mode 100644 index 0000000..ba112f1 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/contracts/common/MessageSigned.sol @@ -0,0 +1,77 @@ +pragma solidity ^0.4.24; + +/** + * @notice Uses ethereum signed messages + */ +contract MessageSigned { + + constructor() internal { + + } + + /** + * @notice recovers address who signed the message + * @param _signHash operation ethereum signed message hash + * @param _messageSignature message `_signHash` signature + */ + function recoverAddress( + bytes32 _signHash, + bytes _messageSignature + ) + internal + pure + returns(address) + { + uint8 v; + bytes32 r; + bytes32 s; + (v,r,s) = signatureSplit(_messageSignature); + return ecrecover( + _signHash, + v, + r, + s + ); + } + + /** + * @notice Hash a hash with `"\x19Ethereum Signed Message:\n32"` + * @param _hash Sign to hash. + * @return signHash Hash to be signed. + */ + function getSignHash( + bytes32 _hash + ) + pure + internal + returns (bytes32 signHash) + { + signHash = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", _hash)); + } + + /** + * @dev divides bytes signature into `uint8 v, bytes32 r, bytes32 s` + */ + function signatureSplit(bytes _signature) + pure + internal + returns (uint8 v, bytes32 r, bytes32 s) + { + // The signature format is a compact form of: + // {bytes32 r}{bytes32 s}{uint8 v} + // Compact means, uint8 is not padded to 32 bytes. + assembly { + r := mload(add(_signature, 32)) + s := mload(add(_signature, 64)) + // Here we are loading the last 32 bytes, including 31 bytes + // of 's'. There is no 'mload8' to do this. + // + // 'byte' is not working due to the Solidity parser, so lets + // use the second best option, 'and' + v := and(mload(add(_signature, 65)), 0xff) + } + + require(v == 27 || v == 28); + } + +} \ No newline at end of file diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/contracts/common/Owned.sol b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/contracts/common/Owned.sol new file mode 100644 index 0000000..2e78af6 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/contracts/common/Owned.sol @@ -0,0 +1,36 @@ +pragma solidity ^0.4.24; + +/// @dev `Owned` is a base level contract that assigns an `owner` that can be +/// later changed +contract Owned { + + /// @dev `owner` is the only address that can call a function with this + /// modifier + modifier onlyOwner() { + require(msg.sender == owner); + _; + } + + address public owner; + + /// @notice The Constructor assigns the message sender to be `owner` + constructor() internal { + owner = msg.sender; + } + + address public newOwner; + + /// @notice `owner` can step down and assign some other address to this role + /// @param _newOwner The address of the new owner. 0x0 can be used to create + /// an unowned neutral vault, however that cannot be undone + function changeOwner(address _newOwner) public onlyOwner { + newOwner = _newOwner; + } + + + function acceptOwnership() public { + if (msg.sender == newOwner) { + owner = newOwner; + } + } +} \ No newline at end of file diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/contracts/common/SafeMath.sol b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/contracts/common/SafeMath.sol new file mode 100644 index 0000000..06a62d9 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/contracts/common/SafeMath.sol @@ -0,0 +1,46 @@ +pragma solidity ^0.4.24; + +/** + * Math operations with safety checks + */ +library SafeMath { + function mul(uint a, uint b) internal pure returns (uint) { + uint c = a * b; + assert(a == 0 || c / a == b); + return c; + } + + function div(uint a, uint b) internal pure returns (uint) { + // assert(b > 0); // Solidity automatically throws when dividing by 0 + uint c = a / b; + // assert(a == b * c + a % b); // There is no case in which this doesn't hold + return c; + } + + function sub(uint a, uint b) internal pure returns (uint) { + assert(b <= a); + return a - b; + } + + function add(uint a, uint b) internal pure returns (uint) { + uint c = a + b; + assert(c >= a); + return c; + } + + function max64(uint64 a, uint64 b) internal pure returns (uint64) { + return a >= b ? a : b; + } + + function min64(uint64 a, uint64 b) internal pure returns (uint64) { + return a < b ? a : b; + } + + function max256(uint256 a, uint256 b) internal pure returns (uint256) { + return a >= b ? a : b; + } + + function min256(uint256 a, uint256 b) internal pure returns (uint256) { + return a < b ? a : b; + } +} diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/contracts/ens/ENS.sol b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/contracts/ens/ENS.sol new file mode 100644 index 0000000..36e4ad4 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/contracts/ens/ENS.sol @@ -0,0 +1,26 @@ +pragma solidity ^0.4.24; + +interface ENS { + + // Logged when the owner of a node assigns a new owner to a subnode. + event NewOwner(bytes32 indexed node, bytes32 indexed label, address owner); + + // Logged when the owner of a node transfers ownership to a new account. + event Transfer(bytes32 indexed node, address owner); + + // Logged when the resolver for a node changes. + event NewResolver(bytes32 indexed node, address resolver); + + // Logged when the TTL of a node changes + event NewTTL(bytes32 indexed node, uint64 ttl); + + + function setSubnodeOwner(bytes32 node, bytes32 label, address owner) public; + function setResolver(bytes32 node, address resolver) public; + function setOwner(bytes32 node, address owner) public; + function setTTL(bytes32 node, uint64 ttl) public; + function owner(bytes32 node) public view returns (address); + function resolver(bytes32 node) public view returns (address); + function ttl(bytes32 node) public view returns (uint64); + +} diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/contracts/ens/ENSRegistry.sol b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/contracts/ens/ENSRegistry.sol new file mode 100644 index 0000000..d849b41 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/contracts/ens/ENSRegistry.sol @@ -0,0 +1,99 @@ +pragma solidity ^0.4.24; + +import "./ENS.sol"; + +/** + * The ENS registry contract. + */ +contract ENSRegistry is ENS { + struct Record { + address owner; + address resolver; + uint64 ttl; + } + + mapping (bytes32 => Record) records; + + // Permits modifications only by the owner of the specified node. + modifier only_owner(bytes32 node) { + require(records[node].owner == msg.sender); + _; + } + + /** + * @dev Constructs a new ENS registrar. + */ + constructor() public { + records[0x0].owner = msg.sender; + } + + /** + * @dev Transfers ownership of a node to a new address. May only be called by the current owner of the node. + * @param node The node to transfer ownership of. + * @param owner The address of the new owner. + */ + function setOwner(bytes32 node, address owner) public only_owner(node) { + emit Transfer(node, owner); + records[node].owner = owner; + } + + /** + * @dev Transfers ownership of a subnode keccak256(node, label) to a new address. May only be called by the owner of the parent node. + * @param node The parent node. + * @param label The hash of the label specifying the subnode. + * @param owner The address of the new owner. + */ + function setSubnodeOwner(bytes32 node, bytes32 label, address owner) public only_owner(node) { + bytes32 subnode = keccak256(abi.encodePacked(node, label)); + emit NewOwner(node, label, owner); + records[subnode].owner = owner; + } + + /** + * @dev Sets the resolver address for the specified node. + * @param node The node to update. + * @param resolver The address of the resolver. + */ + function setResolver(bytes32 node, address resolver) public only_owner(node) { + emit NewResolver(node, resolver); + records[node].resolver = resolver; + } + + /** + * @dev Sets the TTL for the specified node. + * @param node The node to update. + * @param ttl The TTL in seconds. + */ + function setTTL(bytes32 node, uint64 ttl) public only_owner(node) { + emit NewTTL(node, ttl); + records[node].ttl = ttl; + } + + /** + * @dev Returns the address that owns the specified node. + * @param node The specified node. + * @return address of the owner. + */ + function owner(bytes32 node) public view returns (address) { + return records[node].owner; + } + + /** + * @dev Returns the address of the resolver for the specified node. + * @param node The specified node. + * @return address of the resolver. + */ + function resolver(bytes32 node) public view returns (address) { + return records[node].resolver; + } + + /** + * @dev Returns the TTL of a node, and any records associated with it. + * @param node The specified node. + * @return ttl of the node. + */ + function ttl(bytes32 node) public view returns (uint64) { + return records[node].ttl; + } + +} diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/contracts/ens/PublicResolver.sol b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/contracts/ens/PublicResolver.sol new file mode 100644 index 0000000..b89b555 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/contracts/ens/PublicResolver.sol @@ -0,0 +1,238 @@ +pragma solidity ^0.4.24; + +import "./ENS.sol"; + +/** + * A simple resolver anyone can use; only allows the owner of a node to set its + * address. + */ +contract PublicResolver { + + bytes4 constant INTERFACE_META_ID = 0x01ffc9a7; + bytes4 constant ADDR_INTERFACE_ID = 0x3b3b57de; + bytes4 constant CONTENT_INTERFACE_ID = 0xd8389dc5; + bytes4 constant NAME_INTERFACE_ID = 0x691f3431; + bytes4 constant ABI_INTERFACE_ID = 0x2203ab56; + bytes4 constant PUBKEY_INTERFACE_ID = 0xc8690233; + bytes4 constant TEXT_INTERFACE_ID = 0x59d1d43c; + bytes4 constant MULTIHASH_INTERFACE_ID = 0xe89401a1; + + event AddrChanged(bytes32 indexed node, address a); + event ContentChanged(bytes32 indexed node, bytes32 hash); + event NameChanged(bytes32 indexed node, string name); + event ABIChanged(bytes32 indexed node, uint256 indexed contentType); + event PubkeyChanged(bytes32 indexed node, bytes32 x, bytes32 y); + event TextChanged(bytes32 indexed node, string indexedKey, string key); + event MultihashChanged(bytes32 indexed node, bytes hash); + + struct PublicKey { + bytes32 x; + bytes32 y; + } + + struct Record { + address addr; + bytes32 content; + string name; + PublicKey pubkey; + mapping(string=>string) text; + mapping(uint256=>bytes) abis; + bytes multihash; + } + + ENS ens; + + mapping (bytes32 => Record) records; + + modifier only_owner(bytes32 node) { + require(ens.owner(node) == msg.sender); + _; + } + + /** + * Constructor. + * @param ensAddr The ENS registrar contract. + */ + constructor(ENS ensAddr) public { + ens = ensAddr; + } + + /** + * Sets the address associated with an ENS node. + * May only be called by the owner of that node in the ENS registry. + * @param node The node to update. + * @param addr The address to set. + */ + function setAddr(bytes32 node, address addr) public only_owner(node) { + records[node].addr = addr; + emit AddrChanged(node, addr); + } + + /** + * Sets the content hash associated with an ENS node. + * May only be called by the owner of that node in the ENS registry. + * Note that this resource type is not standardized, and will likely change + * in future to a resource type based on multihash. + * @param node The node to update. + * @param hash The content hash to set + */ + function setContent(bytes32 node, bytes32 hash) public only_owner(node) { + records[node].content = hash; + emit ContentChanged(node, hash); + } + + /** + * Sets the multihash associated with an ENS node. + * May only be called by the owner of that node in the ENS registry. + * @param node The node to update. + * @param hash The multihash to set + */ + function setMultihash(bytes32 node, bytes hash) public only_owner(node) { + records[node].multihash = hash; + emit MultihashChanged(node, hash); + } + + /** + * Sets the name associated with an ENS node, for reverse records. + * May only be called by the owner of that node in the ENS registry. + * @param node The node to update. + * @param name The name to set. + */ + function setName(bytes32 node, string name) public only_owner(node) { + records[node].name = name; + emit NameChanged(node, name); + } + + /** + * Sets the ABI associated with an ENS node. + * Nodes may have one ABI of each content type. To remove an ABI, set it to + * the empty string. + * @param node The node to update. + * @param contentType The content type of the ABI + * @param data The ABI data. + */ + function setABI(bytes32 node, uint256 contentType, bytes data) public only_owner(node) { + // Content types must be powers of 2 + require(((contentType - 1) & contentType) == 0); + + records[node].abis[contentType] = data; + emit ABIChanged(node, contentType); + } + + /** + * Sets the SECP256k1 public key associated with an ENS node. + * @param node The ENS node to query + * @param x the X coordinate of the curve point for the public key. + * @param y the Y coordinate of the curve point for the public key. + */ + function setPubkey(bytes32 node, bytes32 x, bytes32 y) public only_owner(node) { + records[node].pubkey = PublicKey(x, y); + emit PubkeyChanged(node, x, y); + } + + /** + * Sets the text data associated with an ENS node and key. + * May only be called by the owner of that node in the ENS registry. + * @param node The node to update. + * @param key The key to set. + * @param value The text data value to set. + */ + function setText(bytes32 node, string key, string value) public only_owner(node) { + records[node].text[key] = value; + emit TextChanged(node, key, key); + } + + /** + * Returns the text data associated with an ENS node and key. + * @param node The ENS node to query. + * @param key The text data key to query. + * @return The associated text data. + */ + function text(bytes32 node, string key) public view returns (string) { + return records[node].text[key]; + } + + /** + * Returns the SECP256k1 public key associated with an ENS node. + * Defined in EIP 619. + * @param node The ENS node to query + * @return x, y the X and Y coordinates of the curve point for the public key. + */ + function pubkey(bytes32 node) public view returns (bytes32 x, bytes32 y) { + return (records[node].pubkey.x, records[node].pubkey.y); + } + + /** + * Returns the ABI associated with an ENS node. + * Defined in EIP205. + * @param node The ENS node to query + * @param contentTypes A bitwise OR of the ABI formats accepted by the caller. + * @return contentType The content type of the return value + * @return data The ABI data + */ + function ABI(bytes32 node, uint256 contentTypes) public view returns (uint256 contentType, bytes data) { + Record storage record = records[node]; + for (contentType = 1; contentType <= contentTypes; contentType <<= 1) { + if ((contentType & contentTypes) != 0 && record.abis[contentType].length > 0) { + data = record.abis[contentType]; + return; + } + } + contentType = 0; + } + + /** + * Returns the name associated with an ENS node, for reverse records. + * Defined in EIP181. + * @param node The ENS node to query. + * @return The associated name. + */ + function name(bytes32 node) public view returns (string) { + return records[node].name; + } + + /** + * Returns the content hash associated with an ENS node. + * Note that this resource type is not standardized, and will likely change + * in future to a resource type based on multihash. + * @param node The ENS node to query. + * @return The associated content hash. + */ + function content(bytes32 node) public view returns (bytes32) { + return records[node].content; + } + + /** + * Returns the multihash associated with an ENS node. + * @param node The ENS node to query. + * @return The associated multihash. + */ + function multihash(bytes32 node) public view returns (bytes) { + return records[node].multihash; + } + + /** + * Returns the address associated with an ENS node. + * @param node The ENS node to query. + * @return The associated address. + */ + function addr(bytes32 node) public view returns (address) { + return records[node].addr; + } + + /** + * Returns true if the resolver implements the interface specified by the provided hash. + * @param interfaceID The ID of the interface to check for. + * @return True if the contract implements the requested interface. + */ + function supportsInterface(bytes4 interfaceID) public pure returns (bool) { + return interfaceID == ADDR_INTERFACE_ID || + interfaceID == CONTENT_INTERFACE_ID || + interfaceID == NAME_INTERFACE_ID || + interfaceID == ABI_INTERFACE_ID || + interfaceID == PUBKEY_INTERFACE_ID || + interfaceID == TEXT_INTERFACE_ID || + interfaceID == MULTIHASH_INTERFACE_ID || + interfaceID == INTERFACE_META_ID; + } +} diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/contracts/ens/ResolverInterface.sol b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/contracts/ens/ResolverInterface.sol new file mode 100644 index 0000000..2139672 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/contracts/ens/ResolverInterface.sol @@ -0,0 +1,10 @@ +pragma solidity ^0.4.24; + +contract ResolverInterface { + function PublicResolver(address ensAddr) public; + function setAddr(bytes32 node, address addr) public; + function setHash(bytes32 node, bytes32 hash) public; + function addr(bytes32 node) public view returns (address); + function hash(bytes32 node) public view returns (bytes32); + function supportsInterface(bytes4 interfaceID) public pure returns (bool); +} diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/contracts/registry/UsernameRegistrar.sol b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/contracts/registry/UsernameRegistrar.sol new file mode 100644 index 0000000..b929a21 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/contracts/registry/UsernameRegistrar.sol @@ -0,0 +1,776 @@ +pragma solidity ^0.4.24; + +import "../common/MerkleProof.sol"; +import "../common/Controlled.sol"; +import "../token/ERC20Token.sol"; +import "../token/ApproveAndCallFallBack.sol"; +import "../ens/ENS.sol"; +import "../ens/PublicResolver.sol"; + +/** + * @author Ricardo Guilherme Schmidt (Status Research & Development GmbH) + * @notice Registers usernames as ENS subnodes of the domain `ensNode` + */ +contract UsernameRegistrar is Controlled, ApproveAndCallFallBack { + + ERC20Token public token; + ENS public ensRegistry; + PublicResolver public resolver; + address public parentRegistry; + + uint256 public constant releaseDelay = 365 days; + mapping (bytes32 => Account) public accounts; + mapping (bytes32 => SlashReserve) reservedSlashers; + + //Slashing conditions + uint256 public usernameMinLength; + bytes32 public reservedUsernamesMerkleRoot; + + event RegistryState(RegistrarState state); + event RegistryPrice(uint256 price); + event RegistryMoved(address newRegistry); + event UsernameOwner(bytes32 indexed nameHash, address owner); + + enum RegistrarState { Inactive, Active, Moved } + bytes32 public ensNode; + uint256 public price; + RegistrarState public state; + uint256 public reserveAmount; + + struct Account { + uint256 balance; + uint256 creationTime; + address owner; + } + + struct SlashReserve { + address reserver; + uint256 blockNumber; + } + + /** + * @notice Callable only by `parentRegistry()` to continue migration of ENSSubdomainRegistry. + */ + modifier onlyParentRegistry { + require(msg.sender == parentRegistry, "Migration only."); + _; + } + + /** + * @notice Initializes UsernameRegistrar contract. + * The only parameter from this list that can be changed later is `_resolver`. + * Other updates require a new contract and migration of domain. + * @param _token ERC20 token with optional `approveAndCall(address,uint256,bytes)` for locking fee. + * @param _ensRegistry Ethereum Name Service root contract address. + * @param _resolver Public Resolver for resolving usernames. + * @param _ensNode ENS node (domain) being used for usernames subnodes (subdomain) + * @param _usernameMinLength Minimum length of usernames + * @param _reservedUsernamesMerkleRoot Merkle root of reserved usernames + * @param _parentRegistry Address of old registry (if any) for optional account migration. + */ + constructor( + ERC20Token _token, + ENS _ensRegistry, + PublicResolver _resolver, + bytes32 _ensNode, + uint256 _usernameMinLength, + bytes32 _reservedUsernamesMerkleRoot, + address _parentRegistry + ) + public + { + require(address(_token) != address(0), "No ERC20Token address defined."); + require(address(_ensRegistry) != address(0), "No ENS address defined."); + require(address(_resolver) != address(0), "No Resolver address defined."); + require(_ensNode != bytes32(0), "No ENS node defined."); + token = _token; + ensRegistry = _ensRegistry; + resolver = _resolver; + ensNode = _ensNode; + usernameMinLength = _usernameMinLength; + reservedUsernamesMerkleRoot = _reservedUsernamesMerkleRoot; + parentRegistry = _parentRegistry; + setState(RegistrarState.Inactive); + } + + /** + * @notice Registers `_label` username to `ensNode` setting msg.sender as owner. + * Terms of name registration: + * - SNT is deposited, not spent; the amount is locked up for 1 year. + * - After 1 year, the user can release the name and receive their deposit back (at any time). + * - User deposits are completely protected. The contract controller cannot access them. + * - User's address(es) will be publicly associated with the ENS name. + * - User must authorise the contract to transfer `price` `token.name()` on their behalf. + * - Usernames registered with less then `usernameMinLength` characters can be slashed. + * - Usernames contained in the merkle tree of root `reservedUsernamesMerkleRoot` can be slashed. + * - Usernames starting with `0x` and bigger then 12 characters can be slashed. + * - If terms of the contract change—e.g. Status makes contract upgrades—the user has the right to release the username and get their deposit back. + * @param _label Choosen unowned username hash. + * @param _account Optional address to set at public resolver. + * @param _pubkeyA Optional pubkey part A to set at public resolver. + * @param _pubkeyB Optional pubkey part B to set at public resolver. + */ + function register( + bytes32 _label, + address _account, + bytes32 _pubkeyA, + bytes32 _pubkeyB + ) + external + returns(bytes32 namehash) + { + return registerUser(msg.sender, _label, _account, _pubkeyA, _pubkeyB); + } + + /** + * @notice Release username and retrieve locked fee, needs to be called + * after `releasePeriod` from creation time by ENS registry owner of domain + * or anytime by account owner when domain migrated to a new registry. + * @param _label Username hash. + */ + function release( + bytes32 _label + ) + external + { + bytes32 namehash = keccak256(abi.encodePacked(ensNode, _label)); + Account memory account = accounts[_label]; + require(account.creationTime > 0, "Username not registered."); + if (state == RegistrarState.Active) { + require(msg.sender == ensRegistry.owner(namehash), "Not owner of ENS node."); + require(block.timestamp > account.creationTime + releaseDelay, "Release period not reached."); + } else { + require(msg.sender == account.owner, "Not the former account owner."); + } + delete accounts[_label]; + if (account.balance > 0) { + reserveAmount -= account.balance; + require(token.transfer(msg.sender, account.balance), "Transfer failed"); + } + if (state == RegistrarState.Active) { + ensRegistry.setSubnodeOwner(ensNode, _label, address(this)); + ensRegistry.setResolver(namehash, address(0)); + ensRegistry.setOwner(namehash, address(0)); + } else { + address newOwner = ensRegistry.owner(ensNode); + //Low level call, case dropUsername not implemented or failing, proceed release. + //Invert (!) to supress warning, return of this call have no use. + !newOwner.call.gas(80000)( + abi.encodeWithSignature( + "dropUsername(bytes32)", + _label + ) + ); + } + emit UsernameOwner(namehash, address(0)); + } + + /** + * @notice update account owner, should be called by new ens node owner + * to update this contract registry, otherwise former owner can release + * if domain is moved to a new registry. + * @param _label Username hash. + **/ + function updateAccountOwner( + bytes32 _label + ) + external + { + bytes32 namehash = keccak256(abi.encodePacked(ensNode, _label)); + require(msg.sender == ensRegistry.owner(namehash), "Caller not owner of ENS node."); + require(accounts[_label].creationTime > 0, "Username not registered."); + require(ensRegistry.owner(ensNode) == address(this), "Registry not owner of registry."); + accounts[_label].owner = msg.sender; + emit UsernameOwner(namehash, msg.sender); + } + + /** + * @notice secretly reserve the slashing reward to `msg.sender` + * @param _secret keccak256(abi.encodePacked(namehash, creationTime, reserveSecret)) + */ + function reserveSlash(bytes32 _secret) external { + require(reservedSlashers[_secret].blockNumber == 0, "Already Reserved"); + reservedSlashers[_secret] = SlashReserve(msg.sender, block.number); + } + + /** + * @notice Slash username smaller then `usernameMinLength`. + * @param _username Raw value of offending username. + */ + function slashSmallUsername( + string _username, + uint256 _reserveSecret + ) + external + { + bytes memory username = bytes(_username); + require(username.length < usernameMinLength, "Not a small username."); + slashUsername(username, _reserveSecret); + } + + /** + * @notice Slash username starting with "0x" and with length greater than 12. + * @param _username Raw value of offending username. + */ + function slashAddressLikeUsername( + string _username, + uint256 _reserveSecret + ) + external + { + bytes memory username = bytes(_username); + require(username.length > 12, "Too small to look like an address."); + require(username[0] == byte("0"), "First character need to be 0"); + require(username[1] == byte("x"), "Second character need to be x"); + for(uint i = 2; i < 7; i++){ + byte b = username[i]; + require((b >= 48 && b <= 57) || (b >= 97 && b <= 102), "Does not look like an address"); + } + slashUsername(username, _reserveSecret); + } + + /** + * @notice Slash username that is exactly a reserved name. + * @param _username Raw value of offending username. + * @param _proof Merkle proof that name is listed on merkle tree. + */ + function slashReservedUsername( + string _username, + bytes32[] _proof, + uint256 _reserveSecret + ) + external + { + bytes memory username = bytes(_username); + require( + MerkleProof.verifyProof( + _proof, + reservedUsernamesMerkleRoot, + keccak256(username) + ), + "Invalid Proof." + ); + slashUsername(username, _reserveSecret); + } + + /** + * @notice Slash username that contains a non alphanumeric character. + * @param _username Raw value of offending username. + * @param _offendingPos Position of non alphanumeric character. + */ + function slashInvalidUsername( + string _username, + uint256 _offendingPos, + uint256 _reserveSecret + ) + external + { + bytes memory username = bytes(_username); + require(username.length > _offendingPos, "Invalid position."); + byte b = username[_offendingPos]; + + require(!((b >= 48 && b <= 57) || (b >= 97 && b <= 122)), "Not invalid character."); + + slashUsername(username, _reserveSecret); + } + + /** + * @notice Clear resolver and ownership of unowned subdomians. + * @param _labels Sequence to erase. + */ + function eraseNode( + bytes32[] _labels + ) + external + { + uint len = _labels.length; + require(len != 0, "Nothing to erase"); + bytes32 label = _labels[len - 1]; + bytes32 subnode = keccak256(abi.encodePacked(ensNode, label)); + require(ensRegistry.owner(subnode) == address(0), "First slash/release top level subdomain"); + ensRegistry.setSubnodeOwner(ensNode, label, address(this)); + if(len > 1) { + eraseNodeHierarchy(len - 2, _labels, subnode); + } + ensRegistry.setResolver(subnode, 0); + ensRegistry.setOwner(subnode, 0); + } + + /** + * @notice Migrate account to new registry, opt-in to new contract. + * @param _label Username hash. + **/ + function moveAccount( + bytes32 _label, + UsernameRegistrar _newRegistry + ) + external + { + require(state == RegistrarState.Moved, "Wrong contract state"); + require(msg.sender == accounts[_label].owner, "Callable only by account owner."); + require(ensRegistry.owner(ensNode) == address(_newRegistry), "Wrong update"); + Account memory account = accounts[_label]; + delete accounts[_label]; + + token.approve(_newRegistry, account.balance); + _newRegistry.migrateUsername( + _label, + account.balance, + account.creationTime, + account.owner + ); + } + + /** + * @notice Activate registration. + * @param _price The price of registration. + */ + function activate( + uint256 _price + ) + external + onlyController + { + require(state == RegistrarState.Inactive, "Registry state is not Inactive"); + require(ensRegistry.owner(ensNode) == address(this), "Registry does not own registry"); + price = _price; + setState(RegistrarState.Active); + emit RegistryPrice(_price); + } + + /** + * @notice Updates Public Resolver for resolving users. + * @param _resolver New PublicResolver. + */ + function setResolver( + address _resolver + ) + external + onlyController + { + resolver = PublicResolver(_resolver); + } + + /** + * @notice Updates registration price. + * @param _price New registration price. + */ + function updateRegistryPrice( + uint256 _price + ) + external + onlyController + { + require(state == RegistrarState.Active, "Registry not owned"); + price = _price; + emit RegistryPrice(_price); + } + + /** + * @notice Transfer ownership of ensNode to `_newRegistry`. + * Usernames registered are not affected, but they would be able to instantly release. + * @param _newRegistry New UsernameRegistrar for hodling `ensNode` node. + */ + function moveRegistry( + UsernameRegistrar _newRegistry + ) + external + onlyController + { + require(_newRegistry != this, "Cannot move to self."); + require(ensRegistry.owner(ensNode) == address(this), "Registry not owned anymore."); + setState(RegistrarState.Moved); + ensRegistry.setOwner(ensNode, _newRegistry); + _newRegistry.migrateRegistry(price); + emit RegistryMoved(_newRegistry); + } + + /** + * @notice Opt-out migration of username from `parentRegistry()`. + * Clear ENS resolver and subnode owner. + * @param _label Username hash. + */ + function dropUsername( + bytes32 _label + ) + external + onlyParentRegistry + { + require(accounts[_label].creationTime == 0, "Already migrated"); + bytes32 namehash = keccak256(abi.encodePacked(ensNode, _label)); + ensRegistry.setSubnodeOwner(ensNode, _label, address(this)); + ensRegistry.setResolver(namehash, address(0)); + ensRegistry.setOwner(namehash, address(0)); + } + + /** + * @notice Withdraw not reserved tokens + * @param _token Address of ERC20 withdrawing excess, or address(0) if want ETH. + * @param _beneficiary Address to send the funds. + **/ + function withdrawExcessBalance( + address _token, + address _beneficiary + ) + external + onlyController + { + require(_beneficiary != address(0), "Cannot burn token"); + if (_token == address(0)) { + _beneficiary.transfer(address(this).balance); + } else { + ERC20Token excessToken = ERC20Token(_token); + uint256 amount = excessToken.balanceOf(address(this)); + if(_token == address(token)){ + require(amount > reserveAmount, "Is not excess"); + amount -= reserveAmount; + } else { + require(amount > 0, "No balance"); + } + excessToken.transfer(_beneficiary, amount); + } + } + + /** + * @notice Withdraw ens nodes not belonging to this contract. + * @param _domainHash Ens node namehash. + * @param _beneficiary New owner of ens node. + **/ + function withdrawWrongNode( + bytes32 _domainHash, + address _beneficiary + ) + external + onlyController + { + require(_beneficiary != address(0), "Cannot burn node"); + require(_domainHash != ensNode, "Cannot withdraw main node"); + require(ensRegistry.owner(_domainHash) == address(this), "Not owner of this node"); + ensRegistry.setOwner(_domainHash, _beneficiary); + } + + /** + * @notice Gets registration price. + * @return Registration price. + **/ + function getPrice() + external + view + returns(uint256 registryPrice) + { + return price; + } + + /** + * @notice reads amount tokens locked in username + * @param _label Username hash. + * @return Locked username balance. + **/ + function getAccountBalance(bytes32 _label) + external + view + returns(uint256 accountBalance) + { + accountBalance = accounts[_label].balance; + } + + /** + * @notice reads username account owner at this contract, + * which can release or migrate in case of upgrade. + * @param _label Username hash. + * @return Username account owner. + **/ + function getAccountOwner(bytes32 _label) + external + view + returns(address owner) + { + owner = accounts[_label].owner; + } + + /** + * @notice reads when the account was registered + * @param _label Username hash. + * @return Registration time. + **/ + function getCreationTime(bytes32 _label) + external + view + returns(uint256 creationTime) + { + creationTime = accounts[_label].creationTime; + } + + /** + * @notice calculate time where username can be released + * @param _label Username hash. + * @return Exact time when username can be released. + **/ + function getReleaseTime(bytes32 _label) + external + view + returns(uint256 releaseTime) + { + uint256 creationTime = accounts[_label].creationTime; + if (creationTime > 0){ + releaseTime = creationTime + releaseDelay; + } + } + + /** + * @notice calculate reward part an account could payout on slash + * @param _label Username hash. + * @return Part of reward + **/ + function getSlashRewardPart(bytes32 _label) + external + view + returns(uint256 partReward) + { + uint256 balance = accounts[_label].balance; + if (balance > 0) { + partReward = balance / 3; + } + } + + /** + * @notice Support for "approveAndCall". Callable only by `token()`. + * @param _from Who approved. + * @param _amount Amount being approved, need to be equal `getPrice()`. + * @param _token Token being approved, need to be equal `token()`. + * @param _data Abi encoded data with selector of `register(bytes32,address,bytes32,bytes32)`. + */ + function receiveApproval( + address _from, + uint256 _amount, + address _token, + bytes _data + ) + public + { + require(_amount == price, "Wrong value"); + require(_token == address(token), "Wrong token"); + require(_token == address(msg.sender), "Wrong call"); + require(_data.length <= 132, "Wrong data length"); + bytes4 sig; + bytes32 label; + address account; + bytes32 pubkeyA; + bytes32 pubkeyB; + (sig, label, account, pubkeyA, pubkeyB) = abiDecodeRegister(_data); + require( + sig == bytes4(0xb82fedbb), //bytes4(keccak256("register(bytes32,address,bytes32,bytes32)")) + "Wrong method selector" + ); + registerUser(_from, label, account, pubkeyA, pubkeyB); + } + + /** + * @notice Continues migration of username to new registry. + * @param _label Username hash. + * @param _tokenBalance Amount being transfered from `parentRegistry()`. + * @param _creationTime Time user registrated in `parentRegistry()` is preserved. + * @param _accountOwner Account owner which migrated the account. + **/ + function migrateUsername( + bytes32 _label, + uint256 _tokenBalance, + uint256 _creationTime, + address _accountOwner + ) + external + onlyParentRegistry + { + if (_tokenBalance > 0) { + require( + token.transferFrom( + parentRegistry, + address(this), + _tokenBalance + ), + "Error moving funds from old registar." + ); + reserveAmount += _tokenBalance; + } + accounts[_label] = Account(_tokenBalance, _creationTime, _accountOwner); + } + + /** + * @dev callable only by parent registry to continue migration + * of registry and activate registration. + * @param _price The price of registration. + **/ + function migrateRegistry( + uint256 _price + ) + external + onlyParentRegistry + { + require(state == RegistrarState.Inactive, "Not Inactive"); + require(ensRegistry.owner(ensNode) == address(this), "ENS registry owner not transfered."); + price = _price; + setState(RegistrarState.Active); + emit RegistryPrice(_price); + } + + /** + * @notice Registers `_label` username to `ensNode` setting msg.sender as owner. + * @param _owner Address registering the user and paying registry price. + * @param _label Choosen unowned username hash. + * @param _account Optional address to set at public resolver. + * @param _pubkeyA Optional pubkey part A to set at public resolver. + * @param _pubkeyB Optional pubkey part B to set at public resolver. + */ + function registerUser( + address _owner, + bytes32 _label, + address _account, + bytes32 _pubkeyA, + bytes32 _pubkeyB + ) + internal + returns(bytes32 namehash) + { + require(state == RegistrarState.Active, "Registry unavailable."); + namehash = keccak256(abi.encodePacked(ensNode, _label)); + require(ensRegistry.owner(namehash) == address(0), "ENS node already owned."); + require(accounts[_label].creationTime == 0, "Username already registered."); + accounts[_label] = Account(price, block.timestamp, _owner); + if(price > 0) { + require(token.allowance(_owner, address(this)) >= price, "Unallowed to spend."); + require( + token.transferFrom( + _owner, + address(this), + price + ), + "Transfer failed" + ); + reserveAmount += price; + } + + bool resolvePubkey = _pubkeyA != 0 || _pubkeyB != 0; + bool resolveAccount = _account != address(0); + if (resolvePubkey || resolveAccount) { + //set to self the ownership to setup initial resolver + ensRegistry.setSubnodeOwner(ensNode, _label, address(this)); + ensRegistry.setResolver(namehash, resolver); //default resolver + if (resolveAccount) { + resolver.setAddr(namehash, _account); + } + if (resolvePubkey) { + resolver.setPubkey(namehash, _pubkeyA, _pubkeyB); + } + ensRegistry.setOwner(namehash, _owner); + } else { + //transfer ownership of subdone directly to registrant + ensRegistry.setSubnodeOwner(ensNode, _label, _owner); + } + emit UsernameOwner(namehash, _owner); + } + + /** + * @dev Removes account hash of `_username` and send account.balance to msg.sender. + * @param _username Username being slashed. + */ + function slashUsername( + bytes _username, + uint256 _reserveSecret + ) + internal + { + bytes32 label = keccak256(_username); + bytes32 namehash = keccak256(abi.encodePacked(ensNode, label)); + uint256 amountToTransfer = 0; + uint256 creationTime = accounts[label].creationTime; + address owner = ensRegistry.owner(namehash); + if(creationTime == 0) { + require( + owner != address(0) || + ensRegistry.resolver(namehash) != address(0), + "Nothing to slash." + ); + } else { + assert(creationTime != block.timestamp); + amountToTransfer = accounts[label].balance; + delete accounts[label]; + } + + ensRegistry.setSubnodeOwner(ensNode, label, address(this)); + ensRegistry.setResolver(namehash, address(0)); + ensRegistry.setOwner(namehash, address(0)); + + if (amountToTransfer > 0) { + reserveAmount -= amountToTransfer; + uint256 partialDeposit = amountToTransfer / 3; + amountToTransfer = partialDeposit * 2; // reserve 1/3 to network (controller) + bytes32 secret = keccak256(abi.encodePacked(namehash, creationTime, _reserveSecret)); + SlashReserve memory reserve = reservedSlashers[secret]; + require(reserve.reserver != address(0), "Not reserved."); + require(reserve.blockNumber < block.number, "Cannot reveal in same block"); + delete reservedSlashers[secret]; + + require(token.transfer(reserve.reserver, amountToTransfer), "Error in transfer."); + } + emit UsernameOwner(namehash, address(0)); + } + + function setState(RegistrarState _state) private { + state = _state; + emit RegistryState(_state); + } + + /** + * @notice recursively erase all _labels in _subnode + * @param _idx recursive position of _labels to erase + * @param _labels list of subnode labes + * @param _subnode subnode being erased + */ + function eraseNodeHierarchy( + uint _idx, + bytes32[] _labels, + bytes32 _subnode + ) + private + { + // Take ownership of the node + ensRegistry.setSubnodeOwner(_subnode, _labels[_idx], address(this)); + bytes32 subnode = keccak256(abi.encodePacked(_subnode, _labels[_idx])); + + // Recurse if there are more labels + if (_idx > 0) { + eraseNodeHierarchy(_idx - 1, _labels, subnode); + } + + // Erase the resolver and owner records + ensRegistry.setResolver(subnode, 0); + ensRegistry.setOwner(subnode, 0); + } + + /** + * @dev Decodes abi encoded data with selector for "register(bytes32,address,bytes32,bytes32)". + * @param _data Abi encoded data. + * @return Decoded registry call. + */ + function abiDecodeRegister( + bytes _data + ) + private + pure + returns( + bytes4 sig, + bytes32 label, + address account, + bytes32 pubkeyA, + bytes32 pubkeyB + ) + { + assembly { + sig := mload(add(_data, add(0x20, 0))) + label := mload(add(_data, 36)) + account := mload(add(_data, 68)) + pubkeyA := mload(add(_data, 100)) + pubkeyB := mload(add(_data, 132)) + } + } +} diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/contracts/test/MerkleProofWrapper.sol b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/contracts/test/MerkleProofWrapper.sol new file mode 100644 index 0000000..018706a --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/contracts/test/MerkleProofWrapper.sol @@ -0,0 +1,19 @@ +pragma solidity ^0.4.24; + +import { MerkleProof } from "../common/MerkleProof.sol"; + + +contract MerkleProofWrapper { + + function verifyProof( + bytes32[] _proof, + bytes32 _root, + bytes32 _leaf + ) + public + pure + returns (bool) + { + return MerkleProof.verifyProof(_proof, _root, _leaf); + } +} diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/contracts/token/ApproveAndCallFallBack.sol b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/contracts/token/ApproveAndCallFallBack.sol new file mode 100644 index 0000000..60f8070 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/contracts/token/ApproveAndCallFallBack.sol @@ -0,0 +1,5 @@ +pragma solidity ^0.4.24; + +contract ApproveAndCallFallBack { + function receiveApproval(address from, uint256 _amount, address _token, bytes _data) public; +} diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/contracts/token/ERC20Receiver.sol b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/contracts/token/ERC20Receiver.sol new file mode 100644 index 0000000..3c90f8c --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/contracts/token/ERC20Receiver.sol @@ -0,0 +1,90 @@ +pragma solidity ^0.4.24; + +import "./ERC20Token.sol"; + +contract ERC20Receiver { + + event TokenDeposited(address indexed token, address indexed sender, uint256 amount); + event TokenWithdrawn(address indexed token, address indexed sender, uint256 amount); + + mapping (address => mapping(address => uint256)) tokenBalances; + + constructor() public { + + } + + function depositToken( + ERC20Token _token + ) + external + { + _depositToken( + msg.sender, + _token, + _token.allowance( + msg.sender, + address(this) + ) + ); + } + + function withdrawToken( + ERC20Token _token, + uint256 _amount + ) + external + { + _withdrawToken(msg.sender, _token, _amount); + } + + function depositToken( + ERC20Token _token, + uint256 _amount + ) + external + { + require(_token.allowance(msg.sender, address(this)) >= _amount); + _depositToken(msg.sender, _token, _amount); + } + + function tokenBalanceOf( + ERC20Token _token, + address _from + ) + external + view + returns(uint256 fromTokenBalance) + { + return tokenBalances[address(_token)][_from]; + } + + function _depositToken( + address _from, + ERC20Token _token, + uint256 _amount + ) + private + { + require(_amount > 0); + if (_token.transferFrom(_from, address(this), _amount)) { + tokenBalances[address(_token)][_from] += _amount; + emit TokenDeposited(address(_token), _from, _amount); + } + } + + function _withdrawToken( + address _from, + ERC20Token _token, + uint256 _amount + ) + private + { + require(_amount > 0); + require(tokenBalances[address(_token)][_from] >= _amount); + tokenBalances[address(_token)][_from] -= _amount; + require(_token.transfer(_from, _amount)); + emit TokenWithdrawn(address(_token), _from, _amount); + } + + +} \ No newline at end of file diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/contracts/token/ERC20Token.sol b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/contracts/token/ERC20Token.sol new file mode 100644 index 0000000..ee9d018 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/contracts/token/ERC20Token.sol @@ -0,0 +1,53 @@ +pragma solidity ^0.4.24; + +// Abstract contract for the full ERC 20 Token standard +// https://github.com/ethereum/EIPs/issues/20 + +interface ERC20Token { + + /** + * @notice send `_value` token to `_to` from `msg.sender` + * @param _to The address of the recipient + * @param _value The amount of token to be transferred + * @return Whether the transfer was successful or not + */ + function transfer(address _to, uint256 _value) external returns (bool success); + + /** + * @notice `msg.sender` approves `_spender` to spend `_value` tokens + * @param _spender The address of the account able to transfer the tokens + * @param _value The amount of tokens to be approved for transfer + * @return Whether the approval was successful or not + */ + function approve(address _spender, uint256 _value) external returns (bool success); + + /** + * @notice send `_value` token to `_to` from `_from` on the condition it is approved by `_from` + * @param _from The address of the sender + * @param _to The address of the recipient + * @param _value The amount of token to be transferred + * @return Whether the transfer was successful or not + */ + function transferFrom(address _from, address _to, uint256 _value) external returns (bool success); + + /** + * @param _owner The address from which the balance will be retrieved + * @return The balance + */ + function balanceOf(address _owner) external view returns (uint256 balance); + + /** + * @param _owner The address of the account owning tokens + * @param _spender The address of the account able to transfer the tokens + * @return Amount of remaining tokens allowed to spent + */ + function allowance(address _owner, address _spender) external view returns (uint256 remaining); + + /** + * @notice return total supply of tokens + */ + function totalSupply() external view returns (uint256 supply); + + event Transfer(address indexed _from, address indexed _to, uint256 _value); + event Approval(address indexed _owner, address indexed _spender, uint256 _value); +} \ No newline at end of file diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/contracts/token/StandardToken.sol b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/contracts/token/StandardToken.sol new file mode 100644 index 0000000..3d61313 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/contracts/token/StandardToken.sol @@ -0,0 +1,128 @@ +pragma solidity ^0.4.24; + +import "./ERC20Token.sol"; + +contract StandardToken is ERC20Token { + + uint256 private supply; + mapping (address => uint256) balances; + mapping (address => mapping (address => uint256)) allowed; + + constructor() internal { } + + function transfer( + address _to, + uint256 _value + ) + external + returns (bool success) + { + return transfer(msg.sender, _to, _value); + } + + function approve( + address _to, + uint256 _value + ) + external + returns (bool success) + { + return approve(msg.sender, _to, _value); + } + + function transferFrom( + address _from, + address _to, + uint256 _value + ) + external + returns (bool success) + { + if (balances[_from] >= _value && + allowed[_from][msg.sender] >= _value && + _value > 0) { + allowed[_from][msg.sender] -= _value; + return transfer(_from, _to, _value); + } else { + return false; + } + } + + function allowance(address _owner, address _spender) + external + view + returns (uint256 remaining) + { + return allowed[_owner][_spender]; + } + + function balanceOf(address _owner) + external + view + returns (uint256 balance) + { + return balances[_owner]; + } + + function totalSupply() + external + view + returns(uint256 currentTotalSupply) + { + return supply; + } + + /** + * @dev Aprove the passed address to spend the specified amount of tokens on behalf of msg.sender. + * @param _from The address that is approving the spend + * @param _spender The address which will spend the funds. + * @param _value The amount of tokens to be spent. + */ + function approve(address _from, address _spender, uint256 _value) internal returns (bool) { + + // To change the approve amount you first have to reduce the addresses` + // allowance to zero by calling `approve(_spender, 0)` if it is not + // already 0 to mitigate the race condition described here: + // https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 + require((_value == 0) || (allowed[_from][_spender] == 0), "Bad usage"); + + allowed[_from][_spender] = _value; + emit Approval(_from, _spender, _value); + return true; + } + + function mint( + address _to, + uint256 _amount + ) + internal + { + balances[_to] += _amount; + supply += _amount; + emit Transfer(0x0, _to, _amount); + } + + function transfer( + address _from, + address _to, + uint256 _value + ) + internal + returns (bool success) + { + if (balances[_from] >= _value && _value > 0) { + balances[_from] -= _value; + if(_to == address(0)) { + supply -= _value; + } else { + balances[_to] += _value; + } + emit Transfer(_from, _to, _value); + return true; + } else { + return false; + } + } + + +} diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/contracts/token/TestToken.sol b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/contracts/token/TestToken.sol new file mode 100644 index 0000000..0e914b1 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/contracts/token/TestToken.sol @@ -0,0 +1,30 @@ +pragma solidity ^0.4.24; + +import "./StandardToken.sol"; +import "./ApproveAndCallFallBack.sol"; + +/** + * @notice ERC20Token for test scripts, can be minted by anyone. + */ +contract TestToken is StandardToken { + + constructor() public { } + + /** + * @notice any caller can mint any `_amount` + * @param _amount how much to be minted + */ + function mint(uint256 _amount) public { + mint(msg.sender, _amount); + } + + function approveAndCall(address _spender, uint256 _value, bytes _extraData) + external + returns (bool success) + { + approve(msg.sender, _spender, _value); + ApproveAndCallFallBack(_spender).receiveApproval(msg.sender, _value, this, _extraData); + return true; + } + +} diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/embark.json b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/embark.json new file mode 100644 index 0000000..f1eb9cc --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/embark.json @@ -0,0 +1,17 @@ +{ + "contracts": ["contracts/**"], + "app": { + "js/dapp.js": ["app/dapp.js"], + "js/index.js": ["app/index.js"], + "index.html": "app/index.html", + "images/": ["app/images/**"] + }, + "buildDir": "dist/", + "config": "config/", + "versions": { + "web3": "1.0.0-beta", + "solc": "0.4.24", + "ipfs-api": "17.2.4" + }, + "plugins": {} +} diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/package.json b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/package.json new file mode 100644 index 0000000..d19f2a7 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/package.json @@ -0,0 +1,65 @@ +{ + "name": "status-contracts", + "version": "0.0.1", + "description": "", + "scripts": { + "solidity-coverage": "./node_modules/.bin/solidity-coverage", + "test": "embark test", + "lint": "eslint" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/status-im/contracts.git" + }, + "author": "Status Research & Development GMBH", + "license": "ISC", + "bugs": { + "url": "https://github.com/status-im/contracts/issues" + }, + "homepage": "https://github.com/status-im/contracts#readme", + "dependencies": { + "@material-ui/core": "^1.2.1", + "@material-ui/icons": "^1.1.0", + "bignumber.js": "^5.0.0", + "classnames": "^2.2.6", + "elliptic": "^6.4.1", + "eth-ens-namehash": "^2.0.8", + "formik": "^0.11.11", + "idna-normalize": "^1.0.0", + "install": "^0.11.0", + "npm": "^6.1.0", + "prop-types": "^15.6.1", + "react": "^16.4.2", + "react-blockies": "^1.3.0", + "react-bootstrap": "^0.32.1", + "react-copy-to-clipboard": "^5.0.1", + "react-dom": "^16.4.2", + "react-redux": "^5.0.7", + "react-toggle": "^4.0.2", + "redux": "^4.0.0", + "redux-action-creator": "^2.3.0", + "redux-thunk": "^2.3.0", + "reselect": "^3.0.1", + "styled-components": "^3.3.2", + "typeface-roboto": "0.0.54", + "web3-utils": "^1.0.0-beta.36" + }, + "devDependencies": { + "@babel/plugin-proposal-class-properties": "^7.0.0", + "@babel/plugin-proposal-decorators": "^7.0.0", + "@babel/plugin-proposal-export-namespace-from": "^7.0.0", + "@babel/plugin-proposal-function-sent": "^7.0.0", + "@babel/plugin-proposal-json-strings": "^7.0.0", + "@babel/plugin-proposal-numeric-separator": "^7.0.0", + "@babel/plugin-proposal-object-rest-spread": "^7.0.0", + "@babel/plugin-proposal-throw-expressions": "^7.0.0", + "@babel/plugin-syntax-dynamic-import": "^7.0.0", + "@babel/plugin-syntax-import-meta": "^7.0.0", + "eslint": "^4.19.1", + "eslint-config-airbnb": "^16.1.0", + "eslint-plugin-import": "^2.12.0", + "eslint-plugin-jsx-a11y": "^6.0.3", + "eslint-plugin-react": "^7.8.2", + "ethereumjs-util": "^5.2.0" + } +} diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/test/abstract/controlled.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/test/abstract/controlled.js new file mode 100644 index 0000000..95e0197 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/test/abstract/controlled.js @@ -0,0 +1,31 @@ + +exports.Test = (Controlled) => { + describe("Controlled", async function() { + this.timeout(0); + var accounts; + before(function(done) { + web3.eth.getAccounts().then(function (res) { + accounts = res; + done(); + }); + }); + + + it("should start with msg.sender as controller", async function() { + var controller = await Controlled.methods.controller().call(); + assert(controller, accounts[0]); + }); + + it("should allow controller to set new controller", async function() { + await Controlled.methods.changeController(accounts[1]).send({from: accounts[0]}); + var controller = await Controlled.methods.controller().call(); + assert(controller, accounts[1]); + }); + + it("should set back to original controller", async function() { + await Controlled.methods.changeController(accounts[0]).send({from: accounts[1]}); + var controller = await Controlled.methods.controller().call(); + assert(controller, accounts[0]); + }); + }); +} \ No newline at end of file diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/test/abstract/erc20tokenspec.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/test/abstract/erc20tokenspec.js new file mode 100644 index 0000000..e5f0637 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/test/abstract/erc20tokenspec.js @@ -0,0 +1,85 @@ + +const ERC20Receiver = require('Embark/contracts/ERC20Receiver'); + +exports.config = { + contracts : { + "ERC20Receiver": { + } + } +} + +exports.Test = (ERC20Token) => { + describe("ERC20Token", function() { + + var accounts; + before(function(done) { + web3.eth.getAccounts().then(function (res) { + accounts = res; + done(); + }); + }); + + it("should transfer 1 token", async function() { + let initialBalance0 = await ERC20Token.methods.balanceOf(accounts[0]).call(); + let initialBalance1 = await ERC20Token.methods.balanceOf(accounts[1]).call(); + await ERC20Token.methods.transfer(accounts[1],1).send({from: accounts[0]}); + let result0 = await ERC20Token.methods.balanceOf(accounts[0]).call(); + let result1 = await ERC20Token.methods.balanceOf(accounts[1]).call(); + + assert.equal(result0, +initialBalance0-1, "account 0 balance unexpected"); + assert.equal(result1, +initialBalance1+1, "account 1 balance unexpected"); + }); + + it("should set approved amount", async function() { + await ERC20Token.methods.approve(accounts[2],10000000).send({from: accounts[0]}); + let result = await ERC20Token.methods.allowance(accounts[0], accounts[2]).call(); + assert.equal(result, 10000000); + }); + + it("should consume allowance amount", async function() { + let initialAllowance = await ERC20Token.methods.allowance(accounts[0], accounts[2]).call(); + await ERC20Token.methods.transferFrom(accounts[0], accounts[0],1).send({from: accounts[2]}); + let result = await ERC20Token.methods.allowance(accounts[0], accounts[2]).call(); + + assert.equal(result, +initialAllowance-1); + }); + + it("should transfer approved amount", async function() { + let initialBalance0 = await ERC20Token.methods.balanceOf(accounts[0]).call(); + let initialBalance1 = await ERC20Token.methods.balanceOf(accounts[1]).call(); + await ERC20Token.methods.transferFrom(accounts[0], accounts[1],1).send({from: accounts[2]}); + let result0 = await ERC20Token.methods.balanceOf(accounts[0]).call(); + let result1 = await ERC20Token.methods.balanceOf(accounts[1]).call(); + + assert.equal(result0, +initialBalance0-1); + assert.equal(result1, +initialBalance1+1); + }); + + + it("should unset approved amount", async function() { + await ERC20Token.methods.approve(accounts[2],0).send({from: accounts[0]}); + let result = await ERC20Token.methods.allowance(accounts[0], accounts[2]).call(); + assert.equal(result, 0); + }); + + it("should deposit approved amount to contract ERC20Receiver", async function() { + //ERC20Receiver = await ERC20Receiver.deploy().send(); + //console.log(ERC20Receiver.address); + await ERC20Token.methods.approve(ERC20Receiver.address, 10).send({from: accounts[0]}); + await ERC20Receiver.methods.depositToken(ERC20Token.address, 10).send({from: accounts[0]}); + let result = await ERC20Receiver.methods.tokenBalanceOf(ERC20Token.address, accounts[0]).call(); + assert.equal(result, 10, "ERC20Receiver.tokenBalanceOf("+ERC20Token.address+","+accounts[0]+") wrong"); + }); + + it("should witdraw approved amount from contract ERC20Receiver", async function() { + let tokenBalance = await ERC20Receiver.methods.tokenBalanceOf(ERC20Token.address, accounts[0]).call(); + await ERC20Receiver.methods.withdrawToken(ERC20Token.address, tokenBalance).send({from: accounts[0]}); + tokenBalance = await ERC20Receiver.methods.tokenBalanceOf(ERC20Token.address, accounts[0]).call(); + assert.equal(tokenBalance, 0, "ERC20Receiver.tokenBalanceOf("+ERC20Token.address+","+accounts[0]+") wrong"); + }); + + //TODO: include checks for expected events fired + + + }); +} \ No newline at end of file diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/test/ensregistry.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/test/ensregistry.js new file mode 100644 index 0000000..74a1be7 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/test/ensregistry.js @@ -0,0 +1,94 @@ +const utils = require('../utils/testUtils.js'); +const ENSRegistry = require('Embark/contracts/ENSRegistry'); +const web3Utils = require('web3-utils'); +const namehash = require('eth-ens-namehash'); + +config({ + contracts: { + "ENSRegistry": { }, + } +}); + +contract('ENS', function () { + this.timeout(0); + let accountsArr; + + before(function(done) { + web3.eth.getAccounts().then(function (res) { + accountsArr = res; + done(); + }); + }); + + it('should allow ownership transfers', async () => { + let result = await ENSRegistry.methods.setOwner(utils.zeroBytes32, accountsArr[1]).send({from: accountsArr[0]}); + assert.equal(await ENSRegistry.methods.owner(utils.zeroBytes32).call(), accountsArr[1]) + assert.equal(result.events.Transfer.returnValues.node, utils.zeroBytes32); + assert.equal(result.events.Transfer.returnValues.owner, accountsArr[1]); + }); + + it('should prohibit transfers by non-owners', async () => { + try { + await ENSRegistry.methods.setOwner(utils.zeroBytes32, accountsArr[2]).send({from: accountsArr[0]}); + } catch (error) { + return utils.ensureException(error); + } + + assert.fail('transfer did not fail'); + }); + + it('should allow setting resolvers', async () => { + let result = await ENSRegistry.methods.setResolver(utils.zeroBytes32, accountsArr[3]).send({from: accountsArr[1]}); + let args = result.events.NewResolver.returnValues; + assert.equal(args.node, utils.zeroBytes32); + assert.equal(args.resolver, accountsArr[3]); + assert.equal(await ENSRegistry.methods.resolver(utils.zeroBytes32).call(), accountsArr[3]); + }); + + it('should prevent setting resolvers by non-owners', async () => { + try { + await ENSRegistry.methods.setResolver(utils.zeroBytes32, accountsArr[4]).send({from: accountsArr[0]}); + } catch (error) { + return utils.ensureException(error); + } + + assert.fail('setting resolver did not fail'); + }); + + it('should allow setting the TTL', async () => { + let result = await ENSRegistry.methods.setTTL(utils.zeroBytes32, 3600).send({from: accountsArr[1]}); + assert.equal(await ENSRegistry.methods.ttl(utils.zeroBytes32).call(), 3600); + let args = result.events.NewTTL.returnValues; + assert.equal(args.node, utils.zeroBytes32); + assert.equal(args.ttl, 3600); + }); + + it('should prevent setting the TTL by non-owners', async () => { + try { + await ENSRegistry.methods.setTTL(utils.zeroBytes32, 1200).send({from: accountsArr[0]}); + } catch (error) { + return utils.ensureException(error); + } + + assert.fail('setting resolver did not fail'); + }); + + it('should allow the creation of subnodes', async () => { + let result = await ENSRegistry.methods.setSubnodeOwner(utils.zeroBytes32, web3Utils.sha3('eth'), accountsArr[2]).send({from: accountsArr[1]}); + assert.equal(await ENSRegistry.methods.owner(namehash.hash('eth')).call(), accountsArr[2]); + let args = result.events.NewOwner.returnValues; + assert.equal(args.node, utils.zeroBytes32); + assert.equal(args.label, web3Utils.sha3('eth')); + assert.equal(args.owner, accountsArr[2]); + }); + + it('should prohibit subnode creation by non-owners', async () => { + try { + await ENSRegistry.methods.setSubnodeOwner(utils.zeroBytes32, web3Utils.sha3('eth'), accountsArr[3]).send({from: accountsArr[0]}); + } catch (error) { + return utils.ensureException(error); + } + + assert.fail('setting resolver did not fail'); + }); +}); diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/test/merkleproof.spec.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/test/merkleproof.spec.js new file mode 100644 index 0000000..6094faa --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/test/merkleproof.spec.js @@ -0,0 +1,66 @@ +const { MerkleTree } = require('../utils/merkleTree.js'); +const { sha3, bufferToHex } = require('ethereumjs-util'); + +const MerkleProofWrapper = require('Embark/contracts/MerkleProofWrapper'); + +var contractsConfig = { + "MerkleProofWrapper": { + + } + }; + +config({ contracts: contractsConfig }); + +contract('MerkleProof', function () { + + describe('verifyProof', function () { + it('should return true for a valid Merkle proof', async function () { + const elements = ['a', 'b', 'c', 'd']; + const merkleTree = new MerkleTree(elements); + + const root = merkleTree.getHexRoot(); + + const proof = merkleTree.getHexProof(elements[0]); + + const leaf = bufferToHex(sha3(elements[0])); + + const result = await MerkleProofWrapper.methods.verifyProof(proof, root, leaf).call(); + + assert(result); + }); + + it('should return false for an invalid Merkle proof', async function () { + const correctElements = ['a', 'b', 'c']; + const correctMerkleTree = new MerkleTree(correctElements); + + const correctRoot = correctMerkleTree.getHexRoot(); + + const correctLeaf = bufferToHex(sha3(correctElements[0])); + + const badElements = ['d', 'e', 'f']; + const badMerkleTree = new MerkleTree(badElements); + + const badProof = badMerkleTree.getHexProof(badElements[0]); + + const result = await MerkleProofWrapper.methods.verifyProof(badProof, correctRoot, correctLeaf).call(); + + assert(!result); + }); + + it('should return false for a Merkle proof of invalid length', async function () { + const elements = ['a', 'b', 'c']; + const merkleTree = new MerkleTree(elements); + + const root = merkleTree.getHexRoot(); + + const proof = merkleTree.getHexProof(elements[0]); + const badProof = proof.slice(0, proof.length - 5); + + const leaf = bufferToHex(sha3(elements[0])); + + const result = await MerkleProofWrapper.methods.verifyProof(badProof, root, leaf).call() + + assert(!result); + }); + }); +}); diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/test/testtoken.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/test/testtoken.js new file mode 100644 index 0000000..3e17461 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/test/testtoken.js @@ -0,0 +1,55 @@ +const Utils = require('../utils/testUtils'); +const TestToken = require('Embark/contracts/TestToken'); +const ERC20TokenSpec = require('./abstract/erc20tokenspec'); + +config({ + contracts: { + "TestToken": { + }, + ...ERC20TokenSpec.config.contracts + } +}); + +contract("TestToken", function() { + this.timeout(0); + var accounts; + before(function(done) { + web3.eth.getAccounts().then(function (res) { + accounts = res; + done(); + }); + }); + + it("should increase totalSupply in mint", async function() { + let initialSupply = await TestToken.methods.totalSupply().call(); + await TestToken.methods.mint(100).send(); + let result = await TestToken.methods.totalSupply().call(); + assert.equal(result, +initialSupply+100); + }); + + it("should increase accountBalance in mint", async function() { + let initialBalance = await TestToken.methods.balanceOf(accounts[0]).call(); + await TestToken.methods.mint(100).send({from: accounts[0]}); + let result = await TestToken.methods.balanceOf(accounts[0]).call(); + assert.equal(result, +initialBalance+100); + }); + + it("should burn account supply", async function() { + let initialBalance = await TestToken.methods.balanceOf(accounts[0]).call(); + await TestToken.methods.transfer(Utils.zeroAddress, initialBalance).send({from: accounts[0]}); + assert.equal(await TestToken.methods.totalSupply().call(), 0); + assert.equal(await TestToken.methods.balanceOf(accounts[0]).call(), 0); + }) + + it("should mint balances for ERC20TokenSpec", async function() { + let initialBalance = 7 * 10 ^ 18; + for(i=0;i { + ens = ENSRegistry; + accountsArr = accounts; + await utils.increaseTime(1 * utils.timeUnits.days) //time cannot start zero + await utils.increaseTime(1000) + done(); + }) + }); + + describe('activate(uint256)', function() { + it('should activate registry', async () => { + const initialPrice = 100 + const resultSetRegistryPrice = await UsernameRegistrar.methods.activate(initialPrice).send({from: accountsArr[0]}); + assert.equal(resultSetRegistryPrice.events.RegistryPrice.returnValues.price, initialPrice, "event RegistryPrice wrong price"); + assert.equal(await UsernameRegistrar.methods.state().call(), 1, "Wrong registry state") + assert.equal(await UsernameRegistrar.methods.price().call(), initialPrice, "Wrong registry price") + }); + }); + + describe('updateRegistryPrice(uint256)', function() { + it('should change registry price', async () => { + const newPrice = registry.price; + const resultUpdateRegistryPrice = await UsernameRegistrar.methods.updateRegistryPrice(newPrice).send({from: accountsArr[0]}); + assert.equal(resultUpdateRegistryPrice.events.RegistryPrice.returnValues.price, registry.price, "event RegistryPrice wrong price"); + assert.equal(await UsernameRegistrar.methods.state().call(), 1, "Wrong registry state") + assert.equal(await UsernameRegistrar.methods.price().call(), newPrice, "Wrong registry price") + }); + }); + + describe('register(bytes32,address,bytes32,bytes32)', function() { + it('should register username', async () => { + const registrant = accountsArr[5]; + const username = 'erin'; + const usernameHash = namehash.hash(username + '.' + registry.registry); + const label = web3Utils.sha3(username); + const registryPrice = await UsernameRegistrar.methods.getPrice().call() + await TestToken.methods.mint(registry.price).send({from: registrant}); + const initialRegistrantBalance = await TestToken.methods.balanceOf(registrant).call(); + const initialRegistryBalance = await TestToken.methods.balanceOf(UsernameRegistrar.address).call(); + await TestToken.methods.approve(UsernameRegistrar.address, registry.price).send({from: registrant}); + const resultRegister = await UsernameRegistrar.methods.register( + web3Utils.sha3(username), + utils.zeroAddress, + utils.zeroBytes32, + utils.zeroBytes32 + ).send({from: registrant}); + assert.equal(resultRegister.events['0'].raw.topics[0], web3Utils.sha3("Transfer(address,address,uint256)"), "Wrong Event"); + assert.equal(utils.eventAddress(resultRegister.events['0'].raw.topics[1]), registrant, "Wrong Transfer from"); + assert.equal(utils.eventAddress(resultRegister.events['0'].raw.topics[2]), UsernameRegistrar.address, "Wrong transfer to"); + assert.equal(resultRegister.events['0'].raw.data, registry.price, "Wrong transfer value"); + assert.equal(resultRegister.events['1'].raw.topics[0], web3Utils.sha3("NewOwner(bytes32,bytes32,address)"), "Wrong Event"); + assert.equal(resultRegister.events['1'].raw.topics[1], registry.namehash, "Wrong Node"); + assert.equal(resultRegister.events['1'].raw.topics[2], label, "Wrong Label"); + assert.equal(utils.eventAddress(resultRegister.events['1'].raw.data), registrant, "Wrong subnode owner"); + assert.equal(resultRegister.events.UsernameOwner.returnValues.owner, registrant, "event UsernameOwner owner mismatch"); + assert.equal(resultRegister.events.UsernameOwner.returnValues.nameHash, usernameHash, "event UsernameOwner usernameHash mismatch"); + assert.equal(await ens.methods.owner(usernameHash).call(), registrant, "ENSRegistry owner mismatch"); + assert.equal(await ens.methods.resolver(usernameHash).call(), utils.zeroAddress, "Resolver wrongly defined"); + assert.equal(await UsernameRegistrar.methods.getAccountBalance(label).call(), registryPrice, "Registry username account balance wrong"); + assert.equal(await UsernameRegistrar.methods.getAccountOwner(label).call(), registrant, "Account owner mismatch"); + assert.equal(await TestToken.methods.balanceOf(registrant).call(), +initialRegistrantBalance-registryPrice, "User final balance wrong") + assert.equal(await TestToken.methods.balanceOf(UsernameRegistrar.address).call(), (+initialRegistryBalance)+(+registry.price), "Registry final balance wrong") + }); + it('should register username only resolveing address ', async () => { + const registrant = accountsArr[2]; + await TestToken.methods.mint(registry.price).send({from: registrant}); + await TestToken.methods.approve(UsernameRegistrar.address, registry.price).send({from: registrant}); + const username = 'bob'; + const usernameHash = namehash.hash(username + '.' + registry.registry); + const label = web3Utils.sha3(username); + const resultRegister = await UsernameRegistrar.methods.register( + web3Utils.sha3(username), + + registrant, + utils.zeroBytes32, + utils.zeroBytes32 + ).send({from: registrant}); + assert.equal(resultRegister.events['0'].raw.topics[0], web3Utils.sha3("Transfer(address,address,uint256)"), "Wrong Event"); + assert.equal(utils.eventAddress(resultRegister.events['0'].raw.topics[1]), registrant, "Wrong Transfer from"); + assert.equal(utils.eventAddress(resultRegister.events['0'].raw.topics[2]), UsernameRegistrar.address, "Wrong transfer to"); + assert.equal(resultRegister.events['0'].raw.data, registry.price, "Wrong transfer value"); + assert.equal(resultRegister.events['1'].raw.topics[0], web3Utils.sha3("NewOwner(bytes32,bytes32,address)"), "Wrong Event"); + assert.equal(resultRegister.events['1'].raw.topics[1], registry.namehash, "Wrong Node"); + assert.equal(resultRegister.events['1'].raw.topics[2], label, "Wrong Label"); + assert.equal(utils.eventAddress(resultRegister.events['1'].raw.data), UsernameRegistrar.address, "Wrong subnode owner"); + assert.equal(resultRegister.events['2'].raw.topics[0], web3Utils.sha3("NewResolver(bytes32,address)"), "Wrong Event"); + assert.equal(resultRegister.events['2'].raw.topics[1], usernameHash, "Wrong Username"); + assert.equal(utils.eventAddress(resultRegister.events['2'].raw.data), PublicResolver.address, "Wrong Resolver"); + assert.equal(resultRegister.events['3'].raw.topics[0], web3Utils.sha3("AddrChanged(bytes32,address)"), "Wrong Event"); + assert.equal(resultRegister.events['3'].raw.topics[1], usernameHash, "Wrong Username"); + assert.equal(utils.eventAddress(resultRegister.events['3'].raw.data), registrant, "Wrong address to resolve"); + assert.equal(resultRegister.events['4'].raw.topics[0], web3Utils.sha3("Transfer(bytes32,address)"), "Wrong Event"); + assert.equal(resultRegister.events['4'].raw.topics[1], usernameHash, "Wrong Username"); + assert.equal(utils.eventAddress(resultRegister.events['4'].raw.data), registrant, "Wrong registry.namehash owner"); + assert.equal(resultRegister.events.UsernameOwner.returnValues.owner, registrant, "event UsernameOwner owner mismatch"); + assert.equal(resultRegister.events.UsernameOwner.returnValues.nameHash, usernameHash, "event UsernameOwner usernameHash mismatch"); + assert.equal(await ens.methods.owner(usernameHash).call(), registrant, "ENSRegistry owner mismatch"); + assert.equal(await ens.methods.resolver(usernameHash).call(), PublicResolver.address, "Resolver wrongly defined"); + assert.equal(await UsernameRegistrar.methods.getAccountBalance(label).call(), registry.price, "Wrong account balance"); + assert.equal(await UsernameRegistrar.methods.getAccountOwner(label).call(), registrant, "Account owner mismatch"); + assert.equal(await PublicResolver.methods.addr(usernameHash).call(), registrant, "Resolved address not set"); + const resolverPubKey = await PublicResolver.methods.pubkey(usernameHash).call(); + assert.equal(resolverPubKey[0], utils.zeroBytes32 , "Unexpected resolved pubkey[0]"); + assert.equal(resolverPubKey[1], utils.zeroBytes32 , "Unexpected resolved pubkey[1]"); + }); + it('should register username with only status contact', async () => { + const username = 'carlos'; + const registrant = accountsArr[3]; + await TestToken.methods.mint(registry.price).send({from: registrant}); + await TestToken.methods.approve(UsernameRegistrar.address, registry.price).send({from: registrant}); + const usernameHash = namehash.hash(username + '.' + registry.registry); + const contactCode = '0x04dbb31252d9bddb4e4d362c7b9c80cba74732280737af97971f42ccbdc716f3f3efb1db366880e52d09b1bfd59842e833f3004088892b7d14b9ce9e957cea9a82'; + const points = utils.generateXY(contactCode); + const label = web3Utils.sha3(username); + const resultRegister = await UsernameRegistrar.methods.register( + web3Utils.sha3(username), + utils.zeroAddress, + points.x, + points.y + ).send({from: registrant}); + assert.equal(resultRegister.events['0'].raw.topics[0], web3Utils.sha3("Transfer(address,address,uint256)"), "Wrong Event"); + assert.equal(utils.eventAddress(resultRegister.events['0'].raw.topics[1]), registrant, "Wrong Transfer from"); + assert.equal(utils.eventAddress(resultRegister.events['0'].raw.topics[2]), UsernameRegistrar.address, "Wrong transfer to"); + assert.equal(resultRegister.events['0'].raw.data, registry.price, "Wrong transfer value"); + assert.equal(resultRegister.events['1'].raw.topics[0], web3Utils.sha3("NewOwner(bytes32,bytes32,address)"), "Wrong Event"); + assert.equal(resultRegister.events['1'].raw.topics[1], registry.namehash, "Wrong Node"); + assert.equal(resultRegister.events['1'].raw.topics[2], label, "Wrong Label"); + assert.equal(utils.eventAddress(resultRegister.events['1'].raw.data), UsernameRegistrar.address, "Wrong subnode owner"); + assert.equal(resultRegister.events['2'].raw.topics[0], web3Utils.sha3("NewResolver(bytes32,address)"), "Wrong Event"); + assert.equal(resultRegister.events['2'].raw.topics[1], usernameHash, "Wrong Username"); + assert.equal(utils.eventAddress(resultRegister.events['2'].raw.data), PublicResolver.address, "Wrong Resolver"); + assert.equal(resultRegister.events['3'].raw.topics[0], web3Utils.sha3("PubkeyChanged(bytes32,bytes32,bytes32)"), "Wrong Event"); + assert.equal(resultRegister.events['3'].raw.topics[1], usernameHash, "Wrong Username"); + assert.equal(resultRegister.events['3'].raw.data, points.x.concat(points.y.substr(2))) + assert.equal(resultRegister.events['4'].raw.topics[0], web3Utils.sha3("Transfer(bytes32,address)"), "Wrong Event"); + assert.equal(resultRegister.events['4'].raw.topics[1], usernameHash, "Wrong Username"); + assert.equal(utils.eventAddress(resultRegister.events['4'].raw.data), registrant, "Wrong registry.namehash owner"); + assert.equal(resultRegister.events.UsernameOwner.returnValues.owner, registrant, "event UsernameOwner owner mismatch"); + assert.equal(resultRegister.events.UsernameOwner.returnValues.nameHash, usernameHash, "event UsernameOwner usernameHash mismatch"); + assert.equal(await ens.methods.owner(usernameHash).call(), registrant, "ENSRegistry owner mismatch"); + assert.equal(await ens.methods.resolver(usernameHash).call(), PublicResolver.address, "Resolver wrongly defined"); + assert.equal(await UsernameRegistrar.methods.getAccountBalance(label).call(), registry.price, "Wrong account balance"); + assert.equal(await UsernameRegistrar.methods.getAccountOwner(label).call(), registrant, "Account owner mismatch"); + assert.equal(await PublicResolver.methods.addr(usernameHash).call(), utils.zeroAddress, "Resolved address not set"); + const resolverPubKey = await PublicResolver.methods.pubkey(usernameHash).call(); + const pubKey = utils.keyFromXY(resolverPubKey[0], resolverPubKey[1]); + assert.equal(pubKey, contactCode, "pubKey does not match contract code"); + }); + it('should register username with status contact code and address', async () => { + const registrant = accountsArr[2]; + await TestToken.methods.mint(registry.price).send({from: registrant}); + await TestToken.methods.approve(UsernameRegistrar.address, registry.price).send({from: registrant}); + const username = 'bob2'; + const usernameHash = namehash.hash(username + '.' + registry.registry); + const contactCode = '0x04dbb31252d9bddb4e4d362c7b9c80cba74732280737af97971f42ccbdc716f3f3efb1db366880e52d09b1bfd59842e833f3004088892b7d14b9ce9e957cea9a82'; + const points = utils.generateXY(contactCode); + const label = web3Utils.sha3(username); + const resultRegister = await UsernameRegistrar.methods.register( + label, + registrant, + points.x, + points.y + ).send({from: registrant}); + assert.equal(resultRegister.events['0'].raw.topics[0], web3Utils.sha3("Transfer(address,address,uint256)"), "Wrong Event"); + assert.equal(utils.eventAddress(resultRegister.events['0'].raw.topics[1]), registrant, "Wrong Transfer from"); + assert.equal(utils.eventAddress(resultRegister.events['0'].raw.topics[2]), UsernameRegistrar.address, "Wrong transfer to"); + assert.equal(resultRegister.events['0'].raw.data, registry.price, "Wrong transfer value"); + assert.equal(resultRegister.events['1'].raw.topics[0], web3Utils.sha3("NewOwner(bytes32,bytes32,address)"), "Wrong Event"); + assert.equal(resultRegister.events['1'].raw.topics[1], registry.namehash, "Wrong Node"); + assert.equal(resultRegister.events['1'].raw.topics[2], label, "Wrong Label"); + assert.equal(utils.eventAddress(resultRegister.events['1'].raw.data), UsernameRegistrar.address, "Wrong subnode owner"); + assert.equal(resultRegister.events['2'].raw.topics[0], web3Utils.sha3("NewResolver(bytes32,address)"), "Wrong Event"); + assert.equal(resultRegister.events['2'].raw.topics[1], usernameHash, "Wrong Username"); + assert.equal(utils.eventAddress(resultRegister.events['2'].raw.data), await UsernameRegistrar.methods.resolver().call(), "Wrong Resolver"); + assert.equal(resultRegister.events['3'].raw.topics[0], web3Utils.sha3("AddrChanged(bytes32,address)"), "Wrong Event"); + assert.equal(resultRegister.events['3'].raw.topics[1], usernameHash, "Wrong Username"); + assert.equal(utils.eventAddress(resultRegister.events['3'].raw.data), registrant, "Wrong address to resolve"); + assert.equal(resultRegister.events['4'].raw.topics[0], web3Utils.sha3("PubkeyChanged(bytes32,bytes32,bytes32)"), "Wrong Event"); + assert.equal(resultRegister.events['4'].raw.topics[1], usernameHash, "Wrong Username"); + assert.equal(resultRegister.events['4'].raw.data, points.x.concat(points.y.substr(2))) + assert.equal(resultRegister.events['5'].raw.topics[0], web3Utils.sha3("Transfer(bytes32,address)"), "Wrong Event"); + assert.equal(resultRegister.events['5'].raw.topics[1], usernameHash, "Wrong Username"); + assert.equal(utils.eventAddress(resultRegister.events['5'].raw.data), registrant, "Wrong registry.namehash owner"); + assert.equal(resultRegister.events.UsernameOwner.returnValues.owner, registrant, "event UsernameOwner owner mismatch"); + assert.equal(resultRegister.events.UsernameOwner.returnValues.nameHash, usernameHash, "event UsernameOwner usernameHash mismatch"); + assert.equal(await ens.methods.owner(usernameHash).call(), registrant, "ENSRegistry owner mismatch"); + assert.equal(await ens.methods.resolver(usernameHash).call(), PublicResolver.address, "Resolver wrongly defined"); + assert.equal(await UsernameRegistrar.methods.getAccountBalance(label).call(), registry.price, "Wrong account balance"); + assert.equal(await UsernameRegistrar.methods.getAccountOwner(label).call(), registrant, "Account owner mismatch"); + assert.equal(await PublicResolver.methods.addr(usernameHash).call(), registrant, "Resolved address not set"); + const resolverPubKey = await PublicResolver.methods.pubkey(usernameHash).call(); + const pubKey = utils.keyFromXY(resolverPubKey[0], resolverPubKey[1]); + assert.equal(pubKey, contactCode, "pubKey does not match contract code"); + }); + }); + + describe('receiveApproval(address,uint256,address,bytes)', function() { + it('should register username', async () => { + const registrant = accountsArr[5]; + const username = 'erinauto'; + const usernameHash = namehash.hash(username + '.' + registry.registry); + const label = web3Utils.sha3(username); + const registryPrice = await UsernameRegistrar.methods.getPrice().call() + await TestToken.methods.mint(registry.price).send({from: registrant}); + const initialRegistrantBalance = await TestToken.methods.balanceOf(registrant).call(); + const initialRegistryBalance = await TestToken.methods.balanceOf(UsernameRegistrar.address).call(); + + const registerCall = UsernameRegistrar.methods.register( + web3Utils.sha3(username), + utils.zeroAddress, + utils.zeroBytes32, + utils.zeroBytes32 + ).encodeABI(); + const approveAndCallResult = await TestToken.methods.approveAndCall(UsernameRegistrar.address, registry.price, registerCall).send({from: registrant}); + // TODO: check events + assert.equal(await ens.methods.owner(usernameHash).call(), registrant, "ENSRegistry owner mismatch"); + assert.equal(await ens.methods.resolver(usernameHash).call(), utils.zeroAddress, "Resolver wrongly defined"); + assert.equal(await UsernameRegistrar.methods.getAccountBalance(label).call(), registryPrice, "Registry username account balance wrong"); + assert.equal(await UsernameRegistrar.methods.getAccountOwner(label).call(), registrant, "Account owner mismatch"); + assert.equal(await TestToken.methods.balanceOf(registrant).call(), +initialRegistrantBalance-registryPrice, "User final balance wrong") + assert.equal(await TestToken.methods.balanceOf(UsernameRegistrar.address).call(), (+initialRegistryBalance)+(+registry.price), "Registry final balance wrong") + }); + it('should register username only resolving address ', async () => { + const registrant = accountsArr[2]; + await TestToken.methods.mint(registry.price).send({from: registrant}); + const username = 'bobauto'; + const usernameHash = namehash.hash(username + '.' + registry.registry); + const label = web3Utils.sha3(username); + const registerCall = UsernameRegistrar.methods.register( + web3Utils.sha3(username), + + registrant, + utils.zeroBytes32, + utils.zeroBytes32 + ).encodeABI(); + + const approveAndCallResult = await TestToken.methods.approveAndCall(UsernameRegistrar.address, registry.price, registerCall).send({from: registrant}); + // TODO: check events + + assert.equal(await ens.methods.owner(usernameHash).call(), registrant, "ENSRegistry owner mismatch"); + assert.equal(await ens.methods.resolver(usernameHash).call(), PublicResolver.address, "Resolver wrongly defined"); + assert.equal(await UsernameRegistrar.methods.getAccountBalance(label).call(), registry.price, "Wrong account balance"); + assert.equal(await UsernameRegistrar.methods.getAccountOwner(label).call(), registrant, "Account owner mismatch"); + assert.equal(await PublicResolver.methods.addr(usernameHash).call(), registrant, "Resolved address not set"); + const resolverPubKey = await PublicResolver.methods.pubkey(usernameHash).call(); + assert.equal(resolverPubKey[0], utils.zeroBytes32 , "Unexpected resolved pubkey[0]"); + assert.equal(resolverPubKey[1], utils.zeroBytes32 , "Unexpected resolved pubkey[1]"); + }); + + it('should register username with only status contact', async () => { + const username = 'carlosauto'; + const registrant = accountsArr[3]; + await TestToken.methods.mint(registry.price).send({from: registrant}); + const usernameHash = namehash.hash(username + '.' + registry.registry); + const contactCode = '0x04dbb31252d9bddb4e4d362c7b9c80cba74732280737af97971f42ccbdc716f3f3efb1db366880e52d09b1bfd59842e833f3004088892b7d14b9ce9e957cea9a82'; + const points = utils.generateXY(contactCode); + const label = web3Utils.sha3(username); + const registerCall = UsernameRegistrar.methods.register( + web3Utils.sha3(username), + utils.zeroAddress, + points.x, + points.y + ).encodeABI(); + + const approveAndCallResult = await TestToken.methods.approveAndCall(UsernameRegistrar.address, registry.price, registerCall).send({from: registrant}); + // TODO: check events + assert.equal(await ens.methods.owner(usernameHash).call(), registrant, "ENSRegistry owner mismatch"); + assert.equal(await ens.methods.resolver(usernameHash).call(), PublicResolver.address, "Resolver wrongly defined"); + assert.equal(await UsernameRegistrar.methods.getAccountBalance(label).call(), registry.price, "Wrong account balance"); + assert.equal(await UsernameRegistrar.methods.getAccountOwner(label).call(), registrant, "Account owner mismatch"); + assert.equal(await PublicResolver.methods.addr(usernameHash).call(), utils.zeroAddress, "Resolved address not set"); + const resolverPubKey = await PublicResolver.methods.pubkey(usernameHash).call(); + const pubKey = utils.keyFromXY(resolverPubKey[0], resolverPubKey[1]); + assert.equal(pubKey, contactCode, "pubKey does not match contract code"); + }); + it('should register username with status contact code and address', async () => { + const registrant = accountsArr[2]; + await TestToken.methods.mint(registry.price).send({from: registrant}); + const username = 'bob2auto'; + const usernameHash = namehash.hash(username + '.' + registry.registry); + const contactCode = '0x04dbb31252d9bddb4e4d362c7b9c80cba74732280737af97971f42ccbdc716f3f3efb1db366880e52d09b1bfd59842e833f3004088892b7d14b9ce9e957cea9a82'; + const points = utils.generateXY(contactCode); + const label = web3Utils.sha3(username); + const registerCall = UsernameRegistrar.methods.register( + label, + registrant, + points.x, + points.y + ).encodeABI(); + + const approveAndCallResult = await TestToken.methods.approveAndCall(UsernameRegistrar.address, registry.price, registerCall).send({from: registrant}); + // TODO: check events + assert.equal(await ens.methods.owner(usernameHash).call(), registrant, "ENSRegistry owner mismatch"); + assert.equal(await ens.methods.resolver(usernameHash).call(), PublicResolver.address, "Resolver wrongly defined"); + assert.equal(await UsernameRegistrar.methods.getAccountBalance(label).call(), registry.price, "Wrong account balance"); + assert.equal(await UsernameRegistrar.methods.getAccountOwner(label).call(), registrant, "Account owner mismatch"); + assert.equal(await PublicResolver.methods.addr(usernameHash).call(), registrant, "Resolved address not set"); + const resolverPubKey = await PublicResolver.methods.pubkey(usernameHash).call(); + const pubKey = utils.keyFromXY(resolverPubKey[0], resolverPubKey[1]); + assert.equal(pubKey, contactCode, "pubKey does not match contract code"); + }); + }); + + describe('release(bytes32)', function() { + it('should not release username due delay', async () => { + let registrant = accountsArr[6]; + await TestToken.methods.mint(registry.price).send({from: registrant}); + await TestToken.methods.approve(UsernameRegistrar.address, registry.price).send({from: registrant}); + let username = 'mistaker'; + await UsernameRegistrar.methods.register( + web3Utils.sha3(username), + utils.zeroAddress, + utils.zeroBytes32, + utils.zeroBytes32 + ).send({from: registrant}); + let failed; + try{ + await UsernameRegistrar.methods.release( + web3Utils.sha3(username), + ).send({from: registrant}); + failed = false; + } catch(e){ + failed = true; + } + assert(failed, "Released after delay period"); + }); + it('should release username', async () => {; + const registrant = accountsArr[6]; + await TestToken.methods.mint(registry.price).send({from: registrant}); + await TestToken.methods.approve(UsernameRegistrar.address, registry.price).send({from: registrant}); + const username = 'frank'; + const label = web3Utils.sha3(username); + await UsernameRegistrar.methods.register( + label, + utils.zeroAddress, + utils.zeroBytes32, + utils.zeroBytes32 + ).send({from: registrant}); + const releaseDelay = await UsernameRegistrar.methods.releaseDelay().call(); + await utils.increaseTime(releaseDelay) + await utils.increaseTime(1000) + const initialAccountBalance = await UsernameRegistrar.methods.getAccountBalance(label).call(); + const initialRegistrantBalance = await TestToken.methods.balanceOf(registrant).call(); + const initialRegistryBalance = await TestToken.methods.balanceOf(UsernameRegistrar.address).call(); + await utils.increaseTime(1000) + const resultRelease = await UsernameRegistrar.methods.release( + web3Utils.sha3(username), + + ).send({from: registrant}); + //TODO: check events + assert.equal(await UsernameRegistrar.methods.getAccountBalance(label).call(), 0, "Final balance didnt zeroed"); + assert.equal(await TestToken.methods.balanceOf(registrant).call(), (+initialRegistrantBalance)+(+initialAccountBalance), "Releaser token balance didnt increase") + assert.equal(await TestToken.methods.balanceOf(UsernameRegistrar.address).call(), (+initialRegistryBalance)-(+initialAccountBalance), "Registry token balance didnt decrease") + }); + it('should release transfered username', async () => { + let registrant = accountsArr[7]; + await TestToken.methods.mint(registry.price).send({from: registrant}); + await TestToken.methods.approve(UsernameRegistrar.address, registry.price).send({from: registrant}); + let username = 'grace'; + let usernameHash = namehash.hash(username + '.' + registry.registry); + let label = web3Utils.sha3(username); + let newOwner = accountsArr[8]; + await UsernameRegistrar.methods.register( + label, + utils.zeroAddress, + utils.zeroBytes32, + utils.zeroBytes32 + ).send({from: registrant}); + await ens.methods.setOwner(usernameHash, newOwner).send({from: registrant}); + let releaseDelay = await UsernameRegistrar.methods.releaseDelay().call(); + await utils.increaseTime(releaseDelay) + await utils.increaseTime(1000) + let initialAccountBalance = await UsernameRegistrar.methods.getAccountBalance(label).call(); + let initialRegistrantBalance = await TestToken.methods.balanceOf(newOwner).call(); + let initialRegistryBalance = await TestToken.methods.balanceOf(UsernameRegistrar.address).call(); + await utils.increaseTime(1000) + let resultRelease = await UsernameRegistrar.methods.release( + label + ).send({from: newOwner}); + //TODO: check events + assert.equal(await UsernameRegistrar.methods.getAccountBalance(label).call(), 0, "Final balance didnt zeroed"); + assert.equal(await TestToken.methods.balanceOf(newOwner).call(), (+initialRegistrantBalance)+(+initialAccountBalance), "New owner token balance didnt increase") + assert.equal(await TestToken.methods.balanceOf(UsernameRegistrar.address).call(), (+initialRegistryBalance)-(+initialAccountBalance), "Registry token balance didnt decrease") + }); + it('should release moved username account balance by owner', async () => { + const registrant = accountsArr[5]; + await TestToken.methods.mint(dummyRegistry.price).send({from: registrant}); + await DummyUsernameRegistrar.methods.activate(dummyRegistry.price).send({from: accountsArr[0]}); + await TestToken.methods.approve(DummyUsernameRegistrar.address, dummyRegistry.price).send({from: registrant}); + + const username = 'hardhead'; + const label = web3Utils.sha3(username); + const usernameHash = namehash.hash(username + '.' + dummyRegistry.registry); + await DummyUsernameRegistrar.methods.register( + label, + registrant, + utils.zeroBytes32, + utils.zeroBytes32 + ).send({from: registrant}); + let initialAccountBalance = await DummyUsernameRegistrar.methods.getAccountBalance(label).call(); + const initialRegistrantBalance = await TestToken.methods.balanceOf(registrant).call(); + const initialRegistryBalance = await TestToken.methods.balanceOf(DummyUsernameRegistrar.address).call(); + await DummyUsernameRegistrar.methods.moveRegistry(UpdatedDummyUsernameRegistrar.address).send(); + + assert.equal(await ens.methods.owner(usernameHash).call(), registrant, "ENSRegistry owner mismatch"); + assert.equal(await ens.methods.resolver(usernameHash).call(), PublicResolver.address, "Resolver wrongly defined"); + assert.equal(await PublicResolver.methods.addr(usernameHash).call(), registrant, "Resolved address not set"); + + const resultRelease = await DummyUsernameRegistrar.methods.release( + label + ).send({from: registrant}); + //TODO: verify events + assert.equal(await TestToken.methods.balanceOf(registrant).call(), (+initialRegistrantBalance)+(+initialAccountBalance), "New owner token balance didnt increase") + assert.equal(await TestToken.methods.balanceOf(DummyUsernameRegistrar.address).call(), (+initialRegistryBalance)-(+initialAccountBalance), "Registry token balance didnt decrease") + assert.equal(await ens.methods.resolver(usernameHash).call(), utils.zeroAddress, "Resolver not undefined"); + assert.equal(await ens.methods.owner(usernameHash).call(), utils.zeroAddress, "Owner not removed"); + //We are not cleaning PublicResolver or any resolver, so the value should remain the same. + assert.equal(await PublicResolver.methods.addr(usernameHash).call(), registrant, "Resolved address not set"); + }); + }); + + describe('updateAccountOwner(bytes32)', function() { + it('should update username account owner', async () => { + let username = 'heidi'; + let label = web3Utils.sha3(username); + let registrant = accountsArr[8]; + await TestToken.methods.mint(registry.price).send({from: registrant}); + await TestToken.methods.approve(UsernameRegistrar.address, registry.price).send({from: registrant}); + let newOwner = accountsArr[9]; + let usernameHash = namehash.hash(username + '.' + registry.registry); + + await UsernameRegistrar.methods.register( + label, + utils.zeroAddress, + utils.zeroBytes32, + utils.zeroBytes32 + ).send({from: registrant}); + await ens.methods.setOwner(usernameHash, newOwner).send({from: registrant}); + let resultUpdateOwner = await UsernameRegistrar.methods.updateAccountOwner( + label + ).send({from: newOwner}); + //TODO: check events + assert.equal(await UsernameRegistrar.methods.getAccountOwner(label).call(), newOwner, "Backup owner not updated"); + }); + }); + + describe('slashInvalidUsername(string,uint256,uint256)', function() { + it('should slash invalid username', async () => { + let username = 'alicé'; + let label = web3Utils.sha3(username); + let usernameHash = namehash.hash(username + '.' + registry.registry); + let registrant = accountsArr[1]; + await TestToken.methods.mint(registry.price).send({from: registrant}); + await TestToken.methods.approve(UsernameRegistrar.address, registry.price).send({from: registrant}); + await UsernameRegistrar.methods.register( + web3Utils.sha3(username), + + utils.zeroAddress, + utils.zeroBytes32, + utils.zeroBytes32 + ).send({from: registrant}); + await utils.increaseTime(20000) + assert.equal(await ens.methods.owner(usernameHash).call(), registrant); + assert.notEqual(await UsernameRegistrar.methods.getCreationTime(label).call(), 0); + const creationTime = await UsernameRegistrar.methods.getCreationTime(web3Utils.sha3(username)).call(); + const reserveSecret = 1337; + const secret = web3Utils.soliditySha3(usernameHash, creationTime, reserveSecret); + await UsernameRegistrar.methods.reserveSlash(secret).send(); + await UsernameRegistrar.methods.slashInvalidUsername(username, 4, reserveSecret).send() + //TODO: check events + assert.equal(await UsernameRegistrar.methods.getCreationTime(label).call(), 0); + assert.equal(await ens.methods.owner(usernameHash).call(), utils.zeroAddress); + }); + it('should not slash valid username', async () => { + const username = 'legituser'; + const usernameHash = namehash.hash(username + '.' + registry.registry); + const registrant = accountsArr[1]; + await TestToken.methods.mint(registry.price).send({from: registrant}); + await TestToken.methods.approve(UsernameRegistrar.address, registry.price).send({from: registrant}); + await UsernameRegistrar.methods.register( + web3Utils.sha3(username), + utils.zeroAddress, + utils.zeroBytes32, + utils.zeroBytes32 + ).send({from: registrant}); + await utils.increaseTime(20000) + const creationTime = await UsernameRegistrar.methods.getCreationTime(web3Utils.sha3(username)).call(); + const reserveSecret = 1337; + const secret = web3Utils.soliditySha3(usernameHash, creationTime, reserveSecret); + await UsernameRegistrar.methods.reserveSlash(secret).send(); + let failed; + try{ + await UsernameRegistrar.methods.slashInvalidUsername(username, 4, reserveSecret).send() + failed = false; + } catch(e){ + failed = true; + } + assert(failed, "Was slashed anyway"); + }); + }); + + describe('slashReservedUsername(string,bytes32[],uint256)', function() { + it('should not slash not reserved name username', async () => { + const username = 'somedummyname123'; + const usernameHash = namehash.hash(username + '.' + registry.registry); + const registrant = accountsArr[1]; + await TestToken.methods.mint(registry.price).send({from: registrant}); + await TestToken.methods.approve(UsernameRegistrar.address, registry.price).send({from: registrant}); + await UsernameRegistrar.methods.register( + web3Utils.sha3(username), + utils.zeroAddress, + utils.zeroBytes32, + utils.zeroBytes32 + ).send({from: registrant}); + await utils.increaseTime(20000) + assert.equal(await ens.methods.owner(usernameHash).call(), registrant); + const creationTime = await UsernameRegistrar.methods.getCreationTime(web3Utils.sha3(username)).call(); + const reserveSecret = 1337; + const secret = web3Utils.soliditySha3(usernameHash, creationTime, reserveSecret); + await UsernameRegistrar.methods.reserveSlash(secret).send(); + let failed; + try{ + await UsernameRegistrar.methods.slashReservedUsername(username, merkleTree.getHexProof(ReservedUsernames[0]), reserveSecret).send() + failed = false; + } catch(e){ + failed = true; + } + assert(failed, "Was slashed anyway"); + }); + it('should not slash reserved name username with wrong proof ', async () => { + const username = ReservedUsernames[5]; + const usernameHash = namehash.hash(username + '.' + registry.registry); + const registrant = accountsArr[1]; + await TestToken.methods.mint(registry.price).send({from: registrant}); + await TestToken.methods.approve(UsernameRegistrar.address, registry.price).send({from: registrant}); + await UsernameRegistrar.methods.register( + web3Utils.sha3(username), + utils.zeroAddress, + utils.zeroBytes32, + utils.zeroBytes32 + ).send({from: registrant}); + await utils.increaseTime(20000) + assert.equal(await ens.methods.owner(usernameHash).call(), registrant); + const creationTime = await UsernameRegistrar.methods.getCreationTime(web3Utils.sha3(username)).call(); + const reserveSecret = 1337; + const secret = web3Utils.soliditySha3(usernameHash, creationTime, reserveSecret); + await UsernameRegistrar.methods.reserveSlash(secret).send(); + let failed; + try{ + await UsernameRegistrar.methods.slashReservedUsername(username, merkleTree.getHexProof(ReservedUsernames[1]), reserveSecret).send() + failed = false; + } catch(e){ + failed = true; + } + assert(failed, "Was slashed anyway"); + }); + it('should slash reserved name username', async () => { + const username = ReservedUsernames[7]; + const usernameHash = namehash.hash(username + '.' + registry.registry); + const registrant = accountsArr[1]; + await TestToken.methods.mint(registry.price).send({from: registrant}); + await TestToken.methods.approve(UsernameRegistrar.address, registry.price).send({from: registrant}); + await UsernameRegistrar.methods.register( + web3Utils.sha3(username), + utils.zeroAddress, + utils.zeroBytes32, + utils.zeroBytes32 + ).send({from: registrant}); + await utils.increaseTime(20000) + assert.equal(await ens.methods.owner(usernameHash).call(), registrant); + const creationTime = await UsernameRegistrar.methods.getCreationTime(web3Utils.sha3(username)).call(); + const reserveSecret = 1337; + const secret = web3Utils.soliditySha3(usernameHash, creationTime, reserveSecret); + await UsernameRegistrar.methods.reserveSlash(secret).send(); + result = await UsernameRegistrar.methods.slashReservedUsername(username, merkleTree.getHexProof(username), reserveSecret).send() + //TODO: check events + assert.equal(await ens.methods.owner(usernameHash).call(), utils.zeroAddress); + }); + }); + + describe('slashSmallUsername(string,uint256)', function() { + it('should not slash big username', async() =>{ + let username = '1234567890'; + let usernameHash = namehash.hash(username + '.' + registry.registry); + let registrant = accountsArr[1]; + await TestToken.methods.mint(registry.price).send({from: registrant}); + await TestToken.methods.approve(UsernameRegistrar.address, registry.price).send({from: registrant}); + await UsernameRegistrar.methods.register( + web3Utils.sha3(username), + utils.zeroAddress, + utils.zeroBytes32, + utils.zeroBytes32 + ).send({from: registrant}); + await utils.increaseTime(1000) + const creationTime = await UsernameRegistrar.methods.getCreationTime(web3Utils.sha3(username)).call(); + const reserveSecret = 1337; + const secret = web3Utils.soliditySha3(usernameHash, creationTime, reserveSecret); + await UsernameRegistrar.methods.reserveSlash(secret).send(); + let failed; + try{ + await UsernameRegistrar.methods.slashSmallUsername(username).send() + failed = false; + } catch(e){ + failed = true; + } + assert(failed, "Was slashed anyway"); + }) + it('should slash small username', async () => { + let username = 'a'; + let usernameHash = namehash.hash(username + '.' + registry.registry); + let registrant = accountsArr[1]; + await TestToken.methods.mint(registry.price).send({from: registrant}); + await TestToken.methods.approve(UsernameRegistrar.address, registry.price).send({from: registrant}); + await UsernameRegistrar.methods.register( + web3Utils.sha3(username), + + utils.zeroAddress, + utils.zeroBytes32, + utils.zeroBytes32 + ).send({from: registrant}); + await utils.increaseTime(20000) + assert.equal(await ens.methods.owner(usernameHash).call(), registrant); + const creationTime = await UsernameRegistrar.methods.getCreationTime(web3Utils.sha3(username)).call(); + const reserveSecret = 1337; + const secret = web3Utils.soliditySha3(usernameHash, creationTime, reserveSecret); + await UsernameRegistrar.methods.reserveSlash(secret).send(); + result = await UsernameRegistrar.methods.slashSmallUsername(username, reserveSecret).send() + assert.equal(await ens.methods.owner(usernameHash).call(), utils.zeroAddress); + }); + }); + + describe('slashAddressLikeUsername(string,uint256)', function() { + it('should slash username that starts with 0x and is 12 of lenght or bigger', async () => { + let username = '0xc6b95bd26123'; + const userlabelHash = web3Utils.soliditySha3({value: username, type: "string"}); + const usernameHash = namehash.hash(username + '.' + registry.registry); + let registrant = accountsArr[1]; + await TestToken.methods.mint(registry.price).send({from: registrant}); + await TestToken.methods.approve(UsernameRegistrar.address, registry.price).send({from: registrant}); + await UsernameRegistrar.methods.register( + userlabelHash, + utils.zeroAddress, + utils.zeroBytes32, + utils.zeroBytes32 + ).send({from: registrant}); + await utils.increaseTime(1000) + assert.equal(await ens.methods.owner(usernameHash).call(), registrant); + const creationTime = await UsernameRegistrar.methods.getCreationTime(userlabelHash).call(); + const reserveSecret = 1337; + const secret = web3Utils.soliditySha3(usernameHash, creationTime, reserveSecret); + await UsernameRegistrar.methods.reserveSlash(secret).send(); + result = await UsernameRegistrar.methods.slashAddressLikeUsername(username, reserveSecret).send() + assert.equal(await ens.methods.owner(usernameHash).call(), utils.zeroAddress); + }); + it('should not slash username that starts with 0x but is smaller then 12', async () => { + let username = "0xc6b95bd26"; + const userlabelHash = web3Utils.soliditySha3({value: username, type: "string"}); + const usernameHash = namehash.hash(username + '.' + registry.registry); + let registrant = accountsArr[1]; + await TestToken.methods.mint(registry.price).send({from: registrant}); + await TestToken.methods.approve(UsernameRegistrar.address, registry.price).send({from: registrant}); + await UsernameRegistrar.methods.register( + userlabelHash, + utils.zeroAddress, + utils.zeroBytes32, + utils.zeroBytes32 + ).send({from: registrant}); + await utils.increaseTime(20000) + const creationTime = await UsernameRegistrar.methods.getCreationTime(userlabelHash).call(); + const reserveSecret = 1337; + const secret = web3Utils.soliditySha3(usernameHash, creationTime, reserveSecret); + await UsernameRegistrar.methods.reserveSlash(secret).send(); + let failed; + try{ + result = await UsernameRegistrar.methods.slashAddressLikeUsername(username, reserveSecret).send() + failed = false; + } catch(e){ + failed = true; + } + assert(failed, "Was slashed anyway"); + }); + it('should not slash username that dont starts 0x and is bigger than 12', async () => { + const username = "0a002322c6b95bd26"; + const userlabelHash = web3Utils.soliditySha3({value: username, type: "string"}); + const usernameHash = namehash.hash(username + '.' + registry.registry); + const registrant = accountsArr[1]; + await TestToken.methods.mint(registry.price).send({from: registrant}); + await TestToken.methods.approve(UsernameRegistrar.address, registry.price).send({from: registrant}); + await UsernameRegistrar.methods.register( + userlabelHash, + utils.zeroAddress, + utils.zeroBytes32, + utils.zeroBytes32 + ).send({from: registrant}); + await utils.increaseTime(20000) + const creationTime = await UsernameRegistrar.methods.getCreationTime(userlabelHash).call(); + const reserveSecret = 1337; + const secret = web3Utils.soliditySha3(usernameHash, creationTime, reserveSecret); + await UsernameRegistrar.methods.reserveSlash(secret).send(); + let failed; + try{ + await UsernameRegistrar.methods.slashAddressLikeUsername(username, reserveSecret).send() + failed = false; + } catch(e){ + failed = true; + } + assert(failed, "Was slashed anyway"); + }); + it('should not slash username that starts with 0x but dont use hex chars', async () => { + const username = "0xprotocolstatus"; + const userlabelHash = web3Utils.soliditySha3({value: username, type: "string"}); + const usernameHash = namehash.hash(username + '.' + registry.registry); + const registrant = accountsArr[1]; + await TestToken.methods.mint(registry.price).send({from: registrant}); + await TestToken.methods.approve(UsernameRegistrar.address, registry.price).send({from: registrant}); + await UsernameRegistrar.methods.register( + userlabelHash, + utils.zeroAddress, + utils.zeroBytes32, + utils.zeroBytes32 + ).send({from: registrant}); + await utils.increaseTime(20000) + const creationTime = await UsernameRegistrar.methods.getCreationTime(userlabelHash).call(); + const reserveSecret = 1337; + const secret = web3Utils.soliditySha3(usernameHash, creationTime, reserveSecret); + await UsernameRegistrar.methods.reserveSlash(secret).send(); + let failed; + try{ + await UsernameRegistrar.methods.slashAddressLikeUsername(username, reserveSecret).send() + failed = false; + } catch(e){ + failed = true; + } + assert(failed, "Was slashed anyway"); + }); + }); + describe('slashUsername(bytes,uint256)', function() { + it('should slash a username and get funds from registrant', async () => { + const username = 'b'; + const usernameHash = namehash.hash(username + '.' + registry.registry); + const registrant = accountsArr[1]; + const slasher = accountsArr[2]; + const label = web3Utils.sha3(username); + await TestToken.methods.mint(registry.price).send({from: registrant}); + await TestToken.methods.approve(UsernameRegistrar.address, registry.price).send({from: registrant}); + await UsernameRegistrar.methods.register( + label, + utils.zeroAddress, + utils.zeroBytes32, + utils.zeroBytes32 + ).send({from: registrant}); + await utils.increaseTime(20000) + const partReward = await UsernameRegistrar.methods.getSlashRewardPart(label).call(); + assert.equal(await ens.methods.owner(usernameHash).call(), registrant); + const initialSlasherBalance = await TestToken.methods.balanceOf(slasher).call(); + const creationTime = await UsernameRegistrar.methods.getCreationTime(label).call(); + const reserveSecret = 1337; + const secret = web3Utils.soliditySha3(usernameHash, creationTime, reserveSecret); + await UsernameRegistrar.methods.reserveSlash(secret).send({from: slasher}); + await UsernameRegistrar.methods.slashSmallUsername(username, reserveSecret).send({from: slasher}) + //TODO: check events + assert.equal(await TestToken.methods.balanceOf(slasher).call(), (+initialSlasherBalance)+((+partReward)*2)); + assert.equal(await ens.methods.owner(usernameHash).call(), utils.zeroAddress); + }); + + it('should slash a username of a not migrated subnode that became unallowed', async () => { + const registrant = accountsArr[5]; + const notRegistrant = accountsArr[6]; + + await TestToken.methods.mint(dummy2Registry.price).send({from: registrant}); + await TestToken.methods.approve(Dummy2UsernameRegistrar.address, dummy2Registry.price).send({from: registrant}); + + const username = ReservedUsernames[10]; + const label = web3Utils.sha3(username); + const usernameHash = namehash.hash(username + '.' + dummy2Registry.registry); + await Dummy2UsernameRegistrar.methods.register( + label, + registrant, + utils.zeroBytes32, + utils.zeroBytes32 + ).send({from: registrant}); + await utils.increaseTime(20000) + let initialAccountBalance = await Dummy2UsernameRegistrar.methods.getAccountBalance(label).call(); + const initialRegistrantBalance = await TestToken.methods.balanceOf(registrant).call(); + const initialRegistryBalance = await TestToken.methods.balanceOf(Dummy2UsernameRegistrar.address).call(); + + + await Dummy2UsernameRegistrar.methods.moveRegistry(UpdatedDummy2UsernameRegistrar.address).send(); + + assert.equal(await ens.methods.owner(usernameHash).call(), registrant, "ENSRegistry owner mismatch"); + assert.equal(await ens.methods.resolver(usernameHash).call(), PublicResolver.address, "Resolver wrongly defined"); + assert.equal(await PublicResolver.methods.addr(usernameHash).call(), registrant, "Resolved address not set"); + const creationTime = await UsernameRegistrar.methods.getCreationTime(label).call(); + const reserveSecret = 1337; + const secret = web3Utils.soliditySha3(usernameHash, creationTime, reserveSecret); + await UsernameRegistrar.methods.reserveSlash(secret).send({from: notRegistrant}); + const resultRelease = await UpdatedDummy2UsernameRegistrar.methods.slashReservedUsername( + username, + merkleTree.getHexProof(username), + reserveSecret + ).send({from: notRegistrant }); + //TODO: verify events + + assert.equal(await ens.methods.resolver(usernameHash).call(), utils.zeroAddress, "Resolver not undefined"); + assert.equal(await ens.methods.owner(usernameHash).call(), utils.zeroAddress, "Owner not removed"); + //We are not cleaning PublicResolver or any resolver, so the value should remain the same. + assert.equal(await PublicResolver.methods.addr(usernameHash).call(), registrant, "Resolved address not set"); + }); + }); + + describe('reserveSlash(bytes32)', function() { + it('should send 2/3 funds to reserver', async() =>{ + const username = 'c'; + const label = web3Utils.sha3(username); + const usernameHash = namehash.hash(username + '.' + registry.registry); + const registrant = accountsArr[1]; + const slashReserverCaller = accountsArr[2]; + await TestToken.methods.mint(registry.price).send({from: registrant}); + await TestToken.methods.approve(UsernameRegistrar.address, registry.price).send({from: registrant}); + await UsernameRegistrar.methods.register( + web3Utils.sha3(username), + utils.zeroAddress, + utils.zeroBytes32, + utils.zeroBytes32 + ).send({from: registrant}); + await utils.increaseTime(20000) + assert.equal(await ens.methods.owner(usernameHash).call(), registrant); + const partReward = await UsernameRegistrar.methods.getSlashRewardPart(label).call(); + const initialSlashReserverBalance = await TestToken.methods.balanceOf(slashReserverCaller).call(); + const creationTime = await UsernameRegistrar.methods.getCreationTime(label).call(); + const reserveSecret = 1337; + const secret = web3Utils.soliditySha3(usernameHash, creationTime, reserveSecret); + await UsernameRegistrar.methods.reserveSlash(secret).send({from: slashReserverCaller}); + await UsernameRegistrar.methods.slashSmallUsername(username, reserveSecret).send({from: slashReserverCaller}) + //TODO: check events + assert.equal(await TestToken.methods.balanceOf(slashReserverCaller).call(), (+initialSlashReserverBalance)+(+partReward*2)); + assert.equal(await ens.methods.owner(usernameHash).call(), utils.zeroAddress); + }); + }); + +describe('eraseNode(bytes32[])', function() { + it('should clear unowned subdomains of users', async () => {; + const registrant = accountsArr[6]; + const anyone = accountsArr[5]; + await TestToken.methods.mint(registry.price).send({from: registrant}); + await TestToken.methods.approve(UsernameRegistrar.address, registry.price).send({from: registrant}); + const username = "root"; + const usernameHash = namehash.hash(username + '.' + registry.registry); + const label = web3Utils.sha3(username); + const labels = [ + web3Utils.sha3("10"), + web3Utils.sha3("9"), + web3Utils.sha3("8"), + web3Utils.sha3("7"), + web3Utils.sha3("6"), + web3Utils.sha3("5"), + web3Utils.sha3("4"), + web3Utils.sha3("3"), + web3Utils.sha3("2"), + web3Utils.sha3("1"), + web3Utils.sha3("0"), + web3Utils.sha3(username), + ]; + await UsernameRegistrar.methods.register( + label, + utils.zeroAddress, + utils.zeroBytes32, + utils.zeroBytes32 + ).send({from: registrant}); + assert.equal(await ens.methods.owner(usernameHash).call(), registrant); + const releaseDelay = await UsernameRegistrar.methods.releaseDelay().call(); + await utils.increaseTime(releaseDelay) + await utils.increaseTime(1000) + await utils.increaseTime(1000) + let subnode = usernameHash; + for (let index = labels.length - 1; index > 0; index--) { + const label = labels[index - 1]; + await ENSRegistry.methods.setSubnodeOwner(subnode, label, registrant).send({from: registrant}); + subnode = web3Utils.soliditySha3(subnode, label); + assert.equal(await ens.methods.owner(subnode).call(), registrant); + + } + + const resultRelease = await UsernameRegistrar.methods.release(web3Utils.sha3(username)).send({from: registrant}); + + subnode = usernameHash; + for (let index = labels.length - 1; index > 0; index--) { + const label = labels[index - 1]; + subnode = web3Utils.soliditySha3(subnode, label); + assert.equal(await ens.methods.owner(subnode).call(), registrant); + } + + const resultErase = await UsernameRegistrar.methods.eraseNode( + labels + ).send({from: anyone}); + //TODO: check events + + subnode = usernameHash; + for (let index = labels.length - 1; index > 0; index--) { + const label = labels[index - 1]; + subnode = web3Utils.soliditySha3(subnode, label); + assert.equal(await ens.methods.owner(subnode).call(), utils.zeroAddress); + } + }); + + +}); + + describe('moveRegistry(address)', function() { + it('should move registry to new registry and migrate', async () => { + const result = await UsernameRegistrar.methods.moveRegistry(UpdatedUsernameRegistrar.address).send(); + //TODO: check events + assert.equal(await ens.methods.owner(registry.namehash).call(), UpdatedUsernameRegistrar.address, "registry ownership not moved correctly") + assert.equal(await UpdatedUsernameRegistrar.methods.getPrice().call(), registry.price, "updated registry didnt migrated price") + }); + }); + + describe('moveAccount(label,address)', function() { + it('should move username to new registry by account owner', async () => { + const registrant = accountsArr[5]; + const username = 'erin'; + const usernameHash = namehash.hash(username + '.' + registry.registry); + const label = web3Utils.sha3(username); + + const accountBalance = await UsernameRegistrar.methods.getAccountBalance(label).call() + assert.notEqual(accountBalance, 0); + const initialRegistryBalance = await TestToken.methods.balanceOf(UsernameRegistrar.address).call(); + const initialUpdatedRegistryBalance = await TestToken.methods.balanceOf(UpdatedUsernameRegistrar.address).call(); + const creationTime = await UsernameRegistrar.methods.getCreationTime(label).call(); + assert.notEqual(creationTime, 0); + assert.equal(await UpdatedUsernameRegistrar.methods.getCreationTime(label).call(), 0); + const result = await UsernameRegistrar.methods.moveAccount(label, UpdatedUsernameRegistrar.address).send({from: registrant}); + assert.equal(await UsernameRegistrar.methods.getCreationTime(label).call(), 0); + assert.equal(await UpdatedUsernameRegistrar.methods.getCreationTime(label).call(), creationTime); + assert.equal(await TestToken.methods.balanceOf(UsernameRegistrar.address).call(), (+initialRegistryBalance)-(+accountBalance)) + assert.equal(await TestToken.methods.balanceOf(UpdatedUsernameRegistrar.address).call(), (+initialUpdatedRegistryBalance)+(+accountBalance)) + }); + }); + +}); diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/utils/merkleTree.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/utils/merkleTree.js new file mode 100644 index 0000000..bdc7e80 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/utils/merkleTree.js @@ -0,0 +1,133 @@ +const { sha3, bufferToHex } = require('ethereumjs-util'); + +class MerkleTree { + constructor(elements) { + // Filter empty strings and hash elements + this.elements = elements.filter(el => el).map(el => sha3(el)); + + // Deduplicate elements + this.elements = this.bufDedup(this.elements); + // Sort elements + this.elements.sort(Buffer.compare); + + // Create layers + this.layers = this.getLayers(this.elements); + } + + getLayers(elements) { + if (elements.length == 0) { + return [[""]]; + } + + const layers = []; + layers.push(elements); + + // Get next layer until we reach the root + while (layers[layers.length - 1].length > 1) { + layers.push(this.getNextLayer(layers[layers.length - 1])); + } + + return layers; + } + + getNextLayer(elements) { + return elements.reduce((layer, el, idx, arr) => { + if (idx % 2 === 0) { + // Hash the current element with its pair element + layer.push(this.combinedHash(el, arr[idx + 1])); + } + + return layer; + }, []); + } + + combinedHash(first, second) { + if (!first) { return second; } + if (!second) { return first; } + + return sha3(this.sortAndConcat(first, second)); + } + + getRoot() { + return this.layers[this.layers.length - 1][0]; + } + + getHexRoot() { + return bufferToHex(this.getRoot()); + } + + getProof(el) { + let idx = this.bufIndexOf(el, this.elements); + + if (idx === -1) { + throw new Error("Element does not exist in Merkle tree"); + } + + return this.layers.reduce((proof, layer) => { + const pairElement = this.getPairElement(idx, layer); + + if (pairElement) { + proof.push(pairElement); + } + + idx = Math.floor(idx / 2); + + return proof; + }, []); + } + + getHexProof(el) { + const proof = this.getProof(el); + + return this.bufArrToHex(proof); + } + + getPairElement(idx, layer) { + const pairIdx = idx % 2 === 0 ? idx + 1 : idx - 1; + + if (pairIdx < layer.length) { + return layer[pairIdx]; + } else { + return null; + } + } + + bufIndexOf(el, arr) { + let hash; + + // Convert element to 32 byte hash if it is not one already + if (el.length !== 32 || !Buffer.isBuffer(el)) { + hash = sha3(el); + } else { + hash = el; + } + + for (let i = 0; i < arr.length; i++) { + if (hash.equals(arr[i])) { + return i; + } + } + + return -1; + } + + bufDedup(elements) { + return elements.filter((el, idx) => { + return this.bufIndexOf(el, elements) === idx; + }); + } + + bufArrToHex(arr) { + if (arr.some(el => !Buffer.isBuffer(el))) { + throw new Error("Array is not an array of buffers"); + } + + return arr.map(el => '0x' + el.toString('hex')); + } + + sortAndConcat(...args) { + return Buffer.concat([...args].sort(Buffer.compare)); + } +} + +exports.MerkleTree = MerkleTree; \ No newline at end of file diff --git a/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/utils/testUtils.js b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/utils/testUtils.js new file mode 100644 index 0000000..0a488e3 --- /dev/null +++ b/audits/2018-10_ENS-Usernames_Sigma-Prime/code/ens-usernames/utils/testUtils.js @@ -0,0 +1,262 @@ +const EC = require('elliptic').ec; +const ec = new EC('secp256k1'); +const web3Utils = require('web3-utils'); + +// This has been tested with the real Ethereum network and Testrpc. +// Copied and edited from: https://gist.github.com/xavierlepretre/d5583222fde52ddfbc58b7cfa0d2d0a9 +exports.assertReverts = (contractMethodCall, maxGasAvailable) => { + return new Promise((resolve, reject) => { + try { + resolve(contractMethodCall()) + } catch (error) { + reject(error) + } + }) + .then(tx => { + assert.equal(tx.receipt.gasUsed, maxGasAvailable, "tx successful, the max gas available was not consumed") + }) + .catch(error => { + if ((error + "").indexOf("invalid opcode") < 0 && (error + "").indexOf("out of gas") < 0) { + // Checks if the error is from TestRpc. If it is then ignore it. + // Otherwise relay/throw the error produced by the above assertion. + // Note that no error is thrown when using a real Ethereum network AND the assertion above is true. + throw error + } + }) +} + +exports.listenForEvent = event => new Promise((resolve, reject) => { + event({}, (error, response) => { + if (!error) { + resolve(response.args) + } else { + reject(error) + } + event.stopWatching() + }) +}); + +exports.eventValues = (receipt, eventName) => { + if(receipt.events[eventName]) + return receipt.events[eventName].returnValues; +} + +exports.eventAddress = (bytes32Address) => { + return web3Utils.toChecksumAddress("0x"+bytes32Address.substring(26)) +} + +exports.addressToBytes32 = (address) => { + const stringed = "0000000000000000000000000000000000000000000000000000000000000000" + address.slice(2); + return "0x" + stringed.substring(stringed.length - 64, stringed.length); +} + + +// OpenZeppelin's expectThrow helper - +// Source: https://github.com/OpenZeppelin/zeppelin-solidity/blob/master/test/helpers/expectThrow.js +exports.expectThrow = async promise => { + try { + await promise; + } catch (error) { + // TODO: Check jump destination to destinguish between a throw + // and an actual invalid jump. + const invalidOpcode = error.message.search('invalid opcode') >= 0; + // TODO: When we contract A calls contract B, and B throws, instead + // of an 'invalid jump', we get an 'out of gas' error. How do + // we distinguish this from an actual out of gas event? (The + // testrpc log actually show an 'invalid jump' event.) + const outOfGas = error.message.search('out of gas') >= 0; + const revert = error.message.search('revert') >= 0; + assert( + invalidOpcode || outOfGas || revert, + 'Expected throw, got \'' + error + '\' instead', + ); + return; + } + assert.fail('Expected throw not received'); + }; + + + +exports.assertJump = (error) => { + assert(error.message.search('revert') > -1, 'Revert should happen'); +} + + +var callbackToResolve = function (resolve, reject) { + return function (error, value) { + if (error) { + reject(error); + } else { + resolve(value); + } + }; +}; + +exports.promisify = (func) => + (...args) => { + return new Promise((resolve, reject) => { + const callback = (err, data) => err ? reject(err) : resolve(data); + func.apply(this, [...args, callback]); + }); + } + + +// This has been tested with the real Ethereum network and Testrpc. +// Copied and edited from: https://gist.github.com/xavierlepretre/d5583222fde52ddfbc58b7cfa0d2d0a9 +exports.assertReverts = (contractMethodCall, maxGasAvailable) => { + return new Promise((resolve, reject) => { + try { + resolve(contractMethodCall()) + } catch (error) { + reject(error) + } + }) + .then(tx => { + assert.equal(tx.receipt.gasUsed, maxGasAvailable, "tx successful, the max gas available was not consumed") + }) + .catch(error => { + if ((error + "").indexOf("invalid opcode") < 0 && (error + "").indexOf("out of gas") < 0) { + // Checks if the error is from TestRpc. If it is then ignore it. + // Otherwise relay/throw the error produced by the above assertion. + // Note that no error is thrown when using a real Ethereum network AND the assertion above is true. + throw error + } + }) +} + +exports.listenForEvent = event => new Promise((resolve, reject) => { + event({}, (error, response) => { + if (!error) { + resolve(response.args) + } else { + reject(error) + } + event.stopWatching() + }) +}); + +exports.eventValues = (receipt, eventName) => { + if(receipt.events[eventName]) + return receipt.events[eventName].returnValues; +} + +exports.addressToBytes32 = (address) => { + const stringed = "0000000000000000000000000000000000000000000000000000000000000000" + address.slice(2); + return "0x" + stringed.substring(stringed.length - 64, stringed.length); +} + + +// OpenZeppelin's expectThrow helper - +// Source: https://github.com/OpenZeppelin/zeppelin-solidity/blob/master/test/helpers/expectThrow.js +exports.expectThrow = async promise => { + try { + await promise; + } catch (error) { + // TODO: Check jump destination to destinguish between a throw + // and an actual invalid jump. + const invalidOpcode = error.message.search('invalid opcode') >= 0; + // TODO: When we contract A calls contract B, and B throws, instead + // of an 'invalid jump', we get an 'out of gas' error. How do + // we distinguish this from an actual out of gas event? (The + // testrpc log actually show an 'invalid jump' event.) + const outOfGas = error.message.search('out of gas') >= 0; + const revert = error.message.search('revert') >= 0; + assert( + invalidOpcode || outOfGas || revert, + 'Expected throw, got \'' + error + '\' instead', + ); + return; + } + assert.fail('Expected throw not received'); + }; + +exports.assertJump = (error) => { + assert(error.message.search('revert') > -1, 'Revert should happen'); +} + +var callbackToResolve = function (resolve, reject) { + return function (error, value) { + if (error) { + reject(error); + } else { + resolve(value); + } + }; +}; + +exports.promisify = (func) => + (...args) => { + return new Promise((resolve, reject) => { + const callback = (err, data) => err ? reject(err) : resolve(data); + func.apply(this, [...args, callback]); + }); + } + +exports.zeroAddress = '0x0000000000000000000000000000000000000000'; +exports.zeroBytes32 = "0x0000000000000000000000000000000000000000000000000000000000000000"; +exports.timeUnits = { + seconds: 1, + minutes: 60, + hours: 60 * 60, + days: 24 * 60 * 60, + weeks: 7 * 24 * 60 * 60, + years: 365 * 24 * 60 * 60 +} + +exports.ensureException = function(error) { + assert(isException(error), error.toString()); +}; + +function isException(error) { + let strError = error.toString(); + return strError.includes('invalid opcode') || strError.includes('invalid JUMP') || strError.includes('revert'); +} + +exports.increaseTime = async (amount) => { + return new Promise(function(resolve, reject) { + web3.currentProvider.sendAsync( + { + jsonrpc: '2.0', + method: 'evm_increaseTime', + params: [+amount], + id: new Date().getSeconds() + }, + async (error) => { + if (error) { + console.log(error); + return reject(err); + } + await web3.currentProvider.sendAsync( + { + jsonrpc: '2.0', + method: 'evm_mine', + params: [], + id: new Date().getSeconds() + }, (error) => { + if (error) { + console.log(error); + return reject(err); + } + resolve(); + } + ) + } + ) + }); +} + +exports.generateXY = pub => { + const stripped = pub.slice(2); + const key = ec.keyFromPublic(stripped, 'hex'); + const pubPoint = key.getPublic(); + const x = '0x' + pubPoint.getX().toString(16); + const y = '0x'+ pubPoint.getY().toString(16); + return { x, y }; +} + +exports.keyFromXY = (X, Y) => { + const x = Buffer.from(X.substring(2), 'hex'); + const y = Buffer.from(Y.substring(2), 'hex'); + const keys = ec.keyFromPublic({ x, y }, 'hex'); + return `0x${keys.getPublic().encode('hex')}`; +}