1\xfcgX\x15\xaa\x00\x00\u07d4\xad\xff\r\x1d\v\x97G\x1ev\u05c9\xd2\u470at\xf9\xbdT\xff\x89e\xea=\xb7UF`\x00\x00\u07d4\xae\x06,D\x86\x18d0u\xdez\x0004-\xce\xd6=\xba\u05c9,\xc6\u034c\u0082\xb3\x00\x00\xe0\x94\xae\x10\xe2z\x01O\r0k\xaf&mH\x97\u021a\xee\xe2\xe9t\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xae\x12k8,\xf2W\xfa\xd7\xf0\xbc}\x16)~T\xccrg\u0689\x10CV\x1a\x88)0\x00\x00\u07d4\xae\x13\xa0\x85\x11\x11\x0f2\xe5;\xe4\x12xE\xc8C\xa1\xa5|{\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94\xae\x17\x9aF\r\xb6c&t=$\xe6u#\xa5{$m\xaf\u007f\x8a\x01\x00\a\xae|\xe5\xbb\xe4\x00\x00\u07d4\xae\"(ey\x90y\xaa\xf4\xf0gJ\f\u06ab\x02\xa6\xd5p\xff\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xae#\x9a\xcf\xfdN\xbe.\x1b\xa5\xb4\x17\x05r\xdcy\xcce3\xec\x8a\x02\x8a\x85t%Fo\x80\x00\x00\u07d4\xae/\x9c\x19\xacv\x13e\x94C#\x93\xb0G\x1d\b\x90!d\u04c9%\xdf\x05\u01a8\x97\xe4\x00\x00\u07d4\xae4\x86\x1d4\"S\x19O\xfcfR\xdf\xdeQ\xabD\xca\xd3\xfe\x89\x19F\bhc\x16\xbd\x80\x00\u07d4\xae6\xf7E!!\x91>\x80\x0e\x0f\xcd\x1ae\xa5G\x1c#\x84o\x89\b\xe3\xf5\v\x17<\x10\x00\x00\u07d4\xae?\x98\xa4C\xef\xe0\x0f>q\x1dR]\x98\x94\u071aa\x15{\x89\x10\x04\xe2\xe4_\xb7\xee\x00\x00\xe0\x94\xaeG\xe2`\x9c\xfa\xfe6\x9df\xd4\x15\xd99\xde\x05\b\x1a\x98r\x8a\x05\xba\xec\xf0%\xf9\xb6P\x00\x00\u07d4\xaeO\x12.5\xc0\xb1\xd1\xe4\x06\x92\x91E|\x83\xc0\u007f\x96_\xa3\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xaePU\x81L\xb8\xbe\f\x11{\xb8\xb1\xc8\u04b6;F\x98\xb7(\x89\x01\xbc\x93.\xc5s\xa3\x80\x00\u07d4\xaeS\x8cs\u0173\x8d\x8dXM~\xbd\xad\xef\xb1\\\xab\xe4\x83W\x896'\xe8\xf7\x127<\x00\x00\u07d4\xaeW\xcc\x12\x9a\x96\xa8\x99\x81\xda\xc6\r/\xfb\x87}]\xc5\xe42\x89<:#\x94\xb3\x96U\x00\x00\u07d4\xaeZ\xa1\xe6\u00b6\x0fo\xd3\xef\xe7!\xbbJq\x9c\xbe=o]\x89+$\u01b5Z^b\x00\x00\u07d4\xae\\\x9b\xda\xd3\xc5\u0221\"\x04D\xae\xa5\xc2)\xc1\x83\x9f\x1dd\x89\x19\xe2\xa4\xc8\x18\xb9\x06\x00\x00\u07d4\xae\\\xe35Z{\xa9\xb32v\f\tP\u00bcE\xa8_\xa9\xa0\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\xe0\x94\xae]\"\x1a\xfc\xd3\u0493U\xf5\b\xea\xdf\xca@\x8c\xe3<\xa9\x03\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\xaec[\xf781\x11\x9d-)\xc0\xd0O\xf8\xf8\xd8\u0425zF\x89Hz\x9a0E9D\x00\x00\xe0\x94\xaed\x81U\xa6X7\x0f\x92\x9b\xe3\x84\xf7\xe0\x01\x04~I\xddF\x8a\x02\xdf$\xae2\xbe D\x00\x00\xe0\x94\xaeo\fs\xfd\xd7|H\x97'Q!t\u0675\x02\x96a\x1cL\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xaep\xe6\x9d,J\n\xf8\x18\x80{\x1a'\x05\xf7\x9f\u0435\xdb\u01095e\x9e\xf9?\x0f\xc4\x00\x00\u07d4\xaew9\x12N\xd1S\x05%\x03\xfc\x10\x14\x10\xd1\xff\xd8\xcd\x13\xb7\x8964\xfb\x9f\x14\x89\xa7\x00\x00\u07d4\xaex\xbb\x84\x919\xa6\xba8\xae\x92\xa0\x9ai`\x1c\xc4\xcbb\u0449\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xae\x84\"\x10\xf4M\x14\u0124\u06d1\xfc\x9d;;P\x01O{\xf7\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xae\x84.\x81\x85\x8e\xcf\xed\xf6Plhm\xc2\x04\xac\x15\xbf\x8b$\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\xae\x89T\xf8\xd6\x16m\xe5\a\xcfa)}\x0f\xc7\xcak\x9eq(\x89\x10CV\x1a\x88)0\x00\x00\u07d4\xae\x9e\xcdk\u0755.\xf4\x97\xc0\x05\n\u0aca\x82\xa9\x18\x98\u0389\x01\xa0Ui\r\x9d\xb8\x00\x00\u07d4\xae\x9f\\?\xbb\xe0\u027c\xbf\x1a\xf8\xfft\xea(\v:]\x8b\b\x89]\u0212\xaa\x111\xc8\x00\x00\u07d4\xae\xad\x88\u0589Ak\x1c\x91\xf26D!7[}\x82\xd0RR\n\xfb\\Wm\x9f~\xb9>\u048a\r\xd0A \xba\t\xcf\xe6\x00\x00\u07d4\xae\xc2\u007f\xf5\xd7\xf9\xdd\u0691\x18?F\xf9\xd5%C\xb6\xcd+/\x89\x18e\x01'\xcc=\xc8\x00\x00\u07d4\xae\xe4\x9dh\xad\xed\xb0\x81\xfdCpZ_x\xc7x\xfb\x90\xdeH\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xae\xf5\xb1\"X\xa1\x8d\xec\a\xd5\xec.1et\x91\x9dy\xd6\u0589lk\x93[\x8b\xbd@\x00\x00\u07d4\xae\xfc\xfe\x88\xc8&\xcc\xf11\xd5N\xb4\ua7b8\x0ea\xe1\xee%\x89\x12nr\xa6\x9aP\xd0\x00\x00\u07d4\xaf\x06\xf5\xfam\x12\x14\xecC\x96}\x1b\xd4\xdd\xe7J\xb8\x14\xa98\x89\x04\xc5>\xcd\xc1\x8a`\x00\x00\u07d4\xaf\x11H\xefl\x8e\x10=u0\xef\xc9\x16y\u026c'\x00\t\x93\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xaf >\"\x9d~mA\x9d\xf47\x8e\xa9\x87\x15Q_c\x14\x85\x89j\xcb=\xf2~\x1f\x88\x00\x00\xe0\x94\xaf X\xc7(,\xf6|\x8c<\xf90\x13<\x89a|\xe7])\x8a\x01w\"J\xa8D\xc7 \x00\x00\u07d4\xaf&\xf7\u01bfE> x\xf0\x89S\u4c80\x04\xa2\xc1\xe2\t\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xaf0\x87\xe6.\x04\xbf\x90\rZT\xdc>\x94bt\u0692B;\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xaf6\x14\u0736\x8a6\xe4ZN\x91\x1ebybG\"-Y[\x89z\x81\x06_\x11\x03\xbc\x00\x00\u07d4\xaf6\x15\u01c9\u0431\x15*\xd4\xdb%\xfe]\xcf\"(\x04\xcfb\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xaf<\xb5\x96Y3\xe7\xda\u0603i;\x9c>\x15\xbe\xb6\x8aHs\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xafD\x93\xe8R\x1c\xa8\x9d\x95\xf5&|\x1a\xb6?\x9fEA\x1e\x1b\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xafL\xf4\x17\x85\x16\x1fW\x1d\f\xa6\x9c\x94\xf8\x02\x1fA)N\u028a\x02\x15\xf85\xbcv\x9d\xa8\x00\x00\u07d4\xafR\x9b\xdbE\x9c\xc1\x85\xbe\xe5\xa1\u014b\xf7\xe8\xcc\xe2\\\x15\r\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\u07d4\xafg\xfd>\x12\u007f\xd9\xdc6\xeb?\xcdj\x80\u01feOu2\xb2\x89Z\x87\xe7\xd7\xf5\xf6X\x00\x00\u07d4\xafw\x1094Z40\x01\xbc\x0f\x8aY#\xb1&\xb6\rP\x9c\x895e\x9e\xf9?\x0f\xc4\x00\x00\xe0\x94\xaf\u007fy\xcbAZ\x1f\xb8\u06fd\tF\a\xee\x8dA\xfb|Z;\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xaf\x87\xd27\x1e\xf3x\x95\u007f\xbd\x05\xba/\x1df\x93\x1b\x01\u2e09%\xf2s\x93=\xb5p\x00\x00\u07d4\xaf\x88\x0f\xc7V}U\x95\xca\xcc\xe1\\?\xc1L\x87B\xc2l\x9e\x89\a?u\u0460\x85\xba\x00\x00\u07d4\xaf\x8e\x1d\xcb1L\x95\r6\x87CM0\x98X\xe1\xa8s\x9c\u0509\x0e~\xeb\xa3A\vt\x00\x00\u07d4\xaf\x99-\xd6i\xc0\x88>U\x15\xd3\xf3\x11*\x13\xf6\x17\xa4\xc3g\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xaf\xa1\u056d8\xfe\xd4GY\xc0[\x89\x93\xc1\xaa\r\xac\xe1\x9f@\x89\x04V9\x18$O@\x00\x00\xe0\x94\xaf\xa59XnG\x19\x17J;F\xb9\xb3\xe6c\xa7\u0475\xb9\x87\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\xaf\xa6\x94n\xff\xd5\xffS\x15O\x82\x01\x02S\xdfG\xae(\f\u0309j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xaf\xc8\xeb\u860b\xd4\x10Z\xccL\x01\x8eTj\x1e\x8f\x9cx\x88\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94\xaf\xcc}\xbb\x83V\xd8B\xd4:\xe7\xe2<\x84\"\xb0\"\xa3\b\x03\x8a\x06o\xfc\xbf\xd5\xe5\xa3\x00\x00\x00\u07d4\xaf\xd0\x19\xff6\xa0\x91U4ki\x97H\x15\xa1\xc9\x12\xc9\n\xa4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xaf\xda\xc5\xc1\xcbV\xe2E\xbfp3\x00f\xa8\x17\uabecL\u0449\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xaf\xdd\x1bxab\xb81~ \xf0\xe9y\xf4\xb2\xceHmv]\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xaf\xf1\x04Z\xdf'\xa1\xaa2\x94a\xb2M\xe1\xba\u950ai\x8b\x89\x01\u03c4\xa3\n\n\f\x00\x00\u07d4\xaf\xf1\a\x96\v~\xc3N\u0590\xb6e\x02M`\x83\x8c\x19\x0fp\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xaf\xf1\x1c\xcfi\x93\x04\xd5\xf5\x86*\xf8`\x83E\x1c&\xe7\x9a\xe5\x89l]\xb2\xa4\xd8\x15\xdc\x00\x00\u07d4\xaf\xf1at\nm\x90\x9f\xe9\x9cY\xa9\xb7yE\xc9\x1c\xc9\x14H\x89\x03@\xaa\xd2\x1b;p\x00\x00\xe0\x94\xaf\xfc\x99\xd5\ubd28O\xe7x\x8d\x97\xdc\xe2t\xb08$\x048\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\xaf\xfe\xa0G7\"\xcb\u007f\x0e\x0e\x86\xb9\xe1\x18\x83\xbfB\x8d\x8dT\x89i*\xe8\x89p\x81\xd0\x00\x00\xe0\x94\xb0\t\x96\xb0Vn\xcb>rC\xb8\"y\x88\u0733R\xc2\x18\x99\x8a\x02\x8a\x85t%Fo\x80\x00\x00\u07d4\xb0\x1e8\x9b(\xa3\x1d\x8eI\x95\xbd\xd7\xd7\xc8\x1b\xee\xab\x1eA\x19\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb0-\x06(s3EE\u03a2\x92\x18\xe4\x05w`Y\x0ft#\x89\xac\xb6\xa1\xc7\xd9:\x88\x00\x00\u07d4\xb0/\xa2\x93\x87\xec\x12\xe3\u007fi\"\xacL\xe9\x8c[\t\xe0\xb0\x0f\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb06\x91k\xda\u03d4\xb6\x9eZ\x8ae`)u\xeb\x02a\x04\u0749\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xb0A1\x0f\xe9\xee\u0586L\xed\u053e\xe5\x8d\xf8\x8e\xb4\xed<\xac\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xb0U\xafL\xad\xfc\xfd\xb4%\xcfe\xbad1\a\x8f\a\xec\u056b\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94\xb0W\x11S\xdb\x1cN\u05ec\xae\xfe\x13\xec\xdf\xdbr\xe7\xe4\xf0j\x8a\x11\f\xffyj\xc1\x95 \x00\x00\u07d4\xb0n\xab\t\xa6\x10\u01a5=V\xa9F\xb2\xc44\x87\xac\x1d[-\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb0rI\xe0U\x04J\x91U5\x9a@)7\xbb\xd9T\xfeH\xb6\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94\xb0v\x182\x8a\x90\x13\a\xa1\xb7\xa0\xd0X\xfc\xd5xn\x9er\xfe\x8a\x06gI]JC0\xce\x00\x00\u07d4\xb0y\xbbM\x98f\x14:m\xa7*\xe7\xac\x00\"\x06)\x811\\\x89)3\x1eeX\xf0\xe0\x00\x00\u07d4\xb0{\xcc\bZ\xb3\xf7)\xf2D\x00Ah7\xb6\x996\xba\x88s\x89lm\x84\xbc\xcd\xd9\xce\x00\x00\u07d4\xb0{\xcf\x1c\xc5\xd4F.Q$\xc9e\xec\xf0\xd7\r\xc2z\xcau\x89V\xbcu\xe2\xd61\x00\x00\x00\u07d4\xb0|\xb9\xc1$\x05\xb7\x11\x80uC\u0113De\xf8\u007f\x98\xbd-\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xb0\u007f\u07af\xf9\x1dD`\xfel\xd0\u8870\xbd\x8d\"\xa6.\x87\x8a\x01\x1d%)\xf3SZ\xb0\x00\x00\xe0\x94\xb0\x9f\xe6\xd44\x9b\x99\xbc7\x93\x80T\x02-T\xfc\xa3f\xf7\xaf\x8a*Z\x05\x8f\u0095\xed\x00\x00\x00\xe0\x94\xb0\xaa\x00\x95\f\x0e\x81\xfa2\x10\x17>r\x9a\xaf\x16:'\xcdq\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4\xb0\xacN\xfff\x80\xee\x14\x16\x9c\xda\xdb\xff\xdb0\x80Om%\xf5\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb0\xb3j\xf9\xae\xee\u07d7\xb6\xb0\"\x80\xf1\x14\xf19\x84\xea2`\x895e\x9e\xf9?\x0f\xc4\x00\x00\u07d4\xb0\xb7y\xb9K\xfa<.\x1fX{\u031c~!x\x92\"7\x8f\x89T\x06\x923\xbf\u007fx\x00\x00\u07d4\xb0\xba\xeb0\xe3\x13wlLm$t\x02\xbaAg\xaf\u0361\u0309j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xb0\xbb)\xa8a\xea\x1dBME\xac\u053f\u0112\xfb\x8e\xd8\t\xb7\x89\x04V9\x18$O@\x00\x00\xe0\x94\xb0\xc1\xb1w\xa2 \xe4\x1f|t\xd0|\u0785i\xc2\x1cu\xc2\xf9\x8a\x01/\x93\x9c\x99\xed\xab\x80\x00\x00\u07d4\xb0\xc7\xceL\r\xc3\u00bb\xb9\x9c\xc1\x85{\x8aE_a\x17\x11\u0389\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xb0\xce\xf8\xe8\xfb\x89\x84\xa6\x01\x9f\x01\xc6y\xf2r\xbb\xe6\x8f\\w\x89\b=lz\xabc`\x00\x00\xe0\x94\xb0\xd3+\xd7\xe4\u6577\xb0\x1a\xa3\xd0Ao\x80U}\xba\x99\x03\x8a\x03s\x9f\xf0\xf6\xe6\x130\x00\x00\xe0\x94\xb0\xd3\u0247+\x85\x05n\xa0\xc0\xe6\xd1\xec\xf7\xa7~<\u6ac5\x8a\x01\x0f\b\xed\xa8\xe5U\t\x80\x00\u07d4\xb0\xe4i\u0206Y8\x15\xb3IV8Y]\xae\xf0f_\xaeb\x89i*\xe8\x89p\x81\xd0\x00\x00\u07d4\xb0\xe7`\xbb\a\xc0\x81wsE\xe0W\x8e\x8b\u0218\"mN;\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb1\x040\x04\xec\x19A\xa8\xcfO+\x00\xb1W\x00\u076co\xf1~\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb1\x05\xdd=\x98|\xff\xd8\x13\xe9\xc8P\n\x80\xa1\xad%}V\u0189lj\xccg\u05f1\xd4\x00\x00\u07d4\xb1\x0f\u04a6G\x10/\x88\x1ft\xc9\xfb\xc3}\xa62\x94\x9f#u\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\xe0\x94\xb1\x15\xee:\xb7d\x1e\x1a\xa6\xd0\x00\xe4\x1b\xfc\x1e\xc7!\f/2\x8a\x02\xc0\xbb=\xd3\fN \x00\x00\u07d4\xb1\x17\x8a\xd4s\x83\xc3\x1c\x814\xa1\x94\x1c\xbc\xd4t\xd0bD\xe2\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xb1\x17\x95\x89\u1779\xd4\x15W\xbb\xec\x1c\xb2L\xcc-\xec\x1c\u007f\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\xb1\x19\u76a9\xb9\x16Re\x81\xcb\xf5!\xefGJ\xe8M\xcf\xf4\x89O\xba\x10\x01\xe5\xbe\xfe\x00\x00\u07d4\xb1\x1f\xa7\xfb'\n\xbc\xdfZ.\xab\x95\xaa0\u013566\uffc9+^:\xf1k\x18\x80\x00\x00\u07d4\xb1$\xbc\xb6\xff\xa40\xfc\xae.\x86\xb4_'\xe3\xf2\x1e\x81\xee\b\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb1)\xa5\xcbq\x05\xfe\x81\v\u0615\xdcr\x06\xa9\x91\xa4TT\x88\x89\x01\xa0Ui\r\x9d\xb8\x00\x00\xe0\x94\xb1.\xd0{\x8a8\xadU\x066?\xc0z\vmy\x996\xbd\xaf\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xb14\xc0\x049\x1a\xb4\x99(x3zQ\xec$/B(WB\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb1?\x93\xaf0\xe8\xd7fs\x81\xb2\xb9[\xc1\xa6\x99\xd5\xe3\xe1)\x89\x16\u012b\xbe\xbe\xa0\x10\x00\x00\u07d4\xb1E\x92\x85\x86>\xa2\xdb7Y\xe5F\u03b3\xfb7a\xf5\x90\x9c\x89<\xd7*\x89@\x87\xe0\x80\x00\u07d4\xb1F\xa0\xb9%U<\xf0o\xca\xf5J\x1bM\xfe\xa6!)\aW\x89lnY\xe6|xT\x00\x00\xe0\x94\xb1Jz\xaa\x8fI\xf2\xfb\x9a\x81\x02\u05bb\xe4\u010a\xe7\xc0o\xb2\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xb1K\xbe\xffpr\tu\xdca\x91\xb2\xa4O\xf4\x9f&r\x87<\x89\a\xc0\x86\x0eZ\x80\xdc\x00\x00\xe0\x94\xb1L\xc8\xde3\xd63\x826S\x9aH\x90 \xceFU\xa3+\u018a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xb1M\xdb\x03\x86\xfb`c\x98\xb8\xccGVZ\xfa\xe0\x0f\xf1\xd6j\x89\xa1*\xff\b>f\xf0\x00\x00\u07d4\xb1S\xf8(\xdd\amJ|\x1c%t\xbb-\xee\x1aD\xa3\x18\xa8\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xb1T\x0e\x94\xcf\xf3F\\\xc3\u0447\xe7\xc8\u3f6f\x98FY\u2262\x15\xe4C\x90\xe33\x00\x00\u07d4\xb1X\xdbC\xfab\xd3\x0ee\xf3\u041b\xf7\x81\u01f6sr\uba89l]\xb2\xa4\xd8\x15\xdc\x00\x00\u07d4\xb1ar_\xdc\xed\xd1yR\xd5{#\xef([~K\x11i\xe8\x89\x02\xb6\xdf\xed6d\x95\x80\x00\u07d4\xb1dy\xba\x8e}\xf8\xf6>\x1b\x95\xd1I\u0345)\xd75\xc2\u0689-\xe3:j\xac2T\x80\x00\u07d4\xb1f\xe3}.P\x1a\xe7<\x84\x14+_\xfbZ\xa6U\xddZ\x99\x89l]\xb2\xa4\xd8\x15\xdc\x00\x00\u07d4\xb1\x83\xeb\xeeO\xcbB\xc2 \xe4wt\xf5\x9dlT\xd5\xe3*\xb1\x89V\xf7\xa9\xc3<\x04\xd1\x00\x00\u07d4\xb1\x88\a\x84D\x02~8g\x98\xa8\xaehi\x89\x19\xd5\xcc#\r\x89\x0e~\xeb\xa3A\vt\x00\x00\u07d4\xb1\x89j7\xe5\u0602Z-\x01vZ\xe5\xdeb\x99w\u0783R\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xb1\x8eg\xa5\x05\n\x1d\xc9\xfb\x19\t\x19\xa3=\xa88\xefDP\x14\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xb1\xa2\xb4:t3\xdd\x15\v\xb8\"'\xedQ\x9c\u05b1B\u04c2\x89\x94mb\rtK\x88\x00\x00\u07d4\xb1\xc0\u040b6\xe1\x84\xf9\x95*@7\xe3\xe5:f}\a\nN\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb1\xc3(\xfb\x98\xf2\xf1\x9a\xb6do\n|\x8cVo\xdaZ\x85@\x89\x87\x86x2n\xac\x90\x00\x00\xe0\x94\xb1\xc7Qxi9\xbb\xa0\xd6q\xa6w\xa1X\u01ab\xe7&^F\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94\xb1\xcdK\xdf\xd1\x04H\x9a\x02n\u025dYs\a\xa0By\xf1s\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xb1\u03d4\xf8\t\x15\x05\x05_\x01\n\xb4\xba\u0196\xe0\xca\x0fg\xa1\x89U\xa6\xe7\x9c\xcd\x1d0\x00\x00\u07d4\xb1\u05b0\x1b\x94\xd8T\xfe\x8b7J\xa6^\x89\\\xf2*\xa2V\x0e\x892\xf5\x1e\u06ea\xa30\x00\x00\xe0\x94\xb1\u06e5%\v\xa9bWU$n\x06yg\xf2\xad/\a\x91\u078a\x10\xf0\xcf\x06M\u0552\x00\x00\x00\u07d4\xb1\xe2\u0755\xe3\x9a\xe9w\\U\xae\xb1?\x12\xc2\xfa#0S\xba\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb1\xe6\xe8\x10\xc2J\xb0H\x8d\xe9\xe0\x1eWH7\x82\x9f|w\u0409\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xb1\xe9\xc5\xf1\xd2\x1eauzk.\xe7Y\x13\xfcZ\x1aA\x01\u00c9lk\x93[\x8b\xbd@\x00\x00\u07d4\xb2\x03\u049elV\xb9&\x99\u0139-\x1fo\x84d\x8d\xc4\u03fc\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xb2\x16\xdcY\xe2|=ry\xf5\xcd[\xb2\xbe\u03f2`n\x14\u0649\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xb2\x1byy\xbf|\\\xa0\x1f\xa8-\xd6@\xb4\x1c9\xe6\u01bcu\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\xb2#\xbf\x1f\xbf\x80H\\\xa2\xb5V}\x98\xdb{\xc3SM\xd6i\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xb2-PU\xd9b15\x96\x1ej\xbd'<\x90\xde\xea\x16\xa3\xe7\x89K\xe4\xe7&{j\xe0\x00\x00\u07d4\xb2-\xad\xd7\xe1\xe0R2\xa927\xba\xed\x98\xe0\u07d2\xb1\x86\x9e\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb24\x03_uDF<\xe1\xe2+\xc5S\x06F\x84\xc5\x13\xcdQ\x89\r\x89\xfa=\u010d\xcf\x00\x00\u07d4\xb2G\u03dcr\xecH*\xf3\xea\xa7Ye\x8fy=g\nW\f\x891p\x8a\xe0\x04T@\x00\x00\u07d4\xb2ghA\xee\x9f-1\xc1r\xe8#\x03\xb0\xfe\x9b\xbf\x9f\x1e\t\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xb2y\xc7\xd3U\u0088\x03\x92\xaa\u046a!\xee\x86|;5\a\u07c9D[\xe3\xf2\uf1d4\x00\x00\u07d4\xb2|\x1a$ L\x1e\x11\x8du\x14\x9d\xd1\t1\x1e\a\xc0s\xab\x89\xa8\r$g~\xfe\xf0\x00\x00\u07d4\xb2\x81\x81\xa4X\xa4@\xf1\u01bb\x1d\xe8@\x02\x81\xa3\x14\x8fL5\x89\x14b\fW\xdd\xda\xe0\x00\x00\xe0\x94\xb2\x82E\x03|\xb1\x92\xf7W\x85\u02c6\xcb\xfe|\x93\r\xa2X\xb0\x8a\x03c\\\x9a\xdc]\xea\x00\x00\x00\u07d4\xb2\x87\xf7\xf8\xd8\u00c7,\x1bXk\xcd}\n\xed\xbf~s'2\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xb2\x8b\xb3\x9f4fQ|\xd4o\x97\x9c\xf5\x96S\xee}\x8f\x15.\x89\x18e\x01'\xcc=\xc8\x00\x00\u07d4\xb2\x8d\xbf\xc6I\x98\x94\xf7:q\xfa\xa0\n\xbe\x0fK\xc9\u045f*\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xb2\x96\x8f}5\xf2\b\x87\x161\xc6h{?=\xae\xab\xc6al\x89\bu\xc4\u007f(\x9fv\x00\x00\u07d4\xb2\x9f[|\x190\xd9\xf9z\x11^\x06pf\xf0\xb5M\xb4K;\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb2\xa1D\xb1\xeag\xb9Q\x0f\"g\xf9\xda9\xd3\xf9=\xe2fB\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb2\xa2\xc2\x11\x16\x12\xfb\x8b\xbb\x8e}\xd97\x8dg\xf1\xa3\x84\xf0P\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xb2\xa4\x98\xf0;\xd7\x17\x8b\u0627\x89\xa0\x0fR7\xafy\xa3\xe3\xf8\x8a\x04\x1b\xad\x15^e\x12 \x00\x00\u07d4\xb2\xaa/\x1f\x8e\x93\xe7\x97\x13\xd9,\xea\x9f\xfc\xe9\xa4\n\xf9\xc8-\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb2\xb5\x16\xfd\u045e\u007f8d\xb6\xd2\xcf\x1b%*AV\xf1\xb0;\x89\x02\xe9\x83\xc7a\x15\xfc\x00\x00\u07d4\xb2\xb7\u0374\xffKa\u0577\xce\v\"p\xbb\xb5&\x97C\xec\x04\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb2\xbd\xbe\u07d5\x90\x84v\xd7\x14\x8a7\f\u0193t6(\x05\u007f\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xb2\xbf\xaaX\xb5\x19l\\\xb7\xf8\x9d\xe1_G\x9d\x188\xdeq=\x89\x01#n\xfc\xbc\xbb4\x00\x00\u07d4\xb2\xc5>\xfa3\xfeJ:\x1a\x80 \\s\xec;\x1d\xbc\xad\x06\x02\x89h\x01\u06b3Y\x18\x93\x80\x00\xe0\x94\xb2\xd06\x05\x15\xf1}\xab\xa9\x0f\u02ec\x82\x05\xd5i\xb9\x15\u05ac\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94\xb2\xd1\xe9\x9a\xf9\x121\x85\x8epe\xdd\x19\x183\r\xc4\xc7G\u054a\x03\x89O\x0eo\x9b\x9fp\x00\x00\u07d4\xb2\u066b\x96d\xbc\xf6\xdf <4o\u0192\xfd\x9c\xba\xb9 ^\x89\x17\xbex\x97`e\x18\x00\x00\u07d4\xb2\u0777\x86\xd3yN'\x01\x87\xd0E\x1a\xd6\u0237\x9e\x0e\x87E\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xb2\xe0\x85\xfd\xdd\x14h\xba\aA['NsN\x11#\u007f\xb2\xa9\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xb2\xe9\xd7k\xf5\x0f\xc3k\xf7\u04d4Kc\xe9\u0288\x9bi\x99h\x89\x902\xeab\xb7K\x10\x00\x00\xe0\x94\xb2\xf9\xc9r\xc1\xe9swU\xb3\xff\x1b0\x88s\x83\x969[&\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94\xb2\xfc\x84\xa3\xe5\nP\xaf\x02\xf9M\xa08>\u055fq\xff\x01\u05ca\x06ZM\xa2]0\x16\xc0\x00\x00\u07d4\xb3\x05\v\xef\xf9\xde3\xc8\x0e\x1f\xa1R%\xe2\x8f,A:\xe3\x13\x89%\xf2s\x93=\xb5p\x00\x00\u07d4\xb3\x11\x96qJH\xdf\xf7&\xea\x943\xcd)\x12\xf1\xa4\x14\xb3\xb3\x89\x91Hx\xa8\xc0^\xe0\x00\x00\xe0\x94\xb3\x14[tPm\x1a\x8d\x04|\xdc\xdcU9*{SPy\x9a\x8a\x1bb)t\x1c\r=]\x80\x00\u07d4\xb3 \x83H6\xd1\xdb\xfd\xa9\xe7\xa3\x18M\x1a\xd1\xfdC \xcc\xc0\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb3#\u073f.\xdd\xc58.\u4efb \x1c\xa3\x93\x1b\xe8\xb48\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xb3$\x00\xfd\x13\xc5P\t\x17\xcb\x03{)\xfe\"\xe7\xd5\"\x8f-\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4\xb3%gL\x01\xe3\xf7)\rR&3\x9f\xbe\xacg\xd2!'\x9f\x89\x97\xc9\xceL\xf6\xd5\xc0\x00\x00\u07d4\xb3(%\xd5\xf3\xdb$\x9e\xf4\xe8\\\xc4\xf31S\x95\x89v\u8f09\x1b-\xf9\xd2\x19\xf5y\x80\x00\u07d4\xb3*\xf3\xd3\xe8\xd0u4I&To.2\x88{\xf9;\x16\xbd\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xb3/\x1c&\x89\xa5\xcey\xf1\xbc\x97\v1XO\x1b\xcf\"\x83\xe7\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xb3<\x03#\xfb\xf9\xc2l\x1d\x8a\xc4N\xf7C\x91\u0400F\x96\u0689\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xb3O\x04\xb8\xdbe\xbb\xa9\xc2n\xfcL\xe6\xef\xc5\x04\x81\xf3\xd6]\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xb3U}9\xb5A\x1b\x84D__T\xf3\x8fb\xd2qM\x00\x87\x89 \x86\xac5\x10R`\x00\x00\xe0\x94\xb3X\xe9|p\xb6\x05\xb1\xd7\xd7)\u07f6@\xb4<^\xaf\xd1\xe7\x8a\x04<3\xc1\x93ud\x80\x00\x00\u0794\xb3^\x8a\x1c\r\xac~\x0ef\u06ecsjY*\xbdD\x01%a\x88\xcf\xceU\xaa\x12\xb3\x00\x00\xe0\x94\xb3fx\x94\xb7\x86<\x06\x8a\xd3D\x87?\xcf\xf4\xb5g\x1e\x06\x89\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xb3qw1\xda\xd6Q2\xday-\x87`0\xe4j\xc2'\xbb\x8a\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb3s\x1b\x04l\x8a\u0195\xa1'\xfdy\u0425\xd5\xfaj\xe6\xd1.\x89lO\xd1\xee$nx\x00\x00\u07d4\xb3|+\x9fPc{\xec\xe0\u0295\x92\b\xae\xfe\xe6F;\xa7 \x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xb3\x88\xb5\xdf\xec\xd2\xc5\u4d56W|d%V\xdb\xfe'xU\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xb3\x8cNS{]\xf90\xd6Zt\xd0C\x83\x1dkH[\xbd\xe4\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\xe0\x94\xb3\x919Wa\x94\xa0\x86a\x95\x15\x1f3\xf2\x14\n\xd1\u0306\u03ca\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\xb3\x9fL\x00\xb2c\f\xab}\xb7)^\xf4=G\xd5\x01\xe1\u007f\u05c9\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xb3\xa6K\x11vrOT\t\xe1AJ5#f\x1b\xae\xe7KJ\x89\x01ch\xffO\xf9\xc1\x00\x00\u07d4\xb3\xa6\xbdA\xf9\xd9\xc3 \x1e\x05\v\x87\x19\x8f\xbd\xa3\x994\"\x10\x89\xc4a\xe1\xdd\x10)\xb5\x80\x00\u07d4\xb3\xa8\xc2\xcb}5\x8eW9\x94\x1d\x94[\xa9\x04Z\x02:\x8b\xbb\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb3\xaeT\xfb\xa0\x9d>\xe1\u05bd\xd1\xe9W\x929\x19\x02L5\xfa\x89\x03\x8d,\xeee\xb2*\x80\x00\u07d4\xb3\xb7\xf4\x93\xb4J,\x8d\x80\xecx\xb1\xcd\xc7Ze+s\xb0l\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb3\xc2(s\x1d\x18m-\xed[_\xbe\x00Lfl\x8eF\x9b\x86\x89\x01\x92t\xb2Y\xf6T\x00\x00\u07d4\xb3\xc2``\x9b\x9d\xf4\t^l]\xff9\x8e\xeb^-\xf4\x99\x85\x89\r\xc5_\xdb\x17d{\x00\x00\u07d4\xb3\xc6[\x84Z\xbal\xd8\x16\xfb\xaa\xe9\x83\xe0\xe4l\x82\xaa\x86\"\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb3\xc9H\x11\xe7\x17[\x14\x8b(\x1c\x1a\x84[\xfc\x9b\xb6\xfb\xc1\x15\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xb3\xe2\x0e\xb4\xde\x18\xbd\x06\x02!h\x98\x94\xbe\u5bb2SQ\xee\x89\x03\xfc\x80\xcc\xe5\x16Y\x80\x00\u07d4\xb3\xe3\xc49\x06\x98\x80\x15f\x00\u0089.D\x8dA6\xc9-\x9b\x89.\x14\x1e\xa0\x81\xca\b\x00\x00\xe0\x94\xb3\xf8*\x87\xe5\x9a9\xd0\u0480\x8f\aQ\xebr\xc22\x9c\xdc\u014a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\xb3\xfc\x1dh\x81\xab\xfc\xb8\xbe\xcc\v\xb0!\xb8\xb7;r3\u0751\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\u07d4\xb4\x05\x94\xc4\xf3fN\xf8I\u0326\"{\x8a%\xaai\t%\xee\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xb4\x1e\xaf]Q\xa5\xba\x1b\xa3\x9b\xb4\x18\u06f5O\xabu\x0e\xfb\x1f\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb4$\u058d\x9d\r\x00\xce\xc1\x93\x8c\x85N\x15\xff\xb8\x80\xba\x01p\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xb4%bs\x96+\xf61\xd0\x14U\\\xc1\xda\r\xcc1akI\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb40g\xfep\u0675Ys\xbaX\xdcd\xdd\u007f1\x1eUBY\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xb46W\xa5\x0e\xec\xbc0w\xe0\x05\xd8\xf8\xd9O7xv\xba\u0509\x01\xec\x1b:\x1f\xf7Z\x00\x00\u07d4\xb4<'\xf7\xa0\xa1\"\bK\x98\xf4\x83\x92%A\u0203l\xee,\x89&\u009eG\u0104L\x00\x00\xe0\x94\xb4A5v\x86\x9c\b\xf9Q*\xd3\x11\xfe\x92Y\x88\xa5-4\x14\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xb4F\x05U$q\xa6\xee\xe4\u06abq\xff;\xb4\x13&\xd4s\xe0\x89-~=Q\xbaS\xd0\x00\x00\u07d4\xb4GW\x1d\xac\xbb>\u02f6\xd1\xcf\v\f\x8f88\xe5#$\xe2\x89\x01\xa3\x18f\u007f\xb4\x05\x80\x00\u07d4\xb4G\x83\xc8\xe5{H\a\x93\xcb\u059aE\xd9\f{O\fH\xac\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xb4H\x15\xa0\xf2\x8eV\x9d\x0e\x92\x1aJ\u078f\xb2d%&Iz\x89\x03\x027\x9b\xf2\xca.\x00\x00\u07d4\xb4Im\xdb'y\x9a\"$W\xd79y\x11g(\u8844[\x89\x8d\x81\x9e\xa6_\xa6/\x80\x00\xe0\x94\xb4RL\x95\xa7\x86\x0e!\x84\x02\x96\xa6\x16$@\x19B\x1cJ\xba\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xb4\\\xca\r6\x82fbh<\xf7\u0432\xfd\xach\u007f\x02\xd0\u010965\u026d\xc5\u07a0\x00\x00\u0794\xb4d@\u01d7\xa5V\xe0L}\x91\x04f\x04\x91\xf9k\xb0v\xbf\x88\xce\xc7o\x0eqR\x00\x00\u07d4\xb4j\u0386^,P\xeaF\x98\xd2\x16\xabE]\xffZ\x11\xcdr\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb4m\x11\x82\xe5\xaa\xca\xff\r&\xb2\xfc\xf7/<\x9f\xfb\xcd\xd9}\x89\xaa*`<\xdd\u007f,\x00\x00\u07d4\xb4\x89!\xc9h}U\x10tE\x84\x93n\x88\x86\xbd\xbf-\xf6\x9b\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb4\x98\xbb\x0fR\x00\x05\xb6!jD%\xb7Z\xa9\xad\xc5-b+\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\xb4\xb1\x1d\x10\x9f`\x8f\xa8\xed\xd3\xfe\xa9\xf8\xc3\x15d\x9a\xeb=\x11\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\xb4\xb1K\xf4TU\u042b\b\x035\x8bu$\xa7+\xe1\xa2\x04[\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xb4\xb1\x85\xd9C\xee+Xc\x1e3\xdf\xf5\xafhT\xc1y\x93\xac\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb4\xbf$\u02c3hk\xc4i\x86\x9f\xef\xb0D\xb9\tqi\x93\xe2\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb4\xc2\x00@\xcc\u0661\xa3(=\xa4\u0522\xf3e\x82\bC\xd7\xe2\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb4\xc8\x17\x0f{*\xb56\xd1\u0662[\xdd :\xe1(\x8d\xc3\u0549\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xb4\xd8/.i\x94?}\xe0\xf5\xf7t8y@o\xac.\x9c\xec\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\xe0\x94\xb4\xddF\f\xd0\x16rZd\xb2.\xa4\xf8\xe0n\x06gN\x03>\x8a\x01#\x1b\xb8t\x85G\xa8\x00\x00\u07d4\xb4\xddT\x99\xda\xeb%\a\xfb-\xe1\"\x97s\x1dLr\xb1k\xb0\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xb5\x04l\xb3\xdc\x1d\xed\xbd6E\x14\xa2\x84\x8eD\xc1\xdeN\xd1G\x8a\x03{}\x9b\xb8 @^\x00\x00\xe0\x94\xb5\b\xf9\x87\xb2\xde4\xaeL\xf1\x93\u0785\xbf\xf6\x13\x89b\x1f\x88\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xb5\tU\xaan4\x15q\x98f\b\xbd\u0211\xc2\x13\x9fT\f\u07c9j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xb5\f\x14\x9a\x19\x06\xfa\xd2xo\xfb\x13Z\xabP\x177\xe9\xe5o\x89\x15\b\x94\xe8I\xb3\x90\x00\x00\u07d4\xb5\f\x9fW\x89\xaeD\xe2\xdc\xe0\x17\xc7\x14\xca\xf0\f\x83\x00\x84\u0089\x15[\xd90\u007f\x9f\xe8\x00\x00\u07d4\xb5\x14\x88,\x97\x9b\xb6B\xa8\r\u04c7T\u0578\xc8)m\x9a\a\x893\xc5I\x901r\f\x00\x00\u07d4\xb5\x1d\u0734\xddN\x8a\xe6\xbe3m\xd9eIq\xd9\xfe\xc8kA\x89\x16\xd4d\xf8=\u2500\x00\u07d4\xb5\x1eU\x8e\xb5Q/\xbc\xfa\x81\xf8\u043d\x93\x8cy\xeb\xb5$+\x89&\u009eG\u0104L\x00\x00\u07d4\xb5#\xff\xf9t\x98q\xb3S\x88C\x887\xf7\xe6\xe0\u07a9\xcbk\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xb5-\xfbE\xde]t\xe3\xdf \x832\xbcW\x1c\x80\x9b\x8d\xcf2\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xb55\xf8\u06c7\x9f\xc6\u007f\xecX\x82J\\\xbenT\x98\xab\xa6\x92\x89g\x8a\x93 b\xe4\x18\x00\x00\u07d4\xb57\xd3jp\xee\xb8\xd3\xe5\xc8\r\xe8\x15\"\\\x11X\u02d2\u0109QP\xae\x84\xa8\xcd\xf0\x00\x00\u07d4\xb5;\xcb\x17L%\x184\x8b\x81\x8a\xec\xe0 6E\x96Fk\xa3\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb5I>\xf1srDE\xcf4\\\x03]'\x9b\xa7Y\xf2\x8dQ\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xb5S\xd2]kT!\xe8\x1c*\xd0^\v\x8b\xa7Q\xf8\xf0\x10\xe3\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb5Tt\xbaX\xf0\xf2\xf4\x0el\xba\xbe\xd4\xea\x17n\x01\x1f\xca\u0589j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xb5U\xd0\x0f\x91\x90\xcc6w\xae\xf3\x14\xac\xd7?\xdc99\x92Y\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb5W\xab\x949\xefP\xd27\xb5S\xf0%\b6JFj\\\x03\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xb5jx\x00(\x03\x9c\x81\xca\xf3{gu\xc6 \u7195Gd\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb5j\u04ae\xc6\xc8\xc3\xf1\x9e\x15\x15\xbb\xb7\u0751(RV\xb69\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb5t\x13\x06\n\xf3\xf1N\xb4y\x06_\x1e\x9d\x19\xb3uz\xe8\u0309\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\xb5uI\xbf\xbc\x9b\xdd\x18\xf76\xb2&P\xe4\x8as`\x1f\xa6\\\x89\x18-~L\xfd\xa08\x00\x00\xe0\x94\xb5w\xb6\xbe\xfa\x05N\x9c\x04\x04a\x85P\x94\xb0\x02\xd7\xf5{\u05ca\x18#\xf3\xcfb\x1d#@\x00\x00\u07d4\xb5{\x04\xfa#\xd1 ?\xae\x06\x1e\xacEB\xcb`\xf3\xa5v7\x89\nZ\xa8P\t\xe3\x9c\x00\x00\u07d4\xb5\x87\f\xe3B\xd43C36s\x03\x8bGd\xa4n\x92_>\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb5\x87\xb4J,\xa7\x9eK\xc1\u074b\xfd\xd4: qP\xf2\xe7\xe0\x89\",\x8e\xb3\xfff@\x00\x00\u07d4\xb5\x89gm\x15\xa0DH4B0\xd4\xff'\xc9^\xdf\x12,I\x8965\u026d\xc5\u07a0\x00\x00\u0794\xb5\x8bR\x86^\xa5]\x806\xf2\xfa\xb2`\x98\xb3R\u0283~\x18\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\xb5\x90k\n\u9881X\xe8\xacU\x0e9\xda\bn\xe3\x15v#\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xb5\xa4g\x96\x85\xfa\x14\x19l.\x920\xc8\xc4\xe3;\xff\xbc\x10\xe2\x89K\xe4\xe7&{j\xe0\x00\x00\u07d4\xb5\xa5\x89\u075f@q\u06f6\xfb\xa8\x9b?]]\xae}\x96\xc1c\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb5\xa6\x06\xf4\xdd\u02f9G\x1e\xc6\u007fe\x8c\xaf+\x00\xees\x02^\x89\xeaun\xa9*\xfct\x00\x00\u07d4\xb5\xadQW\u0769!\xe6\xba\xfa\u0350\x86\xaes\xae\x1fa\x1d?\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb5\xad\xd1\u701f}\x03\x06\x9b\xfe\x88;\n\x93\"\x10\xbe\x87\x12\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb5\xba)\x91|x\xa1\xd9\xe5\xc5\xc7\x13fl\x1eA\x1d\u007fi:\x89\xa8\r$g~\xfe\xf0\x00\x00\u07d4\xb5\xc8\x16\xa8(<\xa4\xdfh\xa1\xa7=c\xbd\x80&\x04\x88\xdf\b\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xb5\xca\xc5\xed\x03G}9\v\xb2g\xd4\xeb\xd4a\x01\xfb\xc2\xc3\u0689\n\xad\xec\x98?\xcf\xf4\x00\x00\u07d4\xb5\u037cA\x15@oR\u5a85\xd0\xfe\xa1p\u0497\x9c\u01fa\x89Hz\x9a0E9D\x00\x00\u0794\xb5\u0653M{)+\xcf`;(\x80t\x1e\xb7`(\x83\x83\xa0\x88\xe7\xc2Q\x85\x05\x06\x00\x00\u07d4\xb5\xddP\xa1]\xa3Ih\x89\nS\xb4\xf1?\xe1\xaf\b\x1b\xaa\xaa\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xb5\xfa\x81\x84\xe4>\xd3\u0e2b\x91!da\xb3R\x8d\x84\xfd\t\x89\x91Hx\xa8\xc0^\xe0\x00\x00\u07d4\xb5\xfb~\xa2\xdd\xc1Y\x8bfz\x9dW\xdd9\xe8Z8\xf3]V\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xb6\x00B\x97R\xf3\x99\xc8\r\a4tK\xae\n\x02.\xcag\u0189\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xb6\x00\xfe\xabJ\xa9lSu\x04\xd9`W\"1Ai,\x19:\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xb6\x04|\u07d3-\xb3\xe4\x04_Iv\x12#AS~\u0556\x1e\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xb6\x15\xe9@\x14>\xb5\u007f\x87X\x93\xbc\x98\xa6\x1b=a\x8c\x1e\x8c\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xb6\x1c4\xfc\xac\xdap\x1aZ\xa8p$Y\u07b0\u4b83\x8d\xf8\x8a\aiZ\x92\xc2\ro\xe0\x00\x00\xe0\x94\xb60d\xbd3U\xe6\xe0~-7p$\x12Z3wlJ\xfa\x8a\b7Z*\xbc\xca$@\x00\x00\u07d4\xb65\xa4\xbcq\xfb(\xfd\xd5\xd2\xc3\"\x98:V\u0084Bni\x89\t79SM(h\x00\x00\u07d4\xb6F\u07d8\xb4\x94BtkaR\\\x81\xa3\xb0K\xa3\x10bP\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xb6YA\xd4LP\xd2Ffg\r6Gf\xe9\x91\xc0.\x11\u0089 \x86\xac5\x10R`\x00\x00\xe0\x94\xb6[\u05c0\xc7CA\x15\x16 'VR#\xf4NT\x98\xff\x8c\x8a\x04<0\xfb\b\x84\xa9l\x00\x00\u07d4\xb6d\x11\xe3\xa0-\xed\xb7&\xfay\x10}\xc9\v\xc1\xca\xe6MH\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb6fu\x14.1\x11\xa1\xc2\xea\x1e\xb2A\x9c\xfaB\xaa\xf7\xa24\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xb6o\x92\x12K^c\x03XY\xe3\x90b\x88i\xdb\u07a9H^\x8a\x02\x15\xf85\xbcv\x9d\xa8\x00\x00\u07d4\xb6rsJ\xfc\xc2$\xe2\xe6\t\xfcQ\xd4\xf0Ys'D\xc9H\x89\x10\x04\xe2\xe4_\xb7\xee\x00\x00\xe0\x94\xb6w\x1b\v\xf3B\u007f\x9a\xe7\xa9>|.a\xeec\x94\x1f\xdb\b\x8a\x03\xfb&i)T\xbf\xc0\x00\x00\u07d4\xb6z\x80\xf1p\x19}\x96\xcd\xccJ\xb6\u02e6'\xb4\xaf\xa6\xe1,\x89\x82\x1a\xb0\xd4AI\x80\x00\x00\u07d4\xb6\x88\x99\xe7a\rL\x93\xa255\xbc\xc4H\x94[\xa1fo\x1c\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xb6\xa8)3\xc9\xea\u06bd\x98\x1e]m`\xa6\x81\x8f\xf8\x06\xe3k\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\xe0\x94\xb6\xaa\u02cc\xb3\v\xab*\xe4\xa2BF&\xe6\xe1+\x02\xd0F\x05\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xb6\xb3J&?\x10\xc3\xd2\xec\xeb\n\xccU\x9a{*\xb8\\\xe5e\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xb6\xbf\xe1\xc3\xef\x94\xe1\x84o\xb9\xe3\xac\xfe\x9bP\xc3\xe9\x06\x923\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\xb6\xcdt2\xd5\x16\x1b\xe7\x97h\xadE\xde>Dz\a\x98 c\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xb6\xceM\xc5`\xfcs\xdci\xfbzb\xe3\x88\xdb~r\xeavO\x894]\xf1i\xe9\xa3X\x00\x00\u07d4\xb6\xde\u03c2\x96\x98\x19\xba\x02\xde)\xb9\xb5\x93\xf2\x1bd\xee\xda\x0f\x89(\x1d\x90\x1fO\xdd\x10\x00\x00\xe0\x94\xb6\xe6\xc3\"+ko\x9b\xe2\x87]*\x89\xf1'\xfbd\x10\x0f\xe2\x8a\x01\xb2\x1dS#\xcc0 \x00\x00\u07d4\xb6\xe8\xaf\xd9=\xfa\x9a\xf2\u007f9\xb4\xdf\x06\ag\x10\xbe\xe3\u07eb\x89\x01Z\xf1\u05cbX\xc4\x00\x00\xe0\x94\xb6\xf7\x8d\xa4\xf4\xd0A\xb3\xbc\x14\xbc[\xa5\x19\xa5\xba\f2\xf1(\x8a$}\xd3,?\xe1\x95\x04\x80\x00\xe0\x94\xb6\xfb9xbP\b\x14&\xa3B\xc7\rG\xeeR\x1e[\xc5c\x8a\x03-&\xd1.\x98\v`\x00\x00\u07d4\xb7\r\xba\x93\x91h+J6Nw\xfe\x99%c\x01\xa6\xc0\xbf\x1f\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xb7\x16#\xf3Q\a\xcft1\xa8?\xb3\xd2\x04\xb2\x9e\u0c67\xf4\x89\x01\x11du\x9f\xfb2\x00\x00\u07d4\xb7\x1a\x13\xba\x8e\x95\x16{\x803\x1bR\u059e7\x05O\xe7\xa8&\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xb7\x1bb\xf4\xb4H\xc0+\x12\x01\xcb^9J\xe6'\xb0\xa5`\xee\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xb7\" \xad\xe3d\xd06\x9f--\xa7\x83\xcaGM{\x9b4\u0389\x1b\x1a\xb3\x19\xf5\xecu\x00\x00\xe0\x94\xb7#\r\x1d\x1f\xf2\xac\xa3f\x969\x14\xa7\x9d\xf9\xf7\xc5\xea,\x98\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\xe0\x94\xb7$\n\U000af433<\b\xae\x97d\x10>5\xdc\xe3c\x84(\x8a\x01\xca\xdd/\xe9hnc\x80\x00\u07d4\xb7'\xa9\xfc\x82\xe1\xcf\xfc\\\x17_\xa1HZ\x9b\xef\xa2\u037d\u04496'\xe8\xf7\x127<\x00\x00\u07d4\xb7,*\x01\x1c\r\xf5\x0f\xbbn(\xb2\n\xe1\xaa\xd2\x17\x88g\x90\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xb78-7\xdb\x03\x98\xacrA\f\xf9\x81=\xe9\xf8\xe1\uc36d\x8966\xc2^f\xec\xe7\x00\x00\u07d4\xb7;O\xf9\x9e\xb8\x8f\u061b\vmW\xa9\xbc3\x8e\x88o\xa0j\x89\x01\xbc\x16\xd6t\xec\x80\x00\x00\u07d4\xb7=jwU\x9c\x86\xcfet$)\x039K\xac\xf9n5p\x89\x04\xf1\xa7|\xcd;\xa0\x00\x00\u07d4\xb7Cr\xdb\xfa\x18\x1d\xc9$/9\xbf\x1d71\xdf\xfe+\xda\u03c9lk\x93[\x8b\xbd@\x00\x00\u07d4\xb7G\x9d\xabP\"\xc4\xd5\u06ea\xf8\xde\x17\x1bN\x95\x1d\u0464W\x89\x04V9\x18$O@\x00\x00\u07d4\xb7I\xb5N\x04\u0571\x9b\xdc\xed\xfb\x84\xdaw\x01\xabG\x8c'\xae\x89\x91Hx\xa8\xc0^\xe0\x00\x00\u07d4\xb7N\xd2f`\x01\xc1c3\xcfz\xf5\x9eJ=H`6;\x9c\x89\n~\xbd^Cc\xa0\x00\x00\u07d4\xb7QI\xe1\x85\xf6\xe3\x92pWs\x90s\xa1\x82*\xe1\xcf\r\xf2\x89\xd8\xd8X?\xa2\xd5/\x00\x00\u07d4\xb7S\xa7_\x9e\xd1\v!d:\n=\xc0Qz\xc9k\x1a@h\x89\x15\xc8\x18[,\x1f\xf4\x00\x00\xe0\x94\xb7V\xadR\xf3\xbft\xa7\xd2LgG\x1e\b\x87Ci6PL\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xb7Wn\x9d1M\xf4\x1e\xc5Pd\x94):\xfb\x1b\xd5\xd3\xf6]\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xb7X\x89o\x1b\xaa\x86O\x17\xeb\xed\x16\xd9S\x88o\xeeh\xaa\xe6\x8965\u026d\xc5\u07a0\x00\x00\u0794\xb7h\xb5#N\xba:\x99h\xb3Mm\xdbH\x1c\x84\x19\xb3e]\x88\xcf\xceU\xaa\x12\xb3\x00\x00\u07d4\xb7\x82\xbf\xd1\xe2\xdep\xf4gdo\x9b\xc0\x9e\xa5\xb1\xfc\xf4P\xaf\x89\x0e~\xeb\xa3A\vt\x00\x00\xe0\x94\xb7\xa2\xc1\x03r\x8bs\x05\xb5\xaen\x96\x1c\x94\xee\x99\xc9\xfe\x8e+\x8a\n\x96\x81c\xf0\xa5{@\x00\x00\u07d4\xb7\xa3\x1a|8\xf3\xdb\t2.\xae\x11\xd2'!A\xea\"\x99\x02\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb7\xa6y\x1c\x16\xebN!b\xf1Ke7\xa0+=c\xbf\xc6\x02\x89*Rc\x91\xac\x93v\x00\x00\u07d4\xb7\xa7\xf7|4\x8f\x92\xa9\xf1\x10\fk\xd8)\xa8\xacm\u007f\u03d1\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4\xb7\xc0w\x94ft\xba\x93A\xfbLtz]P\xf5\xd2\xdad\x15\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb7\xc0\xd0\xcc\vM4-@b\xba\xc6$\xcc\xc3\xc7\f\xc6\xda?\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xb7\xc9\xf1+\x03\x8esCm\x17\xe1\xc1/\xfe\x1a\xec\u0373\xf5\x8c\x89\x1dF\x01b\xf5\x16\xf0\x00\x00\u07d4\xb7\xcck\x1a\xcc2\u0632\x95\xdfh\xed\x9d^`\xb8\xf6L\xb6{\x89\x10CV\x1a\x88)0\x00\x00\u07d4\xb7\xcehK\t\xab\xdaS8\x9a\x87Si\xf7\x19X\xae\xac;\u0749lk\x93[\x8b\xbd@\x00\x00\u07d4\xb7\xd1.\x84\xa2\xe4\u01264Z\xf1\xdd\x1d\xa9\xf2PJ*\x99n\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xb7\xd2R\xee\x94\x02\xb0\xee\xf1D)_\x0ei\xf0\xdbXl\bq\x89#\xc7W\a+\x8d\xd0\x00\x00\xe0\x94\xb7\u0541\xfe\n\xf1\xec8?;\xce\x00\xaf\x91\x99\xf3\xcf_\xe0\xcc\xe2\x8c\xd1J\x89\xcf\x15&@\xc5\xc80\x00\x00\u07d4\xb8R\x18\xf3B\xf8\x01.\u069f'Nc\xce!R\xb2\xdc\xfd\xab\x89\xa8\r$g~\xfe\xf0\x00\x00\u07d4\xb8UP\x10wn<\\\xb3\x11\xa5\xad\xee\xfe\x9e\x92\xbb\x9ad\xb9\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\xb8_&\xdd\x0er\xd9\u009e\xba\xf6\x97\xa8\xafwG,+X\xb5\x8a\x02\x85\x19\xac\xc7\x19\fp\x00\x00\u07d4\xb8_\xf0>{_\xc4\"\x98\x1f\xae^\x99A\xda\xcb\u06bau\x84\x89Hz\x9a0E9D\x00\x00\xe0\x94\xb8f\a\x02\x1bb\xd3@\xcf&R\xf3\xf9_\xd2\xdcgi\x8b\u07ca\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\xb8}\xe1\xbc\u0492i\xd5!\xb8v\x1c\u00dc\xfbC\x19\xd2\xea\u054965\u026d\xc5\u07a0\x00\x00\u07d4\xb8\u007fSv\xc2\xde\vl\xc3\xc1y\xc0`\x87\xaaG=kFt\x89Hz\x9a0E9D\x00\x00\u07d4\xb8\x84\xad\u060d\x83\xdcVJ\xb8\xe0\xe0,\xbd\xb69\x19\xae\xa8D\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb8\x8a7\xc2\u007fx\xa6\x17\xd5\xc0\x91\xb7\u0577:7a\xe6_*\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb8\x94x\"\u056c\u79ad\x83&\xe9T\x96\"\x1e\v\xe6\xb7=\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xb8\x9c\x03n\xd7\u0112\x87\x99!\xbeA\xe1\f\xa1i\x81\x98\xa7L\x89b\xa9\x92\xe5:\n\xf0\x00\x00\xe0\x94\xb8\x9fF2\xdfY\t\xe5\x8b*\x99d\xf7O\xeb\x9a;\x01\xe0\u014a\x04\x88u\xbc\xc6\xe7\xcb\xeb\x80\x00\u07d4\xb8\xa7\x9c\x84\x94^G\xa9\xc3C\x86\x83\u05b5\x84,\xffv\x84\xb1\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb8\xa9y5'Y\xba\t\xe3Z\xa5\x93]\xf1u\xbf\xf6x\xa1\b\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xb8\xab9\x80[\xd8!\x18Ol\xbd=$s4{\x12\xbf\x17\\\x89\x06hZ\xc1\xbf\xe3,\x00\x00\xe0\x94\xb8\xac\x11}\x9f\r\xba\x80\x90\x14E\x82:\x92\x11\x03\xa51o\x85Zew\x9d\x1b\x8a\x05\x15\n\xe8J\x8c\xdf\x00\x00\x00\u07d4\xb9\xe9\f\x11\x92\xb3\xd5\xd3\xe3\xab\a\x00\xf1\xbfe_]\xd44z\x89\x1b\x19\xe5\vD\x97|\x00\x00\u07d4\xb9\xfd83\xe8\x8e|\xf1\xfa\x98y\xbd\xf5Z\xf4\xb9\x9c\xd5\xce?\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xba\x02I\xe0\x1d\x94[\xef\x93\xee^\xc6\x19%\xe0<\\\xa5\t\xfd\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xba\x0f9\x02;\xdb)\xeb\x18b\xa9\xf9\x05\x9c\xab]0nf/\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xba\x10\xf2vB\x90\xf8uCCr\xf7\x9d\xbfq8\x01\u02ac\x01\x893\xc5I\x901r\f\x00\x00\u07d4\xba\x151\xfb\x9ey\x18\x96\xbc\xf3\xa8\x05X\xa3Y\xf6\xe7\xc1D\xbd\x89\u0556{\xe4\xfc?\x10\x00\x00\u07d4\xba\x17m\xbe2I\xe3E\xcdO\xa9g\xc0\xed\x13\xb2LG\u5189\x15\xae\xf9\xf1\xc3\x1c\u007f\x00\x00\xe0\x94\xba\x1f\x0e\x03\u02da\xa0!\xf4\xdc\xeb\xfa\x94\xe5\u0209\xc9\u01fc\x9e\x8a\x06\u0450\xc4u\x16\x9a \x00\x00\u07d4\xba\x1f\xca\xf2#\x93~\xf8\x9e\x85gU\x03\xbd\xb7\xcaj\x92\x8bx\x89\"\xb1\xc8\xc1\"z\x00\x00\x00\xe0\x94\xba$\xfcCgS\xa79\xdb,\x8d@\xe6\xd4\xd0LR\x8e\x86\xfa\x8a\x02\xc0\xbb=\xd3\fN \x00\x00\u07d4\xbaB\xf9\xaa\xceL\x18E\x04\xab\xf5BWb\xac\xa2oq\xfb\u0709\x02\a\a}\u0627\x9c\x00\x00\u07d4\xbaF\x9a\xa5\u00c6\xb1\x92\x95\u0521\xb5G;T\x03S9\f\x85\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xbad@\xae\xb3s{\x8e\xf0\xf1\xaf\x9b\f\x15\xf4\xc2\x14\xff\xc7\u03c965\u026d\xc5\u07a0\x00\x00\xe0\x94\xbam1\xb9\xa2a\xd6@\xb5\u07a5\x1e\xf2\x16,1\t\xf1\uba0a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\xbap\xe8\xb4u\x9c\f<\x82\xcc\x00\xacN\x9a\x94\xdd[\xaf\xb2\xb8\x890C\xfa3\xc4\x12\xd7\x00\x00\u07d4\xba\x8ac\xf3\xf4\r\u4a03\x88\xbcP!/\xea\x8e\x06O\xbb\x86\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xba\x8eF\u059d.#C\xd8l`\xd8,\xf4, A\xa0\xc1\u0089\x05k\xc7^-c\x10\x00\x00\u07d4\xba\xa4\xb6L+\x15\xb7\x9f_ BF\xfdp\xbc\xbd\x86\xe4\xa9*\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xba\u0212,J\xcc},\xb6\xfdY\xa1N\xb4\\\xf3\xe7\x02!K\x89+^:\xf1k\x18\x80\x00\x00\u07d4\xba\xd25\xd5\b]\u01f0h\xa6|A&w\xb0>\x186\x88L\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xba\xd4B^\x17\x1c>r\x97^\xb4j\xc0\xa0\x15\xdb1Z]\x8f\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xba\xdc*\xef\x9fYQ\xa8\u05cak5\xc3\u0433\xa4\xe6\xe2\xe79\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xba\xdeCY\x9e\x02\xf8OL0\x14W\x1c\x97k\x13\xa3le\xab\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xba\xe9\xb8/r\x99c\x14\be\x9d\xd7N\x89\x1c\xb8\xf3\x86\x0f\xe5\x89j\xcb=\xf2~\x1f\x88\x00\x00\xe0\x94\xbb\x03f\xa7\u03fd4E\xa7\r\xb7\xfeZ\xe3H\x85uO\xd4h\x8a\x01M\xef,B\xeb\xd6@\x00\x00\u07d4\xbb\aj\xac\x92 \x80i\xea1\x8a1\xff\x8e\xeb\x14\xb7\xe9\x96\xe3\x89\b\x13\xcaV\x90m4\x00\x00\u07d4\xbb\bW\xf1\xc9\x11\xb2K\x86\u0227\x06\x81G?\u6aa1\xcc\xe2\x89\x05k\xc7^-c\x10\x00\x00\u0794\xbb\x19\xbf\x91\u02edt\xcc\xeb_\x81\x1d\xb2~A\x1b\xc2\xea\x06V\x88\xf4?\xc2\xc0N\xe0\x00\x00\xe0\x94\xbb'\u01a7\xf9\x10uGZ\xb2)a\x90@\xf8\x04\xc8\xeczj\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xbb7\x1cr\xc9\xf01l\xea+\xd9\xc6\xfb\xb4\a\x9ewT)\xef\x89_h\xe8\x13\x1e\u03c0\x00\x00\xe0\x94\xbb;\x01\v\x18\xe6\xe2\xbe\x115\x87\x10&\xb7\xba\x15\xea\x0f\xde$\x8a\x02 |\x800\x9bwp\x00\x00\xe0\x94\xbb;\x90\x05\xf4o\xd2\xca;0\x16%\x99\x92\x8cw\xd9\xf6\xb6\x01\x8a\x01\xb1\xae\u007f+\x1b\xf7\xdb\x00\x00\u07d4\xbb?\xc0\xa2\x9c\x03Mq\b\x12\xdc\xc7u\xc8\u02b9\u048diu\x899\xd4\xe8D\xd1\xcf_\x00\x00\u07d4\xbbH\xea\xf5\x16\xce-\xec>A\xfe\xb4\xc6y\xe4\x95vA\x16O\x89\xcf\x15&@\xc5\xc80\x00\x00\u07d4\xbbKJKT\x80p\xffAC,\x9e\b\xa0\xcao\xa7\xbc\x9fv\x89.\x14\x1e\xa0\x81\xca\b\x00\x00\u07d4\xbbV\xa4\x04r<\xff \xd0hT\x88\xb0Z\x02\xcd\xc3Z\xac\xaa\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xbba\x8e%\"\x1a\u0667@\xb2\x99\xed\x14\x06\xbc94\xb0\xb1m\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xbba\xa0K\xff\xd5|\x10G\rE\u00d1\x03\xf6FP4v\x16\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xbbh#\xa1\xbd\x81\x9f\x13QU8&J-\xe0R\xb4D\"\b\x89\x01ch\xffO\xf9\xc1\x00\x00\u07d4\xbbl(J\xac\x8ai\xb7\\\u0770\x0f(\xe1EX;V\xbe\u0389lk\x93[\x8b\xbd@\x00\x00\u07d4\xbbu\xcbPQ\xa0\xb0\x94KFs\xcau*\x97\x03\u007f|\x8c\x15\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xbb\x99;\x96\xee\x92Z\xda}\x99\u05c6W=?\x89\x18\f\u3a89lk\x93[\x8b\xbd@\x00\x00\u07d4\xbb\xa3\u0180\x04$\x8eH\x95s\xab\xb2t6w\x06k$\u0227\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xbb\xa4\xfa\xc3\xc4 9\xd8(\xe7B\xcd\xe0\xef\xff\xe7t\x94\x1b9\x89lj\u04c2\xd4\xfba\x00\x00\u07d4\xbb\xa8\xab\"\xd2\xfe\xdb\xcf\xc6?hL\b\xaf\xdf\x1c\x17P\x90\xb5\x89\x05_)\xf3~N;\x80\x00\u07d4\xbb\xa9v\xf1\xa1!_u\x12\x87\x18\x92\xd4_pH\xac\xd3V\u0209lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xbb\xab\x00\v\x04\b\xed\x01Z7\xc0GG\xbcF\x1a\xb1N\x15\x1b\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xbb\xab\xf6d;\xebK\xd0\x1c\x12\v\xd0Y\x8a\t\x87\xd8)g\u0449\xb52\x81x\xad\x0f*\x00\x00\u07d4\xbb\xb4\xee\x1d\x82\xf2\xe1VD,\xc938\xa2\xfc(o\xa2\x88d\x89JD\x91\xbdm\xcd(\x00\x00\u07d4\xbb\xb5\xa0\xf4\x80,\x86H\x00\x9e\x8ai\x98\xaf5,\u0787TO\x89\x05-T(\x04\xf1\xce\x00\x00\u07d4\xbb\xb6C\xd2\x18{6J\xfc\x10\xa6\xfd6\x8d}U\xf5\r\x1a<\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xbb\xb8\xff\xe4?\x98\u078e\xae\x18F#\xaeRd\xe4$\u0438\u05c9\x05\xd5?\xfd\xe9(\b\x00\x00\u07d4\xbb\xbdn\u02f5u(\x91\xb4\u03b3\xcc\xe7:\x8fGpY7o\x89\x01\xf3\x99\xb1C\x8a\x10\x00\x00\u07d4\xbb\xbf9\xb1\xb6y\x95\xa4\"APO\x97\x03\u04a1JQV\x96\x89U\xa6\xe7\x9c\xcd\x1d0\x00\x00\u07d4\xbb\xc8\xea\xffc~\x94\xfc\u014d\x91\xdb\\\x89\x12\x1d\x06\xe1/\xff\x98\x80\x00\u07d4\xbc\u065e\xdc!`\xf2\x10\xa0^:\x1f\xa0\xb0CL\xed\x00C\x9b\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xbc\u07ec\xb9\xd9\x02<4\x17\x18.\x91\x00\xe8\xea\x1d73\x93\xa3\x89\x034-`\xdf\xf1\x96\x00\x00\u07d4\xbc\xe1>\"2*\u03f3U\xcd!\xfd\r\xf6\f\xf9:\xdd&\u0189\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xbc\xe4\x04u\xd3E\xb0q-\xeep=\x87\xcdvW\xfc\u007f;b\x8a\x01\xa4 \xdb\x02\xbd}X\x00\x00\u07d4\xbc\xed\xc4&|\u02c9\xb3\x1b\xb7d\xd7!\x11q\x00\x8d\x94\xd4M\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xbc\xfc\x98\xe5\xc8+j\xdb\x18\n?\xcb\x12\v\x9av\x90\xc8j?\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xbd\x04;g\xc6>`\xf8A\xcc\xca\x15\xb1)\xcd\xfee\x90\xc8\xe3\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xbd\x04\u007f\xf1\xe6\x9c\u01b2\x9a\xd2d\x97\xa9\xa6\xf2z\x90?\xc4\u0749.\xe4IU\b\x98\xe4\x00\x00\u07d4\xbd\b\xe0\xcd\xde\xc0\x97\xdby\x01\ua05a=\x1f\xd9\u0789Q\xa2\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xbd\t\x12l\x89\x1cJ\x83\x06\x80Y\xfe\x0e\x15ylFa\xa9\xf4\x89+^:\xf1k\x18\x80\x00\x00\u07d4\xbd\f\\\u05d9\xeb\u0106B\xef\x97\xd7N\x8eB\x90d\xfe\u4489\x11\xac(\xa8\xc7)X\x00\x00\u07d4\xbd\x17\xee\xd8+\x9a%\x92\x01\x9a\x1b\x1b<\x0f\xba\xd4\\@\x8d\"\x89\r\x8drkqw\xa8\x00\x00\u07d4\xbd\x18\x037\v\u0771)\xd29\xfd\x16\xea\x85&\xa6\x18\x8a\u5389\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xbd+p\xfe\xcc7d\x0fiQO\xc7\xf3@IF\xaa\xd8k\x11\x89A\rXj \xa4\xc0\x00\x00\u07d4\xbd0\x97\xa7\x9b<\r.\xbf\xf0\xe6\xe8j\xb0\xed\xad\xbe\xd4p\x96\x89Z\x87\xe7\xd7\xf5\xf6X\x00\x00\u07d4\xbd2]@)\xe0\xd8r\x9fm9\x9cG\x82$\xae\x9ez\xe4\x1e\x89\xd2U\xd1\x12\xe1\x03\xa0\x00\x00\u07d4\xbdC*9\x16$\x9bG$):\xf9\x14nI\xb8(\n\u007f*\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xbdG\xf5\xf7n;\x93\x0f\xd9HR\t\xef\xa0\xd4v=\xa0uh\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xbdK`\xfa\xect\n!\xe3\a\x13\x91\xf9j\xa54\xf7\xc1\xf4N\x89\t\xdd\xc1\xe3\xb9\x01\x18\x00\x00\u07d4\xbdK\u0571\"\xd8\xef{|\x8f\x06gE\x03 \xdb!\x16\x14.\x89 \x86\xac5\x10R`\x00\x00\u07d4\xbdQ\xee.\xa1C\u05f1\u05b7~~D\xbd\xd7\xda\x12\U00105b09G~\x06\u0332\xb9(\x00\x00\u07d4\xbdY\tN\aO\x8dy\x14*\xb1H\x9f\x14\x8e2\x15\x1f \x89\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xbdZ\x8c\x94\xbd\x8b\xe6G\x06D\xf7\f\x8f\x8a3\xa8\xa5\\cA\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xbd^G:\xbc\xe8\xf9zi2\xf7|/\xac\xaf\x9c\xc0\xa0\x05\x14\x89<\x92X\xa1\x06\xa6\xb7\x00\x00\u07d4\xbd_F\u02ab,=K(\x93\x96\xbb\xb0\u007f *\x06\x11>\xd4\xc3\xfb\xa1\xa8\x91;\x19@~\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xbd\x9eV\xe9\x02\xf4\xbe\x1f\xc8v\x8d\x808\xba\xc6>*\u02ff\x8e\x8965f3\xeb\xd8\xea\x00\x00\u07d4\xbd\xa4\xbe1~~K\xed\x84\xc0I^\xee2\xd6\a\xec8\xcaR\x89}2'yx\xefN\x80\x00\u07d4\xbd\xb6\v\x82:\x11s\xd4Z\a\x92$_\xb4\x96\xf1\xfd3\x01\u03c9lk\x93[\x8b\xbd@\x00\x00\u07d4\xbd\xba\xf6CM@\xd65[\x1e\x80\xe4\f\u012b\x9ch\xd9a\x16\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xbd\xc0,\xd43\f\x93\xd6\xfb\xdaOm\xb2\xa8]\xf2/C\xc23\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xbd\xc4aF+c\"\xb4b\xbd\xb3?\"y\x9e\x81\b\xe2A}\x89$=M\x18\"\x9c\xa2\x00\x00\u07d4\xbd\xc79\xa6\x99p\v.\x8e,JL{\x05\x8a\x0eQ=\u07be\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xbd\xc7Hs\xaf\x92+\x9d\xf4t\x85;\x0f\xa7\xff\v\xf8\xc8&\x95\x89\xd8\xc9F\x00c\xd3\x1c\x00\x00\u07d4\xbd\xca*\x0f\xf3E\x88\xafb_\xa8\xe2\x8f\xc3\x01Z\xb5\xa3\xaa\x00\x89~\xd7?w5R\xfc\x00\x00\u07d4\xbd\xd3%N\x1b:m\xc6\xcc,i}Eq\x1a\xca!\xd5\x16\xb2\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xbd\u07e3M\x0e\xbf\x1b\x04\xafS\xb9\x9b\x82IJ\x9e=\x8a\xa1\x00\x8a\x02\x8a\x85t%Fo\x80\x00\x00\u07d4\xbd\xe4\xc7?\x96\x9b\x89\xe9\u03aef\xa2\xb5\x18DH\x0e\x03\x8e\x9a\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xbd\xe9xj\x84\xe7[H\xf1\x8erm\u05cdp\xe4\xaf>\xd8\x02\x8a\x016\x9f\xb9a(\xacH\x00\x00\u07d4\xbd\xed\x11a/\xb5\xc6\u0699\xd1\xe3\x0e2\v\xc0\x99Tf\x14\x1e\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xbd\xed~\a\xd0q\x1ehM\xe6Z\u0232\xabW\xc5\\\x1a\x86E\x89 \t\xc5\u023fo\xdc\x00\x00\u07d4\xbd\xf6\x93\xf83\xc3\xfeG\x17S\x18G\x88\xebK\xfeJ\xdc?\x96\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xbd\xf6\xe6\x8c\f\xd7X@\x80\xe8G\xd7,\xbb#\xaa\xd4j\xeb\x1d\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xbe\n/8_\t\xdb\xfc\xe9g2\xe1+\xb4\n\xc3I\x87\x1b\xa8\x89WL\x11^\x02\xb8\xbe\x00\x00\u07d4\xbe\f*\x80\xb9\xde\bK\x17(\x94\xa7l\xf4szOR\x9e\x1a\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\xbe\x1c\xd7\xf4\xc4r\a\th\xf3\xbd\xe2h6k!\xee\xea\x83!\x89\xe9\x1a|\u045f\xa3\xb0\x00\x00\u07d4\xbe#F\xa2\u007f\xf9\xb7\x02\x04OP\r\xef\xf2\xe7\xff\xe6\x82EA\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xbe$q\xa6\u007f`G\x91\x87r\xd0\xe3h9%^\xd9\u0591\xae\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xbe+\"\x80R7h\xea\x8a\xc3\\\xd9\xe8\x88\xd6\nq\x93\x00\u0509lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xbe+2nx\xed\x10\xe5P\xfe\xe8\xef\xa8\xf8\a\x03\x96R/Z\x8a\bW\xe0\xd6\xf1\xdav\xa0\x00\x00\xe0\x94\xbe0Zyn3\xbb\xf7\xf9\xae\xaee\x12\x95\x90f\xef\xda\x10\x10\x8a\x02M\xceT\xd3J\x1a\x00\x00\x00\u07d4\xbeG\x8e\x8e=\xdek\xd4\x03\xbb-\x1ce|C\x10\xee\x19'#\x89\x1a\xb2\xcf|\x9f\x87\xe2\x00\x00\u07d4\xbeN}\x98?.*ck\x11\x02\xecp9\xef\xeb\xc8B\u9349\x03\x93\xef\x1aQ'\xc8\x00\x00\u07d4\xbeO\xd0sap\"\xb6\u007f\\\x13I\x9b\x82\u007fv69\xe4\xe3\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xbeRZ3\xea\x91aw\xf1r\x83\xfc\xa2\x9e\x8b5\v\u007fS\v\x89\x8f\x01\x9a\xafF\xe8x\x00\x00\u07d4\xbeS2/C\xfb\xb5\x84\x94\xd7\xcc\xe1\x9d\xda'+$P\xe8'\x89\n\xd7\u03afB\\\x15\x00\x00\u07d4\xbeS\x82F\xddNo\f \xbfZ\xd17<;F:\x13\x1e\x86\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xbeZ`h\x99\x98c\x9a\xd7[\xc1\x05\xa3qt>\xef\x0fy@\x89\x1b2|s\xe1%z\x00\x00\u07d4\xbe\\\xba\x8d7By\x86\xe8\xca&\x00\xe8X\xbb\x03\xc3YR\x0f\x89\xa00\xdc\xeb\xbd/L\x00\x00\u07d4\xbe`\x03~\x90qJK\x91~a\xf1\x93\xd84\x90g\x03\xb1:\x89\\(=A\x03\x94\x10\x00\x00\u07d4\xbec:77\xf6\x849\xba\xc7\xc9\nR\x14 X\ue38ao\x894\n\xad!\xb3\xb7\x00\x00\x00\xe0\x94\xbee\x9d\x85\xe7\xc3O\x883\xea\u007fH\x8d\xe1\xfb\xb5\xd4\x14\x9b\xef\x8a\x01\xeb\xd2:\xd9\u057br\x00\x00\u07d4\xbes'M\x8cZ\xa4J<\xbe\xfc\x82c\xc3{\xa1!\xb2\n\u04c9\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xbe\x86\u0430C\x84\x19\u03b1\xa081\x927\xbaR\x06\xd7.F\x8964\xfb\x9f\x14\x89\xa7\x00\x00\u07d4\xbe\x8d\u007f\x18\xad\xfe]l\xc7u9I\x89\xe1\x93\f\x97\x9d\x00}\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xbe\x91\x86\xc3JRQJ\xbb\x91\a\x86\x0fgO\x97\xb8!\xbd[\x89\x1b\xa0\x1e\xe4\x06\x03\x10\x00\x00\u07d4\xbe\x93W\x93\xf4[p\xd8\x04]&T\xd8\xdd:\xd2K[a7\x89/\xb4t\t\x8fg\xc0\x00\x00\u07d4\xbe\x98\xa7\u007f\xd4\x10\x97\xb3OY\xd7X\x9b\xaa\xd0!e\x9f\xf7\x12\x890\xca\x02O\x98{\x90\x00\x00\u07d4\xbe\x9b\x8c4\xb7\x8e\xe9G\xff\x81G.\xdaz\xf9\xd2\x04\xbc\x84f\x89\b!\xab\rD\x14\x98\x00\x00\u07d4\xbe\xa0\r\xf1pg\xa4:\x82\xbc\x1d\xae\xca\xfbl\x140\x0e\x89\xe6\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4\xbe\xa0\xaf\xc9:\xae!\b\xa3\xfa\xc0Yb;\xf8o\xa5\x82\xa7^\x89\\(=A\x03\x94\x10\x00\x00\u07d4\xbe\xb35\x8cP\u03dfu\xff\xc7mD<,\u007fU\aZ\x05\x89\x89\x90\xf54`\x8ar\x88\x00\x00\u07d4\xbe\xb4\xfd1UYC`E\u0739\x9dI\xdc\xec\x03\xf4\fB\u0709lk\x93[\x8b\xbd@\x00\x00\u07d4\xbe\xc2\xe6\xde9\xc0|+\xaeUj\u03fe\xe2\xc4r\x8b\x99\x82\xe3\x89\x1f\x0f\xf8\xf0\x1d\xaa\xd4\x00\x00\u07d4\xbe\xc6d\x0fI\t\xb5\x8c\xbf\x1e\x80cB\x96\x1d`u\x95\tl\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\xbe\xc8\xca\xf7\xeeIF\x8f\xeeU.\xff:\xc5#N\xb9\xb1}B\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xbe\xce\xf6\x1c\x1cD+\xef|\xe0Ks\xad\xb2I\xa8\xba\x04~\x00\x896;V\u00e7T\xc8\x00\x00\u0794\xbe\xd4d\x9d\xf6F\u2052)\x03-\x88hUo\xe1\xe0S\u04c8\xfc\x93c\x92\x80\x1c\x00\x00\xe0\x94\xbe\xd4\xc8\xf0\x06\xa2|\x1e_|\xe2\x05\xdeu\xf5\x16\xbf\xb9\xf7d\x8a\x03c\\\x9a\xdc]\xea\x00\x00\x00\u07d4\xbe\xe8\u0430\bB\x19T\xf9-\x00\r9\x0f\xb8\xf8\xe6X\xea\xee\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xbe\xec\u05af\x90\f\x8b\x06J\xfc\xc6\a?-\x85\u055a\xf1\x19V\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xbe\xef\x94!8y\xe0&\"\x14+\xeaa)\tx\x93\x9a`\u05ca\x016\x85{2\xad\x86\x04\x80\x00\xe0\x94\xbe\xf0}\x97\xc3H\x1f\x9dj\xee\x1c\x98\xf9\xd9\x1a\x18\n2D+\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\xbe\xfbD\x8c\f_h?\xb6~\xe5p\xba\xf0\xdbV\x86Y\x97Q\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xbf\x05\a\f,4!\x93\x11\xc4T\x8b&\x14\xa48\x81\r\xedm\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xbf\x05\xff^\xcf\r\xf2\u07c8wY\xfb\x82t\xd928\xac&}\x89+^:\xf1k\x18\x80\x00\x00\xe0\x94\xbf\t\xd7pH\xe2p\xb6b3\x0e\x94\x86\xb3\x8bC\xcdx\x14\x95\x8a\\S\x9b{\xf4\xff(\x80\x00\x00\u07d4\xbf\x17\xf3\x97\xf8\xf4o\x1b\xaeE\u0447\x14\x8c\x06\xee\xb9Y\xfaM\x896I\u0156$\xbb0\x00\x00\u07d4\xbf\x186A\xed\xb8\x86\xce`\xb8\x19\x02a\xe1OB\xd9<\xce\x01\x89\x01[5W\xf1\x93\u007f\x80\x00\u07d4\xbf*\xeaZ\x1d\xcfn\u04f5\xe829D\xe9\x83\xfe\xdf\u046c\xfb\x89U\xa6\xe7\x9c\xcd\x1d0\x00\x00\u07d4\xbf@\x96\xbcT}\xbf\xc4\xe7H\t\xa3\x1c\x03\x9e{8\x9d^\x17\x89\u0556{\xe4\xfc?\x10\x00\x00\u07d4\xbfI\xc1H\x981eg\u0637\t\xc2\xe5\x05\x94\xb3f\xc6\u04cc\x89'\xbf8\xc6TM\xf5\x00\x00\u07d4\xbfLs\xa7\xed\xe7\xb1d\xfe\a!\x14\x846T\xe4\xd8x\x1d\u0789lk\x93[\x8b\xbd@\x00\x00\u07d4\xbfP\xce.&K\x9f\xe2\xb0h0az\xed\xf5\x02\xb25\x1bE\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xbfY\xae\xe2\x81\xfaC\xfe\x97\x19CQ\xa9\x85~\x01\xa3\xb8\x97\xb2\x89 \x86\xac5\x10R`\x00\x00\u07d4\xbfh\u048a\xaf\x1e\xee\xfe\xf6F\xb6^\x8c\xc8\u0450\xf6\xc6\u069c\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xbfi%\xc0\aQ\x00\x84@\xa6s\x9a\x02\xbf+l\u06ab^:\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xbfw\x01\xfcb%\u0561x\x15C\x8a\x89A\xd2\x1e\xbc]\x05\x9d\x89e\xea=\xb7UF`\x00\x00\u07d4\xbf\x8b\x80\x05\xd66\xa4\x96d\xf7Bu\xefBC\x8a\xcde\xac\x91\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xbf\x92A\x8a\fl1$M\"\x02`\xcb>\x86}\u05f4\xefI\x89\x05i\x00\xd3<\xa7\xfc\x00\x00\u07d4\xbf\x9a\xcdDE\xd9\xc9UF\x89\u02bb\xba\xb1\x88\x00\xff\x17A\u008965\u026d\xc5\u07a0\x00\x00\u07d4\xbf\x9f'\x1fz~\x12\xe3m\xd2\xfe\x9f\xac\xeb\xf3\x85\xfeaB\xbd\x89\x03f\xf8O{\xb7\x84\x00\x00\u07d4\xbf\xa8\xc8X\xdf\x10,\xb1$!\x00\x8b\n1\xc4\xc7\x19\n\xd5`\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xbf\xae\xb9\x10ga}\u03cbD\x17+\x02\xafaVt\x83]\xba\x89\b\xb5\x9e\x88H\x13\b\x80\x00\xe0\x94\xbf\xb0\xea\x02\xfe\xb6\x1d\xec\x9e\"\xa5\a\tY3\x02\x99\xc40r\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94\xbf\xbc\xa4\x18\xd3R\x9c\xb3\x93\b\x10b\x03*n\x11\x83\u01b2\u070a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xbf\xbe\x05\u831c\xbb\xcc\x0e\x92\xa4\x05\xfa\xc1\xd8]\xe2H\xee$\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94\xbf\xbf\xbc\xb6V\u0099+\xe8\xfc\u0782\x19\xfb\xc5J\xad\u055f)\x8a\x02\x1e\x18\xd2\xc8!\xc7R\x00\x00\u07d4\xbf\xc5z\xa6f\xfa\u239f\x10zI\xcbP\x89\xa4\xe2!Q\u074965\u026d\xc5\u07a0\x00\x00\u07d4\xbf\u02d70$c\x04p\r\xa9\vAS\xe7\x11Ab.\x1cA\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xbf\xd9<\x90\u009c\a\xbc_\xb5\xfcI\xae\xeaU\xa4\x0e\x13O5\x8a\x05\xed\xe2\x0f\x01\xa4Y\x80\x00\x00\xe0\x94\xbf\xe3\xa1\xfcn$\xc8\xf7\xb3%\x05`\x99\x1f\x93\u02e2\u03c0G\x8a\x10\xf0\xcf\x06M\u0552\x00\x00\x00\u07d4\xbf\u6f30\xf0\xc0xRd3$\xaa]\xf5\xfdb%\xab\xc3\u0289\x04\t\xe5+H6\x9a\x00\x00\u07d4\xbf\xf5\xdfv\x994\xb8\x94<\xa9\x13}\x0e\xfe\xf2\xfen\xbb\xb3N\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xbf\xfbi)$\x1fx\x86\x93'>p\"\xe6\x0e>\xab\x1f\xe8O\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc0\x06O\x1d\x94t\xab\x91]V\x90l\x9f\xb3 \xa2\xc7\t\x8c\x9b\x89\x13h?\u007f<\x15\xd8\x00\x00\u07d4\xc0\a\xf0\xbd\xb6\xe7\x00\x92\x02\xb7\xaf>\xa9\t\x02i|r\x14\x13\x89\xa2\xa0\xe4>\u007f\xb9\x83\x00\x00\u07d4\xc0\n\xb0\x80\xb6C\xe1\u00ba\xe3c\xe0\u0455\xde.\xff\xfc\x1cD\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u0794\xc0 wD\x9a\x13Jz\xd1\xef~M\x92z\xff\xec\ueb75\xae\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\xc0$q\xe3\xfc.\xa0S&\x15\xa7W\x1dI2\x89\xc1<6\xef\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xc0-n\xad\xea\xcf\x1bx\xb3\u0285\x03\\c{\xb1\xce\x01\xf4\x90\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xc03\xb12Z\n\xf4Tr\xc2U'\x85;\x1f\x1c!\xfa5\u0789lk\x93[\x8b\xbd@\x00\x00\u07d4\xc03\xbe\x10\xcbHa;\xd5\xeb\xcb3\xedI\x02\xf3\x8bX0\x03\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xc04[3\xf4\x9c\xe2\u007f\xe8,\xf7\xc8M\x14\x1ch\xf5\x90\xcev\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xc0=\xe4*\x10\x9bezd\xe9\"$\xc0\x8d\xc1'^\x80\u0672\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xc0@i\u07f1\x8b\tlxg\xf8\xbe\xe7zm\xc7Gz\xd0b\x89\x90\xf54`\x8ar\x88\x00\x00\xe0\x94\xc0A?Z|-\x9aK\x81\b(\x9e\xf6\xec\xd2qx\x15$\xf4\x8a\n\x96\x81c\xf0\xa5{@\x00\x00\u07d4\xc0C\xf2E-\u02d6\x02\xefb\xbd6\x0e\x03=\xd29q\xfe\x84\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xc0OK\xd4\x04\x9f\x04F\x85\xb8\x83\xb6)Y\xaec\x1df~5\x8a\x01;\x80\xb9\x9cQ\x85p\x00\x00\u07d4\xc0V\u053dk\xf3\u02ec\xace\xf8\xf5\xa0\xe3\x98\v\x85'@\xae\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xc0[t\x06 \xf1s\xf1nRG\x1d\u00cb\x9cQJ\v\x15&\x89\a\x96\xe3\xea?\x8a\xb0\x00\x00\u07d4\xc0i\xef\x0e\xb3B\x99\xab\xd2\xe3-\xab\xc4yD\xb2r3H$\x89\x06\x81U\xa46v\xe0\x00\x00\u07d4\xc0l\xeb\xbb\xf7\xf5\x14\x9af\xf7\xeb\x97k>G\xd5e\x16\xda/\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xc0r^\u00bd\xc3:\x1d\x82`q\u07a2\x9db\xd48Z\x8c%\x8a\b\xa0\x85\x13F:\xa6\x10\x00\x00\u07d4\xc0~8g\xad\xa0\x96\x80z\x05\x1al\x9c4\xcc;?J\xd3J\x89`\xf0f \xa8IE\x00\x00\u07d4\xc0\x89^\xfd\x05m\x9a:\x81\xc3\xdaW\x8a\xda1\x1b\xfb\x93V\u03c9\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xc0\x90\xfe#\xdc\xd8k5\x8c2\xe4\x8d*\xf9\x10$%\x9fef\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xc0\x9af\x17*\xea7\r\x9ac\xda\x04\xffq\xff\xbb\xfc\xff\u007f\x94\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc0\x9e<\xfc\x19\xf6\x05\xff>\xc9\xc9\xc7\x0e%@\xd7\xee\x97Cf\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xc0\xa0*\xb9N\xbeV\xd0E\xb4\x1bb\x9b\x98F.:\x02J\x93\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xc0\xa3\x93\b\xa8\x0e\x9e\x84\xaa\xaf\x16\xac\x01\xe3\xb0\x1dt\xbdk-\x89\afM\xddL\x1c\v\x80\x00\u07d4\xc0\xa6\u02edwi*=\x88\xd1A\xefv\x9a\x99\xbb\x9e<\x99Q\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94\xc0\xa7\xe8C]\xff\x14\xc2Uws\x9d\xb5\\$\u057fW\xa3\u064a\nm\xd9\f\xaeQ\x14H\x00\x00\u07d4\xc0\xae\x14\xd7$\x83./\xce'x\xde\u007f{\x8d\xaf{\x12\xa9>\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xc0\xaf\xb7\u0637\x93p\xcf\xd6c\u018c\u01b9p*7\u035e\xff\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xc0\xb0\xb7\xa8\xa6\xe1\xac\xdd\x05\xe4\u007f\x94\xc0\x96\x88\xaa\x16\u01ed\x8d\x89\x03{m\x02\xacvq\x00\x00\xe0\x94\xc0\xb3\xf2D\xbc\xa7\xb7\xde[H\xa5>\u06dc\xbe\xab\vm\x88\xc0\x8a\x01;\x80\xb9\x9cQ\x85p\x00\x00\u07d4\xc0\xc0M\x01\x06\x81\x0e>\xc0\xe5J\x19\U000ab157\xe6\x9aW=\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\u07d4\xc0\xca2w\x94.tE\x87K\xe3\x1c\xeb\x90)rqO\x18#\x89\r\x8drkqw\xa8\x00\x00\u07d4\xc0\u02ed<\xcd\xf6T\xda\"\xcb\xcf\\xe\x97\xca\x19U\xc1\x15\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc0\xcb\xf6\x03/\xa3\x9e|F\xffw\x8a\x94\xf7\xd4E\xfe\"\xcf0\x89\x10\xce\x1d=\x8c\xb3\x18\x00\x00\u07d4\xc0\xe0\xb9\x03\b\x8e\fc\xf5=\xd0iWTR\xaf\xf5$\x10\u00c9\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xc0\xe4W\xbdV\xec6\xa1$k\xfa20\xff\xf3\x8eY&\xef\"\x89i*\xe8\x89p\x81\xd0\x00\x00\u07d4\xc0\xed\rJ\xd1\r\xe045\xb1S\xa0\xfc%\xde;\x93\xf4R\x04\x89\xabM\xcf9\x9a:`\x00\x00\u07d4\xc0\xf2\x9e\xd0\af\x11\xb5\xe5^\x13\x05G\xe6\x8aH\xe2m\xf5\u4262\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xc1\x13(x#\\]\u06e5\xd9\xf3\"\x8bR6\xe4p \xdco\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xc1\x17\r\xba\xad\xb3\xde\xe6\x19\x8e\xa5D\xba\xec\x93%\x18`\xfd\xa5\x89A\rXj \xa4\xc0\x00\x00\xe0\x94\xc1&W=\x87\xb0\x17ZR\x95\xf1\xdd\a\xc5u\u03cc\xfa\x15\xf2\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xc1'\xaa\xb5\x90e\xa2\x86D\xa5k\xa3\xf1^.\xac\x13\xda)\x95\x89 \x86\xac5\x10R`\x00\x00\xe0\x94\xc1+\u007f@\u07da/{\xf9\x83f\x14\"\xab\x84\xc9\xc1\xf5\bX\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xc1,\xfb{=\xf7\x0f\xce\xca\x0e\xde&5\x00\xe2xs\xf8\xed\x16\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xc1/\x88\x1f\xa1\x12\xb8\x19\x9e\xcb\xc7>\xc4\x18W\x90\xe6\x14\xa2\x0f\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc18Lnq~\xbeK#\x01NQ\xf3\x1c\x9d\xf7\xe4\xe2[1\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xc1C\x8c\x99\xddQ\xef\x1c\xa88j\xf0\xa3\x17\xe9\xb0AEx\x88\x89\f\x1d\xaf\x81\u0623\xce\x00\x00\u07d4\xc1c\x12(\xef\xbf*.:@\x92\xee\x89\x00\xc69\xed4\xfb\u02093\xc5I\x901r\f\x00\x00\u07d4\xc1u\xbe1\x94\xe6iB-\x15\xfe\xe8\x1e\xb9\xf2\xc5lg\xd9\u0249\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xc1\x82v\x86\xc0\x16\x94\x85\xec\x15\xb3\xa7\xc8\xc0\x15\x17\xa2\x87M\xe1\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\xc1\x8a\xb4g\xfe\xb5\xa0\xaa\xdf\xff\x91#\x0f\xf0VFMx\xd8\x00\x89lk\x93[\x8b\xbd@\x00\x00\u0794\xc1\x95\x05CUM\x8aq0\x03\xf6b\xbba,\x10\xadL\xdf!\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\xc1\xa4\x1aZ'\x19\x92&\xe4\xc7\xeb\x19\x8b\x03\x1bY\x19o\x98B\x89\nZ\xa8P\t\xe3\x9c\x00\x00\u07d4\xc1\xb2\xa0\xfb\x9c\xadE\xcdi\x91\x92\xcd'T\v\x88\xd38By\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xc1\xb2\xaa\x8c\xb2\xbfb\xcd\xc1:G\xec\xc4e\u007f\xac\xaa\x99_\x98\x8967\x93\xfa\x96\u6980\x00\u07d4\xc1\xb5\x00\x01\x1c\xfb\xa9]|\xd66\xe9^l\xbfagFK%\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xc1\xb9\xa5pM5\x1c\xfe\x98?y\xab\xee\xc3\u06fb\xae;\xb6)\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xc1\xcb\xd2\xe23*RL\xf2\x19\xb1\r\x87\x1c\xcc \xaf\x1f\xb0\xfa\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xc1\xcd\xc6\x01\xf8\x9c\x04(\xb3\x13\x02\u0447\xe0\xdc\b\xad}\x1cW\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94\xc1\u052f8\xe9\xbay\x90@\x89HI\xb8\xa8!\x93u\xf1\xacx\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xc1\xe1@\x9c\xa5,%CQ4\xd0\x06\u00a6\xa8T-\xfbrs\x89\x01\xdd\x1eK\xd8\xd1\xee\x00\x00\u07d4\xc1\xeb\xa5hJ\xa1\xb2L\xbac\x15\x02c\xb7\xa9\x13\x1a\xee\u008d\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xc1\xec\x81\xdd\x12=K|-\u0674\xd48\xa7\a,\x11\u0707L\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc1\xf3\x9b\xd3]\xd9\xce\xc37\xb9oG\xc6w\x81\x81`\xdf7\xb7\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u0794\xc1\xff\xad\a\u06d6\x13\x8cK*S\x0e\xc1\xc7\xde)\xb8\xa0Y,\x88\xf4?\xc2\xc0N\xe0\x00\x00\xe0\x94\xc2\x1f\xa6d:\x1f\x14\xc0)\x96\xadqD\xb7Y&\xe8~\xcbK\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xc24\nL\xa9L\x96x\xb7IL<\x85%(\xed\xe5\xeeR\x9f\x89\x02\xa3k\x05\xa3\xfd|\x80\x00\u07d4\xc29\xab\u07ee>\x9a\xf5E\u007fR\xed+\x91\xfd\n\xb4\xd9\xc7\x00\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc2;/\x92\x1c\xe4\xa3z%\x9e\u4b4b!X\xd1]fOY\x89\x01`\x89\x95\xe8\xbd?\x80\x00\u07d4\xc2C\x99\xb4\xbf\x86\xf73\x8f\xbfd^;\"\xb0\u0dd79\x12\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc2L\u03bc#D\xcc\xe5d\x17\xfbhL\xf8\x16\x13\xf0\xf4\xb9\xbd\x89T\x06\x923\xbf\u007fx\x00\x00\u07d4\xc2Rf\xc7gf2\xf1>\xf2\x9b\xe4U\ud50a\xddVw\x92\x89Hz\x9a0E9D\x00\x00\u07d4\xc2\\\xf8&U\f\x8e\xaf\x10\xaf\"4\xfe\xf9\x04\u0779R\x13\xbe\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xc2f?\x81E\xdb\xfe\xc6\xc6F\xfc\\I\x96\x13E\xde\x1c\x9f\x11\x89%g\xacp9+\x88\x00\x00\u07d4\xc2pEh\x854+d\vL\xfc\x1bR\x0e\x1aTN\xe0\xd5q\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4\xc2sv\xf4]!\xe1^\xde;&\xf2e_\xce\xe0,\xcc\x0f*\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xc2w\x97q\xf0Smy\xa8p\x8fi1\xab\xc4K05\u964a\x047\u04ca\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\xc2\xc1>r\xd2h\xe7\x15\r\u01d9\xe7\xc6\xcf\x03\u0209T\xce\u05c9%\xf2s\x93=\xb5p\x00\x00\u07d4\xc2\xcb\x1a\xda]\xa9\xa0B8s\x81G\x93\xf1aD\xef6\xb2\xf3\x89HU~;p\x17\xdf\x00\x00\u07d4\xc2\xd1w\x8e\xf6\xee_\xe4\x88\xc1E\xf3Xkn\xbb\xe3\xfb\xb4E\x89>\x1f\xf1\xe0;U\xa8\x00\x00\xe0\x94\xc2\xd9\xee\xdb\xc9\x01\x92c\xd9\xd1l\u016e\a-\x1d=\xd9\xdb\x03\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xc2\xe0XJq4\x8c\xc3\x14\xb7; )\xb6#\v\x92\u06f1\x16\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc2\xe2\u0518\xf7\r\xcd\bY\xe5\v\x02:q\nmK!3\xbd\x8989\x11\xf0\f\xbc\xe1\x00\x00\u07d4\xc2\xed_\xfd\u046d\xd8U\xa2i/\xe0b\xb5\xd6\x18t#`\u0509A\rXj \xa4\xc0\x00\x00\u07d4\xc2\xee\x91\xd3\xefX\xc9\u0465\x89\x84N\xa1\xae1%\xd6\u017ai\x894\x95tD\xb8@\xe8\x00\x00\u07d4\xc2\xfa\xfd\xd3\n\xcbmg\x06\xe9)<\xb0&A\xf9\xed\xbe\a\xb5\x89Q\x00\x86\vC\x0fH\x00\x00\u07d4\xc2\xfd\v\xf7\xc7%\xef>\x04~Z\xe1\u009f\xe1\x8f\x12\xa7)\x9c\x89Hz\x9a0E9D\x00\x00\u07d4\xc2\xfe}us\x1fcm\xcd\t\xdb\xda\x06q9;\xa0\xc8*}\x89wC\"\x17\xe6\x83`\x00\x00\u07d4\xc3\x10z\x9a\xf32-R8\xdf\x012A\x911b\x959W}\x89\x1a\xb4\xe4d\xd4\x141\x00\x00\xe0\x94\xc3\x11\v\xe0\x1d\xc9sL\xfcn\x1c\xe0\u007f\x87\xd7}\x13E\xb7\xe1\x8a\x01\x0f\f\xe9I\xe0\x0f\x93\x00\x00\u07d4\xc3 8\xcaR\xae\xe1\x97E\xbe\\1\xfc\xdcT\x14\x8b\xb2\xc4\u0409\x02\xb5\xaa\xd7,e \x00\x00\u07d4\xc3%\xc3R\x80\x1b\xa8\x83\xb3\"l_\xeb\r\xf9\xea\xe2\xd6\xe6S\x89\u0556{\xe4\xfc?\x10\x00\x00\u07d4\xc3.\xc7\xe4*\xd1l\xe3\xe2UZ\xd4\xc5C\x06\xed\xa0\xb2gX\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc32\xdfP\xb1<\x014\x90\xa5\xd7\xc7]\xbf\xa3f\u0687\xb6\u0589\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xc3:\u0373\xba\x1a\xab'P{\x86\xb1]g\xfa\xf9\x1e\xcfb\x93\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xc3>\u0393Z\x8fN\xf98\xea~\x1b\xac\x87\u02d2]\x84\x90\u028a\a\x03\x8c\x16x\x1fxH\x00\x00\u07d4\xc3@\xf9\xb9\x1c&r\x8c1\xd1!\xd5\xd6\xfc;\xb5m=\x86$\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc3F\xcb\x1f\xbc\xe2\xab(]\x8eT\x01\xf4-\xd7#M7\xe8m\x89\x04\x86\u02d7\x99\x19\x1e\x00\x00\xe0\x94\xc3H=n\x88\xac\x1fJ\xe7<\xc4@\x8dl\x03\xab\xe0\xe4\x9d\u028a\x03\x99\x92d\x8a#\u0220\x00\x00\xe0\x94\xc3H\xfcZF\x13#\xb5{\xe3\x03\u02c96\x1b\x99\x19\x13\xdf(\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\xc3N;\xa12.\xd0W\x11\x83\xa2O\x94 N\xe4\x9c\x18fA\x89\x03'\xaf\uf927\xbc\x00\x00\xe0\x94\xc3[\x95\xa2\xa3s|\xb8\xf0\xf5\x96\xb3E$\x87+\xd3\r\xa24\x8a\x01\x98\xbe\x85#^-P\x00\x00\xe0\x94\xc3c\x1cv\x98\xb6\xc5\x11\x19\x89\xbfE''\xb3\xf99Zm\xea\x8a\x02C'X\x96d\x1d\xbe\x00\x00\u07d4\xc3l\vc\xbf\xd7\\/\x8e\xfb\x06\b\x83\xd8h\xcc\xcdl\xbd\xb4\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\xe0\x94\xc3uk\xcd\xcc~\xect\xed\x89j\xdf\xc35'Y0&n\b\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\u00c4\xacn\xe2|9\xe2\xf2x\xc2 \xbd\xfa[\xae\xd6&\xd9\u04c9 \x86\xac5\x10R`\x00\x00\u07d4\u00e0F\xe3\u04b2\xbfh\x14\x88\x82n2\xd9\xc0aQ\x8c\xfe\x8c\x89\x8c\xf2?\x90\x9c\x0f\xa0\x00\x00\u07d4\u00e9\"j\xe2u\xdf,\xab1+\x91\x10@cJ\x9c\x9c\x9e\xf6\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\u00f9(\xa7o\xadex\xf0O\x05U\xe69R\xcd!\xd1R\n\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xc3\xc2)s)\xa6\xfd\x99\x11~T\xfcj\xf3y\xb4\xd5VT~\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xc3\xc3\xc2Q\rg\x80 HZcs]\x13\a\xecL\xa60+\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xc3\xcbk6\xafD?,n%\x8bJ9U:\x81\x87G\x81\x1f\x89WG=\x05\u06ba\xe8\x00\x00\xe0\x94\xc3\xdbVW\xbbr\xf1\rX\xf21\xfd\xdf\x11\x98\n\xffg\x86\x93\x8a\x01@a\xb9\xd7z^\x98\x00\x00\xe0\x94\xc3\u06df\xb6\xf4lH\n\xf3De\u05d7S\xb4\xe2\xb7Jg\u038a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xc3\xddX\x908\x860;\x92\x86%%z\xe1\xa0\x13\xd7\x1a\xe2\x16\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc3\xe0G\x1cd\xff5\xfaR2\xcc1!\xd1\u04cd\x1a\x0f\xb7\u0789lk\x93[\x8b\xbd@\x00\x00\u07d4\xc3\xe2\f\x96\u07cdN8\xf5\v&Z\x98\xa9\x06\xd6\x1b\xc5\x1aq\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc3\u31f0<\xe9\\\xcf\xd7\xfaQ\u0744\x01\x83\xbcCS(\t\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xc3\xf8\xf6r\x95\xa5\xcd\x04\x93d\xd0]#P\xa3\xe5.\x84\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xc4\x01\xc4'\xcc\xcf\xf1\r\xec\xb8d /6\xf5\x80\x83\"\xa0\xa8\x89\xb4{Q\xa6\x9c\xd4\x02\x00\x00\u07d4\xc4\b\x8c\x02_>\x85\x01?T9\xfb4@\xa1s\x01\xe5D\xfe\x89~\t\xdbM\x9f?4\x00\x00\u07d4\xc4\x14a\xa3\u03fd2\u0246UU\xa4\x8117\xc0v1#`\x8965\xc6 G9\u0640\x00\u07d4\xc4 8\x8f\xbe\xe8J\xd6V\xddh\xcd\xc1\xfb\xaa\x93\x92x\v4\x89\n-\xcac\xaa\xf4\u0140\x00\u07d4\xc4\"P\xb0\xfeB\xe6\xb7\xdc\xd5\u0210\xa6\xf0\u020f__\xb5t\x89\b\x1e\xe4\x82SY\x84\x00\x00\u07d4\xc4-j\xebq\x0e:P\xbf\xb4Ml1\t)i\xa1\x1a\xa7\xf3\x89\b\"c\xca\xfd\x8c\xea\x00\x00\xe0\x94\xc4@\xc7\xca/\x96Kir\xeffJ\"a\xdd\xe8\x92a\x9d\x9c\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94\xc4K\xde\xc8\xc3l\\h\xba\xa2\xdd\xf1\xd41i2)rlC\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\xc4OJ\xb5\xbc`9|s~\xb0h3\x91\xb63\xf8\xa2G\x1b\x12\x1c\xa4\x89 .h\xf2\u00ae\xe4\x00\x00\u07d4\xc4h\x1es\xbb\x0e2\xf6\xb7& H1\xffi\xba\xa4\x87~2\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4\xc4k\xbd\xefv\xd4\xca`\xd3\x16\xc0\u007f]\x1ax\x0e;\x16_~\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc4}a\v9\x92P\xf7\x0e\xcf\x13\x89\xba\xb6),\x91&O#\x89\x0f\xa7\xe7\xb5\xdf<\xd0\x00\x00\u07d4\u0100;\xb4\a\xc7b\xf9\vu\x96\xe6\xfd\u1513\x1ev\x95\x90\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\u0106Q\xc1\xd9\xc1k\xffL\x95T\x88l??&C\x1foh\x89#\xab\x95\x99\xc4?\b\x00\x00\u07d4\u0109\xc8?\xfb\xb0%*\xc0\xdb\xe3R\x12\x17c\x0e\x0fI\x1f\x14\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\u010bi<\xac\xef\xdb\xd6\xcb]x\x95\xa4.1\x962~&\x1c\x8965\u026d\xc5\u07a0\x00\x00\u07d4\u0113H\x9eV\u00fd\xd8)\x00}\xc2\xf9VA)\x06\xf7k\xfa\x89\x02\xa7\x91H\x8eqT\x00\x00\u07d4\u0116\u02f0E\x9aj\x01`\x0f\u0149\xa5Z2\xb4T!\u007f\x9d\x89\x0e\u0683\x8cI)\b\x00\x00\u07d4\u011c\xfa\xa9g\xf3\xaf\xbfU\x03\x10a\xfcL\xef\x88\xf8]\xa5\x84\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\u0136\xe5\xf0\x9c\xc1\xb9\r\xf0x\x03\xce=M\x13vj\x9cF\xf4\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94\u013e\xc9c\b\xa2\x0f\x90\u02b1\x83\x99\u0113\xfd=\x06Z\xbfE\x8a\x02\xf6\xf1\a\x80\xd2,\xc0\x00\x00\xe0\x94\xc4\xc0\x1a\xfc>\x0f\x04R!\xda\x12\x84\u05c7\x85tD/\xb9\xac\x8a\x01\x92\xb5\u0249\x02J\x19\xc1\xbdo\x12\x80\x00\xe0\x94\xc5\x00\xb7 sN\xd2)8\u05cc^H\xb2\xba\x93g\xa5u\xba\x8a\a\x12\x9e\x1c\xdf7>\xe0\x00\x00\u07d4\xc5\x0f\xe4\x15\xa6A\xb0\x85lNu\xbf\x96\x05\x15D\x1a\xfa5\x8d\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc5\x13L\xfb\xb1\xdfz \xb0\xedpWb.\xee\u0480\x94}\xad\x89\xcd\xff\x97\xfa\xbc\xb4`\x00\x00\xe0\x94\xc5\x17\xd01\\\x87\x88\x13\xc7\x17\u132f\xa1\xea\xb2eN\x01\u068a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xc5\x18y\x9aY%Wb\x13\xe2\x18\x96\xe0S\x9a\xbb\x85\xb0Z\xe3\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xc5\"\xe2\x0f\xbf\x04\xed\u007fk\x05\xa3{G\x18\xd6\xfc\xe0\x14.\x1a\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xc5$\bmF\xc8\x11+\x12\x8b/\xafo|}\x81`\xa88l\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xc5-\x1a\fs\u00a1\xbe\x84\x91Q\x85\xf8\xb3O\xaa\n\xdf\x1d\xe3\x89K\xe4\xea\xb3\xfa\x0f\xa6\x80\x00\xe0\x94\xc55\x94\xc7\u03f2\xa0\x8f(L\xc9\u05e6;\xbd\xfc\v1\x972\x8a\nk#(\xff:b\xc0\x00\x00\u07d4\xc57I(\xcd\xf1\x93pTC\xb1L\xc2\r\xa4#G<\xd9\u03c9\a}\x10P\x9b\xb3\xaf\x80\x00\u07d4\xc58\xa0\xff(*\xaa_Ku\u03f6,p\x03~\xe6}O\xb5\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc5;P\xfd;+r\xbclC\v\xaf\x19JQU\x85\u04d8m\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xc5=y\xf7\u02dbp\x95/\xd3\x0f\xceX\xd5K\x9f\vY\xf6G\x8a\x01\x13\xe2\xd6tCE\xf8\x00\x00\u07d4\xc5I\u07c3\xc6\xf6^\xec\x0f\x1d\u0260\x93J\\_:P\xfd\x88\x89\x9d\xc0\\\xce(\u00b8\x00\x00\u07d4\xc5P\x05\xa6\xc3~\x8c\xa7\xe5C\xce%\x99s\xa3\xca\u0396\x1aJ\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc5U\xb91V\xf0\x91\x01#\x80\x00\xe0\x94\u0166)\xa3\x96%R\u02ce\xde\u0609cj\xaf\xbd\f\x18\xcee\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\u016e\x86\xb0\xc6\xc7\xe3\x90\x0f\x13h\x10\\VS\u007f\xaf\x8dt>\x89\n1\x06+\xee\xedp\x00\x00\u07d4\u0170\t\xba\xea\xf7\x88\xa2v\xbd5\x81:\xd6[@\v\x84\x9f;\x8965\u026d\xc5\u07a0\x00\x00\u07d4\u0175l\xd24&|(\xe8\x9cok\"f\xb0\x86\xa1/\x97\f\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\xc5\u01a4\x99\x8a3\xfe\xb7dCz\x8b\xe9)\xa7;\xa3J\ad\x8a\n\x96\x81c\xf0\xa5{@\x00\x00\xe0\x94\xc5\xc7=a\xcc\xe7\xc8\xfeL\x8f\xce)\xf3\x90\x92\xcd\x19>\x0f\xff\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xc5\xc7Y\vV!\xec\xf85\x85\x88\u079bh\x90\xf2baC\U000498a1]\tQ\x9b\xe0\x00\x00\u07d4\xc5\xcd\xce\xe0\xe8]\x11}\xab\xbfSj?@i\xbfD?T\xe7\x89j\xc5\xc6-\x94\x86\a\x00\x00\u07d4\xc5\u050c\xa2\xdb/\x85\xd8\xc5U\xcb\x0e\x9c\xfe\x82i6x?\x9e\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xc5\xde\x12\x03\xd3\xcc,\xea1\xc8.\xe2\xdeY\x16\x88\a\x99\xea\xfd\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\xc5\xe4\x88\xcf+Vw\x939q\xf6L\xb8 -\xd0WR\xa2\xc0\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xc5\xe8\x12\xf7o\x15\xf2\xe1\xf2\xf9\xbcH#H<\x88\x04cog\x89\x03\xf5\x14\x19:\xbb\x84\x00\x00\u07d4\xc5\u94d34\xf1%.\u04ba&\x81D\x87\xdf\u0498+1(\x89\x03\xcbq\xf5\x1f\xc5X\x00\x00\u07d4\xc5\xebB)^\x9c\xad\xea\xf2\xaf\x12\xde\u078a\x8dS\xc5y\xc4i\x89\xcf\x15&@\xc5\xc80\x00\x00\xe0\x94\xc5\xed\xbb\xd2\xca\x03WeJ\xd0\xeaG\x93\xf8\xc5\xce\xcd0\xe2T\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xc5\xf6K\xab\xb7\x031B\xf2\x0eF\u05eab\x01\xed\x86\xf6q\x03\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc5\xf6\x87qrF\u068a \r \xe5\u9f2c`\xb6\u007f8a\x89\x01\x8d\x99?4\xae\xf1\x00\x00\u07d4\xc6\x04[<5\vL\xe9\xca\fkuO\xb4\x1ai\xb9~\x99\x00\x892$\xf4'#\xd4T\x00\x00\u07d4\xc6\v\x04eN\x00;F\x83\x04\x1f\x1c\xbdk\u00cf\xda|\xdb\u0589lk\x93[\x8b\xbd@\x00\x00\u07d4\xc6\x14F\xb7T\xc2N;\x16B\xd9\xe5\x17e\xb4\xd3\xe4k4\xb6\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc6\x18R\x13!\xab\xaf[&Q:J\x95(\bo\"\n\xdco\x89\x01v\xb3D\xf2\xa7\x8c\x00\x00\u07d4\xc6#FW\xa8\a8A&\xf8\x96\x8c\xa1p\x8b\xb0{\xaaI<\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xc6%\xf8\u024d'\xa0\x9a\x1b\u02bdQ(\xb1\u00a9HV\xaf0\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xc65^\xc4v\x8cp\xa4\x9a\xf6\x95\x13\u0343\xa5\xbc\xa7\xe3\xb9\u034a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xc6:\xc4\x17\x99.\x9f\x9b`8n\xd9S\xe6\xd7\xdf\xf2\xb0\x90\xe8\x89\xd8\xd8X?\xa2\xd5/\x00\x00\u07d4\xc6<\u05c8!\x18\xb8\xa9\x1e\aML\x8fK\xa9\x18Q0;\x9a\x89\x0e\x189\x8ev\x01\x90\x00\x00\u07d4\xc6R\x87\x1d\x19$\"\u01bc#_\xa0c\xb4J~\x1dC\u3149\bg\x0e\x9e\xc6Y\x8c\x00\x00\xe0\x94\xc6gD\x1e\u007f)y\x9a\xbaadQ\xd5;?H\x9f\x9e\x0fH\x8a\x02\xf2\x9a\xceh\xad\u0740\x00\x00\u07d4\xc6j\xe4\xce\xe8\u007f\xb352\x19\xf7\u007f\x1dd\x86\u0140(\x032\x89\x01\x9a\x16\xb0o\xf8\xcb\x00\x00\u07d4\xc6t\xf2\x8c\x8a\xfd\a?\x8by\x96\x91\xb2\xf0XM\xf9B\xe8D\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\u0197\xb7\x04w\u02b4.+\x8b&f\x81\xf4\xaesu\xbb%A\x8a\x01.W2\xba\xba\\\x98\x00\x00\u07d4\u019b\x85U9\xce\x1b\x04qG(\xee\xc2Z7\xf3g\x95\x1d\xe7\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u019b\xe4@\x13Mb\x80\x98\x01D\xa9\xf6M\x84t\x8a7\xf3I\x89&\u009eG\u0104L\x00\x00\u07d4\u019df<\x8d`\x90\x83\x91\xc8\xd26\x19\x153\xfd\xf7wV\x13\x89\x1aJ\xba\"\\ t\x00\x00\u0794\u01a2\x86\xe0e\xc8_:\xf7H\x12\xed\x8b\u04e8\xce]%\xe2\x1d\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\u01a3\x0e\xf5\xbb3 \xf4\r\xc5\xe9\x81#\rR\xae:\xc1\x93\"\x89\t\xdd\xc1\xe3\xb9\x01\x18\x00\x00\u07d4\u01ae(}\xdb\xe1\x14\x9b\xa1m\xdc\xcaO\xe0j\xa2\uaa48\xa9\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xc6\xc7\xc1\x917\x98\x97\u075c\x9d\x9a3\x83\x9cJ_b\xc0\x89\r\x89\xd8\xd8T\xb2$0h\x80\x00\xe0\x94\xc6\xcdh\xec56,Z\xd8L\x82\xadN\xdc#!%\x91-\x99\x8a\x05\xe0T\x9c\x962\xe1\xd8\x00\x00\u07d4\xc6\u0615N\x8f?\xc53\xd2\xd20\xff\x02\\\xb4\xdc\xe1O4&\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xc6\xdb\u06de\xfd^\xc1\xb3xn\x06q\xeb\"y\xb2S\xf2\x15\xed\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xc6\xdf u\xeb\xd2@\xd4Hi\u00bek\u07c2\xe6=N\xf1\xf5\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xc6\xe2\xf5\xaf\x97\x9a\x03\xfdr:\x1bn\xfar\x83\x18\u03dc\x18\x00\x89$=M\x18\"\x9c\xa2\x00\x00\u07d4\xc6\xe3$\xbe\xeb[6v^\xcdFB`\xf7\xf2`\x06\xc5\xc6.\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc6\xe4\xcc\fr\x83\xfc\x1c\x85\xbcH\x13\xef\xfa\xafr\xb4\x98#\xc0\x89\x0f\x03\x1e\xc9\xc8}\xd3\x00\x00\xe0\x94\xc6\xee5\x93B)i5)\xdcA\u067bq\xa2IfX\xb8\x8e\x8a\x04+\xf0kx\xed;P\x00\x00\u07d4\xc6\xfb\x1e\xe3t\x17\u0400\xa0\xd0H\x92;\u06ba\xb0\x95\xd0w\u0189\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xc7\x05'\xd4D\u0110\xe9\xfc?\\\xc4Nf\xebO0k8\x0f\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xc7\r\x85mb\x1e\xc1E0<\nd\x00\xcd\x17\xbb\xd6\xf5\xea\xf7\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xc7\x0f\xa4Uv\xbf\x9c\x86_\x988\x93\x00,AI&\xf6\x10)\x89\x15\xb4\xaa\x8e\x97\x02h\x00\x00\u07d4\xc7\x11E\xe5)\u01e7\x14\xe6y\x03\xeeb\x06\xe4\xc3\x04+g'\x89M\x85<\x8f\x89\b\x98\x00\x00\u07d4\xc7\x1b*=q5\u04a8_\xb5\xa5q\u073ei^\x13\xfcC\u034965\u026d\xc5\u07a0\x00\x00\u07d4\xc7\x1f\x1du\x87?3\u0732\xddK9\x87\xa1-\a\x91\xa5\xce'\x897\b\xba\xed=h\x90\x00\x00\u07d4\xc7\x1f\x92\xa3\xa5J{\x8c/^\xa4C\x05\xfc\u02c4\xee\xe21H\x89\x02\xb5\x9c\xa11\xd2\x06\x00\x00\u07d4\xc7!\xb2\xa7\xaaD\xc2\x12\x98\xe8P9\xd0\x0e.F\x0eg\v\x9c\x89\a\xa1\xfe\x16\x02w\x00\x00\x00\u07d4\xc7,\xb3\x01%\x8e\x91\xbc\b\x99\x8a\x80]\u0452\xf2\\/\x9a5\x89 \t\xc5\u023fo\xdc\x00\x00\xe0\x94\xc76\x8b\x97\t\xa5\xc1\xb5\x1c\n\xdf\x18ze\xdf\x14\xe1+}\xba\x8a\x02\x02o\xc7\u007f\x03\u5b80\x00\u07d4\xc79%\x9e\u007f\x85\xf2e\x9b\xef_`\x9e\xd8k=Yl \x1e\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xc7>!\x12(\"\x15\xdc\ab\xf3+~\x80}\xcd\x1az\xae>\x8a\x01v\f\xbcb;\xb3P\x00\x00\xe0\x94\xc7If\x80B\xe7\x11#\xa6H\x97^\b\xedc\x82\xf8>\x05\xe2\x8a\x02\xf6\xf1\a\x80\xd2,\xc0\x00\x00\u07d4\xc7J9\x95\xf8\a\xde\x1d\xb0\x1a.\xb9\xc6.\x97\xd0T\x8fio\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xc7Pl\x10\x19\x12\x1f\xf0\x8a,\x8c\x15\x91\xa6^\xb4\xbd\xfbJ?\x89 \x86\xac5\x10R`\x00\x00\u07d4\xc7\\7\xce-\xa0k\xbc@\b\x11Y\u01ba\x0f\x97n9\x93\xb1\x89:y#\x15\x1e\xcfX\x00\x00\u07d4\xc7]\"Y0j\xec}\xf0\"v\x8ci\x89\x9ae!\x85\xdb\u0109\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xc7`\x97\x1b\xbc\x18\x1cj|\xf7tA\xf2BG\u045c\xe9\xb4\u03c9lk\x93[\x8b\xbd@\x00\x00\u07d4\xc7a0\xc7<\xb9!\x028\x02\\\x9d\xf9]\v\xe5J\xc6\u007f\xbe\x89QP\xae\x84\xa8\xcd\xf0\x00\x00\u07d4\xc7e\xe0\x04v\x81\tG\x81j\xf1B\xd4m.\u7f28\xccO\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xc7g^VG\xb9\xd8\xda\xf4\xd3\xdf\xf1\xe5R\xf6\xb0qT\xac8\x89\t\xc2\x00vQ\xb2P\x00\x00\u07d4\xc7{\x01\xa6\xe9\x11\xfa\x98\x8d\x01\xa3\xab3dk\xee\xf9\xc18\xf3\x89'\x1bo\xa5\xdb\xe6\xcc\x00\x00\u07d4\u01c3z\u0420\xbf\x14\x18i7\xac\xe0lUF\xa3j\xa5OF\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\u01d8\x06\x03+\xc7\xd8(\xf1\x9a\u01a6@\u018e=\x82\x0f\xa4B\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\u01d9\xe3N\x88\xff\x88\xbe}\xe2\x8e\x15\xe4\xf2\xa6=\v3\xc4\u02c9\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\u01ddPb\u01d6\xddwa\xf1\xf1>U\x8ds\xa5\x9f\x82\xf3\x8b\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\u01e0\x18\xf0\x96\x8aQ\xd1\xf6`<\\I\xdcT[\xcb\x0f\xf2\x93\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\u01ef\xf9\x19)yt\x89UZ/\xf1\xd1M\\iZ\x10\x83U\x8965\u026d\xc5\u07a0\x00\x00\u0794\u01f1\xc8>c ?\x95G&>\xf6(.}\xa3;n\xd6Y\x88\xfc\x93c\x92\x80\x1c\x00\x00\xe0\x94\u01f3\x9b\x06\x04Q\x00\f\xa1\x04\x9b\xa1T\xbc\xfa\x00\xff\x8a\xf2b\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\u01ff\x17\xc4\xc1\x1f\x98\x94\x1fP~w\bO\xff\xbd-\xbd=\xb5\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\u01ff.\xd1\xed1)@\xeej\xde\xd1Qn&\x8eJ`HV\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xc7\xd4O\xe3,\u007f\x8c\xd5\xf1\xa9t'\xb6\xcd:\xfc\x9eE\x02>\x89U\xa6\xe7\x9c\xcd\x1d0\x00\x00\u07d4\xc7\xd5\xc7\x05@\x81\xe9\x18\xech{Z\xb3n\x97=\x18\x13)5\x89\t\xdd\xc1\xe3\xb9\x01\x18\x00\x00\u07d4\xc7\xde^\x8e\xaf\xb5\xf6+\x1a\n\xf2\x19\\\xf7\x93\u01c9L\x92h\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xc7\xe30\xcd\f\x89\n\u025f\xe7q\xfc\xc7\xe7\xb0\t\xb7A=\x8a\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xc7\xea\xc3\x1a\xbc\xe6\xd5\xf1\u07a4\"\x02\xb6\xa6t\x15=\xb4z)\x89 \t\xc5\u023fo\xdc\x00\x00\xe0\x94\xc7\xecb\xb8\x04\xb1\xf6\x9b\x1e0p\xb5\xd3b\xc6/\xb3\t\xb0p\x8a\x02\xc4k\xf5A`f\x11\x00\x00\u07d4\xc7\xf7+\xb7X\x01k7G\x14\u0509\x9b\xce\"\xb4\xae\xc7\n1\x89:&\xc9G\x8f^-\x00\x00\u0794\xc8\v6\u047e\xaf\xba_\xccdM`\xacnF\xed)'\xe7\u0708\xb9\x8b\xc8)\xa6\xf9\x00\x00\u07d4\xc8\x11\xc2\xe9\xaa\x1a\xc3F.\xba^\x88\xfc\xb5\x12\x0e\x9fn,\xa2\x89K\xe6\u0607\xbd\x87n\x00\x00\u07d4\xc8\x17\xdf\x1b\x91\xfa\xf3\x0f\xe3%\x15qr|\x97\x11\xb4]\x8f\x06\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\xc8\x1f\xb7\xd2\x0f\u0480\x01\x92\xf0\xaa\xc1\x98\xd6\u05a3}?\xcb}\x89\x0e\x11I3\x1c-\xde\x00\x00\u07d4\xc8 \xc7\x11\xf0w\x05'8\a\xaa\xaam\xe4M\x0eKH\xbe.\x89\bg\x0e\x9e\xc6Y\x8c\x00\x00\u07d4\xc8#\x1b\xa5\xa4\x11\xa1>\"+)\xbf\xc1\b?v1X\xf2&\x8967\tlK\xcci\x00\x00\u07d4\xc86\xe2Jo\xcf)\x94;6\b\xe6b)\n!_e)\xea\x89\x0f\xd4Pd\xea\xee\x10\x00\x00\xe0\x94\xc8;\xa6\u0755I\xbe\x1d2\x87\xa5\xa6T\xd1\x06\xc3Lk]\xa2\x8a\x01{x\x83\xc0i\x16`\x00\x00\u07d4\xc8>\x9djX%;\uefb7\x93\xe6\xf2\x8b\x05JXI\x1bt\x89\x0fF\u00b6\xf5\xa9\x14\x00\x00\u07d4\xc8A\x88O\xa4x_\xb7s\xb2\x8e\x97\x15\xfa\xe9\x9aQ40]\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc8M\x9b\xea\n{\x9f\x14\x02 \xfd\x8b\x90\x97\u03ff\xd5\xed\xf5d\x89\x06\xab\x9e\u0091\xad}\x80\x00\u07d4\xc8RB\x8d+Xd\x97\xac\xd3\fV\xaa\x13\xfbU\x82\xf8D\x02\x893B\xd6\r\xff\x19`\x00\x00\u07d4\xc8S![\x9b\x9f-,\xd0t\x1eX^\x98{_\xb8\f!.\x89T\x06\x923\xbf\u007fx\x00\x00\u07d4\xc8S%\uaca5\x9b>\xd8c\xc8j_)\x06\xa0B)\xff\xa9\x89\x19=\u007f}%=\xe0\x00\x00\u07d4\xc8^\xf2}\x82\x04\x03\x80_\xc9\xed%\x9f\xffd\xac\xb8\xd64j\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc8akN\xc0\x91(\xcd\xff9\xd6\u4e6c\x86\xee\xc4q\xd5\xf2\x89\x01\r:\xa56\xe2\x94\x00\x00\xe0\x94\xc8a\x90\x90K\x8d\a\x9e\xc0\x10\xe4b\xcb\xff\xc9\b4\xff\xaa\\\x8a\x02#\x85\xa8'\xe8\x15P\x00\x00\u07d4\xc8q\r~\x8bZ;\u059aB\xfe\x0f\xa8\xb8|5\u007f\xdd\xcd\u0209\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xc8sR\u06e5\x82\xee f\xb9\xc0\x02\xa9b\xe0\x03\x13Ox\xb1\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94\xc8|w\xe3\xc2J\xde\xcd\xcd\x108\xa3\x8bV\xe1\x8d\xea\u04f7\x02\x8a\x01\xdd\f\x88_\x9a\r\x80\x00\x00\u07d4\xc8}:\xe3\u0607\x04\u066b\x00\t\xdc\xc1\xa0\x06q1\xf8\xba<\x89j\xc5\xc6-\x94\x86\a\x00\x00\xe0\x94\u0201N4R>8\xe1\xf9'\xa7\xdc\xe8FjDz\t6\x03\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\u0202U\xed\xdc\xf5!\xc6\xf8\x1d\x97\xf5\xa4!\x81\xc9\a=N\xf1\x89\x0f\u00d0D\xd0\n*\x80\x00\u07d4\u0205\xa1\x8a\xab\xf4T\x1b{{~\xcd0\xf6\xfa\u619d\x95i\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u020c\xa1\xe6\xe5\xf4\xd5X\xd17\x80\xf4\x88\xf1\rJ\xd3\x13\r4\x89T\x06\x923\xbf\u007fx\x00\x00\u07d4\u020e\xecT\xd3\x05\xc9(\xcc(H\xc2\xfe\xe251\xac\xb9mI\x89lj\u04c2\xd4\xfba\x00\x00\xe0\x94\u021c\xf5\x04\xb9\xf3\xf85\x18\x1f\xd8BO\\\xcb\xc8\xe1\xbd\xdf}\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\u0222\xc4\xe5\x9e\x1c\u007f\xc5H\x05X\x048\xae\xd3\xe4J\xfd\xf0\x0e\x89\x02b\x9ff\xe0\xc50\x00\x00\u07d4\u022aI\u301f\b\x99\xf2\x8a\xb5~gCp\x9dXA\x903\x89/\xb4t\t\x8fg\xc0\x00\x00\u07d4\u022b\x1a<\xf4l\xb8\xb0d\xdf.\"-9`s\x94 2w\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u0231\x85\x05%\xd9F\xf2\xae\x84\xf3\x17\xb1Q\x88\xc56\xa5\u0706\x89\x91\x8d\xdc:B\xa3\xd4\x00\x00\u07d4\xc8\xd4\xe1Y\x9d\x03\xb7\x98\t\xe0\x13\n\x8d\u00c4\b\xf0^\x8c\u04c9\x9f\xad\x06$\x12y\x16\x00\x00\u07d4\xc8\xdd'\xf1k\xf2$P\xf5w\x1b\x9f\xe4\xedO\xfc\xb3\t6\xf4\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\u07d4\xc8\xdezVL\u007f@\x12\xa6\xf6\xd1\x0f\u040fG\x89\x0f\xbf\a\u0509\x10CV\x1a\x88)0\x00\x00\u07d4\xc8\xe2\xad\xebT^I\x9d\x98,\f\x11sc\u03b4\x89\u0171\x1f\x895e\x9e\xf9?\x0f\xc4\x00\x00\xe0\x94\xc8\xe5X\xa3\xc5i~o\xb2:%\x94\u0200\xb7\xa1\xb6\x8f\x98`\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xc8\xf2\xb3 \xe6\xdf\xd7\t\x06\u0157\xba\xd2\xf9P\x13\x12\u01c2Y\x89Q\x93K\x8b:W\xd0\x00\x00\u07d4\xc9\x03\x00\xcb\x1d@w\xe6\xa6\xd7\xe1i\xa4`F\x8c\xf4\xa4\x92\u05c9lk\x93[\x8b\xbd@\x00\x00\u07d4\xc9\f7e\x15k\u028eH\x97\xab\x80$\x19\x15<\xbeR%\xa9\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xc9\x10\xa9pUl\x97\x16\xeaS\xaff\xdd\xef\x93\x141$\x91=\x89U\xa6\xe7\x9c\xcd\x1d0\x00\x00\xe0\x94\xc9\x12{\u007ff)\xee\x13\xfc?`\xbc/Dg\xa2\aE\xa7b\x8a\x03|\x9a\xa4\xe7\xceB\x1d\x80\x00\u07d4\xc9\x1b\xb5b\xe4+\xd4a0\xe2\u04eeFR\xb6\xa4\ub1bc\x0f\x89\x1dF\x01b\xf5\x16\xf0\x00\x00\xe0\x94\xc90\x88y\x05m\xfe\x13\x8e\xf8 \x8fy\xa9\x15\u01bc~p\xa8\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94\xc94\xbe\xca\xf7\x1f\"_\x8bJK\xf7\xb1\x97\xf4\xac\x9604\\\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xc9?\xbd\xe8\xd4m+\xcc\x0f\xa9\xb3;\u063a\u007f\x80B\x12Ue\x89K\xe4\xe7&{j\xe0\x00\x00\u07d4\xc9@\x89U:\xe4\xc2,\xa0\x9f\xbc\x98\xf5pu\xcf.\u0155\x04\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xc9A\x10\xe7\x1a\xfeW\x8a\xa2\x18\xe4\xfc(d\x03\xb03\n\u038d\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xc9F\u056c\xc14n\xba\nry\xa0\xac\x1dF\\\x99m\x82~\x8a\x03x=T_\xdf\n\xa4\x00\x00\u07d4\xc9J(\xfb20\xa9\xdd\xfa\x96Nw\x0f,\xe3\xc2S\xa7\xbeO\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xc9JXR\x03\xda{\xba\xfd\x93\xe1X\x84\xe6`\u0531\xea\xd8T\x8a\x01{x\x83\xc0i\x16`\x00\x00\u07d4\xc9O|5\xc0'\xd4}\xf8\xefO\x9d\xf8Z\x92H\xa1}\xd2;\x89\x01\x9f\x8euY\x92L\x00\x00\u07d4\xc9Q\x90\f4\x1a\xbb\xb3\xba\xfb\xf7\xee )7pq\xdb\xc3j\x89\x11\xc2]\x00M\x01\xf8\x00\x00\u07d4\xc9S\xf94\xc0\xeb-\x0f\x14K\u06b0\x04\x83\xfd\x81\x94\x86\\\xe7\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc9f&r\x8a\xaaLO\xb3\xd3\x1c&\xdf:\xf3\x10\b\x17\x10\u0449\xb5\x0f\u03ef\xeb\xec\xb0\x00\x00\u07d4\xc9gQel\n\x8e\xf45{sD2!4\xb9\x83PJ\u0289lk\x93[\x8b\xbd@\x00\x00\u07d4\u0240Hh\u007f+\xfc\u027d\x90\xed\x18slW\xed\xd3R\xb6]\x8965\u026d\xc5\u07a0\x00\x00\u07d4\u0241\xd3\x12\u0487\xd5X\x87\x1e\u0757:\xbbv\xb9y\xe5\xc3^\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\u0242Xmc\xb0\xd7L \x1b\x1a\xf8A\x83r\xe3\fv\x16\xbe\x89\x05k\xc7^-c\x10\x00\x00\u07d4\u0249CO\x82Z\xaf\x9cU/h^\xba|\x11\xdbJ_\xc7:\x89\x1b(\u014d\x96\x96\xb4\x00\x00\u07d4\u0249\xee\xc3\a\u80db\x9dr7\xcf\xda\b\x82)b\xab\u41c9\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\u0252\xbeY\xc6r\x1c\xafN\x02\x8f\x9e\x8f\x05\xc2\\UQ[\u0509\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\u0255{\xa9L\x1b)\xe5'~\xc3f\"pI\x04\xc6=\xc0#\x89h>\xfcg\x82d,\x00\x00\xe0\x94\u025a\x9c\xd6\xc9\xc1\xbe54\xee\u0352\xec\xc2/\\8\xe9Q[\x8a\x01\x05Y;:\x16\x9dw\x00\x00\xe0\x94\u026c\x01\xc3\xfb\t)\x03?\f\xcc~\x1a\xcf\uaae7\x94]G\x8a\x02\xa3j\x9e\x9c\xa4\xd2\x03\x80\x00\u07d4\u0276\x98\xe8\x98\xd2\rMO@\x8eNM\x06\x19\"\xaa\x85c\a\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\u0276\xb6\x86\x11\x16\x91\xeej\xa1\x97\xc7#\x1a\x88\xdc`\xbd)]\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xc9\u01ec\v\u0753B\xb5\xea\xd46\t#\xf6\x8cr\xa6\xbac:\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xc9\xc8\r\xc1.{\xab\x86\xe9I\xd0\x1eL>\xd3_+\x9b\xba_\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc9\xd7dF\u056a\xdf\xf8\vh\xb9\x1b\b\u035b\xc8\xf5U\x1a\xc1\x89&\xb4\xbd\x91\x10\xdc\xe8\x00\x00\xe0\x94\xc9\u073b\x05oM\xb7\xd9\xda9\x93b\x02\u017d\x820\xb3\xb4w\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xc9\xe0&\b\x06h(\x84\x8a\xeb(\xc76r\xa1)%\x18\x1fM\x89\x1b\x1bk\u05efd\xc7\x00\x00\u07d4\xca\x042\xcb\x15{Qy\xf0.\xbb\xa5\xc9\u0475O\xecM\x88\u028965\u026d\xc5\u07a0\x00\x00\u07d4\xca\x12,\xf0\U00094216\xb7HC\xf4\x9a\xfe\u043a\x16\x18\xee\u05c9\x1e[\x8f\xa8\xfe*\xc0\x00\x00\xe0\x94\xca\"\u0363`m\xa5\xca\xd0\x13\xb8\aG\x06\xd7\xe9\xe7!\xa5\f\x8a\x01q\x81\xc6\xfa9\x81\x94\x00\x00\u07d4\xca#\xf6-\xff\rd`\x03lb\xe8@\xae\xc5W~\v\xef\u0489\a\xa1\xfe\x16\x02w\x00\x00\x00\u07d4\xca%\xff4\x93L\x19B\xe2*N{\xd5o\x14\x02\x1a\x1a\xf0\x88\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\u07d4\xca7?\xe3\xc9\x06\xb8\xc6U\x9e\xe4\x9c\xcd\a\xf3|\xd4\xfbRf\x89a\t=|,m8\x00\x00\u07d4\xcaA\u032c0\x17 R\xd5\"\xcd//\x95}$\x81S@\x9f\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xcaB\x88\x01N\xdd\xc5c/_\xac\xb5\xe3\x85\x17\xa8\xf8\xbc]\x98\x89\x12nr\xa6\x9aP\xd0\x00\x00\u07d4\xcaB\x88c\xa5\xca06\x98\x92\xd6\x12\x18>\xf9\xfb\x1a\x04\xbc\xea\x89Rf<\u02b1\xe1\xc0\x00\x00\u07d4\xcaI\xa5\xf5\x8a\xdb\xef\xae#\xeeY\xee\xa2A\xcf\x04\x82b.\xaa\x89M\x85<\x8f\x89\b\x98\x00\x00\u07d4\xcaL\xa9\xe4w\x9dS\x0e\u02ec\xd4~j\x80X\xcf\xdee\u064f\x89+^:\xf1k\x18\x80\x00\x00\u07d4\xcae~\xc0o\xe5\xbc\t\xcf#\xe5*\xf7\xf8\f\xc3h\x9en\u07890\xca\x02O\x98{\x90\x00\x00\u07d4\xcaf\xb2(\x0f\xa2\x82\u0176v1\xceU+b\xeeU\xad\x84t\x89j\xc4\"\xf54\x92\x88\x00\x00\xe0\x94\xcal\x81\x8b\xef\xd2Q6\x1e\x02t@h\xbe\x99\u062a`\xb8J\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xcap\xf4\u077f\x06\x9d!C\xbdk\xbc\u007fikRx\x9b2\u7262\xa1]\tQ\x9b\xe0\x00\x00\xe0\x94\xcatuvDjL\x8f0\xb0\x83@\xfe\xe1\x98\xdec\xec\x92\u03ca\x01|\x8e\x12\x06r*0\x00\x00\u07d4\xca{\xa3\xffSl~_\x0e\x158\x00\xbd8=\xb81)\x98\xe0\x89\t1\xac=k\xb2@\x00\x00\xe0\x94\u0282v\xc4w\xb4\xa0{\x80\x10{\x845\x94\x18\x96\a\xb5;\xec\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\u0284\t\b>\x01\xb3\x97\xcf\x12\x92\x8a\x05\xb6\x84U\xceb\x01\u07c9V\xbcu\xe2\xd61\x00\x00\x00\u07d4\u0298\u01d8\x8e\xfa\b\xe9%\uf719ER\x03&\xe9\xf4;\x99\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\u029a\x04*j\x80o\xfc\x92\x17\x95\x00\xd2D)\xe8\xabR\x81\x17\x89;\xa1\x91\v\xf3A\xb0\x00\x00\u07d4\u029d\xec\x02\x84\x1a\xdf\\\xc9 WjQ\x87\xed\u04bdCJ\x18\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\u029f\xaa\x17T/\xaf\xbb8\x8e\xab!\xbcL\x94\u89f3G\x88\x89lk\x8f\xce\r\x18y\x80\x00\xe0\x94\u02aah\xeel\xdf\r4EJv\x9b\r\xa1H\xa1\xfa\xaa\x18e\x8a\x01\x87.\x1d\xe7\xfeR\xc0\x00\x00\u07d4\u02ad\x9d\xc2\rX\x9c\xe4(\xd8\xfd\xa3\xa9\xd5:`{y\x88\xb5\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\u02b0\xd3,\xf3v\u007f\xa6\xb3S|\x842\x8b\xaa\x9fPE\x816\x8a\x01\xe5\xb8\xfa\x8f\xe2\xac\x00\x00\x00\u07d4\u02b9\xa3\x01\xe6\xbdF\xe9@5P(\xec\xcd@\xceMZ\x1a\u00c9\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\u02b9\xa9z\xda\x06\\\x87\x81nh`\xa8\xf1Bo\xe6\xb3\xd7u\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\u02ba\xb6'N\xd1P\x89s~({\xe8x\xb7W\x93Hd\xe2\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\u02bd\xaf5OG \xa4f\xa7d\xa5(\xd6\x0e:H*9<\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xca\xcbg^\t\x96#T\x04\ufbfb.\u02c1R'\x1bU\xe0\x89%\xf2s\x93=\xb5p\x00\x00\u07d4\xca\xd1O\x9e\xbb\xa7f\x80\xeb\x83k\a\x9c\u007f{\xaa\xf4\x81\xedm\x89\f\xef={\xd7\xd04\x00\x00\xe0\x94\xca\xe3\xa2S\xbc\xb2\xcfN\x13\xba\x80\u0098\xab\x04\x02\xda|*\xa0\x8a\x01$\xbc\r\u0752\xe5`\x00\x00\u07d4\xca\xef\x02{\x1a\xb5\x04\xc7?A\xf2\xa1\ty\xb4t\xf9~0\x9f\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xca\xf4H\x1d\x9d\xb7\x8d\xc4\xf2_{J\u023d;\x1c\xa0\x10k1\x8a\x01\x0f\f\xf0d\xddY \x00\x00\xe0\x94\xca\xfd\xe8U\x86L%\x98\xda<\xaf\xc0Z\u064d\U00089380H\x8a\x03\x00\xa8\xed\x96\xffJ\x94\x00\x00\xe0\x94\xcb\r\xd7\xcfN]\x86a\xf6\x02\x89C\xa4\xb9\xb7\\\x91D6\xa7\x8a\x19i6\x89t\xc0[\x00\x00\x00\u07d4\xcb\x1b\xb6\xf1\xda^\xb1\rH\x99\xf7\xe6\x1d\x06\xc1\xb0\x0f\u07f5-\x898E$\xccp\xb7x\x00\x00\u07d4\xcb=vl\x98?\x19+\xce\xca\xc7\x0fN\xe0=\xd9\xffqMQ\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xcbB\xb4N\xb5\xfd`\xb5\x83~O\x9e\xb4rgR=\x1a\"\x9c\x89.\xe4IU\b\x98\xe4\x00\x00\u07d4\xcbG\xbd0\u03e8\xecTh\xaa\xa6\xa9FB\xce\xd9\xc8\x19\xc8\u0509\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xcbH\xfe\x82e\u066fU\xebp\x06\xbc3VE\xb0\xa3\xa1\x83\xbe\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xcbJ\x91M+\xb0)\xf3._\xef\\#LO\xec--\xd5w\x89a\x94\x04\x9f0\xf7 \x00\x00\xe0\x94\xcbJ\xbf\u0082\xae\xd7n]W\xaf\xfd\xa5B\xc1\xf3\x82\xfc\xac\xf4\x8a\x01\xb9\x0f\x11\xc3\x18?\xaa\x00\x00\u07d4\xcbJ\xd0\xc7#\xdaF\xabV\xd5&\xda\f\x1d%\xc7=\xaf\xf1\n\x89\x1b\xa5\xab\xf9\xe7y8\x00\x00\u07d4\xcbK\xb1\xc6#\xba(\xdcB\xbd\xaa\xa6\xe7N\x1d*\xa1%l*\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\xcbPXt\x12\x82#\x04\xeb\u02e0}\xab:\x0f\t\xff\xfe\u4189JD\x91\xbdm\xcd(\x00\x00\u07d4\xcbX\x99\v\u0350\u03ffm\x8f\t\x86\xf6\xfa`\x02v\xb9N-\x8964\xbf9\xab\x98x\x80\x00\u07d4\xcbh\xaeZ\xbe\x02\xdc\xf8\xcb\u016aq\x9c%\x81FQ\xaf\x8b\x85\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xcbty\x10\x9bC\xb2fW\xf4F_M\x18\xc6\xf9t\xbe_B\x89b\xa9\x92\xe5:\n\xf0\x00\x00\xe0\x94\xcb}+\x80\x89\xe91,\u026e\xaa's\xf3S\b\xecl*{\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\u02c6\xed\xbc\x8b\xbb\x1f\x911\x02+\xe6IV^\xbd\xb0\x9e2\xa1\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u02d3\x19\x9b\x9c\x90\xbcI\x15\xbd\x85\x9e=B\x86m\xc8\xc1\x87I\x89\f\x90\xdf\a\xde\xf7\x8c\x00\x00\u07d4\u02d4\xe7o\xeb\xe2\b\x11g3\xe7n\x80]H\xd1\x12\xec\x9f\u028965\u026d\xc5\u07a0\x00\x00\u07d4\u02dbQ\x03\xe4\u0389\xafOd\x91aP\xbf\xf9\xee\u02df\xaa\\\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\u02e2\\zP<\xc8\xe0\xd0Iq\xca\x05\xc7b\xf9\xb7b\xb4\x8b\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\u02e2\x88\xcd<\x1e\xb4\u055d\xdb\x06\xa6B\x1c\x14\xc3E\xa4{$\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\u02f3\x18\x9eK\xd7\xf4_\x17\x8b\x1c0\xc7n&1MJK\n\x89\x0f\xfe\vg|e\xa9\x80\x00\xe0\x94\u02f7\xbe\x17\x95?,\u0313\u1f19\x80[\xf4U\x11CNL\x8a\n\xae[\x9d\xf5m/ \x00\x00\xe0\x94\xcb\xc0KM\x8b\x82\xca\xf6p\x99o\x16\f6)@\xd6o\xcf\x1a\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xcb\u07974\xb8\xe6\xaaS\x8c)\x1dm\u007f\xac\xed\xb0\xf38\xf8W\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xcb\xe1\xb9H\x86M\x84t\xe7e\x14XX\xfc\xa4U\x0fxK\x92\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xcb\xe5/\xc53\xd7\xdd`\x8c\x92\xa2`\xb3|?E\u07b4\xeb3\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xcb\xe8\x10\xfe\x0f\xec\xc9dGJ\x1d\xb9w(\xbc\x87\xe9s\xfc\xbd\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xcb\xf1j\x0f\xe2tRX\xcdR\xdb+\xf2\x19T\xc9u\xfcj\x15\x89\x10CV\x1a\x88)0\x00\x00\xe0\x94\xcb\xf3\u007f\xf8T\xa2\xf1\xceS\x93D\x94wx\x92\xd3\xeceW\x82\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xcb\xfaj\xf6\u0083\xb0F\xe2w,`c\xb0\xb2\x15S\xc4\x01\x06\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xcb\xfav\xdb\x04\xce8\xfb ]7\xb8\xd3w\xcf\x13\x80\xda\x03\x17\x89M\x85<\x8f\x89\b\x98\x00\x00\u07d4\xcc\x03I\x85\xd3\xf2\x8c-9\xb1\xa3K\xce\xd4\u04f2\xb6\xca#N\x89\t\xdd\xc1\xe3\xb9\x01\x18\x00\x00\u07d4\xcc\x04\x8d\u01f9]\xca%\xdf&\xee\xfac\x9d\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xcc+_D\x8f5(\xd3\xfeA\xcc}\x1f\xa9\xc0\xdcv\xf1\xb7v\x89\x03@\xaa\xd2\x1b;p\x00\x00\u07d4\xcc-\x04\xf0\xa4\x01q\x89\xb3@\xcaw\x19\x86A\xdc\xf6Ek\x91\x89\u0556{\xe4\xfc?\x10\x00\x00\xe0\x94\xccA\x9f\u0651+\x85\x13VY\xe7z\x93\xbc=\xf1\x82\xd4Q\x15\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xccE\xfb:U[\xad\x80{8\x8a\x03W\xc8U _|u\xe8\x89.\xe4IU\b\x98\xe4\x00\x00\u07d4\xccHAM*\xc4\xd4*Yb\xf2\x9e\xeeD\x97\t/C\x13R\x89\b\xbaR\xe6\xfcE\xe4\x00\x00\u07d4\xccJ/,\xf8l\xf3\xe43u\xf3`\xa4sF\x91\x19_\x14\x90\x89I\x15\x05;\xd1)\t\x80\x00\u07d4\xccO\x0f\xf2\xae\xb6}T\xce;\xc8\xc6Q\v\x9a\xe8>\x9d2\x8b\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xccO\xaa\xc0\v\xe6b\x8f\x92\xefk\x8c\xb1\xb1\xe7j\xac\x81\xfa\x18\x89\v\"\xa2\xea\xb0\xf0\xfd\x00\x00\xe0\x94\xccO\xebr\u07d8\xff5\xa18\xe0\x17a\xd1 ?\x9b~\xdf\n\x8a\x01{x\x83\xc0i\x16`\x00\x00\u07d4\xcc`oQ\x13\x97\xa3\x8f\u01c7+\u04f0\xbd\x03\xc7\x1b\xbdv\x8b\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xcc`\xf86\xac\xde\xf3T\x8a\x1f\xef\u0321>\u01a97\xdbD\xa0\x89\x04\xb0m\xbb\xb4\x0fJ\x00\x00\u07d4\xccl\x03\xbd`>\t\xdeT\xe9\xc4\u056cmA\xcb\xceqW$\x89\x05V\xf6L\x1f\xe7\xfa\x00\x00\u07d4\xccl-\xf0\x0e\x86\xec\xa4\x0f!\xff\xda\x1ag\xa1i\x0fG|e\x89\xabM\xcf9\x9a:`\x00\x00\xe0\x94\xccm{\x12\x06\x1b\xc9m\x10M`me\xff\xa3+\x006\xeb\a\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xccs\xdd5kIy\xb5y\xb4\x01\xd4\xccz1\xa2h\xdd\xceZ\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94\xccu\x8d\a\x1d%\xa62\n\xf6\x8c]\xc9\xc4\xf6\x95[\xa9E \x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xcc{\x04\x81\xcc2\xe6\xfa\xef#\x86\xa0p\"\xbc\xb6\xd2\u00f4\xfc\x89\xabM\xcf9\x9a:`\x00\x00\xe0\x94\u0314;\xe1\",\xd1@\n#\x99\xdd\x1bE\x94E\xcfmT\xa9\x8a\x02\xa7@\xaee6\xfc\x88\x00\x00\u07d4\u0315\x19\xd1\xf3\x98_k%^\xad\xed\x12\xd5bJ\x97'!\xe1\x8965\u026d\xc5\u07a0\x00\x00\u0794\u031a\xc7\x15\xcdo&\x10\xc5+XgdV\x88B\x97\x01\x8b)\x88\xb9\x8b\xc8)\xa6\xf9\x00\x00\u07d4\u0320{\xb7\x94W\x1dJ\xcf\x04\x1d\xad\x87\xf0\xd1\xef1\x85\xb3\x19\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u032b\xc6\x04\x8aSFD$\xfc\xf7n\xeb\x9en\x18\x01\xfa#\u0509\x02\xab{&\x0f\xf3\xfd\x00\x00\u07d4\u032e\r=\x85*}\xa3\x86\x0f\x066\x15L\nl\xa3\x16(\u0509\x05\xc6\xd1+k\xc1\xa0\x00\x00\u07d4\xcc\xca$\xd8\xc5mn,\a\xdb\bn\xc0~X[\xe2g\xac\x8d\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xcc\xd5!\x13-\x98l\xb9hi\x84&\"\xa7\u0762l>\xd0W\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xcc\xf49u\xb7k\xfes_\xec<\xb7\xd4\xdd$\xf8\x05\xba\tb\x89\x03@\xaa\xd2\x1b;p\x00\x00\u07d4\xcc\xf6*f?\x13S\xba.\xf8\xe6R\x1d\xc1\xec\xb6s\xec\x8e\xf7\x89\b=lz\xabc`\x00\x00\u07d4\xcc\xf7\x11\r\x1b\u0667K\xfd\x1d}}-\x9dU`~{\x83}\x890\xca\x02O\x98{\x90\x00\x00\u07d4\xcc\xfdrW`\xa6\x88#\xff\x1e\x06/L\xc9~\x13`\xe8\u0657\x89\x15\xacV\xed\xc4\xd1,\x00\x00\u07d4\xcd\x02\x0f\x8e\xdf\xcfRG\x98\xa9\xb7:d\x034\xbb\xf7/\x80\xa5\x89\a?u\u0460\x85\xba\x00\x00\u07d4\xcd\x06\xf8\xc1\xb5\u037d(\xe2\xd9kcF\xc3\xe8Z\x04\x83\xba$\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xcd\a.n\x183\x13y\x95\x19m{\xb1r_\xef\x87a\xf6U\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xcd\n\x16\x1b\xc3g\xae\t'\xa9*\xac\x9c\xf6\xe5\bg\x14\xef\u0289lk\x93[\x8b\xbd@\x00\x00\u07d4\xcd\n\xf3GN\"\xf0i\xec4\a\x87\r\xd7pD=[\x12\xb0\x89\x8e^\xb4\xeew\xb2\xef\x00\x00\u07d4\xcd\v\x02W\u70e3\xd2\xc2\u3e9dny\xb7^\xf9\x80$\u0509\x9f\xad\x06$\x12y\x16\x00\x00\u07d4\xcd\x10,\xd6\xdb=\xf1J\u05af\x0f\x87\xc7$y\x86\x1b\xfc=$\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xcd\x1ef\xedS\x9d\xd9/\xc4\v\xba\xa1\xfa\x16\u078c\x02\xc1ME\x89\fw\xe4%hc\xd8\x00\x00\u07d4\xcd\x1e\xd2c\xfb\xf6\xf6\xf7\xb4\x8a\xef\x8fs=2\x9dC\x82\xc7\u01c9\x01\x00\xbd3\xfb\x98\xba\x00\x00\u07d4\xcd*6\xd7S\xe9\xe0\xed\x01*XMqh\aX{A\xd5j\x89\x0e+\xa7[\v\x1f\x1c\x00\x00\u07d4\xcd2\xa4\xa8\xa2\u007f\x1c\xc69T\xaacOxW\x05s4\u01e3\x89:\xd1fWlr\xd4\x00\x00\u07d4\xcd5\xff\x01\x0e\xc5\x01\xa7!\xa1\xb2\xf0z\x9c\xa5\x87}\xfc\xf9Z\x89\xd9o\u0390\u03eb\xcc\x00\x00\u07d4\xcdC\x06\xd7\xf6\x94z\xc1tMN\x13\xb8\xef2\xcbe~\x1c\x00\x89\x1b\x1a\xb3\x19\xf5\xecu\x00\x00\u07d4\xcdC%\x8bs\x92\xa90\x83\x9aQ\xb2\xef\x8a\xd24\x12\xf7Z\x9f\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xcdI\xbf\x18^p\xd0E\a\x99\x9f\x92\xa4\xdeDU1('\u040965\u026d\xc5\u07a0\x00\x00\u07d4\xcdU\x10\xa2B\u07f0\x18=\xe9%\xfb\xa8f\xe3\x12\xfa\xbc\x16W\x89\x82\x1a\xb0\xd4AI\x80\x00\x00\u07d4\xcdVj\u05f8\x83\xf0\x1f\u04d9\x8a\x9aX\xa9\xde\xe4rM\u0725\x89\x030\xae\x185\xbe0\x00\x00\xe0\x94\xcdY\xf3\xdd\xe7~\t\x94\v\xef\xb6\xeeX\x03\x19e\xca\xe7\xa36\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xcdr]p\xbe\x97\xe6w\xe3\xc8\xe8\\\v&\xef1\xe9\x95PE\x89Hz\x9a0E9D\x00\x00\xe0\x94\xcd~G\x90\x94d\xd8q\xb9\xa6\xdcv\xa8\xe9\x19]\xb3H^z\x8a\x02\x15\xf85\xbcv\x9d\xa8\x00\x00\u07d4\xcd~\xce\bkKa\x9b;6\x93R\xee8\xb7\x1d\xdb\x06C\x9a\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xcd\u007f\t\xd7\xedf\xd0\u00cb\u016dN2\xb7\xf2\xb0\x8d\xc1\xb3\r\x89>;\xb3M\xa2\xa4p\x00\x00\u07d4\u0355)I+\\)\xe4u\xac\xb9A@+=;\xa5\x06\x86\xb0\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\u0355\xfaB=o\xc1 'J\xac\xde\x19\xf4\xee\xb7f\xf1\x04 \x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\u035bL\xefs9\f\x83\xa8\xfdq\u05f5@\xa7\xf9\u03cb\x8c\x92\x89\x04\xe1\x00;(\xd9(\x00\x00\u07d4\u0361t\x11\t\xc0&[?\xb2\xbf\x8d^\xc9\u00b8\xa34kc\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\u0361\xb8\x86\u39d5\u027aw\x91N\n/\xe5go\x0f\\\u03c9\x05\xbf`\xeaB\xc2\x04\x00\x00\u07d4\u0364S\x0fK\x9b\xc5\t\x05\xb7\x9d\x17\u008f\xc4o\x954\x9b\u07c93\x10\xe0I\x11\xf1\xf8\x00\x00\u07d4\u036bF\xa5\x90 \x80do\xbf\x95B\x04 J\xe8\x84\x04\x82+\x89\x1d\x8a\x96\xe5\xc6\x06\xeb\x00\x00\u07d4\u0375\x97)\x900\x18?n-#\x853\xf4d*\xa5\x87T\xb6\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xcd\xd5\u0601\xa76,\x90p\a;\u07fcu\xe7$S\xacQ\x0e\x89-\xa5\x18\xea\xe4\x8e\xe8\x00\x00\u07d4\xcd\xd6\rs\xef\xaa\xd8s\u027b\xfb\x17\x8c\xa1\xb7\x10Z\x81\xa6\x81\x89\x01\xbc\x16\xd6t\xec\x80\x00\x00\u07d4\xcd\xd9\xef\xacMm`\xbdq\xd9U\x85\xdc\xe5\u0557\x05\xc15d\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xcd\xe3m\x81\xd1(\u015d\xa1Ee!\x93\xee\u00bf\xd9e\x86\xef\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xcd\xea8o\x9d\x0f\xd8\x04\xd0(\x18\xf27\xb7\xd9\xfavF\xd3^\x89\xa3I\xd3m\x80\xecW\x80\x00\u07d4\xcd\xec\xf5gT3\u0370\xc2\xe5Zh\xdb]\x8b\xbexA\x9d\u0489\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xcd\xfd\x82\x173\x97%\xd7\xeb\xac\x11\xa66U\xf2e\xef\xf1\xcc=\x8a\x01\x0f\fid\x10\xe3\xa9\x00\x00\u07d4\xce\a\x9fQ\x88wt\xd8\x02\x1c\xb3\xb5u\xf5\x8f\x18\xe9\xac\xf9\x84\x89\t\xc2\x00vQ\xb2P\x00\x00\u07d4\xce\x18\x84\u077b\xb8\xe1\x0eM\xbanD\xfe\xee\u00a7\xe5\xf9/\x05\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xce\x1b\f\xb4j\xae\xcf\u05db\x88\f\xad\x0f-\u068a\x8d\xed\u0431\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xce&\xf9\xa50_\x83\x81\tCT\xdb\xfc\x92fN\x84\xf9\x02\xb5\x89\fz\xaa\xb0Y\x1e\xec\x00\x00\u07d4\xce-\xea\xb5\x1c\n\x9a\xe0\x9c\xd2\x12\xc4\xfaL\xc5+S\xcc\r\xec\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xce.\r\xa8\x93F\x99\xbb\x1aU>U\xa0\xb8\\\x16\x945\xbe\xa3\x8a\x01\x0f\fid\x10\xe3\xa9\x00\x00\u07d4\xce:a\xf0F\x1b\x00\x93^\x85\xfa\x1e\xad\x82\xc4^Zd\u0508\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xceK\x06]\xbc\xb20G 2b\xfbH\xc1\x18\x83d\x97tp\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xceS\xc8\xcd\xd7B\x96\xac\xa9\x87\xb2\xbc\x19\u00b8u\xa4\x87I\u0409\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xce^\x04\xf0\x18Ci\xbc\xfa\x06\xac\xa6o\xfa\x91\xbfY\xfa\x0f\xb9\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\xce^\xb6:{\xf4\xfb\xc2\xf6\u4ea0\u018a\xb1\xcbL\xf9\x8f\xb4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xceb\x12Z\xde\xc37\n\xc5!\x10\x95:Nv\v\xe9E\x1e;\x89\b=lz\xabc`\x00\x00\xe0\x94\xceq\bmL`%T\xb8-\xcb\xfc\xe8\x8d cMS\xccM\x8a\t(\x96R\x9b\xad\u0708\x00\x00\u07d4\u038akmP3\xb1I\x8b\x1f\xfe\xb4\x1aAU\x04\x05\xfa\x03\xa2\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\u0397\x86\xd3q/\xa2\x00\xe9\xf6\x857\xee\xaa\x1a\x06\xa6\xf4ZK\x89a\t=|,m8\x00\x00\u07d4\u039d!\u0192\xcd<\x01\xf2\x01\x1fP_\x87\x006\xfa\x8fl\u0489\x15\xaf\x1dx\xb5\x8c@\x00\x00\xe0\x94\u03a2\x89f#\xf4\x91\x02\x87\xa2\xbd\u017e\x83\xae\xa3\xf2\xe6\xde\b\x8a\x01\xfbZ7Q\xe4\x90\xdc\x00\x00\u07d4\u03a3JM\xd9=\u066e\xfd9\x90\x02\xa9}\x99z\x1bK\x89\u0349QP\xae\x84\xa8\xcd\xf0\x00\x00\u07d4\u03a4?pu\x81k`\xbb\xfc\u62d9:\xf0\x88\x12p\xf6\u0109lk\x93[\x8b\xbd@\x00\x00\u07d4\u03a8t3AS<\xb2\xf0\xb9\xc6\xef\xb8\xfd\xa8\rw\x16(%\x89\x05k\xc7^-c\x10\x00\x00\u07d4\u03b0\x89\xec\x8ax3~\x8e\xf8\x8d\xe1\x1bI\xe3\u0751\x0ft\x8f\x8965\u026d\xc5\u07a0\x00\x00\u07d4\u03b3=x\xe7Tz\x9d\xa2\xe8}Q\xae\xc5\xf3D\x1c\x87\x92:\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\u03b3\x898\x1dH\xa8\xaeO\xfcH:\u043b^ L\xfd\xb1\xec\x89('\xe6\xe4\xddb\xba\x80\x00\u07d4\xce\xc6\xfce\x85?\x9c\xce_\x8e\x84Fv6.\x15y\x01_\x02\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xce\xd3\u01fe\x8d\xe7XQ@\x95*\xebP\x1d\xc1\xf8v\ucbf0\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xce\xd8\x1e\xc3S?\xf1\xbf\xeb\xf3\xe3\x84>\xe7@\xad\x11u\x8d>\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xce\u0733\xa1\u0584?\xb6\xbe\xf6Ca}\xea\U000cf398\xdd_\x89\x19\xe2\xa4\xc8\x18\xb9\x06\x00\x00\u07d4\xce\xe6\x99\xc0pzx6%+)/\x04|\xe8\xad(\x9b/U\x89\x11\x9a\x1e!\xaaiV\x00\x00\u07d4\xce\xedG\xca[\x89\x9f\xd1b?!\xe9\xbdM\xb6Z\x10\u5c1d\x89\a8w@L\x1e\xee\x00\x00\u07d4\xce\xf7tQ\u07e2\xc6C\xe0\v\x15mlo\xf8N#s\xebf\x89\n1\x06+\xee\xedp\x00\x00\u07d4\xcf\x11i\x04\x1c\x17E\xe4[\x17$5\xa2\xfc\x99\xb4\x9a\xce+\x00\x89\x01\xbb\x88\xba\xab-|\x00\x00\xe0\x94\xcf\x15v\x12vN\x0f\u0596\xc8\xcb_\xba\x85\xdfL\r\xdc<\xb0\x8a\x06ZM\xa2]0\x16\xc0\x00\x00\u0794\xcf\x1b\xdby\x9b.\xa6<\xe14f\x8b\xdc\x19\x8bT\x84\x0f\x18\v\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\xcf\"\x88\xefN\xbf\x88\xe8m\xb1=\x8a\x0e\v\xf5*\x05e\x82\u00c9\x89Po\xbf\x97@t\x00\x00\u07d4\xcf&Ni%\x13\t\x06\xc4\xd7\xc1\x85\x91\xaaA\xb2\xa6\u007foX\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xcf&\xb4{\xd04\xbcP\x8elK\xcf\xd6\xc7\xd3\x004\x92Wa\x89a\x94\x04\x9f0\xf7 \x00\x00\xe0\x94\xcf.*\xd65\xe9\x86\x1a\xe9\\\xb9\xba\xfc\xca\x03kR\x81\xf5\u038a\at2!~h6\x00\x00\x00\u07d4\xcf.s@B\xa3U\xd0_\xfb.9\x15\xb1h\x11\xf4Zi^\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xcf4\x8f/\xe4{~A<\az{\xaf:u\xfb\xf8B\x86\x92\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xcf?\x91(\xb0r\x03\xa3\xe1\r}WU\xc0\u012b\xc6\xe2\xca\u008a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\xcf?\xbf\xa1\xfd2\u05e6\xe0\xe6\xf8\xefN\xabW\xbe4\x02\\L\x899\xa1\xc0\xf7YMH\x00\x00\u07d4\xcfAftn\x1d;\xc1\xf8\xd0qK\x01\xf1~\x8ab\xdf\x14d\x896w\x03n\xdf\n\xf6\x00\x00\u07d4\xcfO\x118\xf1\xbdk\xf5\xb6\u0505\xcc\xe4\xc1\x01\u007f\u02c5\xf0}\x89/\u043cw\xc3+\xff\x00\x00\u07d4\xcfZo\x9d\xf7Uy\xc6D\xf7\x94q\x12\x15\xb3\rw\xa0\xce@\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xcf^\x0e\xac\u0473\x9d\x06U\xf2\xf7u5\xeff\b\xeb\x95\v\xa0\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xcfhM\xfb\x83\x04r\x93U\xb5\x83\x15\xe8\x01\x9b\x1a\xa2\xad\x1b\xac\x89\x17r$\xaa\x84Lr\x00\x00\u07d4\xcfi@\x81\xc7m\x18\xc6L\xa7\x13\x82\xbe\\\xd6;<\xb4v\xf8\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xcfnR\xe6\xb7t\x80\xb1\x86~\xfe\xc6Dm\x9f\xc3\xcc5w\xe8\x89\f\t\x01\xf6\xbd\x98y\x00\x00\u07d4\u03c8: 2\x96g\xea\"j\x1e\x9a\x92*\x12\xf2\x1f\xaa\x03\x81V\x91\x8cO\u02dc\x89\x04E\x91\xd6\u007f\xec\xc8\x00\x00\u07d4\xcf\xf7\xf8\x9aMB\x19\xa3\x82\x95%\x131V\x82\x10\xff\xc1\xc14\x89_h\xe8\x13\x1e\u03c0\x00\x00\u07d4\xcf\xf8\xd0k\x00\xe3\xf5\f\x19\x10\x99\xadV\xbaj\xe2eq\u0348\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xcf\xfcI\xc1x~\ubcb5l\xab\xe9$\x04\xb66\x14}EX\x8a\x013\xe00\x8f@\xa3\u0680\x00\u07d4\xd0\bQ;'`J\x89\xba\x17c\xb6\xf8L\u6233F\x94[\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xd0\x0f\x06r\x86\xc0\xfb\u0402\xf9\xf4\xa6\x10\x83\xecv\u07b3\xce\xe6\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xd0\x15\xf6\xfc\xb8M\xf7\xbbA\x0e\x8c\x8f\x04\x89J\x88\x1d\xca\xc27\x898E$\xccp\xb7x\x00\x00\u07d4\xd0\x1a\xf9\x13O\xafRW\x17N\x8by\x18oB\xee5Nd-\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xd0!\b\u04ae<\xab\x10\xcb\xcf\x16W\xaf\">\x02|\x82\x10\xf6\x89lm\x84\xbc\xcd\xd9\xce\x00\x00\u07d4\xd0*\xfe\u03ce.\u00b6*\u022d Aa\xfd\x1f\xaew\x1d\x0e\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd01\x919\xfb\xab.\x8e*\xcc\xc1\xd9$\u0531\x1d\xf6ilZ\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xd07\xd2\x15\xd1\x1d\x1d\xf3\xd5O\xbd2\x1c\u0495\xc5F^';\x89K\xe4\xe7&{j\xe0\x00\x00\u07d4\xd0:-\xa4\x1e\x86\x8e\xd3\xfe\xf5t[\x96\xf5\xec\xa4b\xffo\u0689\xa2\xa1]\tQ\x9b\xe0\x00\x00\xe0\x94\xd0?\xc1eWj\xae\xd5%\xe5P,\x8e\x14\x0f\x8b.\x86\x969\x8a\x01sV\u0633%\x01\xc8\x00\x00\u07d4\xd0C\xa0\x11\xecBp\xee~\u0239hsu\x15\xe5\x03\xf80(\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xd0K\x86\x1b=\x9a\xccV:\x90\x16\x89\x94\x1a\xb1\xe1\x86\x11a\xa2\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xd0ZD|\x91\x1d\xbb'[\xfb.Z7\xe5\xa7\x03\xa5o\x99\x97\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xd0_\xfb+t\xf8g O\xe51e;\x02H\xe2\x1c\x13TN\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xd0bX\x81q\u03d9\xbb\xebX\xf1&\xb8p\xf9\xa3r\x8da\xec\x89\xf3\xf2\v\x8d\xfai\xd0\x00\x00\u07d4\xd0c\x8e\xa5q\x89\xa6\xa6\x99\x02J\u05ccq\xd99\xc1\xc2\xff\x8c\x89\x8e\xaeVg\x10\xfc \x00\x00\xe0\x94\xd0d\x8aX\x1b5\b\xe15\xa2\x93]\x12\xc9epE\xd8q\u028a\x01\xb2\u07dd!\x9fW\x98\x00\x00\u07d4\xd0q\x19)f\xebi\xc3R\x0f\xca:\xa4\xdd\x04)~\xa0KN\x89\x05\xf6\x8e\x811\xec\xf8\x00\x00\u07d4\xd0q\x85 \xea\xe0\xa4\xd6-p\xde\x1b\xe0\xcaC\x1c^\xea$\x82\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd0w]\xba*\xf4\xc3\n:x6Y9\xcdq\xc2\xf9\u0795\u0489i*\xe8\x89p\x81\xd0\x00\x00\u07d4\xd0{\xe0\xf9\t\x97\xca\xf9\x03\u022c\x1dS\xcd\xe9\x04\xfb\x19\aA\x8968\x908\xb6\x99\xb4\x00\x00\u07d4\xd0~Q\x18d\xb1\u03d9i\xe3V\x06\x02\x82\x9e2\xfcNq\xf5\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\u07d4\u0400\x94\x98\xc5H\x04z\x1e**\xa6\xa2\x9c\xd6\x1a\x0e\xe2h\xbd\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u0402'_tZ,\xac\x02v\xfb\xdb\x02\u0532\xa3\xab\x17\x11\xfe\x89\x01\xa0Ui\r\x9d\xb8\x00\x00\u07d4\u040f\xc0\x9a\x000\xfd\t(\xcd2\x11\x98X\x01\x82\xa7j\xae\x9f\x8965\u026d\xc5\u07a0\x00\x00\u07d4\u0413\xe8)\x81\x9f\xd2\xe2[\x978\x00\xbb=XA\xdd\x15-\x05\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\u0414J\xa1\x85\xa13pa\xae \u071d\xd9l\x83\xb2\xbaF\x02\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\u0416V[|t\a\xd0e6X\x03U\xfd\xd6\xd29\x14J\xa1\x89\r\x8drkqw\xa8\x00\x00\u07d4\u041c\xb2\xe6\b-i:\x13\xe8\xd2\xf6\x8d\xd1\u0744a\xf5X@\x8965\u026d\xc5\u07a0\x00\x00\u07d4\u0426\xc6\xf9\xe9\u0133\x83\xd7\x16\xb3\x1d\xe7\x8dVAM\xe8\xfa\x91\x89\x10CV\x1a\x88)0\x00\x00\u07d4\u0427 \x9b\x80\xcf`\xdbb\xf5}\n]}R\x1ai`fU\x89\b\xacr0H\x9e\x80\x00\x00\xe0\x94\u0428\xab\xd8\n\x19\x9bT\xb0\x8be\xf0\x1d \x9c'\xfe\xf0\x11[\x8a\x01a\xc6&\xdca\xa2\xef\x80\x00\xe0\x94\u042b\xccp\xc0B\x0e\x0e\x17/\x97\xd4;\x87\xd5\xe8\f3n\xa9\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\u042es]\x91^\x94hf\xe1\xfe\xa7~^\xa4f\xb5\xca\xdd\x16\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u0431\x1do+\u0394^\fjP \u00f5'S\xf8\x03\xf9\u0449\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xd0\xc1\x01\xfd\x1f\x01\xc6?k\x1d\x19\xbc\x92\r\x9f\x93#\x14\xb16\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xd0\xc5Z\xbf\x97o\xdc=\xb2\xaf\u9f99\u0519HMWl\x02\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xd0\u0422\xadE\xf5\x9a\x9d\xcc\u0195\xd8_%\xcaF\xed1\xa5\xa3\x89-\x89W}}@ \x00\x00\u07d4\xd0\xd6,G\xea`\xfb\x90\xa3c\x92\t\xbb\xfd\xd4\xd93\x99\x1c\u0189\n\x84Jt$\xd9\xc8\x00\x00\u07d4\xd0\xdbEax o\\D0\xfe\x00Pc\x90<=zI\xa7\x89&I\x1eE\xa7S\xc0\x80\x00\u07d4\xd0\xe1\x94\xf3K\x1d\xb6\t(\x85\t\xcc\xd2\xe7;a1\xa2S\x8b\x8965f3\xeb\xd8\xea\x00\x00\u07d4\xd0\xe3^\x04vF\xe7Y\xf4Qp\x93\xd6@\x86BQ\u007f\bM\x89\u054f\xa4h\x18\xec\u02c0\x00\u07d4\xd0\xeeM\x02\xcf$8,0\x90\xd3\xe9\x95`\xde6xs\\\u07c9\x82\x1a\xb0\xd4AI\x80\x00\x00\u07d4\xd0\xf0OR\x10\x9a\xeb\xec\x9a{\x1e\x932v\x1e\x9f\xe2\xb9{\xb5\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xd0\xf9Yx\x11\xb0\xb9\x92\xbb}7W\xaa%\xb4\xc2V\x1d2\xe2\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xd1\x03\x02\xfa\xa1\x92\x9a2i\x04\xd3v\xbf\v\x8d\xc9:\xd0LL\x89a\t=|,m8\x00\x00\xe0\x94\xd1\x10\r\xd0\x0f\xe2\xdd\xf1\x81c\xad\x96M\vi\xf1\xf2\xe9e\x8a\x8a\x01C\x12\tU\xb2Pk\x00\x00\u07d4\xd1\x16\xf3\xdc\xd5\xdbtK\xd0\b\x88v\x87\xaa\x0e\xc9\xfdr\x92\xaa\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xd1\x19A|Fs,\xf3M\x1a\x1a\xfby\xc3\xe7\xe2\u034e\xec\xe4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd1-w\xae\x01\xa9-5\x11{\xacpZ\xac\u0642\xd0.t\xc1\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xd15yK\x14\x9a\x18\xe1G\xd1nb\x1ai1\xf0\xa4\n\x96\x9a\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94\xd1C%8\xe3[vd\x95j\u4563*\xbd\xf0A\xa7\xa2\x1c\x8a\x04+\xf0kx\xed;P\x00\x00\u07d4\xd1C\x82g#\x17\x04\xfcr\x80\xd5c\xad\xf4v8D\xa8\a\"\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xd1S\x8e\x9a\x87\u5729\xec\x8eX&\xa5\xb7\x93\xf9\x9f\x96\xc4\u00c965\u026d\xc5\u07a0\x00\x00\xe0\x94\xd1d\x85\x03\xb1\xcc\u0178\xbe\x03\xfa\x1e\xc4\xf3\xee&~j\xdf{\x8a\x01;\xef\xbfQ\xee\xc0\x90\x00\x00\xe0\x94\xd1h,!Y\x01\x8d\xc3\xd0\u007f\b$\n\x8c`m\xafe\xf8\xe1\x8a*Z\x05\x8f\u0095\xed\x00\x00\x00\u07d4\xd1q\xc3\xf2%\x8a\xef5\xe5\x99\xc7\xda\x1a\xa0s\x00#M\xa9\xa6\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd1w\x8c\x13\xfb\xd9h\xbc\b<\xb7\xd1\x02O\xfe\x1fI\xd0,\xaa\x89\xd9\xec\xb4\xfd \x8eP\x00\x00\u07d4\xd1\u007f\xbe\"\xd9\x04b\xed7(\x06p\xa2\xea\v0\x86\xa0\xd6\u0589\n\xd6\xee\xdd\x17\xcf;\x80\x00\u07d4\u0441\x1cU\x97i\x80\xf0\x83\x90\x1d\x8a\r\xb2i\"-\xfb\\\xfe\x89T\x06\x923\xbf\u007fx\x00\x00\u07d4\u044e\xb9\xe1\u0485\u06be\x93\xe5\u053a\xe7k\xee\xfeC\xb5!\xe8\x89$=M\x18\"\x9c\xa2\x00\x00\u07d4\u0453\xe5\x83\xd6\a\x05c\xe7\xb8b\xb9aJG\u9509\xf3\xe5\x8965f3\xeb\xd8\xea\x00\x00\u07d4\u0457\x8f.4@\u007f\xab\x1d\xc2\x18=\x95\xcf\xdab`\xb3Y\x82\x89*\xb7\xb2`\xff?\xd0\x00\x00\u07d4\u045c\xaf9\xbb7\u007f\xdf,\xf1\x9b\xd4\xfbRY\x1c&1\xa6<\x8965\u026d\xc5\u07a0\x00\x00\u0794\u0463\x96\xdc\u06b2\xc7IA0\xb3\xfd0x 4\r\xfd\x8c\x1f\x88\xf9\"P\xe2\xdf\xd0\x00\x00\xe0\x94\u0467\x1b-\bX\xe82p\b]\x95\xa3\xb1T\x96P\x03^#\x8a\x03'\xbb\t\xd0j\xa8P\x00\x00\u07d4\u046c\xb5\xad\xc1\x189s%\x8dk\x85$\xff\xa2\x8f\xfe\xb2=\xe3\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\u0473\u007f\x03\xcb\x10t$\xe9\xc4\xddW\\\xcdOL\xeeW\xe6\u0349lk\x93[\x8b\xbd@\x00\x00\u07d4\u0475\xa4T\xac4\x05\xbbAy \x8cl\x84\xde\x00k\u02db\xe9\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xd1\xc4YT\xa6+\x91\x1a\xd7\x01\xff.\x90\x13\x1e\x8c\xeb\x89\xc9\\\x89K\x91\xa2\xdeE~\x88\x00\x00\u07d4\xd1\xc9np\xf0Z\xe0\xe6\xcd`!\xb2\b7P\xa7q|\xdeV\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xd1\u0571\u007f\xfe-{\xbby\xcc}y0\xbc\xb2\xe5\x18\xfb\x1b\xbf\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xd1\xda\f\x8f\xb7\xc2\x10\xe0\xf2\xeca\x8f\x85\xbd\xae}>sK\x1c\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xd1\xddy\xfb\x15\x81`\xe5\xb4\xe8\xe2?1.j\x90\u007f\xbcMN\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xd1\xdeZ\xad:_\xd8\x03\U00071bb6\x10<\xb8\xe1O\xe7#\xb7\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xd1\xe1\xf2\xb9\xc1l0\x98t\xde\xe7\xfa\xc3&u\xaf\xf1)\u00d8\x89\x03\xf2M\x8eJ\x00p\x00\x00\xe0\x94\xd1\xe5\xe24\xa9\xf4Bf\xa4\xa6$\x1a\x84\u05e1\xa5Z\u0567\xfe\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xd1\xeaMr\xa6{[>\x0f1UY\xf5+\xd0aMq0i\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd1\xee\x90YW\xfe|\xc7\x0e\xc8\xf2\x86\x8bC\xfeG\xb1?\xeb\xff\x89\x02b\x9ff\xe0\xc50\x00\x00\u07d4\xd1\xf1iM\"g\x1bZ\xadj\x94\x99\\6\x9f\xbea3go\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xd1\xf4\xdc\x1d\u06ca\xbb\x88H\xa8\xb1N%\xf3\xb5Z\x85\x91\xc2f\x89\r\x8drkqw\xa8\x00\x00\u07d4\xd1\xfe\u042e\xe6\xf5\xdf\xd7\xe2Wi%L<\xfa\xd1Z\xde\u032a\x89'\x92\xc8\xfcKS(\x00\x00\u07d4\xd2\x05\x1c\xb3\xcbg\x04\xf0T\x8c\u0210\xab\n\x19\xdb4\x15\xb4*\x89\x12\x1b.^ddx\x00\x00\u07d4\xd2\x06\xaa\u07736\xd4^yr\xe9<\xb0uG\x1d\x15\x89{]\x89 \x86\xac5\x10R`\x00\x00\u07d4\xd2\tH+\xb5I\xab\xc4w{\xeam\u007fe\x00b\xc9\xc5z\x1c\x89\x11e\x1a\xc3\xe7\xa7X\x00\x00\u07d4\xd2\r\xcb\vxh+\x94\xbc0\x00(\x14H\xd5W\xa2\v\xfc\x83\x890\x84\x9e\xbe\x166\x9c\x00\x00\u07d4\xd2\x10{57&\u00e2\xb4ef\xea\xa7\xd9\xf8\v]!\xdb\xe3\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xd2\x11\xb2\x1f\x1b\x12\xb5\ta\x81Y\r\xe0~\xf8\x1a\x89S~\xad\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd2\x18\xef\xb4\u06d8\x1c\xddjy\u007fK\u050c|&)<\xeb@\x89\xa1Fk1\xc6C\x1c\x00\x00\xe0\x94\xd2\x1asA\xeb\x84\xfd\x15\x10T\xe5\u31fb%\xd3nI\x9c\t\x8a\x02\xf6\xf1\a\x80\xd2,\xc0\x00\x00\xe0\x94\xd2$\xf8\x80\xf9G\x9a\x89\xd3/\t\xe5+\u9432\x88\x13\\\xef\x8a\x03\xa9\u057a\xa4\xab\xf1\xd0\x00\x00\u07d4\xd2/\f\xa4\xcdG\x9ef\x17u\x05;\xccI\xe3\x90\xf6p\u074a\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xd21\x92\x975\x13!\x02G\x1b\xa5\x90\a\xb6dL\xc0\xc1\xde>\x8967\tlK\xcci\x00\x00\u07d4\xd25\xd1\\\xb5\xec\xee\xbba)\x9e\x0e\x82\u007f\xa8'H\x91\x1d\x89\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xd2:$\xd7\xf9F\x83C\xc1C\xa4\x1ds\xb8\x8f|\xbec\xbe^\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xd2=z\xff\xac\xdc>\x9f=\xaez\xfc\xb4\x00oX\xf8\xa4F\x00\x89\xc3(\t>a\xee@\x00\x00\u07d4\xd2C\x18L\x80\x1e]y\xd2\x06?5x\u06ee\x81\u7ce9\u02c9k\u0722h\x1e\x1a\xba\x00\x00\u07d4\xd2KfD\xf49\xc8\x05\x1d\xfcd\u04c1\xb8\xc8lu\xc1u8\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xd2K\xf1--\xdfE}\xec\xb1xt\xef\xde R\xb6\\\xbbI\x8a\x02\xf6\xf1\a\x80\xd2,\xc0\x00\x00\xe0\x94\xd2Q\xf9\x03\xae\x18rrY\xee\xe8A\xa1\x89\xa1\xf5i\xa5\xfdv\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xd2R\x96\v\v\xf6\xb2\x84\x8f\u07ad\x80\x13m\xb5\xf5\a\xf8\xbe\x02\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xd2X\x1aU\xce#\xab\x10\u062d\x8cD7\x8fY\a\x9b\xd6\xf6X\x8a\x01\xdd\f\x88_\x9a\r\x80\x00\x00\u07d4\xd2Z\xec\xd7\xeb\x8b\xd64[\x06;]\xbd'\x1cw\xd3QD\x94\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4\xd2|#O\xf7\xac\xca\xce=\x99g\b\xf8\xf9\xb0Ip\xf9}6\x89Hz\x9a0E9D\x00\x00\u07d4\u0482\x98RM\xf5\xecK$\xb0\xff\xb9\u07c5\x17\n\x14Z\x9e\xb5\x89\x0f\x98\xa3\xb9\xb37\xe2\x00\x00\xe0\x94\u0483\xb8\xed\xb1\n%R\x8aD\x04\xde\x1ce\xe7A\r\xbc\xaag\x8a\x02\x8a\x85t%Fo\x80\x00\x00\u07d4\u0484\xa5\x03\x82\xf8:am9\xb8\xa9\xc0\xf3\x96\xe0\ubfe9]\x8966\xc2^f\xec\xe7\x00\x00\u07d4\u0488\xe7\xcb{\xa9\xf6 \xab\x0ftR\xe5\bc=\x1cZ\xa2v\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\u049d\xc0\x8e\xfb\xb3\xd7.&?x\xabv\x10\xd0\"m\xe7k\x00\x8a\x02\x8a\x85t%Fo\x80\x00\x00\u07d4\u04a00\xac\x89R2_\x9e\x1d\xb3x\xa7\x14\x85\xa2N\x1b\a\xb2\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u04a4y@CG\xc5T:\xab)*\xe1\xbbJo\x15\x83W\xfa\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\u04a5\xa0$#\nW\xcc\xc6fv\v\x89\xb0\xe2l\xaf\u0449\u01ca\n\x96YZ\\n\x8a?\x80\x00\u07d4\u04a8\x03'\xcb\xe5\\L{\xd5\x1f\xf9\xdd\xe4\xcad\x8f\x9e\xb3\xf8\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\u07d4\u04a8Oug\\b\xd8\f\x88ulB\x8e\xee+\xcb\x18T!\x89A\rXj \xa4\xc0\x00\x00\u07d4\u04ab\xd8J\x18\x10\x93\xe5\xe2)\x13oB\xd85\xe8#]\xe1\t\x89\x05k\xe0<\xa3\xe4}\x80\x00\u07d4\u04ac\r:X`^\x1d\x0f\x0e\xb3\xde%\xb2\xca\xd1)\xed`X\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\u04bfg\xa7\xf3\xc6\xceV\xb7\xbeAg]\xbb\xad\xfe~\xa9:3\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xd2\xdb\xeb\xe8\x9b\x03W\xae\xa9\x8b\xbe\x8eIc8\u07bb(\xe8\x05\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xd2\xe2\x1e\xd5hh\xfa\xb2\x8e\tG\x92z\xda\xf2\x9f#\xeb\xadl\x89l\x18O\x13U\xd0\xe8\x00\x00\u07d4\xd2\xe8\x17s\x8a\xbf\x1f\xb4\x86X?\x80\xc3P1\x8b\xed\x86\f\x80\x89\r\x02\xce\xcf_]\x81\x00\x00\u07d4\xd2\xed\xd1\xdd\xd6\xd8m\xc0\x05\xba\xebT\x1d\"\xb6@\xd5\xc7\xca\xe5\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xd2\xf1\x99\x8e\x1c\xb1X\f\xecOl\x04}\xcd=\xce\xc5L\xf7<\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xd2\xf2A%]\xd7\xc3\xf7<\a\x040q\xec\b\xdd\xd9\xc5\xcd\xe5\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xd2\xffg \x16\xf6;/\x859\x8fJo\xed\xbb`\xa5\r<\u0389\x12\x91$o[sJ\x00\x00\u07d4\xd3\rLC\xad\xcfU\xb2\xcbS\u0583#&A4I\x8d\x89\u038965\u026d\xc5\u07a0\x00\x00\u07d4\xd3\x0e\xe9\xa1+Mh\xab\xac\xe6\xba\u029a\u05ff\\\xd1\xfa\xf9\x1c\x89QO\xcb$\xff\x9cP\x00\x00\u07d4\xd3\x11\x8e\xa3\xc85\x05\xa9\u0613\xbbg\xe2\xde\x14-Sz>\xe7\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xd3\x11\xbc\u05eaN\x9bO8?\xf3\xd0\u05b6\xe0~!\xe3p]\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xd3\x15\xde\xea\x1d\x8c\x12q\xf9\xd11\x12c\xabG\xc0\a\xaf\xb6\xf5\x89\x03\xc8\x1dNeK@\x00\x00\u07d4\xd3+,y\xc3dx\xc5C\x19\x01\xf6\xd7\x00\xb0M\xbe\x9b\x88\x10\x89\x15w\x9a\x9d\xe6\xee\xb0\x00\x00\u07d4\xd3+EVF\x14Ql\x91\xb0\u007f\xa9\xf7-\xcfx|\xceN\x1c\x89\x0f\xc6o\xae7F\xac\x00\x00\u07d4\xd30r\x811\xfe\x8e:\x15Hz4W<\x93E~*\xfe\x95\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xd31\xc8#\x82Z\x9eRc\xd0R\u0611]M\xcd\xe0z\\7\x89\x1e\x93\x12\x83\xcc\xc8P\x00\x00\u07d4\xd33btE\xf2\u05c7\x90\x1e\xf3;\xb2\xa8\xa3g^'\xff\xec\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xd3<\xf8+\xf1LY&@\xa0\x86\b\x91L#py\u057e4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd3Mp\x8ds\x98\x02E3\xa5\xa2\xb20\x9b\x19\xd3\xc5Qq\xbb\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xd3N\x03\xd3j+\xd4\u045a_\xa1b\x18\xd1\xd6\x1e?\xfa\v\x15\x89\x11X\xe4`\x91=\x00\x00\x00\u07d4\xd3Pu\xcaa\xfeY\xd1#\x96\x9c6\xa8-\x1a\xb2\xd9\x18\xaa8\x89\x90\xf54`\x8ar\x88\x00\x00\u07d4\xd3g\x00\x9a\xb6X&;b\xc23:\x1c\x9eA@I\x8e\x13\x89\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd3g\x9aG\xdf-\x99\xa4\x9b\x01\u024d\x1c>\f\x98|\xe1\xe1X\x89\x0f-\xc7\xd4\u007f\x15`\x00\x00\xe0\x94\u04cf\xa2\xc4\xcc\x14z\xd0j\u0562\xf7Uy(\x1f\"\xa7\xcc\x1f\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94\u04da]\xa4`9+\x94\v\u01ee8\xf1e\u007f\x8a\x01f\xc5H\b\x89\xdbw\x00\x00\xe0\x94\xd3\xd6\xe9\xfb\x82T/\u049e\xd9\xea6\t\x89\x1e\x15\x13\x96\xb6\xf7\x8a\voX\x8a\xa7\xbc\xf5\xc0\x00\x00\xe0\x94\xd3\xda\u0476\u040dE\x81\u032ee\xa8s-\xb6\xaci\xf0\u019e\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xd3\xdf;S\xcb;GU\xdeT\xe1\x80E\x1c\xc4L\x9e\x8a\u0a89#\u0114\t\xb9w\x82\x80\x00\u07d4\xd3\xf8s\xbd\x99V\x13W\x89\xab\x00\xeb\xc1\x95\xb9\"\xe9K%\x9d\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd4\x02\xb4\xf6\xa0\x99\xeb\xe7\x16\xcb\x14\xdfOy\xc0\xcd\x01\xc6\a\x1b\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xd4\r\x00U\xfd\x9a8H\x8a\xff\x92?\xd0=5\xecF\xd7\x11\xb3\x8a\x01\x0f\b\xed\xa8\xe5U\t\x80\x00\u07d4\xd4\x0e\xd6j\xb3\xce\xff$\xca\x05\xec\xd4q\ufd12\xc1__\xfa\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xd4\x18\x87\v\xc2\xe4\xfa{\x8aa!\xae\br\xd5RG\xb6%\x01\x89U\xa6\xe7\x9c\xcd\x1d0\x00\x00\u07d4\xd4\x1d\u007f\xb4\x9f\xe7\x01\xba\xac%qpBl\u0273\x8c\xa3\xa9\xb2\x89\t\x8a}\x9b\x83\x14\xc0\x00\x00\u07d4\xd4 U\x92\x84@U\xb3\u01e1\xf8\f\xef\xe3\xb8\xebP\x9b\xcd\xe7\x89\t\xb3\xbf\xd3B\xa9\xfc\x80\x00\u07d4\xd4+ \xbd\x03\x11`\x8bf\xf8\xa6\xd1[*\x95\xe6\xde'\u017f\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd44O}\\\xade\xd1~\\-\x0es#\x94=ob\xfe\x92\x89\x0e~\xeb\xa3A\vt\x00\x00\u07d4\xd4>\xe48\xd8=\xe9\xa3ub\xbbN(l\xb1\xbd\x19\xf4\x96M\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xd4C4\xb4\xe2:\x16\x9a\f\x16\xbd!\xe8f\xbb\xa5-\x97\x05\x87\x89\x8c\xf2?\x90\x9c\x0f\xa0\x00\x00\xe0\x94\xd4M\x81\xe1\x8fF\xe2\u03f5\xc1\xfc\xf5\x04\x1b\xc8V\x97g\xd1\x00\x8a\a\xb4B\xe6\x84\xf6Z\xa4\x00\x00\u07d4\xd4OJ\xc5\xfa\xd7k\xdc\x157\xa3\xb3\xafdr1\x9bA\r\x9d\x89V\xbcu\xe2\xd61\x00\x00\x00\u07d4\xd4O^\xdf+\xcf$3\xf2\x11\xda\xdd\f\xc4P\xdb\x1b\x00\x8e\x14\x89\x0e~\xeb\xa3A\vt\x00\x00\xe0\x94\xd4Oj\u00d2;_\xd71\xa4\xc4YD\xecO~\xc5*j\xe4\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xd4[3A\xe8\xf1\\\x802\x93 \u00d7~;\x90\xe7\x82j~\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xd4]]\xaa\x13\x8d\xd1\xd3t\xc7\x1b\x90\x19\x91h\x11\xf4\xb2\nN\x89\x1f9\x9b\x148\xa1\x00\x00\x00\u07d4\xd4`\xa4\xb9\b\xdd+\x05gY\xb4\x88\x85\vf\xa88\xfcw\xa8\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xd4g\xcf\x06L\bq\x98\x9b\x90\u0632\xeb\x14\xcc\xc6;6\b#\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xd4k\xaea\xb0'\xe5\xbbB.\x83\xa3\xf9\xc9?<\x8f\xc7}'\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd4o\x82#E)\x82\xa1\xee\xa0\x19\xa8\x81n\xfc-o\xc0\ah\x89\amA\xc6$\x94\x84\x00\x00\u07d4\xd4uG\u007f\xa5c\x90\xd30\x17Q\x8dg\x11\x02\u007f\x05\U0008dfc9k\x11\x133\xd4\xfdL\x00\x00\u07d4\xd4|$.\xdf\xfe\xa0\x91\xbcT\xd5}\xf5\xd1\xfd\xb91\x01Gl\x89\x9d\xf7\u07e8\xf7`H\x00\x00\u07d4\xd4}\x86\x85\xfa\xee\x14|R\x0f\u0646p\x91u\xbf/\x88k\xef\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd4\u007fP\u07c9\xa1\xcf\xf9e\x13\xbe\xf1\xb2\xae:)q\xac\xcf,\x89-\x89W}}@ \x00\x00\u07d4\u0502\xe7\xf6\x8eA\xf28\xfeQx)\xde\x15G\u007f\xe0\xf6\xdd\x1d\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\u0507\x9f\xd1+\x1f:'\xf7\xe1\tv\x1b#\xca4\xfa#\x06K\x1c\xaf\x00Qn(pJ\x82\xa4\xf8\x89Hz\x9a0E9D\x00\x00\u07d4\xd5\x00\xe4\xd1\u0242K\xa9\xf5\xb65\u03e3\xa8\xc2\u00cb\xbdL\xed\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xd5\b\u04dcp\x91oj\xbcL\xc7\xf9\x99\xf0\x11\xf0w\x10X\x02\x89\x05rM$\xaf\xe7\u007f\x00\x00\u07d4\xd5\x0f\u007f\xa0>8\x98v\u04d0\x8b`\xa57\xa6pc\x04\xfbV\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xd5\x13\xa4P\x80\xff/\xeb\xe6,\u0545J\xbe)\xeeDg\xf9\x96\x89\bN\x13\xbcO\xc5\xd8\x00\x00\u07d4\xd5'o\f\xd5\xff\xd5\xff\xb6?\x98\xb5p=U\x94\xed\xe0\x83\x8b\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xd5)KfbB0;m\xf0\xb1\u020d7B\x9b\xc8\xc9e\xaa\x89\x10M\r\x00\u04b7\xf6\x00\x00\u07d4\xd5*\xec\xc6I98\xa2\x8c\xa1\xc3g\xb7\x01\xc2\x15\x98\xb6\xa0.\x89;\xa1\x91\v\xf3A\xb0\x00\x00\u07d4\xd5\x99x\xee \xa3\x8c?I\x8dc\xd5\u007f1\xa3\x9fj\x06\x8a\x022\xb3o\xfcg*\xb0\x00\x00\u07d4\u05568\xd3\xc5\xfa\xa7q\x1b\xf0\x85t_\x9d[\xdc#\u0518\u0609lk\x93[\x8b\xbd@\x00\x00\xe0\x94\u055d\x92\xd2\xc8p\x19\x80\xcc\a<7]r\n\xf0dt<\f\x8a\x04\x05\xfd\xf7\u5bc5\xe0\x00\x00\u07d4\u0567\xbe\xc32\xad\xde\x18\xb3\x10KW\x92Tj\xa5\x9b\x87\x9bR\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u0571\x17\xec\x11n\xb8FA\x89a\xeb~\xdbb\x9c\xd0\xddi\u007f\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\u0572\x84\x04\x010\xab\xf7\xc1\xd1cq#q\xcc~(\xadf\u0689j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\u0579\xd2w\u062a\xd2\x06\x97\xa5\x1fv\xe2\tx\x99k\xff\xe0U\x89\a\xc3\xfe<\aj\xb5\x00\x00\u07d4\u057d^\x84U\xc10\x16\x93W\xc4q\xe3\u6077\x99jrv\x89-\x9e(\x8f\x8a\xbb6\x00\x00\u07d4\xd5\u02e5\xb2k\xea]s\xfa\xbb\x1a\xba\xfa\xcd\xef\x85\xde\xf3h\u0309\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xd5\xceU\u0476/YC\xc0?\x89\b\xe3\x1f\xe1h\x9d\x8a\x00\x00\u07d4\xd6\x06Q\xe3\x93x4#\xe5\xcc\x1b\xc5\xf8\x89\xe4N\xf7\xea$>\x89\x15\x9ev7\x11)\xc8\x00\x00\u07d4\xd6\t\xbfO\x14n\xeak\r\xc8\xe0m\xdc\xf4D\x8a\x1f\xcc\xc9\xfa\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd6\t\xec\v\xe7\r\n\xd2ong\xc9\xd4v+R\xeeQ\x12,\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xd6\nRX\a(R\r\xf7Tk\xc1\xe2\x83)\x17\x88\u06ee\f\x8964\x89\xef?\xf0\xd7\x00\x00\u07d4\xd6\v$s!\xa3*Z\xff\xb9k\x1e'\x99'\xccXM\xe9C\x89z\xd0 \xd6\xdd\xd7v\x00\x00\u07d4\xd6\x11\x02v\xcf\xe3\x1eB\x82ZW\u007fkC]\xbc\xc1\f\xf7d\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xd6\x12Y{\xc3\x17C\u01c63\xf63\xf29\xb1\xe9Bk\xd9%\x8a\x10\x17\xf7\u07d6\xbe\x17\x80\x00\x00\u07d4\xd6#J\xafE\xc6\xf2.f\xa2%\xff\xb9:\xddb\x9bN\xf8\x0f\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xd6.\u06d6\xfc\u259a\xaflT^\x96|\xf1\xc0\xbc\x80R\x05\x89\x04\xa5eSjZ\u0680\x00\u07d4\xd60\v2\x15\xb1\x1d\xe7b\xec\xdeKp\xb7\x92}\x01)\x15\x82\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd69]\xb5\xa4\xbbf\xe6\x0fL\xfb\xcd\xf0\x05{\xb4\xd9xb\xe2\x891T\xc9r\x9d\x05x\x00\x00\xe0\x94\xd6J-P\xf8\x85\x857\x18\x8a$\xe0\xf5\r\xf1h\x1a\xb0~\u05ca\b7Z*\xbc\xca$@\x00\x00\u07d4\xd6X\n\xb5\xedL}\xfaPo\xa6\xfed\xad\\\xe1)pw2\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xd6Y\x8b\x13\x86\xe9<\\\u02d6\x02\xffK\xbb\xec\xdb\xd3p\x1d\u0109\f%\xf4\xec\xb0A\xf0\x00\x00\u07d4\xd6dM@\xe9\v\xc9\u007f\xe7\xdf\xe7\u02bd2i\xfdW\x9b\xa4\xb3\x89\b\x9e\x91y\x94\xf7\x1c\x00\x00\xe0\x94\xd6g\f\x03m\xf7T\xbeC\xda\u074fP\xfe\xea(\x9d\x06\x1f\u058a\x01D\xa2\x904H\xce\xf7\x80\x00\u07d4\xd6hR:\x90\xf0)=e\xc58\xd2\xddlWg7\x10\x19n\x89\x02$,0\xb8S\xee\x00\x00\u07d4\xd6j\xb7\x92\x94\aL\x8bb}\x84-\xabA\xe1}\xd7\f]\xe5\x8965\u026d\xc5\u07a0\x00\x00\u0794\xd6j\xcc\r\x11\xb6\x89\u03a6\xd9\xea_\xf4\x01L\"J]\xc7\u0108\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\xd6m\xdf\x11Y\xcf\"\xfd\x8czK\xc8\u0540wV\xd43\xc4>\x89wC\"\x17\xe6\x83`\x00\x00\u07d4\u0587\xce\xc0\x05\x90\x87\xfd\xc7\x13\xd4\xd2\xd6^w\xda\xef\xed\xc1_\x89\x03@\xaa\xd2\x1b;p\x00\x00\u07d4\u0588\xe7\x85\u024f\x00\xf8K:\xa1S3U\u01e2X\xe8yH\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\u05a2.Y\x8d\xab\u04ce\xa6\xe9X\xbdy\u050d\u0756\x04\xf4\u07c965\u026d\xc5\u07a0\x00\x00\u07d4\u05a7\xacM\xe7\xb5\x10\xf0\xe8\xdeQ\x9d\x97?\xa4\xc0\x1b\xa84\x00\x89e\xea=\xb7UF`\x00\x00\u07d4\u05ac\xc2 \xba.Q\xdf\xcf!\xd4C6\x1e\xeav\\\xbd5\u0609\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\u05ac\xff\u043f\u065c8.{\xd5o\xf0\xe6\x14J\x9eR\xb0\x8e\x89\b\xacr0H\x9e\x80\x00\x00\u07d4\xd6\xc0\u043c\x93\xa6.%qtp\x0e\x10\xf0$\u0232?\x1f\x87\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xd6\xcf\\\x1b\u03dd\xa6b\xbc\xea\"U\x90P\x99\xf9\xd6\xe8M\u030a\x01\u011eB\x01W\xd9\xc2\x00\x00\u07d4\xd6\xd05r\xa4RE\xdb\xd46\x8cO\x82\xc9W\x14\xbd!g\xe2\x89?\x00\xc3\xd6f\x86\xfc\x00\x00\u07d4\xd6\xd6wiX\xee#\x14:\x81\xad\xad\xeb\b8 \t\xe9\x96\u0089\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xd6\xd9\xe3\x0f\bB\x01*qv\xa9\x17\xd9\xd2\x04\x8c\xa0s\x87Y\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xd6\xe0\x9e\x98\xfe\x13\x003!\x04\xc1\xca4\xfb\xfa\xc5T6N\u0649lk\x93[\x8b\xbd@\x00\x00\u07d4\xd6\xe8\xe9z\u90db\x9e\xe5\a\xee\xdb(\xed\xfbtw\x03\x149\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd6\uea18\u052e+q\x80'\xa1\x9c\xe9\xa5\xebs\x00\xab\xe3\u0289\x01}J\xce\xeec\u06c0\x00\xe0\x94\xd6\xf1\xe5[\x16\x94\b\x9e\xbc\xb4\xfe}x\x82\xaaf\u0217av\x8a\x04<#\xbd\xbe\x92\x9d\xb3\x00\x00\u07d4\xd6\xf4\xa7\xd0N\x8f\xaf \xe8\xc6\ub15c\xf7\xf7\x8d\xd2=z\x15\x89\a$\xde\xd1\xc7H\x14\x00\x00\u07d4\xd6\xfc\x04F\u01a8\xd4\n\xe3U\x1d\xb7\xe7\x01\xd1\xfa\x87nJI\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd7\x03\u01a4\xf1\x1d`\x19Ey\u054c'f\xa7\xef\x16\xc3\n)\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd7\x05%\x19uj\xf4%\x90\xf1S\x91\xb7#\xa0?\xa5d\xa9Q\x89\xfa61H\r\x01\xfd\x80\x00\u07d4\xd7\na+\xd6\u0769\xea\xb0\xdd\xdc\xffJ\xafA\"\u04cf\xea\xe4\x89\x1dF\x01b\xf5\x16\xf0\x00\x00\u07d4\xd7\n\xd2\xc4\xe9\uefe67\xefV\xbdHj\u04a1\xe5\xbc\xe0\x93\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xd7\x14\f\x8eZC\a\xfa\xb0\xcc'\xba\u0752\x95\x01\x8b\xf8yp\x89\x05\xf1\x01kPv\xd0\x00\x00\u07d4\xd7\x16J\xa2a\xc0\x9a\u0672\xb5\x06\x8dE>\xd8\xebj\xa10\x83\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xd7\x1eC\xa4Qw\xadQ\xcb\xe0\xf7!\x84\xa5\xcbP9\x17(Z\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xd7\x1f\xb10\xf0\x15\fVRi\xe0\x0e\xfbC\x90+R\xa4U\xa6\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xd7\"W8\xdc\xf3W\x848\xf8\xe7\u0233\x83~B\xe0J&/\x89\x18+\x8c\ubec3\xaa\x00\x00\u07d4\xd7'MP\x80M\x9cw\u0693\xfaH\x01V\xef\xe5{\xa5\x01\u0789i*\xe8\x89p\x81\xd0\x00\x00\u07d4\xd71\xbbk_<79^\t\u03ac\xcd\x14\xa9\x18\xa6\x06\a\x89\x89\u0556{\xe4\xfc?\x10\x00\x00\xe0\x94\xd7>\xd2\u0645\xb5\xf2\x1bU\xb2td;\xc6\xda\x03\x1d\x8e\u074d\x8a\nm\xd9\f\xaeQ\x14H\x00\x00\u07d4\xd7D\xac~S\x10\xbeijc\xb0\x03\xc4\v\xd097\x05a\u0189Z\x87\xe7\xd7\xf5\xf6X\x00\x00\xe0\x94\xd7Jn\x8dj\xab4\u0385\x97h\x14\xc12{\xd6\xea\a\x84\u048a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\xd7ZP*[gr\x87G\x0fe\u016aQ\xb8|\x10\x15\x05r\x8910\xb4dc\x85t\x00\x00\u07d4\xd7m\xba\xeb\xc3\rN\xf6{\x03\xe6\xe6\xec\xc6\xd8N\x00MP-\x89mv\xb9\x18\x8e\x13\x85\x00\x00\u07d4\xd7q\xd9\xe0\u028a\b\xa1\x13wW1CN\xb3'\x05\x99\xc4\r\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xd7x\x8e\xf2\x86X\xaa\x06\xccS\xe1\xf3\xf0\xdeX\xe5\xc3q\xbex\x8a\x01je\x02\xf1Z\x1eT\x00\x00\u07d4\xd7x\x92\xe2';#]v\x89\xe40\xe7\xae\ud73c\xe8\xa1\xf3\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u05c1\xf7\xfc\t\x18F\x11V\x85p\xb4\x98n,r\x87+~\u0409\x01\x15\x95a\x06]]\x00\x00\u07d4\u05c5\xa8\xf1\x8c8\xb9\xbcO\xfb\x9b\x8f\xa8\xc7r{\xd6B\xee\x1c\x8965\u026d\xc5\u07a0\x00\x00\u07d4\u05ce\xcd%\xad\xc8k\xc2\x05\x1d\x96\xf6Sd\x86kB\xa4&\xb7\x89\xd20X\xbf/&\x12\x00\x00\xe0\x94\u05cf\x84\xe3\x89D\xa0\xe0%_\xae\xceH\xbaIP\u053d9\u048a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\u05d4\x83\xf6\xa8DO%I\xd6\x11\xaf\xe0,C-\x15\xe1\x10Q\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\u05d85\xe4\x04\xfb\x86\xbf\x84_\xba\t\rk\xa2^\f\x88f\xa6\x89\x82\x1a\xb0\xd4AI\x80\x00\x00\u07d4\u05da\xff\x13\xba-\xa7]F$\f\xac\n$g\xc6V\x94\x98#\x89]\u0212\xaa\x111\xc8\x00\x00\u07d4\u05dd\xb5\xabCb\x1az=\xa7\x95\xe5\x89)\xf3\xdd%\xafg\u0649lj\xccg\u05f1\xd4\x00\x00\u07d4\u05e1C\x1e\xe4S\xd1\xe4\x9a\x05P\xd1%hy\xb4\xf5\xd1\x02\x01\x89Z\x87\xe7\xd7\xf5\xf6X\x00\x00\u07d4\u05ed\t\xc6\xd3&WhSU\xb5\xc6\uc39fW\xb4\ube42\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\u05f7@\xdf\xf8\xc4Wf\x8f\xdft\xf6\xa2f\xbf\xc1\u0737#\xf9\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xd7\u0080>\u05f0\xe0\x83sQA\x1a\x8ef7\xd1h\xbc[\x05\x8a\x06A\xda\xf5\xc9\x1b\xd95\x80\x00\u07d4\xd7\xc6&]\xea\x11\x87l\x90;q\x8eL\u062b$\xfe&[\u0789lk\x93[\x8b\xbd@\x00\x00\u07d4\xd7\xca\u007f\xdc\xfe\xbeE\x88\xef\xf5B\x1d\x15\"\xb6\x13(\xdf{\xf3\x89\xd8\xe6\x00\x1el0+\x00\x00\u07d4\xd7\u037dA\xff\xf2\r\xf7'\xc7\vbU\xc1\xbav\x06\x05Th\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xd7\xd1W\xe4\xc0\xa9d7\xa6\u0485t\x1d\xd2>\xc46\x1f\xa3k\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd7\xd2\xc6\xfc\xa8\xad\x1fu9R\x10\xb5}\xe5\xdf\xd6s\x939\t\x89\x12nr\xa6\x9aP\xd0\x00\x00\xe0\x94\xd7\xd3\xc7Y Y\x048\xb8,>\x95\x15\xbe.\xb6\xedz\x8b\x1a\x8a\f\xb4\x9bD\xba`-\x80\x00\x00\u07d4\xd7\xd7\xf2\u02a4b\xa4\x1b;0\xa3J\xeb;\xa6\x10\x10\xe2bo\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd7\xe7J\xfd\xba\xd5^\x96\u03bcZ7O,\x8bv\x86\x80\xf2\xb0\x89\x05]\xe6\xa7y\xbb\xac\x00\x00\xe0\x94\xd7\xeb\x901b'\x1c\x1a\xfa5\xfei\xe3s\"\u0224\u049b\x11\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xd7\xeb\u0779\xf99\x87w\x9bh\x01U7T8\xdbe\xaf\xcbj\x89\x05t\x1a\xfe\xff\x94L\x00\x00\u07d4\xd7\xef4\x0ef\xb0\u05ef\xcc\xe2\n\x19\xcb{\xfc\x81\xda3\xd9N\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xd7\xf3p\u053e\xd9\xd5|oI\u0259\xder\x9e\xe5i\xd3\xf4\xe4\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xd7\xfa_\xfb`H\xf9o\xb1\xab\xa0\x9e\xf8{\x1c\x11\xddp\x05\xe4\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xd8\x06\x9f\x84\xb5!I?G\x15\x03\u007f2&\xb2_3\xb6\x05\x86\x89g\x8a\x93 b\xe4\x18\x00\x00\u0794\xd8\x15\xe1\xd9\xf4\xe2\xb5\xe5~4\x82k|\xfd\x88\x81\xb8Th\x90\x88\xf0\x15\xf2W6B\x00\x00\u07d4\xd8\x1b\xd5K\xa2\xc4Jok\xeb\x15a\u058b\x80\xb5DNm\u0189?\x17\r~\xe4\"\xf8\x9c\x80-1({\x96q\xe8\x1c\x88\xb9\x8b\xc8)\xa6\xf9\x00\x00\u07d4\xd8K\x92/xA\xfcWt\xf0\x0e\x14`J\xe0\xdfB\xc8U\x1e\x89\xd9o\u0390\u03eb\xcc\x00\x00\u07d4\xd8U\xb0<\xcb\x02\x9awG\xb1\xf0s\x03\xe0\xa6dy59\u0209lk\x93[\x8b\xbd@\x00\x00\u07d4\xd8_\u07af*a\xf9]\xb9\x02\xf9\xb5\xa5<\x9b\x8f\x92f\u00ec\x89l\xf6Z~\x90G(\x00\x00\u07d4\xd8q^\xf9\x17o\x85\v.0\xeb\x8e8'\a\xf7w\xa6\xfb\xe9\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd8t\xb9\u07eeEj\x92\x9b\xa3\xb1\xa2~W,\x9b,\xec\u07f3\x89\t79SM(h\x00\x00\u07d4\u0613\n9\xc7sW\xc3\n\u04e0`\xf0\v\x06\x04c1\xfdb\x89,s\xc97t,P\x00\x00\u07d4\u061b\xc2q\xb2{\xa3\xabib\xc9JU\x90\x06\xae8\xd5\xf5j\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u0637}\xb9\xb8\x1b\xbe\x90B{b\xf7\x02\xb2\x01\xff\u009f\xf6\x18\x892m\x1eC\x96\xd4\\\x00\x00\u07d4\xd8\xcdd\xe0(N\xecS\xaaF9\xaf\xc4u\b\x10\xb9\u007f\xabV\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xd8\xd6C\x84$\x9bwg\x94\x06;V\x98x\xd5\xe3\xb50\xa4\xb2\x89\t\xa0C\u0432\xf9V\x80\x00\u07d4\xd8\xd6T \xc1\x8c#'\xccZ\xf9t%\xf8W\xe4\xa9\xfdQ\xb3\x89_h\xe8\x13\x1e\u03c0\x00\x00\u07d4\xd8\xe5\xc9g^\xf4\xde\xed&k\x86\x95o\xc4Y\x0e\xa7\u0522}\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xd8\xe8GB\x92\xe7\xa0Q`L\xa1d\xc0pw\x83\xbb(\x85\xe8\x8a\x02\xd4\xca\x05\xe2\xb4<\xa8\x00\x00\u07d4\xd8\xebxP>\xc3\x1aT\xa9\x016x\x1a\xe1\t\x00Lt2W\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xd8\xee\xf4\xcfK\xeb\x01\xee \xd1\x11t\x8ba\xcbM?d\x1a\x01\x89\x94\x89#z\u06daP\x00\x00\u07d4\xd8\xf4\xba\xe6\xf8M\x91\rm}Z\xc9\x14\xb1\xe6\x83r\xf9A5\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xd8\xf6 6\xf0;v5\xb8X\xf1\x10?\x8a\x1d\x90\x19\xa8\x92\xb6\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\u07d4\xd8\xf6e\xfd\x8c\xd5\u00bc\xc6\xdd\xc0\xa8\xaeR\x1eM\u01aa``\x89\\(=A\x03\x94\x10\x00\x00\u07d4\xd8\xf9$\fU\xcf\xf05RB\x80\xc0\x9e\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xd8\xfe\b\x8f\xff\u0394\x8fQ7\xee#\xb0\x1d\x95\x9e\x84\xacB#\x89\f[T\xa9O\xc0\x17\x00\x00\u07d4\xd9\x0f0\t\xdbC~N\x11\u01c0\xbe\u0209os\x8de\xef\r\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xd9\x10;\xb6\xb6zU\xa7\xfe\xce-\x1a\xf6-E|!x\x94m\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xd9\x13\xf0w\x19Iu\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xd9D\u0226\x9f\xf2\xca\x12Ii\f\x12)\xc7\x19/6%\x10b\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xd9JW\x88*Rs\x9b\xbe*\x06G\xc8\f$\xf5\x8a+O\x1c\x89H\xb5N*\xdb\xe1+\x00\x00\xe0\x94\xd9SB\x95<\x8a!\xe8\xb65\xee\xfa\u01c1\x9b\xea0\xf1pG\x8a\x13\xf0l\u007f\xfe\xf0]@\x00\x00\u07d4\xd9\\\x90\xff\xbeT\x84\x86G\x80\xb8gIJ\x83\u0212V\xd6\xe4\x89X\xe7\x92n\xe8X\xa0\x00\x00\u07d4\xd9g\x11T\x0e.\x99\x83C\xd4\xf5\x90\xb6\xfc\x8f\xac;\xb8\xb3\x1d\x89_Z@h\xb7\x1c\xb0\x00\x00\u07d4\xd9j\xc2Pt\t\u01e3\x83\xab.\xee\x18\"\xa5\xd78\xb3kV\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xd9m\xb3;{Z\x95\f>\xfa-\xc3\x1b\x10\xba\x10\xa52\uf1c9lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xd9wYe\xb7\x16Gfu\xa8\xd5\x13\xeb\x14\xbb\xf7\xb0|\xd1J\x8a\x01\x13.m-#\xc5\xe4\x00\x00\u07d4\xd9{\xc8J\xbdG\xc0[\xbfE{.\xf6Y\xd6\x1c\xa5\xe5\u43c9\x06\x9d\x17\x11\x9d\u0168\x00\x00\u07d4\xd9\u007fE&\u07a9\xb1c\xf8\xe8\xe3:k\u03d2\xfb\x90}\xe6\xec\x89\x0feJ\xafM\xb2\xf0\x00\x00\u07d4\xd9\u007f\xe6\xf5?*X\xf6\xd7mu*\xdft\xa8\xa2\xc1\x8e\x90t\x89\x10\xcd\xf9\xb6\x9aCW\x00\x00\u07d4\u0659\x99\xa2I\r\x94\x94\xa50\xca\xe4\xda\xf3\x85T\xf4\xddc>\x89\x06\x81U\xa46v\xe0\x00\x00\u07d4\u065d\xf7B\x1b\x93\x82\xe4,\x89\xb0\x06\xc7\xf0\x87p*\aW\xc0\x89\x1a\x05V\x90\xd9\u06c0\x00\x00\xe0\x94\u0677\x83\xd3\x1d2\xad\xc5\x0f\xa3\xea\u02a1]\x92\xb5h\xea\xebG\x8a\a3\xaf\x907L\x1b(\x00\x00\u07d4\xd9\xd3p\xfe\xc65v\xab\x15\xb3\x18\xbf\x9eX6M\u00a3U*\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94\xd9\xd4/\xd1>\xbdK\xf6\x9c\xac^\x9c~\x82H:\xb4m\xd7\xe9\x8a\x01!\xeah\xc1\x14\xe5\x10\x00\x00\u07d4\xd9\xe2~\xb0}\xfcq\xa7\x06\x06\f\u007f\a\x928\u0293\xe8\x859\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xd9\xe3\x85~\xfd\x1e *D\x17p\xa7w\xa4\x9d\xccE\xe2\xe0\u04c9\f\x1d\xaf\x81\u0623\xce\x00\x00\u07d4\xd9\xec.\xfe\x99\xff\\\xf0\r\x03\xa81{\x92\xa2J\xefD\x1f~\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd9\xec\x8f\xe6\x9bw\x16\xc0\x86Z\xf8\x88\xa1\x1b+\x12\xf7 \xed3\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xd9\xf1\xb2d\b\xf0\xecg\xad\x1d\ro\xe2.\x85\x15\xe1t\x06$\x89\x01M\x11 \u05f1`\x00\x00\u07d4\xd9\xf5G\xf2\xc1\xde\x0e\u064aS\xd1a\xdfWc]\xd2\x1a\x00\xbd\x89\x05V\xf6L\x1f\xe7\xfa\x00\x00\u07d4\xd9\xff\x11]\x01&l\x9fs\xb0c\xc1\xc28\xef5e\xe6;6\x89$\xdc\xe5M4\xa1\xa0\x00\x00\u07d4\xda\x06\x04N)#&\xffil\x0091h\xceF\xff\xac9\xec\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xda*\x14\xf9r@\x15\u05d0\x14\xed\x8eY\th\x1dYaH\xf1\x89\x02\xa1\x0f\x0f\x8a\x91\xab\x80\x00\u07d4\xda*\u054ew\xde\xdd\xed\xe2\x18vF\xc4e\x94Z\x8d\xc3\xf6A\x89#\xc7W\a+\x8d\xd0\x00\x00\u07d4\xda0\x17\xc1P\xdd\r\xce\u007f\u03c8\x1b\nH\xd0\xd1\xc7V\xc4\u01c9\x05k\xf9\x1b\x1ae\xeb\x00\x00\u07d4\xda4\xb2\xea\xe3\v\xaf\xe8\xda\xec\xcd\xe8\x19\xa7\x94\u0349\xe0\x95I\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xdaJ_U\u007f;\xab9\n\x92\xf4\x9b\x9b\x90\n\xf3\fF\xae\x80\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xdaPU7S\u007f\xfb3\xc4\x15\xfe\xc6Ni\xba\xe0\x90\xc5\xf6\x0f\x89\b\xacr0H\x9e\x80\x00\x00\u07d4\xdai\x8dd\xc6\\\u007f+,rS\x05\x9c\xd3\u0441\u0619\xb6\xb7\x89\x10\x04\xe2\xe4_\xb7\xee\x00\x00\u07d4\xdaw2\xf0/.'.\xaf(\u07d7.\xcc\r\xde\xed\x9c\xf4\x98\x89\v \xbf\xbfig\x89\x00\x00\u07d4\xdaz\xd0%\xeb\xde%\xd2\"C\u02c3\x0e\xa1\xd3\xf6JVc#\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94\u0685]SG\u007fP^\xc4\xc8\xd5\u8ed1\x80\u04c6\x81\x11\x9c\x8a\x01/\x93\x9c\x99\xed\xab\x80\x00\x00\u07d4\u0687^N/<\xab\xe4\xf3~\x0e\xae\xd7\xd1\xf6\xdc\xc6\xff\xefC\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u068b\xbe\xe1\x82\xe4U\xd2\t\x8a\xcb3\x8amE\xb4\xb1~\u0636\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u0698.\x96C\xff\xec\xe7#\aZ@\xfewnZ\xce\x04\xb2\x9b\x89\b\xb8\xb6\u0259\x9b\xf2\x00\x00\u07d4\u069fUF\tF\u05ff\xb5p\xdd\xecu|\xa5w;XB\x9a\x89\x1b\x84]v\x9e\xb4H\x00\x00\u07d4\u06a1\xbdz\x91H\xfb\x86\\\xd6\x12\xdd5\xf1b\x86\x1d\x0f;\u0709\xa68\xabr\xd9,\x13\x80\x00\xe0\x94\u06a6<\xbd\xa4]\u0507\xa3\xf1\xcdJtj\x01\xbb^\x06\v\x90\x8a\x01\x04\x16\u0670*\x89$\x00\x00\u07d4\u06a7v\xa6uDi\u05f9&z\x89\xb8g%\xe7@\xda\x0f\xa0\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\u06ac\x91\xc1\xe8Y\xd5\xe5~\xd3\bKP \x0f\x97f\xe2\xc5+\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\u06ac\xda\xf4\"&\xd1\\\xb1\u03d8\xfa\x15\x04\x8c\u007fL\xee\xfei\x89\x10CV\x1a\x88)0\x00\x00\xe0\x94\u06b6\xbc\u06c3\xcf$\xa0\xae\x1c\xb2\x1b;[\x83\xc2\xf3\x82I'\x8a\n\x96\x81c\xf0\xa5{@\x00\x00\u07d4\u06bb\b\x89\xfc\x04)&\xb0^\xf5{% \x91\n\xbcKAI\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u06bc\"PB\xa6Y,\xfa\x13\xeb\xe5N\xfaA\x04\bx\xa5\xa2\x89\x0e\x11\xfa\xd5\xd8\\\xa3\x00\x00\u07d4\xda\xc0\xc1w\xf1\x1c\\>>x\xf2\xef\xd6c\xd12!H\x85t\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xda\xd16\xb8\x81x\xb4\x83zlx\x0f\xeb\xa2&\xb9\x85i\xa9L\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xda\xdb\xfa\xfd\x8bb\xb9*$\xef\xd7RV\u0743\xab\xdb\u05fb\u06c9\x01\x11du\x9f\xfb2\x00\x00\u07d4\xda\xdc\x00\xaby'`\xcf1\xce\xe3R\xf8\x0elMcQ\x89lf\xe9\xa5Sx\xb8\x00\x00\u07d4\xda\xe0\xd3>\xaa4\x15i\xfa\x9f\xf5\x98&\x84\x85JJ2\x8an\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xda\xe7 \x1e\xab\x8c\x063\x02\x93\ri9)\xd0\u007f\x95\xe7\x19b\x89\x91\xae\xc0(\xb4\x19\x81\x00\x00\u07d4\xda\xed\u052d\x10{'\x1e\x89Hl\xbf\x80\xeb\xd6!\u0757Ex\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xdb\x04\xfa\xd9\u011f\x9e\x88\v\xeb\x8f\xcf\x1d:8\x90\u4cc4o\x89CZ\xe6\xcc\fX\xe5\x00\x00\u07d4\xdb\f\u01cft\u0642{\u070ads'n\xb8O\u0717b\x12\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xdb\x12\x93\xa5\x06\xe9\f\xad*Y\xe1\xb8V\x1f^f\x96\x1ag\x88\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xdb\x19\xa3\x98\"06\x8f\x01w!\x9c\xb1\f\xb2Y\u0372%|\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xdb#\xa6\xfe\xf1\xaf{X\x1ew,\xf9\x18\x82\u07b2Qo\xc0\xa7\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xdb$O\x97\xd9\xc4K\x15\x8a@\xed\x96\x06\xd9\xf7\xbd8\x9131\x89\x05\x87\x88\u02d4\xb1\xd8\x00\x00\u07d4\xdb(\x8f\x80\xff\xe22\u00baG\u0314\xc7c\xcfo\u0278+\r\x89\x04\x9b\x9c\xa9\xa6\x944\x00\x00\u07d4\xdb*\f\x9a\xb6M\xf5\x8d\u07f1\u06ec\xf8\xba\r\x89\xc8[1\xb4\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xdb4t^\u0785v\xb4\x99\xdb\x01\xbe\xb7\xc1\xec\u0685\xcfJ\xbe\x89\x04V9\x18$O@\x00\x00\u07d4\xdb?%\x8a\xb2\xa3\xc2\xcf3\x9cD\x99\xf7ZK\xd1\xd3G.\x9e\x89QP\xae\x84\xa8\xcd\xf0\x00\x00\u07d4\xdbK\xc8;\x0ek\xaa\xdb\x11V\xc5\xcf\x06\xe0\xf7!\x80\x8cR\u01c9/\xb4t\t\x8fg\xc0\x00\x00\u07d4\xdbc\x12-\xe7\x03}\xa4\x97\x151\xfa\u9bc5\x86x\x86\u0192\x89\x0f\x04%\xb0d\x1f4\x00\x00\u07d4\xdbl*s\xda\xc7BJ\xb0\xd01\xb6ga\x12%f\xc0\x10C\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xdbnV\f\x9b\xc6 \u053e\xa3\xa9MG\xf7\x88\v\xf4\u007f-_\x89\x04\xda\x0f\xdf\xcf\x05v\x00\x00\u07d4\xdbo\xf7\x1b=\xb0\x92\x8f\x83\x9e\x05\xa72;\xfbW\u049c\x87\xaa\x891T\xc9r\x9d\x05x\x00\x00\u07d4\xdbsF\vY\xd8\xe8PE\xd5\xe7R\xe6%Y\x87^BP.\x8963\x03\"\xd5#\x8c\x00\x00\u07d4\xdbw\xb8\x8d\xcbq/\xd1~\xe9\x1a[\x94t\x8dr\f\x90\xa9\x94\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xdb}@7\b\x1fle\xf9Gk\x06\x87\xd9\u007f\x1e\x04M\n\x1d\x89#\xc7W\a+\x8d\xd0\x00\x00\xe0\x94\u06c8.\xac\xed\xd0\xef\xf2cQ\x1b1*\u06fcY\u01b8\xb2[\x8a\x01\xedO\xdez\"6\xb0\x00\x00\u07d4\u06d3q\xb3\fL\x84NY\xe0>\x92K\xe6\x06\xa98\xd1\xd3\x10\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u06e4ym\f\xebM:\x83k\x84\xc9o\x91\n\xfc\x10?[\xa0\x89\t\b\xf4\x93\xf77A\x00\x00\u07d4\u06ed\xc6\x1e\xd5\xf0F\n\u007f\x18\xe5\x1b/\xb2aM\x92d\xa0\xe0\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\u06f6\xacH@'\x04\x16B\xbb\xfd\x8d\x80\xf9\xd0\xc1\xcf3\xc1\xeb\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u06fc\xbby\xbfG\x9aB\xadq\xdb\u02b7{Z\u07ea\x87,X\x89]\u0212\xaa\x111\xc8\x00\x00\u07d4\xdb\xc1\xce\x0eI\xb1\xa7\x05\xd2. 7\xae\xc8x\xee\ru\xc7\x03\x89\r\x8drkqw\xa8\x00\x00\u07d4\xdb\xc1\xd0\xee+\xabS\x11@\xde\x13w\"\xcd6\xbd\xb4\xe4q\x94\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xdb\u015e\u0609s\u07ad1\b\x84\":\xf4\x97c\xc0P0\xf1\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u0794\xdb\xc6ie\xe4&\xff\x1a\xc8z\xd6\xebx\xc1\xd9Rq\x15\x8f\x9f\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\xdb\xcb\xcdzW\ua7724\x9b\x87\x8a\xf3K\x1a\xd6B\xa7\xf1\u0449\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xdb\xd5\x1c\xdf,;\xfa\xcd\xff\x10b!\xde.\x19\xadmB\x04\x14\x89_h\xe8\x13\x1e\u03c0\x00\x00\u07d4\xdb\xd7\x1e\xfaK\x93\u0209\xe7e\x93\xde`\x9c;\x04\u02ef\xbe\b\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xdb\xf5\xf0a\xa0\xf4\x8e^ia\x879\xa7}.\xc1\x97h\xd2\x01\x89\b=lz\xabc`\x00\x00\u07d4\xdb\xf8\xb19g\xf5Q%'-\xe0V%6\xc4P\xbaVU\xa0\x89n\xf5x\xf0n\f\xcb\x00\x00\u07d4\xdb\xfb\x1b\xb4d\xb8\xa5\x8eP\r.\xd8\u0797,E\xf5\xf1\xc0\xfb\x89V\xbcu\xe2\xd61\x00\x00\x00\xe0\x94\xdc\x06~\xd3\xe1-q\x1e\xd4u\xf5\x15n\xf7\xe7\x1a\x80\xd94\xb9\x8a\x02\x05\xb4\u07e1\xeetx\x00\x00\u07d4\xdc\b\u007f\x93\x90\xfb\x9e\x97j\xc2:\xb6\x89TJ\tB\xec !\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4\xdc\x1e\xb9\xb6\xe6CQ\xf5d$P\x96E\xf8>y\xee\xe7l\xf4\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xdc\x1f\x19ya_\b!@\xb8\xbbx\xc6{'\xa1\x94'\x13\xb1\x89\x03@\xaa\xd2\x1b;p\x00\x00\u07d4\xdc#\xb2`\xfc\xc2n}\x10\xf4\xbd\x04J\xf7\x94W\x94`\xd9\u0689\x1b\x1bk\u05efd\xc7\x00\x00\u07d4\xdc)\x11\x97E\xd23s \xdaQ\xe1\x91\x00\xc9H\u0640\xb9\x15\x89\b\xacr0H\x9e\x80\x00\x00\u07d4\xdc-\x15\xa6\x9fk\xb3;$j\xef@E\aQ\xc2\xf6uj\u0489l4\x10\x80\xbd\x1f\xb0\x00\x00\u07d4\xdc=\xaeY\xed\x0f\xe1\x8bXQ\x1eo\xe2\xfbi\xb2\x19h\x94#\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94\xdc?\x0evr\xf7\x1f\xe7R[\xa3\v\x97U\x18: \xb9\x16j\x8a\x02\b\x9c\xf5{[>\x96\x80\x00\xe0\x94\xdcCE\u0581.\x87\n\xe9\fV\x8cg\xd2\xc5g\u03f4\xf0<\x8a\x01k5-\xa5\xe0\xed0\x00\x00\u07d4\xdcD'[\x17\x15\xba\xea\x1b\x03EsZ)\xacB\xc9\xf5\x1bO\x89?\x19\xbe\xb8\xdd\x1a\xb0\x00\x00\u07d4\xdcF\xc13%\u034e\xdf\x020\xd0h\x89d\x86\xf0\a\xbfN\xf1\x89Hz\x9a0E9D\x00\x00\u07d4\xdcQ\xb2\u071d$z\x1d\x0e[\xc3l\xa3\x15oz\xf2\x1f\xf9\xf6\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xdcS\x05\xb4\x02\n\x06\xb4\x9de||\xa3L5\xc9\x1c_,V\x8a\x01}\xf6\xc1\r\xbe\xba\x97\x00\x00\u07d4\xdcW4[8\xe0\xf0g\u0263\x1d\x9d\xea\xc5'Z\x10\x94\x93!\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xdcWG}\xaf\xa4/p\\\u007f\xe4\x0e\xae\x9c\x81un\x02%\xf1\x89\x1b\x1b\x81(\xa7An\x00\x00\u07d4\xdc_Z\xd6c\xa6\xf2c2}d\xca\xc9\xcb\x13=,\x96\x05\x97\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xdcp:_7\x94\xc8Ml\xb3TI\x18\xca\xe1J5\u00fdO\x89dI\xe8NG\xa8\xa8\x00\x00\xe0\x94\xdcs\x8f\xb2\x17\u03ad/iYL\b\x17\r\xe1\xaf\x10\xc4\x19\xe3\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\xdcv\xe8[\xa5\v\x9b1\xec\x1e& \xbc\xe6\xe7\xc8\x05\x8c\x0e\xaf\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\u0703\xb6\xfd\rQ!1 G\a\xea\xf7.\xa0\xc8\u027e\xf9v\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u070c)\x12\xf0\x84\xa6\u0444\xaasc\x85\x13\u033c2n\x01\x02\x89F3\xbc6\xcb\xc2\xdc\x00\x00\u07d4\u0711\x1c\xf7\xdc]\u04016Vg\x05(\xe93\x8eg\x03G\x86\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u0730;\xfal\x111#NV\xb7\xea|Or\x14\x87Tkz\x89Hz\x9a0E9D\x00\x00\xe0\x94\u0736M\xf47X\xc7\u03d7O\xa6`HO\xbbq\x8f\x8cg\xc1\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xdc\xc5-\x8f\x8d\x9f\xc7B\xa8\xb8'g\xf0US\x87\xc5c\xef\xff\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xdc\xcb7\x0e\u058a\xa9\"(0C\xef|\xad\x1b\x9d@?\xc3J\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xdc\u0324 E\xec>\x16P\x8b`?\xd96\xe7\xfd}\xe5\xf3j\x89\x01\x11du\x9f\xfb2\x00\x00\u07d4\xdc\xd1\fU\xbb\x85OuD4\xf1!\x9c,\x9a\x98\xac\xe7\x9f\x03\x89\xd8\xd8X?\xa2\xd5/\x00\x00\u07d4\xdc\u057c\xa2\x00S\x95\xb6u\xfd\xe5\x03VY\xb2k\xfe\xfcI\xee\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\u07d4\xdc\u06fdN&\x04\xe4\x0e\x17\x10\xccg0(\x9d\xcc\xfa\u04c9-\x89\xf9]\xd2\xec'\xcc\xe0\x00\x00\u07d4\xdc\xe3\f1\xf3\xcafr\x1e\xcb!<\x80\x9a\xabV\x1d\x9bR\xe4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xdc\xf39eS\x13\x80\x161h\xfc\x11\xf6~\x89\xc6\xf1\xbc\x17\x8a\x89\x12'v\x854\x06\xb0\x80\x00\u07d4\xdc\xf6\xb6W&n\x91\xa4\xda\xe6\x03=\xda\xc1S2\u074d+4\x89_h\xe8\x13\x1e\u03c0\x00\x00\u07d4\xdc\xf9q\x9b\xe8|oFum\xb4\x89\x1d\xb9\xb6\x11\xd2F\x9cP\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xdc\xff\xf3\xe8\xd2<*4\xb5k\u0473\xbdE\u01d3tC\"9\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\xdd\x04\xee\xe7N\v\xf3\f?\x8dl,\u007fR\xe0Q\x92\x10\u07d3\x89\x04V9\x18$O@\x00\x00\xe0\x94\xdd&\xb4)\xfdC\xd8N\xc1y\x82S$\xba\u057f\xb9\x16\xb3`\x8a\x01\x16\xbf\x95\xbc\x842\x98\x00\x00\u07d4\xdd*#:\xde\xdef\xfe\x11&\xd6\xc1h#\xb6*\x02\x1f\xed\u06c9lk\x93[\x8b\xbd@\x00\x00\u07d4\xdd+\u07e9\x17\xc1\xf3\x10\xe6\xfa5\xaa\x8a\xf1i9\xc23\xcd}\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xdd5\xcf\xdb\u02d93\x95Sz\xec\xc9\xf5\x90\x85\xa8\xd5\u0776\xf5\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xddG\x18\x9a>d9qg\xf0b\x0eHEe\xb7b\xbf\xbb\xf4\x89dI\xe8NG\xa8\xa8\x00\x00\u07d4\xddM\xd6\xd3`3\xb0co\u030d\t8`\x9fM\xd6OJ\x86\x89\x03@\xaa\xd2\x1b;p\x00\x00\u07d4\xddO_\xa2\x11\x1d\xb6\x8fk\xde5\x89\xb60)9[i\xa9-\x89\b\x96=\xd8\xc2\xc5\xe0\x00\x00\xe0\x94\xddc\x04/%\xed2\x88J\xd2n:\xd9Y\xeb\x94\xea6\xbfg\x8a\x04\x84\xd7\xfd\xe7\u0553\xf0\x00\x00\u07d4\xdde\xf6\xe1qc\xb5\xd2\x03d\x1fQ\xcc{$\xb0\x0f\x02\xc8\xfb\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xddl\x06!\x93\xea\xc2=/\xdb\xf9\x97\xd5\x06:4k\xb3\xb4p\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xdd{\u0366Y$\xaa\xa4\x9b\x80\x98J\xe1su\x02X\xb9(G\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xdd\u007f\xf4A\xbao\xfe6q\xf3\xc0\u06bb\xff\x18#\xa5\x043p\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u0742T\x12\x1an\x94/\xc9\b(\xf2C\x1fQ\x1d\xad\u007f2\u6263\x9b)\xe1\xf3`\xe8\x00\x00\xe0\x94\u074a\xf9\xe7vR#\xf4DoD\xd3\xd5\t\x81\x9a==\xb4\x11\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94\u0755\xdb\xe3\x0f\x1f\x18w\xc5\xddv\x84\xae\xef0*\xb6\x88Q\x92\x8a\x01\xc5\xd8\xd6\xeb>2P\x00\x00\xe0\x94\u0756|L_\x8a\xe4~&o\xb4\x16\xaa\u0456N\xe3\xe7\xe8\u00ca\x01\xa4 \xdb\x02\xbd}X\x00\x00\u07d4\u075bHZ;\x1c\xd3:j\x9cb\xf1\xe5\xbe\xe9'\x01\x85m%\x89\f3\x83\xed\x03\x1b~\x80\x00\xe0\x94\u0763q\xe6\x00\xd3\x06\x88\xd4q\x0e\b\x8e\x02\xfd\xf2\xb9RM_\x8a\x01w\"J\xa8D\xc7 \x00\x00\u07d4\u0764\xed*X\xa8\xdd \xa72u4{X\rq\xb9[\xf9\x9a\x89\x15\xa1<\xc2\x01\xe4\xdc\x00\x00\xe0\x94\u0764\xff}\xe4\x91\u0187\xdfEt\xdd\x1b\x17\xff\x8f$k\xa3\u044a\x04&\x84\xa4\x1a\xbf\xd8@\x00\x00\u07d4\u076bkQ\xa9\x03\v@\xfb\x95\xcf\vt\x8a\x05\x9c$\x17\xbe\u01c9lk\x93[\x8b\xbd@\x00\x00\xe0\x94\u076bu\xfb/\xf9\xfe\u02c8\xf8\x94vh\x8e+\x00\xe3g\xeb\xf9\x8a\x04\x1b\xad\x15^e\x12 \x00\x00\xe0\x94\u076b\xf1<<\x8e\xa4\xe3\xd7=x\xecqz\xfa\xfaC\x0eTy\x8a\b\xcf#\xf9\t\xc0\xfa\x00\x00\x00\u07d4\u076c1*\x96UBj\x9c\f\x9e\xfa?\xd8%Y\xefE\x05\xbf\x89\x15\xbeat\xe1\x91.\x00\x00\u07d4\u076ck\xf4\xbb\xdd}Y}\x9chm\x06\x95Y;\xed\xcc\xc7\xfa\x89.\xe4IU\b\x98\xe4\x00\x00\xe0\x94\u077d+\x93,v;\xa5\xb1\xb7\xae;6.\xac>\x8d@\x12\x1a\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\u077d\xdd\x1b\xbd8\xff\xad\xe00]0\xf0 (\xd9.\x9f:\xa8\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u077e\xe6\xf0\x94\xea\xe64 \xb0\x03\xfbGW\x14*\xeal\xd0\xfd\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xdd\u059c[\x9b\xf5\xebZ9\xce\xe7\xc34\x1a\x12\r\x97?\xdb4\x89k\xc1K\x8f\x8e\x1b5\x00\x00\xe0\x94\xdd\xdd{\x9en\xab@\x9b\x92&:\xc2r\u0680\x1bfO\x8aW\x8ai\xe1\r\xe7fv\u0400\x00\x00\u07d4\xdd\xe6p\xd0\x169fuv\xa2-\xd0]2F\xd6\x1f\x06\xe0\x83\x89\x01s\x17\x90SM\xf2\x00\x00\xe0\x94\xdd\xe7zG@\xba\b\xe7\xf7?\xbe:\x16t\x91)1t.\xeb\x8a\x044\xfeMC\x82\xf1\u0500\x00\u07d4\xdd\xe8\xf0\xc3\x1bt\x15Q\x1d\xce\xd1\xcd}F2>K\xd1\"2\x89WG=\x05\u06ba\xe8\x00\x00\u07d4\xdd\xe9i\xae\xf3N\xa8z\u0099\xb7Y~)+J\x01U\u030a\x89\x102\xf2YJ\x01s\x80\x00\u07d4\xdd\xf0\xcc\xe1\xfe\x99m\x91v5\xf0\a\x12\xf4\x05 \x91\xdf\xf9\xea\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xdd\xf3\xadv58\x10\xbej\x89\xd71\xb7\x87\xf6\xf1q\x88a+\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94\xdd\xf5\x81\n\x0e\xb2\xfb.22;\xb2\u0255\t\xab2\x0f$\xac\x8a\x03\xca\\f\u067cD0\x00\x00\xe0\x94\xdd\xf9\\\x1e\x99\xce/\x9fV\x98\x05|\x19\xd5\xc9@'\xeeJn\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u0794\xdd\xfa\xfd\xbc|\x90\xf12\x0eT\xb9\x8f7F\x17\xfb\xd0\x1d\x10\x9f\x88\xb9\x8b\xc8)\xa6\xf9\x00\x00\u07d4\xdd\xfc\xca\x13\xf94\xf0\u03fe#\x1d\xa109\xd7\x04u\xe6\xa1\u040968\"\x16`\xa5\xaa\x80\x00\u07d4\xde\x02~\xfb\xb3\x85\x03\"n\xd8q\t\x9c\xb3\v\xdb\x02\xaf\x135\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xde\x06\xd5\xeawzN\xb1G^`]\xbc\xbfCDN\x807\xea\x8a\n\x96\x81c\xf0\xa5{@\x00\x00\u07d4\xde\a\xfb[zFN;\xa7\xfb\xe0\x9e\x9a\xcb'\x1a\xf53\x8cX\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\u07d4\xde\x11!\x82\x9c\x9a\b(@\x87\xa4?\xbd/\xc1\x14*23\xb4\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xde\x17kR\x84\xbc\xee:\x83\x8b\xa2Og\xfc|\xbfg\u05ce\xf6\x89\x02\t\xce\b\xc9b\xb0\x00\x00\u07d4\xde!\"\x93\xf8\xf1\xd21\xfa\x10\xe6\tG\rQ,\xb8\xff\xc5\x12\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xde0\xe4\x9eZ\xb3\x13!M/\x01\u072b\u0389@\xb8\x1b\x1cv\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\u07d4\xde3\xd7\b\xa3\xb8\x9e\x90\x9e\xafe;0\xfd\u00e5\xd5\u0334\xb3\x89\t\x9c\x88\"\x9f\xd4\xc2\x00\x00\u07d4\xde7B\x99\xc1\xd0}ySs\x85\x19\x0fD.\xf9\xca$\x06\x1f\x89\a?u\u0460\x85\xba\x00\x00\u07d4\xdeB\xfc\xd2L\xe4#\x93\x830CgY_\x06\x8f\fa\a@\x89\x02r*p\xf1\xa9\xa0\x00\x00\u07d4\xdeP\x86\x8e\xb7\xe3\xc7\x197\xecs\xfa\x89\u074b\x9e\xe1\rE\xaa\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xdeU\xde\x04X\xf8P\xb3~Mx\xa6A\xdd.\xb2\u074f8\u0389\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xde[\x00_\xe8\u06ae\x8d\x1f\x05\xde>\xda\x04 f\xc6\xc4i\x1c\x89;\xa1\x91\v\xf3A\xb0\x00\x00\u07d4\xdea-\a$\xe8N\xa4\xa7\xfe\xaa=!B\xbd^\xe8-2\x01\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xdem61\x06\xccb8\xd2\xf0\x92\xf0\xf07!6\xd1\xcdP\u018a\x01!\xeah\xc1\x14\xe5\x10\x00\x00\u07d4\xde}\xee\"\x0f\x04W\xa7\x18}V\xc1\xc4\x1f.\xb0\n\xc5`!\x89\"%\xf3\x9c\x85\x05*\x00\x00\u07d4\u0782\u030dJ\x1b\xb1\xd9CC\x92\x96[>\x80\xba\xd3\xc0=O\x89P\x18nu\u0797\xa6\x00\x00\u07d4\u0797\xf43\a\x00\xb4\x8cImC|\x91\xca\x1d\xe9\u0130\x1b\xa4\x89\x9d\xcc\x05\x15\xb5n\f\x00\x00\u07d4\u079e\xffLy\x88\x11\xd9h\xdc\xcbF\r\x9b\x06\x9c\xf3\x02x\xe0\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\u07b1\xbc4\xd8mJM\xde%\x80\u063e\xaf\aN\xb0\xe1\xa2D\x89U\xa6\xe7\x9c\xcd\x1d0\x00\x00\u07d4\u07b2I]j\xca{*j-\x13\x8bn\x1aB\xe2\xdc1\x1f\u0749lk\x93[\x8b\xbd@\x00\x00\u07d4\u07b9rTGL\r/Zyp\xdc\xdb/R\xfb\x10\x98\xb8\x96\x8965\u026d\xc5\u07a0\x00\x00\u07d4\u07b9\xa4\x9aC\x870 \xf0u\x91\x85\xe2\v\xbbL\U000c1ecf\x89\vx\xed\xb0\xbf.^\x00\x00\u07d4\u07bb\u0743\x1e\x0f \xaen7\x82R\xde\xcd\xf9/|\xf0\xc6X\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xde\xc3\xee\xc2d\nu,Fn+~~\u616f\xe9\xacA\xf4\x89G\u0257SYk(\x80\x00\u07d4\xde\xc8#s\xad\xe8\xeb\xcf*\xcbo\x8b\xc2AM\u05eb\xb7\rw\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xde\u0221\xa8\x98\xf1\xb8\x95\xd80\x1f\xe6J\xb3\xad]\xe9A\xf6\x89\x89*\xb4\xf6~\x8as\x0f\x80\x00\u07d4\xde\u025e\x97/\xcaqwP\x8c\x8e\x1aG\xac\"\xd7h\xac\xab|\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xde\xd8w7\x84\a\xb9Nx\x1cN\xf4\xaf|\xfc[\xc2 \xb5\x16\x89\x141y\xd8i\x11\x02\x00\x00\u07d4\xde\xe9B\xd5\xca\xf5\xfa\xc1\x14!\xd8k\x01\vE\x8e\\9)\x90\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xde\xee&\x89\xfa\x90\x06\xb5\x9c\xf2\x85#}\xe5;:\u007f\xd0\x148\x89\x18ey\xf2\x9e %\x00\x00\u07d4\xde\xfd\xdf\u055b\x8d,\x15N\xec\xf5\xc7\xc1g\xbf\v\xa2\x90]>\x89\x05\x12\xcb^&GB\x00\x00\u07d4\xde\xfe\x91A\xf4pE\x99\x15\x9d{\"=\xe4+\xff\xd8\x04\x96\xb3\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xdf\t\x8f^N=\xff\xa5\x1a\xf27\xbd\xa8e,Os\ud726\x89\x1b6\xa6DJ>\x18\x00\x00\xe0\x94\xdf\r\ba{\xd2R\xa9\x11\u07cb\xd4\x1a9\xb8=\u07c0\x96s\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xdf\x0f\xf1\xf3\xd2z\x8e\xc9\xfb\x8fk\f\xb2T\xa6;\xba\x82$\xa5\x89\xec\xc5 )E\xd0\x02\x00\x00\u07d4\xdf\x1f\xa2\xe2\x0e1\x98^\xbe,\x0f\f\x93\xb5L\x0f\xb6z&K\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xdf!\x1c\xd2\x12\x88\xd6\xc5o\xaef\xc3\xffTb]\u0531T'\x89\x87\x86\xcdvN\x1f,\x00\x00\u07d4\xdf#k\xf6\xab\xf4\xf3)7\x95\xbf\f(q\x8f\x93\u3c73k\x89Hz\x9a0E9D\x00\x00\u07d4\xdf1\x02_VI\xd2\xc6\xee\xa4\x1e\u04fd\xd3G\x1ay\x0fu\x9a\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xdf7\xc2.`:\xed\xb6\nbrS\xc4}\x8b\xa8f\xf6\xd9r\x8a\x05\x15\n\xe8J\x8c\xdf\x00\x00\x00\u07d4\xdf;r\u017dq\u0501N\x88\xa6#!\xa9=@\x11\xe3W\x8b\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xdf?W\xb8\xeed4\xd0G\"=\xeft\xb2\x0fc\xf9\xe4\xf9U\x89\r\x94b\xc6\xcbKZ\x00\x00\u07d4\xdfD\xc4\u007f\xc3\x03\xacv\xe7O\x97\x19L\xcag\xb5\xbb<\x02?\x89 \t\xc5\u023fo\xdc\x00\x00\u07d4\xdfG\xa6\x1brSQ\x93\xc5a\xcc\xccu\xc3\xf3\xce\b\x04\xa2\x0e\x89\x15\x93\\\vN=x\x00\x00\u07d4\xdfG\xa8\xef\x95\xf2\xf4\x9f\x8eoX\x18AT\x14]\x11\xf7'\x97\x89g\x8a\x93 b\xe4\x18\x00\x00\u07d4\xdfS\x003F\xd6\\^zdk\xc04\xf2\xb7\xd3/\xcb\xe5j\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xdfW5:\xaf\xf2\xaa\xdb\n\x04\xf9\x01N\x8d\xa7\x88N\x86X\x9c\x89\bH\x86\xa6nO\xb0\x00\x00\u07d4\xdf`\xf1\x8c\x81*\x11\xedN'v\xe7\xa8\x0e\xcf^S\x05\xb3\u05890\xca\x02O\x98{\x90\x00\x00\u07d4\xdfd\x85\xc4)z\xc1R\xb2\x89\xb1\x9d\xde2\xc7~\xc4\x17\xf4}\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xdff\n\x91\u06b9\xf70\xf6\x19\rP\xc89\x05aP\aV\u0289lk\x93[\x8b\xbd@\x00\x00\u07d4\xdfn\xd6\x00jj\xbe\x88n\xd3=\x95\xa4\xde(\xfc\x12\x189'\x891T\xc9r\x9d\x05x\x00\x00\u07d4\u07c5\x10y>\xee\x81\x1c-\xab\x1c\x93\xc6\xf4G?0\xfb\xef[\x8965\u026d\xc5\u07a0\x00\x00\u07d4\u07cdH\xb1\xeb\a\xb3\xc2\x17y\x0el-\xf0M\xc3\x19\xe7\xe8H\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\u07e6\xb8\xb8\xad1\x84\xe3W\xda()Q\u05d1a\u03f0\x89\xbc\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\xe0\x94\u07ef1\xe6\"\xc0=\x9e\x18\xa0\u0778\xbe`\xfb\xe3\xe6a\xbe\n\x8a\x02\x1e\x17\x1a>\xc9\xf7,\x00\x00\u07d4\u07f1bn\xf4\x8a\x1d}uR\xa5\xe0)\x8f\x1f\xc2:;H-\x89\\\xe8\x95\u0754\x9e\xfa\x00\x00\xe0\x94\u07f4\u052d\xe5/\u0301\x8a\xccz,k\xb2\xb0\x02$e\x8fx\x8a\x01\xa4 \xdb\x02\xbd}X\x00\x00\u07d4\u07fdB2\xc1|@z\x98\r\xb8\u007f\xfb\u036060\xe5\xc4Y\x89\x1d\xfc\u007f\x92I#S\x00\x00\u07d4\xdf\xcb\xdf\tEN\x1a^J@\xd3\xee\xf7\xc5\xcf\x1c\xd3\u0794\x86\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xdf\xdb\xce\xc1\x01K\x96\xda!X\xcaQ>\x9c\x8d;\x9a\xf1\xc3\u0409lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xdf\xde\xd2WK'\xd1a:}\x98\xb7\x15\x15\x9b\r\x00\xba\xab(\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xdf\xdfC9P\x8b\x0fnZ\xb1\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xe0\x06\x04b\xc4\u007f\xf9g\x9b\xae\xf0qY\xca\xe0\x8c)\xf2t\xa9\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe0\r\x15;\x106\x91C\xf9\u007fT\xb8\xd4\xca\"\x9e\xb3\xe8\xf3$\x89\b=lz\xabc`\x00\x00\u07d4\xe0\x12\xdbE8'\xa5\x8e\x16\xc16V\b\xd3n\xd6Xr\x05\a\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe0\x15G\xbaB\xfc\xaf\xaf\x93\x93\x8b\xec\xf7i\x9ft)\n\xf7O\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe0\x16\xdc\x13\x8e%\x81[\x90\xbe?\xe9\xee\xe8\xff\xb2\xe1\x05bO\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xe0\x18Y\xf2B\xf1\xa0\xec`/\xa8\xa3\xb0\xb5v@\xec\x89\a^\x89\x1e\x16,\x17{\xe5\xcc\x00\x00\xe0\x94\xe0 \xe8cb\xb4\x87u(6\xa6\xde\v\xc0,\xd8\u061a\x8bj\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xe0#\xf0\x9b(\x87a,|\x9c\xf1\x98\x8e::`+3\x94\u0249lk\x93[\x8b\xbd@\x00\x00\u07d4\xe0'\"\x13\xe8\xd2\xfd>\x96\xbdb\x17\xb2KK\xa0\x1bapy\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xe0+t\xa4v(\xbe1[\x1fv\xb3\x15\x05J\xd4J\xe9qo\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\xe02 \u0197\xbc\u048f&\xef\vt@J\x8b\xeb\x06\xb2\xba{\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xe05/\u07c1\x9b\xa2e\xf1L\x06\xa61\\J\xc1\xfe\x13\x1b.\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xe08\x8a\xed\xdd?\xe2\xadV\xf8WH\xe8\x0eq\n4\xb7\xc9.\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xe0<\x00\xd0\x03\x88\xec\xbfO&=\n\xc7x\xbbA\xa5z@\u064966\xc9yd6t\x00\x00\u07d4\xe0I \xdcn\xcc\x1dn\xcc\bO\x88\xaa\n\xf5\u06d7\xbf\x89:\x89\t\xdd\xc1\xe3\xb9\x01\x18\x00\x00\u07d4\xe0Ir\xa8<\xa4\x11+\xc8q\xc7-J\xe1al/\a(\u06c9\x0e\x81\xc7\u007f)\xa3/\x00\x00\u07d4\xe0O\xf5\xe5\xa7\u2bd9]\x88W\xce\x02\x90\xb5:+\x0e\xda]\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xe0P)\xac\xeb\axg[\xef\x17A\xab,\u0493\x1e\xf7\xc8K\x8a\x01\x0f\r\xba\xe6\x10\tR\x80\x00\u07d4\xe0V\xbf?\xf4\x1c&%o\xefQqf\x12\xb9\u04da\u0799\x9c\x89\x05k\xe7W\xa1.\n\x80\x00\u07d4\xe0a\xa4\xf2\xfcw\xb2\x96\u045a\xda#\x8eI\xa5\u02ce\xcb\xfap\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xe0f>\x8c\xd6g\x92\xa6A\xf5nP\x03f\x01G\x88\x0f\x01\x8e\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe0f\x8f\xa8,\x14\xd6\xe8\xd9:S\x11>\xf2\x86/\xa8\x15\x81\xbc\x89//9\xfclT\x00\x00\x00\u07d4\xe0i\xc0\x173R\xb1\v\xf6\x83G\x19\xdb[\xed\x01\xad\xf9{\xbc\x89\x01\x064\xf8\xe52;\x00\x00\u07d4\xe0l)\xa8\x15\x17\xe0\u0507\xb6\u007f\xb0\xb6\xaa\xbcOW6\x83\x88\x89\x15\xbeat\xe1\x91.\x00\x00\u07d4\xe0l\xb6)G\x04\xee\xa7C|/\xc3\xd3\as\xb7\xbf8\x88\x9a\x89\x01\x16\xdc:\x89\x94\xb3\x00\x00\u07d4\xe0q7\xae\r\x11m\x0353\xc4\uad16\xf8\xa9\xfb\tV\x9c\x89K\xe4\xe7&{j\xe0\x00\x00\xe0\x94\xe0v\xdb0\xabHoy\x19N\xbb\xc4]\x8f\xab\x9a\x92B\xf6T\x8a\x01\x06`~4\x94\xba\xa0\x00\x00\u07d4\xe0~\xbb\xc7\xf4\xdaAnB\xc8\xd4\xf8B\xab\xa1b3\xc1%\x80\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe0\x81\xca\x1fH\x82\xdb`C\u0569\x19\a\x03\xfd\xe0\xab;\xf5m\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xe0\x83\xd3Hc\xe0\xe1\u007f\x92ky(\xed\xff1~\x99\x8e\x9cK\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xe0\x8b\x9a\xbak\xd9\u048b\xc2\x05gy\xd2\xfb\xf0\xf2\x85Z=\x9d\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe0\x8b\u009c+H\xb1i\xff+\xdc\x16qLXnl\xb8\\\u03c9\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xe0\x8c`11\x06\xe3\xf93O\xe6\xf7\xe7bM!\x110\xc0w\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\xe0\x9ch\xe6\x19\x98\xd9\xc8\x1b\x14\xe4\xee\x80+\xa7\xad\xf6\xd7L\u06c9\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xe0\x9f\xeauZ\xee\x1aD\xc0\xa8\x9f\x03\xb5\u07b7b\xba3\x00o\x89;\xa2\x89\xbc\x94O\xf7\x00\x00\xe0\x94\xe0\xa2T\xac\t\xb9r[\xeb\xc8\xe4`C\x1d\xd0s.\xbc\xab\xbf\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94\xe0\xaai6UU\xb7?(#3\xd1\xe3\f\x1b\xbd\a(T\xe8\x8a\x01{x\x83\xc0i\x16`\x00\x00\u07d4\xe0\xba\u064e\ue598\xdb\xf6\xd7`\x85\xb7\x92=\xe5uN\x90m\x89\t\r\x97/22<\x00\x00\u07d4\xe0\u012b\x90r\xb4\xe6\xe3eJI\xf8\xa8\xdb\x02jK3\x86\xa9\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe0\u0380\xa4a\xb6H\xa5\x01\xfd\v\x82F\x90\u0206\x8b\x0eM\xe8\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xe0\xcfi\x8a\x053'\xeb\xd1k}w\x00\t/\xe2\xe8T$F\x89\x05*4\u02f6\x1fW\x80\x00\xe0\x94\xe0\xd21\xe1D\xec\x91\a8l|\x9b\x02\xf1p,\xea\xa4\xf7\x00\x8a\x01\x0f\r\xba\xe6\x10\tR\x80\x00\u07d4\xe0\xd7kqf\xb1\xf3\xa1+@\x91\xee+)\u078c\xaa}\a\u06c9lk\x93[\x8b\xbd@\x00\x00\u07d4\xe0\xe0\xb2\xe2\x9d\xdes\xafu\x98~\xe4Dl\x82\x9a\x18\x9c\x95\xbc\x89\b\x13\xcaV\x90m4\x00\x00\xe0\x94\xe0\xe9xu=\x98/\u007f\x9d\x1d#\x8a\x18\xbdH\x89\xae\xfeE\x1b\x8a\x02\r\u058a\xaf2\x89\x10\x00\x00\u07d4\xe0\xf3r4|\x96\xb5_}C\x06\x03K\xeb\x83&o\xd9\tf\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xe0\xf9\x03\xc1\xe4\x8a\xc4!\xabHR\x8f=J&H\b\x0f\xe0C\x897\b\xba\xed=h\x90\x00\x00\u07d4\xe0\xff\v\xd9\x15D9\u0125\xb7#>)\x1d}\x86\x8a\xf5?3\x89\x15y!jQ\xbb\xfb\x00\x00\xe0\x94\xe1\n\xc1\x9cTo\xc2T|a\xc19\xf5\xd1\xf4Zff\u0570\x8a\x01\x02\xdao\xd0\xf7:<\x00\x00\xe0\x94\xe1\fT\x00\x88\x11?\xa6\xec\x00\xb4\xb2\u0202O\x87\x96\xe9n\u010a2\x0fE\t\xab\x1e\xc7\xc0\x00\x00\xe0\x94\xe1\x17:$})\xd8#\x8d\xf0\x92/M\xf2Z\x05\xf2\xafw\u00ca\bx\xc9]V\x0f0G\x80\x00\xe0\x94\xe1 >\xb3\xa7#\xe9\x9c\" \x11|\xa6\xaf\xebf\xfaBOa\x8a\x02\x00\uf49e2V\xfe\x00\x00\xe0\x94\xe11\xf8~\xfc^\xf0~C\xf0\xf2\xf4\xa7G\xb5Q\xd7P\xd9\xe6\x8a\x04<%\xe0\xdc\xc1\xbd\x1c\x00\x00\u07d4\xe13N\x99\x83y\xdf\xe9\x83\x17pby\x1b\x90\xf8\x0e\xe2-\x8d\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xe15@\xec\xee\x11\xb2\x12\xe8\xb7u\u070eq\xf3t\xaa\xe9\xb3\xf8\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe1;=+\xbf\u073c\x87r\xa23\x15rL\x14%\x16|V\x88\x897\xf3y\x14\x1e\xd0K\x80\x00\u07d4\xe1D=\xbd\x95\xccA#\u007fa:HEi\x88\xa0Oh2\x82\x89\xd8\xd8X?\xa2\xd5/\x00\x00\u07d4\xe1F\x17\xf6\x02%\x01\xe9~{>-\x886\xaaa\xf0\xff-\xba\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xe1I\xb5rl\xafm^\xb5\xbf*\xccA\xd4\xe2\xdc2\x8d\u1089i*\xe8\x89p\x81\xd0\x00\x00\xe0\x94\xe1T\xda\xea\xdbTX8\xcb\u01aa\fUu\x19\x02\xf5(h*\x8a\x01\n\xfc\x1a\xde;N\xd4\x00\x00\u07d4\xe1l\xe3Ya\xcdt\xbdY\r\x04\u012dJ\x19\x89\xe0V\x91\u0189\a\xea(2uw\b\x00\x00\u07d4\xe1r\xdf\xc8\xf8\f\xd1\xf8\u03459\xdc&\b \x14\xf5\xa8\xe3\u8262\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xe1w\xe0\xc2\x01\xd35\xba9V\x92\x9cW\x15\x88\xb5\x1cR#\xae\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe1x\x12\xf6l^e\x94\x1e\x18lF\x92+n{/\x0e\xebF\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4\xe1\x80\u079e\x86\xf5{\xaf\xac\u05d0O\x98&\xb6\xb4\xb2c7\xa3\x89-\x04\x1dpZ,`\x00\x00\xe0\x94\xe1\x92H\x9b\x85\xa9\x82\xc1\x882F\xd9\x15\xb2)\xcb\x13 \u007f8\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\xe1\x95\xbb\xc6,{tD\x04\x0e\xb9\x96#\x96Ovg\xb3v\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xe2\x06\xfbs$\xe9\u07b7\x9e\x19\x904\x96\u0596\x1b\x9b\xe5f\x03\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xe2\aW\x8e\x1fM\u06cf\xf6\u0546{9X-q\xb9\x81*\u0149\xd2U\xd1\x12\xe1\x03\xa0\x00\x00\u07d4\xe2\b\x81*h@\x98\xf3\xdaN\xfej\xba%bV\xad\xfe?\xe6\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xe2\tT\xd0\xf4\x10\x8c\x82\xd4\u0732\x14\x8d&\xbb\xd9$\xf6\xdd$\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xe2\v\xb9\xf3\x96d\x19\xe1K\xbb\xaa\xaag\x89\xe9$\x96\u03e4y\x89\xbb\xd8%\x03\aRv\x00\x00\u07d4\xe2\r\x1b\xcbq(m\xc7\x12\x8a\x9f\xc7\xc6\xed\u007fs8\x92\xee\xf5\x896d\xf8\xe7\xc2J\xf4\x00\x00\u0794\xe2\x19\x12\x15\x98?3\xfd3\xe2,\u0522I\x00T\xdaS\xfd\u0708\xdbD\xe0I\xbb,\x00\x00\u07d4\xe2\x19\x8c\x8c\xa1\xb3\x99\xf7R\x15a\xfdS\x84\xa7\x13/\xbaHk\x897\b\xba\xed=h\x90\x00\x00\xe0\x94\xe2\x1cw\x8e\xf2\xa0\xd7\xf7Q\xea\x8c\aM\x1f\x81\"C\x86>N\x8a\x01\x1f\xc7\x0e,\x8c\x8a\xe1\x80\x00\xe0\x94\xe2)\xe7F\xa8?,\xe2S\xb0\xb0>\xb1G$\x11\xb5~W\x00\x8a\x016\x9f\xb9a(\xacH\x00\x00\u07d4\xe2+ \xc7x\x94F;\xafwL\xc2V\u057d\u06ff}\xdd\t\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xe20\xfe\x1b\xff\x03\x18m\x02\x19\xf1]LH\x1b}Y\xbe(j\x89\x01\xfdt\x1e\x80\x88\x97\x00\x00\u07d4\xe27\xba\xa4\xdb\u0252n2\xa3\xd8]\x12d@-T\xdb\x01/\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe2A\t\xbe/Q=\x87I\x8e\x92j(d\x99uO\x9e\u051e\x890\x0e\xa8\xad\x1f'\xca\x00\x00\u07d4\xe2Fh<\u025d\xb7\u0125+\u02ec\xaa\xb0\xb3/k\xfc\x93\u05c9lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xe2Z\x16{\x03\x1e\x84am\x0f\x01?1\xbd\xa9]\xcccP\xb9\x8a\x02\x8c*\xaa\u0243\xd0]\u0187st\xa8\xf4F\xee\xe9\x89\n\xb6@9\x12\x010\x00\x00\u07d4\xe2\x8b\x06\"Y\xe9n\xeb<\x8dA\x04\x94?\x9e\xb3%\x89<\xf5\x89Hz\x9a0E9D\x00\x00\xe0\x94\u237c\x8e\xfd^Ajv.\xc0\xe0\x18\x86K\xb9\xaa\x83({\x8a\x051\xf2\x00\xab>\x03\n\x80\x00\u07d4\xe2\x90K\x1a\xef\xa0V9\x8bb4\xcb5\x81\x12\x88\xd76\xdbg\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\u274a\xe4R\xdc\xf3\xb6\xacd^c\x04\t8UQ\xfa\xae\n\x89\x04Z\r\xa4\xad\xf5B\x00\x00\u07d4\xe2\xbb\xf8FA\xe3T\x1fl3\xe6\xedh:cZp\xbd\xe2\xec\x89\x1bA<\xfc\xbfY\xb7\x80\x00\u07d4\xe2\xcf6\n\xa22\x9e\xb7\x9d+\xf7\xca\x04\xa2z\x17\xc52\xe4\u0609\x05\x87\x88\u02d4\xb1\xd8\x00\x00\u07d4\xe2\xdf#\xf6\xea\x04\xbe\xcfJ\xb7\x01t\x8d\xc0\x961\x84U\\\u06c9lk\x93[\x8b\xbd@\x00\x00\u07d4\xe2\xe1\\`\xdd8\x1e:K\xe2Pq\xab$\x9aL\\Rd\u0689\u007fk\u011b\x81\xb57\x00\x00\u07d4\xe2\xe2nN\x1d\xcf0\xd0H\xccn\u03ddQ\xec\x12\x05\xa4\xe9&\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\xe2\xeei\x1f#~\xe6R\x9beW\xf2\xfc\xdd=\xcf\fY\xecc\x8a\x01'r\x9c\x14h| \x00\x00\u07d4\xe2\xef\xa5\xfc\xa7\x958\xce`h\xbf1\xd2\xc5\x16\xd4\xd5<\b\xe5\x89\a\x1c\xc4\b\xdfc@\x00\x00\xe0\x94\xe2\xef\u0429\xbc@~\xce\x03\xd6~\x8e\xc8\xe9\u0483\xf4\x8d*I\x8a\x02\x99\xb3;\xf9\u0144\xe0\x00\x00\u07d4\xe2\xf4\r5\x8f^?\xe7F>\xc7\x04\x80\xbd.\u04d8\xa7\x06;\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xe2\xf98=X\x10\xea{C\x18+\x87\x04\xb6+'\xf5\x92]9\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xe2\xff\x9e\xe4\xb6\xec\xc1AA\xcct\xcaR\xa9\xe7\xa2\xee\x14\xd9\b\x89K\xe4\xe7&{j\xe0\x00\x00\xe0\x94\xe3\x02\x12\xb2\x01\x1b\xb5k\xdb\xf1\xbc5i\x0f:N\x0f\xd9\x05\xea\x8a\x01\xb2\u07dd!\x9fW\x98\x00\x00\u07d4\xe3\x03\x16\u007f=I`\xfe\x88\x1b2\x80\n+J\xef\xf1\xb0\x88\u0509lk\x93[\x8b\xbd@\x00\x00\u07d4\xe3\x04\xa3/\x05\xa87btJ\x95B\x97o\xf9\xb7#\xfa1\xea\x89Ur\xf2@\xa3F \x00\x00\u07d4\xe3\bCR\x04y7d\xf5\xfc\xbee\xebQ\x0fZtJeZ\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xe3\t\x97L\xe3\x9d`\xaa\xdf.ig2Q\xbf\x0e\x04v\n\x10\x89\r\xc5_\xdb\x17d{\x00\x00\u07d4\xe3\x1bN\xef\x18L$\xab\t\x8e6\xc8\x02qK\xd4t=\xd0\u0509\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xe3!\xbbJ\x94j\xda\xfd\xad\xe4W\x1f\xb1\\\x00C\u04de\xe3_\x89Udu8+L\x9e\x00\x00\u07d4\xe3&<\xe8\xafm\xb3\xe4gXE\x02\xedq\t\x12^\xae\"\xa5\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe3+\x1cG%\xa1\x87TI\u93d7\x0e\xb3\xe5@b\xd1X\x00\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xe3/\x95vmW\xb5\xcdK\x172\x89\u0587o\x9edU\x81\x94\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xe38@\u063c\xa7\u0698\xa6\xf3\u0416\xd8=\xe7\x8bp\xb7\x1e\xf8\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe38\xe8Y\xfe.\x8c\x15UHH\xb7\\\xae\u0368w\xa0\xe82\x89a\xac\xff\x81\xa7\x8a\xd4\x00\x00\u07d4\xe3=\x98\x02 \xfa\xb2Y\xafj\x1fK8\xcf\x0e\xf3\xc6\xe2\xea\x1a\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xe3=\xf4\u0380\u0336*v\xb1+\xcd\xfc\xec\xc4b\x89\x97:\xa9\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94\xe3?\xf9\x87T\x1d\xde\\\xde\u0a29m\xcc?3\xc3\xf2L\u008a*Z\x05\x8f\u0095\xed\x00\x00\x00\u07d4\xe3A\v\xb7U|\xf9\x1dy\xfai\xd0\xdf\xea\n\xa0u@&Q\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe3Ad-@\u04af\xce.\x91\a\xc6py\xacz&`\bl\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xe3TS\xee\xf2\xcc2\x89\x10CR\x8d\t\x84i\x80\x00\xe0\x94\xe5\x10\xd6y\u007f\xba=f\x93\x83Z\x84N\xa2\xadT\x06\x91\x97\x1b\x8a\x03\xae9\xd4s\x83\xe8t\x00\x00\u07d4\xe5\x14!\xf8\xee\"\x10\xc7\x1e\xd8p\xfea\x82v\u0215J\xfb\xe9\x89Hz\x9a0E9D\x00\x00\u07d4\xe5\x1e\xb8~\u007f\xb71\x1fR(\xc4y\xb4\x8e\u0247\x881\xacL\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe5!V1\xb1BH\xd4Z%R\x96\xbe\xd1\xfb\xfa\x030\xff5\x89G\x03\xe6\xebR\x91\xb8\x00\x00\xe0\x94\xe5(\xa0\xe5\xa2g\xd6g\xe99:e\x84\xe1\x9b4\u071b\xe9s\x8a\x01/\x93\x9c\x99\xed\xab\x80\x00\x00\u07d4\xe54%\xd8\xdf\x1f\x11\xc3A\xffX\xae_\x148\xab\xf1\xcaS\u03c9\x11t\xa5\xcd\xf8\x8b\xc8\x00\x00\u07d4\xe5No\x9c\xffV\xe1\x9cF\x1e\xb4T\xf9\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xe5A\x02SM\xe8\xf2>\xff\xb0\x93\xb3\x12B\xad;#?\xac\xfd\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xe5E\xee\x84\xeaH\xe5d\x16\x1e\x94\x82\u055b\xcf@j`,\xa2\x89dI\xe8NG\xa8\xa8\x00\x00\u07d4\xe5H\x1a\u007f\xedB\xb9\x01\xbb\xed x\x9b\u052d\xe5\r_\x83\xb9\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe5Y\xb5\xfd3{\x9cUr\xa9\xbf\x9e\x0f%!\xf7\xd4F\xdb\xe4\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xe5\\\x80R\n\x1b\x0fu[\x9a,\xd3\xce!Ov%e>\x8a\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xe5mC\x13$\xc9)\x11\xa1t\x9d\xf2\x92p\x9c\x14\xb7ze\u034a\x01\xbc\x85\xdc*\x89\xbb \x00\x00\u07d4\xe5})\x95\xb0\xeb\xdf?<\xa6\xc0\x15\xeb\x04&\r\xbb\x98\xb7\u0189lk\x93[\x8b\xbd@\x00\x00\u07d4\u51f1j\xbc\x8at\b\x1e6\x13\xe1CB\xc03u\xbf\bG\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe5\x89\xfav\x98M\xb5\xec@\x04\xb4n\u8954\x92\xc3\aD\u0389\x97\xc9\xceL\xf6\xd5\xc0\x00\x00\u07d4\xe5\x8d\xd228\xeen\xa7\xc2\x13\x8d8]\xf5\x00\xc3%\xf3v\xbe\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4\xe5\x95?\xeaIq\x04\xef\x9a\xd2\xd4\xe5\x84\x1c'\x1f\a5\x19\u0089&)\xf6n\fS\x00\x00\x00\xe0\x94\u5587\x97F\x8e\xf7g\x10\x1bv\x1dC\x1f\xce\x14\xab\xff\u06f4\x8a\x01\xb3\xd9i\xfaA\x1c\xa0\x00\x00\u07d4\xe5\x97\xf0\x83\xa4i\xc4Y\x1c=+\x1d,w'\x87\xbe\xfe'\xb2\x89\x0f-\xc7\xd4\u007f\x15`\x00\x00\u07d4\xe5\x9b;\xd3\x00\x89?\x97#>\xf9G\xc4or\x17\xe3\x92\xf7\xe9\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xe5\xa3e4<\xc4\xeb\x1ew\x03h\xe1\xf1\x14Jw\xb82\xd7\xe0\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xe5\xa3\xd7\xeb\x13\xb1\\\x10\x01w#m\x1b\xeb0\xd1~\xe1T \x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe5\xaa\v\x83;\xb9\x16\xdc\x19\xa8\xddh?\x0e\xde$\x1d\x98\x8e\xba\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\u5def\x14i\x86\xc0\xff\x8f\x85\xd2.l\xc34\a}\x84\xe8$\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe5\xb8&\x19l\x0e\x1b\xc1\x11\x9b\x02\x1c\xf6\xd2Y\xa6\x10\u0256p\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xe5\xb9o\u026c\x03\xd4H\xc1a:\xc9\x1d\x15\x97\x81E\xdb\xdf\u0449\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\u5e40\u048e\xec\xe2\xc0o\xcal\x94s\x06\x8b7\u0526\xd6\xe9\x89%\xaf\u058c\xac+\x90\x00\x00\u07d4\u5eb4\xf0\xaf\u0629\u0463\x81\xb4Wa\xaa\x18\xf3\xd3\xcc\xe1\x05\x89Q\xbf\xd7\xc18x\xd1\x00\x00\u07d4\xe5\xbc\u020c;%on\xd5\xfeU\x0eJ\x18\x19\x8b\x943V\xad\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe5\xbd\xf3OL\xccH>L\xa50\xcc|\xf2\xbb\x18\xfe\xbe\x92\xb3\x89\x06\xd85\xa1\v\xbc\xd2\x00\x00\u07d4\xe5\u0713I\xcbR\xe1a\x19a\"\u03c7\xa3\x896\xe2\xc5\u007f4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe5\xe38\x00\xa1\xb2\xe9k\xde\x101c\n\x95\x9a\xa0\a\xf2nQ\x89Hz\x9a0E9D\x00\x00\u07d4\xe5\xe3~\x19@\x8f,\xfb\xec\x834\x9d\u0501S\xa4\xa7\x95\xa0\x8f\x89\u3bb5sr@\xa0\x00\x00\u07d4\xe5\xed\xc7>bo]4A\xa4U9\xb5\xf7\xa3\x98\u0153\xed\xf6\x89.\xe4IU\b\x98\xe4\x00\x00\u07d4\xe5\xed\xf8\x12?$\x03\xce\x1a\x02\x99\xbe\xcfz\xactM\a_#\x89\n\xdaUGK\x814\x00\x00\u07d4\xe5\xf8\xefm\x97\x066\xb0\u072aO \x0f\xfd\xc9\xe7Z\xf1t\x1c\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe5\xfb1\xa5\xca\xeej\x96\xde9;\xdb\xf8\x9f\xbee\xfe\x12[\xb3\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xe5\xfb\xe3I\x84\xb67\x19o3\x1cg\x9d\f\fG\xd84\x10\xe1\x89llD\xfeG\xec\x05\x00\x00\u07d4\xe6\tU\xdc\v\xc1V\xf6\xc4\x18I\xf6\xbdwk\xa4K\x0e\xf0\xa1\x89\x10C\x16'\xa0\x93;\x00\x00\u07d4\xe6\nU\xf2\u07d9m\u00ee\xdbil\b\xdd\xe09\xb2d\x1d\xe8\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xe6\x11[\x13\xf9y_~\x95e\x02\xd5\aEg\u06b9E\xcek\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\xe6\x1f(\t\x15\xc7t\xa3\x1d\"<\xf8\f\x06\x92f\xe5\xad\xf1\x9b\x89/\xb4t\t\x8fg\xc0\x00\x00\u07d4\xe6/\x98e\a\x12\xeb\x15\x87S\xd8)r\xb8\u9723\xf6\x18w\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xe6/\x9d|d\xe8\xe2cZ\xeb\x88=\xd7;\xa6\x84\xee|\x10y\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xe6>xt\x14\xb9\x04\x84x\xa5\a35\x9e\xcd\xd7\xe3dz\xa6\x89U\xa6\xe7\x9c\xcd\x1d0\x00\x00\u07d4\xe6FfXr\xe4\v\rz\xa2\xff\x82r\x9c\xaa\xba[\xc3\u8789\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xe6N\xf0\x12e\x8dT\xf8\xe8`\x9cN\x90#\xc0\x9f\xe8e\xc8;\x89\x01\x84\x93\xfb\xa6N\xf0\x00\x00\u07d4\xe6On\x1dd\x01\xb5l\akd\xa1\xb0\x86}\v/1\rN\x89\x02\u02edq\xc5:\xe5\x00\x00\u07d4\xe6g\xf6R\xf9W\u008c\x0ef\u04364\x17\xc8\f\x8c\x9d\xb8x\x89 \x9d\x92/RY\xc5\x00\x00\xe0\x94\xe6w\xc3\x1f\xd9\xcbr\x00u\u0724\x9f\x1a\xbc\xcdY\xec3\xf74\x8a\x01\xa6\u05be\xb1\xd4.\xe0\x00\x00\u07d4\xe6|,\x16e\u02038h\x81\x87b\x9fI\xe9\x9b`\xb2\u04fa\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xe6\x9al\xdb:\x8a}\xb8\xe1\xf3\f\x8b\x84\xcds\xba\xe0+\xc0\xf8\x8a\x03\x94\xfd\xc2\xe4R\xf6q\x80\x00\u07d4\xe6\x9d\x1c7\x8bw\x1e\x0f\xef\xf0Q\xdbi\xd9f\xacgy\xf4\xed\x89\x1d\xfaj\xaa\x14\x97\x04\x00\x00\u07d4\xe6\x9f\xcc&\xed\"_{.7\x984\xc5$\xd7\f\x175\u5f09lk\x93[\x8b\xbd@\x00\x00\u07d4\xe6\xa3\x01\x0f\x02\x01\xbc\x94\xffg\xa2\xf6\x99\xdf\xc2\x06\xf9\xe7gB\x89/\xa7\xcb\xf6dd\x98\x00\x00\u07d4\xe6\xa6\xf6\xddop\xa4V\xf4\xec\x15\xefz\xd5\xe5\u06f6\x8b\xd7\u0709\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xe6\xb2\x0f\x98\n\xd8S\xad\x04\xcb\xfc\x88|\xe6`\x1ck\xe0\xb2L\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\u6cec?]M\xa5\xa8\x85}\v?0\xfcK+i+w\u05c9O%\x91\xf8\x96\xa6P\x00\x00\u07d4\xe6\xb9T_~\u0406\xe5R\x92F9\xf9\xa9\xed\xbb\xd5T\v>\x89\xcb\xd4{n\xaa\x8c\xc0\x00\x00\xe0\x94\xe6\xbc\xd3\n\x8f\xa18\xc5\xd9\xe5\xf6\xc7\xd2\u0680i\x92\x81-\u034a7\x0e\xa0\xd4|\xf6\x1a\x80\x00\x00\u07d4\xe6\xc8\x1f\xfc\xec\xb4~\xcd\xc5\\\vq\xe4\x85_>^\x97\xfc\x1e\x89\x12\x1e\xa6\x8c\x11NQ\x00\x00\u07d4\xe6\xcb&\vqmL\n\xb7&\xee\xeb\a\xc8pr\x04\xe2v\xae\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xe6\xcb?1$\xc9\xc9\xcc84\xb1'K\xc33dV\xa3\x8b\xac\x89\x17+\x1d\xe0\xa2\x13\xff\x00\x00\xe0\x94\xe6\xd2\"\t\xff\u0438u\t\xad\xe3\xa8\xe2\xefB\x98y\u02c9\xb5\x8a\x03\xa7\xaa\x9e\x18\x99\xca0\x00\x00\u07d4\xe6\u051f\x86\xc2(\xf4sg\xa3^\x88l\xaa\xcb'\x1eS\x94)\x89\x16^\xc0\x9d\xa7\xa1\x98\x00\x00\u07d4\xe6\xe6!\xea\xab\x01\xf2\x0e\xf0\x83k|\xadGFL\xb5\xfd<\x96\x89\x11!\x93B\xaf\xa2K\x00\x00\u07d4\xe6\xe8\x861{jf\xa5\xb4\xf8\x1b\xf1d\xc58\xc2d5\x17e\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe6\u98ddu\x0f\xe9\x949N\xb6\x82\x86\xe5\xeab\xa6\x99x\x82\x89 \x86\xac5\x10R`\x00\x00\xe0\x94\xe6\xec\\\xf0\u011b\x9c1~\x1epc\x15\uf7b7\xc0\xbf\x11\xa7\x8a\x03\xa4i\xf3F~\x8e\xc0\x00\x00\u07d4\xe6\xf5\xebd\x9a\xfb\x99Y\x9cAK'\xa9\xc9\xc8U5\u007f\xa8x\x89\x90\xf54`\x8ar\x88\x00\x00\xe0\x94\xe6\xfe\n\xfb\x9d\xce\xdd7\xb2\xe2,E\x1b\xa6\xfe\xabg4\x803\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xe7\x10\xdc\u041b\x81\x01\xf9C{\xd9}\xb9\ns\xef\x99=\v\xf4\x89\x14\xee6\xc0Z\xc2R\x00\x00\u07d4\xe7'\xe6~\xf9\x11\xb8\x1fl\xf9\xc7?\xcb\xfe\xbc+\x02\xb5\xbf\u0189lk\x93[\x8b\xbd@\x00\x00\u07d4\xe7.\x1d3\\\u009a\x96\xb9\xb1\xc0/\x00:\x16\xd9q\xe9\v\x9d\x89U\xa6\xe7\x9c\xcd\x1d0\x00\x00\u07d4\xe71\x1c\x953\xf0\t,rH\xc9s\x9b[,\x86J4\xb1\u0389\x97\xf9}l\xc2m\xfe\x00\x00\u07d4\xe7;\xfe\xad\xa6\xf0\xfd\x01o\xbc\x84>\xbc\xf6\xe3p\xa6[\xe7\f\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xe7<\xcfCg%\xc1Q\xe2U\xcc\xf5!\f\xfc\xe5\xa4?\x13\xe3\x89\x01\x15NS!}\xdb\x00\x00\u07d4\xe7B\xb1\xe6\x06\x9a\x8f\xfc'\f\xc6\x1f\xa1d\xac\x15SE\\\x10]\x04\x88~\x14\x89\x06\x96\xd8Y\x00 \xbb\x00\x00\u07d4\xe7\\\x1f\xb1w\b\x9f>X\xb1\x06y5\xa6Yn\xf1s\u007f\xb5\x89\x05j\x87\x9f\xa7uG\x00\x00\u07d4\xe7\\;8\xa5\x8a?3\xd5V\x90\xa5\xa5\x97f\xbe\x18^\x02\x84\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xe7a\xd2\u007f\xa3P,\xc7k\xb1\xa6\bt\x0e\x14\x03\u03dd\xfci\x89\x0f-\xc7\xd4\u007f\x15`\x00\x00\u07d4\xe7f\xf3O\xf1o<\xfc\xc9s!r\x1fC\xdd\xf5\xa3\x8b\f\xf4\x89T\x06\x923\xbf\u007fx\x00\x00\u07d4\xe7m\x94Z\xa8\x9d\xf1\xe4W\xaa4+1\x02\x8a^\x910\xb2\u03897\b\xba\xed=h\x90\x00\x00\u07d4\xe7s^\xc7e\x18\xfcj\xa9-\xa8qZ\x9e\xe3\xf6%x\x8f\x13\x89lM\x16\v\xaf\xa1\xb7\x80\x00\xe0\x94\xe7z\x89\xbdE\xdc\x04\xee\xb4\xe4\x1d{Ykp~nQ\xe7L\x8a\x02\x8a\x85t%Fo\x80\x00\x00\u07d4\xe7}}\uac96\u0234\xfa\a\xca;\xe1\x84\x16=Zm`l\x89\x05\x049\x04\xb6q\x19\x00\x00\u07d4\xe7\u007f\xeb\xab\xdf\b\x0f\x0f]\xca\x1d?Wf\xf2\xa7\x9c\x0f\xfa|\x89K\"\x9d(\xa8Ch\x00\x00\xe0\x94\u7025c\x06\xba\x1ek\xb31\x95,\"S\x9b\x85\x8a\xf9\xf7}\x8a\n\x96\x81c\xf0\xa5{@\x00\x00\u07d4\xe7\x81\xecs-@\x12\x02\xbb\x9b\xd18`\x91\r\xd6\u009a\xc0\xb6\x89C8t\xf62\xcc`\x00\x00\u07d4\xe7\x84\xdc\xc8s\xaa\x8c\x15\x13\xec&\xff6\xbc\x92\xea\xc6\xd4\xc9h\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xe7\x91-L\xf4V,W=\xdc[q\xe3s\x10\xe3x\xef\x86\u0249\x15[\xd90\u007f\x9f\xe8\x00\x00\u07d4\xe7\x91\u0545\xb8\x996\xb2])\x8f\x9d5\xf9\xf9\xed\xc2Z)2\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe7\x924\x9c\xe9\xf6\xf1O\x81\xd0g@\x96\xbe\xfa\x1f\x92!\xcd\xea\x89[]#J\r\xb48\x80\x00\u07d4\xe7\x96\xfdN\x83\x9bL\x95\xd7Q\x0f\xb7\xc5\xc7+\x83\xc6\xc3\xe3\u01c9\x1b\xc43\xf2?\x83\x14\x00\x00\xe0\x94\xe7\xa4/Y\xfe\xe0t\xe4\xfb\x13\xea\x9eW\xec\xf1\xccH(\"I\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xe7\xa4V\f\x84\xb2\x0e\x0f\xb5LIg\f)\x03\xb0\xa9lB\xa4\x89 j\xea\u01e9\x03\x98\x00\x00\u07d4\xe7\xa8\xe4q\xea\xfby\x8fET\xccnRg0\xfdV\xe6,}\x8965\u026d\xc5\u07a0\x00\x00\u07d4\u7f82\xc6Y<\x1e\xed\xdd*\xe0\xb1P\x01\xff \x1a\xb5{/\x89\x01\t\x10\xd4\xcd\xc9\xf6\x00\x00\u07d4\xe7\u01b5\xfc\x05\xfct\x8e[C\x81rdI\xa1\xc0\xad\x0f\xb0\xf1\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe7\xd1u$\xd0\v\xad\x82I|\x0f'\x15jd\u007f\xf5\x1d'\x92\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xe7\xd2\x13\x94\u007f\u02d0J\xd78H\v\x1e\xed/\\2\x9f'\xe8\x89\x01\x03\u00f1\xd3\xe9\xc3\x00\x00\u07d4\xe7\xd6$\x06 \xf4,^\u06f2\xed\xe6\xae\xc4=\xa4\xed\x9bWW\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xe7\xda`\x9d@\xcd\xe8\x0f\x00\xce[O\xfbj\xa9\u04304\x94\xfc\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xe7\xf0oi\x9b\xe3\x1cD\vC\xb4\xdb\x05\x01\xec\x0e%&\x16D\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xe7\xf4\xd7\xfeoV\x1f\u007f\xa1\xda0\x05\xfd6TQ\xad\x89\u07c9\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xe7\xfd\x8f\xd9Y\xae\xd2v~\xa7\xfa\x96\f\xe1\xdbS\xaf\x80%s\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xe8\x0e\u007f\xef\x18\xa5\xdb\x15\xb0\x14s\xf3\xadkx\xb2\xa2\xf8\xac\u0649\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xe8\x13\u007f\xc1\xb2\xec|\xc7\x10:\xf9!\x89\x9bJ9\xe1\xd9Y\xa1\x89P\xc5\xe7a\xa4D\b\x00\x00\u07d4\xe8\x1c-4l\n\xdfL\xc5g\b\xf69K\xa6\xc8\u0226J\x1e\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe8,X\xc5yC\x1bg5F\xb5:\x86E\x9a\xca\xf1\u079b\x93\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xe84\xc6C\x18 \\\xa7\xddJ!\xab\xcb\b&l\xb2\x1f\xf0,\x8965\xc6 G9\u0640\x00\u07d4\xe86\x04\xe4\xffk\xe7\xf9o`\x18\xd3\xec0r\xecR]\xffk\x89\t\xdd\xc1\xe3\xb9\x01\x18\x00\x00\xe0\x94\xe8E\xe3\x87\xc4\xcb\u07d8\"\x80\xf6\xaa\x01\xc4\x0eK\xe9X\u0772\x8a\x05K@\xb1\xf8R\xbd\xa0\x00\x00\u07d4\xe8H\xca~\xbf\xf5\xc2O\x9b\x9c1g\x97\xa4;\xf7\xc3V)-\x89\x06.\x11\\\x00\x8a\x88\x00\x00\u07d4\xe8KU\xb5%\xf1\x03\x9etK\x91\x8c\xb33$\x92\xe4^\xcaz\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xe8O\x80v\xa0\xf2\x96\x9e\xcd3>\xef\x8d\xe4\x10B\x98b\x91\xf2\x89\x17k4O*x\xc0\x00\x00\u07d4\xe8d\xfe\xc0~\xd1!Je1\x1e\x11\xe3)\xde\x04\r\x04\xf0\xfd\x89Y\u0283\xf5\xc4\x04\x96\x80\x00\u07d4\xe8}\xba\xc66\xa3w!\xdfT\xb0\x8a2\xefIY\xb5\xe4\xff\x82\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xe8~\x9b\xbf\xbb\xb7\x1c\x1at\ft\xc7#Bm\xf5]\x06=\u064a\x01\xb1\x92\x8c\x00\u01e68\x00\x00\u07d4\xe8~\xacm`+A\t\xc9g\x1b\xf5{\x95\f,\xfd\xb9\x9dU\x89\x02\xb4\xf2\x19r\xec\xce\x00\x00\xe0\x94\u807b\xbeir-\x81\xef\xec\xaaH\u0455*\x10\xa2\xbf\xac\x8f\x8a\x03c\\\x9a\xdc]\xea\x00\x00\x00\u07d4\xe8\x92Is\x8b~\xce\xd7\xcbfjf\xe4s\xbcv\x82/U\t\x8d\x89\xb9\x1c\u0149lk\x93[\x8b\xbd@\x00\x00\u07d4\xe8\xc3\u04f0\xe1\u007f\x97\xd1\xe7V\xe6\x84\xf9N\x14p\xf9\x9c\x95\xa1\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\xe0\x94\xe8\xc3\xf0E\xbb}8\xc9\xd2\U000d5c3a\x84\x92\xb2S#\t\x01\x8a\x01\xe7\xe4\x17\x1b\xf4\u04e0\x00\x00\u07d4\xe8\xccC\xbcO\x8a\xcf9\xbf\xf0N\xbf\xbfB\xaa\xc0j2\x84p\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xe8\xd9B\xd8/\x17^\xcb\x1c\x16\xa4\x05\xb1\x01C\xb3\xf4k\x96:\x89\x1e\xd2\xe8\xffm\x97\x1c\x00\x00\u07d4\xe8\u077e\xd72\xeb\xfeu@\x96\xfd\xe9\bk\x8e\xa4\xa4\xcd\xc6\x16\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe8\xder^\xca]\xef\x80_\xf7\x94\x1d1\xac\x1c.4-\xfe\x95\x89\x85~\ro\x1d\xa7j\x00\x00\u07d4\xe8\xe9\x85\x05\x86\xe9OR\x99\xabIK\xb8!\xa5\xf4\f\x00\xbd\x04\x89\xcf\x15&@\xc5\xc80\x00\x00\xe0\x94\xe8\xea\u047b\x90\xcc\u00ee\xa2\xb0\xdc\u0175\x80VUFU\xd1\u054a\x01\xa4\xab\xa2%\xc2\a@\x00\x00\u07d4\xe8\xea\xf1)D\t-\xc3Y\x9b9S\xfa|\xb1\xc9v\x1c\xc2F\x89a\x94\x04\x9f0\xf7 \x00\x00\xe0\x94\xe8\xedQ\xbb\xb3\xac\xe6\x9e\x06\x02K3\xf8hD\xc4sH\u06de\x8a\"\xf9\xea\x89\xf4\xa7\xd6\xc4\x00\x00\u07d4\xe8\xef\x10\r|\xe0\x89X2\xf2g\x8d\xf7-J\u03cc(\xb8\xe3\x89\x1b\x1bk\u05efd\xc7\x00\x00\u07d4\xe8\xf2\x99i\xe7\\e\xe0\x1c\xe3\xd8aT }\n\x9e|v\xf2\x89\xa2/\xa9\xa7:'\x19\x80\x00\u07d4\xe8\xfc6\xb0\x13\x1e\xc1 \xac\x9e\x85\xaf\xc1\f\xe7\vV\u0636\xba\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xe9\n5L\xec\x04\u059e]\x96\xdd\xc0\xc5\x13\x8d=3\x15\n\xa0\x89\x1b\x1a}\u03caD\u04c0\x00\xe0\x94\xe9\x13>}1\x84]_+f\xa2a\x87\x92\xe8i1\x1a\xcff\x8a\x05\x17\xc0\xcb\xf9\xa3\x90\x88\x00\x00\u07d4\xe9\x1d\xac\x01\x95\xb1\x9e7\xb5\x9bS\xf7\xc0\x17\xc0\xb29[\xa4L\x89e\xea=\xb7UF`\x00\x00\u07d4\xe9\x1f\xa0\xba\xda\u0779\xa9~\x88\xd3\xf4\xdb|U\u05bbt0\xfe\x89\x14b\fW\xdd\xda\xe0\x00\x00\u07d4\xe9#\xc0aw\xb3B~\xa4H\xc0\xa6\xff\x01\x9bT\xccT\x8d\x95\x89\x01\xf7\x80\x01Fg\xf2\x80\x00\xe0\x94\xe9=G\xa8\u0288]T\fNRo%\xd5\xc6\xf2\xc1\b\u0138\x8a\x17\xda:\x04\u01f3\xe0\x00\x00\x00\u07d4\xe9E\x8fh\xbb',\xb5g:\x04\xf7\x81\xb4\x03Uo\u04e3\x87\x89\x03N\x8b\x88\xce\xe2\xd4\x00\x00\u07d4\xe9IA\xb6\x03`\x19\xb4\x01j0\xc1\x03}Zi\x03\xba\xba\xad\x89*H\xac\xabb\x04\xb0\x00\x00\u07d4\xe9I[\xa5\x84'(\xc0\ud5fe7\xd0\xe4\"\xb9\x8di ,\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe9M\xed\x99\u0735r\xb9\xbb\x1d\u02e3/m\xee\x91\xe0W\x98N\x89\x15[\xd90\u007f\x9f\xe8\x00\x00\xe0\x94\xe9QyR}\uc951l\xa9\xa3\x8f!\\\x1e\x9c\xe77\xb4\u024a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94\xe9U\x91\x85\xf1f\xfc\x95\x13\xccq\x11aD\xce-\xeb\x0f\x1dK\x8a\x04<3\xc1\x93ud\x80\x00\x00\u0794\xe9^\x92\xbb\xc6\xde\a\xbf:f\x0e\xbf_\xeb\x1c\x8a5'\xe1\u0148\xfc\x93c\x92\x80\x1c\x00\x00\xe0\x94\xe9e\u06a3@9\xf7\xf0\xdfb7Z7\u5acar\xb3\x01\xe7\x8a\x01\x03\xfd\xde\u0373\xf5p\x00\x00\u07d4\xe9i\xea\x15\x95\xed\xc5\u0127\a\xcf\xde8\t)c2Q\xa2\xb0\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xe9k\x18N\x1f\x0fT\x92J\xc8t\xf6\v\xbfDptF\xb7+\x89\x9d\xcc\x05\x15\xb5n\f\x00\x00\xe0\x94\xe9m}L\xdd\x15U:NM1mmd\x80\xca<\xea\x1e8\x8a\x02\x95]\x02\xe1\xa15\xa0\x00\x00\u07d4\xe9n-8\x13\xef\xd1\x16_\x12\xf6\x02\xf9\u007fJb\x90\x9d\x1b;\xc0\xe9\xaa\"\u007f\x90\x89'\xcaK\xd7\x19\xf0\xb8\x00\x00\u07d4\xea,\x19}&\xe9\x8b\r\xa8>\x1br\u01c7a\x8c\x97\x9d=\xb0\x89\x01\x11du\x9f\xfb2\x00\x00\xe0\x94\xea7y\xd1J\x13\xf6\u01c5f\xbc\xde@5\x91A:b9\u06ca)\xb7d2\xb9DQ \x00\x00\u07d4\xeaN\x80\x9e&j\xe5\xf1<\xdb\u33dd\x04V\xe68m\x12t\x89\xf3\xf2\v\x8d\xfai\xd0\x00\x00\xe0\x94\xeaS\xc9T\xf4\xed\x97\xfdH\x10\x11\x1b\u06b6\x9e\xf9\x81\xef%\xb9\x8a\x03\xa9\u057a\xa4\xab\xf1\xd0\x00\x00\u07d4\xeaS\xd2ed\x85\x9d\x9e\x90\xbb\x0eS\xb7\xab\xf5`\xe0\x16,8\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xea`Ci\x12\xdek\xf1\x87\u04e4r\xff\x8fS3\xa0\xf7\xed\x06\x89\x01\x11du\x9f\xfb2\x00\x00\u07d4\xea`T\x9e\xc7U?Q\x1d!I\xf2\xd4fl\xbd\x92C\xd9<\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xeaf\xe7\xb8M\u037f6\xee\xa3\xe7[\x858*u\xf1\xa1]\x96\x89]\xbc\x91\x91&o\x11\x80\x00\u07d4\xeahlPW\t<\x17\x1cf\u06d9\xe0\x1b\x0e\xce\xcb0\x86\x83\x89\x14\u0768],\xe1G\x80\x00\u07d4\xeaj\xfe,\xc9(\xac\x83\x91\xeb\x1e\x16_\xc4\x00@\xe3t!\u7262\u007f\xa0c\xb2\xe2\xe6\x80\x00\u07d4\xeay\x05}\xab\xef^d\xe7\xb4O\u007f\x18d\x8e~S7\x18\u0489\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xea|Mm\xc7)\xcdk\x15|\x03\xad#|\xa1\x9a \x93F\u00c9lk\x93[\x8b\xbd@\x00\x00\u07d4\xea\x81h\xfb\xf2%\xe7\x86E\x9c\xa6\xbb\x18\xd9c\xd2kPS\t\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xea\x81\u02868T\f\xd9\xd4\xd7=\x06\x0f,\xeb\xf2$\x1f\xfc>\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xea\x83\x17\x19yYB@A\xd9\xd7\xc6z>\xce\x1d\xbbx\xbbU\x89\x15[\xd90\u007f\x9f\xe8\x00\x00\u07d4\xea\x85'\xfe\xbf\xa1\xad\xe2\x9e&A\x93)\u04d3\xb9@\xbb\xb7\u0709lj\xccg\u05f1\xd4\x00\x00\u07d4\xea\x8f0\xb6\xe4\xc5\xe6R\x90\xfb\x98d%\x9b\u0159\x0f\xa8\ue289\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xea\x94\xf3(\b\xa2\uf29b\xf0\x86\x1d\x1d$\x04\xf7\xb7\xbe%\x8a\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xea\xa4\\\xea\x02\xd8},\xc8\xfd\xa9CN-\x98[\xd4\x03\x15\x84\x89h\x1f\xc2\xccn+\x8b\x00\x00\xe0\x94\uac3d\x14\x83\t\x18l\xf8\xcb\xd1;r2\xd8\tZ\u02c3:\x8a\x02C\x9a\x88\x1cjq|\x00\x00\u07d4\uaed0\xd3y\x89\xaa\xb3\x1f\xea\xe5G\xe0\xe6\xf3\x99\x9c\xe6\xa3]\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xea\xc0\x82~\xff\fn?\xf2\x8a}JT\xf6\\\xb7h\x9d{\x99\x89\x9a\xd9\u67ddGR\x00\x00\u07d4\xea\xc1H(&\xac\xb6\x11\x1e\x19\xd3@\xa4_\xb8QWk\xed`\x89\x01\xbe\x8b\xab\x04\u067e\x80\x00\xe0\x94\xea\xc1{\x81\xedQ\x91\xfb\b\x02\xaaT3s\x13\x83A\a\xaa\xa4\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xea\u00efW\x84\x92\u007f\u9958\xfcN\xec8\xb8\x10/7\xbcX\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xea\u01b9\x88BT.\xa1\v\xb7O&\xd7\xc7H\x8fi\x8bdR\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94\xea\xc7h\xbf\x14\xb8\xf9C.i\xea\xa8*\x99\xfb\xeb\x94\xcd\f\x9c\x8a\x14\u06f2\x19\\\xa2(\x90\x00\x00\u07d4\xea\xd2\x1c\x1d\xec\u03ff\x1c\\\xd9f\x88\xa2Gki\xba\a\xceJ\x89\x03\xf2M\x8eJ\x00p\x00\x00\u07d4\xea\xd4\xd2\xee\xfbv\xab\xaeU3\x96\x1e\xdd\x11@\x04\x06\xb2\x98\xfc\x89\xd2U\xd1\x12\xe1\x03\xa0\x00\x00\u07d4\xea\xd6Rb\xed]\x12-\xf2\xb2u\x14\x10\xf9\x8c2\xd1#\x8fQ\x89\x05\x83\x17\xedF\xb9\xb8\x00\x00\u07d4\xea\xd7P\x16\u3801Pr\xb6\xb1\b\xbc\xc1\xb7\x99\xac\xf08>\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xea\xea#\xaa\x05r\x00\xe7\xc9\xc1^\x8f\xf1\x90\xd0\xe6l\f\x0e\x83\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xea\xed\x16\xea\xf5\u06ab[\xf0)^^\a\u007fY\xfb\x82U\x90\v\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xea\xed\xcck\x8bib\xd5\xd9(\x8c\x15lW\x9dG\xc0\xa9\xfc\xff\x89\x04\x9b\x9c\xa9\xa6\x944\x00\x00\u07d4\xea\xf5#\x88Tn\xc3Z\xcaolc\x93\xd8\xd6\t\xde:K\xf3\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xeb\x10E\x8d\xac\xa7\x9eJk$\xb2\x9a\x8a\x8a\xdaq\x1b\u007f.\xb6\x89\u063beI\xb0+\xb8\x00\x00\u07d4\xeb\x1c\xea{E\u047dM\x0e*\x00{\u04ff\xb3Tu\x9e,\x16\x89\n\xbb\xcdN\xf3wX\x00\x00\u07d4\xeb%H\x1f\u035c\"\x1f\x1a\xc7\xe5\xfd\x1e\u0353\a\xa1b\x15\xb8\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\xe0\x94\xeb.\xf3\u04cf\xe6R@<\xd4\xc9\xd8^\xd7\xf0h,\xd7\xc2\u078a\t\x0fSF\b\xa7(\x80\x00\x00\xe0\x94\xeb;\xddY\xdc\u0765\xa9\xbb*\xc1d\x1f\xd0!\x80\xf5\xf3e`\x8a\x01e\xc9fG\xb3\x8a \x00\x00\u07d4\xeb<\xe7\xfc8\x1cQ\xdb}_\xbdi/\x8f\x9e\x05\x8aLp=\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xebE?Z:\xdd\u074a\xb5gP\xfa\xdb\x0f\xe7\xf9M\x9c\x89\xe7\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xebO\x00\xe2\x836\xea\t\x94%\x88\ueb12\x18\x11\xc5\"\x14<\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xebR\xab\x10U4\x922\x9c\x1cT\x83:\xe6\x10\xf3\x98\xa6[\x9d\x89\b=lz\xabc`\x00\x00\u07d4\xebW\r\xba\x97R'\xb1\xc4-n\x8d\xea,V\u026d\x96\x06p\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xebc\x94\xa7\xbf\xa4\u0489\x11\u0565\xb2>\x93\xf3^4\f\"\x94\x89\x04:w\xaa\xbd\x00x\x00\x00\u07d4\xebh\x10i\x1d\x1a\xe0\u045eG\xbd\"\u03be\u0cfa'\xf8\x8a\x89\x87\x85c\x15\xd8x\x15\x00\x00\u07d4\xebvBL\x0f\u0557\xd3\xe3A\xa9d*\xd1\xee\x11\x8b+W\x9d\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xeb| +F+|\u0145]t\x84u_n&\xefC\xa1\x15\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xeb\x83\\\x1a\x91\x18\x17\x87\x8a3\xd1gV\x9e\xa3\xcd\u04c7\xf3(\x8965\u026d\xc5\u07a0\x00\x00\u07d4\ub268\x82g\t\t\xcf7~\x9ex(n\xe9{\xa7\x8dF\u0089+|\xc2\xe9\xc3\"\\\x00\x00\xe0\x94\xeb\x90\u01d3\xb3S\x97a\xe1\xc8\x14\xa2\x96q\x14\x86\x92\x19>\xb4\x8a\x02\x8a\x85t%Fo\x80\x00\x00\u07d4\xeb\x9c\xc9\xfe\bi\xd2\u06b5,\u01ea\xe8\xfdW\xad\xb3_\x9f\xeb\x89j\x93\xbb\x17\xaf\x81\xf8\x00\x00\xe0\x94\ub8c8\xb0\xda'\xc8{\x1c\xc0\xea\xc6\xc5{,Z\vE\x9c\x1a\x8a\x01p\xa0\xf5\x04\x0eP@\x00\x00\u07d4\xeb\xaa!m\xe9\xccZC\x03\x17\a\xd3o\xe6\u057e\xdc\x05\xbd\xf0\x89j\xc5\xc6-\x94\x86\a\x00\x00\u07d4\xeb\xac+D\b\xefT1\xa1;\x85\b\xe8bP\x98!\x14\xe1E\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xeb\xb6,\xf8\xe2,\x88K\x1b(\xc6\xfa\x88\xfb\xbc\x17\x93\x8a\xa7\x87\x89+By\x84\x03\u0278\x00\x00\u07d4\xeb\xb7\xd2\xe1\x1b\u01b5\x8f\n\x8dE\xc2\xf6\xde0\x10W\n\u0211\x89\x01s\x17\x90SM\xf2\x00\x00\u07d4\xeb\xbbO,=\xa8\xbe>\xb6-\x1f\xfb\x1f\x95\x02a\u03d8\xec\u0689lk\x93[\x8b\xbd@\x00\x00\u07d4\xeb\xbdM\xb9\x01\x99R\u058b\x1b\x0fm\x8c\xf0h<\x008{\xb5\x89\x12\x04\x01V=}\x91\x00\x00\u07d4\xeb\xbe\xeb%\x91\x84\xa6\xe0\x1c\xcc\xfc\"\a\xbb\u0603xZ\xc9\n\x89!\x9b\xc1\xb0G\x83\xd3\x00\x00\u07d4\xeb\xd3V\x15j81#4=H\x84;\xff\xeda\x03\xe8f\xb3\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xeb\xd3{%ec\xe3\fo\x92\x89\xa8\xe2p/\bR\x88\b3\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\xeb\xe4l\xc3\xc3L2\xf5\xad\xd6\xc3\x19[\xb4\x86\xc4q>\xb9\x18\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xeb\xff\x84\xbb\xefB0q\xe6\x04\xc3a\xbb\xa6w\xf5Y=\xefN\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xec\t'\xba\xc7\xdc6f\x9c(5J\xb1\xbe\x83\xd7\xee\xc3\t4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xec\x0e\x18\xa0\x1d\xc4\xdc]\xaa\xe5g\xc3\xfaL\u007f\x8f\x9bY\x02\x05\x89\x11\x1f\xfe@JA\xe6\x00\x00\xe0\x94\xec\x116,\xec\x81\t\x85\xd0\xeb\xbd{sE\x14D\x98[6\x9f\x8a\x06ZNIWpW1\x80\x00\u07d4\xec,\xb8\xb97\x8d\xff1\xae\xc3\xc2.\x0em\xad\xff1J\xb5\u0749lk\x93[\x8b\xbd@\x00\x00\u07d4\xec0\xad\u0749[\x82\xee1\x9eT\xfb\x04\xcb+\xb09q\xf3k\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xec;\x8bX\xa1'\x03\xe5\x81\xce_\xfd~!\xc5}\x1e\\f?\x89\\(=A\x03\x94\x10\x00\x00\u07d4\xecHg\xd2\x17Z\xb5\xb9F\x93aYUFUF\x84\u0364`\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xecM\b\xaa.GIm\u0287\"]\xe3?+@\xa8\xa5\xb3o\x89\b\x90\xb0\xc2\xe1O\xb8\x00\x00\u07d4\xecX\xbc\r\f \xd8\xf4\x94efAS\xc5\xc1\x96\xfeY\u6f89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xec[\x19\x8a\x00\u03f5Z\x97\xb5\xd56D\xcf\xfa\x8a\x04\u04abE\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xec]\xf2'\xbf\xa8]z\xd7kBn\x1c\xee\x96;\xc7\xf5\x19\u074965\u026d\xc5\u07a0\x00\x00\xe0\x94\xec_\xea\xfe!\f\x12\xbf\u0265\xd0Y%\xa1#\xf1\xe7?\xbe\xf8\x8a`\x8f\xcf=\x88t\x8d\x00\x00\x00\u07d4\xeci\x04\xba\xe1\xf6\x97\x90Y\x17\t\xb0`\x97\x83s?%s\xe3\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94\xecs\x11L^@o\u06fe\t\xb4\xfab\x1b\xd7\x0e\xd5N\xa1\xef\x8a\x050%\xcd!o\xceP\x00\x00\u07d4\xecs\x83=\xe4\xb8\x10\xbb\x02x\x10\xfc\x8fi\xf5D\xe8<\x12\u044965\u026d\xc5\u07a0\x00\x00\u07d4\xecu\xb4\xa4u\x13\x12\v\xa5\xf8`9\x81O\x19\x98\xe3\x81z\u00c9\t\xb0\xbc\xe2\xe8\xfd\xba\x00\x00\u07d4\xecv\xf1.W\xa6U\x04\x03?,\v\xceo\xc0;\xd7\xfa\n\u0109\xc2\x12z\xf8X\xdap\x00\x00\u0794\xec\x80\x14\xef\xc7\xcb\xe5\xb0\xceP\xf3V,\xf4\xe6\u007f\x85\x93\xcd2\x88\xf0\x15\xf2W6B\x00\x00\u07d4\xec\x82\xf5\r\x06G_hM\xf1\xb3\x92\xe0\r\xa3A\xaa\x14TD\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xec\x83\xe7\x98\u00d6\xb7\xa5^*\"$\xab\u0343K'\xeaE\x9c\x8a\x02\x8a\x85t%Fo\x80\x00\x00\u07d4\xec\x89\xf2\xb6x\xa1\xa1[\x914\xec^\xb7\fjb\a\x1f\xba\xf9\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xec\x8c\x1d{j\xac\xcdB\x9d\xb3\xa9\x1e\xe4\xc9\xeb\x1c\xa4\xf6\xf7<\x89\xe6d\x99\"\x88\xf2(\x00\x00\xe0\x94\xec\x98Q\xbd\x91rpa\x02g\xd6\x05\x18\xb5M<\xa2\xb3[\x17\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4\xec\x99\xe9]\xec\xe4o\xff\xfb\x17^\xb6@\x0f\xbe\xbb\b\ue6d5\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xec\xa5\xf5\x87\x92\xb8\xc6-*\xf5Vq~\xe3\xee0(\xbeM\u0389lk\x93[\x8b\xbd@\x00\x00\u07d4\xec\xabZ\xba[\x82\x8d\xe1pS\x81\xf3\x8b\xc7D\xb3+\xa1\xb47\x892\xf5\x1e\u06ea\xa30\x00\x00\u07d4\xec\xaf3P\xb7\xce\x14M\x06\x8b\x18`\x10\x85,\x84\xdd\f\xe0\xf0\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xec\xb9LV\x8b\xfeY\xad\xe6Pd_O&0lsl\xac\xe4\x89\x0e~\xeb\xa3A\vt\x00\x00\xe0\x94\xec\xbeB^g\r9\tN \xfbVC\xa9\xd8\x18\xee\xd26\u078a\x01\x0f\f\xf0d\xddY \x00\x00\xe0\x94\xec\xbe^\x1c\x9a\u04b1\xdc\xcf\n0_\xc9R/Fi\xdd:\xe7\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\xec\xcfz\x04W\xb5f\xb3F\xcag:\x18\x0fDA0!j\u00c9\x05k\xc7^-c\x10\x00\x00\u07d4\xec\u0466(\x025\x1aAV\x8d#\x030\x04\xac\xc6\xc0\x05\xa5\u04c9\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\u07d4\xec\xd2v\xafd\u01dd\x1b\u0669+\x86\xb5\u835a\x95\xeb\x88\xf8\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xec\u0506\xfc\x19g\x91\xb9,\xf6\x12\xd3HaO\x91VH\x8b~\x8a\x02\x8a\x85t%Fo\x80\x00\x00\u07d4\xec\xda\xf92)\xb4^\xe6r\xf6]\xb5\x06\xfb^\xca\x00\xf7\xfc\xe6\x89W\x01\xf9m\xcc@\xee\x80\x00\u07d4\xec\xe1\x11g\vV<\u037e\xbc\xa5#\x84)\x0e\xcdh\xfe\\\x92\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xec\xe1\x15&\x82\xb7Y\x8f\xe2\xd1\xe2\x1e\xc1U3\x88T5\xac\x85\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xec\xe1)\bw\xb5\x83\xe3a\xa2\xd4\x1b\x00\x93F\xe6'N%8\x89\x10CV\x1a\x88)0\x00\x00\u07d4\xec\xf0]\a\xea\x02n~\xbfIA\x00#5\xba\xf2\xfe\xd0\xf0\x02\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xec\xf2L\xdd|\"\x92\x8cD\x1eiM\xe4\xaa1\xb0\xfa\xb5\x97x\x89 \x86\xac5\x10R`\x00\x00\xe0\x94\xec\xfd\x00M\x02\xf3l\xd4\u0634\xa8\xc1\xa9S;j\xf8\\\xd7\x16\x8a\x01\x0fA\xac\xb4\xbb;\x9c\x00\x00\xe0\x94\xed\x02\x06\xcb#1Q(\xf8\xca\xff&\xf6\xa3\v\x98Tg\xd0\"\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4\xed\x10e\xdb\u03dds\xc0O\xfcy\b\x87\r\x88\x14h\xc1\xe12\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xed\x12vQ;o\u0186(\xa7A\x85\xc2\xe2\f\xbb\xcax\x17\xbf\x89\nZ\xa8P\t\xe3\x9c\x00\x00\xe0\x94\xed\x12\xa1\xba\x1f\xb8\xad\xfc\xb2\r\xfa\x19X.RZ\xa3\xb7E$\x8a\x01je\x02\xf1Z\x1eT\x00\x00\u07d4\xed\x16\xce9\xfe\xef;\xd7\xf5\xd1b\x04^\x0fg\xc0\xf0\x00F\xbb\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xed\x1a\\C\xc5t\xd4\xe94)\x9b$\xf1G,\u071f\xd6\xf0\x10\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xed\x1b$\xb6\x91-Q\xb34\xac\r\xe6\xe7q\xc7\xc0EF\x95\xea\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\xed\x1f\x1e\x11Z\r`\xce\x02\xfb%\xdf\x01M(\x9e:\f\xbe}\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xed10\\1\x9f\x92s\u04d3m\x8f[/q\u9c72)c\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xed2z\x14\xd5\u03ed\u0641\x03\xfc\t\x99q\x8d~\xd7\x05(\xea\x89N\x10\x03\xb2\x8d\x92\x80\x00\x00\u07d4\xed<\xbc7\x82\u03bdg\x98\x9b0\\A3\xb2\xcd\xe3\"\x11\xeb\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xed@\x14S\x8c\xeefJ/\xbc\xb6\xdcf\x9fz\xb1m\v\xa5|\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xedA\u188f\\\xaa\x848\x80\xefN\x8b\b\xbdl3\x14\x1e\u07c9*\xd5\xdd\xfaz\x8d\x83\x00\x00\xe0\x94\xedK\xe0J\x05-z\u0333\xdc\u03901\x9d\xba@ \xab,h\x8a\a\xf3zp\xea\xf3b\x17\x80\x00\xe0\x94\xedR\xa2\xcc\bi\u071e\x9f\x84+\u0415|G\xa8\xe9\xb0\xc9\xff\x8a\x02\x05\xb4\u07e1\xeetx\x00\x00\u07d4\xed[LA\xe7b\xd9B@Cs\xca\xf2\x1e\xd4a]%\xe6\xc1\x89m-O=\x95%\xb4\x00\x00\u07d4\xed`\u012bnT\x02\x061~5\x94zc\xa9\xcak\x03\xe2\u02c9\x03\x1a\u066d\vF\u007f\x80\x00\u07d4\xedd\x1e\x066\x8f\xb0\xef\xaa\x17\x03\xe0\x1f\xe4\x8fJhS\t\xeb\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xedfC\xc0\xe8\x88K-2\x11\x857\x85\xa0\x8b\xf8\xf3>\u049f\x89Hz\x9a0E9D\x00\x00\xe0\x94\xedp\xa3|\xdd\x1c\xbd\xa9tm\x93\x96X\xae*a\x81(\x85x\x8a\x02\bj\xc3Q\x05&\x00\x00\x00\u07d4\xedsFvn\x1agm\r\x06\xec\x82\x18g\xa2v\xa0\x83\xbf1\x89\u064a\t1\xcc-I\x00\x00\u07d4\xed\x86&\x16\xfc\xbf\xb3\xbe\xcbt\x06\xf7<\\\xbf\xf0\f\x94\aU\x89\\(=A\x03\x94\x10\x00\x00\u07d4\xed\x9e\x03\f\xa7\\\xb1\u049e\xa0\x1d\rL\xdf\xdc\xcd8D\xb6\xe4\x89\x01\xac\xc1\x16\u03ef\xb1\x80\x00\xe0\x94\ud7bc\u02e4/\x98\x15\xe7\x823&m\xd6\xe85\xb6\xaf\xc3\x1b\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\ud7f1\xf5\xaf/\xbf\u007f\xfcP)\xce\xe4+p\xff\\'[\xf5\x89\x0f-\xc7\xd4\u007f\x15`\x00\x00\u07d4\xed\xa4\xb2\xfaY\u0584\xb2z\x81\r\xf8\x97\x8as\xdf0\x8ac\u0089\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\xed\xb4s59y\xa2\x06\x87\x9d\xe1D\xc1\n:\xcf\x12\xa7'OV9a\xf57R\x9d\x89\xc7\u0789lk\x93[\x8b\xbd@\x00\x00\u07d4\xeer\x88\xd9\x10\x86\xd9\xe2\xeb\x91\x00\x14\u066b\x90\xa0-x\u00a0\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xee|=\xed|(\xf4Y\xc9/\xe1;M\x95\xba\xfb\xab\x026}\x89%\xf2s\x93=\xb5p\x00\x00\xe0\x94\xee\x86} \x91k\xd2\xe9\xc9\xec\xe0\x8a\xa0C\x85\xdbf|\x91.\x8a\n\x96\x81c\xf0\xa5{@\x00\x00\u07d4\ue25b\x02\xcb\xcb99\xcda\xde\x13B\xd5\x04\x82\xab\xb6\x852\x89_h\xe8\x13\x1e\u03c0\x00\x00\u07d4\xee\x90m}_\x17H%\x81t\xbeL\xbc8\x93\x03\x02\xab{B\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\ue5ea\x8a\u019e\xdfz\x98}mp\x97\x9f\x8e\xc1\xfb\xcaz\x94\x89\x14b\fW\xdd\xda\xe0\x00\x00\u07d4\xee\xa1\xe9y\x88\xdeu\xd8!\xcd(\xadh\"\xb2,\u0398\x8b1\x89\x1c0s\x1c\xec\x03 \x00\x00\xe0\x94\xee\u048c?\x06\x8e\tJ0K\x85<\x95\nh\t\xeb\xcb\x03\xe0\x8a\x03\xa9\u057a\xa4\xab\xf1\xd0\x00\x00\u07d4\xee\u04c4\xef-A\xd9\xd2\x03\x97NW\xc1#(\xeav\x0e\b\xea\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xee\xdflB\x80\xe6\xeb\x05\xb94\xac\xe4(\xe1\x1dB1\xb5\x90[\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xee\xe7a\x84~3\xfda\u0653\x87\xee\x14b\x86\x94\u047f\xd5%\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xee\xe9\xd0Rn\xda\x01\xe41\x16\xa3\x952-\u0689pW\x8f9\x8a\x02\x1e\x19\x99\xbb\xd5\u04be\x00\x00\u07d4\xee\xf1\xbb\xb1\xe5\xa8?\u0782H\xf8\x8e\xe3\x01\x8a\xfa-\x132\xeb\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xee\xfb\xa1-\xfc\x99gB\xdby\x04d\xca}';\xe6\xe8\x1b>\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xee\xfd\x05\xb0\xe3\xc4\x17\xd5[3C\x06\x04\x86\xcd\xd5\xe9*\xa7\xa6\x89M\x85<\x8f\x89\b\x98\x00\x00\u07d4\xef\r\xc7\xddzS\xd6\x12r\x8b\xcb\u04b2|\x19\xddM}fo\x89&A\x1c[5\xf0Z\x00\x00\u07d4\xef\x11RR\xb1\xb8E\u0345\u007f\x00-c\x0f\x1bo\xa3zNP\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xef\x1c\x04w\xf1\x18M`\xac\u02b3t\xd3tUz\n>\x10\xf3\x89\b=lz\xabc`\x00\x00\u07d4\xef,4\xbbH}7b\xc3\u0327\x82\xcc\xddz\x8f\xbb\n\x991\x89\t\xc2\x00vQ\xb2P\x00\x00\u07d4\xef5\xf6\u0531\a^j\xa19\x15\x1c\x97K/FX\xf7\x058\x89<;\xc3?\x94\xe5\r\x80\x00\u07d4\xef9\u0291s\xdf\x15S\x1ds\xe6\xb7*hKQ\xba\x0f+\xb4\x89V\xa0\xb4un\xe28\x00\x00\u07d4\xefF<&y\xfb'\x91d\xe2\f=&\x915\x87s\xa0\xad\x95\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xefG\xcf\a>6\xf2q\xd5\"\xd7\xfaNq \xadP\a\xa0\xbc\x89\x87\x86x2n\xac\x90\x00\x00\u07d4\xefa\x15[\xa0\t\xdc\u07be\xf1\v(\xd9\xda=\x1b\xc6\xc9\xce\u0509\x034-`\xdf\xf1\x96\x00\x00\u0794\xefix\x1f2\xff\xce34o,\x9a\xe3\xf0\x84\x93\xf3\xe8/\x89\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\xefv\xa4\u034f\xeb\xcb\u0278\x18\xf1x(\xf8\xd94s\xf3\xf3\u02c9\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\uf4c1\x8fhM\xb0\xc3g^\xc8\x132\xb3\x18>\xcc(\xa4\x95\x89T\x06\x923\xbf\u007fx\x00\x00\xe0\x94\xef\x9fY\xae\xdaA\x8c\x14\x94h-\x94\x1a\xabI$\xb5\xf4\x92\x9a\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\uf9b1\xf0\xdb`57\x82h\x91\xb8\xb4\xbc\x169\x84\xbb@\u03495e\x9e\xf9?\x0f\xc4\x00\x00\u07d4\xef\xbdR\xf9}\xa5\xfd:g:F\xcb\xf30D{~\x8a\xad\\\x89\x05l<\x9b\x80\xa0\xa6\x80\x00\xe0\x94\xef\xc8\xcf\x19c\u0269Rg\xb2(\xc0\x86#\x98\x89\xf4\xdf\xd4g\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xef\u02ae\x9f\xf6M,\xd9[RI\xdc\xff\xe7\xfa\xa0\xa0\xc0\xe4M\x89\x15\xbeat\xe1\x91.\x00\x00\u07d4\xef\xcc\xe0k\xd6\b\x9d\x0eE\x8e\xf5a\xf5\xa6\x89H\n\xfep\x00\x89 \x86\xac5\x10R`\x00\x00\u07d4\xef\xe0g]\xa9\x8a]\xdap\u0356\x19k\x87\xf4\xe7&\xb43H\x89?\x19\xbe\xb8\xdd\x1a\xb0\x00\x00\u07d4\xef\xe8\xff\x87\xfc&\x0e\agc\x8d\xd5\xd0/\xc4g.\x0e\xc0m\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xef\xeb\x19\x97\xaa\xd2w\xcc3C\x0ea\x11\xed\tCY@H\xb8\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xef\xee\xa0\x10uo\x81\xdaK\xa2[r\x17\x87\xf0X\x17\v\uff49\x01\u009c\x9c\xf7p\xef\x00\x00\u07d4\xef\xf5\x1dr\xad\xfa\xe1C\xed\xf3\xa4+\x1a\xecU\xa2\xcc\xdd\v\x90\x89\x10CV\x1a\x88)0\x00\x00\u07d4\xef\xf8kQ#\xbc\xdc\x17\xedL\xe8\xe0[~\x12\xe5\x13\x93\xa1\xf7\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xef\xfc\x15\u41f1\xbe\xda\n\x8d\x13%\xbd\xb4\x17\"@\xdcT\n\x89\x03\x8599\xee\xe1\xde\x00\x00\xe0\x94\xf0\x11\x95\xd6W\xef<\x94.l\xb89I\xe5\xa2\v\\\xfa\x8b\x1e\x8a\x05ts\xd0]\xab\xae\x80\x00\x00\u07d4\xf0'\x96)Q\x01gB\x88\xc1\xd94g\x05=\x04\"\x19\xb7\x94\x89(\x1d\x90\x1fO\xdd\x10\x00\x00\u07d4\xf09h={=\"[\xc7\xd8\u07ed\xefc\x164A\xbeA\xe2\x89\x01\xdd\x1eK\xd8\xd1\xee\x00\x00\u07d4\xf0Jj7\x97\b\xb9B\x8dr*\xa2\xb0kw\xe8\x895\u03c9\x89\x10CV\x1a\x88)0\x00\x00\u07d4\xf0M,\x91\xef\xb6\xe9\xc4_\xfb\xe7KCL\x8c_+\x02\x8f\x1f\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xf0W\xaaf\xcav~\xde\x12J\x1c[\x9c\xc5\xfc\x94\xef\v\x017\x89p\xa2K\u02b6\xf4]\x00\x00\u07d4\xf0[\xa8\u05f6\x859\xd930\v\xc9(\x9c=\x94t\xd0A\x9e\x89\x06\xda'\x02M\xd9`\x00\x00\u07d4\xf0\\\xee\xabeA\x05dp\x99Qw<\x84E\xad\x9fN\u01d7\x89\x10C\x16'\xa0\x93;\x00\x00\xe0\x94\xf0_\xcdL\rs\xaa\x16~US\xc8\xc0\xd6\xd4\xf2\xfa\xa3\x97W\x8a\x02\xd2\xd6l1p\xb2\x98\x00\x00\u07d4\xf0g\xe1\xf1\u0583UjL\xc4\xfd\f\x03\x13#\x9f2\xc4\xcf\u060965\u026d\xc5\u07a0\x00\x00\u07d4\xf0g\xfb\x10\u07f2\x93\u962b\xe5d\xc0U\xe34\x8f\x9f\xbf\x1e\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf0h\xdf\xe9]\x15\xcd:\u007f\x98\xff\xa6\x88\xb44hB\xbe&\x90\x89D\n\xd8\x19\xe0\x97L\x00\x00\xe0\x94\xf0j\x85J<]\xc3m\x1cI\xf4\xc8}m\xb33\xb5~J\u074a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xf0y\xe1\xb1&_P\xe8\u0229\x8e\xc0\u01c1^\xb3\xae\xac\x9e\xb4\x89\x01\x16\xdc:\x89\x94\xb3\x00\x00\xe0\x94\xf0{\xd0\xe5\xc2\xcei\xc7\u0127$\xbd&\xbb\xfa\x9d*\x17\xca\x03\x8a\x01@a\xb9\xd7z^\x98\x00\x00\xe0\x94\xf0\x83*k\xb2U\x03\xee\xcaC[\xe3\x1b\v\xf9\x05\xca\x1f\xcfW\x8a\x01je\x02\xf1Z\x1eT\x00\x00\u07d4\xf0\x9b>\x87\xf9\x13\xdd\xfdW\xae\x80I\xc71\u06e9\xb66\xdf\u00c9 \xf5\xb1\uab4d\x80\x00\x00\u07d4\xf0\xb14\v\x99oo\v\xf0\xd9V\x1c\x84\x9c\xaf\u007fD0\xbe\xfa\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xf0\xb1\xf9\xe2x2\xc6\xdei\x14\xd7\n\xfc#\x8ct\x99\x95\xac\xe4\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xf0\xb4i\xea\xe8\x9d@\f\xe7\xd5\xd6j\x96\x95\x03p6\xb8\x89\x03\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xf0\xb9\u0583\u03a1+\xa6\x00\xba\xac\xe2\x19\xb0\xb3\xc9~\x8c\x00\xe4\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xf0\xbe\x0f\xafMy#\xfcDF\"\u0458\f\xf2\u0650\xaa\xb3\a\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf0\xc0\x81\xdaR\xa9\xae6d*\xdf^\b _\x05\xc5Ah\xa6\x89\x06\x04o7\xe5\x94\\\x00\x00\u07d4\xf0\xc7\r\rm\xabvc\xaa\x9e\xd9\xce\xeaV~\xe2\u01b0'e\x89qC\x8a\u0167\x91\xa0\x80\x00\u07d4\xf0\xcb\xef\x84\xe1ic\x00\x98\xd4\xe3\x01\xb2\x02\b\xef\x05\x84j\u0249\x0e\v\x83EPkN\x00\x00\u07d4\xf0\xd2\x16c\u0630\x17n\x05\xfd\xe1\xb9\x0e\xf3\x1f\x850\xfd\xa9_\x89lj\xccg\u05f1\xd4\x00\x00\xe0\x94\xf0\xd5\xc3\x1c\xcbl\xbe0\xc7\xc9\xea\x19\xf2h\xd1Y\x85\x1f\x8c\x9c\x8a\x03\x89O\x0eo\x9b\x9fp\x00\x00\u07d4\xf0\xd6L\xf9\xdf\tt\x113\xd1pH_\xd2K\x00P\x11\xd5 \x89\x1b\b\x93A\xe1O\xcc\x00\x00\u07d4\xf0\xd8X\x10^\x1bd\x81\x01\xac?\x85\xa0\xf8\"+\xf4\xf8\x1dj\x89 \x86\xac5\x10R`\x00\x00\u07d4\xf0\xdcC\xf2\x05a\x91'P{+\x1c\x1c\xfd\xf3-(1\t \x89\x10^\xb7\x9b\x94\x17\b\x80\x00\u07d4\xf0\xe1\u07e4*\u07ac/\x17\xf6\xfd\xf5\x84\xc9Hb\xfdV3\x93\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xf0\xe2d\x9c~j?,]\xfe3\xbb\xfb\xd9'\xca<5\nX\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf0\xe7\xfb\x9eB\nS@\xd56\xf4\x04\b4O\xea\xef\xc0j\xef\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xf1\x04b\xe5\x8f\xcc\a\U000d5121\x87c\x94Q\x16~\x85\x92\x01\x89\t4\xdd]3\xbc\x97\x00\x00\xe0\x94\xf1\x06a\xff\x94\x14\x0f >zH%rCy8\xbe\xc9\xc3\xf7\x8a\x04<3\xc1\x93ud\x80\x00\x00\u0794\xf1\x14\xff\r\x0f$\xef\xf8\x96\xed\xdeTq\u07a4\x84\x82J\x99\xb3\x88\xbe -j\x0e\xda\x00\x00\u07d4\xf1\x16\xb0\xb4h\x0fS\xabr\xc9h\xba\x80.\x10\xaa\x1b\xe1\x1d\u0209\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xf1\x1c\xf5\xd3cto\xeehd\xd3\xca3m\xd8\x06y\xbb\x87\xae\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4\xf1\x1e\x01\u01e9\xd1$\x99\x00_M\xaew\x16\tZ4\x17bw\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xf1;\b0\x93\xbaVN-\xc61V\x8c\xf7T\r\x9a\x0e\xc7\x19\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\xf1O\x0e\xb8m\xb0\xebhu?\x16\x91\x8e]K\x80t7\xbd>\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xf1Qx\xff\xc4:\xa8\a\x0e\xce2~\x93\x0f\x80\x9a\xb1\xa5O\x9d\x89\n\xb6@9\x12\x010\x00\x00\u07d4\xf1V\xdc\v*\x98\x1e[U\xd3\xf2\xf0;\x814\xe31\u06ed\xb7\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xf1]\x9dZ!\xb1\x92\x9ey\x03q\xa1\u007f\x16\xd9_\fie\\\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf1^\x18,O\xbb\xady\xbd\x934\"B\xd4\xdc\xcf+\xe5\x89%\x89i*\xe8\x89p\x81\xd0\x00\x00\u07d4\xf1bM\x98\ve3o\xea\u0166\xd5A%\x00\\\xfc\xf2\xaa\u02c9lk\x93[\x8b\xbd@\x00\x00\u07d4\xf1g\xf5\x86\x8d\xcfB3\xa7\x83\x06\th,\xaf-\xf4\xb1\xb8\a\x89\x81\xe5B\xe1\xa78?\x00\x00\u07d4\xf1m\xe1\x89\x1d\x81\x96F\x13\x95\xf9\xb16&[;\x95F\xf6\xef\x89\x01\xb2\x8e\x1f\x98\xbb\u0380\x00\u07d4\xf1z\x92\xe06\x1d\xba\xce\xcd\xc5\xde\r\x18\x94\x95Z\xf6\xa9\xb6\x06\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf1z\xdbt\x0fE\u02fd\xe3\tN~\x13qo\x81\x03\xf5c\xbd\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf1\x8b\x14\xcb\xf6iC6\xd0\xfe\x12\xac\x1f%\xdf-\xa0\xc0]\xbb\x89\xd8\xd4`,&\xbfl\x00\x00\u07d4\xf1\x9b98\x9dG\xb1\x1b\x8a,?\x1d\xa9\x12M\xec\xff\xbe\xfa\xf7\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf1\x9f\x195\b9>M*\x12{ \xb2\x03\x1f9\xc8%\x81\u0189\xbd\xbdz\x83\xbd/l\x00\x00\u07d4\xf1\xa1\xf3 @yd\xfd<\x8f.,\u0224X\r\xa9O\x01\xea\x89ll!wU|D\x00\x00\u07d4\xf1\xb4\xec\xc65%\xf7C,=\x83O\xfe+\x97\x0f\xbe\xb8r\x12\x89\xa2\xa2@h\xfa\u0340\x00\x00\u07d4\U000753ef\xfa\x87\x94\xf5\n\xf8\xe8\x83\t\u01e6&TU\xd5\x1a\x8963\x03\"\xd5#\x8c\x00\x00\u07d4\xf1\xc8\u0129A\xb4b\x8c\rl0\xfd\xa5dR\u065c~\x1bd\x89N\x8c\xea\x1e\xdeu\x04\x00\x00\u07d4\xf1\xda@so\x99\xd5\xdf;\x06\x8a]t_\xaf\xc6F?\u0271\x89\x06\x96\xca#\x05\x8d\xa1\x00\x00\u07d4\xf1\u070a\xc8\x10B\xc6z\x9c\\c2!\xa8\xf76>e\x87\f\x9f(t$\u04a9`\x89J\xcfX\xe0rW\x10\x00\x00\u07d4\xf2B\u0684]B\u053fw\x9a\x00\xf2\x95\xb4\aP\xfeI\xea\x13\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xf2RY\xa5\xc99\xcd%\x96l\x9bc\x03\xd3s\x1cS\u077cL\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xf2^Lp\xbcFV2\u021eV%\xa82\xa7r/k\xff\xab\x89\xf3K\x82\xfd\x8e\x91 \x00\x00\u07d4\xf2k\xce\xdc\xe3\xfe\xad\u03a3\xbc>\x96\xeb\x10@\xdf\xd8\xff\u1809*\x03I\x19\u07ff\xbc\x00\x00\u07d4\xf2py%v\xf0]QD\x93\xff\xd1\xf5\xe8K\xecK-\xf8\x10\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xf2s,\xf2\xc1;\x8b\xb8\xe7I*\x98\x8f_\x89\xe3\x82s\xdd\u0209 \x86\xac5\x10R`\x00\x00\xe0\x94\xf2t.hY\xc5i\xd5\xf2\x10\x83Q\xe0\xbfM\xca5*H\xa8\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xf2\x81:d\xc5&]\x02\x025\u02dc1\x9bl\x96\xf9\x06\xc4\x1e\x89\x12\xf99\u025e\u06b8\x00\x00\u07d4\xf2\x87\xffR\xf4a\x11z\xdb>\x1d\xaaq\x93-\x14\x93\xc6_.\x89\xc5S%\xcat\x15\xe0\x00\x00\u07d4\xf2\xab\x11au\x02D\xd0\xec\xd0H\xee\r>Q\xab\xb1C\xa2\xfd\x89B\xfe+\x90ss\xbc\x00\x00\u07d4\xf2\xb4\xab,\x94'\xa9\x01^\xf6\xee\xff\xf5\xed\xb6\x019\xb7\x19\u0449&\u06d9*;\x18\x00\x00\x00\u07d4\xf2\xc0>*8\x99\x8c!d\x87`\xf1\xe5\xae~\xa3\a}\x85\"\x89\x8f?q\x93\xab\a\x9c\x00\x00\u0794\xf2\u0090N\x9f\xa6d\xa1\x1e\xe2VV\xd8\xfd,\xc0\u0665\"\xa0\x88\xb9\x8b\xc8)\xa6\xf9\x00\x00\u07d4\xf2\xc3b\xb0\xef\x99\x1b\xc8/\xb3nf\xffu\x93*\xe8\u0742%\x89\x04\x02\xf4\xcf\xeeb\xe8\x00\x00\u07d4\xf2\xd0\xe9\x86\xd8\x14\xea\x13\xc8\xf4f\xa0S\x8cS\u0712&Q\xf0\x89J\xcfX\xe0rW\x10\x00\x00\xe0\x94\xf2\u04775w$\xecL\x03\x18[\x87\x9bc\xf5~&X\x91S\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94\xf2\xd5v<\xe0s\x12~,\xed\xdeo\xab\xa7\x86\xc7<\xa9AA\x8a\x01\xacB\x86\x10\x01\x91\xf0\x00\x00\xe0\x94\xf2\u055c\x89#u\x90s\xd6\xf4\x15\xaa\xf8\xeb\x06_\xf2\U000f614a\x01\xab,\xf7\xc9\xf8~ \x00\x00\u07d4\xf2\xe9\x9f\\\xbb\x83kz\xd3bGW\x1a0,\xbeKH\x1ci\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xf2\xed>w%J\u02c3#\x1d\xc0\x86\x0e\x1a\x11$+\xa6'\u06c9kV\x05\x15\x82\xa9p\x00\x00\xe0\x94\xf2\xed\xde7\xf9\xa8\u00dd\u07a2My\xf4\x01WW\xd0k\xf7\x86\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\xf2\xef\xe9e`\xc9\xd9{r\xbd6DxC\x88\\\x1d\x90\xc21\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf2\xfb\xb6\u0607\xf8\xb8\xcc:\x86\x9a\xba\x84\u007f=\x1fd\xfcc\x97\xaae\xfbS\xa8\xf0z\x0f\x89:\xae0\xe8\xbc\xee\x89|\xf28\x1fa\x9f\x15\x00\x00\u07d4\xf3@\x83\xec\xea8P\x17\xaa@\xbd\xd3^\xf7\xef\xfbL\xe7v-\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xf3F\xd7\u0792t\x1c\b\xfcX\xa6M\xb5[\x06-\xde\x01-\x14\x89\x0f\xffk\x1fv\x1em\x00\x00\xe0\x94\xf3U\xd3\xec\f\xfb\x90}\x8d\xbb\x1b\xf3FNE\x81(\x19\v\xac\x8a\x01\v\x04n\u007f\r\x80\x10\x00\x00\u07d4\xf3m\xf0/\xbd\x89`sG\xaf\xce)i\xb9\xc4#jX\xa5\x06\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf3s\xe9\u06ac\f\x86u\xf5;yz\x16\x0fo\xc04\xaek#\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xf3{BeG\xa1d-\x8032H\x14\xf0\xed\xe3\x11O\xc2\x12\x89\x15\xbeat\xe1\x91.\x00\x00\u07d4\xf3{\xf7\x8cXu\x15G\x11\xcbd\r7\xeam(\xcf\xcb\x12Y\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xf3\x82\xdfX1U\xd8T\x8f?\x93D\f\xd5\xf6\x8c\xb7\x9d`&\x8a8u}\x02\u007f\xc1\xfd\\\x00\x00\xe0\x94\xf3\x82\xe4\xc2\x04\x10\xb9Q\b\x9e\x19\xba\x96\xa2\xfe\xe3\xd9\x1c\xce~\x8a\x01\x11\xfaV\xee\u00a88\x00\x00\xe0\x94\xf3\x8al\xa8\x01hS~\x97M\x14\xe1\xc3\xd19\x90\xa4L,\x1b\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xf3\x9a\x9dz\xa3X\x1d\xf0~\xe4'\x9a\xe6\xc3\x12\xef!\x036X\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xf3\xb6h\xb3\xf1M\x92\x0e\xbc7\x90\x92\u06d8\x03\x1bg\xb2\x19\xb3\x89\n\xd6\xee\xdd\x17\xcf;\x80\x00\u07d4\U000fe679\x10<\xe7U\n\xa7O\xf1\xdb\x18\xe0\x9d\xfe2\xe0\x05\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf3\xc1\xab\u049d\xc5{A\xdc\x19-\x0e8M\x02\x1d\xf0\xb4\xf6\u0509\x97\xae\f\u07cf\x86\xf8\x00\x00\u07d4\xf3\xc4qm\x1e\xe5'\x9a\x86\xd0\x16:\x14a\x81\x81\xe1a6\u01c965\u026d\xc5\u07a0\x00\x00\xe0\x94\xf3\u030b\xcbU\x94e\xf8\x1b\xfeX;\u05eb\n#\x06E;\x9e\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xf3\u0588\xf0k\xbd\xbfP\xf9\x93,AE\xcb\xe4\x8e\xcd\xf6\x89\x04\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xf3\xdb\xcf\x13Z\u02dd\xee\x1aH\x9cY<\x02O\x03\u00bb\xae\u0389lk\x93[\x8b\xbd@\x00\x00\u07d4\xf3\xde_&\xefj\xde\xd6\xf0m;\x91\x13F\xeep@\x1d\xa4\xa0\x89\x13:\xb3}\x9f\x9d\x03\x00\x00\u07d4\xf3\xdfc\xa9q\x99\x93308;>\xd7W\v\x96\u0101#4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf3\xe7OG\f}:?\x003x\x0fv\xa8\x9f>\xf6\x91\xe6\u02c9\xa3\xcf\xe61\xd1Cd\x00\x00\u07d4\xf3\xeb\x19H\xb9Q\xe2-\xf1ax)\xbf;\x8d\x86\x80\xeckh\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xf3\xf1\xfa9\x18\xca4\xe2\xcf~\x84g\v\x1fM\x8e\xca\x16\r\xb3\x89$\xdc\xe5M4\xa1\xa0\x00\x00\u07d4\xf3\xf2O\u009e @?\xc0\xe8\xf5\xeb\xbbU4&\xf7\x82p\xa2\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xf3\xfar5R\xa5\xd0Q.+b\xf4\x8d\xca{+\x81\x050[\x89\amA\xc6$\x94\x84\x00\x00\u07d4\xf3\xfeQ\xfd\xe3D\x13\xc73\x18\xb9\xc8T7\xfe~\x82\x0fV\x1a\x896b2\\\u044f\xe0\x00\x00\u07d4\xf4\x00\xf9=_\\~?\xc3\x03\x12\x9a\xc8\xfb\f/xd\a\xfa\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf4\v\x13O\xea\"\u01b2\x9c\x84W\xf4\x9f\x00\x0f\x9c\xdax\x9a\u06c9 \x86\xac5\x10R`\x00\x00\u07d4\xf4\x15W\xdf\u07f1\xa1\xbd\xce\xfe\xfe.\xba\x1e!\xfe\nJ\x99B\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xf4\x17z\r\x85\u050b\x0e&B\x11\xce*\xa2\xef\xd3\xf1\xb4\u007f\b\x89\xc2\xcc\xca&\xb7\xe8\x0e\x80\x00\u07d4\xf4/\x90R1\xc7p\xf0\xa4\x06\xf2\xb7h\x87\u007f\xb4\x9e\xee\x0f!\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\u07d4\xf42\xb9\u06ef\x11\xbd\xbds\xb6Q\x9f\xc0\xa9\x04\x19\x87q\xaa\u0189\b=lz\xabc`\x00\x00\u07d4\xf4=\xa3\xa4\xe3\xf5\xfa\xb1\x04\u029b\xc1\xa0\xf7\xf3\xbbJV\xf3Q\x89lj\xccg\u05f1\xd4\x00\x00\xe0\x94\xf4G\x10\x8b\x98\xdfd\xb5~\x87\x103\x88\\\x1a\xd7\x1d\xb1\xa3\xf9\x8a\x01v\xf4\x9e\xad4\x83P\x80\x00\u07d4\xf4O\x85Q\xac\xe93r\a\x12\xc5\u0111\u0376\xf2\xf9Qsl\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u0794\xf4V\x05Z\x11\xab\x91\xfff\x8e.\xc9\"\x96\x1f*#\xe3\xdb%\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\xf4V\xa7[\xb9\x96U\xa7A,\xe9}\xa0\x81\x81m\xfd\xb2\xb1\xf2\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xf4[\x1d\xcb.A\xdc'\xff\xa0$\u06ad\xf6\x19\xc1\x11u\xc0\x87\x89\x01\x11du\x9f\xfb2\x00\x00\u07d4\xf4c\xa9\f\xb3\xf1>\x1f\x06CB66\xbe\xab\x84\xc1#\xb0m\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\xf4h\x90n~\xdffJ\xb0\u063e=\x83\xebz\xb3\xf7\xff\xdcx\x89\\(=A\x03\x94\x10\x00\x00\u07d4\xf4i\x80\u3929\u049ajn\x90`E7\xa3\x11K\xcb(\x97\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xf4kk\x9c|\xb5R\x82\x9c\x1d=\xfd\x8f\xfb\x11\xaa\xba\xe7\x82\xf6\x89\x01#n\xfc\xbc\xbb4\x00\x00\u07d4\xf4v\xe1&\u007f\x86$|\xc9\b\x81o.z\xd58\x8c\x95-\xb0\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xf4v\xf2\xcbr\b\xa3.\x05\x1f\xd9N\xa8f)\x92c\x82\x87\xa2\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94\xf4{\xb14\xda0\xa8\x12\xd0\x03\xaf\x8d\u0338\x88\xf4K\xbfW$\x8a\x01\x19Y\xb7\xfe3\x95X\x00\x00\u07d4\xf4\x83\xf6\a\xa2\x1f\xcc(\x10\n\x01\x8cV\x8f\xfb\xe1@8\x04\x10\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xf4\x8e\x1f\x13\xf6\xafM\x84\xb3q\xd7\xdeK'=\x03\xa2c'\x8e\x89 \x86\xac5\x10R`\x00\x00\xe0\x94\xf4\x9cG\xb3\xef\xd8knj[\xc9A\x8d\x1f\x9f\xec\x81Ki\xef\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94\xf4\x9fo\x9b\xaa\xbc\x01\x8c\x8f\x8e\x11\x9e\x01\x15\xf4\x91\xfc\x92\xa8\xa4\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xf4\xa3g\xb1f\u0499\x1a+\xfd\xa9\xf5dc\xa0\x9f%,\x1b\x1d\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xf4\xa5\x1f\xceJ\x1d[\x94\xb0q\x83\x89\xbaNx\x14\x13\x9c\xa78\x89\x10CV\x1a\x88)0\x00\x00\u07d4\xf4\xa9\xd0\f\xef\xa9{zX\xef\x94\x17\xfcbg\xa5\x06\x909\xee\x89\x01.\x89(\u007f\xa7\x84\x00\x00\u07d4\xf4\xaa\xa3\xa6\x16>7\x06W{I\xc0v~\x94\x8ah\x1e\x16\xee\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf4\xb1bn$\xf3\v\xca\xd9'!\xb2\x93r\x89U\xa6\xe7\x9c\xcd\x1d0\x00\x00\u07d4\xf5U\xa2{\xb1\xe2\xfdN,\u01c4\xca\ue493\x9f\xc0n/\u0249lk\x93[\x8b\xbd@\x00\x00\u07d4\xf5X\xa2\xb2\xdd&\u0755\x93\xaa\xe0E1\xfd<<\u00c5Kg\x89\n\xbb\xcdN\xf3wX\x00\x00\u07d4\xf5`H\xdd!\x81\u0523od\xfc\xec\xc6!T\x81\xe4*\xbc\x15\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xf5dB\xf6\x0e!i\x13\x95\u043f\xfa\xa9\x19M\xca\xff\x12\u2dc9\x0e\x189\x8ev\x01\x90\x00\x00\u07d4\xf5yqJE\xeb\x8fR\xc3\xd5{\xbd\xef\xd2\xc1[./\x11\u07c9T\x91YV\xc4\t`\x00\x00\u07d4\xf5\x93\xc6R\x85\xeek\xbdf7\U000fe3c9\xad@\u0509\xf6U\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xf5\x98\xdb.\t\xa8\xa5\xee}r\r+\\C\xbb\x12m\x11\xec\u0089\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xf5\x9d\xab\x1b\xf8\xdf\x112~a\xf9\xb7\xa1KV:\x96\xec5T\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94\xf5\x9f\x9f\x02\xbb\u024e\xfe\t~\xab\xb7\x82\x10\x97\x90!\x89\x8b\xfd\x8a\x02\x1e\x17\x1a>\xc9\xf7,\x00\x00\u07d4\xf5\xa5E\x9f\xcd\xd5\xe5\xb2s\x83\r\xf8\x8e\xeaL\xb7}\xda\u07f9\x89\x04\t\xe5+H6\x9a\x00\x00\u07d4\xf5\xa7gj\xd1H\xae\x9c\x1e\xf8\xb6\xf5\xe5\xa0\xc2\xc4s\xbe\x85\v\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xf5\xb0h\x98\x9d\xf2\x9c%5w\xd0@Z\xden\x0eu(\xf8\x9e\x89WG=\x05\u06ba\xe8\x00\x00\u07d4\xf5\xb6\xe9\x06\x1aN\xb0\x96\x16\aw\xe2gb\xcfH\xbd\u0635]\x89\r\xc5_\xdb\x17d{\x00\x00\u07d4\xf5\xcf\xfb\xbabN~\xb3!\xbc\x83\xc6\f\xa6\x81\x99\xb4\xe3fq\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf5\xd1ER\xb1\xdc\xe0\xd6\xdc\x1f2\r\xa6\xff\u02231\xcdo\f\x89Hz\x9a0E9D\x00\x00\xe0\x94\xf5\xd6\x1a\xc4\u0295G^[{\xff\xd5\xf2\xf6\x90\xb3\x16u\x96\x15\x8a\x06\x92\xae\x88\x97\b\x1d\x00\x00\x00\u07d4\xf5\xd9\xcf\x00\xd6X\xddEQzH\xa9\xd3\xf5\xf63T\x1aS=\x89\x06O_\xdfIOx\x00\x00\u07d4\xf5\xea\xdc\xd2\u0478ez\x12\x1f3\xc4X\xa8\xb1>v\xb6U&\x89\r\x8b\x0fZZ\xc2J\x00\x00\u07d4\xf6\a\xc2\x15\r>\x1b\x99\xf2O\xa1\xc7\xd5@\xad\xd3\\N\xbe\x1e\x89\xa7\xf1\xaa\a\xfc\x8f\xaa\x00\x00\u07d4\xf6\v\xd75T>k\xfd.\xa6\xf1\x1b\xffbs@\xbc\x03Z#\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf6\f\x1bE\xf1d\xb9X\x0e 'Z\\9\xe1\xd7\x1e5\xf8\x91\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xf6\x0fb\xd797\x95?\xef5\x16\x9e\x11\xd8r\xd2\xea1~\xec\x8a\x01!\xeah\xc1\x14\xe5\x10\x00\x00\u07d4\xf6\x12\x83\xb4\xbd\x85\x04\x05\x8c\xa3`\u94d9\x9bb\xcb\xc8\xcdg\x89\r\xd2\xd5\xfc\xf3\xbc\x9c\x00\x00\u07d4\xf6\x17\xb9g\xb9\xbdH_v\x95\xd2\xefQ\xfbw\x92\u0618\xf5\x00\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xf6\x18\u0671\x04A\x14\x80\xa8c\xe6#\xfcU#-\x1aOH\xaa\x89\x0eh\x9emD\xb1f\x80\x00\u07d4\xf6\"\u5126b>\xaa\xf9\x9f+\xe4\x9eS\x80\xc5\xcb\xcf\\\u0609\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xf62\xad\xffI\r\xa4\xb7-\x126\xd0KQ\x0ft\xd2\xfa\xa3\u0349K\xe4\xe7&{j\xe0\x00\x00\u07d4\xf69\xac1\u069fg'\x1b\xd1\x04\x02\xb7eN\\\xe7c\xbdG\x89\x15\xaf\x0fB\xba\xf9&\x00\x00\u07d4\xf6:W\x9b\xc3\xea\u00a9I\x04\x10\x12\x8d\xbc\xeb\xe6\xd9\u0782C\x89P\xc5\xe7a\xa4D\b\x00\x00\u07d4\xf6E\xdd|\x89\x00\x93\xe8\xe4\u022a\x92\xa6\xbb55\"\xd3\u0718\x89\aC\x9f\xa2\t\x9eX\x00\x00\xe0\x94\xf6H\xea\x89\xc2u%q\x01r\x94Ny\xed\xff\x84x\x03\xb7u\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\xf6JJ\xc8\xd5@\xa9(\x9ch\xd9`\xd5\xfb|\xc4Zw\x83\x1c\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf6N\xcf!\x17\x93\x1cmSZ1\x1eO\xfe\xae\xf9\u0514\x05\xb8\x89\x90\xf54`\x8ar\x88\x00\x00\u07d4\xf6O\xe0\x93\x9a\x8d\x1e\xea*\x0e\u035a\x970\xfdyX\xe31\t\x89\x01\x1d\xe1\xe6\xdbE\f\x00\x00\u07d4\xf6V\x16\xbe\x9c\x8by~t\x15\"|\x918\xfa\xa0\x89\x17B\u05c9*\xd3s\xcef\x8e\x98\x00\x00\u07d4\xf6W\xfc\xbeh.\xb4\xe8\xdb\x15.\u03c9$V\x00\vQ=\x15\x89i*\xe8\x89p\x81\xd0\x00\x00\u07d4\xf6X\x19\xacL\xc1L\x13\u007f\x05\xddyw\xc7\xda\xe0\x8d\x1aJ\xb5\x89\x05\x87\x88\u02d4\xb1\xd8\x00\x00\u07d4\xf6{\xb8\xe2\x11\x8b\xbc\u0550'fn\xed\xf6\x94>\xc9\xf8\x80\xa5\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xf6\x84d\xbfd\xf2A\x13V\xe4\xd3%\x0e\xfe\xfe\\P\xa5\xf6[\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xf6\x86x[\x89r\va\x14_\ua017\x8dj\u030e\v\xc1\x96\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xf6\x8c^3\xfa\x97\x13\x9d\xf5\xb2\xe68\x86\xce4\xeb\xf3\u45dc\x89\xb3\xfaAi\xe2\xd8\xe0\x00\x00\u07d4\xf6\xa8cWW\xc5\xe8\xc14\xd2\r\x02\x8c\xf7x\u03c6\t\xe4j\x89O\x1dw/\xae\xc1|\x00\x00\u07d4\xf6\xb7\x82\xf4\xdc\xd7E\xa6\xc0\xe2\xe00`\x0e\x04\xa2K%\xe5B\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\xe0\x94\xf6\xbc7\xb1\u04a3x\x8dX\x9bm\xe2\x12\xdc\x17\x13\xb2\xf6\u738a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\xf6\xc3\u010a\x1a\xc0\xa3G\x99\xf0M\xb8n\u01e9u\xfewh\xf3\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xf6\xd2]?=\x84m#\x9fR_\xa8\xca\xc9{\xc45x\u06ec\x890\x92\u007ft\xc9\xde\x00\x00\x00\u07d4\xf6\xea\xacp2\u0512\xef\x17\xfd`\x95\xaf\xc1\x1dcOV\xb3\x82\x89\x1b\x1bk\u05efd\xc7\x00\x00\xe0\x94\xf6\xea\xd6}\xbf[~\xb13X\xe1\x0f6\x18\x9dS\xe6C\xcf\u03ca\bxg\x83&\xea\xc9\x00\x00\x00\u07d4\xf6\xf1\xa4C\t\x05\x1ck%\xe4}\xff\x90\x9b\x17\x9b\xb9\xabY\x1c\x89i*\xe8\x89p\x81\xd0\x00\x00\u07d4\xf7\x03(\xef\x97b_\xe7E\xfa\xa4\x9e\xe0\xf9\u052a;\r\xfbi\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xf7\n\x99\x8aq{3\x8d\x1d\u0658T@\x9b\x1a3\x8d\ue930\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf7\rcz\x84\\\x06\xdbl\u0711\xe67\x1c\xe7\xc48\x8ab\x8e\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xf7\x15R\x13D\x98\x92tK\xc6\x0f.\x04@\a\x88\xbd\x04\x1f\u0749\x03\x9f\xba\xe8\xd0B\xdd\x00\x00\xe0\x94\xf7\x1bE4\xf2\x86\xe40\x93\xb1\xe1^\xfe\xa7I\xe7Y{\x8bW\x8a\x16\x1c\x13\xd34\x1c\x87(\x00\x00\u07d4\xf74\xec\x03rM\xde\xe5\xbbRy\xaa\x1a\xfc\xf6\x1b\f\xb4H\xa1\x89\xe5\xbf,\u0270\x97\x80\x00\x00\u07d4\xf76\u0716v\x00\x128\x8f\xe8\x8bf\xc0n\xfeW\xe0\xd7\xcf\n\x89q\xd7Z\xb9\xb9 P\x00\x00\u07d4\xf7:\xc4l ;\xe1S\x81\x11\xb1Q\xec\x82 \u01c6\xd8AD\x89\x0f\xf77x\x17\xb8+\x80\x00\u07d4\xf7=\xd9\xc1B\xb7\x1b\xce\x11\xd0n0\xe7\xe7\xd02\xf2\uc71e\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xf7A\x8a\xa0\xe7\x13\xd2H\"\x87v\xb2\xe7CB\"\xaeu\u3949lk\x93[\x8b\xbd@\x00\x00\u07d4\xf7Nn\x14S\x82\xb4\u06c2\x1f\xe0\xf2\u0643\x88\xf4V\t\u019f\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xf7P\f\x16o\x8b\xea/\x824v\x06\xe5\x02K\xe9\xe4\xf4\u0399\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xf7W\xfc\x87 \xd3\xc4\xfaRw\a^`\xbd\\A\x1a\xeb\xd9w\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf7[\xb3\x9cy\x97y\xeb\xc0J3m&\r\xa61F\xed\x98\u0409\x01Z\xf1\u05cbX\xc4\x00\x00\xe0\x94\xf7h\xf3!\xfdd3\xd9kO5M<\xc1e,\x172\xf5\u007f\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xf7oi\xce\xe4\xfa\xa0\xa6;0\xae\x1ex\x81\xf4\xf7\x15ep\x10\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xf7w6\x1a=\u062bb\xe5\xf1\xb9\xb0GV\x8c\xc0\xb5UpL\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xf7|{\x84QI\xef\xba\x19\xe2a\xbc|u\x15y\b\xaf\xa9\x90\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf7\u007f\x95\x87\xffz-r\x95\xf1\xf5q\u0206\xbd3\x92jR|\x89lh\xcc\u041b\x02,\x00\x00\u07d4\xf7\x82X\xc1$\x81\xbc\xdd\u06f7*\x8c\xa0\xc0C\tra\xc6\u0149\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xf7\x98\xd1m\xa4\xe4`\xc4`\xcdH_\xae\x0f\xa0Y\x97\b\ub08965\u026d\xc5\u07a0\x00\x00\u07d4\xf7\xa1\xad\xe2\xd0\xf5)\x12=\x10U\xf1\x9b\x17\x91\x9fV!Ng\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xf7\xac\xff\x93K\x84\xda\ti\xdc7\xa8\xfc\xf6C\xb7\xd7\xfb\xedA\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\xf7\xb1Q\xcc^W\x1c\x17\xc7e9\xdb\xe9\x96L\xbbo\xe5\xdey\x89tq|\xfbh\x83\x10\x00\x00\u07d4\xf7\xb2\x9b\x82\x19\\\x88-\xabx\x97\u00ae\x95\xe7w\x10\xf5xu\x89w5Aa2\xdb\xfc\x00\x00\u07d4\xf7\xbcLD\x91\rZ\xed\xd6n\xd25U8\xa6\xb1\x93\xc3a\xec\x89\x05A\xde,-\x8db\x00\x00\u07d4\xf7\xc0\f\xdb\x1f\x02\x03\x10\u056c\xab{Ij\xaaD\xb7y\b^\x89Z\x87\xe7\xd7\xf5\xf6X\x00\x00\u07d4\xf7\xc1\xb4C\x96\x8b\x11{]\u0677UW/\xcd9\xca^\xc0K\x89\x18\xb9h\u0092\xf1\xb5\x00\x00\xe0\x94\xf7\xc5\x0f\x92*\xd1ka\xc6\u047a\xa0E\xed\x81h\x15\xba\u010f\x8a\x02\xa99j\x97\x84\xad}\x00\x00\u07d4\xf7\xc7\b\x01Pq\xd4\xfb\n:*\t\xa4]\x15c\x96\xe34\x9e\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xf7\xcb\u06e6\xbel\xfeh\xdb\xc2<+\x0f\xf50\xee\x05\"o\x84\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xf7\xd0\xd3\x10\xac\xea\x18@a8\xba\xaa\xbb\xfe\x05q\xe8\r\xe8_\x89Hz\x9a0E9D\x00\x00\u07d4\xf7\u05ef LV\xf3\x1f\xd9C\x98\xe4\r\xf1\x96K\u063f\x12<\x89\b!\xd2!\xb5)\x1f\x80\x00\u07d4\xf7\xdc%\x11\x96\xfb\u02f7|\x94}|\x19F\xb0\xffe\x02\x1c\xea\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xf7\xe4Z\x12\xaaq\x1cp\x9a\xce\xfe\x95\xf3;xa-*\xd2*\x8a\x0e\x06U\xe2\xf2k\xc9\x18\x00\x00\u07d4\xf7\xf4\x89\x8cLRm\x95_!\xf0U\xcbnG\xb9\x15\xe5\x19d\x89|\b`\xe5\xa8\r\xc0\x00\x00\u07d4\xf7\xf9\x1ez\xcb[\x81)\xa3\x06\x87|\xe3\x16\x8eoC\x8bf\xa1\x89\t\x8a}\x9b\x83\x14\xc0\x00\x00\u07d4\xf7\xfcE\xab\xf7oP\x88\xe2\u5d68\xd12\xf2\x8aMN\xc1\xc0\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf8\x06:\xf4\xcc\x1d\xd9a\x9a\xb5\u063f\xf3\xfc\xd1\xfa\xa8H\x82!\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf8\bnBf\x1e\xa9)\xd2\u0761\xablt\x8c\xe3\x05]\x11\x1e\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xf8\bw\x86\xb4-\xa0N\xd6\xd1\xe0\xfe&\xf6\xc0\xee\xfe\x1e\x9fZ\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xf8\r6\x19p/\xa5\x83\x8cH9\x18Y\xa89\xfb\x9c\xe7\x16\x0f\x89l\a\xa7\u0471np\x00\x00\u07d4\xf8\x14y\x9fm\xdfM\xcb)\xc7\xee\x87\x0eu\xf9\xcc-52m\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xf8\x15\xc1\n\x03-\x13\xc3K\x89v\xfan;\xd2\xc9\x13\x1a\x8b\xa9\x89Hz\x9a0E9D\x00\x00\u07d4\xf8\x16\"\xe5WW\xda\xeafu\x97]\xd958\xda}\x16\x99\x1e\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf8$\xee3\x1eJ\xc3\xccXv\x939[W\xec\xf6%\xa6\xc0\u0089V\xc9]\xe8\xe8\xca\x1d\x00\x00\u07d4\xf8'\xd5n\xd2\xd3' \u052b\xf1\x03\xd6\xd0\xefM;\xcdU\x9b\x89\x01l\x80\x06W\x91\xa2\x80\x00\u07d4\xf8)\x85\x91R>P\xb1\x03\xf0\xb7\x01\xd6#\xcb\xf0\xf7EV\xf6\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xf8H\xfc\xe9\xaba\x1c}\x99 n#\xfa\u019a\u0508\xb9O\xe1\x89\x02\xa1\x12\x9d\t6r\x00\x00\u07d4\xf8O\t\n\xdf?\x8d\xb7\u1533P\xfb\xb7u\x00i\x9ff\xfd\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xf8Q\xb0\x10\xf63\xc4\n\xf1\xa8\xf0js\ubeabe\az\xb5\x89\xee\x86D/\xcd\x06\xc0\x00\x00\u07d4\xf8X\x17\x1a\x04\xd3W\xa1;IA\xc1n~U\xdd\u0514\x13)\x89\x02F\xa5!\x8f*\x00\x00\x00\u07d4\xf8[\xab\x1c\xb3q\x0f\xc0_\xa1\x9f\xfa\xc2.gR\x1a\v\xa2\x1d\x89l\x955\u007f\xa6\xb3l\x00\x00\u07d4\xf8j>\xa8\a\x1fp\x95\xc7\u06ca\x05\xaePz\x89)\u06f8v\x89\x126\xef\xcb\u02f3@\x00\x00\u07d4\xf8pL\x16\xd2\xfd[\xa3\xa2\xc0\x1d\x0e\xb2\x04\x84\xe6\xec\xfa1\t\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xf8p\x99_\xe1\xe5\"2\x1duC7\xa4\\\f\x9d{8\x95\x1c\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xf8s\xe5ze\xc9;n\x18\xcbu\xf0\xdc\a}[\x893\xdc\\\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\u07d4\xf8ua\x9d\x8a#\xe4]\x89\x98\u0444\u0500\xc0t\x89p\x82*\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xf8{\xb0{(\x9d\xf70\x1eT\xc0\xef\xdaj,\xf2\x91\xe8\x92\x00\x89K\xe4\xe7&{j\xe0\x00\x00\u0794\xf8\x89\x00\xdbsyU\xb1Q\x9b\x1a}\x17\n\x18\x86L\xe5\x90\xeb\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\xf8\x8bX\xdb7B\vFL\v\xe8\x8bE\xee+\x95)\x0f\x8c\xfa\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\xf8\x96+u\xdb]$\xc7\xe8\xb7\xce\xf1\x06\x8c>g\u03bb0\xa5\x89\x0f-\xc7\xd4\u007f\x15`\x00\x00\u07d4\xf8\xa0e\xf2\x87\xd9\x1dw\xcdbj\xf3\x8f\xfa\"\r\x9bU*+\x89g\x8a\x93 b\xe4\x18\x00\x00\u07d4\xf8\xa4\x9c\xa29\f\x1fm\\\x0ebQ;\a\x95qt?|\u0189\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xf8\xa5\f\xee.h\x8c\xee\u3b24\u0522\x97%\xd4\a,\u0103\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf8\xacJ9\xb5<\x110x \x97;D\x13e\xcf\xfeYof\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf8\xae\x85{g\xa4\xa2\x89:?\xbe|z\x87\xff\x1c\x01\u01a6\xe7\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xf8\xbf\x9c\x04\x87NZw\xf3\x8fL8R~\x80\xc6v\xf7\xb8\x87\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf8\xc7\xf3J8\xb3\x18\x01\xdaC\x064w\xb1+'\xd0\xf2\x03\xff\x89\x1a\u04ba\xbao\xefH\x00\x00\u07d4\xf8\xca3l\x8e\x91\xbd \xe3\x14\xc2\v-\xd4`\x8b\x9c\x8b\x94Y\x89-\u071b\u0173,x\x00\x00\u07d4\xf8\xd1t$\xc7g\xbe\xa3\x12\x05s\x9a+W\xa7'r\x14\uef89\x02F\xdd\xf9yvh\x00\x00\u07d4\xf8\xd5-\xcc_\x96\xcc(\x00{>\u02f4\t\xf7\xe2*dl\xaa\x89\b\x16\x90\xe1\x81(H\x00\x00\u07d4\xf8\xdc\xe8g\xf0\xa3\x9c[\xef\x9e\xeb\xa6\t\"\x9e\xfa\x02g\x8bl\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf8\xf2&\x14*B\x844\xab\x17\xa1\x86J%\x97\xf6J\xab/\x06\x89\tY\x8b/\xb2\xe9\xf2\x80\x00\u07d4\xf8\xf6d^\r\xeedK=\xad\x81\xd5q\uf6ef\x84\x00!\xad\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf9\x01\xc0\x0f\xc1\u06c8\xb6\x9cK\xc3%+\\\xa7\x0e\xa6\xee\\\xf6\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xf9=[\xcb\x06D\xb0\xcc\xe5\xfc\u0763C\xf5\x16\x8f\xfa\xb2\x87}\x89\vb\a\xb6}&\xf9\x00\x00\u07d4\xf9W\x0e\x92L\x95\u07bbpa6\x97\x92\xcf.\xfe\u00a8-^\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xf9d \x86\xb1\xfb\xaea\xa6\x80M\xbe_\xb1^\xc2\u04b57\xf4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf9d\x88i\x85\x90\xdc;,UVB\xb8q4\x8d\xfa\x06z\u0549\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xf9d\u064d(\x170\xba5\xb2\xe3\xa3\x14yn{B\xfe\xdfg\x89S\xb0\x87`\x98\xd8\f\x00\x00\u07d4\xf9e\ri\x89\xf1\x99\xab\x1c\xc4ycm\xed0\xf2A\x02\x1fe\x89.\x14\x1e\xa0\x81\xca\b\x00\x00\xe0\x94\xf9h\x83X$Y\x90\x8c\x82v'\xe8o(\xe6F\xf9\xc7\xfcz\x8a\x01\u0127\x877\xcd\u03f8\x00\x00\u07d4\xf9kL\x00voSsj\x85t\xf8\"\xe6GL/!\xda-\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xf9r\x9dH(,\x9e\x87\x16m^\xef-\x01\xed\xa9\xdb\xf7\x88!\x89\x05k\x83\xdd\xc7(T\x80\x00\u07d4\xf9v~N\xcbJY\x80Ru\b\u05fe\xc3\xd4^Ld\x9c\x13\x89g\x8a\x93 b\xe4\x18\x00\x00\xe0\x94\xf9x\xb0%\xb6B3U\\\xc3\xc1\x9a\xda\u007fA\x99\xc94\x8b\xf7\x8aT\xb4\v\x1f\x85+\xda\x00\x00\x00\u07d4\xf9{V\xeb\u0577z\xbc\x9f\xba\u02eb\u0514\xb9\xd2\xc2!\xcd\x03\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xf9\x81\x1f\xa1\x9d\xad\xbf\x02\x9f\x8b\xfeV\x9a\xdb\x18\"\x8c\x80H\x1a\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xf9\x82Ps\fLa\xc5\u007f\x12\x985\xf2h\b\x94yEB\xf3\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\xf9\x894gr\x99^\xc1\x90o\xaf\xfe\xba*\u007f\xe7\u079ck\xab\x8a\x01je\x02\xf1Z\x1eT\x00\x00\u07d4\xf9\x98\xca4\x11s\nl\xd1\x0etU\xb0A\x0f\xb0\xf6\xd3\xff\x80\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf9\x9a\xeeDKW\x83\xc0\x93\xcf\xff\xd1\xc4c,\xf9\x90\x9f\xbb\x91\x1d/\x81\x92\xf8B\t\x89\x90\xf54`\x8ar\x88\x00\x00\u07d4\xf9\xbf\xb5\x9dS\x8a\xfcHt\xd4\xf5\x94\x1b\b\xc9s\x0e8\xe2K\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\xf9\xdd#\x90\b\x18/\xb5\x19\xfb0\xee\xdd \x93\xfe\xd1c\x9b\xe8\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xf9\u07ba\xec\xb5\xf39\xbe\xeaH\x94\xe5 K\xfa4\r\x06\u007f%\x89ZB\x84Fs\xb1d\x00\x00\xe0\x94\xf9\xe3tG@lA!\x97\xb2\u2bbc\x00\x1dn0\u024c`\x8a\x01\xc4y\xbbCI\xc0\xee\x00\x00\u07d4\xf9\xe7\"/\xaa\xf0\xf4\xda@\xc1\u0124\x0607:\t\xbe\u05f6\x89\x9bO\u0730\x94V$\x00\x00\u07d4\xf9\xec\xe0\"\xbc\xcd,\x924i\x11\xe7\x9d\xd5\x03\x03\xc0\x1e\x01\x88\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xfa\x00\xc3v\xe8\x9c\x05\u81c1z\x9d\xd0t\x8d\x96\xf3A\xaa\x89\x89\x10M\r\x00\u04b7\xf6\x00\x00\u07d4\xfa\f\x1a\x98\x8c\x8a\x17\xad5(\xeb(\xb3@\x9d\xaaX\"_&\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xfa\x10_\x1a\x11\xb6\xe4\xb1\xf5`\x12\xa2y\"\xe2\xac-\xa4\x81/\x8a\x02\x05\xb4\u07e1\xeetx\x00\x00\u07d4\xfa\x14/\xe4~\u0697\xe6P;8k\x18\xa2\xbe\xdds\u0335\xb1\x89.\x15:\xd8\x15H\x10\x00\x00\u07d4\xfa\x14\xb5f#J\xbe\xe70B\xc3\x1d!qq\x82\u02e1J\xa1\x89\x11\xc7\xea\x16.x \x00\x00\u07d4\xfa\x19\xd6\xf7\xa5\x0fO\a\x98\x93\xd1g\xbf\x14\xe2\x1d\x00s\u0456\x89\x1c\xbb:?\xf0\x8d\b\x00\x00\u07d4\xfa\x1f\x19q\xa7u\xc3PO\xefPy\xf6@\xc2\u013c\xe7\xac\x05\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xfa'\x9b\xfd\x87g\xf9V\xbf\u007f\xa0\xbdV`\x16\x8d\xa7V\x86\xbd\x89\x90\xf54`\x8ar\x88\x00\x00\xe0\x94\xfa'\xccI\xd0\vl\x98s6\xa8u\xae9\xdaX\xfb\x04\x1b.\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94\xfa(2\x99`=\x87X\xe8\u02b0\x82\x12],\x8f}DT)\x8a\x01[\xca\xcb\x1e\x05\x01\xae\x80\x00\u07d4\xfa+\xbc\xa1]?\u37ca2\x8e\x91\xf9\r\xa1Oz\xc6%=\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xfa/\u049d\x03\xfe\xe9\xa0x\x93\xdf:&\x9fV\xb7/.\x1ed\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xfa3U2\x85\xa9sq\x9a\r_\x95o\xf8a\xb2\u061e\xd3\x04\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xfa:\fK\x90?n\xa5.\xa7\xab{\x88c\xb6\xa6\x16\xadfP\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xfa:\x1a\xa4H\x8b5\x1a\xa7V\f\xf5\xeec\n/\xd4\\2\"\x89/\xa4~j\xa74\r\x00\x00\u07d4\xfaA\tq\xad\"\x9c06\xf4\x1a\u03c5/*\u0259(\x19P\x89\u0633\x11\xa8\xdd\xfa|\x00\x00\u07d4\xfaD\xa8U\xe4\x04\xc8m\f\xa8\xef3$%\x1d\xfb4\x9cS\x9e\x89T\"S\xa1&\xce@\x00\x00\xe0\x94\xfaR\x01\xfe\x13B\xaf\x110{\x91B\xa0A$<\xa9./\t\x8a 8\x11j:\xc0C\x98\x00\x00\xe0\x94\xfa`\x86\x8a\xaf\xd4\xffL\\W\x91K\x8e\u054bBWs\u07e9\x8a\x01\xcf\xe5\xc8\b\xf3\x9f\xbc\x00\x00\u07d4\xfag\xb6{O7\xa0\x15\t\x15\x11\x0e\xde\a;\x05\xb8S\xbd\xa2\x89#\x19\xba\x94sq\xad\x00\x00\u07d4\xfah\xe0\xcb>\xdfQ\xf0\xa6\xf2\x11\u0272\xcb^\a<\x9b\xff\xe6\x89\x0f\xc969(\x01\xc0\x00\x00\xe0\x94\xfaj7\xf0\x18\xe9yg\x93\u007f\xc5\xe8a{\xa1\u05c6\xdd_w\x8a\x04<0\xfb\b\x84\xa9l\x00\x00\u07d4\xfav\x06C[5l\xee%{\xd2\xfc\xd3\xd9\xea\xcb<\xd1\xc4\xe1\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94\xfaz\xdff\v\x8d\x99\xce\x15\x93=|_\a/<\xbe\xb9\x9d3\x8a\x01@a\xb9\xd7z^\x98\x00\x00\u07d4\xfa\x86\xca'\xbf(T\u0648p\x83\u007f\xb6\xf6\xdf\xe4\xbfdS\xfc\x89\x11u~\x85%\xcf\x14\x80\x00\u07d4\xfa\x8c\xf4\xe6'i\x8c]W\x88\xab\xb7\x88\x04\x17\xe7P#\x13\x99\x89\xe6\x1a6\x96\xee\xf6\x10\x00\x00\u07d4\xfa\x8e;\x1f\x13C9\x00s}\xaa\xf1\xf6)\x9cH\x87\xf8[_\x89&\u009eG\u0104L\x00\x00\u07d4\xfa\x9e\xc8\xef\xe0\x86\x86\xfaX\xc1\x813Xr\xbai\x85`\ucac9lj\xccg\u05f1\xd4\x00\x00\u07d4\xfa\xad\x90]\x84|{#A\x8a\xee\xcb\xe3\xad\u06cd\xd3\xf8\x92J\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xfa\xae\xba\x8f\xc0\xbb\xdaU<\xa7.0\xef=s.&\xe8 A\x89H\x8d(*\xaf\xc9\xf6\x80\x00\u07d4\xfa\xb4\x87P\r\xf2\x0f\xb8>\xbe\xd9\x16y\x1dV\x17r\xad\xbe\xbf\x89lkLM\xa6\u077e\x00\x00\u07d4\xfa\xc5\u0294u\x80x\xfb\xfc\xcd\x19\xdb5X\xda~\u8827h\x897(\xa6+\r\xcf\xf6\x00\x00\u07d4\xfa\xd9j\xb6\xacv\x8a\xd5\t\x94R\xacGw\xbd\x1aG\xed\u010f\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94\xfa\xe7g\x19\xd9~\xacA\x87\x04(\xe9@'\x9d\x97\xddW\xb2\xf6\x8a\x14\u06f2\x19\\\xa2(\x90\x00\x00\u07d4\xfa\u8053pG\x89Zf\f\xf2)v\x0f'\xe6h(\xd6C\x89\t\xdd\xc1\xe3\xb9\x01\x18\x00\x00\u07d4\xfa\xe9,\x13p\xe9\u115a]\xf8;V\xd0\xf5\x86\xaa;@L\x89\x05\u0174\xf3\xd8C\x98\x00\x00\xe0\x94\xfa\xf5\xf0\xb7\xb6\xd5X\xf5\t\r\x9e\xa1\xfb-B%\x9cX`x\x8a\x01Z\xff\xb8B\fkd\x00\x00\xe0\x94\xfb\x12o\x0e\xc7i\xf4\x9d\xce\xfc\xa2\xf2\x00(dQX0\x84\xb8\x8a\x01\x0f\xcb\xc25\x03\x96\xbf\x00\x00\xe0\x94\xfb\x13^\xb1Z\x8b\xacr\xb6\x99\x154*`\xbb\xc0k~\a|\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xfb\"<\x1e\"\xea\xc1&\x9b2\xee\x15jS\x85\x92.\xd3o\xb8\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xfb7\xcfkO\x81\xa9\xe2\"\xfb\xa2.\x9b\xd2KP\x98\xb73\u03c9\x02\x1auJm\xc5(\x00\x00\u07d4\xfb8`\xf4\x12\x1cC.\xbd\xc8\xecj\x031\xb1\xb7\ty.\x90\x89 \x8c9J\xf1\u0208\x00\x00\u07d4\xfb9\x18\x9a\xf8v\xe7b\xc7\x1dl>t\x18\x93\xdf\"l\xed\u0589\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xfb:\v\rkjq\x8fo\xc0)*\x82]\xc9$z\x90\xa5\u0409\n\xd6\xdd\x19\x9e\x97[\x00\x00\xe0\x94\xfb?\xa1\xac\b\xab\xa9\xcc;\xf0\xfe\x9dH8 h\x8fe\xb4\x10\x8a\x06ZM\xa2]0\x16\xc0\x00\x00\u07d4\xfb?\xe0\x9b\xb86\x86\x15)\xd7Q\x8d\xa2v5\xf58PV\x15\x89K\xe3\x92\x16\xfd\xa0p\x00\x00\xe0\x94\xfbQ%\xbf\x0f^\xb0\xb6\xf0 \xe5k\xfc/\xdf=@,\t~\x8a\x01@a\xb9\xd7z^\x98\x00\x00\u07d4\xfbU\x18qL\xef\xc3m\x04\x86]\xe5\x91^\xf0\xffG\xdf\xe7C\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xfb_\xfa\xa0\xf7aW&5x\x91GX\x18\x93\x9d 7\u03d6\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xfbh\\\x15\xe49\x96^\xf6&\xbf\r\x83L\u0468\x9f+V\x95\x89\u0556{\xe4\xfc?\x10\x00\x00\u07d4\xfbtK\x95\x1d\tK1\x02b\xc8\xf9\x86\xc8`\u07da\xb1\xdee\x89\x02\xd1\xc5\x15\xf1\xcbJ\x80\x00\u07d4\xfby\xab\u06d2\\U\xb9\xf9\x8e\xfe\xefd\xcf\xc9\xeba\xf5\x1b\xb1\x89a@\xc0V\xfb\n\xc8\x00\x00\u07d4\xfb\x81\x13\xf9M\x91s\xee\xfdZ0s\xf5\x16\x80:\x10\xb2\x86\xae\x89\x04V9\x18$O@\x00\x00\u07d4\xfb\x84,\xa2\xc5\xef\x139\x17\xa26\xa0\u052c@i\x01\x10\xb08\x89\x10\x96\x9ab\xbe\x15\x88\x00\x00\u07d4\xfb\x91\xfb\x1aiUS\xf0\u018e!'m\xec\xf0\xb89\t\xb8m\x89\x05l\x006\x17\xafx\x00\x00\u07d4\xfb\x94s\xcfw\x125\n\x1f\xa09Rs\xfc\x80V\aR\xe4\xfb\x89\x06\xaf!\x98\xba\x85\xaa\x00\x00\xe0\x94\xfb\x94\x9cd\u007f\xdc\xfd%\x14\xc7\u054e1\xf2\x8aS-\x8cX3\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xfb\xa5HmS\xc6\xe2@IBA\xab\xf8~C\xc7`\rA:\x89k\xbfaIIH4\x00\x00\u07d4\xfb\xb1a\xfe\x87_\t)\nK&+\xc6\x01\x10\x84\x8f\r\"&\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xfb\xbb\xeb\u03fe#^W\xdd#\x06\xad\x1a\x9e\u0141\xc7\xf9\xf4\x8f\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\xe0\x94\xfb\xc0\x1d\xb5NG\xcd\xc3\xc48iJ\xb7\x17\xa8V\xc2?\xe6\xe9\x8a\x01\xcaqP\xab\x17OG\x00\x00\xe0\x94\xfb\xcf\xccJ{\x0f&\xcf&\xe9\xf33!2\xe2\xfcj#\af\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xfb\xe7\x16\"\xbc\xbd1\xc1\xa3iv\xe7\xe5\xf6p\xc0\u007f\xfe\x16\u0789\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xfb\xed\xe3,4\x9f3\x00\xefL\xd3;M\xe7\xdc\x18\xe4C\xd3&\x89\xabM\xcf9\x9a:`\x00\x00\u07d4\xfb\xf2\x04\xc8\x13\xf86\xd89b\u01c7\fx\b\xca4\u007f\xd3>\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xfb\xf7Y3\xe0\x1bu\xb1T\xef\x06i\ak\xe8\u007fb\xdf\xfa\xe1\x8a\x10\x84cr\xf2I\xd4\xc0\x00\x00\u07d4\xfc\x00\x96\xb2\x1e\x95\xac\xb8\xd6\x19\xd1v\xa4\xa1\xd8\xd5)\xba\xdb\xef\x89\x14\xd9i;\xcb\xec\x02\x80\x00\xe0\x94\xfc\x00\xa4 \xa3a\a\xdf\xd5\xf4\x95\x12\x8a_\u5af2\xdb\x0f4\x8a\x01C\x17\x9d\x86\x91\x10 \x00\x00\xe0\x94\xfc\x01\x8ai\n\xd6tm\xbe:\u03d7\x12\xdd\xcaR\xb6%\x009\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xfc\x02s@3\xe5\u007fpQ~\n\xfc~\xe6$a\xf0o\xad\x8e\x89\x15[\xd90\u007f\x9f\xe8\x00\x00\u07d4\xfc\x0e\xe6\xf7\u00b3qJ\xe9\x91lEVf\x05\xb6V\xf3$A\x89_h\xe8\x13\x1e\u03c0\x00\x00\u07d4\xfc\x10\xb7\xa6{2h\xd53\x1b\xfbj\x14\xde\xf5\xeaJ\x16,\xa3\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xfc\x15\u02d9\xa8\xd1\x03\v\x12w\n\xdd\x03:y\xee\r\f\x90\x8c\x89\x12\xfa\x00\xbdR\xe6$\x00\x00\u07d4\xfc)R\xb4\u011f\xed\u043c\x05(\xa3\bI^mj\x1cq\u0589lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xfc,\x1f\x88\x96\x1d\x01\x9c>\x9e\xa30\t\x15.\x06\x93\xfb\xf8\x8a\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\xe0\x94\xfc6\x11\x05\u0750\xf9\xed\xe5fI\x9di\xe9\x13\x03\x95\xf1*\u020aS\xa4\xfe/ N\x80\xe0\x00\x00\u07d4\xfc7/\xf6\x92|\xb3\x96\xd9\xcf)\x805\x00\x11\r\xa62\xbcR\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xfc9\xbeA\tK\x19\x97\xd2\x16\x9e\x82d\xc2\u00fa\xa6\u025b\u0109lk\x93[\x8b\xbd@\x00\x00\u07d4\xfc=\"k\xb3jX\xf5&V\x88W\xb0\xbb\x12\xd1\t\xec\x93\x01\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xfcC\x82\x9a\u01c7\xff\x88\xaa\xf1\x83\xba5*\xad\xbfZ\x15\xb1\x93\x89\u05ac\n+\x05R\xe0\x00\x00\u07d4\xfcI\xc1C\x9aA\u05b3\xcf&\xbbg\xe06R$\xe5\xe3\x8f_\x8966\u05ef^\u024e\x00\x00\u07d4\xfcU\x00\x82Q\x05\xcfq*1\x8a^\x9c;\xfci\u021d\f\x12\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\xfcf\xfa\xba'\u007fK]\xe6J\xd4^\xb1\x9c1\xe0\f\xed>\u054a\x011\xbe\xb9%\xff\xd3 \x00\x00\xe0\x94\xfc~\"\xa5\x03\xecZ\xbe\x9b\b\xc5\v\xd1I\x99\xf5 \xfaH\x84\x8a\x01ZG}\xfb\xe1\xea\x14\x80\x00\u07d4\xfc\x82\x15\xa0\xa6\x99\x13\xf6*C\xbf\x1c\x85\x90\xb9\xdd\xcd\r\x8d\u06c9lk\x93[\x8b\xbd@\x00\x00\u07d4\xfc\x98\x9c\xb4\x87\xbf\x1a}\x17\xe4\xc1\xb7\u0137\xaa\xfd\xdak\n\x8d\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xfc\x9b4td\xb2\xf9\x92\x9d\x80~\x03\x9d\xaeH\xd3\u064d\xe3y\x8a\x02\xf6\xf1\a\x80\xd2,\xc0\x00\x00\u07d4\xfc\xa4;\xbc#\xa0\xd3!\xba\x9eF\xb9)s\\\xe7\xd8\xef\f\x18\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xfc\xa7>\xff\x87q\xc0\x10;\xa3\xcc\x1a\x9c%\x94H\xc7*\xbf\v\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xfc\xad\xa3\x00(?k\xcc\x13J\x91Eg`\xb0\xd7}\xe4\x10\xe0\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xfc\xbc\\q\xac\xe7\x97AE\v\x01,\xf6\xb8\xd3\xf1}\xb6\x8ap\x8a\x02\x05\xb4\u07e1\xeetx\x00\x00\u07d4\xfc\xbd\x85\xfe\xeajuO\xcf4ID\x9e7\xff\x97\x84\xf7w<\x89\xa7J\xdai\xab\xd7x\x00\x00\xe0\x94\xfc\xc9\u0524&.z\x02z\xb7Q\x91\x10\xd8\x02\u0115\xce\xea9\x8a\x01YQ\x82\"K&H\x00\x00\xe0\x94\xfc\xcd\r\x1e\xce\xe2z\xdd\xea\x95\xf6\x85z\xee\xc8\u01e0K(\xee\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94\xfc\u0434\x82|\xd2\b\xff\xbf^u\x9d\xba\x8c<\xc6\x1d\x8c,<\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xfc\xe0\x89c\\\xe9z\xba\xc0kD\x81\x9b\xe5\xbb\n>.\v7\x89\x05\x03\x92\nv0\xa7\x80\x00\u07d4\xfc\xf1\x99\xf8\xb8T\"/\x18.N\x1d\t\x9dN2>*\xae\x01\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xfc\xfc:P\x04\xd6xa?\v6\xa6B&\x9a\u007f7\x1c?j\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xfd\x19\x1a5\x15}x\x13s\xfbA\x1b\xf9\xf2R\x90\x04|^\xef\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xfd\x1f\xaa4{\x0f\u0300L-\xa8l6\xd5\xf1\u044bp\x87\xbb\x89\x02\xd6\xeb$z\x96\xf6\x00\x00\u07d4\xfd\x1f\xb5\xa8\x9a\x89\xa7!\xb8yph\xfb\xc4\u007f>\x9dR\xe1I\x89\f\u0435\x83\u007f\xc6X\x00\x00\u07d4\xfd OOJ\xba%%\xbar\x8a\xfd\xf7\x87\x92\xcb\u07b75\xae\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xfd'W\xcc5Q\xa0\x95\x87\x8d\x97\x87V\x15\xfe\fj2\xaa\x8a\x89 m\xb1R\x99\xbe\xac\x00\x00\u07d4\xfd(r\u045eW\x85<\xfa\x16\xef\xfe\x93\u0431\xd4{O\x93\xfb\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xfd))'\x1e\x9d \x95\xa2dv~{\r\xf5.\xa0\xd1\xd4\x00\x89\xa2\xa1\xeb%\x1bZ\xe4\x00\x00\u07d4\xfd7z8Rr\x90\f\xb46\xa3\xbbyb\xcd\xff\xe9?]\xad\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xfd@$+\xb3Jp\x85^\xf0\xfd\x90\xf3\x80-\xec!6\xb3'\x89h\xa8u\a>)$\x00\x00\xe0\x94\xfdE,9i\xec\xe3\x80\x1cT \xf1\xcd\u02a1\xc7\x1e\xd2=\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\xfdKU\x1fo\xdb\u0366\xc5\x11\xb5\xbb7\"P\xa6\xb7\x83\xe54\x89\x01\x1d\xe1\xe6\xdbE\f\x00\x00\u07d4\xfdK\x98\x95X\xae\x11\xbe\f;6\xe2\xd6\xf2\xa5J\x93C\xca.\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xfdM\xe8\xe3t\x8a(\x9c\xf7\xd0`Q}\x9d88\x8d\xb0\x1f\xb8\x89\r\x8drkqw\xa8\x00\x00\u07d4\xfdZc\x15\u007f\x91O\u04d8\uac5c\x13}\xd9U\v\xb7q\\\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xfd`\u04b5\xaf=5\xf7\xaa\xf0\u00d3\x05.y\xc4\xd8#\u0645\x89\x03\x0e\xb5\r.\x14\b\x00\x00\u07d4\xfdhm\xe5?\xa9\u007f\x99c\x9e%hT\x97 \xbcX\x8c\x9e\xfc\x89j\xc5\xc6-\x94\x86\a\x00\x00\u07d4\xfd~\u078fR@\xa0eA\xebi\x9dx,/\x9a\xfb!p\xf6\x89Hz\x9a0E9D\x00\x00\u07d4\xfd\x81+\u019f\xb1p\xefW\xe22~\x80\xaf\xfd\x14\xf8\xe4\xb6\u0489lk\x93[\x8b\xbd@\x00\x00\u07d4\xfd\x88\xd1\x14\"\x0f\b\x1c\xb3\xd5\xe1[\xe8\x15*\xb0sfWj\x89\x10CV\x1a\x88)0\x00\x00\u07d4\xfd\x91\x856\xa8\xef\xa6\xf6\xce\xfe\x1f\xa1\x159\x95\xfe\xf5\xe3=;\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xfd\x92\x0fr&\x82\xaf\xb5\xafE\x1b\x05D\xd4\xf4\x1b;\x9dWB\x89~R\x05j\x12?<\x00\x00\u07d4\xfd\x95y\xf1\x19\xbb\xc8\x19\xa0+a\u3348\x03\xc9B\xf2M2\x89\x05\xb9~\x90\x81\xd9@\x00\x00\u07d4\xfd\xa0\xce\x153\a\a\xf1\v\xce2\x01\x17- \x18\xb9\xdd\xeat\x89\x02\xd0A\xd7\x05\xa2\xc6\x00\x00\xe0\x94\xfd\xa3\x04(\x19\xaf>f)\x00\xe1\xb9+CX\xed\xa6\xe9%\x90\x8a\x19\a\xa2\x84\u054fc\xe0\x00\x00\u07d4\xfd\xa6\x81\x0e\xa5\xac\x98]o\xfb\xf1\xc5\x11\xf1\xc1B\xed\xcf\xdd\xf7\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xfd\xb39D\xf26\x06\x15\xe5\xbe#\x95w\u0221\x9b\xa5-\x98\x87\x89 \x9d\x92/RY\xc5\x00\x00\u07d4\xfd\xbaSY\xf7\xec;\xc7p\xacI\x97]\x84N\xc9qbV\xf1\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xfd\xc4\xd4vZ\x94/[\xf9i1\xa9\xe8\xccz\xb8\xb7W\xffL\x8a\x12lG\x8a\x0e>\xa8`\x00\x00\xe0\x94\xfd\xcd]\x80\xb1\x05\x89zW\xab\xc4xev\x8b)\x00RB\x95\x8a\x01Z\xf1\u05cbX\xc4\x00\x00\x00\u0794\xfd\xd1\x19_y}O5q}\x15\xe6\xf9\x81\n\x9a?\xf5T`\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\xfd\xd5\x02\xa7N\x81;\u03e3U\xce\xda<\x17ojhq\xaf\u007f\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xfd\u357c\vm\\\xbbL\x1d\x8f\xea>\vK\xffc^\x9d\xb7\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xfd\xea\xac*\xcf\x1d\x13\x8e\x19\xf2\xfc?\x9f\xb7E\x92\xe3\ud04a\x89$=M\x18\"\x9c\xa2\x00\x00\u07d4\xfd\xec\xc8-\xdf\xc5a\x92\xe2oV<=h\xcbTJ\x96\xbf\xed\x89\x17\xda:\x04\u01f3\xe0\x00\x00\u07d4\xfd\xf4#C\x01\x9b\v\fk\xf2`\xb1s\xaf\xab~E\xb9\xd6!\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\xfd\xf4I\xf1\b\xc6\xfbOZ+\b\x1e\xed~E\u645eM%\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xfd\xfda4\xc0J\x8a\xb7\xeb\x16\xf0\x06C\xf8\xfe\xd7\u06aa\ucc89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xfe\x00\xbfC\x99\x11\xa5S\x98-\xb68\x03\x92E\xbc\xf02\xdb\u0709\x15[\xd90\u007f\x9f\xe8\x00\x00\u07d4\xfe\x01n\xc1~\xc5\xf1\x0e;\xb9\x8f\xf4\xa1\xed\xa0E\x15v\x82\xab\x89\x14_T\x02\xe7\xb2\xe6\x00\x00\u07d4\xfe\x0e0\xe2\x14)\rt=\xd3\x0e\xb0\x82\xf1\xf0\xa5\"Z\xdea\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xfe!\v\x8f\x04\xdcmOv!j\xcf\xcb\u055b\xa8;\xe9\xb60\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xfe\"\xa0\xb3\x88f\x8d\x1a\xe2d>w\x1d\xac\xf3\x8aCB#\u0309\xd8\xdb^\xbd{&8\x00\x00\u07d4\xfe6&\x88\x84_\xa2D\u0300~K\x110\xeb7A\xa8\x05\x1e\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xfe8'\xd5v0\u03c7a\xd5\x12y{\v\x85\x8eG\x8b\xbd\x12\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xfeA\x8bB\x1a\x9cm76\x02y\x04u\xd20>\x11\xa7Y0\x897\b\xba\xed=h\x90\x00\x00\u07d4\xfeBI\x12yP\xe2\xf8\x96\xec\x0e~.=\x05Z\xab\x10U\x0f\x89$=M\x18\"\x9c\xa2\x00\x00\xe0\x94\xfeM\x84\x03!o\xd5qW+\xf1\xbd\xb0\x1d\x00W\x89x\u0588\x8a\x02\x15\xf85\xbcv\x9d\xa8\x00\x00\u07d4\xfeS\xb9I\x89\u0619d\xda aS\x95&\xbb\xe9y\xdd.\xa9\x89h\xa8u\a>)$\x00\x00\u07d4\xfeT\x9b\xbf\xe6G@\x18\x98\x92\x93%8\u06afF\u04b6\x1dO\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\xe0\x94\xfea]\x97\\\b\x87\xe0\xc9\x11>\xc7)\x84 \xa7\x93\xaf\x8b\x96\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xfee\xc4\x18\x8dy\"Wi\td D\xfd\xc5#\x95V\x01e\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xfei\u007f\xf2,\xa5G\xbf\xc9^3\xd9`\xda`\\gc\xf3[\x89G\xd4\x11\x9f\xd9`\x94\x00\x00\u07d4\xfej\x89[y\\\xb4\xbf\x85\x90=<\xe0\x9cZ\xa49S\u04ff\x89\xb8Pz\x82\a( \x00\x00\u07d4\xfeo_B\xb6\x19;\x1a\xd1b\x06\u4bf5#\x9dM}\xb4^\x89]\u0212\xaa\x111\xc8\x00\x00\u07d4\xfep\x11\xb6\x98\xbf3q\x13-tE\xb1\x9e\xb5\xb0\x945j\xee\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xfe\x80\xe9#-\xea\xff\x19\xba\xf9\x98i\x88:K\xdf\x00\x04\xe5<\x89.b\xf2\ni\xbe@\x00\x00\u07d4\xfe\x8en6eW\r\xffz\x1b\xdaiz\xa5\x89\xc0\xb4\xe9\x02J\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xfe\x8f\x1f\u072b\u007f\xbe\u0266\xa3\xfc\xc5\aa\x96\x00P\\6\xa3\x89\x01\x11du\x9f\xfb2\x00\x00\u07d4\xfe\x91\xec\xcf+\xd5f\xaf\xa1\x16\x96\xc5\x04\x9f\xa8Lic\nR\x89i*\xe8\x89p\x81\xd0\x00\x00\u07d4\xfe\x96\xc4\xcd8\x15b@\x1a\xa3*\x86\xe6[\x9dR\xfa\x8a\xee'\x89\x8f\x1d\\\x1c\xae7@\x00\x00\u07d4\xfe\x98\xc6d\xc3\xe4G\xa9^i\xbdX!q\xb7\x17n\xa2\xa6\x85\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xfe\x9a\xd1.\xf0]m\x90&\x1f\x96\xc84\n\x03\x81\x97M\xf4w\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xfe\x9c\x0f\xff\xef\xb8\x03\b\x12V\xc0\xcfMfY\xe6\xd3>\xb4\xfb\x89R\xd5B\x80O\x1c\xe0\x00\x00\u07d4\xfe\x9c\xfc;\xb2\x93\u0772\x85\xe6%\xf3X/t\xa6\xb0\xa5\xa6\u0349j\xcb=\xf2~\x1f\x88\x00\x00\xe0\x94\xfe\x9e\x11\x97\u05d7JvH\xdc\u01e01\x12\xa8\x8e\xdb\xc9\x04]\x8a\x01\n\xfc\x1a\xde;N\xd4\x00\x00\xe0\x94\xfe\xac\xa2\xactbK\xf3H\xda\u0258QC\xcf\xd6R\xa4\xbeU\x8a\x05\x89\u007f\u02f0)\x14\b\x80\x00\u07d4\xfe\xad\x18\x03\xe5\xe77\xa6\x8e\x18G-\x9a\xc7\x15\xf0\x99L\u00be\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xfe\xb8\xb8\xe2\xafqj\xe4\x1f\xc7\xc0K\xcf)T\x01VF\x1ek\x89TQt\xa5(\xa7z\x00\x00\u07d4\xfe\xb9-0\xbf\x01\xff\x9a\x19\x01flUsS+\xfa\a\xee\xec\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xfe\xbc1s\xbc\x90r\x13cT\x00+{O\xb3\xbf\xc5?\"\xf1\x89\x14\x0e\xc8\x0f\xa7\xee\x88\x00\x00\u07d4\xfe\xbdH\xd0\xff\xdb\xd5el\xd5\xe6\x866:a\x14R(\xf2y\x89\x97\xc9\xceL\xf6\xd5\xc0\x00\x00\u07d4\xfe\xbd\x9f\x81\xcfx\xbd_\xb6\u0139\xa2K\xd4\x14\xbb\x9b\xfaLN\x89k\xe1\x0f\xb8\xedn\x13\x80\x00\u07d4\xfe\xc0o\xe2{D\u01c4\xb29n\xc9/{\x92:\xd1~\x90w\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xfe\xc1NT\x85\xde+>\xef^t\xc4aF\u06ceEN\x035\x89\t\xb4\x1f\xbf\x9e\n\xec\x00\x00\u07d4\xfe\xd8Gm\x10\u0544\xb3\x8b\xfag7`\x0e\xf1\x9d5\xc4\x1e\u0609b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4\xfe\xef;n\xab\xc9J\xff\xd31\f\x1cM\x0ee7^\x13\x11\x19\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xfe\xf0\x9dp$?9\xed\x8c\xd8\x00\xbf\x96QG\x9e\x8fJ\xca<\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xfe\xf3\xb3\u07ad\x1ai&\u051a\xa3+\x12\xc2*\xf5M\x9f\xf9\x85\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xff\v|\xb7\x1d\xa9\xd4\xc1\xean\xcc(\xeb\xdaPLc\xf8/\u04498\x8a\x88]\xf2\xfcl\x00\x00\u07d4\xff\f\xc6\u73c9lk\x93[\x8b\xbd@\x00\x00\u07d4\xff'&)AH\xb8lx\xa97$\x97\xe4Y\x89\x8e\xd3\xfe\xe3\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xff=\xedz@\u04ef\xf0\u05e8\xc4_\xa6\x13j\xa0C=\xb4W\x89lh\xcc\u041b\x02,\x00\x00\u07d4\xff>\xeeW\xc3Mm\xae\x97\r\x8b1\x11\x17\xc55\x86\xcd5\x02\x89\\(=A\x03\x94\x10\x00\x00\u07d4\xff>\xf6\xba\x15\x1c!\xb5\x99\x86\xaed\xf6\xe8\"\x8b\u0262\xc73\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xffA\xd9\xe1\xb4\xef\xfe\x18\u0630\xd1\xf6?\xc4%_\xb4\xe0l=\x89Hz\x9a0E9D\x00\x00\u07d4\xffE\xcb4\xc9(6M\x9c\xc9\u063b\x0074ta\x8f\x06\xf3\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94\xffI\xa7u\x81N\xc0\x00Q\xa7\x95\xa8u\xde$Y.\xa4\x00\u050a*Z\x05\x8f\u0095\xed\x00\x00\x00\u07d4\xffJ@\x8fP\xe9\xe7!F\xa2\x8c\xe4\xfc\x8d\x90'\x1f\x11n\x84\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xffM\x9c\x84\x84\xc4\x10T\x89H\xa4\x80\xc2?\x80\xc2@\x80\xc2A\x80\xc2B\x80\xc2C\x80\xc2D\x80\xc2E\x80\xc2F\x80\xc2G\x80\xc2H\x80\xc2I\x80\xc2J\x80\xc2K\x80\xc2L\x80\xc2M\x80\xc2N\x80\xc2O\x80\xc2P\x80\xc2Q\x80\xc2R\x80\xc2S\x80\xc2T\x80\xc2U\x80\xc2V\x80\xc2W\x80\xc2X\x80\xc2Y\x80\xc2Z\x80\xc2[\x80\xc2\\\x80\xc2]\x80\xc2^\x80\xc2_\x80\xc2`\x80\xc2a\x80\xc2b\x80\xc2c\x80\xc2d\x80\xc2e\x80\xc2f\x80\xc2g\x80\xc2h\x80\xc2i\x80\xc2j\x80\xc2k\x80\xc2l\x80\xc2m\x80\xc2n\x80\xc2o\x80\xc2p\x80\xc2q\x80\xc2r\x80\xc2s\x80\xc2t\x80\xc2u\x80\xc2v\x80\xc2w\x80\xc2x\x80\xc2y\x80\xc2z\x80\xc2{\x80\xc2|\x80\xc2}\x80\xc2~\x80\xc2\u007f\x80\u00c1\x80\x80\u00c1\x81\x80\u00c1\x82\x80\u00c1\x83\x80\u00c1\x84\x80\u00c1\x85\x80\u00c1\x86\x80\u00c1\x87\x80\u00c1\x88\x80\u00c1\x89\x80\u00c1\x8a\x80\u00c1\x8b\x80\u00c1\x8c\x80\u00c1\x8d\x80\u00c1\x8e\x80\u00c1\x8f\x80\u00c1\x90\x80\u00c1\x91\x80\u00c1\x92\x80\u00c1\x93\x80\u00c1\x94\x80\u00c1\x95\x80\u00c1\x96\x80\u00c1\x97\x80\u00c1\x98\x80\u00c1\x99\x80\u00c1\x9a\x80\u00c1\x9b\x80\u00c1\x9c\x80\u00c1\x9d\x80\u00c1\x9e\x80\u00c1\x9f\x80\u00c1\xa0\x80\u00c1\xa1\x80\u00c1\xa2\x80\u00c1\xa3\x80\u00c1\xa4\x80\u00c1\xa5\x80\u00c1\xa6\x80\u00c1\xa7\x80\u00c1\xa8\x80\u00c1\xa9\x80\u00c1\xaa\x80\u00c1\xab\x80\u00c1\xac\x80\u00c1\xad\x80\u00c1\xae\x80\u00c1\xaf\x80\u00c1\xb0\x80\u00c1\xb1\x80\u00c1\xb2\x80\u00c1\xb3\x80\u00c1\xb4\x80\u00c1\xb5\x80\u00c1\xb6\x80\u00c1\xb7\x80\u00c1\xb8\x80\u00c1\xb9\x80\u00c1\xba\x80\u00c1\xbb\x80\u00c1\xbc\x80\u00c1\xbd\x80\u00c1\xbe\x80\u00c1\xbf\x80\u00c1\xc0\x80\u00c1\xc1\x80\u00c1\u0080\u00c1\u00c0\u00c1\u0100\u00c1\u0140\u00c1\u0180\u00c1\u01c0\u00c1\u0200\u00c1\u0240\u00c1\u0280\u00c1\u02c0\u00c1\u0300\u00c1\u0340\u00c1\u0380\u00c1\u03c0\u00c1\u0400\u00c1\u0440\u00c1\u0480\u00c1\u04c0\u00c1\u0500\u00c1\u0540\u00c1\u0580\u00c1\u05c0\u00c1\u0600\u00c1\u0640\u00c1\u0680\u00c1\u06c0\u00c1\u0700\u00c1\u0740\u00c1\u0780\u00c1\u07c0\u00c1\xe0\x80\u00c1\xe1\x80\u00c1\xe2\x80\u00c1\xe3\x80\u00c1\xe4\x80\u00c1\xe5\x80\u00c1\xe6\x80\u00c1\xe7\x80\u00c1\xe8\x80\u00c1\xe9\x80\u00c1\xea\x80\u00c1\xeb\x80\u00c1\xec\x80\u00c1\xed\x80\u00c1\xee\x80\u00c1\xef\x80\u00c1\xf0\x80\u00c1\xf1\x80\u00c1\xf2\x80\u00c1\xf3\x80\u00c1\xf4\x80\u00c1\xf5\x80\u00c1\xf6\x80\u00c1\xf7\x80\u00c1\xf8\x80\u00c1\xf9\x80\u00c1\xfa\x80\u00c1\xfb\x80\u00c1\xfc\x80\u00c1\xfd\x80\u00c1\xfe\x80\u00c1\xff\x80\u3507KT\xa8\xbd\x15)f\xd6?pk\xae\x1f\xfe\xb0A\x19!\xe5\x8d\f\x9f,\x9c\xd0Ft\xed\xea@\x00\x00\x00"
+const devAllocData = "\xf9\x01\x94\xc2\x01\x01\xc2\x02\x01\xc2\x03\x01\xc2\x04\x01\xf0\x94\x1a&3\x8f\r\x90^)_\u0337\x1f\xa9\ua11f\xfa\x12\xaa\xf4\x9a\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf0\x94.\xf4q\x00\xe0x{\x91Q\x05\xfd^?O\xf6u y\xd5\u02da\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf0\x94l8jK&\xf7<\x80/4g?rH\xbb\x11\x8f\x97BJ\x9a\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf0\x94\xb9\xc0\x15\x91\x8b\u06ba$\xb4\xff\x05z\x92\xa3\x87=n\xb2\x01\xbe\x9a\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf0\x94\xcd*=\x9f\x93\x8e\x13\u0354~\xc0Z\xbc\u007f\xe74\u07cd\xd8&\x9a\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf0\x94\xdb\xdb\xdb,\xbd#\xb7\x83t\x1e\x8d\u007f\xcfQ\xe4Y\xb4\x97\u499a\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf0\x94\xe4\x15{4\xea\x96\x15\u03fd\xe6\xb4\xfd\xa4\x19\x82\x81$\xb7\fx\x9a\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf0\x94\xe6qo\x95D\xa5lS\r\x86\x8eK\xfb\xac\xb1r1[\u07ad\x9a\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
diff --git a/core/genesis_test.go b/core/genesis_test.go
new file mode 100644
index 0000000000..b73dd776fe
--- /dev/null
+++ b/core/genesis_test.go
@@ -0,0 +1,161 @@
+// Copyright 2017 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+package core
+
+import (
+ "math/big"
+ "reflect"
+ "testing"
+
+ "github.com/davecgh/go-spew/spew"
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/core/vm"
+ "github.com/ethereum/go-ethereum/ethdb"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/ethereum/go-ethereum/params"
+ "github.com/ethereum/go-ethereum/pow"
+)
+
+func TestDefaultGenesisBlock(t *testing.T) {
+ block, _ := DefaultGenesisBlock().ToBlock()
+ if block.Hash() != params.MainNetGenesisHash {
+ t.Errorf("wrong mainnet genesis hash, got %v, want %v", block.Hash(), params.MainNetGenesisHash)
+ }
+ block, _ = DefaultTestnetGenesisBlock().ToBlock()
+ if block.Hash() != params.TestNetGenesisHash {
+ t.Errorf("wrong testnet genesis hash, got %v, want %v", block.Hash(), params.TestNetGenesisHash)
+ }
+}
+
+func TestSetupGenesis(t *testing.T) {
+ var (
+ customghash = common.HexToHash("0x89c99d90b79719238d2645c7642f2c9295246e80775b38cfd162b696817fbd50")
+ customg = Genesis{
+ Config: ¶ms.ChainConfig{HomesteadBlock: big.NewInt(3)},
+ Alloc: GenesisAlloc{
+ {1}: {Balance: big.NewInt(1), Storage: map[common.Hash]common.Hash{{1}: {1}}},
+ },
+ }
+ oldcustomg = customg
+ )
+ oldcustomg.Config = ¶ms.ChainConfig{HomesteadBlock: big.NewInt(2)}
+ tests := []struct {
+ name string
+ fn func(ethdb.Database) (*params.ChainConfig, common.Hash, error)
+ wantConfig *params.ChainConfig
+ wantHash common.Hash
+ wantErr error
+ }{
+ {
+ name: "genesis without ChainConfig",
+ fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
+ return SetupGenesisBlock(db, new(Genesis))
+ },
+ wantErr: errGenesisNoConfig,
+ wantConfig: params.AllProtocolChanges,
+ },
+ {
+ name: "no block in DB, genesis == nil",
+ fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
+ return SetupGenesisBlock(db, nil)
+ },
+ wantHash: params.MainNetGenesisHash,
+ wantConfig: params.MainnetChainConfig,
+ },
+ {
+ name: "mainnet block in DB, genesis == nil",
+ fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
+ DefaultGenesisBlock().MustCommit(db)
+ return SetupGenesisBlock(db, nil)
+ },
+ wantHash: params.MainNetGenesisHash,
+ wantConfig: params.MainnetChainConfig,
+ },
+ {
+ name: "custom block in DB, genesis == nil",
+ fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
+ customg.MustCommit(db)
+ return SetupGenesisBlock(db, nil)
+ },
+ wantHash: customghash,
+ wantConfig: customg.Config,
+ },
+ {
+ name: "custom block in DB, genesis == testnet",
+ fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
+ customg.MustCommit(db)
+ return SetupGenesisBlock(db, DefaultTestnetGenesisBlock())
+ },
+ wantErr: &GenesisMismatchError{Stored: customghash, New: params.TestNetGenesisHash},
+ wantHash: params.TestNetGenesisHash,
+ wantConfig: params.TestnetChainConfig,
+ },
+ {
+ name: "compatible config in DB",
+ fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
+ oldcustomg.MustCommit(db)
+ return SetupGenesisBlock(db, &customg)
+ },
+ wantHash: customghash,
+ wantConfig: customg.Config,
+ },
+ {
+ name: "incompatible config in DB",
+ fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
+ // Commit the 'old' genesis block with Homestead transition at #2.
+ // Advance to block #4, past the homestead transition block of customg.
+ genesis := oldcustomg.MustCommit(db)
+ bc, _ := NewBlockChain(db, oldcustomg.Config, pow.FakePow{}, new(event.TypeMux), vm.Config{})
+ bc.SetValidator(bproc{})
+ bc.InsertChain(makeBlockChainWithDiff(genesis, []int{2, 3, 4, 5}, 0))
+ bc.CurrentBlock()
+ // This should return a compatibility error.
+ return SetupGenesisBlock(db, &customg)
+ },
+ wantHash: customghash,
+ wantConfig: customg.Config,
+ wantErr: ¶ms.ConfigCompatError{
+ What: "Homestead fork block",
+ StoredConfig: big.NewInt(2),
+ NewConfig: big.NewInt(3),
+ RewindTo: 1,
+ },
+ },
+ }
+
+ for _, test := range tests {
+ db, _ := ethdb.NewMemDatabase()
+ config, hash, err := test.fn(db)
+ // Check the return values.
+ if !reflect.DeepEqual(err, test.wantErr) {
+ spew := spew.ConfigState{DisablePointerAddresses: true, DisableCapacities: true}
+ t.Errorf("%s: returned error %#v, want %#v", test.name, spew.NewFormatter(err), spew.NewFormatter(test.wantErr))
+ }
+ if !reflect.DeepEqual(config, test.wantConfig) {
+ t.Errorf("%s:\nreturned %v\nwant %v", test.name, config, test.wantConfig)
+ }
+ if hash != test.wantHash {
+ t.Errorf("%s: returned hash %s, want %s", test.name, hash.Hex(), test.wantHash.Hex())
+ } else if err == nil {
+ // Check database content.
+ stored := GetBlock(db, test.wantHash, 0)
+ if stored.Hash() != test.wantHash {
+ t.Errorf("%s: block in DB has hash %s, want %s", test.name, stored.Hash(), test.wantHash)
+ }
+ }
+ }
+}
diff --git a/core/headerchain.go b/core/headerchain.go
index 1dc189323d..e7660cc600 100644
--- a/core/headerchain.go
+++ b/core/headerchain.go
@@ -30,8 +30,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethdb"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/pow"
"github.com/hashicorp/golang-lru"
@@ -98,12 +97,7 @@ func NewHeaderChain(chainDb ethdb.Database, config *params.ChainConfig, getValid
hc.genesisHeader = hc.GetHeaderByNumber(0)
if hc.genesisHeader == nil {
- genesisBlock, err := WriteDefaultGenesisBlock(chainDb)
- if err != nil {
- return nil, err
- }
- glog.V(logger.Info).Infoln("WARNING: Wrote default ethereum genesis block")
- hc.genesisHeader = genesisBlock.Header()
+ return nil, ErrNoGenesis
}
hc.currentHeader = hc.genesisHeader
@@ -155,12 +149,11 @@ func (hc *HeaderChain) WriteHeader(header *types.Header) (status WriteStatus, er
// Irrelevant of the canonical status, write the td and header to the database
if err := hc.WriteTd(hash, number, externTd); err != nil {
- glog.Fatalf("failed to write header total difficulty: %v", err)
+ log.Crit("Failed to write header total difficulty", "err", err)
}
if err := WriteHeader(hc.chainDb, header); err != nil {
- glog.Fatalf("failed to write header contents: %v", err)
+ log.Crit("Failed to write header content", "err", err)
}
-
// If the total difficulty is higher than our known, add it to the canonical chain
// Second clause in the if statement reduces the vulnerability to selfish mining.
// Please refer to http://www.cs.cornell.edu/~ie53/publications/btcProcFC.pdf
@@ -186,15 +179,13 @@ func (hc *HeaderChain) WriteHeader(header *types.Header) (status WriteStatus, er
headNumber = headHeader.Number.Uint64() - 1
headHeader = hc.GetHeader(headHash, headNumber)
}
-
// Extend the canonical chain with the new header
if err := WriteCanonicalHash(hc.chainDb, hash, number); err != nil {
- glog.Fatalf("failed to insert header number: %v", err)
+ log.Crit("Failed to insert header number", "err", err)
}
if err := WriteHeadHeaderHash(hc.chainDb, hash); err != nil {
- glog.Fatalf("failed to insert head header hash: %v", err)
+ log.Crit("Failed to insert head header hash", "err", err)
}
-
hc.currentHeaderHash, hc.currentHeader = hash, types.CopyHeader(header)
status = CanonStatTy
@@ -223,21 +214,19 @@ type WhCallback func(*types.Header) error
// should be done or not. The reason behind the optional check is because some
// of the header retrieval mechanisms already need to verfy nonces, as well as
// because nonces can be verified sparsely, not needing to check each.
-func (hc *HeaderChain) InsertHeaderChain(chain []*types.Header, checkFreq int, writeHeader WhCallback) (int, error) {
+
+func (hc *HeaderChain) ValidateHeaderChain(chain []*types.Header, checkFreq int) (int, error) {
// Do a sanity check that the provided chain is actually ordered and linked
for i := 1; i < len(chain); i++ {
if chain[i].Number.Uint64() != chain[i-1].Number.Uint64()+1 || chain[i].ParentHash != chain[i-1].Hash() {
// Chain broke ancestry, log a messge (programming error) and skip insertion
- failure := fmt.Errorf("non contiguous insert: item %d is #%d [%x…], item %d is #%d [%x…] (parent [%x…])",
- i-1, chain[i-1].Number.Uint64(), chain[i-1].Hash().Bytes()[:4], i, chain[i].Number.Uint64(), chain[i].Hash().Bytes()[:4], chain[i].ParentHash.Bytes()[:4])
+ log.Error("Non contiguous header insert", "number", chain[i].Number, "hash", chain[i].Hash(),
+ "parent", chain[i].ParentHash, "prevnumber", chain[i-1].Number, "prevhash", chain[i-1].Hash())
- glog.V(logger.Error).Info(failure.Error())
- return 0, failure
+ return 0, fmt.Errorf("non contiguous insert: item %d is #%d [%x…], item %d is #%d [%x…] (parent [%x…])", i-1, chain[i-1].Number,
+ chain[i-1].Hash().Bytes()[:4], i, chain[i].Number, chain[i].Hash().Bytes()[:4], chain[i].ParentHash[:4])
}
}
- // Collect some import statistics to report on
- stats := struct{ processed, ignored int }{}
- start := time.Now()
// Generate the list of headers that should be POW verified
verify := make([]bool, len(chain))
@@ -313,11 +302,18 @@ func (hc *HeaderChain) InsertHeaderChain(chain []*types.Header, checkFreq int, w
}
}
}
+
+ return 0, nil
+}
+
+func (hc *HeaderChain) InsertHeaderChain(chain []*types.Header, writeHeader WhCallback, start time.Time) (int, error) {
+ // Collect some import statistics to report on
+ stats := struct{ processed, ignored int }{}
// All headers passed verification, import them into the database
for i, header := range chain {
// Short circuit insertion if shutting down
if hc.procInterrupt() {
- glog.V(logger.Debug).Infoln("premature abort during header chain processing")
+ log.Debug("Premature abort during headers processing")
break
}
hash := header.Hash()
@@ -333,13 +329,9 @@ func (hc *HeaderChain) InsertHeaderChain(chain []*types.Header, checkFreq int, w
stats.processed++
}
// Report some public statistics so the user has a clue what's going on
- first, last := chain[0], chain[len(chain)-1]
-
- ignored := ""
- if stats.ignored > 0 {
- ignored = fmt.Sprintf(" (%d ignored)", stats.ignored)
- }
- glog.V(logger.Info).Infof("imported %4d headers%s in %9v. #%v [%x… / %x…]", stats.processed, ignored, common.PrettyDuration(time.Since(start)), last.Number, first.Hash().Bytes()[:4], last.Hash().Bytes()[:4])
+ last := chain[len(chain)-1]
+ log.Info("Imported new block headers", "count", stats.processed, "elapsed", common.PrettyDuration(time.Since(start)),
+ "number", last.Number, "hash", last.Hash(), "ignored", stats.ignored)
return 0, nil
}
@@ -360,7 +352,7 @@ func (hc *HeaderChain) GetBlockHashesFromHash(hash common.Hash, max uint64) []co
break
}
chain = append(chain, next)
- if header.Number.Cmp(common.Big0) == 0 {
+ if header.Number.Sign() == 0 {
break
}
}
@@ -446,7 +438,7 @@ func (hc *HeaderChain) CurrentHeader() *types.Header {
// SetCurrentHeader sets the current head header of the canonical chain.
func (hc *HeaderChain) SetCurrentHeader(head *types.Header) {
if err := WriteHeadHeaderHash(hc.chainDb, head.Hash()); err != nil {
- glog.Fatalf("failed to insert head header hash: %v", err)
+ log.Crit("Failed to insert head header hash", "err", err)
}
hc.currentHeader = head
hc.currentHeaderHash = head.Hash()
@@ -489,7 +481,7 @@ func (hc *HeaderChain) SetHead(head uint64, delFn DeleteCallback) {
hc.currentHeaderHash = hc.currentHeader.Hash()
if err := WriteHeadHeaderHash(hc.chainDb, hc.currentHeaderHash); err != nil {
- glog.Fatalf("failed to reset head header hash: %v", err)
+ log.Crit("Failed to reset head header hash", "err", err)
}
}
diff --git a/core/mkalloc.go b/core/mkalloc.go
new file mode 100644
index 0000000000..565e8c5826
--- /dev/null
+++ b/core/mkalloc.go
@@ -0,0 +1,85 @@
+// Copyright 2017 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+// +build none
+
+/*
+
+ The mkalloc tool creates the genesis allocation constants in genesis_alloc.go
+ It outputs a const declaration that contains an RLP-encoded list of (address, balance) tuples.
+
+ go run mkalloc.go genesis.json
+
+*/
+package main
+
+import (
+ "encoding/json"
+ "fmt"
+ "math/big"
+ "os"
+ "sort"
+ "strconv"
+
+ "github.com/ethereum/go-ethereum/core"
+ "github.com/ethereum/go-ethereum/rlp"
+)
+
+type allocItem struct{ Addr, Balance *big.Int }
+
+type allocList []allocItem
+
+func (a allocList) Len() int { return len(a) }
+func (a allocList) Less(i, j int) bool { return a[i].Addr.Cmp(a[j].Addr) < 0 }
+func (a allocList) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
+
+func makelist(g *core.Genesis) allocList {
+ a := make(allocList, 0, len(g.Alloc))
+ for addr, account := range g.Alloc {
+ if len(account.Storage) > 0 || len(account.Code) > 0 || account.Nonce != 0 {
+ panic(fmt.Sprintf("can't encode account %x", addr))
+ }
+ a = append(a, allocItem{addr.Big(), account.Balance})
+ }
+ sort.Sort(a)
+ return a
+}
+
+func makealloc(g *core.Genesis) string {
+ a := makelist(g)
+ data, err := rlp.EncodeToBytes(a)
+ if err != nil {
+ panic(err)
+ }
+ return strconv.QuoteToASCII(string(data))
+}
+
+func main() {
+ if len(os.Args) != 2 {
+ fmt.Fprintln(os.Stderr, "Usage: mkalloc genesis.json")
+ os.Exit(1)
+ }
+
+ g := new(core.Genesis)
+ file, err := os.Open(os.Args[1])
+ if err != nil {
+ panic(err)
+ }
+ if err := json.NewDecoder(file).Decode(g); err != nil {
+ panic(err)
+ }
+ fmt.Println("const allocData =", makealloc(g))
+}
diff --git a/core/state/iterator.go b/core/state/iterator.go
index a58a15ad39..170aec9833 100644
--- a/core/state/iterator.go
+++ b/core/state/iterator.go
@@ -31,15 +31,14 @@ import (
type NodeIterator struct {
state *StateDB // State being iterated
- stateIt *trie.NodeIterator // Primary iterator for the global state trie
- dataIt *trie.NodeIterator // Secondary iterator for the data trie of a contract
+ stateIt trie.NodeIterator // Primary iterator for the global state trie
+ dataIt trie.NodeIterator // Secondary iterator for the data trie of a contract
accountHash common.Hash // Hash of the node containing the account
codeHash common.Hash // Hash of the contract source code
code []byte // Source code associated with a contract
Hash common.Hash // Hash of the current entry being iterated (nil if not standalone)
- Entry interface{} // Current state entry being iterated (internal representation)
Parent common.Hash // Hash of the first full ancestor node (nil if current is the root)
Error error // Failure set in case of an internal error in the iterator
@@ -80,9 +79,9 @@ func (it *NodeIterator) step() error {
}
// If we had data nodes previously, we surely have at least state nodes
if it.dataIt != nil {
- if cont := it.dataIt.Next(); !cont {
- if it.dataIt.Error != nil {
- return it.dataIt.Error
+ if cont := it.dataIt.Next(true); !cont {
+ if it.dataIt.Error() != nil {
+ return it.dataIt.Error()
}
it.dataIt = nil
}
@@ -94,15 +93,15 @@ func (it *NodeIterator) step() error {
return nil
}
// Step to the next state trie node, terminating if we're out of nodes
- if cont := it.stateIt.Next(); !cont {
- if it.stateIt.Error != nil {
- return it.stateIt.Error
+ if cont := it.stateIt.Next(true); !cont {
+ if it.stateIt.Error() != nil {
+ return it.stateIt.Error()
}
it.state, it.stateIt = nil, nil
return nil
}
// If the state trie node is an internal entry, leave as is
- if !it.stateIt.Leaf {
+ if !it.stateIt.Leaf() {
return nil
}
// Otherwise we've reached an account node, initiate data iteration
@@ -112,7 +111,7 @@ func (it *NodeIterator) step() error {
Root common.Hash
CodeHash []byte
}
- if err := rlp.Decode(bytes.NewReader(it.stateIt.LeafBlob), &account); err != nil {
+ if err := rlp.Decode(bytes.NewReader(it.stateIt.LeafBlob()), &account); err != nil {
return err
}
dataTrie, err := trie.New(account.Root, it.state.db)
@@ -120,7 +119,7 @@ func (it *NodeIterator) step() error {
return err
}
it.dataIt = trie.NewNodeIterator(dataTrie)
- if !it.dataIt.Next() {
+ if !it.dataIt.Next(true) {
it.dataIt = nil
}
if !bytes.Equal(account.CodeHash, emptyCodeHash) {
@@ -130,7 +129,7 @@ func (it *NodeIterator) step() error {
return fmt.Errorf("code %x: %v", account.CodeHash, err)
}
}
- it.accountHash = it.stateIt.Parent
+ it.accountHash = it.stateIt.Parent()
return nil
}
@@ -138,7 +137,7 @@ func (it *NodeIterator) step() error {
// The method returns whether there are any more data left for inspection.
func (it *NodeIterator) retrieve() bool {
// Clear out any previously set values
- it.Hash, it.Entry = common.Hash{}, nil
+ it.Hash = common.Hash{}
// If the iteration's done, return no available data
if it.state == nil {
@@ -147,14 +146,14 @@ func (it *NodeIterator) retrieve() bool {
// Otherwise retrieve the current entry
switch {
case it.dataIt != nil:
- it.Hash, it.Entry, it.Parent = it.dataIt.Hash, it.dataIt.Node, it.dataIt.Parent
+ it.Hash, it.Parent = it.dataIt.Hash(), it.dataIt.Parent()
if it.Parent == (common.Hash{}) {
it.Parent = it.accountHash
}
case it.code != nil:
- it.Hash, it.Entry, it.Parent = it.codeHash, it.code, it.accountHash
+ it.Hash, it.Parent = it.codeHash, it.accountHash
case it.stateIt != nil:
- it.Hash, it.Entry, it.Parent = it.stateIt.Hash, it.stateIt.Node, it.stateIt.Parent
+ it.Hash, it.Parent = it.stateIt.Hash(), it.stateIt.Parent()
}
return true
}
diff --git a/core/state/journal.go b/core/state/journal.go
index 68d07fa03c..5cd41477d9 100644
--- a/core/state/journal.go
+++ b/core/state/journal.go
@@ -34,7 +34,7 @@ type (
account *common.Address
}
resetObjectChange struct {
- prev *StateObject
+ prev *stateObject
}
suicideChange struct {
account *common.Address
@@ -86,7 +86,7 @@ func (ch resetObjectChange) undo(s *StateDB) {
}
func (ch suicideChange) undo(s *StateDB) {
- obj := s.GetStateObject(*ch.account)
+ obj := s.getStateObject(*ch.account)
if obj != nil {
obj.suicided = ch.prev
obj.setBalance(ch.prevbalance)
@@ -103,19 +103,19 @@ func (ch touchChange) undo(s *StateDB) {
}
func (ch balanceChange) undo(s *StateDB) {
- s.GetStateObject(*ch.account).setBalance(ch.prev)
+ s.getStateObject(*ch.account).setBalance(ch.prev)
}
func (ch nonceChange) undo(s *StateDB) {
- s.GetStateObject(*ch.account).setNonce(ch.prev)
+ s.getStateObject(*ch.account).setNonce(ch.prev)
}
func (ch codeChange) undo(s *StateDB) {
- s.GetStateObject(*ch.account).setCode(common.BytesToHash(ch.prevhash), ch.prevcode)
+ s.getStateObject(*ch.account).setCode(common.BytesToHash(ch.prevhash), ch.prevcode)
}
func (ch storageChange) undo(s *StateDB) {
- s.GetStateObject(*ch.account).setState(ch.key, ch.prevalue)
+ s.getStateObject(*ch.account).setState(ch.key, ch.prevalue)
}
func (ch refundChange) undo(s *StateDB) {
diff --git a/core/state/managed_state.go b/core/state/managed_state.go
index 0d8f9dd284..1390ef4a00 100644
--- a/core/state/managed_state.go
+++ b/core/state/managed_state.go
@@ -23,7 +23,7 @@ import (
)
type account struct {
- stateObject *StateObject
+ stateObject *stateObject
nstart uint64
nonces []bool
}
@@ -128,7 +128,7 @@ func (ms *ManagedState) getAccount(addr common.Address) *account {
} else {
// Always make sure the state account nonce isn't actually higher
// than the tracked one.
- so := ms.StateDB.GetStateObject(addr)
+ so := ms.StateDB.getStateObject(addr)
if so != nil && uint64(len(account.nonces))+account.nstart < so.Nonce() {
ms.accounts[addr] = newAccount(so)
}
@@ -138,6 +138,6 @@ func (ms *ManagedState) getAccount(addr common.Address) *account {
return ms.accounts[addr]
}
-func newAccount(so *StateObject) *account {
+func newAccount(so *stateObject) *account {
return &account{so, so.Nonce(), nil}
}
diff --git a/core/state/managed_state_test.go b/core/state/managed_state_test.go
index 0a3be9f5a9..ea5737a089 100644
--- a/core/state/managed_state_test.go
+++ b/core/state/managed_state_test.go
@@ -30,7 +30,7 @@ func create() (*ManagedState, *account) {
statedb, _ := New(common.Hash{}, db)
ms := ManageState(statedb)
ms.StateDB.SetNonce(addr, 100)
- ms.accounts[addr] = newAccount(ms.StateDB.GetStateObject(addr))
+ ms.accounts[addr] = newAccount(ms.StateDB.getStateObject(addr))
return ms, ms.accounts[addr]
}
diff --git a/core/state/state_object.go b/core/state/state_object.go
index 87aa8ccd65..7f994ee6d6 100644
--- a/core/state/state_object.go
+++ b/core/state/state_object.go
@@ -24,8 +24,6 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/trie"
)
@@ -57,13 +55,13 @@ func (self Storage) Copy() Storage {
return cpy
}
-// StateObject represents an Ethereum account which is being modified.
+// stateObject represents an Ethereum account which is being modified.
//
// The usage pattern is as follows:
// First you need to obtain a state object.
// Account values can be accessed and modified through the object.
// Finally, call CommitTrie to write the modified storage trie into a database.
-type StateObject struct {
+type stateObject struct {
address common.Address // Ethereum address of this account
data Account
db *StateDB
@@ -93,8 +91,8 @@ type StateObject struct {
}
// empty returns whether the account is considered empty.
-func (s *StateObject) empty() bool {
- return s.data.Nonce == 0 && s.data.Balance.BitLen() == 0 && bytes.Equal(s.data.CodeHash, emptyCodeHash)
+func (s *stateObject) empty() bool {
+ return s.data.Nonce == 0 && s.data.Balance.Sign() == 0 && bytes.Equal(s.data.CodeHash, emptyCodeHash)
}
// Account is the Ethereum consensus representation of accounts.
@@ -107,40 +105,37 @@ type Account struct {
}
// newObject creates a state object.
-func newObject(db *StateDB, address common.Address, data Account, onDirty func(addr common.Address)) *StateObject {
+func newObject(db *StateDB, address common.Address, data Account, onDirty func(addr common.Address)) *stateObject {
if data.Balance == nil {
data.Balance = new(big.Int)
}
if data.CodeHash == nil {
data.CodeHash = emptyCodeHash
}
- return &StateObject{db: db, address: address, data: data, cachedStorage: make(Storage), dirtyStorage: make(Storage), onDirty: onDirty}
+ return &stateObject{db: db, address: address, data: data, cachedStorage: make(Storage), dirtyStorage: make(Storage), onDirty: onDirty}
}
// EncodeRLP implements rlp.Encoder.
-func (c *StateObject) EncodeRLP(w io.Writer) error {
+func (c *stateObject) EncodeRLP(w io.Writer) error {
return rlp.Encode(w, c.data)
}
// setError remembers the first non-nil error it is called with.
-func (self *StateObject) setError(err error) {
+func (self *stateObject) setError(err error) {
if self.dbErr == nil {
self.dbErr = err
}
}
-func (self *StateObject) markSuicided() {
+func (self *stateObject) markSuicided() {
self.suicided = true
if self.onDirty != nil {
self.onDirty(self.Address())
self.onDirty = nil
}
- if glog.V(logger.Core) {
- glog.Infof("%x: #%d %v X\n", self.Address(), self.Nonce(), self.Balance())
- }
}
-func (c *StateObject) touch() {
+func (c *stateObject) touch() {
c.db.journal = append(c.db.journal, touchChange{
account: &c.address,
prev: c.touched,
@@ -152,7 +147,7 @@ func (c *StateObject) touch() {
c.touched = true
}
-func (c *StateObject) getTrie(db trie.Database) *trie.SecureTrie {
+func (c *stateObject) getTrie(db trie.Database) *trie.SecureTrie {
if c.trie == nil {
var err error
c.trie, err = trie.NewSecure(c.data.Root, db, 0)
@@ -165,7 +160,7 @@ func (c *StateObject) getTrie(db trie.Database) *trie.SecureTrie {
}
// GetState returns a value in account storage.
-func (self *StateObject) GetState(db trie.Database, key common.Hash) common.Hash {
+func (self *stateObject) GetState(db trie.Database, key common.Hash) common.Hash {
value, exists := self.cachedStorage[key]
if exists {
return value
@@ -185,7 +180,7 @@ func (self *StateObject) GetState(db trie.Database, key common.Hash) common.Hash
}
// SetState updates a value in account storage.
-func (self *StateObject) SetState(db trie.Database, key, value common.Hash) {
+func (self *stateObject) SetState(db trie.Database, key, value common.Hash) {
self.db.journal = append(self.db.journal, storageChange{
account: &self.address,
key: key,
@@ -194,7 +189,7 @@ func (self *StateObject) SetState(db trie.Database, key, value common.Hash) {
self.setState(key, value)
}
-func (self *StateObject) setState(key, value common.Hash) {
+func (self *stateObject) setState(key, value common.Hash) {
self.cachedStorage[key] = value
self.dirtyStorage[key] = value
@@ -205,7 +200,7 @@ func (self *StateObject) setState(key, value common.Hash) {
}
// updateTrie writes cached storage modifications into the object's storage trie.
-func (self *StateObject) updateTrie(db trie.Database) {
+func (self *stateObject) updateTrie(db trie.Database) {
tr := self.getTrie(db)
for key, value := range self.dirtyStorage {
delete(self.dirtyStorage, key)
@@ -220,14 +215,14 @@ func (self *StateObject) updateTrie(db trie.Database) {
}
// UpdateRoot sets the trie root to the current root hash of
-func (self *StateObject) updateRoot(db trie.Database) {
+func (self *stateObject) updateRoot(db trie.Database) {
self.updateTrie(db)
self.data.Root = self.trie.Hash()
}
// CommitTrie the storage trie of the object to dwb.
// This updates the trie root.
-func (self *StateObject) CommitTrie(db trie.Database, dbw trie.DatabaseWriter) error {
+func (self *stateObject) CommitTrie(db trie.Database, dbw trie.DatabaseWriter) error {
self.updateTrie(db)
if self.dbErr != nil {
return self.dbErr
@@ -241,10 +236,10 @@ func (self *StateObject) CommitTrie(db trie.Database, dbw trie.DatabaseWriter) e
// AddBalance removes amount from c's balance.
// It is used to add funds to the destination account of a transfer.
-func (c *StateObject) AddBalance(amount *big.Int) {
+func (c *stateObject) AddBalance(amount *big.Int) {
// EIP158: We must check emptiness for the objects such that the account
// clearing (0,0,0 objects) can take effect.
- if amount.Cmp(common.Big0) == 0 {
+ if amount.Sign() == 0 {
if c.empty() {
c.touch()
}
@@ -252,26 +247,18 @@ func (c *StateObject) AddBalance(amount *big.Int) {
return
}
c.SetBalance(new(big.Int).Add(c.Balance(), amount))
-
- if glog.V(logger.Core) {
- glog.Infof("%x: #%d %v (+ %v)\n", c.Address(), c.Nonce(), c.Balance(), amount)
- }
}
// SubBalance removes amount from c's balance.
// It is used to remove funds from the origin account of a transfer.
-func (c *StateObject) SubBalance(amount *big.Int) {
- if amount.Cmp(common.Big0) == 0 {
+func (c *stateObject) SubBalance(amount *big.Int) {
+ if amount.Sign() == 0 {
return
}
c.SetBalance(new(big.Int).Sub(c.Balance(), amount))
-
- if glog.V(logger.Core) {
- glog.Infof("%x: #%d %v (- %v)\n", c.Address(), c.Nonce(), c.Balance(), amount)
- }
}
-func (self *StateObject) SetBalance(amount *big.Int) {
+func (self *stateObject) SetBalance(amount *big.Int) {
self.db.journal = append(self.db.journal, balanceChange{
account: &self.address,
prev: new(big.Int).Set(self.data.Balance),
@@ -279,7 +266,7 @@ func (self *StateObject) SetBalance(amount *big.Int) {
self.setBalance(amount)
}
-func (self *StateObject) setBalance(amount *big.Int) {
+func (self *stateObject) setBalance(amount *big.Int) {
self.data.Balance = amount
if self.onDirty != nil {
self.onDirty(self.Address())
@@ -288,9 +275,9 @@ func (self *StateObject) setBalance(amount *big.Int) {
}
// Return the gas back to the origin. Used by the Virtual machine or Closures
-func (c *StateObject) ReturnGas(gas *big.Int) {}
+func (c *stateObject) ReturnGas(gas *big.Int) {}
-func (self *StateObject) deepCopy(db *StateDB, onDirty func(addr common.Address)) *StateObject {
+func (self *stateObject) deepCopy(db *StateDB, onDirty func(addr common.Address)) *stateObject {
stateObject := newObject(db, self.address, self.data, onDirty)
stateObject.trie = self.trie
stateObject.code = self.code
@@ -307,12 +294,12 @@ func (self *StateObject) deepCopy(db *StateDB, onDirty func(addr common.Address)
//
// Returns the address of the contract/account
-func (c *StateObject) Address() common.Address {
+func (c *stateObject) Address() common.Address {
return c.address
}
// Code returns the contract code associated with this object, if any.
-func (self *StateObject) Code(db trie.Database) []byte {
+func (self *stateObject) Code(db trie.Database) []byte {
if self.code != nil {
return self.code
}
@@ -327,7 +314,7 @@ func (self *StateObject) Code(db trie.Database) []byte {
return code
}
-func (self *StateObject) SetCode(codeHash common.Hash, code []byte) {
+func (self *stateObject) SetCode(codeHash common.Hash, code []byte) {
prevcode := self.Code(self.db.db)
self.db.journal = append(self.db.journal, codeChange{
account: &self.address,
@@ -337,7 +324,7 @@ func (self *StateObject) SetCode(codeHash common.Hash, code []byte) {
self.setCode(codeHash, code)
}
-func (self *StateObject) setCode(codeHash common.Hash, code []byte) {
+func (self *stateObject) setCode(codeHash common.Hash, code []byte) {
self.code = code
self.data.CodeHash = codeHash[:]
self.dirtyCode = true
@@ -347,7 +334,7 @@ func (self *StateObject) setCode(codeHash common.Hash, code []byte) {
}
}
-func (self *StateObject) SetNonce(nonce uint64) {
+func (self *stateObject) SetNonce(nonce uint64) {
self.db.journal = append(self.db.journal, nonceChange{
account: &self.address,
prev: self.data.Nonce,
@@ -355,7 +342,7 @@ func (self *StateObject) SetNonce(nonce uint64) {
self.setNonce(nonce)
}
-func (self *StateObject) setNonce(nonce uint64) {
+func (self *stateObject) setNonce(nonce uint64) {
self.data.Nonce = nonce
if self.onDirty != nil {
self.onDirty(self.Address())
@@ -363,37 +350,21 @@ func (self *StateObject) setNonce(nonce uint64) {
}
}
-func (self *StateObject) CodeHash() []byte {
+func (self *stateObject) CodeHash() []byte {
return self.data.CodeHash
}
-func (self *StateObject) Balance() *big.Int {
+func (self *stateObject) Balance() *big.Int {
return self.data.Balance
}
-func (self *StateObject) Nonce() uint64 {
+func (self *stateObject) Nonce() uint64 {
return self.data.Nonce
}
-// Never called, but must be present to allow StateObject to be used
+// Never called, but must be present to allow stateObject to be used
// as a vm.Account interface that also satisfies the vm.ContractRef
// interface. Interfaces are awesome.
-func (self *StateObject) Value() *big.Int {
- panic("Value on StateObject should never be called")
-}
-
-func (self *StateObject) ForEachStorage(cb func(key, value common.Hash) bool) {
- // When iterating over the storage check the cache first
- for h, value := range self.cachedStorage {
- cb(h, value)
- }
-
- it := self.getTrie(self.db.db).Iterator()
- for it.Next() {
- // ignore cached values
- key := common.BytesToHash(self.trie.GetKey(it.Key))
- if _, ok := self.cachedStorage[key]; !ok {
- cb(key, common.BytesToHash(it.Value))
- }
- }
+func (self *stateObject) Value() *big.Int {
+ panic("Value on stateObject should never be called")
}
diff --git a/core/state/state_test.go b/core/state/state_test.go
index 435d1d8293..3bc63c1486 100644
--- a/core/state/state_test.go
+++ b/core/state/state_test.go
@@ -152,7 +152,7 @@ func TestSnapshot2(t *testing.T) {
state.SetState(stateobjaddr1, storageaddr, data1)
// db, trie are already non-empty values
- so0 := state.GetStateObject(stateobjaddr0)
+ so0 := state.getStateObject(stateobjaddr0)
so0.SetBalance(big.NewInt(42))
so0.SetNonce(43)
so0.SetCode(crypto.Keccak256Hash([]byte{'c', 'a', 'f', 'e'}), []byte{'c', 'a', 'f', 'e'})
@@ -164,7 +164,7 @@ func TestSnapshot2(t *testing.T) {
state.Reset(root)
// and one with deleted == true
- so1 := state.GetStateObject(stateobjaddr1)
+ so1 := state.getStateObject(stateobjaddr1)
so1.SetBalance(big.NewInt(52))
so1.SetNonce(53)
so1.SetCode(crypto.Keccak256Hash([]byte{'c', 'a', 'f', 'e', '2'}), []byte{'c', 'a', 'f', 'e', '2'})
@@ -172,7 +172,7 @@ func TestSnapshot2(t *testing.T) {
so1.deleted = true
state.setStateObject(so1)
- so1 = state.GetStateObject(stateobjaddr1)
+ so1 = state.getStateObject(stateobjaddr1)
if so1 != nil {
t.Fatalf("deleted object not nil when getting")
}
@@ -180,7 +180,7 @@ func TestSnapshot2(t *testing.T) {
snapshot := state.Snapshot()
state.RevertToSnapshot(snapshot)
- so0Restored := state.GetStateObject(stateobjaddr0)
+ so0Restored := state.getStateObject(stateobjaddr0)
// Update lazily-loaded values before comparing.
so0Restored.GetState(db, storageaddr)
so0Restored.Code(db)
@@ -188,13 +188,13 @@ func TestSnapshot2(t *testing.T) {
compareStateObjects(so0Restored, so0, t)
// deleted should be nil, both before and after restore of state copy
- so1Restored := state.GetStateObject(stateobjaddr1)
+ so1Restored := state.getStateObject(stateobjaddr1)
if so1Restored != nil {
t.Fatalf("deleted object not nil after restoring snapshot: %+v", so1Restored)
}
}
-func compareStateObjects(so0, so1 *StateObject, t *testing.T) {
+func compareStateObjects(so0, so1 *stateObject, t *testing.T) {
if so0.Address() != so1.Address() {
t.Fatalf("Address mismatch: have %v, want %v", so0.address, so1.address)
}
diff --git a/core/state/statedb.go b/core/state/statedb.go
index bbccba9fba..0c72fc6b07 100644
--- a/core/state/statedb.go
+++ b/core/state/statedb.go
@@ -25,11 +25,9 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
- "github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethdb"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/trie"
lru "github.com/hashicorp/golang-lru"
@@ -64,7 +62,7 @@ type StateDB struct {
codeSizeCache *lru.Cache
// This map holds 'live' objects, which will get modified while processing a state transition.
- stateObjects map[common.Address]*StateObject
+ stateObjects map[common.Address]*stateObject
stateObjectsDirty map[common.Address]struct{}
// The refund counter, also used by state transitioning.
@@ -97,7 +95,7 @@ func New(root common.Hash, db ethdb.Database) (*StateDB, error) {
db: db,
trie: tr,
codeSizeCache: csc,
- stateObjects: make(map[common.Address]*StateObject),
+ stateObjects: make(map[common.Address]*stateObject),
stateObjectsDirty: make(map[common.Address]struct{}),
refund: new(big.Int),
logs: make(map[common.Hash][]*types.Log),
@@ -119,7 +117,7 @@ func (self *StateDB) New(root common.Hash) (*StateDB, error) {
db: self.db,
trie: tr,
codeSizeCache: self.codeSizeCache,
- stateObjects: make(map[common.Address]*StateObject),
+ stateObjects: make(map[common.Address]*stateObject),
stateObjectsDirty: make(map[common.Address]struct{}),
refund: new(big.Int),
logs: make(map[common.Hash][]*types.Log),
@@ -138,7 +136,7 @@ func (self *StateDB) Reset(root common.Hash) error {
return err
}
self.trie = tr
- self.stateObjects = make(map[common.Address]*StateObject)
+ self.stateObjects = make(map[common.Address]*stateObject)
self.stateObjectsDirty = make(map[common.Address]struct{})
self.thash = common.Hash{}
self.bhash = common.Hash{}
@@ -227,23 +225,19 @@ func (self *StateDB) AddRefund(gas *big.Int) {
// Exist reports whether the given account address exists in the state.
// Notably this also returns true for suicided accounts.
func (self *StateDB) Exist(addr common.Address) bool {
- return self.GetStateObject(addr) != nil
+ return self.getStateObject(addr) != nil
}
// Empty returns whether the state object is either non-existent
// or empty according to the EIP161 specification (balance = nonce = code = 0)
func (self *StateDB) Empty(addr common.Address) bool {
- so := self.GetStateObject(addr)
+ so := self.getStateObject(addr)
return so == nil || so.empty()
}
-func (self *StateDB) GetAccount(addr common.Address) vm.Account {
- return self.GetStateObject(addr)
-}
-
// Retrieve the balance from the given address or 0 if object not found
func (self *StateDB) GetBalance(addr common.Address) *big.Int {
- stateObject := self.GetStateObject(addr)
+ stateObject := self.getStateObject(addr)
if stateObject != nil {
return stateObject.Balance()
}
@@ -251,7 +245,7 @@ func (self *StateDB) GetBalance(addr common.Address) *big.Int {
}
func (self *StateDB) GetNonce(addr common.Address) uint64 {
- stateObject := self.GetStateObject(addr)
+ stateObject := self.getStateObject(addr)
if stateObject != nil {
return stateObject.Nonce()
}
@@ -260,7 +254,7 @@ func (self *StateDB) GetNonce(addr common.Address) uint64 {
}
func (self *StateDB) GetCode(addr common.Address) []byte {
- stateObject := self.GetStateObject(addr)
+ stateObject := self.getStateObject(addr)
if stateObject != nil {
code := stateObject.Code(self.db)
key := common.BytesToHash(stateObject.CodeHash())
@@ -271,7 +265,7 @@ func (self *StateDB) GetCode(addr common.Address) []byte {
}
func (self *StateDB) GetCodeSize(addr common.Address) int {
- stateObject := self.GetStateObject(addr)
+ stateObject := self.getStateObject(addr)
if stateObject == nil {
return 0
}
@@ -287,7 +281,7 @@ func (self *StateDB) GetCodeSize(addr common.Address) int {
}
func (self *StateDB) GetCodeHash(addr common.Address) common.Hash {
- stateObject := self.GetStateObject(addr)
+ stateObject := self.getStateObject(addr)
if stateObject == nil {
return common.Hash{}
}
@@ -295,7 +289,7 @@ func (self *StateDB) GetCodeHash(addr common.Address) common.Hash {
}
func (self *StateDB) GetState(a common.Address, b common.Hash) common.Hash {
- stateObject := self.GetStateObject(a)
+ stateObject := self.getStateObject(a)
if stateObject != nil {
return stateObject.GetState(self.db, b)
}
@@ -303,7 +297,7 @@ func (self *StateDB) GetState(a common.Address, b common.Hash) common.Hash {
}
func (self *StateDB) HasSuicided(addr common.Address) bool {
- stateObject := self.GetStateObject(addr)
+ stateObject := self.getStateObject(addr)
if stateObject != nil {
return stateObject.suicided
}
@@ -362,9 +356,9 @@ func (self *StateDB) SetState(addr common.Address, key common.Hash, value common
// This clears the account balance.
//
// The account's state object is still available until the state is committed,
-// GetStateObject will return a non-nil account after Suicide.
+// getStateObject will return a non-nil account after Suicide.
func (self *StateDB) Suicide(addr common.Address) bool {
- stateObject := self.GetStateObject(addr)
+ stateObject := self.getStateObject(addr)
if stateObject == nil {
return false
}
@@ -383,7 +377,7 @@ func (self *StateDB) Suicide(addr common.Address) bool {
//
// updateStateObject writes the given object to the trie.
-func (self *StateDB) updateStateObject(stateObject *StateObject) {
+func (self *StateDB) updateStateObject(stateObject *stateObject) {
addr := stateObject.Address()
data, err := rlp.EncodeToBytes(stateObject)
if err != nil {
@@ -393,14 +387,14 @@ func (self *StateDB) updateStateObject(stateObject *StateObject) {
}
// deleteStateObject removes the given object from the state trie.
-func (self *StateDB) deleteStateObject(stateObject *StateObject) {
+func (self *StateDB) deleteStateObject(stateObject *stateObject) {
stateObject.deleted = true
addr := stateObject.Address()
self.trie.Delete(addr[:])
}
// Retrieve a state object given my the address. Returns nil if not found.
-func (self *StateDB) GetStateObject(addr common.Address) (stateObject *StateObject) {
+func (self *StateDB) getStateObject(addr common.Address) (stateObject *stateObject) {
// Prefer 'live' objects.
if obj := self.stateObjects[addr]; obj != nil {
if obj.deleted {
@@ -416,7 +410,7 @@ func (self *StateDB) GetStateObject(addr common.Address) (stateObject *StateObje
}
var data Account
if err := rlp.DecodeBytes(enc, &data); err != nil {
- glog.Errorf("can't decode object at %x: %v", addr[:], err)
+ log.Error("Failed to decode state object", "addr", addr, "err", err)
return nil
}
// Insert into the live set.
@@ -425,13 +419,13 @@ func (self *StateDB) GetStateObject(addr common.Address) (stateObject *StateObje
return obj
}
-func (self *StateDB) setStateObject(object *StateObject) {
+func (self *StateDB) setStateObject(object *stateObject) {
self.stateObjects[object.Address()] = object
}
// Retrieve a state object or create a new state object if nil
-func (self *StateDB) GetOrNewStateObject(addr common.Address) *StateObject {
- stateObject := self.GetStateObject(addr)
+func (self *StateDB) GetOrNewStateObject(addr common.Address) *stateObject {
+ stateObject := self.getStateObject(addr)
if stateObject == nil || stateObject.deleted {
stateObject, _ = self.createObject(addr)
}
@@ -446,14 +440,11 @@ func (self *StateDB) MarkStateObjectDirty(addr common.Address) {
// createObject creates a new state object. If there is an existing account with
// the given address, it is overwritten and returned as the second return value.
-func (self *StateDB) createObject(addr common.Address) (newobj, prev *StateObject) {
- prev = self.GetStateObject(addr)
+func (self *StateDB) createObject(addr common.Address) (newobj, prev *stateObject) {
+ prev = self.getStateObject(addr)
newobj = newObject(self, addr, Account{}, self.MarkStateObjectDirty)
newobj.setNonce(0) // sets the object to dirty
if prev == nil {
- if glog.V(logger.Core) {
- glog.Infof("(+) %x\n", addr)
- }
self.journal = append(self.journal, createObjectChange{account: &addr})
} else {
self.journal = append(self.journal, resetObjectChange{prev: prev})
@@ -472,12 +463,32 @@ func (self *StateDB) createObject(addr common.Address) (newobj, prev *StateObjec
// 2. tx_create(sha(account ++ nonce)) (note that this gets the address of 1)
//
// Carrying over the balance ensures that Ether doesn't disappear.
-func (self *StateDB) CreateAccount(addr common.Address) vm.Account {
+func (self *StateDB) CreateAccount(addr common.Address) {
new, prev := self.createObject(addr)
if prev != nil {
new.setBalance(prev.data.Balance)
}
- return new
+}
+
+func (db *StateDB) ForEachStorage(addr common.Address, cb func(key, value common.Hash) bool) {
+ so := db.getStateObject(addr)
+ if so == nil {
+ return
+ }
+
+ // When iterating over the storage check the cache first
+ for h, value := range so.cachedStorage {
+ cb(h, value)
+ }
+
+ it := so.getTrie(db.db).Iterator()
+ for it.Next() {
+ // ignore cached values
+ key := common.BytesToHash(db.trie.GetKey(it.Key))
+ if _, ok := so.cachedStorage[key]; !ok {
+ cb(key, common.BytesToHash(it.Value))
+ }
+ }
}
// Copy creates a deep, independent copy of the state.
@@ -492,7 +503,7 @@ func (self *StateDB) Copy() *StateDB {
trie: self.trie,
pastTries: self.pastTries,
codeSizeCache: self.codeSizeCache,
- stateObjects: make(map[common.Address]*StateObject, len(self.stateObjectsDirty)),
+ stateObjects: make(map[common.Address]*stateObject, len(self.stateObjectsDirty)),
stateObjectsDirty: make(map[common.Address]struct{}, len(self.stateObjectsDirty)),
refund: new(big.Int).Set(self.refund),
logs: make(map[common.Hash][]*types.Log, len(self.logs)),
@@ -600,9 +611,9 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (root common.Hash, err error)
// the root hash stored in a block.
func (s *StateDB) CommitBatch(deleteEmptyObjects bool) (root common.Hash, batch ethdb.Batch) {
batch = s.db.NewBatch()
- root, _ = s.commit(batch, deleteEmptyObjects)
+ root, _ = s.CommitTo(batch, deleteEmptyObjects)
- glog.V(logger.Debug).Infof("Trie cache stats: %d misses, %d unloads", trie.CacheMisses(), trie.CacheUnloads())
+ log.Debug("Trie cache stats after commit", "misses", trie.CacheMisses(), "unloads", trie.CacheUnloads())
return root, batch
}
@@ -612,7 +623,8 @@ func (s *StateDB) clearJournalAndRefund() {
s.refund = new(big.Int)
}
-func (s *StateDB) commit(dbw trie.DatabaseWriter, deleteEmptyObjects bool) (root common.Hash, err error) {
+// CommitTo writes the state to the given database.
+func (s *StateDB) CommitTo(dbw trie.DatabaseWriter, deleteEmptyObjects bool) (root common.Hash, err error) {
defer s.clearJournalAndRefund()
// Commit objects to the trie.
diff --git a/core/state/statedb_test.go b/core/state/statedb_test.go
index 8743173009..597de3be53 100644
--- a/core/state/statedb_test.go
+++ b/core/state/statedb_test.go
@@ -331,12 +331,11 @@ func (test *snapshotTest) checkEqual(state, checkstate *StateDB) error {
checkeq("GetCodeHash", state.GetCodeHash(addr), checkstate.GetCodeHash(addr))
checkeq("GetCodeSize", state.GetCodeSize(addr), checkstate.GetCodeSize(addr))
// Check storage.
- if obj := state.GetStateObject(addr); obj != nil {
- obj.ForEachStorage(func(key, val common.Hash) bool {
+ if obj := state.getStateObject(addr); obj != nil {
+ state.ForEachStorage(addr, func(key, val common.Hash) bool {
return checkeq("GetState("+key.Hex()+")", val, checkstate.GetState(addr, key))
})
- checkobj := checkstate.GetStateObject(addr)
- checkobj.ForEachStorage(func(key, checkval common.Hash) bool {
+ checkstate.ForEachStorage(addr, func(key, checkval common.Hash) bool {
return checkeq("GetState("+key.Hex()+")", state.GetState(addr, key), checkval)
})
}
diff --git a/core/state_processor.go b/core/state_processor.go
index 6485e9abda..3edc042a36 100644
--- a/core/state_processor.go
+++ b/core/state_processor.go
@@ -23,8 +23,6 @@ import (
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
"github.com/ethereum/go-ethereum/params"
)
@@ -122,8 +120,6 @@ func ApplyTransaction(config *params.ChainConfig, bc *BlockChain, gp *GasPool, s
receipt.Logs = statedb.GetLogs(tx.Hash())
receipt.Bloom = types.CreateBloom(types.Receipts{receipt})
- glog.V(logger.Debug).Infoln(receipt)
-
return receipt, gas, err
}
diff --git a/core/state_transition.go b/core/state_transition.go
index 3cb7e500c5..fb75186470 100644
--- a/core/state_transition.go
+++ b/core/state_transition.go
@@ -17,18 +17,19 @@
package core
import (
- "fmt"
+ "errors"
"math/big"
"github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/core/vm"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params"
)
var (
- Big0 = big.NewInt(0)
+ Big0 = big.NewInt(0)
+ errInsufficientBalanceForGas = errors.New("insufficient balance to pay for gas")
)
/*
@@ -49,15 +50,16 @@ The state transitioning model does all all the necessary work to work out a vali
6) Derive new state root
*/
type StateTransition struct {
- gp *GasPool
- msg Message
- gas, gasPrice *big.Int
- initialGas *big.Int
- value *big.Int
- data []byte
- state vm.StateDB
+ gp *GasPool
+ msg Message
+ gas uint64
+ gasPrice *big.Int
+ initialGas *big.Int
+ value *big.Int
+ data []byte
+ state vm.StateDB
- env *vm.EVM
+ evm *vm.EVM
}
// Message represents a message sent to a contract.
@@ -81,12 +83,14 @@ func MessageCreatesContract(msg Message) bool {
// IntrinsicGas computes the 'intrinsic gas' for a message
// with the given data.
+//
+// TODO convert to uint64
func IntrinsicGas(data []byte, contractCreation, homestead bool) *big.Int {
igas := new(big.Int)
if contractCreation && homestead {
- igas.Set(params.TxGasContractCreation)
+ igas.SetUint64(params.TxGasContractCreation)
} else {
- igas.Set(params.TxGas)
+ igas.SetUint64(params.TxGas)
}
if len(data) > 0 {
var nz int64
@@ -96,27 +100,26 @@ func IntrinsicGas(data []byte, contractCreation, homestead bool) *big.Int {
}
}
m := big.NewInt(nz)
- m.Mul(m, params.TxDataNonZeroGas)
+ m.Mul(m, new(big.Int).SetUint64(params.TxDataNonZeroGas))
igas.Add(igas, m)
m.SetInt64(int64(len(data)) - nz)
- m.Mul(m, params.TxDataZeroGas)
+ m.Mul(m, new(big.Int).SetUint64(params.TxDataZeroGas))
igas.Add(igas, m)
}
return igas
}
// NewStateTransition initialises and returns a new state transition object.
-func NewStateTransition(env *vm.EVM, msg Message, gp *GasPool) *StateTransition {
+func NewStateTransition(evm *vm.EVM, msg Message, gp *GasPool) *StateTransition {
return &StateTransition{
gp: gp,
- env: env,
+ evm: evm,
msg: msg,
- gas: new(big.Int),
gasPrice: msg.GasPrice(),
initialGas: new(big.Int),
value: msg.Value(),
data: msg.Data(),
- state: env.StateDB,
+ state: evm.StateDB,
}
}
@@ -127,63 +130,68 @@ func NewStateTransition(env *vm.EVM, msg Message, gp *GasPool) *StateTransition
// the gas used (which includes gas refunds) and an error if it failed. An error always
// indicates a core error meaning that the message would always fail for that particular
// state and would never be accepted within a block.
-func ApplyMessage(env *vm.EVM, msg Message, gp *GasPool) ([]byte, *big.Int, error) {
- st := NewStateTransition(env, msg, gp)
+func ApplyMessage(evm *vm.EVM, msg Message, gp *GasPool) ([]byte, *big.Int, error) {
+ st := NewStateTransition(evm, msg, gp)
ret, _, gasUsed, err := st.TransitionDb()
return ret, gasUsed, err
}
-func (self *StateTransition) from() vm.Account {
+func (self *StateTransition) from() vm.AccountRef {
f := self.msg.From()
if !self.state.Exist(f) {
- return self.state.CreateAccount(f)
+ self.state.CreateAccount(f)
}
- return self.state.GetAccount(f)
+ return vm.AccountRef(f)
}
-func (self *StateTransition) to() vm.Account {
+func (self *StateTransition) to() vm.AccountRef {
if self.msg == nil {
- return nil
+ return vm.AccountRef{}
}
to := self.msg.To()
if to == nil {
- return nil // contract creation
+ return vm.AccountRef{} // contract creation
}
+ reference := vm.AccountRef(*to)
if !self.state.Exist(*to) {
- return self.state.CreateAccount(*to)
+ self.state.CreateAccount(*to)
}
- return self.state.GetAccount(*to)
+ return reference
}
-func (self *StateTransition) useGas(amount *big.Int) error {
- if self.gas.Cmp(amount) < 0 {
+func (self *StateTransition) useGas(amount uint64) error {
+ if self.gas < amount {
return vm.ErrOutOfGas
}
- self.gas.Sub(self.gas, amount)
+ self.gas -= amount
return nil
}
-func (self *StateTransition) addGas(amount *big.Int) {
- self.gas.Add(self.gas, amount)
-}
-
func (self *StateTransition) buyGas() error {
mgas := self.msg.Gas()
+ if mgas.BitLen() > 64 {
+ return vm.ErrOutOfGas
+ }
+
mgval := new(big.Int).Mul(mgas, self.gasPrice)
- sender := self.from()
- if sender.Balance().Cmp(mgval) < 0 {
- return fmt.Errorf("insufficient ETH for gas (%x). Req %v, has %v", sender.Address().Bytes()[:4], mgval, sender.Balance())
+ var (
+ state = self.state
+ sender = self.from()
+ )
+ if state.GetBalance(sender.Address()).Cmp(mgval) < 0 {
+ return errInsufficientBalanceForGas
}
if err := self.gp.SubGas(mgas); err != nil {
return err
}
- self.addGas(mgas)
+ self.gas += mgas.Uint64()
+
self.initialGas.Set(mgas)
- sender.SubBalance(mgval)
+ state.SubBalance(sender.Address(), mgval)
return nil
}
@@ -209,7 +217,9 @@ func (self *StateTransition) preCheck() (err error) {
return nil
}
-// TransitionDb will move the state by applying the message against the given environment.
+// TransitionDb will transition the state by applying the current message and returning the result
+// including the required gas for the operation as well as the used gas. It returns an error if it
+// failed. An error indicates a consensus issue.
func (self *StateTransition) TransitionDb() (ret []byte, requiredGas, usedGas *big.Int, err error) {
if err = self.preCheck(); err != nil {
return
@@ -217,29 +227,35 @@ func (self *StateTransition) TransitionDb() (ret []byte, requiredGas, usedGas *b
msg := self.msg
sender := self.from() // err checked in preCheck
- homestead := self.env.ChainConfig().IsHomestead(self.env.BlockNumber)
+ homestead := self.evm.ChainConfig().IsHomestead(self.evm.BlockNumber)
contractCreation := MessageCreatesContract(msg)
// Pay intrinsic gas
- if err = self.useGas(IntrinsicGas(self.data, contractCreation, homestead)); err != nil {
+ // TODO convert to uint64
+ intrinsicGas := IntrinsicGas(self.data, contractCreation, homestead)
+ if intrinsicGas.BitLen() > 64 {
+ return nil, nil, nil, InvalidTxError(vm.ErrOutOfGas)
+ }
+
+ if err = self.useGas(intrinsicGas.Uint64()); err != nil {
return nil, nil, nil, InvalidTxError(err)
}
var (
- vmenv = self.env
+ evm = self.evm
// vm errors do not effect consensus and are therefor
// not assigned to err, except for insufficient balance
// error.
vmerr error
)
if contractCreation {
- ret, _, vmerr = vmenv.Create(sender, self.data, self.gas, self.value)
+ ret, _, self.gas, vmerr = evm.Create(sender, self.data, self.gas, self.value)
} else {
// Increment the nonce for the next transaction
self.state.SetNonce(sender.Address(), self.state.GetNonce(sender.Address())+1)
- ret, vmerr = vmenv.Call(sender, self.to().Address(), self.data, self.gas, self.value)
+ ret, self.gas, vmerr = evm.Call(sender, self.to().Address(), self.data, self.gas, self.value)
}
if vmerr != nil {
- glog.V(logger.Core).Infoln("vm returned with error:", err)
+ log.Debug("VM returned with error", "err", err)
// The only possible consensus-error would be if there wasn't
// sufficient balance to make the transfer happen. The first
// balance transfer may never fail.
@@ -251,7 +267,7 @@ func (self *StateTransition) TransitionDb() (ret []byte, requiredGas, usedGas *b
requiredGas = new(big.Int).Set(self.gasUsed())
self.refundGas()
- self.state.AddBalance(self.env.Coinbase, new(big.Int).Mul(self.gasUsed(), self.gasPrice))
+ self.state.AddBalance(self.evm.Coinbase, new(big.Int).Mul(self.gasUsed(), self.gasPrice))
return ret, requiredGas, self.gasUsed(), err
}
@@ -260,20 +276,21 @@ func (self *StateTransition) refundGas() {
// Return eth for remaining gas to the sender account,
// exchanged at the original rate.
sender := self.from() // err already checked
- remaining := new(big.Int).Mul(self.gas, self.gasPrice)
- sender.AddBalance(remaining)
+ remaining := new(big.Int).Mul(new(big.Int).SetUint64(self.gas), self.gasPrice)
+ self.state.AddBalance(sender.Address(), remaining)
// Apply refund counter, capped to half of the used gas.
uhalf := remaining.Div(self.gasUsed(), common.Big2)
- refund := common.BigMin(uhalf, self.state.GetRefund())
- self.gas.Add(self.gas, refund)
+ refund := math.BigMin(uhalf, self.state.GetRefund())
+ self.gas += refund.Uint64()
+
self.state.AddBalance(sender.Address(), refund.Mul(refund, self.gasPrice))
// Also return remaining gas to the block gas counter so it is
// available for the next transaction.
- self.gp.AddGas(self.gas)
+ self.gp.AddGas(new(big.Int).SetUint64(self.gas))
}
func (self *StateTransition) gasUsed() *big.Int {
- return new(big.Int).Sub(self.initialGas, self.gas)
+ return new(big.Int).Sub(self.initialGas, new(big.Int).SetUint64(self.gas))
}
diff --git a/core/tx_pool.go b/core/tx_pool.go
index ca16c1ba3c..49bd81e483 100644
--- a/core/tx_pool.go
+++ b/core/tx_pool.go
@@ -28,8 +28,7 @@ import (
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/event"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/metrics"
"github.com/ethereum/go-ethereum/params"
"gopkg.in/karalabe/cookiejar.v2/collections/prque"
@@ -163,15 +162,10 @@ func (pool *TxPool) eventLoop() {
func (pool *TxPool) resetState() {
currentState, err := pool.currentState()
if err != nil {
- glog.V(logger.Error).Infof("Failed to get current state: %v", err)
+ log.Error("Failed reset txpool state", "err", err)
return
}
- managedState := state.ManageState(currentState)
- if err != nil {
- glog.V(logger.Error).Infof("Failed to get managed state: %v", err)
- return
- }
- pool.pendingState = managedState
+ pool.pendingState = state.ManageState(currentState)
// validate the pool of pending transactions, this will remove
// any transactions that have been included in the block or
@@ -193,7 +187,8 @@ func (pool *TxPool) Stop() {
pool.events.Unsubscribe()
close(pool.quit)
pool.wg.Wait()
- glog.V(logger.Info).Infoln("Transaction pool stopped")
+
+ log.Info("Transaction pool stopped")
}
func (pool *TxPool) State() *state.ManagedState {
@@ -300,7 +295,7 @@ func (pool *TxPool) validateTx(tx *types.Transaction) error {
// Transactions can't be negative. This may never happen
// using RLP decoded transactions but may occur if you create
// a transaction using the RPC for example.
- if tx.Value().Cmp(common.Big0) < 0 {
+ if tx.Value().Sign() < 0 {
return ErrNegativeValue
}
@@ -324,24 +319,19 @@ func (pool *TxPool) add(tx *types.Transaction) error {
// If the transaction is already known, discard it
hash := tx.Hash()
if pool.all[hash] != nil {
- return fmt.Errorf("Known transaction: %x", hash[:4])
+ log.Trace("Discarding already known transaction", "hash", hash)
+ return fmt.Errorf("known transaction: %x", hash)
}
// Otherwise ensure basic validation passes and queue it up
if err := pool.validateTx(tx); err != nil {
+ log.Trace("Discarding invalid transaction", "hash", hash, "err", err)
invalidTxCounter.Inc(1)
return err
}
pool.enqueueTx(hash, tx)
// Print a log message if low enough level is set
- if glog.V(logger.Debug) {
- rcpt := "[NEW_CONTRACT]"
- if to := tx.To(); to != nil {
- rcpt = common.Bytes2Hex(to[:4])
- }
- from, _ := types.Sender(pool.signer, tx) // from already verified during tx validation
- glog.Infof("(t) 0x%x => %s (%v) %x\n", from[:4], rcpt, tx.Value, hash)
- }
+ log.Debug("Pooled new transaction", "hash", hash, "from", log.Lazy{Fn: func() common.Address { from, _ := types.Sender(pool.signer, tx); return from }}, "to", tx.To())
return nil
}
@@ -410,7 +400,6 @@ func (pool *TxPool) Add(tx *types.Transaction) error {
if err != nil {
return err
}
-
pool.promoteExecutables(state)
return nil
@@ -421,19 +410,21 @@ func (pool *TxPool) AddBatch(txs []*types.Transaction) error {
pool.mu.Lock()
defer pool.mu.Unlock()
+ // Add the batch of transaction, tracking the accepted ones
+ added := 0
for _, tx := range txs {
- if err := pool.add(tx); err != nil {
- glog.V(logger.Debug).Infoln("tx error:", err)
+ if err := pool.add(tx); err == nil {
+ added++
}
}
-
- state, err := pool.currentState()
- if err != nil {
- return err
+ // Only reprocess the internal state if something was actually added
+ if added > 0 {
+ state, err := pool.currentState()
+ if err != nil {
+ return err
+ }
+ pool.promoteExecutables(state)
}
-
- pool.promoteExecutables(state)
-
return nil
}
@@ -514,33 +505,29 @@ func (pool *TxPool) promoteExecutables(state *state.StateDB) {
for addr, list := range pool.queue {
// Drop all transactions that are deemed too old (low nonce)
for _, tx := range list.Forward(state.GetNonce(addr)) {
- if glog.V(logger.Core) {
- glog.Infof("Removed old queued transaction: %v", tx)
- }
- delete(pool.all, tx.Hash())
+ hash := tx.Hash()
+ log.Debug("Removed old queued transaction", "hash", hash)
+ delete(pool.all, hash)
}
// Drop all transactions that are too costly (low balance)
drops, _ := list.Filter(state.GetBalance(addr))
for _, tx := range drops {
- if glog.V(logger.Core) {
- glog.Infof("Removed unpayable queued transaction: %v", tx)
- }
- delete(pool.all, tx.Hash())
+ hash := tx.Hash()
+ log.Debug("Removed unpayable queued transaction", "hash", hash)
+ delete(pool.all, hash)
queuedNofundsCounter.Inc(1)
}
// Gather all executable transactions and promote them
for _, tx := range list.Ready(pool.pendingState.GetNonce(addr)) {
- if glog.V(logger.Core) {
- glog.Infof("Promoting queued transaction: %v", tx)
- }
- pool.promoteTx(addr, tx.Hash(), tx)
+ hash := tx.Hash()
+ log.Debug("Promoting queued transaction", "hash", hash)
+ pool.promoteTx(addr, hash, tx)
}
// Drop all transactions over the allowed limit
for _, tx := range list.Cap(int(maxQueuedPerAccount)) {
- if glog.V(logger.Core) {
- glog.Infof("Removed cap-exceeding queued transaction: %v", tx)
- }
- delete(pool.all, tx.Hash())
+ hash := tx.Hash()
+ log.Debug("Removed cap-exceeding queued transaction", "hash", hash)
+ delete(pool.all, hash)
queuedRLCounter.Inc(1)
}
queued += uint64(list.Len())
@@ -651,25 +638,22 @@ func (pool *TxPool) demoteUnexecutables(state *state.StateDB) {
// Drop all transactions that are deemed too old (low nonce)
for _, tx := range list.Forward(nonce) {
- if glog.V(logger.Core) {
- glog.Infof("Removed old pending transaction: %v", tx)
- }
- delete(pool.all, tx.Hash())
+ hash := tx.Hash()
+ log.Debug("Removed old pending transaction", "hash", hash)
+ delete(pool.all, hash)
}
// Drop all transactions that are too costly (low balance), and queue any invalids back for later
drops, invalids := list.Filter(state.GetBalance(addr))
for _, tx := range drops {
- if glog.V(logger.Core) {
- glog.Infof("Removed unpayable pending transaction: %v", tx)
- }
- delete(pool.all, tx.Hash())
+ hash := tx.Hash()
+ log.Debug("Removed unpayable pending transaction", "hash", hash)
+ delete(pool.all, hash)
pendingNofundsCounter.Inc(1)
}
for _, tx := range invalids {
- if glog.V(logger.Core) {
- glog.Infof("Demoting pending transaction: %v", tx)
- }
- pool.enqueueTx(tx.Hash(), tx)
+ hash := tx.Hash()
+ log.Debug("Demoting pending transaction", "hash", hash)
+ pool.enqueueTx(hash, tx)
}
// Delete the entire queue entry if it became empty.
if list.Empty() {
diff --git a/core/tx_pool_test.go b/core/tx_pool_test.go
index 98a34b7573..7655779335 100644
--- a/core/tx_pool_test.go
+++ b/core/tx_pool_test.go
@@ -29,6 +29,7 @@ import (
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
+ "github.com/ethereum/go-ethereum/params"
)
func transaction(nonce uint64, gaslimit *big.Int, key *ecdsa.PrivateKey) *types.Transaction {
@@ -41,7 +42,7 @@ func setupTxPool() (*TxPool, *ecdsa.PrivateKey) {
statedb, _ := state.New(common.Hash{}, db)
key, _ := crypto.GenerateKey()
- newPool := NewTxPool(testChainConfig(), new(event.TypeMux), func() (*state.StateDB, error) { return statedb, nil }, func() *big.Int { return big.NewInt(1000000) })
+ newPool := NewTxPool(params.TestChainConfig, new(event.TypeMux), func() (*state.StateDB, error) { return statedb, nil }, func() *big.Int { return big.NewInt(1000000) })
newPool.resetState()
return newPool, key
@@ -65,7 +66,7 @@ func TestStateChangeDuringPoolReset(t *testing.T) {
)
// setup pool with 2 transaction in it
- statedb.SetBalance(address, new(big.Int).Mul(common.Big1, common.Ether))
+ statedb.SetBalance(address, new(big.Int).SetUint64(params.Ether))
tx0 := transaction(0, big.NewInt(100000), key)
tx1 := transaction(1, big.NewInt(100000), key)
@@ -82,7 +83,7 @@ func TestStateChangeDuringPoolReset(t *testing.T) {
statedb, _ = state.New(common.Hash{}, db)
// simulate that the new head block included tx0 and tx1
statedb.SetNonce(address, 2)
- statedb.SetBalance(address, new(big.Int).Mul(common.Big1, common.Ether))
+ statedb.SetBalance(address, new(big.Int).SetUint64(params.Ether))
trigger = false
}
return stdb, nil
@@ -90,7 +91,7 @@ func TestStateChangeDuringPoolReset(t *testing.T) {
gasLimitFunc := func() *big.Int { return big.NewInt(1000000000) }
- txpool := NewTxPool(testChainConfig(), mux, stateFunc, gasLimitFunc)
+ txpool := NewTxPool(params.TestChainConfig, mux, stateFunc, gasLimitFunc)
txpool.resetState()
nonce := txpool.State().GetNonce(address)
@@ -563,7 +564,7 @@ func TestTransactionQueueGlobalLimiting(t *testing.T) {
db, _ := ethdb.NewMemDatabase()
statedb, _ := state.New(common.Hash{}, db)
- pool := NewTxPool(testChainConfig(), new(event.TypeMux), func() (*state.StateDB, error) { return statedb, nil }, func() *big.Int { return big.NewInt(1000000) })
+ pool := NewTxPool(params.TestChainConfig, new(event.TypeMux), func() (*state.StateDB, error) { return statedb, nil }, func() *big.Int { return big.NewInt(1000000) })
pool.resetState()
// Create a number of test accounts and fund them
@@ -712,7 +713,7 @@ func TestTransactionPendingGlobalLimiting(t *testing.T) {
db, _ := ethdb.NewMemDatabase()
statedb, _ := state.New(common.Hash{}, db)
- pool := NewTxPool(testChainConfig(), new(event.TypeMux), func() (*state.StateDB, error) { return statedb, nil }, func() *big.Int { return big.NewInt(1000000) })
+ pool := NewTxPool(params.TestChainConfig, new(event.TypeMux), func() (*state.StateDB, error) { return statedb, nil }, func() *big.Int { return big.NewInt(1000000) })
pool.resetState()
// Create a number of test accounts and fund them
@@ -758,7 +759,7 @@ func TestTransactionPendingMinimumAllowance(t *testing.T) {
db, _ := ethdb.NewMemDatabase()
statedb, _ := state.New(common.Hash{}, db)
- pool := NewTxPool(testChainConfig(), new(event.TypeMux), func() (*state.StateDB, error) { return statedb, nil }, func() *big.Int { return big.NewInt(1000000) })
+ pool := NewTxPool(params.TestChainConfig, new(event.TypeMux), func() (*state.StateDB, error) { return statedb, nil }, func() *big.Int { return big.NewInt(1000000) })
pool.resetState()
// Create a number of test accounts and fund them
diff --git a/core/types/block.go b/core/types/block.go
index 1a2a1f2bda..b699ba6862 100644
--- a/core/types/block.go
+++ b/core/types/block.go
@@ -19,8 +19,6 @@ package types
import (
"encoding/binary"
- "encoding/json"
- "errors"
"fmt"
"io"
"math/big"
@@ -39,12 +37,6 @@ var (
EmptyUncleHash = CalcUncleHash(nil)
)
-var (
- errMissingHeaderMixDigest = errors.New("missing mixHash in JSON block header")
- errMissingHeaderFields = errors.New("missing required JSON block header fields")
- errBadNonceSize = errors.New("invalid block nonce size, want 8 bytes")
-)
-
// A BlockNonce is a 64-bit hash which proves (combined with the
// mix-hash) that a sufficient amount of computation has been carried
// out on a block.
@@ -62,51 +54,45 @@ func (n BlockNonce) Uint64() uint64 {
return binary.BigEndian.Uint64(n[:])
}
-// MarshalJSON implements json.Marshaler
-func (n BlockNonce) MarshalJSON() ([]byte, error) {
- return hexutil.Bytes(n[:]).MarshalJSON()
+// MarshalText encodes n as a hex string with 0x prefix.
+func (n BlockNonce) MarshalText() ([]byte, error) {
+ return hexutil.Bytes(n[:]).MarshalText()
}
-// UnmarshalJSON implements json.Unmarshaler
-func (n *BlockNonce) UnmarshalJSON(input []byte) error {
- return hexutil.UnmarshalJSON("BlockNonce", input, n[:])
+// UnmarshalText implements encoding.TextUnmarshaler.
+func (n *BlockNonce) UnmarshalText(input []byte) error {
+ return hexutil.UnmarshalFixedText("BlockNonce", input, n[:])
}
+//go:generate gencodec -type Header -field-override headerMarshaling -out gen_header_json.go
+
// Header represents a block header in the Ethereum blockchain.
type Header struct {
- ParentHash common.Hash // Hash to the previous block
- UncleHash common.Hash // Uncles of this block
- Coinbase common.Address // The coin base address
- Root common.Hash // Block Trie state
- TxHash common.Hash // Tx sha
- ReceiptHash common.Hash // Receipt sha
- Bloom Bloom // Bloom
- Difficulty *big.Int // Difficulty for the current block
- Number *big.Int // The block number
- GasLimit *big.Int // Gas limit
- GasUsed *big.Int // Gas used
- Time *big.Int // Creation time
- Extra []byte // Extra data
- MixDigest common.Hash // for quick difficulty verification
- Nonce BlockNonce
+ ParentHash common.Hash `json:"parentHash"`
+ UncleHash common.Hash `json:"sha3Uncles"`
+ Coinbase common.Address `json:"miner"`
+ Root common.Hash `json:"stateRoot"`
+ TxHash common.Hash `json:"transactionsRoot"`
+ ReceiptHash common.Hash `json:"receiptsRoot"`
+ Bloom Bloom `json:"logsBloom"`
+ Difficulty *big.Int `json:"difficulty"`
+ Number *big.Int `json:"number"`
+ GasLimit *big.Int `json:"gasLimit"`
+ GasUsed *big.Int `json:"gasUsed"`
+ Time *big.Int `json:"timestamp"`
+ Extra []byte `json:"extraData"`
+ MixDigest common.Hash `json:"mixHash"`
+ Nonce BlockNonce `json:"nonce"`
}
-type jsonHeader struct {
- ParentHash *common.Hash `json:"parentHash"`
- UncleHash *common.Hash `json:"sha3Uncles"`
- Coinbase *common.Address `json:"miner"`
- Root *common.Hash `json:"stateRoot"`
- TxHash *common.Hash `json:"transactionsRoot"`
- ReceiptHash *common.Hash `json:"receiptsRoot"`
- Bloom *Bloom `json:"logsBloom"`
- Difficulty *hexutil.Big `json:"difficulty"`
- Number *hexutil.Big `json:"number"`
- GasLimit *hexutil.Big `json:"gasLimit"`
- GasUsed *hexutil.Big `json:"gasUsed"`
- Time *hexutil.Big `json:"timestamp"`
- Extra *hexutil.Bytes `json:"extraData"`
- MixDigest *common.Hash `json:"mixHash"`
- Nonce *BlockNonce `json:"nonce"`
+// field type overrides for gencodec
+type headerMarshaling struct {
+ Difficulty *hexutil.Big
+ Number *hexutil.Big
+ GasLimit *hexutil.Big
+ GasUsed *hexutil.Big
+ Time *hexutil.Big
+ Extra hexutil.Bytes
}
// Hash returns the block hash of the header, which is simply the keccak256 hash of its
@@ -134,65 +120,6 @@ func (h *Header) HashNoNonce() common.Hash {
})
}
-// MarshalJSON encodes headers into the web3 RPC response block format.
-func (h *Header) MarshalJSON() ([]byte, error) {
- return json.Marshal(&jsonHeader{
- ParentHash: &h.ParentHash,
- UncleHash: &h.UncleHash,
- Coinbase: &h.Coinbase,
- Root: &h.Root,
- TxHash: &h.TxHash,
- ReceiptHash: &h.ReceiptHash,
- Bloom: &h.Bloom,
- Difficulty: (*hexutil.Big)(h.Difficulty),
- Number: (*hexutil.Big)(h.Number),
- GasLimit: (*hexutil.Big)(h.GasLimit),
- GasUsed: (*hexutil.Big)(h.GasUsed),
- Time: (*hexutil.Big)(h.Time),
- Extra: (*hexutil.Bytes)(&h.Extra),
- MixDigest: &h.MixDigest,
- Nonce: &h.Nonce,
- })
-}
-
-// UnmarshalJSON decodes headers from the web3 RPC response block format.
-func (h *Header) UnmarshalJSON(input []byte) error {
- var dec jsonHeader
- if err := json.Unmarshal(input, &dec); err != nil {
- return err
- }
- // Ensure that all fields are set. MixDigest is checked separately because
- // it is a recent addition to the spec (as of August 2016) and older RPC server
- // implementations might not provide it.
- if dec.MixDigest == nil {
- return errMissingHeaderMixDigest
- }
- if dec.ParentHash == nil || dec.UncleHash == nil || dec.Coinbase == nil ||
- dec.Root == nil || dec.TxHash == nil || dec.ReceiptHash == nil ||
- dec.Bloom == nil || dec.Difficulty == nil || dec.Number == nil ||
- dec.GasLimit == nil || dec.GasUsed == nil || dec.Time == nil ||
- dec.Extra == nil || dec.Nonce == nil {
- return errMissingHeaderFields
- }
- // Assign all values.
- h.ParentHash = *dec.ParentHash
- h.UncleHash = *dec.UncleHash
- h.Coinbase = *dec.Coinbase
- h.Root = *dec.Root
- h.TxHash = *dec.TxHash
- h.ReceiptHash = *dec.ReceiptHash
- h.Bloom = *dec.Bloom
- h.Difficulty = (*big.Int)(dec.Difficulty)
- h.Number = (*big.Int)(dec.Number)
- h.GasLimit = (*big.Int)(dec.GasLimit)
- h.GasUsed = (*big.Int)(dec.GasUsed)
- h.Time = (*big.Int)(dec.Time)
- h.Extra = *dec.Extra
- h.MixDigest = *dec.MixDigest
- h.Nonce = *dec.Nonce
- return nil
-}
-
func rlpHash(x interface{}) (h common.Hash) {
hw := sha3.NewKeccak256()
rlp.Encode(hw, x)
diff --git a/core/types/bloom9.go b/core/types/bloom9.go
index 32aa47a41b..60aacc3016 100644
--- a/core/types/bloom9.go
+++ b/core/types/bloom9.go
@@ -20,7 +20,6 @@ import (
"fmt"
"math/big"
- "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/crypto"
)
@@ -60,7 +59,7 @@ func (b *Bloom) Add(d *big.Int) {
// Big converts b to a big integer.
func (b Bloom) Big() *big.Int {
- return common.Bytes2Big(b[:])
+ return new(big.Int).SetBytes(b[:])
}
func (b Bloom) Bytes() []byte {
@@ -72,17 +71,18 @@ func (b Bloom) Test(test *big.Int) bool {
}
func (b Bloom) TestBytes(test []byte) bool {
- return b.Test(common.BytesToBig(test))
+ return b.Test(new(big.Int).SetBytes(test))
+
}
-// MarshalJSON encodes b as a hex string with 0x prefix.
-func (b Bloom) MarshalJSON() ([]byte, error) {
- return hexutil.Bytes(b[:]).MarshalJSON()
+// MarshalText encodes b as a hex string with 0x prefix.
+func (b Bloom) MarshalText() ([]byte, error) {
+ return hexutil.Bytes(b[:]).MarshalText()
}
-// UnmarshalJSON b as a hex string with 0x prefix.
-func (b *Bloom) UnmarshalJSON(input []byte) error {
- return hexutil.UnmarshalJSON("Bloom", input, b[:])
+// UnmarshalText b as a hex string with 0x prefix.
+func (b *Bloom) UnmarshalText(input []byte) error {
+ return hexutil.UnmarshalFixedText("Bloom", input, b[:])
}
func CreateBloom(receipts Receipts) Bloom {
diff --git a/core/types/gen_header_json.go b/core/types/gen_header_json.go
new file mode 100644
index 0000000000..860622e6eb
--- /dev/null
+++ b/core/types/gen_header_json.go
@@ -0,0 +1,136 @@
+// generated by github.com/fjl/gencodec, do not edit.
+
+package types
+
+import (
+ "encoding/json"
+ "errors"
+ "math/big"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/common/hexutil"
+)
+
+func (h *Header) MarshalJSON() ([]byte, error) {
+ type HeaderJSON struct {
+ ParentHash *common.Hash `json:"parentHash"`
+ UncleHash *common.Hash `json:"sha3Uncles"`
+ Coinbase *common.Address `json:"miner"`
+ Root *common.Hash `json:"stateRoot"`
+ TxHash *common.Hash `json:"transactionsRoot"`
+ ReceiptHash *common.Hash `json:"receiptsRoot"`
+ Bloom *Bloom `json:"logsBloom"`
+ Difficulty *hexutil.Big `json:"difficulty"`
+ Number *hexutil.Big `json:"number"`
+ GasLimit *hexutil.Big `json:"gasLimit"`
+ GasUsed *hexutil.Big `json:"gasUsed"`
+ Time *hexutil.Big `json:"timestamp"`
+ Extra hexutil.Bytes `json:"extraData"`
+ MixDigest *common.Hash `json:"mixHash"`
+ Nonce *BlockNonce `json:"nonce"`
+ }
+ var enc HeaderJSON
+ enc.ParentHash = &h.ParentHash
+ enc.UncleHash = &h.UncleHash
+ enc.Coinbase = &h.Coinbase
+ enc.Root = &h.Root
+ enc.TxHash = &h.TxHash
+ enc.ReceiptHash = &h.ReceiptHash
+ enc.Bloom = &h.Bloom
+ enc.Difficulty = (*hexutil.Big)(h.Difficulty)
+ enc.Number = (*hexutil.Big)(h.Number)
+ enc.GasLimit = (*hexutil.Big)(h.GasLimit)
+ enc.GasUsed = (*hexutil.Big)(h.GasUsed)
+ enc.Time = (*hexutil.Big)(h.Time)
+ enc.Extra = h.Extra
+ enc.MixDigest = &h.MixDigest
+ enc.Nonce = &h.Nonce
+ return json.Marshal(&enc)
+}
+
+func (h *Header) UnmarshalJSON(input []byte) error {
+ type HeaderJSON struct {
+ ParentHash *common.Hash `json:"parentHash"`
+ UncleHash *common.Hash `json:"sha3Uncles"`
+ Coinbase *common.Address `json:"miner"`
+ Root *common.Hash `json:"stateRoot"`
+ TxHash *common.Hash `json:"transactionsRoot"`
+ ReceiptHash *common.Hash `json:"receiptsRoot"`
+ Bloom *Bloom `json:"logsBloom"`
+ Difficulty *hexutil.Big `json:"difficulty"`
+ Number *hexutil.Big `json:"number"`
+ GasLimit *hexutil.Big `json:"gasLimit"`
+ GasUsed *hexutil.Big `json:"gasUsed"`
+ Time *hexutil.Big `json:"timestamp"`
+ Extra hexutil.Bytes `json:"extraData"`
+ MixDigest *common.Hash `json:"mixHash"`
+ Nonce *BlockNonce `json:"nonce"`
+ }
+ var dec HeaderJSON
+ if err := json.Unmarshal(input, &dec); err != nil {
+ return err
+ }
+ var x Header
+ if dec.ParentHash == nil {
+ return errors.New("missing required field 'parentHash' for Header")
+ }
+ x.ParentHash = *dec.ParentHash
+ if dec.UncleHash == nil {
+ return errors.New("missing required field 'sha3Uncles' for Header")
+ }
+ x.UncleHash = *dec.UncleHash
+ if dec.Coinbase == nil {
+ return errors.New("missing required field 'miner' for Header")
+ }
+ x.Coinbase = *dec.Coinbase
+ if dec.Root == nil {
+ return errors.New("missing required field 'stateRoot' for Header")
+ }
+ x.Root = *dec.Root
+ if dec.TxHash == nil {
+ return errors.New("missing required field 'transactionsRoot' for Header")
+ }
+ x.TxHash = *dec.TxHash
+ if dec.ReceiptHash == nil {
+ return errors.New("missing required field 'receiptsRoot' for Header")
+ }
+ x.ReceiptHash = *dec.ReceiptHash
+ if dec.Bloom == nil {
+ return errors.New("missing required field 'logsBloom' for Header")
+ }
+ x.Bloom = *dec.Bloom
+ if dec.Difficulty == nil {
+ return errors.New("missing required field 'difficulty' for Header")
+ }
+ x.Difficulty = (*big.Int)(dec.Difficulty)
+ if dec.Number == nil {
+ return errors.New("missing required field 'number' for Header")
+ }
+ x.Number = (*big.Int)(dec.Number)
+ if dec.GasLimit == nil {
+ return errors.New("missing required field 'gasLimit' for Header")
+ }
+ x.GasLimit = (*big.Int)(dec.GasLimit)
+ if dec.GasUsed == nil {
+ return errors.New("missing required field 'gasUsed' for Header")
+ }
+ x.GasUsed = (*big.Int)(dec.GasUsed)
+ if dec.Time == nil {
+ return errors.New("missing required field 'timestamp' for Header")
+ }
+ x.Time = (*big.Int)(dec.Time)
+ if dec.Extra == nil {
+ return errors.New("missing required field 'extraData' for Header")
+ }
+ x.Extra = dec.Extra
+ if dec.MixDigest == nil {
+ return errors.New("missing required field 'mixHash' for Header")
+ }
+ x.MixDigest = *dec.MixDigest
+ if dec.Nonce == nil {
+ return errors.New("missing required field 'nonce' for Header")
+ }
+ x.Nonce = *dec.Nonce
+ *h = x
+ return nil
+}
diff --git a/core/types/gen_log_json.go b/core/types/gen_log_json.go
new file mode 100644
index 0000000000..ef2cdfd890
--- /dev/null
+++ b/core/types/gen_log_json.go
@@ -0,0 +1,90 @@
+// generated by github.com/fjl/gencodec, do not edit.
+
+package types
+
+import (
+ "encoding/json"
+ "errors"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/common/hexutil"
+)
+
+func (l *Log) MarshalJSON() ([]byte, error) {
+ type LogJSON struct {
+ Address *common.Address `json:"address"`
+ Topics []common.Hash `json:"topics"`
+ Data hexutil.Bytes `json:"data"`
+ BlockNumber *hexutil.Uint64 `json:"blockNumber" optional:"yes"`
+ TxHash *common.Hash `json:"transactionHash"`
+ TxIndex *hexutil.Uint `json:"transactionIndex"`
+ BlockHash *common.Hash `json:"blockHash" optional:"yes"`
+ Index *hexutil.Uint `json:"logIndex"`
+ Removed *bool `json:"removed" optional:"yes"`
+ }
+ var enc LogJSON
+ enc.Address = &l.Address
+ enc.Topics = l.Topics
+ enc.Data = l.Data
+ enc.BlockNumber = (*hexutil.Uint64)(&l.BlockNumber)
+ enc.TxHash = &l.TxHash
+ enc.TxIndex = (*hexutil.Uint)(&l.TxIndex)
+ enc.BlockHash = &l.BlockHash
+ enc.Index = (*hexutil.Uint)(&l.Index)
+ enc.Removed = &l.Removed
+ return json.Marshal(&enc)
+}
+
+func (l *Log) UnmarshalJSON(input []byte) error {
+ type LogJSON struct {
+ Address *common.Address `json:"address"`
+ Topics []common.Hash `json:"topics"`
+ Data hexutil.Bytes `json:"data"`
+ BlockNumber *hexutil.Uint64 `json:"blockNumber" optional:"yes"`
+ TxHash *common.Hash `json:"transactionHash"`
+ TxIndex *hexutil.Uint `json:"transactionIndex"`
+ BlockHash *common.Hash `json:"blockHash" optional:"yes"`
+ Index *hexutil.Uint `json:"logIndex"`
+ Removed *bool `json:"removed" optional:"yes"`
+ }
+ var dec LogJSON
+ if err := json.Unmarshal(input, &dec); err != nil {
+ return err
+ }
+ var x Log
+ if dec.Address == nil {
+ return errors.New("missing required field 'address' for Log")
+ }
+ x.Address = *dec.Address
+ if dec.Topics == nil {
+ return errors.New("missing required field 'topics' for Log")
+ }
+ x.Topics = dec.Topics
+ if dec.Data == nil {
+ return errors.New("missing required field 'data' for Log")
+ }
+ x.Data = dec.Data
+ if dec.BlockNumber != nil {
+ x.BlockNumber = uint64(*dec.BlockNumber)
+ }
+ if dec.TxHash == nil {
+ return errors.New("missing required field 'transactionHash' for Log")
+ }
+ x.TxHash = *dec.TxHash
+ if dec.TxIndex == nil {
+ return errors.New("missing required field 'transactionIndex' for Log")
+ }
+ x.TxIndex = uint(*dec.TxIndex)
+ if dec.BlockHash != nil {
+ x.BlockHash = *dec.BlockHash
+ }
+ if dec.Index == nil {
+ return errors.New("missing required field 'logIndex' for Log")
+ }
+ x.Index = uint(*dec.Index)
+ if dec.Removed != nil {
+ x.Removed = *dec.Removed
+ }
+ *l = x
+ return nil
+}
diff --git a/core/types/gen_receipt_json.go b/core/types/gen_receipt_json.go
new file mode 100644
index 0000000000..b9e9bee260
--- /dev/null
+++ b/core/types/gen_receipt_json.go
@@ -0,0 +1,79 @@
+// generated by github.com/fjl/gencodec, do not edit.
+
+package types
+
+import (
+ "encoding/json"
+ "errors"
+ "math/big"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/common/hexutil"
+)
+
+func (r *Receipt) MarshalJSON() ([]byte, error) {
+ type ReceiptJSON struct {
+ PostState hexutil.Bytes `json:"root"`
+ CumulativeGasUsed *hexutil.Big `json:"cumulativeGasUsed"`
+ Bloom *Bloom `json:"logsBloom"`
+ Logs []*Log `json:"logs"`
+ TxHash *common.Hash `json:"transactionHash"`
+ ContractAddress *common.Address `json:"contractAddress" optional:"true"`
+ GasUsed *hexutil.Big `json:"gasUsed"`
+ }
+ var enc ReceiptJSON
+ enc.PostState = r.PostState
+ enc.CumulativeGasUsed = (*hexutil.Big)(r.CumulativeGasUsed)
+ enc.Bloom = &r.Bloom
+ enc.Logs = r.Logs
+ enc.TxHash = &r.TxHash
+ enc.ContractAddress = &r.ContractAddress
+ enc.GasUsed = (*hexutil.Big)(r.GasUsed)
+ return json.Marshal(&enc)
+}
+
+func (r *Receipt) UnmarshalJSON(input []byte) error {
+ type ReceiptJSON struct {
+ PostState hexutil.Bytes `json:"root"`
+ CumulativeGasUsed *hexutil.Big `json:"cumulativeGasUsed"`
+ Bloom *Bloom `json:"logsBloom"`
+ Logs []*Log `json:"logs"`
+ TxHash *common.Hash `json:"transactionHash"`
+ ContractAddress *common.Address `json:"contractAddress" optional:"true"`
+ GasUsed *hexutil.Big `json:"gasUsed"`
+ }
+ var dec ReceiptJSON
+ if err := json.Unmarshal(input, &dec); err != nil {
+ return err
+ }
+ var x Receipt
+ if dec.PostState == nil {
+ return errors.New("missing required field 'root' for Receipt")
+ }
+ x.PostState = dec.PostState
+ if dec.CumulativeGasUsed == nil {
+ return errors.New("missing required field 'cumulativeGasUsed' for Receipt")
+ }
+ x.CumulativeGasUsed = (*big.Int)(dec.CumulativeGasUsed)
+ if dec.Bloom == nil {
+ return errors.New("missing required field 'logsBloom' for Receipt")
+ }
+ x.Bloom = *dec.Bloom
+ if dec.Logs == nil {
+ return errors.New("missing required field 'logs' for Receipt")
+ }
+ x.Logs = dec.Logs
+ if dec.TxHash == nil {
+ return errors.New("missing required field 'transactionHash' for Receipt")
+ }
+ x.TxHash = *dec.TxHash
+ if dec.ContractAddress != nil {
+ x.ContractAddress = *dec.ContractAddress
+ }
+ if dec.GasUsed == nil {
+ return errors.New("missing required field 'gasUsed' for Receipt")
+ }
+ x.GasUsed = (*big.Int)(dec.GasUsed)
+ *r = x
+ return nil
+}
diff --git a/core/types/gen_tx_json.go b/core/types/gen_tx_json.go
new file mode 100644
index 0000000000..8bbe629d70
--- /dev/null
+++ b/core/types/gen_tx_json.go
@@ -0,0 +1,99 @@
+// generated by github.com/fjl/gencodec, do not edit.
+
+package types
+
+import (
+ "encoding/json"
+ "errors"
+ "math/big"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/common/hexutil"
+)
+
+func (t *txdata) MarshalJSON() ([]byte, error) {
+ type txdataJSON struct {
+ AccountNonce *hexutil.Uint64 `json:"nonce"`
+ Price *hexutil.Big `json:"gasPrice"`
+ GasLimit *hexutil.Big `json:"gasLimit"`
+ Recipient *common.Address `json:"to" optional:"yes" rlp:"nil"`
+ Amount *hexutil.Big `json:"value"`
+ Payload hexutil.Bytes `json:"input"`
+ V *hexutil.Big `json:"v"`
+ R *hexutil.Big `json:"r"`
+ S *hexutil.Big `json:"s"`
+ Hash *common.Hash `json:"hash" optional:"yes" rlp:"-"`
+ }
+ var enc txdataJSON
+ enc.AccountNonce = (*hexutil.Uint64)(&t.AccountNonce)
+ enc.Price = (*hexutil.Big)(t.Price)
+ enc.GasLimit = (*hexutil.Big)(t.GasLimit)
+ enc.Recipient = t.Recipient
+ enc.Amount = (*hexutil.Big)(t.Amount)
+ enc.Payload = t.Payload
+ enc.V = (*hexutil.Big)(t.V)
+ enc.R = (*hexutil.Big)(t.R)
+ enc.S = (*hexutil.Big)(t.S)
+ enc.Hash = t.Hash
+ return json.Marshal(&enc)
+}
+
+func (t *txdata) UnmarshalJSON(input []byte) error {
+ type txdataJSON struct {
+ AccountNonce *hexutil.Uint64 `json:"nonce"`
+ Price *hexutil.Big `json:"gasPrice"`
+ GasLimit *hexutil.Big `json:"gasLimit"`
+ Recipient *common.Address `json:"to" optional:"yes" rlp:"nil"`
+ Amount *hexutil.Big `json:"value"`
+ Payload hexutil.Bytes `json:"input"`
+ V *hexutil.Big `json:"v"`
+ R *hexutil.Big `json:"r"`
+ S *hexutil.Big `json:"s"`
+ Hash *common.Hash `json:"hash" optional:"yes" rlp:"-"`
+ }
+ var dec txdataJSON
+ if err := json.Unmarshal(input, &dec); err != nil {
+ return err
+ }
+ var x txdata
+ if dec.AccountNonce == nil {
+ return errors.New("missing required field 'nonce' for txdata")
+ }
+ x.AccountNonce = uint64(*dec.AccountNonce)
+ if dec.Price == nil {
+ return errors.New("missing required field 'gasPrice' for txdata")
+ }
+ x.Price = (*big.Int)(dec.Price)
+ if dec.GasLimit == nil {
+ return errors.New("missing required field 'gasLimit' for txdata")
+ }
+ x.GasLimit = (*big.Int)(dec.GasLimit)
+ if dec.Recipient != nil {
+ x.Recipient = dec.Recipient
+ }
+ if dec.Amount == nil {
+ return errors.New("missing required field 'value' for txdata")
+ }
+ x.Amount = (*big.Int)(dec.Amount)
+ if dec.Payload == nil {
+ return errors.New("missing required field 'input' for txdata")
+ }
+ x.Payload = dec.Payload
+ if dec.V == nil {
+ return errors.New("missing required field 'v' for txdata")
+ }
+ x.V = (*big.Int)(dec.V)
+ if dec.R == nil {
+ return errors.New("missing required field 'r' for txdata")
+ }
+ x.R = (*big.Int)(dec.R)
+ if dec.S == nil {
+ return errors.New("missing required field 's' for txdata")
+ }
+ x.S = (*big.Int)(dec.S)
+ if dec.Hash != nil {
+ x.Hash = dec.Hash
+ }
+ *t = x
+ return nil
+}
diff --git a/core/types/log.go b/core/types/log.go
index 7efb06b5c1..57fc7b3631 100644
--- a/core/types/log.go
+++ b/core/types/log.go
@@ -17,8 +17,6 @@
package types
import (
- "encoding/json"
- "errors"
"fmt"
"io"
@@ -27,27 +25,42 @@ import (
"github.com/ethereum/go-ethereum/rlp"
)
-var errMissingLogFields = errors.New("missing required JSON log fields")
+//go:generate gencodec -type Log -field-override logMarshaling -out gen_log_json.go
// Log represents a contract log event. These events are generated by the LOG opcode and
// stored/indexed by the node.
type Log struct {
- // Consensus fields.
- Address common.Address // address of the contract that generated the event
- Topics []common.Hash // list of topics provided by the contract.
- Data []byte // supplied by the contract, usually ABI-encoded
+ // Consensus fields:
+ // address of the contract that generated the event
+ Address common.Address `json:"address"`
+ // list of topics provided by the contract.
+ Topics []common.Hash `json:"topics"`
+ // supplied by the contract, usually ABI-encoded
+ Data []byte `json:"data"`
// Derived fields. These fields are filled in by the node
// but not secured by consensus.
- BlockNumber uint64 // block in which the transaction was included
- TxHash common.Hash // hash of the transaction
- TxIndex uint // index of the transaction in the block
- BlockHash common.Hash // hash of the block in which the transaction was included
- Index uint // index of the log in the receipt
+ // block in which the transaction was included
+ BlockNumber uint64 `json:"blockNumber" optional:"yes"`
+ // hash of the transaction
+ TxHash common.Hash `json:"transactionHash"`
+ // index of the transaction in the block
+ TxIndex uint `json:"transactionIndex"`
+ // hash of the block in which the transaction was included
+ BlockHash common.Hash `json:"blockHash" optional:"yes"`
+ // index of the log in the receipt
+ Index uint `json:"logIndex"`
// The Removed field is true if this log was reverted due to a chain reorganisation.
// You must pay attention to this field if you receive logs through a filter query.
- Removed bool
+ Removed bool `json:"removed" optional:"yes"`
+}
+
+type logMarshaling struct {
+ Data hexutil.Bytes
+ BlockNumber hexutil.Uint64
+ TxIndex hexutil.Uint
+ Index hexutil.Uint
}
type rlpLog struct {
@@ -67,18 +80,6 @@ type rlpStorageLog struct {
Index uint
}
-type jsonLog struct {
- Address *common.Address `json:"address"`
- Topics *[]common.Hash `json:"topics"`
- Data *hexutil.Bytes `json:"data"`
- BlockNumber *hexutil.Uint64 `json:"blockNumber"`
- TxIndex *hexutil.Uint `json:"transactionIndex"`
- TxHash *common.Hash `json:"transactionHash"`
- BlockHash *common.Hash `json:"blockHash"`
- Index *hexutil.Uint `json:"logIndex"`
- Removed bool `json:"removed"`
-}
-
// EncodeRLP implements rlp.Encoder.
func (l *Log) EncodeRLP(w io.Writer) error {
return rlp.Encode(w, rlpLog{Address: l.Address, Topics: l.Topics, Data: l.Data})
@@ -98,54 +99,6 @@ func (l *Log) String() string {
return fmt.Sprintf(`log: %x %x %x %x %d %x %d`, l.Address, l.Topics, l.Data, l.TxHash, l.TxIndex, l.BlockHash, l.Index)
}
-// MarshalJSON implements json.Marshaler.
-func (l *Log) MarshalJSON() ([]byte, error) {
- jslog := &jsonLog{
- Address: &l.Address,
- Topics: &l.Topics,
- Data: (*hexutil.Bytes)(&l.Data),
- TxIndex: (*hexutil.Uint)(&l.TxIndex),
- TxHash: &l.TxHash,
- Index: (*hexutil.Uint)(&l.Index),
- Removed: l.Removed,
- }
- // Set block information for mined logs.
- if (l.BlockHash != common.Hash{}) {
- jslog.BlockHash = &l.BlockHash
- jslog.BlockNumber = (*hexutil.Uint64)(&l.BlockNumber)
- }
- return json.Marshal(jslog)
-}
-
-// UnmarshalJSON implements json.Umarshaler.
-func (l *Log) UnmarshalJSON(input []byte) error {
- var dec jsonLog
- if err := json.Unmarshal(input, &dec); err != nil {
- return err
- }
- if dec.Address == nil || dec.Topics == nil || dec.Data == nil ||
- dec.TxIndex == nil || dec.TxHash == nil || dec.Index == nil {
- return errMissingLogFields
- }
- declog := Log{
- Address: *dec.Address,
- Topics: *dec.Topics,
- Data: *dec.Data,
- TxHash: *dec.TxHash,
- TxIndex: uint(*dec.TxIndex),
- Index: uint(*dec.Index),
- Removed: dec.Removed,
- }
- // Block information may be missing if the log is received through
- // the pending log filter, so it's handled specially here.
- if dec.BlockHash != nil && dec.BlockNumber != nil {
- declog.BlockHash = *dec.BlockHash
- declog.BlockNumber = uint64(*dec.BlockNumber)
- }
- *l = declog
- return nil
-}
-
// LogForStorage is a wrapper around a Log that flattens and parses the entire content of
// a log including non-consensus fields.
type LogForStorage Log
diff --git a/core/types/log_test.go b/core/types/log_test.go
index bf742ccac2..0e56acfe4a 100644
--- a/core/types/log_test.go
+++ b/core/types/log_test.go
@@ -18,6 +18,7 @@ package types
import (
"encoding/json"
+ "fmt"
"reflect"
"testing"
@@ -96,7 +97,7 @@ var unmarshalLogTests = map[string]struct {
},
"missing data": {
input: `{"address":"0xecf8f87f810ecf450940c9f60066b4a7a501d6a7","blockHash":"0x656c34545f90a730a19008c0e7a7cd4fb3895064b48d6d69761bd5abad681056","blockNumber":"0x1ecfa4","logIndex":"0x2","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x00000000000000000000000080b2c9d7cbbf30a1b0fc8983c647d754c6525615","0x000000000000000000000000f9dff387dcb5cc4cca5b91adb07a95f54e9f1bb6"],"transactionHash":"0x3b198bfd5d2907285af009e9ae84a0ecd63677110d89d7e030251acb87f6487e","transactionIndex":"0x3"}`,
- wantError: errMissingLogFields,
+ wantError: fmt.Errorf("missing required field 'data' for Log"),
},
}
diff --git a/core/types/receipt.go b/core/types/receipt.go
index 0a6a35e334..5bfcb15fc7 100644
--- a/core/types/receipt.go
+++ b/core/types/receipt.go
@@ -17,8 +17,6 @@
package types
import (
- "encoding/json"
- "errors"
"fmt"
"io"
"math/big"
@@ -28,33 +26,26 @@ import (
"github.com/ethereum/go-ethereum/rlp"
)
-var (
- errMissingReceiptPostState = errors.New("missing post state root in JSON receipt")
- errMissingReceiptFields = errors.New("missing required JSON receipt fields")
-)
+//go:generate gencodec -type Receipt -field-override receiptMarshaling -out gen_receipt_json.go
// Receipt represents the results of a transaction.
type Receipt struct {
// Consensus fields
- PostState []byte
- CumulativeGasUsed *big.Int
- Bloom Bloom
- Logs []*Log
+ PostState []byte `json:"root"`
+ CumulativeGasUsed *big.Int `json:"cumulativeGasUsed"`
+ Bloom Bloom `json:"logsBloom"`
+ Logs []*Log `json:"logs"`
// Implementation fields (don't reorder!)
- TxHash common.Hash
- ContractAddress common.Address
- GasUsed *big.Int
+ TxHash common.Hash `json:"transactionHash"`
+ ContractAddress common.Address `json:"contractAddress" optional:"true"`
+ GasUsed *big.Int `json:"gasUsed"`
}
-type jsonReceipt struct {
- PostState *common.Hash `json:"root"`
- CumulativeGasUsed *hexutil.Big `json:"cumulativeGasUsed"`
- Bloom *Bloom `json:"logsBloom"`
- Logs []*Log `json:"logs"`
- TxHash *common.Hash `json:"transactionHash"`
- ContractAddress *common.Address `json:"contractAddress"`
- GasUsed *hexutil.Big `json:"gasUsed"`
+type receiptMarshaling struct {
+ PostState hexutil.Bytes
+ CumulativeGasUsed *hexutil.Big
+ GasUsed *hexutil.Big
}
// NewReceipt creates a barebone transaction receipt, copying the init fields.
@@ -84,51 +75,6 @@ func (r *Receipt) DecodeRLP(s *rlp.Stream) error {
return nil
}
-// MarshalJSON encodes receipts into the web3 RPC response block format.
-func (r *Receipt) MarshalJSON() ([]byte, error) {
- root := common.BytesToHash(r.PostState)
-
- return json.Marshal(&jsonReceipt{
- PostState: &root,
- CumulativeGasUsed: (*hexutil.Big)(r.CumulativeGasUsed),
- Bloom: &r.Bloom,
- Logs: r.Logs,
- TxHash: &r.TxHash,
- ContractAddress: &r.ContractAddress,
- GasUsed: (*hexutil.Big)(r.GasUsed),
- })
-}
-
-// UnmarshalJSON decodes the web3 RPC receipt format.
-func (r *Receipt) UnmarshalJSON(input []byte) error {
- var dec jsonReceipt
- if err := json.Unmarshal(input, &dec); err != nil {
- return err
- }
- // Ensure that all fields are set. PostState is checked separately because it is a
- // recent addition to the RPC spec (as of August 2016) and older implementations might
- // not provide it. Note that ContractAddress is not checked because it can be null.
- if dec.PostState == nil {
- return errMissingReceiptPostState
- }
- if dec.CumulativeGasUsed == nil || dec.Bloom == nil ||
- dec.Logs == nil || dec.TxHash == nil || dec.GasUsed == nil {
- return errMissingReceiptFields
- }
- *r = Receipt{
- PostState: (*dec.PostState)[:],
- CumulativeGasUsed: (*big.Int)(dec.CumulativeGasUsed),
- Bloom: *dec.Bloom,
- Logs: dec.Logs,
- TxHash: *dec.TxHash,
- GasUsed: (*big.Int)(dec.GasUsed),
- }
- if dec.ContractAddress != nil {
- r.ContractAddress = *dec.ContractAddress
- }
- return nil
-}
-
// String implements the Stringer interface.
func (r *Receipt) String() string {
return fmt.Sprintf("receipt{med=%x cgas=%v bloom=%x logs=%v}", r.PostState, r.CumulativeGasUsed, r.Bloom, r.Logs)
diff --git a/core/types/transaction.go b/core/types/transaction.go
index 9382acb70b..86948b5b74 100644
--- a/core/types/transaction.go
+++ b/core/types/transaction.go
@@ -18,7 +18,6 @@ package types
import (
"container/heap"
- "encoding/json"
"errors"
"fmt"
"io"
@@ -28,21 +27,19 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/crypto"
- "github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp"
)
-var ErrInvalidSig = errors.New("invalid transaction v, r, s values")
+//go:generate gencodec -type txdata -field-override txdataMarshaling -out gen_tx_json.go
var (
- errMissingTxSignatureFields = errors.New("missing required JSON transaction signature fields")
- errMissingTxFields = errors.New("missing required JSON transaction fields")
- errNoSigner = errors.New("missing signing methods")
+ ErrInvalidSig = errors.New("invalid transaction v, r, s values")
+ errNoSigner = errors.New("missing signing methods")
)
// deriveSigner makes a *best* guess about which signer to use.
func deriveSigner(V *big.Int) Signer {
- if V.BitLen() > 0 && isProtectedV(V) {
+ if V.Sign() != 0 && isProtectedV(V) {
return EIP155Signer{chainId: deriveChainId(V)}
} else {
return HomesteadSigner{}
@@ -58,26 +55,31 @@ type Transaction struct {
}
type txdata struct {
- AccountNonce uint64
- Price, GasLimit *big.Int
- Recipient *common.Address `rlp:"nil"` // nil means contract creation
- Amount *big.Int
- Payload []byte
- V *big.Int // signature
- R, S *big.Int // signature
+ AccountNonce uint64 `json:"nonce"`
+ Price *big.Int `json:"gasPrice"`
+ GasLimit *big.Int `json:"gasLimit"`
+ Recipient *common.Address `json:"to" optional:"yes" rlp:"nil"` // nil means contract creation
+ Amount *big.Int `json:"value"`
+ Payload []byte `json:"input"`
+
+ // Signature values
+ V *big.Int `json:"v"`
+ R *big.Int `json:"r"`
+ S *big.Int `json:"s"`
+
+ // This is only used when marshaling to JSON.
+ Hash *common.Hash `json:"hash" optional:"yes" rlp:"-"`
}
-type jsonTransaction struct {
- Hash *common.Hash `json:"hash"`
- AccountNonce *hexutil.Uint64 `json:"nonce"`
- Price *hexutil.Big `json:"gasPrice"`
- GasLimit *hexutil.Big `json:"gas"`
- Recipient *common.Address `json:"to"`
- Amount *hexutil.Big `json:"value"`
- Payload *hexutil.Bytes `json:"input"`
- V *hexutil.Big `json:"v"`
- R *hexutil.Big `json:"r"`
- S *hexutil.Big `json:"s"`
+type txdataMarshaling struct {
+ AccountNonce hexutil.Uint64
+ Price *hexutil.Big
+ GasLimit *hexutil.Big
+ Amount *hexutil.Big
+ Payload hexutil.Bytes
+ V *hexutil.Big
+ R *hexutil.Big
+ S *hexutil.Big
}
func NewTransaction(nonce uint64, to common.Address, amount, gasLimit, gasPrice *big.Int, data []byte) *Transaction {
@@ -116,19 +118,6 @@ func newTransaction(nonce uint64, to *common.Address, amount, gasLimit, gasPrice
return &Transaction{data: d}
}
-func pickSigner(rules params.Rules) Signer {
- var signer Signer
- switch {
- case rules.IsEIP155:
- signer = NewEIP155Signer(rules.ChainId)
- case rules.IsHomestead:
- signer = HomesteadSigner{}
- default:
- signer = FrontierSigner{}
- }
- return signer
-}
-
// ChainId returns which chain id this transaction was signed for (if at all)
func (tx *Transaction) ChainId() *big.Int {
return deriveChainId(tx.data.V)
@@ -164,66 +153,30 @@ func (tx *Transaction) DecodeRLP(s *rlp.Stream) error {
return err
}
-// MarshalJSON encodes transactions into the web3 RPC response block format.
func (tx *Transaction) MarshalJSON() ([]byte, error) {
hash := tx.Hash()
-
- return json.Marshal(&jsonTransaction{
- Hash: &hash,
- AccountNonce: (*hexutil.Uint64)(&tx.data.AccountNonce),
- Price: (*hexutil.Big)(tx.data.Price),
- GasLimit: (*hexutil.Big)(tx.data.GasLimit),
- Recipient: tx.data.Recipient,
- Amount: (*hexutil.Big)(tx.data.Amount),
- Payload: (*hexutil.Bytes)(&tx.data.Payload),
- V: (*hexutil.Big)(tx.data.V),
- R: (*hexutil.Big)(tx.data.R),
- S: (*hexutil.Big)(tx.data.S),
- })
+ data := tx.data
+ data.Hash = &hash
+ return data.MarshalJSON()
}
// UnmarshalJSON decodes the web3 RPC transaction format.
func (tx *Transaction) UnmarshalJSON(input []byte) error {
- var dec jsonTransaction
- if err := json.Unmarshal(input, &dec); err != nil {
+ var dec txdata
+ if err := dec.UnmarshalJSON(input); err != nil {
return err
}
- // Ensure that all fields are set. V, R, S are checked separately because they're a
- // recent addition to the RPC spec (as of August 2016) and older implementations might
- // not provide them. Note that Recipient is not checked because it can be missing for
- // contract creations.
- if dec.V == nil || dec.R == nil || dec.S == nil {
- return errMissingTxSignatureFields
- }
-
var V byte
- if isProtectedV((*big.Int)(dec.V)) {
- chainId := deriveChainId((*big.Int)(dec.V)).Uint64()
- V = byte(dec.V.ToInt().Uint64() - 35 - 2*chainId)
+ if isProtectedV(dec.V) {
+ chainId := deriveChainId(dec.V).Uint64()
+ V = byte(dec.V.Uint64() - 35 - 2*chainId)
} else {
- V = byte(((*big.Int)(dec.V)).Uint64() - 27)
+ V = byte(dec.V.Uint64() - 27)
}
- if !crypto.ValidateSignatureValues(V, (*big.Int)(dec.R), (*big.Int)(dec.S), false) {
+ if !crypto.ValidateSignatureValues(V, dec.R, dec.S, false) {
return ErrInvalidSig
}
-
- if dec.AccountNonce == nil || dec.Price == nil || dec.GasLimit == nil || dec.Amount == nil || dec.Payload == nil {
- return errMissingTxFields
- }
- // Assign the fields. This is not atomic but reusing transactions
- // for decoding isn't thread safe anyway.
- *tx = Transaction{}
- tx.data = txdata{
- AccountNonce: uint64(*dec.AccountNonce),
- Recipient: dec.Recipient,
- Amount: (*big.Int)(dec.Amount),
- GasLimit: (*big.Int)(dec.GasLimit),
- Price: (*big.Int)(dec.Price),
- Payload: *dec.Payload,
- V: (*big.Int)(dec.V),
- R: (*big.Int)(dec.R),
- S: (*big.Int)(dec.S),
- }
+ *tx = Transaction{data: dec}
return nil
}
diff --git a/core/types/transaction_signing.go b/core/types/transaction_signing.go
index 7d7b63e9f1..b4bab0aad7 100644
--- a/core/types/transaction_signing.go
+++ b/core/types/transaction_signing.go
@@ -112,6 +112,9 @@ type EIP155Signer struct {
}
func NewEIP155Signer(chainId *big.Int) EIP155Signer {
+ if chainId == nil {
+ chainId = new(big.Int)
+ }
return EIP155Signer{
chainId: chainId,
chainIdMul: new(big.Int).Mul(chainId, big.NewInt(2)),
@@ -167,7 +170,7 @@ func (s EIP155Signer) WithSignature(tx *Transaction, sig []byte) (*Transaction,
cpy.data.R = new(big.Int).SetBytes(sig[:32])
cpy.data.S = new(big.Int).SetBytes(sig[32:64])
cpy.data.V = new(big.Int).SetBytes([]byte{sig[64]})
- if s.chainId.BitLen() > 0 {
+ if s.chainId.Sign() != 0 {
cpy.data.V = big.NewInt(int64(sig[64] + 35))
cpy.data.V.Add(cpy.data.V, s.chainIdMul)
}
diff --git a/core/types/transaction_signing_test.go b/core/types/transaction_signing_test.go
index 3216fcfad3..7f799fb101 100644
--- a/core/types/transaction_signing_test.go
+++ b/core/types/transaction_signing_test.go
@@ -71,7 +71,7 @@ func TestEIP155ChainId(t *testing.T) {
t.Error("didn't expect tx to be protected")
}
- if tx.ChainId().BitLen() > 0 {
+ if tx.ChainId().Sign() != 0 {
t.Error("expected chain id to be 0 got", tx.ChainId())
}
}
diff --git a/core/vm/asm.go b/core/vm/asm.go
deleted file mode 100644
index d7dbde5e82..0000000000
--- a/core/vm/asm.go
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright 2014 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see .
-
-package vm
-
-import (
- "fmt"
- "math/big"
-
- "github.com/ethereum/go-ethereum/common"
-)
-
-// Disassemble disassembles the byte code and returns the string
-// representation (human readable opcodes).
-func Disassemble(script []byte) (asm []string) {
- pc := new(big.Int)
- for {
- if pc.Cmp(big.NewInt(int64(len(script)))) >= 0 {
- return
- }
-
- // Get the memory location of pc
- val := script[pc.Int64()]
- // Get the opcode (it must be an opcode!)
- op := OpCode(val)
-
- asm = append(asm, fmt.Sprintf("%v", op))
-
- switch op {
- case PUSH1, PUSH2, PUSH3, PUSH4, PUSH5, PUSH6, PUSH7, PUSH8, PUSH9, PUSH10, PUSH11, PUSH12, PUSH13, PUSH14, PUSH15, PUSH16, PUSH17, PUSH18, PUSH19, PUSH20, PUSH21, PUSH22, PUSH23, PUSH24, PUSH25, PUSH26, PUSH27, PUSH28, PUSH29, PUSH30, PUSH31, PUSH32:
- pc.Add(pc, common.Big1)
- a := int64(op) - int64(PUSH1) + 1
- if int(pc.Int64()+a) > len(script) {
- return nil
- }
-
- data := script[pc.Int64() : pc.Int64()+a]
- if len(data) == 0 {
- data = []byte{0}
- }
- asm = append(asm, fmt.Sprintf("0x%x", data))
-
- pc.Add(pc, big.NewInt(a-1))
- }
-
- pc.Add(pc, common.Big1)
- }
-}
diff --git a/core/vm/common.go b/core/vm/common.go
index 2878b92d2a..779cee006d 100644
--- a/core/vm/common.go
+++ b/core/vm/common.go
@@ -17,103 +17,51 @@
package vm
import (
- "math"
"math/big"
"github.com/ethereum/go-ethereum/common"
- "github.com/ethereum/go-ethereum/params"
-)
-
-// Type is the VM type accepted by **NewVm**
-type Type byte
-
-const (
- StdVmTy Type = iota // Default standard VM
- JitVmTy // LLVM JIT VM
- MaxVmTy
-)
-
-var (
- Pow256 = common.BigPow(2, 256) // Pow256 is 2**256
-
- U256 = common.U256 // Shortcut to common.U256
- S256 = common.S256 // Shortcut to common.S256
-
- Zero = common.Big0 // Shortcut to common.Big0
- One = common.Big1 // Shortcut to common.Big1
-
- max = big.NewInt(math.MaxInt64) // Maximum 64 bit integer
+ "github.com/ethereum/go-ethereum/common/math"
)
// calculates the memory size required for a step
func calcMemSize(off, l *big.Int) *big.Int {
- if l.Cmp(common.Big0) == 0 {
+ if l.Sign() == 0 {
return common.Big0
}
return new(big.Int).Add(off, l)
}
-// calculates the quadratic gas
-func quadMemGas(mem *Memory, newMemSize, gas *big.Int) {
- if newMemSize.Cmp(common.Big0) > 0 {
- newMemSizeWords := toWordSize(newMemSize)
- newMemSize.Mul(newMemSizeWords, u256(32))
-
- if newMemSize.Cmp(u256(int64(mem.Len()))) > 0 {
- // be careful reusing variables here when changing.
- // The order has been optimised to reduce allocation
- oldSize := toWordSize(big.NewInt(int64(mem.Len())))
- pow := new(big.Int).Exp(oldSize, common.Big2, Zero)
- linCoef := oldSize.Mul(oldSize, params.MemoryGas)
- quadCoef := new(big.Int).Div(pow, params.QuadCoeffDiv)
- oldTotalFee := new(big.Int).Add(linCoef, quadCoef)
-
- pow.Exp(newMemSizeWords, common.Big2, Zero)
- linCoef = linCoef.Mul(newMemSizeWords, params.MemoryGas)
- quadCoef = quadCoef.Div(pow, params.QuadCoeffDiv)
- newTotalFee := linCoef.Add(linCoef, quadCoef)
-
- fee := newTotalFee.Sub(newTotalFee, oldTotalFee)
- gas.Add(gas, fee)
- }
- }
-}
-
-// Simple helper
-func u256(n int64) *big.Int {
- return big.NewInt(n)
-}
-
-// Mainly used for print variables and passing to Print*
-func toValue(val *big.Int) interface{} {
- // Let's assume a string on right padded zero's
- b := val.Bytes()
- if b[0] != 0 && b[len(b)-1] == 0x0 && b[len(b)-2] == 0x0 {
- return string(b)
- }
-
- return val
-}
-
// getData returns a slice from the data based on the start and size and pads
// up to size with zero's. This function is overflow safe.
func getData(data []byte, start, size *big.Int) []byte {
dlen := big.NewInt(int64(len(data)))
- s := common.BigMin(start, dlen)
- e := common.BigMin(new(big.Int).Add(s, size), dlen)
+ s := math.BigMin(start, dlen)
+ e := math.BigMin(new(big.Int).Add(s, size), dlen)
return common.RightPadBytes(data[s.Uint64():e.Uint64()], int(size.Uint64()))
}
-// useGas attempts to subtract the amount of gas and returns whether it was
-// successful
-func useGas(gas, amount *big.Int) bool {
- if gas.Cmp(amount) < 0 {
- return false
+// bigUint64 returns the integer casted to a uint64 and returns whether it
+// overflowed in the process.
+func bigUint64(v *big.Int) (uint64, bool) {
+ return v.Uint64(), v.BitLen() > 64
+}
+
+// toWordSize returns the ceiled word size required for memory expansion.
+func toWordSize(size uint64) uint64 {
+ if size > math.MaxUint64-31 {
+ return math.MaxUint64/32 + 1
}
- // Sub the amount of gas from the remaining
- gas.Sub(gas, amount)
+ return (size + 31) / 32
+}
+
+func allZero(b []byte) bool {
+ for _, byte := range b {
+ if byte != 0 {
+ return false
+ }
+ }
return true
}
diff --git a/core/vm/contract.go b/core/vm/contract.go
index dfa93ab18b..66748e8215 100644
--- a/core/vm/contract.go
+++ b/core/vm/contract.go
@@ -24,13 +24,21 @@ import (
// ContractRef is a reference to the contract's backing object
type ContractRef interface {
- ReturnGas(*big.Int)
Address() common.Address
- Value() *big.Int
- SetCode(common.Hash, []byte)
- ForEachStorage(callback func(key, value common.Hash) bool)
}
+// AccountRef implements ContractRef.
+//
+// Account references are used during EVM initialisation and
+// it's primary use is to fetch addresses. Removing this object
+// proves difficult because of the cached jump destinations which
+// are fetched from the parent contract (i.e. the caller), which
+// is a ContractRef.
+type AccountRef common.Address
+
+// Address casts AccountRef to a Address
+func (ar AccountRef) Address() common.Address { return (common.Address)(ar) }
+
// Contract represents an ethereum contract in the state database. It contains
// the the contract code, calling arguments. Contract implements ContractRef
type Contract struct {
@@ -48,7 +56,8 @@ type Contract struct {
CodeAddr *common.Address
Input []byte
- value, Gas, UsedGas *big.Int
+ Gas uint64
+ value *big.Int
Args []byte
@@ -56,7 +65,7 @@ type Contract struct {
}
// NewContract returns a new contract environment for the execution of EVM.
-func NewContract(caller ContractRef, object ContractRef, value, gas *big.Int) *Contract {
+func NewContract(caller ContractRef, object ContractRef, value *big.Int, gas uint64) *Contract {
c := &Contract{CallerAddress: caller.Address(), caller: caller, self: object, Args: nil}
if parent, ok := caller.(*Contract); ok {
@@ -68,9 +77,9 @@ func NewContract(caller ContractRef, object ContractRef, value, gas *big.Int) *C
// Gas should be a pointer so it can safely be reduced through the run
// This pointer will be off the state transition
- c.Gas = gas //new(big.Int).Set(gas)
- c.value = new(big.Int).Set(value)
- c.UsedGas = new(big.Int)
+ c.Gas = gas
+ // ensures a value is set
+ c.value = value
return c
}
@@ -81,7 +90,10 @@ func (c *Contract) AsDelegate() *Contract {
c.DelegateCall = true
// NOTE: caller must, at all times be a contract. It should never happen
// that caller is something other than a Contract.
- c.CallerAddress = c.caller.(*Contract).CallerAddress
+ parent := c.caller.(*Contract)
+ c.CallerAddress = parent.CallerAddress
+ c.value = parent.value
+
return c
}
@@ -107,27 +119,13 @@ func (c *Contract) Caller() common.Address {
return c.CallerAddress
}
-// Finalise finalises the contract and returning any remaining gas to the original
-// caller.
-func (c *Contract) Finalise() {
- // Return the remaining gas to the caller
- c.caller.ReturnGas(c.Gas)
-}
-
// UseGas attempts the use gas and subtracts it and returns true on success
-func (c *Contract) UseGas(gas *big.Int) (ok bool) {
- ok = useGas(c.Gas, gas)
- if ok {
- c.UsedGas.Add(c.UsedGas, gas)
+func (c *Contract) UseGas(gas uint64) (ok bool) {
+ if c.Gas < gas {
+ return false
}
- return
-}
-
-// ReturnGas adds the given gas back to itself.
-func (c *Contract) ReturnGas(gas *big.Int) {
- // Return the gas to the context
- c.Gas.Add(c.Gas, gas)
- c.UsedGas.Sub(c.UsedGas, gas)
+ c.Gas -= gas
+ return true
}
// Address returns the contracts address
@@ -153,9 +151,3 @@ func (self *Contract) SetCallCode(addr *common.Address, hash common.Hash, code [
self.CodeHash = hash
self.CodeAddr = addr
}
-
-// EachStorage iterates the contract's storage and calls a method for every key
-// value pair.
-func (self *Contract) ForEachStorage(cb func(key, value common.Hash) bool) {
- self.caller.ForEachStorage(cb)
-}
diff --git a/core/vm/contracts.go b/core/vm/contracts.go
index 9645d268fe..e87640d022 100644
--- a/core/vm/contracts.go
+++ b/core/vm/contracts.go
@@ -17,28 +17,29 @@
package vm
import (
+ "crypto/sha256"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params"
+ "golang.org/x/crypto/ripemd160"
)
// Precompiled contract is the basic interface for native Go contracts. The implementation
// requires a deterministic gas count based on the input size of the Run method of the
// contract.
type PrecompiledContract interface {
- RequiredGas(inputSize int) *big.Int // RequiredPrice calculates the contract gas use
- Run(input []byte) []byte // Run runs the precompiled contract
+ RequiredGas(inputSize int) uint64 // RequiredPrice calculates the contract gas use
+ Run(input []byte) []byte // Run runs the precompiled contract
}
// Precompiled contains the default set of ethereum contracts
var PrecompiledContracts = map[common.Address]PrecompiledContract{
common.BytesToAddress([]byte{1}): &ecrecover{},
- common.BytesToAddress([]byte{2}): &sha256{},
- common.BytesToAddress([]byte{3}): &ripemd160{},
+ common.BytesToAddress([]byte{2}): &sha256hash{},
+ common.BytesToAddress([]byte{3}): &ripemd160hash{},
common.BytesToAddress([]byte{4}): &dataCopy{},
}
@@ -57,7 +58,7 @@ func RunPrecompiledContract(p PrecompiledContract, input []byte, contract *Contr
// ECRECOVER implemented as a native contract
type ecrecover struct{}
-func (c *ecrecover) RequiredGas(inputSize int) *big.Int {
+func (c *ecrecover) RequiredGas(inputSize int) uint64 {
return params.EcrecoverGas
}
@@ -68,20 +69,20 @@ func (c *ecrecover) Run(in []byte) []byte {
// "in" is (hash, v, r, s), each 32 bytes
// but for ecrecover we want (r, s, v)
- r := common.BytesToBig(in[64:96])
- s := common.BytesToBig(in[96:128])
+ r := new(big.Int).SetBytes(in[64:96])
+ s := new(big.Int).SetBytes(in[96:128])
v := in[63] - 27
// tighter sig s values in homestead only apply to tx sigs
- if common.Bytes2Big(in[32:63]).BitLen() > 0 || !crypto.ValidateSignatureValues(v, r, s, false) {
- glog.V(logger.Detail).Infof("ECRECOVER error: v, r or s value invalid")
+ if !allZero(in[32:63]) || !crypto.ValidateSignatureValues(v, r, s, false) {
+ log.Trace("ECRECOVER error: v, r or s value invalid")
return nil
}
// v needs to be at the end for libsecp256k1
pubKey, err := crypto.Ecrecover(in[:32], append(in[64:128], v))
// make sure the public key is a valid one
if err != nil {
- glog.V(logger.Detail).Infoln("ECRECOVER error: ", err)
+ log.Trace("ECRECOVER failed", "err", err)
return nil
}
@@ -90,37 +91,45 @@ func (c *ecrecover) Run(in []byte) []byte {
}
// SHA256 implemented as a native contract
-type sha256 struct{}
+type sha256hash struct{}
-func (c *sha256) RequiredGas(inputSize int) *big.Int {
- n := big.NewInt(int64(inputSize+31) / 32)
- n.Mul(n, params.Sha256WordGas)
- return n.Add(n, params.Sha256Gas)
+// RequiredGas returns the gas required to execute the pre-compiled contract.
+//
+// This method does not require any overflow checking as the input size gas costs
+// required for anything significant is so high it's impossible to pay for.
+func (c *sha256hash) RequiredGas(inputSize int) uint64 {
+ return uint64(inputSize+31)/32*params.Sha256WordGas + params.Sha256Gas
}
-func (c *sha256) Run(in []byte) []byte {
- return crypto.Sha256(in)
+func (c *sha256hash) Run(in []byte) []byte {
+ h := sha256.Sum256(in)
+ return h[:]
}
// RIPMED160 implemented as a native contract
-type ripemd160 struct{}
+type ripemd160hash struct{}
-func (c *ripemd160) RequiredGas(inputSize int) *big.Int {
- n := big.NewInt(int64(inputSize+31) / 32)
- n.Mul(n, params.Ripemd160WordGas)
- return n.Add(n, params.Ripemd160Gas)
+// RequiredGas returns the gas required to execute the pre-compiled contract.
+//
+// This method does not require any overflow checking as the input size gas costs
+// required for anything significant is so high it's impossible to pay for.
+func (c *ripemd160hash) RequiredGas(inputSize int) uint64 {
+ return uint64(inputSize+31)/32*params.Ripemd160WordGas + params.Ripemd160Gas
}
-func (c *ripemd160) Run(in []byte) []byte {
- return common.LeftPadBytes(crypto.Ripemd160(in), 32)
+func (c *ripemd160hash) Run(in []byte) []byte {
+ ripemd := ripemd160.New()
+ ripemd.Write(in)
+ return common.LeftPadBytes(ripemd.Sum(nil), 32)
}
// data copy implemented as a native contract
type dataCopy struct{}
-func (c *dataCopy) RequiredGas(inputSize int) *big.Int {
- n := big.NewInt(int64(inputSize+31) / 32)
- n.Mul(n, params.IdentityWordGas)
-
- return n.Add(n, params.IdentityGas)
+// RequiredGas returns the gas required to execute the pre-compiled contract.
+//
+// This method does not require any overflow checking as the input size gas costs
+// required for anything significant is so high it's impossible to pay for.
+func (c *dataCopy) RequiredGas(inputSize int) uint64 {
+ return uint64(inputSize+31)/32*params.IdentityWordGas + params.IdentityGas
}
func (c *dataCopy) Run(in []byte) []byte {
return in
diff --git a/core/vm/environment.go b/core/vm/evm.go
similarity index 81%
rename from core/vm/environment.go
rename to core/vm/evm.go
index c19ef464ba..71efcfa458 100644
--- a/core/vm/environment.go
+++ b/core/vm/evm.go
@@ -17,7 +17,6 @@
package vm
import (
- "fmt"
"math/big"
"sync/atomic"
@@ -102,39 +101,30 @@ func (evm *EVM) Cancel() {
// Call executes the contract associated with the addr with the given input as parameters. It also handles any
// necessary value transfer required and takes the necessary steps to create accounts and reverses the state in
// case of an execution error or failed value transfer.
-func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas, value *big.Int) (ret []byte, err error) {
+func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas uint64, value *big.Int) (ret []byte, leftOverGas uint64, err error) {
if evm.vmConfig.NoRecursion && evm.depth > 0 {
- caller.ReturnGas(gas)
-
- return nil, nil
+ return nil, gas, nil
}
// Depth check execution. Fail if we're trying to execute above the
// limit.
- if evm.depth > int(params.CallCreateDepth.Int64()) {
- caller.ReturnGas(gas)
-
- return nil, ErrDepth
+ if evm.depth > int(params.CallCreateDepth) {
+ return nil, gas, ErrDepth
}
if !evm.Context.CanTransfer(evm.StateDB, caller.Address(), value) {
- caller.ReturnGas(gas)
-
- return nil, ErrInsufficientBalance
+ return nil, gas, ErrInsufficientBalance
}
var (
- to Account
+ to = AccountRef(addr)
snapshot = evm.StateDB.Snapshot()
)
if !evm.StateDB.Exist(addr) {
- if PrecompiledContracts[addr] == nil && evm.ChainConfig().IsEIP158(evm.BlockNumber) && value.BitLen() == 0 {
- caller.ReturnGas(gas)
- return nil, nil
+ if PrecompiledContracts[addr] == nil && evm.ChainConfig().IsEIP158(evm.BlockNumber) && value.Sign() == 0 {
+ return nil, gas, nil
}
- to = evm.StateDB.CreateAccount(addr)
- } else {
- to = evm.StateDB.GetAccount(addr)
+ evm.StateDB.CreateAccount(addr)
}
evm.Transfer(evm.StateDB, caller.Address(), to.Address(), value)
@@ -143,7 +133,6 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas,
// only.
contract := NewContract(caller, to, value, gas)
contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr))
- defer contract.Finalise()
ret, err = evm.interpreter.Run(contract, input)
// When an error was returned by the EVM or when setting the creation code
@@ -154,7 +143,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas,
evm.StateDB.RevertToSnapshot(snapshot)
}
- return ret, err
+ return ret, contract.Gas, err
}
// CallCode executes the contract associated with the addr with the given input as parameters. It also handles any
@@ -162,36 +151,29 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas,
// case of an execution error or failed value transfer.
//
// CallCode differs from Call in the sense that it executes the given address' code with the caller as context.
-func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, gas, value *big.Int) (ret []byte, err error) {
+func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, gas uint64, value *big.Int) (ret []byte, leftOverGas uint64, err error) {
if evm.vmConfig.NoRecursion && evm.depth > 0 {
- caller.ReturnGas(gas)
-
- return nil, nil
+ return nil, gas, nil
}
// Depth check execution. Fail if we're trying to execute above the
// limit.
- if evm.depth > int(params.CallCreateDepth.Int64()) {
- caller.ReturnGas(gas)
-
- return nil, ErrDepth
+ if evm.depth > int(params.CallCreateDepth) {
+ return nil, gas, ErrDepth
}
if !evm.CanTransfer(evm.StateDB, caller.Address(), value) {
- caller.ReturnGas(gas)
-
- return nil, fmt.Errorf("insufficient funds to transfer value. Req %v, has %v", value, evm.StateDB.GetBalance(caller.Address()))
+ return nil, gas, ErrInsufficientBalance
}
var (
snapshot = evm.StateDB.Snapshot()
- to = evm.StateDB.GetAccount(caller.Address())
+ to = AccountRef(caller.Address())
)
// initialise a new contract and set the code that is to be used by the
// E The contract is a scoped evmironment for this execution context
// only.
contract := NewContract(caller, to, value, gas)
contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr))
- defer contract.Finalise()
ret, err = evm.interpreter.Run(contract, input)
if err != nil {
@@ -200,7 +182,7 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte,
evm.StateDB.RevertToSnapshot(snapshot)
}
- return ret, err
+ return ret, contract.Gas, err
}
// DelegateCall executes the contract associated with the addr with the given input as parameters.
@@ -208,29 +190,25 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte,
//
// DelegateCall differs from CallCode in the sense that it executes the given address' code with the caller as context
// and the caller is set to the caller of the caller.
-func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []byte, gas *big.Int) (ret []byte, err error) {
+func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []byte, gas uint64) (ret []byte, leftOverGas uint64, err error) {
if evm.vmConfig.NoRecursion && evm.depth > 0 {
- caller.ReturnGas(gas)
-
- return nil, nil
+ return nil, gas, nil
}
// Depth check execution. Fail if we're trying to execute above the
// limit.
- if evm.depth > int(params.CallCreateDepth.Int64()) {
- caller.ReturnGas(gas)
- return nil, ErrDepth
+ if evm.depth > int(params.CallCreateDepth) {
+ return nil, gas, ErrDepth
}
var (
snapshot = evm.StateDB.Snapshot()
- to = evm.StateDB.GetAccount(caller.Address())
+ to = AccountRef(caller.Address())
)
// Iinitialise a new contract and make initialise the delegate values
- contract := NewContract(caller, to, caller.Value(), gas).AsDelegate()
+ contract := NewContract(caller, to, nil, gas).AsDelegate()
contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr))
- defer contract.Finalise()
ret, err = evm.interpreter.Run(contract, input)
if err != nil {
@@ -239,28 +217,22 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by
evm.StateDB.RevertToSnapshot(snapshot)
}
- return ret, err
+ return ret, contract.Gas, err
}
// Create creates a new contract using code as deployment code.
-func (evm *EVM) Create(caller ContractRef, code []byte, gas, value *big.Int) (ret []byte, contractAddr common.Address, err error) {
+func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *big.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) {
if evm.vmConfig.NoRecursion && evm.depth > 0 {
- caller.ReturnGas(gas)
-
- return nil, common.Address{}, nil
+ return nil, common.Address{}, gas, nil
}
// Depth check execution. Fail if we're trying to execute above the
// limit.
- if evm.depth > int(params.CallCreateDepth.Int64()) {
- caller.ReturnGas(gas)
-
- return nil, common.Address{}, ErrDepth
+ if evm.depth > int(params.CallCreateDepth) {
+ return nil, common.Address{}, gas, ErrDepth
}
if !evm.CanTransfer(evm.StateDB, caller.Address(), value) {
- caller.ReturnGas(gas)
-
- return nil, common.Address{}, ErrInsufficientBalance
+ return nil, common.Address{}, gas, ErrInsufficientBalance
}
// Create a new account on the state
@@ -269,18 +241,17 @@ func (evm *EVM) Create(caller ContractRef, code []byte, gas, value *big.Int) (re
snapshot := evm.StateDB.Snapshot()
contractAddr = crypto.CreateAddress(caller.Address(), nonce)
- to := evm.StateDB.CreateAccount(contractAddr)
+ evm.StateDB.CreateAccount(contractAddr)
if evm.ChainConfig().IsEIP158(evm.BlockNumber) {
evm.StateDB.SetNonce(contractAddr, 1)
}
- evm.Transfer(evm.StateDB, caller.Address(), to.Address(), value)
+ evm.Transfer(evm.StateDB, caller.Address(), contractAddr, value)
// initialise a new contract and set the code that is to be used by the
// E The contract is a scoped evmironment for this execution context
// only.
- contract := NewContract(caller, to, value, gas)
+ contract := NewContract(caller, AccountRef(contractAddr), value, gas)
contract.SetCallCode(&contractAddr, crypto.Keccak256Hash(code), code)
- defer contract.Finalise()
ret, err = evm.interpreter.Run(contract, nil)
@@ -291,9 +262,8 @@ func (evm *EVM) Create(caller ContractRef, code []byte, gas, value *big.Int) (re
// be stored due to not enough gas set an error and let it be handled
// by the error checking condition below.
if err == nil && !maxCodeSizeExceeded {
- dataGas := big.NewInt(int64(len(ret)))
- dataGas.Mul(dataGas, params.CreateDataGas)
- if contract.UseGas(dataGas) {
+ createDataGas := uint64(len(ret)) * params.CreateDataGas
+ if contract.UseGas(createDataGas) {
evm.StateDB.SetCode(contractAddr, ret)
} else {
err = ErrCodeStoreOutOfGas
@@ -305,11 +275,10 @@ func (evm *EVM) Create(caller ContractRef, code []byte, gas, value *big.Int) (re
// when we're in homestead this also counts for code storage gas errors.
if maxCodeSizeExceeded ||
(err != nil && (evm.ChainConfig().IsHomestead(evm.BlockNumber) || err != ErrCodeStoreOutOfGas)) {
- contract.UseGas(contract.Gas)
evm.StateDB.RevertToSnapshot(snapshot)
// Nothing should be returned when an error is thrown.
- return nil, contractAddr, err
+ return nil, contractAddr, 0, err
}
// If the vm returned with an error the return value should be set to nil.
// This isn't consensus critical but merely to for behaviour reasons such as
@@ -318,7 +287,7 @@ func (evm *EVM) Create(caller ContractRef, code []byte, gas, value *big.Int) (re
ret = nil
}
- return ret, contractAddr, err
+ return ret, contractAddr, contract.Gas, err
}
// ChainConfig returns the evmironment's chain configuration
diff --git a/core/vm/gas.go b/core/vm/gas.go
index cb225b6cac..dd64d5f178 100644
--- a/core/vm/gas.go
+++ b/core/vm/gas.go
@@ -17,149 +17,42 @@
package vm
import (
- "fmt"
"math/big"
"github.com/ethereum/go-ethereum/params"
)
-var (
- GasQuickStep = big.NewInt(2)
- GasFastestStep = big.NewInt(3)
- GasFastStep = big.NewInt(5)
- GasMidStep = big.NewInt(8)
- GasSlowStep = big.NewInt(10)
- GasExtStep = big.NewInt(20)
+const (
+ GasQuickStep uint64 = 2
+ GasFastestStep uint64 = 3
+ GasFastStep uint64 = 5
+ GasMidStep uint64 = 8
+ GasSlowStep uint64 = 10
+ GasExtStep uint64 = 20
- GasReturn = big.NewInt(0)
- GasStop = big.NewInt(0)
-
- GasContractByte = big.NewInt(200)
-
- n64 = big.NewInt(64)
+ GasReturn uint64 = 0
+ GasStop uint64 = 0
+ GasContractByte uint64 = 200
)
// calcGas returns the actual gas cost of the call.
//
// The cost of gas was changed during the homestead price change HF. To allow for EIP150
// to be implemented. The returned gas is gas - base * 63 / 64.
-func callGas(gasTable params.GasTable, availableGas, base, callCost *big.Int) *big.Int {
- if gasTable.CreateBySuicide != nil {
- availableGas = new(big.Int).Sub(availableGas, base)
- g := new(big.Int).Div(availableGas, n64)
- g.Sub(availableGas, g)
-
- if g.Cmp(callCost) < 0 {
- return g
+func callGas(gasTable params.GasTable, availableGas, base uint64, callCost *big.Int) (uint64, error) {
+ if gasTable.CreateBySuicide > 0 {
+ availableGas = availableGas - base
+ gas := availableGas - availableGas/64
+ // If the bit length exceeds 64 bit we know that the newly calculated "gas" for EIP150
+ // is smaller than the requested amount. Therefor we return the new gas instead
+ // of returning an error.
+ if callCost.BitLen() > 64 || gas < callCost.Uint64() {
+ return gas, nil
}
}
- return callCost
-}
-
-// baseCheck checks for any stack error underflows
-func baseCheck(op OpCode, stack *Stack, gas *big.Int) error {
- // PUSH and DUP are a bit special. They all cost the same but we do want to have checking on stack push limit
- // PUSH is also allowed to calculate the same price for all PUSHes
- // DUP requirements are handled elsewhere (except for the stack limit check)
- if op >= PUSH1 && op <= PUSH32 {
- op = PUSH1
- }
- if op >= DUP1 && op <= DUP16 {
- op = DUP1
+ if callCost.BitLen() > 64 {
+ return 0, errGasUintOverflow
}
- if r, ok := _baseCheck[op]; ok {
- err := stack.require(r.stackPop)
- if err != nil {
- return err
- }
-
- if r.stackPush > 0 && stack.len()-r.stackPop+r.stackPush > int(params.StackLimit.Int64()) {
- return fmt.Errorf("stack limit reached %d (%d)", stack.len(), params.StackLimit.Int64())
- }
-
- gas.Add(gas, r.gas)
- }
- return nil
-}
-
-// casts a arbitrary number to the amount of words (sets of 32 bytes)
-func toWordSize(size *big.Int) *big.Int {
- tmp := new(big.Int)
- tmp.Add(size, u256(31))
- tmp.Div(tmp, u256(32))
- return tmp
-}
-
-type req struct {
- stackPop int
- gas *big.Int
- stackPush int
-}
-
-var _baseCheck = map[OpCode]req{
- // opcode | stack pop | gas price | stack push
- ADD: {2, GasFastestStep, 1},
- LT: {2, GasFastestStep, 1},
- GT: {2, GasFastestStep, 1},
- SLT: {2, GasFastestStep, 1},
- SGT: {2, GasFastestStep, 1},
- EQ: {2, GasFastestStep, 1},
- ISZERO: {1, GasFastestStep, 1},
- SUB: {2, GasFastestStep, 1},
- AND: {2, GasFastestStep, 1},
- OR: {2, GasFastestStep, 1},
- XOR: {2, GasFastestStep, 1},
- NOT: {1, GasFastestStep, 1},
- BYTE: {2, GasFastestStep, 1},
- CALLDATALOAD: {1, GasFastestStep, 1},
- CALLDATACOPY: {3, GasFastestStep, 1},
- MLOAD: {1, GasFastestStep, 1},
- MSTORE: {2, GasFastestStep, 0},
- MSTORE8: {2, GasFastestStep, 0},
- CODECOPY: {3, GasFastestStep, 0},
- MUL: {2, GasFastStep, 1},
- DIV: {2, GasFastStep, 1},
- SDIV: {2, GasFastStep, 1},
- MOD: {2, GasFastStep, 1},
- SMOD: {2, GasFastStep, 1},
- SIGNEXTEND: {2, GasFastStep, 1},
- ADDMOD: {3, GasMidStep, 1},
- MULMOD: {3, GasMidStep, 1},
- JUMP: {1, GasMidStep, 0},
- JUMPI: {2, GasSlowStep, 0},
- EXP: {2, GasSlowStep, 1},
- ADDRESS: {0, GasQuickStep, 1},
- ORIGIN: {0, GasQuickStep, 1},
- CALLER: {0, GasQuickStep, 1},
- CALLVALUE: {0, GasQuickStep, 1},
- CODESIZE: {0, GasQuickStep, 1},
- GASPRICE: {0, GasQuickStep, 1},
- COINBASE: {0, GasQuickStep, 1},
- TIMESTAMP: {0, GasQuickStep, 1},
- NUMBER: {0, GasQuickStep, 1},
- CALLDATASIZE: {0, GasQuickStep, 1},
- DIFFICULTY: {0, GasQuickStep, 1},
- GASLIMIT: {0, GasQuickStep, 1},
- POP: {1, GasQuickStep, 0},
- PC: {0, GasQuickStep, 1},
- MSIZE: {0, GasQuickStep, 1},
- GAS: {0, GasQuickStep, 1},
- BLOCKHASH: {1, GasExtStep, 1},
- BALANCE: {1, Zero, 1},
- EXTCODESIZE: {1, Zero, 1},
- EXTCODECOPY: {4, Zero, 0},
- SLOAD: {1, params.SloadGas, 1},
- SSTORE: {2, Zero, 0},
- SHA3: {2, params.Sha3Gas, 1},
- CREATE: {3, params.CreateGas, 1},
- // Zero is calculated in the gasSwitch
- CALL: {7, Zero, 1},
- CALLCODE: {7, Zero, 1},
- DELEGATECALL: {6, Zero, 1},
- SELFDESTRUCT: {1, Zero, 0},
- JUMPDEST: {0, params.JumpdestGas, 0},
- RETURN: {2, Zero, 0},
- PUSH1: {0, GasFastestStep, 1},
- DUP1: {0, Zero, 1},
+ return callCost.Uint64(), nil
}
diff --git a/core/vm/gas_table.go b/core/vm/gas_table.go
index 4d2c4e94ae..f1c62df8e7 100644
--- a/core/vm/gas_table.go
+++ b/core/vm/gas_table.go
@@ -1,56 +1,80 @@
package vm
import (
+ gmath "math"
"math/big"
"github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/params"
)
-func memoryGasCost(mem *Memory, newMemSize *big.Int) *big.Int {
- gas := new(big.Int)
- if newMemSize.Cmp(common.Big0) > 0 {
- newMemSizeWords := toWordSize(newMemSize)
-
- if newMemSize.Cmp(u256(int64(mem.Len()))) > 0 {
- // be careful reusing variables here when changing.
- // The order has been optimised to reduce allocation
- oldSize := toWordSize(big.NewInt(int64(mem.Len())))
- pow := new(big.Int).Exp(oldSize, common.Big2, Zero)
- linCoef := oldSize.Mul(oldSize, params.MemoryGas)
- quadCoef := new(big.Int).Div(pow, params.QuadCoeffDiv)
- oldTotalFee := new(big.Int).Add(linCoef, quadCoef)
-
- pow.Exp(newMemSizeWords, common.Big2, Zero)
- linCoef = linCoef.Mul(newMemSizeWords, params.MemoryGas)
- quadCoef = quadCoef.Div(pow, params.QuadCoeffDiv)
- newTotalFee := linCoef.Add(linCoef, quadCoef)
-
- fee := newTotalFee.Sub(newTotalFee, oldTotalFee)
- gas.Add(gas, fee)
- }
+// memoryGasCosts calculates the quadratic gas for memory expansion. It does so
+// only for the memory region that is expanded, not the total memory.
+func memoryGasCost(mem *Memory, newMemSize uint64) (uint64, error) {
+ // The maximum that will fit in a uint64 is max_word_count - 1
+ // anything above that will result in an overflow.
+ if newMemSize > gmath.MaxUint64-32 {
+ return 0, errGasUintOverflow
}
- return gas
+
+ if newMemSize == 0 {
+ return 0, nil
+ }
+
+ newMemSizeWords := toWordSize(newMemSize)
+ newMemSize = newMemSizeWords * 32
+
+ if newMemSize > uint64(mem.Len()) {
+ square := newMemSizeWords * newMemSizeWords
+ linCoef := newMemSizeWords * params.MemoryGas
+ quadCoef := square / params.QuadCoeffDiv
+ newTotalFee := linCoef + quadCoef
+
+ fee := newTotalFee - mem.lastGasCost
+ mem.lastGasCost = newTotalFee
+
+ return fee, nil
+ }
+ return 0, nil
}
-func constGasFunc(gas *big.Int) gasFunc {
- return func(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
- return gas
+func constGasFunc(gas uint64) gasFunc {
+ return func(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
+ return gas, nil
}
}
-func gasCalldataCopy(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
- gas := memoryGasCost(mem, memorySize)
- gas.Add(gas, GasFastestStep)
- words := toWordSize(stack.Back(2))
+func gasCalldataCopy(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
+ gas, err := memoryGasCost(mem, memorySize)
+ if err != nil {
+ return 0, err
+ }
- return gas.Add(gas, words.Mul(words, params.CopyGas))
+ var overflow bool
+ if gas, overflow = math.SafeAdd(gas, GasFastestStep); overflow {
+ return 0, errGasUintOverflow
+ }
+
+ words, overflow := bigUint64(stack.Back(2))
+ if overflow {
+ return 0, errGasUintOverflow
+ }
+
+ if words, overflow = math.SafeMul(toWordSize(words), params.CopyGas); overflow {
+ return 0, errGasUintOverflow
+ }
+
+ if gas, overflow = math.SafeAdd(gas, words); overflow {
+ return 0, errGasUintOverflow
+ }
+ return gas, nil
}
-func gasSStore(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
+func gasSStore(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
var (
y, x = stack.Back(1), stack.Back(0)
- val = env.StateDB.GetState(contract.Address(), common.BigToHash(x))
+ val = evm.StateDB.GetState(contract.Address(), common.BigToHash(x))
)
// This checks for 3 scenario's and calculates gas accordingly
// 1. From a zero-value address to a non-zero value (NEW VALUE)
@@ -58,189 +82,335 @@ func gasSStore(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, m
// 3. From a non-zero to a non-zero (CHANGE)
if common.EmptyHash(val) && !common.EmptyHash(common.BigToHash(y)) {
// 0 => non 0
- return new(big.Int).Set(params.SstoreSetGas)
+ return params.SstoreSetGas, nil
} else if !common.EmptyHash(val) && common.EmptyHash(common.BigToHash(y)) {
- env.StateDB.AddRefund(params.SstoreRefundGas)
+ evm.StateDB.AddRefund(new(big.Int).SetUint64(params.SstoreRefundGas))
- return new(big.Int).Set(params.SstoreClearGas)
+ return params.SstoreClearGas, nil
} else {
// non 0 => non 0 (or 0 => 0)
- return new(big.Int).Set(params.SstoreResetGas)
+ return params.SstoreResetGas, nil
}
}
-func makeGasLog(n uint) gasFunc {
- return func(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
- mSize := stack.Back(1)
+func makeGasLog(n uint64) gasFunc {
+ return func(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
+ requestedSize, overflow := bigUint64(stack.Back(1))
+ if overflow {
+ return 0, errGasUintOverflow
+ }
- gas := new(big.Int).Add(memoryGasCost(mem, memorySize), params.LogGas)
- gas.Add(gas, new(big.Int).Mul(big.NewInt(int64(n)), params.LogTopicGas))
- gas.Add(gas, new(big.Int).Mul(mSize, params.LogDataGas))
- return gas
+ gas, err := memoryGasCost(mem, memorySize)
+ if err != nil {
+ return 0, err
+ }
+
+ if gas, overflow = math.SafeAdd(gas, params.LogGas); overflow {
+ return 0, errGasUintOverflow
+ }
+ if gas, overflow = math.SafeAdd(gas, n*params.LogTopicGas); overflow {
+ return 0, errGasUintOverflow
+ }
+
+ var memorySizeGas uint64
+ if memorySizeGas, overflow = math.SafeMul(requestedSize, params.LogDataGas); overflow {
+ return 0, errGasUintOverflow
+ }
+ if gas, overflow = math.SafeAdd(gas, memorySizeGas); overflow {
+ return 0, errGasUintOverflow
+ }
+ return gas, nil
}
}
-func gasSha3(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
- gas := memoryGasCost(mem, memorySize)
- gas.Add(gas, params.Sha3Gas)
- words := toWordSize(stack.Back(1))
- return gas.Add(gas, words.Mul(words, params.Sha3WordGas))
+func gasSha3(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
+ var overflow bool
+ gas, err := memoryGasCost(mem, memorySize)
+ if err != nil {
+ return 0, err
+ }
+
+ if gas, overflow = math.SafeAdd(gas, params.Sha3Gas); overflow {
+ return 0, errGasUintOverflow
+ }
+
+ wordGas, overflow := bigUint64(stack.Back(1))
+ if overflow {
+ return 0, errGasUintOverflow
+ }
+ if wordGas, overflow = math.SafeMul(toWordSize(wordGas), params.Sha3WordGas); overflow {
+ return 0, errGasUintOverflow
+ }
+ if gas, overflow = math.SafeAdd(gas, wordGas); overflow {
+ return 0, errGasUintOverflow
+ }
+ return gas, nil
}
-func gasCodeCopy(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
- gas := memoryGasCost(mem, memorySize)
- gas.Add(gas, GasFastestStep)
- words := toWordSize(stack.Back(2))
+func gasCodeCopy(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
+ gas, err := memoryGasCost(mem, memorySize)
+ if err != nil {
+ return 0, err
+ }
- return gas.Add(gas, words.Mul(words, params.CopyGas))
+ var overflow bool
+ if gas, overflow = math.SafeAdd(gas, GasFastestStep); overflow {
+ return 0, errGasUintOverflow
+ }
+
+ wordGas, overflow := bigUint64(stack.Back(2))
+ if overflow {
+ return 0, errGasUintOverflow
+ }
+ if wordGas, overflow = math.SafeMul(toWordSize(wordGas), params.CopyGas); overflow {
+ return 0, errGasUintOverflow
+ }
+ if gas, overflow = math.SafeAdd(gas, wordGas); overflow {
+ return 0, errGasUintOverflow
+ }
+ return gas, nil
}
-func gasExtCodeCopy(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
- gas := memoryGasCost(mem, memorySize)
- gas.Add(gas, gt.ExtcodeCopy)
- words := toWordSize(stack.Back(3))
+func gasExtCodeCopy(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
+ gas, err := memoryGasCost(mem, memorySize)
+ if err != nil {
+ return 0, err
+ }
- return gas.Add(gas, words.Mul(words, params.CopyGas))
+ var overflow bool
+ if gas, overflow = math.SafeAdd(gas, gt.ExtcodeCopy); overflow {
+ return 0, errGasUintOverflow
+ }
+
+ wordGas, overflow := bigUint64(stack.Back(3))
+ if overflow {
+ return 0, errGasUintOverflow
+ }
+
+ if wordGas, overflow = math.SafeMul(toWordSize(wordGas), params.CopyGas); overflow {
+ return 0, errGasUintOverflow
+ }
+
+ if gas, overflow = math.SafeAdd(gas, wordGas); overflow {
+ return 0, errGasUintOverflow
+ }
+ return gas, nil
}
-func gasMLoad(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
- return new(big.Int).Add(GasFastestStep, memoryGasCost(mem, memorySize))
+func gasMLoad(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
+ var overflow bool
+ gas, err := memoryGasCost(mem, memorySize)
+ if err != nil {
+ return 0, errGasUintOverflow
+ }
+ if gas, overflow = math.SafeAdd(gas, GasFastestStep); overflow {
+ return 0, errGasUintOverflow
+ }
+ return gas, nil
}
-func gasMStore8(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
- return new(big.Int).Add(GasFastestStep, memoryGasCost(mem, memorySize))
+func gasMStore8(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
+ var overflow bool
+ gas, err := memoryGasCost(mem, memorySize)
+ if err != nil {
+ return 0, errGasUintOverflow
+ }
+ if gas, overflow = math.SafeAdd(gas, GasFastestStep); overflow {
+ return 0, errGasUintOverflow
+ }
+ return gas, nil
}
-func gasMStore(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
- return new(big.Int).Add(GasFastestStep, memoryGasCost(mem, memorySize))
+func gasMStore(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
+ var overflow bool
+ gas, err := memoryGasCost(mem, memorySize)
+ if err != nil {
+ return 0, errGasUintOverflow
+ }
+ if gas, overflow = math.SafeAdd(gas, GasFastestStep); overflow {
+ return 0, errGasUintOverflow
+ }
+ return gas, nil
}
-func gasCreate(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
- return new(big.Int).Add(params.CreateGas, memoryGasCost(mem, memorySize))
+func gasCreate(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
+ var overflow bool
+ gas, err := memoryGasCost(mem, memorySize)
+ if err != nil {
+ return 0, err
+ }
+ if gas, overflow = math.SafeAdd(gas, params.CreateGas); overflow {
+ return 0, errGasUintOverflow
+ }
+ return gas, nil
}
-func gasBalance(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
- return gt.Balance
+func gasBalance(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
+ return gt.Balance, nil
}
-func gasExtCodeSize(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
- return gt.ExtcodeSize
+func gasExtCodeSize(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
+ return gt.ExtcodeSize, nil
}
-func gasSLoad(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
- return gt.SLoad
+func gasSLoad(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
+ return gt.SLoad, nil
}
-func gasExp(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
- expByteLen := int64((stack.data[stack.len()-2].BitLen() + 7) / 8)
- gas := big.NewInt(expByteLen)
- gas.Mul(gas, gt.ExpByte)
- return gas.Add(gas, GasSlowStep)
-}
+func gasExp(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
+ expByteLen := uint64((stack.data[stack.len()-2].BitLen() + 7) / 8)
-func gasCall(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
- gas := new(big.Int).Set(gt.Calls)
-
- transfersValue := stack.Back(2).BitLen() > 0
var (
- address = common.BigToAddress(stack.Back(1))
- eip158 = env.ChainConfig().IsEIP158(env.BlockNumber)
+ gas = expByteLen * gt.ExpByte // no overflow check required. Max is 256 * ExpByte gas
+ overflow bool
+ )
+ if gas, overflow = math.SafeAdd(gas, GasSlowStep); overflow {
+ return 0, errGasUintOverflow
+ }
+ return gas, nil
+}
+
+func gasCall(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
+ var (
+ gas = gt.Calls
+ transfersValue = stack.Back(2).Sign() != 0
+ address = common.BigToAddress(stack.Back(1))
+ eip158 = evm.ChainConfig().IsEIP158(evm.BlockNumber)
)
if eip158 {
- if env.StateDB.Empty(address) && transfersValue {
- gas.Add(gas, params.CallNewAccountGas)
+ if evm.StateDB.Empty(address) && transfersValue {
+ gas += params.CallNewAccountGas
}
- } else if !env.StateDB.Exist(address) {
- gas.Add(gas, params.CallNewAccountGas)
+ } else if !evm.StateDB.Exist(address) {
+ gas += params.CallNewAccountGas
}
if transfersValue {
- gas.Add(gas, params.CallValueTransferGas)
+ gas += params.CallValueTransferGas
+ }
+ memoryGas, err := memoryGasCost(mem, memorySize)
+ if err != nil {
+ return 0, err
+ }
+ var overflow bool
+ if gas, overflow = math.SafeAdd(gas, memoryGas); overflow {
+ return 0, errGasUintOverflow
}
- gas.Add(gas, memoryGasCost(mem, memorySize))
- cg := callGas(gt, contract.Gas, gas, stack.data[stack.len()-1])
+ cg, err := callGas(gt, contract.Gas, gas, stack.Back(0))
+ if err != nil {
+ return 0, err
+ }
// Replace the stack item with the new gas calculation. This means that
// either the original item is left on the stack or the item is replaced by:
// (availableGas - gas) * 63 / 64
// We replace the stack item so that it's available when the opCall instruction is
// called. This information is otherwise lost due to the dependency on *current*
// available gas.
- stack.data[stack.len()-1] = cg
+ stack.data[stack.len()-1] = new(big.Int).SetUint64(cg)
- return gas.Add(gas, cg)
+ if gas, overflow = math.SafeAdd(gas, cg); overflow {
+ return 0, errGasUintOverflow
+ }
+ return gas, nil
}
-func gasCallCode(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
- gas := new(big.Int).Set(gt.Calls)
- if stack.Back(2).BitLen() > 0 {
- gas.Add(gas, params.CallValueTransferGas)
+func gasCallCode(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
+ gas := gt.Calls
+ if stack.Back(2).Sign() != 0 {
+ gas += params.CallValueTransferGas
+ }
+ memoryGas, err := memoryGasCost(mem, memorySize)
+ if err != nil {
+ return 0, err
+ }
+ var overflow bool
+ if gas, overflow = math.SafeAdd(gas, memoryGas); overflow {
+ return 0, errGasUintOverflow
}
- gas.Add(gas, memoryGasCost(mem, memorySize))
- cg := callGas(gt, contract.Gas, gas, stack.data[stack.len()-1])
+ cg, err := callGas(gt, contract.Gas, gas, stack.Back(0))
+ if err != nil {
+ return 0, err
+ }
// Replace the stack item with the new gas calculation. This means that
// either the original item is left on the stack or the item is replaced by:
// (availableGas - gas) * 63 / 64
// We replace the stack item so that it's available when the opCall instruction is
// called. This information is otherwise lost due to the dependency on *current*
// available gas.
- stack.data[stack.len()-1] = cg
+ stack.data[stack.len()-1] = new(big.Int).SetUint64(cg)
- return gas.Add(gas, cg)
+ if gas, overflow = math.SafeAdd(gas, cg); overflow {
+ return 0, errGasUintOverflow
+ }
+ return gas, nil
}
-func gasReturn(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
+func gasReturn(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
return memoryGasCost(mem, memorySize)
}
-func gasSuicide(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
- gas := new(big.Int)
+func gasSuicide(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
+ var gas uint64
// EIP150 homestead gas reprice fork:
- if env.ChainConfig().IsEIP150(env.BlockNumber) {
- gas.Set(gt.Suicide)
+ if evm.ChainConfig().IsEIP150(evm.BlockNumber) {
+ gas = gt.Suicide
var (
address = common.BigToAddress(stack.Back(0))
- eip158 = env.ChainConfig().IsEIP158(env.BlockNumber)
+ eip158 = evm.ChainConfig().IsEIP158(evm.BlockNumber)
)
if eip158 {
// if empty and transfers value
- if env.StateDB.Empty(address) && env.StateDB.GetBalance(contract.Address()).BitLen() > 0 {
- gas.Add(gas, gt.CreateBySuicide)
+ if evm.StateDB.Empty(address) && evm.StateDB.GetBalance(contract.Address()).Sign() != 0 {
+ gas += gt.CreateBySuicide
}
- } else if !env.StateDB.Exist(address) {
- gas.Add(gas, gt.CreateBySuicide)
+ } else if !evm.StateDB.Exist(address) {
+ gas += gt.CreateBySuicide
}
}
- if !env.StateDB.HasSuicided(contract.Address()) {
- env.StateDB.AddRefund(params.SuicideRefundGas)
+ if !evm.StateDB.HasSuicided(contract.Address()) {
+ evm.StateDB.AddRefund(new(big.Int).SetUint64(params.SuicideRefundGas))
}
- return gas
+ return gas, nil
}
-func gasDelegateCall(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
- gas := new(big.Int).Add(gt.Calls, memoryGasCost(mem, memorySize))
+func gasDelegateCall(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
+ gas, err := memoryGasCost(mem, memorySize)
+ if err != nil {
+ return 0, err
+ }
+ var overflow bool
+ if gas, overflow = math.SafeAdd(gas, gt.Calls); overflow {
+ return 0, errGasUintOverflow
+ }
- cg := callGas(gt, contract.Gas, gas, stack.data[stack.len()-1])
+ cg, err := callGas(gt, contract.Gas, gas, stack.Back(0))
+ if err != nil {
+ return 0, err
+ }
// Replace the stack item with the new gas calculation. This means that
// either the original item is left on the stack or the item is replaced by:
// (availableGas - gas) * 63 / 64
// We replace the stack item so that it's available when the opCall instruction is
// called.
- stack.data[stack.len()-1] = cg
+ stack.data[stack.len()-1] = new(big.Int).SetUint64(cg)
- return gas.Add(gas, cg)
+ if gas, overflow = math.SafeAdd(gas, cg); overflow {
+ return 0, errGasUintOverflow
+ }
+ return gas, nil
}
-func gasPush(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
- return GasFastestStep
+func gasPush(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
+ return GasFastestStep, nil
}
-func gasSwap(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
- return GasFastestStep
+func gasSwap(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
+ return GasFastestStep, nil
}
-func gasDup(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
- return GasFastestStep
+func gasDup(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
+ return GasFastestStep, nil
}
diff --git a/core/vm/gas_table_test.go b/core/vm/gas_table_test.go
new file mode 100644
index 0000000000..cceb892859
--- /dev/null
+++ b/core/vm/gas_table_test.go
@@ -0,0 +1,24 @@
+package vm
+
+import (
+ "math"
+ "testing"
+)
+
+func TestMemoryGasCost(t *testing.T) {
+ size := uint64(math.MaxUint64 - 64)
+ _, err := memoryGasCost(&Memory{}, size)
+ if err != nil {
+ t.Error("didn't expect error:", err)
+ }
+
+ _, err = memoryGasCost(&Memory{}, size+32)
+ if err != nil {
+ t.Error("didn't expect error:", err)
+ }
+
+ _, err = memoryGasCost(&Memory{}, size+33)
+ if err == nil {
+ t.Error("expected error")
+ }
+}
diff --git a/core/vm/instructions.go b/core/vm/instructions.go
index 3b1b06cca1..bfc0a668e4 100644
--- a/core/vm/instructions.go
+++ b/core/vm/instructions.go
@@ -27,42 +27,56 @@ import (
"github.com/ethereum/go-ethereum/params"
)
-func opAdd(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+var bigZero = new(big.Int)
+
+func opAdd(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
x, y := stack.pop(), stack.pop()
- stack.push(U256(x.Add(x, y)))
+ stack.push(math.U256(x.Add(x, y)))
+
+ evm.interpreter.intPool.put(y)
+
return nil, nil
}
-func opSub(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+func opSub(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
x, y := stack.pop(), stack.pop()
- stack.push(U256(x.Sub(x, y)))
+ stack.push(math.U256(x.Sub(x, y)))
+
+ evm.interpreter.intPool.put(y)
+
return nil, nil
}
-func opMul(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+func opMul(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
x, y := stack.pop(), stack.pop()
- stack.push(U256(x.Mul(x, y)))
+ stack.push(math.U256(x.Mul(x, y)))
+
+ evm.interpreter.intPool.put(y)
+
return nil, nil
}
-func opDiv(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+func opDiv(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
x, y := stack.pop(), stack.pop()
- if y.Cmp(common.Big0) != 0 {
- stack.push(U256(x.Div(x, y)))
+ if y.Sign() != 0 {
+ stack.push(math.U256(x.Div(x, y)))
} else {
stack.push(new(big.Int))
}
+
+ evm.interpreter.intPool.put(y)
+
return nil, nil
}
-func opSdiv(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
- x, y := S256(stack.pop()), S256(stack.pop())
- if y.Cmp(common.Big0) == 0 {
+func opSdiv(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+ x, y := math.S256(stack.pop()), math.S256(stack.pop())
+ if y.Sign() == 0 {
stack.push(new(big.Int))
return nil, nil
} else {
n := new(big.Int)
- if new(big.Int).Mul(x, y).Cmp(common.Big0) < 0 {
+ if evm.interpreter.intPool.get().Mul(x, y).Sign() < 0 {
n.SetInt64(-1)
} else {
n.SetInt64(1)
@@ -71,29 +85,31 @@ func opSdiv(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Sta
res := x.Div(x.Abs(x), y.Abs(y))
res.Mul(res, n)
- stack.push(U256(res))
+ stack.push(math.U256(res))
}
+ evm.interpreter.intPool.put(y)
return nil, nil
}
-func opMod(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+func opMod(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
x, y := stack.pop(), stack.pop()
- if y.Cmp(common.Big0) == 0 {
+ if y.Sign() == 0 {
stack.push(new(big.Int))
} else {
- stack.push(U256(x.Mod(x, y)))
+ stack.push(math.U256(x.Mod(x, y)))
}
+ evm.interpreter.intPool.put(y)
return nil, nil
}
-func opSmod(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
- x, y := S256(stack.pop()), S256(stack.pop())
+func opSmod(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+ x, y := math.S256(stack.pop()), math.S256(stack.pop())
- if y.Cmp(common.Big0) == 0 {
+ if y.Sign() == 0 {
stack.push(new(big.Int))
} else {
n := new(big.Int)
- if x.Cmp(common.Big0) < 0 {
+ if x.Sign() < 0 {
n.SetInt64(-1)
} else {
n.SetInt64(1)
@@ -102,224 +118,262 @@ func opSmod(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Sta
res := x.Mod(x.Abs(x), y.Abs(y))
res.Mul(res, n)
- stack.push(U256(res))
+ stack.push(math.U256(res))
}
+ evm.interpreter.intPool.put(y)
return nil, nil
}
-func opExp(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+func opExp(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
base, exponent := stack.pop(), stack.pop()
stack.push(math.Exp(base, exponent))
+
+ evm.interpreter.intPool.put(base, exponent)
+
return nil, nil
}
-func opSignExtend(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+func opSignExtend(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
back := stack.pop()
if back.Cmp(big.NewInt(31)) < 0 {
bit := uint(back.Uint64()*8 + 7)
num := stack.pop()
mask := back.Lsh(common.Big1, bit)
mask.Sub(mask, common.Big1)
- if common.BitTest(num, int(bit)) {
+ if num.Bit(int(bit)) > 0 {
num.Or(num, mask.Not(mask))
} else {
num.And(num, mask)
}
- stack.push(U256(num))
+ stack.push(math.U256(num))
}
+
+ evm.interpreter.intPool.put(back)
return nil, nil
}
-func opNot(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+func opNot(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
x := stack.pop()
- stack.push(U256(x.Not(x)))
+ stack.push(math.U256(x.Not(x)))
return nil, nil
}
-func opLt(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+func opLt(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
x, y := stack.pop(), stack.pop()
if x.Cmp(y) < 0 {
- stack.push(big.NewInt(1))
+ stack.push(evm.interpreter.intPool.get().SetUint64(1))
} else {
stack.push(new(big.Int))
}
+
+ evm.interpreter.intPool.put(x, y)
return nil, nil
}
-func opGt(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+func opGt(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
x, y := stack.pop(), stack.pop()
if x.Cmp(y) > 0 {
- stack.push(big.NewInt(1))
+ stack.push(evm.interpreter.intPool.get().SetUint64(1))
} else {
stack.push(new(big.Int))
}
+
+ evm.interpreter.intPool.put(x, y)
return nil, nil
}
-func opSlt(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
- x, y := S256(stack.pop()), S256(stack.pop())
- if x.Cmp(S256(y)) < 0 {
- stack.push(big.NewInt(1))
+func opSlt(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+ x, y := math.S256(stack.pop()), math.S256(stack.pop())
+ if x.Cmp(math.S256(y)) < 0 {
+ stack.push(evm.interpreter.intPool.get().SetUint64(1))
} else {
stack.push(new(big.Int))
}
+
+ evm.interpreter.intPool.put(x, y)
return nil, nil
}
-func opSgt(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
- x, y := S256(stack.pop()), S256(stack.pop())
+func opSgt(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+ x, y := math.S256(stack.pop()), math.S256(stack.pop())
if x.Cmp(y) > 0 {
- stack.push(big.NewInt(1))
+ stack.push(evm.interpreter.intPool.get().SetUint64(1))
} else {
stack.push(new(big.Int))
}
+
+ evm.interpreter.intPool.put(x, y)
return nil, nil
}
-func opEq(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+func opEq(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
x, y := stack.pop(), stack.pop()
if x.Cmp(y) == 0 {
- stack.push(big.NewInt(1))
+ stack.push(evm.interpreter.intPool.get().SetUint64(1))
} else {
stack.push(new(big.Int))
}
+
+ evm.interpreter.intPool.put(x, y)
return nil, nil
}
-func opIszero(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+func opIszero(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
x := stack.pop()
- if x.Cmp(common.Big0) > 0 {
+ if x.Sign() > 0 {
stack.push(new(big.Int))
} else {
- stack.push(big.NewInt(1))
+ stack.push(evm.interpreter.intPool.get().SetUint64(1))
}
+
+ evm.interpreter.intPool.put(x)
return nil, nil
}
-func opAnd(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+func opAnd(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
x, y := stack.pop(), stack.pop()
stack.push(x.And(x, y))
+
+ evm.interpreter.intPool.put(y)
return nil, nil
}
-func opOr(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+func opOr(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
x, y := stack.pop(), stack.pop()
stack.push(x.Or(x, y))
+
+ evm.interpreter.intPool.put(y)
return nil, nil
}
-func opXor(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+func opXor(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
x, y := stack.pop(), stack.pop()
stack.push(x.Xor(x, y))
+
+ evm.interpreter.intPool.put(y)
return nil, nil
}
-func opByte(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+
+func opByte(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
th, val := stack.pop(), stack.pop()
if th.Cmp(big.NewInt(32)) < 0 {
- byte := big.NewInt(int64(common.LeftPadBytes(val.Bytes(), 32)[th.Int64()]))
+ byte := evm.interpreter.intPool.get().SetInt64(int64(math.PaddedBigBytes(val, 32)[th.Int64()]))
stack.push(byte)
} else {
stack.push(new(big.Int))
}
+
+ evm.interpreter.intPool.put(th, val)
return nil, nil
}
-func opAddmod(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+func opAddmod(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
x, y, z := stack.pop(), stack.pop(), stack.pop()
- if z.Cmp(Zero) > 0 {
+ if z.Cmp(bigZero) > 0 {
add := x.Add(x, y)
add.Mod(add, z)
- stack.push(U256(add))
+ stack.push(math.U256(add))
} else {
stack.push(new(big.Int))
}
+
+ evm.interpreter.intPool.put(y, z)
return nil, nil
}
-func opMulmod(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+func opMulmod(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
x, y, z := stack.pop(), stack.pop(), stack.pop()
- if z.Cmp(Zero) > 0 {
+ if z.Cmp(bigZero) > 0 {
mul := x.Mul(x, y)
mul.Mod(mul, z)
- stack.push(U256(mul))
+ stack.push(math.U256(mul))
} else {
stack.push(new(big.Int))
}
+
+ evm.interpreter.intPool.put(y, z)
return nil, nil
}
-func opSha3(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+func opSha3(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
offset, size := stack.pop(), stack.pop()
data := memory.Get(offset.Int64(), size.Int64())
hash := crypto.Keccak256(data)
- if env.vmConfig.EnablePreimageRecording {
- env.StateDB.AddPreimage(common.BytesToHash(hash), data)
+ if evm.vmConfig.EnablePreimageRecording {
+ evm.StateDB.AddPreimage(common.BytesToHash(hash), data)
}
- stack.push(common.BytesToBig(hash))
+ stack.push(new(big.Int).SetBytes(hash))
+
+ evm.interpreter.intPool.put(offset, size)
return nil, nil
}
-func opAddress(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
- stack.push(common.Bytes2Big(contract.Address().Bytes()))
+func opAddress(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+ stack.push(contract.Address().Big())
return nil, nil
}
-func opBalance(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+func opBalance(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
addr := common.BigToAddress(stack.pop())
- balance := env.StateDB.GetBalance(addr)
+ balance := evm.StateDB.GetBalance(addr)
stack.push(new(big.Int).Set(balance))
return nil, nil
}
-func opOrigin(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
- stack.push(env.Origin.Big())
+func opOrigin(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+ stack.push(evm.Origin.Big())
return nil, nil
}
-func opCaller(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+func opCaller(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
stack.push(contract.Caller().Big())
return nil, nil
}
-func opCallValue(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
- stack.push(new(big.Int).Set(contract.value))
+func opCallValue(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+ stack.push(evm.interpreter.intPool.get().Set(contract.value))
return nil, nil
}
-func opCalldataLoad(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
- stack.push(common.Bytes2Big(getData(contract.Input, stack.pop(), common.Big32)))
+func opCalldataLoad(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+ stack.push(new(big.Int).SetBytes(getData(contract.Input, stack.pop(), common.Big32)))
return nil, nil
}
-func opCalldataSize(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
- stack.push(big.NewInt(int64(len(contract.Input))))
+func opCalldataSize(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+ stack.push(evm.interpreter.intPool.get().SetInt64(int64(len(contract.Input))))
return nil, nil
}
-func opCalldataCopy(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+func opCalldataCopy(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
var (
mOff = stack.pop()
cOff = stack.pop()
l = stack.pop()
)
memory.Set(mOff.Uint64(), l.Uint64(), getData(contract.Input, cOff, l))
+
+ evm.interpreter.intPool.put(mOff, cOff, l)
return nil, nil
}
-func opExtCodeSize(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
- addr := common.BigToAddress(stack.pop())
- l := big.NewInt(int64(env.StateDB.GetCodeSize(addr)))
+func opExtCodeSize(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+ a := stack.pop()
+
+ addr := common.BigToAddress(a)
+ a.SetInt64(int64(evm.StateDB.GetCodeSize(addr)))
+ stack.push(a)
+
+ return nil, nil
+}
+
+func opCodeSize(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+ l := evm.interpreter.intPool.get().SetInt64(int64(len(contract.Code)))
stack.push(l)
return nil, nil
}
-func opCodeSize(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
- l := big.NewInt(int64(len(contract.Code)))
- stack.push(l)
- return nil, nil
-}
-
-func opCodeCopy(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+func opCodeCopy(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
var (
mOff = stack.pop()
cOff = stack.pop()
@@ -328,115 +382,131 @@ func opCodeCopy(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack
codeCopy := getData(contract.Code, cOff, l)
memory.Set(mOff.Uint64(), l.Uint64(), codeCopy)
+
+ evm.interpreter.intPool.put(mOff, cOff, l)
return nil, nil
}
-func opExtCodeCopy(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+func opExtCodeCopy(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
var (
addr = common.BigToAddress(stack.pop())
mOff = stack.pop()
cOff = stack.pop()
l = stack.pop()
)
- codeCopy := getData(env.StateDB.GetCode(addr), cOff, l)
+ codeCopy := getData(evm.StateDB.GetCode(addr), cOff, l)
memory.Set(mOff.Uint64(), l.Uint64(), codeCopy)
+
+ evm.interpreter.intPool.put(mOff, cOff, l)
+
return nil, nil
}
-func opGasprice(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
- stack.push(new(big.Int).Set(env.GasPrice))
+func opGasprice(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+ stack.push(evm.interpreter.intPool.get().Set(evm.GasPrice))
return nil, nil
}
-func opBlockhash(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+func opBlockhash(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
num := stack.pop()
- n := new(big.Int).Sub(env.BlockNumber, common.Big257)
- if num.Cmp(n) > 0 && num.Cmp(env.BlockNumber) < 0 {
- stack.push(env.GetHash(num.Uint64()).Big())
+ n := evm.interpreter.intPool.get().Sub(evm.BlockNumber, common.Big257)
+ if num.Cmp(n) > 0 && num.Cmp(evm.BlockNumber) < 0 {
+ stack.push(evm.GetHash(num.Uint64()).Big())
} else {
stack.push(new(big.Int))
}
+
+ evm.interpreter.intPool.put(num, n)
return nil, nil
}
-func opCoinbase(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
- stack.push(env.Coinbase.Big())
+func opCoinbase(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+ stack.push(evm.Coinbase.Big())
return nil, nil
}
-func opTimestamp(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
- stack.push(U256(new(big.Int).Set(env.Time)))
+func opTimestamp(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+ stack.push(math.U256(new(big.Int).Set(evm.Time)))
return nil, nil
}
-func opNumber(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
- stack.push(U256(new(big.Int).Set(env.BlockNumber)))
+func opNumber(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+ stack.push(math.U256(new(big.Int).Set(evm.BlockNumber)))
return nil, nil
}
-func opDifficulty(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
- stack.push(U256(new(big.Int).Set(env.Difficulty)))
+func opDifficulty(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+ stack.push(math.U256(new(big.Int).Set(evm.Difficulty)))
return nil, nil
}
-func opGasLimit(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
- stack.push(U256(new(big.Int).Set(env.GasLimit)))
+func opGasLimit(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+ stack.push(math.U256(new(big.Int).Set(evm.GasLimit)))
return nil, nil
}
-func opPop(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
- stack.pop()
+func opPop(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+ evm.interpreter.intPool.put(stack.pop())
return nil, nil
}
-func opMload(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+func opMload(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
offset := stack.pop()
- val := common.BigD(memory.Get(offset.Int64(), 32))
+ val := new(big.Int).SetBytes(memory.Get(offset.Int64(), 32))
stack.push(val)
+
+ evm.interpreter.intPool.put(offset)
return nil, nil
}
-func opMstore(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+func opMstore(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
// pop value of the stack
mStart, val := stack.pop(), stack.pop()
- memory.Set(mStart.Uint64(), 32, common.BigToBytes(val, 256))
+ memory.Set(mStart.Uint64(), 32, math.PaddedBigBytes(val, 32))
+
+ evm.interpreter.intPool.put(mStart, val)
return nil, nil
}
-func opMstore8(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+func opMstore8(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
off, val := stack.pop().Int64(), stack.pop().Int64()
memory.store[off] = byte(val & 0xff)
+
return nil, nil
}
-func opSload(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+func opSload(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
loc := common.BigToHash(stack.pop())
- val := env.StateDB.GetState(contract.Address(), loc).Big()
+ val := evm.StateDB.GetState(contract.Address(), loc).Big()
stack.push(val)
return nil, nil
}
-func opSstore(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+func opSstore(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
loc := common.BigToHash(stack.pop())
val := stack.pop()
- env.StateDB.SetState(contract.Address(), loc, common.BigToHash(val))
+ evm.StateDB.SetState(contract.Address(), loc, common.BigToHash(val))
+
+ evm.interpreter.intPool.put(val)
return nil, nil
}
-func opJump(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+func opJump(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
pos := stack.pop()
if !contract.jumpdests.has(contract.CodeHash, contract.Code, pos) {
nop := contract.GetOp(pos.Uint64())
return nil, fmt.Errorf("invalid jump destination (%v) %v", nop, pos)
}
*pc = pos.Uint64()
+
+ evm.interpreter.intPool.put(pos)
return nil, nil
}
-func opJumpi(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+func opJumpi(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
pos, cond := stack.pop(), stack.pop()
- if cond.Cmp(common.BigTrue) >= 0 {
+ if cond.Sign() != 0 {
if !contract.jumpdests.has(contract.CodeHash, contract.Code, pos) {
nop := contract.GetOp(pos.Uint64())
return nil, fmt.Errorf("invalid jump destination (%v) %v", nop, pos)
@@ -445,60 +515,65 @@ func opJumpi(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *St
} else {
*pc++
}
+
+ evm.interpreter.intPool.put(pos, cond)
return nil, nil
}
-func opJumpdest(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+func opJumpdest(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
return nil, nil
}
-func opPc(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
- stack.push(new(big.Int).SetUint64(*pc))
+func opPc(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+ stack.push(evm.interpreter.intPool.get().SetUint64(*pc))
return nil, nil
}
-func opMsize(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
- stack.push(big.NewInt(int64(memory.Len())))
+func opMsize(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+ stack.push(evm.interpreter.intPool.get().SetInt64(int64(memory.Len())))
return nil, nil
}
-func opGas(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
- stack.push(new(big.Int).Set(contract.Gas))
+func opGas(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+ stack.push(evm.interpreter.intPool.get().SetUint64(contract.Gas))
return nil, nil
}
-func opCreate(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+func opCreate(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
var (
value = stack.pop()
offset, size = stack.pop(), stack.pop()
input = memory.Get(offset.Int64(), size.Int64())
- gas = new(big.Int).Set(contract.Gas)
+ gas = contract.Gas
)
- if env.ChainConfig().IsEIP150(env.BlockNumber) {
- gas.Div(gas, n64)
- gas = gas.Sub(contract.Gas, gas)
+ if evm.ChainConfig().IsEIP150(evm.BlockNumber) {
+ gas -= gas / 64
}
contract.UseGas(gas)
- _, addr, suberr := env.Create(contract, input, gas, value)
+ _, addr, returnGas, suberr := evm.Create(contract, input, gas, value)
// Push item on the stack based on the returned error. If the ruleset is
// homestead we must check for CodeStoreOutOfGasError (homestead only
// rule) and treat as an error, if the ruleset is frontier we must
// ignore this error and pretend the operation was successful.
- if env.ChainConfig().IsHomestead(env.BlockNumber) && suberr == ErrCodeStoreOutOfGas {
+ if evm.ChainConfig().IsHomestead(evm.BlockNumber) && suberr == ErrCodeStoreOutOfGas {
stack.push(new(big.Int))
} else if suberr != nil && suberr != ErrCodeStoreOutOfGas {
stack.push(new(big.Int))
} else {
stack.push(addr.Big())
}
+ contract.Gas += returnGas
+
+ evm.interpreter.intPool.put(value, offset, size)
+
return nil, nil
}
-func opCall(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
- gas := stack.pop()
+func opCall(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+ gas := stack.pop().Uint64()
// pop gas and value of the stack.
addr, value := stack.pop(), stack.pop()
- value = U256(value)
+ value = math.U256(value)
// pop input size and offset
inOffset, inSize := stack.pop(), stack.pop()
// pop return size and offset
@@ -509,28 +584,29 @@ func opCall(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Sta
// Get the arguments from the memory
args := memory.Get(inOffset.Int64(), inSize.Int64())
- if len(value.Bytes()) > 0 {
- gas.Add(gas, params.CallStipend)
+ if value.Sign() != 0 {
+ gas += params.CallStipend
}
- ret, err := env.Call(contract, address, args, gas, value)
-
+ ret, returnGas, err := evm.Call(contract, address, args, gas, value)
if err != nil {
stack.push(new(big.Int))
-
} else {
stack.push(big.NewInt(1))
memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
}
+ contract.Gas += returnGas
+
+ evm.interpreter.intPool.put(addr, value, inOffset, inSize, retOffset, retSize)
return nil, nil
}
-func opCallCode(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
- gas := stack.pop()
+func opCallCode(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+ gas := stack.pop().Uint64()
// pop gas and value of the stack.
addr, value := stack.pop(), stack.pop()
- value = U256(value)
+ value = math.U256(value)
// pop input size and offset
inOffset, inSize := stack.pop(), stack.pop()
// pop return size and offset
@@ -541,12 +617,11 @@ func opCallCode(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack
// Get the arguments from the memory
args := memory.Get(inOffset.Int64(), inSize.Int64())
- if len(value.Bytes()) > 0 {
- gas.Add(gas, params.CallStipend)
+ if value.Sign() != 0 {
+ gas += params.CallStipend
}
- ret, err := env.CallCode(contract, address, args, gas, value)
-
+ ret, returnGas, err := evm.CallCode(contract, address, args, gas, value)
if err != nil {
stack.push(new(big.Int))
@@ -555,46 +630,54 @@ func opCallCode(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack
memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
}
+ contract.Gas += returnGas
+
+ evm.interpreter.intPool.put(addr, value, inOffset, inSize, retOffset, retSize)
return nil, nil
}
-func opDelegateCall(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+func opDelegateCall(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
// if not homestead return an error. DELEGATECALL is not supported
// during pre-homestead.
- if !env.ChainConfig().IsHomestead(env.BlockNumber) {
+ if !evm.ChainConfig().IsHomestead(evm.BlockNumber) {
return nil, fmt.Errorf("invalid opcode %x", DELEGATECALL)
}
- gas, to, inOffset, inSize, outOffset, outSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop()
+ gas, to, inOffset, inSize, outOffset, outSize := stack.pop().Uint64(), stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop()
toAddr := common.BigToAddress(to)
args := memory.Get(inOffset.Int64(), inSize.Int64())
- ret, err := env.DelegateCall(contract, toAddr, args, gas)
+
+ ret, returnGas, err := evm.DelegateCall(contract, toAddr, args, gas)
if err != nil {
stack.push(new(big.Int))
} else {
stack.push(big.NewInt(1))
memory.Set(outOffset.Uint64(), outSize.Uint64(), ret)
}
+ contract.Gas += returnGas
+
+ evm.interpreter.intPool.put(to, inOffset, inSize, outOffset, outSize)
return nil, nil
}
-func opReturn(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+func opReturn(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
offset, size := stack.pop(), stack.pop()
ret := memory.GetPtr(offset.Int64(), size.Int64())
+ evm.interpreter.intPool.put(offset, size)
return ret, nil
}
-func opStop(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+func opStop(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
return nil, nil
}
-func opSuicide(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
- balance := env.StateDB.GetBalance(contract.Address())
- env.StateDB.AddBalance(common.BigToAddress(stack.pop()), balance)
+func opSuicide(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+ balance := evm.StateDB.GetBalance(contract.Address())
+ evm.StateDB.AddBalance(common.BigToAddress(stack.pop()), balance)
- env.StateDB.Suicide(contract.Address())
+ evm.StateDB.Suicide(contract.Address())
return nil, nil
}
@@ -603,7 +686,7 @@ func opSuicide(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *
// make log instruction function
func makeLog(size int) executionFunc {
- return func(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+ return func(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
topics := make([]common.Hash, size)
mStart, mSize := stack.pop(), stack.pop()
for i := 0; i < size; i++ {
@@ -611,23 +694,25 @@ func makeLog(size int) executionFunc {
}
d := memory.Get(mStart.Int64(), mSize.Int64())
- env.StateDB.AddLog(&types.Log{
+ evm.StateDB.AddLog(&types.Log{
Address: contract.Address(),
Topics: topics,
Data: d,
// This is a non-consensus field, but assigned here because
// core/state doesn't know the current block number.
- BlockNumber: env.BlockNumber.Uint64(),
+ BlockNumber: evm.BlockNumber.Uint64(),
})
+
+ evm.interpreter.intPool.put(mStart, mSize)
return nil, nil
}
}
// make push instruction function
func makePush(size uint64, bsize *big.Int) executionFunc {
- return func(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
- byts := getData(contract.Code, new(big.Int).SetUint64(*pc+1), bsize)
- stack.push(common.Bytes2Big(byts))
+ return func(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+ byts := getData(contract.Code, evm.interpreter.intPool.get().SetUint64(*pc+1), bsize)
+ stack.push(new(big.Int).SetBytes(byts))
*pc += size
return nil, nil
}
@@ -635,7 +720,7 @@ func makePush(size uint64, bsize *big.Int) executionFunc {
// make push instruction function
func makeDup(size int64) executionFunc {
- return func(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+ return func(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
stack.dup(int(size))
return nil, nil
}
@@ -645,7 +730,7 @@ func makeDup(size int64) executionFunc {
func makeSwap(size int64) executionFunc {
// switch n + 1 otherwise n would be swapped with n
size += 1
- return func(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+ return func(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
stack.swap(int(size))
return nil, nil
}
diff --git a/core/vm/int_pool_verifier.go b/core/vm/int_pool_verifier.go
new file mode 100644
index 0000000000..61c83ba7e9
--- /dev/null
+++ b/core/vm/int_pool_verifier.go
@@ -0,0 +1,15 @@
+// +build VERIFY_EVM_INTEGER_POOL
+
+package vm
+
+import "fmt"
+
+const verifyPool = true
+
+func verifyIntegerPool(ip *intPool) {
+ for i, item := range ip.pool.data {
+ if item.Cmp(checkVal) != 0 {
+ panic(fmt.Sprintf("%d'th item failed aggressive pool check. Value was modified", i))
+ }
+ }
+}
diff --git a/core/vm/int_pool_verifier_empty.go b/core/vm/int_pool_verifier_empty.go
new file mode 100644
index 0000000000..982f8c6dd5
--- /dev/null
+++ b/core/vm/int_pool_verifier_empty.go
@@ -0,0 +1,7 @@
+// +build !VERIFY_EVM_INTEGER_POOL
+
+package vm
+
+const verifyPool = false
+
+func verifyIntegerPool(ip *intPool) {}
diff --git a/core/vm/interface.go b/core/vm/interface.go
index 6f15112eea..4d8ece41ca 100644
--- a/core/vm/interface.go
+++ b/core/vm/interface.go
@@ -25,8 +25,7 @@ import (
// StateDB is an EVM database for full state querying.
type StateDB interface {
- GetAccount(common.Address) Account
- CreateAccount(common.Address) Account
+ CreateAccount(common.Address)
SubBalance(common.Address, *big.Int)
AddBalance(common.Address, *big.Int)
@@ -61,20 +60,8 @@ type StateDB interface {
AddLog(*types.Log)
AddPreimage(common.Hash, []byte)
-}
-// Account represents a contract or basic ethereum account.
-type Account interface {
- SubBalance(amount *big.Int)
- AddBalance(amount *big.Int)
- SetBalance(*big.Int)
- SetNonce(uint64)
- Balance() *big.Int
- Address() common.Address
- ReturnGas(*big.Int)
- SetCode(common.Hash, []byte)
- ForEachStorage(cb func(key, value common.Hash) bool)
- Value() *big.Int
+ ForEachStorage(common.Address, func(common.Hash, common.Hash) bool)
}
// CallContext provides a basic interface for the EVM calling conventions. The EVM EVM
diff --git a/core/vm/vm.go b/core/vm/interpreter.go
similarity index 81%
rename from core/vm/vm.go
rename to core/vm/interpreter.go
index 05886a8639..8ee9d3ca79 100644
--- a/core/vm/vm.go
+++ b/core/vm/interpreter.go
@@ -18,14 +18,13 @@ package vm
import (
"fmt"
- "math/big"
"sync/atomic"
"time"
"github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/crypto"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params"
)
@@ -60,6 +59,7 @@ type Interpreter struct {
env *EVM
cfg Config
gasTable params.GasTable
+ intPool *intPool
}
// NewInterpreter returns a new instance of the Interpreter.
@@ -75,6 +75,7 @@ func NewInterpreter(env *EVM, cfg Config) *Interpreter {
env: env,
cfg: cfg,
gasTable: env.ChainConfig().GasTable(env.BlockNumber),
+ intPool: newIntPool(),
}
}
@@ -106,24 +107,22 @@ func (evm *Interpreter) Run(contract *Contract, input []byte) (ret []byte, err e
// For optimisation reason we're using uint64 as the program counter.
// It's theoretically possible to go above 2^64. The YP defines the PC to be uint256. Practically much less so feasible.
pc = uint64(0) // program counter
- cost *big.Int
+ cost uint64
)
contract.Input = input
// User defer pattern to check for an error and, based on the error being nil or not, use all gas and return.
defer func() {
if err != nil && evm.cfg.Debug {
+ // XXX For debugging
+ //fmt.Printf("%04d: %8v cost = %-8d stack = %-8d ERR = %v\n", pc, op, cost, stack.len(), err)
evm.cfg.Tracer.CaptureState(evm.env, pc, op, contract.Gas, cost, mem, stack, contract, evm.env.depth, err)
}
}()
- if glog.V(logger.Debug) {
- glog.Infof("evm running: %x\n", codehash[:4])
- tstart := time.Now()
- defer func() {
- glog.Infof("evm done: %x. time: %v\n", codehash[:4], time.Since(tstart))
- }()
- }
+ log.Debug("EVM running contract", "hash", codehash[:])
+ tstart := time.Now()
+ defer log.Debug("EVM finished running contract", "hash", codehash[:], "elapsed", time.Since(tstart))
// The Interpreter main run loop (contextual). This loop runs until either an
// explicit STOP, RETURN or SELFDESTRUCT is executed, an error occurred during
@@ -147,34 +146,46 @@ func (evm *Interpreter) Run(contract *Contract, input []byte) (ret []byte, err e
return nil, err
}
- var memorySize *big.Int
+ var memorySize uint64
// calculate the new memory size and expand the memory to fit
// the operation
if operation.memorySize != nil {
- memorySize = operation.memorySize(stack)
+ memSize, overflow := bigUint64(operation.memorySize(stack))
+ if overflow {
+ return nil, errGasUintOverflow
+ }
// memory is expanded in words of 32 bytes. Gas
// is also calculated in words.
- memorySize.Mul(toWordSize(memorySize), big.NewInt(32))
+ if memorySize, overflow = math.SafeMul(toWordSize(memSize), 32); overflow {
+ return nil, errGasUintOverflow
+ }
}
if !evm.cfg.DisableGasMetering {
// consume the gas and return an error if not enough gas is available.
// cost is explicitly set so that the capture state defer method cas get the proper cost
- cost = operation.gasCost(evm.gasTable, evm.env, contract, stack, mem, memorySize)
- if !contract.UseGas(cost) {
+ cost, err = operation.gasCost(evm.gasTable, evm.env, contract, stack, mem, memorySize)
+ if err != nil || !contract.UseGas(cost) {
return nil, ErrOutOfGas
}
}
- if memorySize != nil {
- mem.Resize(memorySize.Uint64())
+ if memorySize > 0 {
+ mem.Resize(memorySize)
}
if evm.cfg.Debug {
evm.cfg.Tracer.CaptureState(evm.env, pc, op, contract.Gas, cost, mem, stack, contract, evm.env.depth, err)
}
+ // XXX For debugging
+ //fmt.Printf("%04d: %8v cost = %-8d stack = %-8d\n", pc, op, cost, stack.len())
// execute the operation
res, err := operation.execute(&pc, evm.env, contract, mem, stack)
+ // verifyPool is a build flag. Pool verification makes sure the integrity
+ // of the integer pool by comparing values to a default value.
+ if verifyPool {
+ verifyIntegerPool(evm.intPool)
+ }
switch {
case err != nil:
return nil, err
diff --git a/core/vm/disasm.go b/core/vm/intpool.go
similarity index 54%
rename from core/vm/disasm.go
rename to core/vm/intpool.go
index 2bfea5cbda..4f1228e149 100644
--- a/core/vm/disasm.go
+++ b/core/vm/intpool.go
@@ -1,4 +1,4 @@
-// Copyright 2015 The go-ethereum Authors
+// Copyright 2017 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
@@ -16,22 +16,34 @@
package vm
-import "fmt"
+import "math/big"
-func Disasm(code []byte) []string {
- var out []string
- for pc := uint64(0); pc < uint64(len(code)); pc++ {
- op := OpCode(code[pc])
- out = append(out, op.String())
+var checkVal = big.NewInt(-42)
- switch op {
- case PUSH1, PUSH2, PUSH3, PUSH4, PUSH5, PUSH6, PUSH7, PUSH8, PUSH9, PUSH10, PUSH11, PUSH12, PUSH13, PUSH14, PUSH15, PUSH16, PUSH17, PUSH18, PUSH19, PUSH20, PUSH21, PUSH22, PUSH23, PUSH24, PUSH25, PUSH26, PUSH27, PUSH28, PUSH29, PUSH30, PUSH31, PUSH32:
- a := uint64(op) - uint64(PUSH1) + 1
- out = append(out, fmt.Sprintf("0x%x", code[pc+1:pc+1+a]))
-
- pc += a
- }
- }
-
- return out
+// intPool is a pool of big integers that
+// can be reused for all big.Int operations.
+type intPool struct {
+ pool *Stack
+}
+
+func newIntPool() *intPool {
+ return &intPool{pool: newstack()}
+}
+
+func (p *intPool) get() *big.Int {
+ if p.pool.len() > 0 {
+ return p.pool.pop()
+ }
+ return new(big.Int)
+}
+func (p *intPool) put(is ...*big.Int) {
+ for _, i := range is {
+ // verifyPool is a build flag. Pool verification makes sure the integrity
+ // of the integer pool by comparing values to a default value.
+ if verifyPool {
+ i.Set(checkVal)
+ }
+
+ p.pool.push(i)
+ }
}
diff --git a/core/vm/jump_table.go b/core/vm/jump_table.go
index 0737982745..ed30100ac1 100644
--- a/core/vm/jump_table.go
+++ b/core/vm/jump_table.go
@@ -17,6 +17,7 @@
package vm
import (
+ "errors"
"math/big"
"github.com/ethereum/go-ethereum/params"
@@ -24,11 +25,13 @@ import (
type (
executionFunc func(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error)
- gasFunc func(params.GasTable, *EVM, *Contract, *Stack, *Memory, *big.Int) *big.Int
+ gasFunc func(params.GasTable, *EVM, *Contract, *Stack, *Memory, uint64) (uint64, error) // last parameter is the requested memory size as a uint64
stackValidationFunc func(*Stack) error
memorySizeFunc func(*Stack) *big.Int
)
+var errGasUintOverflow = errors.New("gas uint64 overflow")
+
type operation struct {
// op is the operation function
execute executionFunc
@@ -54,7 +57,7 @@ func NewJumpTable() [256]operation {
return [256]operation{
STOP: {
execute: opStop,
- gasCost: constGasFunc(new(big.Int)),
+ gasCost: constGasFunc(0),
validateStack: makeStackFunc(0, 0),
halts: true,
valid: true,
@@ -62,139 +65,139 @@ func NewJumpTable() [256]operation {
ADD: {
execute: opAdd,
gasCost: constGasFunc(GasFastestStep),
- validateStack: makeStackFunc(2, -1),
+ validateStack: makeStackFunc(2, 1),
valid: true,
},
MUL: {
execute: opMul,
gasCost: constGasFunc(GasFastStep),
- validateStack: makeStackFunc(2, -1),
+ validateStack: makeStackFunc(2, 1),
valid: true,
},
SUB: {
execute: opSub,
gasCost: constGasFunc(GasFastestStep),
- validateStack: makeStackFunc(2, -1),
+ validateStack: makeStackFunc(2, 1),
valid: true,
},
DIV: {
execute: opDiv,
gasCost: constGasFunc(GasFastStep),
- validateStack: makeStackFunc(2, -1),
+ validateStack: makeStackFunc(2, 1),
valid: true,
},
SDIV: {
execute: opSdiv,
gasCost: constGasFunc(GasFastStep),
- validateStack: makeStackFunc(2, -1),
+ validateStack: makeStackFunc(2, 1),
valid: true,
},
MOD: {
execute: opMod,
gasCost: constGasFunc(GasFastStep),
- validateStack: makeStackFunc(2, -1),
+ validateStack: makeStackFunc(2, 1),
valid: true,
},
SMOD: {
execute: opSmod,
gasCost: constGasFunc(GasFastStep),
- validateStack: makeStackFunc(2, -1),
+ validateStack: makeStackFunc(2, 1),
valid: true,
},
ADDMOD: {
execute: opAddmod,
gasCost: constGasFunc(GasMidStep),
- validateStack: makeStackFunc(3, -2),
+ validateStack: makeStackFunc(3, 1),
valid: true,
},
MULMOD: {
execute: opMulmod,
gasCost: constGasFunc(GasMidStep),
- validateStack: makeStackFunc(3, -2),
+ validateStack: makeStackFunc(3, 1),
valid: true,
},
EXP: {
execute: opExp,
gasCost: gasExp,
- validateStack: makeStackFunc(2, -1),
+ validateStack: makeStackFunc(2, 1),
valid: true,
},
SIGNEXTEND: {
execute: opSignExtend,
gasCost: constGasFunc(GasFastStep),
- validateStack: makeStackFunc(2, -1),
+ validateStack: makeStackFunc(2, 1),
valid: true,
},
LT: {
execute: opLt,
gasCost: constGasFunc(GasFastestStep),
- validateStack: makeStackFunc(2, -1),
+ validateStack: makeStackFunc(2, 1),
valid: true,
},
GT: {
execute: opGt,
gasCost: constGasFunc(GasFastestStep),
- validateStack: makeStackFunc(2, -1),
+ validateStack: makeStackFunc(2, 1),
valid: true,
},
SLT: {
execute: opSlt,
gasCost: constGasFunc(GasFastestStep),
- validateStack: makeStackFunc(2, -1),
+ validateStack: makeStackFunc(2, 1),
valid: true,
},
SGT: {
execute: opSgt,
gasCost: constGasFunc(GasFastestStep),
- validateStack: makeStackFunc(2, -1),
+ validateStack: makeStackFunc(2, 1),
valid: true,
},
EQ: {
execute: opEq,
gasCost: constGasFunc(GasFastestStep),
- validateStack: makeStackFunc(2, -1),
+ validateStack: makeStackFunc(2, 1),
valid: true,
},
ISZERO: {
execute: opIszero,
gasCost: constGasFunc(GasFastestStep),
- validateStack: makeStackFunc(1, 0),
+ validateStack: makeStackFunc(1, 1),
valid: true,
},
AND: {
execute: opAnd,
gasCost: constGasFunc(GasFastestStep),
- validateStack: makeStackFunc(2, -1),
+ validateStack: makeStackFunc(2, 1),
valid: true,
},
XOR: {
execute: opXor,
gasCost: constGasFunc(GasFastestStep),
- validateStack: makeStackFunc(2, -1),
+ validateStack: makeStackFunc(2, 1),
valid: true,
},
OR: {
execute: opOr,
gasCost: constGasFunc(GasFastestStep),
- validateStack: makeStackFunc(2, -1),
+ validateStack: makeStackFunc(2, 1),
valid: true,
},
NOT: {
execute: opNot,
gasCost: constGasFunc(GasFastestStep),
- validateStack: makeStackFunc(1, 0),
+ validateStack: makeStackFunc(1, 1),
valid: true,
},
BYTE: {
execute: opByte,
gasCost: constGasFunc(GasFastestStep),
- validateStack: makeStackFunc(2, -1),
+ validateStack: makeStackFunc(2, 1),
valid: true,
},
SHA3: {
execute: opSha3,
gasCost: gasSha3,
- validateStack: makeStackFunc(2, -1),
+ validateStack: makeStackFunc(2, 1),
memorySize: memorySha3,
valid: true,
},
@@ -207,7 +210,7 @@ func NewJumpTable() [256]operation {
BALANCE: {
execute: opBalance,
gasCost: gasBalance,
- validateStack: makeStackFunc(1, 0),
+ validateStack: makeStackFunc(1, 1),
valid: true,
},
ORIGIN: {
@@ -231,7 +234,7 @@ func NewJumpTable() [256]operation {
CALLDATALOAD: {
execute: opCalldataLoad,
gasCost: constGasFunc(GasFastestStep),
- validateStack: makeStackFunc(1, 0),
+ validateStack: makeStackFunc(1, 1),
valid: true,
},
CALLDATASIZE: {
@@ -243,7 +246,7 @@ func NewJumpTable() [256]operation {
CALLDATACOPY: {
execute: opCalldataCopy,
gasCost: gasCalldataCopy,
- validateStack: makeStackFunc(3, -3),
+ validateStack: makeStackFunc(3, 0),
memorySize: memoryCalldataCopy,
valid: true,
},
@@ -256,7 +259,7 @@ func NewJumpTable() [256]operation {
CODECOPY: {
execute: opCodeCopy,
gasCost: gasCodeCopy,
- validateStack: makeStackFunc(3, -3),
+ validateStack: makeStackFunc(3, 0),
memorySize: memoryCodeCopy,
valid: true,
},
@@ -269,20 +272,20 @@ func NewJumpTable() [256]operation {
EXTCODESIZE: {
execute: opExtCodeSize,
gasCost: gasExtCodeSize,
- validateStack: makeStackFunc(1, 0),
+ validateStack: makeStackFunc(1, 1),
valid: true,
},
EXTCODECOPY: {
execute: opExtCodeCopy,
gasCost: gasExtCodeCopy,
- validateStack: makeStackFunc(4, -4),
+ validateStack: makeStackFunc(4, 0),
memorySize: memoryExtCodeCopy,
valid: true,
},
BLOCKHASH: {
execute: opBlockhash,
gasCost: constGasFunc(GasExtStep),
- validateStack: makeStackFunc(1, 0),
+ validateStack: makeStackFunc(1, 1),
valid: true,
},
COINBASE: {
@@ -318,20 +321,20 @@ func NewJumpTable() [256]operation {
POP: {
execute: opPop,
gasCost: constGasFunc(GasQuickStep),
- validateStack: makeStackFunc(1, -1),
+ validateStack: makeStackFunc(1, 0),
valid: true,
},
MLOAD: {
execute: opMload,
gasCost: gasMLoad,
- validateStack: makeStackFunc(1, 0),
+ validateStack: makeStackFunc(1, 1),
memorySize: memoryMLoad,
valid: true,
},
MSTORE: {
execute: opMstore,
gasCost: gasMStore,
- validateStack: makeStackFunc(2, -2),
+ validateStack: makeStackFunc(2, 0),
memorySize: memoryMStore,
valid: true,
},
@@ -339,33 +342,33 @@ func NewJumpTable() [256]operation {
execute: opMstore8,
gasCost: gasMStore8,
memorySize: memoryMStore8,
- validateStack: makeStackFunc(2, -2),
+ validateStack: makeStackFunc(2, 0),
valid: true,
},
SLOAD: {
execute: opSload,
gasCost: gasSLoad,
- validateStack: makeStackFunc(1, 0),
+ validateStack: makeStackFunc(1, 1),
valid: true,
},
SSTORE: {
execute: opSstore,
gasCost: gasSStore,
- validateStack: makeStackFunc(2, -2),
+ validateStack: makeStackFunc(2, 0),
valid: true,
},
JUMP: {
execute: opJump,
gasCost: constGasFunc(GasMidStep),
- validateStack: makeStackFunc(1, -1),
+ validateStack: makeStackFunc(1, 0),
jumps: true,
valid: true,
},
JUMPI: {
execute: opJumpi,
gasCost: constGasFunc(GasSlowStep),
- validateStack: makeStackFunc(2, -2),
+ validateStack: makeStackFunc(2, 0),
jumps: true,
valid: true,
},
@@ -780,63 +783,63 @@ func NewJumpTable() [256]operation {
LOG0: {
execute: makeLog(0),
gasCost: makeGasLog(0),
- validateStack: makeStackFunc(2, -2),
+ validateStack: makeStackFunc(2, 0),
memorySize: memoryLog,
valid: true,
},
LOG1: {
execute: makeLog(1),
gasCost: makeGasLog(1),
- validateStack: makeStackFunc(3, -3),
+ validateStack: makeStackFunc(3, 0),
memorySize: memoryLog,
valid: true,
},
LOG2: {
execute: makeLog(2),
gasCost: makeGasLog(2),
- validateStack: makeStackFunc(4, -4),
+ validateStack: makeStackFunc(4, 0),
memorySize: memoryLog,
valid: true,
},
LOG3: {
execute: makeLog(3),
gasCost: makeGasLog(3),
- validateStack: makeStackFunc(5, -5),
+ validateStack: makeStackFunc(5, 0),
memorySize: memoryLog,
valid: true,
},
LOG4: {
execute: makeLog(4),
gasCost: makeGasLog(4),
- validateStack: makeStackFunc(6, -6),
+ validateStack: makeStackFunc(6, 0),
memorySize: memoryLog,
valid: true,
},
CREATE: {
execute: opCreate,
gasCost: gasCreate,
- validateStack: makeStackFunc(3, -2),
+ validateStack: makeStackFunc(3, 1),
memorySize: memoryCreate,
valid: true,
},
CALL: {
execute: opCall,
gasCost: gasCall,
- validateStack: makeStackFunc(7, -6),
+ validateStack: makeStackFunc(7, 1),
memorySize: memoryCall,
valid: true,
},
CALLCODE: {
execute: opCallCode,
gasCost: gasCallCode,
- validateStack: makeStackFunc(7, -6),
+ validateStack: makeStackFunc(7, 1),
memorySize: memoryCall,
valid: true,
},
RETURN: {
execute: opReturn,
gasCost: gasReturn,
- validateStack: makeStackFunc(2, -2),
+ validateStack: makeStackFunc(2, 0),
memorySize: memoryReturn,
halts: true,
valid: true,
@@ -844,14 +847,14 @@ func NewJumpTable() [256]operation {
DELEGATECALL: {
execute: opDelegateCall,
gasCost: gasDelegateCall,
- validateStack: makeStackFunc(6, -5),
+ validateStack: makeStackFunc(6, 1),
memorySize: memoryDelegateCall,
valid: true,
},
SELFDESTRUCT: {
execute: opSuicide,
gasCost: gasSuicide,
- validateStack: makeStackFunc(1, -1),
+ validateStack: makeStackFunc(1, 0),
halts: true,
valid: true,
},
diff --git a/core/vm/logger.go b/core/vm/logger.go
index db8c20e07f..825025b05f 100644
--- a/core/vm/logger.go
+++ b/core/vm/logger.go
@@ -17,12 +17,14 @@
package vm
import (
+ "encoding/hex"
"fmt"
+ "io"
"math/big"
- "os"
- "unicode"
"github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/common/math"
+ "github.com/ethereum/go-ethereum/core/types"
)
type Storage map[common.Hash]common.Hash
@@ -50,8 +52,8 @@ type LogConfig struct {
type StructLog struct {
Pc uint64
Op OpCode
- Gas *big.Int
- GasCost *big.Int
+ Gas uint64
+ GasCost uint64
Memory []byte
Stack []*big.Int
Storage map[common.Hash]common.Hash
@@ -65,7 +67,7 @@ type StructLog struct {
// Note that reference types are actual VM data structures; make copies
// if you need to retain them beyond the current call.
type Tracer interface {
- CaptureState(env *EVM, pc uint64, op OpCode, gas, cost *big.Int, memory *Memory, stack *Stack, contract *Contract, depth int, err error) error
+ CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *Memory, stack *Stack, contract *Contract, depth int, err error) error
}
// StructLogger is an EVM state logger and implements Tracer.
@@ -94,7 +96,7 @@ func NewStructLogger(cfg *LogConfig) *StructLogger {
// captureState logs a new structured log message and pushes it out to the environment
//
// captureState also tracks SSTORE ops to track dirty values.
-func (l *StructLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost *big.Int, memory *Memory, stack *Stack, contract *Contract, depth int, err error) error {
+func (l *StructLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *Memory, stack *Stack, contract *Contract, depth int, err error) error {
// check if already accumulated the specified number of logs
if l.cfg.Limit != 0 && l.cfg.Limit <= len(l.logs) {
return ErrTraceLimitReached
@@ -144,7 +146,8 @@ func (l *StructLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost *b
storage = make(Storage)
// Get the contract account and loop over each storage entry. This may involve looping over
// the trie and is a very expensive process.
- env.StateDB.GetAccount(contract.Address()).ForEachStorage(func(key, value common.Hash) bool {
+
+ env.StateDB.ForEachStorage(contract.Address(), func(key, value common.Hash) bool {
storage[key] = value
// Return true, indicating we'd like to continue.
return true
@@ -155,7 +158,7 @@ func (l *StructLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost *b
}
}
// create a new snaptshot of the EVM.
- log := StructLog{pc, op, new(big.Int).Set(gas), cost, mem, stck, storage, env.depth, err}
+ log := StructLog{pc, op, gas, cost, mem, stck, storage, env.depth, err}
l.logs = append(l.logs, log)
return nil
@@ -166,45 +169,38 @@ func (l *StructLogger) StructLogs() []StructLog {
return l.logs
}
-// StdErrFormat formats a slice of StructLogs to human readable format
-func StdErrFormat(logs []StructLog) {
- fmt.Fprintf(os.Stderr, "VM STAT %d OPs\n", len(logs))
+// WriteTrace writes a formatted trace to the given writer
+func WriteTrace(writer io.Writer, logs []StructLog) {
for _, log := range logs {
- fmt.Fprintf(os.Stderr, "PC %08d: %s GAS: %v COST: %v", log.Pc, log.Op, log.Gas, log.GasCost)
+ fmt.Fprintf(writer, "%-10spc=%08d gas=%v cost=%v", log.Op, log.Pc, log.Gas, log.GasCost)
if log.Err != nil {
- fmt.Fprintf(os.Stderr, " ERROR: %v", log.Err)
+ fmt.Fprintf(writer, " ERROR: %v", log.Err)
}
- fmt.Fprintf(os.Stderr, "\n")
-
- fmt.Fprintln(os.Stderr, "STACK =", len(log.Stack))
+ fmt.Fprintf(writer, "\n")
for i := len(log.Stack) - 1; i >= 0; i-- {
- fmt.Fprintf(os.Stderr, "%04d: %x\n", len(log.Stack)-i-1, common.LeftPadBytes(log.Stack[i].Bytes(), 32))
+ fmt.Fprintf(writer, "%08d %x\n", len(log.Stack)-i-1, math.PaddedBigBytes(log.Stack[i], 32))
}
- const maxMem = 10
- addr := 0
- fmt.Fprintln(os.Stderr, "MEM =", len(log.Memory))
- for i := 0; i+16 <= len(log.Memory) && addr < maxMem; i += 16 {
- data := log.Memory[i : i+16]
- str := fmt.Sprintf("%04d: % x ", addr*16, data)
- for _, r := range data {
- if r == 0 {
- str += "."
- } else if unicode.IsPrint(rune(r)) {
- str += fmt.Sprintf("%s", string(r))
- } else {
- str += "?"
- }
- }
- addr++
- fmt.Fprintln(os.Stderr, str)
- }
+ fmt.Fprint(writer, hex.Dump(log.Memory))
- fmt.Fprintln(os.Stderr, "STORAGE =", len(log.Storage))
for h, item := range log.Storage {
- fmt.Fprintf(os.Stderr, "%x: %x\n", h, item)
+ fmt.Fprintf(writer, "%x: %x\n", h, item)
}
- fmt.Fprintln(os.Stderr)
+ fmt.Fprintln(writer)
+ }
+}
+
+// WriteLogs writes vm logs in a readable format to the given writer
+func WriteLogs(writer io.Writer, logs []*types.Log) {
+ for _, log := range logs {
+ fmt.Fprintf(writer, "LOG%d: %x bn=%d txi=%x\n", len(log.Topics), log.Address, log.BlockNumber, log.TxIndex)
+
+ for i, topic := range log.Topics {
+ fmt.Fprintf(writer, "%08d %x\n", i, topic)
+ }
+
+ fmt.Fprint(writer, hex.Dump(log.Data))
+ fmt.Fprintln(writer)
}
}
diff --git a/core/vm/logger_test.go b/core/vm/logger_test.go
index 1d0bd96fad..b6fa31132a 100644
--- a/core/vm/logger_test.go
+++ b/core/vm/logger_test.go
@@ -46,24 +46,20 @@ type dummyStateDB struct {
ref *dummyContractRef
}
-func (d dummyStateDB) GetAccount(common.Address) Account {
- return d.ref
-}
-
func TestStoreCapture(t *testing.T) {
var (
env = NewEVM(Context{}, nil, params.TestChainConfig, Config{EnableJit: false, ForceJit: false})
logger = NewStructLogger(nil)
mem = NewMemory()
stack = newstack()
- contract = NewContract(&dummyContractRef{}, &dummyContractRef{}, new(big.Int), new(big.Int))
+ contract = NewContract(&dummyContractRef{}, &dummyContractRef{}, new(big.Int), 0)
)
stack.push(big.NewInt(1))
stack.push(big.NewInt(0))
var index common.Hash
- logger.CaptureState(env, 0, SSTORE, new(big.Int), new(big.Int), mem, stack, contract, 0, nil)
+ logger.CaptureState(env, 0, SSTORE, 0, 0, mem, stack, contract, 0, nil)
if len(logger.changedValues[contract.Address()]) == 0 {
t.Fatalf("expected exactly 1 changed value on address %x, got %d", contract.Address(), len(logger.changedValues[contract.Address()]))
}
@@ -78,20 +74,20 @@ func TestStorageCapture(t *testing.T) {
t.Skip("implementing this function is difficult. it requires all sort of interfaces to be implemented which isn't trivial. The value (the actual test) isn't worth it")
var (
ref = &dummyContractRef{}
- contract = NewContract(ref, ref, new(big.Int), new(big.Int))
+ contract = NewContract(ref, ref, new(big.Int), 0)
env = NewEVM(Context{}, dummyStateDB{ref: ref}, params.TestChainConfig, Config{EnableJit: false, ForceJit: false})
logger = NewStructLogger(nil)
mem = NewMemory()
stack = newstack()
)
- logger.CaptureState(env, 0, STOP, new(big.Int), new(big.Int), mem, stack, contract, 0, nil)
+ logger.CaptureState(env, 0, STOP, 0, 0, mem, stack, contract, 0, nil)
if ref.calledForEach {
t.Error("didn't expect for each to be called")
}
logger = NewStructLogger(&LogConfig{FullStorage: true})
- logger.CaptureState(env, 0, STOP, new(big.Int), new(big.Int), mem, stack, contract, 0, nil)
+ logger.CaptureState(env, 0, STOP, 0, 0, mem, stack, contract, 0, nil)
if !ref.calledForEach {
t.Error("expected for each to be called")
}
diff --git a/core/vm/memory.go b/core/vm/memory.go
index d011884173..99a84d2271 100644
--- a/core/vm/memory.go
+++ b/core/vm/memory.go
@@ -20,11 +20,12 @@ import "fmt"
// Memory implements a simple memory model for the ethereum virtual machine.
type Memory struct {
- store []byte
+ store []byte
+ lastGasCost uint64
}
func NewMemory() *Memory {
- return &Memory{nil}
+ return &Memory{}
}
// Set sets offset + size to value
diff --git a/core/vm/memory_table.go b/core/vm/memory_table.go
index 4db9948375..3141a2f61a 100644
--- a/core/vm/memory_table.go
+++ b/core/vm/memory_table.go
@@ -3,7 +3,7 @@ package vm
import (
"math/big"
- "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/common/math"
)
func memorySha3(stack *Stack) *big.Int {
@@ -42,20 +42,20 @@ func memoryCall(stack *Stack) *big.Int {
x := calcMemSize(stack.Back(5), stack.Back(6))
y := calcMemSize(stack.Back(3), stack.Back(4))
- return common.BigMax(x, y)
+ return math.BigMax(x, y)
}
func memoryCallCode(stack *Stack) *big.Int {
x := calcMemSize(stack.Back(5), stack.Back(6))
y := calcMemSize(stack.Back(3), stack.Back(4))
- return common.BigMax(x, y)
+ return math.BigMax(x, y)
}
func memoryDelegateCall(stack *Stack) *big.Int {
x := calcMemSize(stack.Back(4), stack.Back(5))
y := calcMemSize(stack.Back(2), stack.Back(3))
- return common.BigMax(x, y)
+ return math.BigMax(x, y)
}
func memoryReturn(stack *Stack) *big.Int {
diff --git a/core/vm/noop.go b/core/vm/noop.go
index 7835eeaf35..2a04a95654 100644
--- a/core/vm/noop.go
+++ b/core/vm/noop.go
@@ -45,26 +45,26 @@ func (NoopEVMCallContext) DelegateCall(me ContractRef, addr common.Address, data
type NoopStateDB struct{}
-func (NoopStateDB) GetAccount(common.Address) Account { return nil }
-func (NoopStateDB) CreateAccount(common.Address) Account { return nil }
-func (NoopStateDB) SubBalance(common.Address, *big.Int) {}
-func (NoopStateDB) AddBalance(common.Address, *big.Int) {}
-func (NoopStateDB) GetBalance(common.Address) *big.Int { return nil }
-func (NoopStateDB) GetNonce(common.Address) uint64 { return 0 }
-func (NoopStateDB) SetNonce(common.Address, uint64) {}
-func (NoopStateDB) GetCodeHash(common.Address) common.Hash { return common.Hash{} }
-func (NoopStateDB) GetCode(common.Address) []byte { return nil }
-func (NoopStateDB) SetCode(common.Address, []byte) {}
-func (NoopStateDB) GetCodeSize(common.Address) int { return 0 }
-func (NoopStateDB) AddRefund(*big.Int) {}
-func (NoopStateDB) GetRefund() *big.Int { return nil }
-func (NoopStateDB) GetState(common.Address, common.Hash) common.Hash { return common.Hash{} }
-func (NoopStateDB) SetState(common.Address, common.Hash, common.Hash) {}
-func (NoopStateDB) Suicide(common.Address) bool { return false }
-func (NoopStateDB) HasSuicided(common.Address) bool { return false }
-func (NoopStateDB) Exist(common.Address) bool { return false }
-func (NoopStateDB) Empty(common.Address) bool { return false }
-func (NoopStateDB) RevertToSnapshot(int) {}
-func (NoopStateDB) Snapshot() int { return 0 }
-func (NoopStateDB) AddLog(*types.Log) {}
-func (NoopStateDB) AddPreimage(common.Hash, []byte) {}
+func (NoopStateDB) CreateAccount(common.Address) {}
+func (NoopStateDB) SubBalance(common.Address, *big.Int) {}
+func (NoopStateDB) AddBalance(common.Address, *big.Int) {}
+func (NoopStateDB) GetBalance(common.Address) *big.Int { return nil }
+func (NoopStateDB) GetNonce(common.Address) uint64 { return 0 }
+func (NoopStateDB) SetNonce(common.Address, uint64) {}
+func (NoopStateDB) GetCodeHash(common.Address) common.Hash { return common.Hash{} }
+func (NoopStateDB) GetCode(common.Address) []byte { return nil }
+func (NoopStateDB) SetCode(common.Address, []byte) {}
+func (NoopStateDB) GetCodeSize(common.Address) int { return 0 }
+func (NoopStateDB) AddRefund(*big.Int) {}
+func (NoopStateDB) GetRefund() *big.Int { return nil }
+func (NoopStateDB) GetState(common.Address, common.Hash) common.Hash { return common.Hash{} }
+func (NoopStateDB) SetState(common.Address, common.Hash, common.Hash) {}
+func (NoopStateDB) Suicide(common.Address) bool { return false }
+func (NoopStateDB) HasSuicided(common.Address) bool { return false }
+func (NoopStateDB) Exist(common.Address) bool { return false }
+func (NoopStateDB) Empty(common.Address) bool { return false }
+func (NoopStateDB) RevertToSnapshot(int) {}
+func (NoopStateDB) Snapshot() int { return 0 }
+func (NoopStateDB) AddLog(*types.Log) {}
+func (NoopStateDB) AddPreimage(common.Hash, []byte) {}
+func (NoopStateDB) ForEachStorage(common.Address, func(common.Hash, common.Hash) bool) {}
diff --git a/core/vm/runtime/env.go b/core/vm/runtime/env.go
index a25c6d71c6..9aa88e6690 100644
--- a/core/vm/runtime/env.go
+++ b/core/vm/runtime/env.go
@@ -36,7 +36,7 @@ func NewEnv(cfg *Config, state *state.StateDB) *vm.EVM {
BlockNumber: cfg.BlockNumber,
Time: cfg.Time,
Difficulty: cfg.Difficulty,
- GasLimit: cfg.GasLimit,
+ GasLimit: new(big.Int).SetUint64(cfg.GasLimit),
GasPrice: new(big.Int),
}
diff --git a/core/vm/runtime/fuzz.go b/core/vm/runtime/fuzz.go
new file mode 100644
index 0000000000..de5b0f45d9
--- /dev/null
+++ b/core/vm/runtime/fuzz.go
@@ -0,0 +1,20 @@
+// +build gofuzz
+
+package runtime
+
+// Fuzz is the basic entry point for the go-fuzz tool
+//
+// This returns 1 for valid parsable/runable code, 0
+// for invalid opcode.
+func Fuzz(input []byte) int {
+ _, _, err := Execute(input, input, &Config{
+ GasLimit: 3000000,
+ })
+
+ // invalid opcode
+ if err != nil && len(err.Error()) > 6 && string(err.Error()[:7]) == "invalid" {
+ return 0
+ }
+
+ return 1
+}
diff --git a/core/vm/runtime/runtime.go b/core/vm/runtime/runtime.go
index b5adb982c3..94265626f2 100644
--- a/core/vm/runtime/runtime.go
+++ b/core/vm/runtime/runtime.go
@@ -17,6 +17,7 @@
package runtime
import (
+ "math"
"math/big"
"time"
@@ -37,7 +38,7 @@ type Config struct {
Coinbase common.Address
BlockNumber *big.Int
Time *big.Int
- GasLimit *big.Int
+ GasLimit uint64
GasPrice *big.Int
Value *big.Int
DisableJit bool // "disable" so it's enabled by default
@@ -68,8 +69,8 @@ func setDefaults(cfg *Config) {
if cfg.Time == nil {
cfg.Time = big.NewInt(time.Now().Unix())
}
- if cfg.GasLimit == nil {
- cfg.GasLimit = new(big.Int).Set(common.MaxBig)
+ if cfg.GasLimit == 0 {
+ cfg.GasLimit = math.MaxUint64
}
if cfg.GasPrice == nil {
cfg.GasPrice = new(big.Int)
@@ -104,17 +105,17 @@ func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) {
cfg.State, _ = state.New(common.Hash{}, db)
}
var (
- vmenv = NewEnv(cfg, cfg.State)
- sender = cfg.State.CreateAccount(cfg.Origin)
- receiver = cfg.State.CreateAccount(common.StringToAddress("contract"))
+ address = common.StringToAddress("contract")
+ vmenv = NewEnv(cfg, cfg.State)
+ sender = vm.AccountRef(cfg.Origin)
)
+ cfg.State.CreateAccount(address)
// set the receiver's (the executing contract) code for execution.
- receiver.SetCode(crypto.Keccak256Hash(code), code)
-
+ cfg.State.SetCode(address, code)
// Call the code with the given configuration.
- ret, err := vmenv.Call(
+ ret, _, err := vmenv.Call(
sender,
- receiver.Address(),
+ common.StringToAddress("contract"),
input,
cfg.GasLimit,
cfg.Value,
@@ -136,16 +137,17 @@ func Create(input []byte, cfg *Config) ([]byte, common.Address, error) {
}
var (
vmenv = NewEnv(cfg, cfg.State)
- sender = cfg.State.CreateAccount(cfg.Origin)
+ sender = vm.AccountRef(cfg.Origin)
)
// Call the code with the given configuration.
- return vmenv.Create(
+ code, address, _, err := vmenv.Create(
sender,
input,
cfg.GasLimit,
cfg.Value,
)
+ return code, address, err
}
// Call executes the code given by the contract's address. It will return the
@@ -160,7 +162,7 @@ func Call(address common.Address, input []byte, cfg *Config) ([]byte, error) {
sender := cfg.State.GetOrNewStateObject(cfg.Origin)
// Call the code with the given configuration.
- ret, err := vmenv.Call(
+ ret, _, err := vmenv.Call(
sender,
address,
input,
diff --git a/core/vm/runtime/runtime_test.go b/core/vm/runtime/runtime_test.go
index 1e618b688a..fe39e97a01 100644
--- a/core/vm/runtime/runtime_test.go
+++ b/core/vm/runtime/runtime_test.go
@@ -39,8 +39,8 @@ func TestDefaults(t *testing.T) {
if cfg.Time == nil {
t.Error("expected time to be non nil")
}
- if cfg.GasLimit == nil {
- t.Error("expected time to be non nil")
+ if cfg.GasLimit == 0 {
+ t.Error("didn't expect gaslimit to be zero")
}
if cfg.GasPrice == nil {
t.Error("expected time to be non nil")
@@ -87,7 +87,7 @@ func TestExecute(t *testing.T) {
t.Fatal("didn't expect error", err)
}
- num := common.BytesToBig(ret)
+ num := new(big.Int).SetBytes(ret)
if num.Cmp(big.NewInt(10)) != 0 {
t.Error("Expected 10, got", num)
}
@@ -111,7 +111,7 @@ func TestCall(t *testing.T) {
t.Fatal("didn't expect error", err)
}
- num := common.BytesToBig(ret)
+ num := new(big.Int).SetBytes(ret)
if num.Cmp(big.NewInt(10)) != 0 {
t.Error("Expected 10, got", num)
}
diff --git a/core/vm/stack_table.go b/core/vm/stack_table.go
index eed8805f23..ddc41fed23 100644
--- a/core/vm/stack_table.go
+++ b/core/vm/stack_table.go
@@ -6,13 +6,13 @@ import (
"github.com/ethereum/go-ethereum/params"
)
-func makeStackFunc(pop, diff int) stackValidationFunc {
+func makeStackFunc(pop, push int) stackValidationFunc {
return func(stack *Stack) error {
if err := stack.require(pop); err != nil {
return err
}
- if int64(stack.len()+diff) > params.StackLimit.Int64() {
+ if stack.len()+push-pop > int(params.StackLimit) {
return fmt.Errorf("stack limit reached %d (%d)", stack.len(), params.StackLimit)
}
return nil
@@ -20,9 +20,9 @@ func makeStackFunc(pop, diff int) stackValidationFunc {
}
func makeDupStackFunc(n int) stackValidationFunc {
- return makeStackFunc(n, 1)
+ return makeStackFunc(n, n+1)
}
func makeSwapStackFunc(n int) stackValidationFunc {
- return makeStackFunc(n, 0)
+ return makeStackFunc(n, n)
}
diff --git a/core/vm/virtual_machine.go b/core/vm/virtual_machine.go
deleted file mode 100644
index 6291088846..0000000000
--- a/core/vm/virtual_machine.go
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright 2014 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see .
-
-package vm
-
-// VirtualMachine is an EVM interface
-type VirtualMachine interface {
- Run(*Contract, []byte) ([]byte, error)
-}
diff --git a/crypto/crypto.go b/crypto/crypto.go
index ce45ebd389..0b8c06008e 100644
--- a/crypto/crypto.go
+++ b/crypto/crypto.go
@@ -20,24 +20,24 @@ import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
- "crypto/sha256"
- "fmt"
+ "encoding/hex"
+ "errors"
"io"
"io/ioutil"
"math/big"
"os"
- "encoding/hex"
- "errors"
-
"github.com/ethereum/go-ethereum/common"
- "github.com/ethereum/go-ethereum/crypto/ecies"
- "github.com/ethereum/go-ethereum/crypto/secp256k1"
"github.com/ethereum/go-ethereum/crypto/sha3"
"github.com/ethereum/go-ethereum/rlp"
- "golang.org/x/crypto/ripemd160"
)
+var (
+ secp256k1_N, _ = new(big.Int).SetString("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", 16)
+ secp256k1_halfN = new(big.Int).Div(secp256k1_N, big.NewInt(2))
+)
+
+// Keccak256 calculates and returns the Keccak256 hash of the input data.
func Keccak256(data ...[]byte) []byte {
d := sha3.NewKeccak256()
for _, b := range data {
@@ -46,6 +46,8 @@ func Keccak256(data ...[]byte) []byte {
return d.Sum(nil)
}
+// Keccak256Hash calculates and returns the Keccak256 hash of the input data,
+// converting it to an internal Hash data structure.
func Keccak256Hash(data ...[]byte) (h common.Hash) {
d := sha3.NewKeccak256()
for _, b := range data {
@@ -55,8 +57,16 @@ func Keccak256Hash(data ...[]byte) (h common.Hash) {
return h
}
+// Keccak512 calculates and returns the Keccak512 hash of the input data.
+func Keccak512(data ...[]byte) []byte {
+ d := sha3.NewKeccak512()
+ for _, b := range data {
+ d.Write(b)
+ }
+ return d.Sum(nil)
+}
+
// Deprecated: For backward compatibility as other packages depend on these
-func Sha3(data ...[]byte) []byte { return Keccak256(data...) }
func Sha3Hash(data ...[]byte) common.Hash { return Keccak256Hash(data...) }
// Creates an ethereum address given the bytes and the nonce
@@ -65,39 +75,16 @@ func CreateAddress(b common.Address, nonce uint64) common.Address {
return common.BytesToAddress(Keccak256(data)[12:])
}
-func Sha256(data []byte) []byte {
- hash := sha256.Sum256(data)
-
- return hash[:]
-}
-
-func Ripemd160(data []byte) []byte {
- ripemd := ripemd160.New()
- ripemd.Write(data)
-
- return ripemd.Sum(nil)
-}
-
-// Ecrecover returns the public key for the private key that was used to
-// calculate the signature.
-//
-// Note: secp256k1 expects the recover id to be either 0, 1. Ethereum
-// signatures have a recover id with an offset of 27. Callers must take
-// this into account and if "recovering" from an Ethereum signature adjust.
-func Ecrecover(hash, sig []byte) ([]byte, error) {
- return secp256k1.RecoverPubkey(hash, sig)
-}
-
-// New methods using proper ecdsa keys from the stdlib
+// ToECDSA creates a private key with the given D value.
func ToECDSA(prv []byte) *ecdsa.PrivateKey {
if len(prv) == 0 {
return nil
}
priv := new(ecdsa.PrivateKey)
- priv.PublicKey.Curve = secp256k1.S256()
- priv.D = common.BigD(prv)
- priv.PublicKey.X, priv.PublicKey.Y = secp256k1.S256().ScalarBaseMult(prv)
+ priv.PublicKey.Curve = S256()
+ priv.D = new(big.Int).SetBytes(prv)
+ priv.PublicKey.X, priv.PublicKey.Y = priv.PublicKey.Curve.ScalarBaseMult(prv)
return priv
}
@@ -112,15 +99,15 @@ func ToECDSAPub(pub []byte) *ecdsa.PublicKey {
if len(pub) == 0 {
return nil
}
- x, y := elliptic.Unmarshal(secp256k1.S256(), pub)
- return &ecdsa.PublicKey{Curve: secp256k1.S256(), X: x, Y: y}
+ x, y := elliptic.Unmarshal(S256(), pub)
+ return &ecdsa.PublicKey{Curve: S256(), X: x, Y: y}
}
func FromECDSAPub(pub *ecdsa.PublicKey) []byte {
if pub == nil || pub.X == nil || pub.Y == nil {
return nil
}
- return elliptic.Marshal(secp256k1.S256(), pub.X, pub.Y)
+ return elliptic.Marshal(S256(), pub.X, pub.Y)
}
// HexToECDSA parses a secp256k1 private key.
@@ -164,7 +151,7 @@ func SaveECDSA(file string, key *ecdsa.PrivateKey) error {
}
func GenerateKey() (*ecdsa.PrivateKey, error) {
- return ecdsa.GenerateKey(secp256k1.S256(), rand.Reader)
+ return ecdsa.GenerateKey(S256(), rand.Reader)
}
// ValidateSignatureValues verifies whether the signature values are valid with
@@ -175,49 +162,11 @@ func ValidateSignatureValues(v byte, r, s *big.Int, homestead bool) bool {
}
// reject upper range of s values (ECDSA malleability)
// see discussion in secp256k1/libsecp256k1/include/secp256k1.h
- if homestead && s.Cmp(secp256k1.HalfN) > 0 {
+ if homestead && s.Cmp(secp256k1_halfN) > 0 {
return false
}
// Frontier: allow s to be in full N range
- return r.Cmp(secp256k1.N) < 0 && s.Cmp(secp256k1.N) < 0 && (v == 0 || v == 1)
-}
-
-func SigToPub(hash, sig []byte) (*ecdsa.PublicKey, error) {
- s, err := Ecrecover(hash, sig)
- if err != nil {
- return nil, err
- }
-
- x, y := elliptic.Unmarshal(secp256k1.S256(), s)
- return &ecdsa.PublicKey{Curve: secp256k1.S256(), X: x, Y: y}, nil
-}
-
-// Sign calculates an ECDSA signature.
-//
-// This function is susceptible to chosen plaintext attacks that can leak
-// information about the private key that is used for signing. Callers must
-// be aware that the given hash cannot be chosen by an adversery. Common
-// solution is to hash any input before calculating the signature.
-//
-// The produced signature is in the [R || S || V] format where V is 0 or 1.
-func Sign(data []byte, prv *ecdsa.PrivateKey) (sig []byte, err error) {
- if len(data) != 32 {
- return nil, fmt.Errorf("hash is required to be exactly 32 bytes (%d)", len(data))
- }
-
- seckey := common.LeftPadBytes(prv.D.Bytes(), prv.Params().BitSize/8)
- defer zeroBytes(seckey)
- sig, err = secp256k1.Sign(data, seckey)
- return
-}
-
-func Encrypt(pub *ecdsa.PublicKey, message []byte) ([]byte, error) {
- return ecies.Encrypt(rand.Reader, ecies.ImportECDSAPublic(pub), message, nil, nil)
-}
-
-func Decrypt(prv *ecdsa.PrivateKey, ct []byte) ([]byte, error) {
- key := ecies.ImportECDSA(prv)
- return key.Decrypt(rand.Reader, ct, nil, nil)
+ return r.Cmp(secp256k1_N) < 0 && s.Cmp(secp256k1_N) < 0 && (v == 0 || v == 1)
}
func PubkeyToAddress(p ecdsa.PublicKey) common.Address {
diff --git a/crypto/crypto_test.go b/crypto/crypto_test.go
index d4d3098494..e518ac22d8 100644
--- a/crypto/crypto_test.go
+++ b/crypto/crypto_test.go
@@ -28,7 +28,6 @@ import (
"time"
"github.com/ethereum/go-ethereum/common"
- "github.com/ethereum/go-ethereum/crypto/secp256k1"
)
var testAddrHex = "970e8128ab834e8eac17ab8e3812f010678cf791"
@@ -37,30 +36,12 @@ var testPrivHex = "289c2857d4598e37fb9647507e47a309d6133539bf21a8b9cb6df88fd5232
// These tests are sanity checks.
// They should ensure that we don't e.g. use Sha3-224 instead of Sha3-256
// and that the sha3 library uses keccak-f permutation.
-func TestSha3(t *testing.T) {
- msg := []byte("abc")
- exp, _ := hex.DecodeString("4e03657aea45a94fc7d47ba826c8d667c0d1e6e33a64a036ec44f58fa12d6c45")
- checkhash(t, "Sha3-256", func(in []byte) []byte { return Keccak256(in) }, msg, exp)
-}
-
func TestSha3Hash(t *testing.T) {
msg := []byte("abc")
exp, _ := hex.DecodeString("4e03657aea45a94fc7d47ba826c8d667c0d1e6e33a64a036ec44f58fa12d6c45")
checkhash(t, "Sha3-256-array", func(in []byte) []byte { h := Keccak256Hash(in); return h[:] }, msg, exp)
}
-func TestSha256(t *testing.T) {
- msg := []byte("abc")
- exp, _ := hex.DecodeString("ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad")
- checkhash(t, "Sha256", Sha256, msg, exp)
-}
-
-func TestRipemd160(t *testing.T) {
- msg := []byte("abc")
- exp, _ := hex.DecodeString("8eb208f7e05d987a9b044a8e98c6b087f15a0bfc")
- checkhash(t, "Ripemd160", Ripemd160, msg, exp)
-}
-
func BenchmarkSha3(b *testing.B) {
a := []byte("hello world")
amount := 1000000
@@ -170,7 +151,7 @@ func TestValidateSignatureValues(t *testing.T) {
minusOne := big.NewInt(-1)
one := common.Big1
zero := common.Big0
- secp256k1nMinus1 := new(big.Int).Sub(secp256k1.N, common.Big1)
+ secp256k1nMinus1 := new(big.Int).Sub(secp256k1_N, common.Big1)
// correct v,r,s
check(true, 0, one, one)
@@ -197,9 +178,9 @@ func TestValidateSignatureValues(t *testing.T) {
// correct sig with max r,s
check(true, 0, secp256k1nMinus1, secp256k1nMinus1)
// correct v, combinations of incorrect r,s at upper limit
- check(false, 0, secp256k1.N, secp256k1nMinus1)
- check(false, 0, secp256k1nMinus1, secp256k1.N)
- check(false, 0, secp256k1.N, secp256k1.N)
+ check(false, 0, secp256k1_N, secp256k1nMinus1)
+ check(false, 0, secp256k1nMinus1, secp256k1_N)
+ check(false, 0, secp256k1_N, secp256k1_N)
// current callers ensures r,s cannot be negative, but let's test for that too
// as crypto package could be used stand-alone
@@ -225,14 +206,13 @@ func checkAddr(t *testing.T, addr0, addr1 common.Address) {
func TestPythonIntegration(t *testing.T) {
kh := "289c2857d4598e37fb9647507e47a309d6133539bf21a8b9cb6df88fd5232032"
k0, _ := HexToECDSA(kh)
- k1 := FromECDSA(k0)
msg0 := Keccak256([]byte("foo"))
- sig0, _ := secp256k1.Sign(msg0, k1)
+ sig0, _ := Sign(msg0, k0)
msg1 := common.FromHex("00000000000000000000000000000000")
- sig1, _ := secp256k1.Sign(msg0, k1)
+ sig1, _ := Sign(msg0, k0)
- fmt.Printf("msg: %x, privkey: %x sig: %x\n", msg0, k1, sig0)
- fmt.Printf("msg: %x, privkey: %x sig: %x\n", msg1, k1, sig1)
+ t.Logf("msg: %x, privkey: %s sig: %x\n", msg0, kh, sig0)
+ t.Logf("msg: %x, privkey: %s sig: %x\n", msg1, kh, sig1)
}
diff --git a/crypto/ecies/asn1.go b/crypto/ecies/asn1.go
index 508a645cdf..d3e77d8490 100644
--- a/crypto/ecies/asn1.go
+++ b/crypto/ecies/asn1.go
@@ -42,7 +42,7 @@ import (
"hash"
"math/big"
- "github.com/ethereum/go-ethereum/crypto/secp256k1"
+ ethcrypto "github.com/ethereum/go-ethereum/crypto"
)
var (
@@ -120,7 +120,7 @@ func (curve secgNamedCurve) Equal(curve2 secgNamedCurve) bool {
func namedCurveFromOID(curve secgNamedCurve) elliptic.Curve {
switch {
case curve.Equal(secgNamedCurveS256):
- return secp256k1.S256()
+ return ethcrypto.S256()
case curve.Equal(secgNamedCurveP256):
return elliptic.P256()
case curve.Equal(secgNamedCurveP384):
@@ -139,7 +139,7 @@ func oidFromNamedCurve(curve elliptic.Curve) (secgNamedCurve, bool) {
return secgNamedCurveP384, true
case elliptic.P521():
return secgNamedCurveP521, true
- case secp256k1.S256():
+ case ethcrypto.S256():
return secgNamedCurveS256, true
}
diff --git a/crypto/ecies/ecies_test.go b/crypto/ecies/ecies_test.go
index 3b3517baf3..7c454aa730 100644
--- a/crypto/ecies/ecies_test.go
+++ b/crypto/ecies/ecies_test.go
@@ -31,7 +31,6 @@ package ecies
import (
"bytes"
- "crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/sha256"
@@ -42,7 +41,7 @@ import (
"math/big"
"testing"
- "github.com/ethereum/go-ethereum/crypto/secp256k1"
+ "github.com/ethereum/go-ethereum/crypto"
)
var dumpEnc bool
@@ -150,7 +149,7 @@ func TestSharedKey(t *testing.T) {
func TestSharedKeyPadding(t *testing.T) {
// sanity checks
prv0 := hexKey("1adf5c18167d96a1f9a0b1ef63be8aa27eaf6032c233b2b38f7850cf5b859fd9")
- prv1 := hexKey("97a076fc7fcd9208240668e31c9abee952cbb6e375d1b8febc7499d6e16f1a")
+ prv1 := hexKey("0097a076fc7fcd9208240668e31c9abee952cbb6e375d1b8febc7499d6e16f1a")
x0, _ := new(big.Int).SetString("1a8ed022ff7aec59dc1b440446bdda5ff6bcb3509a8b109077282b361efffbd8", 16)
x1, _ := new(big.Int).SetString("6ab3ac374251f638d0abb3ef596d1dc67955b507c104e5f2009724812dc027b8", 16)
y0, _ := new(big.Int).SetString("e040bd480b1deccc3bc40bd5b1fdcb7bfd352500b477cb9471366dbd4493f923", 16)
@@ -354,7 +353,7 @@ func BenchmarkGenSharedKeyP256(b *testing.B) {
// Benchmark the generation of S256 shared keys.
func BenchmarkGenSharedKeyS256(b *testing.B) {
- prv, err := GenerateKey(rand.Reader, secp256k1.S256(), nil)
+ prv, err := GenerateKey(rand.Reader, crypto.S256(), nil)
if err != nil {
fmt.Println(err.Error())
b.FailNow()
@@ -597,6 +596,29 @@ func TestBasicKeyValidation(t *testing.T) {
}
}
+func TestBox(t *testing.T) {
+ prv1 := hexKey("4b50fa71f5c3eeb8fdc452224b2395af2fcc3d125e06c32c82e048c0559db03f")
+ prv2 := hexKey("d0b043b4c5d657670778242d82d68a29d25d7d711127d17b8e299f156dad361a")
+ pub2 := &prv2.PublicKey
+
+ message := []byte("Hello, world.")
+ ct, err := Encrypt(rand.Reader, pub2, message, nil, nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ pt, err := prv2.Decrypt(rand.Reader, ct, nil, nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !bytes.Equal(pt, message) {
+ t.Fatal("ecies: plaintext doesn't match message")
+ }
+ if _, err = prv1.Decrypt(rand.Reader, ct, nil, nil); err == nil {
+ t.Fatal("ecies: encryption should not have succeeded")
+ }
+}
+
// Verify GenerateShared against static values - useful when
// debugging changes in underlying libs
func TestSharedKeyStatic(t *testing.T) {
@@ -628,11 +650,10 @@ func TestSharedKeyStatic(t *testing.T) {
}
}
-// TODO: remove after refactoring packages crypto and crypto/ecies
func hexKey(prv string) *PrivateKey {
- priv := new(ecdsa.PrivateKey)
- priv.PublicKey.Curve = secp256k1.S256()
- priv.D, _ = new(big.Int).SetString(prv, 16)
- priv.PublicKey.X, priv.PublicKey.Y = secp256k1.S256().ScalarBaseMult(priv.D.Bytes())
- return ImportECDSA(priv)
+ key, err := crypto.HexToECDSA(prv)
+ if err != nil {
+ panic(err)
+ }
+ return ImportECDSA(key)
}
diff --git a/crypto/ecies/params.go b/crypto/ecies/params.go
index 511c53ebc0..826d90c845 100644
--- a/crypto/ecies/params.go
+++ b/crypto/ecies/params.go
@@ -42,11 +42,11 @@ import (
"fmt"
"hash"
- "github.com/ethereum/go-ethereum/crypto/secp256k1"
+ ethcrypto "github.com/ethereum/go-ethereum/crypto"
)
var (
- DefaultCurve = secp256k1.S256()
+ DefaultCurve = ethcrypto.S256()
ErrUnsupportedECDHAlgorithm = fmt.Errorf("ecies: unsupported ECDH algorithm")
ErrUnsupportedECIESParameters = fmt.Errorf("ecies: unsupported ECIES parameters")
)
@@ -100,7 +100,7 @@ var (
)
var paramsFromCurve = map[elliptic.Curve]*ECIESParams{
- secp256k1.S256(): ECIES_AES128_SHA256,
+ ethcrypto.S256(): ECIES_AES128_SHA256,
elliptic.P256(): ECIES_AES128_SHA256,
elliptic.P384(): ECIES_AES256_SHA384,
elliptic.P521(): ECIES_AES256_SHA512,
diff --git a/crypto/encrypt_decrypt_test.go b/crypto/encrypt_decrypt_test.go
deleted file mode 100644
index fcf40b70fd..0000000000
--- a/crypto/encrypt_decrypt_test.go
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright 2014 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see .
-
-package crypto
-
-import (
- "bytes"
- "fmt"
- "testing"
-
- "github.com/ethereum/go-ethereum/common"
-)
-
-func TestBox(t *testing.T) {
- prv1 := ToECDSA(common.Hex2Bytes("4b50fa71f5c3eeb8fdc452224b2395af2fcc3d125e06c32c82e048c0559db03f"))
- prv2 := ToECDSA(common.Hex2Bytes("d0b043b4c5d657670778242d82d68a29d25d7d711127d17b8e299f156dad361a"))
- pub2 := ToECDSAPub(common.Hex2Bytes("04bd27a63c91fe3233c5777e6d3d7b39204d398c8f92655947eb5a373d46e1688f022a1632d264725cbc7dc43ee1cfebde42fa0a86d08b55d2acfbb5e9b3b48dc5"))
-
- message := []byte("Hello, world.")
- ct, err := Encrypt(pub2, message)
- if err != nil {
- fmt.Println(err.Error())
- t.FailNow()
- }
-
- pt, err := Decrypt(prv2, ct)
- if err != nil {
- fmt.Println(err.Error())
- t.FailNow()
- }
-
- if !bytes.Equal(pt, message) {
- fmt.Println("ecies: plaintext doesn't match message")
- t.FailNow()
- }
-
- _, err = Decrypt(prv1, pt)
- if err == nil {
- fmt.Println("ecies: encryption should not have succeeded")
- t.FailNow()
- }
-
-}
diff --git a/crypto/secp256k1/curve.go b/crypto/secp256k1/curve.go
index 61cad54636..ec6d266cec 100644
--- a/crypto/secp256k1/curve.go
+++ b/crypto/secp256k1/curve.go
@@ -36,6 +36,8 @@ import (
"math/big"
"sync"
"unsafe"
+
+ "github.com/ethereum/go-ethereum/common/math"
)
/*
@@ -230,8 +232,8 @@ func (BitCurve *BitCurve) ScalarMult(Bx, By *big.Int, scalar []byte) (*big.Int,
// Do the multiplication in C, updating point.
point := make([]byte, 64)
- readBits(point[:32], Bx)
- readBits(point[32:], By)
+ math.ReadBits(Bx, point[:32])
+ math.ReadBits(By, point[32:])
pointPtr := (*C.uchar)(unsafe.Pointer(&point[0]))
scalarPtr := (*C.uchar)(unsafe.Pointer(&scalar[0]))
res := C.secp256k1_pubkey_scalar_mul(context, pointPtr, scalarPtr)
diff --git a/crypto/secp256k1/curve_test.go b/crypto/secp256k1/curve_test.go
deleted file mode 100644
index d915ee8525..0000000000
--- a/crypto/secp256k1/curve_test.go
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright 2015 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see .
-
-package secp256k1
-
-import (
- "bytes"
- "encoding/hex"
- "math/big"
- "testing"
-)
-
-func TestReadBits(t *testing.T) {
- check := func(input string) {
- want, _ := hex.DecodeString(input)
- int, _ := new(big.Int).SetString(input, 16)
- buf := make([]byte, len(want))
- readBits(buf, int)
- if !bytes.Equal(buf, want) {
- t.Errorf("have: %x\nwant: %x", buf, want)
- }
- }
- check("000000000000000000000000000000000000000000000000000000FEFCF3F8F0")
- check("0000000000012345000000000000000000000000000000000000FEFCF3F8F0")
- check("18F8F8F1000111000110011100222004330052300000000000000000FEFCF3F8F0")
-}
diff --git a/crypto/secp256k1/secp256.go b/crypto/secp256k1/secp256.go
index 4284115e2d..0ffa04fe09 100644
--- a/crypto/secp256k1/secp256.go
+++ b/crypto/secp256k1/secp256.go
@@ -38,21 +38,12 @@ import "C"
import (
"errors"
- "math/big"
"unsafe"
)
-var (
- context *C.secp256k1_context
- N *big.Int
- HalfN *big.Int
-)
+var context *C.secp256k1_context
func init() {
- N, _ = new(big.Int).SetString("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", 16)
- // N / 2 == 57896044618658097711785492504343953926418782139537452191302581570759080747168
- HalfN, _ = new(big.Int).SetString("7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0", 16)
-
// around 20 ms on a modern CPU.
context = C.secp256k1_context_create_sign_verify()
C.secp256k1_context_set_illegal_callback(context, C.callbackFunc(C.secp256k1GoPanicIllegal), nil)
@@ -137,16 +128,3 @@ func checkSignature(sig []byte) error {
}
return nil
}
-
-// reads num into buf as big-endian bytes.
-func readBits(buf []byte, num *big.Int) {
- const wordLen = int(unsafe.Sizeof(big.Word(0)))
- i := len(buf)
- for _, d := range num.Bits() {
- for j := 0; j < wordLen && i > 0; j++ {
- i--
- buf[i] = byte(d)
- d >>= 8
- }
- }
-}
diff --git a/crypto/secp256k1/secp256_test.go b/crypto/secp256k1/secp256_test.go
index 287ab512ec..f6582ecd54 100644
--- a/crypto/secp256k1/secp256_test.go
+++ b/crypto/secp256k1/secp256_test.go
@@ -24,6 +24,7 @@ import (
"encoding/hex"
"testing"
+ "github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/crypto/randentropy"
)
@@ -35,9 +36,7 @@ func generateKeyPair() (pubkey, privkey []byte) {
panic(err)
}
pubkey = elliptic.Marshal(S256(), key.X, key.Y)
- privkey = make([]byte, 32)
- readBits(privkey, key.D)
- return pubkey, privkey
+ return pubkey, math.PaddedBigBytes(key.D, 32)
}
func randSig() []byte {
diff --git a/crypto/sha3/hashes.go b/crypto/sha3/hashes.go
index 669cd5543c..fa0d7b4362 100644
--- a/crypto/sha3/hashes.go
+++ b/crypto/sha3/hashes.go
@@ -15,6 +15,9 @@ import (
// NewKeccak256 creates a new Keccak-256 hash.
func NewKeccak256() hash.Hash { return &state{rate: 136, outputLen: 32, dsbyte: 0x01} }
+// NewKeccak512 creates a new Keccak-512 hash.
+func NewKeccak512() hash.Hash { return &state{rate: 72, outputLen: 64, dsbyte: 0x01} }
+
// New224 creates a new SHA3-224 hash.
// Its generic security strength is 224 bits against preimage attacks,
// and 112 bits against collision attacks.
diff --git a/crypto/sha3/keccakf_amd64.s b/crypto/sha3/keccakf_amd64.s
index a35335178e..f88533accd 100644
--- a/crypto/sha3/keccakf_amd64.s
+++ b/crypto/sha3/keccakf_amd64.s
@@ -322,7 +322,6 @@
// func keccakF1600(state *[25]uint64)
TEXT ·keccakF1600(SB), 0, $200-8
MOVQ state+0(FP), rpState
- SUBQ $(8*25), SP
// Convert the user state into an internal state
NOTQ _be(rpState)
@@ -388,5 +387,4 @@ TEXT ·keccakF1600(SB), 0, $200-8
NOTQ _mi(rpState)
NOTQ _sa(rpState)
- ADDQ $(8*25), SP
RET
diff --git a/crypto/signature_cgo.go b/crypto/signature_cgo.go
new file mode 100644
index 0000000000..d1485de08c
--- /dev/null
+++ b/crypto/signature_cgo.go
@@ -0,0 +1,64 @@
+// Copyright 2016 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+// +build !nacl,!js,!nocgo
+
+package crypto
+
+import (
+ "crypto/ecdsa"
+ "crypto/elliptic"
+ "fmt"
+
+ "github.com/ethereum/go-ethereum/common/math"
+ "github.com/ethereum/go-ethereum/crypto/secp256k1"
+)
+
+func Ecrecover(hash, sig []byte) ([]byte, error) {
+ return secp256k1.RecoverPubkey(hash, sig)
+}
+
+func SigToPub(hash, sig []byte) (*ecdsa.PublicKey, error) {
+ s, err := Ecrecover(hash, sig)
+ if err != nil {
+ return nil, err
+ }
+
+ x, y := elliptic.Unmarshal(S256(), s)
+ return &ecdsa.PublicKey{Curve: S256(), X: x, Y: y}, nil
+}
+
+// Sign calculates an ECDSA signature.
+//
+// This function is susceptible to chosen plaintext attacks that can leak
+// information about the private key that is used for signing. Callers must
+// be aware that the given hash cannot be chosen by an adversery. Common
+// solution is to hash any input before calculating the signature.
+//
+// The produced signature is in the [R || S || V] format where V is 0 or 1.
+func Sign(hash []byte, prv *ecdsa.PrivateKey) (sig []byte, err error) {
+ if len(hash) != 32 {
+ return nil, fmt.Errorf("hash is required to be exactly 32 bytes (%d)", len(hash))
+ }
+ seckey := math.PaddedBigBytes(prv.D, prv.Params().BitSize/8)
+ defer zeroBytes(seckey)
+ return secp256k1.Sign(hash, seckey)
+}
+
+// S256 returns an instance of the secp256k1 curve.
+func S256() elliptic.Curve {
+ return secp256k1.S256()
+}
diff --git a/crypto/signature_nocgo.go b/crypto/signature_nocgo.go
new file mode 100644
index 0000000000..47880aaf4d
--- /dev/null
+++ b/crypto/signature_nocgo.go
@@ -0,0 +1,77 @@
+// Copyright 2016 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+// +build nacl js nocgo
+
+package crypto
+
+import (
+ "crypto/ecdsa"
+ "crypto/elliptic"
+ "fmt"
+
+ "github.com/btcsuite/btcd/btcec"
+)
+
+func Ecrecover(hash, sig []byte) ([]byte, error) {
+ pub, err := SigToPub(hash, sig)
+ if err != nil {
+ return nil, err
+ }
+ bytes := (*btcec.PublicKey)(pub).SerializeUncompressed()
+ return bytes, err
+}
+
+func SigToPub(hash, sig []byte) (*ecdsa.PublicKey, error) {
+ // Convert to btcec input format with 'recovery id' v at the beginning.
+ btcsig := make([]byte, 65)
+ btcsig[0] = sig[64] + 27
+ copy(btcsig[1:], sig)
+
+ pub, _, err := btcec.RecoverCompact(btcec.S256(), btcsig, hash)
+ return (*ecdsa.PublicKey)(pub), err
+}
+
+// Sign calculates an ECDSA signature.
+//
+// This function is susceptible to chosen plaintext attacks that can leak
+// information about the private key that is used for signing. Callers must
+// be aware that the given hash cannot be chosen by an adversery. Common
+// solution is to hash any input before calculating the signature.
+//
+// The produced signature is in the [R || S || V] format where V is 0 or 1.
+func Sign(hash []byte, prv *ecdsa.PrivateKey) ([]byte, error) {
+ if len(hash) != 32 {
+ return nil, fmt.Errorf("hash is required to be exactly 32 bytes (%d)", len(hash))
+ }
+ if prv.Curve != btcec.S256() {
+ return nil, fmt.Errorf("private key curve is not secp256k1")
+ }
+ sig, err := btcec.SignCompact(btcec.S256(), (*btcec.PrivateKey)(prv), hash, false)
+ if err != nil {
+ return nil, err
+ }
+ // Convert to Ethereum signature format with 'recovery id' v at the end.
+ v := sig[0] - 27
+ copy(sig, sig[1:])
+ sig[64] = v
+ return sig, nil
+}
+
+// S256 returns an instance of the secp256k1 curve.
+func S256() elliptic.Curve {
+ return btcec.S256()
+}
diff --git a/common/math/exp.go b/crypto/signature_test.go
similarity index 53%
rename from common/math/exp.go
rename to crypto/signature_test.go
index 6f6c040e07..ca7eefe992 100644
--- a/common/math/exp.go
+++ b/crypto/signature_test.go
@@ -14,31 +14,23 @@
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see .
-package math
+package crypto
import (
- "math/big"
-
- "github.com/ethereum/go-ethereum/common"
+ "bytes"
+ "encoding/hex"
+ "testing"
)
-// wordSize is the size number of bits in a big.Int Word.
-const wordSize = 32 << (uint64(^big.Word(0)) >> 63)
-
-// Exp implement exponentiation by squaring algorithm.
-//
-// Courtesy @karalabe and @chfast
-func Exp(base, exponent *big.Int) *big.Int {
- result := big.NewInt(1)
-
- for _, word := range exponent.Bits() {
- for i := 0; i < wordSize; i++ {
- if word&1 == 1 {
- common.U256(result.Mul(result, base))
- }
- common.U256(base.Mul(base, base))
- word >>= 1
- }
+func TestRecoverSanity(t *testing.T) {
+ msg, _ := hex.DecodeString("ce0677bb30baa8cf067c88db9811f4333d131bf8bcf12fe7065d211dce971008")
+ sig, _ := hex.DecodeString("90f27b8b488db00b00606796d2987f6a5f59ae62ea05effe84fef5b8b0e549984a691139ad57a3f0b906637673aa2f63d1f55cb1a69199d4009eea23ceaddc9301")
+ pubkey1, _ := hex.DecodeString("04e32df42865e97135acfb65f3bae71bdc86f4d49150ad6a440b6f15878109880a0a2b2667f7e725ceea70c673093bf67663e0312623c8e091b13cf2c0f11ef652")
+ pubkey2, err := Ecrecover(msg, sig)
+ if err != nil {
+ t.Fatalf("recover error: %s", err)
+ }
+ if !bytes.Equal(pubkey1, pubkey2) {
+ t.Errorf("pubkey mismatch: want: %x have: %x", pubkey1, pubkey2)
}
- return result
}
diff --git a/errs/errors.go b/errs/errors.go
deleted file mode 100644
index daa814db71..0000000000
--- a/errs/errors.go
+++ /dev/null
@@ -1,88 +0,0 @@
-// Copyright 2015 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see .
-
-package errs
-
-import (
- "fmt"
-
- "github.com/ethereum/go-ethereum/logger/glog"
-)
-
-/*
-Errors implements an error handler providing standardised errors for a package.
-Fields:
-
- Errors:
- a map from error codes to description
-
- Package:
- name of the package/component
-*/
-type Errors struct {
- Errors map[int]string
- Package string
-}
-
-/*
-Error implements the standard go error interface.
-
- errors.New(code, format, params ...interface{})
-
-Prints as:
-
- [package] description: details
-
-where details is fmt.Sprintf(self.format, self.params...)
-*/
-type Error struct {
- Code int
- Name string
- Package string
- message string
- format string
- params []interface{}
-}
-
-func (self *Errors) New(code int, format string, params ...interface{}) *Error {
- name, ok := self.Errors[code]
- if !ok {
- panic("invalid error code")
- }
- return &Error{
- Code: code,
- Name: name,
- Package: self.Package,
- format: format,
- params: params,
- }
-}
-
-func (self Error) Error() (message string) {
- if len(message) == 0 {
- self.message = fmt.Sprintf("[%s] ERROR: %s", self.Package, self.Name)
- if self.format != "" {
- self.message += ": " + fmt.Sprintf(self.format, self.params...)
- }
- }
- return self.message
-}
-
-func (self Error) Log(v glog.Verbose) {
- if v {
- v.Infoln(self)
- }
-}
diff --git a/eth/api.go b/eth/api.go
index 07df0b79e3..b64153fd72 100644
--- a/eth/api.go
+++ b/eth/api.go
@@ -19,6 +19,7 @@ package eth
import (
"bytes"
"compress/gzip"
+ "context"
"errors"
"fmt"
"io"
@@ -29,7 +30,6 @@ import (
"strings"
"time"
- "github.com/ethereum/ethash"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core"
@@ -37,13 +37,9 @@ import (
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/internal/ethapi"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
"github.com/ethereum/go-ethereum/miner"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp"
- "github.com/ethereum/go-ethereum/rpc"
- "golang.org/x/net/context"
)
const defaultTraceTimeout = 5 * time.Second
@@ -104,17 +100,17 @@ func (s *PublicMinerAPI) SubmitWork(nonce types.BlockNonce, solution, digest com
// result[0], 32 bytes hex encoded current block header pow-hash
// result[1], 32 bytes hex encoded seed hash used for DAG
// result[2], 32 bytes hex encoded boundary condition ("target"), 2^256/difficulty
-func (s *PublicMinerAPI) GetWork() (work [3]string, err error) {
+func (s *PublicMinerAPI) GetWork() ([3]string, error) {
if !s.e.IsMining() {
if err := s.e.StartMining(0); err != nil {
- return work, err
+ return [3]string{}, err
}
}
- if work, err = s.agent.GetWork(); err == nil {
- return
+ work, err := s.agent.GetWork()
+ if err != nil {
+ return work, fmt.Errorf("mining not ready: %v", err)
}
- glog.V(logger.Debug).Infof("%v", err)
- return work, fmt.Errorf("mining not ready")
+ return work, nil
}
// SubmitHashrate can be used for remote miners to submit their hash rate. This enables the node to report the combined
@@ -139,7 +135,6 @@ func NewPrivateMinerAPI(e *Ethereum) *PrivateMinerAPI {
// Start the miner with the given number of threads. If threads is nil the number of
// workers started is equal to the number of logical CPU's that are usable by this process.
func (s *PrivateMinerAPI) Start(threads *int) (bool, error) {
- s.e.StartAutoDAG()
var err error
if threads == nil {
err = s.e.StartMining(runtime.NumCPU())
@@ -175,25 +170,9 @@ func (s *PrivateMinerAPI) SetEtherbase(etherbase common.Address) bool {
return true
}
-// StartAutoDAG starts auto DAG generation. This will prevent the DAG generating on epoch change
-// which will cause the node to stop mining during the generation process.
-func (s *PrivateMinerAPI) StartAutoDAG() bool {
- s.e.StartAutoDAG()
- return true
-}
-
-// StopAutoDAG stops auto DAG generation
-func (s *PrivateMinerAPI) StopAutoDAG() bool {
- s.e.StopAutoDAG()
- return true
-}
-
-// MakeDAG creates the new DAG for the given block number
-func (s *PrivateMinerAPI) MakeDAG(blockNr rpc.BlockNumber) (bool, error) {
- if err := ethash.MakeDAG(uint64(blockNr.Int64()), ""); err != nil {
- return false, err
- }
- return true, nil
+// GetHashrate returns the current hashrate of the miner.
+func (s *PrivateMinerAPI) GetHashrate() uint64 {
+ return uint64(s.e.miner.HashRate())
}
// PrivateAdminAPI is the collection of Etheruem full node-related APIs
@@ -566,3 +545,9 @@ func (api *PrivateDebugAPI) Preimage(ctx context.Context, hash common.Hash) (hex
db := core.PreimageTable(api.eth.ChainDb())
return db.Get(hash.Bytes())
}
+
+// GetBadBLocks returns a list of the last 'bad blocks' that the client has seen on the network
+// and returns them as a JSON list of block-hashes
+func (api *PrivateDebugAPI) GetBadBlocks(ctx context.Context) ([]core.BadBlockArgs, error) {
+ return api.eth.BlockChain().BadBlocks()
+}
diff --git a/eth/api_backend.go b/eth/api_backend.go
index 1174588ea7..418a344354 100644
--- a/eth/api_backend.go
+++ b/eth/api_backend.go
@@ -17,10 +17,12 @@
package eth
import (
+ "context"
"math/big"
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
@@ -32,7 +34,6 @@ import (
"github.com/ethereum/go-ethereum/internal/ethapi"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rpc"
- "golang.org/x/net/context"
)
// EthApiBackend implements ethapi.Backend for full nodes
@@ -50,6 +51,7 @@ func (b *EthApiBackend) CurrentBlock() *types.Block {
}
func (b *EthApiBackend) SetHead(number uint64) {
+ b.eth.protocolManager.downloader.Cancel()
b.eth.blockchain.SetHead(number)
}
@@ -106,14 +108,14 @@ func (b *EthApiBackend) GetTd(blockHash common.Hash) *big.Int {
return b.eth.blockchain.GetTdByHash(blockHash)
}
-func (b *EthApiBackend) GetVMEnv(ctx context.Context, msg core.Message, state ethapi.State, header *types.Header) (*vm.EVM, func() error, error) {
+func (b *EthApiBackend) GetEVM(ctx context.Context, msg core.Message, state ethapi.State, header *types.Header, vmCfg vm.Config) (*vm.EVM, func() error, error) {
statedb := state.(EthApiState).state
from := statedb.GetOrNewStateObject(msg.From())
- from.SetBalance(common.MaxBig)
+ from.SetBalance(math.MaxBig256)
vmError := func() error { return nil }
context := core.NewEVMContext(msg, header, b.eth.BlockChain())
- return vm.NewEVM(context, statedb, b.eth.chainConfig, vm.Config{}), vmError, nil
+ return vm.NewEVM(context, statedb, b.eth.chainConfig, vmCfg), vmError, nil
}
func (b *EthApiBackend) SendTx(ctx context.Context, signedTx *types.Transaction) error {
diff --git a/eth/backend.go b/eth/backend.go
index ef3ac93c89..b8df98976d 100644
--- a/eth/backend.go
+++ b/eth/backend.go
@@ -18,17 +18,12 @@
package eth
import (
- "errors"
"fmt"
"math/big"
- "os"
- "path/filepath"
"regexp"
- "strings"
"sync"
"time"
- "github.com/ethereum/ethash"
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
@@ -40,8 +35,7 @@ import (
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/internal/ethapi"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/miner"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/p2p"
@@ -64,27 +58,35 @@ var (
)
type Config struct {
- ChainConfig *params.ChainConfig // chain configuration
+ // The genesis block, which is inserted if the database is empty.
+ // If nil, the Ethereum main net block is used.
+ Genesis *core.Genesis
- NetworkId int // Network ID to use for selecting peers to connect to
- Genesis string // Genesis JSON to seed the chain database with
- FastSync bool // Enables the state download based fast synchronisation algorithm
- LightMode bool // Running in light client mode
- LightServ int // Maximum percentage of time allowed for serving LES requests
- LightPeers int // Maximum number of LES client peers
- MaxPeers int // Maximum number of global peers
+ NetworkId int // Network ID to use for selecting peers to connect to
+
+ FastSync bool // Enables the state download based fast synchronisation algorithm
+ LightMode bool // Running in light client mode
+ LightServ int // Maximum percentage of time allowed for serving LES requests
+ LightPeers int // Maximum number of LES client peers
+ MaxPeers int // Maximum number of global peers
SkipBcVersionCheck bool // e.g. blockchain export
DatabaseCache int
DatabaseHandles int
DocRoot string
- AutoDAG bool
PowFake bool
PowTest bool
PowShared bool
ExtraData []byte
+ EthashCacheDir string
+ EthashCachesInMem int
+ EthashCachesOnDisk int
+ EthashDatasetDir string
+ EthashDatasetsInMem int
+ EthashDatasetsOnDisk int
+
Etherbase common.Address
GasPrice *big.Int
MinerThreads int
@@ -98,9 +100,6 @@ type Config struct {
GpobaseCorrectionFactor int
EnablePreimageRecording bool
-
- TestGenesisBlock *types.Block // Genesis block to seed the chain database with (testing only!)
- TestGenesisState ethdb.Database // Genesis state to seed the database with (testing only!)
}
type LesServer interface {
@@ -133,8 +132,6 @@ type Ethereum struct {
miner *miner.Miner
Mining bool
MinerThreads int
- AutoDAG bool
- autodagquit chan bool
etherbase common.Address
solcPath string
@@ -155,36 +152,30 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
return nil, err
}
stopDbUpgrade := upgradeSequentialKeys(chainDb)
- if err := SetupGenesisBlock(&chainDb, config); err != nil {
- return nil, err
- }
- pow, err := CreatePoW(config)
- if err != nil {
- return nil, err
+ chainConfig, genesisHash, genesisErr := core.SetupGenesisBlock(chainDb, config.Genesis)
+ if _, ok := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !ok {
+ return nil, genesisErr
}
+ log.Info("Initialised chain configuration", "config", chainConfig)
eth := &Ethereum{
chainDb: chainDb,
+ chainConfig: chainConfig,
eventMux: ctx.EventMux,
accountManager: ctx.AccountManager,
- pow: pow,
+ pow: CreatePoW(ctx, config),
shutdownChan: make(chan bool),
stopDbUpgrade: stopDbUpgrade,
netVersionId: config.NetworkId,
etherbase: config.Etherbase,
MinerThreads: config.MinerThreads,
- AutoDAG: config.AutoDAG,
solcPath: config.SolcPath,
}
- if err := upgradeChainDatabase(chainDb); err != nil {
- return nil, err
- }
if err := addMipmapBloomBins(chainDb); err != nil {
return nil, err
}
-
- glog.V(logger.Info).Infof("Protocol Versions: %v, Network Id: %v", ProtocolVersions, config.NetworkId)
+ log.Info("Initialising Ethereum protocol", "versions", ProtocolVersions, "network", config.NetworkId)
if !config.SkipBcVersionCheck {
bcVersion := core.GetBlockChainVersion(chainDb)
@@ -194,33 +185,18 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
core.WriteBlockChainVersion(chainDb, core.BlockChainVersion)
}
- // load the genesis block or write a new one if no genesis
- // block is prenent in the database.
- genesis := core.GetBlock(chainDb, core.GetCanonicalHash(chainDb, 0), 0)
- if genesis == nil {
- genesis, err = core.WriteDefaultGenesisBlock(chainDb)
- if err != nil {
- return nil, err
- }
- glog.V(logger.Info).Infoln("WARNING: Wrote default ethereum genesis block")
- }
-
- if config.ChainConfig == nil {
- return nil, errors.New("missing chain config")
- }
- core.WriteChainConfig(chainDb, genesis.Hash(), config.ChainConfig)
-
- eth.chainConfig = config.ChainConfig
-
- glog.V(logger.Info).Infoln("Chain config:", eth.chainConfig)
-
- eth.blockchain, err = core.NewBlockChain(chainDb, eth.chainConfig, eth.pow, eth.EventMux(), vm.Config{EnablePreimageRecording: config.EnablePreimageRecording})
+ vmConfig := vm.Config{EnablePreimageRecording: config.EnablePreimageRecording}
+ eth.blockchain, err = core.NewBlockChain(chainDb, eth.chainConfig, eth.pow, eth.eventMux, vmConfig)
if err != nil {
- if err == core.ErrNoGenesis {
- return nil, fmt.Errorf(`No chain found. Please initialise a new chain using the "init" subcommand.`)
- }
return nil, err
}
+ // Rewind the chain in case of an incompatible config upgrade.
+ if compat, ok := genesisErr.(*params.ConfigCompatError); ok {
+ log.Warn("Rewinding chain to upgrade configuration", "err", compat)
+ eth.blockchain.SetHead(compat.RewindTo)
+ core.WriteChainConfig(chainDb, genesisHash, chainConfig)
+ }
+
newPool := core.NewTxPool(eth.chainConfig, eth.EventMux(), eth.blockchain.State, eth.blockchain.GasLimit)
eth.txPool = newPool
@@ -265,43 +241,21 @@ func CreateDB(ctx *node.ServiceContext, config *Config, name string) (ethdb.Data
return db, err
}
-// SetupGenesisBlock initializes the genesis block for an Ethereum service
-func SetupGenesisBlock(chainDb *ethdb.Database, config *Config) error {
- // Load up any custom genesis block if requested
- if len(config.Genesis) > 0 {
- block, err := core.WriteGenesisBlock(*chainDb, strings.NewReader(config.Genesis))
- if err != nil {
- return err
- }
- glog.V(logger.Info).Infof("Successfully wrote custom genesis block: %x", block.Hash())
- }
- // Load up a test setup if directly injected
- if config.TestGenesisState != nil {
- *chainDb = config.TestGenesisState
- }
- if config.TestGenesisBlock != nil {
- core.WriteTd(*chainDb, config.TestGenesisBlock.Hash(), config.TestGenesisBlock.NumberU64(), config.TestGenesisBlock.Difficulty())
- core.WriteBlock(*chainDb, config.TestGenesisBlock)
- core.WriteCanonicalHash(*chainDb, config.TestGenesisBlock.Hash(), config.TestGenesisBlock.NumberU64())
- core.WriteHeadBlockHash(*chainDb, config.TestGenesisBlock.Hash())
- }
- return nil
-}
-
// CreatePoW creates the required type of PoW instance for an Ethereum service
-func CreatePoW(config *Config) (pow.PoW, error) {
+func CreatePoW(ctx *node.ServiceContext, config *Config) pow.PoW {
switch {
case config.PowFake:
- glog.V(logger.Info).Infof("ethash used in fake mode")
- return pow.PoW(core.FakePow{}), nil
+ log.Warn("Ethash used in fake mode")
+ return pow.FakePow{}
case config.PowTest:
- glog.V(logger.Info).Infof("ethash used in test mode")
- return ethash.NewForTesting()
+ log.Warn("Ethash used in test mode")
+ return pow.NewTestEthash()
case config.PowShared:
- glog.V(logger.Info).Infof("ethash used in shared mode")
- return ethash.NewShared(), nil
+ log.Warn("Ethash used in shared mode")
+ return pow.NewSharedEthash()
default:
- return ethash.New(), nil
+ return pow.NewFullEthash(ctx.ResolvePath(config.EthashCacheDir), config.EthashCachesInMem, config.EthashCachesOnDisk,
+ config.EthashDatasetDir, config.EthashDatasetsInMem, config.EthashDatasetsOnDisk)
}
}
@@ -381,9 +335,8 @@ func (self *Ethereum) SetEtherbase(etherbase common.Address) {
func (s *Ethereum) StartMining(threads int) error {
eb, err := s.Etherbase()
if err != nil {
- err = fmt.Errorf("Cannot start mining without etherbase address: %v", err)
- glog.V(logger.Error).Infoln(err)
- return err
+ log.Error("Cannot start mining without etherbase", "err", err)
+ return fmt.Errorf("etherbase missing: %v", err)
}
go s.miner.Start(eb, threads)
return nil
@@ -418,9 +371,7 @@ func (s *Ethereum) Protocols() []p2p.Protocol {
// Ethereum protocol implementation.
func (s *Ethereum) Start(srvr *p2p.Server) error {
s.netRPCService = ethapi.NewPublicNetAPI(srvr, s.NetVersion())
- if s.AutoDAG {
- s.StartAutoDAG()
- }
+
s.protocolManager.Start()
if s.lesServer != nil {
s.lesServer.Start(srvr)
@@ -443,8 +394,6 @@ func (s *Ethereum) Stop() error {
s.miner.Stop()
s.eventMux.Stop()
- s.StopAutoDAG()
-
s.chainDb.Close()
close(s.shutdownChan)
@@ -455,74 +404,3 @@ func (s *Ethereum) Stop() error {
func (s *Ethereum) WaitForShutdown() {
<-s.shutdownChan
}
-
-// StartAutoDAG() spawns a go routine that checks the DAG every autoDAGcheckInterval
-// by default that is 10 times per epoch
-// in epoch n, if we past autoDAGepochHeight within-epoch blocks,
-// it calls ethash.MakeDAG to pregenerate the DAG for the next epoch n+1
-// if it does not exist yet as well as remove the DAG for epoch n-1
-// the loop quits if autodagquit channel is closed, it can safely restart and
-// stop any number of times.
-// For any more sophisticated pattern of DAG generation, use CLI subcommand
-// makedag
-func (self *Ethereum) StartAutoDAG() {
- if self.autodagquit != nil {
- return // already started
- }
- go func() {
- glog.V(logger.Info).Infof("Automatic pregeneration of ethash DAG ON (ethash dir: %s)", ethash.DefaultDir)
- var nextEpoch uint64
- timer := time.After(0)
- self.autodagquit = make(chan bool)
- for {
- select {
- case <-timer:
- glog.V(logger.Info).Infof("checking DAG (ethash dir: %s)", ethash.DefaultDir)
- currentBlock := self.BlockChain().CurrentBlock().NumberU64()
- thisEpoch := currentBlock / epochLength
- if nextEpoch <= thisEpoch {
- if currentBlock%epochLength > autoDAGepochHeight {
- if thisEpoch > 0 {
- previousDag, previousDagFull := dagFiles(thisEpoch - 1)
- os.Remove(filepath.Join(ethash.DefaultDir, previousDag))
- os.Remove(filepath.Join(ethash.DefaultDir, previousDagFull))
- glog.V(logger.Info).Infof("removed DAG for epoch %d (%s)", thisEpoch-1, previousDag)
- }
- nextEpoch = thisEpoch + 1
- dag, _ := dagFiles(nextEpoch)
- if _, err := os.Stat(dag); os.IsNotExist(err) {
- glog.V(logger.Info).Infof("Pregenerating DAG for epoch %d (%s)", nextEpoch, dag)
- err := ethash.MakeDAG(nextEpoch*epochLength, "") // "" -> ethash.DefaultDir
- if err != nil {
- glog.V(logger.Error).Infof("Error generating DAG for epoch %d (%s)", nextEpoch, dag)
- return
- }
- } else {
- glog.V(logger.Error).Infof("DAG for epoch %d (%s)", nextEpoch, dag)
- }
- }
- }
- timer = time.After(autoDAGcheckInterval)
- case <-self.autodagquit:
- return
- }
- }
- }()
-}
-
-// stopAutoDAG stops automatic DAG pregeneration by quitting the loop
-func (self *Ethereum) StopAutoDAG() {
- if self.autodagquit != nil {
- close(self.autodagquit)
- self.autodagquit = nil
- }
- glog.V(logger.Info).Infof("Automatic pregeneration of ethash DAG OFF (ethash dir: %s)", ethash.DefaultDir)
-}
-
-// dagFiles(epoch) returns the two alternative DAG filenames (not a path)
-// 1) - 2) full-R-
-func dagFiles(epoch uint64) (string, string) {
- seedHash, _ := ethash.GetSeedHash(epoch * epochLength)
- dag := fmt.Sprintf("full-R%d-%x", ethashRevision, seedHash[:8])
- return dag, "full-R" + dag
-}
diff --git a/eth/backend_test.go b/eth/backend_test.go
index 574731fbe5..f60e3214c3 100644
--- a/eth/backend_test.go
+++ b/eth/backend_test.go
@@ -30,7 +30,7 @@ import (
func TestMipmapUpgrade(t *testing.T) {
db, _ := ethdb.NewMemDatabase()
addr := common.BytesToAddress([]byte("jeff"))
- genesis := core.WriteGenesisBlockForTesting(db)
+ genesis := new(core.Genesis).MustCommit(db)
chain, receipts := core.GenerateChain(params.TestChainConfig, genesis, db, 10, func(i int, gen *core.BlockGen) {
var receipts types.Receipts
diff --git a/eth/bad_block.go b/eth/bad_block.go
index e0f05f540f..dd1ced8048 100644
--- a/eth/bad_block.go
+++ b/eth/bad_block.go
@@ -25,8 +25,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rlp"
)
@@ -66,9 +65,9 @@ func sendBadBlockReport(block *types.Block, err error) {
client := http.Client{Timeout: 8 * time.Second}
resp, err := client.Post(badBlocksURL, "application/json", bytes.NewReader(jsonStr))
if err != nil {
- glog.V(logger.Debug).Infoln(err)
+ log.Debug("Failed to report bad block", "err", err)
return
}
- glog.V(logger.Debug).Infof("Bad Block Report posted (%d)", resp.StatusCode)
+ log.Debug("Bad block report posted", "status", resp.StatusCode)
resp.Body.Close()
}
diff --git a/eth/bind.go b/eth/bind.go
index a9864b3677..2459341834 100644
--- a/eth/bind.go
+++ b/eth/bind.go
@@ -17,6 +17,7 @@
package eth
import (
+ "context"
"math/big"
"github.com/ethereum/go-ethereum"
@@ -26,7 +27,6 @@ import (
"github.com/ethereum/go-ethereum/internal/ethapi"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/rpc"
- "golang.org/x/net/context"
)
// ContractBackend implements bind.ContractBackend with direct calls to Ethereum
@@ -69,7 +69,7 @@ func (b *ContractBackend) PendingCodeAt(ctx context.Context, contract common.Add
// against the pending block, not the stable head of the chain.
func (b *ContractBackend) CallContract(ctx context.Context, msg ethereum.CallMsg, blockNum *big.Int) ([]byte, error) {
out, err := b.bcapi.Call(ctx, toCallArgs(msg), toBlockNumber(blockNum))
- return common.FromHex(out), err
+ return out, err
}
// ContractCall implements bind.ContractCaller executing an Ethereum contract
@@ -77,7 +77,7 @@ func (b *ContractBackend) CallContract(ctx context.Context, msg ethereum.CallMsg
// against the pending block, not the stable head of the chain.
func (b *ContractBackend) PendingCallContract(ctx context.Context, msg ethereum.CallMsg) ([]byte, error) {
out, err := b.bcapi.Call(ctx, toCallArgs(msg), rpc.PendingBlockNumber)
- return common.FromHex(out), err
+ return out, err
}
func toCallArgs(msg ethereum.CallMsg) ethapi.CallArgs {
diff --git a/eth/db_upgrade.go b/eth/db_upgrade.go
index 5fd73a5867..82cdd7e55e 100644
--- a/eth/db_upgrade.go
+++ b/eth/db_upgrade.go
@@ -28,8 +28,7 @@ import (
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethdb"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rlp"
)
@@ -50,7 +49,7 @@ func upgradeSequentialKeys(db ethdb.Database) (stopFn func()) {
return nil // empty database, nothing to do
}
- glog.V(logger.Info).Infof("Upgrading chain database to use sequential keys")
+ log.Warn("Upgrading chain database to use sequential keys")
stopChn := make(chan struct{})
stoppedChn := make(chan struct{})
@@ -73,11 +72,11 @@ func upgradeSequentialKeys(db ethdb.Database) (stopFn func()) {
err, stopped = upgradeSequentialOrphanedReceipts(db, stopFn)
}
if err == nil && !stopped {
- glog.V(logger.Info).Infof("Database conversion successful")
+ log.Info("Database conversion successful")
db.Put(useSequentialKeys, []byte{42})
}
if err != nil {
- glog.V(logger.Error).Infof("Database conversion failed: %v", err)
+ log.Error("Database conversion failed", "err", err)
}
close(stoppedChn)
}()
@@ -106,7 +105,7 @@ func upgradeSequentialCanonicalNumbers(db ethdb.Database, stopFn func() bool) (e
it.Release()
it = db.(*ethdb.LDBDatabase).NewIterator()
it.Seek(keyPtr)
- glog.V(logger.Info).Infof("converting %d canonical numbers...", cnt)
+ log.Info("Converting canonical numbers", "count", cnt)
}
number := big.NewInt(0).SetBytes(keyPtr[10:]).Uint64()
newKey := []byte("h12345678n")
@@ -125,7 +124,7 @@ func upgradeSequentialCanonicalNumbers(db ethdb.Database, stopFn func() bool) (e
it.Next()
}
if cnt > 0 {
- glog.V(logger.Info).Infof("converted %d canonical numbers...", cnt)
+ log.Info("converted canonical numbers", "count", cnt)
}
return nil, false
}
@@ -149,7 +148,7 @@ func upgradeSequentialBlocks(db ethdb.Database, stopFn func() bool) (error, bool
it.Release()
it = db.(*ethdb.LDBDatabase).NewIterator()
it.Seek(keyPtr)
- glog.V(logger.Info).Infof("converting %d blocks...", cnt)
+ log.Info("Converting blocks", "count", cnt)
}
// convert header, body, td and block receipts
var keyPrefix [38]byte
@@ -177,7 +176,7 @@ func upgradeSequentialBlocks(db ethdb.Database, stopFn func() bool) (error, bool
}
}
if cnt > 0 {
- glog.V(logger.Info).Infof("converted %d blocks...", cnt)
+ log.Info("Converted blocks", "count", cnt)
}
return nil, false
}
@@ -204,7 +203,7 @@ func upgradeSequentialOrphanedReceipts(db ethdb.Database, stopFn func() bool) (e
it.Next()
}
if cnt > 0 {
- glog.V(logger.Info).Infof("removed %d orphaned block receipts...", cnt)
+ log.Info("Removed orphaned block receipts", "count", cnt)
}
return nil, false
}
@@ -253,65 +252,6 @@ func upgradeSequentialBlockData(db ethdb.Database, hash []byte) error {
return nil
}
-// upgradeChainDatabase ensures that the chain database stores block split into
-// separate header and body entries.
-func upgradeChainDatabase(db ethdb.Database) error {
- // Short circuit if the head block is stored already as separate header and body
- data, err := db.Get([]byte("LastBlock"))
- if err != nil {
- return nil
- }
- head := common.BytesToHash(data)
-
- if block := core.GetBlockByHashOld(db, head); block == nil {
- return nil
- }
- // At least some of the database is still the old format, upgrade (skip the head block!)
- glog.V(logger.Info).Info("Old database detected, upgrading...")
-
- if db, ok := db.(*ethdb.LDBDatabase); ok {
- blockPrefix := []byte("block-hash-")
- for it := db.NewIterator(); it.Next(); {
- // Skip anything other than a combined block
- if !bytes.HasPrefix(it.Key(), blockPrefix) {
- continue
- }
- // Skip the head block (merge last to signal upgrade completion)
- if bytes.HasSuffix(it.Key(), head.Bytes()) {
- continue
- }
- // Load the block, split and serialize (order!)
- block := core.GetBlockByHashOld(db, common.BytesToHash(bytes.TrimPrefix(it.Key(), blockPrefix)))
-
- if err := core.WriteTd(db, block.Hash(), block.NumberU64(), block.DeprecatedTd()); err != nil {
- return err
- }
- if err := core.WriteBody(db, block.Hash(), block.NumberU64(), block.Body()); err != nil {
- return err
- }
- if err := core.WriteHeader(db, block.Header()); err != nil {
- return err
- }
- if err := db.Delete(it.Key()); err != nil {
- return err
- }
- }
- // Lastly, upgrade the head block, disabling the upgrade mechanism
- current := core.GetBlockByHashOld(db, head)
-
- if err := core.WriteTd(db, current.Hash(), current.NumberU64(), current.DeprecatedTd()); err != nil {
- return err
- }
- if err := core.WriteBody(db, current.Hash(), current.NumberU64(), current.Body()); err != nil {
- return err
- }
- if err := core.WriteHeader(db, current.Header()); err != nil {
- return err
- }
- }
- return nil
-}
-
func addMipmapBloomBins(db ethdb.Database) (err error) {
const mipmapVersion uint = 2
@@ -343,7 +283,7 @@ func addMipmapBloomBins(db ethdb.Database) (err error) {
}
tstart := time.Now()
- glog.V(logger.Info).Infoln("upgrading db log bloom bins")
+ log.Warn("Upgrading db log bloom bins")
for i := uint64(0); i <= latestBlock.NumberU64(); i++ {
hash := core.GetCanonicalHash(db, i)
if (hash == common.Hash{}) {
@@ -351,6 +291,6 @@ func addMipmapBloomBins(db ethdb.Database) (err error) {
}
core.WriteMipmapBloom(db, i, core.GetBlockReceipts(db, hash, i))
}
- glog.V(logger.Info).Infoln("upgrade completed in", time.Since(tstart))
+ log.Info("Bloom-bin upgrade completed", "elapsed", common.PrettyDuration(time.Since(tstart)))
return nil
}
diff --git a/eth/downloader/api.go b/eth/downloader/api.go
index e41376810f..d496fa6a4d 100644
--- a/eth/downloader/api.go
+++ b/eth/downloader/api.go
@@ -17,12 +17,12 @@
package downloader
import (
+ "context"
"sync"
ethereum "github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/rpc"
- "golang.org/x/net/context"
)
// PublicDownloaderAPI provides an API which gives information about the current synchronisation status.
diff --git a/eth/downloader/downloader.go b/eth/downloader/downloader.go
index 9be4bd87d0..d269957827 100644
--- a/eth/downloader/downloader.go
+++ b/eth/downloader/downloader.go
@@ -23,7 +23,6 @@ import (
"fmt"
"math"
"math/big"
- "strings"
"sync"
"sync/atomic"
"time"
@@ -33,8 +32,7 @@ import (
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/trie"
"github.com/rcrowley/go-metrics"
@@ -49,12 +47,12 @@ var (
MaxReceiptFetch = 256 // Amount of transaction receipts to allow fetching per request
MaxStateFetch = 384 // Amount of node state values to allow fetching per request
- MaxForkAncestry = 3 * params.EpochDuration.Uint64() // Maximum chain reorganisation
- rttMinEstimate = 2 * time.Second // Minimum round-trip time to target for download requests
- rttMaxEstimate = 20 * time.Second // Maximum rount-trip time to target for download requests
- rttMinConfidence = 0.1 // Worse confidence factor in our estimated RTT value
- ttlScaling = 3 // Constant scaling factor for RTT -> TTL conversion
- ttlLimit = time.Minute // Maximum TTL allowance to prevent reaching crazy timeouts
+ MaxForkAncestry = 3 * params.EpochDuration // Maximum chain reorganisation
+ rttMinEstimate = 2 * time.Second // Minimum round-trip time to target for download requests
+ rttMaxEstimate = 20 * time.Second // Maximum rount-trip time to target for download requests
+ rttMinConfidence = 0.1 // Worse confidence factor in our estimated RTT value
+ ttlScaling = 3 // Constant scaling factor for RTT -> TTL conversion
+ ttlLimit = time.Minute // Maximum TTL allowance to prevent reaching crazy timeouts
qosTuningPeers = 5 // Number of peers to tune based on (best peers)
qosConfidenceCap = 10 // Number of peers above which not to modify RTT confidence
@@ -249,9 +247,10 @@ func (d *Downloader) RegisterPeer(id string, version int, currentHead currentHea
getRelHeaders relativeHeaderFetcherFn, getAbsHeaders absoluteHeaderFetcherFn, getBlockBodies blockBodyFetcherFn,
getReceipts receiptFetcherFn, getNodeData stateFetcherFn) error {
- glog.V(logger.Detail).Infoln("Registering peer", id)
- if err := d.peers.Register(newPeer(id, version, currentHead, getRelHeaders, getAbsHeaders, getBlockBodies, getReceipts, getNodeData)); err != nil {
- glog.V(logger.Error).Infoln("Register failed:", err)
+ logger := log.New("peer", id)
+ logger.Trace("Registering sync peer")
+ if err := d.peers.Register(newPeer(id, version, currentHead, getRelHeaders, getAbsHeaders, getBlockBodies, getReceipts, getNodeData, logger)); err != nil {
+ logger.Error("Failed to register sync peer", "err", err)
return err
}
d.qosReduceConfidence()
@@ -264,9 +263,10 @@ func (d *Downloader) RegisterPeer(id string, version int, currentHead currentHea
// the queue.
func (d *Downloader) UnregisterPeer(id string) error {
// Unregister the peer from the active peer set and revoke any fetch tasks
- glog.V(logger.Detail).Infoln("Unregistering peer", id)
+ logger := log.New("peer", id)
+ logger.Trace("Unregistering sync peer")
if err := d.peers.Unregister(id); err != nil {
- glog.V(logger.Error).Infoln("Unregister failed:", err)
+ logger.Error("Failed to unregister sync peer", "err", err)
return err
}
d.queue.Revoke(id)
@@ -277,7 +277,7 @@ func (d *Downloader) UnregisterPeer(id string) error {
d.cancelLock.RUnlock()
if master {
- d.cancel()
+ d.Cancel()
}
return nil
}
@@ -285,24 +285,19 @@ func (d *Downloader) UnregisterPeer(id string) error {
// Synchronise tries to sync up our local block chain with a remote peer, both
// adding various sanity checks as well as wrapping it with various log entries.
func (d *Downloader) Synchronise(id string, head common.Hash, td *big.Int, mode SyncMode) error {
- glog.V(logger.Detail).Infof("Attempting synchronisation: %v, head [%x…], TD %v", id, head[:4], td)
-
err := d.synchronise(id, head, td, mode)
switch err {
case nil:
- glog.V(logger.Detail).Infof("Synchronisation completed")
-
case errBusy:
- glog.V(logger.Detail).Infof("Synchronisation already in progress")
case errTimeout, errBadPeer, errStallingPeer,
errEmptyHeaderSet, errPeersUnavailable, errTooOld,
errInvalidAncestor, errInvalidChain:
- glog.V(logger.Debug).Infof("Removing peer %v: %v", id, err)
+ log.Warn("Synchronisation failed, dropping peer", "peer", id, "err", err)
d.dropPeer(id)
default:
- glog.V(logger.Warn).Infof("Synchronisation failed: %v", err)
+ log.Warn("Synchronisation failed, retrying", "err", err)
}
return err
}
@@ -323,7 +318,7 @@ func (d *Downloader) synchronise(id string, hash common.Hash, td *big.Int, mode
// Post a user notification of the sync (only once per session)
if atomic.CompareAndSwapInt32(&d.notified, 0, 1) {
- glog.V(logger.Info).Infoln("Block synchronisation started")
+ log.Info("Block synchronisation started")
}
// Reset the queue, peer set and wake channels to clean any internal leftover state
d.queue.Reset()
@@ -357,7 +352,7 @@ func (d *Downloader) synchronise(id string, hash common.Hash, td *big.Int, mode
d.cancelPeer = id
d.cancelLock.Unlock()
- defer d.cancel() // No matter what, we can't leave the cancel channel open
+ defer d.Cancel() // No matter what, we can't leave the cancel channel open
// Set the requested sync mode, unless it's forbidden
d.mode = mode
@@ -388,9 +383,9 @@ func (d *Downloader) syncWithPeer(p *peer, hash common.Hash, td *big.Int) (err e
return errTooOld
}
- glog.V(logger.Debug).Infof("Synchronising with the network using: %s [eth/%d]", p.id, p.version)
+ log.Debug("Synchronising with the network", "peer", p.id, "eth", p.version, "head", hash, "td", td, "mode", d.mode)
defer func(start time.Time) {
- glog.V(logger.Debug).Infof("Synchronisation terminated after %v", time.Since(start))
+ log.Debug("Synchronisation terminated", "elapsed", time.Since(start))
}(time.Now())
// Look up the sync boundaries: the common ancestor and the target block
@@ -438,7 +433,7 @@ func (d *Downloader) syncWithPeer(p *peer, hash common.Hash, td *big.Int) (err e
origin = 0
}
}
- glog.V(logger.Debug).Infof("Fast syncing until pivot block #%d", pivot)
+ log.Debug("Fast syncing until pivot block", "pivot", pivot)
}
d.queue.Prepare(origin+1, d.mode, pivot, latest)
if d.syncInitHook != nil {
@@ -478,7 +473,7 @@ func (d *Downloader) spawnSync(origin uint64, fetchers ...func() error) error {
}
}
d.queue.Close()
- d.cancel()
+ d.Cancel()
wg.Wait()
// If sync failed in the critical section, bump the fail counter
@@ -488,9 +483,9 @@ func (d *Downloader) spawnSync(origin uint64, fetchers ...func() error) error {
return err
}
-// cancel cancels all of the operations and resets the queue. It returns true
+// Cancel cancels all of the operations and resets the queue. It returns true
// if the cancel operation was completed.
-func (d *Downloader) cancel() {
+func (d *Downloader) Cancel() {
// Close the current cancel channel
d.cancelLock.Lock()
if d.cancelCh != nil {
@@ -517,19 +512,20 @@ func (d *Downloader) Terminate() {
d.quitLock.Unlock()
// Cancel any pending download requests
- d.cancel()
+ d.Cancel()
}
// fetchHeight retrieves the head header of the remote peer to aid in estimating
// the total time a pending synchronisation would take.
func (d *Downloader) fetchHeight(p *peer) (*types.Header, error) {
- glog.V(logger.Debug).Infof("%v: retrieving remote chain height", p)
+ p.log.Debug("Retrieving remote chain height")
// Request the advertised remote head block and wait for the response
head, _ := p.currentHead()
go p.getRelHeaders(head, 1, 0, false)
- timeout := time.After(d.requestTTL())
+ ttl := d.requestTTL()
+ timeout := time.After(ttl)
for {
select {
case <-d.cancelCh:
@@ -538,19 +534,21 @@ func (d *Downloader) fetchHeight(p *peer) (*types.Header, error) {
case packet := <-d.headerCh:
// Discard anything not from the origin peer
if packet.PeerId() != p.id {
- glog.V(logger.Debug).Infof("Received headers from incorrect peer(%s)", packet.PeerId())
+ log.Debug("Received headers from incorrect peer", "peer", packet.PeerId())
break
}
// Make sure the peer actually gave something valid
headers := packet.(*headerPack).headers
if len(headers) != 1 {
- glog.V(logger.Debug).Infof("%v: invalid number of head headers: %d != 1", p, len(headers))
+ p.log.Debug("Multiple headers for single request", "headers", len(headers))
return nil, errBadPeer
}
- return headers[0], nil
+ head := headers[0]
+ p.log.Debug("Remote head header identified", "number", head.Number, "hash", head.Hash())
+ return head, nil
case <-timeout:
- glog.V(logger.Debug).Infof("%v: head header timeout", p)
+ p.log.Debug("Waiting for head header timed out", "elapsed", ttl)
return nil, errTimeout
case <-d.bodyCh:
@@ -567,10 +565,10 @@ func (d *Downloader) fetchHeight(p *peer) (*types.Header, error) {
// In the rare scenario when we ended up on a long reorganisation (i.e. none of
// the head links match), we do a binary search to find the common ancestor.
func (d *Downloader) findAncestor(p *peer, height uint64) (uint64, error) {
- glog.V(logger.Debug).Infof("%v: looking for common ancestor (remote height %d)", p, height)
-
// Figure out the valid ancestor range to prevent rewrite attacks
floor, ceil := int64(-1), d.headHeader().Number.Uint64()
+
+ p.log.Debug("Looking for common ancestor", "local", ceil, "remote", height)
if d.mode == FullSync {
ceil = d.headBlock().NumberU64()
} else if d.mode == FastSync {
@@ -598,7 +596,9 @@ func (d *Downloader) findAncestor(p *peer, height uint64) (uint64, error) {
// Wait for the remote response to the head fetch
number, hash := uint64(0), common.Hash{}
- timeout := time.After(d.requestTTL())
+
+ ttl := d.requestTTL()
+ timeout := time.After(ttl)
for finished := false; !finished; {
select {
@@ -608,19 +608,19 @@ func (d *Downloader) findAncestor(p *peer, height uint64) (uint64, error) {
case packet := <-d.headerCh:
// Discard anything not from the origin peer
if packet.PeerId() != p.id {
- glog.V(logger.Debug).Infof("Received headers from incorrect peer(%s)", packet.PeerId())
+ log.Debug("Received headers from incorrect peer", "peer", packet.PeerId())
break
}
// Make sure the peer actually gave something valid
headers := packet.(*headerPack).headers
if len(headers) == 0 {
- glog.V(logger.Warn).Infof("%v: empty head header set", p)
+ p.log.Warn("Empty head header set")
return 0, errEmptyHeaderSet
}
// Make sure the peer's reply conforms to the request
for i := 0; i < len(headers); i++ {
if number := headers[i].Number.Int64(); number != from+int64(i)*16 {
- glog.V(logger.Warn).Infof("%v: head header set (item %d) broke chain ordering: requested %d, got %d", p, i, from+int64(i)*16, number)
+ p.log.Warn("Head headers broke chain ordering", "index", i, "requested", from+int64(i)*16, "received", number)
return 0, errInvalidChain
}
}
@@ -637,7 +637,7 @@ func (d *Downloader) findAncestor(p *peer, height uint64) (uint64, error) {
// If every header is known, even future ones, the peer straight out lied about its head
if number > height && i == limit-1 {
- glog.V(logger.Warn).Infof("%v: lied about chain head: reported %d, found above %d", p, height, number)
+ p.log.Warn("Lied about chain head", "reported", height, "found", number)
return 0, errStallingPeer
}
break
@@ -645,7 +645,7 @@ func (d *Downloader) findAncestor(p *peer, height uint64) (uint64, error) {
}
case <-timeout:
- glog.V(logger.Debug).Infof("%v: head header timeout", p)
+ p.log.Debug("Waiting for head header timed out", "elapsed", ttl)
return 0, errTimeout
case <-d.bodyCh:
@@ -657,10 +657,10 @@ func (d *Downloader) findAncestor(p *peer, height uint64) (uint64, error) {
// If the head fetch already found an ancestor, return
if !common.EmptyHash(hash) {
if int64(number) <= floor {
- glog.V(logger.Warn).Infof("%v: potential rewrite attack: #%d [%x…] <= #%d limit", p, number, hash[:4], floor)
+ p.log.Warn("Ancestor below allowance", "number", number, "hash", hash, "allowance", floor)
return 0, errInvalidAncestor
}
- glog.V(logger.Debug).Infof("%v: common ancestor: #%d [%x…]", p, number, hash[:4])
+ p.log.Debug("Found common ancestor", "number", number, "hash", hash)
return number, nil
}
// Ancestor not found, we need to binary search over our chain
@@ -672,7 +672,9 @@ func (d *Downloader) findAncestor(p *peer, height uint64) (uint64, error) {
// Split our chain interval in two, and request the hash to cross check
check := (start + end) / 2
- timeout := time.After(d.requestTTL())
+ ttl := d.requestTTL()
+ timeout := time.After(ttl)
+
go p.getAbsHeaders(uint64(check), 1, 0, false)
// Wait until a reply arrives to this request
@@ -684,13 +686,13 @@ func (d *Downloader) findAncestor(p *peer, height uint64) (uint64, error) {
case packer := <-d.headerCh:
// Discard anything not from the origin peer
if packer.PeerId() != p.id {
- glog.V(logger.Debug).Infof("Received headers from incorrect peer(%s)", packer.PeerId())
+ log.Debug("Received headers from incorrect peer", "peer", packer.PeerId())
break
}
// Make sure the peer actually gave something valid
headers := packer.(*headerPack).headers
if len(headers) != 1 {
- glog.V(logger.Debug).Infof("%v: invalid search header set (%d)", p, len(headers))
+ p.log.Debug("Multiple headers for single request", "headers", len(headers))
return 0, errBadPeer
}
arrived = true
@@ -702,13 +704,13 @@ func (d *Downloader) findAncestor(p *peer, height uint64) (uint64, error) {
}
header := d.getHeader(headers[0].Hash()) // Independent of sync mode, header surely exists
if header.Number.Uint64() != check {
- glog.V(logger.Debug).Infof("%v: non requested header #%d [%x…], instead of #%d", p, header.Number, header.Hash().Bytes()[:4], check)
+ p.log.Debug("Received non requested header", "number", header.Number, "hash", header.Hash(), "request", check)
return 0, errBadPeer
}
start = check
case <-timeout:
- glog.V(logger.Debug).Infof("%v: search header timeout", p)
+ p.log.Debug("Waiting for search header timed out", "elapsed", ttl)
return 0, errTimeout
case <-d.bodyCh:
@@ -720,10 +722,10 @@ func (d *Downloader) findAncestor(p *peer, height uint64) (uint64, error) {
}
// Ensure valid ancestry and return
if int64(start) <= floor {
- glog.V(logger.Warn).Infof("%v: potential rewrite attack: #%d [%x…] <= #%d limit", p, start, hash[:4], floor)
+ p.log.Warn("Ancestor below allowance", "number", start, "hash", hash, "allowance", floor)
return 0, errInvalidAncestor
}
- glog.V(logger.Debug).Infof("%v: common ancestor: #%d [%x…]", p, start, hash[:4])
+ p.log.Debug("Found common ancestor", "number", start, "hash", hash)
return start, nil
}
@@ -736,8 +738,8 @@ func (d *Downloader) findAncestor(p *peer, height uint64) (uint64, error) {
// can fill in the skeleton - not even the origin peer - it's assumed invalid and
// the origin is dropped.
func (d *Downloader) fetchHeaders(p *peer, from uint64) error {
- glog.V(logger.Debug).Infof("%v: directing header downloads from #%d", p, from)
- defer glog.V(logger.Debug).Infof("%v: header download terminated", p)
+ p.log.Debug("Directing header downloads", "origin", from)
+ defer p.log.Debug("Header download terminated")
// Create a timeout timer, and the associated header fetcher
skeleton := true // Skeleton assembly phase or finishing up
@@ -746,15 +748,18 @@ func (d *Downloader) fetchHeaders(p *peer, from uint64) error {
<-timeout.C // timeout channel should be initially empty
defer timeout.Stop()
+ var ttl time.Duration
getHeaders := func(from uint64) {
request = time.Now()
- timeout.Reset(d.requestTTL())
+
+ ttl = d.requestTTL()
+ timeout.Reset(ttl)
if skeleton {
- glog.V(logger.Detail).Infof("%v: fetching %d skeleton headers from #%d", p, MaxHeaderFetch, from)
+ p.log.Trace("Fetching skeleton headers", "count", MaxHeaderFetch, "from", from)
go p.getAbsHeaders(from+uint64(MaxHeaderFetch)-1, MaxSkeletonSize, MaxHeaderFetch-1, false)
} else {
- glog.V(logger.Detail).Infof("%v: fetching %d full headers from #%d", p, MaxHeaderFetch, from)
+ p.log.Trace("Fetching full headers", "count", MaxHeaderFetch, "from", from)
go p.getAbsHeaders(from, MaxHeaderFetch, 0, false)
}
}
@@ -769,7 +774,7 @@ func (d *Downloader) fetchHeaders(p *peer, from uint64) error {
case packet := <-d.headerCh:
// Make sure the active peer is giving us the skeleton headers
if packet.PeerId() != p.id {
- glog.V(logger.Debug).Infof("Received skeleton headers from incorrect peer (%s)", packet.PeerId())
+ log.Debug("Received skeleton from incorrect peer", "peer", packet.PeerId())
break
}
headerReqTimer.UpdateSince(request)
@@ -783,7 +788,7 @@ func (d *Downloader) fetchHeaders(p *peer, from uint64) error {
}
// If no more headers are inbound, notify the content fetchers and return
if packet.Items() == 0 {
- glog.V(logger.Debug).Infof("%v: no available headers", p)
+ p.log.Debug("No more headers available")
select {
case d.headerProcCh <- nil:
return nil
@@ -797,7 +802,7 @@ func (d *Downloader) fetchHeaders(p *peer, from uint64) error {
if skeleton {
filled, proced, err := d.fillHeaderSkeleton(from, headers)
if err != nil {
- glog.V(logger.Debug).Infof("%v: skeleton chain invalid: %v", p, err)
+ p.log.Debug("Skeleton chain invalid", "err", err)
return errInvalidChain
}
headers = filled[proced:]
@@ -805,7 +810,7 @@ func (d *Downloader) fetchHeaders(p *peer, from uint64) error {
}
// Insert all the new headers and fetch the next batch
if len(headers) > 0 {
- glog.V(logger.Detail).Infof("%v: schedule %d headers from #%d", p, len(headers), from)
+ p.log.Trace("Scheduling new headers", "count", len(headers), "from", from)
select {
case d.headerProcCh <- headers:
case <-d.cancelCh:
@@ -817,7 +822,7 @@ func (d *Downloader) fetchHeaders(p *peer, from uint64) error {
case <-timeout.C:
// Header retrieval timed out, consider the peer bad and drop
- glog.V(logger.Debug).Infof("%v: header request timed out", p)
+ p.log.Debug("Header request timed out", "elapsed", ttl)
headerTimeoutMeter.Mark(1)
d.dropPeer(p.id)
@@ -847,7 +852,7 @@ func (d *Downloader) fetchHeaders(p *peer, from uint64) error {
// The method returs the entire filled skeleton and also the number of headers
// already forwarded for processing.
func (d *Downloader) fillHeaderSkeleton(from uint64, skeleton []*types.Header) ([]*types.Header, int, error) {
- glog.V(logger.Debug).Infof("Filling up skeleton from #%d", from)
+ log.Debug("Filling up skeleton", "from", from)
d.queue.ScheduleSkeleton(from, skeleton)
var (
@@ -866,9 +871,9 @@ func (d *Downloader) fillHeaderSkeleton(from uint64, skeleton []*types.Header) (
)
err := d.fetchParts(errCancelHeaderFetch, d.headerCh, deliver, d.queue.headerContCh, expire,
d.queue.PendingHeaders, d.queue.InFlightHeaders, throttle, reserve,
- nil, fetch, d.queue.CancelHeaders, capacity, d.peers.HeaderIdlePeers, setIdle, "Header")
+ nil, fetch, d.queue.CancelHeaders, capacity, d.peers.HeaderIdlePeers, setIdle, "headers")
- glog.V(logger.Debug).Infof("Skeleton fill terminated: %v", err)
+ log.Debug("Skeleton fill terminated", "err", err)
filled, proced := d.queue.RetrieveHeaders()
return filled, proced, err
@@ -878,7 +883,7 @@ func (d *Downloader) fillHeaderSkeleton(from uint64, skeleton []*types.Header) (
// available peers, reserving a chunk of blocks for each, waiting for delivery
// and also periodically checking for timeouts.
func (d *Downloader) fetchBodies(from uint64) error {
- glog.V(logger.Debug).Infof("Downloading block bodies from #%d", from)
+ log.Debug("Downloading block bodies", "origin", from)
var (
deliver = func(packet dataPack) (int, error) {
@@ -892,9 +897,9 @@ func (d *Downloader) fetchBodies(from uint64) error {
)
err := d.fetchParts(errCancelBodyFetch, d.bodyCh, deliver, d.bodyWakeCh, expire,
d.queue.PendingBlocks, d.queue.InFlightBlocks, d.queue.ShouldThrottleBlocks, d.queue.ReserveBodies,
- d.bodyFetchHook, fetch, d.queue.CancelBodies, capacity, d.peers.BodyIdlePeers, setIdle, "Body")
+ d.bodyFetchHook, fetch, d.queue.CancelBodies, capacity, d.peers.BodyIdlePeers, setIdle, "bodies")
- glog.V(logger.Debug).Infof("Block body download terminated: %v", err)
+ log.Debug("Block body download terminated", "err", err)
return err
}
@@ -902,7 +907,7 @@ func (d *Downloader) fetchBodies(from uint64) error {
// available peers, reserving a chunk of receipts for each, waiting for delivery
// and also periodically checking for timeouts.
func (d *Downloader) fetchReceipts(from uint64) error {
- glog.V(logger.Debug).Infof("Downloading receipts from #%d", from)
+ log.Debug("Downloading transaction receipts", "origin", from)
var (
deliver = func(packet dataPack) (int, error) {
@@ -916,9 +921,9 @@ func (d *Downloader) fetchReceipts(from uint64) error {
)
err := d.fetchParts(errCancelReceiptFetch, d.receiptCh, deliver, d.receiptWakeCh, expire,
d.queue.PendingReceipts, d.queue.InFlightReceipts, d.queue.ShouldThrottleReceipts, d.queue.ReserveReceipts,
- d.receiptFetchHook, fetch, d.queue.CancelReceipts, capacity, d.peers.ReceiptIdlePeers, setIdle, "Receipt")
+ d.receiptFetchHook, fetch, d.queue.CancelReceipts, capacity, d.peers.ReceiptIdlePeers, setIdle, "receipts")
- glog.V(logger.Debug).Infof("Receipt download terminated: %v", err)
+ log.Debug("Transaction receipt download terminated", "err", err)
return err
}
@@ -926,7 +931,7 @@ func (d *Downloader) fetchReceipts(from uint64) error {
// available peers, reserving a chunk of nodes for each, waiting for delivery and
// also periodically checking for timeouts.
func (d *Downloader) fetchNodeData() error {
- glog.V(logger.Debug).Infof("Downloading node state data")
+ log.Debug("Downloading node state data")
var (
deliver = func(packet dataPack) (int, error) {
@@ -934,13 +939,13 @@ func (d *Downloader) fetchNodeData() error {
return d.queue.DeliverNodeData(packet.PeerId(), packet.(*statePack).states, func(delivered int, progressed bool, err error) {
// If the peer returned old-requested data, forgive
if err == trie.ErrNotRequested {
- glog.V(logger.Debug).Infof("peer %s: replied to stale state request, forgiving", packet.PeerId())
+ log.Debug("Forgiving reply to stale state request", "peer", packet.PeerId())
return
}
if err != nil {
// If the node data processing failed, the root hash is very wrong, abort
- glog.V(logger.Error).Infof("peer %d: state processing failed: %v", packet.PeerId(), err)
- d.cancel()
+ log.Error("State processing failed", "peer", packet.PeerId(), "err", err)
+ d.Cancel()
return
}
// Processing succeeded, notify state fetcher of continuation
@@ -958,12 +963,12 @@ func (d *Downloader) fetchNodeData() error {
// If real database progress was made, reset any fast-sync pivot failure
if progressed && atomic.LoadUint32(&d.fsPivotFails) > 1 {
- glog.V(logger.Debug).Infof("fast-sync progressed, resetting fail counter from %d", atomic.LoadUint32(&d.fsPivotFails))
+ log.Debug("Fast-sync progressed, resetting fail counter", "previous", atomic.LoadUint32(&d.fsPivotFails))
atomic.StoreUint32(&d.fsPivotFails, 1) // Don't ever reset to 0, as that will unlock the pivot block
}
// Log a message to the user and return
if delivered > 0 {
- glog.V(logger.Info).Infof("imported %3d state entries in %9v: processed %d, pending at least %d", delivered, common.PrettyDuration(time.Since(start)), syncStatsStateDone, pending)
+ log.Info("Imported new state entries", "count", delivered, "elapsed", common.PrettyDuration(time.Since(start)), "processed", syncStatsStateDone, "pending", pending)
}
})
}
@@ -978,9 +983,9 @@ func (d *Downloader) fetchNodeData() error {
)
err := d.fetchParts(errCancelStateFetch, d.stateCh, deliver, d.stateWakeCh, expire,
d.queue.PendingNodeData, d.queue.InFlightNodeData, throttle, reserve, nil, fetch,
- d.queue.CancelNodeData, capacity, d.peers.NodeDataIdlePeers, setIdle, "State")
+ d.queue.CancelNodeData, capacity, d.peers.NodeDataIdlePeers, setIdle, "states")
- glog.V(logger.Debug).Infof("Node state data download terminated: %v", err)
+ log.Debug("Node state data download terminated", "err", err)
return err
}
@@ -1045,11 +1050,11 @@ func (d *Downloader) fetchParts(errCancel error, deliveryCh chan dataPack, deliv
// Issue a log to the user to see what's going on
switch {
case err == nil && packet.Items() == 0:
- glog.V(logger.Detail).Infof("%s: no %s delivered", peer, strings.ToLower(kind))
+ peer.log.Trace("Requested data not delivered", "type", kind)
case err == nil:
- glog.V(logger.Detail).Infof("%s: delivered %s %s(s)", peer, packet.Stats(), strings.ToLower(kind))
+ peer.log.Trace("Delivered new batch of data", "type", kind, "count", packet.Stats())
default:
- glog.V(logger.Detail).Infof("%s: %s delivery failed: %v", peer, strings.ToLower(kind), err)
+ peer.log.Trace("Failed to deliver retrieved data", "type", kind, "err", err)
}
}
// Blocks assembled, try to update the progress
@@ -1092,10 +1097,10 @@ func (d *Downloader) fetchParts(errCancel error, deliveryCh chan dataPack, deliv
// and latency of a peer separately, which requires pushing the measures capacity a bit and seeing
// how response times reacts, to it always requests one more than the minimum (i.e. min 2).
if fails > 2 {
- glog.V(logger.Detail).Infof("%s: %s delivery timeout", peer, strings.ToLower(kind))
+ peer.log.Trace("Data delivery timed out", "type", kind)
setIdle(peer, 0)
} else {
- glog.V(logger.Debug).Infof("%s: stalling %s delivery, dropping", peer, strings.ToLower(kind))
+ peer.log.Debug("Stalling delivery, dropping", "type", kind)
d.dropPeer(pid)
}
}
@@ -1103,7 +1108,7 @@ func (d *Downloader) fetchParts(errCancel error, deliveryCh chan dataPack, deliv
// If there's nothing more to fetch, wait or terminate
if pending() == 0 {
if !inFlight() && finished {
- glog.V(logger.Debug).Infof("%s fetching completed", kind)
+ log.Debug("Data fetching completed", "type", kind)
return nil
}
break
@@ -1131,14 +1136,12 @@ func (d *Downloader) fetchParts(errCancel error, deliveryCh chan dataPack, deliv
if request == nil {
continue
}
- if glog.V(logger.Detail) {
- if request.From > 0 {
- glog.Infof("%s: requesting %s(s) from #%d", peer, strings.ToLower(kind), request.From)
- } else if len(request.Headers) > 0 {
- glog.Infof("%s: requesting %d %s(s), first at #%d", peer, len(request.Headers), strings.ToLower(kind), request.Headers[0].Number)
- } else {
- glog.Infof("%s: requesting %d %s(s)", peer, len(request.Hashes), strings.ToLower(kind))
- }
+ if request.From > 0 {
+ peer.log.Trace("Requesting new batch of data", "type", kind, "from", request.From)
+ } else if len(request.Headers) > 0 {
+ peer.log.Trace("Requesting new batch of data", "type", kind, "count", len(request.Headers), "from", request.Headers[0].Number)
+ } else {
+ peer.log.Trace("Requesting new batch of data", "type", kind, "count", len(request.Hashes))
}
// Fetch the chunk and make sure any errors return the hashes to the queue
if fetchHook != nil {
@@ -1150,7 +1153,7 @@ func (d *Downloader) fetchParts(errCancel error, deliveryCh chan dataPack, deliv
// case, the internal state of the downloader and the queue is very wrong so
// better hard crash and note the error instead of silently accumulating into
// a much bigger issue.
- panic(fmt.Sprintf("%v: %s fetch assignment failed", peer, strings.ToLower(kind)))
+ panic(fmt.Sprintf("%v: %s fetch assignment failed", peer, kind))
}
running = true
}
@@ -1194,8 +1197,10 @@ func (d *Downloader) processHeaders(origin uint64, td *big.Int) error {
if d.headBlock != nil {
curBlock = d.headBlock().Number()
}
- glog.V(logger.Warn).Infof("Rolled back %d headers (LH: %d->%d, FB: %d->%d, LB: %d->%d)",
- len(hashes), lastHeader, d.headHeader().Number, lastFastBlock, curFastBlock, lastBlock, curBlock)
+ log.Warn("Rolled back headers", "count", len(hashes),
+ "header", fmt.Sprintf("%d->%d", lastHeader, d.headHeader().Number),
+ "fast", fmt.Sprintf("%d->%d", lastFastBlock, curFastBlock),
+ "block", fmt.Sprintf("%d->%d", lastBlock, curBlock))
// If we're already past the pivot point, this could be an attack, thread carefully
if rollback[len(rollback)-1].Number.Uint64() > pivot {
@@ -1203,7 +1208,7 @@ func (d *Downloader) processHeaders(origin uint64, td *big.Int) error {
if atomic.LoadUint32(&d.fsPivotFails) == 0 {
for _, header := range rollback {
if header.Number.Uint64() == pivot {
- glog.V(logger.Warn).Infof("Fast-sync critical section failure, locked pivot to header #%d [%x…]", pivot, header.Hash().Bytes()[:4])
+ log.Warn("Fast-sync pivot locked in", "number", pivot, "hash", header.Hash())
d.fsPivotLock = header
}
}
@@ -1299,7 +1304,7 @@ func (d *Downloader) processHeaders(origin uint64, td *big.Int) error {
if n > 0 {
rollback = append(rollback, chunk[:n]...)
}
- glog.V(logger.Debug).Infof("invalid header #%d [%x…]: %v", chunk[n].Number, chunk[n].Hash().Bytes()[:4], err)
+ log.Debug("Invalid header encountered", "number", chunk[n].Number, "hash", chunk[n].Hash(), "err", err)
return errInvalidChain
}
// All verifications passed, store newly found uncertain headers
@@ -1311,7 +1316,7 @@ func (d *Downloader) processHeaders(origin uint64, td *big.Int) error {
// If we're fast syncing and just pulled in the pivot, make sure it's the one locked in
if d.mode == FastSync && d.fsPivotLock != nil && chunk[0].Number.Uint64() <= pivot && chunk[len(chunk)-1].Number.Uint64() >= pivot {
if pivot := chunk[int(pivot-chunk[0].Number.Uint64())]; pivot.Hash() != d.fsPivotLock.Hash() {
- glog.V(logger.Warn).Infof("Pivot doesn't match locked in version: have #%v [%x…], want #%v [%x…]", pivot.Number, pivot.Hash().Bytes()[:4], d.fsPivotLock.Number, d.fsPivotLock.Hash().Bytes()[:4])
+ log.Warn("Pivot doesn't match locked in one", "remoteNumber", pivot.Number, "remoteHash", pivot.Hash(), "localNumber", d.fsPivotLock.Number, "localHash", d.fsPivotLock.Hash())
return errInvalidChain
}
}
@@ -1328,7 +1333,7 @@ func (d *Downloader) processHeaders(origin uint64, td *big.Int) error {
// Otherwise insert the headers for content retrieval
inserts := d.queue.Schedule(chunk, origin)
if len(inserts) != len(chunk) {
- glog.V(logger.Debug).Infof("stale headers")
+ log.Debug("Stale headers")
return errBadPeer
}
}
@@ -1359,10 +1364,11 @@ func (d *Downloader) processContent() error {
d.chainInsertHook(results)
}
// Actually import the blocks
- if glog.V(logger.Debug) {
- first, last := results[0].Header, results[len(results)-1].Header
- glog.Infof("Inserting chain with %d items (#%d [%x…] - #%d [%x…])", len(results), first.Number, first.Hash().Bytes()[:4], last.Number, last.Hash().Bytes()[:4])
- }
+ first, last := results[0].Header, results[len(results)-1].Header
+ log.Debug("Inserting downloaded chain", "items", len(results),
+ "firstnum", first.Number, "firsthash", first.Hash(),
+ "lastnum", last.Number, "lasthash", last.Hash(),
+ )
for len(results) != 0 {
// Check for any termination requests
select {
@@ -1396,14 +1402,14 @@ func (d *Downloader) processContent() error {
case len(receipts) > 0:
index, err = d.insertReceipts(blocks, receipts)
if err == nil && blocks[len(blocks)-1].NumberU64() == pivot {
- glog.V(logger.Debug).Infof("Committing block #%d [%x…] as the new head", blocks[len(blocks)-1].Number(), blocks[len(blocks)-1].Hash().Bytes()[:4])
+ log.Debug("Committing block as new head", "number", blocks[len(blocks)-1].Number(), "hash", blocks[len(blocks)-1].Hash())
index, err = len(blocks)-1, d.commitHeadBlock(blocks[len(blocks)-1].Hash())
}
default:
index, err = d.insertBlocks(blocks)
}
if err != nil {
- glog.V(logger.Debug).Infof("Result #%d [%x…] processing failed: %v", results[index].Header.Number, results[index].Header.Hash().Bytes()[:4], err)
+ log.Debug("Downloaded item processing failed", "number", results[index].Header.Number, "hash", results[index].Header.Hash(), "err", err)
return errInvalidChain
}
// Shift the results to the next batch
@@ -1471,7 +1477,7 @@ func (d *Downloader) qosTuner() {
atomic.StoreUint64(&d.rttConfidence, conf)
// Log the new QoS values and sleep until the next RTT
- glog.V(logger.Debug).Infof("Quality of service: rtt %v, conf %.3f, ttl %v", rtt, float64(conf)/1000000.0, d.requestTTL())
+ log.Debug("Recalculated downloader QoS values", "rtt", rtt, "confidence", float64(conf)/1000000.0, "ttl", d.requestTTL())
select {
case <-d.quitCh:
return
@@ -1501,7 +1507,7 @@ func (d *Downloader) qosReduceConfidence() {
atomic.StoreUint64(&d.rttConfidence, conf)
rtt := time.Duration(atomic.LoadUint64(&d.rttEstimate))
- glog.V(logger.Debug).Infof("Quality of service: rtt %v, conf %.3f, ttl %v", rtt, float64(conf)/1000000.0, d.requestTTL())
+ log.Debug("Relaxed downloader QoS values", "rtt", rtt, "confidence", float64(conf)/1000000.0, "ttl", d.requestTTL())
}
// requestRTT returns the current target round trip time for a download request
diff --git a/eth/downloader/downloader_test.go b/eth/downloader/downloader_test.go
index b156c471df..267a0def94 100644
--- a/eth/downloader/downloader_test.go
+++ b/eth/downloader/downloader_test.go
@@ -119,7 +119,7 @@ func (dl *downloadTester) makeChain(n int, seed byte, parent *types.Block, paren
// If the block number is multiple of 3, send a bonus transaction to the miner
if parent == dl.genesis && i%3 == 0 {
signer := types.MakeSigner(params.TestChainConfig, block.Number())
- tx, err := types.SignTx(types.NewTransaction(block.TxNonce(testAddress), common.Address{seed}, big.NewInt(1000), params.TxGas, nil, nil), signer, testKey)
+ tx, err := types.SignTx(types.NewTransaction(block.TxNonce(testAddress), common.Address{seed}, big.NewInt(1000), new(big.Int).SetUint64(params.TxGas), nil, nil), signer, testKey)
if err != nil {
panic(err)
}
@@ -982,7 +982,7 @@ func testCancel(t *testing.T, protocol int, mode SyncMode) {
tester.newPeer("peer", protocol, hashes, headers, blocks, receipts)
// Make sure canceling works with a pristine downloader
- tester.downloader.cancel()
+ tester.downloader.Cancel()
if !tester.downloader.queue.Idle() {
t.Errorf("download queue not idle")
}
@@ -990,7 +990,7 @@ func testCancel(t *testing.T, protocol int, mode SyncMode) {
if err := tester.sync("peer", nil, mode); err != nil {
t.Fatalf("failed to synchronise blocks: %v", err)
}
- tester.downloader.cancel()
+ tester.downloader.Cancel()
if !tester.downloader.queue.Idle() {
t.Errorf("download queue not idle")
}
diff --git a/eth/downloader/modes.go b/eth/downloader/modes.go
index ec339c0740..ae3c43888a 100644
--- a/eth/downloader/modes.go
+++ b/eth/downloader/modes.go
@@ -24,3 +24,17 @@ const (
FastSync // Quickly download the headers, full sync only at the chain head
LightSync // Download only the headers and terminate afterwards
)
+
+// String implements the stringer interface.
+func (mode SyncMode) String() string {
+ switch mode {
+ case FullSync:
+ return "full"
+ case FastSync:
+ return "fast"
+ case LightSync:
+ return "light"
+ default:
+ return "unknown"
+ }
+}
diff --git a/eth/downloader/peer.go b/eth/downloader/peer.go
index ea4b6a6f2f..15a912f1f2 100644
--- a/eth/downloader/peer.go
+++ b/eth/downloader/peer.go
@@ -25,12 +25,12 @@ import (
"math"
"math/big"
"sort"
- "strings"
"sync"
"sync/atomic"
"time"
"github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/log"
)
const (
@@ -86,7 +86,8 @@ type peer struct {
getReceipts receiptFetcherFn // [eth/63] Method to retrieve a batch of block transaction receipts
getNodeData stateFetcherFn // [eth/63] Method to retrieve a batch of state trie data
- version int // Eth protocol version number to switch strategies
+ version int // Eth protocol version number to switch strategies
+ log log.Logger // Contextual logger to add extra infos to peer logs
lock sync.RWMutex
}
@@ -94,7 +95,8 @@ type peer struct {
// mechanisms.
func newPeer(id string, version int, currentHead currentHeadRetrievalFn,
getRelHeaders relativeHeaderFetcherFn, getAbsHeaders absoluteHeaderFetcherFn, getBlockBodies blockBodyFetcherFn,
- getReceipts receiptFetcherFn, getNodeData stateFetcherFn) *peer {
+ getReceipts receiptFetcherFn, getNodeData stateFetcherFn, logger log.Logger) *peer {
+
return &peer{
id: id,
lacking: make(map[common.Hash]struct{}),
@@ -108,6 +110,7 @@ func newPeer(id string, version int, currentHead currentHeadRetrievalFn,
getNodeData: getNodeData,
version: version,
+ log: logger,
}
}
@@ -268,6 +271,11 @@ func (p *peer) setIdle(started time.Time, delivered int, throughput *float64, id
*throughput = (1-measurementImpact)*(*throughput) + measurementImpact*measured
p.rtt = time.Duration((1-measurementImpact)*float64(p.rtt) + measurementImpact*float64(elapsed))
+
+ p.log.Trace("Peer throughput measurements updated",
+ "hps", p.headerThroughput, "bps", p.blockThroughput,
+ "rps", p.receiptThroughput, "sps", p.stateThroughput,
+ "miss", len(p.lacking), "rtt", p.rtt)
}
// HeaderCapacity retrieves the peers header download allowance based on its
@@ -332,21 +340,6 @@ func (p *peer) Lacks(hash common.Hash) bool {
return ok
}
-// String implements fmt.Stringer.
-func (p *peer) String() string {
- p.lock.RLock()
- defer p.lock.RUnlock()
-
- return fmt.Sprintf("Peer %s [%s]", p.id, strings.Join([]string{
- fmt.Sprintf("hs %3.2f/s", p.headerThroughput),
- fmt.Sprintf("bs %3.2f/s", p.blockThroughput),
- fmt.Sprintf("rs %3.2f/s", p.receiptThroughput),
- fmt.Sprintf("ss %3.2f/s", p.stateThroughput),
- fmt.Sprintf("miss %4d", len(p.lacking)),
- fmt.Sprintf("rtt %v", p.rtt),
- }, ", "))
-}
-
// peerSet represents the collection of active peer participating in the chain
// download procedure.
type peerSet struct {
diff --git a/eth/downloader/queue.go b/eth/downloader/queue.go
index 5be09f37dc..855097c45a 100644
--- a/eth/downloader/queue.go
+++ b/eth/downloader/queue.go
@@ -30,8 +30,7 @@ import (
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethdb"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/trie"
"github.com/rcrowley/go-metrics"
"gopkg.in/karalabe/cookiejar.v2/collections/prque"
@@ -365,20 +364,20 @@ func (q *queue) Schedule(headers []*types.Header, from uint64) []*types.Header {
// Make sure chain order is honoured and preserved throughout
hash := header.Hash()
if header.Number == nil || header.Number.Uint64() != from {
- glog.V(logger.Warn).Infof("Header #%v [%x…] broke chain ordering, expected %d", header.Number, hash[:4], from)
+ log.Warn("Header broke chain ordering", "number", header.Number, "hash", hash, "expected", from)
break
}
if q.headerHead != (common.Hash{}) && q.headerHead != header.ParentHash {
- glog.V(logger.Warn).Infof("Header #%v [%x…] broke chain ancestry", header.Number, hash[:4])
+ log.Warn("Header broke chain ancestry", "number", header.Number, "hash", hash)
break
}
// Make sure no duplicate requests are executed
if _, ok := q.blockTaskPool[hash]; ok {
- glog.V(logger.Warn).Infof("Header #%d [%x…] already scheduled for block fetch", header.Number.Uint64(), hash[:4])
+ log.Warn("Header already scheduled for block fetch", "number", header.Number, "hash", hash)
continue
}
if _, ok := q.receiptTaskPool[hash]; ok {
- glog.V(logger.Warn).Infof("Header #%d [%x…] already scheduled for receipt fetch", header.Number.Uint64(), hash[:4])
+ log.Warn("Header already scheduled for receipt fetch", "number", header.Number, "hash", hash)
continue
}
// Queue the header for content retrieval
@@ -392,7 +391,7 @@ func (q *queue) Schedule(headers []*types.Header, from uint64) []*types.Header {
}
if q.mode == FastSync && header.Number.Uint64() == q.fastSyncPivot {
// Pivoting point of the fast sync, switch the state retrieval to this
- glog.V(logger.Debug).Infof("Switching state downloads to %d [%x…]", header.Number.Uint64(), header.Hash().Bytes()[:4])
+ log.Debug("Switching state downloads to new block", "number", header.Number, "hash", hash)
q.stateTaskIndex = 0
q.stateTaskPool = make(map[common.Hash]int)
@@ -873,10 +872,10 @@ func (q *queue) DeliverHeaders(id string, headers []*types.Header, headerProcCh
accepted := len(headers) == MaxHeaderFetch
if accepted {
if headers[0].Number.Uint64() != request.From {
- glog.V(logger.Detail).Infof("Peer %s: first header #%v [%x…] broke chain ordering, expected %d", id, headers[0].Number, headers[0].Hash().Bytes()[:4], request.From)
+ log.Trace("First header broke chain ordering", "peer", id, "number", headers[0].Number, "hash", headers[0].Hash(), request.From)
accepted = false
} else if headers[len(headers)-1].Hash() != target {
- glog.V(logger.Detail).Infof("Peer %s: last header #%v [%x…] broke skeleton structure, expected %x", id, headers[len(headers)-1].Number, headers[len(headers)-1].Hash().Bytes()[:4], target[:4])
+ log.Trace("Last header broke skeleton structure ", "peer", id, "number", headers[len(headers)-1].Number, "hash", headers[len(headers)-1].Hash(), "expected", target)
accepted = false
}
}
@@ -884,12 +883,12 @@ func (q *queue) DeliverHeaders(id string, headers []*types.Header, headerProcCh
for i, header := range headers[1:] {
hash := header.Hash()
if want := request.From + 1 + uint64(i); header.Number.Uint64() != want {
- glog.V(logger.Warn).Infof("Peer %s: header #%v [%x…] broke chain ordering, expected %d", id, header.Number, hash[:4], want)
+ log.Warn("Header broke chain ordering", "peer", id, "number", header.Number, "hash", hash, "expected", want)
accepted = false
break
}
if headers[i].Hash() != header.ParentHash {
- glog.V(logger.Warn).Infof("Peer %s: header #%v [%x…] broke chain ancestry", id, header.Number, hash[:4])
+ log.Warn("Header broke chain ancestry", "peer", id, "number", header.Number, "hash", hash)
accepted = false
break
}
@@ -897,7 +896,7 @@ func (q *queue) DeliverHeaders(id string, headers []*types.Header, headerProcCh
}
// If the batch of headers wasn't accepted, mark as unavailable
if !accepted {
- glog.V(logger.Detail).Infof("Peer %s: skeleton filling from header #%d not accepted", id, request.From)
+ log.Trace("Skeleton filling not accepted", "peer", id, "from", request.From)
miss := q.headerPeerMiss[id]
if miss == nil {
@@ -924,7 +923,7 @@ func (q *queue) DeliverHeaders(id string, headers []*types.Header, headerProcCh
select {
case headerProcCh <- process:
- glog.V(logger.Detail).Infof("%s: pre-scheduled %d headers from #%v", id, len(process), process[0].Number)
+ log.Trace("Pre-scheduled new headers", "peer", id, "count", len(process), "from", process[0].Number)
q.headerProced += len(process)
default:
}
diff --git a/eth/fetcher/fetcher.go b/eth/fetcher/fetcher.go
index e225b49965..d82f4f3e6c 100644
--- a/eth/fetcher/fetcher.go
+++ b/eth/fetcher/fetcher.go
@@ -19,15 +19,13 @@ package fetcher
import (
"errors"
- "fmt"
"math/rand"
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/types"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/log"
"gopkg.in/karalabe/cookiejar.v2/collections/prque"
)
@@ -79,8 +77,8 @@ type announce struct {
origin string // Identifier of the peer originating the notification
- fetchHeader headerRequesterFn // [eth/62] Fetcher function to retrieve the header of an announced block
- fetchBodies bodyRequesterFn // [eth/62] Fetcher function to retrieve the body of an announced block
+ fetchHeader headerRequesterFn // Fetcher function to retrieve the header of an announced block
+ fetchBodies bodyRequesterFn // Fetcher function to retrieve the body of an announced block
}
// headerFilterTask represents a batch of headers needing fetcher filtering.
@@ -221,7 +219,7 @@ func (f *Fetcher) Enqueue(peer string, block *types.Block) error {
// FilterHeaders extracts all the headers that were explicitly requested by the fetcher,
// returning those that should be handled differently.
func (f *Fetcher) FilterHeaders(headers []*types.Header, time time.Time) []*types.Header {
- glog.V(logger.Detail).Infof("[eth/62] filtering %d headers", len(headers))
+ log.Trace("Filtering headers", "headers", len(headers))
// Send the filter channel to the fetcher
filter := make(chan *headerFilterTask)
@@ -249,7 +247,7 @@ func (f *Fetcher) FilterHeaders(headers []*types.Header, time time.Time) []*type
// FilterBodies extracts all the block bodies that were explicitly requested by
// the fetcher, returning those that should be handled differently.
func (f *Fetcher) FilterBodies(transactions [][]*types.Transaction, uncles [][]*types.Header, time time.Time) ([][]*types.Transaction, [][]*types.Header) {
- glog.V(logger.Detail).Infof("[eth/62] filtering %d:%d bodies", len(transactions), len(uncles))
+ log.Trace("Filtering bodies", "txs", len(transactions), "uncles", len(uncles))
// Send the filter channel to the fetcher
filter := make(chan *bodyFilterTask)
@@ -324,14 +322,14 @@ func (f *Fetcher) loop() {
count := f.announces[notification.origin] + 1
if count > hashLimit {
- glog.V(logger.Debug).Infof("Peer %s: exceeded outstanding announces (%d)", notification.origin, hashLimit)
+ log.Debug("Peer exceeded outstanding announces", "peer", notification.origin, "limit", hashLimit)
propAnnounceDOSMeter.Mark(1)
break
}
// If we have a valid block number, check that it's potentially useful
if notification.number > 0 {
if dist := int64(notification.number) - int64(f.chainHeight()); dist < -maxUncleDist || dist > maxQueueDist {
- glog.V(logger.Debug).Infof("[eth/62] Peer %s: discarded announcement #%d [%x…], distance %d", notification.origin, notification.number, notification.hash[:4], dist)
+ log.Debug("Peer discarded announcement", "peer", notification.origin, "number", notification.number, "hash", notification.hash, "distance", dist)
propAnnounceDropMeter.Mark(1)
break
}
@@ -381,14 +379,8 @@ func (f *Fetcher) loop() {
}
// Send out all block header requests
for peer, hashes := range request {
- if glog.V(logger.Detail) && len(hashes) > 0 {
- list := "["
- for _, hash := range hashes {
- list += fmt.Sprintf("%x…, ", hash[:4])
- }
- list = list[:len(list)-2] + "]"
- glog.V(logger.Detail).Infof("[eth/62] Peer %s: fetching headers %s", peer, list)
- }
+ log.Trace("Fetching scheduled headers", "peer", peer, "list", hashes)
+
// Create a closure of the fetch and schedule in on a new thread
fetchHeader, hashes := f.fetching[hashes[0]].fetchHeader, hashes
go func() {
@@ -421,15 +413,8 @@ func (f *Fetcher) loop() {
}
// Send out all block body requests
for peer, hashes := range request {
- if glog.V(logger.Detail) && len(hashes) > 0 {
- list := "["
- for _, hash := range hashes {
- list += fmt.Sprintf("%x…, ", hash[:4])
- }
- list = list[:len(list)-2] + "]"
+ log.Trace("Fetching scheduled bodies", "peer", peer, "list", hashes)
- glog.V(logger.Detail).Infof("[eth/62] Peer %s: fetching bodies %s", peer, list)
- }
// Create a closure of the fetch and schedule in on a new thread
if f.completingHook != nil {
f.completingHook(hashes)
@@ -462,7 +447,7 @@ func (f *Fetcher) loop() {
if announce := f.fetching[hash]; announce != nil && f.fetched[hash] == nil && f.completing[hash] == nil && f.queued[hash] == nil {
// If the delivered header does not match the promised number, drop the announcer
if header.Number.Uint64() != announce.number {
- glog.V(logger.Detail).Infof("[eth/62] Peer %s: invalid block number for [%x…]: announced %d, provided %d", announce.origin, header.Hash().Bytes()[:4], announce.number, header.Number.Uint64())
+ log.Trace("Invalid block number fetched", "peer", announce.origin, "hash", header.Hash(), "announced", announce.number, "provided", header.Number)
f.dropPeer(announce.origin)
f.forgetHash(hash)
continue
@@ -474,7 +459,7 @@ func (f *Fetcher) loop() {
// If the block is empty (header only), short circuit into the final import queue
if header.TxHash == types.DeriveSha(types.Transactions{}) && header.UncleHash == types.CalcUncleHash([]*types.Header{}) {
- glog.V(logger.Detail).Infof("[eth/62] Peer %s: block #%d [%x…] empty, skipping body retrieval", announce.origin, header.Number.Uint64(), header.Hash().Bytes()[:4])
+ log.Trace("Block empty, skipping body retrieval", "peer", announce.origin, "number", header.Number, "hash", header.Hash())
block := types.NewBlockWithHeader(header)
block.ReceivedAt = task.time
@@ -486,7 +471,7 @@ func (f *Fetcher) loop() {
// Otherwise add to the list of blocks needing completion
incomplete = append(incomplete, announce)
} else {
- glog.V(logger.Detail).Infof("[eth/62] Peer %s: block #%d [%x…] already imported, discarding header", announce.origin, header.Number.Uint64(), header.Hash().Bytes()[:4])
+ log.Trace("Block already imported, discarding header", "peer", announce.origin, "number", header.Number, "hash", header.Hash())
f.forgetHash(hash)
}
} else {
@@ -617,14 +602,14 @@ func (f *Fetcher) enqueue(peer string, block *types.Block) {
// Ensure the peer isn't DOSing us
count := f.queues[peer] + 1
if count > blockLimit {
- glog.V(logger.Debug).Infof("Peer %s: discarded block #%d [%x…], exceeded allowance (%d)", peer, block.NumberU64(), hash.Bytes()[:4], blockLimit)
+ log.Debug("Discarded propagated block, exceeded allowance", "peer", peer, "number", block.Number(), "hash", hash, "limit", blockLimit)
propBroadcastDOSMeter.Mark(1)
f.forgetHash(hash)
return
}
// Discard any past or too distant blocks
if dist := int64(block.NumberU64()) - int64(f.chainHeight()); dist < -maxUncleDist || dist > maxQueueDist {
- glog.V(logger.Debug).Infof("Peer %s: discarded block #%d [%x…], distance %d", peer, block.NumberU64(), hash.Bytes()[:4], dist)
+ log.Debug("Discarded propagated block, too far away", "peer", peer, "number", block.Number(), "hash", hash, "distance", dist)
propBroadcastDropMeter.Mark(1)
f.forgetHash(hash)
return
@@ -641,9 +626,7 @@ func (f *Fetcher) enqueue(peer string, block *types.Block) {
if f.queueChangeHook != nil {
f.queueChangeHook(op.block.Hash(), true)
}
- if glog.V(logger.Debug) {
- glog.Infof("Peer %s: queued block #%d [%x…], total %v", peer, block.NumberU64(), hash.Bytes()[:4], f.queue.Size())
- }
+ log.Debug("Queued propagated block", "peer", peer, "number", block.Number(), "hash", hash, "queued", f.queue.Size())
}
}
@@ -654,14 +637,14 @@ func (f *Fetcher) insert(peer string, block *types.Block) {
hash := block.Hash()
// Run the import on a new thread
- glog.V(logger.Debug).Infof("Peer %s: importing block #%d [%x…]", peer, block.NumberU64(), hash[:4])
+ log.Debug("Importing propagated block", "peer", peer, "number", block.Number(), "hash", hash)
go func() {
defer func() { f.done <- hash }()
// If the parent's unknown, abort insertion
parent := f.getBlock(block.ParentHash())
if parent == nil {
- glog.V(logger.Debug).Infof("Peer %s: parent [%x…] of block #%d [%x…] unknown", peer, block.ParentHash().Bytes()[:4], block.NumberU64(), hash[:4])
+ log.Debug("Unknown parent of propagated block", "peer", peer, "number", block.Number(), "hash", hash, "parent", block.ParentHash())
return
}
// Quickly validate the header and propagate the block if it passes
@@ -676,13 +659,13 @@ func (f *Fetcher) insert(peer string, block *types.Block) {
default:
// Something went very wrong, drop the peer
- glog.V(logger.Debug).Infof("Peer %s: block #%d [%x…] verification failed: %v", peer, block.NumberU64(), hash[:4], err)
+ log.Debug("Propagated block verification failed", "peer", peer, "number", block.Number(), "hash", hash, "err", err)
f.dropPeer(peer)
return
}
// Run the actual import and log any issues
if _, err := f.insertChain(types.Blocks{block}); err != nil {
- glog.V(logger.Warn).Infof("Peer %s: block #%d [%x…] import failed: %v", peer, block.NumberU64(), hash[:4], err)
+ log.Debug("Propagated block import failed", "peer", peer, "number", block.Number(), "hash", hash, "err", err)
return
}
// If import succeeded, broadcast the block
diff --git a/eth/fetcher/fetcher_test.go b/eth/fetcher/fetcher_test.go
index 2e28541ab3..7a94241c66 100644
--- a/eth/fetcher/fetcher_test.go
+++ b/eth/fetcher/fetcher_test.go
@@ -51,7 +51,7 @@ func makeChain(n int, seed byte, parent *types.Block) ([]common.Hash, map[common
// If the block number is multiple of 3, send a bonus transaction to the miner
if parent == genesis && i%3 == 0 {
signer := types.MakeSigner(params.TestChainConfig, block.Number())
- tx, err := types.SignTx(types.NewTransaction(block.TxNonce(testAddress), common.Address{seed}, big.NewInt(1000), params.TxGas, nil, nil), signer, testKey)
+ tx, err := types.SignTx(types.NewTransaction(block.TxNonce(testAddress), common.Address{seed}, big.NewInt(1000), new(big.Int).SetUint64(params.TxGas), nil, nil), signer, testKey)
if err != nil {
panic(err)
}
diff --git a/eth/filters/api.go b/eth/filters/api.go
index 02a544ce1b..61647a5d07 100644
--- a/eth/filters/api.go
+++ b/eth/filters/api.go
@@ -17,6 +17,7 @@
package filters
import (
+ "context"
"encoding/json"
"errors"
"fmt"
@@ -24,8 +25,6 @@ import (
"sync"
"time"
- "golang.org/x/net/context"
-
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/types"
diff --git a/eth/filters/filter.go b/eth/filters/filter.go
index 9a8e2fd70a..0a0b81224e 100644
--- a/eth/filters/filter.go
+++ b/eth/filters/filter.go
@@ -17,10 +17,10 @@
package filters
import (
+ "context"
"math"
- "time"
-
"math/big"
+ "time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
@@ -28,7 +28,6 @@ import (
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/rpc"
- "golang.org/x/net/context"
)
type Backend interface {
diff --git a/eth/filters/filter_system.go b/eth/filters/filter_system.go
index 3adf8111ad..7abace1e6b 100644
--- a/eth/filters/filter_system.go
+++ b/eth/filters/filter_system.go
@@ -19,6 +19,7 @@
package filters
import (
+ "context"
"errors"
"fmt"
"sync"
@@ -29,7 +30,6 @@ import (
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/rpc"
- "golang.org/x/net/context"
)
// Type determines the kind of filter and is used to put the filter in to
@@ -372,7 +372,8 @@ func (es *EventSystem) lightFilterNewHead(newHeader *types.Header, callBack func
func (es *EventSystem) lightFilterLogs(header *types.Header, addresses []common.Address, topics [][]common.Hash, remove bool) []*types.Log {
if bloomFilter(header.Bloom, addresses, topics) {
// Get the logs of the block
- ctx, _ := context.WithTimeout(context.Background(), time.Second*5)
+ ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
+ defer cancel()
receipts, err := es.backend.GetReceipts(ctx, header.Hash())
if err != nil {
return nil
diff --git a/eth/filters/filter_system_test.go b/eth/filters/filter_system_test.go
index 1cfced7e41..822580b56c 100644
--- a/eth/filters/filter_system_test.go
+++ b/eth/filters/filter_system_test.go
@@ -17,13 +17,12 @@
package filters
import (
+ "context"
"math/big"
"reflect"
"testing"
"time"
- "golang.org/x/net/context"
-
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/types"
@@ -73,12 +72,11 @@ func TestBlockSubscription(t *testing.T) {
t.Parallel()
var (
- mux = new(event.TypeMux)
- db, _ = ethdb.NewMemDatabase()
- backend = &testBackend{mux, db}
- api = NewPublicFilterAPI(backend, false)
-
- genesis = core.WriteGenesisBlockForTesting(db)
+ mux = new(event.TypeMux)
+ db, _ = ethdb.NewMemDatabase()
+ backend = &testBackend{mux, db}
+ api = NewPublicFilterAPI(backend, false)
+ genesis = new(core.Genesis).MustCommit(db)
chain, _ = core.GenerateChain(params.TestChainConfig, genesis, db, 10, func(i int, gen *core.BlockGen) {})
chainEvents = []core.ChainEvent{}
)
diff --git a/eth/filters/filter_test.go b/eth/filters/filter_test.go
index 83ff3e9ce0..cd5e7cafd5 100644
--- a/eth/filters/filter_test.go
+++ b/eth/filters/filter_test.go
@@ -17,13 +17,12 @@
package filters
import (
+ "context"
"io/ioutil"
"math/big"
"os"
"testing"
- "golang.org/x/net/context"
-
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/types"
@@ -61,7 +60,7 @@ func BenchmarkMipmaps(b *testing.B) {
)
defer db.Close()
- genesis := core.WriteGenesisBlockForTesting(db, core.GenesisAccount{Address: addr1, Balance: big.NewInt(1000000)})
+ genesis := core.GenesisBlockForTesting(db, addr1, big.NewInt(1000000))
chain, receipts := core.GenerateChain(params.TestChainConfig, genesis, db, 100010, func(i int, gen *core.BlockGen) {
var receipts types.Receipts
switch i {
@@ -113,7 +112,7 @@ func BenchmarkMipmaps(b *testing.B) {
for i := 0; i < b.N; i++ {
logs, _ := filter.Find(context.Background())
if len(logs) != 4 {
- b.Fatal("expected 4 log, got", len(logs))
+ b.Fatal("expected 4 logs, got", len(logs))
}
}
}
@@ -139,7 +138,7 @@ func TestFilters(t *testing.T) {
)
defer db.Close()
- genesis := core.WriteGenesisBlockForTesting(db, core.GenesisAccount{Address: addr, Balance: big.NewInt(1000000)})
+ genesis := core.GenesisBlockForTesting(db, addr, big.NewInt(1000000))
chain, receipts := core.GenerateChain(params.TestChainConfig, genesis, db, 1000, func(i int, gen *core.BlockGen) {
var receipts types.Receipts
switch i {
diff --git a/eth/gasprice/gasprice.go b/eth/gasprice/gasprice.go
index eb2df4a96e..73951bce90 100644
--- a/eth/gasprice/gasprice.go
+++ b/eth/gasprice/gasprice.go
@@ -25,8 +25,7 @@ import (
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/log"
)
const (
@@ -176,7 +175,7 @@ func (self *GasPriceOracle) processBlock(block *types.Block) {
self.lastBase = newBase
self.lastBaseMutex.Unlock()
- glog.V(logger.Detail).Infof("Processed block #%v, base price is %v\n", i, newBase.Int64())
+ log.Trace("Processed block, base price updated", "number", i, "base", newBase)
}
// returns the lowers possible price with which a tx was or could have been included
diff --git a/eth/gasprice/lightprice.go b/eth/gasprice/lightprice.go
index 8886d32d7d..562c7dd974 100644
--- a/eth/gasprice/lightprice.go
+++ b/eth/gasprice/lightprice.go
@@ -17,6 +17,7 @@
package gasprice
import (
+ "context"
"math/big"
"sort"
"sync"
@@ -24,7 +25,6 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/internal/ethapi"
"github.com/ethereum/go-ethereum/rpc"
- "golang.org/x/net/context"
)
const (
diff --git a/eth/handler.go b/eth/handler.go
index 0e7eed3520..ade8f77192 100644
--- a/eth/handler.go
+++ b/eth/handler.go
@@ -33,8 +33,7 @@ import (
"github.com/ethereum/go-ethereum/eth/fetcher"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/p2p/discover"
"github.com/ethereum/go-ethereum/params"
@@ -116,7 +115,7 @@ func NewProtocolManager(config *params.ChainConfig, fastSync bool, networkId int
}
// Figure out whether to allow fast sync or not
if fastSync && blockchain.CurrentBlock().NumberU64() > 0 {
- glog.V(logger.Info).Infof("blockchain not empty, fast sync disabled")
+ log.Warn("Blockchain not empty, fast sync disabled")
fastSync = false
}
if fastSync {
@@ -179,7 +178,7 @@ func NewProtocolManager(config *params.ChainConfig, fastSync bool, networkId int
manager.fetcher = fetcher.New(blockchain.GetBlockByHash, validator, manager.BroadcastBlock, heighter, inserter, manager.removePeer)
if blockchain.Genesis().Hash().Hex() == defaultGenesisHash && networkId == 1 {
- glog.V(logger.Debug).Infoln("Bad Block Reporting is enabled")
+ log.Debug("Bad block reporting is enabled")
manager.badBlockReportingEnabled = true
}
@@ -200,12 +199,12 @@ func (pm *ProtocolManager) removePeer(id string) {
if peer == nil {
return
}
- glog.V(logger.Debug).Infoln("Removing peer", id)
+ log.Debug("Removing Ethereum peer", "peer", id)
// Unregister the peer from the downloader and Ethereum peer set
pm.downloader.UnregisterPeer(id)
if err := pm.peers.Unregister(id); err != nil {
- glog.V(logger.Error).Infoln("Removal failed:", err)
+ log.Error("Peer removal failed", "peer", id, "err", err)
}
// Hard disconnect at the networking layer
if peer != nil {
@@ -227,7 +226,7 @@ func (pm *ProtocolManager) Start() {
}
func (pm *ProtocolManager) Stop() {
- glog.V(logger.Info).Infoln("Stopping ethereum protocol handler...")
+ log.Info("Stopping Ethereum protocol")
pm.txSub.Unsubscribe() // quits txBroadcastLoop
pm.minedBlockSub.Unsubscribe() // quits blockBroadcastLoop
@@ -248,7 +247,7 @@ func (pm *ProtocolManager) Stop() {
// Wait for all peer handler goroutines and the loops to come down.
pm.wg.Wait()
- glog.V(logger.Info).Infoln("Ethereum protocol handler stopped")
+ log.Info("Ethereum protocol stopped")
}
func (pm *ProtocolManager) newPeer(pv int, p *p2p.Peer, rw p2p.MsgReadWriter) *peer {
@@ -261,22 +260,20 @@ func (pm *ProtocolManager) handle(p *peer) error {
if pm.peers.Len() >= pm.maxPeers {
return p2p.DiscTooManyPeers
}
-
- glog.V(logger.Debug).Infof("%v: peer connected [%s]", p, p.Name())
+ p.Log().Debug("Ethereum peer connected", "name", p.Name())
// Execute the Ethereum handshake
td, head, genesis := pm.blockchain.Status()
if err := p.Handshake(pm.networkId, td, head, genesis); err != nil {
- glog.V(logger.Debug).Infof("%v: handshake failed: %v", p, err)
+ p.Log().Debug("Ethereum handshake failed", "err", err)
return err
}
if rw, ok := p.rw.(*meteredMsgReadWriter); ok {
rw.Init(p.version)
}
// Register the peer locally
- glog.V(logger.Detail).Infof("%v: adding peer", p)
if err := pm.peers.Register(p); err != nil {
- glog.V(logger.Error).Infof("%v: addition failed: %v", p, err)
+ p.Log().Error("Ethereum peer registration failed", "err", err)
return err
}
defer pm.removePeer(p.id)
@@ -297,7 +294,7 @@ func (pm *ProtocolManager) handle(p *peer) error {
}
// Start a timer to disconnect if the peer doesn't reply in time
p.forkDrop = time.AfterFunc(daoChallengeTimeout, func() {
- glog.V(logger.Debug).Infof("%v: timed out DAO fork-check, dropping", p)
+ p.Log().Debug("Timed out DAO fork-check, dropping")
pm.removePeer(p.id)
})
// Make sure it's cleaned up if the peer dies off
@@ -311,7 +308,7 @@ func (pm *ProtocolManager) handle(p *peer) error {
// main loop. handle incoming messages.
for {
if err := pm.handleMsg(p); err != nil {
- glog.V(logger.Debug).Infof("%v: message handling failed: %v", p, err)
+ p.Log().Debug("Ethereum message handling failed", "err", err)
return err
}
}
@@ -387,7 +384,7 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
)
if next <= current {
infos, _ := json.MarshalIndent(p.Peer.Info(), "", " ")
- glog.V(logger.Warn).Infof("%v: GetBlockHeaders skip overflow attack (current %v, skip %v, next %v)\nMalicious peer infos: %s", p, current, query.Skip, next, infos)
+ p.Log().Warn("GetBlockHeaders skip overflow attack", "current", current, "skip", query.Skip, "next", next, "attacker", infos)
unknown = true
} else {
if header := pm.blockchain.GetHeaderByNumber(next); header != nil {
@@ -435,7 +432,7 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
}
// If we're seemingly on the same chain, disable the drop timer
if verifyDAO {
- glog.V(logger.Debug).Infof("%v: seems to be on the same side of the DAO fork", p)
+ p.Log().Debug("Seems to be on the same side of the DAO fork")
p.forkDrop.Stop()
p.forkDrop = nil
return nil
@@ -452,10 +449,10 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
// Validate the header and either drop the peer or continue
if err := core.ValidateDAOHeaderExtraData(pm.chainconfig, headers[0]); err != nil {
- glog.V(logger.Debug).Infof("%v: verified to be on the other side of the DAO fork, dropping", p)
+ p.Log().Debug("Verified to be on the other side of the DAO fork, dropping")
return err
}
- glog.V(logger.Debug).Infof("%v: verified to be on the same side of the DAO fork", p)
+ p.Log().Debug("Verified to be on the same side of the DAO fork")
return nil
}
// Irrelevant of the fork checks, send the header to the fetcher just in case
@@ -464,7 +461,7 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
if len(headers) > 0 || !filter {
err := pm.downloader.DeliverHeaders(p.id, headers)
if err != nil {
- glog.V(logger.Debug).Infoln(err)
+ log.Debug("Failed to deliver headers", "err", err)
}
}
@@ -517,7 +514,7 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
if len(trasactions) > 0 || len(uncles) > 0 || !filter {
err := pm.downloader.DeliverBodies(p.id, trasactions, uncles)
if err != nil {
- glog.V(logger.Debug).Infoln(err)
+ log.Debug("Failed to deliver bodies", "err", err)
}
}
@@ -556,7 +553,7 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
}
// Deliver all to the downloader
if err := pm.downloader.DeliverNodeData(p.id, data); err != nil {
- glog.V(logger.Debug).Infof("failed to deliver node state data: %v", err)
+ log.Debug("Failed to deliver node state data", "err", err)
}
case p.version >= eth63 && msg.Code == GetReceiptsMsg:
@@ -587,7 +584,7 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
}
// If known, encode and queue for response packet
if encoded, err := rlp.EncodeToBytes(results); err != nil {
- glog.V(logger.Error).Infof("failed to encode receipt: %v", err)
+ log.Error("Failed to encode receipt", "err", err)
} else {
receipts = append(receipts, encoded)
bytes += len(encoded)
@@ -603,7 +600,7 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
}
// Deliver all to the downloader
if err := pm.downloader.DeliverReceipts(p.id, receipts); err != nil {
- glog.V(logger.Debug).Infof("failed to deliver receipts: %v", err)
+ log.Debug("Failed to deliver receipts", "err", err)
}
case msg.Code == NewBlockHashesMsg:
@@ -696,7 +693,7 @@ func (pm *ProtocolManager) BroadcastBlock(block *types.Block, propagate bool) {
if parent := pm.blockchain.GetBlock(block.ParentHash(), block.NumberU64()-1); parent != nil {
td = new(big.Int).Add(block.Difficulty(), pm.blockchain.GetTd(block.ParentHash(), block.NumberU64()-1))
} else {
- glog.V(logger.Error).Infof("propagating dangling block #%d [%x]", block.NumberU64(), hash[:4])
+ log.Error("Propagating dangling block", "number", block.Number(), "hash", hash)
return
}
// Send the block to a subset of our peers
@@ -704,14 +701,14 @@ func (pm *ProtocolManager) BroadcastBlock(block *types.Block, propagate bool) {
for _, peer := range transfer {
peer.SendNewBlock(block, td)
}
- glog.V(logger.Detail).Infof("propagated block %x to %d peers in %v", hash[:4], len(transfer), time.Since(block.ReceivedAt))
+ log.Trace("Propagated block", "hash", hash, "recipients", len(transfer), "duration", common.PrettyDuration(time.Since(block.ReceivedAt)))
}
// Otherwise if the block is indeed in out own chain, announce it
if pm.blockchain.HasBlock(hash) {
for _, peer := range peers {
peer.SendNewBlockHashes([]common.Hash{hash}, []uint64{block.NumberU64()})
}
- glog.V(logger.Detail).Infof("announced block %x to %d peers in %v", hash[:4], len(peers), time.Since(block.ReceivedAt))
+ log.Trace("Announced block", "hash", hash, "recipients", len(peers), "duration", common.PrettyDuration(time.Since(block.ReceivedAt)))
}
}
@@ -724,7 +721,7 @@ func (pm *ProtocolManager) BroadcastTx(hash common.Hash, tx *types.Transaction)
for _, peer := range peers {
peer.SendTransactions(types.Transactions{tx})
}
- glog.V(logger.Detail).Infoln("broadcast tx to", len(peers), "peers")
+ log.Trace("Broadcast transaction", "hash", hash, "recipients", len(peers))
}
// Mined broadcast loop
diff --git a/eth/handler_test.go b/eth/handler_test.go
index 8a5d7173b3..31435b331d 100644
--- a/eth/handler_test.go
+++ b/eth/handler_test.go
@@ -34,8 +34,11 @@ import (
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/params"
+ "github.com/ethereum/go-ethereum/pow"
)
+var bigTxGas = new(big.Int).SetUint64(params.TxGas)
+
// Tests that protocol versions and modes of operations are matched up properly.
func TestProtocolCompatibility(t *testing.T) {
// Define the compatibility chart
@@ -312,13 +315,13 @@ func testGetNodeData(t *testing.T, protocol int) {
switch i {
case 0:
// In block 1, the test bank sends account #1 some ether.
- tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank.Address), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil), signer, testBankKey)
+ tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank), acc1Addr, big.NewInt(10000), bigTxGas, nil, nil), signer, testBankKey)
block.AddTx(tx)
case 1:
// In block 2, the test bank sends some more ether to account #1.
// acc1Addr passes it on to account #2.
- tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank.Address), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, testBankKey)
- tx2, _ := types.SignTx(types.NewTransaction(block.TxNonce(acc1Addr), acc2Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, acc1Key)
+ tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank), acc1Addr, big.NewInt(1000), bigTxGas, nil, nil), signer, testBankKey)
+ tx2, _ := types.SignTx(types.NewTransaction(block.TxNonce(acc1Addr), acc2Addr, big.NewInt(1000), bigTxGas, nil, nil), signer, acc1Key)
block.AddTx(tx1)
block.AddTx(tx2)
case 2:
@@ -369,7 +372,7 @@ func testGetNodeData(t *testing.T, protocol int) {
for i := 0; i < len(data); i++ {
statedb.Put(hashes[i].Bytes(), data[i])
}
- accounts := []common.Address{testBank.Address, acc1Addr, acc2Addr}
+ accounts := []common.Address{testBank, acc1Addr, acc2Addr}
for i := uint64(0); i <= pm.blockchain.CurrentBlock().NumberU64(); i++ {
trie, _ := state.New(pm.blockchain.GetBlockByNumber(i).Root(), statedb)
@@ -404,13 +407,13 @@ func testGetReceipt(t *testing.T, protocol int) {
switch i {
case 0:
// In block 1, the test bank sends account #1 some ether.
- tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank.Address), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil), signer, testBankKey)
+ tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank), acc1Addr, big.NewInt(10000), bigTxGas, nil, nil), signer, testBankKey)
block.AddTx(tx)
case 1:
// In block 2, the test bank sends some more ether to account #1.
// acc1Addr passes it on to account #2.
- tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank.Address), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, testBankKey)
- tx2, _ := types.SignTx(types.NewTransaction(block.TxNonce(acc1Addr), acc2Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, acc1Key)
+ tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank), acc1Addr, big.NewInt(1000), bigTxGas, nil, nil), signer, testBankKey)
+ tx2, _ := types.SignTx(types.NewTransaction(block.TxNonce(acc1Addr), acc2Addr, big.NewInt(1000), bigTxGas, nil, nil), signer, acc1Key)
block.AddTx(tx1)
block.AddTx(tx2)
case 2:
@@ -466,10 +469,11 @@ func testDAOChallenge(t *testing.T, localForked, remoteForked bool, timeout bool
// Create a DAO aware protocol manager
var (
evmux = new(event.TypeMux)
- pow = new(core.FakePow)
+ pow = new(pow.FakePow)
db, _ = ethdb.NewMemDatabase()
- genesis = core.WriteGenesisBlockForTesting(db)
config = ¶ms.ChainConfig{DAOForkBlock: big.NewInt(1), DAOForkSupport: localForked}
+ gspec = &core.Genesis{Config: config}
+ genesis = gspec.MustCommit(db)
blockchain, _ = core.NewBlockChain(db, config, pow, evmux, vm.Config{})
)
pm, err := NewProtocolManager(config, false, NetworkId, 1000, evmux, new(testTxPool), pow, blockchain, db)
diff --git a/eth/helper_test.go b/eth/helper_test.go
index 0861c884bd..e67b496915 100644
--- a/eth/helper_test.go
+++ b/eth/helper_test.go
@@ -37,14 +37,12 @@ import (
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/p2p/discover"
"github.com/ethereum/go-ethereum/params"
+ "github.com/ethereum/go-ethereum/pow"
)
var (
testBankKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
- testBank = core.GenesisAccount{
- Address: crypto.PubkeyToAddress(testBankKey.PublicKey),
- Balance: big.NewInt(1000000),
- }
+ testBank = crypto.PubkeyToAddress(testBankKey.PublicKey)
)
// newTestProtocolManager creates a new protocol manager for testing purposes,
@@ -52,19 +50,22 @@ var (
// channels for different events.
func newTestProtocolManager(fastSync bool, blocks int, generator func(int, *core.BlockGen), newtx chan<- []*types.Transaction) (*ProtocolManager, error) {
var (
- evmux = new(event.TypeMux)
- pow = new(core.FakePow)
- db, _ = ethdb.NewMemDatabase()
- genesis = core.WriteGenesisBlockForTesting(db, testBank)
- chainConfig = ¶ms.ChainConfig{HomesteadBlock: big.NewInt(0)} // homestead set to 0 because of chain maker
- blockchain, _ = core.NewBlockChain(db, chainConfig, pow, evmux, vm.Config{})
+ evmux = new(event.TypeMux)
+ pow = new(pow.FakePow)
+ db, _ = ethdb.NewMemDatabase()
+ gspec = &core.Genesis{
+ Config: params.TestChainConfig,
+ Alloc: core.GenesisAlloc{testBank: {Balance: big.NewInt(1000000)}},
+ }
+ genesis = gspec.MustCommit(db)
+ blockchain, _ = core.NewBlockChain(db, gspec.Config, pow, evmux, vm.Config{})
)
- chain, _ := core.GenerateChain(chainConfig, genesis, db, blocks, generator)
+ chain, _ := core.GenerateChain(gspec.Config, genesis, db, blocks, generator)
if _, err := blockchain.InsertChain(chain); err != nil {
panic(err)
}
- pm, err := NewProtocolManager(chainConfig, fastSync, NetworkId, 1000, evmux, &testTxPool{added: newtx}, pow, blockchain, db)
+ pm, err := NewProtocolManager(gspec.Config, fastSync, NetworkId, 1000, evmux, &testTxPool{added: newtx}, pow, blockchain, db)
if err != nil {
return nil, err
}
diff --git a/eth/peer.go b/eth/peer.go
index aa85631ea2..6884fee8e8 100644
--- a/eth/peer.go
+++ b/eth/peer.go
@@ -25,8 +25,6 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/rlp"
"gopkg.in/fatih/set.v0"
@@ -189,44 +187,44 @@ func (p *peer) SendReceiptsRLP(receipts []rlp.RawValue) error {
return p2p.Send(p.rw, ReceiptsMsg, receipts)
}
-// RequestHeaders is a wrapper around the header query functions to fetch a
+// RequestOneHeader is a wrapper around the header query functions to fetch a
// single header. It is used solely by the fetcher.
func (p *peer) RequestOneHeader(hash common.Hash) error {
- glog.V(logger.Debug).Infof("%v fetching a single header: %x", p, hash)
+ p.Log().Debug("Fetching single header", "hash", hash)
return p2p.Send(p.rw, GetBlockHeadersMsg, &getBlockHeadersData{Origin: hashOrNumber{Hash: hash}, Amount: uint64(1), Skip: uint64(0), Reverse: false})
}
// RequestHeadersByHash fetches a batch of blocks' headers corresponding to the
// specified header query, based on the hash of an origin block.
func (p *peer) RequestHeadersByHash(origin common.Hash, amount int, skip int, reverse bool) error {
- glog.V(logger.Debug).Infof("%v fetching %d headers from %x, skipping %d (reverse = %v)", p, amount, origin[:4], skip, reverse)
+ p.Log().Debug("Fetching batch of headers", "count", amount, "fromhash", origin, "skip", skip, "reverse", reverse)
return p2p.Send(p.rw, GetBlockHeadersMsg, &getBlockHeadersData{Origin: hashOrNumber{Hash: origin}, Amount: uint64(amount), Skip: uint64(skip), Reverse: reverse})
}
// RequestHeadersByNumber fetches a batch of blocks' headers corresponding to the
// specified header query, based on the number of an origin block.
func (p *peer) RequestHeadersByNumber(origin uint64, amount int, skip int, reverse bool) error {
- glog.V(logger.Debug).Infof("%v fetching %d headers from #%d, skipping %d (reverse = %v)", p, amount, origin, skip, reverse)
+ p.Log().Debug("Fetching batch of headers", "count", amount, "fromnum", origin, "skip", skip, "reverse", reverse)
return p2p.Send(p.rw, GetBlockHeadersMsg, &getBlockHeadersData{Origin: hashOrNumber{Number: origin}, Amount: uint64(amount), Skip: uint64(skip), Reverse: reverse})
}
// RequestBodies fetches a batch of blocks' bodies corresponding to the hashes
// specified.
func (p *peer) RequestBodies(hashes []common.Hash) error {
- glog.V(logger.Debug).Infof("%v fetching %d block bodies", p, len(hashes))
+ p.Log().Debug("Fetching batch of block bodies", "count", len(hashes))
return p2p.Send(p.rw, GetBlockBodiesMsg, hashes)
}
// RequestNodeData fetches a batch of arbitrary data from a node's known state
// data, corresponding to the specified hashes.
func (p *peer) RequestNodeData(hashes []common.Hash) error {
- glog.V(logger.Debug).Infof("%v fetching %v state data", p, len(hashes))
+ p.Log().Debug("Fetching batch of state data", "count", len(hashes))
return p2p.Send(p.rw, GetNodeDataMsg, hashes)
}
// RequestReceipts fetches a batch of transaction receipts from a remote node.
func (p *peer) RequestReceipts(hashes []common.Hash) error {
- glog.V(logger.Debug).Infof("%v fetching %v receipts", p, len(hashes))
+ p.Log().Debug("Fetching batch of receipts", "count", len(hashes))
return p2p.Send(p.rw, GetReceiptsMsg, hashes)
}
@@ -281,7 +279,7 @@ func (p *peer) readStatus(network int, status *statusData, genesis common.Hash)
return errResp(ErrDecode, "msg %v: %v", msg, err)
}
if status.GenesisBlock != genesis {
- return errResp(ErrGenesisBlockMismatch, "%x (!= %x)", status.GenesisBlock, genesis)
+ return errResp(ErrGenesisBlockMismatch, "%x (!= %x)", status.GenesisBlock[:8], genesis[:8])
}
if int(status.NetworkId) != network {
return errResp(ErrNetworkIdMismatch, "%d (!= %d)", status.NetworkId, network)
diff --git a/eth/protocol_test.go b/eth/protocol_test.go
index 3b80564333..253dcd8a7f 100644
--- a/eth/protocol_test.go
+++ b/eth/protocol_test.go
@@ -30,8 +30,7 @@ import (
)
func init() {
- // glog.SetToStderr(true)
- // glog.SetV(6)
+ // log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(false))))
}
var testAccount, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
@@ -64,7 +63,7 @@ func testStatusMsgErrors(t *testing.T, protocol int) {
},
{
code: StatusMsg, data: statusData{uint32(protocol), NetworkId, td, currentBlock, common.Hash{3}},
- wantError: errResp(ErrGenesisBlockMismatch, "0300000000000000000000000000000000000000000000000000000000000000 (!= %x)", genesis),
+ wantError: errResp(ErrGenesisBlockMismatch, "0300000000000000 (!= %x)", genesis[:8]),
},
}
diff --git a/eth/sync.go b/eth/sync.go
index 373cc2054b..f2cae6c198 100644
--- a/eth/sync.go
+++ b/eth/sync.go
@@ -24,8 +24,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/eth/downloader"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/p2p/discover"
)
@@ -87,7 +86,7 @@ func (pm *ProtocolManager) txsyncLoop() {
delete(pending, s.p.ID())
}
// Send the pack in the background.
- glog.V(logger.Detail).Infof("%v: sending %d transactions (%v)", s.p.Peer, len(pack.txs), size)
+ s.p.Log().Trace("Sending batch of transactions", "count", len(pack.txs), "bytes", size)
sending = true
go func() { done <- pack.p.SendTransactions(pack.txs) }()
}
@@ -117,7 +116,7 @@ func (pm *ProtocolManager) txsyncLoop() {
sending = false
// Stop tracking peers that cause send failures.
if err != nil {
- glog.V(logger.Debug).Infof("%v: tx send failed: %v", pack.p.Peer, err)
+ pack.p.Log().Debug("Transaction send failed", "err", err)
delete(pending, pack.p.ID())
}
// Schedule the next send.
@@ -176,6 +175,14 @@ func (pm *ProtocolManager) synchronise(peer *peer) {
// Otherwise try to sync with the downloader
mode := downloader.FullSync
if atomic.LoadUint32(&pm.fastSync) == 1 {
+ // Fast sync was explicitly requested, and explicitly granted
+ mode = downloader.FastSync
+ } else if currentBlock.NumberU64() == 0 && pm.blockchain.CurrentFastBlock().NumberU64() > 0 {
+ // The database seems empty as the current block is the genesis. Yet the fast
+ // block is ahead, so fast sync was enabled for this node at a certain point.
+ // The only scenario where this can happen is if the user manually (or via a
+ // bad block) rolled back a fast sync node below the sync point. In this case
+ // however it's safe to reenable fast sync.
mode = downloader.FastSync
}
if err := pm.downloader.Synchronise(peer.id, pHead, pTd, mode); err != nil {
@@ -187,7 +194,7 @@ func (pm *ProtocolManager) synchronise(peer *peer) {
if atomic.LoadUint32(&pm.fastSync) == 1 {
// Disable fast sync if we indeed have something in our chain
if pm.blockchain.CurrentBlock().NumberU64() > 0 {
- glog.V(logger.Info).Infof("fast sync complete, auto disabling")
+ log.Info("Fast sync complete, auto disabling")
atomic.StoreUint32(&pm.fastSync, 0)
}
}
diff --git a/ethclient/ethclient.go b/ethclient/ethclient.go
index 1d04d9e032..59f60d6598 100644
--- a/ethclient/ethclient.go
+++ b/ethclient/ethclient.go
@@ -18,6 +18,7 @@
package ethclient
import (
+ "context"
"encoding/json"
"fmt"
"math/big"
@@ -28,7 +29,6 @@ import (
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/rpc"
- "golang.org/x/net/context"
)
// Client defines typed wrappers for the Ethereum RPC API.
diff --git a/ethdb/database.go b/ethdb/database.go
index c0e92a87bc..7d5fb0b9ef 100644
--- a/ethdb/database.go
+++ b/ethdb/database.go
@@ -17,14 +17,12 @@
package ethdb
import (
- "path/filepath"
"strconv"
"strings"
"sync"
"time"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/metrics"
"github.com/syndtr/goleveldb/leveldb"
"github.com/syndtr/goleveldb/leveldb/errors"
@@ -37,20 +35,6 @@ import (
var OpenFileLimit = 64
-// cacheRatio specifies how the total allotted cache is distributed between the
-// various system databases.
-var cacheRatio = map[string]float64{
- "chaindata": 1.0,
- "lightchaindata": 1.0,
-}
-
-// handleRatio specifies how the total allotted file descriptors is distributed
-// between the various system databases.
-var handleRatio = map[string]float64{
- "chaindata": 1.0,
- "lightchaindata": 1.0,
-}
-
type LDBDatabase struct {
fn string // filename for reporting
db *leveldb.DB // LevelDB instance
@@ -67,20 +51,22 @@ type LDBDatabase struct {
quitLock sync.Mutex // Mutex protecting the quit channel access
quitChan chan chan error // Quit channel to stop the metrics collection before closing the database
+
+ log log.Logger // Contextual logger tracking the database path
}
// NewLDBDatabase returns a LevelDB wrapped object.
func NewLDBDatabase(file string, cache int, handles int) (*LDBDatabase, error) {
- // Calculate the cache and file descriptor allowance for this particular database
- cache = int(float64(cache) * cacheRatio[filepath.Base(file)])
+ logger := log.New("database", file)
+
+ // Ensure we have some minimal caching and file guarantees
if cache < 16 {
cache = 16
}
- handles = int(float64(handles) * handleRatio[filepath.Base(file)])
if handles < 16 {
handles = 16
}
- glog.V(logger.Info).Infof("Allotted %dMB cache and %d file handles to %s", cache, handles, file)
+ logger.Info("Allocated cache and file handles", "cache", cache, "handles", handles)
// Open the db and recover any potential corruptions
db, err := leveldb.OpenFile(file, &opt.Options{
@@ -97,8 +83,9 @@ func NewLDBDatabase(file string, cache int, handles int) (*LDBDatabase, error) {
return nil, err
}
return &LDBDatabase{
- fn: file,
- db: db,
+ fn: file,
+ db: db,
+ log: logger,
}, nil
}
@@ -108,105 +95,103 @@ func (db *LDBDatabase) Path() string {
}
// Put puts the given key / value to the queue
-func (self *LDBDatabase) Put(key []byte, value []byte) error {
+func (db *LDBDatabase) Put(key []byte, value []byte) error {
// Measure the database put latency, if requested
- if self.putTimer != nil {
- defer self.putTimer.UpdateSince(time.Now())
+ if db.putTimer != nil {
+ defer db.putTimer.UpdateSince(time.Now())
}
// Generate the data to write to disk, update the meter and write
//value = rle.Compress(value)
- if self.writeMeter != nil {
- self.writeMeter.Mark(int64(len(value)))
+ if db.writeMeter != nil {
+ db.writeMeter.Mark(int64(len(value)))
}
- return self.db.Put(key, value, nil)
+ return db.db.Put(key, value, nil)
}
// Get returns the given key if it's present.
-func (self *LDBDatabase) Get(key []byte) ([]byte, error) {
+func (db *LDBDatabase) Get(key []byte) ([]byte, error) {
// Measure the database get latency, if requested
- if self.getTimer != nil {
- defer self.getTimer.UpdateSince(time.Now())
+ if db.getTimer != nil {
+ defer db.getTimer.UpdateSince(time.Now())
}
// Retrieve the key and increment the miss counter if not found
- dat, err := self.db.Get(key, nil)
+ dat, err := db.db.Get(key, nil)
if err != nil {
- if self.missMeter != nil {
- self.missMeter.Mark(1)
+ if db.missMeter != nil {
+ db.missMeter.Mark(1)
}
return nil, err
}
// Otherwise update the actually retrieved amount of data
- if self.readMeter != nil {
- self.readMeter.Mark(int64(len(dat)))
+ if db.readMeter != nil {
+ db.readMeter.Mark(int64(len(dat)))
}
return dat, nil
//return rle.Decompress(dat)
}
// Delete deletes the key from the queue and database
-func (self *LDBDatabase) Delete(key []byte) error {
+func (db *LDBDatabase) Delete(key []byte) error {
// Measure the database delete latency, if requested
- if self.delTimer != nil {
- defer self.delTimer.UpdateSince(time.Now())
+ if db.delTimer != nil {
+ defer db.delTimer.UpdateSince(time.Now())
}
// Execute the actual operation
- return self.db.Delete(key, nil)
+ return db.db.Delete(key, nil)
}
-func (self *LDBDatabase) NewIterator() iterator.Iterator {
- return self.db.NewIterator(nil, nil)
+func (db *LDBDatabase) NewIterator() iterator.Iterator {
+ return db.db.NewIterator(nil, nil)
}
-func (self *LDBDatabase) Close() {
+func (db *LDBDatabase) Close() {
// Stop the metrics collection to avoid internal database races
- self.quitLock.Lock()
- defer self.quitLock.Unlock()
+ db.quitLock.Lock()
+ defer db.quitLock.Unlock()
- if self.quitChan != nil {
+ if db.quitChan != nil {
errc := make(chan error)
- self.quitChan <- errc
+ db.quitChan <- errc
if err := <-errc; err != nil {
- glog.V(logger.Error).Infof("metrics failure in '%s': %v\n", self.fn, err)
+ db.log.Error("Metrics collection failed", "err", err)
}
}
- err := self.db.Close()
- if glog.V(logger.Error) {
- if err == nil {
- glog.Infoln("closed db:", self.fn)
- } else {
- glog.Errorf("error closing db %s: %v", self.fn, err)
- }
+ err := db.db.Close()
+ if err == nil {
+ db.log.Info("Database closed")
+ } else {
+ db.log.Error("Failed to close database", "err", err)
}
}
-func (self *LDBDatabase) LDB() *leveldb.DB {
- return self.db
+func (db *LDBDatabase) LDB() *leveldb.DB {
+ return db.db
}
// Meter configures the database metrics collectors and
-func (self *LDBDatabase) Meter(prefix string) {
+func (db *LDBDatabase) Meter(prefix string) {
// Short circuit metering if the metrics system is disabled
if !metrics.Enabled {
return
}
// Initialize all the metrics collector at the requested prefix
- self.getTimer = metrics.NewTimer(prefix + "user/gets")
- self.putTimer = metrics.NewTimer(prefix + "user/puts")
- self.delTimer = metrics.NewTimer(prefix + "user/dels")
- self.missMeter = metrics.NewMeter(prefix + "user/misses")
- self.readMeter = metrics.NewMeter(prefix + "user/reads")
- self.writeMeter = metrics.NewMeter(prefix + "user/writes")
- self.compTimeMeter = metrics.NewMeter(prefix + "compact/time")
- self.compReadMeter = metrics.NewMeter(prefix + "compact/input")
- self.compWriteMeter = metrics.NewMeter(prefix + "compact/output")
+ db.getTimer = metrics.NewTimer(prefix + "user/gets")
+ db.putTimer = metrics.NewTimer(prefix + "user/puts")
+ db.delTimer = metrics.NewTimer(prefix + "user/dels")
+ db.missMeter = metrics.NewMeter(prefix + "user/misses")
+ db.readMeter = metrics.NewMeter(prefix + "user/reads")
+ db.writeMeter = metrics.NewMeter(prefix + "user/writes")
+ db.compTimeMeter = metrics.NewMeter(prefix + "compact/time")
+ db.compReadMeter = metrics.NewMeter(prefix + "compact/input")
+ db.compWriteMeter = metrics.NewMeter(prefix + "compact/output")
// Create a quit channel for the periodic collector and run it
- self.quitLock.Lock()
- self.quitChan = make(chan chan error)
- self.quitLock.Unlock()
+ db.quitLock.Lock()
+ db.quitChan = make(chan chan error)
+ db.quitLock.Unlock()
- go self.meter(3 * time.Second)
+ go db.meter(3 * time.Second)
}
// meter periodically retrieves internal leveldb counters and reports them to
@@ -220,7 +205,7 @@ func (self *LDBDatabase) Meter(prefix string) {
// 1 | 85 | 109.27913 | 28.09293 | 213.92493 | 214.26294
// 2 | 523 | 1000.37159 | 7.26059 | 66.86342 | 66.77884
// 3 | 570 | 1113.18458 | 0.00000 | 0.00000 | 0.00000
-func (self *LDBDatabase) meter(refresh time.Duration) {
+func (db *LDBDatabase) meter(refresh time.Duration) {
// Create the counters to store current and previous values
counters := make([][]float64, 2)
for i := 0; i < 2; i++ {
@@ -229,9 +214,9 @@ func (self *LDBDatabase) meter(refresh time.Duration) {
// Iterate ad infinitum and collect the stats
for i := 1; ; i++ {
// Retrieve the database stats
- stats, err := self.db.GetProperty("leveldb.stats")
+ stats, err := db.db.GetProperty("leveldb.stats")
if err != nil {
- glog.V(logger.Error).Infof("failed to read database stats: %v", err)
+ db.log.Error("Failed to read database stats", "err", err)
return
}
// Find the compaction table, skip the header
@@ -240,7 +225,7 @@ func (self *LDBDatabase) meter(refresh time.Duration) {
lines = lines[1:]
}
if len(lines) <= 3 {
- glog.V(logger.Error).Infof("compaction table not found")
+ db.log.Error("Compaction table not found")
return
}
lines = lines[3:]
@@ -255,27 +240,27 @@ func (self *LDBDatabase) meter(refresh time.Duration) {
break
}
for idx, counter := range parts[3:] {
- if value, err := strconv.ParseFloat(strings.TrimSpace(counter), 64); err != nil {
- glog.V(logger.Error).Infof("compaction entry parsing failed: %v", err)
+ value, err := strconv.ParseFloat(strings.TrimSpace(counter), 64)
+ if err != nil {
+ db.log.Error("Compaction entry parsing failed", "err", err)
return
- } else {
- counters[i%2][idx] += value
}
+ counters[i%2][idx] += value
}
}
// Update all the requested meters
- if self.compTimeMeter != nil {
- self.compTimeMeter.Mark(int64((counters[i%2][0] - counters[(i-1)%2][0]) * 1000 * 1000 * 1000))
+ if db.compTimeMeter != nil {
+ db.compTimeMeter.Mark(int64((counters[i%2][0] - counters[(i-1)%2][0]) * 1000 * 1000 * 1000))
}
- if self.compReadMeter != nil {
- self.compReadMeter.Mark(int64((counters[i%2][1] - counters[(i-1)%2][1]) * 1024 * 1024))
+ if db.compReadMeter != nil {
+ db.compReadMeter.Mark(int64((counters[i%2][1] - counters[(i-1)%2][1]) * 1024 * 1024))
}
- if self.compWriteMeter != nil {
- self.compWriteMeter.Mark(int64((counters[i%2][2] - counters[(i-1)%2][2]) * 1024 * 1024))
+ if db.compWriteMeter != nil {
+ db.compWriteMeter.Mark(int64((counters[i%2][2] - counters[(i-1)%2][2]) * 1024 * 1024))
}
// Sleep a bit, then repeat the stats collection
select {
- case errc := <-self.quitChan:
+ case errc := <-db.quitChan:
// Quit requesting, stop hammering the database
errc <- nil
return
diff --git a/ethstats/ethstats.go b/ethstats/ethstats.go
index 8692a43bdc..9d494b615d 100644
--- a/ethstats/ethstats.go
+++ b/ethstats/ethstats.go
@@ -22,10 +22,11 @@ import (
"errors"
"fmt"
"math/big"
+ "net"
+ "net/url"
"regexp"
"runtime"
"strconv"
- "strings"
"time"
"github.com/ethereum/go-ethereum/common"
@@ -34,8 +35,7 @@ import (
"github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/les"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/rpc"
@@ -96,13 +96,13 @@ func (s *Service) Start(server *p2p.Server) error {
s.server = server
go s.loop()
- glog.V(logger.Info).Infoln("Stats daemon started")
+ log.Info("Stats daemon started")
return nil
}
// Stop implements node.Service, terminating the monitoring and reporting daemon.
func (s *Service) Stop() error {
- glog.V(logger.Info).Infoln("Stats daemon stopped")
+ log.Info("Stats daemon stopped")
return nil
}
@@ -124,36 +124,45 @@ func (s *Service) loop() {
// Loop reporting until termination
for {
- // Establish a websocket connection to the server and authenticate the node
- url := fmt.Sprintf("%s/api", s.host)
- if !strings.Contains(url, "://") {
- url = "wss://" + url
+ // Resolve the URL, defaulting to TLS, but falling back to none too
+ path := fmt.Sprintf("%s/api", s.host)
+ urls := []string{path}
+
+ if parsed, err := url.Parse(path); err == nil && !parsed.IsAbs() {
+ urls = []string{"wss://" + path, "ws://" + path}
+ }
+ // Establish a websocket connection to the server on any supported URL
+ var (
+ conf *websocket.Config
+ conn *websocket.Conn
+ err error
+ )
+ for _, url := range urls {
+ if conf, err = websocket.NewConfig(url, "http://localhost/"); err != nil {
+ continue
+ }
+ conf.Dialer = &net.Dialer{Timeout: 3 * time.Second}
+ if conn, err = websocket.DialConfig(conf); err == nil {
+ break
+ }
}
- conn, err := websocket.Dial(url, "", "http://localhost/")
if err != nil {
- glog.V(logger.Warn).Infof("Stats server unreachable: %v", err)
+ log.Warn("Stats server unreachable", "err", err)
time.Sleep(10 * time.Second)
continue
}
- in := json.NewDecoder(conn)
- out := json.NewEncoder(conn)
-
- if err = s.login(in, out); err != nil {
- glog.V(logger.Warn).Infof("Stats login failed: %v", err)
+ // Authenticate the client with the server
+ if err = s.login(conn); err != nil {
+ log.Warn("Stats login failed", "err", err)
conn.Close()
time.Sleep(10 * time.Second)
continue
}
- go s.readLoop(conn, in)
+ go s.readLoop(conn)
// Send the initial stats so our node looks decent from the get go
- if err = s.report(out); err != nil {
- glog.V(logger.Warn).Infof("Initial stats report failed: %v", err)
- conn.Close()
- continue
- }
- if err = s.reportHistory(out, nil); err != nil {
- glog.V(logger.Warn).Infof("History report failed: %v", err)
+ if err = s.report(conn); err != nil {
+ log.Warn("Initial stats report failed", "err", err)
conn.Close()
continue
}
@@ -163,23 +172,23 @@ func (s *Service) loop() {
for err == nil {
select {
case <-fullReport.C:
- if err = s.report(out); err != nil {
- glog.V(logger.Warn).Infof("Full stats report failed: %v", err)
+ if err = s.report(conn); err != nil {
+ log.Warn("Full stats report failed", "err", err)
}
case list := <-s.histCh:
- if err = s.reportHistory(out, list); err != nil {
- glog.V(logger.Warn).Infof("Block history report failed: %v", err)
+ if err = s.reportHistory(conn, list); err != nil {
+ log.Warn("Requested history report failed", "err", err)
}
case head, ok := <-headSub.Chan():
if !ok { // node stopped
conn.Close()
return
}
- if err = s.reportBlock(out, head.Data.(core.ChainHeadEvent).Block); err != nil {
- glog.V(logger.Warn).Infof("Block stats report failed: %v", err)
+ if err = s.reportBlock(conn, head.Data.(core.ChainHeadEvent).Block); err != nil {
+ log.Warn("Block stats report failed", "err", err)
}
- if err = s.reportPending(out); err != nil {
- glog.V(logger.Warn).Infof("Post-block transaction stats report failed: %v", err)
+ if err = s.reportPending(conn); err != nil {
+ log.Warn("Post-block transaction stats report failed", "err", err)
}
case _, ok := <-txSub.Chan():
if !ok { // node stopped
@@ -194,8 +203,8 @@ func (s *Service) loop() {
exhausted = true
}
}
- if err = s.reportPending(out); err != nil {
- glog.V(logger.Warn).Infof("Transaction stats report failed: %v", err)
+ if err = s.reportPending(conn); err != nil {
+ log.Warn("Transaction stats report failed", "err", err)
}
}
}
@@ -208,24 +217,25 @@ func (s *Service) loop() {
// from the network socket. If any of them match an active request, it forwards
// it, if they themselves are requests it initiates a reply, and lastly it drops
// unknown packets.
-func (s *Service) readLoop(conn *websocket.Conn, in *json.Decoder) {
+func (s *Service) readLoop(conn *websocket.Conn) {
// If the read loop exists, close the connection
defer conn.Close()
for {
// Retrieve the next generic network packet and bail out on error
var msg map[string][]interface{}
- if err := in.Decode(&msg); err != nil {
- glog.V(logger.Warn).Infof("Failed to decode stats server message: %v", err)
+ if err := websocket.JSON.Receive(conn, &msg); err != nil {
+ log.Warn("Failed to decode stats server message", "err", err)
return
}
+ log.Trace("Received message from stats server", "msg", msg)
if len(msg["emit"]) == 0 {
- glog.V(logger.Warn).Infof("Stats server sent non-broadcast: %v", msg)
+ log.Warn("Stats server sent non-broadcast", "msg", msg)
return
}
command, ok := msg["emit"][0].(string)
if !ok {
- glog.V(logger.Warn).Infof("Invalid stats server message type: %v", msg["emit"][0])
+ log.Warn("Invalid stats server message type", "type", msg["emit"][0])
return
}
// If the message is a ping reply, deliver (someone must be listening!)
@@ -236,7 +246,7 @@ func (s *Service) readLoop(conn *websocket.Conn, in *json.Decoder) {
continue
default:
// Ping routine dead, abort
- glog.V(logger.Warn).Infof("Stats server pinger seems to have died")
+ log.Warn("Stats server pinger seems to have died")
return
}
}
@@ -245,12 +255,13 @@ func (s *Service) readLoop(conn *websocket.Conn, in *json.Decoder) {
// Make sure the request is valid and doesn't crash us
request, ok := msg["emit"][1].(map[string]interface{})
if !ok {
- glog.V(logger.Warn).Infof("Invalid history request: %v", msg["emit"][1])
- return
+ log.Warn("Invalid stats history request", "msg", msg["emit"][1])
+ s.histCh <- nil
+ continue // Ethstats sometime sends invalid history requests, ignore those
}
list, ok := request["list"].([]interface{})
if !ok {
- glog.V(logger.Warn).Infof("Invalid history block list: %v", request["list"])
+ log.Warn("Invalid stats history block list", "list", request["list"])
return
}
// Convert the block number list to an integer list
@@ -258,7 +269,7 @@ func (s *Service) readLoop(conn *websocket.Conn, in *json.Decoder) {
for i, num := range list {
n, ok := num.(float64)
if !ok {
- glog.V(logger.Warn).Infof("Invalid history block number: %v", num)
+ log.Warn("Invalid stats history block number", "number", num)
return
}
numbers[i] = uint64(n)
@@ -270,7 +281,7 @@ func (s *Service) readLoop(conn *websocket.Conn, in *json.Decoder) {
}
}
// Report anything else and continue
- glog.V(logger.Info).Infof("Unknown stats message: %v", msg)
+ log.Info("Unknown stats message", "msg", msg)
}
}
@@ -297,7 +308,7 @@ type authMsg struct {
}
// login tries to authorize the client at the remote server.
-func (s *Service) login(in *json.Decoder, out *json.Encoder) error {
+func (s *Service) login(conn *websocket.Conn) error {
// Construct and send the login authentication
infos := s.server.NodeInfo()
@@ -328,12 +339,12 @@ func (s *Service) login(in *json.Decoder, out *json.Encoder) error {
login := map[string][]interface{}{
"emit": {"hello", auth},
}
- if err := out.Encode(login); err != nil {
+ if err := websocket.JSON.Send(conn, login); err != nil {
return err
}
// Retrieve the remote ack or connection termination
var ack map[string][]string
- if err := in.Decode(&ack); err != nil || len(ack["emit"]) != 1 || ack["emit"][0] != "ready" {
+ if err := websocket.JSON.Receive(conn, &ack); err != nil || len(ack["emit"]) != 1 || ack["emit"][0] != "ready" {
return errors.New("unauthorized")
}
return nil
@@ -342,17 +353,17 @@ func (s *Service) login(in *json.Decoder, out *json.Encoder) error {
// report collects all possible data to report and send it to the stats server.
// This should only be used on reconnects or rarely to avoid overloading the
// server. Use the individual methods for reporting subscribed events.
-func (s *Service) report(out *json.Encoder) error {
- if err := s.reportLatency(out); err != nil {
+func (s *Service) report(conn *websocket.Conn) error {
+ if err := s.reportLatency(conn); err != nil {
return err
}
- if err := s.reportBlock(out, nil); err != nil {
+ if err := s.reportBlock(conn, nil); err != nil {
return err
}
- if err := s.reportPending(out); err != nil {
+ if err := s.reportPending(conn); err != nil {
return err
}
- if err := s.reportStats(out); err != nil {
+ if err := s.reportStats(conn); err != nil {
return err
}
return nil
@@ -360,7 +371,7 @@ func (s *Service) report(out *json.Encoder) error {
// reportLatency sends a ping request to the server, measures the RTT time and
// finally sends a latency update.
-func (s *Service) reportLatency(out *json.Encoder) error {
+func (s *Service) reportLatency(conn *websocket.Conn) error {
// Send the current time to the ethstats server
start := time.Now()
@@ -370,7 +381,7 @@ func (s *Service) reportLatency(out *json.Encoder) error {
"clientTime": start.String(),
}},
}
- if err := out.Encode(ping); err != nil {
+ if err := websocket.JSON.Send(conn, ping); err != nil {
return err
}
// Wait for the pong request to arrive back
@@ -381,28 +392,35 @@ func (s *Service) reportLatency(out *json.Encoder) error {
// Ping timeout, abort
return errors.New("ping timed out")
}
+ latency := strconv.Itoa(int((time.Since(start) / time.Duration(2)).Nanoseconds() / 1000000))
+
// Send back the measured latency
- latency := map[string][]interface{}{
+ log.Trace("Sending measured latency to ethstats", "latency", latency)
+
+ stats := map[string][]interface{}{
"emit": {"latency", map[string]string{
"id": s.node,
- "latency": strconv.Itoa(int((time.Since(start) / time.Duration(2)).Nanoseconds() / 1000000)),
+ "latency": latency,
}},
}
- return out.Encode(latency)
+ return websocket.JSON.Send(conn, stats)
}
// blockStats is the information to report about individual blocks.
type blockStats struct {
- Number *big.Int `json:"number"`
- Hash common.Hash `json:"hash"`
- Timestamp *big.Int `json:"timestamp"`
- Miner common.Address `json:"miner"`
- GasUsed *big.Int `json:"gasUsed"`
- GasLimit *big.Int `json:"gasLimit"`
- Diff string `json:"difficulty"`
- TotalDiff string `json:"totalDifficulty"`
- Txs txStats `json:"transactions"`
- Uncles uncleStats `json:"uncles"`
+ Number *big.Int `json:"number"`
+ Hash common.Hash `json:"hash"`
+ ParentHash common.Hash `json:"parentHash"`
+ Timestamp *big.Int `json:"timestamp"`
+ Miner common.Address `json:"miner"`
+ GasUsed *big.Int `json:"gasUsed"`
+ GasLimit *big.Int `json:"gasLimit"`
+ Diff string `json:"difficulty"`
+ TotalDiff string `json:"totalDifficulty"`
+ Txs txStats `json:"transactions"`
+ TxHash common.Hash `json:"transactionsRoot"`
+ Root common.Hash `json:"stateRoot"`
+ Uncles uncleStats `json:"uncles"`
}
// txStats is a custom wrapper around a transaction array to force serializing
@@ -428,16 +446,21 @@ func (s uncleStats) MarshalJSON() ([]byte, error) {
}
// reportBlock retrieves the current chain head and repors it to the stats server.
-func (s *Service) reportBlock(out *json.Encoder, block *types.Block) error {
- // Assemble the block stats report and send it to the server
+func (s *Service) reportBlock(conn *websocket.Conn, block *types.Block) error {
+ // Gather the block details from the header or block chain
+ details := s.assembleBlockStats(block)
+
+ // Assemble the block report and send it to the server
+ log.Trace("Sending new block to ethstats", "number", details.Number, "hash", details.Hash)
+
stats := map[string]interface{}{
"id": s.node,
- "block": s.assembleBlockStats(block),
+ "block": details,
}
report := map[string][]interface{}{
"emit": {"block", stats},
}
- return out.Encode(report)
+ return websocket.JSON.Send(conn, report)
}
// assembleBlockStats retrieves any required metadata to report a single block
@@ -471,22 +494,25 @@ func (s *Service) assembleBlockStats(block *types.Block) *blockStats {
}
// Assemble and return the block stats
return &blockStats{
- Number: header.Number,
- Hash: header.Hash(),
- Timestamp: header.Time,
- Miner: header.Coinbase,
- GasUsed: new(big.Int).Set(header.GasUsed),
- GasLimit: new(big.Int).Set(header.GasLimit),
- Diff: header.Difficulty.String(),
- TotalDiff: td.String(),
- Txs: txs,
- Uncles: uncles,
+ Number: header.Number,
+ Hash: header.Hash(),
+ ParentHash: header.ParentHash,
+ Timestamp: header.Time,
+ Miner: header.Coinbase,
+ GasUsed: new(big.Int).Set(header.GasUsed),
+ GasLimit: new(big.Int).Set(header.GasLimit),
+ Diff: header.Difficulty.String(),
+ TotalDiff: td.String(),
+ Txs: txs,
+ TxHash: header.TxHash,
+ Root: header.Root,
+ Uncles: uncles,
}
}
// reportHistory retrieves the most recent batch of blocks and reports it to the
// stats server.
-func (s *Service) reportHistory(out *json.Encoder, list []uint64) error {
+func (s *Service) reportHistory(conn *websocket.Conn, list []uint64) error {
// Figure out the indexes that need reporting
indexes := make([]uint64, 0, historyUpdateRange)
if len(list) > 0 {
@@ -494,17 +520,17 @@ func (s *Service) reportHistory(out *json.Encoder, list []uint64) error {
indexes = append(indexes, list...)
} else {
// No indexes requested, send back the top ones
- var head *types.Header
+ var head int64
if s.eth != nil {
- head = s.eth.BlockChain().CurrentHeader()
+ head = s.eth.BlockChain().CurrentHeader().Number.Int64()
} else {
- head = s.les.BlockChain().CurrentHeader()
+ head = s.les.BlockChain().CurrentHeader().Number.Int64()
}
- start := head.Number.Int64() - historyUpdateRange
+ start := head - historyUpdateRange + 1
if start < 0 {
start = 0
}
- for i := uint64(start); i <= head.Number.Uint64(); i++ {
+ for i := uint64(start); i <= uint64(head); i++ {
indexes = append(indexes, i)
}
}
@@ -512,12 +538,14 @@ func (s *Service) reportHistory(out *json.Encoder, list []uint64) error {
history := make([]*blockStats, len(indexes))
for i, number := range indexes {
if s.eth != nil {
- history[i] = s.assembleBlockStats(s.eth.BlockChain().GetBlockByNumber(number))
+ history[len(history)-1-i] = s.assembleBlockStats(s.eth.BlockChain().GetBlockByNumber(number))
} else {
- history[i] = s.assembleBlockStats(types.NewBlockWithHeader(s.les.BlockChain().GetHeaderByNumber(number)))
+ history[len(history)-1-i] = s.assembleBlockStats(types.NewBlockWithHeader(s.les.BlockChain().GetHeaderByNumber(number)))
}
}
// Assemble the history report and send it to the server
+ log.Trace("Sending historical blocks to ethstats", "first", history[0].Number, "last", history[len(history)-1].Number)
+
stats := map[string]interface{}{
"id": s.node,
"history": history,
@@ -525,7 +553,7 @@ func (s *Service) reportHistory(out *json.Encoder, list []uint64) error {
report := map[string][]interface{}{
"emit": {"history", stats},
}
- return out.Encode(report)
+ return websocket.JSON.Send(conn, report)
}
// pendStats is the information to report about pending transactions.
@@ -535,7 +563,7 @@ type pendStats struct {
// reportPending retrieves the current number of pending transactions and reports
// it to the stats server.
-func (s *Service) reportPending(out *json.Encoder) error {
+func (s *Service) reportPending(conn *websocket.Conn) error {
// Retrieve the pending count from the local blockchain
var pending int
if s.eth != nil {
@@ -544,6 +572,8 @@ func (s *Service) reportPending(out *json.Encoder) error {
pending = s.les.TxPool().Stats()
}
// Assemble the transaction stats and send it to the server
+ log.Trace("Sending pending transactions to ethstats", "count", pending)
+
stats := map[string]interface{}{
"id": s.node,
"stats": &pendStats{
@@ -553,10 +583,10 @@ func (s *Service) reportPending(out *json.Encoder) error {
report := map[string][]interface{}{
"emit": {"pending", stats},
}
- return out.Encode(report)
+ return websocket.JSON.Send(conn, report)
}
-// blockStats is the information to report about the local node.
+// nodeStats is the information to report about the local node.
type nodeStats struct {
Active bool `json:"active"`
Syncing bool `json:"syncing"`
@@ -569,7 +599,7 @@ type nodeStats struct {
// reportPending retrieves various stats about the node at the networking and
// mining layer and reports it to the stats server.
-func (s *Service) reportStats(out *json.Encoder) error {
+func (s *Service) reportStats(conn *websocket.Conn) error {
// Gather the syncing and mining infos from the local miner instance
var (
mining bool
@@ -589,6 +619,9 @@ func (s *Service) reportStats(out *json.Encoder) error {
sync := s.les.Downloader().Progress()
syncing = s.les.BlockChain().CurrentHeader().Number.Uint64() >= sync.HighestBlock
}
+ // Assemble the node stats and send it to the server
+ log.Trace("Sending node details to ethstats")
+
stats := map[string]interface{}{
"id": s.node,
"stats": &nodeStats{
@@ -604,5 +637,5 @@ func (s *Service) reportStats(out *json.Encoder) error {
report := map[string][]interface{}{
"emit": {"stats", stats},
}
- return out.Encode(report)
+ return websocket.JSON.Send(conn, report)
}
diff --git a/event/subscription.go b/event/subscription.go
index 83bd21213d..02d7b9d7d4 100644
--- a/event/subscription.go
+++ b/event/subscription.go
@@ -17,11 +17,11 @@
package event
import (
+ "context"
"sync"
"time"
"github.com/ethereum/go-ethereum/common/mclock"
- "golang.org/x/net/context"
)
// Subscription represents a stream of events. The carrier of the events is typically a
diff --git a/event/subscription_test.go b/event/subscription_test.go
index a4fe30298c..aa6d98984d 100644
--- a/event/subscription_test.go
+++ b/event/subscription_test.go
@@ -17,11 +17,10 @@
package event
import (
+ "context"
"errors"
"testing"
"time"
-
- "golang.org/x/net/context"
)
var errInts = errors.New("error in subscribeInts")
diff --git a/interfaces.go b/interfaces.go
index f7e71a3173..744f07b95a 100644
--- a/interfaces.go
+++ b/interfaces.go
@@ -18,12 +18,12 @@
package ethereum
import (
+ "context"
"errors"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
- "golang.org/x/net/context"
)
// NotFound is returned by API methods if the requested item does not exist.
diff --git a/internal/build/util.go b/internal/build/util.go
index 1523a067bc..44f6760b95 100644
--- a/internal/build/util.go
+++ b/internal/build/util.go
@@ -26,6 +26,7 @@ import (
"os"
"os/exec"
"path/filepath"
+ "runtime"
"strings"
"text/template"
)
@@ -52,19 +53,10 @@ func MustRunCommand(cmd string, args ...string) {
// GOPATH returns the value that the GOPATH environment
// variable should be set to.
func GOPATH() string {
- path := filepath.SplitList(os.Getenv("GOPATH"))
- if len(path) == 0 {
+ if os.Getenv("GOPATH") == "" {
log.Fatal("GOPATH is not set")
}
- // Ensure that our internal vendor folder is on GOPATH
- vendor, _ := filepath.Abs(filepath.Join("build", "_vendor"))
- for _, dir := range path {
- if dir == vendor {
- return strings.Join(path, string(filepath.ListSeparator))
- }
- }
- newpath := append(path[:1], append([]string{vendor}, path[1:]...)...)
- return strings.Join(newpath, string(filepath.ListSeparator))
+ return os.Getenv("GOPATH")
}
// VERSION returns the content of the VERSION file.
@@ -145,3 +137,30 @@ func CopyFile(dst, src string, mode os.FileMode) {
log.Fatal(err)
}
}
+
+// ExpandPackagesNoVendor expands a cmd/go import path pattern, skipping
+// vendored packages.
+func ExpandPackagesNoVendor(patterns []string) []string {
+ expand := false
+ for _, pkg := range patterns {
+ if strings.Contains(pkg, "...") {
+ expand = true
+ }
+ }
+ if expand {
+ args := append([]string{"list"}, patterns...)
+ cmd := exec.Command(filepath.Join(runtime.GOROOT(), "bin", "go"), args...)
+ out, err := cmd.CombinedOutput()
+ if err != nil {
+ log.Fatalf("package listing failed: %v\n%s", err, string(out))
+ }
+ var packages []string
+ for _, line := range strings.Split(string(out), "\n") {
+ if !strings.Contains(line, "/vendor/") {
+ packages = append(packages, strings.TrimSpace(line))
+ }
+ }
+ return packages
+ }
+ return patterns
+}
diff --git a/internal/debug/api.go b/internal/debug/api.go
index 96091541b5..8b7693f6a4 100644
--- a/internal/debug/api.go
+++ b/internal/debug/api.go
@@ -33,8 +33,7 @@ import (
"sync"
"time"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/log"
)
// Handler is the global debugging handler.
@@ -51,23 +50,22 @@ type HandlerT struct {
traceFile string
}
-// Verbosity sets the glog verbosity ceiling.
-// The verbosity of individual packages and source files
-// can be raised using Vmodule.
+// Verbosity sets the log verbosity ceiling. The verbosity of individual packages
+// and source files can be raised using Vmodule.
func (*HandlerT) Verbosity(level int) {
- glog.SetV(level)
+ glogger.Verbosity(log.Lvl(level))
}
-// Vmodule sets the glog verbosity pattern. See package
-// glog for details on pattern syntax.
+// Vmodule sets the log verbosity pattern. See package log for details on the
+// pattern syntax.
func (*HandlerT) Vmodule(pattern string) error {
- return glog.GetVModule().Set(pattern)
+ return glogger.Vmodule(pattern)
}
-// BacktraceAt sets the glog backtrace location.
-// See package glog for details on pattern syntax.
+// BacktraceAt sets the log backtrace location. See package log for details on
+// the pattern syntax.
func (*HandlerT) BacktraceAt(location string) error {
- return glog.GetTraceLocation().Set(location)
+ return glogger.BacktraceAt(location)
}
// MemStats returns detailed runtime memory statistics.
@@ -112,7 +110,7 @@ func (h *HandlerT) StartCPUProfile(file string) error {
}
h.cpuW = f
h.cpuFile = file
- glog.V(logger.Info).Infoln("CPU profiling started, writing to", h.cpuFile)
+ log.Info("CPU profiling started", "dump", h.cpuFile)
return nil
}
@@ -124,7 +122,7 @@ func (h *HandlerT) StopCPUProfile() error {
if h.cpuW == nil {
return errors.New("CPU profiling not in progress")
}
- glog.V(logger.Info).Infoln("done writing CPU profile to", h.cpuFile)
+ log.Info("Done writing CPU profile", "dump", h.cpuFile)
h.cpuW.Close()
h.cpuW = nil
h.cpuFile = ""
@@ -180,7 +178,7 @@ func (*HandlerT) Stacks() string {
func writeProfile(name, file string) error {
p := pprof.Lookup(name)
- glog.V(logger.Info).Infof("writing %d %s profile records to %s", p.Count(), name, file)
+ log.Info("Writing profile records", "count", p.Count(), "type", name, "dump", file)
f, err := os.Create(expandHome(file))
if err != nil {
return err
diff --git a/internal/debug/flags.go b/internal/debug/flags.go
index d7bbfae1eb..6247cc7dc0 100644
--- a/internal/debug/flags.go
+++ b/internal/debug/flags.go
@@ -18,30 +18,37 @@ package debug
import (
"fmt"
+ "io"
"net/http"
_ "net/http/pprof"
+ "os"
"runtime"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/log"
+ "github.com/ethereum/go-ethereum/log/term"
+ colorable "github.com/mattn/go-colorable"
"gopkg.in/urfave/cli.v1"
)
var (
- verbosityFlag = cli.GenericFlag{
+ verbosityFlag = cli.IntFlag{
Name: "verbosity",
- Usage: "Logging verbosity: 0=silent, 1=error, 2=warn, 3=info, 4=core, 5=debug, 6=detail",
- Value: glog.GetVerbosity(),
+ Usage: "Logging verbosity: 0=silent, 1=error, 2=warn, 3=info, 4=debug, 5=detail",
+ Value: 3,
}
- vmoduleFlag = cli.GenericFlag{
+ vmoduleFlag = cli.StringFlag{
Name: "vmodule",
- Usage: "Per-module verbosity: comma-separated list of = (e.g. eth/*=6,p2p=5)",
- Value: glog.GetVModule(),
+ Usage: "Per-module verbosity: comma-separated list of = (e.g. eth/*=5,p2p=4)",
+ Value: "",
}
- backtraceAtFlag = cli.GenericFlag{
+ backtraceAtFlag = cli.StringFlag{
Name: "backtrace",
Usage: "Request a stack trace at a specific logging statement (e.g. \"block.go:271\")",
- Value: glog.GetTraceLocation(),
+ Value: "",
+ }
+ debugFlag = cli.BoolFlag{
+ Name: "debug",
+ Usage: "Prepends log messages with call-site location (file and line number)",
}
pprofFlag = cli.BoolFlag{
Name: "pprof",
@@ -78,17 +85,31 @@ var (
// Flags holds all command-line flags required for debugging.
var Flags = []cli.Flag{
- verbosityFlag, vmoduleFlag, backtraceAtFlag,
+ verbosityFlag, vmoduleFlag, backtraceAtFlag, debugFlag,
pprofFlag, pprofAddrFlag, pprofPortFlag,
memprofilerateFlag, blockprofilerateFlag, cpuprofileFlag, traceFlag,
}
+var glogger *log.GlogHandler
+
+func init() {
+ usecolor := term.IsTty(os.Stderr.Fd()) && os.Getenv("TERM") != "dumb"
+ output := io.Writer(os.Stderr)
+ if usecolor {
+ output = colorable.NewColorableStderr()
+ }
+ glogger = log.NewGlogHandler(log.StreamHandler(output, log.TerminalFormat(usecolor)))
+}
+
// Setup initializes profiling and logging based on the CLI flags.
// It should be called as early as possible in the program.
func Setup(ctx *cli.Context) error {
// logging
- glog.CopyStandardLogTo("INFO")
- glog.SetToStderr(true)
+ log.PrintOrigins(ctx.GlobalBool(debugFlag.Name))
+ glogger.Verbosity(log.Lvl(ctx.GlobalInt(verbosityFlag.Name)))
+ glogger.Vmodule(ctx.GlobalString(vmoduleFlag.Name))
+ glogger.BacktraceAt(ctx.GlobalString(backtraceAtFlag.Name))
+ log.Root().SetHandler(glogger)
// profiling, tracing
runtime.MemProfileRate = ctx.GlobalInt(memprofilerateFlag.Name)
@@ -108,8 +129,10 @@ func Setup(ctx *cli.Context) error {
if ctx.GlobalBool(pprofFlag.Name) {
address := fmt.Sprintf("%s:%d", ctx.GlobalString(pprofAddrFlag.Name), ctx.GlobalInt(pprofPortFlag.Name))
go func() {
- glog.V(logger.Info).Infof("starting pprof server at http://%s/debug/pprof", address)
- glog.Errorln(http.ListenAndServe(address, nil))
+ log.Info("Starting pprof server", "addr", fmt.Sprintf("http://%s/debug/pprof", address))
+ if err := http.ListenAndServe(address, nil); err != nil {
+ log.Error("Failure in running pprof server", "err", err)
+ }
}()
}
return nil
diff --git a/internal/debug/trace.go b/internal/debug/trace.go
index c0cf921ff0..cab5deaafd 100644
--- a/internal/debug/trace.go
+++ b/internal/debug/trace.go
@@ -23,8 +23,7 @@ import (
"os"
"runtime/trace"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/log"
)
// StartGoTrace turns on tracing, writing to the given file.
@@ -44,7 +43,7 @@ func (h *HandlerT) StartGoTrace(file string) error {
}
h.traceW = f
h.traceFile = file
- glog.V(logger.Info).Infoln("trace started, writing to", h.traceFile)
+ log.Info("Go tracing started", "dump", h.traceFile)
return nil
}
@@ -56,7 +55,7 @@ func (h *HandlerT) StopGoTrace() error {
if h.traceW == nil {
return errors.New("trace not in progress")
}
- glog.V(logger.Info).Infoln("done writing trace to", h.traceFile)
+ log.Info("Done writing Go trace", "dump", h.traceFile)
h.traceW.Close()
h.traceW = nil
h.traceFile = ""
diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go
index cf82cc8665..ccb7ec80b1 100644
--- a/internal/ethapi/api.go
+++ b/internal/ethapi/api.go
@@ -18,35 +18,39 @@ package ethapi
import (
"bytes"
+ "context"
"encoding/hex"
"errors"
"fmt"
- "math"
"math/big"
"strings"
"time"
- "github.com/ethereum/ethash"
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/accounts/keystore"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
+ "github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethdb"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/p2p"
+ "github.com/ethereum/go-ethereum/params"
+ "github.com/ethereum/go-ethereum/pow"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/rpc"
"github.com/syndtr/goleveldb/leveldb"
"github.com/syndtr/goleveldb/leveldb/util"
- "golang.org/x/net/context"
)
-const defaultGas = 90000
+const (
+ defaultGas = 90000
+ defaultGasPrice = 50 * params.Shannon
+ emptyHex = "0x"
+)
// PublicEthereumAPI provides an API to access Ethereum related information.
// It offers only methods that operate on public data that is freely available to anyone.
@@ -447,7 +451,7 @@ func (s *PublicBlockChainAPI) GetBlockByNumber(ctx context.Context, blockNr rpc.
response, err := s.rpcOutputBlock(block, true, fullTx)
if err == nil && blockNr == rpc.PendingBlockNumber {
// Pending blocks need to nil out a few fields
- for _, field := range []string{"hash", "nonce", "logsBloom", "miner"} {
+ for _, field := range []string{"hash", "nonce", "miner"} {
response[field] = nil
}
}
@@ -473,7 +477,7 @@ func (s *PublicBlockChainAPI) GetUncleByBlockNumberAndIndex(ctx context.Context,
if block != nil {
uncles := block.Uncles()
if index >= hexutil.Uint(len(uncles)) {
- glog.V(logger.Debug).Infof("uncle block on index %d not found for block #%d", index, blockNr)
+ log.Debug("Requested uncle not found", "number", blockNr, "hash", block.Hash(), "index", index)
return nil, nil
}
block = types.NewBlockWithHeader(uncles[index])
@@ -489,7 +493,7 @@ func (s *PublicBlockChainAPI) GetUncleByBlockHashAndIndex(ctx context.Context, b
if block != nil {
uncles := block.Uncles()
if index >= hexutil.Uint(len(uncles)) {
- glog.V(logger.Debug).Infof("uncle block on index %d not found for block %s", index, blockHash.Hex())
+ log.Debug("Requested uncle not found", "number", block.Number(), "hash", blockHash, "index", index)
return nil, nil
}
block = types.NewBlockWithHeader(uncles[index])
@@ -574,12 +578,12 @@ type CallArgs struct {
Data hexutil.Bytes `json:"data"`
}
-func (s *PublicBlockChainAPI) doCall(ctx context.Context, args CallArgs, blockNr rpc.BlockNumber) (string, *big.Int, error) {
- defer func(start time.Time) { glog.V(logger.Debug).Infof("call took %v", time.Since(start)) }(time.Now())
+func (s *PublicBlockChainAPI) doCall(ctx context.Context, args CallArgs, blockNr rpc.BlockNumber, vmCfg vm.Config) ([]byte, *big.Int, error) {
+ defer func(start time.Time) { log.Debug("Executing EVM call finished", "runtime", time.Since(start)) }(time.Now())
state, header, err := s.b.StateAndHeaderByNumber(ctx, blockNr)
if state == nil || err != nil {
- return "0x", common.Big0, err
+ return nil, common.Big0, err
}
// Set sender address or use a default if none specified
addr := args.From
@@ -589,47 +593,67 @@ func (s *PublicBlockChainAPI) doCall(ctx context.Context, args CallArgs, blockNr
addr = accounts[0].Address
}
}
- } else {
- addr = args.From
}
// Set default gas & gas price if none were set
gas, gasPrice := args.Gas.ToInt(), args.GasPrice.ToInt()
- if gas.Cmp(common.Big0) == 0 {
+ if gas.Sign() == 0 {
gas = big.NewInt(50000000)
}
- if gasPrice.Cmp(common.Big0) == 0 {
- gasPrice = new(big.Int).Mul(big.NewInt(50), common.Shannon)
+ if gasPrice.Sign() == 0 {
+ gasPrice = new(big.Int).SetUint64(defaultGasPrice)
}
+
+ // Create new call message
msg := types.NewMessage(addr, args.To, 0, args.Value.ToInt(), gas, gasPrice, args.Data, false)
- // Execute the call and return
- vmenv, vmError, err := s.b.GetVMEnv(ctx, msg, state, header)
+ // Setup context so it may be cancelled the call has completed
+ // or, in case of unmetered gas, setup a context with a timeout.
+ var cancel context.CancelFunc
+ if vmCfg.DisableGasMetering {
+ ctx, cancel = context.WithTimeout(ctx, time.Second*5)
+ } else {
+ ctx, cancel = context.WithCancel(ctx)
+ }
+ // Make sure the context is cancelled when the call has completed
+ // this makes sure resources are cleaned up.
+ defer func() { cancel() }()
+
+ // Get a new instance of the EVM.
+ evm, vmError, err := s.b.GetEVM(ctx, msg, state, header, vmCfg)
if err != nil {
- return "0x", common.Big0, err
+ return nil, common.Big0, err
}
- gp := new(core.GasPool).AddGas(common.MaxBig)
- res, gas, err := core.ApplyMessage(vmenv, msg, gp)
+ // Wait for the context to be done and cancel the evm. Even if the
+ // EVM has finished, cancelling may be done (repeatedly)
+ go func() {
+ select {
+ case <-ctx.Done():
+ evm.Cancel()
+ }
+ }()
+
+ // Setup the gas pool (also for unmetered requests)
+ // and apply the message.
+ gp := new(core.GasPool).AddGas(math.MaxBig256)
+ res, gas, err := core.ApplyMessage(evm, msg, gp)
if err := vmError(); err != nil {
- return "0x", common.Big0, err
+ return nil, common.Big0, err
}
- if len(res) == 0 { // backwards compatibility
- return "0x", gas, err
- }
- return common.ToHex(res), gas, err
+ return res, gas, err
}
// Call executes the given transaction on the state for the given block number.
// It doesn't make and changes in the state/blockchain and is useful to execute and retrieve values.
-func (s *PublicBlockChainAPI) Call(ctx context.Context, args CallArgs, blockNr rpc.BlockNumber) (string, error) {
- result, _, err := s.doCall(ctx, args, blockNr)
- return result, err
+func (s *PublicBlockChainAPI) Call(ctx context.Context, args CallArgs, blockNr rpc.BlockNumber) (hexutil.Bytes, error) {
+ result, _, err := s.doCall(ctx, args, blockNr, vm.Config{DisableGasMetering: true})
+ return (hexutil.Bytes)(result), err
}
// EstimateGas returns an estimate of the amount of gas needed to execute the given transaction.
func (s *PublicBlockChainAPI) EstimateGas(ctx context.Context, args CallArgs) (*hexutil.Big, error) {
// Binary search the gas requirement, as it may be higher than the amount used
var lo, hi uint64
- if (*big.Int)(&args.Gas).BitLen() > 0 {
+ if (*big.Int)(&args.Gas).Sign() != 0 {
hi = (*big.Int)(&args.Gas).Uint64()
} else {
// Retrieve the current pending block to act as the gas ceiling
@@ -644,7 +668,7 @@ func (s *PublicBlockChainAPI) EstimateGas(ctx context.Context, args CallArgs) (*
mid := (hi + lo) / 2
(*big.Int)(&args.Gas).SetUint64(mid)
- _, gas, err := s.doCall(ctx, args, rpc.PendingBlockNumber)
+ _, gas, err := s.doCall(ctx, args, rpc.PendingBlockNumber, vm.Config{})
// If the transaction became invalid or used all the gas (failed), raise the gas limit
if err != nil || gas.Cmp((*big.Int)(&args.Gas)) == 0 {
@@ -671,8 +695,8 @@ type ExecutionResult struct {
type StructLogRes struct {
Pc uint64 `json:"pc"`
Op string `json:"op"`
- Gas *big.Int `json:"gas"`
- GasCost *big.Int `json:"gasCost"`
+ Gas uint64 `json:"gas"`
+ GasCost uint64 `json:"gasCost"`
Depth int `json:"depth"`
Error error `json:"error"`
Stack []string `json:"stack"`
@@ -696,7 +720,7 @@ func FormatLogs(structLogs []vm.StructLog) []StructLogRes {
}
for i, stackValue := range trace.Stack {
- formattedStructLogs[index].Stack[i] = fmt.Sprintf("%x", common.LeftPadBytes(stackValue.Bytes(), 32))
+ formattedStructLogs[index].Stack[i] = fmt.Sprintf("%x", math.PaddedBigBytes(stackValue, 32))
}
for i := 0; i+32 <= len(trace.Memory); i += 32 {
@@ -975,42 +999,40 @@ func getTransactionBlockData(chainDb ethdb.Database, txHash common.Hash) (common
}
// GetTransactionByHash returns the transaction for the given hash
-func (s *PublicTransactionPoolAPI) GetTransactionByHash(ctx context.Context, txHash common.Hash) (*RPCTransaction, error) {
+func (s *PublicTransactionPoolAPI) GetTransactionByHash(ctx context.Context, hash common.Hash) (*RPCTransaction, error) {
var tx *types.Transaction
var isPending bool
var err error
- if tx, isPending, err = getTransaction(s.b.ChainDb(), s.b, txHash); err != nil {
- glog.V(logger.Debug).Infof("%v\n", err)
+ if tx, isPending, err = getTransaction(s.b.ChainDb(), s.b, hash); err != nil {
+ log.Debug("Failed to retrieve transaction", "hash", hash, "err", err)
return nil, nil
} else if tx == nil {
return nil, nil
}
-
if isPending {
return newRPCPendingTransaction(tx), nil
}
- blockHash, _, _, err := getTransactionBlockData(s.b.ChainDb(), txHash)
+ blockHash, _, _, err := getTransactionBlockData(s.b.ChainDb(), hash)
if err != nil {
- glog.V(logger.Debug).Infof("%v\n", err)
+ log.Debug("Failed to retrieve transaction block", "hash", hash, "err", err)
return nil, nil
}
if block, _ := s.b.GetBlock(ctx, blockHash); block != nil {
- return newRPCTransaction(block, txHash)
+ return newRPCTransaction(block, hash)
}
-
return nil, nil
}
// GetRawTransactionByHash returns the bytes of the transaction for the given hash.
-func (s *PublicTransactionPoolAPI) GetRawTransactionByHash(ctx context.Context, txHash common.Hash) (hexutil.Bytes, error) {
+func (s *PublicTransactionPoolAPI) GetRawTransactionByHash(ctx context.Context, hash common.Hash) (hexutil.Bytes, error) {
var tx *types.Transaction
var err error
- if tx, _, err = getTransaction(s.b.ChainDb(), s.b, txHash); err != nil {
- glog.V(logger.Debug).Infof("%v\n", err)
+ if tx, _, err = getTransaction(s.b.ChainDb(), s.b, hash); err != nil {
+ log.Debug("Failed to retrieve transaction", "hash", hash, "err", err)
return nil, nil
} else if tx == nil {
return nil, nil
@@ -1020,22 +1042,22 @@ func (s *PublicTransactionPoolAPI) GetRawTransactionByHash(ctx context.Context,
}
// GetTransactionReceipt returns the transaction receipt for the given transaction hash.
-func (s *PublicTransactionPoolAPI) GetTransactionReceipt(txHash common.Hash) (map[string]interface{}, error) {
- receipt := core.GetReceipt(s.b.ChainDb(), txHash)
+func (s *PublicTransactionPoolAPI) GetTransactionReceipt(hash common.Hash) (map[string]interface{}, error) {
+ receipt := core.GetReceipt(s.b.ChainDb(), hash)
if receipt == nil {
- glog.V(logger.Debug).Infof("receipt not found for transaction %s", txHash.Hex())
+ log.Debug("Receipt not found for transaction", "hash", hash)
return nil, nil
}
- tx, _, err := getTransaction(s.b.ChainDb(), s.b, txHash)
+ tx, _, err := getTransaction(s.b.ChainDb(), s.b, hash)
if err != nil {
- glog.V(logger.Debug).Infof("%v\n", err)
+ log.Debug("Failed to retrieve transaction", "hash", hash, "err", err)
return nil, nil
}
- txBlock, blockIndex, index, err := getTransactionBlockData(s.b.ChainDb(), txHash)
+ txBlock, blockIndex, index, err := getTransactionBlockData(s.b.ChainDb(), hash)
if err != nil {
- glog.V(logger.Debug).Infof("%v\n", err)
+ log.Debug("Failed to retrieve transaction block", "hash", hash, "err", err)
return nil, nil
}
@@ -1049,7 +1071,7 @@ func (s *PublicTransactionPoolAPI) GetTransactionReceipt(txHash common.Hash) (ma
"root": hexutil.Bytes(receipt.PostState),
"blockHash": txBlock,
"blockNumber": hexutil.Uint64(blockIndex),
- "transactionHash": txHash,
+ "transactionHash": hash,
"transactionIndex": hexutil.Uint64(index),
"from": from,
"to": tx.To(),
@@ -1138,9 +1160,9 @@ func submitTransaction(ctx context.Context, b Backend, tx *types.Transaction) (c
signer := types.MakeSigner(b.ChainConfig(), b.CurrentBlock().Number())
from, _ := types.Sender(signer, tx)
addr := crypto.CreateAddress(from, tx.Nonce())
- glog.V(logger.Info).Infof("Tx(%s) created: %s\n", tx.Hash().Hex(), addr.Hex())
+ log.Info("Submitted contract creation", "fullhash", tx.Hash().Hex(), "contract", addr.Hex())
} else {
- glog.V(logger.Info).Infof("Tx(%s) to: %s\n", tx.Hash().Hex(), tx.To().Hex())
+ log.Info("Submitted transaction", "fullhash", tx.Hash().Hex(), "recipient", tx.To())
}
return tx.Hash(), nil
}
@@ -1192,9 +1214,9 @@ func (s *PublicTransactionPoolAPI) SendRawTransaction(ctx context.Context, encod
return "", err
}
addr := crypto.CreateAddress(from, tx.Nonce())
- glog.V(logger.Info).Infof("Tx(%x) created: %x\n", tx.Hash(), addr)
+ log.Info("Submitted contract creation", "fullhash", tx.Hash().Hex(), "contract", addr.Hex())
} else {
- glog.V(logger.Info).Infof("Tx(%x) to: %x\n", tx.Hash(), tx.To())
+ log.Info("Submitted transaction", "fullhash", tx.Hash().Hex(), "recipient", tx.To())
}
return tx.Hash().Hex(), nil
@@ -1356,11 +1378,7 @@ func (api *PublicDebugAPI) SeedHash(ctx context.Context, number uint64) (string,
if block == nil {
return "", fmt.Errorf("block #%d not found", number)
}
- hash, err := ethash.GetSeedHash(number)
- if err != nil {
- return "", err
- }
- return fmt.Sprintf("0x%x", hash), nil
+ return fmt.Sprintf("0x%x", pow.EthashSeedHash(number)), nil
}
// PrivateDebugAPI is the collection of Etheruem APIs exposed over the private
@@ -1399,10 +1417,10 @@ func (api *PrivateDebugAPI) ChaindbCompact() error {
return fmt.Errorf("chaindbCompact does not work for memory databases")
}
for b := byte(0); b < 255; b++ {
- glog.V(logger.Info).Infof("compacting chain DB range 0x%0.2X-0x%0.2X", b, b+1)
+ log.Info("Compacting chain database", "range", fmt.Sprintf("0x%0.2X-0x%0.2X", b, b+1))
err := ldb.LDB().CompactRange(util.Range{Start: []byte{b}, Limit: []byte{b + 1}})
if err != nil {
- glog.Errorf("compaction error: %v", err)
+ log.Error("Database compaction failed", "err", err)
return err
}
}
diff --git a/internal/ethapi/backend.go b/internal/ethapi/backend.go
index ebb14a5b5c..50cd3801b5 100644
--- a/internal/ethapi/backend.go
+++ b/internal/ethapi/backend.go
@@ -18,6 +18,7 @@
package ethapi
import (
+ "context"
"math/big"
"github.com/ethereum/go-ethereum/accounts"
@@ -30,7 +31,6 @@ import (
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rpc"
- "golang.org/x/net/context"
)
// Backend interface provides the common API services (that are provided by
@@ -51,7 +51,7 @@ type Backend interface {
GetBlock(ctx context.Context, blockHash common.Hash) (*types.Block, error)
GetReceipts(ctx context.Context, blockHash common.Hash) (types.Receipts, error)
GetTd(blockHash common.Hash) *big.Int
- GetVMEnv(ctx context.Context, msg core.Message, state State, header *types.Header) (*vm.EVM, func() error, error)
+ GetEVM(ctx context.Context, msg core.Message, state State, header *types.Header, vmCfg vm.Config) (*vm.EVM, func() error, error)
// TxPool API
SendTx(ctx context.Context, signedTx *types.Transaction) error
RemoveTx(txHash common.Hash)
@@ -73,8 +73,7 @@ type State interface {
}
func GetAPIs(apiBackend Backend, solcPath string) []rpc.API {
- compiler := makeCompilerAPIs(solcPath)
- all := []rpc.API{
+ return []rpc.API{
{
Namespace: "eth",
Version: "1.0",
@@ -116,5 +115,4 @@ func GetAPIs(apiBackend Backend, solcPath string) []rpc.API {
Public: false,
},
}
- return append(compiler, all...)
}
diff --git a/internal/ethapi/solc.go b/internal/ethapi/solc.go
deleted file mode 100644
index b9acc518b6..0000000000
--- a/internal/ethapi/solc.go
+++ /dev/null
@@ -1,82 +0,0 @@
-// Copyright 2016 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see .
-
-package ethapi
-
-import (
- "sync"
-
- "github.com/ethereum/go-ethereum/common/compiler"
- "github.com/ethereum/go-ethereum/rpc"
-)
-
-func makeCompilerAPIs(solcPath string) []rpc.API {
- c := &compilerAPI{solc: solcPath}
- return []rpc.API{
- {
- Namespace: "eth",
- Version: "1.0",
- Service: (*PublicCompilerAPI)(c),
- Public: true,
- },
- {
- Namespace: "admin",
- Version: "1.0",
- Service: (*CompilerAdminAPI)(c),
- Public: true,
- },
- }
-}
-
-type compilerAPI struct {
- // This lock guards the solc path set through the API.
- // It also ensures that only one solc process is used at
- // any time.
- mu sync.Mutex
- solc string
-}
-
-type CompilerAdminAPI compilerAPI
-
-// SetSolc sets the Solidity compiler path to be used by the node.
-func (api *CompilerAdminAPI) SetSolc(path string) (string, error) {
- api.mu.Lock()
- defer api.mu.Unlock()
- info, err := compiler.SolidityVersion(path)
- if err != nil {
- return "", err
- }
- api.solc = path
- return info.FullVersion, nil
-}
-
-type PublicCompilerAPI compilerAPI
-
-// CompileSolidity compiles the given solidity source.
-func (api *PublicCompilerAPI) CompileSolidity(source string) (map[string]*compiler.Contract, error) {
- api.mu.Lock()
- defer api.mu.Unlock()
- return compiler.CompileSolidityString(api.solc, source)
-}
-
-func (api *PublicCompilerAPI) GetCompilers() ([]string, error) {
- api.mu.Lock()
- defer api.mu.Unlock()
- if _, err := compiler.SolidityVersion(api.solc); err == nil {
- return []string{"Solidity"}, nil
- }
- return []string{}, nil
-}
diff --git a/internal/ethapi/tracer.go b/internal/ethapi/tracer.go
index ef107fc42f..fe26853753 100644
--- a/internal/ethapi/tracer.go
+++ b/internal/ethapi/tracer.go
@@ -278,7 +278,7 @@ func wrapError(context string, err error) error {
}
// CaptureState implements the Tracer interface to trace a single step of VM execution
-func (jst *JavascriptTracer) CaptureState(env *vm.EVM, pc uint64, op vm.OpCode, gas, cost *big.Int, memory *vm.Memory, stack *vm.Stack, contract *vm.Contract, depth int, err error) error {
+func (jst *JavascriptTracer) CaptureState(env *vm.EVM, pc uint64, op vm.OpCode, gas, cost uint64, memory *vm.Memory, stack *vm.Stack, contract *vm.Contract, depth int, err error) error {
if jst.err == nil {
jst.memory.memory = memory
jst.stack.stack = stack
@@ -288,8 +288,8 @@ func (jst *JavascriptTracer) CaptureState(env *vm.EVM, pc uint64, op vm.OpCode,
jst.log["pc"] = pc
jst.log["op"] = ocw.toValue(jst.vm)
- jst.log["gas"] = gas.Int64()
- jst.log["gasPrice"] = cost.Int64()
+ jst.log["gas"] = gas
+ jst.log["gasPrice"] = cost
jst.log["memory"] = jst.memvalue
jst.log["stack"] = jst.stackvalue
jst.log["depth"] = depth
diff --git a/internal/ethapi/tracer_test.go b/internal/ethapi/tracer_test.go
index 65a23f55e7..0ef450ce32 100644
--- a/internal/ethapi/tracer_test.go
+++ b/internal/ethapi/tracer_test.go
@@ -45,7 +45,7 @@ func (account) ForEachStorage(cb func(key, value common.Hash) bool) {}
func runTrace(tracer *JavascriptTracer) (interface{}, error) {
env := vm.NewEVM(vm.Context{}, nil, params.TestChainConfig, vm.Config{Debug: true, Tracer: tracer})
- contract := vm.NewContract(account{}, account{}, big.NewInt(0), big.NewInt(10000))
+ contract := vm.NewContract(account{}, account{}, big.NewInt(0), 10000)
contract.Code = []byte{byte(vm.PUSH1), 0x1, byte(vm.PUSH1), 0x1, 0x0}
_, err := env.Interpreter().Run(contract, []byte{})
@@ -134,12 +134,12 @@ func TestHaltBetweenSteps(t *testing.T) {
}
env := vm.NewEVM(vm.Context{}, nil, params.TestChainConfig, vm.Config{Debug: true, Tracer: tracer})
- contract := vm.NewContract(&account{}, &account{}, big.NewInt(0), big.NewInt(0))
+ contract := vm.NewContract(&account{}, &account{}, big.NewInt(0), 0)
- tracer.CaptureState(env, 0, 0, big.NewInt(0), big.NewInt(0), nil, nil, contract, 0, nil)
+ tracer.CaptureState(env, 0, 0, 0, 0, nil, nil, contract, 0, nil)
timeout := errors.New("stahp")
tracer.Stop(timeout)
- tracer.CaptureState(env, 0, 0, big.NewInt(0), big.NewInt(0), nil, nil, contract, 0, nil)
+ tracer.CaptureState(env, 0, 0, 0, 0, nil, nil, contract, 0, nil)
if _, err := tracer.GetResult(); err.Error() != "stahp in server-side tracer function 'step'" {
t.Errorf("Expected timeout error, got %v", err)
diff --git a/internal/jsre/deps/bindata.go b/internal/jsre/deps/bindata.go
index 5f6a2b873a..782d4df808 100644
--- a/internal/jsre/deps/bindata.go
+++ b/internal/jsre/deps/bindata.go
@@ -84,7 +84,7 @@ func bignumberJs() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "bignumber.js", size: 17314, mode: os.FileMode(420), modTime: time.Unix(1484232218, 0)}
+ info := bindataFileInfo{name: "bignumber.js", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -104,7 +104,7 @@ func web3Js() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "web3.js", size: 491740, mode: os.FileMode(420), modTime: time.Unix(1484232456, 0)}
+ info := bindataFileInfo{name: "web3.js", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
diff --git a/internal/jsre/deps/deps.go b/internal/jsre/deps/deps.go
index 8d0e1a4000..fe2e6f2fad 100644
--- a/internal/jsre/deps/deps.go
+++ b/internal/jsre/deps/deps.go
@@ -17,4 +17,5 @@
// Package deps contains the console JavaScript dependencies Go embedded.
package deps
-//go:generate go-bindata -o bindata.go bignumber.js web3.js
+//go:generate go-bindata -nometadata -pkg deps -o bindata.go bignumber.js web3.js
+//go:generate gofmt -w -s bindata.go
diff --git a/internal/web3ext/web3ext.go b/internal/web3ext/web3ext.go
index 2012c2517f..79f7817810 100644
--- a/internal/web3ext/web3ext.go
+++ b/internal/web3ext/web3ext.go
@@ -27,9 +27,12 @@ var Modules = map[string]string{
"personal": Personal_JS,
"rpc": RPC_JS,
"shh": Shh_JS,
+ "swarmfs": SWARMFS_JS,
"txpool": TxPool_JS,
+
}
+
const Chequebook_JS = `
web3._extend({
property: 'chequebook',
@@ -294,7 +297,12 @@ web3._extend({
call: 'debug_preimage',
params: 1,
inputFormatter: [null]
- })
+ }),
+ new web3._extend.Method({
+ name: 'getBadBlocks',
+ call: 'debug_getBadBlocks',
+ params: 0,
+ }),
],
properties: []
});
@@ -394,20 +402,8 @@ web3._extend({
inputFormatter: [web3._extend.utils.fromDecimal]
}),
new web3._extend.Method({
- name: 'startAutoDAG',
- call: 'miner_startAutoDAG',
- params: 0
- }),
- new web3._extend.Method({
- name: 'stopAutoDAG',
- call: 'miner_stopAutoDAG',
- params: 0
- }),
- new web3._extend.Method({
- name: 'makeDAG',
- call: 'miner_makeDAG',
- params: 1,
- inputFormatter: [web3._extend.formatters.inputDefaultBlockNumberFormatter]
+ name: 'getHashrate',
+ call: 'miner_getHashrate'
})
],
properties: []
@@ -493,6 +489,32 @@ web3._extend({
]
});
`
+const SWARMFS_JS = `
+web3._extend({
+ property: 'swarmfs',
+ methods:
+ [
+ new web3._extend.Method({
+ name: 'mount',
+ call: 'swarmfs_mount',
+ params: 2,
+ inputFormatter: [null,null]
+ }),
+ new web3._extend.Method({
+ name: 'unmount',
+ call: 'swarmfs_unmount',
+ params: 1,
+ inputFormatter: [null]
+ }),
+ new web3._extend.Method({
+ name: 'listmounts',
+ call: 'swarmfs_listmounts',
+ params: 0,
+ inputFormatter: []
+ })
+ ]
+});
+`
const TxPool_JS = `
web3._extend({
diff --git a/les/api_backend.go b/les/api_backend.go
index 3a71ac4e02..df2782f780 100644
--- a/les/api_backend.go
+++ b/les/api_backend.go
@@ -17,10 +17,12 @@
package les
import (
+ "context"
"math/big"
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
@@ -32,7 +34,6 @@ import (
"github.com/ethereum/go-ethereum/light"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rpc"
- "golang.org/x/net/context"
)
type LesApiBackend struct {
@@ -49,6 +50,7 @@ func (b *LesApiBackend) CurrentBlock() *types.Block {
}
func (b *LesApiBackend) SetHead(number uint64) {
+ b.eth.protocolManager.downloader.Cancel()
b.eth.blockchain.SetHead(number)
}
@@ -88,18 +90,18 @@ func (b *LesApiBackend) GetTd(blockHash common.Hash) *big.Int {
return b.eth.blockchain.GetTdByHash(blockHash)
}
-func (b *LesApiBackend) GetVMEnv(ctx context.Context, msg core.Message, state ethapi.State, header *types.Header) (*vm.EVM, func() error, error) {
+func (b *LesApiBackend) GetEVM(ctx context.Context, msg core.Message, state ethapi.State, header *types.Header, vmCfg vm.Config) (*vm.EVM, func() error, error) {
stateDb := state.(*light.LightState).Copy()
addr := msg.From()
from, err := stateDb.GetOrNewStateObject(ctx, addr)
if err != nil {
return nil, nil, err
}
- from.SetBalance(common.MaxBig)
+ from.SetBalance(math.MaxBig256)
vmstate := light.NewVMState(ctx, stateDb)
context := core.NewEVMContext(msg, header, b.eth.blockchain)
- return vm.NewEVM(context, vmstate, b.eth.chainConfig, vm.Config{}), vmstate.Error, nil
+ return vm.NewEVM(context, vmstate, b.eth.chainConfig, vmCfg), vmstate.Error, nil
}
func (b *LesApiBackend) SendTx(ctx context.Context, signedTx *types.Transaction) error {
diff --git a/les/backend.go b/les/backend.go
index 21ee084987..d656cf41f5 100644
--- a/les/backend.go
+++ b/les/backend.go
@@ -18,7 +18,6 @@
package les
import (
- "errors"
"fmt"
"time"
@@ -36,8 +35,7 @@ import (
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/internal/ethapi"
"github.com/ethereum/go-ethereum/light"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/params"
@@ -75,13 +73,11 @@ func New(ctx *node.ServiceContext, config *eth.Config) (*LightEthereum, error) {
if err != nil {
return nil, err
}
- if err := eth.SetupGenesisBlock(&chainDb, config); err != nil {
- return nil, err
- }
- pow, err := eth.CreatePoW(config)
- if err != nil {
- return nil, err
+ chainConfig, genesisHash, genesisErr := core.SetupGenesisBlock(chainDb, config.Genesis)
+ if _, isCompat := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !isCompat {
+ return nil, genesisErr
}
+ log.Info("Initialised chain configuration", "config", chainConfig)
odr := NewLesOdr(chainDb)
relay := NewLesTxRelay()
@@ -89,30 +85,32 @@ func New(ctx *node.ServiceContext, config *eth.Config) (*LightEthereum, error) {
odr: odr,
relay: relay,
chainDb: chainDb,
+ chainConfig: chainConfig,
eventMux: ctx.EventMux,
accountManager: ctx.AccountManager,
- pow: pow,
+ pow: eth.CreatePoW(ctx, config),
shutdownChan: make(chan bool),
netVersionId: config.NetworkId,
solcPath: config.SolcPath,
}
- if config.ChainConfig == nil {
- return nil, errors.New("missing chain config")
- }
- eth.chainConfig = config.ChainConfig
eth.blockchain, err = light.NewLightChain(odr, eth.chainConfig, eth.pow, eth.eventMux)
if err != nil {
- if err == core.ErrNoGenesis {
- return nil, fmt.Errorf(`Genesis block not found. Please supply a genesis block with the "--genesis /path/to/file" argument`)
- }
return nil, err
}
+ // Rewind the chain in case of an incompatible config upgrade.
+ if compat, ok := genesisErr.(*params.ConfigCompatError); ok {
+ log.Warn("Rewinding chain to upgrade configuration", "err", compat)
+ eth.blockchain.SetHead(compat.RewindTo)
+ core.WriteChainConfig(chainDb, genesisHash, chainConfig)
+ }
eth.txPool = light.NewTxPool(eth.chainConfig, eth.eventMux, eth.blockchain, eth.relay)
if eth.protocolManager, err = NewProtocolManager(eth.chainConfig, config.LightMode, config.NetworkId, eth.eventMux, eth.pow, eth.blockchain, nil, chainDb, odr, relay); err != nil {
return nil, err
}
+ relay.ps = eth.protocolManager.peers
+ relay.reqDist = eth.protocolManager.reqDist
eth.ApiBackend = &LesApiBackend{eth, nil}
eth.ApiBackend.gpo = gasprice.NewLightPriceOracle(eth.ApiBackend)
@@ -188,7 +186,7 @@ func (s *LightEthereum) Protocols() []p2p.Protocol {
// Start implements node.Service, starting all internal goroutines needed by the
// Ethereum protocol implementation.
func (s *LightEthereum) Start(srvr *p2p.Server) error {
- glog.V(logger.Info).Infof("WARNING: light client mode is an experimental feature")
+ log.Warn("Light client mode is an experimental feature")
s.netRPCService = ethapi.NewPublicNetAPI(srvr, s.netVersionId)
s.protocolManager.Start(srvr)
return nil
diff --git a/les/distributor.go b/les/distributor.go
new file mode 100644
index 0000000000..c59b36146f
--- /dev/null
+++ b/les/distributor.go
@@ -0,0 +1,259 @@
+// Copyright 2016 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+// Package light implements on-demand retrieval capable state and chain objects
+// for the Ethereum Light Client.
+package les
+
+import (
+ "container/list"
+ "errors"
+ "sync"
+ "time"
+)
+
+// ErrNoPeers is returned if no peers capable of serving a queued request are available
+var ErrNoPeers = errors.New("no suitable peers available")
+
+// requestDistributor implements a mechanism that distributes requests to
+// suitable peers, obeying flow control rules and prioritizing them in creation
+// order (even when a resend is necessary).
+type requestDistributor struct {
+ reqQueue *list.List
+ lastReqOrder uint64
+ stopChn, loopChn chan struct{}
+ loopNextSent bool
+ lock sync.Mutex
+
+ getAllPeers func() map[distPeer]struct{}
+}
+
+// distPeer is an LES server peer interface for the request distributor.
+// waitBefore returns either the necessary waiting time before sending a request
+// with the given upper estimated cost or the estimated remaining relative buffer
+// value after sending such a request (in which case the request can be sent
+// immediately). At least one of these values is always zero.
+type distPeer interface {
+ waitBefore(uint64) (time.Duration, float64)
+ canQueue() bool
+ queueSend(f func())
+}
+
+// distReq is the request abstraction used by the distributor. It is based on
+// three callback functions:
+// - getCost returns the upper estimate of the cost of sending the request to a given peer
+// - canSend tells if the server peer is suitable to serve the request
+// - request prepares sending the request to the given peer and returns a function that
+// does the actual sending. Request order should be preserved but the callback itself should not
+// block until it is sent because other peers might still be able to receive requests while
+// one of them is blocking. Instead, the returned function is put in the peer's send queue.
+type distReq struct {
+ getCost func(distPeer) uint64
+ canSend func(distPeer) bool
+ request func(distPeer) func()
+
+ reqOrder uint64
+ sentChn chan distPeer
+ element *list.Element
+}
+
+// newRequestDistributor creates a new request distributor
+func newRequestDistributor(getAllPeers func() map[distPeer]struct{}, stopChn chan struct{}) *requestDistributor {
+ r := &requestDistributor{
+ reqQueue: list.New(),
+ loopChn: make(chan struct{}, 2),
+ stopChn: stopChn,
+ getAllPeers: getAllPeers,
+ }
+ go r.loop()
+ return r
+}
+
+// distMaxWait is the maximum waiting time after which further necessary waiting
+// times are recalculated based on new feedback from the servers
+const distMaxWait = time.Millisecond * 10
+
+// main event loop
+func (d *requestDistributor) loop() {
+ for {
+ select {
+ case <-d.stopChn:
+ d.lock.Lock()
+ elem := d.reqQueue.Front()
+ for elem != nil {
+ close(elem.Value.(*distReq).sentChn)
+ elem = elem.Next()
+ }
+ d.lock.Unlock()
+ return
+ case <-d.loopChn:
+ d.lock.Lock()
+ d.loopNextSent = false
+ loop:
+ for {
+ peer, req, wait := d.nextRequest()
+ if req != nil && wait == 0 {
+ chn := req.sentChn // save sentChn because remove sets it to nil
+ d.remove(req)
+ send := req.request(peer)
+ if send != nil {
+ peer.queueSend(send)
+ }
+ chn <- peer
+ close(chn)
+ } else {
+ if wait == 0 {
+ // no request to send and nothing to wait for; the next
+ // queued request will wake up the loop
+ break loop
+ }
+ d.loopNextSent = true // a "next" signal has been sent, do not send another one until this one has been received
+ if wait > distMaxWait {
+ // waiting times may be reduced by incoming request replies, if it is too long, recalculate it periodically
+ wait = distMaxWait
+ }
+ go func() {
+ time.Sleep(wait)
+ d.loopChn <- struct{}{}
+ }()
+ break loop
+ }
+ }
+ d.lock.Unlock()
+ }
+ }
+}
+
+// selectPeerItem represents a peer to be selected for a request by weightedRandomSelect
+type selectPeerItem struct {
+ peer distPeer
+ req *distReq
+ weight int64
+}
+
+// Weight implements wrsItem interface
+func (sp selectPeerItem) Weight() int64 {
+ return sp.weight
+}
+
+// nextRequest returns the next possible request from any peer, along with the
+// associated peer and necessary waiting time
+func (d *requestDistributor) nextRequest() (distPeer, *distReq, time.Duration) {
+ peers := d.getAllPeers()
+
+ elem := d.reqQueue.Front()
+ var (
+ bestPeer distPeer
+ bestReq *distReq
+ bestWait time.Duration
+ sel *weightedRandomSelect
+ )
+
+ for (len(peers) > 0 || elem == d.reqQueue.Front()) && elem != nil {
+ req := elem.Value.(*distReq)
+ canSend := false
+ for peer, _ := range peers {
+ if peer.canQueue() && req.canSend(peer) {
+ canSend = true
+ cost := req.getCost(peer)
+ wait, bufRemain := peer.waitBefore(cost)
+ if wait == 0 {
+ if sel == nil {
+ sel = newWeightedRandomSelect()
+ }
+ sel.update(selectPeerItem{peer: peer, req: req, weight: int64(bufRemain*1000000) + 1})
+ } else {
+ if bestReq == nil || wait < bestWait {
+ bestPeer = peer
+ bestReq = req
+ bestWait = wait
+ }
+ }
+ delete(peers, peer)
+ }
+ }
+ next := elem.Next()
+ if !canSend && elem == d.reqQueue.Front() {
+ close(req.sentChn)
+ d.remove(req)
+ }
+ elem = next
+ }
+
+ if sel != nil {
+ c := sel.choose().(selectPeerItem)
+ return c.peer, c.req, 0
+ }
+ return bestPeer, bestReq, bestWait
+}
+
+// queue adds a request to the distribution queue, returns a channel where the
+// receiving peer is sent once the request has been sent (request callback returned).
+// If the request is cancelled or timed out without suitable peers, the channel is
+// closed without sending any peer references to it.
+func (d *requestDistributor) queue(r *distReq) chan distPeer {
+ d.lock.Lock()
+ defer d.lock.Unlock()
+
+ if r.reqOrder == 0 {
+ d.lastReqOrder++
+ r.reqOrder = d.lastReqOrder
+ }
+
+ back := d.reqQueue.Back()
+ if back == nil || r.reqOrder > back.Value.(*distReq).reqOrder {
+ r.element = d.reqQueue.PushBack(r)
+ } else {
+ before := d.reqQueue.Front()
+ for before.Value.(*distReq).reqOrder < r.reqOrder {
+ before = before.Next()
+ }
+ r.element = d.reqQueue.InsertBefore(r, before)
+ }
+
+ if !d.loopNextSent {
+ d.loopNextSent = true
+ d.loopChn <- struct{}{}
+ }
+
+ r.sentChn = make(chan distPeer, 1)
+ return r.sentChn
+}
+
+// cancel removes a request from the queue if it has not been sent yet (returns
+// false if it has been sent already). It is guaranteed that the callback functions
+// will not be called after cancel returns.
+func (d *requestDistributor) cancel(r *distReq) bool {
+ d.lock.Lock()
+ defer d.lock.Unlock()
+
+ if r.sentChn == nil {
+ return false
+ }
+
+ close(r.sentChn)
+ d.remove(r)
+ return true
+}
+
+// remove removes a request from the queue
+func (d *requestDistributor) remove(r *distReq) {
+ r.sentChn = nil
+ if r.element != nil {
+ d.reqQueue.Remove(r.element)
+ r.element = nil
+ }
+}
diff --git a/les/distributor_test.go b/les/distributor_test.go
new file mode 100644
index 0000000000..f2eb80729b
--- /dev/null
+++ b/les/distributor_test.go
@@ -0,0 +1,192 @@
+// Copyright 2016 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+// Package light implements on-demand retrieval capable state and chain objects
+// for the Ethereum Light Client.
+package les
+
+import (
+ "math/rand"
+ "sync"
+ "testing"
+ "time"
+)
+
+type testDistReq struct {
+ cost, procTime, order uint64
+ canSendTo map[*testDistPeer]struct{}
+}
+
+func (r *testDistReq) getCost(dp distPeer) uint64 {
+ return r.cost
+}
+
+func (r *testDistReq) canSend(dp distPeer) bool {
+ _, ok := r.canSendTo[dp.(*testDistPeer)]
+ return ok
+}
+
+func (r *testDistReq) request(dp distPeer) func() {
+ return func() { dp.(*testDistPeer).send(r) }
+}
+
+type testDistPeer struct {
+ sent []*testDistReq
+ sumCost uint64
+ lock sync.RWMutex
+}
+
+func (p *testDistPeer) send(r *testDistReq) {
+ p.lock.Lock()
+ defer p.lock.Unlock()
+
+ p.sent = append(p.sent, r)
+ p.sumCost += r.cost
+}
+
+func (p *testDistPeer) worker(t *testing.T, checkOrder bool, stop chan struct{}) {
+ var last uint64
+ for {
+ wait := time.Millisecond
+ p.lock.Lock()
+ if len(p.sent) > 0 {
+ rq := p.sent[0]
+ wait = time.Duration(rq.procTime)
+ p.sumCost -= rq.cost
+ if checkOrder {
+ if rq.order <= last {
+ t.Errorf("Requests processed in wrong order")
+ }
+ last = rq.order
+ }
+ p.sent = p.sent[1:]
+ }
+ p.lock.Unlock()
+ select {
+ case <-stop:
+ return
+ case <-time.After(wait):
+ }
+ }
+}
+
+const (
+ testDistBufLimit = 10000000
+ testDistMaxCost = 1000000
+ testDistPeerCount = 5
+ testDistReqCount = 50000
+ testDistMaxResendCount = 3
+)
+
+func (p *testDistPeer) waitBefore(cost uint64) (time.Duration, float64) {
+ p.lock.RLock()
+ sumCost := p.sumCost + cost
+ p.lock.RUnlock()
+ if sumCost < testDistBufLimit {
+ return 0, float64(testDistBufLimit-sumCost) / float64(testDistBufLimit)
+ } else {
+ return time.Duration(sumCost - testDistBufLimit), 0
+ }
+}
+
+func (p *testDistPeer) canQueue() bool {
+ return true
+}
+
+func (p *testDistPeer) queueSend(f func()) {
+ f()
+}
+
+func TestRequestDistributor(t *testing.T) {
+ testRequestDistributor(t, false)
+}
+
+func TestRequestDistributorResend(t *testing.T) {
+ testRequestDistributor(t, true)
+}
+
+func testRequestDistributor(t *testing.T, resend bool) {
+ stop := make(chan struct{})
+ defer close(stop)
+
+ var peers [testDistPeerCount]*testDistPeer
+ for i, _ := range peers {
+ peers[i] = &testDistPeer{}
+ go peers[i].worker(t, !resend, stop)
+ }
+
+ dist := newRequestDistributor(func() map[distPeer]struct{} {
+ m := make(map[distPeer]struct{})
+ for _, peer := range peers {
+ m[peer] = struct{}{}
+ }
+ return m
+ }, stop)
+
+ var wg sync.WaitGroup
+
+ for i := 1; i <= testDistReqCount; i++ {
+ cost := uint64(rand.Int63n(testDistMaxCost))
+ procTime := uint64(rand.Int63n(int64(cost + 1)))
+ rq := &testDistReq{
+ cost: cost,
+ procTime: procTime,
+ order: uint64(i),
+ canSendTo: make(map[*testDistPeer]struct{}),
+ }
+ for _, peer := range peers {
+ if rand.Intn(2) != 0 {
+ rq.canSendTo[peer] = struct{}{}
+ }
+ }
+
+ wg.Add(1)
+ req := &distReq{
+ getCost: rq.getCost,
+ canSend: rq.canSend,
+ request: rq.request,
+ }
+ chn := dist.queue(req)
+ go func() {
+ cnt := 1
+ if resend && len(rq.canSendTo) != 0 {
+ cnt = rand.Intn(testDistMaxResendCount) + 1
+ }
+ for i := 0; i < cnt; i++ {
+ if i != 0 {
+ chn = dist.queue(req)
+ }
+ p := <-chn
+ if p == nil {
+ if len(rq.canSendTo) != 0 {
+ t.Errorf("Request that could have been sent was dropped")
+ }
+ } else {
+ peer := p.(*testDistPeer)
+ if _, ok := rq.canSendTo[peer]; !ok {
+ t.Errorf("Request sent to wrong peer")
+ }
+ }
+ }
+ wg.Done()
+ }()
+ if rand.Intn(1000) == 0 {
+ time.Sleep(time.Duration(rand.Intn(5000000)))
+ }
+ }
+
+ wg.Wait()
+}
diff --git a/les/execqueue.go b/les/execqueue.go
new file mode 100644
index 0000000000..ac779003bd
--- /dev/null
+++ b/les/execqueue.go
@@ -0,0 +1,71 @@
+// Copyright 2017 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+package les
+
+import (
+ "sync/atomic"
+)
+
+// ExecQueue implements a queue that executes function calls in a single thread,
+// in the same order as they have been queued.
+type execQueue struct {
+ chn chan func()
+ cnt, stop, capacity int32
+}
+
+// NewExecQueue creates a new execution queue.
+func newExecQueue(capacity int32) *execQueue {
+ q := &execQueue{
+ chn: make(chan func(), capacity),
+ capacity: capacity,
+ }
+ go q.loop()
+ return q
+}
+
+func (q *execQueue) loop() {
+ for f := range q.chn {
+ atomic.AddInt32(&q.cnt, -1)
+ if atomic.LoadInt32(&q.stop) != 0 {
+ return
+ }
+ f()
+ }
+}
+
+// CanQueue returns true if more function calls can be added to the execution queue.
+func (q *execQueue) canQueue() bool {
+ return atomic.LoadInt32(&q.stop) == 0 && atomic.LoadInt32(&q.cnt) < q.capacity
+}
+
+// Queue adds a function call to the execution queue. Returns true if successful.
+func (q *execQueue) queue(f func()) bool {
+ if atomic.LoadInt32(&q.stop) != 0 {
+ return false
+ }
+ if atomic.AddInt32(&q.cnt, 1) > q.capacity {
+ atomic.AddInt32(&q.cnt, -1)
+ return false
+ }
+ q.chn <- f
+ return true
+}
+
+// Stop stops the exec queue.
+func (q *execQueue) quit() {
+ atomic.StoreInt32(&q.stop, 1)
+}
diff --git a/les/fetcher.go b/les/fetcher.go
index de706de5e0..353e919323 100644
--- a/les/fetcher.go
+++ b/les/fetcher.go
@@ -27,8 +27,7 @@ import (
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/light"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/log"
)
const (
@@ -136,35 +135,38 @@ func (f *lightFetcher) syncLoop() {
f.lock.Lock()
s := requesting
requesting = false
+ var (
+ rq *distReq
+ reqID uint64
+ )
if !f.syncing && !(newAnnounce && s) {
- reqID := getNextReqID()
- if peer, node, amount, retry := f.nextRequest(reqID); node != nil {
- requesting = true
- if reqID, ok := f.request(peer, reqID, node, amount); ok {
- go func() {
- time.Sleep(softRequestTimeout)
- f.reqMu.Lock()
- req, ok := f.requested[reqID]
- if ok {
- req.timeout = true
- f.requested[reqID] = req
- }
- f.reqMu.Unlock()
- // keep starting new requests while possible
- f.requestChn <- false
- }()
- }
- } else {
- if retry {
- requesting = true
- go func() {
- time.Sleep(time.Millisecond * 100)
- f.requestChn <- false
- }()
- }
+ rq, reqID = f.nextRequest()
+ }
+ syncing := f.syncing
+ f.lock.Unlock()
+
+ if rq != nil {
+ requesting = true
+ _, ok := <-f.pm.reqDist.queue(rq)
+ if !ok {
+ f.requestChn <- false
+ }
+
+ if !syncing {
+ go func() {
+ time.Sleep(softRequestTimeout)
+ f.reqMu.Lock()
+ req, ok := f.requested[reqID]
+ if ok {
+ req.timeout = true
+ f.requested[reqID] = req
+ }
+ f.reqMu.Unlock()
+ // keep starting new requests while possible
+ f.requestChn <- false
+ }()
}
}
- f.lock.Unlock()
case reqID := <-f.timeoutChn:
f.reqMu.Lock()
req, ok := f.requested[reqID]
@@ -174,7 +176,7 @@ func (f *lightFetcher) syncLoop() {
f.reqMu.Unlock()
if ok {
f.pm.serverPool.adjustResponseTime(req.peer.poolEntry, time.Duration(mclock.Now()-req.sent), true)
- glog.V(logger.Debug).Infof("hard timeout by peer %v", req.peer.id)
+ req.peer.Log().Debug("Fetching data timed out hard")
go f.pm.removePeer(req.peer.id)
}
case resp := <-f.deliverChn:
@@ -192,13 +194,13 @@ func (f *lightFetcher) syncLoop() {
}
f.lock.Lock()
if !ok || !(f.syncing || f.processResponse(req, resp)) {
- glog.V(logger.Debug).Infof("failed processing response by peer %v", resp.peer.id)
+ resp.peer.Log().Debug("Failed processing response")
go f.pm.removePeer(resp.peer.id)
}
f.lock.Unlock()
case p := <-f.syncDone:
f.lock.Lock()
- glog.V(logger.Debug).Infof("done synchronising with peer %v", p.id)
+ p.Log().Debug("Done synchronising with peer")
f.checkSyncedHeaders(p)
f.syncing = false
f.lock.Unlock()
@@ -239,17 +241,17 @@ func (f *lightFetcher) removePeer(p *peer) {
func (f *lightFetcher) announce(p *peer, head *announceData) {
f.lock.Lock()
defer f.lock.Unlock()
- glog.V(logger.Debug).Infof("received announce from peer %v #%d %016x reorg: %d", p.id, head.Number, head.Hash[:8], head.ReorgDepth)
+ p.Log().Debug("Received new announcement", "number", head.Number, "hash", head.Hash, "reorg", head.ReorgDepth)
fp := f.peers[p]
if fp == nil {
- glog.V(logger.Debug).Infof("announce: unknown peer")
+ p.Log().Debug("Announcement from unknown peer")
return
}
if fp.lastAnnounced != nil && head.Td.Cmp(fp.lastAnnounced.td) <= 0 {
// announced tds should be strictly monotonic
- glog.V(logger.Debug).Infof("non-monotonic Td from peer %v", p.id)
+ p.Log().Debug("Received non-monotonic td", "current", head.Td, "previous", fp.lastAnnounced.td)
go f.pm.removePeer(p.id)
return
}
@@ -335,6 +337,12 @@ func (f *lightFetcher) peerHasBlock(p *peer, hash common.Hash, number uint64) bo
f.lock.Lock()
defer f.lock.Unlock()
+ if f.syncing {
+ // always return true when syncing
+ // false positives are acceptable, a more sophisticated condition can be implemented later
+ return true
+ }
+
fp := f.peers[p]
if fp == nil || fp.root == nil {
return false
@@ -347,43 +355,13 @@ func (f *lightFetcher) peerHasBlock(p *peer, hash common.Hash, number uint64) bo
f.chain.LockChain()
defer f.chain.UnlockChain()
// if it's older than the peer's block tree root but it's in the same canonical chain
- // than the root, we can still be sure the peer knows it
+ // as the root, we can still be sure the peer knows it
+ //
+ // when syncing, just check if it is part of the known chain, there is nothing better we
+ // can do since we do not know the most recent block hash yet
return core.GetCanonicalHash(f.pm.chainDb, fp.root.number) == fp.root.hash && core.GetCanonicalHash(f.pm.chainDb, number) == hash
}
-// request initiates a header download request from a certain peer
-func (f *lightFetcher) request(p *peer, reqID uint64, n *fetcherTreeNode, amount uint64) (uint64, bool) {
- fp := f.peers[p]
- if fp == nil {
- glog.V(logger.Debug).Infof("request: unknown peer")
- p.fcServer.DeassignRequest(reqID)
- return 0, false
- }
- if fp.bestConfirmed == nil || fp.root == nil || !f.checkKnownNode(p, fp.root) {
- f.syncing = true
- go func() {
- glog.V(logger.Debug).Infof("synchronising with peer %v", p.id)
- f.pm.synchronise(p)
- f.syncDone <- p
- }()
- p.fcServer.DeassignRequest(reqID)
- return 0, false
- }
-
- n.requested = true
- cost := p.GetRequestCost(GetBlockHeadersMsg, int(amount))
- p.fcServer.SendRequest(reqID, cost)
- f.reqMu.Lock()
- f.requested[reqID] = fetchRequest{hash: n.hash, amount: amount, peer: p, sent: mclock.Now()}
- f.reqMu.Unlock()
- go p.RequestHeadersByHash(reqID, cost, n.hash, int(amount), 0, true)
- go func() {
- time.Sleep(hardRequestTimeout)
- f.timeoutChn <- reqID
- }()
- return reqID, true
-}
-
// requestAmount calculates the amount of headers to be downloaded starting
// from a certain head backwards
func (f *lightFetcher) requestAmount(p *peer, n *fetcherTreeNode) uint64 {
@@ -409,12 +387,13 @@ func (f *lightFetcher) requestedID(reqID uint64) bool {
// nextRequest selects the peer and announced head to be requested next, amount
// to be downloaded starting from the head backwards is also returned
-func (f *lightFetcher) nextRequest(reqID uint64) (*peer, *fetcherTreeNode, uint64, bool) {
+func (f *lightFetcher) nextRequest() (*distReq, uint64) {
var (
bestHash common.Hash
bestAmount uint64
)
bestTd := f.maxConfirmedTd
+ bestSyncing := false
for p, fp := range f.peers {
for hash, n := range fp.nodeByHash {
@@ -424,29 +403,83 @@ func (f *lightFetcher) nextRequest(reqID uint64) (*peer, *fetcherTreeNode, uint6
bestHash = hash
bestAmount = amount
bestTd = n.td
+ bestSyncing = fp.bestConfirmed == nil || fp.root == nil || !f.checkKnownNode(p, fp.root)
}
}
}
}
if bestTd == f.maxConfirmedTd {
- return nil, nil, 0, false
+ return nil, 0
}
- peer, _, locked := f.pm.serverPool.selectPeer(reqID, func(p *peer) (bool, time.Duration) {
- fp := f.peers[p]
- if fp == nil || fp.nodeByHash[bestHash] == nil {
- return false, 0
+ f.syncing = bestSyncing
+
+ var rq *distReq
+ reqID := getNextReqID()
+ if f.syncing {
+ rq = &distReq{
+ getCost: func(dp distPeer) uint64 {
+ return 0
+ },
+ canSend: func(dp distPeer) bool {
+ p := dp.(*peer)
+ fp := f.peers[p]
+ return fp != nil && fp.nodeByHash[bestHash] != nil
+ },
+ request: func(dp distPeer) func() {
+ go func() {
+ p := dp.(*peer)
+ p.Log().Debug("Synchronisation started")
+ f.pm.synchronise(p)
+ f.syncDone <- p
+ }()
+ return nil
+ },
+ }
+ } else {
+ rq = &distReq{
+ getCost: func(dp distPeer) uint64 {
+ p := dp.(*peer)
+ return p.GetRequestCost(GetBlockHeadersMsg, int(bestAmount))
+ },
+ canSend: func(dp distPeer) bool {
+ p := dp.(*peer)
+ f.lock.Lock()
+ defer f.lock.Unlock()
+
+ fp := f.peers[p]
+ if fp == nil {
+ return false
+ }
+ n := fp.nodeByHash[bestHash]
+ return n != nil && !n.requested
+ },
+ request: func(dp distPeer) func() {
+ p := dp.(*peer)
+ f.lock.Lock()
+ fp := f.peers[p]
+ if fp != nil {
+ n := fp.nodeByHash[bestHash]
+ if n != nil {
+ n.requested = true
+ }
+ }
+ f.lock.Unlock()
+
+ cost := p.GetRequestCost(GetBlockHeadersMsg, int(bestAmount))
+ p.fcServer.QueueRequest(reqID, cost)
+ f.reqMu.Lock()
+ f.requested[reqID] = fetchRequest{hash: bestHash, amount: bestAmount, peer: p, sent: mclock.Now()}
+ f.reqMu.Unlock()
+ go func() {
+ time.Sleep(hardRequestTimeout)
+ f.timeoutChn <- reqID
+ }()
+ return func() { p.RequestHeadersByHash(reqID, cost, bestHash, int(bestAmount), 0, true) }
+ },
}
- return true, p.fcServer.CanSend(p.GetRequestCost(GetBlockHeadersMsg, int(bestAmount)))
- })
- if !locked {
- return nil, nil, 0, true
}
- var node *fetcherTreeNode
- if peer != nil {
- node = f.peers[peer].nodeByHash[bestHash]
- }
- return peer, node, bestAmount, false
+ return rq, reqID
}
// deliverHeaders delivers header download request responses for processing
@@ -457,7 +490,7 @@ func (f *lightFetcher) deliverHeaders(peer *peer, reqID uint64, headers []*types
// processResponse processes header download request responses, returns true if successful
func (f *lightFetcher) processResponse(req fetchRequest, resp fetchResponse) bool {
if uint64(len(resp.headers)) != req.amount || resp.headers[0].Hash() != req.hash {
- glog.V(logger.Debug).Infof("response mismatch %v %016x != %v %016x", len(resp.headers), resp.headers[0].Hash().Bytes()[:8], req.amount, req.hash[:8])
+ req.peer.Log().Debug("Response content mismatch", "requested", len(resp.headers), "reqfrom", resp.headers[0], "delivered", req.amount, "delfrom", req.hash)
return false
}
headers := make([]*types.Header, req.amount)
@@ -468,14 +501,14 @@ func (f *lightFetcher) processResponse(req fetchRequest, resp fetchResponse) boo
if err == core.BlockFutureErr {
return true
}
- glog.V(logger.Debug).Infof("InsertHeaderChain error: %v", err)
+ log.Debug("Failed to insert header chain", "err", err)
return false
}
tds := make([]*big.Int, len(headers))
for i, header := range headers {
td := f.chain.GetTd(header.Hash(), header.Number.Uint64())
if td == nil {
- glog.V(logger.Debug).Infof("TD not found for header %v of %v", i+1, len(headers))
+ log.Debug("Total difficulty not found for header", "index", i+1, "number", header.Number, "hash", header.Hash())
return false
}
tds[i] = td
@@ -490,7 +523,7 @@ func (f *lightFetcher) newHeaders(headers []*types.Header, tds []*big.Int) {
var maxTd *big.Int
for p, fp := range f.peers {
if !f.checkAnnouncedHeaders(fp, headers, tds) {
- glog.V(logger.Debug).Infof("announce inconsistency by peer %v", p.id)
+ p.Log().Debug("Inconsistent announcement")
go f.pm.removePeer(p.id)
}
if fp.confirmedTd != nil && (maxTd == nil || maxTd.Cmp(fp.confirmedTd) > 0) {
@@ -576,7 +609,7 @@ func (f *lightFetcher) checkAnnouncedHeaders(fp *fetcherPeerInfo, headers []*typ
func (f *lightFetcher) checkSyncedHeaders(p *peer) {
fp := f.peers[p]
if fp == nil {
- glog.V(logger.Debug).Infof("checkSyncedHeaders: unknown peer")
+ p.Log().Debug("Unknown peer to check sync headers")
return
}
n := fp.lastAnnounced
@@ -589,7 +622,7 @@ func (f *lightFetcher) checkSyncedHeaders(p *peer) {
}
// now n is the latest downloaded header after syncing
if n == nil {
- glog.V(logger.Debug).Infof("synchronisation failed with peer %v", p.id)
+ p.Log().Debug("Synchronisation failed")
go f.pm.removePeer(p.id)
} else {
header := f.chain.GetHeader(n.hash, n.number)
@@ -610,12 +643,12 @@ func (f *lightFetcher) checkKnownNode(p *peer, n *fetcherTreeNode) bool {
fp := f.peers[p]
if fp == nil {
- glog.V(logger.Debug).Infof("checkKnownNode: unknown peer")
+ p.Log().Debug("Unknown peer to check known nodes")
return false
}
header := f.chain.GetHeader(n.hash, n.number)
if !f.checkAnnouncedHeaders(fp, []*types.Header{header}, []*big.Int{td}) {
- glog.V(logger.Debug).Infof("announce inconsistency by peer %v", p.id)
+ p.Log().Debug("Inconsistent announcement")
go f.pm.removePeer(p.id)
}
if fp.confirmedTd != nil {
@@ -700,7 +733,7 @@ func (f *lightFetcher) checkUpdateStats(p *peer, newEntry *updateStatsEntry) {
now := mclock.Now()
fp := f.peers[p]
if fp == nil {
- glog.V(logger.Debug).Infof("checkUpdateStats: unknown peer")
+ p.Log().Debug("Unknown peer to check update stats")
return
}
if newEntry != nil && fp.firstUpdateStats == nil {
diff --git a/les/flowcontrol/control.go b/les/flowcontrol/control.go
index e45537cf5e..e40e693464 100644
--- a/les/flowcontrol/control.go
+++ b/les/flowcontrol/control.go
@@ -94,14 +94,12 @@ func (peer *ClientNode) RequestProcessed(cost uint64) (bv, realCost uint64) {
}
type ServerNode struct {
- bufEstimate uint64
- lastTime mclock.AbsTime
- params *ServerParams
- sumCost uint64 // sum of req costs sent to this server
- pending map[uint64]uint64 // value = sumCost after sending the given req
- assignedRequest uint64 // when != 0, only the request with the given ID can be sent to this peer
- assignToken chan struct{} // send to this channel before assigning, read from it after deassigning
- lock sync.RWMutex
+ bufEstimate uint64
+ lastTime mclock.AbsTime
+ params *ServerParams
+ sumCost uint64 // sum of req costs sent to this server
+ pending map[uint64]uint64 // value = sumCost after sending the given req
+ lock sync.RWMutex
}
func NewServerNode(params *ServerParams) *ServerNode {
@@ -110,7 +108,6 @@ func NewServerNode(params *ServerParams) *ServerNode {
lastTime: mclock.Now(),
params: params,
pending: make(map[uint64]uint64),
- assignToken: make(chan struct{}, 1),
}
}
@@ -127,94 +124,37 @@ func (peer *ServerNode) recalcBLE(time mclock.AbsTime) {
}
// safetyMargin is added to the flow control waiting time when estimated buffer value is low
-const safetyMargin = time.Millisecond * 200
+const safetyMargin = time.Millisecond
-func (peer *ServerNode) canSend(maxCost uint64) time.Duration {
+func (peer *ServerNode) canSend(maxCost uint64) (time.Duration, float64) {
+ peer.recalcBLE(mclock.Now())
maxCost += uint64(safetyMargin) * peer.params.MinRecharge / uint64(fcTimeConst)
if maxCost > peer.params.BufLimit {
maxCost = peer.params.BufLimit
}
if peer.bufEstimate >= maxCost {
- return 0
+ return 0, float64(peer.bufEstimate-maxCost) / float64(peer.params.BufLimit)
}
- return time.Duration((maxCost - peer.bufEstimate) * uint64(fcTimeConst) / peer.params.MinRecharge)
+ return time.Duration((maxCost - peer.bufEstimate) * uint64(fcTimeConst) / peer.params.MinRecharge), 0
}
// CanSend returns the minimum waiting time required before sending a request
-// with the given maximum estimated cost
-func (peer *ServerNode) CanSend(maxCost uint64) time.Duration {
+// with the given maximum estimated cost. Second return value is the relative
+// estimated buffer level after sending the request (divided by BufLimit).
+func (peer *ServerNode) CanSend(maxCost uint64) (time.Duration, float64) {
peer.lock.RLock()
defer peer.lock.RUnlock()
return peer.canSend(maxCost)
}
-// AssignRequest tries to assign the server node to the given request, guaranteeing
-// that once it returns true, no request will be sent to the node before this one
-func (peer *ServerNode) AssignRequest(reqID uint64) bool {
- select {
- case peer.assignToken <- struct{}{}:
- default:
- return false
- }
- peer.lock.Lock()
- peer.assignedRequest = reqID
- peer.lock.Unlock()
- return true
-}
-
-// MustAssignRequest waits until the node can be assigned to the given request.
-// It is always guaranteed that assignments are released in a short amount of time.
-func (peer *ServerNode) MustAssignRequest(reqID uint64) {
- peer.assignToken <- struct{}{}
- peer.lock.Lock()
- peer.assignedRequest = reqID
- peer.lock.Unlock()
-}
-
-// DeassignRequest releases a request assignment in case the planned request
-// is not being sent.
-func (peer *ServerNode) DeassignRequest(reqID uint64) {
- peer.lock.Lock()
- if peer.assignedRequest == reqID {
- peer.assignedRequest = 0
- <-peer.assignToken
- }
- peer.lock.Unlock()
-}
-
-// IsAssigned returns true if the server node has already been assigned to a request
-// (note that this function returning false does not guarantee that you can assign a request
-// immediately afterwards, its only purpose is to help peer selection)
-func (peer *ServerNode) IsAssigned() bool {
- peer.lock.RLock()
- locked := peer.assignedRequest != 0
- peer.lock.RUnlock()
- return locked
-}
-
-// blocks until request can be sent
-func (peer *ServerNode) SendRequest(reqID, maxCost uint64) {
+// QueueRequest should be called when the request has been assigned to the given
+// server node, before putting it in the send queue. It is mandatory that requests
+// are sent in the same order as the QueueRequest calls are made.
+func (peer *ServerNode) QueueRequest(reqID, maxCost uint64) {
peer.lock.Lock()
defer peer.lock.Unlock()
- if peer.assignedRequest != reqID {
- peer.lock.Unlock()
- peer.MustAssignRequest(reqID)
- peer.lock.Lock()
- }
-
- peer.recalcBLE(mclock.Now())
- wait := peer.canSend(maxCost)
- for wait > 0 {
- peer.lock.Unlock()
- time.Sleep(wait)
- peer.lock.Lock()
- peer.recalcBLE(mclock.Now())
- wait = peer.canSend(maxCost)
- }
- peer.assignedRequest = 0
- <-peer.assignToken
peer.bufEstimate -= maxCost
peer.sumCost += maxCost
if reqID >= 0 {
@@ -222,6 +162,8 @@ func (peer *ServerNode) SendRequest(reqID, maxCost uint64) {
}
}
+// GotReply adjusts estimated buffer value according to the value included in
+// the latest request reply.
func (peer *ServerNode) GotReply(reqID, bv uint64) {
peer.lock.Lock()
@@ -235,6 +177,10 @@ func (peer *ServerNode) GotReply(reqID, bv uint64) {
return
}
delete(peer.pending, reqID)
- peer.bufEstimate = bv - (peer.sumCost - sc)
+ cc := peer.sumCost - sc
+ peer.bufEstimate = 0
+ if bv > cc {
+ peer.bufEstimate = bv - cc
+ }
peer.lastTime = mclock.Now()
}
diff --git a/les/handler.go b/les/handler.go
index 42a45845d0..ece2060ee8 100644
--- a/les/handler.go
+++ b/les/handler.go
@@ -34,8 +34,7 @@ import (
"github.com/ethereum/go-ethereum/eth/downloader"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/p2p/discover"
"github.com/ethereum/go-ethereum/p2p/discv5"
@@ -103,6 +102,7 @@ type ProtocolManager struct {
odr *LesOdr
server *LesServer
serverPool *serverPool
+ reqDist *requestDistributor
downloader *downloader.Downloader
fetcher *lightFetcher
@@ -199,14 +199,22 @@ func NewProtocolManager(chainConfig *params.ChainConfig, lightSync bool, network
}
if lightSync {
- glog.V(logger.Debug).Infof("LES: create downloader")
manager.downloader = downloader.New(downloader.LightSync, chainDb, manager.eventMux, blockchain.HasHeader, nil, blockchain.GetHeaderByHash,
nil, blockchain.CurrentHeader, nil, nil, nil, blockchain.GetTdByHash,
blockchain.InsertHeaderChain, nil, nil, blockchain.Rollback, removePeer)
}
+ manager.reqDist = newRequestDistributor(func() map[distPeer]struct{} {
+ m := make(map[distPeer]struct{})
+ peers := manager.peers.AllPeers()
+ for _, peer := range peers {
+ m[peer] = struct{}{}
+ }
+ return m
+ }, manager.quitSync)
if odr != nil {
odr.removePeer = removePeer
+ odr.reqDist = manager.reqDist
}
/*validator := func(block *types.Block, parent *types.Block) error {
@@ -226,16 +234,13 @@ func (pm *ProtocolManager) removePeer(id string) {
if peer == nil {
return
}
+ log.Debug("Removing light Ethereum peer", "peer", id)
if err := pm.peers.Unregister(id); err != nil {
if err == errNotRegistered {
return
}
- glog.V(logger.Error).Infoln("Removal failed:", err)
}
- glog.V(logger.Debug).Infoln("Removing peer", id)
-
// Unregister the peer from the downloader and Ethereum peer set
- glog.V(logger.Debug).Infof("LES: unregister peer %v", id)
if pm.lightSync {
pm.downloader.UnregisterPeer(id)
if pm.txrelay != nil {
@@ -268,9 +273,11 @@ func (pm *ProtocolManager) Start(srvr *p2p.Server) {
} else {
if topicDisc != nil {
go func() {
- glog.V(logger.Info).Infoln("Starting registering topic", string(lesTopic))
+ logger := log.New("topic", lesTopic)
+ logger.Info("Starting topic registration")
+ defer logger.Info("Terminated topic registration")
+
topicDisc.RegisterTopic(lesTopic, pm.quitSync)
- glog.V(logger.Info).Infoln("Stopped registering topic", string(lesTopic))
}()
}
go func() {
@@ -283,7 +290,7 @@ func (pm *ProtocolManager) Start(srvr *p2p.Server) {
func (pm *ProtocolManager) Stop() {
// Showing a log message. During download / process this could actually
// take between 5 to 10 seconds and therefor feedback is required.
- glog.V(logger.Info).Infoln("Stopping light ethereum protocol handler...")
+ log.Info("Stopping light Ethereum protocol")
// Quit the sync loop.
// After this send has completed, no new peers will be accepted.
@@ -300,7 +307,7 @@ func (pm *ProtocolManager) Stop() {
// Wait for any process action
pm.wg.Wait()
- glog.V(logger.Info).Infoln("Light ethereum protocol handler stopped")
+ log.Info("Light Ethereum protocol stopped")
}
func (pm *ProtocolManager) newPeer(pv, nv int, p *p2p.Peer, rw p2p.MsgReadWriter) *peer {
@@ -310,22 +317,21 @@ func (pm *ProtocolManager) newPeer(pv, nv int, p *p2p.Peer, rw p2p.MsgReadWriter
// handle is the callback invoked to manage the life cycle of a les peer. When
// this function terminates, the peer is disconnected.
func (pm *ProtocolManager) handle(p *peer) error {
- glog.V(logger.Debug).Infof("%v: peer connected [%s]", p, p.Name())
+ p.Log().Debug("Light Ethereum peer connected", "name", p.Name())
// Execute the LES handshake
td, head, genesis := pm.blockchain.Status()
headNum := core.GetBlockNumber(pm.chainDb, head)
if err := p.Handshake(td, head, headNum, genesis, pm.server); err != nil {
- glog.V(logger.Debug).Infof("%v: handshake failed: %v", p, err)
+ p.Log().Debug("Light Ethereum handshake failed", "err", err)
return err
}
if rw, ok := p.rw.(*meteredMsgReadWriter); ok {
rw.Init(p.version)
}
// Register the peer locally
- glog.V(logger.Detail).Infof("%v: adding peer", p)
if err := pm.peers.Register(p); err != nil {
- glog.V(logger.Error).Infof("%v: addition failed: %v", p, err)
+ p.Log().Error("Light Ethereum peer registration failed", "err", err)
return err
}
defer func() {
@@ -334,23 +340,53 @@ func (pm *ProtocolManager) handle(p *peer) error {
}
pm.removePeer(p.id)
}()
-
// Register the peer in the downloader. If the downloader considers it banned, we disconnect
- glog.V(logger.Debug).Infof("LES: register peer %v", p.id)
if pm.lightSync {
requestHeadersByHash := func(origin common.Hash, amount int, skip int, reverse bool) error {
reqID := getNextReqID()
- cost := p.GetRequestCost(GetBlockHeadersMsg, amount)
- p.fcServer.MustAssignRequest(reqID)
- p.fcServer.SendRequest(reqID, cost)
- return p.RequestHeadersByHash(reqID, cost, origin, amount, skip, reverse)
+ rq := &distReq{
+ getCost: func(dp distPeer) uint64 {
+ peer := dp.(*peer)
+ return peer.GetRequestCost(GetBlockHeadersMsg, amount)
+ },
+ canSend: func(dp distPeer) bool {
+ return dp.(*peer) == p
+ },
+ request: func(dp distPeer) func() {
+ peer := dp.(*peer)
+ cost := peer.GetRequestCost(GetBlockHeadersMsg, amount)
+ peer.fcServer.QueueRequest(reqID, cost)
+ return func() { peer.RequestHeadersByHash(reqID, cost, origin, amount, skip, reverse) }
+ },
+ }
+ _, ok := <-pm.reqDist.queue(rq)
+ if !ok {
+ return ErrNoPeers
+ }
+ return nil
}
requestHeadersByNumber := func(origin uint64, amount int, skip int, reverse bool) error {
reqID := getNextReqID()
- cost := p.GetRequestCost(GetBlockHeadersMsg, amount)
- p.fcServer.MustAssignRequest(reqID)
- p.fcServer.SendRequest(reqID, cost)
- return p.RequestHeadersByNumber(reqID, cost, origin, amount, skip, reverse)
+ rq := &distReq{
+ getCost: func(dp distPeer) uint64 {
+ peer := dp.(*peer)
+ return peer.GetRequestCost(GetBlockHeadersMsg, amount)
+ },
+ canSend: func(dp distPeer) bool {
+ return dp.(*peer) == p
+ },
+ request: func(dp distPeer) func() {
+ peer := dp.(*peer)
+ cost := peer.GetRequestCost(GetBlockHeadersMsg, amount)
+ peer.fcServer.QueueRequest(reqID, cost)
+ return func() { peer.RequestHeadersByNumber(reqID, cost, origin, amount, skip, reverse) }
+ },
+ }
+ _, ok := <-pm.reqDist.queue(rq)
+ if !ok {
+ return ErrNoPeers
+ }
+ return nil
}
if err := pm.downloader.RegisterPeer(p.id, ethVersion, p.HeadAndTd,
requestHeadersByHash, requestHeadersByNumber, nil, nil, nil); err != nil {
@@ -390,7 +426,7 @@ func (pm *ProtocolManager) handle(p *peer) error {
// main loop. handle incoming messages.
for {
if err := pm.handleMsg(p); err != nil {
- glog.V(logger.Debug).Infof("%v: message handling failed: %v", p, err)
+ p.Log().Debug("Light Ethereum message handling failed", "err", err)
return err
}
}
@@ -406,8 +442,7 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
if err != nil {
return err
}
-
- glog.V(logger.Debug).Infoln("msg:", msg.Code, msg.Size)
+ p.Log().Trace("Light Ethereum message arrived", "code", msg.Code, "bytes", msg.Size)
costs := p.fcCosts[msg.Code]
reject := func(reqCnt, maxCnt uint64) bool {
@@ -420,7 +455,8 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
cost = pm.server.defParams.BufLimit
}
if cost > bufValue {
- glog.V(logger.Error).Infof("Request from %v came %v too early", p.id, time.Duration((cost-bufValue)*1000000/pm.server.defParams.MinRecharge))
+ recharge := time.Duration((cost - bufValue) * 1000000 / pm.server.defParams.MinRecharge)
+ p.Log().Error("Request came too early", "recharge", common.PrettyDuration(recharge))
return true
}
return false
@@ -436,25 +472,25 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
// Handle the message depending on its contents
switch msg.Code {
case StatusMsg:
- glog.V(logger.Debug).Infof("<=== StatusMsg from peer %v", p.id)
+ p.Log().Trace("Received status message")
// Status messages should never arrive after the handshake
return errResp(ErrExtraStatusMsg, "uncontrolled status message")
// Block header query, collect the requested headers and reply
case AnnounceMsg:
- glog.V(logger.Debug).Infoln("<=== AnnounceMsg from peer %v:", p.id)
+ p.Log().Trace("Received announce message")
var req announceData
if err := msg.Decode(&req); err != nil {
return errResp(ErrDecode, "%v: %v", msg, err)
}
- glog.V(logger.Detail).Infoln("AnnounceMsg:", req.Number, req.Hash, req.Td, req.ReorgDepth)
+ p.Log().Trace("Announce message content", "number", req.Number, "hash", req.Hash, "td", req.Td, "reorg", req.ReorgDepth)
if pm.fetcher != nil {
pm.fetcher.announce(p, &req)
}
case GetBlockHeadersMsg:
- glog.V(logger.Debug).Infof("<=== GetBlockHeadersMsg from peer %v", p.id)
+ p.Log().Trace("Received block header request")
// Decode the complex header query
var req struct {
ReqID uint64
@@ -539,7 +575,7 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
return errResp(ErrUnexpectedResponse, "")
}
- glog.V(logger.Debug).Infof("<=== BlockHeadersMsg from peer %v", p.id)
+ p.Log().Trace("Received block header response message")
// A batch of headers arrived to one of our previous requests
var resp struct {
ReqID, BV uint64
@@ -554,12 +590,12 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
} else {
err := pm.downloader.DeliverHeaders(p.id, resp.Headers)
if err != nil {
- glog.V(logger.Debug).Infoln(err)
+ log.Debug(fmt.Sprint(err))
}
}
case GetBlockBodiesMsg:
- glog.V(logger.Debug).Infof("<=== GetBlockBodiesMsg from peer %v", p.id)
+ p.Log().Trace("Received block bodies request")
// Decode the retrieval message
var req struct {
ReqID uint64
@@ -596,7 +632,7 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
return errResp(ErrUnexpectedResponse, "")
}
- glog.V(logger.Debug).Infof("<=== BlockBodiesMsg from peer %v", p.id)
+ p.Log().Trace("Received block bodies response")
// A batch of block bodies arrived to one of our previous requests
var resp struct {
ReqID, BV uint64
@@ -613,7 +649,7 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
}
case GetCodeMsg:
- glog.V(logger.Debug).Infof("<=== GetCodeMsg from peer %v", p.id)
+ p.Log().Trace("Received code request")
// Decode the retrieval message
var req struct {
ReqID uint64
@@ -657,7 +693,7 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
return errResp(ErrUnexpectedResponse, "")
}
- glog.V(logger.Debug).Infof("<=== CodeMsg from peer %v", p.id)
+ p.Log().Trace("Received code response")
// A batch of node state data arrived to one of our previous requests
var resp struct {
ReqID, BV uint64
@@ -674,7 +710,7 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
}
case GetReceiptsMsg:
- glog.V(logger.Debug).Infof("<=== GetReceiptsMsg from peer %v", p.id)
+ p.Log().Trace("Received receipts request")
// Decode the retrieval message
var req struct {
ReqID uint64
@@ -705,7 +741,7 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
}
// If known, encode and queue for response packet
if encoded, err := rlp.EncodeToBytes(results); err != nil {
- glog.V(logger.Error).Infof("failed to encode receipt: %v", err)
+ log.Error("Failed to encode receipt", "err", err)
} else {
receipts = append(receipts, encoded)
bytes += len(encoded)
@@ -720,7 +756,7 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
return errResp(ErrUnexpectedResponse, "")
}
- glog.V(logger.Debug).Infof("<=== ReceiptsMsg from peer %v", p.id)
+ p.Log().Trace("Received receipts response")
// A batch of receipts arrived to one of our previous requests
var resp struct {
ReqID, BV uint64
@@ -737,7 +773,7 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
}
case GetProofsMsg:
- glog.V(logger.Debug).Infof("<=== GetProofsMsg from peer %v", p.id)
+ p.Log().Trace("Received proofs request")
// Decode the retrieval message
var req struct {
ReqID uint64
@@ -787,7 +823,7 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
return errResp(ErrUnexpectedResponse, "")
}
- glog.V(logger.Debug).Infof("<=== ProofsMsg from peer %v", p.id)
+ p.Log().Trace("Received proofs response")
// A batch of merkle proofs arrived to one of our previous requests
var resp struct {
ReqID, BV uint64
@@ -804,7 +840,7 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
}
case GetHeaderProofsMsg:
- glog.V(logger.Debug).Infof("<=== GetHeaderProofsMsg from peer %v", p.id)
+ p.Log().Trace("Received headers proof request")
// Decode the retrieval message
var req struct {
ReqID uint64
@@ -848,7 +884,7 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
return errResp(ErrUnexpectedResponse, "")
}
- glog.V(logger.Debug).Infof("<=== HeaderProofsMsg from peer %v", p.id)
+ p.Log().Trace("Received headers proof response")
var resp struct {
ReqID, BV uint64
Data []ChtResp
@@ -885,14 +921,19 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
pm.server.fcCostStats.update(msg.Code, uint64(reqCnt), rcost)
default:
- glog.V(logger.Debug).Infof("<=== unknown message with code %d from peer %v", msg.Code, p.id)
+ p.Log().Trace("Received unknown message", "code", msg.Code)
return errResp(ErrInvalidMsgCode, "%v", msg.Code)
}
if deliverMsg != nil {
- return pm.odr.Deliver(p, deliverMsg)
+ err := pm.odr.Deliver(p, deliverMsg)
+ if err != nil {
+ p.responseErrors++
+ if p.responseErrors > maxResponseErrors {
+ return err
+ }
+ }
}
-
return nil
}
diff --git a/les/helper_test.go b/les/helper_test.go
index e0b7558eeb..f37bec80e1 100644
--- a/les/helper_test.go
+++ b/les/helper_test.go
@@ -39,6 +39,7 @@ import (
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/p2p/discover"
"github.com/ethereum/go-ethereum/params"
+ "github.com/ethereum/go-ethereum/pow"
)
var (
@@ -57,6 +58,8 @@ var (
testContractDeployed = uint64(2)
testBufLimit = uint64(100)
+
+ bigTxGas = new(big.Int).SetUint64(params.TxGas)
)
/*
@@ -80,15 +83,15 @@ func testChainGen(i int, block *core.BlockGen) {
switch i {
case 0:
// In block 1, the test bank sends account #1 some ether.
- tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil), signer, testBankKey)
+ tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(10000), bigTxGas, nil, nil), signer, testBankKey)
block.AddTx(tx)
case 1:
// In block 2, the test bank sends some more ether to account #1.
// acc1Addr passes it on to account #2.
// acc1Addr creates a test contract.
- tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, testBankKey)
+ tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(1000), bigTxGas, nil, nil), signer, testBankKey)
nonce := block.TxNonce(acc1Addr)
- tx2, _ := types.SignTx(types.NewTransaction(nonce, acc2Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, acc1Key)
+ tx2, _ := types.SignTx(types.NewTransaction(nonce, acc2Addr, big.NewInt(1000), bigTxGas, nil, nil), signer, acc1Key)
nonce++
tx3, _ := types.SignTx(types.NewContractCreation(nonce, big.NewInt(0), big.NewInt(200000), big.NewInt(0), testContractCode), signer, acc1Key)
testContractAddr = crypto.CreateAddress(acc1Addr, nonce)
@@ -131,28 +134,31 @@ func testRCL() RequestCostList {
// channels for different events.
func newTestProtocolManager(lightSync bool, blocks int, generator func(int, *core.BlockGen)) (*ProtocolManager, ethdb.Database, *LesOdr, error) {
var (
- evmux = new(event.TypeMux)
- pow = new(core.FakePow)
- db, _ = ethdb.NewMemDatabase()
- genesis = core.WriteGenesisBlockForTesting(db, core.GenesisAccount{Address: testBankAddress, Balance: testBankFunds})
- chainConfig = ¶ms.ChainConfig{HomesteadBlock: big.NewInt(0)} // homestead set to 0 because of chain maker
- odr *LesOdr
- chain BlockChain
+ evmux = new(event.TypeMux)
+ pow = new(pow.FakePow)
+ db, _ = ethdb.NewMemDatabase()
+ gspec = core.Genesis{
+ Config: params.TestChainConfig,
+ Alloc: core.GenesisAlloc{testBankAddress: {Balance: testBankFunds}},
+ }
+ genesis = gspec.MustCommit(db)
+ odr *LesOdr
+ chain BlockChain
)
if lightSync {
odr = NewLesOdr(db)
- chain, _ = light.NewLightChain(odr, chainConfig, pow, evmux)
+ chain, _ = light.NewLightChain(odr, gspec.Config, pow, evmux)
} else {
- blockchain, _ := core.NewBlockChain(db, chainConfig, pow, evmux, vm.Config{})
- gchain, _ := core.GenerateChain(chainConfig, genesis, db, blocks, generator)
+ blockchain, _ := core.NewBlockChain(db, gspec.Config, pow, evmux, vm.Config{})
+ gchain, _ := core.GenerateChain(gspec.Config, genesis, db, blocks, generator)
if _, err := blockchain.InsertChain(gchain); err != nil {
panic(err)
}
chain = blockchain
}
- pm, err := NewProtocolManager(chainConfig, lightSync, NetworkId, evmux, pow, chain, nil, db, odr, nil)
+ pm, err := NewProtocolManager(gspec.Config, lightSync, NetworkId, evmux, pow, chain, nil, db, odr, nil)
if err != nil {
return nil, nil, nil, err
}
@@ -349,11 +355,15 @@ func (p *testServerPool) setPeer(peer *peer) {
p.peer = peer
}
-func (p *testServerPool) selectPeerWait(uint64, func(*peer) (bool, time.Duration), <-chan struct{}) *peer {
+func (p *testServerPool) getAllPeers() map[distPeer]struct{} {
p.lock.RLock()
defer p.lock.RUnlock()
- return p.peer
+ m := make(map[distPeer]struct{})
+ if p.peer != nil {
+ m[p.peer] = struct{}{}
+ }
+ return m
}
func (p *testServerPool) adjustResponseTime(*poolEntry, time.Duration, bool) {
diff --git a/les/odr.go b/les/odr.go
index 88c7d85a59..684f36c761 100644
--- a/les/odr.go
+++ b/les/odr.go
@@ -17,6 +17,7 @@
package les
import (
+ "context"
"crypto/rand"
"encoding/binary"
"sync"
@@ -25,22 +26,18 @@ import (
"github.com/ethereum/go-ethereum/common/mclock"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/light"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
- "golang.org/x/net/context"
+ "github.com/ethereum/go-ethereum/log"
)
var (
softRequestTimeout = time.Millisecond * 500
hardRequestTimeout = time.Second * 10
- retryPeers = time.Second * 1
)
// peerDropFn is a callback type for dropping a peer detected as malicious.
type peerDropFn func(id string)
type odrPeerSelector interface {
- selectPeerWait(uint64, func(*peer) (bool, time.Duration), <-chan struct{}) *peer
adjustResponseTime(*poolEntry, time.Duration, bool)
}
@@ -52,6 +49,7 @@ type LesOdr struct {
mlock, clock sync.Mutex
sentReqs map[uint64]*sentReq
serverPool odrPeerSelector
+ reqDist *requestDistributor
}
func NewLesOdr(db ethdb.Database) *LesOdr {
@@ -70,9 +68,8 @@ func (odr *LesOdr) Database() ethdb.Database {
return odr.db
}
-// validatorFunc is a function that processes a message and returns true if
-// it was a meaningful answer to a given request
-type validatorFunc func(ethdb.Database, *Msg) bool
+// validatorFunc is a function that processes a message.
+type validatorFunc func(ethdb.Database, *Msg) error
// sentReq is a request waiting for an answer that satisfies its valFunc
type sentReq struct {
@@ -113,18 +110,19 @@ func (self *LesOdr) Deliver(peer *peer, msg *Msg) error {
return errResp(ErrUnexpectedResponse, "reqID = %v", msg.ReqID)
}
- if req.valFunc(self.db, msg) {
- close(delivered)
- req.lock.Lock()
- delete(req.sentTo, peer)
- if req.answered != nil {
- close(req.answered)
- req.answered = nil
- }
- req.lock.Unlock()
- return nil
+ if err := req.valFunc(self.db, msg); err != nil {
+ peer.Log().Warn("Invalid odr response", "err", err)
+ return errResp(ErrInvalidResponse, "reqID = %v", msg.ReqID)
}
- return errResp(ErrInvalidResponse, "reqID = %v", msg.ReqID)
+ close(delivered)
+ req.lock.Lock()
+ delete(req.sentTo, peer)
+ if req.answered != nil {
+ close(req.answered)
+ req.answered = nil
+ }
+ req.lock.Unlock()
+ return nil
}
func (self *LesOdr) requestPeer(req *sentReq, peer *peer, delivered, timeout chan struct{}, reqWg *sync.WaitGroup) {
@@ -151,7 +149,7 @@ func (self *LesOdr) requestPeer(req *sentReq, peer *peer, delivered, timeout cha
select {
case <-delivered:
case <-time.After(hardRequestTimeout):
- glog.V(logger.Debug).Infof("ODR hard request timeout from peer %v", peer.id)
+ peer.Log().Debug("Request timed out hard")
go self.removePeer(peer.id)
case <-self.stop:
return
@@ -166,18 +164,48 @@ func (self *LesOdr) requestPeer(req *sentReq, peer *peer, delivered, timeout cha
func (self *LesOdr) networkRequest(ctx context.Context, lreq LesOdrRequest) error {
answered := make(chan struct{})
req := &sentReq{
- valFunc: lreq.Valid,
+ valFunc: lreq.Validate,
sentTo: make(map[*peer]chan struct{}),
answered: answered, // reply delivered by any peer
}
- reqID := getNextReqID()
- self.mlock.Lock()
- self.sentReqs[reqID] = req
- self.mlock.Unlock()
+
+ exclude := make(map[*peer]struct{})
reqWg := new(sync.WaitGroup)
reqWg.Add(1)
defer reqWg.Done()
+
+ var timeout chan struct{}
+ reqID := getNextReqID()
+ rq := &distReq{
+ getCost: func(dp distPeer) uint64 {
+ return lreq.GetCost(dp.(*peer))
+ },
+ canSend: func(dp distPeer) bool {
+ p := dp.(*peer)
+ _, ok := exclude[p]
+ return !ok && lreq.CanSend(p)
+ },
+ request: func(dp distPeer) func() {
+ p := dp.(*peer)
+ exclude[p] = struct{}{}
+ delivered := make(chan struct{})
+ timeout = make(chan struct{})
+ req.lock.Lock()
+ req.sentTo[p] = delivered
+ req.lock.Unlock()
+ reqWg.Add(1)
+ cost := lreq.GetCost(p)
+ p.fcServer.QueueRequest(reqID, cost)
+ go self.requestPeer(req, p, delivered, timeout, reqWg)
+ return func() { lreq.Request(reqID, p) }
+ },
+ }
+
+ self.mlock.Lock()
+ self.sentReqs[reqID] = req
+ self.mlock.Unlock()
+
go func() {
reqWg.Wait()
self.mlock.Lock()
@@ -185,50 +213,32 @@ func (self *LesOdr) networkRequest(ctx context.Context, lreq LesOdrRequest) erro
self.mlock.Unlock()
}()
- exclude := make(map[*peer]struct{})
for {
- var p *peer
- if self.serverPool != nil {
- p = self.serverPool.selectPeerWait(reqID, func(p *peer) (bool, time.Duration) {
- if _, ok := exclude[p]; ok || !lreq.CanSend(p) {
- return false, 0
- }
- return true, p.fcServer.CanSend(lreq.GetCost(p))
- }, ctx.Done())
+ peerChn := self.reqDist.queue(rq)
+ select {
+ case <-ctx.Done():
+ self.reqDist.cancel(rq)
+ return ctx.Err()
+ case <-answered:
+ self.reqDist.cancel(rq)
+ return nil
+ case _, ok := <-peerChn:
+ if !ok {
+ return ErrNoPeers
+ }
}
- if p == nil {
- select {
- case <-ctx.Done():
- return ctx.Err()
- case <-req.answered:
- return nil
- case <-time.After(retryPeers):
- }
- } else {
- exclude[p] = struct{}{}
- delivered := make(chan struct{})
- timeout := make(chan struct{})
- req.lock.Lock()
- req.sentTo[p] = delivered
- req.lock.Unlock()
- reqWg.Add(1)
- cost := lreq.GetCost(p)
- p.fcServer.SendRequest(reqID, cost)
- go self.requestPeer(req, p, delivered, timeout, reqWg)
- lreq.Request(reqID, p)
- select {
- case <-ctx.Done():
- return ctx.Err()
- case <-answered:
- return nil
- case <-timeout:
- }
+ select {
+ case <-ctx.Done():
+ return ctx.Err()
+ case <-answered:
+ return nil
+ case <-timeout:
}
}
}
-// Retrieve tries to fetch an object from the local db, then from the LES network.
+// Retrieve tries to fetch an object from the LES network.
// If the network retrieval was successful, it stores the object in local db.
func (self *LesOdr) Retrieve(ctx context.Context, req light.OdrRequest) (err error) {
lreq := LesRequest(req)
@@ -237,7 +247,7 @@ func (self *LesOdr) Retrieve(ctx context.Context, req light.OdrRequest) (err err
// retrieved from network, store in db
req.StoreResult(self.db)
} else {
- glog.V(logger.Debug).Infof("networkRequest err = %v", err)
+ log.Debug("Failed to retrieve data from network", "err", err)
}
return
}
diff --git a/les/odr_requests.go b/les/odr_requests.go
index 2987eb297a..1f853b3417 100644
--- a/les/odr_requests.go
+++ b/les/odr_requests.go
@@ -19,8 +19,9 @@
package les
import (
- "bytes"
"encoding/binary"
+ "errors"
+ "fmt"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
@@ -28,17 +29,27 @@ import (
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/light"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/trie"
)
+var (
+ errInvalidMessageType = errors.New("invalid message type")
+ errMultipleEntries = errors.New("multiple response entries")
+ errHeaderUnavailable = errors.New("header unavailable")
+ errTxHashMismatch = errors.New("transaction hash mismatch")
+ errUncleHashMismatch = errors.New("uncle hash mismatch")
+ errReceiptHashMismatch = errors.New("receipt hash mismatch")
+ errDataHashMismatch = errors.New("data hash mismatch")
+ errCHTHashMismatch = errors.New("cht hash mismatch")
+)
+
type LesOdrRequest interface {
GetCost(*peer) uint64
CanSend(*peer) bool
Request(uint64, *peer) error
- Valid(ethdb.Database, *Msg) bool // if true, keeps the retrieved object
+ Validate(ethdb.Database, *Msg) error
}
func LesRequest(req light.OdrRequest) LesOdrRequest {
@@ -63,59 +74,55 @@ type BlockRequest light.BlockRequest
// GetCost returns the cost of the given ODR request according to the serving
// peer's cost table (implementation of LesOdrRequest)
-func (self *BlockRequest) GetCost(peer *peer) uint64 {
+func (r *BlockRequest) GetCost(peer *peer) uint64 {
return peer.GetRequestCost(GetBlockBodiesMsg, 1)
}
// CanSend tells if a certain peer is suitable for serving the given request
-func (self *BlockRequest) CanSend(peer *peer) bool {
- return peer.HasBlock(self.Hash, self.Number)
+func (r *BlockRequest) CanSend(peer *peer) bool {
+ return peer.HasBlock(r.Hash, r.Number)
}
// Request sends an ODR request to the LES network (implementation of LesOdrRequest)
-func (self *BlockRequest) Request(reqID uint64, peer *peer) error {
- glog.V(logger.Debug).Infof("ODR: requesting body of block %08x from peer %v", self.Hash[:4], peer.id)
- return peer.RequestBodies(reqID, self.GetCost(peer), []common.Hash{self.Hash})
+func (r *BlockRequest) Request(reqID uint64, peer *peer) error {
+ peer.Log().Debug("Requesting block body", "hash", r.Hash)
+ return peer.RequestBodies(reqID, r.GetCost(peer), []common.Hash{r.Hash})
}
// Valid processes an ODR request reply message from the LES network
// returns true and stores results in memory if the message was a valid reply
// to the request (implementation of LesOdrRequest)
-func (self *BlockRequest) Valid(db ethdb.Database, msg *Msg) bool {
- glog.V(logger.Debug).Infof("ODR: validating body of block %08x", self.Hash[:4])
+func (r *BlockRequest) Validate(db ethdb.Database, msg *Msg) error {
+ log.Debug("Validating block body", "hash", r.Hash)
+
+ // Ensure we have a correct message with a single block body
if msg.MsgType != MsgBlockBodies {
- glog.V(logger.Debug).Infof("ODR: invalid message type")
- return false
+ return errInvalidMessageType
}
bodies := msg.Obj.([]*types.Body)
if len(bodies) != 1 {
- glog.V(logger.Debug).Infof("ODR: invalid number of entries: %d", len(bodies))
- return false
+ return errMultipleEntries
}
body := bodies[0]
- header := core.GetHeader(db, self.Hash, self.Number)
+
+ // Retrieve our stored header and validate block content against it
+ header := core.GetHeader(db, r.Hash, r.Number)
if header == nil {
- glog.V(logger.Debug).Infof("ODR: header not found for block %08x", self.Hash[:4])
- return false
+ return errHeaderUnavailable
}
- txHash := types.DeriveSha(types.Transactions(body.Transactions))
- if header.TxHash != txHash {
- glog.V(logger.Debug).Infof("ODR: header.TxHash %08x does not match received txHash %08x", header.TxHash[:4], txHash[:4])
- return false
+ if header.TxHash != types.DeriveSha(types.Transactions(body.Transactions)) {
+ return errTxHashMismatch
}
- uncleHash := types.CalcUncleHash(body.Uncles)
- if header.UncleHash != uncleHash {
- glog.V(logger.Debug).Infof("ODR: header.UncleHash %08x does not match received uncleHash %08x", header.UncleHash[:4], uncleHash[:4])
- return false
+ if header.UncleHash != types.CalcUncleHash(body.Uncles) {
+ return errUncleHashMismatch
}
+ // Validations passed, encode and store RLP
data, err := rlp.EncodeToBytes(body)
if err != nil {
- glog.V(logger.Debug).Infof("ODR: body RLP encode error: %v", err)
- return false
+ return err
}
- self.Rlp = data
- glog.V(logger.Debug).Infof("ODR: validation successful")
- return true
+ r.Rlp = data
+ return nil
}
// ReceiptsRequest is the ODR request type for block receipts by block hash
@@ -123,48 +130,48 @@ type ReceiptsRequest light.ReceiptsRequest
// GetCost returns the cost of the given ODR request according to the serving
// peer's cost table (implementation of LesOdrRequest)
-func (self *ReceiptsRequest) GetCost(peer *peer) uint64 {
+func (r *ReceiptsRequest) GetCost(peer *peer) uint64 {
return peer.GetRequestCost(GetReceiptsMsg, 1)
}
// CanSend tells if a certain peer is suitable for serving the given request
-func (self *ReceiptsRequest) CanSend(peer *peer) bool {
- return peer.HasBlock(self.Hash, self.Number)
+func (r *ReceiptsRequest) CanSend(peer *peer) bool {
+ return peer.HasBlock(r.Hash, r.Number)
}
// Request sends an ODR request to the LES network (implementation of LesOdrRequest)
-func (self *ReceiptsRequest) Request(reqID uint64, peer *peer) error {
- glog.V(logger.Debug).Infof("ODR: requesting receipts for block %08x from peer %v", self.Hash[:4], peer.id)
- return peer.RequestReceipts(reqID, self.GetCost(peer), []common.Hash{self.Hash})
+func (r *ReceiptsRequest) Request(reqID uint64, peer *peer) error {
+ peer.Log().Debug("Requesting block receipts", "hash", r.Hash)
+ return peer.RequestReceipts(reqID, r.GetCost(peer), []common.Hash{r.Hash})
}
// Valid processes an ODR request reply message from the LES network
// returns true and stores results in memory if the message was a valid reply
// to the request (implementation of LesOdrRequest)
-func (self *ReceiptsRequest) Valid(db ethdb.Database, msg *Msg) bool {
- glog.V(logger.Debug).Infof("ODR: validating receipts for block %08x", self.Hash[:4])
+func (r *ReceiptsRequest) Validate(db ethdb.Database, msg *Msg) error {
+ log.Debug("Validating block receipts", "hash", r.Hash)
+
+ // Ensure we have a correct message with a single block receipt
if msg.MsgType != MsgReceipts {
- glog.V(logger.Debug).Infof("ODR: invalid message type")
- return false
+ return errInvalidMessageType
}
receipts := msg.Obj.([]types.Receipts)
if len(receipts) != 1 {
- glog.V(logger.Debug).Infof("ODR: invalid number of entries: %d", len(receipts))
- return false
+ return errMultipleEntries
}
- hash := types.DeriveSha(receipts[0])
- header := core.GetHeader(db, self.Hash, self.Number)
+ receipt := receipts[0]
+
+ // Retrieve our stored header and validate receipt content against it
+ header := core.GetHeader(db, r.Hash, r.Number)
if header == nil {
- glog.V(logger.Debug).Infof("ODR: header not found for block %08x", self.Hash[:4])
- return false
+ return errHeaderUnavailable
}
- if !bytes.Equal(header.ReceiptHash[:], hash[:]) {
- glog.V(logger.Debug).Infof("ODR: header receipts hash %08x does not match calculated RLP hash %08x", header.ReceiptHash[:4], hash[:4])
- return false
+ if header.ReceiptHash != types.DeriveSha(receipt) {
+ return errReceiptHashMismatch
}
- self.Receipts = receipts[0]
- glog.V(logger.Debug).Infof("ODR: validation successful")
- return true
+ // Validations passed, store and return
+ r.Receipts = receipt
+ return nil
}
type ProofReq struct {
@@ -178,49 +185,46 @@ type TrieRequest light.TrieRequest
// GetCost returns the cost of the given ODR request according to the serving
// peer's cost table (implementation of LesOdrRequest)
-func (self *TrieRequest) GetCost(peer *peer) uint64 {
+func (r *TrieRequest) GetCost(peer *peer) uint64 {
return peer.GetRequestCost(GetProofsMsg, 1)
}
// CanSend tells if a certain peer is suitable for serving the given request
-func (self *TrieRequest) CanSend(peer *peer) bool {
- return peer.HasBlock(self.Id.BlockHash, self.Id.BlockNumber)
+func (r *TrieRequest) CanSend(peer *peer) bool {
+ return peer.HasBlock(r.Id.BlockHash, r.Id.BlockNumber)
}
// Request sends an ODR request to the LES network (implementation of LesOdrRequest)
-func (self *TrieRequest) Request(reqID uint64, peer *peer) error {
- glog.V(logger.Debug).Infof("ODR: requesting trie root %08x key %08x from peer %v", self.Id.Root[:4], self.Key[:4], peer.id)
+func (r *TrieRequest) Request(reqID uint64, peer *peer) error {
+ peer.Log().Debug("Requesting trie proof", "root", r.Id.Root, "key", r.Key)
req := &ProofReq{
- BHash: self.Id.BlockHash,
- AccKey: self.Id.AccKey,
- Key: self.Key,
+ BHash: r.Id.BlockHash,
+ AccKey: r.Id.AccKey,
+ Key: r.Key,
}
- return peer.RequestProofs(reqID, self.GetCost(peer), []*ProofReq{req})
+ return peer.RequestProofs(reqID, r.GetCost(peer), []*ProofReq{req})
}
// Valid processes an ODR request reply message from the LES network
// returns true and stores results in memory if the message was a valid reply
// to the request (implementation of LesOdrRequest)
-func (self *TrieRequest) Valid(db ethdb.Database, msg *Msg) bool {
- glog.V(logger.Debug).Infof("ODR: validating trie root %08x key %08x", self.Id.Root[:4], self.Key[:4])
+func (r *TrieRequest) Validate(db ethdb.Database, msg *Msg) error {
+ log.Debug("Validating trie proof", "root", r.Id.Root, "key", r.Key)
+ // Ensure we have a correct message with a single proof
if msg.MsgType != MsgProofs {
- glog.V(logger.Debug).Infof("ODR: invalid message type")
- return false
+ return errInvalidMessageType
}
proofs := msg.Obj.([][]rlp.RawValue)
if len(proofs) != 1 {
- glog.V(logger.Debug).Infof("ODR: invalid number of entries: %d", len(proofs))
- return false
+ return errMultipleEntries
}
- _, err := trie.VerifyProof(self.Id.Root, self.Key, proofs[0])
- if err != nil {
- glog.V(logger.Debug).Infof("ODR: merkle proof verification error: %v", err)
- return false
+ // Verify the proof and store if checks out
+ if _, err := trie.VerifyProof(r.Id.Root, r.Key, proofs[0]); err != nil {
+ return fmt.Errorf("merkle proof verification failed: %v", err)
}
- self.Proof = proofs[0]
- glog.V(logger.Debug).Infof("ODR: validation successful")
- return true
+ r.Proof = proofs[0]
+ return nil
}
type CodeReq struct {
@@ -233,47 +237,47 @@ type CodeRequest light.CodeRequest
// GetCost returns the cost of the given ODR request according to the serving
// peer's cost table (implementation of LesOdrRequest)
-func (self *CodeRequest) GetCost(peer *peer) uint64 {
+func (r *CodeRequest) GetCost(peer *peer) uint64 {
return peer.GetRequestCost(GetCodeMsg, 1)
}
// CanSend tells if a certain peer is suitable for serving the given request
-func (self *CodeRequest) CanSend(peer *peer) bool {
- return peer.HasBlock(self.Id.BlockHash, self.Id.BlockNumber)
+func (r *CodeRequest) CanSend(peer *peer) bool {
+ return peer.HasBlock(r.Id.BlockHash, r.Id.BlockNumber)
}
// Request sends an ODR request to the LES network (implementation of LesOdrRequest)
-func (self *CodeRequest) Request(reqID uint64, peer *peer) error {
- glog.V(logger.Debug).Infof("ODR: requesting node data for hash %08x from peer %v", self.Hash[:4], peer.id)
+func (r *CodeRequest) Request(reqID uint64, peer *peer) error {
+ peer.Log().Debug("Requesting code data", "hash", r.Hash)
req := &CodeReq{
- BHash: self.Id.BlockHash,
- AccKey: self.Id.AccKey,
+ BHash: r.Id.BlockHash,
+ AccKey: r.Id.AccKey,
}
- return peer.RequestCode(reqID, self.GetCost(peer), []*CodeReq{req})
+ return peer.RequestCode(reqID, r.GetCost(peer), []*CodeReq{req})
}
// Valid processes an ODR request reply message from the LES network
// returns true and stores results in memory if the message was a valid reply
// to the request (implementation of LesOdrRequest)
-func (self *CodeRequest) Valid(db ethdb.Database, msg *Msg) bool {
- glog.V(logger.Debug).Infof("ODR: validating node data for hash %08x", self.Hash[:4])
+func (r *CodeRequest) Validate(db ethdb.Database, msg *Msg) error {
+ log.Debug("Validating code data", "hash", r.Hash)
+
+ // Ensure we have a correct message with a single code element
if msg.MsgType != MsgCode {
- glog.V(logger.Debug).Infof("ODR: invalid message type")
- return false
+ return errInvalidMessageType
}
reply := msg.Obj.([][]byte)
if len(reply) != 1 {
- glog.V(logger.Debug).Infof("ODR: invalid number of entries: %d", len(reply))
- return false
+ return errMultipleEntries
}
data := reply[0]
- if hash := crypto.Keccak256Hash(data); self.Hash != hash {
- glog.V(logger.Debug).Infof("ODR: requested hash %08x does not match received data hash %08x", self.Hash[:4], hash[:4])
- return false
+
+ // Verify the data and store if checks out
+ if hash := crypto.Keccak256Hash(data); r.Hash != hash {
+ return errDataHashMismatch
}
- self.Data = data
- glog.V(logger.Debug).Infof("ODR: validation successful")
- return true
+ r.Data = data
+ return nil
}
type ChtReq struct {
@@ -290,64 +294,63 @@ type ChtRequest light.ChtRequest
// GetCost returns the cost of the given ODR request according to the serving
// peer's cost table (implementation of LesOdrRequest)
-func (self *ChtRequest) GetCost(peer *peer) uint64 {
+func (r *ChtRequest) GetCost(peer *peer) uint64 {
return peer.GetRequestCost(GetHeaderProofsMsg, 1)
}
// CanSend tells if a certain peer is suitable for serving the given request
-func (self *ChtRequest) CanSend(peer *peer) bool {
+func (r *ChtRequest) CanSend(peer *peer) bool {
peer.lock.RLock()
defer peer.lock.RUnlock()
- return self.ChtNum <= (peer.headInfo.Number-light.ChtConfirmations)/light.ChtFrequency
+ return r.ChtNum <= (peer.headInfo.Number-light.ChtConfirmations)/light.ChtFrequency
}
// Request sends an ODR request to the LES network (implementation of LesOdrRequest)
-func (self *ChtRequest) Request(reqID uint64, peer *peer) error {
- glog.V(logger.Debug).Infof("ODR: requesting CHT #%d block #%d from peer %v", self.ChtNum, self.BlockNum, peer.id)
+func (r *ChtRequest) Request(reqID uint64, peer *peer) error {
+ peer.Log().Debug("Requesting CHT", "cht", r.ChtNum, "block", r.BlockNum)
req := &ChtReq{
- ChtNum: self.ChtNum,
- BlockNum: self.BlockNum,
+ ChtNum: r.ChtNum,
+ BlockNum: r.BlockNum,
}
- return peer.RequestHeaderProofs(reqID, self.GetCost(peer), []*ChtReq{req})
+ return peer.RequestHeaderProofs(reqID, r.GetCost(peer), []*ChtReq{req})
}
// Valid processes an ODR request reply message from the LES network
// returns true and stores results in memory if the message was a valid reply
// to the request (implementation of LesOdrRequest)
-func (self *ChtRequest) Valid(db ethdb.Database, msg *Msg) bool {
- glog.V(logger.Debug).Infof("ODR: validating CHT #%d block #%d", self.ChtNum, self.BlockNum)
+func (r *ChtRequest) Validate(db ethdb.Database, msg *Msg) error {
+ log.Debug("Validating CHT", "cht", r.ChtNum, "block", r.BlockNum)
+ // Ensure we have a correct message with a single proof element
if msg.MsgType != MsgHeaderProofs {
- glog.V(logger.Debug).Infof("ODR: invalid message type")
- return false
+ return errInvalidMessageType
}
proofs := msg.Obj.([]ChtResp)
if len(proofs) != 1 {
- glog.V(logger.Debug).Infof("ODR: invalid number of entries: %d", len(proofs))
- return false
+ return errMultipleEntries
}
proof := proofs[0]
+
+ // Verify the CHT
var encNumber [8]byte
- binary.BigEndian.PutUint64(encNumber[:], self.BlockNum)
- value, err := trie.VerifyProof(self.ChtRoot, encNumber[:], proof.Proof)
+ binary.BigEndian.PutUint64(encNumber[:], r.BlockNum)
+
+ value, err := trie.VerifyProof(r.ChtRoot, encNumber[:], proof.Proof)
if err != nil {
- glog.V(logger.Debug).Infof("ODR: CHT merkle proof verification error: %v", err)
- return false
+ return err
}
var node light.ChtNode
if err := rlp.DecodeBytes(value, &node); err != nil {
- glog.V(logger.Debug).Infof("ODR: error decoding CHT node: %v", err)
- return false
+ return err
}
if node.Hash != proof.Header.Hash() {
- glog.V(logger.Debug).Infof("ODR: CHT header hash does not match")
- return false
+ return errCHTHashMismatch
}
+ // Verifications passed, store and return
+ r.Header = proof.Header
+ r.Proof = proof.Proof
+ r.Td = node.Td
- self.Proof = proof.Proof
- self.Header = proof.Header
- self.Td = node.Td
- glog.V(logger.Debug).Infof("ODR: validation successful")
- return true
+ return nil
}
diff --git a/les/odr_test.go b/les/odr_test.go
index 622d89e5c7..6b074f1a22 100644
--- a/les/odr_test.go
+++ b/les/odr_test.go
@@ -18,11 +18,13 @@ package les
import (
"bytes"
+ "context"
"math/big"
"testing"
"time"
"github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
@@ -31,7 +33,6 @@ import (
"github.com/ethereum/go-ethereum/light"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp"
- "golang.org/x/net/context"
)
type odrTestFn func(ctx context.Context, db ethdb.Database, config *params.ChainConfig, bc *core.BlockChain, lc *light.LightChain, bhash common.Hash) []byte
@@ -118,7 +119,7 @@ func odrContractCall(ctx context.Context, db ethdb.Database, config *params.Chai
if err == nil {
from := statedb.GetOrNewStateObject(testBankAddress)
- from.SetBalance(common.MaxBig)
+ from.SetBalance(math.MaxBig256)
msg := callmsg{types.NewMessage(from.Address(), &testContractAddr, 0, new(big.Int), big.NewInt(100000), new(big.Int), data, false)}
@@ -126,7 +127,7 @@ func odrContractCall(ctx context.Context, db ethdb.Database, config *params.Chai
vmenv := vm.NewEVM(context, statedb, config, vm.Config{})
//vmenv := core.NewEnv(statedb, config, bc, msg, header, vm.Config{})
- gp := new(core.GasPool).AddGas(common.MaxBig)
+ gp := new(core.GasPool).AddGas(math.MaxBig256)
ret, _, _ := core.ApplyMessage(vmenv, msg, gp)
res = append(res, ret...)
}
@@ -136,7 +137,7 @@ func odrContractCall(ctx context.Context, db ethdb.Database, config *params.Chai
vmstate := light.NewVMState(ctx, state)
from, err := state.GetOrNewStateObject(ctx, testBankAddress)
if err == nil {
- from.SetBalance(common.MaxBig)
+ from.SetBalance(math.MaxBig256)
msg := callmsg{types.NewMessage(from.Address(), &testContractAddr, 0, new(big.Int), big.NewInt(100000), new(big.Int), data, false)}
@@ -144,7 +145,7 @@ func odrContractCall(ctx context.Context, db ethdb.Database, config *params.Chai
vmenv := vm.NewEVM(context, vmstate, config, vm.Config{})
//vmenv := light.NewEnv(ctx, state, config, lc, msg, header, vm.Config{})
- gp := new(core.GasPool).AddGas(common.MaxBig)
+ gp := new(core.GasPool).AddGas(math.MaxBig256)
ret, _, _ := core.ApplyMessage(vmenv, msg, gp)
if vmstate.Error() == nil {
res = append(res, ret...)
@@ -161,8 +162,11 @@ func testOdr(t *testing.T, protocol int, expFail uint64, fn odrTestFn) {
lpm, ldb, odr := newTestProtocolManagerMust(t, true, 0, nil)
_, err1, lpeer, err2 := newTestPeerPair("peer", protocol, pm, lpm)
pool := &testServerPool{}
+ lpm.reqDist = newRequestDistributor(pool.getAllPeers, lpm.quitSync)
+ odr.reqDist = lpm.reqDist
pool.setPeer(lpeer)
odr.serverPool = pool
+ lpeer.hasBlock = func(common.Hash, uint64) bool { return true }
select {
case <-time.After(time.Millisecond * 100):
case err := <-err1:
@@ -177,8 +181,11 @@ func testOdr(t *testing.T, protocol int, expFail uint64, fn odrTestFn) {
for i := uint64(0); i <= pm.blockchain.CurrentHeader().Number.Uint64(); i++ {
bhash := core.GetCanonicalHash(db, i)
b1 := fn(light.NoOdr, db, pm.chainConfig, pm.blockchain.(*core.BlockChain), nil, bhash)
- ctx, _ := context.WithTimeout(context.Background(), 200*time.Millisecond)
+
+ ctx, cancel := context.WithTimeout(context.Background(), 200*time.Millisecond)
+ defer cancel()
b2 := fn(ctx, ldb, lpm.chainConfig, nil, lpm.blockchain.(*light.LightChain), bhash)
+
eq := bytes.Equal(b1, b2)
exp := i < expFail
if exp && !eq {
diff --git a/les/peer.go b/les/peer.go
index d5008ded11..4793da2963 100644
--- a/les/peer.go
+++ b/les/peer.go
@@ -22,13 +22,12 @@ import (
"fmt"
"math/big"
"sync"
+ "time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/les/flowcontrol"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/rlp"
)
@@ -39,7 +38,10 @@ var (
errNotRegistered = errors.New("peer is not registered")
)
-const maxHeadInfoLen = 20
+const (
+ maxHeadInfoLen = 20
+ maxResponseErrors = 50 // number of invalid responses tolerated (makes the protocol less brittle but still avoids spam)
+)
type peer struct {
*p2p.Peer
@@ -55,9 +57,11 @@ type peer struct {
lock sync.RWMutex
announceChn chan announceData
+ sendQueue *execQueue
- poolEntry *poolEntry
- hasBlock func(common.Hash, uint64) bool
+ poolEntry *poolEntry
+ hasBlock func(common.Hash, uint64) bool
+ responseErrors int
fcClient *flowcontrol.ClientNode // nil if the peer is server only
fcServer *flowcontrol.ServerNode // nil if the peer is client only
@@ -78,6 +82,14 @@ func newPeer(version, network int, p *p2p.Peer, rw p2p.MsgReadWriter) *peer {
}
}
+func (p *peer) canQueue() bool {
+ return p.sendQueue.canQueue()
+}
+
+func (p *peer) queueSend(f func()) {
+ p.sendQueue.queue(f)
+}
+
// Info gathers and returns a collection of metadata known about a peer.
func (p *peer) Info() *eth.PeerInfo {
return ð.PeerInfo{
@@ -119,6 +131,11 @@ func (p *peer) Td() *big.Int {
return new(big.Int).Set(p.headInfo.Td)
}
+// waitBefore implements distPeer interface
+func (p *peer) waitBefore(maxCost uint64) (time.Duration, float64) {
+ return p.fcServer.CanSend(maxCost)
+}
+
func sendRequest(w p2p.MsgWriter, msgcode, reqID, cost uint64, data interface{}) error {
type req struct {
ReqID uint64
@@ -196,54 +213,51 @@ func (p *peer) SendHeaderProofs(reqID, bv uint64, proofs []ChtResp) error {
// RequestHeadersByHash fetches a batch of blocks' headers corresponding to the
// specified header query, based on the hash of an origin block.
func (p *peer) RequestHeadersByHash(reqID, cost uint64, origin common.Hash, amount int, skip int, reverse bool) error {
- glog.V(logger.Debug).Infof("%v fetching %d headers from %x, skipping %d (reverse = %v)", p, amount, origin[:4], skip, reverse)
+ p.Log().Debug("Fetching batch of headers", "count", amount, "fromhash", origin, "skip", skip, "reverse", reverse)
return sendRequest(p.rw, GetBlockHeadersMsg, reqID, cost, &getBlockHeadersData{Origin: hashOrNumber{Hash: origin}, Amount: uint64(amount), Skip: uint64(skip), Reverse: reverse})
}
// RequestHeadersByNumber fetches a batch of blocks' headers corresponding to the
// specified header query, based on the number of an origin block.
func (p *peer) RequestHeadersByNumber(reqID, cost, origin uint64, amount int, skip int, reverse bool) error {
- glog.V(logger.Debug).Infof("%v fetching %d headers from #%d, skipping %d (reverse = %v)", p, amount, origin, skip, reverse)
+ p.Log().Debug("Fetching batch of headers", "count", amount, "fromnum", origin, "skip", skip, "reverse", reverse)
return sendRequest(p.rw, GetBlockHeadersMsg, reqID, cost, &getBlockHeadersData{Origin: hashOrNumber{Number: origin}, Amount: uint64(amount), Skip: uint64(skip), Reverse: reverse})
}
// RequestBodies fetches a batch of blocks' bodies corresponding to the hashes
// specified.
func (p *peer) RequestBodies(reqID, cost uint64, hashes []common.Hash) error {
- glog.V(logger.Debug).Infof("%v fetching %d block bodies", p, len(hashes))
+ p.Log().Debug("Fetching batch of block bodies", "count", len(hashes))
return sendRequest(p.rw, GetBlockBodiesMsg, reqID, cost, hashes)
}
// RequestCode fetches a batch of arbitrary data from a node's known state
// data, corresponding to the specified hashes.
func (p *peer) RequestCode(reqID, cost uint64, reqs []*CodeReq) error {
- glog.V(logger.Debug).Infof("%v fetching %v state data", p, len(reqs))
+ p.Log().Debug("Fetching batch of codes", "count", len(reqs))
return sendRequest(p.rw, GetCodeMsg, reqID, cost, reqs)
}
// RequestReceipts fetches a batch of transaction receipts from a remote node.
func (p *peer) RequestReceipts(reqID, cost uint64, hashes []common.Hash) error {
- glog.V(logger.Debug).Infof("%v fetching %v receipts", p, len(hashes))
+ p.Log().Debug("Fetching batch of receipts", "count", len(hashes))
return sendRequest(p.rw, GetReceiptsMsg, reqID, cost, hashes)
}
// RequestProofs fetches a batch of merkle proofs from a remote node.
func (p *peer) RequestProofs(reqID, cost uint64, reqs []*ProofReq) error {
- glog.V(logger.Debug).Infof("%v fetching %v proofs", p, len(reqs))
+ p.Log().Debug("Fetching batch of proofs", "count", len(reqs))
return sendRequest(p.rw, GetProofsMsg, reqID, cost, reqs)
}
// RequestHeaderProofs fetches a batch of header merkle proofs from a remote node.
func (p *peer) RequestHeaderProofs(reqID, cost uint64, reqs []*ChtReq) error {
- glog.V(logger.Debug).Infof("%v fetching %v header proofs", p, len(reqs))
+ p.Log().Debug("Fetching batch of header proofs", "count", len(reqs))
return sendRequest(p.rw, GetHeaderProofsMsg, reqID, cost, reqs)
}
-func (p *peer) SendTxs(cost uint64, txs types.Transactions) error {
- glog.V(logger.Debug).Infof("%v relaying %v txs", p, len(txs))
- reqID := getNextReqID()
- p.fcServer.MustAssignRequest(reqID)
- p.fcServer.SendRequest(reqID, cost)
+func (p *peer) SendTxs(reqID, cost uint64, txs types.Transactions) error {
+ p.Log().Debug("Fetching batch of transactions", "count", len(txs))
return p2p.Send(p.rw, SendTxMsg, txs)
}
@@ -368,7 +382,7 @@ func (p *peer) Handshake(td *big.Int, head common.Hash, headNum uint64, genesis
}
if rGenesis != genesis {
- return errResp(ErrGenesisBlockMismatch, "%x (!= %x)", rGenesis, genesis)
+ return errResp(ErrGenesisBlockMismatch, "%x (!= %x)", rGenesis[:8], genesis[:8])
}
if int(rNetwork) != p.network {
return errResp(ErrNetworkIdMismatch, "%d (!= %d)", rNetwork, p.network)
@@ -446,6 +460,7 @@ func (ps *peerSet) Register(p *peer) error {
return errAlreadyRegistered
}
ps.peers[p.id] = p
+ p.sendQueue = newExecQueue(100)
return nil
}
@@ -455,8 +470,10 @@ func (ps *peerSet) Unregister(id string) error {
ps.lock.Lock()
defer ps.lock.Unlock()
- if _, ok := ps.peers[id]; !ok {
+ if p, ok := ps.peers[id]; !ok {
return errNotRegistered
+ } else {
+ p.sendQueue.quit()
}
delete(ps.peers, id)
return nil
diff --git a/les/request_test.go b/les/request_test.go
index 10e9edf8be..ba1fc15bd7 100644
--- a/les/request_test.go
+++ b/les/request_test.go
@@ -17,6 +17,7 @@
package les
import (
+ "context"
"testing"
"time"
@@ -25,7 +26,6 @@ import (
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/light"
- "golang.org/x/net/context"
)
var testBankSecureTrieKey = secAddr(testBankAddress)
@@ -72,8 +72,11 @@ func testAccess(t *testing.T, protocol int, fn accessTestFn) {
lpm, ldb, odr := newTestProtocolManagerMust(t, true, 0, nil)
_, err1, lpeer, err2 := newTestPeerPair("peer", protocol, pm, lpm)
pool := &testServerPool{}
+ lpm.reqDist = newRequestDistributor(pool.getAllPeers, lpm.quitSync)
+ odr.reqDist = lpm.reqDist
pool.setPeer(lpeer)
odr.serverPool = pool
+ lpeer.hasBlock = func(common.Hash, uint64) bool { return true }
select {
case <-time.After(time.Millisecond * 100):
case err := <-err1:
@@ -88,7 +91,9 @@ func testAccess(t *testing.T, protocol int, fn accessTestFn) {
for i := uint64(0); i <= pm.blockchain.CurrentHeader().Number.Uint64(); i++ {
bhash := core.GetCanonicalHash(db, i)
if req := fn(ldb, bhash, i); req != nil {
- ctx, _ := context.WithTimeout(context.Background(), 200*time.Millisecond)
+ ctx, cancel := context.WithTimeout(context.Background(), 200*time.Millisecond)
+ defer cancel()
+
err := odr.Retrieve(ctx, req)
got := err == nil
exp := i < expFail
diff --git a/les/server.go b/les/server.go
index c4c6fcab52..5957add367 100644
--- a/les/server.go
+++ b/les/server.go
@@ -30,8 +30,7 @@ import (
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/les/flowcontrol"
"github.com/ethereum/go-ethereum/light"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/trie"
@@ -46,7 +45,7 @@ type LesServer struct {
}
func NewLesServer(eth *eth.Ethereum, config *eth.Config) (*LesServer, error) {
- pm, err := NewProtocolManager(config.ChainConfig, false, config.NetworkId, eth.EventMux(), eth.Pow(), eth.BlockChain(), eth.TxPool(), eth.ChainDb(), nil, nil)
+ pm, err := NewProtocolManager(eth.BlockChain().Config(), false, config.NetworkId, eth.EventMux(), eth.Pow(), eth.BlockChain(), eth.TxPool(), eth.ChainDb(), nil, nil)
if err != nil {
return nil, err
}
@@ -292,7 +291,7 @@ func (pm *ProtocolManager) blockLoop() {
lastHead = header
lastBroadcastTd = td
- glog.V(logger.Debug).Infoln("===> ", number, hash, td, reorg)
+ log.Debug("Announcing block to peers", "number", number, "hash", hash, "td", td, "reorg", reorg)
announce := announceData{Hash: hash, Number: number, Td: td, ReorgDepth: reorg}
for _, p := range peers {
@@ -396,7 +395,7 @@ func makeCht(db ethdb.Database) bool {
} else {
lastChtNum++
- glog.V(logger.Detail).Infof("cht: %d %064x", lastChtNum, root)
+ log.Trace("Generated CHT", "number", lastChtNum, "root", root.Hex())
storeChtRoot(db, lastChtNum, root)
var data [8]byte
diff --git a/les/serverpool.go b/les/serverpool.go
index 9735a718e5..64fe991c63 100644
--- a/les/serverpool.go
+++ b/les/serverpool.go
@@ -18,6 +18,7 @@
package les
import (
+ "fmt"
"io"
"math"
"math/rand"
@@ -28,8 +29,7 @@ import (
"github.com/ethereum/go-ethereum/common/mclock"
"github.com/ethereum/go-ethereum/ethdb"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/p2p/discover"
"github.com/ethereum/go-ethereum/p2p/discv5"
@@ -162,7 +162,7 @@ func (pool *serverPool) connect(p *peer, ip net.IP, port uint16) *poolEntry {
if entry == nil {
entry = pool.findOrNewNode(p.ID(), ip, port)
}
- glog.V(logger.Debug).Infof("connecting to %v, state: %v", p.id, entry.state)
+ p.Log().Debug("Connecting to new peer", "state", entry.state)
if entry.state == psConnected || entry.state == psRegistered {
return nil
}
@@ -184,7 +184,7 @@ func (pool *serverPool) connect(p *peer, ip net.IP, port uint16) *poolEntry {
// registered should be called after a successful handshake
func (pool *serverPool) registered(entry *poolEntry) {
- glog.V(logger.Debug).Infof("registered %v", entry.id.String())
+ log.Debug("Registered new entry", "enode", entry.id)
pool.lock.Lock()
defer pool.lock.Unlock()
@@ -202,7 +202,7 @@ func (pool *serverPool) registered(entry *poolEntry) {
// can be updated optionally (not updated if no registration happened, in this case
// only connection statistics are updated, just like in case of timeout)
func (pool *serverPool) disconnect(entry *poolEntry) {
- glog.V(logger.Debug).Infof("disconnected %v", entry.id.String())
+ log.Debug("Disconnected old entry", "enode", entry.id)
pool.lock.Lock()
defer pool.lock.Unlock()
@@ -268,82 +268,6 @@ func (pool *serverPool) adjustResponseTime(entry *poolEntry, time time.Duration,
}
}
-type selectPeerItem struct {
- peer *peer
- weight int64
- wait time.Duration
-}
-
-func (sp selectPeerItem) Weight() int64 {
- return sp.weight
-}
-
-// selectPeer selects a suitable peer for a request, also returning a necessary waiting time to perform the request
-// and a "locked" flag meaning that the request has been assigned to the given peer and its execution is guaranteed
-// after the given waiting time. If locked flag is false, selectPeer should be called again after the waiting time.
-func (pool *serverPool) selectPeer(reqID uint64, canSend func(*peer) (bool, time.Duration)) (*peer, time.Duration, bool) {
- pool.lock.Lock()
- type selectPeer struct {
- peer *peer
- rstat, tstat float64
- }
- var list []selectPeer
- sel := newWeightedRandomSelect()
- for _, entry := range pool.entries {
- if entry.state == psRegistered {
- if !entry.peer.fcServer.IsAssigned() {
- list = append(list, selectPeer{entry.peer, entry.responseStats.recentAvg(), entry.timeoutStats.recentAvg()})
- }
- }
- }
- pool.lock.Unlock()
-
- for _, sp := range list {
- ok, wait := canSend(sp.peer)
- if ok {
- w := int64(1000000000 * (peerSelectMinWeight + math.Exp(-(sp.rstat+float64(wait))/float64(responseScoreTC))*math.Pow((1-sp.tstat), timeoutPow)))
- sel.update(selectPeerItem{peer: sp.peer, weight: w, wait: wait})
- }
- }
- choice := sel.choose()
- if choice == nil {
- return nil, 0, false
- }
- peer, wait := choice.(selectPeerItem).peer, choice.(selectPeerItem).wait
- locked := false
- if wait < time.Millisecond*100 {
- if peer.fcServer.AssignRequest(reqID) {
- ok, w := canSend(peer)
- wait = time.Duration(w)
- if ok && wait < time.Millisecond*100 {
- locked = true
- } else {
- peer.fcServer.DeassignRequest(reqID)
- wait = time.Millisecond * 100
- }
- }
- } else {
- wait = time.Millisecond * 100
- }
- return peer, wait, locked
-}
-
-// selectPeer selects a suitable peer for a request, waiting until an assignment to
-// the request is guaranteed or the process is aborted.
-func (pool *serverPool) selectPeerWait(reqID uint64, canSend func(*peer) (bool, time.Duration), abort <-chan struct{}) *peer {
- for {
- peer, wait, locked := pool.selectPeer(reqID, canSend)
- if locked {
- return peer
- }
- select {
- case <-abort:
- return nil
- case <-time.After(wait):
- }
- }
-}
-
// eventLoop handles pool events and mutex locking for all internal functions
func (pool *serverPool) eventLoop() {
lookupCnt := 0
@@ -418,7 +342,7 @@ func (pool *serverPool) findOrNewNode(id discover.NodeID, ip net.IP, port uint16
now := mclock.Now()
entry := pool.entries[id]
if entry == nil {
- glog.V(logger.Debug).Infof("discovered %v", id.String())
+ log.Debug("Discovered new entry", "id", id)
entry = &poolEntry{
id: id,
addr: make(map[string]*poolEntryAddress),
@@ -459,11 +383,15 @@ func (pool *serverPool) loadNodes() {
var list []*poolEntry
err = rlp.DecodeBytes(enc, &list)
if err != nil {
- glog.V(logger.Debug).Infof("node list decode error: %v", err)
+ log.Debug("Failed to decode node list", "err", err)
return
}
for _, e := range list {
- glog.V(logger.Debug).Infof("loaded server stats %016x fails: %v connStats: %v / %v delayStats: %v / %v responseStats: %v / %v timeoutStats: %v / %v", e.id[0:8], e.lastConnected.fails, e.connectStats.avg, e.connectStats.weight, time.Duration(e.delayStats.avg), e.delayStats.weight, time.Duration(e.responseStats.avg), e.responseStats.weight, e.timeoutStats.avg, e.timeoutStats.weight)
+ log.Debug("Loaded server stats", "id", e.id, "fails", e.lastConnected.fails,
+ "conn", fmt.Sprintf("%v/%v", e.connectStats.avg, e.connectStats.weight),
+ "delay", fmt.Sprintf("%v/%v", time.Duration(e.delayStats.avg), e.delayStats.weight),
+ "response", fmt.Sprintf("%v/%v", time.Duration(e.responseStats.avg), e.responseStats.weight),
+ "timeout", fmt.Sprintf("%v/%v", e.timeoutStats.avg, e.timeoutStats.weight))
pool.entries[e.id] = e
pool.knownQueue.setLatest(e)
pool.knownSelect.update((*knownEntry)(e))
@@ -568,7 +496,7 @@ func (pool *serverPool) dial(entry *poolEntry, knownSelected bool) {
pool.newSelected++
}
addr := entry.addrSelect.choose().(*poolEntryAddress)
- glog.V(logger.Debug).Infof("dialing %v out of %v, known: %v", entry.id.String()+"@"+addr.strKey(), len(entry.addr), knownSelected)
+ log.Debug("Dialing new peer", "lesaddr", entry.id.String()+"@"+addr.strKey(), "set", len(entry.addr), "known", knownSelected)
entry.dialed = addr
go func() {
pool.server.AddPeer(discover.NewNode(entry.id, addr.ip, addr.port, addr.port))
@@ -589,7 +517,7 @@ func (pool *serverPool) checkDialTimeout(entry *poolEntry) {
if entry.state != psDialed {
return
}
- glog.V(logger.Debug).Infof("timeout %v", entry.id.String()+"@"+entry.dialed.strKey())
+ log.Debug("Dial timeout", "lesaddr", entry.id.String()+"@"+entry.dialed.strKey())
entry.state = psNotConnected
if entry.knownSelected {
pool.knownSelected--
diff --git a/les/sync.go b/les/sync.go
index c143cb1453..c0e17f97d9 100644
--- a/les/sync.go
+++ b/les/sync.go
@@ -17,12 +17,12 @@
package les
import (
+ "context"
"time"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/eth/downloader"
"github.com/ethereum/go-ethereum/light"
- "golang.org/x/net/context"
)
const (
@@ -77,8 +77,8 @@ func (pm *ProtocolManager) synchronise(peer *peer) {
return
}
- ctx, _ := context.WithTimeout(context.Background(), time.Second*5)
+ ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
+ defer cancel()
pm.blockchain.(*light.LightChain).SyncCht(ctx)
-
pm.downloader.Synchronise(peer.id, peer.Head(), peer.Td(), downloader.LightSync)
}
diff --git a/les/txrelay.go b/les/txrelay.go
index 76d416c57a..1ca3467e4d 100644
--- a/les/txrelay.go
+++ b/les/txrelay.go
@@ -35,13 +35,14 @@ type LesTxRelay struct {
peerList []*peer
peerStartPos int
lock sync.RWMutex
+
+ reqDist *requestDistributor
}
func NewLesTxRelay() *LesTxRelay {
return &LesTxRelay{
txSent: make(map[common.Hash]*ltrInfo),
txPending: make(map[common.Hash]struct{}),
- ps: newPeerSet(),
}
}
@@ -108,10 +109,26 @@ func (self *LesTxRelay) send(txs types.Transactions, count int) {
}
for p, list := range sendTo {
- cost := p.GetRequestCost(SendTxMsg, len(list))
- go func(p *peer, list types.Transactions, cost uint64) {
- p.SendTxs(cost, list)
- }(p, list, cost)
+ pp := p
+ ll := list
+
+ reqID := getNextReqID()
+ rq := &distReq{
+ getCost: func(dp distPeer) uint64 {
+ peer := dp.(*peer)
+ return peer.GetRequestCost(SendTxMsg, len(ll))
+ },
+ canSend: func(dp distPeer) bool {
+ return dp.(*peer) == pp
+ },
+ request: func(dp distPeer) func() {
+ peer := dp.(*peer)
+ cost := peer.GetRequestCost(SendTxMsg, len(ll))
+ peer.fcServer.QueueRequest(reqID, cost)
+ return func() { peer.SendTxs(reqID, cost, ll) }
+ },
+ }
+ self.reqDist.queue(rq)
}
}
diff --git a/light/lightchain.go b/light/lightchain.go
index 0d28ad2f45..98fb024f0b 100644
--- a/light/lightchain.go
+++ b/light/lightchain.go
@@ -17,6 +17,7 @@
package light
import (
+ "context"
"math/big"
"sync"
"sync/atomic"
@@ -27,13 +28,11 @@ import (
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/pow"
"github.com/ethereum/go-ethereum/rlp"
"github.com/hashicorp/golang-lru"
- "golang.org/x/net/context"
)
var (
@@ -97,38 +96,13 @@ func NewLightChain(odr OdrBackend, config *params.ChainConfig, pow pow.PoW, mux
bc.genesisBlock, _ = bc.GetBlockByNumber(NoOdr, 0)
if bc.genesisBlock == nil {
- bc.genesisBlock, err = core.WriteDefaultGenesisBlock(odr.Database())
- if err != nil {
- return nil, err
- }
- glog.V(logger.Info).Infoln("WARNING: Wrote default ethereum genesis block")
+ return nil, core.ErrNoGenesis
}
- if bc.genesisBlock.Hash() == (common.Hash{212, 229, 103, 64, 248, 118, 174, 248, 192, 16, 184, 106, 64, 213, 245, 103, 69, 161, 24, 208, 144, 106, 52, 230, 154, 236, 140, 13, 177, 203, 143, 163}) {
+ if bc.genesisBlock.Hash() == params.MainNetGenesisHash {
// add trusted CHT
- if config.DAOForkSupport {
- WriteTrustedCht(bc.chainDb, TrustedCht{
- Number: 637,
- Root: common.HexToHash("01e408d9b1942f05dba1a879f3eaafe34d219edaeb8223fecf1244cc023d3e23"),
- })
- } else {
- WriteTrustedCht(bc.chainDb, TrustedCht{
- Number: 523,
- Root: common.HexToHash("c035076523faf514038f619715de404a65398c51899b5dccca9c05b00bc79315"),
- })
- }
- glog.V(logger.Info).Infoln("Added trusted CHT for mainnet")
- } else {
- if bc.genesisBlock.Hash() == (common.Hash{12, 215, 134, 162, 66, 93, 22, 241, 82, 198, 88, 49, 108, 66, 62, 108, 225, 24, 30, 21, 195, 41, 88, 38, 215, 201, 144, 76, 186, 156, 227, 3}) {
- // add trusted CHT for testnet
- WriteTrustedCht(bc.chainDb, TrustedCht{
- Number: 452,
- Root: common.HexToHash("511da2c88e32b14cf4a4e62f7fcbb297139faebc260a4ab5eb43cce6edcba324"),
- })
- glog.V(logger.Info).Infoln("Added trusted CHT for testnet")
- } else {
- DeleteTrustedCht(bc.chainDb)
- }
+ WriteTrustedCht(bc.chainDb, TrustedCht{Number: 805, Root: common.HexToHash("85e4286fe0a730390245c49de8476977afdae0eb5530b277f62a52b12313d50f")})
+ log.Info("Added trusted CHT for mainnet")
}
if err := bc.loadLastState(); err != nil {
@@ -137,9 +111,9 @@ func NewLightChain(odr OdrBackend, config *params.ChainConfig, pow pow.PoW, mux
// Check the current state of the block hashes and make sure that we do not have any of the bad blocks in our chain
for hash := range core.BadHashes {
if header := bc.GetHeaderByHash(hash); header != nil {
- glog.V(logger.Error).Infof("Found bad hash, rewinding chain to block #%d [%x…]", header.Number, header.ParentHash[:4])
+ log.Error("Found bad hash, rewinding chain", "number", header.Number, "hash", header.ParentHash)
bc.SetHead(header.Number.Uint64() - 1)
- glog.V(logger.Error).Infoln("Chain rewind was successful, resuming normal operation")
+ log.Error("Chain rewind was successful, resuming normal operation")
}
}
return bc, nil
@@ -169,7 +143,10 @@ func (self *LightChain) loadLastState() error {
// Issue a status log and return
header := self.hc.CurrentHeader()
headerTd := self.GetTd(header.Hash(), header.Number.Uint64())
- glog.V(logger.Info).Infof("Last header: #%d [%x…] TD=%v", self.hc.CurrentHeader().Number, self.hc.CurrentHeader().Hash().Bytes()[:4], headerTd)
+ log.Info("Loaded most recent local header", "number", header.Number, "hash", header.Hash(), "td", headerTd)
+
+ // Try to be smart and issue a pow verification for the head to pre-generate caches
+ go self.pow.Verify(types.NewBlockWithHeader(header))
return nil
}
@@ -246,10 +223,10 @@ func (bc *LightChain) ResetWithGenesisBlock(genesis *types.Block) {
// Prepare the genesis block and reinitialise the chain
if err := core.WriteTd(bc.chainDb, genesis.Hash(), genesis.NumberU64(), genesis.Difficulty()); err != nil {
- glog.Fatalf("failed to write genesis block TD: %v", err)
+ log.Crit("Failed to write genesis block TD", "err", err)
}
if err := core.WriteBlock(bc.chainDb, genesis); err != nil {
- glog.Fatalf("failed to write genesis block: %v", err)
+ log.Crit("Failed to write genesis block", "err", err)
}
bc.genesisBlock = genesis
bc.hc.SetGenesis(bc.genesisBlock.Header())
@@ -345,8 +322,7 @@ func (bc *LightChain) Stop() {
atomic.StoreInt32(&bc.procInterrupt, 1)
bc.wg.Wait()
-
- glog.V(logger.Info).Infoln("Chain manager stopped")
+ log.Info("Blockchain manager stopped")
}
// Rollback is designed to remove a chain of links from the database that aren't
@@ -390,9 +366,17 @@ func (self *LightChain) postChainEvents(events []interface{}) {
// In the case of a light chain, InsertHeaderChain also creates and posts light
// chain events when necessary.
func (self *LightChain) InsertHeaderChain(chain []*types.Header, checkFreq int) (int, error) {
+ start := time.Now()
+ if i, err := self.hc.ValidateHeaderChain(chain, checkFreq); err != nil {
+ return i, err
+ }
+
// Make sure only one thread manipulates the chain at once
self.chainmu.Lock()
- defer self.chainmu.Unlock()
+ defer func() {
+ self.chainmu.Unlock()
+ time.Sleep(time.Millisecond * 10) // ugly hack; do not hog chain lock in case syncing is CPU-limited by validation
+ }()
self.wg.Add(1)
defer self.wg.Done()
@@ -406,24 +390,19 @@ func (self *LightChain) InsertHeaderChain(chain []*types.Header, checkFreq int)
switch status {
case core.CanonStatTy:
- if glog.V(logger.Debug) {
- glog.Infof("[%v] inserted header #%d (%x...).\n", time.Now().UnixNano(), header.Number, header.Hash().Bytes()[0:4])
- }
+ log.Debug("Inserted new header", "number", header.Number, "hash", header.Hash())
events = append(events, core.ChainEvent{Block: types.NewBlockWithHeader(header), Hash: header.Hash()})
case core.SideStatTy:
- if glog.V(logger.Detail) {
- glog.Infof("inserted forked header #%d (TD=%v) (%x...).\n", header.Number, header.Difficulty, header.Hash().Bytes()[0:4])
- }
+ log.Debug("Inserted forked header", "number", header.Number, "hash", header.Hash())
events = append(events, core.ChainSideEvent{Block: types.NewBlockWithHeader(header)})
case core.SplitStatTy:
events = append(events, core.ChainSplitEvent{Block: types.NewBlockWithHeader(header)})
}
-
return err
}
- i, err := self.hc.InsertHeaderChain(chain, checkFreq, whFunc)
+ i, err := self.hc.InsertHeaderChain(chain, whFunc, start)
go self.postChainEvents(events)
return i, err
}
diff --git a/light/lightchain_test.go b/light/lightchain_test.go
index 0ba9258873..e9236f1fd2 100644
--- a/light/lightchain_test.go
+++ b/light/lightchain_test.go
@@ -17,12 +17,11 @@
package light
import (
+ "context"
"fmt"
"math/big"
- "runtime"
"testing"
- "github.com/ethereum/ethash"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/types"
@@ -30,8 +29,6 @@ import (
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/pow"
- "github.com/hashicorp/golang-lru"
- "golang.org/x/net/context"
)
// So we can deterministically seed different blockchains
@@ -60,14 +57,10 @@ func testChainConfig() *params.ChainConfig {
// chain. Depending on the full flag, if creates either a full block chain or a
// header only chain.
func newCanonical(n int) (ethdb.Database, *LightChain, error) {
- // Create te new chain database
db, _ := ethdb.NewMemDatabase()
- evmux := &event.TypeMux{}
-
- // Initialize a fresh chain with only a genesis block
- genesis, _ := core.WriteTestNetGenesisBlock(db)
-
- blockchain, _ := NewLightChain(&dummyOdr{db: db}, testChainConfig(), core.FakePow{}, evmux)
+ gspec := core.Genesis{Config: testChainConfig()}
+ genesis := gspec.MustCommit(db)
+ blockchain, _ := NewLightChain(&dummyOdr{db: db}, gspec.Config, pow.FakePow{}, new(event.TypeMux))
// Create and inject the requested chain
if n == 0 {
return db, blockchain, nil
@@ -78,26 +71,20 @@ func newCanonical(n int) (ethdb.Database, *LightChain, error) {
return db, blockchain, err
}
-func init() {
- runtime.GOMAXPROCS(runtime.NumCPU())
-}
-
-func thePow() pow.PoW {
- pow, _ := ethash.NewForTesting()
- return pow
-}
-
-func theLightChain(db ethdb.Database, t *testing.T) *LightChain {
- var eventMux event.TypeMux
- core.WriteTestNetGenesisBlock(db)
- LightChain, err := NewLightChain(&dummyOdr{db: db}, testChainConfig(), thePow(), &eventMux)
- if err != nil {
- t.Error("failed creating LightChain:", err)
- t.FailNow()
- return nil
+// newTestLightChain creates a LightChain that doesn't validate anything.
+func newTestLightChain() *LightChain {
+ db, _ := ethdb.NewMemDatabase()
+ gspec := &core.Genesis{
+ Difficulty: big.NewInt(1),
+ Config: testChainConfig(),
}
-
- return LightChain
+ gspec.MustCommit(db)
+ lc, err := NewLightChain(&dummyOdr{db: db}, gspec.Config, pow.NewTestEthash(), new(event.TypeMux))
+ if err != nil {
+ panic(err)
+ }
+ lc.SetValidator(bproc{})
+ return lc
}
// Test fork of length N starting from block i
@@ -308,20 +295,6 @@ func (odr *dummyOdr) Retrieve(ctx context.Context, req OdrRequest) error {
return nil
}
-func chm(genesis *types.Block, db ethdb.Database) *LightChain {
- odr := &dummyOdr{db: db}
- var eventMux event.TypeMux
- bc := &LightChain{odr: odr, chainDb: db, genesisBlock: genesis, eventMux: &eventMux, pow: core.FakePow{}}
- bc.hc, _ = core.NewHeaderChain(db, testChainConfig(), bc.Validator, bc.getProcInterrupt)
- bc.bodyCache, _ = lru.New(100)
- bc.bodyRLPCache, _ = lru.New(100)
- bc.blockCache, _ = lru.New(100)
- bc.SetValidator(bproc{})
- bc.ResetWithGenesisBlock(genesis)
-
- return bc
-}
-
// Tests that reorganizing a long difficult chain after a short easy one
// overwrites the canonical numbers and links in the database.
func TestReorgLongHeaders(t *testing.T) {
@@ -335,14 +308,11 @@ func TestReorgShortHeaders(t *testing.T) {
}
func testReorg(t *testing.T, first, second []int, td int64) {
- // Create a pristine block chain
- db, _ := ethdb.NewMemDatabase()
- genesis, _ := core.WriteTestNetGenesisBlock(db)
- bc := chm(genesis, db)
+ bc := newTestLightChain()
// Insert an easy and a difficult chain afterwards
- bc.InsertHeaderChain(makeHeaderChainWithDiff(genesis, first, 11), 1)
- bc.InsertHeaderChain(makeHeaderChainWithDiff(genesis, second, 22), 1)
+ bc.InsertHeaderChain(makeHeaderChainWithDiff(bc.genesisBlock, first, 11), 1)
+ bc.InsertHeaderChain(makeHeaderChainWithDiff(bc.genesisBlock, second, 22), 1)
// Check that the chain is valid number and link wise
prev := bc.CurrentHeader()
for header := bc.GetHeaderByNumber(bc.CurrentHeader().Number.Uint64() - 1); header.Number.Uint64() != 0; prev, header = header, bc.GetHeaderByNumber(header.Number.Uint64()-1) {
@@ -351,7 +321,7 @@ func testReorg(t *testing.T, first, second []int, td int64) {
}
}
// Make sure the chain total difficulty is the correct one
- want := new(big.Int).Add(genesis.Difficulty(), big.NewInt(td))
+ want := new(big.Int).Add(bc.genesisBlock.Difficulty(), big.NewInt(td))
if have := bc.GetTdByHash(bc.CurrentHeader().Hash()); have.Cmp(want) != 0 {
t.Errorf("total difficulty mismatch: have %v, want %v", have, want)
}
@@ -359,14 +329,11 @@ func testReorg(t *testing.T, first, second []int, td int64) {
// Tests that the insertion functions detect banned hashes.
func TestBadHeaderHashes(t *testing.T) {
- // Create a pristine block chain
- db, _ := ethdb.NewMemDatabase()
- genesis, _ := core.WriteTestNetGenesisBlock(db)
- bc := chm(genesis, db)
+ bc := newTestLightChain()
// Create a chain, ban a hash and try to import
var err error
- headers := makeHeaderChainWithDiff(genesis, []int{1, 2, 4}, 10)
+ headers := makeHeaderChainWithDiff(bc.genesisBlock, []int{1, 2, 4}, 10)
core.BadHashes[headers[2].Hash()] = true
_, err = bc.InsertHeaderChain(headers, 1)
if !core.IsBadHashError(err) {
@@ -377,13 +344,10 @@ func TestBadHeaderHashes(t *testing.T) {
// Tests that bad hashes are detected on boot, and the chan rolled back to a
// good state prior to the bad hash.
func TestReorgBadHeaderHashes(t *testing.T) {
- // Create a pristine block chain
- db, _ := ethdb.NewMemDatabase()
- genesis, _ := core.WriteTestNetGenesisBlock(db)
- bc := chm(genesis, db)
+ bc := newTestLightChain()
// Create a chain, import and ban aferwards
- headers := makeHeaderChainWithDiff(genesis, []int{1, 2, 3, 4}, 10)
+ headers := makeHeaderChainWithDiff(bc.genesisBlock, []int{1, 2, 3, 4}, 10)
if _, err := bc.InsertHeaderChain(headers, 1); err != nil {
t.Fatalf("failed to import headers: %v", err)
@@ -393,8 +357,9 @@ func TestReorgBadHeaderHashes(t *testing.T) {
}
core.BadHashes[headers[3].Hash()] = true
defer func() { delete(core.BadHashes, headers[3].Hash()) }()
- // Create a new chain manager and check it rolled back the state
- ncm, err := NewLightChain(&dummyOdr{db: db}, testChainConfig(), core.FakePow{}, new(event.TypeMux))
+
+ // Create a new LightChain and check that it rolled back the state.
+ ncm, err := NewLightChain(&dummyOdr{db: bc.chainDb}, testChainConfig(), pow.FakePow{}, new(event.TypeMux))
if err != nil {
t.Fatalf("failed to create new chain manager: %v", err)
}
diff --git a/light/odr.go b/light/odr.go
index 4f6ef6b9ed..ca6364f287 100644
--- a/light/odr.go
+++ b/light/odr.go
@@ -19,6 +19,7 @@
package light
import (
+ "context"
"math/big"
"github.com/ethereum/go-ethereum/common"
@@ -27,7 +28,6 @@ import (
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/rlp"
- "golang.org/x/net/context"
)
// NoOdr is the default context passed to an ODR capable function when the ODR
diff --git a/light/odr_test.go b/light/odr_test.go
index a2f969acb3..37d9999941 100644
--- a/light/odr_test.go
+++ b/light/odr_test.go
@@ -18,12 +18,14 @@ package light
import (
"bytes"
+ "context"
"errors"
"math/big"
"testing"
"time"
"github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
@@ -32,9 +34,9 @@ import (
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/params"
+ "github.com/ethereum/go-ethereum/pow"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/trie"
- "golang.org/x/net/context"
)
var (
@@ -49,6 +51,8 @@ var (
testContractCode = common.Hex2Bytes("606060405260cc8060106000396000f360606040526000357c01000000000000000000000000000000000000000000000000000000009004806360cd2685146041578063c16431b914606b57603f565b005b6055600480803590602001909190505060a9565b6040518082815260200191505060405180910390f35b60886004808035906020019091908035906020019091905050608a565b005b80600060005083606481101560025790900160005b50819055505b5050565b6000600060005082606481101560025790900160005b5054905060c7565b91905056")
testContractAddr common.Address
+
+ bigTxGas = new(big.Int).SetUint64(params.TxGas)
)
type testOdr struct {
@@ -167,14 +171,14 @@ func odrContractCall(ctx context.Context, db ethdb.Database, bc *core.BlockChain
statedb, err := state.New(header.Root, db)
if err == nil {
from := statedb.GetOrNewStateObject(testBankAddress)
- from.SetBalance(common.MaxBig)
+ from.SetBalance(math.MaxBig256)
msg := callmsg{types.NewMessage(from.Address(), &testContractAddr, 0, new(big.Int), big.NewInt(1000000), new(big.Int), data, false)}
context := core.NewEVMContext(msg, header, bc)
vmenv := vm.NewEVM(context, statedb, config, vm.Config{})
- gp := new(core.GasPool).AddGas(common.MaxBig)
+ gp := new(core.GasPool).AddGas(math.MaxBig256)
ret, _, _ := core.ApplyMessage(vmenv, msg, gp)
res = append(res, ret...)
}
@@ -184,12 +188,12 @@ func odrContractCall(ctx context.Context, db ethdb.Database, bc *core.BlockChain
vmstate := NewVMState(ctx, state)
from, err := state.GetOrNewStateObject(ctx, testBankAddress)
if err == nil {
- from.SetBalance(common.MaxBig)
+ from.SetBalance(math.MaxBig256)
msg := callmsg{types.NewMessage(from.Address(), &testContractAddr, 0, new(big.Int), big.NewInt(1000000), new(big.Int), data, false)}
context := core.NewEVMContext(msg, header, lc)
vmenv := vm.NewEVM(context, vmstate, config, vm.Config{})
- gp := new(core.GasPool).AddGas(common.MaxBig)
+ gp := new(core.GasPool).AddGas(math.MaxBig256)
ret, _, _ := core.ApplyMessage(vmenv, msg, gp)
if vmstate.Error() == nil {
res = append(res, ret...)
@@ -205,15 +209,15 @@ func testChainGen(i int, block *core.BlockGen) {
switch i {
case 0:
// In block 1, the test bank sends account #1 some ether.
- tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil), signer, testBankKey)
+ tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(10000), bigTxGas, nil, nil), signer, testBankKey)
block.AddTx(tx)
case 1:
// In block 2, the test bank sends some more ether to account #1.
// acc1Addr passes it on to account #2.
// acc1Addr creates a test contract.
- tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, testBankKey)
+ tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(1000), bigTxGas, nil, nil), signer, testBankKey)
nonce := block.TxNonce(acc1Addr)
- tx2, _ := types.SignTx(types.NewTransaction(nonce, acc2Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, acc1Key)
+ tx2, _ := types.SignTx(types.NewTransaction(nonce, acc2Addr, big.NewInt(1000), bigTxGas, nil, nil), signer, acc1Key)
nonce++
tx3, _ := types.SignTx(types.NewContractCreation(nonce, big.NewInt(0), big.NewInt(1000000), big.NewInt(0), testContractCode), signer, acc1Key)
testContractAddr = crypto.CreateAddress(acc1Addr, nonce)
@@ -244,12 +248,13 @@ func testChainGen(i int, block *core.BlockGen) {
func testChainOdr(t *testing.T, protocol int, expFail uint64, fn odrTestFn) {
var (
evmux = new(event.TypeMux)
- pow = new(core.FakePow)
+ pow = new(pow.FakePow)
sdb, _ = ethdb.NewMemDatabase()
ldb, _ = ethdb.NewMemDatabase()
- genesis = core.WriteGenesisBlockForTesting(sdb, core.GenesisAccount{Address: testBankAddress, Balance: testBankFunds})
+ gspec = core.Genesis{Alloc: core.GenesisAlloc{testBankAddress: {Balance: testBankFunds}}}
+ genesis = gspec.MustCommit(sdb)
)
- core.WriteGenesisBlockForTesting(ldb, core.GenesisAccount{Address: testBankAddress, Balance: testBankFunds})
+ gspec.MustCommit(ldb)
// Assemble the test environment
blockchain, _ := core.NewBlockChain(sdb, testChainConfig(), pow, evmux, vm.Config{})
chainConfig := ¶ms.ChainConfig{HomesteadBlock: new(big.Int)}
@@ -273,8 +278,11 @@ func testChainOdr(t *testing.T, protocol int, expFail uint64, fn odrTestFn) {
for i := uint64(0); i <= blockchain.CurrentHeader().Number.Uint64(); i++ {
bhash := core.GetCanonicalHash(sdb, i)
b1 := fn(NoOdr, sdb, blockchain, nil, bhash)
- ctx, _ := context.WithTimeout(context.Background(), 200*time.Millisecond)
+
+ ctx, cancel := context.WithTimeout(context.Background(), 200*time.Millisecond)
+ defer cancel()
b2 := fn(ctx, ldb, nil, lightchain, bhash)
+
eq := bytes.Equal(b1, b2)
exp := i < expFail
if exp && !eq {
diff --git a/light/odr_util.go b/light/odr_util.go
index 7617116212..d7f8458f12 100644
--- a/light/odr_util.go
+++ b/light/odr_util.go
@@ -18,6 +18,7 @@ package light
import (
"bytes"
+ "context"
"errors"
"math/big"
@@ -26,10 +27,7 @@ import (
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethdb"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
"github.com/ethereum/go-ethereum/rlp"
- "golang.org/x/net/context"
)
var sha3_nil = crypto.Keccak256Hash(nil)
@@ -149,7 +147,6 @@ func GetBody(ctx context.Context, odr OdrBackend, hash common.Hash, number uint6
}
body := new(types.Body)
if err := rlp.Decode(bytes.NewReader(data), body); err != nil {
- glog.V(logger.Error).Infof("invalid block body RLP for hash %x: %v", hash, err)
return nil, err
}
return body, nil
@@ -181,7 +178,6 @@ func GetBlockReceipts(ctx context.Context, odr OdrBackend, hash common.Hash, num
r := &ReceiptsRequest{Hash: hash, Number: number}
if err := odr.Retrieve(ctx, r); err != nil {
return nil, err
- } else {
- return r.Receipts, nil
}
+ return r.Receipts, nil
}
diff --git a/light/state.go b/light/state.go
index f8b75c5880..b184dc3a5c 100644
--- a/light/state.go
+++ b/light/state.go
@@ -17,13 +17,11 @@
package light
import (
+ "context"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
- "golang.org/x/net/context"
)
// LightState is a memory representation of a state.
@@ -239,10 +237,6 @@ func (self *LightState) GetOrNewStateObject(ctx context.Context, addr common.Add
// newStateObject creates a state object whether it exists in the state or not
func (self *LightState) newStateObject(addr common.Address) *StateObject {
- if glog.V(logger.Core) {
- glog.Infof("(+) %x\n", addr)
- }
-
stateObject := NewStateObject(addr, self.odr)
self.stateObjects[addr.Str()] = stateObject
@@ -268,6 +262,26 @@ func (self *LightState) CreateStateObject(ctx context.Context, addr common.Addre
return newSo, nil
}
+// ForEachStorage calls a callback function for every key/value pair found
+// in the local storage cache. Note that unlike core/state.StateObject,
+// light.StateObject only returns cached values and doesn't download the
+// entire storage tree.
+func (self *LightState) ForEachStorage(ctx context.Context, addr common.Address, cb func(key, value common.Hash) bool) error {
+ so, err := self.GetStateObject(ctx, addr)
+ if err != nil {
+ return err
+ }
+
+ if so == nil {
+ return nil
+ }
+
+ for h, v := range so.storage {
+ cb(h, v)
+ }
+ return nil
+}
+
//
// Setting, copying of the state methods
//
diff --git a/light/state_object.go b/light/state_object.go
index 56f607bffa..a54ea1d9ff 100644
--- a/light/state_object.go
+++ b/light/state_object.go
@@ -18,15 +18,13 @@ package light
import (
"bytes"
+ "context"
"fmt"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
"github.com/ethereum/go-ethereum/rlp"
- "golang.org/x/net/context"
)
var emptyCodeHash = crypto.Keccak256(nil)
@@ -108,10 +106,6 @@ func NewStateObject(address common.Address, odr OdrBackend) *StateObject {
func (self *StateObject) MarkForDeletion() {
self.remove = true
self.dirty = true
-
- if glog.V(logger.Core) {
- glog.Infof("%x: #%d %v X\n", self.Address(), self.nonce, self.balance)
- }
}
// getAddr gets the storage value at the given address from the trie
@@ -157,19 +151,11 @@ func (self *StateObject) SetState(k, value common.Hash) {
// AddBalance adds the given amount to the account balance
func (c *StateObject) AddBalance(amount *big.Int) {
c.SetBalance(new(big.Int).Add(c.balance, amount))
-
- if glog.V(logger.Core) {
- glog.Infof("%x: #%d %v (+ %v)\n", c.Address(), c.nonce, c.balance, amount)
- }
}
// SubBalance subtracts the given amount from the account balance
func (c *StateObject) SubBalance(amount *big.Int) {
c.SetBalance(new(big.Int).Sub(c.balance, amount))
-
- if glog.V(logger.Core) {
- glog.Infof("%x: #%d %v (- %v)\n", c.Address(), c.nonce, c.balance, amount)
- }
}
// SetBalance sets the account balance to the given amount
@@ -203,7 +189,7 @@ func (self *StateObject) Copy() *StateObject {
// empty returns whether the account is considered empty.
func (self *StateObject) empty() bool {
- return self.nonce == 0 && self.balance.BitLen() == 0 && bytes.Equal(self.codeHash, emptyCodeHash)
+ return self.nonce == 0 && self.balance.Sign() == 0 && bytes.Equal(self.codeHash, emptyCodeHash)
}
// Balance returns the account balance
diff --git a/light/state_test.go b/light/state_test.go
index d594ab9ff0..e776efec8e 100644
--- a/light/state_test.go
+++ b/light/state_test.go
@@ -18,6 +18,7 @@ package light
import (
"bytes"
+ "context"
"math/big"
"testing"
@@ -26,7 +27,6 @@ import (
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethdb"
- "golang.org/x/net/context"
)
func makeTestState() (common.Hash, ethdb.Database) {
diff --git a/light/trie.go b/light/trie.go
index c5525358a4..1440f2fbfd 100644
--- a/light/trie.go
+++ b/light/trie.go
@@ -17,9 +17,10 @@
package light
import (
+ "context"
+
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/trie"
- "golang.org/x/net/context"
)
// LightTrie is an ODR-capable wrapper around trie.SecureTrie
diff --git a/light/txpool.go b/light/txpool.go
index bcdb6123de..4461958065 100644
--- a/light/txpool.go
+++ b/light/txpool.go
@@ -17,6 +17,7 @@
package light
import (
+ "context"
"fmt"
"sync"
"time"
@@ -26,11 +27,9 @@ import (
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp"
- "golang.org/x/net/context"
)
// txPermanent is the number of mined blocks after a mined transaction is
@@ -231,13 +230,13 @@ func (pool *TxPool) rollbackTxs(hash common.Hash, txc txStateChanges) {
}
}
-// setNewHead sets a new head header, processing (and rolling back if necessary)
+// reorgOnNewHead sets a new head header, processing (and rolling back if necessary)
// the blocks since the last known head and returns a txStateChanges map containing
// the recently mined and rolled back transaction hashes. If an error (context
// timeout) occurs during checking new blocks, it leaves the locally known head
// at the latest checked block and still returns a valid txStateChanges, making it
// possible to continue checking the missing blocks at the next chain head event
-func (pool *TxPool) setNewHead(ctx context.Context, newHeader *types.Header) (txStateChanges, error) {
+func (pool *TxPool) reorgOnNewHead(ctx context.Context, newHeader *types.Header) (txStateChanges, error) {
txc := make(txStateChanges)
oldh := pool.chain.GetHeaderByHash(pool.head)
newh := newHeader
@@ -277,15 +276,17 @@ func (pool *TxPool) setNewHead(ctx context.Context, newHeader *types.Header) (tx
// clear old mined tx entries of old blocks
if idx := newHeader.Number.Uint64(); idx > pool.clearIdx+txPermanent {
idx2 := idx - txPermanent
- for i := pool.clearIdx; i < idx2; i++ {
- hash := core.GetCanonicalHash(pool.chainDb, i)
- if list, ok := pool.mined[hash]; ok {
- hashes := make([]common.Hash, len(list))
- for i, tx := range list {
- hashes[i] = tx.Hash()
+ if len(pool.mined) > 0 {
+ for i := pool.clearIdx; i < idx2; i++ {
+ hash := core.GetCanonicalHash(pool.chainDb, i)
+ if list, ok := pool.mined[hash]; ok {
+ hashes := make([]common.Hash, len(list))
+ for i, tx := range list {
+ hashes[i] = tx.Hash()
+ }
+ pool.relay.Discard(hashes)
+ delete(pool.mined, hash)
}
- pool.relay.Discard(hashes)
- delete(pool.mined, hash)
}
}
pool.clearIdx = idx2
@@ -304,24 +305,33 @@ func (pool *TxPool) eventLoop() {
for ev := range pool.events.Chan() {
switch ev.Data.(type) {
case core.ChainHeadEvent:
- pool.mu.Lock()
- ctx, _ := context.WithTimeout(context.Background(), blockCheckTimeout)
- head := pool.chain.CurrentHeader()
- txc, _ := pool.setNewHead(ctx, head)
- m, r := txc.getLists()
- pool.relay.NewHead(pool.head, m, r)
- pool.homestead = pool.config.IsHomestead(head.Number)
- pool.signer = types.MakeSigner(pool.config, head.Number)
- pool.mu.Unlock()
+ pool.setNewHead(ev.Data.(core.ChainHeadEvent).Block.Header())
+ // hack in order to avoid hogging the lock; this part will
+ // be replaced by a subsequent PR.
+ time.Sleep(time.Millisecond)
}
}
}
+func (pool *TxPool) setNewHead(head *types.Header) {
+ pool.mu.Lock()
+ defer pool.mu.Unlock()
+
+ ctx, cancel := context.WithTimeout(context.Background(), blockCheckTimeout)
+ defer cancel()
+
+ txc, _ := pool.reorgOnNewHead(ctx, head)
+ m, r := txc.getLists()
+ pool.relay.NewHead(pool.head, m, r)
+ pool.homestead = pool.config.IsHomestead(head.Number)
+ pool.signer = types.MakeSigner(pool.config, head.Number)
+}
+
// Stop stops the light transaction pool
func (pool *TxPool) Stop() {
close(pool.quit)
pool.events.Unsubscribe()
- glog.V(logger.Info).Infoln("Transaction pool stopped")
+ log.Info("Transaction pool stopped")
}
// Stats returns the number of currently pending (locally created) transactions
@@ -366,7 +376,7 @@ func (pool *TxPool) validateTx(ctx context.Context, tx *types.Transaction) error
// Transactions can't be negative. This may never happen
// using RLP decoded transactions but may occur if you create
// a transaction using the RPC for example.
- if tx.Value().Cmp(common.Big0) < 0 {
+ if tx.Value().Sign() < 0 {
return core.ErrNegativeValue
}
@@ -417,20 +427,8 @@ func (self *TxPool) add(ctx context.Context, tx *types.Transaction) error {
go self.eventMux.Post(core.TxPreEvent{Tx: tx})
}
- if glog.V(logger.Debug) {
- var toname string
- if to := tx.To(); to != nil {
- toname = common.Bytes2Hex(to[:4])
- } else {
- toname = "[NEW_CONTRACT]"
- }
- // we can ignore the error here because From is
- // verified in ValidateTransaction.
- f, _ := types.Sender(self.signer, tx)
- from := common.Bytes2Hex(f[:4])
- glog.Infof("(t) %x => %s (%v) %x\n", from, toname, tx.Value, hash)
- }
-
+ // Print a log message if low enough level is set
+ log.Debug("Pooled new transaction", "hash", hash, "from", log.Lazy{Fn: func() common.Address { from, _ := types.Sender(self.signer, tx); return from }}, "to", tx.To())
return nil
}
@@ -463,15 +461,10 @@ func (self *TxPool) AddBatch(ctx context.Context, txs []*types.Transaction) {
var sendTx types.Transactions
for _, tx := range txs {
- if err := self.add(ctx, tx); err != nil {
- glog.V(logger.Debug).Infoln("tx error:", err)
- } else {
+ if err := self.add(ctx, tx); err == nil {
sendTx = append(sendTx, tx)
- h := tx.Hash()
- glog.V(logger.Debug).Infof("tx %x\n", h[:4])
}
}
-
if len(sendTx) > 0 {
self.relay.Send(sendTx)
}
diff --git a/light/txpool_test.go b/light/txpool_test.go
index d8f04e6173..2b5fa7116d 100644
--- a/light/txpool_test.go
+++ b/light/txpool_test.go
@@ -17,6 +17,7 @@
package light
import (
+ "context"
"math"
"math/big"
"testing"
@@ -29,7 +30,7 @@ import (
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/params"
- "golang.org/x/net/context"
+ "github.com/ethereum/go-ethereum/pow"
)
type testTxRelay struct {
@@ -77,17 +78,18 @@ func txPoolTestChainGen(i int, block *core.BlockGen) {
func TestTxPool(t *testing.T) {
for i := range testTx {
- testTx[i], _ = types.SignTx(types.NewTransaction(uint64(i), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil), types.HomesteadSigner{}, testBankKey)
+ testTx[i], _ = types.SignTx(types.NewTransaction(uint64(i), acc1Addr, big.NewInt(10000), bigTxGas, nil, nil), types.HomesteadSigner{}, testBankKey)
}
var (
evmux = new(event.TypeMux)
- pow = new(core.FakePow)
+ pow = new(pow.FakePow)
sdb, _ = ethdb.NewMemDatabase()
ldb, _ = ethdb.NewMemDatabase()
- genesis = core.WriteGenesisBlockForTesting(sdb, core.GenesisAccount{Address: testBankAddress, Balance: testBankFunds})
+ gspec = core.Genesis{Alloc: core.GenesisAlloc{testBankAddress: {Balance: testBankFunds}}}
+ genesis = gspec.MustCommit(sdb)
)
- core.WriteGenesisBlockForTesting(ldb, core.GenesisAccount{Address: testBankAddress, Balance: testBankFunds})
+ gspec.MustCommit(ldb)
// Assemble the test environment
blockchain, _ := core.NewBlockChain(sdb, testChainConfig(), pow, evmux, vm.Config{})
chainConfig := ¶ms.ChainConfig{HomesteadBlock: new(big.Int)}
@@ -106,10 +108,11 @@ func TestTxPool(t *testing.T) {
lightchain.SetValidator(bproc{})
txPermanent = 50
pool := NewTxPool(testChainConfig(), evmux, lightchain, relay)
+ ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
+ defer cancel()
for ii, block := range gchain {
i := ii + 1
- ctx, _ := context.WithTimeout(context.Background(), 200*time.Millisecond)
s := sentTx(i - 1)
e := sentTx(i)
for i := s; i < e; i++ {
diff --git a/light/vm_env.go b/light/vm_env.go
index d2cc7e9608..54aa12875b 100644
--- a/light/vm_env.go
+++ b/light/vm_env.go
@@ -17,13 +17,12 @@
package light
import (
+ "context"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
- "github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto"
- "golang.org/x/net/context"
)
// VMState is a wrapper for the light state that holds the actual context and
@@ -64,27 +63,10 @@ func (self *VMState) RevertToSnapshot(idx int) {
self.snapshots = self.snapshots[:idx]
}
-// GetAccount returns the account object of the given account or nil if the
-// account does not exist
-func (s *VMState) GetAccount(addr common.Address) vm.Account {
- so, err := s.state.GetStateObject(s.ctx, addr)
- s.errHandler(err)
- if err != nil {
- // return a dummy state object to avoid panics
- so = s.state.newStateObject(addr)
- }
- return so
-}
-
// CreateAccount creates creates a new account object and takes ownership.
-func (s *VMState) CreateAccount(addr common.Address) vm.Account {
- so, err := s.state.CreateStateObject(s.ctx, addr)
+func (s *VMState) CreateAccount(addr common.Address) {
+ _, err := s.state.CreateStateObject(s.ctx, addr)
s.errHandler(err)
- if err != nil {
- // return a dummy state object to avoid panics
- so = s.state.newStateObject(addr)
- }
- return so
}
// AddBalance adds the given amount to the balance of the specified account
@@ -99,6 +81,15 @@ func (s *VMState) SubBalance(addr common.Address, amount *big.Int) {
s.errHandler(err)
}
+// ForEachStorage calls a callback function for every key/value pair found
+// in the local storage cache. Note that unlike core/state.StateObject,
+// light.StateObject only returns cached values and doesn't download the
+// entire storage tree.
+func (s *VMState) ForEachStorage(addr common.Address, cb func(key, value common.Hash) bool) {
+ err := s.state.ForEachStorage(s.ctx, addr, cb)
+ s.errHandler(err)
+}
+
// GetBalance retrieves the balance from the given address or 0 if the account does
// not exist
func (s *VMState) GetBalance(addr common.Address) *big.Int {
diff --git a/log/CONTRIBUTORS b/log/CONTRIBUTORS
new file mode 100644
index 0000000000..a0866713be
--- /dev/null
+++ b/log/CONTRIBUTORS
@@ -0,0 +1,11 @@
+Contributors to log15:
+
+- Aaron L
+- Alan Shreve
+- Chris Hines
+- Ciaran Downey
+- Dmitry Chestnykh
+- Evan Shaw
+- Péter Szilágyi
+- Trevor Gattis
+- Vincent Vanackere
diff --git a/log/LICENSE b/log/LICENSE
new file mode 100644
index 0000000000..5f0d1fb6a7
--- /dev/null
+++ b/log/LICENSE
@@ -0,0 +1,13 @@
+Copyright 2014 Alan Shreve
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/log/README.md b/log/README.md
new file mode 100644
index 0000000000..0951b21cb5
--- /dev/null
+++ b/log/README.md
@@ -0,0 +1,77 @@
+
+
+# log15 [](https://godoc.org/github.com/inconshreveable/log15) [](https://travis-ci.org/inconshreveable/log15)
+
+Package log15 provides an opinionated, simple toolkit for best-practice logging in Go (golang) that is both human and machine readable. It is modeled after the Go standard library's [`io`](http://golang.org/pkg/io/) and [`net/http`](http://golang.org/pkg/net/http/) packages and is an alternative to the standard library's [`log`](http://golang.org/pkg/log/) package.
+
+## Features
+- A simple, easy-to-understand API
+- Promotes structured logging by encouraging use of key/value pairs
+- Child loggers which inherit and add their own private context
+- Lazy evaluation of expensive operations
+- Simple Handler interface allowing for construction of flexible, custom logging configurations with a tiny API.
+- Color terminal support
+- Built-in support for logging to files, streams, syslog, and the network
+- Support for forking records to multiple handlers, buffering records for output, failing over from failed handler writes, + more
+
+## Versioning
+The API of the master branch of log15 should always be considered unstable. If you want to rely on a stable API,
+you must vendor the library.
+
+## Importing
+
+```go
+import log "github.com/inconshreveable/log15"
+```
+
+## Examples
+
+```go
+// all loggers can have key/value context
+srvlog := log.New("module", "app/server")
+
+// all log messages can have key/value context
+srvlog.Warn("abnormal conn rate", "rate", curRate, "low", lowRate, "high", highRate)
+
+// child loggers with inherited context
+connlog := srvlog.New("raddr", c.RemoteAddr())
+connlog.Info("connection open")
+
+// lazy evaluation
+connlog.Debug("ping remote", "latency", log.Lazy{pingRemote})
+
+// flexible configuration
+srvlog.SetHandler(log.MultiHandler(
+ log.StreamHandler(os.Stderr, log.LogfmtFormat()),
+ log.LvlFilterHandler(
+ log.LvlError,
+ log.Must.FileHandler("errors.json", log.JsonFormat()))))
+```
+
+Will result in output that looks like this:
+
+```
+WARN[06-17|21:58:10] abnormal conn rate module=app/server rate=0.500 low=0.100 high=0.800
+INFO[06-17|21:58:10] connection open module=app/server raddr=10.0.0.1
+```
+
+## Breaking API Changes
+The following commits broke API stability. This reference is intended to help you understand the consequences of updating to a newer version
+of log15.
+
+- 57a084d014d4150152b19e4e531399a7145d1540 - Added a `Get()` method to the `Logger` interface to retrieve the current handler
+- 93404652ee366648fa622b64d1e2b67d75a3094a - `Record` field `Call` changed to `stack.Call` with switch to `github.com/go-stack/stack`
+- a5e7613673c73281f58e15a87d2cf0cf111e8152 - Restored `syslog.Priority` argument to the `SyslogXxx` handler constructors
+
+## FAQ
+
+### The varargs style is brittle and error prone! Can I have type safety please?
+Yes. Use `log.Ctx`:
+
+```go
+srvlog := log.New(log.Ctx{"module": "app/server"})
+srvlog.Warn("abnormal conn rate", log.Ctx{"rate": curRate, "low": lowRate, "high": highRate})
+```
+
+## License
+Apache
diff --git a/log/README_ETHEREUM.md b/log/README_ETHEREUM.md
new file mode 100644
index 0000000000..f6c42ccc03
--- /dev/null
+++ b/log/README_ETHEREUM.md
@@ -0,0 +1,5 @@
+This package is a fork of https://github.com/inconshreveable/log15, with some
+minor modifications required by the go-ethereum codebase:
+
+ * Support for log level `trace`
+ * Modified behavior to exit on `critical` failure
diff --git a/log/doc.go b/log/doc.go
new file mode 100644
index 0000000000..83ad8c54f6
--- /dev/null
+++ b/log/doc.go
@@ -0,0 +1,333 @@
+/*
+Package log15 provides an opinionated, simple toolkit for best-practice logging that is
+both human and machine readable. It is modeled after the standard library's io and net/http
+packages.
+
+This package enforces you to only log key/value pairs. Keys must be strings. Values may be
+any type that you like. The default output format is logfmt, but you may also choose to use
+JSON instead if that suits you. Here's how you log:
+
+ log.Info("page accessed", "path", r.URL.Path, "user_id", user.id)
+
+This will output a line that looks like:
+
+ lvl=info t=2014-05-02T16:07:23-0700 msg="page accessed" path=/org/71/profile user_id=9
+
+Getting Started
+
+To get started, you'll want to import the library:
+
+ import log "github.com/inconshreveable/log15"
+
+
+Now you're ready to start logging:
+
+ func main() {
+ log.Info("Program starting", "args", os.Args())
+ }
+
+
+Convention
+
+Because recording a human-meaningful message is common and good practice, the first argument to every
+logging method is the value to the *implicit* key 'msg'.
+
+Additionally, the level you choose for a message will be automatically added with the key 'lvl', and so
+will the current timestamp with key 't'.
+
+You may supply any additional context as a set of key/value pairs to the logging function. log15 allows
+you to favor terseness, ordering, and speed over safety. This is a reasonable tradeoff for
+logging functions. You don't need to explicitly state keys/values, log15 understands that they alternate
+in the variadic argument list:
+
+ log.Warn("size out of bounds", "low", lowBound, "high", highBound, "val", val)
+
+If you really do favor your type-safety, you may choose to pass a log.Ctx instead:
+
+ log.Warn("size out of bounds", log.Ctx{"low": lowBound, "high": highBound, "val": val})
+
+
+Context loggers
+
+Frequently, you want to add context to a logger so that you can track actions associated with it. An http
+request is a good example. You can easily create new loggers that have context that is automatically included
+with each log line:
+
+ requestlogger := log.New("path", r.URL.Path)
+
+ // later
+ requestlogger.Debug("db txn commit", "duration", txnTimer.Finish())
+
+This will output a log line that includes the path context that is attached to the logger:
+
+ lvl=dbug t=2014-05-02T16:07:23-0700 path=/repo/12/add_hook msg="db txn commit" duration=0.12
+
+
+Handlers
+
+The Handler interface defines where log lines are printed to and how they are formated. Handler is a
+single interface that is inspired by net/http's handler interface:
+
+ type Handler interface {
+ Log(r *Record) error
+ }
+
+
+Handlers can filter records, format them, or dispatch to multiple other Handlers.
+This package implements a number of Handlers for common logging patterns that are
+easily composed to create flexible, custom logging structures.
+
+Here's an example handler that prints logfmt output to Stdout:
+
+ handler := log.StreamHandler(os.Stdout, log.LogfmtFormat())
+
+Here's an example handler that defers to two other handlers. One handler only prints records
+from the rpc package in logfmt to standard out. The other prints records at Error level
+or above in JSON formatted output to the file /var/log/service.json
+
+ handler := log.MultiHandler(
+ log.LvlFilterHandler(log.LvlError, log.Must.FileHandler("/var/log/service.json", log.JsonFormat())),
+ log.MatchFilterHandler("pkg", "app/rpc" log.StdoutHandler())
+ )
+
+Logging File Names and Line Numbers
+
+This package implements three Handlers that add debugging information to the
+context, CallerFileHandler, CallerFuncHandler and CallerStackHandler. Here's
+an example that adds the source file and line number of each logging call to
+the context.
+
+ h := log.CallerFileHandler(log.StdoutHandler)
+ log.Root().SetHandler(h)
+ ...
+ log.Error("open file", "err", err)
+
+This will output a line that looks like:
+
+ lvl=eror t=2014-05-02T16:07:23-0700 msg="open file" err="file not found" caller=data.go:42
+
+Here's an example that logs the call stack rather than just the call site.
+
+ h := log.CallerStackHandler("%+v", log.StdoutHandler)
+ log.Root().SetHandler(h)
+ ...
+ log.Error("open file", "err", err)
+
+This will output a line that looks like:
+
+ lvl=eror t=2014-05-02T16:07:23-0700 msg="open file" err="file not found" stack="[pkg/data.go:42 pkg/cmd/main.go]"
+
+The "%+v" format instructs the handler to include the path of the source file
+relative to the compile time GOPATH. The github.com/go-stack/stack package
+documents the full list of formatting verbs and modifiers available.
+
+Custom Handlers
+
+The Handler interface is so simple that it's also trivial to write your own. Let's create an
+example handler which tries to write to one handler, but if that fails it falls back to
+writing to another handler and includes the error that it encountered when trying to write
+to the primary. This might be useful when trying to log over a network socket, but if that
+fails you want to log those records to a file on disk.
+
+ type BackupHandler struct {
+ Primary Handler
+ Secondary Handler
+ }
+
+ func (h *BackupHandler) Log (r *Record) error {
+ err := h.Primary.Log(r)
+ if err != nil {
+ r.Ctx = append(ctx, "primary_err", err)
+ return h.Secondary.Log(r)
+ }
+ return nil
+ }
+
+This pattern is so useful that a generic version that handles an arbitrary number of Handlers
+is included as part of this library called FailoverHandler.
+
+Logging Expensive Operations
+
+Sometimes, you want to log values that are extremely expensive to compute, but you don't want to pay
+the price of computing them if you haven't turned up your logging level to a high level of detail.
+
+This package provides a simple type to annotate a logging operation that you want to be evaluated
+lazily, just when it is about to be logged, so that it would not be evaluated if an upstream Handler
+filters it out. Just wrap any function which takes no arguments with the log.Lazy type. For example:
+
+ func factorRSAKey() (factors []int) {
+ // return the factors of a very large number
+ }
+
+ log.Debug("factors", log.Lazy{factorRSAKey})
+
+If this message is not logged for any reason (like logging at the Error level), then
+factorRSAKey is never evaluated.
+
+Dynamic context values
+
+The same log.Lazy mechanism can be used to attach context to a logger which you want to be
+evaluated when the message is logged, but not when the logger is created. For example, let's imagine
+a game where you have Player objects:
+
+ type Player struct {
+ name string
+ alive bool
+ log.Logger
+ }
+
+You always want to log a player's name and whether they're alive or dead, so when you create the player
+object, you might do:
+
+ p := &Player{name: name, alive: true}
+ p.Logger = log.New("name", p.name, "alive", p.alive)
+
+Only now, even after a player has died, the logger will still report they are alive because the logging
+context is evaluated when the logger was created. By using the Lazy wrapper, we can defer the evaluation
+of whether the player is alive or not to each log message, so that the log records will reflect the player's
+current state no matter when the log message is written:
+
+ p := &Player{name: name, alive: true}
+ isAlive := func() bool { return p.alive }
+ player.Logger = log.New("name", p.name, "alive", log.Lazy{isAlive})
+
+Terminal Format
+
+If log15 detects that stdout is a terminal, it will configure the default
+handler for it (which is log.StdoutHandler) to use TerminalFormat. This format
+logs records nicely for your terminal, including color-coded output based
+on log level.
+
+Error Handling
+
+Becasuse log15 allows you to step around the type system, there are a few ways you can specify
+invalid arguments to the logging functions. You could, for example, wrap something that is not
+a zero-argument function with log.Lazy or pass a context key that is not a string. Since logging libraries
+are typically the mechanism by which errors are reported, it would be onerous for the logging functions
+to return errors. Instead, log15 handles errors by making these guarantees to you:
+
+- Any log record containing an error will still be printed with the error explained to you as part of the log record.
+
+- Any log record containing an error will include the context key LOG15_ERROR, enabling you to easily
+(and if you like, automatically) detect if any of your logging calls are passing bad values.
+
+Understanding this, you might wonder why the Handler interface can return an error value in its Log method. Handlers
+are encouraged to return errors only if they fail to write their log records out to an external source like if the
+syslog daemon is not responding. This allows the construction of useful handlers which cope with those failures
+like the FailoverHandler.
+
+Library Use
+
+log15 is intended to be useful for library authors as a way to provide configurable logging to
+users of their library. Best practice for use in a library is to always disable all output for your logger
+by default and to provide a public Logger instance that consumers of your library can configure. Like so:
+
+ package yourlib
+
+ import "github.com/inconshreveable/log15"
+
+ var Log = log.New()
+
+ func init() {
+ Log.SetHandler(log.DiscardHandler())
+ }
+
+Users of your library may then enable it if they like:
+
+ import "github.com/inconshreveable/log15"
+ import "example.com/yourlib"
+
+ func main() {
+ handler := // custom handler setup
+ yourlib.Log.SetHandler(handler)
+ }
+
+Best practices attaching logger context
+
+The ability to attach context to a logger is a powerful one. Where should you do it and why?
+I favor embedding a Logger directly into any persistent object in my application and adding
+unique, tracing context keys to it. For instance, imagine I am writing a web browser:
+
+ type Tab struct {
+ url string
+ render *RenderingContext
+ // ...
+
+ Logger
+ }
+
+ func NewTab(url string) *Tab {
+ return &Tab {
+ // ...
+ url: url,
+
+ Logger: log.New("url", url),
+ }
+ }
+
+When a new tab is created, I assign a logger to it with the url of
+the tab as context so it can easily be traced through the logs.
+Now, whenever we perform any operation with the tab, we'll log with its
+embedded logger and it will include the tab title automatically:
+
+ tab.Debug("moved position", "idx", tab.idx)
+
+There's only one problem. What if the tab url changes? We could
+use log.Lazy to make sure the current url is always written, but that
+would mean that we couldn't trace a tab's full lifetime through our
+logs after the user navigate to a new URL.
+
+Instead, think about what values to attach to your loggers the
+same way you think about what to use as a key in a SQL database schema.
+If it's possible to use a natural key that is unique for the lifetime of the
+object, do so. But otherwise, log15's ext package has a handy RandId
+function to let you generate what you might call "surrogate keys"
+They're just random hex identifiers to use for tracing. Back to our
+Tab example, we would prefer to set up our Logger like so:
+
+ import logext "github.com/inconshreveable/log15/ext"
+
+ t := &Tab {
+ // ...
+ url: url,
+ }
+
+ t.Logger = log.New("id", logext.RandId(8), "url", log.Lazy{t.getUrl})
+ return t
+
+Now we'll have a unique traceable identifier even across loading new urls, but
+we'll still be able to see the tab's current url in the log messages.
+
+Must
+
+For all Handler functions which can return an error, there is a version of that
+function which will return no error but panics on failure. They are all available
+on the Must object. For example:
+
+ log.Must.FileHandler("/path", log.JsonFormat)
+ log.Must.NetHandler("tcp", ":1234", log.JsonFormat)
+
+Inspiration and Credit
+
+All of the following excellent projects inspired the design of this library:
+
+code.google.com/p/log4go
+
+github.com/op/go-logging
+
+github.com/technoweenie/grohl
+
+github.com/Sirupsen/logrus
+
+github.com/kr/logfmt
+
+github.com/spacemonkeygo/spacelog
+
+golang's stdlib, notably io and net/http
+
+The Name
+
+https://xkcd.com/927/
+
+*/
+package log
diff --git a/log/format.go b/log/format.go
new file mode 100644
index 0000000000..e315b5237d
--- /dev/null
+++ b/log/format.go
@@ -0,0 +1,363 @@
+package log
+
+import (
+ "bytes"
+ "encoding/json"
+ "fmt"
+ "reflect"
+ "strconv"
+ "strings"
+ "sync"
+ "sync/atomic"
+ "time"
+ "unicode/utf8"
+)
+
+const (
+ timeFormat = "2006-01-02T15:04:05-0700"
+ termTimeFormat = "01-02|15:04:05"
+ floatFormat = 'f'
+ termMsgJust = 40
+)
+
+// locationTrims are trimmed for display to avoid unwieldy log lines.
+var locationTrims = []string{
+ "github.com/ethereum/go-ethereum/",
+}
+
+// PrintOrigins sets or unsets log location (file:line) printing for terminal
+// format output.
+func PrintOrigins(print bool) {
+ if print {
+ atomic.StoreUint32(&locationEnabled, 1)
+ } else {
+ atomic.StoreUint32(&locationEnabled, 0)
+ }
+}
+
+// locationEnabled is an atomic flag controlling whether the terminal formatter
+// should append the log locations too when printing entries.
+var locationEnabled uint32
+
+// locationLength is the maxmimum path length encountered, which all logs are
+// padded to to aid in alignment.
+var locationLength uint32
+
+// fieldPadding is a global map with maximum field value lengths seen until now
+// to allow padding log contexts in a bit smarter way.
+var fieldPadding = make(map[string]int)
+
+// fieldPaddingLock is a global mutex protecting the field padding map.
+var fieldPaddingLock sync.RWMutex
+
+type Format interface {
+ Format(r *Record) []byte
+}
+
+// FormatFunc returns a new Format object which uses
+// the given function to perform record formatting.
+func FormatFunc(f func(*Record) []byte) Format {
+ return formatFunc(f)
+}
+
+type formatFunc func(*Record) []byte
+
+func (f formatFunc) Format(r *Record) []byte {
+ return f(r)
+}
+
+// TerminalStringer is an analogous interface to the stdlib stringer, allowing
+// own types to have custom shortened serialization formats when printed to the
+// screen.
+type TerminalStringer interface {
+ TerminalString() string
+}
+
+// TerminalFormat formats log records optimized for human readability on
+// a terminal with color-coded level output and terser human friendly timestamp.
+// This format should only be used for interactive programs or while developing.
+//
+// [TIME] [LEVEL] MESAGE key=value key=value ...
+//
+// Example:
+//
+// [May 16 20:58:45] [DBUG] remove route ns=haproxy addr=127.0.0.1:50002
+//
+func TerminalFormat(usecolor bool) Format {
+ return FormatFunc(func(r *Record) []byte {
+ var color = 0
+ if usecolor {
+ switch r.Lvl {
+ case LvlCrit:
+ color = 35
+ case LvlError:
+ color = 31
+ case LvlWarn:
+ color = 33
+ case LvlInfo:
+ color = 32
+ case LvlDebug:
+ color = 36
+ case LvlTrace:
+ color = 34
+ }
+ }
+
+ b := &bytes.Buffer{}
+ lvl := r.Lvl.AlignedString()
+ if atomic.LoadUint32(&locationEnabled) != 0 {
+ // Log origin printing was requested, format the location path and line number
+ location := fmt.Sprintf("%+v", r.Call)
+ for _, prefix := range locationTrims {
+ location = strings.TrimPrefix(location, prefix)
+ }
+ // Maintain the maximum location length for fancyer alignment
+ align := int(atomic.LoadUint32(&locationLength))
+ if align < len(location) {
+ align = len(location)
+ atomic.StoreUint32(&locationLength, uint32(align))
+ }
+ padding := strings.Repeat(" ", align-len(location))
+
+ // Assemble and print the log heading
+ if color > 0 {
+ fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%s|%s]%s %s ", color, lvl, r.Time.Format(termTimeFormat), location, padding, r.Msg)
+ } else {
+ fmt.Fprintf(b, "%s[%s|%s]%s %s ", lvl, r.Time.Format(termTimeFormat), location, padding, r.Msg)
+ }
+ } else {
+ if color > 0 {
+ fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%s] %s ", color, lvl, r.Time.Format(termTimeFormat), r.Msg)
+ } else {
+ fmt.Fprintf(b, "%s[%s] %s ", lvl, r.Time.Format(termTimeFormat), r.Msg)
+ }
+ }
+ // try to justify the log output for short messages
+ if len(r.Ctx) > 0 && len(r.Msg) < termMsgJust {
+ b.Write(bytes.Repeat([]byte{' '}, termMsgJust-len(r.Msg)))
+ }
+
+ // print the keys logfmt style
+ logfmt(b, r.Ctx, color, true)
+ return b.Bytes()
+ })
+}
+
+// LogfmtFormat prints records in logfmt format, an easy machine-parseable but human-readable
+// format for key/value pairs.
+//
+// For more details see: http://godoc.org/github.com/kr/logfmt
+//
+func LogfmtFormat() Format {
+ return FormatFunc(func(r *Record) []byte {
+ common := []interface{}{r.KeyNames.Time, r.Time, r.KeyNames.Lvl, r.Lvl, r.KeyNames.Msg, r.Msg}
+ buf := &bytes.Buffer{}
+ logfmt(buf, append(common, r.Ctx...), 0, false)
+ return buf.Bytes()
+ })
+}
+
+func logfmt(buf *bytes.Buffer, ctx []interface{}, color int, term bool) {
+ for i := 0; i < len(ctx); i += 2 {
+ if i != 0 {
+ buf.WriteByte(' ')
+ }
+
+ k, ok := ctx[i].(string)
+ v := formatLogfmtValue(ctx[i+1], term)
+ if !ok {
+ k, v = errorKey, formatLogfmtValue(k, term)
+ }
+
+ // XXX: we should probably check that all of your key bytes aren't invalid
+ fieldPaddingLock.RLock()
+ padding := fieldPadding[k]
+ fieldPaddingLock.RUnlock()
+
+ length := utf8.RuneCountInString(v)
+ if padding < length {
+ padding = length
+
+ fieldPaddingLock.Lock()
+ fieldPadding[k] = padding
+ fieldPaddingLock.Unlock()
+ }
+ if color > 0 {
+ fmt.Fprintf(buf, "\x1b[%dm%s\x1b[0m=", color, k)
+ } else {
+ buf.WriteString(k)
+ buf.WriteByte('=')
+ }
+ buf.WriteString(v)
+ if i < len(ctx)-2 {
+ buf.Write(bytes.Repeat([]byte{' '}, padding-length))
+ }
+ }
+ buf.WriteByte('\n')
+}
+
+// JsonFormat formats log records as JSON objects separated by newlines.
+// It is the equivalent of JsonFormatEx(false, true).
+func JsonFormat() Format {
+ return JsonFormatEx(false, true)
+}
+
+// JsonFormatEx formats log records as JSON objects. If pretty is true,
+// records will be pretty-printed. If lineSeparated is true, records
+// will be logged with a new line between each record.
+func JsonFormatEx(pretty, lineSeparated bool) Format {
+ jsonMarshal := json.Marshal
+ if pretty {
+ jsonMarshal = func(v interface{}) ([]byte, error) {
+ return json.MarshalIndent(v, "", " ")
+ }
+ }
+
+ return FormatFunc(func(r *Record) []byte {
+ props := make(map[string]interface{})
+
+ props[r.KeyNames.Time] = r.Time
+ props[r.KeyNames.Lvl] = r.Lvl.String()
+ props[r.KeyNames.Msg] = r.Msg
+
+ for i := 0; i < len(r.Ctx); i += 2 {
+ k, ok := r.Ctx[i].(string)
+ if !ok {
+ props[errorKey] = fmt.Sprintf("%+v is not a string key", r.Ctx[i])
+ }
+ props[k] = formatJsonValue(r.Ctx[i+1])
+ }
+
+ b, err := jsonMarshal(props)
+ if err != nil {
+ b, _ = jsonMarshal(map[string]string{
+ errorKey: err.Error(),
+ })
+ return b
+ }
+
+ if lineSeparated {
+ b = append(b, '\n')
+ }
+
+ return b
+ })
+}
+
+func formatShared(value interface{}) (result interface{}) {
+ defer func() {
+ if err := recover(); err != nil {
+ if v := reflect.ValueOf(value); v.Kind() == reflect.Ptr && v.IsNil() {
+ result = "nil"
+ } else {
+ panic(err)
+ }
+ }
+ }()
+
+ switch v := value.(type) {
+ case time.Time:
+ return v.Format(timeFormat)
+
+ case error:
+ return v.Error()
+
+ case fmt.Stringer:
+ return v.String()
+
+ default:
+ return v
+ }
+}
+
+func formatJsonValue(value interface{}) interface{} {
+ value = formatShared(value)
+ switch value.(type) {
+ case int, int8, int16, int32, int64, float32, float64, uint, uint8, uint16, uint32, uint64, string:
+ return value
+ default:
+ return fmt.Sprintf("%+v", value)
+ }
+}
+
+// formatValue formats a value for serialization
+func formatLogfmtValue(value interface{}, term bool) string {
+ if value == nil {
+ return "nil"
+ }
+
+ if t, ok := value.(time.Time); ok {
+ // Performance optimization: No need for escaping since the provided
+ // timeFormat doesn't have any escape characters, and escaping is
+ // expensive.
+ return t.Format(timeFormat)
+ }
+ if term {
+ if s, ok := value.(TerminalStringer); ok {
+ // Custom terminal stringer provided, use that
+ return escapeString(s.TerminalString())
+ }
+ }
+ value = formatShared(value)
+ switch v := value.(type) {
+ case bool:
+ return strconv.FormatBool(v)
+ case float32:
+ return strconv.FormatFloat(float64(v), floatFormat, 3, 64)
+ case float64:
+ return strconv.FormatFloat(v, floatFormat, 3, 64)
+ case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64:
+ return fmt.Sprintf("%d", value)
+ case string:
+ return escapeString(v)
+ default:
+ return escapeString(fmt.Sprintf("%+v", value))
+ }
+}
+
+var stringBufPool = sync.Pool{
+ New: func() interface{} { return new(bytes.Buffer) },
+}
+
+func escapeString(s string) string {
+ needsQuotes := false
+ needsEscape := false
+ for _, r := range s {
+ if r <= ' ' || r == '=' || r == '"' {
+ needsQuotes = true
+ }
+ if r == '\\' || r == '"' || r == '\n' || r == '\r' || r == '\t' {
+ needsEscape = true
+ }
+ }
+ if needsEscape == false && needsQuotes == false {
+ return s
+ }
+ e := stringBufPool.Get().(*bytes.Buffer)
+ e.WriteByte('"')
+ for _, r := range s {
+ switch r {
+ case '\\', '"':
+ e.WriteByte('\\')
+ e.WriteByte(byte(r))
+ case '\n':
+ e.WriteString("\\n")
+ case '\r':
+ e.WriteString("\\r")
+ case '\t':
+ e.WriteString("\\t")
+ default:
+ e.WriteRune(r)
+ }
+ }
+ e.WriteByte('"')
+ var ret string
+ if needsQuotes {
+ ret = e.String()
+ } else {
+ ret = string(e.Bytes()[1 : e.Len()-1])
+ }
+ e.Reset()
+ stringBufPool.Put(e)
+ return ret
+}
diff --git a/log/handler.go b/log/handler.go
new file mode 100644
index 0000000000..d5594b853d
--- /dev/null
+++ b/log/handler.go
@@ -0,0 +1,361 @@
+package log
+
+import (
+ "fmt"
+ "io"
+ "net"
+ "os"
+ "reflect"
+ "sync"
+
+ "github.com/go-stack/stack"
+)
+
+// A Logger prints its log records by writing to a Handler.
+// The Handler interface defines where and how log records are written.
+// Handlers are composable, providing you great flexibility in combining
+// them to achieve the logging structure that suits your applications.
+type Handler interface {
+ Log(r *Record) error
+}
+
+// FuncHandler returns a Handler that logs records with the given
+// function.
+func FuncHandler(fn func(r *Record) error) Handler {
+ return funcHandler(fn)
+}
+
+type funcHandler func(r *Record) error
+
+func (h funcHandler) Log(r *Record) error {
+ return h(r)
+}
+
+// StreamHandler writes log records to an io.Writer
+// with the given format. StreamHandler can be used
+// to easily begin writing log records to other
+// outputs.
+//
+// StreamHandler wraps itself with LazyHandler and SyncHandler
+// to evaluate Lazy objects and perform safe concurrent writes.
+func StreamHandler(wr io.Writer, fmtr Format) Handler {
+ h := FuncHandler(func(r *Record) error {
+ _, err := wr.Write(fmtr.Format(r))
+ return err
+ })
+ return LazyHandler(SyncHandler(h))
+}
+
+// SyncHandler can be wrapped around a handler to guarantee that
+// only a single Log operation can proceed at a time. It's necessary
+// for thread-safe concurrent writes.
+func SyncHandler(h Handler) Handler {
+ var mu sync.Mutex
+ return FuncHandler(func(r *Record) error {
+ defer mu.Unlock()
+ mu.Lock()
+ return h.Log(r)
+ })
+}
+
+// FileHandler returns a handler which writes log records to the give file
+// using the given format. If the path
+// already exists, FileHandler will append to the given file. If it does not,
+// FileHandler will create the file with mode 0644.
+func FileHandler(path string, fmtr Format) (Handler, error) {
+ f, err := os.OpenFile(path, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
+ if err != nil {
+ return nil, err
+ }
+ return closingHandler{f, StreamHandler(f, fmtr)}, nil
+}
+
+// NetHandler opens a socket to the given address and writes records
+// over the connection.
+func NetHandler(network, addr string, fmtr Format) (Handler, error) {
+ conn, err := net.Dial(network, addr)
+ if err != nil {
+ return nil, err
+ }
+
+ return closingHandler{conn, StreamHandler(conn, fmtr)}, nil
+}
+
+// XXX: closingHandler is essentially unused at the moment
+// it's meant for a future time when the Handler interface supports
+// a possible Close() operation
+type closingHandler struct {
+ io.WriteCloser
+ Handler
+}
+
+func (h *closingHandler) Close() error {
+ return h.WriteCloser.Close()
+}
+
+// CallerFileHandler returns a Handler that adds the line number and file of
+// the calling function to the context with key "caller".
+func CallerFileHandler(h Handler) Handler {
+ return FuncHandler(func(r *Record) error {
+ r.Ctx = append(r.Ctx, "caller", fmt.Sprint(r.Call))
+ return h.Log(r)
+ })
+}
+
+// CallerFuncHandler returns a Handler that adds the calling function name to
+// the context with key "fn".
+func CallerFuncHandler(h Handler) Handler {
+ return FuncHandler(func(r *Record) error {
+ r.Ctx = append(r.Ctx, "fn", formatCall("%+n", r.Call))
+ return h.Log(r)
+ })
+}
+
+// This function is here to please go vet on Go < 1.8.
+func formatCall(format string, c stack.Call) string {
+ return fmt.Sprintf(format, c)
+}
+
+// CallerStackHandler returns a Handler that adds a stack trace to the context
+// with key "stack". The stack trace is formated as a space separated list of
+// call sites inside matching []'s. The most recent call site is listed first.
+// Each call site is formatted according to format. See the documentation of
+// package github.com/go-stack/stack for the list of supported formats.
+func CallerStackHandler(format string, h Handler) Handler {
+ return FuncHandler(func(r *Record) error {
+ s := stack.Trace().TrimBelow(r.Call).TrimRuntime()
+ if len(s) > 0 {
+ r.Ctx = append(r.Ctx, "stack", fmt.Sprintf(format, s))
+ }
+ return h.Log(r)
+ })
+}
+
+// FilterHandler returns a Handler that only writes records to the
+// wrapped Handler if the given function evaluates true. For example,
+// to only log records where the 'err' key is not nil:
+//
+// logger.SetHandler(FilterHandler(func(r *Record) bool {
+// for i := 0; i < len(r.Ctx); i += 2 {
+// if r.Ctx[i] == "err" {
+// return r.Ctx[i+1] != nil
+// }
+// }
+// return false
+// }, h))
+//
+func FilterHandler(fn func(r *Record) bool, h Handler) Handler {
+ return FuncHandler(func(r *Record) error {
+ if fn(r) {
+ return h.Log(r)
+ }
+ return nil
+ })
+}
+
+// MatchFilterHandler returns a Handler that only writes records
+// to the wrapped Handler if the given key in the logged
+// context matches the value. For example, to only log records
+// from your ui package:
+//
+// log.MatchFilterHandler("pkg", "app/ui", log.StdoutHandler)
+//
+func MatchFilterHandler(key string, value interface{}, h Handler) Handler {
+ return FilterHandler(func(r *Record) (pass bool) {
+ switch key {
+ case r.KeyNames.Lvl:
+ return r.Lvl == value
+ case r.KeyNames.Time:
+ return r.Time == value
+ case r.KeyNames.Msg:
+ return r.Msg == value
+ }
+
+ for i := 0; i < len(r.Ctx); i += 2 {
+ if r.Ctx[i] == key {
+ return r.Ctx[i+1] == value
+ }
+ }
+ return false
+ }, h)
+}
+
+// LvlFilterHandler returns a Handler that only writes
+// records which are less than the given verbosity
+// level to the wrapped Handler. For example, to only
+// log Error/Crit records:
+//
+// log.LvlFilterHandler(log.LvlError, log.StdoutHandler)
+//
+func LvlFilterHandler(maxLvl Lvl, h Handler) Handler {
+ return FilterHandler(func(r *Record) (pass bool) {
+ return r.Lvl <= maxLvl
+ }, h)
+}
+
+// A MultiHandler dispatches any write to each of its handlers.
+// This is useful for writing different types of log information
+// to different locations. For example, to log to a file and
+// standard error:
+//
+// log.MultiHandler(
+// log.Must.FileHandler("/var/log/app.log", log.LogfmtFormat()),
+// log.StderrHandler)
+//
+func MultiHandler(hs ...Handler) Handler {
+ return FuncHandler(func(r *Record) error {
+ for _, h := range hs {
+ // what to do about failures?
+ h.Log(r)
+ }
+ return nil
+ })
+}
+
+// A FailoverHandler writes all log records to the first handler
+// specified, but will failover and write to the second handler if
+// the first handler has failed, and so on for all handlers specified.
+// For example you might want to log to a network socket, but failover
+// to writing to a file if the network fails, and then to
+// standard out if the file write fails:
+//
+// log.FailoverHandler(
+// log.Must.NetHandler("tcp", ":9090", log.JsonFormat()),
+// log.Must.FileHandler("/var/log/app.log", log.LogfmtFormat()),
+// log.StdoutHandler)
+//
+// All writes that do not go to the first handler will add context with keys of
+// the form "failover_err_{idx}" which explain the error encountered while
+// trying to write to the handlers before them in the list.
+func FailoverHandler(hs ...Handler) Handler {
+ return FuncHandler(func(r *Record) error {
+ var err error
+ for i, h := range hs {
+ err = h.Log(r)
+ if err == nil {
+ return nil
+ } else {
+ r.Ctx = append(r.Ctx, fmt.Sprintf("failover_err_%d", i), err)
+ }
+ }
+
+ return err
+ })
+}
+
+// ChannelHandler writes all records to the given channel.
+// It blocks if the channel is full. Useful for async processing
+// of log messages, it's used by BufferedHandler.
+func ChannelHandler(recs chan<- *Record) Handler {
+ return FuncHandler(func(r *Record) error {
+ recs <- r
+ return nil
+ })
+}
+
+// BufferedHandler writes all records to a buffered
+// channel of the given size which flushes into the wrapped
+// handler whenever it is available for writing. Since these
+// writes happen asynchronously, all writes to a BufferedHandler
+// never return an error and any errors from the wrapped handler are ignored.
+func BufferedHandler(bufSize int, h Handler) Handler {
+ recs := make(chan *Record, bufSize)
+ go func() {
+ for m := range recs {
+ _ = h.Log(m)
+ }
+ }()
+ return ChannelHandler(recs)
+}
+
+// LazyHandler writes all values to the wrapped handler after evaluating
+// any lazy functions in the record's context. It is already wrapped
+// around StreamHandler and SyslogHandler in this library, you'll only need
+// it if you write your own Handler.
+func LazyHandler(h Handler) Handler {
+ return FuncHandler(func(r *Record) error {
+ // go through the values (odd indices) and reassign
+ // the values of any lazy fn to the result of its execution
+ hadErr := false
+ for i := 1; i < len(r.Ctx); i += 2 {
+ lz, ok := r.Ctx[i].(Lazy)
+ if ok {
+ v, err := evaluateLazy(lz)
+ if err != nil {
+ hadErr = true
+ r.Ctx[i] = err
+ } else {
+ if cs, ok := v.(stack.CallStack); ok {
+ v = cs.TrimBelow(r.Call).TrimRuntime()
+ }
+ r.Ctx[i] = v
+ }
+ }
+ }
+
+ if hadErr {
+ r.Ctx = append(r.Ctx, errorKey, "bad lazy")
+ }
+
+ return h.Log(r)
+ })
+}
+
+func evaluateLazy(lz Lazy) (interface{}, error) {
+ t := reflect.TypeOf(lz.Fn)
+
+ if t.Kind() != reflect.Func {
+ return nil, fmt.Errorf("INVALID_LAZY, not func: %+v", lz.Fn)
+ }
+
+ if t.NumIn() > 0 {
+ return nil, fmt.Errorf("INVALID_LAZY, func takes args: %+v", lz.Fn)
+ }
+
+ if t.NumOut() == 0 {
+ return nil, fmt.Errorf("INVALID_LAZY, no func return val: %+v", lz.Fn)
+ }
+
+ value := reflect.ValueOf(lz.Fn)
+ results := value.Call([]reflect.Value{})
+ if len(results) == 1 {
+ return results[0].Interface(), nil
+ } else {
+ values := make([]interface{}, len(results))
+ for i, v := range results {
+ values[i] = v.Interface()
+ }
+ return values, nil
+ }
+}
+
+// DiscardHandler reports success for all writes but does nothing.
+// It is useful for dynamically disabling logging at runtime via
+// a Logger's SetHandler method.
+func DiscardHandler() Handler {
+ return FuncHandler(func(r *Record) error {
+ return nil
+ })
+}
+
+// The Must object provides the following Handler creation functions
+// which instead of returning an error parameter only return a Handler
+// and panic on failure: FileHandler, NetHandler, SyslogHandler, SyslogNetHandler
+var Must muster
+
+func must(h Handler, err error) Handler {
+ if err != nil {
+ panic(err)
+ }
+ return h
+}
+
+type muster struct{}
+
+func (m muster) FileHandler(path string, fmtr Format) Handler {
+ return must(FileHandler(path, fmtr))
+}
+
+func (m muster) NetHandler(network, addr string, fmtr Format) Handler {
+ return must(NetHandler(network, addr, fmtr))
+}
diff --git a/log/handler_glog.go b/log/handler_glog.go
new file mode 100644
index 0000000000..f8b932fd1b
--- /dev/null
+++ b/log/handler_glog.go
@@ -0,0 +1,227 @@
+// Copyright 2017 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+package log
+
+import (
+ "errors"
+ "fmt"
+ "regexp"
+ "runtime"
+ "strconv"
+ "strings"
+ "sync"
+ "sync/atomic"
+)
+
+// errVmoduleSyntax is returned when a user vmodule pattern is invalid.
+var errVmoduleSyntax = errors.New("expect comma-separated list of filename=N")
+
+// errTraceSyntax is returned when a user backtrace pattern is invalid.
+var errTraceSyntax = errors.New("expect file.go:234")
+
+// GlogHandler is a log handler that mimics the filtering features of Google's
+// glog logger: setting global log levels; overriding with callsite pattern
+// matches; and requesting backtraces at certain positions.
+type GlogHandler struct {
+ origin Handler // The origin handler this wraps
+
+ level uint32 // Current log level, atomically accessible
+ override uint32 // Flag whether overrides are used, atomically accessible
+ backtrace uint32 // Flag whether backtrace location is set
+
+ patterns []pattern // Current list of patterns to override with
+ siteCache map[uintptr]Lvl // Cache of callsite pattern evaluations
+ location string // file:line location where to do a stackdump at
+ lock sync.RWMutex // Lock protecting the override pattern list
+}
+
+// NewGlogHandler creates a new log handler with filtering functionality similar
+// to Google's glog logger. The returned handler implements Handler.
+func NewGlogHandler(h Handler) *GlogHandler {
+ return &GlogHandler{
+ origin: h,
+ }
+}
+
+// pattern contains a filter for the Vmodule option, holding a verbosity level
+// and a file pattern to match.
+type pattern struct {
+ pattern *regexp.Regexp
+ level Lvl
+}
+
+// Verbosity sets the glog verbosity ceiling. The verbosity of individual packages
+// and source files can be raised using Vmodule.
+func (h *GlogHandler) Verbosity(level Lvl) {
+ atomic.StoreUint32(&h.level, uint32(level))
+}
+
+// Vmodule sets the glog verbosity pattern.
+//
+// The syntax of the argument is a comma-separated list of pattern=N, where the
+// pattern is a literal file name or "glob" pattern matching and N is a V level.
+//
+// For instance:
+//
+// pattern="gopher.go=3"
+// sets the V level to 3 in all Go files named "gopher.go"
+//
+// pattern="foo=3"
+// sets V to 3 in all files of any packages whose import path ends in "foo"
+//
+// pattern="foo/*=3"
+// sets V to 3 in all files of any packages whose import path contains "foo"
+func (h *GlogHandler) Vmodule(ruleset string) error {
+ var filter []pattern
+ for _, rule := range strings.Split(ruleset, ",") {
+ // Empty strings such as from a trailing comma can be ignored
+ if len(rule) == 0 {
+ continue
+ }
+ // Ensure we have a pattern = level filter rule
+ parts := strings.Split(rule, "=")
+ if len(parts) != 2 {
+ return errVmoduleSyntax
+ }
+ parts[0] = strings.TrimSpace(parts[0])
+ parts[1] = strings.TrimSpace(parts[1])
+ if len(parts[0]) == 0 || len(parts[1]) == 0 {
+ return errVmoduleSyntax
+ }
+ // Parse the level and if correct, assemble the filter rule
+ level, err := strconv.Atoi(parts[1])
+ if err != nil {
+ return errVmoduleSyntax
+ }
+ if level <= 0 {
+ continue // Ignore. It's harmless but no point in paying the overhead.
+ }
+ // Compile the rule pattern into a regular expression
+ matcher := ".*"
+ for _, comp := range strings.Split(parts[0], "/") {
+ if comp == "*" {
+ matcher += "(/.*)?"
+ } else if comp != "" {
+ matcher += "/" + regexp.QuoteMeta(comp)
+ }
+ }
+ if !strings.HasSuffix(parts[0], ".go") {
+ matcher += "/[^/]+\\.go"
+ }
+ matcher = matcher + "$"
+
+ re, _ := regexp.Compile(matcher)
+ filter = append(filter, pattern{re, Lvl(level)})
+ }
+ // Swap out the vmodule pattern for the new filter system
+ h.lock.Lock()
+ defer h.lock.Unlock()
+
+ h.patterns = filter
+ h.siteCache = make(map[uintptr]Lvl)
+ atomic.StoreUint32(&h.override, uint32(len(filter)))
+
+ return nil
+}
+
+// BacktraceAt sets the glog backtrace location. When set to a file and line
+// number holding a logging statement, a stack trace will be written to the Info
+// log whenever execution hits that statement.
+//
+// Unlike with Vmodule, the ".go" must be present.
+func (h *GlogHandler) BacktraceAt(location string) error {
+ // Ensure the backtrace location contains two non-empty elements
+ parts := strings.Split(location, ":")
+ if len(parts) != 2 {
+ return errTraceSyntax
+ }
+ parts[0] = strings.TrimSpace(parts[0])
+ parts[1] = strings.TrimSpace(parts[1])
+ if len(parts[0]) == 0 || len(parts[1]) == 0 {
+ return errTraceSyntax
+ }
+ // Ensure the .go prefix is present and the line is valid
+ if !strings.HasSuffix(parts[0], ".go") {
+ return errTraceSyntax
+ }
+ if _, err := strconv.Atoi(parts[1]); err != nil {
+ return errTraceSyntax
+ }
+ // All seems valid
+ h.lock.Lock()
+ defer h.lock.Unlock()
+
+ h.location = location
+ atomic.StoreUint32(&h.backtrace, uint32(len(location)))
+
+ return nil
+}
+
+// Log implements Handler.Log, filtering a log record through the global, local
+// and backtrace filters, finally emitting it if either allow it through.
+func (h *GlogHandler) Log(r *Record) error {
+ // If backtracing is requested, check whether this is the callsite
+ if atomic.LoadUint32(&h.backtrace) > 0 {
+ // Everything below here is slow. Although we could cache the call sites the
+ // same way as for vmodule, backtracing is so rare it's not worth the extra
+ // complexity.
+ h.lock.RLock()
+ match := h.location == r.Call.String()
+ h.lock.RUnlock()
+
+ if match {
+ // Callsite matched, raise the log level to info and gather the stacks
+ r.Lvl = LvlInfo
+
+ buf := make([]byte, 1024*1024)
+ buf = buf[:runtime.Stack(buf, true)]
+ r.Msg += "\n\n" + string(buf)
+ }
+ }
+ // If the global log level allows, fast track logging
+ if atomic.LoadUint32(&h.level) >= uint32(r.Lvl) {
+ return h.origin.Log(r)
+ }
+ // If no local overrides are present, fast track skipping
+ if atomic.LoadUint32(&h.override) == 0 {
+ return nil
+ }
+ // Check callsite cache for previously calculated log levels
+ h.lock.RLock()
+ lvl, ok := h.siteCache[r.Call.PC()]
+ h.lock.RUnlock()
+
+ // If we didn't cache the callsite yet, calculate it
+ if !ok {
+ h.lock.Lock()
+ for _, rule := range h.patterns {
+ if rule.pattern.MatchString(fmt.Sprintf("%+s", r.Call)) {
+ h.siteCache[r.Call.PC()], lvl, ok = rule.level, rule.level, true
+ break
+ }
+ }
+ // If no rule matched, remember to drop log the next time
+ if !ok {
+ h.siteCache[r.Call.PC()] = 0
+ }
+ h.lock.Unlock()
+ }
+ if lvl >= r.Lvl {
+ return h.origin.Log(r)
+ }
+ return nil
+}
diff --git a/log/handler_go13.go b/log/handler_go13.go
new file mode 100644
index 0000000000..0843ed0e5f
--- /dev/null
+++ b/log/handler_go13.go
@@ -0,0 +1,26 @@
+// +build !go1.4
+
+package log
+
+import (
+ "sync/atomic"
+ "unsafe"
+)
+
+// swapHandler wraps another handler that may be swapped out
+// dynamically at runtime in a thread-safe fashion.
+type swapHandler struct {
+ handler unsafe.Pointer
+}
+
+func (h *swapHandler) Log(r *Record) error {
+ return h.Get().Log(r)
+}
+
+func (h *swapHandler) Get() Handler {
+ return *(*Handler)(atomic.LoadPointer(&h.handler))
+}
+
+func (h *swapHandler) Swap(newHandler Handler) {
+ atomic.StorePointer(&h.handler, unsafe.Pointer(&newHandler))
+}
diff --git a/log/handler_go14.go b/log/handler_go14.go
new file mode 100644
index 0000000000..05dedbf2a7
--- /dev/null
+++ b/log/handler_go14.go
@@ -0,0 +1,23 @@
+// +build go1.4
+
+package log
+
+import "sync/atomic"
+
+// swapHandler wraps another handler that may be swapped out
+// dynamically at runtime in a thread-safe fashion.
+type swapHandler struct {
+ handler atomic.Value
+}
+
+func (h *swapHandler) Log(r *Record) error {
+ return (*h.handler.Load().(*Handler)).Log(r)
+}
+
+func (h *swapHandler) Swap(newHandler Handler) {
+ h.handler.Store(&newHandler)
+}
+
+func (h *swapHandler) Get() Handler {
+ return *h.handler.Load().(*Handler)
+}
diff --git a/log/logger.go b/log/logger.go
new file mode 100644
index 0000000000..15c83a9b25
--- /dev/null
+++ b/log/logger.go
@@ -0,0 +1,240 @@
+package log
+
+import (
+ "fmt"
+ "os"
+ "time"
+
+ "github.com/go-stack/stack"
+)
+
+const timeKey = "t"
+const lvlKey = "lvl"
+const msgKey = "msg"
+const errorKey = "LOG15_ERROR"
+
+type Lvl int
+
+const (
+ LvlCrit Lvl = iota
+ LvlError
+ LvlWarn
+ LvlInfo
+ LvlDebug
+ LvlTrace
+)
+
+// Aligned returns a 5-character string containing the name of a Lvl.
+func (l Lvl) AlignedString() string {
+ switch l {
+ case LvlTrace:
+ return "TRACE"
+ case LvlDebug:
+ return "DEBUG"
+ case LvlInfo:
+ return "INFO "
+ case LvlWarn:
+ return "WARN "
+ case LvlError:
+ return "ERROR"
+ case LvlCrit:
+ return "CRIT "
+ default:
+ panic("bad level")
+ }
+}
+
+// Strings returns the name of a Lvl.
+func (l Lvl) String() string {
+ switch l {
+ case LvlTrace:
+ return "trce"
+ case LvlDebug:
+ return "dbug"
+ case LvlInfo:
+ return "info"
+ case LvlWarn:
+ return "warn"
+ case LvlError:
+ return "eror"
+ case LvlCrit:
+ return "crit"
+ default:
+ panic("bad level")
+ }
+}
+
+// Returns the appropriate Lvl from a string name.
+// Useful for parsing command line args and configuration files.
+func LvlFromString(lvlString string) (Lvl, error) {
+ switch lvlString {
+ case "trace", "trce":
+ return LvlTrace, nil
+ case "debug", "dbug":
+ return LvlDebug, nil
+ case "info":
+ return LvlInfo, nil
+ case "warn":
+ return LvlWarn, nil
+ case "error", "eror":
+ return LvlError, nil
+ case "crit":
+ return LvlCrit, nil
+ default:
+ return LvlDebug, fmt.Errorf("Unknown level: %v", lvlString)
+ }
+}
+
+// A Record is what a Logger asks its handler to write
+type Record struct {
+ Time time.Time
+ Lvl Lvl
+ Msg string
+ Ctx []interface{}
+ Call stack.Call
+ KeyNames RecordKeyNames
+}
+
+type RecordKeyNames struct {
+ Time string
+ Msg string
+ Lvl string
+}
+
+// A Logger writes key/value pairs to a Handler
+type Logger interface {
+ // New returns a new Logger that has this logger's context plus the given context
+ New(ctx ...interface{}) Logger
+
+ // GetHandler gets the handler associated with the logger.
+ GetHandler() Handler
+
+ // SetHandler updates the logger to write records to the specified handler.
+ SetHandler(h Handler)
+
+ // Log a message at the given level with context key/value pairs
+ Trace(msg string, ctx ...interface{})
+ Debug(msg string, ctx ...interface{})
+ Info(msg string, ctx ...interface{})
+ Warn(msg string, ctx ...interface{})
+ Error(msg string, ctx ...interface{})
+ Crit(msg string, ctx ...interface{})
+}
+
+type logger struct {
+ ctx []interface{}
+ h *swapHandler
+}
+
+func (l *logger) write(msg string, lvl Lvl, ctx []interface{}) {
+ l.h.Log(&Record{
+ Time: time.Now(),
+ Lvl: lvl,
+ Msg: msg,
+ Ctx: newContext(l.ctx, ctx),
+ Call: stack.Caller(2),
+ KeyNames: RecordKeyNames{
+ Time: timeKey,
+ Msg: msgKey,
+ Lvl: lvlKey,
+ },
+ })
+}
+
+func (l *logger) New(ctx ...interface{}) Logger {
+ child := &logger{newContext(l.ctx, ctx), new(swapHandler)}
+ child.SetHandler(l.h)
+ return child
+}
+
+func newContext(prefix []interface{}, suffix []interface{}) []interface{} {
+ normalizedSuffix := normalize(suffix)
+ newCtx := make([]interface{}, len(prefix)+len(normalizedSuffix))
+ n := copy(newCtx, prefix)
+ copy(newCtx[n:], normalizedSuffix)
+ return newCtx
+}
+
+func (l *logger) Trace(msg string, ctx ...interface{}) {
+ l.write(msg, LvlTrace, ctx)
+}
+
+func (l *logger) Debug(msg string, ctx ...interface{}) {
+ l.write(msg, LvlDebug, ctx)
+}
+
+func (l *logger) Info(msg string, ctx ...interface{}) {
+ l.write(msg, LvlInfo, ctx)
+}
+
+func (l *logger) Warn(msg string, ctx ...interface{}) {
+ l.write(msg, LvlWarn, ctx)
+}
+
+func (l *logger) Error(msg string, ctx ...interface{}) {
+ l.write(msg, LvlError, ctx)
+}
+
+func (l *logger) Crit(msg string, ctx ...interface{}) {
+ l.write(msg, LvlCrit, ctx)
+ os.Exit(1)
+}
+
+func (l *logger) GetHandler() Handler {
+ return l.h.Get()
+}
+
+func (l *logger) SetHandler(h Handler) {
+ l.h.Swap(h)
+}
+
+func normalize(ctx []interface{}) []interface{} {
+ // if the caller passed a Ctx object, then expand it
+ if len(ctx) == 1 {
+ if ctxMap, ok := ctx[0].(Ctx); ok {
+ ctx = ctxMap.toArray()
+ }
+ }
+
+ // ctx needs to be even because it's a series of key/value pairs
+ // no one wants to check for errors on logging functions,
+ // so instead of erroring on bad input, we'll just make sure
+ // that things are the right length and users can fix bugs
+ // when they see the output looks wrong
+ if len(ctx)%2 != 0 {
+ ctx = append(ctx, nil, errorKey, "Normalized odd number of arguments by adding nil")
+ }
+
+ return ctx
+}
+
+// Lazy allows you to defer calculation of a logged value that is expensive
+// to compute until it is certain that it must be evaluated with the given filters.
+//
+// Lazy may also be used in conjunction with a Logger's New() function
+// to generate a child logger which always reports the current value of changing
+// state.
+//
+// You may wrap any function which takes no arguments to Lazy. It may return any
+// number of values of any type.
+type Lazy struct {
+ Fn interface{}
+}
+
+// Ctx is a map of key/value pairs to pass as context to a log function
+// Use this only if you really need greater safety around the arguments you pass
+// to the logging functions.
+type Ctx map[string]interface{}
+
+func (c Ctx) toArray() []interface{} {
+ arr := make([]interface{}, len(c)*2)
+
+ i := 0
+ for k, v := range c {
+ arr[i] = k
+ arr[i+1] = v
+ i += 2
+ }
+
+ return arr
+}
diff --git a/log/root.go b/log/root.go
new file mode 100644
index 0000000000..71b8cef6d4
--- /dev/null
+++ b/log/root.go
@@ -0,0 +1,61 @@
+package log
+
+import (
+ "os"
+)
+
+var (
+ root = &logger{[]interface{}{}, new(swapHandler)}
+ StdoutHandler = StreamHandler(os.Stdout, LogfmtFormat())
+ StderrHandler = StreamHandler(os.Stderr, LogfmtFormat())
+)
+
+func init() {
+ root.SetHandler(DiscardHandler())
+}
+
+// New returns a new logger with the given context.
+// New is a convenient alias for Root().New
+func New(ctx ...interface{}) Logger {
+ return root.New(ctx...)
+}
+
+// Root returns the root logger
+func Root() Logger {
+ return root
+}
+
+// The following functions bypass the exported logger methods (logger.Debug,
+// etc.) to keep the call depth the same for all paths to logger.write so
+// runtime.Caller(2) always refers to the call site in client code.
+
+// Trace is a convenient alias for Root().Trace
+func Trace(msg string, ctx ...interface{}) {
+ root.write(msg, LvlTrace, ctx)
+}
+
+// Debug is a convenient alias for Root().Debug
+func Debug(msg string, ctx ...interface{}) {
+ root.write(msg, LvlDebug, ctx)
+}
+
+// Info is a convenient alias for Root().Info
+func Info(msg string, ctx ...interface{}) {
+ root.write(msg, LvlInfo, ctx)
+}
+
+// Warn is a convenient alias for Root().Warn
+func Warn(msg string, ctx ...interface{}) {
+ root.write(msg, LvlWarn, ctx)
+}
+
+// Error is a convenient alias for Root().Error
+func Error(msg string, ctx ...interface{}) {
+ root.write(msg, LvlError, ctx)
+}
+
+// Crit is a convenient alias for Root().Crit
+func Crit(msg string, ctx ...interface{}) {
+ root.write(msg, LvlCrit, ctx)
+ os.Exit(1)
+}
diff --git a/log/syslog.go b/log/syslog.go
new file mode 100644
index 0000000000..71a17b30b3
--- /dev/null
+++ b/log/syslog.go
@@ -0,0 +1,57 @@
+// +build !windows,!plan9
+
+package log
+
+import (
+ "log/syslog"
+ "strings"
+)
+
+// SyslogHandler opens a connection to the system syslog daemon by calling
+// syslog.New and writes all records to it.
+func SyslogHandler(priority syslog.Priority, tag string, fmtr Format) (Handler, error) {
+ wr, err := syslog.New(priority, tag)
+ return sharedSyslog(fmtr, wr, err)
+}
+
+// SyslogNetHandler opens a connection to a log daemon over the network and writes
+// all log records to it.
+func SyslogNetHandler(net, addr string, priority syslog.Priority, tag string, fmtr Format) (Handler, error) {
+ wr, err := syslog.Dial(net, addr, priority, tag)
+ return sharedSyslog(fmtr, wr, err)
+}
+
+func sharedSyslog(fmtr Format, sysWr *syslog.Writer, err error) (Handler, error) {
+ if err != nil {
+ return nil, err
+ }
+ h := FuncHandler(func(r *Record) error {
+ var syslogFn = sysWr.Info
+ switch r.Lvl {
+ case LvlCrit:
+ syslogFn = sysWr.Crit
+ case LvlError:
+ syslogFn = sysWr.Err
+ case LvlWarn:
+ syslogFn = sysWr.Warning
+ case LvlInfo:
+ syslogFn = sysWr.Info
+ case LvlDebug:
+ syslogFn = sysWr.Debug
+ case LvlTrace:
+ syslogFn = func(m string) error { return nil } // There's no syslog level for trace
+ }
+
+ s := strings.TrimSpace(string(fmtr.Format(r)))
+ return syslogFn(s)
+ })
+ return LazyHandler(&closingHandler{sysWr, h}), nil
+}
+
+func (m muster) SyslogHandler(priority syslog.Priority, tag string, fmtr Format) Handler {
+ return must(SyslogHandler(priority, tag, fmtr))
+}
+
+func (m muster) SyslogNetHandler(net, addr string, priority syslog.Priority, tag string, fmtr Format) Handler {
+ return must(SyslogNetHandler(net, addr, priority, tag, fmtr))
+}
diff --git a/log/term/LICENSE b/log/term/LICENSE
new file mode 100644
index 0000000000..f090cb42f3
--- /dev/null
+++ b/log/term/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2014 Simon Eskildsen
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/log/term/terminal_appengine.go b/log/term/terminal_appengine.go
new file mode 100644
index 0000000000..c1b5d2a3b1
--- /dev/null
+++ b/log/term/terminal_appengine.go
@@ -0,0 +1,13 @@
+// Based on ssh/terminal:
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build appengine
+
+package term
+
+// IsTty always returns false on AppEngine.
+func IsTty(fd uintptr) bool {
+ return false
+}
diff --git a/log/term/terminal_darwin.go b/log/term/terminal_darwin.go
new file mode 100644
index 0000000000..d8f351b1b1
--- /dev/null
+++ b/log/term/terminal_darwin.go
@@ -0,0 +1,13 @@
+// Based on ssh/terminal:
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+// +build !appengine
+
+package term
+
+import "syscall"
+
+const ioctlReadTermios = syscall.TIOCGETA
+
+type Termios syscall.Termios
diff --git a/log/term/terminal_freebsd.go b/log/term/terminal_freebsd.go
new file mode 100644
index 0000000000..cfaceab337
--- /dev/null
+++ b/log/term/terminal_freebsd.go
@@ -0,0 +1,18 @@
+package term
+
+import (
+ "syscall"
+)
+
+const ioctlReadTermios = syscall.TIOCGETA
+
+// Go 1.2 doesn't include Termios for FreeBSD. This should be added in 1.3 and this could be merged with terminal_darwin.
+type Termios struct {
+ Iflag uint32
+ Oflag uint32
+ Cflag uint32
+ Lflag uint32
+ Cc [20]uint8
+ Ispeed uint32
+ Ospeed uint32
+}
diff --git a/log/term/terminal_linux.go b/log/term/terminal_linux.go
new file mode 100644
index 0000000000..5290468d69
--- /dev/null
+++ b/log/term/terminal_linux.go
@@ -0,0 +1,14 @@
+// Based on ssh/terminal:
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !appengine
+
+package term
+
+import "syscall"
+
+const ioctlReadTermios = syscall.TCGETS
+
+type Termios syscall.Termios
diff --git a/log/term/terminal_netbsd.go b/log/term/terminal_netbsd.go
new file mode 100644
index 0000000000..f9bb9e1c23
--- /dev/null
+++ b/log/term/terminal_netbsd.go
@@ -0,0 +1,7 @@
+package term
+
+import "syscall"
+
+const ioctlReadTermios = syscall.TIOCGETA
+
+type Termios syscall.Termios
diff --git a/log/term/terminal_notwindows.go b/log/term/terminal_notwindows.go
new file mode 100644
index 0000000000..c9af534f62
--- /dev/null
+++ b/log/term/terminal_notwindows.go
@@ -0,0 +1,20 @@
+// Based on ssh/terminal:
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build linux,!appengine darwin freebsd openbsd netbsd
+
+package term
+
+import (
+ "syscall"
+ "unsafe"
+)
+
+// IsTty returns true if the given file descriptor is a terminal.
+func IsTty(fd uintptr) bool {
+ var termios Termios
+ _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, fd, ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0)
+ return err == 0
+}
diff --git a/log/term/terminal_openbsd.go b/log/term/terminal_openbsd.go
new file mode 100644
index 0000000000..f9bb9e1c23
--- /dev/null
+++ b/log/term/terminal_openbsd.go
@@ -0,0 +1,7 @@
+package term
+
+import "syscall"
+
+const ioctlReadTermios = syscall.TIOCGETA
+
+type Termios syscall.Termios
diff --git a/log/term/terminal_solaris.go b/log/term/terminal_solaris.go
new file mode 100644
index 0000000000..033c163246
--- /dev/null
+++ b/log/term/terminal_solaris.go
@@ -0,0 +1,9 @@
+package term
+
+import "golang.org/x/sys/unix"
+
+// IsTty returns true if the given file descriptor is a terminal.
+func IsTty(fd uintptr) bool {
+ _, err := unix.IoctlGetTermios(int(fd), unix.TCGETA)
+ return err == nil
+}
diff --git a/log/term/terminal_windows.go b/log/term/terminal_windows.go
new file mode 100644
index 0000000000..df3c30c158
--- /dev/null
+++ b/log/term/terminal_windows.go
@@ -0,0 +1,26 @@
+// Based on ssh/terminal:
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build windows
+
+package term
+
+import (
+ "syscall"
+ "unsafe"
+)
+
+var kernel32 = syscall.NewLazyDLL("kernel32.dll")
+
+var (
+ procGetConsoleMode = kernel32.NewProc("GetConsoleMode")
+)
+
+// IsTty returns true if the given file descriptor is a terminal.
+func IsTty(fd uintptr) bool {
+ var st uint32
+ r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, fd, uintptr(unsafe.Pointer(&st)), 0)
+ return r != 0 && e == 0
+}
diff --git a/logger/glog/LICENSE b/logger/glog/LICENSE
deleted file mode 100644
index 37ec93a14f..0000000000
--- a/logger/glog/LICENSE
+++ /dev/null
@@ -1,191 +0,0 @@
-Apache License
-Version 2.0, January 2004
-http://www.apache.org/licenses/
-
-TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
-1. Definitions.
-
-"License" shall mean the terms and conditions for use, reproduction, and
-distribution as defined by Sections 1 through 9 of this document.
-
-"Licensor" shall mean the copyright owner or entity authorized by the copyright
-owner that is granting the License.
-
-"Legal Entity" shall mean the union of the acting entity and all other entities
-that control, are controlled by, or are under common control with that entity.
-For the purposes of this definition, "control" means (i) the power, direct or
-indirect, to cause the direction or management of such entity, whether by
-contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the
-outstanding shares, or (iii) beneficial ownership of such entity.
-
-"You" (or "Your") shall mean an individual or Legal Entity exercising
-permissions granted by this License.
-
-"Source" form shall mean the preferred form for making modifications, including
-but not limited to software source code, documentation source, and configuration
-files.
-
-"Object" form shall mean any form resulting from mechanical transformation or
-translation of a Source form, including but not limited to compiled object code,
-generated documentation, and conversions to other media types.
-
-"Work" shall mean the work of authorship, whether in Source or Object form, made
-available under the License, as indicated by a copyright notice that is included
-in or attached to the work (an example is provided in the Appendix below).
-
-"Derivative Works" shall mean any work, whether in Source or Object form, that
-is based on (or derived from) the Work and for which the editorial revisions,
-annotations, elaborations, or other modifications represent, as a whole, an
-original work of authorship. For the purposes of this License, Derivative Works
-shall not include works that remain separable from, or merely link (or bind by
-name) to the interfaces of, the Work and Derivative Works thereof.
-
-"Contribution" shall mean any work of authorship, including the original version
-of the Work and any modifications or additions to that Work or Derivative Works
-thereof, that is intentionally submitted to Licensor for inclusion in the Work
-by the copyright owner or by an individual or Legal Entity authorized to submit
-on behalf of the copyright owner. For the purposes of this definition,
-"submitted" means any form of electronic, verbal, or written communication sent
-to the Licensor or its representatives, including but not limited to
-communication on electronic mailing lists, source code control systems, and
-issue tracking systems that are managed by, or on behalf of, the Licensor for
-the purpose of discussing and improving the Work, but excluding communication
-that is conspicuously marked or otherwise designated in writing by the copyright
-owner as "Not a Contribution."
-
-"Contributor" shall mean Licensor and any individual or Legal Entity on behalf
-of whom a Contribution has been received by Licensor and subsequently
-incorporated within the Work.
-
-2. Grant of Copyright License.
-
-Subject to the terms and conditions of this License, each Contributor hereby
-grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
-irrevocable copyright license to reproduce, prepare Derivative Works of,
-publicly display, publicly perform, sublicense, and distribute the Work and such
-Derivative Works in Source or Object form.
-
-3. Grant of Patent License.
-
-Subject to the terms and conditions of this License, each Contributor hereby
-grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
-irrevocable (except as stated in this section) patent license to make, have
-made, use, offer to sell, sell, import, and otherwise transfer the Work, where
-such license applies only to those patent claims licensable by such Contributor
-that are necessarily infringed by their Contribution(s) alone or by combination
-of their Contribution(s) with the Work to which such Contribution(s) was
-submitted. If You institute patent litigation against any entity (including a
-cross-claim or counterclaim in a lawsuit) alleging that the Work or a
-Contribution incorporated within the Work constitutes direct or contributory
-patent infringement, then any patent licenses granted to You under this License
-for that Work shall terminate as of the date such litigation is filed.
-
-4. Redistribution.
-
-You may reproduce and distribute copies of the Work or Derivative Works thereof
-in any medium, with or without modifications, and in Source or Object form,
-provided that You meet the following conditions:
-
-You must give any other recipients of the Work or Derivative Works a copy of
-this License; and
-You must cause any modified files to carry prominent notices stating that You
-changed the files; and
-You must retain, in the Source form of any Derivative Works that You distribute,
-all copyright, patent, trademark, and attribution notices from the Source form
-of the Work, excluding those notices that do not pertain to any part of the
-Derivative Works; and
-If the Work includes a "NOTICE" text file as part of its distribution, then any
-Derivative Works that You distribute must include a readable copy of the
-attribution notices contained within such NOTICE file, excluding those notices
-that do not pertain to any part of the Derivative Works, in at least one of the
-following places: within a NOTICE text file distributed as part of the
-Derivative Works; within the Source form or documentation, if provided along
-with the Derivative Works; or, within a display generated by the Derivative
-Works, if and wherever such third-party notices normally appear. The contents of
-the NOTICE file are for informational purposes only and do not modify the
-License. You may add Your own attribution notices within Derivative Works that
-You distribute, alongside or as an addendum to the NOTICE text from the Work,
-provided that such additional attribution notices cannot be construed as
-modifying the License.
-You may add Your own copyright statement to Your modifications and may provide
-additional or different license terms and conditions for use, reproduction, or
-distribution of Your modifications, or for any such Derivative Works as a whole,
-provided Your use, reproduction, and distribution of the Work otherwise complies
-with the conditions stated in this License.
-
-5. Submission of Contributions.
-
-Unless You explicitly state otherwise, any Contribution intentionally submitted
-for inclusion in the Work by You to the Licensor shall be under the terms and
-conditions of this License, without any additional terms or conditions.
-Notwithstanding the above, nothing herein shall supersede or modify the terms of
-any separate license agreement you may have executed with Licensor regarding
-such Contributions.
-
-6. Trademarks.
-
-This License does not grant permission to use the trade names, trademarks,
-service marks, or product names of the Licensor, except as required for
-reasonable and customary use in describing the origin of the Work and
-reproducing the content of the NOTICE file.
-
-7. Disclaimer of Warranty.
-
-Unless required by applicable law or agreed to in writing, Licensor provides the
-Work (and each Contributor provides its Contributions) on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
-including, without limitation, any warranties or conditions of TITLE,
-NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are
-solely responsible for determining the appropriateness of using or
-redistributing the Work and assume any risks associated with Your exercise of
-permissions under this License.
-
-8. Limitation of Liability.
-
-In no event and under no legal theory, whether in tort (including negligence),
-contract, or otherwise, unless required by applicable law (such as deliberate
-and grossly negligent acts) or agreed to in writing, shall any Contributor be
-liable to You for damages, including any direct, indirect, special, incidental,
-or consequential damages of any character arising as a result of this License or
-out of the use or inability to use the Work (including but not limited to
-damages for loss of goodwill, work stoppage, computer failure or malfunction, or
-any and all other commercial damages or losses), even if such Contributor has
-been advised of the possibility of such damages.
-
-9. Accepting Warranty or Additional Liability.
-
-While redistributing the Work or Derivative Works thereof, You may choose to
-offer, and charge a fee for, acceptance of support, warranty, indemnity, or
-other liability obligations and/or rights consistent with this License. However,
-in accepting such obligations, You may act only on Your own behalf and on Your
-sole responsibility, not on behalf of any other Contributor, and only if You
-agree to indemnify, defend, and hold each Contributor harmless for any liability
-incurred by, or claims asserted against, such Contributor by reason of your
-accepting any such warranty or additional liability.
-
-END OF TERMS AND CONDITIONS
-
-APPENDIX: How to apply the Apache License to your work
-
-To apply the Apache License to your work, attach the following boilerplate
-notice, with the fields enclosed by brackets "[]" replaced with your own
-identifying information. (Don't include the brackets!) The text should be
-enclosed in the appropriate comment syntax for the file format. We also
-recommend that a file or class name and description of purpose be included on
-the same "printed page" as the copyright notice for easier identification within
-third-party archives.
-
- Copyright [yyyy] [name of copyright owner]
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
diff --git a/logger/glog/README b/logger/glog/README
deleted file mode 100644
index c7b1e60cc1..0000000000
--- a/logger/glog/README
+++ /dev/null
@@ -1,44 +0,0 @@
-glog
-====
-
-Leveled execution logs for Go.
-
-This is an efficient pure Go implementation of leveled logs in the
-manner of the open source C++ package
- http://code.google.com/p/google-glog
-
-By binding methods to booleans it is possible to use the log package
-without paying the expense of evaluating the arguments to the log.
-Through the -vmodule flag, the package also provides fine-grained
-control over logging at the file level.
-
-The comment from glog.go introduces the ideas:
-
- Package glog implements logging analogous to the Google-internal
- C++ INFO/ERROR/V setup. It provides functions Info, Warning,
- Error, Fatal, plus formatting variants such as Infof. It
- also provides V-style logging controlled by the -v and
- -vmodule=file=2 flags.
-
- Basic examples:
-
- glog.Info("Prepare to repel boarders")
-
- glog.Fatalf("Initialization failed: %s", err)
-
- See the documentation for the V function for an explanation
- of these examples:
-
- if glog.V(2) {
- glog.Info("Starting transaction...")
- }
-
- glog.V(2).Infoln("Processed", nItems, "elements")
-
-
-The repository contains an open source version of the log package
-used inside Google. The master copy of the source lives inside
-Google, not here. The code in this repo is for export only and is not itself
-under development. Feature requests will be ignored.
-
-Send bug reports to golang-nuts@googlegroups.com.
diff --git a/logger/glog/glog.go b/logger/glog/glog.go
deleted file mode 100644
index 0b33527c32..0000000000
--- a/logger/glog/glog.go
+++ /dev/null
@@ -1,1223 +0,0 @@
-// Go support for leveled logs, analogous to https://code.google.com/p/google-glog/
-//
-// Copyright 2013 Google Inc. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// Package glog implements logging analogous to the Google-internal C++ INFO/ERROR/V setup.
-// It provides functions Info, Warning, Error, Fatal, plus formatting variants such as
-// Infof. It also provides V-style logging controlled by the -v and -vmodule=file=2 flags.
-//
-// Basic examples:
-//
-// glog.Info("Prepare to repel boarders")
-//
-// glog.Fatalf("Initialization failed: %s", err)
-//
-// See the documentation for the V function for an explanation of these examples:
-//
-// if glog.V(2) {
-// glog.Info("Starting transaction...")
-// }
-//
-// glog.V(2).Infoln("Processed", nItems, "elements")
-//
-// Log output is buffered and written periodically using Flush. Programs
-// should call Flush before exiting to guarantee all log output is written.
-//
-// By default, all log statements write to files in a temporary directory.
-// This package provides several flags that modify this behavior.
-// As a result, flag.Parse must be called before any logging is done.
-//
-// -logtostderr=false
-// Logs are written to standard error instead of to files.
-// -alsologtostderr=false
-// Logs are written to standard error as well as to files.
-// -stderrthreshold=ERROR
-// Log events at or above this severity are logged to standard
-// error as well as to files.
-// -log_dir=""
-// Log files will be written to this directory instead of the
-// default temporary directory.
-//
-// Other flags provide aids to debugging.
-//
-// -log_backtrace_at=""
-// When set to a file and line number holding a logging statement,
-// such as
-// -log_backtrace_at=gopherflakes.go:234
-// a stack trace will be written to the Info log whenever execution
-// hits that statement. (Unlike with -vmodule, the ".go" must be
-// present.)
-// -v=0
-// Enable V-leveled logging at the specified level.
-// -vmodule=""
-// The syntax of the argument is a comma-separated list of pattern=N,
-// where pattern is a literal file name or "glob" pattern matching
-// and N is a V level. For instance,
-//
-// -vmodule=gopher.go=3
-// sets the V level to 3 in all Go files named "gopher.go".
-//
-// -vmodule=foo=3
-// sets V to 3 in all files of any packages whose import path ends in "foo".
-//
-// -vmodule=foo/*=3
-// sets V to 3 in all files of any packages whose import path contains "foo".
-package glog
-
-import (
- "bufio"
- "bytes"
- "errors"
- "fmt"
- "io"
- stdLog "log"
- "os"
- "regexp"
- "runtime"
- "strconv"
- "strings"
- "sync"
- "sync/atomic"
- "time"
-)
-
-// severity identifies the sort of log: info, warning etc. It also implements
-// the flag.Value interface. The -stderrthreshold flag is of type severity and
-// should be modified only through the flag.Value interface. The values match
-// the corresponding constants in C++.
-type severity int32 // sync/atomic int32
-
-// These constants identify the log levels in order of increasing severity.
-// A message written to a high-severity log file is also written to each
-// lower-severity log file.
-const (
- infoLog severity = iota
- warningLog
- errorLog
- fatalLog
- numSeverity = 4
-)
-
-const severityChar = "IWEF"
-
-var severityName = []string{
- infoLog: "INFO",
- warningLog: "WARNING",
- errorLog: "ERROR",
- fatalLog: "FATAL",
-}
-
-// these path prefixes are trimmed for display, but not when
-// matching vmodule filters.
-var trimPrefixes = []string{
- "/github.com/ethereum/go-ethereum",
- "/github.com/ethereum/ethash",
-}
-
-func trimToImportPath(file string) string {
- if root := strings.LastIndex(file, "src/"); root != 0 {
- file = file[root+3:]
- }
- return file
-}
-
-// SetV sets the global verbosity level
-func SetV(v int) {
- logging.verbosity.set(Level(v))
-}
-
-// SetToStderr sets the global output style
-func SetToStderr(toStderr bool) {
- logging.mu.Lock()
- logging.toStderr = toStderr
- logging.mu.Unlock()
-}
-
-// GetTraceLocation returns the global TraceLocation flag.
-func GetTraceLocation() *TraceLocation {
- return &logging.traceLocation
-}
-
-// GetVModule returns the global verbosity pattern flag.
-func GetVModule() *moduleSpec {
- return &logging.vmodule
-}
-
-// GetVerbosity returns the global verbosity level flag.
-func GetVerbosity() *Level {
- return &logging.verbosity
-}
-
-// get returns the value of the severity.
-func (s *severity) get() severity {
- return severity(atomic.LoadInt32((*int32)(s)))
-}
-
-// set sets the value of the severity.
-func (s *severity) set(val severity) {
- atomic.StoreInt32((*int32)(s), int32(val))
-}
-
-// String is part of the flag.Value interface.
-func (s *severity) String() string {
- return strconv.FormatInt(int64(*s), 10)
-}
-
-// Get is part of the flag.Value interface.
-func (s *severity) Get() interface{} {
- return *s
-}
-
-// Set is part of the flag.Value interface.
-func (s *severity) Set(value string) error {
- var threshold severity
- // Is it a known name?
- if v, ok := severityByName(value); ok {
- threshold = v
- } else {
- v, err := strconv.Atoi(value)
- if err != nil {
- return err
- }
- threshold = severity(v)
- }
- logging.stderrThreshold.set(threshold)
- return nil
-}
-
-func severityByName(s string) (severity, bool) {
- s = strings.ToUpper(s)
- for i, name := range severityName {
- if name == s {
- return severity(i), true
- }
- }
- return 0, false
-}
-
-// OutputStats tracks the number of output lines and bytes written.
-type OutputStats struct {
- lines int64
- bytes int64
-}
-
-// Lines returns the number of lines written.
-func (s *OutputStats) Lines() int64 {
- return atomic.LoadInt64(&s.lines)
-}
-
-// Bytes returns the number of bytes written.
-func (s *OutputStats) Bytes() int64 {
- return atomic.LoadInt64(&s.bytes)
-}
-
-// Stats tracks the number of lines of output and number of bytes
-// per severity level. Values must be read with atomic.LoadInt64.
-var Stats struct {
- Info, Warning, Error OutputStats
-}
-
-var severityStats = [numSeverity]*OutputStats{
- infoLog: &Stats.Info,
- warningLog: &Stats.Warning,
- errorLog: &Stats.Error,
-}
-
-// Level is exported because it appears in the arguments to V and is
-// the type of the v flag, which can be set programmatically.
-// It's a distinct type because we want to discriminate it from logType.
-// Variables of type level are only changed under logging.mu.
-// The -v flag is read only with atomic ops, so the state of the logging
-// module is consistent.
-
-// Level is treated as a sync/atomic int32.
-
-// Level specifies a level of verbosity for V logs. *Level implements
-// flag.Value; the -v flag is of type Level and should be modified
-// only through the flag.Value interface.
-type Level int32
-
-// get returns the value of the Level.
-func (l *Level) get() Level {
- return Level(atomic.LoadInt32((*int32)(l)))
-}
-
-// set sets the value of the Level.
-func (l *Level) set(val Level) {
- atomic.StoreInt32((*int32)(l), int32(val))
-}
-
-// String is part of the flag.Value interface.
-func (l *Level) String() string {
- return strconv.FormatInt(int64(*l), 10)
-}
-
-// Get is part of the flag.Value interface.
-func (l *Level) Get() interface{} {
- return *l
-}
-
-// Set is part of the flag.Value interface.
-func (l *Level) Set(value string) error {
- v, err := strconv.Atoi(value)
- if err != nil {
- return err
- }
- logging.mu.Lock()
- defer logging.mu.Unlock()
- logging.setVState(Level(v), logging.vmodule.filter, false)
- return nil
-}
-
-// moduleSpec represents the setting of the -vmodule flag.
-type moduleSpec struct {
- filter []modulePat
-}
-
-// modulePat contains a filter for the -vmodule flag.
-// It holds a verbosity level and a file pattern to match.
-type modulePat struct {
- pattern *regexp.Regexp
- level Level
-}
-
-func (m *moduleSpec) String() string {
- // Lock because the type is not atomic. TODO: clean this up.
- logging.mu.Lock()
- defer logging.mu.Unlock()
- var b bytes.Buffer
- for i, f := range m.filter {
- if i > 0 {
- b.WriteRune(',')
- }
- fmt.Fprintf(&b, "%s=%d", f.pattern, f.level)
- }
- return b.String()
-}
-
-// Get is part of the (Go 1.2) flag.Getter interface. It always returns nil for this flag type since the
-// struct is not exported.
-func (m *moduleSpec) Get() interface{} {
- return nil
-}
-
-var errVmoduleSyntax = errors.New("syntax error: expect comma-separated list of filename=N")
-
-// Syntax: -vmodule=recordio=2,file=1,gfs*=3
-func (m *moduleSpec) Set(value string) error {
- var filter []modulePat
- for _, pat := range strings.Split(value, ",") {
- if len(pat) == 0 {
- // Empty strings such as from a trailing comma can be ignored.
- continue
- }
- patLev := strings.Split(pat, "=")
- if len(patLev) != 2 || len(patLev[0]) == 0 || len(patLev[1]) == 0 {
- return errVmoduleSyntax
- }
- pattern := patLev[0]
- v, err := strconv.Atoi(patLev[1])
- if err != nil {
- return errors.New("syntax error: expect comma-separated list of filename=N")
- }
- if v < 0 {
- return errors.New("negative value for vmodule level")
- }
- if v == 0 {
- continue // Ignore. It's harmless but no point in paying the overhead.
- }
- // TODO: check syntax of filter?
- re, _ := compileModulePattern(pattern)
- filter = append(filter, modulePat{re, Level(v)})
- }
- logging.mu.Lock()
- defer logging.mu.Unlock()
- logging.setVState(logging.verbosity, filter, true)
- return nil
-}
-
-// compiles a vmodule pattern to a regular expression.
-func compileModulePattern(pat string) (*regexp.Regexp, error) {
- re := ".*"
- for _, comp := range strings.Split(pat, "/") {
- if comp == "*" {
- re += "(/.*)?"
- } else if comp != "" {
- // TODO: maybe return error if comp contains *
- re += "/" + regexp.QuoteMeta(comp)
- }
- }
- if !strings.HasSuffix(pat, ".go") {
- re += "/[^/]+\\.go"
- }
- return regexp.Compile(re + "$")
-}
-
-// traceLocation represents the setting of the -log_backtrace_at flag.
-type TraceLocation struct {
- file string
- line int
-}
-
-// isSet reports whether the trace location has been specified.
-// logging.mu is held.
-func (t *TraceLocation) isSet() bool {
- return t.line > 0
-}
-
-// match reports whether the specified file and line matches the trace location.
-// The argument file name is the full path, not the basename specified in the flag.
-// logging.mu is held.
-func (t *TraceLocation) match(file string, line int) bool {
- if t.line != line {
- return false
- }
- if i := strings.LastIndex(file, "/"); i >= 0 {
- file = file[i+1:]
- }
- return t.file == file
-}
-
-func (t *TraceLocation) String() string {
- // Lock because the type is not atomic. TODO: clean this up.
- logging.mu.Lock()
- defer logging.mu.Unlock()
- return fmt.Sprintf("%s:%d", t.file, t.line)
-}
-
-// Get is part of the (Go 1.2) flag.Getter interface. It always returns nil for this flag type since the
-// struct is not exported
-func (t *TraceLocation) Get() interface{} {
- return nil
-}
-
-var errTraceSyntax = errors.New("syntax error: expect file.go:234")
-
-// Syntax: -log_backtrace_at=gopherflakes.go:234
-// Note that unlike vmodule the file extension is included here.
-func (t *TraceLocation) Set(value string) error {
- if value == "" {
- // Unset.
- logging.mu.Lock()
- t.line = 0
- t.file = ""
- logging.mu.Unlock()
- return nil
- }
-
- fields := strings.Split(value, ":")
- if len(fields) != 2 {
- return errTraceSyntax
- }
- file, line := fields[0], fields[1]
- if !strings.Contains(file, ".") {
- return errTraceSyntax
- }
- v, err := strconv.Atoi(line)
- if err != nil {
- return errTraceSyntax
- }
- if v <= 0 {
- return errors.New("negative or zero value for level")
- }
- logging.mu.Lock()
- defer logging.mu.Unlock()
- t.line = v
- t.file = file
- return nil
-}
-
-// flushSyncWriter is the interface satisfied by logging destinations.
-type flushSyncWriter interface {
- Flush() error
- Sync() error
- io.Writer
-}
-
-func init() {
- //flag.BoolVar(&logging.toStderr, "logtostderr", false, "log to standard error instead of files")
- //flag.BoolVar(&logging.alsoToStderr, "alsologtostderr", false, "log to standard error as well as files")
- //flag.Var(&logging.verbosity, "v", "log level for V logs")
- //flag.Var(&logging.stderrThreshold, "stderrthreshold", "logs at or above this threshold go to stderr")
- //flag.Var(&logging.vmodule, "vmodule", "comma-separated list of pattern=N settings for file-filtered logging")
- //flag.Var(&logging.traceLocation, "log_backtrace_at", "when logging hits line file:N, emit a stack trace")
-
- // Default stderrThreshold is ERROR.
- logging.stderrThreshold = errorLog
- logging.setVState(3, nil, false)
- go logging.flushDaemon()
-}
-
-// Flush flushes all pending log I/O.
-func Flush() {
- logging.lockAndFlushAll()
-}
-
-// loggingT collects all the global state of the logging setup.
-type loggingT struct {
- // Boolean flags. Not handled atomically because the flag.Value interface
- // does not let us avoid the =true, and that shorthand is necessary for
- // compatibility. TODO: does this matter enough to fix? Seems unlikely.
- toStderr bool // The -logtostderr flag.
- alsoToStderr bool // The -alsologtostderr flag.
-
- // Level flag. Handled atomically.
- stderrThreshold severity // The -stderrthreshold flag.
-
- // freeList is a list of byte buffers, maintained under freeListMu.
- freeList *buffer
- // freeListMu maintains the free list. It is separate from the main mutex
- // so buffers can be grabbed and printed to without holding the main lock,
- // for better parallelization.
- freeListMu sync.Mutex
-
- // mu protects the remaining elements of this structure and is
- // used to synchronize logging.
- mu sync.Mutex
- // file holds writer for each of the log types.
- file [numSeverity]flushSyncWriter
- // pcs is used in V to avoid an allocation when computing the caller's PC.
- pcs [1]uintptr
- // vmap is a cache of the V Level for each V() call site, identified by PC.
- // It is wiped whenever the vmodule flag changes state.
- vmap map[uintptr]Level
- // filterLength stores the length of the vmodule filter chain. If greater
- // than zero, it means vmodule is enabled. It may be read safely
- // using sync.LoadInt32, but is only modified under mu.
- filterLength int32
- // traceLocation is the state of the -log_backtrace_at flag.
- traceLocation TraceLocation
- // These flags are modified only under lock, although verbosity may be fetched
- // safely using atomic.LoadInt32.
- vmodule moduleSpec // The state of the -vmodule flag.
- verbosity Level // V logging level, the value of the -v flag/
-}
-
-// buffer holds a byte Buffer for reuse. The zero value is ready for use.
-type buffer struct {
- bytes.Buffer
- tmp [64]byte // temporary byte array for creating headers.
- next *buffer
-}
-
-var logging loggingT
-
-// setVState sets a consistent state for V logging.
-// l.mu is held.
-func (l *loggingT) setVState(verbosity Level, filter []modulePat, setFilter bool) {
- // Turn verbosity off so V will not fire while we are in transition.
- logging.verbosity.set(0)
- // Ditto for filter length.
- atomic.StoreInt32(&logging.filterLength, 0)
-
- // Set the new filters and wipe the pc->Level map if the filter has changed.
- if setFilter {
- logging.vmodule.filter = filter
- logging.vmap = make(map[uintptr]Level)
- }
-
- // Things are consistent now, so enable filtering and verbosity.
- // They are enabled in order opposite to that in V.
- atomic.StoreInt32(&logging.filterLength, int32(len(filter)))
- logging.verbosity.set(verbosity)
-}
-
-// getBuffer returns a new, ready-to-use buffer.
-func (l *loggingT) getBuffer() *buffer {
- l.freeListMu.Lock()
- b := l.freeList
- if b != nil {
- l.freeList = b.next
- }
- l.freeListMu.Unlock()
- if b == nil {
- b = new(buffer)
- } else {
- b.next = nil
- b.Reset()
- }
- return b
-}
-
-// putBuffer returns a buffer to the free list.
-func (l *loggingT) putBuffer(b *buffer) {
- if b.Len() >= 256 {
- // Let big buffers die a natural death.
- return
- }
- l.freeListMu.Lock()
- b.next = l.freeList
- l.freeList = b
- l.freeListMu.Unlock()
-}
-
-var timeNow = time.Now // Stubbed out for testing.
-
-/*
-header formats a log header as defined by the C++ implementation.
-It returns a buffer containing the formatted header and the user's file and line number.
-The depth specifies how many stack frames above lives the source line to be identified in the log message.
-
-Log lines have this form:
- Lmmdd hh:mm:ss.uuuuuu threadid file:line] msg...
-where the fields are defined as follows:
- L A single character, representing the log level (eg 'I' for INFO)
- mm The month (zero padded; ie May is '05')
- dd The day (zero padded)
- hh:mm:ss.uuuuuu Time in hours, minutes and fractional seconds
- threadid The space-padded thread ID as returned by GetTID()
- file The file name
- line The line number
- msg The user-supplied message
-*/
-func (l *loggingT) header(s severity, depth int) (*buffer, string, int) {
- _, file, line, ok := runtime.Caller(3 + depth)
- if !ok {
- file = "???"
- line = 1
- } else {
- file = trimToImportPath(file)
- for _, p := range trimPrefixes {
- if strings.HasPrefix(file, p) {
- file = file[len(p):]
- break
- }
- }
- file = file[1:] // drop '/'
- }
- return l.formatHeader(s, file, line), file, line
-}
-
-// formatHeader formats a log header using the provided file name and line number.
-func (l *loggingT) formatHeader(s severity, file string, line int) *buffer {
- now := timeNow()
- if line < 0 {
- line = 0 // not a real line number, but acceptable to someDigits
- }
- if s > fatalLog {
- s = infoLog // for safety.
- }
- buf := l.getBuffer()
-
- // Avoid Fprintf, for speed. The format is so simple that we can do it quickly by hand.
- // It's worth about 3X. Fprintf is hard.
- _, month, day := now.Date()
- hour, minute, second := now.Clock()
- // Lmmdd hh:mm:ss.uuuuuu threadid file:line]
- buf.tmp[0] = severityChar[s]
- buf.twoDigits(1, int(month))
- buf.twoDigits(3, day)
- buf.tmp[5] = ' '
- buf.twoDigits(6, hour)
- buf.tmp[8] = ':'
- buf.twoDigits(9, minute)
- buf.tmp[11] = ':'
- buf.twoDigits(12, second)
- buf.tmp[14] = '.'
- buf.nDigits(6, 15, now.Nanosecond()/1000, '0')
- buf.tmp[21] = ' '
- buf.Write(buf.tmp[:22])
- buf.WriteString(file)
- buf.tmp[0] = ':'
- n := buf.someDigits(1, line)
- buf.tmp[n+1] = ']'
- buf.tmp[n+2] = ' '
- buf.Write(buf.tmp[:n+3])
- return buf
-}
-
-// Some custom tiny helper functions to print the log header efficiently.
-
-const digits = "0123456789"
-
-// twoDigits formats a zero-prefixed two-digit integer at buf.tmp[i].
-func (buf *buffer) twoDigits(i, d int) {
- buf.tmp[i+1] = digits[d%10]
- d /= 10
- buf.tmp[i] = digits[d%10]
-}
-
-// nDigits formats an n-digit integer at buf.tmp[i],
-// padding with pad on the left.
-// It assumes d >= 0.
-func (buf *buffer) nDigits(n, i, d int, pad byte) {
- j := n - 1
- for ; j >= 0 && d > 0; j-- {
- buf.tmp[i+j] = digits[d%10]
- d /= 10
- }
- for ; j >= 0; j-- {
- buf.tmp[i+j] = pad
- }
-}
-
-// someDigits formats a zero-prefixed variable-width integer at buf.tmp[i].
-func (buf *buffer) someDigits(i, d int) int {
- // Print into the top, then copy down. We know there's space for at least
- // a 10-digit number.
- j := len(buf.tmp)
- for {
- j--
- buf.tmp[j] = digits[d%10]
- d /= 10
- if d == 0 {
- break
- }
- }
- return copy(buf.tmp[i:], buf.tmp[j:])
-}
-
-func (l *loggingT) println(s severity, args ...interface{}) {
- buf, file, line := l.header(s, 0)
- fmt.Fprintln(buf, args...)
- l.output(s, buf, file, line, false)
-}
-
-func (l *loggingT) print(s severity, args ...interface{}) {
- l.printDepth(s, 1, args...)
-}
-
-func (l *loggingT) printDepth(s severity, depth int, args ...interface{}) {
- buf, file, line := l.header(s, depth)
- fmt.Fprint(buf, args...)
- if buf.Bytes()[buf.Len()-1] != '\n' {
- buf.WriteByte('\n')
- }
- l.output(s, buf, file, line, false)
-}
-
-func (l *loggingT) printfmt(s severity, format string, args ...interface{}) {
- buf, file, line := l.header(s, 0)
- fmt.Fprintf(buf, format, args...)
- if buf.Bytes()[buf.Len()-1] != '\n' {
- buf.WriteByte('\n')
- }
- l.output(s, buf, file, line, false)
-}
-
-// printWithFileLine behaves like print but uses the provided file and line number. If
-// alsoLogToStderr is true, the log message always appears on standard error; it
-// will also appear in the log file unless --logtostderr is set.
-func (l *loggingT) printWithFileLine(s severity, file string, line int, alsoToStderr bool, args ...interface{}) {
- buf := l.formatHeader(s, file, line)
- fmt.Fprint(buf, args...)
- if buf.Bytes()[buf.Len()-1] != '\n' {
- buf.WriteByte('\n')
- }
- l.output(s, buf, file, line, alsoToStderr)
-}
-
-// output writes the data to the log files and releases the buffer.
-func (l *loggingT) output(s severity, buf *buffer, file string, line int, alsoToStderr bool) {
- l.mu.Lock()
- if l.traceLocation.isSet() {
- if l.traceLocation.match(file, line) {
- buf.Write(stacks(false))
- }
- }
- data := buf.Bytes()
- if l.toStderr {
- os.Stderr.Write(data)
- } else {
- if alsoToStderr || l.alsoToStderr || s >= l.stderrThreshold.get() {
- os.Stderr.Write(data)
- }
- if l.file[s] == nil {
- if err := l.createFiles(s); err != nil {
- os.Stderr.Write(data) // Make sure the message appears somewhere.
- l.exit(err)
- }
- }
- switch s {
- case fatalLog:
- l.file[fatalLog].Write(data)
- fallthrough
- case errorLog:
- l.file[errorLog].Write(data)
- fallthrough
- case warningLog:
- l.file[warningLog].Write(data)
- fallthrough
- case infoLog:
- l.file[infoLog].Write(data)
- }
- }
- if s == fatalLog {
- // If we got here via Exit rather than Fatal, print no stacks.
- if atomic.LoadUint32(&fatalNoStacks) > 0 {
- l.mu.Unlock()
- timeoutFlush(10 * time.Second)
- os.Exit(1)
- }
- // Dump all goroutine stacks before exiting.
- // First, make sure we see the trace for the current goroutine on standard error.
- // If -logtostderr has been specified, the loop below will do that anyway
- // as the first stack in the full dump.
- if !l.toStderr {
- os.Stderr.Write(stacks(false))
- }
- // Write the stack trace for all goroutines to the files.
- trace := stacks(true)
- logExitFunc = func(error) {} // If we get a write error, we'll still exit below.
- for log := fatalLog; log >= infoLog; log-- {
- if f := l.file[log]; f != nil { // Can be nil if -logtostderr is set.
- f.Write(trace)
- }
- }
- l.mu.Unlock()
- timeoutFlush(10 * time.Second)
- os.Exit(255) // C++ uses -1, which is silly because it's anded with 255 anyway.
- }
- l.putBuffer(buf)
- l.mu.Unlock()
- if stats := severityStats[s]; stats != nil {
- atomic.AddInt64(&stats.lines, 1)
- atomic.AddInt64(&stats.bytes, int64(len(data)))
- }
-}
-
-// timeoutFlush calls Flush and returns when it completes or after timeout
-// elapses, whichever happens first. This is needed because the hooks invoked
-// by Flush may deadlock when glog.Fatal is called from a hook that holds
-// a lock.
-func timeoutFlush(timeout time.Duration) {
- done := make(chan bool, 1)
- go func() {
- Flush() // calls logging.lockAndFlushAll()
- done <- true
- }()
- select {
- case <-done:
- case <-time.After(timeout):
- fmt.Fprintln(os.Stderr, "glog: Flush took longer than", timeout)
- }
-}
-
-// stacks is a wrapper for runtime.Stack that attempts to recover the data for all goroutines.
-func stacks(all bool) []byte {
- // We don't know how big the traces are, so grow a few times if they don't fit. Start large, though.
- n := 10000
- if all {
- n = 100000
- }
- var trace []byte
- for i := 0; i < 5; i++ {
- trace = make([]byte, n)
- nbytes := runtime.Stack(trace, all)
- if nbytes < len(trace) {
- return trace[:nbytes]
- }
- n *= 2
- }
- return trace
-}
-
-// logExitFunc provides a simple mechanism to override the default behavior
-// of exiting on error. Used in testing and to guarantee we reach a required exit
-// for fatal logs. Instead, exit could be a function rather than a method but that
-// would make its use clumsier.
-var logExitFunc func(error)
-
-// exit is called if there is trouble creating or writing log files.
-// It flushes the logs and exits the program; there's no point in hanging around.
-// l.mu is held.
-func (l *loggingT) exit(err error) {
- fmt.Fprintf(os.Stderr, "log: exiting because of error: %s\n", err)
- // If logExitFunc is set, we do that instead of exiting.
- if logExitFunc != nil {
- logExitFunc(err)
- return
- }
- l.flushAll()
- os.Exit(2)
-}
-
-// syncBuffer joins a bufio.Writer to its underlying file, providing access to the
-// file's Sync method and providing a wrapper for the Write method that provides log
-// file rotation. There are conflicting methods, so the file cannot be embedded.
-// l.mu is held for all its methods.
-type syncBuffer struct {
- logger *loggingT
- *bufio.Writer
- file *os.File
- sev severity
- nbytes uint64 // The number of bytes written to this file
-}
-
-func (sb *syncBuffer) Sync() error {
- return sb.file.Sync()
-}
-
-func (sb *syncBuffer) Write(p []byte) (n int, err error) {
- if sb.nbytes+uint64(len(p)) >= MaxSize {
- if err := sb.rotateFile(time.Now()); err != nil {
- sb.logger.exit(err)
- }
- }
- n, err = sb.Writer.Write(p)
- sb.nbytes += uint64(n)
- if err != nil {
- sb.logger.exit(err)
- }
- return
-}
-
-// rotateFile closes the syncBuffer's file and starts a new one.
-func (sb *syncBuffer) rotateFile(now time.Time) error {
- if sb.file != nil {
- sb.Flush()
- sb.file.Close()
- }
- var err error
- sb.file, _, err = create(severityName[sb.sev], now)
- sb.nbytes = 0
- if err != nil {
- return err
- }
-
- sb.Writer = bufio.NewWriterSize(sb.file, bufferSize)
-
- // Write header.
- var buf bytes.Buffer
- fmt.Fprintf(&buf, "Log file created at: %s\n", now.Format("2006/01/02 15:04:05"))
- fmt.Fprintf(&buf, "Running on machine: %s\n", host)
- fmt.Fprintf(&buf, "Binary: Built with %s %s for %s/%s\n", runtime.Compiler, runtime.Version(), runtime.GOOS, runtime.GOARCH)
- fmt.Fprintf(&buf, "Log line format: [IWEF]mmdd hh:mm:ss.uuuuuu threadid file:line] msg\n")
- n, err := sb.file.Write(buf.Bytes())
- sb.nbytes += uint64(n)
- return err
-}
-
-// bufferSize sizes the buffer associated with each log file. It's large
-// so that log records can accumulate without the logging thread blocking
-// on disk I/O. The flushDaemon will block instead.
-const bufferSize = 256 * 1024
-
-// createFiles creates all the log files for severity from sev down to infoLog.
-// l.mu is held.
-func (l *loggingT) createFiles(sev severity) error {
- now := time.Now()
- // Files are created in decreasing severity order, so as soon as we find one
- // has already been created, we can stop.
- for s := sev; s >= infoLog && l.file[s] == nil; s-- {
- sb := &syncBuffer{
- logger: l,
- sev: s,
- }
- if err := sb.rotateFile(now); err != nil {
- return err
- }
- l.file[s] = sb
- }
- return nil
-}
-
-const flushInterval = 30 * time.Second
-
-// flushDaemon periodically flushes the log file buffers.
-func (l *loggingT) flushDaemon() {
- for range time.NewTicker(flushInterval).C {
- l.lockAndFlushAll()
- }
-}
-
-// lockAndFlushAll is like flushAll but locks l.mu first.
-func (l *loggingT) lockAndFlushAll() {
- l.mu.Lock()
- l.flushAll()
- l.mu.Unlock()
-}
-
-// flushAll flushes all the logs and attempts to "sync" their data to disk.
-// l.mu is held.
-func (l *loggingT) flushAll() {
- // Flush from fatal down, in case there's trouble flushing.
- for s := fatalLog; s >= infoLog; s-- {
- file := l.file[s]
- if file != nil {
- file.Flush() // ignore error
- file.Sync() // ignore error
- }
- }
-}
-
-// CopyStandardLogTo arranges for messages written to the Go "log" package's
-// default logs to also appear in the Google logs for the named and lower
-// severities. Subsequent changes to the standard log's default output location
-// or format may break this behavior.
-//
-// Valid names are "INFO", "WARNING", "ERROR", and "FATAL". If the name is not
-// recognized, CopyStandardLogTo panics.
-func CopyStandardLogTo(name string) {
- sev, ok := severityByName(name)
- if !ok {
- panic(fmt.Sprintf("log.CopyStandardLogTo(%q): unrecognized severity name", name))
- }
- // Set a log format that captures the user's file and line:
- // d.go:23: message
- stdLog.SetFlags(stdLog.Lshortfile)
- stdLog.SetOutput(logBridge(sev))
-}
-
-// logBridge provides the Write method that enables CopyStandardLogTo to connect
-// Go's standard logs to the logs provided by this package.
-type logBridge severity
-
-// Write parses the standard logging line and passes its components to the
-// logger for severity(lb).
-func (lb logBridge) Write(b []byte) (n int, err error) {
- var (
- file = "???"
- line = 1
- text string
- )
- // Split "d.go:23: message" into "d.go", "23", and "message".
- if parts := bytes.SplitN(b, []byte{':'}, 3); len(parts) != 3 || len(parts[0]) < 1 || len(parts[2]) < 1 {
- text = fmt.Sprintf("bad log format: %s", b)
- } else {
- file = string(parts[0])
- text = string(parts[2][1:]) // skip leading space
- line, err = strconv.Atoi(string(parts[1]))
- if err != nil {
- text = fmt.Sprintf("bad line number: %s", b)
- line = 1
- }
- }
- // printWithFileLine with alsoToStderr=true, so standard log messages
- // always appear on standard error.
- logging.printWithFileLine(severity(lb), file, line, true, text)
- return len(b), nil
-}
-
-// setV computes and remembers the V level for a given PC
-// when vmodule is enabled.
-// File pattern matching takes the basename of the file, stripped
-// of its .go suffix, and uses filepath.Match, which is a little more
-// general than the *? matching used in C++.
-// l.mu is held.
-func (l *loggingT) setV(pc uintptr) Level {
- fn := runtime.FuncForPC(pc)
- file, _ := fn.FileLine(pc)
- file = trimToImportPath(file)
- for _, filter := range l.vmodule.filter {
- if filter.pattern.MatchString(file) {
- l.vmap[pc] = filter.level
- return filter.level
- }
- }
- l.vmap[pc] = 0
- return 0
-}
-
-// Verbose is a boolean type that implements Infof (like Printf) etc.
-// See the documentation of V for more information.
-type Verbose bool
-
-// V reports whether verbosity at the call site is at least the requested level.
-// The returned value is a boolean of type Verbose, which implements Info, Infoln
-// and Infof. These methods will write to the Info log if called.
-// Thus, one may write either
-// if glog.V(2) { glog.Info("log this") }
-// or
-// glog.V(2).Info("log this")
-// The second form is shorter but the first is cheaper if logging is off because it does
-// not evaluate its arguments.
-//
-// Whether an individual call to V generates a log record depends on the setting of
-// the -v and --vmodule flags; both are off by default. If the level in the call to
-// V is at least the value of -v, or of -vmodule for the source file containing the
-// call, the V call will log.
-func V(level Level) Verbose {
- // This function tries hard to be cheap unless there's work to do.
- // The fast path is two atomic loads and compares.
-
- // Here is a cheap but safe test to see if V logging is enabled globally.
- if logging.verbosity.get() >= level {
- return Verbose(true)
- }
-
- // It's off globally but it vmodule may still be set.
- // Here is another cheap but safe test to see if vmodule is enabled.
- if atomic.LoadInt32(&logging.filterLength) > 0 {
- // Now we need a proper lock to use the logging structure. The pcs field
- // is shared so we must lock before accessing it. This is fairly expensive,
- // but if V logging is enabled we're slow anyway.
- logging.mu.Lock()
- defer logging.mu.Unlock()
- if runtime.Callers(2, logging.pcs[:]) == 0 {
- return Verbose(false)
- }
- v, ok := logging.vmap[logging.pcs[0]]
- if !ok {
- v = logging.setV(logging.pcs[0])
- }
- return Verbose(v >= level)
- }
- return Verbose(false)
-}
-
-// Info is equivalent to the global Info function, guarded by the value of v.
-// See the documentation of V for usage.
-func (v Verbose) Info(args ...interface{}) {
- if v {
- logging.print(infoLog, args...)
- }
-}
-
-// Infoln is equivalent to the global Infoln function, guarded by the value of v.
-// See the documentation of V for usage.
-func (v Verbose) Infoln(args ...interface{}) {
- if v {
- logging.println(infoLog, args...)
- }
-}
-
-// Infof is equivalent to the global Infof function, guarded by the value of v.
-// See the documentation of V for usage.
-func (v Verbose) Infof(format string, args ...interface{}) {
- if v {
- logging.printfmt(infoLog, format, args...)
- }
-}
-
-// Info logs to the INFO log.
-// Arguments are handled in the manner of fmt.Print; a newline is appended if missing.
-func Info(args ...interface{}) {
- logging.print(infoLog, args...)
-}
-
-// InfoDepth acts as Info but uses depth to determine which call frame to log.
-// InfoDepth(0, "msg") is the same as Info("msg").
-func InfoDepth(depth int, args ...interface{}) {
- logging.printDepth(infoLog, depth, args...)
-}
-
-// Infoln logs to the INFO log.
-// Arguments are handled in the manner of fmt.Println; a newline is appended if missing.
-func Infoln(args ...interface{}) {
- logging.print(infoLog, args...)
-}
-
-// Infof logs to the INFO log.
-// Arguments are handled in the manner of fmt.Printf; a newline is appended if missing.
-func Infof(format string, args ...interface{}) {
- logging.printfmt(infoLog, format, args...)
-}
-
-// Warning logs to the WARNING and INFO logs.
-// Arguments are handled in the manner of fmt.Print; a newline is appended if missing.
-func Warning(args ...interface{}) {
- logging.print(warningLog, args...)
-}
-
-// WarningDepth acts as Warning but uses depth to determine which call frame to log.
-// WarningDepth(0, "msg") is the same as Warning("msg").
-func WarningDepth(depth int, args ...interface{}) {
- logging.printDepth(warningLog, depth, args...)
-}
-
-// Warningln logs to the WARNING and INFO logs.
-// Arguments are handled in the manner of fmt.Println; a newline is appended if missing.
-func Warningln(args ...interface{}) {
- logging.println(warningLog, args...)
-}
-
-// Warningf logs to the WARNING and INFO logs.
-// Arguments are handled in the manner of fmt.Printf; a newline is appended if missing.
-func Warningf(format string, args ...interface{}) {
- logging.printfmt(warningLog, format, args...)
-}
-
-// Error logs to the ERROR, WARNING, and INFO logs.
-// Arguments are handled in the manner of fmt.Print; a newline is appended if missing.
-func Error(args ...interface{}) {
- logging.print(errorLog, args...)
-}
-
-// ErrorDepth acts as Error but uses depth to determine which call frame to log.
-// ErrorDepth(0, "msg") is the same as Error("msg").
-func ErrorDepth(depth int, args ...interface{}) {
- logging.printDepth(errorLog, depth, args...)
-}
-
-// Errorln logs to the ERROR, WARNING, and INFO logs.
-// Arguments are handled in the manner of fmt.Println; a newline is appended if missing.
-func Errorln(args ...interface{}) {
- logging.println(errorLog, args...)
-}
-
-// Errorf logs to the ERROR, WARNING, and INFO logs.
-// Arguments are handled in the manner of fmt.Printf; a newline is appended if missing.
-func Errorf(format string, args ...interface{}) {
- logging.printfmt(errorLog, format, args...)
-}
-
-// Fatal logs to the FATAL, ERROR, WARNING, and INFO logs,
-// including a stack trace of all running goroutines, then calls os.Exit(255).
-// Arguments are handled in the manner of fmt.Print; a newline is appended if missing.
-func Fatal(args ...interface{}) {
- logging.print(fatalLog, args...)
-}
-
-// FatalDepth acts as Fatal but uses depth to determine which call frame to log.
-// FatalDepth(0, "msg") is the same as Fatal("msg").
-func FatalDepth(depth int, args ...interface{}) {
- logging.printDepth(fatalLog, depth, args...)
-}
-
-// Fatalln logs to the FATAL, ERROR, WARNING, and INFO logs,
-// including a stack trace of all running goroutines, then calls os.Exit(255).
-// Arguments are handled in the manner of fmt.Println; a newline is appended if missing.
-func Fatalln(args ...interface{}) {
- logging.println(fatalLog, args...)
-}
-
-// Fatalf logs to the FATAL, ERROR, WARNING, and INFO logs,
-// including a stack trace of all running goroutines, then calls os.Exit(255).
-// Arguments are handled in the manner of fmt.Printf; a newline is appended if missing.
-func Fatalf(format string, args ...interface{}) {
- logging.printfmt(fatalLog, format, args...)
-}
-
-// fatalNoStacks is non-zero if we are to exit without dumping goroutine stacks.
-// It allows Exit and relatives to use the Fatal logs.
-var fatalNoStacks uint32
-
-// Exit logs to the FATAL, ERROR, WARNING, and INFO logs, then calls os.Exit(1).
-// Arguments are handled in the manner of fmt.Print; a newline is appended if missing.
-func Exit(args ...interface{}) {
- atomic.StoreUint32(&fatalNoStacks, 1)
- logging.print(fatalLog, args...)
-}
-
-// ExitDepth acts as Exit but uses depth to determine which call frame to log.
-// ExitDepth(0, "msg") is the same as Exit("msg").
-func ExitDepth(depth int, args ...interface{}) {
- atomic.StoreUint32(&fatalNoStacks, 1)
- logging.printDepth(fatalLog, depth, args...)
-}
-
-// Exitln logs to the FATAL, ERROR, WARNING, and INFO logs, then calls os.Exit(1).
-func Exitln(args ...interface{}) {
- atomic.StoreUint32(&fatalNoStacks, 1)
- logging.println(fatalLog, args...)
-}
-
-// Exitf logs to the FATAL, ERROR, WARNING, and INFO logs, then calls os.Exit(1).
-// Arguments are handled in the manner of fmt.Printf; a newline is appended if missing.
-func Exitf(format string, args ...interface{}) {
- atomic.StoreUint32(&fatalNoStacks, 1)
- logging.printfmt(fatalLog, format, args...)
-}
diff --git a/logger/glog/glog_file.go b/logger/glog/glog_file.go
deleted file mode 100644
index 2fc96eb4e1..0000000000
--- a/logger/glog/glog_file.go
+++ /dev/null
@@ -1,128 +0,0 @@
-// Go support for leveled logs, analogous to https://code.google.com/p/google-glog/
-//
-// Copyright 2013 Google Inc. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// File I/O for logs.
-
-package glog
-
-import (
- "errors"
- "fmt"
- "os"
- "os/user"
- "path/filepath"
- "strings"
- "sync"
- "time"
-)
-
-// MaxSize is the maximum size of a log file in bytes.
-var MaxSize uint64 = 1024 * 1024 * 1800
-
-// logDirs lists the candidate directories for new log files.
-var logDirs []string
-
-// If non-empty, overrides the choice of directory in which to write logs.
-// See createLogDirs for the full list of possible destinations.
-//var logDir = flag.String("log_dir", "", "If non-empty, write log files in this directory")
-var logDir *string = new(string)
-
-func SetLogDir(str string) {
- *logDir = str
-}
-
-func createLogDirs() {
- if *logDir != "" {
- logDirs = append(logDirs, *logDir)
- }
- logDirs = append(logDirs, os.TempDir())
-}
-
-var (
- pid = os.Getpid()
- program = filepath.Base(os.Args[0])
- host = "unknownhost"
- userName = "unknownuser"
-)
-
-func init() {
- h, err := os.Hostname()
- if err == nil {
- host = shortHostname(h)
- }
-
- current, err := user.Current()
- if err == nil {
- userName = current.Username
- }
-
- // Sanitize userName since it may contain filepath separators on Windows.
- userName = strings.Replace(userName, `\`, "_", -1)
-}
-
-// shortHostname returns its argument, truncating at the first period.
-// For instance, given "www.google.com" it returns "www".
-func shortHostname(hostname string) string {
- if i := strings.Index(hostname, "."); i >= 0 {
- return hostname[:i]
- }
- return hostname
-}
-
-// logName returns a new log file name containing tag, with start time t, and
-// the name for the symlink for tag.
-func logName(tag string, t time.Time) (name, link string) {
- name = fmt.Sprintf("%s.%s.%s.log.%s.%04d%02d%02d-%02d%02d%02d.%d",
- program,
- host,
- userName,
- tag,
- t.Year(),
- t.Month(),
- t.Day(),
- t.Hour(),
- t.Minute(),
- t.Second(),
- pid)
- return name, program + "." + tag
-}
-
-var onceLogDirs sync.Once
-
-// create creates a new log file and returns the file and its filename, which
-// contains tag ("INFO", "FATAL", etc.) and t. If the file is created
-// successfully, create also attempts to update the symlink for that tag, ignoring
-// errors.
-func create(tag string, t time.Time) (f *os.File, filename string, err error) {
- onceLogDirs.Do(createLogDirs)
- if len(logDirs) == 0 {
- return nil, "", errors.New("log: no log dirs")
- }
- name, link := logName(tag, t)
- var lastErr error
- for _, dir := range logDirs {
- fname := filepath.Join(dir, name)
- f, err := os.Create(fname)
- if err == nil {
- symlink := filepath.Join(dir, link)
- os.Remove(symlink) // ignore err
- os.Symlink(name, symlink) // ignore err
- return f, fname, nil
- }
- lastErr = err
- }
- return nil, "", fmt.Errorf("log: cannot create log: %v", lastErr)
-}
diff --git a/logger/glog/glog_test.go b/logger/glog/glog_test.go
deleted file mode 100644
index b58f3d6426..0000000000
--- a/logger/glog/glog_test.go
+++ /dev/null
@@ -1,436 +0,0 @@
-// Go support for leveled logs, analogous to https://code.google.com/p/google-glog/
-//
-// Copyright 2013 Google Inc. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package glog
-
-import (
- "bytes"
- "fmt"
- stdLog "log"
- "path/filepath"
- "runtime"
- "strconv"
- "strings"
- "testing"
- "time"
-)
-
-// Test that shortHostname works as advertised.
-func TestShortHostname(t *testing.T) {
- for hostname, expect := range map[string]string{
- "": "",
- "host": "host",
- "host.google.com": "host",
- } {
- if got := shortHostname(hostname); expect != got {
- t.Errorf("shortHostname(%q): expected %q, got %q", hostname, expect, got)
- }
- }
-}
-
-// flushBuffer wraps a bytes.Buffer to satisfy flushSyncWriter.
-type flushBuffer struct {
- bytes.Buffer
-}
-
-func (f *flushBuffer) Flush() error {
- return nil
-}
-
-func (f *flushBuffer) Sync() error {
- return nil
-}
-
-// swap sets the log writers and returns the old array.
-func (l *loggingT) swap(writers [numSeverity]flushSyncWriter) (old [numSeverity]flushSyncWriter) {
- l.mu.Lock()
- defer l.mu.Unlock()
- old = l.file
- for i, w := range writers {
- logging.file[i] = w
- }
- return
-}
-
-// newBuffers sets the log writers to all new byte buffers and returns the old array.
-func (l *loggingT) newBuffers() [numSeverity]flushSyncWriter {
- return l.swap([numSeverity]flushSyncWriter{new(flushBuffer), new(flushBuffer), new(flushBuffer), new(flushBuffer)})
-}
-
-// contents returns the specified log value as a string.
-func contents(s severity) string {
- return logging.file[s].(*flushBuffer).String()
-}
-
-// contains reports whether the string is contained in the log.
-func contains(s severity, str string, t *testing.T) bool {
- return strings.Contains(contents(s), str)
-}
-
-// setFlags configures the logging flags how the test expects them.
-func setFlags() {
- logging.toStderr = false
-}
-
-// Test that Info works as advertised.
-func TestInfo(t *testing.T) {
- setFlags()
- defer logging.swap(logging.newBuffers())
- Info("test")
- if !contains(infoLog, "I", t) {
- t.Errorf("Info has wrong character: %q", contents(infoLog))
- }
- if !contains(infoLog, "test", t) {
- t.Error("Info failed")
- }
-}
-
-func TestInfoDepth(t *testing.T) {
- setFlags()
- defer logging.swap(logging.newBuffers())
-
- f := func() { InfoDepth(1, "depth-test1") }
-
- // The next three lines must stay together
- _, _, wantLine, _ := runtime.Caller(0)
- InfoDepth(0, "depth-test0")
- f()
-
- msgs := strings.Split(strings.TrimSuffix(contents(infoLog), "\n"), "\n")
- if len(msgs) != 2 {
- t.Fatalf("Got %d lines, expected 2", len(msgs))
- }
-
- for i, m := range msgs {
- if !strings.HasPrefix(m, "I") {
- t.Errorf("InfoDepth[%d] has wrong character: %q", i, m)
- }
- w := fmt.Sprintf("depth-test%d", i)
- if !strings.Contains(m, w) {
- t.Errorf("InfoDepth[%d] missing %q: %q", i, w, m)
- }
-
- // pull out the line number (between : and ])
- msg := m[strings.LastIndex(m, ":")+1:]
- x := strings.Index(msg, "]")
- if x < 0 {
- t.Errorf("InfoDepth[%d]: missing ']': %q", i, m)
- continue
- }
- line, err := strconv.Atoi(msg[:x])
- if err != nil {
- t.Errorf("InfoDepth[%d]: bad line number: %q", i, m)
- continue
- }
- wantLine++
- if wantLine != line {
- t.Errorf("InfoDepth[%d]: got line %d, want %d", i, line, wantLine)
- }
- }
-}
-
-func init() {
- CopyStandardLogTo("INFO")
-}
-
-// Test that CopyStandardLogTo panics on bad input.
-func TestCopyStandardLogToPanic(t *testing.T) {
- defer func() {
- if s, ok := recover().(string); !ok || !strings.Contains(s, "LOG") {
- t.Errorf(`CopyStandardLogTo("LOG") should have panicked: %v`, s)
- }
- }()
- CopyStandardLogTo("LOG")
-}
-
-// Test that using the standard log package logs to INFO.
-func TestStandardLog(t *testing.T) {
- setFlags()
- defer logging.swap(logging.newBuffers())
- stdLog.Print("test")
- if !contains(infoLog, "I", t) {
- t.Errorf("Info has wrong character: %q", contents(infoLog))
- }
- if !contains(infoLog, "test", t) {
- t.Error("Info failed")
- }
-}
-
-// Test that the header has the correct format.
-func TestHeader(t *testing.T) {
- setFlags()
- defer logging.swap(logging.newBuffers())
- defer func(previous func() time.Time) { timeNow = previous }(timeNow)
- timeNow = func() time.Time {
- return time.Date(2006, 1, 2, 15, 4, 5, .067890e9, time.Local)
- }
- pid = 1234
- Info("test")
- var line int
- format := "I0102 15:04:05.067890 logger/glog/glog_test.go:%d] test\n"
- n, err := fmt.Sscanf(contents(infoLog), format, &line)
- if n != 1 || err != nil {
- t.Errorf("log format error: %d elements, error %s:\n%s", n, err, contents(infoLog))
- }
- // Scanf treats multiple spaces as equivalent to a single space,
- // so check for correct space-padding also.
- want := fmt.Sprintf(format, line)
- if contents(infoLog) != want {
- t.Errorf("log format error: got:\n\t%q\nwant:\t%q", contents(infoLog), want)
- }
-}
-
-// Test that an Error log goes to Warning and Info.
-// Even in the Info log, the source character will be E, so the data should
-// all be identical.
-func TestError(t *testing.T) {
- setFlags()
- defer logging.swap(logging.newBuffers())
- Error("test")
- if !contains(errorLog, "E", t) {
- t.Errorf("Error has wrong character: %q", contents(errorLog))
- }
- if !contains(errorLog, "test", t) {
- t.Error("Error failed")
- }
- str := contents(errorLog)
- if !contains(warningLog, str, t) {
- t.Error("Warning failed")
- }
- if !contains(infoLog, str, t) {
- t.Error("Info failed")
- }
-}
-
-// Test that a Warning log goes to Info.
-// Even in the Info log, the source character will be W, so the data should
-// all be identical.
-func TestWarning(t *testing.T) {
- setFlags()
- defer logging.swap(logging.newBuffers())
- Warning("test")
- if !contains(warningLog, "W", t) {
- t.Errorf("Warning has wrong character: %q", contents(warningLog))
- }
- if !contains(warningLog, "test", t) {
- t.Error("Warning failed")
- }
- str := contents(warningLog)
- if !contains(infoLog, str, t) {
- t.Error("Info failed")
- }
-}
-
-// Test that a V log goes to Info.
-func TestV(t *testing.T) {
- setFlags()
- defer logging.swap(logging.newBuffers())
- logging.verbosity.Set("2")
- defer logging.verbosity.Set("0")
- V(2).Info("test")
- if !contains(infoLog, "I", t) {
- t.Errorf("Info has wrong character: %q", contents(infoLog))
- }
- if !contains(infoLog, "test", t) {
- t.Error("Info failed")
- }
-}
-
-// Test that a vmodule enables a log in this file.
-func TestVmoduleOn(t *testing.T) {
- setFlags()
- defer logging.swap(logging.newBuffers())
- logging.vmodule.Set("glog_test.go=2")
- defer logging.vmodule.Set("")
- if !V(1) {
- t.Error("V not enabled for 1")
- }
- if !V(2) {
- t.Error("V not enabled for 2")
- }
- if V(3) {
- t.Error("V enabled for 3")
- }
- V(2).Info("test")
- if !contains(infoLog, "I", t) {
- t.Errorf("Info has wrong character: %q", contents(infoLog))
- }
- if !contains(infoLog, "test", t) {
- t.Error("Info failed")
- }
-}
-
-// Test that a vmodule of another file does not enable a log in this file.
-func TestVmoduleOff(t *testing.T) {
- setFlags()
- defer logging.swap(logging.newBuffers())
- logging.vmodule.Set("notthisfile=2")
- defer logging.vmodule.Set("")
- for i := 1; i <= 3; i++ {
- if V(Level(i)) {
- t.Errorf("V enabled for %d", i)
- }
- }
- V(2).Info("test")
- if contents(infoLog) != "" {
- t.Error("V logged incorrectly")
- }
-}
-
-var patternTests = []struct{ input, want string }{
- {"foo/bar/x.go", ".*/foo/bar/x\\.go$"},
- {"foo/*/x.go", ".*/foo(/.*)?/x\\.go$"},
- {"foo/*", ".*/foo(/.*)?/[^/]+\\.go$"},
-}
-
-func TestCompileModulePattern(t *testing.T) {
- for _, test := range patternTests {
- re, err := compileModulePattern(test.input)
- if err != nil {
- t.Fatalf("%s: %v", test.input, err)
- }
- if re.String() != test.want {
- t.Errorf("mismatch for %q: got %q, want %q", test.input, re.String(), test.want)
- }
- }
-}
-
-// vGlobs are patterns that match/don't match this file at V=2.
-var vGlobs = map[string]bool{
- // Easy to test the numeric match here.
- "glog_test.go=1": false, // If -vmodule sets V to 1, V(2) will fail.
- "glog_test.go=2": true,
- "glog_test.go=3": true, // If -vmodule sets V to 1, V(3) will succeed.
-
- // Import path prefix matching
- "logger/glog=1": false,
- "logger/glog=2": true,
- "logger/glog=3": true,
-
- // Import path glob matching
- "logger/*=1": false,
- "logger/*=2": true,
- "logger/*=3": true,
-
- // These all use 2 and check the patterns.
- "*=2": true,
-}
-
-// Test that vmodule globbing works as advertised.
-func testVmoduleGlob(pat string, match bool, t *testing.T) {
- setFlags()
- defer logging.swap(logging.newBuffers())
- defer logging.vmodule.Set("")
- logging.vmodule.Set(pat)
- if V(2) != Verbose(match) {
- t.Errorf("incorrect match for %q: got %t expected %t", pat, V(2), match)
- }
-}
-
-// Test that a vmodule globbing works as advertised.
-func TestVmoduleGlob(t *testing.T) {
- for glob, match := range vGlobs {
- testVmoduleGlob(glob, match, t)
- }
-}
-
-func TestRollover(t *testing.T) {
- setFlags()
- var err error
- defer func(previous func(error)) { logExitFunc = previous }(logExitFunc)
- logExitFunc = func(e error) {
- err = e
- }
- defer func(previous uint64) { MaxSize = previous }(MaxSize)
- MaxSize = 512
-
- Info("x") // Be sure we have a file.
- info, ok := logging.file[infoLog].(*syncBuffer)
- if !ok {
- t.Fatal("info wasn't created")
- }
- if err != nil {
- t.Fatalf("info has initial error: %v", err)
- }
- fname0 := info.file.Name()
- Info(strings.Repeat("x", int(MaxSize))) // force a rollover
- if err != nil {
- t.Fatalf("info has error after big write: %v", err)
- }
-
- // Make sure the next log file gets a file name with a different
- // time stamp.
- //
- // TODO: determine whether we need to support subsecond log
- // rotation. C++ does not appear to handle this case (nor does it
- // handle Daylight Savings Time properly).
- time.Sleep(1 * time.Second)
-
- Info("x") // create a new file
- if err != nil {
- t.Fatalf("error after rotation: %v", err)
- }
- fname1 := info.file.Name()
- if fname0 == fname1 {
- t.Errorf("info.f.Name did not change: %v", fname0)
- }
- if info.nbytes >= MaxSize {
- t.Errorf("file size was not reset: %d", info.nbytes)
- }
-}
-
-func TestLogBacktraceAt(t *testing.T) {
- setFlags()
- defer logging.swap(logging.newBuffers())
- // The peculiar style of this code simplifies line counting and maintenance of the
- // tracing block below.
- var infoLine string
- setTraceLocation := func(file string, line int, ok bool, delta int) {
- if !ok {
- t.Fatal("could not get file:line")
- }
- _, file = filepath.Split(file)
- infoLine = fmt.Sprintf("%s:%d", file, line+delta)
- err := logging.traceLocation.Set(infoLine)
- if err != nil {
- t.Fatal("error setting log_backtrace_at: ", err)
- }
- }
- {
- // Start of tracing block. These lines know about each other's relative position.
- _, file, line, ok := runtime.Caller(0)
- setTraceLocation(file, line, ok, +2) // Two lines between Caller and Info calls.
- Info("we want a stack trace here")
- }
- numAppearances := strings.Count(contents(infoLog), infoLine)
- if numAppearances < 2 {
- // Need 2 appearances, one in the log header and one in the trace:
- // log_test.go:281: I0511 16:36:06.952398 02238 log_test.go:280] we want a stack trace here
- // ...
- // github.com/glog/glog_test.go:280 (0x41ba91)
- // ...
- // We could be more precise but that would require knowing the details
- // of the traceback format, which may not be dependable.
- t.Fatal("got no trace back; log is ", contents(infoLog))
- }
-}
-
-func BenchmarkHeader(b *testing.B) {
- for i := 0; i < b.N; i++ {
- buf, _, _ := logging.header(infoLog, 0)
- logging.putBuffer(buf)
- }
-}
diff --git a/metrics/metrics.go b/metrics/metrics.go
index d756894f38..9906bb8ad2 100644
--- a/metrics/metrics.go
+++ b/metrics/metrics.go
@@ -23,8 +23,7 @@ import (
"strings"
"time"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/log"
"github.com/rcrowley/go-metrics"
"github.com/rcrowley/go-metrics/exp"
)
@@ -41,7 +40,7 @@ var Enabled = false
func init() {
for _, arg := range os.Args {
if strings.TrimLeft(arg, "-") == MetricsEnabledFlag {
- glog.V(logger.Info).Infof("Enabling metrics collection")
+ log.Info("Enabling metrics collection")
Enabled = true
}
}
@@ -102,7 +101,7 @@ func CollectProcessMetrics(refresh time.Duration) {
diskWrites = metrics.GetOrRegisterMeter("system/disk/writecount", metrics.DefaultRegistry)
diskWriteBytes = metrics.GetOrRegisterMeter("system/disk/writedata", metrics.DefaultRegistry)
} else {
- glog.V(logger.Debug).Infof("failed to read disk metrics: %v", err)
+ log.Debug("Failed to read disk metrics", "err", err)
}
// Iterate loading the different stats and updating the meters
for i := 1; ; i++ {
diff --git a/miner/agent.go b/miner/agent.go
index 697e3971b7..3c407f20bb 100644
--- a/miner/agent.go
+++ b/miner/agent.go
@@ -17,14 +17,14 @@
package miner
import (
+ "fmt"
"sync"
"sync/atomic"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/pow"
)
@@ -108,10 +108,10 @@ done:
}
func (self *CpuAgent) mine(work *Work, stop <-chan struct{}) {
- glog.V(logger.Debug).Infof("(re)started agent[%d]. mining...\n", self.index)
+ log.Debug(fmt.Sprintf("(re)started agent[%d]. mining...\n", self.index))
// Mine
- nonce, mixDigest := self.pow.Search(work.Block, stop, self.index)
+ nonce, mixDigest := self.pow.Search(work.Block, stop)
if nonce != 0 {
block := work.Block.WithMiningResult(types.EncodeNonce(nonce), common.BytesToHash(mixDigest))
self.returnCh <- &Result{work, block}
@@ -121,5 +121,5 @@ func (self *CpuAgent) mine(work *Work, stop <-chan struct{}) {
}
func (self *CpuAgent) GetHashRate() int64 {
- return self.pow.GetHashrate()
+ return int64(self.pow.Hashrate())
}
diff --git a/miner/miner.go b/miner/miner.go
index 61cd3e0499..dc0591b9a0 100644
--- a/miner/miner.go
+++ b/miner/miner.go
@@ -30,8 +30,7 @@ import (
"github.com/ethereum/go-ethereum/eth/downloader"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/pow"
)
@@ -87,7 +86,7 @@ out:
if self.Mining() {
self.Stop()
atomic.StoreInt32(&self.shouldStart, 1)
- glog.V(logger.Info).Infoln("Mining operation aborted due to sync operation")
+ log.Info(fmt.Sprint("Mining operation aborted due to sync operation"))
}
case downloader.DoneEvent, downloader.FailedEvent:
shouldStart := atomic.LoadInt32(&self.shouldStart) == 1
@@ -124,7 +123,7 @@ func (self *Miner) Start(coinbase common.Address, threads int) {
self.threads = threads
if atomic.LoadInt32(&self.canStart) == 0 {
- glog.V(logger.Info).Infoln("Can not start mining operation due to network sync (starts when finished)")
+ log.Info(fmt.Sprint("Can not start mining operation due to network sync (starts when finished)"))
return
}
atomic.StoreInt32(&self.mining, 1)
@@ -133,7 +132,7 @@ func (self *Miner) Start(coinbase common.Address, threads int) {
self.worker.register(NewCpuAgent(i, self.pow))
}
- glog.V(logger.Info).Infof("Starting mining operation (CPU=%d TOT=%d)\n", threads, len(self.worker.agents))
+ log.Info(fmt.Sprintf("Starting mining operation (CPU=%d TOT=%d)\n", threads, len(self.worker.agents)))
self.worker.start()
self.worker.commitNewWork()
}
@@ -160,18 +159,20 @@ func (self *Miner) Mining() bool {
}
func (self *Miner) HashRate() (tot int64) {
- tot += self.pow.GetHashrate()
+ tot += int64(self.pow.Hashrate())
// do we care this might race? is it worth we're rewriting some
// aspects of the worker/locking up agents so we can get an accurate
// hashrate?
for agent := range self.worker.agents {
- tot += agent.GetHashRate()
+ if _, ok := agent.(*CpuAgent); !ok {
+ tot += agent.GetHashRate()
+ }
}
return
}
func (self *Miner) SetExtra(extra []byte) error {
- if uint64(len(extra)) > params.MaximumExtraDataSize.Uint64() {
+ if uint64(len(extra)) > params.MaximumExtraDataSize {
return fmt.Errorf("Extra exceeds max length. %d > %v", len(extra), params.MaximumExtraDataSize)
}
self.worker.setExtra(extra)
diff --git a/miner/remote_agent.go b/miner/remote_agent.go
index 23277bac8b..08c5fc6f08 100644
--- a/miner/remote_agent.go
+++ b/miner/remote_agent.go
@@ -18,16 +18,15 @@ package miner
import (
"errors"
+ "fmt"
"math/big"
"sync"
"sync/atomic"
"time"
- "github.com/ethereum/ethash"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/pow"
)
@@ -115,7 +114,7 @@ func (a *RemoteAgent) GetWork() ([3]string, error) {
block := a.currentWork.Block
res[0] = block.HashNoNonce().Hex()
- seedHash, _ := ethash.GetSeedHash(block.NumberU64())
+ seedHash := pow.EthashSeedHash(block.NumberU64())
res[1] = common.BytesToHash(seedHash).Hex()
// Calculate the "target" to be returned to the external miner
n := big.NewInt(1)
@@ -140,13 +139,13 @@ func (a *RemoteAgent) SubmitWork(nonce types.BlockNonce, mixDigest, hash common.
// Make sure the work submitted is present
work := a.work[hash]
if work == nil {
- glog.V(logger.Info).Infof("Work was submitted for %x but no pending work found", hash)
+ log.Info(fmt.Sprintf("Work was submitted for %x but no pending work found", hash))
return false
}
// Make sure the PoW solutions is indeed valid
block := work.Block.WithMiningResult(nonce, mixDigest)
- if !a.pow.Verify(block) {
- glog.V(logger.Warn).Infof("Invalid PoW submitted for %x", hash)
+ if err := a.pow.Verify(block); err != nil {
+ log.Warn(fmt.Sprintf("Invalid PoW submitted for %x: %v", hash, err))
return false
}
// Solutions seems to be valid, return to the miner and notify acceptance
diff --git a/miner/unconfirmed.go b/miner/unconfirmed.go
index 86a30de35c..bb7d0ff267 100644
--- a/miner/unconfirmed.go
+++ b/miner/unconfirmed.go
@@ -18,12 +18,12 @@ package miner
import (
"container/ring"
+ "fmt"
"sync"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/log"
)
// headerRetriever is used by the unconfirmed block set to verify whether a previously
@@ -80,7 +80,7 @@ func (set *unconfirmedBlocks) Insert(index uint64, hash common.Hash) {
set.blocks.Move(-1).Link(item)
}
// Display a log for the user to notify of a new mined block unconfirmed
- glog.V(logger.Info).Infof("🔨 mined potential block #%d [%x…], waiting for %d blocks to confirm", index, hash.Bytes()[:4], set.depth)
+ log.Info(fmt.Sprintf("🔨 mined potential block #%d [%x…], waiting for %d blocks to confirm", index, hash.Bytes()[:4], set.depth))
}
// Shift drops all unconfirmed blocks from the set which exceed the unconfirmed sets depth
@@ -100,11 +100,11 @@ func (set *unconfirmedBlocks) Shift(height uint64) {
header := set.chain.GetHeaderByNumber(next.index)
switch {
case header == nil:
- glog.V(logger.Warn).Infof("failed to retrieve header of mined block #%d [%x…]", next.index, next.hash.Bytes()[:4])
+ log.Warn(fmt.Sprintf("failed to retrieve header of mined block #%d [%x…]", next.index, next.hash.Bytes()[:4]))
case header.Hash() == next.hash:
- glog.V(logger.Info).Infof("🔗 mined block #%d [%x…] reached canonical chain", next.index, next.hash.Bytes()[:4])
+ log.Info(fmt.Sprintf("🔗 mined block #%d [%x…] reached canonical chain", next.index, next.hash.Bytes()[:4]))
default:
- glog.V(logger.Info).Infof("⑂ mined block #%d [%x…] became a side fork", next.index, next.hash.Bytes()[:4])
+ log.Info(fmt.Sprintf("⑂ mined block #%d [%x…] became a side fork", next.index, next.hash.Bytes()[:4]))
}
// Drop the block out of the ring
if set.blocks.Value == set.blocks.Next().Value {
diff --git a/miner/worker.go b/miner/worker.go
index ef64c8fc91..2f090924e2 100644
--- a/miner/worker.go
+++ b/miner/worker.go
@@ -32,8 +32,7 @@ import (
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/pow"
"gopkg.in/fatih/set.v0"
@@ -278,7 +277,7 @@ func (self *worker) wait() {
if self.fullValidation {
if _, err := self.chain.InsertChain(types.Blocks{block}); err != nil {
- glog.V(logger.Error).Infoln("mining err", err)
+ log.Error(fmt.Sprint("mining err", err))
continue
}
go self.mux.Post(core.NewMinedBlockEvent{Block: block})
@@ -286,19 +285,19 @@ func (self *worker) wait() {
work.state.Commit(self.config.IsEIP158(block.Number()))
parent := self.chain.GetBlock(block.ParentHash(), block.NumberU64()-1)
if parent == nil {
- glog.V(logger.Error).Infoln("Invalid block found during mining")
+ log.Error(fmt.Sprint("Invalid block found during mining"))
continue
}
auxValidator := self.eth.BlockChain().AuxValidator()
if err := core.ValidateHeader(self.config, auxValidator, block.Header(), parent.Header(), true, false); err != nil && err != core.BlockFutureErr {
- glog.V(logger.Error).Infoln("Invalid header on mined block:", err)
+ log.Error(fmt.Sprint("Invalid header on mined block:", err))
continue
}
stat, err := self.chain.WriteBlock(block)
if err != nil {
- glog.V(logger.Error).Infoln("error writing block to chain", err)
+ log.Error(fmt.Sprint("error writing block to chain", err))
continue
}
@@ -334,7 +333,7 @@ func (self *worker) wait() {
self.mux.Post(logs)
}
if err := core.WriteBlockReceipts(self.chainDb, block.Hash(), block.NumberU64(), receipts); err != nil {
- glog.V(logger.Warn).Infoln("error writing block receipts:", err)
+ log.Warn(fmt.Sprint("error writing block receipts:", err))
}
}(block, work.state.Logs(), work.receipts)
}
@@ -427,7 +426,7 @@ func (self *worker) commitNewWork() {
// this will ensure we're not going off too far in the future
if now := time.Now().Unix(); tstamp > now+4 {
wait := time.Duration(tstamp-now) * time.Second
- glog.V(logger.Info).Infoln("We are too far in the future. Waiting for", wait)
+ log.Info(fmt.Sprint("We are too far in the future. Waiting for", wait))
time.Sleep(wait)
}
@@ -458,7 +457,7 @@ func (self *worker) commitNewWork() {
// Could potentially happen if starting to mine in an odd state.
err := self.makeCurrent(parent, header)
if err != nil {
- glog.V(logger.Info).Infoln("Could not create new env for mining, retrying on next block.")
+ log.Info(fmt.Sprint("Could not create new env for mining, retrying on next block."))
return
}
// Create the current work task and check any fork transitions needed
@@ -469,7 +468,7 @@ func (self *worker) commitNewWork() {
pending, err := self.eth.TxPool().Pending()
if err != nil {
- glog.Errorf("Could not fetch pending transactions: %v", err)
+ log.Error(fmt.Sprintf("Could not fetch pending transactions: %v", err))
return
}
@@ -489,13 +488,12 @@ func (self *worker) commitNewWork() {
break
}
if err := self.commitUncle(work, uncle.Header()); err != nil {
- if glog.V(logger.Ridiculousness) {
- glog.V(logger.Detail).Infof("Bad uncle found and will be removed (%x)\n", hash[:4])
- glog.V(logger.Detail).Infoln(uncle)
- }
+ log.Trace(fmt.Sprintf("Bad uncle found and will be removed (%x)\n", hash[:4]))
+ log.Trace(fmt.Sprint(uncle))
+
badUncles = append(badUncles, hash)
} else {
- glog.V(logger.Debug).Infof("committing %x as uncle\n", hash[:4])
+ log.Debug(fmt.Sprintf("committing %x as uncle\n", hash[:4]))
uncles = append(uncles, uncle.Header())
}
}
@@ -514,7 +512,7 @@ func (self *worker) commitNewWork() {
// We only care about logging if we're actually mining.
if atomic.LoadInt32(&self.mining) == 1 {
- glog.V(logger.Info).Infof("commit new work on block %v with %d txs & %d uncles. Took %v\n", work.Block.Number(), work.tcount, len(uncles), time.Since(tstart))
+ log.Info(fmt.Sprintf("commit new work on block %v with %d txs & %d uncles. Took %v\n", work.Block.Number(), work.tcount, len(uncles), time.Since(tstart)))
self.unconfirmed.Shift(work.Block.NumberU64() - 1)
}
self.push(work)
@@ -554,7 +552,7 @@ func (env *Work) commitTransactions(mux *event.TypeMux, txs *types.TransactionsB
// Check whether the tx is replay protected. If we're not in the EIP155 hf
// phase, start ignoring the sender until we do.
if tx.Protected() && !env.config.IsEIP155(env.header.Number) {
- glog.V(logger.Detail).Infof("Transaction (%x) is replay protected, but we haven't yet hardforked. Transaction will be ignored until we hardfork.\n", tx.Hash())
+ log.Trace(fmt.Sprintf("Transaction (%x) is replay protected, but we haven't yet hardforked. Transaction will be ignored until we hardfork.\n", tx.Hash()))
txs.Pop()
continue
@@ -563,7 +561,7 @@ func (env *Work) commitTransactions(mux *event.TypeMux, txs *types.TransactionsB
// Ignore any transactions (and accounts subsequently) with low gas limits
if tx.GasPrice().Cmp(gasPrice) < 0 && !env.ownedAccounts.Has(from) {
// Pop the current low-priced transaction without shifting in the next from the account
- glog.V(logger.Info).Infof("Transaction (%x) below gas price (tx=%v ask=%v). All sequential txs from this address(%x) will be ignored\n", tx.Hash().Bytes()[:4], common.CurrencyToString(tx.GasPrice()), common.CurrencyToString(gasPrice), from[:4])
+ log.Info(fmt.Sprintf("Transaction (%x) below gas price (tx=%dwei ask=%dwei). All sequential txs from this address(%x) will be ignored\n", tx.Hash().Bytes()[:4], tx.GasPrice(), gasPrice, from[:4]))
env.lowGasTxs = append(env.lowGasTxs, tx)
txs.Pop()
@@ -577,12 +575,12 @@ func (env *Work) commitTransactions(mux *event.TypeMux, txs *types.TransactionsB
switch {
case core.IsGasLimitErr(err):
// Pop the current out-of-gas transaction without shifting in the next from the account
- glog.V(logger.Detail).Infof("Gas limit reached for (%x) in this block. Continue to try smaller txs\n", from[:4])
+ log.Trace(fmt.Sprintf("Gas limit reached for (%x) in this block. Continue to try smaller txs\n", from[:4]))
txs.Pop()
case err != nil:
// Pop the current failed transaction without shifting in the next from the account
- glog.V(logger.Detail).Infof("Transaction (%x) failed, will be removed: %v\n", tx.Hash().Bytes()[:4], err)
+ log.Trace(fmt.Sprintf("Transaction (%x) failed, will be removed: %v\n", tx.Hash().Bytes()[:4], err))
env.failedTxs = append(env.failedTxs, tx)
txs.Pop()
diff --git a/mobile/big.go b/mobile/big.go
index 9a55836c13..525717caa8 100644
--- a/mobile/big.go
+++ b/mobile/big.go
@@ -93,3 +93,8 @@ func (bi *BigInts) Set(index int, bigint *BigInt) error {
bi.bigints[index] = bigint.bigint
return nil
}
+
+// GetString returns the value of x as a formatted string in some number base.
+func (bi *BigInt) GetString(base int) string {
+ return bi.bigint.Text(base)
+}
diff --git a/mobile/context.go b/mobile/context.go
index 9df94b6896..f1fff90114 100644
--- a/mobile/context.go
+++ b/mobile/context.go
@@ -20,9 +20,8 @@
package geth
import (
+ "context"
"time"
-
- "golang.org/x/net/context"
)
// Context carries a deadline, a cancelation signal, and other values across API
diff --git a/mobile/doc.go b/mobile/doc.go
index 89be470cce..64d47bec2a 100644
--- a/mobile/doc.go
+++ b/mobile/doc.go
@@ -16,7 +16,7 @@
// Package geth contains the simplified mobile APIs to go-ethereum.
//
-// The scope of this package is *not* to allow writing a custom Ethereun client
+// The scope of this package is *not* to allow writing a custom Ethereum client
// with pieces plucked from go-ethereum, rather to allow writing native dapps on
// mobile platforms. Keep this in mind when using or extending this package!
//
diff --git a/mobile/geth.go b/mobile/geth.go
index af0054cdcd..e070cec56d 100644
--- a/mobile/geth.go
+++ b/mobile/geth.go
@@ -20,11 +20,12 @@
package geth
import (
+ "encoding/json"
"fmt"
"math/big"
"path/filepath"
- "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/ethstats"
@@ -32,7 +33,7 @@ import (
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/p2p/nat"
"github.com/ethereum/go-ethereum/params"
- "github.com/ethereum/go-ethereum/whisper/whisperv2"
+ whisper "github.com/ethereum/go-ethereum/whisper/whisperv2"
)
// NodeConfig represents the collection of configuration values to fine tune the Geth
@@ -93,6 +94,18 @@ func NewNodeConfig() *NodeConfig {
return &config
}
+// SetMainnet sets up the node for use on the Ethereum mainnet.
+func (cfg *NodeConfig) SetMainnet() {
+ cfg.EthereumGenesis = ""
+ cfg.EthereumChainConfig = MainnetChainConfig()
+}
+
+// SetTestnet sets up the node for use on the Ethereum testnet.
+func (cfg *NodeConfig) SetTestnet() {
+ cfg.EthereumGenesis = TestnetGenesis()
+ cfg.EthereumChainConfig = TestnetChainConfig()
+}
+
// Node represents a Geth Ethereum node instance.
type Node struct {
node *node.Node
@@ -128,30 +141,47 @@ func NewNode(datadir string, config *NodeConfig) (stack *Node, _ error) {
if err != nil {
return nil, err
}
+
+ var genesis *core.Genesis
+ if config.EthereumGenesis != "" {
+ genesis = new(core.Genesis)
+ if err := json.Unmarshal([]byte(config.EthereumGenesis), genesis); err != nil {
+ return nil, fmt.Errorf("invalid EthereumGenesis: %v", err)
+ }
+ }
+ if config.EthereumChainConfig != nil {
+ if genesis == nil {
+ genesis = core.DefaultGenesisBlock()
+ }
+ genesis.Config = ¶ms.ChainConfig{
+ ChainId: big.NewInt(config.EthereumChainConfig.ChainID),
+ HomesteadBlock: big.NewInt(config.EthereumChainConfig.HomesteadBlock),
+ DAOForkBlock: big.NewInt(config.EthereumChainConfig.DAOForkBlock),
+ DAOForkSupport: config.EthereumChainConfig.DAOForkSupport,
+ EIP150Block: big.NewInt(config.EthereumChainConfig.EIP150Block),
+ EIP150Hash: config.EthereumChainConfig.EIP150Hash.hash,
+ EIP155Block: big.NewInt(config.EthereumChainConfig.EIP155Block),
+ EIP158Block: big.NewInt(config.EthereumChainConfig.EIP158Block),
+ }
+ }
+
// Register the Ethereum protocol if requested
if config.EthereumEnabled {
ethConf := ð.Config{
- ChainConfig: ¶ms.ChainConfig{
- ChainId: big.NewInt(config.EthereumChainConfig.ChainID),
- HomesteadBlock: big.NewInt(config.EthereumChainConfig.HomesteadBlock),
- DAOForkBlock: big.NewInt(config.EthereumChainConfig.DAOForkBlock),
- DAOForkSupport: config.EthereumChainConfig.DAOForkSupport,
- EIP150Block: big.NewInt(config.EthereumChainConfig.EIP150Block),
- EIP150Hash: config.EthereumChainConfig.EIP150Hash.hash,
- EIP155Block: big.NewInt(config.EthereumChainConfig.EIP155Block),
- EIP158Block: big.NewInt(config.EthereumChainConfig.EIP158Block),
- },
- Genesis: config.EthereumGenesis,
+ Genesis: genesis,
LightMode: true,
DatabaseCache: config.EthereumDatabaseCache,
NetworkId: config.EthereumNetworkID,
- GasPrice: new(big.Int).Mul(big.NewInt(20), common.Shannon),
- GpoMinGasPrice: new(big.Int).Mul(big.NewInt(20), common.Shannon),
- GpoMaxGasPrice: new(big.Int).Mul(big.NewInt(500), common.Shannon),
+ GasPrice: new(big.Int).SetUint64(20 * params.Shannon),
+ GpoMinGasPrice: new(big.Int).SetUint64(50 * params.Shannon),
+ GpoMaxGasPrice: new(big.Int).SetUint64(500 * params.Shannon),
GpoFullBlockRatio: 80,
GpobaseStepDown: 10,
GpobaseStepUp: 100,
GpobaseCorrectionFactor: 110,
+ EthashCacheDir: "ethash",
+ EthashCachesInMem: 2,
+ EthashCachesOnDisk: 3,
}
if err := rawStack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
return les.New(ctx, ethConf)
@@ -172,7 +202,7 @@ func NewNode(datadir string, config *NodeConfig) (stack *Node, _ error) {
}
// Register the Whisper protocol if requested
if config.WhisperEnabled {
- if err := rawStack.Register(func(*node.ServiceContext) (node.Service, error) { return whisperv2.New(), nil }); err != nil {
+ if err := rawStack.Register(func(*node.ServiceContext) (node.Service, error) { return whisper.New(), nil }); err != nil {
return nil, fmt.Errorf("whisper init: %v", err)
}
}
diff --git a/mobile/init.go b/mobile/init.go
index 0fbc6bd3e8..2025d85edc 100644
--- a/mobile/init.go
+++ b/mobile/init.go
@@ -19,16 +19,15 @@
package geth
import (
+ "os"
"runtime"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/log"
)
func init() {
// Initialize the logger
- glog.SetV(logger.Info)
- glog.SetToStderr(true)
+ log.Root().SetHandler(log.LvlFilterHandler(log.LvlInfo, log.StreamHandler(os.Stderr, log.TerminalFormat(false))))
// Initialize the goroutine count
runtime.GOMAXPROCS(runtime.NumCPU())
diff --git a/mobile/logger.go b/mobile/logger.go
index 97f80f9bbc..7078c4fd2c 100644
--- a/mobile/logger.go
+++ b/mobile/logger.go
@@ -17,10 +17,12 @@
package geth
import (
- "github.com/ethereum/go-ethereum/logger/glog"
+ "os"
+
+ "github.com/ethereum/go-ethereum/log"
)
// SetVerbosity sets the global verbosity level (between 0 and 6 - see logger/verbosity.go).
func SetVerbosity(level int) {
- glog.SetV(level)
+ log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(level), log.StreamHandler(os.Stderr, log.TerminalFormat(false))))
}
diff --git a/mobile/params.go b/mobile/params.go
index 87747c7b0d..6ca0c1b3a3 100644
--- a/mobile/params.go
+++ b/mobile/params.go
@@ -19,6 +19,8 @@
package geth
import (
+ "encoding/json"
+
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/p2p/discv5"
"github.com/ethereum/go-ethereum/params"
@@ -60,7 +62,11 @@ func TestnetChainConfig() *ChainConfig {
// TestnetGenesis returns the JSON spec to use for the Ethereum test network.
func TestnetGenesis() string {
- return core.DefaultTestnetGenesisBlock()
+ enc, err := json.Marshal(core.DefaultTestnetGenesisBlock())
+ if err != nil {
+ panic(err)
+ }
+ return string(enc)
}
// ChainConfig is the core config which determines the blockchain settings.
diff --git a/node/config.go b/node/config.go
index c09f51747b..608c9a6b42 100644
--- a/node/config.go
+++ b/node/config.go
@@ -31,8 +31,7 @@ import (
"github.com/ethereum/go-ethereum/accounts/usbwallet"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/p2p/discover"
"github.com/ethereum/go-ethereum/p2p/discv5"
"github.com/ethereum/go-ethereum/p2p/nat"
@@ -334,7 +333,7 @@ func (c *Config) NodeKey() *ecdsa.PrivateKey {
if c.DataDir == "" {
key, err := crypto.GenerateKey()
if err != nil {
- glog.Fatalf("Failed to generate ephemeral node key: %v", err)
+ log.Crit(fmt.Sprintf("Failed to generate ephemeral node key: %v", err))
}
return key
}
@@ -346,16 +345,16 @@ func (c *Config) NodeKey() *ecdsa.PrivateKey {
// No persistent key found, generate and store a new one.
key, err := crypto.GenerateKey()
if err != nil {
- glog.Fatalf("Failed to generate node key: %v", err)
+ log.Crit(fmt.Sprintf("Failed to generate node key: %v", err))
}
instanceDir := filepath.Join(c.DataDir, c.name())
if err := os.MkdirAll(instanceDir, 0700); err != nil {
- glog.V(logger.Error).Infof("Failed to persist node key: %v", err)
+ log.Error(fmt.Sprintf("Failed to persist node key: %v", err))
return key
}
keyfile = filepath.Join(instanceDir, datadirPrivateKey)
if err := crypto.SaveECDSA(keyfile, key); err != nil {
- glog.V(logger.Error).Infof("Failed to persist node key: %v", err)
+ log.Error(fmt.Sprintf("Failed to persist node key: %v", err))
}
return key
}
@@ -383,7 +382,7 @@ func (c *Config) parsePersistentNodes(path string) []*discover.Node {
// Load the nodes from the config file.
var nodelist []string
if err := common.LoadJSON(path, &nodelist); err != nil {
- glog.V(logger.Error).Infof("Can't load node file %s: %v", path, err)
+ log.Error(fmt.Sprintf("Can't load node file %s: %v", path, err))
return nil
}
// Interpret the list as a discovery node array
@@ -394,7 +393,7 @@ func (c *Config) parsePersistentNodes(path string) []*discover.Node {
}
node, err := discover.ParseNode(url)
if err != nil {
- glog.V(logger.Error).Infof("Node URL %s: %v\n", url, err)
+ log.Error(fmt.Sprintf("Node URL %s: %v\n", url, err))
continue
}
nodes = append(nodes, node)
@@ -442,7 +441,7 @@ func makeAccountManager(conf *Config) (*accounts.Manager, string, error) {
keystore.NewKeyStore(keydir, scryptN, scryptP),
}
if ledgerhub, err := usbwallet.NewLedgerHub(); err != nil {
- glog.V(logger.Warn).Infof("Failed to start Ledger hub, disabling: %v", err)
+ log.Warn(fmt.Sprintf("Failed to start Ledger hub, disabling: %v", err))
} else {
backends = append(backends, ledgerhub)
}
diff --git a/node/node.go b/node/node.go
index 4b56fba4c5..c7e28af377 100644
--- a/node/node.go
+++ b/node/node.go
@@ -18,6 +18,7 @@ package node
import (
"errors"
+ "fmt"
"net"
"os"
"path/filepath"
@@ -30,8 +31,7 @@ import (
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/internal/debug"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/rpc"
"github.com/syndtr/goleveldb/leveldb/storage"
@@ -173,7 +173,7 @@ func (n *Node) Start() error {
MaxPendingPeers: n.config.MaxPendingPeers,
}
running := &p2p.Server{Config: n.serverConfig}
- glog.V(logger.Info).Infoln("instance:", n.serverConfig.Name)
+ log.Info(fmt.Sprint("instance:", n.serverConfig.Name))
// Otherwise copy and specialize the P2P configuration
services := make(map[reflect.Type]Service)
@@ -301,7 +301,7 @@ func (n *Node) startInProc(apis []rpc.API) error {
if err := handler.RegisterName(api.Namespace, api.Service); err != nil {
return err
}
- glog.V(logger.Debug).Infof("InProc registered %T under '%s'", api.Service, api.Namespace)
+ log.Debug(fmt.Sprintf("InProc registered %T under '%s'", api.Service, api.Namespace))
}
n.inprocHandler = handler
return nil
@@ -327,7 +327,7 @@ func (n *Node) startIPC(apis []rpc.API) error {
if err := handler.RegisterName(api.Namespace, api.Service); err != nil {
return err
}
- glog.V(logger.Debug).Infof("IPC registered %T under '%s'", api.Service, api.Namespace)
+ log.Debug(fmt.Sprintf("IPC registered %T under '%s'", api.Service, api.Namespace))
}
// All APIs registered, start the IPC listener
var (
@@ -338,7 +338,7 @@ func (n *Node) startIPC(apis []rpc.API) error {
return err
}
go func() {
- glog.V(logger.Info).Infof("IPC endpoint opened: %s", n.ipcEndpoint)
+ log.Info(fmt.Sprintf("IPC endpoint opened: %s", n.ipcEndpoint))
for {
conn, err := listener.Accept()
@@ -351,7 +351,7 @@ func (n *Node) startIPC(apis []rpc.API) error {
return
}
// Not closed, just some error; report and continue
- glog.V(logger.Error).Infof("IPC accept failed: %v", err)
+ log.Error(fmt.Sprintf("IPC accept failed: %v", err))
continue
}
go handler.ServeCodec(rpc.NewJSONCodec(conn), rpc.OptionMethodInvocation|rpc.OptionSubscriptions)
@@ -370,7 +370,7 @@ func (n *Node) stopIPC() {
n.ipcListener.Close()
n.ipcListener = nil
- glog.V(logger.Info).Infof("IPC endpoint closed: %s", n.ipcEndpoint)
+ log.Info(fmt.Sprintf("IPC endpoint closed: %s", n.ipcEndpoint))
}
if n.ipcHandler != nil {
n.ipcHandler.Stop()
@@ -396,7 +396,7 @@ func (n *Node) startHTTP(endpoint string, apis []rpc.API, modules []string, cors
if err := handler.RegisterName(api.Namespace, api.Service); err != nil {
return err
}
- glog.V(logger.Debug).Infof("HTTP registered %T under '%s'", api.Service, api.Namespace)
+ log.Debug(fmt.Sprintf("HTTP registered %T under '%s'", api.Service, api.Namespace))
}
}
// All APIs registered, start the HTTP listener
@@ -408,7 +408,7 @@ func (n *Node) startHTTP(endpoint string, apis []rpc.API, modules []string, cors
return err
}
go rpc.NewHTTPServer(cors, handler).Serve(listener)
- glog.V(logger.Info).Infof("HTTP endpoint opened: http://%s", endpoint)
+ log.Info(fmt.Sprintf("HTTP endpoint opened: http://%s", endpoint))
// All listeners booted successfully
n.httpEndpoint = endpoint
@@ -424,7 +424,7 @@ func (n *Node) stopHTTP() {
n.httpListener.Close()
n.httpListener = nil
- glog.V(logger.Info).Infof("HTTP endpoint closed: http://%s", n.httpEndpoint)
+ log.Info(fmt.Sprintf("HTTP endpoint closed: http://%s", n.httpEndpoint))
}
if n.httpHandler != nil {
n.httpHandler.Stop()
@@ -450,7 +450,7 @@ func (n *Node) startWS(endpoint string, apis []rpc.API, modules []string, wsOrig
if err := handler.RegisterName(api.Namespace, api.Service); err != nil {
return err
}
- glog.V(logger.Debug).Infof("WebSocket registered %T under '%s'", api.Service, api.Namespace)
+ log.Debug(fmt.Sprintf("WebSocket registered %T under '%s'", api.Service, api.Namespace))
}
}
// All APIs registered, start the HTTP listener
@@ -462,7 +462,7 @@ func (n *Node) startWS(endpoint string, apis []rpc.API, modules []string, wsOrig
return err
}
go rpc.NewWSServer(wsOrigins, handler).Serve(listener)
- glog.V(logger.Info).Infof("WebSocket endpoint opened: ws://%s", endpoint)
+ log.Info(fmt.Sprintf("WebSocket endpoint opened: ws://%s", endpoint))
// All listeners booted successfully
n.wsEndpoint = endpoint
@@ -478,7 +478,7 @@ func (n *Node) stopWS() {
n.wsListener.Close()
n.wsListener = nil
- glog.V(logger.Info).Infof("WebSocket endpoint closed: ws://%s", n.wsEndpoint)
+ log.Info(fmt.Sprintf("WebSocket endpoint closed: ws://%s", n.wsEndpoint))
}
if n.wsHandler != nil {
n.wsHandler.Stop()
diff --git a/node/service.go b/node/service.go
index 1cd1fe808e..5e1eb0e645 100644
--- a/node/service.go
+++ b/node/service.go
@@ -46,6 +46,13 @@ func (ctx *ServiceContext) OpenDatabase(name string, cache int, handles int) (et
return ethdb.NewLDBDatabase(ctx.config.resolvePath(name), cache, handles)
}
+// ResolvePath resolves a user path into the data directory if that was relative
+// and if the user actually uses persistent storage. It will return an empty string
+// for emphemeral storage and the user's own input for absolute paths.
+func (ctx *ServiceContext) ResolvePath(path string) string {
+ return ctx.config.resolvePath(path)
+}
+
// Service retrieves a currently running service registered of a specific type.
func (ctx *ServiceContext) Service(service interface{}) error {
element := reflect.ValueOf(service).Elem()
diff --git a/p2p/dial.go b/p2p/dial.go
index 57fba136a1..bb3befab24 100644
--- a/p2p/dial.go
+++ b/p2p/dial.go
@@ -24,8 +24,7 @@ import (
"net"
"time"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/p2p/discover"
"github.com/ethereum/go-ethereum/p2p/netutil"
)
@@ -134,7 +133,7 @@ func (s *dialstate) newTasks(nRunning int, peers map[discover.NodeID]*Peer, now
var newtasks []task
addDial := func(flag connFlag, n *discover.Node) bool {
if err := s.checkDial(n, peers); err != nil {
- glog.V(logger.Debug).Infof("skipping dial candidate %x@%v:%d: %v", n.ID[:8], n.IP, n.TCP, err)
+ log.Trace("Skipping dial candidate", "id", n.ID, "addr", &net.TCPAddr{IP: n.IP, Port: int(n.TCP)}, "err", err)
return false
}
s.dialing[n.ID] = flag
@@ -163,7 +162,7 @@ func (s *dialstate) newTasks(nRunning int, peers map[discover.NodeID]*Peer, now
err := s.checkDial(t.dest, peers)
switch err {
case errNotWhitelisted, errSelf:
- glog.V(logger.Debug).Infof("removing static dial candidate %x@%v:%d: %v", t.dest.ID[:8], t.dest.IP, t.dest.TCP, err)
+ log.Warn("Removing static dial candidate", "id", t.dest.ID, "addr", &net.TCPAddr{IP: t.dest.IP, Port: int(t.dest.TCP)}, "err", err)
delete(s.static, t.dest.ID)
case nil:
s.dialing[id] = t.flags
@@ -267,7 +266,7 @@ func (t *dialTask) Do(srv *Server) {
// The backoff delay resets when the node is found.
func (t *dialTask) resolve(srv *Server) bool {
if srv.ntab == nil {
- glog.V(logger.Debug).Infof("can't resolve node %x: discovery is disabled", t.dest.ID[:6])
+ log.Debug("Can't resolve node", "id", t.dest.ID, "err", "discovery is disabled")
return false
}
if t.resolveDelay == 0 {
@@ -283,23 +282,22 @@ func (t *dialTask) resolve(srv *Server) bool {
if t.resolveDelay > maxResolveDelay {
t.resolveDelay = maxResolveDelay
}
- glog.V(logger.Debug).Infof("resolving node %x failed (new delay: %v)", t.dest.ID[:6], t.resolveDelay)
+ log.Debug("Resolving node failed", "id", t.dest.ID, "newdelay", t.resolveDelay)
return false
}
// The node was found.
t.resolveDelay = initialResolveDelay
t.dest = resolved
- glog.V(logger.Debug).Infof("resolved node %x: %v:%d", t.dest.ID[:6], t.dest.IP, t.dest.TCP)
+ log.Debug("Resolved node", "id", t.dest.ID, "addr", &net.TCPAddr{IP: t.dest.IP, Port: int(t.dest.TCP)})
return true
}
// dial performs the actual connection attempt.
func (t *dialTask) dial(srv *Server, dest *discover.Node) bool {
addr := &net.TCPAddr{IP: dest.IP, Port: int(dest.TCP)}
- glog.V(logger.Debug).Infof("dial tcp %v (%x)\n", addr, dest.ID[:6])
fd, err := srv.Dialer.Dial("tcp", addr.String())
if err != nil {
- glog.V(logger.Detail).Infof("%v", err)
+ log.Trace("Dial error", "task", t, "err", err)
return false
}
mfd := newMeteredConn(fd, false)
diff --git a/p2p/discover/database.go b/p2p/discover/database.go
index 8d20d1ec74..7206a63c63 100644
--- a/p2p/discover/database.go
+++ b/p2p/discover/database.go
@@ -28,8 +28,7 @@ import (
"time"
"github.com/ethereum/go-ethereum/crypto"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rlp"
"github.com/syndtr/goleveldb/leveldb"
"github.com/syndtr/goleveldb/leveldb/errors"
@@ -180,12 +179,11 @@ func (db *nodeDB) storeInt64(key []byte, n int64) error {
func (db *nodeDB) node(id NodeID) *Node {
blob, err := db.lvl.Get(makeKey(id, nodeDBDiscoverRoot), nil)
if err != nil {
- glog.V(logger.Detail).Infof("failed to retrieve node %v: %v", id, err)
return nil
}
node := new(Node)
if err := rlp.DecodeBytes(blob, node); err != nil {
- glog.V(logger.Warn).Infof("failed to decode node RLP: %v", err)
+ log.Error("Failed to decode node RLP", "err", err)
return nil
}
node.sha = crypto.Keccak256Hash(node.ID[:])
@@ -233,7 +231,7 @@ func (db *nodeDB) expirer() {
select {
case <-tick:
if err := db.expireNodes(); err != nil {
- glog.V(logger.Error).Infof("Failed to expire nodedb items: %v", err)
+ log.Error("Failed to expire nodedb items", "err", err)
}
case <-db.quit:
@@ -352,9 +350,7 @@ func nextNode(it iterator.Iterator) *Node {
}
var n Node
if err := rlp.DecodeBytes(it.Value(), &n); err != nil {
- if glog.V(logger.Warn) {
- glog.Errorf("invalid node %x: %v", id, err)
- }
+ log.Warn("Failed to decode node RLP", "id", id, "err", err)
continue
}
return &n
diff --git a/p2p/discover/node.go b/p2p/discover/node.go
index 8b1062d87b..6a7ab814e1 100644
--- a/p2p/discover/node.go
+++ b/p2p/discover/node.go
@@ -221,6 +221,11 @@ func (n NodeID) GoString() string {
return fmt.Sprintf("discover.HexID(\"%x\")", n[:])
}
+// TerminalString returns a shortened hex string for terminal logging.
+func (n NodeID) TerminalString() string {
+ return hex.EncodeToString(n[:8])
+}
+
// HexID converts a hex string to a NodeID.
// The string may be prefixed with 0x.
func HexID(in string) (NodeID, error) {
@@ -259,7 +264,7 @@ func PubkeyID(pub *ecdsa.PublicKey) NodeID {
// Pubkey returns the public key represented by the node ID.
// It returns an error if the ID is not a point on the curve.
func (id NodeID) Pubkey() (*ecdsa.PublicKey, error) {
- p := &ecdsa.PublicKey{Curve: secp256k1.S256(), X: new(big.Int), Y: new(big.Int)}
+ p := &ecdsa.PublicKey{Curve: crypto.S256(), X: new(big.Int), Y: new(big.Int)}
half := len(id) / 2
p.X.SetBytes(id[:half])
p.Y.SetBytes(id[half:])
diff --git a/p2p/discover/ntp.go b/p2p/discover/ntp.go
index c1a4b3af10..1bb52399fb 100644
--- a/p2p/discover/ntp.go
+++ b/p2p/discover/ntp.go
@@ -23,11 +23,9 @@ import (
"fmt"
"net"
"sort"
- "strings"
"time"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/log"
)
const (
@@ -51,16 +49,10 @@ func checkClockDrift() {
return
}
if drift < -driftThreshold || drift > driftThreshold {
- warning := fmt.Sprintf("System clock seems off by %v, which can prevent network connectivity", drift)
- howtofix := fmt.Sprintf("Please enable network time synchronisation in system settings")
- separator := strings.Repeat("-", len(warning))
-
- glog.V(logger.Warn).Info(separator)
- glog.V(logger.Warn).Info(warning)
- glog.V(logger.Warn).Info(howtofix)
- glog.V(logger.Warn).Info(separator)
+ log.Warn(fmt.Sprintf("System clock seems off by %v, which can prevent network connectivity", drift))
+ log.Warn("Please enable network time synchronisation in system settings.")
} else {
- glog.V(logger.Debug).Infof("Sanity NTP check reported %v drift, all ok", drift)
+ log.Debug("NTP sanity check done", "drift", drift)
}
}
diff --git a/p2p/discover/table.go b/p2p/discover/table.go
index 839e3ec7e7..2f5a26c34c 100644
--- a/p2p/discover/table.go
+++ b/p2p/discover/table.go
@@ -34,8 +34,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/log"
)
const (
@@ -278,10 +277,10 @@ func (tab *Table) lookup(targetID NodeID, refreshIfEmpty bool) []*Node {
// Bump the failure counter to detect and evacuate non-bonded entries
fails := tab.db.findFails(n.ID) + 1
tab.db.updateFindFails(n.ID, fails)
- glog.V(logger.Detail).Infof("Bumping failures for %x: %d", n.ID[:8], fails)
+ log.Trace("Bumping findnode failure counter", "id", n.ID, "failcount", fails)
if fails >= maxFindnodeFailures {
- glog.V(logger.Detail).Infof("Evacuating node %x: %d findnode failures", n.ID[:8], fails)
+ log.Trace("Too many findnode failures, dropping", "id", n.ID, "failcount", fails)
tab.delete(n)
}
}
@@ -384,14 +383,13 @@ func (tab *Table) doRefresh(done chan struct{}) {
// (hopefully) still alive.
seeds := tab.db.querySeeds(seedCount, seedMaxAge)
seeds = tab.bondall(append(seeds, tab.nursery...))
- if glog.V(logger.Debug) {
- if len(seeds) == 0 {
- glog.Infof("no seed nodes found")
- }
- for _, n := range seeds {
- age := time.Since(tab.db.lastPong(n.ID))
- glog.Infof("seed node (age %v): %v", age, n)
- }
+
+ if len(seeds) == 0 {
+ log.Debug("No discv4 seed nodes found")
+ }
+ for _, n := range seeds {
+ age := log.Lazy{Fn: func() time.Duration { return time.Since(tab.db.lastPong(n.ID)) }}
+ log.Trace("Found seed node in database", "id", n.ID, "addr", n.addr(), "age", age)
}
tab.mutex.Lock()
tab.stuff(seeds)
@@ -470,7 +468,7 @@ func (tab *Table) bond(pinged bool, id NodeID, addr *net.UDPAddr, tcpPort uint16
var result error
age := time.Since(tab.db.lastPong(id))
if node == nil || fails > 0 || age > nodeDBNodeExpiration {
- glog.V(logger.Detail).Infof("Bonding %x: known=%t, fails=%d age=%v", id[:8], node != nil, fails, age)
+ log.Trace("Starting bonding ping/pong", "id", id, "known", node != nil, "failcount", fails, "age", age)
tab.bondmu.Lock()
w := tab.bonding[id]
diff --git a/p2p/discover/udp.go b/p2p/discover/udp.go
index e09c63ffb6..93545e7d55 100644
--- a/p2p/discover/udp.go
+++ b/p2p/discover/udp.go
@@ -26,8 +26,7 @@ import (
"time"
"github.com/ethereum/go-ethereum/crypto"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/p2p/nat"
"github.com/ethereum/go-ethereum/p2p/netutil"
"github.com/ethereum/go-ethereum/rlp"
@@ -148,6 +147,7 @@ func nodeToRPC(n *Node) rpcNode {
type packet interface {
handle(t *udp, from *net.UDPAddr, fromID NodeID, mac []byte) error
+ name() string
}
type conn interface {
@@ -224,7 +224,7 @@ func ListenUDP(priv *ecdsa.PrivateKey, laddr string, natm nat.Interface, nodeDBP
if err != nil {
return nil, err
}
- glog.V(logger.Info).Infoln("Listening,", tab.self)
+ log.Debug("UDP listener up", "self", tab.self)
return tab, nil
}
@@ -270,7 +270,7 @@ func (t *udp) close() {
func (t *udp) ping(toid NodeID, toaddr *net.UDPAddr) error {
// TODO: maybe check for ReplyTo field in callback to measure RTT
errc := t.pending(toid, pongPacket, func(interface{}) bool { return true })
- t.send(toaddr, pingPacket, ping{
+ t.send(toaddr, pingPacket, &ping{
Version: Version,
From: t.ourEndpoint,
To: makeEndpoint(toaddr, 0), // TODO: maybe use known TCP port from DB
@@ -294,14 +294,14 @@ func (t *udp) findnode(toid NodeID, toaddr *net.UDPAddr, target NodeID) ([]*Node
nreceived++
n, err := t.nodeFromRPC(toaddr, rn)
if err != nil {
- glog.V(logger.Detail).Infof("invalid neighbor node (%v) from %v: %v", rn.IP, toaddr, err)
+ log.Trace("Invalid neighbor node received", "ip", rn.IP, "addr", toaddr, "err", err)
continue
}
nodes = append(nodes, n)
}
return nreceived >= bucketSize
})
- t.send(toaddr, findnodePacket, findnode{
+ t.send(toaddr, findnodePacket, &findnode{
Target: target,
Expiration: uint64(time.Now().Add(expiration).Unix()),
})
@@ -459,15 +459,13 @@ func init() {
}
}
-func (t *udp) send(toaddr *net.UDPAddr, ptype byte, req interface{}) error {
+func (t *udp) send(toaddr *net.UDPAddr, ptype byte, req packet) error {
packet, err := encodePacket(t.priv, ptype, req)
if err != nil {
return err
}
- glog.V(logger.Detail).Infof(">>> %v %T\n", toaddr, req)
- if _, err = t.conn.WriteToUDP(packet, toaddr); err != nil {
- glog.V(logger.Detail).Infoln("UDP send failed:", err)
- }
+ _, err = t.conn.WriteToUDP(packet, toaddr)
+ log.Trace(">> "+req.name(), "addr", toaddr, "err", err)
return err
}
@@ -476,13 +474,13 @@ func encodePacket(priv *ecdsa.PrivateKey, ptype byte, req interface{}) ([]byte,
b.Write(headSpace)
b.WriteByte(ptype)
if err := rlp.Encode(b, req); err != nil {
- glog.V(logger.Error).Infoln("error encoding packet:", err)
+ log.Error("Can't encode discv4 packet", "err", err)
return nil, err
}
packet := b.Bytes()
sig, err := crypto.Sign(crypto.Keccak256(packet[headSize:]), priv)
if err != nil {
- glog.V(logger.Error).Infoln("could not sign packet:", err)
+ log.Error("Can't sign discv4 packet", "err", err)
return nil, err
}
copy(packet[macSize:], sig)
@@ -504,11 +502,11 @@ func (t *udp) readLoop() {
nbytes, from, err := t.conn.ReadFromUDP(buf)
if netutil.IsTemporaryError(err) {
// Ignore temporary read errors.
- glog.V(logger.Debug).Infof("Temporary read error: %v", err)
+ log.Debug("Temporary UDP read error", "err", err)
continue
} else if err != nil {
// Shut down the loop for permament errors.
- glog.V(logger.Debug).Infof("Read error: %v", err)
+ log.Debug("UDP read error", "err", err)
return
}
t.handlePacket(from, buf[:nbytes])
@@ -518,14 +516,11 @@ func (t *udp) readLoop() {
func (t *udp) handlePacket(from *net.UDPAddr, buf []byte) error {
packet, fromID, hash, err := decodePacket(buf)
if err != nil {
- glog.V(logger.Debug).Infof("Bad packet from %v: %v\n", from, err)
+ log.Debug("Bad discv4 packet", "addr", from, "err", err)
return err
}
- status := "ok"
- if err = packet.handle(t, from, fromID, hash); err != nil {
- status = err.Error()
- }
- glog.V(logger.Detail).Infof("<<< %v %T: %s\n", from, packet, status)
+ err = packet.handle(t, from, fromID, hash)
+ log.Trace("<< "+packet.name(), "addr", from, "err", err)
return err
}
@@ -564,7 +559,7 @@ func (req *ping) handle(t *udp, from *net.UDPAddr, fromID NodeID, mac []byte) er
if expired(req.Expiration) {
return errExpired
}
- t.send(from, pongPacket, pong{
+ t.send(from, pongPacket, &pong{
To: makeEndpoint(from, req.From.TCP),
ReplyTok: mac,
Expiration: uint64(time.Now().Add(expiration).Unix()),
@@ -576,6 +571,8 @@ func (req *ping) handle(t *udp, from *net.UDPAddr, fromID NodeID, mac []byte) er
return nil
}
+func (req *ping) name() string { return "PING/v4" }
+
func (req *pong) handle(t *udp, from *net.UDPAddr, fromID NodeID, mac []byte) error {
if expired(req.Expiration) {
return errExpired
@@ -586,6 +583,8 @@ func (req *pong) handle(t *udp, from *net.UDPAddr, fromID NodeID, mac []byte) er
return nil
}
+func (req *pong) name() string { return "PONG/v4" }
+
func (req *findnode) handle(t *udp, from *net.UDPAddr, fromID NodeID, mac []byte) error {
if expired(req.Expiration) {
return errExpired
@@ -614,13 +613,15 @@ func (req *findnode) handle(t *udp, from *net.UDPAddr, fromID NodeID, mac []byte
}
p.Nodes = append(p.Nodes, nodeToRPC(n))
if len(p.Nodes) == maxNeighbors || i == len(closest)-1 {
- t.send(from, neighborsPacket, p)
+ t.send(from, neighborsPacket, &p)
p.Nodes = p.Nodes[:0]
}
}
return nil
}
+func (req *findnode) name() string { return "FINDNODE/v4" }
+
func (req *neighbors) handle(t *udp, from *net.UDPAddr, fromID NodeID, mac []byte) error {
if expired(req.Expiration) {
return errExpired
@@ -631,6 +632,8 @@ func (req *neighbors) handle(t *udp, from *net.UDPAddr, fromID NodeID, mac []byt
return nil
}
+func (req *neighbors) name() string { return "NEIGHBORS/v4" }
+
func expired(ts uint64) bool {
return time.Unix(int64(ts), 0).Before(time.Now())
}
diff --git a/p2p/discv5/crypto.go b/p2p/discv5/crypto.go
deleted file mode 100644
index 48b2a8a729..0000000000
--- a/p2p/discv5/crypto.go
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2016 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see .
-
-package discv5
-
-import (
- //"github.com/btcsuite/btcd/btcec"
- "github.com/ethereum/go-ethereum/crypto/secp256k1"
-)
-
-func S256() *secp256k1.BitCurve {
- return secp256k1.S256()
-}
-
-// This version should be used for NaCl compilation
-/*func S256() *btcec.KoblitzCurve {
- return S256()
-}*/
diff --git a/p2p/discv5/database.go b/p2p/discv5/database.go
index 44be8a74ec..a3b044ec18 100644
--- a/p2p/discv5/database.go
+++ b/p2p/discv5/database.go
@@ -23,13 +23,13 @@ import (
"bytes"
"crypto/rand"
"encoding/binary"
+ "fmt"
"os"
"sync"
"time"
"github.com/ethereum/go-ethereum/crypto"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rlp"
"github.com/syndtr/goleveldb/leveldb"
"github.com/syndtr/goleveldb/leveldb/errors"
@@ -192,7 +192,7 @@ func (db *nodeDB) fetchRLP(key []byte, val interface{}) error {
}
err = rlp.DecodeBytes(blob, val)
if err != nil {
- glog.V(logger.Warn).Infof("key %x (%T) %v", key, val, err)
+ log.Warn(fmt.Sprintf("key %x (%T) %v", key, val, err))
}
return err
}
@@ -244,7 +244,7 @@ func (db *nodeDB) expirer() {
select {
case <-tick:
if err := db.expireNodes(); err != nil {
- glog.V(logger.Error).Infof("Failed to expire nodedb items: %v", err)
+ log.Error(fmt.Sprintf("Failed to expire nodedb items: %v", err))
}
case <-db.quit:
@@ -396,9 +396,7 @@ func nextNode(it iterator.Iterator) *Node {
}
var n Node
if err := rlp.DecodeBytes(it.Value(), &n); err != nil {
- if glog.V(logger.Warn) {
- glog.Errorf("invalid node %x: %v", id, err)
- }
+ log.Warn(fmt.Sprintf("invalid node %x: %v", id, err))
continue
}
return &n
diff --git a/p2p/discv5/net.go b/p2p/discv5/net.go
index 74d485836e..a39cfcc645 100644
--- a/p2p/discv5/net.go
+++ b/p2p/discv5/net.go
@@ -28,8 +28,7 @@ import (
"github.com/ethereum/go-ethereum/common/mclock"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/crypto/sha3"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/p2p/nat"
"github.com/ethereum/go-ethereum/p2p/netutil"
"github.com/ethereum/go-ethereum/rlp"
@@ -437,10 +436,10 @@ loop:
if err := net.handle(n, pkt.ev, &pkt); err != nil {
status = err.Error()
}
- if glog.V(logger.Detail) {
- glog.Infof("<<< (%d) %v from %x@%v: %v -> %v (%v)",
+ log.Trace("", "msg", log.Lazy{Fn: func() string {
+ return fmt.Sprintf("<<< (%d) %v from %x@%v: %v -> %v (%v)",
net.tab.count, pkt.ev, pkt.remoteID[:8], pkt.remoteAddr, prestate, n.state, status)
- }
+ }})
// TODO: persist state if n.state goes >= known, delete if it goes <= known
// State transition timeouts.
@@ -456,10 +455,10 @@ loop:
if err := net.handle(timeout.node, timeout.ev, nil); err != nil {
status = err.Error()
}
- if glog.V(logger.Detail) {
- glog.Infof("--- (%d) %v for %x@%v: %v -> %v (%v)",
+ log.Trace("", "msg", log.Lazy{Fn: func() string {
+ return fmt.Sprintf("--- (%d) %v for %x@%v: %v -> %v (%v)",
net.tab.count, timeout.ev, timeout.node.ID[:8], timeout.node.addr(), prestate, timeout.node.state, status)
- }
+ }})
// Querying.
case q := <-net.queryReq:
@@ -655,7 +654,7 @@ loop:
}
debugLog("loop stopped")
- glog.V(logger.Debug).Infof("shutting down")
+ log.Debug(fmt.Sprintf("shutting down"))
if net.conn != nil {
net.conn.Close()
}
@@ -685,20 +684,20 @@ func (net *Network) refresh(done chan<- struct{}) {
seeds = net.nursery
}
if len(seeds) == 0 {
- glog.V(logger.Detail).Info("no seed nodes found")
+ log.Trace(fmt.Sprint("no seed nodes found"))
close(done)
return
}
for _, n := range seeds {
- if glog.V(logger.Debug) {
+ log.Debug("", "msg", log.Lazy{Fn: func() string {
var age string
if net.db != nil {
age = time.Since(net.db.lastPong(n.ID)).String()
} else {
age = "unknown"
}
- glog.Infof("seed node (age %s): %v", age, n)
- }
+ return fmt.Sprintf("seed node (age %s): %v", age, n)
+ }})
n = net.internNodeFromDB(n)
if n.state == unknown {
net.transition(n, verifyinit)
@@ -1254,7 +1253,7 @@ func (net *Network) handleNeighboursPacket(n *Node, pkt *ingressPacket) error {
for i, rn := range req.Nodes {
nn, err := net.internNodeFromNeighbours(pkt.remoteAddr, rn)
if err != nil {
- glog.V(logger.Debug).Infof("invalid neighbour (%v) from %x@%v: %v", rn.IP, n.ID[:8], pkt.remoteAddr, err)
+ log.Debug(fmt.Sprintf("invalid neighbour (%v) from %x@%v: %v", rn.IP, n.ID[:8], pkt.remoteAddr, err))
continue
}
nodes[i] = nn
diff --git a/p2p/discv5/node.go b/p2p/discv5/node.go
index cfc833ff55..c99b4da145 100644
--- a/p2p/discv5/node.go
+++ b/p2p/discv5/node.go
@@ -297,7 +297,7 @@ func PubkeyID(pub *ecdsa.PublicKey) NodeID {
// Pubkey returns the public key represented by the node ID.
// It returns an error if the ID is not a point on the curve.
func (id NodeID) Pubkey() (*ecdsa.PublicKey, error) {
- p := &ecdsa.PublicKey{Curve: S256(), X: new(big.Int), Y: new(big.Int)}
+ p := &ecdsa.PublicKey{Curve: crypto.S256(), X: new(big.Int), Y: new(big.Int)}
half := len(id) / 2
p.X.SetBytes(id[:half])
p.Y.SetBytes(id[half:])
diff --git a/p2p/discv5/ntp.go b/p2p/discv5/ntp.go
index 81c0e63365..f78d5dc43c 100644
--- a/p2p/discv5/ntp.go
+++ b/p2p/discv5/ntp.go
@@ -26,8 +26,7 @@ import (
"strings"
"time"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/log"
)
const (
@@ -55,12 +54,12 @@ func checkClockDrift() {
howtofix := fmt.Sprintf("Please enable network time synchronisation in system settings")
separator := strings.Repeat("-", len(warning))
- glog.V(logger.Warn).Info(separator)
- glog.V(logger.Warn).Info(warning)
- glog.V(logger.Warn).Info(howtofix)
- glog.V(logger.Warn).Info(separator)
+ log.Warn(fmt.Sprint(separator))
+ log.Warn(fmt.Sprint(warning))
+ log.Warn(fmt.Sprint(howtofix))
+ log.Warn(fmt.Sprint(separator))
} else {
- glog.V(logger.Debug).Infof("Sanity NTP check reported %v drift, all ok", drift)
+ log.Debug(fmt.Sprintf("Sanity NTP check reported %v drift, all ok", drift))
}
}
diff --git a/p2p/discv5/sim_test.go b/p2p/discv5/sim_test.go
index 3f7fe7463b..bf57872e2d 100644
--- a/p2p/discv5/sim_test.go
+++ b/p2p/discv5/sim_test.go
@@ -65,10 +65,6 @@ func TestSimTopics(t *testing.T) {
if runWithPlaygroundTime(t) {
return
}
-
- // glog.SetV(6)
- // glog.SetToStderr(true)
-
sim := newSimulation()
bootnode := sim.launchNode(false)
@@ -158,10 +154,6 @@ func TestSimTopicHierarchy(t *testing.T) {
if runWithPlaygroundTime(t) {
return
}
-
- // glog.SetV(6)
- // glog.SetToStderr(true)
-
sim := newSimulation()
bootnode := sim.launchNode(false)
diff --git a/p2p/discv5/udp.go b/p2p/discv5/udp.go
index b43f6d1980..26087cd8e5 100644
--- a/p2p/discv5/udp.go
+++ b/p2p/discv5/udp.go
@@ -26,8 +26,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/p2p/nat"
"github.com/ethereum/go-ethereum/p2p/netutil"
"github.com/ethereum/go-ethereum/rlp"
@@ -348,9 +347,9 @@ func (t *udp) sendPacket(toid NodeID, toaddr *net.UDPAddr, ptype byte, req inter
//fmt.Println(err)
return hash, err
}
- glog.V(logger.Detail).Infof(">>> %v to %x@%v\n", nodeEvent(ptype), toid[:8], toaddr)
+ log.Trace(fmt.Sprintf(">>> %v to %x@%v", nodeEvent(ptype), toid[:8], toaddr))
if _, err = t.conn.WriteToUDP(packet, toaddr); err != nil {
- glog.V(logger.Detail).Infoln("UDP send failed:", err)
+ log.Trace(fmt.Sprint("UDP send failed:", err))
}
//fmt.Println(err)
return hash, err
@@ -364,13 +363,13 @@ func encodePacket(priv *ecdsa.PrivateKey, ptype byte, req interface{}) (p, hash
b.Write(headSpace)
b.WriteByte(ptype)
if err := rlp.Encode(b, req); err != nil {
- glog.V(logger.Error).Infoln("error encoding packet:", err)
+ log.Error(fmt.Sprint("error encoding packet:", err))
return nil, nil, err
}
packet := b.Bytes()
sig, err := crypto.Sign(crypto.Keccak256(packet[headSize:]), priv)
if err != nil {
- glog.V(logger.Error).Infoln("could not sign packet:", err)
+ log.Error(fmt.Sprint("could not sign packet:", err))
return nil, nil, err
}
copy(packet[macSize:], sig)
@@ -393,11 +392,11 @@ func (t *udp) readLoop() {
nbytes, from, err := t.conn.ReadFromUDP(buf)
if netutil.IsTemporaryError(err) {
// Ignore temporary read errors.
- glog.V(logger.Debug).Infof("Temporary read error: %v", err)
+ log.Debug(fmt.Sprintf("Temporary read error: %v", err))
continue
} else if err != nil {
// Shut down the loop for permament errors.
- glog.V(logger.Debug).Infof("Read error: %v", err)
+ log.Debug(fmt.Sprintf("Read error: %v", err))
return
}
t.handlePacket(from, buf[:nbytes])
@@ -407,7 +406,7 @@ func (t *udp) readLoop() {
func (t *udp) handlePacket(from *net.UDPAddr, buf []byte) error {
pkt := ingressPacket{remoteAddr: from}
if err := decodePacket(buf, &pkt); err != nil {
- glog.V(logger.Debug).Infof("Bad packet from %v: %v\n", from, err)
+ log.Debug(fmt.Sprintf("Bad packet from %v: %v", from, err))
//fmt.Println("bad packet", err)
return err
}
diff --git a/p2p/nat/nat.go b/p2p/nat/nat.go
index f9ba93613e..a254648c66 100644
--- a/p2p/nat/nat.go
+++ b/p2p/nat/nat.go
@@ -25,8 +25,7 @@ import (
"sync"
"time"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/log"
"github.com/jackpal/go-nat-pmp"
)
@@ -99,16 +98,17 @@ const (
// Map adds a port mapping on m and keeps it alive until c is closed.
// This function is typically invoked in its own goroutine.
func Map(m Interface, c chan struct{}, protocol string, extport, intport int, name string) {
+ log := log.New("proto", protocol, "extport", extport, "intport", intport, "interface", m)
refresh := time.NewTimer(mapUpdateInterval)
defer func() {
refresh.Stop()
- glog.V(logger.Debug).Infof("deleting port mapping: %s %d -> %d (%s) using %s\n", protocol, extport, intport, name, m)
+ log.Debug("Deleting port mapping")
m.DeleteMapping(protocol, extport, intport)
}()
if err := m.AddMapping(protocol, extport, intport, name, mapTimeout); err != nil {
- glog.V(logger.Debug).Infof("network port %s:%d could not be mapped: %v\n", protocol, intport, err)
+ log.Debug("Couldn't add port mapping", "err", err)
} else {
- glog.V(logger.Info).Infof("mapped network port %s:%d -> %d (%s) using %s\n", protocol, extport, intport, name, m)
+ log.Info("Mapped network port")
}
for {
select {
@@ -117,9 +117,9 @@ func Map(m Interface, c chan struct{}, protocol string, extport, intport int, na
return
}
case <-refresh.C:
- glog.V(logger.Detail).Infof("refresh port mapping %s:%d -> %d (%s) using %s\n", protocol, extport, intport, name, m)
+ log.Trace("Refreshing port mapping")
if err := m.AddMapping(protocol, extport, intport, name, mapTimeout); err != nil {
- glog.V(logger.Debug).Infof("network port %s:%d could not be mapped: %v\n", protocol, intport, err)
+ log.Debug("Couldn't add port mapping", "err", err)
}
refresh.Reset(mapUpdateInterval)
}
diff --git a/p2p/peer.go b/p2p/peer.go
index b9d6c099dd..a9c20189a4 100644
--- a/p2p/peer.go
+++ b/p2p/peer.go
@@ -17,7 +17,6 @@
package p2p
import (
- "errors"
"fmt"
"io"
"net"
@@ -25,8 +24,8 @@ import (
"sync"
"time"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/common/mclock"
+ "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/p2p/discover"
"github.com/ethereum/go-ethereum/rlp"
)
@@ -65,6 +64,8 @@ type protoHandshake struct {
type Peer struct {
rw *conn
running map[string]*protoRW
+ log log.Logger
+ created mclock.AbsTime
wg sync.WaitGroup
protoErr chan error
@@ -126,20 +127,25 @@ func newPeer(conn *conn, protocols []Protocol) *Peer {
p := &Peer{
rw: conn,
running: protomap,
+ created: mclock.Now(),
disc: make(chan DiscReason),
protoErr: make(chan error, len(protomap)+1), // protocols + pingLoop
closed: make(chan struct{}),
+ log: log.New("id", conn.id, "conn", conn.flags),
}
return p
}
-func (p *Peer) run() DiscReason {
+func (p *Peer) Log() log.Logger {
+ return p.log
+}
+
+func (p *Peer) run() (remoteRequested bool, err error) {
var (
writeStart = make(chan struct{}, 1)
writeErr = make(chan error, 1)
readErr = make(chan error, 1)
- reason DiscReason
- requested bool
+ reason DiscReason // sent to the peer
)
p.wg.Add(2)
go p.readLoop(readErr)
@@ -153,31 +159,26 @@ func (p *Peer) run() DiscReason {
loop:
for {
select {
- case err := <-writeErr:
+ case err = <-writeErr:
// A write finished. Allow the next write to start if
// there was no error.
if err != nil {
- glog.V(logger.Detail).Infof("%v: write error: %v\n", p, err)
reason = DiscNetworkError
break loop
}
writeStart <- struct{}{}
- case err := <-readErr:
+ case err = <-readErr:
if r, ok := err.(DiscReason); ok {
- glog.V(logger.Debug).Infof("%v: remote requested disconnect: %v\n", p, r)
- requested = true
+ remoteRequested = true
reason = r
} else {
- glog.V(logger.Detail).Infof("%v: read error: %v\n", p, err)
reason = DiscNetworkError
}
break loop
- case err := <-p.protoErr:
+ case err = <-p.protoErr:
reason = discReasonForError(err)
- glog.V(logger.Debug).Infof("%v: protocol error: %v (%v)\n", p, err, reason)
break loop
- case reason = <-p.disc:
- glog.V(logger.Debug).Infof("%v: locally requested disconnect: %v\n", p, reason)
+ case err = <-p.disc:
break loop
}
}
@@ -185,10 +186,7 @@ loop:
close(p.closed)
p.rw.close(reason)
p.wg.Wait()
- if requested {
- reason = DiscRequested
- }
- return reason
+ return remoteRequested, err
}
func (p *Peer) pingLoop() {
@@ -298,14 +296,14 @@ func (p *Peer) startProtocols(writeStart <-chan struct{}, writeErr chan<- error)
proto.closed = p.closed
proto.wstart = writeStart
proto.werr = writeErr
- glog.V(logger.Detail).Infof("%v: Starting protocol %s/%d\n", p, proto.Name, proto.Version)
+ p.log.Trace(fmt.Sprintf("Starting protocol %s/%d", proto.Name, proto.Version))
go func() {
err := proto.Run(p, proto)
if err == nil {
- glog.V(logger.Detail).Infof("%v: Protocol %s/%d returned\n", p, proto.Name, proto.Version)
- err = errors.New("protocol returned")
+ p.log.Trace(fmt.Sprintf("Protocol %s/%d returned", proto.Name, proto.Version))
+ err = errProtocolReturned
} else if err != io.EOF {
- glog.V(logger.Detail).Infof("%v: Protocol %s/%d error: %v\n", p, proto.Name, proto.Version, err)
+ p.log.Trace(fmt.Sprintf("Protocol %s/%d failed", proto.Name, proto.Version), "err", err)
}
p.protoErr <- err
p.wg.Done()
diff --git a/p2p/peer_error.go b/p2p/peer_error.go
index 62c7b665dd..a1cddb707b 100644
--- a/p2p/peer_error.go
+++ b/p2p/peer_error.go
@@ -17,6 +17,7 @@
package p2p
import (
+ "errors"
"fmt"
)
@@ -51,6 +52,8 @@ func (self *peerError) Error() string {
return self.message
}
+var errProtocolReturned = errors.New("protocol returned")
+
type DiscReason uint
const (
@@ -70,24 +73,24 @@ const (
)
var discReasonToString = [...]string{
- DiscRequested: "Disconnect requested",
- DiscNetworkError: "Network error",
- DiscProtocolError: "Breach of protocol",
- DiscUselessPeer: "Useless peer",
- DiscTooManyPeers: "Too many peers",
- DiscAlreadyConnected: "Already connected",
- DiscIncompatibleVersion: "Incompatible P2P protocol version",
- DiscInvalidIdentity: "Invalid node identity",
- DiscQuitting: "Client quitting",
- DiscUnexpectedIdentity: "Unexpected identity",
- DiscSelf: "Connected to self",
- DiscReadTimeout: "Read timeout",
- DiscSubprotocolError: "Subprotocol error",
+ DiscRequested: "disconnect requested",
+ DiscNetworkError: "network error",
+ DiscProtocolError: "breach of protocol",
+ DiscUselessPeer: "useless peer",
+ DiscTooManyPeers: "too many peers",
+ DiscAlreadyConnected: "already connected",
+ DiscIncompatibleVersion: "incompatible p2p protocol version",
+ DiscInvalidIdentity: "invalid node identity",
+ DiscQuitting: "client quitting",
+ DiscUnexpectedIdentity: "unexpected identity",
+ DiscSelf: "connected to self",
+ DiscReadTimeout: "read timeout",
+ DiscSubprotocolError: "subprotocol error",
}
func (d DiscReason) String() string {
if len(discReasonToString) < int(d) {
- return fmt.Sprintf("Unknown Reason(%d)", d)
+ return fmt.Sprintf("unknown disconnect reason %d", d)
}
return discReasonToString[d]
}
@@ -100,6 +103,9 @@ func discReasonForError(err error) DiscReason {
if reason, ok := err.(DiscReason); ok {
return reason
}
+ if err == errProtocolReturned {
+ return DiscQuitting
+ }
peerError, ok := err.(*peerError)
if ok {
switch peerError.code {
diff --git a/p2p/peer_test.go b/p2p/peer_test.go
index f44300b15c..a3e1c74fd8 100644
--- a/p2p/peer_test.go
+++ b/p2p/peer_test.go
@@ -43,7 +43,7 @@ var discard = Protocol{
},
}
-func testPeer(protos []Protocol) (func(), *conn, *Peer, <-chan DiscReason) {
+func testPeer(protos []Protocol) (func(), *conn, *Peer, <-chan error) {
fd1, fd2 := net.Pipe()
c1 := &conn{fd: fd1, transport: newTestTransport(randomID(), fd1)}
c2 := &conn{fd: fd2, transport: newTestTransport(randomID(), fd2)}
@@ -53,15 +53,17 @@ func testPeer(protos []Protocol) (func(), *conn, *Peer, <-chan DiscReason) {
}
peer := newPeer(c1, protos)
- errc := make(chan DiscReason, 1)
- go func() { errc <- peer.run() }()
+ errc := make(chan error, 1)
+ go func() {
+ _, err := peer.run()
+ errc <- err
+ }()
closer := func() { c2.close(errors.New("close func called")) }
return closer, c2, peer, errc
}
func TestPeerProtoReadMsg(t *testing.T) {
- done := make(chan struct{})
proto := Protocol{
Name: "a",
Length: 5,
@@ -75,7 +77,6 @@ func TestPeerProtoReadMsg(t *testing.T) {
if err := ExpectMsg(rw, 4, []uint{3}); err != nil {
t.Error(err)
}
- close(done)
return nil
},
}
@@ -88,9 +89,10 @@ func TestPeerProtoReadMsg(t *testing.T) {
Send(rw, baseProtocolLength+4, []uint{3})
select {
- case <-done:
case err := <-errc:
- t.Errorf("peer returned: %v", err)
+ if err != errProtocolReturned {
+ t.Errorf("peer returned error: %v", err)
+ }
case <-time.After(2 * time.Second):
t.Errorf("receive timeout")
}
@@ -137,8 +139,8 @@ func TestPeerDisconnect(t *testing.T) {
}
select {
case reason := <-disc:
- if reason != DiscRequested {
- t.Errorf("run returned wrong reason: got %v, want %v", reason, DiscRequested)
+ if reason != DiscQuitting {
+ t.Errorf("run returned wrong reason: got %v, want %v", reason, DiscQuitting)
}
case <-time.After(500 * time.Millisecond):
t.Error("peer did not return")
diff --git a/p2p/rlpx.go b/p2p/rlpx.go
index c6fd841f7c..b2775cacdc 100644
--- a/p2p/rlpx.go
+++ b/p2p/rlpx.go
@@ -303,7 +303,7 @@ func (h *encHandshake) makeAuthMsg(prv *ecdsa.PrivateKey, token []byte) (*authMs
return nil, err
}
// Generate random keypair to for ECDH.
- h.randomPrivKey, err = ecies.GenerateKey(rand.Reader, secp256k1.S256(), nil)
+ h.randomPrivKey, err = ecies.GenerateKey(rand.Reader, crypto.S256(), nil)
if err != nil {
return nil, err
}
@@ -381,7 +381,7 @@ func (h *encHandshake) handleAuthMsg(msg *authMsgV4, prv *ecdsa.PrivateKey) erro
// Generate random keypair for ECDH.
// If a private key is already set, use it instead of generating one (for testing).
if h.randomPrivKey == nil {
- h.randomPrivKey, err = ecies.GenerateKey(rand.Reader, secp256k1.S256(), nil)
+ h.randomPrivKey, err = ecies.GenerateKey(rand.Reader, crypto.S256(), nil)
if err != nil {
return err
}
diff --git a/p2p/server.go b/p2p/server.go
index 298148d3ee..48b4e8be3d 100644
--- a/p2p/server.go
+++ b/p2p/server.go
@@ -25,8 +25,9 @@ import (
"sync"
"time"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/common/mclock"
+ "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/p2p/discover"
"github.com/ethereum/go-ethereum/p2p/discv5"
"github.com/ethereum/go-ethereum/p2p/nat"
@@ -163,12 +164,18 @@ type Server struct {
removestatic chan *discover.Node
posthandshake chan *conn
addpeer chan *conn
- delpeer chan *Peer
+ delpeer chan peerDrop
loopWG sync.WaitGroup // loop, listenLoop
}
type peerOpFunc func(map[discover.NodeID]*Peer)
+type peerDrop struct {
+ *Peer
+ err error
+ requested bool // true if signaled by the peer
+}
+
type connFlag int
const (
@@ -205,9 +212,9 @@ type transport interface {
}
func (c *conn) String() string {
- s := c.flags.String() + " conn"
+ s := c.flags.String()
if (c.id != discover.NodeID{}) {
- s += fmt.Sprintf(" %x", c.id[:8])
+ s += " " + c.id.String()
}
s += " " + c.fd.RemoteAddr().String()
return s
@@ -216,16 +223,16 @@ func (c *conn) String() string {
func (f connFlag) String() string {
s := ""
if f&trustedConn != 0 {
- s += " trusted"
+ s += "-trusted"
}
if f&dynDialedConn != 0 {
- s += " dyn dial"
+ s += "-dyndial"
}
if f&staticDialedConn != 0 {
- s += " static dial"
+ s += "-staticdial"
}
if f&inboundConn != 0 {
- s += " inbound"
+ s += "-inbound"
}
if s != "" {
s = s[1:]
@@ -289,26 +296,30 @@ func (srv *Server) Self() *discover.Node {
srv.lock.Lock()
defer srv.lock.Unlock()
- // If the server's not running, return an empty node
if !srv.running {
return &discover.Node{IP: net.ParseIP("0.0.0.0")}
}
- // If the node is running but discovery is off, manually assemble the node infos
- if srv.ntab == nil {
- // Inbound connections disabled, use zero address
- if srv.listener == nil {
+ return srv.makeSelf(srv.listener, srv.ntab)
+}
+
+func (srv *Server) makeSelf(listener net.Listener, ntab discoverTable) *discover.Node {
+ // If the server's not running, return an empty node.
+ // If the node is running but discovery is off, manually assemble the node infos.
+ if ntab == nil {
+ // Inbound connections disabled, use zero address.
+ if listener == nil {
return &discover.Node{IP: net.ParseIP("0.0.0.0"), ID: discover.PubkeyID(&srv.PrivateKey.PublicKey)}
}
// Otherwise inject the listener address too
- addr := srv.listener.Addr().(*net.TCPAddr)
+ addr := listener.Addr().(*net.TCPAddr)
return &discover.Node{
ID: discover.PubkeyID(&srv.PrivateKey.PublicKey),
IP: addr.IP,
TCP: uint16(addr.Port),
}
}
- // Otherwise return the live node infos
- return srv.ntab.Self()
+ // Otherwise return the discovery node.
+ return ntab.Self()
}
// Stop terminates the server and all active peer connections.
@@ -337,7 +348,7 @@ func (srv *Server) Start() (err error) {
return errors.New("server already running")
}
srv.running = true
- glog.V(logger.Info).Infoln("Starting Server")
+ log.Info("Starting P2P networking")
// static fields
if srv.PrivateKey == nil {
@@ -351,7 +362,7 @@ func (srv *Server) Start() (err error) {
}
srv.quit = make(chan struct{})
srv.addpeer = make(chan *conn)
- srv.delpeer = make(chan *Peer)
+ srv.delpeer = make(chan peerDrop)
srv.posthandshake = make(chan *conn)
srv.addstatic = make(chan *discover.Node)
srv.removestatic = make(chan *discover.Node)
@@ -399,7 +410,7 @@ func (srv *Server) Start() (err error) {
}
}
if srv.NoDial && srv.ListenAddr == "" {
- glog.V(logger.Warn).Infoln("I will be kind-of useless, neither dialing nor listening.")
+ log.Warn("P2P server will be useless, neither dialing nor listening")
}
srv.loopWG.Add(1)
@@ -467,7 +478,7 @@ func (srv *Server) run(dialstate dialer) {
i := 0
for ; len(runningTasks) < maxActiveDialTasks && i < len(ts); i++ {
t := ts[i]
- glog.V(logger.Detail).Infoln("new task:", t)
+ log.Trace("New dial task", "task", t)
go func() { t.Do(srv); taskdone <- t }()
runningTasks = append(runningTasks, t)
}
@@ -490,19 +501,18 @@ running:
select {
case <-srv.quit:
// The server was stopped. Run the cleanup logic.
- glog.V(logger.Detail).Infoln("<-quit: spinning down")
break running
case n := <-srv.addstatic:
// This channel is used by AddPeer to add to the
// ephemeral static peer list. Add it to the dialer,
// it will keep the node connected.
- glog.V(logger.Detail).Infoln("<-addstatic:", n)
+ log.Debug("Adding static node", "node", n)
dialstate.addStatic(n)
case n := <-srv.removestatic:
// This channel is used by RemovePeer to send a
// disconnect request to a peer and begin the
// stop keeping the node connected
- glog.V(logger.Detail).Infoln("<-removestatic:", n)
+ log.Debug("Removing static node", "node", n)
dialstate.removeStatic(n)
if p, ok := peers[n.ID]; ok {
p.Disconnect(DiscRequested)
@@ -515,7 +525,7 @@ running:
// A task got done. Tell dialstate about it so it
// can update its state and remove it from the active
// tasks list.
- glog.V(logger.Detail).Infoln("<-taskdone:", t)
+ log.Trace("Dial task done", "task", t)
dialstate.taskDone(t, time.Now())
delTask(t)
case c := <-srv.posthandshake:
@@ -525,19 +535,17 @@ running:
// Ensure that the trusted flag is set before checking against MaxPeers.
c.flags |= trustedConn
}
- glog.V(logger.Detail).Infoln("<-posthandshake:", c)
// TODO: track in-progress inbound node IDs (pre-Peer) to avoid dialing them.
c.cont <- srv.encHandshakeChecks(peers, c)
case c := <-srv.addpeer:
// At this point the connection is past the protocol handshake.
// Its capabilities are known and the remote identity is verified.
- glog.V(logger.Detail).Infoln("<-addpeer:", c)
err := srv.protoHandshakeChecks(peers, c)
- if err != nil {
- glog.V(logger.Detail).Infof("Not adding %v as peer: %v", c, err)
- } else {
+ if err == nil {
// The handshakes are done and it passed all checks.
p := newPeer(c, srv.Protocols)
+ name := truncateName(c.name)
+ log.Debug("Adding p2p peer", "id", c.id, "name", name, "addr", c.fd.RemoteAddr(), "peers", len(peers)+1)
peers[c.id] = p
go srv.runPeer(p)
}
@@ -545,13 +553,16 @@ running:
// dial tasks complete after the peer has been added or
// discarded. Unblock the task last.
c.cont <- err
- case p := <-srv.delpeer:
+ case pd := <-srv.delpeer:
// A peer disconnected.
- glog.V(logger.Detail).Infoln("<-delpeer:", p)
- delete(peers, p.ID())
+ d := common.PrettyDuration(mclock.Now() - pd.created)
+ pd.log.Debug("Removing p2p peer", "duration", d, "peers", len(peers)-1, "req", pd.requested, "err", pd.err)
+ delete(peers, pd.ID())
}
}
+ log.Trace("P2P networking is spinning down")
+
// Terminate discovery. If there is a running lookup it will terminate soon.
if srv.ntab != nil {
srv.ntab.Close()
@@ -566,10 +577,9 @@ running:
// Wait for peers to shut down. Pending connections and tasks are
// not handled here and will terminate soon-ish because srv.quit
// is closed.
- glog.V(logger.Detail).Infof("ignoring %d pending tasks at spindown", len(runningTasks))
for len(peers) > 0 {
p := <-srv.delpeer
- glog.V(logger.Detail).Infoln("<-delpeer (spindown):", p)
+ p.log.Trace("<-delpeer (spindown)", "remainingTasks", len(runningTasks))
delete(peers, p.ID())
}
}
@@ -605,7 +615,7 @@ type tempError interface {
// inbound connections.
func (srv *Server) listenLoop() {
defer srv.loopWG.Done()
- glog.V(logger.Info).Infoln("Listening on", srv.listener.Addr())
+ log.Info("RLPx listener up", "self", srv.makeSelf(srv.listener, srv.ntab))
// This channel acts as a semaphore limiting
// active inbound connections that are lingering pre-handshake.
@@ -630,10 +640,10 @@ func (srv *Server) listenLoop() {
for {
fd, err = srv.listener.Accept()
if tempErr, ok := err.(tempError); ok && tempErr.Temporary() {
- glog.V(logger.Debug).Infof("Temporary read error: %v", err)
+ log.Debug("Temporary read error", "err", err)
continue
} else if err != nil {
- glog.V(logger.Debug).Infof("Read error: %v", err)
+ log.Debug("Read error", "err", err)
return
}
break
@@ -642,7 +652,7 @@ func (srv *Server) listenLoop() {
// Reject connections that do not match NetRestrict.
if srv.NetRestrict != nil {
if tcp, ok := fd.RemoteAddr().(*net.TCPAddr); ok && !srv.NetRestrict.Contains(tcp.IP) {
- glog.V(logger.Debug).Infof("Rejected conn %v because it is not whitelisted in NetRestrict", fd.RemoteAddr())
+ log.Debug("Rejected conn (not whitelisted in NetRestrict)", "addr", fd.RemoteAddr())
fd.Close()
slots <- struct{}{}
continue
@@ -650,7 +660,7 @@ func (srv *Server) listenLoop() {
}
fd = newMeteredConn(fd, true)
- glog.V(logger.Debug).Infof("Accepted conn %v", fd.RemoteAddr())
+ log.Trace("Accepted connection", "addr", fd.RemoteAddr())
// Spawn the handler. It will give the slot back when the connection
// has been established.
@@ -677,36 +687,37 @@ func (srv *Server) setupConn(fd net.Conn, flags connFlag, dialDest *discover.Nod
// Run the encryption handshake.
var err error
if c.id, err = c.doEncHandshake(srv.PrivateKey, dialDest); err != nil {
- glog.V(logger.Debug).Infof("%v faild enc handshake: %v", c, err)
+ log.Trace("Failed RLPx handshake", "addr", c.fd.RemoteAddr(), "conn", c.flags, "err", err)
c.close(err)
return
}
+ clog := log.New("id", c.id, "addr", c.fd.RemoteAddr(), "conn", c.flags)
// For dialed connections, check that the remote public key matches.
if dialDest != nil && c.id != dialDest.ID {
c.close(DiscUnexpectedIdentity)
- glog.V(logger.Debug).Infof("%v dialed identity mismatch, want %x", c, dialDest.ID[:8])
+ clog.Trace("Dialed identity mismatch", "want", c, dialDest.ID)
return
}
if err := srv.checkpoint(c, srv.posthandshake); err != nil {
- glog.V(logger.Debug).Infof("%v failed checkpoint posthandshake: %v", c, err)
+ clog.Trace("Rejected peer before protocol handshake", "err", err)
c.close(err)
return
}
// Run the protocol handshake
phs, err := c.doProtoHandshake(srv.ourHandshake)
if err != nil {
- glog.V(logger.Debug).Infof("%v failed proto handshake: %v", c, err)
+ clog.Trace("Failed proto handshake", "err", err)
c.close(err)
return
}
if phs.ID != c.id {
- glog.V(logger.Debug).Infof("%v wrong proto handshake identity: %x", c, phs.ID[:8])
+ clog.Trace("Wrong devp2p handshake identity", "err", phs.ID)
c.close(DiscUnexpectedIdentity)
return
}
c.caps, c.name = phs.Caps, phs.Name
if err := srv.checkpoint(c, srv.addpeer); err != nil {
- glog.V(logger.Debug).Infof("%v failed checkpoint addpeer: %v", c, err)
+ clog.Trace("Rejected peer", "err", err)
c.close(err)
return
}
@@ -714,6 +725,13 @@ func (srv *Server) setupConn(fd net.Conn, flags connFlag, dialDest *discover.Nod
// launched by run.
}
+func truncateName(s string) string {
+ if len(s) > 20 {
+ return s[:20] + "..."
+ }
+ return s
+}
+
// checkpoint sends the conn to run, which performs the
// post-handshake checks for the stage (posthandshake, addpeer).
func (srv *Server) checkpoint(c *conn, stage chan<- *conn) error {
@@ -734,17 +752,13 @@ func (srv *Server) checkpoint(c *conn, stage chan<- *conn) error {
// it waits until the Peer logic returns and removes
// the peer.
func (srv *Server) runPeer(p *Peer) {
- glog.V(logger.Debug).Infof("Added %v\n", p)
-
if srv.newPeerHook != nil {
srv.newPeerHook(p)
}
- discreason := p.run()
+ remoteRequested, err := p.run()
// Note: run waits for existing peers to be sent on srv.delpeer
// before returning, so this send should not select on srv.quit.
- srv.delpeer <- p
-
- glog.V(logger.Debug).Infof("Removed %v (%v)\n", p, discreason)
+ srv.delpeer <- peerDrop{p, err, remoteRequested}
}
// NodeInfo represents a short summary of the information known about the host.
diff --git a/p2p/server_test.go b/p2p/server_test.go
index 313d086ec4..971faf002c 100644
--- a/p2p/server_test.go
+++ b/p2p/server_test.go
@@ -31,8 +31,7 @@ import (
)
func init() {
- // glog.SetV(6)
- // glog.SetToStderr(true)
+ // log.Root().SetHandler(log.LvlFilterHandler(log.LvlError, log.StreamHandler(os.Stderr, log.TerminalFormat(false))))
}
type testTransport struct {
diff --git a/params/bootnodes.go b/params/bootnodes.go
index 13414cb954..ab7ec46590 100644
--- a/params/bootnodes.go
+++ b/params/bootnodes.go
@@ -19,19 +19,22 @@ package params
// MainnetBootnodes are the enode URLs of the P2P bootstrap nodes running on
// the main Ethereum network.
var MainnetBootnodes = []string{
- // ETH/DEV Go Bootnodes
+
+ // Ethereum Foundation Go Bootnodes
"enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@52.16.188.185:30303", // IE
- "enode://de471bccee3d042261d52e9bff31458daecc406142b401d4cd848f677479f73104b9fdeb090af9583d3391b7f10cb2ba9e26865dd5fca4fcdc0fb1e3b723c786@54.94.239.50:30303", // BR
+ "enode://3f1d12044546b76342d59d4a05532c14b85aa669704bfe1f864fe079415aa2c02d743e03218e57a33fb94523adb54032871a6c51b2cc5514cb7c7e35b3ed0a99@13.93.211.84:30303", // US-WEST
+ "enode://78de8a0916848093c73790ead81d1928bec737d565119932b98c6b100d944b7a95e94f847f689fc723399d2e31129d182f7ef3863f2b4c820abbf3ab2722344d@191.235.84.50:30303", // BR
+ "enode://158f8aab45f6d19c6cbf4a089c2670541a8da11978a2f90dbf6a502a4a3bab80d288afdbeb7ec0ef6d92de563767f3b1ea9e8e334ca711e9f8e2df5a0385e8e6@13.75.154.138:30303", // AU
"enode://1118980bf48b0a3640bdba04e0fe78b1add18e1cd99bf22d53daac1fd9972ad650df52176e7c7d89d1114cfef2bc23a2959aa54998a46afcf7d91809f0855082@52.74.57.123:30303", // SG
- // ETH/DEV Cpp Bootnodes
- "enode://979b7fa28feeb35a4741660a16076f1943202cb72b6af70d327f053e248bab9ba81760f39d0701ef1d8f89cc1fbd2cacba0710a12cd5314d5e0c9021aa3637f9@5.1.83.226:30303",
+ // Ethereum Foundation Cpp Bootnodes
+ "enode://979b7fa28feeb35a4741660a16076f1943202cb72b6af70d327f053e248bab9ba81760f39d0701ef1d8f89cc1fbd2cacba0710a12cd5314d5e0c9021aa3637f9@5.1.83.226:30303", // DE
+
}
// TestnetBootnodes are the enode URLs of the P2P bootstrap nodes running on the
// Morden test network.
var TestnetBootnodes = []string{
- // ETH/DEV Go Bootnodes
"enode://e4533109cc9bd7604e4ff6c095f7a1d807e15b38e9bfeb05d3b7c423ba86af0a9e89abbf40bd9dde4250fef114cd09270fa4e224cbeef8b7bf05a51e8260d6b8@94.242.229.4:40404",
"enode://8c336ee6f03e99613ad21274f269479bf4413fb294d697ef15ab897598afb931f56beb8e97af530aee20ce2bcba5776f4a312bc168545de4d43736992c814592@94.242.229.203:30303",
}
diff --git a/params/config.go b/params/config.go
index 8c285781e9..47d7c2ad06 100644
--- a/params/config.go
+++ b/params/config.go
@@ -23,29 +23,43 @@ import (
"github.com/ethereum/go-ethereum/common"
)
-// MainnetChainConfig is the chain parameters to run a node on the main network.
-var MainnetChainConfig = &ChainConfig{
- ChainId: MainNetChainID,
- HomesteadBlock: MainNetHomesteadBlock,
- DAOForkBlock: MainNetDAOForkBlock,
- DAOForkSupport: true,
- EIP150Block: MainNetHomesteadGasRepriceBlock,
- EIP150Hash: MainNetHomesteadGasRepriceHash,
- EIP155Block: MainNetSpuriousDragon,
- EIP158Block: MainNetSpuriousDragon,
-}
+var (
+ // MainnetChainConfig is the chain parameters to run a node on the main network.
+ MainnetChainConfig = &ChainConfig{
+ ChainId: MainNetChainID,
+ HomesteadBlock: MainNetHomesteadBlock,
+ DAOForkBlock: MainNetDAOForkBlock,
+ DAOForkSupport: true,
+ EIP150Block: MainNetHomesteadGasRepriceBlock,
+ EIP150Hash: MainNetHomesteadGasRepriceHash,
+ EIP155Block: MainNetSpuriousDragon,
+ EIP158Block: MainNetSpuriousDragon,
+ }
-// TestnetChainConfig is the chain parameters to run a node on the test network.
-var TestnetChainConfig = &ChainConfig{
- ChainId: big.NewInt(3),
- HomesteadBlock: big.NewInt(0),
- DAOForkBlock: nil,
- DAOForkSupport: true,
- EIP150Block: big.NewInt(0),
- EIP150Hash: common.HexToHash("0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d"),
- EIP155Block: big.NewInt(10),
- EIP158Block: big.NewInt(10),
-}
+ // TestnetChainConfig contains the chain parameters to run a node on the ropsten test network.
+ TestnetChainConfig = &ChainConfig{
+ ChainId: big.NewInt(3),
+ HomesteadBlock: big.NewInt(0),
+ DAOForkBlock: nil,
+ DAOForkSupport: true,
+ EIP150Block: big.NewInt(0),
+ EIP150Hash: common.HexToHash("0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d"),
+ EIP155Block: big.NewInt(10),
+ EIP158Block: big.NewInt(10),
+ }
+
+ // AllProtocolChanges contains every protocol change (EIPs)
+ // introduced and accepted by the Ethereum core developers.
+ // TestChainConfig is like AllProtocolChanges but has chain ID 1.
+ //
+ // This configuration is intentionally not using keyed fields.
+ // This configuration must *always* have all forks enabled, which
+ // means that all fields must be set at all times. This forces
+ // anyone adding flags to the config to also have to set these
+ // fields.
+ AllProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0)}
+ TestChainConfig = &ChainConfig{big.NewInt(1), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0)}
+)
// ChainConfig is the core config which determines the blockchain settings.
//
@@ -67,7 +81,7 @@ type ChainConfig struct {
EIP158Block *big.Int `json:"eip158Block"` // EIP158 HF block
}
-// String implements the Stringer interface.
+// String implements the fmt.Stringer interface.
func (c *ChainConfig) String() string {
return fmt.Sprintf("{ChainID: %v Homestead: %v DAO: %v DAOSupport: %v EIP150: %v EIP155: %v EIP158: %v}",
c.ChainId,
@@ -80,17 +94,26 @@ func (c *ChainConfig) String() string {
)
}
-var (
- TestChainConfig = &ChainConfig{big.NewInt(1), new(big.Int), new(big.Int), true, new(big.Int), common.Hash{}, new(big.Int), new(big.Int)}
- TestRules = TestChainConfig.Rules(new(big.Int))
-)
-
// IsHomestead returns whether num is either equal to the homestead block or greater.
func (c *ChainConfig) IsHomestead(num *big.Int) bool {
- if c.HomesteadBlock == nil || num == nil {
- return false
- }
- return num.Cmp(c.HomesteadBlock) >= 0
+ return isForked(c.HomesteadBlock, num)
+}
+
+// IsDAO returns whether num is either equal to the DAO fork block or greater.
+func (c *ChainConfig) IsDAOFork(num *big.Int) bool {
+ return isForked(c.DAOForkBlock, num)
+}
+
+func (c *ChainConfig) IsEIP150(num *big.Int) bool {
+ return isForked(c.EIP150Block, num)
+}
+
+func (c *ChainConfig) IsEIP155(num *big.Int) bool {
+ return isForked(c.EIP155Block, num)
+}
+
+func (c *ChainConfig) IsEIP158(num *big.Int) bool {
+ return isForked(c.EIP158Block, num)
}
// GasTable returns the gas table corresponding to the current phase (homestead or homestead reprice).
@@ -100,51 +123,110 @@ func (c *ChainConfig) GasTable(num *big.Int) GasTable {
if num == nil {
return GasTableHomestead
}
-
switch {
- case c.EIP158Block != nil && num.Cmp(c.EIP158Block) >= 0:
+ case c.IsEIP158(num):
return GasTableEIP158
- case c.EIP150Block != nil && num.Cmp(c.EIP150Block) >= 0:
+ case c.IsEIP150(num):
return GasTableHomesteadGasRepriceFork
default:
return GasTableHomestead
}
}
-func (c *ChainConfig) IsEIP150(num *big.Int) bool {
- if c.EIP150Block == nil || num == nil {
+// CheckCompatible checks whether scheduled fork transitions have been imported
+// with a mismatching chain configuration.
+func (c *ChainConfig) CheckCompatible(newcfg *ChainConfig, height uint64) *ConfigCompatError {
+ bhead := new(big.Int).SetUint64(height)
+
+ // Iterate checkCompatible to find the lowest conflict.
+ var lasterr *ConfigCompatError
+ for {
+ err := c.checkCompatible(newcfg, bhead)
+ if err == nil || (lasterr != nil && err.RewindTo == lasterr.RewindTo) {
+ break
+ }
+ lasterr = err
+ bhead.SetUint64(err.RewindTo)
+ }
+ return lasterr
+}
+
+func (c *ChainConfig) checkCompatible(newcfg *ChainConfig, head *big.Int) *ConfigCompatError {
+ if isForkIncompatible(c.HomesteadBlock, newcfg.HomesteadBlock, head) {
+ return newCompatError("Homestead fork block", c.HomesteadBlock, newcfg.HomesteadBlock)
+ }
+ if isForkIncompatible(c.DAOForkBlock, newcfg.DAOForkBlock, head) {
+ return newCompatError("DAO fork block", c.DAOForkBlock, newcfg.DAOForkBlock)
+ }
+ if c.IsDAOFork(head) && c.DAOForkSupport != newcfg.DAOForkSupport {
+ return newCompatError("DAO fork support flag", c.DAOForkBlock, newcfg.DAOForkBlock)
+ }
+ if isForkIncompatible(c.EIP150Block, newcfg.EIP150Block, head) {
+ return newCompatError("EIP150 fork block", c.EIP150Block, newcfg.EIP150Block)
+ }
+ if isForkIncompatible(c.EIP155Block, newcfg.EIP155Block, head) {
+ return newCompatError("EIP155 fork block", c.EIP155Block, newcfg.EIP155Block)
+ }
+ if isForkIncompatible(c.EIP158Block, newcfg.EIP158Block, head) {
+ return newCompatError("EIP158 fork block", c.EIP158Block, newcfg.EIP158Block)
+ }
+ if c.IsEIP158(head) && !configNumEqual(c.ChainId, newcfg.ChainId) {
+ return newCompatError("EIP158 chain ID", c.EIP158Block, newcfg.EIP158Block)
+ }
+ return nil
+}
+
+// isForkIncompatible returns true if a fork scheduled at s1 cannot be rescheduled to
+// block s2 because head is already past the fork.
+func isForkIncompatible(s1, s2, head *big.Int) bool {
+ return (isForked(s1, head) || isForked(s2, head)) && !configNumEqual(s1, s2)
+}
+
+// isForked returns whether a fork scheduled at block s is active at the given head block.
+func isForked(s, head *big.Int) bool {
+ if s == nil || head == nil {
return false
}
- return num.Cmp(c.EIP150Block) >= 0
-
+ return s.Cmp(head) <= 0
}
-func (c *ChainConfig) IsEIP155(num *big.Int) bool {
- if c.EIP155Block == nil || num == nil {
- return false
+func configNumEqual(x, y *big.Int) bool {
+ if x == nil {
+ return y == nil
}
- return num.Cmp(c.EIP155Block) >= 0
-
-}
-
-func (c *ChainConfig) IsEIP158(num *big.Int) bool {
- if c.EIP158Block == nil || num == nil {
- return false
+ if y == nil {
+ return x == nil
}
- return num.Cmp(c.EIP158Block) >= 0
-
+ return x.Cmp(y) == 0
}
-// Rules wraps ChainConfig and is merely syntatic sugar or can be used for functions
-// that do not have or require information about the block.
-//
-// Rules is a one time interface meaning that it shouldn't be used in between transition
-// phases.
-type Rules struct {
- ChainId *big.Int
- IsHomestead, IsEIP150, IsEIP155, IsEIP158 bool
+// ConfigCompatError is raised if the locally-stored blockchain is initialised with a
+// ChainConfig that would alter the past.
+type ConfigCompatError struct {
+ What string
+ // block numbers of the stored and new configurations
+ StoredConfig, NewConfig *big.Int
+ // the block number to which the local chain must be rewound to correct the error
+ RewindTo uint64
}
-func (c *ChainConfig) Rules(num *big.Int) Rules {
- return Rules{ChainId: new(big.Int).Set(c.ChainId), IsHomestead: c.IsHomestead(num), IsEIP150: c.IsEIP150(num), IsEIP155: c.IsEIP155(num), IsEIP158: c.IsEIP158(num)}
+func newCompatError(what string, storedblock, newblock *big.Int) *ConfigCompatError {
+ var rew *big.Int
+ switch {
+ case storedblock == nil:
+ rew = newblock
+ case newblock == nil || storedblock.Cmp(newblock) < 0:
+ rew = storedblock
+ default:
+ rew = newblock
+ }
+ err := &ConfigCompatError{what, storedblock, newblock, 0}
+ if rew != nil && rew.Sign() > 0 {
+ err.RewindTo = rew.Uint64() - 1
+ }
+ return err
+}
+
+func (err *ConfigCompatError) Error() string {
+ return fmt.Sprintf("mismatching %s in database (have %d, want %d, rewindto %d)", err.What, err.StoredConfig, err.NewConfig, err.RewindTo)
}
diff --git a/params/config_test.go b/params/config_test.go
new file mode 100644
index 0000000000..487dc380c5
--- /dev/null
+++ b/params/config_test.go
@@ -0,0 +1,81 @@
+// Copyright 2017 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+package params
+
+import (
+ "math/big"
+ "reflect"
+ "testing"
+)
+
+func TestCheckCompatible(t *testing.T) {
+ type test struct {
+ stored, new *ChainConfig
+ head uint64
+ wantErr *ConfigCompatError
+ }
+ tests := []test{
+ {stored: AllProtocolChanges, new: AllProtocolChanges, head: 0, wantErr: nil},
+ {stored: AllProtocolChanges, new: AllProtocolChanges, head: 100, wantErr: nil},
+ {
+ stored: &ChainConfig{EIP150Block: big.NewInt(10)},
+ new: &ChainConfig{EIP150Block: big.NewInt(20)},
+ head: 9,
+ wantErr: nil,
+ },
+ {
+ stored: AllProtocolChanges,
+ new: &ChainConfig{HomesteadBlock: nil},
+ head: 3,
+ wantErr: &ConfigCompatError{
+ What: "Homestead fork block",
+ StoredConfig: big.NewInt(0),
+ NewConfig: nil,
+ RewindTo: 0,
+ },
+ },
+ {
+ stored: AllProtocolChanges,
+ new: &ChainConfig{HomesteadBlock: big.NewInt(1)},
+ head: 3,
+ wantErr: &ConfigCompatError{
+ What: "Homestead fork block",
+ StoredConfig: big.NewInt(0),
+ NewConfig: big.NewInt(1),
+ RewindTo: 0,
+ },
+ },
+ {
+ stored: &ChainConfig{HomesteadBlock: big.NewInt(30), EIP150Block: big.NewInt(10)},
+ new: &ChainConfig{HomesteadBlock: big.NewInt(25), EIP150Block: big.NewInt(20)},
+ head: 25,
+ wantErr: &ConfigCompatError{
+ What: "EIP150 fork block",
+ StoredConfig: big.NewInt(10),
+ NewConfig: big.NewInt(20),
+ RewindTo: 9,
+ },
+ },
+ }
+
+ for _, test := range tests {
+ err := test.stored.CheckCompatible(test.new, test.head)
+ if !reflect.DeepEqual(err, test.wantErr) {
+ t.Errorf("error mismatch:\nstored: %v\nnew: %v\nhead: %v\nerr: %v\nwant: %v", test.stored, test.new, test.head, err, test.wantErr)
+ }
+ }
+}
diff --git a/params/dao.go b/params/dao.go
index 3e2a68cc9e..ef8e838ff7 100644
--- a/params/dao.go
+++ b/params/dao.go
@@ -17,8 +17,6 @@
package params
import (
- "encoding/json"
- "fmt"
"math/big"
"github.com/ethereum/go-ethereum/common"
@@ -47,372 +45,123 @@ var DAORefundContract = common.HexToAddress("0xbf4ed7b27f1d666546e30d74d50d173d2
// DAODrainList is the list of accounts whose full balances will be moved into a
// refund contract at the beginning of the dao-fork block.
-var DAODrainList []common.Address
-
-func init() {
- // Parse the list of DAO accounts to drain
- var list []map[string]string
- if err := json.Unmarshal([]byte(daoDrainListJSON), &list); err != nil {
- panic(fmt.Errorf("Failed to parse DAO drain list: %v", err))
- }
- // Collect all the accounts that need draining
- for _, dao := range list {
- DAODrainList = append(DAODrainList, common.HexToAddress(dao["address"]))
- DAODrainList = append(DAODrainList, common.HexToAddress(dao["extraBalanceAccount"]))
+func DAODrainList() []common.Address {
+ return []common.Address{
+ common.HexToAddress("0xd4fe7bc31cedb7bfb8a345f31e668033056b2728"),
+ common.HexToAddress("0xb3fb0e5aba0e20e5c49d252dfd30e102b171a425"),
+ common.HexToAddress("0x2c19c7f9ae8b751e37aeb2d93a699722395ae18f"),
+ common.HexToAddress("0xecd135fa4f61a655311e86238c92adcd779555d2"),
+ common.HexToAddress("0x1975bd06d486162d5dc297798dfc41edd5d160a7"),
+ common.HexToAddress("0xa3acf3a1e16b1d7c315e23510fdd7847b48234f6"),
+ common.HexToAddress("0x319f70bab6845585f412ec7724b744fec6095c85"),
+ common.HexToAddress("0x06706dd3f2c9abf0a21ddcc6941d9b86f0596936"),
+ common.HexToAddress("0x5c8536898fbb74fc7445814902fd08422eac56d0"),
+ common.HexToAddress("0x6966ab0d485353095148a2155858910e0965b6f9"),
+ common.HexToAddress("0x779543a0491a837ca36ce8c635d6154e3c4911a6"),
+ common.HexToAddress("0x2a5ed960395e2a49b1c758cef4aa15213cfd874c"),
+ common.HexToAddress("0x5c6e67ccd5849c0d29219c4f95f1a7a93b3f5dc5"),
+ common.HexToAddress("0x9c50426be05db97f5d64fc54bf89eff947f0a321"),
+ common.HexToAddress("0x200450f06520bdd6c527622a273333384d870efb"),
+ common.HexToAddress("0xbe8539bfe837b67d1282b2b1d61c3f723966f049"),
+ common.HexToAddress("0x6b0c4d41ba9ab8d8cfb5d379c69a612f2ced8ecb"),
+ common.HexToAddress("0xf1385fb24aad0cd7432824085e42aff90886fef5"),
+ common.HexToAddress("0xd1ac8b1ef1b69ff51d1d401a476e7e612414f091"),
+ common.HexToAddress("0x8163e7fb499e90f8544ea62bbf80d21cd26d9efd"),
+ common.HexToAddress("0x51e0ddd9998364a2eb38588679f0d2c42653e4a6"),
+ common.HexToAddress("0x627a0a960c079c21c34f7612d5d230e01b4ad4c7"),
+ common.HexToAddress("0xf0b1aa0eb660754448a7937c022e30aa692fe0c5"),
+ common.HexToAddress("0x24c4d950dfd4dd1902bbed3508144a54542bba94"),
+ common.HexToAddress("0x9f27daea7aca0aa0446220b98d028715e3bc803d"),
+ common.HexToAddress("0xa5dc5acd6a7968a4554d89d65e59b7fd3bff0f90"),
+ common.HexToAddress("0xd9aef3a1e38a39c16b31d1ace71bca8ef58d315b"),
+ common.HexToAddress("0x63ed5a272de2f6d968408b4acb9024f4cc208ebf"),
+ common.HexToAddress("0x6f6704e5a10332af6672e50b3d9754dc460dfa4d"),
+ common.HexToAddress("0x77ca7b50b6cd7e2f3fa008e24ab793fd56cb15f6"),
+ common.HexToAddress("0x492ea3bb0f3315521c31f273e565b868fc090f17"),
+ common.HexToAddress("0x0ff30d6de14a8224aa97b78aea5388d1c51c1f00"),
+ common.HexToAddress("0x9ea779f907f0b315b364b0cfc39a0fde5b02a416"),
+ common.HexToAddress("0xceaeb481747ca6c540a000c1f3641f8cef161fa7"),
+ common.HexToAddress("0xcc34673c6c40e791051898567a1222daf90be287"),
+ common.HexToAddress("0x579a80d909f346fbfb1189493f521d7f48d52238"),
+ common.HexToAddress("0xe308bd1ac5fda103967359b2712dd89deffb7973"),
+ common.HexToAddress("0x4cb31628079fb14e4bc3cd5e30c2f7489b00960c"),
+ common.HexToAddress("0xac1ecab32727358dba8962a0f3b261731aad9723"),
+ common.HexToAddress("0x4fd6ace747f06ece9c49699c7cabc62d02211f75"),
+ common.HexToAddress("0x440c59b325d2997a134c2c7c60a8c61611212bad"),
+ common.HexToAddress("0x4486a3d68fac6967006d7a517b889fd3f98c102b"),
+ common.HexToAddress("0x9c15b54878ba618f494b38f0ae7443db6af648ba"),
+ common.HexToAddress("0x27b137a85656544b1ccb5a0f2e561a5703c6a68f"),
+ common.HexToAddress("0x21c7fdb9ed8d291d79ffd82eb2c4356ec0d81241"),
+ common.HexToAddress("0x23b75c2f6791eef49c69684db4c6c1f93bf49a50"),
+ common.HexToAddress("0x1ca6abd14d30affe533b24d7a21bff4c2d5e1f3b"),
+ common.HexToAddress("0xb9637156d330c0d605a791f1c31ba5890582fe1c"),
+ common.HexToAddress("0x6131c42fa982e56929107413a9d526fd99405560"),
+ common.HexToAddress("0x1591fc0f688c81fbeb17f5426a162a7024d430c2"),
+ common.HexToAddress("0x542a9515200d14b68e934e9830d91645a980dd7a"),
+ common.HexToAddress("0xc4bbd073882dd2add2424cf47d35213405b01324"),
+ common.HexToAddress("0x782495b7b3355efb2833d56ecb34dc22ad7dfcc4"),
+ common.HexToAddress("0x58b95c9a9d5d26825e70a82b6adb139d3fd829eb"),
+ common.HexToAddress("0x3ba4d81db016dc2890c81f3acec2454bff5aada5"),
+ common.HexToAddress("0xb52042c8ca3f8aa246fa79c3feaa3d959347c0ab"),
+ common.HexToAddress("0xe4ae1efdfc53b73893af49113d8694a057b9c0d1"),
+ common.HexToAddress("0x3c02a7bc0391e86d91b7d144e61c2c01a25a79c5"),
+ common.HexToAddress("0x0737a6b837f97f46ebade41b9bc3e1c509c85c53"),
+ common.HexToAddress("0x97f43a37f595ab5dd318fb46e7a155eae057317a"),
+ common.HexToAddress("0x52c5317c848ba20c7504cb2c8052abd1fde29d03"),
+ common.HexToAddress("0x4863226780fe7c0356454236d3b1c8792785748d"),
+ common.HexToAddress("0x5d2b2e6fcbe3b11d26b525e085ff818dae332479"),
+ common.HexToAddress("0x5f9f3392e9f62f63b8eac0beb55541fc8627f42c"),
+ common.HexToAddress("0x057b56736d32b86616a10f619859c6cd6f59092a"),
+ common.HexToAddress("0x9aa008f65de0b923a2a4f02012ad034a5e2e2192"),
+ common.HexToAddress("0x304a554a310c7e546dfe434669c62820b7d83490"),
+ common.HexToAddress("0x914d1b8b43e92723e64fd0a06f5bdb8dd9b10c79"),
+ common.HexToAddress("0x4deb0033bb26bc534b197e61d19e0733e5679784"),
+ common.HexToAddress("0x07f5c1e1bc2c93e0402f23341973a0e043f7bf8a"),
+ common.HexToAddress("0x35a051a0010aba705c9008d7a7eff6fb88f6ea7b"),
+ common.HexToAddress("0x4fa802324e929786dbda3b8820dc7834e9134a2a"),
+ common.HexToAddress("0x9da397b9e80755301a3b32173283a91c0ef6c87e"),
+ common.HexToAddress("0x8d9edb3054ce5c5774a420ac37ebae0ac02343c6"),
+ common.HexToAddress("0x0101f3be8ebb4bbd39a2e3b9a3639d4259832fd9"),
+ common.HexToAddress("0x5dc28b15dffed94048d73806ce4b7a4612a1d48f"),
+ common.HexToAddress("0xbcf899e6c7d9d5a215ab1e3444c86806fa854c76"),
+ common.HexToAddress("0x12e626b0eebfe86a56d633b9864e389b45dcb260"),
+ common.HexToAddress("0xa2f1ccba9395d7fcb155bba8bc92db9bafaeade7"),
+ common.HexToAddress("0xec8e57756626fdc07c63ad2eafbd28d08e7b0ca5"),
+ common.HexToAddress("0xd164b088bd9108b60d0ca3751da4bceb207b0782"),
+ common.HexToAddress("0x6231b6d0d5e77fe001c2a460bd9584fee60d409b"),
+ common.HexToAddress("0x1cba23d343a983e9b5cfd19496b9a9701ada385f"),
+ common.HexToAddress("0xa82f360a8d3455c5c41366975bde739c37bfeb8a"),
+ common.HexToAddress("0x9fcd2deaff372a39cc679d5c5e4de7bafb0b1339"),
+ common.HexToAddress("0x005f5cee7a43331d5a3d3eec71305925a62f34b6"),
+ common.HexToAddress("0x0e0da70933f4c7849fc0d203f5d1d43b9ae4532d"),
+ common.HexToAddress("0xd131637d5275fd1a68a3200f4ad25c71a2a9522e"),
+ common.HexToAddress("0xbc07118b9ac290e4622f5e77a0853539789effbe"),
+ common.HexToAddress("0x47e7aa56d6bdf3f36be34619660de61275420af8"),
+ common.HexToAddress("0xacd87e28b0c9d1254e868b81cba4cc20d9a32225"),
+ common.HexToAddress("0xadf80daec7ba8dcf15392f1ac611fff65d94f880"),
+ common.HexToAddress("0x5524c55fb03cf21f549444ccbecb664d0acad706"),
+ common.HexToAddress("0x40b803a9abce16f50f36a77ba41180eb90023925"),
+ common.HexToAddress("0xfe24cdd8648121a43a7c86d289be4dd2951ed49f"),
+ common.HexToAddress("0x17802f43a0137c506ba92291391a8a8f207f487d"),
+ common.HexToAddress("0x253488078a4edf4d6f42f113d1e62836a942cf1a"),
+ common.HexToAddress("0x86af3e9626fce1957c82e88cbf04ddf3a2ed7915"),
+ common.HexToAddress("0xb136707642a4ea12fb4bae820f03d2562ebff487"),
+ common.HexToAddress("0xdbe9b615a3ae8709af8b93336ce9b477e4ac0940"),
+ common.HexToAddress("0xf14c14075d6c4ed84b86798af0956deef67365b5"),
+ common.HexToAddress("0xca544e5c4687d109611d0f8f928b53a25af72448"),
+ common.HexToAddress("0xaeeb8ff27288bdabc0fa5ebb731b6f409507516c"),
+ common.HexToAddress("0xcbb9d3703e651b0d496cdefb8b92c25aeb2171f7"),
+ common.HexToAddress("0x6d87578288b6cb5549d5076a207456a1f6a63dc0"),
+ common.HexToAddress("0xb2c6f0dfbb716ac562e2d85d6cb2f8d5ee87603e"),
+ common.HexToAddress("0xaccc230e8a6e5be9160b8cdf2864dd2a001c28b6"),
+ common.HexToAddress("0x2b3455ec7fedf16e646268bf88846bd7a2319bb2"),
+ common.HexToAddress("0x4613f3bca5c44ea06337a9e439fbc6d42e501d0a"),
+ common.HexToAddress("0xd343b217de44030afaa275f54d31a9317c7f441e"),
+ common.HexToAddress("0x84ef4b2357079cd7a7c69fd7a37cd0609a679106"),
+ common.HexToAddress("0xda2fef9e4a3230988ff17df2165440f37e8b1708"),
+ common.HexToAddress("0xf4c64518ea10f995918a454158c6b61407ea345c"),
+ common.HexToAddress("0x7602b46df5390e432ef1c307d4f2c9ff6d65cc97"),
+ common.HexToAddress("0xbb9bc244d798123fde783fcc1c72d3bb8c189413"),
+ common.HexToAddress("0x807640a13483f8ac783c557fcdf27be11ea4ac7a"),
}
}
-
-// daoDrainListJSON is the JSON encoded list of accounts whose full balances will
-// be moved into a refund contract at the beginning of the dao-fork block.
-const daoDrainListJSON = `
-[
- {
- "address":"0xd4fe7bc31cedb7bfb8a345f31e668033056b2728",
- "balance":"186cc8bfaefb7be",
- "extraBalance":"0",
- "extraBalanceAccount":"0xb3fb0e5aba0e20e5c49d252dfd30e102b171a425"
- },
- {
- "address":"0x2c19c7f9ae8b751e37aeb2d93a699722395ae18f",
- "balance":"b14e8feab1ff435",
- "extraBalance":"0",
- "extraBalanceAccount":"0xecd135fa4f61a655311e86238c92adcd779555d2"
- },
- {
- "address":"0x1975bd06d486162d5dc297798dfc41edd5d160a7",
- "balance":"359d26614cb5070c77",
- "extraBalance":"0",
- "extraBalanceAccount":"0xa3acf3a1e16b1d7c315e23510fdd7847b48234f6"
- },
- {
- "address":"0x319f70bab6845585f412ec7724b744fec6095c85",
- "balance":"6e075cd846d2cb1d42",
- "extraBalance":"13d34fd41b545b81",
- "extraBalanceAccount":"0x06706dd3f2c9abf0a21ddcc6941d9b86f0596936"
- },
- {
- "address":"0x5c8536898fbb74fc7445814902fd08422eac56d0",
- "balance":"b1e5593558008fd78",
- "extraBalance":"0",
- "extraBalanceAccount":"0x6966ab0d485353095148a2155858910e0965b6f9"
- },
- {
- "address":"0x779543a0491a837ca36ce8c635d6154e3c4911a6",
- "balance":"392eaa20d1aad59a4c",
- "extraBalance":"426938826a96c9",
- "extraBalanceAccount":"0x2a5ed960395e2a49b1c758cef4aa15213cfd874c"
- },
- {
- "address":"0x5c6e67ccd5849c0d29219c4f95f1a7a93b3f5dc5",
- "balance":"2875d22b29793d4ba7",
- "extraBalance":"0",
- "extraBalanceAccount":"0x9c50426be05db97f5d64fc54bf89eff947f0a321"
- },
- {
- "address":"0x200450f06520bdd6c527622a273333384d870efb",
- "balance":"43c341d9f96954c049",
- "extraBalance":"0",
- "extraBalanceAccount":"0xbe8539bfe837b67d1282b2b1d61c3f723966f049"
- },
- {
- "address":"0x6b0c4d41ba9ab8d8cfb5d379c69a612f2ced8ecb",
- "balance":"75251057154d70fa816",
- "extraBalance":"0",
- "extraBalanceAccount":"0xf1385fb24aad0cd7432824085e42aff90886fef5"
- },
- {
- "address":"0xd1ac8b1ef1b69ff51d1d401a476e7e612414f091",
- "balance":"392409769296cf67f36",
- "extraBalance":"0",
- "extraBalanceAccount":"0x8163e7fb499e90f8544ea62bbf80d21cd26d9efd"
- },
- {
- "address":"0x51e0ddd9998364a2eb38588679f0d2c42653e4a6",
- "balance":"8ac72eccbf4e8083",
- "extraBalance":"0",
- "extraBalanceAccount":"0x627a0a960c079c21c34f7612d5d230e01b4ad4c7"
- },
- {
- "address":"0xf0b1aa0eb660754448a7937c022e30aa692fe0c5",
- "balance":"82289c3bb3e8c98799",
- "extraBalance":"0",
- "extraBalanceAccount":"0x24c4d950dfd4dd1902bbed3508144a54542bba94"
- },
- {
- "address":"0x9f27daea7aca0aa0446220b98d028715e3bc803d",
- "balance":"56bc29049ebed40fd",
- "extraBalance":"0",
- "extraBalanceAccount":"0xa5dc5acd6a7968a4554d89d65e59b7fd3bff0f90"
- },
- {
- "address":"0xd9aef3a1e38a39c16b31d1ace71bca8ef58d315b",
- "balance":"56bc7d3ff79110524",
- "extraBalance":"0",
- "extraBalanceAccount":"0x63ed5a272de2f6d968408b4acb9024f4cc208ebf"
- },
- {
- "address":"0x6f6704e5a10332af6672e50b3d9754dc460dfa4d",
- "balance":"23b651bd48cbc70cc",
- "extraBalance":"0",
- "extraBalanceAccount":"0x77ca7b50b6cd7e2f3fa008e24ab793fd56cb15f6"
- },
- {
- "address":"0x492ea3bb0f3315521c31f273e565b868fc090f17",
- "balance":"13ea6d4fee651dd7c9",
- "extraBalance":"0",
- "extraBalanceAccount":"0x0ff30d6de14a8224aa97b78aea5388d1c51c1f00"
- },
- {
- "address":"0x9ea779f907f0b315b364b0cfc39a0fde5b02a416",
- "balance":"35ac471a3836ae7de5a",
- "extraBalance":"0",
- "extraBalanceAccount":"0xceaeb481747ca6c540a000c1f3641f8cef161fa7"
- },
- {
- "address":"0xcc34673c6c40e791051898567a1222daf90be287",
- "balance":"d529c0b76b7aa0",
- "extraBalance":"0",
- "extraBalanceAccount":"0x579a80d909f346fbfb1189493f521d7f48d52238"
- },
- {
- "address":"0xe308bd1ac5fda103967359b2712dd89deffb7973",
- "balance":"5cd9e7df3a8e5cdd3",
- "extraBalance":"0",
- "extraBalanceAccount":"0x4cb31628079fb14e4bc3cd5e30c2f7489b00960c"
- },
- {
- "address":"0xac1ecab32727358dba8962a0f3b261731aad9723",
- "balance":"2c8442fe35363313b93",
- "extraBalance":"0",
- "extraBalanceAccount":"0x4fd6ace747f06ece9c49699c7cabc62d02211f75"
- },
- {
- "address":"0x440c59b325d2997a134c2c7c60a8c61611212bad",
- "balance":"e77583a3958130e53",
- "extraBalance":"0",
- "extraBalanceAccount":"0x4486a3d68fac6967006d7a517b889fd3f98c102b"
- },
- {
- "address":"0x9c15b54878ba618f494b38f0ae7443db6af648ba",
- "balance":"1f0b6ade348ca998",
- "extraBalance":"0",
- "extraBalanceAccount":"0x27b137a85656544b1ccb5a0f2e561a5703c6a68f"
- },
- {
- "address":"0x21c7fdb9ed8d291d79ffd82eb2c4356ec0d81241",
- "balance":"61725880736659",
- "extraBalance":"0",
- "extraBalanceAccount":"0x23b75c2f6791eef49c69684db4c6c1f93bf49a50"
- },
- {
- "address":"0x1ca6abd14d30affe533b24d7a21bff4c2d5e1f3b",
- "balance":"42948d8dc7ddbc22d",
- "extraBalance":"0",
- "extraBalanceAccount":"0xb9637156d330c0d605a791f1c31ba5890582fe1c"
- },
- {
- "address":"0x6131c42fa982e56929107413a9d526fd99405560",
- "balance":"7306683851d1eafbfa",
- "extraBalance":"0",
- "extraBalanceAccount":"0x1591fc0f688c81fbeb17f5426a162a7024d430c2"
- },
- {
- "address":"0x542a9515200d14b68e934e9830d91645a980dd7a",
- "balance":"2a8457d0d8432e21d0c",
- "extraBalance":"0",
- "extraBalanceAccount":"0xc4bbd073882dd2add2424cf47d35213405b01324"
- },
- {
- "address":"0x782495b7b3355efb2833d56ecb34dc22ad7dfcc4",
- "balance":"d8d7391feaeaa8cdb",
- "extraBalance":"0",
- "extraBalanceAccount":"0x58b95c9a9d5d26825e70a82b6adb139d3fd829eb"
- },
- {
- "address":"0x3ba4d81db016dc2890c81f3acec2454bff5aada5",
- "balance":"1",
- "extraBalance":"0",
- "extraBalanceAccount":"0xb52042c8ca3f8aa246fa79c3feaa3d959347c0ab"
- },
- {
- "address":"0xe4ae1efdfc53b73893af49113d8694a057b9c0d1",
- "balance":"456397665fa74041",
- "extraBalance":"0",
- "extraBalanceAccount":"0x3c02a7bc0391e86d91b7d144e61c2c01a25a79c5"
- },
- {
- "address":"0x0737a6b837f97f46ebade41b9bc3e1c509c85c53",
- "balance":"6324dcb7126ecbef",
- "extraBalance":"0",
- "extraBalanceAccount":"0x97f43a37f595ab5dd318fb46e7a155eae057317a"
- },
- {
- "address":"0x52c5317c848ba20c7504cb2c8052abd1fde29d03",
- "balance":"6c3419b0705c01cd0d",
- "extraBalance":"0",
- "extraBalanceAccount":"0x4863226780fe7c0356454236d3b1c8792785748d"
- },
- {
- "address":"0x5d2b2e6fcbe3b11d26b525e085ff818dae332479",
- "balance":"456397665fa74041",
- "extraBalance":"0",
- "extraBalanceAccount":"0x5f9f3392e9f62f63b8eac0beb55541fc8627f42c"
- },
- {
- "address":"0x057b56736d32b86616a10f619859c6cd6f59092a",
- "balance":"232c025bb44b46",
- "extraBalance":"0",
- "extraBalanceAccount":"0x9aa008f65de0b923a2a4f02012ad034a5e2e2192"
- },
- {
- "address":"0x304a554a310c7e546dfe434669c62820b7d83490",
- "balance":"3034f5ca7d45e17df199b",
- "extraBalance":"f7d15162c44e97b6e",
- "extraBalanceAccount":"0x914d1b8b43e92723e64fd0a06f5bdb8dd9b10c79"
- },
- {
- "address":"0x4deb0033bb26bc534b197e61d19e0733e5679784",
- "balance":"4417e96ed796591e09",
- "extraBalance":"0",
- "extraBalanceAccount":"0x07f5c1e1bc2c93e0402f23341973a0e043f7bf8a"
- },
- {
- "address":"0x35a051a0010aba705c9008d7a7eff6fb88f6ea7b",
- "balance":"d3ff7771412bbcc9",
- "extraBalance":"0",
- "extraBalanceAccount":"0x4fa802324e929786dbda3b8820dc7834e9134a2a"
- },
- {
- "address":"0x9da397b9e80755301a3b32173283a91c0ef6c87e",
- "balance":"32ae324c233816b4c2",
- "extraBalance":"0",
- "extraBalanceAccount":"0x8d9edb3054ce5c5774a420ac37ebae0ac02343c6"
- },
- {
- "address":"0x0101f3be8ebb4bbd39a2e3b9a3639d4259832fd9",
- "balance":"1e530695b705f037c6",
- "extraBalance":"0",
- "extraBalanceAccount":"0x5dc28b15dffed94048d73806ce4b7a4612a1d48f"
- },
- {
- "address":"0xbcf899e6c7d9d5a215ab1e3444c86806fa854c76",
- "balance":"68013bad5b4b1133fc5",
- "extraBalance":"0",
- "extraBalanceAccount":"0x12e626b0eebfe86a56d633b9864e389b45dcb260"
- },
- {
- "address":"0xa2f1ccba9395d7fcb155bba8bc92db9bafaeade7",
- "balance":"456397665fa74041",
- "extraBalance":"0",
- "extraBalanceAccount":"0xec8e57756626fdc07c63ad2eafbd28d08e7b0ca5"
- },
- {
- "address":"0xd164b088bd9108b60d0ca3751da4bceb207b0782",
- "balance":"3635ce47fabaaa336e",
- "extraBalance":"0",
- "extraBalanceAccount":"0x6231b6d0d5e77fe001c2a460bd9584fee60d409b"
- },
- {
- "address":"0x1cba23d343a983e9b5cfd19496b9a9701ada385f",
- "balance":"f3abd9906c170a",
- "extraBalance":"0",
- "extraBalanceAccount":"0xa82f360a8d3455c5c41366975bde739c37bfeb8a"
- },
- {
- "address":"0x9fcd2deaff372a39cc679d5c5e4de7bafb0b1339",
- "balance":"4c6679d9d9b95a4e08",
- "extraBalance":"0",
- "extraBalanceAccount":"0x005f5cee7a43331d5a3d3eec71305925a62f34b6"
- },
- {
- "address":"0x0e0da70933f4c7849fc0d203f5d1d43b9ae4532d",
- "balance":"40f622936475de31849",
- "extraBalance":"671e1bbabded39754",
- "extraBalanceAccount":"0xd131637d5275fd1a68a3200f4ad25c71a2a9522e"
- },
- {
- "address":"0xbc07118b9ac290e4622f5e77a0853539789effbe",
- "balance":"1316ccfa4a35db5e58f",
- "extraBalance":"0",
- "extraBalanceAccount":"0x47e7aa56d6bdf3f36be34619660de61275420af8"
- },
- {
- "address":"0xacd87e28b0c9d1254e868b81cba4cc20d9a32225",
- "balance":"b3ad6bb72000bab9f",
- "extraBalance":"0",
- "extraBalanceAccount":"0xadf80daec7ba8dcf15392f1ac611fff65d94f880"
- },
- {
- "address":"0x5524c55fb03cf21f549444ccbecb664d0acad706",
- "balance":"16f2da372a5c8a70967",
- "extraBalance":"0",
- "extraBalanceAccount":"0x40b803a9abce16f50f36a77ba41180eb90023925"
- },
- {
- "address":"0xfe24cdd8648121a43a7c86d289be4dd2951ed49f",
- "balance":"ea0b1bdc78f500a43",
- "extraBalance":"0",
- "extraBalanceAccount":"0x17802f43a0137c506ba92291391a8a8f207f487d"
- },
- {
- "address":"0x253488078a4edf4d6f42f113d1e62836a942cf1a",
- "balance":"3060e3aed135cc80",
- "extraBalance":"0",
- "extraBalanceAccount":"0x86af3e9626fce1957c82e88cbf04ddf3a2ed7915"
- },
- {
- "address":"0xb136707642a4ea12fb4bae820f03d2562ebff487",
- "balance":"6050bdeb3354b5c98adc3",
- "extraBalance":"0",
- "extraBalanceAccount":"0xdbe9b615a3ae8709af8b93336ce9b477e4ac0940"
- },
- {
- "address":"0xf14c14075d6c4ed84b86798af0956deef67365b5",
- "balance":"1d77844e94c25ba2",
- "extraBalance":"0",
- "extraBalanceAccount":"0xca544e5c4687d109611d0f8f928b53a25af72448"
- },
- {
- "address":"0xaeeb8ff27288bdabc0fa5ebb731b6f409507516c",
- "balance":"2e93a72de4fc5ec0ed",
- "extraBalance":"0",
- "extraBalanceAccount":"0xcbb9d3703e651b0d496cdefb8b92c25aeb2171f7"
- },
- {
- "address":"0x6d87578288b6cb5549d5076a207456a1f6a63dc0",
- "balance":"1afd340799e48c18",
- "extraBalance":"0",
- "extraBalanceAccount":"0xb2c6f0dfbb716ac562e2d85d6cb2f8d5ee87603e"
- },
- {
- "address":"0xaccc230e8a6e5be9160b8cdf2864dd2a001c28b6",
- "balance":"14d0944eb3be947a8",
- "extraBalance":"0",
- "extraBalanceAccount":"0x2b3455ec7fedf16e646268bf88846bd7a2319bb2"
- },
- {
- "address":"0x4613f3bca5c44ea06337a9e439fbc6d42e501d0a",
- "balance":"6202b236a200e365eba",
- "extraBalance":"11979be9020f03ec4ec",
- "extraBalanceAccount":"0xd343b217de44030afaa275f54d31a9317c7f441e"
- },
- {
- "address":"0x84ef4b2357079cd7a7c69fd7a37cd0609a679106",
- "balance":"7ed634ebbba531901e07",
- "extraBalance":"f9c5eff28cb08720c85",
- "extraBalanceAccount":"0xda2fef9e4a3230988ff17df2165440f37e8b1708"
- },
- {
- "address":"0xf4c64518ea10f995918a454158c6b61407ea345c",
- "balance":"39152e15508a96ff894a",
- "extraBalance":"14041ca908bcc185c8",
- "extraBalanceAccount":"0x7602b46df5390e432ef1c307d4f2c9ff6d65cc97"
- },
- {
- "address":"0xbb9bc244d798123fde783fcc1c72d3bb8c189413",
- "balance":"1",
- "extraBalance":"5553ebc",
- "extraBalanceAccount":"0x807640a13483f8ac783c557fcdf27be11ea4ac7a"
- }
-]
-`
diff --git a/logger/verbosity.go b/params/denomination.go
similarity index 66%
rename from logger/verbosity.go
rename to params/denomination.go
index aa3d59c30d..9e1b52506f 100644
--- a/logger/verbosity.go
+++ b/params/denomination.go
@@ -1,4 +1,4 @@
-// Copyright 2015 The go-ethereum Authors
+// Copyright 2017 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
@@ -14,15 +14,21 @@
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see .
-package logger
+package params
const (
- Error = iota + 1
- Warn
- Info
- Core
- Debug
- Detail
-
- Ridiculousness = 100
+ // These are the multipliers for ether denominations.
+ // Example: To get the wei value of an amount in 'douglas', use
+ //
+ // new(big.Int).Mul(value, big.NewInt(params.Douglas))
+ //
+ Wei = 1
+ Ada = 1e3
+ Babbage = 1e6
+ Shannon = 1e9
+ Szabo = 1e12
+ Finney = 1e15
+ Ether = 1e18
+ Einstein = 1e21
+ Douglas = 1e42
)
diff --git a/params/gas_table.go b/params/gas_table.go
index 093dacc8b3..a060539041 100644
--- a/params/gas_table.go
+++ b/params/gas_table.go
@@ -16,41 +16,35 @@
package params
-import "math/big"
-
type GasTable struct {
- ExtcodeSize *big.Int
- ExtcodeCopy *big.Int
- Balance *big.Int
- SLoad *big.Int
- Calls *big.Int
- Suicide *big.Int
+ ExtcodeSize uint64
+ ExtcodeCopy uint64
+ Balance uint64
+ SLoad uint64
+ Calls uint64
+ Suicide uint64
- ExpByte *big.Int
+ ExpByte uint64
// CreateBySuicide occurs when the
// refunded account is one that does
// not exist. This logic is similar
// to call. May be left nil. Nil means
// not charged.
- CreateBySuicide *big.Int
+ CreateBySuicide uint64
}
var (
// GasTableHomestead contain the gas prices for
// the homestead phase.
GasTableHomestead = GasTable{
- ExtcodeSize: big.NewInt(20),
- ExtcodeCopy: big.NewInt(20),
- Balance: big.NewInt(20),
- SLoad: big.NewInt(50),
- Calls: big.NewInt(40),
- Suicide: big.NewInt(0),
- ExpByte: big.NewInt(10),
-
- // explicitly set to nil to indicate
- // this rule does not apply to homestead.
- CreateBySuicide: nil,
+ ExtcodeSize: 20,
+ ExtcodeCopy: 20,
+ Balance: 20,
+ SLoad: 50,
+ Calls: 40,
+ Suicide: 0,
+ ExpByte: 10,
}
// GasTableHomestead contain the gas re-prices for
@@ -58,26 +52,26 @@ var (
//
// TODO rename to GasTableEIP150
GasTableHomesteadGasRepriceFork = GasTable{
- ExtcodeSize: big.NewInt(700),
- ExtcodeCopy: big.NewInt(700),
- Balance: big.NewInt(400),
- SLoad: big.NewInt(200),
- Calls: big.NewInt(700),
- Suicide: big.NewInt(5000),
- ExpByte: big.NewInt(10),
+ ExtcodeSize: 700,
+ ExtcodeCopy: 700,
+ Balance: 400,
+ SLoad: 200,
+ Calls: 700,
+ Suicide: 5000,
+ ExpByte: 10,
- CreateBySuicide: big.NewInt(25000),
+ CreateBySuicide: 25000,
}
GasTableEIP158 = GasTable{
- ExtcodeSize: big.NewInt(700),
- ExtcodeCopy: big.NewInt(700),
- Balance: big.NewInt(400),
- SLoad: big.NewInt(200),
- Calls: big.NewInt(700),
- Suicide: big.NewInt(5000),
- ExpByte: big.NewInt(50),
+ ExtcodeSize: 700,
+ ExtcodeCopy: 700,
+ Balance: 400,
+ SLoad: 200,
+ Calls: 700,
+ Suicide: 5000,
+ ExpByte: 50,
- CreateBySuicide: big.NewInt(25000),
+ CreateBySuicide: 25000,
}
)
diff --git a/params/protocol_params.go b/params/protocol_params.go
index f5b6bedeb7..f48bf4992d 100644
--- a/params/protocol_params.go
+++ b/params/protocol_params.go
@@ -18,56 +18,58 @@ package params
import "math/big"
-var (
- MaximumExtraDataSize = big.NewInt(32) // Maximum size extra data may be after Genesis.
- ExpByteGas = big.NewInt(10) // Times ceil(log256(exponent)) for the EXP instruction.
- SloadGas = big.NewInt(50) // Multiplied by the number of 32-byte words that are copied (round up) for any *COPY operation and added.
- CallValueTransferGas = big.NewInt(9000) // Paid for CALL when the value transfer is non-zero.
- CallNewAccountGas = big.NewInt(25000) // Paid for CALL when the destination address didn't exist prior.
- TxGas = big.NewInt(21000) // Per transaction not creating a contract. NOTE: Not payable on data of calls between transactions.
- TxGasContractCreation = big.NewInt(53000) // Per transaction that creates a contract. NOTE: Not payable on data of calls between transactions.
- TxDataZeroGas = big.NewInt(4) // Per byte of data attached to a transaction that equals zero. NOTE: Not payable on data of calls between transactions.
- DifficultyBoundDivisor = big.NewInt(2048) // The bound divisor of the difficulty, used in the update calculations.
- QuadCoeffDiv = big.NewInt(512) // Divisor for the quadratic particle of the memory cost equation.
- GenesisDifficulty = big.NewInt(131072) // Difficulty of the Genesis block.
- DurationLimit = big.NewInt(13) // The decision boundary on the blocktime duration used to determine whether difficulty should go up or not.
- SstoreSetGas = big.NewInt(20000) // Once per SLOAD operation.
- LogDataGas = big.NewInt(8) // Per byte in a LOG* operation's data.
- CallStipend = big.NewInt(2300) // Free gas given at beginning of call.
- EcrecoverGas = big.NewInt(3000) //
- Sha256WordGas = big.NewInt(12) //
+const (
+ MaximumExtraDataSize uint64 = 32 // Maximum size extra data may be after Genesis.
+ ExpByteGas uint64 = 10 // Times ceil(log256(exponent)) for the EXP instruction.
+ SloadGas uint64 = 50 // Multiplied by the number of 32-byte words that are copied (round up) for any *COPY operation and added.
+ CallValueTransferGas uint64 = 9000 // Paid for CALL when the value transfer is non-zero.
+ CallNewAccountGas uint64 = 25000 // Paid for CALL when the destination address didn't exist prior.
+ TxGas uint64 = 21000 // Per transaction not creating a contract. NOTE: Not payable on data of calls between transactions.
+ TxGasContractCreation uint64 = 53000 // Per transaction that creates a contract. NOTE: Not payable on data of calls between transactions.
+ TxDataZeroGas uint64 = 4 // Per byte of data attached to a transaction that equals zero. NOTE: Not payable on data of calls between transactions.
+ QuadCoeffDiv uint64 = 512 // Divisor for the quadratic particle of the memory cost equation.
+ SstoreSetGas uint64 = 20000 // Once per SLOAD operation.
+ LogDataGas uint64 = 8 // Per byte in a LOG* operation's data.
+ CallStipend uint64 = 2300 // Free gas given at beginning of call.
+ EcrecoverGas uint64 = 3000 //
+ Sha256WordGas uint64 = 12 //
- MinGasLimit = big.NewInt(5000) // Minimum the gas limit may ever be.
- GenesisGasLimit = big.NewInt(4712388) // Gas limit of the Genesis block.
- TargetGasLimit = new(big.Int).Set(GenesisGasLimit) // The artificial target
-
- Sha3Gas = big.NewInt(30) // Once per SHA3 operation.
- Sha256Gas = big.NewInt(60) //
- IdentityWordGas = big.NewInt(3) //
- Sha3WordGas = big.NewInt(6) // Once per word of the SHA3 operation's data.
- SstoreResetGas = big.NewInt(5000) // Once per SSTORE operation if the zeroness changes from zero.
- SstoreClearGas = big.NewInt(5000) // Once per SSTORE operation if the zeroness doesn't change.
- SstoreRefundGas = big.NewInt(15000) // Once per SSTORE operation if the zeroness changes to zero.
- JumpdestGas = big.NewInt(1) // Refunded gas, once per SSTORE operation if the zeroness changes to zero.
- IdentityGas = big.NewInt(15) //
- GasLimitBoundDivisor = big.NewInt(1024) // The bound divisor of the gas limit, used in update calculations.
- EpochDuration = big.NewInt(30000) // Duration between proof-of-work epochs.
- CallGas = big.NewInt(40) // Once per CALL operation & message call transaction.
- CreateDataGas = big.NewInt(200) //
- Ripemd160Gas = big.NewInt(600) //
- Ripemd160WordGas = big.NewInt(120) //
- MinimumDifficulty = big.NewInt(131072) // The minimum that the difficulty may ever be.
- CallCreateDepth = big.NewInt(1024) // Maximum depth of call/create stack.
- ExpGas = big.NewInt(10) // Once per EXP instruction.
- LogGas = big.NewInt(375) // Per LOG* operation.
- CopyGas = big.NewInt(3) //
- StackLimit = big.NewInt(1024) // Maximum size of VM stack allowed.
- TierStepGas = big.NewInt(0) // Once per operation, for a selection of them.
- LogTopicGas = big.NewInt(375) // Multiplied by the * of the LOG*, per LOG transaction. e.g. LOG0 incurs 0 * c_txLogTopicGas, LOG4 incurs 4 * c_txLogTopicGas.
- CreateGas = big.NewInt(32000) // Once per CREATE operation & contract-creation transaction.
- SuicideRefundGas = big.NewInt(24000) // Refunded following a suicide operation.
- MemoryGas = big.NewInt(3) // Times the address of the (highest referenced byte in memory + 1). NOTE: referencing happens on read, write and in instructions such as RETURN and CALL.
- TxDataNonZeroGas = big.NewInt(68) // Per byte of data attached to a transaction that is not equal to zero. NOTE: Not payable on data of calls between transactions.
+ Sha3Gas uint64 = 30 // Once per SHA3 operation.
+ Sha256Gas uint64 = 60 //
+ IdentityWordGas uint64 = 3 //
+ Sha3WordGas uint64 = 6 // Once per word of the SHA3 operation's data.
+ SstoreResetGas uint64 = 5000 // Once per SSTORE operation if the zeroness changes from zero.
+ SstoreClearGas uint64 = 5000 // Once per SSTORE operation if the zeroness doesn't change.
+ SstoreRefundGas uint64 = 15000 // Once per SSTORE operation if the zeroness changes to zero.
+ JumpdestGas uint64 = 1 // Refunded gas, once per SSTORE operation if the zeroness changes to zero.
+ IdentityGas uint64 = 15 //
+ EpochDuration uint64 = 30000 // Duration between proof-of-work epochs.
+ CallGas uint64 = 40 // Once per CALL operation & message call transaction.
+ CreateDataGas uint64 = 200 //
+ Ripemd160Gas uint64 = 600 //
+ Ripemd160WordGas uint64 = 120 //
+ CallCreateDepth uint64 = 1024 // Maximum depth of call/create stack.
+ ExpGas uint64 = 10 // Once per EXP instruction
+ LogGas uint64 = 375 // Per LOG* operation.
+ CopyGas uint64 = 3 //
+ StackLimit uint64 = 1024 // Maximum size of VM stack allowed.
+ TierStepGas uint64 = 0 // Once per operation, for a selection of them.
+ LogTopicGas uint64 = 375 // Multiplied by the * of the LOG*, per LOG transaction. e.g. LOG0 incurs 0 * c_txLogTopicGas, LOG4 incurs 4 * c_txLogTopicGas.
+ CreateGas uint64 = 32000 // Once per CREATE operation & contract-creation transaction.
+ SuicideRefundGas uint64 = 24000 // Refunded following a suicide operation.
+ MemoryGas uint64 = 3 // Times the address of the (highest referenced byte in memory + 1). NOTE: referencing happens on read, write and in instructions such as RETURN and CALL.
+ TxDataNonZeroGas uint64 = 68 // Per byte of data attached to a transaction that is not equal to zero. NOTE: Not payable on data of calls between transactions.
MaxCodeSize = 24576
)
+
+var (
+ GasLimitBoundDivisor = big.NewInt(1024) // The bound divisor of the gas limit, used in update calculations.
+ MinGasLimit = big.NewInt(5000) // Minimum the gas limit may ever be.
+ GenesisGasLimit = big.NewInt(4712388) // Gas limit of the Genesis block.
+ TargetGasLimit = new(big.Int).Set(GenesisGasLimit) // The artificial target
+ DifficultyBoundDivisor = big.NewInt(2048) // The bound divisor of the difficulty, used in the update calculations.
+ GenesisDifficulty = big.NewInt(131072) // Difficulty of the Genesis block.
+ MinimumDifficulty = big.NewInt(131072) // The minimum that the difficulty may ever be.
+ DurationLimit = big.NewInt(13) // The decision boundary on the blocktime duration used to determine whether difficulty should go up or not.
+)
diff --git a/params/version.go b/params/version.go
index bc5756fc62..fef360473f 100644
--- a/params/version.go
+++ b/params/version.go
@@ -19,10 +19,10 @@ package params
import "fmt"
const (
- VersionMajor = 1 // Major version component of the current release
- VersionMinor = 5 // Minor version component of the current release
- VersionPatch = 9 // Patch version component of the current release
- VersionMeta = "stable" // Version metadata to append to the version string
+ VersionMajor = 1 // Major version component of the current release
+ VersionMinor = 6 // Minor version component of the current release
+ VersionPatch = 0 // Patch version component of the current release
+ VersionMeta = "unstable" // Version metadata to append to the version string
)
// Version holds the textual version string.
diff --git a/pow/ethash.go b/pow/ethash.go
new file mode 100644
index 0000000000..9adc38540d
--- /dev/null
+++ b/pow/ethash.go
@@ -0,0 +1,589 @@
+// Copyright 2017 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+package pow
+
+import (
+ "bytes"
+ "errors"
+ "fmt"
+ "math"
+ "math/big"
+ "math/rand"
+ "os"
+ "path/filepath"
+ "reflect"
+ "strconv"
+ "sync"
+ "time"
+ "unsafe"
+
+ mmap "github.com/edsrzf/mmap-go"
+ "github.com/ethereum/go-ethereum/log"
+ metrics "github.com/rcrowley/go-metrics"
+)
+
+var (
+ ErrInvalidDumpMagic = errors.New("invalid dump magic")
+ ErrNonceOutOfRange = errors.New("nonce out of range")
+ ErrInvalidDifficulty = errors.New("non-positive difficulty")
+ ErrInvalidMixDigest = errors.New("invalid mix digest")
+ ErrInvalidPoW = errors.New("pow difficulty invalid")
+)
+
+var (
+ // maxUint256 is a big integer representing 2^256-1
+ maxUint256 = new(big.Int).Exp(big.NewInt(2), big.NewInt(256), big.NewInt(0))
+
+ // sharedEthash is a full instance that can be shared between multiple users.
+ sharedEthash = NewFullEthash("", 3, 0, "", 1, 0)
+
+ // algorithmRevision is the data structure version used for file naming.
+ algorithmRevision = 23
+
+ // dumpMagic is a dataset dump header to sanity check a data dump.
+ dumpMagic = []uint32{0xbaddcafe, 0xfee1dead}
+)
+
+// isLittleEndian returns whether the local system is running in little or big
+// endian byte order.
+func isLittleEndian() bool {
+ n := uint32(0x01020304)
+ return *(*byte)(unsafe.Pointer(&n)) == 0x04
+}
+
+// memoryMap tries to memory map a file of uint32s for read only access.
+func memoryMap(path string) (*os.File, mmap.MMap, []uint32, error) {
+ file, err := os.OpenFile(path, os.O_RDONLY, 0644)
+ if err != nil {
+ return nil, nil, nil, err
+ }
+ mem, buffer, err := memoryMapFile(file, false)
+ if err != nil {
+ file.Close()
+ return nil, nil, nil, err
+ }
+ for i, magic := range dumpMagic {
+ if buffer[i] != magic {
+ mem.Unmap()
+ file.Close()
+ return nil, nil, nil, ErrInvalidDumpMagic
+ }
+ }
+ return file, mem, buffer[len(dumpMagic):], err
+}
+
+// memoryMapFile tries to memory map an already opened file descriptor.
+func memoryMapFile(file *os.File, write bool) (mmap.MMap, []uint32, error) {
+ // Try to memory map the file
+ flag := mmap.RDONLY
+ if write {
+ flag = mmap.RDWR
+ }
+ mem, err := mmap.Map(file, flag, 0)
+ if err != nil {
+ return nil, nil, err
+ }
+ // Yay, we managed to memory map the file, here be dragons
+ header := *(*reflect.SliceHeader)(unsafe.Pointer(&mem))
+ header.Len /= 4
+ header.Cap /= 4
+
+ return mem, *(*[]uint32)(unsafe.Pointer(&header)), nil
+}
+
+// memoryMapAndGenerate tries to memory map a temporary file of uint32s for write
+// access, fill it with the data from a generator and then move it into the final
+// path requested.
+func memoryMapAndGenerate(path string, size uint64, generator func(buffer []uint32)) (*os.File, mmap.MMap, []uint32, error) {
+ // Ensure the data folder exists
+ if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
+ return nil, nil, nil, err
+ }
+ // Create a huge temporary empty file to fill with data
+ temp := path + "." + strconv.Itoa(rand.Int())
+
+ dump, err := os.Create(temp)
+ if err != nil {
+ return nil, nil, nil, err
+ }
+ if err = dump.Truncate(int64(len(dumpMagic))*4 + int64(size)); err != nil {
+ return nil, nil, nil, err
+ }
+ // Memory map the file for writing and fill it with the generator
+ mem, buffer, err := memoryMapFile(dump, true)
+ if err != nil {
+ dump.Close()
+ return nil, nil, nil, err
+ }
+ copy(buffer, dumpMagic)
+
+ data := buffer[len(dumpMagic):]
+ generator(data)
+
+ if err := mem.Flush(); err != nil {
+ mem.Unmap()
+ dump.Close()
+ return nil, nil, nil, err
+ }
+ os.Rename(temp, path)
+ return dump, mem, data, nil
+}
+
+// cache wraps an ethash cache with some metadata to allow easier concurrent use.
+type cache struct {
+ epoch uint64 // Epoch for which this cache is relevant
+
+ dump *os.File // File descriptor of the memory mapped cache
+ mmap mmap.MMap // Memory map itself to unmap before releasing
+
+ cache []uint32 // The actual cache data content (may be memory mapped)
+ used time.Time // Timestamp of the last use for smarter eviction
+ once sync.Once // Ensures the cache is generated only once
+ lock sync.Mutex // Ensures thread safety for updating the usage time
+}
+
+// generate ensures that the cache content is generated before use.
+func (c *cache) generate(dir string, limit int, test bool) {
+ c.once.Do(func() {
+ // If we have a testing cache, generate and return
+ if test {
+ c.cache = make([]uint32, 1024/4)
+ generateCache(c.cache, c.epoch, seedHash(c.epoch*epochLength+1))
+ return
+ }
+ // If we don't store anything on disk, generate and return
+ size := cacheSize(c.epoch*epochLength + 1)
+ seed := seedHash(c.epoch*epochLength + 1)
+
+ if dir == "" {
+ c.cache = make([]uint32, size/4)
+ generateCache(c.cache, c.epoch, seed)
+ return
+ }
+ // Disk storage is needed, this will get fancy
+ var endian string
+ if !isLittleEndian() {
+ endian = ".be"
+ }
+ path := filepath.Join(dir, fmt.Sprintf("cache-R%d-%x%s", algorithmRevision, seed[:8], endian))
+ logger := log.New("epoch", c.epoch)
+
+ // Try to load the file from disk and memory map it
+ var err error
+ c.dump, c.mmap, c.cache, err = memoryMap(path)
+ if err == nil {
+ logger.Debug("Loaded old ethash cache from disk")
+ return
+ }
+ logger.Debug("Failed to load old ethash cache", "err", err)
+
+ // No previous cache available, create a new cache file to fill
+ c.dump, c.mmap, c.cache, err = memoryMapAndGenerate(path, size, func(buffer []uint32) { generateCache(buffer, c.epoch, seed) })
+ if err != nil {
+ logger.Error("Failed to generate mapped ethash cache", "err", err)
+
+ c.cache = make([]uint32, size/4)
+ generateCache(c.cache, c.epoch, seed)
+ }
+ // Iterate over all previous instances and delete old ones
+ for ep := int(c.epoch) - limit; ep >= 0; ep-- {
+ seed := seedHash(uint64(ep)*epochLength + 1)
+ path := filepath.Join(dir, fmt.Sprintf("cache-R%d-%x%s", algorithmRevision, seed[:8], endian))
+ os.Remove(path)
+ }
+ })
+}
+
+// release closes any file handlers and memory maps open.
+func (c *cache) release() {
+ if c.mmap != nil {
+ c.mmap.Unmap()
+ c.mmap = nil
+ }
+ if c.dump != nil {
+ c.dump.Close()
+ c.dump = nil
+ }
+}
+
+// dataset wraps an ethash dataset with some metadata to allow easier concurrent use.
+type dataset struct {
+ epoch uint64 // Epoch for which this cache is relevant
+
+ dump *os.File // File descriptor of the memory mapped cache
+ mmap mmap.MMap // Memory map itself to unmap before releasing
+
+ dataset []uint32 // The actual cache data content
+ used time.Time // Timestamp of the last use for smarter eviction
+ once sync.Once // Ensures the cache is generated only once
+ lock sync.Mutex // Ensures thread safety for updating the usage time
+}
+
+// generate ensures that the dataset content is generated before use.
+func (d *dataset) generate(dir string, limit int, test bool) {
+ d.once.Do(func() {
+ // If we have a testing dataset, generate and return
+ if test {
+ cache := make([]uint32, 1024/4)
+ generateCache(cache, d.epoch, seedHash(d.epoch*epochLength+1))
+
+ d.dataset = make([]uint32, 32*1024/4)
+ generateDataset(d.dataset, d.epoch, cache)
+
+ return
+ }
+ // If we don't store anything on disk, generate and return
+ csize := cacheSize(d.epoch*epochLength + 1)
+ dsize := datasetSize(d.epoch*epochLength + 1)
+ seed := seedHash(d.epoch*epochLength + 1)
+
+ if dir == "" {
+ cache := make([]uint32, csize/4)
+ generateCache(cache, d.epoch, seed)
+
+ d.dataset = make([]uint32, dsize/4)
+ generateDataset(d.dataset, d.epoch, cache)
+ }
+ // Disk storage is needed, this will get fancy
+ var endian string
+ if !isLittleEndian() {
+ endian = ".be"
+ }
+ path := filepath.Join(dir, fmt.Sprintf("full-R%d-%x%s", algorithmRevision, seed[:8], endian))
+ logger := log.New("epoch", d.epoch)
+
+ // Try to load the file from disk and memory map it
+ var err error
+ d.dump, d.mmap, d.dataset, err = memoryMap(path)
+ if err == nil {
+ logger.Debug("Loaded old ethash dataset from disk")
+ return
+ }
+ logger.Debug("Failed to load old ethash dataset", "err", err)
+
+ // No previous dataset available, create a new dataset file to fill
+ cache := make([]uint32, csize/4)
+ generateCache(cache, d.epoch, seed)
+
+ d.dump, d.mmap, d.dataset, err = memoryMapAndGenerate(path, dsize, func(buffer []uint32) { generateDataset(buffer, d.epoch, cache) })
+ if err != nil {
+ logger.Error("Failed to generate mapped ethash dataset", "err", err)
+
+ d.dataset = make([]uint32, dsize/2)
+ generateDataset(d.dataset, d.epoch, cache)
+ }
+ // Iterate over all previous instances and delete old ones
+ for ep := int(d.epoch) - limit; ep >= 0; ep-- {
+ seed := seedHash(uint64(ep)*epochLength + 1)
+ path := filepath.Join(dir, fmt.Sprintf("full-R%d-%x%s", algorithmRevision, seed[:8], endian))
+ os.Remove(path)
+ }
+ })
+}
+
+// release closes any file handlers and memory maps open.
+func (d *dataset) release() {
+ if d.mmap != nil {
+ d.mmap.Unmap()
+ d.mmap = nil
+ }
+ if d.dump != nil {
+ d.dump.Close()
+ d.dump = nil
+ }
+}
+
+// MakeCache generates a new ethash cache and optionally stores it to disk.
+func MakeCache(block uint64, dir string) {
+ c := cache{epoch: block/epochLength + 1}
+ c.generate(dir, math.MaxInt32, false)
+ c.release()
+}
+
+// MakeDataset generates a new ethash dataset and optionally stores it to disk.
+func MakeDataset(block uint64, dir string) {
+ d := dataset{epoch: block/epochLength + 1}
+ d.generate(dir, math.MaxInt32, false)
+ d.release()
+}
+
+// Ethash is a PoW data struture implementing the ethash algorithm.
+type Ethash struct {
+ cachedir string // Data directory to store the verification caches
+ cachesinmem int // Number of caches to keep in memory
+ cachesondisk int // Number of caches to keep on disk
+ dagdir string // Data directory to store full mining datasets
+ dagsinmem int // Number of mining datasets to keep in memory
+ dagsondisk int // Number of mining datasets to keep on disk
+
+ caches map[uint64]*cache // In memory caches to avoid regenerating too often
+ fcache *cache // Pre-generated cache for the estimated future epoch
+ datasets map[uint64]*dataset // In memory datasets to avoid regenerating too often
+ fdataset *dataset // Pre-generated dataset for the estimated future epoch
+ lock sync.Mutex // Ensures thread safety for the in-memory caches
+
+ hashrate metrics.Meter // Meter tracking the average hashrate
+
+ tester bool // Flag whether to use a smaller test dataset
+}
+
+// NewFullEthash creates a full sized ethash PoW scheme.
+func NewFullEthash(cachedir string, cachesinmem, cachesondisk int, dagdir string, dagsinmem, dagsondisk int) PoW {
+ if cachesinmem <= 0 {
+ log.Warn("One ethash cache must alwast be in memory", "requested", cachesinmem)
+ cachesinmem = 1
+ }
+ if cachedir != "" && cachesondisk > 0 {
+ log.Info("Disk storage enabled for ethash caches", "dir", cachedir, "count", cachesondisk)
+ }
+ if dagdir != "" && dagsondisk > 0 {
+ log.Info("Disk storage enabled for ethash DAGs", "dir", dagdir, "count", dagsondisk)
+ }
+ return &Ethash{
+ cachedir: cachedir,
+ cachesinmem: cachesinmem,
+ cachesondisk: cachesondisk,
+ dagdir: dagdir,
+ dagsinmem: dagsinmem,
+ dagsondisk: dagsondisk,
+ caches: make(map[uint64]*cache),
+ datasets: make(map[uint64]*dataset),
+ hashrate: metrics.NewMeter(),
+ }
+}
+
+// NewTestEthash creates a small sized ethash PoW scheme useful only for testing
+// purposes.
+func NewTestEthash() PoW {
+ return &Ethash{
+ cachesinmem: 1,
+ caches: make(map[uint64]*cache),
+ datasets: make(map[uint64]*dataset),
+ tester: true,
+ hashrate: metrics.NewMeter(),
+ }
+}
+
+// NewSharedEthash creates a full sized ethash PoW shared between all requesters
+// running in the same process.
+func NewSharedEthash() PoW {
+ return sharedEthash
+}
+
+// Verify implements PoW, checking whether the given block satisfies the PoW
+// difficulty requirements.
+func (ethash *Ethash) Verify(block Block) error {
+ // Sanity check that the block number is below the lookup table size (60M blocks)
+ number := block.NumberU64()
+ if number/epochLength >= uint64(len(cacheSizes)) {
+ // Go < 1.7 cannot calculate new cache/dataset sizes (no fast prime check)
+ return ErrNonceOutOfRange
+ }
+ // Ensure that we have a valid difficulty for the block
+ difficulty := block.Difficulty()
+ if difficulty.Sign() <= 0 {
+ return ErrInvalidDifficulty
+ }
+ // Recompute the digest and PoW value and verify against the block
+ cache := ethash.cache(number)
+
+ size := datasetSize(number)
+ if ethash.tester {
+ size = 32 * 1024
+ }
+ digest, result := hashimotoLight(size, cache, block.HashNoNonce().Bytes(), block.Nonce())
+ if !bytes.Equal(block.MixDigest().Bytes(), digest) {
+ return ErrInvalidMixDigest
+ }
+ target := new(big.Int).Div(maxUint256, difficulty)
+ if new(big.Int).SetBytes(result).Cmp(target) > 0 {
+ return ErrInvalidPoW
+ }
+ return nil
+}
+
+// cache tries to retrieve a verification cache for the specified block number
+// by first checking against a list of in-memory caches, then against caches
+// stored on disk, and finally generating one if none can be found.
+func (ethash *Ethash) cache(block uint64) []uint32 {
+ epoch := block / epochLength
+
+ // If we have a PoW for that epoch, use that
+ ethash.lock.Lock()
+
+ current, future := ethash.caches[epoch], (*cache)(nil)
+ if current == nil {
+ // No in-memory cache, evict the oldest if the cache limit was reached
+ for len(ethash.caches) > 0 && len(ethash.caches) >= ethash.cachesinmem {
+ var evict *cache
+ for _, cache := range ethash.caches {
+ if evict == nil || evict.used.After(cache.used) {
+ evict = cache
+ }
+ }
+ delete(ethash.caches, evict.epoch)
+ evict.release()
+
+ log.Trace("Evicted ethash cache", "epoch", evict.epoch, "used", evict.used)
+ }
+ // If we have the new cache pre-generated, use that, otherwise create a new one
+ if ethash.fcache != nil && ethash.fcache.epoch == epoch {
+ log.Trace("Using pre-generated cache", "epoch", epoch)
+ current, ethash.fcache = ethash.fcache, nil
+ } else {
+ log.Trace("Requiring new ethash cache", "epoch", epoch)
+ current = &cache{epoch: epoch}
+ }
+ ethash.caches[epoch] = current
+
+ // If we just used up the future cache, or need a refresh, regenerate
+ if ethash.fcache == nil || ethash.fcache.epoch <= epoch {
+ if ethash.fcache != nil {
+ ethash.fcache.release()
+ }
+ log.Trace("Requiring new future ethash cache", "epoch", epoch+1)
+ future = &cache{epoch: epoch + 1}
+ ethash.fcache = future
+ }
+ }
+ current.used = time.Now()
+ ethash.lock.Unlock()
+
+ // Wait for generation finish, bump the timestamp and finalize the cache
+ current.generate(ethash.cachedir, ethash.cachesondisk, ethash.tester)
+
+ current.lock.Lock()
+ current.used = time.Now()
+ current.lock.Unlock()
+
+ // If we exhausted the future cache, now's a good time to regenerate it
+ if future != nil {
+ go future.generate(ethash.cachedir, ethash.cachesondisk, ethash.tester)
+ }
+ return current.cache
+}
+
+// Search implements PoW, attempting to find a nonce that satisfies the block's
+// difficulty requirements.
+func (ethash *Ethash) Search(block Block, stop <-chan struct{}) (uint64, []byte) {
+ var (
+ hash = block.HashNoNonce().Bytes()
+ diff = block.Difficulty()
+ target = new(big.Int).Div(maxUint256, diff)
+ dataset = ethash.dataset(block.NumberU64())
+ rand = rand.New(rand.NewSource(time.Now().UnixNano()))
+ nonce = uint64(rand.Int63())
+ attempts int64
+ )
+ // Start generating random nonces until we abort or find a good one
+ for {
+ select {
+ case <-stop:
+ // Mining terminated, update stats and abort
+ ethash.hashrate.Mark(attempts)
+ return 0, nil
+
+ default:
+ // We don't have to update hash rate on every nonce, so update after after 2^X nonces
+ attempts++
+ if (attempts % (1 << 15)) == 0 {
+ ethash.hashrate.Mark(attempts)
+ attempts = 0
+ }
+ // Compute the PoW value of this nonce
+ digest, result := hashimotoFull(dataset, hash, nonce)
+ if new(big.Int).SetBytes(result).Cmp(target) <= 0 {
+ return nonce, digest
+ }
+ nonce++
+ }
+ }
+}
+
+// dataset tries to retrieve a mining dataset for the specified block number
+// by first checking against a list of in-memory datasets, then against DAGs
+// stored on disk, and finally generating one if none can be found.
+func (ethash *Ethash) dataset(block uint64) []uint32 {
+ epoch := block / epochLength
+
+ // If we have a PoW for that epoch, use that
+ ethash.lock.Lock()
+
+ current, future := ethash.datasets[epoch], (*dataset)(nil)
+ if current == nil {
+ // No in-memory dataset, evict the oldest if the dataset limit was reached
+ for len(ethash.datasets) > 0 && len(ethash.datasets) >= ethash.dagsinmem {
+ var evict *dataset
+ for _, dataset := range ethash.datasets {
+ if evict == nil || evict.used.After(dataset.used) {
+ evict = dataset
+ }
+ }
+ delete(ethash.datasets, evict.epoch)
+ evict.release()
+
+ log.Trace("Evicted ethash dataset", "epoch", evict.epoch, "used", evict.used)
+ }
+ // If we have the new cache pre-generated, use that, otherwise create a new one
+ if ethash.fdataset != nil && ethash.fdataset.epoch == epoch {
+ log.Trace("Using pre-generated dataset", "epoch", epoch)
+ current = &dataset{epoch: ethash.fdataset.epoch} // Reload from disk
+ ethash.fdataset = nil
+ } else {
+ log.Trace("Requiring new ethash dataset", "epoch", epoch)
+ current = &dataset{epoch: epoch}
+ }
+ ethash.datasets[epoch] = current
+
+ // If we just used up the future dataset, or need a refresh, regenerate
+ if ethash.fdataset == nil || ethash.fdataset.epoch <= epoch {
+ if ethash.fdataset != nil {
+ ethash.fdataset.release()
+ }
+ log.Trace("Requiring new future ethash dataset", "epoch", epoch+1)
+ future = &dataset{epoch: epoch + 1}
+ ethash.fdataset = future
+ }
+ }
+ current.used = time.Now()
+ ethash.lock.Unlock()
+
+ // Wait for generation finish, bump the timestamp and finalize the cache
+ current.generate(ethash.dagdir, ethash.dagsondisk, ethash.tester)
+
+ current.lock.Lock()
+ current.used = time.Now()
+ current.lock.Unlock()
+
+ // If we exhausted the future dataset, now's a good time to regenerate it
+ if future != nil {
+ go future.generate(ethash.dagdir, ethash.dagsondisk, ethash.tester)
+ }
+ return current.dataset
+}
+
+// Hashrate implements PoW, returning the measured rate of the search invocations
+// per second over the last minute.
+func (ethash *Ethash) Hashrate() float64 {
+ return ethash.hashrate.Rate1()
+}
+
+// EthashSeedHash is the seed to use for generating a vrification cache and the
+// mining dataset.
+func EthashSeedHash(block uint64) []byte {
+ return seedHash(block)
+}
diff --git a/pow/ethash_algo.go b/pow/ethash_algo.go
new file mode 100644
index 0000000000..1e996785ff
--- /dev/null
+++ b/pow/ethash_algo.go
@@ -0,0 +1,1103 @@
+// Copyright 2017 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+package pow
+
+import (
+ "encoding/binary"
+ "hash"
+ "reflect"
+ "runtime"
+ "sync"
+ "sync/atomic"
+ "time"
+ "unsafe"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/crypto"
+ "github.com/ethereum/go-ethereum/crypto/sha3"
+ "github.com/ethereum/go-ethereum/log"
+)
+
+const (
+ datasetInitBytes = 1 << 30 // Bytes in dataset at genesis
+ datasetGrowthBytes = 1 << 23 // Dataset growth per epoch
+ cacheInitBytes = 1 << 24 // Bytes in cache at genesis
+ cacheGrowthBytes = 1 << 17 // Cache growth per epoch
+ epochLength = 30000 // Blocks per epoch
+ mixBytes = 128 // Width of mix
+ hashBytes = 64 // Hash length in bytes
+ hashWords = 16 // Number of 32 bit ints in a hash
+ datasetParents = 256 // Number of parents of each dataset element
+ cacheRounds = 3 // Number of rounds in cache production
+ loopAccesses = 64 // Number of accesses in hashimoto loop
+)
+
+// hasher is a repetitive hasher allowing the same hash data structures to be
+// reused between hash runs instead of requiring new ones to be created.
+type hasher func(dest []byte, data []byte)
+
+// makeHasher creates a repetitive hasher, allowing the same hash data structures
+// to be reused between hash runs instead of requiring new ones to be created.
+//
+// The returned function is not thread safe!
+func makeHasher(h hash.Hash) hasher {
+ return func(dest []byte, data []byte) {
+ h.Write(data)
+ h.Sum(dest[:0])
+ h.Reset()
+ }
+}
+
+// seedHash is the seed to use for generating a verification cache and the mining
+// dataset.
+func seedHash(block uint64) []byte {
+ seed := make([]byte, 32)
+ if block < epochLength {
+ return seed
+ }
+ keccak256 := makeHasher(sha3.NewKeccak256())
+ for i := 0; i < int(block/epochLength); i++ {
+ keccak256(seed, seed)
+ }
+ return seed
+}
+
+// generateCache creates a verification cache of a given size for an input seed.
+// The cache production process involves first sequentially filling up 32 MB of
+// memory, then performing two passes of Sergio Demian Lerner's RandMemoHash
+// algorithm from Strict Memory Hard Hashing Functions (2014). The output is a
+// set of 524288 64-byte values.
+//
+// This method places the result into dest in machine byte order.
+func generateCache(dest []uint32, epoch uint64, seed []byte) {
+ // Print some debug logs to allow analysis on low end devices
+ logger := log.New("epoch", epoch)
+
+ start := time.Now()
+ defer func() {
+ elapsed := time.Since(start)
+
+ logFn := logger.Debug
+ if elapsed > 3*time.Second {
+ logFn = logger.Info
+ }
+ logFn("Generated ethash verification cache", "elapsed", common.PrettyDuration(elapsed))
+ }()
+ // Convert our destination slice to a byte buffer
+ header := *(*reflect.SliceHeader)(unsafe.Pointer(&dest))
+ header.Len *= 4
+ header.Cap *= 4
+ cache := *(*[]byte)(unsafe.Pointer(&header))
+
+ // Calculate the number of thoretical rows (we'll store in one buffer nonetheless)
+ size := uint64(len(cache))
+ rows := int(size) / hashBytes
+
+ // Start a monitoring goroutine to report progress on low end devices
+ var progress uint32
+
+ done := make(chan struct{})
+ defer close(done)
+
+ go func() {
+ for {
+ select {
+ case <-done:
+ return
+ case <-time.After(3 * time.Second):
+ logger.Info("Generating ethash verification cache", "percentage", atomic.LoadUint32(&progress)*100/uint32(rows)/4, "elapsed", common.PrettyDuration(time.Since(start)))
+ }
+ }
+ }()
+ // Create a hasher to reuse between invocations
+ keccak512 := makeHasher(sha3.NewKeccak512())
+
+ // Sequentially produce the initial dataset
+ keccak512(cache, seed)
+ for offset := uint64(hashBytes); offset < size; offset += hashBytes {
+ keccak512(cache[offset:], cache[offset-hashBytes:offset])
+ atomic.AddUint32(&progress, 1)
+ }
+ // Use a low-round version of randmemohash
+ temp := make([]byte, hashBytes)
+
+ for i := 0; i < cacheRounds; i++ {
+ for j := 0; j < rows; j++ {
+ var (
+ srcOff = ((j - 1 + rows) % rows) * hashBytes
+ dstOff = j * hashBytes
+ xorOff = (binary.LittleEndian.Uint32(cache[dstOff:]) % uint32(rows)) * hashBytes
+ )
+ xorBytes(temp, cache[srcOff:srcOff+hashBytes], cache[xorOff:xorOff+hashBytes])
+ keccak512(cache[dstOff:], temp)
+
+ atomic.AddUint32(&progress, 1)
+ }
+ }
+ // Swap the byte order on big endian systems and return
+ if !isLittleEndian() {
+ swap(cache)
+ }
+}
+
+// swap changes the byte order of the buffer assuming a uint32 representation.
+func swap(buffer []byte) {
+ for i := 0; i < len(buffer); i += 4 {
+ binary.BigEndian.PutUint32(buffer[i:], binary.LittleEndian.Uint32(buffer[i:]))
+ }
+}
+
+// prepare converts an ethash cache or dataset from a byte stream into the internal
+// int representation. All ethash methods work with ints to avoid constant byte to
+// int conversions as well as to handle both little and big endian systems.
+func prepare(dest []uint32, src []byte) {
+ for i := 0; i < len(dest); i++ {
+ dest[i] = binary.LittleEndian.Uint32(src[i*4:])
+ }
+}
+
+// fnv is an algorithm inspired by the FNV hash, which in some cases is used as
+// a non-associative substitute for XOR. Note that we multiply the prime with
+// the full 32-bit input, in contrast with the FNV-1 spec which multiplies the
+// prime with one byte (octet) in turn.
+func fnv(a, b uint32) uint32 {
+ return a*0x01000193 ^ b
+}
+
+// fnvHash mixes in data into mix using the ethash fnv method.
+func fnvHash(mix []uint32, data []uint32) {
+ for i := 0; i < len(mix); i++ {
+ mix[i] = mix[i]*0x01000193 ^ data[i]
+ }
+}
+
+// generateDatasetItem combines data from 256 pseudorandomly selected cache nodes,
+// and hashes that to compute a single dataset node.
+func generateDatasetItem(cache []uint32, index uint32, keccak512 hasher) []byte {
+ // Calculate the number of thoretical rows (we use one buffer nonetheless)
+ rows := uint32(len(cache) / hashWords)
+
+ // Initialize the mix
+ mix := make([]byte, hashBytes)
+
+ binary.LittleEndian.PutUint32(mix, cache[(index%rows)*hashWords]^index)
+ for i := 1; i < hashWords; i++ {
+ binary.LittleEndian.PutUint32(mix[i*4:], cache[(index%rows)*hashWords+uint32(i)])
+ }
+ keccak512(mix, mix)
+
+ // Convert the mix to uint32s to avoid constant bit shifting
+ intMix := make([]uint32, hashWords)
+ for i := 0; i < len(intMix); i++ {
+ intMix[i] = binary.LittleEndian.Uint32(mix[i*4:])
+ }
+ // fnv it with a lot of random cache nodes based on index
+ for i := uint32(0); i < datasetParents; i++ {
+ parent := fnv(index^i, intMix[i%16]) % rows
+ fnvHash(intMix, cache[parent*hashWords:])
+ }
+ // Flatten the uint32 mix into a binary one and return
+ for i, val := range intMix {
+ binary.LittleEndian.PutUint32(mix[i*4:], val)
+ }
+ keccak512(mix, mix)
+ return mix
+}
+
+// generateDataset generates the entire ethash dataset for mining.
+//
+// This method places the result into dest in machine byte order.
+func generateDataset(dest []uint32, epoch uint64, cache []uint32) {
+ // Print some debug logs to allow analysis on low end devices
+ logger := log.New("epoch", epoch)
+
+ start := time.Now()
+ defer func() {
+ elapsed := time.Since(start)
+
+ logFn := logger.Debug
+ if elapsed > 3*time.Second {
+ logFn = logger.Info
+ }
+ logFn("Generated ethash verification cache", "elapsed", common.PrettyDuration(elapsed))
+ }()
+
+ // Figure out whether the bytes need to be swapped for the machine
+ swapped := !isLittleEndian()
+
+ // Convert our destination slice to a byte buffer
+ header := *(*reflect.SliceHeader)(unsafe.Pointer(&dest))
+ header.Len *= 4
+ header.Cap *= 4
+ dataset := *(*[]byte)(unsafe.Pointer(&header))
+
+ // Generate the dataset on many goroutines since it takes a while
+ threads := runtime.NumCPU()
+ size := uint64(len(dataset))
+
+ var pend sync.WaitGroup
+ pend.Add(threads)
+
+ var progress uint32
+ for i := 0; i < threads; i++ {
+ go func(id int) {
+ defer pend.Done()
+
+ // Create a hasher to reuse between invocations
+ keccak512 := makeHasher(sha3.NewKeccak512())
+
+ // Calculate the data segment this thread should generate
+ batch := uint32((size + hashBytes*uint64(threads) - 1) / (hashBytes * uint64(threads)))
+ first := uint32(id) * batch
+ limit := first + batch
+ if limit > uint32(size/hashBytes) {
+ limit = uint32(size / hashBytes)
+ }
+ // Calculate the dataset segment
+ percent := uint32(size / hashBytes / 100)
+ for index := first; index < limit; index++ {
+ item := generateDatasetItem(cache, index, keccak512)
+ if swapped {
+ swap(item)
+ }
+ copy(dataset[index*hashBytes:], item)
+
+ if status := atomic.AddUint32(&progress, 1); status%percent == 0 {
+ logger.Info("Generating DAG in progress", "percentage", uint64(status*100)/(size/hashBytes), "elapsed", common.PrettyDuration(time.Since(start)))
+ }
+ }
+ }(i)
+ }
+ // Wait for all the generators to finish and return
+ pend.Wait()
+}
+
+// hashimoto aggregates data from the full dataset in order to produce our final
+// value for a particular header hash and nonce.
+func hashimoto(hash []byte, nonce uint64, size uint64, lookup func(index uint32) []uint32) ([]byte, []byte) {
+ // Calculate the number of thoretical rows (we use one buffer nonetheless)
+ rows := uint32(size / mixBytes)
+
+ // Combine header+nonce into a 64 byte seed
+ seed := make([]byte, 40)
+ copy(seed, hash)
+ binary.LittleEndian.PutUint64(seed[32:], nonce)
+
+ seed = crypto.Keccak512(seed)
+ seedHead := binary.LittleEndian.Uint32(seed)
+
+ // Start the mix with replicated seed
+ mix := make([]uint32, mixBytes/4)
+ for i := 0; i < len(mix); i++ {
+ mix[i] = binary.LittleEndian.Uint32(seed[i%16*4:])
+ }
+ // Mix in random dataset nodes
+ temp := make([]uint32, len(mix))
+
+ for i := 0; i < loopAccesses; i++ {
+ parent := fnv(uint32(i)^seedHead, mix[i%len(mix)]) % rows
+ for j := uint32(0); j < mixBytes/hashBytes; j++ {
+ copy(temp[j*hashWords:], lookup(2*parent+j))
+ }
+ fnvHash(mix, temp)
+ }
+ // Compress mix
+ for i := 0; i < len(mix); i += 4 {
+ mix[i/4] = fnv(fnv(fnv(mix[i], mix[i+1]), mix[i+2]), mix[i+3])
+ }
+ mix = mix[:len(mix)/4]
+
+ digest := make([]byte, common.HashLength)
+ for i, val := range mix {
+ binary.LittleEndian.PutUint32(digest[i*4:], val)
+ }
+ return digest, crypto.Keccak256(append(seed, digest...))
+}
+
+// hashimotoLight aggregates data from the full dataset (using only a small
+// in-memory cache) in order to produce our final value for a particular header
+// hash and nonce.
+func hashimotoLight(size uint64, cache []uint32, hash []byte, nonce uint64) ([]byte, []byte) {
+ keccak512 := makeHasher(sha3.NewKeccak512())
+
+ lookup := func(index uint32) []uint32 {
+ rawData := generateDatasetItem(cache, index, keccak512)
+
+ data := make([]uint32, len(rawData)/4)
+ for i := 0; i < len(data); i++ {
+ data[i] = binary.LittleEndian.Uint32(rawData[i*4:])
+ }
+ return data
+ }
+ return hashimoto(hash, nonce, size, lookup)
+}
+
+// hashimotoFull aggregates data from the full dataset (using the full in-memory
+// dataset) in order to produce our final value for a particular header hash and
+// nonce.
+func hashimotoFull(dataset []uint32, hash []byte, nonce uint64) ([]byte, []byte) {
+ lookup := func(index uint32) []uint32 {
+ offset := index * hashWords
+ return dataset[offset : offset+hashWords]
+ }
+ return hashimoto(hash, nonce, uint64(len(dataset))*4, lookup)
+}
+
+// datasetSizes is a lookup table for the ethash dataset size for the first 2048
+// epochs (i.e. 61440000 blocks).
+var datasetSizes = []uint64{
+ 1073739904, 1082130304, 1090514816, 1098906752, 1107293056,
+ 1115684224, 1124070016, 1132461952, 1140849536, 1149232768,
+ 1157627776, 1166013824, 1174404736, 1182786944, 1191180416,
+ 1199568512, 1207958912, 1216345216, 1224732032, 1233124736,
+ 1241513344, 1249902464, 1258290304, 1266673792, 1275067264,
+ 1283453312, 1291844992, 1300234112, 1308619904, 1317010048,
+ 1325397376, 1333787776, 1342176128, 1350561664, 1358954368,
+ 1367339392, 1375731584, 1384118144, 1392507008, 1400897408,
+ 1409284736, 1417673344, 1426062464, 1434451072, 1442839168,
+ 1451229056, 1459615616, 1468006016, 1476394112, 1484782976,
+ 1493171584, 1501559168, 1509948032, 1518337664, 1526726528,
+ 1535114624, 1543503488, 1551892096, 1560278656, 1568669056,
+ 1577056384, 1585446272, 1593831296, 1602219392, 1610610304,
+ 1619000192, 1627386752, 1635773824, 1644164224, 1652555648,
+ 1660943488, 1669332608, 1677721216, 1686109312, 1694497664,
+ 1702886272, 1711274624, 1719661184, 1728047744, 1736434816,
+ 1744829056, 1753218944, 1761606272, 1769995904, 1778382464,
+ 1786772864, 1795157888, 1803550592, 1811937664, 1820327552,
+ 1828711552, 1837102976, 1845488768, 1853879936, 1862269312,
+ 1870656896, 1879048064, 1887431552, 1895825024, 1904212096,
+ 1912601216, 1920988544, 1929379456, 1937765504, 1946156672,
+ 1954543232, 1962932096, 1971321728, 1979707264, 1988093056,
+ 1996487552, 2004874624, 2013262208, 2021653888, 2030039936,
+ 2038430848, 2046819968, 2055208576, 2063596672, 2071981952,
+ 2080373632, 2088762752, 2097149056, 2105539712, 2113928576,
+ 2122315136, 2130700672, 2139092608, 2147483264, 2155872128,
+ 2164257664, 2172642176, 2181035392, 2189426048, 2197814912,
+ 2206203008, 2214587264, 2222979712, 2231367808, 2239758208,
+ 2248145024, 2256527744, 2264922752, 2273312128, 2281701248,
+ 2290086272, 2298476672, 2306867072, 2315251072, 2323639168,
+ 2332032128, 2340420224, 2348808064, 2357196416, 2365580416,
+ 2373966976, 2382363008, 2390748544, 2399139968, 2407530368,
+ 2415918976, 2424307328, 2432695424, 2441084288, 2449472384,
+ 2457861248, 2466247808, 2474637184, 2483026816, 2491414144,
+ 2499803776, 2508191872, 2516582272, 2524970368, 2533359232,
+ 2541743488, 2550134144, 2558525056, 2566913408, 2575301504,
+ 2583686528, 2592073856, 2600467328, 2608856192, 2617240448,
+ 2625631616, 2634022016, 2642407552, 2650796416, 2659188352,
+ 2667574912, 2675965312, 2684352896, 2692738688, 2701130624,
+ 2709518464, 2717907328, 2726293376, 2734685056, 2743073152,
+ 2751462016, 2759851648, 2768232832, 2776625536, 2785017728,
+ 2793401984, 2801794432, 2810182016, 2818571648, 2826959488,
+ 2835349376, 2843734144, 2852121472, 2860514432, 2868900992,
+ 2877286784, 2885676928, 2894069632, 2902451584, 2910843008,
+ 2919234688, 2927622784, 2936011648, 2944400768, 2952789376,
+ 2961177728, 2969565568, 2977951616, 2986338944, 2994731392,
+ 3003120256, 3011508352, 3019895936, 3028287104, 3036675968,
+ 3045063808, 3053452928, 3061837696, 3070228352, 3078615424,
+ 3087003776, 3095394944, 3103782272, 3112173184, 3120562048,
+ 3128944768, 3137339264, 3145725056, 3154109312, 3162505088,
+ 3170893184, 3179280256, 3187669376, 3196056704, 3204445568,
+ 3212836736, 3221224064, 3229612928, 3238002304, 3246391168,
+ 3254778496, 3263165824, 3271556224, 3279944576, 3288332416,
+ 3296719232, 3305110912, 3313500032, 3321887104, 3330273152,
+ 3338658944, 3347053184, 3355440512, 3363827072, 3372220288,
+ 3380608384, 3388997504, 3397384576, 3405774208, 3414163072,
+ 3422551936, 3430937984, 3439328384, 3447714176, 3456104576,
+ 3464493952, 3472883584, 3481268864, 3489655168, 3498048896,
+ 3506434432, 3514826368, 3523213952, 3531603584, 3539987072,
+ 3548380288, 3556763264, 3565157248, 3573545344, 3581934464,
+ 3590324096, 3598712704, 3607098752, 3615488384, 3623877248,
+ 3632265856, 3640646528, 3649043584, 3657430144, 3665821568,
+ 3674207872, 3682597504, 3690984832, 3699367808, 3707764352,
+ 3716152448, 3724541056, 3732925568, 3741318016, 3749706368,
+ 3758091136, 3766481536, 3774872704, 3783260032, 3791650432,
+ 3800036224, 3808427648, 3816815488, 3825204608, 3833592704,
+ 3841981568, 3850370432, 3858755968, 3867147904, 3875536256,
+ 3883920512, 3892313728, 3900702592, 3909087872, 3917478784,
+ 3925868416, 3934256512, 3942645376, 3951032192, 3959422336,
+ 3967809152, 3976200064, 3984588416, 3992974976, 4001363584,
+ 4009751168, 4018141312, 4026530432, 4034911616, 4043308928,
+ 4051695488, 4060084352, 4068472448, 4076862848, 4085249408,
+ 4093640576, 4102028416, 4110413696, 4118805632, 4127194496,
+ 4135583104, 4143971968, 4152360832, 4160746112, 4169135744,
+ 4177525888, 4185912704, 4194303616, 4202691968, 4211076736,
+ 4219463552, 4227855488, 4236246656, 4244633728, 4253022848,
+ 4261412224, 4269799808, 4278184832, 4286578048, 4294962304,
+ 4303349632, 4311743104, 4320130432, 4328521088, 4336909184,
+ 4345295488, 4353687424, 4362073472, 4370458496, 4378852736,
+ 4387238528, 4395630208, 4404019072, 4412407424, 4420790656,
+ 4429182848, 4437571456, 4445962112, 4454344064, 4462738048,
+ 4471119232, 4479516544, 4487904128, 4496289664, 4504682368,
+ 4513068416, 4521459584, 4529846144, 4538232704, 4546619776,
+ 4555010176, 4563402112, 4571790208, 4580174464, 4588567936,
+ 4596957056, 4605344896, 4613734016, 4622119808, 4630511488,
+ 4638898816, 4647287936, 4655675264, 4664065664, 4672451968,
+ 4680842624, 4689231488, 4697620352, 4706007424, 4714397056,
+ 4722786176, 4731173248, 4739562368, 4747951744, 4756340608,
+ 4764727936, 4773114496, 4781504384, 4789894784, 4798283648,
+ 4806667648, 4815059584, 4823449472, 4831835776, 4840226176,
+ 4848612224, 4857003392, 4865391488, 4873780096, 4882169728,
+ 4890557312, 4898946944, 4907333248, 4915722368, 4924110976,
+ 4932499328, 4940889728, 4949276032, 4957666432, 4966054784,
+ 4974438016, 4982831488, 4991221376, 4999607168, 5007998848,
+ 5016386432, 5024763776, 5033164672, 5041544576, 5049941888,
+ 5058329728, 5066717056, 5075107456, 5083494272, 5091883904,
+ 5100273536, 5108662144, 5117048192, 5125436032, 5133827456,
+ 5142215296, 5150605184, 5158993024, 5167382144, 5175769472,
+ 5184157568, 5192543872, 5200936064, 5209324928, 5217711232,
+ 5226102656, 5234490496, 5242877312, 5251263872, 5259654016,
+ 5268040832, 5276434304, 5284819328, 5293209728, 5301598592,
+ 5309986688, 5318374784, 5326764416, 5335151488, 5343542144,
+ 5351929472, 5360319872, 5368706944, 5377096576, 5385484928,
+ 5393871232, 5402263424, 5410650496, 5419040384, 5427426944,
+ 5435816576, 5444205952, 5452594816, 5460981376, 5469367936,
+ 5477760896, 5486148736, 5494536832, 5502925952, 5511315328,
+ 5519703424, 5528089984, 5536481152, 5544869504, 5553256064,
+ 5561645696, 5570032768, 5578423936, 5586811264, 5595193216,
+ 5603585408, 5611972736, 5620366208, 5628750464, 5637143936,
+ 5645528192, 5653921408, 5662310272, 5670694784, 5679082624,
+ 5687474048, 5695864448, 5704251008, 5712641408, 5721030272,
+ 5729416832, 5737806208, 5746194304, 5754583936, 5762969984,
+ 5771358592, 5779748224, 5788137856, 5796527488, 5804911232,
+ 5813300608, 5821692544, 5830082176, 5838468992, 5846855552,
+ 5855247488, 5863636096, 5872024448, 5880411008, 5888799872,
+ 5897186432, 5905576832, 5913966976, 5922352768, 5930744704,
+ 5939132288, 5947522432, 5955911296, 5964299392, 5972688256,
+ 5981074304, 5989465472, 5997851008, 6006241408, 6014627968,
+ 6023015552, 6031408256, 6039796096, 6048185216, 6056574848,
+ 6064963456, 6073351808, 6081736064, 6090128768, 6098517632,
+ 6106906496, 6115289216, 6123680896, 6132070016, 6140459648,
+ 6148849024, 6157237376, 6165624704, 6174009728, 6182403712,
+ 6190792064, 6199176064, 6207569792, 6215952256, 6224345216,
+ 6232732544, 6241124224, 6249510272, 6257899136, 6266287744,
+ 6274676864, 6283065728, 6291454336, 6299843456, 6308232064,
+ 6316620928, 6325006208, 6333395584, 6341784704, 6350174848,
+ 6358562176, 6366951296, 6375337856, 6383729536, 6392119168,
+ 6400504192, 6408895616, 6417283456, 6425673344, 6434059136,
+ 6442444672, 6450837376, 6459223424, 6467613056, 6476004224,
+ 6484393088, 6492781952, 6501170048, 6509555072, 6517947008,
+ 6526336384, 6534725504, 6543112832, 6551500672, 6559888768,
+ 6568278656, 6576662912, 6585055616, 6593443456, 6601834112,
+ 6610219648, 6618610304, 6626999168, 6635385472, 6643777408,
+ 6652164224, 6660552832, 6668941952, 6677330048, 6685719424,
+ 6694107776, 6702493568, 6710882176, 6719274112, 6727662976,
+ 6736052096, 6744437632, 6752825984, 6761213824, 6769604224,
+ 6777993856, 6786383488, 6794770816, 6803158144, 6811549312,
+ 6819937664, 6828326528, 6836706176, 6845101696, 6853491328,
+ 6861880448, 6870269312, 6878655104, 6887046272, 6895433344,
+ 6903822208, 6912212864, 6920596864, 6928988288, 6937377152,
+ 6945764992, 6954149248, 6962544256, 6970928768, 6979317376,
+ 6987709312, 6996093824, 7004487296, 7012875392, 7021258624,
+ 7029652352, 7038038912, 7046427776, 7054818944, 7063207808,
+ 7071595136, 7079980928, 7088372608, 7096759424, 7105149824,
+ 7113536896, 7121928064, 7130315392, 7138699648, 7147092352,
+ 7155479168, 7163865728, 7172249984, 7180648064, 7189036672,
+ 7197424768, 7205810816, 7214196608, 7222589824, 7230975104,
+ 7239367552, 7247755904, 7256145536, 7264533376, 7272921472,
+ 7281308032, 7289694848, 7298088832, 7306471808, 7314864512,
+ 7323253888, 7331643008, 7340029568, 7348419712, 7356808832,
+ 7365196672, 7373585792, 7381973888, 7390362752, 7398750592,
+ 7407138944, 7415528576, 7423915648, 7432302208, 7440690304,
+ 7449080192, 7457472128, 7465860992, 7474249088, 7482635648,
+ 7491023744, 7499412608, 7507803008, 7516192384, 7524579968,
+ 7532967296, 7541358464, 7549745792, 7558134656, 7566524032,
+ 7574912896, 7583300992, 7591690112, 7600075136, 7608466816,
+ 7616854912, 7625244544, 7633629824, 7642020992, 7650410368,
+ 7658794112, 7667187328, 7675574912, 7683961984, 7692349568,
+ 7700739712, 7709130368, 7717519232, 7725905536, 7734295424,
+ 7742683264, 7751069056, 7759457408, 7767849088, 7776238208,
+ 7784626816, 7793014912, 7801405312, 7809792128, 7818179968,
+ 7826571136, 7834957184, 7843347328, 7851732352, 7860124544,
+ 7868512384, 7876902016, 7885287808, 7893679744, 7902067072,
+ 7910455936, 7918844288, 7927230848, 7935622784, 7944009344,
+ 7952400256, 7960786048, 7969176704, 7977565312, 7985953408,
+ 7994339968, 8002730368, 8011119488, 8019508096, 8027896192,
+ 8036285056, 8044674688, 8053062272, 8061448832, 8069838464,
+ 8078227328, 8086616704, 8095006592, 8103393664, 8111783552,
+ 8120171392, 8128560256, 8136949376, 8145336704, 8153726848,
+ 8162114944, 8170503296, 8178891904, 8187280768, 8195669632,
+ 8204058496, 8212444544, 8220834176, 8229222272, 8237612672,
+ 8246000768, 8254389376, 8262775168, 8271167104, 8279553664,
+ 8287944064, 8296333184, 8304715136, 8313108352, 8321497984,
+ 8329885568, 8338274432, 8346663296, 8355052928, 8363441536,
+ 8371828352, 8380217984, 8388606592, 8396996224, 8405384576,
+ 8413772672, 8422161536, 8430549376, 8438939008, 8447326592,
+ 8455715456, 8464104832, 8472492928, 8480882048, 8489270656,
+ 8497659776, 8506045312, 8514434944, 8522823808, 8531208832,
+ 8539602304, 8547990656, 8556378752, 8564768384, 8573154176,
+ 8581542784, 8589933952, 8598322816, 8606705024, 8615099264,
+ 8623487872, 8631876992, 8640264064, 8648653952, 8657040256,
+ 8665430656, 8673820544, 8682209152, 8690592128, 8698977152,
+ 8707374464, 8715763328, 8724151424, 8732540032, 8740928384,
+ 8749315712, 8757704576, 8766089344, 8774480768, 8782871936,
+ 8791260032, 8799645824, 8808034432, 8816426368, 8824812928,
+ 8833199488, 8841591424, 8849976448, 8858366336, 8866757248,
+ 8875147136, 8883532928, 8891923328, 8900306816, 8908700288,
+ 8917088384, 8925478784, 8933867392, 8942250368, 8950644608,
+ 8959032704, 8967420544, 8975809664, 8984197504, 8992584064,
+ 9000976256, 9009362048, 9017752448, 9026141312, 9034530688,
+ 9042917504, 9051307904, 9059694208, 9068084864, 9076471424,
+ 9084861824, 9093250688, 9101638528, 9110027648, 9118416512,
+ 9126803584, 9135188096, 9143581312, 9151969664, 9160356224,
+ 9168747136, 9177134464, 9185525632, 9193910144, 9202302848,
+ 9210690688, 9219079552, 9227465344, 9235854464, 9244244864,
+ 9252633472, 9261021824, 9269411456, 9277799296, 9286188928,
+ 9294574208, 9302965888, 9311351936, 9319740032, 9328131968,
+ 9336516736, 9344907392, 9353296768, 9361685888, 9370074752,
+ 9378463616, 9386849408, 9395239808, 9403629184, 9412016512,
+ 9420405376, 9428795008, 9437181568, 9445570688, 9453960832,
+ 9462346624, 9470738048, 9479121536, 9487515008, 9495903616,
+ 9504289664, 9512678528, 9521067904, 9529456256, 9537843584,
+ 9546233728, 9554621312, 9563011456, 9571398784, 9579788672,
+ 9588178304, 9596567168, 9604954496, 9613343104, 9621732992,
+ 9630121856, 9638508416, 9646898816, 9655283584, 9663675776,
+ 9672061312, 9680449664, 9688840064, 9697230464, 9705617536,
+ 9714003584, 9722393984, 9730772608, 9739172224, 9747561088,
+ 9755945344, 9764338816, 9772726144, 9781116544, 9789503872,
+ 9797892992, 9806282624, 9814670464, 9823056512, 9831439232,
+ 9839833984, 9848224384, 9856613504, 9865000576, 9873391232,
+ 9881772416, 9890162816, 9898556288, 9906940544, 9915333248,
+ 9923721088, 9932108672, 9940496512, 9948888448, 9957276544,
+ 9965666176, 9974048384, 9982441088, 9990830464, 9999219584,
+ 10007602816, 10015996544, 10024385152, 10032774016, 10041163648,
+ 10049548928, 10057940096, 10066329472, 10074717824, 10083105152,
+ 10091495296, 10099878784, 10108272256, 10116660608, 10125049216,
+ 10133437312, 10141825664, 10150213504, 10158601088, 10166991232,
+ 10175378816, 10183766144, 10192157312, 10200545408, 10208935552,
+ 10217322112, 10225712768, 10234099328, 10242489472, 10250876032,
+ 10259264896, 10267656064, 10276042624, 10284429184, 10292820352,
+ 10301209472, 10309598848, 10317987712, 10326375296, 10334763392,
+ 10343153536, 10351541632, 10359930752, 10368318592, 10376707456,
+ 10385096576, 10393484672, 10401867136, 10410262144, 10418647424,
+ 10427039104, 10435425664, 10443810176, 10452203648, 10460589952,
+ 10468982144, 10477369472, 10485759104, 10494147712, 10502533504,
+ 10510923392, 10519313536, 10527702656, 10536091264, 10544478592,
+ 10552867712, 10561255808, 10569642368, 10578032768, 10586423168,
+ 10594805632, 10603200128, 10611588992, 10619976064, 10628361344,
+ 10636754048, 10645143424, 10653531776, 10661920384, 10670307968,
+ 10678696832, 10687086464, 10695475072, 10703863168, 10712246144,
+ 10720639616, 10729026688, 10737414784, 10745806208, 10754190976,
+ 10762581376, 10770971264, 10779356288, 10787747456, 10796135552,
+ 10804525184, 10812915584, 10821301888, 10829692288, 10838078336,
+ 10846469248, 10854858368, 10863247232, 10871631488, 10880023424,
+ 10888412032, 10896799616, 10905188992, 10913574016, 10921964672,
+ 10930352768, 10938742912, 10947132544, 10955518592, 10963909504,
+ 10972298368, 10980687488, 10989074816, 10997462912, 11005851776,
+ 11014241152, 11022627712, 11031017344, 11039403904, 11047793024,
+ 11056184704, 11064570752, 11072960896, 11081343872, 11089737856,
+ 11098128256, 11106514816, 11114904448, 11123293568, 11131680128,
+ 11140065152, 11148458368, 11156845696, 11165236864, 11173624192,
+ 11182013824, 11190402688, 11198790784, 11207179136, 11215568768,
+ 11223957376, 11232345728, 11240734592, 11249122688, 11257511296,
+ 11265899648, 11274285952, 11282675584, 11291065472, 11299452544,
+ 11307842432, 11316231296, 11324616832, 11333009024, 11341395584,
+ 11349782656, 11358172288, 11366560384, 11374950016, 11383339648,
+ 11391721856, 11400117376, 11408504192, 11416893568, 11425283456,
+ 11433671552, 11442061184, 11450444672, 11458837888, 11467226752,
+ 11475611776, 11484003968, 11492392064, 11500780672, 11509169024,
+ 11517550976, 11525944448, 11534335616, 11542724224, 11551111808,
+ 11559500672, 11567890304, 11576277376, 11584667008, 11593056128,
+ 11601443456, 11609830016, 11618221952, 11626607488, 11634995072,
+ 11643387776, 11651775104, 11660161664, 11668552576, 11676940928,
+ 11685330304, 11693718656, 11702106496, 11710496128, 11718882688,
+ 11727273088, 11735660416, 11744050048, 11752437376, 11760824704,
+ 11769216128, 11777604736, 11785991296, 11794381952, 11802770048,
+ 11811157888, 11819548544, 11827932544, 11836324736, 11844713344,
+ 11853100928, 11861486464, 11869879936, 11878268032, 11886656896,
+ 11895044992, 11903433088, 11911822976, 11920210816, 11928600448,
+ 11936987264, 11945375872, 11953761152, 11962151296, 11970543488,
+ 11978928512, 11987320448, 11995708288, 12004095104, 12012486272,
+ 12020875136, 12029255552, 12037652096, 12046039168, 12054429568,
+ 12062813824, 12071206528, 12079594624, 12087983744, 12096371072,
+ 12104759936, 12113147264, 12121534592, 12129924992, 12138314624,
+ 12146703232, 12155091584, 12163481216, 12171864704, 12180255872,
+ 12188643968, 12197034112, 12205424512, 12213811328, 12222199424,
+ 12230590336, 12238977664, 12247365248, 12255755392, 12264143488,
+ 12272531584, 12280920448, 12289309568, 12297694592, 12306086528,
+ 12314475392, 12322865024, 12331253632, 12339640448, 12348029312,
+ 12356418944, 12364805248, 12373196672, 12381580928, 12389969024,
+ 12398357632, 12406750592, 12415138432, 12423527552, 12431916416,
+ 12440304512, 12448692352, 12457081216, 12465467776, 12473859968,
+ 12482245504, 12490636672, 12499025536, 12507411584, 12515801728,
+ 12524190592, 12532577152, 12540966272, 12549354368, 12557743232,
+ 12566129536, 12574523264, 12582911872, 12591299456, 12599688064,
+ 12608074624, 12616463488, 12624845696, 12633239936, 12641631616,
+ 12650019968, 12658407296, 12666795136, 12675183232, 12683574656,
+ 12691960192, 12700350592, 12708740224, 12717128576, 12725515904,
+ 12733906816, 12742295168, 12750680192, 12759071872, 12767460736,
+ 12775848832, 12784236928, 12792626816, 12801014656, 12809404288,
+ 12817789312, 12826181504, 12834568832, 12842954624, 12851345792,
+ 12859732352, 12868122496, 12876512128, 12884901248, 12893289088,
+ 12901672832, 12910067584, 12918455168, 12926842496, 12935232896,
+ 12943620736, 12952009856, 12960396928, 12968786816, 12977176192,
+ 12985563776, 12993951104, 13002341504, 13010730368, 13019115392,
+ 13027506304, 13035895168, 13044272512, 13052673152, 13061062528,
+ 13069446272, 13077838976, 13086227072, 13094613632, 13103000192,
+ 13111393664, 13119782528, 13128157568, 13136559232, 13144945024,
+ 13153329536, 13161724288, 13170111872, 13178502784, 13186884736,
+ 13195279744, 13203667072, 13212057472, 13220445824, 13228832128,
+ 13237221248, 13245610624, 13254000512, 13262388352, 13270777472,
+ 13279166336, 13287553408, 13295943296, 13304331904, 13312719488,
+ 13321108096, 13329494656, 13337885824, 13346274944, 13354663808,
+ 13363051136, 13371439232, 13379825024, 13388210816, 13396605056,
+ 13404995456, 13413380224, 13421771392, 13430159744, 13438546048,
+ 13446937216, 13455326848, 13463708288, 13472103808, 13480492672,
+ 13488875648, 13497269888, 13505657728, 13514045312, 13522435712,
+ 13530824576, 13539210112, 13547599232, 13555989376, 13564379008,
+ 13572766336, 13581154432, 13589544832, 13597932928, 13606320512,
+ 13614710656, 13623097472, 13631477632, 13639874944, 13648264064,
+ 13656652928, 13665041792, 13673430656, 13681818496, 13690207616,
+ 13698595712, 13706982272, 13715373184, 13723762048, 13732150144,
+ 13740536704, 13748926592, 13757316224, 13765700992, 13774090112,
+ 13782477952, 13790869376, 13799259008, 13807647872, 13816036736,
+ 13824425344, 13832814208, 13841202304, 13849591424, 13857978752,
+ 13866368896, 13874754688, 13883145344, 13891533184, 13899919232,
+ 13908311168, 13916692096, 13925085056, 13933473152, 13941866368,
+ 13950253696, 13958643584, 13967032192, 13975417216, 13983807616,
+ 13992197504, 14000582272, 14008973696, 14017363072, 14025752192,
+ 14034137984, 14042528384, 14050918016, 14059301504, 14067691648,
+ 14076083584, 14084470144, 14092852352, 14101249664, 14109635968,
+ 14118024832, 14126407552, 14134804352, 14143188608, 14151577984,
+ 14159968384, 14168357248, 14176741504, 14185127296, 14193521024,
+ 14201911424, 14210301824, 14218685056, 14227067264, 14235467392,
+ 14243855488, 14252243072, 14260630144, 14269021568, 14277409408,
+ 14285799296, 14294187904, 14302571392, 14310961792, 14319353728,
+ 14327738752, 14336130944, 14344518784, 14352906368, 14361296512,
+ 14369685376, 14378071424, 14386462592, 14394848128, 14403230848,
+ 14411627392, 14420013952, 14428402304, 14436793472, 14445181568,
+ 14453569664, 14461959808, 14470347904, 14478737024, 14487122816,
+ 14495511424, 14503901824, 14512291712, 14520677504, 14529064832,
+ 14537456768, 14545845632, 14554234496, 14562618496, 14571011456,
+ 14579398784, 14587789184, 14596172672, 14604564608, 14612953984,
+ 14621341312, 14629724288, 14638120832, 14646503296, 14654897536,
+ 14663284864, 14671675264, 14680061056, 14688447616, 14696835968,
+ 14705228416, 14713616768, 14722003328, 14730392192, 14738784128,
+ 14747172736, 14755561088, 14763947648, 14772336512, 14780725376,
+ 14789110144, 14797499776, 14805892736, 14814276992, 14822670208,
+ 14831056256, 14839444352, 14847836032, 14856222848, 14864612992,
+ 14872997504, 14881388672, 14889775744, 14898165376, 14906553472,
+ 14914944896, 14923329664, 14931721856, 14940109696, 14948497024,
+ 14956887424, 14965276544, 14973663616, 14982053248, 14990439808,
+ 14998830976, 15007216768, 15015605888, 15023995264, 15032385152,
+ 15040768384, 15049154944, 15057549184, 15065939072, 15074328448,
+ 15082715008, 15091104128, 15099493504, 15107879296, 15116269184,
+ 15124659584, 15133042304, 15141431936, 15149824384, 15158214272,
+ 15166602368, 15174991232, 15183378304, 15191760512, 15200154496,
+ 15208542592, 15216931712, 15225323392, 15233708416, 15242098048,
+ 15250489216, 15258875264, 15267265408, 15275654528, 15284043136,
+ 15292431488, 15300819584, 15309208192, 15317596544, 15325986176,
+ 15334374784, 15342763648, 15351151744, 15359540608, 15367929728,
+ 15376318336, 15384706432, 15393092992, 15401481856, 15409869952,
+ 15418258816, 15426649984, 15435037568, 15443425664, 15451815296,
+ 15460203392, 15468589184, 15476979328, 15485369216, 15493755776,
+ 15502146944, 15510534272, 15518924416, 15527311232, 15535699072,
+ 15544089472, 15552478336, 15560866688, 15569254528, 15577642624,
+ 15586031488, 15594419072, 15602809472, 15611199104, 15619586432,
+ 15627975296, 15636364928, 15644753792, 15653141888, 15661529216,
+ 15669918848, 15678305152, 15686696576, 15695083136, 15703474048,
+ 15711861632, 15720251264, 15728636288, 15737027456, 15745417088,
+ 15753804928, 15762194048, 15770582656, 15778971008, 15787358336,
+ 15795747712, 15804132224, 15812523392, 15820909696, 15829300096,
+ 15837691264, 15846071936, 15854466944, 15862855808, 15871244672,
+ 15879634816, 15888020608, 15896409728, 15904799104, 15913185152,
+ 15921577088, 15929966464, 15938354816, 15946743424, 15955129472,
+ 15963519872, 15971907968, 15980296064, 15988684928, 15997073024,
+ 16005460864, 16013851264, 16022241152, 16030629248, 16039012736,
+ 16047406976, 16055794816, 16064181376, 16072571264, 16080957824,
+ 16089346688, 16097737856, 16106125184, 16114514816, 16122904192,
+ 16131292544, 16139678848, 16148066944, 16156453504, 16164839552,
+ 16173236096, 16181623424, 16190012032, 16198401152, 16206790528,
+ 16215177344, 16223567744, 16231956352, 16240344704, 16248731008,
+ 16257117824, 16265504384, 16273898624, 16282281856, 16290668672,
+ 16299064192, 16307449216, 16315842176, 16324230016, 16332613504,
+ 16341006464, 16349394304, 16357783168, 16366172288, 16374561664,
+ 16382951296, 16391337856, 16399726208, 16408116352, 16416505472,
+ 16424892032, 16433282176, 16441668224, 16450058624, 16458448768,
+ 16466836864, 16475224448, 16483613056, 16492001408, 16500391808,
+ 16508779648, 16517166976, 16525555328, 16533944192, 16542330752,
+ 16550719616, 16559110528, 16567497088, 16575888512, 16584274816,
+ 16592665472, 16601051008, 16609442944, 16617832064, 16626218624,
+ 16634607488, 16642996096, 16651385728, 16659773824, 16668163712,
+ 16676552576, 16684938112, 16693328768, 16701718144, 16710095488,
+ 16718492288, 16726883968, 16735272832, 16743661184, 16752049792,
+ 16760436608, 16768827008, 16777214336, 16785599104, 16793992832,
+ 16802381696, 16810768768, 16819151744, 16827542656, 16835934848,
+ 16844323712, 16852711552, 16861101952, 16869489536, 16877876864,
+ 16886265728, 16894653056, 16903044736, 16911431296, 16919821696,
+ 16928207488, 16936592768, 16944987776, 16953375616, 16961763968,
+ 16970152832, 16978540928, 16986929536, 16995319168, 17003704448,
+ 17012096896, 17020481152, 17028870784, 17037262208, 17045649536,
+ 17054039936, 17062426496, 17070814336, 17079205504, 17087592064,
+ 17095978112, 17104369024, 17112759424, 17121147776, 17129536384,
+ 17137926016, 17146314368, 17154700928, 17163089792, 17171480192,
+ 17179864192, 17188256896, 17196644992, 17205033856, 17213423488,
+ 17221811072, 17230198912, 17238588032, 17246976896, 17255360384,
+ 17263754624, 17272143232, 17280530048, 17288918912, 17297309312,
+ 17305696384, 17314085504, 17322475136, 17330863744, 17339252096,
+ 17347640192, 17356026496, 17364413824, 17372796544, 17381190016,
+ 17389583488, 17397972608, 17406360704, 17414748544, 17423135872,
+ 17431527296, 17439915904, 17448303232, 17456691584, 17465081728,
+ 17473468288, 17481857408, 17490247552, 17498635904, 17507022464,
+ 17515409024, 17523801728, 17532189824, 17540577664, 17548966016,
+ 17557353344, 17565741184, 17574131584, 17582519168, 17590907008,
+ 17599296128, 17607687808, 17616076672, 17624455808, 17632852352,
+ 17641238656, 17649630848, 17658018944, 17666403968, 17674794112,
+ 17683178368, 17691573376, 17699962496, 17708350592, 17716739968,
+ 17725126528, 17733517184, 17741898112, 17750293888, 17758673024,
+ 17767070336, 17775458432, 17783848832, 17792236928, 17800625536,
+ 17809012352, 17817402752, 17825785984, 17834178944, 17842563968,
+ 17850955648, 17859344512, 17867732864, 17876119424, 17884511872,
+ 17892900224, 17901287296, 17909677696, 17918058112, 17926451072,
+ 17934843776, 17943230848, 17951609216, 17960008576, 17968397696,
+ 17976784256, 17985175424, 17993564032, 18001952128, 18010339712,
+ 18018728576, 18027116672, 18035503232, 18043894144, 18052283264,
+ 18060672128, 18069056384, 18077449856, 18085837184, 18094225792,
+ 18102613376, 18111004544, 18119388544, 18127781248, 18136170368,
+ 18144558976, 18152947328, 18161336192, 18169724288, 18178108544,
+ 18186498944, 18194886784, 18203275648, 18211666048, 18220048768,
+ 18228444544, 18236833408, 18245220736}
+
+// cacheSizes is a lookup table for the ethash verification cache size for the
+// first 2048 epochs (i.e. 61440000 blocks).
+var cacheSizes = []uint64{
+ 16776896, 16907456, 17039296, 17170112, 17301056, 17432512, 17563072,
+ 17693888, 17824192, 17955904, 18087488, 18218176, 18349504, 18481088,
+ 18611392, 18742336, 18874304, 19004224, 19135936, 19267264, 19398208,
+ 19529408, 19660096, 19791424, 19922752, 20053952, 20184896, 20315968,
+ 20446912, 20576576, 20709184, 20840384, 20971072, 21102272, 21233216,
+ 21364544, 21494848, 21626816, 21757376, 21887552, 22019392, 22151104,
+ 22281536, 22412224, 22543936, 22675264, 22806464, 22935872, 23068096,
+ 23198272, 23330752, 23459008, 23592512, 23723968, 23854912, 23986112,
+ 24116672, 24247616, 24378688, 24509504, 24640832, 24772544, 24903488,
+ 25034432, 25165376, 25296704, 25427392, 25558592, 25690048, 25820096,
+ 25951936, 26081728, 26214208, 26345024, 26476096, 26606656, 26737472,
+ 26869184, 26998208, 27131584, 27262528, 27393728, 27523904, 27655744,
+ 27786688, 27917888, 28049344, 28179904, 28311488, 28441792, 28573504,
+ 28700864, 28835648, 28966208, 29096768, 29228608, 29359808, 29490752,
+ 29621824, 29752256, 29882816, 30014912, 30144448, 30273728, 30406976,
+ 30538432, 30670784, 30799936, 30932672, 31063744, 31195072, 31325248,
+ 31456192, 31588288, 31719232, 31850432, 31981504, 32110784, 32243392,
+ 32372672, 32505664, 32636608, 32767808, 32897344, 33029824, 33160768,
+ 33289664, 33423296, 33554368, 33683648, 33816512, 33947456, 34076992,
+ 34208704, 34340032, 34471744, 34600256, 34734016, 34864576, 34993984,
+ 35127104, 35258176, 35386688, 35518528, 35650624, 35782336, 35910976,
+ 36044608, 36175808, 36305728, 36436672, 36568384, 36699968, 36830656,
+ 36961984, 37093312, 37223488, 37355072, 37486528, 37617472, 37747904,
+ 37879232, 38009792, 38141888, 38272448, 38403392, 38535104, 38660672,
+ 38795584, 38925632, 39059264, 39190336, 39320768, 39452096, 39581632,
+ 39713984, 39844928, 39974848, 40107968, 40238144, 40367168, 40500032,
+ 40631744, 40762816, 40894144, 41023552, 41155904, 41286208, 41418304,
+ 41547712, 41680448, 41811904, 41942848, 42073792, 42204992, 42334912,
+ 42467008, 42597824, 42729152, 42860096, 42991552, 43122368, 43253696,
+ 43382848, 43515712, 43646912, 43777088, 43907648, 44039104, 44170432,
+ 44302144, 44433344, 44564288, 44694976, 44825152, 44956864, 45088448,
+ 45219008, 45350464, 45481024, 45612608, 45744064, 45874496, 46006208,
+ 46136768, 46267712, 46399424, 46529344, 46660672, 46791488, 46923328,
+ 47053504, 47185856, 47316928, 47447872, 47579072, 47710144, 47839936,
+ 47971648, 48103232, 48234176, 48365248, 48496192, 48627136, 48757312,
+ 48889664, 49020736, 49149248, 49283008, 49413824, 49545152, 49675712,
+ 49807168, 49938368, 50069056, 50200256, 50331584, 50462656, 50593472,
+ 50724032, 50853952, 50986048, 51117632, 51248576, 51379904, 51510848,
+ 51641792, 51773248, 51903296, 52035136, 52164032, 52297664, 52427968,
+ 52557376, 52690112, 52821952, 52952896, 53081536, 53213504, 53344576,
+ 53475776, 53608384, 53738816, 53870528, 54000832, 54131776, 54263744,
+ 54394688, 54525248, 54655936, 54787904, 54918592, 55049152, 55181248,
+ 55312064, 55442752, 55574336, 55705024, 55836224, 55967168, 56097856,
+ 56228672, 56358592, 56490176, 56621888, 56753728, 56884928, 57015488,
+ 57146816, 57278272, 57409216, 57540416, 57671104, 57802432, 57933632,
+ 58064576, 58195264, 58326976, 58457408, 58588864, 58720192, 58849984,
+ 58981696, 59113024, 59243456, 59375552, 59506624, 59637568, 59768512,
+ 59897792, 60030016, 60161984, 60293056, 60423872, 60554432, 60683968,
+ 60817216, 60948032, 61079488, 61209664, 61341376, 61471936, 61602752,
+ 61733696, 61865792, 61996736, 62127808, 62259136, 62389568, 62520512,
+ 62651584, 62781632, 62910784, 63045056, 63176128, 63307072, 63438656,
+ 63569216, 63700928, 63831616, 63960896, 64093888, 64225088, 64355392,
+ 64486976, 64617664, 64748608, 64879424, 65009216, 65142464, 65273792,
+ 65402816, 65535424, 65666752, 65797696, 65927744, 66060224, 66191296,
+ 66321344, 66453056, 66584384, 66715328, 66846656, 66977728, 67108672,
+ 67239104, 67370432, 67501888, 67631296, 67763776, 67895104, 68026304,
+ 68157248, 68287936, 68419264, 68548288, 68681408, 68811968, 68942912,
+ 69074624, 69205568, 69337024, 69467584, 69599168, 69729472, 69861184,
+ 69989824, 70122944, 70253888, 70385344, 70515904, 70647232, 70778816,
+ 70907968, 71040832, 71171648, 71303104, 71432512, 71564992, 71695168,
+ 71826368, 71958464, 72089536, 72219712, 72350144, 72482624, 72613568,
+ 72744512, 72875584, 73006144, 73138112, 73268672, 73400128, 73530944,
+ 73662272, 73793344, 73924544, 74055104, 74185792, 74316992, 74448832,
+ 74579392, 74710976, 74841664, 74972864, 75102784, 75233344, 75364544,
+ 75497024, 75627584, 75759296, 75890624, 76021696, 76152256, 76283072,
+ 76414144, 76545856, 76676672, 76806976, 76937792, 77070016, 77200832,
+ 77331392, 77462464, 77593664, 77725376, 77856448, 77987776, 78118336,
+ 78249664, 78380992, 78511424, 78642496, 78773056, 78905152, 79033664,
+ 79166656, 79297472, 79429568, 79560512, 79690816, 79822784, 79953472,
+ 80084672, 80214208, 80346944, 80477632, 80608576, 80740288, 80870848,
+ 81002048, 81133504, 81264448, 81395648, 81525952, 81657536, 81786304,
+ 81919808, 82050112, 82181312, 82311616, 82443968, 82573376, 82705984,
+ 82835776, 82967744, 83096768, 83230528, 83359552, 83491264, 83622464,
+ 83753536, 83886016, 84015296, 84147776, 84277184, 84409792, 84540608,
+ 84672064, 84803008, 84934336, 85065152, 85193792, 85326784, 85458496,
+ 85589312, 85721024, 85851968, 85982656, 86112448, 86244416, 86370112,
+ 86506688, 86637632, 86769344, 86900672, 87031744, 87162304, 87293632,
+ 87424576, 87555392, 87687104, 87816896, 87947968, 88079168, 88211264,
+ 88341824, 88473152, 88603712, 88735424, 88862912, 88996672, 89128384,
+ 89259712, 89390272, 89521984, 89652544, 89783872, 89914816, 90045376,
+ 90177088, 90307904, 90438848, 90569152, 90700096, 90832832, 90963776,
+ 91093696, 91223744, 91356992, 91486784, 91618496, 91749824, 91880384,
+ 92012224, 92143552, 92273344, 92405696, 92536768, 92666432, 92798912,
+ 92926016, 93060544, 93192128, 93322816, 93453632, 93583936, 93715136,
+ 93845056, 93977792, 94109504, 94240448, 94371776, 94501184, 94632896,
+ 94764224, 94895552, 95023424, 95158208, 95287744, 95420224, 95550016,
+ 95681216, 95811904, 95943872, 96075328, 96203584, 96337856, 96468544,
+ 96599744, 96731072, 96860992, 96992576, 97124288, 97254848, 97385536,
+ 97517248, 97647808, 97779392, 97910464, 98041408, 98172608, 98303168,
+ 98434496, 98565568, 98696768, 98827328, 98958784, 99089728, 99220928,
+ 99352384, 99482816, 99614272, 99745472, 99876416, 100007104,
+ 100138048, 100267072, 100401088, 100529984, 100662592, 100791872,
+ 100925248, 101056064, 101187392, 101317952, 101449408, 101580608,
+ 101711296, 101841728, 101973824, 102104896, 102235712, 102366016,
+ 102498112, 102628672, 102760384, 102890432, 103021888, 103153472,
+ 103284032, 103415744, 103545152, 103677248, 103808576, 103939648,
+ 104070976, 104201792, 104332736, 104462528, 104594752, 104725952,
+ 104854592, 104988608, 105118912, 105247808, 105381184, 105511232,
+ 105643072, 105774784, 105903296, 106037056, 106167872, 106298944,
+ 106429504, 106561472, 106691392, 106822592, 106954304, 107085376,
+ 107216576, 107346368, 107478464, 107609792, 107739712, 107872192,
+ 108003136, 108131392, 108265408, 108396224, 108527168, 108657344,
+ 108789568, 108920384, 109049792, 109182272, 109312576, 109444928,
+ 109572928, 109706944, 109837888, 109969088, 110099648, 110230976,
+ 110362432, 110492992, 110624704, 110755264, 110886208, 111017408,
+ 111148864, 111279296, 111410752, 111541952, 111673024, 111803456,
+ 111933632, 112066496, 112196416, 112328512, 112457792, 112590784,
+ 112715968, 112852672, 112983616, 113114944, 113244224, 113376448,
+ 113505472, 113639104, 113770304, 113901376, 114031552, 114163264,
+ 114294592, 114425536, 114556864, 114687424, 114818624, 114948544,
+ 115080512, 115212224, 115343296, 115473472, 115605184, 115736128,
+ 115867072, 115997248, 116128576, 116260288, 116391488, 116522944,
+ 116652992, 116784704, 116915648, 117046208, 117178304, 117308608,
+ 117440192, 117569728, 117701824, 117833024, 117964096, 118094656,
+ 118225984, 118357312, 118489024, 118617536, 118749632, 118882112,
+ 119012416, 119144384, 119275328, 119406016, 119537344, 119668672,
+ 119798464, 119928896, 120061376, 120192832, 120321728, 120454336,
+ 120584512, 120716608, 120848192, 120979136, 121109056, 121241408,
+ 121372352, 121502912, 121634752, 121764416, 121895744, 122027072,
+ 122157632, 122289088, 122421184, 122550592, 122682944, 122813888,
+ 122945344, 123075776, 123207488, 123338048, 123468736, 123600704,
+ 123731264, 123861952, 123993664, 124124608, 124256192, 124386368,
+ 124518208, 124649024, 124778048, 124911296, 125041088, 125173696,
+ 125303744, 125432896, 125566912, 125696576, 125829056, 125958592,
+ 126090304, 126221248, 126352832, 126483776, 126615232, 126746432,
+ 126876608, 127008704, 127139392, 127270336, 127401152, 127532224,
+ 127663552, 127794752, 127925696, 128055232, 128188096, 128319424,
+ 128449856, 128581312, 128712256, 128843584, 128973632, 129103808,
+ 129236288, 129365696, 129498944, 129629888, 129760832, 129892288,
+ 130023104, 130154048, 130283968, 130416448, 130547008, 130678336,
+ 130807616, 130939456, 131071552, 131202112, 131331776, 131464384,
+ 131594048, 131727296, 131858368, 131987392, 132120256, 132250816,
+ 132382528, 132513728, 132644672, 132774976, 132905792, 133038016,
+ 133168832, 133299392, 133429312, 133562048, 133692992, 133823296,
+ 133954624, 134086336, 134217152, 134348608, 134479808, 134607296,
+ 134741056, 134872384, 135002944, 135134144, 135265472, 135396544,
+ 135527872, 135659072, 135787712, 135921472, 136052416, 136182848,
+ 136313792, 136444864, 136576448, 136707904, 136837952, 136970048,
+ 137099584, 137232064, 137363392, 137494208, 137625536, 137755712,
+ 137887424, 138018368, 138149824, 138280256, 138411584, 138539584,
+ 138672832, 138804928, 138936128, 139066688, 139196864, 139328704,
+ 139460032, 139590208, 139721024, 139852864, 139984576, 140115776,
+ 140245696, 140376512, 140508352, 140640064, 140769856, 140902336,
+ 141032768, 141162688, 141294016, 141426496, 141556544, 141687488,
+ 141819584, 141949888, 142080448, 142212544, 142342336, 142474432,
+ 142606144, 142736192, 142868288, 142997824, 143129408, 143258944,
+ 143392448, 143523136, 143653696, 143785024, 143916992, 144045632,
+ 144177856, 144309184, 144440768, 144570688, 144701888, 144832448,
+ 144965056, 145096384, 145227584, 145358656, 145489856, 145620928,
+ 145751488, 145883072, 146011456, 146144704, 146275264, 146407232,
+ 146538176, 146668736, 146800448, 146931392, 147062336, 147193664,
+ 147324224, 147455936, 147586624, 147717056, 147848768, 147979456,
+ 148110784, 148242368, 148373312, 148503232, 148635584, 148766144,
+ 148897088, 149028416, 149159488, 149290688, 149420224, 149551552,
+ 149683136, 149814976, 149943616, 150076352, 150208064, 150338624,
+ 150470464, 150600256, 150732224, 150862784, 150993088, 151125952,
+ 151254976, 151388096, 151519168, 151649728, 151778752, 151911104,
+ 152042944, 152174144, 152304704, 152435648, 152567488, 152698816,
+ 152828992, 152960576, 153091648, 153222976, 153353792, 153484096,
+ 153616192, 153747008, 153878336, 154008256, 154139968, 154270912,
+ 154402624, 154533824, 154663616, 154795712, 154926272, 155057984,
+ 155188928, 155319872, 155450816, 155580608, 155712064, 155843392,
+ 155971136, 156106688, 156237376, 156367424, 156499264, 156630976,
+ 156761536, 156892352, 157024064, 157155008, 157284416, 157415872,
+ 157545536, 157677248, 157810496, 157938112, 158071744, 158203328,
+ 158334656, 158464832, 158596288, 158727616, 158858048, 158988992,
+ 159121216, 159252416, 159381568, 159513152, 159645632, 159776192,
+ 159906496, 160038464, 160169536, 160300352, 160430656, 160563008,
+ 160693952, 160822208, 160956352, 161086784, 161217344, 161349184,
+ 161480512, 161611456, 161742272, 161873216, 162002752, 162135872,
+ 162266432, 162397888, 162529216, 162660032, 162790976, 162922048,
+ 163052096, 163184576, 163314752, 163446592, 163577408, 163707968,
+ 163839296, 163969984, 164100928, 164233024, 164364224, 164494912,
+ 164625856, 164756672, 164887616, 165019072, 165150016, 165280064,
+ 165412672, 165543104, 165674944, 165805888, 165936832, 166067648,
+ 166198336, 166330048, 166461248, 166591552, 166722496, 166854208,
+ 166985408, 167116736, 167246656, 167378368, 167508416, 167641024,
+ 167771584, 167903168, 168034112, 168164032, 168295744, 168427456,
+ 168557632, 168688448, 168819136, 168951616, 169082176, 169213504,
+ 169344832, 169475648, 169605952, 169738048, 169866304, 169999552,
+ 170131264, 170262464, 170393536, 170524352, 170655424, 170782016,
+ 170917696, 171048896, 171179072, 171310784, 171439936, 171573184,
+ 171702976, 171835072, 171966272, 172097216, 172228288, 172359232,
+ 172489664, 172621376, 172747712, 172883264, 173014208, 173144512,
+ 173275072, 173407424, 173539136, 173669696, 173800768, 173931712,
+ 174063424, 174193472, 174325696, 174455744, 174586816, 174718912,
+ 174849728, 174977728, 175109696, 175242688, 175374272, 175504832,
+ 175636288, 175765696, 175898432, 176028992, 176159936, 176291264,
+ 176422592, 176552512, 176684864, 176815424, 176946496, 177076544,
+ 177209152, 177340096, 177470528, 177600704, 177731648, 177864256,
+ 177994816, 178126528, 178257472, 178387648, 178518464, 178650176,
+ 178781888, 178912064, 179044288, 179174848, 179305024, 179436736,
+ 179568448, 179698496, 179830208, 179960512, 180092608, 180223808,
+ 180354752, 180485696, 180617152, 180748096, 180877504, 181009984,
+ 181139264, 181272512, 181402688, 181532608, 181663168, 181795136,
+ 181926592, 182057536, 182190016, 182320192, 182451904, 182582336,
+ 182713792, 182843072, 182976064, 183107264, 183237056, 183368384,
+ 183494848, 183631424, 183762752, 183893824, 184024768, 184154816,
+ 184286656, 184417984, 184548928, 184680128, 184810816, 184941248,
+ 185072704, 185203904, 185335616, 185465408, 185596352, 185727296,
+ 185859904, 185989696, 186121664, 186252992, 186383552, 186514112,
+ 186645952, 186777152, 186907328, 187037504, 187170112, 187301824,
+ 187429184, 187562048, 187693504, 187825472, 187957184, 188087104,
+ 188218304, 188349376, 188481344, 188609728, 188743616, 188874304,
+ 189005248, 189136448, 189265088, 189396544, 189528128, 189660992,
+ 189791936, 189923264, 190054208, 190182848, 190315072, 190447424,
+ 190577984, 190709312, 190840768, 190971328, 191102656, 191233472,
+ 191364032, 191495872, 191626816, 191758016, 191888192, 192020288,
+ 192148928, 192282176, 192413504, 192542528, 192674752, 192805952,
+ 192937792, 193068608, 193198912, 193330496, 193462208, 193592384,
+ 193723456, 193854272, 193985984, 194116672, 194247232, 194379712,
+ 194508352, 194641856, 194772544, 194900672, 195035072, 195166016,
+ 195296704, 195428032, 195558592, 195690304, 195818176, 195952576,
+ 196083392, 196214336, 196345792, 196476736, 196607552, 196739008,
+ 196869952, 197000768, 197130688, 197262784, 197394368, 197523904,
+ 197656384, 197787584, 197916608, 198049472, 198180544, 198310208,
+ 198442432, 198573632, 198705088, 198834368, 198967232, 199097792,
+ 199228352, 199360192, 199491392, 199621696, 199751744, 199883968,
+ 200014016, 200146624, 200276672, 200408128, 200540096, 200671168,
+ 200801984, 200933312, 201062464, 201194944, 201326144, 201457472,
+ 201588544, 201719744, 201850816, 201981632, 202111552, 202244032,
+ 202374464, 202505152, 202636352, 202767808, 202898368, 203030336,
+ 203159872, 203292608, 203423296, 203553472, 203685824, 203816896,
+ 203947712, 204078272, 204208192, 204341056, 204472256, 204603328,
+ 204733888, 204864448, 204996544, 205125568, 205258304, 205388864,
+ 205517632, 205650112, 205782208, 205913536, 206044736, 206176192,
+ 206307008, 206434496, 206569024, 206700224, 206831168, 206961856,
+ 207093056, 207223616, 207355328, 207486784, 207616832, 207749056,
+ 207879104, 208010048, 208141888, 208273216, 208404032, 208534336,
+ 208666048, 208796864, 208927424, 209059264, 209189824, 209321792,
+ 209451584, 209582656, 209715136, 209845568, 209976896, 210106432,
+ 210239296, 210370112, 210501568, 210630976, 210763712, 210894272,
+ 211024832, 211156672, 211287616, 211418176, 211549376, 211679296,
+ 211812032, 211942592, 212074432, 212204864, 212334016, 212467648,
+ 212597824, 212727616, 212860352, 212991424, 213120832, 213253952,
+ 213385024, 213515584, 213645632, 213777728, 213909184, 214040128,
+ 214170688, 214302656, 214433728, 214564544, 214695232, 214826048,
+ 214956992, 215089088, 215219776, 215350592, 215482304, 215613248,
+ 215743552, 215874752, 216005312, 216137024, 216267328, 216399296,
+ 216530752, 216661696, 216790592, 216923968, 217054528, 217183168,
+ 217316672, 217448128, 217579072, 217709504, 217838912, 217972672,
+ 218102848, 218233024, 218364736, 218496832, 218627776, 218759104,
+ 218888896, 219021248, 219151936, 219281728, 219413056, 219545024,
+ 219675968, 219807296, 219938624, 220069312, 220200128, 220331456,
+ 220461632, 220592704, 220725184, 220855744, 220987072, 221117888,
+ 221249216, 221378368, 221510336, 221642048, 221772736, 221904832,
+ 222031808, 222166976, 222297536, 222428992, 222559936, 222690368,
+ 222820672, 222953152, 223083968, 223213376, 223345984, 223476928,
+ 223608512, 223738688, 223869376, 224001472, 224132672, 224262848,
+ 224394944, 224524864, 224657344, 224788288, 224919488, 225050432,
+ 225181504, 225312704, 225443776, 225574592, 225704768, 225834176,
+ 225966784, 226097216, 226229824, 226360384, 226491712, 226623424,
+ 226754368, 226885312, 227015104, 227147456, 227278528, 227409472,
+ 227539904, 227669696, 227802944, 227932352, 228065216, 228196288,
+ 228326464, 228457792, 228588736, 228720064, 228850112, 228981056,
+ 229113152, 229243328, 229375936, 229505344, 229636928, 229769152,
+ 229894976, 230030272, 230162368, 230292416, 230424512, 230553152,
+ 230684864, 230816704, 230948416, 231079616, 231210944, 231342016,
+ 231472448, 231603776, 231733952, 231866176, 231996736, 232127296,
+ 232259392, 232388672, 232521664, 232652608, 232782272, 232914496,
+ 233043904, 233175616, 233306816, 233438528, 233569984, 233699776,
+ 233830592, 233962688, 234092224, 234221888, 234353984, 234485312,
+ 234618304, 234749888, 234880832, 235011776, 235142464, 235274048,
+ 235403456, 235535936, 235667392, 235797568, 235928768, 236057152,
+ 236190272, 236322752, 236453312, 236583616, 236715712, 236846528,
+ 236976448, 237108544, 237239104, 237371072, 237501632, 237630784,
+ 237764416, 237895232, 238026688, 238157632, 238286912, 238419392,
+ 238548032, 238681024, 238812608, 238941632, 239075008, 239206336,
+ 239335232, 239466944, 239599168, 239730496, 239861312, 239992384,
+ 240122816, 240254656, 240385856, 240516928, 240647872, 240779072,
+ 240909632, 241040704, 241171904, 241302848, 241433408, 241565248,
+ 241696192, 241825984, 241958848, 242088256, 242220224, 242352064,
+ 242481856, 242611648, 242744896, 242876224, 243005632, 243138496,
+ 243268672, 243400384, 243531712, 243662656, 243793856, 243924544,
+ 244054592, 244187072, 244316608, 244448704, 244580032, 244710976,
+ 244841536, 244972864, 245104448, 245233984, 245365312, 245497792,
+ 245628736, 245759936, 245889856, 246021056, 246152512, 246284224,
+ 246415168, 246545344, 246675904, 246808384, 246939584, 247070144,
+ 247199552, 247331648, 247463872, 247593536, 247726016, 247857088,
+ 247987648, 248116928, 248249536, 248380736, 248512064, 248643008,
+ 248773312, 248901056, 249036608, 249167552, 249298624, 249429184,
+ 249560512, 249692096, 249822784, 249954112, 250085312, 250215488,
+ 250345792, 250478528, 250608704, 250739264, 250870976, 251002816,
+ 251133632, 251263552, 251395136, 251523904, 251657792, 251789248,
+ 251919424, 252051392, 252182464, 252313408, 252444224, 252575552,
+ 252706624, 252836032, 252968512, 253099712, 253227584, 253361728,
+ 253493056, 253623488, 253754432, 253885504, 254017216, 254148032,
+ 254279488, 254410432, 254541376, 254672576, 254803264, 254933824,
+ 255065792, 255196736, 255326528, 255458752, 255589952, 255721408,
+ 255851072, 255983296, 256114624, 256244416, 256374208, 256507712,
+ 256636096, 256768832, 256900544, 257031616, 257162176, 257294272,
+ 257424448, 257555776, 257686976, 257818432, 257949632, 258079552,
+ 258211136, 258342464, 258473408, 258603712, 258734656, 258867008,
+ 258996544, 259127744, 259260224, 259391296, 259522112, 259651904,
+ 259784384, 259915328, 260045888, 260175424, 260308544, 260438336,
+ 260570944, 260700992, 260832448, 260963776, 261092672, 261226304,
+ 261356864, 261487936, 261619648, 261750592, 261879872, 262011968,
+ 262143424, 262274752, 262404416, 262537024, 262667968, 262799296,
+ 262928704, 263061184, 263191744, 263322944, 263454656, 263585216,
+ 263716672, 263847872, 263978944, 264108608, 264241088, 264371648,
+ 264501184, 264632768, 264764096, 264895936, 265024576, 265158464,
+ 265287488, 265418432, 265550528, 265681216, 265813312, 265943488,
+ 266075968, 266206144, 266337728, 266468032, 266600384, 266731072,
+ 266862272, 266993344, 267124288, 267255616, 267386432, 267516992,
+ 267648704, 267777728, 267910592, 268040512, 268172096, 268302784,
+ 268435264, 268566208, 268696256, 268828096, 268959296, 269090368,
+ 269221312, 269352256, 269482688, 269614784, 269745856, 269876416,
+ 270007616, 270139328, 270270272, 270401216, 270531904, 270663616,
+ 270791744, 270924736, 271056832, 271186112, 271317184, 271449536,
+ 271580992, 271711936, 271843136, 271973056, 272105408, 272236352,
+ 272367296, 272498368, 272629568, 272759488, 272891456, 273022784,
+ 273153856, 273284672, 273415616, 273547072, 273677632, 273808448,
+ 273937088, 274071488, 274200896, 274332992, 274463296, 274595392,
+ 274726208, 274857536, 274988992, 275118656, 275250496, 275382208,
+ 275513024, 275643968, 275775296, 275906368, 276037184, 276167872,
+ 276297664, 276429376, 276560576, 276692672, 276822976, 276955072,
+ 277085632, 277216832, 277347008, 277478848, 277609664, 277740992,
+ 277868608, 278002624, 278134336, 278265536, 278395328, 278526784,
+ 278657728, 278789824, 278921152, 279052096, 279182912, 279313088,
+ 279443776, 279576256, 279706048, 279838528, 279969728, 280099648,
+ 280230976, 280361408, 280493632, 280622528, 280755392, 280887104,
+ 281018176, 281147968, 281278912, 281411392, 281542592, 281673152,
+ 281803712, 281935552, 282066496, 282197312, 282329024, 282458816,
+ 282590272, 282720832, 282853184, 282983744, 283115072, 283246144,
+ 283377344, 283508416, 283639744, 283770304, 283901504, 284032576,
+ 284163136, 284294848, 284426176, 284556992, 284687296, 284819264,
+ 284950208, 285081536}
diff --git a/pow/ethash_algo_go1.7.go b/pow/ethash_algo_go1.7.go
new file mode 100644
index 0000000000..ce05b3bb08
--- /dev/null
+++ b/pow/ethash_algo_go1.7.go
@@ -0,0 +1,47 @@
+// Copyright 2017 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+// +build !go1.8
+
+package pow
+
+// cacheSize calculates and returns the size of the ethash verification cache that
+// belongs to a certain block number. The cache size grows linearly, however, we
+// always take the highest prime below the linearly growing threshold in order to
+// reduce the risk of accidental regularities leading to cyclic behavior.
+func cacheSize(block uint64) uint64 {
+ // If we have a pre-generated value, use that
+ epoch := int(block / epochLength)
+ if epoch < len(cacheSizes) {
+ return cacheSizes[epoch]
+ }
+ // We don't have a way to verify primes fast before Go 1.8
+ panic("fast prime testing unsupported in Go < 1.8")
+}
+
+// datasetSize calculates and returns the size of the ethash mining dataset that
+// belongs to a certain block number. The dataset size grows linearly, however, we
+// always take the highest prime below the linearly growing threshold in order to
+// reduce the risk of accidental regularities leading to cyclic behavior.
+func datasetSize(block uint64) uint64 {
+ // If we have a pre-generated value, use that
+ epoch := int(block / epochLength)
+ if epoch < len(datasetSizes) {
+ return datasetSizes[epoch]
+ }
+ // We don't have a way to verify primes fast before Go 1.8
+ panic("fast prime testing unsupported in Go < 1.8")
+}
diff --git a/pow/ethash_algo_go1.8.go b/pow/ethash_algo_go1.8.go
new file mode 100644
index 0000000000..cac96cd5e9
--- /dev/null
+++ b/pow/ethash_algo_go1.8.go
@@ -0,0 +1,57 @@
+// Copyright 2017 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+// +build go1.8
+
+package pow
+
+import "math/big"
+
+// cacheSize calculates and returns the size of the ethash verification cache that
+// belongs to a certain block number. The cache size grows linearly, however, we
+// always take the highest prime below the linearly growing threshold in order to
+// reduce the risk of accidental regularities leading to cyclic behavior.
+func cacheSize(block uint64) uint64 {
+ // If we have a pre-generated value, use that
+ epoch := int(block / epochLength)
+ if epoch < len(cacheSizes) {
+ return cacheSizes[epoch]
+ }
+ // No known cache size, calculate manually (sanity branch only)
+ size := uint64(cacheInitBytes + cacheGrowthBytes*uint64(epoch) - hashBytes)
+ for !new(big.Int).SetUint64(size / hashBytes).ProbablyPrime(1) { // Always accurate for n < 2^64
+ size -= 2 * hashBytes
+ }
+ return size
+}
+
+// datasetSize calculates and returns the size of the ethash mining dataset that
+// belongs to a certain block number. The dataset size grows linearly, however, we
+// always take the highest prime below the linearly growing threshold in order to
+// reduce the risk of accidental regularities leading to cyclic behavior.
+func datasetSize(block uint64) uint64 {
+ // If we have a pre-generated value, use that
+ epoch := int(block / epochLength)
+ if epoch < len(datasetSizes) {
+ return datasetSizes[epoch]
+ }
+ // No known dataset size, calculate manually (sanity branch only)
+ size := uint64(datasetInitBytes + datasetGrowthBytes*uint64(epoch) - mixBytes)
+ for !new(big.Int).SetUint64(size / mixBytes).ProbablyPrime(1) { // Always accurate for n < 2^64
+ size -= 2 * mixBytes
+ }
+ return size
+}
diff --git a/pow/ethash_algo_go1.8_test.go b/pow/ethash_algo_go1.8_test.go
new file mode 100644
index 0000000000..57e0b0b7a2
--- /dev/null
+++ b/pow/ethash_algo_go1.8_test.go
@@ -0,0 +1,46 @@
+// Copyright 2017 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+// +build go1.8
+
+package pow
+
+import "testing"
+
+// Tests whether the dataset size calculator work correctly by cross checking the
+// hard coded lookup table with the value generated by it.
+func TestSizeCalculations(t *testing.T) {
+ var tests []uint64
+
+ // Verify all the cache sizes from the lookup table
+ defer func(sizes []uint64) { cacheSizes = sizes }(cacheSizes)
+ tests, cacheSizes = cacheSizes, []uint64{}
+
+ for i, test := range tests {
+ if size := cacheSize(uint64(i*epochLength) + 1); size != test {
+ t.Errorf("cache %d: cache size mismatch: have %d, want %d", i, size, test)
+ }
+ }
+ // Verify all the dataset sizes from the lookup table
+ defer func(sizes []uint64) { datasetSizes = sizes }(datasetSizes)
+ tests, datasetSizes = datasetSizes, []uint64{}
+
+ for i, test := range tests {
+ if size := datasetSize(uint64(i*epochLength) + 1); size != test {
+ t.Errorf("dataset %d: dataset size mismatch: have %d, want %d", i, size, test)
+ }
+ }
+}
diff --git a/pow/ethash_algo_test.go b/pow/ethash_algo_test.go
new file mode 100644
index 0000000000..0605d70ad7
--- /dev/null
+++ b/pow/ethash_algo_test.go
@@ -0,0 +1,774 @@
+// Copyright 2017 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+package pow
+
+import (
+ "bytes"
+ "io/ioutil"
+ "math/big"
+ "os"
+ "reflect"
+ "sync"
+ "testing"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/common/hexutil"
+ "github.com/ethereum/go-ethereum/core/types"
+)
+
+// Tests that verification caches can be correctly generated.
+func TestCacheGeneration(t *testing.T) {
+ tests := []struct {
+ size uint64
+ epoch uint64
+ cache []byte
+ }{
+ {
+ size: 1024,
+ epoch: 0,
+ cache: hexutil.MustDecode("0x" +
+ "7ce2991c951f7bf4c4c1bb119887ee07871eb5339d7b97b8588e85c742de90e5bafd5bbe6ce93a134fb6be9ad3e30db99d9528a2ea7846833f52e9ca119b6b54" +
+ "8979480c46e19972bd0738779c932c1b43e665a2fd3122fc3ddb2691f353ceb0ed3e38b8f51fd55b6940290743563c9f8fa8822e611924657501a12aafab8a8d" +
+ "88fb5fbae3a99d14792406672e783a06940a42799b1c38bc28715db6d37cb11f9f6b24e386dc52dd8c286bd8c36fa813dffe4448a9f56ebcbeea866b42f68d22" +
+ "6c32aae4d695a23cab28fd74af53b0c2efcc180ceaaccc0b2e280103d097a03c1d1b0f0f26ce5f32a90238f9bc49f645db001ef9cd3d13d44743f841fad11a37" +
+ "fa290c62c16042f703578921f30b9951465aae2af4a5dad43a7341d7b4a62750954965a47a1c3af638dc3495c4d62a9bab843168c9fc0114e79cffd1b2827b01" +
+ "75d30ba054658f214e946cf24c43b40d3383fbb0493408e5c5392434ca21bbcf43200dfb876c713d201813934fa485f48767c5915745cf0986b1dc0f33e57748" +
+ "bf483ee2aff4248dfe461ec0504a13628401020fc22638584a8f2f5206a13b2f233898c78359b21c8226024d0a7a93df5eb6c282bdbf005a4aab497e096f2847" +
+ "76c71cee57932a8fb89f6d6b8743b60a4ea374899a94a2e0f218d5c55818cefb1790c8529a76dba31ebb0f4592d709b49587d2317970d39c086f18dd244291d9" +
+ "eedb16705e53e3350591bd4ff4566a3595ac0f0ce24b5e112a3d033bc51b6fea0a92296dea7f5e20bf6ee6bc347d868fda193c395b9bb147e55e5a9f67cfe741" +
+ "7eea7d699b155bd13804204df7ea91fa9249e4474dddf35188f77019c67d201e4c10d7079c5ad492a71afff9a23ca7e900ba7d1bdeaf3270514d8eb35eab8a0a" +
+ "718bb7273aeb37768fa589ed8ab01fbf4027f4ebdbbae128d21e485f061c20183a9bc2e31edbda0727442e9d58eb0fe198440fe199e02e77c0f7b99973f1f74c" +
+ "c9089a51ab96c94a84d66e6aa48b2d0a4543adb5a789039a2aa7b335ca85c91026c7d3c894da53ae364188c3fd92f78e01d080399884a47385aa792e38150cda" +
+ "a8620b2ebeca41fbc773bb837b5e724d6eb2de570d99858df0d7d97067fb8103b21757873b735097b35d3bea8fd1c359a9e8a63c1540c76c9784cf8d975e995c" +
+ "778401b94a2e66e6993ad67ad3ecdc2acb17779f1ea8606827ec92b11c728f8c3b6d3f04a3e6ed05ff81dd76d5dc5695a50377bc135aaf1671cf68b750315493" +
+ "6c64510164d53312bf3c41740c7a237b05faf4a191bd8a95dafa068dbcf370255c725900ce5c934f36feadcfe55b687c440574c1f06f39d207a8553d39156a24" +
+ "845f64fd8324bb85312979dead74f764c9677aab89801ad4f927f1c00f12e28f22422bb44200d1969d9ab377dd6b099dc6dbc3222e9321b2c1e84f8e2f07731c"),
+ },
+ {
+ size: 1024,
+ epoch: 1,
+ cache: hexutil.MustDecode("0x" +
+ "1f56855d59cc5a085720899b4377a0198f1abe948d85fe5820dc0e346b7c0931b9cde8e541d751de3b2b3275d0aabfae316209d5879297d8bd99f8a033c9d4df" +
+ "35add1029f4e6404a022d504fb8023e42989aba985a65933b0109c7218854356f9284983c9e7de97de591828ae348b63d1fc78d8db58157344d4e06530ffd422" +
+ "5c7f6080d451ff94961ec2dd9e28e6d81b49102451676dbdcb6ef1094c1e8b29e7e808d47b2ba5aeb52dabf00d5f0ee08c116289cbf56d8132e5ca557c3d6220" +
+ "5ba3a48539acabfd4ca3c89e3aaa668e24ffeaeb9eb0136a9fc5a8a676b6d5ad76175eeda0a1fa44b5ff5591079e4b7f581569b6c82416adcb82d7e92980df67" +
+ "2248c4024013e7be52cf91a82491627d9e6d80eda2770ab82badc5e120cd33a4c84495f718b57396a8f397e797087fad81fa50f0e2f5da71e40816a85de35a96" +
+ "3cd351364905c45b3116ff25851d43a2ca1d2aa5cdb408440dabef8c57778fc18608bf431d0c7ffd37649a21a7bb9d90def39c821669dbaf165c0262434dfb08" +
+ "5d057a12de4a7a59fd2dfc931c29c20371abf748b69b618a9bd485b3fb3166cad4d3d27edf0197aabeceb28b96670bdf020f26d1bb9b564aaf82d866bdffd6d4" +
+ "1aea89e20b15a5d1264ab01d1556bfc2a266081609d60928216bd9646038f07de9fedcc9f2b86ab1b07d7bd88ba1df08b3d89b2ac789001b48a723f217debcb7" +
+ "090303a3ef50c1d5d99a75c640ec2b401ab149e06511753d8c49cafdde2929ae61e09cc0f0319d262869d21ead9e0cf5ff2de3dbedfb994f32432d2e4aa44c82" +
+ "7c42781d1477fe03ea0772998e776d63363c6c3edd2d52c89b4d2c9d89cdd90fa33b2b41c8e3f78ef06fe90bcf5cc5756d33a032f16b744141aaa8852bb4cb3a" +
+ "40792b93489c6d6e56c235ec4aa36c263e9b766a4daaff34b2ea709f9f811aef498a65bfbc1deffd36fcc4d1a123345fac7bf57a1fb50394843cd28976a6c7ff" +
+ "fe70f7b8d8f384aa06e2c9964c92a8788cef397fffdd35181b42a35d5d98cd7244bbd09e802888d7efc0311ae58e0961e3656205df4bdc553f317df4b6ede4ca" +
+ "846294a32aec830ab1aa5aac4e78b821c35c70fd752fec353e373bf9be656e775a0111bcbeffdfebd3bd5251d27b9f6971aa561a2bd27a99d61b2ce3965c3726" +
+ "1e114353e6a31b09340f4078b8a8c6ce6ff4213067a8f21020f78aff4f8b472b701ef730aacb8ce7806ea31b14abe8f8efdd6357ca299d339abc4e43ba324ad1" +
+ "efe6eb1a5a6e137daa6ec9f6be30931ca368a944cfcf2a0a29f9a9664188f0466e6f078c347f9fe26a9a89d2029462b19245f24ace47aecace6ef85a4e96b31b" +
+ "5f470eb0165c6375eb8f245d50a25d521d1e569e3b2dccce626752bb26eae624a24511e831a81fab6898a791579f462574ca4851e6588116493dbccc3072e0c5"),
+ },
+ }
+ for i, tt := range tests {
+ cache := make([]uint32, tt.size/4)
+ generateCache(cache, tt.epoch, seedHash(tt.epoch*epochLength+1))
+
+ want := make([]uint32, tt.size/4)
+ prepare(want, tt.cache)
+
+ if !reflect.DeepEqual(cache, want) {
+ t.Errorf("cache %d: content mismatch: have %x, want %x", i, cache, want)
+ }
+ }
+}
+
+func TestDatasetGeneration(t *testing.T) {
+ tests := []struct {
+ epoch uint64
+ cacheSize uint64
+ datasetSize uint64
+ dataset []byte
+ }{
+ {
+ epoch: 0,
+ cacheSize: 1024,
+ datasetSize: 32 * 1024,
+ dataset: hexutil.MustDecode("0x" +
+ "4bc09fbd530a041dd2ec296110a29e8f130f179c59d223f51ecce3126e8b0c74326abc2f32ccd9d7f976bd0944e3ccf8479db39343cbbffa467046ca97e2da63" +
+ "da5f9d9688c7c33ab7b8aace570e422fa48b24659b72fc534669209d66389ca15b099c5604601e7581488e3bd6925cec0f12d465f8004d4fa84793f8e1e46a1b" +
+ "31b7298991c6142f4f0b6e6b296728ae5fa63ccb667b61fbb1b078003d18d97b906af157debed5e6c55d5a61cae90c85f9e97d565314a2f9fd9e0c08430547d0" +
+ "7cfcee3271f921b95c32a11596219abaa30abc62c2c72c6725078c436c677320594df6bcb92134c1b114fffec982a1f68f13a9f812f074b9fb9c78f2cd4c1c90" +
+ "7ebf1e447f7a422b06303921e3d54f430584d849eaa4b7d652e92a5d659bdfc462adcdd7991e8c66a19da4ddb5390463d073941491859397f135ebbbdbdf5801" +
+ "cafb873c383893390141ae385515504d74a33608273310c312ba468046d2e20c271a38cc0e3920b39705050e752f34f244fc23ddd17ff18677756a87671d4145" +
+ "3aebf97e4890da1d645f41eb20da92a8537c787ce419580073c46aa3bb154952993142ec5b4fb6e8f108fd15fc618cd5c27b45a37ee6dcd52a4ce656c0f58604" +
+ "717ec55f5e592355f1f20e8316f8fd77243734a8b0f50ad93c1d95b5b0482afb22cd0667d935bd6053d7198b54974e10d100df7ca3ec2e0bb5ccce5807b266e0" +
+ "8429d5fec2ae6ae1cc7c5efc27f19c89d4b4a6c5c0b9397886dac635ba37446ff528b582457a4fe7f803f1a47903574f8982d4a679b627396a4e97aaa12fa179" +
+ "0d31ba52e9010bc3c26ace81f702f86649fe9eeda9ec03b74a8a5cf540d82e22af33ab893564397dfc4edd8b1677350df5b82ab61d24db95f58fd2d78afb49c7" +
+ "2d2b1fefa8ff6606b8623829cc752ea37d663b945f3f1d48ad07b1416af252f81b55acd8f164da4faa9d9453721b3b795041ce7df7c77edc13865dbe04fee331" +
+ "47daebe18c183c4a6594a6df3a4d2dc5e3811d805102c9c49286e3d12b38927fa49a7b0cdcb1d799f57118953e31c560aae213a1799d59a78ae68f0590347061" +
+ "fc2668caf08f860452f6b7d3ebc1efecc2e1227d33296b1f1850360dee7236e85274eaede4d18a58b4261ce1f6a7d283dcf64e6d021813f82a566354445327e5" +
+ "6217279b2393fe5aa0f9eb149d4866e1105106bcc221810ceaf053f2ec733d8a22f409c1baf955e50184005c5d55de907de97f5f713b62ae10937e1a7af6267b" +
+ "d2a239e8589017197c343b81540bc26bc52bffd5336fb1da1202a511c7175014d2f500b9d9ce78e4b9f2b158d0fb27af352b6f78c129cad642fe909612c9d658" +
+ "17a8d7f9195ee97201675a918e3cf520fdc19f92b7e6a3db806d4f3799361334082cc58a22ddb4e4f5760bd1667c177b26be325166c6bbed669a158fc87acd43" +
+ "a2462e12578d72db6606f9e24ae659ff411ac9b31d696b8354fd08a591622967a14f8468eaaae3907b7818154ba2d6e4581589354d178bb6ae1c03651c44bbf0" +
+ "e7fa52cb0da09508b5a444aed05a54f416841247a4fe36bd5529029e3adf78b105e22468ed775f4d0954504dd55f2c9b9e6b3a086370b2c0b6fec7efd6914e07" +
+ "26627edb7a04869a874e31f448271077a7de3031cf81bdbc39848efee6075e0d65fa3a32640e9f0395cf7ec12139992aff0a54e0a7dfe5048b3cc03246b56f7d" +
+ "3093538a7b87538d8792a665bc589373621b2f3cf47d2c1f8f580fe34d79c6b2a66323ce89808ce0e5cf77700f5a4446c4be01a310e8f7c7ebefe756b0044886" +
+ "a0477c88ee8ea8c71503748a4cf9eb40ad5c1c8accf7c63c0f43a94ed2b8a5999df3ab9b11b80de73310e036ca88668e640015fcf9cd18eed05517d54896f43e" +
+ "25e7931b44872c4e4183500e0e8c5103292bca1c0d6b0b00c9acce25d31204bb3e4f255c03a0a0916664e9c831b28b364078109a74411a11afb1e610c7d1c9d4" +
+ "ba5e10d0ee0da409654d9e7308395e17caeb9caebccb0192679866e6f2ecb5f10044333bb70d61712adb6d74cdec6918ed9a71d9925da576a1e6f4e906a5cd5f" +
+ "0e94a25e48a4141e4e2770144b63e2449b0f84c82879f34d78440cc430196ba85a213fdac1bcf279a46d7592fa29a876bb7a2efb7081365522a3f06fdceaedd3" +
+ "cc0335cef9ea570733fe8799bb1b918aa7732b4d175929d80c7844a78e19f2dc6a6febf648f49b40320b0f7d784e7f84e45408d70b046bd01cbd8fdaf606fcd3" +
+ "02f4e5a48ab8d13e93a246adfcc94f3109e02a7a969986e75b6ced6bf2d11a55ab77488e131b65a06398fa8e384dc90d875584c9b17cdcf2da5dd72a461cd07c" +
+ "4a955c5fe48509b3284476c42247e086de7d63839b7358cf4ebd9edf9ac8b6fd0c096166405de19c51e8785009d30feb67cdb8ff9ba55459dfdffba8c022e26c" +
+ "0ebd399e4b76ccb4d5491a862c2c4d8cdf1461a96c9b98150e170efacec980edc00a2c7f6d7c6bea3075627e1eb386a7f1ede1059da81a4ac5cf35aa173c88c5" +
+ "1818dc0fbc688b68b82ddc225b6c87588e0c680e303e737c82a13e34be58df8b0cb336aeacc698c79e7682ebb69e6cd6bdc5d11790c96afcfa9290f39515142f" +
+ "5f90b938216a1d14bc049ce3f0ac135722208b989d2557d3520c2186479f179e50fe5b125b8d6638a65047729c6249b9b2c6381c9103c97d1b389cc9cdb31c21" +
+ "8a2eecbf4b9ad1dcfa57446cde88f96563a544c49d6f5303a84a1b7cf074fca78e67e72c9ffa0c542fb646418c6434b16b771088140725cf2dc723c1a975c4ca" +
+ "8a80e633721274907353f51e95952c2b403b45750b42ad10961f60473eb54616f61f7b038c5b7eca475d6a2b844994a9eeddce4f7bb49782e50ef78bc13b85d1" +
+ "9e956f47c60823f3d1981413cb78d309f63a844694861b11b5238961c71f61d82daef6795734f0961e92b9167c57f48e91693e9656fcc6e88f9ce2d373da26bf" +
+ "45b3dff50211fec72387005a7e04828e4ae7ddd10fc2332acf5f1b0f67adcd863752573c2d24488857bfc58c41af45be7641f5cfff611f184612fc0d695866f4" +
+ "2b396b1d9881f442c4a995f4b500f02d4ab4b53ad6e01776ab0e244583f01301203a1515f3dbb73906014e36c7143bf882b005f0228ca0562623893c8a24b7c6" +
+ "4c2c561912010c121b5c3a1e35e75c0b094731e9c0d6acf5a2b1e5b179355525a175640579705f898feb98bffa25633bc126613fa27d2ceb214812902ada23f4" +
+ "367a78655d0d2276095c9e83dfa79153730103963499c367c5621fecfd0888253df82b3d5716703ef92594cf269310b9e6c892c488edb3bba1d0b216e92f622a" +
+ "7f8f7f00d2926d81a4c7ca6cef40d240576a8d5541ccf561c8e0e699925d20347ba7493ed6e182cfe3b633e70b3ce3a0d90813574f6fe329c495d3cd46fd5d7e" +
+ "bdde58d7eafcb134a9a5d3e5d66136e8c9b5d9ecac195dcc44158941c9fe2d87db52a7ddcedc9f82ec160901cc36a9c877af80ceae0563dfa75cabde5d7a7c94" +
+ "9f24bc190f7c2045368356474ff6eee284e7125d1c5f9a036fbde24cecfd3a30481ce077f20cbcb31924368296abf66ce4834102cf7cb949d1b4c6faa6d006ef" +
+ "21379cead5d5a39324d41555c46e0b42a1e871143e47f8e6b3d794e75d7a43c282732766d856e04e666ea346657b157404b0fc8534a2dee8243d40a5e37609e6" +
+ "18bc1d52b91a7623aaf8214a97e4c8c5d860b31c3792b129354a121a7a7e42b50dfbe3ab6590769401eb280545547a43c3a1455355d5d5fdedccb472abfe75b8" +
+ "f5e7d62b0b31553d8d55de0c3c71e6f5a2abba6fe81e9a42ec1968f235bc4296c1ac5df7430917453384450ab56dafa7c7af764cefa3b0bc861c52ae27692365" +
+ "9d7d9ed7609958884147acca867909a75bb6a2c364debefaf98c7ff70c7f4acb5cdb81100fd79a48c5139f8bbdc6553b509f1eb0f5d5d31886a602cd669b3f9f" +
+ "59195a1fa2bcff1170003ba1b2e5e9ad7f2bfcd0573d0f2be9d8fc1773c3a63a2b9292cdbf9b4515c0b1d51772e5ee95303ff493d85314c989e269df4ec3a916" +
+ "40988a11c6a4ad96f7d0541a150edf444c2b1672aa6d37564453b835c2d39864c05c4366492fc9164bf73795410e7aae8206430403357fec6389142b4976b218" +
+ "d70622b4098e322f73020a0d045f07668d1e512c6eeed6e2befbfc3a6ac64054396df96fd41f7aeefa0ab1f66bb52ee1a1df066f365fc43ff0800b0398b621f9" +
+ "a415895268505a81517c44a56dc94e76580fd107dba034bab9f4f4b8a9f881ff34c60c406c47b6d4a998894401006aa88f328393f9cd55a2b4d24db5abbcb05e" +
+ "20d392f3feab3ca12dac475eb3690f2bf9c699d7d90900d9a840068c8cdda2ca7a27bebd685a26eb01a768259a65ab4d7efc1811c87a5a1f4e5038f6b3dc74a6" +
+ "b46d9ac58d31bfc22dac23645aeef819329c9419326f22e1c24c53457baf62ae9b92ab5f999d4ef0ccfb5a21b7598340eb2d399ec81588b6a674c5a1e45aa238" +
+ "c55cae8e1af0f5d64ea378b8afeab263a3a2e5c71cdda4cdb824ae55df2b0260aadf386275ef57781d46f6da3d0b300ea68c14a620c25b5df738c54aef04d63b" +
+ "7dee06cd225e9ed00e78abcddca5a133d8b5e0d9b287e6436014c5da729442239bddb7ecd3fe34e6f6e530134a03ef45de4ae4fe3bf507f16cdfb9bab1fc90e8" +
+ "dc565e4a7ead95352c5a894661e5d82c6d0fc47843d5cab12c4013db76c90734cbff34c73d0d873ac9b27b417665f4948469865f33179624860604a9aba2ceb1" +
+ "68e74b6af3d1ad0bfcac4180ea844339a034b6b2c3e2f61f0c7afbaa76c1ebe93727df1d3db27d59a5cf51b2baaf637b6eb8a20302ef9af0b25dbe3a5e74331c" +
+ "6b0c8a0cf2a2ad72d2e19797983e09468ea95270dc229f2fa084dd2aa96e722016504f6d82508572d9c30711c3ef41ae3ae2f36cc6f5dddbcb0b40d9499b24c5" +
+ "4cd36d2927a6b9d57e335e4fca7f0f16887711a8c1ffa0b48bda46c506ca444b7c23e2c8dd086c2a87283d5fc0d58e9a384106837318dc84ffe65b52d4cb9141" +
+ "2672adfe139c3327350fe3cf355a08c0ca43598a253833e114243c5253077d65643323f5d69b3c7902d91bab7a0928754e7d80afab8d48539fcbe0d9ab83b4db" +
+ "43a6594c4071df2ef35acd1f53006a570f09104f1776b26a303e2aec93a00d2fd8c952d1ca0e54504cd9b469be7c1e71557ec31467ecc773ee817b17c4418712" +
+ "163ae86646b20b80c85860e828c48e88f1309c9ff018e6a95f4c1178de6a4f9f5860039511845da7d8727b5d824ba2502d0a3d76ce74372db77c2050c728dd65" +
+ "b3a15da4f1e1e41c3c2acfebc5618e5e923d503c43a3421d2628ac037c5ce13c74c4ee14d47af02323872f6bf2e8bf09d017ea6e8ec4d3f9fc4fb203ac4e1663" +
+ "756b11629224c676713a42b1f43dfd6362876be1c4865928688765589e26c8dd8bc04ca18d76ced7f786cdb0fa5028ae53991d5b7b45f93bbd50aeb97300f04e" +
+ "69c6736f270907f6a7ad76dde0a365183a961bc8385511e0f22ce0cb8f3c42c5d3928621841e30285fb625294865409267dbb0cf91730ba2fb1088fb79789a54" +
+ "a856311bdca5b0ac0e95fbc79b11c561dc03ea82db182808031e86ec327097143ee761bb62dae8a9f4101fabcac1fc87b3c2080820582dc8a7a8287364550013" +
+ "08053c781b3eb279c89e817fe97103b6930fef2dbf7728def389403a4283f63ec04ae953784b749f0ea6f08749781cd17fadfd15bb197afd2f4e0a8aade2b1ad" +
+ "5100cbdce49ed59658993c00e06bf57c0026b97beadc30cd25f586ff03ab40fcd731535c9a1ccb2c99dc7f8815feab767e1237cb069981f28d8fe26bdec24218" +
+ "488e6086c0ab0efc5d4211fa0726b3a11387df9bb62b863a7b154ca390a268f5e49f50dec45d24bece2a06575cc07a24bfff017d7445024739efb050ace5f345" +
+ "98dacda843d4ef5bfb2c931dc16ee3dd8b61a6f01d9a7de8bbb6d89ca8695f8ef8bd1cc6e0455848fac7691e6789218790270aef40fba114557fd88ff74fe8fc" +
+ "476d9b9665d7e45582540710ce92c8dcad1ad8c05642a23a0d58c02db37ae1a0e70fbc5f71b1300fe398c74cbad37fd57379f58dd3e2d3de6860a17acf3c9321" +
+ "02eb4f9d596497bd849c5bfaf59a83113ef389b6896aa4d4665504a22486299993a9987b2bbdb47d59b3f6ce5d2c9f9ba33b5f0760388ca7f8d8af07c1cd28f5" +
+ "67a417a59ebde4bb9867d4e7b7b79dd8665602c029e9a16a7718efde3d034f13f7f0b9af1702c335893526cb87afc2100e874b25c37fd666bf34bf6a653c7cf5" +
+ "44e1fe0286a6723c7d33461dea380b392dad68f79a78fe1b785d7833ca0d1cd68cff472991a625e3099f3ad2cdc99bd37eae35353cecf424098389dbaf1885fd" +
+ "7db54909a92ee879609eb2e9ef4de1f4338f0df53dbde486ede944ae69869fac701d4f1f48c83757b470ea28c9de2ae5f1ef5d1c91118d16ca0d80b1baf3d314" +
+ "056949df27a09eff70c9ac50b54feff67a165ce5e22ba2222defedc7c39e02356c3553e97524c1506441527da4f5de121142ccd494f83114b3ca2dc37e15c752" +
+ "e2faed7d50254124d68f67e26f4f50c9f0edf6e58b916ca830c4e33801dc11039b18292b87b08f4f2edbaaacddcdab78ff3a0004f86034080f2ca4394b14aed4" +
+ "31e38e3605e6b257bd772954d2f4b846a17df7ed6e5dafa33964d9e56a07a19898fb4dfe8b2ddbd11fa0013e6ebc0e429a5166a43d1ec45557cd1fc1bddbec4b" +
+ "2e9ca26395394c96395ff8f557bd0f7f805c09f0c18534585b7c7fc1d07f145372983ad77fa804fbb7765934e72beae0929a87cc6bf7f6c242ff5db2d4d5541c" +
+ "8c366d22e24e1da5379836fc0eb484683285f99f178b98ca170464bdff60ee04584c12c65408102ac6dc7d10bf58a7d770bf1b3c636a48f934f6f4bbdbcc75d3" +
+ "fc551de3ebaf77006707f6120b3804f2bef9b4bd59f5996610c09ba3953994d1b78a9f3bc3bafeb52266f10755ea842e5b4370c937c09afd34a092ff9b98b4d3" +
+ "518bc2480d4b132455b7f03774ad76b83b254742117921c31cebeab5f39c145f7f373a5603d17dd95217ba1af37a0aa95b2992efcd02d0bb4ad08ebafb31440f" +
+ "1ccfce45882b547ee4bf6ec7ecae11ed79fc63b03636c8a14ec4e0f6877eb658d839be2eac0f10a8948e74203f46078ce66aad2764ff05590e2ac7a8dd8b3036" +
+ "901fcb7ff3369ee989a28e34b9b62e1e607d14da3049ded1a4ee50257195eaaef995bed79ec85111abb522aba1fb306869a1ab381e82943f35345bb5502bb90a" +
+ "e2a0af77526a84754ee4d600ba7f8ac98705ee687bab949a081849889d7b83a21a3dd34af84dc2b9458230ef0ff44c6398d3c6e48e5c09c399ac4d4c7b285549" +
+ "e0bcab7fd96de42f072f1cb633e3e250745321049d0d7ecdef4636e70e94c8414e76ecaedd6ee0792e97de11e7dc1e1e1801ad68f9147278e268d7ad76c5bbb7" +
+ "98386fdc13ca8c77569d96e0debba8ea3b751352136c8f1c8d611a69f1baa9aa4b9d0a476ebd5dd21339ef7f97f09aa86b69a7b114cebe17a6b0e58bf52803d6" +
+ "fd47d9eac3a988b51e9bca95c546d49367a3126bf8ee44fbd0e77611473a1d3d2de0ce4ea54f9bb7f9dd0d0c065f613a623fad43a445eba294fd00037492914f" +
+ "b74d10d0b97a0cf9bd3151c3cade89521f36b6fe1aca7f352e79a77d063da5337a7c88d90e9e566bcd97732baa4459305967c2f65adf1a4a4c7991cbc99df3b7" +
+ "14335a107a97a4ab104bc94fecd1d003fe6d2f22e717853c449881c4ccaa7e7a1e44961a14a47a0d0aa1b1493dd02760ff4d31fbddf5941f93c8e5925d1886e2" +
+ "8761baef8610fa6be016c8f4fe65bb0f335152d5e94893e274f2ab90118e4c07957d252963755b4b638ffc0a734fbe6e32c2e304b10a46a4eed330d101c4f0ae" +
+ "011e7f94b89bc0eb9d358a6548b3f0c47ccc3c2d986d381437c49041629c6cbf61bdf0825efe17e4abef128003681450ceeff0e28842895d8e338c247abf81cb" +
+ "7260fd45042c1f6c630a4b195579721392e577fbfdb9f5b003a8b9a6bc15ae754f6255131a0be600c7b07e2cee1ffe32aad4687f9a429998ed9059a99fd879ea" +
+ "c4dcb55f4551bbb70c187cf1b162e2ca4a929edd6ec9260877df652622ae073fc63c0d8522d3882ba888ac50a67a68fb6530193f93165093a1d8132e87d8887e" +
+ "ff2fdab0fbae6ab9506dae61fada4023133d166bcf1956aedc3237c77d1c81dcc84ae957d89367b0fc950c78e58f2cb9c4fd93e16b94421fdecd46c3ff55592e" +
+ "4374a7f7d8ede9923115770cb416071e8f102d4ad78b891464ffd14f589c238c8e13a4e2a81744d179e7d3ae36cffee75ceb99633face85d077d0c15b3970930" +
+ "075dc08b420e0a545200895207c5a746a18ce9ab64a50d3dcf44da857fb65e4efc29b2b4d532dc6a03b699dcfd77030a4945e6431273e25f06ad8f913c2a9eb7" +
+ "59d8d3049868d337e451726d95c4cf8baf381096fc9b62679175dc8f14e52f8b99f212cab6544414c62f17c8323256cce95356dcd351e34c7a1576b17c1406d7" +
+ "5b8bcca8099a1993df1541ded61b876ae83396b191b719c4b1cbe50d73fc13da352d827ba09aa7fdfef3e4e0273c31ef4fd38b93cf64199c3969a7c09dd5e0f3" +
+ "ff93a5a7db9c2c1ec25e3060bcb5481c6802e1eca78f31862842ea08e8f92b8e52856c4c9fedd0bf20e386cfdf926425f7756ff41fd3567c5bf334e96e3f492f" +
+ "74bd0519d8d98efa0b427ba681b8b1be8fab041ff084dc5f8c4d5d48f481115d7e407ad8a6034f481c2be86f8451980c3aa83a3fff245d90d13801a54527e97b" +
+ "e392b25867882d43e3819f4a8aa380db63954ec23d2f0c11a7aa5bc7a3aedc43ecd3b024280ed8843399e28deb954bfc11a3197fb14a9c9a895859e390e9586e" +
+ "2ad21da39bb9ba79a62222d228a0fc96a24e801f00afc3f98d2168a8a253f24deffe461f6313de9b433e1d2e307239c0e3fd5d9fe4c8352c2c6797b1737e93fc" +
+ "14d411bc69bbc9d78cf91734052b8aa1dab348e4c243b8e6d623865c135f807de8d5fd88f3921327affa37066dd538351bc4ec52eece88856de0a424a87d062a" +
+ "f68cf24db37dbaa8e8e96a812fbf32ccafdf1b9d27f11bea23df02143bd09061a881c010819a315a5b6ee44b3c60979b3f7b41f488b2429d49377d6542fb0e22" +
+ "d09a0ef5b81aa7c8134c0aecdc7a4f9228559d0bb826d30fd77fe0f834212647ce61e22fef0a1c10eb4177de81c31c12054a15f81b605619f3045646110673d0" +
+ "b2d79d80577fa43284266fd2ed54f9a3b9df3509f79559c5bc51a58521bfeb2f95d8851527b7ea47b92a694f6ea2b67dc2d4f506d11d2db32c2929cdf5c8816b" +
+ "7f0c310cceb7ede08d5965ed2c7be6c0a317251c7d31cc4a15f6d7976a8a1e6a2f386fe0071d43a50bd0ce5e864a8e449fe9600c6e4a84866879c490de9f9d46" +
+ "3f22708abf34d3e180dbb6005484a6afad373838cdac335f05c034e3090b2fbaaa53fa2db1f96bbe141d570f17363ff98672500e16994b79be74634755b09e66" +
+ "f1b37e338c946bf85e06c97e31dbddf257d58fd10468278648d86f38710c2ca0b6ea7cac4ea0e2c49b96bf1998bde1b3d38aa853736308e12b4a0d467fdb8a73" +
+ "0d810ce45518614bd5845f58a9835a5cfbe745f45ef59ce9a677d10d8c9f6294f1a0565301efb3c6610afda35167150bd326c77057e530c213da63af3e6a600a" +
+ "d87b16ec5cbf76a13764f71b3e7e0c867086ebd9fad02e1d747030064e071a13da4758cd0fa20872b3dc350f4cbfcde1b68a97aca41e32207b40beddec412c0e" +
+ "c75d87c6671ed94bda5170aa2866509161c28d550190675f60139a7b460469f3d4829b3c65f5d185936582629160522fcfdcc53fd0dcc8fc46de11d52bfcc5e6" +
+ "3407ecbbb682cc1693d6543756fa4e068e92ae1a94924a1ff6891361e5f262b7d3c3a3bc2866f54e6d03ebd5479afa3f424077d51668cc60e23b35fb0222ae22" +
+ "5223ba8a8c416b68c8853022d150c951f06f8f85c2078d3035b8ac3ae984ffcfb024431acaae8bfbeb981870f9ad6bbb88d7d5ff34ba21a44cbffd0aeaa435ba" +
+ "7d40d22602e807ac9a69db514ab13248133142cf03fac999a2b185f34d83fdb495ef042d4a5e92f2624193c88858d91c0812b18fd67046cf50635e6ab1ea9ade" +
+ "7b1fe783dc5147f14f9194cfa92c03a0456f4171f9e5c156fee1c607a1e9e06535f2dac49b92ddf5fdacbf88a062bd7ca5439bae645100121e598deee6043baa" +
+ "85cc0d727f08d37a766a55a9ca21ffb6594fb73f9aad15be4a64bafddb6c85d00f7bb5705d9e56b410dd80df8b087b6d67c7ca84eff2ad699f901415fab21343" +
+ "6351a9bdf83b440e29f3950c7e4c49963ab109686d78fce629e9207db2e17eb5f02f01db6441002d72c06c6c6bbcdc0a7443589ba29909a5a78864ad51e1dfda" +
+ "14782d869e4989ac3c5ef0aa1eabe540e9e7cd4e8eabe25b07f300a134a92718186f085d5c10a711ed0e574bf7550f6bccfc3c094d6e59619bde9fd892af8ef2" +
+ "50e1cc3afdcd9c84ccb97344542843028b00064b0c3d18ac0f0703fe6f9683d40813abbb883e164c5797bc1555338566cf8cdd358e9fcb0e93f08f7ae06a5121" +
+ "c67a231106ad8fd42f0798d7185c2de78b8b76c10e82272a405212ce3b904f90236eeea02054953b967cb614e8f8ac49b977152a52df981c86fa4a92f7f70eb6" +
+ "cd4eb65986564039b0d77f8bafedb4fcbf9c34b8fe9c5fa87b0785c118a8624498fb0184a0dbbfb16777579e1964330c12e494449f6aa5cf69ec4a32054be553" +
+ "6027e0d27c7044abd4c0b8e43db703209037efcfd08944647a90a1ab0c71011753354990cac5a472fae44dc370aac8131ebdf31456a8484e7fdefd268cbf5cb5" +
+ "85ac615039d3655b1348fc0b3b078ac41cbcaf6aaedcc1153bb8d55c307f45405ad6a959abb37bf8891c8dec79a9d7ccd9b791cb60361d4a28f33ec0dfd13fa8" +
+ "e0b9b29e14bf36f5047e51a39c2efcefcc156bd08e46c5c1000a3cdc2bb20713e19d6f492c40e51eb93628cf85d07041ae5353e7decc824cbb1db8ab3a7a7fca" +
+ "ff04c2af423bcfb1864ddc864624b827ddcff2a2f8fdb7a3d86d76e72b4f850ec1262d8fc89e7b12e4cc618afe6a2bdf205075c2008f93b7281d80180199409c" +
+ "de850d1f14ca0ff960f69772385cf0f0a0f47cafd5489ea4fd8b68ec7aa539b942379139756c95bb90818842cd43511edbb7577ae469f46728b13a61e6eede06" +
+ "3a4cdfab5ed590feb807d55d76e518d1d74bfa6704f7c8ccc672824b4d5ef5fa5b3ab8fdf2b6c1753404ba35b76aaa931a4e0e5ca7e440524166b23e9a8be9e8" +
+ "635381f6c9086802d428fece81395dada6b3b866e905ec00ccc4fb9b8415dd15e443f84b7220e3b28700ce3d88f9c6df2afea39e0ead537a50ee11f0c247ee86" +
+ "d4b3074e8761de4de611c409c6d4c369c2c11742a7763f6550edfaae49afeec33353a14d2ae60687dbeefd2fe29689da6ae79d7b06042dfd25a68bde9182fba4" +
+ "1ac53706a8b96535057fc2f99ac84a9cfc6549920c3e2cab44e48a08e77207b6a95b2f6179d6dfd6c2d9e3c91106a7a687e40bb2a1c5ccf566c0e31a0fdbd0a4" +
+ "f270f9812208f939efd9698a8b28ce9c5633f18ace7ab0a7550d9e7e26cf62eef49200331e19a64bed648b5d18ceb389bafbcb3f280ba78e4cf03b053f2a5f08" +
+ "3c852452837138004073cf6726143179386279f1a8f15d44876c19bf6c2e2992ce6056191bb1a386f0e1f6f249495cff126991c6560e3f613e56525c0c49b5cc" +
+ "2ea4e736d83480f2b45d7dc840b849887f54a2aa072e72e3fd0db34e5cddb02221fdf2a40fb6ec271ba3a09de8dc73c24328c5d9a33ae0adc9874902f25d5bef" +
+ "4d85914557e2983c93fba16cdd4bd929e878b5d51b142b6e9aa0ce84871b7b03ee6cc13251e17547c2d20a7d4e948760e207e29de58a7ccb71b87f99d79837db" +
+ "d0f293ad3d33ffe91435598e8a4584b7b7ef5b1a895a2827b4976f81d335e4aa6feda3539690899619a4cb34fdcbbecf1b8b38cec2ec7c07ce84ec3044f49656" +
+ "28fdba8971585afb509526640d36425777b6ddf5b2a49d795fdcf71e57fd35f29fff37890541b6e152f14fb6ea4c70a1b9f159d02ed895a68dcc276f5d5ae83e" +
+ "47c021392ee22a398c8c73b3446d61562b3ec596036959aa645a65e5d24f733e142ec0e184b72a2adcbe3913932b2c9503c856a7e989d24f306e01e99268188d" +
+ "f858694e297803effeb8e28bf8fb63ed6787acc2c61f509e19099607512d40928a08e649474a43728b63523175fad12ad088aade0c1e20815c7c12773bc959e8" +
+ "640ee23eef2b1653ae8918615b45158a01be5a5f39a75a7c6cd8f1f6b463516539771ad251d5c2d40c5049877765512c44e58bd3b9ac3a0ac281771097880fe2" +
+ "c9516dcd6f1373e1e8a52fc485d104004dcc839fe3d120f1432b213388dd37980ce8238c87a70d5abe95d78d696d2436eb23a8f620ce74335d5e47f6524b11c3" +
+ "e22288644b539e3ab664dd5fd6bafb02897aab35adaef204f82d9318b22f45b787f5bacd74b01d23537973060868a47f2e3a45c1d8805a1d657f2332af8170e2" +
+ "9435d7540e70e92a8c8794bf22d3e11d54ff2d48cbc7a1ac3cecfc48f80fe521f6852f97aafa0605f3e7084b15e61a74869512c9c2d84180686ea07b562cf35b" +
+ "5a0ca529481ddbdba9c60729f821dc7a5a8b5c7eaef1ea7927d455a702aab538e7441933c4fff2d27de5659d6fa41f0ee72bb13a829839267f3a7b51a81a85b0" +
+ "d737194d94e1bf8173248cb057cee19eb5e2cdda38c529298f3c4d3b95400198063c5b27e9262f9c66425c65568a09035bed9cd55c1f2ec4becb6b9c59445398" +
+ "ad5b7c85142e713b6dd32493dcb817c8bcdbd728e325c25c5a14d764b63f960d1e48a0bc7f4d2bf51060f83b1d1f2591c6a9b79182e686b887a2c1461442e2f9" +
+ "16e8582e298f87ca95a8052df33af20ebded7bb1c528920233d1aca3b3789494d97084890fa3db0ea7eb561b0087c4a90000db41ea072613f91ebba82790f33c" +
+ "fd52cdd92d2ef1246911ef1dd82ad083881b72a08a40ee55884380dd136a7c0724cded69c6abf1f156b14ecd7284abcbf66522264145ee78ab0ef0d2a74eb390" +
+ "10946d5efefb7175164e96621d3f158de8b57956b8b1155c35b32007e47d915cb61dabd556a370537737574741fcf9a8a23f7155bf1f0e3d3c0d2088d1191d9c" +
+ "9c974139303f3dda55a70ab4810fddca3561114969d370f4e6bad60a53815eab1c4613854d04ba8b049dd7ab1a935c728299d1502ff9aa3fbb356f87f2a52b6e" +
+ "947dc79b5fd211ed31dee722d3fd857f43aad973fbfacb7cbfe1b2553bdc76142ccae5b4021a4647b8d8087925dd3191a57198792b6f918de87a92705ce57905" +
+ "f2dcfb67a20f8c77e700933432d60a4536d0959415f15f3eb8a788f1b19c497d3b68194e27ee736231835469d8bf0ce1717ecf533ab77dd97b35881d8eda959f" +
+ "54a7935b1bc11d7f2e472757734afaf0463da3fad9804eb948e8d6444e8394b33f1c187618c7c02371ee6d378ebb7a20b6049a5504daa71999d15944ee82650a" +
+ "2388f374f3ec3afd4ca58ef3f2588997d194a2741252cf6562e00cd6b5c5fe4066454d2b3150317694052b4dafb40c2f04c850e4062cd8f0af2da75280046850" +
+ "77990788b27fa457ae9d0b622d18fc070f1d2661ecab529b5cb82f30a29610dc6a9e93ca9a2617ab0109957a45c1204e5eedb8860c6f4d57122060f39a4194fc" +
+ "a285f1e9e7a75cc3511b8cb4865719c2260a630845051876e7795bba59573b6ce5faf7e5708eda7be25dd49c8cace4c04c541074d703e6601e043f6c63a0a371" +
+ "1a381f0ff83d136f4aa29de266169ce5b3105cbfeffba370fa306a93830e3c0519a495b8b9f4b72078e2c45421b4b0667f903676a1339c70ddd1a90dbd21853b" +
+ "2826ac3fa5add5073c634d4c5e87db0efe18638ee93c460257e52aacb8600ff36739818056110b2e974a1959e3784903aa97b0fcd9264f7d8f6bb5d8b7d9f03c" +
+ "4b643955bf7966250936d4e7d651712db5e695a6a36b5e6f56c651ff737042b5bb73638e21ca6ce9a3e63fbb1906675d97001d7ee240d277d62df18acb169677" +
+ "963d231c5276bdf5767ec35fbedb062e61c23d759aefd287b2dd62a0d6f0518d90b3c1756fde50afd33cab395ddf3cd538b9ad8862a199141331c63110c9ddaf" +
+ "fa3d6c63a1fb1b45529eace826cc29a1df5df327bb782e573c41864c18e6d31401d19719326e5c35bb50de7fdc67177a6a6015b4264fecba2360ab72ae8b060a" +
+ "6c66c5a05782a15fe3c1833b47e3495d29f2cfa579fcb08f02fd064e9ef2ef5564ac6a43cfbcae7d79e9f87ebc2176611823c6624db11892f8c47f8c96a49539" +
+ "1c18f821ecdefb343eae3fd98dae1ef96fa3527788543c0d06d9793579cc62d91dc4d25312901c6368ba81c8536c6287230e8f97d25f6c77366609580cf26a27" +
+ "88502a9aada84a794d3674ae11cd1742cf245e9d9502dbb5b340c2a6c79e3607f6b47666e1ea991ccfbdf6cc41ede46d043bc4d3e5e6882414dc65d62f9f47b9" +
+ "fb7b828a89afd6361ae458c2cdc82f459c54977072702ee5a4c22955b8019d8b8d91f558897c4b661f8e5412ccdc10c40521303c0ffd353a0c04cebca5622a71" +
+ "192b144d0f9c5c0706a130df887526b7b6e0f358ad9f7d0fd4d87c5fdb29a7453388c0d009da0d4c47a5d6cf8363892ac42b6ce3388771f698802b4dbfd66aa3" +
+ "5fa6a6f8b42dd8446324501c807b6e72cdd35cfe08956a52f86bb4709fe2980f62152dba3571f18fcc4c1cf7a25384c4b5174e93e5afc9b9f12db2bd505ddade" +
+ "d670d0d71b9548f9a07ef98521961cd96e8f363cf3222336bc4baa284b5305aab47dace615c1b3f3fb1ee23ad9ca3f58b086d9169ee5b2d3c2831e1db4f905da" +
+ "11e1fe79e3d48c01bd9879ed68391e4d24d6db8d6774cb8747e7ea368aba3bbf355386408af4a59b23fce74a5e673a1044db66ed8529a65462269480736cdaa5" +
+ "0784fbd77e1c41197335b4c517af8a67eef5b7165c5fd6022cceed0396089c3985c36595497db0a0fcae478e4e4d68c57b93f466aae86dd4244633beaa8116a0" +
+ "de25d2a54353b7ee85fee58ad4780a2957d69816585a64f65e75f332614aa6786d1a1432f6acde385d3d6e870bc968c60c81401726a958f0caae336c83a9523a" +
+ "c174faed43ec67473dcd151506e334a6aaf1731dd3aaa831f934be83beaefafa11810e7eb140f4fe80cfba574e6106c1bfe9f0b20173a4ec2663ce0580df6daa" +
+ "7966a3a8906677ab680025782c61b95cec6a73b5deb16599e6521f9c6c4cae0d9286566388d5181d6ba11c51a25c62b510d9b1793f3ce9f73ff0c9226c8aae69" +
+ "5d014287df074a244014720ee38e3968557db00aa63dab71854b8573c42c65116e3d88bf040d53ef3165a5827c717179e2939e310be5eaf6fb75447ba98ce925" +
+ "98e83a32a90eea848500a30eaaaceb307d37b1201b83a744468a1a52632ce5525c1fce5f702421e42e7cc4c61caed539dc09001cd31a8a2b48a783c36c56a3a2" +
+ "d50de42c63981c86642cc92bcceeec8a66b4afad3c1be1df4bcb8beedd442c281080c94692bf453196ed1a66a074d56a8e7f60238ce18358373efc173e70c691" +
+ "f832e1139bc04e6258d77cf7529af7ce5eca28ca5cda818625c0bb5beca96d99fc9b6689a7771434aa96e23c55a41cff7b7b718df58260b3bc91762034debf49" +
+ "7d8ca8d5764c52bc9665bf86db5407ee1b786d90f8d7772597eceb98f0121e3996e771d951568a162f6b71042998db8208ece5b8b0c68107b8e2079765b0d8c3" +
+ "2747597072756208b0d84415a5334a88d916bda390e26ccf3046b860e7ccbe22c48cd3d3f51bb65a98ace74d52613f782db726babd02780b8d620655bf9d551c" +
+ "ae9ef3056e3d24f5e7c3105c4857492fedd244ac2b8c30a874c1446630b042d819bc6b6d2d96829de903db22af706e93c5ae876d72c633600222443d1765bc62" +
+ "a8a20c458ae55bce8cbbef753cccc5e7d929408d6a3709467373651f0163128aba4142ecc56ef11ff1fabf5eaf6e955b4252d1350e9002300a1236ab2fa0ed34" +
+ "c9cc7dc1d4f09bd31296cec1493e725b57cc496fdac4e8d26197376bda7f74c0965c4352bc9d5c731df04f9908899cce6ec3afe15210d115992b2d95308dd032" +
+ "13c557ac527424c7db02475a2fc78b88d022d212c3d02d5ee490e2436e6e572e8a1330465b9052f8a3de01aab76662d18fa3d076fb77103fe432d549bc861fcf" +
+ "f63f3401cda31673ee48826b68b387802fea4471deb1fc928586f1b1614c16311c9820b563ab0112c28af5c1af5121818540c4b7d7f549b33906c1b86c6674ad" +
+ "799acee7342e4a79d9295493b2430fd08f373338795764621bca444868f3f42b0e40abd4b8e148cad2861fb4980b83bb58d40eeecd8d8cb1ef1ece17b0ab72e5" +
+ "06c6e650a3a43081f545acbac51ed7e121df51edb75120cce30ef7dbf41fad331120e537fb35be45d93de4fac0cadc7e5f644e2b767a285facd5f12845559785" +
+ "57f4afc276e21d77f6162062430dc8918435f035f435ea419ae9f1ddb6afd46b243f8bd6a3a33e7970e7e76fab9ba6afa72a4806189462f9d0f231a23e3ee1cc" +
+ "51cd10cb9043a27deecaca866751f971254fbe3084c243ef5f516bb652988b770896ae5abfa12db2eb2abe404cf694e9f60d47e734e260ae668b750e11b26001" +
+ "0d2bee5ca555a44523742fb069e484f7a69c12d4bad026c03ed7af10ebc9cf2f54d143fbe4de83448df80668217a11f5a1187f35ff306e6c685cfc2417c14aa7" +
+ "aeba1fb7dab05c913fbcbb8e677dd0f89324048862220ab6f5340c38b70804f625f5a526d6675a49fdc22ea6ceed477097fc723a7b6eaffd65c48dbee13df566" +
+ "f8f3449d91abb367cf37a8460fc8072c4ac75f88be8b9c840ef438cbf12a2e7d55799f641316e3381f72265425f3e90fbeaa9919533d8f9262da27f1f933d4f9" +
+ "a83e07aeb968016fed89e7b16babf0b6af3800a27c9c3d330b6bf8be447d31bedcc526b1bb53ecb10c3ea098bfa7d014d93274bec70b6e82bd5c443e860835f0" +
+ "ae82b7be7c78cd996e0990e3cac8c1c431481c8159ae1dbc40c03f4ac543e5758f347e12715822d86c881030de83a76ba1c49e4d4836bab7b5287122ccf523d2" +
+ "33935d802d2bca303cf57b36a5ff17e7c611f1cf99699881ae464da2911d77580587a7228db8325f204adb14413a13fe318e995d60e35c88bb47b99ba9ee8daa" +
+ "3e40ce5818876a3911107a159125dcf768ba04074e5771334e0de430c439070422508577e474e9532f7dfbc489d0c87d37103920415b6c116a422ac15e0736a8" +
+ "1e1e317adc87005f868815950882fc7497794c5eaf76f9def434d198304ff495bd2f9f4026aea330450741fb969700b953ab265aabf1fe146d861ba2aedc53d4" +
+ "f929abec2dee710aed8fa605fbb9bba914eaff01fdc113836d34d855383e4a311b4ec6ef6e80dfe32bc8035d84ddc4e2c305c112b93560112c1f3dff800d6043" +
+ "7eab01991f924075b4dea4db01c377ee1ca374d383ff1fbb463bf7078f6cc7509a0ecf536871abe7c95bf89f29c71f72f1a2002854113cb0d6d2192c00123010" +
+ "8dc9477808a218f84afb81f0274718c024393d5be66edaac7406e520b0c8e2c02ab98ee7b290db261f2122ea68bd79f2cc6dc64936af5064cce2b4d1b7078703" +
+ "951b6b81b9b60b99da4c2d12bbb50351a5b7713541db0958740910ff69e748c71bc7470a3c05489febefd384e06d267371935f652736bbcaacb20c34bd50144c" +
+ "71923b5a521ac4b1ba694d024ba51b4bef3ffcff74d5dc63810b2c0f529073e13ec3232d8647ad124b21ff73402d371c0db39d46cf4d2d4cf7ad43fd8dd365f6" +
+ "9b6b7bcdf664df0e62ba58f3ca0c62ad6fdcc9b091fb4926cb47b5ff8de7d3b12bd8709a46e5c3d5f0d22934c7a0574ee70b87af97d0fa46f7d9673915fed1d5" +
+ "a6c57197524ec9978d1bdf65633721ea2ccc25626dcb5e7f5e090b00e413c10a6d20b45fb8e98c22928de6dda184e856c86792c7cd09d38e4333a76882d363f1" +
+ "7f4d773ba104b2d04fd81027da087258fb175bfa8005c035a4719bac5b9630ae57889fb3b52a0fd47ec4060137b0f95fa5d5684172d07ca91e91eaf20dbfdea8" +
+ "a3e23937f33d8774f30c7e8e5d4b2d5371e5ea5e8d290970904c4c1ff33baf675ed79599653808f652ec4fd0088877f7dd7973023ccc8377d1ada2b80c07d077" +
+ "d7208686354f511925a3514c9e93c13525353b3d9528ab678e3e783c290ead88c2c3d6230bd4cb3bf79fce6dc3e95bfebda41e5d994e61ab083d73408ff6b627" +
+ "6996a263d2920170fff6869c2311441837a2fc190bee104328591b402defa38b421b972b01d020bd20b1b6a6ae884b23eb829fdf032a81d4f199a87ef125d4cc" +
+ "8662e24deb93700980e6ebc6882bcbaaa0283492e81f81e76bbe2ce18df4fb665436310658918ee217b5da262f1a1adbd59eb3c555cfebb12280058c75b5b33f" +
+ "8aa8c2d7cebf12ce46c5f49ecec5a865a9f0b65476793884f0021f8731b1bd288f55dfa1665776b2aee1007bcaa6d92a76a2ba9925bcfa68db7cc727b2a07ebc" +
+ "e24c0314c96ee4d6164c699e585461388dd73476a1e0519d92f51b64eb2842a7b17bb55d512d52da802df63206ee926f6a6a8c32de7b30e7cd3f23e37e0fd82a" +
+ "556323736ecd9de77494a2f8702463f40fb837c2a99270b9050b0cbbc2c305a32380ff5fa94bf9c101c667f36293c12ff9aaf6e0a810b75230caf915135cbe6e" +
+ "63ffb2a0e8632d32f72a65aa965fc556e10ddf6d5e40be919066eebda09d581a32156e1675300f52c8b355e88696fc2a67dd8e350a6e902e082af28a9809ba11" +
+ "ae0a5fd9c6627fb808d757147e5d59cffd9c45874478ab226e72909ccba6592a54391d072c7eb0221f1ff7be9924b9d037e4f8c31e94fdc814a8c4cc7ad4c9f6" +
+ "eacd5af66dd76bb6222b2fd3ea50a828fc3a91ef8b084214bfdcca56348517be18ca472166dd7f18c8e444e3641486e7dada626ced8710fc73a2b09b6e9395b0" +
+ "31ee2c48c9183851357d230204c911b345457de602824273193b795fc21e90a0c1cdaaba36787424b23ce73e2116947f143f9641d39a4c07c2e40e02f3bd7c68" +
+ "6899fd57e3eb23c6f5615c9dbc279fca0d4218bc79d928e70018533a85b4646bdc78015149b4d41d77ec7b46900e7fd5250116ce978f825569bd887bf3fd0365" +
+ "e1259a7514116fdcdd6da3ffdf432bbe8e59b9bca9222c5dca1eaa61caf29b8461ddced6f312838fe490f742db696fadddd19bab8de6bedaade878be07aca4ac" +
+ "76d69b81a6890e66dccd702720c3bd5601c6abdab95fbe4ccde6e35385b75e1977d5085ace928adfa382ea2890889017b9c4c81d9ba4629771f84cced6280db7" +
+ "a6cd83ff9375ffb0a75a6bebba9a209f048788ba39127c1036e4bd0aad9be40754fd75295611e455909a818a3541af32eae98df7222353a4405da0e7be9f1cf1" +
+ "bcb823fdea7976a810e8a3c7bf93fd947f961a344a93aa1ba99bf2df48ec82769d8c08e7b14191050d5706a9467c9122f34e27f060dd4d6e936c414c4e551b9e" +
+ "5d6b5b58347ed0012a8a323f41b43bf5e960b2806de59da85b998affdb490fbc965d569114223db3ca65df69a617f6808bea23017327ddaf32990070aaf5f444" +
+ "a9db44a57b5c92bc27bc71c5f8a2b6929edfed8e182bf5942564ef045c75448450eb1a4e4e09a1875e8a4a74f229879ccb7a2f2cd0359abd91a782c2ec1f68bb" +
+ "40ce0a63bcc014b198adc222fc957eec0483f5b93f0db91b7ab3b3e3c59841dae057eec97abb55fc42b2de124946e66ed2a7fe8cd047cb79051b55f82594ab45" +
+ "711c92364f932a5fd274fe184c85583ac7cfaf258c57e296f9c18fd181308565315e27272cbad3b21cb4490ca0e5f675365caac42f299e22d8a74ca51a9d0883" +
+ "bb376804e234502db66067e7a434d38c3dc075346e888e4558b1745d00458df99db02f0e4c37702fb0989387f74d002a924790a6b7351ee0f41684bef079be26" +
+ "ee9d70b560c006cff4b08b9578afb5019c21ab9418ae4ecaa7a1cfed2d880a06a03c2c7711b601a2cb3d9193e1577b4f1d0e614c0be1f69205fa6524fee80bf1" +
+ "e1f1906b50e75fea2d19b8a83071a460145e1730581e5e9538888d2e797ee3cbd3b31399ecb4d6244ee44362493802b142ea397c2e7a3c1bc86f0ea0546a38ce" +
+ "574e1df0c27ad8a28dca70f659ae6a1369d8b3aee7d0dd24ea370cc2bc1b1a4dc9f63911b63e60fe4ed8552bbca10e01c82d11b0ddf748d234b4aa3b31683c09" +
+ "86358fad680dd2178902beadc4646b3eceff572631ff9e6b64d8a622ad9f0308cc46b7d422ce792fe5573e9b9480e1ae9fedf31edaaac3b08c5a2c6c27d6b033" +
+ "6b92a3da7b838bb0a2916ebb6ee72bf33a7fa70630491f49c67031ce4b9dec2315088d0a5cbf7473fd121e0ef5f4e92d43114014c9f8c6e671086a446eb1f66f" +
+ "70f0cb0c668998ed96ee0ad2687946681fe40dc46cbd170e0cabb6f6216be61221f171fb2f4273f58c10d5c4eccafd1df62fdc8ac2c5c8f6d5eb637b71fa89e3" +
+ "f8347343f89667a4450c5c6e3791034d2dc3a593185b55bb95d8f8f2984ef981e4b692c1383ace4cb2c4adb80d5d582857b5d0e3ccb12845a59587b47232ad20" +
+ "926efa78e05a57b136e284401c516296b6b194d541ec165d11ef94f166cb52f45145d745ff3deaf643b5c45573ed0e69a22f0e0c9c5367f6d1398105516729b6" +
+ "3f2edf1b01ad9633edf80efbba6555d4253fd99b45a36f16ba98ea0bb0d80533aed806544a084a398a692f698c78b9bcfc9b4d3328dd869dbf7085893b8dafe1" +
+ "59e0517c2f6a3ddfd4a8c670072b30c96b90f81fcc08523e4fd75919752bfa52a1db7c374debbd83ca8e311b98b0d8275bedad215847fa8984cb50e108f69550" +
+ "f6517d719dbb5dade1d3c283357e14b6d9e85d61e33813546517e1262a7cbac814d79cf6b7e21b0fbbee9b6314f02b2d4e6995d2231670884c78cfd86a2acbcf" +
+ "0a178ba64de2f13f022e22b9b968ceefaff374aff02b703811f3dc541a69a21d6e1c5d1aca48889b125ff1274e65413f61e42bb0194b60b65a3454c696033cc8" +
+ "e3cc3613a52850296a0154bde0e2a81b7a6489bfce505dbe1bc44e0e1052f678297bb19cbdf7970bfa5268af8a54eee004063f9894118ddce7fae8bbba53a428" +
+ "678cec8a2bf6cca2b1a5f4a2e95562437e4eae41167f39d2a150f7c46c1eb6da35587f7234d870b16ed91c7db548ddc99967381b4bb4f3a2b0a5ebcbc7ab1b06" +
+ "7d5418768eaf7d526ca116e239ceb3ab393c45f3b32b713c11fa8e5ae8d7611e6008fa08d1305d5655315a72c85a04dc853da3e8ea9d46674194e15226f126c1" +
+ "a233c26dd7d3cc04ae572320d0c351911b6fcdbc0b8450523e96022f4b964d4e479b6cb1c40a6d27699b57ed2952ef7fb3172c69ba7beb8c8633a01070ac4344" +
+ "d4c401acf8ca7fcafeaa59e1d4c2ff251bb67dbe10a862103df1b416fd2097fe412b3da9d4095b48ea094fc3bbf2ca41e4452af3a179580e3bc11a7d97ba050c" +
+ "ae1d6b8075da267b3ae2231a1fcfce0c976402f34963c007d4f85d9ca95646990d1bb09691ceea3b34211dc58409e052d0acf8c2296a7e8fb52d7c673506d89b" +
+ "847c369daec7909da8657e8976f59f2ef4c8a049b46fdf30d6d223ea4175e4d60e469bcea0eb3bdcaa4d6024f2b43cf6de9bb40efa9172381291079dd82ac5b2" +
+ "39f2051a7f1aabcb8d50333e8c160de19ce1c76ced8056a0724ac630dd45ec4e315437391158a633c179a3d1f364b475454fd29c1e539077b9d5f7227786a5d9" +
+ "d8ec78e5615c25e517e9fcaf07611b85dff2c131a1b11a901a431a601854e5cb627cf7b8b0c5e66ad6cf60b7ffd6c6441f9ecd58f414013279e9de533d8d797b" +
+ "936cfdbfcc78342b7ab586457541df5f3b7d1873612df200896e2929f44c6fe10d24f7e6dbe52b6c42c0a40c947c1cbda2a41437079eebcdc29716d80957c159" +
+ "627e7366cc16df92cdedfa9f52edc848335f1c7152652fe24661a469fd503393229063c7ab20d8d895139a2f580dceac9f6dd4c4ac652b1d60c2b8a1b0b2923a" +
+ "86c31742807549e6d523b3c88d31e8534b9e05a6c63f6c8fb8a1eb4dad733d92e7071e410f0087ca3074f4a2df511ae89cefe9ed09a8df603d61f23754e43cc2" +
+ "e42bcdcbe58b0587aba9a62f32c7507116fdc8a9db3d65d6c0097c8f473eb7f3bcd11ab81d5b636b0812b7982201a63d0b8d40f2c38f65ffd953668eaa5751b3" +
+ "dab7f038aa7adbcd1f1102267c9d55d43649f9b4f65f1851546c5a9ef2c7ef56e84b16f12641e9d5ddaa78ec778b5f113b2e06bad5821e1a5203b006a774e36f" +
+ "56c9336d92c8cd8bddcf014b6d58c394e2a93554af6361fc1bbd13c359fed98bb5adfa4dd1266e2744e126e1bc029ab28fd68b648a2ab26ac23252171b298641" +
+ "2621f2a8697a00ab3fdc1b3b04921390ee16d213601ab249a51830661051d34eb777f690fc2d8dfb8e0898567e388830bac8b0bc896f43003feadf34256a927e" +
+ "b4d9293e32ca135351a19d1246cda30551c87de1e148ff5ea576b67e19e1a0389b88a5548b3b1a8cbee19eecc7de5c2333264c711d50d688a1c57eebc28dd6f3" +
+ "3dc0e4cb857973c3d0f28683a6f3c09db9f54b8fabeca9e4f9b86d794ca55d6611858f0d48736adc10dd6763ed7199bad81369ab1f3de30f521d43382bcccb7b" +
+ "be0178f716d5c3cb87488cebd7d9e2bbe671dfcf2512f1b815075777ea92a867f35e09ff0110e61db24423d0598eb6fd078dde0dc2b5d7f5e0bb6fee207da109" +
+ "2e656b5c982866d5fe01e6db79809646559a6f2b9088e977789aac74435dc625b54296b25788bfbbda9bbb25247d428f5141b03172fa11f12339b91ca96c92e7" +
+ "ea5a128c8046087dc7a7eba63e3bdb200565d8a103e7b3c292b088eb06aa27b43688c8516bbffcf123499574f00908ff43d66b79106cebaf16725f1dee600a29" +
+ "7b3a3da878940867f9549e65c73ea798ca923b012fb8a7ef3e2ded1d2c4e85635219f627dc4feb90f884ae6436e7b44f9159f9889d8e194828e079cd2ee60a7a" +
+ "6fbb6b8fc1f7355d7322709fabddd76e4283ddda3018b7882ad79b32bac133da415453eecd5bb1f0deb4f3b987a71a2f2e60194cde63a42b91b39bfe51b4aa8c" +
+ "20952b601df11d170c65a7fe935915890849a367936e97bd242edf305eaf2f4f4fb9e5ee1464c51a899ba5cc69cf56731502c1b75d0d565b1dce15440b0de0f5" +
+ "58bd4f810bf058af99c158a2be0dd02a01bb5317f55675f4d42c6766fc61271954b6988c33a84518bcedbac8de305946d060d19c4691c026953ebd680a4c9012" +
+ "0e8bd54675d6c33cc86e65f5cd3c34cb1e6fd47784a64f39e95a1945b5c21df2b3288f963863b33366908b05c2bd499dd25c1b8e97329d7e435899afeaed174d" +
+ "2a2471b6e8d6ad7a0b1b6a8b19fbd976362283e5abffcbd2cd310245092749b23e0d114e727622953487f373c833281a74a1b97742ca99e49cac14d9102e3680" +
+ "404509889ace009c47d075ba9891e7f67b89aca3e213150f3c715cbab1869135601612d7dffda3cc104b6508f56eb8b7e7f379b21e1ce290ce5fb96f53e3a7eb" +
+ "c7f7bddcbdfc266f23b775602d8d12527d30446cb4144df7fe3c2756e232a8ffca625d7b6ea2c8c0a92e6425ba67ab75160623c39f01fd96856b582e257a6930" +
+ "224c6da90a6eac4249214c3b85aef52835d904a8a5e224d59eae0c80a33b3141ffb31a7d8e62833fa4c850fa6be135558fff5434777df45feed00316c475759f" +
+ "ac6e014e9d3cf23e7322281ed75623ed69a81d6f05ee7de193f6b44ede4a94ced27aef5ab9056144593a836da80f5297875e7bd84d8ca6df95de8650b00b3528" +
+ "123132f26aabf755d00450648e44f3beafa4dc746775958c6dd88bee825c29112a3af582bb2ebe628d70364fe9ad01b8a9961d5b71018690440151486114af1a" +
+ "d85679bcd3eca510c6d6887e70e0d04b04fc2db5ab1eb21fff925b66f08f4fcbf31be3d743154056ba137727b63576e72f1756029c86bbcf9452fc6cfd89f3b5" +
+ "9f243d84c410253ba7c9284191a0ed87b2513901a93606f1aeb736c90dfe40c0a343d45e9a992ea894b22ee5d49e0f7d55d9bddaa6c74bde8ca5839db67b77a9" +
+ "ef740f9a47241f05e5dc1b9c95c459cc9db560b1db090daa3f4c6de46f695a158baaf357a1fc63ebc0d9db8144137ec4bd69c5af89cdf9cfa66e06bff6339d62" +
+ "2c372fbe5a855d14fa7ff3726512f966e4da0556b29ca6d7517803f897d0e1911f9b46a291002a8320091aa7016cb7ac993e35c8b0f5aed3c94ff0b5dadd8b77" +
+ "056d06d1bed59aaf7bca8516c3bba6b33e12df2e5ca4aa40664b3bf48c4dc2c57cfd74c765fe9f794f55b5df6ac6dd2b3592bbc71354c8dd9ae41b0a05e1c7c0" +
+ "d3bd1a0ac6b671c48c01d4a0fec7a01ad11040f213461759f9e029c835ca1d22f9a661b69d72bc46e34b1be7ed85a21830fb87baa74d7ab145ac1647f5f2df68" +
+ "671100d4d9e41082d3c81f3b5a6e603bb33fd56c1dbcbdce5e213c651da45d9d1dd7532d9a955202338387af6315137dc458fed62920a0e721aa7ff1660981c0" +
+ "e4c3de0a4863f6f660a7c1b9745ea26036a25cfa37e1337ded405ebb0401d7041a7938800a97a032fcababcc06391a77a580b1a61de014db9d7e280ffa6b2381" +
+ "ab6969ae5cfcca00a47ac2fa05be02aae7beb806d2afcc11dc0642d2a12ecde2d2926efd9fe790e1bee19f9114d22ca42f438ef656a1311e4931ab7fac93ed17" +
+ "3f68ea0abed18cc2c8905bb2d599780690eabe4996e38872a3190fee361df9fecd5906f664106de4835f8fbb657366327871a2d38cbb671df04e0d14fe97e260" +
+ "c42eb07bd1d70514913c7a64a51e405cc92e06845e5a78981fef9822fc79e9937ce0513138f6bbf247f5c457da708cf84e30d083b4ba48d2d43d70e7c31e9482" +
+ "4472617910a3de4369217b4daf892c2c3250d1de0457e88b3bcb5c4568f9b26aa675c551a9a730fe9ea8145ce7f8e23ec825be9be3b9edd588c391295fe31ac5" +
+ "bfc97d2e438ca9bf6551728b3be6d6c6ac064baca763e0eaa24f754f4bbc84a4377de45fb6a8f37150865df18749df1af4ea911b62f616dd4dd4b25b27c7b6fd" +
+ "99d8c00ce8a53fde3ced091891e8daf43cade10086be046ee5607003de24101db49b1a4fb0ac270d05bab12583e263e903e94dab8bba7c785e40499ab01ff92b" +
+ "b82c2e5342dce84881adedf77cab593f541e4c963f4f9ffc80a16bd4eb7f20ef4bf3f57abc7cbd86332d8be80f0794fc82767d13c71d8ee20468ee35c13308b0" +
+ "dc29ebe8c6a81e02ee9a21807ff57e4d932edcaf59ae9e76f7cdad46b32f94a74982f0887d7083c90ff54058e873b10cec67fba1b717deba5356e170dec1a40d" +
+ "36c57674ad8d43c5c98022b553fe060251b994271585f702de3e71fb1c8e36293dd44a4b99a1baf33f6205e9fbc9acdfe8cfdf007224f93a7104e7803454fdc0" +
+ "9fc5a20be59f600ee734847257a5ad62c599a7fa836d1174a6291e61c1be4b310bd4d7b7cb9be976dbdfdd2b99340a9863c8c0e5009165d7097317e6c3a29cfc" +
+ "dc84b19bc68f38694998f626567b80ce6699124b12bae4bb9e661c2484f5109517318341287e142a849d61d0d7b11d4996547e7325f28842dcaed26367f7a888" +
+ "e58c24c857da2f48a9fb91c78cf351a23e82ae443223580a9fe15a6a778f6c13be66888219e3e15971170712b6c356520cc15e4e75167993b66e6f125799cd40" +
+ "86c72588a85f68361f1c2f09e87f9a4de95ef9a3b92c3313664a706cb72916b96a9cb50771f6917ddcf696ce8d7f2525745fb6edc30bf3fdaad66ca5b013300a" +
+ "7ec7cd274327b1b9cd931c068d8fa9fd6336d59f6ac79b84a24b34c47e408b3bcb8ead49428c123922e54bfcaec7e39c4d6ef79e5645a35f715d151e679ef5c6" +
+ "6f86cd013fdaab978ee4e52eea5e2753e693271344a1f215e1c690de06f29c856c469ccb484d445bacb16694f4def1537cdb32260705e8a50fd65e98a24967a2" +
+ "456af6cf90643638999389a35de6e192068fd2e2ec29aced58611560c792ea5c7fa37583ebd5452a8d94cbf1898937dd8aa6656047e6e03f84dfd0bded514a6c" +
+ "b47ca71c2cf1e76f606c04374663712fd96925eecf0ac1c38392390c8cb095f39e1814252ded78b55ebeb9915dc5e2ec14fe99e3a075bd389ac601681f154286" +
+ "885289e568a8646d94abc806b4637492e3a407cde582d42764eef0d56ab14b00e9aa1f64d8fdd533d4314145c8255c44d0c746af6da844d285eb044d57e8cafb" +
+ "ab6c3b962e0177f11a839f4a5c0d2c2e8d5f76375ac115e0a89f460ea1be238f974a68e0693d15790117106c1a65ab5f7aa08e738aa888d5b56be39d2078837d" +
+ "fb2357d86f5be85a9af41aed611b231495564493e46acc90c6a3e67d5b055320290aef508aa6a1896f19cb5633edc0fec023216726e50960a44d81e0614ce748" +
+ "6ccfdaf620eaac0517e8cdeb1095d55f3a60d61dd27d967eb26128b84c9ea8418779e074cee8961c5dac811ce5ee8134d3910a47de7a1344293f5c64ae8f1b38" +
+ "9d6c457dc74e7005c339394f5f24630f5e40cf270640d1e4c27cb6a74fb440f3203026acfcd31f39cd4844ede7e785290878fac8770f930e96c3edf61748dc6f" +
+ "b7476832cf77ddfbe8eb8e12fd002038630301439ef8a7659bb10593a92cb84018e1ec78856f403e1eb9d6343aa0bbd77a63d776f1d12838f27f3cf6296ab0b3" +
+ "b4436f0ec545a5a1e92a5351fb273b3ed56a40e5a5d25e0057f4077bfeba2e2d8cb17a553b157609b20bfb5cd2699af9936f50d823bb59a950a24b8fd15ed705" +
+ "b1628663f0eb5b5c2b18f000ab039bc425ebafb2010e1a2264c38fa2bbd0f77e38eac8acd670565490fd60cac7fd28d988c8dc0658505dd98425f22c94647d44" +
+ "5d0236b97ea58b3c71feee90be0055ce1fabda5ebfced9d9bf5efaeac8408c4b6bcdb39851cfe038d88ada5211de2f0f69e9e3c62453106c366cf0c40971c0e8" +
+ "e8f2a790aa66999a0cb4cdb57a8c2d812e9e4a66df2f001a57e291864339257ec26c9bc2dc6cb2eb5c3301c167e1ed0387f9ce9f76c6759ebe5c68e8be378c42" +
+ "e0350b344acbc8b40c95cee9e82bb43cef5e91a32a6be8a727d5fbe089321ede3abee4da6b9f41775d7e9abc36f6a5d26ab88ba32978b5ea0ad63f0ce8a772be" +
+ "5aa51143bcd00d78bdcbd69beb652139ad658dc7ad242b2057eacee092aab4940d6ff993a8c7d8fbe93c08c93c45d5f3a01058f3c75c94be9da1a19a97754734" +
+ "b713e1ad6b7cd472619ec1abd4cf42f50b0648661c2b8dbe8976037c094c7176090ba94618e1918db44f5d2c367a0c7f911132d9a8b2398b9417542c7ad99b53" +
+ "a7ca48253bab8382a1a24d35b9b9818bda513f4b52fc576a71fa63e72aa8042ee1fc806c6fd3fc16e07ed2caf9f82bd3bb6b393b2708c051c24c2e05aaf72531" +
+ "d865888db06f719314d6094b2c4f0718c151c88958d2d6c8a6f49464f81cc46709dde026f4e05325ea4ca2dddf9a79bf98bff3aa5eb412434f0b7457b4ed47ab" +
+ "85a212e0c7720c78c961d56141bff0f964622d4d3984c1017de6f5846c72fae0c771a819ba6c111bd739fcf16f4b85f8101e7c3f0daefe753ec130a6f34c7697" +
+ "4dc531f83715ecae28bf2e55111778ae42aef17fa95340584cfae3d4599af9dbd10211baf3aafa8ac8a07edf8243daffd6a6486b1e3be4b60711194261e2b646" +
+ "e2667554cc0bb2fc07054b653231cede43154c9002890ca20b0ac81c4788847c6ecf7c174e528f36f8cfc53f3366fa9ce07b1843939cf6d318ed11f7ba6eb791" +
+ "ce25e75cbe37d2ee3d45bea487d969de041011959c0fed4e6c86802a7485fad70059ece14a29b03d4df41677acf71419ee63f1101060ca5e4ca0ab2edd71fe77" +
+ "46c6bd9f36bdbbf0a9956eaaf974f7bef982cd34881abd686fe77b536c85d042d77dadd00c5cb0130737e5318a025e6ae6af96ca28cbd41094d86a85765ff891" +
+ "af825793910c406470cc61be5d9282911d2faf82abfb309598fce0101ca64abe3920701a958c20ac35927733466a23de809afa2bdf331f68c3ab0cfa08b0c549" +
+ "a20e9b50dbe85d22d215d0e5fef854ba271a4c0f95e6abca19018bdd4a042721887418136b4a60cf291bf06ec47a5a4d2f9b29f988733c6bf6f65da5a95f8939" +
+ "fe0f2bab0bdce98569a81f861014e532f6a995542db02b6bdf3169191d300fb0429c1cae1d2dd4d29e0b61751576e04b558d38d3afcce8326c2871e969c1492a" +
+ "8391c0becec29edcf7f038a8093471763db9f13b97114acf7a979f5ba3bf6f990317890ee0705850fb97bfacf306a0ad621b2c3b633af01fc5aa059c0e22ed17" +
+ "23584dde6cf140bd1d0087ca9090ca9f07d3b93c60938af8df976555455bafbd8cc986ba32fc3f15b5962dbb2d37b6ae55a7de0c0c6f2366be0278e26bf9a725" +
+ "f61f2bcb545d66f79261783f7f03395f2a5d27e56af62a01ffcf778c3c686e244bd9b7e5029d1d40dd2250705c6825bf78e83730212640cb5ba54191b61fce33" +
+ "ce6df7721b15662162b631d99e6431efd24ec35639c2b97f10374fa5b9e2ca4231f523195206fb9695ec7721c98d74f29533cf714866adae8edbe8ed2d0969c4" +
+ "9ed36200c4b8b75131e6d1efa913106bb0759aa8255bd6a9dc2b00407358f4523486575b111676730094f46d0a7b95427df74f053c6611b4c465efa5310f760c" +
+ "5ff081e841e5f90c2de35855d45a7f35ce73d7c7f9f61fbfa953398e042c3946aaa4b7a2094d95410b8a5ef76c8b57d49f77311192b3f4578f37bda1a426de7c" +
+ "7cc54b5400bd16bb30cd8d1b7b42ff31c5e3759e3c9a7668174c02bc5a08f1bcc7e3ba145fa5f5c41e48877b41b0ef8fffd0f75c6547047c2e7b7c7e1aef2cda" +
+ "c4a778adbf71257618b4eb3c6dbd8211f829c1d6373415b969cc48f33d586d2678e7c1b441364a9fe2bb426a33b2a132741fac547766d196df3505fdb17977de" +
+ "7853cdcd8d9932eb9452620aa4921b4416f65055d77573b132a40795bf142815b655e670bf2c4464adb5d826a1744c8049d7a6cfbc8a4634e66eb32f0cb6fa17" +
+ "ffa8925131c3a253101733406a2a3a0dc61ec3ca1448623b6295791d4e2d65d303f78038e15d0ef75d823759bcb4b277b51410c37d5efbbb2e3a9e0cd78a8475" +
+ "05d44bb1fed7f72b1bf1a96ad0148e816d34c66b1b5faf172b8141ba007bf2e5dbbfee4b09ef66656ea3cde54f086040d14116aa7f3584ab6773f6091a2fbcee" +
+ "f59d6ea115f88ef9fcb358c87c35caf7c1a6022e141a3c688beef17da5a619e733d854218b30d5edc39b933b19dedd6750acabc52234934b08f930b608a18008" +
+ "838cb0fb73d4c78af0c468d9fa4fc5852135ae91ae00a99a6c603371d09b031ee37f87586cdc83897d8fd8ee2e07b9d0478a812d3f7eddca08860386e3ad9521" +
+ "98d5fc04fd0aba4b3da6ab8bdd9eca8e0399a2012d6158ed75ced5f432a223449b4e3db3fd4b19c494a69e9f2670833f8a88f7b2873319e9495f03fc69b6d098" +
+ "6006e3ffd8cdb9c1b98f72345848deea1b98ff6ef766f4398e642e5f2b217c1a87a608c1dc701bbb79d75a4433ca1d600061836888a220ee262124d145d371f6" +
+ "576f04cf71701133787a97aaa615ca98138c2be1046604d885e2f274b0de8743af50ad5dfc4c3a09164448e102be577eecf77ffaec1724f91f00f908ff6af41e" +
+ "57056dfa8f5dbcade85a66c10e524bae55922b4084407fb36ca8d6b7322f76a8139be9455a34440c719d0db8a36385efa48841170c8d35046407b586f5bbd169" +
+ "7cbaf6819b663fb17d0f0ae89691a099a8ccf47fa61fb6dbb22b3298e5cf2465e4b93c49da70fa76924fdf29389194cc5c61cb4b3084d0851bc3018270d1a24c" +
+ "b4b04e8af927d9fec9ea1c9ce18d4dbe61f7aac0ffd4e7c2e9729b49ed9874b883ec644864c6d9ad0422c4d89f87df1dfb2c96314b6a3e19afd21783f365445f" +
+ "bef10562a26b48df42dc344ddd63fcc03220dbde98f1109cade221027c40f0f996f4beb29513c3979ba374c4c6a2c2dc6276ca6be66eecf1dcb245d6efe78aea" +
+ "e49ece37f87894bef3c0cb1b993d974685564e2476c12c8d8f63a1aaf142fe34a6840be340b64f96d441f4537dff434ddce630101ed9f78e807881f6b7590697" +
+ "bc97e60accd7a135d8915781f4fc22e437145154dad0a39e5e306c117b11deb10462ba74d58e81de7674ef0bcb20b38511991447f63ad906b11abd4ba88df3c9" +
+ "e6931f87fece49f48543fed0439c88ad78f82aabb32dea03d030bdd76efef6b737daac2de2db1cce10e2ec74565b0a609606cbb6aa259ba88715229b8176c874" +
+ "db3fc4f6db9f167e7b2d55b33a261f9eecb69a0d36ecf9ec4f8f9cee5b74bcdc5d77b02ada89f56259edeec0d9ea866ccf454b9abd29d5d21041179912a5c302" +
+ "1862d850c3ff483e09479957df5bde03a29504b4a43e1fd40af2b8a2653a37cae89c8d917aecdec3959fecd32b7fd313a61e134abc15ad008aa993aba9629a5f" +
+ "0af0ec713f742bee096e171729e70530b60f910ef83746a61580f0cc6d67723792c0e0e94775d5b1edf37864a50678d197bb34a97e84d7f764c0bfe05f4b2d0c" +
+ "dc431d1f4410500dbe2758eb05bb6b19b154707c255a97cedc6aec1841f1817f6bcba0b9a9c1d3aebf747bec4423c71309fb8b4ada90dd9f7adbcffebbc905de" +
+ "74ce531403df33457c4d0b970fea5df4f85732e3c33c5b8242b041141a8c51a62f0bb14dbe07b14d3f5ce646d76e87b258e9b62128f9c0c0a8014f2c5b3d3dbd" +
+ "a3a77be6222419cd3fbbd3b842c46c099f142bcd36442961e8205ec5d7fd159befdbff12693953307026f1e06fd57b6447dd3cb52df466f0352cc46f27d1fc56" +
+ "56e06f68ca2847d291421bc9e0af6bbcfb7b3ce07600827809506ba3f96f40ca22766f8cba32d4461488f6596082a52c11e9ac908922075a7b443c41e55b719d" +
+ "9cac9fb587cf02432e1accf3cb7a16de0d5bc3a1c0aeff5a1795680b4551316e3d7b5a9bc63a09c6f75b0f00eb69fb6ef5130c1ec40c7a7d5d6ccce364b74f63" +
+ "a836a4a711027e592d6a70e10e573cc6d730a0def4a7a2d4dfcf3b0aba37fa2060ae6935710191c023a0b8e123a67ee811ed43b5127a1c4cf82d52ad6c40fd66" +
+ "1160f77dc320bbed349c8b6d08b2a7a6234a8dc88e4744b51d2d7c56e02f1c3bea9e6c2c3d5522ca02ec7e0b8160555eaf28797ed30b5c931a73562791f5f0a1" +
+ "b7ce83824bae17de449cff41312bd441f34df62904f4a0265d6fb9b8a352895ac6f0025d6b2074570970b4e679c559d03ef40794708eae36567008d9c33f7fc3" +
+ "5f8df7e901c27f408cc7fcc52631f1178695ea660d07df541e5a32721d145a32e8d32f06301b5073149e8798371fdb1a2daa5e1d02c24da07682a2cbacf5af55" +
+ "64810e479e5966dc6bfe14b4472c42cb154e19f7b8659d42de5ac926224cc6b0d8f3fa797058fd6e21ea85146838c4612760d84e24341825b6931a6417327394" +
+ "0154125254d4e11ac80e475a178605e851e1be39695cdc0781da241f232cedb32a04b1cc7352882fb635162ec3f5fc5004cfa7d03780753c14173ae7b12a71cd" +
+ "b40d4835023a00a4803bdfb6916956ade9f687af567e6f29981120d306084ad061ca1585f0e9497fdb27f9d54cbac8fecff176145114ebfc17e3f346b246ab91" +
+ "094dac0e684a708b45dcea16378fc29683dd033310068339b13d995dce77a50f9ee9cb4cf564566b05ce352a21159ad21e720e05ce6069a5ef4e9fe8ffd28516" +
+ "8356a0b80c4d1da547776f486a117f6f7ff6557edae7d68834cd71973517cfe4af045ad0fecdead68edc8017000958b69410247a51bd9bd3152dd57389f25223" +
+ "d5e88c0d343ab3aeb89b763eeb7ee48b3966fee147a4614e436c9a1a398487c80a001700666251b3dd6a2e5dc96814d21e6498e75811ba4c51160cbecb7d5510" +
+ "62697171a25a6abbc41fd806c3dfc83daaa10d7ce47f5a29ef0d85dda5a61429c637520e6a4048624cbb25f53977254cf803848ad81f25eda07690fe7a0466e4" +
+ "d18a2fd145dda1c94a994bc4ba5ce1aa1b50c38151febee757afceeaa91c7b35e57b90ff7b62efa929dcb962d32dde5a0bc3159524728621a3d7487eb7c3edd8" +
+ "6df3f8a18e590039bfc84a22b23b11468c90dcdc8506187233d8a6b3dc9785ddf6f341709fefccde91a7a0925a8446b1896aabd6a6826ef88b756a9711cb3b78" +
+ "1ab1f4df4d0515070e41fd5b0c5483270307e60eaaaf0b3a48f6bb96eef6141075445285675bb12f2ce38b42c91c1e063400d7bba9b322a0783e7d2f5d3f8874" +
+ "52ceb65bdedaa032336d969d2e0e3007d2ac07bcf054b9d0330f2e26c486c054bfa709fdabe283ed9a4ae67cee24f40f2a5c4e70160e6ceead208ca400959922" +
+ "70bc35be104c9ad94cdbe288b1c599db1758331340c9e927bc9d688e4186d5badd463bd3ba116bdc22a39c604778cd95503ce4ce642041e89bcdeb86fb19ab25" +
+ "e1f94ed2a2f857b228ed4a582ad411d7273a0d5189bf7a2b87a135753e03383033b989ea532041ab9ed397ecb3ce61e01923b3729068f6828ffd12e2ab1d28db" +
+ "6ed7423d458decb00476657a0580b4af3aa5615bf07df55beaa2bec71447aeb39791477dd09349bf573e29e9c4fd454b4bbf1e19591bf38dc47c83bf39babdc8" +
+ "737d69ce4b586cd10ed406426b88e686c11072f04c680e8b6275166e2dbe91f701642b1b4ed92d23d6fe14f39ff7f5a09401f3a398eb4bb742f6cf10aa35e767" +
+ "7e6e92aec791e94f8122e8c9cc9d0bc979e3eac6562ab614ff20330b00d9cdbd08e9deaeaf5cd67b49164f550c5f5c2d7523fe5ad71a2bd03fe2a97329980cb3" +
+ "049ecf6d677d815e56f7cc27407cf73528549ea98265ef90277c14763d5acb3572f5a482432cd8288972af580fdd3418889bfa6a373c4813c4c45e933ea4ec72" +
+ "cdd068089c2a30897dd57031445834de9f23faf506ad930d843b1cabad2c0aa8965d1b5e57032c969f9f55fe2a3049f4e63d5b5c6f5f760da5ba44e3bb9307e9" +
+ "ea39973d05a74a49e15bb71eaecf62373153ca316fdd40b1c64ce2896c95a7b5df970c2bec85edbd5ed84fa7949c08d5ec4d987052fffe357d444e2408a22295" +
+ "6ac1fb272f5023740b381e00dae9f09751a33bc6ad673c4221ce3f932164deb99f1da3eb3581caf475e385bcc56d47a7a1615a9543403750f0121d5482c4ea5c" +
+ "94fa3428178f6a4deea08d754ba2abb3d1aa48c3e06f06ffcdf4571579d398cd991e60599e9633fae6a0c07e10e538aebb7d33aa127c830f14b083728f6ad7eb" +
+ "c9a60a0ba222f47780eaa82a21393a49defee97aa8c3aa2fa53a2af86059a7587074128c2fee7060f398ae70b156d53aba0bf1af4bff10a966ce7e6382cec4b6" +
+ "054a8f6b9ef0e8729ee182f86c862f9b7d5ea36ef7e15bed10ed41b25738c380e58cf42795e3202749074fe5cb6e8fcb49a116f54d84734a834609a3443b8b42" +
+ "97c05ced428f5756ba59bfc1535bc7e16d370d81b72b1f3f78ba75c820b22e485dc042e4f38e93cc2918a491750c92998f03aee571cbe9abce4d00fdf9801f9e" +
+ "8e0fa276822e1e5349945f1d337e656b431c48c1a2e9d4142ea14e9427881bf201ad8cd8effaa6fe6a7e07c8112299db1b327a0cc34c9fbd35596f4ee25caeee" +
+ "221afad93ce7df64aa6ac766cf4fe1660446dcbafdfb86b4e0fea78c29c3e84ce42da4a503178bd250a6dbc4fc65e397062229001da05d5be118dea7ca5ce67f" +
+ "b4ee07a8b01e408aebef2c913434921df686a242b7d015a559f9efdc54ad62d7f31ceb72463041843d7fb60f948fed03ff143fe24ab81bd4ef6bdabb856ef1b7" +
+ "174cc987436322271bf48423114e05758a08cdbf300931fc7e950830b7ee920f7033541f1db9b0d2b91cad80d06c049b05fd0a76d6dc211bef2a08d53b1d16d4" +
+ "2232fb263941daac4e004542517807341bde98e9990a97739ef86d66c7a51324f1f6911cce4c3db37ebacb6e58eb02d8f7d6ea31338b56a99649c4e730a01bca" +
+ "deb6fc87cabe00addf1bf76b83927de26bc2bb3f0cd5945d863b0c31cfe8fd4b60462000a911755cbecdb6a98139041d52df498aa99aa3876836ce5b5bb426e7" +
+ "c22b5977902e0b3425fdbdb8f44e8758b207b469c3e5363f552c89fbf778e95e8b7ff6566ab591fb68a8bde38d8169c708a321b669c08d9ecf1a06c5321bb1cc" +
+ "9c8a585b6381645edfbd1ea4a2ad7e7eb8be6c431958add393c0a257aeb283644c6fe97580aef613f1b9d83e5b009f7a4d059025c11e0a0a67801be511dc097e" +
+ "4e7c065684effcafab83e0e716e2d0862e83b295f82089ed3ba4f6897c8d8eb2b358231f95eef840e1fe22e9065de2b3dfb3633e2968135756cd9c109e8acbb3" +
+ "172bbb6680c2e4fd69e179916a7849315c9f4dc86991d75cc6358617454694b3fcf2471ec7fca6ea2d99f704b9aa37a25a3b3183c5e32e3711346ba2336d6001" +
+ "489afb9cbd8822dbe4f0323ebf7cfa9367b6548213d473c0f07b1bb6d16e1c66fd2bfa1ca623e03149fc81eb6f71c12e7b4b76ca588548bb4872469687f334f9" +
+ "7e114a16a0a58ec70ed74ef69dd96666a85aa52d1ca812235796d90b9af4296247f4c1ab632effeaaef6acbb637f1aa9379195b3b668ca541bc6eb595bbc430b" +
+ "28adc5d1a26fd4cc2239516ac9ca9c0c028110926a2f88881a5886554c31539f4c8260e16364f4ac27710d2becdadf573f4a2b7b55d76ef059432c91c6f5beb1" +
+ "56686a620bdb4aea50df564cc0c5ccd8a93c454e06b8969a0f59d63ae5a29105149c08a5de65e87b0dc445dc5d86db8788ba77b83e22125c69621140d7f17906" +
+ "4ec0157a877cc51ce3c0d565bdf6c884f69b0ca631d6863770f6db30eff847e33c8b30d5714668a38a09f454ee44ff2b7f97207f10efcba74325378f6f272ef9" +
+ "9f09c501c12bd0a4155f559a604204b36751ce8d4c0af35a8b445a9290c305d5d3ea21f944e31df9a711ee90bd16a37850e2a87c3bd3fdecdc6e2f261a5d6d0d" +
+ "580990fcab9228cbb39f8c79608d821ce27c10b0ee0b5a96474759f67970cbe03cec9fe594765bc935abccf867b9717a4087465c8604eae89497c8ffae7e46f7" +
+ "ade2848916b54aa796809cb98a4364b7b44c17944dbc408909a92d4cbb24a514b72fe8de7d1cbba0a101973fa9b29d97dcf1f4ed8a05d5e0cb38849dc6e2d041" +
+ "16892ce649e0a553a727bfbb1d5794a059d6a411e43876e561d83bd22c054680cc8fa928f5f4be2d849f02ddf9c6d11ba35810b81553e1938ab013663f6ef35b" +
+ "08f06260932d7acf99f57967eec57a61f03d880c3225e53102a672f5842da21aaaee02444d372ab8ed7096235a4926e3288912d9c736c2c4dc49918abdfdd6d6" +
+ "d0df5be0133abd61b02a6f008909c5350f9077598ab2e612603431bddd3826e314feb280585b37eb89e597f7f0bdb738a9a93d9af224659d50c8f7479b240487" +
+ "76c2a960eb18923fa2d3b31b3d20ef538759cf22f5b415d19bdae689f2bab651d79ff99f77a721bc1b2233da12c12be0c9881ad82fc97a6343b3af8207dda8b6" +
+ "5c600644d741b8a16750964e341e060260c4de26f991f3a1f6a606d1153565f1c9cfee58eef327edc0e9cfaa206ce930b191f521be2344949bc75d583a413a96" +
+ "ee4edac424cbf9bdad2883c96a1306b96ee059d8044e3b7af4e7138697f142774ed6409a86a3c6c456600d4e405e6117ec759f4b22d7e5a185b0f9c67ad987bc" +
+ "58d2e8c929d4a487e5b77201d7c1416878e8d63258b2f58727cb631494cf1d68b99c28493b99b0409ccc1f9c218a2b95c45ff36563f0045ae5c3098f641ea6a9" +
+ "b48a3e1489831b2d176a1e0cb2afe6bd8cc5e797de01391e47e798c1aa945d33d5e7dd607aa73c9efe93f0646adcd7e211303ac7deea4d02c80370e8e867e2ad" +
+ "9942bfd5a66143560a1f59e5be1f3aeecd7eab689a4a481aec78045ae0604f69d9eea550152f6e2bc692529357b509d60e5a497bd94e63dc698cdfa2a3a55976" +
+ "0b2d072a2fe9c1fd41f31518aae0edaab532591476a9c5a61cd76937575cef71ff5dd66e158e7820b4b6bff4067cc26ee9aa66f41b80f078645b920512b5efd8" +
+ "88b3644601a72e3f665b9c8f0ee246593667379b8fa043718f2d75c21d2a11640c328971c32d5743c11ada6c95cfabf1c6b66e0b09342afc899e1f272ec48a7f" +
+ "ba5a51943763bf969cbac879363e14dad1952517d8f4b463511adccf25e655bced7cd9666d01dd4f2a0a21729ac4f44970c9c478a995d1c3b358a244110f1db9" +
+ "fe6335685701e0c2660ae69d33a93a75e44f5374b979a5af140200db43ff612be2728548192ebfd0a3860a9e135b910fe3fb249926d334167622bf4123bdf0d5" +
+ "38e9ff2a3bb67a44f8407328e3c94b47d92e0401aa1db85459967699804df245a7808f972683afded9cad8fbce15c1be38fd10c62c7abc302eb0537d5cc573ec" +
+ "245513a87c1a8d386f7ef0c4a91ec3c602b14a14ae395da13284df3391b929c7379e181c5d3d4597e3c955ef6e3dc2fc55890df04785bdd4e3fa35ac775f44ef" +
+ "9d7813cc036d6bcc316e869eeddf7b30e4b837e9285eb20397b4d7e0d12080c502c750268bcd6ffc323cb094afbe8304ae840d37be833878697f2cf931faf06d" +
+ "28dc6c7e1b5df69327127b47eddd0237f1bb5942ee5903d8cbfe1b11484199e90fe7c8e7f2f725deb2293630bd8c8a377d539736e2ccc2b90c08b97abd8c5ce4" +
+ "ea91a6219ab06c61c31eb48a35587b3c1719f387bd8c2063c5a79d041ca8a9ffac2e3c728f74efdb74ee0730f84cb3a8aefff7c8a1b570127cfc93eb6d3327f5" +
+ "ba7f886dee8be0548f710d6bfb18cbe5910bf61aed2c95028006f419241d968933aa00bb0760a41d2693465827a00837a84cadaf8a8e804d175adc5915c6cb6e" +
+ "fefb2cf70db063f2f3812da17586436c176aa0a815dfc7983eb88bfb1b6d1db7ab119cd3058c0db4d1910034f70f6eedfee8b742ea45af9780f415be2f851061" +
+ "313a218ad48e992b75afaa07c33ca47ee0155fe72e13d7e5736e512c5e5a45d351f7c7902d8b0fa31b34569a9aea31b018d63d572a9898c389d07caa427f114d" +
+ "251263d56cf5d6663159c2b32683b266fb909ba9d4caadaeda6700c03b25307cdea597a3287fd76082dbf33f073482872fdb494b892112c594d7f265d2799b5e" +
+ "5ec46a30fbf1557fa344a664a7af457a4e8ce2c014a270215d3f95d47a42d8f86a61d6d6b363d04a99a0d8f06c5b15cd803d951aea0ca185a807ca4c677db789" +
+ "fca64f0c5ba95b8c64f930eda658f9f773a9e1c8669589a7d98ade8dbc2c2c4cbbaf6ea2bbc6e762d4098f4db0d3f055958ae9da15ae57ee0b60fb9513dacf5a" +
+ "d65e34613570186acecf9e165bfa470aabcd35f22620497fbcabf220c53cff84eec12cf9965297b364f0e9122895c175d213fc2a9c9cbf27ebe1cf96fdacaf1c" +
+ "1c79ede66cfaa5057d33e09b31b43869812e5a0ce730663c18c4333141ae9565e437d99ade6b2cbe005214e8b3392c55bf4d7b38ef16e7f84b4ba3c85e1dfd1a" +
+ "ca8da1a5c75fd190e7752926533327880aed1461c7e9de2443ba0a2d094f4a14d5fffd3b102ea78acd34d162e82ab78fbb82bfbc8a9708ab532aa861643c39cd" +
+ "2bc89f2be53c583f9930fb2da14f1c5d5f218384b1740a76bd8b7ddd2c9888c8d7e7e78cc7a3304fa41995c7c1c3316894296caeeb9711f0e6bf16abc380bd41" +
+ "10448be3cb03cc3246ee7b9559c858307001033c84ecf89690526544c05c146f206d4a21e710597bb57759d232154a1f9d88eb3f3440374bad1e901da7a154b8" +
+ "39a6d1b1b6b2ab0be872ff036a9f9f769a169fbf91bada732d8f28c453b9be49011b211155fa5c588b43018775f99e3b92b322a4c41282326b79fd26541ccafc" +
+ "c0e2f09797e3217fb0e5785b72e654dbcde8ba14b2d56faa2218748c6789c158bb635d43c9a64690b004ab70f457e9fd959b2d90875966968c7ac44b103283e7" +
+ "50b60deeb1f89444aee25fbdb7fa3a96d70c3dce38246f111e466cdfa3b807c54ed584f5b1a64456e923dcf37f45b36cea3d602ba3a55a4fd883ebb6dc198650" +
+ "b522461614656897b9b7d408d48b12e594af06c91f715b32a4ed65a379f0ab461acb9b8b20d1f1b12e9f7fea422c0c7d545eff4152e06002cbd120fd74b483d3" +
+ "a0ee30cfd851c98e9aa8fb19b60528de4a75b412bed656933ae8ab600aeaef5befdcca4d35fa472ed38ffb91a9017c19c5d500426f262ba379034c45cf5d1627" +
+ "48da223207721b4bc4504b79309f3d622c53dfe3c83ff8866dd7614a2e90a85c077b2e18bf1cb6008f0d785d6a0ffd5f15a83a343036f3fdd25314bfe47b5a12" +
+ "58a7c89475f39a58a671d0a17f6fd100a8928181b94d8d53149316d5addf14bd398b538e2593273f02cf296fd73ff92d02230de939dae94e03d44ce93dd4dfa1" +
+ "b9219fd369c854ec409d7bf94b316e5e9c16e1ba525a783e24bd3fc0ecc949be245c402efae8ea77aaca74c78703506cfd5a5a614793e04c76652b4f344f79fd" +
+ "f2da1e34f650fc1094116ead723813d204ffe375d20707fd94d90f21c009194201c88d22afaee83a8a6be7518dc915331b863664e033d397c64e1516c0fd9324" +
+ "11614a1bdf2feb86e0d0ae21e784a55086c596c7eedd44d3afd7295455450f507f1c1a33c9ba94d50931ec054d8740510ea23990c266f30678a74fdd485b482b" +
+ "cbfb4070e3f10b66c65a4210794a3137adabe887ffb9bcf2a30c625138f840b2666610e76e5a0abc183088a94930c025836653eddbc440621bbf94761c74e108" +
+ "3672c6a914a753fd452e8e7a02c54b21d7bab4b705b4509b9b5b27e2e5144289eece950c3634b410b5e3cf8c5a5f74d98b55d17d45d7014390cf696a7e693777" +
+ "4c028517062a69276910cf5f139078e8ef6e77aa8b35aa55fd4f53e48ae6b4875d1732b286ffe8bf852b73af7b964fdf1aa4c4f16d9f14485a2b1a704c2615ac" +
+ "8ac74eaaacec7e8e4e506e1b418d377e4d5a271dfab47b3d3c11a809beda596fdf37935dfe06c147dfe7d5be696ffb2a0cff907d1eb2a88477c261d5a7aba06c" +
+ "d70dc52d00b9a9d851e849f86e1cba91b4c40d1ae3d4f21a2763369dde34d084adfc09d2a6cb5f09114cd8d6fa26d15f1ec428adc245064e5b8e80f21b0b3ff2" +
+ "6690398d3080f5355fc082bc4bf3a38576c7da00efbc80839dc9a06fab2b998a152553c36fab42e03e3e4b54456ed954e53bd63902d89e2617a263e70146d1eb" +
+ "71557baf43aeb0a681f600a784778c895afce26fe17e3ac33990c54cd96fcb2432de79d4f95ab2fb96effdd37f4e4247ae5b4c1fa461ca3269d45a90af090333" +
+ "fc3ab5152bd5aed4445eab93466701382ba76fc8745abd911bdb45a494e1c62647670380c04377bcdb5e631318dfa79850469a988094acd48a4110bbc7289617" +
+ "ce436294ff242302d154ad75437ae2f551df5b84f884c87497de0bb2ef7bd41a8c758e4b158084c78ef047389d88974faafa00ce7396e849509d39c403fdcca6" +
+ "8f47e1d0fc294e5510a07af24c165e1a4b4ba9498e7b333c4e8624c552801079775fc684b6e98b72ff133164a2052c2aadcef168d9cdeab8a935c98f08e23b95" +
+ "859277381a2ce23ea61fbe9ec1439a489523161ed370b0069aa6a5c7981e4a80c04e304ff2fd85f80b51e3de3484b53084f376cc72a390aaefc49baddf4d2545" +
+ "93dcb5a49326c9c15c3d1c0e0709c9879d68bee07b956d018a995bf1e7f8fa03ef2079d01e0bec601519704cced98854c94f1f0ae837653f14c0221e12f2cbdb" +
+ "1564066062bc1d4dcf7ed8b2c980b90e8101842d5844375cb370f402d858dffd9eb52572f8420d4d246462230ca0dbd567250e4f065730a6aecbd804b1acf949" +
+ "30e2890a39fdd4c1eb693f7e345504dbad5ac207f1a649968c3a7b416bd972b6a6bfde04375337a93b0ac08f6fae62c0fa7df8ae9deeee421f7ac62d8cf5ecf3" +
+ "b5ff39877ee4abaeb9db03d8a8f13f7925e54267a2651c55ecf580d5cbb24bf504fb01291e3e97ad1696ed995608fceda79f2441ca67bfe3c31f4f4bf0fffcd6" +
+ "55408744524412cd4d3cbdbdd216694aa7477e88b25f7efeb34abf491a50695ff686829a8fea9e999877bcb37291b8dbeeddfd44465a2c28a215aa532590c487" +
+ "d4747b6ece4e1aeaef725cb305d11b965a9647bef36a5c2fb45cc334d35ff4e308cd8813b6de3953b35a4ef6a3ae07794f8b54ef6365a573135320612bd1acfe" +
+ "6cac5524c0e98b6f2a33a790b94f5134f0cba075a6fa93c191f4176ca62ea2e365557d6b3363a17b9ee52f3c347c82cd19f8432d16a934ae9c5d4d4505e7d20e" +
+ "1ae31bb64ccb084f7a59744b27d58c2388d449ff4b63604878ae858240348ecfcb51761678265bd60d5dd7d51e25e91668fdf80f6b726b29ef6c3f0f229d8af4" +
+ "b2cdadc3ca7fbadab49b28819b9c9b92b49cbe9a281e5891f4eae7616013777605a0623dd7a650baf9a9dad66ca9aae3c76ef1e27db32bd9514a2776eb0c8d05" +
+ "65eec06fc4c8a69c417efa336842e248e5a51e3b5f3ba3227e3f78f1bd12d81595e03a01f4259c772fd481ab5f3d7a945e1c95fe0dc3c4742eeb7e15c9426ec3" +
+ "ed4c90ee07d56acc78fecfd7c5ce1e04e7db1a970091f15c90f0aae2865d135395d27787aaf68c6a179064d82691e0b6c795f61875f317dc6d2e8feea55a28f2" +
+ "461d74e14e350351720b6f536adfe3addd4111f08e3a84da2656fd4bc83989b329b383da9f01cf2392aa0b19577884d1281f2e6c106df451c078a472b36057d3" +
+ "065dfc4bbb47ce4e5dce4acf6da095bdd10322f3ae12bcdd1f805e73b303f1fc7a7e16cf3ffd822bd8b25fbc93be065019e394113182713f1ad299ae6537f6bf" +
+ "57116e8dc9ec775519b797ab4107c2ac5129ba85188852c3bc5f116044bbd8985b6dc8b8da4659589bf9d2351c4c3adaed87fe2ea20ef6bf62224c7af86fe8b4" +
+ "973e558f39465dff43bf23cf1f78957514e4e82a3009d40d97bf8d8442a11deabde806e2fa84c1ba75273da75ce8dad3b2a34786b2958ac4bfd248ebe604a173" +
+ "83c727b11dd922b1f72476af700b663fbd7033d0ac74b463d40a92d26c938b69f96fb4a9cb7a9ca2bd9496251270c0c5fcae6b3c2eda5377b897891648a97125" +
+ "8ac71fed8dce8e02c30961a299cb7f3145845dbe8f4dfaaaf4baf0ca3fb730abdd258e98215f072a943d5aee8d8bc4c86023524f7b69186d99ad88ccdfc0b4bd" +
+ "7db422bbad7eaa0824ce24b5c186e172c8c584f1cc5c126c901a69ebee8dbd230a653a3643b7875672d22fd86079daf8d834ba33664f5ad0b6eec767b4f58b45" +
+ "e67b776b90e0a5e130aa5365003eb7fd78b757b1cf9133f6a1d51064b293cb42c8c41b15b7e95e2a39fa5dae19c6e20031d2bfa4632c37779163fdecc6b45624" +
+ "4d6bfd01a8877f6fe7739591917a86e7dd795ad85cc3f256cff5961e8b62e92a0754a51f2c6d59819446eec8bdd08b87cf9f4fb5373e809d52240d2dd691cd50" +
+ "37fc79d35b61d63851917cfdba164868a3f79e2061bd4610c1f5216ed77df00baa75f949ad37142db4fd282a5c7d2e2636ca590f92fc4781d4f51efa69f53947" +
+ "d4fca1dc7dd2429837b6d7e5c9528effdecf6f731f676587785e5c4096bdb6f1f44e72f5f77d9025813e848881506f65bfb0f2b2d3ae6f9e00731929b5ac083d" +
+ "b1c9c324703e63fef6319e1d8150aa0ff7d9a2049961df9158f3e1f2e540a91feb742625d2a859a452186d2ccaa3ec2ba086ee0868a4dc24ae6818fc02f9c1df" +
+ "dc326cc31c46feefda97265238592f638968627ec24903b97513ab05ed58ce5b516decda0e2fbf01a70e6cb2e53c3e7b8855f80cd7e007b78da727ef0893e099" +
+ "592ba684d62ae2d1f06ad148fa7f34cfc724d804149cda21aee7eac064ad20d29132b260c2c2867fa6a2e747739fc30df2f002c2a99da6c7e64ee51e806af7d9" +
+ "768aec456b93a05002666cb61b2229c99f2cdef9afc9cea1c4ee3a85dd189823399781ee33cde2abedff09c47960c035e075a29156005d75845a11fa06abcc50" +
+ "5f7f849a0caaf683f334e9e7bbbef90fe6cf94cbf87767219440d31713daef6ad1e4a1cc720ce59fee4cf7731e46bbba9ec1648908ea345030aa8f10ade10ffa" +
+ "3d2acfd480b0b11eadc4fb2b740596b204e911456cb2f35ad9993ab7dd6a48b35ba0c207625384bb3c2ff24437810bd13c7ee96cd6f97f19ffd537ad182a3657" +
+ "b0e83d42fd6e2ebac6cbf5ea1bde97465b7cec6954ff5b5be049e59a49ea25ed6667dbace765401bde12031e5cfabf2df7afb728d2a0b2a38b24d79bf23a313c" +
+ "40fe5adef97487641c6088dd8712c0c352708e474b02c08fd2d71b6d44f16d82f291ccd61c43a339408379a8de54cfdbbae5e421e084112fbc17fb5561e084d1" +
+ "4149bf4bb06fd161878d8574f856867cff974d5898e161923d55bdac8699c9df6a220bcb6c800d3ae7f107b8c4acab206d780aafaf6c2e2379de8c900700d9c9" +
+ "c87d464772514c5aa3e5f5bfc00fb54f2b74702838b4731c5ac8a070b50783e81dd97fa8d55c739d026b607a2a78aba1bb79b1a7a3c22c78368672ac020061e6" +
+ "d9683d57d6989c6c6f08b8d5d74720f5cb25505fbe81d2bf53a68e972a54784705b20f83fd1ab5afff30764ef89dba4465b56f48b325ab3810bf8dcbf4faa61f" +
+ "676e2043ac8540df9e3af4c0f51d816e89c09bf67253be45fc5f75f64be97f6c7dc0c6392af6fa8e75aab58eda976b36773cd37d315771400a2cb846fdef3d8a" +
+ "a15bce5dfda0379e526f87cf67767a2ab93d41c85b4ed016ed0a89d2f94737433a3ebade813def29eaa18a1fb925fca7d08d1020f64caebc562cb4ad2fb241e2" +
+ "94923b2f2df5e6c4953c4b73be0f5568defe57ce49d16e2a205323e46cbb5a3e77fff1557671503bd7b5de5320f1fb951fbe26400cfa854af2d12fab0215310c" +
+ "f070add34dc4565d1757d7e10a03e3bb73a607ed7e10861b1274ddee76183cf7e56c1de7162c805c2dba0e0331d36f3a4e2019a2e0705ee2747ed1e52bc3a6fb" +
+ "3b061f784348204cdf8d643ff6c271fa72b56900edcc2f77201f3bd4fc296ad6534a7029ea66761bb9a3589a1f6ef566504c70297b98fbb603214fed2e4b7ca1" +
+ "06e3f0e993118897fa641fb9722d4667fa98d07a6837e5ab2144e5ec1548a7dbca28c559f2a9a99d54b8e55f56d0e59bcef1ac45e2046835b60579da0d2261e7" +
+ "30dab9009d138421c6458d146e870358b0b3fa20257e50b58f167c6b47edf7053513d58f33547d06ce52458baaa4dcf15f77b103565c66a81f183c827801b455" +
+ "b61b6287a46a37a96884075a7eada9ba7f0ddcc14654bf87a26d2e27a978b415257773796923a220e06b25af16fb5aaded9b2d081a4c64106df460ddce9c3b2a" +
+ "c8553e1521e501ad29a4b7f7681c9b60576a127087a5237c4c2bacf9b163dd590e63f2bc80e7f1e613773f87d034313064710404739d63363d204be7b14800c4" +
+ "d8c1b6a2a21da70223be51d281fee302ef806454f9d7d28244ba537c1d9f8f1bcc5d47038d986a8f95ca48437ffe94fd44a90bb03014a259112a97508adb3db4" +
+ "34f72a5268c1af6bc6d5801e579aab2228ca33600ebbf1a1959081c3a4ca99e444f97409f5e0ca4779241c9aacad1f4ee7fb4369bd6ae076378e4f63000b9a5c" +
+ "849ba6e72e47e2454a44659149338ac0767cd25d8693c0d143e354bd600f1c1d3a44eeb024923ea659060665d5cd9a4ca1ca86162819556535fd59b9fde90caa" +
+ "29920efe99479fe7e4b4e5371e13ccb43a1419cf023433239d840900d31bab37fabc3fd20e31bb7dbcb3ae8df66f67e2844944bcf544b658364f9e3d0b6d84b4" +
+ "63ad4eb621644fd7d774b501407a1178814b15149345d551b474347188067db2ab4d7f4d1abd3027133039e855e129f3f5649550da8c04fe2db57cb89bf1bf4f" +
+ "72eb35ccfe31afb92f6136d4c2a1c115b07b721b2da43151f11c356256230408979c5d95243714429e2c9500e7b043b20dac8a9763e5b487d1cbdb34ac379b9c" +
+ "6409454c79385b6e562459c4fdaad1b7f9297c1473e9b90fffe6d1c5390e241a187a4cefa2eb0cb0c11f4ca6c5b961c18ceb57892295290dbc991692556bffa3" +
+ "b8c405cf285e6bcb8a90246ad0ac15122f4cf73adc129d23aa2240733404beb6d74bf698e5589288a522573c774ce9f514b5d5c086382ea1dd4e89ff5facbf23" +
+ "d36bc3d203941e17747ede4b82820351f4df278ddb787ce8f6f1cc468ef953399efb072ce706e253f1bab76444bb70be6443cd0db633e958dc57bd223e00418e" +
+ "915a7c2e4d94c0623f9788276480cdfe798387d35e2ea2d304d066aec7627794cdd4200a44208d6c87f242c76e2d4a3f966b6fb96eaa63d892c1a177bef249b4" +
+ "fdd1a4c06c791f677dd9919f739ccf318bd77835330b0219786249c9c9736161dac771a838724f2dd70afba46a6782fd27601cf8a7126ae95a66e526131a68d7" +
+ "7a809e513533ed8021eecdbc5851dfcf95e10f1bbe47b5c7f079275a1837836245266b66d89fab25ac4bd6c1225560bea3259b67bf50a58ee056754d574da79e" +
+ "f9a1a0df3a5defed0f74fe74ce0bf65a04086f17e94a8451828c723c97932f26f9349f1a2c7866c617a528602721de4f3cc8916bcfc66cdc106bafa26ea87a13" +
+ "94dfa37e396365fb7f92df007b46a50ff04c7f85bfa679230ebedf18c2fb876fc7098dd1c4328adf85de71c31d94687a308053bfcdc158cfa7772170fbed63f5" +
+ "37dda41f65196dfacdd1186b5de0f3369d841ce6502192292d05a19ce7464f5bcab3015c721cac13ddca561b92dc1ee25d3068dc1945a1b4e2bd1e6604c42e4c" +
+ "3c04b490f6365828957990007394557854a903e19feb06906e41cbc8766bf37bd7dece90f4cdc987709b1129e84bfdc502543b5bfa887bf78553a5ec10ad68c5" +
+ "d10eff75f7aa495e7d934a55577fdc0aead31aee4522db0259d7d4ea8438a7996d80a787465a2980457193d1c4bf1a0a1e01741d72e5fc4dfe58475c1c01026b" +
+ "5a3bc973b902280753e9c3226db9cc778e2506c56ee86ae85b4d54dbf05394107329b2d1ee56522cb1ce562fb1aa4e592199d9c29f64cc3ab1d757531e209eec" +
+ "aa138d8388169b5e28c45f5aba267eeaa57f69869f0b6855d82b0eafcde63895251f41e8e676a0ab12ef3f569bb7de91b79fa46ad9637da01ca004f4d30259c1" +
+ "f5b00761f6ca9c17721a6718390624a10a11f7f52d7afb71ee5f8338828910e48f94a1347761abac87897b2dd0e23f1d325aec5031ef58f2972e8b402e05f8c1" +
+ "ae7053a90380a1ae0d4d06645548c23e13afa31aac8ff83b10f8341418af4114632f6406d6e33076391696c9161d63c8bcfd1c625fc737f68198046212d1638a" +
+ "d2d2d42ff7029c1fcc682a046edc4d4f24862d82c600180b1e8f57ff6a3865dfe9274f9886d00efa523a1b3b3757c4489200fec3dc5583854c955492336253dd" +
+ "767f2a60ce3d224afcff9cdc19e9b28830d33affda6af99942a8fe39562055f3e884fd6c1ebc1908ac159061f35e9b0da80434ce9673d9c6b87265170077c670" +
+ "743e37474d7605cd01c44af600f16d9ffaf24acf87fbe5ccf39bac41047a810d210051c87f06147a0bb8f1427a406700483679638f1af23f1dafb7aa0c468669" +
+ "71c3a82f535c26cf6cb335e8e915fda393799d3dbe0e04b907ed3612d12ac95783a6876cd986d2a13b82192532e02c250eaa42f891d2481655fa4494c723fe00" +
+ "87d224444245eb5b0eade5f741b025db1992a8ad0dce51b0c1af4a18a9e244f9f755891adf0f19179c7baa6c32bffc91e0b03c4ed3aaee1978b6a1f03b87ac6a" +
+ "fc3b9e7030bb212b17de198edfccde29d04224798c1204e47ea235f048724fac62d637d1ba0ee3922048fcf79c746b6c0c036d882e3491fd72bad6e009c6403e" +
+ "55876f4d31330caa02aedd0b0c121c3c41e736853a08071f0dd4ddc7412db0bbe274a9ac2932552bb37c40e72c2ef1d7cca8236942e480d709d3ea9d5ae0a1b7",
+ ),
+ },
+ }
+ for i, tt := range tests {
+ cache := make([]uint32, tt.cacheSize/4)
+ generateCache(cache, tt.epoch, seedHash(tt.epoch*epochLength+1))
+
+ dataset := make([]uint32, tt.datasetSize/4)
+ generateDataset(dataset, tt.epoch, cache)
+
+ want := make([]uint32, tt.datasetSize/4)
+ prepare(want, tt.dataset)
+
+ if !reflect.DeepEqual(dataset, want) {
+ t.Errorf("dataset %d: content mismatch: have %x, want %x", i, dataset, want)
+ }
+ }
+}
+
+// Tests whether the hashimoto lookup works for both light as well as the full
+// datasets.
+func TestHashimoto(t *testing.T) {
+ // Create the verification cache and mining dataset
+ cache := make([]uint32, 1024/4)
+ generateCache(cache, 0, make([]byte, 32))
+
+ dataset := make([]uint32, 32*1024/4)
+ generateDataset(dataset, 0, cache)
+
+ // Create a block to verify
+ hash := hexutil.MustDecode("0xc9149cc0386e689d789a1c2f3d5d169a61a6218ed30e74414dc736e442ef3d1f")
+ nonce := uint64(0)
+
+ wantDigest := hexutil.MustDecode("0xe4073cffaef931d37117cefd9afd27ea0f1cad6a981dd2605c4a1ac97c519800")
+ wantResult := hexutil.MustDecode("0xd3539235ee2e6f8db665c0a72169f55b7f6c605712330b778ec3944f0eb5a557")
+
+ digest, result := hashimotoLight(32*1024, cache, hash, nonce)
+ if !bytes.Equal(digest, wantDigest) {
+ t.Errorf("light hashimoto digest mismatch: have %x, want %x", digest, wantDigest)
+ }
+ if !bytes.Equal(result, wantResult) {
+ t.Errorf("light hashimoto result mismatch: have %x, want %x", result, wantResult)
+ }
+ digest, result = hashimotoFull(dataset, hash, nonce)
+ if !bytes.Equal(digest, wantDigest) {
+ t.Errorf("full hashimoto digest mismatch: have %x, want %x", digest, wantDigest)
+ }
+ if !bytes.Equal(result, wantResult) {
+ t.Errorf("full hashimoto result mismatch: have %x, want %x", result, wantResult)
+ }
+}
+
+// Tests that caches generated on disk may be done concurrently.
+func TestConcurrentDiskCacheGeneration(t *testing.T) {
+ // Create a temp folder to generate the caches into
+ cachedir, err := ioutil.TempDir("", "")
+ if err != nil {
+ t.Fatalf("Failed to create temporary cache dir: %v", err)
+ }
+ defer os.RemoveAll(cachedir)
+
+ // Define a heavy enough block, one from mainnet should do
+ block := types.NewBlockWithHeader(&types.Header{
+ Number: big.NewInt(3311058),
+ ParentHash: common.HexToHash("0xd783efa4d392943503f28438ad5830b2d5964696ffc285f338585e9fe0a37a05"),
+ UncleHash: common.HexToHash("0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"),
+ Coinbase: common.HexToAddress("0xc0ea08a2d404d3172d2add29a45be56da40e2949"),
+ Root: common.HexToHash("0x77d14e10470b5850332524f8cd6f69ad21f070ce92dca33ab2858300242ef2f1"),
+ TxHash: common.HexToHash("0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"),
+ ReceiptHash: common.HexToHash("0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"),
+ Difficulty: big.NewInt(167925187834220),
+ GasLimit: big.NewInt(4015682),
+ GasUsed: big.NewInt(0),
+ Time: big.NewInt(1488928920),
+ Extra: []byte("www.bw.com"),
+ MixDigest: common.HexToHash("0x3e140b0784516af5e5ec6730f2fb20cca22f32be399b9e4ad77d32541f798cd0"),
+ Nonce: types.EncodeNonce(0xf400cd0006070c49),
+ })
+ // Simulate multiple processes sharing the same datadir
+ var pend sync.WaitGroup
+
+ for i := 0; i < 3; i++ {
+ pend.Add(1)
+
+ go func(idx int) {
+ defer pend.Done()
+
+ ethash := NewFullEthash(cachedir, 0, 1, "", 0, 0)
+ if err := ethash.Verify(block); err != nil {
+ t.Errorf("proc %d: block verification failed: %v", idx, err)
+ }
+ }(i)
+ }
+ pend.Wait()
+}
+
+func TestTestMode(t *testing.T) {
+ head := &types.Header{Difficulty: big.NewInt(100)}
+ ethash := NewTestEthash()
+ nonce, mix := ethash.Search(types.NewBlockWithHeader(head), nil)
+ head.Nonce = types.EncodeNonce(nonce)
+ copy(head.MixDigest[:], mix)
+ if err := ethash.Verify(types.NewBlockWithHeader(head)); err != nil {
+ t.Error("unexpected Verify error:", err)
+ }
+}
+
+// Benchmarks the cache generation performance.
+func BenchmarkCacheGeneration(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ cache := make([]uint32, cacheSize(1)/4)
+ generateCache(cache, 0, make([]byte, 32))
+ }
+}
+
+// Benchmarks the dataset (small) generation performance.
+func BenchmarkSmallDatasetGeneration(b *testing.B) {
+ cache := make([]uint32, 65536/4)
+ generateCache(cache, 0, make([]byte, 32))
+
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ dataset := make([]uint32, 32*65536/4)
+ generateDataset(dataset, 0, cache)
+ }
+}
+
+// Benchmarks the light verification performance.
+func BenchmarkHashimotoLight(b *testing.B) {
+ cache := make([]uint32, cacheSize(1)/4)
+ generateCache(cache, 0, make([]byte, 32))
+
+ hash := hexutil.MustDecode("0xc9149cc0386e689d789a1c2f3d5d169a61a6218ed30e74414dc736e442ef3d1f")
+
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ hashimotoLight(datasetSize(1), cache, hash, 0)
+ }
+}
+
+// Benchmarks the full (small) verification performance.
+func BenchmarkHashimotoFullSmall(b *testing.B) {
+ cache := make([]uint32, 65536/4)
+ generateCache(cache, 0, make([]byte, 32))
+
+ dataset := make([]uint32, 32*65536/4)
+ generateDataset(dataset, 0, cache)
+
+ hash := hexutil.MustDecode("0xc9149cc0386e689d789a1c2f3d5d169a61a6218ed30e74414dc736e442ef3d1f")
+
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ hashimotoFull(dataset, hash, 0)
+ }
+}
diff --git a/pow/pow.go b/pow/pow.go
index 592d964751..4849adb3ea 100644
--- a/pow/pow.go
+++ b/pow/pow.go
@@ -16,9 +16,43 @@
package pow
-type PoW interface {
- Search(block Block, stop <-chan struct{}, index int) (uint64, []byte)
- Verify(block Block) bool
- GetHashrate() int64
- Turbo(bool)
+import (
+ "math/big"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/core/types"
+)
+
+type Block interface {
+ Difficulty() *big.Int
+ HashNoNonce() common.Hash
+ Nonce() uint64
+ MixDigest() common.Hash
+ NumberU64() uint64
}
+
+type ChainManager interface {
+ GetBlockByNumber(uint64) *types.Block
+ CurrentBlock() *types.Block
+}
+
+type PoW interface {
+ Verify(block Block) error
+ Search(block Block, stop <-chan struct{}) (uint64, []byte)
+ Hashrate() float64
+}
+
+// FakePow is a non-validating proof of work implementation.
+// It returns true from Verify for any block.
+type FakePow struct{}
+
+// Verify implements PoW, returning a success for an input.
+func (pow FakePow) Verify(block Block) error { return nil }
+
+// Search implements PoW, returning the nonce 0 for any call.
+func (pow FakePow) Search(block Block, stop <-chan struct{}) (uint64, []byte) {
+ return 0, nil
+}
+
+// Hashrate implements PoW, returning 0.
+func (pow FakePow) Hashrate() float64 { return 0 }
diff --git a/pow/xor.go b/pow/xor.go
new file mode 100644
index 0000000000..558aeb4690
--- /dev/null
+++ b/pow/xor.go
@@ -0,0 +1,85 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Source: https://golang.org/src/crypto/cipher/xor.go
+
+package pow
+
+import (
+ "runtime"
+ "unsafe"
+)
+
+const wordSize = int(unsafe.Sizeof(uintptr(0)))
+const supportsUnaligned = runtime.GOARCH == "386" || runtime.GOARCH == "amd64" || runtime.GOARCH == "ppc64" || runtime.GOARCH == "ppc64le" || runtime.GOARCH == "s390x"
+
+// fastXORBytes xors in bulk. It only works on architectures that
+// support unaligned read/writes.
+func fastXORBytes(dst, a, b []byte) int {
+ n := len(a)
+ if len(b) < n {
+ n = len(b)
+ }
+
+ w := n / wordSize
+ if w > 0 {
+ dw := *(*[]uintptr)(unsafe.Pointer(&dst))
+ aw := *(*[]uintptr)(unsafe.Pointer(&a))
+ bw := *(*[]uintptr)(unsafe.Pointer(&b))
+ for i := 0; i < w; i++ {
+ dw[i] = aw[i] ^ bw[i]
+ }
+ }
+
+ for i := (n - n%wordSize); i < n; i++ {
+ dst[i] = a[i] ^ b[i]
+ }
+
+ return n
+}
+
+func safeXORBytes(dst, a, b []byte) int {
+ n := len(a)
+ if len(b) < n {
+ n = len(b)
+ }
+ for i := 0; i < n; i++ {
+ dst[i] = a[i] ^ b[i]
+ }
+ return n
+}
+
+// xorBytes xors the bytes in a and b. The destination is assumed to have enough
+// space. Returns the number of bytes xor'd.
+func xorBytes(dst, a, b []byte) int {
+ if supportsUnaligned {
+ return fastXORBytes(dst, a, b)
+ }
+ // TODO(hanwen): if (dst, a, b) have common alignment
+ // we could still try fastXORBytes. It is not clear
+ // how often this happens, and it's only worth it if
+ // the block encryption itself is hardware
+ // accelerated.
+ return safeXORBytes(dst, a, b)
+}
+
+// fastXORWords XORs multiples of 4 or 8 bytes (depending on architecture.)
+// The arguments are assumed to be of equal length.
+func fastXORWords(dst, a, b []byte) {
+ dw := *(*[]uintptr)(unsafe.Pointer(&dst))
+ aw := *(*[]uintptr)(unsafe.Pointer(&a))
+ bw := *(*[]uintptr)(unsafe.Pointer(&b))
+ n := len(b) / wordSize
+ for i := 0; i < n; i++ {
+ dw[i] = aw[i] ^ bw[i]
+ }
+}
+
+func xorWords(dst, a, b []byte) {
+ if supportsUnaligned {
+ fastXORWords(dst, a, b)
+ } else {
+ safeXORBytes(dst, a, b)
+ }
+}
diff --git a/rlp/decode.go b/rlp/decode.go
index c4e5869cc9..ee0b7dbcd3 100644
--- a/rlp/decode.go
+++ b/rlp/decode.go
@@ -63,12 +63,16 @@ type Decoder interface {
// must contain an element for each decoded field. Decode returns an
// error if there are too few or too many elements.
//
-// The decoding of struct fields honours two struct tags, "tail" and
-// "nil". For an explanation of "tail", see the example.
-// The "nil" tag applies to pointer-typed fields and changes the
-// decoding rules for the field such that input values of size zero
-// decode as a nil pointer. This tag can be useful when decoding
-// recursive types.
+// The decoding of struct fields honours certain struct tags, "tail",
+// "nil" and "-".
+//
+// The "-" tag ignores fields.
+//
+// For an explanation of "tail", see the example.
+//
+// The "nil" tag applies to pointer-typed fields and changes the decoding
+// rules for the field such that input values of size zero decode as a nil
+// pointer. This tag can be useful when decoding recursive types.
//
// type StructWithEmptyOK struct {
// Foo *[20]byte `rlp:"nil"`
diff --git a/rlp/decode_test.go b/rlp/decode_test.go
index 2d465b74dc..d762e195d0 100644
--- a/rlp/decode_test.go
+++ b/rlp/decode_test.go
@@ -339,6 +339,12 @@ var (
)
)
+type hasIgnoredField struct {
+ A uint
+ B uint `rlp:"-"`
+ C uint
+}
+
var decodeTests = []decodeTest{
// booleans
{input: "01", ptr: new(bool), value: true},
@@ -490,6 +496,13 @@ var decodeTests = []decodeTest{
value: tailRaw{A: 1, Tail: []RawValue{}},
},
+ // struct tag "-"
+ {
+ input: "C20102",
+ ptr: new(hasIgnoredField),
+ value: hasIgnoredField{A: 1, C: 2},
+ },
+
// RawValue
{input: "01", ptr: new(RawValue), value: RawValue(unhex("01"))},
{input: "82FFFF", ptr: new(RawValue), value: RawValue(unhex("82FFFF"))},
diff --git a/rlp/encode_test.go b/rlp/encode_test.go
index 6f38294e46..827960f7c1 100644
--- a/rlp/encode_test.go
+++ b/rlp/encode_test.go
@@ -218,6 +218,7 @@ var encTests = []encTest{
{val: &tailRaw{A: 1, Tail: []RawValue{unhex("02")}}, output: "C20102"},
{val: &tailRaw{A: 1, Tail: []RawValue{}}, output: "C101"},
{val: &tailRaw{A: 1, Tail: nil}, output: "C101"},
+ {val: &hasIgnoredField{A: 1, B: 2, C: 3}, output: "C20103"},
// nil
{val: (*uint)(nil), output: "80"},
diff --git a/rlp/typecache.go b/rlp/typecache.go
index a2f217c66f..3df799e1ec 100644
--- a/rlp/typecache.go
+++ b/rlp/typecache.go
@@ -37,11 +37,12 @@ type typeinfo struct {
type tags struct {
// rlp:"nil" controls whether empty input results in a nil pointer.
nilOK bool
-
// rlp:"tail" controls whether this field swallows additional list
// elements. It can only be set for the last field, which must be
// of slice type.
tail bool
+ // rlp:"-" ignores fields.
+ ignored bool
}
type typekey struct {
@@ -101,6 +102,9 @@ func structFields(typ reflect.Type) (fields []field, err error) {
if err != nil {
return nil, err
}
+ if tags.ignored {
+ continue
+ }
info, err := cachedTypeInfo1(f.Type, tags)
if err != nil {
return nil, err
@@ -117,6 +121,8 @@ func parseStructTag(typ reflect.Type, fi int) (tags, error) {
for _, t := range strings.Split(f.Tag.Get("rlp"), ",") {
switch t = strings.TrimSpace(t); t {
case "":
+ case "-":
+ ts.ignored = true
case "nil":
ts.nilOK = true
case "tail":
diff --git a/rpc/client.go b/rpc/client.go
index 269eb78c86..2c35ba54a5 100644
--- a/rpc/client.go
+++ b/rpc/client.go
@@ -19,6 +19,7 @@ package rpc
import (
"bytes"
"container/list"
+ "context"
"encoding/json"
"errors"
"fmt"
@@ -30,9 +31,7 @@ import (
"sync/atomic"
"time"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
- "golang.org/x/net/context"
+ "github.com/ethereum/go-ethereum/log"
)
var (
@@ -408,9 +407,9 @@ func (c *Client) newMessage(method string, paramsIn ...interface{}) (*jsonrpcMes
func (c *Client) send(ctx context.Context, op *requestOp, msg interface{}) error {
select {
case c.requestOp <- op:
- if glog.V(logger.Detail) {
- glog.Info("sending ", msg)
- }
+ log.Trace("", "msg", log.Lazy{Fn: func() string {
+ return fmt.Sprint("sending ", msg)
+ }})
err := c.write(ctx, msg)
c.sendDone <- err
return err
@@ -445,7 +444,7 @@ func (c *Client) write(ctx context.Context, msg interface{}) error {
func (c *Client) reconnect(ctx context.Context) error {
newconn, err := c.connectFunc(ctx)
if err != nil {
- glog.V(logger.Detail).Infof("reconnect failed: %v", err)
+ log.Trace(fmt.Sprintf("reconnect failed: %v", err))
return err
}
select {
@@ -496,31 +495,31 @@ func (c *Client) dispatch(conn net.Conn) {
for _, msg := range batch {
switch {
case msg.isNotification():
- if glog.V(logger.Detail) {
- glog.Info("<-readResp: notification ", msg)
- }
+ log.Trace("", "msg", log.Lazy{Fn: func() string {
+ return fmt.Sprint("<-readResp: notification ", msg)
+ }})
c.handleNotification(msg)
case msg.isResponse():
- if glog.V(logger.Detail) {
- glog.Info("<-readResp: response ", msg)
- }
+ log.Trace("", "msg", log.Lazy{Fn: func() string {
+ return fmt.Sprint("<-readResp: response ", msg)
+ }})
c.handleResponse(msg)
default:
- if glog.V(logger.Debug) {
- glog.Error("<-readResp: dropping weird message", msg)
- }
+ log.Debug("", "msg", log.Lazy{Fn: func() string {
+ return fmt.Sprint("<-readResp: dropping weird message", msg)
+ }})
// TODO: maybe close
}
}
case err := <-c.readErr:
- glog.V(logger.Debug).Infof("<-readErr: %v", err)
+ log.Debug(fmt.Sprintf("<-readErr: %v", err))
c.closeRequestOps(err)
conn.Close()
reading = false
case newconn := <-c.reconnected:
- glog.V(logger.Debug).Infof("<-reconnected: (reading=%t) %v", reading, conn.RemoteAddr())
+ log.Debug(fmt.Sprintf("<-reconnected: (reading=%t) %v", reading, conn.RemoteAddr()))
if reading {
// Wait for the previous read loop to exit. This is a rare case.
conn.Close()
@@ -577,7 +576,7 @@ func (c *Client) closeRequestOps(err error) {
func (c *Client) handleNotification(msg *jsonrpcMessage) {
if msg.Method != notificationMethod {
- glog.V(logger.Debug).Info("dropping non-subscription message: ", msg)
+ log.Debug(fmt.Sprint("dropping non-subscription message: ", msg))
return
}
var subResult struct {
@@ -585,7 +584,7 @@ func (c *Client) handleNotification(msg *jsonrpcMessage) {
Result json.RawMessage `json:"result"`
}
if err := json.Unmarshal(msg.Params, &subResult); err != nil {
- glog.V(logger.Debug).Info("dropping invalid subscription message: ", msg)
+ log.Debug(fmt.Sprint("dropping invalid subscription message: ", msg))
return
}
if c.subs[subResult.ID] != nil {
@@ -596,7 +595,7 @@ func (c *Client) handleNotification(msg *jsonrpcMessage) {
func (c *Client) handleResponse(msg *jsonrpcMessage) {
op := c.respWait[string(msg.ID)]
if op == nil {
- glog.V(logger.Debug).Infof("unsolicited response %v", msg)
+ log.Debug(fmt.Sprintf("unsolicited response %v", msg))
return
}
delete(c.respWait, string(msg.ID))
diff --git a/rpc/client_context_go1.4.go b/rpc/client_context_go1.4.go
deleted file mode 100644
index ac956a17dd..0000000000
--- a/rpc/client_context_go1.4.go
+++ /dev/null
@@ -1,60 +0,0 @@
-// Copyright 2016 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see .
-
-// +build !go1.5
-
-package rpc
-
-import (
- "net"
- "net/http"
- "time"
-
- "golang.org/x/net/context"
-)
-
-// In older versions of Go (below 1.5), dials cannot be canceled
-// via a channel or context. The context deadline can still applied.
-
-// contextDialer returns a dialer that applies the deadline value from the given context.
-func contextDialer(ctx context.Context) *net.Dialer {
- dialer := &net.Dialer{KeepAlive: tcpKeepAliveInterval}
- if deadline, ok := ctx.Deadline(); ok {
- dialer.Deadline = deadline
- } else {
- dialer.Deadline = time.Now().Add(defaultDialTimeout)
- }
- return dialer
-}
-
-// dialContext connects to the given address, aborting the dial if ctx is canceled.
-func dialContext(ctx context.Context, network, addr string) (net.Conn, error) {
- return contextDialer(ctx).Dial(network, addr)
-}
-
-// requestWithContext copies req, adding the cancelation channel and deadline from ctx.
-func requestWithContext(c *http.Client, req *http.Request, ctx context.Context) (*http.Client, *http.Request) {
- // Set Timeout on the client if the context has a deadline.
- // Note that there is no default timeout (unlike in contextDialer) because
- // the timeout applies to the entire request, including reads from body.
- if deadline, ok := ctx.Deadline(); ok {
- c2 := *c
- c2.Timeout = deadline.Sub(time.Now())
- c = &c2
- }
- req2 := *req
- return c, &req2
-}
diff --git a/rpc/client_context_go1.5.go b/rpc/client_context_go1.5.go
deleted file mode 100644
index 4a007d9f8a..0000000000
--- a/rpc/client_context_go1.5.go
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright 2016 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see .
-
-// +build go1.5,!go1.6
-
-package rpc
-
-import (
- "net"
- "net/http"
- "time"
-
- "golang.org/x/net/context"
-)
-
-// In Go 1.5, dials cannot be canceled via a channel or context. The context deadline can
-// still be applied. Go 1.5 adds the ability to cancel HTTP requests via a channel.
-
-// contextDialer returns a dialer that applies the deadline value from the given context.
-func contextDialer(ctx context.Context) *net.Dialer {
- dialer := &net.Dialer{KeepAlive: tcpKeepAliveInterval}
- if deadline, ok := ctx.Deadline(); ok {
- dialer.Deadline = deadline
- } else {
- dialer.Deadline = time.Now().Add(defaultDialTimeout)
- }
- return dialer
-}
-
-// dialContext connects to the given address, aborting the dial if ctx is canceled.
-func dialContext(ctx context.Context, network, addr string) (net.Conn, error) {
- return contextDialer(ctx).Dial(network, addr)
-}
-
-// requestWithContext copies req, adding the cancelation channel and deadline from ctx.
-func requestWithContext(c *http.Client, req *http.Request, ctx context.Context) (*http.Client, *http.Request) {
- // Set Timeout on the client if the context has a deadline.
- // Note that there is no default timeout (unlike in contextDialer) because
- // the timeout applies to the entire request, including reads from body.
- if deadline, ok := ctx.Deadline(); ok {
- c2 := *c
- c2.Timeout = deadline.Sub(time.Now())
- c = &c2
- }
- req2 := *req
- req2.Cancel = ctx.Done()
- return c, &req2
-}
diff --git a/rpc/client_context_go1.6.go b/rpc/client_context_go1.6.go
deleted file mode 100644
index 67777ddc6a..0000000000
--- a/rpc/client_context_go1.6.go
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright 2016 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see .
-
-// +build go1.6,!go1.7
-
-package rpc
-
-import (
- "net"
- "net/http"
- "time"
-
- "golang.org/x/net/context"
-)
-
-// In Go 1.6, net.Dialer gained the ability to cancel via a channel.
-
-// contextDialer returns a dialer that applies the deadline value from the given context.
-func contextDialer(ctx context.Context) *net.Dialer {
- dialer := &net.Dialer{Cancel: ctx.Done(), KeepAlive: tcpKeepAliveInterval}
- if deadline, ok := ctx.Deadline(); ok {
- dialer.Deadline = deadline
- } else {
- dialer.Deadline = time.Now().Add(defaultDialTimeout)
- }
- return dialer
-}
-
-// dialContext connects to the given address, aborting the dial if ctx is canceled.
-func dialContext(ctx context.Context, network, addr string) (net.Conn, error) {
- return contextDialer(ctx).Dial(network, addr)
-}
-
-// requestWithContext copies req, adding the cancelation channel and deadline from ctx.
-func requestWithContext(c *http.Client, req *http.Request, ctx context.Context) (*http.Client, *http.Request) {
- // We set Timeout on the client for Go <= 1.5. There
- // is no need to do that here because the dial will be canceled
- // by package http.
- req2 := *req
- req2.Cancel = ctx.Done()
- return c, &req2
-}
diff --git a/rpc/client_context_go1.7.go b/rpc/client_context_go1.7.go
deleted file mode 100644
index 56ce12ab8e..0000000000
--- a/rpc/client_context_go1.7.go
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright 2016 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see .
-
-// +build go1.7
-
-package rpc
-
-import (
- "context"
- "net"
- "net/http"
- "time"
-)
-
-// In Go 1.7, context moved into the standard library and support
-// for cancelation via context was added to net.Dialer and http.Request.
-
-// contextDialer returns a dialer that applies the deadline value from the given context.
-func contextDialer(ctx context.Context) *net.Dialer {
- dialer := &net.Dialer{Cancel: ctx.Done(), KeepAlive: tcpKeepAliveInterval}
- if deadline, ok := ctx.Deadline(); ok {
- dialer.Deadline = deadline
- } else {
- dialer.Deadline = time.Now().Add(defaultDialTimeout)
- }
- return dialer
-}
-
-// dialContext connects to the given address, aborting the dial if ctx is canceled.
-func dialContext(ctx context.Context, network, addr string) (net.Conn, error) {
- d := &net.Dialer{KeepAlive: tcpKeepAliveInterval}
- return d.DialContext(ctx, network, addr)
-}
-
-// requestWithContext copies req, adding the cancelation channel and deadline from ctx.
-func requestWithContext(c *http.Client, req *http.Request, ctx context.Context) (*http.Client, *http.Request) {
- return c, req.WithContext(ctx)
-}
diff --git a/rpc/client_example_test.go b/rpc/client_example_test.go
index 3462b3685b..8276a9eadd 100644
--- a/rpc/client_example_test.go
+++ b/rpc/client_example_test.go
@@ -17,12 +17,12 @@
package rpc_test
import (
+ "context"
"fmt"
"math/big"
"time"
"github.com/ethereum/go-ethereum/rpc"
- "golang.org/x/net/context"
)
// In this example, our client whishes to track the latest 'block number'
diff --git a/rpc/client_test.go b/rpc/client_test.go
index 476c8c6f36..41471dceaf 100644
--- a/rpc/client_test.go
+++ b/rpc/client_test.go
@@ -17,6 +17,7 @@
package rpc
import (
+ "context"
"fmt"
"math/rand"
"net"
@@ -30,9 +31,7 @@ import (
"time"
"github.com/davecgh/go-spew/spew"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
- "golang.org/x/net/context"
+ "github.com/ethereum/go-ethereum/log"
)
func TestClientRequest(t *testing.T) {
@@ -147,10 +146,6 @@ func testClientCancel(transport string, t *testing.T) {
// You probably want to run with -parallel 1 or comment out
// the call to t.Parallel if you enable the logging.
t.Parallel()
- // glog.SetV(6)
- // glog.SetToStderr(true)
- // defer glog.SetToStderr(false)
- // glog.Infoln("testing ", transport)
// The actual test starts here.
var (
@@ -181,7 +176,7 @@ func testClientCancel(transport string, t *testing.T) {
// The key thing here is that no call will ever complete successfully.
err := client.CallContext(ctx, nil, "service_sleep", 2*maxContextCancelTimeout)
if err != nil {
- glog.V(logger.Debug).Infoln("got expected error:", err)
+ log.Debug(fmt.Sprint("got expected error:", err))
} else {
t.Errorf("no error for call with %v wait time", timeout)
}
@@ -532,7 +527,7 @@ func (l *flakeyListener) Accept() (net.Conn, error) {
if err == nil {
timeout := time.Duration(rand.Int63n(int64(l.maxKillTimeout)))
time.AfterFunc(timeout, func() {
- glog.V(logger.Debug).Infof("killing conn %v after %v", c.LocalAddr(), timeout)
+ log.Debug(fmt.Sprintf("killing conn %v after %v", c.LocalAddr(), timeout))
c.Close()
})
}
diff --git a/rpc/http.go b/rpc/http.go
index 7d4fe5d474..89175b1496 100644
--- a/rpc/http.go
+++ b/rpc/http.go
@@ -18,6 +18,7 @@ package rpc
import (
"bytes"
+ "context"
"encoding/json"
"fmt"
"io"
@@ -29,7 +30,6 @@ import (
"time"
"github.com/rs/cors"
- "golang.org/x/net/context"
)
const (
@@ -115,11 +115,11 @@ func (hc *httpConn) doRequest(ctx context.Context, msg interface{}) (io.ReadClos
if err != nil {
return nil, err
}
- client, req := requestWithContext(hc.client, hc.req, ctx)
+ req := hc.req.WithContext(ctx)
req.Body = ioutil.NopCloser(bytes.NewReader(body))
req.ContentLength = int64(len(body))
- resp, err := client.Do(req)
+ resp, err := hc.client.Do(req)
if err != nil {
return nil, err
}
@@ -171,6 +171,7 @@ func newCorsHandler(srv *Server, corsString string) http.Handler {
AllowedOrigins: allowedOrigins,
AllowedMethods: []string{"POST", "GET"},
MaxAge: 600,
+ AllowedHeaders: []string{"*"},
})
return c.Handler(srv)
}
diff --git a/rpc/inproc.go b/rpc/inproc.go
index f72b974977..595a7ca651 100644
--- a/rpc/inproc.go
+++ b/rpc/inproc.go
@@ -17,9 +17,8 @@
package rpc
import (
+ "context"
"net"
-
- "golang.org/x/net/context"
)
// NewInProcClient attaches an in-process connection to the given RPC server.
diff --git a/rpc/ipc.go b/rpc/ipc.go
index c2b9e38710..8de18a56fe 100644
--- a/rpc/ipc.go
+++ b/rpc/ipc.go
@@ -17,11 +17,11 @@
package rpc
import (
+ "context"
+ "fmt"
"net"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
- "golang.org/x/net/context"
+ "github.com/ethereum/go-ethereum/log"
)
// CreateIPCListener creates an listener, on Unix platforms this is a unix socket, on
@@ -37,7 +37,7 @@ func (srv *Server) ServeListener(l net.Listener) error {
if err != nil {
return err
}
- glog.V(logger.Detail).Infoln("accepted conn", conn.RemoteAddr())
+ log.Trace(fmt.Sprint("accepted conn", conn.RemoteAddr()))
go srv.ServeCodec(NewJSONCodec(conn), OptionMethodInvocation|OptionSubscriptions)
}
}
diff --git a/rpc/ipc_unix.go b/rpc/ipc_unix.go
index a25b216277..0851ea61e1 100644
--- a/rpc/ipc_unix.go
+++ b/rpc/ipc_unix.go
@@ -19,11 +19,10 @@
package rpc
import (
+ "context"
"net"
"os"
"path/filepath"
-
- "golang.org/x/net/context"
)
// ipcListen will create a Unix socket on the given endpoint.
diff --git a/rpc/ipc_windows.go b/rpc/ipc_windows.go
index 68234d2151..ca56a3ce43 100644
--- a/rpc/ipc_windows.go
+++ b/rpc/ipc_windows.go
@@ -19,10 +19,10 @@
package rpc
import (
+ "context"
"net"
"time"
- "golang.org/x/net/context"
"gopkg.in/natefinch/npipe.v2"
)
diff --git a/rpc/json.go b/rpc/json.go
index 61a4ddf432..c777fab6eb 100644
--- a/rpc/json.go
+++ b/rpc/json.go
@@ -26,8 +26,7 @@ import (
"strings"
"sync"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/log"
)
const (
@@ -171,7 +170,7 @@ func parseRequest(incomingMsg json.RawMessage) ([]rpcRequest, bool, Error) {
// first param must be subscription name
var subscribeMethod [1]string
if err := json.Unmarshal(in.Payload, &subscribeMethod); err != nil {
- glog.V(logger.Debug).Infof("Unable to parse subscription method: %v\n", err)
+ log.Debug(fmt.Sprintf("Unable to parse subscription method: %v\n", err))
return nil, false, &invalidRequestError{"Unable to parse subscription request"}
}
@@ -224,7 +223,7 @@ func parseBatchRequest(incomingMsg json.RawMessage) ([]rpcRequest, bool, Error)
// first param must be subscription name
var subscribeMethod [1]string
if err := json.Unmarshal(r.Payload, &subscribeMethod); err != nil {
- glog.V(logger.Debug).Infof("Unable to parse subscription method: %v\n", err)
+ log.Debug(fmt.Sprintf("Unable to parse subscription method: %v\n", err))
return nil, false, &invalidRequestError{"Unable to parse subscription request"}
}
diff --git a/rpc/server.go b/rpc/server.go
index 996c637004..8627b55928 100644
--- a/rpc/server.go
+++ b/rpc/server.go
@@ -17,14 +17,14 @@
package rpc
import (
+ "context"
"fmt"
"reflect"
"runtime"
+ "sync"
"sync/atomic"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
- "golang.org/x/net/context"
+ "github.com/ethereum/go-ethereum/log"
"gopkg.in/fatih/set.v0"
)
@@ -144,14 +144,15 @@ func hasOption(option CodecOption, options []CodecOption) bool {
// requests until the codec returns an error when reading a request (in most cases
// an EOF). It executes requests in parallel when singleShot is false.
func (s *Server) serveRequest(codec ServerCodec, singleShot bool, options CodecOption) error {
+ var pend sync.WaitGroup
+
defer func() {
if err := recover(); err != nil {
const size = 64 << 10
buf := make([]byte, size)
buf = buf[:runtime.Stack(buf, false)]
- glog.Errorln(string(buf))
+ log.Error(fmt.Sprint(string(buf)))
}
-
s.codecsMu.Lock()
s.codecs.Remove(codec)
s.codecsMu.Unlock()
@@ -180,8 +181,13 @@ func (s *Server) serveRequest(codec ServerCodec, singleShot bool, options CodecO
for atomic.LoadInt32(&s.run) == 1 {
reqs, batch, err := s.readRequest(codec)
if err != nil {
- glog.V(logger.Debug).Infof("read error %v\n", err)
- codec.Write(codec.CreateErrorResponse(nil, err))
+ // If a parsing error occurred, send an error
+ if err.Error() != "EOF" {
+ log.Debug(fmt.Sprintf("read error %v\n", err))
+ codec.Write(codec.CreateErrorResponse(nil, err))
+ }
+ // Error or end of stream, wait for requests and tear down
+ pend.Wait()
return nil
}
@@ -200,20 +206,27 @@ func (s *Server) serveRequest(codec ServerCodec, singleShot bool, options CodecO
}
return nil
}
-
- if singleShot && batch {
- s.execBatch(ctx, codec, reqs)
+ // If a single shot request is executing, run and return immediately
+ if singleShot {
+ if batch {
+ s.execBatch(ctx, codec, reqs)
+ } else {
+ s.exec(ctx, codec, reqs[0])
+ }
return nil
- } else if singleShot && !batch {
- s.exec(ctx, codec, reqs[0])
- return nil
- } else if !singleShot && batch {
- go s.execBatch(ctx, codec, reqs)
- } else {
- go s.exec(ctx, codec, reqs[0])
}
- }
+ // For multi-shot connections, start a goroutine to serve and loop back
+ pend.Add(1)
+ go func(reqs []*serverRequest, batch bool) {
+ defer pend.Done()
+ if batch {
+ s.execBatch(ctx, codec, reqs)
+ } else {
+ s.exec(ctx, codec, reqs[0])
+ }
+ }(reqs, batch)
+ }
return nil
}
@@ -236,7 +249,7 @@ func (s *Server) ServeSingleRequest(codec ServerCodec, options CodecOption) {
// close all codecs which will cancel pending requests/subscriptions.
func (s *Server) Stop() {
if atomic.CompareAndSwapInt32(&s.run, 1, 0) {
- glog.V(logger.Debug).Infoln("RPC Server shutdown initiatied")
+ log.Debug(fmt.Sprint("RPC Server shutdown initiatied"))
s.codecsMu.Lock()
defer s.codecsMu.Unlock()
s.codecs.Each(func(c interface{}) bool {
@@ -341,7 +354,7 @@ func (s *Server) exec(ctx context.Context, codec ServerCodec, req *serverRequest
}
if err := codec.Write(response); err != nil {
- glog.V(logger.Error).Infof("%v\n", err)
+ log.Error(fmt.Sprintf("%v\n", err))
codec.Close()
}
@@ -368,7 +381,7 @@ func (s *Server) execBatch(ctx context.Context, codec ServerCodec, requests []*s
}
if err := codec.Write(responses); err != nil {
- glog.V(logger.Error).Infof("%v\n", err)
+ log.Error(fmt.Sprintf("%v\n", err))
codec.Close()
}
diff --git a/rpc/server_test.go b/rpc/server_test.go
index c3c88fab75..90d62f26d8 100644
--- a/rpc/server_test.go
+++ b/rpc/server_test.go
@@ -17,13 +17,12 @@
package rpc
import (
+ "context"
"encoding/json"
"net"
"reflect"
"testing"
"time"
-
- "golang.org/x/net/context"
)
type Service struct{}
diff --git a/rpc/subscription.go b/rpc/subscription.go
index bcdc3cdfca..9ab6af9e14 100644
--- a/rpc/subscription.go
+++ b/rpc/subscription.go
@@ -17,10 +17,9 @@
package rpc
import (
+ "context"
"errors"
"sync"
-
- "golang.org/x/net/context"
)
var (
diff --git a/rpc/subscription_test.go b/rpc/subscription_test.go
index 00c4e0e354..345b4e5f29 100644
--- a/rpc/subscription_test.go
+++ b/rpc/subscription_test.go
@@ -17,13 +17,12 @@
package rpc
import (
+ "context"
"encoding/json"
"net"
"sync"
"testing"
"time"
-
- "golang.org/x/net/context"
)
type NotificationTestService struct {
diff --git a/rpc/utils.go b/rpc/utils.go
index c249e9b4a8..2506c48331 100644
--- a/rpc/utils.go
+++ b/rpc/utils.go
@@ -18,6 +18,7 @@ package rpc
import (
"bufio"
+ "context"
crand "crypto/rand"
"encoding/binary"
"encoding/hex"
@@ -29,8 +30,6 @@ import (
"time"
"unicode"
"unicode/utf8"
-
- "golang.org/x/net/context"
)
var (
diff --git a/rpc/websocket.go b/rpc/websocket.go
index fc3cd07099..5870108206 100644
--- a/rpc/websocket.go
+++ b/rpc/websocket.go
@@ -17,6 +17,7 @@
package rpc
import (
+ "context"
"crypto/tls"
"fmt"
"net"
@@ -24,10 +25,9 @@ import (
"net/url"
"os"
"strings"
+ "time"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
- "golang.org/x/net/context"
+ "github.com/ethereum/go-ethereum/log"
"golang.org/x/net/websocket"
"gopkg.in/fatih/set.v0"
)
@@ -76,14 +76,14 @@ func wsHandshakeValidator(allowedOrigins []string) func(*websocket.Config, *http
}
}
- glog.V(logger.Debug).Infof("Allowed origin(s) for WS RPC interface %v\n", origins.List())
+ log.Debug(fmt.Sprintf("Allowed origin(s) for WS RPC interface %v\n", origins.List()))
f := func(cfg *websocket.Config, req *http.Request) error {
origin := strings.ToLower(req.Header.Get("Origin"))
if allowAllOrigins || origins.Has(origin) {
return nil
}
- glog.V(logger.Debug).Infof("origin '%s' not allowed on WS-RPC interface\n", origin)
+ log.Debug(fmt.Sprintf("origin '%s' not allowed on WS-RPC interface\n", origin))
return fmt.Errorf("origin %s not allowed", origin)
}
@@ -150,3 +150,18 @@ func wsDialAddress(location *url.URL) string {
}
return location.Host
}
+
+func dialContext(ctx context.Context, network, addr string) (net.Conn, error) {
+ d := &net.Dialer{KeepAlive: tcpKeepAliveInterval}
+ return d.DialContext(ctx, network, addr)
+}
+
+func contextDialer(ctx context.Context) *net.Dialer {
+ dialer := &net.Dialer{Cancel: ctx.Done(), KeepAlive: tcpKeepAliveInterval}
+ if deadline, ok := ctx.Deadline(); ok {
+ dialer.Deadline = deadline
+ } else {
+ dialer.Deadline = time.Now().Add(defaultDialTimeout)
+ }
+ return dialer
+}
diff --git a/swarm/api/api.go b/swarm/api/api.go
index f92a14653d..7af27208df 100644
--- a/swarm/api/api.go
+++ b/swarm/api/api.go
@@ -25,8 +25,7 @@ import (
"sync"
"github.com/ethereum/go-ethereum/common"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/swarm/storage"
)
@@ -72,9 +71,9 @@ type ErrResolve error
// DNS Resolver
func (self *Api) Resolve(hostPort string, nameresolver bool) (storage.Key, error) {
- glog.V(logger.Detail).Infof("Resolving : %v", hostPort)
+ log.Trace(fmt.Sprintf("Resolving : %v", hostPort))
if hashMatcher.MatchString(hostPort) || self.dns == nil {
- glog.V(logger.Detail).Infof("host is a contentHash: '%v'", hostPort)
+ log.Trace(fmt.Sprintf("host is a contentHash: '%v'", hostPort))
return storage.Key(common.Hex2Bytes(hostPort)), nil
}
if !nameresolver {
@@ -83,9 +82,9 @@ func (self *Api) Resolve(hostPort string, nameresolver bool) (storage.Key, error
contentHash, err := self.dns.Resolve(hostPort)
if err != nil {
err = ErrResolve(err)
- glog.V(logger.Warn).Infof("DNS error : %v", err)
+ log.Warn(fmt.Sprintf("DNS error : %v", err))
}
- glog.V(logger.Detail).Infof("host lookup: %v -> %v", err)
+ log.Trace(fmt.Sprintf("host lookup: %v -> %v", hostPort, contentHash))
return contentHash[:], err
}
func Parse(uri string) (hostPort, path string) {
@@ -110,7 +109,7 @@ func Parse(uri string) (hostPort, path string) {
path = parts[i]
}
}
- glog.V(logger.Debug).Infof("host: '%s', path '%s' requested.", hostPort, path)
+ log.Debug(fmt.Sprintf("host: '%s', path '%s' requested.", hostPort, path))
return
}
@@ -118,7 +117,7 @@ func (self *Api) parseAndResolve(uri string, nameresolver bool) (key storage.Key
hostPort, path = Parse(uri)
//resolving host and port
contentHash, err := self.Resolve(hostPort, nameresolver)
- glog.V(logger.Debug).Infof("Resolved '%s' to contentHash: '%s', path: '%s'", uri, contentHash, path)
+ log.Debug(fmt.Sprintf("Resolved '%s' to contentHash: '%s', path: '%s'", uri, contentHash, path))
return contentHash[:], hostPort, path, err
}
@@ -152,11 +151,11 @@ func (self *Api) Get(uri string, nameresolver bool) (reader storage.LazySectionR
quitC := make(chan bool)
trie, err := loadManifest(self.dpa, key, quitC)
if err != nil {
- glog.V(logger.Warn).Infof("loadManifestTrie error: %v", err)
+ log.Warn(fmt.Sprintf("loadManifestTrie error: %v", err))
return
}
- glog.V(logger.Detail).Infof("getEntry(%s)", path)
+ log.Trace(fmt.Sprintf("getEntry(%s)", path))
entry, _ := trie.getEntry(path)
@@ -164,12 +163,12 @@ func (self *Api) Get(uri string, nameresolver bool) (reader storage.LazySectionR
key = common.Hex2Bytes(entry.Hash)
status = entry.Status
mimeType = entry.ContentType
- glog.V(logger.Detail).Infof("content lookup key: '%v' (%v)", key, mimeType)
+ log.Trace(fmt.Sprintf("content lookup key: '%v' (%v)", key, mimeType))
reader = self.dpa.Retrieve(key)
} else {
status = http.StatusNotFound
err = fmt.Errorf("manifest entry for '%s' not found", path)
- glog.V(logger.Warn).Infof("%v", err)
+ log.Warn(fmt.Sprintf("%v", err))
}
return
}
diff --git a/swarm/api/api_test.go b/swarm/api/api_test.go
index b098119591..16e90dd329 100644
--- a/swarm/api/api_test.go
+++ b/swarm/api/api_test.go
@@ -17,13 +17,13 @@
package api
import (
+ "fmt"
"io"
"io/ioutil"
"os"
"testing"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/swarm/storage"
)
@@ -76,7 +76,7 @@ func checkResponse(t *testing.T, resp *testResponse, exp *Response) {
// func expResponse(content []byte, mimeType string, status int) *Response {
func expResponse(content string, mimeType string, status int) *Response {
- glog.V(logger.Detail).Infof("expected content (%v): %v ", len(content), content)
+ log.Trace(fmt.Sprintf("expected content (%v): %v ", len(content), content))
return &Response{mimeType, status, int64(len(content)), content}
}
@@ -91,7 +91,7 @@ func testGet(t *testing.T, api *Api, bzzhash string) *testResponse {
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
- glog.V(logger.Detail).Infof("reader size: %v ", size)
+ log.Trace(fmt.Sprintf("reader size: %v ", size))
s := make([]byte, size)
_, err = reader.Read(s)
if err != io.EOF {
diff --git a/swarm/api/filesystem.go b/swarm/api/filesystem.go
index 96aaf36df7..c2583e265f 100644
--- a/swarm/api/filesystem.go
+++ b/swarm/api/filesystem.go
@@ -26,8 +26,7 @@ import (
"sync"
"github.com/ethereum/go-ethereum/common"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/swarm/storage"
)
@@ -63,7 +62,7 @@ func (self *FileSystem) Upload(lpath, index string) (string, error) {
var start int
if stat.IsDir() {
start = len(localpath)
- glog.V(logger.Debug).Infof("uploading '%s'", localpath)
+ log.Debug(fmt.Sprintf("uploading '%s'", localpath))
err = filepath.Walk(localpath, func(path string, info os.FileInfo, err error) error {
if (err == nil) && !info.IsDir() {
//fmt.Printf("lp %s path %s\n", localpath, path)
@@ -198,7 +197,7 @@ func (self *FileSystem) Download(bzzpath, localpath string) error {
quitC := make(chan bool)
trie, err := loadManifest(self.api.dpa, key, quitC)
if err != nil {
- glog.V(logger.Warn).Infof("fs.Download: loadManifestTrie error: %v", err)
+ log.Warn(fmt.Sprintf("fs.Download: loadManifestTrie error: %v", err))
return err
}
@@ -212,7 +211,7 @@ func (self *FileSystem) Download(bzzpath, localpath string) error {
prevPath := lpath
err = trie.listWithPrefix(path, quitC, func(entry *manifestTrieEntry, suffix string) {
- glog.V(logger.Detail).Infof("fs.Download: %#v", entry)
+ log.Trace(fmt.Sprintf("fs.Download: %#v", entry))
key = common.Hex2Bytes(entry.Hash)
path := lpath + "/" + suffix
diff --git a/swarm/api/fuse.go b/swarm/api/fuse.go
new file mode 100644
index 0000000000..4b1f817f8c
--- /dev/null
+++ b/swarm/api/fuse.go
@@ -0,0 +1,139 @@
+// Copyright 2017 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+// +build !windows
+
+package api
+
+import (
+ "io"
+ "os"
+
+ "bazil.org/fuse"
+ "bazil.org/fuse/fs"
+ "github.com/ethereum/go-ethereum/log"
+ "github.com/ethereum/go-ethereum/swarm/storage"
+ "golang.org/x/net/context"
+)
+
+
+
+
+// Data structures used for Fuse filesystem, serving directories and serving files to Fuse driver
+type FS struct {
+ root *Dir
+}
+
+type Dir struct {
+ inode uint64
+ name string
+ path string
+ directories []*Dir
+ files []*File
+}
+
+type File struct {
+ inode uint64
+ name string
+ path string
+ key storage.Key
+ swarmApi *Api
+ fileSize uint64
+ reader storage.LazySectionReader
+}
+
+
+// Functions which satisfy the Fuse File System requests
+func (filesystem *FS) Root() (fs.Node, error) {
+ return filesystem.root, nil
+}
+
+func (directory *Dir) Attr(ctx context.Context, a *fuse.Attr) error {
+ a.Inode = directory.inode
+ //TODO: need to get permission as argument
+ a.Mode = os.ModeDir | 0500
+ a.Uid = uint32(os.Getuid())
+ a.Gid = uint32(os.Getegid())
+ return nil
+}
+
+func (directory *Dir) Lookup(ctx context.Context, name string) (fs.Node, error) {
+ if directory.files != nil {
+ for _, n := range directory.files {
+ if n.name == name {
+ return n, nil
+ }
+ }
+ }
+ if directory.directories != nil {
+ for _, n := range directory.directories {
+ if n.name == name {
+ return n, nil
+ }
+ }
+ }
+ return nil, fuse.ENOENT
+}
+
+func (d *Dir) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) {
+ var children []fuse.Dirent
+ if d.files != nil {
+ for _, file := range d.files {
+ children = append(children, fuse.Dirent{Inode: file.inode, Type: fuse.DT_File, Name: file.name})
+ }
+ }
+ if d.directories != nil {
+ for _, dir := range d.directories {
+ children = append(children, fuse.Dirent{Inode: dir.inode, Type: fuse.DT_Dir, Name: dir.name})
+ }
+ }
+ return children, nil
+}
+
+func (file *File) Attr(ctx context.Context, a *fuse.Attr) error {
+
+ a.Inode = file.inode
+ //TODO: need to get permission as argument
+ a.Mode = 0500
+ a.Uid = uint32(os.Getuid())
+ a.Gid = uint32(os.Getegid())
+
+
+ reader := file.swarmApi.Retrieve(file.key)
+ quitC := make(chan bool)
+ size, err := reader.Size(quitC)
+ if err != nil {
+ log.Warn("Couldnt file size of file %s : %v", file.path, err)
+ a.Size = uint64(0)
+ }
+ a.Size = uint64(size)
+ file.fileSize = a.Size
+ return nil
+}
+
+var _ = fs.HandleReader(&File{})
+
+func (file *File) Read(ctx context.Context, req *fuse.ReadRequest, resp *fuse.ReadResponse) error {
+ buf := make([]byte, req.Size)
+ reader := file.swarmApi.Retrieve(file.key)
+ n, err := reader.ReadAt(buf, req.Offset)
+ if err == io.ErrUnexpectedEOF || err == io.EOF {
+ err = nil
+ }
+ resp.Data = buf[:n]
+ return err
+
+}
diff --git a/swarm/api/http/roundtripper.go b/swarm/api/http/roundtripper.go
index 7b5bbc8838..328177a218 100644
--- a/swarm/api/http/roundtripper.go
+++ b/swarm/api/http/roundtripper.go
@@ -20,8 +20,7 @@ import (
"fmt"
"net/http"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/log"
)
/*
@@ -58,7 +57,7 @@ func (self *RoundTripper) RoundTrip(req *http.Request) (resp *http.Response, err
host = "localhost"
}
url := fmt.Sprintf("http://%s:%s/%s:/%s/%s", host, self.Port, req.Proto, req.URL.Host, req.URL.Path)
- glog.V(logger.Info).Infof("roundtripper: proxying request '%s' to '%s'", req.RequestURI, url)
+ log.Info(fmt.Sprintf("roundtripper: proxying request '%s' to '%s'", req.RequestURI, url))
reqProxy, err := http.NewRequest(req.Method, url, req.Body)
if err != nil {
return nil, err
diff --git a/swarm/api/http/server.go b/swarm/api/http/server.go
index afd867efc8..ae113750ff 100644
--- a/swarm/api/http/server.go
+++ b/swarm/api/http/server.go
@@ -21,6 +21,7 @@ package http
import (
"bytes"
+ "fmt"
"io"
"net/http"
"regexp"
@@ -29,8 +30,7 @@ import (
"time"
"github.com/ethereum/go-ethereum/common"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/swarm/api"
"github.com/ethereum/go-ethereum/swarm/storage"
"github.com/rs/cors"
@@ -82,11 +82,12 @@ func StartHttpServer(api *api.Api, server *Server) {
AllowedOrigins: allowedOrigins,
AllowedMethods: []string{"POST", "GET", "DELETE", "PATCH", "PUT"},
MaxAge: 600,
+ AllowedHeaders: []string{"*"},
})
hdlr := c.Handler(serveMux)
go http.ListenAndServe(server.Addr, hdlr)
- glog.V(logger.Info).Infof("Swarm HTTP proxy started on localhost:%s", server.Addr)
+ log.Info(fmt.Sprintf("Swarm HTTP proxy started on localhost:%s", server.Addr))
}
func handler(w http.ResponseWriter, r *http.Request, a *api.Api) {
@@ -100,13 +101,13 @@ func handler(w http.ResponseWriter, r *http.Request, a *api.Api) {
// return
// }
// }
- glog.V(logger.Debug).Infof("HTTP %s request URL: '%s', Host: '%s', Path: '%s', Referer: '%s', Accept: '%s'", r.Method, r.RequestURI, requestURL.Host, requestURL.Path, r.Referer(), r.Header.Get("Accept"))
+ log.Debug(fmt.Sprintf("HTTP %s request URL: '%s', Host: '%s', Path: '%s', Referer: '%s', Accept: '%s'", r.Method, r.RequestURI, requestURL.Host, requestURL.Path, r.Referer(), r.Header.Get("Accept")))
uri := requestURL.Path
var raw, nameresolver bool
var proto string
// HTTP-based URL protocol handler
- glog.V(logger.Debug).Infof("BZZ request URI: '%s'", uri)
+ log.Debug(fmt.Sprintf("BZZ request URI: '%s'", uri))
path := bzzPrefix.ReplaceAllStringFunc(uri, func(p string) string {
proto = p
@@ -115,24 +116,18 @@ func handler(w http.ResponseWriter, r *http.Request, a *api.Api) {
// protocol identification (ugly)
if proto == "" {
- if glog.V(logger.Error) {
- glog.Errorf(
- "[BZZ] Swarm: Protocol error in request `%s`.",
- uri,
- )
- http.Error(w, "Invalid request URL: need access protocol (bzz:/, bzzr:/, bzzi:/) as first element in path.", http.StatusBadRequest)
- return
- }
+ log.Error(fmt.Sprintf("[BZZ] Swarm: Protocol error in request `%s`.", uri))
+ http.Error(w, "Invalid request URL: need access protocol (bzz:/, bzzr:/, bzzi:/) as first element in path.", http.StatusBadRequest)
+ return
}
if len(proto) > 4 {
raw = proto[1:5] == "bzzr"
nameresolver = proto[1:5] != "bzzi"
}
- glog.V(logger.Debug).Infof(
- "[BZZ] Swarm: %s request over protocol %s '%s' received.",
- r.Method, proto, path,
- )
+ log.Debug("", "msg", log.Lazy{Fn: func() string {
+ return fmt.Sprintf("[BZZ] Swarm: %s request over protocol %s '%s' received.", r.Method, proto, path)
+ }})
switch {
case r.Method == "POST" || r.Method == "PUT":
@@ -142,7 +137,7 @@ func handler(w http.ResponseWriter, r *http.Request, a *api.Api) {
}
key, err := a.Store(io.LimitReader(r.Body, r.ContentLength), r.ContentLength, nil)
if err == nil {
- glog.V(logger.Debug).Infof("Content for %v stored", key.Log())
+ log.Debug(fmt.Sprintf("Content for %v stored", key.Log()))
} else {
http.Error(w, err.Error(), http.StatusBadRequest)
return
@@ -164,10 +159,10 @@ func handler(w http.ResponseWriter, r *http.Request, a *api.Api) {
path = api.RegularSlashes(path)
mime := r.Header.Get("Content-Type")
// TODO proper root hash separation
- glog.V(logger.Debug).Infof("Modify '%s' to store %v as '%s'.", path, key.Log(), mime)
+ log.Debug(fmt.Sprintf("Modify '%s' to store %v as '%s'.", path, key.Log(), mime))
newKey, err := a.Modify(path, common.Bytes2Hex(key), mime, nameresolver)
if err == nil {
- glog.V(logger.Debug).Infof("Swarm replaced manifest by '%s'", newKey)
+ log.Debug(fmt.Sprintf("Swarm replaced manifest by '%s'", newKey))
w.Header().Set("Content-Type", "text/plain")
http.ServeContent(w, r, "", time.Now(), bytes.NewReader([]byte(newKey)))
} else {
@@ -182,10 +177,10 @@ func handler(w http.ResponseWriter, r *http.Request, a *api.Api) {
return
} else {
path = api.RegularSlashes(path)
- glog.V(logger.Debug).Infof("Delete '%s'.", path)
+ log.Debug(fmt.Sprintf("Delete '%s'.", path))
newKey, err := a.Modify(path, "", "", nameresolver)
if err == nil {
- glog.V(logger.Debug).Infof("Swarm replaced manifest by '%s'", newKey)
+ log.Debug(fmt.Sprintf("Swarm replaced manifest by '%s'", newKey))
w.Header().Set("Content-Type", "text/plain")
http.ServeContent(w, r, "", time.Now(), bytes.NewReader([]byte(newKey)))
} else {
@@ -206,7 +201,7 @@ func handler(w http.ResponseWriter, r *http.Request, a *api.Api) {
if parsedurl == path {
key, err := a.Resolve(parsedurl, nameresolver)
if err != nil {
- glog.V(logger.Error).Infof("%v", err)
+ log.Error(fmt.Sprintf("%v", err))
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
@@ -226,12 +221,12 @@ func handler(w http.ResponseWriter, r *http.Request, a *api.Api) {
quitC := make(chan bool)
size, err := reader.Size(quitC)
if err != nil {
- glog.V(logger.Debug).Infof("Could not determine size: %v", err.Error())
+ log.Debug(fmt.Sprintf("Could not determine size: %v", err.Error()))
//An error on call to Size means we don't have the root chunk
http.Error(w, err.Error(), http.StatusNotFound)
return
}
- glog.V(logger.Debug).Infof("Reading %d bytes.", size)
+ log.Debug(fmt.Sprintf("Reading %d bytes.", size))
// setting mime type
qv := requestURL.Query()
@@ -242,11 +237,11 @@ func handler(w http.ResponseWriter, r *http.Request, a *api.Api) {
w.Header().Set("Content-Type", mimeType)
http.ServeContent(w, r, uri, forever(), reader)
- glog.V(logger.Debug).Infof("Serve raw content '%s' (%d bytes) as '%s'", uri, size, mimeType)
+ log.Debug(fmt.Sprintf("Serve raw content '%s' (%d bytes) as '%s'", uri, size, mimeType))
// retrieve path via manifest
} else {
- glog.V(logger.Debug).Infof("Structured GET request '%s' received.", uri)
+ log.Debug(fmt.Sprintf("Structured GET request '%s' received.", uri))
// add trailing slash, if missing
if rootDocumentUri.MatchString(uri) {
http.Redirect(w, r, path+"/", http.StatusFound)
@@ -255,10 +250,10 @@ func handler(w http.ResponseWriter, r *http.Request, a *api.Api) {
reader, mimeType, status, err := a.Get(path, nameresolver)
if err != nil {
if _, ok := err.(api.ErrResolve); ok {
- glog.V(logger.Debug).Infof("%v", err)
+ log.Debug(fmt.Sprintf("%v", err))
status = http.StatusBadRequest
} else {
- glog.V(logger.Debug).Infof("error retrieving '%s': %v", uri, err)
+ log.Debug(fmt.Sprintf("error retrieving '%s': %v", uri, err))
status = http.StatusNotFound
}
http.Error(w, err.Error(), status)
@@ -274,12 +269,12 @@ func handler(w http.ResponseWriter, r *http.Request, a *api.Api) {
quitC := make(chan bool)
size, err := reader.Size(quitC)
if err != nil {
- glog.V(logger.Debug).Infof("Could not determine size: %v", err.Error())
+ log.Debug(fmt.Sprintf("Could not determine size: %v", err.Error()))
//An error on call to Size means we don't have the root chunk
http.Error(w, err.Error(), http.StatusNotFound)
return
}
- glog.V(logger.Debug).Infof("Served '%s' (%d bytes) as '%s' (status code: %v)", uri, size, mimeType, status)
+ log.Debug(fmt.Sprintf("Served '%s' (%d bytes) as '%s' (status code: %v)", uri, size, mimeType, status))
http.ServeContent(w, r, path, forever(), reader)
@@ -293,13 +288,11 @@ func (self *sequentialReader) ReadAt(target []byte, off int64) (n int, err error
self.lock.Lock()
// assert self.pos <= off
if self.pos > off {
- glog.V(logger.Error).Infof("non-sequential read attempted from sequentialReader; %d > %d",
- self.pos, off)
+ log.Error(fmt.Sprintf("non-sequential read attempted from sequentialReader; %d > %d", self.pos, off))
panic("Non-sequential read attempt")
}
if self.pos != off {
- glog.V(logger.Debug).Infof("deferred read in POST at position %d, offset %d.",
- self.pos, off)
+ log.Debug(fmt.Sprintf("deferred read in POST at position %d, offset %d.", self.pos, off))
wait := make(chan bool)
self.ahead[off] = wait
self.lock.Unlock()
@@ -315,10 +308,9 @@ func (self *sequentialReader) ReadAt(target []byte, off int64) (n int, err error
for localPos < len(target) {
n, err = self.reader.Read(target[localPos:])
localPos += n
- glog.V(logger.Debug).Infof("Read %d bytes into buffer size %d from POST, error %v.",
- n, len(target), err)
+ log.Debug(fmt.Sprintf("Read %d bytes into buffer size %d from POST, error %v.", n, len(target), err))
if err != nil {
- glog.V(logger.Debug).Infof("POST stream's reading terminated with %v.", err)
+ log.Debug(fmt.Sprintf("POST stream's reading terminated with %v.", err))
for i := range self.ahead {
self.ahead[i] <- true
delete(self.ahead, i)
@@ -330,8 +322,7 @@ func (self *sequentialReader) ReadAt(target []byte, off int64) (n int, err error
}
wait := self.ahead[self.pos]
if wait != nil {
- glog.V(logger.Debug).Infof("deferred read in POST at position %d triggered.",
- self.pos)
+ log.Debug(fmt.Sprintf("deferred read in POST at position %d triggered.", self.pos))
delete(self.ahead, self.pos)
close(wait)
}
diff --git a/swarm/api/http/server_test.go b/swarm/api/http/server_test.go
index 0785890978..88b49b9a5e 100644
--- a/swarm/api/http/server_test.go
+++ b/swarm/api/http/server_test.go
@@ -113,6 +113,9 @@ func TestBzzrGetPath(t *testing.T) {
url += common.ToHex(key[0])[2:] + "/" + k[1:] + "?content_type=text/plain"
}
resp, err = http.Get(url)
+ if err != nil {
+ t.Fatalf("Request failed: %v", err)
+ }
defer resp.Body.Close()
respbody, err = ioutil.ReadAll(resp.Body)
diff --git a/swarm/api/manifest.go b/swarm/api/manifest.go
index 36c0b04362..199f259e1f 100644
--- a/swarm/api/manifest.go
+++ b/swarm/api/manifest.go
@@ -23,8 +23,7 @@ import (
"sync"
"github.com/ethereum/go-ethereum/common"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/swarm/storage"
)
@@ -52,7 +51,7 @@ type manifestTrieEntry struct {
func loadManifest(dpa *storage.DPA, hash storage.Key, quitC chan bool) (trie *manifestTrie, err error) { // non-recursive, subtrees are downloaded on-demand
- glog.V(logger.Detail).Infof("manifest lookup key: '%v'.", hash.Log())
+ log.Trace(fmt.Sprintf("manifest lookup key: '%v'.", hash.Log()))
// retrieve manifest via DPA
manifestReader := dpa.Retrieve(hash)
return readManifest(manifestReader, hash, dpa, quitC)
@@ -70,23 +69,23 @@ func readManifest(manifestReader storage.LazySectionReader, hash storage.Key, dp
manifestData := make([]byte, size)
read, err := manifestReader.Read(manifestData)
if int64(read) < size {
- glog.V(logger.Detail).Infof("Manifest %v not found.", hash.Log())
+ log.Trace(fmt.Sprintf("Manifest %v not found.", hash.Log()))
if err == nil {
err = fmt.Errorf("Manifest retrieval cut short: read %v, expect %v", read, size)
}
return
}
- glog.V(logger.Detail).Infof("Manifest %v retrieved", hash.Log())
+ log.Trace(fmt.Sprintf("Manifest %v retrieved", hash.Log()))
man := manifestJSON{}
err = json.Unmarshal(manifestData, &man)
if err != nil {
err = fmt.Errorf("Manifest %v is malformed: %v", hash.Log(), err)
- glog.V(logger.Detail).Infof("%v", err)
+ log.Trace(fmt.Sprintf("%v", err))
return
}
- glog.V(logger.Detail).Infof("Manifest %v has %d entries.", hash.Log(), len(man.Entries))
+ log.Trace(fmt.Sprintf("Manifest %v has %d entries.", hash.Log(), len(man.Entries)))
trie = &manifestTrie{
dpa: dpa,
@@ -286,7 +285,7 @@ func (self *manifestTrie) listWithPrefix(prefix string, quitC chan bool, cb func
func (self *manifestTrie) findPrefixOf(path string, quitC chan bool) (entry *manifestTrieEntry, pos int) {
- glog.V(logger.Detail).Infof("findPrefixOf(%s)", path)
+ log.Trace(fmt.Sprintf("findPrefixOf(%s)", path))
if len(path) == 0 {
return self.entries[256], 0
@@ -298,9 +297,9 @@ func (self *manifestTrie) findPrefixOf(path string, quitC chan bool) (entry *man
return self.entries[256], 0
}
epl := len(entry.Path)
- glog.V(logger.Detail).Infof("path = %v entry.Path = %v epl = %v", path, entry.Path, epl)
+ log.Trace(fmt.Sprintf("path = %v entry.Path = %v epl = %v", path, entry.Path, epl))
if (len(path) >= epl) && (path[:epl] == entry.Path) {
- glog.V(logger.Detail).Infof("entry.ContentType = %v", entry.ContentType)
+ log.Trace(fmt.Sprintf("entry.ContentType = %v", entry.ContentType))
if entry.ContentType == manifestType {
err := self.loadSubTrie(entry, quitC)
if err != nil {
diff --git a/pow/block.go b/swarm/api/swarmfs.go
similarity index 63%
rename from pow/block.go
rename to swarm/api/swarmfs.go
index 11807113dc..8427d3c5b1 100644
--- a/pow/block.go
+++ b/swarm/api/swarmfs.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The go-ethereum Authors
+// Copyright 2017 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
@@ -14,24 +14,35 @@
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see .
-package pow
+package api
import (
- "math/big"
-
- "github.com/ethereum/go-ethereum/common"
- "github.com/ethereum/go-ethereum/core/types"
+ "time"
+ "sync"
)
-type Block interface {
- Difficulty() *big.Int
- HashNoNonce() common.Hash
- Nonce() uint64
- MixDigest() common.Hash
- NumberU64() uint64
+const (
+ Swarmfs_Version = "0.1"
+ mountTimeout = time.Second * 5
+ maxFuseMounts = 5
+)
+
+
+type SwarmFS struct {
+ swarmApi *Api
+ activeMounts map[string]*MountInfo
+ activeLock *sync.RWMutex
}
-type ChainManager interface {
- GetBlockByNumber(uint64) *types.Block
- CurrentBlock() *types.Block
+
+
+func NewSwarmFS(api *Api) *SwarmFS {
+ swarmfs := &SwarmFS{
+ swarmApi: api,
+ activeLock: &sync.RWMutex{},
+ activeMounts: map[string]*MountInfo{},
+ }
+ return swarmfs
}
+
+
diff --git a/swarm/api/swarmfs_unix.go b/swarm/api/swarmfs_unix.go
new file mode 100644
index 0000000000..ae0216e1d7
--- /dev/null
+++ b/swarm/api/swarmfs_unix.go
@@ -0,0 +1,266 @@
+// Copyright 2017 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+// +build linux darwin
+
+package api
+
+import (
+ "path/filepath"
+ "fmt"
+ "strings"
+ "time"
+ "github.com/ethereum/go-ethereum/swarm/storage"
+ "bazil.org/fuse"
+ "github.com/ethereum/go-ethereum/log"
+ "github.com/ethereum/go-ethereum/common"
+ "bazil.org/fuse/fs"
+ "sync"
+)
+
+
+var (
+ inode uint64 = 1
+ inodeLock sync.RWMutex
+)
+
+// information about every active mount
+type MountInfo struct {
+ mountPoint string
+ manifestHash string
+ resolvedKey storage.Key
+ rootDir *Dir
+ fuseConnection *fuse.Conn
+}
+
+// Inode numbers need to be unique, they are used for caching inside fuse
+func NewInode() uint64 {
+ inodeLock.Lock()
+ defer inodeLock.Unlock()
+ inode += 1
+ return inode
+}
+
+
+
+func (self *SwarmFS) Mount(mhash, mountpoint string) (string, error) {
+
+ self.activeLock.Lock()
+ defer self.activeLock.Unlock()
+
+ noOfActiveMounts := len(self.activeMounts)
+ if noOfActiveMounts >= maxFuseMounts {
+ err := fmt.Errorf("Max mount count reached. Cannot mount %s ", mountpoint)
+ log.Warn(err.Error())
+ return err.Error(), err
+ }
+
+ cleanedMountPoint, err := filepath.Abs(filepath.Clean(mountpoint))
+ if err != nil {
+ return err.Error(), err
+ }
+
+ if _, ok := self.activeMounts[cleanedMountPoint]; ok {
+ err := fmt.Errorf("Mountpoint %s already mounted.", cleanedMountPoint)
+ log.Warn(err.Error())
+ return err.Error(), err
+ }
+
+ log.Info(fmt.Sprintf("Attempting to mount %s ", cleanedMountPoint))
+ key, _, path, err := self.swarmApi.parseAndResolve(mhash, true)
+ if err != nil {
+ errStr := fmt.Sprintf("Could not resolve %s : %v", mhash, err)
+ log.Warn(errStr)
+ return errStr, err
+ }
+
+ if len(path) > 0 {
+ path += "/"
+ }
+
+ quitC := make(chan bool)
+ trie, err := loadManifest(self.swarmApi.dpa, key, quitC)
+ if err != nil {
+ errStr := fmt.Sprintf("fs.Download: loadManifestTrie error: %v", err)
+ log.Warn(errStr)
+ return errStr, err
+ }
+
+ dirTree := map[string]*Dir{}
+
+ rootDir := &Dir{
+ inode: NewInode(),
+ name: "root",
+ directories: nil,
+ files: nil,
+ }
+ dirTree["root"] = rootDir
+
+ err = trie.listWithPrefix(path, quitC, func(entry *manifestTrieEntry, suffix string) {
+
+ key = common.Hex2Bytes(entry.Hash)
+ fullpath := "/" + suffix
+ basepath := filepath.Dir(fullpath)
+ filename := filepath.Base(fullpath)
+
+ parentDir := rootDir
+ dirUntilNow := ""
+ paths := strings.Split(basepath, "/")
+ for i := range paths {
+ if paths[i] != "" {
+ thisDir := paths[i]
+ dirUntilNow = dirUntilNow + "/" + thisDir
+
+ if _, ok := dirTree[dirUntilNow]; !ok {
+ dirTree[dirUntilNow] = &Dir{
+ inode: NewInode(),
+ name: thisDir,
+ path: dirUntilNow,
+ directories: nil,
+ files: nil,
+ }
+ parentDir.directories = append(parentDir.directories, dirTree[dirUntilNow])
+ parentDir = dirTree[dirUntilNow]
+
+ } else {
+ parentDir = dirTree[dirUntilNow]
+ }
+
+ }
+ }
+ thisFile := &File{
+ inode: NewInode(),
+ name: filename,
+ path: fullpath,
+ key: key,
+ swarmApi: self.swarmApi,
+ }
+ parentDir.files = append(parentDir.files, thisFile)
+ })
+
+ fconn, err := fuse.Mount(cleanedMountPoint, fuse.FSName("swarmfs"), fuse.VolumeName(mhash))
+ if err != nil {
+ fuse.Unmount(cleanedMountPoint)
+ errStr := fmt.Sprintf("Mounting %s encountered error: %v", cleanedMountPoint, err)
+ log.Warn(errStr)
+ return errStr, err
+ }
+
+ mounterr := make(chan error, 1)
+ go func() {
+ log.Info(fmt.Sprintf("Serving %s at %s", mhash, cleanedMountPoint))
+ filesys := &FS{root: rootDir}
+ if err := fs.Serve(fconn, filesys); err != nil {
+ log.Warn(fmt.Sprintf("Could not Serve FS error: %v", err))
+ }
+ }()
+
+ // Check if the mount process has an error to report.
+ select {
+
+ case <-time.After(mountTimeout):
+ err := fmt.Errorf("Mounting %s timed out.", cleanedMountPoint)
+ log.Warn(err.Error())
+ return err.Error(), err
+
+ case err := <-mounterr:
+ errStr := fmt.Sprintf("Mounting %s encountered error: %v", cleanedMountPoint, err)
+ log.Warn(errStr)
+ return errStr, err
+
+ case <-fconn.Ready:
+ log.Debug(fmt.Sprintf("Mounting connection succeeded for : %v", cleanedMountPoint))
+ }
+
+
+
+ //Assemble and Store the mount information for future use
+ mountInformation := &MountInfo{
+ mountPoint: cleanedMountPoint,
+ manifestHash: mhash,
+ resolvedKey: key,
+ rootDir: rootDir,
+ fuseConnection: fconn,
+ }
+ self.activeMounts[cleanedMountPoint] = mountInformation
+
+ succString := fmt.Sprintf("Mounting successful for %s", cleanedMountPoint)
+ log.Info(succString)
+
+ return succString, nil
+}
+
+func (self *SwarmFS) Unmount(mountpoint string) (string, error) {
+
+ self.activeLock.Lock()
+ defer self.activeLock.Unlock()
+
+ cleanedMountPoint, err := filepath.Abs(filepath.Clean(mountpoint))
+ if err != nil {
+ return err.Error(), err
+ }
+
+ // Get the mount information based on the mountpoint argument
+ mountInfo := self.activeMounts[cleanedMountPoint]
+
+
+ if mountInfo == nil || mountInfo.mountPoint != cleanedMountPoint {
+ err := fmt.Errorf("Could not find mount information for %s ", cleanedMountPoint)
+ log.Warn(err.Error())
+ return err.Error(), err
+ }
+
+ err = fuse.Unmount(cleanedMountPoint)
+ if err != nil {
+ //TODO: try forceful unmount if normal unmount fails
+ errStr := fmt.Sprintf("UnMount error: %v", err)
+ log.Warn(errStr)
+ return errStr, err
+ }
+
+ mountInfo.fuseConnection.Close()
+
+ //remove the mount information from the active map
+ delete(self.activeMounts, cleanedMountPoint)
+
+ succString := fmt.Sprintf("UnMounting %v succeeded", cleanedMountPoint)
+ log.Info(succString)
+ return succString, nil
+}
+
+func (self *SwarmFS) Listmounts() (string, error) {
+
+ self.activeLock.RLock()
+ defer self.activeLock.RUnlock()
+
+ var rows []string
+ for mp := range self.activeMounts {
+ mountInfo := self.activeMounts[mp]
+ rows = append(rows, fmt.Sprintf("Swarm Root: %s, Mount Point: %s ", mountInfo.manifestHash, mountInfo.mountPoint))
+ }
+
+ return strings.Join(rows, "\n"), nil
+}
+
+func (self *SwarmFS) Stop() bool {
+
+ for mp := range self.activeMounts {
+ mountInfo := self.activeMounts[mp]
+ self.Unmount(mountInfo.mountPoint)
+ }
+
+ return true
+}
diff --git a/swarm/api/swarmfs_unix_test.go b/swarm/api/swarmfs_unix_test.go
new file mode 100644
index 0000000000..4f59dba5b6
--- /dev/null
+++ b/swarm/api/swarmfs_unix_test.go
@@ -0,0 +1,122 @@
+// Copyright 2016 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+// +build linux darwin
+
+package api
+
+import (
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "testing"
+)
+
+var testUploadDir, _ = ioutil.TempDir(os.TempDir(), "fuse-source")
+var testMountDir, _ = ioutil.TempDir(os.TempDir(), "fuse-dest")
+
+func testFuseFileSystem(t *testing.T, f func(*FileSystem)) {
+ testApi(t, func(api *Api) {
+ f(NewFileSystem(api))
+ })
+}
+
+func createTestFiles(t *testing.T, files []string) {
+
+ os.RemoveAll(testUploadDir)
+ os.RemoveAll(testMountDir)
+ defer os.MkdirAll(testMountDir, 0777)
+
+ for f := range files {
+ actualPath := filepath.Join(testUploadDir, files[f])
+ filePath := filepath.Dir(actualPath)
+
+ err := os.MkdirAll(filePath, 0777)
+ if err != nil {
+ t.Fatalf("Error creating directory '%v' : %v", filePath, err)
+ }
+
+ _, err1 := os.OpenFile(actualPath, os.O_RDONLY|os.O_CREATE, 0666)
+ if err1 != nil {
+ t.Fatalf("Error creating file %v: %v", actualPath, err1)
+ }
+ }
+
+}
+
+func compareFiles(t *testing.T, files []string) {
+
+ for f := range files {
+
+ sourceFile := filepath.Join(testUploadDir, files[f])
+ destinationFile := filepath.Join(testMountDir, files[f])
+
+ sfinfo, err := os.Stat(sourceFile)
+ if err != nil {
+ t.Fatalf("Source file %v missing in mount: %v", files[f], err)
+ }
+
+ dfinfo, err := os.Stat(destinationFile)
+ if err != nil {
+ t.Fatalf("Destination file %v missing in mount: %v", files[f], err)
+ }
+
+ if sfinfo.Size() != dfinfo.Size() {
+ t.Fatalf("Size mismatch source (%v) vs destination(%v)", sfinfo.Size(), dfinfo.Size())
+ }
+
+ if dfinfo.Mode().Perm().String() != "-r-x------" {
+ t.Fatalf("Permission is not 0500for file: %v", err)
+ }
+
+ }
+}
+
+func doHashTest(fs *FileSystem, t *testing.T, ensName string, files ...string) {
+
+ createTestFiles(t, files)
+ bzzhash, err := fs.Upload(testUploadDir, "")
+ if err != nil {
+ t.Fatalf("Error uploading directory %v: %v", testUploadDir, err)
+ }
+
+ swarmfs := NewSwarmFS(fs.api)
+ _ ,err1 := swarmfs.Mount(bzzhash, testMountDir)
+ if err1 != nil {
+
+ t.Fatalf("Error mounting hash %v: %v", bzzhash, err)
+ }
+ compareFiles(t, files)
+ _, err2 := swarmfs.Unmount(testMountDir)
+ if err2 != nil {
+ t.Fatalf("Error unmounting path %v: %v", testMountDir, err)
+ }
+ swarmfs.Stop()
+
+}
+
+// mounting with manifest Hash
+func TestFuseMountingScenarios(t *testing.T) {
+ testFuseFileSystem(t, func(fs *FileSystem) {
+
+ //doHashTest(fs,t, "test","1.txt")
+ doHashTest(fs, t, "", "1.txt")
+ doHashTest(fs, t, "", "1.txt", "11.txt", "111.txt", "two/2.txt", "two/two/2.txt", "three/3.txt")
+ doHashTest(fs, t, "", "1/2/3/4/5/6/7/8/9/10/11/12/1.txt")
+ doHashTest(fs, t, "", "one/one.txt", "one.txt", "once/one.txt", "one/one/one.txt")
+
+ })
+}
diff --git a/accounts/usbwallet/usbwallet_ios.go b/swarm/api/swarmfs_windows.go
similarity index 57%
rename from accounts/usbwallet/usbwallet_ios.go
rename to swarm/api/swarmfs_windows.go
index 17d3429031..525a25399a 100644
--- a/accounts/usbwallet/usbwallet_ios.go
+++ b/swarm/api/swarmfs_windows.go
@@ -14,25 +14,35 @@
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see .
-// This file contains the implementation for interacting with the Ledger hardware
-// wallets. The wire protocol spec can be found in the Ledger Blue GitHub repo:
-// https://raw.githubusercontent.com/LedgerHQ/blue-app-eth/master/doc/ethapp.asc
+// +build windows
-// +build ios
-
-package usbwallet
+package api
import (
- "errors"
-
- "github.com/ethereum/go-ethereum/accounts"
+ "github.com/ethereum/go-ethereum/log"
)
-// Here be dragons! There is no USB support on iOS.
-
-// ErrIOSNotSupported is returned for all USB hardware backends on iOS.
-var ErrIOSNotSupported = errors.New("no USB support on iOS")
-
-func NewLedgerHub() (accounts.Backend, error) {
- return nil, ErrIOSNotSupported
+// Dummy struct and functions to satsfy windows build
+type MountInfo struct {
}
+
+
+func (self *SwarmFS) Mount(mhash, mountpoint string) error {
+ log.Info("Platform not supported")
+ return nil
+}
+
+func (self *SwarmFS) Unmount(mountpoint string) error {
+ log.Info("Platform not supported")
+ return nil
+}
+
+func (self *SwarmFS) Listmounts() (string, error) {
+ log.Info("Platform not supported")
+ return "",nil
+}
+
+func (self *SwarmFS) Stop() error {
+ log.Info("Platform not supported")
+ return nil
+}
\ No newline at end of file
diff --git a/swarm/network/depo.go b/swarm/network/depo.go
index 454a572709..e76bfa66c5 100644
--- a/swarm/network/depo.go
+++ b/swarm/network/depo.go
@@ -19,10 +19,10 @@ package network
import (
"bytes"
"encoding/binary"
+ "fmt"
"time"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/swarm/storage"
)
@@ -60,8 +60,8 @@ func (self *Depo) HandleUnsyncedKeysMsg(req *unsyncedKeysMsgData, p *peer) error
missing = append(missing, req)
}
}
- glog.V(logger.Debug).Infof("Depo.HandleUnsyncedKeysMsg: received %v unsynced keys: %v missing. new state: %v", len(unsynced), len(missing), req.State)
- glog.V(logger.Detail).Infof("Depo.HandleUnsyncedKeysMsg: received %v", unsynced)
+ log.Debug(fmt.Sprintf("Depo.HandleUnsyncedKeysMsg: received %v unsynced keys: %v missing. new state: %v", len(unsynced), len(missing), req.State))
+ log.Trace(fmt.Sprintf("Depo.HandleUnsyncedKeysMsg: received %v", unsynced))
// send delivery request with missing keys
err = p.deliveryRequest(missing)
if err != nil {
@@ -81,7 +81,7 @@ func (self *Depo) HandleUnsyncedKeysMsg(req *unsyncedKeysMsgData, p *peer) error
func (self *Depo) HandleDeliveryRequestMsg(req *deliveryRequestMsgData, p *peer) error {
deliver := req.Deliver
// queue the actual delivery of a chunk ()
- glog.V(logger.Detail).Infof("Depo.HandleDeliveryRequestMsg: received %v delivery requests: %v", len(deliver), deliver)
+ log.Trace(fmt.Sprintf("Depo.HandleDeliveryRequestMsg: received %v delivery requests: %v", len(deliver), deliver))
for _, sreq := range deliver {
// TODO: look up in cache here or in deliveries
// priorities are taken from the message so the remote party can
@@ -104,29 +104,29 @@ func (self *Depo) HandleStoreRequestMsg(req *storeRequestMsgData, p *peer) {
chunk, err := self.localStore.Get(req.Key)
switch {
case err != nil:
- glog.V(logger.Detail).Infof("Depo.handleStoreRequest: %v not found locally. create new chunk/request", req.Key)
+ log.Trace(fmt.Sprintf("Depo.handleStoreRequest: %v not found locally. create new chunk/request", req.Key))
// not found in memory cache, ie., a genuine store request
// create chunk
chunk = storage.NewChunk(req.Key, nil)
case chunk.SData == nil:
// found chunk in memory store, needs the data, validate now
- glog.V(logger.Detail).Infof("Depo.HandleStoreRequest: %v. request entry found", req)
+ log.Trace(fmt.Sprintf("Depo.HandleStoreRequest: %v. request entry found", req))
default:
// data is found, store request ignored
// this should update access count?
- glog.V(logger.Detail).Infof("Depo.HandleStoreRequest: %v found locally. ignore.", req)
+ log.Trace(fmt.Sprintf("Depo.HandleStoreRequest: %v found locally. ignore.", req))
islocal = true
//return
}
-
+
hasher := self.hashfunc()
hasher.Write(req.SData)
if !bytes.Equal(hasher.Sum(nil), req.Key) {
// data does not validate, ignore
// TODO: peer should be penalised/dropped?
- glog.V(logger.Warn).Infof("Depo.HandleStoreRequest: chunk invalid. store request ignored: %v", req)
+ log.Warn(fmt.Sprintf("Depo.HandleStoreRequest: chunk invalid. store request ignored: %v", req))
return
}
@@ -136,7 +136,7 @@ func (self *Depo) HandleStoreRequestMsg(req *storeRequestMsgData, p *peer) {
// update chunk with size and data
chunk.SData = req.SData // protocol validates that SData is minimum 9 bytes long (int64 size + at least one byte of data)
chunk.Size = int64(binary.LittleEndian.Uint64(req.SData[0:8]))
- glog.V(logger.Detail).Infof("delivery of %v from %v", chunk, p)
+ log.Trace(fmt.Sprintf("delivery of %v from %v", chunk, p))
chunk.Source = p
self.netStore.Put(chunk)
}
@@ -152,7 +152,7 @@ func (self *Depo) HandleRetrieveRequestMsg(req *retrieveRequestMsgData, p *peer)
err = p.swap.Add(1)
}
if err != nil {
- glog.V(logger.Warn).Infof("Depo.HandleRetrieveRequest: %v - cannot process request: %v", req.Key.Log(), err)
+ log.Warn(fmt.Sprintf("Depo.HandleRetrieveRequest: %v - cannot process request: %v", req.Key.Log(), err))
return
}
@@ -163,7 +163,7 @@ func (self *Depo) HandleRetrieveRequestMsg(req *retrieveRequestMsgData, p *peer)
req = self.strategyUpdateRequest(chunk.Req, req)
// check if we can immediately deliver
if chunk.SData != nil {
- glog.V(logger.Detail).Infof("Depo.HandleRetrieveRequest: %v - content found, delivering...", req.Key.Log())
+ log.Trace(fmt.Sprintf("Depo.HandleRetrieveRequest: %v - content found, delivering...", req.Key.Log()))
if req.MaxSize == 0 || int64(req.MaxSize) >= chunk.Size {
sreq := &storeRequestMsgData{
@@ -174,16 +174,16 @@ func (self *Depo) HandleRetrieveRequestMsg(req *retrieveRequestMsgData, p *peer)
}
p.syncer.addRequest(sreq, DeliverReq)
} else {
- glog.V(logger.Detail).Infof("Depo.HandleRetrieveRequest: %v - content found, not wanted", req.Key.Log())
+ log.Trace(fmt.Sprintf("Depo.HandleRetrieveRequest: %v - content found, not wanted", req.Key.Log()))
}
} else {
- glog.V(logger.Detail).Infof("Depo.HandleRetrieveRequest: %v - content not found locally. asked swarm for help. will get back", req.Key.Log())
+ log.Trace(fmt.Sprintf("Depo.HandleRetrieveRequest: %v - content not found locally. asked swarm for help. will get back", req.Key.Log()))
}
}
// add peer request the chunk and decides the timeout for the response if still searching
func (self *Depo) strategyUpdateRequest(rs *storage.RequestStatus, origReq *retrieveRequestMsgData) (req *retrieveRequestMsgData) {
- glog.V(logger.Detail).Infof("Depo.strategyUpdateRequest: key %v", origReq.Key.Log())
+ log.Trace(fmt.Sprintf("Depo.strategyUpdateRequest: key %v", origReq.Key.Log()))
// we do not create an alternative one
req = origReq
if rs != nil {
@@ -211,7 +211,7 @@ only add if less than requesterCount peers forwarded the same request id so far
note this is done irrespective of status (searching or found)
*/
func (self *Depo) addRequester(rs *storage.RequestStatus, req *retrieveRequestMsgData) {
- glog.V(logger.Detail).Infof("Depo.addRequester: key %v - add peer to req.Id %v", req.Key.Log(), req.from, req.Id)
+ log.Trace(fmt.Sprintf("Depo.addRequester: key %v - add peer to req.Id %v", req.Key.Log(), req.Id))
list := rs.Requesters[req.Id]
rs.Requesters[req.Id] = append(list, req)
}
diff --git a/swarm/network/forwarding.go b/swarm/network/forwarding.go
index fef79c70bb..88a82a678c 100644
--- a/swarm/network/forwarding.go
+++ b/swarm/network/forwarding.go
@@ -17,11 +17,11 @@
package network
import (
+ "fmt"
"math/rand"
"time"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/swarm/storage"
)
@@ -56,10 +56,10 @@ var searchTimeout = 3 * time.Second
// logic propagating retrieve requests to peers given by the kademlia hive
func (self *forwarder) Retrieve(chunk *storage.Chunk) {
peers := self.hive.getPeers(chunk.Key, 0)
- glog.V(logger.Detail).Infof("forwarder.Retrieve: %v - received %d peers from KΛÐΞMLIΛ...", chunk.Key.Log(), len(peers))
+ log.Trace(fmt.Sprintf("forwarder.Retrieve: %v - received %d peers from KΛÐΞMLIΛ...", chunk.Key.Log(), len(peers)))
OUT:
for _, p := range peers {
- glog.V(logger.Detail).Infof("forwarder.Retrieve: sending retrieveRequest %v to peer [%v]", chunk.Key.Log(), p)
+ log.Trace(fmt.Sprintf("forwarder.Retrieve: sending retrieveRequest %v to peer [%v]", chunk.Key.Log(), p))
for _, recipients := range chunk.Req.Requesters {
for _, recipient := range recipients {
req := recipient.(*retrieveRequestMsgData)
@@ -80,7 +80,7 @@ OUT:
p.retrieve(req)
break OUT
}
- glog.V(logger.Warn).Infof("forwarder.Retrieve: unable to send retrieveRequest to peer [%v]: %v", chunk.Key.Log(), err)
+ log.Warn(fmt.Sprintf("forwarder.Retrieve: unable to send retrieveRequest to peer [%v]: %v", chunk.Key.Log(), err))
}
}
@@ -98,14 +98,14 @@ func (self *forwarder) Store(chunk *storage.Chunk) {
source = chunk.Source.(*peer)
}
for _, p := range self.hive.getPeers(chunk.Key, 0) {
- glog.V(logger.Detail).Infof("forwarder.Store: %v %v", p, chunk)
+ log.Trace(fmt.Sprintf("forwarder.Store: %v %v", p, chunk))
if p.syncer != nil && (source == nil || p.Addr() != source.Addr()) {
n++
Deliver(p, msg, PropagateReq)
}
}
- glog.V(logger.Detail).Infof("forwarder.Store: sent to %v peers (chunk = %v)", n, chunk)
+ log.Trace(fmt.Sprintf("forwarder.Store: sent to %v peers (chunk = %v)", n, chunk))
}
// once a chunk is found deliver it to its requesters unless timed out
@@ -123,7 +123,7 @@ func (self *forwarder) Deliver(chunk *storage.Chunk) {
for id, r := range requesters {
req = r.(*retrieveRequestMsgData)
if req.timeout == nil || req.timeout.After(time.Now()) {
- glog.V(logger.Detail).Infof("forwarder.Deliver: %v -> %v", req.Id, req.from)
+ log.Trace(fmt.Sprintf("forwarder.Deliver: %v -> %v", req.Id, req.from))
msg.Id = uint64(id)
Deliver(req.from, msg, DeliverReq)
n++
@@ -133,7 +133,7 @@ func (self *forwarder) Deliver(chunk *storage.Chunk) {
}
}
}
- glog.V(logger.Detail).Infof("forwarder.Deliver: submit chunk %v (request id %v) for delivery to %v peers", chunk.Key.Log(), id, n)
+ log.Trace(fmt.Sprintf("forwarder.Deliver: submit chunk %v (request id %v) for delivery to %v peers", chunk.Key.Log(), id, n))
}
}
diff --git a/swarm/network/hive.go b/swarm/network/hive.go
index f81761b97d..70652c4509 100644
--- a/swarm/network/hive.go
+++ b/swarm/network/hive.go
@@ -23,8 +23,7 @@ import (
"time"
"github.com/ethereum/go-ethereum/common"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/p2p/discover"
"github.com/ethereum/go-ethereum/p2p/netutil"
"github.com/ethereum/go-ethereum/swarm/network/kademlia"
@@ -129,7 +128,7 @@ func (self *Hive) Start(id discover.NodeID, listenAddr func() string, connectPee
self.listenAddr = listenAddr
err = self.kad.Load(self.path, nil)
if err != nil {
- glog.V(logger.Warn).Infof("Warning: error reading kaddb '%s' (skipping): %v", self.path, err)
+ log.Warn(fmt.Sprintf("Warning: error reading kaddb '%s' (skipping): %v", self.path, err))
err = nil
}
// this loop is doing bootstrapping and maintains a healthy table
@@ -145,7 +144,7 @@ func (self *Hive) Start(id discover.NodeID, listenAddr func() string, connectPee
node, need, proxLimit := self.kad.Suggest()
if node != nil && len(node.Url) > 0 {
- glog.V(logger.Detail).Infof("call known bee %v", node.Url)
+ log.Trace(fmt.Sprintf("call known bee %v", node.Url))
// enode or any lower level connection address is unnecessary in future
// discovery table is used to look it up.
connectPeer(node.Url)
@@ -159,21 +158,21 @@ func (self *Hive) Start(id discover.NodeID, listenAddr func() string, connectPee
req := &retrieveRequestMsgData{
Key: storage.Key(randAddr[:]),
}
- glog.V(logger.Detail).Infof("call any bee near %v (PO%03d) - messenger bee: %v", randAddr, proxLimit, peers[0])
+ log.Trace(fmt.Sprintf("call any bee near %v (PO%03d) - messenger bee: %v", randAddr, proxLimit, peers[0]))
peers[0].(*peer).retrieve(req)
} else {
- glog.V(logger.Warn).Infof("no peer")
+ log.Warn(fmt.Sprintf("no peer"))
}
- glog.V(logger.Detail).Infof("buzz kept alive")
+ log.Trace(fmt.Sprintf("buzz kept alive"))
} else {
- glog.V(logger.Info).Infof("no need for more bees")
+ log.Info(fmt.Sprintf("no need for more bees"))
}
select {
case self.toggle <- need:
case <-self.quit:
return
}
- glog.V(logger.Debug).Infof("queen's address: %v, population: %d (%d)", self.addr, self.kad.Count(), self.kad.DBCount())
+ log.Debug(fmt.Sprintf("queen's address: %v, population: %d (%d)", self.addr, self.kad.Count(), self.kad.DBCount()))
}
}()
return
@@ -192,7 +191,7 @@ func (self *Hive) keepAlive() {
if self.kad.DBCount() > 0 {
select {
case self.more <- true:
- glog.V(logger.Debug).Infof("buzz wakeup")
+ log.Debug(fmt.Sprintf("buzz wakeup"))
default:
}
}
@@ -224,7 +223,7 @@ func (self *Hive) addPeer(p *peer) error {
default:
}
}()
- glog.V(logger.Detail).Infof("hi new bee %v", p)
+ log.Trace(fmt.Sprintf("hi new bee %v", p))
err := self.kad.On(p, loadSync)
if err != nil {
return err
@@ -235,21 +234,21 @@ func (self *Hive) addPeer(p *peer) error {
// to send the 6 byte self lookup
// we do not record as request or forward it, just reply with peers
p.retrieve(&retrieveRequestMsgData{})
- glog.V(logger.Detail).Infof("'whatsup wheresdaparty' sent to %v", p)
+ log.Trace(fmt.Sprintf("'whatsup wheresdaparty' sent to %v", p))
return nil
}
// called after peer disconnected
func (self *Hive) removePeer(p *peer) {
- glog.V(logger.Debug).Infof("bee %v removed", p)
+ log.Debug(fmt.Sprintf("bee %v removed", p))
self.kad.Off(p, saveSync)
select {
case self.more <- true:
default:
}
if self.kad.Count() == 0 {
- glog.V(logger.Debug).Infof("empty, all bees gone")
+ log.Debug(fmt.Sprintf("empty, all bees gone"))
}
}
@@ -265,7 +264,7 @@ func (self *Hive) getPeers(target storage.Key, max int) (peers []*peer) {
// disconnects all the peers
func (self *Hive) DropAll() {
- glog.V(logger.Info).Infof("dropping all bees")
+ log.Info(fmt.Sprintf("dropping all bees"))
for _, node := range self.kad.FindClosest(kademlia.Address{}, 0) {
node.Drop()
}
@@ -290,7 +289,7 @@ func (self *Hive) HandlePeersMsg(req *peersMsgData, from *peer) {
var nrs []*kademlia.NodeRecord
for _, p := range req.Peers {
if err := netutil.CheckRelayIP(from.remoteAddr.IP, p.IP); err != nil {
- glog.V(logger.Detail).Infof("invalid peer IP %v from %v: %v", from.remoteAddr.IP, p.IP, err)
+ log.Trace(fmt.Sprintf("invalid peer IP %v from %v: %v", from.remoteAddr.IP, p.IP, err))
continue
}
nrs = append(nrs, newNodeRecord(p))
@@ -326,7 +325,7 @@ func loadSync(record *kademlia.NodeRecord, node kademlia.Node) error {
return fmt.Errorf("invalid type")
}
if record.Meta == nil {
- glog.V(logger.Debug).Infof("no sync state for node record %v setting default", record)
+ log.Debug(fmt.Sprintf("no sync state for node record %v setting default", record))
p.syncState = &syncState{DbSyncState: &storage.DbSyncState{}}
return nil
}
@@ -334,7 +333,7 @@ func loadSync(record *kademlia.NodeRecord, node kademlia.Node) error {
if err != nil {
return fmt.Errorf("error decoding kddb record meta info into a sync state: %v", err)
}
- glog.V(logger.Detail).Infof("sync state for node record %v read from Meta: %s", record, string(*(record.Meta)))
+ log.Trace(fmt.Sprintf("sync state for node record %v read from Meta: %s", record, string(*(record.Meta))))
p.syncState = state
return err
}
@@ -344,10 +343,10 @@ func saveSync(record *kademlia.NodeRecord, node kademlia.Node) {
if p, ok := node.(*peer); ok {
meta, err := encodeSync(p.syncState)
if err != nil {
- glog.V(logger.Warn).Infof("error saving sync state for %v: %v", node, err)
+ log.Warn(fmt.Sprintf("error saving sync state for %v: %v", node, err))
return
}
- glog.V(logger.Detail).Infof("saved sync state for %v: %s", node, string(*meta))
+ log.Trace(fmt.Sprintf("saved sync state for %v: %s", node, string(*meta)))
record.Meta = meta
}
}
@@ -370,7 +369,7 @@ func (self *Hive) peers(req *retrieveRequestMsgData) {
for _, peer := range self.getPeers(key, int(req.MaxPeers)) {
addrs = append(addrs, peer.remoteAddr)
}
- glog.V(logger.Debug).Infof("Hive sending %d peer addresses to %v. req.Id: %v, req.Key: %v", len(addrs), req.from, req.Id, req.Key.Log())
+ log.Debug(fmt.Sprintf("Hive sending %d peer addresses to %v. req.Id: %v, req.Key: %v", len(addrs), req.from, req.Id, req.Key.Log()))
peersData := &peersMsgData{
Peers: addrs,
diff --git a/swarm/network/kademlia/kaddb.go b/swarm/network/kademlia/kaddb.go
index 53a7db451c..3e4b261fde 100644
--- a/swarm/network/kademlia/kaddb.go
+++ b/swarm/network/kademlia/kaddb.go
@@ -24,8 +24,7 @@ import (
"sync"
"time"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/log"
)
type NodeData interface {
@@ -88,12 +87,12 @@ func (self *KadDb) findOrCreate(index int, a Address, url string) *NodeRecord {
Addr: a,
Url: url,
}
- glog.V(logger.Info).Infof("add new record %v to kaddb", record)
+ log.Info(fmt.Sprintf("add new record %v to kaddb", record))
// insert in kaddb
self.index[a] = record
self.Nodes[index] = append(self.Nodes[index], record)
} else {
- glog.V(logger.Info).Infof("found record %v in kaddb", record)
+ log.Info(fmt.Sprintf("found record %v in kaddb", record))
}
// update last seen time
record.setSeen()
@@ -121,13 +120,13 @@ func (self *KadDb) add(nrs []*NodeRecord, proximityBin func(Address) int) {
copy(newnodes[:], nodes[:dbcursor])
newnodes[dbcursor] = node
copy(newnodes[dbcursor+1:], nodes[dbcursor:])
- glog.V(logger.Detail).Infof("new nodes: %v (keys: %v)\nnodes: %v", newnodes, nodes)
+ log.Trace(fmt.Sprintf("new nodes: %v, nodes: %v", newnodes, nodes))
self.Nodes[index] = newnodes
n++
}
}
if n > 0 {
- glog.V(logger.Debug).Infof("%d/%d node records (new/known)", n, len(nrs))
+ log.Debug(fmt.Sprintf("%d/%d node records (new/known)", n, len(nrs)))
}
}
@@ -207,13 +206,13 @@ func (self *KadDb) findBest(maxBinSize int, binSize func(int) int) (node *NodeRe
// skip already connected nodes
if node.node != nil {
- glog.V(logger.Debug).Infof("kaddb record %v (PO%03d:%d/%d) already connected", node.Addr, po, cursor, len(dbrow))
+ log.Debug(fmt.Sprintf("kaddb record %v (PO%03d:%d/%d) already connected", node.Addr, po, cursor, len(dbrow)))
continue ROW
}
// if node is scheduled to connect
if time.Time(node.After).After(time.Now()) {
- glog.V(logger.Debug).Infof("kaddb record %v (PO%03d:%d) skipped. seen at %v (%v ago), scheduled at %v", node.Addr, po, cursor, node.Seen, delta, node.After)
+ log.Debug(fmt.Sprintf("kaddb record %v (PO%03d:%d) skipped. seen at %v (%v ago), scheduled at %v", node.Addr, po, cursor, node.Seen, delta, node.After))
continue ROW
}
@@ -224,17 +223,17 @@ func (self *KadDb) findBest(maxBinSize int, binSize func(int) int) (node *NodeRe
if delta > self.purgeInterval {
// remove node
purge[cursor] = true
- glog.V(logger.Debug).Infof("kaddb record %v (PO%03d:%d) unreachable since %v. Removed", node.Addr, po, cursor, node.Seen)
+ log.Debug(fmt.Sprintf("kaddb record %v (PO%03d:%d) unreachable since %v. Removed", node.Addr, po, cursor, node.Seen))
continue ROW
}
- glog.V(logger.Debug).Infof("kaddb record %v (PO%03d:%d) ready to be tried. seen at %v (%v ago), scheduled at %v", node.Addr, po, cursor, node.Seen, delta, node.After)
+ log.Debug(fmt.Sprintf("kaddb record %v (PO%03d:%d) ready to be tried. seen at %v (%v ago), scheduled at %v", node.Addr, po, cursor, node.Seen, delta, node.After))
// scheduling next check
interval = time.Duration(delta * time.Duration(self.connRetryExp))
after = time.Now().Add(interval)
- glog.V(logger.Debug).Infof("kaddb record %v (PO%03d:%d) selected as candidate connection %v. seen at %v (%v ago), selectable since %v, retry after %v (in %v)", node.Addr, po, cursor, rounds, node.Seen, delta, node.After, after, interval)
+ log.Debug(fmt.Sprintf("kaddb record %v (PO%03d:%d) selected as candidate connection %v. seen at %v (%v ago), selectable since %v, retry after %v (in %v)", node.Addr, po, cursor, rounds, node.Seen, delta, node.After, after, interval))
node.After = after
found = true
} // ROW
@@ -295,9 +294,9 @@ func (self *KadDb) save(path string, cb func(*NodeRecord, Node)) error {
}
err = ioutil.WriteFile(path, data, os.ModePerm)
if err != nil {
- glog.V(logger.Warn).Infof("unable to save kaddb with %v nodes to %v: err", n, path, err)
+ log.Warn(fmt.Sprintf("unable to save kaddb with %v nodes to %v: %v", n, path, err))
} else {
- glog.V(logger.Info).Infof("saved kaddb with %v nodes to %v", n, path)
+ log.Info(fmt.Sprintf("saved kaddb with %v nodes to %v", n, path))
}
return err
}
@@ -338,7 +337,7 @@ func (self *KadDb) load(path string, cb func(*NodeRecord, Node) error) (err erro
}
self.delete(po, purge)
}
- glog.V(logger.Info).Infof("loaded kaddb with %v nodes from %v", n, path)
+ log.Info(fmt.Sprintf("loaded kaddb with %v nodes from %v", n, path))
return
}
diff --git a/swarm/network/kademlia/kademlia.go b/swarm/network/kademlia/kademlia.go
index 87c57cefe6..bf976a3e1d 100644
--- a/swarm/network/kademlia/kademlia.go
+++ b/swarm/network/kademlia/kademlia.go
@@ -23,8 +23,7 @@ import (
"sync"
"time"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/log"
)
const (
@@ -117,7 +116,7 @@ func (self *Kademlia) DBCount() int {
// On is the entry point called when a new nodes is added
// unsafe in that node is not checked to be already active node (to be called once)
func (self *Kademlia) On(node Node, cb func(*NodeRecord, Node) error) (err error) {
- glog.V(logger.Warn).Infof("%v", self)
+ log.Debug(fmt.Sprintf("%v", self))
defer self.lock.Unlock()
self.lock.Lock()
@@ -126,11 +125,11 @@ func (self *Kademlia) On(node Node, cb func(*NodeRecord, Node) error) (err error
if cb != nil {
err = cb(record, node)
- glog.V(logger.Detail).Infof("cb(%v, %v) ->%v", record, node, err)
+ log.Trace(fmt.Sprintf("cb(%v, %v) ->%v", record, node, err))
if err != nil {
return fmt.Errorf("unable to add node %v, callback error: %v", node.Addr(), err)
}
- glog.V(logger.Debug).Infof("add node record %v with node %v", record, node)
+ log.Debug(fmt.Sprintf("add node record %v with node %v", record, node))
}
// insert in kademlia table of active nodes
@@ -139,7 +138,7 @@ func (self *Kademlia) On(node Node, cb func(*NodeRecord, Node) error) (err error
// TODO: give priority to peers with active traffic
if len(bucket) < self.BucketSize { // >= allows us to add peers beyond the bucketsize limitation
self.buckets[index] = append(bucket, node)
- glog.V(logger.Debug).Infof("add node %v to table", node)
+ log.Debug(fmt.Sprintf("add node %v to table", node))
self.setProxLimit(index, true)
record.node = node
self.count++
@@ -159,10 +158,10 @@ func (self *Kademlia) On(node Node, cb func(*NodeRecord, Node) error) (err error
}
}
if replaced == nil {
- glog.V(logger.Debug).Infof("all peers wanted, PO%03d bucket full", index)
+ log.Debug(fmt.Sprintf("all peers wanted, PO%03d bucket full", index))
return fmt.Errorf("bucket full")
}
- glog.V(logger.Debug).Infof("node %v replaced by %v (idle for %v > %v)", replaced, node, idle, self.MaxIdleInterval)
+ log.Debug(fmt.Sprintf("node %v replaced by %v (idle for %v > %v)", replaced, node, idle, self.MaxIdleInterval))
replaced.Drop()
// actually replace in the row. When off(node) is called, the peer is no longer in the row
bucket[pos] = node
@@ -195,7 +194,7 @@ func (self *Kademlia) Off(node Node, cb func(*NodeRecord, Node)) (err error) {
}
record.node = nil
self.count--
- glog.V(logger.Debug).Infof("remove node %v from table, population now is %v", node, self.count)
+ log.Debug(fmt.Sprintf("remove node %v from table, population now is %v", node, self.count))
return
}
@@ -223,7 +222,7 @@ func (self *Kademlia) setProxLimit(r int, on bool) {
self.proxLimit++
curr = len(self.buckets[self.proxLimit])
- glog.V(logger.Detail).Infof("proxbin contraction (size: %v, limit: %v, bin: %v)", self.proxSize, self.proxLimit, r)
+ log.Trace(fmt.Sprintf("proxbin contraction (size: %v, limit: %v, bin: %v)", self.proxSize, self.proxLimit, r))
}
return
}
@@ -237,7 +236,7 @@ func (self *Kademlia) setProxLimit(r int, on bool) {
//
self.proxLimit--
self.proxSize += len(self.buckets[self.proxLimit])
- glog.V(logger.Detail).Infof("proxbin expansion (size: %v, limit: %v, bin: %v)", self.proxSize, self.proxLimit, r)
+ log.Trace(fmt.Sprintf("proxbin expansion (size: %v, limit: %v, bin: %v)", self.proxSize, self.proxLimit, r))
}
}
@@ -257,7 +256,7 @@ func (self *Kademlia) FindClosest(target Address, max int) []Node {
po := self.proximityBin(target)
index := po
step := 1
- glog.V(logger.Detail).Infof("serving %v nodes at %v (PO%02d)", max, index, po)
+ log.Trace(fmt.Sprintf("serving %v nodes at %v (PO%02d)", max, index, po))
// if max is set to 0, just want a full bucket, dynamic number
min := max
@@ -276,7 +275,7 @@ func (self *Kademlia) FindClosest(target Address, max int) []Node {
n++
}
// terminate if index reached the bottom or enough peers > min
- glog.V(logger.Detail).Infof("add %v -> %v (PO%02d, PO%03d)", len(self.buckets[index]), n, index, po)
+ log.Trace(fmt.Sprintf("add %v -> %v (PO%02d, PO%03d)", len(self.buckets[index]), n, index, po))
if n >= min && (step < 0 || max == 0) {
break
}
@@ -287,7 +286,7 @@ func (self *Kademlia) FindClosest(target Address, max int) []Node {
}
index += step
}
- glog.V(logger.Detail).Infof("serve %d (<=%d) nodes for target lookup %v (PO%03d)", n, max, target, po)
+ log.Trace(fmt.Sprintf("serve %d (<=%d) nodes for target lookup %v (PO%03d)", n, max, target, po))
return r.nodes
}
diff --git a/swarm/network/protocol.go b/swarm/network/protocol.go
index 763fb0b8e2..d013b3109b 100644
--- a/swarm/network/protocol.go
+++ b/swarm/network/protocol.go
@@ -31,15 +31,14 @@ The bzz protocol component speaks the bzz protocol
*/
import (
+ "errors"
"fmt"
"net"
"strconv"
"time"
"github.com/ethereum/go-ethereum/contracts/chequebook"
- "github.com/ethereum/go-ethereum/errs"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/p2p/discover"
bzzswap "github.com/ethereum/go-ethereum/swarm/services/swap"
@@ -54,32 +53,6 @@ const (
NetworkId = 3
)
-const (
- ErrMsgTooLarge = iota
- ErrDecode
- ErrInvalidMsgCode
- ErrVersionMismatch
- ErrNetworkIdMismatch
- ErrNoStatusMsg
- ErrExtraStatusMsg
- ErrSwap
- ErrSync
- ErrUnwanted
-)
-
-var errorToString = map[int]string{
- ErrMsgTooLarge: "Message too long",
- ErrDecode: "Invalid message",
- ErrInvalidMsgCode: "Invalid message code",
- ErrVersionMismatch: "Protocol version mismatch",
- ErrNetworkIdMismatch: "NetworkId mismatch",
- ErrNoStatusMsg: "No status message",
- ErrExtraStatusMsg: "Extra status message",
- ErrSwap: "SWAP error",
- ErrSync: "Sync error",
- ErrUnwanted: "Unwanted peer",
-}
-
// bzz represents the swarm wire protocol
// an instance is running on each peer
type bzz struct {
@@ -92,7 +65,6 @@ type bzz struct {
remoteAddr *peerAddr // remote peers address
peer *p2p.Peer // the p2p peer object
rw p2p.MsgReadWriter // messageReadWriter to send messages to
- errors *errs.Errors // errors table
backend chequebook.Backend
lastActive time.Time
NetworkId uint64
@@ -163,17 +135,13 @@ the main protocol loop that
func run(requestDb *storage.LDBDatabase, depo StorageHandler, backend chequebook.Backend, hive *Hive, dbaccess *DbAccess, sp *bzzswap.SwapParams, sy *SyncParams, networkId uint64, p *p2p.Peer, rw p2p.MsgReadWriter) (err error) {
self := &bzz{
- storage: depo,
- backend: backend,
- hive: hive,
- dbAccess: dbaccess,
- requestDb: requestDb,
- peer: p,
- rw: rw,
- errors: &errs.Errors{
- Package: "BZZ",
- Errors: errorToString,
- },
+ storage: depo,
+ backend: backend,
+ hive: hive,
+ dbAccess: dbaccess,
+ requestDb: requestDb,
+ peer: p,
+ rw: rw,
swapParams: sp,
syncParams: sy,
swapEnabled: hive.swapEnabled,
@@ -201,7 +169,7 @@ func run(requestDb *storage.LDBDatabase, depo StorageHandler, backend chequebook
// the main forever loop that handles incoming requests
for {
if self.hive.blockRead {
- glog.V(logger.Warn).Infof("Cannot read network")
+ log.Warn(fmt.Sprintf("Cannot read network"))
time.Sleep(100 * time.Millisecond)
continue
}
@@ -221,12 +189,12 @@ func (self *bzz) Drop() {
// one cycle of the main forever loop that handles and dispatches incoming messages
func (self *bzz) handle() error {
msg, err := self.rw.ReadMsg()
- glog.V(logger.Debug).Infof("<- %v", msg)
+ log.Debug(fmt.Sprintf("<- %v", msg))
if err != nil {
return err
}
if msg.Size > ProtocolMaxMsgSize {
- return self.protoError(ErrMsgTooLarge, "%v > %v", msg.Size, ProtocolMaxMsgSize)
+ return fmt.Errorf("message too long: %v > %v", msg.Size, ProtocolMaxMsgSize)
}
// make sure that the payload has been fully consumed
defer msg.Discard()
@@ -236,21 +204,21 @@ func (self *bzz) handle() error {
case statusMsg:
// no extra status message allowed. The one needed already handled by
// handleStatus
- glog.V(logger.Debug).Infof("Status message: %v", msg)
- return self.protoError(ErrExtraStatusMsg, "")
+ log.Debug(fmt.Sprintf("Status message: %v", msg))
+ return errors.New("extra status message")
case storeRequestMsg:
// store requests are dispatched to netStore
var req storeRequestMsgData
if err := msg.Decode(&req); err != nil {
- return self.protoError(ErrDecode, "<- %v: %v", msg, err)
+ return fmt.Errorf("<- %v: %v", msg, err)
}
- if len(req.SData) < 9 {
- return self.protoError(ErrDecode, "<- %v: Data too short (%v)", msg)
+ if n := len(req.SData); n < 9 {
+ return fmt.Errorf("<- %v: Data too short (%v)", msg, n)
}
// last Active time is set only when receiving chunks
self.lastActive = time.Now()
- glog.V(logger.Detail).Infof("incoming store request: %s", req.String())
+ log.Trace(fmt.Sprintf("incoming store request: %s", req.String()))
// swap accounting is done within forwarding
self.storage.HandleStoreRequestMsg(&req, &peer{bzz: self})
@@ -258,14 +226,14 @@ func (self *bzz) handle() error {
// retrieve Requests are dispatched to netStore
var req retrieveRequestMsgData
if err := msg.Decode(&req); err != nil {
- return self.protoError(ErrDecode, "<- %v: %v", msg, err)
+ return fmt.Errorf("<- %v: %v", msg, err)
}
req.from = &peer{bzz: self}
// if request is lookup and not to be delivered
if req.isLookup() {
- glog.V(logger.Detail).Infof("self lookup for %v: responding with peers only...", req.from)
+ log.Trace(fmt.Sprintf("self lookup for %v: responding with peers only...", req.from))
} else if req.Key == nil {
- return self.protoError(ErrDecode, "protocol handler: req.Key == nil || req.Timeout == nil")
+ return fmt.Errorf("protocol handler: req.Key == nil || req.Timeout == nil")
} else {
// swap accounting is done within netStore
self.storage.HandleRetrieveRequestMsg(&req, &peer{bzz: self})
@@ -278,18 +246,18 @@ func (self *bzz) handle() error {
// dispatches new peer data to the hive that adds them to KADDB
var req peersMsgData
if err := msg.Decode(&req); err != nil {
- return self.protoError(ErrDecode, "<- %v: %v", msg, err)
+ return fmt.Errorf("<- %v: %v", msg, err)
}
req.from = &peer{bzz: self}
- glog.V(logger.Detail).Infof("<- peer addresses: %v", req)
+ log.Trace(fmt.Sprintf("<- peer addresses: %v", req))
self.hive.HandlePeersMsg(&req, &peer{bzz: self})
case syncRequestMsg:
var req syncRequestMsgData
if err := msg.Decode(&req); err != nil {
- return self.protoError(ErrDecode, "<- %v: %v", msg, err)
+ return fmt.Errorf("<- %v: %v", msg, err)
}
- glog.V(logger.Debug).Infof("<- sync request: %v", req)
+ log.Debug(fmt.Sprintf("<- sync request: %v", req))
self.lastActive = time.Now()
self.sync(req.SyncState)
@@ -297,13 +265,13 @@ func (self *bzz) handle() error {
// coming from parent node offering
var req unsyncedKeysMsgData
if err := msg.Decode(&req); err != nil {
- return self.protoError(ErrDecode, "<- %v: %v", msg, err)
+ return fmt.Errorf("<- %v: %v", msg, err)
}
- glog.V(logger.Debug).Infof("<- unsynced keys : %s", req.String())
+ log.Debug(fmt.Sprintf("<- unsynced keys : %s", req.String()))
err := self.storage.HandleUnsyncedKeysMsg(&req, &peer{bzz: self})
self.lastActive = time.Now()
if err != nil {
- return self.protoError(ErrDecode, "<- %v: %v", msg, err)
+ return fmt.Errorf("<- %v: %v", msg, err)
}
case deliveryRequestMsg:
@@ -311,13 +279,13 @@ func (self *bzz) handle() error {
// also relays the last synced state to the source
var req deliveryRequestMsgData
if err := msg.Decode(&req); err != nil {
- return self.protoError(ErrDecode, "<-msg %v: %v", msg, err)
+ return fmt.Errorf("<-msg %v: %v", msg, err)
}
- glog.V(logger.Debug).Infof("<- delivery request: %s", req.String())
+ log.Debug(fmt.Sprintf("<- delivery request: %s", req.String()))
err := self.storage.HandleDeliveryRequestMsg(&req, &peer{bzz: self})
self.lastActive = time.Now()
if err != nil {
- return self.protoError(ErrDecode, "<- %v: %v", msg, err)
+ return fmt.Errorf("<- %v: %v", msg, err)
}
case paymentMsg:
@@ -325,15 +293,15 @@ func (self *bzz) handle() error {
if self.swapEnabled {
var req paymentMsgData
if err := msg.Decode(&req); err != nil {
- return self.protoError(ErrDecode, "<- %v: %v", msg, err)
+ return fmt.Errorf("<- %v: %v", msg, err)
}
- glog.V(logger.Debug).Infof("<- payment: %s", req.String())
+ log.Debug(fmt.Sprintf("<- payment: %s", req.String()))
self.swap.Receive(int(req.Units), req.Promise)
}
default:
// no other message is allowed
- return self.protoError(ErrInvalidMsgCode, "%v", msg.Code)
+ return fmt.Errorf("invalid message code: %v", msg.Code)
}
return nil
}
@@ -353,7 +321,7 @@ func (self *bzz) handleStatus() (err error) {
err = p2p.Send(self.rw, statusMsg, handshake)
if err != nil {
- self.protoError(ErrNoStatusMsg, err.Error())
+ return err
}
// read and handle remote status
@@ -364,45 +332,45 @@ func (self *bzz) handleStatus() (err error) {
}
if msg.Code != statusMsg {
- self.protoError(ErrNoStatusMsg, "first msg has code %x (!= %x)", msg.Code, statusMsg)
+ return fmt.Errorf("first msg has code %x (!= %x)", msg.Code, statusMsg)
}
if msg.Size > ProtocolMaxMsgSize {
- return self.protoError(ErrMsgTooLarge, "%v > %v", msg.Size, ProtocolMaxMsgSize)
+ return fmt.Errorf("message too long: %v > %v", msg.Size, ProtocolMaxMsgSize)
}
var status statusMsgData
if err := msg.Decode(&status); err != nil {
- return self.protoError(ErrDecode, " %v: %v", msg, err)
+ return fmt.Errorf("<- %v: %v", msg, err)
}
if status.NetworkId != self.NetworkId {
- return self.protoError(ErrNetworkIdMismatch, "%d (!= %d)", status.NetworkId, self.NetworkId)
+ return fmt.Errorf("network id mismatch: %d (!= %d)", status.NetworkId, self.NetworkId)
}
if Version != status.Version {
- return self.protoError(ErrVersionMismatch, "%d (!= %d)", status.Version, Version)
+ return fmt.Errorf("protocol version mismatch: %d (!= %d)", status.Version, Version)
}
self.remoteAddr = self.peerAddr(status.Addr)
- glog.V(logger.Detail).Infof("self: advertised IP: %v, peer advertised: %v, local address: %v\npeer: advertised IP: %v, remote address: %v\n", self.selfAddr(), self.remoteAddr, self.peer.LocalAddr(), status.Addr.IP, self.peer.RemoteAddr())
+ log.Trace(fmt.Sprintf("self: advertised IP: %v, peer advertised: %v, local address: %v\npeer: advertised IP: %v, remote address: %v\n", self.selfAddr(), self.remoteAddr, self.peer.LocalAddr(), status.Addr.IP, self.peer.RemoteAddr()))
if self.swapEnabled {
// set remote profile for accounting
self.swap, err = bzzswap.NewSwap(self.swapParams, status.Swap, self.backend, self)
if err != nil {
- return self.protoError(ErrSwap, "%v", err)
+ return err
}
}
- glog.V(logger.Info).Infof("Peer %08x is capable (%d/%d)", self.remoteAddr.Addr[:4], status.Version, status.NetworkId)
+ log.Info(fmt.Sprintf("Peer %08x is capable (%d/%d)", self.remoteAddr.Addr[:4], status.Version, status.NetworkId))
err = self.hive.addPeer(&peer{bzz: self})
if err != nil {
- return self.protoError(ErrUnwanted, "%v", err)
+ return err
}
// hive sets syncstate so sync should start after node added
- glog.V(logger.Info).Infof("syncronisation request sent with %v", self.syncState)
+ log.Info(fmt.Sprintf("syncronisation request sent with %v", self.syncState))
self.syncRequest()
return nil
@@ -411,7 +379,7 @@ func (self *bzz) handleStatus() (err error) {
func (self *bzz) sync(state *syncState) error {
// syncer setup
if self.syncer != nil {
- return self.protoError(ErrSync, "sync request can only be sent once")
+ return errors.New("sync request can only be sent once")
}
cnt := self.dbAccess.counter()
@@ -421,7 +389,7 @@ func (self *bzz) sync(state *syncState) error {
// an explicitly received nil syncstate disables syncronisation
if state == nil {
self.syncEnabled = false
- glog.V(logger.Warn).Infof("syncronisation disabled for peer %v", self)
+ log.Warn(fmt.Sprintf("syncronisation disabled for peer %v", self))
state = &syncState{DbSyncState: &storage.DbSyncState{}, Synced: true}
} else {
state.synced = make(chan bool)
@@ -430,7 +398,7 @@ func (self *bzz) sync(state *syncState) error {
state.Start = storage.Key(start[:])
state.Stop = storage.Key(stop[:])
}
- glog.V(logger.Debug).Infof("syncronisation requested by peer %v at state %v", self, state)
+ log.Debug(fmt.Sprintf("syncronisation requested by peer %v at state %v", self, state))
}
var err error
self.syncer, err = newSyncer(
@@ -441,9 +409,9 @@ func (self *bzz) sync(state *syncState) error {
self.syncParams, state, func() bool { return self.syncEnabled },
)
if err != nil {
- return self.protoError(ErrSync, "%v", err)
+ return nil
}
- glog.V(logger.Detail).Infof("syncer set for peer %v", self)
+ log.Trace(fmt.Sprintf("syncer set for peer %v", self))
return nil
}
@@ -490,11 +458,11 @@ func (self *bzz) store(req *storeRequestMsgData) error {
func (self *bzz) syncRequest() error {
req := &syncRequestMsgData{}
if self.hive.syncEnabled {
- glog.V(logger.Debug).Infof("syncronisation request to peer %v at state %v", self, self.syncState)
+ log.Debug(fmt.Sprintf("syncronisation request to peer %v at state %v", self, self.syncState))
req.SyncState = self.syncState
}
if self.syncState == nil {
- glog.V(logger.Warn).Infof("syncronisation disabled for peer %v at state %v", self, self.syncState)
+ log.Warn(fmt.Sprintf("syncronisation disabled for peer %v at state %v", self, self.syncState))
}
return self.send(syncRequestMsg, req)
}
@@ -532,17 +500,11 @@ func (self *bzz) peers(req *peersMsgData) error {
return self.send(peersMsg, req)
}
-func (self *bzz) protoError(code int, format string, params ...interface{}) (err *errs.Error) {
- err = self.errors.New(code, format, params...)
- err.Log(glog.V(logger.Info))
- return
-}
-
func (self *bzz) send(msg uint64, data interface{}) error {
if self.hive.blockWrite {
return fmt.Errorf("network write blocked")
}
- glog.V(logger.Detail).Infof("-> %v: %v (%T) to %v", msg, data, data, self)
+ log.Trace(fmt.Sprintf("-> %v: %v (%T) to %v", msg, data, data, self))
err := p2p.Send(self.rw, msg, data)
if err != nil {
self.Drop()
diff --git a/swarm/network/syncdb.go b/swarm/network/syncdb.go
index cef32610f6..88b4b68dd0 100644
--- a/swarm/network/syncdb.go
+++ b/swarm/network/syncdb.go
@@ -20,8 +20,7 @@ import (
"encoding/binary"
"fmt"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/swarm/storage"
"github.com/syndtr/goleveldb/leveldb"
"github.com/syndtr/goleveldb/leveldb/iterator"
@@ -80,7 +79,7 @@ func newSyncDb(db *storage.LDBDatabase, key storage.Key, priority uint, bufferSi
batch: make(chan chan int),
dbBatchSize: dbBatchSize,
}
- glog.V(logger.Detail).Infof("syncDb[peer: %v, priority: %v] - initialised", key.Log(), priority)
+ log.Trace(fmt.Sprintf("syncDb[peer: %v, priority: %v] - initialised", key.Log(), priority))
// starts the main forever loop reading from buffer
go syncdb.bufferRead(deliver)
@@ -126,9 +125,9 @@ func (self *syncDb) bufferRead(deliver func(interface{}, chan bool) bool) {
var counter uint64
if err == nil {
counter = binary.BigEndian.Uint64(data)
- glog.V(logger.Detail).Infof("syncDb[%v/%v] - counter read from db at %v", self.key.Log(), self.priority, counter)
+ log.Trace(fmt.Sprintf("syncDb[%v/%v] - counter read from db at %v", self.key.Log(), self.priority, counter))
} else {
- glog.V(logger.Detail).Infof("syncDb[%v/%v] - counter starts at %v", self.key.Log(), self.priority, counter)
+ log.Trace(fmt.Sprintf("syncDb[%v/%v] - counter starts at %v", self.key.Log(), self.priority, counter))
}
LOOP:
@@ -142,7 +141,7 @@ LOOP:
// if syncdb is stopped. In this case we need to save the item to the db
more = deliver(req, self.quit)
if !more {
- glog.V(logger.Debug).Infof("syncDb[%v/%v] quit: switching to db. session tally (db/total): %v/%v", self.key.Log(), self.priority, self.dbTotal, self.total)
+ log.Debug(fmt.Sprintf("syncDb[%v/%v] quit: switching to db. session tally (db/total): %v/%v", self.key.Log(), self.priority, self.dbTotal, self.total))
// received quit signal, save request currently waiting delivery
// by switching to db mode and closing the buffer
buffer = nil
@@ -152,12 +151,12 @@ LOOP:
break // break from select, this item will be written to the db
}
self.total++
- glog.V(logger.Detail).Infof("syncDb[%v/%v] deliver (db/total): %v/%v", self.key.Log(), self.priority, self.dbTotal, self.total)
+ log.Trace(fmt.Sprintf("syncDb[%v/%v] deliver (db/total): %v/%v", self.key.Log(), self.priority, self.dbTotal, self.total))
// by the time deliver returns, there were new writes to the buffer
// if buffer contention is detected, switch to db mode which drains
// the buffer so no process will block on pushing store requests
if len(buffer) == cap(buffer) {
- glog.V(logger.Debug).Infof("syncDb[%v/%v] buffer full %v: switching to db. session tally (db/total): %v/%v", self.key.Log(), self.priority, cap(buffer), self.dbTotal, self.total)
+ log.Debug(fmt.Sprintf("syncDb[%v/%v] buffer full %v: switching to db. session tally (db/total): %v/%v", self.key.Log(), self.priority, cap(buffer), self.dbTotal, self.total))
buffer = nil
db = self.buffer
}
@@ -170,7 +169,7 @@ LOOP:
binary.BigEndian.PutUint64(counterValue, counter)
batch.Put(self.counterKey, counterValue) // persist counter in batch
self.writeSyncBatch(batch) // save batch
- glog.V(logger.Detail).Infof("syncDb[%v/%v] quitting: save current batch to db", self.key.Log(), self.priority)
+ log.Trace(fmt.Sprintf("syncDb[%v/%v] quitting: save current batch to db", self.key.Log(), self.priority))
break LOOP
}
self.dbTotal++
@@ -181,7 +180,7 @@ LOOP:
if inBatch == 0 && quit != nil {
// there was no writes since the last batch so db depleted
// switch to buffer mode
- glog.V(logger.Debug).Infof("syncDb[%v/%v] empty db: switching to buffer", self.key.Log(), self.priority)
+ log.Debug(fmt.Sprintf("syncDb[%v/%v] empty db: switching to buffer", self.key.Log(), self.priority))
db = nil
buffer = self.buffer
dbSize <- 0 // indicates to 'caller' that batch has been written
@@ -190,7 +189,7 @@ LOOP:
}
binary.BigEndian.PutUint64(counterValue, counter)
batch.Put(self.counterKey, counterValue)
- glog.V(logger.Debug).Infof("syncDb[%v/%v] write batch %v/%v - %x - %x", self.key.Log(), self.priority, inBatch, counter, self.counterKey, counterValue)
+ log.Debug(fmt.Sprintf("syncDb[%v/%v] write batch %v/%v - %x - %x", self.key.Log(), self.priority, inBatch, counter, self.counterKey, counterValue))
batch = self.writeSyncBatch(batch)
dbSize <- inBatch // indicates to 'caller' that batch has been written
inBatch = 0
@@ -202,7 +201,7 @@ LOOP:
db = self.buffer
buffer = nil
quit = nil
- glog.V(logger.Detail).Infof("syncDb[%v/%v] quitting: save buffer to db", self.key.Log(), self.priority)
+ log.Trace(fmt.Sprintf("syncDb[%v/%v] quitting: save buffer to db", self.key.Log(), self.priority))
close(db)
continue LOOP
}
@@ -210,15 +209,15 @@ LOOP:
// only get here if we put req into db
entry, err = self.newSyncDbEntry(req, counter)
if err != nil {
- glog.V(logger.Warn).Infof("syncDb[%v/%v] saving request %v (#%v/%v) failed: %v", self.key.Log(), self.priority, req, inBatch, inDb, err)
+ log.Warn(fmt.Sprintf("syncDb[%v/%v] saving request %v (#%v/%v) failed: %v", self.key.Log(), self.priority, req, inBatch, inDb, err))
continue LOOP
}
batch.Put(entry.key, entry.val)
- glog.V(logger.Detail).Infof("syncDb[%v/%v] to batch %v '%v' (#%v/%v/%v)", self.key.Log(), self.priority, req, entry, inBatch, inDb, counter)
+ log.Trace(fmt.Sprintf("syncDb[%v/%v] to batch %v '%v' (#%v/%v/%v)", self.key.Log(), self.priority, req, entry, inBatch, inDb, counter))
// if just switched to db mode and not quitting, then launch dbRead
// in a parallel go routine to send deliveries from db
if inDb == 0 && quit != nil {
- glog.V(logger.Detail).Infof("syncDb[%v/%v] start dbRead")
+ log.Trace(fmt.Sprintf("syncDb[%v/%v] start dbRead", self.key.Log(), self.priority))
go self.dbRead(true, counter, deliver)
}
inDb++
@@ -229,7 +228,7 @@ LOOP:
batch = self.writeSyncBatch(batch)
}
}
- glog.V(logger.Info).Infof("syncDb[%v:%v]: saved %v keys (saved counter at %v)", self.key.Log(), self.priority, inBatch, counter)
+ log.Info(fmt.Sprintf("syncDb[%v:%v]: saved %v keys (saved counter at %v)", self.key.Log(), self.priority, inBatch, counter))
close(self.done)
}
@@ -237,7 +236,7 @@ LOOP:
func (self *syncDb) writeSyncBatch(batch *leveldb.Batch) *leveldb.Batch {
err := self.db.Write(batch)
if err != nil {
- glog.V(logger.Warn).Infof("syncDb[%v/%v] saving batch to db failed: %v", self.key.Log(), self.priority, err)
+ log.Warn(fmt.Sprintf("syncDb[%v/%v] saving batch to db failed: %v", self.key.Log(), self.priority, err))
return batch
}
return new(leveldb.Batch)
@@ -311,7 +310,7 @@ func (self *syncDb) dbRead(useBatches bool, counter uint64, fun func(interface{}
continue
}
del = new(leveldb.Batch)
- glog.V(logger.Detail).Infof("syncDb[%v/%v]: new iterator: %x (batch %v, count %v)", self.key.Log(), self.priority, key, batches, cnt)
+ log.Trace(fmt.Sprintf("syncDb[%v/%v]: new iterator: %x (batch %v, count %v)", self.key.Log(), self.priority, key, batches, cnt))
for n = 0; !useBatches || n < cnt; it.Next() {
copy(key, it.Key())
@@ -323,11 +322,11 @@ func (self *syncDb) dbRead(useBatches bool, counter uint64, fun func(interface{}
val := make([]byte, 40)
copy(val, it.Value())
entry = &syncDbEntry{key, val}
- // glog.V(logger.Detail).Infof("syncDb[%v/%v] - %v, batches: %v, total: %v, session total from db: %v/%v", self.key.Log(), self.priority, self.key.Log(), batches, total, self.dbTotal, self.total)
+ // log.Trace(fmt.Sprintf("syncDb[%v/%v] - %v, batches: %v, total: %v, session total from db: %v/%v", self.key.Log(), self.priority, self.key.Log(), batches, total, self.dbTotal, self.total))
more = fun(entry, self.quit)
if !more {
// quit received when waiting to deliver entry, the entry will not be deleted
- glog.V(logger.Detail).Infof("syncDb[%v/%v] batch %v quit after %v/%v items", self.key.Log(), self.priority, batches, n, cnt)
+ log.Trace(fmt.Sprintf("syncDb[%v/%v] batch %v quit after %v/%v items", self.key.Log(), self.priority, batches, n, cnt))
break
}
// since subsequent batches of the same db session are indexed incrementally
@@ -337,7 +336,7 @@ func (self *syncDb) dbRead(useBatches bool, counter uint64, fun func(interface{}
n++
total++
}
- glog.V(logger.Debug).Infof("syncDb[%v/%v] - db session closed, batches: %v, total: %v, session total from db: %v/%v", self.key.Log(), self.priority, batches, total, self.dbTotal, self.total)
+ log.Debug(fmt.Sprintf("syncDb[%v/%v] - db session closed, batches: %v, total: %v, session total from db: %v/%v", self.key.Log(), self.priority, batches, total, self.dbTotal, self.total))
self.db.Write(del) // this could be async called only when db is idle
it.Release()
}
diff --git a/swarm/network/syncdb_test.go b/swarm/network/syncdb_test.go
index 21453a1102..be21d156f9 100644
--- a/swarm/network/syncdb_test.go
+++ b/swarm/network/syncdb_test.go
@@ -18,6 +18,7 @@ package network
import (
"bytes"
+ "fmt"
"io/ioutil"
"os"
"path/filepath"
@@ -25,14 +26,12 @@ import (
"time"
"github.com/ethereum/go-ethereum/crypto"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/swarm/storage"
)
func init() {
- glog.SetV(0)
- glog.SetToStderr(true)
+ log.Root().SetHandler(log.LvlFilterHandler(log.LvlCrit, log.StreamHandler(os.Stderr, log.TerminalFormat(false))))
}
type testSyncDb struct {
@@ -83,7 +82,7 @@ func (self *testSyncDb) push(n int) {
self.sent = append(self.sent, self.c)
self.c++
}
- glog.V(logger.Debug).Infof("pushed %v requests", n)
+ log.Debug(fmt.Sprintf("pushed %v requests", n))
}
func (self *testSyncDb) draindb() {
@@ -128,7 +127,7 @@ func (self *testSyncDb) expect(n int, db bool) {
}
if len(self.sent) > self.at && !bytes.Equal(crypto.Keccak256([]byte{byte(self.sent[self.at])}), self.delivered[self.at]) {
self.t.Fatalf("expected delivery %v/%v/%v to be hash of %v, from db: %v = %v", i, n, self.at, self.sent[self.at], ok, db)
- glog.V(logger.Debug).Infof("%v/%v/%v to be hash of %v, from db: %v = %v", i, n, self.at, self.sent[self.at], ok, db)
+ log.Debug(fmt.Sprintf("%v/%v/%v to be hash of %v, from db: %v = %v", i, n, self.at, self.sent[self.at], ok, db))
}
if !ok && db {
self.t.Fatalf("expected delivery %v/%v/%v from db", i, n, self.at)
diff --git a/swarm/network/syncer.go b/swarm/network/syncer.go
index b6b1ea3b60..20129c2a81 100644
--- a/swarm/network/syncer.go
+++ b/swarm/network/syncer.go
@@ -22,8 +22,7 @@ import (
"fmt"
"path/filepath"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/swarm/storage"
)
@@ -209,7 +208,7 @@ func newSyncer(
// initialise a syncdb instance for each priority queue
self.queues[i] = newSyncDb(db, remotekey, uint(i), syncBufferSize, dbBatchSize, self.deliver(uint(i)))
}
- glog.V(logger.Info).Infof("syncer started: %v", state)
+ log.Info(fmt.Sprintf("syncer started: %v", state))
// launch chunk delivery service
go self.syncDeliveries()
// launch sync task manager
@@ -270,14 +269,14 @@ func (self *syncer) sync() {
// 0. first replay stale requests from request db
if state.SessionAt == 0 {
- glog.V(logger.Debug).Infof("syncer[%v]: nothing to sync", self.key.Log())
+ log.Debug(fmt.Sprintf("syncer[%v]: nothing to sync", self.key.Log()))
return
}
- glog.V(logger.Debug).Infof("syncer[%v]: start replaying stale requests from request db", self.key.Log())
+ log.Debug(fmt.Sprintf("syncer[%v]: start replaying stale requests from request db", self.key.Log()))
for p := priorities - 1; p >= 0; p-- {
self.queues[p].dbRead(false, 0, self.replay())
}
- glog.V(logger.Debug).Infof("syncer[%v]: done replaying stale requests from request db", self.key.Log())
+ log.Debug(fmt.Sprintf("syncer[%v]: done replaying stale requests from request db", self.key.Log()))
// unless peer is synced sync unfinished history beginning on
if !state.Synced {
@@ -286,7 +285,7 @@ func (self *syncer) sync() {
if !storage.IsZeroKey(state.Latest) {
// 1. there is unfinished earlier sync
state.Start = state.Latest
- glog.V(logger.Debug).Infof("syncer[%v]: start syncronising backlog (unfinished sync: %v)", self.key.Log(), state)
+ log.Debug(fmt.Sprintf("syncer[%v]: start syncronising backlog (unfinished sync: %v)", self.key.Log(), state))
// blocks while the entire history upto state is synced
self.syncState(state)
if state.Last < state.SessionAt {
@@ -298,7 +297,7 @@ func (self *syncer) sync() {
// 2. sync up to last disconnect1
if state.First < state.LastSeenAt {
state.Last = state.LastSeenAt
- glog.V(logger.Debug).Infof("syncer[%v]: start syncronising history upto last disconnect at %v: %v", self.key.Log(), state.LastSeenAt, state)
+ log.Debug(fmt.Sprintf("syncer[%v]: start syncronising history upto last disconnect at %v: %v", self.key.Log(), state.LastSeenAt, state))
self.syncState(state)
state.First = state.LastSeenAt
}
@@ -313,11 +312,11 @@ func (self *syncer) sync() {
// if there have been new chunks since last session
if state.LastSeenAt < state.SessionAt {
state.Last = state.SessionAt
- glog.V(logger.Debug).Infof("syncer[%v]: start syncronising history since last disconnect at %v up until session start at %v: %v", self.key.Log(), state.LastSeenAt, state.SessionAt, state)
+ log.Debug(fmt.Sprintf("syncer[%v]: start syncronising history since last disconnect at %v up until session start at %v: %v", self.key.Log(), state.LastSeenAt, state.SessionAt, state))
// blocks until state syncing is finished
self.syncState(state)
}
- glog.V(logger.Info).Infof("syncer[%v]: syncing all history complete", self.key.Log())
+ log.Info(fmt.Sprintf("syncer[%v]: syncing all history complete", self.key.Log()))
}
@@ -333,7 +332,7 @@ func (self *syncer) syncState(state *syncState) {
// stop quits both request processor and saves the request cache to disk
func (self *syncer) stop() {
close(self.quit)
- glog.V(logger.Detail).Infof("syncer[%v]: stop and save sync request db backlog", self.key.Log())
+ log.Trace(fmt.Sprintf("syncer[%v]: stop and save sync request db backlog", self.key.Log()))
for _, db := range self.queues {
db.stop()
}
@@ -366,7 +365,7 @@ func (self *syncer) newSyncRequest(req interface{}, p int) (*syncRequest, error)
func (self *syncer) syncHistory(state *syncState) chan interface{} {
var n uint
history := make(chan interface{})
- glog.V(logger.Debug).Infof("syncer[%v]: syncing history between %v - %v for chunk addresses %v - %v", self.key.Log(), state.First, state.Last, state.Start, state.Stop)
+ log.Debug(fmt.Sprintf("syncer[%v]: syncing history between %v - %v for chunk addresses %v - %v", self.key.Log(), state.First, state.Last, state.Start, state.Stop))
it := self.dbAccess.iterator(state)
if it != nil {
go func() {
@@ -382,13 +381,13 @@ func (self *syncer) syncHistory(state *syncState) chan interface{} {
// blocking until history channel is read from
case history <- storage.Key(key):
n++
- glog.V(logger.Detail).Infof("syncer[%v]: history: %v (%v keys)", self.key.Log(), key.Log(), n)
+ log.Trace(fmt.Sprintf("syncer[%v]: history: %v (%v keys)", self.key.Log(), key.Log(), n))
state.Latest = key
case <-self.quit:
return
}
}
- glog.V(logger.Debug).Infof("syncer[%v]: finished syncing history between %v - %v for chunk addresses %v - %v (at %v) (chunks = %v)", self.key.Log(), state.First, state.Last, state.Start, state.Stop, state.Latest, n)
+ log.Debug(fmt.Sprintf("syncer[%v]: finished syncing history between %v - %v for chunk addresses %v - %v (at %v) (chunks = %v)", self.key.Log(), state.First, state.Last, state.Start, state.Stop, state.Latest, n))
}()
}
return history
@@ -438,14 +437,14 @@ LOOP:
for priority = High; priority >= 0; priority-- {
// the first priority channel that is non-empty will be assigned to keys
if len(self.keys[priority]) > 0 {
- glog.V(logger.Detail).Infof("syncer[%v]: reading request with priority %v", self.key.Log(), priority)
+ log.Trace(fmt.Sprintf("syncer[%v]: reading request with priority %v", self.key.Log(), priority))
keys = self.keys[priority]
break PRIORITIES
}
- glog.V(logger.Detail).Infof("syncer[%v/%v]: queue: [%v, %v, %v]", self.key.Log(), priority, len(self.keys[High]), len(self.keys[Medium]), len(self.keys[Low]))
+ log.Trace(fmt.Sprintf("syncer[%v/%v]: queue: [%v, %v, %v]", self.key.Log(), priority, len(self.keys[High]), len(self.keys[Medium]), len(self.keys[Low])))
// if the input queue is empty on this level, resort to history if there is any
if uint(priority) == histPrior && history != nil {
- glog.V(logger.Detail).Infof("syncer[%v]: reading history for %v", self.key.Log(), self.key)
+ log.Trace(fmt.Sprintf("syncer[%v]: reading history for %v", self.key.Log(), self.key))
keys = history
break PRIORITIES
}
@@ -455,7 +454,7 @@ LOOP:
// if peer ready to receive but nothing to send
if keys == nil && deliveryRequest == nil {
// if no items left and switch to waiting mode
- glog.V(logger.Detail).Infof("syncer[%v]: buffers consumed. Waiting", self.key.Log())
+ log.Trace(fmt.Sprintf("syncer[%v]: buffers consumed. Waiting", self.key.Log()))
newUnsyncedKeys = self.newUnsyncedKeys
}
@@ -476,15 +475,15 @@ LOOP:
// (all nonhistorical outgoing traffic sheduled and persisted
state.LastSeenAt = self.dbAccess.counter()
state.Latest = storage.ZeroKey
- glog.V(logger.Detail).Infof("syncer[%v]: sending %v", self.key.Log(), unsynced)
+ log.Trace(fmt.Sprintf("syncer[%v]: sending %v", self.key.Log(), unsynced))
// send the unsynced keys
stateCopy := *state
err := self.unsyncedKeys(unsynced, &stateCopy)
if err != nil {
- glog.V(logger.Warn).Infof("syncer[%v]: unable to send unsynced keys: %v", err)
+ log.Warn(fmt.Sprintf("syncer[%v]: unable to send unsynced keys: %v", self.key.Log(), err))
}
self.state = state
- glog.V(logger.Debug).Infof("syncer[%v]: --> %v keys sent: (total: %v (%v), history: %v), sent sync state: %v", self.key.Log(), len(unsynced), keyCounts, keyCount, historyCnt, stateCopy)
+ log.Debug(fmt.Sprintf("syncer[%v]: --> %v keys sent: (total: %v (%v), history: %v), sent sync state: %v", self.key.Log(), len(unsynced), keyCounts, keyCount, historyCnt, stateCopy))
unsynced = nil
keys = nil
}
@@ -495,7 +494,7 @@ LOOP:
break LOOP
case req, more = <-keys:
if keys == history && !more {
- glog.V(logger.Detail).Infof("syncer[%v]: syncing history segment complete", self.key.Log())
+ log.Trace(fmt.Sprintf("syncer[%v]: syncing history segment complete", self.key.Log()))
// history channel is closed, waiting for new state (called from sync())
syncStates = self.syncStates
state.Synced = true // this signals that the current segment is complete
@@ -508,7 +507,7 @@ LOOP:
history = nil
}
case <-deliveryRequest:
- glog.V(logger.Detail).Infof("syncer[%v]: peer ready to receive", self.key.Log())
+ log.Trace(fmt.Sprintf("syncer[%v]: peer ready to receive", self.key.Log()))
// this 1 cap channel can wake up the loop
// signaling that peer is ready to receive unsynced Keys
@@ -516,7 +515,7 @@ LOOP:
deliveryRequest = nil
case <-newUnsyncedKeys:
- glog.V(logger.Detail).Infof("syncer[%v]: new unsynced keys available", self.key.Log())
+ log.Trace(fmt.Sprintf("syncer[%v]: new unsynced keys available", self.key.Log()))
// this 1 cap channel can wake up the loop
// signals that data is available to send if peer is ready to receive
newUnsyncedKeys = nil
@@ -526,11 +525,11 @@ LOOP:
// this resets the state
if !more {
state = self.state
- glog.V(logger.Detail).Infof("syncer[%v]: (priority %v) syncing complete upto %v)", self.key.Log(), priority, state)
+ log.Trace(fmt.Sprintf("syncer[%v]: (priority %v) syncing complete upto %v)", self.key.Log(), priority, state))
state.Synced = true
syncStates = nil
} else {
- glog.V(logger.Detail).Infof("syncer[%v]: (priority %v) syncing history upto %v priority %v)", self.key.Log(), priority, state, histPrior)
+ log.Trace(fmt.Sprintf("syncer[%v]: (priority %v) syncing history upto %v priority %v)", self.key.Log(), priority, state, histPrior))
state.Synced = false
history = self.syncHistory(state)
// only one history at a time, only allow another one once the
@@ -542,19 +541,19 @@ LOOP:
continue LOOP
}
- glog.V(logger.Detail).Infof("syncer[%v]: (priority %v) added to unsynced keys: %v", self.key.Log(), priority, req)
+ log.Trace(fmt.Sprintf("syncer[%v]: (priority %v) added to unsynced keys: %v", self.key.Log(), priority, req))
keyCounts[priority]++
keyCount++
if keys == history {
- glog.V(logger.Detail).Infof("syncer[%v]: (priority %v) history item %v (synced = %v)", self.key.Log(), priority, req, state.Synced)
+ log.Trace(fmt.Sprintf("syncer[%v]: (priority %v) history item %v (synced = %v)", self.key.Log(), priority, req, state.Synced))
historyCnt++
}
if sreq, err := self.newSyncRequest(req, priority); err == nil {
// extract key from req
- glog.V(logger.Detail).Infof("syncer[%v]: (priority %v): request %v (synced = %v)", self.key.Log(), priority, req, state.Synced)
+ log.Trace(fmt.Sprintf("syncer[%v]: (priority %v): request %v (synced = %v)", self.key.Log(), priority, req, state.Synced))
unsynced = append(unsynced, sreq)
} else {
- glog.V(logger.Warn).Infof("syncer[%v]: (priority %v): error creating request for %v: %v)", self.key.Log(), priority, req, state.Synced, err)
+ log.Warn(fmt.Sprintf("syncer[%v]: (priority %v): error creating request for %v: %v)", self.key.Log(), priority, req, err))
}
}
@@ -601,18 +600,18 @@ func (self *syncer) syncDeliveries() {
total++
msg, err = self.newStoreRequestMsgData(req)
if err != nil {
- glog.V(logger.Warn).Infof("syncer[%v]: failed to create store request for %v: %v", self.key.Log(), req, err)
+ log.Warn(fmt.Sprintf("syncer[%v]: failed to create store request for %v: %v", self.key.Log(), req, err))
} else {
err = self.store(msg)
if err != nil {
- glog.V(logger.Warn).Infof("syncer[%v]: failed to deliver %v: %v", self.key.Log(), req, err)
+ log.Warn(fmt.Sprintf("syncer[%v]: failed to deliver %v: %v", self.key.Log(), req, err))
} else {
success++
- glog.V(logger.Detail).Infof("syncer[%v]: %v successfully delivered", self.key.Log(), req)
+ log.Trace(fmt.Sprintf("syncer[%v]: %v successfully delivered", self.key.Log(), req))
}
}
if total%self.SyncBatchSize == 0 {
- glog.V(logger.Debug).Infof("syncer[%v]: deliver Total: %v, Success: %v, High: %v/%v, Medium: %v/%v, Low %v/%v", self.key.Log(), total, success, c[High], n[High], c[Medium], n[Medium], c[Low], n[Low])
+ log.Debug(fmt.Sprintf("syncer[%v]: deliver Total: %v, Success: %v, High: %v/%v, Medium: %v/%v, Low %v/%v", self.key.Log(), total, success, c[High], n[High], c[Medium], n[Medium], c[Low], n[Low]))
}
}
}
@@ -679,7 +678,7 @@ func (self *syncer) addDelivery(req interface{}, priority uint, quit chan bool)
func (self *syncer) doDelivery(req interface{}, priority uint, quit chan bool) bool {
msgdata, err := self.newStoreRequestMsgData(req)
if err != nil {
- glog.V(logger.Warn).Infof("unable to deliver request %v: %v", msgdata, err)
+ log.Warn(fmt.Sprintf("unable to deliver request %v: %v", msgdata, err))
return false
}
select {
diff --git a/swarm/services/swap/swap.go b/swarm/services/swap/swap.go
index f72036d720..093892e8d9 100644
--- a/swarm/services/swap/swap.go
+++ b/swarm/services/swap/swap.go
@@ -17,6 +17,7 @@
package swap
import (
+ "context"
"crypto/ecdsa"
"fmt"
"math/big"
@@ -31,10 +32,8 @@ import (
"github.com/ethereum/go-ethereum/contracts/chequebook/contract"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/swarm/services/swap/swap"
- "golang.org/x/net/context"
)
// SwAP Swarm Accounting Protocol with
@@ -132,19 +131,19 @@ func NewSwap(local *SwapParams, remote *SwapProfile, backend chequebook.Backend,
// TODO: monitoring a chequebooks events
ok, err = chequebook.ValidateCode(ctx, backend, remote.Contract)
if !ok {
- glog.V(logger.Info).Infof("invalid contract %v for peer %v: %v)", remote.Contract.Hex()[:8], proto, err)
+ log.Info(fmt.Sprintf("invalid contract %v for peer %v: %v)", remote.Contract.Hex()[:8], proto, err))
} else {
// remote contract valid, create inbox
in, err = chequebook.NewInbox(local.privateKey, remote.Contract, local.Beneficiary, crypto.ToECDSAPub(common.FromHex(remote.PublicKey)), backend)
if err != nil {
- glog.V(logger.Warn).Infof("unable to set up inbox for chequebook contract %v for peer %v: %v)", remote.Contract.Hex()[:8], proto, err)
+ log.Warn(fmt.Sprintf("unable to set up inbox for chequebook contract %v for peer %v: %v)", remote.Contract.Hex()[:8], proto, err))
}
}
// check if local chequebook contract is valid
ok, err = chequebook.ValidateCode(ctx, backend, local.Contract)
if !ok {
- glog.V(logger.Warn).Infof("unable to set up outbox for peer %v: chequebook contract (owner: %v): %v)", proto, local.owner.Hex(), err)
+ log.Warn(fmt.Sprintf("unable to set up outbox for peer %v: chequebook contract (owner: %v): %v)", proto, local.owner.Hex(), err))
} else {
out = chequebook.NewOutbox(local.Chequebook(), remote.Beneficiary)
}
@@ -172,7 +171,7 @@ func NewSwap(local *SwapParams, remote *SwapProfile, backend chequebook.Backend,
} else {
sell = "selling to peer disabled"
}
- glog.V(logger.Warn).Infof("SWAP arrangement with <%v>: %v; %v)", proto, buy, sell)
+ log.Warn(fmt.Sprintf("SWAP arrangement with <%v>: %v; %v)", proto, buy, sell))
return
}
@@ -217,13 +216,13 @@ func (self *SwapParams) deployChequebook(ctx context.Context, backend chequebook
opts.Value = self.AutoDepositBuffer
opts.Context = ctx
- glog.V(logger.Info).Infof("Deploying new chequebook (owner: %v)", opts.From.Hex())
+ log.Info(fmt.Sprintf("Deploying new chequebook (owner: %v)", opts.From.Hex()))
contract, err := deployChequebookLoop(opts, backend)
if err != nil {
- glog.V(logger.Error).Infof("unable to deploy new chequebook: %v", err)
+ log.Error(fmt.Sprintf("unable to deploy new chequebook: %v", err))
return err
}
- glog.V(logger.Info).Infof("new chequebook deployed at %v (owner: %v)", contract.Hex(), opts.From.Hex())
+ log.Info(fmt.Sprintf("new chequebook deployed at %v (owner: %v)", contract.Hex(), opts.From.Hex()))
// need to save config at this point
self.lock.Lock()
@@ -231,7 +230,7 @@ func (self *SwapParams) deployChequebook(ctx context.Context, backend chequebook
err = self.newChequebookFromContract(path, backend)
self.lock.Unlock()
if err != nil {
- glog.V(logger.Warn).Infof("error initialising cheque book (owner: %v): %v", opts.From.Hex(), err)
+ log.Warn(fmt.Sprintf("error initialising cheque book (owner: %v): %v", opts.From.Hex(), err))
}
return err
}
@@ -244,11 +243,11 @@ func deployChequebookLoop(opts *bind.TransactOpts, backend chequebook.Backend) (
time.Sleep(chequebookDeployDelay)
}
if _, tx, _, err = contract.DeployChequebook(opts, backend); err != nil {
- glog.V(logger.Warn).Infof("can't send chequebook deploy tx (try %d): %v", try, err)
+ log.Warn(fmt.Sprintf("can't send chequebook deploy tx (try %d): %v", try, err))
continue
}
if addr, err = bind.WaitDeployed(opts.Context, backend, tx); err != nil {
- glog.V(logger.Warn).Infof("chequebook deploy error (try %d): %v", try, err)
+ log.Warn(fmt.Sprintf("chequebook deploy error (try %d): %v", try, err))
continue
}
return addr, nil
@@ -271,13 +270,13 @@ func (self *SwapParams) newChequebookFromContract(path string, backend chequeboo
if err != nil {
self.chbook, err = chequebook.NewChequebook(chbookpath, self.Contract, self.privateKey, backend)
if err != nil {
- glog.V(logger.Warn).Infof("unable to initialise chequebook (owner: %v): %v", self.owner.Hex(), err)
+ log.Warn(fmt.Sprintf("unable to initialise chequebook (owner: %v): %v", self.owner.Hex(), err))
return fmt.Errorf("unable to initialise chequebook (owner: %v): %v", self.owner.Hex(), err)
}
}
self.chbook.AutoDeposit(self.AutoDepositInterval, self.AutoDepositThreshold, self.AutoDepositBuffer)
- glog.V(logger.Info).Infof("auto deposit ON for %v -> %v: interval = %v, threshold = %v, buffer = %v)", crypto.PubkeyToAddress(*(self.publicKey)).Hex()[:8], self.Contract.Hex()[:8], self.AutoDepositInterval, self.AutoDepositThreshold, self.AutoDepositBuffer)
+ log.Info(fmt.Sprintf("auto deposit ON for %v -> %v: interval = %v, threshold = %v, buffer = %v)", crypto.PubkeyToAddress(*(self.publicKey)).Hex()[:8], self.Contract.Hex()[:8], self.AutoDepositInterval, self.AutoDepositThreshold, self.AutoDepositBuffer))
return nil
}
diff --git a/swarm/services/swap/swap/swap.go b/swarm/services/swap/swap/swap.go
index 9d5da7c3a7..a78f1f0e2a 100644
--- a/swarm/services/swap/swap/swap.go
+++ b/swarm/services/swap/swap/swap.go
@@ -22,9 +22,7 @@ import (
"sync"
"time"
- "github.com/ethereum/go-ethereum/common"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/log"
)
// SwAP Swarm Accounting Protocol with
@@ -121,16 +119,16 @@ func (self *Swap) SetRemote(remote *Profile) {
self.lock.Lock()
self.remote = remote
- if self.Sells && (remote.BuyAt.Cmp(common.Big0) <= 0 || self.local.SellAt.Cmp(common.Big0) <= 0 || remote.BuyAt.Cmp(self.local.SellAt) < 0) {
+ if self.Sells && (remote.BuyAt.Sign() <= 0 || self.local.SellAt.Sign() <= 0 || remote.BuyAt.Cmp(self.local.SellAt) < 0) {
self.Out.Stop()
self.Sells = false
}
- if self.Buys && (remote.SellAt.Cmp(common.Big0) <= 0 || self.local.BuyAt.Cmp(common.Big0) <= 0 || self.local.BuyAt.Cmp(self.remote.SellAt) < 0) {
+ if self.Buys && (remote.SellAt.Sign() <= 0 || self.local.BuyAt.Sign() <= 0 || self.local.BuyAt.Cmp(self.remote.SellAt) < 0) {
self.In.Stop()
self.Buys = false
}
- glog.V(logger.Debug).Infof("<%v> remote profile set: pay at: %v, drop at: %v, buy at: %v, sell at: %v", self.proto, remote.PayAt, remote.DropAt, remote.BuyAt, remote.SellAt)
+ log.Debug(fmt.Sprintf("<%v> remote profile set: pay at: %v, drop at: %v, buy at: %v, sell at: %v", self.proto, remote.PayAt, remote.DropAt, remote.BuyAt, remote.SellAt))
}
@@ -148,15 +146,15 @@ func (self *Swap) setParams(local *Params) {
if self.Sells {
self.In.AutoCash(local.AutoCashInterval, local.AutoCashThreshold)
- glog.V(logger.Info).Infof("<%v> set autocash to every %v, max uncashed limit: %v", self.proto, local.AutoCashInterval, local.AutoCashThreshold)
+ log.Info(fmt.Sprintf("<%v> set autocash to every %v, max uncashed limit: %v", self.proto, local.AutoCashInterval, local.AutoCashThreshold))
} else {
- glog.V(logger.Info).Infof("<%v> autocash off (not selling)", self.proto)
+ log.Info(fmt.Sprintf("<%v> autocash off (not selling)", self.proto))
}
if self.Buys {
self.Out.AutoDeposit(local.AutoDepositInterval, local.AutoDepositThreshold, local.AutoDepositBuffer)
- glog.V(logger.Info).Infof("<%v> set autodeposit to every %v, pay at: %v, buffer: %v", self.proto, local.AutoDepositInterval, local.AutoDepositThreshold, local.AutoDepositBuffer)
+ log.Info(fmt.Sprintf("<%v> set autodeposit to every %v, pay at: %v, buffer: %v", self.proto, local.AutoDepositInterval, local.AutoDepositThreshold, local.AutoDepositBuffer))
} else {
- glog.V(logger.Info).Infof("<%v> autodeposit off (not buying)", self.proto)
+ log.Info(fmt.Sprintf("<%v> autodeposit off (not buying)", self.proto))
}
}
@@ -168,16 +166,16 @@ func (self *Swap) Add(n int) error {
self.lock.Lock()
self.balance += n
if !self.Sells && self.balance > 0 {
- glog.V(logger.Detail).Infof("<%v> remote peer cannot have debt (balance: %v)", self.proto, self.balance)
+ log.Trace(fmt.Sprintf("<%v> remote peer cannot have debt (balance: %v)", self.proto, self.balance))
self.proto.Drop()
return fmt.Errorf("[SWAP] <%v> remote peer cannot have debt (balance: %v)", self.proto, self.balance)
}
if !self.Buys && self.balance < 0 {
- glog.V(logger.Detail).Infof("<%v> we cannot have debt (balance: %v)", self.proto, self.balance)
+ log.Trace(fmt.Sprintf("<%v> we cannot have debt (balance: %v)", self.proto, self.balance))
return fmt.Errorf("[SWAP] <%v> we cannot have debt (balance: %v)", self.proto, self.balance)
}
if self.balance >= int(self.local.DropAt) {
- glog.V(logger.Detail).Infof("<%v> remote peer has too much debt (balance: %v, disconnect threshold: %v)", self.proto, self.balance, self.local.DropAt)
+ log.Trace(fmt.Sprintf("<%v> remote peer has too much debt (balance: %v, disconnect threshold: %v)", self.proto, self.balance, self.local.DropAt))
self.proto.Drop()
return fmt.Errorf("[SWAP] <%v> remote peer has too much debt (balance: %v, disconnect threshold: %v)", self.proto, self.balance, self.local.DropAt)
} else if self.balance <= -int(self.remote.PayAt) {
@@ -201,9 +199,9 @@ func (self *Swap) send() {
amount.Mul(amount, self.remote.SellAt)
promise, err := self.Out.Issue(amount)
if err != nil {
- glog.V(logger.Warn).Infof("<%v> cannot issue cheque (amount: %v, channel: %v): %v", self.proto, amount, self.Out, err)
+ log.Warn(fmt.Sprintf("<%v> cannot issue cheque (amount: %v, channel: %v): %v", self.proto, amount, self.Out, err))
} else {
- glog.V(logger.Warn).Infof("<%v> cheque issued (amount: %v, channel: %v)", self.proto, amount, self.Out)
+ log.Warn(fmt.Sprintf("<%v> cheque issued (amount: %v, channel: %v)", self.proto, amount, self.Out))
self.proto.Pay(-self.balance, promise)
self.balance = 0
}
@@ -229,13 +227,13 @@ func (self *Swap) Receive(units int, promise Promise) error {
return fmt.Errorf("invalid amount: %v = %v * %v (units sent in msg * agreed sale unit price) != %v (signed in cheque)", price, units, self.local.SellAt, amount)
}
if err != nil {
- glog.V(logger.Detail).Infof("<%v> invalid promise (amount: %v, channel: %v): %v", self.proto, amount, self.In, err)
+ log.Trace(fmt.Sprintf("<%v> invalid promise (amount: %v, channel: %v): %v", self.proto, amount, self.In, err))
return err
}
// credit remote peer with units
self.Add(-units)
- glog.V(logger.Detail).Infof("<%v> received promise (amount: %v, channel: %v): %v", self.proto, amount, self.In, promise)
+ log.Trace(fmt.Sprintf("<%v> received promise (amount: %v, channel: %v): %v", self.proto, amount, self.In, promise))
return nil
}
diff --git a/swarm/storage/common_test.go b/swarm/storage/common_test.go
index 2a83f471d3..44d1dd1f72 100644
--- a/swarm/storage/common_test.go
+++ b/swarm/storage/common_test.go
@@ -24,8 +24,7 @@ import (
"sync"
"testing"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/log"
)
type brokenLimitedReader struct {
@@ -92,14 +91,14 @@ func testStore(m ChunkStore, l int64, branches int64, t *testing.T) {
go func(chunk *Chunk) {
storedChunk, err := m.Get(chunk.Key)
if err == notFound {
- glog.V(logger.Detail).Infof("chunk '%v' not found", chunk.Key.Log())
+ log.Trace(fmt.Sprintf("chunk '%v' not found", chunk.Key.Log()))
} else if err != nil {
- glog.V(logger.Detail).Infof("error retrieving chunk %v: %v", chunk.Key.Log(), err)
+ log.Trace(fmt.Sprintf("error retrieving chunk %v: %v", chunk.Key.Log(), err))
} else {
chunk.SData = storedChunk.SData
chunk.Size = storedChunk.Size
}
- glog.V(logger.Detail).Infof("chunk '%v' not found", chunk.Key.Log())
+ log.Trace(fmt.Sprintf("chunk '%v' not found", chunk.Key.Log()))
close(chunk.C)
}(ch)
}
diff --git a/swarm/storage/dbstore.go b/swarm/storage/dbstore.go
index e320cd3279..30925a919f 100644
--- a/swarm/storage/dbstore.go
+++ b/swarm/storage/dbstore.go
@@ -28,8 +28,7 @@ import (
"fmt"
"sync"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rlp"
"github.com/syndtr/goleveldb/leveldb"
"github.com/syndtr/goleveldb/leveldb/iterator"
@@ -279,7 +278,7 @@ func (s *DbStore) Cleanup() {
data, err := s.db.Get(getDataKey(index.Idx))
if err != nil {
- glog.V(logger.Warn).Infof("Chunk %x found but could not be accessed: %v", key[:], err)
+ log.Warn(fmt.Sprintf("Chunk %x found but could not be accessed: %v", key[:], err))
s.delete(index.Idx, getIndexKey(key[1:]))
errorsFound++
} else {
@@ -287,7 +286,7 @@ func (s *DbStore) Cleanup() {
hasher.Write(data)
hash := hasher.Sum(nil)
if !bytes.Equal(hash, key[1:]) {
- glog.V(logger.Warn).Infof("Found invalid chunk. Hash mismatch. hash=%x, key=%x", hash, key[:])
+ log.Warn(fmt.Sprintf("Found invalid chunk. Hash mismatch. hash=%x, key=%x", hash, key[:]))
s.delete(index.Idx, getIndexKey(key[1:]))
errorsFound++
}
@@ -295,7 +294,7 @@ func (s *DbStore) Cleanup() {
it.Next()
}
it.Release()
- glog.V(logger.Warn).Infof("Found %v errors out of %v entries", errorsFound, total)
+ log.Warn(fmt.Sprintf("Found %v errors out of %v entries", errorsFound, total))
}
func (s *DbStore) delete(idx uint64, idxKey []byte) {
@@ -324,7 +323,7 @@ func (s *DbStore) Put(chunk *Chunk) {
if chunk.dbStored != nil {
close(chunk.dbStored)
}
- glog.V(logger.Detail).Infof("Storing to DB: chunk already exists, only update access")
+ log.Trace(fmt.Sprintf("Storing to DB: chunk already exists, only update access"))
return // already exists, only update access
}
@@ -356,7 +355,7 @@ func (s *DbStore) Put(chunk *Chunk) {
if chunk.dbStored != nil {
close(chunk.dbStored)
}
- glog.V(logger.Detail).Infof("DbStore.Put: %v. db storage counter: %v ", chunk.Key.Log(), s.dataIdx)
+ log.Trace(fmt.Sprintf("DbStore.Put: %v. db storage counter: %v ", chunk.Key.Log(), s.dataIdx))
}
// try to find index; if found, update access cnt and return true
@@ -390,7 +389,7 @@ func (s *DbStore) Get(key Key) (chunk *Chunk, err error) {
var data []byte
data, err = s.db.Get(getDataKey(index.Idx))
if err != nil {
- glog.V(logger.Detail).Infof("DBStore: Chunk %v found but could not be accessed: %v", key.Log(), err)
+ log.Trace(fmt.Sprintf("DBStore: Chunk %v found but could not be accessed: %v", key.Log(), err))
s.delete(index.Idx, getIndexKey(key))
return
}
diff --git a/swarm/storage/dpa.go b/swarm/storage/dpa.go
index 7b3e23cac2..e16e4aacb4 100644
--- a/swarm/storage/dpa.go
+++ b/swarm/storage/dpa.go
@@ -18,12 +18,12 @@ package storage
import (
"errors"
+ "fmt"
"io"
"sync"
"time"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/log"
)
/*
@@ -131,17 +131,17 @@ func (self *DPA) retrieveLoop() {
for i := 0; i < maxRetrieveProcesses; i++ {
go self.retrieveWorker()
}
- glog.V(logger.Detail).Infof("dpa: retrieve loop spawning %v workers", maxRetrieveProcesses)
+ log.Trace(fmt.Sprintf("dpa: retrieve loop spawning %v workers", maxRetrieveProcesses))
}
func (self *DPA) retrieveWorker() {
for chunk := range self.retrieveC {
- glog.V(logger.Detail).Infof("dpa: retrieve loop : chunk %v", chunk.Key.Log())
+ log.Trace(fmt.Sprintf("dpa: retrieve loop : chunk %v", chunk.Key.Log()))
storedChunk, err := self.Get(chunk.Key)
if err == notFound {
- glog.V(logger.Detail).Infof("chunk %v not found", chunk.Key.Log())
+ log.Trace(fmt.Sprintf("chunk %v not found", chunk.Key.Log()))
} else if err != nil {
- glog.V(logger.Detail).Infof("error retrieving chunk %v: %v", chunk.Key.Log(), err)
+ log.Trace(fmt.Sprintf("error retrieving chunk %v: %v", chunk.Key.Log(), err))
} else {
chunk.SData = storedChunk.SData
chunk.Size = storedChunk.Size
@@ -162,7 +162,7 @@ func (self *DPA) storeLoop() {
for i := 0; i < maxStoreProcesses; i++ {
go self.storeWorker()
}
- glog.V(logger.Detail).Infof("dpa: store spawning %v workers", maxStoreProcesses)
+ log.Trace(fmt.Sprintf("dpa: store spawning %v workers", maxStoreProcesses))
}
func (self *DPA) storeWorker() {
@@ -170,7 +170,7 @@ func (self *DPA) storeWorker() {
for chunk := range self.storeC {
self.Put(chunk)
if chunk.wg != nil {
- glog.V(logger.Detail).Infof("dpa: store processor %v", chunk.Key.Log())
+ log.Trace(fmt.Sprintf("dpa: store processor %v", chunk.Key.Log()))
chunk.wg.Done()
}
@@ -203,17 +203,17 @@ func (self *dpaChunkStore) Get(key Key) (chunk *Chunk, err error) {
chunk, err = self.netStore.Get(key)
// timeout := time.Now().Add(searchTimeout)
if chunk.SData != nil {
- glog.V(logger.Detail).Infof("DPA.Get: %v found locally, %d bytes", key.Log(), len(chunk.SData))
+ log.Trace(fmt.Sprintf("DPA.Get: %v found locally, %d bytes", key.Log(), len(chunk.SData)))
return
}
// TODO: use self.timer time.Timer and reset with defer disableTimer
timer := time.After(searchTimeout)
select {
case <-timer:
- glog.V(logger.Detail).Infof("DPA.Get: %v request time out ", key.Log())
+ log.Trace(fmt.Sprintf("DPA.Get: %v request time out ", key.Log()))
err = notFound
case <-chunk.Req.C:
- glog.V(logger.Detail).Infof("DPA.Get: %v retrieved, %d bytes (%p)", key.Log(), len(chunk.SData), chunk)
+ log.Trace(fmt.Sprintf("DPA.Get: %v retrieved, %d bytes (%p)", key.Log(), len(chunk.SData), chunk))
}
return
}
@@ -222,18 +222,18 @@ func (self *dpaChunkStore) Get(key Key) (chunk *Chunk, err error) {
func (self *dpaChunkStore) Put(entry *Chunk) {
chunk, err := self.localStore.Get(entry.Key)
if err != nil {
- glog.V(logger.Detail).Infof("DPA.Put: %v new chunk. call netStore.Put", entry.Key.Log())
+ log.Trace(fmt.Sprintf("DPA.Put: %v new chunk. call netStore.Put", entry.Key.Log()))
chunk = entry
} else if chunk.SData == nil {
- glog.V(logger.Detail).Infof("DPA.Put: %v request entry found", entry.Key.Log())
+ log.Trace(fmt.Sprintf("DPA.Put: %v request entry found", entry.Key.Log()))
chunk.SData = entry.SData
chunk.Size = entry.Size
} else {
- glog.V(logger.Detail).Infof("DPA.Put: %v chunk already known", entry.Key.Log())
+ log.Trace(fmt.Sprintf("DPA.Put: %v chunk already known", entry.Key.Log()))
return
}
// from this point on the storage logic is the same with network storage requests
- glog.V(logger.Detail).Infof("DPA.Put %v: %v", self.n, chunk.Key.Log())
+ log.Trace(fmt.Sprintf("DPA.Put %v: %v", self.n, chunk.Key.Log()))
self.n++
self.netStore.Put(chunk)
}
diff --git a/swarm/storage/memstore.go b/swarm/storage/memstore.go
index 7903d33e70..f96792c6ea 100644
--- a/swarm/storage/memstore.go
+++ b/swarm/storage/memstore.go
@@ -19,10 +19,10 @@
package storage
import (
+ "fmt"
"sync"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/log"
)
const (
@@ -287,11 +287,11 @@ func (s *MemStore) removeOldest() {
}
if node.entry.dbStored != nil {
- glog.V(logger.Detail).Infof("Memstore Clean: Waiting for chunk %v to be saved", node.entry.Key.Log())
+ log.Trace(fmt.Sprintf("Memstore Clean: Waiting for chunk %v to be saved", node.entry.Key.Log()))
<-node.entry.dbStored
- glog.V(logger.Detail).Infof("Memstore Clean: Chunk %v saved to DBStore. Ready to clear from mem.", node.entry.Key.Log())
+ log.Trace(fmt.Sprintf("Memstore Clean: Chunk %v saved to DBStore. Ready to clear from mem.", node.entry.Key.Log()))
} else {
- glog.V(logger.Detail).Infof("Memstore Clean: Chunk %v already in DB. Ready to delete.", node.entry.Key.Log())
+ log.Trace(fmt.Sprintf("Memstore Clean: Chunk %v already in DB. Ready to delete.", node.entry.Key.Log()))
}
if node.entry.SData != nil {
diff --git a/swarm/storage/netstore.go b/swarm/storage/netstore.go
index 46479b58a5..7c0436c3fd 100644
--- a/swarm/storage/netstore.go
+++ b/swarm/storage/netstore.go
@@ -17,12 +17,12 @@
package storage
import (
+ "fmt"
"path/filepath"
"sync"
"time"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/log"
)
/*
@@ -98,14 +98,14 @@ func (self *NetStore) Put(entry *Chunk) {
// handle deliveries
if entry.Req != nil {
- glog.V(logger.Detail).Infof("NetStore.Put: localStore.Put %v hit existing request...delivering", entry.Key.Log())
+ log.Trace(fmt.Sprintf("NetStore.Put: localStore.Put %v hit existing request...delivering", entry.Key.Log()))
// closing C signals to other routines (local requests)
// that the chunk is has been retrieved
close(entry.Req.C)
// deliver the chunk to requesters upstream
go self.cloud.Deliver(entry)
} else {
- glog.V(logger.Detail).Infof("NetStore.Put: localStore.Put %v stored locally", entry.Key.Log())
+ log.Trace(fmt.Sprintf("NetStore.Put: localStore.Put %v stored locally", entry.Key.Log()))
// handle propagating store requests
// go self.cloud.Store(entry)
go self.cloud.Store(entry)
@@ -118,15 +118,15 @@ func (self *NetStore) Get(key Key) (*Chunk, error) {
chunk, err := self.localStore.Get(key)
if err == nil {
if chunk.Req == nil {
- glog.V(logger.Detail).Infof("NetStore.Get: %v found locally", key)
+ log.Trace(fmt.Sprintf("NetStore.Get: %v found locally", key))
} else {
- glog.V(logger.Detail).Infof("NetStore.Get: %v hit on an existing request", key)
+ log.Trace(fmt.Sprintf("NetStore.Get: %v hit on an existing request", key))
// no need to launch again
}
return chunk, err
}
// no data and no request status
- glog.V(logger.Detail).Infof("NetStore.Get: %v not found locally. open new request", key)
+ log.Trace(fmt.Sprintf("NetStore.Get: %v not found locally. open new request", key))
chunk = NewChunk(key, newRequestStatus(key))
self.localStore.memStore.Put(chunk)
go self.cloud.Retrieve(chunk)
diff --git a/swarm/swarm.go b/swarm/swarm.go
index eab01f036c..0ce31bcad9 100644
--- a/swarm/swarm.go
+++ b/swarm/swarm.go
@@ -18,6 +18,7 @@ package swarm
import (
"bytes"
+ "context"
"crypto/ecdsa"
"fmt"
@@ -26,8 +27,7 @@ import (
"github.com/ethereum/go-ethereum/contracts/chequebook"
"github.com/ethereum/go-ethereum/contracts/ens"
"github.com/ethereum/go-ethereum/crypto"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/p2p/discover"
@@ -36,7 +36,6 @@ import (
httpapi "github.com/ethereum/go-ethereum/swarm/api/http"
"github.com/ethereum/go-ethereum/swarm/network"
"github.com/ethereum/go-ethereum/swarm/storage"
- "golang.org/x/net/context"
)
// the swarm stack
@@ -54,7 +53,8 @@ type Swarm struct {
privateKey *ecdsa.PrivateKey
corsString string
swapEnabled bool
- lstore *storage.LocalStore // local store, needs to store for releasing resources after node stopped
+ lstore *storage.LocalStore // local store, needs to store for releasing resources after node stopped
+ sfs *api.SwarmFS // need this to cleanup all the active mounts on node exit
}
type SwarmAPI struct {
@@ -88,7 +88,7 @@ func NewSwarm(ctx *node.ServiceContext, backend chequebook.Backend, config *api.
privateKey: config.Swap.PrivateKey(),
corsString: cors,
}
- glog.V(logger.Debug).Infof("Setting up Swarm service components")
+ log.Debug(fmt.Sprintf("Setting up Swarm service components"))
hash := storage.MakeHashFunc(config.ChunkerParams.Hash)
self.lstore, err = storage.NewLocalStore(hash, config.StoreParams)
@@ -97,10 +97,10 @@ func NewSwarm(ctx *node.ServiceContext, backend chequebook.Backend, config *api.
}
// setup local store
- glog.V(logger.Debug).Infof("Set up local storage")
+ log.Debug(fmt.Sprintf("Set up local storage"))
self.dbAccess = network.NewDbAccess(self.lstore)
- glog.V(logger.Debug).Infof("Set up local db access (iterator/counter)")
+ log.Debug(fmt.Sprintf("Set up local db access (iterator/counter)"))
// set up the kademlia hive
self.hive = network.NewHive(
@@ -109,26 +109,26 @@ func NewSwarm(ctx *node.ServiceContext, backend chequebook.Backend, config *api.
swapEnabled, // SWAP enabled
syncEnabled, // syncronisation enabled
)
- glog.V(logger.Debug).Infof("Set up swarm network with Kademlia hive")
+ log.Debug(fmt.Sprintf("Set up swarm network with Kademlia hive"))
// setup cloud storage backend
cloud := network.NewForwarder(self.hive)
- glog.V(logger.Debug).Infof("-> set swarm forwarder as cloud storage backend")
+ log.Debug(fmt.Sprintf("-> set swarm forwarder as cloud storage backend"))
// setup cloud storage internal access layer
self.storage = storage.NewNetStore(hash, self.lstore, cloud, config.StoreParams)
- glog.V(logger.Debug).Infof("-> swarm net store shared access layer to Swarm Chunk Store")
+ log.Debug(fmt.Sprintf("-> swarm net store shared access layer to Swarm Chunk Store"))
// set up Depo (storage handler = cloud storage access layer for incoming remote requests)
self.depo = network.NewDepo(hash, self.lstore, self.storage)
- glog.V(logger.Debug).Infof("-> REmote Access to CHunks")
+ log.Debug(fmt.Sprintf("-> REmote Access to CHunks"))
// set up DPA, the cloud storage local access layer
dpaChunkStore := storage.NewDpaChunkStore(self.lstore, self.storage)
- glog.V(logger.Debug).Infof("-> Local Access to Swarm")
+ log.Debug(fmt.Sprintf("-> Local Access to Swarm"))
// Swarm Hash Merklised Chunking for Arbitrary-length Document/File storage
self.dpa = storage.NewDPA(dpaChunkStore, self.config.ChunkerParams)
- glog.V(logger.Debug).Infof("-> Content Store API")
+ log.Debug(fmt.Sprintf("-> Content Store API"))
// set up high level api
transactOpts := bind.NewKeyedTransactor(self.privateKey)
@@ -137,11 +137,14 @@ func NewSwarm(ctx *node.ServiceContext, backend chequebook.Backend, config *api.
if err != nil {
return nil, err
}
- glog.V(logger.Debug).Infof("-> Swarm Domain Name Registrar @ address %v", config.EnsRoot.Hex())
+ log.Debug(fmt.Sprintf("-> Swarm Domain Name Registrar @ address %v", config.EnsRoot.Hex()))
self.api = api.NewApi(self.dpa, self.dns)
// Manifests for Smart Hosting
- glog.V(logger.Debug).Infof("-> Web3 virtual server API")
+ log.Debug(fmt.Sprintf("-> Web3 virtual server API"))
+
+ self.sfs = api.NewSwarmFS(self.api)
+ log.Debug("-> Initializing Fuse file system")
return self, nil
}
@@ -173,21 +176,21 @@ func (self *Swarm) Start(net *p2p.Server) error {
if err != nil {
return fmt.Errorf("Unable to set chequebook for SWAP: %v", err)
}
- glog.V(logger.Debug).Infof("-> cheque book for SWAP: %v", self.config.Swap.Chequebook())
+ log.Debug(fmt.Sprintf("-> cheque book for SWAP: %v", self.config.Swap.Chequebook()))
} else {
- glog.V(logger.Debug).Infof("SWAP disabled: no cheque book set")
+ log.Debug(fmt.Sprintf("SWAP disabled: no cheque book set"))
}
- glog.V(logger.Warn).Infof("Starting Swarm service")
+ log.Warn(fmt.Sprintf("Starting Swarm service"))
self.hive.Start(
discover.PubkeyID(&net.PrivateKey.PublicKey),
func() string { return net.ListenAddr },
connectPeer,
)
- glog.V(logger.Info).Infof("Swarm network started on bzz address: %v", self.hive.Addr())
+ log.Info(fmt.Sprintf("Swarm network started on bzz address: %v", self.hive.Addr()))
self.dpa.Start()
- glog.V(logger.Debug).Infof("Swarm DPA started")
+ log.Debug(fmt.Sprintf("Swarm DPA started"))
// start swarm http proxy server
if self.config.Port != "" {
@@ -195,10 +198,10 @@ func (self *Swarm) Start(net *p2p.Server) error {
go httpapi.StartHttpServer(self.api, &httpapi.Server{Addr: addr, CorsString: self.corsString})
}
- glog.V(logger.Debug).Infof("Swarm http proxy started on port: %v", self.config.Port)
+ log.Debug(fmt.Sprintf("Swarm http proxy started on port: %v", self.config.Port))
if self.corsString != "" {
- glog.V(logger.Debug).Infof("Swarm http proxy started with corsdomain:", self.corsString)
+ log.Debug(fmt.Sprintf("Swarm http proxy started with corsdomain: %v", self.corsString))
}
return nil
@@ -217,7 +220,7 @@ func (self *Swarm) Stop() error {
if self.lstore != nil {
self.lstore.DbStore.Close()
}
-
+ self.sfs.Stop()
return self.config.Save()
}
@@ -241,6 +244,7 @@ func (self *Swarm) APIs() []rpc.API {
Service: api.NewStorage(self.api),
Public: true,
},
+
{
Namespace: "bzz",
Version: "0.1",
@@ -265,6 +269,12 @@ func (self *Swarm) APIs() []rpc.API {
Service: chequebook.NewApi(self.config.Swap.Chequebook),
Public: false,
},
+ {
+ Namespace: "swarmfs",
+ Version: api.Swarmfs_Version,
+ Service: self.sfs,
+ Public: false,
+ },
// {Namespace, Version, api.NewAdmin(self), false},
}
}
@@ -279,7 +289,7 @@ func (self *Swarm) SetChequebook(ctx context.Context) error {
if err != nil {
return err
}
- glog.V(logger.Info).Infof("new chequebook set (%v): saving config file, resetting all connections in the hive", self.config.Swap.Contract.Hex())
+ log.Info(fmt.Sprintf("new chequebook set (%v): saving config file, resetting all connections in the hive", self.config.Swap.Contract.Hex()))
self.config.Save()
self.hive.DropAll()
return nil
diff --git a/tests/block_test_util.go b/tests/block_test_util.go
index 470eb7cb7f..456a4ccb86 100644
--- a/tests/block_test_util.go
+++ b/tests/block_test_util.go
@@ -26,17 +26,16 @@ import (
"strconv"
"strings"
- "github.com/ethereum/ethash"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
- "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
- "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params"
+ "github.com/ethereum/go-ethereum/pow"
"github.com/ethereum/go-ethereum/rlp"
)
@@ -146,15 +145,15 @@ func runBlockTests(homesteadBlock, daoForkBlock, gasPriceFork *big.Int, bt map[s
}
for name, test := range bt {
- if skipTest[name] {
- glog.Infoln("Skipping block test", name)
+ if skipTest[name] /*|| name != "CallingCanonicalContractFromFork_CALLCODE"*/ {
+ log.Info(fmt.Sprint("Skipping block test", name))
continue
}
// test the block
if err := runBlockTest(homesteadBlock, daoForkBlock, gasPriceFork, test); err != nil {
return fmt.Errorf("%s: %v", name, err)
}
- glog.Infoln("Block test passed: ", name)
+ log.Info(fmt.Sprint("Block test passed: ", name))
}
return nil
@@ -173,10 +172,11 @@ func runBlockTest(homesteadBlock, daoForkBlock, gasPriceFork *big.Int, test *Blo
core.WriteHeadBlockHash(db, test.Genesis.Hash())
evmux := new(event.TypeMux)
config := ¶ms.ChainConfig{HomesteadBlock: homesteadBlock, DAOForkBlock: daoForkBlock, DAOForkSupport: true, EIP150Block: gasPriceFork}
- chain, err := core.NewBlockChain(db, config, ethash.NewShared(), evmux, vm.Config{})
+ chain, err := core.NewBlockChain(db, config, pow.NewSharedEthash(), evmux, vm.Config{})
if err != nil {
return err
}
+ defer chain.Stop()
//vm.Debug = true
validBlocks, err := test.TryBlocksInsert(chain)
@@ -221,10 +221,12 @@ func (t *BlockTest) InsertPreState(db ethdb.Database) (*state.StateDB, error) {
if err != nil {
return nil, err
}
- obj := statedb.CreateAccount(common.HexToAddress(addrString))
- obj.SetCode(crypto.Keccak256Hash(code), code)
- obj.SetBalance(balance)
- obj.SetNonce(nonce)
+
+ addr := common.HexToAddress(addrString)
+ statedb.CreateAccount(addr)
+ statedb.SetCode(addr, code)
+ statedb.SetBalance(addr, balance)
+ statedb.SetNonce(addr, nonce)
for k, v := range acct.Storage {
statedb.SetState(common.HexToAddress(addrString), common.HexToHash(k), common.HexToHash(v))
}
diff --git a/tests/state_test_util.go b/tests/state_test_util.go
index 5469a4c71b..81f49efa5b 100644
--- a/tests/state_test_util.go
+++ b/tests/state_test_util.go
@@ -26,11 +26,12 @@ import (
"testing"
"github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethdb"
- "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params"
)
@@ -108,8 +109,8 @@ func runStateTests(chainConfig *params.ChainConfig, tests map[string]VmTest, ski
}
for name, test := range tests {
- if skipTest[name] {
- glog.Infoln("Skipping state test", name)
+ if skipTest[name] /*|| name != "JUMPDEST_Attack"*/ {
+ log.Info(fmt.Sprint("Skipping state test", name))
continue
}
@@ -118,7 +119,7 @@ func runStateTests(chainConfig *params.ChainConfig, tests map[string]VmTest, ski
return fmt.Errorf("%s: %s\n", name, err.Error())
}
- //glog.Infoln("State test passed: ", name)
+ //log.Info(fmt.Sprint("State test passed: ", name))
//fmt.Println(string(statedb.Dump()))
}
return nil
@@ -165,25 +166,25 @@ func runStateTest(chainConfig *params.ChainConfig, test VmTest) error {
// check post state
for addr, account := range test.Post {
- obj := statedb.GetStateObject(common.HexToAddress(addr))
- if obj == nil {
+ address := common.HexToAddress(addr)
+ if !statedb.Exist(address) {
return fmt.Errorf("did not find expected post-state account: %s", addr)
}
- if obj.Balance().Cmp(common.Big(account.Balance)) != 0 {
- return fmt.Errorf("(%x) balance failed. Expected: %v have: %v\n", obj.Address().Bytes()[:4], common.String2Big(account.Balance), obj.Balance())
+ if balance := statedb.GetBalance(address); balance.Cmp(math.MustParseBig256(account.Balance)) != 0 {
+ return fmt.Errorf("(%x) balance failed. Expected: %v have: %v\n", address[:4], math.MustParseBig256(account.Balance), balance)
}
- if obj.Nonce() != common.String2Big(account.Nonce).Uint64() {
- return fmt.Errorf("(%x) nonce failed. Expected: %v have: %v\n", obj.Address().Bytes()[:4], account.Nonce, obj.Nonce())
+ if nonce := statedb.GetNonce(address); nonce != math.MustParseUint64(account.Nonce) {
+ return fmt.Errorf("(%x) nonce failed. Expected: %v have: %v\n", address[:4], account.Nonce, nonce)
}
for addr, value := range account.Storage {
- v := statedb.GetState(obj.Address(), common.HexToHash(addr))
+ v := statedb.GetState(address, common.HexToHash(addr))
vexp := common.HexToHash(value)
if v != vexp {
- return fmt.Errorf("storage failed:\n%x: %s:\nexpected: %x\nhave: %x\n(%v %v)\n", obj.Address().Bytes(), addr, vexp, v, vexp.Big(), v.Big())
+ return fmt.Errorf("storage failed:\n%x: %s:\nexpected: %x\nhave: %x\n(%v %v)\n", address[:4], addr, vexp, v, vexp.Big(), v.Big())
}
}
}
@@ -205,7 +206,7 @@ func runStateTest(chainConfig *params.ChainConfig, test VmTest) error {
func RunState(chainConfig *params.ChainConfig, statedb *state.StateDB, env, tx map[string]string) ([]byte, []*types.Log, *big.Int, error) {
environment, msg := NewEVMEnvironment(false, chainConfig, statedb, env, tx)
- gaspool := new(core.GasPool).AddGas(common.Big(env["currentGasLimit"]))
+ gaspool := new(core.GasPool).AddGas(math.MustParseBig256(env["currentGasLimit"]))
root, _ := statedb.Commit(false)
statedb.Reset(root)
diff --git a/tests/transaction_test_util.go b/tests/transaction_test_util.go
index 678513e11a..1ecc73a67c 100644
--- a/tests/transaction_test_util.go
+++ b/tests/transaction_test_util.go
@@ -24,8 +24,9 @@ import (
"runtime"
"github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/core/types"
- "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp"
)
@@ -64,14 +65,14 @@ func RunTransactionTestsWithReader(config *params.ChainConfig, r io.Reader, skip
for name, test := range bt {
// if the test should be skipped, return
if skipTest[name] {
- glog.Infoln("Skipping transaction test", name)
+ log.Info(fmt.Sprint("Skipping transaction test", name))
return nil
}
// test the block
if err := runTransactionTest(config, test); err != nil {
return err
}
- glog.Infoln("Transaction test passed: ", name)
+ log.Info(fmt.Sprint("Transaction test passed: ", name))
}
return nil
@@ -98,7 +99,7 @@ func runTransactionTests(config *params.ChainConfig, tests map[string]Transactio
for name, test := range tests {
// if the test should be skipped, return
if skipTest[name] {
- glog.Infoln("Skipping transaction test", name)
+ log.Info(fmt.Sprint("Skipping transaction test", name))
return nil
}
@@ -106,7 +107,7 @@ func runTransactionTests(config *params.ChainConfig, tests map[string]Transactio
if err := runTransactionTest(config, test); err != nil {
return fmt.Errorf("%s: %v", name, err)
}
- glog.Infoln("Transaction test passed: ", name)
+ log.Info(fmt.Sprint("Transaction test passed: ", name))
}
return nil
@@ -161,7 +162,7 @@ func verifyTxFields(chainConfig *params.ChainConfig, txTest TransactionTest, dec
var decodedSender common.Address
- signer := types.MakeSigner(chainConfig, common.String2Big(txTest.Blocknumber))
+ signer := types.MakeSigner(chainConfig, math.MustParseBig256(txTest.Blocknumber))
decodedSender, err = types.Sender(signer, decodedTx)
if err != nil {
return err
diff --git a/tests/util.go b/tests/util.go
index 134d5b4f80..7a08e5ed82 100644
--- a/tests/util.go
+++ b/tests/util.go
@@ -24,13 +24,14 @@ import (
"os"
"github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethdb"
- "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params"
)
@@ -40,7 +41,7 @@ var (
)
func init() {
- glog.SetV(0)
+ log.Root().SetHandler(log.LvlFilterHandler(log.LvlCrit, log.StreamHandler(os.Stderr, log.TerminalFormat(false))))
if os.Getenv("JITVM") == "true" {
ForceJit = true
EnableJit = true
@@ -70,7 +71,7 @@ func checkLogs(tlog []Log, logs []*types.Log) error {
}
}
}
- genBloom := common.LeftPadBytes(types.LogsBloom([]*types.Log{logs[i]}).Bytes(), 256)
+ genBloom := math.PaddedBigBytes(types.LogsBloom([]*types.Log{logs[i]}), 256)
if !bytes.Equal(genBloom, common.Hex2Bytes(log.BloomF)) {
return fmt.Errorf("bloom mismatch")
@@ -119,8 +120,8 @@ func insertAccount(state *state.StateDB, saddr string, account Account) {
}
addr := common.HexToAddress(saddr)
state.SetCode(addr, common.Hex2Bytes(account.Code))
- state.SetNonce(addr, common.Big(account.Nonce).Uint64())
- state.SetBalance(addr, common.Big(account.Balance))
+ state.SetNonce(addr, math.MustParseUint64(account.Nonce))
+ state.SetBalance(addr, math.MustParseBig256(account.Balance))
for a, v := range account.Storage {
state.SetState(addr, common.HexToHash(a), common.HexToHash(v))
}
@@ -152,10 +153,10 @@ type VmTest struct {
func NewEVMEnvironment(vmTest bool, chainConfig *params.ChainConfig, statedb *state.StateDB, envValues map[string]string, tx map[string]string) (*vm.EVM, core.Message) {
var (
data = common.FromHex(tx["data"])
- gas = common.Big(tx["gasLimit"])
- price = common.Big(tx["gasPrice"])
- value = common.Big(tx["value"])
- nonce = common.Big(tx["nonce"]).Uint64()
+ gas = math.MustParseBig256(tx["gasLimit"])
+ price = math.MustParseBig256(tx["gasPrice"])
+ value = math.MustParseBig256(tx["value"])
+ nonce = math.MustParseUint64(tx["nonce"])
)
origin := common.HexToAddress(tx["caller"])
@@ -198,10 +199,10 @@ func NewEVMEnvironment(vmTest bool, chainConfig *params.ChainConfig, statedb *st
Origin: origin,
Coinbase: common.HexToAddress(envValues["currentCoinbase"]),
- BlockNumber: common.Big(envValues["currentNumber"]),
- Time: common.Big(envValues["currentTimestamp"]),
- GasLimit: common.Big(envValues["currentGasLimit"]),
- Difficulty: common.Big(envValues["currentDifficulty"]),
+ BlockNumber: math.MustParseBig256(envValues["currentNumber"]),
+ Time: math.MustParseBig256(envValues["currentTimestamp"]),
+ GasLimit: math.MustParseBig256(envValues["currentGasLimit"]),
+ Difficulty: math.MustParseBig256(envValues["currentDifficulty"]),
GasPrice: price,
}
if context.GasPrice == nil {
diff --git a/tests/vm_test_util.go b/tests/vm_test_util.go
index 25e55886f4..d2ddee039e 100644
--- a/tests/vm_test_util.go
+++ b/tests/vm_test_util.go
@@ -25,11 +25,12 @@ import (
"testing"
"github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/ethdb"
- "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params"
)
@@ -129,8 +130,8 @@ func runVmTests(tests map[string]VmTest, skipTests []string) error {
}
for name, test := range tests {
- if skipTest[name] /*|| name != "loop_stacklimit_1021"*/ {
- glog.Infoln("Skipping VM test", name)
+ if skipTest[name] /*|| name != "exp0"*/ {
+ log.Info(fmt.Sprint("Skipping VM test", name))
continue
}
@@ -138,7 +139,7 @@ func runVmTests(tests map[string]VmTest, skipTests []string) error {
return fmt.Errorf("%s %s", name, err.Error())
}
- glog.Infoln("VM test passed: ", name)
+ log.Info(fmt.Sprint("VM test passed: ", name))
//fmt.Println(string(statedb.Dump()))
}
return nil
@@ -180,23 +181,23 @@ func runVmTest(test VmTest) error {
if len(test.Gas) == 0 && err == nil {
return fmt.Errorf("gas unspecified, indicating an error. VM returned (incorrectly) successful")
} else {
- gexp := common.Big(test.Gas)
+ gexp := math.MustParseBig256(test.Gas)
if gexp.Cmp(gas) != 0 {
return fmt.Errorf("gas failed. Expected %v, got %v\n", gexp, gas)
}
}
// check post state
- for addr, account := range test.Post {
- obj := statedb.GetStateObject(common.HexToAddress(addr))
- if obj == nil {
+ for address, account := range test.Post {
+ accountAddr := common.HexToAddress(address)
+ if !statedb.Exist(accountAddr) {
continue
}
for addr, value := range account.Storage {
- v := statedb.GetState(obj.Address(), common.HexToHash(addr))
+ v := statedb.GetState(accountAddr, common.HexToHash(addr))
vexp := common.HexToHash(value)
if v != vexp {
- return fmt.Errorf("(%x: %s) storage failed. Expected %x, got %x (%v %v)\n", obj.Address().Bytes()[0:4], addr, vexp, v, vexp.Big(), v.Big())
+ return fmt.Errorf("(%x: %s) storage failed. Expected %x, got %x (%v %v)\n", addr[:4], addr, vexp, v, vexp.Big(), v.Big())
}
}
}
@@ -222,13 +223,13 @@ func RunVm(statedb *state.StateDB, env, exec map[string]string) ([]byte, []*type
to = common.HexToAddress(exec["address"])
from = common.HexToAddress(exec["caller"])
data = common.FromHex(exec["data"])
- gas = common.Big(exec["gas"])
- value = common.Big(exec["value"])
+ gas = math.MustParseBig256(exec["gas"])
+ value = math.MustParseBig256(exec["value"])
)
caller := statedb.GetOrNewStateObject(from)
vm.PrecompiledContracts = make(map[common.Address]vm.PrecompiledContract)
environment, _ := NewEVMEnvironment(true, chainConfig, statedb, env, exec)
- ret, err := environment.Call(caller, to, data, gas, value)
- return ret, statedb.Logs(), gas, err
+ ret, g, err := environment.Call(caller, to, data, gas.Uint64(), value)
+ return ret, statedb.Logs(), new(big.Int).SetUint64(g), err
}
diff --git a/trie/iterator.go b/trie/iterator.go
index afde6e19e6..234c49ecc8 100644
--- a/trie/iterator.go
+++ b/trie/iterator.go
@@ -16,13 +16,14 @@
package trie
-import "github.com/ethereum/go-ethereum/common"
+import (
+ "bytes"
+ "github.com/ethereum/go-ethereum/common"
+)
// Iterator is a key-value trie iterator that traverses a Trie.
type Iterator struct {
- trie *Trie
- nodeIt *NodeIterator
- keyBuf []byte
+ nodeIt NodeIterator
Key []byte // Current data key on which the iterator is positioned on
Value []byte // Current data value on which the iterator is positioned on
@@ -31,19 +32,23 @@ type Iterator struct {
// NewIterator creates a new key-value iterator.
func NewIterator(trie *Trie) *Iterator {
return &Iterator{
- trie: trie,
nodeIt: NewNodeIterator(trie),
- keyBuf: make([]byte, 0, 64),
- Key: nil,
+ }
+}
+
+// FromNodeIterator creates a new key-value iterator from a node iterator
+func NewIteratorFromNodeIterator(it NodeIterator) *Iterator {
+ return &Iterator{
+ nodeIt: it,
}
}
// Next moves the iterator forward one key-value entry.
func (it *Iterator) Next() bool {
- for it.nodeIt.Next() {
- if it.nodeIt.Leaf {
- it.Key = it.makeKey()
- it.Value = it.nodeIt.LeafBlob
+ for it.nodeIt.Next(true) {
+ if it.nodeIt.Leaf() {
+ it.Key = decodeCompact(it.nodeIt.Path())
+ it.Value = it.nodeIt.LeafBlob()
return true
}
}
@@ -52,74 +57,123 @@ func (it *Iterator) Next() bool {
return false
}
-func (it *Iterator) makeKey() []byte {
- key := it.keyBuf[:0]
- for _, se := range it.nodeIt.stack {
- switch node := se.node.(type) {
- case *fullNode:
- if se.child <= 16 {
- key = append(key, byte(se.child))
- }
- case *shortNode:
- if hasTerm(node.Key) {
- key = append(key, node.Key[:len(node.Key)-1]...)
- } else {
- key = append(key, node.Key...)
- }
- }
- }
- return decodeCompact(key)
+// NodeIterator is an iterator to traverse the trie pre-order.
+type NodeIterator interface {
+ // Hash returns the hash of the current node
+ Hash() common.Hash
+ // Parent returns the hash of the parent of the current node
+ Parent() common.Hash
+ // Leaf returns true iff the current node is a leaf node.
+ Leaf() bool
+ // LeafBlob returns the contents of the node, if it is a leaf.
+ // Callers must not retain references to the return value after calling Next()
+ LeafBlob() []byte
+ // Path returns the hex-encoded path to the current node.
+ // Callers must not retain references to the return value after calling Next()
+ Path() []byte
+ // Next moves the iterator to the next node. If the parameter is false, any child
+ // nodes will be skipped.
+ Next(bool) bool
+ // Error returns the error status of the iterator.
+ Error() error
}
// nodeIteratorState represents the iteration state at one particular node of the
// trie, which can be resumed at a later invocation.
type nodeIteratorState struct {
- hash common.Hash // Hash of the node being iterated (nil if not standalone)
- node node // Trie node being iterated
- parent common.Hash // Hash of the first full ancestor node (nil if current is the root)
- child int // Child to be processed next
+ hash common.Hash // Hash of the node being iterated (nil if not standalone)
+ node node // Trie node being iterated
+ parent common.Hash // Hash of the first full ancestor node (nil if current is the root)
+ child int // Child to be processed next
+ pathlen int // Length of the path to this node
}
-// NodeIterator is an iterator to traverse the trie post-order.
-type NodeIterator struct {
+type nodeIterator struct {
trie *Trie // Trie being iterated
stack []*nodeIteratorState // Hierarchy of trie nodes persisting the iteration state
- Hash common.Hash // Hash of the current node being iterated (nil if not standalone)
- Node node // Current node being iterated (internal representation)
- Parent common.Hash // Hash of the first full ancestor node (nil if current is the root)
- Leaf bool // Flag whether the current node is a value (data) node
- LeafBlob []byte // Data blob contained within a leaf (otherwise nil)
+ err error // Failure set in case of an internal error in the iterator
- Error error // Failure set in case of an internal error in the iterator
+ path []byte // Path to the current node
}
// NewNodeIterator creates an post-order trie iterator.
-func NewNodeIterator(trie *Trie) *NodeIterator {
+func NewNodeIterator(trie *Trie) NodeIterator {
if trie.Hash() == emptyState {
- return new(NodeIterator)
+ return new(nodeIterator)
}
- return &NodeIterator{trie: trie}
+ return &nodeIterator{trie: trie}
+}
+
+// Hash returns the hash of the current node
+func (it *nodeIterator) Hash() common.Hash {
+ if len(it.stack) == 0 {
+ return common.Hash{}
+ }
+
+ return it.stack[len(it.stack)-1].hash
+}
+
+// Parent returns the hash of the parent node
+func (it *nodeIterator) Parent() common.Hash {
+ if len(it.stack) == 0 {
+ return common.Hash{}
+ }
+
+ return it.stack[len(it.stack)-1].parent
+}
+
+// Leaf returns true if the current node is a leaf
+func (it *nodeIterator) Leaf() bool {
+ if len(it.stack) == 0 {
+ return false
+ }
+
+ _, ok := it.stack[len(it.stack)-1].node.(valueNode)
+ return ok
+}
+
+// LeafBlob returns the data for the current node, if it is a leaf
+func (it *nodeIterator) LeafBlob() []byte {
+ if len(it.stack) == 0 {
+ return nil
+ }
+
+ if node, ok := it.stack[len(it.stack)-1].node.(valueNode); ok {
+ return []byte(node)
+ }
+ return nil
+}
+
+// Path returns the hex-encoded path to the current node
+func (it *nodeIterator) Path() []byte {
+ return it.path
+}
+
+// Error returns the error set in case of an internal error in the iterator
+func (it *nodeIterator) Error() error {
+ return it.err
}
// Next moves the iterator to the next node, returning whether there are any
// further nodes. In case of an internal error this method returns false and
-// sets the Error field to the encountered failure.
-func (it *NodeIterator) Next() bool {
+// sets the Error field to the encountered failure. If `descend` is false,
+// skips iterating over any subnodes of the current node.
+func (it *nodeIterator) Next(descend bool) bool {
// If the iterator failed previously, don't do anything
- if it.Error != nil {
+ if it.err != nil {
return false
}
// Otherwise step forward with the iterator and report any errors
- if err := it.step(); err != nil {
- it.Error = err
+ if err := it.step(descend); err != nil {
+ it.err = err
return false
}
- return it.retrieve()
+ return it.trie != nil
}
// step moves the iterator to the next node of the trie.
-func (it *NodeIterator) step() error {
+func (it *nodeIterator) step(descend bool) error {
if it.trie == nil {
// Abort if we reached the end of the iteration
return nil
@@ -132,93 +186,180 @@ func (it *NodeIterator) step() error {
state.hash = root
}
it.stack = append(it.stack, state)
- } else {
- // Continue iterating at the previous node otherwise.
+ return nil
+ }
+
+ if !descend {
+ // If we're skipping children, pop the current node first
+ it.path = it.path[:it.stack[len(it.stack)-1].pathlen]
it.stack = it.stack[:len(it.stack)-1]
+ }
+
+ // Continue iteration to the next child
+outer:
+ for {
if len(it.stack) == 0 {
it.trie = nil
return nil
}
- }
-
- // Continue iteration to the next child
- for {
parent := it.stack[len(it.stack)-1]
ancestor := parent.hash
if (ancestor == common.Hash{}) {
ancestor = parent.parent
}
if node, ok := parent.node.(*fullNode); ok {
- // Full node, traverse all children, then the node itself
- if parent.child >= len(node.Children) {
- break
- }
+ // Full node, iterate over children
for parent.child++; parent.child < len(node.Children); parent.child++ {
- if current := node.Children[parent.child]; current != nil {
+ child := node.Children[parent.child]
+ if child != nil {
+ hash, _ := child.cache()
it.stack = append(it.stack, &nodeIteratorState{
- hash: common.BytesToHash(node.flags.hash),
- node: current,
- parent: ancestor,
- child: -1,
+ hash: common.BytesToHash(hash),
+ node: child,
+ parent: ancestor,
+ child: -1,
+ pathlen: len(it.path),
})
- break
+ it.path = append(it.path, byte(parent.child))
+ break outer
}
}
} else if node, ok := parent.node.(*shortNode); ok {
- // Short node, traverse the pointer singleton child, then the node itself
- if parent.child >= 0 {
+ // Short node, return the pointer singleton child
+ if parent.child < 0 {
+ parent.child++
+ hash, _ := node.Val.cache()
+ it.stack = append(it.stack, &nodeIteratorState{
+ hash: common.BytesToHash(hash),
+ node: node.Val,
+ parent: ancestor,
+ child: -1,
+ pathlen: len(it.path),
+ })
+ if hasTerm(node.Key) {
+ it.path = append(it.path, node.Key[:len(node.Key)-1]...)
+ } else {
+ it.path = append(it.path, node.Key...)
+ }
break
}
- parent.child++
- it.stack = append(it.stack, &nodeIteratorState{
- hash: common.BytesToHash(node.flags.hash),
- node: node.Val,
- parent: ancestor,
- child: -1,
- })
} else if hash, ok := parent.node.(hashNode); ok {
- // Hash node, resolve the hash child from the database, then the node itself
- if parent.child >= 0 {
+ // Hash node, resolve the hash child from the database
+ if parent.child < 0 {
+ parent.child++
+ node, err := it.trie.resolveHash(hash, nil, nil)
+ if err != nil {
+ return err
+ }
+ it.stack = append(it.stack, &nodeIteratorState{
+ hash: common.BytesToHash(hash),
+ node: node,
+ parent: ancestor,
+ child: -1,
+ pathlen: len(it.path),
+ })
break
}
- parent.child++
-
- node, err := it.trie.resolveHash(hash, nil, nil)
- if err != nil {
- return err
- }
- it.stack = append(it.stack, &nodeIteratorState{
- hash: common.BytesToHash(hash),
- node: node,
- parent: ancestor,
- child: -1,
- })
- } else {
- break
}
+ it.path = it.path[:parent.pathlen]
+ it.stack = it.stack[:len(it.stack)-1]
}
return nil
}
-// retrieve pulls and caches the current trie node the iterator is traversing.
-// In case of a value node, the additional leaf blob is also populated with the
-// data contents for external interpretation.
-//
-// The method returns whether there are any more data left for inspection.
-func (it *NodeIterator) retrieve() bool {
- // Clear out any previously set values
- it.Hash, it.Node, it.Parent, it.Leaf, it.LeafBlob = common.Hash{}, nil, common.Hash{}, false, nil
+type differenceIterator struct {
+ a, b NodeIterator // Nodes returned are those in b - a.
+ eof bool // Indicates a has run out of elements
+ count int // Number of nodes scanned on either trie
+}
- // If the iteration's done, return no available data
- if it.trie == nil {
+// NewDifferenceIterator constructs a NodeIterator that iterates over elements in b that
+// are not in a. Returns the iterator, and a pointer to an integer recording the number
+// of nodes seen.
+func NewDifferenceIterator(a, b NodeIterator) (NodeIterator, *int) {
+ a.Next(true)
+ it := &differenceIterator{
+ a: a,
+ b: b,
+ }
+ return it, &it.count
+}
+
+func (it *differenceIterator) Hash() common.Hash {
+ return it.b.Hash()
+}
+
+func (it *differenceIterator) Parent() common.Hash {
+ return it.b.Parent()
+}
+
+func (it *differenceIterator) Leaf() bool {
+ return it.b.Leaf()
+}
+
+func (it *differenceIterator) LeafBlob() []byte {
+ return it.b.LeafBlob()
+}
+
+func (it *differenceIterator) Path() []byte {
+ return it.b.Path()
+}
+
+func (it *differenceIterator) Next(bool) bool {
+ // Invariants:
+ // - We always advance at least one element in b.
+ // - At the start of this function, a's path is lexically greater than b's.
+ if !it.b.Next(true) {
return false
}
- // Otherwise retrieve the current node and resolve leaf accessors
- state := it.stack[len(it.stack)-1]
+ it.count += 1
- it.Hash, it.Node, it.Parent = state.hash, state.node, state.parent
- if value, ok := it.Node.(valueNode); ok {
- it.Leaf, it.LeafBlob = true, []byte(value)
+ if it.eof {
+ // a has reached eof, so we just return all elements from b
+ return true
+ }
+
+ for {
+ apath, bpath := it.a.Path(), it.b.Path()
+ switch bytes.Compare(apath, bpath) {
+ case -1:
+ // b jumped past a; advance a
+ if !it.a.Next(true) {
+ it.eof = true
+ return true
+ }
+ it.count += 1
+ case 1:
+ // b is before a
+ return true
+ case 0:
+ if it.a.Hash() != it.b.Hash() || it.a.Leaf() != it.b.Leaf() {
+ // Keys are identical, but hashes or leaf status differs
+ return true
+ }
+ if it.a.Leaf() && it.b.Leaf() && !bytes.Equal(it.a.LeafBlob(), it.b.LeafBlob()) {
+ // Both are leaf nodes, but with different values
+ return true
+ }
+
+ // a and b are identical; skip this whole subtree if the nodes have hashes
+ hasHash := it.a.Hash() == common.Hash{}
+ if !it.b.Next(hasHash) {
+ return false
+ }
+ it.count += 1
+ if !it.a.Next(hasHash) {
+ it.eof = true
+ return true
+ }
+ it.count += 1
+ }
}
- return true
+}
+
+func (it *differenceIterator) Error() error {
+ if err := it.a.Error(); err != nil {
+ return err
+ }
+ return it.b.Error()
}
diff --git a/trie/iterator_test.go b/trie/iterator_test.go
index c56ac85be5..0ad9711edd 100644
--- a/trie/iterator_test.go
+++ b/trie/iterator_test.go
@@ -99,9 +99,9 @@ func TestNodeIteratorCoverage(t *testing.T) {
// Gather all the node hashes found by the iterator
hashes := make(map[common.Hash]struct{})
- for it := NewNodeIterator(trie); it.Next(); {
- if it.Hash != (common.Hash{}) {
- hashes[it.Hash] = struct{}{}
+ for it := NewNodeIterator(trie); it.Next(true); {
+ if it.Hash() != (common.Hash{}) {
+ hashes[it.Hash()] = struct{}{}
}
}
// Cross check the hashes and the database itself
@@ -116,3 +116,60 @@ func TestNodeIteratorCoverage(t *testing.T) {
}
}
}
+
+func TestDifferenceIterator(t *testing.T) {
+ triea := newEmpty()
+ valsa := []struct{ k, v string }{
+ {"bar", "b"},
+ {"barb", "ba"},
+ {"bars", "bb"},
+ {"bard", "bc"},
+ {"fab", "z"},
+ {"foo", "a"},
+ {"food", "ab"},
+ {"foos", "aa"},
+ }
+ for _, val := range valsa {
+ triea.Update([]byte(val.k), []byte(val.v))
+ }
+ triea.Commit()
+
+ trieb := newEmpty()
+ valsb := []struct{ k, v string }{
+ {"aardvark", "c"},
+ {"bar", "b"},
+ {"barb", "bd"},
+ {"bars", "be"},
+ {"fab", "z"},
+ {"foo", "a"},
+ {"foos", "aa"},
+ {"food", "ab"},
+ {"jars", "d"},
+ }
+ for _, val := range valsb {
+ trieb.Update([]byte(val.k), []byte(val.v))
+ }
+ trieb.Commit()
+
+ found := make(map[string]string)
+ di, _ := NewDifferenceIterator(NewNodeIterator(triea), NewNodeIterator(trieb))
+ it := NewIteratorFromNodeIterator(di)
+ for it.Next() {
+ found[string(it.Key)] = string(it.Value)
+ }
+
+ all := []struct{ k, v string }{
+ {"aardvark", "c"},
+ {"barb", "bd"},
+ {"bars", "be"},
+ {"jars", "d"},
+ }
+ for _, item := range all {
+ if found[item.k] != item.v {
+ t.Errorf("iterator value mismatch for %s: got %q want %q", item.k, found[item.k], item.v)
+ }
+ }
+ if len(found) != len(all) {
+ t.Errorf("iterator count mismatch: got %d values, want %d", len(found), len(all))
+ }
+}
diff --git a/trie/proof.go b/trie/proof.go
index bea5e5c098..06cf827ab1 100644
--- a/trie/proof.go
+++ b/trie/proof.go
@@ -23,8 +23,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto/sha3"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rlp"
)
@@ -61,9 +60,7 @@ func (t *Trie) Prove(key []byte) []rlp.RawValue {
var err error
tn, err = t.resolveHash(n, nil, nil)
if err != nil {
- if glog.V(logger.Error) {
- glog.Errorf("Unhandled trie error: %v", err)
- }
+ log.Error(fmt.Sprintf("Unhandled trie error: %v", err))
return nil
}
default:
diff --git a/trie/secure_trie.go b/trie/secure_trie.go
index 4d9ebe4d37..113fb6a1af 100644
--- a/trie/secure_trie.go
+++ b/trie/secure_trie.go
@@ -17,9 +17,10 @@
package trie
import (
+ "fmt"
+
"github.com/ethereum/go-ethereum/common"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/log"
)
var secureKeyPrefix = []byte("secure-key-")
@@ -70,8 +71,8 @@ func NewSecure(root common.Hash, db Database, cachelimit uint16) (*SecureTrie, e
// The value bytes must not be modified by the caller.
func (t *SecureTrie) Get(key []byte) []byte {
res, err := t.TryGet(key)
- if err != nil && glog.V(logger.Error) {
- glog.Errorf("Unhandled trie error: %v", err)
+ if err != nil {
+ log.Error(fmt.Sprintf("Unhandled trie error: %v", err))
}
return res
}
@@ -90,8 +91,8 @@ func (t *SecureTrie) TryGet(key []byte) ([]byte, error) {
// The value bytes must not be modified by the caller while they are
// stored in the trie.
func (t *SecureTrie) Update(key, value []byte) {
- if err := t.TryUpdate(key, value); err != nil && glog.V(logger.Error) {
- glog.Errorf("Unhandled trie error: %v", err)
+ if err := t.TryUpdate(key, value); err != nil {
+ log.Error(fmt.Sprintf("Unhandled trie error: %v", err))
}
}
@@ -115,8 +116,8 @@ func (t *SecureTrie) TryUpdate(key, value []byte) error {
// Delete removes any existing value for key from the trie.
func (t *SecureTrie) Delete(key []byte) {
- if err := t.TryDelete(key); err != nil && glog.V(logger.Error) {
- glog.Errorf("Unhandled trie error: %v", err)
+ if err := t.TryDelete(key); err != nil {
+ log.Error(fmt.Sprintf("Unhandled trie error: %v", err))
}
}
@@ -159,7 +160,7 @@ func (t *SecureTrie) Iterator() *Iterator {
return t.trie.Iterator()
}
-func (t *SecureTrie) NodeIterator() *NodeIterator {
+func (t *SecureTrie) NodeIterator() NodeIterator {
return NewNodeIterator(&t.trie)
}
diff --git a/trie/sync_test.go b/trie/sync_test.go
index 4168c4d658..acae039cd5 100644
--- a/trie/sync_test.go
+++ b/trie/sync_test.go
@@ -81,9 +81,9 @@ func checkTrieConsistency(db Database, root common.Hash) error {
return nil // // Consider a non existent state consistent
}
it := NewNodeIterator(trie)
- for it.Next() {
+ for it.Next(true) {
}
- return it.Error
+ return it.Error()
}
// Tests that an empty trie is not scheduled for syncing.
diff --git a/trie/trie.go b/trie/trie.go
index cd9e20cacb..2a60440689 100644
--- a/trie/trie.go
+++ b/trie/trie.go
@@ -23,8 +23,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto/sha3"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/log"
"github.com/rcrowley/go-metrics"
)
@@ -135,8 +134,8 @@ func (t *Trie) Iterator() *Iterator {
// The value bytes must not be modified by the caller.
func (t *Trie) Get(key []byte) []byte {
res, err := t.TryGet(key)
- if err != nil && glog.V(logger.Error) {
- glog.Errorf("Unhandled trie error: %v", err)
+ if err != nil {
+ log.Error(fmt.Sprintf("Unhandled trie error: %v", err))
}
return res
}
@@ -198,8 +197,8 @@ func (t *Trie) tryGet(origNode node, key []byte, pos int) (value []byte, newnode
// The value bytes must not be modified by the caller while they are
// stored in the trie.
func (t *Trie) Update(key, value []byte) {
- if err := t.TryUpdate(key, value); err != nil && glog.V(logger.Error) {
- glog.Errorf("Unhandled trie error: %v", err)
+ if err := t.TryUpdate(key, value); err != nil {
+ log.Error(fmt.Sprintf("Unhandled trie error: %v", err))
}
}
@@ -300,8 +299,8 @@ func (t *Trie) insert(n node, prefix, key []byte, value node) (bool, node, error
// Delete removes any existing value for key from the trie.
func (t *Trie) Delete(key []byte) {
- if err := t.TryDelete(key); err != nil && glog.V(logger.Error) {
- glog.Errorf("Unhandled trie error: %v", err)
+ if err := t.TryDelete(key); err != nil {
+ log.Error(fmt.Sprintf("Unhandled trie error: %v", err))
}
}
diff --git a/trie/trie_test.go b/trie/trie_test.go
index 60307dba8c..01ae3a4e7b 100644
--- a/trie/trie_test.go
+++ b/trie/trie_test.go
@@ -377,7 +377,7 @@ func (randTest) Generate(r *rand.Rand, size int) reflect.Value {
if len(allKeys) < 2 || r.Intn(100) < 10 {
// new key
key := make([]byte, r.Intn(50))
- randRead(r, key)
+ r.Read(key)
allKeys = append(allKeys, key)
return key
}
@@ -401,22 +401,6 @@ func (randTest) Generate(r *rand.Rand, size int) reflect.Value {
return reflect.ValueOf(steps)
}
-// rand.Rand provides a Read method in Go 1.7 and later, but
-// we can't use it yet.
-func randRead(r *rand.Rand, b []byte) {
- pos := 0
- val := 0
- for n := 0; n < len(b); n++ {
- if pos == 0 {
- val = r.Int()
- pos = 7
- }
- b[n] = byte(val)
- val >>= 8
- pos--
- }
-}
-
func runRandTest(rt randTest) bool {
db, _ := ethdb.NewMemDatabase()
tr, _ := New(common.Hash{}, db)
diff --git a/vendor.conf b/vendor.conf
deleted file mode 100644
index 92092a2acd..0000000000
--- a/vendor.conf
+++ /dev/null
@@ -1,44 +0,0 @@
-# package
-github.com/ethereum/go-ethereum
-
-# import
-github.com/Azure/azure-sdk-for-go v5.0.0-beta-5-gbd73d95
-github.com/aristanetworks/goarista ockafka-v0.0.2-21-g34c98d5
-github.com/cespare/cp 165db2f
-github.com/davecgh/go-spew v1.1.0
-github.com/ethereum/ethash v23.1-249-g214d4c0
-github.com/fatih/color v1.2-2-ge8e01ee
-github.com/gizak/termui v2.1.1-9-gf63e0cd
-github.com/golang/snappy d9eb7a3
-github.com/hashicorp/golang-lru 0a025b7
-github.com/huin/goupnp 679507a
-github.com/jackpal/go-nat-pmp v1.0.1-4-g1fa385a
-github.com/karalabe/gousb ffa821b
-github.com/maruel/panicparse ad66119
-github.com/mattn/go-colorable v0.0.6-9-gd228849
-github.com/mattn/go-isatty 30a891c
-github.com/mattn/go-runewidth v0.0.1-10-g737072b
-github.com/mitchellh/go-wordwrap ad45545
-github.com/nsf/termbox-go abe82ce
-github.com/pborman/uuid v1.0-19-g5007efa
-github.com/peterh/liner 3c5f577
-github.com/rcrowley/go-metrics 1f30fe9
-github.com/rjeczalik/notify 7e20c15
-github.com/robertkrimen/otto bf1c379
-github.com/rs/cors v1.0
-github.com/rs/xhandler v1.0-1-ged27b6f
-github.com/syndtr/goleveldb 23851d9
-golang.org/x/crypto 7c6cc32
-golang.org/x/net 60c41d1
-golang.org/x/sys d75a526
-golang.org/x/text 44f4f65
-golang.org/x/tools 116266f6
-gopkg.in/check.v1 20d25e2
-gopkg.in/fatih/set.v0 v0.1.0-3-g27c4092
-gopkg.in/karalabe/cookiejar.v2 8dcd6a7
-gopkg.in/natefinch/npipe.v2 c1b8fa8
-gopkg.in/sourcemap.v1 v1.0.3
-gopkg.in/urfave/cli.v1 v1.19.1
-
-# exclude
--golang.org/x/net/context
diff --git a/vendor/bazil.org/fuse/LICENSE b/vendor/bazil.org/fuse/LICENSE
new file mode 100644
index 0000000000..4ac7cd8389
--- /dev/null
+++ b/vendor/bazil.org/fuse/LICENSE
@@ -0,0 +1,93 @@
+Copyright (c) 2013-2015 Tommi Virtanen.
+Copyright (c) 2009, 2011, 2012 The Go Authors.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+ * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+
+The following included software components have additional copyright
+notices and license terms that may differ from the above.
+
+
+File fuse.go:
+
+// Adapted from Plan 9 from User Space's src/cmd/9pfuse/fuse.c,
+// which carries this notice:
+//
+// The files in this directory are subject to the following license.
+//
+// The author of this software is Russ Cox.
+//
+// Copyright (c) 2006 Russ Cox
+//
+// Permission to use, copy, modify, and distribute this software for any
+// purpose without fee is hereby granted, provided that this entire notice
+// is included in all copies of any software which is or includes a copy
+// or modification of this software and in all copies of the supporting
+// documentation for such software.
+//
+// THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+// WARRANTY. IN PARTICULAR, THE AUTHOR MAKES NO REPRESENTATION OR WARRANTY
+// OF ANY KIND CONCERNING THE MERCHANTABILITY OF THIS SOFTWARE OR ITS
+// FITNESS FOR ANY PARTICULAR PURPOSE.
+
+
+File fuse_kernel.go:
+
+// Derived from FUSE's fuse_kernel.h
+/*
+ This file defines the kernel interface of FUSE
+ Copyright (C) 2001-2007 Miklos Szeredi
+
+
+ This -- and only this -- header file may also be distributed under
+ the terms of the BSD Licence as follows:
+
+ Copyright (C) 2001-2007 Miklos Szeredi. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.
+*/
diff --git a/vendor/bazil.org/fuse/README.md b/vendor/bazil.org/fuse/README.md
new file mode 100644
index 0000000000..8c6d556ee3
--- /dev/null
+++ b/vendor/bazil.org/fuse/README.md
@@ -0,0 +1,23 @@
+bazil.org/fuse -- Filesystems in Go
+===================================
+
+`bazil.org/fuse` is a Go library for writing FUSE userspace
+filesystems.
+
+It is a from-scratch implementation of the kernel-userspace
+communication protocol, and does not use the C library from the
+project called FUSE. `bazil.org/fuse` embraces Go fully for safety and
+ease of programming.
+
+Here’s how to get going:
+
+ go get bazil.org/fuse
+
+Website: http://bazil.org/fuse/
+
+Github repository: https://github.com/bazil/fuse
+
+API docs: http://godoc.org/bazil.org/fuse
+
+Our thanks to Russ Cox for his fuse library, which this project is
+based on.
diff --git a/vendor/bazil.org/fuse/buffer.go b/vendor/bazil.org/fuse/buffer.go
new file mode 100644
index 0000000000..bb1d2b7769
--- /dev/null
+++ b/vendor/bazil.org/fuse/buffer.go
@@ -0,0 +1,35 @@
+package fuse
+
+import "unsafe"
+
+// buffer provides a mechanism for constructing a message from
+// multiple segments.
+type buffer []byte
+
+// alloc allocates size bytes and returns a pointer to the new
+// segment.
+func (w *buffer) alloc(size uintptr) unsafe.Pointer {
+ s := int(size)
+ if len(*w)+s > cap(*w) {
+ old := *w
+ *w = make([]byte, len(*w), 2*cap(*w)+s)
+ copy(*w, old)
+ }
+ l := len(*w)
+ *w = (*w)[:l+s]
+ return unsafe.Pointer(&(*w)[l])
+}
+
+// reset clears out the contents of the buffer.
+func (w *buffer) reset() {
+ for i := range (*w)[:cap(*w)] {
+ (*w)[i] = 0
+ }
+ *w = (*w)[:0]
+}
+
+func newBuffer(extra uintptr) buffer {
+ const hdrSize = unsafe.Sizeof(outHeader{})
+ buf := make(buffer, hdrSize, hdrSize+extra)
+ return buf
+}
diff --git a/vendor/bazil.org/fuse/debug.go b/vendor/bazil.org/fuse/debug.go
new file mode 100644
index 0000000000..be9f900d5e
--- /dev/null
+++ b/vendor/bazil.org/fuse/debug.go
@@ -0,0 +1,21 @@
+package fuse
+
+import (
+ "runtime"
+)
+
+func stack() string {
+ buf := make([]byte, 1024)
+ return string(buf[:runtime.Stack(buf, false)])
+}
+
+func nop(msg interface{}) {}
+
+// Debug is called to output debug messages, including protocol
+// traces. The default behavior is to do nothing.
+//
+// The messages have human-friendly string representations and are
+// safe to marshal to JSON.
+//
+// Implementations must not retain msg.
+var Debug func(msg interface{}) = nop
diff --git a/vendor/bazil.org/fuse/error_darwin.go b/vendor/bazil.org/fuse/error_darwin.go
new file mode 100644
index 0000000000..a3fb89ca29
--- /dev/null
+++ b/vendor/bazil.org/fuse/error_darwin.go
@@ -0,0 +1,17 @@
+package fuse
+
+import (
+ "syscall"
+)
+
+const (
+ ENOATTR = Errno(syscall.ENOATTR)
+)
+
+const (
+ errNoXattr = ENOATTR
+)
+
+func init() {
+ errnoNames[errNoXattr] = "ENOATTR"
+}
diff --git a/vendor/bazil.org/fuse/error_freebsd.go b/vendor/bazil.org/fuse/error_freebsd.go
new file mode 100644
index 0000000000..c6ea6d6e71
--- /dev/null
+++ b/vendor/bazil.org/fuse/error_freebsd.go
@@ -0,0 +1,15 @@
+package fuse
+
+import "syscall"
+
+const (
+ ENOATTR = Errno(syscall.ENOATTR)
+)
+
+const (
+ errNoXattr = ENOATTR
+)
+
+func init() {
+ errnoNames[errNoXattr] = "ENOATTR"
+}
diff --git a/vendor/bazil.org/fuse/error_linux.go b/vendor/bazil.org/fuse/error_linux.go
new file mode 100644
index 0000000000..6f113e71ed
--- /dev/null
+++ b/vendor/bazil.org/fuse/error_linux.go
@@ -0,0 +1,17 @@
+package fuse
+
+import (
+ "syscall"
+)
+
+const (
+ ENODATA = Errno(syscall.ENODATA)
+)
+
+const (
+ errNoXattr = ENODATA
+)
+
+func init() {
+ errnoNames[errNoXattr] = "ENODATA"
+}
diff --git a/vendor/bazil.org/fuse/error_std.go b/vendor/bazil.org/fuse/error_std.go
new file mode 100644
index 0000000000..398f43fbf6
--- /dev/null
+++ b/vendor/bazil.org/fuse/error_std.go
@@ -0,0 +1,31 @@
+package fuse
+
+// There is very little commonality in extended attribute errors
+// across platforms.
+//
+// getxattr return value for "extended attribute does not exist" is
+// ENOATTR on OS X, and ENODATA on Linux and apparently at least
+// NetBSD. There may be a #define ENOATTR on Linux too, but the value
+// is ENODATA in the actual syscalls. FreeBSD and OpenBSD have no
+// ENODATA, only ENOATTR. ENOATTR is not in any of the standards,
+// ENODATA exists but is only used for STREAMs.
+//
+// Each platform will define it a errNoXattr constant, and this file
+// will enforce that it implements the right interfaces and hide the
+// implementation.
+//
+// https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man2/getxattr.2.html
+// http://mail-index.netbsd.org/tech-kern/2012/04/30/msg013090.html
+// http://mail-index.netbsd.org/tech-kern/2012/04/30/msg013097.html
+// http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/errno.h.html
+// http://www.freebsd.org/cgi/man.cgi?query=extattr_get_file&sektion=2
+// http://nixdoc.net/man-pages/openbsd/man2/extattr_get_file.2.html
+
+// ErrNoXattr is a platform-independent error value meaning the
+// extended attribute was not found. It can be used to respond to
+// GetxattrRequest and such.
+const ErrNoXattr = errNoXattr
+
+var _ error = ErrNoXattr
+var _ Errno = ErrNoXattr
+var _ ErrorNumber = ErrNoXattr
diff --git a/vendor/bazil.org/fuse/fs/serve.go b/vendor/bazil.org/fuse/fs/serve.go
new file mode 100644
index 0000000000..e9fc56590f
--- /dev/null
+++ b/vendor/bazil.org/fuse/fs/serve.go
@@ -0,0 +1,1568 @@
+// FUSE service loop, for servers that wish to use it.
+
+package fs // import "bazil.org/fuse/fs"
+
+import (
+ "encoding/binary"
+ "fmt"
+ "hash/fnv"
+ "io"
+ "log"
+ "reflect"
+ "runtime"
+ "strings"
+ "sync"
+ "time"
+
+ "golang.org/x/net/context"
+)
+
+import (
+ "bytes"
+
+ "bazil.org/fuse"
+ "bazil.org/fuse/fuseutil"
+)
+
+const (
+ attrValidTime = 1 * time.Minute
+ entryValidTime = 1 * time.Minute
+)
+
+// TODO: FINISH DOCS
+
+// An FS is the interface required of a file system.
+//
+// Other FUSE requests can be handled by implementing methods from the
+// FS* interfaces, for example FSStatfser.
+type FS interface {
+ // Root is called to obtain the Node for the file system root.
+ Root() (Node, error)
+}
+
+type FSStatfser interface {
+ // Statfs is called to obtain file system metadata.
+ // It should write that data to resp.
+ Statfs(ctx context.Context, req *fuse.StatfsRequest, resp *fuse.StatfsResponse) error
+}
+
+type FSDestroyer interface {
+ // Destroy is called when the file system is shutting down.
+ //
+ // Linux only sends this request for block device backed (fuseblk)
+ // filesystems, to allow them to flush writes to disk before the
+ // unmount completes.
+ Destroy()
+}
+
+type FSInodeGenerator interface {
+ // GenerateInode is called to pick a dynamic inode number when it
+ // would otherwise be 0.
+ //
+ // Not all filesystems bother tracking inodes, but FUSE requires
+ // the inode to be set, and fewer duplicates in general makes UNIX
+ // tools work better.
+ //
+ // Operations where the nodes may return 0 inodes include Getattr,
+ // Setattr and ReadDir.
+ //
+ // If FS does not implement FSInodeGenerator, GenerateDynamicInode
+ // is used.
+ //
+ // Implementing this is useful to e.g. constrain the range of
+ // inode values used for dynamic inodes.
+ GenerateInode(parentInode uint64, name string) uint64
+}
+
+// A Node is the interface required of a file or directory.
+// See the documentation for type FS for general information
+// pertaining to all methods.
+//
+// A Node must be usable as a map key, that is, it cannot be a
+// function, map or slice.
+//
+// Other FUSE requests can be handled by implementing methods from the
+// Node* interfaces, for example NodeOpener.
+//
+// Methods returning Node should take care to return the same Node
+// when the result is logically the same instance. Without this, each
+// Node will get a new NodeID, causing spurious cache invalidations,
+// extra lookups and aliasing anomalies. This may not matter for a
+// simple, read-only filesystem.
+type Node interface {
+ // Attr fills attr with the standard metadata for the node.
+ //
+ // Fields with reasonable defaults are prepopulated. For example,
+ // all times are set to a fixed moment when the program started.
+ //
+ // If Inode is left as 0, a dynamic inode number is chosen.
+ //
+ // The result may be cached for the duration set in Valid.
+ Attr(ctx context.Context, attr *fuse.Attr) error
+}
+
+type NodeGetattrer interface {
+ // Getattr obtains the standard metadata for the receiver.
+ // It should store that metadata in resp.
+ //
+ // If this method is not implemented, the attributes will be
+ // generated based on Attr(), with zero values filled in.
+ Getattr(ctx context.Context, req *fuse.GetattrRequest, resp *fuse.GetattrResponse) error
+}
+
+type NodeSetattrer interface {
+ // Setattr sets the standard metadata for the receiver.
+ //
+ // Note, this is also used to communicate changes in the size of
+ // the file, outside of Writes.
+ //
+ // req.Valid is a bitmask of what fields are actually being set.
+ // For example, the method should not change the mode of the file
+ // unless req.Valid.Mode() is true.
+ Setattr(ctx context.Context, req *fuse.SetattrRequest, resp *fuse.SetattrResponse) error
+}
+
+type NodeSymlinker interface {
+ // Symlink creates a new symbolic link in the receiver, which must be a directory.
+ //
+ // TODO is the above true about directories?
+ Symlink(ctx context.Context, req *fuse.SymlinkRequest) (Node, error)
+}
+
+// This optional request will be called only for symbolic link nodes.
+type NodeReadlinker interface {
+ // Readlink reads a symbolic link.
+ Readlink(ctx context.Context, req *fuse.ReadlinkRequest) (string, error)
+}
+
+type NodeLinker interface {
+ // Link creates a new directory entry in the receiver based on an
+ // existing Node. Receiver must be a directory.
+ Link(ctx context.Context, req *fuse.LinkRequest, old Node) (Node, error)
+}
+
+type NodeRemover interface {
+ // Remove removes the entry with the given name from
+ // the receiver, which must be a directory. The entry to be removed
+ // may correspond to a file (unlink) or to a directory (rmdir).
+ Remove(ctx context.Context, req *fuse.RemoveRequest) error
+}
+
+type NodeAccesser interface {
+ // Access checks whether the calling context has permission for
+ // the given operations on the receiver. If so, Access should
+ // return nil. If not, Access should return EPERM.
+ //
+ // Note that this call affects the result of the access(2) system
+ // call but not the open(2) system call. If Access is not
+ // implemented, the Node behaves as if it always returns nil
+ // (permission granted), relying on checks in Open instead.
+ Access(ctx context.Context, req *fuse.AccessRequest) error
+}
+
+type NodeStringLookuper interface {
+ // Lookup looks up a specific entry in the receiver,
+ // which must be a directory. Lookup should return a Node
+ // corresponding to the entry. If the name does not exist in
+ // the directory, Lookup should return ENOENT.
+ //
+ // Lookup need not to handle the names "." and "..".
+ Lookup(ctx context.Context, name string) (Node, error)
+}
+
+type NodeRequestLookuper interface {
+ // Lookup looks up a specific entry in the receiver.
+ // See NodeStringLookuper for more.
+ Lookup(ctx context.Context, req *fuse.LookupRequest, resp *fuse.LookupResponse) (Node, error)
+}
+
+type NodeMkdirer interface {
+ Mkdir(ctx context.Context, req *fuse.MkdirRequest) (Node, error)
+}
+
+type NodeOpener interface {
+ // Open opens the receiver. After a successful open, a client
+ // process has a file descriptor referring to this Handle.
+ //
+ // Open can also be also called on non-files. For example,
+ // directories are Opened for ReadDir or fchdir(2).
+ //
+ // If this method is not implemented, the open will always
+ // succeed, and the Node itself will be used as the Handle.
+ //
+ // XXX note about access. XXX OpenFlags.
+ Open(ctx context.Context, req *fuse.OpenRequest, resp *fuse.OpenResponse) (Handle, error)
+}
+
+type NodeCreater interface {
+ // Create creates a new directory entry in the receiver, which
+ // must be a directory.
+ Create(ctx context.Context, req *fuse.CreateRequest, resp *fuse.CreateResponse) (Node, Handle, error)
+}
+
+type NodeForgetter interface {
+ // Forget about this node. This node will not receive further
+ // method calls.
+ //
+ // Forget is not necessarily seen on unmount, as all nodes are
+ // implicitly forgotten as part part of the unmount.
+ Forget()
+}
+
+type NodeRenamer interface {
+ Rename(ctx context.Context, req *fuse.RenameRequest, newDir Node) error
+}
+
+type NodeMknoder interface {
+ Mknod(ctx context.Context, req *fuse.MknodRequest) (Node, error)
+}
+
+// TODO this should be on Handle not Node
+type NodeFsyncer interface {
+ Fsync(ctx context.Context, req *fuse.FsyncRequest) error
+}
+
+type NodeGetxattrer interface {
+ // Getxattr gets an extended attribute by the given name from the
+ // node.
+ //
+ // If there is no xattr by that name, returns fuse.ErrNoXattr.
+ Getxattr(ctx context.Context, req *fuse.GetxattrRequest, resp *fuse.GetxattrResponse) error
+}
+
+type NodeListxattrer interface {
+ // Listxattr lists the extended attributes recorded for the node.
+ Listxattr(ctx context.Context, req *fuse.ListxattrRequest, resp *fuse.ListxattrResponse) error
+}
+
+type NodeSetxattrer interface {
+ // Setxattr sets an extended attribute with the given name and
+ // value for the node.
+ Setxattr(ctx context.Context, req *fuse.SetxattrRequest) error
+}
+
+type NodeRemovexattrer interface {
+ // Removexattr removes an extended attribute for the name.
+ //
+ // If there is no xattr by that name, returns fuse.ErrNoXattr.
+ Removexattr(ctx context.Context, req *fuse.RemovexattrRequest) error
+}
+
+var startTime = time.Now()
+
+func nodeAttr(ctx context.Context, n Node, attr *fuse.Attr) error {
+ attr.Valid = attrValidTime
+ attr.Nlink = 1
+ attr.Atime = startTime
+ attr.Mtime = startTime
+ attr.Ctime = startTime
+ attr.Crtime = startTime
+ if err := n.Attr(ctx, attr); err != nil {
+ return err
+ }
+ return nil
+}
+
+// A Handle is the interface required of an opened file or directory.
+// See the documentation for type FS for general information
+// pertaining to all methods.
+//
+// Other FUSE requests can be handled by implementing methods from the
+// Handle* interfaces. The most common to implement are HandleReader,
+// HandleReadDirer, and HandleWriter.
+//
+// TODO implement methods: Getlk, Setlk, Setlkw
+type Handle interface {
+}
+
+type HandleFlusher interface {
+ // Flush is called each time the file or directory is closed.
+ // Because there can be multiple file descriptors referring to a
+ // single opened file, Flush can be called multiple times.
+ Flush(ctx context.Context, req *fuse.FlushRequest) error
+}
+
+type HandleReadAller interface {
+ ReadAll(ctx context.Context) ([]byte, error)
+}
+
+type HandleReadDirAller interface {
+ ReadDirAll(ctx context.Context) ([]fuse.Dirent, error)
+}
+
+type HandleReader interface {
+ // Read requests to read data from the handle.
+ //
+ // There is a page cache in the kernel that normally submits only
+ // page-aligned reads spanning one or more pages. However, you
+ // should not rely on this. To see individual requests as
+ // submitted by the file system clients, set OpenDirectIO.
+ //
+ // Note that reads beyond the size of the file as reported by Attr
+ // are not even attempted (except in OpenDirectIO mode).
+ Read(ctx context.Context, req *fuse.ReadRequest, resp *fuse.ReadResponse) error
+}
+
+type HandleWriter interface {
+ // Write requests to write data into the handle at the given offset.
+ // Store the amount of data written in resp.Size.
+ //
+ // There is a writeback page cache in the kernel that normally submits
+ // only page-aligned writes spanning one or more pages. However,
+ // you should not rely on this. To see individual requests as
+ // submitted by the file system clients, set OpenDirectIO.
+ //
+ // Writes that grow the file are expected to update the file size
+ // (as seen through Attr). Note that file size changes are
+ // communicated also through Setattr.
+ Write(ctx context.Context, req *fuse.WriteRequest, resp *fuse.WriteResponse) error
+}
+
+type HandleReleaser interface {
+ Release(ctx context.Context, req *fuse.ReleaseRequest) error
+}
+
+type Config struct {
+ // Function to send debug log messages to. If nil, use fuse.Debug.
+ // Note that changing this or fuse.Debug may not affect existing
+ // calls to Serve.
+ //
+ // See fuse.Debug for the rules that log functions must follow.
+ Debug func(msg interface{})
+
+ // Function to put things into context for processing the request.
+ // The returned context must have ctx as its parent.
+ //
+ // Note that changing this may not affect existing calls to Serve.
+ //
+ // Must not retain req.
+ WithContext func(ctx context.Context, req fuse.Request) context.Context
+}
+
+// New returns a new FUSE server ready to serve this kernel FUSE
+// connection.
+//
+// Config may be nil.
+func New(conn *fuse.Conn, config *Config) *Server {
+ s := &Server{
+ conn: conn,
+ req: map[fuse.RequestID]*serveRequest{},
+ nodeRef: map[Node]fuse.NodeID{},
+ dynamicInode: GenerateDynamicInode,
+ }
+ if config != nil {
+ s.debug = config.Debug
+ s.context = config.WithContext
+ }
+ if s.debug == nil {
+ s.debug = fuse.Debug
+ }
+ return s
+}
+
+type Server struct {
+ // set in New
+ conn *fuse.Conn
+ debug func(msg interface{})
+ context func(ctx context.Context, req fuse.Request) context.Context
+
+ // set once at Serve time
+ fs FS
+ dynamicInode func(parent uint64, name string) uint64
+
+ // state, protected by meta
+ meta sync.Mutex
+ req map[fuse.RequestID]*serveRequest
+ node []*serveNode
+ nodeRef map[Node]fuse.NodeID
+ handle []*serveHandle
+ freeNode []fuse.NodeID
+ freeHandle []fuse.HandleID
+ nodeGen uint64
+
+ // Used to ensure worker goroutines finish before Serve returns
+ wg sync.WaitGroup
+}
+
+// Serve serves the FUSE connection by making calls to the methods
+// of fs and the Nodes and Handles it makes available. It returns only
+// when the connection has been closed or an unexpected error occurs.
+func (s *Server) Serve(fs FS) error {
+ defer s.wg.Wait() // Wait for worker goroutines to complete before return
+
+ s.fs = fs
+ if dyn, ok := fs.(FSInodeGenerator); ok {
+ s.dynamicInode = dyn.GenerateInode
+ }
+
+ root, err := fs.Root()
+ if err != nil {
+ return fmt.Errorf("cannot obtain root node: %v", err)
+ }
+ // Recognize the root node if it's ever returned from Lookup,
+ // passed to Invalidate, etc.
+ s.nodeRef[root] = 1
+ s.node = append(s.node, nil, &serveNode{
+ inode: 1,
+ generation: s.nodeGen,
+ node: root,
+ refs: 1,
+ })
+ s.handle = append(s.handle, nil)
+
+ for {
+ req, err := s.conn.ReadRequest()
+ if err != nil {
+ if err == io.EOF {
+ break
+ }
+ return err
+ }
+
+ s.wg.Add(1)
+ go func() {
+ defer s.wg.Done()
+ s.serve(req)
+ }()
+ }
+ return nil
+}
+
+// Serve serves a FUSE connection with the default settings. See
+// Server.Serve.
+func Serve(c *fuse.Conn, fs FS) error {
+ server := New(c, nil)
+ return server.Serve(fs)
+}
+
+type nothing struct{}
+
+type serveRequest struct {
+ Request fuse.Request
+ cancel func()
+}
+
+type serveNode struct {
+ inode uint64
+ generation uint64
+ node Node
+ refs uint64
+
+ // Delay freeing the NodeID until waitgroup is done. This allows
+ // using the NodeID for short periods of time without holding the
+ // Server.meta lock.
+ //
+ // Rules:
+ //
+ // - hold Server.meta while calling wg.Add, then unlock
+ // - do NOT try to reacquire Server.meta
+ wg sync.WaitGroup
+}
+
+func (sn *serveNode) attr(ctx context.Context, attr *fuse.Attr) error {
+ err := nodeAttr(ctx, sn.node, attr)
+ if attr.Inode == 0 {
+ attr.Inode = sn.inode
+ }
+ return err
+}
+
+type serveHandle struct {
+ handle Handle
+ readData []byte
+ nodeID fuse.NodeID
+}
+
+// NodeRef is deprecated. It remains here to decrease code churn on
+// FUSE library users. You may remove it from your program now;
+// returning the same Node values are now recognized automatically,
+// without needing NodeRef.
+type NodeRef struct{}
+
+func (c *Server) saveNode(inode uint64, node Node) (id fuse.NodeID, gen uint64) {
+ c.meta.Lock()
+ defer c.meta.Unlock()
+
+ if id, ok := c.nodeRef[node]; ok {
+ sn := c.node[id]
+ sn.refs++
+ return id, sn.generation
+ }
+
+ sn := &serveNode{inode: inode, node: node, refs: 1}
+ if n := len(c.freeNode); n > 0 {
+ id = c.freeNode[n-1]
+ c.freeNode = c.freeNode[:n-1]
+ c.node[id] = sn
+ c.nodeGen++
+ } else {
+ id = fuse.NodeID(len(c.node))
+ c.node = append(c.node, sn)
+ }
+ sn.generation = c.nodeGen
+ c.nodeRef[node] = id
+ return id, sn.generation
+}
+
+func (c *Server) saveHandle(handle Handle, nodeID fuse.NodeID) (id fuse.HandleID) {
+ c.meta.Lock()
+ shandle := &serveHandle{handle: handle, nodeID: nodeID}
+ if n := len(c.freeHandle); n > 0 {
+ id = c.freeHandle[n-1]
+ c.freeHandle = c.freeHandle[:n-1]
+ c.handle[id] = shandle
+ } else {
+ id = fuse.HandleID(len(c.handle))
+ c.handle = append(c.handle, shandle)
+ }
+ c.meta.Unlock()
+ return
+}
+
+type nodeRefcountDropBug struct {
+ N uint64
+ Refs uint64
+ Node fuse.NodeID
+}
+
+func (n *nodeRefcountDropBug) String() string {
+ return fmt.Sprintf("bug: trying to drop %d of %d references to %v", n.N, n.Refs, n.Node)
+}
+
+func (c *Server) dropNode(id fuse.NodeID, n uint64) (forget bool) {
+ c.meta.Lock()
+ defer c.meta.Unlock()
+ snode := c.node[id]
+
+ if snode == nil {
+ // this should only happen if refcounts kernel<->us disagree
+ // *and* two ForgetRequests for the same node race each other;
+ // this indicates a bug somewhere
+ c.debug(nodeRefcountDropBug{N: n, Node: id})
+
+ // we may end up triggering Forget twice, but that's better
+ // than not even once, and that's the best we can do
+ return true
+ }
+
+ if n > snode.refs {
+ c.debug(nodeRefcountDropBug{N: n, Refs: snode.refs, Node: id})
+ n = snode.refs
+ }
+
+ snode.refs -= n
+ if snode.refs == 0 {
+ snode.wg.Wait()
+ c.node[id] = nil
+ delete(c.nodeRef, snode.node)
+ c.freeNode = append(c.freeNode, id)
+ return true
+ }
+ return false
+}
+
+func (c *Server) dropHandle(id fuse.HandleID) {
+ c.meta.Lock()
+ c.handle[id] = nil
+ c.freeHandle = append(c.freeHandle, id)
+ c.meta.Unlock()
+}
+
+type missingHandle struct {
+ Handle fuse.HandleID
+ MaxHandle fuse.HandleID
+}
+
+func (m missingHandle) String() string {
+ return fmt.Sprint("missing handle: ", m.Handle, m.MaxHandle)
+}
+
+// Returns nil for invalid handles.
+func (c *Server) getHandle(id fuse.HandleID) (shandle *serveHandle) {
+ c.meta.Lock()
+ defer c.meta.Unlock()
+ if id < fuse.HandleID(len(c.handle)) {
+ shandle = c.handle[uint(id)]
+ }
+ if shandle == nil {
+ c.debug(missingHandle{
+ Handle: id,
+ MaxHandle: fuse.HandleID(len(c.handle)),
+ })
+ }
+ return
+}
+
+type request struct {
+ Op string
+ Request *fuse.Header
+ In interface{} `json:",omitempty"`
+}
+
+func (r request) String() string {
+ return fmt.Sprintf("<- %s", r.In)
+}
+
+type logResponseHeader struct {
+ ID fuse.RequestID
+}
+
+func (m logResponseHeader) String() string {
+ return fmt.Sprintf("ID=%v", m.ID)
+}
+
+type response struct {
+ Op string
+ Request logResponseHeader
+ Out interface{} `json:",omitempty"`
+ // Errno contains the errno value as a string, for example "EPERM".
+ Errno string `json:",omitempty"`
+ // Error may contain a free form error message.
+ Error string `json:",omitempty"`
+}
+
+func (r response) errstr() string {
+ s := r.Errno
+ if r.Error != "" {
+ // prefix the errno constant to the long form message
+ s = s + ": " + r.Error
+ }
+ return s
+}
+
+func (r response) String() string {
+ switch {
+ case r.Errno != "" && r.Out != nil:
+ return fmt.Sprintf("-> [%v] %v error=%s", r.Request, r.Out, r.errstr())
+ case r.Errno != "":
+ return fmt.Sprintf("-> [%v] %s error=%s", r.Request, r.Op, r.errstr())
+ case r.Out != nil:
+ // make sure (seemingly) empty values are readable
+ switch r.Out.(type) {
+ case string:
+ return fmt.Sprintf("-> [%v] %s %q", r.Request, r.Op, r.Out)
+ case []byte:
+ return fmt.Sprintf("-> [%v] %s [% x]", r.Request, r.Op, r.Out)
+ default:
+ return fmt.Sprintf("-> [%v] %v", r.Request, r.Out)
+ }
+ default:
+ return fmt.Sprintf("-> [%v] %s", r.Request, r.Op)
+ }
+}
+
+type notification struct {
+ Op string
+ Node fuse.NodeID
+ Out interface{} `json:",omitempty"`
+ Err string `json:",omitempty"`
+}
+
+func (n notification) String() string {
+ var buf bytes.Buffer
+ fmt.Fprintf(&buf, "=> %s %v", n.Op, n.Node)
+ if n.Out != nil {
+ // make sure (seemingly) empty values are readable
+ switch n.Out.(type) {
+ case string:
+ fmt.Fprintf(&buf, " %q", n.Out)
+ case []byte:
+ fmt.Fprintf(&buf, " [% x]", n.Out)
+ default:
+ fmt.Fprintf(&buf, " %s", n.Out)
+ }
+ }
+ if n.Err != "" {
+ fmt.Fprintf(&buf, " Err:%v", n.Err)
+ }
+ return buf.String()
+}
+
+type logMissingNode struct {
+ MaxNode fuse.NodeID
+}
+
+func opName(req fuse.Request) string {
+ t := reflect.Indirect(reflect.ValueOf(req)).Type()
+ s := t.Name()
+ s = strings.TrimSuffix(s, "Request")
+ return s
+}
+
+type logLinkRequestOldNodeNotFound struct {
+ Request *fuse.Header
+ In *fuse.LinkRequest
+}
+
+func (m *logLinkRequestOldNodeNotFound) String() string {
+ return fmt.Sprintf("In LinkRequest (request %v), node %d not found", m.Request.Hdr().ID, m.In.OldNode)
+}
+
+type renameNewDirNodeNotFound struct {
+ Request *fuse.Header
+ In *fuse.RenameRequest
+}
+
+func (m *renameNewDirNodeNotFound) String() string {
+ return fmt.Sprintf("In RenameRequest (request %v), node %d not found", m.Request.Hdr().ID, m.In.NewDir)
+}
+
+type handlerPanickedError struct {
+ Request interface{}
+ Err interface{}
+}
+
+var _ error = handlerPanickedError{}
+
+func (h handlerPanickedError) Error() string {
+ return fmt.Sprintf("handler panicked: %v", h.Err)
+}
+
+var _ fuse.ErrorNumber = handlerPanickedError{}
+
+func (h handlerPanickedError) Errno() fuse.Errno {
+ if err, ok := h.Err.(fuse.ErrorNumber); ok {
+ return err.Errno()
+ }
+ return fuse.DefaultErrno
+}
+
+// handlerTerminatedError happens when a handler terminates itself
+// with runtime.Goexit. This is most commonly because of incorrect use
+// of testing.TB.FailNow, typically via t.Fatal.
+type handlerTerminatedError struct {
+ Request interface{}
+}
+
+var _ error = handlerTerminatedError{}
+
+func (h handlerTerminatedError) Error() string {
+ return fmt.Sprintf("handler terminated (called runtime.Goexit)")
+}
+
+var _ fuse.ErrorNumber = handlerTerminatedError{}
+
+func (h handlerTerminatedError) Errno() fuse.Errno {
+ return fuse.DefaultErrno
+}
+
+type handleNotReaderError struct {
+ handle Handle
+}
+
+var _ error = handleNotReaderError{}
+
+func (e handleNotReaderError) Error() string {
+ return fmt.Sprintf("handle has no Read: %T", e.handle)
+}
+
+var _ fuse.ErrorNumber = handleNotReaderError{}
+
+func (e handleNotReaderError) Errno() fuse.Errno {
+ return fuse.ENOTSUP
+}
+
+func initLookupResponse(s *fuse.LookupResponse) {
+ s.EntryValid = entryValidTime
+}
+
+func (c *Server) serve(r fuse.Request) {
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+ parentCtx := ctx
+ if c.context != nil {
+ ctx = c.context(ctx, r)
+ }
+
+ req := &serveRequest{Request: r, cancel: cancel}
+
+ c.debug(request{
+ Op: opName(r),
+ Request: r.Hdr(),
+ In: r,
+ })
+ var node Node
+ var snode *serveNode
+ c.meta.Lock()
+ hdr := r.Hdr()
+ if id := hdr.Node; id != 0 {
+ if id < fuse.NodeID(len(c.node)) {
+ snode = c.node[uint(id)]
+ }
+ if snode == nil {
+ c.meta.Unlock()
+ c.debug(response{
+ Op: opName(r),
+ Request: logResponseHeader{ID: hdr.ID},
+ Error: fuse.ESTALE.ErrnoName(),
+ // this is the only place that sets both Error and
+ // Out; not sure if i want to do that; might get rid
+ // of len(c.node) things altogether
+ Out: logMissingNode{
+ MaxNode: fuse.NodeID(len(c.node)),
+ },
+ })
+ r.RespondError(fuse.ESTALE)
+ return
+ }
+ node = snode.node
+ }
+ if c.req[hdr.ID] != nil {
+ // This happens with OSXFUSE. Assume it's okay and
+ // that we'll never see an interrupt for this one.
+ // Otherwise everything wedges. TODO: Report to OSXFUSE?
+ //
+ // TODO this might have been because of missing done() calls
+ } else {
+ c.req[hdr.ID] = req
+ }
+ c.meta.Unlock()
+
+ // Call this before responding.
+ // After responding is too late: we might get another request
+ // with the same ID and be very confused.
+ done := func(resp interface{}) {
+ msg := response{
+ Op: opName(r),
+ Request: logResponseHeader{ID: hdr.ID},
+ }
+ if err, ok := resp.(error); ok {
+ msg.Error = err.Error()
+ if ferr, ok := err.(fuse.ErrorNumber); ok {
+ errno := ferr.Errno()
+ msg.Errno = errno.ErrnoName()
+ if errno == err {
+ // it's just a fuse.Errno with no extra detail;
+ // skip the textual message for log readability
+ msg.Error = ""
+ }
+ } else {
+ msg.Errno = fuse.DefaultErrno.ErrnoName()
+ }
+ } else {
+ msg.Out = resp
+ }
+ c.debug(msg)
+
+ c.meta.Lock()
+ delete(c.req, hdr.ID)
+ c.meta.Unlock()
+ }
+
+ var responded bool
+ defer func() {
+ if rec := recover(); rec != nil {
+ const size = 1 << 16
+ buf := make([]byte, size)
+ n := runtime.Stack(buf, false)
+ buf = buf[:n]
+ log.Printf("fuse: panic in handler for %v: %v\n%s", r, rec, buf)
+ err := handlerPanickedError{
+ Request: r,
+ Err: rec,
+ }
+ done(err)
+ r.RespondError(err)
+ return
+ }
+
+ if !responded {
+ err := handlerTerminatedError{
+ Request: r,
+ }
+ done(err)
+ r.RespondError(err)
+ }
+ }()
+
+ if err := c.handleRequest(ctx, node, snode, r, done); err != nil {
+ if err == context.Canceled {
+ select {
+ case <-parentCtx.Done():
+ // We canceled the parent context because of an
+ // incoming interrupt request, so return EINTR
+ // to trigger the right behavior in the client app.
+ //
+ // Only do this when it's the parent context that was
+ // canceled, not a context controlled by the program
+ // using this library, so we don't return EINTR too
+ // eagerly -- it might cause busy loops.
+ //
+ // Decent write-up on role of EINTR:
+ // http://250bpm.com/blog:12
+ err = fuse.EINTR
+ default:
+ // nothing
+ }
+ }
+ done(err)
+ r.RespondError(err)
+ }
+
+ // disarm runtime.Goexit protection
+ responded = true
+}
+
+// handleRequest will either a) call done(s) and r.Respond(s) OR b) return an error.
+func (c *Server) handleRequest(ctx context.Context, node Node, snode *serveNode, r fuse.Request, done func(resp interface{})) error {
+ switch r := r.(type) {
+ default:
+ // Note: To FUSE, ENOSYS means "this server never implements this request."
+ // It would be inappropriate to return ENOSYS for other operations in this
+ // switch that might only be unavailable in some contexts, not all.
+ return fuse.ENOSYS
+
+ case *fuse.StatfsRequest:
+ s := &fuse.StatfsResponse{}
+ if fs, ok := c.fs.(FSStatfser); ok {
+ if err := fs.Statfs(ctx, r, s); err != nil {
+ return err
+ }
+ }
+ done(s)
+ r.Respond(s)
+ return nil
+
+ // Node operations.
+ case *fuse.GetattrRequest:
+ s := &fuse.GetattrResponse{}
+ if n, ok := node.(NodeGetattrer); ok {
+ if err := n.Getattr(ctx, r, s); err != nil {
+ return err
+ }
+ } else {
+ if err := snode.attr(ctx, &s.Attr); err != nil {
+ return err
+ }
+ }
+ done(s)
+ r.Respond(s)
+ return nil
+
+ case *fuse.SetattrRequest:
+ s := &fuse.SetattrResponse{}
+ if n, ok := node.(NodeSetattrer); ok {
+ if err := n.Setattr(ctx, r, s); err != nil {
+ return err
+ }
+ }
+
+ if err := snode.attr(ctx, &s.Attr); err != nil {
+ return err
+ }
+ done(s)
+ r.Respond(s)
+ return nil
+
+ case *fuse.SymlinkRequest:
+ s := &fuse.SymlinkResponse{}
+ initLookupResponse(&s.LookupResponse)
+ n, ok := node.(NodeSymlinker)
+ if !ok {
+ return fuse.EIO // XXX or EPERM like Mkdir?
+ }
+ n2, err := n.Symlink(ctx, r)
+ if err != nil {
+ return err
+ }
+ if err := c.saveLookup(ctx, &s.LookupResponse, snode, r.NewName, n2); err != nil {
+ return err
+ }
+ done(s)
+ r.Respond(s)
+ return nil
+
+ case *fuse.ReadlinkRequest:
+ n, ok := node.(NodeReadlinker)
+ if !ok {
+ return fuse.EIO /// XXX or EPERM?
+ }
+ target, err := n.Readlink(ctx, r)
+ if err != nil {
+ return err
+ }
+ done(target)
+ r.Respond(target)
+ return nil
+
+ case *fuse.LinkRequest:
+ n, ok := node.(NodeLinker)
+ if !ok {
+ return fuse.EIO /// XXX or EPERM?
+ }
+ c.meta.Lock()
+ var oldNode *serveNode
+ if int(r.OldNode) < len(c.node) {
+ oldNode = c.node[r.OldNode]
+ }
+ c.meta.Unlock()
+ if oldNode == nil {
+ c.debug(logLinkRequestOldNodeNotFound{
+ Request: r.Hdr(),
+ In: r,
+ })
+ return fuse.EIO
+ }
+ n2, err := n.Link(ctx, r, oldNode.node)
+ if err != nil {
+ return err
+ }
+ s := &fuse.LookupResponse{}
+ initLookupResponse(s)
+ if err := c.saveLookup(ctx, s, snode, r.NewName, n2); err != nil {
+ return err
+ }
+ done(s)
+ r.Respond(s)
+ return nil
+
+ case *fuse.RemoveRequest:
+ n, ok := node.(NodeRemover)
+ if !ok {
+ return fuse.EIO /// XXX or EPERM?
+ }
+ err := n.Remove(ctx, r)
+ if err != nil {
+ return err
+ }
+ done(nil)
+ r.Respond()
+ return nil
+
+ case *fuse.AccessRequest:
+ if n, ok := node.(NodeAccesser); ok {
+ if err := n.Access(ctx, r); err != nil {
+ return err
+ }
+ }
+ done(nil)
+ r.Respond()
+ return nil
+
+ case *fuse.LookupRequest:
+ var n2 Node
+ var err error
+ s := &fuse.LookupResponse{}
+ initLookupResponse(s)
+ if n, ok := node.(NodeStringLookuper); ok {
+ n2, err = n.Lookup(ctx, r.Name)
+ } else if n, ok := node.(NodeRequestLookuper); ok {
+ n2, err = n.Lookup(ctx, r, s)
+ } else {
+ return fuse.ENOENT
+ }
+ if err != nil {
+ return err
+ }
+ if err := c.saveLookup(ctx, s, snode, r.Name, n2); err != nil {
+ return err
+ }
+ done(s)
+ r.Respond(s)
+ return nil
+
+ case *fuse.MkdirRequest:
+ s := &fuse.MkdirResponse{}
+ initLookupResponse(&s.LookupResponse)
+ n, ok := node.(NodeMkdirer)
+ if !ok {
+ return fuse.EPERM
+ }
+ n2, err := n.Mkdir(ctx, r)
+ if err != nil {
+ return err
+ }
+ if err := c.saveLookup(ctx, &s.LookupResponse, snode, r.Name, n2); err != nil {
+ return err
+ }
+ done(s)
+ r.Respond(s)
+ return nil
+
+ case *fuse.OpenRequest:
+ s := &fuse.OpenResponse{}
+ var h2 Handle
+ if n, ok := node.(NodeOpener); ok {
+ hh, err := n.Open(ctx, r, s)
+ if err != nil {
+ return err
+ }
+ h2 = hh
+ } else {
+ h2 = node
+ }
+ s.Handle = c.saveHandle(h2, r.Hdr().Node)
+ done(s)
+ r.Respond(s)
+ return nil
+
+ case *fuse.CreateRequest:
+ n, ok := node.(NodeCreater)
+ if !ok {
+ // If we send back ENOSYS, FUSE will try mknod+open.
+ return fuse.EPERM
+ }
+ s := &fuse.CreateResponse{OpenResponse: fuse.OpenResponse{}}
+ initLookupResponse(&s.LookupResponse)
+ n2, h2, err := n.Create(ctx, r, s)
+ if err != nil {
+ return err
+ }
+ if err := c.saveLookup(ctx, &s.LookupResponse, snode, r.Name, n2); err != nil {
+ return err
+ }
+ s.Handle = c.saveHandle(h2, r.Hdr().Node)
+ done(s)
+ r.Respond(s)
+ return nil
+
+ case *fuse.GetxattrRequest:
+ n, ok := node.(NodeGetxattrer)
+ if !ok {
+ return fuse.ENOTSUP
+ }
+ s := &fuse.GetxattrResponse{}
+ err := n.Getxattr(ctx, r, s)
+ if err != nil {
+ return err
+ }
+ if r.Size != 0 && uint64(len(s.Xattr)) > uint64(r.Size) {
+ return fuse.ERANGE
+ }
+ done(s)
+ r.Respond(s)
+ return nil
+
+ case *fuse.ListxattrRequest:
+ n, ok := node.(NodeListxattrer)
+ if !ok {
+ return fuse.ENOTSUP
+ }
+ s := &fuse.ListxattrResponse{}
+ err := n.Listxattr(ctx, r, s)
+ if err != nil {
+ return err
+ }
+ if r.Size != 0 && uint64(len(s.Xattr)) > uint64(r.Size) {
+ return fuse.ERANGE
+ }
+ done(s)
+ r.Respond(s)
+ return nil
+
+ case *fuse.SetxattrRequest:
+ n, ok := node.(NodeSetxattrer)
+ if !ok {
+ return fuse.ENOTSUP
+ }
+ err := n.Setxattr(ctx, r)
+ if err != nil {
+ return err
+ }
+ done(nil)
+ r.Respond()
+ return nil
+
+ case *fuse.RemovexattrRequest:
+ n, ok := node.(NodeRemovexattrer)
+ if !ok {
+ return fuse.ENOTSUP
+ }
+ err := n.Removexattr(ctx, r)
+ if err != nil {
+ return err
+ }
+ done(nil)
+ r.Respond()
+ return nil
+
+ case *fuse.ForgetRequest:
+ forget := c.dropNode(r.Hdr().Node, r.N)
+ if forget {
+ n, ok := node.(NodeForgetter)
+ if ok {
+ n.Forget()
+ }
+ }
+ done(nil)
+ r.Respond()
+ return nil
+
+ // Handle operations.
+ case *fuse.ReadRequest:
+ shandle := c.getHandle(r.Handle)
+ if shandle == nil {
+ return fuse.ESTALE
+ }
+ handle := shandle.handle
+
+ s := &fuse.ReadResponse{Data: make([]byte, 0, r.Size)}
+ if r.Dir {
+ if h, ok := handle.(HandleReadDirAller); ok {
+ // detect rewinddir(3) or similar seek and refresh
+ // contents
+ if r.Offset == 0 {
+ shandle.readData = nil
+ }
+
+ if shandle.readData == nil {
+ dirs, err := h.ReadDirAll(ctx)
+ if err != nil {
+ return err
+ }
+ var data []byte
+ for _, dir := range dirs {
+ if dir.Inode == 0 {
+ dir.Inode = c.dynamicInode(snode.inode, dir.Name)
+ }
+ data = fuse.AppendDirent(data, dir)
+ }
+ shandle.readData = data
+ }
+ fuseutil.HandleRead(r, s, shandle.readData)
+ done(s)
+ r.Respond(s)
+ return nil
+ }
+ } else {
+ if h, ok := handle.(HandleReadAller); ok {
+ if shandle.readData == nil {
+ data, err := h.ReadAll(ctx)
+ if err != nil {
+ return err
+ }
+ if data == nil {
+ data = []byte{}
+ }
+ shandle.readData = data
+ }
+ fuseutil.HandleRead(r, s, shandle.readData)
+ done(s)
+ r.Respond(s)
+ return nil
+ }
+ h, ok := handle.(HandleReader)
+ if !ok {
+ err := handleNotReaderError{handle: handle}
+ return err
+ }
+ if err := h.Read(ctx, r, s); err != nil {
+ return err
+ }
+ }
+ done(s)
+ r.Respond(s)
+ return nil
+
+ case *fuse.WriteRequest:
+ shandle := c.getHandle(r.Handle)
+ if shandle == nil {
+ return fuse.ESTALE
+ }
+
+ s := &fuse.WriteResponse{}
+ if h, ok := shandle.handle.(HandleWriter); ok {
+ if err := h.Write(ctx, r, s); err != nil {
+ return err
+ }
+ done(s)
+ r.Respond(s)
+ return nil
+ }
+ return fuse.EIO
+
+ case *fuse.FlushRequest:
+ shandle := c.getHandle(r.Handle)
+ if shandle == nil {
+ return fuse.ESTALE
+ }
+ handle := shandle.handle
+
+ if h, ok := handle.(HandleFlusher); ok {
+ if err := h.Flush(ctx, r); err != nil {
+ return err
+ }
+ }
+ done(nil)
+ r.Respond()
+ return nil
+
+ case *fuse.ReleaseRequest:
+ shandle := c.getHandle(r.Handle)
+ if shandle == nil {
+ return fuse.ESTALE
+ }
+ handle := shandle.handle
+
+ // No matter what, release the handle.
+ c.dropHandle(r.Handle)
+
+ if h, ok := handle.(HandleReleaser); ok {
+ if err := h.Release(ctx, r); err != nil {
+ return err
+ }
+ }
+ done(nil)
+ r.Respond()
+ return nil
+
+ case *fuse.DestroyRequest:
+ if fs, ok := c.fs.(FSDestroyer); ok {
+ fs.Destroy()
+ }
+ done(nil)
+ r.Respond()
+ return nil
+
+ case *fuse.RenameRequest:
+ c.meta.Lock()
+ var newDirNode *serveNode
+ if int(r.NewDir) < len(c.node) {
+ newDirNode = c.node[r.NewDir]
+ }
+ c.meta.Unlock()
+ if newDirNode == nil {
+ c.debug(renameNewDirNodeNotFound{
+ Request: r.Hdr(),
+ In: r,
+ })
+ return fuse.EIO
+ }
+ n, ok := node.(NodeRenamer)
+ if !ok {
+ return fuse.EIO // XXX or EPERM like Mkdir?
+ }
+ err := n.Rename(ctx, r, newDirNode.node)
+ if err != nil {
+ return err
+ }
+ done(nil)
+ r.Respond()
+ return nil
+
+ case *fuse.MknodRequest:
+ n, ok := node.(NodeMknoder)
+ if !ok {
+ return fuse.EIO
+ }
+ n2, err := n.Mknod(ctx, r)
+ if err != nil {
+ return err
+ }
+ s := &fuse.LookupResponse{}
+ initLookupResponse(s)
+ if err := c.saveLookup(ctx, s, snode, r.Name, n2); err != nil {
+ return err
+ }
+ done(s)
+ r.Respond(s)
+ return nil
+
+ case *fuse.FsyncRequest:
+ n, ok := node.(NodeFsyncer)
+ if !ok {
+ return fuse.EIO
+ }
+ err := n.Fsync(ctx, r)
+ if err != nil {
+ return err
+ }
+ done(nil)
+ r.Respond()
+ return nil
+
+ case *fuse.InterruptRequest:
+ c.meta.Lock()
+ ireq := c.req[r.IntrID]
+ if ireq != nil && ireq.cancel != nil {
+ ireq.cancel()
+ ireq.cancel = nil
+ }
+ c.meta.Unlock()
+ done(nil)
+ r.Respond()
+ return nil
+
+ /* case *FsyncdirRequest:
+ return ENOSYS
+
+ case *GetlkRequest, *SetlkRequest, *SetlkwRequest:
+ return ENOSYS
+
+ case *BmapRequest:
+ return ENOSYS
+
+ case *SetvolnameRequest, *GetxtimesRequest, *ExchangeRequest:
+ return ENOSYS
+ */
+ }
+
+ panic("not reached")
+}
+
+func (c *Server) saveLookup(ctx context.Context, s *fuse.LookupResponse, snode *serveNode, elem string, n2 Node) error {
+ if err := nodeAttr(ctx, n2, &s.Attr); err != nil {
+ return err
+ }
+ if s.Attr.Inode == 0 {
+ s.Attr.Inode = c.dynamicInode(snode.inode, elem)
+ }
+
+ s.Node, s.Generation = c.saveNode(s.Attr.Inode, n2)
+ return nil
+}
+
+type invalidateNodeDetail struct {
+ Off int64
+ Size int64
+}
+
+func (i invalidateNodeDetail) String() string {
+ return fmt.Sprintf("Off:%d Size:%d", i.Off, i.Size)
+}
+
+func errstr(err error) string {
+ if err == nil {
+ return ""
+ }
+ return err.Error()
+}
+
+func (s *Server) invalidateNode(node Node, off int64, size int64) error {
+ s.meta.Lock()
+ id, ok := s.nodeRef[node]
+ if ok {
+ snode := s.node[id]
+ snode.wg.Add(1)
+ defer snode.wg.Done()
+ }
+ s.meta.Unlock()
+ if !ok {
+ // This is what the kernel would have said, if we had been
+ // able to send this message; it's not cached.
+ return fuse.ErrNotCached
+ }
+ // Delay logging until after we can record the error too. We
+ // consider a /dev/fuse write to be instantaneous enough to not
+ // need separate before and after messages.
+ err := s.conn.InvalidateNode(id, off, size)
+ s.debug(notification{
+ Op: "InvalidateNode",
+ Node: id,
+ Out: invalidateNodeDetail{
+ Off: off,
+ Size: size,
+ },
+ Err: errstr(err),
+ })
+ return err
+}
+
+// InvalidateNodeAttr invalidates the kernel cache of the attributes
+// of node.
+//
+// Returns fuse.ErrNotCached if the kernel is not currently caching
+// the node.
+func (s *Server) InvalidateNodeAttr(node Node) error {
+ return s.invalidateNode(node, 0, 0)
+}
+
+// InvalidateNodeData invalidates the kernel cache of the attributes
+// and data of node.
+//
+// Returns fuse.ErrNotCached if the kernel is not currently caching
+// the node.
+func (s *Server) InvalidateNodeData(node Node) error {
+ return s.invalidateNode(node, 0, -1)
+}
+
+// InvalidateNodeDataRange invalidates the kernel cache of the
+// attributes and a range of the data of node.
+//
+// Returns fuse.ErrNotCached if the kernel is not currently caching
+// the node.
+func (s *Server) InvalidateNodeDataRange(node Node, off int64, size int64) error {
+ return s.invalidateNode(node, off, size)
+}
+
+type invalidateEntryDetail struct {
+ Name string
+}
+
+func (i invalidateEntryDetail) String() string {
+ return fmt.Sprintf("%q", i.Name)
+}
+
+// InvalidateEntry invalidates the kernel cache of the directory entry
+// identified by parent node and entry basename.
+//
+// Kernel may or may not cache directory listings. To invalidate
+// those, use InvalidateNode to invalidate all of the data for a
+// directory. (As of 2015-06, Linux FUSE does not cache directory
+// listings.)
+//
+// Returns ErrNotCached if the kernel is not currently caching the
+// node.
+func (s *Server) InvalidateEntry(parent Node, name string) error {
+ s.meta.Lock()
+ id, ok := s.nodeRef[parent]
+ if ok {
+ snode := s.node[id]
+ snode.wg.Add(1)
+ defer snode.wg.Done()
+ }
+ s.meta.Unlock()
+ if !ok {
+ // This is what the kernel would have said, if we had been
+ // able to send this message; it's not cached.
+ return fuse.ErrNotCached
+ }
+ err := s.conn.InvalidateEntry(id, name)
+ s.debug(notification{
+ Op: "InvalidateEntry",
+ Node: id,
+ Out: invalidateEntryDetail{
+ Name: name,
+ },
+ Err: errstr(err),
+ })
+ return err
+}
+
+// DataHandle returns a read-only Handle that satisfies reads
+// using the given data.
+func DataHandle(data []byte) Handle {
+ return &dataHandle{data}
+}
+
+type dataHandle struct {
+ data []byte
+}
+
+func (d *dataHandle) ReadAll(ctx context.Context) ([]byte, error) {
+ return d.data, nil
+}
+
+// GenerateDynamicInode returns a dynamic inode.
+//
+// The parent inode and current entry name are used as the criteria
+// for choosing a pseudorandom inode. This makes it likely the same
+// entry will get the same inode on multiple runs.
+func GenerateDynamicInode(parent uint64, name string) uint64 {
+ h := fnv.New64a()
+ var buf [8]byte
+ binary.LittleEndian.PutUint64(buf[:], parent)
+ _, _ = h.Write(buf[:])
+ _, _ = h.Write([]byte(name))
+ var inode uint64
+ for {
+ inode = h.Sum64()
+ if inode != 0 {
+ break
+ }
+ // there's a tiny probability that result is zero; change the
+ // input a little and try again
+ _, _ = h.Write([]byte{'x'})
+ }
+ return inode
+}
diff --git a/vendor/bazil.org/fuse/fs/tree.go b/vendor/bazil.org/fuse/fs/tree.go
new file mode 100644
index 0000000000..7e078045a5
--- /dev/null
+++ b/vendor/bazil.org/fuse/fs/tree.go
@@ -0,0 +1,99 @@
+// FUSE directory tree, for servers that wish to use it with the service loop.
+
+package fs
+
+import (
+ "os"
+ pathpkg "path"
+ "strings"
+
+ "golang.org/x/net/context"
+)
+
+import (
+ "bazil.org/fuse"
+)
+
+// A Tree implements a basic read-only directory tree for FUSE.
+// The Nodes contained in it may still be writable.
+type Tree struct {
+ tree
+}
+
+func (t *Tree) Root() (Node, error) {
+ return &t.tree, nil
+}
+
+// Add adds the path to the tree, resolving to the given node.
+// If path or a prefix of path has already been added to the tree,
+// Add panics.
+//
+// Add is only safe to call before starting to serve requests.
+func (t *Tree) Add(path string, node Node) {
+ path = pathpkg.Clean("/" + path)[1:]
+ elems := strings.Split(path, "/")
+ dir := Node(&t.tree)
+ for i, elem := range elems {
+ dt, ok := dir.(*tree)
+ if !ok {
+ panic("fuse: Tree.Add for " + strings.Join(elems[:i], "/") + " and " + path)
+ }
+ n := dt.lookup(elem)
+ if n != nil {
+ if i+1 == len(elems) {
+ panic("fuse: Tree.Add for " + path + " conflicts with " + elem)
+ }
+ dir = n
+ } else {
+ if i+1 == len(elems) {
+ dt.add(elem, node)
+ } else {
+ dir = &tree{}
+ dt.add(elem, dir)
+ }
+ }
+ }
+}
+
+type treeDir struct {
+ name string
+ node Node
+}
+
+type tree struct {
+ dir []treeDir
+}
+
+func (t *tree) lookup(name string) Node {
+ for _, d := range t.dir {
+ if d.name == name {
+ return d.node
+ }
+ }
+ return nil
+}
+
+func (t *tree) add(name string, n Node) {
+ t.dir = append(t.dir, treeDir{name, n})
+}
+
+func (t *tree) Attr(ctx context.Context, a *fuse.Attr) error {
+ a.Mode = os.ModeDir | 0555
+ return nil
+}
+
+func (t *tree) Lookup(ctx context.Context, name string) (Node, error) {
+ n := t.lookup(name)
+ if n != nil {
+ return n, nil
+ }
+ return nil, fuse.ENOENT
+}
+
+func (t *tree) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) {
+ var out []fuse.Dirent
+ for _, d := range t.dir {
+ out = append(out, fuse.Dirent{Name: d.name})
+ }
+ return out, nil
+}
diff --git a/vendor/bazil.org/fuse/fuse.go b/vendor/bazil.org/fuse/fuse.go
new file mode 100644
index 0000000000..6db0ef2935
--- /dev/null
+++ b/vendor/bazil.org/fuse/fuse.go
@@ -0,0 +1,2303 @@
+// See the file LICENSE for copyright and licensing information.
+
+// Adapted from Plan 9 from User Space's src/cmd/9pfuse/fuse.c,
+// which carries this notice:
+//
+// The files in this directory are subject to the following license.
+//
+// The author of this software is Russ Cox.
+//
+// Copyright (c) 2006 Russ Cox
+//
+// Permission to use, copy, modify, and distribute this software for any
+// purpose without fee is hereby granted, provided that this entire notice
+// is included in all copies of any software which is or includes a copy
+// or modification of this software and in all copies of the supporting
+// documentation for such software.
+//
+// THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+// WARRANTY. IN PARTICULAR, THE AUTHOR MAKES NO REPRESENTATION OR WARRANTY
+// OF ANY KIND CONCERNING THE MERCHANTABILITY OF THIS SOFTWARE OR ITS
+// FITNESS FOR ANY PARTICULAR PURPOSE.
+
+// Package fuse enables writing FUSE file systems on Linux, OS X, and FreeBSD.
+//
+// On OS X, it requires OSXFUSE (http://osxfuse.github.com/).
+//
+// There are two approaches to writing a FUSE file system. The first is to speak
+// the low-level message protocol, reading from a Conn using ReadRequest and
+// writing using the various Respond methods. This approach is closest to
+// the actual interaction with the kernel and can be the simplest one in contexts
+// such as protocol translators.
+//
+// Servers of synthesized file systems tend to share common
+// bookkeeping abstracted away by the second approach, which is to
+// call fs.Serve to serve the FUSE protocol using an implementation of
+// the service methods in the interfaces FS* (file system), Node* (file
+// or directory), and Handle* (opened file or directory).
+// There are a daunting number of such methods that can be written,
+// but few are required.
+// The specific methods are described in the documentation for those interfaces.
+//
+// The hellofs subdirectory contains a simple illustration of the fs.Serve approach.
+//
+// Service Methods
+//
+// The required and optional methods for the FS, Node, and Handle interfaces
+// have the general form
+//
+// Op(ctx context.Context, req *OpRequest, resp *OpResponse) error
+//
+// where Op is the name of a FUSE operation. Op reads request
+// parameters from req and writes results to resp. An operation whose
+// only result is the error result omits the resp parameter.
+//
+// Multiple goroutines may call service methods simultaneously; the
+// methods being called are responsible for appropriate
+// synchronization.
+//
+// The operation must not hold on to the request or response,
+// including any []byte fields such as WriteRequest.Data or
+// SetxattrRequest.Xattr.
+//
+// Errors
+//
+// Operations can return errors. The FUSE interface can only
+// communicate POSIX errno error numbers to file system clients, the
+// message is not visible to file system clients. The returned error
+// can implement ErrorNumber to control the errno returned. Without
+// ErrorNumber, a generic errno (EIO) is returned.
+//
+// Error messages will be visible in the debug log as part of the
+// response.
+//
+// Interrupted Operations
+//
+// In some file systems, some operations
+// may take an undetermined amount of time. For example, a Read waiting for
+// a network message or a matching Write might wait indefinitely. If the request
+// is cancelled and no longer needed, the context will be cancelled.
+// Blocking operations should select on a receive from ctx.Done() and attempt to
+// abort the operation early if the receive succeeds (meaning the channel is closed).
+// To indicate that the operation failed because it was aborted, return fuse.EINTR.
+//
+// If an operation does not block for an indefinite amount of time, supporting
+// cancellation is not necessary.
+//
+// Authentication
+//
+// All requests types embed a Header, meaning that the method can
+// inspect req.Pid, req.Uid, and req.Gid as necessary to implement
+// permission checking. The kernel FUSE layer normally prevents other
+// users from accessing the FUSE file system (to change this, see
+// AllowOther, AllowRoot), but does not enforce access modes (to
+// change this, see DefaultPermissions).
+//
+// Mount Options
+//
+// Behavior and metadata of the mounted file system can be changed by
+// passing MountOption values to Mount.
+//
+package fuse // import "bazil.org/fuse"
+
+import (
+ "bytes"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "io"
+ "os"
+ "sync"
+ "syscall"
+ "time"
+ "unsafe"
+)
+
+// A Conn represents a connection to a mounted FUSE file system.
+type Conn struct {
+ // Ready is closed when the mount is complete or has failed.
+ Ready <-chan struct{}
+
+ // MountError stores any error from the mount process. Only valid
+ // after Ready is closed.
+ MountError error
+
+ // File handle for kernel communication. Only safe to access if
+ // rio or wio is held.
+ dev *os.File
+ wio sync.RWMutex
+ rio sync.RWMutex
+
+ // Protocol version negotiated with InitRequest/InitResponse.
+ proto Protocol
+}
+
+// MountpointDoesNotExistError is an error returned when the
+// mountpoint does not exist.
+type MountpointDoesNotExistError struct {
+ Path string
+}
+
+var _ error = (*MountpointDoesNotExistError)(nil)
+
+func (e *MountpointDoesNotExistError) Error() string {
+ return fmt.Sprintf("mountpoint does not exist: %v", e.Path)
+}
+
+// Mount mounts a new FUSE connection on the named directory
+// and returns a connection for reading and writing FUSE messages.
+//
+// After a successful return, caller must call Close to free
+// resources.
+//
+// Even on successful return, the new mount is not guaranteed to be
+// visible until after Conn.Ready is closed. See Conn.MountError for
+// possible errors. Incoming requests on Conn must be served to make
+// progress.
+func Mount(dir string, options ...MountOption) (*Conn, error) {
+ conf := mountConfig{
+ options: make(map[string]string),
+ }
+ for _, option := range options {
+ if err := option(&conf); err != nil {
+ return nil, err
+ }
+ }
+
+ ready := make(chan struct{}, 1)
+ c := &Conn{
+ Ready: ready,
+ }
+ f, err := mount(dir, &conf, ready, &c.MountError)
+ if err != nil {
+ return nil, err
+ }
+ c.dev = f
+
+ if err := initMount(c, &conf); err != nil {
+ c.Close()
+ if err == ErrClosedWithoutInit {
+ // see if we can provide a better error
+ <-c.Ready
+ if err := c.MountError; err != nil {
+ return nil, err
+ }
+ }
+ return nil, err
+ }
+
+ return c, nil
+}
+
+type OldVersionError struct {
+ Kernel Protocol
+ LibraryMin Protocol
+}
+
+func (e *OldVersionError) Error() string {
+ return fmt.Sprintf("kernel FUSE version is too old: %v < %v", e.Kernel, e.LibraryMin)
+}
+
+var (
+ ErrClosedWithoutInit = errors.New("fuse connection closed without init")
+)
+
+func initMount(c *Conn, conf *mountConfig) error {
+ req, err := c.ReadRequest()
+ if err != nil {
+ if err == io.EOF {
+ return ErrClosedWithoutInit
+ }
+ return err
+ }
+ r, ok := req.(*InitRequest)
+ if !ok {
+ return fmt.Errorf("missing init, got: %T", req)
+ }
+
+ min := Protocol{protoVersionMinMajor, protoVersionMinMinor}
+ if r.Kernel.LT(min) {
+ req.RespondError(Errno(syscall.EPROTO))
+ c.Close()
+ return &OldVersionError{
+ Kernel: r.Kernel,
+ LibraryMin: min,
+ }
+ }
+
+ proto := Protocol{protoVersionMaxMajor, protoVersionMaxMinor}
+ if r.Kernel.LT(proto) {
+ // Kernel doesn't support the latest version we have.
+ proto = r.Kernel
+ }
+ c.proto = proto
+
+ s := &InitResponse{
+ Library: proto,
+ MaxReadahead: conf.maxReadahead,
+ MaxWrite: maxWrite,
+ Flags: InitBigWrites | conf.initFlags,
+ }
+ r.Respond(s)
+ return nil
+}
+
+// A Request represents a single FUSE request received from the kernel.
+// Use a type switch to determine the specific kind.
+// A request of unrecognized type will have concrete type *Header.
+type Request interface {
+ // Hdr returns the Header associated with this request.
+ Hdr() *Header
+
+ // RespondError responds to the request with the given error.
+ RespondError(error)
+
+ String() string
+}
+
+// A RequestID identifies an active FUSE request.
+type RequestID uint64
+
+func (r RequestID) String() string {
+ return fmt.Sprintf("%#x", uint64(r))
+}
+
+// A NodeID is a number identifying a directory or file.
+// It must be unique among IDs returned in LookupResponses
+// that have not yet been forgotten by ForgetRequests.
+type NodeID uint64
+
+func (n NodeID) String() string {
+ return fmt.Sprintf("%#x", uint64(n))
+}
+
+// A HandleID is a number identifying an open directory or file.
+// It only needs to be unique while the directory or file is open.
+type HandleID uint64
+
+func (h HandleID) String() string {
+ return fmt.Sprintf("%#x", uint64(h))
+}
+
+// The RootID identifies the root directory of a FUSE file system.
+const RootID NodeID = rootID
+
+// A Header describes the basic information sent in every request.
+type Header struct {
+ Conn *Conn `json:"-"` // connection this request was received on
+ ID RequestID // unique ID for request
+ Node NodeID // file or directory the request is about
+ Uid uint32 // user ID of process making request
+ Gid uint32 // group ID of process making request
+ Pid uint32 // process ID of process making request
+
+ // for returning to reqPool
+ msg *message
+}
+
+func (h *Header) String() string {
+ return fmt.Sprintf("ID=%v Node=%v Uid=%d Gid=%d Pid=%d", h.ID, h.Node, h.Uid, h.Gid, h.Pid)
+}
+
+func (h *Header) Hdr() *Header {
+ return h
+}
+
+func (h *Header) noResponse() {
+ putMessage(h.msg)
+}
+
+func (h *Header) respond(msg []byte) {
+ out := (*outHeader)(unsafe.Pointer(&msg[0]))
+ out.Unique = uint64(h.ID)
+ h.Conn.respond(msg)
+ putMessage(h.msg)
+}
+
+// An ErrorNumber is an error with a specific error number.
+//
+// Operations may return an error value that implements ErrorNumber to
+// control what specific error number (errno) to return.
+type ErrorNumber interface {
+ // Errno returns the the error number (errno) for this error.
+ Errno() Errno
+}
+
+const (
+ // ENOSYS indicates that the call is not supported.
+ ENOSYS = Errno(syscall.ENOSYS)
+
+ // ESTALE is used by Serve to respond to violations of the FUSE protocol.
+ ESTALE = Errno(syscall.ESTALE)
+
+ ENOENT = Errno(syscall.ENOENT)
+ EIO = Errno(syscall.EIO)
+ EPERM = Errno(syscall.EPERM)
+
+ // EINTR indicates request was interrupted by an InterruptRequest.
+ // See also fs.Intr.
+ EINTR = Errno(syscall.EINTR)
+
+ ERANGE = Errno(syscall.ERANGE)
+ ENOTSUP = Errno(syscall.ENOTSUP)
+ EEXIST = Errno(syscall.EEXIST)
+)
+
+// DefaultErrno is the errno used when error returned does not
+// implement ErrorNumber.
+const DefaultErrno = EIO
+
+var errnoNames = map[Errno]string{
+ ENOSYS: "ENOSYS",
+ ESTALE: "ESTALE",
+ ENOENT: "ENOENT",
+ EIO: "EIO",
+ EPERM: "EPERM",
+ EINTR: "EINTR",
+ EEXIST: "EEXIST",
+}
+
+// Errno implements Error and ErrorNumber using a syscall.Errno.
+type Errno syscall.Errno
+
+var _ = ErrorNumber(Errno(0))
+var _ = error(Errno(0))
+
+func (e Errno) Errno() Errno {
+ return e
+}
+
+func (e Errno) String() string {
+ return syscall.Errno(e).Error()
+}
+
+func (e Errno) Error() string {
+ return syscall.Errno(e).Error()
+}
+
+// ErrnoName returns the short non-numeric identifier for this errno.
+// For example, "EIO".
+func (e Errno) ErrnoName() string {
+ s := errnoNames[e]
+ if s == "" {
+ s = fmt.Sprint(e.Errno())
+ }
+ return s
+}
+
+func (e Errno) MarshalText() ([]byte, error) {
+ s := e.ErrnoName()
+ return []byte(s), nil
+}
+
+func (h *Header) RespondError(err error) {
+ errno := DefaultErrno
+ if ferr, ok := err.(ErrorNumber); ok {
+ errno = ferr.Errno()
+ }
+ // FUSE uses negative errors!
+ // TODO: File bug report against OSXFUSE: positive error causes kernel panic.
+ buf := newBuffer(0)
+ hOut := (*outHeader)(unsafe.Pointer(&buf[0]))
+ hOut.Error = -int32(errno)
+ h.respond(buf)
+}
+
+// All requests read from the kernel, without data, are shorter than
+// this.
+var maxRequestSize = syscall.Getpagesize()
+var bufSize = maxRequestSize + maxWrite
+
+// reqPool is a pool of messages.
+//
+// Lifetime of a logical message is from getMessage to putMessage.
+// getMessage is called by ReadRequest. putMessage is called by
+// Conn.ReadRequest, Request.Respond, or Request.RespondError.
+//
+// Messages in the pool are guaranteed to have conn and off zeroed,
+// buf allocated and len==bufSize, and hdr set.
+var reqPool = sync.Pool{
+ New: allocMessage,
+}
+
+func allocMessage() interface{} {
+ m := &message{buf: make([]byte, bufSize)}
+ m.hdr = (*inHeader)(unsafe.Pointer(&m.buf[0]))
+ return m
+}
+
+func getMessage(c *Conn) *message {
+ m := reqPool.Get().(*message)
+ m.conn = c
+ return m
+}
+
+func putMessage(m *message) {
+ m.buf = m.buf[:bufSize]
+ m.conn = nil
+ m.off = 0
+ reqPool.Put(m)
+}
+
+// a message represents the bytes of a single FUSE message
+type message struct {
+ conn *Conn
+ buf []byte // all bytes
+ hdr *inHeader // header
+ off int // offset for reading additional fields
+}
+
+func (m *message) len() uintptr {
+ return uintptr(len(m.buf) - m.off)
+}
+
+func (m *message) data() unsafe.Pointer {
+ var p unsafe.Pointer
+ if m.off < len(m.buf) {
+ p = unsafe.Pointer(&m.buf[m.off])
+ }
+ return p
+}
+
+func (m *message) bytes() []byte {
+ return m.buf[m.off:]
+}
+
+func (m *message) Header() Header {
+ h := m.hdr
+ return Header{
+ Conn: m.conn,
+ ID: RequestID(h.Unique),
+ Node: NodeID(h.Nodeid),
+ Uid: h.Uid,
+ Gid: h.Gid,
+ Pid: h.Pid,
+
+ msg: m,
+ }
+}
+
+// fileMode returns a Go os.FileMode from a Unix mode.
+func fileMode(unixMode uint32) os.FileMode {
+ mode := os.FileMode(unixMode & 0777)
+ switch unixMode & syscall.S_IFMT {
+ case syscall.S_IFREG:
+ // nothing
+ case syscall.S_IFDIR:
+ mode |= os.ModeDir
+ case syscall.S_IFCHR:
+ mode |= os.ModeCharDevice | os.ModeDevice
+ case syscall.S_IFBLK:
+ mode |= os.ModeDevice
+ case syscall.S_IFIFO:
+ mode |= os.ModeNamedPipe
+ case syscall.S_IFLNK:
+ mode |= os.ModeSymlink
+ case syscall.S_IFSOCK:
+ mode |= os.ModeSocket
+ default:
+ // no idea
+ mode |= os.ModeDevice
+ }
+ if unixMode&syscall.S_ISUID != 0 {
+ mode |= os.ModeSetuid
+ }
+ if unixMode&syscall.S_ISGID != 0 {
+ mode |= os.ModeSetgid
+ }
+ return mode
+}
+
+type noOpcode struct {
+ Opcode uint32
+}
+
+func (m noOpcode) String() string {
+ return fmt.Sprintf("No opcode %v", m.Opcode)
+}
+
+type malformedMessage struct {
+}
+
+func (malformedMessage) String() string {
+ return "malformed message"
+}
+
+// Close closes the FUSE connection.
+func (c *Conn) Close() error {
+ c.wio.Lock()
+ defer c.wio.Unlock()
+ c.rio.Lock()
+ defer c.rio.Unlock()
+ return c.dev.Close()
+}
+
+// caller must hold wio or rio
+func (c *Conn) fd() int {
+ return int(c.dev.Fd())
+}
+
+func (c *Conn) Protocol() Protocol {
+ return c.proto
+}
+
+// ReadRequest returns the next FUSE request from the kernel.
+//
+// Caller must call either Request.Respond or Request.RespondError in
+// a reasonable time. Caller must not retain Request after that call.
+func (c *Conn) ReadRequest() (Request, error) {
+ m := getMessage(c)
+loop:
+ c.rio.RLock()
+ n, err := syscall.Read(c.fd(), m.buf)
+ c.rio.RUnlock()
+ if err == syscall.EINTR {
+ // OSXFUSE sends EINTR to userspace when a request interrupt
+ // completed before it got sent to userspace?
+ goto loop
+ }
+ if err != nil && err != syscall.ENODEV {
+ putMessage(m)
+ return nil, err
+ }
+ if n <= 0 {
+ putMessage(m)
+ return nil, io.EOF
+ }
+ m.buf = m.buf[:n]
+
+ if n < inHeaderSize {
+ putMessage(m)
+ return nil, errors.New("fuse: message too short")
+ }
+
+ // FreeBSD FUSE sends a short length in the header
+ // for FUSE_INIT even though the actual read length is correct.
+ if n == inHeaderSize+initInSize && m.hdr.Opcode == opInit && m.hdr.Len < uint32(n) {
+ m.hdr.Len = uint32(n)
+ }
+
+ // OSXFUSE sometimes sends the wrong m.hdr.Len in a FUSE_WRITE message.
+ if m.hdr.Len < uint32(n) && m.hdr.Len >= uint32(unsafe.Sizeof(writeIn{})) && m.hdr.Opcode == opWrite {
+ m.hdr.Len = uint32(n)
+ }
+
+ if m.hdr.Len != uint32(n) {
+ // prepare error message before returning m to pool
+ err := fmt.Errorf("fuse: read %d opcode %d but expected %d", n, m.hdr.Opcode, m.hdr.Len)
+ putMessage(m)
+ return nil, err
+ }
+
+ m.off = inHeaderSize
+
+ // Convert to data structures.
+ // Do not trust kernel to hand us well-formed data.
+ var req Request
+ switch m.hdr.Opcode {
+ default:
+ Debug(noOpcode{Opcode: m.hdr.Opcode})
+ goto unrecognized
+
+ case opLookup:
+ buf := m.bytes()
+ n := len(buf)
+ if n == 0 || buf[n-1] != '\x00' {
+ goto corrupt
+ }
+ req = &LookupRequest{
+ Header: m.Header(),
+ Name: string(buf[:n-1]),
+ }
+
+ case opForget:
+ in := (*forgetIn)(m.data())
+ if m.len() < unsafe.Sizeof(*in) {
+ goto corrupt
+ }
+ req = &ForgetRequest{
+ Header: m.Header(),
+ N: in.Nlookup,
+ }
+
+ case opGetattr:
+ switch {
+ case c.proto.LT(Protocol{7, 9}):
+ req = &GetattrRequest{
+ Header: m.Header(),
+ }
+
+ default:
+ in := (*getattrIn)(m.data())
+ if m.len() < unsafe.Sizeof(*in) {
+ goto corrupt
+ }
+ req = &GetattrRequest{
+ Header: m.Header(),
+ Flags: GetattrFlags(in.GetattrFlags),
+ Handle: HandleID(in.Fh),
+ }
+ }
+
+ case opSetattr:
+ in := (*setattrIn)(m.data())
+ if m.len() < unsafe.Sizeof(*in) {
+ goto corrupt
+ }
+ req = &SetattrRequest{
+ Header: m.Header(),
+ Valid: SetattrValid(in.Valid),
+ Handle: HandleID(in.Fh),
+ Size: in.Size,
+ Atime: time.Unix(int64(in.Atime), int64(in.AtimeNsec)),
+ Mtime: time.Unix(int64(in.Mtime), int64(in.MtimeNsec)),
+ Mode: fileMode(in.Mode),
+ Uid: in.Uid,
+ Gid: in.Gid,
+ Bkuptime: in.BkupTime(),
+ Chgtime: in.Chgtime(),
+ Flags: in.Flags(),
+ }
+
+ case opReadlink:
+ if len(m.bytes()) > 0 {
+ goto corrupt
+ }
+ req = &ReadlinkRequest{
+ Header: m.Header(),
+ }
+
+ case opSymlink:
+ // m.bytes() is "newName\0target\0"
+ names := m.bytes()
+ if len(names) == 0 || names[len(names)-1] != 0 {
+ goto corrupt
+ }
+ i := bytes.IndexByte(names, '\x00')
+ if i < 0 {
+ goto corrupt
+ }
+ newName, target := names[0:i], names[i+1:len(names)-1]
+ req = &SymlinkRequest{
+ Header: m.Header(),
+ NewName: string(newName),
+ Target: string(target),
+ }
+
+ case opLink:
+ in := (*linkIn)(m.data())
+ if m.len() < unsafe.Sizeof(*in) {
+ goto corrupt
+ }
+ newName := m.bytes()[unsafe.Sizeof(*in):]
+ if len(newName) < 2 || newName[len(newName)-1] != 0 {
+ goto corrupt
+ }
+ newName = newName[:len(newName)-1]
+ req = &LinkRequest{
+ Header: m.Header(),
+ OldNode: NodeID(in.Oldnodeid),
+ NewName: string(newName),
+ }
+
+ case opMknod:
+ size := mknodInSize(c.proto)
+ if m.len() < size {
+ goto corrupt
+ }
+ in := (*mknodIn)(m.data())
+ name := m.bytes()[size:]
+ if len(name) < 2 || name[len(name)-1] != '\x00' {
+ goto corrupt
+ }
+ name = name[:len(name)-1]
+ r := &MknodRequest{
+ Header: m.Header(),
+ Mode: fileMode(in.Mode),
+ Rdev: in.Rdev,
+ Name: string(name),
+ }
+ if c.proto.GE(Protocol{7, 12}) {
+ r.Umask = fileMode(in.Umask) & os.ModePerm
+ }
+ req = r
+
+ case opMkdir:
+ size := mkdirInSize(c.proto)
+ if m.len() < size {
+ goto corrupt
+ }
+ in := (*mkdirIn)(m.data())
+ name := m.bytes()[size:]
+ i := bytes.IndexByte(name, '\x00')
+ if i < 0 {
+ goto corrupt
+ }
+ r := &MkdirRequest{
+ Header: m.Header(),
+ Name: string(name[:i]),
+ // observed on Linux: mkdirIn.Mode & syscall.S_IFMT == 0,
+ // and this causes fileMode to go into it's "no idea"
+ // code branch; enforce type to directory
+ Mode: fileMode((in.Mode &^ syscall.S_IFMT) | syscall.S_IFDIR),
+ }
+ if c.proto.GE(Protocol{7, 12}) {
+ r.Umask = fileMode(in.Umask) & os.ModePerm
+ }
+ req = r
+
+ case opUnlink, opRmdir:
+ buf := m.bytes()
+ n := len(buf)
+ if n == 0 || buf[n-1] != '\x00' {
+ goto corrupt
+ }
+ req = &RemoveRequest{
+ Header: m.Header(),
+ Name: string(buf[:n-1]),
+ Dir: m.hdr.Opcode == opRmdir,
+ }
+
+ case opRename:
+ in := (*renameIn)(m.data())
+ if m.len() < unsafe.Sizeof(*in) {
+ goto corrupt
+ }
+ newDirNodeID := NodeID(in.Newdir)
+ oldNew := m.bytes()[unsafe.Sizeof(*in):]
+ // oldNew should be "old\x00new\x00"
+ if len(oldNew) < 4 {
+ goto corrupt
+ }
+ if oldNew[len(oldNew)-1] != '\x00' {
+ goto corrupt
+ }
+ i := bytes.IndexByte(oldNew, '\x00')
+ if i < 0 {
+ goto corrupt
+ }
+ oldName, newName := string(oldNew[:i]), string(oldNew[i+1:len(oldNew)-1])
+ req = &RenameRequest{
+ Header: m.Header(),
+ NewDir: newDirNodeID,
+ OldName: oldName,
+ NewName: newName,
+ }
+
+ case opOpendir, opOpen:
+ in := (*openIn)(m.data())
+ if m.len() < unsafe.Sizeof(*in) {
+ goto corrupt
+ }
+ req = &OpenRequest{
+ Header: m.Header(),
+ Dir: m.hdr.Opcode == opOpendir,
+ Flags: openFlags(in.Flags),
+ }
+
+ case opRead, opReaddir:
+ in := (*readIn)(m.data())
+ if m.len() < readInSize(c.proto) {
+ goto corrupt
+ }
+ r := &ReadRequest{
+ Header: m.Header(),
+ Dir: m.hdr.Opcode == opReaddir,
+ Handle: HandleID(in.Fh),
+ Offset: int64(in.Offset),
+ Size: int(in.Size),
+ }
+ if c.proto.GE(Protocol{7, 9}) {
+ r.Flags = ReadFlags(in.ReadFlags)
+ r.LockOwner = in.LockOwner
+ r.FileFlags = openFlags(in.Flags)
+ }
+ req = r
+
+ case opWrite:
+ in := (*writeIn)(m.data())
+ if m.len() < writeInSize(c.proto) {
+ goto corrupt
+ }
+ r := &WriteRequest{
+ Header: m.Header(),
+ Handle: HandleID(in.Fh),
+ Offset: int64(in.Offset),
+ Flags: WriteFlags(in.WriteFlags),
+ }
+ if c.proto.GE(Protocol{7, 9}) {
+ r.LockOwner = in.LockOwner
+ r.FileFlags = openFlags(in.Flags)
+ }
+ buf := m.bytes()[writeInSize(c.proto):]
+ if uint32(len(buf)) < in.Size {
+ goto corrupt
+ }
+ r.Data = buf
+ req = r
+
+ case opStatfs:
+ req = &StatfsRequest{
+ Header: m.Header(),
+ }
+
+ case opRelease, opReleasedir:
+ in := (*releaseIn)(m.data())
+ if m.len() < unsafe.Sizeof(*in) {
+ goto corrupt
+ }
+ req = &ReleaseRequest{
+ Header: m.Header(),
+ Dir: m.hdr.Opcode == opReleasedir,
+ Handle: HandleID(in.Fh),
+ Flags: openFlags(in.Flags),
+ ReleaseFlags: ReleaseFlags(in.ReleaseFlags),
+ LockOwner: in.LockOwner,
+ }
+
+ case opFsync, opFsyncdir:
+ in := (*fsyncIn)(m.data())
+ if m.len() < unsafe.Sizeof(*in) {
+ goto corrupt
+ }
+ req = &FsyncRequest{
+ Dir: m.hdr.Opcode == opFsyncdir,
+ Header: m.Header(),
+ Handle: HandleID(in.Fh),
+ Flags: in.FsyncFlags,
+ }
+
+ case opSetxattr:
+ in := (*setxattrIn)(m.data())
+ if m.len() < unsafe.Sizeof(*in) {
+ goto corrupt
+ }
+ m.off += int(unsafe.Sizeof(*in))
+ name := m.bytes()
+ i := bytes.IndexByte(name, '\x00')
+ if i < 0 {
+ goto corrupt
+ }
+ xattr := name[i+1:]
+ if uint32(len(xattr)) < in.Size {
+ goto corrupt
+ }
+ xattr = xattr[:in.Size]
+ req = &SetxattrRequest{
+ Header: m.Header(),
+ Flags: in.Flags,
+ Position: in.position(),
+ Name: string(name[:i]),
+ Xattr: xattr,
+ }
+
+ case opGetxattr:
+ in := (*getxattrIn)(m.data())
+ if m.len() < unsafe.Sizeof(*in) {
+ goto corrupt
+ }
+ name := m.bytes()[unsafe.Sizeof(*in):]
+ i := bytes.IndexByte(name, '\x00')
+ if i < 0 {
+ goto corrupt
+ }
+ req = &GetxattrRequest{
+ Header: m.Header(),
+ Name: string(name[:i]),
+ Size: in.Size,
+ Position: in.position(),
+ }
+
+ case opListxattr:
+ in := (*getxattrIn)(m.data())
+ if m.len() < unsafe.Sizeof(*in) {
+ goto corrupt
+ }
+ req = &ListxattrRequest{
+ Header: m.Header(),
+ Size: in.Size,
+ Position: in.position(),
+ }
+
+ case opRemovexattr:
+ buf := m.bytes()
+ n := len(buf)
+ if n == 0 || buf[n-1] != '\x00' {
+ goto corrupt
+ }
+ req = &RemovexattrRequest{
+ Header: m.Header(),
+ Name: string(buf[:n-1]),
+ }
+
+ case opFlush:
+ in := (*flushIn)(m.data())
+ if m.len() < unsafe.Sizeof(*in) {
+ goto corrupt
+ }
+ req = &FlushRequest{
+ Header: m.Header(),
+ Handle: HandleID(in.Fh),
+ Flags: in.FlushFlags,
+ LockOwner: in.LockOwner,
+ }
+
+ case opInit:
+ in := (*initIn)(m.data())
+ if m.len() < unsafe.Sizeof(*in) {
+ goto corrupt
+ }
+ req = &InitRequest{
+ Header: m.Header(),
+ Kernel: Protocol{in.Major, in.Minor},
+ MaxReadahead: in.MaxReadahead,
+ Flags: InitFlags(in.Flags),
+ }
+
+ case opGetlk:
+ panic("opGetlk")
+ case opSetlk:
+ panic("opSetlk")
+ case opSetlkw:
+ panic("opSetlkw")
+
+ case opAccess:
+ in := (*accessIn)(m.data())
+ if m.len() < unsafe.Sizeof(*in) {
+ goto corrupt
+ }
+ req = &AccessRequest{
+ Header: m.Header(),
+ Mask: in.Mask,
+ }
+
+ case opCreate:
+ size := createInSize(c.proto)
+ if m.len() < size {
+ goto corrupt
+ }
+ in := (*createIn)(m.data())
+ name := m.bytes()[size:]
+ i := bytes.IndexByte(name, '\x00')
+ if i < 0 {
+ goto corrupt
+ }
+ r := &CreateRequest{
+ Header: m.Header(),
+ Flags: openFlags(in.Flags),
+ Mode: fileMode(in.Mode),
+ Name: string(name[:i]),
+ }
+ if c.proto.GE(Protocol{7, 12}) {
+ r.Umask = fileMode(in.Umask) & os.ModePerm
+ }
+ req = r
+
+ case opInterrupt:
+ in := (*interruptIn)(m.data())
+ if m.len() < unsafe.Sizeof(*in) {
+ goto corrupt
+ }
+ req = &InterruptRequest{
+ Header: m.Header(),
+ IntrID: RequestID(in.Unique),
+ }
+
+ case opBmap:
+ panic("opBmap")
+
+ case opDestroy:
+ req = &DestroyRequest{
+ Header: m.Header(),
+ }
+
+ // OS X
+ case opSetvolname:
+ panic("opSetvolname")
+ case opGetxtimes:
+ panic("opGetxtimes")
+ case opExchange:
+ in := (*exchangeIn)(m.data())
+ if m.len() < unsafe.Sizeof(*in) {
+ goto corrupt
+ }
+ oldDirNodeID := NodeID(in.Olddir)
+ newDirNodeID := NodeID(in.Newdir)
+ oldNew := m.bytes()[unsafe.Sizeof(*in):]
+ // oldNew should be "oldname\x00newname\x00"
+ if len(oldNew) < 4 {
+ goto corrupt
+ }
+ if oldNew[len(oldNew)-1] != '\x00' {
+ goto corrupt
+ }
+ i := bytes.IndexByte(oldNew, '\x00')
+ if i < 0 {
+ goto corrupt
+ }
+ oldName, newName := string(oldNew[:i]), string(oldNew[i+1:len(oldNew)-1])
+ req = &ExchangeDataRequest{
+ Header: m.Header(),
+ OldDir: oldDirNodeID,
+ NewDir: newDirNodeID,
+ OldName: oldName,
+ NewName: newName,
+ // TODO options
+ }
+ }
+
+ return req, nil
+
+corrupt:
+ Debug(malformedMessage{})
+ putMessage(m)
+ return nil, fmt.Errorf("fuse: malformed message")
+
+unrecognized:
+ // Unrecognized message.
+ // Assume higher-level code will send a "no idea what you mean" error.
+ h := m.Header()
+ return &h, nil
+}
+
+type bugShortKernelWrite struct {
+ Written int64
+ Length int64
+ Error string
+ Stack string
+}
+
+func (b bugShortKernelWrite) String() string {
+ return fmt.Sprintf("short kernel write: written=%d/%d error=%q stack=\n%s", b.Written, b.Length, b.Error, b.Stack)
+}
+
+type bugKernelWriteError struct {
+ Error string
+ Stack string
+}
+
+func (b bugKernelWriteError) String() string {
+ return fmt.Sprintf("kernel write error: error=%q stack=\n%s", b.Error, b.Stack)
+}
+
+// safe to call even with nil error
+func errorString(err error) string {
+ if err == nil {
+ return ""
+ }
+ return err.Error()
+}
+
+func (c *Conn) writeToKernel(msg []byte) error {
+ out := (*outHeader)(unsafe.Pointer(&msg[0]))
+ out.Len = uint32(len(msg))
+
+ c.wio.RLock()
+ defer c.wio.RUnlock()
+ nn, err := syscall.Write(c.fd(), msg)
+ if err == nil && nn != len(msg) {
+ Debug(bugShortKernelWrite{
+ Written: int64(nn),
+ Length: int64(len(msg)),
+ Error: errorString(err),
+ Stack: stack(),
+ })
+ }
+ return err
+}
+
+func (c *Conn) respond(msg []byte) {
+ if err := c.writeToKernel(msg); err != nil {
+ Debug(bugKernelWriteError{
+ Error: errorString(err),
+ Stack: stack(),
+ })
+ }
+}
+
+type notCachedError struct{}
+
+func (notCachedError) Error() string {
+ return "node not cached"
+}
+
+var _ ErrorNumber = notCachedError{}
+
+func (notCachedError) Errno() Errno {
+ // Behave just like if the original syscall.ENOENT had been passed
+ // straight through.
+ return ENOENT
+}
+
+var (
+ ErrNotCached = notCachedError{}
+)
+
+// sendInvalidate sends an invalidate notification to kernel.
+//
+// A returned ENOENT is translated to a friendlier error.
+func (c *Conn) sendInvalidate(msg []byte) error {
+ switch err := c.writeToKernel(msg); err {
+ case syscall.ENOENT:
+ return ErrNotCached
+ default:
+ return err
+ }
+}
+
+// InvalidateNode invalidates the kernel cache of the attributes and a
+// range of the data of a node.
+//
+// Giving offset 0 and size -1 means all data. To invalidate just the
+// attributes, give offset 0 and size 0.
+//
+// Returns ErrNotCached if the kernel is not currently caching the
+// node.
+func (c *Conn) InvalidateNode(nodeID NodeID, off int64, size int64) error {
+ buf := newBuffer(unsafe.Sizeof(notifyInvalInodeOut{}))
+ h := (*outHeader)(unsafe.Pointer(&buf[0]))
+ // h.Unique is 0
+ h.Error = notifyCodeInvalInode
+ out := (*notifyInvalInodeOut)(buf.alloc(unsafe.Sizeof(notifyInvalInodeOut{})))
+ out.Ino = uint64(nodeID)
+ out.Off = off
+ out.Len = size
+ return c.sendInvalidate(buf)
+}
+
+// InvalidateEntry invalidates the kernel cache of the directory entry
+// identified by parent directory node ID and entry basename.
+//
+// Kernel may or may not cache directory listings. To invalidate
+// those, use InvalidateNode to invalidate all of the data for a
+// directory. (As of 2015-06, Linux FUSE does not cache directory
+// listings.)
+//
+// Returns ErrNotCached if the kernel is not currently caching the
+// node.
+func (c *Conn) InvalidateEntry(parent NodeID, name string) error {
+ const maxUint32 = ^uint32(0)
+ if uint64(len(name)) > uint64(maxUint32) {
+ // very unlikely, but we don't want to silently truncate
+ return syscall.ENAMETOOLONG
+ }
+ buf := newBuffer(unsafe.Sizeof(notifyInvalEntryOut{}) + uintptr(len(name)) + 1)
+ h := (*outHeader)(unsafe.Pointer(&buf[0]))
+ // h.Unique is 0
+ h.Error = notifyCodeInvalEntry
+ out := (*notifyInvalEntryOut)(buf.alloc(unsafe.Sizeof(notifyInvalEntryOut{})))
+ out.Parent = uint64(parent)
+ out.Namelen = uint32(len(name))
+ buf = append(buf, name...)
+ buf = append(buf, '\x00')
+ return c.sendInvalidate(buf)
+}
+
+// An InitRequest is the first request sent on a FUSE file system.
+type InitRequest struct {
+ Header `json:"-"`
+ Kernel Protocol
+ // Maximum readahead in bytes that the kernel plans to use.
+ MaxReadahead uint32
+ Flags InitFlags
+}
+
+var _ = Request(&InitRequest{})
+
+func (r *InitRequest) String() string {
+ return fmt.Sprintf("Init [%v] %v ra=%d fl=%v", &r.Header, r.Kernel, r.MaxReadahead, r.Flags)
+}
+
+// An InitResponse is the response to an InitRequest.
+type InitResponse struct {
+ Library Protocol
+ // Maximum readahead in bytes that the kernel can use. Ignored if
+ // greater than InitRequest.MaxReadahead.
+ MaxReadahead uint32
+ Flags InitFlags
+ // Maximum size of a single write operation.
+ // Linux enforces a minimum of 4 KiB.
+ MaxWrite uint32
+}
+
+func (r *InitResponse) String() string {
+ return fmt.Sprintf("Init %v ra=%d fl=%v w=%d", r.Library, r.MaxReadahead, r.Flags, r.MaxWrite)
+}
+
+// Respond replies to the request with the given response.
+func (r *InitRequest) Respond(resp *InitResponse) {
+ buf := newBuffer(unsafe.Sizeof(initOut{}))
+ out := (*initOut)(buf.alloc(unsafe.Sizeof(initOut{})))
+ out.Major = resp.Library.Major
+ out.Minor = resp.Library.Minor
+ out.MaxReadahead = resp.MaxReadahead
+ out.Flags = uint32(resp.Flags)
+ out.MaxWrite = resp.MaxWrite
+
+ // MaxWrite larger than our receive buffer would just lead to
+ // errors on large writes.
+ if out.MaxWrite > maxWrite {
+ out.MaxWrite = maxWrite
+ }
+ r.respond(buf)
+}
+
+// A StatfsRequest requests information about the mounted file system.
+type StatfsRequest struct {
+ Header `json:"-"`
+}
+
+var _ = Request(&StatfsRequest{})
+
+func (r *StatfsRequest) String() string {
+ return fmt.Sprintf("Statfs [%s]", &r.Header)
+}
+
+// Respond replies to the request with the given response.
+func (r *StatfsRequest) Respond(resp *StatfsResponse) {
+ buf := newBuffer(unsafe.Sizeof(statfsOut{}))
+ out := (*statfsOut)(buf.alloc(unsafe.Sizeof(statfsOut{})))
+ out.St = kstatfs{
+ Blocks: resp.Blocks,
+ Bfree: resp.Bfree,
+ Bavail: resp.Bavail,
+ Files: resp.Files,
+ Bsize: resp.Bsize,
+ Namelen: resp.Namelen,
+ Frsize: resp.Frsize,
+ }
+ r.respond(buf)
+}
+
+// A StatfsResponse is the response to a StatfsRequest.
+type StatfsResponse struct {
+ Blocks uint64 // Total data blocks in file system.
+ Bfree uint64 // Free blocks in file system.
+ Bavail uint64 // Free blocks in file system if you're not root.
+ Files uint64 // Total files in file system.
+ Ffree uint64 // Free files in file system.
+ Bsize uint32 // Block size
+ Namelen uint32 // Maximum file name length?
+ Frsize uint32 // Fragment size, smallest addressable data size in the file system.
+}
+
+func (r *StatfsResponse) String() string {
+ return fmt.Sprintf("Statfs blocks=%d/%d/%d files=%d/%d bsize=%d frsize=%d namelen=%d",
+ r.Bavail, r.Bfree, r.Blocks,
+ r.Ffree, r.Files,
+ r.Bsize,
+ r.Frsize,
+ r.Namelen,
+ )
+}
+
+// An AccessRequest asks whether the file can be accessed
+// for the purpose specified by the mask.
+type AccessRequest struct {
+ Header `json:"-"`
+ Mask uint32
+}
+
+var _ = Request(&AccessRequest{})
+
+func (r *AccessRequest) String() string {
+ return fmt.Sprintf("Access [%s] mask=%#x", &r.Header, r.Mask)
+}
+
+// Respond replies to the request indicating that access is allowed.
+// To deny access, use RespondError.
+func (r *AccessRequest) Respond() {
+ buf := newBuffer(0)
+ r.respond(buf)
+}
+
+// An Attr is the metadata for a single file or directory.
+type Attr struct {
+ Valid time.Duration // how long Attr can be cached
+
+ Inode uint64 // inode number
+ Size uint64 // size in bytes
+ Blocks uint64 // size in 512-byte units
+ Atime time.Time // time of last access
+ Mtime time.Time // time of last modification
+ Ctime time.Time // time of last inode change
+ Crtime time.Time // time of creation (OS X only)
+ Mode os.FileMode // file mode
+ Nlink uint32 // number of links (usually 1)
+ Uid uint32 // owner uid
+ Gid uint32 // group gid
+ Rdev uint32 // device numbers
+ Flags uint32 // chflags(2) flags (OS X only)
+ BlockSize uint32 // preferred blocksize for filesystem I/O
+}
+
+func (a Attr) String() string {
+ return fmt.Sprintf("valid=%v ino=%v size=%d mode=%v", a.Valid, a.Inode, a.Size, a.Mode)
+}
+
+func unix(t time.Time) (sec uint64, nsec uint32) {
+ nano := t.UnixNano()
+ sec = uint64(nano / 1e9)
+ nsec = uint32(nano % 1e9)
+ return
+}
+
+func (a *Attr) attr(out *attr, proto Protocol) {
+ out.Ino = a.Inode
+ out.Size = a.Size
+ out.Blocks = a.Blocks
+ out.Atime, out.AtimeNsec = unix(a.Atime)
+ out.Mtime, out.MtimeNsec = unix(a.Mtime)
+ out.Ctime, out.CtimeNsec = unix(a.Ctime)
+ out.SetCrtime(unix(a.Crtime))
+ out.Mode = uint32(a.Mode) & 0777
+ switch {
+ default:
+ out.Mode |= syscall.S_IFREG
+ case a.Mode&os.ModeDir != 0:
+ out.Mode |= syscall.S_IFDIR
+ case a.Mode&os.ModeDevice != 0:
+ if a.Mode&os.ModeCharDevice != 0 {
+ out.Mode |= syscall.S_IFCHR
+ } else {
+ out.Mode |= syscall.S_IFBLK
+ }
+ case a.Mode&os.ModeNamedPipe != 0:
+ out.Mode |= syscall.S_IFIFO
+ case a.Mode&os.ModeSymlink != 0:
+ out.Mode |= syscall.S_IFLNK
+ case a.Mode&os.ModeSocket != 0:
+ out.Mode |= syscall.S_IFSOCK
+ }
+ if a.Mode&os.ModeSetuid != 0 {
+ out.Mode |= syscall.S_ISUID
+ }
+ if a.Mode&os.ModeSetgid != 0 {
+ out.Mode |= syscall.S_ISGID
+ }
+ out.Nlink = a.Nlink
+ out.Uid = a.Uid
+ out.Gid = a.Gid
+ out.Rdev = a.Rdev
+ out.SetFlags(a.Flags)
+ if proto.GE(Protocol{7, 9}) {
+ out.Blksize = a.BlockSize
+ }
+
+ return
+}
+
+// A GetattrRequest asks for the metadata for the file denoted by r.Node.
+type GetattrRequest struct {
+ Header `json:"-"`
+ Flags GetattrFlags
+ Handle HandleID
+}
+
+var _ = Request(&GetattrRequest{})
+
+func (r *GetattrRequest) String() string {
+ return fmt.Sprintf("Getattr [%s] %v fl=%v", &r.Header, r.Handle, r.Flags)
+}
+
+// Respond replies to the request with the given response.
+func (r *GetattrRequest) Respond(resp *GetattrResponse) {
+ size := attrOutSize(r.Header.Conn.proto)
+ buf := newBuffer(size)
+ out := (*attrOut)(buf.alloc(size))
+ out.AttrValid = uint64(resp.Attr.Valid / time.Second)
+ out.AttrValidNsec = uint32(resp.Attr.Valid % time.Second / time.Nanosecond)
+ resp.Attr.attr(&out.Attr, r.Header.Conn.proto)
+ r.respond(buf)
+}
+
+// A GetattrResponse is the response to a GetattrRequest.
+type GetattrResponse struct {
+ Attr Attr // file attributes
+}
+
+func (r *GetattrResponse) String() string {
+ return fmt.Sprintf("Getattr %v", r.Attr)
+}
+
+// A GetxattrRequest asks for the extended attributes associated with r.Node.
+type GetxattrRequest struct {
+ Header `json:"-"`
+
+ // Maximum size to return.
+ Size uint32
+
+ // Name of the attribute requested.
+ Name string
+
+ // Offset within extended attributes.
+ //
+ // Only valid for OS X, and then only with the resource fork
+ // attribute.
+ Position uint32
+}
+
+var _ = Request(&GetxattrRequest{})
+
+func (r *GetxattrRequest) String() string {
+ return fmt.Sprintf("Getxattr [%s] %q %d @%d", &r.Header, r.Name, r.Size, r.Position)
+}
+
+// Respond replies to the request with the given response.
+func (r *GetxattrRequest) Respond(resp *GetxattrResponse) {
+ if r.Size == 0 {
+ buf := newBuffer(unsafe.Sizeof(getxattrOut{}))
+ out := (*getxattrOut)(buf.alloc(unsafe.Sizeof(getxattrOut{})))
+ out.Size = uint32(len(resp.Xattr))
+ r.respond(buf)
+ } else {
+ buf := newBuffer(uintptr(len(resp.Xattr)))
+ buf = append(buf, resp.Xattr...)
+ r.respond(buf)
+ }
+}
+
+// A GetxattrResponse is the response to a GetxattrRequest.
+type GetxattrResponse struct {
+ Xattr []byte
+}
+
+func (r *GetxattrResponse) String() string {
+ return fmt.Sprintf("Getxattr %x", r.Xattr)
+}
+
+// A ListxattrRequest asks to list the extended attributes associated with r.Node.
+type ListxattrRequest struct {
+ Header `json:"-"`
+ Size uint32 // maximum size to return
+ Position uint32 // offset within attribute list
+}
+
+var _ = Request(&ListxattrRequest{})
+
+func (r *ListxattrRequest) String() string {
+ return fmt.Sprintf("Listxattr [%s] %d @%d", &r.Header, r.Size, r.Position)
+}
+
+// Respond replies to the request with the given response.
+func (r *ListxattrRequest) Respond(resp *ListxattrResponse) {
+ if r.Size == 0 {
+ buf := newBuffer(unsafe.Sizeof(getxattrOut{}))
+ out := (*getxattrOut)(buf.alloc(unsafe.Sizeof(getxattrOut{})))
+ out.Size = uint32(len(resp.Xattr))
+ r.respond(buf)
+ } else {
+ buf := newBuffer(uintptr(len(resp.Xattr)))
+ buf = append(buf, resp.Xattr...)
+ r.respond(buf)
+ }
+}
+
+// A ListxattrResponse is the response to a ListxattrRequest.
+type ListxattrResponse struct {
+ Xattr []byte
+}
+
+func (r *ListxattrResponse) String() string {
+ return fmt.Sprintf("Listxattr %x", r.Xattr)
+}
+
+// Append adds an extended attribute name to the response.
+func (r *ListxattrResponse) Append(names ...string) {
+ for _, name := range names {
+ r.Xattr = append(r.Xattr, name...)
+ r.Xattr = append(r.Xattr, '\x00')
+ }
+}
+
+// A RemovexattrRequest asks to remove an extended attribute associated with r.Node.
+type RemovexattrRequest struct {
+ Header `json:"-"`
+ Name string // name of extended attribute
+}
+
+var _ = Request(&RemovexattrRequest{})
+
+func (r *RemovexattrRequest) String() string {
+ return fmt.Sprintf("Removexattr [%s] %q", &r.Header, r.Name)
+}
+
+// Respond replies to the request, indicating that the attribute was removed.
+func (r *RemovexattrRequest) Respond() {
+ buf := newBuffer(0)
+ r.respond(buf)
+}
+
+// A SetxattrRequest asks to set an extended attribute associated with a file.
+type SetxattrRequest struct {
+ Header `json:"-"`
+
+ // Flags can make the request fail if attribute does/not already
+ // exist. Unfortunately, the constants are platform-specific and
+ // not exposed by Go1.2. Look for XATTR_CREATE, XATTR_REPLACE.
+ //
+ // TODO improve this later
+ //
+ // TODO XATTR_CREATE and exist -> EEXIST
+ //
+ // TODO XATTR_REPLACE and not exist -> ENODATA
+ Flags uint32
+
+ // Offset within extended attributes.
+ //
+ // Only valid for OS X, and then only with the resource fork
+ // attribute.
+ Position uint32
+
+ Name string
+ Xattr []byte
+}
+
+var _ = Request(&SetxattrRequest{})
+
+func trunc(b []byte, max int) ([]byte, string) {
+ if len(b) > max {
+ return b[:max], "..."
+ }
+ return b, ""
+}
+
+func (r *SetxattrRequest) String() string {
+ xattr, tail := trunc(r.Xattr, 16)
+ return fmt.Sprintf("Setxattr [%s] %q %x%s fl=%v @%#x", &r.Header, r.Name, xattr, tail, r.Flags, r.Position)
+}
+
+// Respond replies to the request, indicating that the extended attribute was set.
+func (r *SetxattrRequest) Respond() {
+ buf := newBuffer(0)
+ r.respond(buf)
+}
+
+// A LookupRequest asks to look up the given name in the directory named by r.Node.
+type LookupRequest struct {
+ Header `json:"-"`
+ Name string
+}
+
+var _ = Request(&LookupRequest{})
+
+func (r *LookupRequest) String() string {
+ return fmt.Sprintf("Lookup [%s] %q", &r.Header, r.Name)
+}
+
+// Respond replies to the request with the given response.
+func (r *LookupRequest) Respond(resp *LookupResponse) {
+ size := entryOutSize(r.Header.Conn.proto)
+ buf := newBuffer(size)
+ out := (*entryOut)(buf.alloc(size))
+ out.Nodeid = uint64(resp.Node)
+ out.Generation = resp.Generation
+ out.EntryValid = uint64(resp.EntryValid / time.Second)
+ out.EntryValidNsec = uint32(resp.EntryValid % time.Second / time.Nanosecond)
+ out.AttrValid = uint64(resp.Attr.Valid / time.Second)
+ out.AttrValidNsec = uint32(resp.Attr.Valid % time.Second / time.Nanosecond)
+ resp.Attr.attr(&out.Attr, r.Header.Conn.proto)
+ r.respond(buf)
+}
+
+// A LookupResponse is the response to a LookupRequest.
+type LookupResponse struct {
+ Node NodeID
+ Generation uint64
+ EntryValid time.Duration
+ Attr Attr
+}
+
+func (r *LookupResponse) string() string {
+ return fmt.Sprintf("%v gen=%d valid=%v attr={%v}", r.Node, r.Generation, r.EntryValid, r.Attr)
+}
+
+func (r *LookupResponse) String() string {
+ return fmt.Sprintf("Lookup %s", r.string())
+}
+
+// An OpenRequest asks to open a file or directory
+type OpenRequest struct {
+ Header `json:"-"`
+ Dir bool // is this Opendir?
+ Flags OpenFlags
+}
+
+var _ = Request(&OpenRequest{})
+
+func (r *OpenRequest) String() string {
+ return fmt.Sprintf("Open [%s] dir=%v fl=%v", &r.Header, r.Dir, r.Flags)
+}
+
+// Respond replies to the request with the given response.
+func (r *OpenRequest) Respond(resp *OpenResponse) {
+ buf := newBuffer(unsafe.Sizeof(openOut{}))
+ out := (*openOut)(buf.alloc(unsafe.Sizeof(openOut{})))
+ out.Fh = uint64(resp.Handle)
+ out.OpenFlags = uint32(resp.Flags)
+ r.respond(buf)
+}
+
+// A OpenResponse is the response to a OpenRequest.
+type OpenResponse struct {
+ Handle HandleID
+ Flags OpenResponseFlags
+}
+
+func (r *OpenResponse) string() string {
+ return fmt.Sprintf("%v fl=%v", r.Handle, r.Flags)
+}
+
+func (r *OpenResponse) String() string {
+ return fmt.Sprintf("Open %s", r.string())
+}
+
+// A CreateRequest asks to create and open a file (not a directory).
+type CreateRequest struct {
+ Header `json:"-"`
+ Name string
+ Flags OpenFlags
+ Mode os.FileMode
+ // Umask of the request. Not supported on OS X.
+ Umask os.FileMode
+}
+
+var _ = Request(&CreateRequest{})
+
+func (r *CreateRequest) String() string {
+ return fmt.Sprintf("Create [%s] %q fl=%v mode=%v umask=%v", &r.Header, r.Name, r.Flags, r.Mode, r.Umask)
+}
+
+// Respond replies to the request with the given response.
+func (r *CreateRequest) Respond(resp *CreateResponse) {
+ eSize := entryOutSize(r.Header.Conn.proto)
+ buf := newBuffer(eSize + unsafe.Sizeof(openOut{}))
+
+ e := (*entryOut)(buf.alloc(eSize))
+ e.Nodeid = uint64(resp.Node)
+ e.Generation = resp.Generation
+ e.EntryValid = uint64(resp.EntryValid / time.Second)
+ e.EntryValidNsec = uint32(resp.EntryValid % time.Second / time.Nanosecond)
+ e.AttrValid = uint64(resp.Attr.Valid / time.Second)
+ e.AttrValidNsec = uint32(resp.Attr.Valid % time.Second / time.Nanosecond)
+ resp.Attr.attr(&e.Attr, r.Header.Conn.proto)
+
+ o := (*openOut)(buf.alloc(unsafe.Sizeof(openOut{})))
+ o.Fh = uint64(resp.Handle)
+ o.OpenFlags = uint32(resp.Flags)
+
+ r.respond(buf)
+}
+
+// A CreateResponse is the response to a CreateRequest.
+// It describes the created node and opened handle.
+type CreateResponse struct {
+ LookupResponse
+ OpenResponse
+}
+
+func (r *CreateResponse) String() string {
+ return fmt.Sprintf("Create {%s} {%s}", r.LookupResponse.string(), r.OpenResponse.string())
+}
+
+// A MkdirRequest asks to create (but not open) a directory.
+type MkdirRequest struct {
+ Header `json:"-"`
+ Name string
+ Mode os.FileMode
+ // Umask of the request. Not supported on OS X.
+ Umask os.FileMode
+}
+
+var _ = Request(&MkdirRequest{})
+
+func (r *MkdirRequest) String() string {
+ return fmt.Sprintf("Mkdir [%s] %q mode=%v umask=%v", &r.Header, r.Name, r.Mode, r.Umask)
+}
+
+// Respond replies to the request with the given response.
+func (r *MkdirRequest) Respond(resp *MkdirResponse) {
+ size := entryOutSize(r.Header.Conn.proto)
+ buf := newBuffer(size)
+ out := (*entryOut)(buf.alloc(size))
+ out.Nodeid = uint64(resp.Node)
+ out.Generation = resp.Generation
+ out.EntryValid = uint64(resp.EntryValid / time.Second)
+ out.EntryValidNsec = uint32(resp.EntryValid % time.Second / time.Nanosecond)
+ out.AttrValid = uint64(resp.Attr.Valid / time.Second)
+ out.AttrValidNsec = uint32(resp.Attr.Valid % time.Second / time.Nanosecond)
+ resp.Attr.attr(&out.Attr, r.Header.Conn.proto)
+ r.respond(buf)
+}
+
+// A MkdirResponse is the response to a MkdirRequest.
+type MkdirResponse struct {
+ LookupResponse
+}
+
+func (r *MkdirResponse) String() string {
+ return fmt.Sprintf("Mkdir %v", r.LookupResponse.string())
+}
+
+// A ReadRequest asks to read from an open file.
+type ReadRequest struct {
+ Header `json:"-"`
+ Dir bool // is this Readdir?
+ Handle HandleID
+ Offset int64
+ Size int
+ Flags ReadFlags
+ LockOwner uint64
+ FileFlags OpenFlags
+}
+
+var _ = Request(&ReadRequest{})
+
+func (r *ReadRequest) String() string {
+ return fmt.Sprintf("Read [%s] %v %d @%#x dir=%v fl=%v lock=%d ffl=%v", &r.Header, r.Handle, r.Size, r.Offset, r.Dir, r.Flags, r.LockOwner, r.FileFlags)
+}
+
+// Respond replies to the request with the given response.
+func (r *ReadRequest) Respond(resp *ReadResponse) {
+ buf := newBuffer(uintptr(len(resp.Data)))
+ buf = append(buf, resp.Data...)
+ r.respond(buf)
+}
+
+// A ReadResponse is the response to a ReadRequest.
+type ReadResponse struct {
+ Data []byte
+}
+
+func (r *ReadResponse) String() string {
+ return fmt.Sprintf("Read %d", len(r.Data))
+}
+
+type jsonReadResponse struct {
+ Len uint64
+}
+
+func (r *ReadResponse) MarshalJSON() ([]byte, error) {
+ j := jsonReadResponse{
+ Len: uint64(len(r.Data)),
+ }
+ return json.Marshal(j)
+}
+
+// A ReleaseRequest asks to release (close) an open file handle.
+type ReleaseRequest struct {
+ Header `json:"-"`
+ Dir bool // is this Releasedir?
+ Handle HandleID
+ Flags OpenFlags // flags from OpenRequest
+ ReleaseFlags ReleaseFlags
+ LockOwner uint32
+}
+
+var _ = Request(&ReleaseRequest{})
+
+func (r *ReleaseRequest) String() string {
+ return fmt.Sprintf("Release [%s] %v fl=%v rfl=%v owner=%#x", &r.Header, r.Handle, r.Flags, r.ReleaseFlags, r.LockOwner)
+}
+
+// Respond replies to the request, indicating that the handle has been released.
+func (r *ReleaseRequest) Respond() {
+ buf := newBuffer(0)
+ r.respond(buf)
+}
+
+// A DestroyRequest is sent by the kernel when unmounting the file system.
+// No more requests will be received after this one, but it should still be
+// responded to.
+type DestroyRequest struct {
+ Header `json:"-"`
+}
+
+var _ = Request(&DestroyRequest{})
+
+func (r *DestroyRequest) String() string {
+ return fmt.Sprintf("Destroy [%s]", &r.Header)
+}
+
+// Respond replies to the request.
+func (r *DestroyRequest) Respond() {
+ buf := newBuffer(0)
+ r.respond(buf)
+}
+
+// A ForgetRequest is sent by the kernel when forgetting about r.Node
+// as returned by r.N lookup requests.
+type ForgetRequest struct {
+ Header `json:"-"`
+ N uint64
+}
+
+var _ = Request(&ForgetRequest{})
+
+func (r *ForgetRequest) String() string {
+ return fmt.Sprintf("Forget [%s] %d", &r.Header, r.N)
+}
+
+// Respond replies to the request, indicating that the forgetfulness has been recorded.
+func (r *ForgetRequest) Respond() {
+ // Don't reply to forget messages.
+ r.noResponse()
+}
+
+// A Dirent represents a single directory entry.
+type Dirent struct {
+ // Inode this entry names.
+ Inode uint64
+
+ // Type of the entry, for example DT_File.
+ //
+ // Setting this is optional. The zero value (DT_Unknown) means
+ // callers will just need to do a Getattr when the type is
+ // needed. Providing a type can speed up operations
+ // significantly.
+ Type DirentType
+
+ // Name of the entry
+ Name string
+}
+
+// Type of an entry in a directory listing.
+type DirentType uint32
+
+const (
+ // These don't quite match os.FileMode; especially there's an
+ // explicit unknown, instead of zero value meaning file. They
+ // are also not quite syscall.DT_*; nothing says the FUSE
+ // protocol follows those, and even if they were, we don't
+ // want each fs to fiddle with syscall.
+
+ // The shift by 12 is hardcoded in the FUSE userspace
+ // low-level C library, so it's safe here.
+
+ DT_Unknown DirentType = 0
+ DT_Socket DirentType = syscall.S_IFSOCK >> 12
+ DT_Link DirentType = syscall.S_IFLNK >> 12
+ DT_File DirentType = syscall.S_IFREG >> 12
+ DT_Block DirentType = syscall.S_IFBLK >> 12
+ DT_Dir DirentType = syscall.S_IFDIR >> 12
+ DT_Char DirentType = syscall.S_IFCHR >> 12
+ DT_FIFO DirentType = syscall.S_IFIFO >> 12
+)
+
+func (t DirentType) String() string {
+ switch t {
+ case DT_Unknown:
+ return "unknown"
+ case DT_Socket:
+ return "socket"
+ case DT_Link:
+ return "link"
+ case DT_File:
+ return "file"
+ case DT_Block:
+ return "block"
+ case DT_Dir:
+ return "dir"
+ case DT_Char:
+ return "char"
+ case DT_FIFO:
+ return "fifo"
+ }
+ return "invalid"
+}
+
+// AppendDirent appends the encoded form of a directory entry to data
+// and returns the resulting slice.
+func AppendDirent(data []byte, dir Dirent) []byte {
+ de := dirent{
+ Ino: dir.Inode,
+ Namelen: uint32(len(dir.Name)),
+ Type: uint32(dir.Type),
+ }
+ de.Off = uint64(len(data) + direntSize + (len(dir.Name)+7)&^7)
+ data = append(data, (*[direntSize]byte)(unsafe.Pointer(&de))[:]...)
+ data = append(data, dir.Name...)
+ n := direntSize + uintptr(len(dir.Name))
+ if n%8 != 0 {
+ var pad [8]byte
+ data = append(data, pad[:8-n%8]...)
+ }
+ return data
+}
+
+// A WriteRequest asks to write to an open file.
+type WriteRequest struct {
+ Header
+ Handle HandleID
+ Offset int64
+ Data []byte
+ Flags WriteFlags
+ LockOwner uint64
+ FileFlags OpenFlags
+}
+
+var _ = Request(&WriteRequest{})
+
+func (r *WriteRequest) String() string {
+ return fmt.Sprintf("Write [%s] %v %d @%d fl=%v lock=%d ffl=%v", &r.Header, r.Handle, len(r.Data), r.Offset, r.Flags, r.LockOwner, r.FileFlags)
+}
+
+type jsonWriteRequest struct {
+ Handle HandleID
+ Offset int64
+ Len uint64
+ Flags WriteFlags
+}
+
+func (r *WriteRequest) MarshalJSON() ([]byte, error) {
+ j := jsonWriteRequest{
+ Handle: r.Handle,
+ Offset: r.Offset,
+ Len: uint64(len(r.Data)),
+ Flags: r.Flags,
+ }
+ return json.Marshal(j)
+}
+
+// Respond replies to the request with the given response.
+func (r *WriteRequest) Respond(resp *WriteResponse) {
+ buf := newBuffer(unsafe.Sizeof(writeOut{}))
+ out := (*writeOut)(buf.alloc(unsafe.Sizeof(writeOut{})))
+ out.Size = uint32(resp.Size)
+ r.respond(buf)
+}
+
+// A WriteResponse replies to a write indicating how many bytes were written.
+type WriteResponse struct {
+ Size int
+}
+
+func (r *WriteResponse) String() string {
+ return fmt.Sprintf("Write %d", r.Size)
+}
+
+// A SetattrRequest asks to change one or more attributes associated with a file,
+// as indicated by Valid.
+type SetattrRequest struct {
+ Header `json:"-"`
+ Valid SetattrValid
+ Handle HandleID
+ Size uint64
+ Atime time.Time
+ Mtime time.Time
+ Mode os.FileMode
+ Uid uint32
+ Gid uint32
+
+ // OS X only
+ Bkuptime time.Time
+ Chgtime time.Time
+ Crtime time.Time
+ Flags uint32 // see chflags(2)
+}
+
+var _ = Request(&SetattrRequest{})
+
+func (r *SetattrRequest) String() string {
+ var buf bytes.Buffer
+ fmt.Fprintf(&buf, "Setattr [%s]", &r.Header)
+ if r.Valid.Mode() {
+ fmt.Fprintf(&buf, " mode=%v", r.Mode)
+ }
+ if r.Valid.Uid() {
+ fmt.Fprintf(&buf, " uid=%d", r.Uid)
+ }
+ if r.Valid.Gid() {
+ fmt.Fprintf(&buf, " gid=%d", r.Gid)
+ }
+ if r.Valid.Size() {
+ fmt.Fprintf(&buf, " size=%d", r.Size)
+ }
+ if r.Valid.Atime() {
+ fmt.Fprintf(&buf, " atime=%v", r.Atime)
+ }
+ if r.Valid.AtimeNow() {
+ fmt.Fprintf(&buf, " atime=now")
+ }
+ if r.Valid.Mtime() {
+ fmt.Fprintf(&buf, " mtime=%v", r.Mtime)
+ }
+ if r.Valid.MtimeNow() {
+ fmt.Fprintf(&buf, " mtime=now")
+ }
+ if r.Valid.Handle() {
+ fmt.Fprintf(&buf, " handle=%v", r.Handle)
+ } else {
+ fmt.Fprintf(&buf, " handle=INVALID-%v", r.Handle)
+ }
+ if r.Valid.LockOwner() {
+ fmt.Fprintf(&buf, " lockowner")
+ }
+ if r.Valid.Crtime() {
+ fmt.Fprintf(&buf, " crtime=%v", r.Crtime)
+ }
+ if r.Valid.Chgtime() {
+ fmt.Fprintf(&buf, " chgtime=%v", r.Chgtime)
+ }
+ if r.Valid.Bkuptime() {
+ fmt.Fprintf(&buf, " bkuptime=%v", r.Bkuptime)
+ }
+ if r.Valid.Flags() {
+ fmt.Fprintf(&buf, " flags=%v", r.Flags)
+ }
+ return buf.String()
+}
+
+// Respond replies to the request with the given response,
+// giving the updated attributes.
+func (r *SetattrRequest) Respond(resp *SetattrResponse) {
+ size := attrOutSize(r.Header.Conn.proto)
+ buf := newBuffer(size)
+ out := (*attrOut)(buf.alloc(size))
+ out.AttrValid = uint64(resp.Attr.Valid / time.Second)
+ out.AttrValidNsec = uint32(resp.Attr.Valid % time.Second / time.Nanosecond)
+ resp.Attr.attr(&out.Attr, r.Header.Conn.proto)
+ r.respond(buf)
+}
+
+// A SetattrResponse is the response to a SetattrRequest.
+type SetattrResponse struct {
+ Attr Attr // file attributes
+}
+
+func (r *SetattrResponse) String() string {
+ return fmt.Sprintf("Setattr %v", r.Attr)
+}
+
+// A FlushRequest asks for the current state of an open file to be flushed
+// to storage, as when a file descriptor is being closed. A single opened Handle
+// may receive multiple FlushRequests over its lifetime.
+type FlushRequest struct {
+ Header `json:"-"`
+ Handle HandleID
+ Flags uint32
+ LockOwner uint64
+}
+
+var _ = Request(&FlushRequest{})
+
+func (r *FlushRequest) String() string {
+ return fmt.Sprintf("Flush [%s] %v fl=%#x lk=%#x", &r.Header, r.Handle, r.Flags, r.LockOwner)
+}
+
+// Respond replies to the request, indicating that the flush succeeded.
+func (r *FlushRequest) Respond() {
+ buf := newBuffer(0)
+ r.respond(buf)
+}
+
+// A RemoveRequest asks to remove a file or directory from the
+// directory r.Node.
+type RemoveRequest struct {
+ Header `json:"-"`
+ Name string // name of the entry to remove
+ Dir bool // is this rmdir?
+}
+
+var _ = Request(&RemoveRequest{})
+
+func (r *RemoveRequest) String() string {
+ return fmt.Sprintf("Remove [%s] %q dir=%v", &r.Header, r.Name, r.Dir)
+}
+
+// Respond replies to the request, indicating that the file was removed.
+func (r *RemoveRequest) Respond() {
+ buf := newBuffer(0)
+ r.respond(buf)
+}
+
+// A SymlinkRequest is a request to create a symlink making NewName point to Target.
+type SymlinkRequest struct {
+ Header `json:"-"`
+ NewName, Target string
+}
+
+var _ = Request(&SymlinkRequest{})
+
+func (r *SymlinkRequest) String() string {
+ return fmt.Sprintf("Symlink [%s] from %q to target %q", &r.Header, r.NewName, r.Target)
+}
+
+// Respond replies to the request, indicating that the symlink was created.
+func (r *SymlinkRequest) Respond(resp *SymlinkResponse) {
+ size := entryOutSize(r.Header.Conn.proto)
+ buf := newBuffer(size)
+ out := (*entryOut)(buf.alloc(size))
+ out.Nodeid = uint64(resp.Node)
+ out.Generation = resp.Generation
+ out.EntryValid = uint64(resp.EntryValid / time.Second)
+ out.EntryValidNsec = uint32(resp.EntryValid % time.Second / time.Nanosecond)
+ out.AttrValid = uint64(resp.Attr.Valid / time.Second)
+ out.AttrValidNsec = uint32(resp.Attr.Valid % time.Second / time.Nanosecond)
+ resp.Attr.attr(&out.Attr, r.Header.Conn.proto)
+ r.respond(buf)
+}
+
+// A SymlinkResponse is the response to a SymlinkRequest.
+type SymlinkResponse struct {
+ LookupResponse
+}
+
+func (r *SymlinkResponse) String() string {
+ return fmt.Sprintf("Symlink %v", r.LookupResponse.string())
+}
+
+// A ReadlinkRequest is a request to read a symlink's target.
+type ReadlinkRequest struct {
+ Header `json:"-"`
+}
+
+var _ = Request(&ReadlinkRequest{})
+
+func (r *ReadlinkRequest) String() string {
+ return fmt.Sprintf("Readlink [%s]", &r.Header)
+}
+
+func (r *ReadlinkRequest) Respond(target string) {
+ buf := newBuffer(uintptr(len(target)))
+ buf = append(buf, target...)
+ r.respond(buf)
+}
+
+// A LinkRequest is a request to create a hard link.
+type LinkRequest struct {
+ Header `json:"-"`
+ OldNode NodeID
+ NewName string
+}
+
+var _ = Request(&LinkRequest{})
+
+func (r *LinkRequest) String() string {
+ return fmt.Sprintf("Link [%s] node %d to %q", &r.Header, r.OldNode, r.NewName)
+}
+
+func (r *LinkRequest) Respond(resp *LookupResponse) {
+ size := entryOutSize(r.Header.Conn.proto)
+ buf := newBuffer(size)
+ out := (*entryOut)(buf.alloc(size))
+ out.Nodeid = uint64(resp.Node)
+ out.Generation = resp.Generation
+ out.EntryValid = uint64(resp.EntryValid / time.Second)
+ out.EntryValidNsec = uint32(resp.EntryValid % time.Second / time.Nanosecond)
+ out.AttrValid = uint64(resp.Attr.Valid / time.Second)
+ out.AttrValidNsec = uint32(resp.Attr.Valid % time.Second / time.Nanosecond)
+ resp.Attr.attr(&out.Attr, r.Header.Conn.proto)
+ r.respond(buf)
+}
+
+// A RenameRequest is a request to rename a file.
+type RenameRequest struct {
+ Header `json:"-"`
+ NewDir NodeID
+ OldName, NewName string
+}
+
+var _ = Request(&RenameRequest{})
+
+func (r *RenameRequest) String() string {
+ return fmt.Sprintf("Rename [%s] from %q to dirnode %v %q", &r.Header, r.OldName, r.NewDir, r.NewName)
+}
+
+func (r *RenameRequest) Respond() {
+ buf := newBuffer(0)
+ r.respond(buf)
+}
+
+type MknodRequest struct {
+ Header `json:"-"`
+ Name string
+ Mode os.FileMode
+ Rdev uint32
+ // Umask of the request. Not supported on OS X.
+ Umask os.FileMode
+}
+
+var _ = Request(&MknodRequest{})
+
+func (r *MknodRequest) String() string {
+ return fmt.Sprintf("Mknod [%s] Name %q mode=%v umask=%v rdev=%d", &r.Header, r.Name, r.Mode, r.Umask, r.Rdev)
+}
+
+func (r *MknodRequest) Respond(resp *LookupResponse) {
+ size := entryOutSize(r.Header.Conn.proto)
+ buf := newBuffer(size)
+ out := (*entryOut)(buf.alloc(size))
+ out.Nodeid = uint64(resp.Node)
+ out.Generation = resp.Generation
+ out.EntryValid = uint64(resp.EntryValid / time.Second)
+ out.EntryValidNsec = uint32(resp.EntryValid % time.Second / time.Nanosecond)
+ out.AttrValid = uint64(resp.Attr.Valid / time.Second)
+ out.AttrValidNsec = uint32(resp.Attr.Valid % time.Second / time.Nanosecond)
+ resp.Attr.attr(&out.Attr, r.Header.Conn.proto)
+ r.respond(buf)
+}
+
+type FsyncRequest struct {
+ Header `json:"-"`
+ Handle HandleID
+ // TODO bit 1 is datasync, not well documented upstream
+ Flags uint32
+ Dir bool
+}
+
+var _ = Request(&FsyncRequest{})
+
+func (r *FsyncRequest) String() string {
+ return fmt.Sprintf("Fsync [%s] Handle %v Flags %v", &r.Header, r.Handle, r.Flags)
+}
+
+func (r *FsyncRequest) Respond() {
+ buf := newBuffer(0)
+ r.respond(buf)
+}
+
+// An InterruptRequest is a request to interrupt another pending request. The
+// response to that request should return an error status of EINTR.
+type InterruptRequest struct {
+ Header `json:"-"`
+ IntrID RequestID // ID of the request to be interrupt.
+}
+
+var _ = Request(&InterruptRequest{})
+
+func (r *InterruptRequest) Respond() {
+ // nothing to do here
+ r.noResponse()
+}
+
+func (r *InterruptRequest) String() string {
+ return fmt.Sprintf("Interrupt [%s] ID %v", &r.Header, r.IntrID)
+}
+
+// An ExchangeDataRequest is a request to exchange the contents of two
+// files, while leaving most metadata untouched.
+//
+// This request comes from OS X exchangedata(2) and represents its
+// specific semantics. Crucially, it is very different from Linux
+// renameat(2) RENAME_EXCHANGE.
+//
+// https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man2/exchangedata.2.html
+type ExchangeDataRequest struct {
+ Header `json:"-"`
+ OldDir, NewDir NodeID
+ OldName, NewName string
+ // TODO options
+}
+
+var _ = Request(&ExchangeDataRequest{})
+
+func (r *ExchangeDataRequest) String() string {
+ // TODO options
+ return fmt.Sprintf("ExchangeData [%s] %v %q and %v %q", &r.Header, r.OldDir, r.OldName, r.NewDir, r.NewName)
+}
+
+func (r *ExchangeDataRequest) Respond() {
+ buf := newBuffer(0)
+ r.respond(buf)
+}
diff --git a/vendor/bazil.org/fuse/fuse.iml b/vendor/bazil.org/fuse/fuse.iml
new file mode 100644
index 0000000000..792ad4c30c
--- /dev/null
+++ b/vendor/bazil.org/fuse/fuse.iml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/vendor/bazil.org/fuse/fuse_darwin.go b/vendor/bazil.org/fuse/fuse_darwin.go
new file mode 100644
index 0000000000..b58dca97d6
--- /dev/null
+++ b/vendor/bazil.org/fuse/fuse_darwin.go
@@ -0,0 +1,9 @@
+package fuse
+
+// Maximum file write size we are prepared to receive from the kernel.
+//
+// This value has to be >=16MB or OSXFUSE (3.4.0 observed) will
+// forcibly close the /dev/fuse file descriptor on a Setxattr with a
+// 16MB value. See TestSetxattr16MB and
+// https://github.com/bazil/fuse/issues/42
+const maxWrite = 16 * 1024 * 1024
diff --git a/vendor/bazil.org/fuse/fuse_freebsd.go b/vendor/bazil.org/fuse/fuse_freebsd.go
new file mode 100644
index 0000000000..4aa83a0d41
--- /dev/null
+++ b/vendor/bazil.org/fuse/fuse_freebsd.go
@@ -0,0 +1,6 @@
+package fuse
+
+// Maximum file write size we are prepared to receive from the kernel.
+//
+// This number is just a guess.
+const maxWrite = 128 * 1024
diff --git a/vendor/bazil.org/fuse/fuse_kernel.go b/vendor/bazil.org/fuse/fuse_kernel.go
new file mode 100644
index 0000000000..87c5ca1dc6
--- /dev/null
+++ b/vendor/bazil.org/fuse/fuse_kernel.go
@@ -0,0 +1,774 @@
+// See the file LICENSE for copyright and licensing information.
+
+// Derived from FUSE's fuse_kernel.h, which carries this notice:
+/*
+ This file defines the kernel interface of FUSE
+ Copyright (C) 2001-2007 Miklos Szeredi
+
+
+ This -- and only this -- header file may also be distributed under
+ the terms of the BSD Licence as follows:
+
+ Copyright (C) 2001-2007 Miklos Szeredi. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.
+*/
+
+package fuse
+
+import (
+ "fmt"
+ "syscall"
+ "unsafe"
+)
+
+// The FUSE version implemented by the package.
+const (
+ protoVersionMinMajor = 7
+ protoVersionMinMinor = 8
+ protoVersionMaxMajor = 7
+ protoVersionMaxMinor = 12
+)
+
+const (
+ rootID = 1
+)
+
+type kstatfs struct {
+ Blocks uint64
+ Bfree uint64
+ Bavail uint64
+ Files uint64
+ Ffree uint64
+ Bsize uint32
+ Namelen uint32
+ Frsize uint32
+ _ uint32
+ Spare [6]uint32
+}
+
+type fileLock struct {
+ Start uint64
+ End uint64
+ Type uint32
+ Pid uint32
+}
+
+// GetattrFlags are bit flags that can be seen in GetattrRequest.
+type GetattrFlags uint32
+
+const (
+ // Indicates the handle is valid.
+ GetattrFh GetattrFlags = 1 << 0
+)
+
+var getattrFlagsNames = []flagName{
+ {uint32(GetattrFh), "GetattrFh"},
+}
+
+func (fl GetattrFlags) String() string {
+ return flagString(uint32(fl), getattrFlagsNames)
+}
+
+// The SetattrValid are bit flags describing which fields in the SetattrRequest
+// are included in the change.
+type SetattrValid uint32
+
+const (
+ SetattrMode SetattrValid = 1 << 0
+ SetattrUid SetattrValid = 1 << 1
+ SetattrGid SetattrValid = 1 << 2
+ SetattrSize SetattrValid = 1 << 3
+ SetattrAtime SetattrValid = 1 << 4
+ SetattrMtime SetattrValid = 1 << 5
+ SetattrHandle SetattrValid = 1 << 6
+
+ // Linux only(?)
+ SetattrAtimeNow SetattrValid = 1 << 7
+ SetattrMtimeNow SetattrValid = 1 << 8
+ SetattrLockOwner SetattrValid = 1 << 9 // http://www.mail-archive.com/git-commits-head@vger.kernel.org/msg27852.html
+
+ // OS X only
+ SetattrCrtime SetattrValid = 1 << 28
+ SetattrChgtime SetattrValid = 1 << 29
+ SetattrBkuptime SetattrValid = 1 << 30
+ SetattrFlags SetattrValid = 1 << 31
+)
+
+func (fl SetattrValid) Mode() bool { return fl&SetattrMode != 0 }
+func (fl SetattrValid) Uid() bool { return fl&SetattrUid != 0 }
+func (fl SetattrValid) Gid() bool { return fl&SetattrGid != 0 }
+func (fl SetattrValid) Size() bool { return fl&SetattrSize != 0 }
+func (fl SetattrValid) Atime() bool { return fl&SetattrAtime != 0 }
+func (fl SetattrValid) Mtime() bool { return fl&SetattrMtime != 0 }
+func (fl SetattrValid) Handle() bool { return fl&SetattrHandle != 0 }
+func (fl SetattrValid) AtimeNow() bool { return fl&SetattrAtimeNow != 0 }
+func (fl SetattrValid) MtimeNow() bool { return fl&SetattrMtimeNow != 0 }
+func (fl SetattrValid) LockOwner() bool { return fl&SetattrLockOwner != 0 }
+func (fl SetattrValid) Crtime() bool { return fl&SetattrCrtime != 0 }
+func (fl SetattrValid) Chgtime() bool { return fl&SetattrChgtime != 0 }
+func (fl SetattrValid) Bkuptime() bool { return fl&SetattrBkuptime != 0 }
+func (fl SetattrValid) Flags() bool { return fl&SetattrFlags != 0 }
+
+func (fl SetattrValid) String() string {
+ return flagString(uint32(fl), setattrValidNames)
+}
+
+var setattrValidNames = []flagName{
+ {uint32(SetattrMode), "SetattrMode"},
+ {uint32(SetattrUid), "SetattrUid"},
+ {uint32(SetattrGid), "SetattrGid"},
+ {uint32(SetattrSize), "SetattrSize"},
+ {uint32(SetattrAtime), "SetattrAtime"},
+ {uint32(SetattrMtime), "SetattrMtime"},
+ {uint32(SetattrHandle), "SetattrHandle"},
+ {uint32(SetattrAtimeNow), "SetattrAtimeNow"},
+ {uint32(SetattrMtimeNow), "SetattrMtimeNow"},
+ {uint32(SetattrLockOwner), "SetattrLockOwner"},
+ {uint32(SetattrCrtime), "SetattrCrtime"},
+ {uint32(SetattrChgtime), "SetattrChgtime"},
+ {uint32(SetattrBkuptime), "SetattrBkuptime"},
+ {uint32(SetattrFlags), "SetattrFlags"},
+}
+
+// Flags that can be seen in OpenRequest.Flags.
+const (
+ // Access modes. These are not 1-bit flags, but alternatives where
+ // only one can be chosen. See the IsReadOnly etc convenience
+ // methods.
+ OpenReadOnly OpenFlags = syscall.O_RDONLY
+ OpenWriteOnly OpenFlags = syscall.O_WRONLY
+ OpenReadWrite OpenFlags = syscall.O_RDWR
+
+ // File was opened in append-only mode, all writes will go to end
+ // of file. OS X does not provide this information.
+ OpenAppend OpenFlags = syscall.O_APPEND
+ OpenCreate OpenFlags = syscall.O_CREAT
+ OpenDirectory OpenFlags = syscall.O_DIRECTORY
+ OpenExclusive OpenFlags = syscall.O_EXCL
+ OpenNonblock OpenFlags = syscall.O_NONBLOCK
+ OpenSync OpenFlags = syscall.O_SYNC
+ OpenTruncate OpenFlags = syscall.O_TRUNC
+)
+
+// OpenAccessModeMask is a bitmask that separates the access mode
+// from the other flags in OpenFlags.
+const OpenAccessModeMask OpenFlags = syscall.O_ACCMODE
+
+// OpenFlags are the O_FOO flags passed to open/create/etc calls. For
+// example, os.O_WRONLY | os.O_APPEND.
+type OpenFlags uint32
+
+func (fl OpenFlags) String() string {
+ // O_RDONLY, O_RWONLY, O_RDWR are not flags
+ s := accModeName(fl & OpenAccessModeMask)
+ flags := uint32(fl &^ OpenAccessModeMask)
+ if flags != 0 {
+ s = s + "+" + flagString(flags, openFlagNames)
+ }
+ return s
+}
+
+// Return true if OpenReadOnly is set.
+func (fl OpenFlags) IsReadOnly() bool {
+ return fl&OpenAccessModeMask == OpenReadOnly
+}
+
+// Return true if OpenWriteOnly is set.
+func (fl OpenFlags) IsWriteOnly() bool {
+ return fl&OpenAccessModeMask == OpenWriteOnly
+}
+
+// Return true if OpenReadWrite is set.
+func (fl OpenFlags) IsReadWrite() bool {
+ return fl&OpenAccessModeMask == OpenReadWrite
+}
+
+func accModeName(flags OpenFlags) string {
+ switch flags {
+ case OpenReadOnly:
+ return "OpenReadOnly"
+ case OpenWriteOnly:
+ return "OpenWriteOnly"
+ case OpenReadWrite:
+ return "OpenReadWrite"
+ default:
+ return ""
+ }
+}
+
+var openFlagNames = []flagName{
+ {uint32(OpenAppend), "OpenAppend"},
+ {uint32(OpenCreate), "OpenCreate"},
+ {uint32(OpenDirectory), "OpenDirectory"},
+ {uint32(OpenExclusive), "OpenExclusive"},
+ {uint32(OpenNonblock), "OpenNonblock"},
+ {uint32(OpenSync), "OpenSync"},
+ {uint32(OpenTruncate), "OpenTruncate"},
+}
+
+// The OpenResponseFlags are returned in the OpenResponse.
+type OpenResponseFlags uint32
+
+const (
+ OpenDirectIO OpenResponseFlags = 1 << 0 // bypass page cache for this open file
+ OpenKeepCache OpenResponseFlags = 1 << 1 // don't invalidate the data cache on open
+ OpenNonSeekable OpenResponseFlags = 1 << 2 // mark the file as non-seekable (not supported on OS X)
+
+ OpenPurgeAttr OpenResponseFlags = 1 << 30 // OS X
+ OpenPurgeUBC OpenResponseFlags = 1 << 31 // OS X
+)
+
+func (fl OpenResponseFlags) String() string {
+ return flagString(uint32(fl), openResponseFlagNames)
+}
+
+var openResponseFlagNames = []flagName{
+ {uint32(OpenDirectIO), "OpenDirectIO"},
+ {uint32(OpenKeepCache), "OpenKeepCache"},
+ {uint32(OpenNonSeekable), "OpenNonSeekable"},
+ {uint32(OpenPurgeAttr), "OpenPurgeAttr"},
+ {uint32(OpenPurgeUBC), "OpenPurgeUBC"},
+}
+
+// The InitFlags are used in the Init exchange.
+type InitFlags uint32
+
+const (
+ InitAsyncRead InitFlags = 1 << 0
+ InitPosixLocks InitFlags = 1 << 1
+ InitFileOps InitFlags = 1 << 2
+ InitAtomicTrunc InitFlags = 1 << 3
+ InitExportSupport InitFlags = 1 << 4
+ InitBigWrites InitFlags = 1 << 5
+ // Do not mask file access modes with umask. Not supported on OS X.
+ InitDontMask InitFlags = 1 << 6
+ InitSpliceWrite InitFlags = 1 << 7
+ InitSpliceMove InitFlags = 1 << 8
+ InitSpliceRead InitFlags = 1 << 9
+ InitFlockLocks InitFlags = 1 << 10
+ InitHasIoctlDir InitFlags = 1 << 11
+ InitAutoInvalData InitFlags = 1 << 12
+ InitDoReaddirplus InitFlags = 1 << 13
+ InitReaddirplusAuto InitFlags = 1 << 14
+ InitAsyncDIO InitFlags = 1 << 15
+ InitWritebackCache InitFlags = 1 << 16
+ InitNoOpenSupport InitFlags = 1 << 17
+
+ InitCaseSensitive InitFlags = 1 << 29 // OS X only
+ InitVolRename InitFlags = 1 << 30 // OS X only
+ InitXtimes InitFlags = 1 << 31 // OS X only
+)
+
+type flagName struct {
+ bit uint32
+ name string
+}
+
+var initFlagNames = []flagName{
+ {uint32(InitAsyncRead), "InitAsyncRead"},
+ {uint32(InitPosixLocks), "InitPosixLocks"},
+ {uint32(InitFileOps), "InitFileOps"},
+ {uint32(InitAtomicTrunc), "InitAtomicTrunc"},
+ {uint32(InitExportSupport), "InitExportSupport"},
+ {uint32(InitBigWrites), "InitBigWrites"},
+ {uint32(InitDontMask), "InitDontMask"},
+ {uint32(InitSpliceWrite), "InitSpliceWrite"},
+ {uint32(InitSpliceMove), "InitSpliceMove"},
+ {uint32(InitSpliceRead), "InitSpliceRead"},
+ {uint32(InitFlockLocks), "InitFlockLocks"},
+ {uint32(InitHasIoctlDir), "InitHasIoctlDir"},
+ {uint32(InitAutoInvalData), "InitAutoInvalData"},
+ {uint32(InitDoReaddirplus), "InitDoReaddirplus"},
+ {uint32(InitReaddirplusAuto), "InitReaddirplusAuto"},
+ {uint32(InitAsyncDIO), "InitAsyncDIO"},
+ {uint32(InitWritebackCache), "InitWritebackCache"},
+ {uint32(InitNoOpenSupport), "InitNoOpenSupport"},
+
+ {uint32(InitCaseSensitive), "InitCaseSensitive"},
+ {uint32(InitVolRename), "InitVolRename"},
+ {uint32(InitXtimes), "InitXtimes"},
+}
+
+func (fl InitFlags) String() string {
+ return flagString(uint32(fl), initFlagNames)
+}
+
+func flagString(f uint32, names []flagName) string {
+ var s string
+
+ if f == 0 {
+ return "0"
+ }
+
+ for _, n := range names {
+ if f&n.bit != 0 {
+ s += "+" + n.name
+ f &^= n.bit
+ }
+ }
+ if f != 0 {
+ s += fmt.Sprintf("%+#x", f)
+ }
+ return s[1:]
+}
+
+// The ReleaseFlags are used in the Release exchange.
+type ReleaseFlags uint32
+
+const (
+ ReleaseFlush ReleaseFlags = 1 << 0
+)
+
+func (fl ReleaseFlags) String() string {
+ return flagString(uint32(fl), releaseFlagNames)
+}
+
+var releaseFlagNames = []flagName{
+ {uint32(ReleaseFlush), "ReleaseFlush"},
+}
+
+// Opcodes
+const (
+ opLookup = 1
+ opForget = 2 // no reply
+ opGetattr = 3
+ opSetattr = 4
+ opReadlink = 5
+ opSymlink = 6
+ opMknod = 8
+ opMkdir = 9
+ opUnlink = 10
+ opRmdir = 11
+ opRename = 12
+ opLink = 13
+ opOpen = 14
+ opRead = 15
+ opWrite = 16
+ opStatfs = 17
+ opRelease = 18
+ opFsync = 20
+ opSetxattr = 21
+ opGetxattr = 22
+ opListxattr = 23
+ opRemovexattr = 24
+ opFlush = 25
+ opInit = 26
+ opOpendir = 27
+ opReaddir = 28
+ opReleasedir = 29
+ opFsyncdir = 30
+ opGetlk = 31
+ opSetlk = 32
+ opSetlkw = 33
+ opAccess = 34
+ opCreate = 35
+ opInterrupt = 36
+ opBmap = 37
+ opDestroy = 38
+ opIoctl = 39 // Linux?
+ opPoll = 40 // Linux?
+
+ // OS X
+ opSetvolname = 61
+ opGetxtimes = 62
+ opExchange = 63
+)
+
+type entryOut struct {
+ Nodeid uint64 // Inode ID
+ Generation uint64 // Inode generation
+ EntryValid uint64 // Cache timeout for the name
+ AttrValid uint64 // Cache timeout for the attributes
+ EntryValidNsec uint32
+ AttrValidNsec uint32
+ Attr attr
+}
+
+func entryOutSize(p Protocol) uintptr {
+ switch {
+ case p.LT(Protocol{7, 9}):
+ return unsafe.Offsetof(entryOut{}.Attr) + unsafe.Offsetof(entryOut{}.Attr.Blksize)
+ default:
+ return unsafe.Sizeof(entryOut{})
+ }
+}
+
+type forgetIn struct {
+ Nlookup uint64
+}
+
+type getattrIn struct {
+ GetattrFlags uint32
+ _ uint32
+ Fh uint64
+}
+
+type attrOut struct {
+ AttrValid uint64 // Cache timeout for the attributes
+ AttrValidNsec uint32
+ _ uint32
+ Attr attr
+}
+
+func attrOutSize(p Protocol) uintptr {
+ switch {
+ case p.LT(Protocol{7, 9}):
+ return unsafe.Offsetof(attrOut{}.Attr) + unsafe.Offsetof(attrOut{}.Attr.Blksize)
+ default:
+ return unsafe.Sizeof(attrOut{})
+ }
+}
+
+// OS X
+type getxtimesOut struct {
+ Bkuptime uint64
+ Crtime uint64
+ BkuptimeNsec uint32
+ CrtimeNsec uint32
+}
+
+type mknodIn struct {
+ Mode uint32
+ Rdev uint32
+ Umask uint32
+ _ uint32
+ // "filename\x00" follows.
+}
+
+func mknodInSize(p Protocol) uintptr {
+ switch {
+ case p.LT(Protocol{7, 12}):
+ return unsafe.Offsetof(mknodIn{}.Umask)
+ default:
+ return unsafe.Sizeof(mknodIn{})
+ }
+}
+
+type mkdirIn struct {
+ Mode uint32
+ Umask uint32
+ // filename follows
+}
+
+func mkdirInSize(p Protocol) uintptr {
+ switch {
+ case p.LT(Protocol{7, 12}):
+ return unsafe.Offsetof(mkdirIn{}.Umask) + 4
+ default:
+ return unsafe.Sizeof(mkdirIn{})
+ }
+}
+
+type renameIn struct {
+ Newdir uint64
+ // "oldname\x00newname\x00" follows
+}
+
+// OS X
+type exchangeIn struct {
+ Olddir uint64
+ Newdir uint64
+ Options uint64
+ // "oldname\x00newname\x00" follows
+}
+
+type linkIn struct {
+ Oldnodeid uint64
+}
+
+type setattrInCommon struct {
+ Valid uint32
+ _ uint32
+ Fh uint64
+ Size uint64
+ LockOwner uint64 // unused on OS X?
+ Atime uint64
+ Mtime uint64
+ Unused2 uint64
+ AtimeNsec uint32
+ MtimeNsec uint32
+ Unused3 uint32
+ Mode uint32
+ Unused4 uint32
+ Uid uint32
+ Gid uint32
+ Unused5 uint32
+}
+
+type openIn struct {
+ Flags uint32
+ Unused uint32
+}
+
+type openOut struct {
+ Fh uint64
+ OpenFlags uint32
+ _ uint32
+}
+
+type createIn struct {
+ Flags uint32
+ Mode uint32
+ Umask uint32
+ _ uint32
+}
+
+func createInSize(p Protocol) uintptr {
+ switch {
+ case p.LT(Protocol{7, 12}):
+ return unsafe.Offsetof(createIn{}.Umask)
+ default:
+ return unsafe.Sizeof(createIn{})
+ }
+}
+
+type releaseIn struct {
+ Fh uint64
+ Flags uint32
+ ReleaseFlags uint32
+ LockOwner uint32
+}
+
+type flushIn struct {
+ Fh uint64
+ FlushFlags uint32
+ _ uint32
+ LockOwner uint64
+}
+
+type readIn struct {
+ Fh uint64
+ Offset uint64
+ Size uint32
+ ReadFlags uint32
+ LockOwner uint64
+ Flags uint32
+ _ uint32
+}
+
+func readInSize(p Protocol) uintptr {
+ switch {
+ case p.LT(Protocol{7, 9}):
+ return unsafe.Offsetof(readIn{}.ReadFlags) + 4
+ default:
+ return unsafe.Sizeof(readIn{})
+ }
+}
+
+// The ReadFlags are passed in ReadRequest.
+type ReadFlags uint32
+
+const (
+ // LockOwner field is valid.
+ ReadLockOwner ReadFlags = 1 << 1
+)
+
+var readFlagNames = []flagName{
+ {uint32(ReadLockOwner), "ReadLockOwner"},
+}
+
+func (fl ReadFlags) String() string {
+ return flagString(uint32(fl), readFlagNames)
+}
+
+type writeIn struct {
+ Fh uint64
+ Offset uint64
+ Size uint32
+ WriteFlags uint32
+ LockOwner uint64
+ Flags uint32
+ _ uint32
+}
+
+func writeInSize(p Protocol) uintptr {
+ switch {
+ case p.LT(Protocol{7, 9}):
+ return unsafe.Offsetof(writeIn{}.LockOwner)
+ default:
+ return unsafe.Sizeof(writeIn{})
+ }
+}
+
+type writeOut struct {
+ Size uint32
+ _ uint32
+}
+
+// The WriteFlags are passed in WriteRequest.
+type WriteFlags uint32
+
+const (
+ WriteCache WriteFlags = 1 << 0
+ // LockOwner field is valid.
+ WriteLockOwner WriteFlags = 1 << 1
+)
+
+var writeFlagNames = []flagName{
+ {uint32(WriteCache), "WriteCache"},
+ {uint32(WriteLockOwner), "WriteLockOwner"},
+}
+
+func (fl WriteFlags) String() string {
+ return flagString(uint32(fl), writeFlagNames)
+}
+
+const compatStatfsSize = 48
+
+type statfsOut struct {
+ St kstatfs
+}
+
+type fsyncIn struct {
+ Fh uint64
+ FsyncFlags uint32
+ _ uint32
+}
+
+type setxattrInCommon struct {
+ Size uint32
+ Flags uint32
+}
+
+func (setxattrInCommon) position() uint32 {
+ return 0
+}
+
+type getxattrInCommon struct {
+ Size uint32
+ _ uint32
+}
+
+func (getxattrInCommon) position() uint32 {
+ return 0
+}
+
+type getxattrOut struct {
+ Size uint32
+ _ uint32
+}
+
+type lkIn struct {
+ Fh uint64
+ Owner uint64
+ Lk fileLock
+ LkFlags uint32
+ _ uint32
+}
+
+func lkInSize(p Protocol) uintptr {
+ switch {
+ case p.LT(Protocol{7, 9}):
+ return unsafe.Offsetof(lkIn{}.LkFlags)
+ default:
+ return unsafe.Sizeof(lkIn{})
+ }
+}
+
+type lkOut struct {
+ Lk fileLock
+}
+
+type accessIn struct {
+ Mask uint32
+ _ uint32
+}
+
+type initIn struct {
+ Major uint32
+ Minor uint32
+ MaxReadahead uint32
+ Flags uint32
+}
+
+const initInSize = int(unsafe.Sizeof(initIn{}))
+
+type initOut struct {
+ Major uint32
+ Minor uint32
+ MaxReadahead uint32
+ Flags uint32
+ Unused uint32
+ MaxWrite uint32
+}
+
+type interruptIn struct {
+ Unique uint64
+}
+
+type bmapIn struct {
+ Block uint64
+ BlockSize uint32
+ _ uint32
+}
+
+type bmapOut struct {
+ Block uint64
+}
+
+type inHeader struct {
+ Len uint32
+ Opcode uint32
+ Unique uint64
+ Nodeid uint64
+ Uid uint32
+ Gid uint32
+ Pid uint32
+ _ uint32
+}
+
+const inHeaderSize = int(unsafe.Sizeof(inHeader{}))
+
+type outHeader struct {
+ Len uint32
+ Error int32
+ Unique uint64
+}
+
+type dirent struct {
+ Ino uint64
+ Off uint64
+ Namelen uint32
+ Type uint32
+ Name [0]byte
+}
+
+const direntSize = 8 + 8 + 4 + 4
+
+const (
+ notifyCodePoll int32 = 1
+ notifyCodeInvalInode int32 = 2
+ notifyCodeInvalEntry int32 = 3
+)
+
+type notifyInvalInodeOut struct {
+ Ino uint64
+ Off int64
+ Len int64
+}
+
+type notifyInvalEntryOut struct {
+ Parent uint64
+ Namelen uint32
+ _ uint32
+}
diff --git a/vendor/bazil.org/fuse/fuse_kernel_darwin.go b/vendor/bazil.org/fuse/fuse_kernel_darwin.go
new file mode 100644
index 0000000000..b9873fdf39
--- /dev/null
+++ b/vendor/bazil.org/fuse/fuse_kernel_darwin.go
@@ -0,0 +1,88 @@
+package fuse
+
+import (
+ "time"
+)
+
+type attr struct {
+ Ino uint64
+ Size uint64
+ Blocks uint64
+ Atime uint64
+ Mtime uint64
+ Ctime uint64
+ Crtime_ uint64 // OS X only
+ AtimeNsec uint32
+ MtimeNsec uint32
+ CtimeNsec uint32
+ CrtimeNsec uint32 // OS X only
+ Mode uint32
+ Nlink uint32
+ Uid uint32
+ Gid uint32
+ Rdev uint32
+ Flags_ uint32 // OS X only; see chflags(2)
+ Blksize uint32
+ padding uint32
+}
+
+func (a *attr) SetCrtime(s uint64, ns uint32) {
+ a.Crtime_, a.CrtimeNsec = s, ns
+}
+
+func (a *attr) SetFlags(f uint32) {
+ a.Flags_ = f
+}
+
+type setattrIn struct {
+ setattrInCommon
+
+ // OS X only
+ Bkuptime_ uint64
+ Chgtime_ uint64
+ Crtime uint64
+ BkuptimeNsec uint32
+ ChgtimeNsec uint32
+ CrtimeNsec uint32
+ Flags_ uint32 // see chflags(2)
+}
+
+func (in *setattrIn) BkupTime() time.Time {
+ return time.Unix(int64(in.Bkuptime_), int64(in.BkuptimeNsec))
+}
+
+func (in *setattrIn) Chgtime() time.Time {
+ return time.Unix(int64(in.Chgtime_), int64(in.ChgtimeNsec))
+}
+
+func (in *setattrIn) Flags() uint32 {
+ return in.Flags_
+}
+
+func openFlags(flags uint32) OpenFlags {
+ return OpenFlags(flags)
+}
+
+type getxattrIn struct {
+ getxattrInCommon
+
+ // OS X only
+ Position uint32
+ Padding uint32
+}
+
+func (g *getxattrIn) position() uint32 {
+ return g.Position
+}
+
+type setxattrIn struct {
+ setxattrInCommon
+
+ // OS X only
+ Position uint32
+ Padding uint32
+}
+
+func (s *setxattrIn) position() uint32 {
+ return s.Position
+}
diff --git a/vendor/bazil.org/fuse/fuse_kernel_freebsd.go b/vendor/bazil.org/fuse/fuse_kernel_freebsd.go
new file mode 100644
index 0000000000..b1141e41dc
--- /dev/null
+++ b/vendor/bazil.org/fuse/fuse_kernel_freebsd.go
@@ -0,0 +1,62 @@
+package fuse
+
+import "time"
+
+type attr struct {
+ Ino uint64
+ Size uint64
+ Blocks uint64
+ Atime uint64
+ Mtime uint64
+ Ctime uint64
+ AtimeNsec uint32
+ MtimeNsec uint32
+ CtimeNsec uint32
+ Mode uint32
+ Nlink uint32
+ Uid uint32
+ Gid uint32
+ Rdev uint32
+ Blksize uint32
+ padding uint32
+}
+
+func (a *attr) Crtime() time.Time {
+ return time.Time{}
+}
+
+func (a *attr) SetCrtime(s uint64, ns uint32) {
+ // ignored on freebsd
+}
+
+func (a *attr) SetFlags(f uint32) {
+ // ignored on freebsd
+}
+
+type setattrIn struct {
+ setattrInCommon
+}
+
+func (in *setattrIn) BkupTime() time.Time {
+ return time.Time{}
+}
+
+func (in *setattrIn) Chgtime() time.Time {
+ return time.Time{}
+}
+
+func (in *setattrIn) Flags() uint32 {
+ return 0
+}
+
+func openFlags(flags uint32) OpenFlags {
+ return OpenFlags(flags)
+}
+
+type getxattrIn struct {
+ getxattrInCommon
+}
+
+type setxattrIn struct {
+ setxattrInCommon
+}
diff --git a/vendor/bazil.org/fuse/fuse_kernel_linux.go b/vendor/bazil.org/fuse/fuse_kernel_linux.go
new file mode 100644
index 0000000000..d3ba866178
--- /dev/null
+++ b/vendor/bazil.org/fuse/fuse_kernel_linux.go
@@ -0,0 +1,70 @@
+package fuse
+
+import "time"
+
+type attr struct {
+ Ino uint64
+ Size uint64
+ Blocks uint64
+ Atime uint64
+ Mtime uint64
+ Ctime uint64
+ AtimeNsec uint32
+ MtimeNsec uint32
+ CtimeNsec uint32
+ Mode uint32
+ Nlink uint32
+ Uid uint32
+ Gid uint32
+ Rdev uint32
+ Blksize uint32
+ padding uint32
+}
+
+func (a *attr) Crtime() time.Time {
+ return time.Time{}
+}
+
+func (a *attr) SetCrtime(s uint64, ns uint32) {
+ // Ignored on Linux.
+}
+
+func (a *attr) SetFlags(f uint32) {
+ // Ignored on Linux.
+}
+
+type setattrIn struct {
+ setattrInCommon
+}
+
+func (in *setattrIn) BkupTime() time.Time {
+ return time.Time{}
+}
+
+func (in *setattrIn) Chgtime() time.Time {
+ return time.Time{}
+}
+
+func (in *setattrIn) Flags() uint32 {
+ return 0
+}
+
+func openFlags(flags uint32) OpenFlags {
+ // on amd64, the 32-bit O_LARGEFILE flag is always seen;
+ // on i386, the flag probably depends on the app
+ // requesting, but in any case should be utterly
+ // uninteresting to us here; our kernel protocol messages
+ // are not directly related to the client app's kernel
+ // API/ABI
+ flags &^= 0x8000
+
+ return OpenFlags(flags)
+}
+
+type getxattrIn struct {
+ getxattrInCommon
+}
+
+type setxattrIn struct {
+ setxattrInCommon
+}
diff --git a/vendor/bazil.org/fuse/fuse_kernel_std.go b/vendor/bazil.org/fuse/fuse_kernel_std.go
new file mode 100644
index 0000000000..074cfd3228
--- /dev/null
+++ b/vendor/bazil.org/fuse/fuse_kernel_std.go
@@ -0,0 +1 @@
+package fuse
diff --git a/vendor/bazil.org/fuse/fuse_linux.go b/vendor/bazil.org/fuse/fuse_linux.go
new file mode 100644
index 0000000000..5fb96f9ae9
--- /dev/null
+++ b/vendor/bazil.org/fuse/fuse_linux.go
@@ -0,0 +1,7 @@
+package fuse
+
+// Maximum file write size we are prepared to receive from the kernel.
+//
+// Linux 4.2.0 has been observed to cap this value at 128kB
+// (FUSE_MAX_PAGES_PER_REQ=32, 4kB pages).
+const maxWrite = 128 * 1024
diff --git a/vendor/bazil.org/fuse/fuseutil/fuseutil.go b/vendor/bazil.org/fuse/fuseutil/fuseutil.go
new file mode 100644
index 0000000000..b3f52b73b2
--- /dev/null
+++ b/vendor/bazil.org/fuse/fuseutil/fuseutil.go
@@ -0,0 +1,20 @@
+package fuseutil // import "bazil.org/fuse/fuseutil"
+
+import (
+ "bazil.org/fuse"
+)
+
+// HandleRead handles a read request assuming that data is the entire file content.
+// It adjusts the amount returned in resp according to req.Offset and req.Size.
+func HandleRead(req *fuse.ReadRequest, resp *fuse.ReadResponse, data []byte) {
+ if req.Offset >= int64(len(data)) {
+ data = nil
+ } else {
+ data = data[req.Offset:]
+ }
+ if len(data) > req.Size {
+ data = data[:req.Size]
+ }
+ n := copy(resp.Data[:req.Size], data)
+ resp.Data = resp.Data[:n]
+}
diff --git a/vendor/bazil.org/fuse/mount.go b/vendor/bazil.org/fuse/mount.go
new file mode 100644
index 0000000000..8054e9021c
--- /dev/null
+++ b/vendor/bazil.org/fuse/mount.go
@@ -0,0 +1,38 @@
+package fuse
+
+import (
+ "bufio"
+ "errors"
+ "io"
+ "log"
+ "sync"
+)
+
+var (
+ // ErrOSXFUSENotFound is returned from Mount when the OSXFUSE
+ // installation is not detected.
+ //
+ // Only happens on OS X. Make sure OSXFUSE is installed, or see
+ // OSXFUSELocations for customization.
+ ErrOSXFUSENotFound = errors.New("cannot locate OSXFUSE")
+)
+
+func neverIgnoreLine(line string) bool {
+ return false
+}
+
+func lineLogger(wg *sync.WaitGroup, prefix string, ignore func(line string) bool, r io.ReadCloser) {
+ defer wg.Done()
+
+ scanner := bufio.NewScanner(r)
+ for scanner.Scan() {
+ line := scanner.Text()
+ if ignore(line) {
+ continue
+ }
+ log.Printf("%s: %s", prefix, line)
+ }
+ if err := scanner.Err(); err != nil {
+ log.Printf("%s, error reading: %v", prefix, err)
+ }
+}
diff --git a/vendor/bazil.org/fuse/mount_darwin.go b/vendor/bazil.org/fuse/mount_darwin.go
new file mode 100644
index 0000000000..c1c36e62b5
--- /dev/null
+++ b/vendor/bazil.org/fuse/mount_darwin.go
@@ -0,0 +1,208 @@
+package fuse
+
+import (
+ "errors"
+ "fmt"
+ "log"
+ "os"
+ "os/exec"
+ "path"
+ "strconv"
+ "strings"
+ "sync"
+ "syscall"
+)
+
+var (
+ errNoAvail = errors.New("no available fuse devices")
+ errNotLoaded = errors.New("osxfuse is not loaded")
+)
+
+func loadOSXFUSE(bin string) error {
+ cmd := exec.Command(bin)
+ cmd.Dir = "/"
+ cmd.Stdout = os.Stdout
+ cmd.Stderr = os.Stderr
+ err := cmd.Run()
+ return err
+}
+
+func openOSXFUSEDev(devPrefix string) (*os.File, error) {
+ var f *os.File
+ var err error
+ for i := uint64(0); ; i++ {
+ path := devPrefix + strconv.FormatUint(i, 10)
+ f, err = os.OpenFile(path, os.O_RDWR, 0000)
+ if os.IsNotExist(err) {
+ if i == 0 {
+ // not even the first device was found -> fuse is not loaded
+ return nil, errNotLoaded
+ }
+
+ // we've run out of kernel-provided devices
+ return nil, errNoAvail
+ }
+
+ if err2, ok := err.(*os.PathError); ok && err2.Err == syscall.EBUSY {
+ // try the next one
+ continue
+ }
+
+ if err != nil {
+ return nil, err
+ }
+ return f, nil
+ }
+}
+
+func handleMountOSXFUSE(helperName string, errCh chan<- error) func(line string) (ignore bool) {
+ var noMountpointPrefix = helperName + `: `
+ const noMountpointSuffix = `: No such file or directory`
+ return func(line string) (ignore bool) {
+ if strings.HasPrefix(line, noMountpointPrefix) && strings.HasSuffix(line, noMountpointSuffix) {
+ // re-extract it from the error message in case some layer
+ // changed the path
+ mountpoint := line[len(noMountpointPrefix) : len(line)-len(noMountpointSuffix)]
+ err := &MountpointDoesNotExistError{
+ Path: mountpoint,
+ }
+ select {
+ case errCh <- err:
+ return true
+ default:
+ // not the first error; fall back to logging it
+ return false
+ }
+ }
+
+ return false
+ }
+}
+
+// isBoringMountOSXFUSEError returns whether the Wait error is
+// uninteresting; exit status 64 is.
+func isBoringMountOSXFUSEError(err error) bool {
+ if err, ok := err.(*exec.ExitError); ok && err.Exited() {
+ if status, ok := err.Sys().(syscall.WaitStatus); ok && status.ExitStatus() == 64 {
+ return true
+ }
+ }
+ return false
+}
+
+func callMount(bin string, daemonVar string, dir string, conf *mountConfig, f *os.File, ready chan<- struct{}, errp *error) error {
+ for k, v := range conf.options {
+ if strings.Contains(k, ",") || strings.Contains(v, ",") {
+ // Silly limitation but the mount helper does not
+ // understand any escaping. See TestMountOptionCommaError.
+ return fmt.Errorf("mount options cannot contain commas on darwin: %q=%q", k, v)
+ }
+ }
+ cmd := exec.Command(
+ bin,
+ "-o", conf.getOptions(),
+ // Tell osxfuse-kext how large our buffer is. It must split
+ // writes larger than this into multiple writes.
+ //
+ // OSXFUSE seems to ignore InitResponse.MaxWrite, and uses
+ // this instead.
+ "-o", "iosize="+strconv.FormatUint(maxWrite, 10),
+ // refers to fd passed in cmd.ExtraFiles
+ "3",
+ dir,
+ )
+ cmd.ExtraFiles = []*os.File{f}
+ cmd.Env = os.Environ()
+ // OSXFUSE <3.3.0
+ cmd.Env = append(cmd.Env, "MOUNT_FUSEFS_CALL_BY_LIB=")
+ // OSXFUSE >=3.3.0
+ cmd.Env = append(cmd.Env, "MOUNT_OSXFUSE_CALL_BY_LIB=")
+
+ daemon := os.Args[0]
+ if daemonVar != "" {
+ cmd.Env = append(cmd.Env, daemonVar+"="+daemon)
+ }
+
+ stdout, err := cmd.StdoutPipe()
+ if err != nil {
+ return fmt.Errorf("setting up mount_osxfusefs stderr: %v", err)
+ }
+ stderr, err := cmd.StderrPipe()
+ if err != nil {
+ return fmt.Errorf("setting up mount_osxfusefs stderr: %v", err)
+ }
+
+ if err := cmd.Start(); err != nil {
+ return fmt.Errorf("mount_osxfusefs: %v", err)
+ }
+ helperErrCh := make(chan error, 1)
+ go func() {
+ var wg sync.WaitGroup
+ wg.Add(2)
+ go lineLogger(&wg, "mount helper output", neverIgnoreLine, stdout)
+ helperName := path.Base(bin)
+ go lineLogger(&wg, "mount helper error", handleMountOSXFUSE(helperName, helperErrCh), stderr)
+ wg.Wait()
+ if err := cmd.Wait(); err != nil {
+ // see if we have a better error to report
+ select {
+ case helperErr := <-helperErrCh:
+ // log the Wait error if it's not what we expected
+ if !isBoringMountOSXFUSEError(err) {
+ log.Printf("mount helper failed: %v", err)
+ }
+ // and now return what we grabbed from stderr as the real
+ // error
+ *errp = helperErr
+ close(ready)
+ return
+ default:
+ // nope, fall back to generic message
+ }
+
+ *errp = fmt.Errorf("mount_osxfusefs: %v", err)
+ close(ready)
+ return
+ }
+
+ *errp = nil
+ close(ready)
+ }()
+ return nil
+}
+
+func mount(dir string, conf *mountConfig, ready chan<- struct{}, errp *error) (*os.File, error) {
+ locations := conf.osxfuseLocations
+ if locations == nil {
+ locations = []OSXFUSEPaths{
+ OSXFUSELocationV3,
+ OSXFUSELocationV2,
+ }
+ }
+ for _, loc := range locations {
+ if _, err := os.Stat(loc.Mount); os.IsNotExist(err) {
+ // try the other locations
+ continue
+ }
+
+ f, err := openOSXFUSEDev(loc.DevicePrefix)
+ if err == errNotLoaded {
+ err = loadOSXFUSE(loc.Load)
+ if err != nil {
+ return nil, err
+ }
+ // try again
+ f, err = openOSXFUSEDev(loc.DevicePrefix)
+ }
+ if err != nil {
+ return nil, err
+ }
+ err = callMount(loc.Mount, loc.DaemonVar, dir, conf, f, ready, errp)
+ if err != nil {
+ f.Close()
+ return nil, err
+ }
+ return f, nil
+ }
+ return nil, ErrOSXFUSENotFound
+}
diff --git a/vendor/bazil.org/fuse/mount_freebsd.go b/vendor/bazil.org/fuse/mount_freebsd.go
new file mode 100644
index 0000000000..70bb410249
--- /dev/null
+++ b/vendor/bazil.org/fuse/mount_freebsd.go
@@ -0,0 +1,111 @@
+package fuse
+
+import (
+ "fmt"
+ "log"
+ "os"
+ "os/exec"
+ "strings"
+ "sync"
+ "syscall"
+)
+
+func handleMountFusefsStderr(errCh chan<- error) func(line string) (ignore bool) {
+ return func(line string) (ignore bool) {
+ const (
+ noMountpointPrefix = `mount_fusefs: `
+ noMountpointSuffix = `: No such file or directory`
+ )
+ if strings.HasPrefix(line, noMountpointPrefix) && strings.HasSuffix(line, noMountpointSuffix) {
+ // re-extract it from the error message in case some layer
+ // changed the path
+ mountpoint := line[len(noMountpointPrefix) : len(line)-len(noMountpointSuffix)]
+ err := &MountpointDoesNotExistError{
+ Path: mountpoint,
+ }
+ select {
+ case errCh <- err:
+ return true
+ default:
+ // not the first error; fall back to logging it
+ return false
+ }
+ }
+
+ return false
+ }
+}
+
+// isBoringMountFusefsError returns whether the Wait error is
+// uninteresting; exit status 1 is.
+func isBoringMountFusefsError(err error) bool {
+ if err, ok := err.(*exec.ExitError); ok && err.Exited() {
+ if status, ok := err.Sys().(syscall.WaitStatus); ok && status.ExitStatus() == 1 {
+ return true
+ }
+ }
+ return false
+}
+
+func mount(dir string, conf *mountConfig, ready chan<- struct{}, errp *error) (*os.File, error) {
+ for k, v := range conf.options {
+ if strings.Contains(k, ",") || strings.Contains(v, ",") {
+ // Silly limitation but the mount helper does not
+ // understand any escaping. See TestMountOptionCommaError.
+ return nil, fmt.Errorf("mount options cannot contain commas on FreeBSD: %q=%q", k, v)
+ }
+ }
+
+ f, err := os.OpenFile("/dev/fuse", os.O_RDWR, 0000)
+ if err != nil {
+ *errp = err
+ return nil, err
+ }
+
+ cmd := exec.Command(
+ "/sbin/mount_fusefs",
+ "--safe",
+ "-o", conf.getOptions(),
+ "3",
+ dir,
+ )
+ cmd.ExtraFiles = []*os.File{f}
+
+ stdout, err := cmd.StdoutPipe()
+ if err != nil {
+ return nil, fmt.Errorf("setting up mount_fusefs stderr: %v", err)
+ }
+ stderr, err := cmd.StderrPipe()
+ if err != nil {
+ return nil, fmt.Errorf("setting up mount_fusefs stderr: %v", err)
+ }
+
+ if err := cmd.Start(); err != nil {
+ return nil, fmt.Errorf("mount_fusefs: %v", err)
+ }
+ helperErrCh := make(chan error, 1)
+ var wg sync.WaitGroup
+ wg.Add(2)
+ go lineLogger(&wg, "mount helper output", neverIgnoreLine, stdout)
+ go lineLogger(&wg, "mount helper error", handleMountFusefsStderr(helperErrCh), stderr)
+ wg.Wait()
+ if err := cmd.Wait(); err != nil {
+ // see if we have a better error to report
+ select {
+ case helperErr := <-helperErrCh:
+ // log the Wait error if it's not what we expected
+ if !isBoringMountFusefsError(err) {
+ log.Printf("mount helper failed: %v", err)
+ }
+ // and now return what we grabbed from stderr as the real
+ // error
+ return nil, helperErr
+ default:
+ // nope, fall back to generic message
+ }
+ return nil, fmt.Errorf("mount_fusefs: %v", err)
+ }
+
+ close(ready)
+ return f, nil
+}
diff --git a/vendor/bazil.org/fuse/mount_linux.go b/vendor/bazil.org/fuse/mount_linux.go
new file mode 100644
index 0000000000..197d1044e9
--- /dev/null
+++ b/vendor/bazil.org/fuse/mount_linux.go
@@ -0,0 +1,150 @@
+package fuse
+
+import (
+ "fmt"
+ "log"
+ "net"
+ "os"
+ "os/exec"
+ "strings"
+ "sync"
+ "syscall"
+)
+
+func handleFusermountStderr(errCh chan<- error) func(line string) (ignore bool) {
+ return func(line string) (ignore bool) {
+ if line == `fusermount: failed to open /etc/fuse.conf: Permission denied` {
+ // Silence this particular message, it occurs way too
+ // commonly and isn't very relevant to whether the mount
+ // succeeds or not.
+ return true
+ }
+
+ const (
+ noMountpointPrefix = `fusermount: failed to access mountpoint `
+ noMountpointSuffix = `: No such file or directory`
+ )
+ if strings.HasPrefix(line, noMountpointPrefix) && strings.HasSuffix(line, noMountpointSuffix) {
+ // re-extract it from the error message in case some layer
+ // changed the path
+ mountpoint := line[len(noMountpointPrefix) : len(line)-len(noMountpointSuffix)]
+ err := &MountpointDoesNotExistError{
+ Path: mountpoint,
+ }
+ select {
+ case errCh <- err:
+ return true
+ default:
+ // not the first error; fall back to logging it
+ return false
+ }
+ }
+
+ return false
+ }
+}
+
+// isBoringFusermountError returns whether the Wait error is
+// uninteresting; exit status 1 is.
+func isBoringFusermountError(err error) bool {
+ if err, ok := err.(*exec.ExitError); ok && err.Exited() {
+ if status, ok := err.Sys().(syscall.WaitStatus); ok && status.ExitStatus() == 1 {
+ return true
+ }
+ }
+ return false
+}
+
+func mount(dir string, conf *mountConfig, ready chan<- struct{}, errp *error) (fusefd *os.File, err error) {
+ // linux mount is never delayed
+ close(ready)
+
+ fds, err := syscall.Socketpair(syscall.AF_FILE, syscall.SOCK_STREAM, 0)
+ if err != nil {
+ return nil, fmt.Errorf("socketpair error: %v", err)
+ }
+
+ writeFile := os.NewFile(uintptr(fds[0]), "fusermount-child-writes")
+ defer writeFile.Close()
+
+ readFile := os.NewFile(uintptr(fds[1]), "fusermount-parent-reads")
+ defer readFile.Close()
+
+ cmd := exec.Command(
+ "fusermount",
+ "-o", conf.getOptions(),
+ "--",
+ dir,
+ )
+ cmd.Env = append(os.Environ(), "_FUSE_COMMFD=3")
+
+ cmd.ExtraFiles = []*os.File{writeFile}
+
+ var wg sync.WaitGroup
+ stdout, err := cmd.StdoutPipe()
+ if err != nil {
+ return nil, fmt.Errorf("setting up fusermount stderr: %v", err)
+ }
+ stderr, err := cmd.StderrPipe()
+ if err != nil {
+ return nil, fmt.Errorf("setting up fusermount stderr: %v", err)
+ }
+
+ if err := cmd.Start(); err != nil {
+ return nil, fmt.Errorf("fusermount: %v", err)
+ }
+ helperErrCh := make(chan error, 1)
+ wg.Add(2)
+ go lineLogger(&wg, "mount helper output", neverIgnoreLine, stdout)
+ go lineLogger(&wg, "mount helper error", handleFusermountStderr(helperErrCh), stderr)
+ wg.Wait()
+ if err := cmd.Wait(); err != nil {
+ // see if we have a better error to report
+ select {
+ case helperErr := <-helperErrCh:
+ // log the Wait error if it's not what we expected
+ if !isBoringFusermountError(err) {
+ log.Printf("mount helper failed: %v", err)
+ }
+ // and now return what we grabbed from stderr as the real
+ // error
+ return nil, helperErr
+ default:
+ // nope, fall back to generic message
+ }
+
+ return nil, fmt.Errorf("fusermount: %v", err)
+ }
+
+ c, err := net.FileConn(readFile)
+ if err != nil {
+ return nil, fmt.Errorf("FileConn from fusermount socket: %v", err)
+ }
+ defer c.Close()
+
+ uc, ok := c.(*net.UnixConn)
+ if !ok {
+ return nil, fmt.Errorf("unexpected FileConn type; expected UnixConn, got %T", c)
+ }
+
+ buf := make([]byte, 32) // expect 1 byte
+ oob := make([]byte, 32) // expect 24 bytes
+ _, oobn, _, _, err := uc.ReadMsgUnix(buf, oob)
+ scms, err := syscall.ParseSocketControlMessage(oob[:oobn])
+ if err != nil {
+ return nil, fmt.Errorf("ParseSocketControlMessage: %v", err)
+ }
+ if len(scms) != 1 {
+ return nil, fmt.Errorf("expected 1 SocketControlMessage; got scms = %#v", scms)
+ }
+ scm := scms[0]
+ gotFds, err := syscall.ParseUnixRights(&scm)
+ if err != nil {
+ return nil, fmt.Errorf("syscall.ParseUnixRights: %v", err)
+ }
+ if len(gotFds) != 1 {
+ return nil, fmt.Errorf("wanted 1 fd; got %#v", gotFds)
+ }
+ f := os.NewFile(uintptr(gotFds[0]), "/dev/fuse")
+ return f, nil
+}
diff --git a/vendor/bazil.org/fuse/options.go b/vendor/bazil.org/fuse/options.go
new file mode 100644
index 0000000000..65ce8a5410
--- /dev/null
+++ b/vendor/bazil.org/fuse/options.go
@@ -0,0 +1,310 @@
+package fuse
+
+import (
+ "errors"
+ "strings"
+)
+
+func dummyOption(conf *mountConfig) error {
+ return nil
+}
+
+// mountConfig holds the configuration for a mount operation.
+// Use it by passing MountOption values to Mount.
+type mountConfig struct {
+ options map[string]string
+ maxReadahead uint32
+ initFlags InitFlags
+ osxfuseLocations []OSXFUSEPaths
+}
+
+func escapeComma(s string) string {
+ s = strings.Replace(s, `\`, `\\`, -1)
+ s = strings.Replace(s, `,`, `\,`, -1)
+ return s
+}
+
+// getOptions makes a string of options suitable for passing to FUSE
+// mount flag `-o`. Returns an empty string if no options were set.
+// Any platform specific adjustments should happen before the call.
+func (m *mountConfig) getOptions() string {
+ var opts []string
+ for k, v := range m.options {
+ k = escapeComma(k)
+ if v != "" {
+ k += "=" + escapeComma(v)
+ }
+ opts = append(opts, k)
+ }
+ return strings.Join(opts, ",")
+}
+
+type mountOption func(*mountConfig) error
+
+// MountOption is passed to Mount to change the behavior of the mount.
+type MountOption mountOption
+
+// FSName sets the file system name (also called source) that is
+// visible in the list of mounted file systems.
+//
+// FreeBSD ignores this option.
+func FSName(name string) MountOption {
+ return func(conf *mountConfig) error {
+ conf.options["fsname"] = name
+ return nil
+ }
+}
+
+// Subtype sets the subtype of the mount. The main type is always
+// `fuse`. The type in a list of mounted file systems will look like
+// `fuse.foo`.
+//
+// OS X ignores this option.
+// FreeBSD ignores this option.
+func Subtype(fstype string) MountOption {
+ return func(conf *mountConfig) error {
+ conf.options["subtype"] = fstype
+ return nil
+ }
+}
+
+// LocalVolume sets the volume to be local (instead of network),
+// changing the behavior of Finder, Spotlight, and such.
+//
+// OS X only. Others ignore this option.
+func LocalVolume() MountOption {
+ return localVolume
+}
+
+// VolumeName sets the volume name shown in Finder.
+//
+// OS X only. Others ignore this option.
+func VolumeName(name string) MountOption {
+ return volumeName(name)
+}
+
+// NoAppleDouble makes OSXFUSE disallow files with names used by OS X
+// to store extended attributes on file systems that do not support
+// them natively.
+//
+// Such file names are:
+//
+// ._*
+// .DS_Store
+//
+// OS X only. Others ignore this option.
+func NoAppleDouble() MountOption {
+ return noAppleDouble
+}
+
+// NoAppleXattr makes OSXFUSE disallow extended attributes with the
+// prefix "com.apple.". This disables persistent Finder state and
+// other such information.
+//
+// OS X only. Others ignore this option.
+func NoAppleXattr() MountOption {
+ return noAppleXattr
+}
+
+// ExclCreate causes O_EXCL flag to be set for only "truly" exclusive creates,
+// i.e. create calls for which the initiator explicitly set the O_EXCL flag.
+//
+// OSXFUSE expects all create calls to return EEXIST in case the file
+// already exists, regardless of whether O_EXCL was specified or not.
+// To ensure this behavior, it normally sets OpenExclusive for all
+// Create calls, regardless of whether the original call had it set.
+// For distributed filesystems, that may force every file create to be
+// a distributed consensus action, causing undesirable delays.
+//
+// This option makes the FUSE filesystem see the original flag value,
+// and better decide when to ensure global consensus.
+//
+// Note that returning EEXIST on existing file create is still
+// expected with OSXFUSE, regardless of the presence of the
+// OpenExclusive flag.
+//
+// For more information, see
+// https://github.com/osxfuse/osxfuse/issues/209
+//
+// OS X only. Others ignore this options.
+// Requires OSXFUSE 3.4.1 or newer.
+func ExclCreate() MountOption {
+ return exclCreate
+}
+
+// DaemonTimeout sets the time in seconds between a request and a reply before
+// the FUSE mount is declared dead.
+//
+// OS X and FreeBSD only. Others ignore this option.
+func DaemonTimeout(name string) MountOption {
+ return daemonTimeout(name)
+}
+
+var ErrCannotCombineAllowOtherAndAllowRoot = errors.New("cannot combine AllowOther and AllowRoot")
+
+// AllowOther allows other users to access the file system.
+//
+// Only one of AllowOther or AllowRoot can be used.
+func AllowOther() MountOption {
+ return func(conf *mountConfig) error {
+ if _, ok := conf.options["allow_root"]; ok {
+ return ErrCannotCombineAllowOtherAndAllowRoot
+ }
+ conf.options["allow_other"] = ""
+ return nil
+ }
+}
+
+// AllowRoot allows other users to access the file system.
+//
+// Only one of AllowOther or AllowRoot can be used.
+//
+// FreeBSD ignores this option.
+func AllowRoot() MountOption {
+ return func(conf *mountConfig) error {
+ if _, ok := conf.options["allow_other"]; ok {
+ return ErrCannotCombineAllowOtherAndAllowRoot
+ }
+ conf.options["allow_root"] = ""
+ return nil
+ }
+}
+
+// AllowDev enables interpreting character or block special devices on the
+// filesystem.
+func AllowDev() MountOption {
+ return func(conf *mountConfig) error {
+ conf.options["dev"] = ""
+ return nil
+ }
+}
+
+// AllowSUID allows set-user-identifier or set-group-identifier bits to take
+// effect.
+func AllowSUID() MountOption {
+ return func(conf *mountConfig) error {
+ conf.options["suid"] = ""
+ return nil
+ }
+}
+
+// DefaultPermissions makes the kernel enforce access control based on
+// the file mode (as in chmod).
+//
+// Without this option, the Node itself decides what is and is not
+// allowed. This is normally ok because FUSE file systems cannot be
+// accessed by other users without AllowOther/AllowRoot.
+//
+// FreeBSD ignores this option.
+func DefaultPermissions() MountOption {
+ return func(conf *mountConfig) error {
+ conf.options["default_permissions"] = ""
+ return nil
+ }
+}
+
+// ReadOnly makes the mount read-only.
+func ReadOnly() MountOption {
+ return func(conf *mountConfig) error {
+ conf.options["ro"] = ""
+ return nil
+ }
+}
+
+// MaxReadahead sets the number of bytes that can be prefetched for
+// sequential reads. The kernel can enforce a maximum value lower than
+// this.
+//
+// This setting makes the kernel perform speculative reads that do not
+// originate from any client process. This usually tremendously
+// improves read performance.
+func MaxReadahead(n uint32) MountOption {
+ return func(conf *mountConfig) error {
+ conf.maxReadahead = n
+ return nil
+ }
+}
+
+// AsyncRead enables multiple outstanding read requests for the same
+// handle. Without this, there is at most one request in flight at a
+// time.
+func AsyncRead() MountOption {
+ return func(conf *mountConfig) error {
+ conf.initFlags |= InitAsyncRead
+ return nil
+ }
+}
+
+// WritebackCache enables the kernel to buffer writes before sending
+// them to the FUSE server. Without this, writethrough caching is
+// used.
+func WritebackCache() MountOption {
+ return func(conf *mountConfig) error {
+ conf.initFlags |= InitWritebackCache
+ return nil
+ }
+}
+
+// OSXFUSEPaths describes the paths used by an installed OSXFUSE
+// version. See OSXFUSELocationV3 for typical values.
+type OSXFUSEPaths struct {
+ // Prefix for the device file. At mount time, an incrementing
+ // number is suffixed until a free FUSE device is found.
+ DevicePrefix string
+ // Path of the load helper, used to load the kernel extension if
+ // no device files are found.
+ Load string
+ // Path of the mount helper, used for the actual mount operation.
+ Mount string
+ // Environment variable used to pass the path to the executable
+ // calling the mount helper.
+ DaemonVar string
+}
+
+// Default paths for OSXFUSE. See OSXFUSELocations.
+var (
+ OSXFUSELocationV3 = OSXFUSEPaths{
+ DevicePrefix: "/dev/osxfuse",
+ Load: "/Library/Filesystems/osxfuse.fs/Contents/Resources/load_osxfuse",
+ Mount: "/Library/Filesystems/osxfuse.fs/Contents/Resources/mount_osxfuse",
+ DaemonVar: "MOUNT_OSXFUSE_DAEMON_PATH",
+ }
+ OSXFUSELocationV2 = OSXFUSEPaths{
+ DevicePrefix: "/dev/osxfuse",
+ Load: "/Library/Filesystems/osxfusefs.fs/Support/load_osxfusefs",
+ Mount: "/Library/Filesystems/osxfusefs.fs/Support/mount_osxfusefs",
+ DaemonVar: "MOUNT_FUSEFS_DAEMON_PATH",
+ }
+)
+
+// OSXFUSELocations sets where to look for OSXFUSE files. The
+// arguments are all the possible locations. The previous locations
+// are replaced.
+//
+// Without this option, OSXFUSELocationV3 and OSXFUSELocationV2 are
+// used.
+//
+// OS X only. Others ignore this option.
+func OSXFUSELocations(paths ...OSXFUSEPaths) MountOption {
+ return func(conf *mountConfig) error {
+ if len(paths) == 0 {
+ return errors.New("must specify at least one location for OSXFUSELocations")
+ }
+ // replace previous values, but make a copy so there's no
+ // worries about caller mutating their slice
+ conf.osxfuseLocations = append(conf.osxfuseLocations[:0], paths...)
+ return nil
+ }
+}
+
+// AllowNonEmptyMount allows the mounting over a non-empty directory.
+//
+// The files in it will be shadowed by the freshly created mount. By
+// default these mounts are rejected to prevent accidental covering up
+// of data, which could for example prevent automatic backup.
+func AllowNonEmptyMount() MountOption {
+ return func(conf *mountConfig) error {
+ conf.options["nonempty"] = ""
+ return nil
+ }
+}
diff --git a/vendor/bazil.org/fuse/options_darwin.go b/vendor/bazil.org/fuse/options_darwin.go
new file mode 100644
index 0000000000..faa9d78e74
--- /dev/null
+++ b/vendor/bazil.org/fuse/options_darwin.go
@@ -0,0 +1,35 @@
+package fuse
+
+func localVolume(conf *mountConfig) error {
+ conf.options["local"] = ""
+ return nil
+}
+
+func volumeName(name string) MountOption {
+ return func(conf *mountConfig) error {
+ conf.options["volname"] = name
+ return nil
+ }
+}
+
+func daemonTimeout(name string) MountOption {
+ return func(conf *mountConfig) error {
+ conf.options["daemon_timeout"] = name
+ return nil
+ }
+}
+
+func noAppleXattr(conf *mountConfig) error {
+ conf.options["noapplexattr"] = ""
+ return nil
+}
+
+func noAppleDouble(conf *mountConfig) error {
+ conf.options["noappledouble"] = ""
+ return nil
+}
+
+func exclCreate(conf *mountConfig) error {
+ conf.options["excl_create"] = ""
+ return nil
+}
diff --git a/vendor/bazil.org/fuse/options_freebsd.go b/vendor/bazil.org/fuse/options_freebsd.go
new file mode 100644
index 0000000000..7c164b1368
--- /dev/null
+++ b/vendor/bazil.org/fuse/options_freebsd.go
@@ -0,0 +1,28 @@
+package fuse
+
+func localVolume(conf *mountConfig) error {
+ return nil
+}
+
+func volumeName(name string) MountOption {
+ return dummyOption
+}
+
+func daemonTimeout(name string) MountOption {
+ return func(conf *mountConfig) error {
+ conf.options["timeout"] = name
+ return nil
+ }
+}
+
+func noAppleXattr(conf *mountConfig) error {
+ return nil
+}
+
+func noAppleDouble(conf *mountConfig) error {
+ return nil
+}
+
+func exclCreate(conf *mountConfig) error {
+ return nil
+}
diff --git a/vendor/bazil.org/fuse/options_linux.go b/vendor/bazil.org/fuse/options_linux.go
new file mode 100644
index 0000000000..13f0896d58
--- /dev/null
+++ b/vendor/bazil.org/fuse/options_linux.go
@@ -0,0 +1,25 @@
+package fuse
+
+func localVolume(conf *mountConfig) error {
+ return nil
+}
+
+func volumeName(name string) MountOption {
+ return dummyOption
+}
+
+func daemonTimeout(name string) MountOption {
+ return dummyOption
+}
+
+func noAppleXattr(conf *mountConfig) error {
+ return nil
+}
+
+func noAppleDouble(conf *mountConfig) error {
+ return nil
+}
+
+func exclCreate(conf *mountConfig) error {
+ return nil
+}
diff --git a/vendor/bazil.org/fuse/protocol.go b/vendor/bazil.org/fuse/protocol.go
new file mode 100644
index 0000000000..a77bbf72f1
--- /dev/null
+++ b/vendor/bazil.org/fuse/protocol.go
@@ -0,0 +1,75 @@
+package fuse
+
+import (
+ "fmt"
+)
+
+// Protocol is a FUSE protocol version number.
+type Protocol struct {
+ Major uint32
+ Minor uint32
+}
+
+func (p Protocol) String() string {
+ return fmt.Sprintf("%d.%d", p.Major, p.Minor)
+}
+
+// LT returns whether a is less than b.
+func (a Protocol) LT(b Protocol) bool {
+ return a.Major < b.Major ||
+ (a.Major == b.Major && a.Minor < b.Minor)
+}
+
+// GE returns whether a is greater than or equal to b.
+func (a Protocol) GE(b Protocol) bool {
+ return a.Major > b.Major ||
+ (a.Major == b.Major && a.Minor >= b.Minor)
+}
+
+func (a Protocol) is79() bool {
+ return a.GE(Protocol{7, 9})
+}
+
+// HasAttrBlockSize returns whether Attr.BlockSize is respected by the
+// kernel.
+func (a Protocol) HasAttrBlockSize() bool {
+ return a.is79()
+}
+
+// HasReadWriteFlags returns whether ReadRequest/WriteRequest
+// fields Flags and FileFlags are valid.
+func (a Protocol) HasReadWriteFlags() bool {
+ return a.is79()
+}
+
+// HasGetattrFlags returns whether GetattrRequest field Flags is
+// valid.
+func (a Protocol) HasGetattrFlags() bool {
+ return a.is79()
+}
+
+func (a Protocol) is710() bool {
+ return a.GE(Protocol{7, 10})
+}
+
+// HasOpenNonSeekable returns whether OpenResponse field Flags flag
+// OpenNonSeekable is supported.
+func (a Protocol) HasOpenNonSeekable() bool {
+ return a.is710()
+}
+
+func (a Protocol) is712() bool {
+ return a.GE(Protocol{7, 12})
+}
+
+// HasUmask returns whether CreateRequest/MkdirRequest/MknodRequest
+// field Umask is valid.
+func (a Protocol) HasUmask() bool {
+ return a.is712()
+}
+
+// HasInvalidate returns whether InvalidateNode/InvalidateEntry are
+// supported.
+func (a Protocol) HasInvalidate() bool {
+ return a.is712()
+}
diff --git a/vendor/bazil.org/fuse/unmount.go b/vendor/bazil.org/fuse/unmount.go
new file mode 100644
index 0000000000..ffe3f155c4
--- /dev/null
+++ b/vendor/bazil.org/fuse/unmount.go
@@ -0,0 +1,6 @@
+package fuse
+
+// Unmount tries to unmount the filesystem mounted at dir.
+func Unmount(dir string) error {
+ return unmount(dir)
+}
diff --git a/vendor/bazil.org/fuse/unmount_linux.go b/vendor/bazil.org/fuse/unmount_linux.go
new file mode 100644
index 0000000000..088f0cfeee
--- /dev/null
+++ b/vendor/bazil.org/fuse/unmount_linux.go
@@ -0,0 +1,21 @@
+package fuse
+
+import (
+ "bytes"
+ "errors"
+ "os/exec"
+)
+
+func unmount(dir string) error {
+ cmd := exec.Command("fusermount", "-u", dir)
+ output, err := cmd.CombinedOutput()
+ if err != nil {
+ if len(output) > 0 {
+ output = bytes.TrimRight(output, "\n")
+ msg := err.Error() + ": " + string(output)
+ err = errors.New(msg)
+ }
+ return err
+ }
+ return nil
+}
diff --git a/vendor/bazil.org/fuse/unmount_std.go b/vendor/bazil.org/fuse/unmount_std.go
new file mode 100644
index 0000000000..d6efe276f6
--- /dev/null
+++ b/vendor/bazil.org/fuse/unmount_std.go
@@ -0,0 +1,17 @@
+// +build !linux
+
+package fuse
+
+import (
+ "os"
+ "syscall"
+)
+
+func unmount(dir string) error {
+ err := syscall.Unmount(dir, 0)
+ if err != nil {
+ err = &os.PathError{Op: "unmount", Path: dir, Err: err}
+ return err
+ }
+ return nil
+}
diff --git a/vendor/github.com/Azure/azure-sdk-for-go/.gitignore b/vendor/github.com/Azure/azure-sdk-for-go/.gitignore
deleted file mode 100644
index 2da4dc3587..0000000000
--- a/vendor/github.com/Azure/azure-sdk-for-go/.gitignore
+++ /dev/null
@@ -1,32 +0,0 @@
-# Compiled Object files, Static and Dynamic libs (Shared Objects)
-*.o
-*.a
-*.so
-
-# Folders
-_obj
-_test
-
-# Architecture specific extensions/prefixes
-*.[568vq]
-[568vq].out
-
-*.cgo1.go
-*.cgo2.c
-_cgo_defun.c
-_cgo_gotypes.go
-_cgo_export.*
-
-_testmain.go
-
-*.exe
-*.test
-*.prof
-
-# Editor swap files
-*.swp
-*~
-.DS_Store
-
-# ignore vendor/
-vendor/
diff --git a/vendor/github.com/Azure/azure-sdk-for-go/.travis.yml b/vendor/github.com/Azure/azure-sdk-for-go/.travis.yml
deleted file mode 100644
index 6a134afebf..0000000000
--- a/vendor/github.com/Azure/azure-sdk-for-go/.travis.yml
+++ /dev/null
@@ -1,33 +0,0 @@
-sudo: false
-
-language: go
-
-go: 1.7
-
-install:
- - go get -u github.com/golang/lint/golint
- - go get -u github.com/Masterminds/glide
- - go get -u golang.org/x/net/context
- - go get -u github.com/HewlettPackard/gas
- - go get -u gopkg.in/godo.v2/cmd/godo
- - export GO15VENDOREXPERIMENT=1
- - glide install
-
-script:
- - gas -skip=management/examples/*.go -skip=*vendor* -skip=Gododir/* ./... | tee gas-scan.txt
- - test -z "$(grep 'Severity:\s*HIGH' gas-scan.txt)"
- - test -z "$(gofmt -s -l $(find ./arm/* -type d -print) | tee /dev/stderr)"
- - test -z "$(gofmt -s -l -w management | tee /dev/stderr)"
- - test -z "$(gofmt -s -l -w storage | tee /dev/stderr)"
- - test -z "$(gofmt -s -l -w Gododir | tee /dev/stderr)"
- - test -z "$(go build $(find ./* -type d -print | grep -v '^./vendor$') | tee /dev/stderr)"
- - test -z "$(go vet $(find ./arm/* -type d -print) | tee /dev/stderr)"
- - test -z "$(golint ./arm/... | tee /dev/stderr)"
- - go test -v ./storage/... -check.v
- - test -z "$(golint ./storage/... | tee /dev/stderr)"
- - go vet ./storage/...
- - go test -v ./management/...
- - test -z "$(golint ./management/... | grep -v 'should have comment' | grep -v 'stutters' | tee /dev/stderr)"
- - go vet ./management/...
- - test -z "$(golint ./Gododir/... | tee /dev/stderr)"
- - go vet ./Gododir/...
diff --git a/vendor/github.com/aristanetworks/goarista/monotime/nanotime.go b/vendor/github.com/aristanetworks/goarista/monotime/nanotime.go
index efc1b92a60..5f5fbc7ae5 100644
--- a/vendor/github.com/aristanetworks/goarista/monotime/nanotime.go
+++ b/vendor/github.com/aristanetworks/goarista/monotime/nanotime.go
@@ -6,6 +6,7 @@
package monotime
import (
+ "time"
_ "unsafe" // required to use //go:linkname
)
@@ -22,3 +23,9 @@ func nanotime() int64
func Now() uint64 {
return uint64(nanotime())
}
+
+// Since returns the amount of time that has elapsed since t. t should be
+// the result of a call to Now() on the same machine.
+func Since(t uint64) time.Duration {
+ return time.Duration(Now() - t)
+}
diff --git a/vendor/github.com/btcsuite/btcd/LICENSE b/vendor/github.com/btcsuite/btcd/LICENSE
new file mode 100644
index 0000000000..53ba0c5608
--- /dev/null
+++ b/vendor/github.com/btcsuite/btcd/LICENSE
@@ -0,0 +1,16 @@
+ISC License
+
+Copyright (c) 2013-2017 The btcsuite developers
+Copyright (c) 2015-2016 The Decred developers
+
+Permission to use, copy, modify, and distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/vendor/github.com/btcsuite/btcd/btcec/README.md b/vendor/github.com/btcsuite/btcd/btcec/README.md
new file mode 100644
index 0000000000..5875dfc91b
--- /dev/null
+++ b/vendor/github.com/btcsuite/btcd/btcec/README.md
@@ -0,0 +1,74 @@
+btcec
+=====
+
+[]
+(https://travis-ci.org/btcsuite/btcec) [![ISC License]
+(http://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org)
+[]
+(http://godoc.org/github.com/btcsuite/btcd/btcec)
+
+Package btcec implements elliptic curve cryptography needed for working with
+Bitcoin (secp256k1 only for now). It is designed so that it may be used with the
+standard crypto/ecdsa packages provided with go. A comprehensive suite of test
+is provided to ensure proper functionality. Package btcec was originally based
+on work from ThePiachu which is licensed under the same terms as Go, but it has
+signficantly diverged since then. The btcsuite developers original is licensed
+under the liberal ISC license.
+
+Although this package was primarily written for btcd, it has intentionally been
+designed so it can be used as a standalone package for any projects needing to
+use secp256k1 elliptic curve cryptography.
+
+## Installation and Updating
+
+```bash
+$ go get -u github.com/btcsuite/btcd/btcec
+```
+
+## Examples
+
+* [Sign Message]
+ (http://godoc.org/github.com/btcsuite/btcd/btcec#example-package--SignMessage)
+ Demonstrates signing a message with a secp256k1 private key that is first
+ parsed form raw bytes and serializing the generated signature.
+
+* [Verify Signature]
+ (http://godoc.org/github.com/btcsuite/btcd/btcec#example-package--VerifySignature)
+ Demonstrates verifying a secp256k1 signature against a public key that is
+ first parsed from raw bytes. The signature is also parsed from raw bytes.
+
+* [Encryption]
+ (http://godoc.org/github.com/btcsuite/btcd/btcec#example-package--EncryptMessage)
+ Demonstrates encrypting a message for a public key that is first parsed from
+ raw bytes, then decrypting it using the corresponding private key.
+
+* [Decryption]
+ (http://godoc.org/github.com/btcsuite/btcd/btcec#example-package--DecryptMessage)
+ Demonstrates decrypting a message using a private key that is first parsed
+ from raw bytes.
+
+## GPG Verification Key
+
+All official release tags are signed by Conformal so users can ensure the code
+has not been tampered with and is coming from the btcsuite developers. To
+verify the signature perform the following:
+
+- Download the public key from the Conformal website at
+ https://opensource.conformal.com/GIT-GPG-KEY-conformal.txt
+
+- Import the public key into your GPG keyring:
+ ```bash
+ gpg --import GIT-GPG-KEY-conformal.txt
+ ```
+
+- Verify the release tag with the following command where `TAG_NAME` is a
+ placeholder for the specific tag:
+ ```bash
+ git tag -v TAG_NAME
+ ```
+
+## License
+
+Package btcec is licensed under the [copyfree](http://copyfree.org) ISC License
+except for btcec.go and btcec_test.go which is under the same license as Go.
+
diff --git a/vendor/github.com/btcsuite/btcd/btcec/btcec.go b/vendor/github.com/btcsuite/btcd/btcec/btcec.go
new file mode 100644
index 0000000000..98d7b14329
--- /dev/null
+++ b/vendor/github.com/btcsuite/btcd/btcec/btcec.go
@@ -0,0 +1,956 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Copyright 2011 ThePiachu. All rights reserved.
+// Copyright 2013-2014 The btcsuite developers
+// Use of this source code is governed by an ISC
+// license that can be found in the LICENSE file.
+
+package btcec
+
+// References:
+// [SECG]: Recommended Elliptic Curve Domain Parameters
+// http://www.secg.org/sec2-v2.pdf
+//
+// [GECC]: Guide to Elliptic Curve Cryptography (Hankerson, Menezes, Vanstone)
+
+// This package operates, internally, on Jacobian coordinates. For a given
+// (x, y) position on the curve, the Jacobian coordinates are (x1, y1, z1)
+// where x = x1/z1² and y = y1/z1³. The greatest speedups come when the whole
+// calculation can be performed within the transform (as in ScalarMult and
+// ScalarBaseMult). But even for Add and Double, it's faster to apply and
+// reverse the transform than to operate in affine coordinates.
+
+import (
+ "crypto/elliptic"
+ "math/big"
+ "sync"
+)
+
+var (
+ // fieldOne is simply the integer 1 in field representation. It is
+ // used to avoid needing to create it multiple times during the internal
+ // arithmetic.
+ fieldOne = new(fieldVal).SetInt(1)
+)
+
+// KoblitzCurve supports a koblitz curve implementation that fits the ECC Curve
+// interface from crypto/elliptic.
+type KoblitzCurve struct {
+ *elliptic.CurveParams
+ q *big.Int
+ H int // cofactor of the curve.
+
+ // byteSize is simply the bit size / 8 and is provided for convenience
+ // since it is calculated repeatedly.
+ byteSize int
+
+ // bytePoints
+ bytePoints *[32][256][3]fieldVal
+
+ // The next 6 values are used specifically for endomorphism
+ // optimizations in ScalarMult.
+
+ // lambda must fulfill lambda^3 = 1 mod N where N is the order of G.
+ lambda *big.Int
+
+ // beta must fulfill beta^3 = 1 mod P where P is the prime field of the
+ // curve.
+ beta *fieldVal
+
+ // See the EndomorphismVectors in gensecp256k1.go to see how these are
+ // derived.
+ a1 *big.Int
+ b1 *big.Int
+ a2 *big.Int
+ b2 *big.Int
+}
+
+// Params returns the parameters for the curve.
+func (curve *KoblitzCurve) Params() *elliptic.CurveParams {
+ return curve.CurveParams
+}
+
+// bigAffineToField takes an affine point (x, y) as big integers and converts
+// it to an affine point as field values.
+func (curve *KoblitzCurve) bigAffineToField(x, y *big.Int) (*fieldVal, *fieldVal) {
+ x3, y3 := new(fieldVal), new(fieldVal)
+ x3.SetByteSlice(x.Bytes())
+ y3.SetByteSlice(y.Bytes())
+
+ return x3, y3
+}
+
+// fieldJacobianToBigAffine takes a Jacobian point (x, y, z) as field values and
+// converts it to an affine point as big integers.
+func (curve *KoblitzCurve) fieldJacobianToBigAffine(x, y, z *fieldVal) (*big.Int, *big.Int) {
+ // Inversions are expensive and both point addition and point doubling
+ // are faster when working with points that have a z value of one. So,
+ // if the point needs to be converted to affine, go ahead and normalize
+ // the point itself at the same time as the calculation is the same.
+ var zInv, tempZ fieldVal
+ zInv.Set(z).Inverse() // zInv = Z^-1
+ tempZ.SquareVal(&zInv) // tempZ = Z^-2
+ x.Mul(&tempZ) // X = X/Z^2 (mag: 1)
+ y.Mul(tempZ.Mul(&zInv)) // Y = Y/Z^3 (mag: 1)
+ z.SetInt(1) // Z = 1 (mag: 1)
+
+ // Normalize the x and y values.
+ x.Normalize()
+ y.Normalize()
+
+ // Convert the field values for the now affine point to big.Ints.
+ x3, y3 := new(big.Int), new(big.Int)
+ x3.SetBytes(x.Bytes()[:])
+ y3.SetBytes(y.Bytes()[:])
+ return x3, y3
+}
+
+// IsOnCurve returns boolean if the point (x,y) is on the curve.
+// Part of the elliptic.Curve interface. This function differs from the
+// crypto/elliptic algorithm since a = 0 not -3.
+func (curve *KoblitzCurve) IsOnCurve(x, y *big.Int) bool {
+ // Convert big ints to field values for faster arithmetic.
+ fx, fy := curve.bigAffineToField(x, y)
+
+ // Elliptic curve equation for secp256k1 is: y^2 = x^3 + 7
+ y2 := new(fieldVal).SquareVal(fy).Normalize()
+ result := new(fieldVal).SquareVal(fx).Mul(fx).AddInt(7).Normalize()
+ return y2.Equals(result)
+}
+
+// addZ1AndZ2EqualsOne adds two Jacobian points that are already known to have
+// z values of 1 and stores the result in (x3, y3, z3). That is to say
+// (x1, y1, 1) + (x2, y2, 1) = (x3, y3, z3). It performs faster addition than
+// the generic add routine since less arithmetic is needed due to the ability to
+// avoid the z value multiplications.
+func (curve *KoblitzCurve) addZ1AndZ2EqualsOne(x1, y1, z1, x2, y2, x3, y3, z3 *fieldVal) {
+ // To compute the point addition efficiently, this implementation splits
+ // the equation into intermediate elements which are used to minimize
+ // the number of field multiplications using the method shown at:
+ // http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-mmadd-2007-bl
+ //
+ // In particular it performs the calculations using the following:
+ // H = X2-X1, HH = H^2, I = 4*HH, J = H*I, r = 2*(Y2-Y1), V = X1*I
+ // X3 = r^2-J-2*V, Y3 = r*(V-X3)-2*Y1*J, Z3 = 2*H
+ //
+ // This results in a cost of 4 field multiplications, 2 field squarings,
+ // 6 field additions, and 5 integer multiplications.
+
+ // When the x coordinates are the same for two points on the curve, the
+ // y coordinates either must be the same, in which case it is point
+ // doubling, or they are opposite and the result is the point at
+ // infinity per the group law for elliptic curve cryptography.
+ x1.Normalize()
+ y1.Normalize()
+ x2.Normalize()
+ y2.Normalize()
+ if x1.Equals(x2) {
+ if y1.Equals(y2) {
+ // Since x1 == x2 and y1 == y2, point doubling must be
+ // done, otherwise the addition would end up dividing
+ // by zero.
+ curve.doubleJacobian(x1, y1, z1, x3, y3, z3)
+ return
+ }
+
+ // Since x1 == x2 and y1 == -y2, the sum is the point at
+ // infinity per the group law.
+ x3.SetInt(0)
+ y3.SetInt(0)
+ z3.SetInt(0)
+ return
+ }
+
+ // Calculate X3, Y3, and Z3 according to the intermediate elements
+ // breakdown above.
+ var h, i, j, r, v fieldVal
+ var negJ, neg2V, negX3 fieldVal
+ h.Set(x1).Negate(1).Add(x2) // H = X2-X1 (mag: 3)
+ i.SquareVal(&h).MulInt(4) // I = 4*H^2 (mag: 4)
+ j.Mul2(&h, &i) // J = H*I (mag: 1)
+ r.Set(y1).Negate(1).Add(y2).MulInt(2) // r = 2*(Y2-Y1) (mag: 6)
+ v.Mul2(x1, &i) // V = X1*I (mag: 1)
+ negJ.Set(&j).Negate(1) // negJ = -J (mag: 2)
+ neg2V.Set(&v).MulInt(2).Negate(2) // neg2V = -(2*V) (mag: 3)
+ x3.Set(&r).Square().Add(&negJ).Add(&neg2V) // X3 = r^2-J-2*V (mag: 6)
+ negX3.Set(x3).Negate(6) // negX3 = -X3 (mag: 7)
+ j.Mul(y1).MulInt(2).Negate(2) // J = -(2*Y1*J) (mag: 3)
+ y3.Set(&v).Add(&negX3).Mul(&r).Add(&j) // Y3 = r*(V-X3)-2*Y1*J (mag: 4)
+ z3.Set(&h).MulInt(2) // Z3 = 2*H (mag: 6)
+
+ // Normalize the resulting field values to a magnitude of 1 as needed.
+ x3.Normalize()
+ y3.Normalize()
+ z3.Normalize()
+}
+
+// addZ1EqualsZ2 adds two Jacobian points that are already known to have the
+// same z value and stores the result in (x3, y3, z3). That is to say
+// (x1, y1, z1) + (x2, y2, z1) = (x3, y3, z3). It performs faster addition than
+// the generic add routine since less arithmetic is needed due to the known
+// equivalence.
+func (curve *KoblitzCurve) addZ1EqualsZ2(x1, y1, z1, x2, y2, x3, y3, z3 *fieldVal) {
+ // To compute the point addition efficiently, this implementation splits
+ // the equation into intermediate elements which are used to minimize
+ // the number of field multiplications using a slightly modified version
+ // of the method shown at:
+ // http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-mmadd-2007-bl
+ //
+ // In particular it performs the calculations using the following:
+ // A = X2-X1, B = A^2, C=Y2-Y1, D = C^2, E = X1*B, F = X2*B
+ // X3 = D-E-F, Y3 = C*(E-X3)-Y1*(F-E), Z3 = Z1*A
+ //
+ // This results in a cost of 5 field multiplications, 2 field squarings,
+ // 9 field additions, and 0 integer multiplications.
+
+ // When the x coordinates are the same for two points on the curve, the
+ // y coordinates either must be the same, in which case it is point
+ // doubling, or they are opposite and the result is the point at
+ // infinity per the group law for elliptic curve cryptography.
+ x1.Normalize()
+ y1.Normalize()
+ x2.Normalize()
+ y2.Normalize()
+ if x1.Equals(x2) {
+ if y1.Equals(y2) {
+ // Since x1 == x2 and y1 == y2, point doubling must be
+ // done, otherwise the addition would end up dividing
+ // by zero.
+ curve.doubleJacobian(x1, y1, z1, x3, y3, z3)
+ return
+ }
+
+ // Since x1 == x2 and y1 == -y2, the sum is the point at
+ // infinity per the group law.
+ x3.SetInt(0)
+ y3.SetInt(0)
+ z3.SetInt(0)
+ return
+ }
+
+ // Calculate X3, Y3, and Z3 according to the intermediate elements
+ // breakdown above.
+ var a, b, c, d, e, f fieldVal
+ var negX1, negY1, negE, negX3 fieldVal
+ negX1.Set(x1).Negate(1) // negX1 = -X1 (mag: 2)
+ negY1.Set(y1).Negate(1) // negY1 = -Y1 (mag: 2)
+ a.Set(&negX1).Add(x2) // A = X2-X1 (mag: 3)
+ b.SquareVal(&a) // B = A^2 (mag: 1)
+ c.Set(&negY1).Add(y2) // C = Y2-Y1 (mag: 3)
+ d.SquareVal(&c) // D = C^2 (mag: 1)
+ e.Mul2(x1, &b) // E = X1*B (mag: 1)
+ negE.Set(&e).Negate(1) // negE = -E (mag: 2)
+ f.Mul2(x2, &b) // F = X2*B (mag: 1)
+ x3.Add2(&e, &f).Negate(3).Add(&d) // X3 = D-E-F (mag: 5)
+ negX3.Set(x3).Negate(5).Normalize() // negX3 = -X3 (mag: 1)
+ y3.Set(y1).Mul(f.Add(&negE)).Negate(3) // Y3 = -(Y1*(F-E)) (mag: 4)
+ y3.Add(e.Add(&negX3).Mul(&c)) // Y3 = C*(E-X3)+Y3 (mag: 5)
+ z3.Mul2(z1, &a) // Z3 = Z1*A (mag: 1)
+
+ // Normalize the resulting field values to a magnitude of 1 as needed.
+ x3.Normalize()
+ y3.Normalize()
+}
+
+// addZ2EqualsOne adds two Jacobian points when the second point is already
+// known to have a z value of 1 (and the z value for the first point is not 1)
+// and stores the result in (x3, y3, z3). That is to say (x1, y1, z1) +
+// (x2, y2, 1) = (x3, y3, z3). It performs faster addition than the generic
+// add routine since less arithmetic is needed due to the ability to avoid
+// multiplications by the second point's z value.
+func (curve *KoblitzCurve) addZ2EqualsOne(x1, y1, z1, x2, y2, x3, y3, z3 *fieldVal) {
+ // To compute the point addition efficiently, this implementation splits
+ // the equation into intermediate elements which are used to minimize
+ // the number of field multiplications using the method shown at:
+ // http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-madd-2007-bl
+ //
+ // In particular it performs the calculations using the following:
+ // Z1Z1 = Z1^2, U2 = X2*Z1Z1, S2 = Y2*Z1*Z1Z1, H = U2-X1, HH = H^2,
+ // I = 4*HH, J = H*I, r = 2*(S2-Y1), V = X1*I
+ // X3 = r^2-J-2*V, Y3 = r*(V-X3)-2*Y1*J, Z3 = (Z1+H)^2-Z1Z1-HH
+ //
+ // This results in a cost of 7 field multiplications, 4 field squarings,
+ // 9 field additions, and 4 integer multiplications.
+
+ // When the x coordinates are the same for two points on the curve, the
+ // y coordinates either must be the same, in which case it is point
+ // doubling, or they are opposite and the result is the point at
+ // infinity per the group law for elliptic curve cryptography. Since
+ // any number of Jacobian coordinates can represent the same affine
+ // point, the x and y values need to be converted to like terms. Due to
+ // the assumption made for this function that the second point has a z
+ // value of 1 (z2=1), the first point is already "converted".
+ var z1z1, u2, s2 fieldVal
+ x1.Normalize()
+ y1.Normalize()
+ z1z1.SquareVal(z1) // Z1Z1 = Z1^2 (mag: 1)
+ u2.Set(x2).Mul(&z1z1).Normalize() // U2 = X2*Z1Z1 (mag: 1)
+ s2.Set(y2).Mul(&z1z1).Mul(z1).Normalize() // S2 = Y2*Z1*Z1Z1 (mag: 1)
+ if x1.Equals(&u2) {
+ if y1.Equals(&s2) {
+ // Since x1 == x2 and y1 == y2, point doubling must be
+ // done, otherwise the addition would end up dividing
+ // by zero.
+ curve.doubleJacobian(x1, y1, z1, x3, y3, z3)
+ return
+ }
+
+ // Since x1 == x2 and y1 == -y2, the sum is the point at
+ // infinity per the group law.
+ x3.SetInt(0)
+ y3.SetInt(0)
+ z3.SetInt(0)
+ return
+ }
+
+ // Calculate X3, Y3, and Z3 according to the intermediate elements
+ // breakdown above.
+ var h, hh, i, j, r, rr, v fieldVal
+ var negX1, negY1, negX3 fieldVal
+ negX1.Set(x1).Negate(1) // negX1 = -X1 (mag: 2)
+ h.Add2(&u2, &negX1) // H = U2-X1 (mag: 3)
+ hh.SquareVal(&h) // HH = H^2 (mag: 1)
+ i.Set(&hh).MulInt(4) // I = 4 * HH (mag: 4)
+ j.Mul2(&h, &i) // J = H*I (mag: 1)
+ negY1.Set(y1).Negate(1) // negY1 = -Y1 (mag: 2)
+ r.Set(&s2).Add(&negY1).MulInt(2) // r = 2*(S2-Y1) (mag: 6)
+ rr.SquareVal(&r) // rr = r^2 (mag: 1)
+ v.Mul2(x1, &i) // V = X1*I (mag: 1)
+ x3.Set(&v).MulInt(2).Add(&j).Negate(3) // X3 = -(J+2*V) (mag: 4)
+ x3.Add(&rr) // X3 = r^2+X3 (mag: 5)
+ negX3.Set(x3).Negate(5) // negX3 = -X3 (mag: 6)
+ y3.Set(y1).Mul(&j).MulInt(2).Negate(2) // Y3 = -(2*Y1*J) (mag: 3)
+ y3.Add(v.Add(&negX3).Mul(&r)) // Y3 = r*(V-X3)+Y3 (mag: 4)
+ z3.Add2(z1, &h).Square() // Z3 = (Z1+H)^2 (mag: 1)
+ z3.Add(z1z1.Add(&hh).Negate(2)) // Z3 = Z3-(Z1Z1+HH) (mag: 4)
+
+ // Normalize the resulting field values to a magnitude of 1 as needed.
+ x3.Normalize()
+ y3.Normalize()
+ z3.Normalize()
+}
+
+// addGeneric adds two Jacobian points (x1, y1, z1) and (x2, y2, z2) without any
+// assumptions about the z values of the two points and stores the result in
+// (x3, y3, z3). That is to say (x1, y1, z1) + (x2, y2, z2) = (x3, y3, z3). It
+// is the slowest of the add routines due to requiring the most arithmetic.
+func (curve *KoblitzCurve) addGeneric(x1, y1, z1, x2, y2, z2, x3, y3, z3 *fieldVal) {
+ // To compute the point addition efficiently, this implementation splits
+ // the equation into intermediate elements which are used to minimize
+ // the number of field multiplications using the method shown at:
+ // http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-add-2007-bl
+ //
+ // In particular it performs the calculations using the following:
+ // Z1Z1 = Z1^2, Z2Z2 = Z2^2, U1 = X1*Z2Z2, U2 = X2*Z1Z1, S1 = Y1*Z2*Z2Z2
+ // S2 = Y2*Z1*Z1Z1, H = U2-U1, I = (2*H)^2, J = H*I, r = 2*(S2-S1)
+ // V = U1*I
+ // X3 = r^2-J-2*V, Y3 = r*(V-X3)-2*S1*J, Z3 = ((Z1+Z2)^2-Z1Z1-Z2Z2)*H
+ //
+ // This results in a cost of 11 field multiplications, 5 field squarings,
+ // 9 field additions, and 4 integer multiplications.
+
+ // When the x coordinates are the same for two points on the curve, the
+ // y coordinates either must be the same, in which case it is point
+ // doubling, or they are opposite and the result is the point at
+ // infinity. Since any number of Jacobian coordinates can represent the
+ // same affine point, the x and y values need to be converted to like
+ // terms.
+ var z1z1, z2z2, u1, u2, s1, s2 fieldVal
+ z1z1.SquareVal(z1) // Z1Z1 = Z1^2 (mag: 1)
+ z2z2.SquareVal(z2) // Z2Z2 = Z2^2 (mag: 1)
+ u1.Set(x1).Mul(&z2z2).Normalize() // U1 = X1*Z2Z2 (mag: 1)
+ u2.Set(x2).Mul(&z1z1).Normalize() // U2 = X2*Z1Z1 (mag: 1)
+ s1.Set(y1).Mul(&z2z2).Mul(z2).Normalize() // S1 = Y1*Z2*Z2Z2 (mag: 1)
+ s2.Set(y2).Mul(&z1z1).Mul(z1).Normalize() // S2 = Y2*Z1*Z1Z1 (mag: 1)
+ if u1.Equals(&u2) {
+ if s1.Equals(&s2) {
+ // Since x1 == x2 and y1 == y2, point doubling must be
+ // done, otherwise the addition would end up dividing
+ // by zero.
+ curve.doubleJacobian(x1, y1, z1, x3, y3, z3)
+ return
+ }
+
+ // Since x1 == x2 and y1 == -y2, the sum is the point at
+ // infinity per the group law.
+ x3.SetInt(0)
+ y3.SetInt(0)
+ z3.SetInt(0)
+ return
+ }
+
+ // Calculate X3, Y3, and Z3 according to the intermediate elements
+ // breakdown above.
+ var h, i, j, r, rr, v fieldVal
+ var negU1, negS1, negX3 fieldVal
+ negU1.Set(&u1).Negate(1) // negU1 = -U1 (mag: 2)
+ h.Add2(&u2, &negU1) // H = U2-U1 (mag: 3)
+ i.Set(&h).MulInt(2).Square() // I = (2*H)^2 (mag: 2)
+ j.Mul2(&h, &i) // J = H*I (mag: 1)
+ negS1.Set(&s1).Negate(1) // negS1 = -S1 (mag: 2)
+ r.Set(&s2).Add(&negS1).MulInt(2) // r = 2*(S2-S1) (mag: 6)
+ rr.SquareVal(&r) // rr = r^2 (mag: 1)
+ v.Mul2(&u1, &i) // V = U1*I (mag: 1)
+ x3.Set(&v).MulInt(2).Add(&j).Negate(3) // X3 = -(J+2*V) (mag: 4)
+ x3.Add(&rr) // X3 = r^2+X3 (mag: 5)
+ negX3.Set(x3).Negate(5) // negX3 = -X3 (mag: 6)
+ y3.Mul2(&s1, &j).MulInt(2).Negate(2) // Y3 = -(2*S1*J) (mag: 3)
+ y3.Add(v.Add(&negX3).Mul(&r)) // Y3 = r*(V-X3)+Y3 (mag: 4)
+ z3.Add2(z1, z2).Square() // Z3 = (Z1+Z2)^2 (mag: 1)
+ z3.Add(z1z1.Add(&z2z2).Negate(2)) // Z3 = Z3-(Z1Z1+Z2Z2) (mag: 4)
+ z3.Mul(&h) // Z3 = Z3*H (mag: 1)
+
+ // Normalize the resulting field values to a magnitude of 1 as needed.
+ x3.Normalize()
+ y3.Normalize()
+}
+
+// addJacobian adds the passed Jacobian points (x1, y1, z1) and (x2, y2, z2)
+// together and stores the result in (x3, y3, z3).
+func (curve *KoblitzCurve) addJacobian(x1, y1, z1, x2, y2, z2, x3, y3, z3 *fieldVal) {
+ // A point at infinity is the identity according to the group law for
+ // elliptic curve cryptography. Thus, ∞ + P = P and P + ∞ = P.
+ if (x1.IsZero() && y1.IsZero()) || z1.IsZero() {
+ x3.Set(x2)
+ y3.Set(y2)
+ z3.Set(z2)
+ return
+ }
+ if (x2.IsZero() && y2.IsZero()) || z2.IsZero() {
+ x3.Set(x1)
+ y3.Set(y1)
+ z3.Set(z1)
+ return
+ }
+
+ // Faster point addition can be achieved when certain assumptions are
+ // met. For example, when both points have the same z value, arithmetic
+ // on the z values can be avoided. This section thus checks for these
+ // conditions and calls an appropriate add function which is accelerated
+ // by using those assumptions.
+ z1.Normalize()
+ z2.Normalize()
+ isZ1One := z1.Equals(fieldOne)
+ isZ2One := z2.Equals(fieldOne)
+ switch {
+ case isZ1One && isZ2One:
+ curve.addZ1AndZ2EqualsOne(x1, y1, z1, x2, y2, x3, y3, z3)
+ return
+ case z1.Equals(z2):
+ curve.addZ1EqualsZ2(x1, y1, z1, x2, y2, x3, y3, z3)
+ return
+ case isZ2One:
+ curve.addZ2EqualsOne(x1, y1, z1, x2, y2, x3, y3, z3)
+ return
+ }
+
+ // None of the above assumptions are true, so fall back to generic
+ // point addition.
+ curve.addGeneric(x1, y1, z1, x2, y2, z2, x3, y3, z3)
+}
+
+// Add returns the sum of (x1,y1) and (x2,y2). Part of the elliptic.Curve
+// interface.
+func (curve *KoblitzCurve) Add(x1, y1, x2, y2 *big.Int) (*big.Int, *big.Int) {
+ // A point at infinity is the identity according to the group law for
+ // elliptic curve cryptography. Thus, ∞ + P = P and P + ∞ = P.
+ if x1.Sign() == 0 && y1.Sign() == 0 {
+ return x2, y2
+ }
+ if x2.Sign() == 0 && y2.Sign() == 0 {
+ return x1, y1
+ }
+
+ // Convert the affine coordinates from big integers to field values
+ // and do the point addition in Jacobian projective space.
+ fx1, fy1 := curve.bigAffineToField(x1, y1)
+ fx2, fy2 := curve.bigAffineToField(x2, y2)
+ fx3, fy3, fz3 := new(fieldVal), new(fieldVal), new(fieldVal)
+ fOne := new(fieldVal).SetInt(1)
+ curve.addJacobian(fx1, fy1, fOne, fx2, fy2, fOne, fx3, fy3, fz3)
+
+ // Convert the Jacobian coordinate field values back to affine big
+ // integers.
+ return curve.fieldJacobianToBigAffine(fx3, fy3, fz3)
+}
+
+// doubleZ1EqualsOne performs point doubling on the passed Jacobian point
+// when the point is already known to have a z value of 1 and stores
+// the result in (x3, y3, z3). That is to say (x3, y3, z3) = 2*(x1, y1, 1). It
+// performs faster point doubling than the generic routine since less arithmetic
+// is needed due to the ability to avoid multiplication by the z value.
+func (curve *KoblitzCurve) doubleZ1EqualsOne(x1, y1, x3, y3, z3 *fieldVal) {
+ // This function uses the assumptions that z1 is 1, thus the point
+ // doubling formulas reduce to:
+ //
+ // X3 = (3*X1^2)^2 - 8*X1*Y1^2
+ // Y3 = (3*X1^2)*(4*X1*Y1^2 - X3) - 8*Y1^4
+ // Z3 = 2*Y1
+ //
+ // To compute the above efficiently, this implementation splits the
+ // equation into intermediate elements which are used to minimize the
+ // number of field multiplications in favor of field squarings which
+ // are roughly 35% faster than field multiplications with the current
+ // implementation at the time this was written.
+ //
+ // This uses a slightly modified version of the method shown at:
+ // http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-mdbl-2007-bl
+ //
+ // In particular it performs the calculations using the following:
+ // A = X1^2, B = Y1^2, C = B^2, D = 2*((X1+B)^2-A-C)
+ // E = 3*A, F = E^2, X3 = F-2*D, Y3 = E*(D-X3)-8*C
+ // Z3 = 2*Y1
+ //
+ // This results in a cost of 1 field multiplication, 5 field squarings,
+ // 6 field additions, and 5 integer multiplications.
+ var a, b, c, d, e, f fieldVal
+ z3.Set(y1).MulInt(2) // Z3 = 2*Y1 (mag: 2)
+ a.SquareVal(x1) // A = X1^2 (mag: 1)
+ b.SquareVal(y1) // B = Y1^2 (mag: 1)
+ c.SquareVal(&b) // C = B^2 (mag: 1)
+ b.Add(x1).Square() // B = (X1+B)^2 (mag: 1)
+ d.Set(&a).Add(&c).Negate(2) // D = -(A+C) (mag: 3)
+ d.Add(&b).MulInt(2) // D = 2*(B+D)(mag: 8)
+ e.Set(&a).MulInt(3) // E = 3*A (mag: 3)
+ f.SquareVal(&e) // F = E^2 (mag: 1)
+ x3.Set(&d).MulInt(2).Negate(16) // X3 = -(2*D) (mag: 17)
+ x3.Add(&f) // X3 = F+X3 (mag: 18)
+ f.Set(x3).Negate(18).Add(&d).Normalize() // F = D-X3 (mag: 1)
+ y3.Set(&c).MulInt(8).Negate(8) // Y3 = -(8*C) (mag: 9)
+ y3.Add(f.Mul(&e)) // Y3 = E*F+Y3 (mag: 10)
+
+ // Normalize the field values back to a magnitude of 1.
+ x3.Normalize()
+ y3.Normalize()
+ z3.Normalize()
+}
+
+// doubleGeneric performs point doubling on the passed Jacobian point without
+// any assumptions about the z value and stores the result in (x3, y3, z3).
+// That is to say (x3, y3, z3) = 2*(x1, y1, z1). It is the slowest of the point
+// doubling routines due to requiring the most arithmetic.
+func (curve *KoblitzCurve) doubleGeneric(x1, y1, z1, x3, y3, z3 *fieldVal) {
+ // Point doubling formula for Jacobian coordinates for the secp256k1
+ // curve:
+ // X3 = (3*X1^2)^2 - 8*X1*Y1^2
+ // Y3 = (3*X1^2)*(4*X1*Y1^2 - X3) - 8*Y1^4
+ // Z3 = 2*Y1*Z1
+ //
+ // To compute the above efficiently, this implementation splits the
+ // equation into intermediate elements which are used to minimize the
+ // number of field multiplications in favor of field squarings which
+ // are roughly 35% faster than field multiplications with the current
+ // implementation at the time this was written.
+ //
+ // This uses a slightly modified version of the method shown at:
+ // http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-dbl-2009-l
+ //
+ // In particular it performs the calculations using the following:
+ // A = X1^2, B = Y1^2, C = B^2, D = 2*((X1+B)^2-A-C)
+ // E = 3*A, F = E^2, X3 = F-2*D, Y3 = E*(D-X3)-8*C
+ // Z3 = 2*Y1*Z1
+ //
+ // This results in a cost of 1 field multiplication, 5 field squarings,
+ // 6 field additions, and 5 integer multiplications.
+ var a, b, c, d, e, f fieldVal
+ z3.Mul2(y1, z1).MulInt(2) // Z3 = 2*Y1*Z1 (mag: 2)
+ a.SquareVal(x1) // A = X1^2 (mag: 1)
+ b.SquareVal(y1) // B = Y1^2 (mag: 1)
+ c.SquareVal(&b) // C = B^2 (mag: 1)
+ b.Add(x1).Square() // B = (X1+B)^2 (mag: 1)
+ d.Set(&a).Add(&c).Negate(2) // D = -(A+C) (mag: 3)
+ d.Add(&b).MulInt(2) // D = 2*(B+D)(mag: 8)
+ e.Set(&a).MulInt(3) // E = 3*A (mag: 3)
+ f.SquareVal(&e) // F = E^2 (mag: 1)
+ x3.Set(&d).MulInt(2).Negate(16) // X3 = -(2*D) (mag: 17)
+ x3.Add(&f) // X3 = F+X3 (mag: 18)
+ f.Set(x3).Negate(18).Add(&d).Normalize() // F = D-X3 (mag: 1)
+ y3.Set(&c).MulInt(8).Negate(8) // Y3 = -(8*C) (mag: 9)
+ y3.Add(f.Mul(&e)) // Y3 = E*F+Y3 (mag: 10)
+
+ // Normalize the field values back to a magnitude of 1.
+ x3.Normalize()
+ y3.Normalize()
+ z3.Normalize()
+}
+
+// doubleJacobian doubles the passed Jacobian point (x1, y1, z1) and stores the
+// result in (x3, y3, z3).
+func (curve *KoblitzCurve) doubleJacobian(x1, y1, z1, x3, y3, z3 *fieldVal) {
+ // Doubling a point at infinity is still infinity.
+ if y1.IsZero() || z1.IsZero() {
+ x3.SetInt(0)
+ y3.SetInt(0)
+ z3.SetInt(0)
+ return
+ }
+
+ // Slightly faster point doubling can be achieved when the z value is 1
+ // by avoiding the multiplication on the z value. This section calls
+ // a point doubling function which is accelerated by using that
+ // assumption when possible.
+ if z1.Normalize().Equals(fieldOne) {
+ curve.doubleZ1EqualsOne(x1, y1, x3, y3, z3)
+ return
+ }
+
+ // Fall back to generic point doubling which works with arbitrary z
+ // values.
+ curve.doubleGeneric(x1, y1, z1, x3, y3, z3)
+}
+
+// Double returns 2*(x1,y1). Part of the elliptic.Curve interface.
+func (curve *KoblitzCurve) Double(x1, y1 *big.Int) (*big.Int, *big.Int) {
+ if y1.Sign() == 0 {
+ return new(big.Int), new(big.Int)
+ }
+
+ // Convert the affine coordinates from big integers to field values
+ // and do the point doubling in Jacobian projective space.
+ fx1, fy1 := curve.bigAffineToField(x1, y1)
+ fx3, fy3, fz3 := new(fieldVal), new(fieldVal), new(fieldVal)
+ fOne := new(fieldVal).SetInt(1)
+ curve.doubleJacobian(fx1, fy1, fOne, fx3, fy3, fz3)
+
+ // Convert the Jacobian coordinate field values back to affine big
+ // integers.
+ return curve.fieldJacobianToBigAffine(fx3, fy3, fz3)
+}
+
+// splitK returns a balanced length-two representation of k and their signs.
+// This is algorithm 3.74 from [GECC].
+//
+// One thing of note about this algorithm is that no matter what c1 and c2 are,
+// the final equation of k = k1 + k2 * lambda (mod n) will hold. This is
+// provable mathematically due to how a1/b1/a2/b2 are computed.
+//
+// c1 and c2 are chosen to minimize the max(k1,k2).
+func (curve *KoblitzCurve) splitK(k []byte) ([]byte, []byte, int, int) {
+ // All math here is done with big.Int, which is slow.
+ // At some point, it might be useful to write something similar to
+ // fieldVal but for N instead of P as the prime field if this ends up
+ // being a bottleneck.
+ bigIntK := new(big.Int)
+ c1, c2 := new(big.Int), new(big.Int)
+ tmp1, tmp2 := new(big.Int), new(big.Int)
+ k1, k2 := new(big.Int), new(big.Int)
+
+ bigIntK.SetBytes(k)
+ // c1 = round(b2 * k / n) from step 4.
+ // Rounding isn't really necessary and costs too much, hence skipped
+ c1.Mul(curve.b2, bigIntK)
+ c1.Div(c1, curve.N)
+ // c2 = round(b1 * k / n) from step 4 (sign reversed to optimize one step)
+ // Rounding isn't really necessary and costs too much, hence skipped
+ c2.Mul(curve.b1, bigIntK)
+ c2.Div(c2, curve.N)
+ // k1 = k - c1 * a1 - c2 * a2 from step 5 (note c2's sign is reversed)
+ tmp1.Mul(c1, curve.a1)
+ tmp2.Mul(c2, curve.a2)
+ k1.Sub(bigIntK, tmp1)
+ k1.Add(k1, tmp2)
+ // k2 = - c1 * b1 - c2 * b2 from step 5 (note c2's sign is reversed)
+ tmp1.Mul(c1, curve.b1)
+ tmp2.Mul(c2, curve.b2)
+ k2.Sub(tmp2, tmp1)
+
+ // Note Bytes() throws out the sign of k1 and k2. This matters
+ // since k1 and/or k2 can be negative. Hence, we pass that
+ // back separately.
+ return k1.Bytes(), k2.Bytes(), k1.Sign(), k2.Sign()
+}
+
+// moduloReduce reduces k from more than 32 bytes to 32 bytes and under. This
+// is done by doing a simple modulo curve.N. We can do this since G^N = 1 and
+// thus any other valid point on the elliptic curve has the same order.
+func (curve *KoblitzCurve) moduloReduce(k []byte) []byte {
+ // Since the order of G is curve.N, we can use a much smaller number
+ // by doing modulo curve.N
+ if len(k) > curve.byteSize {
+ // Reduce k by performing modulo curve.N.
+ tmpK := new(big.Int).SetBytes(k)
+ tmpK.Mod(tmpK, curve.N)
+ return tmpK.Bytes()
+ }
+
+ return k
+}
+
+// NAF takes a positive integer k and returns the Non-Adjacent Form (NAF) as two
+// byte slices. The first is where 1s will be. The second is where -1s will
+// be. NAF is convenient in that on average, only 1/3rd of its values are
+// non-zero. This is algorithm 3.30 from [GECC].
+//
+// Essentially, this makes it possible to minimize the number of operations
+// since the resulting ints returned will be at least 50% 0s.
+func NAF(k []byte) ([]byte, []byte) {
+ // The essence of this algorithm is that whenever we have consecutive 1s
+ // in the binary, we want to put a -1 in the lowest bit and get a bunch
+ // of 0s up to the highest bit of consecutive 1s. This is due to this
+ // identity:
+ // 2^n + 2^(n-1) + 2^(n-2) + ... + 2^(n-k) = 2^(n+1) - 2^(n-k)
+ //
+ // The algorithm thus may need to go 1 more bit than the length of the
+ // bits we actually have, hence bits being 1 bit longer than was
+ // necessary. Since we need to know whether adding will cause a carry,
+ // we go from right-to-left in this addition.
+ var carry, curIsOne, nextIsOne bool
+ // these default to zero
+ retPos := make([]byte, len(k)+1)
+ retNeg := make([]byte, len(k)+1)
+ for i := len(k) - 1; i >= 0; i-- {
+ curByte := k[i]
+ for j := uint(0); j < 8; j++ {
+ curIsOne = curByte&1 == 1
+ if j == 7 {
+ if i == 0 {
+ nextIsOne = false
+ } else {
+ nextIsOne = k[i-1]&1 == 1
+ }
+ } else {
+ nextIsOne = curByte&2 == 2
+ }
+ if carry {
+ if curIsOne {
+ // This bit is 1, so continue to carry
+ // and don't need to do anything.
+ } else {
+ // We've hit a 0 after some number of
+ // 1s.
+ if nextIsOne {
+ // Start carrying again since
+ // a new sequence of 1s is
+ // starting.
+ retNeg[i+1] += 1 << j
+ } else {
+ // Stop carrying since 1s have
+ // stopped.
+ carry = false
+ retPos[i+1] += 1 << j
+ }
+ }
+ } else if curIsOne {
+ if nextIsOne {
+ // If this is the start of at least 2
+ // consecutive 1s, set the current one
+ // to -1 and start carrying.
+ retNeg[i+1] += 1 << j
+ carry = true
+ } else {
+ // This is a singleton, not consecutive
+ // 1s.
+ retPos[i+1] += 1 << j
+ }
+ }
+ curByte >>= 1
+ }
+ }
+ if carry {
+ retPos[0] = 1
+ }
+
+ return retPos, retNeg
+}
+
+// ScalarMult returns k*(Bx, By) where k is a big endian integer.
+// Part of the elliptic.Curve interface.
+func (curve *KoblitzCurve) ScalarMult(Bx, By *big.Int, k []byte) (*big.Int, *big.Int) {
+ // Point Q = ∞ (point at infinity).
+ qx, qy, qz := new(fieldVal), new(fieldVal), new(fieldVal)
+
+ // Decompose K into k1 and k2 in order to halve the number of EC ops.
+ // See Algorithm 3.74 in [GECC].
+ k1, k2, signK1, signK2 := curve.splitK(curve.moduloReduce(k))
+
+ // The main equation here to remember is:
+ // k * P = k1 * P + k2 * ϕ(P)
+ //
+ // P1 below is P in the equation, P2 below is ϕ(P) in the equation
+ p1x, p1y := curve.bigAffineToField(Bx, By)
+ p1yNeg := new(fieldVal).NegateVal(p1y, 1)
+ p1z := new(fieldVal).SetInt(1)
+
+ // NOTE: ϕ(x,y) = (βx,y). The Jacobian z coordinate is 1, so this math
+ // goes through.
+ p2x := new(fieldVal).Mul2(p1x, curve.beta)
+ p2y := new(fieldVal).Set(p1y)
+ p2yNeg := new(fieldVal).NegateVal(p2y, 1)
+ p2z := new(fieldVal).SetInt(1)
+
+ // Flip the positive and negative values of the points as needed
+ // depending on the signs of k1 and k2. As mentioned in the equation
+ // above, each of k1 and k2 are multiplied by the respective point.
+ // Since -k * P is the same thing as k * -P, and the group law for
+ // elliptic curves states that P(x, y) = -P(x, -y), it's faster and
+ // simplifies the code to just make the point negative.
+ if signK1 == -1 {
+ p1y, p1yNeg = p1yNeg, p1y
+ }
+ if signK2 == -1 {
+ p2y, p2yNeg = p2yNeg, p2y
+ }
+
+ // NAF versions of k1 and k2 should have a lot more zeros.
+ //
+ // The Pos version of the bytes contain the +1s and the Neg versions
+ // contain the -1s.
+ k1PosNAF, k1NegNAF := NAF(k1)
+ k2PosNAF, k2NegNAF := NAF(k2)
+ k1Len := len(k1PosNAF)
+ k2Len := len(k2PosNAF)
+
+ m := k1Len
+ if m < k2Len {
+ m = k2Len
+ }
+
+ // Add left-to-right using the NAF optimization. See algorithm 3.77
+ // from [GECC]. This should be faster overall since there will be a lot
+ // more instances of 0, hence reducing the number of Jacobian additions
+ // at the cost of 1 possible extra doubling.
+ var k1BytePos, k1ByteNeg, k2BytePos, k2ByteNeg byte
+ for i := 0; i < m; i++ {
+ // Since we're going left-to-right, pad the front with 0s.
+ if i < m-k1Len {
+ k1BytePos = 0
+ k1ByteNeg = 0
+ } else {
+ k1BytePos = k1PosNAF[i-(m-k1Len)]
+ k1ByteNeg = k1NegNAF[i-(m-k1Len)]
+ }
+ if i < m-k2Len {
+ k2BytePos = 0
+ k2ByteNeg = 0
+ } else {
+ k2BytePos = k2PosNAF[i-(m-k2Len)]
+ k2ByteNeg = k2NegNAF[i-(m-k2Len)]
+ }
+
+ for j := 7; j >= 0; j-- {
+ // Q = 2 * Q
+ curve.doubleJacobian(qx, qy, qz, qx, qy, qz)
+
+ if k1BytePos&0x80 == 0x80 {
+ curve.addJacobian(qx, qy, qz, p1x, p1y, p1z,
+ qx, qy, qz)
+ } else if k1ByteNeg&0x80 == 0x80 {
+ curve.addJacobian(qx, qy, qz, p1x, p1yNeg, p1z,
+ qx, qy, qz)
+ }
+
+ if k2BytePos&0x80 == 0x80 {
+ curve.addJacobian(qx, qy, qz, p2x, p2y, p2z,
+ qx, qy, qz)
+ } else if k2ByteNeg&0x80 == 0x80 {
+ curve.addJacobian(qx, qy, qz, p2x, p2yNeg, p2z,
+ qx, qy, qz)
+ }
+ k1BytePos <<= 1
+ k1ByteNeg <<= 1
+ k2BytePos <<= 1
+ k2ByteNeg <<= 1
+ }
+ }
+
+ // Convert the Jacobian coordinate field values back to affine big.Ints.
+ return curve.fieldJacobianToBigAffine(qx, qy, qz)
+}
+
+// ScalarBaseMult returns k*G where G is the base point of the group and k is a
+// big endian integer.
+// Part of the elliptic.Curve interface.
+func (curve *KoblitzCurve) ScalarBaseMult(k []byte) (*big.Int, *big.Int) {
+ newK := curve.moduloReduce(k)
+ diff := len(curve.bytePoints) - len(newK)
+
+ // Point Q = ∞ (point at infinity).
+ qx, qy, qz := new(fieldVal), new(fieldVal), new(fieldVal)
+
+ // curve.bytePoints has all 256 byte points for each 8-bit window. The
+ // strategy is to add up the byte points. This is best understood by
+ // expressing k in base-256 which it already sort of is.
+ // Each "digit" in the 8-bit window can be looked up using bytePoints
+ // and added together.
+ for i, byteVal := range newK {
+ p := curve.bytePoints[diff+i][byteVal]
+ curve.addJacobian(qx, qy, qz, &p[0], &p[1], &p[2], qx, qy, qz)
+ }
+ return curve.fieldJacobianToBigAffine(qx, qy, qz)
+}
+
+// QPlus1Div4 returns the Q+1/4 constant for the curve for use in calculating
+// square roots via exponention.
+func (curve *KoblitzCurve) QPlus1Div4() *big.Int {
+ return curve.q
+}
+
+var initonce sync.Once
+var secp256k1 KoblitzCurve
+
+func initAll() {
+ initS256()
+}
+
+// fromHex converts the passed hex string into a big integer pointer and will
+// panic is there is an error. This is only provided for the hard-coded
+// constants so errors in the source code can bet detected. It will only (and
+// must only) be called for initialization purposes.
+func fromHex(s string) *big.Int {
+ r, ok := new(big.Int).SetString(s, 16)
+ if !ok {
+ panic("invalid hex in source file: " + s)
+ }
+ return r
+}
+
+func initS256() {
+ // Curve parameters taken from [SECG] section 2.4.1.
+ secp256k1.CurveParams = new(elliptic.CurveParams)
+ secp256k1.P = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F")
+ secp256k1.N = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141")
+ secp256k1.B = fromHex("0000000000000000000000000000000000000000000000000000000000000007")
+ secp256k1.Gx = fromHex("79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798")
+ secp256k1.Gy = fromHex("483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8")
+ secp256k1.BitSize = 256
+ secp256k1.H = 1
+ secp256k1.q = new(big.Int).Div(new(big.Int).Add(secp256k1.P,
+ big.NewInt(1)), big.NewInt(4))
+
+ // Provided for convenience since this gets computed repeatedly.
+ secp256k1.byteSize = secp256k1.BitSize / 8
+
+ // Deserialize and set the pre-computed table used to accelerate scalar
+ // base multiplication. This is hard-coded data, so any errors are
+ // panics because it means something is wrong in the source code.
+ if err := loadS256BytePoints(); err != nil {
+ panic(err)
+ }
+
+ // Next 6 constants are from Hal Finney's bitcointalk.org post:
+ // https://bitcointalk.org/index.php?topic=3238.msg45565#msg45565
+ // May he rest in peace.
+ //
+ // They have also been independently derived from the code in the
+ // EndomorphismVectors function in gensecp256k1.go.
+ secp256k1.lambda = fromHex("5363AD4CC05C30E0A5261C028812645A122E22EA20816678DF02967C1B23BD72")
+ secp256k1.beta = new(fieldVal).SetHex("7AE96A2B657C07106E64479EAC3434E99CF0497512F58995C1396C28719501EE")
+ secp256k1.a1 = fromHex("3086D221A7D46BCDE86C90E49284EB15")
+ secp256k1.b1 = fromHex("-E4437ED6010E88286F547FA90ABFE4C3")
+ secp256k1.a2 = fromHex("114CA50F7A8E2F3F657C1108D9D44CFD8")
+ secp256k1.b2 = fromHex("3086D221A7D46BCDE86C90E49284EB15")
+
+ // Alternatively, we can use the parameters below, however, they seem
+ // to be about 8% slower.
+ // secp256k1.lambda = fromHex("AC9C52B33FA3CF1F5AD9E3FD77ED9BA4A880B9FC8EC739C2E0CFC810B51283CE")
+ // secp256k1.beta = new(fieldVal).SetHex("851695D49A83F8EF919BB86153CBCB16630FB68AED0A766A3EC693D68E6AFA40")
+ // secp256k1.a1 = fromHex("E4437ED6010E88286F547FA90ABFE4C3")
+ // secp256k1.b1 = fromHex("-3086D221A7D46BCDE86C90E49284EB15")
+ // secp256k1.a2 = fromHex("3086D221A7D46BCDE86C90E49284EB15")
+ // secp256k1.b2 = fromHex("114CA50F7A8E2F3F657C1108D9D44CFD8")
+}
+
+// S256 returns a Curve which implements secp256k1.
+func S256() *KoblitzCurve {
+ initonce.Do(initAll)
+ return &secp256k1
+}
diff --git a/vendor/github.com/btcsuite/btcd/btcec/ciphering.go b/vendor/github.com/btcsuite/btcd/btcec/ciphering.go
new file mode 100644
index 0000000000..b18c9b7a30
--- /dev/null
+++ b/vendor/github.com/btcsuite/btcd/btcec/ciphering.go
@@ -0,0 +1,216 @@
+// Copyright (c) 2015-2016 The btcsuite developers
+// Use of this source code is governed by an ISC
+// license that can be found in the LICENSE file.
+
+package btcec
+
+import (
+ "bytes"
+ "crypto/aes"
+ "crypto/cipher"
+ "crypto/hmac"
+ "crypto/rand"
+ "crypto/sha256"
+ "crypto/sha512"
+ "errors"
+ "io"
+)
+
+var (
+ // ErrInvalidMAC occurs when Message Authentication Check (MAC) fails
+ // during decryption. This happens because of either invalid private key or
+ // corrupt ciphertext.
+ ErrInvalidMAC = errors.New("invalid mac hash")
+
+ // errInputTooShort occurs when the input ciphertext to the Decrypt
+ // function is less than 134 bytes long.
+ errInputTooShort = errors.New("ciphertext too short")
+
+ // errUnsupportedCurve occurs when the first two bytes of the encrypted
+ // text aren't 0x02CA (= 712 = secp256k1, from OpenSSL).
+ errUnsupportedCurve = errors.New("unsupported curve")
+
+ errInvalidXLength = errors.New("invalid X length, must be 32")
+ errInvalidYLength = errors.New("invalid Y length, must be 32")
+ errInvalidPadding = errors.New("invalid PKCS#7 padding")
+
+ // 0x02CA = 714
+ ciphCurveBytes = [2]byte{0x02, 0xCA}
+ // 0x20 = 32
+ ciphCoordLength = [2]byte{0x00, 0x20}
+)
+
+// GenerateSharedSecret generates a shared secret based on a private key and a
+// public key using Diffie-Hellman key exchange (ECDH) (RFC 4753).
+// RFC5903 Section 9 states we should only return x.
+func GenerateSharedSecret(privkey *PrivateKey, pubkey *PublicKey) []byte {
+ x, _ := pubkey.Curve.ScalarMult(pubkey.X, pubkey.Y, privkey.D.Bytes())
+ return x.Bytes()
+}
+
+// Encrypt encrypts data for the target public key using AES-256-CBC. It also
+// generates a private key (the pubkey of which is also in the output). The only
+// supported curve is secp256k1. The `structure' that it encodes everything into
+// is:
+//
+// struct {
+// // Initialization Vector used for AES-256-CBC
+// IV [16]byte
+// // Public Key: curve(2) + len_of_pubkeyX(2) + pubkeyX +
+// // len_of_pubkeyY(2) + pubkeyY (curve = 714)
+// PublicKey [70]byte
+// // Cipher text
+// Data []byte
+// // HMAC-SHA-256 Message Authentication Code
+// HMAC [32]byte
+// }
+//
+// The primary aim is to ensure byte compatibility with Pyelliptic. Also, refer
+// to section 5.8.1 of ANSI X9.63 for rationale on this format.
+func Encrypt(pubkey *PublicKey, in []byte) ([]byte, error) {
+ ephemeral, err := NewPrivateKey(S256())
+ if err != nil {
+ return nil, err
+ }
+ ecdhKey := GenerateSharedSecret(ephemeral, pubkey)
+ derivedKey := sha512.Sum512(ecdhKey)
+ keyE := derivedKey[:32]
+ keyM := derivedKey[32:]
+
+ paddedIn := addPKCSPadding(in)
+ // IV + Curve params/X/Y + padded plaintext/ciphertext + HMAC-256
+ out := make([]byte, aes.BlockSize+70+len(paddedIn)+sha256.Size)
+ iv := out[:aes.BlockSize]
+ if _, err = io.ReadFull(rand.Reader, iv); err != nil {
+ return nil, err
+ }
+ // start writing public key
+ pb := ephemeral.PubKey().SerializeUncompressed()
+ offset := aes.BlockSize
+
+ // curve and X length
+ copy(out[offset:offset+4], append(ciphCurveBytes[:], ciphCoordLength[:]...))
+ offset += 4
+ // X
+ copy(out[offset:offset+32], pb[1:33])
+ offset += 32
+ // Y length
+ copy(out[offset:offset+2], ciphCoordLength[:])
+ offset += 2
+ // Y
+ copy(out[offset:offset+32], pb[33:])
+ offset += 32
+
+ // start encryption
+ block, err := aes.NewCipher(keyE)
+ if err != nil {
+ return nil, err
+ }
+ mode := cipher.NewCBCEncrypter(block, iv)
+ mode.CryptBlocks(out[offset:len(out)-sha256.Size], paddedIn)
+
+ // start HMAC-SHA-256
+ hm := hmac.New(sha256.New, keyM)
+ hm.Write(out[:len(out)-sha256.Size]) // everything is hashed
+ copy(out[len(out)-sha256.Size:], hm.Sum(nil)) // write checksum
+
+ return out, nil
+}
+
+// Decrypt decrypts data that was encrypted using the Encrypt function.
+func Decrypt(priv *PrivateKey, in []byte) ([]byte, error) {
+ // IV + Curve params/X/Y + 1 block + HMAC-256
+ if len(in) < aes.BlockSize+70+aes.BlockSize+sha256.Size {
+ return nil, errInputTooShort
+ }
+
+ // read iv
+ iv := in[:aes.BlockSize]
+ offset := aes.BlockSize
+
+ // start reading pubkey
+ if !bytes.Equal(in[offset:offset+2], ciphCurveBytes[:]) {
+ return nil, errUnsupportedCurve
+ }
+ offset += 2
+
+ if !bytes.Equal(in[offset:offset+2], ciphCoordLength[:]) {
+ return nil, errInvalidXLength
+ }
+ offset += 2
+
+ xBytes := in[offset : offset+32]
+ offset += 32
+
+ if !bytes.Equal(in[offset:offset+2], ciphCoordLength[:]) {
+ return nil, errInvalidYLength
+ }
+ offset += 2
+
+ yBytes := in[offset : offset+32]
+ offset += 32
+
+ pb := make([]byte, 65)
+ pb[0] = byte(0x04) // uncompressed
+ copy(pb[1:33], xBytes)
+ copy(pb[33:], yBytes)
+ // check if (X, Y) lies on the curve and create a Pubkey if it does
+ pubkey, err := ParsePubKey(pb, S256())
+ if err != nil {
+ return nil, err
+ }
+
+ // check for cipher text length
+ if (len(in)-aes.BlockSize-offset-sha256.Size)%aes.BlockSize != 0 {
+ return nil, errInvalidPadding // not padded to 16 bytes
+ }
+
+ // read hmac
+ messageMAC := in[len(in)-sha256.Size:]
+
+ // generate shared secret
+ ecdhKey := GenerateSharedSecret(priv, pubkey)
+ derivedKey := sha512.Sum512(ecdhKey)
+ keyE := derivedKey[:32]
+ keyM := derivedKey[32:]
+
+ // verify mac
+ hm := hmac.New(sha256.New, keyM)
+ hm.Write(in[:len(in)-sha256.Size]) // everything is hashed
+ expectedMAC := hm.Sum(nil)
+ if !hmac.Equal(messageMAC, expectedMAC) {
+ return nil, ErrInvalidMAC
+ }
+
+ // start decryption
+ block, err := aes.NewCipher(keyE)
+ if err != nil {
+ return nil, err
+ }
+ mode := cipher.NewCBCDecrypter(block, iv)
+ // same length as ciphertext
+ plaintext := make([]byte, len(in)-offset-sha256.Size)
+ mode.CryptBlocks(plaintext, in[offset:len(in)-sha256.Size])
+
+ return removePKCSPadding(plaintext)
+}
+
+// Implement PKCS#7 padding with block size of 16 (AES block size).
+
+// addPKCSPadding adds padding to a block of data
+func addPKCSPadding(src []byte) []byte {
+ padding := aes.BlockSize - len(src)%aes.BlockSize
+ padtext := bytes.Repeat([]byte{byte(padding)}, padding)
+ return append(src, padtext...)
+}
+
+// removePKCSPadding removes padding from data that was added with addPKCSPadding
+func removePKCSPadding(src []byte) ([]byte, error) {
+ length := len(src)
+ padLength := int(src[length-1])
+ if padLength > aes.BlockSize || length < aes.BlockSize {
+ return nil, errInvalidPadding
+ }
+
+ return src[:length-padLength], nil
+}
diff --git a/vendor/github.com/btcsuite/btcd/btcec/doc.go b/vendor/github.com/btcsuite/btcd/btcec/doc.go
new file mode 100644
index 0000000000..fa8346ab0f
--- /dev/null
+++ b/vendor/github.com/btcsuite/btcd/btcec/doc.go
@@ -0,0 +1,21 @@
+// Copyright (c) 2013-2014 The btcsuite developers
+// Use of this source code is governed by an ISC
+// license that can be found in the LICENSE file.
+
+/*
+Package btcec implements support for the elliptic curves needed for bitcoin.
+
+Bitcoin uses elliptic curve cryptography using koblitz curves
+(specifically secp256k1) for cryptographic functions. See
+http://www.secg.org/collateral/sec2_final.pdf for details on the
+standard.
+
+This package provides the data structures and functions implementing the
+crypto/elliptic Curve interface in order to permit using these curves
+with the standard crypto/ecdsa package provided with go. Helper
+functionality is provided to parse signatures and public keys from
+standard formats. It was designed for use with btcd, but should be
+general enough for other uses of elliptic curve crypto. It was originally based
+on some initial work by ThePiachu, but has significantly diverged since then.
+*/
+package btcec
diff --git a/vendor/github.com/btcsuite/btcd/btcec/field.go b/vendor/github.com/btcsuite/btcd/btcec/field.go
new file mode 100644
index 0000000000..c2c6a645d4
--- /dev/null
+++ b/vendor/github.com/btcsuite/btcd/btcec/field.go
@@ -0,0 +1,1262 @@
+// Copyright (c) 2013-2016 The btcsuite developers
+// Copyright (c) 2013-2016 Dave Collins
+// Use of this source code is governed by an ISC
+// license that can be found in the LICENSE file.
+
+package btcec
+
+// References:
+// [HAC]: Handbook of Applied Cryptography Menezes, van Oorschot, Vanstone.
+// http://cacr.uwaterloo.ca/hac/
+
+// All elliptic curve operations for secp256k1 are done in a finite field
+// characterized by a 256-bit prime. Given this precision is larger than the
+// biggest available native type, obviously some form of bignum math is needed.
+// This package implements specialized fixed-precision field arithmetic rather
+// than relying on an arbitrary-precision arithmetic package such as math/big
+// for dealing with the field math since the size is known. As a result, rather
+// large performance gains are achieved by taking advantage of many
+// optimizations not available to arbitrary-precision arithmetic and generic
+// modular arithmetic algorithms.
+//
+// There are various ways to internally represent each finite field element.
+// For example, the most obvious representation would be to use an array of 4
+// uint64s (64 bits * 4 = 256 bits). However, that representation suffers from
+// a couple of issues. First, there is no native Go type large enough to handle
+// the intermediate results while adding or multiplying two 64-bit numbers, and
+// second there is no space left for overflows when performing the intermediate
+// arithmetic between each array element which would lead to expensive carry
+// propagation.
+//
+// Given the above, this implementation represents the the field elements as
+// 10 uint32s with each word (array entry) treated as base 2^26. This was
+// chosen for the following reasons:
+// 1) Most systems at the current time are 64-bit (or at least have 64-bit
+// registers available for specialized purposes such as MMX) so the
+// intermediate results can typically be done using a native register (and
+// using uint64s to avoid the need for additional half-word arithmetic)
+// 2) In order to allow addition of the internal words without having to
+// propagate the the carry, the max normalized value for each register must
+// be less than the number of bits available in the register
+// 3) Since we're dealing with 32-bit values, 64-bits of overflow is a
+// reasonable choice for #2
+// 4) Given the need for 256-bits of precision and the properties stated in #1,
+// #2, and #3, the representation which best accommodates this is 10 uint32s
+// with base 2^26 (26 bits * 10 = 260 bits, so the final word only needs 22
+// bits) which leaves the desired 64 bits (32 * 10 = 320, 320 - 256 = 64) for
+// overflow
+//
+// Since it is so important that the field arithmetic is extremely fast for
+// high performance crypto, this package does not perform any validation where
+// it ordinarily would. For example, some functions only give the correct
+// result is the field is normalized and there is no checking to ensure it is.
+// While I typically prefer to ensure all state and input is valid for most
+// packages, this code is really only used internally and every extra check
+// counts.
+
+import (
+ "encoding/hex"
+)
+
+// Constants used to make the code more readable.
+const (
+ twoBitsMask = 0x3
+ fourBitsMask = 0xf
+ sixBitsMask = 0x3f
+ eightBitsMask = 0xff
+)
+
+// Constants related to the field representation.
+const (
+ // fieldWords is the number of words used to internally represent the
+ // 256-bit value.
+ fieldWords = 10
+
+ // fieldBase is the exponent used to form the numeric base of each word.
+ // 2^(fieldBase*i) where i is the word position.
+ fieldBase = 26
+
+ // fieldOverflowBits is the minimum number of "overflow" bits for each
+ // word in the field value.
+ fieldOverflowBits = 32 - fieldBase
+
+ // fieldBaseMask is the mask for the bits in each word needed to
+ // represent the numeric base of each word (except the most significant
+ // word).
+ fieldBaseMask = (1 << fieldBase) - 1
+
+ // fieldMSBBits is the number of bits in the most significant word used
+ // to represent the value.
+ fieldMSBBits = 256 - (fieldBase * (fieldWords - 1))
+
+ // fieldMSBMask is the mask for the bits in the most significant word
+ // needed to represent the value.
+ fieldMSBMask = (1 << fieldMSBBits) - 1
+
+ // fieldPrimeWordZero is word zero of the secp256k1 prime in the
+ // internal field representation. It is used during negation.
+ fieldPrimeWordZero = 0x3fffc2f
+
+ // fieldPrimeWordOne is word one of the secp256k1 prime in the
+ // internal field representation. It is used during negation.
+ fieldPrimeWordOne = 0x3ffffbf
+
+ // primeLowBits is the lower 2*fieldBase bits of the secp256k1 prime in
+ // its standard normalized form. It is used during modular reduction.
+ primeLowBits = 0xffffefffffc2f
+)
+
+// fieldVal implements optimized fixed-precision arithmetic over the
+// secp256k1 finite field. This means all arithmetic is performed modulo
+// 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f. It
+// represents each 256-bit value as 10 32-bit integers in base 2^26. This
+// provides 6 bits of overflow in each word (10 bits in the most significant
+// word) for a total of 64 bits of overflow (9*6 + 10 = 64). It only implements
+// the arithmetic needed for elliptic curve operations.
+//
+// The following depicts the internal representation:
+// -----------------------------------------------------------------
+// | n[9] | n[8] | ... | n[0] |
+// | 32 bits available | 32 bits available | ... | 32 bits available |
+// | 22 bits for value | 26 bits for value | ... | 26 bits for value |
+// | 10 bits overflow | 6 bits overflow | ... | 6 bits overflow |
+// | Mult: 2^(26*9) | Mult: 2^(26*8) | ... | Mult: 2^(26*0) |
+// -----------------------------------------------------------------
+//
+// For example, consider the number 2^49 + 1. It would be represented as:
+// n[0] = 1
+// n[1] = 2^23
+// n[2..9] = 0
+//
+// The full 256-bit value is then calculated by looping i from 9..0 and
+// doing sum(n[i] * 2^(26i)) like so:
+// n[9] * 2^(26*9) = 0 * 2^234 = 0
+// n[8] * 2^(26*8) = 0 * 2^208 = 0
+// ...
+// n[1] * 2^(26*1) = 2^23 * 2^26 = 2^49
+// n[0] * 2^(26*0) = 1 * 2^0 = 1
+// Sum: 0 + 0 + ... + 2^49 + 1 = 2^49 + 1
+type fieldVal struct {
+ n [10]uint32
+}
+
+// String returns the field value as a human-readable hex string.
+func (f fieldVal) String() string {
+ t := new(fieldVal).Set(&f).Normalize()
+ return hex.EncodeToString(t.Bytes()[:])
+}
+
+// Zero sets the field value to zero. A newly created field value is already
+// set to zero. This function can be useful to clear an existing field value
+// for reuse.
+func (f *fieldVal) Zero() {
+ f.n[0] = 0
+ f.n[1] = 0
+ f.n[2] = 0
+ f.n[3] = 0
+ f.n[4] = 0
+ f.n[5] = 0
+ f.n[6] = 0
+ f.n[7] = 0
+ f.n[8] = 0
+ f.n[9] = 0
+}
+
+// Set sets the field value equal to the passed value.
+//
+// The field value is returned to support chaining. This enables syntax like:
+// f := new(fieldVal).Set(f2).Add(1) so that f = f2 + 1 where f2 is not
+// modified.
+func (f *fieldVal) Set(val *fieldVal) *fieldVal {
+ *f = *val
+ return f
+}
+
+// SetInt sets the field value to the passed integer. This is a convenience
+// function since it is fairly common to perform some arithemetic with small
+// native integers.
+//
+// The field value is returned to support chaining. This enables syntax such
+// as f := new(fieldVal).SetInt(2).Mul(f2) so that f = 2 * f2.
+func (f *fieldVal) SetInt(ui uint) *fieldVal {
+ f.Zero()
+ f.n[0] = uint32(ui)
+ return f
+}
+
+// SetBytes packs the passed 32-byte big-endian value into the internal field
+// value representation.
+//
+// The field value is returned to support chaining. This enables syntax like:
+// f := new(fieldVal).SetBytes(byteArray).Mul(f2) so that f = ba * f2.
+func (f *fieldVal) SetBytes(b *[32]byte) *fieldVal {
+ // Pack the 256 total bits across the 10 uint32 words with a max of
+ // 26-bits per word. This could be done with a couple of for loops,
+ // but this unrolled version is significantly faster. Benchmarks show
+ // this is about 34 times faster than the variant which uses loops.
+ f.n[0] = uint32(b[31]) | uint32(b[30])<<8 | uint32(b[29])<<16 |
+ (uint32(b[28])&twoBitsMask)<<24
+ f.n[1] = uint32(b[28])>>2 | uint32(b[27])<<6 | uint32(b[26])<<14 |
+ (uint32(b[25])&fourBitsMask)<<22
+ f.n[2] = uint32(b[25])>>4 | uint32(b[24])<<4 | uint32(b[23])<<12 |
+ (uint32(b[22])&sixBitsMask)<<20
+ f.n[3] = uint32(b[22])>>6 | uint32(b[21])<<2 | uint32(b[20])<<10 |
+ uint32(b[19])<<18
+ f.n[4] = uint32(b[18]) | uint32(b[17])<<8 | uint32(b[16])<<16 |
+ (uint32(b[15])&twoBitsMask)<<24
+ f.n[5] = uint32(b[15])>>2 | uint32(b[14])<<6 | uint32(b[13])<<14 |
+ (uint32(b[12])&fourBitsMask)<<22
+ f.n[6] = uint32(b[12])>>4 | uint32(b[11])<<4 | uint32(b[10])<<12 |
+ (uint32(b[9])&sixBitsMask)<<20
+ f.n[7] = uint32(b[9])>>6 | uint32(b[8])<<2 | uint32(b[7])<<10 |
+ uint32(b[6])<<18
+ f.n[8] = uint32(b[5]) | uint32(b[4])<<8 | uint32(b[3])<<16 |
+ (uint32(b[2])&twoBitsMask)<<24
+ f.n[9] = uint32(b[2])>>2 | uint32(b[1])<<6 | uint32(b[0])<<14
+ return f
+}
+
+// SetByteSlice packs the passed big-endian value into the internal field value
+// representation. Only the first 32-bytes are used. As a result, it is up to
+// the caller to ensure numbers of the appropriate size are used or the value
+// will be truncated.
+//
+// The field value is returned to support chaining. This enables syntax like:
+// f := new(fieldVal).SetByteSlice(byteSlice)
+func (f *fieldVal) SetByteSlice(b []byte) *fieldVal {
+ var b32 [32]byte
+ for i := 0; i < len(b); i++ {
+ if i < 32 {
+ b32[i+(32-len(b))] = b[i]
+ }
+ }
+ return f.SetBytes(&b32)
+}
+
+// SetHex decodes the passed big-endian hex string into the internal field value
+// representation. Only the first 32-bytes are used.
+//
+// The field value is returned to support chaining. This enables syntax like:
+// f := new(fieldVal).SetHex("0abc").Add(1) so that f = 0x0abc + 1
+func (f *fieldVal) SetHex(hexString string) *fieldVal {
+ if len(hexString)%2 != 0 {
+ hexString = "0" + hexString
+ }
+ bytes, _ := hex.DecodeString(hexString)
+ return f.SetByteSlice(bytes)
+}
+
+// Normalize normalizes the internal field words into the desired range and
+// performs fast modular reduction over the secp256k1 prime by making use of the
+// special form of the prime.
+func (f *fieldVal) Normalize() *fieldVal {
+ // The field representation leaves 6 bits of overflow in each
+ // word so intermediate calculations can be performed without needing
+ // to propagate the carry to each higher word during the calculations.
+ // In order to normalize, first we need to "compact" the full 256-bit
+ // value to the right and treat the additional 64 leftmost bits as
+ // the magnitude.
+ m := f.n[0]
+ t0 := m & fieldBaseMask
+ m = (m >> fieldBase) + f.n[1]
+ t1 := m & fieldBaseMask
+ m = (m >> fieldBase) + f.n[2]
+ t2 := m & fieldBaseMask
+ m = (m >> fieldBase) + f.n[3]
+ t3 := m & fieldBaseMask
+ m = (m >> fieldBase) + f.n[4]
+ t4 := m & fieldBaseMask
+ m = (m >> fieldBase) + f.n[5]
+ t5 := m & fieldBaseMask
+ m = (m >> fieldBase) + f.n[6]
+ t6 := m & fieldBaseMask
+ m = (m >> fieldBase) + f.n[7]
+ t7 := m & fieldBaseMask
+ m = (m >> fieldBase) + f.n[8]
+ t8 := m & fieldBaseMask
+ m = (m >> fieldBase) + f.n[9]
+ t9 := m & fieldMSBMask
+ m = m >> fieldMSBBits
+
+ // At this point, if the magnitude is greater than 0, the overall value
+ // is greater than the max possible 256-bit value. In particular, it is
+ // "how many times larger" than the max value it is. Since this field
+ // is doing arithmetic modulo the secp256k1 prime, we need to perform
+ // modular reduction over the prime.
+ //
+ // Per [HAC] section 14.3.4: Reduction method of moduli of special form,
+ // when the modulus is of the special form m = b^t - c, highly efficient
+ // reduction can be achieved.
+ //
+ // The secp256k1 prime is equivalent to 2^256 - 4294968273, so it fits
+ // this criteria.
+ //
+ // 4294968273 in field representation (base 2^26) is:
+ // n[0] = 977
+ // n[1] = 64
+ // That is to say (2^26 * 64) + 977 = 4294968273
+ //
+ // The algorithm presented in the referenced section typically repeats
+ // until the quotient is zero. However, due to our field representation
+ // we already know at least how many times we would need to repeat as
+ // it's the value currently in m. Thus we can simply multiply the
+ // magnitude by the field representation of the prime and do a single
+ // iteration. Notice that nothing will be changed when the magnitude is
+ // zero, so we could skip this in that case, however always running
+ // regardless allows it to run in constant time.
+ r := t0 + m*977
+ t0 = r & fieldBaseMask
+ r = (r >> fieldBase) + t1 + m*64
+ t1 = r & fieldBaseMask
+ r = (r >> fieldBase) + t2
+ t2 = r & fieldBaseMask
+ r = (r >> fieldBase) + t3
+ t3 = r & fieldBaseMask
+ r = (r >> fieldBase) + t4
+ t4 = r & fieldBaseMask
+ r = (r >> fieldBase) + t5
+ t5 = r & fieldBaseMask
+ r = (r >> fieldBase) + t6
+ t6 = r & fieldBaseMask
+ r = (r >> fieldBase) + t7
+ t7 = r & fieldBaseMask
+ r = (r >> fieldBase) + t8
+ t8 = r & fieldBaseMask
+ r = (r >> fieldBase) + t9
+ t9 = r & fieldMSBMask
+
+ // At this point, the result will be in the range 0 <= result <=
+ // prime + (2^64 - c). Therefore, one more subtraction of the prime
+ // might be needed if the current result is greater than or equal to the
+ // prime. The following does the final reduction in constant time.
+ // Note that the if/else here intentionally does the bitwise OR with
+ // zero even though it won't change the value to ensure constant time
+ // between the branches.
+ var mask int32
+ lowBits := uint64(t1)<> fieldBase) & fieldBaseMask)
+ t2 = t2 & uint32(mask)
+ t3 = t3 & uint32(mask)
+ t4 = t4 & uint32(mask)
+ t5 = t5 & uint32(mask)
+ t6 = t6 & uint32(mask)
+ t7 = t7 & uint32(mask)
+ t8 = t8 & uint32(mask)
+ t9 = t9 & uint32(mask)
+
+ // Finally, set the normalized and reduced words.
+ f.n[0] = t0
+ f.n[1] = t1
+ f.n[2] = t2
+ f.n[3] = t3
+ f.n[4] = t4
+ f.n[5] = t5
+ f.n[6] = t6
+ f.n[7] = t7
+ f.n[8] = t8
+ f.n[9] = t9
+ return f
+}
+
+// PutBytes unpacks the field value to a 32-byte big-endian value using the
+// passed byte array. There is a similar function, Bytes, which unpacks the
+// field value into a new array and returns that. This version is provided
+// since it can be useful to cut down on the number of allocations by allowing
+// the caller to reuse a buffer.
+//
+// The field value must be normalized for this function to return the correct
+// result.
+func (f *fieldVal) PutBytes(b *[32]byte) {
+ // Unpack the 256 total bits from the 10 uint32 words with a max of
+ // 26-bits per word. This could be done with a couple of for loops,
+ // but this unrolled version is a bit faster. Benchmarks show this is
+ // about 10 times faster than the variant which uses loops.
+ b[31] = byte(f.n[0] & eightBitsMask)
+ b[30] = byte((f.n[0] >> 8) & eightBitsMask)
+ b[29] = byte((f.n[0] >> 16) & eightBitsMask)
+ b[28] = byte((f.n[0]>>24)&twoBitsMask | (f.n[1]&sixBitsMask)<<2)
+ b[27] = byte((f.n[1] >> 6) & eightBitsMask)
+ b[26] = byte((f.n[1] >> 14) & eightBitsMask)
+ b[25] = byte((f.n[1]>>22)&fourBitsMask | (f.n[2]&fourBitsMask)<<4)
+ b[24] = byte((f.n[2] >> 4) & eightBitsMask)
+ b[23] = byte((f.n[2] >> 12) & eightBitsMask)
+ b[22] = byte((f.n[2]>>20)&sixBitsMask | (f.n[3]&twoBitsMask)<<6)
+ b[21] = byte((f.n[3] >> 2) & eightBitsMask)
+ b[20] = byte((f.n[3] >> 10) & eightBitsMask)
+ b[19] = byte((f.n[3] >> 18) & eightBitsMask)
+ b[18] = byte(f.n[4] & eightBitsMask)
+ b[17] = byte((f.n[4] >> 8) & eightBitsMask)
+ b[16] = byte((f.n[4] >> 16) & eightBitsMask)
+ b[15] = byte((f.n[4]>>24)&twoBitsMask | (f.n[5]&sixBitsMask)<<2)
+ b[14] = byte((f.n[5] >> 6) & eightBitsMask)
+ b[13] = byte((f.n[5] >> 14) & eightBitsMask)
+ b[12] = byte((f.n[5]>>22)&fourBitsMask | (f.n[6]&fourBitsMask)<<4)
+ b[11] = byte((f.n[6] >> 4) & eightBitsMask)
+ b[10] = byte((f.n[6] >> 12) & eightBitsMask)
+ b[9] = byte((f.n[6]>>20)&sixBitsMask | (f.n[7]&twoBitsMask)<<6)
+ b[8] = byte((f.n[7] >> 2) & eightBitsMask)
+ b[7] = byte((f.n[7] >> 10) & eightBitsMask)
+ b[6] = byte((f.n[7] >> 18) & eightBitsMask)
+ b[5] = byte(f.n[8] & eightBitsMask)
+ b[4] = byte((f.n[8] >> 8) & eightBitsMask)
+ b[3] = byte((f.n[8] >> 16) & eightBitsMask)
+ b[2] = byte((f.n[8]>>24)&twoBitsMask | (f.n[9]&sixBitsMask)<<2)
+ b[1] = byte((f.n[9] >> 6) & eightBitsMask)
+ b[0] = byte((f.n[9] >> 14) & eightBitsMask)
+}
+
+// Bytes unpacks the field value to a 32-byte big-endian value. See PutBytes
+// for a variant that allows the a buffer to be passed which can be useful to
+// to cut down on the number of allocations by allowing the caller to reuse a
+// buffer.
+//
+// The field value must be normalized for this function to return correct
+// result.
+func (f *fieldVal) Bytes() *[32]byte {
+ b := new([32]byte)
+ f.PutBytes(b)
+ return b
+}
+
+// IsZero returns whether or not the field value is equal to zero.
+func (f *fieldVal) IsZero() bool {
+ // The value can only be zero if no bits are set in any of the words.
+ // This is a constant time implementation.
+ bits := f.n[0] | f.n[1] | f.n[2] | f.n[3] | f.n[4] |
+ f.n[5] | f.n[6] | f.n[7] | f.n[8] | f.n[9]
+
+ return bits == 0
+}
+
+// IsOdd returns whether or not the field value is an odd number.
+//
+// The field value must be normalized for this function to return correct
+// result.
+func (f *fieldVal) IsOdd() bool {
+ // Only odd numbers have the bottom bit set.
+ return f.n[0]&1 == 1
+}
+
+// Equals returns whether or not the two field values are the same. Both
+// field values being compared must be normalized for this function to return
+// the correct result.
+func (f *fieldVal) Equals(val *fieldVal) bool {
+ // Xor only sets bits when they are different, so the two field values
+ // can only be the same if no bits are set after xoring each word.
+ // This is a constant time implementation.
+ bits := (f.n[0] ^ val.n[0]) | (f.n[1] ^ val.n[1]) | (f.n[2] ^ val.n[2]) |
+ (f.n[3] ^ val.n[3]) | (f.n[4] ^ val.n[4]) | (f.n[5] ^ val.n[5]) |
+ (f.n[6] ^ val.n[6]) | (f.n[7] ^ val.n[7]) | (f.n[8] ^ val.n[8]) |
+ (f.n[9] ^ val.n[9])
+
+ return bits == 0
+}
+
+// NegateVal negates the passed value and stores the result in f. The caller
+// must provide the magnitude of the passed value for a correct result.
+//
+// The field value is returned to support chaining. This enables syntax like:
+// f.NegateVal(f2).AddInt(1) so that f = -f2 + 1.
+func (f *fieldVal) NegateVal(val *fieldVal, magnitude uint32) *fieldVal {
+ // Negation in the field is just the prime minus the value. However,
+ // in order to allow negation against a field value without having to
+ // normalize/reduce it first, multiply by the magnitude (that is how
+ // "far" away it is from the normalized value) to adjust. Also, since
+ // negating a value pushes it one more order of magnitude away from the
+ // normalized range, add 1 to compensate.
+ //
+ // For some intuition here, imagine you're performing mod 12 arithmetic
+ // (picture a clock) and you are negating the number 7. So you start at
+ // 12 (which is of course 0 under mod 12) and count backwards (left on
+ // the clock) 7 times to arrive at 5. Notice this is just 12-7 = 5.
+ // Now, assume you're starting with 19, which is a number that is
+ // already larger than the modulus and congruent to 7 (mod 12). When a
+ // value is already in the desired range, its magnitude is 1. Since 19
+ // is an additional "step", its magnitude (mod 12) is 2. Since any
+ // multiple of the modulus is conguent to zero (mod m), the answer can
+ // be shortcut by simply mulplying the magnitude by the modulus and
+ // subtracting. Keeping with the example, this would be (2*12)-19 = 5.
+ f.n[0] = (magnitude+1)*fieldPrimeWordZero - val.n[0]
+ f.n[1] = (magnitude+1)*fieldPrimeWordOne - val.n[1]
+ f.n[2] = (magnitude+1)*fieldBaseMask - val.n[2]
+ f.n[3] = (magnitude+1)*fieldBaseMask - val.n[3]
+ f.n[4] = (magnitude+1)*fieldBaseMask - val.n[4]
+ f.n[5] = (magnitude+1)*fieldBaseMask - val.n[5]
+ f.n[6] = (magnitude+1)*fieldBaseMask - val.n[6]
+ f.n[7] = (magnitude+1)*fieldBaseMask - val.n[7]
+ f.n[8] = (magnitude+1)*fieldBaseMask - val.n[8]
+ f.n[9] = (magnitude+1)*fieldMSBMask - val.n[9]
+
+ return f
+}
+
+// Negate negates the field value. The existing field value is modified. The
+// caller must provide the magnitude of the field value for a correct result.
+//
+// The field value is returned to support chaining. This enables syntax like:
+// f.Negate().AddInt(1) so that f = -f + 1.
+func (f *fieldVal) Negate(magnitude uint32) *fieldVal {
+ return f.NegateVal(f, magnitude)
+}
+
+// AddInt adds the passed integer to the existing field value and stores the
+// result in f. This is a convenience function since it is fairly common to
+// perform some arithemetic with small native integers.
+//
+// The field value is returned to support chaining. This enables syntax like:
+// f.AddInt(1).Add(f2) so that f = f + 1 + f2.
+func (f *fieldVal) AddInt(ui uint) *fieldVal {
+ // Since the field representation intentionally provides overflow bits,
+ // it's ok to use carryless addition as the carry bit is safely part of
+ // the word and will be normalized out.
+ f.n[0] += uint32(ui)
+
+ return f
+}
+
+// Add adds the passed value to the existing field value and stores the result
+// in f.
+//
+// The field value is returned to support chaining. This enables syntax like:
+// f.Add(f2).AddInt(1) so that f = f + f2 + 1.
+func (f *fieldVal) Add(val *fieldVal) *fieldVal {
+ // Since the field representation intentionally provides overflow bits,
+ // it's ok to use carryless addition as the carry bit is safely part of
+ // each word and will be normalized out. This could obviously be done
+ // in a loop, but the unrolled version is faster.
+ f.n[0] += val.n[0]
+ f.n[1] += val.n[1]
+ f.n[2] += val.n[2]
+ f.n[3] += val.n[3]
+ f.n[4] += val.n[4]
+ f.n[5] += val.n[5]
+ f.n[6] += val.n[6]
+ f.n[7] += val.n[7]
+ f.n[8] += val.n[8]
+ f.n[9] += val.n[9]
+
+ return f
+}
+
+// Add2 adds the passed two field values together and stores the result in f.
+//
+// The field value is returned to support chaining. This enables syntax like:
+// f3.Add2(f, f2).AddInt(1) so that f3 = f + f2 + 1.
+func (f *fieldVal) Add2(val *fieldVal, val2 *fieldVal) *fieldVal {
+ // Since the field representation intentionally provides overflow bits,
+ // it's ok to use carryless addition as the carry bit is safely part of
+ // each word and will be normalized out. This could obviously be done
+ // in a loop, but the unrolled version is faster.
+ f.n[0] = val.n[0] + val2.n[0]
+ f.n[1] = val.n[1] + val2.n[1]
+ f.n[2] = val.n[2] + val2.n[2]
+ f.n[3] = val.n[3] + val2.n[3]
+ f.n[4] = val.n[4] + val2.n[4]
+ f.n[5] = val.n[5] + val2.n[5]
+ f.n[6] = val.n[6] + val2.n[6]
+ f.n[7] = val.n[7] + val2.n[7]
+ f.n[8] = val.n[8] + val2.n[8]
+ f.n[9] = val.n[9] + val2.n[9]
+
+ return f
+}
+
+// MulInt multiplies the field value by the passed int and stores the result in
+// f. Note that this function can overflow if multiplying the value by any of
+// the individual words exceeds a max uint32. Therefore it is important that
+// the caller ensures no overflows will occur before using this function.
+//
+// The field value is returned to support chaining. This enables syntax like:
+// f.MulInt(2).Add(f2) so that f = 2 * f + f2.
+func (f *fieldVal) MulInt(val uint) *fieldVal {
+ // Since each word of the field representation can hold up to
+ // fieldOverflowBits extra bits which will be normalized out, it's safe
+ // to multiply each word without using a larger type or carry
+ // propagation so long as the values won't overflow a uint32. This
+ // could obviously be done in a loop, but the unrolled version is
+ // faster.
+ ui := uint32(val)
+ f.n[0] *= ui
+ f.n[1] *= ui
+ f.n[2] *= ui
+ f.n[3] *= ui
+ f.n[4] *= ui
+ f.n[5] *= ui
+ f.n[6] *= ui
+ f.n[7] *= ui
+ f.n[8] *= ui
+ f.n[9] *= ui
+
+ return f
+}
+
+// Mul multiplies the passed value to the existing field value and stores the
+// result in f. Note that this function can overflow if multiplying any
+// of the individual words exceeds a max uint32. In practice, this means the
+// magnitude of either value involved in the multiplication must be a max of
+// 8.
+//
+// The field value is returned to support chaining. This enables syntax like:
+// f.Mul(f2).AddInt(1) so that f = (f * f2) + 1.
+func (f *fieldVal) Mul(val *fieldVal) *fieldVal {
+ return f.Mul2(f, val)
+}
+
+// Mul2 multiplies the passed two field values together and stores the result
+// result in f. Note that this function can overflow if multiplying any of
+// the individual words exceeds a max uint32. In practice, this means the
+// magnitude of either value involved in the multiplication must be a max of
+// 8.
+//
+// The field value is returned to support chaining. This enables syntax like:
+// f3.Mul2(f, f2).AddInt(1) so that f3 = (f * f2) + 1.
+func (f *fieldVal) Mul2(val *fieldVal, val2 *fieldVal) *fieldVal {
+ // This could be done with a couple of for loops and an array to store
+ // the intermediate terms, but this unrolled version is significantly
+ // faster.
+
+ // Terms for 2^(fieldBase*0).
+ m := uint64(val.n[0]) * uint64(val2.n[0])
+ t0 := m & fieldBaseMask
+
+ // Terms for 2^(fieldBase*1).
+ m = (m >> fieldBase) +
+ uint64(val.n[0])*uint64(val2.n[1]) +
+ uint64(val.n[1])*uint64(val2.n[0])
+ t1 := m & fieldBaseMask
+
+ // Terms for 2^(fieldBase*2).
+ m = (m >> fieldBase) +
+ uint64(val.n[0])*uint64(val2.n[2]) +
+ uint64(val.n[1])*uint64(val2.n[1]) +
+ uint64(val.n[2])*uint64(val2.n[0])
+ t2 := m & fieldBaseMask
+
+ // Terms for 2^(fieldBase*3).
+ m = (m >> fieldBase) +
+ uint64(val.n[0])*uint64(val2.n[3]) +
+ uint64(val.n[1])*uint64(val2.n[2]) +
+ uint64(val.n[2])*uint64(val2.n[1]) +
+ uint64(val.n[3])*uint64(val2.n[0])
+ t3 := m & fieldBaseMask
+
+ // Terms for 2^(fieldBase*4).
+ m = (m >> fieldBase) +
+ uint64(val.n[0])*uint64(val2.n[4]) +
+ uint64(val.n[1])*uint64(val2.n[3]) +
+ uint64(val.n[2])*uint64(val2.n[2]) +
+ uint64(val.n[3])*uint64(val2.n[1]) +
+ uint64(val.n[4])*uint64(val2.n[0])
+ t4 := m & fieldBaseMask
+
+ // Terms for 2^(fieldBase*5).
+ m = (m >> fieldBase) +
+ uint64(val.n[0])*uint64(val2.n[5]) +
+ uint64(val.n[1])*uint64(val2.n[4]) +
+ uint64(val.n[2])*uint64(val2.n[3]) +
+ uint64(val.n[3])*uint64(val2.n[2]) +
+ uint64(val.n[4])*uint64(val2.n[1]) +
+ uint64(val.n[5])*uint64(val2.n[0])
+ t5 := m & fieldBaseMask
+
+ // Terms for 2^(fieldBase*6).
+ m = (m >> fieldBase) +
+ uint64(val.n[0])*uint64(val2.n[6]) +
+ uint64(val.n[1])*uint64(val2.n[5]) +
+ uint64(val.n[2])*uint64(val2.n[4]) +
+ uint64(val.n[3])*uint64(val2.n[3]) +
+ uint64(val.n[4])*uint64(val2.n[2]) +
+ uint64(val.n[5])*uint64(val2.n[1]) +
+ uint64(val.n[6])*uint64(val2.n[0])
+ t6 := m & fieldBaseMask
+
+ // Terms for 2^(fieldBase*7).
+ m = (m >> fieldBase) +
+ uint64(val.n[0])*uint64(val2.n[7]) +
+ uint64(val.n[1])*uint64(val2.n[6]) +
+ uint64(val.n[2])*uint64(val2.n[5]) +
+ uint64(val.n[3])*uint64(val2.n[4]) +
+ uint64(val.n[4])*uint64(val2.n[3]) +
+ uint64(val.n[5])*uint64(val2.n[2]) +
+ uint64(val.n[6])*uint64(val2.n[1]) +
+ uint64(val.n[7])*uint64(val2.n[0])
+ t7 := m & fieldBaseMask
+
+ // Terms for 2^(fieldBase*8).
+ m = (m >> fieldBase) +
+ uint64(val.n[0])*uint64(val2.n[8]) +
+ uint64(val.n[1])*uint64(val2.n[7]) +
+ uint64(val.n[2])*uint64(val2.n[6]) +
+ uint64(val.n[3])*uint64(val2.n[5]) +
+ uint64(val.n[4])*uint64(val2.n[4]) +
+ uint64(val.n[5])*uint64(val2.n[3]) +
+ uint64(val.n[6])*uint64(val2.n[2]) +
+ uint64(val.n[7])*uint64(val2.n[1]) +
+ uint64(val.n[8])*uint64(val2.n[0])
+ t8 := m & fieldBaseMask
+
+ // Terms for 2^(fieldBase*9).
+ m = (m >> fieldBase) +
+ uint64(val.n[0])*uint64(val2.n[9]) +
+ uint64(val.n[1])*uint64(val2.n[8]) +
+ uint64(val.n[2])*uint64(val2.n[7]) +
+ uint64(val.n[3])*uint64(val2.n[6]) +
+ uint64(val.n[4])*uint64(val2.n[5]) +
+ uint64(val.n[5])*uint64(val2.n[4]) +
+ uint64(val.n[6])*uint64(val2.n[3]) +
+ uint64(val.n[7])*uint64(val2.n[2]) +
+ uint64(val.n[8])*uint64(val2.n[1]) +
+ uint64(val.n[9])*uint64(val2.n[0])
+ t9 := m & fieldBaseMask
+
+ // Terms for 2^(fieldBase*10).
+ m = (m >> fieldBase) +
+ uint64(val.n[1])*uint64(val2.n[9]) +
+ uint64(val.n[2])*uint64(val2.n[8]) +
+ uint64(val.n[3])*uint64(val2.n[7]) +
+ uint64(val.n[4])*uint64(val2.n[6]) +
+ uint64(val.n[5])*uint64(val2.n[5]) +
+ uint64(val.n[6])*uint64(val2.n[4]) +
+ uint64(val.n[7])*uint64(val2.n[3]) +
+ uint64(val.n[8])*uint64(val2.n[2]) +
+ uint64(val.n[9])*uint64(val2.n[1])
+ t10 := m & fieldBaseMask
+
+ // Terms for 2^(fieldBase*11).
+ m = (m >> fieldBase) +
+ uint64(val.n[2])*uint64(val2.n[9]) +
+ uint64(val.n[3])*uint64(val2.n[8]) +
+ uint64(val.n[4])*uint64(val2.n[7]) +
+ uint64(val.n[5])*uint64(val2.n[6]) +
+ uint64(val.n[6])*uint64(val2.n[5]) +
+ uint64(val.n[7])*uint64(val2.n[4]) +
+ uint64(val.n[8])*uint64(val2.n[3]) +
+ uint64(val.n[9])*uint64(val2.n[2])
+ t11 := m & fieldBaseMask
+
+ // Terms for 2^(fieldBase*12).
+ m = (m >> fieldBase) +
+ uint64(val.n[3])*uint64(val2.n[9]) +
+ uint64(val.n[4])*uint64(val2.n[8]) +
+ uint64(val.n[5])*uint64(val2.n[7]) +
+ uint64(val.n[6])*uint64(val2.n[6]) +
+ uint64(val.n[7])*uint64(val2.n[5]) +
+ uint64(val.n[8])*uint64(val2.n[4]) +
+ uint64(val.n[9])*uint64(val2.n[3])
+ t12 := m & fieldBaseMask
+
+ // Terms for 2^(fieldBase*13).
+ m = (m >> fieldBase) +
+ uint64(val.n[4])*uint64(val2.n[9]) +
+ uint64(val.n[5])*uint64(val2.n[8]) +
+ uint64(val.n[6])*uint64(val2.n[7]) +
+ uint64(val.n[7])*uint64(val2.n[6]) +
+ uint64(val.n[8])*uint64(val2.n[5]) +
+ uint64(val.n[9])*uint64(val2.n[4])
+ t13 := m & fieldBaseMask
+
+ // Terms for 2^(fieldBase*14).
+ m = (m >> fieldBase) +
+ uint64(val.n[5])*uint64(val2.n[9]) +
+ uint64(val.n[6])*uint64(val2.n[8]) +
+ uint64(val.n[7])*uint64(val2.n[7]) +
+ uint64(val.n[8])*uint64(val2.n[6]) +
+ uint64(val.n[9])*uint64(val2.n[5])
+ t14 := m & fieldBaseMask
+
+ // Terms for 2^(fieldBase*15).
+ m = (m >> fieldBase) +
+ uint64(val.n[6])*uint64(val2.n[9]) +
+ uint64(val.n[7])*uint64(val2.n[8]) +
+ uint64(val.n[8])*uint64(val2.n[7]) +
+ uint64(val.n[9])*uint64(val2.n[6])
+ t15 := m & fieldBaseMask
+
+ // Terms for 2^(fieldBase*16).
+ m = (m >> fieldBase) +
+ uint64(val.n[7])*uint64(val2.n[9]) +
+ uint64(val.n[8])*uint64(val2.n[8]) +
+ uint64(val.n[9])*uint64(val2.n[7])
+ t16 := m & fieldBaseMask
+
+ // Terms for 2^(fieldBase*17).
+ m = (m >> fieldBase) +
+ uint64(val.n[8])*uint64(val2.n[9]) +
+ uint64(val.n[9])*uint64(val2.n[8])
+ t17 := m & fieldBaseMask
+
+ // Terms for 2^(fieldBase*18).
+ m = (m >> fieldBase) + uint64(val.n[9])*uint64(val2.n[9])
+ t18 := m & fieldBaseMask
+
+ // What's left is for 2^(fieldBase*19).
+ t19 := m >> fieldBase
+
+ // At this point, all of the terms are grouped into their respective
+ // base.
+ //
+ // Per [HAC] section 14.3.4: Reduction method of moduli of special form,
+ // when the modulus is of the special form m = b^t - c, highly efficient
+ // reduction can be achieved per the provided algorithm.
+ //
+ // The secp256k1 prime is equivalent to 2^256 - 4294968273, so it fits
+ // this criteria.
+ //
+ // 4294968273 in field representation (base 2^26) is:
+ // n[0] = 977
+ // n[1] = 64
+ // That is to say (2^26 * 64) + 977 = 4294968273
+ //
+ // Since each word is in base 26, the upper terms (t10 and up) start
+ // at 260 bits (versus the final desired range of 256 bits), so the
+ // field representation of 'c' from above needs to be adjusted for the
+ // extra 4 bits by multiplying it by 2^4 = 16. 4294968273 * 16 =
+ // 68719492368. Thus, the adjusted field representation of 'c' is:
+ // n[0] = 977 * 16 = 15632
+ // n[1] = 64 * 16 = 1024
+ // That is to say (2^26 * 1024) + 15632 = 68719492368
+ //
+ // To reduce the final term, t19, the entire 'c' value is needed instead
+ // of only n[0] because there are no more terms left to handle n[1].
+ // This means there might be some magnitude left in the upper bits that
+ // is handled below.
+ m = t0 + t10*15632
+ t0 = m & fieldBaseMask
+ m = (m >> fieldBase) + t1 + t10*1024 + t11*15632
+ t1 = m & fieldBaseMask
+ m = (m >> fieldBase) + t2 + t11*1024 + t12*15632
+ t2 = m & fieldBaseMask
+ m = (m >> fieldBase) + t3 + t12*1024 + t13*15632
+ t3 = m & fieldBaseMask
+ m = (m >> fieldBase) + t4 + t13*1024 + t14*15632
+ t4 = m & fieldBaseMask
+ m = (m >> fieldBase) + t5 + t14*1024 + t15*15632
+ t5 = m & fieldBaseMask
+ m = (m >> fieldBase) + t6 + t15*1024 + t16*15632
+ t6 = m & fieldBaseMask
+ m = (m >> fieldBase) + t7 + t16*1024 + t17*15632
+ t7 = m & fieldBaseMask
+ m = (m >> fieldBase) + t8 + t17*1024 + t18*15632
+ t8 = m & fieldBaseMask
+ m = (m >> fieldBase) + t9 + t18*1024 + t19*68719492368
+ t9 = m & fieldMSBMask
+ m = m >> fieldMSBBits
+
+ // At this point, if the magnitude is greater than 0, the overall value
+ // is greater than the max possible 256-bit value. In particular, it is
+ // "how many times larger" than the max value it is.
+ //
+ // The algorithm presented in [HAC] section 14.3.4 repeats until the
+ // quotient is zero. However, due to the above, we already know at
+ // least how many times we would need to repeat as it's the value
+ // currently in m. Thus we can simply multiply the magnitude by the
+ // field representation of the prime and do a single iteration. Notice
+ // that nothing will be changed when the magnitude is zero, so we could
+ // skip this in that case, however always running regardless allows it
+ // to run in constant time. The final result will be in the range
+ // 0 <= result <= prime + (2^64 - c), so it is guaranteed to have a
+ // magnitude of 1, but it is denormalized.
+ d := t0 + m*977
+ f.n[0] = uint32(d & fieldBaseMask)
+ d = (d >> fieldBase) + t1 + m*64
+ f.n[1] = uint32(d & fieldBaseMask)
+ f.n[2] = uint32((d >> fieldBase) + t2)
+ f.n[3] = uint32(t3)
+ f.n[4] = uint32(t4)
+ f.n[5] = uint32(t5)
+ f.n[6] = uint32(t6)
+ f.n[7] = uint32(t7)
+ f.n[8] = uint32(t8)
+ f.n[9] = uint32(t9)
+
+ return f
+}
+
+// Square squares the field value. The existing field value is modified. Note
+// that this function can overflow if multiplying any of the individual words
+// exceeds a max uint32. In practice, this means the magnitude of the field
+// must be a max of 8 to prevent overflow.
+//
+// The field value is returned to support chaining. This enables syntax like:
+// f.Square().Mul(f2) so that f = f^2 * f2.
+func (f *fieldVal) Square() *fieldVal {
+ return f.SquareVal(f)
+}
+
+// SquareVal squares the passed value and stores the result in f. Note that
+// this function can overflow if multiplying any of the individual words
+// exceeds a max uint32. In practice, this means the magnitude of the field
+// being squred must be a max of 8 to prevent overflow.
+//
+// The field value is returned to support chaining. This enables syntax like:
+// f3.SquareVal(f).Mul(f) so that f3 = f^2 * f = f^3.
+func (f *fieldVal) SquareVal(val *fieldVal) *fieldVal {
+ // This could be done with a couple of for loops and an array to store
+ // the intermediate terms, but this unrolled version is significantly
+ // faster.
+
+ // Terms for 2^(fieldBase*0).
+ m := uint64(val.n[0]) * uint64(val.n[0])
+ t0 := m & fieldBaseMask
+
+ // Terms for 2^(fieldBase*1).
+ m = (m >> fieldBase) + 2*uint64(val.n[0])*uint64(val.n[1])
+ t1 := m & fieldBaseMask
+
+ // Terms for 2^(fieldBase*2).
+ m = (m >> fieldBase) +
+ 2*uint64(val.n[0])*uint64(val.n[2]) +
+ uint64(val.n[1])*uint64(val.n[1])
+ t2 := m & fieldBaseMask
+
+ // Terms for 2^(fieldBase*3).
+ m = (m >> fieldBase) +
+ 2*uint64(val.n[0])*uint64(val.n[3]) +
+ 2*uint64(val.n[1])*uint64(val.n[2])
+ t3 := m & fieldBaseMask
+
+ // Terms for 2^(fieldBase*4).
+ m = (m >> fieldBase) +
+ 2*uint64(val.n[0])*uint64(val.n[4]) +
+ 2*uint64(val.n[1])*uint64(val.n[3]) +
+ uint64(val.n[2])*uint64(val.n[2])
+ t4 := m & fieldBaseMask
+
+ // Terms for 2^(fieldBase*5).
+ m = (m >> fieldBase) +
+ 2*uint64(val.n[0])*uint64(val.n[5]) +
+ 2*uint64(val.n[1])*uint64(val.n[4]) +
+ 2*uint64(val.n[2])*uint64(val.n[3])
+ t5 := m & fieldBaseMask
+
+ // Terms for 2^(fieldBase*6).
+ m = (m >> fieldBase) +
+ 2*uint64(val.n[0])*uint64(val.n[6]) +
+ 2*uint64(val.n[1])*uint64(val.n[5]) +
+ 2*uint64(val.n[2])*uint64(val.n[4]) +
+ uint64(val.n[3])*uint64(val.n[3])
+ t6 := m & fieldBaseMask
+
+ // Terms for 2^(fieldBase*7).
+ m = (m >> fieldBase) +
+ 2*uint64(val.n[0])*uint64(val.n[7]) +
+ 2*uint64(val.n[1])*uint64(val.n[6]) +
+ 2*uint64(val.n[2])*uint64(val.n[5]) +
+ 2*uint64(val.n[3])*uint64(val.n[4])
+ t7 := m & fieldBaseMask
+
+ // Terms for 2^(fieldBase*8).
+ m = (m >> fieldBase) +
+ 2*uint64(val.n[0])*uint64(val.n[8]) +
+ 2*uint64(val.n[1])*uint64(val.n[7]) +
+ 2*uint64(val.n[2])*uint64(val.n[6]) +
+ 2*uint64(val.n[3])*uint64(val.n[5]) +
+ uint64(val.n[4])*uint64(val.n[4])
+ t8 := m & fieldBaseMask
+
+ // Terms for 2^(fieldBase*9).
+ m = (m >> fieldBase) +
+ 2*uint64(val.n[0])*uint64(val.n[9]) +
+ 2*uint64(val.n[1])*uint64(val.n[8]) +
+ 2*uint64(val.n[2])*uint64(val.n[7]) +
+ 2*uint64(val.n[3])*uint64(val.n[6]) +
+ 2*uint64(val.n[4])*uint64(val.n[5])
+ t9 := m & fieldBaseMask
+
+ // Terms for 2^(fieldBase*10).
+ m = (m >> fieldBase) +
+ 2*uint64(val.n[1])*uint64(val.n[9]) +
+ 2*uint64(val.n[2])*uint64(val.n[8]) +
+ 2*uint64(val.n[3])*uint64(val.n[7]) +
+ 2*uint64(val.n[4])*uint64(val.n[6]) +
+ uint64(val.n[5])*uint64(val.n[5])
+ t10 := m & fieldBaseMask
+
+ // Terms for 2^(fieldBase*11).
+ m = (m >> fieldBase) +
+ 2*uint64(val.n[2])*uint64(val.n[9]) +
+ 2*uint64(val.n[3])*uint64(val.n[8]) +
+ 2*uint64(val.n[4])*uint64(val.n[7]) +
+ 2*uint64(val.n[5])*uint64(val.n[6])
+ t11 := m & fieldBaseMask
+
+ // Terms for 2^(fieldBase*12).
+ m = (m >> fieldBase) +
+ 2*uint64(val.n[3])*uint64(val.n[9]) +
+ 2*uint64(val.n[4])*uint64(val.n[8]) +
+ 2*uint64(val.n[5])*uint64(val.n[7]) +
+ uint64(val.n[6])*uint64(val.n[6])
+ t12 := m & fieldBaseMask
+
+ // Terms for 2^(fieldBase*13).
+ m = (m >> fieldBase) +
+ 2*uint64(val.n[4])*uint64(val.n[9]) +
+ 2*uint64(val.n[5])*uint64(val.n[8]) +
+ 2*uint64(val.n[6])*uint64(val.n[7])
+ t13 := m & fieldBaseMask
+
+ // Terms for 2^(fieldBase*14).
+ m = (m >> fieldBase) +
+ 2*uint64(val.n[5])*uint64(val.n[9]) +
+ 2*uint64(val.n[6])*uint64(val.n[8]) +
+ uint64(val.n[7])*uint64(val.n[7])
+ t14 := m & fieldBaseMask
+
+ // Terms for 2^(fieldBase*15).
+ m = (m >> fieldBase) +
+ 2*uint64(val.n[6])*uint64(val.n[9]) +
+ 2*uint64(val.n[7])*uint64(val.n[8])
+ t15 := m & fieldBaseMask
+
+ // Terms for 2^(fieldBase*16).
+ m = (m >> fieldBase) +
+ 2*uint64(val.n[7])*uint64(val.n[9]) +
+ uint64(val.n[8])*uint64(val.n[8])
+ t16 := m & fieldBaseMask
+
+ // Terms for 2^(fieldBase*17).
+ m = (m >> fieldBase) + 2*uint64(val.n[8])*uint64(val.n[9])
+ t17 := m & fieldBaseMask
+
+ // Terms for 2^(fieldBase*18).
+ m = (m >> fieldBase) + uint64(val.n[9])*uint64(val.n[9])
+ t18 := m & fieldBaseMask
+
+ // What's left is for 2^(fieldBase*19).
+ t19 := m >> fieldBase
+
+ // At this point, all of the terms are grouped into their respective
+ // base.
+ //
+ // Per [HAC] section 14.3.4: Reduction method of moduli of special form,
+ // when the modulus is of the special form m = b^t - c, highly efficient
+ // reduction can be achieved per the provided algorithm.
+ //
+ // The secp256k1 prime is equivalent to 2^256 - 4294968273, so it fits
+ // this criteria.
+ //
+ // 4294968273 in field representation (base 2^26) is:
+ // n[0] = 977
+ // n[1] = 64
+ // That is to say (2^26 * 64) + 977 = 4294968273
+ //
+ // Since each word is in base 26, the upper terms (t10 and up) start
+ // at 260 bits (versus the final desired range of 256 bits), so the
+ // field representation of 'c' from above needs to be adjusted for the
+ // extra 4 bits by multiplying it by 2^4 = 16. 4294968273 * 16 =
+ // 68719492368. Thus, the adjusted field representation of 'c' is:
+ // n[0] = 977 * 16 = 15632
+ // n[1] = 64 * 16 = 1024
+ // That is to say (2^26 * 1024) + 15632 = 68719492368
+ //
+ // To reduce the final term, t19, the entire 'c' value is needed instead
+ // of only n[0] because there are no more terms left to handle n[1].
+ // This means there might be some magnitude left in the upper bits that
+ // is handled below.
+ m = t0 + t10*15632
+ t0 = m & fieldBaseMask
+ m = (m >> fieldBase) + t1 + t10*1024 + t11*15632
+ t1 = m & fieldBaseMask
+ m = (m >> fieldBase) + t2 + t11*1024 + t12*15632
+ t2 = m & fieldBaseMask
+ m = (m >> fieldBase) + t3 + t12*1024 + t13*15632
+ t3 = m & fieldBaseMask
+ m = (m >> fieldBase) + t4 + t13*1024 + t14*15632
+ t4 = m & fieldBaseMask
+ m = (m >> fieldBase) + t5 + t14*1024 + t15*15632
+ t5 = m & fieldBaseMask
+ m = (m >> fieldBase) + t6 + t15*1024 + t16*15632
+ t6 = m & fieldBaseMask
+ m = (m >> fieldBase) + t7 + t16*1024 + t17*15632
+ t7 = m & fieldBaseMask
+ m = (m >> fieldBase) + t8 + t17*1024 + t18*15632
+ t8 = m & fieldBaseMask
+ m = (m >> fieldBase) + t9 + t18*1024 + t19*68719492368
+ t9 = m & fieldMSBMask
+ m = m >> fieldMSBBits
+
+ // At this point, if the magnitude is greater than 0, the overall value
+ // is greater than the max possible 256-bit value. In particular, it is
+ // "how many times larger" than the max value it is.
+ //
+ // The algorithm presented in [HAC] section 14.3.4 repeats until the
+ // quotient is zero. However, due to the above, we already know at
+ // least how many times we would need to repeat as it's the value
+ // currently in m. Thus we can simply multiply the magnitude by the
+ // field representation of the prime and do a single iteration. Notice
+ // that nothing will be changed when the magnitude is zero, so we could
+ // skip this in that case, however always running regardless allows it
+ // to run in constant time. The final result will be in the range
+ // 0 <= result <= prime + (2^64 - c), so it is guaranteed to have a
+ // magnitude of 1, but it is denormalized.
+ n := t0 + m*977
+ f.n[0] = uint32(n & fieldBaseMask)
+ n = (n >> fieldBase) + t1 + m*64
+ f.n[1] = uint32(n & fieldBaseMask)
+ f.n[2] = uint32((n >> fieldBase) + t2)
+ f.n[3] = uint32(t3)
+ f.n[4] = uint32(t4)
+ f.n[5] = uint32(t5)
+ f.n[6] = uint32(t6)
+ f.n[7] = uint32(t7)
+ f.n[8] = uint32(t8)
+ f.n[9] = uint32(t9)
+
+ return f
+}
+
+// Inverse finds the modular multiplicative inverse of the field value. The
+// existing field value is modified.
+//
+// The field value is returned to support chaining. This enables syntax like:
+// f.Inverse().Mul(f2) so that f = f^-1 * f2.
+func (f *fieldVal) Inverse() *fieldVal {
+ // Fermat's little theorem states that for a nonzero number a and prime
+ // prime p, a^(p-1) = 1 (mod p). Since the multipliciative inverse is
+ // a*b = 1 (mod p), it follows that b = a*a^(p-2) = a^(p-1) = 1 (mod p).
+ // Thus, a^(p-2) is the multiplicative inverse.
+ //
+ // In order to efficiently compute a^(p-2), p-2 needs to be split into
+ // a sequence of squares and multipications that minimizes the number of
+ // multiplications needed (since they are more costly than squarings).
+ // Intermediate results are saved and reused as well.
+ //
+ // The secp256k1 prime - 2 is 2^256 - 4294968275.
+ //
+ // This has a cost of 258 field squarings and 33 field multiplications.
+ var a2, a3, a4, a10, a11, a21, a42, a45, a63, a1019, a1023 fieldVal
+ a2.SquareVal(f)
+ a3.Mul2(&a2, f)
+ a4.SquareVal(&a2)
+ a10.SquareVal(&a4).Mul(&a2)
+ a11.Mul2(&a10, f)
+ a21.Mul2(&a10, &a11)
+ a42.SquareVal(&a21)
+ a45.Mul2(&a42, &a3)
+ a63.Mul2(&a42, &a21)
+ a1019.SquareVal(&a63).Square().Square().Square().Mul(&a11)
+ a1023.Mul2(&a1019, &a4)
+ f.Set(&a63) // f = a^(2^6 - 1)
+ f.Square().Square().Square().Square().Square() // f = a^(2^11 - 32)
+ f.Square().Square().Square().Square().Square() // f = a^(2^16 - 1024)
+ f.Mul(&a1023) // f = a^(2^16 - 1)
+ f.Square().Square().Square().Square().Square() // f = a^(2^21 - 32)
+ f.Square().Square().Square().Square().Square() // f = a^(2^26 - 1024)
+ f.Mul(&a1023) // f = a^(2^26 - 1)
+ f.Square().Square().Square().Square().Square() // f = a^(2^31 - 32)
+ f.Square().Square().Square().Square().Square() // f = a^(2^36 - 1024)
+ f.Mul(&a1023) // f = a^(2^36 - 1)
+ f.Square().Square().Square().Square().Square() // f = a^(2^41 - 32)
+ f.Square().Square().Square().Square().Square() // f = a^(2^46 - 1024)
+ f.Mul(&a1023) // f = a^(2^46 - 1)
+ f.Square().Square().Square().Square().Square() // f = a^(2^51 - 32)
+ f.Square().Square().Square().Square().Square() // f = a^(2^56 - 1024)
+ f.Mul(&a1023) // f = a^(2^56 - 1)
+ f.Square().Square().Square().Square().Square() // f = a^(2^61 - 32)
+ f.Square().Square().Square().Square().Square() // f = a^(2^66 - 1024)
+ f.Mul(&a1023) // f = a^(2^66 - 1)
+ f.Square().Square().Square().Square().Square() // f = a^(2^71 - 32)
+ f.Square().Square().Square().Square().Square() // f = a^(2^76 - 1024)
+ f.Mul(&a1023) // f = a^(2^76 - 1)
+ f.Square().Square().Square().Square().Square() // f = a^(2^81 - 32)
+ f.Square().Square().Square().Square().Square() // f = a^(2^86 - 1024)
+ f.Mul(&a1023) // f = a^(2^86 - 1)
+ f.Square().Square().Square().Square().Square() // f = a^(2^91 - 32)
+ f.Square().Square().Square().Square().Square() // f = a^(2^96 - 1024)
+ f.Mul(&a1023) // f = a^(2^96 - 1)
+ f.Square().Square().Square().Square().Square() // f = a^(2^101 - 32)
+ f.Square().Square().Square().Square().Square() // f = a^(2^106 - 1024)
+ f.Mul(&a1023) // f = a^(2^106 - 1)
+ f.Square().Square().Square().Square().Square() // f = a^(2^111 - 32)
+ f.Square().Square().Square().Square().Square() // f = a^(2^116 - 1024)
+ f.Mul(&a1023) // f = a^(2^116 - 1)
+ f.Square().Square().Square().Square().Square() // f = a^(2^121 - 32)
+ f.Square().Square().Square().Square().Square() // f = a^(2^126 - 1024)
+ f.Mul(&a1023) // f = a^(2^126 - 1)
+ f.Square().Square().Square().Square().Square() // f = a^(2^131 - 32)
+ f.Square().Square().Square().Square().Square() // f = a^(2^136 - 1024)
+ f.Mul(&a1023) // f = a^(2^136 - 1)
+ f.Square().Square().Square().Square().Square() // f = a^(2^141 - 32)
+ f.Square().Square().Square().Square().Square() // f = a^(2^146 - 1024)
+ f.Mul(&a1023) // f = a^(2^146 - 1)
+ f.Square().Square().Square().Square().Square() // f = a^(2^151 - 32)
+ f.Square().Square().Square().Square().Square() // f = a^(2^156 - 1024)
+ f.Mul(&a1023) // f = a^(2^156 - 1)
+ f.Square().Square().Square().Square().Square() // f = a^(2^161 - 32)
+ f.Square().Square().Square().Square().Square() // f = a^(2^166 - 1024)
+ f.Mul(&a1023) // f = a^(2^166 - 1)
+ f.Square().Square().Square().Square().Square() // f = a^(2^171 - 32)
+ f.Square().Square().Square().Square().Square() // f = a^(2^176 - 1024)
+ f.Mul(&a1023) // f = a^(2^176 - 1)
+ f.Square().Square().Square().Square().Square() // f = a^(2^181 - 32)
+ f.Square().Square().Square().Square().Square() // f = a^(2^186 - 1024)
+ f.Mul(&a1023) // f = a^(2^186 - 1)
+ f.Square().Square().Square().Square().Square() // f = a^(2^191 - 32)
+ f.Square().Square().Square().Square().Square() // f = a^(2^196 - 1024)
+ f.Mul(&a1023) // f = a^(2^196 - 1)
+ f.Square().Square().Square().Square().Square() // f = a^(2^201 - 32)
+ f.Square().Square().Square().Square().Square() // f = a^(2^206 - 1024)
+ f.Mul(&a1023) // f = a^(2^206 - 1)
+ f.Square().Square().Square().Square().Square() // f = a^(2^211 - 32)
+ f.Square().Square().Square().Square().Square() // f = a^(2^216 - 1024)
+ f.Mul(&a1023) // f = a^(2^216 - 1)
+ f.Square().Square().Square().Square().Square() // f = a^(2^221 - 32)
+ f.Square().Square().Square().Square().Square() // f = a^(2^226 - 1024)
+ f.Mul(&a1019) // f = a^(2^226 - 5)
+ f.Square().Square().Square().Square().Square() // f = a^(2^231 - 160)
+ f.Square().Square().Square().Square().Square() // f = a^(2^236 - 5120)
+ f.Mul(&a1023) // f = a^(2^236 - 4097)
+ f.Square().Square().Square().Square().Square() // f = a^(2^241 - 131104)
+ f.Square().Square().Square().Square().Square() // f = a^(2^246 - 4195328)
+ f.Mul(&a1023) // f = a^(2^246 - 4194305)
+ f.Square().Square().Square().Square().Square() // f = a^(2^251 - 134217760)
+ f.Square().Square().Square().Square().Square() // f = a^(2^256 - 4294968320)
+ return f.Mul(&a45) // f = a^(2^256 - 4294968275) = a^(p-2)
+}
diff --git a/vendor/github.com/btcsuite/btcd/btcec/genprecomps.go b/vendor/github.com/btcsuite/btcd/btcec/genprecomps.go
new file mode 100644
index 0000000000..d4a9c1b830
--- /dev/null
+++ b/vendor/github.com/btcsuite/btcd/btcec/genprecomps.go
@@ -0,0 +1,63 @@
+// Copyright 2015 The btcsuite developers
+// Use of this source code is governed by an ISC
+// license that can be found in the LICENSE file.
+
+// This file is ignored during the regular build due to the following build tag.
+// It is called by go generate and used to automatically generate pre-computed
+// tables used to accelerate operations.
+// +build ignore
+
+package main
+
+import (
+ "bytes"
+ "compress/zlib"
+ "encoding/base64"
+ "fmt"
+ "log"
+ "os"
+
+ "github.com/btcsuite/btcd/btcec"
+)
+
+func main() {
+ fi, err := os.Create("secp256k1.go")
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer fi.Close()
+
+ // Compress the serialized byte points.
+ serialized := btcec.S256().SerializedBytePoints()
+ var compressed bytes.Buffer
+ w := zlib.NewWriter(&compressed)
+ if _, err := w.Write(serialized); err != nil {
+ fmt.Println(err)
+ os.Exit(1)
+ }
+ w.Close()
+
+ // Encode the compressed byte points with base64.
+ encoded := make([]byte, base64.StdEncoding.EncodedLen(compressed.Len()))
+ base64.StdEncoding.Encode(encoded, compressed.Bytes())
+
+ fmt.Fprintln(fi, "// Copyright (c) 2015 The btcsuite developers")
+ fmt.Fprintln(fi, "// Use of this source code is governed by an ISC")
+ fmt.Fprintln(fi, "// license that can be found in the LICENSE file.")
+ fmt.Fprintln(fi)
+ fmt.Fprintln(fi, "package btcec")
+ fmt.Fprintln(fi)
+ fmt.Fprintln(fi, "// Auto-generated file (see genprecomps.go)")
+ fmt.Fprintln(fi, "// DO NOT EDIT")
+ fmt.Fprintln(fi)
+ fmt.Fprintf(fi, "var secp256k1BytePoints = %q\n", string(encoded))
+
+ a1, b1, a2, b2 := btcec.S256().EndomorphismVectors()
+ fmt.Println("The following values are the computed linearly " +
+ "independent vectors needed to make use of the secp256k1 " +
+ "endomorphism:")
+ fmt.Printf("a1: %x\n", a1)
+ fmt.Printf("b1: %x\n", b1)
+ fmt.Printf("a2: %x\n", a2)
+ fmt.Printf("b2: %x\n", b2)
+}
diff --git a/vendor/github.com/btcsuite/btcd/btcec/gensecp256k1.go b/vendor/github.com/btcsuite/btcd/btcec/gensecp256k1.go
new file mode 100644
index 0000000000..1928702da8
--- /dev/null
+++ b/vendor/github.com/btcsuite/btcd/btcec/gensecp256k1.go
@@ -0,0 +1,203 @@
+// Copyright (c) 2014-2015 The btcsuite developers
+// Use of this source code is governed by an ISC
+// license that can be found in the LICENSE file.
+
+// This file is ignored during the regular build due to the following build tag.
+// This build tag is set during go generate.
+// +build gensecp256k1
+
+package btcec
+
+// References:
+// [GECC]: Guide to Elliptic Curve Cryptography (Hankerson, Menezes, Vanstone)
+
+import (
+ "encoding/binary"
+ "math/big"
+)
+
+// secp256k1BytePoints are dummy points used so the code which generates the
+// real values can compile.
+var secp256k1BytePoints = ""
+
+// getDoublingPoints returns all the possible G^(2^i) for i in
+// 0..n-1 where n is the curve's bit size (256 in the case of secp256k1)
+// the coordinates are recorded as Jacobian coordinates.
+func (curve *KoblitzCurve) getDoublingPoints() [][3]fieldVal {
+ doublingPoints := make([][3]fieldVal, curve.BitSize)
+
+ // initialize px, py, pz to the Jacobian coordinates for the base point
+ px, py := curve.bigAffineToField(curve.Gx, curve.Gy)
+ pz := new(fieldVal).SetInt(1)
+ for i := 0; i < curve.BitSize; i++ {
+ doublingPoints[i] = [3]fieldVal{*px, *py, *pz}
+ // P = 2*P
+ curve.doubleJacobian(px, py, pz, px, py, pz)
+ }
+ return doublingPoints
+}
+
+// SerializedBytePoints returns a serialized byte slice which contains all of
+// the possible points per 8-bit window. This is used to when generating
+// secp256k1.go.
+func (curve *KoblitzCurve) SerializedBytePoints() []byte {
+ doublingPoints := curve.getDoublingPoints()
+
+ // Segregate the bits into byte-sized windows
+ serialized := make([]byte, curve.byteSize*256*3*10*4)
+ offset := 0
+ for byteNum := 0; byteNum < curve.byteSize; byteNum++ {
+ // Grab the 8 bits that make up this byte from doublingPoints.
+ startingBit := 8 * (curve.byteSize - byteNum - 1)
+ computingPoints := doublingPoints[startingBit : startingBit+8]
+
+ // Compute all points in this window and serialize them.
+ for i := 0; i < 256; i++ {
+ px, py, pz := new(fieldVal), new(fieldVal), new(fieldVal)
+ for j := 0; j < 8; j++ {
+ if i>>uint(j)&1 == 1 {
+ curve.addJacobian(px, py, pz, &computingPoints[j][0],
+ &computingPoints[j][1], &computingPoints[j][2], px, py, pz)
+ }
+ }
+ for i := 0; i < 10; i++ {
+ binary.LittleEndian.PutUint32(serialized[offset:], px.n[i])
+ offset += 4
+ }
+ for i := 0; i < 10; i++ {
+ binary.LittleEndian.PutUint32(serialized[offset:], py.n[i])
+ offset += 4
+ }
+ for i := 0; i < 10; i++ {
+ binary.LittleEndian.PutUint32(serialized[offset:], pz.n[i])
+ offset += 4
+ }
+ }
+ }
+
+ return serialized
+}
+
+// sqrt returns the square root of the provided big integer using Newton's
+// method. It's only compiled and used during generation of pre-computed
+// values, so speed is not a huge concern.
+func sqrt(n *big.Int) *big.Int {
+ // Initial guess = 2^(log_2(n)/2)
+ guess := big.NewInt(2)
+ guess.Exp(guess, big.NewInt(int64(n.BitLen()/2)), nil)
+
+ // Now refine using Newton's method.
+ big2 := big.NewInt(2)
+ prevGuess := big.NewInt(0)
+ for {
+ prevGuess.Set(guess)
+ guess.Add(guess, new(big.Int).Div(n, guess))
+ guess.Div(guess, big2)
+ if guess.Cmp(prevGuess) == 0 {
+ break
+ }
+ }
+ return guess
+}
+
+// EndomorphismVectors runs the first 3 steps of algorithm 3.74 from [GECC] to
+// generate the linearly independent vectors needed to generate a balanced
+// length-two representation of a multiplier such that k = k1 + k2λ (mod N) and
+// returns them. Since the values will always be the same given the fact that N
+// and λ are fixed, the final results can be accelerated by storing the
+// precomputed values with the curve.
+func (curve *KoblitzCurve) EndomorphismVectors() (a1, b1, a2, b2 *big.Int) {
+ bigMinus1 := big.NewInt(-1)
+
+ // This section uses an extended Euclidean algorithm to generate a
+ // sequence of equations:
+ // s[i] * N + t[i] * λ = r[i]
+
+ nSqrt := sqrt(curve.N)
+ u, v := new(big.Int).Set(curve.N), new(big.Int).Set(curve.lambda)
+ x1, y1 := big.NewInt(1), big.NewInt(0)
+ x2, y2 := big.NewInt(0), big.NewInt(1)
+ q, r := new(big.Int), new(big.Int)
+ qu, qx1, qy1 := new(big.Int), new(big.Int), new(big.Int)
+ s, t := new(big.Int), new(big.Int)
+ ri, ti := new(big.Int), new(big.Int)
+ a1, b1, a2, b2 = new(big.Int), new(big.Int), new(big.Int), new(big.Int)
+ found, oneMore := false, false
+ for u.Sign() != 0 {
+ // q = v/u
+ q.Div(v, u)
+
+ // r = v - q*u
+ qu.Mul(q, u)
+ r.Sub(v, qu)
+
+ // s = x2 - q*x1
+ qx1.Mul(q, x1)
+ s.Sub(x2, qx1)
+
+ // t = y2 - q*y1
+ qy1.Mul(q, y1)
+ t.Sub(y2, qy1)
+
+ // v = u, u = r, x2 = x1, x1 = s, y2 = y1, y1 = t
+ v.Set(u)
+ u.Set(r)
+ x2.Set(x1)
+ x1.Set(s)
+ y2.Set(y1)
+ y1.Set(t)
+
+ // As soon as the remainder is less than the sqrt of n, the
+ // values of a1 and b1 are known.
+ if !found && r.Cmp(nSqrt) < 0 {
+ // When this condition executes ri and ti represent the
+ // r[i] and t[i] values such that i is the greatest
+ // index for which r >= sqrt(n). Meanwhile, the current
+ // r and t values are r[i+1] and t[i+1], respectively.
+
+ // a1 = r[i+1], b1 = -t[i+1]
+ a1.Set(r)
+ b1.Mul(t, bigMinus1)
+ found = true
+ oneMore = true
+
+ // Skip to the next iteration so ri and ti are not
+ // modified.
+ continue
+
+ } else if oneMore {
+ // When this condition executes ri and ti still
+ // represent the r[i] and t[i] values while the current
+ // r and t are r[i+2] and t[i+2], respectively.
+
+ // sum1 = r[i]^2 + t[i]^2
+ rSquared := new(big.Int).Mul(ri, ri)
+ tSquared := new(big.Int).Mul(ti, ti)
+ sum1 := new(big.Int).Add(rSquared, tSquared)
+
+ // sum2 = r[i+2]^2 + t[i+2]^2
+ r2Squared := new(big.Int).Mul(r, r)
+ t2Squared := new(big.Int).Mul(t, t)
+ sum2 := new(big.Int).Add(r2Squared, t2Squared)
+
+ // if (r[i]^2 + t[i]^2) <= (r[i+2]^2 + t[i+2]^2)
+ if sum1.Cmp(sum2) <= 0 {
+ // a2 = r[i], b2 = -t[i]
+ a2.Set(ri)
+ b2.Mul(ti, bigMinus1)
+ } else {
+ // a2 = r[i+2], b2 = -t[i+2]
+ a2.Set(r)
+ b2.Mul(t, bigMinus1)
+ }
+
+ // All done.
+ break
+ }
+
+ ri.Set(r)
+ ti.Set(t)
+ }
+
+ return a1, b1, a2, b2
+}
diff --git a/vendor/github.com/btcsuite/btcd/btcec/precompute.go b/vendor/github.com/btcsuite/btcd/btcec/precompute.go
new file mode 100644
index 0000000000..034cd55332
--- /dev/null
+++ b/vendor/github.com/btcsuite/btcd/btcec/precompute.go
@@ -0,0 +1,67 @@
+// Copyright 2015 The btcsuite developers
+// Use of this source code is governed by an ISC
+// license that can be found in the LICENSE file.
+
+package btcec
+
+import (
+ "compress/zlib"
+ "encoding/base64"
+ "encoding/binary"
+ "io/ioutil"
+ "strings"
+)
+
+//go:generate go run -tags gensecp256k1 genprecomps.go
+
+// loadS256BytePoints decompresses and deserializes the pre-computed byte points
+// used to accelerate scalar base multiplication for the secp256k1 curve. This
+// approach is used since it allows the compile to use significantly less ram
+// and be performed much faster than it is with hard-coding the final in-memory
+// data structure. At the same time, it is quite fast to generate the in-memory
+// data structure at init time with this approach versus computing the table.
+func loadS256BytePoints() error {
+ // There will be no byte points to load when generating them.
+ bp := secp256k1BytePoints
+ if len(bp) == 0 {
+ return nil
+ }
+
+ // Decompress the pre-computed table used to accelerate scalar base
+ // multiplication.
+ decoder := base64.NewDecoder(base64.StdEncoding, strings.NewReader(bp))
+ r, err := zlib.NewReader(decoder)
+ if err != nil {
+ return err
+ }
+ serialized, err := ioutil.ReadAll(r)
+ if err != nil {
+ return err
+ }
+
+ // Deserialize the precomputed byte points and set the curve to them.
+ offset := 0
+ var bytePoints [32][256][3]fieldVal
+ for byteNum := 0; byteNum < 32; byteNum++ {
+ // All points in this window.
+ for i := 0; i < 256; i++ {
+ px := &bytePoints[byteNum][i][0]
+ py := &bytePoints[byteNum][i][1]
+ pz := &bytePoints[byteNum][i][2]
+ for i := 0; i < 10; i++ {
+ px.n[i] = binary.LittleEndian.Uint32(serialized[offset:])
+ offset += 4
+ }
+ for i := 0; i < 10; i++ {
+ py.n[i] = binary.LittleEndian.Uint32(serialized[offset:])
+ offset += 4
+ }
+ for i := 0; i < 10; i++ {
+ pz.n[i] = binary.LittleEndian.Uint32(serialized[offset:])
+ offset += 4
+ }
+ }
+ }
+ secp256k1.bytePoints = &bytePoints
+ return nil
+}
diff --git a/vendor/github.com/btcsuite/btcd/btcec/privkey.go b/vendor/github.com/btcsuite/btcd/btcec/privkey.go
new file mode 100644
index 0000000000..676a8c3fb0
--- /dev/null
+++ b/vendor/github.com/btcsuite/btcd/btcec/privkey.go
@@ -0,0 +1,73 @@
+// Copyright (c) 2013-2016 The btcsuite developers
+// Use of this source code is governed by an ISC
+// license that can be found in the LICENSE file.
+
+package btcec
+
+import (
+ "crypto/ecdsa"
+ "crypto/elliptic"
+ "crypto/rand"
+ "math/big"
+)
+
+// PrivateKey wraps an ecdsa.PrivateKey as a convenience mainly for signing
+// things with the the private key without having to directly import the ecdsa
+// package.
+type PrivateKey ecdsa.PrivateKey
+
+// PrivKeyFromBytes returns a private and public key for `curve' based on the
+// private key passed as an argument as a byte slice.
+func PrivKeyFromBytes(curve elliptic.Curve, pk []byte) (*PrivateKey,
+ *PublicKey) {
+ x, y := curve.ScalarBaseMult(pk)
+
+ priv := &ecdsa.PrivateKey{
+ PublicKey: ecdsa.PublicKey{
+ Curve: curve,
+ X: x,
+ Y: y,
+ },
+ D: new(big.Int).SetBytes(pk),
+ }
+
+ return (*PrivateKey)(priv), (*PublicKey)(&priv.PublicKey)
+}
+
+// NewPrivateKey is a wrapper for ecdsa.GenerateKey that returns a PrivateKey
+// instead of the normal ecdsa.PrivateKey.
+func NewPrivateKey(curve elliptic.Curve) (*PrivateKey, error) {
+ key, err := ecdsa.GenerateKey(curve, rand.Reader)
+ if err != nil {
+ return nil, err
+ }
+ return (*PrivateKey)(key), nil
+}
+
+// PubKey returns the PublicKey corresponding to this private key.
+func (p *PrivateKey) PubKey() *PublicKey {
+ return (*PublicKey)(&p.PublicKey)
+}
+
+// ToECDSA returns the private key as a *ecdsa.PrivateKey.
+func (p *PrivateKey) ToECDSA() *ecdsa.PrivateKey {
+ return (*ecdsa.PrivateKey)(p)
+}
+
+// Sign generates an ECDSA signature for the provided hash (which should be the result
+// of hashing a larger message) using the private key. Produced signature
+// is deterministic (same message and same key yield the same signature) and canonical
+// in accordance with RFC6979 and BIP0062.
+func (p *PrivateKey) Sign(hash []byte) (*Signature, error) {
+ return signRFC6979(p, hash)
+}
+
+// PrivKeyBytesLen defines the length in bytes of a serialized private key.
+const PrivKeyBytesLen = 32
+
+// Serialize returns the private key number d as a big-endian binary-encoded
+// number, padded to a length of 32 bytes.
+func (p *PrivateKey) Serialize() []byte {
+ b := make([]byte, 0, PrivKeyBytesLen)
+ return paddedAppend(PrivKeyBytesLen, b, p.ToECDSA().D.Bytes())
+}
diff --git a/vendor/github.com/btcsuite/btcd/btcec/pubkey.go b/vendor/github.com/btcsuite/btcd/btcec/pubkey.go
new file mode 100644
index 0000000000..f145414ecc
--- /dev/null
+++ b/vendor/github.com/btcsuite/btcd/btcec/pubkey.go
@@ -0,0 +1,172 @@
+// Copyright (c) 2013-2014 The btcsuite developers
+// Use of this source code is governed by an ISC
+// license that can be found in the LICENSE file.
+
+package btcec
+
+import (
+ "crypto/ecdsa"
+ "errors"
+ "fmt"
+ "math/big"
+)
+
+// These constants define the lengths of serialized public keys.
+const (
+ PubKeyBytesLenCompressed = 33
+ PubKeyBytesLenUncompressed = 65
+ PubKeyBytesLenHybrid = 65
+)
+
+func isOdd(a *big.Int) bool {
+ return a.Bit(0) == 1
+}
+
+// decompressPoint decompresses a point on the given curve given the X point and
+// the solution to use.
+func decompressPoint(curve *KoblitzCurve, x *big.Int, ybit bool) (*big.Int, error) {
+ // TODO: This will probably only work for secp256k1 due to
+ // optimizations.
+
+ // Y = +-sqrt(x^3 + B)
+ x3 := new(big.Int).Mul(x, x)
+ x3.Mul(x3, x)
+ x3.Add(x3, curve.Params().B)
+
+ // now calculate sqrt mod p of x2 + B
+ // This code used to do a full sqrt based on tonelli/shanks,
+ // but this was replaced by the algorithms referenced in
+ // https://bitcointalk.org/index.php?topic=162805.msg1712294#msg1712294
+ y := new(big.Int).Exp(x3, curve.QPlus1Div4(), curve.Params().P)
+
+ if ybit != isOdd(y) {
+ y.Sub(curve.Params().P, y)
+ }
+ if ybit != isOdd(y) {
+ return nil, fmt.Errorf("ybit doesn't match oddness")
+ }
+ return y, nil
+}
+
+const (
+ pubkeyCompressed byte = 0x2 // y_bit + x coord
+ pubkeyUncompressed byte = 0x4 // x coord + y coord
+ pubkeyHybrid byte = 0x6 // y_bit + x coord + y coord
+)
+
+// ParsePubKey parses a public key for a koblitz curve from a bytestring into a
+// ecdsa.Publickey, verifying that it is valid. It supports compressed,
+// uncompressed and hybrid signature formats.
+func ParsePubKey(pubKeyStr []byte, curve *KoblitzCurve) (key *PublicKey, err error) {
+ pubkey := PublicKey{}
+ pubkey.Curve = curve
+
+ if len(pubKeyStr) == 0 {
+ return nil, errors.New("pubkey string is empty")
+ }
+
+ format := pubKeyStr[0]
+ ybit := (format & 0x1) == 0x1
+ format &= ^byte(0x1)
+
+ switch len(pubKeyStr) {
+ case PubKeyBytesLenUncompressed:
+ if format != pubkeyUncompressed && format != pubkeyHybrid {
+ return nil, fmt.Errorf("invalid magic in pubkey str: "+
+ "%d", pubKeyStr[0])
+ }
+
+ pubkey.X = new(big.Int).SetBytes(pubKeyStr[1:33])
+ pubkey.Y = new(big.Int).SetBytes(pubKeyStr[33:])
+ // hybrid keys have extra information, make use of it.
+ if format == pubkeyHybrid && ybit != isOdd(pubkey.Y) {
+ return nil, fmt.Errorf("ybit doesn't match oddness")
+ }
+ case PubKeyBytesLenCompressed:
+ // format is 0x2 | solution,
+ // solution determines which solution of the curve we use.
+ /// y^2 = x^3 + Curve.B
+ if format != pubkeyCompressed {
+ return nil, fmt.Errorf("invalid magic in compressed "+
+ "pubkey string: %d", pubKeyStr[0])
+ }
+ pubkey.X = new(big.Int).SetBytes(pubKeyStr[1:33])
+ pubkey.Y, err = decompressPoint(curve, pubkey.X, ybit)
+ if err != nil {
+ return nil, err
+ }
+ default: // wrong!
+ return nil, fmt.Errorf("invalid pub key length %d",
+ len(pubKeyStr))
+ }
+
+ if pubkey.X.Cmp(pubkey.Curve.Params().P) >= 0 {
+ return nil, fmt.Errorf("pubkey X parameter is >= to P")
+ }
+ if pubkey.Y.Cmp(pubkey.Curve.Params().P) >= 0 {
+ return nil, fmt.Errorf("pubkey Y parameter is >= to P")
+ }
+ if !pubkey.Curve.IsOnCurve(pubkey.X, pubkey.Y) {
+ return nil, fmt.Errorf("pubkey isn't on secp256k1 curve")
+ }
+ return &pubkey, nil
+}
+
+// PublicKey is an ecdsa.PublicKey with additional functions to
+// serialize in uncompressed, compressed, and hybrid formats.
+type PublicKey ecdsa.PublicKey
+
+// ToECDSA returns the public key as a *ecdsa.PublicKey.
+func (p *PublicKey) ToECDSA() *ecdsa.PublicKey {
+ return (*ecdsa.PublicKey)(p)
+}
+
+// SerializeUncompressed serializes a public key in a 65-byte uncompressed
+// format.
+func (p *PublicKey) SerializeUncompressed() []byte {
+ b := make([]byte, 0, PubKeyBytesLenUncompressed)
+ b = append(b, pubkeyUncompressed)
+ b = paddedAppend(32, b, p.X.Bytes())
+ return paddedAppend(32, b, p.Y.Bytes())
+}
+
+// SerializeCompressed serializes a public key in a 33-byte compressed format.
+func (p *PublicKey) SerializeCompressed() []byte {
+ b := make([]byte, 0, PubKeyBytesLenCompressed)
+ format := pubkeyCompressed
+ if isOdd(p.Y) {
+ format |= 0x1
+ }
+ b = append(b, format)
+ return paddedAppend(32, b, p.X.Bytes())
+}
+
+// SerializeHybrid serializes a public key in a 65-byte hybrid format.
+func (p *PublicKey) SerializeHybrid() []byte {
+ b := make([]byte, 0, PubKeyBytesLenHybrid)
+ format := pubkeyHybrid
+ if isOdd(p.Y) {
+ format |= 0x1
+ }
+ b = append(b, format)
+ b = paddedAppend(32, b, p.X.Bytes())
+ return paddedAppend(32, b, p.Y.Bytes())
+}
+
+// IsEqual compares this PublicKey instance to the one passed, returning true if
+// both PublicKeys are equivalent. A PublicKey is equivalent to another, if they
+// both have the same X and Y coordinate.
+func (p *PublicKey) IsEqual(otherPubKey *PublicKey) bool {
+ return p.X.Cmp(otherPubKey.X) == 0 &&
+ p.Y.Cmp(otherPubKey.Y) == 0
+}
+
+// paddedAppend appends the src byte slice to dst, returning the new slice.
+// If the length of the source is smaller than the passed size, leading zero
+// bytes are appended to the dst slice before appending src.
+func paddedAppend(size uint, dst, src []byte) []byte {
+ for i := 0; i < int(size)-len(src); i++ {
+ dst = append(dst, 0)
+ }
+ return append(dst, src...)
+}
diff --git a/vendor/github.com/btcsuite/btcd/btcec/secp256k1.go b/vendor/github.com/btcsuite/btcd/btcec/secp256k1.go
new file mode 100644
index 0000000000..5e7bffe4d9
--- /dev/null
+++ b/vendor/github.com/btcsuite/btcd/btcec/secp256k1.go
@@ -0,0 +1,10 @@
+// Copyright (c) 2015 The btcsuite developers
+// Use of this source code is governed by an ISC
+// license that can be found in the LICENSE file.
+
+package btcec
+
+// Auto-generated file (see genprecomps.go)
+// DO NOT EDIT
+
+var secp256k1BytePoints = "eJzEmoc/UI/3xs+ws5OZGaKi7BWKhqKU1RYaPkaDEA2kJERZaSdtbZJIRkoZpSVpb4WUREr4+f0V3/sX3HPuc57neb9eF/5HT12OJPy+1kbjUwxYojoI9978SCNZij7p55KAQTuXdaZTbogC2CUE4Z5gMzCa0MXzngnBojAJas8GDFQ5jw9KBgmPjeKwA+KQ1P8cRne1U+S7PHDIS6A+h2R64/OLxNb0QHhXBwRMkCXZ5rGg/u0EG2m+hpyUKPr1KpP6FIfRqHYCQYtSXrrDGvZpiXChsjCYKKzDN8a+qK0xAJJL+jhX3Ypm1ZhDWvcmfq96lb5XFKPSWwl4FNPCsUvPwqMDmhTwWoSPfvzLjxPOkd+l8dhvUA6YM4lflYyG81dO8Jme/WC64BWN6VhFxfMXwghHV/C9dRSUH1ehUVYm5txVhNDZUTAj/RXsmhrFBp/P8I1Ns+nYjxdonzufJk53Jph/jM4HS0KRwAgcuLgIvjecgsei+STvZoayGpW8ffgOavnpDEnaInSvXR0evZqAB+fdhn/uu3F+3BWstH3AGx7OgelC+zHztCbujNnP7vOU4JHJZsiPWkSrPkZy3jNx9vpRhNMkRuMak+vkNC0TV6pbk2qKFZg7/MOCzAYKvpfM3nUb2ej9HnI/IgexP+vRyKcJi0d3w+A3CfCW7aD/JnbA4aYzNPmZEkivuIHmr5/yM3l5utmyl5aNXga9syTALEACzN+fg5W9FSBecoG3up4F6WRLHjlcApKEbGh6oTA+KBaEGWebILaxkCKM8kkCbSmyP5flklagY/s+WiC0Ac3UivGVqxIUyguQeVQ///TbgZULQwn0s3h/QhFN/NoKmTdXwucvv9FmhAb82zyPvlknUmu7DoplOuH6PX1soCWJ6xZcA3eHt5A06TxUxCuBRfhoyD3C8FrbngLir1Dd3M1YYPOEA58W45PDb0hzczM9XGACKpLHuM7/GKVOOcSis7bCIoEyejppHXgMOJKDySjofAastUEFdpWIwO3gjYzOOqz+7SzsNHmGYzv7aIvcPwy6VMnZHE+istqQIxsHH78M5ysDlaz7PgiTJ1znxMnC7OAdQnn+H/CEyW+8IaUIgkpX0aXjJLdhC3jt30AuGY9JReYzL7+5FLoGWjEsLwIj60cO6Wonq8am071BSwzYPsjZi0bDvOa31Fo6lz/U/mLzymy8/ckEPDaYsK7LYdh3Ope6TmZi7bn5rPdqAC6nnuNZT4Th89kRVLxOAGRrG/nc70nUu66bs1xvwbwNbhjcsI/DP/mCwY10SH/1kYy9BWGWgiM8e5+KcWeNYPP0ZHAJayKzJ+WM2z7AV5fjMP5KOe/LNALvdG1odXIG7a/jUaf0FSS2nMSpDrPwZsgkeNf5CPcvzYSRXTIgPm09B/2yoKKDHaz+cQB23Lfkztfh0LRYgaRPboOxO6bAyQ1KsPXXJ0zwuIUv+7zw45VS/nTgBd9ImM5rpzWDids/NrsjBvl2KiD3+z2XKtZRudsSKt0YBL+gga+eLgMt91L6fa6Z79tL8WUZezBc6kxjPyhz4d/raO4TT3ry86j4fSTOOzoIOR1zcPGTcyCnaQAif1y58NdcVJCzpMS6cGg/y+BNVmyY6YeyOtvw0tO1nCSgAv8ywkG5IJtKr1+gsT4FbFWXDRcH0ijq0Te0P7ycvt9cR48KlcDs1HIYcMnFpeMr+GbYVW7MvQD5oo+xeoMiXh5zBnvti9F6tiCkmftSkVQwmFpnwZndL2HMrI/Y2LEX10dX4Oohv5SK84WfE/Rg15VNZDT/F3w7FQemwnp0N7mHf0d/At3NxjD91mrYld8KqZ+NYKJXMJ6N/McPfjrzev9zfHj0eNheNxLub/QFRc0m0k27zm2Gw6AgewfvXumBk47OhPxxzzh+4mewXtEO51cXQXVgJTksd8WSGwKw4dtmmt+kROtPT8OCwBp+/Xomb51cj7l7XtNv53BUnHcE1rEQPDKt5UYjF9JSukoq90ehwOhY2JT8iOu2LqSgrzqoumUmbZg1GlbNnAYKyq/4woA1/Ht3CNlxK2WNHQRJsSh6Kb4BXuaHUWmiEKws/MkXeCMEnjyG27aY8AONGbxe6zTcX34UbTy/wgcBRyw9NgKMnDpowel+uNfTRV7X9LlDKgrcbxXTlFYREBV0oaiZKRz7SxNUdL1BvNqVVk90wfddx/DDhJ3oLnuVFmmOY2EPUxY/6opty9Thv19/YcCskdcIhYOccytPX6rJ2SuLWCzVBES6z+DAFUckp7FQ39uNxisKqfvwPDh3cCasC23ByXAQvDMPgFrCQV5SVQ992dLQlicO7V1tuOFUP8vrPkXzowM0Mb6aV8xxhMpbRjS3qg+yN4+AVZ/LcdhsoMZBK1q39x3fUlSjEHcrDFyVhYHPnuHUnXegJtUCTko78+47nbzgXAhX67mxVowBrqn6zuOn2FHjiy6+c9KZr6vow4Ob/tis3wti7Q78UjCJ8LoXZDzahupLmASlRkFJmSP/vDgcjNTsWKXoGZmufI/9jxzIWW4jm/wQwrtBP8H46V0uCnjFpnmGsOmgDCVsm4hrnzXD4yUnMPaDO9+fU8dCbbe4sD0OUh9kQOhEDfCNXgAs5Yh+5sN47+zJSDIyfPX6SN5X10cSptp81OgAhr1RgMYrY+HDsNfg2pGCmd33wGJdKe1PqYWN077gPb10Tt1jjAdDJEAoS53L7Wvgs18a5ZRrkp/KHcoYcwGKSvfCkYO2eKZsGj9WnAh78RpGhz3Hcbn70G70bKy8Iwu3R/TgjclaYDbYgcPk94DQD0NQzUmH5xETeLpsMfWk7wXxjLk46UUIfTCLgk4tee4+J4RXHhGkVfiz5PFdvFAqAEJjdXFquzlP/ylHmt/q4PmQLlrJC303Eeg8WcF6B+rxhLgr7fa/g3nTLqONZh8lH7fl3V2juO3QWN5XMwL+6V0HuXBN6Du3l3SG9J0++hTIb7/HsSkn6KRcMUWPuIRLPdXAa95reCB1lHf2fOX36pIUZaSFSmkRcK9DmDZIT6H5sdKcNkIVDixoJawY6lW726El+xkrNn/nYCURThw4xylVYRwz4ABkYAAjrW+xTPAjaiIjkDw4B9ZYvOLAeQZg53CRj9pU8bO4LWzqKg37FWtx1N8aTtrlxtNW9+EOZSfQmfsM6qwO8OiIw9wf/BjzdEfDQqk13LK0n4+Vzht6HzGo+VhNzlvN8X6SC3S018AXlWOQo2wM5zOnU/x+Qfp8g3DY7yVU4v+WGmNewBWh3Zhcfhe/HG5BG9CCUar6TAG/aM4RByz7eBWuu3Vwd3oqXpTrIfsrPVBzeAro71EGiVpHdHE+CzNdd9ApkbPwLK6cphwJx5tB7agwYIlyXz1hj6g47F3zCe+fX0HHxs7E6sIjvMqwGJ49NYUXi5rQ9Okz2JqWjI7SFiAkG4Fv8z7gpVnOYDVpERUZf6K3J05T1Lkn6PUjHaq3/qM5H82g71gn1F+8wDKKh3Cy1RrwPjgDJ7oagVDNSFqnKYSyj/ORklRgNlvyxpE1xLXqlJlxmTa/agMT+0ioPF2KDtKT4WfIAjYU1oOKz3PxvkUQvFSJg6Mr1chzwB+L0v25yqGY4+PX0YQae74oJQtzxQw5tcGej8k2wQxhfdpoFMDnW8xRcNYXtIcJyC9G4YVJuiBeqAUty4x4oPI0TrEppHr/o9D6djTeedNJ8zYuBKnwTTS2bzz0NIzApyoHWDz/Aly/HkNFKaZsMPsmaA0447gfzajxnw755ghAkpMO+i6Rph2LctD7fDH1RhfRw05T2KySCI3vNvD6Kk8ejNGANdOyYfncRyR9ZwrluXexQfYf3GR0hpW+PSDHj9Z4b/pCokA9uJozGSfc1sSsWwtAeGjHz3vvc8QpUch3zYY9KzdA29XvpOevDtM07lFigTzHKyhC3KNuPjBCFq8tfgtyfwywwNge5kda4p3dRuCZ8Q+6hq0BoY2u+G/udJz1wZ5/d1nDIi9pPG68Hay/laL8nBGw/bo9Oad85jwva/LK382ff02hji1SfEf+LN0cylbD/tOwP0kCHgaOhSaR4RylXwShyasxeU83PWIJ2rAhE+pxG73b0wMDqZrwUrUbX+xSZNktaiQ26Q6ec79EJ5cks7xUIEw78IUX67mSxkJ5mBdvAF7a00lj3mc+v+8R/St7QLeHr6MEhyL6EZvDaT+Hc2OAJNzY3oM9YlV4OWISfPeJRd/4fXDJpBTvP7uNu9f+Rsn1/yAndyKMnWAMbopFzGMKwWvwFD71y+dESwPwXxaC0k1KUOq9klZKK0MBieJw4UgIGHsZwxzt0PaQNZ+v7aKSrbWod6ub4uUCuNBqIsw7q8A+DUup9nc7NcgbUu2JwxR56ysc3nQAzrproPnb19w8h+DB7TR6JLKBJhXX4UcbKbR/n4dz3z2jwAceoHeiAdTFDuIYJWOQjHxL9dU3WTdtEp1P/4XvRl3ANr1KXOcwk4MWOKPOSzkabiQBzfpOICqRBx80XtPJLAvyKBqPEjnZ9HtXICXk7maNFDfYM1kE/rx8iprTBmlHfT4tSK6CvftOg/D41XTLQYMrpAtJe5cxblqoDmqPnMHt8QCXd2VA4afFcHmaAo+xi8Q/trq4am4tq1THg2H2BNAJG8/1yjeBJUqpz8Uby40W8d+Vszi3aTtOOVHBX34lc/lGU1gllg8KU77zSYVBqJ/cDbW322G09Wr4dskWOpI2wYC4FPSd0oYrh06Dp/kejElZTE6jFVh6VS0cWWhA3rEG+EjsMNVOfUBXU0fASidbKJCp5QX+V3mzVDH9G2bHI7ac4Bda6yA88w7HjbzKYtv04KHNezQ9VYyLUBO3Kdng8v1DHJhxjec3WkF7vi9bJrfAlCJF2GlZApeCx3JWyCV2jGrFRBhPz9Ou0vDFYbBs1m5+daUROvwMoHEbUI/7R5y15xTsX74U1b7mUKjLUpoqJMxR/q3YGrKFbiyzhZ1JA3xhmBU7b9ClM+1VYN37D0eJtKLGcF8yTN8I0lda6U29HmjFpGO0rz/7h62iaWnjKLrFD5p2Mt3q+QDn8wywT/EoWV8ShIM7TOHiCGtqtyiFYVGF3P2fB648YA8+/22kRN6H3+y0IcpuBOx0vccPH/eD1rFNvKsrAfafrGMVAVf8sPcNYLU0nnYKhro2K7A/k4BrHGtZKG40xB9VIsm/JfDAQpinhCbjq9BptP3YbEpYx7Av2BfEx/VSzXakfs9COO0QBHqHC4jqPkH61Ie0dvIrKLltDiOsu2nTu2CWva1AiyKG0Z8nR2l7cxm2bXhCyy/300qZVr4/3Rii1VLgpqEdvEydzII7KpDLE/GvgwcqBiWz1I5CmNEXAnLC48ErI5J2CHeTnIEQayzejEtqAQucppKmQxsvlUV2zn1NqpqiMNX6GgWsU4SJTWPQ9t9NcH+ykEx2C1LLMmtW7I7C9G/KaF2iCivPhiPAaLx0ShOnmbrymu3bqKTGmJbOOIPHpCdz3F01nJUkAloTmsDz9CR8UHYDTbSG2FQyG7vCLoKUrADGP97Hh84yb7yoCMYCWdTr6gIb569mjaVTOUHyCFTJrKDwuZNggWYgqk9Xh1NlmmCuuhgTJkmyR6EfbdDZzUGfMuikvhYs2PIRXXuseO7T9Xy1eQSYdC/lScES+Nh7FMSNlufsfntqvauNe6cb0GjbOmw/9ZF2aU0Ada+zELTQEB3rtfmm9TVY0G+MnokZPPF4L9gG/iTt/jN43NMcJHfUcZjFIUxa2cyvDZIhOr6K1m68wP2yh2njz8e8fl8A5McIwLczfnzmWBVInr9P0lLn6GjBfijNmwgwMZsixEfR+nHV2COgDRlHv8D5ReakbDBAGsv/ofeDy1C3zpY2Nj/govcDBP+t48ImGSjOt0TZ06FUZPMINzUVQQXu5Pp562DZr7eY+SMAum93UU2rDiyWTSXfnrsw2JpHid3boaWkE7dJ/yKxJRGoFHwPf46rgqwcgLg5SfTn5WN8trqOI66XsNZaSTh+3J6viD3n6/E7wDL6Ge7aag53NeZjdU4bpfuPI5Wzj3ntHgMyQj0+6qNDT5e68+eUEsh8rAzXTZOpYrMG/NAP46mnozFqiwRbFhTQFuMefHn1M+uNUUFnHSPoH/hNFa27cdl/xjSptBDW/r0Lb17GoaaGCGk5nqfWHzIg6GgDf+IzcI7WcKTXI5lTxsFsyKPq5x0olJYNuu7uJBOcCnnvBEBG5zMZXTKgDQuugJO9L1RKpZPLlA38pOIAdN9qoIOvHnL5DUPoyziFbY6j+IjXET7lnAYlY4VAyQDAY5QOJv1+Qq/PhmBJixScOaNLO1xK+Gv9TqoyAJ74Yyp0+Kui6oVbFJKjTPfb1qL9YyWQkm7h65szYPUQs8qXiaFU+Vtqf1dBolsbYLNLP69+Oo9FHO2g6+BkXtTwB9LOmVKzrj3JdLrQryMRKOCzBjvalVFy71f6nmME8UuGbjXRHsLVvSiiYjHXjbDlnvR/+HzdO4xqbsKQgD0oISEL9eOPwDz1hfTj9V9WzDyMu10F0EywHlsve7Hvkx+gO+0Abf6nD801fzG7TwNvDnSzh5UI2Y7txV7rV0BlLzClvxAq6yTgzRYDiFF6wlGFuni73x+Di6ez+eRI7HibhXe2XYbAbVV0oqqTDtvogltrIhubaXPpwTL2Oh/CaqNG8KcVVtBxZzbuX3YGjW3HQ3mDEOiqlOEojfsUFv4a7OabEN3wxCl1rbx60isWW/qSytq/geoYPTidY0WuV7S4TjEfE7wD4FBLFyW2n4DU7dNwZfpjLDvxEO6/kAO9in1QcrMa3714z+Ja12DWsjq4fPw2Deh85hH9MhQf/YQEVMdCdIInKL8oAJFNZ8hujyEG9rylWQkpaCuZyWGyXSzpswVtrxqD9xCXiAX/xnj9XxRTY8H9s+TBqtyar60nfmrpyOl/jvKDkfqQ/EeXfpwWIhWVRXjM8xRFHDVG0a6Z+GNMKKkNy4BJR0KGeHw4aOZ9J+XnJ2BkYhjF7BoBq1PugfjvYzhslCCOcVqDFaJzwU7QDI5sOA0X9q9GtySEqTn7EKiSs7M2QsLJbWQ60YEzz9Vj3WlBKFAQpaiF4VQ9oQpVSZvafyRT/X4DaHffybt3CnL5oZ+467IYzPrqjdP1e2BV+mpokP2Bn1a9BYOPAly+Up9S8qayWVcAXGjSgYNR72mZUxkfjnpHe4t/Q8uMtRQId2HjXgUSOmfDy0Rm0WCRLHyg/bxc5Ay/jzLnQo3b/GVZKr+a1IK/Ng7QHgdk6a83aMVXgs6YFDgo2E/GI+Tp5L0IfmivSRcPS7FqTxY3PH0PpxSLae5yFTjbMQGdw8ejctpt3tQiTbY210inXZ3HNG7HYL/b5OopQyO1jMH4mDJ4xRyGmRY70WphHixaNR82HcnlpTHLqHfGMWwTUoJbJcIw1awbZD5LQKiCF/t9TsWuE3G0sG48LNi+l9xismDjoftwyVQFHtv+5a5jb2lawzbaInwZe1u1ef60ayCpEop9QwTSoHON/T7ZwfveuyDYEUP76r+Rz+oUdt4xBpNUQ7HmpANAsAo9KK4Dt8OikDbqCi3PfUnl8qdxrWcXlgwWkdnzTsybaIvugTn4zV6ERJWH+rNfLEaHR3DArmgctV4Nbp42xIG0d6gW/4b2yphge+VZ2njMAN4WmGFkWDc08iTYa7iFpFafgkqzKxC4aw3zotMoFHSQVheow+M76mzkqQC2ExsoafFI3nygmLyyVqN9XzkK3OqlP4HZVK8pCQUXflBXSCwEdI7Afu+ZtPC/zSQXsowjB1fBltuJNFDlTCnXx0D6zUhYX9DAb+4cI4d308n5xzb2OybMCyRGUFngHwgcE8KhUorgsseRNWos0KftLnvqFWDS9wZ46qpFl1NvQ1D1YxKVGaSVD4VA4+53EjquRH8vm6GtUiX1qtvAw6IedFRBElgSA857hoPJMTloHNiNB621sK/zPCW5rsVNv3/QnhgbfH4uhAS/leHMwSA48X4CNBodBIPI5zh1mgTdXl4KrbU/MO+VBP1aas/7bkeR359jlOQpDF7zrqBARAHP9VlPP1PHcb/bEZZaOQGmPViGc2ceoZI9bdTtZQHw7jQ2SoTCCu086NyUwiEKWRxJb2GzYgsc5aGbXyjF/m+0IXq2G8sop7Ds4xKategnC2uNIZr9iLpnnUWRgzlQG+KKnyaOhLfxwzEXl4C//HF+n+XBdiLTabhQDV/b9gqDMw5CceYMfDtcFPZf3sjZ637D/K1L8FrceUh+MZECvQ/zoEMdfA95DO//hdPSbjMoqYvH7SdbyGCwFU4kDgPbqV8wd4sQaG+JYPVhwljdNYz2iYyAXvhFphY/4ZrKCfb1quOgp7k8SjcKbX5tYdO0v2wuPobrYmXB40sle9Q0w3eH2Xz/Ry4vv+lEmi5aUPpkGUdILqDiTwfAUNcY/mjmkmdEBCWnrsWeC0vYIWMifQ2+Qm6pdWz1RxDlep/h73CAv4tHo2BVGKsOKwZXd3ec+LiLD70MYTqSD8Lh/Xg92BLjNolCrGYNxoZ+oVvj88jAcABULa5TUoY95U7PZKttkyhGNpi/hGuB/r0KOP5CEw3UPNhlkQjZrA2AD9ViWHpOjuZKpKPY4XwIzJOF+UayKKE7ngPa2/BLyRN6cswVvwyc4aJaLzwbshYMP+Zxd7IRjP31g9fU3eOCna3sdsQWhJ8WwvdgWZgnf4TNd6rjua39HLRGGURKpcjpgjiFLf/LtvoDPHPIO9cuRpzs5Ul7rx+jU1PU8NxvgCrxf5gQ1ElVz9bSjLyh7zK8B74vH0dzt/3CVrt1fOq8B/28OBZ2D8yCyLrJKP+jmvMs1bhrdzxFDK/m3znDsPSUOak33KL1Jw0hY0Eg1/uUgZ+vJ8TVtPC4a7pYercFu79VYVKvNqTaxpC+sAo8UMulXetPoXqYBnpbTMQnv1NpdPFMave7CdfV+7G6XI0jMgRh/CQtoHsJ5Ivp+L7JHS7uG85X//NEw9q/0BH0lcw2PAbtlwAL1Gwh3XMVjJhyEky8CHqbgqHfTpCvfY6mwq5tdO/STYq/ZgPjwjbh/Cfa+PnHYez/Yo4ZyhEUu6kTTutdxbb508EkXRKfusoBDuxHKfMo7t1Si68iz/PR2frosrWM7iy8DPeVj6NPpCDflZWGg4Zl+Kr7LwvtEOCkGzzUzwdZZ9soHviyk729alHdWBXWj5UFgxJ1CLkeSVFyvdC0tJs7+oOw96w0ilUuofgfCbh67HnWlNeA41t12VRQgXK3q+ATdScK/BfNK6b7o7mVEyz/GoY7RuTgoJ8YPDBUxG+OCVTx5zU2/NEA16XeND/uO6/IjgLf5/5QqjGNhxfoQPZocZYP+Ay5u3ZRuIcgLCsrxoLJVXyxfidrnQ2HZtMhdu+VgYkyJpyl+B86lP6Hu9XGwwEdLTg4pJXPZpvp/a4ELg8Vp6nT5KFGRJoGb6piY/16TpdNgbOP1LlcSgP1n7vBqdrVsOFNJc/LlYaKIWa85VsNZzfcoJQDL2D4eR10qOjmFjUbqLu2BX5FlJHhU0loRDNSjZmPrkFFIOrzBtZvNyCJZ9NoW0Mf4GUPqHNOxOb/DIZyew527H/Kj14ugmNZb/lX4wqyFdaG3ClTcPnxVhiA9fxyqS3EHbaHaz+UKGIRodfhX1z1tpRHTknHrz6JcLarBAwuaVKK4XAwkroDC86KwccpKnxQrJOkTp4BtZmHObPtCJzYYowHksJ4wg1lUL+mxD0692CXz2PqXnSI7mpu5eVmAlS2bgwaBOXT3KZqNj+uDBuvPIKkxCLqETfEENHXZJD9D3y1R0L3Cgk4Ev8CAs+foPO9diDp/B7POM/iq8/ucJOHPb4s6yWR32eGbiOHewTM4IOrMo9VVQTe18w+z/Zz6VEj/PA9Hk70h5NDhD/r3RMCy3JV/Fh9l8d0ADwjG9DxOoVnWg+RoMk01L9YAooqWVxW60nezrmYYHmWXrmZwHQ5VzCTSIWObXvxdU4qeB26SOVWMbS38RCXBSlw7L9IOl6lAkmLXmCX7kRQkHsCgycH6VLtW0gTz6BRY5fhzutaOCI1BXsczGBw8mq61uMEzXQDnctaeeNbX1p5cDdeCRjHxy2yQMWpj6fOnQBmC0RJ7vs9umyZxTK9jrzlhTMkL3RBi/EioFe8G+bUOUDRWwM4NcTl4iHWsDrCCrQuq1NyawIYdOiQS4cNWvmfhhsfNdAoWQ+uVAfBHvtQfnoxgexHb4WgdT4gNmjF1sFm9C3OHjVnfiHbVj2w9jdip5wbrCNXR3ZlWiw/dQHDewWUWD6CpnnNIaW2FC4+Nwzs9p0mDa2DoBojAu6NS2nsGHvY83QY6RYvx4ycGaDrPResZhvAskVj2HO/E7tUVeCxX/1c9X4J+Sb4Y0mCHZdvaqD63jgctV8E1oiMB99VeiQY9Q1Nr5vjvUhJ/LkpkrZNucOXbU8hKz3j7/u14J+CLZwY1MCTe43ItiGYTUebk8ai02D58Bxfam8mF5te+rlSDMqWPUSRaUlUft4aZ7ur0D2l+djtN9QFLn9FuZC7LLdKhyuUdEEws4yCk67D8o/tQ9k2H8NjpsE7q5N0OXEKhP7wBjmvGKrZOZQz4iP5/bPPKNCZCDv3v8M1/07ypJ58VL3xD+QF3MFNoZSEAiTAYXEAd7Q54SR/cQwRWYh7F9ugx7tf6BotR2bXL/EpZTOSuTkeHud8goUqsyg1QAHNRYqpbvhIqtyqiOcCR+ED3x7+8ESf73USbHg4DAatbkBszmvylrQi98eJ9Dt0DVv/fgLKNnfQclo47ZlvBjHS9ynZspiqCz/y748GIP9UhLzv7sHRfraA205ii4c8p59QAfPMehj9/gXvCH6JpqPPsZD9BGx2HkYfrzjSBOG1IG28C1p32oKh7GK0uriLw5NS+a5EEAp2FHPah6VoLDfIX4w+cV1XM1yYowph4wtQ4UY2f08QZy91ZW68ZYMHr3bRm3vleF+8FdX3TIdbx2Xg0oxayBmXh9LWXagytgp2Jk1l/boKjuj/BpO9psDZguew210XptxYBTOc5aFPwoOMpl0AzZXXoFTyP2x5thYfvCKwuCWJUn/kIOyZOF6u94abn7Qwxicep3+wp+jfW0BIXIUfHPXBFnE/MLVTg5ePTGDQfzxqi42mLzGWeELnKzzs0OaGhX0828yTRzVs5vlDPWzvckWa5ygIr9fr4MYFwSwz6T9YVzkc5kXqU4HbAnyStoTS3CTB9HwI/PpQggsff0Hr3/U0xzeAwkevwFFffCG4Yyps39QOtcfUoTB3Nl5434mdO9/yxnUJtFBOC47tD2PTDGk67J1L2y1UyXOI38bGmpCvUBb01oRiRtA5FP6Sy6fdl3Ng4DeuXNXBnZ9zKK3DDEbuWo3wfCtq1e+mRX+2Y96LShK/twwvOQO7idyC3eO8YKmjIbQtV4fYhXfYwvQePzDop+cje1DXcTcqrvJF402bQcy7lm3sh0PHJ1XmHRb8MP8wdo5X5cXxx7FOtBqCdBZQXLwiCT7wwE6b0aD5oZZiZZ5y9qf9rHS6iU4XnaWDU3aQDsnz7b9bKNM+fYjlTOHSUMdad0WMU3bvQZ3J7jB8WzUvVV1Df8bNwsBDslgy0xvOusrCreLXMD75LvMSdXZxysLGrRn4vcwdn86Iwrci/fRorQcfXjQMTLIy4FmOA93c1UUJmz2pT8CT5pnsZNexATja7TxM+mxLuvlGcMVlLGe0S+IY/bdYPv8U3fj6nj/PsIVH5yzZ59Zc6PmSD39uDgffInE6M/knSuoUwVKDCzhBJ4tD9JbxugsaOEkoHpzGLaSIV8qgt/gErPhSiHkrKsjTOARWLJ3KP7SmQrLOLoq1SMBG4U5QU5EE48w7PMejja5Gr4HZrUo89Uo73JDYxX4uXdhuth2Or/OHL2/E4KzQCW5XsKMzB38xzHNip4OX+YztCP4u/xm/uv7jTymE+ooWsFrmDE7+NI3qCv14WmMmhefOgekNH2ni9Cvc9fYI6VUdx3BBAfBemIQNs5zBM2YH/6mbTXffzKTjUxZwztvrPLLvAlfY7YSti2xh376psEBChu7s8iHLIAMQnDCCt2oWE5tXQUZCHobO2ApCltYQvP4DfZmfQPnan+D2H1H6lmhB3p8jYbdeEvZOF4XalgK2fzAaCrYeRLPNzaTc9hLG/pUmeT1P2F/hSzEK5WxWWw8fo63RdJkGPF4vQjVe/Wgl642NG97g1/2b0Om0Fp0YsRMWkDWPD/1JilLisDOyiyMSe8lpzUfONtmHyvX3ofHoYSy76UkqM4J4hU4mSd4xhY2F6hym2olHG1SYk8Zi0OlbtO2dNZgEzMIXhy8OdXhRVgxXgPT2LDLp/gbWTVE4z+46bWv6yPb9w+mvkRh+7oolvYkLsdffCMLty8ktYykayo3DQ2uDKbR/LRlfuUVVCg2U2ehFtoVSLBWmCiU5RfAWm7CufTRZXLDmm8N/8EKzkxyUMZWFlp7iJWO/c34igfgC4uu/ZsGO0O8we3c9rlhtDcmWEZQ9pMcqB2XUDwqhGGmCVd8OUGLUbnBfYcWLFztC/ZGT9DZSjFoyPOnhtjaU+G2Az1KGw33fZr58/QkeXgYYuOE0Oqu40I0OGf4ncxJeJpni6xOW+MBHD+S61cl9y2GKCrjNRoHmOF9i1pCGU/ly5RUMNlZivYxnXK44DApib2CYsRIWPxaE2slHKX3VQSgX3Uxm2RMwdtxROjNDD6xmKcA10Tjwi7qM60VqMO5yPV1zn8DVR3SofoY+l0z25lX2zty+UgDcXV9S8vxTrPjDhWq658EMs0HaEvUTQ7CRrgYMeb2AJrZn6kDO7p289r9e/PpzIXrUm2DCi91cOX4b5s3YA1U2C/DH8lV0eaUN5AWdgbPDDsEatSzy66knFc0LtCbCkAKPHmDTPxkw/+lIkrhhCFNFP9LF7img5ZPPY2y0+FCzPEw/1YpzEzbQ66lOOGGWC7jKSIGkrDvLXa7GS7wX3s/OpXbx0TD/3kZ+PPCQTZea4Byl5/y+UREUJFfBB007cHt6mE0rGzD7iBr23hhG7ZmikMvReGHEBbo1RgJCt9XwH8WHePD7e4h7fBmPZQPaTg3jfpdGsp/iS+JDGXHAWATq3qbTGKxGuUXRoLZaGc+5ptCGAUtwj/cEhwstZNLkB9PvysHqPXpg2bUFP440AfV7s0h5ZQXr9FyFTP0gXuM8Abd5ifLlP9pAUSu5UEkUzG21sG2GIFv7TgWfOCU4q25Dg7POcKObCN4LMIXNhq/paL8/ZNefo99H1tCX8HAYFriYq51GgJvVCDaxE4BjylaQmCYCz370oNjyFmxpS4PqM9/BW2cSPxrs4HexgZh7ZiuK+Q+DaINoGh+WiPYazlxSfpuS1ixHv/ILFNbrRXe7dbhhsA3VZo+ESOU3uKR3J/Dg0I4n7KAe7QG4cCscWvOaqCROA8u1A0hLxwIm/XPAxT4l1JMwH/28/oJolTHWHPInja2pWNh8CoOswlF0mMXQXOt5zsmtrBsSBXNU17BL92de1OdDT17Xgs7O87BTvIHL7W2hqK+L31tthS77Nzgxt5he79VkswstsCVPjr9IdePz8Y+hvF0P/kYto9YQN+rQ7cHDXt4w+VApB8w5B1UvhHH7dB9OytHBka7j4a9PKEj8S8fYQSE2FL3Mu7PPguiwZ7xEShJCTRr5/fCZ9OqGPvyZ28OzNsiQRm4AhLzsoqeONSgvMp0jJMajW7IeugZcx9ZqLZi4L40rP2rRi7yfHKlvixMGReD71ZvQ6a9J4gbZ1OnUzB8eKILUw1ZcVjSFPgmOpQQBb16stwtF/BYCrVajXI8/MGfYX8p2GgcWhZNpgnozujufQ5myLXTEfDTpR/lSnYIK33KdCjaWs3mJtxHA6OE0rmUqJezZy+GyctCj0sa48iWOi9qH7ZBF1lPLqUHGCGJDajj3whI+4hxOrZn9qLrwDSx58oljjKbD9bp59M5yEeZ2jgNLxwEYdeUOX70jjVrpbmSwpZP0gq7A7Ix8zru9G+p1trBLkQHYpO6hjPIW8BylxnNOnCeN8Aje/MCXtW0rOezmVKpOOckb84Wh7swmeH5oH2cvM0WnKG2a0e2KC1esJluLIryY9AMa++ZAsIQofPiUBtePWtDd/MVQ+2UdTcwayfNX7YHAvap06P0F/u/xUxA6KAPD9h7gYr0e8Ou8BDr2/fjfXFuU99gAUie24w6PjfRaoR7jGhn6Zq/DXee8yUHan+WFkrFFdxQ4b//Li4dLwc3YOLa+4AOiZ8dC8p8xLLJxBA63egM79lxg0QNKOF1bEbf+cUOPAwPQnPuBdB1Hwt6dwXzJsxXqIi+wcJsjSdeoQPiGet5R08l2+tG8Ie8lP3USgz/Rf1FXdQPGGiSTVEEBr5E+TRkjZvLt1ALSnBcI837V4OPjUjD+ph/K973h1JQEOHRVAHwlI2jxgYcUjHvwxpz7fPPON/4tawvC41zwxFVZHnkskp2fRfPEDEdcJiGDw98vwQYTBxrnbIQOkXLwc34v+q2oxeGeUniuyx2MPwhDzoAXtJdrY+TLZppx4QxtFbaDNSc18eK8Cfh22njOOk0gaFcCC9yesvnaXlhjLYmTVjpymAvBwr0R+KYqEQ26vkLtWimKy55BEvdPwx03K2r/Fgq/t/2AO3eUoWOiPodPioXauadovXUEfqkcpHPH19CwwiQace0Fz97aBf0ekvAn/jvrWEzi57utcbt0IX5YZ8jm0i/x2o41GD1GjqpMvOBLLYB++i4YSHanNF8juPBtIq08/ZjWHqqmi5IDfO9pHbf136KUClW49XYO2FZZU3WgEMrMN0Uhk+2sKxKNfwtWkG2kBj0vSiDLaRYQfkcPPKKfwEc+SxUHRuP25hyI+OVDZi7P2EW5iQWie/i5tBGEPJtONq17ye36fvBS1aBYl17MSg1DsaTHEK4QzhrvVrN/qDpoPzGhI6HVEHBEk0PeVuOh8wcg20QDixUUUFjuOiv83sO6/42FpRtPwfXZFjyjQphSEsdT57dIrvytiPZ/hsGv11Vcei6Hfxfow16/i5gV/4WUWxPRc6sVKyY18inDNBYJyoW/wp9IGRfjGT0BsOn5RALRxbDruRtrn7iCB8ea8XGZF2gc+QHerfpERc+vQ6W4IOgXPiCbaa7kvlKCht8OorbITFjsvgu1jglxgNIh2volDBdusITmjz304oA7bDs+kwTNZqHkhOnYnzmP2rZUYv6F65B7tQq9hKWh7K0J3nPeAXYeW6mpZTptXZnHI9Q+YMLuEbBizy3M/JtGiVP0IeO2Nl0qXkt/jpWg1G0fdD8nj6fEZHhRhTE1aAlDm/MgjzyhCWsT42Dkx89Y+3svvVmtyS3BqzBtnDpm6UiwjdjyoR5khPEKVnCjSgS7L+ayn4MIf9O7R3MgA35JzsXM10m8cfsCkG96irJP1MDedT4JG1mD/ZGxtNnsIAyfswM+t1hy2bUubNpWytv1Y2C37SgIvXKbCjYo4t4ZkazklUzHKyZzReV+jHGYRgpznCHoeCq1XDMf4obH8KDgHdYoSmL75E1cO88YMtvuoM/Jq+i20JUDDYvhQuR4kCi1pb3GlnT/2B00m3we9rrlsuWyLm5MuI4+9p852eY2BAwzgNLaY/hu7iU2HaOKu04JsGm7GufsjOW/pilovjUKvSv3QPF6U/gwNZCeqxxk7ZFavNvzEglbufDHx4W80UIfpnf9ocQJs8nrqBbM2DvAm/rc8auxIk6JWM0SObOxaFYYr+7IxpobInTOfSQ8G2sMLbmWnFH2hhs2/WIZYwXcVmDBQTYDHJVTiQOpS+HKdzWgR6aA+ntgleEdqrA4Ct5a8+mI7mKeajEDuLWBQnVjeOEQi6+PGAPv0nLwQH4VZsqGwL/P22n2uEr2NJhAsbU6qK61EMRcfvDgUhHIWJFACr0P6LZnF/jObYbefYr0yv0RLY65zo5Fm2i/0C+s+CsDxVnmaBddSi8C83GPaS8vSOzg5pJcis9/is5roulwihQvXTMS8iJSMdS9Fq+22mHt4jzS/5tP9d820sHzTWxfNRv0P75EHWMzuG6tTy2ucby5bzWMsSyA0NiHeDsuAXz+GfIiqSKwVX3Dg7dtQS7NESR+9pFA8mHM9gXWPLAAuskb/8Qdp7fCOng54CocW20Dada19PL0e6zYKwu6Z6spp/Yne+iJc7FGHvpo3SNpzT+0NkMZQjQ0Mei7OXha7qIJia1cyd30abESXhz9DqJzG2mq8guMX6MIl2Jy8MmKX7D2nzcK3dUAv02rYeQZFRAK7mU1lSl8q3EhnJMyguVaEtg34TiqSR2hctU5/MyuApzNHlD6x35ySBeF9cd7ObnHFqYdjWW/d1vxu/FZOu4zBlTqrsKjelUUam7ixzME0Qlvwt1h4uCZfQaUh2bq+nMEiv7K0eDbWLi18BRLz8nhLSb/8Ov3p7CsVRiKtkaw5xBjv9bt5/1hY/BEsD2NmGNDGw1u/f8/yJg+Np8b7dRgw6APlwX5wZlVnRC1qBpWHLSDk1kvqe6rHmyXCed9GxzZ8LAGNKupgbPdAQqdEkT6vzfCh2lCFC11FJd220HDTGEIdwzHhSIMy89v4slO+1AhgDn2vQGZjpDBRQFZEPZwEmrkXqLdK/W5Q10V6hKq+Ud/HH373ErWZgU4JCRo+vKKls9NYaX32+mu2QeMHG4H2jtWcmuOG9tbvwfV0Xoom/ILWpcrUeETf/joroH5hlMhpEIR+vIV8OZ5R+q9+5cGb/tRpsBhevboGmSr3SCw3cO1lUM9K0YW1urmQPlZbz7x7w2pdb2lWX91oackHJsm7ib/x6VovnERHllhC3dbqzhVoYP6n7hxSkXiEINI8upWX6jp2EDRJqepuWYptvxRgxmljXhD8SOvjMomxwvL4WeuFmzc8BVbPGfi5PA1PO99HwQv04IYi+Og+88abS5up/E3kLZEeHLXCyHo2rkfU3x+sJjidw4K1ofOPaNIZ8g/Ij3mwQi/AVwYM8it0V6wZHUEt81cBz7V31ii1g4+2UlC2UhdvvokA094POTVhvr0oeUIXgrV41yHd7ymJIsq3YRBuEQL3knfA9+Zp6ltXzD/V/ac1K+9Y/MDx/Dh8sugtiwcvz7Vg+l9lqB0oB4e3Sogte+2NCn7HPo/uUP/1TnDhfW1uFs3DQyjNWCR8yiY6pZOLW+E6XNsCx02ukHu7nNB6foXdHbxw7MTp3GTgQ4Uf7/Egn/n0URnKWiUXEBCi3rpk0sgVB1cxg4bj1N1qxp+llSDdz+NWVuwCopurqS9kzvR56gLb0/NoXzFLORre2jCgVN4ZeowmLz2NXdlniVD2Qa8PzkNl46ayQqVqpBmnAIPmhdjG2uhT64OSIRkwqiiJvx024c2bCmnv/dWYMS6SEjXdyDPuHegmeeIAk+Gw+QV97lS/i5Lfn0FBUtUqHO6OLlH7eW+2n90pKiMa/+54SxbUZBsdKEwM0N4fOwr9sk7w1d5Qyw0O4qdL5ZRTWsljM5/RGpzZWGSxxey/qHLvYdMaZfPI7o2PYx/tTmQSfwgFF/MYp+eKBglNRE2KwZTaPhXnN9+CQfaf0ND6XiY5xdIVif28WL3FNxyRBDMz1vDjSeH4Vr9QZKT0oL0bedQpHcKvwp+SZPva9HL37r4XK+Xrw7XhP/0HpL5w2ymAV+uUS/hb26BOC79Lt6vbaOJT5NAwtYTjf4TB/N5gviuASkr/gEnK7tQUUQBhox2Ive8ZLimK0orNSvY/sMw6DA3oUm5S+jF5eP87eJWDhG7w3Hqbez/KA6lJ8wEfeNTQwwgBjMyehC3xWBWhjOUQD+NqtLnuwUenO4ZCS6xk3Gt/lG+liwN/uYx+NM/A3P3HkDzpHF8QOU7PelYOuTBwRBxyxaaxsuQ6nMbiNAJheTE3fQqcivfMvqPLodNojaLZ1ipbggxsva0478x3FOCIBNxnz+e1sP5nqM58nM71Og2QfWmfHIv/0Oy6n/BSdKR1W4aQ7x1MKgkfaUdb39R3k2GdSsNKKJmEbwNLWbnglb+fnE5yU2whPpSe7q+SA/bPijR/PFmqPVaFH5p6bONZCWO6z1G2hCJc9abQEHTdzqnF8lxB4k0Z5XR5PgSsLwjwubCGykn/DyaZF+FiNvyIJupC1v3rOOcgM/caPyGPUPzqGOfE9y9HQ4q90KgrugbV66ThF9vWiFNSY+qlqwCo5gb2JgazPnTPpDtmNOsvuA7JIZ9wlHlEyEk+gBPCfqLX83zOb+hB/St1uOHbdeooNcMu2reYqOfDFpsFoB7Y8ahRUESdkZ6oPMcTXw/VZyfciARF+MebTf0PaaG4oOCoGEzEqYfEaYHaUJgO0yXH6ZfQYdgF/aMDuLxnd9oi89xCEtTgaWWT6Hv41+Q2mIIdQ98yHjuI/7WLQZ9I3bDct0+GLVRgiu2TQDRB5E0SWgVyBxRwsgSbWyYWw/9Ih74uMYWrEIGoPTPfhTePwo0vq2ny+4v0CvAkpe8/MhpsgG064U+bZBWIbPoOdC/dh6EDOWooCbzqeXvYFV8Hju7iVHvWnceCEGoyDiLFOrDUclVNHsKwtc1Fezw8jyoPD3LsrGyYLE3jZKWMlp/XkwObyIhv7CbFl8xgNw4G8JypkexOqC67gU9G7YF6ieG0ZfaveT7yI3sgr0pd40E2JtOguuzvCFRyQAWv3kLqp2jIH14KbPUAPmGW1Nf0zuo9jUDdVkHWNu6E02+OHGNz336rnMXmwJewcyz9+iF3D3Ml95M9/7aQSW54cHgSmqN/si6hTPwwsApcokZRnFjBDhJZS1FbW/AoBnDQeGjCcSNu4fLXl4B6pfG1IRxoJB5hZxbS2B0khV8lC2jlR52cPumEeYW7YXYYXK0Kn4ym3bdg8ywVPyQug7wfiJKrT5FI9qUwc8rD7QeqlDpsR7y82kG2dhvtHLrKg79W0mPJh7n4sgkXj5TDn5HzqdPt/1xqVQADk7w4k2BVlQh9JOd/N5wYp4TlC74Q8sNBCFPaC7c7lWBL/c+kHfSArB/sgo/rR3yrBdi0Cy2GH/XypOFsx2U5fzgr0bzcNySi9hRpgvjbj4k5avzafK9JAo7fZ01alvZ77gMFAnU4L0COVo/OBva972nlIcN6OE0BzXVCfab/8ZDzYL0E+Rhcsx7aLpYyIseBPAnkTgSXNJJHQJ3cbieB4cucQM3+SSYvVAGmg3TqXB1KN1JG+Tk1BOwbM0P8Lg8DOYKvYKTDo5Q5fuXhSdrw1dHAZTVv8Ipwp6UJSDHg0F96LFoGN+t2MGp4+ehf24qztcSgmkKzrStYJDOhKyEfJlS+O/bAjoFJdySdJMaBpbiDjc1aGhmOLr0CPVppuGdY6XY4fyUKk3f4fRSJSqaXkWR16p5ULsTqUsAamdM59fPH3J0uT3ueDUBTkgsxF+L54LowuOkfMGVD2VFIhgoQ6htF3ylH3DTzAkNFCs5vasb7oruwJaylxx8w4+bc7X5524A0dNL2HveHpbWFOEEpyyepatHmu/iKW7NeriUX4DrVLKgYJ4tjPQsI+XIAfziH4rbV3zmLMxnzUfHWXNxGPw0LobWN1385g2Bo8JG+GS4nNfdTUOrkYvhkIYtevj50o/lwmxgEcY7M2ow4IQBjI8SJ8umZJhyninVWJtV/ymRbM8aUF2+HQeEa2m06jl+O04bIqY1Yd1radjl+h5LTI+wbPtTeKJ/HIUWb6CHT85QXdZJGpQWhffGnmh8NQW0Nt7l+2pl+NsliFIsn7OWYhM8vrUCK4/vwMVZupC/ootA6DbMy3fCZf7DqKMtEp0brfDa0gDuHXWLE6rVuGuGNtwKXE23Rt7lLOVYqL0Wjf4e/nCqcDV3XTjAI33f0qT6TaR5RRCe3G2Dg+8KKe1zKFeHJkH27cvwb78+N4klAjncoJ7iNLKYZATu+6dwS6QjJwVJAXo+xwRrJ0o02c+HZG/STqNkFhw5F+3uT4TiOHt4fuQNP4tP+j/iy7shxL8L42ckDS0qSUMy2jtS0jALKRWKhFQion5kz0JGmSkqDZIiDS1NhJayIklGNESSMkr19C6e+wV8/7jPOdf1+VDWnn80WyCQk9a48MnWB7hR4ypdNe/Do7+M4KKPBZ68/wenxeynL7/OYNKOcpZ+bgd/d/jBXwV3OL18gJdFDfVU1GqSMzUHS/9+aqlrA8vkKfhw1BF6PsscP8WKg+pELbTcLQcz7b7z3d4ivjLzAJ/z6yax7gCCEwv4/hMl/Kkfw6dm99Hus8Ng0tJZtKHpFmrfE4BdjwfQaP0SaNVdQcOL98PVMjdoXBiGU45MgKLeXdhWNoE9RL0wpOY/XHhFDMxcAUWP+ZP/+FXcdDAMgtzMYMmnO7jWbwfILlOjByunY9/uH1Dv9oFWB7tQTkMozLYygZyFcjAQg2ArkIILDmrig61nQOfTcfys9ZU71q+CuSVOcEtHF3auGAOG/87xlCM9ND/GAuSqTOjJ3WUUdN+S1r8ei5mdc7jadR89uK0O+onu1G7TAzs/auDmiGU8b/AFrlvWSducF9LtgzVctDQS+Nkw2DCjGWJ8C7lNYyl/27GH3Ff1c3vfb97SWQOde4EEPXRpiqYsLM3fBUaJgiRWMBMWVyQN8cZKWiIagxmn13LpyQA23RiOp2vE4LePP3t13UWvnwrgKhMAQdGbaalKBx1/UIAFnU148fgAc7AqrHadTOGtn8DkSxgFFe7hOf/s0EUont7vbYfhqz/yrPNfQeS0NlgcGMetfn954qVYPGO/BFLH3qT7ptXUdKGXksLvwZKbWWSRZQ5T3y6E60KeXK+ykJ7oqMHRbgOsKnpDTTKjQXTqZ96jugz/5hvBe8038Cy3iCP/vaGFMoV0M8MLv16tRKPv+Wy17QI8SA0jrb864OESAjoLDTHo2yu4NfiMl19YhovqY6i3Uo9aT4Xh1QuZpFplBvt+LQZDQ11ocTDlfTl5ZP87Hr89u8ySFdPIQC2SU8pOw4wyOdhtLM9urZ/QNndox/NGkqTLe+xal4z55u3Q7vmKeht/wnhZgCBJRXjiogrSIgaccX4JRSXocJKEPq5ZPBwPXbtFbkkncOlZDVh1MRWTHrdyQ70bq3bJkLx/HO/93cqXg1aAfFIr5Z9x44WzLEB1mw9fPPCAP2gO9e4YeY46/xdtjntwmm4lnr1TTRL7EuD17Glwd856+vtEiA+rd3CGgC07KjfBuSLCys4HeGzXIxT+qsh4UAgEo6IoS/MVxb41AYfKyzxzrAjGl6dS03YnKg8+hamNtyhwtjCkvfLlt/aIpeMN+ejWZfAxXxuXjjhHK7YE88ej11nE4xDEtirCAZbDz3tUIHHaaShtvsjWYa+4O34b1y4to3e3mErHXSWzc+awoHUoC2vXcrjXc/5wugpWzB5Lk1Yuxs7+z+j3ZDv2u5xjJxVjKC++zss8+yAQF/D2B4Z8rzqD5BaNRImg7+CTsARcFrlDoJ4kiJhIo3znPkzKygCxLgscM6UKvwvnguOs19CzYTfJ19ShyGd5yI7X4/uvkXvTNXD57Atokj6CGjKPYt3VlxSmtx+TbvtwhbQs/BYwxLWFF2DjpEuQP7ELPj4oJ9efozAyaDSUhh2G5N9RIPifBowwPsFfpFaw+hRpqLndBO3fouBsgyVvDnkLBvJt8HHQmZ97TgSjeRLgeSEdbtjXkMSIh5xhdYJnfTNDI0V5sGpGrhZZDYGbFODnw3nY3u8KCi3a/Lovl6LOb+ANPSaw49xWZCcx3KO4no8XK4LRYxu+vzuNDNzlINTHEAP8PahQtJo3Bfpi6GAnln1W4Jk7hEC+ZgvvvJYJmSc+gvZpRSxu2Mfs/ZN/+KaxSfoXrrf24A2PTGBpyDzu548omjMIt2UHye9IPw9TfY0bcw7irEhpWCw4HOdJakKtzGautLDmRUIFsEIqC39NkCSjLE0qPOxPCp9r6PiVO/hkzkjIblTD0Urx+MIsgf7u7WBLo824LWg2PbNJp73Bx8H60weWix0DkjO+4/NhGnDn8zJeIapJUfLGIDLuO2kcPIxz9T6xVPtNHLCRhC7hZEibqgoHon+w2eEZILVjE+8oekWPjC+gpKIlS31x54ZkQ2h3R/ZxPUDqH1todLo2unTfoptK0+Gy/kNypGI2HnCg/kOy0PhhAwUvmwRvn35n7xsppJ84EoSdunhj8QLq3+yJ9sNKedGqUdA9lAcaj3Jgwvxuzt0QivqXP+PB6Qbk4dRIj5OGcbOFBxRb60OryGuc7VfP3zv+soyaPXs31dHAdntc5ezAwbKx/N/SFGrJHQfHT1SB0NYQcKowp/k/uzA+MgjNTo3BNUO9oSxCdPXMI7KfogmjVf+i73/nUaf3AmiFOJD38SiWNnTmyqsJkB+6g2b+rCHHMRbQaudHCcds4MJ3Y1iTYc0+0xAtfl7iR0kRvMZzAX318qB9eVNAveovKkyqhPeDY8ivPAjq774D+Uwl8txoyjMF55F59gmSFVIAs01f4E+BIRWseMNbjNbT6rDNpK1jBlZ5b6FSpAby6tM4/+twMBhnTTvutkDIwz80roMweOk7PPguBRzX7MH/WoKhe8U53kWGsPrYIH1rD0d1yzskmieLxq7ruKMiFPsfWNCaUF2e5pKLUes1wMtElqyW9vHS4T1Y8aaEU517UXPmSf5UNJH7FWLBuk4LCkumgPyJShLpc4OxVlUYYmYL14OOkvVIW8y/vwF1hebR3dzF1PRFAhYvX8m5JaF8IjyIVqx9C4IKb7lnoTEGlN+g/YqueAuEqQL04eTPRXRu1n3akr2LPz0/Rh1YBxFG3mDop0tukwGLz2fzXHU5ePVKnPv2/sCC2vko/66bMgz7wETxC9brv6QT/kZU79tMw+eNg32u5fBc0506Rrwnr5VIH8+bwjijDHS4sI2OzNyIZ5y7IOU/ZZgkbgtnpq7ix9Vn4enNqxCXMUCZX7RgfdtOFlfcCTObSnjfDDEQffscPx6I4OMq72F3tiZpTH8E6c3XIOlwILuG+lB6uBcXyA8D795sTD40FxcqnoPDVWIotUCLDj/8jHPbvGD/mGouKrtGB0cD1L5TxcGpA/Bl2gEI6TRgvznpLGFohd9Ke0DrlQeqHZVk/VQxGFiTBXrnTKBxyml2WhMKleH6ZH5Om3bMbeTiiA8095Q/h82eARtmvWCB4r9wdN5vtB3RjTlFm3CB+x6yXXsdDUUsedmbBdy3fRwkH30CteYqvFJPFWvHCLFq3XtY6+sEMdc+UOX7jfhKeQvi8RnwYUY5rdZ2g/bNHSg1/hf1JbVT6Js47vX8ildvvSSXxj1YIjQMSp9Jk+CWVujV3EZhTYb0cpQvJHYNcKuSLMwJVydZr2z8kTkSxo16BUm/r8IRgwHS15kDj0MqocepCorU92Ha3s1wR9eASqNMIFh1C/vNqkCPJjv8MnaICb6qsMdZE961URbjBOdhU0AFHt+vCZ52ongIVpBizxIIvf6a/3OeiJG/fbBK6xjczT5CNwbegPMxNTD4tBXdNvvRYKskvDgeSf4O6bRsRBDE26nw5lNKULH0DnfeGwsJH77Q5r8O4CZfzFZuqfTwvDkv/hoHL08XQMzICAj+L527WgwgdukU7DSSgAcHcuFb5jBqGLkHzu+zx8zpOfTsjgs/1iEMOE3g8zwbRx3/BQcMJ/EXEWvYP/UmtO83pTGH79O7xe3ocGkSPTOXAe8BP1Dbsp5nTFsEeNyQ22bFsf7caSCnfQZ731TBw/tifN5zEhyI0SbxV39wICATcgsjwTH2J66PGINKJS3QfTWabJoCmW1kYecLDZ7xSgwDj4WyzPgLWPq4hH1SL8J/my7z4c2m3KL1mgtvacLYh05olfuMX4QrkOZFX/ir1UX302RwpVIO10YrsYF/N7iNR4hsX4oGtRP4q4o8PttQxa/KY3nCuXuQo5zAutrl1JsgztUK40HHkOnrlhi4o9ZF33doopqVJy1/f5YU3Z5jddBLuv3KACSGK0BOzng4KWjBVnGf6bwx4Bzp73Aeb0OzuwgmfNpM61/k4rGPw0DxUxokl5STnnsqjV6pBr+KUijfYBnNfT0BHYXWYW/XDTDr1IOXctYUFLGN2+/cQt9MeXCqkieXTxPRzHQt77l+HN0btcipWQx2t7SSzPlWjtqUwDZf4kFY6AkfGnkNmotTeSAqgu4+sWOReE3IV7yIWT+0eefBPfhr+k5O/1lG8YUzOPhoHmrpHEHvnq1Q8FYYtpjU0qeoQF5yfRb1D2jjk8wySMv/CcmTdsL9SDeQj27lerFpoJhXg28MRch1iDuO3nyJc48/oR45N96V68kTbLopZX8uWvyWBYUZK0jkoCXq8Qzaez8Deq47wUrjWOzKHUVfe09SC/jChq2GMCkjjl9XB7GM8XpcO6IY9xavpuKyTpYJiae5ctZcluiNQQkIu7ecxjJxQ8j47xuMXNfNPx5ocmXWNmwcMCTZ9ba4YSCVcqbowg67Q1g1GE9JkR40OMWPFPsUwSbRFyP6i+HliFzsaPcg8wWqkNcVAOtSy+Cfayea7H/HY5yW0pX+OE4ViKWWqzs449pirCtVgfIP+/ltbgaVzVeBk7UfMFNzFsuvdOeJxfqIWZegv2UyZS5WBa9Lu/mTmwJM8dOFc209XDtODrIvJVJJ8yba7XoBou2+8AZ3Q3hw6x84XNwO1wTHksv1uyS1/jZ98dsH20394Px/p2mKtixfu6sLMhveULT+Iponw3yqSwGTwodB08hVPG3HMuiePgs0pWVp2t4RcMqtlt8pMyjqXyHlLz9obbkkyk1+jtODXtC1Vj/MFT0Fnr0jwKH6AS0DA7AcytWm292w6WwxrZb0oBtZVhQiVs+11kPZa6gBxyoTeHuwB9WtOAL/fgMXXxnB5f8iUSTWkCe7/YHqi3Ogs00HdPZ4UPhgNbfLWHCcxwaaczeH3s+7Qj4RKfB93xi+PTkW/EZOg++b+vnMyEs0al4rLGy4guqTPtOq+fdhSUMA372XiDWlzZhwbAwMs1NFy28bueOoBj9OVqQlI3TJXEIUc9z8afzENGi8UI4haxVBaVQuXhichYtbQ8FkfDY0PxjyZSkHNlJNxnuhsZwrbM1V04dDg8hJfi0/yLsCyvndfRWqGzuA/XNyILgwCkXaaqk9/AQ/t2P4bWMAvVKaIJf8CL+Ej6K+9hZ8mjGbDe4hS+QYo9/Q3E09VeHgw2JadMkAC7ZZ4eGL4TTrShH1dA7jFANlXCvRQMF5SuTqawoBMS4UWC4AZjYX0GFZG5zsHwM//2WQ9JTLOCxrD8wyNcPbPpJDTNXGpTF6kPF+HCaJH0aX99oYrVzCk49Eg0fmZDybYk/3zouBgfgLjNPcT4ef1FPg0QzaeV8UfwfokNF6R6xdI8SPPpXT2VlSEGQ4yBVxJmi8SBcmdVaQMwaT2bdZdHp7Nuj7VbPU+xO8RXcqzMyM541B0fjdSgYM6svB5lcwGqcvoAn1liRUJMcbJ+5BISld+IcV5LNYhrwmHeCZ7pOwo3+IJXstoUOghAyneLJ44SAcBGO4bDkVgmMnkmBPOpucHk0aA3e4JNeWp8UqsqrEBcp3+QwUoQOJXrth/7HjqNxynU/1feYbbkfRVN8BU1YCD8hVwmW7PxxTLABRz4b6QHoZf/SRxaOVo3mD1G8qyTiJahUj+ejFV+x1P54+mSvCFQ8ZaNc/S4s9TvDcxHSu7bwCX5f/Jt0AAzIztcXIRB3c0y8PxcYXOLs1hMJLByD+ynK6v+0hFD0+zWnGArD8xy80uGOLS8gM9HKKeOk7HTp7ygNnlltATGQiHFssCZ6RqvADIlFJ4RCc+qQPLl3P8Zbabradsw0OrfzOh/tuglFLM79Y+gZff7OgM8paeOaUGageLcbo4fkcukqAbjZ3onChPB6vLEVlDxvwHJeH5w9vANFJKpAZ4IZOpfe555IedV3JwOA5YTzb6QwLORSxyfhcspyqTRcFZeDMOF+Wbr+B/wLdyejcFApZ50nDW1QgNqIAFk/2oS8Dk+DT2KH+6JpETrsbyLJxCp8NPkS334lw+e5DtMMJWOajD74YrOJHNXJgfDCKH0abcNEqY1LbFQNOGqb8ZV4Pp95fjMtbdoG6vQad/6sLf+tiQCcjkMPSARzrvzD2/cNZE90oy+sDtp8bhMTUNBybLggnrm3i4KmKJC/zAA3CSyB222eMtNsGtpMD4OH+1SCuM4d7J4tCgWAMnP0Tw+kf9Fgwf6iPPinS44wXcPxYPXqY6UH2BG2S/ioLf74+pvmLtoPomfe049w0UigJ4dObH5HA3nquWprJ+hZFdCVUAZJtR9C9MSvJT7gM88ytQO9lPlgphuCuZe94d+cRMN0dwdlBRiD+ZDotfzIZjV5upNXL+7nm2z8gt++sVPIXNyzbidUqrlRqaQrJf1T4RWcprVv8jD1HJ8F8LXc0WncQREN80fzJInB6ZU3b9I2hfdkTWO8dCVLH/vHR/goobX8PrfoZ/PPiSg4PioDLoS0AC4yhQ+srCocsQb0/nRw58Qyf7oqB/qt9qBo6Be0ep4NzjD2Amj6ckdrE6ZoR5FXwhXYqK2KJdxCvdu5G9elX8fO7u+R24yG9sBSG/y5Z4cjGL2R2+SJNX7QcNG/E4zPzv7StIRsefqwEJxVVGuM8AkYnN2Gt+QCDxUvsdg2ElDA/ejfyMqzba0PmMaO5760lRTVYwJvtnvTwTjrP3nOXp7YGQl7Yen6fuhQf/7wLj9NFsKpYHGzuTAVxVXu6kjkJavLfIRaZwtEQQUjct4urb//Bav1ZbN+ogPO8dOBV330ePysA1MkPjIM6+dreq/g0WwHd3fbDneGFVLNiGhy7rgRnjuZBlrMCr6i/DGluoeS/cgcMdOrDfXsRPFO6AlJHjAGNlqnwsaoS/F/m4FoT5lfK83Cl8RmKT/wBbbecqfTVB0rf0Aw+GwxAb/kFPnqjEKVD53OQPPCP78eoLe8vKF3VoEMjR1JPzyAartKEZ95CdLjlBZe8OQXr9uvBqN3jSCcvlYWnHILU+kJ4fW4ChekIwrPMfzBv8B16/XWg6/tW4Me0Gj44uRmMQ25S66r9/GZUDw2uEACpuiYIld6PTrs+YoFROF9KWgoB3ePg7/zNkDFiIuQtegFFsaLg7rKZj2Y30WdpXZ7v/oRlyqTB5OUf3C9/lFZaB0DQwrFgAdNgVtoSbt+Qjw1rz+Nhk6s89+5vzJd0hHC4CEmPvXhv/VHqWDEcHlaE87W4PnbnLihV0oVqizBaOmI7fb2uh5tVV2Ht1o04a7UBmPVtQ8cCa3rcGMez8kfDGP8JfFt6JupsXcGL7shS3cRvdO68CpgXB1JDaCeaHQ7lN99e45bYp+Tz7DpvCa5icXpDR3uMcf2w8XBZ5AQ9jb4MY/dMwvFmWZy62QpuWX1Fx92M19cpkEiWKlTdmggV7xfR6Hn+/NahksaFDyeNLlta+/ILpAxOJZWzCbR7tQQOD9YB3SJLLtqYQW4xp1CsL5hOWkvDuxvfcMKstXxV6AKkLxTnlcVT4YGyJx9/Z0tvDDTxl/QU6I2TRQUqg7GrV8PPH+VsWpfNkUPzUG9bQ/MPF9BPyT/4/ZEzP/x9iDa/DKUU1Tcw/LUA8iIf6tw4EdZqlfKoBh1qasOhNw6z7dYJ5Jdlz86dmWDZfxZyixrQPk0ZeqwT+e/n59Aw1Kv+blOxYecwiF34GmbukaXiO9cwet4VKJCUgcVxKnQq6DVXX9+J8w4IgYXcba4KjMYjemd50fNYSgiZBX/ezoAQPs7NfeXk+3Afu5S0scnls9huqY/bbv3D5DYfiIxfjt57dOAjipF4Syb1/U1DD8dCqPhWz3ohTOrvt1Ldr6NYt2Ak3Rk3ATLuT8EzGnWkJZaIgt35tNi1mnXN5oCxvi052l3iCVI3aKqjFmjKZMEVWk6iTxtJANeA8k1Vzu5QojitP2Bnp0AO+r5QHyQI5jLvaFjICHhkeIdSlm+FxQUjYJfDMY4f7UDTJwfzJ20vysyeDj9a3+OkurX4BGXAvuwMxaZHQcN4BZbxEOUaFTt0LI9CvVMWIHphBL26sJ6kEm6Qokc+3+pUYL2e43Sypp0MDwqwVJ4i/lkgBV9rItjZ4zU/PjIKV67yhGdLFKig6wfdmC9Me1Rf07/P3zA/XQD0NyiS3fVw3Ll8An3fFAQjnudiw9kO/Ha8FA5vY1wt5YyjfEShVuYPPmnqh4PznkFn/VQ65/kbHzgowKU0Ecz0iAH9VydYaIECrNgYQ5fObKZozxpYftaO/K9KEKruY4/vu/j0M2ApszdcE2cMUjvisfvfB/60eSlcC3+CC/UDsevAJMhaPwfLLj+DxgAVWPlzOlh0dfNfR20K/hbDXnLn6ZODMb2J9ObJ9fok8KeMTh/8Sqs+K8D4wlWgpD+JN6T+wbY8W1IVnIl3wjr56aUdNFL1D346/hOOCRqDU9B2mvYgku4+EOVrGYrsd6eRjwgbc5JkDq8xEKXSbwXwfa0M1N5wp8NZSqg8bSLauI5lT5cCtgzJg4QPD2GCjyS3BfzlM69HQt3s/Xwz0YFdw+7yS7vF+OG6EM2Y7oXTtvpg+4I4tFSzhEu3jcDmTDameVrQRu3j4KkpBNsStmHVtmIe4XyS3llLwaM+O/gjJAQ74urg28fPaC+5jn9EGECKdTzU+n6DURMT8eWtKzRXdSmb60pC0vYaGH6cqcDoJk7T3k+2Ziok93IFv1taCWh4jrZLX8WUy/pw88Iq1FJKhEOfQ9hl4X5QXJAI3zR/4iF/BXw65BLpTpNAtlUaKkwFIb9jkLWb91PtOmMwrn/FiV2zSCbwLVjNV6Z/WSthzIuxkNJqxgZJcTDiy376uSyE60/KQspUfdaMPQMXjf9QzOhMfPx4BnwcaKKSBH8++XAAElZF4MbD/2D5oAxpf9Sm7i43VNmWQJRA4OA/Hi+m3WdP55/wxFgMexKjYd3AJwycX0b/DTmr6L2h/VObBiBnDl6pP6hnrBW4ak3hjEotCNNBckwiyvDqRmtbW2jaog7vnu0YwuMEfr/mF1q8kWGf4aswfUICg4MV/+eqCGPSv5L9Jjk4d2cuT4ysw1V7Kvm2sD9pd9xh5f3JrDV8HP/4MR6Oz8uje2PHQ/z2Uj74awCyNj2iX9NOo8r9UbQhNxwPxPrCwQVJdKn3BY+PnQqHIq7TXM+zkKQlicf4EDauDuVVB21gbmU732z6DJcPLOUSs2GQrTCb1XVP0ljjXzir2ZqHj6vCp3rraL7yAjgVGkJ58c8gSGMK6NU+4xf31uORmBiaKpTDG3ebU07UI3g204dyHtwGw01XeH4JwPukJyDVpQazvZV4t5YOP5lwC2yXHqKn53pYd4Eh2W3Wggc1DBLt9vw2Zzv427XCqrxDqLI1FrJOv6AGgQFYezWTsjpSaZf6VDgf94OMTqmB909dfjhNFjTVk1kqbjd/eVSEJ66Xwbd7l/nHv7FguXob900/gZp4HG9MMuExKp0oc3cGHOx+gpoLfCl4jTouj5SCcYcKuCn7Ad7Z5I/HtX/isHh7elAUSg/rTsOv24tJNvowzwyUhYIte3GlqT1MDOiGkvouXGAmBdYJwuibtYdybHezdO14sE6bAe8gAGOi9tH1b5q4VLAQjDt78WDC6KFMqYe705U4SuYtLX8kD6MrJsFUs32cc7MKBs12YVmwAo5a4Y4S1wNpz+UmOmvjzMIn5OHwqQTY/8wS1p3Uga4rohC2+iPk5jvCA3NRaJ0aQmHrDdGvbQr8O3AIqPwStY/oZGdVW/YVSKRVH+Jg2cx6+D13KrWpeyOXj4RLdo7sZR6Fp7OX8SZNM7wf/Ygl3QdgdKUPbilz5fC1NjwqfgTcCGOa8l2DPz+PhbM0mjILg/C/fFke8fc1hhtdoZMthtS/QQpqRsmAmrM6G11Np5MHcyB6/CV6KOoF9cOaec5aK7rFZSh2djKILdHnk6uSOe/6DqqQuUdjnFbSZW9N2n+mFDMD4sF8fTsUiZqA07w1vOtmN2wZfEtJjgZkVb0Z5gfJQJdSD0veC6CQ9gpojERwPNfMa/VHU+F/trQ47wD2tF8Gie9CdOWlF25c8IcH/3vGLQ5SMMm8CRfIOOOMf054aEsN7V1jSmeHN5D/ldv871QTGj3dwI4p0jBilBws97Mny399uHb8ROhQFaasnB6KOLceD6v9RyI0D38UTITa0jPYtjiaBMZl01PpLs4ST+BpPstRoe8Qp3xdA0rmW0k/Xh4WfM/G9uCj9N3rEUwu2gizXeq4LkUEK/6W88XCs7ws34QcRPRgp5IQ6Vum4+eb5mDy+zwvaSpBwdbfQ/srhlbaUrQ5djfP8NGHucnFmKKdSr8970KhdCvtuFmOL5q2gLRTDOdFFxG+fsx/PgGUiP6ife9XEo3cTfOqLMFSfBasMZoBdw7H0+EqL5L+qwRhEoJg/yoHfde8Yu3yhbTJ1Ir252Wi2Qs7Clh9Cj+vu4N/zJ5B7yRD6O6KoRi9WXSxcTiA3hJadbcNvLz7MLdCETsCd2L9RR942q8EQRbKlBTnR0kbW+HQY0UQ/+bMN3RTOVCyFfYmJsPqSer8KkkZMtVfcph+EZ95/oC0JpbRv2/MeSvm4596X/66aC8HpwhDbZsK1MvN5IU+/Sgns5QT7FzY1H86T1l+gJ+eWoKOx23oUelfCtScAjlp8uwbcY/vXiMctIugUxIXUDbNBNIqa6Fwvzjr7fzK369PgpBbTXgiqRU2u5lghbsR3ki9yo8enqOogCgQniLE9l5i3GU0FOONPjx94XpI/WePi3Jv8sGqJoDl1XhN5yU02GWA6Z5YdpxvAlU2v8H/+2N0bRiOPwd0YMePo2Ce+BSrrZ+AkORdEptiQcnBsrA2vBRTrpqRyLHlvHbNNlBS/kh79qbRsuVfIU4yAm0gFVtUCZ4IqoJ1ZyOWpMmAVtQYnPNQg8/LfWe/mlrI3RSIdQnmeKlzFIwefgWrp52D41fVabX42yFGi+A9jyvgWEMPNljo07NHOXx1jx4cKZnNzw/O5m3dn+nqPQecN7edc9o20NOsCM4YfpjN6vrZrlEZxCOy4FjdcnquvA1Gmi6E/27Z0cicqbhATxU/75hHszTU2OibIIQ1ePOiIn/8kS9FoRmBFGKeNPRfPlC5+VEaM+oL/Pu6GiYFi0HppmVkfF+OLEujyKlQmWI9bWnGin6e3DGFci7+YsXYj3DylTCMrpODR6VtcE7zPIq8mMslOY2YsM+a7MSL8eSph1AXHcjPI6aBwvuvdEdoDRZaClOZzGZMr94Cbtpf6JmdEa38uI5z5SJxtqAmKB7eSduNCuilpiw/dn/LXedLUTRfFGo2H2QvnV0ctr2EtgUqQvVCH5x37ReN6/tKVR+WYUWyPa2xf4QCIQ5U/L2IPyxs4AnemuDb6gc1Opv5nmUrnhU7yDlytiClup5Ga/qD2/vzLPdvG27yNwcDPVP+qFhBY/+tpJZTtTh+3E3aGjOX3F/+5J9j11CAzVO0GBwH8spGnB6+CstCjHm07VrqD3lIfY4b+XbGWr6t0QBH9umy5z8J+PvpKl51CMCCBiW20e2EWy6x2CMaxndatdlYroRuZ2rC+rcKMHeoJ3yi1LCsWgcOdOahmKsNz5JazbtWVtEN3048dW03KHUJwol9T1B7pwx8sHwLH6zf8o01m+D1yT+Yln2JG56W0+X5xbhy01iIH1eIf+yf8carATi95jFcFtrGRe3KGNS5iidmxJLEyHZKf0kQpV+OZ3utIV4hiN2UWlCqcgL0d96FOc1COMk4l01Tb+NgykiY9iSVtU4I4N4Hv2DmpeVYHmdMS65k8dnwz5jjFImvmh9Roa4EDAqchwMntWD+hc0cZHmCz+bFQMn1u7zOsR+8Vy+Hgs0X4deAIZSMHKAs6XYSlHhLo47Vkm2rIzTc+AMtPl600l8Xzx8RJ8kQJRAZG4o7v45nCxtdrukXxIO7oyhdpJRIpg+d/LxZ4eQ9VJo6AS6avQNH5xQueXscc5+f5ZDkLSiheoNyDzwl36KJ4Fxvh/NV9WHasHgc8GoE5xu3YViKIp6a9g0rM4KoPiINZN5EcsubAL7VIAEvq1bS0sY99EXImU+uUaEJX7whcfMfcJwrB3fzl4GKiQGJgOyQW6kxDC8kw48JsGilAM3fkApzHvnxj1AvqqudBHvUdkOJxDiov/qeJesfoMykM1zsOx14shwKyTTxmo/KODkslkclBcLJVm2Y5t4IgSm3EW1sWPPFM5C4ogI9F/PYL06Mxh3wg5x4D2w5pw+u+QG853cc9njX4qxHFSg1xKLLLpmQT5MXnNfUhfpvKbS+UxrmqTXQ2MmjKGfNCzixcTRu/zOVF4rt5bGJ6dD51BZrlS5xwmoFOHvyEyyJr8C0pQJwUTaOo/cuwSUnRNB4lAZ5ukVizoZDpHqIYI9yID9Z8o0jjndD5d7LfN/1Nt8+uR4qTsWCy/sDPG1MNlhLKsP0dd/Y3K2GXGbnD/HECTKeJwH6AsNA/9w1en/qCPcJbmSrQlk4qmfImRL28CFRikTH7qWfS6Nh+4ThNO3jLNAaCKGBYToctlAHbsZdhU3qMZCfE43vzaJZfOQM3nVyBhaGW0Pbvpvs/PsZR0tMA70rZ1ngjT37ngmkWXM6YYGyC8YFn6Qg34+kNuYoHBd4CCVzVWHj7s9wUpgw3Xcc511JgCizdhwft4uWbtUgS7cU0DrfAS6BALXuaeQ2tZzFLqdxZP0r0mpYCNc8S0h6ig8HbLLGmfJRMF9NE6J36jIesAH3797cnqWGM9//JPmyD7xzjidt/yXExcsUsGLBdAibE4jJCwtJdIYceuWc5jsyhmznkcsbix7geI0vlO7eT8q7pOBnymbaVu+C9ilzIFW4ij9rP8bprp/5/MYoNB1fRX/ElWBnnjpotFnw/q44MJ+vxo7DfOiY9khYdiwB12aI8emM1ehrOR2EnivC7lpjWKEexnuWXefNi+ZyU9/rIR6p5bCAu5RzKZH/mxjFGTMFwM1rGXx5K8xBb+eCXlMOG83R5VcNv6mw0Y1L9nZT9vRimhlvBH0XBuD4XTE0zZrLwdZimHZdh17ecoe+ouXc4+WIqScCYa2jMsw8Nwh1VUUgsfg0xifqk9nhdl4M0znunCzvWfmVOy63sWCuCVxpDYXa7U4YbfYcv5xOgNDhmTB4sJoFOgXgzNNyXC28BD4NsU7S4l4QanjEB/2O8ZsDM/C+zXG0GpPDC2Ses1NQC62ZtAgLP0yFSXUbGeti2V7pIxXuVGUlQz2cUpXOKhljeQy5kv0HFfp+SxwKT6Xjy7QyXFPYwC+VnpLLglDyWrkXZ8SnkovsGggdeQDWf5KBLXHtXOf5gvfZmsLZKkeOUZ8Drve2gNW3KOibMIpnepSBabcSfH4uhyu95vFweQvefd6Dx41rJq/uuRSuMJlSD+fxQdEC2lWoPKSHkvTBwYOTCn1Ieb0SNLxqJt+CforetpHuh1+D0eTMciGiMEfMCDLy7vPzM/3wSEGXKC0LNA/lgcCbPn6ZFk37ntzAmW8ZAhN6ef8ECXCMecVz7brZ1XoO/v4dTKNW58KzsFwaiLsOBrunQNv38XCeq+njMwF4cXMFDZ8wDjMLhMm0cTlIitvyt9G/sEF5Irin32Z7p/v8bvk51pTNoaVrJTDUohi9TZmsiy1B9etwbEYhUOGDbNwjAVKigDcWa8Pc9X/o6idjvvm9gQpwAVwcdxKXSsqBg3M1LIlJgmW13eAjIQq6IkZDnnwKkqa/hs1O2lQ+oYb/xsiDTOMYKHhRg14Zp0HO8hnpWstTQeAj9PyWjFfHHcDhWx7DaRtB2DFvFR1cNZ6F9/3HOxMmYE+eKfRJqnPTsg1cUiEF8mZu+MpBGoaJ60D6wmN0M0OC1nt+h4nRg/TTooxmx83izks34OuDBRzrPTTf6mQQs1hB28rF6MJIYz7WokLbeQ7/ileDuZDL3m1pbDTEk+MF53OzdRh7O/mz7mItCO1oR/vyKtK2zMTmyk7WKN4DydpqIKIng6cuL8aO9BJemSqI9yPiMHNbOdy80Y3YIwg+qxei99TJcNwkGmUM7TC55DpKy2vw8HwNXqc4m/frrcIdQwyuMzOG96wSB5nI9+y6z4zkt8TCscxJXKavg1MFtvM3sTMUzcvwWOIxdt8+HVyle8jc+j68FN5MaeI6lHrxBQbor4UPtdF0bdEp1nlmQBfeaoNnlBx4tS8G/eK75OqbBNZxprhvwROyOu8I3T6ReGbnS/i0cwoMTkZutV+PRuOdIb/1KIx6M5cFo4PxAOqyQ9cEsImzYutzIlB0e4h9B6p5mt0wXP9agrTLbOCwdyErXzrFFTsaaLnIEVzoaAwd4zNAo+Q3TvEaS7sPL+SAwwaoONGF5fW/YEWHKo3VVyHLlxLQe6iZmic6Qu2oA/Bex5gsK9uw4ucFtk6bzQmfg0Ht+UgeOCYIGiIf4L0t0laNa9Bd/IQXF1iTzt433GQhwq+ehnLWeQvqS5oADzV6WbdtJxUdLqBJK3y4SeYCx2uNA/elgfzlcAqHnZakJTwGJk98S8UDi4m9N4LloiyenlHAC5WFwXxCPZTJ9sEOkQ7U6dWAgRBtfOQuRherZlDtnkcos20RdbRU8p6gAyC3ZRPu3bwXs1fIwbtrDii26zBOfHYfw6/b4mP/cBzVegaSb2mg0A8F/HD/Fr0T1oHxB/6xj1E+mozW5Hc7xsHc6hhaVtmIO2N3Qu6sEfDq7F4Y+04M9igtgN1yS7muqwBO6O7mYP/zaPsuEi8MW4PzW4fz9rInxDrC0J+lzMtD9dFZIpcM/PVo6iE3Tlg+yCt8+0n6ex/3eE/hzIApUH1xFb4ZdR5EPe7gC8dNFFhxjWomLyOZPHdYE3gBTpySgRsTpeFw72fIST7PDUrNMPLmRXBKrAWhio20M/Mc1wfPxZRmedKeogX5tu95SvUvuLT0I8t2Didu/8czwwtId/gx7umeymq6npAyRxfa4wshY9tUur/QBTaJvqIbLccgN/QXq5xeBBcfv6ZrrkexZ+MIaExRYKuxE2jL4Xj2NVkIXQo1zCDK9xKfc/emEv7u20H6d7TgnII2bkj7ChcdzeipizuGv6iEsU/2Q8EEZywf/g/MZ6hilY0xSMcZA439S7+S9tAokyx6FHWG1mk40IjqvZxy8R2HePpjmJc0VBYd4HtSDiCk9prmP0+FS4EBPPmhDew7dxQ01/egtkodHThFsGTEeOhSnECLzyzgB4/ewN5oQxRVycbrj9u4V3gx3Rruyt+KxGFo2ziyVJtPXz1E3gqEIQYv8cdnbY4RjIHTJhegd6IZqQuIQdrpNnIzuEfPC91xar4QnOrfQGk+22H8rolET8+SyIrRVE/awP7hPHr7Bv5jJY2T8xdzZKEE6HxwprAbLuj7xweOOInR5nVKkOhSCG27roOo9T5anHqE3qrkkmjtJNTROQWyQu4wp2MtoMk4uGXwmP1/ZUGEWDr9VK1kTdjP2/IO8VbzuSApswB53zzq9zAC6dTnlJcbBlf0NkPEvmHw8aQzBls24q4fujD190+aeXs+XJpBEHF3ALUlHXDVtk4QyjpMowp7uXr5Y+7ZYAjFv37A2bUz4GfMdGguqWTXHlO88ukWiUXvpojx21BmdhKOjj5PyktGkXPRXXD9aAY/9k/HkojL/NAxEfX9/lC2mBxEj4+kt8tvocygKYgrn8KLjZKw0kuFHY96YG6pAiZnrMN7oxKp8bcfqMxJ4ttic3FNWg8JpI6BHckGJJxmx7MomcQerwNF4Xn8beiNT54zqEVtDRr7ubNDqgAcyvKlUR4v4HrJXnCNr0TLsD0c6iCMQum6lLjLDMZ/mQXLT0vBzIXjKT1liInLQylzyK0+mU1DH9HDlD5zHT9VfsG5HQehXUYWrlrr0pqvbfjIUghWll5DtV1b2KS2hG1nruIWcS18vqyGWwIUwTppH3YM/oL/aieAbYovOG/WhbuX31LiOylyk9XEWzo2UF2pBFn/9XNiuBrYPi1FlckjccFKHVrnUwF3TeVo0aJe9Ba+DC3u6nAj4CQ/86rC3AMX8aJQHS2KLOPvKzzRuWcn7tO6yNqbDTGjfjTcGFDkmnwbOLjFgn5Pc6dS7yj8s7gFLmrcw+7V6hycuRobdVThQaozPl6nzSInXuG+9fNIMk+Dr7umwEu/WlZfsoQOjTEE2yIAb7Eh7hl1G3uvvoXm0gD6uLWHW0bqwg6xRihwOULNaiNhr6YWbL+tiv2hBaSZ5UNSls1gpdoBub4zMFO6Al6Pnw+LVpRg0jaCZHFbNEh1pwmicWgo3grqzU9pcVQvbPk1FQTVD4NTlAE+Ga4Djj6q5PIGyH36TYjWGgNBrxuGunAY7997luea1FPSJ1/e7yYI7jY/wT3gAd26VIFv24xpePQfzpdIpNjmhWhrvQbqHUfgzD3TQf3NJ7zd7Iv/ZmaAsOJ0kBXTwg7fAXw8WgIq7o7ApYu7+Jo+wJKbe+HWFhN4Pl+ZpDu1+bt3ztD9F+OKcnVgS0MO3FnJB0QEYHGSAvv/84NG9Q5ufDSSSgMU+MjVtbTqrhhFjX1Cp57chAXqY+BflgfeSx9HZw7cwLhZbRi4ehfGqEuj88kNQ/5nQbHvXuOIdSLw2U4SQqv8+HTFCoDwe9Q7HPi/V7ocL9gJ1c2aNOaAOJV0j4IZK1ogbvsMkHt/GI6cMKBmy+uk+UqcJ966yy8nraMFFlLgek4YIiZbQuK5Ahh84svzcpqo7EUE2I1Ux077fvpRmQHvbpVCIpmBilIdOlr6sUnKWTI/I0Rfz/wFicnAqoX+sLZhPi6adgOf9omB8EApHqpXAn/z+3hmszuuV69Bi4AksMwNo2E3F+Mx4zJw2DAGtNo6oH5jKvY6XEBynYayeWXY9vcFStS9INvZBvhcSRtprQI0TBXH4Rc0cME+O4yRt4Invw3pTuBEKNsSzxvlk6G77B57TtWB3LtSkGr3GNtatHhLTCtd3aTJewOO0zZxcRLwe0DfdFP56qcR4DpuFf0REeETC+KpYsVLyvb0Rj+nIvy55gceONFLC3bpUraHDmT8kSLhzlN8ptke60J/s2DvLipdEUQO/pdw5lxPjPBIRkuF8dBj8IM7/G3w7Y6HdF9uH0z6VgUdmY7wvsGeLWdYUk2FI+kNZdj/69uXZw8CNXf4UGsFKm3cQxMKJ9GUB9kYV3MVsn94kbfKApgbaQEmG5lfnfalftgKd74kY+leMR7T+BvBt5D67rrQVNUIWiyHYGUtDm/DNuCqGVNw3aIlcF9UBSTe7eBh22bTqvYlGLReFlobhOCJnQZ9PeGNU36fB/tzY1HHzoGVv98hg3el1HDOh8qFC+C6zDiwz9nKF/bK8MxqeXqZOAOcvilize75fOhKN29YYklfg23ok74BvIBcGPnwFu/avAdCOi/xs2RLFk7+AHP9d3CJaDY+vlnAJx5PhuDb4XSn8zmLL8qCfdZ30GPUTXa21oAmpeMcoTsXYkrr+fVWASiSnUDpEhX4/HIQlHTshzCeA+VeQiTa0Qhyic5oqjeNIiIVYVrKPZT8oMCvezKoWuYyn08UIEGVCFybrQy7i3aDRsoo+mIvAHYj3uKb7Hk8omsdBNs7o9/Z3zB5nwLXPT5PBZ7eFN33mWZtNIWjxyJotLcn+Mqk82OPe7TyShwbGHTDkleK6CViCl+vVOJBNTl49bSJ3QpmU9Sx8aw73Bv0Pk3iqo9h2Dq3G8+6BPGgpgMUHhSH/cc/U3ucMA3unosr1KfSxgQH3Oj4g1NMxuH0X0tZW0GZFkgxlMTY0dYHD+jQcmGyvVWO2halFN8yxIlTy6Do/gX0GfV0KP8E4eyi9xjaOw9kJqvA05Lb6AWb6JqJFNGPc9Ari3Dlv5Gw/rYo2ItPRBfTj2C+eid7b9kA62tTOXiJJG/2cuYFxrFQCbfou4AJYK4L5Yi/Q7W2yawxX4KPimiD9KZWirtxAZa+zYOuuTX4954FRI90Ivft1yhm1Ea8lRXOJ2da8OSsY3z0QATMKhnLRrOG/KteAyC7m6t8cvCpmS7ovshB6aOxkLUtjOLV31C8RSd/9xLHe5amMNb0PeNoHXb8/YGaU1bCwq6/NMH0AJ+584hdxeaAYqIguz9HWGzpD71vX4JmWxmHV0hRhKwqroSp7LbkBRmMmQOqjsNgWZ00fPZuQk0LXw7oHAYSx2fjPasfFCYzn11aR0DZTmC9yS/wZqUhtJ1vwO0/nmGFlzQm3g/E33+mYWZqBcn7edH80mMYVFHFZQuFoGfebfTfk04v/1xmCfNE9AE5vtSRCvO2biJlk6v81nkDlWjJwsl71WBjJc1fZZ+z/7wX9FFhBqnnjyOpJFcU7NiKRWe0oM94FKyK/YwbEv7Si2WyIFVwBdSylHCjmA28PfCLNegKr3k0gA0TJeDf2ntU3rwYC6WfkkavIEc2baGRLxJx4RkLPhjL+MttBp8doQkfqkJwudF1mrwii+oiJfmV8yDH1L2H0uhkDnbcyGPENDhytQKkJT3HKZlmnLfIlBdunQgTPy+Erz+ukE/yIMy+nkc/FAtxWNVwcJdIRvFNcvCj7TEluQ/lx8AxSp+eRCpzPkL6oDW82Lqdc4UEYCDoOeTnycDok0DWTktp2f1k+k9/AZwaMQJHhhnhp50a+LrCArYO5uC96DDa1FnHte2j6a/VPOzraaWLUS3w4mAxCz3rg79O4pCn407lc3qgNHAhXfIuwB51RZiuMo2WXxLANYU7ISfqJ3Q8MwK9j4fw6PN0dBXtYh8LBxo+VhPPnejCsCnz2bn4N6T0KKJS0XR4O/IahVid5k0B52Cy2UO+V6nLCZsMeelnb/5yJYLuHjnK8Z4y0HbNEuLLP6C+6niotvpDNTm/efL8ob65HIdvOl1JLWIHfusfC4fzfLkxtha+mr5Bo5k2XBFuzKrRifx1mCBvc0/ADQp1LH16NNx1OEwb6z9h3J9xcHN8EfkN3W7T9psUqpIEm2bdx6Yv9+B5iCBEDqxj+XsJuG3NJppW9BvVlu5lQZm32DRWhdTG28L7+BWsNEcAvnxKxX21U2nepxhqrerm4RjDKGVKVrPt0Uy/nDVdBnhfgxk8XjGZuqd/wbEyP3H3njj+ad8GJ4Jnwo3wWSSwdQXezDnC2bkSkPDWmEZ+b0Tzbht6vKQPPpxehw56xnRw4Wf88FofTH79oN4TmhAv10eFtV8g/dd+Mtk/Gl2eJ2LrV4LbX97zf+lmQ97rS3rLhWF+/kS+dzkd77o2w4ldpWg06hg3COWi/rsNtHVvC6VnB0K+lzjcvQCoMfY7zQkWZdWycvx7fYCzylw4UUsDNRV7acqRi3DIayzccMrj/1a/hLy7AK/SroNIhzqZV9fR+q3lYJLjDNOj9kKzlRbs378Q6vuzSKLZkMzP38N1z7NZvOIiWdWE4REla5h8ZQ6W5evCp4lJbCUsykkdRNIiLyFk+z1oMPPAf1IeWFutgZcuAeQKjADbSHE6L5CFe30E6ZhqEs2PfMRvLDvx3gp1aO5/iRfvSKJimhakvW4hH5rMx+Xv4jvZfzi7vZk3v/zDof0bwEOvmI39J2DtKnNY6v8I9v0O5qO780npxzL8UKxEHQlBFPrQjpx2X8F4281Y1yMMsW19rG67nq+vEsH/9NRJsGoHfLF25OnfHQnX2qLE4jnkVCMFnR0qnLnMhqaPOInhZ5rR/85Jyui+Qy7de0lerAhjo/Ogfec4OGh5FBeFTSTx9YmcXFXDycNdabV1Ed9OyOYjE6xZIlAbHPInw5GJs/HJzhFs61XNVt+/0uVn42imRS6clZhK89W2klycPyjUTQKT0psotyeE52d344Kt6RgkdQBHrZ+KymqX0fHeeJobEkaOMXpwwuI0dP2SxB8K9vRhmT9YCVWjQ3IZOt95RdV+PhCiVYlP8pThfa8ICf+0p8bBN9hs2ch0R5lFZptSQZInSm76D452XISMDGWombsEArS+gPl0WeZnt+H4jhMgKaVGHaV1vNnVD8hSFCftMoDJY8dB/n1zUN61l1s/W+KNG5NJLfwiNDzMRtW9/6PoPAN6/r8ofkehaEdpL6W9aA9FhQYZJSPKKpKU2aQ0ZKRSRFayo8j4iUQJhbLSoBClUJKVSv37P/o+/p73ufe8zpP7GeSvZ+fCbDtx2OdTBSVCdjz2+JD/l40E/zNM6zYc5/h/KTxigRKVfjQE7Xc28MDuO9zdfADMk4a8LL8cFBKrWRpf84yDdpBs9ZYvHr6LeadHQNSdiXx/sRV71Ipjqv9cVmk+jnu+mqOFy2s+Ibmezwi+5Jc7lKDIph0fdazHv3YukG54k66st8SotVdZLN8D3hzcT86fa3HpGQNQEUilpXCCv3gewCltUrCl0hyFJ90AnWGPwE1EFLqdkDwFdWDJlChurvkB81aGQtuJeGjKHQSduuNUJbMV43PekFtbMc/wVocn0jfwqXQ13HP25EgfW2iPl4SJOu+JJJ9gSYwlT6+owEvxw8HskQu2j/wJPdc/oNlEUfxvfwfkfFPn3dIjaJ/zVkyQsaMP6sqgti2XjFKquUflJt97Z4JlmTpY1BLLVCIGyu/zSTdPm2eWqkDN00aq/XIKtw6bxOYzTqKWVReJTmWad3cpplm44PZDoXwnWwTURIU4a6ErHnI/i4lj50G6UiQH8xn+/WwsPmF5iJs5AfyvjIYRE5aBxLc5UKLynC9ssYJuzVi88ns+21tHY2jrcf4mXwRjZtuA5JoxWBi7jnVDE2FW1U1QvKUMf+a84BwbH5oSfofzag7REjUF0LO+BFKOWpA1lDV/O2vg6g8t/B6RAQWqrbTysxgEj1zJZb664K1eRoa9u2BAYSPFqMexjFIdfVr+HrThASRRKRaN3g1O5hPgiPVv2BHnhEVP7eBxdSYaj7LDZiNDNNvxhuO1pkHxkkYw0BkBLWuQ/irsJkPnHu6suEtK/97gR+GTdCalkdaY3KMbzYd4bo41PF29h5f+9Rvqn+OxvaAItm9MA+dF4Xi8VREu937BA0YFYBcsABHXnoH3Yjnu0RXGaKEyvCd7ih1XVdEC1wpkowAQ3bqNn1wdD17p/1j+wV6cKa5D8qMcoL75HI8Ofsir/H7RwVcmcOyrN56zMgQ7yXc8/3gcBMeXk+S+T3z6eQVcXihBOqFeOKp7H0x7bMi5MePhfGQm1v+8Cyu2tnG47xj4b4wRlq5bTMrXX9GtaxvZRF0ExozVh4/X4umbWgyHTtDGXRJa6PXCCEf8Woezn+yC/zodcX63GD+T14Zpe5thr7sqK8+2p4oIBsEXxD7fZNFnlBP3B3iCuEsHRY8QB/PthrTk/X2Ydj0WLmjvQbGjR3DA7zZKdHuz27SF5GkfC2PKTaFNtgKjE8qo+ZY+Tmk5RFOuZ3BO5TgQixDmjZrnqP/dDQoYIQlec++jZUwCJaTeg2yvZlYUOg+nHKdzu6s2nzJphcxVRdiuKgaJtQEgcFGC5nj+4Ra9chZdWECGYXfR4mIo5h/PxraJ8/jLDVP47m0G9v1v6KD+Prrz8SRMHxSCN49m4I3S91S3xBquPT9OwtG6cODja0h+PAHXSHTge2iB+V4t7Pg8kPWm3KSrSmfp8yRvaKvSgxEHRGm8jzX0KrWA5OUQWFV4iogFyFh6qMOrKKJ99y/oyDSERUFrSPTZD4qbEgXXp9SS15/5ZKo7kveOegwaawL4+HsJUBiHcOOYNSVnFFH4lzHsoV5FBkIBFCejCg/D9tCdCZspZ24cjgUrWC1syLdVhCHn310M/lOBUwNzIG2RPt/e4I964SWQGLufrJolQP5sIG68mwnD6rewzUdjcE6ZCvTwOqo4D/WKlq041lYQ1nYrw1vf+Xx6YCG+cxciDYXdaJrdywHHFcFj5yeICQkiqWN6KP7NHn5/289Rehv5oNI2kDyzAB9NysKdFsNob4YcdG8pIHXRbZA60QiGkQjPWu1OH9K/YF53OBukS6LDkqk0r10BMp93wtR/W/laugUIdVlR+IJ51Jd/Ai2FZuOCx0fA+oodXh7KYnUVByx8d5/O1+nA0npzmKaWgoulDvNMYQ1QiyskkTA7NtVO4LRtG3HrgxI2f2AKqrF9ZCblDK9MHsPh/Fec3joGjWan8IDDMBA6oI7j98Xzdu1hkLEzgrxGLUPLDWc5wW0mqG8YyyPOWKFC4WL+nHEdukXOAD1RhozaOZSk/w5ddYN5tf1TyJ37BW/wPHQYthBLZE9gich83Gw1AkZ4t2PxbCOaeSUCzjjb04FHDRi24hH3xCXCGPMKMk305iNJevDv1g3WHL0IJy4xxQu5emB87SionHxDm/Mf0A8de9qY9Yp+Th8HugX66HymhAOajWF9uBA72rwlyaNjYOlofcrteISfpjTjxkEleO90DgePT2U3z5O0NOMCaCpJcMb7Slq42BsuLbIFzZMHwEBKGMwOrWD9MWoUluWM38ZXwecAbXiu3wpuLaUcHGRM2u5jSE5CH5bH3sOa03GwLTaIvYP/UeJbCWi+vRpX+0zGGc+K+XmuOPcaKIL9lXjIlWugF3cbWOL5frY+b0TiwTO5a4I7t0tu5VW6tvBnqhjYVteydPZ7uCwtysVVofjmZST2FQwHgfI4/GyrTHfm3ORWDV3YcnsOiR0whP6XdyFQaSvXOl0g2/92s7GOAidsVmHPugD6p28GfnudIeOEPlTu/I8dFI/C5kpbPvhEkWyif/K0x1+hWLsMXdbZQ35aMzkcWY/bTzyG77P28cmhXSFJP/DLqq04YcJpanqshk9CdaDDYi/73w2hebmeZDDmOPGts9T3VgrXjuuBgd0V0F+7FSz6VCBwmjJFSQzjSpEzWK84kUZP8OWisc6Ua/KZW/M3wdGsCNIrHgsnHvjCiqZD5BZ8AzRTZkLoq1peNXkfpN/7BR46xjyscySfnqgBLllnKWWPAMTfeg3rf96h6bMMhzL2Pfx+UY5NM7bh4uP+8Gu0GIiMZu6SK8Sev/Nhzum5lLpemi0nG1D9y7nwJeMPbi8wJZcBQdgpuw67YtUg/XEuyKaq4QVdT3x/eQEfFo1AO10D6F3ahlskCMyXXMAz287xiSexUBFZwmE9Gfiq8hndrUzggCG//qhbSO0LDaFR9QwPV/9KTg9EqbXGmRqeydG8oG5e9+UeLv38Ga0ljlBruhYMDjOi472H+cbzfrTfHcsvY2bCp4ICFhvYzzojpfHZi3DKEJOFhesP0fOAe1yaKM5bF5zByfe/UkZBPCq8E0GYEof+Fklwe9UE2OukR6e+JPCpij7oXfyYr+afYTGxFRyuoQQ3/TXZvLkB00aowHcdOch/U8y9wydgb+9sXONRBeN1f5No/DIa03wXXORLeXTmGJgqS7hg1hy2mrCNDobZ80l/F86/9IZl4Rr//ngb8zff4KQaUZD7V0zz1vexkXoVvjG4Q0F7fqPfmTSaZngMrrtlg7bYAzLtkIR42znk49EO6y+Ws2XTU766MAXSMmrwxpMW3BVB8NFSldubreDXjK9gqpOPDWmT6Hv2Ywg/kodRxgfgStM/jPK+gaMMY7Bj30jwLnjHAgOfWT9BndMDg0F98B9aBt/DvZUZoJX/g+VS/qOvYsOhehlDkdk2cFO1QLv/JtCbRdZw3fIW1fuq0I+5i9A42oBW79eEtIcbeFV7N1VkTsGXRde5tVONqx+Xw9HyMXivpg5cs8RQVUwAri2cyDsfSsEs4wuYmnkbxAPewM1yNZihH0BRup8hKGobpKjagPOtarBZNJ7Ccx/gLLF5pHf9NUTYn4OiT/KsInCWQ231aMUjVdhauxobr19A7PLBVVY/qW/fRJxl0YGerX0kfX0UK35MIYM4S/iTcwibZB7zaXED1hI8SYUrSkDA6SC9/zwJdo66CHULLWjhiOEg+cqOrilXkPid72QnowuGEMMS4RfJX+s7J9xyQIXfLnjushG02i7i9vh+Ctf9CS4eYay6eyb6Or6DiQv3otro33y+4xgeS5GC2bNXoF22EFx1auV7SgPsLKiPd5pOk4RMGGdMLgVNRQeM+TICdBsEyW/KWaiJ6oKQECE4f/Mlej5MBZEVljA9bwut69RiZbaAss5JsGDRA8rbX8W53uL8Vd0VrfxqME7UH1e4RoNZqhDVhkyEsXqdvEdSGgzeLQPrrdORHxTSr0XmpG21g4pNDmC98ylWzjIHr+31nBxfgzYvyrkh7SBOT3LEn1tSKD3lEy4ruIa1mvPA0d4Y7p6I4njVFho0y8WAI7b4IH0qlrnl4KG8axAQ9g5Ero7Dy0Y24LO2ln5W51ONbQe1jpyODa4T6PPI1diZJEEhUeNQ5Uk51+TqQE9IHfhHaFNqRw+Pe2dNO1fdgIblOnhJMg359HsyVfTD4sVSMPhyMugn3uS2o130R2o6z9gfQvBlEZy7qUqPrRaQ38o+KJ4tDL9Mt1H340fsG7oOAky1GYb6fYhfLj+dsQDrxhpQV4sej9CRgGjbSeB47ygMe68O38Va+b71cLBN/05Wap/hc5wLSUhfhjUbFcGt0BG3iOhhhHgISp1dSuLvH7HquCt8rsyIoyumUJPxH3wqZgd5066wQ+Fs8PjuRQOJyfS7rw/6T+6G+9G+FPR5K945VgneOB5+3XOC/YVz6I9SDl9w/MSB8xbhmrtl4LypHh2a9Hj+E1vyTbKAjI8GpNuyh8/HepBBbz5NWHeMtBdVgkDjb1S/7whPjh3gK4G6UB6exfx3M48L/UhosAdxUztMCuvE4euOU9LOZZyoV8BXXSQg18WRrco7h+S4T9PGW0C27XcWiHjG/X/7KVdQHafNf4oXW8zhzdXRMKbHlatHNBGve4yhK77g1rdH2LPkKG3Pi8bCTHO4lacEjzXfkZNEPB98fh92OMWijLQpPlxtDh/z5NF27wSI1HwJDhKaIF0VR+5QCcZzU6F/pSAtPVeHM6a/5FEjbnK2YyO/nN5CTxQVwGzdBNi0KAi8TiSjucgk/FfVzlrTr8Orxd8gc50rt0cGYYICwnvRHvLvFEB3+d+gs72Ii1fnwlfXYpoSI0muw69yjP9cSI0bBqa3jGDZOwkMH1dGIy8r4gGzAdD4OB+31mbyNJOroLaU4YiWEuyMRrg0/BpGG+5lG/jKwT4At+6OwJTRnuAYawOaHzOxU38Y/P1iTFaDK+lB4ALuMRfE2n5N2OshD4kxBWAxnWDph4OwLdQetkXXweh98TglXBRY4gPNumhCgscU0KHkNpdleHKuciaqZNmA/eI03KI9Eg+9PANb782CSV8F4dOCW5CxGPhvfAFpev2mdz91IS/NDdr19HGehDYt72jhazoeaJp4CtXnXqLckUL0u2wQcLUmlAg2ULrqbp5pN5FKcwpA4VwOtbW7sKhaCUjvSoZ2tbkw7tlYuHhNHUpKkrGv7jJbXV4I1ck/0Uu5B7JPFPHTpLcos3kRrWoeDj77hoOnTxyGvVpLJ+99QTtTSRxeVIoDlQtwSZ8zzFNThlWLJ8BBfT8wuFVHz97PhiTJJ/zySxPZ7r5OV/YU4SERbWzblMNyyhPgaKoo6f6qgYtuG8Hlozu7nbuC2y4N0nPbUti14w/knx8A42pDcPMczmItr/m3+xGYHWCGO3a+4APlRdzZdgULR0lg2HldWiRhDb+TU1kz25aU4AIvq5nEfu3pNLpDjx4N+XtUVBRtfSjKfdfNwdG3k50nyXNilz/59yazldEmmPRdlCZWn6bpX8UheOo3ymzWhPtXpXjaJA+06NaAbPUsWOITCccbhlNVzj8wPNeLM21i0NtjLHjrn+Eug4XkfXETzfKtRMvzXly8GFk0RYGr0zxAyFmANrUJQ53/DuhIOU4HtObCC08B2m3YhjX+29Bt1SaSs15Excvk6bHiWJhfLg3V85qo6uxabA8+Rea+4XhyWAW5rGgAj3GnYalcLl/RMYUyP3VanLiLTGUSKM25kbU8fPi9zgd4eCQffspIwcgKV5wpRJBbpIJBZl94yZSHlC/1h2zfZvOX8kW4ULQRTRxvcJjmIN3SHg7JqmugT/sVJ534wfsstWG4hQu+3LmLEr6b4+EVP8C8dg0+jNCB/HWSvOOXD3wynIi88Q599T+EcuVDjNZ2HM+mrubHWX20XQAhep451z20xCV/nuPJyxWooWGOxtpClBSxHgvsRcH8cC+Z14vDn43afHWvC4iVqtL3HaGw6+d7zj3/D0U93pDvhQksW9VG1cMBtFXeQWZZKQWdmE4iVc/pYnswGn5q4r/7k7HEJJ5vG+1FIQdriH+3mA4lz+Zjjz5S8GVbVKrO47wXflQ+5gawQjN985kI/TNsQGt1I8yuOgn3vxdBV1IwX75Si/OeWtKN/3RxavVXmv//u1U3RGDEpfm0JWoyeDorcUnKGOwW6gZtySlsJnkJJEasIC2ZPXDzsyycuC1MtdNmQM2in1Rz7A+M6TCkccEi8KAlBuNehfH32W1wU10MJgq6IHQqsNOrTZy8bjccPjAFlM/Ow2Pbj/CHk24QdOkS+eYYw9qL1fTpgxeHSnmxn+thcvqqg41zroDCZzv0Kz8C07J+4R5rWxi535IezgxntRlnOKGhnE/O0kLBzTa8SewqTl9bAiHjFOH0D0no0/oOcx0vDPXTPzDqei4ltd1hKxNj/jSulsrmTSLfFzPIdIhCV+nvx1PbPsPHPU00+vFv0pcTh4EltymkcjH6em3nDqqBwocikHT5Hezb84cvJ8jwxvtLANetoPzxTpQjXo8h2imc5HcZz+gIw9hdQuj0fDyWBrTBq0FtPG5lwMKqeSSz8Qnq1p6BVxZXsatfFp7tkGOZ4h+0ylaON39MZDMqowH73Uhu86F9Wz5vmBaDbrsFYeTtNzT30gRwt47iUsEojt68BFaNU8RpmRN5+ZV08tV6hMON5MHv530cZbaV3Ef7orStFV96m4dVO8+TXIAU2mh7DeViCAkAwieLJLroto6MA/RYUz4Z7ae1w1HRCFivLQsvvcbjrKIA1jEcDrMkR/OdejG6XDmAzs5f6fyBHA6+GwlbjyWBbEcr205xZIc/GvDbWph0Ra6hzy1JzLrsS61+Zdzwbwx6a7fhn9Ib3Ov1k9++1AbJXqTNaffBSvghHZ9xikyCDvJ/d3W5QXoB+96TxCc2mRRtrglqmwIw1DSPz22bQurVO8hTcxa4ltRziHAHPx8ZAzsKZsLNx4rwY8ICuvVhAuwvdSb7RS8521yMN56tQxOPGSyVcBaXWbbxKwt9OD3FiBbuuU6FLgqkV9nGD6SrQCXsJC74UkJfq2ZjQYQGLYo3hgvLZHnXyiPgfqkOwur/gl3JdgCd4RT9YxDXyNTh+9sP+ICjOLjGVdLvxaVwumMLdDyaSKdTneD8uEpePvsmtt2MoNflPmDmOgzkI0KoqMUWxZ5kw5/sY6wR0s111sbUdP8s3xuhQDKrN5Nakhxo2s/mv9F7qVK8kRxlsmha21Va7FhPmlqb2WrsRXpe1YRrgwka3Qdwa9l+OPt8LuvuvkwTNzyjN7dT2WTlao5/fBF9Zfdh3HBr+BUWD1+CSuF2jx16xRlx+vh0qHTazLYLKknO9iFdUtzJU29JwovdQVSqqMOv/jbB8ZfHYdJPSVa43E31y8/Aa1MvHvR+zOKgDHtUgqlimBDentBAUUM8vdp9NAgkdqKc6TlUXWnOMxol8HoQwIXXSdyafosmLEqD9O0PsSw2k3cMnIKHhv8oRnwR96yvhd7P1rDo+2v+NSwJHp50x4aE/1+RWIAGySth49MkVDB8zP/9jMTnoxmiDn2BfXF1qJkUTGffyLN63kgKOuCEPra9KO+TirdWp0PiLmuIDAzh297t5KTqD7qzjBDSjsDA+zi0W5HEAmefoGj0IVA5owadqj9xstFQdl4dyfYTp/Lcl4EYENSOTmG+aLBz31APMqfYEDs4HNmJphVv8bKnGhySbuBVGue4eIYI6zfOoWkDclxTfw6E0gFWSd/FVzY3YJLjOlBQG88p70ShdWk6xNT4Qxm70y9JHwxaZwUxWtpc3f+a5/y3AutE68CyP5NOuG5GxdlufOzSASgR3od1GQRrVBzYqdYY3122pbaQDyTv0cdy+xPIZPh7XHKnn6PeKHLCZoDNttHQkBYKJJ/Cy+VOUE+lDY2/vZzbNz4jtekjwDOiE8oHZUD2rTzIpMbgW+dXXLZiL03+l8RZxvYwSl2NXoXcgBXO5+BRoC0c/RLCVy/tYbumBdiZ+IwzozZC5hRznNq8FbQby2F2kwYVDFjAulkHYEbOJ3h3N41+Nsegknw3CUrrgO3ySMix+c4qD4dRkIcS0Nl+erRiBi+72kpxeldYvsIU7jmlwFnFfVR18B8v1TRmxVkmUDu9GssfpWOP+iMITtuOC1bdhh1ennh6jRRm7DGCaX37SV5PC+Z+m4gtg44w1fQqF2imk6LZe1yqdwxyAtNYWCmWdINU2CBSHTY4aYOhTh9u23YYF34dBxqGZdRzg+D2ugi2FSiH+BBHzNYShfF5FtjUe4qnKVwh5XmDoHU0nr8P6T9B7CTc/K8ez5XI4mQlW+jUE4LLgQ0k999Uun/rFvROHM9iflF4xa0Mg45fpEgNRUw4JA9muTe5Vu09b5Q6hpecVmHt10vw8XM46Ge04XM+hx0PV2JoghWcownsILoMCx+WkAxFwfSxzXS9+znpmSeB5r2HnPz0E5/sMoONQz3VU3gC/LuwAb4YGfKnbhuualkKlqU6cCV8Pw+7Usx3dsrDPKl/uG1pL+RlavLf2ZFUmnCZ2m5X0z0zPbhVFwi7ByxheIQMdDp/wQhpDfSdt52q2oS5zsUL3h01pNsJq/CrzyM8GG9OU9Zbwrj3vfD5xBco9nTGJ682Q+Sl+/TiRCqVOjN9PmSDdi/OwrcYQYhRKuPL0VdJQ7sLDydY0/ghpq+efBalfJegVqAzX9ScRYllhnDswiR4NH86L/CqgBlvX/O3ikB+0pxG3w/F8B2TH3z58mGoiRgPaVeiwEmnAttzi8GtaC2+KkHU6PpH64pjSejWaWppfQ01d2ThsQtS1ZzTbBTrjue3y8DO1iUUrtIDf7zN4IXIRg5uv4DXho+Cr3Mv4IeQXJRVXwHi6SZkUR7C4YodcDqjHnQvq5DyJ0GsF7WEbJ+vcFn/GheFL8TdYyog18oYvgWsw28r+6g48yps/dTA21chqL2roag7NXRE/hkIG70DY1sdXGN+lKx/dbGX+TGoQVf4Uj8Srm6aQcFWWbgnwJgCK6fBzM9zYPgnHw75Noe+Pv9B8hfleGK6ISgs3AoHn/ag3ycXrsk6Aq+zFWjZdQG8MU6L3/fN441TR7HdLllIPVEHyt2T4OTPvTg6C2GG8kqobRWBu65FkHXDjetX3oZDo03AQ6ICnR70QuBbfdrtNkBgMA5e9Ezjd682Yf5PWzApPMyK66zh4qsYoLzffNuiCgQKM8Dh3FzotCygJdU7eHn5GhCcJEYho5TgbxXh7i5FWt6TSHpzb2Jz1ic4ETkTJtvvp+fHfsH6nYvJVdAAnq06SWvyftCIyfdhz6l89n2VzbrJJ9Bs5Tna/L0SN9St4em9IyC8J45GfSogt0IXsjNNAigYTipt10EpYzN/yU7mnT1ryeuOGHy44k53nIKpTliOvs1O5aNGD7HnSzO96x6EyPlZQ5xzFadulQYX18/gZrKfrXf/Bf+DF/lqRy5vWbCOvYUMKTW0l/rcN+Lj9wYg2x6AA3HWNOHdERYwqsDxs3fSRZXtJKSVTtWWG7g6tp1XTkbwrFDEPHLiiEt60DljA2stPsMHoxgN1q7DRZWroarUHPPLJCFr8gocue0mD+8PAf3nWvxitRivECxhEcNplH8xFHold9Knk9Zwe2Ig/N7zkUOiD7NrQR3F3/ADq9ee/J9pF3++fw1S0+6CftRwkJttAevTR+HxIwK0zvkJrLJSJKdjJ8ij2obMbR1oUeR7tFpmAaWdG8HIIQ8OnPtEJ6fFkMK3eB7xbSH5lUji7UxX9n5zD23myILazAC6pdWHf8MIKhWW4Q8XbTTLCyPNoXyeOT0HKi2L2b0RYNyvFxSw0hOK2nPwyuXLWJ9gxCurXXF+rwanVOhRmu9Bah8Qga+//FB9phFt99hJhkKT8axDIBd4fuWvh1NZ4kg32XfNpPSPihD9SBPHTCukupTv4CCsAL/bJ3L/JXd++GEPL735jGc1rQS5LiWIDPvJPZlFvP6uMtwR3o5N8rNo2upiUrRu4mmrN8DfMaPh9kwdGGjXQEdjP7j0soNH786kSf/tZ9udcej/+TZt2riGN0eWgsE74SFOVOCGoz9o0155vvPUlZU1F2K40mb4Lr8Cco/+IlXvV7wgwBAS3yfT1LsOcFOiCd5n9PHtrg8YbtKNgclWKKs0m8/49oLMBBlYJHsZ1z39huJfrZgWHAaXuSUYWjCS5pfX0A/HSijangcavQowe8Q71pn/kCxdPtO+XXk0b81J2PN1OhiSOK5fGQL7rrijzIFRsGyRN+8WuEj9kxpwUn4ONAs+B9eVkbQ17gZfvT6cLhi9o1/qqnCqsZRzMhyxLS4Rh43/za5Wm+jZj+dkc2wML5mwgmflJfFRYVM4aKoIr790w5qiJE6qy+NrYR/AWsmXSyUiMcL3LY25FQ52Ly1BdrsrzfodShubSuD9l34UPnOBU5Ry2fKQKV9fOIeM1tbwhvGG0LFiJeerhWNDsis1PtmMP4c0SghSQp+JYvBRJZG/Rl7m22tVwWSkIc2ff58Xt91Gbf9gvr23FCdNm43VT29T2eYxUFFyiLdn2sLFOmmQTbjOfsmHcKLSdlZIaMT/FHeSnN1bfCZ5hbc91WRNMAV7/7Ukcf8hxi5t5Jmf7uDzjm5eVB4FK5r3YMv+25zQVIZp+1RBIWgRdqtWYLxrI+2O1gEB3WCoKIhiu7WN9K00Fqf+rOfmHQiuLhl4OGc8z8ncSwIxceTvk0q600NwvdcHGB44gzsyCGX+2cFfjXC8Ljmfvp2sxttfq4Zm1obX0w70rH6CYctesvgkZfKJHAELGlrAevtt3iA9FoatdeEjpVXwNTz0//ek0CcvEwPfAbY628KsXYmgKfMVZO40osTe2ZA/5w16Tt2JL68KUoN4CuRdlkPnfGW4Uv0c/c1tYcSeVBgmbUcLOtOA7n8jnrWGVV9OJZOXztiSYQgvQuKxxHY9voreTZMeBFDjYkGsvF+FTxzcaI0n41qP71T9Vg2CQk9zp7cSqX2+yD1PmrBYUI7NoQNG6DIdHD8PN2yYRc1NZtCmcYTlaq7xwgRhqH9oSgP/1vGhE1spxkAFb8yLJacdqbTv2AT40q7Po7/eQLc/+6FstCTOadrApx0/UKmgMFTF+gGe7uXCgnEw3j6O+47dwYo/afQqVovKzafCoIUOu/38iCaTOijiiyLMPD0OArL7ye9kJ/rn/WX53cVgHPiEHNrf40LDxXB600QU+bAGRcOUYHA+4gabDSgk2Aunjo7i12W7sPtZPEitnILif0L4sNgkTBQXAmlLJ7AcSAHlcCFM9lhPCkcEIdo2njUEHnPTgt8w5u1tEJ0gB2Zi8vQ5Kp6fVcVR8rkcyKn8h4+dDuDc8OWQNPkUmEhtRGMxQzi0RBrEhTqQ/rVwgHQoTr1QC5pzDHiBhyrZmk/H9MqtpB8O8Dl+Ii7bVkTj/BTQNFMftp8VhymdIyn4vig3TfMBmX+HqPwegofmcjgi+pFqWgl0FvlD8+toMvvdBGMiCmj6vBSQVlYlvVcG8OFQEYeMU2KZzZdY7MBuDn1xEE3ezeDo+SvIQFGbV8lPRLurZnDUfhWrpHTDXP8V9HPuTI7PW0yfrxlz3uJYfuBbT6eXVuH9RlmQCenlinF3uGT+FRjvuIEPjvWGExhI5fVabFsQBy2v3lJVkjjcTThNoVGHWCRokK+kT8X/Dn2ECycrUfKNK+xIs4LAT5Uo8UcVTuy5j3JTcsnv7xkq2JUCjge2saTY/78VL0c5o0figr6VEPRaD3qaZOD8ggbasNGbuv+Ogsx139lD25i2fp6P/ZLWVHb0KQm9EIINNQ/o17L7PPWpKH97PRn99+Xj5u5grG3Ow1uF3eznvBoaEkdBlpoq39y2nArZHSZNPsKDB6ZgiVQHBB+1w+R7JXjy9wTqmzER3Abc2fL0J7jZJA8ZrzaijVMGny+Ppk3jxHnEqVbwHXmKFk0ThAaHAi7sPYlTF9jQtaKTEPDyFmkNO4Uuj3djvPZhWt18iZdfUYFp22yhoLmWpZff42wVQ3oW5oo/qjLYb0k4zHdeivW2sjCqcqhPTWiHZV1XMFMqjKUcZpHXmSCMf5zPhw3uYdaVBDb5vJ96jonAYZZiV4tYWq2kD0WpfrC7dhk2ONjzhbSNpHjTjY3mXQKjGmNoznpJhSqL2KAviq8u6MJZiRJY/fIapA/fgTeKjmHv7CqYKG4Jkm3BXG6ZRgdrWmiLzi1qr5+ABrkjUHjzYvqRr4Ex/jd459B7qFda8YWpiah+xo8uri3GVYMP8XPyLDqx4zvuEy2iK4sXcLG9ALjLvAV3iw7aUK+JXUNsZnB7MtSkxpDn0Y+4R6CHa12F8HqqAQjcSaG3agcIwpWQlRpotdko8E4ZgHVHV0Ka0hEOj2HMfjQWlNUP4DrZC7zhxmSSzs8lhzXS5F7fiV9dSsiw8QMk25rjRdcRsFWonyYNn80hm7/BL7ub6HXlFha/YwoTOUKJPZ8wVHQsCd6Thf6XS/FvyA7qvGDKO5+YIb69hjFXB0m/7xDG7B1EyfFr+d99ebjSYwkbT2iRxZxGUJNfT6VfXfg/uYkwbKsS1CXL8d0BX/beMhYsLL2wJNiDRB59gGGy13FPSj2F3yinhWOFUGOmAp1Lsx/iFkl4HeTOu+8okaxRDCebdHNi4D7+Ui9Iy2IsUUSrjYOMxSg6WAOyww/zvZ2NXF0khFNOR8O7zqlU97KEtv9oJ6NVMWzoeJdVs2zg9ZH3dGl9Hgr8e85Fg3q8afI0NvocDYOXrnJmVif6zDTjYfmjQU3uDBTIGGCBzkFU0b3Gyz6aktDhGRSV2w/bj0rDPplePuFpDBku5WSSsRSefTvJQv7jsFxuD1eH6lNRfCTcXVkPZ8edxwc7TMAtoxhrnz2AE3X3+fcLZVpwdAEt0yvgUptmxDBboAfDQPyeASyync9Fh+25sdeFlkYdx/wTfpQklY0a+BOKIvxJcY4CtdUJQanFAdx+4CT/nTMKihOs+dLTnbTa8z1oBc6kp1UHadWmPLB8KgwnuYOrf5mDRugAyVZcxmWRUiR6dTe/qBMnj6WWFCuvymH62qD5tpOX+SRSfPBoflsuyKXbp+CPBx85KuAZdbhVc0h8AFvaqEPCoCTPq5zCBsYR+KZ2Cx1SeInnyj4M7YUG9rkdTYdDq6kt0ACuti4Ci23lXJzagv1CLaykbkdmSgDPnp/H6i5VHuufApnaDCaT+8AoKg7r94yC+3Nlee04XbjULcyGSaNZWiOQA01cOU7XCBoGn/PiqbJUY7UbX2y4RV5Jy0B5ewTUedzFbfajyXrVMdovKAt7Zz4E78xQzCsbS8/qMujmEEsUTH6G1yzfcsjaKzw/QptbzPShNbIHnmMireCbEPDIjMvvPoTMz8soY0U83HNaQbdazGF7jgaYd97kPcN94GiWJ356eQBOtJ2EyLZVJH/3NppmOPHhN9cpyALAo78Xfx7YC8e0TvLPlfc43GQpOAcegJlLdtNDhU42cE2jfSmWUOLkzVOme7OlPIBO0jQYtz4LoqqqmQ6fwA9PGIRHG/HzXRqwSUaN3rg18IkXRjCqrJ0faAhg0YhS+uZtyJ/XZpJBrDJpjlOG+JOKtL6/CxMUtlGBmgwcSlEAyfJYHky+T2NzlnPyYBIcqFaBdyq7YdHZPKaPo9nzQQDLzEvG9TOvw9JJr+CBbRiZv31Gx8aJQUz7NPqzugNs6nL5n7I2bna248xZS7B8jBf+/TuPEt7Ng04hAThqMYUPzTvNw6c20s/EXpJaqAXK48fg9a5aehvxA71Oe3BXmjA4xgzn7EbiuLt+KOVbj+P2LKEc/RTQ/5cJ132+8+JQ4qQNopC8dQfq5m6Cy44M538KwFmPCJCaOAry984kWfs7EL7wD5CcAHzoS6UY6x9YHKZAPfuUKOzgPDDQ1aXNWzJ4flAW2H1fgN/XmYPMOB2IGuiD6rP64L3UB7StL8JN+UdwyeAJ5g3fzkarGH1fWYHGI2U8JFYEvmHWYNU7iSQ+hfIcxwcc/LMeu7aOg+y0P3jfRwo+0Qxsjz9C7xP+kbjSLP5PdSudlZxELzWew8h1S6HztQKvOakLMjPGY8q3y3DkYB0EP24lDYe/6P2jmLQXLIdVEysx2mkCTw2XgIWl0yBzmhamSijgOO2PGCkkxX5v6rDTPJEX1uwh5cFCwo1y8LKrlasdYzAyqBOCxtdw04SX2BWchWtF9uBRC1uuf/2Ata8Yw5WcItjlowtfn71CnZePebzwd9h7sYL7Cu7w0U8boOPGAQycLjzkDyfYYDeJxB1/QavPHCoKvEGiZ89zWEMxfhBbDts0SvGSvyo0Ba6mjgqk2CF+uvB3B2Xvc4BHL6U5aZMh2Th7Y9fntxD21BxaGpJJ3+wtVvZ3sqD9ECO8m4Kh21w5tH4+2Y9LhVkV1qB2wQK0U6fCpnuN5HljP4mJF1C3kxcXzv+EE3fdpPW/ltFN9SQyGZo30fPP8XTfUthfewPPdz+iCtdPmOHnj4f+DEPni/tJob6ftlTpwnepObih35mt+/bS62tvhnpiNF5d6sQOK/dClPNFuIbWMG67HNS9MQVT97nkWjgKTI0Ju/yeg4H+C/47+QPM6yrjx09NWHm7Loyp+cZZUwX5ZboRLz4WAasflXHgL2N0G2+Npy6kwH3nJP7ZrwEDx+LxWagzNayOQ0PVCFSa+xSlFl/HP6/TeH1fHw8XNMGVQaaQNT6MZy5k7vFYBqNez6b9q7dz7qxwdq8u4pJlT9G/aDEN0xWBTX8SKFviBwY5/8d30vfCjp8HcP8HB6rJqqWlra2U/KiP3FXHQaBuP7xJqQZpjwR+tWEJS566C0ZCmWQSLAGSy15R0uSxdOSmFHxPjcYem5V0K+ohOZz1wtrU0SThYIeFeSPAq/oiD25vw50P9eHf9+uQr+oMyn4InbNL8eDMWghVmIG//64C49IYkHw5HnWm24D0oyOwYrI/VGupgrxcL/8qvESa9YdJXCaMD9o2olguoM1acVh2px0iGkVBVF0TvQKvsGlGI9r32vE8Ywe4rZkMxz4MoKe1IiwzUcDDXQ3sNauM5DaJ8KEWJy7qvE1ygyNYO1GWlj0SotbgYeByxR4eOs6m3fdewpO2O6SavBtDzuRQnY8ArY/8DX8sz7Hwz+GgnSRB75wG4a/eZ7LykcPgWU/A+08W/bFtpu7V7WRu+JfnXBwDArbyXNPcwM22Guxw5Rju6AQU3jeXD5ml83n5oZ1lmYPHnMVg9+oUNPhez6mlj/C04QNO+DMSvJIjqJD0wKWkC4tSxvLEY/rwYe4NlJ/lzCVrFLBpUhhq925DqfQI3FMRRsmF12nr9Cnc62sKuYceQ6y6N6iNHIOuDkd453ai1Mku7NEgTSY/peF0lhwcP20K5Ysm0/3uKXTJSRZu9V8f4oRyyE1I5q61IpjutYELX3RjW74taKUfh8n7rBCWHybL7YX4bNsLWBkYi7mZvri+6CiYPR/g1nWqcPfoHsgVNcLl/sirzKzA/mspz6zbArsyLnDM0kQapAzMU7UF+XdnKLjpPVusnkFdbpU85b8b+OnLNDBRb+PFQoLcOsYFDZ9NhMRGdVjdpIWfx7ygDL2RPMbXDo4NTILpRaV4L+o8b40QBK8jqtD/ZhAenfTn41W2nD9TAhXsqmGfeyAvXWKJJqND8EuBDD4eIwNOD3Rxy+SzfNFuFdbaFeABrSqQv19DRUN8LPjjPHjMzeEXW8Thlswe+FvjgfqzDdizzw1HHM+GUc3rMPvBNdg15wm2yVyk3il24Co+Fk5LqEFt9FU662ADa/bV47k/S/iU91lsPqALaVH7wPqZOQiiHVwkGc5akktG5/xJabMrHLpQS9EGPTzLxpre6N+j7BQLaBCfDsPm/TfEfBHUsfsXTBwvRgsK1ejvclla/fcpFvYaQ5TbRHjVsZIWyjRDR18RrbS8hWdYjUbaSXLmoddYM7YHnPIek+9Dexgtt53HVK7ENTpKNH3ufZr41gH1j3TD6Pmt7JR4ltH2OQkMt4NR3xSIV/6G2rR1cOjVZGr4qIsjn1TSS5Mwzr9oh5IPF9H2shGQpfEMTT608OSEmbhy/V/MFgnCD53/4MQpb5qh3w6Lp2hCR7YmrFUrYa49wfM19Pi09j+6432M5RpHk5tlCNaKlsLctwZkaWYNoQZdsDvgHO2THiSvQEd44CqCE5bvBs9BSwq45kVxh8W5JQ3hpb4FCcYW81s5ol83P/D+V+uhZUi/Q1XJ2LMuByKGfr136UFwxGfyfvCdRcIiqERHkn1LD0OOjS1W77eHtAPFbHTqK4olC4DyuUzMiZ/O3/xm0QL/NPIe6OaJjwZx+sE/7DJ7D5Z/8iX8LQYDYf94evwbiB40JSWVFTjdVpP1JD5yY6Mjt8/fjZ6jhFijVRneHUPK2WnGhR0nOfF3IyhOLyYj7RAoOCbKDYvb+eriz9Ciqw3TlrzArpwNdHenAVU8nsfVkz5xjs5yiPt7jZLyhODR1yDepyYOEzJEScdYCf4NK2YXqXQyui+PXdum0YyWof/+zZ2U1CaTbD/Awj7AF4oTqOPgTgh1iMYMwz6SXrqW3iw3pBFjTuJ/mSd4kbI8HE0WwaVJ/+CUWguebJzNb23+Y9csH14+oZC+f0lnupkFAhlSQPJbMUfyCUZZHmcXQR0cfFtIuwKzye1YNYiHdNCAuxI41epDU7cRrxjWRxP/DtCk/XdIUW4Dr7MQgC3CVrS4z4E8H5vxzpW6cH/eaFoY+IkNolaz1fS/fEL2FBXpfCEBvdmgcm0hTjjtTl6RQzM93ZpgwwGqSPzA9lkSOHLcKXDX6YLTrprwRi2btGIfgtqd8dDS4YftTg/AfdMvuthhj3mnnUDqpjWX/vwBzaN207D/0jD1gBAEBvSwqk4sPF2Yw7WdsbxCrgVajn1AEY8VVOgYTYnvZ1G+pBqcn3+BolLN6N4ZPcjecBPEzNeS8H51jrjUxJ/zJXDXvcXQ/dsKdr5ayfl68zEqWoYMJvjCg8AoWiHrh+PDkdVSJuPYgqlgXqYPtSorsfn5K4yWMKJdG0Kh+eBT3tO7j16NXcHRvx4jDr1dgeoYWDNmNEadnYQLpi2HVMUMMvUpoZaKYVx/owK1egr5duo0PKgpCWPPFOPGl0G467gbd+VNwc6wFtjZsoyHZQbyze4s/Dg/nh5HTASXYzJ4JvIBy6XEk8XMAXS3sMFLl9toqVAeWPMV2GrSz4/UlGHanUGcJLWPI83H4VUHBcYfl3H0F0/85rmAI0fdgpu7ZPFLrjTMiLiKBjUOeGflCbCr1uTVIyXgp58K+oukkEt0DwVPOc1m21Wg4Jktl8Tasfi8ZFC7e4krxrhyfdJefH/pCO5aLQ0CQhMg96U62Dx7iJGm9ng2V4AO1yvxM6kTsHyXHys9UMYK4Q76XbaZljSPhqT1q+hH9VlueDURg1JScdfdf2Ru9wh+ZSrhnMYYftjVT01bRsI+v30w6pwjnVuXQNr3v1EJHsGOnhJyXKbBC48Vw0xPFVJSZrjoZQ5L1f34SbgoR/pfpJkGk0jkwWqafeoURepPZ8epxezw2gJGGwujReAS2vBsJor6isOisXqkF6NFRg2bKOzAXlrlfxs67owA12tzON3SAlY41UDskoXoflmWrdeY4syV69B5WwoVHtlAk2ZJg9Q6Iy5SkYRZ1x/ghkEVvJp8Fu9YemOj0Gx8OsUYvd8mQ5SIEbiWqkBAUwjtKlg2pK0bVXj24eDsSIjzjKSIoQy38F1MWzYag3rtAUiNj8N07ecwJ6CbzF4b8cslYtx4t4D3+VzC1sY86nkiAnF/fsKfzATeUuLLq34doa3ik+FT6wZeeqoZ+tNkacu8RNrri7C5uwwXrV8I6Xk38ZRiAqubRbGN3lve5H4JvlxMAZvcm6zQOxam3xcniWctMLGpHhz2KtKtQCWOffSUDuktYJ3Xz6hzzHu42iMBewv/4IaW3+iVbUBbfozlz+c2MprNof6n/rAlNIgU+7KZ60xg98N8qquXxiQhUez/LYTfehfA4H1xqCr25ezRliA+t5XeaohC+OVz6NPsDWfKJ8OrlABq+ZRAKXt+sNTzVsic0wvf0u7i2etqsNZAFvtQnl8lRrNycwQK0E8yuP6bn6tlQKuyF7Z+0ye0VIAvjYVYJG7Ghw96cvxwad56tZpf3I7COndx/s/zItvdKYJZ99ShzS2HXTrv0qfBdpxjFMf9Gjupu3GIyc9PxpJVQnC0NxB+pgpDUvJ9rj7pgXP2SGCTdDwJWjVwZ9IfUPBqBnlFZmHLJlTRHQ3+b06Q8+4b+NbzApYVDoe+k7/ZojIdxUY/Y0vNozQ7ayffygXYmrJ9iFMHcY6/Oq28VkFnNesgNFKFhbfJ0ymxmWgxtFfx3Sgw6y/DVQO6qFgmAts+7IPcckOeu1wL9+/pYC+pdUDD2mDaFRsoPiqMw/c/QcmGXlq8J5G3dijxmW8rsbKzi4sNx0D4nsP4bbEgqAf/wFNCw3HXRiXKlC3jq5/e4ITxb2n+20TITxsLf9NOQViDMgxGNHJ1nRKsND/POZuT2X3SNO4ebIL+qcfo5xwr9Ny6HyPtbSDL5jt+Et3NLYGpOCncHr4vA+gO0cNvfg+wtaEGgo4sh6O2Y0F38hpOflpLIwSfQ6G8IDhkNcGheiHINZ+DAuFn0aHpFHQKmILg0e3o1OBDp30P8DvxXnykJQJm51Vxdu0ibO335/fHxXinvjjsnebEqlXrIGbYMp6ROIc3JW1hg4DLNLrEjie8NeMlxaqw7T9B6MxYTuVhsnCjJ4r3CR1kbcdqMlOoYpW9S2BE8SOMWWxMjU4qEBbqy/o1/XRPfQaHugxgzmtpGhd0E1OeNIOZZjYFxR+j+wOKoJk3h5MbFNBNtxxSczsg312XoxW3cfYoZ6hYPZuEg91g3TMFEChJBC3xbbS2YAkMO0WgYJqBt87UkcNVT0wocKTyNHN4HiUFwR9SyE7/MSc2nybFO90sslQDNt3ZwHtXmcPCaAtM3lKLjYXKEFkpCCMKzcFnxWJ+o7GRZxz8iAlmcSBT+g89XDzJ7Iwa56wRAEmI5TsWhznQQ5ZP6XyGL8qLaaFVE276zxCrjupiW3Yr9PSNgB2bgmHLK2c8oDmXP81NAKOBUdDqVs4iZQBv0YMd/ebzBkNjCHWX5B9re6hSwp//PP5L57Ta+JLbTFD1OQMXfzlDdGEo+6yQBaPeJpT+Z04XW0Vhp4QuKMSFcf+7FjITWAABPlspPFIUGobqxKpxKZhSGcRXYso4oBzZwX41LT7nTgIdNazjHwqDJmfgZ4M06Mb95HOK2Th/8lQe1lPJ7vlIjomjSFllAA3vasFRudfk7D8C7mSrQfKR4Xzpy1xUHZUIn3Qr6fckLXLU6KeD7eIw/dZ+fqQA8GGMFK0RLiChL5oUkm6Hfs/lacuNFbBb4xZsd+nB2nvBUCEzNO+qQHO/1NKcqztx+ffNMO9eHCiYl+I8AynW9jCAXzP/UnbTCGi5vIm9RJxh9LcYXPrbH2d322LFilgcl+EG9zKDILZwOqzOkwIBmwRa5SFK2QfHs234R/J9tYR+btuCkfc8h3z7DrNurqKAdwKwt0WFQ4Jv8f0FW1BM4AztVN3Bp3o1ucXRkrvitsGF31dIIFYTro3SQKOuc/DFUYnn//KlWGNZnCPvTmZLI6nzYzEWpm3g070G8OfqS8hQCaL5o9ay70oTyDa9gAb+ASRY4ASCi4T4/vLbXDmOQOaMC4aX90HHk2+wMvcnn5YNZrHpS+Dk6Xa2VLsBN1T3UYKQPbzzmY31cVl8fvtNrjNOx/r+cLrUHsj1hSt59eopYMZdLKotDCYhpRxbvQMHgkpIcvEDGr1AEkaEzcdnRunEPctoIDaLPcwFwXKVLF/Km4lPtQ7whsaJtMPkf8Sd51+I79vHj5FoaFJKtJQG7SE0FCkpu2RFISNUEqEikZaGxleFJEpLViEjKxmRNI2sCEVpSEnd/f6K+/n1uh6cx3l8Pu/3o7OMjVe70R6BONZRfEkn/tuLt09NhfBJ6ylO7h/sTQwD+5abcGzREl7bUgR7Ws5iYtQqVilZQ0k7h0NnkSr/nZFFkbXhkBJbh9WsAl8KPHnjhlT6dvM4XYr1ImEBBWjeH0h+CVZ0XNiXBu5uZN34Pt67P5hP93yhsrCPXKLuDbHt0qCZUs/y71fx71PbqGXNE9x6R5EXO7zmPB0zNLcwpNGTRoO65xgIjXmOGmvvU7CCL4SePAzhW9X4g+UArhAcmtv1LP68QxjqsvXgT1oC+x4Sx8Z2I4qvDaD14no4qewjwqh/sLq1ioXfRFJEqjBYjf1EHvZfYVleBf3a8IZ3zw2AnZs9UdOslSJXV1Gc9TzmRxNhXLg7XJ8tytXB5bwURTm2eyLXFQdCsd94ro7+ivn1FjBYaAoa/2qH9l4NpuE9cnh3hhZ98kYvkzx6sKoMMxK34KX1N3HLfwh5BsF4AUR4xDZZEBsk+Kvfh17HGzjtRwuDtg4rHewjRUczKM+yg01PjqDbvGIuGa5GVmcess/WOHjp28Dq6w3gyPaPNDBOD5w7Y+Bl2gK6GD6Tyzc9xVY7KRaGCnTu3cNih9Iw+IkwS8wfA1uPhmD9aQ3c6t4DjVLZ+DTFFtf9FKajzo58ZskRMI6UpGf3TQBnNePaFxfg+o7TvKvOGotPrcLiTRpDbFzAGv0vWSsmiRKWWgAETOGQLh94lfWTXt5dS3oThDi1azW4TH+B6YODdFnUETIjR8DbGk3uDZ2Fd8Pv485D+yAkNpWGXaqiLasc0cP3N7ZKzaQRhiIgaHaRPXz60WqONo6pHU2mKrm4b5w/37z3CgViXbiFf1DPAYC+uUaw/uckODLhOfX9ekEF6UoUUdEFl2VbMVVFBZadKqGb10bBn4gbcHv9btx8Vxpm+PpCgsJ2yCyQhTflKlwxuIkvjqihVtfRcPmbNwp8+jjER0WY6JoA1p4bceFlQRzjI4hTYm/TFY0Y3mXL0NqxGSNWK0Dss7+gYzwOZXrsuMUnFU82dEG3yxV++y8UAjK1YHeuGFvZT4Pqa6pwetN0rLr8nY5Lz+PpeWW8++ACylP7x7NU9aFzlCeN1GuGSdsd+Om6yTTbsAm3qf7kk2JBNPFHMh/e7slyD9Sgo+Y1Lncdj1GB/+jAUwWuyXWmZOslJClqgCfyjLm+QBEFBnVAVj0F949fTZ6Xl0CmmSYIfu8jsREToLw/Bd60rKCyEVkwODgM3uTn4SR1Ccw+mI9bzZLg8aEveEzQhyTHLiLjOd5QMBCDi1qEITn7OujWv4FLVx0xq3YP79R8QnfmfQWlsyNhxUo/dnBV446ZchAgf56dps3g83EJ8K8uiYxPBrD8xie4YcY//KG/jDnuEPwuE4O4WWUs0lCIZR0z4JPxOiwX+obvt9tQx/V7MGdfAkfHBtOr92pwZcYJkLg1Awe+R+EeO2fW/byYhCWbcKzLVdxp3IEBjidg82ILUPKcBjaTavlu5C2UGIzk+ZIx3JzjSWKnLbBKqJzGnJgBLyQU4Vv7Jsobc4nXHU9km8e3+dhUYXgxugvMndJZXeMv7A6J5h2V48BZPp5eeH8A41cGODknGP3GX4K/2zVJuFaANuhfoO7KUAyfNBZexTdS7vBheM77FnjMKeRf7mUU+OUWd+x4hk79rTi8dzVdfqADrxIfYIjeaij9tRdXbetk9RGXYVK9JoQMi8YX7zdC+uAA1r8fBVL7V8Mpn53s+c2H40gSFARC6ELbXY4se81hf2/A+/uCeEPQGCL1XlCt1AGYL7mGtr/Sx5FGz1HlZRuHPD3B1mEmNDJ2GmrJ6kAVj8W6VaLYfSYOPRf3sqeOBbdobALRcbJcvV2YRhnshqdeBCMnm8C25bnwp9sAPvj2oojHII0vD4XUZ1ksMfEXbV+7mSwiJkFM+nvILfCgqUP3/5mDHtnPzYFFMIPPHMvhewWWdK3TgO52K4OtSQWIbf8Ef/xdYFeyMLTs2EdOnTm8rSiK54V3kqRAExU1GsG5jB70TtzPUhMfoJ6LHDXr20Ce0k/83noENd4mgpHOOxzmpAXPBmLh+KWN+DRgEkUfVOeJtsn8W/PK0H3dxus+uwH655NWgwwYd8rCC4Vg5JA7MCJ1MZm7lUJZvANcySriplf1bPOsiY+MUIEemsP3ezVRuaoU1bVzccKRE/BXNgpS717HNVZ93L05jPoeSkC2aTC5XVCFQ9dCucpKg2qO7qV65Ul4M34uKKeL0KdMK/R1lgDHeSfZ2vI6jH00xF6zGunh/fPUMsISI4Y6Z7Dfly6ovsOTbubwsfwMWR2dyN93XsXARdLU02sNBan2vM/akvYdSsKjyxL5luoEMKnaysOvutBMoee4SPg4yItGwR1rMWz4lAz6xU30K+YdPNipD9OUwmhavwYYrxJizWBzvGopjLu0CTpjBXHnzEcwaecqmBYvAOVJhrBTTREn7zCjKem2JHf9AZ5P6UWhW0Y47uMDzDYvw2B3dfB3V+Cc2FS4vnseFicmwIRflzDkpDyMzsiDZPuFtGT6I3b3k4KInBm49NJbeKPexYtbfmKtcicbfK/iOW1h9Kf2DKlOkWBLe23oDsuAl09HssvCNVjrvICsajZAqK0ZZWQ1Q/rjHkjcuQserraEOod5/Ku9H0TWrOevqs+4YLI3SkntpoilGzHk7CwKSMsl+G8CPF/iQko5i6F6xHJurvAG3afbuMRUkv4MKoDv8WwondyBMu+UwaknEG/ERKH913ZQ71Ik6c2LWcTfEkL9CuHvYmHYN3Mm4kUdaN8ZDCNjppDZ3B+YVRMDuSv16cLL15Q5fiVWqNlh7csUSioXgaXbHFih6wB9Mj4CskHzqdw0DeJnj6bZvIt+Hcrge+GtkPsNoftbI5qrCbJixX7cm2VPGV+M2anWn7QT9qFMhzqv/xpNcQbqoOoqhPqXZ8MQ9bPTnFOUnnEVxjasgFsrxcHQaRGcPa7E11YPAy21GFhyxodM/xuy78MdOL5/CZwXGQMhJ3pRbkIzLjSuxC2ecnDpTAqk20jyh9X9vHN1Aq3lN2jWHsgHTuXRSbmplJxzHDq7NMH/9hg4sm0KiZ67h/OjMzBk5k92vNtMpZYGrGRtSILitSRUOBaGV6TzorpLVLEwhw8qnMLjXmvIuoDhiMMLer7+O86+JY0F0QiZk2ez/GdxtNAVgdVdEbxlfiwbP1pGWnsBxAt0+GDxOq7pkQZhKxM4qzeb5uw2hBG6mXjvpzs2rJSk+a/ywD6yHVTV98BDXzWYfTQFHZ8AtwW+AYuuS/iprgMtlxxgnxchmHNkOE/UWUJjRyBUeqZTX34LT7d5wv5zhqMbPafBI/24qKqe+lp68AUbc2WAPoycpYUhAa30SOo8Db74jd/XZYKlzjfcn1HINZOe8mWvP7TimihED6pSw59hZHnfhW0Em6EqsoZfjq8gvcExtNG7j8JvT4fRf81hoNaKrj+XIdEMX/h+XQlf7rEGq9PmXC8uwLV1IaQdmkeyL5Wh4/RWbgkzhojiHvzdGAbFTbd5Qm40j1ZYwccc66FjsIBTskfDuYkStMpoJp8eNML5vg40zlqWpTcf4ineeVhtGEYzyw9DuaIULLM4jac1/pH2216q2HsNLsiI8IbAgxjqNhWLmpLg/dEC/NGBIPCtgva6tqOTwzS0l80kibkWnPPrHhhubYJXe+zws95LnLNWHX60H6PN567SyarjOH+CONo56kH+fk26MD6M9w3MoonOSzFAcjzYp06Ff9GlPPxQOLvPO4PdLvlYZraAHh834ojt3Vw5x4Zv/poI7SnpaNb8FlNbHtK+xxsorTeW9J7f46juBtoXcwf2vjCgZ/bDIb01ndfM3MhbqtLIbu80NmzRwv6aOvAUUSdFmyOg1NdOe35rgVGtFLaVnOBQyTjqF9rPmcl/eMw5aY6IDkSxPZJwTLaCvKtk4Vu2Idn2zUJXARBof5bESX//8Unqwu0iJ9hP6ReMmDqafh+Xga9Oybh37SnYOKwbai+EQp2YJqQlBYDWPAuY6CRMH1vn0W8LBTi2Qo595BNwT0gdLwmxIeO6fjibPgcmFEjA+APC+Hv1CbqQMRrUevNg7YUKuh8qBvdHRpJL/GOU1nDGf58n0EfXADbalsmiS1Qhc3QcRCin8Ge193gzbyVIP1/M6+5MBwddXxwjU8r5Zc/xyBeG5XtqaUmfCx6TnEVT71+keG1duAuH4E7qLdT5uhP+ShiC3h6AWbcjOV9ai/WVg4f2RwqsVbeR8iovGhZ1GuPG60J00TxccE8UmqfJ4aXfRyBmTgxXTz/Nl9rkUHtHPRdtOMhhgWd5XM53aK2fBiuOO5K5WgMFqWzCY8HxfMNvHe637+SBEmUQvhqLR9cK48jb4+HNlEHM/iKJZtELUWdJAwd6DoCgUjkUiq/gPbXGIPs3mL4Wj4PnqeXQMNwPp/x3gr9p/sMM6fEceK6YVS9244W4Dvjg/4pvOcnB9hANkDA9BHXnnWizlRUGFP9HiSkPoFtLHrMvGfOJR5dh2k4DOHfkGwgH12NsSRX8UXrES8b/pZCF6zFsuAfEzQ7jDoepMHnQGMQ/zUaB90sh5uFqHKwSQ6nro7DljxL98Z3KOjfzcULCadZbZQoR64UxadcdWLMiiJIc15P2tUwek+TML/crw6gcB1w0eR96eAvD0/FFpFyQD9k/jWnu0wacZ+5JfmKZuH2zK2dXPqaGFXl0PV0SrANPwvukOL78PYn+qF6Et2GD/DJHgOwLLnLThlNMGmJ0f+lo8M5Gvu00B/73nlFScAetumpAUVdOkZr0bfo7WZ68xJ0ofK467Cr6iSrxVqh0uZEtBuyx52c6oeEwvBn1mbp9h3LHRg8bpAm8JinDhTOefMl/NBesrQGpNBV63G+I94ZfYdf3EjiyczsmOCvDaAtXfP6rEQ0tF7H6SDl4FmXMYULfeJLWAPguWwNSmlY4U1YEIpIDcX/JNs6ca4g2V8ZQ2y9FHhU/Db85byPZm5FYa3AU8akuVCy15nUPl3K07nVo0P9F+j3f4HHaGZT1NKbSD8mQ/uw7ZmoZg+rNNlbb5wvnTcTRNmUObPOOImWnl3Qp4wb3XUBevugpj1xqCTpLy2n5+dXcc+EW3RhbzmbVTnR41pD/VwSzz6l28M34D3fl6EL3tQY4GyJNOmtFodFPD0762+Klh1dpQ3o4+e36iG5RodweOx6C0u+QWPBQhnb8x36PjmCKUgJ8m+rIssvHg4jwclB7q4ypvcqQL1EEt+eZsPrDL9R7s4Sabgzy0dwGGJNuxOm3Wuj6puP8bvNoOLPYh5fJfEAnZX04uzmSvsk2sJUL4oDGGL5wWINdwjwwY6Uc2IT+xcfLUzDuVju5+Lhzs9kbup//AfZKVOMU/6u4x8GR7ryYAIKzTGlr/gNMfnINrLUqeem1WOi9s5zrGuLY6cBvvmq3E33ERoFz7lqY6FpE1X036JRoEe799AgfbbDG0cPaaeLU2ajgOgW8HMZARshffnh+E3h5RNGfrWupZ009HZyXBHObhlwptJonOqXyjVn68Pr5XERFU/COKEWn98lgqrsVUHgPny0Zct3xk6j7qRo5tauBnIQHyEj9Y5OX5hg/lHFh06ZyWNYGWrq7nH0Td+OJsn2YLSMIOzR0WLvyCr/7aofjqpJomy+Diu1ZPLZzGJU5zwbPN9PgmfF4EC0QxKxd71FI9CEJ33yLq31Msdz6MnXrqcMvQTc+LhLJ9X7GkLvOG6MKmSfFvcAvUx2oceVRbL6gQNvNJGHAMhI6Us+yd4AIzHx1G9VK3OClwjN+7fWUf/a2wdQ/MdjYGgtZP3+Rg/QTPCVKYLK4m1012yE3XgwuvF0DVvfaeETQW9hzxYuumGmir24A7V43xCiP2kDAdgTrXt8AtXbqePrcVki8XIUH9XJwbs5a1FrSxFN4BITryHDN6XX04OZneq68h1uj9FBvwS3KWpiFmvOu0o1XbdBZrwgB/Z+htbkH/PU9wOr1Poy+Phw3/2uDFtda/JnsBGIbY9Bykxz4RUfjVocYVntyAua0rcFkya0wZ8cWfvmqgjSvDoNbGu686aMxqBTYceytVvjyxIc+eRnguSVFfDprI7WsTEHLTz4QFrKRd2cKQMVXe1R/fJZd/o6jX00N1PpGlD0++GKmdTYY+PyDBfs0aLmXEZQLCOGh7jQqePYTDb+045E3Mynjqxs4bVWmYbN6WaU5nBKrLeGYfTpuOF/Ax4py2Wt5BwUN+wDfWA6NLr+i480v+bRcLS2abAzb9H6greZ73G9axDdP7Qex2fm8qeQatF3sQd/KaTDBoJnNF2uDcaAs9nm0kK7ZUpK5HUB91eY4eXo7/VZeiga5SqTxVZ3uLRoOdflJ4KW3lWYGRLP2lH58JHKRDCNiuahjE76a5YonKr+yuIUsPLe9B/GieyH64iCd1F2AS64rUHvhWVYT/YISe1TJ58gg77gwDv65fMOnQz5wKvU2n0oyAJvuL2Sr9olcKJnTujLg1eLfYGM9FX4drKXUPcF8bpEZJZcmo3/3EQg1XQ8dH2XorYc+6Y8yJtHPk6AgSA/SBrvocXwwf7x7lRPmfkUbj5OgnPEHtgz6wdxdMqDvKw+10+Xw7fi9WHvYgrT/1WGFQSgHJRqg+3pn6PL9hh9S+rg3UgOKZXawwHpdunugDn5MeMcLzp5kCbtkCHWfjeadDmR56QHWOU6DKIdZPOOKP6d5x6J6pw9lBXTBKneiNJP91BIjCMNN9fHcOym4XdSD1aWnuPDDY+ryBLJcoY3DugVpIDmSqwNSsaU/EO9PMYbOfdNh837i6QmT4e0IaY7/8greh1pgDUtj4chcnLTcEtOcxkBjhSokaO/jtTEvINv4I+vnB+Auj1U07c1IfPrPhQ6U1pOW+wQY7mkAzT+2U7hHAIcMN8J/hUnwudKJCn9lUkWwGwy3fogKF8fC/oL1LOx8i+sP7+BLE+p5ql81L2yKQ0nTLaC5agvPebgHqtabQICRHPknulGheCC9GpnDs/efId2aPjg6zRntKk+CuKM0l2xRgVLPEBzV0YVRC/5y659SNCnMwNO30kBlpgl7RNpwqup17twvD0an+ljZ1gmOXFmPI9Ccl1t8ocsrbkJTejTP7o2HNXPq6KO9JfCdpfDfVSGoWV6CE6TWscx2GdzgFgRvO0rhuMlo7BKcSE0VAiDx6AnHml4mUbOhM1dQ5sXCo9hQURVj407D+eOK6Bu0CZYfUwbHnBU8S1SZunWiIP/Wbp7zQR/m6tpSz1x9nvP2Kmx01aIu4fGwOOc3Tt69Bm3Ob8YVBb2w+EQXbZ42kW4ViOEvJ0sQ0hWj9TpCkGpmABrvZPFamDAE1X/kmfUzqfKoNsraF1PTqjfoKNIFJ2THwrRF79mnqxqvHdiJLWVGvOBFOdmVuWLdiyS2Dj2IgbGzyCtMGX77/8Ed65bi7kMNfN7kMFXJ7+Stq4ugRHwSZYn+RudJyXzQQxuE/aoocewdfOveQvDjPJ73CKT+oAton5RMmscc+ZXxT/p3XwianHrp14sAfqZejBYuK/HNDRss26VBBv7WeOZsKLkkTIVx3sOh/qcTyA6ogGu7MX7W3UmvtSJZs28yWywIwuzZDlz/TApCM0ZC7sZztLN8JKePO8MRuw9QqU8cLcy4houvP8V/t9rB4/N3nmczDRJjdeje/F6wW/2GedtrHjlGEY/e9KX9e91w5MG/PHrLFWy4pgfmMUd5krAlf9o0DMYKDvAr6KbSmb2c8moyzfC+TprzcvF1yTC447GOhSc5Uvjkz3i8echvnXyQDkVzoMRF8Fu/kDxPV4PxiWEwb/Y2Er15HAe0u/B+tShUKl+lzt9RvCCsDfNFt8PG1D/kYiQHmmHjQXXjEpwUFkb1D27CzVmDeK/RG2b+p0CHnyyBveunw/bukXB5+ErA5kOgvkMDLnfcgKTcLAwXyuVHxfacaaHGYHAR/2wSAn/DuXC61o0PLJIFg7/L6PnjUvi3r5oF+3NxTqE4NJu7c3rldLhY8IxusgJcK1QnZfs2tNZYi3qK86H4TRHdGNrrZWrhtMJRFDbMXYCPhB7h9gU1dHSGPqb98OMJrl95i6Q2uofIo8raImwok4Tq7YnQ8vMGJFdrsFjbIji2cCLZhI5g5Y2ZWFC9BKWSyjl6kwV4KDDc21CP3TY7+KDcT3hpsAdtbIfOxOEuvr4UCqLn5mBG2FhYtLWQq7yiyHUwmwJyxOBTYBLtCXqI67y1sGTXC9o07St+jleF6buaeO/166B9fyI/uDqH/hbd5tNh4rT34mawefOMGkr06dEyLTBfHcx+GgCv/zVS3v5erl6+DRzn3cN5j5JQYfE7ODzvOHhtnADXCjpprW8KSH1NJMtxIuwf9YxHjkzmn9EfYJbxc3729TEcn6gI1mNCOfnGXTAb6oqAaWfx3s5CKmndi5fT91LkmwvcuCKWP2sTrNKwwcf9q1l+yF2WG1TwlqJQ2vNWHOZWmIP+n+UYHtHNu7bowNFHT0l9zkaY/mUTzFAKhfD3K7BwjRE2tYuz/rd8Hpu5EioPmMDVFyb8NNmRDd4QSF1Sx0bvQigPeMrRXT48tuoP7xvKLg29kTCw/y5uytfHvFl+PKPKE/Z7DOfBLwQW1hkwoTUQBN894esZQuC5tIsnlvqRTccING7Kwrhf7bBWfCWkvdrIXUtH0eFaU7D/YAxt6vXoZnERukCIppoMoxs+naw15IGLxY7hJtvZXC6hDVufqMOUtZPh+KRSCqsrpsS7C/nzYl9ekl4PXzszMbXtE6e31eG5GgvQC2njNfEJqOc8lIseA7wgthTmG8jA+sDjrFrQh0aW+ugqPh4OXEulRfI76Nb2aHQ7FgBqEnkUVRBAoZN6uLUgE9fb5KFtgyVkK8+nL4bSpI/CeMV+IRdNd8G5JjVgufcpr6rWo8MhW2nlMR2wD28A/9MrWDSnHi0WmaDabT0IihHCkb3vWXxvCmYNd8a6ixaw2EEWSx3sIWD5WerXXMa7TH5z3+Z86gpdNsTXdtCieB+TovXgVaobND99i6KL7/AzNUvc6mwJ+04bc1FBDerf38qLMYUNUAnKD22BdoGJeEi9lIy9hnFnfivv0pXhEXNv4MLhHzB4wXZQf2cCv4bLcnK4Jdv9MacDB3/DwPYhplkpTWP3P8GFBlL02jqa0tQUIbptMSftk+P4tg9YccaPaze+5sS79/DOopmweGAOWUUOMfIsgvNvrtEKfRWe91UWpu02pqrFjlxLojhSX4oejv6AsYJzufO/kdCRJMUjMo9w5yF3mNTgDulPZLg6zpBqn2Xg+PQ5HFweRPkqqnDu/Su6PmME+eSp8zuSw8bMbLB/LMVrGjtRYGATv3FZyqu2akLorW30JDyP/9P04s8XKvnbYgFoMAGW1pCgyYty6fPAOfD/DZC13Rdz/H/BwuAYYEV7bIjxoNXpAnx3fCXpSd1C8XmjuCZFAb6EnkO9d3lsFGrF72bZUpLHexx1ahDNx5vB6lM2FH1pMwZnGYObYADdnBTENl2x/FaqCeYIhNCnJZFwrKyRrx3IpQZwxCMnETIUzCjA7Sg9qssig4Z93NmaDltmAowo/oAqh2Mo8uE4uO8uAO+cHSja4i4HrWinfwKXIMNtI+4d3kHbFBei1J9X8Pf4CvKbzzAnzBanHm3g7gcHOa9MCzZOUuH45C1wRledY+QVaafLPqzLnQCNKsI8LvE2iLjrc0KvA3eOvEoXdIY67lw8BkS+h6TeI/QoTRbkg6Mw6HEDCH5KAul1q+DI/PFc/egPy/rPhv5PmbRZfD7eTNMH+fRNWDD9MRhv82QrHach/4znTmc/enrvD+Q3WfO+xw8gIVIEvuRXUoqeA0203sWODVmUGbMfW3SSWCe8GMYJPWfv32FDziAMs4qf4PL2FrRQMyRxIUF6ojMXY/zKWDg0DM8fbIbi3HbcNEodto0pJI3hxbTbpwmtfadx2Cthau4wIEfLPSgUfokXrBwF+rOMYNTQLl78oANhVnfxtH4xtsk2kEWTF1/4pwSiDf+wo9SaYsMVIGrJVBx5VIGy15RDa9AnHhx2hqa0bcSbZ71g5JJnMHismj1rlGFzvAu7XLsGG8uTSTuiFsMTKijE8iF4ljSTwjUZftLVTYc+CkFzZQUEz/vMx9dmkPtdW5pXWsQjV3/k1jNddPrzd9SW7APjYZPhybFOcPkTx4EBCThzpzY5XzNn2+xuBgUV1H2czSkOJdRkMgzGD7PF0rYWisnNpkrFadCqGU1uQ3xPjjZkFp9BNL+J5oqLgFZWJ1rZ92KbzBfCY1ZwcswoLlleD3I9vvzSrgPF526hB30WQLciIOjHID9vC+aq0JtQ1LSWPQSO8/i4eFJ0/QxKqQ9pbI8l4LgYdo2zwR6H76T3zZwVHx8lx9gLYHv4DP16JMEvco5Aw84xkHqY+KyyMtj1tUBz3FXMPZQI4hv86W1aB3ma3ADhCmdS3ykE9gPF4PZKhe+/8aP0shc4bL4zhTSq8N/mVSz94BwGBQ/N0M4Ybrm/JtsiHTQ75Iwqgd2QerANzMUCuG3XDgqdH4CpnfIwuWYY2MsmkJarFQTPrYBRs01Ast8LdzyYhFvLMqh50QL6XnUQgw4JwJV4pq1bTKDt80Lep3qInz+wYb0gK/7aXw+ij/3wb/YDlNIZDbc2rqLW/1LhcJ82T+/5CupXqqgk+wk+q9MkrfsabLdlNMp/HwY9zWVkX7gGxZSssVRdk8PF1TBx6jhMfevMRZcycbLaPQivJpi7PQSmPAyhl18GYO7N3dwZLwE/pF+Q6t1xPHyyF/9MN+RXo6XB3t0MfY+MpCsyn+hs6ziqmRJGXP0KIlMUecwMD3Q5VciXPUXAM84VRaQ0UcN1He/eehYdzlyjF3W3qEnfF/3G/sagiSf54gF9OCH4Do6VP8S9GaJoHvMMXMedp7Hx80m4RwGkRKzoVKQX/9dnAJ+FetjRJRdf6ttjz8jpUCi6BHc7WpPXyRroSMnDXQu8ebG0NhwpKeeFrUu54cMNbDoyiwsfNKC0rDvFHrjB0w7Us/vpNSSQJwf6eR60pSeKos6FUOu28+gRtBlOX7oI+jk9LOA0k7crKfLT2aLw7ug7/D3RgXZMvsUJ/eawY5YZTRa7gjc9fnLw5CwqNNrJ+oEECtf0aJvNAE0JDsYPoSX4WDWeG/IFYUSmPL8TbeXuH3Hw3zwlcNuZiK82GZL8QX+42GiBsjK1uN8nAC9oKOOuilTa75YAe/zlIG20KnTfHMSnbpV0qmIptV8PAz1rO7b5UcMrCn5A+qh6mCeuDpFGL+F19hR2dvlJSwrGwu9uSWqzW4D9RmfoqbEQifRtgjz5YTDAOtgToY2DArJoypshuIlBb4UsROX50/ibkVQwayd13reErneSNEMjAx/8uYfKl1XRM/MjLTJkTCzrQ4Gvw/HhIT8K3McgHXoL8o22wC7Z5bhtwguYcCwAf43aSKrfD2PU8vdwfL4VH7SZAM6JVVBQqYrjBfRY8Iw7xZwdiylfxLnmkAlHLu2D+BVTceyEMWB1Kokn+GTwHpG3vN5JCT7rWsMw23GwsuYaqDUZgCQ1Q2+fOayclsQSN6rp8pU8fP0tjx+LafEnr72k0PWELkZVUUBYNGXvUoRFLUchUSaFBDfX4itOpBWTXDBrezDonmlCR78OXhs0EtTqZcDOfBj+LD4HknqS4Of+m6eqBPHy2+t4qsYs0A+P4KLRu2CSgTiM+r6OtyqM5FX60zk1w5hmn47GCzqesPhqJV4IkAFZq4f4tFwbCuRqoHLJG3xj6oj+DR0wzy6Cm9Y/hZZ8WcxQjuWQekUWj9OHqc/WQE+EP8aJVELM13O8/y+ijZ0BydnpgYpyE9+NKsOOLxMgOSQK01qjUSeilVxnI9+rQxTWCuA7Adfp+MBQVnZ8gTc+JvC7nqjitjsuswjDj2GT4PviU5Qy5PUbyz7Sm38JvMg4AY5ukQHL9ou4wOARTDqmhfTOC7xHfAcJLRe0LxShve/+4oD1WlL9bAz392vzWUsblI+vg/i6aUPfV2Nx/lGylE5G61gjXii3EneuFYIRgc9h6VYjiO+YyCdGm2Ge0m1q3REBqT8XkUeIOAY2MibFm4DrRxOOiC5H67NboeHbGLTZ6Ayfejfh544ubtiiQ69vnMBDJqNBPiMD7h/u4WtFj8HPRwfv39PFiAeCGOBWDN4bCOs5E0zC5IHUboPnVXOcPrCWmoS+0cvdxnCSK6AxYBh6jinlneKLwNx1PNg96OYgyQ5qi7kAdSfE+P6JXzD36hNQmByOaWwF2/uGeixqJETaGcI7uoAfldfgRbmDbJPXg99Hd0HOeVeMCzxIW5S/QjCaw1eFEmgdtAa5UY9hsu8XtDz8kf9cqaNfglKU0fgce2Uf4fIX8jDx2kRcnXqBdbqYVVV9MVYqCZzXBPN7+1Mket6Tl68aRtkjxGB0516KERCDSzIq+CBHmAV2LyDz31q4qGEn+tsE8ZeCvfz5/RhYNijDv9LnQfiHTrz18i8fkNKl3uqffPShPQlUlaP01QxIHT0C3t2ZRmlXqnimay1ZqQuhltUf+rzlGRmUm9I723BaaDmAI1eYwGUWJXB+QjRmON5ddh6rI03pYYQrGP52Ioc122mc2yYclWkK8mscsTLKn91LszC+YhRkKoyF1e/U4PiX9eSxrpEXDH/O62SmwGmDHSCqE8EHfpVh2I1eLn+gRqcU16He/iAwDxwBH159pLrrJvD1VQVsqFlDN+qTacvyeJJ55gUefmf4YKAM7hXqo4U+Q51waQx4Jwnxgs/nsCJgIe/424T34uXhd/sRMj29nzInzYOKpV+gWWUsrIhxgsj6JTQ7zRt2l3/kwuA/cLj/CbnoFNA4iVycm9dOgfdEoVsjA0x1/Pi352OcUhNLwpkvULH9OEywd6L7o4dmFRMA1UEAymovWajbkD5eOkaNK2eSdn4GfNDbhytVTuMBWxm4svEMDO4bD7aHnpNFbAIcKmtE1e0AO/c3oxbM4ZQHK+CEow/otRnzAhcJ8Nbu5e/Nc2HdO288avaD/X8G0027YzAtNpI6lYRozPM0ejhLG0QTN+LMw28w93I9ZUuuxN70aorViIUHgR/wn4YgiWYUsPQMfegRy8V7sUPsXDSbmxrL4ES/Lx5Ms6VEtIejAk/ZY91dEN4uDqfql3P/6TyYdOkARSX203378zz9lQQJpAdxwIij8H7xU36twzA6+RmbtRnggStW2DOQRVV/16D2qNlQpnseHJI1oe9KGqiY6kL8X1f6vsQCzlxeC51HfuO7Jwe5YIkq3r16mGqbzSg/6g1a6hrDf0tXct1iY/61TZy7hgtSc8oqPNewAJLoCQ2oRUHE+GtA31Rh7o+nUDL3HO4WioTCDyZ06eU9WiI2Ap6U+5Liie9QtPoBPauWAfWHUXxg4Sp2+3sN3mxv4/uHVqG50Rm8disRT9w1xvXGEfTVdQyY7rcDww0rcJtQI8ZfukjiZ6ZQ0+4amu8ynZtF5rHjU23aOtMYHuywx1nSHlzxsIS3T4vFlUM5Prl9Eayta8BJ9QtoXOcuirDUActT69n04wIUhZmsnvwa4xLHQFqdKaeVvOdVlh/4P/dKdvOZCKedPuCqc+4ksjcFZsh1ouLYofw92Qx3LQxhjKokx+F8eHZYash7NmNcxQSqGqmK2Us+0an/YsHHbjKV7WuEU9L34EutMF5bMBx0Zk+Gu5pnSD/DhcPIhoYvEia/nh1c1WSG5aWp5NC+hc5OGQ4PJ3nCc2NJCimzh+yPifBV8i8uftzO69ynwI/YNjyv2UWXX6rCk2m7eWZRLZVsH0G14z5w8cB/XDw/kvYcdYPzhyM4bIsFi6I25D6dypGPAmlm/weYGvAFrQd7UOTrWJr/1o7Lv7pgme5kkmxRhH9Kuahs0UJfX47FLCtl2HLmHoZNHMahGhawP3gBDBOpwWO9DJXztrH8MDX0bNkJA1VXObB1E/T39VGM4EJ0WLeGFsmLUuJVMfAPjIG5J66ilP0GcMMBntsnx/r+QmB7fwJc2vsVNTJzEE11wODDY/T+E0cuopG45vQTeLbfi9bklPM0SWc4Em+ANVbR2GYxDobFOkD4q/cwO388CTbb8iJ3Yzq7cxd9Jwn69GMnXrASA4GJWv9v7//KrfgPQi0+4Z7Fufx6/Xf65r0GvHo/0ISmx3xgdyMsNPiBZSsmQWe+N9kfeMgXe6zA9+43yvcqJSPpT3RJ6Rgek7Bj1XIhnrhuFKRLNbOT8VGuSLrPqzfsGtKsUth8IwzflyyHA6am9EbfmiLuq8GcjlmQNniCFtmp4fZ5fpxZaAA3e9TxZMBWtP1uQL/2OqGcmRE03sgHo8Jw3Oq3HOqvh3GnVyR9kyqHxn1qEDxLjisNC7Abp8Byy+WQvUWINl5v5LgnL+jP49f4YO11KtnXgQZ6E1HlTz4HHxWCu5/OUEJ/DJZVu6HNsJM4Ln41ZOwX5ge3RaBLKxuPpL3mzz2joDFhLc1e7QZ2EgnY8VUH9XWe4HibL9zakUI2+gNUMHot5gvpwL2Dbrj2dhk2xYygjAdX+dVtewpZso5k53nDk5UvwK9hOvYniAHsdoXGfF/uUVuKIaeNIFQ7GavKj8ChY/vozok8uF1sjw4jR0BjpgB5K8jhzJWaeKn6NKu7GmDM9gB+5xMEMotMed9gMqisV4C5i9zotuJZFs6pgaXbcmilvyC/u3mN3ff38L2dy7lbuwwcm6bCFIUN3Pa0Fn0U6uHWFG+wv/iDNEfv5f7cdjI1fAU7UytxQ+E4MJuVjy8GbFDTb8jzg+K5b3E/xMg74BudK5S08RDkqrpS8VEJOLp3BV/L9Edfo2d4uT+F7t/0he8jtMhqWAX+F7adD34fAdtdDaHnshsVHjXlKX2zcGvRVVx6agnHOySy5s0RNLnxFUa7rKNJS8XBr384fSwaJNfnbrhFywvmOtax6uuRaDmwhxQuX2OhH0Ls/sAEcn9dxPGVV1n+pCAbSqWyspQlT7q9BnaOe47XC1TRwyMcsm5Ph3FvPsKhTDHiw6d4S1sVHFr5E7DfDsaOXUqBnsqg/aaXSxZPhoT4HfSodDQ57V4FhrLrqfLZDr7h2sbRj9+SzRMnuCerRR9tEVpaNSFyw21ucNWj27NDOTxuCvo/7oa5zxfA/J5CsPszkjwDZcE3pxgLM0M59b0mqc0CftBpBJ2mFdAu0Mv596JgzuUDvFVFE86Wa/GcCVfp8VgrWn14B3mnDOeNET18aoYUdK33gBUjunGOrhiMi5TA3YcP8p0F62HnxmhMOiqNeUeW4FnRY6i/YwasfefCbiaqMLbUAfc9TYUXn/OwLG8HrvncD5VpvVi2bAsWedbDfrUfpKo1CkZ9/Ec/iqbQiuI7fHxgMrSEPwDzZ6VwtXs+Cfhm4IycTlqbaglp996BRnwyWKMmOQYE4bAvERCw0JsdVfvA5IQim2X9g3UvpsCu/CSqKdHlbpsMfpSymrucZuJhkSPcuLcQBLI/QW5WI0q3moJX8Vqs2yEGY6M+4kZLD641/041ZMBSBh9YTEyWtnl/hJM7x0DEmmOwck0EfbswnZLJiBqisqDRKJsO10/GILvLePLnCDx72xyuyL/lsV9e8uc4P8ztmElvI7Wg+FA6RQ/6oezHJZB9Uozam/Uh5q0VZeerwpluQf4v4Q61H3GkwvBMOum8BntK5XDduHN4xUoP/oUY4Nb7iTQi4znH3hbFPX/TQVFHg9qsVpHoCiWwLBHH8z+nw/fiHIzs/AYRj9pZX3YeRUm342j7QPzzqRv91FejUM04goXT4fGEFHrW0QjvjXeR7owOvpyuyUfXLKWOh0FY/WQNrTcPwbtXdEChogpVnzvS+ror2CQJ3P/JFBRbm0l7uiuKRmwil4SJYFUjCgslUzB5/0TKufmXWsmbppRL4VolN1pbfAB7V6tjQo7xEEdLguw9Y9yVs4Hi2q9C4t9sLHsyisqmbyWnrG3sPLyYz2bdhxv/hsHhMxOoZUkfpOcP4sbch9y6roZOukxjsXYrHDVNCQa0hjHZSkPkloMce/E3euVm8bA7WuAyxJpd2cdBa/Ns9G/L5snPZrHRAkVQd1PBeydD6K/tW/pEk8HccTf/Ln1Ilzfp0soRD2BpnBHeWDIKYv484s5QF5CM2UzODYuQp9Xiuclx+GLsG7zVVgeqUe9A+pM6PDN9BylRbpw9/Tx5KzlBY4kXFvVN4kWXz0GFYymtu6NN1wxN4aGhO7oK7aNRV3ZRk8EDFv+aBiVBK+m+iD6GvY2gBX2puC5iAji9dsS+TZPxlOBGHu2ZCCPXN9KdNkdy/GrHTf9tgM7Cfi7bpgthjjGQ5DSb0t79pdfLk1EmpYJX/jXksYJNnHHwI2Yt3YZLm5Sg0GE4vZNXgz+vx9Gs0vkQOF0Lnxu70dncvVA/Zwtfq94AlTtUwNYlAxeq54H/1BJaePsbWt9dA/e26qJsix85lwSD666N9H26CSQcNiBIiKK+XHvQ+ShB6eHVOEJvKQ2T/sLh4pWcljSaFJMs4bthNPccWs9Ogq18qWohT79RSc6PrtIo8SSacDMMVjVvgBWhpnB2y3689usN2O2cgneqltGmlVMgcGcNTWl+TfUJv1nRYzeZPTUBjYU3US7tCCi19KLx9P/NfyJeHHeRxtzNxRx2p/2B0rjy7ChIENwMSg/ewirnE5B+Por7BUPhoPUmfJVyAuNzavForTkmTJgKM/x82XmsGt1fuJ6NnW3g5rjhPNO0C0OOV0Bc5HZKfOmAYbNk4NmWOvab8J0vud6ACj9FHvgZjVfHV2HhnEFeGySLbi7bUc3IGA5PjuOSw+YcUlfK8p5rMDBLnkXk2mBuqA4WR4hwfdVFdHQeA6LSObB0xnb0+JWGo9efwdBIBzy5fAweGDMKgvf8JHFTa9owbAqssxFFC4vdmGKDPGZiOdt7LYdJVw/BXO+5eMLm21DH5KBgjgTk3NDmTf6p2FztBq/T7rPPPEloFTiORmsZfbSSqTziLX7omQ7t0qE8BlU5+kMWCe2ex0GLHagi3AT6vQZ4WdAm9s96RRKjCS7esoQtS7TA6Y0obz2SzvO2FeCulnLy02mgaaYacP2/QahN0oP/Lr4AnSet+NdzGfmvPw9GtQwzhP/jGskFuFTnMbtu/IleMxThr+4jcNk9ip42/iZ3e01edqaV7z4VJzV1LTT0XIUnOs5gu7EB3Cj7wUcPOIP2NxWsXplK1xfK86NuR0zc8w6u65fQttZ0VJc2hd73baiyawp6jnrJW4++x7dvl0PH86n4uS4Xgv7bT59XfYLFj43B0EyHMw61oFLKQnypcoNfFuzl6pi5lF+lzs87S7GsciOcPioCZqHHoWzMTHyYlccCan/B7FA4njtRi+v3WJJwsBPeyq2jxMaRYOayGHpXJ8K42f30wnYNPskyA4X0ZP4wqp6WRG/mBaGd9OWJJCjG3qDW2Yf4ZIogv/zcBP1TmjA6cjhcbXpOVUEvoHNgDlSeFIX4MH2483EQxyZnw3CBDXRPOJH665bhwIkByK06z22TvcHuiTl4/VTE1A9zIdTRlWqwj9X8n+E8HzGQq6zAWtk0fGckjDGB5mDkbkElC1eS7KUB0qm4jnsVfTHJyxd8r9aBhLA8j6rYTPo2ytAr3IbyUWN5+fAk9jVpgpSpo8m+xIISbH1BYpEcyYi3ckS8CsBmG16xbSasDimDia130H3be67LtOX1Om38Ep6R/sNeXjZKB3Yr6OFqmXo6+DEDBb5HYnTfZFwv8pSOz5pF+6aV8hXFMaTlPwV0Tu1mu52vqGjpRZYvqaDKlHDc/joHVKs1IPWPHPWHAvgcFwdxmUXkfeURrXsliCsSDVjPxpo+p4tD6cX7mOcTDxYcw4aW+lCspw1dq4fx6w17+ckwPdw48xwKKfVSpP9EPia3iYwX3WWXdDEwsp+INz9fZNHKNfif0H1SjpXFsI3ylHJHgm+7R+OA9mH2fiII5xcwShiVE0Xexi8NefR8FMKp72pw9vlnFFu+DtMUH2PxOSVQ8LoKbbwbf79JYLdBc27wWUdNnw6RndsWmukmCcHOXXBy+VTQXOZGEjZqoH76FBq/3g0bduuxmrwJDX/sRBHT+lDbRQGyD0yHByozUN62jQsb4snobTHefzcF7kf24MrbNnBE4i6k/o3g0zNkwFExhifnz4Ed7oexQor43bmJbNggiDYK1rRiLvCIWZvRuFQcwP8c1xbVYOCCsbRKpR/WfFTD+53H+NotLzq2YD+eXLiT1R6LwX+VTnjWai3dCVZm08VFLNtlRjEqk1C7LJKir20mvYN7GLeIQ/juJtKf+QuO3SlEj/vPQfr7TVK2KcBlFUIYUqxGRyPO4fmPZiDeYsLTnXzA76UPhHpUQu2/T7w0VIZuaKnRaTtNaCwUR48XuvDYZQD1N53EDeM/kvnSFrqn5YhjAtfz8tbZFNGwHFUHlMj82kiwkFlMZ19nwfbph2llzT6aMWEOftiwAfZ7lqG1kBOsFGlG0RAjKDlRCll/nmBz01ISXWQNjfElLG5tQaJmn7HVXQPdVKpo2mkFkNl9Bqo+zGSRXFd4tSOIgq/9xtKi5zwHOmlmvSovOvOSxlqKDt2rGP6qVk/Cc9aD+50uOO1jA5vPaYHqtmbcsFqSW83f0M8uJTi6zAJ0jfsod/Nryhv/iGfXzoOol4pUd+E2Y9sObP9ugTJndMG3+BdKB83mNKVsGJF8jJZM9oJ9Mpu4RdSTZcSN+ExXDzjET4C7o26jur8q1jX85Ht5pqgZYIdpp6fTPPMqzMrx5VEhPrz6iCFwsxb6N21hvClEzTyb2uISuHlBPV/f9p3O2rVCvtlqkCvUBr8j7zhc5CAnrr0K8kevwMxTgvTW/zQMqhbRu+/OWJb9F9vj5UBKUYlntHjgspZ/NOtwKbWPTUPZM76smDQdZiyUY7+vGbBBVwG2pbwnH385OtCdysUeB1EuRJF1ovzwqfkCsvkkAjteDlKxoz7o3p1CP6rs8Po+T+j85Q6jv6aQ0oFbHLksHdzPlsFtm2/4d6YZtCtrgU6SAN0eL8QuF3VYfnErnzZtxsr0LWAiK8Uzqzuo0F8EzN0/Q6X2FfpR+IPP9Kiy6OgiVvrlCGUBXuD+owBkNjuR6JPhEB0aR6e6crHqZz23Di+hg17DMdBlE576ncN+LZ3kcDGStulYwGOVLZyd8ggzZxrxrkkl3P8ihjdlBMGYdeUk5mFFue8sSPngVGj7uIK0OyxR8q0dmUxbho9cJSjWNhfT40Kw31EXnc7IwqgCLXi0ORRn/1wBZwRF+GLIV3a4yiS19QRo+CSwicgVunbgBm7+rQQ5PnP5jdVzKvTOA6tgW/i0oJestBNodexM/PhyFqkfaMQV1kP/TJ8IMRMv4P2lq1F9oxneKfvLP/2X8bvB7Shm4oc/V3yDziEvfBX2m7NeOvGsQyZYff8ECbI2wt197D7uOT0+egxLMsdxRf9kCGvczU365SCntI59jYWhLNyQimz/8IGtsZTcZMBbnE05wEoYWiUu8fxQBR6X+ZfzP5+HHSf30RzdO7hwQAW6JwzSDI+5JDvZAmZ1K2LTqXXoe6Of5G4os3P6D7Zds4E/JN/kMW/nUN6BPeRyiSBtsR15rnCA2K0/6dHEFhq/6wlV1uhgnKcxBX6uxqUnPGCbuBIE1zvRI2fCgzX2uF/+LPzKVIKoN63YZ7IVb2V6UWZaBz1XGAvuESr4Y+8F5IREbirpBefPs3mN6QZSa6/nS+sX4vAKXa5JN4Si9DA6fzQNux9nwLwrkvjW+hs9jj9AIXI/aW+KJNm/ywbfbgGoOpyIWU7z6XHBR453Okk/CnZS/L8YrLx1GkeqZsC04mm0ce8Y+Lo2k9STrsLmqVMweHc5XB0hTMXFZkP/y8eBvhu0eYkGFQ0zhNZH8ZizxIZqRtjy+dK/NMZ2Kz9dF8j9/rdQwb2eV7+IgcBNSvB/DJeHPxBqFIbPoLKFEhIVlR3ZiSsNikiJQkVLZaVIQ6JoqWiXRCmJFk0rolJCkooyIkSSkWgYt//gfL/vvOd9noW6ClgfQeA1NBti1pXg8Yp3vGicImwof0vnU+twlMJaCFOQhW73x/xYJxPHznPA7sB22EqPKXnXOnjrrcYlxW/4YbAXiEhPh193NFlISIXWVO+EFKNVcNL5JW/X6adJlh3QpZSIjy3P8Jor8jBz808s1Hbg0xOmg+7oOjphcpxt9qSQ7vKpLNs+FYb7KWF+uwxc6tlK0zXT2S7zCb+IsMbgl8uhq/UPtNvupGav6WiVWkkft4vAeucBuknbwbF4OXeLmmOn/gPavlsGjeyfoJhXNi1V2kDb3upDd6USLfW8xWPUfMg4V5P+8zzLgrZ5lBebCJmNr3hxogHsSdIFwY3+7PAMMWCcIHXHD6fopgYW+exJA21WYC9iTwGXF+GJXeZwrHo5v7y2HxeFXub/dmxFxaJPsK9pOcQ3juVaXX9wxB5cPFEZ1vlmoKZYB7TGNbPrbcDuzjWoGGfKTiv/UsP1JhDJ7+eDc01gytlgzl7NpNYqzQrF9aQj8pidnX/ypLECNMfgL3goO2F/8xiQTl4Mv26Uo2VFA80ZrU1VzwN4QHMa6pflYeOKKxRxU4mMVk+DlZaG8CvyLtRGW7LSPQketnCAWiZc4OvHXeh+G5JyZixzshrYrremdMNsbnA34MiN+8hCOg+9fsZiR9oWECg9jkmGU+lA6lgYO/ET+dyNxaqiOHoxaMov2sV4RNgALzEMgImjM2jfXRcMFhkPkS5euDw3DSawNOcoBsKmwOE8328qeUw0xbsHdoGk71jsHTkOCu+Kwoz6KyyxIxAN/P5w1tBU1knOg8h+KxJ6cY5WC0mjXOMwiGNd8C0N5PabsTRsWwK1BXpw3HENWmFzGXrcpGFOkSkmqljAzvUevGn0fLotNp9CT+9Dm6Je6pA8w9tW26L4pncwNDUGDHYLQ2RLCk2Iy6Dprr3gv0IPfOecxCfy/9Gbkz94a4UeRmEd1b7VhT7JaP6l48xz079DZIQSapxX5NOjJdD9SyCs3/kQ1uxl+C41EUwsftJQ0ieWKV6B/glWaCm0D6x2zMX/SldzAHrwnQsHKVt3GjiPtEeN1uEkaOfCoq2TeMYPQ7y+RBwaI06zz4ijNM33GQwoTQEF1zWkurIAJv7YTtvDu6EsxI1tsQ5eKfbzAk1nCNOsxZ2S5pAp7UbXFgSik2o7FGzVwf3rS1H0rDuM8O+jZ5VVmHr4OD27YARfhn+EUR/d+dc9woo2K8ye24U2tafwwaEuXhb/hMtc03GczGTIrZiG5yNa2NY6HD5J34ULL9vJXXkGnRh2Aw2+N1HeYSdwCVWHo592UWIZ0xGn5fxO6i62V6hCWMoFaP6wGCQ2X4C2B514Y0gXqpqmQVJfOlQ5aoDL52UU22PFKR/TMWTkTpKSKGZDgV5a/1oRRi4dhBc7R2PCh3rIOaKDSU5pEGgwGxVLQzD+szfmLHgHzeNHg/6zfzdRLpN0zQdZddEWFE22pvAruyF430Gy2TwSX1snQ8sYC9BpCiez6EASEWylKFk9dlo99G9P9dBGeheFfepg8f3L2dNjBAg9G4He0tvpfIYIvlbwgKn/SdDHo8m4PtqLxnyRwb+Fk3n6CCUYSvUg27J1tO7ietzadw3EJONJ0bWWv3dv4yMfFfndjCCqdjWBi7HabH9Zl/RHlJLyJF/UUWwGR6scrGq/TyNC2/F48D5K99KGzebdFOBbSH2h6RwyLghkJnuTqaQGyX+diz+pGTckh9GWmaogctiagkVL6doGKf57pQa3zezCupnPYff8RNq3+yw1P50DVd9EQWi/PgSmbUM15/HYpKBFtWdi+ciDv9w9/iBMTk7gNOcYPKalCrvVZuC8ymiYI65JQhGRMDH2MN43FuDax0f5idQ9Wv+0BIQW8b+bcRtfV5bxaCtB2rG9i7NP7+H7mlUYfc4dvxacgJtOo1Ej9V8+4gY49/NEmun9hsR7p4HwRAu6qSlDyY+HwcxWX/5uoI4rFUaCqNkAB8T9ghnBrfxTNY7kK29T4utgbG46ATo+tiSmHcYC5w2gZ8IBuqW7hvsSMzmpdzgqyDniikPvOTfXlN1uzyfbwJdYUKQGyal5+KVNDeJfqeCzvG20eVsb46VX7DxlEr6VVGcd4z42DNIB9ehirDiwiYVNm1A7yQw3nOuEYo8c+lP6GocCfmJLTALLy/97r/s4OiD4i6eGl9CzTl/WD5SCzG5ZuBpzivc/6+LmwgYyKtaB5I3fcHFGM4QUvYAR0pakBha0JNuFhvzzcNC/hrITSkHLdwrc2lZK5sfVodWwB27nMeteNqNe60GsflhNnmsJ7vbN54fPRsKLYUh7LJ5i7skCKn93jnNDV+M8s1w8rhQExbmLMEmwi+1HmoOChB3MS/fiU+9z+dWM59g7wxVelLfTGxUblr/zzylTcjE/EiHPbCXZvbzCx9yfcZdNLtMsbZg0JYqvJFwCwW+bYE6cA38FMbhSE8b5cl40bcYAyD6agL3rgvh+fAd5HRgJBY2u5LIxgzZ/nghLi6L55ikb+h0cz7sd3HkorQR+vU/medOi8cGgKMQUibGu6Gi4JGnHU7UJUmZ9w+eJf+hvixVK6UmDsV8FilMTHyyWho9f1SDT6xT32JziaKXzsMDfjUVj5vCbid9phI4wPSzbC8sqDThIdAysjmNO+n6Gjk+qpk2dQvyTbTArbj+mOLrRk80ucNsjHc9sHgOmtATc/Fx4WkQb7BimSrcPLyXty3KgdcGYZE7/QNx5BBOrRGBORh39nvAVj67Jp2EBd/ij1HtwmxoHRRhMJ3oreeqPWRQiORwentsAXiGv0KymmG97GYCdTjKsFfqCwRJfufuOK1Wl7EXXneowVGCJRSrraNSyW+A31wAsqw7CZuEZEGiVTaGzOzl/dAbq5yNMXyZFjVcecuUVYTI09iSjMCMMffGXq/dF8+4TvTB6/jGyuSUGjisAzh44wRqj5kD2iSmUb7KHfpkdo2N+u+mk4ALUyzbHJ8rDwfvFO/Zf3kGJE+Ngc+dxOnnrCPXMSYK9ixfB98Qkktk3DDZGCsP7ljb4efk1pM2fAmuLL0Lb7Unwsm0rPRuZQkpGPjQ5TIJfm2mCw4dCaFV+C3mP5vGNRg8Q07kPiv3fYWtlIWm5z4bgh6/Z5MR0+BM0jfsW3kCtShlICPiAY8Zo8qtvY9jumzZuSOsl8+lz+ZSeDIys/QhCYwlq7rdBkKwT6t7rgMjlazBCJwF93jgwjXxGx/aNgA3zE+CVsSHayAjAwbuCZJKZy7u0Z8LujhU0fNJv/H6iiKtPmsAd371QlHYXkyXMMa3LB1qXeKPmSEe+7jcEj+NP8iHV6Zh+dDiIiDjgmFfmlBTnTtsTnvOZwGTWk0iiZ9lCXLhQEt8u+862Xyzg9NYFMCPwB9UvlsDh9y1IIN+Ru3WSIGlzLJT99qflKVc5OUsAGqy7aV25NlYfmI+3pJVJqNWar9sV8ge5dp71ciTOOl4E416MgjVzB1H1/BLoVxMi01Y3cJQKpWQLO6p/1A3tCj8pQ8KQPccqwmKhbs78qUv52WfJ1GU3JqybSmnTAnhhVjLcaJairPVbOLVaFmakx/GRvD8EmyOx/VgVR8UBCVscpuJ/LlT5aj4VvNXhU5f0YMp6A64UmYTXvWZT+UFXTjd5yG7W41ngtAckHxKDFSM6QevTDDCOWkJHl9mRt2c1S1+5xGKuWSQWuRaGu1/gikVGfOjeFLxTqwyT9j6G8pd3wORgMYdKFtLtmdm0q9UWrtVFoqUrQIL+AXjQMAkO1z3gSQd7cffEXNYw0KaPiyyopyQE/dIOc2BHOjrcTGYNNXUILAvhvBEScGXjDt4y4zc2FoTyt20qpNVziufFPkWZG9tR3F8b4vzlaF1HNQUnjIWnUxvxsMNSbBrxFsc2hNKFyl18pe0SWoqKQpOkAJxy8OOpm8VgW7kO9b17g9uN9Dl5aDytzXpK5zRU8NcdXThdlw9qLyuofJkdDF+3EK+LdnFCyxZI+JFNjmG2GDG4hEarT4Ljd/WxOU8ZVuSkYrXfJj7//jA9cf5Jx4Zu0dWOWnhEyuw0TgN2iRZA6xxPlrwwwB6Bn2iKH3NAkRZO/l4Nn/MRn/vXcJr5KLATvsaN0zNI4EIv2Hh/AoFPdhwn/xDyTnrywVsxvOqvDKL+VHjk7Y1jRuSylO1tdFWIhgeleiTwoBXSLyhSu9JjqH3TQrsOjYU9J96x5JoAuNa2AXxfbqUbZvb8VGIvvJUPpsPCaRxgmgAyS0bA2m2n8OpuTT5wQQT9Jy0mPfsGKpFcATlnL+OIbAM4JXMfX+zXgGKhQCip3kASWWHg8DEYHTf+pNpz57DM6AgPSUTjx5IvEH57GDy0fAGXP+8lJSV3DrcXoPgaVdZWnYX9A2upa44e5j6qxf86ReDWeFEo3VML9uEEQkMm2EFHwHNRC2LaL3D2MaBd+RVgcm4GPDe6hi1LLvLrSyPJQnI6rTRTh2293pDyq4Dzv9uQl+EoOqwiBIedrHj0m6l4vFUU+w1Ww5jcN3D67EuYPWs92m/6199ZNXyy3BTENU9iSvxPOCziTuxZSE+lZUjy8mq0eWcLU9Qek6tOEteE6MDV5WtAwlScx8+NIQsyp+R3MVg5Mw9Wv5WFttFSeHRpMTgaM+z/dRGvh1SjTdgWuDjzDDbKDpDK9/N0w3YlC9vrYNitFlR3lgKZ9Im4f7w9+ESNxPSzgOWe7fzAfiV2iKewjeIzrJzuB9m9IuAiVYlT+/N4wvEM6LltSNfSPNlMvh2+HvxJWXFvsMfeiWXf68CL63W4acRiaFXciQUbkyhJoR2Vnoihtn84Fj96wwXjQii2SBGuJhuTm2gL7Qn3xAdOF9B6RDSUwk9S+BkPvy2fokniPDR+bQ5mAx8w+nQ7HQk/zr79/iwuv5d6dlwiWZ8lKDr1Anbq6bEKmkCVURibOn6FOOErbDrREs5GlcPgP/7If9fB7ofdKelaOxrEmEHCr2SKUJ0CdbWJVBP6FJwOL4bF+SKwsOg0rN81jwuMLsCV3hHwNSiHrCSPU7ewDGw+vwWehdbhh0Bpem76CqUu9tI5iUF6WzQDClZkQ3e/H1+t/My2mSaYJhiJiS9aSCprNCdbfWHL9Y+5LUsM9pi20sA4A6rVI9ZSUeb+Uc9xTi2yhM4hAsdHIFf8g+1HTwM+UQmi457SbYE2yJQwwCydBeDut4qLFXQo/cMG+KHXhSdkTOCU1AGMtKxGtXNvueFfjytIayLVbMSXfzrga+UN6q64RK0mJqBsfZKXOAVg640YdNnazeOevaFZhTvIKqSRdH4344GA/XD4zRSYqeePpxsy6W68L5yPPIPFs2/A0cg7dOKBGvv6iaCyzF38GGgKTrb22HZegjY5uYBq9Vzov9mIPROMaU+sGHxe+wcDSsPYaJIs7HW/zwF6/jQ0tZjrRpbg7JFT8en8NiiSX8Vp66KpdL0JqD4jmPFFGQbvu8PkP3dJ9d52kGu3xD3WvtTp5YOl9BebXBshuF0cmgQegsTsD/RhbBFljF4HGiaPYJnse9y3XYL7cT48jfUhC3dpeBuznA9tOAQem5+weqIHT7WUxr8vkP0zimiuzXZsLjoAv//lXECylFsnCZHIpg2w9OBYylsfgNN2dv7732k0TtodRgYlUu1jFbBqXQteU6Nw3N1q6Ht4COr797Jd8xV8+E0IJzj28+MLm8jv2Ggo1jdHZ4nL8FBQm+FENpa4dfHCy2O4Bdzw8JRPvO3iDVK4OAzUtlXj9x9nsdQ5ioMcE6l6nS2HbzGEWVJ2JPv4AJyOKcTFbABvu9y5KTOGFtqfpdx2U1gv7YkVa61pXv1x8Az3Zexfgq8XyoP8D1O2sE/iE2uz+G2MFRn9dxTDz1vSol5tOrlLj0KXjQPXNeOhuWcPG1yaBkfUfOiczDUKc3CHmXsb4NilNeR4XBgOyWeykboGKOuHgM34E1xiOgqMletp5bYP1HCiFJtONaCWny6JNtZypsgIKHu/GcP6bTFtRxi/qUeMTlCAX20FFLtvHQuuSMBduVJQlS8KH84p0OUH6/85xmfWcNPk5cPlUGKiAOvYuuFUr2Ao2L8Y11iKw3JTc8y0EKJ2+eMw0n0tGlrr8tbYBeibzbDm7Rn4LnyCDOrHQuP1aHQeZk/vjlShpLALeE4JAvNfB8h2TzbmDq+nkHxLsNX/l281Jc7v9sWxh2zoCXzHZdH6JGZXyguX3oDM4GTo8TOi20+MIeWbPN9VC0MLQwX4Y6MMRVXC+Ek0kQdzfCld5S60HH0CLw/LwK7ra3C4QSAGep0FiwRhjEj6x7DCb+BN4VWYKx3HDloSIJEoDXa9yWy/0x7dVt6imXmd+Oi+CRmF/Iedk8z4yYgFOOPZcPqdIw1qN5aw7VM96mr/zEHurygLItDXYwFo79DDsC3X4PeIQFCM0QBNsY3sWzSJulP64eq3MPpQ0AGZX+LJ7WkuKqEXmhw8w8dvzoCi0CY08VQF9SnLoDrpBhmNX8pzhYtJcvJ00H4/l9Iu7aWn10ZCvJQqTA+VxPqj6/HxqA+wxFYd+nOu0rjXLvAs6zT3Bz/Hl1EEL8WFYNnjdzAu+A6VVnyjPTGRmHfoGKd/NSMXdxceO0mBLmUoQK4swbyT3yk7o5IUBkpxwoaLZDz7Kj3XXwWYp4oSZ99RVP4kKN73AXZrfcSc6xu4Ie8IffqeTTXfrkJZgQ82dB+iiwN+1BdtCB1paRwetprj9xyGpNt3YfUWUxrQCICrwQP4adtFnN55Fhf1joE1G21w6s809FtpAiYVgA0JsnzTKgoez+6jtOUduE3yOC8WGwbmJooorXidK6JqILWvgMZV/8ZTWgY4daInlWXloVluNE1REQWpVxPg7ycrmu37ncpWrMX0patpU0LaPyeqZrGfK8BpSyAMBkpAkHwV7emaS5NjHUhy10pyW/EYjlisxNcX5DC7YBEtbHZDkwQzuDrtNrqsVALxlV/hmqYTYLcCa4AepMhvxwadKRxYHE53hUdDu00frby+mvau6qZNOh2wbncYjbRy4b8xTpQXNZtLbax4fJYRSK+fwOUeT+i6sAWK7H7JGsMF6cwzAZT+5IziV9ZgovF2sik2h+krEiFwmwWN+noPvVwe8aE/NVj8LoAcS2Zjo3U3HCtU4YVJOuAS+AyueIuirtEkHPFpBfSIPgcTAQ+MqPhC4VFGOMXHj9LfycD9dcnkJr+F7p5Mgx/Ta/G3627YHDaBEmctRQWFneAW/BsTHBjadjvhMX1zmHMkFs2cfqCm3mIoVmjGH12G6Fg+AWeVvEPXx+pwKSuC3oz9yEZBQihzVQbyzs9n6yJLWFO0gbP3H4M1t46x/7+drZ85FdWFH5CfeBft2OQDAX1iYLtQmR406oKkrB4oOK/FNX+nw+ltOtRyVQyexfbwp+uRJHEkDB4X64OdnxfXaE+HEaJxHCAqCHI3eljGwJK6S8XAxDsTg6ry4FOwDz1/9pZUVgpgsWAmRk0eAe8eaMBxaRvuHDAhlxVDMP+bJe15akI+z/bzjlW3cZKfEUa46sEaxwza6BBEwwd/cuSHdww1w+jjvAO0zNgHNQ0n0rbjepD9TRWWa68B0/ML6eDnXtxnNJ/S3nrhHc90Vvs6CTUcazDrWRK83zkMtMeex1GzNmP6zM3Q2BVCf6tVIOqCGo1tjqEvQ7p478IQfU0zhJebk2l66w42NYvC1LineER2FAxEXeI9MyPB2z4UZWNjYY6qJjxovooW7Zr0xhF4ek4E2rTX0/HPffjiK6C+0hSu0LKACeMnwjC7hVy41Iyar8Vy5MRXbG+lSDurvoHAjwq+1bGSjM6uptSzw8DAOhYHuv4D595yXvTjJmSMuEKLczbB90cHub7uMLWELKWRo8WhxdKPanp9UPnPWu5zvYMnIhbBJp8ZPFhURMV7atlz90Fo36AJSSdVcN+NNRT6ehs9yjGjiXbNpGb+iu2m76I7txTZac0Ak7oqKN9WxV13x0OK/Vxe8NqFFdUzYfDkHJx++SmwjRt62P3bAQsZqHq+hi/o7uPG2Dzo0TYE7eGtaNi0g5rf99AG4QSo2tfGOxwl4MmAPa1wLiPxE8zVHd+xVcmWpFKu0stWH9huPRdd/U/Qm4rhcCrvPzSqJ7ROEKKq8m1UdzKXzE7FQ+1IRwrK7oHgzUm0WMYUnowSgR+L0qDinQM2CFVh7BIFTt0UQFdeFbN/4H4qzfcGOTFBuCp6D24Jx7D8di9ecTuUiqLPg/PnflQR+wKvhA3ov0F5WP5AF7QCf1KijwgPVVmyjJMKzX4lCgqLmZyzz/C4nJFoXNDH6TsN4PSQPulphtLe+h2gobMMLUrVecX6s7T+xl729z9JCknasKlFEfqChsHHHXMoyaYcxy+r4X1/Wv6xUgg6e4Xx5Yp/c7yIx5Z+XRgY8iF5/3Ry9TuI3mKAE2ZVsGaxKgzLOEK6Rb+hzuoeTEkbA+uWl0PR8DFkm1hLeztKOXngE5/5cJFLrp+BsktP6ULdZzyYJgK64lkAJsGQFnQbPLybIE55EZzv0ibFpakg4mLA4/U6ccQZI7gUU0GR2I8OoyfgiMT/YHxPFR5dO4s83oZAw8SL1KUlSMGrTGBq5SI+d/Qrjlo1HGz3n2WRW864fFc+3RH3QNtlmTx61WLQeqQNXs/1OGvvRHyeJgdGhfPIbZ0DJLrE4CzzU1hx5gX+iHHBrfmjYfLSaE7WmE7v5xnBCZsLGOiajy91l9FE5/FYkWtAvpuFITh6KvhcDeWugBNs0aIMcGcetX2bgNH9V7H1wWRakvMY7ZWTYV2aLKzW3Mbjz4aRXpsI4eSztMNyIUamrMGe8fkorL6Jj6svJcfHyrBa4iT82CRMDXW2MOzKaXw0+wmdFgiF08ItIHV7By8MWMFL52pCFKWi214l7l4Wx5U+xqzd/wqiooxAJvMlSXR44ZLPFWhaYgEag9ksVXGaPVIfwiSv13BryXlY7XqFPv4Rwc3twfRzaDHfS1CFQzOTOO7MVzK/EcOx8Q64VPEFFagaUqHJfqyyroH0tvNQd0ETbgoX4EMtScIPi0BO3Inqbl/DhvGFEDO0i3qzlnKsxmNsPyYN96y9ePGks3y+RpzG/c4FzY9OULH3CeSOyobC/Rc4t6wE9aIl4U0FscU9MZ6h/odWKgWS0QMxuPFiAglurYQHnfHwfa0LhD7RBIHqdbjF4jd/er+bI0Pmg961HLq9Zgm/3juNJ5u3odCGEPyiZA4H777Bhcf/+Zgo4NK8XnL+2EqTwtfyjcFqcA7pJcM8By55LgDesZH8/vNWtmk9BFudK+GxQQCJ7O3kB4v8+cOUOhZ2uEtXdEQgyGAhuL6WoSFlxu5kIcJ5Gyk6YwEJ6CXzqVAHfOooj3IGxpD7K5J0BO9Rqp8itOzN5fmLm7DURZTkJwWgScQIKMlKICVZgJeqoiCeUA1LdmRRo8cTOCazHYfdu4a21dvgjoQcXpY9TvqLpoJ89k8aUTCVExeYU9M5DZS4acuF4YHUNpJ4z5VKerHwMnu268Gdww1QVl+Pzt1tUGE7D6qmWFGElxtu3nefPfdNw8jsPgwyVodtl66SRUkn5x6rxEzLa+hdxVi4fSnWHUa4ae6Njjt6cd3csXDz4E/IDpmOWYMlODb8Fi46b4HDKjZh/Kt5uOVBPZ/V94Uhk+mQcL6EzNJH8Zx5t+GxizrOH1zNf1t/YELaGfBRbIS+vAQO2iwAxncv861yeZBYUQhKQRP52JNc6G6wIJ3ACNzolgR31mbw8WXaoPjBFeIL8oF7l/C0qeM4WfkHhOX/R+U/ZFk2ZQnq2GVTYpMurFoXQ0/srdD0cx/4nJsMs+N8ecfodbiuVph7fP7QhrlT4D87PbC89g3M7QcwICMdDu5MpJPtWRxRR3DN+AxUzyiG0kWx0PZNGurk70LfpiGGJ69pQcpIisvVgdoN/+b8NI5ExU+xYaQG2byaCPuL79GMgVY8rTQGF31Yy6++vqY/tVa469BZsC+xZrOIreRySwmerTwF/X8yecaafaB8QYW+pKfCPl4OC+Iu4EErH4zWBNCfrg7vn0/m5GQJ7lTYwmrqHRwGx+hbwAxa5z+Ph+W/AIkbjzi/XQCuOfajp9w1sDHvoVVmx9nMJozqn3kxzLoMUhappLHfAUuNh0HgEwFYplHHotvnccPnGH5YuZoyTtqwmeAb8GnRxptbAmDOXk148s/3t515RAXpqZjsFUWSShm4zXcneETdx6G6UIgZJ0E+O43A/+QyJJtYOHN4DN77sI4X9adgvM9Y1Hk3kUa4vKSqWz5sbi0Ib0t9wW75S1rQ18Tt3615UKuG9VRMsCE2BYa27wE6NYV/ehjBR995eNxgMV04fJHql86jJSMMWEQkCk/GnKL7c1q5zH04HXsyA1J//5vvjQkePdXDxpKJZN3fz2nXptOs9p28ed9yfDTtCy64NwGCZOXBvXAbzDg0Em/viacVDprkGzQHBZcEkNA9N/zt3oO7Vo2AeZnDuPpTME17+pBHzb/D+q57eZNhEvXN2UhZwbPY3bSLjGy04VrRCR4XsBtCc6ZCe2I33ss8REmp+ymtcxckeMvza7XFIGwsDS8byvGVYQl+dxqLtcq3cNTKJfQ0cRUnCorAfoUIavrbAbuvyoOUvjGcjz8J9zfu42WyJSigPgmM5vzBkv1esI1dMO5oEH0YaQy7l7znlZmAVhKDnPXuLlqukqfyIaIQsRC40FJBrwRLQEp0EgxbaQia2uYYaB0OT1Kf0pHiV/BbtA3sc45xs8YAhfnYgLGpHNx4EE4eYrexAb7CPHyOG+8HUN25hVzntRefjwlgyY11eN9Q+x8Ph8PSHODGkVW86b/hGCkTRov/lGPZ+H8+2zueNpmW8ow3wmBq0I9r1ItQYN8w2BC24Z9PHuPpD9eyuv53St1XyHPvdIKIshzUer+CxWOu/OsTZU46/pt3WRxjz0MJFDj8Lj3W/MgtnYGk6ycFRfFu8NPalPvlROBuwhiUGGMO56GExRddx40q18D4WS9EyGnCiSVTeNduEVwVepvjp7agx70bMHvZOgyyFuKmJ+KUMmENnHKVhlNfmYWSpTBIfjkc8PgAJxVNeWVIJPE1JRpQ/k3Ra83oTaks6BU+gJjqx2Ay3gleKeTDmOAt0Pn3GfadewWq42/x3H0pnKw3Fgbtx7KTfAe1inrCwdP+HPi8g9qmPSK1EeV06/d3bMwO4/waYfCIyad5yx0p6YMHn/abBwODciguN4+ua+mRS1UWXxSJwds3x4G8XCiKz3DAtCoJNFxQQ7t+yNF7cSd03RfC6TltHHXBEXcmCIKn9RQ4e4do0c/n8LG9mi7ZF5M/jONJWpNwibM8nZG4yD9ODofnXyTxXMMRkq9ZiucKN+Fci7E4cnADfXotSXkiydhnux+GJZnDsuAMEoQyuhJ1D0+br6Vju3Vxzz4tdu+t5tR9XvDj42qqbVQGW70mdpqcAmd3LsXL7Y8pwUOY8lU/wbS+Ldw9qARf6nPZ77w0fOy6SGrvikDcP4R+xIjDt9B89r54BcJ3LsLcI5dg/LCNdNdUEjaMSeFHn/dB/9jhNHq+Lc2VUcRKn0gcs+kurHQKA1p/ipbvHgF2Y0vhxf0heGx9HaJv2cOsQ+fgppMS3n+wGC94v+KBsPk0M0YVLLMMgZa04elHUjB8yR6UwfmQv1QSxQzE6cQtB5II3A/udSIQn+mNh7wuoYH9EN/LkOJpexsoZpcvp5gk4vYbEzCivYyXLZQEy21CdKvelHZuFOaTGo+ovDwCvPT1+Oj5Qmo1WELb9n7jjnOCEJlcDy+i7TB+SxfvcHIjPwNh9uw3BDG7PvbacwieykmC9vRJ8Ev9DO9/wZD1ejjv6p3LyQsaqOXUJLpp9gn2WAZgyM8xHH1fB1QEJvP4pZepIPwPq++cwa7liTC3bB6tt/PBZ2npdFrGiWPU5cHEwx+Tcy/9m3Ercftb6K34iQcufILf+gks/uETmc/r5Kfeo6F4ywGyP9FHqXun0Ux/NzhaZ0oxyi2079p+mnVmJh+aVc/OoAvvNx2E87IM8yLv4uA4bxzf/gutNg9g5NNRFDXfgRt0FGjq3WFQM/4brdlZh717bFko1ReaP+fBAe9k8v5ejxqKRrDDzoZrJ0iDSmQ9xVQrwIn+cVSW/xEDGp3AZWQfbrWzhko5VfJtEKV8ey344F7LQtpHSWXJRSj5VUjGkwrRZdxJVljexxN1HGBd2wA4qonB5c0L4fhvTRSp3YRn3m0DeW0HuNNpA8pVD2Bm40OExEYQ3igICz4vwzmTWvhzVxj6Dh7DyW92c1n1flJdNI9Lam1B+NNLDEsRgOjRZfzrQTy2+/wg0a5d1ACpsKt3GgYtfAfPrIMxYWAU1hvKwAyBEGw3WsB+aj3UFPQfrni0DLTCNXGB6Uzsfjeaz/3qoVR7QXisZw/HsYB/V6binx2LMPBJIEQVqOF+/RPcvOgti0q9Ja1TCJ9PdnDRJRfKkJvPggfMcfcfL1Kv+cJn99nwRlDDpBJZVvm3z/WdL2HCmHrWoWL+tOEDzVO7yN2zQ7kpuJhWzT5KaVHxmCk1EQL6/1BwUw//2nKXfk6swBGeFnD14TIYMzWRNaoO46FCBeiZy/D9gDM5/xXGmwd3o4W3GDd2SbD+8UD+nIxQ9H0HjXkZy8q10rDxdBXHTDSDXN3bnCkfwTnPI9ktdyvBt/fcuPQCHC91JRhrBKvHOKLq3xOcIn0do5SleNYrQd65aRV/E8rCypVNfFPRA28MSEHPoiJS2GTCdu+UccHO1bhjYw/fi/8KMsurobl3C8aYNvFFZzm4VfaOrnsV0D11B3wt1ANzhoewe3crB0TZYsSiJHqZ+pZlVIaDc5E7LcxNg7ePHKlkzyFeH9BIozYNcM+s73zJqhKXr39FP9dqgLLEK7jQpcL/jb1GSw/l0VvXb3CyQ4AWn4hG61W3SHpHH91ulwFnVAThS9f/3fjfVHPbgSoF/+LbYCMcJZOFnlbheMXPHGJ7xCBELYecl2dwh7Elny4NxFn33PgHyVJJzUtYkxgAboJ+8FFeGOJv3MTyI9+xqzuOLlo1oaJrCC3/E0ldvpL0stsINz84yMfeyMK4/cX0SfQH3w43gZWrf9IRuQK87OGA2To/2Kd+Kfz3Vhk/CGtD2HY7DOvpYQ0FI9q6M5l+NPXhvYsVlD0+l1/6l1DfpYsUO3MSHBaPwkVL+6Eozx10bmhx6mFLOOIyC0+vL4NvToi6RQVw6MgoOD1vFPWaXafni/5h2+V4yBKKov8+B+Bqxcd4UXEBv7O7gAtSlEDs6kO2MNgA6rKL2StrE7p7H+frMS2wdacK2r0ShuzqaDx/wRTyJi3mnIN1oO1dg+I97XDk80YYkzyLlkdXgqv3MRr4soSPxOmBSn4wvI/3ohibLfRELow/ainS8MKtAEP70DBnEzzoH6QiIQGYoZRGZ9c+4qnLhOHF27lc+mQ5lpT1wX9zRtGyEFHS2NLIzunmYCbbTFuWytHI5asgQ34OyOsKQ/LaldzlfALKl43CZyNvsN0vU5jl7sgJKlb4oq0fjhxqZO57x/rZ5iw9Zi+t721CydnFtDBwOrTamJH0dyNYUSeNBqWzeOrvSHhTfZ0n9qjhHcUjVGVmBhqvBUHA3RSG7bcn+HuP22b24dzVQmBW/g31zYr4ybN+8D5/AHLTDEBw+US4KeHAe0+twlfDN/OZ9xt49tgcUnxZgnsWakGiciyv1BCCoKfzUfvjMuhfMIatHPtJcNob6rj0i5ojRNlgDsIEwd3knqEB5l9v47W4jdhgDuhcIwVTLmlBU/0bzKg5x9WyCjT2qgFZPZ8GltyFobnL4a++E3k0tuG6fV18bG4WifUWcsD1mSCxfjUXrdeFZyq7cFVFLt1uVMFIR0cISagDC5cFfGzec8hReQ36u90gSUgDBJavxMBPQ5D9ohZ3qFXgwPYOHjbrKP9KLafDz2X55ca1+EdmHGyfn4vhzhp4ST2R55XdxL/u83layDkyPbyG/RY9o+YBcfzsLwmq9yrRdXIHX7CfD5Mf7oG+nRP46fqHIDG2CdoOfCKxUCvWsVUFz8spOFlNiHYabqCAodH8d8RtuPdyPiwb20yrQAPvagXxx7O6UFULfC+7FFfNLOJVrX/o/vcG0uOROKHTAFLcMvjA/BX45tBY2CTmAK7bbLC9uwpMHEZCyYtGPHhsFf84KA1eYz/Cnspaor0I8VkK4FZmya63tsPJRaNo+n3GS1X3cWFqDbx/eJzvZlzhRccRjAvtec45Z84waeOciwcwommQ/zu9H9o3O5BJ6FtwHOEPKv/ye0QujtJT7Mja7BZP69PmPmNdOhazmQo33wOh6Z/5RtscLq0dD2v4N4o/uURhXi38LLsZy1+4gfjbSwAaJ+jwAROKqA6BtiP6MHlCL2bmrGTTwav/uCMB1zrJ0iIpJzpb3sCfm0bzjNhDfGnUdCgMD0XZJV48Rug2Fm5WAsODgVA3VpryBc6gWU0ElXoehtT7anDYsxra0wkobBq4RDnCfR9tirpojGOdn+KRkpPwYq8CP/6rBLMPXMVzPx7D2x+LMWhXO8f0dNNNU8Y37SvxmrUnD54zZpMMOajJDCRY1QliX6fgrw2jeOe4faw8twWKXb6A7e+vHBubTDM9CDLT11Ps9l7KKTqDzvNHwcL4y2CeXYs/H9/jUTeSaZPhe/iRAJA5bg1aCvbitGJPpPs2vP7dBHRLX8Duc06gmZM+iVXdo3MaFtAfUsMWQu086sIXWqV+H7y7rDh/IJw13xuAjWs6DSy1Qu1ggiizbP74sIBFBCJogYwCbuuKgfJYWXb4bx2IfWjE5T8EOK1jPMTLN6CacyLuUdAB44ZBVH49naKaszl0ijBF1PWRoe8oEr2oB4Upe1ir+T1Me+SKJyYrs3HXfWw5NhaEynMwocKAx7Qc4Gm6OqDxrBW06k5zKrvCd94FWzXEeGNaJ4ad/UOh5W5g3XyKzJsEITWmB2ct+scUN9Tg8T9nFR9YAm4Ll1Jm5Ue0/CkEUamvoLpVDqK+yOOMrkgqzozGistpcOmUNHp+PEtmfxXxr1kTd3b2sudOE5DcFUe0SYVk44i/qX9iw9YcLl4ujU8yD8D1Bacxy3wkR++XBaMGVXwRcAC4E8BAzoolTZNpxq4U2nK+lfYfjSD3jyYsNNkIqiviQXbnbxx4WU711vdRS3wDzDDfw8MK3OnRmI1cdboV5x2Ugu8O4SC36xzvWZHJXknh9HzYKGhpv46HDutRaFkRPNNywag9w0HHUwI9P1yjo7SKbJ2jqCSjAt3cGmnQtJb6v7xiK9tlKJskDr8WHqCpl01pXPwSGOHlhEF5thwxspsGLbfxg5RyUFMcgroGfTAo2c9zhDdjY6wkBOf6kcugKPRSKFxdV0vquWrooVWBeuNVYN9HRfK8eJ5PPk1me2ML5LfZ5Gj2ncuCcjh252TYIaVFC1KlYIvQVJB5+BTffdsIlgVWOBOk4f3JWAovf4hJOxWoS88O5qMeRHtVsaz+Ybpb9xhn/7TAlQ/EaKeKHL7eocaP5muQgJ88/VAYDZ99zcCk8gxUyeiz3uYOgLJnPK1zCe99P5+vHLEmFklj++wxcOq1ENx985EOb23GtLpKLLNahePWuUDxIRNwearG+SeGcL2INtyvuc5WyUpkeOgzn7h3mGlJGa4dKQWLJibQTgNXst56EJaHasDhmr1wRuopJ7cPUc++ClBadwrG0Ub+Jm6MH+zmwSPxt5RmqQvtqp544tFE1Ov8RoYrLSFl/WNI/TQd3Q/fhCC7FnpnZUa/7ptB8jVRMjIOokoYIHPDmRy27jMdSdTB70tL+EpFIbS27cLucSPA3ec0zxuTyL6OQ+wi2sMzXXUgVmkh7N3USz2nqyEl3w2rJyuA8fYUVmgchddHGoK7pSp2xjlQXWAaBM5YiKeOJ6P9iyh+c8YIqko/QsvjbhZ/KQEFmR+JJhlA6N8XaL7bGFp+uIN57gI6pCUIVQsGMTCROW/mQtwUsoI/dM8DVc0pJPq4n9QW/EDvAxtp+HMtmD97C7+2S8fEbis4VaMCjz5E4Ea9RWTu9JOrc+P4U40YS4WLwEyjY3TS25FETRazj/lTVI4MpnWPmGFRJjxUb6QSr3Wc1TASBuOcebYSwMAdW26qPQOTdk0l2auxoGn5FdOTEinJ3ZCT40wg+8wsbB71kvrMq0D+uhLPVZ1GSyb8BOWCYZx/cTX8Fj8CUW9kYHNkKUStWMjfWi6jp7seFolNZJufdVx9tYszNnvzB7MF8LlCHm7vEID/BM/w+tXFWBWhyWOdtnDUvizqm9/I/Utz8dkXa8yL1oK6QWkWu9WLEZKx+LxAHA7pjsOun4sx1LUNpsXe4CKxHLa4Mw0yQv5S2MNo/Idi8PBzEnfYq4OHlAy+mRaNK21f0sXxEiASMA4ad9+hl0rufOR0Lnh6rIYzGa68bFolSHZeB/jiTJJaP/HKN0XI+TwDXvzjikazev76zorfyTFlTK+glK0TWaXvN4TbaOEbCzEo8n4E0ku2wjU/W5TLXE/d1weh3Tcb3C+mkNqGR3Qi9wKl60vA1M8KnGOYBBJqjbBH3QvTT/mwcdV6WO35hhobxvKO58tIKk4bDkWtQMf93qS34DpvUvuLR4ecYYtSPVzK20IyuwL48rjj0DleAP4KpeLBIH/aE36EhEME+OgiYVAAUdpU3U/W80PpSOoUCk3QhAXjAcz1r1Jn8FHcc20rvxtMJNel9yjhjjXETSnlq0/j2ah4BBxKiiPd+AEa8zEKx24cBU41c+Gi3FketaoU7pS9R53qBI70GQcmN++C1ZgeGpOhQJ9ybuCCVX2Q8OMDStV/pckR8ezzdAXddleHQoMCHhO+AlfcDEeHoQn01c2WFk8vg/qn89DmSQVKvFCFsU7mkH3HEb+sn0Nj43pIcoY7jvskyDLRImxxpIW8giZT+7A/rJQxHgal1vOW/QcwqyqGTjq64SzvMjzf2s4SF6aw8+oHIHzEFbeIWoDq5QOs5a2Mnc7DMKJvGY1IrMH8wDm4d/Z5/KmdznZTCtj+giAc9J/Il6Xv0ubKYyzk/Jr/K75NYT9qWWWsOMhq1kGEQBW27PzHZKPV2FrpEh6wmQnGW4xJzCEWh0lfp9kDe6mpXZ1apHwxTH0K3Jk/jKN0wuFJnw9ab1oL1jfNKQFMeevR1zwn3JM19VrhVp8x1Gjn8vAp5fT97yGYcViT5HsLqLpUn2c+W4P+/qtw4f0XoDtyFGyOnkh3g7bBbV0rtJP6zvZ/vmGragp68C4qHDGZ9pSKwKuOyeDUcJF7NkSBoP4DbFYK5sbpnSz5YCt4V8TQ18pciDA4xO/iR0NfggRGPHxDP8LP08/sl6QwXRiGb4mjBXuWc/GpUppiv5Im55oDbFXncY+HaM+7BXywbBPPK87hs1preN5HWzxysBCnvFwA397Iw2YVPzC5I4Xpka5sIp0PO0rLoH1vGBbdPE0Cydm438iJU40VoKP1PqzdZ8+3h5bSmQiGXxSOc78v4Mq4QRw+6ipkO56k8inicPFFOk5KzCY78dkU+M4NdzbdoK1XrTgidDwszkykltRB8leVh29fMlh59wxI+dlATjkXYcB4Hlb4l0GJqiFb7/pDx8dEs0KFPpyduxYsckehk14AbzvTwdpNN7F/3CWcff8/cH/+hQTRH95WT4Q/HfdJv9UGmtRG0uegHtrS/YfvmV7ArV/66bPjJvZ+85maLceCg5oILD5vzU2bjkGjSiV9T5DkWVa/aJL6Vla7nwFnVx7CifnDwLd7DgreEoOb8XvIOSKND3uao7qbILydXA+Vf9rwyXAlEF+lAxdGf6Fwu8UkKDCNm0U/sNGnMgj/LkidW6+Cft4jVF6YzpKB6lCyMYM/r54NXwU+4qejhnhxVQXLbL9Kwcc+soXAPXCL+sS+ciowtXADLTpzDF9JGNK9bzFg+egTJIVc5CfjBrkwWIDvT3FA371mcPlmN9gtfMgjN08k/D4MJxrdY/20HLr5S4vnhzrhYvn56BkkB7sNzkHN73twzasXG57WUa6jOX2dvpeW6WqhStdhUrZ9Q7a7hcHqgiQob50ERxe74AYXO1o5SxHfiebw18RCGD9bBSeM/8zvtLVgwk1RftHQyv3Vj3G4ahw/ytuKb41MoFHzAJssLKPjl5dS3Ed5qPZ1wK8HCvBtsC3UbZBm8f4i9u3woMV/1vLsL/cxXWk+ztxvCq8813KR5UzYNKsQ7s6xhldTqijxeSycjp1AN7IiKE1gG9icHA5L1PbTwmkSsFNTHdXnfiKp16Ws2nKUd4p4Q+PXuaCVeh+fJ+rBkcfj4fXIn1ji8Q2bxf5lbNgJjtm6Es8UBXPqrlvgNbsNNvyVhpMiQZi/NA5cNvbjmjuK9PluNX0wegN5+wG3F4WCzHYB+LNeH1rmLoPUlXVwZ7CWys+vpu1+UqycFsarO4tAqtCYkm9sY1kLOfCfcRkiUtK5I8QaHhxw5IM3CkDHdBpPuP0O5NzPYtLsJ6AxXBhWLK4H/a0zceb5SaQIetTwoQi2XVbkR6bi8GToEDXcEuYtd6bCPtlj+Og/OTSXVeIxfz/Drpp61j6B4KKfhQ1/LpL/pUa49HwCSJT/ob7mMTT3jhHnHbgOC46cwb/zT7HU3SCYkpQJpdUeOM9BFRJq+njznyV86Ew3PJzgCFZurWxms4VbJVppae9wHpqpSyuHCLbZi9CHzCmkL5EOpb5+ZBilCpav1jIVNoNxxHwYX6YGDwJE4LlkBmf/DkL9iGCc9PgGwAcxbOjdSd9OuZHsnNlQE7oOGm4qg/iUbxifEY0id0PYbusKSugbT/8FRvKqZ/3YlnWKcue0wOcHShDxKoUqO55gYtBZtp12met/zeLc8mf48+pNMl7MGFyJlDxZCUqe3Af5JFv0nxUJtwpH017Zi7glu4i0bzjgoS1t7Dq+D3dfHQZeH9Xh7aO93KrnBNtkrKA59AXqS9egx+9M2FH3gP1nStDQ+hHw5m82TwzZw6XagriregNq7nsNq3wVKXqHOdxrnkSfLotDR5kMKCV9AxeDCZBTbsgbIpl09y2Ccy1dVFa/AkvcD5LjI3OaPsEMmtd3cYeqBslrR2CSgAe6lNSC9HEF+C+yni3XPsUly6zwQMUwKEd/DFsYC9/+8+PjHvUc6Z9D+lNFeapOOpWdrKestibsuikHEQFmYPeknrfMuwmjRzEq5r6EL6qjKCsth0fs30gpi20gIpNh33+d6BN1B0eN0+CJeybj6YuHoT5nNcU3/QcOl1R5Vf9xOODNIKWfxKvFJmOTkgiXqIyEyjYBDhdbCHVendA9J5AvNnbg7ZHq0OLhRecf3efA234gfCEOeTIC/OOaJemr8fGbvbgqPYQPTDUHC/NTHHtkEJoU0iHLYD3MXLiDJ08pBuf6Clx16Rv3FM/Ge2rDQFN0DgWt64ZGw3B+cKWMlhZkUaf8IZ4rZI+07QDmRdnCfAcFmL7Shf70DUe7MkWe636Z1waakKp5PLabSMBM9GMjH08c3TQdfq5dhNmHdSHfMpTfx9RjdHcErWi8C++bo0Cg6zL5b9PC448mgNDK76xbEAAFGX85udoSuzGHbWdUwLrlfjjfrwyOhCnxl6uasG7xO9p9uhxjd4XgPok4nnj0M627vRsrBJvYJOQ0TXFIgFYNeWjxq/zX/4s5YZ88vS1eCmcXvkbvvC/cWFCHTlafqPb0QZq6/p8DypRz6OYguDQnAqZb/QDtaQthlecGsEoPxZ2HhnFCVyMX5YpAyTNl+jBrAoTat9Lzg+ZsteAL+EaK4jeHZq7M64CTc6oguJKgdVIrPAo/D5pROiyeasMtE67ThGxp8B3cwUcWnoBdlXEgjprQOKCJCQticCD6A9ce0OQXtyp5lcxG8K0wRWWb/4k7z38g3//9v4ZNyiiF7IxsQpIV7RKlJGQkDVGKSkkqikS9tYumGUoUEqVNZRQiUamUNKy25Ofz+ye+N65b143zOh/X6ziO53Hjus5SJsPP+K18JJgLq2PElR+4tTqbok5k0crwKJzjEoKfOueDZ9FCyraLg8wUWRBueAHn9MbQPJ+7bGa8g/JrzmJYhSb3z1Xlwe9+lKv0AbQ/GUD78w+4dbUtVtTm8G1NK1oSfoDHulqSYoAB9P6K4bH2xpw1RgB0O++y6MMyErwwCc4OvwhTt57AcSVukPjACdUuOfLKFkk02E6w3ek2ihdG4RaRzxzisY0mzSF8YHMaBBoH2fmCOCp0tWGs4mgwfH2OxVLu07uIZ4jit7HstBJttAzA1pokalQP5pDyYM7cOhmWXfZEqRPPud95P0jJ9JC393X4NTECP+pGgNzuC7Cl6z37B0nDSafboJx0B2a2f+KLwrc5o20av15dx9FPXXCFwgpKnGPC7/T0YJ1lJbh8iiXZqTZkeXURpZ2TgjdeChQl3UQeWpWkvHMcDZyUArW9naQSch8uGbyCzvY/qJOSyWffuPAu+wAU1DXCAMNR1DtaE+zfnqKsyBDsCd5PC2uEEfetAPPna+jum1uw/uE3PFg5G5YVysIrLx06ndiF7RvGw+fpr6HkijQMbjXBoP3R+LgxjEfsEOe8aAso7tGDhYeeYWL4O/y8PIO67t4GX68aNCpMB+u9faTwr5RCnllCZughmDRmMTmliUMdz0Bfm60UGd2FhlMVSFr0HUoaHiTVJkGILRkPtYI1nJxfRcZpCrz+ZT2GfPXAJbMjyDhLnHOVItDl7nA4KP0frV+4E7HGD2fJ/aE/WRdJcc0uNp1UgnsmasPoECv6t9IQ4kZ3sXjscs5RySbnT4vwwOUPmPFnNOeZTeCm1hPgrWXB9kcmApp8Qf3UfBAJ1aMHj6bBzX+S7G+8A09vFONgcSGupVV4ol0C3MN2UuyVt/BvfyzMq5uPiWfjICYzHUM64kj0Thr/PpYBecWSkJp9hLJ9Z1O5ngaMOnYeynZOQWm5QIo5o0xh09vIebotVydbgtmSULbPl6Wo5DUgd12Vm38MB7veW7yor5SPx7lySmM3h+4c4mLTE+g9bSnWTXqEuxOcQKFgBC5SX0sOc02ZQhM5a4sr+wYbgqFJE4+44QkZzOy+wQDnzhoGbwcGYMSwatrT30pmpd9p0iYBSJoZR7YhmuB+bjYFRa+hLHN/mHNZhSMDUyHyXgenKY7ANx0WcK6nha5M2M6HLKU5QO0Sr3MJ5wWOZly8YyOe6NhNFyvK4XyCFvRe/8B0qAdLfpZAr6Mef/5xkBZfS4Lh1+Xg6o0SXDLrLIfZi0H5pQY+HT0RN29y5UPXZdj09D0O8ltJUd9L4cPOv3g9/Ss2pImBlYYmz80OxI2iiWCxqgqO+MXx5U/Xee6YFzD2zG5QXfIVC2XkoSjfgNJEbbnBvQOfDpPgfNvlFHrSh7K3uuD9s7cgLUIXxx8Qh2lHTPjqekdyMhZHo8RWzquP4aC5/ZQ6/A81e8rQ0cY+fLl2Inw2286rhL5zx3/taLz1MQxIK5FtcBUHCyyiMcse863GXFCWsASjpb9p3e/9/NJSio4peXKX1zIY9P5MswMkKUF4Gfjr1HDIIgFI3/GQpvgsIyOBUlodlU8PnhI3rG3n6hWz4GhGB77weYPbMyVh28l21FXoxrsfkrGm8g8EDfPkmFZD3tbtgwdfWNEwsQjIHuq1cpfsaVqLPNaEr6YXl9agjqgAqdzbSd/ijvKKtGyWvTuVjrSPg4yiDggvssZc/3esWzcZfUQqaWvaQvro7IteF1/DIt9drBunBplPDlDk/RqKUN1DErf/cETUOnog+BF2t7zDeW9dYZKoHR46og7qkVM41a4D70UfxMx/V/hIz5sh7ipm10uVmDdPDcvHSYLwVjMoO38MWtXDUeIxU1yeMniOFoX/CqohMrWVA6cn8dGso2RwShlu+D2GB8bV8HS6G5w+2s1dkvuQmgPAsTcAxGYIw4K6GPqqPhZGByBYOrahs0cTRPbn4ulMggUxL9invBPeiK6jRy6ENckIVbNv8aGoZhyua80HJZrJW9aHZ91rxVTjbeB3JYflDizkmy8s4ZFiAWXl/SQjmTdQ4XEX5la6QNTLNmqQDmMfw0JYIbHr/59f9s6ufch7ZOHn4FhIeK2DudNOYJjiTJCzM+TFattooHaoXw/YwIzH71no6kWKG+4O9rt28EqRY3z/lTS5FJ+HjK96nBT7j5WyjCEwzAWU1ydhh4w+PJb1gw9nw1B4QwD1T1HAVWZ20JUtQhg0EbziZUHqkDOd7I/CKQVjaGBiCfdtyaMN5ceQpY3o0qV+qkrRgwmvp8AMyIYQg+3wHCR4556H+NzxAZ9K6YWSWS6wNkKVUsMmQYr7K/queYRNDiyAfscxOEbiB1mtHcXOWx/xhkwnFLq2jCZeEoCmQx7QsfgRzTL0hsyeCqycrYw/VxvyefvNfO1VJ/cP6clM3QK+FBTQev8AvPS6k7rfjMeQRFti3kqX9yXjTLNWXqI5kt7WGsKbiB2Q5/AVJSTfknJEKQRmatIMV23Sj/+OboaFXPP1AUUvl4aVmybhlxZfrrlUjsr6sXBtgRC8U5SFD4ca0dNiEVb+0obrQ/sQ/17IVUl5UFT1i4o01sL5gctk4t2PdklpOKw8CAIcOkBsrTx8FGA+KmIHOa3V8MT4NM1Pv0fziuXwuGcyuIUb88jBBTz6ozjkLgimPx+6aGNPLJYnVkKUnRfhMGGMOenFW06PZYf+9WwQrw8clc+DkTmIqsvhqs9VzMx1R5t/QCvdbDD/hB76blADkaVj4OuvBfBR+SvtrhpN+3eU89Mfs/l4vRYsW3+Fb+U6sbmbKI2vEoPAFwbY/aIUO0zEYbvaH1w37TsYxFiRrfVUdloThX0TjoHBDX2Ay6u49dIa2HfxGCwUkuUXpUlwcmkE6JyZhWZWASDlGEvXFOUh2+8vjJaIY133LB6elQvzzCVB9NUs2m4+HK8fVqS9NQVYVDyU57muWMTTKS8+CdwL3zC/FwLaMwcW3T+PUl3C6D8oi+MOAhyWP8Dadg+h3quKQmtE+Tz7YoRuIA9TnQIvL2bQm+m5vNlEDgQke7h7sgV31xwDC/Ne1Jx0BDeb7eHmT8eh7dA6mHPrKCk+Noebjw9ggHs0Kcq4wQQJRaq+WkIT1xL+qJUnrT0zaOBPMAc/GQ2HFHaR0ojTeHBoj2Kpw7CANDhedg4ukdODM1fmQa1NJDfU64KC/nv4GDqf7tUdBuWuVLp72gFqR8ej/jgnVF/PcO9sHpZPGAbVZ3N4sDoTniz5D1a5xnOX2GVKvP8DP15ah4cDk0Bj+UfYbCMAc68jpFQK4IH6If1W/sZYFEPBz8N55nxBCmh2BPGlZazbqgXvDs0mh7AoMi3MxTDJArBVlgTxjYwfG26SdO5yFjn8EmcvMgP3QQNUfxRAqpvfw8PiT3AsIZgKvtiChsdkEDh0C443+UD8g8nQf8SOPHa6UNb9TRwrHssSvt/gWMhR0M75Be6TWuGqzjtye2cOtQ+jWGLwITpMWw6en77Q8O9isGGTNSdcGUszrg1g4Md4rpyqCZIGFtQg/pBmOvbi0ld6sOteIv2cYQKqUvn0rkwKPhQshvZ9sjCydAnkHW1FLRVtzN06DObNH88tPwWpoNSM7Psew41VMpxoPRnOGCEL2ZhDv8gU/LX+EjnVTgYTVXXYsfAoaouegIwxgXzW0gpWz8jn8Mfn4L8OCX60dxS+tFsM9069JIuEaLb6NQOvlTrjsSBxeLBDYigfr3PingYM7dAE7R5Hbkq4CHeDGsDr6Wpyc6mkWcukAGa/ZZWHaaDmsQhKvE/isGW65NpvQRML8zlgyx0SNakk82+ysCp/CnirWPPr342s8XIORzrlYebFnXTZ9iZaJarCF+kSMuqWgP8e9VOgni8c/jCTDC/Ph5l+RqwwopAfBoZSckcOTF0bz6Zy0tDtKoZnDKfB2pP95PLqBj+YvoJLKwqxsT+QVn5dTTJ9D0nS1xLGKs3kzbXTQP5ZMpqP04f2zc2QyxV4Q60Zspp/8xbJQgxuUgV54VBYsM8KDHPf4t6Pn9nuiBDbi1yCNpHhuO/3JRwlUEtuR82hze0kCg48Q/GFQfwypw3ve7WAsYIimdp/RadJ0jjL5hNkvFCDS04p/CBfD+7O+QHPn3fA6WmnQWNjBt9OH1rrtByPHbsV8opsofBFLSeGWUCghhAGix+GDboKvGLEH6zWeUE3t2+jfWVb2HKZPsw7vIPGpqXSeDVjlD2zlu/82c6bx2txtq0WtmoGg9SyH3xygiooDF2HEt1wsOEjqJYGo6T5ahyu+ZH3R87GM21X4NqrdqwImgDC0yZA+Dlp+BN4i4FHQZxYI8QP2wGHXl1nN50AsH28ge7OmAzrljSzwF5b7DJuALusqzCgdx1aTvujfPwbyg1+Rt7mxYjbRUGgehI7j6nC3+4B9O/WBbg+0og+OSvytKIecD/7no+ubgdzDWXod27krodPadqfENTYYUNnyqOxRuo76Wgc4CVCvaAu403zv44HsXxHrO3VJeVd81C/9iaZWgVixZY+KhnaV59xLWZ6qEPDfkHw1PoBefnnuc50Ap0cUQU7W7xwfcNVzJgwnZ48EqcftsJwabca1D1rxrD7w3myyABsTdClH+NrUdbKF87djcLUpIUYfaiUJ9+zAjPPJeA+4R8VxDiQZ9dveuLXR6O6x3J82ncUT7ZHNa0dvDwY4azLbVY/dJJjCuwgSuYm7Hr4FszPKaKNmiEXLZzM4tHPoUZFCgRHHMewudpwY08O5Dq0w7c5H2CNfiSNufuID2lMxdov2iBqpQZfPwlB9fujqBtaCodF9rHLjq2kqVoHp+ab0qJcG7oV9YX0hCaA2bE4SJnZAQZxwbC+dQ7O27CTZNeO5VcvjmBR+DnWOu1Luz8A7HmD5KQgQ9pWSnhPYSZ5a+xiydAAcJIvY8vnh2i1+S1attEa6iqncaoAomd3Fz91eYzLckYQKD7j50uHWNBDFZ+mLMYjqsJgcWwcFRWl01KpRzx7hxX4/5cL6bUTuE8gHt/mSWODkgBWiOrAm2HHWG7JAzy1JYQkrQ7Q2cmipL7xCzdonYTOUdX48eMnile0hGvf3sPhy6PYtVcfAtKtqSp6I9zJEKDTm6rII0MbTZ++4SeeFqDd+omLLwawlVs0eV/rpT8++bjI+BhHaWwB3+vW9MnPE253CEK9qB8cm9QGNtHJ/NbqCC5bNtRFhU1IY9xT/K95CfclHMe2YimwVLzNFyaMo+WutbC1PJIPnFiPK411MOJYLEjUlLK5xnHqDFUA5y/7ULJEHvMcxvNZa3tuqJXkqi/vOKztKHaENrKTsTqfADW463EJ+kM0UfO3M4/LOYALVMvJe8tlPqBURSVRaQBGCtgeqg53R1/kMEvmmH2m/FN1Gp8cnAZnbp6Cq71t4OJSzt5t4bC/Vwm+N8xki9BymJL8itYWn6QxIWfhoM9JiOk4AKcFI1idpkOJpjwMzHFiTd9uttv8HDdGvIaR1dG0tj6Xn8TV05VzVnThexHuWy0Ns8wOQE3MRtg54RaVf2ome/lqaA3+wW7ecjDdZjuaBobw1gRrmNrfwzELl+AYDgS3MZpcsWMuatal04eAVljTM3JIL3vJ96k0KEt70p1l+7DnsToNlGwAmf3D+M7+LywnY8Rfb+rQldeTcfINgh0fJCgs14QlFE5A5lygN6IbuGm8BEwR7sQr4ERZSqt57C8ZcO13R8m/8dxfvYWOOO/DdcnX2EJzEoSdkSB9auGf30dQ9AQdGBEQTlkVb/CP50yg5Yvx4pJe0FSYi2f879B50yvYKzKIm3WN4e+/AzjeIof/iL6jBevfUfu6Wn58+glXL53K79JG4fFfmnQmdQJMHGMNX4pa6PKMsXg5dh6udczhyhozTFlfAFOHm3LZnPlsFicO75tFQUv/L+SX2rDd72SYK70Z/y5LYOG9kSDu2weH5vWyvJsV6Aye4NLwVXCs/grMTV0I017FsMHyU2Tx1p7bDf24QuQ77T6tAtc9zg31+CBaMV2S82p3glfNK1Cv2YT2nkH84Zw+jHJczf31tvC8ZTl8+G82FNX/5NPPG/nUvGrobZrOxVZ7IHV0I00dPht0bCbAf5N6wVVvHN2qamXjxA3gfUuVPwwGUmHWHphmPQus7iSD02MZsKZ6fFr2C98u/EI6//z5gew4Cm0zJq/wSLqlvgPs841xy2VLaJTeAqviF+OyrcnoWViFXuuCsW6xJ/yNnAol8ZqY/2AKNr0bB9HF8lj58h+7Cm5m55tfwXpZMKd96cAcrx4Ulsxj0SAn+jbLAM71mPOe768479NZbFiijoMhq1DNwBl3SjzllRmBwEeG/DJKDRI39MNqV2V4vraUlka70sAhF9a/QSQ7wgB7hRwgRzKRHA9NAr+lNaTjdAjmRelj+qRj8HdaMJtd76UVI+Ig6T9fdj20ie5c1QJ45sRqm36Q1LsiAt21dNomhFX8+2i/mgJLxe3jm1KfeFijHpyFc/C7fDqY/LeUog0mc2V0LXxZfp+WLMggn5mqIHtWDkwmioOR5UZeyC/YnteT0Zhozizo4BmnC9EGTMFYKolC0gJRxWsidEa+xOyejfT2ylJ03bcPzER08Mb6FnJKz6Pq/vMY0mCLwzarg5JZBMvNv4+3Ps3j+MwLZHvhA5weVQNVThtxVaMEz8v3pLouEeidlsMn9/0GyxM7oa6hAWti/blyTD6KrI2Fgd1qXKb4l/tfaYLpYUFe7eKOa70XkPHENfhPTgXLrDy4cdJ5/neziiN95Sn7vCk4eXTihgt1sNrfAWbEbAOF0eLkUPwDRm+whtPd91F3/i8anTgO+udfwuKBajqESrhmryMusbmOy5wn057lNrjjkS/zwFvO958MJfs0MbTdBieIPMI9U0qh8WYr92pZ07FtXuCweBWWf5ZCQTtR8A3bx5cetFPa7cuUAI9oqYEraMlqcnX/BRgQ2MhJAZ9xZ+AEGGW1m45VOMBxsVaY0p5A5ooeHCVWT3c19fC0lg3MLI7Bex1yIOwzicf7uuBfxxDoFlqGqu/k2Egwgybpb6cZaTtpvnUeaQuNALMdo/nfpRK6nWZDuQtO8YM7aXDeOpM3HFLGUZ2j2WCOKc46oABr51yBf+35WGy1F25NyuVNBaK0QdUFHmg/peElc0g6bjJd+jwWNuv+pQqN6/gq+xMHayFeq31Knma7SUxiIpRvkKSXv19y4W9puPDUjioe6sLP5dUs63+DnEsSqdBYHkvPpcOxJ7twdN9tDh4hDGrhW2H0pMXE6AqTRELAfqQTRi2KYY/N9bBi4m9QfZhLU3epw4YLa+DIYw/YKnUPE/tU8dxGQXo26T9eoNLNun7f8H5eGg1uFwD5TiWUnZ6IPrfESfT6dsKTaTRj1Fous1DmSTsRjkiuwunVSuD1PZvXm7zlbZanWMmBKNc2gEQchTjnVQCUXrzDp80TudZAGZI/H2T+CdyfMQ2uDXXQi/MHOeBfKY5zsEClQ8pQ6e3M11RN4ajkX/AYera20G9w3X08fC+t41NNqyB9SCurS/pR41wcJbgOcfuc2dBd/QuqlefS5d/++HTyG7Ltuc7jb66EZcmGvPX0Zsx8YQbbukdx1ocFVDimgPdkG/HBgxf58KA46K9ZxRXHLWnND3f8ZmEOP5xt4dwOfZa9PYX4xxhKst6Pzy51U8UtdVyeWIIfa5dh2qxh8FjXHh8VzOSpoYKc1DkBlyafwQblclzzTo7S1wSwqmIyaxydDAX/2fG8sUjPO0byFDl/at24A4pq55BDdB1nPCoCpWPzOfyAHMSM+sCWnXNIdbIMzFTZB6GPEvhQWiqfCrjHml7DwH9LGqeLysPLKbFs+Hc7RPmKs3Ddesx5MggqDyK4b5Q9utFd1FG9CX1vFMD39Uyun0YU8qsBB0J2sOrbGyy51QcEvthys+lSiD6+hrqsJMD70nNo267H6ct30dcPpRx+9AbOXrAIc5snU//UGnYQE6NCbUnoau7mgdh0Ontehx4emMTiFyyo69tdGrn/HfasrIUujRmQoqsLSds28MQr7qjdU0C3zqrDf5KlFG3RSudeusHBb0qwvPA5PEyXg854Z7y81Jlr3H9wq+Y1eiDQBU01ybilpo8SfG6jg/Zumq42CbZUrOZLagV4JC6XHCbu5EA1cbAffpzG35Nit12plKYljKNn6MN31OZ/ZT8ofkcuf13+iuqunx7y4u80b900zDvyB6qSxpHSG1EIrE8myR/XsbTCl4dpNLFmwgY6PHsXFd2dCdkpoghKrVA8TRecSwT5tMhWdvKZjqtnJEFSliDF1xvDhJ4AuOe0gbaIWQ1pehw0ysTRHPcM9LOzYomre2GC20Ka2jifUwoLKVzSCP5lrubwP6Kw58cxPjQ8hF8E9ePj7nk0rGcm+uaag7i3GjuO2c7r1gnT9S364JEJnL35I8i/GyBrrUy2H23LFY3aEP9YBJuHqfBSEXt6HW0IsxcO44KNleS0qhN+eZRAlvRrOFwsDStTH1KQ+R/Y6faLJMVNIbcsjb52J8CUQGvQi7iDf6KaYZ36SZj4xhcKvhjTsG8CNDxmDBgVy9GN4moAlOHpOfV4dfUCnN7kQ7YbrmLk2w7adb6MfG5YwxjlkVCcYgfVmndR2fMbtUlno92ZbagzkajoiS5N+OwDBVFSoJx+H6eGToHmIntovdyCA8r96P+pn0q3H4adKvv5SU8VbK0ZBVviLnFnQjqda7vPV4e/A/NWA3rxW4OmDCaiudAOXpBtj+KJUmB4fCv33Z7KTxr1sb2wGLbQNdDc2IjT7arpqNx1SjltQG9UNGCSqDEtsZuGj59fhfuBQXTSywBSFARRK7sTLQt96bSROF31tYEJeztIPmcfhY7og41vNMFaYC46DYvjprZeWiTZTFcH3Sh/jxyURW/hsR0ZlFSby/llFrwwTBIldz3Dv42reNt5Td4ZtQjX61hB58x6ODhzIr40NoCXqWfwpr4vCLr1077Yz7DXfzN7zG3HWz/UYDfOIP9JSeRTLE++4ntpnNsq6v0TiZFGufj+mjG6tZ7AX24SkCy9mbK2/UL1pyNohm8Jv606DOu3JsPiFY9wc+FbPigTQFvvEmy7uAXz/e3JUlAM73TewpZgImx3p2EjF3LkwHnMNBKFlwkC8PGmIvbqbMAHT8uYtvzG2n0JKPjoHLSOFIFu81CyfLKXk09Kwb72/+iCszaJ9odzs/Zomh88Aed5HiCfuc85an8H7D4kw3FZorDFayY8/zsXR4zUg0gNRbr7qRNnatzl64f6QK7rBClvUuG/OVqwb1sF5rYHcPvCWXzGJxobbp0CFZ9kLs+PxWC7LB43vIf7pVShImk1fXioTS5x73F39yoOPDNAv6Z2Uv/6dHh5ogRa79vj0ttDa3XsQbvFkVhntIm2+8USWUtSjc5FvpsUTU670mj68feo22IGgjUJoJmug/tn+NG82MX8oDGFQj8cpR5/fV5oJ8QbstXYoVMXlpq9YQibxysVNlFbozisnr6UbfKicd2jTNJc4IT/nn1GzUsqcOxXLek5rqW2mk0wmK4KE/NO4L2iXp75LYKlGzLJvyCSbofLwXK99yQv5QY4ZR5IT1eAm09OwvopSKMs/sPj65zZyjSChl2SgW0Zhyl272fQV1pEtmM9eFvPCty2ox4TNz0lC9sPFFQ/mxVahEBQ2JQlnjnRlHZJXPL4AstGWEPZYhWYNGMfPgypJKGc0yDeZwimz3/j8e2S7DXE7vvSPlFs6kvsGWdMFWKDVLewh0UvzMBW0bHw7t1KStM+SMOaY1ipqhBT5N7CyohmFHtVxmm/lXmO6Slo/SQHR23ewV4nF860/Ux7Jk+kU0Gzoa06GPN9HeBU311O6v+J1/VkYMnceL6zSJt9ErXBYbgNJU8uQc9ge36rrcB50hdgzJhxoFqvCdenaqDBo1Xku+sSTbjxiuIbV0NSlDhGUhsVa2rQ1PgFdFFLFKwsPbnZOBXjhQtZ+qQask8LBDwtx/WDkzmyYz6Vu8tDt6kKZIyIYfGAcxTk78l/E5SoVE6PKiEHYlZugxavWfxbcx6d+08GXqQYUfUBU/DSPgKDNs/4nP9dDosogh/3neBy0gYSWTSFR+iZQ0f/WjyFqShvowxee7tgXMx1UFGoR9eT/3G80xP4cWY9+Sebwo4z3+DQ0wTOrgpA6bYBumGeBee8jeB7pBmlvnVEi0059CJLDgxmTKIONySDb7e59b0Xn9C+iD6r9Njq1h0aeXEXG+2aRjYlRmA43QCSvl3Ecpcz0GQlzi/qHlOEcRZH/ani8LLv8PWUNa1+LgwSO3NYW/U3zqg0ZcVWN/q05wJ8DdlGu3Rn8hXbvVgmcA8XaUmDy8d0/BDiC4kZJbAkvZpc9pxBXf1zfPtkOJ+o64Cky+tBWkwG1s/fhm2LwjlpuTENXyIELr0OfHp2EUvMdiBH30sQb2rEi9NFh/rDdsyoF6E6C2/+ezUELWb1c9u9H9ii/Qj19B3wQgJi2x41OPBLkH+87kOhrnPQddWXNjzo4RXZKuAqmExTAk/Bna7z5P5cGzos3KkmPxW+9bzGvrLX9D7rD3zOnc5JWhqs6vKZMmXUMWvKKBilNBenZsUPvcdsVrsmC51CG/H5SXFe++snB21OxrxyM3irqQ/Xjj8CxRGieKDpHu4peMcOdctZMl0GVv74CmHic3gtNPAqOwN4PX0bfsu34Kr3w3m95m9W+myON7OtKbG6B7rtDWHWfV+c16sA0z2XUJFLK167sARztFZTWJk9ySTehZHCB6BccTXuSVgBlt0iAC4q7FG4CWW9U6irTgu39RRAnMZJll1aQo3TR/HfuY95Xb4NOOp7saPORNQ7bM3LvZWh5PI1HF6HLLkvAG5GhmPCzGGcr4Xgt9eQhaQcqTreD0X8NsHVlpkQYf2GtkwooOk33aBk5h2w/qcO8vtHwuW+LRT6VwnHV5XBkY22KG8YgfNTDkBqoiONeH+EVh+Uh+d9O1nTdQRenXqN3/h84cVl4vj8RA1CRCQan5mG3iq+dHS+JgTPPYZ6J/1INsQK/ox4jjvM5tASXUHwyNpNc2O+0WbFRXitTR5Mtiuh4pJ98POSBl244E4RxfVsapGHL4z7oNbViI4ueMBb2BSCRJaiyRdnWL9wFCavuQnhAxGosOAoyayeTHeanvGKN+vguoYkHNGOp4U2ssz5B7ns0imOEpBhQx0X3ndtN3gJiYKeyzL+IK0Ems3J1NaGbFseiIGin0FMaw0GOsaQ0UArtUQmU3S2ArvPM/k/O/+3U8yHL4posW2YIBrvLUHNLbbwQ3QPlNEoem18ljMfE1qMNABXXU323rCSjky/y+JLW9BXxgL+DnWFD93xtFVhLI6WzaNvAsrwc/9uCJ0lhmWT1tIUw1S6VmnLH7++JYVTP/h7vBV5/WPMyRgH56+2UJqQCDgm5xPbmtLlmwdQevhFEIs7CGlX54O02iGsYFmI3iwAwg/Cwf7RcBp5ZyS7XYik8km6IH3/H5T/LiGt03vJc6UqlDru5v/OLMG6lBi8e6oAlp1cgfImzrTxjTaYOlXBynHvuOObMry66UvvM59Rnp4LS/RU0ownOjh+Yy42bBlLT71aeOfjReBpOgZKnTPw/MIXZBJdg9k3LClc+RWmn34IEc7nMG1PEaxIc4GBPGtoSNnKmiKz8eTBhbAo1xvJvRqEvW3htoI6tjS4wsBTgPwNGtD+3I4bFlfQ5+RBTln4Dcyd5GHOJDs4F+vGorqy8LX4KKTtI4jtq4Wz7yvh110djO2VhaR7UXw+tBqbtzjQtFkpPKdoOc18rQJvNpVw583NHHvqHMatGs/T33+nhrmCsOZPI+Un+fHz5ij2PjQMjKCI4/2y0F9hAifXGYDymF+UnLmDVgbY8JfoZRg9+gpnRI2Dl9tvU1NuDY5viaYaEQESnV5Pq9Xl4UDzLhrcfJNdg7N5easGPHjVxI2jpUD4oSHdrzdBC/MB8MvewXoa0zFrbw7UPv9Bax5owrVn8tDkLACh5zfCldmT+HixIytcdIewKFM07RDCas1saEITKNrjzp2mDsT3LrPndWlyaZ1HZ+9nU13EWh77MY00T5+H7fLjQUu2FJI8orCtUATn6HhD6OBMWPRwKr0za6Xy5dJoL6oIqbk6sGlvOMmFu6GGog6GzpDABVdn4qv6X/BquhwtENBBsRnvYZXr0NyPK8Pr5p4otnYzflW/SHmPc8ExaBo2fF7MY+xPwcT6WK6/NxbS5hdxY7MEhZRV86NFp8Himi6ZTbnITyI+g41RMixrCOND3UKQM88RDr4VZ+XtX2iF7UV69lUAZMVe4F8/TazSzKZL+Z9RN20kJMi0UF2JIcDQDE/rf4UNKzTx4S01mDWhHkqPhfPN5lrsWqYCx91M8V1JPI/82gdibj/o3ucWGGFvQT/+dkHnnGug9J8KBlw2gIXkSWK5/jRcZAw/Lf7ARe+TQcH/EAm+GQ8dR3zQ5Ioab66zhhUTfpLL7wW0aIk6F5x/DcAm9HfTERqe8pMSF3ehXd8ZMvpsBerL/uCTq/XQNaket6+4B37u2nDu6Fy2m+WCqZdcwbGzH+N+mUDpAweec2QPXt+2AUSTV7KJZiK/3JrIZ7xl2cvnExZ3q0BYpy0UusSA5eQHkNsehOK5LyBma8bQvTacsPMFV1kMw+KUBE53VoFH8QK4d5MuVj5qwMn2r2hAYTVfOdkDLy89oRvtAmRw+Tbqh2rDz93tcNO2hSI2TIYvxi00kDgPxb/Nh77vy7HNyIJ78gbYsdIcLB3/QuvDjbAx8DXKn21Bix8Ir0xj+OfMYA5xjae9v8ugZLcCFFVfJjuxaJYRM+XkpsNYk78UVySLYEH0OxrI+QHj7J5y8aUx4K7nRaSrj8AzYMbZnXj8ynl0zj/PGwQBRv4RhPenBHiH7TC4fWss7bjWw69/T6dQsUF8LFXAU6pE0Pn9Ux7pmkEhcvIwqVkGZkz6BPu9F8BC+N+/Oguwf/xisBjfDocXRHJV9Scy8X3OY3vNoLroOWkY7uGmZFfqUr/HV0orydepiedoxuN5tx+8bdxPbtojBpn/qULygC+kmhfxl/lrSS6zDyzs53K+wXL+nbRkqD9r8ZRPNrA7aDKYKR1El2+XsMdbjwf3vCWDWyt59SIVTo9Lgf0V93is5Fg4s7CIu6qfQ3W6MSvjVnpwYzGO+BmGqaZRNL/kMJsK7cEV/xnB65oyqvX3ZRWvCk5JOsg3HCJ49pIGNnMMghUVeXiiLY4lm9TBd9YFXD73AqYK36M5Iz/Tyk+VELImj994OwJvt+RGExfcpisPlb8v06pwZSyur+AyF1NeUfmJzR99Rce0GPBpG49v6/ajUYYElDxAeGNYynMGfaD0wzAsNBYlu2GL0GXaUZReNZXvyc/lCg09OPz2FLZNe44xFcv4TpAQ+o1TA91Ztdz+eganpj/m1MyJGPNKHfpmvIT3jjvA9t1j3Nopj831Dhw7bRzZH7mJBzzsYH3eTsg3Hw1r/t7jpysvMCl/pFablXC3djR5PBxNbWLbMZY20+byEohSHg1Cd1Jo1mV3rJCwo+2LVkCV2k+am7+LNZSc+OPIn9T8+wBtOMaQlOtMX3X1KPLKVXTP9YA1jQWYM3CEHARLeWf2Itox5S58fiYCC3+68QoxEdrbbgy75gZS5b0ETN+rSAvvKnFafy92dKfRl9PjIDKzCotk+mmpgD+tTxiOJ7+8gnKHaBxwFqadVonkH1QDlhkIzZMTaKbRY5j6cwfXV1+CiP0v6Z2KC37XnsGPputScfI+wpnCIPtmBaofUsB9S/t5eNdwcHT0J4VRR/HFh2yQFRegkQ/T8K2OMSRobOLBhI2ktP0pzfz8D1xHL6OVXdo4zGAytxpLgcqn4SCSZA5aa9/TeytDcg6PAYcX/3jb1lwUCnDDSMXlnJVxnr++S+afm2xgr0QPG55wxTVl5+nWhJlo3jqUmS1l8M61jhTen4Qtdush5rgU9Dv4oOfEWMh8upMP7svEL0qOeFl2Ef78exycElzQDnVw7DyG98UmXGJ6G2p2idObJY+hycYNN9mO4zmleew4QR+CVxfRo0UaUNJpCh+8/cgvJpmXDpsPMu9i+GBdMDaMPEBvJOdA1OzjfLdnBBRMHkcNi+/gWDMJSu98AH7pbez13yoYnJHEAa+CYWxBKTXZj4WHVWXUdruZci+IoKTZGvaa9Z71ba5CxJo80il5RPtdw3jKH2H42nuWQ84cw7xXFSzduBozrtbAfIFrXFysinWFl/nL55c47o8IOPQ0DXF+N+dr6KP9hQO8RWc5fA6eT88VzfDDh13UsCuRMjOHw7+Zj9B4eQzEp+iQepYlrrDbRyNdInlC/2SSLDAmsVVRKGumBa+WvCCFaWNBz2QhBS56yuUNU9Gx6RS5TjXDYZiJdyM+0WaBYVCnsxW7Nj6g8BJb1BR1wjtmFiTZNdS9E5Sh8+dmHn/BD7p4DFRLGqHl+34SXJMKdtaCOEVXldy0NqNWvS9ril9j7752YHkhaFy7iH+1T8R94YtgxEsDGHk8gP1HBMGiKxcxZ8MEmjw6BMRahEDr62esUPfjw3p/MOehB44diq5vJ3aBl6Un3NQWxNl9KshLZeHByUJ2efKRs0s34vUzh+nW+lh8EHgBwxRO0pwyG4yPvUCyWQyqS/9A7peryC+DsW6zL29I+QquMhPxVZUROEjq44GRT9FZ2AJik1OgRm0xoK8P7r84guudB9jmexZbJ+5F4R5/3ii6EB+Zm8Lwil+0/ssE0k/KZoO1p+hf427I4GAQ9tEHgQ/DKUpTko09ReDiEgeeJb2E3vzuILl398DA0436dqTiX1cRnFeyEhcus8IxIoIQIyOM6teLufLGMzZUWkj1uzU5a6kK9TWLgo1mOgc5adMqWyPIcLekowc2wmFdA9CalgrzrJpAofUkifcmYPYoI9z/7DWu/DEBFt+bTf06z3nkXx1uWNAHSfCHhJTruGjKeepc0IreK1MhzdoMVEQ8KXNMAomHnUKl0M+8evV8iA3cTP5HqzEy/Qn5dpezrx1AimIYq7xYxmK7g+HlODmKSnLF3NpiDnA5C5cedwK0LoRfk6zghekP/rUpjF02psCK+9Ox/fsTDNMNJtmEvTAE5RipLEE3LhrC9sKHfDZEAN6ndpDlUD81jhjGIdYT8GW0FSj6GCPP2sg1/7TARu8rrEk1xAt5y6BP5BzcmSKPrn357N6rwU19WyD3ZQxduywLdwL2g7ujFuRNK8dRYSdg3hw1nGfmgwGyAeRTrggupa95QZYEbK5QY48v1znH6j5O/3IU/30M4d8vo2FHox49sBdFBaUp8G6kPFjLPYVisUCSS5pJhx9ugKMHf7GtiDjtnjjEsirz6MGFNbA1QB3Wr1WEjKIVYPLlDbcdMkJB9T+06HETnvuWxy+aPajOfjrLtI6DNVOMKb0wGfrjf+LN1+XkJR/OovOBMqqyqJNr+K12A+xYKA3bEv3wWbMMvrv2jPQMXOHLxrPwu/A9altWo5arPo50n8tXN48D56rheKqplS1k94LpBzW0uf2Is3NzuK7Qi5tlY/nz0TKUT5wInrGe8OfRD1JMFqCrO1Lh1mglaBoZD/8G3vK76GQsvzhA/wTUwKR6J20w16HFx8/QrldI5bGHYbyREa2iNDb585FKjhqh2amJIFWkB2+3fieJOH1KOPcYT+2di6+mKtOdUmM+kL2MY4TloTBZEH4vSoAjS9+znfkM8tXMhbprIZBRpYF2JvJoVBjIwoWisLvFBDJsL/PEGTZsO+ULJ2+XxOiw52BxbC57P6qjJoNuMlx1BXZsHwE+q1rZYX0Ut8hMH5r1dPrt+os0l3uh1t8OqopcCXVBL8Be1Br+5fyglYp+3OQtgEZaCvhML5cz3seAasUrCsnqhocXPMDTTgLWrYgEp6w8mL97JY1UyobnJ76AoftkWvs+EccfP4vnh3jaR3MU1HnsxDd+tgDzDfjvlXOgqyqPSx+txIpID7DhOVTVtg7bpazhZ2oQbJt4CSbqOeMunVcQOkeAbz+bDm0/p4JGXT6G1aeji7MofGxdh1Pe/O+bIyt0TVKEC3It1PnjJfpcfo9TBGzg6Zsg/LVvBNz/FQkCnsKoJjCAiXnSrLR9F/atLeBHvVK0VesVSqxdCSMVTMDQaBtWVd+k2jvGKBV/jfWqLKg2+RD0rVoFazMC4ZPYBZrYKAXd6cm47KsV+DSJQdeWt6gcPpr3/d6Cz2/4om71KdpSI88Jb4QgsEwYKmAOO8grY98SfXygoElrwg6AzIhRfP9sOZ8ozKCDksYgPtqbRHrUSbnvLKmP1ASh7GaaukgdZGkocw4+gvJ5LzDdaxKQXSrsOFsN+b8/cb7IQj5Z8Rn9//WzRJ8FeWq/5T26EezTYgFB+u68TFsdaU4Brli3Hi+8TYDP+2fR5TuxvHBWHqcna4BAgQ3U292BOP2pcMvr6JC3T4Zi+VLau6yLv634x8Zz9GiF5kaaPF0PBvb8JbsL5zE+7hhG9tWz2tyJkPDDgmTH+4ODxTcWeTqah0kNg1ixGciPqqHgfiYYBYXCRTsBnty/iccpv6D8ojPseqMcxTMFYfiDmfTqQThHvH1KHUdLOVPciz91T4CkvA10ylsGGp6eI4vlihC6LB7cTqbRBgcd/t7Uju+/64DL4A84cXYqloTnwrqrF6nCTh1MNwZBt+1LfKJwBM+lyPIh7dew6+obUmts4fGTA+CK30Rq+yoK8vWX+F7FDoj8x2Qls4wEBv1J3lIU5452Rr/aU7xiwlKqlxQHi/pQOJNyHLelbGajvHl8fFEFpqercEAd8dunXvh91T4+N5QZImFfeJfaeHxiNJKlff9DEddiOqqliyrCxaSntYI1JZ1o/gkpuJXeQlGz/Fk2ZyeX3vrOVz985r+iOfxs9Eiyu2EDH+Y005VjcqCgIUrnf9nAUp1MjtE7gKo63lQd1Q0dS+tAxreAXu9pZycEcLhTDT03pdhL8DUI5pjSUjVf9p3sCYNa0TisIxZSjXOgKGQiDOetoK9mSHWCT/BuQSi/0/Sg3x8Jd11fyb23PfmahjaHZ0tDcNshEBRfhIbKOth6YgqWzzSFpSJBoKuST6dOPqPdBX/50JfR8FM5F5dbbMXBpmJYPHY9683YiPtj4kgq4zr62nZAw+Em8t8sCzPm/QNF3U4cjF9OzxSV6YkfkPwMXVTcIksHPn6jucdXoEonQ3szQN0Rb1KdI0eWhzaipMJxMP7owNOXDcM+iTXYb3MNEr5rQuTgX9KMPs5KyfNR9NphMtlyAgUtP0FMzXkIGhwGw8M+8oLdRrDafwR+f3eFg5Jmc79zIQZrXuaFb+7wlxsluLxvDgZZW2KnhzF0LPoHJh3nsFJYjQzGG5OLjSXvvdlJg/rv4cb9LsjSf4ZHXtjCTytfWOYbQNmLt3Dmgh+8YIQw29/VhWny41Forh8ce2QNyY9UIaflOC3t+w9kImrhhoEnq0SWcMi3GaTz4jHLfT/Bnd/UQNJdBM6MT8T1Oo5s1eqMA5PM0BfXYmRlA0wX06dbP2NYZd0cwNXqYNT8lmLNojlfr5qFPAvxclc39XAlT1Jy5+vVfohTP/GYUCFwqtfieV9leNoKLWoKvYMaWu70n95X/Hr2POypNEOl5lSs/CgBQop/6InXNIod4YIB9VqoIt8Ei1xng0N7PUwt/ER/z8VBkZAR7GkUQavxFnxUxYvm3v3FEsHGVL/3G/2Nnoue/83DgcUP6Ky1JPxbLkVLysLwZcMguu92gywVCfAs0cfc2xKwf0co3VtuweXWmhAWDKSY9ZHdVjxGhei/XDgYBmoav2i75g/8jc3Y3LCHMXUkhEzIhRarGmz4sAtMcnfBltQ9JH8jDu7Kb4CK6W0Uc2AMeSaMhdrkvbzPah5PtJHCPRc7IeXbeVw//gtHX/4IJSqnoSZ3PHbbjIeZL6xRrms29v/yAIvch2j9dTvt8gon6f55GD3uI7yLj0PJIb1NndOL/tvd4U/masJf4vT+4R++W7yW/QPnUkRqK6LifUrepAtrEq2pf6YiiZ2o4TT3L2C3uYxzhD/jmJWB8FXvCS69nkyzkxVAyt+Dr+WfIrW6FOpUXkxZuaaslF2CqbiN5RVG05y7O2H4lTGg3q4CVWbjyXnya8wSWEYnT1miTEoGX6nspW8y83hgaI15u0bAkgm3eMTkMoxck8JlJrNA9G4WrFQZCyWmf+G29GOeYhIEfUHqMPFyIJgHFvKzMjHe9C6FjR+vwXULnCn99gZwy6rANt+VIHRaByZZvsWISg/8tbgDtvNTbrlcin27fejx3S0gpvabqu6EgQibQ+qLJDqxVZnN7+azePYanrguGFMUHmDo+172fZ6AahgNnWIIdWuKWPFSKvw0G05eO+Tx4iglyOrphYeFe1BpsRK7b4rgq80IQZ8W8ueGOCg7PRmP+UaioNdiXCjxi7LP7cLInAbaQ22omGQLa3K2wYbFetxb8pHrlG9D93xx3rtwCreZW8MVERP+LX0We8eNhq9bUri/uYnTWxaBW0kcftw4HvcLW0FvQi/6SKuB1ZRM3ndwMkiNU+Opx5aCk7EmKFToA4y3RovG/eQWuxxPXAjATs3X+LrKAHbsOwJLn7mDQvYkdjOUZXu1CCqR3Eydg9IQKGKFv32Wg8RyYThW+ZhizK9CWGULHHbtxh0JR5gkFLGkO5YWrm8FjYcX0fmqKXjsbeLmonhor/nBpbIHaOY3d5DXWsXDx6/mr7dUKOHKNNy0QgrMZpbBsildJJ7qwmEVZ2CL2lAOyZSxR5kH3LA5RoPnvkFrozbE5rXQx2/W+NBECeGsAGdttaG/U9SwYm8uTV+4lPTy4+hMvQC0Bqeiz6NvsOCWETw4JUfFY15xsMY2Hti/hxaumIlLLeNokdoIkPsZiIVbQ2GW3l10P9NN8dNm42ibQzC3V4THBubRqbhT5LJNCGxEl8KXr7/xtJcAPaiIw4Mjh3zSbzkaPd3GXap1MPHnEF86jgdd0+c8MF4GmqYF8caxwZBrr0QetUlwpfUYHRtiNseWd3jRWQY6e4TYRH0+71ltRkrHc3nNxn+spnSP//pdwnDzZzBmUxde+WAJDi/jUHtOOW5dJ0KxY2+i4PkxuBpOQrCTCFxXqEA9j21Y/VgD1godp5XR4agTXkFf3/dAeUUjdn9XprqYBbS82hviVX5BfsVQLgycxiIXTzDxWw2mp61AxEKbz/7uAL9Ll0H15QcKsvSD8iEf0ilIonNvpOGL/Dj+92Eauu3rhrkr19LZt8P4/AQ5CK5dRTNfMOz0taIVo0JgmP1VWol74avZN1C54cX1AiPJ3mISXA3VA+9wIbh4Kw8kS6XxyuFKWHdiLf/ZoE3nH5tz3CwdyHmlhL7JAZxdidBX1MPsFwd15tNY8nU4Hfz6ih/PS+BCuwgI1S5n/X+I9t+lwFn5NK90eQpjxgZCSuhr/PY6iSdpf6PRM/ZA54UgfK35DLt3asDOTRmQv0AaZi4+ix4tkfS3cRs3V4ngKvVcSm10wxEflMk73grOrtKkhtpwKDcsAYO//hS1aiwZZ+Ria/tqqrb2oLgTnhTuJQiRfcW4/ZYZpI/KwiKZFjiu2ErlJtegalYpuzlMBpH38/nlaAXI+PyOT3g8xVTBePo7/i/ZuL3HaKFdtPycMRWoL+HGtCks2ygKT7YqQE/Qanh4/yU1f+6jgdz/2D3oDXY4qfD1WwsxfP9ckjWQAu99fnBbciVtStah0kF7bGq0ZaPeLNJfHYmJiTmk+/QrmPSLgKC8JB7PeQLtgQWkUoK8zXmQDScf4wKXg3Bv7x2ojDsC1y/JwYMPN0FN8Ce/NmjjXw6WPDx4C8k+fc6jl8Vig64Vnj88B/0OWMCKvBV0UX8ZlMacgufZaTjV8CIKa52E3CN5rCq7gtSD/vJaHwHY/noKf9w2n4od3sD/o+C8o4F6/zj+GWa2bLJKZrZKVmkaEVmVVSklKQ3tIlKEMopUGkoJX4WiqSFFQ1NCpKUkFE3Kz+//59xznvt87vv9ep1z7xWpkQG9rQRH3KNhz10Z1BRL4syKa+h6QB8eW1jwV7d35LfcjXzeyFFpvxLt99qDTpNLoaSglBa5t+Pq85owc8j1Rap8h56Z8ThGuBWsLLXp4uLRXNEtintiptCnjD/UkqwLlxO3wOOZk+lqwhZWH+aGI0M/8kLnZOieNZ0t79bzgN91XCooAqfvz0PvqnDsdU/jr5p3yT9gGwSX3aDk/WJ0bZoBdS2RhLFLVKHLwhpPSTbjudKeIYbLg4u1r0Bs2HFcc2kNjFqvgPbKR6FoiNdKaydQRpkKiz8XhMkK6/HirM00Z1Ynnl11Dy32jOW2+qNDWWYEmid9YNeMsTSrQJUWfLrHQjuHU/5JJ7LVmgLv9j+HEePfw5y9DiC5TxPK5c/BwepWWCcyHUd6pDMnWlDVFgPwFZ2Dijtkuea8KaQm38UmV3Nu0kFcnvQd52ev5HXvU6nrhjpvyPWhGSOjsUhHEHrr8/DzoAsbXnsLexKrMfyYKseLnIBWhfM0bsQHUh7VjPFCQqDjMAOdbltSZIovz7/zHntKfrGn7UOYNcQS3aOzeFPtLn56WwpUriRi7oxYHjal5//vWNCK8FN86PhPEtH+QcaPr3HTxgbu2y0Cea8lUFHNG7O2fcLE+RHkMtkY27vqaO41JUrEf/xg5X44XqsDCWmhYLBmAgf9l44tKiU0d2AkGmSmYn/zUw6ZGw+nyyaRVoYifLrTy1dGPcQtPTOoUPUVne03w9vrt7LTVyEUmXON1h3bTx5/RoFV5wS2u7CIbzsnwXp5Zr1qYb5S7kstwpco72o47PUIoPFCalDk2YQ+IdW8adh9Lth0jMX1l+EBDufc9OGYba8IrtPdQPK1DLy0t+AWtzskmbwTK6Y9Q2X3j7TE3QZO53RD69wGlraUws9RerBthgy52VbhNQl7NjF2wEafaTgx5zBC/BHSSX+ESanTISxGDTr/i6S0IW6e2VOLu2ObcdXCUdTgI8LPVslQntJslugu4qYlssAFFnDngS+bp3Wgavwy6moTgM/z9WnYVR0ulvsAFy+p4u9JhuAscQBry7rp2ahS+GQaBUvOSpHtbSf6t7EO6h2OsU29F581VIAb1l4wbskW9D6yGZedbsFIq144Ev0Xa49s46+Ty3HGHQ0WmScB71SD6K6qLSs2jeG5c/xoifBMtNXqpeVWJ3Df2CPg1ScCo2aMh5EV+7D7jRF9zzHEgmNA3rUPOXjgAfzSymSPj4GwKd8Z21crg2eWE/0e3YnntkfhPs9aThQfxuP8xeGBohSF2s5nx00hvPaiLJQ2JVG40lOufxbO7edNaFj+Q/gt7Qi5Wa2g/ZfIPKENhNOHg9ybBtYZ8wyqNRvgwtpEnthxm3MPX4P9u4V4xvBd/CJgPm18rgT/jf+Ii8KW0PxrOijrZYNzV+WAfksNS71MhD+aFbxn1z7WeG05xPoMQq8mcGB5Jt9zk0a1VlHq89bCtxN/k8jERVxoPRL92B5yoQSfTNPEjuv/MFRlGJxT16cK6SP0BaeRlfVHuj8pDzSKx4NEynH4YJ0FWzSj8EbMDfqTM4xsGxfwssZGXn0lhYz/iMHNc+MgNeoj6yjKUuhlK4ip1aKqxnDSeh2CYzKFyS7iFiy6tR2tI5XBTFkRk1bPw5Z+O1T/dQK7Gw/SiTEecCDGnDbtnkHmMRfwxpDXyvSbgvrtKnBSsaRUzGSrrAfQ/fYnpd2vBoE1g+wx6wbkbJOFkN03UTdFEv0XLkcZhXq2KFGjyfuXkdZyN7z8rJpLO804Mc8EHiz+S1W7bvONrtm8Zvpl5u1TSLpEE5wWVkH87nJS8C+H2N2C4GOcBUli+7lb7gGOaSoGNT9B7hhStiZjBbBdooBSOS/BRHE8fF/ajbnxa3n5gu9wo/gQxRbJk7PbUoqYrYmWdj7sNLcKDWyN4HPsPmgRvovCN//wXfuFeGtaO/a5TAT3FS+hpf4TLxOfD6teSMIzP2cwO5sNgdO1oHJvKNsfnQLVTb9gVPdEcJp1mAJLv3HZMlOw2NHIchur0V7mKM2cdJ1CVXdi2f50uJ/fBFIxrXBNvJtb81TgjpAJ/St+RFuP3OXv9ufQPbaTu9/1gv9fQX4wNAF5tkYc72AIRXPyIM/rN8gkmcL1Kfdo1ps0zm67AFN+O8KWL9Z0WdaBnQNkQTuqBDJyduHhxGGQ4nQdJlU6kc6BByiW2wPXcz/DT9EWniYtA+lGS3lmiiosOmSIy0eY4cIqQ14qPAHTC6tRdu4SPqZ3jaTjLCB1eBqXe/7DzWXzh/Y0jd91KIBU70o0fbOc3rqHQN+1GTimVwbWqofSHoOJcMjlI5Vr11Br9AQoajzClZ4OmDdMHe5MVWep3fKQ3PCOijdfh3rBesY/20g4PQeSVoxHx4+FNG1gFVwckwQxahrwUrofTk72ximPdKmu8C+kpEjjSfMlcNhvqOPVMsn3zSP+kKIBi0zOYurNDBz22BQc4mJ5Ff3Gjse+JO88iE69wcy75NlvFUDU0l54uS2bnEo+oMSmi7ho+DqoSdclF0VZeNodj2azpEHkgCyMs3pMN77vAye7WTDF6Ti62QahlXoK6av8oZxP38ln+l5eE2MDChvzuHVZGCYLbuAY8U0ctv05vczS5Z3vH2PG5A/4NawXQpMM4Wl9Hr9YGkImKo+46Ko6p2g7oP2H/Xxw6XFePUUCsuPOweSVgrBIR5HmH5DlyHhd/qllDWH7CkFogPHmRFUUv2kJ8t1xPPujNfhteE635Fzpgtg7GBNzg1UshOHRQ2/2PH4Eiy7p0R2hxZRmoAzyYukwaLUSfd99R3XvFuxISobnjXtx/PxUyssKRfemoXOOsgH38Giu24tU6dlH09830cVUecjxCsWkQVGYl/YUB6peQ3yAOByJu4d5DdN4QdphsDudCR6HfOCq8VLUJke4bX6BB7Yfgi2eRtAccJSmq31AaRFXnHrZH557mVDyQCpkR+pThGIFqu/Mw6UuBDdsnTmpXJsG1Q9h3ZNK0Jq4D3aMABjYFkNHmv1wssAXdJLTB9+3+mzXnw5nPZeh4dOltBOy4VdhET7zesxzTg8xf/FlqlUyg9a7x+hWw3qe+kWBzMzPUf84a9K4UQIvOieh5qpsfBR6mYo+jwPjJn3y1T1K7UaLSdvRnBxeSsHtUV0gUP4MP+kewv2f9oCylQEEfbrKT3e+xbfXktBFIhPDdr8mKjjPsocFqSp/L1YO8cfC+5Yw7tJfTDxph6kt2+kbO+BtHAOXr8RD19LrLHF1AJpOOWKb+XhYaiiF4YvCqOXxFny/4iz/+hLBNk2hPNi5GqxK2uhKzifat0wCNq2u5FduZ+Cr0EjoeHabbJV/cIxKABvH/+TtFp3Y5yzKqk1ScGqo96yDH+F1kwrW2jUBfpSu5csLF8DSoGLaZbGHj07pAtFEaTiYoUKjzUv5buo5PPdpGQvYGEF7YTu7bz/OqnYxpK3RynY5otD5KRa/F09inHsPDHf9hxFnZOH6tVV8a/tCPiDdQYL3oim8wxaSJjxB7YQVsM3gEwRtNcXFCz/huV0+kKJni2fyUsml3JjxyQg4EfuYPCLzIWmGAwZ9lORdr57Bwt6H9FHnFcWa64PXdHV6ug5AVlyPGj69w63P5oPK3fGc57EGTXNtoOenLj5ctZJ2Dq7Gv8lK4JC/ibZU34avCjXUszuKDkufxm3S34c89hP8kn+A+z66kfcvQbCXVMUpB/3xok86uy7cgGvvzuTktGFYvP8zK21W4yybfipZqgrik0W5PrAbCwp3kcKW66Rfp0muCqfxUeEABVftg/7S6Zg0tG6HhBwmHs4m/4KPENB8nAZF1uJUzx1YMjBIcbOjhph5B6mdsYLL1xZAt9sR2hTcBgHrF4NY8Cv6NnsxicrVk3DcRB5TeBK+XteA0eG7yV1VlR22LcQx8i3wYM1ceDNyA44ZfwlSLHsxZk4Yu34YCauTPfDv5EW0+skwuOm6kw/Nk8MR4+rwl2UsXbzyha64PSXZVGNQNz/Kxhlncd2WixjYEcN/hnvgC4lmvDmmikRLm1HZUBMDxwOkrI/iR0cO8r7r8ljZKcshdv8o4/FTnLVRlYpDVdDx3zSSqReFhD1m4Fm6le2n9ELV7+VgerURfSZchZMNd7HbphGuaNxjzftjwajxK7f0z6T/1h3HBUP38d6bBBgMGc65n+fh17oCSnhaz4f2I0xSv0Sjt8pjs1UdBK/aQXOWrIS9oxTodo8NR0aP4ZCyYL7dPhzWefzFAk13jBSQYeVfySQs/xbW6wtRXZw3Cjb2gMW6B+Rz3QoKSyaSKyRC3ntBkolCUNF2pgw6B8aV5vhO8ySN9xbFEn1liGlO5CIpJypPl6Qx3l08/RbjiN+V7PewGtacnUZem8/wDpQH3Yh4frZtK0yMWY935rZC0ZhqHqUwBzLmDaKBqzZoHXyKExebQ1BpKa0UGIFBlVNJvSIFzR18UXnkI8pTeQPdIzp4wsId2PlFB9bPQlI7HU4WY02w7NoAj7htj3/nmKD8vCSMsSnGCouF8HyFCHR4m0GvQxSbb3kNHWpDTGp8j85u0yOf0r3QLC1A09f85Bl7jOFv0Xh8fGYfKWzNh6tr9Gjc6PmcICQFdgtCOGvHPy4zeAWp9XrwfuA7xYTPZttZ6mwlNpM/rGwj9cez0KJcnuWP3YbxkxRYCYzAoWcDlTQtYaG8i3zwhxjxVQXaXZvNxv7p/O7AYvxYHsP/bNVgxuAGcNEwgF4zC/S30uUz82bzEyMp2r4liTTHdhDV/cZFDpaQXPoFzVqXkXn9N/4UnkV+M5eQ0ElbnPrZih12pZJNiTZHL9CGvbuU+GbLBjriXgcTjm1mieh4HCM5lc3LvTlmoiE9Sk8FvbqxkFdmQWuH+GOspSrkH2qhuPqLlOLYxUUmDZibe57eb92CV29pg90JES4ULkRn84U8yiAZ/x2s5e0P/2BYrgQLf5mDNxfEwcQOOZjjMwe+jr7PZYOHaLuMPnx4+wtvbLbCiIsT6Y3aOBIQr+efd82gI1WRXINz6GhIGuw/mELh9+xZ4rUV9aRvoZFCPphQ8AEXbDKER7IPOG2bCMx6WsOhC0vJe20+Jry7AvaqAXzL8RUExKfAyOwR4BXlNeSd/8HcSW8o75Mj3tpthsVnlqGSwQhodByg2NSJXPhVFgzXuKOv71PMma2O/rvb+FR0KbaGnwZ4Echnxu2ETad9aMBbDoyC/6Bb814oufyNQ8LNuPEO0NzrqrR4YB09sE7CYb1dWJk/GtrrpfGNmiAEzX1C558kodJWGe44aMKeDTNpv+1CWv/xCBxZIg96Pjug+OJzbrx9C5Jc/sFunRfo8nge7w+1g9oFfdgUdwHLryqDg6UQLR+Upwdn5OlkqS67n+3kpw9aWb/5Fu0QEQX/hcvQoAdgblUQm19wA9l5NyEmfyUn/FfMk/JUcPLUDrJ7mseROXGY0zccHk4RhFUVh6Aix5xsURDO644irZlyfPr8MF7unEV9Vrbo+0EEoiqLIWT/Z5Qcfx/LVkzlGAlrOvsY6dTUZVjXs5rju23IZZcK9NdnMO88BNHiFnxb4hlJ3xpFGp0asPrCeJaRHfKz1VqUcEkIVmS1oe++cWh5vg0EuBkUSr7gsMKR5Hdt0lCWhMEyySm8h2XASVcVxz6ZSdN/zKJ/jkE8dlCGTj3Mh8/DjSmx+T4mtKygOTutoWp0DFlWp/LXz3PgbMNaEDA8R4Gi0dC214EjNZvA2sgdJaVV4IHFQ5y2/T4cU4zigoOTqKAS8fDLv4yv2jDx03SoUtmJveHG8P5LGCW88OJ892SwKljPBV7L8fuvefxnzFjwLHiFpjOKaauzOaxeeJ6zLy2ljddzUbGxjv6KDvm9kjZoNqqBtIYd5d05T7uWS8ETuYfYvOEQFEbV8PvKU9z/ORxl/hbDhvClOM9ogB7vXE1x/eMg0kWYFOyn0Yk1fRx5+yPQFwds3qZNF+kvKjXaYfuKZpg5QgsebExG8aPSsGL0RP77MpOd9uhwnHMtbo5IAJOUZ3Dy5GK261YBt2OttFdrPnh+P4drAtZi2cdyPJmVBqIL7Hj1jxXkoXOSDm3QgqCkfmje/YPtHzngSg8DvtJpDRoH/+JNJSeaOnM9XGifykfdzMBs9mp0dEvB/tIgkHmjjjYfDHBsjxedcx/kDgtRFn7gi/cnWcAkDT88V5pFci86+ajiBMiYYUaB3x5CtL43DwtK4z3D1/OC/QQXHa1R5WgxuYV40o3ftfRzVRovX5SNSwM18bLYDG5PnA61McqwXO4kSM+KxiPPz/O62CxO1ryIuy82ov3yVeTZp0K5L/Wodq4C3NIpxNqj9SSpHIKh6ZP4bPYGqv3RTCvNA3nyohSa9WQk/8uXAAOBOTB8dwrNnheLK9ecwLehb/HX5kfoK5/F+5vP8MOKLlziIgc+yy7xljpZHPFzNC7HKjyZsp17R2yDankZdlqggTuGx6L5a0u4obIWvDrvAMzajgKrV9BXFy/U8y/iJ6M/QNe7Qd6jvZMaYjQgpTwKdy3fSptcpdDG7xdctg+hKW3GfCQ+gp6fuI5F07P5w9vhkDn5D92Rvg4z4veRnPcWsDupDPNf/octPZO44tUhaj+6H5QvKMGXBcHcMEGCi+LsQCh8LPatC8FbkVP5is5BvqSZDV3Dc2nOe4ClAq/Yep4JhjmH4dMN9SyfdpKixmeRhM6TITa9Qwus8uBOpDUEuw7g1JrJ6PX6DPTlDtLzDd6MSVo4oBnM0s1xHK5ow6+WKMMr5T+8/pMiZV6UxpKS2yykVs6SpzK4VmQR3Hg3E+T1FGCmuwboT7qC80SIhM94QrqyC204ocC0RI4GK7tAxHk06b5ZwC0FQ9eb6gFeWZsx3GkzBwkE4Lq62bRlsIqt3VzBZIcV1a89wO1CgjBbSAXzl3vyD50evmQMsCr9LfYmR/GVhb/Y7KAWtX24wyuTxkBc/jLuvvSV799RQ9EVRhToNokVHL9QqJIsZIRf5y1Of1nwhw2Ijx5yq9DNvO3rFA6K6IBY1Tj+/n42nTX4AaaTWqHNLY5+OIyDZbVbUP3DSejZ/Q1jvLtgX+opWJ+Tw5lPZmPT3kzql2ihhKkmIF4zjY8d/o+vm3qS6joHNlnmQe5SvqB3yRRkepRRcsYJPJZhDVbCU3j1nCtcUB0JNcesIT3OizaO2kprllZiXrM/h22Ro/BwgLZFemQe/5OcXxlDU6sVeoXdgrfjwsh6eTS9G74Y37bWwaOvNqB9zwc66oy46Yk3HnqUxW+XXQGrsOV4+/k7KHbQJrG3k7BrnQEYS4VxbrEfbY+cAKX9D2jwvAVcEorAm76jKMouCWfOfYQlAbKgHhqJAe75ZHbEnHYeGeJWk5f4n58juwpV4qQfE/i+QzpId2lA3fmtLK5sgNGmQlxYas6OvcL87L8FKHfuA0dJd+HZo6W0Z5E27LfPpMBZCThu5H5KizGD9Q7OCPOn8QvVJXC53Jltd65i80sCUOh5FhpiO/Bv3no+ZZ+DIlFW9HDeNnz7sm2I3ZpYoE2X9wYKQX3UXJjcswVHrtTHChNfFDGWxUNHr8OjCiVwPZDJ+RcTscl8FLzYEcQnMptZe6oiLTHM5wuNY0luljm/SF9C5xPm0dLLNSQRMx72Ot/gAy0DVO70Hf75MM+r06BWcsN7wXOx/cBBuE9PydNPB945EByKsedYew8u3baE53wS4Ptvw6D/mir59X7mc+0byXqmCSj1d1HttxEo/3ENT4wfpDDHX7gtWwEEw4Nw/bkMVLwfRvcmisGXsW7o+XMUKh9htP7vKGz5fRIigkZAXrYW9n2WRjNnHboP+nBu70WeOVmSFqZVQfFcK1xak8SOy/pJ79cBbNEXgzd8hRtClcHTtBPGeJvhcH8psg+Uos+Tc+n+psNYIhFE1VsmwxiT7xAtpAER+3RglYwn2X+Pw8SiA7zVqgn9IyIoOdMBaw3SuFVUmapWWYJ/nydIZ57ie2mO4GMax2EHbvHB/17Spn2b2AYSOE7aA4QidEAyKJkblUVg91Yj8r/igN2eZ3j5f+Nwa5kvhm3MAPlWS9ITVgG99CJ6I7+Qm+5WsMTGh3Si4wa8ezuaftZvgIQvPghlbViTogFB995QRXIh/e6NBekLOjDDIICmuayn8PdPaFp1Mq5a843WvDQBh5Kb7LxHBp/E1+Ll3Zm8RCwagrOaIHq3JyxNC+C3zxXJq2ckfHA7hUH7N1JtrSP+/T0O8qpvY0ZmBuZP/ElbFY5yTKQVxp4eBxtG6ECpoiZqeShwY98Y0o47To27zFjrigQoHT+MflFlGPbQFMz8QylMQJPk2g9jwOmzcC9DmawN39F0bRHYkb+Nds25TLxBDOoX3ufopcjRNiW41f8AekePp/z/duLSb9UQZ1jHlRfH4j0daTj+N4s/FfezxJ6VbL1lNOblZHDexkbefPwxe30VgPwxAXjrBcGsd92UvWkjbOnaAQ8TilDyfBXtnH8NPgzfiKrlUXTs92S2LROCk78TyFpNlSelngXbk/Is8Kia0iRkSL3Dn+R9uzj/wxiO9DCCzBghfD5jMc6d8JVv1Y3jL9hHIw8n0WlNCwrN0wUj/xA6NFICVj98zC5LzMilrwTeP9tBFD8FPT3b8LWoO6p61kOzgy38/5sk+7kWJBTexHfeCXFJyQnMsv1F26eIQPGpSaD+MxVyrfPh+YA0jJFTZvFOAWycL8MXH1/E0d6a/Esmi+/9lCeX4K8gIOaMroEqcOBqF2/Ii4e8azMxeDfC/o1nWeH0Guyu2AFuJYchdVU4/KsXginfU2Gy3ir+s14UhSrWYXR4GAU+34UJ38+Cy5TVfDheAkPujAPpKyWYerIYk5amw2DWJaoq+Yhb/LS4+BNDZ14x95bdI1UvJXg4vJDKj4li5o/NNL3rAenmWmBxmxilX+yko7liuC9bBxIXGcEyEyGas9QV44UCSeDMW/r6qZdXuC1ik3X38VrHQjL64wf7xuqC7hMFnDrKFje9X4dLA/yx9tgivOHjwd8loniGVAX4WlVRYgRBcJEWpUtZYJtjFZU9/cDi2ceoHlpJevQkqnvbReOPyWHnbi24PvcdCMU95AJtU5yd8Yv3D+bTSMcmmCoqC40qO0F7Vwb8fSkO9nXL+GhaFn1bVkbJr7eTfPp9Wiefy3HeyTRhaJ295mma/9wAMp/thBVeF9Dh2Tl8lHSbS+9vZ9/kciaTRxiclYD+nYfxaLIMeMr5g31nA7qa3sD9Q515LJjZPdoTYv9uB9vDleS0vo9qdBH+aB3HcRFKYD/BniT2GFLZhxV4WVKG5YLF+ZP6AuwqO8t6ibpwKuEg9D8fB9kKSA++jEX5Sy5YK5kEGkJKPH77Xvp64TNlH1IHry3JaBEyyMVuu/mPrC7uvxPPAhuLST+uiL6p2uCbBX+p00MH5jdvBJ+cIpSPWkit0bF8/Nsx6DruBPuU7+KVnCwqi/Cj2CUEpdf8qH9MGi03qQad3W2YvcMSJ7w5xTPcjqKX5mS82vgXbgrJwlWRXzzD6AK2fjrOjkmdYPSrmXM11TB6ux1E/7NHrewiGlGhD84CT+lojAbBhGi0/RxO43+68x/D01x0YjN9fPmbn6XI0/kaA2g76ojb2xSpxr2V7+17Rp1PRkGb6HWQNFkEc4yu87qnRtCXoQ45gjrsFfgDPX+l4RihcHCqC+XZDSp4fb4+n+mPI8WDv0DC2RDyuxwpevhYeJRDkFl/FRPXZGLuV0/6MuSxQd9j0Da0BHJMrODLOj1O3jeRVyU/prT65bS3ZCRtOjCaan6OovmCsVBtEoFNLA47vffQ3EdXMXT9IzrXcpwVJM7BuNT5YCdpBFei1mHMt5v4oloJbs6y5dZjjzkmeBZ8nalJWiuksVVZlKuKB3lRZz/sb/sBMT3qUNpdgCmZAXig+QIM7BVj/DUVZb9bw63DFfzY+h+Mzp9B3jt0YUZPEsyOCmN4Px+9g2w5oHUSP9HVwDN/ZXjkIjuKismEikgleLNViNcuD+Aj8mJsuWAVKLydRDM6+vHu7mOQsn0nCrl8w6nLRkDE1hhKLtYAs5sDcPKtMRtumApeQl00p7AAFNM20rfFn0nEzw7SHKbSvEX7QDvCApy+q1BlXzrJhkzDPX/deWRjIdmRESsPcd1loxy6tPAnHNd7i/suv4Kc7Zuw2/ESbLIW4Vurr/OZWwuo8oM05LVU0Fb5y5T+uQcXfzbn89IeFFd6m0ZOsMW6kz6ce+gkZOsTVKAI32h3AhWhXQAzNVC5xxsGzVLhkFQAjJEN5ISDJeyhpwMxsZPpaukvvjg0tA97c9licSvMDQsAxeI1EJUrgQaF0vxawhjW7TpOE3ds4kLh+eRf/YjFpqjAvq/H2N9xEZ74mgYp66VAP1cdQvv+wvFnu/h1qBjNyI7G417W0CG9CKh7PRoWroEX1kPQGSkFEzxSQfuzH700WY0KsZd5RWAsx9x04K9q6rDi8SUSGSkKqm/UICxjMY1785bz13vxn+CjUJK+GNSljEA/+hG9DZDn273JqJs6Fg6r5OK+NzI4OcCI1qz5DnnpNWS7/i0fi+iif//dhBlv//Hsq1ZQMXwRmPePgLC5SyjL4y59XeOIdxNGw/bdAeQ21ZElld1hrbMoxL/Sgs8hG2H1glwuWuDCxbf+gtK/L/yRL5OvlAXoKE/hHY9HQtT1J2TQUECbA57wMp83uPzMZd5xsBdeV1aCy/exqLrfnxO/WMHInnto7q4Ep7flcMpQEG9xa0EnvXPUKLMVVvnYQV32W/JuV4FfXU18RbyEBhZoAa7aCd/+hdC9Syo0+68gDjT0UbzhQ0jergHtxU543UIMJua+wKS6ZpSSswVtlzg6c+oIX3znDdtzEfNrzcDkTQWfPHGPM+xiad5zV943rByniU3AEe3CdEXMF6VW3aHDJsPAZ/4aXlzThPUfdPD41Hxoei0Bb0X96OR8OzwpupRKpxyhrdP0wNQuldLqEIWWxOAIK0Uu1EzjIl9xLLm2HP1+K/Dr88EsFK0HIeP1OMNkMv1XeYOFz4XAhRHToOTJlCHeMiTdzedJOSEVuxfLgY1IP7e2xOP0Sg2aefw/6Am7g6KGl9G95xPYCuqiwyQbbJsuDfKCBXzWKQvrx92E1qxSaNWoJpWds3nucVtMl21HtYoyerRJDd5lrKLgiFd8/9J4WHc+E2uUpvLMm7H0b2iPai91sO+GK67YOMSJuXW8/0cM1L28B2ulx8KflEQe0dCExu3P4YhhG4oGO3HxcWkYdO3HsyPjKEehjkML+0nW8CaxdCqJH62lM69UsCDpDyvnSEHlywxSGnaDvsx5CFMkLnLQ3jJ89DMGvR1q8GToDD64cx9FyRnAVjcR/Nl+gYLkhnzc1wIrhm+HU/sj0cnnKRisjMA3FbFwyUgZJo+8j/J3w3i95xZ488Kb5Ca7cvFGZbzqW0N7n87ilmZBzj1hC88yXGB8jziE2j0F7cA67FothbI5qtTW5YfN8vIwuN6GVibbgPcRG5Qe/5bjhcbzjwnV1K7/kRUqEZqnScDwlvU8MDmQJTaIQmvZCX57djaO6H8Ozqtk6WrgNth9exdaVwiScddh2D5diObdmAAu73LIt3gukm49K+5pxRNSWWB9sxjL7ILQmYa49uwafPVeEIZKEp0d07HB+T+e4NrBbYdSwK1dhZ5NbQS/1Do87fEKK1wZjt00ZvkFDEn69+j+Li8S0h9O+0Nkef7eIKY8R467v5UtrfTBfocAfdbw4yKVleSzSg1eBI6gmtSpdPpvG/398g3hZCI+btCEiCVnQEnpJDoPWOB08fM0Ws6Brt1Vo3PtZ6HykztZOdbCP2NrmGW5mrMGHejABH9UbM/Ep80h6Hs2jjz6xWCKwCSeeecAD7rowgXTL6ji9o4FH12F206HacYrJ/D0n0LsqkVexgf4qPt2lNfVh1GP1VAt+xqNaz0BL4rsOEhYAstWe/Cf1IMcu7wQZ8zxRY2vQ5H84BNWjkiBljUV+PrOKTg5ZhyIC6qhjPlnWhByCG6JFPOLFbbweIkQ2S17RNl+uzh9XSSGNO+A9U7HsFRtDvjP6cXCbeGY/1sCzMsK+GSBOee32+Jr9MDsy6l0Q2cMKykr4oD7Osx5WUopfVJgn/mRW3o16fXtOO4sPDLkL2741f8p+Thpc/wmTVqYsoauz1AAXtoIOjetoT3TBI8uv0UH3k4l88Mz4e6Mcir5by86Ja1FZXkLyFAbQ+MCh0HV8RgWmHmNnoVY4I/fJVR+aDihshv9GpxDh7vswfzyEjKs30CQFoDjb82nDy7j0T81iYO/LON1hpt4bPJqMhMZ4qsmDfbT0ISN8wuoMO0mrNm5howtLcld2pRXv0oCgnlkKaoDS/qBo+wlwOznITry+glZvdrON0IHECIbIVS8g39k7eDyyUZQ0pdFK4Y/oDcGr6hHcy0/EJgKh1z7KGrOJnoRMAnc8nfCgSIZWDHzENsUunIVDGeR7mFYNtQn5dP3okvvX8iW/Mheiqq8RGcsjL97GO5d6KWcaCEKrvzICWERVOlzlc0SHUhETA4O+h0lOf+RcHFnDp0QXIZbKkR4S5gnmx1ood9ZbbBgbwJo3QyDymfmOPhZGgTNb4FDaiOn23jCgVhjirg8ly96DYCz8BX45qZG874t5GliZpCVkQ28mEF1cTC6K77nff/+sFvQCX5oIk5fus3Yuvg0bjqgDjYV4/jISEt0P/YFzANNYPaycDAS2Eq9N6VJwCKPS7UfQLapKVgunYreEuV057sSxYx4ikcbLLhW+z5YpU2B98vH48pHgah+fgIsljSFgsk7yaRuDmw7O5Nc53zBFTH3QcB/H7k+ncdC1cWUeEMJrl4ppNnl9ignqIftoaVkPaUDLB47w/Ga8zRnxEGY/N0NN1RPgC+/2/Dx1hYYtamcVq3Po4LblxBd6mjmg3VcnzwMn7cZ0qh8YzDI8+Dka3vYK7uIDfVbeeaoZP447S1i0iT206nh4ZdHgEoaw890KXqbX0xBMWXgrHuXfPISeFHwPtC9rwsiIv+wW8MTBkarw87NvXj6myjH5qykw6ojqEB1De4dWMeFV5Rp2MS9vNDp4v//sQG3E7uptauVI52aWPuEEJxfvZZyTCZib6w3Xhdz4cLWTSQSYQom9d/w3etL5GoUgq9VPqL07lSyMXLk8wkWnOEzl9p110BAmRkcEJ7GcxL9wM//Dr75FsDPG+bCo6hJ3HTNBAs69dn0lSfE2ytDTa8w/5kZwnoDe8FhySTwG+kIwo4GZDM6hn8Ir+Z1W2woJ94A9uan4yu9LhSeaEPDlk5Ct5NIVQfHk82ZS5hUNY1OmAKs7hkJr2VC4IzvR96i48hTllzCLgkrntv9Gh4UHATbxgZWFHHmiBfKUJY1dGYJ6RwZuBq+fRRGXaMpYLdPihcmneDYSeWkIihMF2+IQtvOAr71Q5+XpdwGge2XueXOYuhMK6Ez6d+oJa2Ur1k5ccjL4SC8zwYbTMahQF0I/bdqPzTMLsZEmz0wNegou5sfpT3ef0lqvQQM+5EDtk/SqPvuAdBSsSaNsD44HFQNx40rWH1LBCzItaDN1eKQ5jGCxL0L8cnrIpz66w0XWwWz+js70nykSiMvT8EfIxby/edKkNnyEV5/O8aFs3w5t0SA/n0tp7vyoSAWIIZ2DRfwyZVh/ERQHwbDn3AOjQD1uzNBeKkVCQZo810XZY7W8OXHI+7xRruLtHylLXSeGQ/yAZtBNycGOt4ATUlNptEF6SyO6TTy4wrsrllLQpJScNZqCrUk+/NiGo9KmSfoUOIgGcy4x1wxjsZoutDGfyVkvlkeUldVkG7gWThYUw5bFUdSi/xLeJ6XQqvOKkPdDyc+hdK8dqkDTLKYBS8i78K+00s5QOkzTXSxhagHmWh+exbqllii1/Ms+G0pAeEa77mjTRJmVFzgxLM5KJ6cxfHBhTD3mjgv0byBTfsFqfawEphvf0tR50x4dHg8pHj6wGpBRbaZu4ytPh6g/Zr+/NxClQMPGkHYtxQyjbUhsWVv6FfAOGp/OR1CQpbz9JQUXNWTw5M9Oqj6iyaEb22H6NNXwLh1Pl/+lsUaldPw/PaNFFxcys7uVjhqPiEvFoSWkA485RZK0Vry7J03C0RS/dHk8gdcNGcqy1aJ0n879/J6DWOYvnE/ly7rh/HnPrJruCrojZqANQuF+FFwF+zc+wY0CozYuwbhzIGZ1NjzhcUWe9KK4EFojFuF+2cmQ9uXWdStIU3ftCVwhZMeHCpUo80rRdj45yna5Tmeg0uDwaHgHnntSaT5OJPNlxjh9z5dEAixY/tAP0o6LQXBshXkfamWzs5+wA0jLtPz+D7q/0M03GEUfNBQh+8ThuEFw3iMELwKlxfPg7ABMTAPukF3inzp4NIaTn0nC+7lwPrOIpSgJ4Pvfzdj3JIoFFwQCWfsZ/GbM9ZoNKMRbn2Tgfrmmfg75ik17fOl7COC+CL/PTyarwICReJcNFDC15+XoniEOuz66cPBOhGsPb2IBWASm3Qe5Xq9bry8dgONK76AZ5al0IF3DiB5UQuXVW6n3jRZtrSvolv2olDi3oA/R07h5+GV9PzNDxZx04P9kbKolvuTjDdeoTf/ZWIDKZLfgefw4qIUJO4wIMExcfArgeBrRxd/7TTjkynbAMqyqWbUe1JsWgWvx0+nd90jWfJAML2fpg4dlpLYV/wPUzKMecGic6g/YRcP2Jni20FbCn/ZwRvXXaV+KRGI1b0Nwz2FseFaI0WonICCVTp4KjEa1h7/iEpxp+DFcRs4dEUMzskj9R7ZgP0SBXDu6wvsd7eHgk2K/OpMLK//I0Q7P5ewz2V7MChA+jL+Om2aqAatN+ZzWshDDFaoYl8JX7wzzAzDYmtZOEEKbDs3s+qDQF6o7YAzD1mys8EZOB5sjC4qjfx82jf+3XaNn5vqw+zaEE60zUXxyLuk4dSDPc3G8Asuge99U/zQOgZ3GsnCtB0KUDQ/miY/iwPxtFBa0CiMGQtX0ZQpr6BuRREME91Kd3bb4TgpBaAxC8k7Ox2f5TdDxWczPHDhNc4V3Ea1gQlwXHASbdbZhcH35WBy0j54W/UHtn8uIEHnl9BQpILntVWxZe0/etj2Bjtl3sHrWlswHJYK3uMDSPqgIsq07KOa/L3orBUHZpKyIPvcEFXPTEMtTxsY85VoQUoV9NSvhZYVmXRl+F3QOxrGG8fLYfWSGxjjaAMZ+8RAdMlkWAeuIDP4mK3uv0TxjTvoX9UumLp/DfdITEG/Pzuxy84aouglPSwfRezcBPr5aRxkEQFBkXs43aMCVS/EA4fWYe50LSjLy4YFH7JAfMseniTby4ojgiEgSx+uy/8EMaPNVGZ8FV45GcPTC714pl4et57ai5Xjy+iZag5XTetB3yEWa+rKgIPCgfzioAAEHTqMzzal8Tfl7Zh8J4AW71Wgif8KoEFNhVbsGYS7YTGMj+Vgz/pq3C9mBxwui7J9hfxwpymfn7WfPgnbkq6TA19KdcJHkuJQfbKYN72wJIs5mZSvshYkXiDVfMxn+Z+78LCyP2qPcaEkfXPYsikH7oX48aB+BjoNWKPipS+U9+cMrDB+gYESZTBjmj0cXj0Bjo3ewbG+hexktQeCRTvwQ0kRS7w5BjExSALnWnj4nh5+8c8CUqQG0Ee2AaSUv3HpSnmMXZmP9TZ9UGgWgWkb1LmxNgx8XMbCl51z+dOzSF5om0+6306TwWodvLbDFha9soI9BW8gxMAN7jhYw4BoNShdXwMLRg+D261zWO1aEEhOPELSO5aTqv53WFzhwk+viYHQr9dk5nqU1WK2UNfUm5Byfj2tDS3gHZk/0V//Dqx79RCqZ5vAjM5FvMBwORUIxkDcrga8XrgSPp+rhfywRjimYEn5hr95yRkx2PUlmiNTVxK+s8cDddZc+EEeM8f44RvjPfTt1CzQC/sDkYu1wazqLM9SyuakkgTa8KKIzPIGIE9/G4XJlsH6OTnwvEeFBsZLQ32KObq1+qJMdj/Mv22Cq/UOkfSiAT6/qIX23f6HuSfnw+EFwhCsugKeO37C6f5G9EU9BaoHL+GPuoVg7biRZad9x5W73vO3blloNZ4KGaJF3Fo7mvLv1HFE3gkUlPPAjdfSoa/pKx8yOQbxSxWhw0KfrUMCufmiMOi+TeBZAsl0K9gCPsVfp0PBEfjttCVEV46F5ZbhIHNnOp9BNfRPruHTud/o5bvzaFiRBPUh5ZR7QIVuL54AzUqPuHXKBfz19gDLtJnzm0xZnOD5hVxTi2icRxdkdOZRcpspnMqvglT/xfzKfA3ecA4iFyUEfvWX6lLEyKP8EsqJmvDIOAFwHtlIc/47DMf2ipGW+Uuwnf8ZVDCHJk3OplPL18DXLG3+z10XNMWeQ7bKKj6xPg2+P91J045Uwk25PHTV1Sa3mY3os2kn7NxuAwl2ujwh9Dv9Vf1H6pXe0KwvStcO2WLz4wxQidgBsoedqCfQDJZFLqXwZf00fW8T9VUW8q++H6T26BLNOxWOpyqW868tv3DfcC34dLUFg2ZK0PAjs+mBTR6Hb6iguVaH4LNvOv9+5s6p227Co62mMDjZnFJOreeyBb18+UYnnk6chd3K+zDtbwMdUHXB1aLZuDPcCkzDm3DZfUFSr6nghwfLIHJgLR8uHwc9Jy7xiuNKFK5fw5JhlmD8YgPne3+kiVuaSF5qNGj8OYEjJ9pCbFUofUx1pqx4ezjlYgVCMT+gcZYq3VdtJx3rYHAxGwNl7yNJpnEyXhUXpybHN/C60gIKjumhxbcU1K9YTcO+vmftrHpYlHGCxipfRXXdJ7hNzp1TNCRA70EOftYWxREu1WRFTE/XFUKGbjfXhkjz7dUJ1PfvFhjXS8H5wnK8ueMCBV0qhZt6Y6DhmhU+8nSHM+fusevJS7S7VQpjV2tAvOVTiOithfZLX6HmjP2QGv/jdbeGut1+FJkc+oSpknuoeLkMmJabo7zEd3q4pYFqfYKhvzaZfJYuxtxqZ/ihlwgd2jmwpcoGAlbGQM7lGDCdFkX1ft/hfXkLfep7wQvsftKcQIYrDY58LlQVrgwmYbMFkpP4MDwsN5k+xByitf7iMPGMCwbCWehKc4WGveZg6quLsemZuPzXdJ56XoWf3BGBfClRevX8NkbXi8KazQOUPtYQNBz7+H6vJfOf0XR+lR5GPhlDZa2uVOohC/N3RFLe2Ju4ZakeaB+vwXU2L8FO5zRdPKnE50QG0HI9UYr5PJTM1sBrEi9g4w0F0K1uQAHd1zi1poR6/q6lxPeaVNp3AmQN5hH/joT8lCK8tsgCvGb30Lyh84nNdyfP8g8QsSkOdHs/06uIG1TLDXB1hShZNknC4pHzMDlpH818dAfDZaNwuYg161V484a4brZ1NMQE6OGvfgif5o3mGEMbag83o07LsaxyMhpWPotmqcXqqJJVDucjt4Ps9nFgoTqPulM3MD15gxsT2+i+eR/t/mDCFoWz4ULcTj6lo8xrmibA9kRB/E+3D0L1TKCh6h1XFkyCYce66NfzDTxT9yzL32oFy2RLcMzzRPdr9XzeaB09OaMNxxNDqUlmEpQZzGDD6ea8dG0orfrqAE4HXuHcVRPw4NZqmlg9Ea7oANtHW9CuTln4YGSIF8TukEe/DvxZ+YZGHvlCFgusaHtSGLz4nA7huhkQ+E0Nb9ie4vrZklD9wgr+/TQg44hkMtzPIKmxitM0j4KOoB04j3Ii2SXrwUXhIH55Nnyoj27SjLEH8Oa20bwuQgPG9atgp6IPbn25gErlarm23Z3k1jnAZgugjqO78bbjKxq5qg70VvylwIhYvmi6gjZJjKHUBTY8LEIfvi0qwaInsez33J1WNAihlsV0urBWivbEurK7STQInzDjgH1aEDJ1Fq+vmQpvs6+SVF8zC88kLv9lij+/OUHYCAP4u1MTfLI1wXOHL26r3kOGA+exPdaXLV6PxQ/vZ/CcKa/x6EMrjpD6jUFSVvChvZPWb0sgmxuSMK5dGe1bXdi55AnmS+bDAxdF+K8/kqZfHQfCt13h0I/ZVJNahn0fE3j4zv/I1cYTT3+IwEVHjvOB2yl0QlUe7h/7hUXPbMlb+AWYaBbQ5E8/MDjeE97fk2TRy1Nov8ZI8rAVAmnxCn6V8RqvCNvwsRsVKLD4M14Nn8AmCzdwyGgfshO2x2UeBrD7WgN8efGEN/+cwmUHnLC0NJDbg5LhYpU878C33HZkGMRNF4EPUnkoXvAa5tw7CKv+BdIj8ddctI3Y0HANiW8+T2cF53FwrTBEjyogxwf/4TzdbehWI49bIs5C+zI33Fy7Ce66WfM0m5soGqIDa18t5tn+l+B3SRz5vW6gCvFN7P/mO5r8uUjj9TWJlKNo0w1TGOgIgPk6gVwRvIHHGPpBVfxa2O7eQOrdRzlzhD0Vhp0mvfoJcGXrNnzftJa2vniAf9Ue0AjVP1hk9x/Of54EEs0/eOPsQnY0UoOs1kHw6tdjlaXf6PxUZ5wfuwCFbF6TwIfVsF7Rj9XizNFOfgI8XnoZ1s635ULDP9jSvBhWTP1KILAOE7pyyNllNo1IFEONyQxrbq+jLyTHz2wqME1wKk1KiuRiuw1wZ7ICStZs40vVI2H4LFlYouHNj9yO8/Wr4RjiW4Z43oqbvVRhR9t1iupQ4cy4SgpIYpD7KswTLlZy26YjOH+xGlsvdEIDz0xerneTpPbMhdebp/PzL2owyVAMHxe1w4+tm9FCwYSu3nhL2lke0L4vnfSfzKBjl6eghL0BCNv9Bd+P/ei19jRt6qzCnuGP2bLGBI86ZqLCQ8STFxbh5dUSYGToSjsb9XDWil+c8TIA2rwi8dnYpbA5eQL/V6yMYt0zwcfIHv6MkqJ/wuN5Y9Up2KP0HbfcjoLhR99hjoEWvTxlAir2C/j8FGUw3JoHNzVLuCR3AsukiGBoqx5JfHmMIgde0UY1Wb4ashE6xEVAVHEdOSyazaa5QeBRcZZMx2ZjQNI4yn7+m/esNOUbjrk4T1IT7nAL7zZ5DOxlg1VH/8Ds7efg6FomjeQVZHB3M34IcOF1g8Zw45siKJfU8ayqNrqa+R6vJMtwr1Y47P5ZBvFVS2GsdxbZBw0Hq7ZMVC7fCGKysXDHeCFYVswjpdcG2P30P9TyGoD+ZgEMHGsMLZYII070gcyOJ+TxUoXilqRybtAT6iqei2tuitDDgbP8MtIMDBqFMDpShUo9n8CPSndUi8ojrzUf0U7IDT1iC2DO4Gy2XicDI0UM6bZyN88VvI4n65twfudMbj0iiq3XI8HjYBVet7sNWgcdYPiIeBz83I+lfpEcP8eUVHb3cdDDLB43Yjd66dyHA1NrIKPMAvSsK0nmYQCriQ5Dm28Z3PBOnv1EajizVx9TRV358NJfsOq1DHg9robYSdo82TIczbYep3SHUXzoygbe8MCRjR5fpPuu61BGleFe51qOnrEXLccFgtiyYK5aeR4veqTwjE0nMezoLUr6EYVn7HVA7vxRrLrQQV2nt4CwuRYV2YzB3nRTdF+dDApVDzCxQIM664fy+aYeBNeepB1Lcnig5hAHiPsTvGiiB/XulK80kbZXP8MTE5XBbMMr6AxPwFelK7F6jiYsNzlNhz4ugYU6kbRp91F4NeEpxYSNArM5ddij/AFTbw7AjbjT/IzG0j+bPJS1Pk4Jh45w6+LTdOaBAVhPSKObqYXwWaKcp19LYdGLAnjTyYmSrm+ArqlanBsbCYMRUiDhPBOPSA7NyecIcJUVZ80UYYbHd0H8212+l1hLTr3RJDRGDrQ+ueCNhh5e1xRKmcMGcI3QPDj8VYjbjueT1D8l2CEoCd2OKjDCsh0fFl7Bwm1X6GFMDKzx8IXfBi3wqHgzL9jzFLPmh8FNlzGgeF+dOy6r4ONHmhRMlZzduoQT/r6BfV/vUfbKX9jGoyjxuxjYJgti3K71PMy1jC7nNWJM3QCkv3tCxt8zYfvHcHIQ0sVlZPQ/4s77H6j/feP3IHsLZYbsrayMEBIlUSkqTZXVpImIdpJ3SGVVoggNtIdSsiqFliRaSkWFSn37/hWff+Ccx33OfV3X83q8fnhB9YUnuOheMp/WK2W9+tGsGunPQxcMMFHvBZ6JGA7SpRKYdecfb7xdDR4twfTT4zq4vglmU7HHfGPGJbo+XYy7/AAndYjBuFI1kIzfCaGLhvjzP2gbdmoRrrhRgyYhESRflAuLFt3FLwknQPKdDQT1ZKGMajPvtgzDi4bt3Ng9g1SNzXHVKWF6OXoaGXdNBhMbgo975Umw5Q5Z5teDo1UIjb8zg+p0ijD4kzfWsDEfznfE4JcE4Yan2MnpKo689oP9CnuwCY5wmoUgb4pfTRJTk3HZ6MMk5GgNZfN1uH6hGbuWi2Hdyi5eq61FldIz8J75QbDwzoH8eiGYskERggQ0qCMykI3NpaDVWBhuDljQz8hhPD9wgP0nVHPnnhf09Z06FIEL1dj2o9DyOLb7ak2HDqvQgOtsyN/TS/vrvtOlp9f4qaUdaE0wx3qegobv77Fm7A+Yq/6Dv+QmcGB2GG2Vuocpoxbw0gZBkHG0xcZfa0Fu4kIaL/UE2vPl4HLiII4wtYDMMw7koRxJ5z6Mhjd9hvRunw78vpcILwMfUraVHF+HdexWK4IGEqYcLJPNvRPlYJeHLM1cWk9b1gfy7huXoX/9MS6Y8ZZLPr3hfX+M+VHNK/7ZYwy5LsF0epcm7yk7xDpjg2h9XxCv97GH1w8AA8YcJS3pbPTLHwGK83/R2OEnIPfTAAu4rObY33Wo8McEZpSMQ9uJ5aC1Np9KJJWg7Lc/fB2pRmmf9an/xiUyn3IHvv/Jgwnu4/l2gxBITfSgOZpaUCB/kRVWId7sXsV5d/tQ8Pgkyt87DCf5dpKo7S4oF1lGmS/14WTlBI5rWwxrTq/g2LbrMOBrjMuerWGnnmgY9vscpM8UBq7TAaWQPZgqtoV+f5SkbZ0j8LHXGtxtdJgFH2hzxIp1PFrkI17cIA+efUrQf7oVSg4fA4mtMuxuf4gos5uPH/PGywIxUJrjCJ3PjKDBczv2PemB1opSWrNwE1UqSvNdtSQ8myhIV7Png2npM3iayHB4bQIKX4mlpD1WUDYpDEazFwTlPaR7T9fCj2nBPO/7R7xWJwpRwnY873khh+ntBcnxx9g7rZvkh8dyeGIOjqwdBtHTeyjI3AZSp7Xyr3/vn1g+gl5vVYAYXXF0Si0DkcxkHHe1kE8lz2RfVoU1hcW4Y+ME+lEZBxn6JXwvLgCOBlax2fTZ2MB36YNvM515KA4hRrXU8b6cV0vowES4CFIByjDzZj19rZNhnQU1VLfZhNSiNWHvxnJWudNEU0z74FhnJJuK5KNM2g9ccFwYr2fpo/mtP/z7sQX0FE2AqjGuPPWPB789qEk+hR6k+lwYPe6kUvH1rXz3iQcPntGGrxVOJKr9AVLqROjPUD5rWS+H+ffqsXNjKBzf4kR/pueC2G4xmBnXwbufC1H9yTiW6D8P/dIaMMIjkUQWBtGlAwGUHncRHStGgd94S0pfa8hzjQW4x6WLayWucErgUuaKqzzk505VegZ4VlcL4ver08K1G0j+liznjdjCMHAJhX5tRIOGCHjb94oVwq5S1Dt9mCMTR2cap0GkxzDcF+PGMSdO0IdIRd5SMojnZA1YMP4ivWAnsNbdC9oVM3mxrzgPCY7iuKvTuMf8Kx9pOIm6htfJsm4ipEbrw/L5C2hL2BjKPdmFQZ7xOKZ2AUZtcofHI0ohFO25Ju8vHpUyhPlZ3jBydCBWtcjR/GcaeH13PSUvUMCkkYmUNvwyb9t8EQxk9eDwqRNQvOAaa2wNwgML/8O+8Zq8XcuWL0jNQ43x50lqZBMe6BCHl+Ke0L1/JJZ35UOGdADbV5aiSNB6dFNdRmIJyhzi2sG+ObYwY/EL6Bp6zTnrkjEuyZcNFm3m5wkWJKBXTwNZdnDozmKIHbKDIVFz3lomxX/icrBk83Y2M9GGDTcrOS5jJTpGTcR5IofhR68yLJTeAWomVRTz/Qs/+hJFovoV6LowECu+nMTc3NF0v7Uf/iwRg61p9zHcVAvFLh6A/jXJkFFhiVrrz7JUWjHEyWvDuWv/YcpRAfD+bU8eEoGQZ2tD0T27efzU07TyYTNsmnKTfP8UUfe/f+H9RB2elgRTurAFZVuEcYq8F8kWzyHlhHjsMdtBmQ1n4XXTHIjdow6Kq55BhYQ/Vj12x5SAOWyecp422drga9V7eP2CDunDNr6pLwiykbX08h+XZbyugKETz7HldRyXzurBEz37yF4giK7rNeH2HDF4dE4CS/gQJsS8xraznqwWdIGSP2jBZuEy/m+tBzYMzkQPreGQ6fMQcqYvJM0ua9RzXAk9xx5wx6KLnLdmHn0KLECT3Pv00VkBBK+chx/qQRhdmsXjC0/ijsw/2Bw8hRVs8qnmqTlrW22HwTgDMFr3CPI2elFThROEVqexw6NoFrgTStObHf7x1AAGnbuPLxN04Oi0lZSOt/mU+U/+R9csqvoSFhQyzOyNIt1BZXarLiKXD6PgeM9Neld1gvRnzcPNLv84SbmWr17159ayo1DvpEtR4zo50MQJklaOoeHr+ulF+T3eJm7OJ20vwT0tGX44yZr3RcygiUNreUmVHdh+Zlo/4ikNlPay1/I8XPvbgzxHymNA21USOLIddp10ogZnRajeXEAaywTw2Z6rdDlyO7Y1heKLl3VQ5RWLd3wjwP7NcIpcZgDHNazJpdcZ5URFqPOuCkVq54GhawAt147GIfW7aGhowh+bHSFydTvNSjvBrcnHubfyCPk/7uOFJ635Z8NYHP9dHRsHRWDmkALcrkqjH1Fu/P2oPPXvOQE6McspJuYsr3xdR4XxduRzIgmrxpjDLp+teP/wPC63H6B5dVV8QFSFbPeIUVLxdJhtbo9zR2WRVYMdlFuew8qQhSAu5gqn7xXz0MrDcF5pGrm17wNVxbc43DQRYTaB4egInBnxAz6WytKDlaLkZ7WC7yZP57RUT1y1WRhvfZ/I5UctIGfzC9oevYj8+vPx+RUzCJ/aywXPZ3DC+TJ8VxrJCetFcV+0Ifj6H+WV2wxpZ0ML3iJdPKERjkGaJaS5QIL23M/ADQFbWK/GCSJ9JbDovTnvFTnMjTtSeauEMj9a3ASfD5+Foo/t4LP1G558bgWS5ozSc0vBQPwjL91VxY8kZ/H6jvt8pPwtz7l7j9UELejbZiV4/vA7Vf3j0YCf18Hn6le6Ra9o5vrluEw2A2d/F0WlsUnkISsDpSbv+GTwOlo5P46N3h4H258DOFt6OZuJJOLaG64coydNPz7pgvT2fOjwX489Pa7sv3EGzHdzh3f29qD64RqVnpoMtvYX+VikOhwQdeaPE29ARuIoTN3sic+PqPGMW9/IzMABjp/KAa3LclDwxxJKvkmRhvQs7N3oD2Ny/8Od58Wg6u4reqK+kRUcJLj9XQv9Z6cLhkU5/DylkGdE6+HWIgHKT0X+ZDKRJUK/Y435EnBpKsONQmPgbLon/fAIpLXyPexV6Q5T39yHxoX12BZ5HBfdtOOSrvMgNksI5LpfwyrJLVCSbsXSip95V9la7rrcSnjsDJ+e58ItLUKg1WAGOU89IJn9cVlcIAQE+EFUjRV/+9xNrjpt3Ct9C7IMfoNbvSEERG+ALW41tKxWlc+82wAnt4zBL1PvQp/qbVjjr8GGUdGw4LsU/Bd6hqqHPaJdmRpYvS8PyjSr4HlHJjnpMS48W4o5o0VBer4DZH2sQJMND9H/uS42VWYhpYjCzIVl7DggQpYih7AxdQnsUTSGj4NDoLr9Gu5NLuTIpVJ4+nMPq0+Uw3uR5/mGUBJHvbqCZVv0wclyNh9bcAPWLXoE+5boUOjEe2zy5BuMjH9Pl+Zase/PDXh3vBOUGh3gyRUr0DkvHtrnRuOImdWcLPKaPizNhc+ZO3D50Fxo6teG5zbZUBYwB3T2fGVvuwkwqbMFGxYXg2W+GSdK55BpowccuCkPy8w+soNgPV8JS4W/7VY0LHsA0qIm47VDz/h9dRLu8THFmv+M4L3rYZYUHQl2dT9B+6k0Q9hC2KfxHiw3T+bUXaXguykRZ5pJw5K5MXhodzJpjN+PsR1O6ISKtN5UB11mhdJMKRk+WnUchTsFYHl6Bex1XQslj91hdNcbNlEPojXOKbxRbjtKlMvRDg8JmjNeHwofdmB9XzqfiQrgQck6SP46CAvneeJN/1xW+DKObdWOQLyQPaz1XUYSB51YrUUH98seZeXy0RSy4Tw96iW+WOtCl+9okcNjAfgyVINisQxWF+thZNssfGgXDwfXJ9K2wDE8I/QT7SzI5vfFmjBcaTtfGihiuGELygHrWU5+MvjWz6Sz0t9A87Myms3XRJlVsmDh/poEYCvtfFIPkVW17H7zAtaPdIemMU5wbGUQD81+TDaZmtAQVsdXS/djfr8bLUJnvqn+j4XnHoI9fs0wqOpCSQEHofO1BCRXnoWDrfdgmbsuxLfspZypQbTCCeBs8BVsX16KZhvtUGCpFISGXqABaVvQrhWFivowIPXZuEDlE4DzLDbpXUmeu/6gr4062E3ZTG4LLAHDbvPpji/wsCiQPSfEkZV3NEzyHMTlNTrsekIcViS/w9rxM3D8hCYe/DZIkjZjkf6qUXLfbvxZI8Ybmzw48Zc+/HxyBEprdqKThROPqf9ElxzeMkRN4X7JLlhf202vUixg1lxlsPHp5e+CI+l54UHaktSK6+I+ofyMBA5RyQMTaX/asuwZulQ5gvvl49BZuoFDp/hS//QAnvPiJB1YtYr3CquC+aFU+jlWD9WFdaF79xY4k7yH58/rI9OXClDc3kwba7t509gnuHHRGYrVkMdjTUbwn4UAlh9to6TKMczZNjRtzSUe/+UaaerfplPCl8DX0wXtpG3gSu48KKy6QjLX5uDk9U4wruI8K7lJ4pm+Jt5fvpjla3yg958ud98W4aWS6rBTOZxLShbgz7VvWbM5Ea9HP6R8rSq0Eg7kMTeMwFK5FF5+E4bF73fi4Awb7pCLhuuyuSDxMBue3e/A7fu0IFdXHxSaZsGl8VZ0mRxpxjlRLtjzkN7Yx1Jv3WP8vciPpXYcAfFlghClYsPWjT34TcmKpJsLWaPuLBrOWAzyV/ejhMMWXPVTHO/qOEKNSxT1wb9OtKWCs0W/QoS9Hl5Ukkf1O7Xw5XcrjrmSi+7m1nBGfCfYdbti/ItA/rqtENMWdqDZKXFIypmHk5bfpRgdfzo9XwHiG30Z7NazyjQ3qB/7BERP68BSFweaJKJLEw+kkpObLz/f7gjLHh/BaO/7ICSUgKF6ivjw8UmuDEuAowkCsCB7Jtg122NrxVhoqxvLtWZWMPOwK25/egI+Jsvik74hfnf+MpI5wYoL0yAt1wz0T6zkH9v+adc7Cao8XCDsSC3oFmTS530H+Oijz/Rg81FeWjgCXs59hI91JTDjQCRJ9ACbaLyGuuKvXP4sjpt0TvJth7mwXV4GOuaPYvdhC2hnaSrfnToS417twmCD1RAVfIl+Lp+ETW05EDBTCcYO1vDeznm43tGcJ7YUcWDYVkp5vB5Y/j0um9xBNd9PYewBgEulTRyx1Bc/juuC2kZ7tli2h0/bL8Z9Tseh6vdm0pj3CuTOO0HXqn9d8dc7bHu1jud0R3P2SQX2+ONM8ienw/UPE6F6xxnIU9MEx/hYsB7Yg8+b5dE8fRDMWqdCG5yGA6ZjIa5QE69MnA/7YhTBSID5beADUE88BBta3WmtTjFVhO3gcRM2042ldXgbf+E8fRtwMPHGvXsSwEs6g3JUHsDPJZbw0y2A5Z48ozsXH9MZlV3E98bB6YAjVLhfHPJd29jo/Ah665ABfnXBrC3XSXd1zpNPsgDPfDcaCh2KaNO3QY7YOZlXHR8B2ediYJ7Vf/RYejROa/OErXu28QY7K6i6MAC6D3ey0tZ2Pl07CtPqr2PFyWc4d6c9Hsy34Fr/JgRrBVgpFUUeLbvIzHs+W+9QQ8OSFs4Q/E2q46T46rlR4D5VgfUatGDOi2hYsfol/CoMAgH1dlK5vonOmQ7yrj/TKZMJqhwrKWLeKDBPq4amyvVY6GmMQz6d4B7eA+fP34VIySic8uU8XjU4g2dE9cFSoZeS0hvYT28l6ux4RAaCz7g6uwXrfzzFq0sbcPu5QHCZawrJtvHcFmpJZ/Rf06nkGvL/VU8hQQe57WExB6npgex0dVq6cASMEzmDhU3PyCH9MToZmMDHGcE4qvsUhJcbwJG8q1BxSYr67uiBuLoKXStWxNuGFylsN/DxMhf+GS4Pn/ZdJ8mVIWy80x+uKduCpEo+RMbOoESDAK49uAkkfZNh7ydf2GzgRxJS0zAzeZAUPITAu/4ORGy0pSkW72FQZyJt+fyKR6k84fx9IVR/RR5VnKzBo10UWhPX0ZUbp7Ht5hBLlUjCLrcuSP2ahT2Hyji0SJWyVh9iy+vD4HqHCZXNJVqz9C72WS+juVUi5LX2M7g4tJJT/Cwi7Xb8/NsJwl7oQfyBDPIb3sbtX62x9ZsnNlhfwZ07cyDH3RAFw+NgUZgqrCnOBBWDyaR+QY6DRwYSaQnz5eA+OnbiNjgrnYGTyUfpHA2HJ6MVcdV6dZI7hOC+OJLGjUzi4ccT8E/qbq7/c40TIvQp77YJeP4VBJDezAOuq8FeNAImCZjS9rRptCJ3NrudVYMKFT20bhwLRjPnYLrMG+ir/QJ7yQ68xv+CcX+/Qf3SYzRhew63q8znV30Iq/zn8s4n3WQ4fBZWOjwk/S8FcNPxCi57PYN2PG9BtR4veOVjA+tU26lj/DEa6fOJjrh9AjObRoyddZ0W9tSzyRVPqi2dgTqbtSCueRdfEDGAE72z8X3tM/y+b5Bv1OnD3QmJGHn4P642voz7AGDrWaSRQQMg9/gZG2oGgdyOEbz8GIG+gQVVrVWEhvR7LD1PHCSeWuLdaGHw6vsACefPsOnBj1R87yhFv/iKruEGVO42xGIZZjB/zAku/S0CkV6dZHI1EhuyenlyvjsoHRaFpOqxLLL4Muv7WsAXnWiqO3OOfzVVQI7KSjZrG+BXLsXQPlyPxti+x9ibehS8Rxms39+kYx6f4L+UcG5/5InV64wo6F/+jIs+xOqTD/IuKyuIaDMGO6cRrHdYEQ0vHqGmsl+02dAaxNp34PAJ9my8Txuq5TVwmOcYwJhztOhEEcWtvsWVqYlQrn+ZF1ano1NeEEXUb8YNcZMxrEACNj3Q53YbX1zZIksG75Ixs/IcuCevgvKaj3xZPQ7uLGnEv5J6cOhoOUhOvk03PeZy2ptg3CEwih8FfOJ3XdvZYultFLm1A2C8JnxUKOGbh16zlPYsLpxVSUNp41ntwTp0dD3IEulaFHLkJd/rGgG3XYqITowDEeUrEPgzjO3ex7Ca2wtyTelHo/+2ct2kHv4v0w6U7yWTxYAFP9EZy/o5B1hiphZYvxygyoNunOQzkwuX3IBWIRl4KPyd95/di0dfyFP3TmHel6QJdU0VbDBnEo6P0UWxgHsk7TgG7M8KUdVqV4yavB5vKp8G1elGNN56BmW0V5D9quvos+UpGghYgWj2fkhbWcHeXxbgiu0V4Nh2hVvmXiX3lUJcXFGKCiX6fPmBDKw0UeSHE/5Q5PLRPBC6EX4PPCT1qhC68PopZT2/gmZf5bhSzRYWNRrTjndq6JXXB8o/XPBI1A7eFv2FBqM08FJoPF4V3A5FCRKwZqIv/E3cQx+7X9GPqRWwbcxteLTiGrybGUCjzeNAMNuYb6gLgpOfHf3QDKXRW1aAUuhh7OhaAdKKTXC6ZzcvO/cLvxUocGORMjTxHphtwtQe60kSw8/B4bdLcfGwEXjpYgOcGXODXfgzPVmtDQfCM3mucxwb/hJn16VdNClgFIh3dYDmSwvao1sMc1Iu4rJOIZg/eBdGb4li8WVx7DDPBFO23IW21G14ZcMFclz8BmSe9fOi0zIQqb0Rx+nLkNK+zSz8tRd+B/7hieF1FJaylZ1/GVGJiSCLGSiAyrEi2Le0B7p/C3By8TRYP0OTv87YS/t+dOPnxiOs8Okk+16QgNyvWzGlUYAOuTdS4HxD2pNkAgVXvvCe9/5Qd28ri44rwA/RdlA1/CIcbcvnpGIHMEycTq3rksjMMwyvjEIymS/Fxt8/4IpZOrBi+iz8aaeAxc6tfHxtIh0rn4ZX5FL5Uvlj+CL1AQpq1bABpCB6/Tm+ckeIYs6Hg3eUH27xV4Jh+zIo7tJ9vJh3lYeb1uCCKks45PYRRlsehAcHBClxlD1FXiiBfZua4YO1Fm9UmYuOG6RQ/Lss1KqKwN6je9h23Hiu3q0NZ86WsBjEU89wQcz7x/et+97xJ91hkOKC9MP7GthriIHVL3k4czWNple68XyxU7RAvBojPhPHeNvC6u06IOWRAMF1LZj9yw/GnTLCa18S6d3UBojXXMIRk0ZBhYHN/+z+3yEvSd4+LIHqt+2GFaHL0d66ja/Ovo3TJyXg3E5bdG/1hHVrdSD3RgZuVVhMC2UzGR/54E7xIK5edZXWlKhhRvlJmpfhztlLJUFomgnZzrvJw3Olodz9Ha4MDSaBw0H0LH44zHxZzdEWCvTERwKOmWfSyBuzSR+f0f2NFnRvrhHXDd+OTd6ncH/3GZjm6o87pMRBqPY5m812wtNybRyQZI9b8soYRrWRg5sLf/pmQi/WTiXTR47gN2s1jTt3CE9a7YRzayRwZcEvVtMyhvCVxjQ0PI78cxzBrcUa0uQJ9e++h4BYYZyr+h5/j+pGxcB/z0qbjHWlUeCquBFV8ofDG++wf1zhDKtv9fCa2QYcsmwzae8/D+SYiR5BJni2di8HvlAF5y3jIGmHEj6U0kCVbw9gxzNdTCFvmCIjA0UXQyDLeTnum6QEkTUjWP5OIZVFHac5WIyKMkXUNGI1mGhG8uDn45ATYYu75eVB380RDGt+kZHJFVggmoOjdzejmvRvuO8+F0skO8B98iTW2j4CtipG8LFGW7Q9lEVPy7azqFUg+8/5i7aD8+n5p0kcdPsWTHdTgaCGZFpbm4duoWPZJaOMFfOH4871E2Gey2Pcp9KHsVqn+ec/XzuW8JEndetD875IcC+J57uBLfxgnCHuvngUzA9LsYzEcGiXkIL1JzuozNsGPk6fB2kZs/jD7kRcMbMAl78X4tTDJbxi2Eg+3G0JqX2qvFHGESvmPqNzE/dBjcMHelwshg0tD+lHhAMcG72YZWJkof1oEEzXfErhD97yV4se/CJ3HNQ3qtPujk0kXCjPpgJquDHDEEY03uIjZ2fzn0E32rUqEVsXPIKbuBEuDL7F21IuWH1UEp9sQkjMmE5n3znT6sBUNHP/RhoFx+FGeTP0/E1AI6EFxPtCuGCmMVQqraYLM2dxl/96qNrjhIIlZphpa4GSxb78RC0JQxTzSHmxHCgnfENL7Q+8N+krBm1RoU3XM6nmcCIrJJ5nx9X76NdsWbIe0oSS5Mlw9moF7VS+xHUnmzHkGJDPvAVQM3oxvi2Lxqk/skkuywZUvBThhfET7Bu/gP3uV9Aw00AQvxlHYcLrsNZHDZpLjPDiDAXQip3C3ltWkeivazjs+VzG+3EgHZOC147P4uDwGB4x3gGCBPRA8LIv9Vq+wW3f02nrOW16kZ7Gkc+WkYFmG9cqHYRy3+2cJyMFmWvSYD82cmqnA7VsSkT5MCmWtYmmCWb72QTdScj6F0w3swBtqT+4JCSPU/ojQMr4M92dPAvG+80lw+N/ycbjPyy/3sBPK0zhyJQRcF29CNb06cO0rYGQusGcmrMlYN3KPNomfZ9GfnqNuOaf/5lWgrdkPJbHvsMque0gqzSWHRdlU9DR2/T39QdccuovL4tVgZdHptGQ1xRSfVcG/u9e8RKfALa7Jk2/PSx5+is/rjkwkbY9HAkC016Q7WgNEC3axS2Cq9CjVxQFrmiDv8cMOnq5jfePk8YU0zEwTO8kHy+PoRHH3rCCkDIdX6ID+98sYfO4dmqb28yKo/VZ9bAlcJI/nFxjyEce7GKRZ/0gMnkFzk/VQwe3NfD1tzPF7rnKrjs1YNn2XdiHr8n+ehYJzWlHGVEjfhuWi0WXQlHSzJHyjxWhbYU8nEqIhtq+76B7/xslVMjAu2HhIJX6k7pzjEF5xxOY+MYSfR0k4IesHgfdy+Lpf2PhqokAKfqsgbCIFFQq02Mv0yh41iDBXcJjYOBpGY2PEOQfLyLx5PxYMA4Mh4biXmo48xhrz7/gecsK0PEFgkDJBGo5ugaNNjpDjIkZdzUM46lGRqx9NBTHuclByFpTevxWBm51+LFCxFJ83susccaZtKXfwgedYK5s/DezST7dzFJEVykbuKYxAM/mnaakA42A7Wu4/SzQDMHDPKf+Gp2QtKLe9i7O6RGHh7KbQfWPChxJvsUJpwJwpIo51hr/INEELVCr3ASBoQ7spScAnZNdEQrWg4nCUby2SosNZ/zBBUJZvLk1Bj49z+Q3Ldd5i70DnN/gy3P/7Vlwtgixqh6nR+wGMZwJxUoLYZq4NYdUtZPkdy1YOox5dy9TyIEMaMjVpgf7tUnJIouXVqSxj8Ep0j1UDpce28Gqpw84z7oKXm3tZF3T6bDjmzweevsBHtfpouvNHbRh9BX0Oy0M3waDYEz0TDL40cfOJSPoQQCg/gZ5qlbu5eIH5Zi0JJWOthnArgmhsO1rN4rHvqc8YWkOPlGLEqmm5CoWw4lp4/HrI2E8OjAOmj+Uwcv4iWwdkQN640dC+6l02vNqHNqtnIrNFg5k9TyaY0pNIGObMRiXMUktaUP7+uvAC4xIRTeB/gu/T7Xtd/Bq1BL+7ioK06UeUl/7ISiNL0bj7P30JsCYzgZfg9yAaSgdqwpv2mRQQ0cRLjSd5uWXTOhUVgF/WmxAef31LHd7MrteDySNexrsMHot10w1gwN9uvBzVDOaPwJa8I/nvyx5A6+ojBSnFdDn4Hm0YJcL9XWLQGD0NMx1nkVtQi/p/d6N4NN1A6/6dMD66hv42cyB6oT2QtduGcj3saXHtJY+iW+j158+w1+lXbitUR52qIzh+enP2Km3Fi0VjKB/RjZOSTqBIn0/2M1qDqX/FcY7HkqoPuk1f8RCaLx5HXs9rOHCmr8YnnkQ6zNfkG//Fxhz5RSLVOfztk1h/EOlnhblRJHhahn4EZkHnqrxlGe9nvuWnYTIy5vAzUIf5tjNxMnl1SBm5wY/hTXBPjyAjR9qsvTDFSR17NG/rpBAfwo+wWo2R9lF+pjocxXVUv7pze4DrTphhm6vptJIzU244VkeqY/2JoH0Cfy48A9HPHkHRdnWIHfwOb/r6UKlS5t579/JPGv9ODr+oZEjUt9B6JMh8i6KwzAxQZhkm8RHLk6iCYe7uHPicg7e8BY2LLSHqel+MDVfmXLk74BquRx4hoiC7NkmTIvYAWpj/8DmSy1copyIFZndHJ/SylNDxLDxAMOzzBRyLfunX89rqPTxG57yPI3dbqXo+kYLTh8RgoQxk+Dp6xEQP7mK3mgeACEvIfRqtSKtLm8evteGabcIKyxowY5rxZD8VRROy7twgJ0R/7m9Fi9lCdD3ax/RZ5Y2mL5Zh+zfwxPfF/DBKiNY1p/Kav8827njMCeecYCjHtLceDKDTUvHsmBNC0dGWbOzjTpYX8nAFecvUsL+3bw7N4m6XojRKqMq9Ay2wqk1Dii7UhYDoozh3PEnvLD/GUurT+QNcw9zoI0NW/69ioqSznxn3Edc/v/nSO3yMGq6PlZmvsOsl43cdXcWat2YxmM9VrBXbwKYho3Ake+PoVS7MKitLeSGfClOsbgBr9+eRIc+F1YNs6SbzlYcH+3E7TGxuNBZEZbpHOMJ5/xgskknzs3dDedW3aa2x/W87sJe8pBMhaCrxymrThH2GgfiY/kMjrnmiytqv1GabivZTfBi5x91sH9xKOmHCYLsFjOwD5qOui/DqC9gNpgF3uFw31geergJHDe4gVJNCoYMVNIq5bFgusSL21Qu0/HfRfxUbAeKrB6JsZwLNxx30bUbN1g79i7SSAVQOD5AOU+es+eaSqoe+JdNDy9Twbp0FA2+hd4XftLbv4d5wTk16HcqgwCVOMi7fgoPditSXcEU7piiChc2GeNEo4X4QrWP37hZgJvIEE/5vpA3f9KAnPgDwF1VfHPUKai2fA/Tk5ph+uYaTtuqDsVpq/mlaigmC8VjxO1npLt7F1/MWIB/Ut7zoeB+Hv+9B1RMzKBIcAff/O0BYb+TWWfkFPKx+gN9pT7klG9HtjvVwe3eSoxMsYW9BoX0IGcezzwnheeEpMnJwRJOLvD5py07WF0+l23GvORZ55XBe7QcXLi3Hx5YTsPPNvqYIVDOHustuDPuO15o6eMpDqnMRqqgPO4Zic+ygqI3B3HOhwbuWpWHKxtDebfbSZT0PYdXx62HVx6icOu5MIimieM9+/20MTuA295YsYJ7OcrL7OHZj4TpT8pHSrAaCz/mNUNdSQXuGohgmXtPOZxmU+VfbypZeRkyFj6kBY2P6el/yvDrbhfWJOxhqy0plK4rSsvfDZL3qFfwac8bfuB/kKvfb4J1xQzB6vn0bYMMjph1H+oqm0mpbTg+ieylDa4PWNNlDSct/YndkgLQ/vIK+73KhbW5lqz6/t+MaoYgDYvg+bsmlg28ROs2L8K9r0ZCo1k+d3ZOxJNix2mLbiTOGm1FOgt2sdCCWKxrc6POwd98YYIA2AdEoJfoZ1Tzq4Vx89+S+MIvFLlJhDf83cWLX3azV6Y5798jCUM7lbFByoPWfXangFRHPvkzl1se/usCp1Ihx7KQOfguxKw2BedGhNJOezzyVRYy53uwl8RbfHhMDpwj1tBpWghWf/pAbNYoOGD2lEuUvtPyQhco6/Bi/5xwCh3chUmgy7WHtvPc1x1gamcN+xwt+bN/H9T+Y7mXh/Zg4aIMqCxDELQXxAkGSfx61ljUkXEAHpjA839UoXrEHJ66N4l713ym7QOeVBD+H0Y9OQFrp6bRq4MGUDv4Fy2GpXFFdCPkJM9At2ZR+PbXij8u3s8KQ+MwPGwhdCTbAdFPzJ1xHzrLjeiq3QXqkO2HIckcjJKM597K8xxaqoiXB+zAJ+Menx/3HykpGuGJa8/xzONC9nSPBQjYxspHFKndP4OPy+nDQR9fjNruRWonbHHUVRH4fnA6zcoaJOOKE+w/Yz+b71GmRHdluJ2znma2zMMnXzr4Ukomj3V/B3dj0qE0dSUPnN0KW1emgXe/IIxf1MMN331519QHfGx0JFiHmMH7WxoQrLwFnVKE8b1tC6cXKsCzFS70n/h/XHdkPHcHX8CPOhdo0rI4rImqhG+KNRBqtQ/kZ4yGrkQH7vw7yFnS40Cs/y5OzDOjEO1yUipeCkL5oqjQewiqzUxgpYQ0er11xMV5arxJYiwPLv0Ccqu3cNZMQTJuSaFzARUob2MPZnMaqfH6B9wgdJbsDvbwlNBKbI+6T8ZuJRB1LRl/axdit/1weDvyFtT9y8M7BswiC07Dgema+Oi+EUwMkuYhBz+OH+vFeusdwa5yHc0V0qBJU35Ryqs5NO9uAZx4PhKu/MmBj2KmsENcnV+P1ARH/0wcdF9K0qMeofxNQWxoVYCzluvJPP4u6lYkc8+4e7CwVB4KLlThrFsF1JTvB0MGmejluYjWxm5B65WjYJswU3CHGV4JEoD7FvNBttmWsxYnsorzU7TY14dnLGfj1I8t5BeiijzXjlJS9CBJeRQPDDxnSveC6KQlLL/lIi7ca4E/Uo7hcDqOeVsecaS6OISqBnKVai96fVnD3p/HcMV6GTg/IYaPrSrmrZiHGtU/YfUhS+jqKiDpNH96+1SJ+99NxNp+Rfg1+gg/mfUA/Jy72ar6Nn3dJAKOH6bS25ACHHU7lZXiZPGVwUMKd3lM/atamZo96FLDG3IebgiW0+fTiiObcPOjmVjlkkeP6DrozNGgd3IBXDQjjg2Em3nYpbGgqaiH7DOGx9k40Az/X3xff4COP3zIy99bYcEDG94QVU7LlovA/Yp/vvEqmMyeb4XwoEa6WywIc+IyKKDkLAnPyGazNSPQbeRY2BJ+CMeIyGN/dwfHiK77x2mjQDr/NVk9S8Pnm8yg9/c3evrMClJTDtJmbzFY4yNBs6eqcvi4ajp0z4s6rIJxStEz+PRzGKfkETSu04KxMmfwuN8D+Hp3JqjK1NHx187U+eImGw2uxSjP1RAwXx72VUVy2outOG2bIFHlD8wAbyr3kMTXV9rgge83vDfZGRPmWIDc+DfYo6fGNY/VOF1RCsYY3YGU/V68c1MI2uz7Rfldc+leqjW4F4eB70tNbI4bxvmxh2mC2nl6mzdAdvZVfHpKBBfLzWcNG00w7ViERX/E6EOsHyxpuUz2UWqgmvgN32c+pTdvd9I5U02SDheBxNXpEJltRzoXxkHWg/28eeRkCPprSNWXZ9EkhybcUbCMyuVtQFQhHduXhOLw/ZOp2HIWJLyfA+dezAKpKFmu+rqCle9NgZJ2ZTi7/zZPOJgL0hN6+GpBErV+34OJtdpwVeAHTjwqjamiGRC2laA4Ziq8O2nONecKSUl4OGpptOIE8yT4deM/XAuv+JdeLm200YcLpSU0scURfpffR+OZQ7CkPZstpj3FV+cfQ4HBCo7beR8X19uAps9+VMq1om/D79PG45rw4akO1ayvRhXF/VB9pwfNL4qAt58oRB5Kw7knVqFOkhqJ127gLd8EQDFyC1YcTESJA2b85Vck114bBj3hvXhAYzTmLLIBiYFprJVXTEO4hR9svsy3SmvwvM0R9rpP0PdUnHbEF1DL1Wo0P59LygJjeLP1du5SfA+tzTNo07JuUJsgA6+N+vFM8090ErjHgn33OHGmP8kFSaK3Uw6rJD3A4p3p+DDCHrptSzi47hrsPpoA2QYuqDfRBb42LIVld5wgfRvw3hI9jLaRhTw/UwqYIsOB6q6c1TyGPqkacsgZNXR4sZ/vvSzCG9dH88R0Ifjt1w2CuY+gN+khH4q6TFnVzyle5xGfPHMVLepuYqWYPl6aPxzmGJbAc+t58LapApaOP0qjl7rgnH5F7A05REFf3GlxpwsYTFOHG9+7YZGDPhfl+tCcimvcWzQFdtutwUsv0nBeljyPbZQjpcP6cHjmED2WvoEtfrIkUxYE/81B9nhqTDE1TpAbLIUfpl+joklC8PX6WS7JrMeplVb4t0AaLzmfANelU2BMpy29+2MKq4SLaPGDEZBaa8TzP7byt7fuvPHNSBg/tgfVPrWhtfQ36mmbSj8X36L2phFgeyaPX5Yr4fhJ76EmUYHOe+dQWdV1mmBszDF/slB+z3R0qzcGi/kaOGJMAHyV/MvCLmqs019OIp0+cH9bPFvonUZ6GULFg1KgbVzLbcGz0P/uFJ5bXM6fFEt4ICsEtvNo+OTezy+rtenLOwPIzF1DESXtdLO6mEVmJ8CY85fpzZplGBmQSt0xvfjjmChrP9GGssPL8YzOIja0+o47Q7wpA22h06oJOkpjcf/tIi6riKXhd8whxTKMqwVGkE5VMOeemEGb8+yo+fUG3Pa3G5/MlMc4QTm+4mgLAttu4bK/dqi0VpgOHJ/N1o2GLL9tHY8QiwbZhyGg4WMCZWmjQdSnih4dNcSPt4tRp2QnDPUGksxQIanXLYKDN9fiq8sNNPTdGFbuNqd1xVv56bZYvDT2N87Oi8F7KZ8hLP0KTxHby/6Tf9HoNXKwPaKV1Sd7wAIvOegpDuAtI/9yn3AMebja8tDfEXQnO4f2JYrAKsmPdM66HJbFecCa+Gf81O8Gz7k1iftfKcPukHMU39mKS5qUAOEYXVydxiHrYsE1aRFetbWG2SWHuHnzTm4pMUZTmUZYnigJ9maybLNChm/lr6OHJMM/RPPA9Mt3yLi7mEY8noQ/jyhjv4Is6Ioc4ieaE/HVbQlIrhqFnePkcfrpO6S1XY56mmfR7NoK3nhJAf4rjEBprSxWqxQBn0nL6LjAcBTrToXHbmGkZ3kZUnqTcM1WPVA0HkMVoguoauNVGG34EQ7zfNb61+0yw76CpOo1+LZcGC8slQbHMe6Q070STi/fD7EuK8DFTY4nO8awzz09NkjShtkniC+rG4On02d2zn6Iz4KG4SF3cby/YRzNVLYmQ+Fp3N7rSx88V0BUmyBonU7Db5t8OWW1AX/U/cyPD6vhyBJ7frJ5BxbYX+Ds5KN4X1wa5speh+jMDG6am0LfTlvj6omSrPVhI1q9XIazdrpjuMJsXjtDGPZGpWCqwxNYJ7iX/CxG4akfR7H+9yWMCQqBcdeFeWj4Kgj/pgWXe7PhP/lf+J9zOI7y/g0dpgpQnx/M1bJHYPskaXrbZYHbdqiDSfs13nH6X+ZGm8EP3SWgfmQE+ikVY/OJzyj75gBLrs5huWOGsP5vGTSFNpL5zVcsUuRNbto57CkawSs81ejEdUfw3z0BsVUaxq+exWITynjOyga47yqHg59HkHJHDq+2FMERAytZ6gHzrG55ML0iRv4Zf+nONFX+pFeAIfO/YM2wclq1sI60a2JQvP4Qjy2RgqfSquyzLY5uj/6EvqVxUHzLCyIfK0PNxg4WCq9GPad2dloyBgoS1WmmXgLvKw9FtbX6oFCdhQmOP+G54GwOiT2PVtOmctAEETBtbKJTdwFrHh2iEYcm48LvdnR0zSpSVUvGijJdCLcmlM+WgVSUZoWZgM+2jIPVJ4bBpLniKLouDx9N2MTPhPO5bnIuqffKgVy2BuUsOEbNcxeCv0IrC5omQesfcT6cxLzr9wO8V+QJCz1Gw7Lccjx5xIpaogN4UVY63Ok8AgdfnaANGd/g/b5LUKfRxak/9KEn8SvNWbQXdFdE0J4oV1bsTCLNlm5MbvWl0F/7adPUSSi+QhRqW76i+zdtNvn6gZd5vIdO4+v4ULKZfy/WwRf2jVxZVstji/Qg+IEuv8j5TMNd7FHdMxDkZErg8c4sVCmdzjdzDlC09WlI79OHCZURrCNwhuNX+9DelRZw5rcVhSfp0Xd9dzKw78GYKbXsO8kBrA88h/jy++CdpEiFb87jCq/7XJ4UjsvbMulOVzNnDCvm6++GQbL0vw8gcIvHrN6Pl7bZwYPKTaRSUU0NPltAQ8oOzvvrcpWIKaxV92X7P0440XY7Pwo8SBbp1zDZZC959iqA499D1DtKFsR+OkHxi9HcHxNF7y5tpWrtp/woaQoHa3aR5a0hHrqaz6Wvr4Nwpj1IRnnhfx4msP/nClr85Cw8bmdSOfqI2jVS4EnOPGyTD2Hz2Trw+sRmVrgQzG6ndlLYynAwfD0AdzK2YbZ8Pmy9dpvnGBXjJjkdELHJ4VOlFzl67Rka+b0bG9r3o9eMAdx6O5DeOh+HplO+fILMoHUOwi3fHxCidg73y7xnhaDR5FCpTo+kD/HAjjh6vK8RjdKtoMD5HN1yWQcXbgvB+w0NOPnhIHe+OYqXJq3F3UHJ/Ed/Mj9TGgt23sUssceOLM+msXv0SRg53Yb4xQ6sP25LjpVV+OGFC+38pA2Dqc84W0eOZ13Ko/OrpkPLhSxOUyzDNwZruWGRIZcIhcPX4zawtt+bBI6JYNjFSjravwLmpj/B2ZtmY2KrHKwZJka9b7MhP1AITPWPsfWkSewsmk7hr5S4QKsQfYfdgHy3vbBJ6Argy1JUmErwIXcqrXPuIpUVgfzyuQNed83DaXfEMWRNCVlPquUVQ00olD4WBp8g2PeG4ZErOrBoXwQU63ihkd8x/hxkD1qJZSQT+wV05yqAStoZ+C3ZCm/WJfAb65f8K10fz95QhXUWDfTXbyQ+8XoLr0KVIKv5NHh+ygQj6/c0XGcqnRyVBNtlgWI0yvF6VDaf7OsEpU8CkH59Bq0Qq8PhmRHwMbOWpks+xssBM7Dw8TSWf9GAuiV1UBLgBKayD3DPgpmQOm8XLRCIwgJvZw40egz6Jyxgb8cnVKrphDNh5rAr7judj30GPhO6QLwBoHyNGMrP3ojbdWsoQsWC+tWW8+T55qDiLI1P5xVT0VJ1kjPexSuEBag05BEullVDJ7pFdXWydHyCLmgIHMN5237Ty4Im2nrLExw6DVHydz+h8gUQi3VH4YwBkLuoCdaz61ArvZieR7ty6PeVsGSCCadPMKHvNyugxfov1WMB7ZwlDt2O1zhsURVd015G39rUaOJeKfr+7RzJnV7DWV0W0Bp2gJe3iIOp5m+8d3M3if1dwr63P6LGBHUoujWevAdN/zFeGSw9PRZ/rbOGcCdbWvOpg71/e1L37nAai9GwQfwpLc8Q5NkRv+lT4hxwv6YKW4efQbGXvhjTFQRFd8fDYVVPsOh+Asec3UDN5AMErnSmkdKS8PpaPopWhWFn6HWMFtdAUdVetlIYh1N85ei7WibvKHpO7W0mcPridXwiEMLdvII8HKRRYukPNnx7h/0/XsJulWo49ScPJi3WglOHxcnu4iAnvP7Gzy+ngb1XN49KIHowfwmFiF8CzwuGNOGtMHiI2pPel3PsEvYAQyfPhWXb/+KPUb/gR80unJZtDg6Fcyn443DYPtYfLryKwTm7vXj46m949b+tYPDJgEZMmYFaR9tBrSaVdEdbwd2ximzo+hc8XBnOt6ymjVqhyLP0yEBKGpdP+Y3BGUcxN0QDPJuLSO+2JSq+2wISYkv/7WcfaRzYhjd3+XPi4HvcIB/Av3dow475rbSqJQJOd/Xg1Yl12Fy9GO0lDqGdiwBec02j/7L38BlDM3havAcHvt5A+doqDjsZCZ17vtO3bEF+usGU7kZXclOoDS5y0YT+PW84QPUQL2gcwZ9CA9juTwZ7T1GHENHxOM5WCluTSygkXh9OiOry2x3hNP/lPYwOS2ar8bmctyQOvk35hpPfTGeh5RspJ1wJjrYKouZAJuVffUJR22Vgjm4ILfCzgpP9+vSjbynHx2VT6zRzUHZ8Bn1/tSFrojSNKnQhvTFx9HPvRLTdcBJ/mJzHhYtng1SoDqjv7Kcxt97wF+iD9IYVcLv2Mj5bnovHPR7hsYWfaHZdPVjpyIFQwUn4M+w5+K3+CvdPKJHq60+wNnc6Jay4jB8TCmG6tRmKyuvDPD09eCH3CKz8huj+8A34Nbqd2zPWk8u7I6Q/XhiF12pT0yMzeNvZSb8nHUff7Bo0Fi3hyG0dJB+mCLHq67h8xzCQb94N57LEQF7fCxZc3s9ypudhoEeLlUvbwO1gNfcuuYpTZq4h07tHUJXMoWbPKCqKSwPbL92kJZHO0rtekNexnzBSxpL0dp8g+1NqpP1RAZpHXGE383LUSNzKRyxUecOqYJLZMQHD4lXZOngU9V8b4kzVYaC6u5sdH7bRf8a3oCRxLLrHZ2HWxGoqOvwYHH5uh8+X/SGyYhTMFFfkTsUh2jFQwx3CovR65GUIGqkKyknbWFnAiKl9FObqjIR6PSuaPEqZPoYNsp+fM77LXkcxp7TgtpQS7pvvhDKnSwH3m8JueUtcMecJiKtuQl9nRZRw/4rOi+WBRAtJ4NN8GD9vM1CaCLj4bMCEj39xiqsnfK7P5ak+ZjAlQJY2fR4G8Q9WU/vefOINSjBtdgAvjrnJ9bdO0pehvVzhdRnMH9ZiZ+MBMPIZzW7vIzmv1gh8NJxQsuEdbE25iSY/BlnV1w2S4xeB1PolcMVzOvfk3YakGoIjgc8wemwJzWybDaX/+OGh0Wv2X7eGijTU4HubDpt3CaDAawBz0SI+87OVHto/5itnK1hmjgdmb7jHkdVCOF/tOYlFZaGQvgj42izFicfyKeEGwAvVRaAX/C88Eg3AT38trl7oQndyhHjbJQMoLMzD6+0XMaBiB/rGSrP4YVV8eVKQOPIsxuyaAlZfl/GS0TJQGXEYTJZrkIrdcj72fio8HzkVnxQr87r7Bnzt/l72XXYZlE6og8NwTezaijwmcwFYVQRx3a2f7Or2Ao52NyOLmlOL7zLY+s93ZRR12bfJnu6lD/JfyRc84+wjWCP+ixS/f6LDi+VxW74ovHigAsK2/mQfeYXCyi7zCDk9epu6D42/eMDC5e/hTUcR/R/F9v0P1NvGAfwaZO8oI3tkZpaGjJSGNCgrKUKLkFGphKSiMpJoDymSliSkoZIoLWnQoFJWGvQt8Xj+gXNe53rd9/X5vH84/zxSuCpdGkx/TmeXuX4wT2cFev9uBakdm0B01l2aEi0Aj+WcQbCZ0TPMFsKF7GD5C+aPrv5U9rMRcKc8dCup07g6f7pRGwYDO67gjx5F2L+0jwEOk4OJGnrKGsI7L0FaZ+pL4n4/KM/jJWTXF9InGYB2uzBO+qlHGuue4rn7ffT4vCx7PMtgY41L9L2mmNr4F2/RJlhQcZFlh7LjLVzBgP//M5v2G/vPPOYVvvbY+HgG6Z3347/nx8Bd+RictSOctyddBBNhaY449QLf/f5HnXebWPeQMZ758wuSmoeDq8YoVJ4eD/1NWyCj1R7iixrpTasLDotr4Un7a+FP72JOEBwHvzoms8a5asz9nQw2K/5i3ql30K8Tih8+78U51wPIyTiFrFZpQZrZaNTUa0d71xhQehVDKQfu07kfZ1lq1QqsrO9AwUYjSl41Cpy/OfPbtoMkqRdBx4ou4phOV55rsIUar+0A+5r50GtnyXo2FuDa+ZGN3+dCe4wdSwW7sEFYP50+PYPGGf7jLX/kcdsfe9ZbJwG9zV/gVXsgrxk9Cy7eaIEDumVg9Psg+w5zB0+DNtp7YwO1vdGFm0W5YFWfAJN8iXHQki85yEDM98845bo3pUpbwYCEBwrtUASTEHM6b+mESZalfM5UE+RiSnmP9VII/DqUUylDmetrSrr9NnCzU4GEImWw6EgNT45+iPZjVtHt8V9Jt1cN884ZY+RAKSp/FIfFlktgTWIWxEc9BKkYNTjwRY463IuhbcpUWD80J4VRJRzyzRyKLc4iQQ0mSU1H+y2b4YvUVU503Trk5C4+P9IZ/+l+gowQKTj7rYSiWxvQa58qVBRe4jnvSvj45NWwNnQy7Z7VDsrPluDPPZZgqXIcVMKfoEuQAK2XuMLdq0pI8/xM+FiwDU7Gq6P/40QqODMRDC6fgePfH0BUw0by40Yudr+Dhw5bcoFPKX/afhZF5SOxuVEcElPryL1JhDWXxeFBz1l4rOISF44h3quxhrZ8WQVrq7SwumsY5MoLkXjodLz1oAl+T7uNu8bvhNasDNDfcJa0H4pRvJIIX6o1gtI4UxK7H8fGI8Lgooo9Z77ZxIEN6STTQRh9YT9dqv8O/XWKsKl2GC1ZtpEvzrlNk3aVcPGteAxudePS/J3omfaP5Uf+pqlO4+HFfx6UqOrA/6W/JfFhRbSwqx6UprhCm8hBWrxMj0/4/obJ80RA6FINHB/spO09m2mkjj/2jryFDzTqcNWJ+XhpdSD1vL4A4VuF4W78enS+KAW/Vt2k4Q/TePacFnQOnQofHVaCk8le7llXhwaGk8G8MQHfvmzlp8d90dlSDEd9XAx1Nfo0a8FhuORWDRGP7tBzcWVw979MIq/v0ArdNDz8TYF3PJ3PZV5zYL5hGL7HHJQ7+xnKxEfChF/J7NHbAIPhwlAluxt6VPdA2A49EDq/jPKXnEQpuzRoj7CCy6UvwadgJtdffk8GtY4wseAwD5yIBv8/43BKuhsvE24CLTUTGGcvR6frtvCarYqs920yh6fq4LelNzBWTonizT7jt2NP0DNbG8ZKP4QC8WUk4yfDdwO34kHdA3gpVJjfbK6nwNXCLF4gh8FpArDgyX6SP/gFR3eUAvYkU5nMZY6kQH7dogQWURNgmloIPJOWg+yBHAjQ/4nbjp6lXPt9vMInhuXP60JisRc/lt/EkwqOc99eBYBH0qDm3s+vrC5C8+fR+OpdP3nsNMJ1duoYJKPOr5d6sYyINHjsC8I+3Qskb1pH0fdWwO8GUWpf8wRC223oxbYKCh14B0K2yqArcp8H1inQtZge9te/jtERkkP7TQpvLHrDG2eegu9vwvGKugQ4CjbygwxzvrNlNX0hT2opU6IPf2bAdvO3tP7+bzIUk8BxUlpwQigEMl/KoMCZND6wx5Ik/G7xb7kGmDWlH9+sPcoZ7dW4rHQs+KmIU/uxZnZMGqBqrUDW+SmB0/eo0+qmRxQavphqXVtg8Q15ME17BSLOa6Bq2Cx4ABpY6SiMIsOtUKn2OQVPPwmNfrk0eFYPTvTYQsr6TD4YS2wSKoQTxjvik6HMka7/w8EGkTDR4SVbPreCgOmTsEjkOb6InAy5FzoxPFueEkqf8vKO0ZgqEoAFJ6XZebo2+Ax5ofL5Ljph2gPCfQ94+oZ8eG+yk8eUNWCSo+eQjy7Qug0A23eOgamPHuPOlbcpYGU/56fnwEJzTWxSXQ+HrEx52ZsH9DiHYeSUa7DrbS2WrQjFSc/3ovTr+RgEKXBgxDhquaoIRrZ+IHpABj75z8I6z6PsGijE0+5qU5ftXn6QsxZm2DD/jF9Il/eX0MsHmrAkZSiz9V7AjBIHIgkbGnkpFg7t8YSxmVLw7MREkmu5QgLpIyDvRwLvFB8DE/SyQeHCaroe1EXfAl9h2rW3GHVKD8s9G9B0mCYYaR/i8rg0HJjzGkyO2dLZFcvh8owb6D34DJaduQ8fDrjAEgMTODvOjn7seEnXTjnx7g33aaFZMq5qYnBIDMY7uQ8obZQtTVgpAB0rWiDl0UkY6J8O3Q+3wtY8N/6je5vz630ANcQ4+MJtnnJ/NBy6vh12P1sLEse6WPb3Z7jvpQsyKz6ShcQBmuayiXMcTOjmYVFoCFoEqWecYeO+6/haIgzpUA4rjFiPoYfm88/TlsgGtVDbMA7+++rImTpvyDpgCw5mnmbFF6W8bqE/7NOayl3/1sOd3WP5l6M8SIjexRDda9QQ2cjucz9iVrgGCe4lDloRhKpCCfji8W+802EM4opb4S9Y0lGDMNZ1/4TheU/QYrwFr1A4DRWVi6g4Xojf9ehA6OAdOqwgzoU+rVjrmgCd0v0w8+kr2JX7AwOObqFNfb44OdES3CdI0qERcvDD6h7tG6/HHg924bS5PdgZYYO7eh7wRIdZPFZbDIQlNoPi/Pd859k07HQKYOvj0RyutRUUe0ugMHoa9Z2IgZuzTcDWThlelyXwlSvXIO2EMi20DsWvWISmRZnoTeXQaXSQ/MwIHljUgZzdK7wXYgHCv9PxsdNmXNK/Af9MnwzJw2fCNMmvsNVHAKx8X5LbmXrodU/C6c6R1LjcBCVeP4bfQ+7RLI3EwqY+jmnRh/eJhznbUgLlXszDNQtCyNPShCQNPnJ2ryJFS7VReO8sDN8yCba/GEcqk7tALTwZO8IA7l+/A3DGjLZkttKm1INsm1VJ/0JtwX6fLL9pm8PThJrx2Y1DoHM/ln7sXgg/PtjxeKFyaIrQ49UX1MG87yiPeW7JmTsq+MaI03g5bCTG7FBmrefPud14FabP8YWNajpQWfSJZ84+gHYBE6Hm7l92DJ0E5eEP8UmmKMcddIa7b/bigTJ5mKjyk2Z0POSMWR78MbGN562Mg20mXjR6ajAp28ygVEd/8jllDo2Lq1nqRDdecDUlrY2feJmNHQe034PMLldqzK9j1x1GmPBaB6yTGqjp0nrU/hHDmxpm4Pzjf2GrRSALFMXwx9gK3LPlGHYoCcAIv0b67+Zq3L+6Gz4JV5KgXwuFKqpCgvJ7GisWxW4ni2DtdWlwEJoFHdHiLDStmNvGNqPJ5CO0b+ERzK4bROvHy2H0CScSHGcLK8610LSvN3Dh5XpQEH7IgdlN2CW5g1acnI27dltxfM1rMlorDAE30ul+5kQ4H2FM87MrSaU0lLJPLuGcNepwIOgo2vuthn1XrCBZXIc/rj0IPgoPKbTLBI28F/BaS0VwjtiLI5ZJcl7Gfj5fy9Aks4Abm4Jp84UDZK/ziU7Cc7RrOMHJ3umoZ/8d3oxJ59OyarBieRyk1/6F2QJaGJvez4s3/8bFzw7TMW8RLLhmQkLHBehjrjwsNkvl7y4fh6zXy/8kC+n6zjpQlorhBb0xVD/+Prg/n8dZR8fCksQE9oZl6LxxNY+ZuRLWGy6gMYNlFCb9hLNW7uSXHm9xm5AR1OU0QP/fn6AkpQ23X4+HwrYhy825SAKik3HQKQ3vF9+hUfUy4GhqxO/mL4TLrnvYRfs8p18+ToE/19KqPBt6XvUBnl4IIKXParClPxjS1MZQvFEabKmZQK8DXOHTzh8Q25/CLWNPQIdZE/ctFYMfH79AR+EakInV5dvWT7jj9ivMpqVYLfEW/1le5yq7eThMXw2O9RJKXOvhhceUcNP7EBDTTYeL7yP4VmIYH9Efj7cl/TE0eyzcwQ/8n8VzdBMwZIvv62BXjSjdfaOK4SH5HHG/ioNCxSgtUByyMvvZMEEUTbpfgKFVKLefPkCXUn5RzuqJcLklGBL1DuHMcglQiO+COVYDNHxXJ+v1E3Zu8kQ/9//A4Ns3er0xDPLd1LlxvT4IqxVQ6q7f1GMaDgbDK+HS9UPUfrGK2+KG0RS/crBM9UIFFWNoj3xNkvmdMDo6mb2iO7Bm3U8o2kXs+mox2zVPxmllM6BCxRaSHEu4zG4VVfoDH9XyxbMea1nVN5I/bhJG4x3DsHORHJfeZjh60I1J2ocFvDvh/g0Tfr6tAdPiPuAGqXbMP/2U2gsO45JYAWDHy7jI8wQ/LzlDeWLNNDUlBFyexlLJ4SDaYx/CXfE/yeKWJOACP/AsGmApjV20uScJopS7aOfuJPyyEjBt8RmOzjVit0fq8GBVGrXw2CH/rOIskSDWykR86TPkw+h6sL+1DBMN3/H4NYogRPLoEHuDfn+vpdnTHoCrmQ1sexYBL+5fxy8G6+hskj3OaBSAsIRRuP/Wdwj4Zk37POPwTZ4ZfcsOJ1n71bBCZSH3R7VRzUcL6B19kFIilbDY8S9MHfr2zwtW8Lg3y7EgZDpZftzJa7d/5y3vtECuJoF9bkrhl+FZJL5EkONyb1G3zlq4pGKCMvHGYJalwMXmAlA9ahl9uX0D0qSjuWzLOraaNgGn0FxStDqBw47+5uE/9dn0uBZ0rq3D2aLb8e3Kq9Cf1kcCEb/I+lUeWf/3jA6Ma4aR5rGwR4IgweMb7Su8ynp9anzMbSEKW8+iiNA4HjSowsG7KnDJIxcs/IxA8Iwl39j6gDVSkkn7wC0+Z6kANT9nU8yJSNodkspieV78csAUJO89QCuBm0xz1flw0Fdck9dK+kaj4HgxUFSsBT3tcuIw/2GgN3s+z1lpyJEPDMFfbx1eSugkrxPv8MRBT+wc/pi261fyHhFBODqmivoMvlFhpxw4RbVThthjkpxuyf7LBNlBxo6mX1wP5X+VQUE2kmQ1dnBTdC3deV0Gq+Xvw+o3zlBkW4Qv19+l/sZsWr/VBgr2FUBHkhZuGi4AfWrreO9iFZJ8HgKVMbfJw1yQf/iv532/JaHojhYmZApg1MurEHq4HdaHadPjEGcI2mnM2qtf8uIIP5wbqABSX4PYftwotFT/Cx7L9vOOqtNU87mMCvW34NmHUeQZ/pmswxTB49FB7v0hB7qbWqn91DvMeGVOKd2a1JFwnlNCzKErTwFbpsnCjfZq0ukuhJRjmaBVYzj07jws3f6bw9zFOH7nRtjhb0xlb2wgx2UvK7xRopRDdqjcYAUnDVI4Oy+Avyw8jt3PGZ5gI+pHKUFZeiRkHLpCZVmLeMWkr6j5yhz6LgTC4NJo+p6UwW11NmBdPuT7UhtWtFgOGT8WcqOoGtfduQEWpi4w5asFDyyQxcQAMdp2FyC6ZyfNMZbDcN8MlN+4jra9KKebYQNY6+OAM/TewccsxvvJQ8/7LxyzNjaSWPEAvep6Tm2iZdQaXINXTG1xeNdUCvhxB0/NImi+18QWmYtwu0gI5dUWcuEUAX7Z+h+HzVhL61YWkLRyC7RWjQHjDQspyHQCGF4WA4OOqVB5s5+WO5yAo9Nm0LVNdZRy0QzGzjOGE8mMP5Sn8eXRhrjhhCl5LknCSQ1bSekPQOhiNX40eI2dNdTgSK0qvY1iLDhQhnvuxrDvPRW8cF0KZl+bxWeq9kHnsGxau3gcrDPaTmvGPYaUOjNovbAOrq+TQEMaAJcX8mxlXE1poh/415Fh8DCtAkot59Gph8g1M9+xZ4ILfngphwF2z1nCJw/z4/bzRR9NODJYQCP07/KeF2HALv9B4If9vDCkm2qVztKctQ00TkeC0hUnw6IPcuCet5btVrdRRE4bLL0VRDuPb6U9FYto/K8Ssg0IBTBQglavNozsMqQ6wy7cP/02xD6LpZVPPWF8axTIWetgAK+m4AcSkLXVjZLKptLN+P0UtXUCPZ7gCJabutDkvQsIm7pDYYQWlzoqg7n0GMgb5wpj7Wzp0lctTD1pT5KzxkDC6zn4Q2A/uPT+5EItY1DfcwXP3CcYd2wq9b23oN17M2BDyzS4ca6c454q8hTRT9xoIAVGFv9gipcHhUpV0+eZiCz3hXZOHgFX219h+fxHsC9nGVUfFICFz95SzI5YnCkhwJesSrnA+ATvWJbEof+OwMErL9kzzp7vH1IHM60IuLi5jWIUH+GImVl8oraW9H8I0M5yPd7cr8afN+nxWSdLWDK8FdXKxqCQeCC7SndSYeAXFu5/R0v2aHLoGics05pH00sEQKltLLwtcOOzl85T7+UR0EMDXBn+my9N3kN6wbIcrdsBkrZKsHX6DAiedJ3uZ43Dw1enDO3KNEj9tw/bHnuDUkQlzTMPY0mzyTD3RCsNtulTbu4qPO6pxvDyELi+z6XK/uMgsf8fqd4VYp+7JnDwzGXa83kyfJnUQbqOQSjRUIBPj6yi5rdhKDP/O3pu90d3R3Uo3/QJb9fPhmGvvGmxvAM9+SNBPXYugBU38de8WJA9OQX07CfBy1KC/WcLaZfLEnIYqYHx+I8ismPxyYJueK9/mB2yZmJ+sT7E66xnWfNqkvI+xeE3Yqn73SAcm9VFOhmPQF/djcQKAjlihDAkOp1mhQMO1D4yiq4O9TJduQxwne9OU3R7obkwjUvM5ODsZyOIqVoLFuer+T8lY5j9byInJPZDsuBofqb8Hfac1gTzD7+gzk8MwmOnobHkB9gQkQgb7HTgX7MuS3SF4Ja5JWyQOYM1Z75EaJKAYu0BCNe/woYTTFBoWQTXzarFWBoJpnICGPIzjSaeHg7LL4+CDPsWpIlekFUyQEL2lyhsZhrc/FUJdi++wLqrXdz5qgVHK9iA1MdY3F5pSCKPnmBY/jdQK/pMRV/WctUqN3y7YwEkhrrwrixb2KObQL6Bt3hG21FY0QlE2W54ri8TbPodMdH6L+vsP4TrZRRBuEkafbsaeHTKPzA7swIbKtbRN6scXnQuGiaUHoPq4ZvpX7gSrBAkclCww3qjeTxpuBCKntDmk45/oN7UDrxW3YPAci8Y12kICy9spzMrVKFkVDMFzl+CGzbWA4UkUcKvVZR/4ymsFxakDcXK4F7WS+ZBauie2s9n8ifxm0mjIMXbg40k/hDv0ORvKYMoU6wLgoedOGlELeuO1IAFS2Rhx/vNvOSzLrxaIwJiOiF0RnQyx1WLgfaJIBzz6TD+rK3C6Hwmubge+LIrENxk3vGHaf34uCIOFG7Kw8Dcf6ywANh1/mEoeabHp+2OgUJoFzgVbMdbl47j2klNbPRTG3Rr5+PN6svoHOLJpdWpuPlQPXXqLUaRIxthl7ED/dezguYttoJDhXNJqtEGdvtHguJ6ccrqR9Su1MNzXekouX4JZN14wwFtKnA7ZBXNEHuJ3/cspml/P0Fx1TGyFLwCrdMmcrBbL44oLGarw4ZwPWYRzk84AM1nmsD9w20IUJal45mBFFB4GvIyhVnNvocark6AR6XBsG/TULbRcHJ514AqEvVDfm6lpWO70X/EkB/t81Atzgi2/1HDRIVI6tiWz03yw8Ci/CleSyyigtDvHOA7AqPV1sGIrUpw8I4zmEiORpOw7WTeDBB51xq+TM8hzcW5sEn8C2dI/AbBFQbgJfADF1U1cr/MBpjhZQLiccHsr/WA7W/94FU/oih32V5wDNEH91M3+N4nPVxiqsfyFntob3Mi+HYH03AzbZJ26KOF9/3x8dFJsP7dATwW7wSbJH7zWtuHeMS5GXKF/WDCTG+ua/fmac7dfPHXGDgsnIuvY/1hW9YcehpQDrdNpTmzegSnjHJl7cv6dD4ilZzOWsMFP1fWrBdn0X3OYEftMP0/H7ohupRvcynzuZX0d5w1J3hMhjNVYhz47i8+qn0PkcLZ3LP0E/j9cuXhq4xpXqAeFlVmwYtpDH+XfWFa2Q4imjtB+08bD3xIApm9l/nolBtwPuYTzLcvgXPHbOH99ad8MWk5ledMJfmuCuzpmoChUqF04p46TnNNJUktc161xQwU/O/hmtMdqKCqRzf6b/NUi09wYrcLLM/3AJmVa1j5wyzu6xYGUE1lrs+lGX5L4Pe+ybwoIgaF9sbh2+dSdGTtOTBPiMXnl0XB9L4H/H0yDyeP3U/Tl/bCjMYD0K+9iiYqX+dhsxPosocoLs1QBzkVUbjSfYa0r4bjpRf7EJfvgvmqvvx83VOKalyMp0wH6FC4ODgvqeCr4w9h1MO/ZPK9gkY9reY1Xp9w+3g59ryygBTUHFjlzxiQeFYBUaKqpFpTQmpqw/FTkwU/vpDF4+XuQcKhkZRwyBXiF4yAwzVD3jicSYZLZ8NNxRaIMpwGR2c+BDp2HP0MFSDx8n34SoIw9/NNbtq6jl0ydsHWkmlU8coPtCkFui0/Q01WJRoM5nBYvi5sGL+DAm4+5sc+LqSsV8+RAs8wdO0kLvY/BdqzxgHFV0Fv9AjoPvqTZM/fwWwTcUyesYKDru5m+2mt2LrvOrvsmks3y87SjFYtaLLoRo4bw7foGun8twDuB5/Gh5nENjUXuWyeJcfdSQaFqHFQFtSHNb0mdPV5CjXJduMLhdHUXb6EEwKlWKLcB7s0dtDRGTYgMT8FHqUHc/kRcdK948UfPIxY4sMjaPHWp/Fjr1CrlhHsrlaD0vRy9vuQSBtX3qTaAWu8LPAe+r9ch8TX6Vh6+heaGT3HD59toSKzghW9voHy51s4IqAP1t2YCm2mk8Hgoypa7qiE7xfuYWKHCOw/1M3KFQ14KmcVjNWsZUElS9r4qJVzJwnRisx7LMpHYPoaXdge/xSWlgVQf4wx/n0eCO9PhrKmsC7OuD4VZAJz6YLqcipOk4T1H4MowaWc9eqQqk8u5TDddHTzmMLfYishYWs3znR7QjcmCMPSI1Ww1PwSq5c145XHw3nzwF7Ye0kUpi34S/ZSEvDMTAtTBkbB57WiON5BCVyX3cZDp6Igw3IeeL/0xw/bRHC75U+cdN0TS/aZwPG5UvyQRThjyFNfPDNhc00SPabRtKO9AY5caYMyAx3oiRgNx33jqfTmWdynVMOtRjKgYHsHNWxfcUjnLLYZYQblcvKwNtUKbL9HUMO3fSym4UZ9qW9YdJIvvZnYzO5WSrjMyJ3v3esZyrzxELPlOQSeSkKDiedxVN5o8h9VgwejDSHy8jA2b6zDeK9qSuWRUGh9CpWGHPRKMYWeLf/AIlMHOPiAENUv6gN9o1n8a6wmvTG1hhizdsq5KI3xm+rQetAO7HOc6ZzJPPIpNObk+F3Yrx7NM6NM4FeSF+q4mqD1oWZqU3rHD+eUoWrNSXQ/oMixnzToce8nNjqtAN73LrLOjmJyi7TFsEAgnUlr8UXhL3L91M5K/u9hY99ZyjwvCWOq/EFdF0Bj6STQVNTkgvGHgFWT8ch6E/ZPqeea4UAy8pKwNbeS/x6I43svVoFhiydlCSVRaf4Pis/byAXpfyBIOQpPPLQBG8E0knUX5yv9jZBy4xBVRNrgg5AEKspJxWJKhTMTEnh//UT4FKNCy6df5N7sAZpv3kAbp5+GiPh2XnvUls3i2zj4bTmddhwP6+a4QPPgI2iNNUa/ia/hrUsrzWvegS9yRnHrsKu8MrCZNY6MhAW3trPdl7+UF/eHh4/biUn29zDivymcIKDBm40/UXiBCx9Ybgr39xjCFHjDG926OFAoADjRlR8ESoJL+WN4fy0PnW1bKU5NDBzbB+GlxTAY7T2IJqna1LXrFZ48PUhTHnZQ9RkD2nd2P/7uEoaxlUKU/vM1NqR95+ieBNZ+fYkPn7Rnh/sbQefLQdyluhB7Mk3hcawS3lEJ5Ir9HbB8aw1ZSbSx0tDub/l+hvRHRrB0STT7jZCAXeNm0PmsO+B62Y5DRvqTRU42yz19SIuOZ6HW5v24YlQk+gZoQYl3B824fZKyrIWwJWsJOjTZ4aImoBlji/iAWAeoTJgJW5bpw6fMbCyIRVAU/YnPQ5rgw/QzqOhgjSPWh8IUQ3XuHEVoW28KUZv1INrbBP7om5L9haG98W0ayfiGo754P0WYHWVft0Nw0WkcWOxx50T9P2QUrs+3S9vQcPMMnv7Jk+LkTLn3siyECa3CfNkJsGhDFRxTtYEkhRAqnnqHb6+sx80qHqi9q5Wvzh7qC68EeYuJDdxRuQ1CLh4gOG0LholuoQ/XJpH3RVcY6RdHDusiKMSlkosI4KvGAvyQIQ/nLhbwlxsX6KpOMNr6RZDsyW249agW+bRMwnwRKTgXkk2tMwJ4e+c9WGp9j/JHxOD94vVYZHcFZ0bmkOrHMLKtNgKdHA9ckfEC/8sEaOzcSRveu/Bw4YfY7bmXDy8Shm1ql3lHnBCU+8bx8HNWvGbeYy7LNaK3hQfx0a4k6Pb4y076fths9gf3e4jD5suF3CWUR9aB7tz76DQvN94ADvU91Ph0KWZNC6RXur8oL1EHdhYMQJ31eVwVexv2T83nTCU37C4sA8mpWeS1ewp3KD3g8xfVYf33Mto5/jTPmXgMZeWCeKagCIZOeQdFyacoUa8fcwPNaYKBMITxH15y5yiUXPeHhxm1eGu1HvwrSuaZ056A1kkTEvJtoBtL1cE2OJQdKvI4feZySJFbyobd/phcWglWehup8dZBHKdyjHvdjGH88SsQm7ICFuX4w07j6Sz9eTYaR7VjR6s5peBwThjxF/a7KIBAYjOJVaSyrJUIBq/dD30r4zh37XwsTJjHplp+2F31mtpqbWBZ4zYMaP8N4uq98EbkOY3L3MHy16bihkhtirC6hm7aoTDj3HgwXPOX6HgnU+BqGj9fBa9N3kIDYjl4oqkS4d1z3r8ol158M4bC8M00W3MnWuj686O3v/BWcBKk/BOhzcOH4YY+QY67OoLaLMVBHGyotOMpBDtEwsTJdUMWlqFz+8pg4MUV3DJOAqvCP3NJC0K/pBPZuufy4u5ykq3dgAJbmnhSSjJXTY/m+J2hWBMqCG0B6lCkIkOjVn6G0aktGF7QTE47xOGp2kZUshXF59Jrsa5WDXcuMoTFCj3UefI7Xq3RwTfXR3NHQxBNECPKvzOc99WexAXz7tCUQFMw3e8KK4dmry/+HesEy9nl1l60kLrB2psu4LEJCaQ3poyn+QjAYnMnPpDdz+/eKXGqVSWIGLXSRPd4UOmqpaDWLPrRsA1zR48DuWmn4dOIcNZp7sYNzsug178Arvy7SLXum2Gf/ApUN06CJSoiYHHrKNU6G2NZjDm3TJDmC2abSffaC/zitRUdGzfixKOxtCxECnbORtQ/4Mnbcr/z9qld/CJxJ2YW3Icju0VAwWs7eWirIVbYgIzxXlSe0wtyq5JIsmcd1UdPptrXw9ljky/IlPxFgc6jvLFTCLzjevBj+1ZQ2HoUW2SDUefmXvTNdmDVVx3c4jyL46864ngncdh5tY2spv3Hd7SuoMDEFrgiGE16v+VxoZMuxIw4Bg5pcyi/Sgqmui9huZ0n+d5WaVym/QPjt9wiIbdqfipaRmtXzQe5BavAw0EYri3q5JxkeYyXtCSTyZ/g+Kty+rikCaYGC8KNbAOwAkUMixcDT/dMllg5FsznJqOCrDLcUg3EBQeFwXrCaLi6foD1qA4fiunC7uPC7Jm+CF3PNdDo163Q5FmDi9QCSLK4lMqfHedZrrMp/vl4mH9bFb6J5tJp9d1gtFSb49aYYJNuCWbrJJC7UBednjwMVfaoQpHjLtgoowlPTtrhVbnH9G5KK4yMiaUKDONSDQ9Wm/WbReQMYPidWnQ3uIaT7r2A9o1f4b+qn/B4y3l+kTwRZmspocyivbRumBW8kJCgPd62dLZWkuYn9dGuuDxKmf2S5AaqeZ52F+x9J8vrKxm4cRL3nniAdy8I0RHJC7DJuwSnuwjCpvB4OnhfFY8a74Dag9IQ9ewodkY3ofFIT1psuJs+zLrDZg8CYMdufY7emQra1/W4cYcldOtsg0HBVpAO+kyioUowe7ARYzcUQ/88LQhPW8M4dTnOaVcH0xtSAA6FkBUliLtHK5Cfhh04/DzLX04cxrFGVuDjb4ZGhyUg8NBhlBGK5FJlBdob8h/e95VFp2ItrJWK5qpuM9oqzrw3Swhyg6xx36GZHPnbBs2KWvhVZQK9yNEB71wRnFzszkENv2hTkTgElpzBklhFHCmZCLcfjweJj4p062A6RW7Lgyb5CnjmVUYij00h5YsppFu/w97ZB2Ghx15cOsMXysWdOdVAEdU67oH7al9IDVOCeRWSdL0pBL7ee8+2J2355m1TmufuwcVGPnzHZx5+TjDjOceFIHqWChS9XADx8gdwt+g02DIGKVAsEAIKuujXh91wRlWTr6yxhMdnjvCnj25kJHKI/kEyaobNYY3mT9i21BuuH2nEPIvLWCCuC8sxBS+dUqXDJc64RbcH3c7Yo6bBYX6xIZEdAxvJuP4gDnuiAd3nr/G6/vtQVL4Qp26ThqGFSlaBd1DzYgY80i3iI1tcEe5OBLknSfw4ygrTghdAdkk2pO1fx5nvNKjgfC8f/1mDkiWNaCY8EX5F19Ltiuv0xNoRnoXEoFhGIHy4+ghdJcbD+BOBNMGviKeny4CNjj/m9qlCWNQ2HnysiJNl7oLgVUPKv+BKF50uw9/BPrpXKwdxtfOw6fAu/E8iARPEPbk1NwFCs4ajw+JJ1J59ggUdxahggSTs3f2dvX8ZQki1IUDGGtyc+JfqP2qS1vIGrN+XzemciQrLx4F1cgTudWrB6mlKrNrwFmyEF+KbS7KUETidtdv2wvXN+9j/jxII30rE7WWSmCObTB2hgziY1winhgXiqS3BvNf0BZ5dqkqNuqZw8Wc9RVopskz5ZirXIFgV9xOL16/Eb96PGA54k76gCN0okoAncsJYMbgI1cvOg3fQTEonAc77EkKzpmrxTfE/3NaURml7xKHVRgC6B93Ay/Atvb12ked9ugvJya6wUKiDS+Kv4LS/B9nJUQUq2neh0b08lqu/g98SqnBZsTypF4+B26Pv8Lrr+aycrYIShaOg7MBYbO6TYU+pUJp2fBMsrz2GD+XK2TJAD181v4JF46aC5aA0LCibyGqf19PgrB/k/dIalGcYkqXEGLIXSiSuyaEQQ0uomi4ETyuK2eCLDV3RuMzvbKZCHWjytrPCvDSpnA8qBmBbYD3Gag6Dwe5TpLT/NAY+XAXqFpJ8+os3zXH3gF9NQzbcGoCGd0+h9HsB+HM3GFIn1BKYV0PWNQlQ9jTiFysCuTw6CFrbTblIrg/6nkjA1O6x1HVeDVp8XEnr2GjQns68sfoP9AfsxqOOnjTBtBNF22TB+4QT5ijOopkLtfBv8WJ6JKYPMoN7ac9ddZj/4woXNTylrbvVQGjYGriRtQt17CW4RMwJHx3Jw7nqKThnrCxn9CkP5dNG9HksDDO9HLk7qwlzE705rfQfvf2zFb0ObIWfzY+wNuQ2p4sYw7vjAJucNzB2eyD/+ICiXpMhSsSLNsZr05smHVgUrgaPjIZDUrMy1If2k4hiLzksEqBb3p1800+Gvh5FTv0+hQbmr2HrWc9BergWWKfGwuxUc4RbCZRzWBB3LUygtCxRVvnwgvtOPOF4tWDWblWHqrvpIF1ewe45wD2pc2H7+a18wm4imV7PgAa9lbRz7Ajs3C4KnVXi4O32mSrMV0CJXjs5+Zjg4k9PSKH7Pk/VQ9SSHWSfZwDXfr6no2NUQBTmkGVhG0/K30AdY57jyU9WZHTFDXZ8fIk2CvKwPeIIbB7KjdvKP1Hr0SOIWtDO52TK2Zbz4eVKC9be85YDdCZD3eyT8OskQvjV4/DPZADM/53ks/OMWC53Hn9614kvR0RgwJVxsHK5IN7VBbr7aAduDD3Cf6evhy2jXPlHpB+VnizG05eeYWvCZJi98yOv+xFDwTdesZAssIJAOC3pdCTeshf07Igt1+Wi83Et+GSiBP8+/IEv84rJpL8IlJWTeZzzbKybv4WXdiviwrt6PCdHAq5u6STxYhE23DpAHR/N2XXmBnYWCASlg1r463cHCKwWo1GzxCDM4jvl+h6Ey31VtP98HidYzYWo3Y38yHUT5uu3kFaSCYz/oQ7K7Vcx/7QM3ZV/RV+a4nBreCKYKoyBXqkr/NhLl/nlAzCtHAtf5yRg1vZIFIrNR6dfT+nRpz+wYJMoJdfNZ5GlF9nIw5iSE0Xh8YZiFFLux5+xplClvBGDEmMgxUafx42pg5F/DXH0+/NU2DUBHl1opuw/R/jKyh9YrN7Hmg3L8Wq9ObyvDEOtpU5clVXIBWcmg1m0P6p5zwJ3iYWwPmw1HFKxJDdni6GetwXUE9J52tP3oLJSH4wm3scLBsPgons0ZIlvxLHbhGDpUjdKG2kLN0/PJxMjR1wdrAWK948QhKawxiwrbFoTRyISO1m9eiIbblIn/a9B+ObXXlR/oQnj5CUxLEUcDxk7UZ23IB/2lIMjcJ+j36VyUv4FOJYmBxXRJjD/20b0ShsPV7IbMfCJJOyR9eBZa8bRsBNL2OLiArRb4AL3virB1T+38ZjXX/iiaohHE3zogtVwSrp8ANsNrtJWKQM8/KsM06/KwS2nKI6zrKfypUEwong+f4vYTiYOJiAtvphGjqihn2Or2VFeEiYqbeBNN37xBo8f8HhzGFXbenBk4ldQTPCCu4PDyNLuB+kP9TrjlmCWkn2EsRuH4VS9dBJSeY0Xn45k9xFPoK9uJhuvr0MpFRuw3E9U9ucWnnU7gf0d/6BQIJ7OxZbw+bxgqnNvZY2Fb3j1SiUwCzlN+2a58nhPBdLS/w+WTx1AKyMmt6ZF/LconOp2FdFiXQ0Y2b0A34e859RLmTTuWBrbZU8mgXejsOFZE7UPGwMPphThqQoTsJfNgXuzJ/LD69sAxO5RXpsYpL15CB+EnnF16mJ4P+kaC843AjVjJdCSqAfbG8chqLsSn243wTFnJWCPuAh9gxC2rWimnDlaIO4kBkGSqXiu8CLMPfiD/1YH8fhFCbD7IuH56t18THcHLJNQgRcquhD1LYfO5d6CoKtCNNbBnLTsf4CqpgokOzvTs2FScGDfWJj48Dy5SE2lDU7CXJi3hMxbOsgrchiKnvbDiFlnwdGuERd/Hg0WUztwy11JUh9YQLk2ZSR1cTQNdufQxROnOLKxgy/qBFFrynAou7cCE4UuoUPtTXYwb0bLAV8aGTuLikP6ofpHKadMP4JlIgqgOc8M3F+lYH58G92X8QWVU3WofXgi3hc+jy+3pWKvaSv4jtQAO217SHY8gw7pv/Cm/W/sc55HZ14bcr1rF+kdNOT9M0bBvSny0P6tic7f3MHOptZU3CxDpZ8Xwdu/N6E6fS0KbEO2bz9PnWO1YXPkeda4d4Y023RpXU46a4+T5cWNe1ki2IE95l7Gqk11cEFfE+oLGqj2lCqPdP2ClY0n4XnjcCq664ICVS28pMWBWtpbIeahEWj/scaXu97jR1svLvikzbOsDHG7qAt+iTDjvUGdZD8uAW58FIPfC0+C5+U99LNLlZ7d+I1rVXr5yMo6NI5/QyNCtVHuP0nMGKENMmsXgfqbUbAqLApLKq9RQlI1xk74hN/jfOnSEkcwP5qIRhelQOX+UwioMIcFpjoMNeq4Y80u2KTizMnBnpj5XRar7oji2xoF8Mk+zxn+CJl25zEitAw7hJJROucnyBqNwqly2dRjeYymoA6MbnkBno6S8IPns0CaDcUvyyKDTYJsIdAJAw5JtNs9hARuTob2sQv5YOgOFO10YrB5hnYj2mjwqOPQffjLh7ZPgL7odRTUpQB1bkYQ/a8XdfuSIdjgBBXpRWFx/m2a+nkftArIgVncc+rrsICPM/+DWz5SRPahLMYW/PCwCTy0lINm/6uwtDOIPJ748NtXcpA+KQ2m/ZImU73J3ByXAV72kbik8y8c+TlI7nf6YE5xIrVoiUDoTRsaHqREw1RukUg2cHmyCN61voLP+qLo5OLbtFi+DvYkC8En71Oo5/QenTbcwc69pWyx7gceqcnkIwLnOEPaH7+WXmU7E1vQ/aIDLwt8UCNfF2teZeHR8VJ4zyKDh6+fyy7WiOfn++DKfGlIXfWVrn2P4Ik6h2BAThDvD4YO+X4d3qxdCDapr2iJSxvPk5eGUcqz0EL7EtarqEGcmiLnjIuCwtn7ua+vh0Rc3LBCdSVNdB0H9Sbx/PLkOzo59hErNK3iupDb8HsUY3D0cpo+KEduB46C+BlFyC40xIhMVQjYfx1cfRfygYgimFI8BzLbRair7y6+Ec8HjTIxaEnSYOHxP/mERQfkfargqNF7adi4Zla4+Jxy7UzhQEMYT988CQplKji7pATmRiwj+6WXsXz30D0a8m+IziHaF7UY1galYcdXLRBL1OTW6FiO+VwA6vPtsc4/jJxlz8CSK9/Y7ZwMP79xFaPEAFq+VqLHFGm26h6BcwZWQLb4d1w3z5FZpgrKppfQ3E2qGPVdDe5GF/LYnFv0/OoUfm/kBYFJPpATLg5vb//B9IZYWlGQBZ9FbeBHqg2unvUS/DpjUGu7H0xcfw8GEuzRp0kc5vsI8HdffRhTJQgVU33RJ0OSnd5Z0/6QPWyyaSStzjWg53WNbDbXGH92POeQMgE4kUI8Pk2e6ke8x+d99+D04348t5Poy/UImvn3C13x1iNbRQmQXZwHg7u+UpiaA2RUWrFY+jtYpDaa1T2Kad8kX26dvgqUC/XgvxEjOUTrB7f6vIOtEp34yu0QVFdOAc2Uo0wC0uT9dDvOs5aDK+vewLFfxeAoY82pX0pgy2U1+PdoEZ1p+0jLLzjDHtEKyJNTAZmYk3Rt8lF2NJsGn9cpkbDoFzo/MRvfVklT+3hZNljyDx4OY1gQf4+OH4mg3WqK9K3BFuw8z7PvxRTMLq+A7DBv1H4fQO+HjQSNS1PJx2AO18bFsgjFwPjbI+nB6Scw7kIR7rYeBIu7w3m70zCAZxmsukSE7h44TYJL3Ph2UC9EzTPl4AmZXLvamQY7p4NspjxMsk2BsfaS/AALqCOI4Z+ZKp2pLuXo0Zro5DAVbO7+hBsG+iC83JHMcm7SUnEx2myejz1Dhitw/g98L92i6Bl90Pk6lxoXjwbDvD4OGeqSR96m09fV2SSvos7icfv4YMMVqDRSYxGhtXxIWQ1OSf2AtMqpkLXXmuSbLsJxOWd033MEi1PTac6zLPxwoZO0syaB546V4KDzFi9sfo4JOdn4UkyJIzXVceXRRlh87RZoBB/jNaqCoH9+MxilKvK5ZA1E9U7ys/elbV88ea7rJfxPcgEYr19A5sKaYBrrx0WicnD8+HMoUt5Ol73/4JOkK7ixwxyOByxB0p0w5MLRsNHrEQ4/dox9QirhSeVJVjLwZ5d52tAz4AJ9ItJY2lGEU2ongr/rcRhTXE+LZG+TsuRo9Gq6RQ3LbGDG6fEw4+AR/PfbFH+dsYUZ+WcZrn3mB5vG0L6Ryij4vJUfzQqGjLwUsj6/Apae8qP01xPhpJkYuv48Asbq11nn6y08d2wUp7qfZ2mDO7RTdzfnldzmpf6aYC8yC95t68cKlTgI7Xbnn4lBdKvaGa9d9kXpyyH0x6qSM9ZaQFTCaph5+DKornXAacvL4XDhGoz/U4XxdQYs81CO4vStqHS4NLz9tAS+mqwiDVGktWMOUk2iAFfL5cDx2QdBWzEUDq2+Tw3to2B+zj0cfrKelu16iar/TpJ83X6Ii3rAT7Rq6YNrBl7IH0MfZYfOy5NUMHwXTre2nOFeyY9c5zSLYofc/b7dCk1+vuQFTk1wab8kXFYxhLjpslzQ44eOVw9zQMUrFEENOqShA/YL77LXx0JOj5wMn08fJl9DK15i/AIDXpmAQ9U+XNlfz2ZhgeS//C7GhK+AUYPmoLohAVKF7XjeGH2ESzHw+rosrHz+lkMfzuFr1jXITa/4k6YJbN39kg7s9KHKsxPwQM9vkqkzhac5+TBGRZar9g9CbkQ5ir4VgmtL23DjjctoGDaX7U0jWbv5DY5xK0ZPlWQqNbGkjPBoMgtRh5i3/Xhp2C+wuC+MIUt96KzbBVyeHIHbps7gOvvj8L6gGO5NHQHVmkH4a4w0hv6byJFWVZCNwdCccZ21/CXhQcwioiumGLlSGwZDsnjvajUYLhgOty4u4SVOt3Der1to2GMOO5P+su3B0TS72QJW2J7intofcGweIBZq0c2LXyHsqj0/2a/EPWOkqfBICatVakG9wBk0v/cHHw785ny1yfzMUBp9Jb/TurHGGH94OF/a3gZxz8Vgp/ctoPw26q1JxdmLi+D0vVX0YKg3uBxYRfqWNXTt8CV8NFMGxox7C3rLFEh5iioqvEqFr1w6ZJASWvniFBrvcsKj9p5oeXgknPqqQVEBNfh041EIuF1Jj56s5adR1ZjbEwA5+hNYNK6cvkwUBKcxZjzqbzD4BTvygx/LcPa3BkgvG88v2ITXefnSzHVpHDdmFDQ8q4LTw9tx43cP6lp2FfZP9mTp3Do8962DmsWnQLaQNQYPjoRFiW/4zA4T+r0ik3Q/biN3cz+WrbzH2bJV+K/pLbYIG+Gy33rg1peOD6bUcs7DRjJKn0aju2fCqPhT9OroMO4yO4NLgl24S2AsKF3K4fGbRfDQnHDYUdPHapmOeHGnMvq97gKriQspSTOZml104HPrBHipV4TSfrf540YRtHJbh5UPUsAgKoWivCpBSeUe9sjbgNaXfzBy9gR+NpAKdfr3KK3uMxzLjoSSU4fRuTwPnT7dBY2h3DLPN4W8C5tpeEEjz0kohIm610ncNZgm7/Dh69MyodzaD3crKUETmfBe5ULm7D1kNl+BBhdL4M01ybDVuIyO9tyAXM8kiPE3gnlv/+M2mf1Y3nULNnR+wW9iV7Gm6w8urcuFRR6PYdXeoTOZMBlG0x08bWCAN10Oo2bgJniz8RpNjlSiPWqnYN/s6fjU5hu/aheCelUb0kzwp2/utpBiLstGo5jNjCfTqcmV7Dg3njcNOWP3J3GIuvuPHVyKcdRLZw4+p8qTOrahSt5pGtGSTC7CplQ47C4tHzkaQmxPc81INSiCeyhbs4USB+ZgcccuNhFXgCOyUfAuXg9jNquA08RetPSdDkdbW3HHlh384Ygi+ixJBqPeWko7l0UOe9twlPtY8NH5hCKh32jRdT+c++sx9Is1U8WfFbjNtxNuvggjuS1naIKvNFilfuf5GRco/2U1DHZ85NISxC7ldijTu8sOUzNQ97/H+PK1OZybNYmnm+9m31GD/MR1LlndvYZ2gT9pQ6Q5Fptfpwt/WtC8YTR4r/iGbQe2g9jttXRkZhAUVU2j71oF9DLAjm2fDFBQbw/vMhaGUSdTaO5eF5bSGcHFdcd5wdcATvN25seafnj9XBd5OP2BeWryYPO1Fb2Ko9DuThbM27qRhRufUPnYXJrpU0K5ivtgZsEemioqDB8XXadD55Xh3Oyx/OfaJBzfN4ctorpZVCsbWyOvo27nT96VPQaatErpYWMCdg7Nx+6KDE/UWsVCe23R8MFy8NokgzMcftPGBhGoVJai3p8fKaP7Hcueug4OqzXY9L/tpK/8jW9NOINeHt3wLUEPFPZZg9uZPlr5+zJn5LnDTXULknsLdL8yhFbcLCKxKhcskZGArzUI6Y4HWbj4Ej3IGA0+pXV07lUzJco4UXzYTLad28v1F6RB4mQdrD91Fk8uM0Lvuum0ZtCAHdeIglJJFPmc2oOULkD6yRqg1+MJ3x0dOW1hEDxYqoeudQ2Yc+MGKYlE8L/Qz/T3WhWVClmCQrEEHBrY+T/izsMbqMf948+wIhkpO5WQEVJGZIQiJQ1KaUmKJKWSD02V0VAUKRENikjaw2iRWZGRhlUqpFCI1M/vr/j+A/c8z7nPe7zOuedc8JTeiGuHH+bhR81xf4o8/xEYQOmB8/RQ5QN7rTKE2w8C+KbgLhIsD6f9xwJ48drXuOLvU3hT40Zimh7Ayd84L0QLIkb8whLRQe5ZlEfLfU5zgIkGjz28lV1nG+KkQBNYsaYcLy+QB4lpDfTTNJpn5vxGXvaB3itdwTXmjhTi1YizixbQ88uqcMnGFJYU/IUVxtexb3kt5J57QXKTx+Ch6ln4pvIWHHl9nSWm1fGMl1rgIOWMR5qSyNnIl78EGHHcoQ2cP7ySL/Vl4ZG117D49ghsHyUEyiOFMD97EyQFmbL9rn1I8zthsOA1nYu9BYfGRdHAW3Vq2joR9ktP4tcr89hL051To97Dct/juCctF5JiDkI6vCOHazthfZ4w/BDthU+zP7LHXRm+4nSaz/+dDb3iwSSQ6Y7ne+bQNc2dVCMpBVO8iPqMlDgywg4nCBTxYzFXnrW7gZ6EHsMg87lsZ52DCn/EweT+PSgtCCaQGEV9opn08bYmyiQ1QYyZCGu51+Ghno0gFDscxPe404YjVvh3RwsKhu7BJW9Cefan22xh0o26Rc2Q53wPTSIJmtW/8gGXQqpc5ckpFTPx5kIayov55DNjFjX5KoPKCmWW+TACkqeOwe1hT1Hj/W+qWpFNF58dQU/H5+yQ3w6zflyGkJp4bJlnAC8//4SLVQFg/CycTUq6qKb5CeesquFdHEX2Hzby5+sv4UHiVPCve8Bn57riGK9WnD/6Muq0fIV9b9sBjp9Hj0n5KLRdgoyrBGChRCgYSS2jxQ+XYkVECKetnw9ZB85Qz+STeNIsGhwuu8LhndOh9XkTZdes45axL1CheQKcFfsOxp9a6d/ABNpYOALDZVpgnZIMNJmPoBVtIji9r5b51gZeIJiADUsCOWfUUp6qch5Ou5+DP94W4HjrFf+xraOvE6s5WzQTDrwQRoWEb5xebgb70yUgvGMdjTgmCOku8tRhlga58V1Y1rIL4+7dxMVeZWwhYsLbzOtxzbC1MClEHzr61+GCCgl4ay6A1aq6PGl2Nz4/3APaWg8xwPcvTu0qJJEQQdAf3M1/ctphSmoDxR2awROy08l87CROu9qJrQceYm3QWL7zdzxc//IGdWYPIx3hldyXrgI1WVJ8XvIfXS5shZNKezBRzJk1ig3A0UuRdtS7cfhKgIsTJ8LUEed4rfs+Homv8Mq1ARJxWw3PUnQgcVYb1u/KI5PPlmBYdpaWTfyNR86mgpFsGejLLKGgTht2dpUCgfq9tLIU8ZnLVfJ9WofdD3T447pv7NakQzOX/qBlB/pg3vUJ8O7WJHhx9B5oH3qChau0YfxVaViUPplu/hygo6lL+MsLI1L6owRVqe/hcvRTSJHqwdh9/fzQ9igc2hGLIwodUVbxHKxc0MmdylNAdl4LxK6VRff/rEBwsgLua5xFe+bfJA/cSaVa92CS/HLsFpCD+kUFHDJ1aMe7W2Fd33y8VRnGtQFZJO/0kFPs3Dhn/UZoE1aGHs8LYDo+GG/uVacks2tUmbAD5E+3c12QEdwUes2WMw9wykhjWKOlxFsmbKWTMvNAQ+Ey9kTE8pQjFfT3fB0tT9vJdpYC1NajDIO2r8g2KZkHp4tSjcNktsxyg5+3X9CS4+6UECzKYme2U3jaZNjtpESvbpTwhIxM8lrSCOmj78KrV0V8o9KR8hTiaA8bkX6NLDxarYHlAXFYfncLC+UGwa40Raqwq6HoKEtabfkYXjV+BadQSVirO5pMm7bRk1am+tv9nKXpQTvFbTBo1EGcURmKZVLqfF9MFU6dtcIjQS1841kvtYy0B7WgOu4dXQR6j7bTphEL4Y2rG735owgGHVdgVr4KP3hnSJFJ+3Hq8AAY8H0FrUbAuyT1acf4CF6hKAzBjqHcmVbK0Ql98Lu/C6JiS/ln1z9cvFSfBQRHoUlvFdvcEYK9a1RIyNcJBo7OwJ3VHhRtoQYOUaKsF5nMNTNe86GJU3jdDFVInSfK+3rzOFVEEuYfG7q7CxNo+baxONkwkULH3KHCow0QPkYP1J9sgNPz9GlDswzexPXs0yHKFVum4ifrEPhwEPHu96dwoXACBDsUcv8/E7j+nzzEyz1jydOLkMO82K2tGtQfdHE1akOa2SjQ7TLFsOIWcNeo5Z5JVvxHeyo1ShOZ331IixXv0yYXe/4eMA5WOfnxP/sTPCbFil59uQe7/mWCL7dRU+gPWjphJParvIXLosPA6sNdvnKhAPrPt5BbZSVK7/SDloQT0J8WgRKaUjQF4sjolSLsLtEhUZfLsPatFE6s1Kcf7V4gk7sLUru7YIfrMbbHGCxLMYUirau445siO2+xw5pgCbAylcQcRRcO8dxAdSssMaBgNEx4IAsVhkq843MKCmcPcoezBCzR0eV4n14UUV3LH5YmYZxgKdrfNYWHYaJ01XsdJj2TJK8eFXSeU4wv3D/xvhG/OKrWllLrvuPXQAlwU7nB7+qNeNBhJB57Mpz2rrHh9TVS4CiugCuzvvPYS0do9UtpmHWkCCs0FOjz1SmYIfKTry93Qp3sT3gvXYEvCV7EeAUlWDNzPIy0vkOKm+fzhO3bULByHCUvSiavsRth7yJpeN1YgTuvn+Y9YVNhh3AcDi9Tg9Fz9Hhe6hq8JXOQv58Jpz2lN2izvS+6b5LC9XUC0PXgC+f/8kKRydPBT7aRysdsYc/ecA6yaYTrzwR539pUvFOlCO8d5sPaPdE8N3ALGDuV0zQPMbLJGdLPnw38OrSWrVvWo1iCOGS/ykSdrhM0uXcTWn0eRre0ZpFf7TDMsZGHXHM98nl0h9WNpGDFZlWcsE4Wi8//5p2rt5FjhgNtP3KXD01fxF+0xDhqy2bS6lQCw8r19F3uA/91aeG/xck036SPfy2ToSLRl3h4yXlo+DIabGWNYZ/PQYjOnoghS9T5cEcOz5TQhCN/vKDfqoNWDN/IsaIN7LNyPNzvFeaEXBN6JzaF8/d+4Ovi4WScJAOll8uoO0kUoM6etXVE4VhtIs90mYdhC2fC/HBz3HguFNX/bcKttr00544o7JEeTk/mioHw8INo7qtG4htDoExLCDbm+fKxG3/YZ8tGqosZxMy5qzh3jQG8HitOj64oYn7wClSTnI/hZp95Q0YYOLVmgYbkC3B8fZF/nTaEB8dv0Z0l10kzMJK3/jLAxX8N6DQ4w7ER/vile+aQBlLY+oIeDMMT0BTeC507QsDzqy9PjGiEN6IKpDX5PM5fdwHOa9qRZocK7Mm+RZnfuzk49Dq431/H4c5hfHzpY4Lpl3h9xBCvnbKFwcGJQ960hfJVQsHG/SspPZrFN69+5IGGXfQxaDQKqAWh+JzJVFsjAB1257H5+zie+zIXVy8bxSYBayj8/ndyFnnBntfVMPPqQrBdORmi495Dx+4UXr06A0R376VHgXP48KhGDJNczuNPqVBNhDC1a4yFz0mmLHE0kJ+YvOAbcp1cPXciiQ5E0iFPY1Zed4rejOxj+5ypMKXTgYctng4Hp60Ft9OPaMeSNmwzrAaXfXPww5Nu3O/zDES6h+59cRlFnHEA7XdbyTKa6OTEuyQd3gEnOp/waukInC+mAhHLLeHyAxlq1I4FieJ4Xn9sG27w6QGdtDYYqX0HjN6J8/x3iVi7UQtSnUvRKaOOvz1K528BSBTvS2FavmATlsDWne85fEEyiVgbwTJ1Uba6NAVs3LLhceUkLKAJWGazgya9vszqEj549uc9mi42He7V/Idq+4RpMOE3fNw6Fzdse4dr2mzxn0QAPH59BDWDtvLEN8Jw/nc6x6jd4VfmhvQ6ooostL7BLKPRsFVhHMwd4lvTC3kY+k8TYpfWoZaQHf3ZNornnN4B5qk6VPJXDzvMQ/jbIkMY3WxFIxsYlu/wBc/WGPwcKIfJc//wM4HxlNDVj4fiZpPQmidw5kABq9kbwCjH5bB0fC8Y5JiQsM4lmDRXAQ7NyIITy2RgyWlhqsg2pkb7SSCcNLSDmT4uP3KF+u5X8cjthrT/ciQ5Lw3BJJ9VUFHwjyY/1gPdWfkUmDsOJVcKw2BhER0IkSRrsxe0arUAC4udgO7Nevh44RjYXLeXDNoPQNfNvTjGYj8XWc+AMR+D2GfxBz767Rh0/veI+yxHQ/3EG7DcyhybIkO4a811HBc6jA3tfpFb/2O6nyXH1xqtqUR2JBz77w2Vnt+NtqraYLNkHUeUxPPFV2/45KN/tK/sF9pHbUN6JQTT1Gy4PNQGjbLjsClsH3iHnSb97fPAyPgpufu9hNoDBuz/QhAKbgTgofgX2BujSD0HeuC3H/Hg/li+cBjJQEIYPhoNgmOrIoiajiOLjZtArIhxrM8yym0zRnvFfJTIrCKNhRNQ88U4PFwnDNd7DdlNPZLrHeTJUGg5RI5ZClG1Z3DHoBKNfBhIs58Fku0RJcjxvTHUG/v4z/0OQKEvVCBtTQMjm+iXXBWfPCKCsvrfsKtPCKQSdtM2+Z+0LGkGlf1q59zrBMVFWaA+YyXtE42Bki8H+dw3BWieuQs/yF7iZ/X12BFfSnpaf2jDwt3oJC0E3hMQfkSGQo64JRwW76QvXteg/K0Qb97gwX81L6LI4zwISFrBU0306dj4/VCspAoVM8JJymolxNzq5Gv767nWM5fMXxrhoR3K/DFFHsN7jXGOhhkkP5hJGzrNafRqcc75vRALQvvJICUK7uj8gUefpsG9G1n8sW8qBB88hNUyJlw+9z48Ge1Kfn8PorxXxxB37ONhwu+opLcXHTqmDelgD+Q2TMJtvoVw8EUXz5Oejmpeh3Ct/Tmo9snGc9lROPuKOfRH6IL7nDq4NtAG4tmtqCx7gZ5PWw5akj/xYYQnPc38AH8HZUDf+ycYL13AEnM+c4t3Bj73OA9i9a649rEf6Ynd4a0v7FCrShICp/vRp/cyaHozD1ycD1HVwQUc4p9CWSJN/G/XcRzn8hpErGTBSvkFfYorh5H/siAm1x+3vznFrufewTvH7WR48gHcf74FRx0aB7dPvqD09nRKVo0ANeEVdPHFbwr1j4F9Fd/g0fMdGPL6E/f+pwmDO4q49YA6ZS78g/L3Erhi7xI8M98Xzn/tQDtYjmmn4qBulT7U790CdQsWQcZiZxau1MILjW68/fNrehDkANetrFhtoIj5vRJ4XMig553vIXlnEa6qrSDb8U3YvGk/xoweh9o2eSz84gFLOlmApZwIWq8U45+QgfG5hvT72xIq6lKgUA1flmhuxqVzrvIWYT34lfCA6jx3g/CKCHAZew43FWzgJL1z8OxGG+zyFMe67z0Q/3UKSP+OxYUbwnAzj8GRa+5BndYmmgXbMeCUGz8ZJQ3rr+2l7tyRcEpqI2ZJ/qXwwn5s/fObObwMnuVepXr7KhwvupkuxSlh4lZxKHXYzU3m8RTz8xGeMXgAo5bugGKn97Cj/CPazyqhq8sbWfXacIBN++nujqsYs1GP1xt6gOeozdxi10qnbZOxIvY6DISUU03WOJALs4dOH3t4IP+We+oG6fxzxLUFO9HptDyqpInTcodALA8U/5/9/1dMewcmTjOh9JwCfqkzC27F3IODJxJoe2oIzGgvobCn3/hQqjB8qBvAVVuOsYvDKXD2z8AUzZlwfIktGsW6UkNwHQT86kXVu3JwNkmLKws0oeLJZrRd8QGF4i5yv0cn1+yeSNEyk+l7oQrfyhCCxy/NuXrGIbp88i+pHN+GxVv+gaLQHNaaKc7pnhtQ5WIHeyxXgPD2Ivjg6c75Hvr80aYMformYkDmbZiyS5AlR3dR96g0bDimDB98lTF4yxwYEM4g+P9vFhOc0NQwlzYJ9dFgjyvOlnLivQeGQ1xAG/lvsEDdJ/NxusMkjB/hQfPIHD3H/MQFo6aCg5IAPXw6BV7vXsojrXspyiGWB8KALayH0emYp2i3bgc+FGiHn76zqP67PghE6/EZsTIYNnUXV5n3k07xEk76Zwgj8yUhzrAPL+9bxwqzEHJ1X9KxbCvcGF4LdTbRlHItjtUtV9BIcwNalzgF1+7WgsTGsSAYvYjn3djI2+LXU463Lx6IN+Dr7Qc4KcwSr8qthqoDFvjvpiAsMu2DxRu28gz/zXw07RIHLLEktyJTiqqWpRfjRuNMnVZ6vlICDNS/QMvfLOgLK4dFzs40cUIsOiwbYuTXQWwa0EWndP9BbbwCZFWJwfPgOXjpTSkKea8BudfzcMmDv3gjXJLnvC2kUTXuWO0qDH8LUsnCpAscf9Vj4acEltKaxoKKG+GVaBy0+K/DifITcJuAEGwt3UJO8yXwgL0cF86qhpHCL+CkhipGGv2APtsHlFZfBsEfNSEseCbmrFElXjCNV42cBSfPCdGrAlVaeXA33P9jhDTqAIVL6cK4AtOh/WfBfdlKqlo6DS4UXUJfMUl82BVHtUfvU2uYDCw/rQsmS+w5/2Yd7cNTNBg5nEIPWqFXiQQcDctn3etT2HPjZ7zXMwrmzZbBCPNmvB8gjWdCO1FitRMHu26kT4dD+GdKFyjbTsHNjlPBLfIyXnq7idbGbOIxms9wV2IQvt59AmN2e+PXfX2YtPIu3fARh671iPvzXnATz8IJNmfAyq+NL38N4TnDLThXaBeIJ6pC+htTeG92kuJ3TCRhCqTcX5Fc8mQsFB5Mo6CVn+hOVCr9frQIdgUZg0fZP/wqswAe3ZPlBydWQOVhSdbrcISCZi+UM36HwyJug/wOEbijXkIP/C/g9r2xuLPUjkuPziSTIC2y1MrDuf2/MHHlD9KZLA9Fs8/x1ONKQ/4WDjKuc2n55KMcW9xC65anUkCGBh542oX2+ZNhyz116P29lYbf/ATP1stjirENpMWn89HiGF73tIId9bZjZBiDr0MdGP+uJMekH3z2WCmPGDkOTYtaefJWSbysK4aH7SdgT8AwuLu+EtbKrsLbJIBruoNhlHMSH/OzwgmST6GvdQ8pbWuEy5VmIGmXA8FmSZTRtg92Vimylv8Raul1x5IhbhZ+2MCLixpxbf5QHpXkUtOin3zVrwaPOk1CITV7mGgnQfPGBYB5czTZS1bSgmsMqyNUIE5Hj0/97GfPfx0Ye0WGP6guRPfhfTD6dz5rrtSmw/+UYTBjFXyZDOSqNBxm6bfRZLGzZOdUR4rTPtCpOWOh+GY3jo0ygMcXu1ns2SSSkSuEMZcVaXZEK2amlFOFwEUUKp0BEV7ilDJSDM5e02H9O5fopIUw9Dw+gw78jrSHd4GH1z6YNroNsjuj+eljeQBpFYrNsOSjE2U5MH0PBmidQDHHIxB+YQfqGcjiu42u9HCdMkgu8EX5J3G8aKIszdl8jcXNOvFB7wRWefMUXgzfhOHtZ0GlxRKMKgVg8opAHHfDHTV63cBH/SUXxBZCW3ItrFpxgsRrqzDxojQsWvGM73u70Fn5Wr4zyFw/6hu9320D9/Ui6Vz9S3oyOpL+K1QG9ScdaPTqFxSrTeFTnZ+h/OJKDFU4zBIbZXBFlSBbOjbjmQFJSPWcDtNzqsA+pYefNtnBeHNXat5TAMtL5SFDJ5lebrPnYd7ysKk8CYVW9MGnNQmYvS+fzWUWsXv2P/zv8Cq6dryIb32zg3GV6jD2wFiecHEzrEUPulraiF//mbHMrXIwdzCBwydTQbi/DP5aCILj1TT+LSrPclIWtNJVH1M/T8au40U4dYIpfZk+COf8GuFrshLMFq2jgisH+OS/cr6f/YuEJOrAs2sCbmw4zv8kxg1x6iKwOyEDf4SS6Ou9bbxv5mFIXGWFVT4avDhyIfrPGk3Wv4ooNG6ArfzNQO/9Q1xg8JVF/33F2hOBXJrlibLfA3CBlAF/KXMmga2eGLfJCDRNrmLDzAfw2fAAmY2ZzNPkKnnlpa3431bms1lbYXDGAo5Us4RTqyRQ0/UONG6Zi8te65L1YDVndCSwxrNOCp6TyGXCCNvWmIOl4wL+mlaJbZqm7PSuicaHtnHTo4t46eUvHGaRxH7NV7BSAuHOTUsOzdSAid+SaWrBAjxfocZ36towOLOQ+qu3YP27Cjh9Sw7UMvrxARxH3eFxfKtuCVubXKS7rnYsFFjOe8VNGEevB21rQ5j/xg3kbAXQyS+LJxmK8BSbtehWr457BR5CutR+Dr97C8pnElzZqsBr5WTp+55uuDxjEZx5vxtGluvhLZnLXLVJEL/MFkGXrQxRIdNAINyalDOO0I23H/nMpP10RtIO8wIOY65/E19qGbqPSBmIbDoKv7U0qSpoEh42e8m1hkj9PhnsJf0dY9aPpAXrA9nNaARI+Gbx+NoW+rJqgFXdPGjGCGVe6P8bdyZdxAfZtznUZxr93KkG4SELuehOBqhuuI1bHjSCc+dSetp4bqgHvuett57z2Re5VBetD3fu7eXwvGvg9q6f5cInYYXgENOcK+LhQvdgf2snuThOopono2GsehhsVG2HUUO9qX8DYHViFaR5ukPoxc9ganeeKzkWdH2FoPZTDd071MCGPQtYcawfmLg2YMl4G3r5yYtWBodzeaEJ7fwqCbI727jxow6Mvp7DX306eE8a045jSuQaNp8TTNTxeo8nZfhOggkDf/jW+7ugFVFOIBsCBfe84MfkICyY5IMzupnHHbTh0j492OQqiEphLhi3z4Xfhr3lNTVbUEF/N67/IkuCZfdY74wIiAgPg6TnL0HLsRM7qjeBVG49PI04hJ55ihgw5iAuyvnAf/PfUnmpCrQMdSPt5M+YfPomc6ck1hidpenvxHjFZR1YOz4Pd78ay0WXFKA95xaL/1WFGikjqhE4wwt+FfAmcxtIuO2Aw5+G0EbVeaikrQKaj65wetUE0L2dhuKWYqjX4cKFxVsh+E87ZUlZkeeJHryxXgJMeoehScAgHiqZiQcr7+IsoSqafX8XudURJESUs21UG1zS1Aft23vom6cvhy6ZjzZfxXCpYSimNp0Fyx3P+LmyJY4csYSf96hAkdh57lVYTgk7hLjoiTWWBXiztb8JRt3uR3/Zu7iQf9PyVh2on2kwlFd1PP7jOu4VekvPd36EhS7GsP+vOPyefZdtxFthzT8tqKpSp4s/C/lfwWHKSl1EByzfD+noFoVPL4d5o/LhtbUy/fDQhD79B1Aq9BUeSQnA8+Oa+PFsG5fEeFC5ogu8dvkGY8Yq8+MfCuB3IIAOx4+CMxN/YFa6DTRO/QUuwmlU4/0Zt95p4PzleXzrwkhQPSqBT0Y8o5cmTeS7t5JuBhSjae0xjLSTR/Nhb2GPcRiv9lWH4B1hvKonHKv0xtN2czl+eSSJiqyl4dQrMWp1sqPMlOd0uMgCbu6qY23XSnhsWU355vfYIa2Eo/9bSA9yR/CZ6ixQakvijG8MmdxKtp0/4Oj8r9gpZQlX8wpBUkAE6qsFsOTZJE59NchPD48GySnJ3NV3hY4VF/MIbQ1wrReFu9rJsCGgEQNamyH/WCUqPBeHvzHJnK+7i96cCMPP17v5aNEWHuEySIouwXTMNZ2nteuh93RVmONyiIsyZ2N0gwKZRLzlV/ppuPdkG87X/s0a9Ruge+F6XKYyDWbv3UDS3kOz3VEAz1ILzrbVYfknoSh5dRBXh4Syp2M7vF0jBUfyazh7zgAFnPfgrHVvuTkhnJo/yPCy2nA+Kn4fPQ4+gb7X5mB3dA18yN5MayIiecz2Hdy8LY8dfymi59hzsFp/LgamLIdhZSpwoa+KdHIDOaj9Ks7adBcVvBp55/UNdOGtCv5znEHdE3RoabY4qPgo0LezE6kjpxOkd0hy9J9VvGXndJC5fRWaYpbBGJe51CE/CnIGtNh5VxhFGx6GBQNHUPDtXagc5UJ3rjyj0lnveEzCF/KSngTKNw3BOfgjllSlQLWRP9p1/ybvtycgQPoO+e3tg1F+AOmhkvAt7wEM/7mSll8ppZrB3eid/JmOmejxLokuVLQThtWqtzEiWxC6lSNw7RlDiJX8Dy+KdfOA/3SQeK3LrvWH+HTSERCffxufzjOCrlgpHn8FIGjGSMq/qEz5epF84tha7m6rZJm/38jkvCgWvhYDA7CBzLhizkudzqKv+mDGZ1P+09oBy2Ua0HeuH/VnO8Ltdl0oWVrNckMYrDZskL7tFcKV2QWE20bhOsMESl/ZwfO8pkPlGnWQuNYAOTttweJuOGm0W+JrQSeWXJdHuYtH8ptwA9QfrcR9sqZwsDGZN7RuoxMKI9EofBf9rZZkB+tIPFd6iz6uWIC/LuiQRpQm2K1K4Ki3zfjWdh0ZHkihSC4FoVeusC1oF9m5jEUjCw8oMtGAJw5xIDdvJVx9G4Jn9d9R4LoMLK3MpYD7m8H/mR+pr5zGb2tGwFOZcaSpdgEOfvCD2XJP+KlkF1w938IWK8aQxPqbrOfYBrU6JrCID4OmfhB2Ws7FN3KDEDiYx+Vq02H32gOsnV/HZQc2Q3KOMrh1aoCmVS/5alpS4mYrancQZuzNo0T5Osr8uwsalx3EzcXKQ/qMR8OSsRg/bRkbherj4Ym2fLJjPI29qA1LThSR3s4BkN+lBi+W+NLeUGccmNtGh5ZdpPxXKdx06Cz+tTGDqd/l2Mv2HPf/nghPM2R47ydv/mq4hQ+qyXLd8zm4c/54lFylzell1yhIewekxemCarwFS/vMR+eiKzxd4AA7R7ZCrNBHgIp+LKhaxTec76KHgRi0a39E2/HB7KJrwmmTvnAX74dPzbNpYWs5PBdNhVFyZ2nHS2MYkVdNyiXW+Ef+DxzSXAhFBsJwXdkDNAemgPX5bXgvSphSskbCqpulJHkgiva/KcC/Rmn85scGXvL2P5i8Uh8WVk/EqJYfqDHVCEK3zeVLW77yPVkZ9to/jo79DuLZV6ZDMznT8oTreMX+Dx4Png4LJX6DkncFfip4iEvuToQFGUdR+ag0qVVMQ87xw8A5fSBSNRJODNyHStfZ+BidMcRPgBSSr7PnrhJI/PIZHcZ4oVmQDR2tYKjwLgArn22kYyLDzWPM4U94DXrBdipfJA61/vn8feF3mHZ8BCTcM6XkmgaUiwXc82EtLTfW4o8CsfBlVz/FCwzHH1+GGOSsOLw5UgaZxrVY8M2U6yWe4Xqp42BqIksblLdQYmwHvJBYDMsUJ0FO7EsqGP0WXjb54nnvpWSzrgdeXo6n5XP1eKHGMcq2/sjFXiPBNN+fOs1mg9HLXjpaEE3ph6Ip0/gGtdtuox/jLWm9/kKwyZkErvtE6cyvxWzeWYZ3ZwbDBydJGrbKjvtauunikRrafUmekh6Og61LrWjJnUy+lg1wpm4u5O1pgLuzukko4B4IbrvNt0sj+aMXga6ADf58aUB9Lr/w87BmKpN+AZpPBkDJSx2Wbl9MrXeWY9CQH2Q5WZFMrjeP3/kWhLMEScyhCj/+MeUzujV4Y6EXjLZYBFqrtSBwSSrXK8WRRz9gSlYK3/WUx+z4KOiobYGju5+CScV2btsyAUZovEGJTzV851QpV8mng5/6OxKrO4W/8rxwxt1qKBn1GbwCRaBt018eK3GCfii8oIpUxooTE1FrUBI7D+2G83SVg6w+8+Jjw6B0ryyv1RvFfYtPQbHnLo4YwTDYg2jnNxl/NHRAqlskPdsyFvo1ASQ0JOlqizAuXr0KV8bNpZsF0Vj5SJUlE1LhUKoJNEdNhx2i67C5bDRNTSY+LjWU17GifEvFFXOl5sKma9txuF84r7QQhx2Ns2iwZRodW/+ejE5txtApodBkIw+zbBazg0gbylkXobbqGIgwIxA+NR3ik6IwtESRlXedhCLLWXjaxYIqcgI5tn7Iq9J1YOcmSzS2tWfL0c/pi0M5pDT0YOSMFhTZHo9xPlLQ42sB7b/VwW/7VQp8/p0TR2RzgtAlWORYyhpX/+Ee1R/08owr3xvRR4I9RpAdexycnKvoi7YMPTkhicckVvHtt1dIwc6ci14V0PyocKp9aAI69o2sGOFN5sZ+XOV3B4a5G1NE5AGa3viTIvRCacH0jVyWaATfNe5zbt9j6q4KIWtnT6xKruSRn+p44RFr8n+8GtZplYPp6ikgv/8YTdhmBwq/KmhLmQvmROfQ61c+NEIhl6tnnODLb16Rx9iR4LwgEja71sEp016edyaTH+Rsoa4uB/KbKQe6brtRc80+1GBB+PjuFiUmprK7dTHpOMfy4R4nrhHeRxqXXSn4VQjdvFcBLfcFIOt9Eq+1Xw4+N0ugLnY2XltpgBfdvrBNeizFymzjlRdvwX+qxpBpqUs3Ux+gir4/XJh4ZEibd/H3x5u0/cpVypBfgp+tQ3nLNSEIvxLJhV9WoftwbXglKk7jnIbz6ydf+NbfqXS8+yjt8/lMx3V1QFzsF2hevIIdj9NYaHcRBYlKw4+i01jANyDLJZSC1JfxzZApoP1NEab0buXd5b95XEwj+Ldn4P22jSD7PJmuipznhp2zcNfOqXB1w1E+efQgt3smsuQQ+8358B3Ox9+ic5ruELIoh8cN3QG+VoU8qWHgFKPMRSEe9KVDgJMPO0CbjB+uTlfCgOoUVlyTSmkz5OCGTwgrbBuGB5vCuNmsjgPrR9H0XR6YY/ASc4feVUzCDXq/ShNeWCyG+9qmYB98EuLGPoBFTy/zorU/4KKfG0b9vgynNF/ivZsi8KJBnfTGv8C8WWcp2qQG9DadITSQIwO//9BCZwPemSDIj3UV4JtZA1je3A77MgeHcv0XrQm+Ra9en4KWu/fhcV8e2RtYgliiCKgdmMjyR1RAQoAoom4d7B1MRhd5GZjyMBbunVqO0c3fOXq1CEzZKUNOhevxdOAdrDyyHXQXNqDSviiKuBZJMmaFHLqxHV2VRoDgvtnkefEarq9aC01nPkBh5A54/7QQswSek2bSTph+UA53xwyDmjktcGD1BSq2f0OPhnr4ZYcJIFR9hcIWD8O9/afQc0o3LPJRgdvBGfyp9Tr9d27oBg+N4BXhX3BDtD+/D/cCUzUtEvV/hoPxipDoaUaC6YlwXcOfyxuMUaVpOowz1qTQcUEwZf0azqtWotXdk2GF+GI6njAA4b+k8L3Lfdo9bTFj40u8u8mRImfGgrX6VTY8qwp7j2RQApiymsJ50lB4yOdGCnJCvDurqyiwTP8jaJj+ERcigl27GTSPWIn/lgeiWHE3NLUHocaVErq4zRt8J17F6oGTUD9JFdarvaf5hbLgIvYUb2XY86WbnZSVfRz/TZlHiu0SqJ5zBJp6ZGGauxxVKGpi/FAyR3nU0D/fq/Ts8Viea/kRo0pDQD0yHR33DwfTCUowu18CHy/5gG/0U6DI2xvvhvgReWmQvJQ//td7h+aKj4XsfWvokNcovORex+f3T+HO0bPgzOgvcM9rMRfNJnj0ogR1WsXhRqcLnu8xgb2FEyE6R4jT4o/Dg3ExfO/PCVIqcYLpT7tI5LUKhDsawpUGMfJ+cwtUYsToXvpI3mcexf9O1tKYP/uge5kbrzikCAvs1CnghBt5bXDia3Fv6Z5aCln+leCTZlkYHDoPxReMweSx46Hs/mqKndtCq3JbWexcAgf7jCXRBa951jZjPNNL2PrOC+VvT4MKg+/8bK429x+XRZ05s8lmzx302dYDiadX8MweAZTqmAktuZawa95wyMRs3Ow9AmC7D89//J2yQl+x8NJu7Eq8De57k1nwugK4Jm+l55cWUr1AMt2d+JLAuQ4fDWl7d10f6YyNAZd9uUC/NeHkAj/6Ly8JvH8+pgXWp0hd1Qvcbm6jxdOVQY+a+PucXdw3TBuwfy9X2I/ndLUejotuoKrT63n29CucN0sRv8ZaomapNGalqYKW3Ai+WRPMpYd1ObdRFr+m3EaxF/dZzPw0joieRk8y6nDbJy0o603jOfn9/FDPgv/eVKWcg72QqXCb2gbXc0exK4+tOI928xF6nNdgf88rtm7poTinUM6s2oLNeu2cNO4GSE35TNVnl/LBIdbOX6LGjUkJNGfscNIw3osC4xuwyu4ETRljjOF1fTw7W5HE7HWg8f4lDH71jVNWhIDPnkQWtAiGlb3OkDlGCXP27sHNfvthz2ZlaF4ryYUuTwHTxfh25ySYdjUfSyJlMDkinAtiP2N4xVEctBUFD8dSSs/RQEOdFDK4fpFapf+xs1sdSperspHECF7l607piZPg3diZVCQ+AbSOu1DJjbt43kUbrSeV8/u445z+3yxO+KBOQsOmgtcnNTx9WYr9XqRgamsDO9xlzPZQIH1VI3L+9pVstTv43itRWK1WzU75m2BV02u0uN8PVy8No4r7E6AOt7B9pTFcUEvFf7oioHu+AotcO/nDrAG+I7MDjJtLqM2sFjS++vHh0loYo2pPHnPVQOXSMlR8s4qE3Zppzj4PEvhwHIunHsSCVU9YtMWc0od69M2L5mDzcQt9v1rLMt46HHp6JB5Vd8E3ew5SYLIoGw5YwcNqFf40WQ2MVuRTndVoeJLSC8OOvqCoyXb4+6AcSA2rw+89Wry+QIvmpiuA4bqvuK9nHYiuOwrKsbrcKFmDLspP6dLzYPw0YAjjkuZg2jEGKesCjg0XgcxH60A2SI6Eh+nz6vAG3PQDwElUF74+seOwR9qQdK2FI0oe01LJQTxYfREMz32CFLu1fE49HGcanWHv0Q+5drkkSPb2o9VGd/wl+IvPtx+E4Q+V0HHhMza6rYFWeaLsvXsmZW8FWP8+BuxSqvGnVwesacuDNX/18RM/o48N9VC6SRzfqM8hu0sGsCx2KX+Zfpw9N3tAsYoRPzZUwtpOW/rPqIc7twRhVUoyFJpowe2UQ7R+oB9NhjRYtDGd9XbFQOQ5T/6cJMwVb39j4S5Fqn+uBFaX7bEuPpmOFb+mYA8TnmihQ+7f5/Hx5M34X7w2vVCLBHl7NbhSWot3uiJJz0oSzQ+txJfn4yHy2xKQ+rqCMh8vAovrXuj+VwfuHfuGcxLj+U9RDtjNTMeBpmqWmn2eFtg2oX6eATmwJFwVEYM43UlwLD2JAiQu4lfzBvLqasIpZUvJeYMQjPl8Bc4Y3KAung4nc67zjAWZ1KYkQ3n9mbgy5C/MWxHBXbmSmLl/Ip3/PAif0tThVGA/th5aAqPHx6LC7UU0M3Eq8rh/OD58Dx6ZO5Pr5SawfIwwjEyew9tlUnGNRhOPHP4Pdj8S406plfi1uJls476zaFcaxYSoQL7WOMq8mEAO9Wc4r88QxWw8Yfm7TXhvgSy+6y6BxgB/UPs0HDpz/5LN2HmgbBSHuwzroCB2Ll6IWIbFKQkUHLoIQwYtUK/JCKpimvjUlJOcqruJPRqzwUrOFnrWncDFS4fhiu9WnLVBC6ZWacMqnSLs3HSPAuddop3phWg1UZOCqwVRfOZNeikPYLrDECf6GoOmuggdef8ORK++ojczToLn968kJPQa1eclY6idCoeuysAjj4fB/mlhKFrZAivjo/HWr334sK4OPGfl8VS5XjyxxhGWNgcBlKnC3KniXGwcRnmtpzAuMQ09CjvI3WIL3bjyjEw3+uHWKmfe9m4UfEscNcQ0heT2eyVEvNOG0oggbi8q4BN7T2JL/g0ed34F+1qYQNbkU/SpI4wP2VzG/aMFuELqA3w+JU8F9qa03jWS/+gGowpYQufGDNhnPoeTCixwU95GuLHdn0PUS2jYg1QYU64GIkdCaKaUCpSkJ4NFeh/0rSpm551TcV9ZFH+zGs6Gzxy4YOY22CWaibxrKmTGzoFjNQuHvD6aBHdpUueLUdxq9BxWtHlRXNVXMp89yLuHq4D4yjvc7rQISWISt1fLYNrLRZTcVcbZwktw3uqlvG6rPT3+bxzkSvqwyisLVp1dA1/Mx7O96gh+LreUrUMUUOp0PgfeaoZqJREY0XOcy+71scnsWnBvCOPLyQ2kdk4VJcSsKcdqCbR9Hsfl2fpgZPkA7CrDePaDNHBbMR62Nr+AUxm+MO3+dV6U1EdjFPeTfLs8iASqwAOfGpb6mY8G/V/Q/UIrNvkr4jXpveSdbgsx5wvQ4jPChrJGjGucD36bn/M8kwVYai4LG681gHCEBzvGa/B+Jyea/8YYZn35BXNNLKHc3Z1DbsTR6/8uc5t/ISk4raadw0Vw8qfFZK4/ESqGmNnvykGes3wZjM5bzAWFk1H/yCEO3hsN0PwHi6YO6XmnJPwVz2K/pfmY82EPzW+fDYlhJRB8N4PEHS5hrk8ijz0ci/ZrlSFcyI/KFxngHMFfaNt7i29hIJ6bMAHSth/FpjehJHnWlPe/VYRxZ3dj0JluOKAbhN/dLHCXvz5/Uf8EAslmHP3uLXz9uR1PT5YHW9VR6PPOn58OSpGRtS5NSyqGpWfyeObpLt4kZ46+FS+4VF4J9MXT8LI7Ufc8Q750Io5e3onBffvnoedRQy52E6L21hnceHAUeJo84rR/TZAVKElO3y6DwadD8DS7HFddUuZhG5aRzvQA8PllAraKu8j+zDVctQ3gyFpF3nW/jXLHXIfLp+Oh/+dmehYxF9WeKsGB0rn4ltahffsL3Ft8jY7t+QtSuiakUS/JaRZGXFW+E9//NYDZfWWoYC8H1q73YeSCNyj715SnLZhDNU63wUbzDmS03sUKRWW4onMWWvKKMNpuNTTnioLb9CoWVDan1Qrz4bFfFnt/uwJP5bTAvbofB58kY+JlQ3w35ji9eX6P03A4bti+GWWF5dFnSQ4o/DCH2hn1WLfYA5dtNANJ11RudV0CZ72H40qBWmrYvgjtyAvTu9SgIv08tsgF0fxrBfxlTDysO1VMpS83k8HuxbzU9wAoxazFX7fHg3BtFJaKW+D+l7K0YdltwJhQ3JBSillxpljma43jsrTxsJoIpG62pVrzH0P77wGJUXGo/V8/Vqe3c8z4fKhuXE0vRJNQslkaivXduHxv4BCTTGKVeXpwRuw7zZUxximLF+NF9VnUJiyKMyo04bqyM997FIXFNargouRJ1n/M0fS/zThu/yge/7YL3qxygHMmEyDkiCs2zVjKTdlLWLDJCONiHLjUwJgLHy/jqjM/4VHgcLS/YAkjcraCRC9A4s0hXrtYBpMqL+Hp2L2w00USnaN0WPV2K2eQLFT/isHDLsvQ/ssWEN+gTbX/ZdK+MUM8dWcLj56QSK5ignwzVg8WRB7nru4JuNpKmwfPTKBejfWcH/8bypVWYeQsIfSOdqb9rQSf9saRlsUYFA4OResFulh30433eg8wfHLin8u7eEWRGLWPGQ9LAkrpQe5KPi3yCv6NiiMb82Eo2fGb0uQYFcV+gP+DFrz2WRz++DMkrfpBHrEaTLEfYCo7ctz7s0jCb/Cyrw8or7fgSVtGwcQwScix+oaLFjyAZPF5HJXwgZMuPMbks36cOPiY9Rc7w3Y0hnYx5LI4ITQemuXasF58oDydNWLNgI6doVaTNr7e7YwR2eYwIFaEfm8Wg4L/OvgWeYp6Bv7QFkMD2vp2CRQ/WkkJ2j7stkoHKOolZHwmPN5/jG7/tMKW9AHOULkG85Jl6V2UDBZ4zMUWGYJDOy7Aa9teUi1vJpGv3+EwycPglxfw/Ukn78+rhUL3VL65VgFUsj+Sd7w0b5JPx81R3hizURH7Sn6DobU/2U49QMPyF6GIKUPu7mC0D7vC253VQH9BN/4s2kpH5jTSB71u2qj3mYVj8ijIbRgU/pEB0ctvaO1LVXJwOAHrv03CZPlEVPA+BbIHQyFuRRwk9E2CJU9PslmnGRor24G7zylSaAzEldLJtGWtJUz68wwaQqdAa7AkjHDcDsf/yqCN61j0iEyFCzEWUBwixrMWysMM6uS11/XoqfQo6BUPZ/P29VS/ohyWZf6G6aOr8aXmPog+EkYbzh5AWD0GZTLV4H1sID2uvMB/VtvRLS1HzJ0qjQVuYaTktI5mGjSyl80l9IweDldrx9DX9eYk0dPEAk+KybpMjYvFJ6OJ/Vm+E56De8eps4q0BhyLfTLEmGYk+/AWlKen8s+92+FR4w2cGtWDm7x9sfJkDKL/WOg9vRIn+t/kpX/tecLPQVA8cRR8u/+DiypTQawiE/ba1cDxNnH4fmEMTU82JeV3M/H5wA0qaZtBm0v6aFHPMTwV/4FvfFhGT09OgWMzJCE+V4LiEg7Tq/z7pP7gMQhO8YKXp2bx1nl2aDbpGNU5iMCXpU2oVtQGnodnUElBJGlvlwKHh5oo4iNLonP+gOKd0WAiMw4sbTajecpkSPr3Fw5UKVJe2WIamD0Lsk+uYLUr0VSU2YKZR7RhQdpCKDpkRF4bFeHpuu3MkiYwZbw8v/TJpoTLIuAptZyV2oby3FUZ3s6Qp8kNnuS4SBKcg0SwavobKD4RjfFz5qHUTmvycx8LCnZHMGDeWf6yrhySvgpCXNJtGrvZFYNqXqPADxMSHveEgqUMIfDSBM5qN+fqpVNhueN/lJdXgzaFRbCz9ggcH5VEBVufsHuYJVQvDkKrzLegsDOGPQqm8ZdlHvB86S+IslwM27ztUPD3MBKuGwaK++JJZfgdOtDXTMtlGvn74Eyy6ymHAZFA/iJkS/bjK8G+Swn2zPSBpojJ1K3bTB/Aki276zFx1S2coegJiy/cxRNq1/iw2YihXiyNOsnvyUFOH4Lnh2Ga51bKVOuHPXE/WFffk7+afsIjOmbgVtuMzzcEcvILI8zo3E1vZmfD325BqAro4t1LZFnK25LU5QCmnxqgSQXbcO7tE7DsohDMiMqjJHlDfNHcw1M2XaeRVwrpbJkRzA0x5VTPb7BxWwE+k/eguUOZhydn47yjjTjuQRcW0x+wOGcMFvuGkdqz8zy/IQMCA3qxaVw/Xb/1narJDMUui8NJuygWXKkOl2ee5UTeBLp+6bRhoIKva0eAdNcmdq3uI8d5SWT4VJP33JSAN+4n4JmuIcRfjaeZLRGw+uZx9n3YT3dVHMDEuI6iVx+AgeDRYI2rcVWdDdodt6ZfM56wX0EBld01Iv+X6XDMyQKyBswp3swC5IZ785kyczQy6GJtkwvQcC6ant6bTCk9juTpm4cmV9r51hZxaNqpyHt2r8f6dH9uO1xKqcvl8JbsDr759TwXdl6A9J8DGLtdD/6ZFFJhvAZqyXXhxhTi8z0huDtJBvUc1UCtr5qsFPrZ4954WOzziyJKbdHJ9hFOHnUSXqVdw9zmADBvf8Zh5IPqe16DZLo8eOqZsdo0dWiZ14M9k9bRMt8/dPcIobTaMZL+XoLei4PgzqLhsOtdHyQG2EK2tTTeyRrOV1x9cEJtNOyWaePulyMpsb+KrvhpwYTnvzGKszBpYxNcOF/PPtJmNK9zLdWccqW4lE66YPGWF84Vg7FzlsCyPnXa/O0SDOzMgmWjkuDucFvO861A30c7WOz4ejR9Mw36Z0RAtXQSjvaMB6UAY9qtpMcw5hkaPv3NJ48Qm395A4/rJsOOzRbQ+A24ZuI70kzQwOK406xo9o4k89vw5cYdtGyFOwvM1YV33aO4wzWP/ZTW0MmAk7DTpwmuHRWBXz9PkEOWOycOPfuMjDZIlyArVawHTQzk3+ZzebNeCNT7/OCE/5TBY9sK1vjyhJvXE6hKicB/y3bhQMI7KJpfxkeHGP9KuAvt73pHEZe8yWexI1wdgbD93Xjw/BDDTcoyMLsoFD1q9HHKRy/sytbBjUmiME9lIcd9kYRX8pPQUu40/mYluiSUyj4/hOmCbyeUP3pMaocWgtna5yhkLA+zzf2w/8lwqjQ5SsumTMFL15OgzqEf/a4fpob9xB0RuWh1fRqU5gGvkzch1W4h8jplxPvNfHmF30jYVD2b7PSeYFD6RdDIkIW/oX+gaqI8mc3wwLM2Z0hMVQ6cBCfhvXX+tNzDk5+M6+CU7skgXT2CpARawDL6D75r38jO+d6wN9iNXNTGQ/39J0N7voUNjpPhmk8rvXuyBg0ylnKfrw5K5HyCht4O7KhexMtr/MF10APF306E23anuSqtHiImXkXNLcNYqzSQk+aYstfOKq72e093TILJ/ag8HDwoRBvSRtLlvFx8mLcBpF6vwY6DNWQGDqB2S4vNu5/y4sYJkKr+m2wb5kKdcQbMP+uHydJqaHu1jKdsm8IWJVK4/+JOSGkeDY/eDJBR4DoIi4ymyeLIB+rd6EeDDocZdFDWQ396GZ/G/0fReQVi/bdx+B4pRET2zEhmkrJnCA2JIi0K0UC7aEmlQpEWRUVJJfo3lBQRWZWGolDSNNKwEun1nj/Pyb0+13Xy+wbZTgGRVgW8uGsWXjOrIl68k+fW2uOyji/0wzSIZ3y5RvuuHgO171ow366Eo4reoNoSAb7qbsBXdZdj/dQtmLZLmNrmKvGXa2VQNUEHxKqXgdx6aXi4rh3Oj3pLy/QqeG/5XD5tWEcZOSupPOMRB/cqwVfl31S76wN2T7OH4QYuaDdaBpx/CoCWiArdnTSAs9+sHGKw4XBg9AHanWZMpsau0CMjQYYT0vF18VFODsynBzfXsK7oI16ykMChqJdilutQx7vPVKuXxVb9CqDrdoPrWibQp+F/cd5WcxDuMoBPJYtBP7liiJu7Yc/X8bDNRIIuJMjS4Z9/uanvIk9ZOhtf6pmCxPFhsCNDGW2VouGXwjwaLqBCRxzs0Ev2PtnIXcEVep/h/axR8PjcBFy3yJv2Wb3DPe+tMWKJH1qudkTVnTkYKjQWpOJ6KCdbF76s3IN2MitxVVw5igVGYsGxNiiJkySbmcFwxyCEqpqVcOsueZCaKIymQUUc9m8SRL6ZBz/C52PDsD6sFK8BuYKpdGr5KoaHmhCZk0l/i3ejoVsLeq45SYalc3jRUH/mStXSzj1KoBDVQX0LhsHXySJQI2aAb9+GQPXhN+Azt5ojE+fT2RNfeZzhDVrdeojYUQSufGyF0nW6lJilxfeJ8M2bx/zvxl2qVUwA90eC+E1CgsOSDMGwOIozy8VQqX4M5R0M5PtVN+mx9Vn48ScVm3MO4ZO/zZSSJAOTDktgrNhk2my2CB84zaUl4hEgcuA5PfLLB6mZdnxPLpNNtyqDXsx+sHXciS3pQmwoaUGHPqbjor2DsOCWNGadmozSg2tp6Wd5mK0qCW9WWeKxZbdQQGYabjdYx69++aOdeA/Ngq3o238DpsZKw4sz8/nIBzs+5SKAZR47eZ1MNxarBUGyYxmfzv3BlR+U8KuoCKx5eYU9Jy5jB5Kmse0ROLpwDucMvw5TZydy/9IVcH/cEropKgPho7/g3mFG/DYgE5YbJUJ4fR++MZsAroOxcOXrPL63YjY5dI0BmaFd900L5EXT18OPzK8oLOPK7fiN1lT789EjPTBNZTp0TBUBc6lfZKfeCEvGPaCxT0/Q4QMD4LlQjRvq72BY1hlsmt0M3n2TwVLXBzMiOqlyqI5TQ3uxYYMY1TcXUKtGBhdp3eT/hE05NkoSzIpmwTNjX8rfFQgC5qLcIGmFNxSnsJLkch5cJYdX7myDzTXiIFn5nr6L+OHxjFi0CwN8UvERzC4u47uWEmQ0wx03SXpTz9dhsKrfFEzn9PGLxngcyZ/5cPUHvJa+CK/oq5LJkb18YYoKNcdLwl69V9TovANU5r3igWuHyXicFdedPs3jTBby8lPusGzJDYo0lYczbV9Y4I4JrnEP5invbuBUh7E84fR/EFDmC0t+NvGy/onw4osIdK/4hzO8C8nitCDvTRjEW++GoffWWMpWeIHvHELp7bUYblAbBQfVgd+K6JF6fhU4vUnEDbeHs49CE6UHFuH7WhV21kM2LJSBp1f3wfl1BZi/9Tp8FOvAh8enw4/dgAlyNnD5cBXwYztYP+QkmkpzQV30IE1XXwwmfzbilWvMzzZ+5kvzYjAqbh5/z1KjqAorSN42Cttz8kldOInl9mbjo1FyYPXeko6bPwHHoCvkvd4QR6gKgL2qJm8a/g6MmrP5+jAh9vv9GrY0ZqFJeABIdabzBWFXMHOUh7RNu6H4cgF0FlfjQFQThec3sO6ZfxBzRo52tTUij7CDIyWj4R1KwsunsvzvgCanfvKH7IAdpK6tjXarDsKvV0OM3LEYt5YbwhcPXd7hbAOnRCbz2V4NVLW/j1uumXH8paXYbGvHv23/0VFRA7ig8RVv9eVR3K4YNB30xaWb7fm+myU2Z8zm9Yp76eFJWZomqwHlFU6482oqSzcE84JZPZD9wQI6kmOhcRPBZ7xG0zX+wwkPrUFpciHKr88n7YkptDD+N6ncKaXtkUGc+GwoW29G44Gdy0g1XBW+61fi2DkreOarVkrTsUeNPc0su3wA9da6YiSP4LviQtj8WRsy3/zBox7WuMF9HYo1nMfJZ1rhnkYFi2paw2GJIeawMOHJC9Qgb8QjPKUyFxe5ieB+1+egH/KFymeE8r2I8VR8eib8WKsHgXOUYZdhE9kl27Gw1xRa5RrBxybI4/K75rx52T1sVb5KKcsusbiDNKR6mIGXDPL6KRZg/HQ+BBuJ0WuV62z8aDodm5JFz6ZIgJaOHByhj7xc5iof7iuilpj3cGKfEBo8Ogjlfvqk/G0dq65JwWFR4lBSI0Xz5vvA2ykXsLjoAfrdM4DErI9oWqWAARdaec/QXL45NBmuP1+O4q5jceRGfTwpXkIGlqlk+dcbHFpXsG5pCS8N+4EF2gTX9kTDtTVIgp2RmJrZTdoX3ShqPYDHq994bLQ5zvoQT1+G/FetzxpC015xevVdPjJeEF1UP0CdSCS3X0qFhq2neGLKFBpubg01cUex8ut0Di40gu2/q3haVjuOuLIZ1md9wXeLD+Mfz+Fs81gM1J9VoGZMFpReGUatV/2R3quS21OgM+eP42WjKlA4vpBsl5jDgoxXZLfNnldONqIxS86B7PiZaKycDT6zAtlorjDWSR2Cfdu1oeFPIfw5L0tXdevg5C4VVK9tpIbNi2jE0G57lG/Fx5OW4g4XAJnSBRzW/QbGz78Lky3GQ+DNPjpno8d4Wx1fK0fDvsvX0f+iCCiXO7HzdE1+7/UMHj+N5hdrYil35hk2om2493QMzL82jDfoTIBNThn02OYn5c1zh59aidB4SgrvDt9EtTOVIMxoBMjKizFP0oTp+tP4zOxO6nA0IuvhuhyU/xm2gAHkCVfQuRNnaEajALGRJIjviYU7+gQRQQ+gJDEJfEzs6MOoPLjz1YgGyobBvZZ5eLbXHGIjujAS0mn6qTRuO72P7ovs4WR9D57YWEkfc/PA/Hw5ZOQxqNtXsdzZyxQ1xYRi9F0xKtgDms86ce3KSk4epsWpNo9J0dQMrDfagubIAZI5nE3/rVyJ5wtX8LinI2m10xBb3ZgHCbI36J+5BoQ9ussmtx7Qn+xAXtjqhO6jy+lwjCroCn/iOcWlOLYyksDFAqZY+ePvWc/5XvVE3nC8kQWfxYN7iSvuKphLr24uZO3itZjzwAR2Dc2VcHw5bknSBZU1lpC90JUDzn9l97Y/UPBYGQRtZ6NCmh4MKz7JrR5l8GFeIVf+yYYdk/dCz95CujI045tMvXlFQQPNuMBQL5eH929e45WVCdQhM5tcC17TuTMyeExmEloK/EKlGF1coGcGJr6muOrhau5NjiLN57609idyhfdtuCTApDa3idbFl2CZzng4sCIQ7Q5Uce8Wc/wxLZRaO+bT+VVjMNOqCW/latP7ETEwLm48pOe8pfJ1fjzrRQknHZmBYjX2UCNuDzKLT9K5jXfYYe4SiCgSgfk/V3LU2woW6HpJ7WHXeE5TBry+MAsz/gaielIB/Xo8ihbtkgDHvb181/Md6cbtwPezH9LxhBA8YuJDd3N34h2Z19BnocPG6ebQruROW/7T4h9NBlA6+w4HXTTmN7pZKLDbHcUOfAXLFCUe92do7nOq8fAtf9wcWwFPXmyEjH2L6O2hVXywp5nWzFpEL3W+wMnvY2DTowbYJ/gDlLM64d5JNQo5LAyLFMaQib8y629ugqrjmnBCQBp0J3zF3PhNFGsehZ81gsEi5TadXvxgiJunwFN6hsFh9qicpwsCe1bDpbPW4BdhRtq5PRRtswwmr4rF8Ovn6fSx2ag4TRCEnivCni4dUj10Gz7f/073151i/6VRUDuggnEbAUXH/cSKRdNRpXsY1C7czLHCz6COf/CDr9JYYeKLA57jYHZPBG4MLuXOxUQag6awKl4BJ6y5TyOERmCCXyC8T20mCekmihHRorv3zvCvXSUo5iYN0dYrSWJqEokm1ODpaWd5rO8c1FogSTUmW3CjvTjvO/ofmGtrQNrWedg1sxDHzbjMa/ZdQq2ZTpTB3/h8yFpqvpIDa0qbYPcpaTBQPYcdQUzH1IXY118QJWPrqEnqGm76KQeR3pd54b9WfvfCHC7mF3JggAqtfrQIxSxHkm9BDFmnSvDa0XPo59el7HFIBZzPMJRYFqOjkQCtihrJD6xC4ejDk/jb7Scfvb2WFKALpW4bsZOdNCiPu4hljhfxYsVsWKGjjDEbXDiUT3PZ5Q+UYjWbFMJ3geDQTRLVWIuz0rbhxYZ5dCTsCX2WlEIhyRm40tkFLeUTcc3DYLJ5rQJymoPYL7AYe4Om4rgPI+HPzFrSSl4Ln5ccosD8WzQxsJzfyiOcqvfhHvshr5b9B3qr/9LcQ2IkeegfPup/z+5OF0ldUBw7DM2gU30Pjl9sBJGtPuybNglrnTKwNSiGfvq78iqpb7j97xOwea8PgeIncIf/Mvo2R4yhUpFOP05DXaVrdO/VLdSeHkjJvhk8/sWQ/5pI0WmVcLZoa6dPO0rZztcL6hvfQGvhMxaU/gt6kffQ748xXPUbj1oSBuhYUkqef1JwwqAO2U75wCfL/HByvQ0blzhgfSjAVIsMGghWhel3pCnGdjO/67pAMklSXBwWR7W397F38wAnLBIAAbkxuOpKPomvq0KTrDDQnP4Tvu5ZjsJnBjGhzJbbIo1J6p8QSKZNxb7u4bCtqA3jj3VxUudnbD87HUPMxKCls5JkE1zoQbcezA5UolfTXuNHyfdsW3aC1qg+xYUpe2GmiRzn1Z4Bj3dALWdUoWjgN4bttuF74wQp/Vs3Zn7vAsVvpnQ/8xUumXIH6kwtoXq2OnTovsd42WiwWCaBn8a9w3OzfMD460e+qaAHB46Z0AmDPDhhN5RHvdZc/s+WGoSSuWGTEb9rS4GxpyXITcGfjl7fCE82fETryXKw5HkNypxdS7oj66H7yJCbfZiMU6bXouqGnWTnEQ+uvz7QoKII/DNyAk+j0fyquwVao5rpyIAvaN+dR8UFerzY2B4irW5x0z4ByLrcSI3qI2Ctpg0uHPmM/1Zk4XIxRXZ9GQ0jvTNR4ncHGMgCtARNZBylCpbRk1Em5yl3dfWh1ZgFpFI8wJetvkJN4D9ceV0H/qUm4v6A6+QzfD8o7x5PmTOeQNTbTtC60ArpnojDfQL49LDR0FR+CxRWfQKL0plcOVRHp19pQ7nYOnR/mTVF1DFUTxTdfTXgcOJv/Or7j13d/Dj3bD4XJzjDhdWDNHfpZXYWvkhvFVfyo/uCsEbeiNdXWkKVmzMdKZCDiB//eLz4Ol6XZg8dczrpJTWCWpEkXKm6S78senilyy28al2CqYdGw6EQU3ot1U4ygWGgPn46nN43EvY094CRQgjePtWCC3R0KK99CpyoSqQrfjk83LWFeo/q8AbzkVB4SAcGRzfRjeWC3Ow+GV/HXeKdokIoZ7YNDYyOcmPtFThuMxLyvFZBQqgNGu6fTl7qxaSa2E0iAukwwjGHhb95Y6hvMhreMwO5pzbwsOgYm435QlatPqRp6k+R+fb4TKwVHx96gaNcvnPacR0IEa0B/1thnDpvPYkOubVEbB2POHKBs8o7MNvzJC1M78C1LUrgkXQQfq60x2W+Utju44LXbDPpxOV+lhSfze99BnjPlwacd1gMlm4JxKujTGhDtTN4yJqB4nFFlsq1wvcuqVS9fwtdX1CPXWEAPp9HYuptK7JIaueI6we488NN3n2iGS98f8j3PaWpwuUUKR4cBa57nXh2dQrXznPly55zKN1QjAp9uzGoNQ21V1/lhJ/ObKUkApNmG8HIv2vh7CwizXB5PCpzDc4ZSFH+qq1ovcYXLQMBBBUNYVv8YehqqKS/3jdpx5s8kNlynRc8Xwkrzs3FJcnXMH1tF0UfEwMp/yNgUmlBntu6cG/fQro3rg6+WXRiyqj3oNo7CXTf3sNSHxs44D0XnD+dx/OvEY7dMORlA1PR9IEr9ih+oicratjx73qQ11SDmpeecGllJvxz+w1TOmezuKQsqvq4cPGQT8jl38AHAbM4q1II1FS16fFYP6ydksPHizR4UXkIiOYKs/atdZAxvQWOn0jmfBFLCKl/Tb8+2eGfjY+wcrcfa4X+oh2Xe1llGeF+n3fQbvOXrOMZbtjkcLxCPMXgwSFOQDwc8pf7MgywepIdVTw/gBdtNCnqiy5cSxGEl98S6InoL3xppM4hAVe54fU+lja8zatfnsEINIVPK8yAu7TY/OkBElP2wqeegVD++ycFPWlDWdfLtNv1B+84Lg+9BZNBSvsP7K06QyM6GyiPf8PPhBDyG2YDDeP28paOmeAckoGyrwFSd2pyaSzg3JN+ZLqhjRb8/IgKmcvgx61b///GAOx99piWV0nA78EIXPTiPN2ecxLdB3NwQmksh0T0gXudCkw1raNRFtvAzQ1BbfRmNBYrgdYf/+Hft6Lwb+Y0lPf+C5qetyl2VCbcH3Di/k86cDitlfMH2mGp7Q88+eAAqLvl8BqYx49Ls3Dh1Qs4wnIBPlwlDg+bNvD3W97AJursW9oGh/fJQfJoY3J9dgNqo41BGhahs8gYWHCuB9psHqHHywLsNzEA+nmSvm48RPs2/CGRjVrMY+JpwyIVSPjTSUsyr7KX+FTwa9UiFtvNd9+oUOWwGto79TjujDRl22fKYOgWCmfttMGgsAl3GIvS2enzMOftZL4ndJvUpE7gibmy9MzGHB6qPoWbd7spqWQNCLvLsbvqUlAUXMjX0i7CJ71mzpg1lHHOI2C0hyc1zM7iULDk8p1yXDVCl7oLfkKgzGTY5f8WdDtv0iUtOeh4aEG9jz7i3KctKPDVBrY3zeDW9x6UeCGMxc2F2f71PjTokICyUGPuyR7Hz8Nz6apWFc05+BcP5Ouy+zlBCPhgDwbdi3BnmyjEHlDhEWWVsNyzlhbLtMDkGA1sV7HAgLfH8MiS7fRk318QXC4PQbIF7H9oPqqWbeP8antu2mQNU+uqIGumKqdEfAKl6WPI39MSJubV8KddW3DY+HtQYhrPmvNqKPxHL6fdSiP3NSfg0A91vDvEa3tK82hkvjOMnPEGNjgn8/NJthS8PBu1PqnBN+M16PqsY8iNxsCDza5wmIEDLpvyi531QPazSDbIABOTNPDoMm92kPEi4UtasHjoxmg4jSfnGj1e1+eKB1+cxoiP06Hh/mesc1SDxLkL4cZhIbjflouBcmU8VtGbSyzkeInMdO5dEgx9OzPxrdZSaK8zhctVOmB/YjUdH6WLnvN7+fGNeojbkcipslugZrIEnlhP5JdB5DqgAo/eX2Q9K3ea6egNH0eN42DBlzCL3Ol+SScXF/rBBpFG+D6kZjE6gtRz6yNKunijTMk++BAQxw9y9OE/V0V62K8LOnePcF+dOFQI3+ObVIw7agfBs94ZDpdIQtGSPXzWfQsaK/4kwRHeoHLYFPbrarHshW1wLyCa080jOU11BS4QP0izTufhDLP1MP1oJHfJacD8WCmuvuJGMV63YNyNWziXffifowBnTO+ib315sPiiH79OHwte+o5wbjWjotcdThMbzgqJGrRobPpQHf0hW2k7md6+w0ubxoLC41A8P/ITWqxT5q3PLsHmLwsxKPAm28Z7oFioB/8tWYvh1QKwYMUBtJjcwePn6fHCsA4W8tlCY4fcoO50IBc36vB3JRU8O3I4lAVqUeLOdgrJvM+nrGNBdq0neEiMp2c50pi8yIW3qPWR5285+Bi7C/Yf9cWA4HsgZ6JHqk/E6cC4VgrLVGU1kXT8djmDXNLUYGpiLl3r1KEh16LZn9dQ3QlvGhnWDJECR+BlTw79c5uLCqoAO+x6qeqkLByaO5J8Vh7CeKWXfEGtgDTO+eITGXX8Fe/KzydKgZjuGFIYGU+2nhUMS/Pp3sYSErgjTBEJuVgiMIfWJgyyn/hwWPakgmMqqsjM3oseP5Gn1jvd9PbDe3I4tJWEeibiqPXdVFSIsCTADB62dEF5kBxAWzetf+PByte2Yr2bPeb7z8FdO6q4U3ACRIW0sGfwcuhSmQF1+3VYd54lPruqz6NMBtGhegm4Ln+D5qGikH2uEDKjbVlb9h1rjquGqlHB6DHBEmY7VpHHgQie+cUWrWaIQrLmUkz0yILponPYIn0f2syLp+yme/QpRp8qM16TefoRCN4kB/OtDxM/WUyVxstp6rYL+HVLHVx/foGPaEbA5eFHWOLfAvS8MhaaN/Tj75di4HXhCbzW7MWqV8fA88I/7EEdSrrtCVHe4TxlhhX4m4wniS15sDMjCaP9X9K3ACNIq+mn2JWR2D7QAPWzN/LjPllwzznHrV0msOfiV3B8rMXuu9p5XMAdst+mQusD/GiXlTUkfRwGF6MTaWN3DZ5JiWH9pdc5SnA31QlUkXZ8H42ZakC+Ka/ZTdcIFEMAju3LQfvGGiro3QVNgj/Qp3wni9s2kPDkabjjw2ds6h0HDealdGzqSlSYOgh3m+6DztcuOro6AG1iDBhS9DhnbyZtGakHd/w+8/nt2Wz41wy+ut6DbU19PCqU+aVODykfeEf3wt4jpInC+gX36F60FNQbOWNsnA5uvLQaq51kKVZEl5f5lrOeQTEmlpuAvnM1J11dzgsn/iZcNoYT5j2hhNnX0W9VLu+JyIfCvXZoLgnwokScsiI8wNc2Dw9K1OOyZdq45XYI8r4kAoE2Ki8L5nXdolC6PBlP7ZWgOtlwbFsyh7LHzqR2n+dkNtkdb7a349KgIip5rQAHQ97ijA41XNkkTvYV7/mJnx4dsYzm2U6jcaZaCMr0TYe4S1Kwe/dYmrElDKonu2D7bVlKv+WBpWOy4dV4V9B5OQlsJuVxe/iQ20RtAPuftzgrLBDalltTx/pL+GzfLzavmAa47TJu+JxPJec1oayij3YaPRrKPSP6FTSCn3r9xAWpe6Dd+i7d9dzD45a7oLW6GAiULoKvD0aThpwZbpxVx24VK2CDRTVYHd1CljXv8VLud0xdZQq3zc6i0epstO5YiKNkU1nF9if9vDx0f0dmwjGXGzh/7FLaoywBZ/WiCF+HwZ4efZzpI0Q1OqZg+FIObmc00F69oyz4xwH6RynCgQwzntq1HfKWd/J65etgKuvEYzxvsHiiNsZL6uCLO4M0KlwG2oY/ZIuUeNzgKMPNHxfgAVlbvibfy14mZbRqlgtlDGVF/g8V6JxOMO3MU5Lo+o+VMIUGLDvpYfto/iA8hyLin9JS8ZUw8q0srCuPZJ0rVpywbSM9rxRivZYcqrV+jzsfLycJTycSVOnh6D4DUJeIYl33JTD+9CaI61lJZksVyc3AmZNv7qb01lpyz8zhK5ay8G+zEskUvsCWS+EgXf4Nuq0FsKpUBfs9RCmxZT/XPbaCaQ0EGntsYN7AImiu8ID5IYag+OkzBPqo4sLXX6G41wf+Sm3lA4OjwHgQMNginHZtHIGiBrfgcG0yZWpvpnrPGXw65CZsCAzHTwUToc/jI5w20qDOYDFuW6zPLcWD5ClUgp4e2XxpngC/MTaGm24EOw2vopBeAUwpX8ixM71BK/skFc5IAEeVtZjsoA9nFs7DqCAb2Hp/OdInHQ7M1oJmrRS2yo6Ej8d+4tPgYXg8PpIVLTN5ZtYkmBP9A2davMKkV0G4MXc0fLf7wzmb0sE5I5qyHkdgwXYDWHxvJLzJaUDVNknY5qQLOU1u1HToLW2OOoABX7q47U8yJ05yZd9CXSDZY7T6gT/tOVUDPUtc6X5oKb2rPoFJ/+0noc9e6DDnO58IUID2vfvw8ZV+XqIzHrw3rKcXCvJcvv8lD0Amjt8RQU7Vpiw7Vgxm2/8Gw4YSnGgRS0Jaa9kh+SQ3BE9k7nyPIhkiuKColRoaR8NxLmBxszTweV4IF8dfJCndv/RzdBeoPvdGLT8BeH+vlAo/jIcn4Qr0K+kxXF4pym9vGWJ5uD3+sg+Cb39CYeu5YbBN8C+azxsPl/67gceXGtOvfmk8qhuKUwTjuWXrSPARbObrfZP44V5PNk/XA4Nzl+lGfTSLK4TDykNevIV/kov4UsgpU+cbkY6sEbaSptsbwhurWpSoUAKZhiI4N20y5u/zwXBRKw7fMwvk21Mpaa0qXz05GSTr5pK4vR51/FRDu1lr2PjgXo7wugGvToVh7qnPYPvBhcfaDDH6Ig8297rJFaMJ6h1F6PvdmxB1bciRhi8mJ50h7h73luU3iICb4Gs0NRfD+4fOwNWFbTR74DU+TteBO/ZXQHhNLTdtjSXXQgWYMIdYaeZ99DeZimHPD2LGlEruv2DA6t0RdN5Dg7rqhoO8gyK4fzmK4VJMaspl5PTXjB1er8Oib/589IsCRnrkYpVwKMwrVYR3X9aA2QaEZ2WnsGadDt/Vs+ZqkVxqCbzKRbdL0S8rnKZ7C4J0XTGWLguB1kmeMNvrGpVv/IGK1jU4PlSUrjY4UNyek7BtjRjYTrLFPItV/C0hlt/JTKMfOY5k8foV7kncyLvW5NFkYW8WmCsD8xWcMX3aV9q7VIgUX28jp0eX+Xq4JZ5acIGm+t4mvYgv/O+iBUjsnQujM+vhT38L2OsKUFxCFT5at57jc3axye2/KOb8kMOmy8BWuXsUa5uKgj3N9P7tJhjISIGlPxsxwnsOFv2agYuT7tKeCBO44rSJ4k5K8dcVcnxlgg67pBiB2uVePL/7DccsiKEJ52fiR/PxoHcwhXYtVIBpx0JxbtlGvr5YHz4oL6H17gug7sRu3ibwkl6KqoPC0xYOsXqFQYb6eK9FhFzyj7D04z9sPPEAPTrym9c76pF6jCgkFQdC/awgapknBBSbAociptDLSY9w/KMpsDNRGju+zOdv1iqw/KwPJr4YSyou+XTfcQBTTO1wX64Zygm2YunXCfAl7hsUqitAbK0bvfeSxKsPVeDBwfO8aWYFTx27mqL/nmKllwMkp5aDgcHyoG4XiYK8H2YLHSSb/W7YXFzJPfc76ZhVPLbN9sZrLztAMEoS7l4ugrLeABiQ6eUFF8J5oDkAi/dq0K/gVtw05ImBKyTwibYeRKkb8LGJ36Coop0uGT2l684H+OjRJrid/o/ik9PJ+spX0HNXhvLxH2jOeUv2yAog8/vJEGZpgM6ZwgzL/OmV3GXcM8INA3abgtnOQ1jyRYLdqqzp3TAf3p0qgk9wE0ZNk8S6jWO5+9I8DJJUgMGJK6jaywx3hVhi8TkjSFUYxxby++Bx8wosfqnAns6M0rk60DjGCH4bq7Nq8g6SzzTnI83u/Me4hM/UtvHvGbG4JOUJGP8xAIs5jejhrkzdiTfhZoEuF/kRlhWos0yXKfRNu8h5NUNcoKsLMrkTyHZvOZ2Z1Yr+Uj0UMUkZ3ssbc+/mRSzjNxy/nT3ExSWy8PelLNq2H6dsh3n8dbU59h/aw63b6qkg8BRHpvThYPA0XHSXoDS3g3ZdciD1ns/Ya36CRDx6wUPyIzbYlYPEy6fc++4Spi2WhKyVh7kjfg3pWJ/Exo1mnC2nx/st54Jyid7/n0SiLXEj6PuB/7/nX0Y/r84iC9c3XPncCrZbncZv8bvYIUmc5umMwwxNcX7Xj9DpM4nmp7+Dgp9+mJD2nEOG2EywKhJVOjLR7vELchlirf3ZgrDn5gjQ842kC2gKv/emgdh/K1Ht0ivWcPhHB0cUw83M91QpZAou7d94TUQobFzhgILl29io6gb07w4ig29n6ePuA3S38QTU7RSAm5Ne0YiyNgi7oURffpXzNU81VKl8js9W+PL0vhictikTVkxThjsLv4O1dhqdD6niGcrT8LLuA5ax8KQlFk/Ad1cp1fuGUUq6AeT8dxbNp8VA5ntn7nbbjc4eJdQ8R561x0fguoVv4GCwHVAJQfLnOIK2qewZrcEWrwp4e6QQ6eYP8pa2rZRrVgFdQWd5Zr8qLJthy2Xnl4DwnN/kZp2MKfH3WG8YkegvPUwb/Qusv3XRL2thmO70F3Z3hvKS7jy2EmWW+bOXPrasp7n2+njlTTKnSi1k0w26sLxvFXfc/8JnAxOg59AVUD+3FgrO/sK9Uxdjx8GD6PrtBc3/IQBKtsfgQ8xL0Boczm9nCcI2W1FYlzyeyu2qwexlJUauGgkz94rCx8+mFDD/F61OGoFrb62BLT07cKxHEcs9qwb07OUzcXFohZoQ0mIBLVkr2LZ96A58FefvHYfZct8gPKqZS5lrwuD+0SP40n4cdG9qorkTAmDGzb3grnaQTB3GoPhtB5bYFkfh2gE4W3Mv7PmpAeMLCyn5mwz/XOlEF85b0/ktKXyzWJYKXjiQoJw//ddXSsFDPrigQJ5E32rADft+VD9iBO8/9NITx0UwvFyZ2tXVafOfcrI6NgmiVjfTmSNneHXLKbxw2pMnFLeRgFgcbaB+1tLMZamoNxBjqQgGJ2bxaKlBuqVzDJpfWLHr1wqeEFcHdhXncPvN8dQ6ehktVbWCrFUrySZGjCeJhUD4lRPotPoltc0I5bWhy4k3d0LhdS/0+qkHlgcNac9/UvzT8Spj0HUMqJ2EO55awHzduyAoIE9PH/hgSt8k8LtSQlq79qGVcCNXSp/GaWqnuNj0O2VHmGNC+RRcRprU3akGC6+7ca3UIDZ01ZO9zVGeOSufF75y5kSZV9z79gkL+I6CD4PKcDt2DJ14LQBV8hOxJEaALlvos79JL/hv16al15X5zZNFtGCOAPw7cRL2fomnkq33cfoSJfwWeYkOhjwFm22x7OMzh2/FSoBikDGoebji6Y/XeJbaBI44PA4HT+zAuXm/aX6tBPjlK/C5Fg3MFpkIndlTUMtdgP5mCHPCgfG887oOO51bhzEzZsOkLaFsdCkA5xaNBs0qoqMZ9mTeE05PJlxDwxZn+mIvC2tar0Lh2gVQuMyS8s9YgpJuKVh5ipPvCSMydI5Dw9QxXNU7mdOrduPca5GQ9+wH+/1Rha9hI9krSx50ml1426bj6LUyCJXT74CxVTzQImfKFvAl26wJsHIwCx4ZiXD6vTiOdHxPg1L61Onagh+77rHjq7Ch/wnAZl010P1jg9Wea/n+y7WUcn45y1cANtZ6wAEbFXjVawQZN53hl5USVHScwTfdofi0K4t/OAaDcWcrrqoaSpC7l+mt3Kohh5iImbdNINkaKUvYCl5t9YILB7tprJQrP//eR6PXIETMD6PSlH0gYGEGqicfQNvGfzBD7xvrWhxG7dsXadV2Ark7x2B7qBm5nHlH11fZQO88MxRd0EV//aMBNuvAuF59srrZjGa7FvPc5o184pIH7Ay0BrlfGaxU4EHe60az7xhvTFaJ46Xhjmg94j347a1FKdu5XCghCUW7LrKc+QAuN/jMUKVLveZpQDru1LGhgP/NyaSzw4L4zuAwiEncDnBuNCZvdQTbxy2wNaCQ+9fPAsNvj0n69yAuzXeg/qsA6iXv6Ok7f2qdGIh7LE6x7e9d1BVqzb4j1cl/4xUQaK7krbeNARZ9osXpbkO/v8t66uFwy0kNL78+Q7QiiZ+rXcVTd0KpN0oUAtSr4aDwM7hkOBPeVBjBUi0d8FNp5aoBbfY9q0mR+rOxMnck8N87OMteAi/menFxwncaZTqBnymPpgtjt7Pss1ksJJDCE3xHwBTboWzL2AMXCw0xIuMHftH6RDoDK3Hqwde8YmYoxO0+jo0tDOMO+pFUwzXaER/OPV7j4FO4GK+ITSdUMmWHv50gnnOJ1ZXkwGn/G3o0Yj3hlXxym1oDK9IPoH7hIWwIz8IZPR/Z3XE552wdDoKDfyFAwgGC6ydBk7cYZ9y3g7aAWrhQuRPbtmrhv1OX6PpsSTj79DQ/9d6HU699oqt90rRzrSWkPpsOFy/KssO9XtqD0yn8oTDUvtgGk1Kv0trSA5yUmIXl9//gqAoB0jGS5qIaRzy2pQvXHBSH0lW+EORuyPUG37Hqbivc6R6A0QX5VDuTsa/yNG568pKtd02AyYeXo7h7L70r0uH+swsxaqgvbhCAmf53SPlTCuhb3IP6BBMIrevBDFMrOmcnRKa1W+lIjiHbueqA/PhvlDKwEQrsV9EjQTnQiT9NE3Pd4MijbTQm9yz4tmdC2LQTEH76M8zQDAW/ukJyEFEHRR9NntzlhKVVh7BnrS+3rNLkpdMUoavmIvPVhWz16jbmOltA0d2ReMzuOooF1eNlC0c6vOsfPVoQC2WX5OFqUhnKPM/k3wIA+7P/oyVtQ7XCOJi86AWdznrD+Zf24UsRcyr0XUc1nfXwMlMRDuYV4pUHN6j39kz0WSMMX48ocZPsIXaUKcDWTfo4dslTvvRuHHgVIAnn7celizIwK18Xc41b4PKyhySaXwkX9dZw4dJCEpwtDiHSMSBxZZAMjveBU+4RiCu2gZL2DLwZMgu+JI0Co2f6KDfWCu4NiHDeVgX6mhwOni992HGYGCQ9skQvs0tQNmYMmUZfhPDLQrDzZD6YW1eQtNIZmHHmAqiNyYOYswUgPShBfn+aWOV1G/16LA2dTtfRJywKpZflo7SMFuisPoVXLk3E4vm6vF8okA11Z5KjlQDMeKoBh+N/cWSmLzb2B8Gfu5GgZRDCmof06bBFNGjtOwX3ZQxh0foUfjfyP7aR/YbB93QocdoIVH/7kMnfcSizLuDJVW/oifAwSHxrBt//ZoP4iTC+ZrifNm+3wqxLW/Hb+zm8uOkOe4zT5JZzlnDlqc3QHngTXj8Jc6ZchdBLBjijbiFOOFKDL1o7wWpTDO9ql4OcS1s4cJod/9BpxBt9zAF3iZefa0OxcSKsW7EbbCttaP6ALEwt+kkvZxnTit+9WGXyi+JcC1H/1G8eWTgPdketIcOp2lhvOAGWnNRBBU8XGJzkQoeGPPPdj60wqz4fvsx7RZfHnkCL1YdxpbIIrDAdzS4vFIb6fBiG192mMIeVsK6vDQ871eOKVhkw87wGuRPN4fzNU/TF1wBzHwrxF7F2jHRYiNKKQaT/eAGaZIwnQaGx9MTYBI78U2Lc8gwUK8dCV3Uqr000AOH+dHj/2AP2Bp8hw/JwTGsVBbHELzA6vh3Nte+ApvAnev6qg9vnPsIDS/ZRQKUzVP7ToWvVYrBa/QbM+aHHhxIWsYihGUR/3M7fLh/jnXMWgd2ao3RTTJG65ZVhkv4wTHfZiKaffpKEeSP9uqXEFW7DofTPOWx6F0MoOoHkL2hAx7Dp4HG9Hwb2rUFMfcBn6jxxTrIzengK4eSPFzkzegvFRssDnjAAd/lb3LjyDRal5sHrq2vRRjMaqtdsJjmzJSA/QxLXHbGCoxrZMGhURObzc5A1arFDfz31znlLZ3Rf4P3YRbTwpTvMW2oMK+8dgFILU1DwHIMqYqXctPcRVnwcoM3jR1PEtBnwz3wpfy4aB9411ZwgV03tXqtxxVQTTgqfhXbf9cHuuzMuk6nmEwl5eEFDGQo7nkKJ1wReMhswWeYQjjJ3wFFHWvDRCB8ULTShczdGsbjcZLgxsJvr0r+AZc42eGJ0BB+OUsLbQZLU3dvI9YavIPt1Gdj/mQD7L+VxarUVrjX0IoX7GvSuzIEFv8/nTQOaHGEpjCLTUmmppjoYPxGiTxEzcXCLI09fUTfErZpU0p4Lkmr1lNHwi4YVREG/sSiMso2iqlHfYPKFVooZEQTN3l0QOOoqat60pmjHC5xU8REnFQvCDoMyqOmOpy/P31L367Ow238bn7+0EFd+aMLcpbf4a1gr7C6Shdyf0/hBMEGq2hXgMw44q0obZffk4/uit+TiPYeHUIwOh8iAsJMZiGc64+KcHbx3zSIS7b0OWoe1WTM5gWducqeVyfswQHsc/JbQgeq2DIqcuQiiirxpqWE5aod10JLpxnzZ5TasW7KdJnWJgWppFW7eIY0DYRm4LUkO99wfAcdnDaDWaQVM/dePdk+mUmfdBLAd34UvaQ6tn5uFn+2Csbj8AAV5J/N6gyNU96ePNzbEs3WCKQT1veND/pG0uTsVb/5LIPF+Ifrg/Jx1JJfhbrdxlBoxEs4Vj4HZU5s4aOITEl16j4cPKONoh9fgl3cDHesVWemRLq8sSEfnBmEISLNC2bSx7JG0gF1rW/DHWXEWNzDBkzqtcGaBDLCLJlv+ModXjvlYfeIc3Ez0wvrXUrTbwoH9/ypTxuo4loFX/C7lEdx/Kg3HvO6xTFgj96QugibHu2ywuYvj7T6R8tHh8NdqGg+fU8RoLwUVe75y5s5x9H3xPKpLDaEHXu6wyvs/3rjlLT42/8QGfQfg7igh6ArdTXukOyDtfjO8lhKgr9IR5C4lxls8G0mhr4DvPD0NUyRGwtm/uSTjZIx9dvnk8N2JpuWVofA7JQx13gEz4zvYuuEyOiQpQv+9SjbY/ZN6fyjhSZNPNHn3OZI0WkfO33ZAonIjtVwdzwHiYvC90RsVvZ6z9mEvuHhQmc51HuPE6BrwaxkOvt0ReK87kU5fEobc+cuh89Ajqmi14BKdIBY6n0AnzyVyXsMvPFZmwutny8P76WMgoOs/fndNhx0WBWPi2ToWXPCbJBwe8/ozj6m2qJwTfy6gLWIEU7LUaLVxBl1+NA50dj4izYkloGh4DcoObsDncUkk6/yQNsaIQm3wZfD/s5V8Mq3g/pNh2LAikT85JnC691oWGfEfVXXG8w5taVjmfIN3XXsCEfeH444n6vx5eQrL12Xhgyhxfpe0HTpCGD/SJPAQDMSQgs8w/qgW9hco4ObFESD0eS2IqefQ5OCzMObdHY5bZAXXWrRx+YslPH+kNbzye4Paaxwww/8XXdpTiQvuJnCGpANB4Aj4b/NHPDvjB5x9NwlWvDiKAtHRXL38BSV3XobHcQU4WTyW45+OgC8Nn2i9Zxmnb5tGYzY2YUpdBUd4TIVr56bhgQJTnDjdgcakKYPh+B+wc4cBSha20EzNQNhxpQIstEdB07exuOHEWZixbCZZ39QF/ZcHMdYnA0SyQqDt2FNs7qmm2Oq54NgRiCUz0uH152A+tH0MaDVqou2kJbi5xoe3zZQEoRNDO/HgC3TH/QPlyBu4MJu4/LI1zJIR5LCYq9wo9Ril5MdSR4oxr9+lQPVztPHu7jtQUX4bPokypBqowa6d06nc6w4GDrem+Yr3eVL8Ci4+74OSeSug5fMujlujApvU1Mh4ijxuO/SWL6I9JsWvg/N7l2BujjA/9rYmb71gSEmTgbIJo9FGNpHWiSaRctY6uH5vOQXsVkG3+1KsrOFClQX91P/ABNIq5oL9WnkW/xUCm7/r8ee8h5jabYiFn7NZXC0calp+0SchYzi5KZjLXD6x3glBztaIYps150lJPQmfXU6E21e9uSZhP9tLAHyoD6aQKg0YfJIEt/wk4IDPITbrnUvG7mp09EgUfVNqhW9BkrBq4VNyMqimPQ790Lq8DurPfUODjVtA1Hsavn00lvT3ONGuZiG4sCGHhBKz+az0WvaSdoMHTTnsHpqKymfH0pQeNar2S8IwTwm4fTgKlj+fRfflprLl41goL/+GKQPnoGf2Dx4bu5UbSw1wyn4R8Dd4QYZabyi3ZjFtD47h7of9tM/fHxWPHEQx6RMMsqEsUmcDfVN/k/NMfXg1KZUKG3qw5XUEJk0Wx3u7PUizfBo6CS6Em88VQDLDlkc+0MWzeedB3aABNle8IyGNIKhaXkCmwUm06NR8mHtLCFT0duJtMzX6MaIX5V118PvQrv737CQ/TjGkrkZH1s1Ohpo3w6DAsx4aw8/SqZRo0FcQ4Qzvz1DfUMk75n8HAftH4J6mAv3yw8Hv1nPIVR+E6PxGehbvDSNP+uOkk9vomuxG/FW/lUZtfcGFi6zh1BgPEPtvgLTjgmDkaiUc29KMIf6r4JhBPF0wCqRfdulIQ3M1N3Yh7NxjA00uiSj9Rgc0F1zgZWJzIKskEZXyWuDoCKK1IaoQO9SzggXukAZBVNG2kKpXlGG1z0qutZoDGuvUwOztWfg7xNlCN1+x948QTA1VhfCeaLpx7DscvGtKMm/XkJyyDSX8eAEr/g2DuG0/acxOTRiIViCBE0ncOsOB8wqWgNsfV7Q7V85fswUhNHM0TLDtpyz9fRxy/xns89xO+Wky6JZcBrMz5vIH+7U0PlQOG9PVYf9wAbTZIEmPj6Zxm4co1QXGgOQUIf6wYBJv0b5Ja0WuwMjsIY594sVT6t6QS0wo2kVmoatDOcUWreDq4l/wqVQN5s+4wptnWMDW4P9Qd3UyitAbTL3qw26urdiwzgR318fy8VmBuP/rHsbNNiDx5wG7ymnTw/YVtPOTIpTr+pFVVSjJ52zEzEgtePjkOGdPE4BzFoO4ReMXvVm4AOdHZ8DmK4vRetQzDvmVgWevB1KWRD1HJyuCfPpr9uuxJb2sVFjekEdZxnG0P2ACiJqqQHmFEU/bfRHN01Vhcs9bjJZ7hTtfvIJUuRIaOVsbFBLW06XuSnKaqMW/U5TJ4qgojDuyD3N1j+Fk9dOQ5rydP9Q2som1Pd+MU6VN53bjkeIn5GzHEKK3mWuMbal6xzoSiV5E8/Sj4eA/L/p+2pma0q6Alcsw2FoqBWtn1JNB0Do66RPMpp/yaZqoHjnJOVP7qQnwwOUKRLuXsN0hRcjyuUUOehKwy/kdfunX5ndD/RVeEQCO213woWowFrX7sFegHCjlrMOZhv2QcFMWF+/vh8iDQhgpVczfJUP4fehhflJpQavXK0PKE4Iel0uUdsUcbP08eJ8w0YWnp/iswnOWf/WAjQY08JQBwzHNVejiOguejlbH/5J/U1v2ejjaEUch0SNYoaKS7sRNxtj6saC32oTFZhXj+v6J9LThPF+6cpoUpgqy8c8guJCcyU5nTvPcYeawTUcOnrb2cMzde2ydPpHXJfey7aV8fv/oCp82Ogayam74+bUy+I62w8mrPdBU34B9hFQoNn4CFNacIKvSZwh55XTbNgqnjR0Poy60QqxUAs4BA75r6oCwzAnjp/ui7OlPdOSaITxyOgX+dfIQcPErztnURW/VKslizAqS36mMF9rycfap4exy6ygE77WlzT+NQOS8G8+plIdIj3ngq3CawwRaeaZ6CTcp6ZN7TQVIdhZz50MpuDZ/G59QrWQ9vwTmQxrQs10dI8udqN+hGhuPT4OJgxkka68BGqs+4HmLaqrd5QNv3Evoa7Mat0it5C8xepSZtRXKN6Vj9g0AE69tYBc+nIUePuUtHfnwX3Y5OxSupFlLPOHIqiL6GLKfPkeZQlaPAagpbAUD4aU4J3glmo5T4k6tdMw1zIH31Sr0YdswKl5lCXMPFtO9HBF6ZS3BWw2KcNev29z9QhjO/LPkGzsW4RKNaLB304WV/Qtp4c4/dP7QGXgsFA/hW89gkKw0djYcg8GrU3G+z0R4bzYSrknIwujaOUgXNTFKWofHzqjgC6XSkPjNCQ8PFnFyeD8HlRmDoLkmmyk9p7qbq7D5xD8atD1Bd9PiSC9sKv9NnIf1G5Xx1DodcCp7CxcDDXAibcDEXEX619FGW5uT8LZeCUyXlwOrJfFcs3csdHslQYPhOi7R/Qjzip7QJ7PfuHnmFF5g9YG2mq3neBcdltpE8O7nc9YrrIemXBNWr/qNpqlDMySxG6dkn+TRrVaw3+IoP5KZAPVN1iBTZsYeWV4sIuZMC6qGQ+7lS5ggGwXfhHNhQmEW6aRrgtasYH4oNIxwuA3BCGGa0LqdiruLaW96KU7or2WRxCK4oKUFDgLt5CAwCTaNX44nhrytMSMC1h1bRY/+lmHygkwq/heHH75MhN06dnz7pwkqy12BHd7Ea4Ju8Ye+vzT8/9/cVX7DRt1+oFMxAQbOrIXMg9HwJvIbrfsvhb+K19C+PxfJ7c07ODf/De8z/IEfQBuiVq4A4T8H6bhyEYkXn8WYxSKo+yAN956zQLEVn/FGfRjMSjUDZ91C+t5oiscneoPSGE3+ItqO4g0zIHPseQ4t282WgxZY80QSHDbpY1uJOQqqzKAXisHwJs0cFv73CiAwCCJVxTDBYBXq7wDoytpEp/M66WXOQWgQuM9j2qRo2Mzx8Kr2Lg67yahwPhvNQRQ0yleRv1s8SDUKYkW1HwjEepHPIStqMlMFzfMDLPv2M76aLgepkcIUsiqFJGEs/BX+H3H33ZDj/zZw/BiJ0i5tpZR2aSkpySgkUUZFQ6GiQlZRyk4aRGSmJEKRNopIyYikJUrISCGFEl9396P4PYPrc53HeXxe77/OxzhhTQ4255zCcT7D8MbDTLgX3Erf3+vCjoj/KOTkJsDXSTQyphcDD80GylWkmgQ3CPj+nOQnVODumgkwdrMSW7k8oIimd3zk0U50WveFTv2YBerPJoKaxGiuTfCl36/kwdbmDm4ZmpGO0xWQkXsLjw3c4KW/Smj66kv0cpse2Phn4d9iHei6cBNf343Csc2KfLwvDuJWGbNAvR/O1NOjzP9SIF0qh3/mjQBD6y84ybCX1PTnQVHUZJY8Homd5/fh8vwxNE43lC/viIMxEWpw2ewT2IoF4bLct/z9UwovO16HP1x7seHuMso6lkml4zahjrQNPM6eim4uo7Hp9wRsaW2koNFv6UzXI550TQ2WxFfzKu80rt0tCDvs5sK93FD2/vaYRwtokfjSO+AkoQ2SHcPA6Ykm3pcphJWqmvD2hjhWzVqBuzfsB+8oYzihmcN+f0sh7bwrXus4QLcPviWB+glwfJgRbhyciB/tr8CsmbrouSGA7ihn4+PJbpi7LhKyZx+mX846MHbLHYokY94m8hblh4nhrUkVuOiDC8LoBF4FA/xglQl+G2kBN/cGwzaN3TC4Ko1WGgmjqUEBTndbjvFuP9FtTx5a7FClugkSIHw9DXziymmO3ydMkFeE0VGWnB8WAA4KarQtwJ183jnigD3CMiqFl6HBsOGfFf84oQYmC/fQua37aG/SZhB9uJ9Sdqih5l1T2P4whI93jIPqwI+weeps2pbghA2vIlBbYT4Kzt6D+xuP0eQec7C/VoKXIu5y76h+zKt+yz9aNalWO5n1VifDbPFhXPOwm3eXaYHinApe7BgDZ+fL4NaICHhss4IcJonTxeXH8FSWKnWnBYDsK33YHPMHtbCeZktNR7zriGtmzIbl2+3Z3+UvSn0T4jcXvViqQg98f3pjTMgSKk7TZp1HOfjy1FHw/jUWZ0cs4pQT7XCgXAZ/WCnDq54GPvXSFdb5ldDkKyI40PsIz14RxOcB3pgVLsSDSxLIN04ZRFqv8LaxvXDzhBKNeW0LY/Iz4ezBYhJQ1OaY+Fz4T6cMZwqqQWbqZRiOmVAi9wXV7yagnlsXzZ7WiyERNynr0gIOzriKp83GwpOgVvg0UY6jdqdhR9BECHzzHLKmbuT9zmehMDuN1H1vwpeTavA0joFm7uG5bQ0w2NxFLzGVtQtXs7i1ProNhuHJeeEoedwIdDQv01nLIHQesKONf7rxZ5cLL5nvjZtMx1DRdUc4IFQFM4a8EVReBYNLnpFwgj65D06iXZcyaMPlGJLIWoUj2lfBwsFWPGBnC0EWi9DS2oNMj1XB34xDtCE5GbROPseN25bCcaX5bKPcDTvzxUGhfzW9mXEe5uqrgPuj6+TwYT2bT2zGQtMa0PWShcWfRkHIIxVwKrfkwbEBsKL2OcOlm3jfdC88TwmhMbGXeJIPg0PTLdzcbg5O8uNwz19JmtZ0gT6mFdPpuBLacn4vec/qZAOhRsg9tRnNbceBY5E2D9MJhepHr3jDUzNSdE/D3K+ZrJW0nL3L17D9MGeQVdeHsq0zYflLFRATVuJ7n09xjOtEyLqxFeWUZuPeH97Y6NUFvy9IwaSLrnz8kwzUmSnggMp2XMX34K19M3gUFWOl9C7u/4TkIKcNCvN+01P+w25SrVSvPZGF87Q538gKR/4nRWU9UzGjXhYeLhUE65n7QKlchD8nl6NJoh0um2jIqS0isIPuc4/UbvY3qOWzhJCm0MEHRgrwHX8/Xn7zCFeMrKLbGn8gxl8Wmn4YwWbhcYB7jUHiyQpubb4FwknLkYKu09SQDrx7cBffmSHLYRuWoPc6Cyo/KwDiU6bxIi17bHz0C3PDntDF8b180nUHXpsjwWcehmN52jBU7tOHzyk+fBHv0viyLNh9fTpfG1EB1urroBbasNAtGzrFVTC+dzJovzBDlaogHr1+PvkHBtJuvQKcMuoipLzwRMFdlnwrJZpN2mVBPUoFtXUPocSvdBRYv5dvFOej9o7DVCCZDKW516mgOo23CmtC0jkRSj/3GsCgkCy/HgLXp6/IWvwzfnXr4S8+0/FU+nTsGy8PipKbsOzDOgx4nEknj29Bn+enMSjEl0bMccfTguH8QOsXR9spg9PiOTRJVRPFtaPRoFcds4JyQOSNDo4w6sffwTGUd/QfTrIbD6SmyP8C/aimOAZePHfh6rYF+DdqEZw2F0SJHfqQl9JDVxVNITJ1LHW6zh16Zi4877QjPrdNglQ3K1Be8YOVY86SnXMn7XmqAi6iTqjcfQ/KJo5G167LmPDwHb7xsqQ1poU0cu4IzhE6y/OkhWCTlDqMbCPuvxfAK1/M54zpz6ndwx1lPEbAb+USvndhETxLkoAPlp7w9u4pfGEmB/lO07hiSwZ8zxXHcTLzYZflLbo7/zhvFRsFD1SGQ0xBDUq+cqCRqrrYc3cSjI1u5yusT7vzgtCmpho+ezG4JA7ZqDYSzmfthexdC2DzGQfQV/YnTJwCDm+tuWaKKLXkDXXwx1V0Jjcdf4wpBZsfhvxe5zKbLyX4mtlEcVqACluU6drzCf+z7/8u5P0UaduAYhJNIJ+8nQV6GsDtoQU9mKECgoUCHJA0mSs/AWxN38MqVzt5gl4/uJxsxClVz/C/KnucffAc1n+2pJAmcbh7Shk+RwlTeeYZlEkBznG5RI3bxvHHqXZ0de/Q/DWrs8aUNsy/ZAs3z/nQpKc36VDPaJporwZb4wpARSeMar/c5c9f6+jQNXU4/F4GVsjfgBLr8Wzy1hdSNLtQ40UsPCgtZp87t+j46HYs+TcHTI5JwyjrLKh4bIABnnXM0YWYmJFDZ8vHk+TVidgTOsjVZ/Koj7QA9hvQ4ZAvvOnp0FkCPGle5lZqmp8NInaX+W3UJxa1yGezmZpQv/IXiCzJggffcinPLAEkHuay7obVfNkOcObqDaR3X48H1mmCZ1IiS5jM488esnjMyoaWXw3g6ROms873DBiXnw5qCnNp42Jx6J47gWZ3vcSvlmlQYHgBofQefWsaxfWJGVxqNcBqZfUsKG0Cf5aOxYAXV2DSugsYO90VRv5xAos04lU3n8CdZHco8trI5yrMwV3CFAzXhOLG38LUeXwECU+xhWHx3WB8bT+NbTmO7gsX45rNWvDUZz+IOHXCLls34OqROHuOGG4X3M0r4lXw39rlGHqumtK7zSGiOZ53hAazzDIDHqVmjc7GIThuyKIo78VTd3hgxo/ReLrbBlQ/zSD/6CGr+1XTjagD4POwAfzaDvLwC0UUk6PGHmGuJPfWAhIfucLdgMUgKNGEd6PKuEBzNW0aFUob3DPovKADvz17ibPKdcBAqIDSX22iypQMPOciQooXqujfBl/Y1T8SnN7v5pKre0ileQz8HV4DOlsKObG7ktwkptLEEyawOG8s5U/ewUUOpRS10YG+nBsOBRN6UEN2OFRERXDTtjqcaNKNGyY9RCPve7ghXYga6kTho4s+6DlL0m2nw6AjXo4iA3Gg2dGP1fGnqPjIP97o+ZBWF//jaQpSMM+xCsZdqOI5syaA9vvxZHTSmzaKf0d/gQ/Qfu42c85RPiyvB9JJ2ri/cAu8XB8PI2xOcZwqYdk4Qdwbcp8v+WZg31oF2CVvCO8f+dMF83g6e/cfLRytz1MTekFaxx6OHbCnqoY3FKMkRalnJsEyvAMRyVbQvGQuFFg/pgUpUzn58HYcJ7QCRBVEeUt4OU/bpAJS0Q5UOOoZq7c74eFjFXTBUJRzMzbA3MbjkCI+HdedyeY+MXEI/y2NvXO6oPulINvlx9LaH9f5o5EQ3rNH9r1URCfcN3OktShc/rMbluRKglvfX5L2z0TcsAW2p/8F7r0A7y7uJQnxuVRtpg7OSRbkRmUw//cJrIpNBtFSFwgt1Kd7W19hcaIvhD404wGriXBJ05vHrvwAszTjSfzwFJihfgCz/Z9i1dZCcNkdybyujOS+SsLdhTmQcxxw7bhXfOXKILqodMBS4dF0YMkrspL+Dr8+rcATKerQ+dIPJwTXwD3XTFD6NhtfNC1GpbXfyXTleXwXe5BHXNhOB8+YwJLH52Ff4QsKtP2DYc1lPMk+mP7/7jyQfw+ljvdwQVE7d40eB6N1nXmL1gI+fvEQvbb0Ba1xz6Hq839Us3QZtahHQWKTC8SmGUKnmANdOzqM/i2xpIetwVClkcinvnXiluFrsLZsBibbCNHhGoLykcMwOn0xeBjI0caWRrg5axBfhcnCN7nmIeP/YNj5giL/isD42kLsD7xO3g9kWbN7HheHyoNOpB5v3mbKHglxGG47AbNspMFHThQ3P3xEPrIumFkZypsyXrComySszA3n6oxhlFocyKs3aMLa8jkwZ5U36N/7hjLCcTz8y0wq+mdGe2QaIe5KMSWe3IAZQx1fR/WgPL6WCoQuQewrP9b8tICvVR/EPFMz0klfh7Pv+/GqGoDgR8M4X9gGppU0YoV+ELzoFAdJ90FOWmiO5ddj0G/iLqwIVoVPhWokWbKSLCw38JZViO/6duLGu2uh6r4dG+gU0PkRjSxkpws6FycgXPvJv371gnrMetYavEPHxhaDWsMduCXogh/OLMfZ2kIQO0sWZT7ugp9pb/B0ykI8dieX7r+sJc0dYug50Ih+JytZJ90UNOpbQH38Y/j6/C7aZy+HG2HDaWeJPq/KOI3OZ4s4+I82VF1UgbvrgsA0fTNPvPeAZqw6gTpXHuFStVuwJDgMLWUVwC6/hcOqhSAu+h5+OjITSt07YPfLRLZ5k80OnmfIMVmI19y6gwpRR0hYxhzY8Shvf7GH7gm10PPPN8Fu/Fx49SiZvcbHorylK3fOmsbLj6vAC/N81LH3hQ/d72iybTNJTNnP23clg8D1Ci73LQWh4DWw280ELOXMIbH9EMonnkHvR+707d01mCjiz3+CYskzLIKP+cvgodPjwHwFU9rdWOzTNgG78mdo9PwAD8Z+xfMy3zH2WgLnBrrTDxEpsLIsBaXwBJoXJIKJly6irupIKBrVzsk2VTB1tAVWT06Arxcng3TkbdQfFKewaGnu/y8FQ+O+g9qlq6gXa4PupI57H4jgsTIjWJOfyiuMEnjqiDBITuni3kcnIKmmG/cU5rGRriDmVr4nmUcaUPM5jqXv3+fRip9Q8b4PNX9/ArJPtHlNwlp2UT3FxRWLwfbp0Dm+r6Gnno9Q7nE/7BwLoCS7mBu3rSWdDhda7XMPZpitwGVoBI1rq+H6gRpS7jpPEanWdOH9X7rR7IgHAw5BfRtReN8r3J5jDRO81PH2mftU+fc2FL6Kg0j7NNiZa8v93hp0/stSvFYhCYHfAM7pvEK75htQ3VMPlxc6wpjmFJifEQgBNbFQBnFc9UYB5ap1YZRICv6UyKcqPTuc03eLE8Zkw983EqB3yRueuktCcuJySm9QhOxH9zjqgAO98q6AZz/rqLDjIz54uBqHaW1n7cmrYbOqF/1ZbQxxM71YR+opnFquyC53wllI5xe9iViMkddbKFNJk1WM9aD5nAKITJqPa5aMwhohezyj+gI+9A1AV+IhcH5vg/mLGiEz140aDoyEuP5wEMajWNx4Cc61GoHtHHUoN3PAVsFanustDZ/XbeL1S0bBz5d/4Vh2Lm7yOsVX+l/B9TUFvDNtDp67c49ej/jFfcFHebndaJgmtBSurQymmXMuoeP1cTyn9h3Whyyl2SW3uD53KUjs/4ubnk8Cy48j6GLIFRw98xwovBWByk+3Sc6zjyXflYPpfQX8t+gqlN6Vg0Wh4qyOHqz4LQ9e98aDvcoZnj1xD9VLvafjKz3w42t70LmrDDki+vB0tin7Lasmh2+3QURHiG5/COeu0k3kq3qerKYE0Ln9AlCyUBS+pyiCu9Ih/B4rgXOvlmFb4UzwmtMEljX+4CPsy35L5eCD23V0XXYZor9sYFXXerZ0k6F9P7+h2PACmL+viXY1GvIuEyHQr03nP8HJlGuViOuiF1P2uyB4JpRPC1zbOTJRAERMXrLZ7bEQ6/KblzU/ZuM1neh5/yXGnPJkm3ANbPyvi3VPBEGdkQcF7VKEezOPAdn4csKHNXCpcQe/EkjEOz/3wjgRL2qRleKjgxqwLkwZvl6ORvGpFbAvQpk+re+nwZybWHTCnIeNDMfatEUYI/kCnB6NAMe/d+niyigqO6rHG+/48QsBM0y8dYfkY8xJ9aA77516Hp9FGIJShRkszrGk4eHukNMmxO3XNtG7Oy281aeTI2ODcd6eFN40SwQ++PRDYtAuLskz5SXzVNB4tBlcCzaA6h3TMfDdK8i/MRY/JKjDjORi/nPkEJ3rk+RwkVXwbu16sB07iJevZMF05xMsd8uL7CvFoHrrTTbdXwyyXS446OxCliPTSCbxDoyJ20ttInYY4RLGVpmKoCD6DlMNO6BRuxlG1yhAYLYohon2QJVmE3ntL6H5+hZYtFcG8nVrWLLnAgkfcsD7rMzfxNdT8NEKvmJSyvFd0/jwKym0TFcDOvQIy15I4T+zUp48bxw8S5DDKWKpcIx38ubkC7SyUAlzpMVg463J0ON+F0+qz4U786Rgwa5YPJQtgYfyF4Hn2tdwa5wSzlyuBuka4vw8sAJnzioHz+fX2TBiDEd3bIXd/h28ZsIRSgkop+wTBpCRWwNTtevQ3fEKuvoyqujI8bRz+2jzUFv+LP4HYGeNuF0UXl06StMkLcDzwn08u8YN4v12caGbG1Vq3cODU0JYJuMC7/RTgHDJGJ58vJP2lS7jDnd1VvQUpr4dl+HHwFO29rXG99uN4eVuWch+0o0KqrthUjBC84ajaLTDlwOrkujw+4MoNr0SRsv+gjFjreCijwyHdNXgya8JdGixDW+VyMBPgWY8ayCb3kTVg8Wcg2j40ApizoyAmh/93Cwzk3HRfpp2ayM+rXAilydBuLIyC3o/EnzIkwKtTlc0OX8Ly4bc/3X4WpBr7qZko6/8+NJQB66fQu2xZVh6Qhj8a1Koy3Yvd4l+whn99njzSQo7uxtBZqcFJBuNxPlzJoGeNMPpQmd2Gvcftl3KIMcV60n350H82fcK9tmOpoOsiGkjEzjJdyy4+k/hmjPLwHJZBr6/+getwBB2ZuxH8l6Lc58kok6qC4DjZHCpWUrl36JRv+YetPpFwusrB/hGy3/w5lA4jjBzxyumG/jD01GwhQZhm/FO/nuhmCpXnuNC1yXU9NUR8kYkY214FQvMvEWFMxgEdj3jGQ1y+G7bFP5Um0pp1aqYNdmRQ0WkaeUKE1z8ZxqdyjKDTY9NyVl5Cxr26bC57CZ0iUrA61eMed69dhC9q8kfY8RY7RhB9t95FHlmEW7+7x5flJjGfWaleKue4ECIJke/EKX3bipk8GQY2G76iHvMrsEp+/WoP1OBKrYK86ZGYfr5+TIJiATg7hpXPCKvBNHLnPickClIK5aj7tY/tFx5GMo9N0O9TRtJY/gKaEs5j7NvW4CcnzZ3f0uGs8F29Fv2ORSpCpGmhRYVt1aTZVc8ek5XwjcH5OD+jBOc/Wsn+FXtxb6oQog+ZgwCk2ZCgfsx6rx9BPYGdNHSHfLwaGM1rnm7Gi4JB3PpBzlYO+M4/e5QpQvZkaRXaw5LCo5A0BpJCJvwCO9++YI37zjDgJIlP62r5jj5EvhxaADGD1tNLV/MYE32aHCwegtvZodhzUAqivuVwbqGudBWEIVNym/g588mTp51CuVuqYBikhH9JxGCc2LjSb03nbdeWobFs47ghpyp3NfnDh1BR0F/rjZIH7eGz1amUGE1my8kAUu4VtEj6QBIGOpph+H3ObFBgd6+1wMNvYnQ0fIQVlnexDetvTBTtgp6/hPGvKxKXnnOE/cZafHHcabwZJQJXHmkRE4fn5DHMW84lmWHi1fsRauKbWS7cy3suuXA29+MAhX/P7y4u4PxP3sUm+UO9Wcf8vNQNTzaPYMubnxOH27+pEx1IxhckA1efYfIIeIBJH95TaohSzH/SiA/e2FEos8/cdCFb/wxTwV+zN5Aif7m/GpRD7XfPj/kDUnseFlN92x/0DT3OPSaZAiVqyfBXsVOKLUhdp66D5+5PqE4y3/k1hhLbNvEgUX38HO5HC4/Mhyemtei2+AgpJ6Pxzm1ipijJ8ahPq5QbapNz+I2c8G2TgzJMAS9V1W0pcSWo3dkcb9lOkoU1cLtSOTrhqrweX0syavLwk9/OciaUMS7pYJwx3xtPif+lzZaJmP88B5YpZSNc73+I+fkvzB9vhmMv5LKyxcm0twdP+GvRiSezFGnfx1yVFBqSbtdiQ7Gq2H/cSPw1h5LwdVzIdM7nqfYdMKzeBvyj5rK3hvvYLxpGlT9JwYm/6mDrkIBfHFJx6DIfpQ1tgXFvzFDOysaO0cKkHv7U3B288D6ZlkQnOvEbR552FUvjaO2puC2DVNo5K6dWDktD25f/8jBk/Rp1UMBGF+4H8O3tnDx8hK4uzKIVEtM2SVrLtZH1KN8J/ClldNRLxBBedZ5jqmZiAcVdfncC4LdOVvBz/AhBxoupr9ngkGmaw9N2aMHjoUPeFnqeJo4WY/nLp3FLb/G8EO/l6T6ShW8Enaioqc1vLMaA/uiqrBIQIHkgxZx7ba/KNoRAaE75/NV0T+U/HIjvZGfAaHe8vB7ZxokbEpnY7fN4D7RGjUmFuAptTy00rzJ7yuM6YBfDj3wsAW7L1O54b8UGJb6gfdrx1FL437Sx3V4fXEphMT343MNA5p+VgS66nex7KiMIWOmkl/DTE6yEYfRC9PBvtqRSlI7QPfGJOwYj3BiRDje/1NCrp6mEDRmGUwRXY01JzzwgOptLH8Xxr+F8+nMiWFw55oSzE8+T2fbNlF1oQ28aY3hypMCuOBnGk55bk2RIs/AeAzCGMFMjHjmz9vf+dGV76moWviaI84ZsKzkY6gKTaHgyeIk/kkYrufrcH7gDBqxfR5JlYrSavVk6t8axC/inkPQNknMKwiHrUPdU6hXgNbnFnNcRiC9nqtFJtFhsFZwMnyyLEedSE+MCRvDouYq0GXVgIIzwqnwwjCe+GQd/Nz4jxxUX/Hi+E569nU+DvhI4evXCC2iLRRh5oTCsw+x1S1hEFl7DKPveeNvxXF4f28MVyncgjGjzMEkuBELHhrDFZCAA87v6euPcfBcOwGPe9ymnY902dRnLZl/Y/jqewoUbkmTquYJECt3x1qtd3w0pZdWGV/Dg+H/6HRECq56Kwhy46fhC41iODA0I7N+DdAagzuQnVHI1W4tOPGgKdZfOkmRSyxAUCsE9betQCWfcLq2ppdK1TsQrbpZWS6aw629mBZ7wY1FujB6njuUrYgmxwWl+KfJCjpndvHa9DrQLL+HratDQDvfCAduA4w7+ItDE3ey7T5XXpRXy7ttRtDxXAcKeXMKy5ISSfPhDJK5Zw5/yr7C2ukGLP1wLQiu+ga5lx356ldJ2DRbGD2cfShBoY2dzYWg0moXFM3sQYeCp7yIJfiBlCPEBaWSz/dsljEqAzfMgeNFw+BI/EN0f12AV+MNcVCzF8slKvj8tE14e7w4+Pw+zIemaKDveXm4KuTAfV98QLi9gfU0bVjwaR/E1BrR/Z3r+J/MBo4pzsCefQrwLieAPOx2s5//Qzgwu5jdfk8DXKBPTi+W4sb+eywRuYklXk+AM70O8KL3KpKJPrgLaYHy7EpU37kHglyTaM/BfJwRs4U+ZiqAhsZc2Jeth63vbcDb5TONUXhDrpYWML33FPgp3aHm9OewKJphjttheLV0NM19XIJ3+Rq0OOqRtm8nj6mT4+YDKnjklBs+0BOA2IXqrGnsiSW/v1Fl4jZe8jCArNbvQ82r13mpQAWOLU0C3xQJSDixh5UTn/K24vV8rCoc6y66wuvyRrSV/YV/vryGz3ObqOaoNBxU7YRjYu4k1KPLRz+P53Z/cV5QlEO54T/RUXoSJKzZRd932oJp1gCMjpamLabl9OOxNpf3JaLbtcWwaq0FK9SfR7e7yjhwTw26TGNg+4Z/eO/BS4pIvA/qrq1seOQYHVB2wUmjjemjmQo5Zo6CUsN41m9yIpPDSSD6+QUvf1kE30+W402dQ/S1qA+v+r2FMzMZOlL/cVFqOCtN/QGD5sm0eNsHDlM4QTFiV6nIsxSf7/Ee6hAVuKRez42ekrip7Cuvycln+5Rq/OzjzKry5yizWIscf9hA+vYxQ07cw//eGLJOeRGExnvxvivBJLblJXz8/AcVbqTB2yWdlPLPGrRajPlraS8ZeEhhn3AmRHwIwBuGq3ih+wfOFA6D20Pd37dcA6I+moNaxXGSsfWl5Wej+eiEKbhqoik+XTsV62o2Uk7lCC7LlAIV4VP88mYcdghZs2yjG3erNWHOjGC6+t0FLlw9i1NuCJBBnQAka93BPL0BbtS/RWXC8/jkLi0+UO6MLScnUO3OWoyOSCS5g6ZQHO2H+XN9aJ9jGH/ZMQVzR2wmq5EH0Tp/BLxuOUpxggUk3qoFns8m0saqT+A44gxf6bjLMgpy6FJhzrJ6hiDakEzRHzx44xFB6C8aD1XPgnB0QT29PXINfl0WwO1p16h58U1cbN0Gk/P2ouwKE3DdeIj8fjdToHMqSxdpkVeXMxwdiIODDge4vV4XEsvmUr+RNozuMCOP5tnUkSEMkyc/ocQphDMHBjjzfS/Jdu/DyfeZHd6NhKiBJxT4qpVGRgfSkYvPSdtmL8THWYP/zASe//QGTJwcCdvAEpZuK4OF4sz7DWr4fU0ehQYUcauYA6x5rgnhssn04uROZkGAH/vEuGZjJsoteEreRg54O1WKWy538NmTvlBkcI0Otz3haG8d8A++QtIKafzkqTAduZxPM2traEXsBG6ZnUh2f35x8X4bmJOuBb03FDHM8BL/lysJwavPkN60VL5qK47yRbLcVj6TuxsiMEvNEgpKTsPbwGc8SuMTZyYPzf+cofZumE+l+2+jyFlrrD20F9KDGFID0qBZ9Rfkam7Fhk22FBNlCV9WLaWYETdhRPx7dJFLA9Ph+iD9eTstLPiImw9vYuXUQbYtdKMZ39xQ3asSlgyfDd4/v1BHjya8GF6JQ5TBDbbn4d3hBtxm8Awsyy+jdNgGvig3mzdv3osxF0aBWqwiNxywIoVeO9Z86U/rjDN4hOVk+uR/iVtPiOKwZ+aUsmoCvN5oz9m7pfHcSA+wWTecz8m8A7meRCrKcUHTPbfBsWA59H0ygXfW9rwiZD6blD6CsrN6WHjBCl6YCdKvwDJ0393D1Udz8VGwEPSmi/PazRdZrVadxTf30yXVAlgtrs1Snnkcs2gBhYS9xeN5mjBtzTHcLFOAb1K/4PGPijhxgTpKLvCk8qo1aFfwnTSVZ7DEZRWwVcnijXqn6V1VHmbFNfK6NY30a/Z7mq2iib7KMzD7z9B+/yABWRtH0cFT7qza1A0vbXagS9IKHH1yEI/ODwDj2gi4/cSTWxu14cqZXPI2lgNjKROoM1egkO3nocg8miIH9gHmO3LcWUlWK5UByRdOXJ25BztObcXQ47vA49MKFK71ZNEtudATcwm8PKzBR8kQVjdbkozucgwqjcb9VodxZaAthS/Lw7eSR/DdnrO0c9paWPpUDQ7H6iPgJtpo85MErQ7RVM2PuOjLAZrXWg2j1JK4cf4BUEybCDpi+2HWfzPp/Bgd8rFU5wfBMjQi/hKPPC9EfRWLYW/jbJAqkITwh83QN+sUr9k4DJyG62FsqwOV9VhjQPopfOq9ntcFxuGEy9Kw4849bnpzjNcdC6K8KaG4S64MGx5mUezuYrYQyUCHytWwzlEeLK0GMKWygtWsg1Hx2QFalSeHffdy4cCD4zBZ5Rw3LFsHKXWCcMHZBDcvsAWdx1ZYWjEFI8XKcNW2Mez49yOGSpwmR/0SMtuvA7FD7d32egOtNOiB7D83+U/wEzyfdxfe3DOnkp59/Gl5AdwzkISsxrusqrwEunUtcanFcFjS9pAmRhqA9IcWcpyyHI7u+APZJ83A84w4+I++ygKGn1n263jceewLLPgaAz1Lu6FBQZw243S8/GYkxJ5TJKdhE3FNoRBGHNoF0VWTcKKkB7eaPIXNlhtYHqTIslYCToZYoO3WQLzl9BhEHovj2uOqOJlmo4PiZbq/cAtofBZAa7GxcIINqXlOMbZPMYYO8Sc4XDmYRkvJU6nGbraVXYk0/jifm46QVf4KbQMMMSvtOXj0pkKubRr0Fv7jo3lR+MrsC0+rbcXrVmqQt7EEeiY04WhLP7zie43tIt5T27RSNnTt49rbT/nJJCP4eFsWdl5biF/MbMC3OY9P3y6AXI119ENwKZu9nQS33ujxDnFTjnUaDoc+HqLCjg4q2/MA4x6MJ9Ufvfx5yQW0WfmFnl+LhPPbuzBhriykrzwPAbfv8XrDu+Rd+ZValVK4xNcflYYPpz9D1jcNs0QZK4SNJXvg0642mpKxGdp1naDdZyMOuljiqthLsEnKDL3bFVB5tzgYZV+gqQkToOPvd7z+0Y/iaz6QUf9ejJzfiBNC32FRnQ7k+prBoxdvaKbTYb4/6SdmLZnOay4+Q8/mqUPOv4Fhd1Zj1PQqPJ075KYbbzFy1kTWi1xKgQcPofKsCNI7LYR2qVNIw+kqbv2sgnOH7omzmyax/aPT7L9SGcJCBUnn1S841Z9Cf/1OUkJbCGd//EXhagLQMb+dHaUP49b8EOwyfwCql4vovsZYcPZcgIdeV1DNsUWwcp4s7DfJx27tXlyUNomMV1Tx5PYSzHUtgvJ9TigXJkoWyla47qUk5NuIwLNjR6FfqQks9/+jnMEUEBhuDC/9g5BnSUH4JkleWUXwumQ5PnE9x3vLWujm433YIvcWXLPK8Y7/BLS9PYkrP1TzR3Uz6GgYxVevDaLtnJdwX1OCk5xDqSTMm55cPk3OPSVsrP0W5EW1QNR7J65N2EZp3xC2TrzBUq2lKNZlCnW1syC8tYOO1A2n1EQ9uLhZBB33WZCD+ljY4ZQKr9os2d5/MRTpTMHgPHdM1anDk+8UQCGvgv/bJsNFYiJYn2LC06ergkZ7Kjv8/MQdpwPxzbW3aGkoB/OuadErgxxq928nh08zOUA4GER2zqU+D1POL3WiewEIjx+OBrMHDvih0Jr/CIyjKqXx6FvTg47TxWns9W188txwiC57B67b5eB21CrQ/baZbRbOJQ/zHPZ5kYzDv+rD/PI4CDCcgD2jJ4PHeHV4n1mP+VIW9PCSK3iJ/gFXpSewImwZpn7+wS47lLn3/ln6UzAe1gjEkpJNDa0yWs3n/cIJl7jT0wcyXOjvDFcFdTnV1hvTmhVhsWsu6fxo4VFPptBW+XvcYDqHV+qXg1SENpgH7uPdl4/Q8hIJaO5SwNum02hpnhpZChiRpKcu3+xshtT6ZHYMbOdYqVCUNFGHJRMdaMoxCTxoZ8djlL5waLYj32x8TVd8V+Iom4mwuXg+71W0AZHVv2jz3+N8obSEjrgChxpOIUW3MNC0DsCAxm8AQYp0q5ugK00XD415AJfa6shR3pFeCI3Ai7N9+LdaFpVZz8R/Gq/JRlYNqqLmcZ7aeorb/B1qrWXp6nxhyDH/AyGDgdhwRJDR+wyHdw+DHl0rMlC5iYfDSuCwkRXbGH7Hj3ZioL7Km8qeDPBkQ1V42S0NeY9uUf9lZZbHo7ThsiGe8zgMzTL16NEeiX9j/LFwXR1Ht2vB3ZWLKdLKCY88EwAT0zdQYuPH0utuQp1AFo1YuwP9ZE5S0jJDKB6nwsEBrvjZXxum6uuQbEMSH3krTEbbb6Bf/1R+WZiErjE6ME5kETg8NME80c2crPGVfC5UDO3YDeSwuBjMs4/zZ70T+LJXEzxfOtLXbZ+oRy6HzbsX42ejB7jg0VT+9NEH0mVeo93c27w5cug9ctXlM3tWgVF3Gy2sLgP3b0X8Qc8RwsaIYwFtpX/uehTlJQKxHpoY6fuHqnKGk/n9EPCX6WaVfZmIfyXR/0sv/+xWAbfOsZDfcZ2nNNbjwhX72W2nA70xd2Dt51EkEzoIbz2vYYV9BGmYjIRTfbPx2VpNXH7EGgyMHGlhqAy6SPZQmspGVDKyw+un35DPbn2o/pXDtRqvOKXsBhz0eIsHh/ZwnuaQE8gTBHfmYtpHA3AaOQbSp0+lQ64afJHjuercARgpUUd3yg1gv70Rba+Nh5jeduwfqQmzlp3BvCWPuOVpDB1L+csmUd9owHs8DYxMQbH7s/GNVBqMWjcJcF0dLbeM58GgzWB2ajXHnLLm93+rAV+fhEDRNv5hUQKyN21gWakb/Hu+FBZPb+Q55tNBY/o+al8xmT2n78f4hyvZJeUvZhogXO8sw+VlT0FarYtbU9fQtOsP6VmDPfumjSQs8GYt2XlQ/lgYZs6VxC/3wzA/NQGn3veF37t+wgGNK+A4YzGsu3+fUXUbJC2wgNwTu3h9wCToSr7FJ4yGuufmE3KpsqZFV8/R6Yrb9D71Ob5sGweZs29xsVIDxiu+h66HGnyh+BO8DnoE3y66sMGROzjzxBeC/VJwa+J6MjzQisWfc+DWlRy++1QJtF/HUO1NL+zVns2XIY12rZGHeYcIthX+R0cOf4eHGk38oLiFtOdGk2tOEAw6psMrp0+4X8AKbpzWZ8tqX7zSpoomDV3Y+7ORfyclwc2bp+h7fxHJf4ln26+j4cY2K+zo/Ej77TyoZkw+dw7I8opdSTxvawuYiOnxloxO1KtVgTdNv6E/Q4n2abthhJcFvjseAxcSZ6NTbA9cvBqCb9bdBqHv6pDkNIOOjf8PBx8G4Uv/47A3UIKNvsyjk8376EPcK14U3DHkamNI9OnDb++C2GT6PVj1YxgU1KwER5fh8N8OX3yy/DpWiBOoWYyFluROrByzFETM7XDr1mUoerKeK1IAvkUKk3HTIsZdJ1FWfhK8c36AK5aY42JLgSEbz6f+CXWU+LmMgvRL8KHxUD8OdrJxlwRMe2oD2c+uoXDUI76VHM0Ff0RwQ3A56TsOR5Ha35B9MAQOujI8tjtMvMGLliUkwcTEq7gieQrlzpEmCwk50Pe+QUuXi/CDcgvI98rn8bl18HTVBbijPQnaxFxh3OlTkDVlHfqpbQQv+k5T2yfBtIBJHGU0CFZLz7J/WzSPujaZRu2ZC7qO+3hnSDeUyE+mN8aW4Di3FZ7ZzsEFLYq4/VkvSIxZgqNDdrD5JBWU/j0OIiL7+Yb8WFj4QRoufzqAW1ZdRJ49l25fEwCNc1W0Zrkx6vtJkqvAZ3YTnQxKu9xAySCTOxt+Y1V2JGPBbXLqFYH3ZTtQ2y6Rf/kU0ZnL+lD8KALif1rQz7M1cC7yFc3TvQ6hnxHH22hgXoskr7vYTwtPyMLaenWWKTuAH76shAszpOHwS1se334KvazboehpM74WfctWPfowqDmKS14ngPH4LJi/aDXf3PMcD5AC/n12m4/fDSWa6sYTxpqAVV8QrCiRpxnv//DatSFkVH0fN0it4lKz8bi99TKHXjpIJ04IwPdaGU7Qt8IDKk/J9MloerFgA22yVmP9DG2e+LSKhePH4zANE/iSEwX2a1eydogjzYsOpRPCh7hJOx27O2fB1OqVFLSeaE2EChhfuUUWT8rwt8kPvP94DPqes8dhTaFDv88RrHdmQufWGbRNTAIqks6Q6sjT8HxzHw5bP5b0Imdxo1c7ONppw/4FawA/zoei7cLQGj8Kvl9Xx2v3E2DO8GRiCR8oeFuAt545smDTFg6HxaS13QYyxHpxWfxvjB4/mSrDf5LLvUzU7rXifXcT2KjSHRTkdEj56HDQ7iyjtJ45vKJkDD97cZUfF99CZekQlKo/AV7Vx3H5/ImgfGQkGF+zgoMOS+m9UzbtePOFvWxKOLLfAWZ7BvBr+zqU2mmNQvNVwd1DFParzWLN6QIQZexMM5IWccG7OWj4LYQ2m2ews9EM6FSzhdDjM8hgkyycispA2+ZSyIk+Rc9ZFssOnQSLuStg4WMJ7DSQgR22U9mi7TXoVKRxqtkCCLNKwZmaquiVq86mP4+R/t0SSBoylvPvOayetI/+rJyO2nH2pNcyn7ME41jZIIzyk5xY3kmautv0wLn0O7UY7UXvQ59Id04qh4ZWYUlvJHwwdwH0+IVr19oP3d3W4CR5GUwddnBstQfurwxHob06HDpZFAMmaIB5xju2/LcEM3q1oM/HkaKWplPDejVsVXkKQoYWkPE+nQd6V8LN+N9wOnc3ruwWBpHoLq4ZpoB+j0Lw2YkbPHDvGl2ufgvfr23ghvg4uKvZw0+9LKDD5gFvN0ygv+fiya1yBO30PYUCRzfSftkH+DLdg4TiXtBApzTMsg0A7zOBILE3jqQUDSDw3wcsfSJGr3+soPqdQeBZlAtep21BMtAYuodt5ySBMRx1NRatVcVx3IWfoFKbQ4uEvvA5i9UwXFMFIkc8wrVfa1Fv4w8Qr9wCVyt04Ze7Nvi16fNprQSIPqAAmr8NQffyW3p57he8EMmn6Lw8mrB3OU9qe4zrFrZRSudj+OjbQUGKo6HhSyVPfVfNo/b6srjPZnpsL49+Q93QckSAhA/lYOqXNSiTBDDKopVe64vx4oAZaKVyH0+8C4E3d/rxe84d6tBJgJrFO7gjRQ6cH/7HEgO+JD1iOu6V16OqFcEUtNGSzvwLAom3E9iz6Aomj9EFCyUhmhc7nx7NkGdN+W7ernQTjgR94vdWrRw7YjeWSqTT+IEJEJ3/Ab9rTKbVI25Tp/gDmlowh5UlrqDuiW0oue0Tfn18DT0EZcF+1UTMLQ6CTe/E6cCYJvqBN+DJni14Ztomev2H4H1oEk44YQBaL8XpsvMWGmX8Ak7pT4WmKmkOaJ5HgQYz2NMnh5R69lBUuCA4PjPge99t8WLDIMRv/YahIff54qF95LTGHh0qG0F4WiLcbNMCuclnqX3JXNoif5DT1ZtQR6eIKgv/4YSRHqga8I7P2D2Gb8Ha8DkxihI2KOGIBdO5bCaiYZsTFhcvYEfZkez75CLPCnFiozplWGG/kn/ryWG202O8+cAUhXc/h1UJq3nKj1006JMB2VG6oLNhEmhbIM93yaHzdZWs23ODpU8c5oG4ZzSY/wYrF5XiK7tJsHDI7WPvP6BmkWVYMbMOlEAVPrhfpxV/6nmtUCvkjlvO4V3NpC9iA2cy32O0nAbrtQzDU20B7Ks9DcuebKBrI8NBauYDutwzhUaOEwaFwse8cm8BLD2pCGxnA0mP7XCa/kz8NHU8/MoKAoNdfgzThUHlah2G2F2iZTP9UDzxFeppPoZlWTd46csClDcniHP1horvZmA5+Jm2b7ZE5bqjaLlajVRdPXhTXzx3nisEyVe6YPoumSqqRsH6fxXY0OGEO3veUsvDcXxI/TXVRvyHCnFzsOGiPTXdTeT58XoQXzATVTaLcfPiZoqVa2T54zP4WJ8q7DIcsuaOLTTfoYpeiGlBs50ABre3c+WF/TBpzhI4FlsA5/4hdlY00QpBFVJI38NiG0ThykILyFpVCiYSFexv+w3lu5ai9erdrLtkKu+dt5MM/mVgnqEUfG48jC+8z/OuqHIWrwoCeWNzSnu4l75tnQpHwnt5idpw1nzNcLraGRNmqVDmsUwIzdEGL59t7FLVBRFOFiyyZQ62Ry/AmtsKkGLfBF5nMmFw4UgKdRbkzrRCqNkqSl8v5MMdlUhO0TXBT3UasEEhh1ptTSA0PBI6DO1Rb2UPfBMZBqFOGSRiJYuGB2+jkKEt9CgUUuhtexCO30fLZ+mxo1QXDI7ZBwfxFFi9/gyqwxeQ9MDQeT1Ok4fZKDoUt52vfkjF0MVWVDz1MgQe3sjeH/bwjJNOuN1iBCx32Y1lwuNprfMeSD+dhUtuhuISP2vIKB/yV9h2Fh/lASFuDKnrl/EOQxGYdksBHux5i0mrGkEBilnjwRHMVfXEqWMH0Pif7FDH3yd1vzcsGvuVD1yeAurdyfC8SwN0N46g1vmzwXD4cE5fZALCuuVcJM/UuKQCXbXPQ51GFHacd8XxcyNYTNGL+UQ99vmLgIx7Ob34vgv3JrbQNuE6Ch+vj7GvB+jWhD8s9TsWF4neoz+ak2H2Gk/2N14HHYIeNJf1QeevIRclXwDP1vkUvfYKH1a8A01TVEGDBfFseg5kV+zk5yu6aNwJSZZqm84JyZJgPcIIvhFgRYcBxOidZdU2ebyz6wNbL1SifFMfNvmQTeWPQmH0zt+8PzEMFy9ShCoZxG1eQbTB8zAuPnqQLFvSSLPmFxrlXeVtfbLgEqOHZ8UUQDg5ide49qDc2mf4bvcv3L2lmyrWivAWxaU8veIjNNHQHDgowYoBA76YfYxpvhxV5tixYGo9W5dqQa5kPt3OXURmY2+RqgtB58FxPCXMjd0Cv8O+d3s5bOF+zPXXRIHKe5zrdRBnHK6j4pFqQBfm4YeBWfjpphNFXOmkWMsWdpo2G6Y4OrDQ6uvgFfAOc/+JQepEFdxRtZBvPiyEgMX2dD7wP6hw/Alan33x9SUr2jYMoTJCCqY0vuKA1no6+bKMpFMXs0ZmNTaJuFFA0EwS2/USj4gNeVHCALIMTuDogee4Qr2K1FK3wY9mZXxjGYJ/4xfRqDxBen4xhZst9aFr62VqXWMGuhb+oNmcT393TePix2LQPejMe08G4JgyHXIQAdi/7wK/LTeiI9vNwOeME58/4wrlOqdgoos7hK3opeE1HrigXhhWqrhCvLkBeRXd5Vel5tDXtB3+TszH4NXzMK7tGS2kBnBfNR76b47kjqGd+zFHDNvD5tFnmzPgtq4OD2EB7q+2h4PudegibgMD779yT0A6TFI+BxviP0CceS65siiKfDCAhVpzsNDUAIjEIfumMv/+UU6bK/NxtNJp/rJYjMP/+4KBauPQStAcZNumkvy2UbBKyZAbDPKpLFQBvg2GclKCLATZ7+FtThN5k0075En9JhQHCBDUgx0fzUmgJA+lm7+SbYUZzdGox/HuCpzyiElWO4a7DulDoP1JqGh6hhb7ozAh8BuLHh3D9Ydu0X/rCe67d7NiozQ0jJ4AQqZPeVa+KRx54AQ9Qb9AyPIHfZ5aBY02EQzr8uHHu6844a8R7P09l67824W6JpWga1RE6uvPQGx8A9yK6mMBiz7+FSvDK27qQ8IocTzXoosK5zNpvEg6tVZmks2mGpj5so/zhMdQyTxPSPaXAy27HlQyycbtvV5oP+Y3hUfKsrrwCtqT9IsOPo1hM6FY7h8zEmpOLoTTRZfh/NNPuHlfGLfPE+Mix16Q2/EGjwr9Ace2h6R3Shmyens410GC66dV8Jakc+w56idXrzai2ldx5HjenQP6X3JA22RQt4mlL3WzoF1fiU8E7+WGOwKoZbUEr/95wuuHjQOFShVoiheF5FsbSYSmk+/OryQ17SOv7PgOS1sF4ajrIRbytoIFdeL0Ono02LZloKxANM4tXkvhEb7sLHGD9tw6DJus5vHzN5X06+5MGputA2FanbzeLoO2aOyjut0Ah9eU0GKdwxDjqsKZL6ezh4AA3J9qDtfn/UHtqBsUKePP0YlTofxoIE497kPCuh+prrEZ1ifrcNXIUTBc3AAWlMmiguYAlhfsQo2ienAmNzaZLMnpzv64Ew/zi2UaMM7qAH+6MYAhORLYohkLTi9mUWbmabbNn0quk1fhyH6AySYKcCgxlgp/TwModiSj5z3QpPmFFIIWgZfidMLbzTjMyhh3hQnCThFveNC+im/s6OERrzQwv94ZuqPrWfj9Z/Zb/Rpi1pfxi1sjQGnPTnBR2ArZ8/vxxkJF6Je6wLf/vYYF05Vw5DobLGsXpqd3tEFEdDqn3jHmtqH/z3X4UC+bycP48as4O2AQWot3Q/zF3XzYYQwEPRkGpYsE+Ed4N3VtcAbvcTnY9H4zBRmdBtOvCXxioTW+FdWCi7/M4HONNOguyAev/g38ZsI6vBobzJem/6LPJzJ40gJret2D0DYyD5ZmaHHqzTbScs6A+ya2+E/ZDcdP38bbXkbA/l4rCnoiAxPzX8DGulEkk+PDKm2fQPlbD2VZEy7TmcbBYZb/R9x5t4X4/+//OTRESXtLe6dSIUoIRYNIElmhYaVhh0RvUjRJRpJCRkSRVCINKTSEEgkto5CU/Pr87sT3Blx/vc7XeT4ex3Udx0VG8T5wWFgNmlXO0oKRtrDcTYxne78CGiEFczaJcNOe92R+/h/Pyn1FEVJC0PvWCf/GxrHDgWF04o8ZaeVOxrvnu9hZyoZ1dqjDCIF8fLV/HFSsUOftLQ95tGE+mEfqEQUposDtJjzG4/jXkRGg/qYWx/oPh1w4zLa/3tMsuxOkgEcwa0kwB/Qk8L/JI2lH/2cufrqI9SOlIUh0AINHz6ElkdZcUO/L6xYuYd09IazUdpZ8v+dw3RNlPJKqDtHKHSBvOoU6ek5wf1QBOuxcBf2UDxELvOGNnzutqqzHp+kCsGX3ZGqasIeOVd3niiNbSGHdQappWUe37B+Tq9gutgm25dVHTSD5lSbCXE3c7LgGQu5uwvnPnXhZjgddClPmD7eWgYOJIrQIaMP1ogT8E6mHnx5GofKEDEzMv4enH6zF3VM20JPLDWRfOeSGLdIQ6NIP8wRCyGteHAUcnsjuEhp4sM6ImpJGwa+KabB9hjC0mUqB7Z7p3Kb/noOEP/Gnw4m4cdpyYl9Rav1Tgmfd1VFNuQztVymC+eXd2FHRQ7Oz/zD+u8x25ZZkefwzDDxU4rJPT9BxRBtsdyCwfXGHXC9OxvKKnfSkvAy2bzPjZTeP8CGlZBx7YT77P9LiLJKFAFNfOBN3kx7NacQr9or8SkGWIqdPwokpH/m+J/Eey3O4dsjnHiTHwU7J1fA1+Bj0OSZxWoMyb/FUwQqTFoobuQ32PouFEEkE5TWN2HkgmwY//0BZq7+8PUKG4r7GQqa/HOcvaSN3IWFuuW4JPra1rK8pR3I6zdx/1RYur+6kU2aVUGNqAlT3H1xVusb7z0hDlH0GNm2JhTzxYl4TbwBmf6axqJErTV9QAzaJerxMbCyopepD6xVf+KsigNOnl7Pdqm1cGP0Z9P51oererzxidzz2JjpBTbwNjJ+fy2JjBqD5ajduPNjM3rN3kZmwMmv9UkSPxOn4tHQf3VI3hfUxE0H45HjW/aPMn97dh4yq9Wz/7gnnjqnA+Q8KIU30NviVqsORp/fZ7ogmbB3hT8+OZ3GIeAN83upKITZC7BZ0GAvm9ILLWF0YFl+EMmck8JH9a8hJWkCWZQq0vf089Lsl0SzRLA57roVpoaaw1fYD3AtsYcED/0gzygV3XcnjF5XbQbg+jzbYt7O0rw/vWCgIv/2cYXDMZ7xrfhvnq0/FE8J3sLgonxbIXGCdC4BRR/vJ3M0cfrZoUne2Eka5TcfjEXKoVakMux+t4+z+Ueh16yZtDRcG00h9eC9Qjn9FpCnonxs+OL0OpdTi0epIOhY5zgQHp1V07+YtHP5SFrIvWkDfmVGYnRYC6amV3FuyDK1VyyFNVZ1CX6yh02s8yFFjLIzDp+jseJaFxe9CRPUiMpyxH5v/6fDu02YYFPwL9/S64IQKYYj5LwFmrZtLLUVmqDuLwHluBrwt1mSJf7NIpTYIf3xcjx7NI2DLxf0UHPAEYoZ4pt/lOLTFukNVYiOUhnzG+NpavOSXDMfnWoHp5o/olp1JkiUlnNJ/HrK91oJKw1O2eTCDL4n10QhBc0z9Mx7yS7rg3+OpaDsnA2T2IwpNVR3i9aG73nKRv44Kp+ZrvRgTLwRXAttZdFwZ+yXFc8lcIAmzN1R6VYoUMzXpyUlDdFcrZ41WVchYWYvZN6sg500drCuuobbfh1lgtB153U7hkte+uFKhj51kLEEVN8O2GwEgmPccs5LK8O6wBfzq4VzOF3rMA5ofMDd8OjrfVYRB/QX0pFofRzwwoRnPp5Nc4wvqWmcMM7TGE0f/wStxZ6nMbSQIFspgfZUZj4g04QHlMIjwu0VNxTMoKWoRRHAwVicvw/wwC1g+sAhX2irBf7t/svPMQbx1cCGcfzoaZp7eQ/ad2nRz5Ezsz5CDRTCR061th/pWCoS3+/JP9zTe6LsEvwxbA1+hgW3c1vCwewoQk5kOZk2LSfdKKfKdYqj6JUE28dsoprOVBzXtaIptGBrGycEYlILGuYPodfsv6D/azMc+juDbH/Rpwn0Jeuf2AFOPHyf3NCO4fPUd/XByh+XdWwgVlGjE5QooNFvBe7V7+fniNfjPaxfWfxIAk7hHFHtOhr4v2cofVTRATqGVIuXOUPYkU154LpqUbOaDYe+koWfDuGp3PlffK8SvoXH49KIezCoaDva2d0h+zzymn/JkdNsKRvwMQDHvfFpfcxyuGVXxnNw+/nuyET2er8Vg02r64HKBtkoMg1vhS2BRmw2s/BeJ7ZwG2w8Z0M0rVbTtySraN+c+ih6NYpEOMdCFefzkRi8XrJfj65tDuO6qC9eV2pJM1Vg2Xb+CZ8vZkO9VJdjm5Il1pkWs2n6ShF2vQ4DAfph8XwmiHjfxyye5LFTM8HCfGqyQtcGOY4CVT+2oPFICA4PyWLLrCPn03ubrq8sgvSAXq3qGPGpVPnWtDmSS3ITnpF7BegkvDgspI4U+hLHb8uBXVghf/KIDz1YF4k7LFAi32cYX3pVTwYTXFP1DGI1F83Hb8/kkJ7sbi4JGwZwfX2hMcD0smHYZVR9vprQfXay9OQ+PBdRSqH00924+RTdTzeHtJzmOn/+PI+vncoz5esyPFifJd0Lg/6SNyfg63R2jQEnvtcHA/gzolKdgbaQExVivY9OTjvBiUSRrj3jA5hfmAVY/Z8skcTjUqAcV2mWs9moFuz9phqZtabDq7kk6eSiO3yU1w+goQT6wRh3+vZhCBxdKg1e/M14qisAPfy+AdfFvfpAiSq4uHfxoyT/U1x0FDr8vQMxXKRws/E1CR27BvkvTUGTrdnjxXpVWH7ViJZ+ZtMRDHErsLTggMwhO5TVB3h53Hii9yO19lyFrlDQKhsSi8LxhUEd68CSzFO2v7IE7dTlYYbuU1A/3woflbVDlY0WJfbdROZhp1j1lcFr+CmacW8nPl5lh884JELjLGffMVIRDKjK0PrSGkkcZ4P1XDK4lD2E0q9OOgkHoNLcmldY3NDdPCi9+G8aSOrbc0niON/01geVqMnghdCrMVjiIZhdOUFqYKf5MFKf7tWe5TqQQ2tOf4BtpMTBO3sJL3xnD0jE3uPdMBmTVT4buBmfsnHiIXUNG0EjfCCyaKww6PUVUMdwA89KN2TlsiIuULMHlvAL99+Aqu9S74tMsSXh6XRqmTpyAptp69OH8cuifOZ1nKjhhnGIsu7kHweG+KfyhWBL6Vk2BYBdL4uULyPTIMtqy9CRMrJZDvRX97LfNm13CjMl92X3eUzIObra8pNvLD2GCugx395pB6tfr6LlnGy3puQjh4XtpV/ZJMp4lB8NS22DsCW96UHAX22EivtVZAYctboPD+jmcfViPcmy/Qn6MKkSdqMd0aSbfyLVgZFwD02E9acvM4UbBSo5Ozebg7FIYrSQDz17V4dQLM2DY7e3s7d4DL/NaybtmLF+Ycw+XjwqC7iPjef11FZge1EzYGciegaI0ftg6rv4XB38i2rHxziBdszDGptzdOENMHVZnK7JHjBUNnLqH67yvk/+ry+iYdhTzZn4ARal5tGnFAfDfjtChfRA2lj3j1+FqcNTvNhsEf4Jpnav4YXYYlSm5cHfHJPayEwe7F7Y4P2QuRWbOp/BvOjRwzR6nePbSrc8XqH12GDZ5vKfQNBPYHZ0H6uJPeWDWdXD9c5NTDNzouLwE5xQuZI3cx3BfNgF3VEqCiX0lGdldxPLRbmSw9B/cl18AsbfSWcNXEUYMrGdV0Zf00V4O4vdOoIsdipR4KglHbRKj6sN9XGf3kV6GPIX9/l/BXvgdbLhDsEyuF42GRORN/TL4aNSH968MMOfN5nk7PaF72lhUG9wPtRpmcGCHEn+vfsAKwyRZ2ViYzBZLw7XU/Tjzmj190PyL265M52GPJOHvtUM0cfVtNtVcDv+elJPbsGC004ggM41m/NVsjf/tk8OKF8owSfU2jdnWhm1NH0Azox/X/1pLfVbycEn2HjgKMoq3EZ7/MtSVvh14AJyhysoc23/d4zPzVsKoz0tZdxtSr1M1l37bA44NStBscxQrRvVi4acO+jj9O3kLCtE5l414xDaCR4g8R1UnbTbP1gGj9RJ45eAu2H+oAO4XXCdnr++kWjEAjXnBKM47yXdrP4zRtwQvP2nWzjwJv9Va+eDNKl5quI9zFBZQps4UkD8hDFWLmGPjVCDSuQuLVDLJcoslXjrvT03lN7mzIBTg/j7Sv7GNVf9GwuO3OnBisArMyzfyxOGxnHDoHLRfUMCTG6SxuagHTmxejKc0QyhSSBUEPN9i28EbbJmaSGbnF+E63SI60CcC6422Yb+SAsxTmQ8zZYRAwlET1R2cWTk7mzNqv7JWmAV2PcpGF7VlJGAxAjYkHKLGcQTv5/5Gi3uf4Uz9AbQ5rkgu/abwKlubnnzbwSX7gFE1E61HaMEXTWcsODwOXFIjcPK0GlgY5EsSczqxtiyIZy72IDNHbSjZIg1ZFxdhtt8xNHo0nlfFStKuK7vRskeLkmd/QY2rIzEnNYxn/xSHaQ4ptOvBMTYWDISGrUu5JustPf9QT5u/+ZDJn2v04qQErpqpBOPU3HGt00jy1A+HzYdPkeHo/yBWYylJXZ9GStrBVP0rjle5i0B6sjlrbd9MLpE/OcZ1B6wKOkQZZk5w1XIahYouY/E9g3hTygaMPb5w//yNOM3TGwu+Lmfp/koQD7kB9+ZdxfNfL+GHo/tgYJ4MqHxazVEqN2CSUxIm1dTg9ylD2ZolyQPiQ/egug/2rZmN4WuVQevbCrRoMOKcphr6ee06OP5SpJMZO7DaMwJOF1WASY4UJxyQh8UbBfGDkij2puTQ7Q9jaL3iVT4U0QuyBy6BnI0KibUspBfjDWBD6yCtkRJA4xeudMBEHj2j0zk8IJJdNiqzsf8Rvq87xAtH9SFl5kRq2UZYIJMMiQln+P2ZLho/spjCJr6A0pk1KNaym9FPA8qUt5FC1H74ffEuBpX9B76R7Sx28jY/68minO6d/PdzB1TsUoc5uubklqABvuOGtl43mu/tXYlXMqbBsAkiUPO2CzMOO+CHiilw9msWNKnr4Pr4AbY77kKrGv9Dm3WPMas4BtOzj3NOBrHNJ2nwfTOXZl8/hvz1D4uvaWWjc+2wqX/Y0PmtIJHas/Ch6TL1WjPEBcjiPAmGQUkNTHm2moyuCuGDNQvAeNdsXHGpkfH0FtazGAZGI7LRv/MZjUoMpYJOVbra0MJj5BJow1VD2LfQgGhhCbl6T4ZePUHQ2hcKw5/9x7l/Y/FtvCVZO7/AXX+H85TOAY5rPsauPw0gpXGQNtrmkHBfM398NwBxbqI8QWMqPO5xhaCmJUxzNmBUij5Yjs7BwIJKmHRBG7r63sOqveMRdw+jpscFMFH8Easfl6a8vepQeswaTK5uA9/JS/n4HhPU92mjE/liYOK38v9/gxqhNosPXxeHh4s/Qs7beXB7yVPU1O3HW9qHwc25lQajD+KaSyZkqxqBxXMYNr68gOz7i602Daf2tQPQM/gCVh5Jp+JzO8FLwBIq7izFgrLR0HLdheN9r2Hhmgj01bbDDzNXUpzpFNiRdZ49jpljoaYR9/YbwXgahhf7pmL8uxrWLLehl4eccZG8D+cbjoKJ2iugS+wsKN0ZAyPyDMjJ2gVjQvu4YaIi9/c+QhOPL7QuRQlzDSbz1+iPuMBfEsReiPCNxb2o6ufAFC2Dj1zM+MyEeLh3PYwS3y/FDoUyvrNbDPIOnqZ1bSpQc74I3N4+4zxPGShuXIyd22u4vcuVDm7/wCK6ovBq4To61ONF9wxVefPU1aj51x16p5hgugWT1ScX3p31ij8fGwnC3jOx+VcP73moSxPzSiHjyAI2y8wkG4VIXnXoPTir7wT71wieSpq8eoQUnXUdhgFe8QiSn6Dn+w7u0mRYKaqE4sNU6dl/gtBqro4rH86BDUcZHbuug7zjLa6MWETyM6wh5+x8+l3+lDO7DGB1/zgcSP8ARkfc+cGdeLqXZgs96a3krmnLETOOcVSOHq1rtYDKz4q4rPAf/z4hB47quihPDiQz9S/V+/7kwthnoLumGkxHi8H+qWVY478VLzX/Q0OR36SvtpHfvl8DPd360JHvjO9KEX3jbOBnqD89uz0BYWQ2Prz3hKboyMD7s/K85KwvaFyyBfe/n+jJRBuYXWvLBn0O/O3vTbg59RqZNkazd/Eoev7Wl/Otw/mjaBlmr1GGxUWf4dSGl2S+VB/nPxoN387NhoKEw6h5RhFPZNxHMZvbKPBUBvTONvD4K8VYrpLJmg1WdD4lEkN7P0BD6UQ83HsSTylfgEn7rGH/ms380mcCWymZweM1ibwmNJMnhObwPstjENDyk5OOr+e5dwXh7YOjIHRdEwVfxfLCywpYsbuKg9420YoVjSRaZ8B3hJ/jDRsxWOn+Bi7tOMICs/xJMWY7mR5VRfuN73l8yTkomO3KNi4mdNwA4MqBrfT6qCdnWmejU6kOlF1oglPSr3FVhyWk3z9Hx97v5GRXVdhwQg1+nHBnNSst0A97RoFTi+Fe9wAHneilTVrDQelbB9dukAL5Z+NAap0cDlM6wUKtt0EtJZanCfez2pYsDBRBjI0ZS7U/dMFffBZLOwF+v30GmkKl8fDR+VyjF8GGlf9IUECAE0+J8bU1JuAnUQ53a2+xyOSLKNSyip52uYDrYhl6NeMA8h45EKkcjhkSZnDGfhqHD/nJ11MV+Li1HiofNuPzsA2YJNTPL+Z18d25ciScYwEO960hoESdf3hHc9ivfBzuXIQX9aexaUwvWhgfIcuI0VyjoQzmRmX8bn0Vub2tIBm/MOB/MSzk7kihgUsob4sJVHvm4hbrybCnSYirO2vJZ9Vm+Ps7APoGvpAu7aTj7cvhzaF5BKairOQsA49XPuKCp6oYH1UHRX8/o2zDXxxuVok5zcakPCCFSbsecruYAPj/dx2XlZ9Frxnb4eD3DVRgeoBYyJc6jXLx/KNpuDjCDu2GG8PXFzJsq6HGCnmPeHqZIz7/rYFpE2qous8FLe68xZnN6iiSYAyfQpvoR/AIXLfClVsXbIe65eno7Z+Lf/Wv8zbhchAVMKPTO8fCjas96LpDjdcFnMBnHvU48+Ny3hVQTcWb8nmpcyIbPpOD7rET4X3obmgxEqT2wUksqGIDw0tn8/Nv+zk41BmkgyXZIzmZr1wQhPX3kmHz1TF86Hgin45ciOe+HYHBi3vBv/0gDtepgnjZ8Xxylw2YnBngMbIFAKtdSeDZCvrSu5WoxQjnjjmJN6ddQMMT8fzsmxEo3Kqhm75x5Ot/CzYu3wFyl4ccYKs6JNvdoFc9k3gPOaIpTYIfzkm0bJYlz08L5q9jn/LMCFV2fj+F/Lv/8bdveyHefgydw2EwctJa8BjIo5Pqx6lY4AzapvyEr7lqsNbOk+snreYdkucw7JgpGNR+5Lrruhzi0oFxHS/Y9u4oPOh/m97I30GXqR4c+nQkmAUgbGx25pexx7n2YDG9bFiNG+4/5823+qH4v2PkOrcFCmy+QpyUDPzzHM1TW13pXKYav5wrBOsX9dDE798hq/kj/o7qoLE2ljhQagMl37+Av/020tEWwoC93ThfcwyVx/mz8TdrrtlmAx3H7/IrXwHwzFTBzFJd+GruR25Xu+ntPEv++KeDVM/epSYhH4Bfb4Zc3QAKx8byj/5sOnD5GHVWx6DVSj1IzleFg3Cf5ZOWgrFkCEu+0IbaK1MxR0KKhbNVuC5kB554O5MTVj+GDd+u4PwlqZC9KYTniU8Gj732oBFewTd8LTFxtik9lz9IsYHHKKFDD6zv21P9glFsv0cTEqK+4C6puyQ0bQF8mf+IZhffgN3zjtHaVypwMN6JDW9PgcnKk2CfyDVQjbbkBbu+ovp2G+pb2MbfCk/Bntn10KV4gJ93dlPnlsmw6tQoXLdMgRuS5MA17h0F9ijx+fXdvGjeVKhdqck3HbKha/l4uDj6Ev9+lIzprw0oYO0ySmt3gfGmQri9sQGaU2bykfrTvP0Mw9pJObTp/DHM1fxBlnXfQUt5FRe2KZPYEjH+JBkOTophmLtCDFZFiMHssZWssHcbzHqgiRuOhOB2j9GstMITtHpFKdy1jALfS8GUNSNxyfMouvfKBqfuPwtBEWP4T54Je7eVcZvfMJwe6cOmnkrQ3lvNYwyKcFToTBabAqwwMp0GgqPZS2Mlnpjxgv/ueITSKVaww30yXJ8mQY2i7rQ+rYnvy8dw6bJyWPi9m89fXIoTHrXAXlsh0LF4Dd9vaUFy1U7mVFHcd+YVOt3X4AmRQWTdXYP8Iw5fVghCcYQVnziiAxICU7j5YSpXRGznjCmKLPZ7AS5UX0m3rg+HXqnJcDhxNIv/kOdH/wxpn3QRyggZ8Lz6xfDSfgS39vtB0KQe+iWmA3XNIjB69lpS+Dd0ZlMcsE/8LtYe8KWH6zSxsS6cM4V0aeUVAwjKEQaPYAfKuqEKJyIng1GuCw3s/4qRBqYkPCUK8iLP0E+j8dBkYQ86NxdQrnMC6NnV4GCpAAz3eYDnR70HHcdJJGWni9U+WnAl6yfUWb2Dxg+3ocz3Oyzd+Z4nmvjhgak25NokRvOdA9j6gxloPbxKAv6ObOfUyT8lXEHiZBL+9SijsT8TMG9iEIiue0np8ZZw0lqOp2ythonbU7Htwgyw9OmCsY0LUM2nD1W2LmA9iWJcsnI0rCg5CHIv02mSlT2Ly52ml/mL0CFDgIX8nuPdB/oYVpqCA66SYOgmSPqbt7KeVwttshikEx3XeOeMVBqfLcaJqQF88Ko6DjMVh627y+BpaQde3nmJZkhsA3k9T9q/LAWFH7dxuMk1+Bz0nDd+M4RlVpXA5e8oeJYTvRa3pcqJjaD2oBvLX9jwGLFdaF+xjd8E6YL4nRJYbEP4p+ca6gmUwZdAZTapiuLXQRmoED8e/Ban8Z/JlvBibB7pz5tHbnr5YBS4nC68G+rwba/oQNB4aJd5DVGG2Vj/xAbeCiaj3OAhjjLMgiqpHWisKwmOP9vp/eNAOKdfxaueOfIv69EwwiQCPjzfjKbHswHspmNH5AFcM2oT7D2vimVHR8CF5VrUuWgUvNRbzA/3r6INf6bC2ncNeEQyh7TwKWtsMoPd4c64XsUFcqIFhtisG2O8uuHoDVmUllLGl+8CsCk0FT4NeOJb0/Mwb4YBnbhqBJvWq2LGLWVOhWgOqn6LMUUlgKJryeS1MOTMMmP1YbIk8k0EOlPF4dnmFWw4ey3/SrOjrQcy2VQ/EAdmTUM/dy9a3yTLu44KA0w25xiDmfB4uwboBq4G8c8XOc3XguMn5pHpei8sanSjo94TgS0FyFYwG+ocFkGh3nV8HfUHP38dzY0XqrC2LRDvT/OF1/sYbjZHg9afZDLWCINNGVr837OzcEtNhFfeXY2R0/7g4oOn2aHSCByiEZ9dkoRNOldp+hpXkp0RiwfkleCLfzxnSD+HZgczcPdXAbXdB8GyciWPGFNBXkv14FmFC5uc+42D5r94W0gR63kEs+VoC/gnbwDjhU9C/r0u3jkoS7lTvWmi0g5MOJHIitErIPDuWGyPM4BJqWbQKvUSw8iZFy2Pxe/DFDk9PISKt0ZStM9SdFBTopSSyVAW95Yerp7BbmLrINPdACP6boIKpNKJR2P4Voc+u94vhwbdceA6eYA+ZuuiY3QvJET4wYw/x1nufiXOCeimqCvHscL9JN3OM4XnEoQPLneSzZ0qbFsdxv3fqrDAOwiGn/mLwfgQ8/POoarFCDBwVqY011nQmzkc2q5nQYinKmrZKvLs8Ed0VkqXPCrr6FmDEKgtvgX75jynWy0v+fXIOjprcQncTM7zIr3RXOx7HFrrq2AwTQM+Rj4lj355LCmtxhzNreDdoAULbZ8wTpJiA49T8ObFBLraMxJ0/juFbVLiKCA7FmpmvSbfU45c9a0DkzYyvO2q4XQ9RxC3GDfELcvRJziO93oqo7K1AU5PGgTfOUvZbWcmKTZchlMGL3l0ySQYfziPH14UA5ffylDtPMiDhz5hsUI+fU43gW7Ra9T8VAObZw6HkK7prLQhGuaG7CDBL25U7TcTPE69ZvPOCzD7cgqlDHdFwzpTuHy1CF+LPKaKGG8+26wFdUv/wrkAa1ib0sFH1hjjjA+63LtGBz55xkCq+hlakpYPn9+v4pnTiuiWpQNcPtiC1/vceYvlNpz9cxx0H68E7ZBp2CXzCXe5y3BQ7Qw89PkCDndrxYQpP1lVSRNMXo6DR8abcZPTMTSUS4LV89XQuscUzj26j8WZlvxVZSzWb7BA7T0y0PnLH2esa8ALfZY4d7gVOrSfJsfLW2G3xATQaHejuVJuWK44Er7niNCWH7p4bOc42quTRK1Ph5ilsBMM10VyUuBHGuW3Df0mj4UJ09NRRWkvzmv/Ag3TAui2lAIuXR1DDg53OffybvY+EUZ3b2iAQWIFyt/KoNOO9+mLXRu9uHCSuvyM+YblLv4emM19e29g7SdZWDwzhZZrzaY3pVNY+o0c3Y6uhReKwSxyxgUmvZsAp6elwrGlhlAh6gb1wp+h/OY+zl68hY+MWsOGvwvBQsCc3dYuw0NpPvh57BS4T7L8/NhhPCnxEd0n1pK41gWe+O4aZ5afpl3ucdRVkMLujgiC1VvgkfgO3vVnH531fILNXT94QfcZsKQr8C4ymcI/JWPlHl1QaBNB65KFKEuadDJ7C7++Mg2M19iCzwUEfbFgXvDwHoy+IQDXlDrhuEoAyodLwPUdS7liaSlD6hPQPxmNS1Ie8tatc2F2qzb4FCtgZmosuQZmwrISwhDn8+S4VgHPtG7EvB3VdPeJLh/o0YJ83QEU8ltGrxc74sdpdtjlWYnmRbeo22cBWeVKsb3/PbQVloCq1vXoYVtCvttUub0/lvRMLeCihxyU/f6Le799o8wfR0ljlDTY5eohvflBPR+08WbXcuwrEuXNu1+RR4sANYpYkWV6Fr9vs4RNn+9z/84UML0YTGw7Dk61toKSbySs8f5L2aeyKGaNInY2KMFZy1Y68McT4o7Jo9FjAxRcUs2RkdNw3Cc7wJWZKH+sAu+JaEBFrA0qC3vyvcPp7NqgQO/NEiAz5Ryt79cni7xkvB6bTQt/CYKRvgTck34LTZ1vwVRSjifpnaHbRYSjTU1JMbeQ9lZvAFcBEWid9BYd5k/BG35NJHlLDsLNKjk+a6jH/wlym+FmiDgdjt6VIvDp5nj44+2EGUvlSX/0K6pqr2fBcW/JxOkeXU4yo7QTgew1yhK2dynQyJsp9LHVEY5dzCTfLcb8+WQYrPgeyy/757PRf0/od+9I+DilHAwDp9PUf40gqtQFcQ1ncMsuU0JjIdoleQnE/lvJL0+Og3FjDtDScydx5+uFeGdJGs676A/hrWtZNGA0LI85j49HqOFeBzGYGncRuhuG0YQjffRNrZLGPTblZ8NG0gmTQ8zxDXxpbBPHTRWCE4YH0X2fIj1zqeUPfTNgfGgJuakHsm1uKKdH3+KtY/aAx04ZmGP5mR0ftFNsuCeq3D2B0w7EguWGGZgUOkivEm5A9cV1eHynPihcPgNjfqZwadUishg/QOFzJpHRJllOUDyPkX/D0Hx7ICX/U4AdUyfwlOctHLJlDVy58ZVm+AnCkcEyOo8iuHtxGKihNN/8JwmmnVkQLHScgq07wemTEc+z+kmXbydRTOl1jm4XAJ+TYVQ4UxI8vt/gio7fELRwGJ+98YRnCKtBxJTH3G6Vx4JzAnhoZvhVpwXI7HqJVntPc8zla3Tjf+632JVvdzhyQb0Mhki60dOFtrR8jjlo1TzEPZn7QCdVAxzrBqBeRwbZdhmmyL/CdK/LuEwujPZv1YelDz3ByTaaDv5ny2+/rYWWDdM5ZrM5LtE7B1KLhfDndB9o2DsBFLKuUZiqDWmKikDQ7kpMsk5Ao6eBuC55HikOcUba5Ct0+IsyrDbsgfKsZlCeeBcHxjiy/UAvr/oVRCO0euiJvSv8EFuGTlm6sEAM+fFKF8z5pYV/RAbQbZ4hJzomwI2tprBUXR2Nz3Wyj4wELKhaSZMebkSDmgwerjSX1aaLgdnFSbBzQR+n/puHJy+L86IpBAWtl/hFsC1eHAzksNeWdOyyDK6e+BMSHIGrFhyGC6b2MNXeAPbt7sbHa5dQQMlonGc7kgczIlny6SX0rRkPTg4L0df0Gp7ergWd4wM4ec12Nk0w5XyBXLy09wvYzp1P0w99oLuf5fhWchtPDRcDscEobl0zkZ/v14EQ7W+oMKafD/wazqrNJRiuPJx3nL2H/j91YVSxCMadjMPz7mN5kn4t1Ewej7KeXWg3oYZO942Ed1W1fEpAApykd+F361WUuiAaQ5684lGWVhCXk0u8aS933tXFdXUS+DhFA9zfX6UFKwRpy+5pqDlCivJsV4P7pfe8cmcWr520EWacXUhvH8rDctssdrzhh5dKskhDuZj0k0rwwR4/sFqsi89LDqB4SSG/m2oOJkdSsOOFHOtr2pBOlxep3oilpfk2rFWzmOo/ClL4hL3kM1Mc0hbNpCuGj/nQrHIk3Wgo9ayhgIzZaHf0GZ2c3Q14axuen6MNTU4HOKBwAjtlj0HaspfOj3oH9cPfoM7tWahQgXhnSx+L7jOA7IeNULhrEtgsz4HNeZM4R7aGfmxvwZU7LvO5vx8Z3/XgeBwJT/82cGHGZzY50ET7zi/gnpSF9CS3Bny8sjlz7WY87T8d/zYJwI4FoTgx5ylbdQTAnsYnLHQ2FZz9Z9C+MFcoEUyCA/0zsSfbHA49VYDtF6XB9PghCLsoi2GrnuHr9blc0/abvVxPgfHRVB7x2xrOf/KHCWdnUP1ICU7XDMfyXbdh8quv0N12hj4krSXF1Hm8tk4cmvzD+NuwvXxu1nfKyhgJgn+kMPD4T4g+ZAGOaRIkeCSBj6w0ghwHdWpyKMGYi08wv1ENba4kY2FKClnJzuXQryNZ4MsmSBnig4EH02Hq/96TTn+NccpOrBDqQfWaAUP98Yrv/clko7L/wF1JDM7cHQ834o+Sz+M9lJGsQvFrEqFYMRS9B75S/PpCii6wwfvaFgCpv+BqaB7fdy/FLr3TYBg/huZVb6Xy1NcgF+EFn65OpuoEHehYlYuH39nTg+BQnjv6KM+uD6FDilJDPj6LskM9ybwwnjrOKYFpeyC5OZ7iw42NMOZUF/nWP4aeCZrseukNZwjJYYuVGHR1KEKpRQcctPxM0+2MWXYmsP/H9VS57CNHJPSTvlw33Xy1ki7VWMGfojAat2MMDtwfT0c3SvHX+yoYq7CbouboYGL4bzgraAGLNlqDQ2YFu1ZH8HG9EG4LNAevsxGoIGiPycukUTNiBledTMX1fyzBQHMmlE+bS9oZe8H5jSRZa+2B1vOLcMIIFZ7jNB2jdgtx3z0puKtsxyVGufxL0RRODN8KdHI1rP1eAI1DuzgtWBoC+x/in2RNqLFLQ3XZTBxn3E2V/S1DvNcN+5VX0zyPOLRo6kTt5bb0t0gCNjR/IC9FF3CaUs5VN/7g8hpJaD0kCq0nm/FxlSXdbt1EQrpjwe1XDDjLLEV5yXgqlU2ig1Gq3AgreHjkQtD5fB3SF4uhWbgu3O/YxSukvSndIQ4qTh+Fczycq4XDSTh4Gu5uPE2NXAwCa01gT/IxfnvYk6onyWGAkDZOEf/AlLsJprUX8HL9YgjddBrnm5mC6WJ/fv90BF/bIEyvLmby88r/4MVMEUgUEuIZE37BDsk3XBBMsNi6mLS0IvHG1hbszHDFmyJPuGO2KedO92cv6TrePMyIjs+dAnX5DRBjdxQShjxio7U4bxhi0Gtzj2Nf2yU8aroIDPfHg0mGKGzQTeGKlaM4VkWGdy8KJyMVF1aT/IX1So08Z/RW2l19kqfNk4GWs4loY2FGGiO34szwbbTzQSKJLz2BH6xjoc+oCHvd70Oq8ygoW7SfZ2YwSM8LpUXT67E//hud6Ldjf7ub+GB+Bhz6so3S/g4DdSMP7Hgih2L5zajuZIHleVVY/CSZOv00KDEmng5KbGCvZ6JQXF9PUtQHV5eW0sFuO5Z7mUDCktLYOXE0JfiZ4/EjjMOMEXoTd1DZ/NMYsuAt0rcYOP9lG7v7L+aZCc04IyeZRZW/gJiBJhSWC/F/lhqwNnYUdQWtYYNLUfy25A3uOtaOF7rHktuYNvhgpAE7LWvg7NQTsGppNVz+l0zBnq6oYj2FP+WvB3RWg9b2FFxxxgQODfV16sAdvHfvCCS+2MXVJzaTtX8VrB/jDdE9c9DbSgI3W6rDxKsnSUnLC9Z4zoLGuhQcq/QRqkO/0QGNIcdBJx4ssoLOd5IQfaofZNuVqWxjDuwao8Yfgz35iMRDalKwhrpFK8Eqcw5unUhQv7AH/z62w1FvBTn1TR19zhPk07LtlCuyma79UqENDb3w38AImChyjO5W/aaUxGk0epIkDT4P4vD683Bmz2v8ceooiqz5waKCyvAtUw7nOm+H/JYV4GZ1Gs/Gr0EnByXK2lYBqocbyeygD/spa8Nm9Wk0fdEHepF/jg22JIC481+0k7Wiqm2G8LkzFrWdPrJOtwlEj59LYw5/oj/uu2jDg9e0JWMtr9v+EiKMd6GFkRIGuJSBk6EaLLwdQdOkdVhEZTJb54hik1Qbz/k1k24mvacrMQWUuVSONvwZCcp2Fbz07TlK2WEIrXusaZJjDTQl3aXEtiuYP82UPGZ7wAdNCZB1zqCc3nBySVeF7MsrKN76LT6388JylzyqmSJCrf4T8dw+Scha2QY7X8dRbaUby5f4ocaLP2gg/h/VdktB4YsMVBM25Vg9K+j4sZGis19SsX0mKB49RpcSg9lttCMIKF/i2iZvqth9mVs9lSAt+xyZHfHmW/U9ELt6PS44sJS+fnZiRalu7D3rA9K5OXy3cRgY1P8H/Ufn8R2vVfjg52i89u4ObfuhPOQlBuztN4m2b74CA67DQa3QiucpnsWSkYEwkLyZ3qavxlk1dtRbWEI/No/mru7hLPTAHHI4D++dPkjD3tzgSyJT+IvTWJIuj+RzHkqYvaCMl/mMxszlBOPmmELmVDu8fHs3tpcb4j2pDfg59jbfODcF7l0TIG+FLRg7zgSqlvvzbIf50HX4GxyoN6dq80P4FFZj4ZMlTGbT4H3iAhjdZwPXnQ2o9kYXzzK5SV+eP6LakEm8e/ox3m89Ax82zacXWkkgqmIANh/TUOhbLdwdl8Jbr5fiyv4DeOb4TIosreKfp6th8lZX/jzeGB5P0of8nMP8UlwX02oiadVKhMg3NlhSGEx17mvg21FRSje1hDfVzmBZN8BJRd/R0mM0jCJdWma3Chs83kLWlGBca3gWBJbbgNuS8ai3WAxMBU5R1qQJuNskijSHNjxt509eelELXD5chMhyJZj1wZj9JUPgWfRu8PixB14OMiwfq0d3x3mAzBaFoR05yUfjGT7PnkxnlD/h0ywxlh83A7EnCCU2Md5+J48H9GTx1uFw3JanDWPvBsKM+fm8sawZBlV8cNW6Gbw9upxb03pYabYDzS1p5rQNsvAtNZK9FxmAsaI+O4Qlw5dLubBg12J8Z3CEPtXPxLVHE3Gfnw7EDvrD1WNFFB7gCJPyV/LlGgvaMWYi61/8wrYOgRTz8CPcWW0AR1b5cM1pHQiMEkJHCIJr9BITC0XpjsJTfvvAHAfnFOPkbgk4rzAdDp8K5s9PW/BRgyQFJrjznalXcLdOEye+l4Hg/YXgoa4JKvuWk/IbCWqr+MUTuuywe8lkkqy8zpt2iOBVOTMaFhIOIjtVwXuRPkn9KmPFjqvQ0RJAvWLK/Kl+PLUKjIK2/3Sw/ocRv5EQgbIRKnjRyQ4ztBkKtX6jQ/dC9ni7iQ068kluIJIthjlTQspkiNrxDzd0LSRhmcMklz+DRurvQJHV2Zy1Yyo+nHWOow+u58hgMfj63y32Eb+Kac1n6OPDqaTlY4FfPvTAbgULWKfWg+8yRXA2W4LhvVMY2neUe6YV4FgRdTz+zQ9HaKewXqsKSkZ9YeWCLjAqVoG8FSl8cJIpK92z4OS6ybgwcDE4KZ5lwRXytOz1MTqd7Mwnzw6HN9d20+5mWZLfcwLHhslSdLQ+FjqkcFa8FR5d54V/ha1JScQa3htZwq8t/0hvOJKYfgKtN07g3bYe/MD2O8zv2YfeLoCOe1VAuO8hG7p4QXRuJRUfjoD0q+UYWb0NX2xaBGVjVdk725uPrVWDu+PV0MBsAPWz9+GVQTs8Zm4K/b1aYDR5LSz6EIp2cskcryQMGqKJ8OzebXZfqsii3fvxaeoA7I+Wx7vbCevjlmPqKSb3PzqgSC2gvucGxD3PQLkTuuy4fQKl68dw959A7OoRh99KDryxUQH2Gn8G/fvjKKL4OoQvmYnh3/PBYI4enE015ajtvqC2Q4xrHUxhgv1l/jTxDUZ3PeeBTwqUcS+ZwyNiuV7bEcfED2LAcXk60ikE82/Ig9d7d5oYPY8F+y1g3sXp7BwUgJ1BTmh20hoHl0XhKmUjCK8NRx9TDRz43szP5cQw/XIj1K28zM3esrg88xuFZqzhXW9GQZSVMEWjK95OlsCqBc4wXnsuaqVNob1LLsIOr0oM+K3Evf1joKHZmZ4F26D3s090QNIHygcaoWj4HL6hdZ2qu5eg6NDG/BYfA1aTh+DlxWl+3JPCY54nkWrdLLb3UYDzSjfYVryVC1uS0MhTGuZ/F8btInvAJmM1rvTxws60fgg4UEa/zZaAeV01lQ6uB+siIcD3pVQ/6hb3hF2ARdH3cG3wM65UPAL3LqWhWcN5Khj3FZbpCcOHh9K80VeRGupE4ZawOy7vrqLvw77zdM8e6itNwMnWDbDCUBdaywSJ8yMxLKqDqouayVEuD4VTrgPm1+C+H7rQ8l86Ln8/GWJ98/+3zzgx0BWNjd7jwr1v6M7C75R08xoHhi9ngwVnoWXWeAjc/wRWiMwn91uv+dSdhZwTshTS0m7A4ONFLLdVFov+aCJe0YXc7g76aj4TCmxr+XqdCwqsLOaiQkfsgOv43DECil6MpZG91hBTtoFiTi1ix11OeGfDWF6eIMwPBBzQvakFfz07B6KFo6DJ1gQc1nbD38YEmC5lCR0iqjj2jDRY2Hghi1Tyg1s1NKcyjnX3D+Vg51leNUyEZb20eM+qIJoWcxL7isTA/ogjCt18j/afClFCcfRQjvq4skwepkQGQunqcZiTIQZjlNXoc+pQ9nIm05WJRzhkpSg06TygXcX/sf0VMVhv+JLb3t2AkVsfwtj3IpiUYgJz1CbiNymCj9rdnJw9mqZl7qP9GwA65C+g355qVKk6wL03J9B+7cdYu3QSKHyYgSbKWXTKQZ4sP9bwzmeN0HX0PUmYLaXg7bm4YPsUFOzUgX9RP9lyeRu5XC+D0c3d8O+HBq3re465wipUvvUWHdv0DaYWAmQe/sJPSoXhteNU6FTrBr+yEfSjvIt6d4+CvoJf4Pd3MZRslIGnacoke7+ezj4+hiO2ifAyBW1O69rIPk8XYJgYYEh7Bvm/sIRG74vgNEIUL7+2gCWyzRildRSaIg/ijsvSIBN2mTPeO1P8U22w7XElr54FzM9u4+KnF+izcDi2Ke0E88OboP7xJ3bv1CaNC5rwI7eAgrxk8HbiBAoJj+GY++3QUFAKQbNuks0nbXRqKmCrNgHwTx/BRzYvhfKSUgq+eAqK4/voa/9XGDyRj1YJ+uyW1Q27NGzghcoZdHxohpt1nvCuywcRi7+Qbv0iPP87EGdvOkKn1j3h+BWmsDJuOSzwCIMZKWHwT24WJ10aCyNWmcGR/v3wSs+Q5ngl4H4RBdjz6DjP2VJADerX8Xf9bepLMgKvf80wVUsX5mx3oda9+iThKAwHIx4jxj/Few5lNEbkG3yR2koTW4A6XlTgrANP8HDqNhShkXBnfS16+nyhP72jWeOUGky3l0NJ4Y8sLa+FKy470NZJbhD+ThrMn/4D4ysK9E/mAzYIxOLddg1406YN4CnAR7ILSAC3srUMw1mZCo4qukhfDxGoSgux84pQbEwrwXUp5vTi3TrW0lTgE6YTgI8sYaEwaRLfZwGTVc3Yuuo8gUMUHEyVZ+HhLWT26xCaLjCGc3e+kKZREQ2s2sS9wqE45VgYvHxoBZtKFkLOL0t2slqB2vFiEDwhC58c+IvphS/pgPcFSns6metFOyl4SQ9ucq8Ekv3LMDgC0kOvwew1A3zo7kReIjYaxt5aCaGTFqHPn1HwznMEqq4qhxInhtO552hNlgaEHq3GuQt/gvxLURj/0J0GNV7DPG9/nntPCHLDxSG2YDoMv/AdIr8s54qQVdD+0o68TQqoRVcc50nV8VT/SMh4MxI+GBjDwkPr4INuFRuMPw8bMk/Af7k+aLB2PT7eORJOLdhIIUu0IfDFPbSvDCWJri6oGdyDsbM38sL+C7y15wqHKonwiynapBNnBvo/NwO0uKL0lleQuDkaNuWPofVxMbzmRi0a3s2GbtOJuG2rCRxDZf7xsI+urpXhX3EXyDr+H7alfgVpp3L0i9GEJ3ZrsXfItyr7zEgs0BqjVpfSimG/SHySEEwYt4J11EeBvMhYNgl7yMK/jEDBrgmnkhzu+NgEJnlbaMWYJVg5TICvdaeC7AWkd2LWpHjOGD61jEOL/6rx7MPDYNgwAfX++0MLNcdjeO1K4hvH4Pu4Ak67MRkaQICk5gZBxOxPEJrYC2PNY+jCWjHe9e0jZD0OxtrNw0nLdTy4zxpGpqtL8dl/W9hyKENNfm6o6/2czpdLgcj4dRDl85BO1YnA6YxsGt67lBboq1IbD8PgEiu6278SUz++4qtKHTRmyWJi42Fw+ssZVh1viTfu6nAdfmOOeEAHtL9x2+Jh7GWUhyff7eXS92qwOcKW948P42W5s9BFUIC++E6HER7beK7RaHp5257O94VD9FUxCHU3ZfND06D+bzB4L/+MV8Mn4ewQET6WPpl6laNIaEkRu3pMhru3DLnhrDgd7HLDqMuJMPO+MiWU1NHlSzfYM80W/VuU8XnNBCi9587tzc6gPBDCBuFPwbBwNl6ZEEu2WMvDBfZxtGQgaNweBSLP7blMpAj+3HoD169pQvqac2D+esUQf8xFucTpONspjZtLVWH3kxxSOBNONw6MQNv8t/zQxZ8DtqiSkYYbvoDNaH0xhld5WkJ1axZafk3kw/551HF6Hk7w7Ud/k8/wLLiIazv3s9/n4Vj3bzIobz9NCx8N9aPnVpDJ7OCNfxpR7Vkgm8u+xWD7QhjhMmPofpjCG/NmOL9jHr4JnI/Gd+KxS20hfY1bDU+WdYGeoDjNyY/mmQdN4WTcXBZa/wCMVe+SpOFDyP5ZRisUNKgrIBrOz+iBJtES+vRaHq71iPHVtDjojg2gkt9/8YvOXg4psgPB/CAoETvBF9LWcZaKBCQ1f8Qw4Y/kXh9Gf7v7OOnaXoi8f458dz5hlcb5qKa3iaYYjYN8rSeYs9qFfpgJQM8LpMCp9rQj1oz/Bp6HmzYnyH9tH6Xu1YRJ0naU3uDEJQPPaMe+WVi1Mx2iv/nAlXd3cF31IVz0JRwd91hDR1Ic2qUbc39IPiT+ucnCb2P41i9h/N4IlFgtCD4XC3nFW2kIvJgETkp1PEfLn53nnoICdTH0G5NMBnOr0SdlLj43O8j6Fur/Z///lW/txGXp02nq72HUUJTM+3KfsfnJUzz75QmyHelCg59X4Wo9PRD1+4xuEXL46Zsrt4d8gfbV2+kdxsKjRdMxuT0ZY34NUHkpga5oIw+GG6KtswyK695B9V/yuMitHc59iafGkE+0J2k4NgeogIFSMtQeFKWq9GZ++VIN8k9f5MQhty/+NAfV1AMw9M19zI8VgCgxDTr3ejM9mH8dBuUtcKlxGal9vIROs56xpnc6zrwUxGpWwlA7oEu5vxrAvCMdXJb8gYSH+yg8eBMsvOlFOW89QNzuMJxQ1ADpQ74ovrWbitRlKXtkGTeKvCNhqSKaduEF74iZg28yxtHpLllo+CeKIqFf6P9RdF7/QP5tHL+GiCQrM6OQvZJsGtoqSkpCRVEakkoZkSghbRqSSrSNlkL90FCUSEVWkhBZ7Yyn5x+4D+7XZ71Prq//l+WwZGopeEaK0rmI1+T8uYT83c5xQcpiKniMUL9cDb451uCwAUHUKSuhTvktnGt3lfbeeoxbm96Chth/UGejBj2RcbjCrpM+6zvCBO938OWKB0WWOrH7W22cMXY+P59byhdLAE5d+41+it/5o9ZjfL4mFfSvL6fD/XWsqLEEnsed4Acvr9C6A9qgsUYPLDVlaWmZJpWFHmKVv+10sGkOjLx9mLsmzgDJT5aw/KUcFL2+in/U7uM+9iH32HzcsLMT7zsU8t7ydfh+XglLqy/G3GJJ0LsYw445s1FGPRatFQFUHurTn6pEePZqA56aupF019eBR6IlTN71EQsFF8DCg7+46WsKLZNaD2daLkHG6VEo5OUNh0tngUuMNtjFvIKctBG8r/MtrBAy52fuXdhvNBdmb0/hskdFuKNCBiOHGcHXvnKcina4V+YZmIUe5Y+7ClA6VgLC9vSQeNsxFNQHSN5gDA9nZ8LNx0Gw3OwOSzmL8Drz/VT1YDbdvauKPbvq+GdZMhUpTgKLn8/QXNOAdyac5tnVp+DYzwdUMlIUd68cBo6Lv2D+b3c6FqAB1YFXqDJ+EsSudYWoHA2sOxhAoy+6o3jleD71u47y1v7i3HZBaP/6Fp8fceM87WC2vOtHNhqz+LRHOElLHuPSu4E8v+My+dnrgZhXBupeGA8rjjJfnGVF8ocn0CbWJ9UDLShy9CS/P2nJr/MlQVZyEp54mAT0yY4GlbrQUFCRk3p8eVvXKT7XfBQ/HHQigUFJCHDWZNFZ61noStU/rw1AjlsyzKxroj0uWjjshQGM+NbHMSslIcrEBM463GRYPYeXC5xA3aJ5NO6BJP1IsgTrZbWwQuEt5NwD8IruB7X981jzTgY4rsjF1HVDNNtqDL8ck8AxoUsotKeXx/cg2DsOxymsQU26ctSzSx5rTDXohWwx2HedJePoVbjSSJ8K5lvC0juGeKnfG7xOPoKvsd2g0HeSxZy8ICutATwXbSSTMGs+KqEAn+1m0sUtG/DGq3Juy2nn92ZltGXcEvozdhEdfCKHeh2n+c+r4VDzMJ5/tBYzxBnDu0VS+HCuITs8PIVTY7zprbsthJq2w9M3suA8x5L9jt9EuzNC/H7sCJbHfVi7q5oKixvZp8+cHZ2WoXCLMZyqioK7JuJ0jH1RR1qU6w/n050rB2DF3BDKbxvOT0WIvItUAEMIRsxZz+X9j0Ev6iHk/JIFOY1iCpIV4E05AaC5UJxtLMTAWMwXk6aosu7OiTCkMxteVy6kF4MbIXhoDdnpzORSjwpy+2AFHp7rMXDUCD7iEA8F4pqw7LUDK0E3uTwQ5V2fJOiR3Xm0XCAPj96k4MsXfnRhagXpx0zDxydb+ciReki+Z8+/0x/BTXtnetg1Ed4rbMKK+Z2wsseffJ8JUO5nOwor2UYDC/bShJ5gUBVy5YOPlWBlxkWs3z+RV9kFsF3qE+j42Yy7An9Tz9BlUir7w6L3u6AsYBJUmllz/Z4UzLotg20rA6g18AifE56LP07fIOcELV6TtYT37JMCnj+ASYqZfL9ZniQLc3CScCyqfBcG4+FuaLjwBU1M8IcbK0yh4dJvWBsvQNNTS3lp3gbUv9TLZ2d94f2PbVlZKZ4jTTOo6w1D4JlldOjREn5YbUqvjQ3I9/U+yKBUPDx9Cju+9KIEsfX4ZYcCfJR+C4sWq0B6yzXoeBzNdQM55BgoAtML/oN4SRl+/s2WzW4owfwWSZwSE4aZ4Qn0zlKIWxNO0u0Hd6F/2SgczD8NF9dfgD9z9EHvQyb/GfuXdp32B585F6jU7vy/rE2jFhFV2nBkMhUoTWZlYWmYVrSdJrvPp+WP99HTR+N53CJBcLh6CI++2oXFEsKQtOUo324xgq0t8uj4+Syu3biP6qw6+N7rFOp4F8M3JQKoYPAbyhqUgftKUwh3mUA3vAZIrm4SRa7YDTtWXMN85W98bP4yEvf2gzeeldC/SB6mKF0ErzfqzNeOQ/iltXAFOmnFv21r1CCJfjmuPKozj57L/PPbYDInKrnS5EBJkBweiC3dLfhkRB0cmnoSb8YL4ZtzJ0m0Ug6+3h3FvmNeUcYUoMlKptQyzoplhw0j118/MCXChrt9dqLQOx0oVJWDLXk2eK1aGj0/5sO8lQtZWu8Cfh52gw4LSOLyO/b0JsUKXk9dCF+E+rlWWxKGLgzCpRALXhIxEvdne8Hr0nqKfb2Gl5gLw3rNFOy+6cgeG47zHF13cHffD1On7gb5Xato3YgXOCLWC4osZcBo9RtOz/+Fzz2EUcA/Gow05tG+JyUUXWCGmWUVdKV5BESojgWf+ZKU4VcK3xWPkq6MCYqqOcOE8rmw0f0wCxe9oBEa2Sz/1wDGHL4GGj7Aqc2mfE9QjG8sPE5bw9uh9qApX21oY+mRQSRVZgZrYj6BRlcb1d63hdn6DTzydB9mPsiB9VOfcp6SHL+cb0lbXE2hOjieXqn78znFG5xzqgqeSS7DPZazcH5KK6iutmI/24dkmD0aXEcuwg0DlbROxARqP61g9Q4DqJD/RM/z0slv6ALfxHEYosOw7nMn+y4zJjNNP7SWq6M5OomQ72kGeYr7KPiKFjY3GaHlS1F4uMkC5Upu0NnDH0h/yUKYFeaM96QewPfmlfTqznK419EOkq90YO3vXrS+1EQjWiooOjMUJI7d4uwTk8H78Rl61pSKmk43SaV6OEwbusGXZ16Bn5FxVORbiCvcB2Dl5WOkIAmw41ccfct/zJ9vTwBTO2lKf2UMKxZdZguxFv69ToMDujtAoPAx3sz9BWf/mILoimFgGe8B9kun4KkTp9B5kR6PfP2XorqvYFX7VKp9fhbS/C/gHnMjiCzpo5DIDnaOzoenLi6QUN8OOdM0YcbeJphWXMnPRw8j+bJRAAN+vFpCG5RMkuhDiAB3LlCGwlVCKOdVAt1N63nmUVcMvqkNZk7yIPX8OS3MGol/D0+H4hJxdJFdjtNKRTjA3QcWqLnjo1Eq8NJuGJ4/okvtG1egYZ0glxiNg0GnXGjXLaGCPd346UsW6fy0g/1mrhgTGMPTpC6RAAXTjPxbuKxZFDdjKQvp3cTio1IY3DUCttROwBOuXrjx+QNK62vGJv/5DMrCKK28mjqmX6brm2wx0FIBfsb2QNmTOK6J9KPVW1/ymQt3cFC/DASuhrOnszQf/tvH1eqT4P2Nf3xWOoTde+XJauUpLHHPwKVdr3jffkXuWrcdvMOq+LbEeHizXgA31WpRzqwx5CZmgY4Hf3B11zzcL/UYkhVkedusNvgwchxkOF6HfHOi/xJNcNnJyaA1RY9cP7jhprpiGpksSAv0q9h4hz5MKJGmIOMKMMhPhzX2xSj+ej9JJdvhzL7Z7B2wleCLH9f5M0w+vxOc0hxgsd4Dmml/ig3HPEWTPAW8q3wbNgT5ooVdI9YMJ1gdasQWM0p5yW4PbM1ewfzpEn1ffQvPnWml8GM6+F/baPqjMQHuTP2Emqs6UWEVkGDcPA7M6yHlq8kQ+Tyb3t2ohoR+C9I0NIYbXR+o4/B9Gr/9CQnU2tHrg5J4KqON06+c42OBa+H55Ts45r459JiI0XupQTpz+hc3ntgOkvI3UWiLL9J4BZqgtgr+60xHzQoVGFobjLD3JE5c7wM6abK029COExuuw9+7u3j3mm34/vdx9BljBS7ojReD1UjuTxGcm/yvDyXLuf92If7mAHZY5IaWSRvob4oCzKp7g3Xfa7loYy83R+Ww7uIgcLi4BT2DzFnbyg99fL7x1sUMWbPewV1XfTqzcwbHvV/JK0dGg1nHdmpZ5QyYUMm37jwGh7saUGPwlHut+mjv8jbqpv30I38zb9bIpsj7gax5bysem6+Mr/7agbfoH3AGwhuCHfBR/CnZrV+AJcm7sE+zDpxTNfjLQn8++dcK5Of8Aher91RSr8Mmj9LAbosBJjcuh9v/9ZNq0Dx+5CxHo1RsYHWEPW1LnoNREev5Qt1RcnGS5KN+F0lq6UZUtdqL6YOWKD3GBOZGKPCekydo+sttkJS6Fkes7MJf/bpg83AhZP2eyxkhV7DWXh2Eos3x5IIC+PDMAgMWz4QtJuFovC8Eny2aSAn6XpBQMZGbUkbALZEQVLQcwgszrVlISY8Ly835qOpGvj8oBRZB1liyrYI6gsaBZV8Hiaw/S2qq3hAdOw/MQzro65tDILh8Hzn0+3DReFFcMCAAy8KHcOwHTVRId8I9VY/p64eJ2ORnAYk5neCrU0E3JRZB+3theJ8xGh/rGlKD3naevcKdqo1tOb++lvSmF8PrVYM88txa1G8QAjPwIt22Zv6dkUEbzGNR/FgaayXPJJPlLdg7fYCF52TB+VRjeHZWAx6s+I4/V3lyytkWjBBw4aj1Rbg7W5c8o0fxrXcBtNlMAdz0p/P3mn0wtKyGUg9MwbhAVSzvkoUl2nZ8V72Jyn+qsIiaFRww2svSEVkUqBtMOyv1+XiOB34MfIXe/hvRMRk5yOoih/0yhy1S++HI01iIrkwEh68VnPJZj8P+zKVMVT0uqF4HoaLV3LX1H0/nvoEwt0LonHcMk+YX0Hy/UyBiF8PNB46CV+9rkJBTwAoWgs8BpmS35TvGudkTS6TSN5m7+CPNGJdq2PG1e1qsrNDHraOM4WWUEEbmNaBL6TjIY4TGoELuk7qAZ16q0fsFj8FHYS4LzdaFKmUNqnq2G0w6x6Ny8lJqyH1J21NTaOGi83jsxj7QRVvcFyEPB7xLYKBlMypJTyDhrSV8x6KeA9sdIVCvhePuh3Nh0S7YqjcGUhLT6Ir4EtaedosdDs+kWZ4VPDoogIQLjDk1NQfvn5wDDpMUoWbTHnCQFID0GYk8z9uA9955Slua5pLOmGSyW7eYbbZ1k189gfVWAFJ9Q+sTEiC6yhhef5uJ9QsTeeJXPXIsL2bB77a49LAEnI5L4UUPvVnA6ygnmoZBSrYT/jynSGdkC/Dtjx3YqnKQvPsQoEaOg1SeopOqE38pEObqp7/RPTUTR8vPQs+V9WQZuZgK5TTARtwOI9ulofHEML5bHkbTDN9hibMOis2qIKHjgyxnpEAdQ3KQ7eiKGDyVdM9PxfiwEez3Iwm/yszh9SnaMC5fGX5VW8KCW9qQ2yuFY5XL2V9cA59vLsfkkxmk/OYNe47+jAUj66jxkitd3jgOpqSNZNHG0TRqmh7PVC/iyek+1DbXkcae9IfsUHUw0ZTHAmUdSFjeD3tHe9B6KOHBH2ksPiucNk89AFsqpHh64jq+9mk6GW9UAcH0TpyWeJJGN5wD4dnL8KFIJZ8M+8cgcdWU4DMG+pb6gpGyAew9c5nXtY2CPybPKCS0irKaFcBzSAZHf7dg0Y5V/BZD6VinCJTf+8trcp7ijFcTWflAOl74c5i0X0agec0L3C3xD54bT/PwdZOg78V87JslxpKfNeD2G1lSjw2kHwXncE/rbjiS4kLrc21ppKgm+Dclk4TDNtqbU46HTWs4JymEH87rAvXi47BtrTzlrFqCkmtt4MjCH5QZOpxzchbTcp3X5NqRSYezs+Hk8ickuTQTC/5l5SZdcxA17MPmlVW0I+oB+R5t5UWDjuAxpRnLpuzigeszYU3wAlo7k2ChrT5M2/kUDWTHUJbjBgja3wHu483pRtVxfPctio9kZlJ+qhpYnrbC++9/wc6Q5zR+2CEY4S1NMEuQ2nxiOKZlIWk+dcXlHqMg/d0CjBn5CKR2e/G2gGt4ZM1FnGrkgCMErCh7jhwUfmOqvSkAB3r7yflsDC9dVAg9Ie0welM7vXo5mZz4Gi3Siue4HfNpliGAZuMXLpd0BP+1inw3/wwNRNwnw0vmHK7XBvkLfOFJ0Qu2u60EMZcq6J2wAJ1v/gF12kW8b4cvjFLogbbu3eAjWQc3O5E2HVSBIpuDGPS+ERqTe1kkZRxYnfvIXoH+OH+4Etel36JncwQx5r4QzPs7hc2XaXLG0eXstfguPqm0x/mHpfG5ugHbLIrg8L1ytO3WKPiWPYJyj+Zj2IAPSJsZUm2APkj8PIpdoVf52/48umgSBMoeE+Djs1w6PqeHu9VWwMSBsezf+IIbX43EzFkf+OUCU7LUkYd7mtrgtj+Kpi7fBZ/dtMBwRidIrUM2C52NM+KecueRVeD9NJEVQmwhdqs7+W8UwOcC2vD5QTVPmPeaT8zaRNIWbygrtJR3hK5Fc10ZCF36Fd9PnoAumlfZW2sPKshE0IwvkdjXJwx9hjOh7pU9xS/VhVk51qhi9g3/WuVh3qIc0vTwpd3+PvjB/iZKnb9F19ZeAtloG9j7dSNz8AxQHrMd12S8J0U7cQzaZMSXYhKoWn4zTV2xDeRXaUGs4FQSPu5BVyQAZZwjqf9ZDge27SfLI4yejjVQ/T2dxDRNwKvzM+dLBOKGxxtRt74Ef78/hzbhV2DY9jJqlImlULt5fL5/OGxv/4tNT0+Dl/kINk52otGjhLjyMqN/4Qj+3beTVvgLcr6TBYh0b2Phi12wsUcOTBvOUMLzQLbeEccSUj/Ar3ALPjdppzvaqvBsxSSYqmmJpmNryHfPZw5Nfcl5Y46R7LnFMBDojRONv2G4kjZoCifD/ivjeNDvGj+QzcWrCmKoe/o/Hl0hxJPdijjz9kqSHKkGf9d4g2zcEzB5dpirbh3GAZ1QKNw2BubFHOMHP9Oga9haWPfJGm68HEMpJ9LB/msA9de0UZ5HJmQ+Po4Di5Jw3+pwjA1zw6PLjCDT7TE/F9kIzp3SUOJlhadtZ+Pon7vJxDsYw33H8L3+XfA6SRVy1YaBWZcTuQge57GNBTjmihN3HDiEG61uYMJa4pUXCljJC2D7tGuk53sbrsaHoqnOLBgZdYHDR9bQMZXLnDO1gS7cVsOBr/KwcJIDX8gthllDzRy1ZxbOjFeCdcqAWdsDoTdzAXXjLH5TZQvvL9iCX+YLsm95SGahXbjFOgFcxQXg0poPbH39DQvmnmY1MxHw3BxItd1DND++iJ4HTAUZSUWu37wQOwblcH2W9b+uVYeFfWqwaZwZ5EbKQcDeXsDgKpb21ifVhJ2oXKJLR3YnstYVMZr62QKGeY5C01G36eOcAxBHvynKJRYiqz5j2FAyXny+AUdlJVPyk7Ggnu1Cy1bOojU/E+k7DUO56qJ/rLjt/3clMdJmLk54VopVQoJwBYvhyupSejqukfuXJEKsVDWbi0nzx+xnPDg+8R+LTcP/DqjDmS/T4XXJH95u7AcPzkfgjzgl9PU8B+O7laBhgxSPlPjIzaVq0Hpdmp23rIXBk2Vg6WSHk1tsYcM0Zcxe8Y1v+8TiOJtOvNluAicVCiBK6SVU/EX2eS6LJ7WVWW1dDH7YE4svJ2tTgqsMTtKZBK7nCrjfcx2N/NZG1y0aaI+sAQ9EJrP1w2Cw3fOaZMRTaVewOnyxF4SZ92WhquEddVeXQpTdC9794CmK97ngMf926B82nTynioPTUQP24e1oavgUg2xS8XWsBCxL6+PxyYUsqCsFH8fsZ58fIqBZdIyXllVzdFE0qZieZfuWfqgp6AbNg6t56sVpfKNnMYg02kBz/02OffwLBc/48deOEJwfV4Ix03zQe2k+LbXbhbMi1ElkmzqIL/MDmTn/oVjEQ7SJaMWlx9WxafpCHInNLOOdhS9eTaW5KzVgttAdMvyaR/MldWFZjiBsfl3HM0wCMfRXH4SovId9r23pVaYxTP4EFN8hxWVbn7DV/QGUnxxKol2nwSnlNo2tesFvt+7gx39E4Orsaup1nkwqP5RhTUAGx8jL8f4z/YALtTnvUC3JJIjjHTUpqPt9AsOdVWAROnLuBeSPgzqgtVUKf2pakL3RFtpw6y/iFDFwuHOYXy/pwOHdx/j8vyzPn9rGb0te8UKPLbCKJ+HzxlCoybCAHRXqWHJSigQ+LgUhi2Fkm3KaXEapoLlJFu4qb+ZTqbNxzVQVaEoXwYxXAyxZ+IlKzkyHDeXAAmeX0JT4n1wiaMzzl1eCv7gxeGqb4ts/uyEwOQbtKq1ghUscncOLEPVdihpPifD4rvXkIiYHQ1mToSlhJn5I38s1+b2YfTYbxTZNol09u2j35iywuvMdZjfqgs+K6egh952j9HRxvoMyfxMxQ5OD3TSsPIQXGLiha9MWGr1JFc7+qUTbZ0qYo1dM23Qy0GGDKo+squLH1S6Yb3oXH7WF4GJnUZD1rOMvq7Uo8aUULeqVhR0LM8DkzwFyj04F99A0MM8cgf0m8tD+4jg3nj0HXqMacUWxA0y38ODZi5di4dscajR8CtFxheh+Wxvw1QPaL7GUfKpm44VRKfzh1jio/i8Snd89RrPgTWi0oIocbqlAvNNivGUuRFfSLf597wP/rbcn9d7l4D1WEvIfzeTxx37Doc3DofneO1oveBouhDyBRXMz8PiLmdQuPRmfnR9G5vVfQfdsGEd9s4ag0bdB0PoixVb6YHqcLFjcrKLRLQ+4oGYlxHSYwBMFXXrsYwgiDVNwytB4aKmqwQ5PW7y8vQcePZcFyfZFcG6uMi6o7gWFQVs4a5+LSlIetPT7H/jhMkhV43/Tx5PDSKJqISUvrYMN32/jn2uKMN+ziAxXb4X+R4V4WiCMBNVjOdGkmYdVTaG+u3egUyaV+7oJIpN66VbaIB18fIm2uF6C06Pl2N7qOz95PZLFFS5yX9Z5/ppuDe1lM1hz0zccyh7EHq+rNHLyZPow+ImLQxl/HbTB5ExD8BXThvbMXkrYuBPm2D6i9IdC3N7pyRdPV+O5wHbWmxIGZusBX86XhcmXt7GBSzY4TAiCU+IfWDPiDSxY74uzju1FmUgrFhl9DN7tnASqmkZoOukr3VU9RcUzk2jJh0ZY/caVWvZ/pGbfc6g4YTzyFnlQ0akjAZUilghwhDTvyVjwezXOWDZACRuEQWX0QfT5Ng83OSP4ltig+foZ6DSslpeHR8F06TXg9181Tm/z5Hk1IrSkMgfmxiqDbakAP9Q4BkI35oNTwyL2kPHG3IpPMCVPDG++dKTv1UNwtRRgwrV8bti3CrvSr/KzVGk6ZBADWec/wFU7Tyic8wKWORVjfbYYzBSuIidcxh9CpWCgqILEVD7i5m95KNSnDko160l6uDmWqyFkJ70jK9uVMDsom8UKPXi67BKOGK+I+RmVmKVjiBdaSmhugR10Oj+lR/Zr8ICgDcutF4VrF75imocE5qwUYKi+jgGD+0DeBUEtOh4LgxXZp/MQnAraxBrHj/EtxWB0v5VCm9vOY/ebS3jSWw7mapwndcdJ8EkulTsfjgLe2kYTrwRwxnIi1d7NXPbfC8KcYTB91mgU1flJTpPXUerdi6CoIwQei1qgxEQHSyT/45fSZmSdBrD0lzPHX0yhq1+tkDXWU8/wy+DaNhlbA0to2xgZEupQwSf/CcG3A7pUql9B/z32x0jZQTQMXI01RXIgIpVAIi07aFrUG8zMGg3PFErZKceRLvtbY1zDcU6V7KG7QfF86dNXrr76GAyPTeN7IgTfV9xHqw+dtLh9BrmWzqNjzvXQU/kQJ99fy9ZRHyFVcyX1K0pC4uEOCF22i6Rb3WCoaojWi77Cq+fq6FpLIN3UGclJR3sg13A0bPnziNVS//Ldu+6Ysk6cxGZYU+xxA1bdLsI7Y6VIProa1xgqgECrMyX7m/OKIik4v/IehJSk43k+C63D9vG8VT9Js3kQixz14fJnGerUOUhBh+fAVUltsh7/jKRHFkNW/R188nQzdA2lQJURgq6dEF2tncbmhWqwekYyrduWQu3qunhW7w3nLd8IM6dVY/kThGixqTypdAzmP83ANS+WQ7+2wb8d/4DErwXRNJUEnnLuFeYMWoBASQNMqIpD73PGdMR6GFRPv/hvV6pS0UJ7FC2VY8mNFf84nUFCYzHKva+kEL9tdDzhGUjqJqFL3T5uf/MeQw5V0bTHP0hsmCSU/beVow5dxXBwR0nbD7goMhl+dyfBwlslnFZRhJ/jBnj82vFQNq6bPNe+wWmhrqy19wlpClbTI/PVlFFeTFE9UhxcKU6aVuoQv0mBn25ahz5Fj6Ai2wlsOgbIbddvsDCRw470mRC2OAddRAxhw+QlmFn+DM2rP3L8PReafHA+Gc8y4HO24dBePZK0e7+BX5EqvPBUwrJwpsWT69jVjzBSYStW6h/n9XMrYf+wqVxWpEI7V5nAdB0VDNgnzL+mrvu3w7dj4NXbeGmKO1jN0YXZT4dA+uxEdPioCkqGHfwwYj2kXH3I7wV0ccQiZxb2LsCqJRVYoi7+j0PysGfvOLi8xBP/Purnqb7EZxRsoTc5jHdHJ5Hlzy1Y97SQz9604BkDBMcT9NFQK/TfLq2DT6NzuX7gP9o75jS9v7KI7UpX48cXiWTxRAlELy+n690j4cCb+fBOpQmKCmfQUNBW/KYE2Br+Fo0XavDiv5Oga/AkHWm5xLnNxnRa+TRPU1CHz1XGdFn6Pk6tP8yx9kJ4QFQTPi0spJXfJIFumwFI3MWZ1/2h8N1zHD//GLn79fCGw2NAbY0O/Je2kg/9l8tdt9UxVDGEXfW0yTynlmqbw3hNhTWN79TEST8MgQ5MoijblWRyS5BNN65kBWsT0gyeiYpXj2KxoyzF2HqhmvwksPMOwkphIbA+ro+9Tc+h1nwV/ZL5iLe/bGOBrjYqXGOGu/doAoTPpHVtgXhwWQ47d9ZzTNAtTmRHtpP7jAdmZ+Kzm92oozgCdvX04NZNm+G6mwKdXh6HwzOq6KfATAr8uwpkXfP4Q4Y0yp4QgtNuSlTs0Emt7Q78Tvc8ON8fRR5eprA/TJf2unbByVpvDF5sBh9V0yHAbRn1prnx6BB72hhcTSpBVTxcsg0q3EQ5/1o0B7/RgDSfxdwbehxbLg9nj8e2eEDPDIt7h7P48HcUOW2IB9rXobvyKHg2UpceHvxN11PHgJSpEKUrSJFP8TKQrRVn8xwVaBzujz9sxkPBNSkyef6H2298xJ2/3sDy+Xn4++deEty/j07Gd+Oq0ABMKRCF2BBz3Ll7EZa/eoxurc3suG0QhrTfs5v3KZr7WgB/rX0P6bUq8LfSGcrlpkFW9z7a7tLDJg++U0T0K0z0/coyyvf+eWAI58eaQYPKEXb+fZtmfduBE5e9hav7BGj65be099EOtnuVizJWcpx6XQqiIyJw0xIT2K7zgXucn9Dn8r0omypM/tUfSKl+JP4pSKZiT3HIMizHyU/3UZ/tbnrsfwiKP8nR1rwBDjvxF48VaVF2/0TqNRKG0LR7NP7cEU6/oMO1A7JQrj+ASwYL8eu2dlj+3yy4UlfIKX4Mh9JG4ZmIKfRJawzvmd2IZ7Tmk+fAb7Z0mo/yTxfQ18IgDFaxhdO7RHjQwJ6TTp6kr2PVwd9xM0563kimA5m0c/cfcj81gjcv1AW75nB06G3DpXNuw7qDZ+H3BhGYZBuOW24F8OT+sWyme4FPE8HbHfZUHf4Rlq79SOI74zlZ0ZAqz/xknShhCnb510cGCtj0RRZsrPaw4/Vc6K6ZgeN2xOIL6ccc5zCNPHruQ0nAK/6UEY1b+vShd4oAd53UhOUva0jJTw+M5wnTxsON+FM6AHZ2JcMZ1UNU5CwOmzoeQneRCKNDOKucDqWqjHGYPXoAj68VowkVP9l1Uz5XiZjCnpnX+Nq6Qnybl4EPHeZy2Wc1+l05G34VutMHDR8S2fUeCx8ow7j3NpC7JA1v4FUQ2V7B13yTcMuuSlI7vgR++epAoEEgBEfpQNapKFDNUqS8Ldf53fHLmPkzigS1DGmrQjsJy0zExBmq3D5pNPRpdPHjBfvQVSkOAw3bOWSojNRmboT4mBdwMlWdrQ+u4CMZ+rD64xE4YvOQ1lgMYuz4Fr4vpEp9M/J4ybTdkDZmNdton8WYz2PBdk0Y77W+Siq2f/h6yVdItYukK5WAv1v+YmxdEFqHraA1/3RwPus6as25xmedNKmiW5NGHVGAoElM/a5CODfxII8SHkU1a0aD3t/XbOqqDTaqP8lDHunRyTbMv2OEpVr3weT1OkgCAO3tJtCg24HrDtnwwqV9NFyxGUu7m6gp7wpvcZ3JR6VP4/Cas/hrjhpc1c1gi4oUGm76Edb8WYf75DdzkFYFPloSRpe6fOGOSwg/eWsNdRZt1LjXBzQXv8fzrq74cnwISZx9TvKJ20koroUj5RLR4JcgCIr4kVruCJ571gvMvyfy7297WaP2I566HkkvnifjbW1nKnQZBjOVcylA8jt/8rLBG+Zy3PbAnnQckuhTwDTyjj0MrF/PPbbqkKv7jK55psP+E1sh47Y5xHuXoe/NEXxtLVHUhuFspq0GH9RHQqH6fPALmcJjLwIHj5MGv9W+mPX3EB8PXkXNGQvZb1sGBu0RhKbWb7DqmhSbTlxGN+/OxqVfkikpdgqKLvTiR8H3oWb0FCobYQcHVZHDl9thif4MOlz6lMX3FfHFz8pYua4Q+lNd4N6VKzj0xBqWsyQvFmgHsYpamrhmOgRsHoaRcja8fI0mnIpvRZdVX+nV8IlQ1D0LUze2wGCWESyxmcMGX/+C3dZD7HhkLYx5dhUkZVz51mIbqAy8T6kiUVw8NREilkXxl2lrMVMuFaJ32dPJqbcw26AIVJ7ZgN79QBjxW4oSHEdh7jgV1PmzB3bHnCOtBlcOrdfidoMRcMCO4PDQFhKNP8paglF8fHIop19PhmffnXn8hWSY6zMaqh4ak/9VS4jXVKOawOlseHiINT0VsMjbmIZrbYW+DxmQ/7wcDL5fRpMkdQgyUuHNT5y4bdph/jZ9B3dFb+Xs0EYK9XqI08ts+erDFdQ+VgwmP/fC3cFW7DAnGx1WfOa5pz5BQYUZV4ol0KSvF6BqbiPXJcpC4RI7Mk9N5+Co37xKaTg0SrXBlfBmvNdwjjdITYd3Y09xmIoO1NR1YMVRASyrWsq38jahd95yjPxSyr82xIFMlRacXx4E8kEq8CxlD+48+IjXCo+GEVviOC5JBaM3jiULt0CaGZSE+8f50dQRpmDZ+5aMRlbxaP2PWF937p8mheDm72WocdsRJyXF8gTrB7RYUwF0kybDqe5mzm9qgdIfHuTqGk8bX36liLBivDN3Hpa8G8ap3lYQkjoeSzee49eGorj4ZwuPiL7Eyjcf07U+RTwxUQJkg5r4Qo8JvOi5zNPuvoUKmSs4TOACTj8JXOW8hxQShvCtYQJvcurF637/dK7rRmWCeqhqhPhrqyyuH0jhg91HIcCii8uzp4PR3DH0rolAb1IFP3+4FLuWO8PwWdkghRL8d7UIJyh/4Emnylh5TQ3s/CUPd7Y+gSP5DXhxTz0ZbfFl/YYYOrZ3NhteOIrnaQ/99xvYXMoEFlg+w/BRh1Fiwxac0nWA/1ufQPfmZeDBGmvwyPgDR0oVuVFOGtJ1UylaTJmOjn3GRo9iqEhvHDbdTuYnKal0WmALBMWtoVtimiD+7SV+0tlKC3bJo22/MAoeXgu1s3S57dgM5G8NvMTRGmafl4LX6/J5Xdw0Gl+mSGcierDpij6/yC5EkaTR/PNTCVwRPYTjkhGMTC5ze5YjRPucw5Fa90ku0gW66/5AX50CGXTcpg0zJ7J69US4Ey2HKeqv8f838Fm6hqTe6cGvdDGs/xVJQS53eXfZEnqx3A4S6uaQc+QDeGX3jQpP3+BTFr7wK9yMkwv2wMb1s9G0sBQP2huDbuEODKi5i5UXVKneuoq23vSlUWMvYOFNI8ism4R94cnskKkDR5eoYqnDFL4/Looq9+Ria2Ih7FdWpzbHBlJxTgPVFdWUXzoCzh3SBc8PYrQ5o4jizpnx9m3xuKPdmyPfxaP3THE2/PgQXlxUBbHUGjzk9x/V+lSDwlAIPkowwZSwnRji/hwWXGjAmXO00V9gPFxzWUKVTuIMNQ6kt/oHLIsoxQbzNjbSj6CyiM9kqfaQlXNNAJ5pobDwdJbYfwpcCvrw/H9WtDmyhCaKG9HOx+o4ecN8eNZpBusiOuBZegqd8U0lp5Gx0Jt+gpSTZ8ANibP4R3sylsf9oJcHlCAI93DOtUpm7QxwFzeFCGNt2C29hzQmJkFy4S2ee62UZtuNBq2CHTD6azBcv93Kdy/60LMR/mykOwmSqhtR19Ma1G2+0g0LcbCXusrJMkVw2rqFrmn1k/yWvyT2Mo9tVE/ASlcxUI0XpGofCRgyeoWCmwY4/H40PBxK4qySCdjmYgZXtn3FlLR5ZKYUS6pHdGHBjtX4coc0Htv9lGSXOdMx/VYuvfiA/UWLUOqADu1YFIvRey0gZmMhhTc/gj47O+4Lf0phgluoMVsYztl/gOR1+ux85SqGTVKBn+tWo9rG+1QQVQsCu06w4W1fMPGXZJtn92Fi4mho3O7Fk7ImgI1/Fu8bMRqn5cVRsVUrShzKYkMnFwj7tIcNH12DrxPsaPQReZB8MJzy1bNQct4feCRSgZd3KMO13qcgfCaAp8t/AaWVZhSwRwa6D+ng5aAJ8Lk8knW3WWHLxzY07Ong03m5rOwkStuuSGNciwmsDvoBezLd0ey8JZ84dhb2jXfjhZ4TKSawEm4OL4MVPf24qUcLOsoWsLL+C9h7sQYmPjoNmWW3MCIkh8cYL8N7sx7S4j1zUWeaBJQIbqW8JlkcSEnArhIvEHmqjarasWjcIUiRaXKYmLkA44ONwHl/E99NfIp66/v47YUZYHFBiHI1ZXmHYx5UlRvA6uOXQfKWApzxfYeemWGoFHYILqo/BN8rqtS2OR9agt+A3uo58DM+miXK1YD7fchv6wdcJheP6jUHwPxrMIa3HqPCGT/YcM8KvBATDTJuI6Fau5U3GQTAtl3ucKh0IonEvoMhia0QqvWvN1EJtAP0oRwNoCJkPGRvP0TVZo0sPlaKHtwLg1aHhXhxoxBdjjjNA3PTcIO4CDw+Z4pGwQgTIARUJ28DkY9BoKpzCTb17KWiukG46qeI7p8tYdfkLLz+UYHurtxEdq6K/HPjIEdK1NPd9x5kPJALpTPSoPSRERSNuEr3LeR46CXCi2ITTrtohC5x9+D4yrU4afcObg/5gcUuGqDwYwV0K97DwZJPvFVeAkc+PkgqBifh24PplHQqnENPvuaLrqZwxzWGbPfr885LUZDqeJ7vz4+nHZ5vya/eGOlQAYb0V5FtqyQsdpOCmUFusMrmIjYHmXKE6nBO/4xcVyvEB9zegpbHHHq8eCy06nfDkisW0GQZC37/MsXKvoyWdN6hHe9f0QK3azAubBfqGItAmIEU2H8qxLa3eTzr0Qk4fbyDveKnQ/P9bDgxUp9s11wG5aUaMD4zmGpN6vl7SzdPzPiD6/PsQX1BMtjmvuDepw9gf2MKis2TBivJiRh6+gFfelUCasZN3GOZypJHvdBkuxNanc6lsGf9MNVZCjaIfKJ63RT4oBtLK236MKxzG83L92KP3Quh0cWX7CU/4WYFQZgdWgv2wToUdu8RORRrQ/uxLVj4nxNNyH8PoWGSYJjYSEustGH5OWEQBiuOO/cLS/fMpV5zNcprLcKr6depfkwrvNp0j8vLLcDOoRZFx/4gg/hQvmEgw7UFEeDRk0/b/C2w1uEvCUv1kWmzHWQkHWf5Ox5Q90yClHf14fxOeQhqjYBZ1ikY/cICM72isF9eGGyr9oFvsh9axjnyBHNf1Io0B/V6K4gIW0whhyvI/YoZXyg3ARnzRtx+r4YcqkupbukDaJt4Fs5+d+XFKfNJ+P0imiI2HXe+N4BFipm8QeQah244zgIpofRXbBVPW/GQMqfdIT2LCpaXU8Tz37Sg00CdBZ8NYMPiN9R38Cde8yqE2WIDYBNQypY92bh8YTIu7VCEVzm9tK+mCfr6A/jk20GIf1LCf+zdab10DE3emQ2dq4t5qpAtGNp4s1/LRfZ9d5btDs7kenMjTlmUhErH87FpvBQaiIdAWp4ChFwO4dV7h9F+9UgsCgnFmLp5cOlbK+1s9eMFOBl7Fw3AkcPq8HuHD5VoNkB1YivXjp9M4fKu0HTPiXNNPSH/5ku8NKjP0SMVYEPZWHzYXQCFBnMwY78QqDfPReN3B+FO/RbY/quBVW+/g8mLjcCkYhbeigrF22mWfFhwJ4H1aZTyycE1u6po6IkW9vrq8Pf5qpCk+pQc08z5/QQnMDgjxzs8h9Oi2j/4reIe9rxfwcfP3sOSsRLgsq2Dl1geh96l83HadQUSlnRkJSEFVKsU4dfukTjp/ivwNzCAJW53IPrXg385ModrI1WxuC+UHa0yUGaqEEp4eJLslTmQqGcIf3PEoDhIAX8NXKIdxaPQ3ekP7w9fB4a2fbwJEUbUVUNkkB0off/ADWaOZLBhAta/TOCzn4QRptdB39ZSEow6B/0LtqBVqCi4aVdB1bK3bGRwkH+8LcWPVA9tgvGo2/YFe98a8IGO1/x83CQYF3KfDOyzSdjwLb64HsvTgy/w/ZB57PbHGdw6RsJ90T70nTce9I6bcr90LF0+OB/MjvTgnOuz8f41dRhfGgE7b2tge+sb/nTCECYoNsEIx/8oL1sRaw3/bfXz1/Co7j8u+6pOYy5PZV/f7VzdMAFaH8zjhhX/enfUEL+LNYfKg4v4utBrzuhdyTNlh9Co4Qle/y0DGk6VPO15F0g17+M5qVG48psmyPnv4+Z7E2DxP91dij7BR2da/+vjFLD/5kJ7n+jwTAzG7Xe+0xnLaRiKImgt84XTj67BxlAr6HYrIPSwxKtO72GK7QmIOp/Ogwees5uKP669bM0V0jPIfjvDnU/7SVTuKx2mKxSvPZ4u3pkAMXqGfGrwKcWV3kEvi1JofKEP384c5VLFbFDZqkMCmXI0dcoMTL0igC2lA3R7nxTJurwivUwb6E+cz8UVl0FIMo8q+//CecPDWKi6FCJ22fOguhXH3wgEn+OWcMuuCdFqLxRNCOE1XxXotf0DdLiQiCeaUujyXQ9mO0+KjlaAU5aSsPvzZR4jtJVvOE3lbdt/k7LzX4q0Hcu/l5bT0g2tMMFBB7aMaiDPTco8e/UgPy2LgWud6iBiMEjv3EQxReQQjm3zpJVuovBdNBaVn+jBqQPi3PfrOZ1r3cQu26u5RewHFT1IJi2NYlgw3QKeT0qnly4+9EdXhqO+7YBG6b0oU7udpvuYo8P2cFh2tgNyRjIsa7XhzqQyXj9iE+5a5spf+pTJ28yeujY3sPQbhJi4TWT7QwDqR93iSzn27N4pyk1Nh7G89x3uN9hBmx3voPSMETDx7BtIu2EIn7e68oy0ffxSVQ0/7K2i9/XHYO3nbeTSGMqyO1bhjbzvsCh2AvzeJc2OKS2s9auEUW0FzdaXxoEkK144bhjMfN8PgcmFkDVBCzKV/GHowAWcUH+P84ekwS9LBKPfz+X27kT6+MWbfp7Q4HuBJiAQuZYdv9ShvNg+slrYTvvzy1G07yzWcA+4Lp3FRht6SPmFOIziF3hgVylO7XeDiLr9HLBKguyWZ9O+d/84ytqZHv2QJ6yW+8d5/38fRhVcZ0URTRqBdFcac4yaYd3q23CroQML73/DgiY9uGKxhJqfGuFfwz6YLqlJzkUqpOFXTZd0/UEl7gfWbklDaRgNpWPPkZydLK2Nn8nvcx9xkEwkjNk/ldwb75G6dSJ0FHnxfUMV2Kb9iqPip5DUKktUuXkY53hZQ5bIRF7Xa8uLtwK8dYvC8JGS8Dt7GeU5fYQN7UvRrsiedAMNaG9tI3w/KQgZdpZ8fb8HevQYgEPiWd49swMMf+3g05YT8ViRKGbI5fCw8jge/24tzzr4F/p6JWHNW2fkJ0kksqwRGqJ24+KrBEcPfiDF/oec4myD6heX0Jsr0jA8+zju/e8wDP7J4eCMOSwa7QZbF0ZimXAY2C0J5xIJK17ToQ5GyyJYWeINVE3YgE8fK4NKYycMfH9G6J+I7SE+FBBwkoJFTKDm2EoW/+OD735J4vN0T/T1W0gjT1/hZqXxOOGhOZ16eR8XByuA37o1dDLlLY9dG0yWKYNkuMudHFR8uKViM8usPkrnrKaxz2cB0DjQyIOrhtGXBmVy8c/FqnN/cEqLF9h1KlG5FkH7zEAU9h4Ft6ZGwFnVPbxgWA19uRfKZ2MaIWSmEo/3aweHg3pUb3CA6m/ogKDSejp88DH+9oqAjWFLeb/UfNjoUUg3ryqTcUEBtM0aROOJDMbFRvAhIRUcx0lxnoUZzdCfw7mReqD04TB3lrbgGioDjQEpaBg6AAZbmF3vaVOQhy/GSL7E5/0JaKm3ib8eeUqpIRL0/ogxmP/jC/u2FbTt4jUQ3hNFc5TV0O/1N/jL31HkezWKxjryJmlBEG+/xM0nxoDU3Xs8+WERjV4uwinZ21AtbR6+u3YP59ne5GNS0jArMJ770vy4oHAiyWsuwM5jfWAp48o7NkeBS20JQmgOD4AxDAbPwFv7vkNGvzbKJY6EK8+96bueD819GcoiJU/RJn0DtGZLg+IJJ47IGI1/RL/g9VW57PVIF2qaZDhd/Dh6/FzJi+5FgV3JeChbW8ZhBnF8MWEdFV9cwVqx8SBdthga9WVJ0/EGXcp6CSruxnAzM5AUA+rgbJciBWd+h3mrxlPJAXMIqd/F1tpu/3J5IySoisDU8w08MdOfvu635hVJTyBrrgd/WXaGp/8uw5E6t8FF7AxGtFvB0mopXja2FO6nn4SNBzvhe3w1qnvMpxPfHoFRgRpdHHaGFhWrwMCrThjcOBZygiIgoWsX1gtrc8mIKTTuizaHT5ChzX6qtHGCLcx7J4EzBA/C1uKRvFPoEW68K0lU6Y7DdZbhf2p2ZFKYDsOTEMolIiHQzIFfRCTylfQCSH8wmssPdVP5rX143fASNhyvgu2f7MDbfQF4totTssZyqm4tZM8F+mBTMxw1eSyGb+rhrDgbtg+1g17tMH73ag2dWazBPeebaHpWHt+9/giG5DbQxtutcMppKhxq0YJHJ3eS7m873v4CST9tLCU13MEItUssn1cJfQrN/ChlExR+sgbl6h8Qa1fOsKoLbEqiYYvMG9I2/YY35t6GGaWvcayCOpdIMdzN9MWOXesxcy/SF7PfWFtzk5b83cqbBXeyZUcNBCpmwqeL48BL0pwPdyzk5MQM2qYlB0cK5fFCkw1c766H32fE2TBOlpaNsAH8moemERdBsfE8JOv00U/lifjlQC90PkwCqYlrMdt9Bue/UIRo4SN4fF4PxuifxczeNBDTXwER8eMpOvwaN+y6wH2bHkHuIS0AjKQxizTBLTsNR5xrp7Q3rajmlEQZHyZR11YRvBfw7/88tIC97SF8wTMChr1/y7OF+7mo5zMlOk+nD+ekSHdUHTud/Uy3a4bDw+na3N25GZRcfpPm95NUb7UEe8WH2MDXBKWuLAHH7YvJ1E0AxoZOwjYPP67ysua1Blp0beldctYYAcX1sXguwI5UbSbQ3ISxIHqqkmZsT6OOY7t5ekA6j1q/ne9YRNKcN8e5w7/7HyMc57iFyuClPwX0snZRhsc+LPu6A0+JGPNwi3be5n0WT/WZ8PDpzVycaAtp3vkskiCKo96lAxie5DuRTnhD4DttEOygwpAwqO+P540XlCDqTAtYZDbT1pjz8LN9O5XuqWGNB7dp4cMK3K1QBv2tFzjNaBg0p86n8Egh+LPIAFumdEHdESUOGfOFtMSM2TwwGd+13CG5rWIQp3sbm+Uu052CcZz6Sx9PywmxoA/DsZZjdL3zBJZnJ9KT9yYwxkUJ501YwiNWH4DqfEN+f9mZfmSP4aNj6zhrWy1nO13H/p26EDrDgm8mO+OBOlP+br2Ym3t1cGOXAX5dqQK5z77yjCWHWW3AHPTaVnJMUgL/bNOCvm2bQbizEhcVV/HlPToocEYKlV+k0tn9qhB6wJX0Lxwl47BTfL/pB0vc/k6bUpXhmukH3uCRC5tT5gDfF4KASfb84OZT9rq+lPbtsKNI91jUipmMfqvDWavyGnxdJAbzbfRgUcNq9Iw6QMNC1GEyAdW9vgFnfWpxUpMU3TUVA4GGlXi6QAXu/o+4824I8e/C+BnaW6S9tCQNoamoJEnDLNkzilBJhayGn0hmGSENKUlkNBSZRRooZGS2pTQlT+/ieQnfc59zfa7PX/ecBTxav57HJbry7tBvYLr9LjtI3aLd7ZNAx2MFuQ+I4s44GVjqwGx81gval5/nM7OP4jh3PTj8azF8M45Eg7RmyOtYg1mpw6Huzm0IlamGvG5ZlpXswlHH35Le7dGQ8WY3D7YChqdPBM/ZCJtyFeHChiswJzacHTXfw+Yd0bhv7S0YnaeArdcWQNPmDzTuywT44rsXB9SnwaK0dDp3zY6rsz15o/AO1rmcTFl+M6HK4hwf3CQHlX2xfGriYZhrX4oNpn+hRcEc2zee4c6481CpqwSLlzXQsnIbuPY3kZtVMtFipTFkrbMBheITqFG0AF6uCqeNoWbc0ikOijmWsNx8N8c++8P1wQW44401/st+zM3zgKdXSXKNQzmO7LTHAZ8hXm6+jQUWW2Hhoi7atECalMXlSW+jLpzUlQBnpSrwnzkbUkaNgNNqg9BvNgIK4QGlXvnIUXvPwfU9NyH0WzucNAwD1+uCLGllBNV79qDs7W6QmS4CKScdKfpjCcfGvuPH5MZq6U6UFb8Mns0fCb274/nBq1EQQ8dweNpWtrFVpUM96yBoqhdnl7TyLpGpWCCvA04xp+HEO0u2OhEAq7tXI8x+BxevuPLrirFgpXiUf31RxmmyJmAz6xkus54EYb6WuHVbGelNXA5pMwdZxaYIj9ft5HrnQdDdIA6uxWIca7ACHuWWUZWaAVVrLOQW7cVoba/NK8vWQH37FHIaqQ4eH1ZwSl40PdxZiz12l3HaxQ7QDA2jtLxk7NqcQyXh/9hqtxgoWN3E3dlBOH7bOVx95AGpVmZS19NpcNnBFAxFhehk/xh+pK8DZu//gqWiAtjMPUTtSwypWUEDDS5so/BJ/jxjqwT6lXnzxaHe9JcVcegLgE3gS2w+aQyKZfWo9caUX62eDntTPrChxGfomqsDawSqeJxGJcEUZbR4O5F+7PKkwbgtMKtoHovrXQGhkxVwapgqTHxUSxcsnvIGzT3Y0FLD7lf+QvaOFFZ7poAX9tzm8LAsChiKsgjpN/iwcBncP7IBHmZO5WFJzrAvdxEOFD+AjMTp6KDmwUHLFWBO8ltyHS+DC+7Hwbq0FsqpG4Fa/aIcf8Ie5rrJ42W/oftW1oIvJrqornySb9pF0fmfIThoGgUDFq009WAkPA5IhBOvlWHXQWHY4e7JBlXLeeGjLDzat4LXJBbinT+9LLc4F1wVT9FJ9Z38JmQ4nPA4CJcqBln2gSpS0lKUN1oAFkERrFw8jtuPKWHPiUfIbTqwSrKadB+85oooMf6z6BebSxuRV9Epum36iczH69P1DxrgeX0YrN1oSNeXKNCnqE5o79tP+zVUOLeukd6tU+JowUquxlHUu3M0/PH4gA07/0JeaAWPygkGtUFzzLRTIp+5e7j+6wHYe+kP21zTgra90aRsIgM9mY/IaJ0e/6xJR5cV3hho0E+Hegux+pcdSIuJwWuJ97BU4gv7Ofnx9WwrLNGcxL4Xb8DRwpkYO3QbbkY3KT/MBMIM1EnoayC8TLLgF3NV8ZT1RHgkPIARal1QN+sPThI4TTcO6sDS+D/YblPEi2fEAYquxXNjHmFeXitfXmXDTwPfkELTTLrdOQw+mryF+YGT0fCQHwplpfBVUws+2UZsN7mOU7Vfg8KlJLj9WA7MItdjwdVuniY5BdYo3mDne2Zg9OYVLQg2BbnOLvb9ZM/r20whYo8WrFjyCjRl15JYXR5IaedQjL8Onwg8CXcF7fHov276HA/gHyJBTx3fgvGTl7hg73CsqljHsiNG0ALd3fhvx2IeuCtFr50JMgKV8XabAYdJ7aLjGSe4/14/LlplQ2qb5uL1e+P4Sv00upZmBGPexNDH9f60+kkl9vU70RPX7WTXr8ECcgewb0k+CupJofaCcSCWMQP9E6T4oZ81tHj/xBoLILGwK5iruouKdiahyr/N6OfIkHMqnuaqrIaN2034YNdy+Kc1h2Q874HZz0l0xu0fr5KZR+k4Eup2PKbfcxW4xmkEWZhK0P4soKDoZJ5pqcD9v7JZ8sN5/FM3HjznJ2F43WYOPLSXTs0UQOWpYSg/dz6Iro+A/YVvwDFbkhZkWIJ8fBJnF6mA3aUSLK6tp4ttjaC7FNnh1XBwXTVAzmdy8NpIhLFPmujyejea79yLwgXjMfoi8UavkZAjJUh6cicg5e0U1ogzhGA1V15QMB/Hpuyj+YIDtNYxgf29o7HtwCF+eCkW5juZUOwjBTj5FuCkWB/qxEvwuhmT0bbqCL2MrQZsNQHfu3FY+t8mxFvyUHPoIH+N/80rPbqocEwxle+sx7G6/lQvpEQH2lYOuXIIHjE1gC0DVjRraxY+7NTC+FRfFh7eQ9Zj5+BYs1p02bqeF8vf52m1E2GuwT18sfAQfj8nzKMcWsj99ile2ZHOT3W24IwN0Ww+uIlLU6Rhbs0pkv83HewPEYhW+/NVgQXoXeVF0avW4q0SCdiwaCmdbheDk5PU+dE/a3LPtQa3b0KoO2Mf7rk+kfcOE2ANZz0uep3Fz68IwzLFFfQ9bDbbOXwBox5njP88Hxy65xB75vMCr7uwqzwQ2ho04XHEUbI4oAOChz5idGg05x+dDFc89sPcGUGYnmTFB6qT6Gc0w8DtHo60l8X0YbmgerwRlM0IixfPxefzTvNKjXMclb0KdA7JgU+FEgX8UGKNaj+0as7BM1IFkJSVAJafmUxP/EeB2wLR3UwDQvTz8Vm4OGuLRLN4dwy0zt7L5RHlNONCFLZGGmHhEzGePV8T4uriaYXnQVYdFOXgvaOo7mo0Bd+OZqlVFXjv7xSYs6yPOpX14Jq3NpzZ1QBrzKr5tFYX60fIQVtMEMl1W1DJ0E483TAVQk6NgKiD9hgeMuR4dT18yNWcmr4ewXP9fTR+bzeezGyHcUYKsHWrNvw1/Eqq215QxYdt4CP4GkLV8nBJkys+3XgNTTzFIPN1GvpetIGOYTdo2MxmajYPIxfvYtJk5Kc7xTkzQpJk0Yf3qgfC/AIxqN02SK8qv4Lgn0DMuKQBJ6odQFZdmSJHDgcT8bfQ4VoH+44IwJkdorxiRxQGZeXw2DM+YK9njQfED+Ktf57YIH4Vn9YmwAtzQwhSbMCHhgZ8VvcGzlmRgfF5p2CYRSauzLiFknLj2Vr0AeDzYVAbpkCri0XYfZs0vW+cw8cC//DhMfp4IHmQDS878JSbSaSVOxIkZi8FXUsR/vJvJjrXB6K8fw66NZ7gJvUsvB+lS6FTrSBktgoYPc7EQ72rcYpGO2wpECLdQ1cxKX8R3NvxCYLO7IfZNX9QI8AGPqXk0Md2Fz7yOZ4O+HjQU882PNavRmGxUlz6QRgEdghh68Yx0BW3HZbOqwMnUSm8sOwNJd7UoCuGiWy5M47dVswlv7vzKWe3Fcz1ckeZDYFQfGk/GHyupKz1sznOSBPnpM+HzUM+eTd0F2yLNQXr+Nv4x24Y661YS38Kt+Bd7ub3C3X5dNogJr1yZsmi0zCzzBh+n1uKwTZjYItZPF7s9OKGcG/++9idDSulePt3C0b3D1ijogXB6YuoZ7QT9M6IoQPuCTi55iPZ7Crj7/OesXYQkk/KCL5xWQqaCs/gnj0rqPz4drxv2wLW3U5o772dZNK7QV7eHm+qpMI8HRm4vygYizwew1PfVfQ8MZS7DzWiV1AZH250wznnRsOyK8fpuqgGTNnnCA/T7uLYdZ+5oluTVF7J4sDmVbjjnD1u0hSjAzKieFVADL64duH1FdG0Yl4UWXyxhcqf5jzW9Ribmd3g38se0BLl+7T+1ESI7z/Ndz9K4+D0PdD6/hDa7IkA1aHcWkHHqSTTjZfPPI1lluMgau0gzlpxELOeJVOUgj7En1bm1H83WKzlImRv0icD91u468cYaJQnMpWqodMJE2Ca9xRYEX8S5hZnYZ+EBax+qc+JCRo4otgEApTrMLnCji8fayL15wPkpiJN0iZviH+p4YflBfg6OQmtUA1W18qjYMVnurzyLN3Xn837GjuJ+uYjHD9Fvun3yO2uHI9+KQb+Xzuw6u5DMBR0g3D5mVj0NBX2PFjHho93w5OWjThxqQvKOZvB550mJD7qDs3+WUZ/gqRxQ7Mxb7Wz4/4Mb5azkyAfT0M0LhsOu7Z8ZsOMezDqggtcyw4AN/nN8PpjN+uLd5CAZCtMa/3Im44JQbNbOu2obePBLS6QdrmPA2ZPBhXtFpqlLscDohUUZX8JuwdFoansN9+I8AAsaGHD7TNhekEwj9Ye2qm91TxujiuZPqwB15sAtuEXoKjoI3/5ehS3/fxM1v4jabH2CdgbspEmJGmQ34xuumIkDppzjNB+zyDX69xj88uacGb8FFYPuQUq7tZ09qQxO4h9pURNa9iOvyH4yVW+0rwAlmpp8ga5i/zUT4FNj1yn7y651J3fh5u0lUHtzEc8f+0yKdRd48+WVWQ5IxXkzsSA40xVvNR9g8ct9KWE9WJglZaKAudr0aejAq2q/GHv3A3QL+uOqaXFJHThDiT/FAOVP1ag4dQCSa/06e3rU2QjZI9/dpzEMxvb+H2sB3Tt+gotbxg05LUh3eEM1jjrQ5GhNZqnLiaZFXEc8PExHt/RRyHLncnf1YQLZ4uD990c9mn8zl01hbB5vywc+veDl3UEwX7RDNBbvpFOxuWB9ToFODFzFe5xHob7m61QqsEZqlyq6T8JH5p2vAsHlujRhYKDbCZPkKUax+/SgCpOpuCWfh9aPl4YV0yaR5c2G9B0ZRfMvDwdCj5oQcekEppjpUF3enezFn7m8ZJ/wc3pAnqOU8BRKY5okLgB25NHwL02Jeiym8MZaXEYlT8bM15O5bN52/HAj1f45Hg0cB7BWxeEPqlnQ1yz5MiMmVCjOYu3qWThrxo1fHf4GMgu6oEjdfNQyEMCxk86j7qj9NB2jgk0zm/jeM9PoHR+N5b6mdDT0f04P9cIr7RMhOMCh9l8WRgFH7lBtX6K6FmhhrLfP8LwZF0+NquFdyZ/RWMbUZAK2cl25nsw4fYoerC9GoLvhuC8LhOCdcJgwONoQ2wQvh6NUHw0E6uuJtBMXQfYfuoKT/YLxkFy5DF8EcviN4B1hgb5t04C0UmvcPMEF3QvaUdfOVtcsrKIIps38l6d+RDYY8n3zH+CmpsASJtLoLmwPYUHeeDP9J2UUxCCEdvucetVVxQq2EnTBRP4zRhBeJfC9CVlJ+vp2ODuRx9BsX4z2312YpOrRTj+6T3MtFzFmhcFQGaLLQR+66F3p/vZSvIbNq31IF2xnaQ6WhilEq+h1L8XsKd/IiRH6uNjFSEWNWvkEZF5sPV0AUw5Zo6znXL5+9yHyEfrcXkcwveMhXDKMJQ3dj/HlkhD/nogmB1qM2DB+Uy6Ot+SbP0O0jJDA0i0kqBwR2sK2VXC0q9m06+QRK4fawqZRsnkJf+W7+pp4vFKESgI+43L8vPQMdcRayvnY3HcQopelofeOzK5SPsaZitdI5M3CIdPv4DxC7/gDzlPbpysxUHWhZgZnQ/X9shyuUk3xzeUwaMCU1hcMxaut6ylESd68bVHOu6Y3sIh4xElI10heZoMF5s68a6jGpC23QAPXThP4TMUSVlrEb0KS6TnZ5RJY/UktD27gbKkk0guWhDy8uZha50X+wXuwavTxKhbrQXaDd8yGwrQm7QlNHySAEWEi8PFkseQlFxMD3+UgeIlBqF6NdxmHQF38p2gQVCCF6hH8qyhOzK8IUGThycQ+bRzakQqegyTZ7OTIXhZtwnXaTURXnCg0TO1YZKbPF9YvITNlzdg7mLAmKcVLGw8C10PDmLefkOKUPsMyYVKkCKVziaRJ6jGSpEjfh9Fh8FR5HVnDYV/yaf2om6kJ84ooKACS1NDoSxwE06OeQLRRhNZ7SjDtHvKGOA9kcobbcEur4Ij4ifDvLE1ePLCRVjW9RnkTldS/1U/9rzvCHV8Di/Vn4djNrLkpzMK9qa7UKO1Oyo8+U5/5zix482vlB12ngSeefBFNoRP8Z0Q9EQAnito8A+JPfT5cTAEevbRdfmF3FfURSdsl9JE+yDWrSjF/aaGEFcaT66+XvBgyHud0zeh1Gw/fvVwKacKH8K1RS9JfdZliNkgMsTGX3RaVgMkxjTgzVmH6HvwDV6p9o/DL0ykWRPLKXzIJ2SSJsOOm9/IqziSpR8F0b4nR2GkhyWn76+Gc9aEHYfl2P9DNFsfVYesHWo8MGkVzOA1WHbCFBZ+S2CLs69xkbwmrJrhy6LhK/jTWgGIb9lIBdtS8EJyNr1V+EjryiPQxMkAlNeaQJqVBj60ayHBM+qQ222I9fvqIbXiDNtt74C48UogrmLMy6Wu4cG0Gip6HU42mjpw1XgDF48R54V0D79n9MK8wiHuW4hgl2geZPjOo3ebXoGJ4Fhwde2irjsCvLz/KfBSe/aYLgoy6/bC1xOyeDMyDcKDN2B+zUhINB0JeRXiIGykQhrvy+mnqx81OcwHndRP3LnNjnufbwe3I4bgUnoatpo94JcdrmQ08iTeE67BK0frWb5IHFX//OZ34ypgdLIKPAz6S7mH39PYhBsw7KUQPBM8ilUullR9wpocrp4kt1QPMlMRBd/pC3GhRyBq1CbgnBwx9JoRBvcq3WH/DTea4mVDq7rWkXe4ChxZ4g/nm8OoubIddPzzYEd6AEscegUuMyMxetl0LiqMZPVIaTifqYnzop/A9541MG7pK64KfYoVN0uwLbWIXB/fxe0Rd0D0hjBE2rrgnzVPKMqsCaTT5+Ctw6tYyWI4mpn1441WSwxdO4mz1irDo2OteCI4BT5W7WYV/W8gFC3M7tbteGJdObzty8QjUhIwL0QA5q33oslD3fDRyzb6ufsSPFKcQBPW2lOLznIIcY3huabhrFVhA8uqz7CIdwf8yroLz/SdefUZZ9oaLgK3Zn3gxLcPOUlgD8adQPghos5BQ5rIzwNId3QNHoiNJCncA+Jb1fha7D+sfKbFYwNsQebrbeqWe04yrk6wykCXPA7P5evdY/CslBRpLWnAmf2dXHxMDy5djiCt7tUwos+NpLK8OGDFNHhhsIuuT/9MyW2v6fvnpxjjZw4/ugNIesdYvhnegCKr+2DY/RjaMT6D7GvL4Fv+AtR9tgtSnITgguYINJ88wI7TWsjyaRl9artFQa5OaDV5qGOMPYS18Vqw76UmbLlRj6qXRkBtch/crzJGd3k9+lK8Hu+Zl4C3vyLdsgrnP5v14G+1FrYuHICR0+YBOPRSqJ8AtHzfynPLwqDllBrWbH+I5tljQfl5JR1pK+GaJWlkvUKB+u9fAyX/YJqw8whKP3ZGt4yrdKCCwayxAS7IzsYJXeZwrD2bLAWYX++zhiqLRxCgPonWrb2LTcvUoWpiHNqNmEq7JKxolMpGnj3JG49cnE17JIXob/k7igybgN+0JeH4zcd0rH0G7DYeheqPp9DhpQu5YziwzIk57G0TQ5umq6Pd6sngY3sdi3s88fDVpTTucjVcvxcLu2o/46IeEzrjnoIa63pZ69dwiDjgw7+MLHFZTxavOiIEUQaA0y8r0N1T9pymNgXq9Nz5Vaw1hNy5iXcvL6cm5S5uGKbP3/Y9wBgvP4q0XYBWFsv4W5IhSjwfCS9/L6AHD1XxtsBp2NJ2guSOilFs7T/QEr4Gz1QyKNmvAVN3CIDajFKOsXUD9amdnKkhAneWxdMLWTPYIdpHtasbuPPIYhS7ZwEjzbxwU2TikLveB8Gkhax+VJ9V7E3A2X4dTHR+AvmQRceMdKF5zGe8JmBNdwS38j+HItz3KhU+yH7DjCOX4b+wJrQVnQSvcgHePpfnQJWZ9GxnDm9XNoA7v2/D1NRgmqL1CkfsPEeTvc+TtxrD0llb4KzPdJzy7xXc/rkRBJLSoU49ErXUQ6nuwht4LKBG9wONYWVzBh8/I89XtbeBoYMEFlgmcOaWblp1op0tpZxgsagidwzNOWh8F/2neRAW/9dBiUt+4LSdD5H6GZwnRpB9+FLueKaGyq+V4EudG0+a7QKj9t1is6XTaPnTAvJQjSOJnHxMy31FhiF+8O6LKdyMOcmx8YvB31GKrVefIm+59bgowJw+lxzEC7X6rPTGk17mExRYrsHSigfwLFiOZ9c24/6ya1j+3JF2xK4guQQtKrmwmnc060HnLDnQKs7FRTOPcal+O3hnzqPz9SoollJMJicMeFKtGT25KwvuqgPwYZw4HDdJ5S83/8GuX3J4ffwzeKX6Eh7rvyIp3y/0wEwWjq7R5BylKFzZKgxG677y+twtZLt8DzyK02Fz6xzI9n0BDmMs4OuTfzRlmAs1HL+BhoaaWLnSgj06JOjO2Ofs0DYeZMbL87jvBrDsoiMJTf8MLtKK7HPIDxJWfuTsZyv4g4EpaNl4U1HDBuyfrg1ZdfaoUv8d3571pjS/ftrk1kA6xj2UWTYBHoftwuyDuRRaOhpgnh1uHKPPYVUPeNnAJ1bcHkPXlJZjduhfrvojgT37LNnIVhM+75em8qudKLa5lu+ffsp2YVtg09MNdJ/m80xFRYjZV4vDzmjBbFlFypNRxa30GSZN0KH1jx8gN6+HYm9tlBH2AWWvtXDsjg70d3ayR4Y1bhfqxbMug9yAE7H+yHWkvAr6O9OaM52tSOq/CXC8wh/Trlthd8M2zl2mzqk6wjgr1ZSM5sey2e84rDCvYBmHYdC81pkU8kfSar9Cap5+lZT/u0OOImepOnwOxhZvo4XBz9AneSIoOG2nAzFh2HZJGUKaP8Cl5iCS+BjA31eGwUORAny3TgAPv5GGHXsNcf6gHpephPFYM2+wLBfCtPRBWG1vS5n643Hn8YtQuNUS/nN6gduj/fCxbwMY3U8GYetlNO5YM6+fsYdSm/7he18fDpSTAo3yEjzMx1FRsADjjQ7R8rDZKB41BRZK5+CMF0yHeQyO0JSHhAex2Fm4kTd8eAdYLg4Hkk6CrXcFd/81o1I1Hfia4gClPw1BbO4TxG9H4YLLZL6/fRoazxnNp9ILcUcM8bR7HlRtZI4PLIaB7s06LozSwbuWc1Chbjnqv9wDXYrNWDTyNtepqXPAjOOYNksYxjUH8Rr9DFD5qUUVi++w76nreFCnBAZTM9m9ej8JaTSQcpYBDHMTI8kx69Czr4tkLoewmcpCnLb5Ml6ZYM0HfIRAOzcQNOImgPGZXzxy2xwQf34OrvbvJhWJ3/B5z3eOjt4F66ACY2pksMjHGpxrj8G0zCCi07Vw7twHTL/Xwp5B4RSsJQlBrkBp/+TQ8IsFyF61QrHSazBP0h+muNyAtCFPSaoaDRLeAWixjkHv92fK3DIRIoQW8XwdNVpw0hRCCpuhPHATNfYO8gHjOVR5QRvuj/xJrvukYOSdQp59QJ3eF+mxXN979rJfiv0FW/DJqCDY9OsgTx0JWCIoDTpD7/1aUgu2FdJYeWkjT1eqok8Bw0HiWjOYPFyFUzffBEE3a4i46Uy+LhmQfTOYOsL34q19l7n6QBj/l/YaC20ALcyvgFqCDSTLVLButgCGRWfifP0q2uxZhKrfr4KWbS1u+vEeryX1glS7LswUHQVxiZ5QtjkCyuP6cdnxHM7+q8EXKhdzRet4TNWthsPKSuCbeRk17qpC0GsHMjM9xyMiGnnu9i0wpy6SHb/r8eZmMXxRYQtxx8x5qspv0Pn3j5Mqfah94V8yKk2Hw9p1VFC0F/lsAGw4JQ1BR3+T5t0K/rHyFTpKHoEfMXbYIjMCIyQTcZ+rOibM8mdrSVl4f7OSyzMEOOFjG055cZJWp3yA3fuP476DAnD0cjILNLtyyThZkBNuJ4m1LzFL+A9e6MtFxxMn0GfVW578xoU0Tkhwq5Eej5VRhUXluWjUcYsdRh5lSThDKn+CSTD1O6evt+TnN3JJ9fNIpO1yIPdmKiRH3ecpEYH0UNqQnFxWQWGaB44YqOdtVS/YZeYazHylCnJBBSQDamQQv5Qv+F9l6dMRdE8jmg/3GsO3A5F0RsMYbIRE4ekeBboUlIZWJzNomdtU1ne0gLFyo3nKrCpU+bMAxvUv5KxnJhC5Zy+vP+bFNpdi6XfiJlgjvIgzrJ5RqfQjMI36QkdkbWnB7/EQrPoe5fTXwdavztDc/xlMDu6kF+KH0LBsMwYtfknvSl7jhB5LkF2rSicytNm5dx2XL1EDs7WTyPNqLFyZUotujX/pnooWfY2QgvDQHrDZ3YFr979jk1o7yi5M58rDw2mvoBhceHwUN92VYPsefRi2bSY8nNWHrhUtrPTPhfK106FA5gX33Q2H8JRj/GfUbIrfYACF9R+oeqc8bc5ewhFXxVFv7C78GDkay0POAXRu554PofDimBVM2XuFx19JYpsyLZ7b9h035zny/TmlpO40B+cPy+Z1ORp89y9A2g/gNUce09MCF1RWGY0Hvz5lhXce6P09ETpureG4gOk0yscI3jtG8r3uk6BkFsYL/qsA1LoED2794B8FediZPx8jKrNZRUcKzrf409vNqXinyZVVQtR4pX0DfVgxnspti3GzvB31H1IGPmUMsTxIZxc6wB754zil3hcCHyRgWJgjWny24Pn/nYUzInmQnigDPycb4bqt78hUvI7mhKTy7mMhLPHtMI0oL4PEcQtxrksw2rUrg47IdN4VYojqfz+CqG0F9skJ4RfTULiv/Zt/7nAjv3PzSKVnLFyrn0aaLfbk8U6IjsYvYOO5tfRjQwHkuDyGiuhQSFrVibG/RGDvznGkeluYNXI/wdx1NnjaeynlDIwGq4A2yN9lw3Jlc1hrJ8MYdRXONd4E/oIvSUH2LAWV7SdBU1Foe2BFTROroGjWWu4WlITb+57iyXFxuPKOIv0JfcqbaqV4Wr83BkzJQDWRPPIrLOXYXkv4afYP1Z1uMXxHzok0xjH5bjB15wOoWLaJjA/MwO9OG3DLHCt4VyFKs5fb8g0PDc4L3ohLFouAxPGn6HFUgKuKIuH9ugoOdRWBkv52nrFqPdV5e8HngOU4qmgLHcy/jU8q/uGXvcc5Z1o61VkABGzx56KDO1l5bxfS2eOUrBTDZuHP6XWoL9hrbcZu63NcvcAIGhuWwjlPB5ReE0KtHvIUrZMIWnu24CR/N4pMfEvSwl60ymsyZI1q5dtrP+KD5zmwX7eRr8RU0YaJWbzwiA2I/7hHgxO3sIOmENRZpMOPf8/B+uYCCsfpdNE1FEYbavGpoO14QN0VtX7I8bvT4+FLkzX2Wc9lof4cTKTL5J1nw/MyA9D3rDstcSmCf/n7IeE7gRfWUFONKpp5lsI6mVccbJ/Fq7cRXC2dzztF5VlrSx0NVBlAmFQmqR9QR49/nvj2wCfI29LI/e4ScCB+GsStEcfl3yz5dLEE5DZdRpNPErBlsQyveC2M3spiGGv3DuMeZFHqtkA+ne8MY4Yyx73/FAt9aQVJ+2CWvPCSjCMTcHfSWTro5YrJ05dhjOUt/teiByte2tBE4UjQybzOtY9+wouKZ+R3wpLktb3gydGzcKc0lz5ZS0LcRWu6f+c1dEwJ4b9xVai0yJmNFjyBjWOSsdezhNZF7eQHh7SgN7WRowby8PHERlybEUsqzttJ+EMD3fdOR3g/idZvLMczDUPz6z8MYz7J0/LWMVDTg9DbG8n6ce/Jz3kVC382pX9q5bggRwSE/PdRyPxseLstH/PPT6D7sxKxfNYZ3LFmB4Y1KrLZIm1evU8amoMPcl9TAK0MsaOMf7G8PW4lCn6u4+QjLXzm/G80G3pr4DkFSPnmjF221aCZgyRa4gjazyrp9Gwn9D6+kFenX4DyzYu5e5kVNDybB4t1jTBMWhX2rwEW//ObalszSbhJAOtvDOCNXW8o4RzBhy3z+Eq4FDTrl8KCYgneVuIERVob+K9QLAr8C2CNeEkYqScGdhss4MtPA7i3+zUdjp3DdV8N8JfeOXj64wX5DHPj0H/1ONVfBbq+HcP/blrC6MXJPEb8O7VeLGc98x56XyWIJQ+n4sWvpvzwgQacGHuUlJeHc0JCBMsIGdE7iXqYJnYfur8WsNoWPZD+fgYyIvThYpMem56KwcUZ5/ldtDD77xvkwlFfacbACzrSqYs/tV+y0CEROL1nOXzaU4ApW8Xo+J31vK6xgCbuv8cKrd1omyjCPxY2UUyMJXQcauRakdFc6m4EAqoroP5oBL86tR9+0F7QOSCD8pXdtF1GCJo3d2JV7T44vHcuJdZvA5zynMecbIUZ5VZka/Geo5+Pg4KAkSDWn8gRs9fizsVW1KyugUGhiXixzpfyzW5S6JdUjlk7nZZcMYapN4zYV+4uz3ZfDWlrLsOl7XI08GwXhjib4ZiybTDYdwOO3x8GKyb8YM+royhNNZWW+n1GvexgOqxDaOhuQn4eJZSbr4f6QwXqtvxTFJ7+C6Ut3cH/TCqVfCilvFPPoW3tYZZ2eAirt1+B5jBRUJEX5dF3zHD1hy4qzZPDJdViHHpOC0dZb+RHyXOwzfIwKG/Sh2emPiyivQ2lDvnCydMKOPWdISSN/AFSTwa4vDwVW84l8PWtulBsvxNf/u6gSioHqSOtoP9HHG6vSiKvqaPpfTVjsexf3KIgA5O9WmGaTy60vOun8JkvUffoaZJ5dJb7y82hdGwMdqfqoq/+RPAdpsvdmrMgJncqPzonxCDlxAvM2qlxSi3sX6ECXi73aGyBNFwe58anPt7kaZ4ecEdkCdQ+2Q02gitYZkQnP0Rf3ndjD56uUgSXHZ4s33UMv36zgEgdcygRn0++Ii6QOVaSoz0l4GK1OgxbLwdpvi34pP0trdwyhh0yJ4Fm21QuWzQJpix6RyduJFCvmDMoz1WE1n47jqz3Jd2ni6Flawc3BVVgcpYm7guvx1MqH7GuoRfeLhME1TBJdhQohN4MXYqV/ojtVaX0UDcTY0Z/x6sX/8OL2a94YKYk3PmkTNWSzmDU9AifPD1MS/skQOhxPpdrpOPBMVX46co6+G++DMhYBNLFB1f4cs13Lvg0HIcdXQ5jfZ6B5U5HEit4wVkTf4DBWRsIfrWClXytadiLPXTtyV967pxEs0MMsGDnKehoncr5l/IpKccURM1NccWdD7Bp+QporqniY55JeP0/G5Trj4QRW+v48uElODpWCdxcamFJ5RnYcH4sXhr8C+9/RbPT2xgabVfFibvXs1qOIojbmoGRB0HbczP8IjAV2vp7ODfeG2xeCdKK1EAMM95L/bWXee4VgPaqRRxbd5sS/zWS45IoCnx+n7RaNvHjA/vw/bk9VHokHZ07FWBdVxYsWXKWV97vRL30A1CwSoXsjn3ica6W0LmnENc6J6DicgSV3r9YtEGKn3sZ4nj6zed/JaP71zl0veYefTwykq7lrQfTqsmwuesEivuKQJzbdYZvSbh681UUbNhMuzxusVp0LD0bPZw2W2vBJOMVfP2mIbSddueP8cr4rsABRsYeYkfXDRAcnY2PzW/hrys24GP+DTzHjICA/O9cOEKRxip1sExeCHs/sqI/HxBvParFn+8nQuHFNh6QnMMBg+pwZp0Y3E+exI7qbXD6UC84Xp1PwwcM+IiQAfgoTYdW71j0fpZAFioGLHnCHGIG9vH+tA7qmT2I7VvfU3WvPIxzteFjlRvx8ueP5DlGnI88NOSM9BM0qtUO24eHQM1hFdD8MwyGRylBves+Ct+yCLIcxrNFTwTXbRtB71Py6NDCMF7aewt2FowCtfZVBBues/2k//jDxD7Y9q+YfCN/oaxaN+R+UuCZ86zoaKkMmPus5XdSlfRi/FVc2bCK323vpL9TevHq42Gk6nCPfg7MArsCTdCQcoAIYQJVhYm8cFAfbcPngNC9OwRCOlCnMAenPfOn9bdNQH+4Ia7c+BA3DmVc7C4tvFvoABuDj/BK60AYdWcYBo1eiHdsNcBIZDPv1B7DB3tvs5PpLZpsE8ZlKf/w5Lz/OG57PTyoc0RN/7GgsWsPSn4uhkLjn/wp5xz4FLyinSGZbCvQTseuDFBZ4V8akasAl4qlGA3bSbbrCO648JJ3C53E4o0fwd5BlbYenw+TX0jzzuJRMLbJEh07H7Neey0dlSkjkL3L/00fA+t3PYc7Pc3gMX0Ur9k1HiJcWgCNx7NO/ENKy3Khq9Pi+Rjr4lErYpHAUF5y/jafRnkYXHMNm4YdwnwpAz7IUZBwQhAD+8TRxUYQZ73ygBJdC059YAsTakpg3asW1uvcxUbK9/Cx50p4tjcPn8tYk1SfBTq7q2HNISHQzXXGCrl40HR+CIYe/3BhoRNvDMjEH6mH+W/aK14dtht9bquB19+zcM3eCtZ0ZdAb/EESmhMocI0ydGXZ0WjRn6C/7QReV50Mvsdc2cCzEOsqSun3fle6cPADXuqdDdXjN3ODtx/U/Z7KD5OtYbibPYZGbaYHN25x0GZD+vN+I/6IMuLwU6d4+KJ6DFHZQ3HPxkDrBUGYkG9Op0f0smD1XLhUtQU/vJnHNj4fycZvDcP+YDR1sIQbEkc52T8c9jglQsLFApRVng6/T68BraBknGLtgbdxO/taG8EpV3MwcNSD397SQzNyZF/9y2AWdh2v35wHViwC4/NNIPTMGBjpupI2vfwEEi+WU1vbRQq7dJhH5DOfHX+di4/2c793KNs8NoH20bOw68Jd+lFqBYvyxbHMYBSlnr+BZeczQKokitSlh3qnjTJINomht8hs/DBCn4PWRNPMjbPoYfJjNjSfxt1LAtEkTgYbVIb49k0RnllMBzOj+7huri0kJ9eg5hchvPvhCS1zTQFc95d/mVtBe8w7pqhArFv2nWN/ejEYSJHosTlcql7K9XVuWLrYGtIGzWDKO3fUW5WCSwaK6eP0TvqnHA01temc0HgOSpKycV/HF5zsNw4G8h/hprUzaXSrI28PaGCJ5mUsZhlBTyfY06MfJTzK/xLMDh8NosfToE38O4bKJeMju0P0n8Z/2GS1lQSn+MKmi8vhYHQEtN7QAsmzFnhf+iPfPO0H4Rm3SXHjD5h+7iP1DEqQ5NVx8CaxhJS/GoGWiTZn//ea4vT0STqqlx+Y22FgxTgaNqkF7i+7DhkYzDeipeGX9VKuOplHRqZP+LnFFMJuL4r0K4XF087gWqVpfP1SAhkdM4XZTyug6cE3rozto8nyBmxiNAb2OX7iaSnpoP3fH8z6kQaL96rDm+xmUum8wlfboikoqAiNHyzhUy4jodDxJEV2mnPH+hpct0MTYkIbqXzTLcJZS0EwZzlO8ZuKtTKlNDj9Jt0OzQHd7DZITxsO+6ufQXPDBcxRjEKrPA2UrhLhlbH/6PXABh5fsR66z76HqBwZKJMfhgUiriR+ZiEP4xYOu7MNM1OB9EK+oeWZ1azi/peaVmpDy6PnWNimhN4qyvhj/QeecmYxJvTsxDv7Oonf9UNP227UfmwLkRuOsZLAUU440s1LajvYPXkZagr08MzICFi1yQm85Nei9Bk1+KyyG6rVAiB4yxn42XMKFYIb4JGHBgkuH7rfJkvadjoavC4bws832bxEVYlONY6A1Vqq8Fyknxd6CbGz9Q6IL3YjuaYDLH9tAvx5eA2EXNZQ7rWzUNf7kqbMzCeF02uhpuMsze6WgJErfFD2xQjQ9h2aVVcgjknJ4As2t9laN5Wad0pj2vdCvnbzEGS1T4dPz5SgzNsN+3YPYumh+bCgyQluaWpiir8iZFtOp/QbyF2pB7D26GR4kVSO/9U/wj5FRTRqiON7UnL840oz6n7I4+fTu9hH8xdH+U6A3PfqqHzKlzRmpGOCUToIn2+Bhr5sWmE8n/OCXvHlkhSs054AQlo3OTPxO5sXmVKc2gYsTPyBS7T3o93orxhZbst9fx7CpMOSINa9jc73lcHI0xowtsSOp1urQuU5A+jNuQSL49eQyL1I/u0qCBYf9GDCjKGufXMfVivmsEPAcZ6avpQPdWaDqkY9au7+D6+pasDLC2sx7elBsE6uw8PDA6kw4Bf8Lp/LNyz3oljSayy99ZyqmibCocoUuLTPGZ8UhlKO6Q9+FlUGMZPHULf5cQi+YUBbJv1lP9PR8GBsPge/Ow2TKiI4Lk4PlrhHQ9h7CZzbep0OZazlcT8EIOeRDdQcUSBF0Vq4drKG7+SGo3DealK5FAzXH4yizjp/3Cp5BG6WqcP6+bPAf6ED1zjOBAuTiSB5PpGEg0Noy+J4mBj4BBrXzOR5c03h24oy+NerjJ+0RGjFkl6++LWEMsSvQaz3exwUeIIeVi8x8IEiPK/Yihnhjjhywnc6tuAkTNrejiMvhFGVw0/u+/ofXp0xjV6Uq8F+JWKNsEiI/HubUvrkUUDkP/7ifonvqJuRTKMF6muW0dWk8SCxsBLdA2JQVHUNlYfeBNd5TiAX+oECb+AQMzPp1gmm49OE4NGtNNy2/itPdVnJBqvcQWTiUri7KIA9An/Bd+eF8KinGjIDrcGy7RQ8Lt6FRU+r4bz1Ofj2gMEFbkNC+0iQGdBEAboBL/SV4E5kO7f4+NG1Z4exTfE2lfhmwHlxdzQofQOyKpJk/Pwn3FpoBAsFHXhNwnVWbr6Df7/dw6jIS1zbsoHHZryCmVNuY33WKFaZKgfl5lPxZUkTb6kL5jbnof1oamGlQhuUz/SGBPG7tG9YAErpGIC0iCV+/uPKj2800qg9L9jUSBFy37bR3JrDVFSQye0+stToqAYQH8A9C4/hsaXaUJv1EFWLfChopwEctHpD1baT2SnGB8ocdWDOQkdK3P2Nlao1OGaYIQwsWkpLg3RokXUWl+9poEVaq/BulwV4bSii6v4MTDXWxZMtmpjcmETDKo0xGKfA3L1xeE1GkfPDTf9v//9NOm5Lf4SdePLfKB5z1pPHXFIH8WkEorUz4fuVYtTMHqBHTiPgVmQLRkitpQaFreS1Rg1qxk7Gg4ECXBu8BHrLKyHejwhEhsMUubcUrNqIjpt7oLGjgw49OAAfTabjqoIfaHHLB3dvXUnRWyzBT7cDNr4+DmqvzlH5nQc477gSuVuu4tbMvyT35y30JDOt/y4B3+8pQZq9G4+XOADdV11B7+o1WhJE3BchjZuebcBvm1L4eqwijFg3h9rd48B78k2Svh6Gbq16/HZZHRhfskFZ2zc0TigcbKpF4deOM5A+cJ8NTluiy5tuNE6QpTE3JXBJgS78fiVKq/WvcqyIFmw/ZUyPVbNp3+0uTIhWpku+FWD8yw+zT9zBHqdWVqzOZ9EDE+FN5gwQPuYAZR123NFkQ6/XXKENv0fx+Q8/aMFme0h6NuSYk0dDsK4JSxT/wB9VMvxmaEdfrKij64/voMQvU5g0+iCZPTmNK7rHw7oJe+DtZBEyzrXnlxuXglrkcn43ZgBu3+6G6dmauKx1CU6TFoHho0zhgP4IkPdpwO2NdSj95DOvXT4DhJQXs7ZZLmuEbGT/J6KwZEY+HRkmQhljw7B+xUbYGzCfy7+vZ9Pq5xDaMYFlFYvYzVEZRKcuow6/Ek78foz9W05z+rgAWjS8nA8vcOW8jYdpy/y3tHi5HGzRNIZH4sGY9fIOv78XyHF/dqDXjvH0IriW7q/dyX8ar8HCSmMorh/AU4qXuaXDlIvtzkPekC857FiDe0zHkGLIc85LmUiylnKQXW3DE4c50avDb+HuT0leOeowfDd6AJJqfXjqSSB5LMjFU9kyYH9oMj2fXw9r7jCP23wBXtTGknjOA0y7XAqrpQbxxigb8lUwAjltBV7d4kMCSf2Uv+QML1rgDz7DR8OXP08pvtIOKopMUW+JJKzWlMMksoWJSYdJOXc+HDscA1OczPmyYwK7H9HDo2nm/GXlKJj5xp/+mz1INqu88MVua5a+0AedXzro2fhz6DvbBhrn7sUX5QbwZV8zHBfxhaWbf5C2ygPWlPfEMX1PqUawCBM/HgH9xDhOitCGW5XyUOU4HWafr6b+sRPx7q0UmJwiTJ6Dl+Bh4Uh0nBfFUoEmECyjSpq9cXgosYdWRtmCk6cFpr+ro9DqLSyoyyBwOR0cDZVgjc4H7LTfDqvjHvPFh/+wZmkvyK6VhAsvy3HjU09I3LWILDdbQ1H2QsoNluVTnRfpz6u/IOVlA4EzNWAwcBG3ZAjQFdlcXLxmiHsR0mSd1U3vJ1+juoJP1J+zHme/9htytx3Qbx2A8bmfaVaACqxUjOKtk64CWc2AkhkDMMHgGalfWUddRndwZKk2pydrYfgfYXhWPx52TAuHI5sq+e6jJjapnE5Nm2Ih9GYlvOjfDHb29dy/WR/s9h5nM0lZTHJ+Tqbie6FUNpbFZURRIrYZlu+dyNYGthBzawJk5n1kjfheUvFqwL4XzhxTuBqDjr/mTWElOFpHDb0PbOAyAT2IszWnX4X3YODUE2iZdxk2HFmCq9tu0Ryfbbz5pBLunrgSBb/YQm9RCdatn4iCSjOQm0V5/1ZduuniiQ51Z3iuYRbvrldBEzlFeGpTTON1J0BLlxQ2f3+CCpo6NEOrjk80f4EVU5Vp2CIhitJWgslhjZw5TgPm572Cq3NTYGCXD/oolXKAvC9E2p/C61H+3NqjDLv9ill25i9aZutG827fRIGu+VB1RBesAwvgZ+FOfPDABhbHCkJPpjRlGoZSdPUrqrgiQB5PB0mv7ApFVr7jlXc8MNFDiMNkR4H9cm9aJedFky9t4H5NO5hZNpVTN2rB3rHm5LT6MvQ2bKd0AxlYJTccEx26cde9YNg4ZSlZBXlhXnYQn9ezhOtHJXB6RAfE2VmBv3EYX1NdR7v3LoS1qwvQbc0CeFrRjFu7bGhrVC8mbE8A922mcCoqhAaUx/COtf1cvd6c19alQm7Q9qE8nIQFfvlcn3CQx74ZD/GeZ+Ho9i4KkGihTtPtXF0TBkICfah07Rt93TeSNz3qQq03qvBTZzyMPaIFS0YOwp88pqDA3/w62Jb8jO9ATJow7khr5ZxjYrAeENROltO+WRvpZ/UgNaYEoembZVgq/xZfSE7lziu/qK9VALImJJObxX38MM+bXUUvwpj9s2lT9RVO1R7PL+Qcqe6oG6xfpAFlY8bzIu83rHTyL7RskMWqc5X058AGeF12nPqex8PFY6fhnKoIlPbOo8NxCWS77x++i7qIMiGScKt9JgdmVJBviioN5i2AM2qj4dPOyTT7wH5I6o3hs32rcW6LJMrHt8IXk3NskHuf6qPmkf0uPfjQl4DFj5rgxztXev1nGX9xSIOfq59y14ZOsu6bwgPV3lDZZQw3kmu4T2EmHd1bQcMaW3hjYh4riHniZI0geKJ4j+dcn4NTjlnDU9frFPN5JB1Iu8Bxf2sovqYdR83+jGcWNYHA9bGQWCLIFdtMIH/aWhw5bSF9+bmM3zyyB8Ej08CsI5Reft9CPaajUM7lJG8bLwe1Pz6y6RF3hvRgTu9ZiClXiJysJlKd8HxcNawbsw1T8N05NdCf34NdB8Uhs+UwHgxWQHOTa5jSfo9tq7fxzdsX8L/lq7khShN0noXAjuoPJL/LHo496oQ7N2O4Y1wHVqd2QtXTHspR+8FWQvrwxKUMKyurOcrtOP6MC6E9lVrYEm/Bl5Z84sG70vw4cjnGfxwGL5sGaelqM3JYNQOdKoQh+x5wh2knVt1vpAXi/qgbWs5V3QwWCvOxx/0AW75KJ1ssQsXfvXxpfQxcHmLT7ooDbPbsC3odtR4qRP1U298HoUuP4hoxHe47cZiUSibAm5Ny2LF0Jl3u38pLfgPIrnbC+NHAO+6589vPYmiVvx8aDW5wjvhvFl4/gU3aa+Cb5GRYoxfEUw5FkbRmBunv3MMK5TNo7C0fmPIolZarPqagb8rw7aM5/Ev0RLHyCuyxsMEP7q18efc5zumwh+aSX7zi3iDKSrnDQ9AbyusBhptdEJ+8h3X8D0Pehh206KQ5JAcPZctsH1764jrm7hCBp8btUD6rAtW+ePOnBlWs3bAORN61Yb9GBk6fYA0dbh+4o1QdJrSlwTw9cZKrCEKhlOF4sX0y7n5eyNonm7m2uBRGjhsOXVLDYL/LPbgybQ3MfCgPfOYYrn63E3P+KIOk0DKqPlCFZSlEoqAEo//HcHlHA/VAcfwOI9KyEjILkZGRlZVkpjJLWkpIPxLSkFIJhRSSNoWWkUilSYsUSqFUVCqFNtHw8+8755537n3v3u/n8+sWCu+4hx7PV+D4s2qUHDtAM8cR58rpgXvlbN4xtQ/0CzTg2fW9ZHbpASwf4p3lgn3kvKIYjf5u4Z/22ymiJIoraBeZzJsIlj9TOFzcECV/+nML27HZbV16IB/L0WNU+NqVUFgfqonD40bA/k4p+v3dm+eaNuDwgQx2i36LKSnbyezaL9q4JZ7Obd+Monq6cGbfCxy8NI6lQuVgf9VNSksVRA2/atKsn0UPzhXBO7HHZDBMAXrKrkLB/OV099prvL+4AF77ZLP1g8uQOrcGFlvnsGnlff6hLAGrMlLZQeMfFO82gaS6MSTlPYtbC6oxpGEVjJuvw2jdgJ4hElDsfgfri12he04wfBVPgmuXgrk3WB7CNirQEXNLOrt8OGSojoHhXpm0U70dtVQMIcY5ALZ7yGLW81bWcBRGRxxDwRuWgt4pgMvt9+nS/tk0z7+dWyp/w9dYOVx4vY81+Awapztjw/YqOGauAn8VlvK6J09hd/MuulrjhEfUx9D5KkfgJ96cfcyI269YUVmjEgQeScITupPoTBZhq+o3kJ90hs2mC3P8M3c41VJOMzJm0BV/CQjO+g8POGpBtOpfsrOchCI+Q/9Mzkn6e7ma6boSNMyN52lnxOHhAQVOPKlLWo9recXZGyDzaDJca5qDFXPS0WtkEbwfkMHtj6ZCfOhyysDnXJhcRVZ+1miwBGipXxe+dx2O0cNtQNtjInm/EgXb25+59s1MErfZz5arUviG0HiIFJan89eCYNVGVdS6d5YmzjeA6Y4PuThjNPqvvMVHzF3AVy0ZNYx6CL5ns8BnX/xb5UyJYjpw4oQoBY0dwcOnNOLtrYZgMuM/bjhjzd27r7PgxcM48b81dPWZBUzpXsZ+0gcp5qsGD1TG4o6Li7ApfSttPwlcaqZCo9RUKCCQQTguiZN610Hl5VK8/D0UcnTv0/jx+2HttNlou0ifnvwpRVcFK6j/7MV3Cl9RtVEwVcgN0uDva3xwizhNnOnFsm8X8hRNTVw6EuDul3z80XGFxV+NgqNZRyBbciz/J/ierhVVonusCYcIfIGML8Kw6elTqAxRxgd1ahCxugvrbl8jj/RdaHJ4JPY1nUNh4Xyo+QTw37BW+Kq4j0dt3sk+686zRMNGfPhwCR8SjaVfQpcoOEwSn94Rh5TO27xp1Ed+//wLdretwbtZcRj2ZR8FmKzApy2y8PxINZkkWoC2BIJsaxbajx8OYspG6NB5Bk62xoFs5h7696weC75PoqBaSdAdyKPP6u/Zy8UXqjv9eE6fOsb37sLGNQ3kPS6UBpvaKeD7NFC7MI0Ca1Ow/LcoBxl1gd2K9xApMIZ5YxEYGr+E7sFalE+aCq5bDKB250bui9tLpjtyweVdIoVfTuCVCzuh+tJRzFj+lhRbDOG6wGKeZ1NIL9QF0bNnGenWGtDt5A7WWODOv0bIwpSD1RjUNRk27w7lbTavebP0ZL4lrog1ZhngnefKSQnz4fg2V+qq8aQH2qPhVaMuJpvcBukqTd4ldwYCzjzH9g/dcPucJprOucllxQcp014S9i+xxt8bDWHm6wqIKxek8VkWNMZ0JHpkOuEI3xCMvrGL7q0bD65D3GXw+S5355iTyMhYPPd4Biz8d4zPx37jyQFOnKUxit7UToPOTA1OgEbw/5nMn5sHKcB5BNrZ3OeFar+5/DZCWHAZPsofASkPRelv6XrqDYzmwwWxHGZ8AKITglFA9hNK63yAaT3rSGO1APTnH8XdecOxWDCIz5aH0/2afOzdFEKDUzajpKM8tTU8xL8DOnC0XBsrTrwF4RxdiHtYg7prXiI5S/LJiMm8vCScHZt68Xy/FSzYosbXE4u4r2AiFQgEU4FoHusfd4ZUByv8qH6dz0dqoqTcSLgbPA+e1CaS+NFDcNTvE6asauMwg0Oc9WErah/5jbmzD0ByuwLoZ77AyF4TXn1SDxL03+Ac2TugsG433kv+BkEP4qG8lfHON1U44C2Hd4tO4Zi+YXizuYd+HMlgv+I2ULyrwB/r1/GwhBcYrmwJvrIFFCqeS6UbU1DHZyu/f7QVx00dza11efSr/DMtmylDX06qQJNNGnw2LWIfQXv6NaIHlkXo0a96x6G7t4t/PziFdf4qtCHUAIp/6/K0jyUgarYGc4cL8uh7T3jRNG+yWS5D1Q1LaLHKafCOnAKqIXVwS3s7ya7R57JpxfBNsJHlxniSUdRD9Iq/R9uEbvIcpUmwx7mZr3R3QqWmKDm2VPO04y6gmFoIZndCyNK8mOyFrShCUBUWZFrzucta2HpVm6rv/ISF97MxZlUlxEovh/dzA8Ay4D/uE9EHBamVrNZcQHt3psJePS+u2G8L1nnq9PrjAay/fYW+eCwi18NqkDohmNNkork6RhDm+cbDoU57PCLsxv3gAqWXEtji93+8IGQqNH0w4VDfs7TJaxDs0hby99WxeNP9O8clLGTXoFPsvi0WY0NlIGHEYhi5bQCX1htB8XtD3jbLFofVvaf6rkPY9nQO3/v4EgzFRkG96mdKtjABz7Y4lNWajOenI2Y/riC5rPkc0TcI+gIlZOasBrFKDnhvsQLZfrpEkz3XceK6ajx0ZoBqe91o5Pij0PnwP7a4rQKFdX/RxWsc992ciAN2wvju6D9+f8IX3GunoWTEFBKZmoC3j4qA2p0DnJDE/NlmMasd06W5rm3w6MQgz9wZAUdetNDgyGxc4WMCF/X8UWTlQf6y7h+Mfu6PTyvNOGtKOcokJtNSYRVYe1cOo4XMoXq2Peoob8CfMBX1Hp1C3SZlvtX4G+5eKIKHX1vYe9EVXKCuB9Em1rzGQYM+KimC7zB7yh51jT5qX4FpY2WhQ+wWmo/2A9mQEaA2S4J1cw/h2ac3+E9bE5pvF4Hmng/o9lwNWwvS6OuIFvhlrAwRlVqo4zwL3QO8eNQpXXQoDubRrqPp3KR8GLBfRJtnlMKTZAEQGWYJZ5ydcbd0H5r0L6d2/2LcOmk75t7M5eqTkfhh/SyIPicL1/SSsWiEI3ovEkRFqmabxetJN7KfN0y6Tg2DK6ll9SO0rpADc8vzaLC+nU+oOPHIpHsgKDuWk1TCMUvDAX9lOMKpEdLwRHY8vPZqxPxPH7DziCyJX35Ht431uUFmCb9IzSMMEuMtTuNg6plJ4Oh6EJNro6jr8woo8cmjddY7qXmIq/4tGMu7Ug7BeUV1Pv5nMgy/sRC+dXSg67xe+l2gC17Vs0lh21a2XzGFj/ww5cO3QkheWh4mNdrQf9eTWX+UMjZLBVL5SwYBiblYWp1ET/KDoOyFAB4TU4Ypdd9ZvHwPpmxp4P614nAsQpa/jHEFNa1xeONaOsUva4NbW6wgRNGVJz1Xp8K207x8WjQJ6E/Gq9/L4PwkUwqi5+hZuxOelOrBz9hI8hcwgQdr8vhI+nw+qyFMn9LHs8W6GoozPE2PPNbjRVN1iHrtz7GLbvLKg4IseW8oE8cq8dfAy5T9vZvbTvfhosHZVHFnPFi3mrK1pz1tFL/JhVFdkOefgzZhyRi1zJGrZU3YY8oNsLloCWsLJNixo5M2LPaBtAOmMOpbHezMDuW6TEOOfusIPh9GkEPoGCifGsRmzxNwVPE2DD9RRifaj6B01QuOKhoP4xwlMfKLIsxuGglXm8x5XvE4ePVRnPeUZVPjzlJMdXPlCyoF4LJfhNKGPF56ymRoo0e0RvkNBWar45ML//BlnipX+lqw2Fwz1m0QIviQD7BCD6zDg+DV7HrQHcqpuPAH9Ma+mbV2xlDgdHeA4ufoYiHCwsMFoD13J71fsAYChYZjiLsq7ytqxpXG4dghup1KL3jQOe8tEBYKILnOErqyt7B+/AT89CkAJK+v5ElGQtRb/IGU5TrxqNouyJpuBIF3Y3j++W7oWTWAMyvbyeDbTDif1orKzR9J4EUtFPzQ5vLFxvBLZjl/TzqPFwLLUedwGeTKReDYn2oYOL0R0sJfwxalTNb104Xr83az1ZIEFl/shDeXTKGFjysRNL9iTfhGWDAwmiPXtsHShzIwecjnVv0Nw8Gp9zlSeQOsCgzgy+IDpDhUY9kVz08V7uL0mCE+3TMAFzb8Zg3/DJLTKWPXtod8sHQbLlV8BVv2SMOwyFKIdxIA993zQG25KOZH3aKCoEtUsb6ZDSJa+Nm8mxioXo828idpZYA+2DxYzz1iryGpcwcWxg3NoVMI1u82ZZkT3mA9x4tXC1TCNQcxuHrpC4hZVeDujh9wblY6bTfN5rmzt+LT9s+o7zIZv8+bz7M2moPQnhiQvIFQv0iFXNL6+WpHHdodvALuqq8paYk6zKz9gZrjJsBLXQl+nyTB5KPE96cdpTHvy3HOjRRK2e4OB1uGbnNTOA0mT4Bj5S3saSsIOx7JYoLDEn70bzrbfw7H0HctpOyrw5cyRTDUSg9quy3gfPBnXvOriqZfLuYZea0gpb8cQmbW44SWHJCyrUBhVAbnFaM55+lxePdgLFz1nMu6oYU8ViYOxGz3oOjd2yC2xZF3jRIDP00h/G8whkDoGF5IGU4DGiG0+owc32n8y3V2Z/BhWRePyBQE0/vLyfLndvh43wwS3n3B3WufY8+jh2y+4wfemfAK/BJOwj5PAXgv/QXF/HwpTjydS3dPguFRHaC66yPfK+umL46qZHPHgbYHjoUMS0NI61oNYe4ioDzvEReJrIWlvxPomfBNONPxjIzL20HknQhM8zhL6RnxRC9L6UzGDf4wJpEfbjtGcXmBsHddKNWHpvI52VGw3XI97k5M5g9XXCjT/QJZi+2gd9JlOOgzA3KsdcguRAmqnQWh5qMD5/1agasaN/GCedsgylOCq9vGkfiVDAqQSsAXLtXot54gefU8VDpkC7PnfKOXfzpY6nQPnpyWiwnxsxkFP8C7E0+41VoILN+UkUy6Lr8w1aHQFafglq8pHI7OQKXcbspqIl6lmcuJY3Rhf9tsQvOZaP9gFMstTKDMekmIjf3Dp6UP89FuLbr2YR29URKCh7amsFu1jJ+vSQGpqS8gd38ZmvdXwf0to7Fq8zgWstfDjs4RYLKoG+32zocbRXoY2L4ULnq3cNfcSTizxRf6zkTjpt7JNGmxEjxdcR49zB6h+pw6UDw6nl7smgbS73aStUwaCnv8pXrx/2i2yCSwNSzgRWdGU7TiWbrXlQSuLWbUZFFI6f6RGLI8kTw1ymBTjhVsFDwEMw1OwbtXT6l09ZDjPVzPfYITWfd6MN166QquyzQhfIcB/D4znWc/ygHBt4I4rucWRN5cRb3zSujxj0TQe2xFm3vmw5Y+gCUzt0Gi/gmynvmCzxy4jh7/VpNP3kUMm5FP9btTqDD8HERtE4dDT1xJzamELEa/g9b0OHy1LZbHkznbiaSyb1o8R6V30KiJwmBtchllXZpIzWcDicAJFnTfy6rboglGHIPwiGUoJzoRvN4owt8fxax7fjHLNFfANfNg+O42HnNOR/Gii2no7LAB9RT1SfTXNAg5VAFrwQpOhKpAbVsbC2yUgO1n62GUVj5s1jgMnnOSYOdnfYgPOEspDQtQOeM5LO2Qh+6piTSOpOCIwnD6+fIrzS+uwcXtI6A6Ow2sJM/ws6oQlNe3A2PtT5QQ0Q8PfttCy7ES9vvZRRmHjSBBeBWX/j7CCpdMsCjRDJ+ccsCUoH5aPyeQrO+OwSiB6ZA/iyH2ghBtMozDmOI9FLPyDT+6poTJZlfZcoMIHlDZjkpTFeH5GUuYVqWPD39X0FYnA9IZ9hs/HY4Em/VXye7HYbCJ3ogWo6rQJFkYbNPfICgEoOW/B/zTNQu2RQ+HsRGHsTNbjjfKSmJo9mSAHn3YUNLAe1evgc+nV3AOSYLW6dNYX7kYy7Ktad6Sc3Sb63FpuSy4boql9PEXqMK5EkbNKMb4+FPo2+lOwzr1ONvgBsnqibC6pjasl5LGczrXuCHvLat6XoRPTtIEtZqo+WcWzVS05WHKsqxiLgWhma+gdUcuXRuqO3dgN1hxFzgJloFHXhS6bVjGblfl2bTVBBb7P4NL8bvI56cHGnu40y47OdrktAMsjEaAXZMdv3d5yevvCsBzs4d8q9KFDIc/pA1G2jCx5zyk2Mrgmg1XYfKUyzRG5j7MmyoIRTEF/NOgDL3UxGHUpHw8pJiANRV1fKr9IEU2VkFZuCVNCBIDvaJzGOGyE84IVsFe8eNcO3EfVBjW4LFzrlyQ/hZEZf1QqnQapHoWcX3oChIquAF6bsfJfnkeSev14WLLudi38zQuWKhNO8aJQtmKSGhzGgvBWwgr51jy2oQAWDAsCH6cSiDSJ7wR/wa25yrDhV4XbnFlvjkliQvWqJFFPsEYgZfo/OslyxdtBDeLTIgqloGfN75x91J1yrp9BV+tFcWDatJknNRP370uge04c/L/eQxtz4yFPB0LLjldxBPrkVJ+voASuxZorhhyuIUH4af8NMwzd4bgFwCaQc04YdgCGL5bAaU2tVO/xgaW2f4M3u6dyxPedNCG1ofQbKAMsvWb8ODxETCnRgq+2l8gU3cPurxxM5/Mt8OPcxeCpM9VrOlXhrpX49B78BmbTjjFe3zyUDfnG383zaX8on46nS6Lu25/ZIOvevD4VhhtLXmGM7Kf8ZnFxyE+NICdzXtoU/918il6iwvKrvP81jGgm7sME/RzKD/kPl+TuY1TnlVjW0MsFba2kH9LAHav0KGtZlNA63Y15CxKojHr9kOAbDv7js6G+K9d3OORgBfUPuGK8FSGiKlgqeAPTn80ECQ2gETWU54obAEhJv/4/lgRfv9Ji4yNn+OMipHgLjNI6jQXCmOGvPPnS76z+ggLrr7Lk/Wu49pnM8HgqzU6pauBgt8VFpdzAY0DBiBashfXPHgN4lG3UH1jP2uNnMQTkuZBl4MxpElOw2FTArEGddByZgJc95fC3HRZKlO5ifpaAdx8PwSWv9UGC9cm3OIrjWmb9+E3fWX+19+MIzUMwG5tNI+9kMsfd10COy8JqNSWo1tLfemtUxIlWviy6s3t8CVyPE5KjUNV7X+8p1uaar7Lwo6wEviTdppuN4nRXb23dKtkKZ/2ScMU52h89dkRSrd/welKwqD5dw2vi5kHMSbW6HZKHo9sjqXDtX/QqMUeY0Jf01P7WWxxfBq0an2h1TvHQJn0laH55ONgkCOY37xB64qec0DuETofZkcX7hnA1cTV9HvGMjxWsgQSNhWS2QxjHDvtK6b2rqS5r9rgd+08mKszGYormqAi2RjPxSfSt683YeGOeo4pu0zKu97z5IwD7BayHx4WKEOSVxF7tkdA1mIdOPmsG/xickF/sRxeV1KC51dD6eEkI8rZJADGk3ohT1mF92S30cxjoRzzLRMdNA9Tc+9RXKN9imVf68IYNwKLJT9o6cBVUOupxIJPE3jnvjT2GiMFDUYptGjMadxQfRqmT5QFTxVfOH7fGDrsR4NRvDc9H++HMy0XQkmZIUku7uBZ53dA9EQduC+7Eeo4F2oObIFB4zi8X5dPztVqLDdLhcxyrkLE9WcQXzcCyrsCaM7weFz16BXPi2yEr/drUWJKO0Uev407g+qx7dtHnvpRDSIeisIuJU9qtNhN6zPEMPD3L3jzSQzaz68i/d5poD3kDv/8JeFUuTXdtXPFvVV+tC12DCpEZoJbwBsweSUKePk3bnU4Te/0dMH2y1wY9yaXxg62c96e4Twu8xN0DZsBd/SugFfiNqTOuRh1eRx8ictlucPpJH63gkxau/jCyncwTeI13WwfDVUHz9CixjZeEzEcNh9cTNJy01D4SQgeXfAJVx9YDct/iPHdnn80LDGX7zTogL69GFhYxVC7ynHamZNOOio2uOjXbKzUiuKWUj92UC6DlIRsyFyrDearPoL0tw66E+yPTrcDaeCvLda8T6Q7C9uwbIo+LKwwA3mLYaBVYs5Npdfgp940Whq2E+Q8hUDg7mIMdtHgH2+IlGLyse28Edw5roJ5nc3wDv/h6WAtEvDPhZvPvHmZ6jtetbgOYi37cFOHMKxZdRKr8CyL67nR4qca8OKnOezhVjIVsuR3A9rQH5HPO/cYwijbp+RtGw2RE0VwfXUV5ozQoVUruig86gdfau/mSVe8we7XWLjkpYZjs86z4KQjkNr4jqsfKbPYzc/gKVuGYo/1uTbrANuGyoP74zz+4BUOMRNm4uCYu3zkrQAccY3n8qwECnFcxJkuUfzxPsGBshyWivmNanY9NEpBlDUXxnLXvYN89JYwtq55RN03WqFFyQiWfc/C4r/hoNpkCOlDLu7j1A3hURmosNUVl915hanHxbgseTykTv9D9rOW85ozmVgm48pLSkaitFk9vl5mR8l3/2HGkoPI1QLgneEKqVd6+NXyONie6ApPX9nzzh4nuORwhaueHcQJOjIomzYFpt17jq5672j8zwno0KNHJ3/FozO08cnQW/AedFC1y44gSwTc99qSJZ4EkeGX+KzgM8wVt8DrayTg2bid1D1RD5PLT+OfQ9pw7Wcq/zF4haUlz8B16m5QO+2FVyavxWrrcJQv8YPPfw1xxZyhPa0aR0cyLMDxzDzatF8YPze+In2H1XB3Qz14/qlC7eynnOomC98PmFPIaBs65ONOo+a8AWfHDLo3cyvUSy/i+H6gs99rYJqTMcQ0vAHrD2dBtO8EiHQV4fq1NjzYYwvrA99g6KFgXHrgG881ZAiVUqZfC8IgtdYbqhZW8OkZK9lsXzbs6oviz7KHaYzUX274APCx5BCXL73FPcpiPPlWKfX1JWNAhAydCkkd6u0NjtlgxTt/W8J3fzfSfLwclw4uQCv+xiOGMkc7/wD4Lo2FET/0qWBRA16omQhvY2SGOEOSbz9KJ6/Xw1F/tAm8khSi7EVWEKnsDnOflKDdBWMIdRTExOWfsW1yNuZGeoDYyqcsFHKKpletgVvv3lFg1HH4dUIUliTOQdVjR/Fs3E6oDFWjER6L2CTmN399cAUNaxUo/dgrmrVTD1wSKqBtZQe9cP8AugVjqOBgKi3KmgnLPEVg3C1rvvXnN0xNFYfQXbKwSLMZc67Oxd8zamDZcoQ2V2VSua7Kfh0N0J16FiUMASAsBE3TUyF12H3Eg100XySZw6oG8cD37zQ/9Dd8cYrFCf8RtHhGY1TlWrgzezKZNb/A6lEFbGpih3OWHeO8m1qQcfAiZURPgNK9eXgypweS9Q04sd6BPucV85tZ8SA3Lw21HjwBYzjNA5FTQeT+HaicHwzBUUv4jmARG93ThalzutFjkgwZyaZRVMBCuvFPHQ5k59De7iLsr3TjmvY1ZMDrYeaT3RQmTOTYU0DH8m6y8DJRcLeTgDqrbdReWA5SnwiPhQej5eFYWOuqgvkcgXEyxfCiYgTcXFUG3k25uEs7FtU93vLIRD1Y3bSeJC0aOIRXUnL6IzZ5MQ72bl5PT0Wd8LO8Mgu+zIHTNZp8YsJO7p60isx3GrHGD1uMOSgIS4LHk7L6NDaFndyfHwsxlW18/ronS93RxSuzEqE1NRGX3R0HapL9EGGxFRu6prKebAqaXNkMagFyuPbAFv76WAuVAp/wOFcRaLjaAGMtt+L7mEIW3BMHigpFsHJiAep+n0Iduxqxm57hj9HDwKPHlb7mJ2LjASWeOn2Av96oYa2nt9j5YBBOy/qMk5tMedd8E4jdn8jS1zdwX0U5Z3d/o96tztj0vY+nWKyEDSsO8MExFyggcBzc2JwNSxpfodyWGfynM4b2lu7E5xPvo+XAfJw+eQyNOZOFRVsRjgdc40FUpoSxa2jK3gWwyeogJY6NG3pHEj154AttDVtYL9gIFii7wRv112AnFYDPlmfx+BkzOKWmAF7/08LrY+9g2zFH3LDYFHRu6MHHsZF4ZZ4VBWmMQ3+hcPhY8AYDr1jC7E2N1M/3MHmOBpz5K8CeV95w+sxIdq7ZB39HG4Kt13K+ElAD53LrKbzoF0gHi8O6l1qcOek4fX02Hhr9b5LTYDi0275H//lBZHhYACT3OXGxixT0eAfAH7EUGrFdnSeN7QCduBtDWdJDc3rrQX3KMrS5bkg3ZIXBRV0RWsT62O9PFazdmsnZ33o48tNbkHgtBN6WbrRz5VUwdDCAtkW56Ft3g+rzVOCwizyW/osm/yI3nGszDG26n+COlpWgcV0TxgnaoZ+mFyQ6hYPJtESSk/pL/3lv5BuXvtCDBV7UNeYSjjmlAxfa7nPK+wEK6u7nfcFaUPe0C7YlFaONViPeFBsLDicD2VxQHnb+8KPbWpncui4bL7jswwCJGoh74E3FJSNJ+3AA1uQ349ybclBww5tE3M9wrOA9GLfvEv+wZ9ytdBtzpatxxtFwWjzpHVZIDoepucZw+bAVjVCdSOu9rkH2qngSuHyH31+Vhn9rHoNLrAAKnRsFmj3hKJQiBM2rgnDgCPILtfck4x3IEeeNeMTuXBJviOZfx/XhaVoD/Thwk+++20EXNERxZ2cEVdRH0WnvOJgzyoY2HT5Cs0dOBfMsTVxT8oWX79/ML06e5EPHqmjWUnt+53MSLTN8qOf4FU7W1oGurnTs9b3Lo7L3wI4P23CK5lZ0KLDjvMZMLio8TTqXhqFdgjxUuiWBiWoEyz5s41wnf+gdnM0r7A+j76bffKrjOQeVJ2Oh5Wiw2VgG2SUa0BC7nCMq94H4NhfIfy5DSjf+Q6XieLq/aTmrKSpAnbUD7hAdyV2z2/BVXTosza8kEcNjID/tD1fjdfTVCIXvQooQOicdzA6cYFkjc3j3NRlGz1vNTtMK8VNHEi3sNWS3df/x3NdGoH8/FOouu0KcuS/dsjnJwosnUbPFUoocSOUd/bnUmlMOmfskYdfpo3RgjQnEzV3J64t74eKvjVySbcljtw2Q5ggXdO7ay8lZQnC0cIAWDS8Cg31f2OXsBbw2IMY+f7xpZiGweVAArDGbyYqOUnDq6RUuGlwMnWZryNLXk+JiXel1+j9q7y0lm/o5mHT6Phj/04ajDmcx8Vc93m72o63N3lTa9In+TOxEn/+cafWi4bD3zXVqLxaCcS9b0f6CFC5QPQ2fAkxZxsIG7+cHc6SAKCh8SWfzvFDK3CEJYwcO0majUdzxZR3Yf/HiO/mdWD4uFQU01lLMyG14zDAM7S/KwnjjZ3DeVoFNX63FKIunpPg8EvJL9Dl9VhVqerqSQbU3hC3Rg1PeWlDwI5jmxmXQXLkiuCz9j2cKFeI4nTbobbAk+S9yuCBiBBx21UCxjBEYKOSOu617oS+5hH8+6eTpzl/IUfIRflUtZstABXhRHYE6/4RYtWETGH+14wEJDThNs1jV1p/UJbPJPGQ1KDtPg8qvd0h9oQPOPXyLjlV2gb/5Cy6eGwNpdh+wMbWUeupVoG7kZJBMEGWwyqMdY5fgg08DYGPcC7elvHFQ24Xe2EeSwJ02ejh9ONz5eApdz8+CSxlxZLkhmv+51dHIQEvyGSmP3oZvoD9zK4w+bQmB47eTx0QLvHcyi4zT6ijV/zCaB6wHxZlj8JVSJ7jL7iHJoX38/ViOneZXcbfjDc7QtcJDe16zTPY9upCdDHYlW6DdoomW9eqB/V4dmpG1EzSFztAlXMZdJTag37GWtgXswAr1Af613x+2KEjAcEFZrDjRwOm1f/jwGk8+1qsC9pI+LNHkyytsXemN3w20dzSG1Z9iwEO6hz/ppmCAfib0PZ0NmjVpULXsB/bK7IOuqFC4eUMOzNdMpFWdaRxqFAqp4R6w8dZQH33W3KftS7Z7bMCz2xkXdk6E61NXQNmbCLDvuE9lJmuoLXIle3e2cOG/qxySNBpet/7g8fWjQbfTFKQXO3D0+2Ca9HgCfxnwwHNmCjxumiVtkZnEZfnLSOi0BiSVPKC5WbrkJvyQyr99oLMP72J4RSKK3/0AsVmLMT1+M1/+ow22eQFwL2I3TQwzgY5SAxpIXoGD39eiQf0Y3rfVHy4qy3OOmgSkv7aG2aJf4M/BvxR7U4NE30uzyK3j0Cvjh2h6CJ79TYepVwGaBUz4lmQmbyo2oeqV5vTLVBkzCuQhLuYD+aTMgoBdG8ggUgh+2MejC6Zj38hOfMAj0GeIc7W/bueb01rgqb457pvTiipNBBGGf2DqsFgeOXoTZAsKk/Q2UbrfWc7f3mbi+VWd8FbjPwh7pgKGXd7kOjsK8wIHYULOMCqK+8lZjeE81WgePZHbww+GSGxdniFMlAum9u4ZPG/AC7+MnYgpoYvhVM4CmmswG0a+zsJM50MgMVsJFtZ1Ue2It9zii3Rn9SAcG+7CpcFC2P9yEo6t0sKSfMCIgdGw7rM/bRMPg/9WTIGreitJc4IDT7BaSje37aJZm3+gVvlL0JlkBGJB52lXWwLVDZOm+Rs6cOevd1geY46jbv/jB175NP/wDjyfqgvpYfehNzcFLz3/yX7xx2Dzm3aUsB3Dp9efg6Ua1eg5TxU2bjOB4o2F6Puljf6czsQl9RvA8cEbfJ23Dtzm+dKBs/0cck0axHdMgM45syFilCbePxzHP/J0aYFEIE2bkgpbZPN5bPRIvOw9E1TvAJxWes9C6TboOLgOZx5eynltH8h7eBlq739A+au9CaLt+JLCZBjpexIhbwue+rAKa//acGfiaxoZKoG3tzLHF57DpRMFUCdCFP5uMobICdP5tOQW4NoW1hb9xEeaz3OueAxMumSNCzR08LukIjwrvs4mJYitvrksFB/DJYoFOKzjHX34O56X9SfSO4vdvH6cOFRP6Ybji4+j9Y1IVDg/B/aMtqKzg60cNGw+fY/xgzWfzvLvTVPhWHAdhoQI4ODqKq5LHANXwlZwGdixVcI22DKlk3XeEjpukoaBy9aU6PmMG8se8uaAOrz1qJFHG/rwpO3b0fPKZPiX4c2fnBShtGULB9y2hJ1OBFubzlCdVg1cHmcCJ8+q8/tH40lYxID9k0fB8WZDqmjWoe45yuQhHUb6xrJ48dBOqi2R4Aqd6WAe7MK6ezVA5PoH3AGPyK2kDk8vL+eCR0/IUGUHN/yQ5cwTzTjx9Q/KztSFYaPy+cIqK9LMnI1J8mrwI8gFFy05RX+NPODMqfmcMTMbN9lpw44HBfj47T+6bi1Cjpv94fcuLZCqOkf/+bjhJwUTcnbZwNe3qcOssELe6u+E8vtshvJNBtuzx3H406e0J1OX9uxUpKdxHpT7ShWGx72CsvZWys7X4DshdSiuUAhvr2ylv4tD8UXjflwS/oX+dCjCQodJONusGX18NeBCRxYve3OB3gvr0FrXdVyYm8HhAvEcdksVPN1b+VLjSFglugfLEpfTMOMwurT+EvZtXYAqw45i9fFevjZfGXZL/+SiR2JsdFefytwWYEz8WB7bJYdicdmkpzeH9QSOgMGM4fD60mWSGCB07j0PwS3zOPFCHuZIFfL0J5WQcDQBv10cqu02hQFbX9Q9UUfyF2pJQrOQF6ok4JoQoIW/jfnrgTz0VrrDaKcIUxwesulAHM6K3kwtfmr47vEJHul9HupKZSD6ghy0h+iz0gIG91O2OMMolz0E9lL9yO34NyEOXSOWUYidEt7z3kG/3fQw+O80kFZPIvuWY9TVrYTideV8dq4sC970ZnOR3/D0wzMy99sLH+2MoBH7wWBrIAYqXOHdr69hdMQ6CPvYR6ujxVj3UzJMtcqnW3dN4J7jANlJV1Lyi1gKkvhI3wLf8xaZAl6yYQpNV6oi4dA5vPazKRz7KwrbVjwli5PNIDDXCypjbUhay58bZqXBjXhzaApwRPd8dfgcVM5NySd4UtRifHFYnqfF7IJXRenc4lRDm/PtaXDyXqw5bAarJN7z115xzpd3xrneFjwnVgveSMfB/t0OeC/qFKn9mM8pfmJQpkkYrpBJhQ4ruOHGLf5aWcwDOnv460NXTD/niK2yonxcRAeW1a7lqpWyUNL0hcxGNOD2E9HccTIODujOR7UzWRw5bRdVmyjBzue/+EhCHnh0zWCjd8L06oQud9c8px1yVyBu6ikqyNeDtw9Gw8Pderw52oi3DCvC5RnVuOzYY2pp2wrznsuSzbvLvOfcJ5BbrwL/NE5xn/sWKvyM5PuDUPfRI0C/VrT9zxh8XQe48ZgDdLpIQ77bHjJz+w2vHW6S13UlElgYzpnJifj2ZBEkRizDhfVupJJqCVUnzWGz2ju4vFAJ38SnQZLtRGzKdeFAtWfosSqJNSyqWSdHBoL2SvCGssd4YttLlPc8wAsvbiUvqSBasi4X6ueuIj2jcnL8rAo5tnYUeSIfpUud4WXuLBKKOkJtH9PIdpIKtb5cTHf6YrDBdDSc2ClDsSWBtPH9Y7QPMYeRw2dw7avdKKYyi5N6C3HtsJM0t0AbRrySof2vPDivYiQozLelK3cu852wPBSfcYq+bPNhTdnxIOo8AYyjo6FfpxnEx4LAVNeR/NKnAzrKOmF4z0VuurYNoo7/pbdJU+BSWDUW3lcGKYs4cL21hB44XIP4orlgoDyS8o82wKU54rxyNkPwcnGwjbJitz9NnH5/Othfu8evI3ZBrJoxX53fChG/z5LIJklYcfQ5HJIfhmanb/OnPcc5ybINC7ZVwfapWVw5w420ixbyZQlj+PntH+ks1IcPRvuJEheyglcnmuXdpEqnyfzCezNbLfsD475qQbOBK03tWU6dGyKhzvEi1CR9xzeLAsm26SZ+79+Cb+staYOLKezZW08eT0fil6+JdHLvH4jfEoYpEaW4JewEWLSvB5VXc6Bj6P5pDTwgO01bTPnihiNqH3LVhhuk/v047JdRpJT0BDY595PXnRaCKz8P8bzfbsR/MkltUhhmCnmS56NwbvqVAif1wtlBKgpfJ1iC1IpqErwtQn77jlFd7jWS2xWCTlq1YPlRGIY79nNnRRl7nxCHZ+0bafgcQeTQp9DRYQxX5zRTwMH7uGSLF2esUOVh0TK4z1IKHOaqU8JMWwgy2kB1qrpsbqXJL8oq0UohGfbP6Oakq3/weKY8ZM+Xpz0Wo/jn3XLw7D8Esj+SwKr3E+fUepH+zK+0pc0RPbfKg3HJIpr8yIB6bMeRq/5cXBp5GnO0pdBi/khc0FxKNRtS8fEOfeiK6YO2plBq/nwAZhmdhwzh9bzo8Wc4pbUFi9w2o77ddtp9zAiu2VeT7NI9VN0jC0qHnvDkYX3kviwGLq86R8OPD/IhF0/WGeJT0zAvNvvwgxwU/NBVbRCu95vB6cnxsLFGnhdMUeVDonvRRcQKxugnk6ffUfgcupbbTBXp1caHdDU8BVbneVCIcRqJzHQiP1dN2HziAZ8VOEAxs0y5bPpsOnjUb+j5Pp7i1Ewh29+CwjUPSFUzgfVuMyE4+iWPcnlOtQY98HLMf3DwjgAYHZTmKwLL+HPKW1LwHA8dnqHU05wNT4QCKNC5Feeem8d964Ih0e08vLVvZ8ElwaSnowtr436S7DAt2Nf0g+Pu3yfXf9UwZ+MaLsmKoPNdW6nQ+Dl+qBKC7MvvQX/Ndt764BP9rL3G520HWcWgi+JsL2KQ9RkecauUL2uaQKrUNeguOkriOQF8cb4hfVp0hy86LoAroUq8dOloXDjdBx+XKcCbeddB/sFv3j98HSwc/g5H5zazfksZqGleQ7Oax6CpuZ7qDktBWNEfeFVainEau1lVwBmHhzfyHCdPJtUF7CHykZY06uEZ/3FQrKTAzp1K2NvjQnlhFXjE5zDvQgmIczgLI59r4il5oAUj1aHCIZFPRm+gfYtl0fv80PepuIwrZ1izSqg+3DMuBu/3KdAjLQLKxqugdnsSutxcAK0lp4ZuRwPl6pfS57ey9GWsAjYXFrFQgBr43xrNE8+owg2Zr7hkigXJN66Cb3n9+H2tCVcFnEOnxj6MzVGFq1nz4MxWVdhRdGYoYzeDdnIcLHWopbRoTVZUP8leGeX0YbwZ3DYNYveDWmAxaxxVVmbyiL/G4BDxlovkG/m/5DT+oqSDN0tN4EeLOU4YdMS08FbMjcqHvK9m4LXVD8bmXIWFRz9QudRIorXSEPd6D51Y4sEOwu/giPQJvJriC1MeV4GFxDZ4s30FLAtSAn47Crp4PDrXtWF/XwfDIxl4Jn2ZFRcep2rxGZx56Sj/CZmEv0+qwMx8Y2bFLfzhdTI3RwdAl7krR8XcgsCJF9GlZDNMbg3jjxeMYVOOCVSfs+H4bE3y0B6Hj6tDYXrBkJudb2WrP81kIrqN3foVIWSI+y1sy+jevTvo830dvn+ym5ZmtvDpaU9ApesEPEmL5KWTJ0O38Qp2qT1Ik6KSoaJXBLJH1sOrE39Q6Q3xRsNCDtYawRGDk+CWqj8Ztm3BZuNKOttWRhveGkG7fh0ES70lP9Ue/hj8Cn/aGsLxYH2++30Vlq+3QuMTUVhuKsEiQe7gd2IM3okcgaPer2KN72Pg4aIdXKdsS04ygnit6TRWyonDPblwgMBK3GuwHiS8dMhlpBxssRGlVe1tZFBYBgWQRXtEx+OK79K80j0TpRNaMHvjXpinpQ2LDsbAcokX/LhYl3dvCQP1ncvhatFqvPIyGU70fif74Qagq2MM0lbjcQgMYOdTS0w7uZG1A7aA3prFfD9SCDtcE1jm+Ho4PmwEbLWXI+/183i6yj72lo8An+n1PD5XAXbmy/Ir44XU8mwv9P00gZ93fNnpphi+rxeg5WlH4eJtM04cmr1HfwPfLfzG6hobSM9cBL50bOdS/bNYL+7PhZsV6JhkH4SPluMjlgvB+vtfdrjZzwnqcuDxaj/Fh/fhzflRELh5OeV4B/PV49p8/E4P/GjciqNFJcH2nTT4uU6D3tQ7GOOUgdWf5ODU+fUwW2QJjHcqQfuSRej7ci9JNRJk143G7bcmsN/4aVj97g22NMRD360YKohfxy5LvsNzXy2KvGgJM9Ne0i//ABw3Mp4+/NGFl+678frVdJwoVYN/xF9CNZ4jpx5zePlBHz/el+Ruaz+87z6V/Jf58DJJPbbTcOYNdYrY5rqLzpTogFFsFP24IUu7tueTasFiChh/hT01JEHl8fihvs9j5bNdaHxvGFSHLyaL1GPQmnSW8rOu8Qt1U/J55Ak5tf20Z64jFr+15pnzFGHUnteYbHALdgf30I9RinjMO5mrtO7Q1UxHjKB8cmupRzEhOdgx8jr2/BDB3FWzyOuZKJte84R5o4Tg0JbHsME6nwq+jGJQFoYckV76HafN3yevhctGXfxgQzet6T5I2oetIWLcYhTwz4dMUYSqi7fh0OqzQ7esCI9YXKL7T0pQt9WdfR5HsbRiA4RW5uPVneLgZKZGR1ekwt7jH9jeRIz0s36i7NRCOHShkbVulJBfegceWaENnvQYjj5Io2rL3dxyZRXBP3lqcDWAeq4iDftY/jw3jPYmiUO83CP4eVGT3Y8Iw1UfZV5B1dS1W5E/24fB1tbFvLJfEOYGWILtm60YbJUI7gOdvOQosZhCEl0+HcRx8stAX3wUtkr4QtjKoXzL7afLlV38TywIDOXm80EjH75wqAijJh9AQxtxPmS8GQNvCUDvl3Z03aYLWuuWYJn2Gfy7vp0NKqZA92U9jlv6lq3etvJHayHoT1oKDv0H+O6hn9SdPB+/D6TRneIGWD7pD61ruUNhndHQUDABxlQdxHTzPdAuOwd0P35AI83X/Pb4HywbEUFmRy9ATHIjVlRrwpOG82R5WZDVjIJomNNCtH0RgRbfkvBrvR5v+/KbRRUX4/hEMXgr3kZlD/Vw7cM/4AZR/GKXAn2KWIGznOfAssgN/DLMnLZFDTnJJVuWnKXKhaNmod8FCfwa1oAbx8VQr18TVEmZ04VHTUM7QxBddgaC3t3gnmvXaJZEF2w4eB8OfJpKHRJe1Lexjqpij5KmqiWMSh/GNH8yiEpOo22jr6D2xFiqvNLCgzKG8GmNLc0I/8PiK/TBWEiOl+ybRanTZ/Cf2Lcw5fNsqqoTo80ms6HthSu8TS1inwZDcHFGMB27maOVrbDwaxlNtZyITul64CF8hHdPmUgDqX/QK1gUQkSX03xXKY54X4Eph0+AbqgESv5V4a3lGdQcUYn2d7ex7JypYPasBnoPv6dfN+2ofc8OPvhJkWznEVTX7KIv2SY4c/JxbB+rDccVRdlSKA4+H93DPVXubHM3DWtnmrChgQ6rOVwmk0wtHL9fcsijdvNc21aYeEyNovVXgKL+MEqVdaN2/2aMENoBt5eVg4KWOpS/lOQvzco4e/U7GofZeOR1FXdce0QqBy1xVfl1eLHQkvf9Nx5C1XWpuqmSJ2Sa0UbZXq751YedoVlwfMJMUFidgWOL8si+RwtO6AbjzcjzEBCzjj6O/gBu08UhT/wyJl95zuJhD0B4ezkdvaoCi75tg/valyCpu4IDT+rhtq8AjsIZYFseBsaRFiTRIEpSD8eA1L1G9LEsZv8fjtiWpcK7U97j3lV7ufa4BhsdrmI39TU8UdAComRM6EmAEsk82Q35SYCdt8qhzMIKuVcQnvNW+q0+n3ecnwh7Jx8Fz3uO3HTnMXmo7MYPZ9Pov8L51GPtCiqfYuDeNUnsyjKB3v4hH74RjgLTqqjz8F041r+ELmd1wNbJvnxh10PMuf6E609qgFZCLl/yDaXHy+7xR3EBMEv0QHu+i3Jb7vGzYb9ggp49HtAQhjXDRdnzjC+ouLtRzLPtsFnaniWXRMODD5L4wsoW1vYt5Dl2wyDQMZ5PHlOFjqtWmJKnAP9Fb6Yaw3G4a1QKnprbz1I7xtAcp6kwvM4HF0lOAC/1lRwR2s0vBt1BLGcl2T+rpxPrW+Bgkx20CMtCjdYGKlntDUVLa2HROmNqGZ8GrjZaZLSggn7mfgXF3adhQ7A6JGwrh8USNmCgU0KHBxbQqNtneJlsNLXvH0/WB05zfO8qtuwdAy8vTQXnRzUY4DsHk1KOgLvWAYjyW0N/ZZ9w3O1ork6IpqkXrEAKFkCmzBR8v/8iWVU5g83UUuw/8JpPwHLqs5FgxSoRrt4lB6JlFvAnuIm7a9tIzn83Ngp5sN/hV0O+kwWXf1WCzaVeuNSmC4ZSxey07BQH3A6BIIlStByMpBHWX/n9ZH3Y880TKs1mgNo8S5j+W42X/6cFWid38EiXlyAcYE6zKtV42ZT7sHjYGMoML6T5Q3tVNCUZzD0r+daTvTg5Yiz0zRQD7V3XMfXjI1z5NJAej50DGk+lYefeamq8Mh0aXGfx+3mK2F48gSt+5cGsohC8Gr4VFSv0uFnGCNJc54NjcQZs/9eOpmHvAXbF046J02nCKobJFavxnNdNEKwSg5UjijkwrpP+zsuBgHgPWuXpgq3TJ9BObzGwFL8O/Y3WEPRqBGT+mAHaUhr08mchXtPtoOODRRw0Bkn1nxdtXRGCeg3m6FE3EsY+Wk11Ce/x1Z5swE9iPFGsivtSbHnz2UackZZEh15rw/4d5uBWEIJH/jRR6YqDYNGoRT6DlmCTtwYylunjsKwG7MBgrhUdBlcnaGKLwHTICrfH7QmK2O3QSQsXMkhVSCBX+cDr7cfA+tNYKHN4CmnPH+AflXfwuPgjnd81hpzD7OBi3HiqrV+NBiurcbDQBBQNUlio9RKss8lCdtfmKBsPurslCdeZufKXv1/ROyeaN98EWLKEUODZniGusOHf2Yvp8eWpMCxpM3qr7mKvjTPhdvA7KG81hYy8AJwSMQov1x+lLKVoXPtvBFdLKUNT+DKe8fIVhQQvxvA4EQj5fg2DYlS5ZN9SNB2cR68NBcnIkSjkYh+5uQxgn+o6WFU1GpRn12CQ7wuYnGVFSqaN/NXfEK4+9uGVdc78RHYjzvLXp5yn8nAoRBMKoz9gmrc8l159B6KeJ+H1pFXMNZPB7MQa1v+hBQJ9cuC33JkabzmSd04zhWt8hYbS0zh79jCwPbqOnv5TxDSBelriBzBxKNcytm5nd//RPOrna9ITH0Hxi3Lolfxo3PT+KJeMTsanEcJgYBTJB0u7aNPyEFpgU0mzrq9mm4gyfh4ciJvf7UOj2r2s3GYC99+s53olJVyguYVOqouTje4q1M8ow7WjfsGlBUth/vxl3HJCDSa9S8QdV0fCa63M/4k7776Q3v+Pv0d70R5oh5ZKUxFCSkhUCKUUGSWRKBFKomGW+UFlFBFZiazSzkhFNERoUFGJqF/fW/G7Adfjcc55X9fr9Xz+cc5hdcvp8GlrPxTvksD1UvKoPcwRdiwYw0Zn5OCU/CCVLFrInx5vQ4FTG2iK8he4froQF13+D+0vBODAlGacna4GxWUnMF9yEyz09mDDkyFwZNkdOiztxU983Wn0sBQsLyPYMEwFWizi8WuyDHod2Mh37KagZMFq3tCwmTsPxOPrcXV83l2Ujp4eA2+7bNCtOwYcbH5hUnEjqhz7TD8kq0jy/SkAr+Fo+mESlAoZgZd1DQ/rD+Omeyto//RiXJEtx7Gdr2i88jwsa3WmvbFHWeaxOEjMfoSfny0hfWd/mNAljZ3hTvQi/g+4vR2Lbq5XuScygS/WjYEx7u34deUn+qmXQx5NL0HCWwdNnhnRrp5U3uW5hCvGGaD8ZB1I7PjFr8IyqVlABK6Kl7JZtjlma02nh8PXc7DhL45tXcND+AjDnNZCttRuqpgWirt2FMF//lNo9rw75OZTyEZdDeB2dIAyTxlA9N8umKp6gcTjW6E3/wUGz9xBq88cp7VW7hC0YitcmuOKUd2WEHDJhCtnjcWGO324evwTcPwiiqeN9vKINlVa81WNSx99ovM2KrAhRh/ndppQa0cTXCvzgJvp5rRg3CwYnDvk/kHlKJgxlgeUEWR33sVHwsJsfsiHR7fvgRk+e6DBzYvUz5znhHVNsDhtB4sd04M9v1rgS4AHZXy2gpcXivD2clOQMZZBJWV7dn1hAV1VXbyiQQz0dX7wXtFc8EueBo2RrTyYlwkPS9aC0LoAXBDdRAbtRbipluGNiRz5zinlcNcGEB1fg98WNtGEPFm28stjmdu98FnYnrV6JEBwVxqMPfCLw3PS0HbmDaze4EGbtnyHx87zcJTsbRIS+gXuAeMg/VoluS2aCM8CM8igSgAXVGeQ8VC/dq3fQ59+R8LT7BimECOobJsNy7s/YmJQP9WaxnHJGREw6r2Ecck+KLn9MmjO1wG5hbbwcGUm2lbLY1JuDHSNOsV7gxs5M241SnwdC+evzKENjjtRp14CBmRNecYoJZoacAF8tpXhnwWm1DV2aF6LDGDRBHUop4sQUzoRVGf/hWOdP0jXtY+1zlhy7oM8tD38lOdBK59bZUgjroaBJVjAZcXpcOtPFg1b28ZjbkhQwdsEDru9nwK7R6CquxppxT6hF3IW8D1GAT+FPuJZNbd48qxMnlD4lSYFpcFjPQ/Y2TmJtT9M4tZZIhDb/pfebQKU2x5L625spIz6THqupwaXb3TgnDp7vltcSb/2ikHaoZM47dUh2nZUgFRsg2F991YOWJkFxsIv+Jz4JNBQLMQHNtJw/Lky3OhoZo+ZkfAwNBF9po+EQtEykt8/iS4bLqNt4oqcuVcBFjqsoHTXHNx624OiP6RzWIg4ar3XQY1uczbs2YjXg/L4UZQxDKam84emKNSan4ZVA7P4d/5LCjwmzvV396K5dj4/GHELDxsYwmmXXF6a5Mdr4vTgx45usA3IYbuDMRQTcQHWjBbFRvksEDkrD54edjxf5BMbPhShPX/H8twiCxyYZUqmdcfQcuNimpi7F9vvKsHugXxq6hOHDksfLl3gwFBF7HlMCLytjtKuT4aUVTqRv+4eA/N1HCg36Ccrb9GBKdeWouvaaSxgVED7u+z5xIarJLdiBajsHQm/5u4EjccfwLvJmJ75j6W33V9xb2IYXn1lzpP3Z/HofT9QKFkeNMtWkNHMGxAt0sga9yZh53NreqDgRb+ChVlfIxNUdkviJ00dSF16hdXmxfOVzvnQ5xRNxe5f4dCTlbTQU45typoh6tYv8H2vAS08AqpumuDVLILRF3/xux8aEDFKgObNvszvSgdh4KM6GE0ShEpKRu/Bq8gGE2GW3T5aejoOz38/QCtKPsMp+1qUsPGhw702MGyeG4roZNC97euoTH0uHBu4BgffZWDRjmEsWFAMr1YWU7KbEBxe5MIznp+BWhl38uhvw8bHHSAiFQybwj5DwQ4fHve1lr3idSHu2DZUWrKWi0PqqWa+FSosHoNjnJ/xrIh0Vj6jQqueZtMqMxt4mbQN5ucwlRuIkFVkCptmPsKPf0W5+9JDlNGz5jt+Aui1WQJyQ5xx7X+HYFhiMRam3cG5O4fuLEYKXcyDKXzqXpKwHcOnY8Qhq9+ezk6J52MLdrGsyEbQj11N1kuUyW9dCq6SHc9Tt0xlQ7OJMENAm2f7zUSDj5ehMUaeZB/u5RV/5mHE1hKY2t2PywecQcNYAM5Wq9K3+5Y4te8EndHppDWXd5Ly7Lso2b4LP9gTP8xsZddrBmBs1QEHLgig6Z5Gkhz7kWNGRvOz0HHUtWEqfKrP5qPSh/FQhAqEHEjA7ZvLkLzfoXqVHT5Uu4VzPT/DRsEfeEZsF/fa2eOX69oQ3iQ/xORXeAjdqELmOMaWRfMqP2naOH89ak0/Rye8C0noPyk4pm7Ep0YNdYpRJ37j/XioYTucWVEHkmZb8W2BKr1MFwerPVIwflQxrEp3wymJW9F6ViSrCs5i8Tuv2OagAdDK2eT/6C5mLDUCefMJbJDRB17BstTXPQdv9p2m082mpPnlOrjcaKURq40A0m0h49E/bisRYCvxY/Ter5uit86n5VFtXOeQzzdCHaDC+gR/m6gO56orqCTYn1R2PMU//f3gq7+JQyQP4Zin0iAT/4fn7P7GL71HQ1vBPer/qQtn+r3wtc1wDvjTgd1vTnCp4gKuqnmMdTCJ0nqNYNLZE2TcUY2SIfqgtHQje7wOxnt3x5Co52z0brGhnpdt6PXeAgT/3cagvMlQtn8qfBgnSJExr8B8ZTpR9XqyOGMM588JYH+rMDzZVkeX9+3DNWPc2bBlDJmNeI7/isopv3ArxJXmwvddqlg6zhQkG5dBaZwkKd1TxtC2dvg2ZYA9Vo8FIfUYFAv4wR0P7XCirAxUnDmDHfV3uOHRSYi7vhcLKoxoxS5fTNq8gKJSf8HxgCae2jgGDM3KGK+a4thbb+BxpizWz70Ctw1fcWaYO+fOnoDpcodwgp8+rIyMgeyUnfCdZsNk8WLalvAagp6bwNN16vRq6lJsETUi8teFvyIltM38AkM/4Me8sdw77i5fVijmujdeeFz5CJgcHc4wRwXMa6zohM5F2lsbgbMeKvOBkxHk+YzpSJIEFyRNhX0DS6nuuQ6MuqaBB5wnQvLGbzDN4Ra8V35BIwKG4/fMLBx9MJGPe/4lVQlzaOy5ymvCJvKikhIyTH0GHc8l0VasBQ/1qPH1FHnIVS1AA1kCmfML6L7xHj6oJs9j/pRyXu8hyFnYhvGTT/LZHles60hk4yoC/XehAFFbsT7PFb3fhdCfCVdw2KQXJKc9GqtvzYQArUQUMLYBHW8PvHoiA6LeJbPG/c8w4VI4B8eXsN8PGSgvmsD5k15Bb78xGHgbwtPyX5wnqcofJ43j27MXU/6dTL49p52NLYzga1gBhNYRNLavpUzfBXxklRiNCzfkyx/CSKCnADdOGE3sWoXmWf+4pl9h6Jrnosq60ex+TAEVn2ayzWthWOvpywmxBaQ5ZySO3fees69pQsHIf9hj+Yr8Bc5irddW1KlZCquz1lDl1Z/cdH05ZRy8Rc96GZ7aGuLFXR/I072ev6V08QbvBezd5Yj3xeMh+lgZVqqvwwplYegPi6VQJz2MfVVOlyaH0AnziTT731dQ2PYZfp5yRcmf/fRvpTHsS8zH3DZJVr+3m9/0zsIV0+8SRazg8E/lsL4sDDr/5nPJCHGwuT0ZG+UUeZeFMKY/9OL2Zgc4UPILxJ620XUdPdL/MIanPzKAD2ejeHzaCGwSmgmB09pZbsQOfvrgOOWHX6TIF8eh+7QEB66ShA1FM0AktZDdVg3tTWsL0slzgXvK++jPdcSE0jaMcHGEjpsW8ICANIVX0Mr7G7F+23y0aN7CXil+sExwL4ycnohpFsN40T89UI0ToIyCSaxwzBjafl6DXXdPYVqBD4bCHw5pvA/XHutThKYpaPzT5g1O+lg1KY+kdgrgrUIzLBteA1+uFsGIGhWW7FlFi5bawNhdo3neim8w68tJrt9uwlaRM2CaaQJ5yodB34gcMPsmzmRoBZqF88ntAYN4cTbMc+ihA+9v0Mxvq5i6iZtUQ/F0eRYtviAHz+3u0M7N3hj/xIX+aUrgAe4CM7XrfE4lhqZkdENE9y+I7hCAbrslXKn/A4QPzIaiMdV89E0oHEmdB8WhJ+HjzRUQ0TScHxiNBInBHAr5Jw6ilav4WOcq+i+wHC42vODJetlcrmUIE4utSOGvHoRdfAU1uj0cZbYL+2T2ob9NJr/6/JA7TwTzzKPSHD1yJ2z2MYf4edeYA/7jx79uwaGgZGyXfEMrxluB1n8bYE/wdK52+g5FwtagECTAC6VqyeDJcTq0tA/oeScal1hwuasZvhtzFnyDkviLpAgsqnqLl1X7QTUBoHZgLUXG14KI/mTQDB5OE4fbo2vwJvYxVAG5c88p2n0zjtKsgcy3GrR4VgpHNf2lh0ni/PP1ZB6nm4UFLAk1ckUQ8sqIFmMvvP19GG5bxUGB3SvYPX08CHVY0rTBTTzisjF0esiiR/g8Vujo5nDFS/jI4AX0fS9gCckytN9jz9niASCSaAq5kSmYZE6000GfE69cBYdfn2lm0Q9IOyXCL+8rUWWqM9ktFIH6JH307HnNy5vP0brVHrw++Bx1D7djh6uGeK6/h75ad8LkS4ZgZ5dJJ8Ok8HN2IZRvlKHC2dr8QS8dlzTd4qkvFfH9778sNU8Hjq+ciDsP7aH4M9EkGehHtoOfoW53Jv/x+oYjVO1QUCAf9HXlIPpNM3n2fAQ9oxk4YpMDJp5dwc/UV9Gzs10guP4CWX00w8iKkeArcg0N3t6GXX8GYbarD74fbUIavhuwzdObGipsMG/qQfZ1EYCI6W8gbm4FlJVNxXXfLsLAUVOscRrOZd7qUH83AD5Vu+Ke0P+96b4Ym6TmUvFOAbbMy2Lf1A+0T0KRg6OzwSwukoLN/Lhm/WS4vvADOQR7gZ7hd3D9GwPeyxEP2ojy9dddbOjfQMtH7+UABWO4czQMY5XK4EyVIkvO2AjeyRqo3dPDfza5kuq7fTh/iSyc+CAKWcecKKxQmNO//CbFofV7bZpp7vU3YC0YQRMkRVEsLQVue0+CuZZFMCjlhE/OytGUP3VYFPgTBo+dAP2dVxC116Lukz0UcUME5A884K9T5NhoRhf46dhQCH6icfHVeM+rl/IdCinKn/k/GQEwWmvCnyWbwaH4Bd3cpIwiX2bCJrnH9G/MKdjSvhlMZ8vgMNNRcOq7PItjI/NDZ2hX/oafhCRQ5s8CrEuK5BGaE9g28CXfPmAF5ks10aA4mzJOv4IN/T84hKzZVH0su86Xh285gmj/bwclOthASbAq2OkE0H7rxzzMdx52bmulbZuegKzGLHx7tA5+nxtG06PHwIKEdNoxLQOazifDu9XRmPHfalD3CSH3C31Q82capS29Rw4S40FppDxN80zHsbsvg9DXZag65yTIKV7ALSftsEVyOBfBZm55pA27L/mhkrk92999Ct0h13n4TBP6ueALynyOodGuo3iSjROIiYyDkR/KeW9HEk/PHEEi93JYQmgZ3nm8lH5amw8F22d+eeA1fVytDalRV/jWs2Ugl6PAJq8YH2xMgi35D+hDYTle67vOO+Uz4NccHWgtPcb9V17ze/sBlLWIgxPmljBVZOiczk/EhI8z8GbTWXTfqgSdq8Iwu8Ef0+dOpx+TdaF+42OYuTGOxh/9BQ+sXuENiVZyfmUI3yrd4adbMde7zufldgdIYP1THnlHE+4K7UPBuARQ+lKBR6omw7sZUaBwMpF2Rn+iWLVJ9Dl1PK+sdsT0xxvReP5M9tQN4i+/GbLO7SJl70rKvuYCcwIVwElsI7plfMLLR+RooZwI8uN02P3DCpTlnpJsZjgHZv+gSYVi+HV+GehPKIPvX21pmdktzq8XhkdZY6E6yAczhxWx0CqhIUZ/zYPHp3BvtBll1VSggtonOLr8NCg8l4C2hc6YqNmFogp9eG7fc3R4oooj25vA8rY8zsqZgc///iXdaiM47POYx8W54IabG0D/TzoYS0wlaXE1ePDLg1+nXaT1h6/yHBYGlegWfPFYAy8M7kUjhRJQzM4Chwgznum9DS8cNMUrpk+xa8jTHW0C8M1RExTZmU5Bea94UW0bHlp+ERL8e0BBOwUjdfbjm1wTCDn1kdZsPogfcptJskgNZtxL5Gmnkin81H6+pJSF+20PUZW4EBi/94CPJZPxZNRXiByegjFrg0ij7hGXehdD3fs1vK5kOEhuMoeMLeZw+3ASH9T4gAENuZgnnoT3uy+z9b0GPOYYDK0PTXGiliVEpd7DGsnZ5Lc4Cj5rVMLGi3sA4ybTw9rPeOLmLV7ZepHkPitArJo8qR5SgbYlifxnxnYQkLsIcwNs6YvzSWjec4YvHNgO/+KVIUZHAATFY9gtQAGK7NZgonkJrP3ciOfupML9y0JsP/cIyXtPhl1rZ5Chuz1so9EwPvgclyWPwreL6vlRfRisPJ9B+9p3sOt4NbAYI0EhxqIYX6eEGRnKoC0xHCuO+KFiQBJMtT/Muy7O48jXGtB39QbK5vejpkcx+xvVU1BCHW1bmUHJdv9A2FuYz7V+gh1XzaHJ9yeofdzMTivngtOpflZIsECrYaNJ8ugGmNxygko7E/FfjiQs+VxObQs38iudWWQvf5H9u25AxpxGzrVIAe1lerRt0mts+zEC0tcngKro/qG9VUIjnpZAk/E3sqz4AsuPTqdELIXcY+9ZIl4eGp7uArnXvSzg6gz108+zza1AXjFQhf5r/WAWPMJlEwVw0FwbzpefJuNZgliaMRUOJgTS+stb8FXoT+h5nUoG4suH/H8H1h4Vgeu1T3CanDoabKuhwL43/GDxUtKfMcBC/9rhyq1cSE7phXkLTMHyVwDkmg+A1+BrnPV3Ls2tXcyO4qqcHXMDji6woO0HVtNJJ1143jibp7oM+XDgXv55yI7eSWtz5wcfXq12kO6Pvwp/mg35U/tIKH72Gt9tsOWlVxJ4hvc0NHuvwF+KDOHXHxW+80+cg/W2UWWxEESvaKJQxSj2WvgTp9zQJsv2xZhePQ9npj7Hu4E3oTKzEwcbCHRdy9jUYxVGTFPAgpaFbKyWCYvEHnGVhiw7ybeQoHUPX5+iAJpXzMjZeT1ND33M71RGY/RCEdr4JgJ6HY5hnOMicnpiQJc9LCD0zBtInZOM66btxKXuRrBz2FseM9aJ9I/kk2tgKv2zS8OGAiN4KOmJdftiwXlKPbzUnUoztm2kUZ7NeCx1K8z1toF1Xh/hmJIuOJEv120rhJlio1j6mw1bjw9lL+UBnrV8kP6ORjL/WsHL3qoO+fE4SHi2C1trdtLPf0s4PRlp9eU9oCe4GvVeSmFG+iModjWFW2kONPjkMV6HT3jJJQvsu7qofokpdCSpYMYfIzZXXYeO+bYQ0BsIPY5f8VpKGUz3z+TNu53hbucS/irwlSbEBVNfz15a+8cG1p+XwxERNtgT7wEt0aH4694GuGXwEV5FxEKnlgq/mxuInQsInlw4AAMj5lL1DyU8EJ1NBwqfYF3CSGypTaetX7/DHs9paD5OETLdpkH6R21csUAEc1xqQXNsNIpWpdKcz6eh5F8wao12JtNAANuQv+CwOBmKrZ+DalcnmdTHwPz65+SSfQIOaq2H7GIX3jdGEq6rxOCXwBMoefkORDxbCcs64sBzbDZUfptHG3bmcX9gK/atV4Vb+3bjxW8SdHduGFUE9VLfFw+2w8f41ewS1bcO4vCzMewkBCA+8gWGXWB0uv6DncLbYbamPZpYL6Z9Q06ncbETXrxZyZpe8rDrlhUEqCTzuKxBKkm7Q9P0WkAt9QGJqmnCnNUvaKt5LhisBtj47wEJy16FwllvUdg3kC7dK+C4yvsoG6XNH2eMoMP6veCqqQW/7TdQuPhX9it/wMeHa/AckoC1AregNEWLKs9380W3KdwiagYnjvti7glEpzuP0FrnMKTHJPDtZZl887M9bgq7gqeaBClG3gSWOK/hoiO5GHPgL1q7dULTjhE4q7cFp571xKPvfoCF8EpU+i0ETe1HcdSFcEzbsgliz/lyxig5SLOeybMvdcN8c1+KjovjV34ykOSZSoK6eyhn4iNeJiVIyisr2NWwBudNFqN/zZd5x/V5vHypKYSeimcfnVOwd/4y/JafyhV9ahQUtgxONX3naUPP3UiuAnTPGcNSW036on0HxE714s5nP/j0nBEcsyURnJfIkovXeuwaKOC6wJGw+89HPAzV8GarA427OBLax+9DHyM5Mi08yGlHjKhgx0M6900XVCx7ONJsIxle2wzj6jJw4rpcelAlx9OeK/HHySM4aGkajZGxgqCM39Dxup2u1pdgy/thGFhtjbwrmbSND9FeAYT92fvBYogbVtavg7glMXTyehEl9PbzJZlPMOuROh86JMr9lhawvjSdT6fpg8OOEPR/n0EFVr/Z01kK+ic58vwZK1FPzZZSNXfx594GlBquDp7SHvijaSLu7rhLS6+ewH5NUX7yJpSaH1aB28bd/PW5FszK0Ycqo5Fov6mB/kXo8PfHFnzQ+zvJb7nAOw0VYayQH34+cY6DDUfChkurWbW2GNUkOijSVRSvkRY7GUzkM92bcMqaTdiv6kvWBjaQU/kOLxXo0veEJNoTGkKKrQn4doEDvhuWyiragXTc3xhnKFrDtDRd8D79F4pGP+eMwiB6Y/YOxMKvQPBiYT7Q10E6gevhcKoluEXVY0fwWJ5ssg29VR1Qqug5fmr9yTPlvkJqnyyNem9ON+yVoMPrJSi9q8Pk7iD6HB8L8hfbID/wPi7pP45v3G+A0BlbrjIQgrv6VyhtgRo3vXlGDkUPSK3YEfX959HSyyeouDkQJd7qsNzdiVCWu5AFHVtBetRjmDKqhBpy3uO6t2Hweos6vxQt5bAbdyF+sRHcvFPLDbkKMErkFhmeXY3BCQ9ocTZzZ9NiXiPsBg/vZkHaSIDFdTNRTSkazx4VQf/psrBnjSfkV4uQ+MQdLPs7jVXeGsPYFzYQnrGGbgd8Rs27Pqx2v4FNpe1QPPwUr94iA7T6PksYu8P68SMgxt6LVDMY+OMVPlq/FJQT3XnYnRugHPSOhvXeo38DO+nkxolg2NEHgbVqoCCQxo67bMhcfhIt9/tGJ7Z4QubCUkiLziGLFCtwL0ik/REHwFHoNO9Yl0MSR5dx+dYIMp/yAs7s1WIf6Wd0ePl4qBccpG0L/oPIxnrKfB/Kxs4TwORGIvn7LSW//mnQ13wHnTaMgOmJaZD5cQ/PfvqbpaxzyCEmk7I0zWlGQifpTLoPEbM34IEoS3C8rA0lBhZ0834PC2eYs+0EczJp0YJr4tdh5ehmmBTvAuXRakP+cY3/+74Khr/Oh3e6F1FAMRROnTrPbb9vguxOJXwFa/CcphUYP7kNay6uI9e0PXh3sj9Yxp5k36AsrurNo3Cj3yhrVARL/gyD9R0xOGxiDJ/P/wOPRVtgeBtirdI4KvZU45MJE8nC+jx8sJYC2S4T6h/mwEtXHIJM717+pyAOlTPfoOn59VCcksSDN+7Rpg5ZeFxhBRXaRynCjPCg/xw6f6YV4+yYrloCuLVPBZEzWrxSQhJC1F/RS9oGeo3ZcNtoAki4tNC8mf+BIgixSXgqNvqLYUezMvhZ2nC1txcUb1nAMbGOkHUrDrZM6cZWt0FcYa2FI98bs6fqcDix+wPXjR8P03bvoea1Bzl6DVPDyygu6atnh/peOvKfFP7eIQsy7xiP73oCm7ISaa6rEw2bXkSiVh+gU2YE+zUthMRf38HMYhxo5gsx1xXy3FnZVBwizkXm92GXyD3eHqlFj+MVyPGwHh0ok4S5s6bxfZUsjFPooxrLbDhMgrTpTyc1vZzB/o9auVVMEGfvngATr1zkmqxJENnSgtb7K8HPZz4caEvC3w8caN5GUz5UGodKt01B+2csVhb5s16WDn3ad5+KflXyr6fzKfhjGOu5LWeHFwtBer0S3Jkggzu2TSAvudtQW36DbilOgr2dalxgowLNg9q89aQR+e2xhWGuxTzVeA1yxEq2rEnlbWJv2bPuJxvvy+O+vdOp8owmvzQGeNWZwjuOplDasmY6lzyWJ+2JYOnXj4j7hanA2BSfrq/C+F/S4OihhM0zJrB7SD+INqbhY8sEUlzoRuuG/CMn2w/GFE+mdBMpiPCrgj9moVRm+AOah5+hY6dvYp52KAZZddGu0w9YuOYIeb+Ugv1Vo1D/aQNX6LTA9UggO6dbJB2ZgA/vD6C81kk8t3g8lX8xhTqhCXDCJIU7ri4Bi+lv8IbbdnqjeBGKhvJuQ5sdzD1aQvbv1MD+cxPA3bvoM+o4WNybA8NWusGuEc1c1nuczygVkFdjFkZOsAbn/ktY8mo6HRK3huBTydz42p5qA+/QmxsbYdSRPPJZvo6f5UvAFrGX3D5MgbuHT8YdptvpStwgWV8TgzV6LjT//GIwObkfcwLkoFOzgxLUfGHRrABuC7wA202GuDP6JyoKb6Zc0VO4evU5EBUygCeiB9kh6QJMebGcpstWseb54zR1yU++1N+ONkOa3C9wmtdUGEDe8UNQ7xVG96P/g4Yl20F2Wx6urCU+OL6Fq6bOoVVNmbCWRGFXgx842/TRyftzIOGxGY/zCGInUVMcseUPnd+iQukvM+HkRlso++3Oub8WQKJiC4367zufePKCCpO38MVYMwr7Ws5OPqkUuY9B4EUbqpzzgLbiKfC5HFn2PxFY+2sJrBwUwn13jKnYIpGyTinDRZ7JJ1uO8Px9YihVOo38uhaAjGs/LB3M40vlE7B7/3C0+AjQMncDeupqw5gNB+GBTSg+VU4cmoM+3raPomLhUBTQeD80e1145aCJwpIaZJ3ylqbNrOKA15IsVjqKfbb28u4MS5K/ksTrOzTgzWddXlsaQ+euXqOtXQ8hb/UpbjQpgde3e/CTwj+wrZXggf8s4Hj8PHZrX8YnEmRhXWMZnXTxADnHchrT1QpLJydhdsxnzNfXhXU/76Nbrgt4Hd5A13q2Y+jh79AZmw2vV9/Hv/tyQbhmC7Y/UoNvjxfh+zvpfPPMQ6wRvMLrEpu4cI4BFdWOgwWXazDf+DTsFhsOFXWzYM71HM7W/8VHNR3QceY4uvkultSPm0CFugHs2n4Vhd8Yw94h1ric8I9H7BKDiKiT+OrHZpzxSJMPGybSWPWn6BFvgPYLx4KNpAZrrI7gUtfF9LlbgWVtdMl8qSVKd/nguTRdxLY9eGarNmybboOZe5WgzUeOBytKoHlZENumL+LLNzzw4LIihnVMkTdlQHV6Ll/eUA8Xri/mN2PjcN6bVHr8WxEGm9VZrDufG54sQc0kI2ifcgPGbTEnhxmREKVgR3u2upBG3nLUvFNEba8t6ELLYypbbQR3l9jzg/++cbOFLB6tU8Md1StRxlUHK+Ynwo5b4lQlH8atLgIw13olOdV1wro+EbgQG4vzCufSkVf+eGt/Ph7jXhLOCSL5Tj2o3V+AkXEFcHLTb/RbfpM+tubAWtGxdKS3AsPt3ODcfm06v8gMXGeag3lxFC9Oa6Cn/sRrzUfjyG33qX/bAG558Ib8n+7kLWtFIHupA5UkGpDAPWn+cvMWPQorYufoOn534Qh/tpTCu2uncu2boRyfIw6Jnr48b1UrOikpUMD7lfh6ayF2XxlD44KeUcyheGw8qgyiikKkc0AEVqrVgOrLxZTeWkNNq+fjX9O1XN9xHqPHptJwwyGGsfuP3wdKY02qKoYti+URU55CvXcgxSiKYK/tIJ2svslbh7jE29wDRiaZ4zONaaS4ez3f8V7Ez3g56/Y0QFF9PnnfSOA1wTbw91AqrhAToEP2jnQ+aRk/zUqAuUoHoObaS7axHYn1iw3BKEceckqroEAtkzS8qlAhvIkFso5gkq0vaH5/w3lCx3nj3UCaUyULJn534PRpedLT2cTmFzqprHEnnD0+k7ZvN6PtjwHs59QxJqhC1G1/kj5zFJcsX0NdQ/0ad3stldVs58rNi2h7Qjd1lqZQ22VNSP4ZhFsEL/GHU94oGzCDjhekQOWoHNqta0Kf3NUxbE8pxkpowZcRZznccRXpL9KllhORKHpVhO0kpVhL6TprXO4D9TGVIH7FAhTm3sEHxcVEsxrJduVjfHeqDCskr8BOVR/cOHsaGZZr4sqjE+D+I08qUzSAmytU8etmBy4VFsBPUkqwR2McbBIcxW9XqkGxxzg4J9LGO1XuwJVeL3K9mAJ6kd34W+cy2t4uw5C7XTgvZT1KNAvDxoLNOGdjEa4wiWCvl5/ZefgvPO26EEa9Pw3isQ40YShDb+WZwISCHswct5QuVDyE0/3qeFRyNFwIDYE350NgsdFavnFyHT98JAp7J9TSR10v2vFYnx+qqKBrrQD9fVzDw22foMp/O/AVP8TYK4KQPHiYr02ZS2cOL8ZVtdtJPGUhyhyrhITGF7hF3gJdNZXJuoDBWmkO2Bm0ww27GaB/eCquaRgPYlPHY+uE91j0bSLT8b/s/kAPGifpUJeiHQ8zeAi/V+zFKyku9GfiTKz9DTD9oxp+Kl2Gky6bw+uN++jyuDEcv205Kaa0YurmaFpprsUxh/ay7/5i9pHZgIMmKiBSMA3NX+5lV5MHuM53JW7cWk2PuuaT+KN4iO9cQmppQWjnpQulJ37x6EOmiAN/eYrnPvqp9BTjbYd82EUFJStGoVdpNbYttwS/+nJY1vOX56QyxZ75AmuufIPUlB/kO0sRrY/cBq98S7TZaAZShrE4fNM4WmfzEa4dloVx0ftRYIcF5+jF4eQ6LTjW/JG7hzgn4VI4ee2+SdMPKOIj1xPwhcLQQbGXsrfUsfB8N4qsWsa5j1Xh964XHPyumLLzdsOLFVageSoWl9+6gTPupOO9w4N8f5ktNwupgFZ6FRtbT4e7Ls95ZexZmtrRx1bPI7DwSxZrNAwxVstCeDFRGQKkgkEVp/OHuj0UPtqOrX52spP0JQjpDYSa2ZtQOWonXlBRAY30WPQvCKEtWt+wW28FDeT4sE/oDVjcWIOt//5gr6MRdS83gPQx+TxiZQ5I276D59sXcWzoJjjxYxRqHljKLww+Udf3KfTirxKI1Xmiz7Y7oHu9CkuHXeQ+N30q/6pPXgcP86OXdWS1PBRitMcAawuT4LKFfCFJkCqq7SlJsYg1NmQOrbvAOVIz0CPwBnQOCsFC+14a5WVCE676s9A/ATi2Mwp7d28nV+nZMKFyMwSv3Qw3RQ1AXWgnvB9ZBjaZ60Da6gzMWG2PfRdk8b87N7jBfQoNP7iJsirHQL2REoT9uUTKfXt5W7gYC24TRDupLn4v/RMifz6B6K9z8ZLGKFBJ2o0l39/g1LhYjHIWgX/5C5ga41G9fA/HyepTxYsQuFchBZGzf6HTS39+tFEAf8ZH0zSaglu3LYLillW85m89JTZfokvRAMoPtrH8gl6eUz4O7ywXBrbw4H8HtfDE7834qzoapzoGgfhGIQj32ErCv+Rp54jjkPLdBisrQvHZrGowXV7DzmdkOWXZJVotNcSnz1+B2kglPDp8JAS6+8NooSzs+CPH87cV0IbDaeSrMpX9CmSgyLCBVwn5gInLHM4dNo/b1a9D8SU9TO+8CeF/YzhJQRUWVJtAc/BFSD/7Fw22nuaC3tfAIb9RvfcRfQ8f4KZnwvzC5DSLTTaAoNcbaXZaIOnfr6CDH3Rx2rvJ8EVoAK/XDeLF/q+w6XcsXuwaD77WsngzOQhLYrT54HlL3Lj4NFy2ToOxY6eD3/B4fLh7KjxUNAE7/VaeX+sAL+efhTYZW6rNzMZbj4zJzCefg5VHYluEJVxfoQWh98Tgj9cVisULXOU5nF/fLeb+87fZKD4UdoZUwF+ZAZyiN/L/7f+/VxREcSafh65aKUxtEaVE3TU08lw9rSpz50m28ZCi9wyhQhyEkiMoQ3IXyXaOoknhwiz9rRh2tIeiZJM5frlXRZNWrsCYUeJgKVgHpv8Wo/+UbM7Xq+SueXdB7NAWiDp7ncdPV8S83l/k+NoQDh87hrJJW1DD/R//7o7Est9dqPnRkr52PGCcfBVDTl7Fx7a6kDuQxWG1ZbTpojzUOg+H5w5IzvQbTp7Xg7d1q2Besg561U2CmFMLcGb2fOyb9YeWngrjQJM5GHzHBSTW7MZq8QoYfGtBOyLGQLm7GU/X/I+nBQTQ8J5x5FVnAFpOmVD11BDnJIXDhXkuWORnCZVbhNG0oIRFDApQpfMSZmovQGUjH/r3SBuSwl+AwPJ2SGmwBby9CMxuLkHJ2330zvopj1iwFmZt24UHtWbQaOGuoXyWwKBXhnBp1T3WfmrD2pePwHatHHAafRTyHC05R6aEGsN/UrvvU/b0UIQvl16R+K2dNHNdIYZlqnCvjQa3bxEg12UBcFBdjfaPm888QQISFt1C28kC2Ja7A9KtQuGM1Xl+5acNOnO8cYvbCj52SRlGGDJsKF8PY7Zqkfy4ZIyauJTsb1lRnFE+7l+2hBInu9MJjSJU+KQJqxfMxUx/GdLcOhErJkXzcsOzvOjCK07bnUGhGitZOGYZPc7Rh/NKzfjXV4Pn6v2Dy2nulBC1BSzUnPCy5yGwC5bF6DQPSvEUHXKExbh52S50rM3G3FB9DvIeja0uXTy1Rxg/u8qj+4VeCI5Rh4d7xajglhILKsRSxIRCypyWAeNHNGP24kLo//oVd1fEoXSlDPiU78InrtagVc28aOi8i9QY8pYHcXDrWTqdyLpBrd7p/EhZCTQvTyL3B5s5fUUr5Nj6Yb6REU3WM8ND48XB3OUZOukL8LoqCbDvOE3Zpzzo7apgMPW9BwkvmE9HKpDH7gvw8XoBfP8kysOyFGHBW3naumgHjVFfRvfMo1DxtAimFV+jssKz1DzjM8k7TwerawaQ5vUUre69xml2E9D/jQDeGeeKE58cwvEGBrTwrgukt0zl+PGioKmei3090jhwcRR4TbzFbSUz+e7JLrw4bhoMxFXheoOpfKBMBE4sdYewI8Uce02JNCPCKWHJ/75Xeh627hemG0dd2CBlLw/YCYGsiRPFplrCo4TD3NJ3AIrMl8GJiqH+ePqQvde0YO6aNEo2lIMXrwv5Stx1zvn2k/pt/qNxmyLwmnUTLk77Tc2iSRjtvB3tFWSgIaIa/eWV6bQow1zK4/J0ZSh33IMejrdxa/FoXrpVApZZiIDkocPY6LaRqoTTYOnXIH5mUQKVpX74U0sPyhz3w1XBAE6ZJwatuyShJ0SbG4dc3Ce9gVbuHMcuT3Zj5Do/2P50NedWBuLaWcqwaMZS3jWiD4z+ajMea8aT2TdhQVM/Sly1oNNxufQ2ZTE4XzGArb90eT9+J82MxdizNRZNol/BvoFpOHbebJ7XnA4npxfQ2B3msPfSe15nM5QlAj5ALcgip7/zHu/VaLTjNC/7doc8nR7wPnuA5qfylFrbTJmOz/iJrCote5TEY2dbcf/GRjrcV8idGY74odkcvsR68eYgA5axe0aibnEYnbsbTa+78x4JIdaPOoPV4TlgJKwCTl3LoUZCi+5dekL9u1bBMZ7PIqbXMWB2DXukTmHBVmmwj1cG6TP25LpLH217Csni7ByKio5FLRlNspGppz7fMKiUzyG/zPEwKaUGul2O47st6ayyaSb9beqA79KjQCTlI4uLDnXt2DwY+50g2lkOB5ykIfr20Oy3uGNV8gt6L5ZPa5pyecL1lxByMxe9fcfCwnvGkBJnjE+sbpDl98k42sEd//Rew6n7IyHQOhJy/FNhv54FOA8EofOGAN5m/Ys+LTwDVvsFMVZ+OPCiToiyNYKS5FZ41qUBHiEL+Gd6Eu7GL3izq5B0t3Vh5Yn5Q470kgzXX0BJ6Svw8JYa/AgYhCUKxVQ0TAm6m3/Q5ncr2OL8U/rhM8gKh4tw7YAsap4cCzpKd6lDW4FHanTjW9l8tPJ1ZflScbTPVsDGkMMk0dSCkX+0QXXBTlpbYMo3c97h53dtKC0wFY+fKOXn8/fQjuclLLrnNFenyUB3lgI8tymHpPZp+LQ4np/0afGG+r+gdXYRred0bu/yh8M51jCzVA4qdBqo0laHLns14GBKIF/8PQwNtr0D99T3VLlgLA+80QWhdxew1eIbdUbOw0IpM/gy7hp4xUZxilktHd75kMeMXgK/NxO4G3ykv5fCsExmEBs7D/LH8pNQdFCRLaUD8XPVL1a/84Va3gBImMzCZwKFoCSbzJsGFtGUwxLQb19Hl1eNp6qFT3h8SAafOGQKkrOO8CPbWNJ6MozLG0bibIUVlO6VBbPPqmN68ENW3BcACrW2sDFqGydoLOK0hDXcp6MJjhJn2G76HCz9bQgHlrXx8azTaNwvBPZvgWKH78Gy43NhqZEdHXJL5c1mQ5khYYVBx1fgZNMdpAZaYNM2mx8532PLz2vg3u1VdOyIFS3I/s3TitxY3ns9nJPfxr2xY2D/9gF0LXXCv1F6YPnVAsa/NAc1bwmYK/SJEtbEY3GfMF2QN4STdhlDvJlI0/uvgXrsA6orXI3RYlM5d2Q5Xg5Mg3PGe1COtGFhySbI8vBCVc8YDGxRJG8vMz7Q4QxJiU3ku3MfWJ4yQb93AEeGclK2/yJF6YVz9MhsPKX6C0xPmOGOrjwQ8FWkSrm9ZDRCF1pDiKy2L8apZ2tQIHUrt2sLYESzCZ+Ny6FyL2UOPniCD7lYQcKux+TscZG3DxjBVdODvMzdEEt7A8g1bxq/7K8jHWsT9P1hDB2PxGhhvR1JT27jX3UClHfgJbiF5+G4rMEhvthPA3mlZG+oDRqPXxDmmNGLcR/o6rdRcHPyctz/WJ2ue+Tj9fa3JHQymQpPa0NU7TisVM3nV2d92P2IM5cv6+Kz93z4yNMG2OmYgQ2Rh1nVXAUKt2/gNS3t7DPSGUed/g1fl7iCl60HCsmZgFl/DClbbiTVfE2wtBNhDb1q/r04ETP7lFG2YTMX6r/Bv+397BERT77GE1jolyFInY8hxRxRMDffSO8aBIFixNhfbxbnKLdTQaYoWuwK4ebNo2BCbTLYT24h9df6ZCnwjsNMdsDqtEa+MkOWH7d84pjPNVizlsFJ0IzrotyJ9x8hL0kXsJr+ivanLcaUwB68NHoyqJ5aRC+Mx8B4g3V0SnUvT9hSCBX+S/jnni62fi0MjTN3g8XoJnhx/BxfqzcHDzkHmrJNnYO2n4SCXAP4Mnc1q+q+prp7g9RzYAppvyjm+XeHwybxBdx9wAEGb/gRVbfSeyV9kooZi8HhV7Dg0gJus7nLU78Mg2rDZooe/ZCmPfLi28rJtDppDR8LKCeXQF84tXcjLfHWgRG+4+Fb2G+4lA/kOsaZk+uC0LPbml007Nh/gh91HJ1MNwNsaBZogjIUoFHBH4jx1ePv3fPp5rtwQN/7qCKxA7tvSMHOnbPYM0YLyH8ujDCp5OvBYZj+W4ageoBEXcI5vvw6XTvuylOXBdPfb8bwX2gw9/TF0eTlGtR7v57l1JeAcs4qXOtxli9/CQLdrA+sOmZo/5k95oXFKfRs2BEKUPHl9VOzOOC/Cpwrs5oMzp5lpZjZ6DFWCkijA8XPFuPsp384pew2zZ9hQM9LJ8FKm53gc6eED4s94Gqx4RDZL8m3N6/kvFEN6HA8HMvMc8li9WRyzuxHf7fNaOgzBRSH8i48+is/l5Lm7WLBeKljATiaTGSbah2U+nEOaMlF3liwjp83jQb5hzH4vfYAKYcPh6r1eiy/8ABd2GRMLgFLMVF9GMRYHmfVN0aw7IEpBQYcJ+l/epx8rg9nHXkFN76oQV3NGcq74o41j+eBTIwJnK35Cpibx9dfuNHo+AFUyhAngQhfajBLxpDonyj39wqEq+lCn3oZG2SLkmj/U8hvHsW+jt9omMUtrH8QBO57VkLk3VOIFcPASSqTaN4kkPr4DzcXWPDtcy946Q8XWBLZwJOeT8VG/Q/kGC0IRfZr6erpT/j2rj94Gj/nXYmpHKDPBLnf4XvhanDYlkxRXwzBY9QE2C51CNbLJOBSXENT1rah2Ut/WqJXAhu+HCWnCBtKWSMEpabOpEP3IFqujcs+zQDT2nCgt7dZ1/gBrv2ogJtc3oCCrTy8Wsx0a3YiiHWLg4L4ChZaKMy2+j842+kzWj9exCNnDKf9p0zBafc+XnHHh/d+eQtCYveg78MGOvM2Dxp3J9DbSelQLvWFbrQbgn+DMZtLtg3lqjyGLdfiAyWn8bKXCtvca6eRwRWQclqQ/00SBk/tWtTYshYNXf5yo/Z5lo/aBLe908nuuhTVzZjPi+8cQdFeC5DbdxnCThMmGC7hUPkLfO7qcnzd+oSqG2K4R9odJZWvYN1oY9ipkw5NjT8x9Ys3xVpmkcBgAQxXOMQSQ55UrbiG2uco8oZOTSgeswgWffTn+Cv7sDLbnu6lAXZsFgd5DuL71T9oT8Jk6vMf6v2cLTynPRBeJMdRuF0JtJAhXPnhB3P3zeSIiRmsICSHsqutof15Bx0cmYnzG0QwZ0cqLhFayC9trtKmQx9YKqAY7ylKc/sxMRA4/hz31MRz2oxvaDy9giSf7oSnV/fBme/+kH3El6Vuz8WjRw0g5+savj1Dl0VjJpL4qBng6HUYb88exIt3VKFTpZC/+P0Hb16og0vODvI8cpQ+vogl5xmZfE3fnpMsU9BPPo9X1syhj26W9F+XLuQJvmfT7CPk0HaDDw8T4Dyb2dhTpEQPZ0zAsL4V7CgWiFEWovBwRjIscjwLL7ruY5GMJ5SXmZP02b308+EYXHa/Cb63BcFdQTFY9/0TbAggmi34HBR/j6R327PwTrMBmg6o0/3853D8xBzYbqoIMfMB80CFLih4k3yCMVdO6OKe5HOkM8IZPZJaueJ7ARa0jgLH/XnsO/YA58zxwsRv1eh6voobhwmC3nVD8NQwhUnHXcD7qA3sHhvOHp8/ssPCVLZ6KY2/6jpxR9ZRTEnqAbf9+3CZ1HvIny4FimLStMD7CY7T/AQhm47jDXbjzbWhpLz/EWPgNErxKWKfOl2YZPMTAnXOk8XJf3R43iFc09dF0T3FMDMmGeM+ZsDAQD8++SUMuktbKLhsIXfEnaMnQpo8LPQ8ly52RpeGcLieXI8hkZ0QNm00FOj85s23HWGcUTJId74Ef+8eyN9/Bj8vE4NLAnep8KIICuqNBtnT0/Bt1m4yFv1Ht2Rvcf7gAZZqd8ErrtasHXOXZbe8h1VHbGGk41rigluYdPE/OjE3lW85VVNz2yCnCmvjSSkP1nK7TzGRoyDyzg8yNP/G67sTwWnoDOvKivJP/Usgb12K54yyycT6Nfu2GEO8/Hx2s9CgQy9D4VfmTPq9rIjqnw116bUl9FTNlfPcjGF6qBBsFcyip5/M6IN+Hdrvi8BAvEYWK6bzz5wl2HtjDv6cEIiax0fD8h8nsEnwL2/f6YnOT7qArwmxSeseTvztQpfV28C2R5hZRxJ+LlrFIa/SWfqqDldkLOHL6kuoX0OXFvuOx7Bv1jT+bQ5E/JGB5VtrKNk/k2wGv8OCrasogRPBaEUJS/j3sLGeIas7WML98+NhkWoSagWNAaPt/1jY4ADlq0+HUOdG1LdbQ7k97jSq+i/cFSZYNFWdk+LToEDainSnu6G8814YnhuDqY52tL0QqFzgF2tfMwM9l+u0croWikoP41r7i1h57ROusMznuFG92Od4hKYZZeJCLTNo7dkFAgUfOG1/H6mYviLHfWN4eHs6XnMIhkRLT3ig+x9orEO49ewO+TuV4NevctBstJUTjD+jhv07rk8PIuHAUegcEsZH0nShzSQa45O+cE7lTHgllschEVfokv8DSFjxhGf6KIPCPTvM95sEpeVJ6PZYkf/bchxMLY/Q8dhiCBt9FedcPYzVRsd5ztM97KUyAbodLsEz/3Iq+tMADnFbeXnUdh6ZuRgCvxzCQ2vqhrqwlBrOjIGBCT/p3JwTJPJamR5NWAdJV9aytlIriG7bTlFiBSxy5iVFlojBP4mP/0fRef+F9HBx/IyShpRSmpRKWlTaixAyKmQkRMoWEQ1U1leLiBRZLQplpGSkQUpG0ZAWFaWQokHJ0/MX3Pu653zO5/3+6YLOQm26kBBEw7428XrzTvy55Ch8d10BPVrfSSYimzDUEpyjJ1BCSiT3DbSza+5wvp7mx4vfH8AZMYY8PT4BH+16DQpGovBf1iVe0+7NRzX+UEy1CirN/s0xh1ZyUHoKl0lNpG1Twtju2DDo2bUad8rpgXvVJpzgtQCPPJ2B5RdlyYNvoeO/reD+7zN/KDME2rIUv99+DkWKdXQ6LRVGL4vAehEt/lefz9WNS7j8nRekzx0DT/OE0T77BF80zqePfglAVzLpUPkluJecxT0ehiggM4wmLbMAjd9yeBSs2GLDZbqZ9xe3fsrgfeZPMEEJWHz5cvi1JBElc/TgwkpxyHFYgu6LfFG0oxFWtH4k2+o98LA0gD8V5aFr5x0Y/0ENqj5fIueRg9T0oQWu/argX0nDQOOgF9vpWrPp+qMYnCwJr/2kYO+PYPxzuJJGd72kffL9dF5tJW/RrcHcvf649+ASqmyRhn1ZI2HA9gImHjwFIsteg5+JETeFK9PwxFoc3qEKb29GQongcyqZKwjSOStR/e0LWPJDG01OKaHb9F6YeXkS34qJo/QP5hTy2wM25KhC6o/r0OLoxuoBkaB37AJNVjWAtMBYwABpbL9rDhP22NLzEEEYY1xMtRef8RyxPOi+dR7yb8/G0MM3sDlLgSQclbAwN4C3djK8nxuI1ZGCXKFdgmljGT7ojeKZKsE0BY7jbhUB+u25lt8p6YPWmWZUO/YWRq6aBLZVLdCV0099wZfgmMIjUDgmgp+mi7PlbkUou3SUx4R+xvBXrTRcWARTbuXxr39n4HfqGgg62Q+Zso447pclnP1qAzNdn4GZ9jTc8FgTD8Vv5rrws3BSrBM/3VQBWDCSZ0bKwFpFG7i2M5FVc10wS+MF/BaWQS8XT/IWEOAKEXds33wHK7rMYK3FDbx76St/BgsMOzQHAnbPxb1advxioTPVhz2DBa0MM3+Mg2rnxTjpthzvmPMRfy4Q5yi5YjrXNghLM2+Rfawezwgcjme+joZLHW2U++U2X/4WTXN3f+Qr21fT6T8f6fN4efi4upwqld7x5S55QNv9cOXoBl5udQ3/XnUgj99VvKc7EO7JZmCUZBztEPdH90gLSJiSibBoF5y1f0Jnv07n4QHF8G9XEMVn97BFgQv8NpKkVdFKYDFZkrvDPWF5UDB1haiyy+hZeOLdfVTVVEK5caPpgfcrtnmkBDMuP4NC4VTe+XgtisZKEsh/wFMJGqT6egsG7DtCEa9NaPEreciT6+MCjQ0U+GAQyneIwAOL6zC8bBo8TVYHlTWfoefZdNabOBy8tB5QupQ5v84TAONVx/D9impI/zQabHpqOT3XHVVmqGDOt4lweE45GJhHkuLgIzQ4EALrFkbzIZ94ut9hDp+PG2CjiiuEa1nD5cg2TspIBOM/AawVnk5H07JZaNtLcnc4wmLbhXCPsTT4BkwEIdlhFD7uPU79F4W4fBcJTt1LG/bNJl1/P5icdJVjfvzGooUq4OFmSFidixppg7z9VBiMdLPHQ2/s4JBLAb85moitTQq8JmMSzLBkiPYVIsHFlpD4sh2boIqdHOxw+M1LbN+Wws+V8rC/3woat8/jjSZuNNHhOia/20sFxX585Oh/1KiryKPm61HiNSW0ypcGgfEb4U9TBPbnjOWoF/N44jNRjna7ybrz5HFXRzuLaUSApfM4kJstStrjF/OzHevwzXETtH6zFocdUUGbVya4Umc+urxdxqdaJED7wgdMy5yL+4OyqV54Cj4948nhZuJgtfgQVb19Cd+mB6B6ohDoL3qN7xz7af2uw9i/0obMVo+E80L7cc3uJMx9MBOd8QGs6NaBZ/q17N26ny+taCTZGXrkdtOTSx/EUU/tM7i6IIGU3/bj6korkOQ1OGfqDFxac5Ae3ZFEhcW5LL9IGBVWXKHvc1Lp8xRpMAlThMh3ilxVUAJN9U2Y7SBCt17aktwPC2xpeANHd5zAsPbdqKknAo+Ph9KppGQceOpJmSleHDfULbPWFbP58RY0ODiC720X59UXNcH3rDQtH1zKb5QOk93TBra49RTvNF8FA9eZqKd9kiap3yTtKQgnXByx5ZwlhNQH44XPbTBJWh5HKQqDb0s+rptmD3OyhCl4mwV8PaBCGQ+v8dx5k2FDyXt86FmOdwRmk5FwKZz50w0/N0bjxj5LaLc7wNoh4XSntxjUbnRSWDTj7aK7+N+AMN/VrqNv/3ToGRjA7uEGaDrfALbGT6Crskq4I6cLB1a/ImvXbsqb7w1eS19Q814liJfNo5av/tRudIWDdgVyrkYey0pvhRfZe+kNOUFtYAelWYwCa8mbXGbqix81V8HxKQ8g4OwX+F4Uwtd+zIb+66dpwSJRLoswhMKcSLDzyuL9x5dh7BMbkBQV4VpHZcqvM6H78ko4p3yA9wzTg/lViWwn7s977zlQUcMV1vUNgX/9eux8toBD6iVY9GwS9cySgMCyfyBkNYelSx6ibFg1uk3qZmu7CZjWvA6Ssmyx5PAA6YeOA3uTZSy58CNklgfT9ctHIFJgCRRufsMlxcXY4e2Fva+GD8nrFHgUC1Qo68zRM2W46S9x34nd5Hj8H11Ym0N1WwNpasNZHH9NBtQqEnlisCKmrjTiA5u9OP5PBa2ZPxl3vOvmgLnppJweTsujBCDkZB+tlquGWwGTwaH0K3+bNgovl/zGvmk/ef4pUSiWzOXmdA0o2N7OysGj8WypEam7RWB43wt8vdsPRlTYgWm2Go0tf4Q593TBVk+YI3KSOH1LOvto+cGdG9PRZaU/9z9Pwv9OqWH6mia6FCsA+0cAPPulB35D3H173TIOuzse4+XHYM2OX9j3vAp71PRJeKcyGBu8Js2nP2FYbB1tW2WOzzKN4FuLDtse9IGAmoe0WGQRLqmVBrXv6XT8YRYkzX1Jh8xHQcG5y7RqvB9Mq2mEisEySEwfgH/xJuDrIQcD2w5R+yJxWliexIphPjz3fRbnXE/Gr2MrIaZCAi5utQA9fxHAFjV2O1aDX5aWU9GVYP6qdIpc3GvhvzYBWuy9nf/ON4Yl8pYsJlIIx15XgTOlYd7mxRT9+Bo52J3CFzOHdkZ9NTRcMoJtR4wh2LwJ5EabYTwNhyP6wihT3cGeTavBeMkx/KYRzGPzx8PK+7YcYbgdTk1zprsdkZCfP4HUzCowbf43GhFiR5fdmujVXm1Ii0jhG8b6ULellWLftMOKjRv4dV89OcrNQ42oENqnm4ZfLiqB1dsq1J43gzX2JXNMxyaSCvnGU8J7sccmEV5triOZs3YcY60AA/JjUcdUE5T2/IbZE4Qo93oqWAyWQ9V0TXb0Pktrrc4N3U1Z6Cy8yZYnH7KTdj8an9xFaxW3cHP0Qr504T17Vl7Gd0uC4fddQ5Af9hiPLRbBnWe28bU2f1K/1kf33YW56cxCOny2hKMCzSDNG0Hwugxn1yzBiyWF8CWlHs+8CuXdP+dA2GlznLFrDq2rGQWbfEVgp/5ddlANpFcbj1JsWRruc1wNsgJr8aW2OY+IJ95ZIsGXloyD9pZ/oK1Vgv9ln4bcyd7c4BXLCWc2gYp7LMj8HImtPhakricHfofmYnipCng9cce2jB1cqP+UBS4kwo6EYLgYHMUetbvIzmEUJMF+Lu5YSXuWfua6L1sg8FkprZ8z1Knyw8CtYhvdSjnHNHkcnPMUoDNdnjSvOJWHFThB1r4MfOWZxAu0kqA0qh6ufNgKU5YbgaPn+iHmdcTDtztJQncMeupI0KhNK0HdPhften3BuW8h12kDNBq3cXNRJgc9n0R7dAah4/h6fGjsBcmd7riy4yPPcVuHVy7LwQgrQR7fm04fHtVzdec8Fr4hCRc7prHfvKtUlRmA91XrgY5MBikVNZi1/jUeOicJldF3+MJqC2xfl4lteV6Yp3yeLxuI4pxVivBbezyL+wfCbgMluLYog8y3ucDRD+Ox7FIhbn0pAMvfpHKUMUP65WxutT7Hh/piwNjsBicKn+K01Frwn7MdQ08/h5LXjqR5XAUaWwPpzdckdHZ2Y4PP7zjywXxSgGrOmiyJrcucwKX5FNR6K8D3qOX0NaGFWj3X4BVbaYr78o/qdr+HHyaCfC7BmXUjP2LBkpEQvbsHTcorOGu5PvxUnw7Ll16GhgXaeNpnCp2M1KLHPo8paYYgtEgMsWqaMveW9XLT9n2c+lSPIfE7ZTrEw6tCB5j+owe6HghA+4+pPOaTH0eUbKL6qkFqqZ9CUwfKQCf5Ft50iAH1iVZo91AKDDaY0npxDzZZJgx5iQD/Bu35+ImFlGd3F85n7MBar+UcvXzo+3xbj5dtKig9+B1bijjjascAFDcqRPExZ+Hl7gRWO7OFs+cD5IQmstFkTdL4OI9fLQuHpU/bcdf0bJb3XsnZSbv4SuEUHPfNCrSe3OZbuTZ0Y1UgbDlXi7tfhXP/aE2uOZZLoy6LgmF/OurXaMKoEX1gudcSHY8cAQEnV2ieuxdUk+pohpUw3PIxBSn1xxhnaATLFabjh2PFKFb5GFV/eWPmzzGQpnmDxMs/0uCyUHhmbAwb1xH0NTnTr7XTUe1+K81emM8yl3/QFj1ZPCh9jLZnddNJz2UYF68AJ6yeUZCuK8n59dON8e9JqF4T6qd6gcBcaTprvQjKZQ8xXJQHmw9BkH88FiYeFsOv2IKlf37SpX+vqPrzVvb48BrsfuzBr3aW0JCaymdWKcHTlKmgUjCM89ebkteXkfimfhftKi9l1YStWDCBwaZAmK7cNUNvez+6q3QcEhcdB6/QjSTp1gk7M18NsepojpikDqt1JCnJ+yrrJ4rhrhE9qH5YnfLbunmP8kMK9dzIfXuOgc49IdDepo+LveTQ4uhduPFWFmpf16HJjnIwOzgWNAaIkoqMabbBeHi9VRpevN+Cj8Lf40SZUxgNa3neWsTzD3dwx8J+HNMrBiJ/heBq6wsWfnMeLTeegU07xWmLUCleqzGm60FF7JKoglKSlThmnzBsGrzMl9S6aZOAHkV17EVl8Z/oHd7BYjn6+NfmIe5s76AiWRPIvahOLrq7UPBkCh4XbYGQEQfIXEQY/vtkTbP6tbA99gjXTVeDEA9Dtuzvg7WCTaA/vYdiNSzRZuxWtA6V4AvFkfR92gR6IqMCaXeyOUQjiUQPK+Hnqy/xjNhcqEk0gvh1auitHo3rfp3niI0Toce3Gz+1TYUsmoV75M9ix4TnkN/djjq5WRzG53lcuD8amBqCpm4x1G8xwW+Gz/jlmzdQLXGKclJ9qTXqBgQfPAAXB1bSqHFjYFNxFaV6zqXEo+9gz+kglP1jyUVvv+CRbQ2064UYZGtvB6XF8pA+JxeDsxTB8qUuftxVgUqvfPBG/2QOO3AZbsbZYFH6HEjaOgFOeIwh0dNr4MMIAex8FIEnYybRKf3ZsGhtMoQPOef7yZs46IYpKBw4QMEJCjCtZQFdzUvlpBtluDt7Je6cdIB07N/CE0k5DG20AjEjJZRYcBa1TROpUdWdnRXmYy/1g5fYHfxpiuBcYkfjDo2EQfMmKoq5xL/zTFFr1R0W/XiHBU8fpLpOL5CKn4OR3S9woFAF1jcYAMw8B1JiR/j1RkkwfrqfdzQMJz/bR1C2ypWrum/wkU1DOTrkgHXbz/KSXT9o2F07dBIXBze3vzjR0pcaFYzRdU4j651EGNzixZd3H8apr9dRxQ0fXlqjS1cHy2jHPntKXz6CC/5bCTJRQrB0xU0+9/gG2Ss5wvW6VTz1iwNVtmzGMWuYOgMXcor8bb472RL+ez0NBnJHwFodFbqhW8yDOU1QOHgURqns5ezCVVjyoJFS2sTg2H9b8eTGvyzr6Q72367Al/9O8OmRK6FgQTgaSFRwoOUumqFNEG5zl40VP8AGz0VosGQHRE+OB6tgFy4dmQT5qudgvu4w3CMkAB4CsjQ1NovC+4Vh0OMYrHQahv+m74AlvV5g7m9L/bv/Uu6icdAnc48nJ2yGVMtnqHZ4LkSuHkb9q4VwzfnPoH7kOhyubBzyFjnYX7wURs0tpS/+1vQr4R6XJKfTf1v+8ALTkWTZ7s18PIbG/zCDq3cuU1r+Tcpbu4jOST9iP79YCI3/yVNvDpDfzBv8n/kbFpaUBYPMTBaHAZqmeBfWv3mCNxUyOCXKga4258KiDa6867YITZ4jA7/nSOPdl2dR4Pcl/CP/GAU9yrnyqxX2Lsxjx2mzaF/EbhQ6JgDud43p2fYUnlztDP7rr2JpRCs575/IN3UbUfqpHZ7bsZ7PLUeQPfia1K8HQtFGZcgVicW6ZQRxG8+i08MtvEcgBg/7O7G5giLssJiKb+eUgkPjD3S7cxC+va1kH0tnan8ObJexB9USHChJRhgmJbTTHNbjWPCAgbfjUOqVGbyf5QdXhXfSbatq8JilAC69YyFCcQfPFThI11MWg7ngcfqefIi0Dy2ER9fPoFxSJFn9XAkbHHTgyYomsB73CyfPboStYiY8o1aA7kQ3k7eyE4y1zmTRJ5epVsQSVkwJxvh2L1S86MJr3pVAisV33CbRSkuGZYLd39Mg8HwedzfIQK+lA9QeN4acqTfpXaI/uETooviElbhRdwrZ5t3CmJ26FLRMEvZfVsXMQ7Op9uVBdB23n5+CKwYb1GCOqQs9+zuB3LwUmW4pwYWDVlAx8hJmTj5L2rMuwQ3vefRy2nicoSuPsktGkftqZzA30YPBjhm0NfMppXwbzddVffj4wfmwrfM1Kl4OoPqKCjY594GT8gQhd3sRVAvNYBe7HgqzfwwFOrqYkFwL4p8m0O7cclr1Ogl2R6iAk+ROrDdaiBJ/XKhAdCX8J7adv0wywUUtn3Egaz9H9yaQcKc0QEkTjHYtgttRc1DcM5565/mDpJ43eaW204SXhdQi8hBVSmXhfWcw3AtLoZNn5lJZwFOq/Xqapof0kfKJPlr3wRW/azuy0VC3v/t5iiIHNg15mRKMrr4AX1vK8b6UFt/5JMeRwfMoxywU5m6aAAfkzLA2sRfaKoPB99Ui1L+xned2P4ANGR5kPb+YbEtS8HefIZjc0+b06RGsO2s0N79IAIvXUWjUFQD7zvrDGgvAHrHdPOGRInQsM+XfpaO47FwjBFakkYXSJO5XMKdOx2CYmdGAMeU7ic4bwFXFVtDBjXwwZTzWe3qz0TtnfK/sjpVzjWjxMk00nXWTlzWYwzURHfaaXIvGfdn45o0lffv+HdtDc9g92J+DfrzBLW6vqE5MG8o+baLseWspxeQC0ssCfh13gXIqi/BD5UNK12mEiSyLk4e8doVwD47K2wgXZtvj/ks78bOZFKxargDyaWooKlSEsheDSaTPAuosfvPwMdcxNGqIRyQ24YhXOfw0ZTNMDlsPTrequFRoDdkU6EHbuuew+ftveqn/iip/Ted72Vp44PkLvHdlqHMi/+APM2PWVhKF0/NaYa7WdT7eEIfbOzKhQHYJ1to40nwbwpaXrvhJzBosdgnBfRlDUu1QQn/bId+WyYb+6RLQH3id9/lYoMPWhzA89y7YS6uCn/wteGm7FN1Kp4PifGFIFn/JwvK6MKv8K/N9EZhxz53maTLwyjn0QbYKX+2bgbMhFD9ohIHHpoO0ffgN8AZ/krd7xzeCJGHfxIdgXXqV/ny9TdG79OnBf6JY86GWd+TYsJLnKW7u14Oqq/JQ9/4uqmunUOAUTwzKmMKLVu3gzfPzwCNxEoiV+ePYHeMp+LoObAkdi77+mQTfY9iz9A6/e++OSbaiqH11BZx3Xcn7HdbCc381aL/Sjful/7LOG0lIrrnPkteyINBEBO+sFAPR4zugYc0piFWWgXStMTCy3YD0A7ZTueVjegg+9O3SVnQb7YFbWkbAtjGJfOaP7lBfd/EdwXdgneKKTbd14EbFP6qk07DkVBCui2iA/F2/qCFfGr5Zh8OhZ8tRKFOZj+RtoZYtkVjfGIatDwELlB5TypJ5sHaGEDwd3kYDmbPo1Om38O3hJJA1ayapZ9XwU+wvOxeM46LQERjbrw+Xts3CR3IN7Fe5l4S6r0K8uyq8f5bAw5L3g+zbclw/dRNMW2kB97UewYbMcRip/QVHf3hG0euW0vRbpXzaoIQ6S6bQpfdHoIDEoDv0Lv/z7sGno45Q/pb3fGHhHFoV/gxXf8mkQMMAOidii1WbNGDZkQa+u6IL8x3aUPXUHuzbgFT5zpj2T4rC7TWHaZzlCY6YNQ4UWv7QhYz7/GV4AtnPUODWibMRjULh/G4/3hWcR3nvXVHtqCiM+hMFU59qQ8ykM5BgPozs60phT+wWjD3qwCP3VnL4aHUYoaMLyy8vIKWdayHvdAQ0tA1jMvuFPfJ3yMnBCtpHWGDPeWU03mcOje1vIXwhUMrUD+iZVAQtPzpZZ1srzZsfCwELZeDi0QL+st0anNvMef7QneAiJTx0TQ/KTcpQzaAH7N+vhSa1F6wmu4AmS4uAzN9HvORHIzwOOU/rx1ngk1ErgJeMJP+MSihzKgSd2kecenU8xGZsp8cTtWnCrWJObDCltWs1YHO0EgakSmPNHSUW/n6bnS+OhkvNOyDEt59PV6njkymH0bX7BbnETYJqO0d2lBGjB18d0DxLFmTLEznzbC5q7yjgju4urql7C50PPXHHyLvYYC/DplIF7PdGBTbGv2CrvW/JtkOAvBUyaJjqE7rzSQMlHhdDqJM6xBx9ix2LDWHZqTs0Q3gxPRnmCVnvvTjrgimDsQokTJWjz+6dlN5tzU56qjD6707wa5DkO4V/OEprL9ZOZFqT3AXobYj9vWcY9r7BouU6MMJMFWVuzGAHgTlQnvwaDRNvccDHkQhPn0Cu3HwqP1tJ079Zg8eqcbg5qwAVvBtRo66bqo8o0zWzO+R7IwxSm/fhOp3pyFeUYGN+LhgK1kLog3TImDcA8pMv0CvBZ2iVdQ6Ev8pyjfY07potApVnmqFy5wxcPOYOjbJ34/lvxai6WJx263nQfc8kHN44iUVMzKBkmgXqez9ikS/3qTawgb07nVHZY5DeH9uG317PwLvZM6jVHOCS4x7cGqHNWQeCYPu/bzj9HVHCvgvkK3Sa72ocAP0QRQoSFYav4//QotwOUHq9m72l1elwgCgIWx9BGLqz9sf2gvTXLfh5iTYcaSoC0z9NqJ2nSUejmtCh5DLZf1sJc3xc8Gf8aE6UCx9yXmUo5AP8S1sSDBo8qcF1EdqMH0YOtkthXvQj/NX2hp6+X40hv6Sg9Wc4G8xYj4NTDSnu1VGumn6F93+cRRdW3KcQgUiYGreWrNP0YNI7WdQPn441Q3nySB0PBR9DQS4H8dOJdPi+pAmLTR3BW1AabqmcR+PwjbxzqOsa05Wo6pAgxUzzwrTjmexhcI2/7G6BO2s0oeJOKDRpyZCVvQe3P6qCEU6J5GgynouGbYc+8UJiwWRKsGAwejAZddzTcN/0BOSAUlzTP4ZK7J6y4cEtkJ6jxioysVQ5UhR+uWvz7+Sb8DUvmq0j7fGFkgOixi5cIqaHV0744ljHam5Snwz3FufQrvpl0OmwGz98ugLG7zbxtsJYkH2gAFovbHFFynYuvS0JjWfMqfeDK3w92QPr1nznA4+6oPFLE268OZyq/ExYZvoH7FQZBle7h9zWTpEz89/xE7McCneXAxcvFXhtOgFrU1woqKgSTftlIH/gDwjmjERTrZMw/OEjSIkshVXJgTxlcBI4vK/DQMWFPFZACiRvWfHK7Fp8t9cCfq+dDaO8t8BW+UUQlXoRHxXXwb0xoqh+Uh7WqvyGywUzOeniEI+tzoR9b7txjPBL3ui3g53eLsPT4/VZ+vIYMBB/CZcK1uBitwR0s7ODvgEdMgpcwcUHqkFbIJMml7qgjpA5zFmRxE6aEvBS05GLtILxdLkgnRua/c2ninDpghD6v8/Ep9qCkDDdd4iTl1G1dSBdn5Q8NOPvUJcuyVYSqhRv0opCBoH4QkMZli+7gpsrB7HoXBns9S1mBz8nMsj+g1pJ1TSstgTN5MJQ7JEuRI5PgYO3o+H2yd30bF43zC5az9YvxHCx+GXevqEYjyR28PGXCiAR4EOj4h9D8rpm6tSOYfURhdi16Aw3PAilppRmnJjsiaNuy0DGMykw680c4hMnVB5lSJFZv9nwoh9lXanBNZJ/6OTTM6S4Wxv60oLg4+Yn2FZ9h43iLSBuhSwKzKqnr+a/WTGiAqcW50BG1jhoaTGn76xDZwssKWD0ZpLNUoPTR9ZCYkYix86qgfXjFnPkWD2YIenOMeJj+aedNtcfXYFLPreTVM1iGPEvB2J8ruIY79d8294c6iZJ0pyGQkr6VA4Gt6JI9/o7tGy6DS6/t6JmTRwOViEtXKwFx/oKcf2ndRh8ugt/aLbxzuafNK6nnqWGb8b5g+PwuOoW6L0wAl6r3AOJ+0F0dNMsBA1n1P30EP5zO0LGt4g3jw9j+f4CnlZvCKW+NWzXJYkiU5/TqfYoahpliNmtmuRDSmTRdB7RPBdOPpsIMSreiPO1QL98B138VEOL/xZj3kVjGBwUoE0it/DMujCIytGCZ/FJ2ENytGrmIFopVOP0MY2w8GY9jxBQwv9akkFkUg56lIyEyMsl3MgJ3JJlAMfb7sOJFdtY7MperFA9y5MNXnJo7Df8ISgArQISUKZuzXd/h+NM5VxMEemBJxa/cJ3GQr5WkY5/Ni6iEy428Fn8E58ZXYaxSxTo1P0qnm11GS4Ncf6f+GIOvTCIyi9S8cFSKfgYFwO+Td3oM/wgJ8lvYE339VhzsReKRWbghssCbFjqD0Uz5SFmnhvf++zPCmUnYfS5Tlq7phx2RLTx7gd7sbX4Bb6WUKazI01hrb4BTsoK40jxBjLedowaFrZTkF0bb739kYeXJPNVn7cwfJU8BN7Lp9Efv5NmvDq5/dQkP50BGhtshu5mYqRRUIluZdEwXm40fGpmvNmWS36Go6FIZBFOzQpgzZGO/Oi1MJxGWWwu+sKu1+TB+qQYK4AS5j59B1PPnkelF3qQ07EU6nuI7S7V4bC4KoyfOBkGhUy46+s1bnKS4oj3yTjllTc1mJ9FS/FTlC9VwjU97tRtS7By9jne83EsX7VMginDxvDprgiuPWWPXTkfqWvKO55lJMHSY7Rgy5YyyFfaSF2L90H2hw2w9NcSXrJ0BBoeXk+n8p2BXW2xaddoOLRejsqF9tO6yWJoIbQPuj2Wk6njTIxVl8Jtgt9A5bsJChYIQIWqCB0pOQW3xGfhlo0lLBr8g/PPz8Vfp4x5U0I0jVh8jMXEBMDSTJkEFKPpebAWn0j4j6DiCt2Y/ZnmxHShjPREwtws8L5sBvnyRzGkLYGk5XfQi+5tHG/Ywr6qG2CESinKap+DsJJAnm1pBI/uEvSo6bPF8H+w9/IFHogU44wNkhxiWw+HhKeCY/lz+DR3MrSceA2rSrtJUEaUr/ncB2WRDtx6dg/4i3SDaFUklbUYQuFPgAmr43mT9gKKVY2guH4ApZwkzPwSxAueXOMN76eAttZabhSzgTJDa9a9Y0YS95fhRY175CE0nnQXC4CMaSwX1tShpd5LVqtShR++8/mlZj/9cRIEtaiJ5Ht6HEjeFMUxGhewt7iJTI8AxyoYgM/Dk5C5wZ+F/xiBwG45fNVTCG3zb9Df1F4w2W+DR1/7sFmBKlwMiEbHxmEUXRIJZbeX4T+9+zxlrCNWbogEV9tAyPgqANevakNEsi3gWgfSifamz+r9pD36GJn4BJDrUJaXtEXA4xhjzHtkA8LSnlTrfJSeqE7jC4uewcELa8HYaQBSdx5F9coDtNijiJ2jraBy1nrqkmumhPWfaKSfP3zePw5tcg/TpI52XHRYn1on7MPff8Xh8Ashuuf/nSVK13DI8P/wyJRtvDnDFu8XuFD5t0rI25WLZ4o1QGevKLv9NCJz58246Mx6uqJuwjdWhOGItLnw2m8uRGyVpprSUbB6xye6cukc3nncCm9KWviTeStImIrRzHVnYLCxFFJyxMHZexT8CrQizxWPOEg1jlZ/KKQNt/+hfuRzfr4rEbeNsKGQqhBY3q0OgzoncFDHlzV1slEiaZD9sYcfpYfztNFjsemSCUYFi2GfiDXsbniMgn/dKXFBOOfJ7iKNtgc8b70oOm8PhKZPWzj9wTrWu2MCHntCUU3kGehnR0EvukKW+AK2OmjFt4IM6Potef61/xCc7DIA762rcZddJAjGEjt/KcHlMz1JtOQ/Pil1kB6U9qBK4C+oO2cKBxNyyGtMBy5X0GMNmy7ec+g6+1ZP5MT10WAobgtGi7zJ3tIYxBwm4CKX42zdW8GbTm1D+zlX8f2LWbjIZCYa4DcumvIX1mzTgPS9XvQ4biu47lCH2rIv/PlOGlUGbuJ5LgH8NuMDN9p/xpz5ajBhsRElDzvHuP01BU90otlTh+OVliFHS5gHSsOek76yHq2/xzDvZC3uTb3O1h+zaFlJBm7P+8rqnQa8rPk/iDFez4pLkliiSQe0Nrjyjt2h+DZUFcrikI6ff08nfffjg8VP8HCJFK6yncGNZaJwW8MOBz+6cLa8PtVOnw76N3ZS2E5n+PxZHNwtN2HtEXXalKUHf+a503yN/yh1dTitqnpIv84S/S6LHWKvdUNu0o5iJ85BSao8qIZGkeHPH5i/bQeW3HGB+H1toBjjB97XpqF0qSMtGFnMB+9bwaSgMBJem03r9ufBhEuWnNCdRU42QbzSUZ0yCi5i1O8SKp5qDel7NsFiexsUOL2OFSyDwG5KK0+9JwKpas8h5p0HPfPaxl3aDPF39uJdjR76oGiPpinZtGekFOwdOYa3173AhDpp+h14mRpH6kPP282w1vkICS/JBTgZD0WCYWzpr47PPobRWyEVCtzfgHKrxKHt92aaUO9DF+4qwDxRb6puQFjhGsH2Z0toykA2HilhnF8hDyLkzksaBriyy4NGjXuDfrVdlL2hkyOlxWnevEkgPfMQiP0YCZM3HGJ9h83Q2o4Qt3wk/5itCOseVlNByHWYr/FsyEWKwLVAAS5l9sILn9l0okqCTWU7oc7ABM6DAcyOkQLX+3Fo2ITcZj4M5q/qwrrsVHY5VcBlVom0X16XTLQ/U2iEDoiGNJGZgQTkHEOoaZ5D9nFRMOnnLnhUaAX+33vQ66AoHljXQXfiPfjccXP2sBeAL54ucGBeI+9fiuTk+gpaYjZBUeVS3n7BgjLOmHO/owarJY+DWX3AKvEOZOxxEaMPOuLD/uO4O3svi3a707DjRyhPQI+fSCgBLpuHobCPP43qxijFDdx8TAYtvkaw+7J+nPt9K6yySeSMWC3Y+boePn0ZYGwIwCODsVy2SIeclk6nfJelXCuygXUOusGtVlHI8ijlYLck6HhSTubYDkuDtSk5MA/rR26GTe/HYrKBP7cG6IH7vwRwqhXiVA1PfrfvN+utfkGBDtvQZFUqvL2mT8Uj6iDGXxNWv3kM11RtoPntcF5aJUjqs6oQ6Q9rXwnBNeOd+NwMVXTTMwM7wXr4eV8antxazANm53iLmTW8n6MOFwo1IOyqCWdPSKbl5TYw5XkBZ4Q/x5o7//DeLHN8oGIL4oEedOLwEq4vCofHx7Ip7rQBREVNhuzGg9h4tBYEKxqoa6hH7kwTwCSnMlr8pxDevOqiV2ZToNXQj7QMe/DkEX/2+aTCsxTzuKmtCg+8ugMTHGbS1lIfEhOwBCvd8bjLqg0Vw2thbfJtlr9G+GRob//1n2Ot8lzWtLnHDwcN4PB6KehRqIeC1hI+a7sa//7nS1XbVqLstS68bFRBhVvMWKVfHoTyltKStWoY+tiVv2gf5qqrD/DSrw488dwUEq0tOEDFEJ2E5GBDQTj9enCN3CRLUcpZmSZMV+bQey9xpvhnDq0txXca86B5jwU8UyumXLXREKV6AszzXvGC8Sac98Kef2WG84RhafT0dDBPWDDEaP/Fc3W9Pv74/BmtdUZhsPxCalf/DG7h3bgntJ8WKpqBq5gMLBhYxkK+a/GhwAhcYKqLrlOTYd7e06zoYI0Tv3hSb7U3S5XoQemccPBYXEUjQw5i0cGXXHwsCt+aj2DngfP8ybQKOjzcSAMEQNz9At2eMZZlZqZx7rUCvBHZB00n6tgz4RlfmuAIwzdvxBqwgK8tbrCgf4jZbu/FX28DYdRzI85IOAeJl5bx5vR3dPJOE1sn6oKr/jcafFLH3R9T0fXJQsh/8ZfvffHFqc3/cNGJWFItHsFXi/Rg80wXOj/1E1cln+GCQmWa/UMOF5q/4s8DpZDRVwBxPyLAr344XPr7DOx99qHMpG7YWpTNn2ZP4K2fqsk2tpuEntRjf5glupqqw73lK2iawDk4HdtMO7TFec6+Bshelg8fTOJJLEUC6tyCQDl5FFSERrPqASnqX3iU9n3Ip02L36FkTS1IVHSyrk0Z/hL8wLUfrUEk4h3HKjfRMs9A+iu1n2LdPTHJUxMtZiyHy35uJPhqKbTr6sCLya+pwsgXhPk+JkgmosDcXpp7KpF8nLeBV3AvvHLWwcZOCxi2vY3FZ+TQgS3euPDgZwheFIUv7pvAnZOicKtrkG6m2FLwCVG44D3As+uWQozabrigL88+X3J53H8aWBniAXYPzDHnTDObBE2C/tP3MMwvksYq9dDYuLHwfWs3x00bBftDb8PFt/thliGRR44Y0JkuNF3xj2enOXKXbSpcUc9n7YnjoGHHOboWP4DnBTt4vdQIuDmeQFenGcb3voJJ7iKkWVNH3SKPEb23g2L8cTiWPQ/GjZ0I1ydfhFEh7WBbthht79rB9+dumA+mcGRYHE7dUgm//E3I8yWDUGU71b7wRMfiGMwd7oH7TmpTtfw/jJKYyLeNa+CurDk+Xm4BLV5L///fcZTwTIJfLfLU9c2Vosd74muMxKkNlnSwMRQmrhCEdz6GqDJ/Jr775YOi5z340bUQXL56yAMldXjfDksozatCq4nWoCm0BPJmWOO+wE2Yf/s+NLppweMRnTjgWs07vefhG+dxfFDZDLS/HsXLEia4NK+dMwNSGTf2ktOuSj49qpiN6jezVbgTWzw1h+ib27BZ9wttSsjn4obhcCtbmT9d1aQJX5R5s68vbLbywY32BlAaep4tInxpfOsubi/Mo7/mXaDoPYqXi+tgR4se1Pm859zVRhCZMAqmL3rEyo49mNP7EONk+jA7QoVFze/xlD0t6JS6B9rWmUGg/D6SClai7YXvOO2fIVjMZjolFIBTPo3A3MEV3PynlXp9pOCCdDZX9qtjddM5rFUM4Zk1PyH5hD51bcvmYPtWiuu+z9EtMjCmx53LLexJRYZ45jsb1tXPQeXCB2iUZEwZIMi378+mf7f1ocJ2kFa/rqTyKSqQHFzMY/pcWSv8CIgmOfEGsVMY9FiCdl+RgHVX7KFt+RkKdqjkhA4VvPFmM7t/CeF/Q2zyXjcSLiUrwbJpIpArtpL77h/Ej0mO7DJqGnm1lmBkkBg3Hi/ifT9/wJfX/izbLQNHd63jXf4DcKjRiaTt4tAiqhL/+i8Ho2RJWvFCgG1WWfD1YAFotr9HOR4zeY67JJpME2C9OEfKGO+Puyau4aVi8ZzR8RZGVOjDnahgMJxWxA9n5kPXhKkwc+0Xzq0WoqXunVxkaQOr9o7C5AXG8GjkYU4ttKU/5xfS3qflEDBRF9O1vOF95iDZ9L3Ekf2aFD5jDEw9EEYUac3yttE4/4URbssT5OV8m/+t/wu6L+Kx84IOp3w2hq3TdWh/OjHGlZJ6yy8qSljMMamm1PCtD2pvjsbGNcG0V0YA1ibEgdfkevKc40X5Z2pR7ogqr/GbwNeWNqCZyye0mvcIBrdPhkkFt3i44HusjouhfYfGQeH3CvgTJsViFmnU2ZM9lL8iIkVVOGCyDDr+8+ID9yaBSKEEHhO/QeFBw+GElizeFojEsgRVnL9+AvguT2B/5T720Nbl4Q2WIFflCTZbAshKA6Dw23A+u1wUEpS1YKbRZH64sBoN5bXA+uV6snCW4tY76tA2cR1baFXS3UvL4Es8QuR5ExpYcZ30Q1RIbF8rL1BzwDl2M7Fn1EaaGKgLH3fVwbC/Y0HgnzXkiVnitgnBuMi7HGJ0H1Fn62GUCVKiyun/oP5qFuUMPWvZwBV6KDIRLhuf4V/KW6B+9k2o1DxJ15RWQ9hSKdhcW8drFtnAvMx8KprvSAetLVBowBP7AuTQaOUeWHExHV34End888byMBGQXboRm59Nw/uRznzS5xpkFCIL95xFNZsZvNHHF8q+HwJd25EwsPs8BJx5gQoxpbxhxX8kHp4ChjPm4sRDt3lfeTJs/PaVG1KFIdywA6auOUPctBVi5Q7R2i2WtKftBNe+8qPQjm1wWGQaxY4cCdVjbvDkhq80+kYdbpSaOzRLe2q6noJt13updswxHB3gjf3ZxnDyqwm25XvCpqP9sHmXHdQ3iUFomgImxemwvFcXWMS1U/w0DUiZ2AvWwx/w+AWfyNv3GvuIOtKSwiSO3HSVonLtiUt8IGeSMuind0Chrh1bvM2FMa234ePn5Rw2PZVCngqSUn0Tnz6yC8U3W8BwsQn8stEJKjaJwc4aVdouN58zRq5i8eeRqKslxT0bH+DtQwBKyZ2wJOcOXPh5ju93u8CTA3kUNEuPnFU1UUJPjNb4/4SsVmPI2lPBp798hzf/peHyQ3to6oY99PJXHi1I2ouaCd+gTWeQzKSHQ/jJHVT88h2vnz8TqkpPsP5rEW5e8heD38ymMdmzMVcuBZx09OCKUQHM6noP1c5XsXN7I/88rgLaFmG48E8xOo615nEBZXBKdzT4PnWiusvJrBvgSpKd6SgYEwG6YxtBMt+MXkMv7OQ0nhgyFkqfrgAn78eckLEdPWtdydfpHp27KgBRB0Kht0EKtsd/Yg9ha4itnMsuq/QhyOsVFId0wYy3k9BeywHM907GfSFHOOj7ZpLfYQRHqmtI8MY/1BZXoBvCF/mC4R7mJSvR7uk/SHKqQOnzC7BbWBlSs+7xmuWjoffwOCyPNgcrrz9QI30Xg9t34rUFdzF+nR0tbVeE3tm53JoTQBm5KyjuRyBWKJXiWdVkSjveSkeOh5N58W4UkVKDpAo3LI8qhF/K7yG85xbdcinkmCvX+NON/7BVoIN+OgezN4yAs49k+IDvKLgrVQHnLFVgeFkGrhzzgOxWdrLY6h4+26sH41KGwy6nYJx5ohnUH0TDioKpPNV6JRx+0QajCrdij+02OD0zBqbdsgAv5TtUO2s47QhaT/jsKbSkeuJFn0/sqvuIbT3EcUl7Gfw5YwJH7ltj08rjdKfrJ7y38QH77mo8L11D+/W/YtTCUpD6eoV8HfVgfWviEJPKsNFPATY+7QmekoJ85dVbfC+2gKUfPmQLpVdkaWoJU570YLOhH5/9t4YfTyyg79ZGpBP4ClOvD7n59WL0vP6Qf53WhKK0ID5qOJ7+NVXxXDF7DPEJx0zBrYiDd3lKpTFWLtWgr+oKYNrchk11RliTfJGqjwhh928rWBXDfE19AXPHapqybgJ1/BviUzMDmJdnBzHFEhyR/ABfmmbx1apoVtJ0J5MuP1bRlEVJPwvIUbbkKbO+Ue+LWlj+y5p3tKrQn68vSVO+kxIDzVjowSPstpKCW2u3842YB+jlv5vl06QoYX4ZvEkSxCdpwvDAZwR+lCyCrI/qsFrhBZ7OuQV/Bn3BfPdBWNi0CjWnWJCCVQTnl1fg6yd+HDJOA4ZNrIUf6X9x+44z9FTTF1wVXEBGuAfPt8eAR/51zDjbyaVRw2Da8QcUcs6QpkWcpfWWB+n4ThEsGttOfZ+BHUzEoD55A2Z9NAYDq+VgnJ1G2x6Y4hSXD9x8tI+nQBLXtMqC1JeXyLNK+fQ3BciDDEgY3gi3tZRwwf0WfvJAFuWi14LFoh7yVivl4abmXGZuAIrGxVxgWgFT7ILweaoa/piQRipmnnw2JASeRVeh14nV4KI8NF/Ry1D+fh1Pff4Hdc6J87LSCbDxWhZv213JMxuXs0jYFnzYbQpnXAU57+h2OnPzH6+5Kcq7q+6zVelcGre+mex8HsPZDdPYNVceFvYehB8y39lmcgov+nMZ112WxM8dn7ix6QoaVajBaIVkCn2sDoplbWjsNx+x9z2NfGxPybNF6cn47/Cyvp+DrEzww9jZvDNnAuy5EkC2Gy340Z7btN5Ji5xKh9jJNoe+eL2kL4EyNFvvEKrUGgKKFOHC28389HA0aQ/l4L+Bn/gqpIHmGtVA+jKihYHJsF51FPx43M68+hVZ1NvgpvzT6OIkCc5QBRMnqHBtxTuIbj9Jx4rkoPTDZwiImkvz1yST1E8DFl74AS59b+LNOsIoYIK01uQwPp6iDRX9UWB0YhrsqB9DZjEeKCP7l/fn58Hadc58wfITxAYfgg/aurBH1RHnVN2jp1ejYPeCJ+Ao9YBDveaDcdlt6ArqB6shzn18Swbk/MI481csuawcD1K9q2j8MCB7zSL8XOTEYRkfYViaKHds1oCzdl38/aYY/zf2Phvny5JmphpKGZwnoW4rylA5BJfW3uJObTWQHyFNN2fPpu0eDEeDsumb+1g+LDkNbwTogUhoFrp7mvO0L9pwfMRJ3rBaBb/fuEYb0hRIsE2Ejs79wUvLEIscDDFsuRm9mzABXMcNgz+P+uHMqmaEU09oTOdF7KobDgV6i1Gk4yZW75KkP63jwcvrydD7nMQMWMNb0/Rx98okvHUlnfbGbKLKjDV08a8zlW03h6V/TTjzVhbuV12Oesp7QDDBlQdbS6HMeBa92GmJgy376eNYM8iWOQij+0Mg8vkC/CZlBCrql0B8lhrJpHyH3S3JZD/4mWMmqUBhxylOOrkOe5Qfs2HVQZ435FzO8sfo7XVZiBwoovPiI9BSTglu2fWyTe4g3tuhic4mWRznFsnFDvGUcN0MTryMIJ3OqZwYpwhh70tBILCBBKxUUVLgPTy2vUT6B1tw/d2p/C91LZo+us2nosxgnfAMOilXRhf9V7H5svf49VsMk7UQKZtuhZVaC/Bk8iosbtGFySe+8bs9PTQjSIWzTqZio9s8MFv0kQb+DKJYsyxpPSvF+dmTQVj6OySKnaZvCld5sogBdKrF89cFtWDpbsgFS35gSthVPDBLD8oYsSD1Lq+fPA0+OD7D9pAoqDhWCj805qDq5lwOux5Hz4ulIEIvjqwkbqO220p496IPpgw7CvIXFFhZfjxED+bRNtkH4DtHBu6OEMBDUUn4LfkBRyp+x2kpf6jKrQ92DDnalq+2+GO+AwXNNgHZLDWM6FhJ7k2dGFkYjFr1Anwh8xe+nTMSr84/Q5/WNnBNmxrEXfsADg9EOEXiHUUfO4ftHt244rsiibdY0cI6OxRwTYb2ERog+OU1rbPYQDMG1aC4cyUqXJ1G5x4/53sxhfBQahmedw4Ho6cycNHZHA+4LOFnZTs5KW0bH2zsImN1bahNuo42eo4scewCdPkIwg7To/RzyCEGj4zkbhVbHvg8hdNeWlLrBn+oWzWH332ez4cuEvj4JsE029t0dHEXnm8oxMjRP2nGs6dkZPCNV3fOooN1Ayw9AuDFL1GO8/GC8IdzMXjxXErM0qMLBeFwLOUJ3JudC/+5FmHCzMlgMtUAVWSW89SYMPi65gINJMzCmW4i8Cs9FJv7RMh2hT79TkaYXn4Sv954ApaKF3n9RnHoky+DCWqjubQgBrp1h3FEji3duCUADj3iPD2oiU0sRcjp2CYc/SMSy4Neo+TuBh7/WYgeP3Im/zGmgG3CfL4+GyX/FrBkUjllfQkD/S8hmLL5G/r93YWb7b6xjc9oWB+/Bx/qJoL0PAlQ39YNvxO/w4PLGrh3RQ/O6ghDC90itNgmB10z67nXbR9uPTmIWyLF0ePCGLo2w4Ke9x1Ambil2F3RD5mV4tDY9hh/z9wHU1Y/40S5w7i7eg9BbQA9zv+GdYdC0fXLIjQ6LQgxvxbywyNzSXvSSV6cbMwSyTagvbgUd02r580+C3HdqVqOXTMBFrgJwW0Xb5gj0ke9AZtBv0aYR22NwP8Rd55vPf7vHz9HaA9pKGnREi0VKQ0tKVtEKiQtJUWRSIV2SUhCZlZUhMhIRkapj1GSUpQoKiGh/Pr+Fb/b7/dxXcfxOs7z+Xw8rjuvyWaNUC87Bjd7htAcUS2wL7flPfcqofuwBZV9icOjuzsp0c2GpEbl8ZRPxpQqv4p/V08FP9ESDqoY5MGmIrh6uhj8pT/wt523UBOHo8GDTMravoBebBeEU6ENqOj6nJaWSaDFyEque/uL5D5Gc4lbFYlnXoTmnP9wSpElDLvfyJKPxpGh5jqwa1HHqCc38YBqJZ7858YFB89z3DZFylQWgZ89uji54BxJCHvQFZ8gjrhuTO1WBAMGs8Dl435IN5vJ+ffU4bJxMaX8KAdP72I+FqQMlj/SaI5MN91QGsbaY+X4TrIO95dJwcDVONq75i3pXGhlPZV6qLh0khbtmEzlsUZ08I4WWuc6wjVrEzANBVSgVexW9g4DFWdQnTzyny3lVDA9Cgy8J4PbaXPKJkOQ61AZ6gVjblcUphqTmfC0TZyPJ74hp4z5pHtuCURnfeOlZxUhcpkwCcjYU4G1NeecWI7ipyKxKuQmOK7dB9ftT2NSqhONezUOjj+/CM97ZtP5G+NhT0gw3k1DdnIaBsnLt2LJ4624w8Ed11WpQPKjAxB/U4gCd9vyEqcUDu64g9KD07nmZhBFNupzsoIYZo0dDtcmPkM/d1Fe6bqSNfJP4+1bgGevlfNzcwF2c29mn4QSUHaRh0Ne2ngvczpNaSkEgexwXtqxlnSURvPhN4hnnplS4ElRsPbRhNDeZsi7cA5DD1nhRnLhwW8LwZOGetpyaHXWBuJqtXf4olIb5G78ZWHfFAq5uB4vv7mHe8TmUYTwe5ZWsAGZbd/Iy3EKXr+kC6uD7pOVVAtaidvDvGF/cYmJC93fK8tJ//Vx7fkGnh2QAIZbVeHM3S0g6f+af5UEUYSJFvl/vIxu92ZAr8h6UDU5hFAlzh9PmoBqrhvMWbAeo6Zsp8rzS/Dwpqsspj0CJ63Pgan/yrg0NoROOYyCl1ET2HugjTf2nkYDsXP0Y/1Z1FM4yoqavdxt+pwd9+yHWYUjIHPyCP4gRKzdIYcF9iv5da8c/HCUhg0ne8lELgk9clvgqJw0yL7XoIbzQvxHvw/zzh2h1WnTeX7/bJ54LYUXB9TTGVUPcnkjBBct7oGlnjjU+ijBB7HhrLT3FYfULaV3zjshpecU+B4Qxany6uBXW4sbXhii+euVIDm0+762Llxut5qf7PXHURf3oV/DJ06VHA3CplfRNPc2zu5Mpj3vVfBAtiHMfNWHk/8s43FBSigfuoX+VojBp7Qt1Nalhh5727B06IxVNspy260FqCBbyi93pqNw4BnU28KwkZ7QojvHQXzxMdobtRYcJMzpcJorzTfZSTqmW8h/qTNpfJQEjfMjuHGUO5zptMRv921g2KhOjp2shZt/vKDOqK+4F47D4sIpsOKqE2seC8Ej1uN5x9o2sNz7ghJDxUhCvwh/6Z7ES1sQE58Occ9Gabzz8hp8eLETLpw1BmvbEVg6fiP2C0fR9QWxEHYmgpMtRsEcwTcwUmoX4NOFWN6+kV4JPmArq8e4c89wLnm7EV2EVFF2pwI8L97Me+3O0qj4TFq/dAOf/+0Ocq8KeMVPd6wW14BJf7MxxHMkpNUp0u8Tv3F341xqafKHNf/E4I3QAQwda0TvXXJA5uZqlno6Fn78NiLZt2P5yaPP6GvkgB9EBEhCoRpWaleR78Of9H7/CijYJQK7y+JZvriVNJSc0WVxJSVObAcrrxfsEpDMtuvOsOMvDfg9WQqehYrzj1WelKH8CscIdPHBxscs6H8KazvESeLFOlwuYwJLcofBGUknXv3YnfZql2KX5RNyce+iuUeqcIlpBp/wOAEpCUkUbDcVZieZ4D+1oyBd44hho6JQ8G87vPNBvpN0k57U21BKcxL+6BwHg54FVNY7Ctz0uyGvMwcF115AbysbbhzK1PcKo+nUEyk2H6YEPRvDKW9iJMyOG4v7R27ADa9O4RPTZaRU2YaJHvtx6nQzUvBUg01ky8fTjVBZ25yXJDlRZrEBrlvpAN9tnlO+5G8235vP7pfNwVA7lN3lR5N7wzw2vb4Ruzd9gEURObRibylWv1jGOgG58GuNBnyrledAv2ao8M3GNTwShFPWglLQNSw914ZGvr85Zo8bWS60BNtRbtS40g8W+azClMVeaBp9CZNT0sA0xgdPeqyCZ9vFWOKWOZyakoWfpf7h8oJgbjiQQwVhyGN+P4WFp5misQ/sshtom68WFGR10G2/j7hTeAXbP9Blw7TppDZgzv8lXeVK9bmw9uV9NnplAGGP4tG00xtiPx+AB3CFDk6ajK6p0rjvZDs0DWug6cVpLCZpCKEL3oOmriALHUH6mTGf9RNyKPeCBDh0OLCvzWl0C1lPf9aIwtxjR/mL7i5yG5vBpl7vIHW9LZ6zewTfb1nzebPHNMbtHSyYYAl6G0WhLlgIJuAX9r7khWOnx5Hs6LM01+sjRiVn4s8T/rxpvznUtK8h8em1VBO3i3wSLenPoygs/i1EAwJ/IMdTFuuleyjUYyKMN6zA5uxpsLf3P1r+uYWfqClA7dQmevj5Ic1ZVsm111Jh9jFLmHG0lted3cQ3HXNwVep+DNnzBael2NGOzEhe8jcfl3fbkPQVNWi9pAbyOzPg/uYmNr86E28IT8OeY9UwcsUlNr2hAs4tLrA6xhhyBTrwmLEEJbkG4K4hxp+/Vwg+a6TTRo9AsFZOgKZ/2Zi9xRQ6rzlg6/JqjngyDXS0MilP9gs+PliFKfkOaCO1CH/m/iOPfEGAlHbKrPyCWqFnSA8/kvNKPxo1cAQsD47itcn18N9rG7o+eQxUbRuN7qcXkrtmD9sp7aRO7510S3gtZ9bnkcg0YUjy6QaH0ZMh3qeSotd/54T7gXCPRfDIl6WU2JfD7Us+U5DyBUye9QF/6euA1lEF1gkqg/S3H8jf5AAIpqehqXkfvNbdQdez1HmVhwf/fCoG4pv66ahgLx3X/YYzQgIorHwzjdvVR3KP82nthEpOWFQIDkOcLRwUwT9eqEPKb2t4oX8NTJ4LotTWLsy9H003G1r4/YLtPKFBHDqHI+kdFcJ57cY0XteR3d/UUfu+FWyw8yubnTOiw7bTEJcawx2fD1h+uZ5sRauwKtWCPn+Xp7xwL/b+0QSDw5JY4UgorHgqB9NUH9CHpggW2HudfMPLSdBfGfbavSb+IUXZR6NB/95+1lcSADX5cK67FYD2Mq742G8f3JcP4rr18rxr3iWW2DUdR+i9Yq0Nw0Fm8xj+F4e86OJEmv1kNn87qgS2VaFsczeTevtHg8zrUv45xRzGxMpRrq8rby2dyCozVw/ljBq4fzhD0ieDWK8uHZ3OCWH0WCPQ3f6AumdIgsFGBV6/+Ct823IB3LKd6by/KnzJE4GCARO6NXcUVChfpzORJ1k9vAaPjA2B/sTVdPWsLeiNuYfquyNI7GUqNEaPgitJT2h4dy2f8y6G+HnDwGHMSq49NIqWjnAE6zpfeNqxHzVUFGHfpi/sGJlDYvKbwGRGJB02ekYSj8Vh18ACuPk1kSsKA2lq2jiwtMsgh1X27G/bS0Xvb8LOyE9gaPuKdyZtxIR5tXx1vD6Yr9eFiFwXWvinnYu3OoGN3Q7yaw3FPSe2kvZBTY5NO0rPrj5kPwsZaH+2g6e//g5T3LTIRr0as+8v5N5yff6wbQH0y5SAZ/4hOBE7DfKX9cGS0eNR9rkbzNPKgdQnXSDgNImWZfmC+7a3vFExgZOfWYJWwCCZX5yGbg79WF1XBTrLH+MakwuYZAvkeaOICzrO4qk8SXDg4/S4o5/bf5qwzNxu6KtWhbzZziS2+QX/7luNGzIWs+TXqaAQ6YoOt1SxceEWfvvfEdrpNIeNGvNAH7x5zqQsqpUDNMhmcFgizAvHDeBTH0facc0YO2NGkNl6JbaNUmTPklr8WyRJzZXToO3Var559SWkZwjzgOlejFVbTTM7F/D5ha64XCqC5QISeWHTKFCJ3oQimy7ywr1JfFLYBLd9TOaicDOuveWJx3Zp46bKRljTqANu0Q0YPHYX6DrO4AfcyLUGyPvnO6Lskq0suM0KInYSNgdqwu4vl+lyrS+5eCO+98jB/S2mJOfTzF3uVzHn5UUW0OgAo2YNOP/VC8o8T0NZSyylFbjyhJxw1L4TDTdCP+IPWQNOXFOJ2junQPcnD/K7Zw/nK1TwiuFZjg/aPcTNiiBQ3w4ssI4OL3oO7U7KMMNCn/Zl2PCTUXW8q14E3suZYUTDLto0uwZC4rTI4uUNzo0VgpzuteyhacXD9OzAt9wEV+j8hJVHzPjPzxwQbNqL5T/rQVHECA6VmhLv6ILxl5fCt58u4PJ9K+kJ/QbvnAWkQymUvtRliKktIU/RF27Pl6BPqhNwEg1j5QAlfDBSGAQstOm/6WZ8+c8XluyUAONha1F6XhkP3KnCZUXD6IjcOPo8W50vR2ynHNl4SM/sQtt1IyF4nyDZ7b6Dx3cHU35vOy1YsQXyr6lDZpQNjrv4GZeIv8XiH0rwOvYsXl9/mlcoTsLVXdvhZsorFG3cBNt/TefNxv1QZrOINkQMcYlIM6nKZkHJ33s8kJ+Oi4fy0WFzHDonNILEuTkgmZGCr0THQO3AG6jZNoKG7TZGNedVEPp6I2126oK3u4fxfR1nHF1xibsWj4JdYbHoqBfI9xar4C7p+xhh5sH3htwl86I3uoiVkc93Nbo6Tw3s/5nTIoNMDLykRFZynyl+Sz2XxN3n0i3P4fX+cu5RG84WWxHebM1Gi4l/+D8ZO/wluJ/txA9D6yFh2jB7CU+fsIBrg9dywzFjGNHxmJtaxvPKSnNu/eOJtik7QKohAn6v3Uc6l3KGZkcLx6YS5Cd+gk81zhg1M4Mf3ban+m2uMFnnDtzWNsEFL/RxdOBn6BUbCzOSUnjbqws8a5koIhTglsA43txUDDklivxathVuln7myiJxGO2cwlvjH/FXm0coQYvY6XU0xnguguqPpzHt6T9KF4uB9d2SMFFyB6hvcqHtQV+52lAZRlZNJfMGH552YiHKHQ9mvUPpvKWcYYJCHar8+MHyU4RZ102KD3R18eY/eVgwtpOkNbLho9YzttdkmBQTR6dyGknm1D5wstLi1OO1WKVljcZtN7jd8xdtuSnB9pHjYJKHAPU7xWO74yh47p+NkqeD4L+sY1w7+yPtEDHhT2iJKrtNIej9LV5hms22Ka9J9VMyCM4P5VNPj7H52hnU2nyZbx2WRNFUXYg8cJSn5jVhbJMGiRr2QdPsK5i6ZinrirbQu7fXaGH9Un56iWC/iikv61sNA1Y6PE/vCV7ueYQPxUM4aHEOrpjnRZHOqjTKk8A71ILWpUeAZPd4+GtyBX4putPG7V9hh/FOzP04FfzTtvJ38XFgHPcSm6z9yfXiaIyzm8Fnbi2gnn3y3BqdTd165lA7Zj24vDCEfd8+D7HEalI0fYgvpUdCxThTHiaRxuy2DNKi0jA17gpciRsLy3zr8OqBUlhtuZMmDCjBnQOHsTviA7yZvR2+FnTi8rpCjPUXgn35tzH44QXWUvCBolxX+vhqD3ge2s8/39fC/dAD4KV2nA/+1YSBpvGQPEMZjPZ28pW5YTRuUjSnzX5PRTuP8H31+5gxuhS8+sTh9c1USjndzcGZm7kqzZxS0s5QidE7LO8eR+PlKujD53N03ZegzSETr0TMwG9LVDlarAleRmZT3aM7aMGVFN5gAa8izWHVhrGg47kEpq44DpWjzagybDO8K9hAKOlKo9sH8dh/Sgx+N+lVlRw0VMvARi1vtDEo5B/vFEk6opRo4D19dBPm+aY+3J0ziM+uDAOVYiLLeVJ8bHA4KWM3rjlzlQodIyEZz6FRug6t7G/il5OEQKdkMY9o9kSZt8J0XE6QPypepYrwP1SnKIqZZ4/g0s5V6D1miJ/3N4CAkBvMPedPZ84cROHvPuhdEQUDpa9RRCGK3h6yIBkbQ/h23gJkX+iS16oXYDZsE/Uqj0ZjiReUH64COXdDqVuli/VfmEDMIjk60T8FlE4+gHe9tyD+/HCMuyRNMkfe0W6JVAgIOcXlzwQBLSvQpT8T1lpa83qrNAz7swU2RL/kp9mSOBhwha+WRYPVX2P4C0vBcYU8FtwcgY/LelCt2IdX82YMUSmkvD/VpLWzij7NlwZN0dUo+KmATOe9h1rbICyftIDaLS34aIII1s1vxqNbVsE0JSP4OdaUVB73UE9/Ge9znsQD16+SfkEoB2tupPPVzWDxVBtWqk+FDU8H2PXbcFzyx5lEXEbi02F90GGkjFu64njyrnJafn8j/c5QgI7eBJKsteC5z+/i278OcOlLC6dui8G3t7rpRf4KDF/tzlOE1cHB/gAdVQzlYz3hqBeXB9UBu0noZDJetvKi8StP0MG3J1AnQxRmyv+gCwWyXK0rzvHuchzSZ0mzROKpd1EtVzSdJMGdP+i3hxwUii/CMeofKLLoIXW5z4OKSzfpX/86WvaknwpdPnJk03YYCDWCaybvwKjxBki/+QjVcTmsMGMGTN44Ar9USfFVtbG8Z1IaP90uAJ4nDkBO4xu+cm8Y6H/azt3jO3EMBFGRz0Xc0lADGeds8USVJMQ7zuVfbRacNdIKL3d5s0vSWVyX70T2GvO5r+cQ2hfdpx/Tx0LjrA6AJZIwu3ECWrnMpKbHOzgppo8X7tPk3N1ZXH33Pp8RIbjyzhtn7/xEN5tSUe1+Bdu/WkGDvcpgN9Gd8yz2o7H8NZBJmww+UsXoIZmJxmmydNNEFms272L3su2U9CaFMt7IwKl8xm0mYyBxVShqWArzk/C9vP4u4PJbrSji5InOt/LB424NB259z4m7VeBKXhgcWxjH41bKYEDSdyra+5MV/z2CP8VPYaqcACXcdMaKhcPho5MrGfcthyvBTF65BSy1WpbDR2iS+9T5XLpwPG/f9g5XBIrDyagCrnssBR8Cv2HQnVW4x8eP7AwE6GGpK8c7ppNj5bkhNx8BP68Uk95XF55tOBfelZqh7ywBWtZpBsGoipe+7qczuSKYeEkQ7CwMyeduBYDdWs74LcO2LReYfuuwzbB8fufylktXHSTLLwzalW5U3fCQFuUshZb8S5iu/B+nPyWwrkhkUwkHTCgwxoCV4yBvrhoc8LqDbfabwXHLSKrfrcHz7YNhpZcp6C1Kx9VjbfhqEYK1QiNFX5PBJcLf+ToXos69e/DpkSSZbbaEQ38HYWfNeBy9Qg3EbfZj0o6jrFFZwatODrH2szjW+SrJVybYAU6W4byA4bjVTxQCwvyo46UgbQ8XAx+J85gTVkjTh+bwSOdcHudgSHD7B93uUIPFh4JxvcpFairxwFiJVvZPaIDPVYNQf6uU9t4Th8+u5iRfaw5CmeE8c/8Anu7MHzrrday/JQuf3JnIpUZpsHqpPXQsK8YHrRrgd94bvKzkyeewBm3/N4hZpS0Q0zCKf3zMZJURn+GfVwE9GCkIe09+ID11LWhvLoZvM4fjpY174YVWHigb9JNV0nc8+8uQC96OhL1HXcjEpIE7B+fS83eeaKf8FwrWpUGvfi3ssVoBntNSSTZdGfxPzyDHIAdOP1KIUtYeIBPWB7ZtZfhf1XkCnSt4YOFMMr4sAwFB+3GD/nGWebQNVtdcY+UEN9ixfwI9+O80/22bQnYWgawzUxwKAp9yUMxirJ+QQjleq1h6fj0fsxyBW2VycYRrMK88EMJzA8ZD0+YAqFBV5fq9bTBcoYImFP8i//FAxjdc0Mt+DukNi2SjHRJgZLQLDD7rc8aRmVQx/S0/zrXC18JPadaFW7z24AnqdD7C+daW0HzmAG9RPkfVn86CiXUwPda2BRPlOLpVZkj7I6Opyk2HvbomAVtF0xelmTRyfjWmLDUl5Z2nSF1vE7k/zoCEpFTYbKHJCy7KQbh7MH5a8BjLx61E3YgEcLrMNCxbBuxWjCZbVoUJ61PozfehnjZOwssHXtIhrWPw+JXjUPau5THvd/Ct6AL2d8kDgaBYjDSYBK06q8lv8V6+0T2ZJp/bxQJhw6FDYAnKS3mQsdB3ilh7C55NEIdf1uUcMdWSZeYZwU7PTGp9PIdWfv7FstLiNLJTDA9WKuPfJcNAtc2Ks8ptcEqWEZ27kgOFj37wS5EbYJE85EWGXiC7tBCOf1SE21cu40mxVio5mIW7n2ZR2FD27t83yMm2jbjxYB1mvMka6ktTEKj8iIkyAfRa246jR76Ht46nQWlMJAX/O8lFYZFU4x2Isz5MgjhrhAmFPpiwpJo2zkuju1mamPe7gcvWunH4Z1E0eanBRVICMGVGMxx4ngRvT/dSWPwXnH5MmXYNHqHNFyvoeW4y+IoKcK+hBnScdCIFw3B6M28KHhkxjn6mqNGZpP3w8nsz6it10tRkQ7rGMuA+ah26K7+FFCuisLvHcIf8M7oz+QR9cXhH5hLToDR3FZVZacB4U+blpv+o/YkTv3pxnLN2+0OXTQrtPORJKidqaZaaA/YuIND4GsqZK4Pgle1d1I9bR4UbHOm7fzrPrgyH9TyRA9caw7+sSdCZ8Y6ic2WpykyYFe4ewU3DlOH9zX1g0XCB18hsoLbcdrw40hA21tTi+aKDdODUIvq3yQVt1B7RiEQZ+jPWi2oDkJVHn4Z+FWP4miwPQaK34GvqTO7b1U9umxo58YcYz/22F2tzlan5wiIMv2UBqlc30HStkdS3WIM25bbyNwlT7mqX4qiLjuQrMAJpYhprpUyHiX/qgdfNoGPVZmTSKQqOfzxwmOd6+nqqnOYO+d9F63lU/Wgs6M19D8EROhyR8xZHP++HS7m/8Z50MroW2rOx9Wa+31XGj6t0YOcIxCszhjgs4gGlb1nD5iulYY+7EuepPoWqL6Jss1iIblSbg+jc65Dx+COW3h6PPuMKUFlyLdkFVcEhazNKvzSB62v7+a+3Nqy9bQubH1xE4T2b+OeEl/xMtoVHrNeHE+U6uMvpBN/zaybPBgG4dGkkj39RRhnXnsH2O1/Y7XoZa8tdZjY8x7ubcuDeXF9eKSwD4TkHOWHxCapJ2wJFyg0QcPULln0fxLamFHauVSH/ERcwdrwWhA0qo7jUGUhY6o1FOi/o+oTDsODxA5SB41guGEW3H0VT5l8t2CUcjoLbNjJd9mZT+0S8bteCic8leZ+qP7TfnojrJruzi6I5jHcNxBHW0XC1TRa6ej9j2elaOHmiBix6M+hdSTAbho2kmw9GQuSalXjgw3xaFCnJ0d/s6L81RTBPeDH6uE7HwPCRHDz5HVfNMoVJX2zQecZGGnM3fKgnKvhpVzWdmhjLMzpWY3tjFdaOSgFHUw0o2TEe5TZ8R/Pu0fjzWTs0j93HHud7EHrSMXGsFUXmy+C3SQoQnfODm84epCuf5/KjJd1kIWsMNTJOuPDMCzygGMRKD3/D01N6sEkukmMnLIcfGZP4+OU+uPl7H3hJhpL9zGA88a8TDFYsgQ89AlCGInRO6AKpJTxjif54/va7n+jmOex2KmHBUnVumBvC9/4YwpxHHuBw2QEWqZ/nP5uyeIFXGrl+fU7npMfRIbWJsOVIK2g+Aggbfxj/ijmjTPBwLh8miVHCu0mz9AbeuBTNPXGAEZtj2fWYGLi/HgGb6ySg7mc9KJQ2odLCDs4KC8VTlXv481VfjtELgBwxS3jm1QfjHBLgvO0MPD3zMNvYbYbLf5/A1FMJ1MYyVL/Ajpy/i4NJaBlfi5+OnjrxXHajBydF7kb3x1tR8sEEVDaPYu2gdnQLEoUvLXuGsr0Z6z4dpus1/2Fc+FtyfuDC0+LKuD/yNR2+8YDv3tWD5w8eU/B0HVwUOAulKk3ptcoHCPTdSa+XBVGPWjJLrwgkiSptGNk5i/7E/oftAYF455ce/nd2AJfN2o6/C4NA0SEBg+0/k88xaYgc4qlDUep8fJg7aGxPwPCcdozYfxKGiz+glqnLSaShEqrH6sFmWRFWHurT9Nv7KH39LPablEx/l1by05vC2Dq+kr2M3eDNERmQt87mo32+vGN9Kn54fZa2j0M4r5LNf//68IGn8VB1Ziy8FjKGKK+JcOjMU25dehRk76vRn4u5eF5qIa4f/R2Exnjy7bxl8CffDKTeyFOH4XW4VZRLxVfngLJRM/+IvUQfly2HpkYF8BHZxmtypWFT+DFaZbCY8y68pUfdLfhkZTP2mJmzQkkMZpxfBuuvetPD51og2FoHX+ZO5hevn0DABXve2DqeFkSk8QeH/Rwdt4buBaqAxl8D6NF4hz5R/aR1rh3DRzyj69Ud9LZ+I/44JUhu/4Vy7NmJNOrlJPCJLOHVM0TRbXk6bMp8wdHwhtqL8mnFhpPQIzyG2jM+4VxnfSgP6aKMz0n0UFeEfxuehJBXEnDGWA4HThylsuABqFN2pe2lEuDTNQwuLA5DucIRfF0wibVT/CjU34c9PmriepNCvuJuTH2uY8BAZwZs6avCCXm3qGFeK+z0reKJr2M5KUwSrPduxmHy8yj/iRi8Pm+HlyzeQNGBqzy39QY5Tc3jXL1KvLm7nMW3DEK15Bda3isA2bHTUbksDsSWE4hN3oCtdRk8GDIOvmTPgstlWXS4JwRvr1CCaUJVXPvvLwsd3Is2kYl8/8EnEEq0hMROWTDo9ueW1BaekqgBqnZfqME5FL5Za8DiAXN0WS5I5QITYccdLV7orIMlc5NB1WQKGE2M542b3pJ4XCJO37CJYpYb0Na0V/jy0F1ExR6MNbiGy6VNYEN+DK6R1+XCcbMoMOYknHZdwX+uTeOR/p4Uo98FaXXikNKtDJ5n37OKSTNPWfOSK4f2+eCZ8Tjw7hnO73DiwGMG3Gw+hr8s14U+4TAw/inMfqp/cPeh0bj1cRsMHAmCO36r4bypCLzYfRxmDHFnlH0O3heTZIU9ppDdk4bS7iG4daU8R7gNhwklRfDihg24F+vA404TKos9TC26l2DF6HiYFfSE581Wh4O8GjIP62D6K8BBD0UY86mW3icfge390rhKIh2ko/IpT12Hkw3MYIn0H3D0AtTr+3+7/hdqytW4qEiSpuEwMNL9jj4i19E0VIhovgMcqn6OloNL6fJ2JWjZm8pfp+bT2PR48DyjzIc6e+DWDwOe6qCHmknWLLttGDS/UYU39ecxZnA5vNguSt5nDPFLiCGrB/6GhxeSQL/eFj03Z8DmtQbwyMuO1z8NhxOGi/joEI8nlFpRo2kSCq/Oph7/eEzsM4HfX/Xgaaocjpihx5qt1jAYfx9GwkNc924ppNosh/Vha/nutJXw8MhYaDnZjO87hHDchUo8diaQ2k6NBf9KsyE3QUx9+J3ie5V5WqgKBATcQHosyM1Kd6BaZzXUXL8OpVtjyP5SK+skDvIq/1ia2aUPkw3NUGftN+xadRJiflwHlwUZ5HROB8Kt1rHIqg80y/8h+tQaguKloxCYtIYv3luI6d8ccP/8Ahoc3swt6z7gm1Fn4XXKfuhvBXAO2APzupWg94YuqfRk8yu7O9B2dR3sN3Tj2anL6dyJcFCeMAG8/wXRXTVnynzqgCMfOoDXrDvwvTaRHQSX0KSc07w3WI+y6o2B3wNVKO9jq9o41Hu1AtpqhnPMAqYd75zZtDgHXX+P5s5JBjBtaMc1Njjy8CFve9T+gaxalUg7Q5TjdIs5pAbYLT0W1PqU4IvuX7pUbgcCu/9x6b9gHtPWTANfX2DXbA++teoLnpgzkysmm8BDp/u0SnoWdab2k4bIT/RaMQGrdIeji8I5eqK7DLLTNsIXdyOQPIykbjkHB/wW8gy32/Bj4xwMz68gE3Ri51AZNB7rgy90tGDJr2B4Wa6Bg88ucJ1uE503WUwF6t3UHjWcXW4P0i8feVDcpQP3tgiyxOQiNB0zE5znZ/A/LXmA3loIVD/BPoO+OHiiHNX2i4HAX8bYPzl8yNEOFyV3gNRNJc6tGYPnt/6GpkeF1BHXj4/PDoNn5/7h4tADdHjDaE4tWUiOETGoU9nLCQvnkMKn5ejoHAuqMjw0q3pYPG4hOsvMh4uXE2GduQR/6+/jput7sPFlCI1JSKAsjWGQaZaMKmm3wMJyMtdcvME5D87yzNPeUO1aDldnCOPJ/jHgqz8OvJfFoNkLNbh/cgeGqcVjydU04M/lLPT1LcYuKobDobbUekENVgTM5GvrP+L5QDF21zxCKovP0q7s4ZQwpxN9s7aQXc5YsjNTAVFbbcx76sJnnJ34m04tFw0xbQxcg5cxafBN9yivsc/H8X26MDWnhE6PzKTHyqMp97MUPPdfhiIze0io3hdGS+3g7o9CdMZOFwqP7MaYUTexe/103vMoG/ynNPLLqu9QFvcdnWO6MOCtE5qPVwCLaGn6z00RPCOeQOqpAGiWWM3JL1dxWkQizvz9kHXaFHnyZz3YWb6Y9Vz34TP5h7TQuZaaNZZTddMTXmw2Fp58R77f9xjHKIvBzxN+lCU1C8f9FYMRmu2U+DKDHpTr0TTNe2j4VQXbFhZhwqGxMIn2cMMmW+xZupdrBup5T406nC7woznPr6HjOxeaE+IIOdcN4XqSNzou9KW5B2x5afM4tJ70ktKfaMCaLl0+oVhO18abwD3JCbDrdxpsqpuP5pvUYd//vhnMW0n5+sG8R/gIJX9UYsXWFlhgi5A87OdQTj0DlSO+nGzmhjusB/hERi+EvRAEM+39OP/sJ5ocLgMLkrbRvF/dHBq1grU7NOG3uwyfKZlFoSPFWOf0fBaw96bSvCGOqfMioQMqvHVQhw67h2Lw+4mse9wR8vQZS+OOcdwQL9bfGQ6nvVtw8kF9VBlzmM+NzcDdc9JJ/cMdsG8ZhK7Y+7BqnBT+rkfwm+KP/ofy6fzk5XxlTDU+yGqEVwPzKLtuE+12H45tz3r53ABBRPkqlg8RIv0hB7wRYAyPtJbjEyUnklj9k3KC4rFmx0K+OBWgeXk8jZ4+A9Z5KOKlU/NA6VghffDbRv6NevTqliqoZM3Gc1XCcDD4AJw2egVpP93RY3QDbLWqZ8dZNpgcUgpN+6Jo2J1oUFUxgE/LVGiNhQCt6xnEzVtHYa/+ExjxvoYca0JxbuB/tEqbKSpCAwbnLqV4QXnaXtBP3YUS/HnBdvJqP8WbZKwxQNWcVO/XYEPxOMgZ/4pHBfbD30kFWDtNFP93j5GuSjea2ugP+UsFjVq3DJ8oaIKl6Vwe4WrEdpN+ornZdSyKzoYO3w4U3CdFnlXXYY9SGT29aADKFVa4Rq2URpfU8RXPdrSNNWelZlPUmEXocS2ZS1YKs+PbadCpLQ2z29RBp7seNc2Wk4VZNQXdN8c5g3v5r/tv/qayhxzOCEHJHF+8KK6Liy21wNdAHntUVcls/0KOm7gZHCNdedQoOa5+aQSXyw8QaqrBO7XpaLg1HQvL3tHBumEwsXYs92w7yyfoEbr/FYQe5wKKd2vj3WoPaK2dI1ZNeU7SXk60x240F5SJw/ANCvTqoz5MLZxHAhuXwyHZMhT3b6DGBmVcu2EaHdsXQf0FXfw4OYHjlowE18/JcOxaF03eHoP+uqdpzmVVlL+1m7SfRZLTrXVwsec63dAeAVPXFIBGxw6cluCIMreWYuUVC16z+xNtDbjO1WEysKvhMH9QnwpJAVPJPtSOlUXkqHYgkEklkDMPCrJzpxXs+/IRL30v5nglLUjc5UvbnljjnLNG8KHPlCMF66G6ZA+mXjvMYws38qItn1hp3DgonDCZHyQ+gCPup1FomSNI7tlJJrfGgHbVVahKlALVlA4KXSoHl066wMTxyzHmYC6uHLGfW4//g3q/hXD/XjX4B+hA1K03GJOL8EhkCWrLxHH97lo83pBIbs7bqc8uiQTSD/MyS3HUAV2+PVIYdga4Y8l7TVTZH41+e0pBSLuarJyrYNzUGNhKp0lNJph89WSh4/QKBrPX6NAczVeQcOTReNg3yp68DLTolMZutP8cjFU9crAkYz+8/7aFYjuGWGbOQtw/ZhsbvE+iBI/lKPtrHi1NtsQVtaPhoNoQZy2+RzJpphA2sYKNEsIx6E8/mtfNosJfgSh5eTtqFQ6HwzGvKGjhVHbWGiDt2Wv5qsA3fLTuGv9yHEElwTKwpDuXp+tpQYLXUKemmID6RnU8dPENtqsKc+rdh9hmux+KJwaCidYV2vd3LGxIieP8y3lk4hOPb6NlWM0rHgsnGVHv4lp6HSdF6+4JctYnFbBfoEPO2zRASyyHhkXdxoMdWynVr5hOxUTTU+tBlFmnh90VU6C8QJoU8pVZP3sTfvj1hyvMtsD6k1UwrbSJw5KF4LttICifBrjteouVDn/gMy2fsGxyPJerXIFdLb9o4p0juFNqFbxUrIPbocLg88SVg89fxquCXjhQIUZ3ff6QW0YIT568iDqkVLBhmQQHuOmCwVQzfNT9j0rtnrLyjXkoNL+BQxN3saJRKrn8DmHHaxJ8uF4MvBSPYwfqQ+jhT3BT4jM+W/WTRze0woFDmfA51Yi+6m7BuN1KUF50HAdSKtn7fj9GKLpyQe43/nVqCikrtoOkLNLrF9HwX90UUM7aBJaelRS0pph7vnuQ+MJIzGvz4v9KpXibmDOvl3+CQvumgoLzLoozWslhqyaiaIgGK9T/AqEv28nJZCrcLxnasynzuTXcEn5pptDatjB0K6yBK432sDpyG85LB0g/U4OTGh+yosoFji62hPMbD3KDyBjO2LYSfc++hIHXDiBj/xRO9lqRw6QxYCSjCqmlZqCf2EL3gvJgWsxzfB/Zw1ZDeRv1+B79LdUjqyGf7RlxF503ENzTvcOnz16j4QcfcMO+ENAakMDntvdY53UEvD1WyW5yP7FCRQ+27JWldVJbWU3/GOWcE4L4F0E01Wo5lOkexdZlkig9TR69RypDf8x7nikwlw9bRlGTvjGXPMjiuwkPMWj+EeqOngHrRSdyg6EAjDpyiPPvLWbplZdZ08WVVZxMUa6lFiQlAjFe7D8uvXCCFCYKgfT6HqzT/0c2oRY0Me477VeLY6O+16x/aTqdV1LDIaXlG4WjIdv9N32zCaMUGQc2vbaH4z2teVqPCt+1uUHieBTtk+1Aa6wU7NvnCtlZwXTujD7vHWmI1zVTUGVTMYjnL6Dm32fA/8NymHx9HNjDJgr685JP2zuSwuU/ACVJ2Bafj79jerFtrh4uS2rHqhsm8GD5BqgO98NZCg10jXzw6uoaEvfcg5GrMnFPQSHWXBDG0+PMIDFaiaOWm6LLXlFaraODHmtXU7t3CNkmHeDTtgaw0syPG7aOAtcSd5b50kJj0rL52r7XmJO4n6qK63lSix03LihCyYk5VLVhOng536QCpzscWPoeqmbZkPUxHZqg6ILFYhvxwEd3HFN7kZpfaMEVixd4OWsz2L8g7Ph7l/P7WmFmQBoM9LRCKl4GT+uF5LBgFJQdf45i1wShrH0W26ZVgn7Xfly3g7gixZfea2ZTYK0p2OiZg6DpTPSeLwMqJ1vwS/ktPJQeBY8XdMOKNVYoNVoUfdtHYa76eMj53QuPD4lSmGgxut+VYr0x9RQ+V4XRfRjqv/mNJ/5J85YuJchru88lOcN4TFomvLzJINO1BqL7H0PIiYW0W8qVb69uYKMjotDyfR52es5m4QmWoJHRR/0N2bxM+gUcfamFLlJavErTgGIEVMDqVy9YqCqTnL0IHt53gdQlrcm1w5pjS9r5Z1AUT9kpx5s3ykG7fwBd1KnmWXbP8GrnB/JctIm3vP+JD5ao45UEN/Ce8IxGp+nCut3naYHITyg/FMABoeHUHbkOus/UU9+trdRQ08jzM4v5dtwkOJLuwG8t+lC61hyW5ZSxq95k+BLjCavlg2iEdhGudB/kw9KyYLzDEyLPqPPECUO89lgAq/tE8fn0Ut70zod8e3xg9cgCtMuVgeDbh3Fspx45f4rnT9+j6FF4GO1sa+XHwZdg9ZpJtMFRBoreyoCp2AK4l61NQaPGUIHJTfghuwR2bj1KhTJduPJICK69P4w50BAiLXRgwbLlrBR8Hftc98DRVjHq+vQVhaIS4MG7YMra7s85doqg2t1INpoRoKkzDUzvP8GroxJg0qjvZHhcm+Osf6Kr5WVujzKDZuUx2O4bzDvPTKFzSy5z/DBDyO8zxjtZolQz5FcTrs2hjruakHPEg4LyB1DzrA3lvW9nv9yb8CZiHbi81aJYDQlYVBrMHZfMYKfBKX5+pwUM3FOpVL2CjY/EwB/1jfT67jJ2vtBGeXEyMHu1CfiPfMtTRQ5x9ulpdPniFF47Lotqrrmz9DwHbnbfDRejp8FsYVEI2pdEh2SrKbkoB/K72kjLwpyUT9/HpNpmPFFniLdrTmPTY2MYk/sfWxwNovMjRtHTzyb42OcvXJw3luiSKIR1PsAZUx056ZYcbG6/xpd/i5FFbC33PuyGzeun0FSTEHr4Yxl/m94Pr2SuwNoR0uC86Q29E/gHz79OgLMpflx2/Ah9Cx/PGSf/0tft88FjYAnWL1CBudMb2a33DX1cPYltJe+i2e135BF+ACsKd3HwFGMKcJmJ1ibicHzpRMxbUUlhFyLpYGos/njjwVs2D2VhyBwKSLZHeeULbJNA8H3KSfqkcAi0Fg1AiVoRRhf584DaQbJxkId+55e0YV0e+K1UgmtlZdyj2sAxwpI0fIc8npH+gg/lalFTtQWlxysz3p3HijFDnhJ+m7ZmuXKF9GOQ8gjnsJo5VPbzPb7X2ggHHVdxftoqGjghCO/rRLhuwwKsDE7DfKtA2lH5jjZ254LBui2g86AK3nz5TO82T4fMq0tRq6mOTGsr+VH8BjzcspyM5Y7BswcueHTeNxxeVAXqYiIwSvce1dRKoojbHTo9XB2svycOPX8RnIgUB+PUabR5iJ0k1gtC1bNMUgv7RQoHCklS5QHMHT6cN43QA/FjYQjtv7Hi7XUwd2a4ny4NovEb2KdVk41WtJHfSWW8VaRObxecBnc/LxKOjoBv1gIgkbmFrJeXsnamKN80OUPzhe7STIME1n5UyFbjI7HxB8GcTdNhioMIzhT5TQWqJZhqm0fax6Jw2fQ5ZFWtAYkLP6J18W6+PcIQMqQ7OW9WMDdmqLGspQCopO7CprefqM1kE6w9nsStOh38MlETapoOc1vvCRou1sthJrtx1/XZMPk/U5hlbkSHBRAH2jL4jboKVDyr5QiRRxz2QwCfLAsc+r0Rvb0D8AtF4/x/W/DSsyO4Y7IwBGgOx1vl01GNKkFY/wV+l77If/EHrU8/gHJH/cBJd5DdkgQh2LyDf8gMsfoHpLdCj0gxLZAK3o7mmFZ5uGwujefnLSKBcQgNQT+hKegBDjTe4SVJUrzg72tszD7KqLkSbJ0LwemyPNVliMLIMVnQHi4ONzqjqXLuMMo3OUdTN+0ABwFnlNNQw8icYUQbh8NZmb8c33sRmqLS8HKoICY4refr8J6v3v2GdWO10UHzIY95pgCPPLfTdtV6WH3ADURsgjnTe2g+/GS5Wv8X0FhT9p09iFc2DINl0yJQVTqHXs4oRdGBR+jpKUtWclPozeYlFHLgECTqleHdkinwI1Yb/8vNGeI5V9Ao8Ocl2cmQMCGSMWcMbqv2wbtXVuB1DQVQ9tcG34kWmP7HBN+o+3C7N8DDaYXw9YAdpTzsg2ILb96kNh46DU4i7ZUDy+eWdK4pE7fvuweOcVVkM+UG1Mkt566ZDqxrOhz0JaxB5+gJ+nMricWPWnPWAg0Su/WcU4OsUFPKkcd5/QKf2mkw4rMo56tfh+iKPIyYfwPWDPpCkd422jZ+AWd+6qfb623oY/IU8LvVSUqzYyDNKBnS1b7horerQPb4X1x80QYvRJuh8BRLzg41BT+1iWyx6ziVqP3FeL1m9DvphWZHO7DO3wI6bx8gtYZvNLXMEKzj6sFixl1YqfAXDDp9EVcUYvrnYxBW/Bo7Lv3gMBVlWOEyDQSqLpLc49845oULZa7LwsBmBXjw8TyGNJ8iuZYuWFMmBIlCgnBMZhJs3VfLeyT9MfeRDxpZGhHpiaFIRzIW+y/CdIH9PN7LBJz2CUKu00SSToxBSZNxqDtlKQgW95H/fD9wOxsAfzxjIc5WB0ZL2sH3P9ug020XNy0qQeMQWSx0346TT73DxGInkBxMZ7NryjD64Rwsau2gvB/R5ProHUxz0sV3x0/Qa+kKrlpchzD8IR8XUQRurIKk4LHw6tov3t7tiqMvGMMKVWWeJ3SVvWdn8aJbxykyQWXIC1Qw/0UAzg57Ad3q00BunyzdKBPjAMWhbjt5HWU1TvPFACHQ4xAKu9sIxYIxJGazhoprt9CZlrPsIbKDCtK8aaF6GydrmYLdLkvw++KOl9x+ULz5c4gUiecHk83Rp+oflMk/hTqnO3RfUgb8tz7CHw9C6K2iNi7YvoxVR1hAsakhRh2fwJpGB9FA/wY8cRSEjCcLYcHxOyCq+JNVKntoVH89TRk8z0EP/HCCyjo+WBJF0g6yECtnTyriL/h8Yiocm32DTiQPQ4p9zZHfBihbVoz3xMrCqnZtUNeZBWFPP/Lr/dN5mZ419C7tIq3YcujviYQr4lNw6UgDsg8zh8Hg+TD86A6MFdIFhbEG9MpRg95PHqR87U2M31o4pcYQfXsQxv7nAA8m29GWmUUYY6SNby/fJWVnJ5g0/SnJBR0jyU+52H9u6L0edjhe9DvdrlmAyyRewV2XKdgYUEJy/mepQ/4MqV1swWtdU2Bz+QVS2LmK6gbu4sxJyWTnHYnuP2+w6aURsE9TGMRSDDB5LEHE7Bs80+oIt9RfpPuuX8Fl5G8aEa1EoofP0pzxHhDetQV+tYrCipUR2PaunpdkXeJ/Nxpo2p4HsOz7Gmw9MxNjF1gN7Xc6RptMhtT9D1BydA6rCDZyfUUKqT6Npa9rrsCJK3lwf3IGuz/TwEMJirA0QY7MFpZiXsNP1jirSdPO7EZRnI0vbnWy8YTDbN+xm2eN1IakK+a09ukRMC78BHOnJoKEbw+QST01v7SHvebCOO9YEjScsITebD/e+8YDrrRPoT/j5mFybyzd2B7PgysccWCVMU/pV0FPD0X4TxKG/pMI9pdXYIPINtYr9KID0xfDtz3HIfVwC7ksms1GJ80hb/0PDHeRhz6zGXjYYA4dm5xJsw/20+JeCUi8+5on5a7HU0vGw7+/JVy9tIn8bJdxUqcplIi84iavn5D9ai1aFrlxvdt7XOo0CrIzJWDTpIf4ZcZWPpJdyZNkl0P2yVVg/1YLbDQl4OrKvVxzUxBWll6A+s+fIKp5BzyvmcLbbN5w49f1YFuzHft6NuBRtQlsN3U0nF9RCOhdB/Jqw6jsfD69VzbmtrqJOF7zAHmJFYFbyAg652AG045247Fcb27Qus6uXTP4l78q229dC1Jtx9gk9y9JF63Homg9OJs0ijzSXtGJRbPQMb2S6iac5y6X2/zs/AgOCfjFPe6M9pH60CtZiCsPtpJFQQgoZC3EdWdngH/aPfJ6NBsG5qThiRtrIWTRNHB1OwKpcaeZo9rY2fgZXhwtxfNiVkG22SHQDMgC814pkIlVAGOLLFwU+QZqU9fT9qIYsPj+E29INEBigzN0P9aA5QbS8FZlHMR420OmTQ7eLFsHxbp9vHvHObhYsRfvt13mW4a1cJAIR/RMAr+wDn7kLkr+hzPgesxsXtZynr3Gl3OuaCvaNpryZ/+vAILq4PQ6ildd+cstirehvkUY7utVsFamOq2Y+ge0t2zANUk7Ye8PAbA4uZxzn98lD9lC+lJrgQsGNPnSyHrSalXlMz1eWK4UQ3olqiBkE89GKY4UX3qHpStmwPCPszB/TQwunr8LI8ys0S2xneROGoKRnQlJ9G1Bl+dOUPfqBA5+eAHF3q5wWesjv9Sw4ASfO9QxMBwC5GIwJr8UrwpsxVUy6dg+5D1n5XXALyaNHB2b2ao7CQtvSkOB4GhUvb+MAzUv0puHtnRorg5fvVpLgr9nsIZjNpz1PkcHlLXAaHoaJC0/jc2n+6BNpR+Hy6uBXJIdhh0dA1E5j/jqx5tYO0MGtk02pWVN1zEvRhhv5ixE/QY3CtmjxwGzXpG/bz2+XtiOVgnCcGKNHB6Pv0dPsrSw56cY7zVMZjGPQL5UeRJeeZTD/3Fw3tFA/f8ffw0jQiFEVsgIyUxERcMITVJS+giFUiQVmhKRQhOFSDQ0tEQllTREJFFIk7RsSf38vv/fc973vu/79Xw+HufccyecFgK1IW6qfT4MeqaY81j1c9RPqrDCJILPlr3gT0G/8FirBuY+3slvv2hB0MqzqP7yGaQ3NMEHhxD2wp98WfsADasMpbtaw0Fv+1FSk5eCmpWr8YBrHV77fJrG+Q5114m7MHuXB4e12oPWT18eo+cEhxwmQ3u5Bq4zUoewkl8sr5RKua5BjGt0efVmIT7Z852qSxRw8kpBePcrm8RFtHjnVU34pJfJRQcmoprsHqrb/YJcZFfipz5neD5zJLzceR9v/tCFD9tGQ8cYf7y36RKVKsZRjvJGXFXoQ1Psv7HVaQEQ+erJX2v7GMwfYf3oLvCgPBL7MxbXNx6AmJRKrt8yHxbrK8PPvZUQtOAQCM+04PGy27Cl2QtUFj5D/XBX1L+2m1yfZ/L7wAlwu/8Gy+Q4kdKSFp5ywg+NlcWGvGo3DA6tZ6CUzZ8+36NJB6dAinwpi+3agWlfNvN9y1f0u9ic9x0dYIfCPRBdvQXVTRG2LjWBKL+3+HDUTT546zNvHu+HXFPIajWW8HxKEcbcuMrX9aeCjKQIiPZ+xfubkdUyX8L9YRvpVsJ1ML3SjFaFPixurkBlG4QwS8EC3JzuUuClkfhgsij8ls7h7BveKJKzkho/9aORyQyoevcHa4v0QT3RADPaN8KJ1teYOH8PHHkgQVnbYqnJq54rwmooC7ZTeqU67KZL4CZjgEVd9fDWzQo05+aieu8puLH2Hybfns+PrCezVL4ADHv2EGfjPZr2IxMDd24i360yINQlRmbl+xFaY2hVRhjQYiMQmaTG0TLO3P0zEE6VxuJez8fcq7mRdxd3wcyjA5isfoQKHBTB+6MxftePgdtf7+PkhCVg5WgNko5OqDnsG6mta6N71e/wmxlB/SI5tGl6iQPog1I6RXDu6GWeNtWZg8dNgrarp/lIaTstsZOBunJBquuNpiyBjzhp2yqcrFpNT/w3wLg2E+6Y346eOORTC9Uhfbw9Ok6cyTeNhpxl7ReMmDEbtV7UYmlABRZK6fMI6UoIvSYC9nEAS+eYsbiKDWhVtPOAry7i+cukcFGR9ZoGSfjVGFIdYQZffxzhzLlZODu9EUqUylHmlhmZFSzF9JG3aMInX3imn4W3StUg53MWhW3cQi3G88nydDEeXZaOEUnHUepkMGg5LOE/Uz9ATrY0tM+O4sFDmTjsewnr7SgAHedKcm96jbH6U0nP0HfIxRA5SQXW7wpHu09bEBKu0ZnfH2lJ+QRuFbCFh3vjIaH+KLTN2Q4LH6iC752tPO3gLMzf7gZPgk9iW4YwzHR1hK69dlD31IW1X1fTZlVlyHZR4ytuUbQuKZBl1PTotGs/T1K04Dlj50F1kiU9+NnO2ZdHgnyiLZ/c+AIfyE6Hna5M12Ln4C2ZixzswqwQsA8vSP8HhtaK8Ka/HsKHn8S0uBlksNGfsnfdRxNjTX4VdYVjpjRwyCo9ujHTALTPTgPNX2Mhe1wK9QYkYWPCL8r4tZAEcqzo1dPVIGq2FOX7leBckxGb+Q4gzhpJq6P/surcpzztSQUsajgHbK5ORZPO0qzJqnBjuRAJytVgU4gQrbHThMCgShgYe4AmpieSZsVB3N90jzjNGqYeiya/YZroKyJDf44G0rT5+3nXcUmcknyGFYfczbh0NQocHAlvo6+jzDkDWtifwmuylKFK1BVVfzfg7vqrKLXHGu26luCYy+IwbcEBtpazhTxcCTkXNqJ7/1WeOTyTT/flgV+2HfbfD6FZoyWhqbEbQh68ZPnVZbj9xm3uzlxLwndNqLk/kH0qP0DiBOK6VCP4kuKLom4dLJebQa7rorA2nuGNWDr2ZM1Bxd82dO/sNvCdrwilf25Sy8greNa7kG7YnYNJDoe4OC+As3Su4/S1OiBQ2ggKrhbgvvUKPS6Jxqxr+yh0/3keXPEIv3r+gtX/9fH7xFGo9Go6zXwwAijrLFetf8AOMx7Cen9vvBm8DnMOIazcloGlBcUYNK6TgnqmQrr3LH75ZDYVq7mwRsRZjDo6DZXVdbit7zFXtI2FueEhtIzUwVViAsjOn0FuV/upRucyP7zeT2Iq6rBtcjkoRtwhD//fUFlkAH05WTBvtQVsKTjNL668Ygu3BSx2ZQaMDfjGg9+uUnXcUrj8Vwu0S6fDR9UqXLlpK6bVBrLI46+U1uIJG1Ll+FlxCP/77wwaVujDuK2XMPGuEejcjcfT23xwyUErPlzwhbZKhaFz+FVKHvsPdZukYcn5CTA/dg95Opnhsq8BKJs7DgU6d1Ov7Dy43puD81oOsf0jS1Df8Q00zVvg4Gd3mmZyAwQtTHDyo0OU+88KmntyuXZPD71tUoJr6dsoVjeVD5+/RfXgTEcSm/hVcAe5ORaDjpgDL7YVxMpNE6H08TNan3qCI2xXcEG+PC/0EUbrqBZ8X0ic1H6Q801sWL9EG6K33IFpWwRh71sBOOdURE9FSzFWhujwyen8IVaVNq8+RX9nK8G71jDq/nwG7x3RgBEFO8Bjky8vi0QQwNE8UPUXev+Ecs1iJVgyvRKnL21kSTspnr9wLi9zzYYPD41x0d86qJ7/ndIbOnjKhpFQ1HYGfcSn46pMfbgSJUbjDvbybZ83qHC2HbKFDvKbo354EEVgSt9lfr1PBdUm78ZvWxPx27LpNO32Efz06TKaakRzSHcu5cxRAi+3kfR0vSAe23MM09vGcuL1XrLSvEc3fjVjRetzquvYipqTFSF3Xy2p1clS7hd3ChwzwGd6PeBinx6rybbglZlX8cORXhocYwQBg44U7nKOsgUrwFZdGJ1DT+DfSQlUk3GNC5M0WN64D+NrR8GK0eUw+1oXtziKwuOinfC3ci9ID/vNS6/b8aO5x/mU0WKKWkowP7sPPvY+pBcVGXRdW4kuPa+jyR9TYf9YObb5fAcSryhSSpUgjLhqzFpf4lmzLYb73s/mmtIeeJKaTBO/n6H/hrpEM9kAI/1VYJ9tPEo15+EGD2fo3LuQUz5HYv3CSjza/p2tH4uxrU4DRNqaQcVyT7aK8MOoTbvpr3k9BsaMh0WviqHk3WZ6rmuAjm6BuKZMD056XIenQXNhsPQY1j4cx8c9vcgp1Yyn/frCdv692KORwT9/WcHDfw9h6owcFjPqwPqWh7j2XCdrq1bClqHcm7FjK4itfMmG5XKgXiJKN4M24zStKk5XSKBDtc7clH8MUzeWQhkE0r+Dl3lxoxRcdN7BtrLT0FT/KIkmSZMG6eHI/x7irMJHYOdsxCevfiR4Kwy7FF5QeP9rmvLrAXsb2eL64YuoeKIz33k1AVd9ZVSpWcwey/VAOWQ07MnN4srAZN7m44eLco+h/5ZZkD5yD/0zXAtLNiST8UdrkFZu5YkWgFgiBUt2jabFCpFkPfcipok7oET0VZ7mQXR8hyEssvWA0tnFvHrqSLjwvJITpN/h7ugnbJKx4n/fMovkN5LyGjOYvz6NylSEIG3PGPS3XYNitzw5td6a//ucBM3mJ9j72noaedMMNM4VwRW5SRTVGoF3VMLxfug3+KwZAy/MK+nlYT8wj72NiW8NIXm4Kz2fdZKvaLjA+a1vgb8pYI5aGkvFZcP4Tncw6JtDPwOl4K6/Nou19cFTzV/UMm4jq/Zn4e8ZQVhRcQHa7+figR2DeP81QpfiHzyrqoRJdYtg+McE2mUmjjFKyK8Wroeg60P+GzeTVGS1YcmeOZB4oZIe3nKgxf2T4NCNB5Tn4IC+7RtQd3kejl10BvSuqA5x8AaUq+rG0dt/wLoYC1oXfQtrrlymGdvFIHjgBN5INeUYf3E4lroC5EZmkdVtXVjU/gVaVgfggeJbeP9wBxzT9QO11yoY4mQNC7euo17bs3BO8zg0r47AYPsYeOCmDKee7IS74TFsmNhCx30VIOX9MRDP7Ib6kP9o79dGaBRcTs1Pi1j8iyWmKnyA0mdPQFRYCAS9o6hf2RiVwpey/9xEsiF3/C1UAg+shSh2ihwXr/3MZ2drgmhkN56aMAtLhXWoNFcEeqfU8NxfN8Cu8TQHjD9Gpzavw4yvcnDk9S9M3j4NDltuw3t55/jDolxKC7mAN/Qv8oz9fpwpNgqE/WRh+L04Dn1/kaeaJuMdFwP6fEcER6/UxoQfMRgUJwc2b5vh8UgraA8ugu0DhvhlfDDsrfxHlWqfcZ/WRrottJfOLXUkG6+XfHCeKMhLS3Kq1gZKe7OIaNp9KD/pxtdff+Rd2c/JLiOIlMZ68JsFQ/1m+gXKJhqD30sr9lnfDjeONdHTEct43iknlhbsowX95vwkfSzkre+GqA5jzHrcAtDwCST1PrJCthfI5gpRzK0rIF8biTc/DPHaf018bE0zdGvkocPBOjQ/P4o/OvzjhLuCGPiogir//YLXpeKQGDEIT56Z4X/qOhQSGkuHgj5R3Kl5UCq1EGtXRZG/xTc6NUkbUsd1Qfg5Q3zRUQBzjf7wzV+vWXmaHEwtvkOTzOUpa/YxmD9vBJjH78FDT77Qg7pBnGS5iVXuZUF3yUmWcbPnJYeGY4l3K8cWy8AK+1hU1y/n5dN+0MGyQFp/S5P8jq2An65ZUF52CozfvuKRfwRA0OE6HTiRg9vG+ELAx9FcoBEPUfu7cc+lJvbfns9bTK2h/4EMnAzq4pQSL3aTz4Dtvg/gQZoK9rhdJsGUIspab8u9l97j4LDh8HfeeuKJZfQiYRtPSxOG8I0huHTnPdoq+ZLXN0bjliXTwe+0BfzwMcS0ZjVQijZhIX8bemtpwCsH5GikZA7Nj30L27w6cVXacBDp/ok9Dy2Z5qWCyLylpLxVmRWPC3L59BYMsaigeUPX1o9RBYnSV+z4az7nimVSxdFHtHfBVg5RX4amuAWcxn2h9B8C2LlCANKXnKRj9/1A+tJNvGj+iVbOi4C/i5hi+zNQdP1BdFDNg4QwXVA1FQX7U0V0buZPjthSSO8UDHlblQfnN8pj4gltLHf4CDN+icFt15/wdY45bNy/BN7+O0+znJfhwb5MyN/ghrW+2jD/4xd6elYZFP64UlCCKA2bIQPjhE9y6o9EkPv0ZGjhr/xr72qeXRBCuZkEBr7eGDBlKzZeSQCR7PMkHquEFsUWoPhkO3+slacTI0dQ/HgGD8flfEG1HY55nIP+MTUUXKgNjxZ34bf9Wzn2YwqO61HjyEiACm17DivqR/d5VyC+1pXFdy9CL8NcHkZ76PzzRpBb+h9+WDkR3v37BHsSWkj/oRTl5ljQ9QNO6Fg1D4cnB8AC9TdgYiJHTc6yoHVsMSpqNtJt6U+k8v42OWrXooJkC25+r4ZxfVbc882PF/4bAaGDB2hZ3TiekHae0+dYYfCZYSi8QZ/myKrg/ra/PK7xIa9arQFCZ2TZu8kHz/wnD13HTvFRuziue7GXj/vtwJQ4Gbr2eByvFlKFZyvt6Zb/eSisy+LiG5PwroElzngy5OPxryj34jP++1KP4wxMIcnsDn4y9QLLd6/xIsbCqQsj0Gf9U1AQFed4nwvs3y7OT+XVwfJ6ALrbhMFkxRw0GemOb+d5YtKsVZwaMwEPmOtwne1lqBkxFk5NBhrrP4p/BSRjv8dUDPU/gKdtFLG65zjMsgc+7PaXvp6bBMNdjDDDw4NcNNZyms5yCpBaCv4W63ltzClYuMOdlpzq4AZTJVhlv5FXePzCgYzDtHXnQZJQMseinHbc7/SYAp174N18aTi/Sxxaxw7xXossBosCbNXw46utD+BUayoW/BeICrM7OEpwL3vlToFCsUj8eU6QSqV2YM9YWxih1IGG6y5jYa8H5y07C0bTqzHzAIDoJnmeI74Ap8j9w6T4uSCmexem9i6EUtlw0siooiX2u3mn10jYyMJQkm7Cx1YUotANKxghN5xcqhtpzQZVVrSQhosGElR1ZgSIBatDu+MACwm8wZvP38AH5RsU9+8/Dlo8gWQ3SpLEhEY69koDfmuEgsuT9yhoYYD2fn5cZHkKC9/bQLW6G+a81aXvBW306sJIyG7NoSPyX2lssiQteXKDtPpmo+G+HEju2AyrC59SS5s0nNskDlX7XpPS/K/o1vqORu1qwN79bXh8/G+65fyKMkOa6O3VJDDvHA4WjSmwc0k7S/nPgn8aMrQ8YyXpbtLnPCtHLB2TCOqJy6DZXQ9KTuuRnEgdvVxXBsv3KsLo/UU816WL784JIL8Li8k2rwYzSBOcDiTx/TmyZH1sBD3+eB9yGpLQ9Ol9PnlKA61H72PbpHsYK2kK9WaiZDzNDcrWHof6zi7a4HsKXvb1gNz2TjKUuMmai1Kw4oIcxDsS7Lu5lwtinvCdc0aoJvkfC694hlOqV9LSl1EgUbSTdANFwP1dJ0XYaZKgshtGj1rDaqFDs6fdRSpukTAsK5+D5Q1AU0kMoAho0cZ49n45DQ6JjcGgzkqUruslr7q7ULQ3gybOe0rtZSpgIXea1a0yWftTMxdfTcO42ftAe3YKHa5/Rf5N/1Fx9EV2sLeCuWKnePYHb6xrN4PpSt+h2fc+hF/RILdlt8Encz3vDlDH4BpVEPbq5N3Jr/hn3io+avOAOy7/phfJc2jJvb9gPC8bTlVfo+6jliCksoKUlj+lmofOPKazHiR2yFFBQROtyZ3J3ZaefKjhLF1OVoQ39nfwhtcZ3rJGnQXNFGl6bjTO2zOBR6racdtaK97h1AWCKy2hvncyX42LoIGIqWyQUwYPOrT5ec5jnL39Iva9KKMfoh9BfoiH7q+JRj/rg2A1aQbbWe8G1VMXUHVEA6o3KKN5gzUJrLPBRx1KkHb8G5zJECJhEWGcvCmExQsvkURLKG2TcIfrJ/JZ70sxnXpqAqWzAul1TTgm7XiEzX0bOECuEYvM/5HI/VFcd3E9SO3fBKn9KnDKvRGp7BOuCtOBFQOZOF9qIY8f0Y+zqnL42Yw3MO7rASyy0ofguPnsMPs3no2z5W8Lbbmz1pB/3q6AS982QKTmU9h2ehXMXicHufXaLDLmFBRKroADBmZD8/8WvnaNoxe3jNDKrJHWvU8A9xvDwTPfBHwXWENEmDF7/1ImpymPeNfDHJzmqsPX3ubgfmUhks3UArlzvWiXDWThIMlv11SAbpcrvRx5A5vyb+JVxx/kod0AX6TUIeuMFEg7PcArQxmmt8SCVy/WAC2ZPPg5P4qavVLRy6QCsjM14O9oD8qP1qF/Fr7gEVbMY6W/s9e0RVC29x4nzeyF81cbMFZAAOL27sOcrbmUqeoPR+TnUFzskLP8EARMTmSdm5HQ+OEUmp5RhNrU7/hcM5S/OUzgcz/f02EjcxgnpYtBxxtB4s9XKBB1otgcM7hz/CjeuSlJBtMDceetH+ANNhSqXMxRVy6xVtAUdJoZQ+vWq4DI6ttg2JbISxdU84/pubhiUz9mhFnyndZyvFDcBON9fsK815PgT2srjDtZh15vjXC3uy5luG/Hn/JHODPyGbzpDUDngXqc5zACBAWC8U3+NnRdKMgfQ+7x1L9m1PRoPI25gDAVpcg4LAucbSWhfuYGnjQ7jD3FHCF34D7K536AiM8j+bfJJ3otJQLLnT7Dzf90IWJlK0p2FYBoZxi4f8jjAxHJ+M7OmEUfVuEG1yKS+9rNxyabw2G4j9MThWFYez5P6tahS9NkKUfWDe9OnUvr816zQPoGfuGuA8c3bMXEYbfhtdEj/OGxjWQvb8PZF9XAuyQeFZTt0XD9SJgzTXWojybAuI4ydrjoziesBXn2l0/80PU6VNgasKv5AlRa+Jov7tMBV8HX+Gz1dA58PY1tks+B3vWb4KBmDHnyESwHcrxfRoon6avCr9Ya7AhdSfekFnFi+B34rXaHd4u8Jutnm+DzhBCuyonkXZVakLDai/0qzKFZIZ6jzW6AwTp5EqldQBenL0RD8xYOy1pEml+nQnlTBln3vQUBbTd6cyibr+dL86GYhVC3sxSWDrfAcWM3waL5CMufPODjtcO4z6WTztatpYbyKpwk0gmH78nQ+uu5XL1Lh47mWUPT2gtYGiUAyuML+VRhAT9em0yJ3+/TbZlUuqsqAFGnNFhGwwiCUxox28GGqh6Mo7B747mmqQqkitpwl1Qn3lfUhMNxLRyvpgd1Oj9pmVUzBnZpkPpwLfpkcIn6KnbByKp+nli1Dpr3XmKJ1iHmc0oC0cXTydf3NtrMmMXWUQAz+6/xLLf1VOUryekZ+zCrQQhiTwXDoVcR/OaWE0v6AC0TFSVLi1lgHPqJ/subDT/2BOEro+Gg2dpK06fGQtrrp/DvajtOCJwFp3MqsPSiMz2uGYXXy5UQ1orAmwpNqniTCZXb9PCmTyKlTLnGnQFF5PdggJTCi7h852f2TDWB8nlhnHFgI0kKbGEPU1mK+LAVan/sZAP3i+SrGsranea8eIkgyM7YSjPmpkHb6Vbu1btGH97lQYWsExtqDSM7MzcaEePDv/6ZgYrZJux/vYNc76/mNOtESju/kJRPyuFxb2FOmBuM4vMTsVbYFBwef8V7j0dic9kI/iMmSQ57P+DpjZMpc9NDOjJCHnRO5MJnsdGwfuFeEleUhbAV2mwabI73r1QjjruI/44rgtznw+QlEwA3uoaD1X9HWWyoZ/WXdaB6agPVf6qi3MUFYLt4D6TnRvPMZTpkX2wKF6Q7oX1BAD6b0MtSLhfYs6GR+guqIebzTj7+8SC2xNTDvtMT4PdiYxif+hYvDIRB/ro49ND1JaOZR2hTtSzZjjRE+5cFmKQkCpLmqTRYsQ7qtQZptKU8tBuPo5dkirPS2qm5OBpz516EUAlh8L0awHq1WRxg0gyhui48QjEBO+0NyEd9CTnue83P+4aRlZc1mATpYKJINqYucmGvFYe41/sh75s3nGcFr+CnNk2k/u4wb1qkBInz+/m/BRbUP6sCxJ68gEXRjZC9cAzlLdoDSa4DtCmoCfI7pOH27ct0KPwUywus4OUzjGDNx/GU2LOQzML3kk9oH54Q+AOP7wxxTpA96tvcR+v2BjCKt+SaBUZYqz0Pi78p48yv+/DxiSe4cocYKD7cRaPdTWDWbDHcIT+BnNNF6MaqQXSodKNiyZn80qAcL09h+K+hBR65yGBJ7DoKOOdJkoc348kLsvBPV48Nd+ZxX/wBvvvSDK6ZPGHpU9/haI0Z1KjfpfmZs/lpcBK8nLeLm1y+wDZdI7h00wqGW16DGSqLiRrESUbfEg5O10G54uks4f4Ddre44oP4T3R2pTAI9D+jAztdWLX1GQxsHMdGCVLUHhHBR1J0WbwiHJQ+jIHDHwDm9+7GZ+YXCX98oq7YLnyv18BdzXH82VITkkfIY4bnFVI+Yg4vN0vw2dkBNMKnFE91TsWU6xNow73heCPFFt6q6HDlp7UcVz50roy3gVGYJyQ+vo0ncsdA0OVATDnZiaJCS0D7pjNOWtnBmz3UYeaYSPa+JEHud25jQaIlBvg9h0dtX2BHxQncYRoL0nqetLlIA1K79Pn2+nKuqaqHHUqVMFlgAJ4PE0DHh99Qp+QcHkiYxWmhEnB7Vz2MbRwFYxum4dXTu9A0LAdB8g7tWCaABhddqTMrmiYvUoF99Yl41v8Vi47qgMH4EE5c+wgm+ZSjwahu+vxaFQxybeFFtDEsF2hjwZHIzu9lIKXaDA+aMUgIaUFLcS/tcCzCOvF1pOEiDnunn+HR07V5+70xILLJiTWm6IDhoj0cNPMtdceGo85Qz073kYWv63v4efIqkKx6SpAagTNL1KAgrRILr4znfUeqWEG4GHy+SEBw1CDJpWSBuulxKhp2GEWtSnjf3HC+dCsFf53fzdov/fmvpw44VFrgrvH3IKijGT59TqFR6ucgZKMdNqq9QReX1XCl+BvnN8jCQcNGbLtlxrI9JdScbwY9w9wwMLcdvyiu4ks/hHnL0ku8YJM86IdOptPjdkKj3RmOP6mLqs5byNT+LExt94Zk3Tb+PmM3STVpwuLrtSiS5gtvDqWTVrwL33X7BQvCV3JQ6CHoy10BljMsUBAnwqzFa3lMjTS+MpyL9frjWfLWMfZOX0AtoxXAwKCSJ7af5mOrlcFi0mlat0cOvd08yXnGfPTe+4xrZPdBvMBPdNJ6z3vn2ZBtmyoMS37BE7quwcfB7aw/7yftM57B5hWPqW/tRNjnPIevv3DChncG4GnbQQ9fGNF33Z6hnPvDCdf16bRcNCWn/IJT8t8wMXgi7746HEbhObLP84LVBnuwNVKe0//J4G6J77R25k281WQL7u31pJGoAwvGR8BLpcuccOsImaw8QGSshyL9V8Gh9hGm1KpQ7sg7vCdcFWYOxPIhLKO7VWuB9VPwZ2c/7525iS6Xt1Gc9H5Ys3kjHrITBNfC/eR1VYJcvidCYVErzLnyEYrd1lJYQQlkbtDm+kdnyLdKESbuucV34irYY9ZLrIuUw8dRQ32b4Au34i9jm049N2TK8yt1I4ic0o25zedZqf8puPq4Ixw7i/cylfmohiMctDZh5Ye/eNt0adBsFGfZB62wbWMojMrWB2FRfzgn500FhtnU1jGN1m7tJ3fLiSDvUcKxyXU0+O4CDbtbDnZHZMDUZwOab5BFRysjlIyXIwFBC2jp1kNhE0/oX5aA3bXG6BGiz36hYfQ8YQtdmiVBPUJHYIm1Bawf9odSmmoo6LIKKNk5072QNfjfoVGYVhkBCbUHeH+BCPRcVwI6tgvbig3QTNiHo4JGofO0TJjrWwZ3vn0E4X+b6f5OYRyYLgOP8g+Qwc5/9NPYjHXT/fm6/xqMDIygL68rWaX6P/pSu4aUfFRhoZUK+k8Yh28qnaA+uwoqZ0pw+IFwWLBzPJd+K8IBmTq4KjMR0iyvsvbT5WijpwwPu15Syqi/3KxzA34cjSP36ldwuj4PbYb276SsCXSojOPpuzq5caku9TR8o9dLHXnMlRhYs2QeKxt+hDPqDFWuS1m4/SqtH8rVLvlG2tAyEUQmJVOecT/nP22GZaNCQfC6DETfuwBF1o20X3gyLOsaDzXjW+iMwRa4uHk9hZl04quPWnz1JEHW9fs4VjoRV/mJooDrAE49OpqvJvwiJ8tcSg0Mg2DxaeypPwyOH37JwmE2vHG1E2d8r+Xa5lekcygFAuw2sYeWExlcHYOOlgx7B6ZTfuwMrm4swjfTboPix2206aM5yb+eiKUblvNv8VHwsE8Jgk4+pgXlw9B88BD+zjxBDScGcMQ2A3Q5epqyHZNRU8qLXwwfD2Jv/sF+d1+a3DEdDe/eobf7n8B29914/VQwirWa8hxJQ+hIMgaPcG3wshwPK0dOpVbrcTS4bhwONm2BmedPwfBvkmwufo8XfjYGL5vzuOHzS2j8uIp1DA7ASaNGPlEcx8O8n6D9RQW+FFoEgQuUQF3fAmqFGzi93Y8TFAe4a9kNXLPmB3kaTYbNkIONH39h2QFx8JUaSWLVIvhwdTWUFx7BKrENFDvmPH2etJQFr5TR8ZVvINBTCy5/CIV6keuwUHQfvj11GhVel+Py4iAUe7wap0+oIOHBKJa8bwCBtpW023EkjtnRAkKj0+DsxnBuUDDDhOapVAiH2dg3gUrfm0O2yixsWxAAz/0PU4G/LglXnYWRZzWpfkccWYxQJ+ndKXD1rDKsnuGLe6bPoHvFRfi55AWll6+FVNlocJxbSTVxuzGi/Dz4lonDtpNTWF5xM06u80Da5g6/z2wGK71QKBKv5n2FUbi64CKd6JeGajtF0JQRx5vX3em85yk6sLsekwZlaK61Kb8XjIScrFSykRoFs63j2MVDjl9fkuCwOfchYXg2ztk6hZ8kraVSGVdeq7QIP01Qg2X2zhhiXM7f1ndSTsRoktHaD22r/vG6qE3w7NIBjr39F1fKmUOq0wHOmjyPvv6txB9LpvNM7XV8ocEUL4pEs/ioJlD7bgr3do2G1JAi0DzznYOnRfIscUO69HURPh3iwiciK8HuTgf8C8nj40/Hw5JLa3GDxQy+VGZIlS3DIbaxhMSPLKCZloZ8dLsODyot4e+uevDlyDpOXdSCmycMg0HXV5w8Mw29rnhB9o3/SOmxJf4Nd8J7bcqgeL6KV4xdiepT38Ja1YO0ZMkTDPZeAcO0ImnneH+MWvOKtQX0QHBqPn9QPwg7/g2g5MRiyBzlx342PnRQypPk6xxxp70h72nSg+ZcST4dNQfOnMvB7q3nOGF5DFjr9fHU0bdp5riv8Dwpg+/tnwQusAaS1x5m51kbWeigHu6zTiL90AHKGvwDRu+LMf+RIRwqN4R67VfUfrADPLyG4xnDPi7JnwtzMpbAK7rBki3yOLvlNWg4IKz8IAtNY/ogSq8fDd6kwcQ+A3q4XZi/5fWS8vdiqFepIJE4hFXXt4JOjQr4tB0Bl2ArkjYaD6lJOnzs0AkcPWoizisfQ7YzJoHbwfUo/iOW2na95/Ouubg36B5v2VWEGXrH8LetHv2RcuJ9SRZQKCCOmR/iSaOjBH/cS8d9VdJUl+cHcee70cxuDc04tg5svg4fmldHOrzrDfaGH+BktxJIDwqD0EeC/P6sBTnucqPnUSowQUIFhsc95+jNpjjVohsiet7icvld8KrlCUf/m0nBvwXB7Es/F3WrwKwTrnjxqRCvNtbnuxa+lKz8nqUOl/JmNYZY1YvgsmA4Dx5SgubRuznKpZ86Bexw8fgXmKIhBrsFJ2HuaS/6fmQf/VBAtLqpAZWFV6kq5jU8eLSH7JNW0LJUCcw/fYbD9shTueoFvOXcTI/iEQq1BTlNYjOUdRrQp3MDYEk1fOTPbZK+ok1/nFbR6gNRNOfEcJA7vgJNVBVwRMAmvNW4j0dPmkqWz5w5tG43vJu6kxf0GtAbHT0IFBvJfxtzQE1pKkwZLcrvb8mSi1YAf3oyi/fPPsz2oAWfj0rA9DJTcPS+z7W+6wivdlGilBBU5JZB1IgceKPUTRI6YrhYSwrept3kEz23sS5kLardqcR3357j12oJaEidw/npY9hwfBC1twEYwXE+uPABOV3cCSOsBVF2zTIKtrFgFRw7xOGy8De5FXuOMnwYM5rWqC4e4vI6OGujjFsy9sGb6iv4+9wxflL4F2PCCvG2uArkZyeD7kM5erRYntJr1mBZ3jb+ZlvGxTJFGB/9DVk2n+1LdMH/WgLm9DWiloQIjVmYh72XBbjT3II3lZtAVnACdQQE4z9lIXh0wJr1he4PzeZHPuqZyZnnneBmw16oljQhBxN7iPQcDYaSE+BgTxOHV+iC9ZtCFJ/9ASYuzeADYrspslkGikf5UOd8eRJzV4fNKYfhq8AZevv6Em/3eIlLlZ7TyesraCC4EdJ1NuHaMlcobR0OZcVVEAh+WARj0XTGc361cx38lRUHmZZ5oJB+Gk643KSZ18zg8sYp+NlzKoxcshOdO7X5wucK0rr1F3fknecrpdnk/fYMqtqLwuL4XNCr2IITf37GC91j8INaFu/6mY/HstP5wwRJmv8gh7rFCVbtfoGW43UgXfoQvZD9Tn+6i3Hj8glk5iyDigbiZPJdHyLKJWCpmA8kOViT48Rqbg74g2FB3dhhX8jiKrlcYHGcGoOSsVdpNGx3248qMx/y8pQ9GGR+i52e/aVo68loK23Nv0V+Y02XAz5MkoDCmgxYb+SK92oXgq23M5X/d4VbHSvR32McBN78wJY9Q89/0QS86S24S7xG//Nn4JHiMrRTcOXv1+sp4v48LLF1QYtFk9FHFyHmxBwOlHgE7x/ZkM1vZd5nIoExf0pxa9RWHpfZCbJjFvHfdUO9778Yy+qLULW4D13rHoCtViNZbT2BV14MYOeWx2BX95Q1zgpB1Z1p0O28GO593QmbV0tiWIAwd7gcAF2DeF6kogCikdIw+4UURF4JwniTj1AmoY8lx0bxk123YGSrHcHt9VR6vQpdvIPhk4E8jDA0Rd81rVgWOoeS1I7TI3U/Gr6wis+2v8Nfv7NBYVosqUyaCN5S6RA0ajwnS/3BY6ne/L1jO8rplNLDW37Q8smYB0dJ4Q1/CeiReECDfvXw7t8zTjJw5FzPN3D9XACd6KhHU6k+1puWjiWGCrDG2ZC03V+BWGcu4dEtnJ/vTQuG/2Nbrwo8f+g0Lf3PhdduVoTJl6LgTP1TFp/xBfvWFeELOw/USRmEFwtDsWHMOMrqnMTbFxuC4KqV6L5CmCOul3H42xMw4uVn7tCey5vQjVe+0OVz9rfwUOUY6Mq148Rvm6hvxXqa1D6cg7R+8p2iaXR0kSIIP96DWpc+0C4xDUCJldw0EMkBAndIb2MVOohK4Zo9F2ngrS4UOxZTzpzlHLUQ4bHzaF7elUr/lDbg5ecZ7Pkhm1VqdsHfk6nc5Hudqka1QsAmDTh3phVmXET4vlYX5m0ugbqXf6hwpAxRQxgpxO/kBPV2qH6sCgo8DwL/S8C3Zk70VuIjdqVN4bSjV2nLKFmKez2IX+234yJBI3i9aj/GrbrOdWUjYK7UcRIZEQOvvmrwtdXPoLtoJsUvUcdep///H8AC1Fpxl38e+A+9N8rBPJgJL3qTeNG6+zi9VJdblohhyV4rSBoMgKCcCbB/ugFd9XOG5y8u0Lvt3mB64TWqWu+GvesSMNpOHuqTK6h4ZRPpCh3nII/NJOd3nspqQvHyvkE2XWNPHZ0aIBomB39Kl8OSiFFkrnIJR7h2sa1FAQ4eauLOy45IwQYcEFEPj28IQk6cMHFsFo3oOogaX78Rax3mtT376ee4g6DePYrnPiQ46TkFdIJ7OWPTRiwKaMIS2b+gGrSZnMoKAW8nsExxMKwUTIHtRQqwdXk7HFuZiBnW+8D+pTjNXqlEa1qVQEisnGYaxbPu3PO4KkETHqnkQZfFVlbxMeeJNvlYdHw2PO4oxDm/Hfjr2kecfPsxCMwVg41vnenN5wc0rSgcL8+/Cx0PLPFI1xrsi80AJX9Zct/0H+btZYjfeBur578ArURTmPkyhLYP3uVL6unoG5RBRi0zUGjBQoy/rgyLlkTgswMt2LNoKl469IMn17Vil4E/f4nph6zuT/RnbB1i6WhwTathtyhdOD/YST/SmjmvfQYs1KtBg2hrUCgbRLGHBrDA0BCWOBphtmYKJi+J52fJeRxsU8oTVH+CEN1C6xJhNNmRDH2lyiA86ESl8zZBsVUMnG97gm7n15Dq8kjq+CzCSzYuhxOZvxHyNcFr+XJc/f4pPPtthhb2y6hG5xaGLTmGRsfksGCeOQrXmKDUal2Inz2XVh2by8X/loHWOSvIFD+HO0Ls8bS8D0yRHssTHFbwzEVKsCxkEyuKitCSD9XUXrIapm4/zE4LXxN6FMPqEf+B95pplLJJE/7deQK3n39kvQVbodF/Ffe5XUJDtQfgIFPK7XNrIb8pEnwuEMjX6GBf2AW89zkTL6YK0ci+MD6lqgkqT6LoqlkS/pC6hy7DlOGpyXBYKxMM+X8P0J0HujT/pwqMqTaEHaWlUB6ihrFnz3KjqRB0L7SG6MsyfFjwH22bbcKRReOH9voiTBrZRsVZIRRivQGq86xhQ8E2UD7qjfYz+unGQyUc0ZXIky36eHAv4Ordl2j8lX72Pj0ORi3wgipOw6+hC0h791a4VvAZzt+v5lUbL9C1umF4eDZBQ7YoXK2fShh8GUsDe7G+PxOnvbtCZtPmwPDBJ1Qgp4CpxV9oc4sZHDYjPvbtOIRESnHdnvHY6tdHKVPk2cj+CZbTfl4QfgonF1vBQ/NDMPHBZXrQqQ4TeRJPUj7BC6p82HbDG8qeZwHLA/No95mhXJufwwPONoySh7DaczI9tHhH6ekNaOU3FXUSqnjYailcJW8FfwRngeWXCXxzhyZZlt6GybtC+Yv0Pwp9E00Ch3vAReQXuecN9VuVDQSOrcDdRmuo0uk239BNJNs6Q5hRpEGGozrRaN4G4D/isO/TN/jpOBWXkj7jgat8uz6Kpj2NIROpPBycdYhsXsRSpI0m3G7NJYnZ71B87AaY/MEfJ3uFwlHpVhx3Ziz/7IpGRd1r8Oc2QND+95x0W5Va7rZD/s4eSnfwQ3nvOfjsgRWq6YyA+/pOpGU95NRyzRCae4UnO+egU48F2ry9C0d7XUgo9jOsUasn/2HN2ObKUJF+HIpfPoF983VIrOsHjZuRw+f2L6Tvh8RgrXUdyYw9iVNiJsBos1RQaxJAT2Vrjnm8GcSiWtngijVID2ZxgmktegTuYy+XMTB86VHO836GhcZdcA52c7Ayc0alIX9+YgRHsw7g9P2GFOyoD/ugFP9eKWI571OYfikRdbfbc2FqETUP+YLR/ghctp85T0kEbjiPIig0JMEOAJdFkdyzzAP0l3Wz3YY1LCtXTGUrxHHcQwRjw5384MVoEJB0pJ9bpbm8ciw1hUiw9djxbHX6FMb2toDtPQTbRjmEh4UU7qFINlMWkNeqNaT/qAUC654RzLTjT/qTMfyiAkzpfAGpp5XI/Fk0wo5lVCYURSNr41npqAfgnGvca76faNdU+HdeC1Y9OMdjz7Zj0e1UnPjQBt0UBkBt4xjavFOGzbuzwDZJDJ6qvuGyl+NJ7bI0+2s18HDfONzgHIJzr28kadsC+D6xG3VPyMD9M/dhxxdF+vncAeZfvc94Ogl3hF/lkoHLVGs/h14MWpLVhnHg0bGINfK1WHfPdzYaOwA9s4dY68kfmtCvDSE9pqi9RxQTnjDcVXvMSU5v4eKVb3hywlcKGP4akiY54+MthzlviNdvqftzeQNBcL8GaN7wx7Od4aSbEoP7ZOPZJfwpOGo8g+URilCQNJ3DxWXAulwd5vSs5sjAAFoRfQQykqfwhmBrUPvYxzWnvoP7ohgs/GoC6YetyChICh23H0OXn89xYoQU3NSWhHBNIXAtj4fhSRFcZ2EKkTHLMVjrBpxdvh8PTE8AYe92+NvrDXEDi0l+HfDcEV/p0Jpx8CfnMNl5bsEfMgUI9cd5TIwGBcqFYkHQHZgcHUC+OZvB+poxmEw1ZkNBVYx2COLwqs1kHf4RD3h6g71vBs/6dpafR+SCWq8W3Lh5FyK+qUBHUz+Yx9ZQWPQ5Hn/Rle6m1ZCyUQuXb9OiCFF90NseAynyF1HtzWJ62juCr1U5gemRJB6x4gxaHHaHdWrpaFSrDkf/HqJlF1JRPeASHjunRu/0zUFRWoJlYvpA9c9SqJ74FvOvyEFRaC3VYwDcmGWHvZKSPOPHAi59WEJzlk2BM/JlGBOoxuNateAlRLJcixiM/xQDejk+5NG6jIT9ZrNQ9mX+GJYIaTOyKe+oMaD/N3Bbp412YyUg4N12FJ03DGXP+SOIb0S7kwpwoVgDMktNIa4wkmVraylA2h2Ujd9AjaoCnG8oJckTxhgcU8KT4CnOmCILV3eFoFHUXT6wNxmHxetQzAlHDnnVhM9jozjXpZ89fzdgQ4sAGD94B7/theifVzm/etoKbhtKYED7JFT/tqE/F3dwtfl5TE7UBNkHP1h+RiQ8nBMNlT8380vnpZw5dwJGP5mNn323YNObD9yydAoo1g7A8htBrOBXR1I7mC1rl0OR0xNQv25OIdQKJRJ3oaZFC7Y+Suc/cavBfvQSOC0sxCFlC8h8VhucFrqCrle9MGztDTR4oQE9n+fypyhTCmlxwUjRrbD7vTMm9xbQYGsqh6SOZcPZZrhk5NB5HJgJ9+7LwJT1m+GJjAqorBXA0iH3Km3zAlXdKeQntpn2GctASU8ndyWnYOymCWDp1YhBlQOcse8eGQ2mkdz9OJoePQxvLLKGuFfWkFQ1CnYqasHe5RXooKLLk6cv4o+7BXix0Gq0qV3M47cLgUJEISiF+aFjgx19yX/NgrGzYa7CB5AZXYzC7lp08sw1EN459P4TzHDy83eo7jfANmKv0Kh4ChqMy6ZdCh/h+7tUqBvIwbQ4ZXgz9iPa3unG7+/K6YXkCqheLAvxhreZEhN4IMSAJKafpOxHFuDZpANLhXZz6/5s7ok0w5H3vmL+3xDqy5fBivVpGB2ghYtjAcZWm0FJ2weSGO0Ln8U/0qormezz6wAeDL1Ge5J64eJjdZDfpgdjs5ZiocpNuP5qNW5Mq+ADr/TopNJb/iD8Ebq/T4QNdRb07JcVaItr8CW9tyTYv4mjNDR5b8Ut8t6Rhna3ijly6P53qeVC0GhDOMGXYfroTbw7cB2P3/0Ds5dGQeDrRyCk9YhW3G6kL9EueLRGG2pd9sLqneJk16REDkpZtKlhHddKfMeHJv343fsjS9lI0RQjQxjmKEHHJOdRn2kgisiugLZ38nhV8zlurYvm+fvOwd/ttSByTR5SS824pMwT3K4KwzO3PvjV6c6e496gWUYy5eVvwyKX45TZYQ1nqiPxj8UwXjt/HghWyMP6CSOhxMOa781QwUPD69jSSpxCyqaC3b6NqGHJNP6NFbb1TGLPsXt5+4A1wfAI0KnygWCbNjy8C2FATBRMHVxI3kufHfsb4KnXL+5PV8M2+AUxnj5oYXCLD9WKw9SQeLoiUQk96itxmsgK2DBsGYlG/wTPX3aQEKNIIpmyuMJHFPIMLtCr9xWocNCAbFZ+o0ChHO4MCYP5b2TR595cSPKpgEuP5GFUxWY693UOV8JRfPFCjbt2d0FjMdNV9QIY27af0P05edsMA0EvC3p0XhFUV+hxst1RSr4TDyJhs3m9hAI3yPfA1CN9cNPcAkwt3Sk0axLuim9HzQnz4MX+m3DiBJCRy09qHnmev7y/DepD3STatoHiL2wloTIRkjo5meoa17P3lwSad9maPWsyIDT6JHn+GAOjttzlqM+h2N/oxyv272AFlXP4ZrM6PM/0xuXvf6L4sk56ukcBRvSkkc5/b/jaIk3OyNxKkULGsDdkD64ZuxJvCmygRTlvMGe6MAjYDrJgozL1DVPGM2V65O2piCrvzpPC4zPUG9RArxP76EizMnSPGklGAwo403gafJhognUrvkC/wRNKMv5HuzPO09NNUzkqwxgieyL5+KYZ5D4xhbdTEOq8b0arbnHI4Zvo3TEa40aPoJ9d+rD54SN0nHuPrX3TQd3PAqQ3VuLTrav46xAPjN88lY/N80LNLabQkLCeC+8tIJ/Ez5hiY4X2rVoYP3AZ1167STfj56PPD2s0+TQZZmUn04SDvuDkcB71S3x5dLED+MdsIc+YUfDr0iW6ufYbR0iqwa3bO9jujTLYTFwDi7MCUM3aDxeF6qOXYCNu+PqCLm4Thdr7EiBbKUp7P4bB/icNOH57Crs5CODF8kHaO+TO23Q0aG9jONp7mIJoiyQ7lFbyV00NenC1kC0KXqDc6C+YOPMddfiOoJpl7fQl1QIci0eDc38NXv9wFi8vnsKH72bB8vCj/Lq6ifTvW/JW/TiIuSMFBd0p9L2jAK4/2AzbJglxzomnsGXBc6oYKzB0jndzY89B/L1YEias209LKjRIN18OO7/6ctByAbQ9WArC6Vf4fGkrnJwWTxb5DMa9qynuOOGK0+/huMwb2JElw1kz7cjYIYJuvHwLnnfcoT1rInhN0gDVSCa0bcd0gdk4+nMC52xToabbruT8tJp1Zu7BszemgldnMAuMsYPirWGw61kb3Yn9QmlRS9m1yJMz1ePYI9kJpk6eDMX3omC4yTsUqh5NL98Nx4nG8dB9eCf2rN/PD1OXYtQRQzDMUYM7x0rp84hZsGxjPD2Y4kF7s8NQdMtqfLvsOLguns75j/bS+Hx9gJgkav7ZgGX0EhVDpvCyOe9wX3M/yRYYc/Pzp3wjcg9fKJCFye/GoE3KTFT58w0xeTFvna8J3TsOc6+iGFhs6QPLI/koFCgKv252Y6SKMXrCCJgWOAK3DUTip3d/KCtLjN+fTUPQdAVFO2OwCj8JfmnfccranVA1/j4mCgaS4hZtaAtz4S7lTjzomk6j/E2hYI4EN9vUcIl2Kq70liGxkUL4vV4CbzjOAJ/C6xhpn4oLwy1B9l8zLD/8jwq+jydR7Z3gUNiIbiGT8e/zpyShNQna+mdhmqAelAeegXPHDvFczQ4QEUWO+TQcW3/PApX9sXjSwBkfyVyAqO7RIH28Bk50bocncQ4QuaGX8rwX09X3O2ni6r0kP3EQ30lLwJZP1hC+7QyKXguh30qR/PH/iDvPvxr8/w+/RnunqURokHYaWmbyKVKIZKVhlQoZRbTsbIlChTIrRVZoKC1EGVG00KIiKg1+ff+K3/33nXPO+/G8ruuc8zinLgDG9arQmAWLMFraBHu9r7OvaSeNMrKCrq/LKH20Ii+//xMdnPeRalElPx/iiIRxL737JISZNyN52sYh1hf94n8hSvxxug5ImFewyDhZnj9xAyU7R/O/wyUc6XsApl4fDuELXdEvLo3vz7/HrvOXYXGbAbmmrcMzXdNZ++AgVa/7BEG6E2Cj5FhatZbg9uM+ErrTR96Oe+H9t04o+zAB9ovnYL96IiedGgkK65fynyVOtFJkDU8O2cQzArdyvPcSdr0+gn8f3UnCjm303VcI/NI24I0Jyiz+OQF/JXuDT8ZX/Kt1l+o1yjgu6RI1x16hrZJ6cEFiGXpLfoc9HWtZQXAeLPdL4imtLnTKNhAVHu3hEqUNILBbBir8VsFi22a4JX4Uiv/OoqsKs+DoY10epieD3f+NoKuXpsPfk5PBeksnHtkcxhtdzsCP8rto1yIJl7TqSUouGLbus8fXufXQ0ioCYg9u8a/rQnDk+XqI+9aLdfGWlGSXgf6Pf1LD6CZQcxiFDiVCUHb4KlnVW7LR9gSYtKefVqqdYrIYRscH1qP4hAmY3inH/S9HgneCOq5Ui0SfdA+afuEKvAj+QHOol+u9zuPwliiKW7KfV43RgWXfy3D1Ri3acNCHzCJTqFEqArzefIf1wY0YfkKSIyefp9nlVrDX/xMl4S0I6wjlQ07yPMykkrKWdsKB8p84x/0Vd3hspkWu6uCkkcOJocfozkIHCLPVpVWeCdS+2QuPZLXAq2M/8MJ4Ha55YQCOYvNQTSIQXqeeIHuDkeyqFY3l+8xIYN8ieDh7J0Uqb6X/ygkajd34P9MM0hv9EfccmEr6J6bR5ippuhB5HJY8MMKNN+LJ97sZzHz0HzV8kqAXQX0o1hCJ3+9NI7gzE8/WtIL0v3IMnFWDId464H1/EXktHYtz++Pp/s6DNHCqh5d+G8XCwx/gysu2UO3qCK21AhBtkMuGkSvBTX82hGTfI2Pzn/Tq10lyVctBE7tuKPmyg2seIIjfyKOOhcqQX9vAO4fcdFrWbzrj2cMTT4zlO+PTcMr+NlbE0XB6w1tS9o7AARFXMstIoVLNbl62LheeqAbAwlpJfrEzFsxZBy462OLZZQmQl/kMlr7eToYjDkA/reWGmgA6S5+oaekIWN0sDt3jq3ioUznC4QE29xXiLsHx3JtRS+2GFzmiuxvcphyDZ7NHwDtFM+i+PYlqPUNoe441mO/9DoHnhrbaxwZf3+qlb7eKMd/aBv73W/WGt8uhYuR43BVeg+P8v/JSv48sXZeM6Vs1qWZQmm/rKcOYvQ9hTtNfGP3rFl03Hw6qdA6nsgbho6cYNfw+TN0wnb8rSULhhhpW8ZekIs/3/PRAGx2ZM5O3Slnh1/69mBHmjjFJ4rjDygz+Vj3jfs8r0KO5Fs/9+YuevbbcmnAUF0koc3FoPB+UrqKLvy3gaJwbpZ4bB/U3VGm5Sx60HPrHdRMU+EfsGt483BES9ylg6X6CGtFEKtIpw6pV62j5un7YMpDKqacEeXxQI/Tdn8VVVrFwOc4IXBbKUUmPFoRFJPCvyEas/SlAA9mpHGovDMY3lpD0Li8YNBCAa0EBfOLsULN12ZGt7k/cd9+STma8JLXdKWA4sZ2PvtWGAwmS8MnBBiujItBFndjf/QRHztPEoCWb8Vl2Eu252UK7m2ogPUMDxheswQjnE/AoWQ0vHdAAv7n36UrGbZwxPx3Xt30j26Rx6G0rAqqWL9hmfC76Di5itVWfae0pC1499xDNFz3GE9dq8rWE5RCQJwoLsgwwdpksfxNr46Sfa/iIdxwOU1nMW1atwtX13dyd+Q4HCvUh2eA6TUl6AxGpjrBhjgv3XpqAqf5WVLY6AluvN4L5+/V82VoKZoTPpXOHy+BBgxDG9PwmY7XT8FajlJ6GTabO+VK072QBVzZYgoi3Gq5wyQG7RYYQ9CAKDbZJwmjFLJworwV5pxoxUMSbzysTzDm1c6jddelElxUs2yhMZb2JcM24mD5daKUR+QtYdHgp3TfUhIevnuHLCXIUTMspU3suyf+xIC8/Jr0Ka54lLEHDS0aQjpgibJ4UiDkHppDKl1O8/qocuYcLwcOjyTB2kQEmnr3FC/8sw/gPmjBv63SYdfEuRTQNwMwPmZReKok7RIux55AZFIYMkILH0C4eM4PU3CvgSkJUZXYXJQ87UY+oA/9xnDnEyBjI2v6IG8V7qWSImR8nB1J3/llc6LIPZ18oR51ce7ipXAqvu4voytNZ8Hz9e7yzYBiEjvTl1d6HSOXdVz46xQobVO3QVnM3yKINaH3/gjLCYvzSThP2jM9km9yf9Og/Jdr52g+7yj/h5Fva9DhwDbuOCqYojTmQkCwKq7qXQdf4JLippc1lMnfxsNsd/lKty8dfqcHaXyc5d087uN1RgWP5pVztMp0ezTXEhsEN1KdYSe3fj/LrNVIgPWseicjf4KKdFjDq3CdI1rSBd12+JDnvGUa5JWCJ/1DvFU6hYoVXfFk9DPXSbUBl5nNUDQmnkMOvMHTSLfq0zgb2JHVQ7+ZrbHD1DG/6PZFUv6uASPE3jv0nQ57vVPm711wKNHZicaPPaKGSRU5/vSD8K9LgIgk4GhWG75oD2W+gEpZbHYdz9U5Q+fwCzVqviWeC0mDvlokoqSQKX8efwNqyERhDChC8M40mvwmi+G81UGR8jp7Vf8DNxonwb8JYiCgpY/h0HmHqJxxbbMipLa/p6oUYaPj2BTsWWdNEreOwcpsy/LWfzHru9tht3w6b0RDze+p5yp2vdDDmJGqGfYPfxtocJqsHC2xVIEDiHdH5FxQ8+RcJPrfk6VHnefu+j2yUmM3emYtZfqog7OnJZ0mFtTBP9zCPHSMA+t/30qtVM3HduwaOWamEzZcUQE5gMhg1f8WURd04smobdHX24npVGaz3zmThuD+o/L6IosYtomE3GXplO+BpuT/u9/BnC3d9Ers/gjd0S0HXe0+s819BlyuE2ZYMYIeFNscu0aVDOXPZX0gFy5ytaex8S+qqOoK/o5EPjsqEX1NHw/ljzbBfwASaVnzATKtalhtlTYvhEKimy+P8Req0oMMXNfvkIcNqEyXP9OBCCxeYWhuPL/+FwmB9OKevaUC1yDzqCb7KcTwB6mJ/kU7JABidWEl6kmGcmd1NW4/9ANXZ7hg7vgwu/zcdbpmZwaqYSzwlTwxstkbhuT0/wVTYiVat/4I+W6biR/0YjG6/jJ7jBGAXufHyn+3wgJXIBHTwRtFcVN2hSRVjQ8nkaQG1xwJO+4CgWbMd9g0Io4SAEi0a8oi5fV3g8EGLJ/WdobepDjRS/RSOjpkEw3Se0Kc9f/iRfTr7yySimeAHGD38GAuLzsZn1utw6nshWLpBERQcjLhlXhC2cwmVWoXAoUUjSV8+hEe/MIFRR95D4s0S8vGyBsuuYKjUkYf22g105K49hrr+otNKJpj2sgsfGKrzyfCndP3tcPjsW4yxBeL0NlAOVIa8OTyccFFNOZxumIZ9fmW0boUh3HwhAaunPeTu7MlocXziEM9aQel8FBhtf8/xxYPkemECCU7Pg/hT8mDWacLDc9UhWLmJZ4t9hsW7q9Fthw6OqLWhFMcq3Dy0wTeNR0L17jLO//sZLqSaYZzlLHCID6XMXCNUacthDeGvnPHuFGqPE4ZZdn85WDYf9vtmY+nNBDSOuAXnBO7CmqANuOPwGPqxyQO5czy4rblGS1fX4KB4MQorlhIYV0F/aRRdu7WDZzxgNhg6f+eSJBRMLMH0xL8UNODNuwS9aNsYcTR2VcX1GVGweH8bNSWupdfZIuBiZcl/7m6DwfgmktFtxXTRkbzKw4U/vVzCG8ud8GnRR3i7Rh6UfR6yVXYKVy0fDqZpl6Hm2C72XvKHOgyWQ+7TRor4Go0BF01h22AaHk7NY9XQkSC3chcvSd5ECwMsSafoD/2madRWVQP1osPh5+6nkOB1BDM9UmmwUA4rVUVJ54krZNe+x4EboylW+AHdCNeHg6OW0O8IV+zc9Bh/XdDmKTcOkbTQE/ZtKMTciOlU+XoaR8VJQ5Hsfvz0Ppcdribh0cIvpDQtka+V7KQRkqfB2mks5b/XoUBhaZCbcp/F58yGV84h8NQsgZKCkqFdeS61a4Vwd3Q9nTAfwSG7BWG17TI+sDGHkj54YbRIAlwVOgXv/fKx+vxdHKF3g06OXENFmgAeuVo4VUiU7s1rIoWOPfjvlBOV3+njv3dLWGnmMjg5ohhNpARgWncnn91YSleDXajn8iG8cGA6lcRY4rP44Vj45xlcf/2/79cy8NFxlFYUD5Or5xPP/MDHJR3oZl4J3L53iG4YN/KyaYpUMFkIdj2ohT7TBFqsE0F/3dXpffdH+JfYT+sXmJKEbD4+nNsMwju0QUdjODw8mEbP5m+GNN9yqImKpfw/G3D/rOdwZ6IN4NZL/F+VNLh8u8wmwV0w4/QyPO8ciInP//KAVzRIa7vS22lfhljtjGePicCO8DyIrpqM2OhK+dn6uKJ9C+z2forTc/rATEGGP9w5QGEztGBoBNnS0BRXJZXDxyoZVOvwQl/ZpdR1/CTrr3Dk55FP+Mv3MZC0t4dl5BfSbNUVNNn/OTTNN4CQ7iaqDv4PGs3aYE5eA13fYgHV19TQwdSeLXQd0Uo+Hlw0XaD7zDe4XFhM//2+go15GRAzKAANfsNo4qFbIH2gHAaTV/Mb5Ut4axjwLKcc3PMslCzPeuOrw5LQ5ULoUX2EDddZ8M/Lx8nr82HQu/QVU2+10fumPLq1uRRN7VVAh+5RqVM65ZuFQV/PHpA87gZipg+5RCOR+k/kokt2E7V7SMOMkj4K1/PmdYOprCwoiDNv2tHgJTN4+MaJHmT8xaBpIux+ZhzYLj1Jatd66O14f1goK4vPV17DLr0nUCAhR1tKPPlKSTjo5k0G4Vvm+PisDzlGHcDXc1VwzKR42lKxBfJlhfBWWi+8TTNhk6cjYEJCLKZ+uwzaBersl0q4wDIXdq6J5dmu1/ln+XxY4dpLCuVjofS1Pxv9uEeFocPZfc5osFrawpsPPqCiuzU8vc+J5spKYNg3AdhX6skOo5k77Q7g88maGLtwgH1F7/PT+YfI1sKaX8rEw40BXVhwqB6C1AP5XKYGzY0YSQm7FpLzq3I2cphPhytEwG7pNTo9xQgOFQyngcULKNLwLFo8sWPVVAvIqu1gP+0C7ouxp6NDLph+WBB6v2bxgmESqNT7kD4NvuLH9uPoX0AfWe95y6O1FoHnQkealAowLf8PTqJmcogNoJly4my88QDH/v3Ah5YOwHzVMt69Qhr+ihpDWXYVl66eyxFfzmH76U044T9fOnRRinV8U/CC2nH4cy0JlllrgnrDanqf8wA9VbyhYskgmF7LQ/PyEv66+Qh5ZlWSs5kLWHdIwOHl3/gxB9BpiKQfiZHwU8YPlA0NocPhG6dkScKsM9dxpcRkaJvwg9xvrMLyOQfAJ/8qPWIx2Oagh9vMy+i/8zeYWnRI+MYEsJhM3P9gJNlyMPhUzYBLktuwbNcw8JAa2uG8Uliz/CBtVJCEfaqaKDfLnJZkGZJryEH47lnKJ3Z7Y9hPHU7PvUxK/wBWvCHo3mBCuy7X8p2Rk6mt+w5cVTSm4hAZ1pLz4Guaxmyx4TdkpumAEGSTZ1MJmz+yxsd7v4HgCke6WK5N0yuJVu0IwCeS7qTWoAHLp/7mTX6HseSbGd29/QJ2umag28KbGDJsEcwfulO6f6R57xst0Eqw5X0yV6nRLR9V2jNo91l7uLpLCORmmPHvsklYr7gQ7z8UgS7zKVCr+B5jvRopduNh8PQroDKZhbBYYynvsf6F/+0cA/tctODo8lngNmDPG54NUFpwC84P7uG5Zsk07aotnW0ppZhkezadrAzX/SJA6q4hRiTX0nfn6+h1LZFOfzhOH4WTwNxZjvofjcWmFfow8pszptlfpWn5wiDVWoD9t8Vh7fREuNNyi1t/nKUflWLYnoBwvP8iZhdOJ5PLp+GnSjM+H+znKg5E7UvjIHt3Ps5xM2IN+0nwXTAIT55J4pIEZV69uggW5HmwlLk52exSw29BOWBrp4OvTw7xV34x727fB1Xrt8GyiYEwYYoDv3yRhTbJ8/liz0H4dCcdbvZKQIy8Le1PW8m9Vz7SE4FGClrZhvNEZMhKbjG75EdxmH0vavpbwS39N7gkzJynnDxDkqK/uCG1C2lODjskPeIH8XPp5KgRxGpiUOerzQsu/0XBzB4eqzqCpXcZcJZqFWTk1VCnXTPEiDvhD/XhkNf9FP9Ip7Go2Gau7lmLemoxNKt6JVffN+ePHxTJRT6WAv4ZwOmwOdRplMEZbwCNFvZxhmw5fV0thAk6xTDv5VlWOZ7HJySsoK5qEi4N7cFEF3dsvPOB7aY+xlj/Z7jY9zZ7Ct5DHw897DtnDAeO6mFMxwtSdKjkcW7zOPVnDIgsHEPybb6YtV0EBT6f5ogGWWgd6nYl+zM03sMLd8eXY8P9S9ydUEQKm7LwRXASNkV9oWBnNZieuZ9vXTLHiiRGh+eaKD/mB1nOWg3ri01xy35tkKw+DuMWjQD15B147bQd730WhHEtVeRmEcnhsX7o7F7ATvu+8ErFRtoQqAbZ9ZvxmshTto5UoUleXzDl0R826tbmqvMJFPOlBTd5SFHlKEuwaRlG+kUu+KN9L2BgFrgvXY8C8h4YXa+N9ckJrBeWBgHZE8Fj4l5ccfcQlH7az3fPnMG/DVWYWR+JlxT+wYeUGkz6rIhfdo+FBYNjeFfTWVa0Q0o76MEa6+xIuPQkmowMQpNn0uA9NwJrE0dAm548jK2uhzvJnXwisQpm0XYIWF7J20rvwL0/3ix0UZzGy4qDZcJ76Ng4gddq+NC7wB4yktemgluXWbo7Fk9vk+cTQg5wuE8DNkzazuHzR9P25V78/lU07PpcRG6KNnxsbzF3C6RgfXA6+t6ShbrqRvgUoABLXxiQSIQ0LOccHr5Sml/4F1L/+n7c47WUFu8YDbuc22Hf+0q47T2arrybyLpSq+DORXEeG7yJ3B1rUTFcjufgcLhx8SEkZHui2skA3P91BmYvvkT9WauwIPYe1Rvn0sK2ZN6yVAxOOCzmuZ8vQuWKQDDLGQb2to8IZQfp7uhB1vwTyKGu+vzJfQJM8guCIoVImvBNjsZ/O8Fea/N45I514HNNhmfVNuDbfgkOshgGtauf0KSL/zH9fgRjXFvo7XMpeGZrAJd2JdIn+1AYlToIdaGisGiuHYhI2sOVRjca7SHCrVPn0b23r3H741QQTv4CHxeIcFS3GYydVkIOUTvAb7YS3B21nCYLnocXMvbUedaODJpu8YTY+Sy8WhQ2xXei4tr9WJ7/lX4H2qLPqbO4ZMFEyErvpt3V0/jCjkf8BEeA48bHNGxlC8loGPOw3cfAX0QJjvtkoUSyIT4Wu0Bt2u9ZcMZEcLd0pma/enpYf4d8YsL4bMMgHty0ioOPHKSphxzYUlAP7z5Vgi8zmE/M2Eh1i6fQuapFVGc6G6o0Z8PHuHUgaPEUdmhXUtl0c8gW7sEv8nqQNnkOhvd9J83iYLpo1Eyz6wthR24TZ28xIys9BiOFXfhVey/miblj6nJ7mKxrgHPEe8hvZAHcyPkEIluLWCNMGxR3FMOLsiiaXWGPKcYaaPp8HFYqbIHKpYrY5f6HVlQ/5SfFRrDq1UTcZH0f6yrlyHKRMFqLbcWkJy9RdsUoEJ3QQ+fE3On5QyOY1ttK5VcqobK7id+ufU4B2wFGKkbwuIP3UQsLaWPxXi5YYwLGatXg7B1Bc94n8hr9MpZNCoI4EMB9U2K4q2wjy47NoruqYpBe0A2p3gKYPNKT56w1AvX9ebC35wB6/Sgh5yvbKMY7E9JClCDu0jz4c9CbV+sb0xxpHz74YzHO/jSbV+s+Zqg9CA41s1DqniW0dD2CNfMVqXrJRMp7sBcmWh2nCUU/oHBNFPm7CqP3y6fQ9kUO4jsW0Osl9aht24sJ0Aua0bEgrnqc4zLNcdW5MJZuuo+/i6X+3/7/97+jxiDgJsQnjlzE/IPm0NbvR9o5djRukjpq17uB8YcitA9Xhj3aO0DsUT4vcCiEA50MN2Q/kODXEjjQrwYPw4KhaUYR/FYYCR8/PAU2XQAhN0PA9f1hDJz/kYT6GsjOsIl3GprgMdf3YFQsD0L1j+hSojWuDD0DHjFzMSM+BJrbBPmdSgEJqv1GwdXRtFxfH2aJi6D6M3mS0QrAgNKlsOK5AxqEmUFknSrezDzFEmpz6WKQFrg/HcTq++tIaMR4HKG9hmuX1ZHL7YV0JmsafZyUBMLXhUhSRwMaVM7QjkID2h6phSu3LKSW3WZwyyMAImZ5k57CMjb+8QL2hhI0N+eT8vQ1dPlOLrZ3AE163cqda93Jz2oFZZjf4diWxTTbwxocNMrwqocDROpsJlMtH7gg4s3P2gyhuEWb296sY+nZJ7FKYhLcb3wImzvvQF9QFAeJuuDMMY9I5WMLlOhI055zktC6sprr2xGWdrWh1okjOFZNFCzvqcOTvFfkcC8WJpp08OuuVJoYIstXN5iC695LeFilCdaqH4cHAfG8ty+S6j5OZsosww3Xr4HyswjsKDUA+TG30XvHQb6wch06NVugd6g45Cblkfi8NhTe9woeDdSDktpoeG25FnRPJ/E90wmkeuU2+3afh52NpnjhaidsvDWF43Nm8/sEM7hc/wUOz7GFn97XaZmmF7XtqcKg/3aDRIA2fZp5HcvsLrHWIQah7QKQIa1CjlJNOJgqj5oj7vEeNXP6b1XF0Bb8g/1dg5huT5Cm+APka3bj5TsukHlgM380/IoLxZ9A5bdwePK6iCo7vsL1O4IwTcEHWmLzacpnbRpfdoRGX7nKVIq42b8G7w2cx7D8JXhTxxp2nLGDqCmn8WJAFp0TSgCllRFsN+4O+EzX4p/LvgA6RNHU6NHwJlcOf5mLs9X3BEraGMNHYubBtv8Ax4VKMJAYVReuhVcK0rCTX9DjkfPw57C4oR005MJ5p9Cy8yZg6mwYHfIKlx2o5bU1Q74xaRc2lI1CqwRxnr1CluQt9HHpywwaUZKF928coHM/NbiqzhxO/+zFYy75LP5FAdpCvNBf7glsmhNJjiVGWGK/Dbde3kEeVqPhZPQ6EJnsx4E11fjfps/k2lkCNYVjuEW5ih+ohVOJSir69wrB6+kecFLuKjkHqUF6VBm7uVtCWsEqqtGU5LtxzWRe/561y+VhR3UvtAan8CQfN0o6/wH2NmqiolgM7T5mhymeR+HQkTJQOqEAL3K2o73Hd3zlPIVSLuqC0YurVDXWkN5OjgDP/wbp7/YxNHb20N7vEwed+kK0b95Gm27l4dSn8jB3SS5ssVeC0PxjMM9gCx1dYgJbnfz5cMR3NtvnjPeCRWlF3BADNcfz8t/TsG9KDJ7TK4e0gXFgMk6GZbarceofU7C5UU6PP45j5l1kGa9M1r1ecFhZiG5IyYPqSXfwmJzANrMFMfb2NC5LvMo7jjVSp8EeKj63BK0SnXjYPl3Y+lyQ0ycW0ePNxXRBbBR+tZsAlworYM46NfxcGwjPRl+ncbtHg0iQP2eb/qaHj1ZxbMx1WjvtBQ3fcpRE6w7gsMtvuOPOKRZ2sIHTO9s5zbaJnPVUKWvzYYpWfUXdx7SGXsMUELggxwJj52BgkyEk0y8IvG2HsQI68Pv3FzyUOdQ1N/7y3YP/MLxfG3dOWQTQMBJ0m71xdV4XvFypQBu3TIcnxvH8MqAFCmpcoVxkLC0x1cVlc8Rh1a9Cqkit5ro1n/iA6DPw3pCJoR7tkH4+ApNnLSXNk3k8+Z0NjCq/jNe2pEN4xU1o/SHFf7/+xtS7AxTmuY3sNJEd3Dfx24/yUHx1OxpoG1FX+mR0eR3BqssT8PmHXVzyKYEaFCyhPy0QNV9OgIuvZmGf9Uz40PGQ3q5w4KyOa2ytKAGNQY7Qln4R49QqaMwTYfCP76TQXHOaHXGCL1R+ZYe4m9h+vQaU8uNAc0cGT9wmA/0F0vCCtaD1bxIuO7qI3aL20Sqjx1w1z4bix74lRYFrZPBzES40tAKva7o8KnoGO51aicfWOvLgjzLQ6PuHPQF+vE5kFnRWZPFm95EgYuRPW8RnUrZnGJ/ryOT0X8X8JP8xLA0Mw5pAG7bdlEKl8yVARNoWNXyLQMxiLrV76+GuD8q4c/5uWBUxife/i+PGxa2g0W8NIxIv0ksLPZgys5y/xjzkvyv2wO/edaCVr8WzZEthVMBONkgeA/mib3l6phbMj3NmgxpH3P/vH3ikL6HqFwLgXb8NGl9dAV8jKagp3w7rDat57AxFlL79gNQy9Gn5My8ulrhPw8TuYEi4JKY2DocFH4dh29AuzrcuxPDkLqr7IIBHvDRJTes5Ptm4AWXat+KEVzpwqr8aD9q9QLN2V9I7MoO2dm2Hl4lv2JkH4MG4KOqM2IwF+iKgeyKUzPK7uHBtFnSd/MBZXemYltLCY3k1zPuWzlKLe8DpGYL1xI8s9sUGxoZ94madK6C18iSGrXMB2S++rLPtJ9s5q2D1aVugOQvw9s9HYHmlHEyCD1PZCxPy8l3D0fO6YFhBIBps9SCtMANYlJOK5vcHeXKBBC6VSsTWwHMcdXUWLO1/Dydnl2PZyThedt0SlvRZUWXoeLT4/BiSninAv+Ni9GOYL/vgF/5jehc2/fpNP7MUIGqjAtvseAQTv+dxldMBAPnpZP1Floz+1kDA1he460Q3HrOdCPd6quBC+inc1PUG3KYKksgcabSc2As2097TYGY4jz1viWFvVUHevgSWhDej8hBfuhK7wSSoD+dqW/O5THsMOHgN8l6c5I/1MpCbkseCJgJUVnIJAyS7cUFYA8+JlsQ3zZ0081kCzfrcxzlXx8HhvChKGlyA3ZVnYMF2UeqVSMajEsQ/LlThkZBplNRVyOmek+DzvSYK/DQHNEb2oXzgW3wc3gQW56ppVeVk2uPdSqJLv9CsqUKwQqOSG1P/8a2pl3lNnwIYHQun+Oog1GqJAJFIH/Ka+JqiBczB8uV73BsZhK92tbKDniat2CQDDgXhtLXSFh7HxKNFiSCThCBc2iFHMUviuWLlHooty4OfnTlkZ2aGLnG6vO/3Z8haH4FyUwXgjp4b5Tr9Q8vhN8GsPZllivXpZ/Y8+BtH8NUlF8v150Le9bGw/qYmhY6v45ZL/hB/Zg3FndvCjf6TyUqojStsnkHakEt/XqcD9ZsTOan1I1m5lMKqZdfRoHA1CUkb498jXvRVX4+sh41g02PisHpEBTVs1YEzR/7wqu8zeauRHSqHNnNLqSXYnaiDmdlusH+mKSSVr8OYs74w1bMSTGc54dh9JyjvSBk6XGmCj/cnocbozWRfLQM6rV5wv7kORRSW0MSydyRRZUB7XQzg3EgHKnG+QyEKQnDjtBQsEzOG7W790BCXDykHYthkTBOZzBkAzzeqKNI0m7fUSlHy0PMnlFyIZof+svbDxaya8R5+XN2BgvM/Qnj4RFqeLE8L9lnCqbea4Od4mMdPFsT0uc2UqF9AkYZH0fiiPUyZVQ65FXthelYOPPewhQMVa2nPia8UWqbL//s8cv/RQyQi5Uy3vlyC82bFsExOjG6WWcK3ojWg0L8V1v51wPFXs1l+dyf/ax8LIrWiaF34A0HpCyRYGULLwX8UFfkJ9iXYwWXRW+x09w1/i3qB+kIW9HMgFRZJ64N64ijYqbQK/yuyA5+yZvhP0QlcsqpAWn46Hn/azo++HqZVb9aSqt8YeLsqnT1nZPCcXcb0db4zwH49jPorjGIyvTxwzxtnrH/B+g6GcMf1L46wXwOd6wfJ8mwWJY1H8BFYzHt9t8H9VR/hrqc7ZXkYwR+tHLJ6cxM+jszCk3/WcqWZJp3bcQe/rVfgvy/mYnpSO33hCRBWuIJFHc1x9Odumuixk6vnvoTPX1/B2C4JlqgaTj8yv+F/O6RAXlcf5LtcqKZNig91l1F6pgq0nTLG7voSGLHpO45+2kv9abogY2AA29+vom9D9/rOqzWUte0E945RxuONe7FS6jtMrlsC69xU4ceBpXTIdRy3Ofhyq68KzfKRobNjeqBB14fXZKey/35fmjLEc69d18C/PBf/zv4HzTNEsS9wGly8e4QjzyliqskV3qZhAjAcYJ3zYui/k8bPhJfiyTfVMHFpHmd8zqXJ/Uex7d8LtAzXA5siWXjotABybsfRvN9z6GeFKvdlvSLLj6E89el/eD0rnGzn34C3i/XARTyAd9xrxIQbk+hCVwVsK+3hIPmjNMbiJdrtvAJdvyWg01wXdv3M4GlHXLH32ExQrXyDHXbXsS0ZoG3fW+j4oElVr1eCjacwlA9sgcf3L7N1zEoYNW48zRrKNDWfpSRpOgdLq1yxoLUPjAxlYY9zKR+7VYZXbrTS2w3LaOZlEVhqEA0zfSLxTakS2qdng46eKOxdO4u2FbdT2e3tVOdWyiGDZ+m4uwwmH5zAp3x1cGD9d3Q0M4dp/87TxsVGJJYzGxQ+VNGfFmdQbWuFI+bjWST2BbsrfaHyz3ogplVFQtfPYrpgEk+7fhT6BFWwTtCCM0/WQueONWA40Y4PrBGCqIFTtHJxDVwYngIhseV4MjIAtKMaUb42BsOqzfDD1h1YPmgLb0YP+XTOFFyimcZtu06SWYw4e80wQdG7j+nXwanY8FeV+zNEIOvzecoI9KaHbQbknSvFM8xn00XDx5D7SI4Xm4TC2PC9aLtQG3b+mQNmIhm42nc7nrpyhxV7JDi+8h9S5Qp40NFB6Sb3WTJSElKEv8GpOfUw7/R+cJIVI6VNW7ktoZF9zO04PEYZh2km0ovycZCX8I4rquTZ4IwhdXuE8dijN7luVwqcKz4BU2+e5RXyhsgqghBroYBxx6Pg26wBPhJ0jW/fPYi7Ha3obvkCHFPWw27tTXw8VR0maN5Fl6MfIfp3C8sWxNEEhau07vFpWPwZseK1GOclxEO71Hg40bqO9C+6wZ4wFTh6wwxKbebCt7DxpPZCA7t2n6fm8BT6XDweOjJVMCpMBK32JmNQkT5Pf2BE/ocdwPVNOVw6UklnLQ/wawFrCG7O4euKK/HpkzuI6s2stnUeXzIqJdN3fey4cxU84QqI+GsIJKOHtR/OgfLOfg7lfOiZqYQGTi1YIVOPu+4TqgVvw9+XBOHGChM89iCGHF1/sMBqZZqUuB2OG09G/QebIFA8mWdL6NHMAn1wXliE0eMlYenGD+inkgij922k+Mr36J5/Gy9ZCXKz5Rz8N0cH6mrnodSRKJ4WOJuK39/iZuFGPlSxGqJnlDHPPs7fi5qoq1Qdzj5xhuHzv5PRguMgmFmI8YVFFFl4C/e5ueOgYS0GDM6i1IxxUKY8GRecCsfDY5bj3k83aW3qRwjqscCAnXNxlH8u6X+SxYqhTskZ8ZLfPFlLPzaNIe+gUuz8rIMKxttQ40oO7xj1AKxjfpJ6ywR4WHCWTaKGGlx9D6iIbiFdzwI4KBmBkjlvOHr/ICoKteJwMTP40zoH3nxLoulPVuKZsQGgf82Mzh0rQPsn6qARtQY25jrQ/UcSoDamErOEctiv7gebGnWTmVQlaRpmwJstWRDOY2j3oeG8674s2N+MpdSP31GlSgbO5M2ipxE5vO+MBgYt2oQps9sh5e0UfOssATXRY3jNkfm84/UHiiQRUq75TesyfED7VTPNS0oi7egHeKpfG6K83uO/Fh+Y/2ceLW7r4Q2P9PHEMCVcf6oYHJ0tWPsxUqieDLQLyHHc8RT2WleIV8JWcYaRBJ2Vq+LrznHwWmY+aTwJpRmfR4PJmyjseZRPn3b1wuiOK6SdnUVq37eTma0N311rihmH/LmhYRj4OAbwCPsDuGlfFkpbz8bJKqZwX74Lbds30qT+dFreE4epN6Vh2kldPrvZl95KKEPitIU4/dgH7uy4zfMsU3DKfh1Ya7oJRvtJwINLHZTruxAn/o5lf5eNEB8SDdLWPVgK9hQkZIYCjksY3bTgzoQV5DRtNM0dCOGpPtOhoF6Tx1mvhcwOd5h78Q0lKpdyWYwQHHDYRBL3b3PN+QoYvzcdhP+Iwtvo5+gaagnet1w5v2ITf0pn2BQRzEFnvoG4E3GQhwZuDvuC/1444OoKDUrSvQDtZ8zhyNsRcN2mkhLGboCrMdE0ML+HJPYF4fbLuziwgvjAzcPwacoeKPw7Dj4q2qBV8AyK+ScI4nF2nFbkDk3vo/mZtQtlXx6FW+Ulqee/MfB+Shn7m9/BiekrQbJOlVuVosD/3g12H+VBOLKBLdyK2LfABP59LgfHszfwgmUo1E74w72m03BUylNyCK3Dw8Ym6FcaA+O3a8HoR4b0R90Lxkr+4dULyuG/Y6q0vqMGTC9lYW+uMr/zPQLZl2zhVM4AFI5RxQ+308l8kyBNTe7BtnJjDm1ZgtNMF/G7v/W40EMEFt+6gPL173BF6wi63i9MJ9qn8rlrwui22Z/jDv6DE6mfWfmrFIxMksPbfr9w3nbAV3G2/Hn2WTT7toJKPr0k5YtlQ+f/4XxVQ5Af/x2DhWfyjiVGOM7cl+597qF5pwRZueQ5aWrkwFxDX3wJyvCksxgVkhVx36udvF50FHxJ+AvXUtsw1KGXy7eHwsitWpAebgwzBGO4cHoGLteIJ4XePfCdRsH4vmpQeYLoOXYRKIv/4qIsIxjef4g23r6AY2IrcE0EwuHTDdD9PgBumH5A6aN/obWygGNVzYGPnsJTwauhsnEuDlcowci0TNwTP4aecjnY7ZnLM7NGYEKsBgTJtEOtRi0rtzXg7+w5MNMgkqJPdMDs3e30+FY0TRu4Bsq+QmC/PJwNIhGPDnl7mFYc7K2PI8/Smdy2/ClvH/mYLlgtonQnLfgSUMOr06s5fK8jhXj38/L/dkD8G3WQbo2AexUG5O84k39VC4MK/8DeDWZ4NGQtrDZ/w0bK2SCrns2+swfw4bPpOOXMHrjQOQokdzlz+SFHnjO5iyqUjnGdnSVfvtbF478HgPW7i+DS6owV022G+POa3OT98L9QVzKe6YoWYTt4sacSxel646mpv/GPtjyvFR4GhccHqMlNHhKMJvGRPT9hA9jxoM9bFKlaxnui/ODOFHVY7KYB9w7e5tDcPnhW5cF/hD+R9skBLJKSo3B9P5r68DZNPdcEK5ZNAMUz/fwvfQGtEzoGKVJb8aqLLFmOPM6HjMqoyfkXj/HyptBwI9iik42jXmfj82e/eISZDMxwCibF3F7W7hDl6sA40lO/zVg3EapU/LjZrBijnX5TSMwU9LV9C0pnJvDd7Xr8RCqXl9RsQdtmXai2OANxUE7dR7vI9Vsddm+bR89GPKHAVcu5N8aOgrQ2Ut2CUZCfvISaDvWyg0sJRkycgZUvV3P79XgaMJLDq8MvkMb0ZsRjRlByOgE3PVCh4M/yFJ3ihMKKsmB2YAZa3JpObw2SWW9EAd3UGg6XLN+A38NEejZbElLt5pOaQh/7/e99zZEylNW9HmaurocVLwEMC/vIbfNOeJWTB+ELd1DdSF9KKLkLA2brIcxgO6hXSFLZUjWYOtSjx4ss4ap/Ii3Y+ZzWzH0I+1QewsUXzhQkawLD33/jtM8moPCxdsg5BXHqsDYc1psK43ZLQGbCEsyftoqnhhAXX3Vl2TeKMP7ZA3Y0e879N+rIe8R+rMnpY/U90Vi/JhmmKE/iNbaFlDVFHwQdwhBkQvj941hSmxFHL4MQftkZw5q6Jj722A502ovwyWZBMJi9CvFLLKmnvcH4sHd4W8CE3iSOxJxZSyhI7CO8vdhJyWNM4caasew1qRPye7LoiIAxGDr/xGGN77E9RQ5vvJ6JCy+fhzpjXXCMSYPMHfWgHP+PBnes58jSIU/peIaHuvpwapY8BcV2s5ulMLTuUcRZS7Zh4xxhtjn4mHZe+QkuExTJyuAPVEVMI+i0pYpMZZDoicDLC4z5ZO5MPJL0l48ZrCZh7Zk09vw7NB2IpirPApy4yxDedEvScN0p8CknhPYuBnD8W09OdW9J03onxT/LRHMnDXb+KgsC213BUmIXuMywg+/DemAc5vJHhwy08JCmi/cnQfSUVMx4Iwn3pt/jkP+y0T33Pl+PnM6T95/Brw4HSMTlB6dEV/Ivy81YMwOgwGkQ3947y9e3HcZzQmpk9Tmfj0gcw1EPnuKm3qt0PtIbR2+xgubVimiqPB59d3vAnn9XoPK8IpWuG80vVL+ywJJCvBi/iy2fG4DnGlUWT03jHzO+4ZPtErjJZCqa2XVD/gs5+ClbjKcOBsGUBwTR0X68rlUBhOwDOWyzD430kSUlmS9cdzebPzt+AmEuRmsfWbh42QqOhxG3DfSiYpcce7i3QXLCI7AzaoFgidfcBPd5RcEomPufD15PmM5ujY/IYeclmDcmEi2XncUVS+Ow0m4l3ysp4lMLBEFn8xiasfs8+LsuJ9WTI3hh8z9unXOSi91s0OZKGz+7Fomq5lpQIzOGnmUuAwuLOl6nJ0NN7h8xonU4LJHowGuD0eDtLEyrdDXhlPoF/mMLGPbxPIuHH6BfkzfyeT5Iw323gs6veHje0EGnQ0aCqG0/9w98hrm/isjG8BNmTw2jVa1Z3OwohEklhtxvX0SubxXg/MpuXJe9n4bPVWH/6y64XtODY+Rvc/DOKtZUXoKN4x/iimARCP70Gi5O+kqe0nKYMeSA/vM8qV5bC6vFnXidYxOaXVPE3QXDQdA+mJvG7AdRM3em6Rsg98NMsBF6D1ou+lRV5wZNKeX8YLsOLJDMxBv3r7JqmQcqGdRSs9VqnJLeBsOFovml1zlu9F0MmrnaIJZYh8NS9qCy7h1SXiPLR68do4HvmtiW9waHsRi17ERcOcsABuK/YcCp6Tjx/G++16IA5i5TcHbfJwx+FsPqa2aifo8gJC3VggLjU+ygO56THu6jo2bv0EigkLd4XKKmfU2orvQWxSdchLzFwnCruA1axEIgc8UxErzehQmnI2mSqSjkXPChdjsDErmWDGFZipDmXwCztoSioNQ02NAqw64TIylXqgK3WHjyu5Uu6GvtB98XK0JLzmn8vjiGDux+h/Hf/tA4vRZ+uvA6jw0Mw3gTczow5TacGtpQ8v4K2cs28ITTG1jWQhXOJAEX7zuOLgM7uSF2Od2OSkN1MoQFwiGgH3YRN8hVkVZeCr9YvhV7HsuCmNg3uvR2Nd3avAyqnHXhT7Q61Q5XwiduDWg9ZQXnJK1Dc1lBtozURseWVlI1rKHBRAEorTgNFywcoOzrGo6Maad7f2dhw3VA/+gBHplyFPvZhEcc1wXJ98D31Xy5o/kxyzgsoyIda3pxgnng9A/+qjgf/waOwE0imhBWm4e2flEsU3KRGtoioTCpntMPviBlxwYcXn+Pn9VsxIAEfWga+x2KO45y2UJhHiY1i1fzRlSS34YbU8Pg0YS32PErA6REZUEwJIUjNh/gBQEB9GP7AGqvP4kPQ+M5bNszkvbQBY+7Qph2WAvGD3OFlZ419LfnNOhIpbD7+UMsr5RBAgfP0eDGlzRhWBudWGAJ3eGSWLJXgC5mXKWNoY9oYmkT/ZryG45eCGHP+wK4w72C63PUITZ6BNyxd4eHGj0g5d7Ndy3f0482YZ4waRDaT/rTeb1LbPNNGdyK1tNEewkQK05js6/bKUukjnZNkIHpOYpcp2tMVnm9vN5QG7wE37BQ4m9U1NTE291akFRxC0b9k6Gvgml8+lsUyJ7XxcnXRsPm2H2sbnWfPP/sBfO5SvRavhQFfULA3boKG5s90XXrCz6+zBqMLS6A5JWLmD4pBQT9f+P8qXfJBH/Rg1YDCv6qhjWtlagqLQuGXiL0PSidnBae5bODgmDnKEqfB7eRpGg+8VEZWuR4mWJHCMD4+y1YYvCK8/cGs2/fVNqc6E8Vpt7c7zebzob85FXqjpzdLQzzjoVwYE0S7Xq6kZb6KFFP/ETaYaVHvp8PcLLKNv66QYZf+QtBTYofn93fgbu/yKL02Se8TDEFxPSXk41/EF5/l85GF3+hu70YuNe+pAO355JnbTvIWcyjjSbaZBgQQY56C0Ck/jrN6tzHET6TAJ+K8Xzl3Vw7yZy85u+k4TcUIP/RIfo0U5SHzzuMbwtVcIqSHPwR3Yhja+9CeLQ1QU0Q9Dx7CML6NnBmRhNkGD/jxdlhuGeHKhRfWsxuOY/Y/MgoHtaZxpMWlcO7+AH6En6FDV5aQ9OB3VDTOeQlJ3eiVwQx+Iyl+/aXaOt4Twwu+Ip5NUMsH6bPgnFzcesKYfC8+hiuBCvxuH9/oL7dmc+K/KTFFWvhlr0kuxV9RJ1ecy4KNoIJmsdQO70Byrx24wfNKJ5ZHYu71l8BCZ+f6GWoBEmRMqSzAMFxYD2Pf3aBju1Ngc8WSGvOmmLepOG8zKED9X+OhoGth2h9kjgcbJFn2Yv5PCfiMK81Wca2T/SwxzAWyk4acdX3qXSjoQkawqVh8eeNPDb2LVh90ETlzB8cctIPLyfdhgnv7mDzeCk0CtLjSg1z2LRhFyfaykP+9c3opLcW/k0rgPWCNXQvRI1C8yqh8XAYbc0RATGjQ+x/6hC4aKuz6ORzLLzMGMSOu9Mm1zVYPKmcXHqC6WuvOHiPbqS+wwHkdn4RHzx9kG9OPc/F5EfRd/LYx7qTjUelgGyzISzfr00Sp76Q0yRtllqvQ7dFn9KVaFd6P9Iegwyt6PmFq1Q7cRjMzXYFPBNB3nv2kkrkK9i9xBTbOo/y0aZMMDeVwnMj/5H/JjOY3OzILy2l+MM4O6gQJ3yo1sb3b05F15fv8MZaf/x7xhpHOmtD+JeNtDJtMcR/CONDk5dBUuA0+G6MbNHUDQb/Kig8cx1tfqEN+s21KKf1jC/H7iYDmwj69+Y5bfq1hG1UZkHPk3s42ecbLK3RhLUrHuHegGaKu9uHM2+uA8fsZoi9dJJuR7/ns4ezUf1XDB501wUZB3XacFCIV1gtIJdvizA0Yy/snWdFqjkX+EmUCDjFzuQvr03gaa4x2Jdcpqk/XoBy7GoelXuEJKWXcmRnLaFtD20WdcPpkrbwsngQDU414QylCyAvrwMili/g8tWneNfChkQCNNDPJhxqnwrC7Me/MWXfIu5R3siP9/4kM0Mr+PF3FBk6rcZRsw3AZlwXrn2tDetHneT7jybx738d/KjsPJzZV8wDOWlkp7iTh0nUotd2bc6tGgXBMq2cdCUJ9paks+oXRuPFpnxWTY7krrXS48tB9GacFQiOHQcOi23A+kgsLdrQQrpxZzFhR+6QbJ2BAxMBnKqMsfueKmdfmQQv+25CulcwdVQbY+QaJ75SewpnrlcDedFf0G50F813L4CVW1Qhc7cKaA8xJXXFF9Td6MS7qnVw+rEH3BlSiS+SfkKr/kfuKVAA7aWD8LwqB3YeOctTom345R5dPOaSCANqcixecJcrg46DTOwEcE2+wu8fbOKxTed5psw92K44F7/if7xadBWPGuhlAes26vIi6I91RZsFCpgkuIu2hGhy5JJjeKvxKm0NXAp+lh18XzsVbtyVh90vF9ECpX64cXwT/OuVhx/+WjS78DGeGl3LybJyFPCgACwXacA02kinXwuxA/vQ3ivivIkd6dq0V+w32gvSazdBdHUk1p3Tgd6FSKaDnnhOrphcVAlWv54Ca/t6+KB8G6Vr2KHABWdcIq4F2s4eILfkHb970s8KHc2ccuQk2957A12/PCmyaiZ0SI+gknfyUDDUmVerfNCa53Ognj/7L/nAH6WMh3bPEGrde7npmAjdHOruM/IrafDndPiofp8uzwfKaBzF9gnC3O8vAQXtsyH87Wf+kDn0eA/dASlJGdQ8Xs/jLqTQk3mhfMNlDWYu+8TYmM05u43Z/9ckOBaQQS1+faytegLPbTuNjZcjqJkb4eRGP/jPPoQ/jm6ll6FW4KxixEmF0bi8cAzdCfSBFXLZ8CvFGx0UdVG6/gBd8E+BJ3ImULXTEBsVNyMHx+Kh4Rf4ms922LxJh0692Q3PRVbisMyDmD5BHQb/j0LzjArp8cP4dzSU0o7SHkibNDVQSCmikB2lkiKjNDTIKCtkFyFEPyMllIYUEomShkpJZVQqEeHv//6+uOee7/N5Ps85N6gX7KYE0hWPMzhyvCTm54+DE5XxZHSsja7UhvO8QlOo9BSAw3o5dOSLASZrmGJkwih+XpwFNNkPxxpHcOCoK3DrhCGKzRaEkvEXoMk6kVfV1IOL9n44PzoK3cO9SEeiEESm5WDil19gvtcGoodk0UegnzdNeogRadkYna9CCYWxdMg7Df0XxMFtuQu0rUcIOjf7885PbWjUYURRo6Qof6kQf/qhRHdvvYeVNpcg+6QT6TwdBTs3KXNzRAq2bnRGq1vh/EHCjXH9UTieKA/Xs4DPZFTTB30b+A0p4GFfgjYj88h5qyfM1G7G7pm7wWBkETUvykC1ACf866MD/a5eXPVfF1qvOoZPl1TTnE89uF5cmR63f8KRNAE1DhVwsBiD5CcB3nQ7ERK7ttKK1MOQcRnALv4nxdXFkZyVETt5OoHyE2UIWBNPd25+phCjq1y33YuKj6Rzt+tHqBsZgPJGE1Hn5zsYn6sPGrVfwUhqB8eO+kZSuqI4onwY3ApTw+tuISwq8h9Oqn+GOyKMwe7kPFwb9p2K4h5Ca/p0aIjN5K51D0nisSjvjyznkftGkvNrSdgb5c43Hqhg18YuGhucTE1JKjBM9Qptu7CGJsXcR7vMLihYLwPtfl/4NE6nxpADbGq4jj7oTaFulYdccfASPxMqBLu8Ps7QsATflVWUd6eEzz32QLksbRip7c/hQ01YFNRLBaM2QMfDRjo33hiKUn/yR1VtPvknnUYZJFKiRTeOXZOBiWpPUUh4Gs6cEcB1dgCXTVaxkI8HJi94wObJJjQl3JVyeyppR4cSx5ik8AjZo5wwGeCT9y34a/oVVpSqY59+Gwyv1OF7MVeJ3IWpKHEz7rA9hw+EJ0CqSim8/rkBIr/FYoJfLp2zssWdc6/R08TNvHh6MuWfboUPW4RhuNhC/CrwjMOm6/AN+Xb0GRbNwtmx1LLIH8yOf0N1/bu033EszBL0IJcDrXhkuyI/t8rBzPpSyp2nhi61kfTy3P//7NxOoTXmUN1TgrMCh1j29g4aqMonh9ZgitWxgZLfd3Fc9jEYfdueIkRE4IZ1EH0r+86vEzzw4pOxeHogjG4navID4RiSONPIepJ29OPHCLAdL8tCvaGsFVQMRRuSYVXdACiuWkWPjSvwQehcKGu9jbuN9UBRbBk7fD2DduMdeNLFDCjuz8D23epoNVRPQg6rWGzCOR4wtoLCaQ+o8HkEKHi4oNqYR1jVN59PPLaD/WKL0b5ckMwNRODcezMItxwE0bZhuLVrGhqpZ8LFs7689oQhVMusY2OFneT49CG9u6AB1V3DaIbpalrQPJmMtStAe20dP3a05pX8gy/vsYMbOdPh0HYzOL82FEtVHCDMLx0XvTlL2oSc8/IevX2whrNpKnvd7oclPBYGTdTg475cinRy5CWerZSXu4yqapagdssw0kh24hlC89HPbTi0zAonoekVPPfMOUg+UoDut/9Cvecr/Hn1O56eEMwRY6Rg4raxoK59Cq8o7ASTpQtY9/cwVplWANfj9+Ehl3ycYN0DLw/+AMe3QqBT+Ybn3Z5EH9600MwXpyljoxpO+LGY102cSl2XHuPflz7s9UAHmoT+ALzYjL0LL1Np4HO6O10cDRe6QNqHYwRmKqSoYYTruzRAWLof6uxvwXIDd3o8cBe8Yw3xhUMDaC/7zIa7syD9yRT4Nd4GXm3+iU5bbvBYEXV+LGVO5VfE4fD7jaT0nnFxwC5O0tKgpLrREHkviKfLhMCUq6KscMaRoyWvYO6yz3T55VIOeRwFR8oGKbVMBh6fryJL9xmkP2kdVN0phcTVydhYasJm5w9Dxy49HvdiFMNqCWhd5EOjjgVTbUAn/re2BbN21VPklc9sL6JH1eJnefT1i+ARaQqPChfz0mZlOKupgI9f9IBVkQ/Njd6GbaG3MWvkA5gq8BYXiSrAoaVFMKz0Cq+SugmjT5tCy4eFsGH1T3Z2v8OR4rlom7obQr1MoVUtHOyGb8Oj6Umo9KgGNxo5QWD1bjprcoCucwn1D4SjlOUESNs0BuU3KEHVhA94WCEYhMsmYXDCXZQ+78ozVURp49d2jjw+Eg56XMYZHc9x18VHIMkCePHKalh2TYV3G2pS/slh0NluwoVVyrDxpAxc2h4PocI12Dl9Orw1/8PxC3bC/kPGNDX2DveEarJllgzM+efPU94ehGC513TKsYDPr/nBfsrxkPU5g39XesIzwXyO/6sEy84lUcVmhAz13xy7DDne5hGkF65E1XfPabzQQ/b1GgXb7ouB+zsvVIzbBtd7TuO0ZkeeH7qPryx/gbFDbqgvMAEjJBtB5KgQRHd9oOG7ZqNalhEbCz6Fupg+LDw/jB+eS4CAjDmspjUKhBaYAO9Uhf++tOPl9bLs41zOek+74cjlS7DCRAACHwXzteXxpCU4DNoDVvObl47YsekRJwpfpsNdrXA0+Qi1rCylttl65Ac+fLZ/Ehx9/5jw8330yRaBaxoZXCyhhykSP/FaTD4ff5SJZzkFHUgKTn61xgcn8/n2yHzckRaHBmKbUODtR7jTH8TRc6ups/c+5dbJw6KoX3i1soCSRvrx+aBZFJZtClxcir0xsqzr9Z7jLmvC91Z9KEgQx02Xi+jyq0JW+thE7zdY8T7aTFERihC4owiOS5aDAAvCiJ4QXly9ifd0hOKsce60aLQi+8/aBmEdd2CFsT8LPrqFwxzHA56q4Y4xvlS4dh1+j/sJWV1x9Ky1Blevr+clq3Rh87Y95HmAoXmOAPfvPEHt133x/pz/INhRlMYv+QWrHtbhngX1eMThKpv3WMGXO5/Jo/k0PS4SIx3vdtbvns/bj/twmZQGTDOfQn+7XUG/3xoMpk7Fq0ca4WL2LjCcxqToJAeflgiTx5NXaETHcO3tsSDTYAOC1zfSKQ9zGixeAU0lt1Az+CgV9LnwgtJx0PQuBQ1PaKGShwHMTGphR81quNLageHbV5DOIiNKdvxDPmrLYKx9KFk/eIKxm9Vhd/li+tZrTaIWolxj6MfrfO/T9asqMFRfSdHdwmi4PgMPLx0PnptukN8+TV67x4tfQBL5n3hL1yIUcPL0Tpz02QX3NN0il6RJoFGpBdTlhjv6p9IvzQdkcRG4cPFHHFVyBRKmAe5Zm4EeL0eAi4QEmMXUUetSVXhk1Qqc7YBawc382VQWrWcHolHzE353YTwE+K6iZVGSlOt8noK2GnDE3VwsLzhI3fMSac/NIX4g8eQfgwxgTXQtZyUFwqX8cNL+sgBj3X9Bk+ACpABbSu62hb7zvjBN1xYOX35BjyIj8KRqJZlWHqO78JiMfhzGyTlrucM+jTWXHcSsXjV4dd4Uh9oW0K6/j3m2kxXu2HMaCu62wuUvrmCSH8DvfVZSFSnBsXHiEL8oDebrbINrnbNg8OYM/Bryr5M+/wWLKDe0kT+BFqITITNekPzOHAO/MAuQkJ0A38fr8pP9p2H4Fw9QyDkLxXnWsO7nWMCzbeR/+wVahU7AtrE9kHdLAj+5jYejrpkQsuMOvuvUxnJTZRg8EAzqVl24YeN/PKSjD0/lhmH2TnPYywkYK/IfN9hE43t3AYjdHMh/DpewepQiamSX4RU1dVS8kULplz2xeuU1KNZuo1oHfVDaux62jVHikebhLDftGMvfaGTv26txqdRn1NedSKuCdlCNtD7Yb5jJJxsDuCe/im98awavCTtgRWwubD49HqeM3g2ey6LBLEEAVvcupr0BnsDPR/Od2T85RXQDhNiP4IK1G1BayBSCj9bgdAlDWKWsRbUq3VytF8CaWqYcLWRG9w4MwDTv6WR+ZwQWzl+IPXMJRLN2srPwEXby2EopE+dCvO93sLDz5vg5/gQOj0G9dx9KzFGGxbLJOCbMER0sX3HLpC6qbvlBB/RKaMNRPZpbEgSvbaXIdoIi3A6aSXdzxclorinYqdfwsZX6nGk9B4eKk/Fw8DkQ27iXIq6Lwe9oO3o46zvEaWbTCzkBSLX7xjedC4EMGY2bzdiuUgyrzCbDCckj/D6kliuVV+PwSztBodORlX8FU26VAak0lxJFXIWGvQaw9bc/a5/vYqPsRxyoYknJ655C6hx/WHstmp8O7QDtJ65ocUoZPJ8bY+OG7dCfsAxb2oxhml0bLL4XAKIe3hAVHQqv3jqC5UNJeDLcnt1WN7DkSX24JhzFPx10IFAqAToXNXHlorFc4XYZPFZqQsf5IhbEFnSbdABAX5qmLa0kkyhhLlm9HwsuL8WOiv2kVSYHqv++u3ZRGLe4PQA8/YJCZB9R/dNjaHfWgxZdWID3GszR68tIaHRaxg2d1+jXtkl0b7sEJJ5cAo/CRmHz/Dd4qCqTbdrWYOoqGThRdoQCg3MwSPg2u6Zl05IN5jSneRx9Sf1F8yXloMpuMgePUoYsGTn4bTHEnb3Tcb3uZnBeFIEFcu5kef0QD7rshexr7vTCcjIYznkEPSOayDw/BH0+O9ONYk2aHrWWVumoYtxCLbLRLwODm+Nh7Oy9bLr9Az1RcaTeA4G0r0QAxlgeobmF/fB1pDNf+J6ObeNGQPfKPtZ6/gCfvurHVZmd2OumgH8TDvKmu83o8LoNBqfNpZY52jC+bhW1XhaCxE8GtNvuNTxJ3UkuZU6stPAGjlWKApfP31njhgbcqkaKsn9NX3/a02f7XByafZXd5uqRwJg38PKSNGnO/AKTS0b9cxt/2CYpjjheFsx7NnPMkC87haWgTpAThnTGs+WOvfTCQwZ2TzEmpYxRsK5Tjy/tfATTdeLgm+VlGj+gxmFGTKVrkujkK23o3v8Gi6Pd6dQyd/bqiGEJpQY83O3KheH+eGpWIOVa9kLRNGHY2PCcnUZPpk2zJ/Fx9WzKf6hG1W7H0SljF02IdeYHNZF420UT/iv4Ri7jx9Pvm8U0QvsDt9x0AkVXQXi+fwCtk7vJ0+UonzO3ge6loiT9QpK23O3nzVPieepQP0tXZ0Jy/g0oDN8H0j8FcV26JMRsqOKiSc0wY3cHXBfahGWZAvR7w1gO6I7ir9FrKOboCtiQLQ6yfaPJ+l0UHHjSRkXPx/DWEcKs+8SJbmd0UKylPM+S2U+GUboQ4vALnn8Ygove6WBz4iZpfGzl9e9e4MMvQNRiiXVDgdSdIAuuMjJw55ISTQq2RJkvYaxntwP3j1Llt4bSlNGxD0xHWmOq33D4r92Czk0tJf/R52gwLAqMbqjTL6HD5O21k37b7eTnX6ZC54AqvG09Am5aI7C6KhtP7r/HjofWwaIKYy761sQb92fxDeNOOGWJMOlIIfdnf2WrhRG4bc02fPHhFd1c+xXUGmfiu9mHIVonC5qLNGHW8kX0aup7VBbtxbwjeZw/XZ7UnjSCWI8mepkEcOelHKo6PBp+GmtC6aa16GLZAge4kExrtXmFwgtadyiUd5xQoL1ZonS4dyz0nSnEer9aWkrv2SX7JXRiIFPaGbw5uBJuRvVRvEY9TqhjMCtzgLfKgnT503+Q495I/UvTOXeTGeV9MeDm6WX042wCjqyXAUn7Gbz04DcuSrfBUr/feN3jPo/QGQX+y2ehrrcc7Kr/wMu36oLx8rlQf86X5t+05TZ/Q953/SaFTgzng0vLWMbxKq8Ny4EDYvoQqdJDW9SCYKH/KnIr+MPiglFsdykVNXxiSXH4d/IWrKT82xNhnfMXdlgsQUGutbirpoq+ffjFztcm8qDVcrp8N5Ch9irOq1CB6R6WOH3yL9pdLM6bfi8DQ5XNsPZNDEo4hcFZ/dGw6GUbH91vBU7RSTClox0XeQ2Di92dKDvnGFsPm4mv2j9xp9QjfvNvO87ZNupfRrzowv7H9PL8C5pbtho1+ldh+L879vQ6A9/SwhHpKriKKUDNixsUnlwC0uvaKC1LFt6uTaeDU8/isWHLqXRoDfwyV8BBMXmYAl/IcOkTXKOWyef7h9DRxBqGlryD8w+foG/SDlwySwVeqIuD7eoIjj/qQxqHDuEtbRUeE9ZPsRaePC7oJ4jUjKfO+qd82scC7qqosMDIg7zhxCyyFW8Au6MLWf2cDNRXXQSJxiB42vcAbd1MoXJiOh8puUGZxU6gD4V4NWoLeLV+40/+1vjhZzovnzGEd+RU4Ke0IMQEaNLpQ19R1eIRbk5+QvGbF+C7nY20rLoAWHMv7ZW0hYR8S06fOpUjb+Zha28a6bgO51MuFRDZ4YbF2iEwoC5Bh0ptIOfuaLy12oU1wrfxvBNfOO5aHTlqjiK/1CD47TuT09aOpBt/xeDukhpWb6skb2l5iLefTnXRaZC23oZCXm+lgt3llJz3E1X/9e3r+mRyP9CLbdk99OqLFm8QfIYB1+bzQuU38DnxHGmJzmM9aR14pdZFpxI8cfUlGZ6h8Jc/fngDf4TrQXfBaVy99SgYrfGCli1mgCcyULzSAJfPPMR2ZpUo5OTNppNdYCDeH8e4JpCsjS43DlmDjvAEqq27x9vj7dFm+SRWCEqiGo8l1Nn1nu6l9eK2YbfpE5lCdsUhMp/wgqckjAG5Qlu4nPWa+pPUaW/9Iv6WZ8gqs+P4zDsLMBc2w9BOR4pWsKC2TBFeo2dJqRLLWLxWFW43veGguk42bbaAXNmNKHFtGCnNy8RfPdasetGOggrX0v35Z6BG+zIGTJkEdsuEYHeqH7cf2Ash7epcc/UwPzyzHxxOKfJVB3EUj/Xii7v0KE5JFKRbhSi2zBM8le7QRWEPTBqXjOG3rdgm89/NGSQQ+J+kg7qKsDpuHmvI+bFw6wEO9h9k5SpptoiYQVss7vO3uBNwY/V7KJloCekdmpSjM53Hbb6LovNuw9+Xe2narRL4G2dJhcuCYOXd+9wROgYuj7bA2C+fqbz0MTyKcwTZPT78d/wLqFW9CC7iH+no8G4y/6gKH9y8CEPGkbHECf5lM4qyC0NRpvMrtp9R5ounvpPkul8od1QfJIcWwPh7D1mpwx8uDlPlE3uscOETZT4/cQV42J6HR0YZlOVoAQUXfLgp6j44Hi0gG70M7hGsBcmFHpQqugna111AOV8P9lsuAOG9W8DCnUDllgvEky2+mfqdJ/ba8qWnjZxa+JlSx+TCos0q4LV5HloMyvMMkCepBfc5ZdIqOqh+DK6v3QRbHFq4oLmN2htGwKrGQsg1deEk78ncOWYyne92oaWjlED/tS5uE09FfwiGl5/VoVrEEyfOSIHbmWdY6MQ/pyuLpgm35vGRVxZgVhHKL3XUcPcORRj34CAkxu+i/QrOeFilnPpXeOH8xeL0uGUvJK36SDpC5+HBPgMoG7kPvgecxMKx0VSbbYOHcldh28UQVmyLg+kCnlC37AApO8jC9II/cKlfFj8aDoNx5XXY4rEB351JhyWZ6yg7cAg3afxmuwFx+KC7CT6VjKHCzmy+ciQIasTmgGACw3VLVyyYWopLQ5tR+6UkbJ3mRhcCmvk/uwd87ZQPaIeqQucXIRpbmoefx7nCGf+rePAIQtoFT06vfITDJhyghZ3NnGe2HhbnecP8Riuy1H4FAxUxeN5FHQadBSmsLYXVV8bB1UYHvtngi0smO2OiUwSLv7OkphtXGCMQ9Ho3stBUV545PgzK9W7BLs1WcN29Dob9uQ6hfy5xgO1z/KEzGboq5qLRi1/wNnQ6e8qexsXLdkLWLiN48fEEPpW7TSbvP6BMiQlMXTWWa9YP541Zp7mr6w41No7FfWdjMMXUjo2/DUdD0ybqW68C53CQLGxU0LlsNYefb8O82WEsFDGJX5zbAg+8lPhSbR3u26YJ8XNFYL/BJZ6eEcnJS0ZD1nZTaBpYw2ols8DbJgiLZ5fQGWVhuPiwhHKGe+CWUw0UdWQs1erX4YWaZnj02wfm9AnAXF9pYAcx8N51nGvq94HTWX+yOSZDxepbaESIPXtGR8Put9+hZn8tvDwuDULZ+7FB9QTcG5ONV5ZuZR1pV0z0lYMOudMk5y+FwYs94GYIgKGmKecMxKLEiSw81byWX36K4b8rFHmf5zPy143Bry0z4ESiNKTpPwSpr+tYdGoW5/W9pnXpv1Cpu4p3n/znfCkPcFpbPfi8HgdPOoex7NJocNE5y8NnDee3p8LowIJR0BR2G+c8lqUPpxoxsmQiTLlrRm9/vSTZo2H8/uV4pCOb6M6yUxQ2OZLV3ovCncNPqN5zLBj2xZDY+jWgMm052mMFDExoxfu7OmGMxR6YJfOau5ubqQJ1wNawklPWvcOzfWlUZyCMRe3e3FuyA7YvcEaN5YvhXkMwmYtKQ63ZXMq+dAEevJ4LpmYeOHHACQSz8+mm1mXwXzwaA0rjefQKM9A4pwpn7I3J2eocF1r3886lp7Cv6DCc/HMW+8KseMQjhKNVGuBb7sD7E+fgoPM2mlvcCL+fRcNDl7f8dfIWihJbi8p57lAwSxacLUM50+0KeYlE4x0taxTCcLA2q+XoLW9gifhuVHudisWFyhBsOISVNwdo058cejjZCY2GItFobRGLm/wFMohmX3k10PQ3AqkkQ7j7+By0TvPmn+t1OT51D2gtqISAN+V4YPYfvH8xArJzx4HcCz2STFflJUeTIPCIEe7K1MDXMx1gi9c0HPfoLJ7Zow151hJg4NdIfYkbyM/mEefMnM5/FmvQ6X/57xLLZO3HF3DHPnWOvaoNIr3FECRjCWJht3CjmCstt+sG24ch8Cfdiq5n3sAViydwu4oEzPgUjMOVAjh+2DEK742ky4fD+KiJPZx9sJx21cZjvf1MmrdKCF5ljSXeOoHGPJVg9fyjNKK3jX1yfLlf7wfTqEFoWexDki/VIHOTPxtofKT/HueAvNwLOh3xBptqF2Be9lvwrnyND6Krqb1NB57JXob1otNZrKSef8weRKX/HvLC5v18pHYDHLjdhhJVI2ms+igYfmIr7jaPpz3PXvHjjSdgDYryeuVv0JUuzBNH58GUPYq8WdgGTB9Po8Wz77Gvnz5NnPwZ/0iHwmi7xTxK5ci/91GnQ23eIJMvBNUJ+/lB6g46nnuMq8dt4sEBO/hw2gxXGtRDregIjH3aTQHXRSBFVQb2CJ3nBYuDoVnoKQr80IXfj1LBuGoQbvXngffyNNYrYvD+MgO/Dsvns6p+7PW5GS9OuombYBmWSQtyvC+joqgvwwdp+Hm1nJ7JaTOeHwe/Grrh0Qwt3LNPBR5SLlSfqMT9z41Q+wXA7rk3eMW2x1TzejGUJnTDqy3msGzaIboQ/REHHpmzo20qrQ8yBfHIOyicVk8/3ZXpzeFHaFy+nTj1I4Tr+5FiRSJ9H/4Ss3OsweR3B04wzsI9DTakI1hMO55Io4yOBGJME1zJHODPu9ZDYIky3Bf7xXsz7bC4dy2Yjh/k8283wpPgD5xXJM7Wq9ywXfIPJC20hWRrE64tKcKTVtu4J2YJTt3chX5SmWjVthMnlofgpWVEBcVacGrWRJp0zpGz9u0nkTW1/7i4Al0Hh+Cd+jYQmXEZzJKjIadFGp7lfCSB/ijyGatGw9rnsfO7f9m4J4+SR02pbk0JH864istWq8Dvp4008WEiTp8kz3j2KJlp3sEdU4/zrsVNrOtjiWYHN+MqU3UY2jcXO+pDcf8rd9ho9YWyEv7SwWWFHPf9Bl4RfEWTu4gnvtcA22V7obC3mKdMqAOx+49gefldzqgwRvtaH3o1dgQPk5oGc84ZgvO9tZiT8pU9bo4FdT1vuGJiDp+PDXGb40Rq9lTEIbdMfvtDB8a6/8DQQROqDbyFmS8uQdXWKtjtsAKfy+xDnbw4UhmSxevDNWBEdjn4RM6niT03UOTaMlz4axzO6VrOPsEuJC4via9c1+PcuOFQEasLGZ8AegXTQXXWejpXcIhs7oeA59xJNFpsOxicvgKzYobB5Y8FeGrrHtyjV8zOhkLYlLuCXK0FyNNwOpWsicZbdTlo+UIZFt7ezy4vJ4Ny22aYst2KQk9eZN1EPZyryFR75AfUO95ng/0qUPWfL14+7MAbcp7gu4RclJRyYOmhGXTd2JIMmx+A7feJ9P6VIHw8aMdDyaUorNnA9jV/qEVOBKI+L+fyy1W4q2AxLPdVpAVvrWBNwDe4dryZrs4+RJKNrThnVyaqedfSQEAFRN9LIpGLucAVYmDTthX3xYagzC8rwPWx5J55B90+S+JOxY9Uvfc6Onz3wEuzR4KeogR3OGVyiGopvf0oiMOGHeHZ4WlwqewqRTz0h0WtV7lJfRxoibryuJSnPObgXNJNceSkMftJM3k6R258BgM0B4+26uNCHYC+C7ok4pHDZUErWPGmBYiflKPfDtk4LasQNmi28E93dThTYgZrQhqgTe0wj33dgXr7drHULCDcWoC7JZrR404Evbo7g292jgfL3K0Yk9xJbdkrqWfabrr32xrzbx7GwdOWtLbcDx48v09+P6WgflQfSp5oh9fXM/HS3nyQevuF7LfOp8bRN3DpoiZO+tIAZyImgnMaYHpKCsa82M3Sfg3o4+vJRQlnKSduLzW9nsFn7fU5p24UbHs8CCnOPeAyLpZcFs6CFP9eOPDb5J+Tf0LNNz8pM22IRwLDps3NWKUiz41QA+dvNuLb9vekO/c5nz+2COc8a4F1JpH0+tgEODNZivqUqkHB+Qh6eyXwLvkbYHk+hPoO7QGLnc1sqPKU1qyWgrFXy+jK63iKeeUKrt+acZHNCpK1q6Ekw389d/cerz/7hbe4GEJG1HS0FZgFa2IcadnIMpb5speuLYwEGfd8jrg3np6NcaMrsxVg7PladlYxoJe//Sjy+RYIFbfnxIoUCrisDwksy2IzT1KoHcCPEj26+3MiBXUHQd34Sq7CG5C3NAwGLGRxuHE2uMx6hhKpk/95kxlk1w2Ap+4XbHJ0B9no//D6MxVU6DfG3VY3YJpmHzxJJDBOG0sKRx3hYcozaA8yA9fpuXjVt5UFj/6kyARrzg7fTccajWFyw0a49U4YfTxtcEpjOOxJfAx+186BWMFceDuA/FChinvNBGGkwVZcFngUMyYuR02aSqs7buLhTl0OG5ZEDxx6qK1hPO5PV4Q37oD4WZL+XKnjnD5FHGsxBz8vHqK6Lza4TcKbK/v3c0eKBJQGDvJJ2y7QNYvjxOGT6FfqGuqZYsunny+Bmmm38OOO01TSqgJT+oZg/8l8HJYQSvo+IfDuuR6faD2A1eHSFLJmPLtFq/D90QgtgR4UsOkmd+v/hpgxeWRy7xWNK9kA3dCHXjSSpC4I8Y/zk6FmcA5vkVfAOOPx5I+fINEsgVs+FWKbSS5KgAQ2br6CdqLy0Fz+DqWM0rn8RDHvcpLChaPHoNEZLXrzJhzaJIdIM1aJNL5bAidsIslLXVzgc4CvbX1K504vx4y+b7CrKZ5vloeicE8Z6odogM7xP1QyrJ7ah1ZQYlAn91Y/ACkdG4r8tZNK5Ivg0JgFoK6rC+ubTCgs9wo0D+ihoJ0x/vqwBUOLIiBcbjjF7BbjGM+xfO2uAWjemQbfD83lWbtE4MKMcej3vQK99LZx81d3uP9kHq39YkdXnqpAm5cq1kdsRy+lfBa33cOvi0ooeUwpbZH7QBNyv9LK9puQ02oDJ2ft4/rZX7FbWRsLUxfQ4I18HN1yiw96ueMbcU+Ys2o4TzhgBHc2NJJJcsi/bhaCN06f8KBqHEotP0Y91s6UppbMe3V+ouw3C/AOCOG4sJOs+C2DhRRtYUNqCCx4Js9LalK5ICINIzdU4C8NAbiYv4TzPu7jNz90mPWX0q7SXfw6U4e3RntyGAzn1RPG//N2fYg6+hHdl6bi/DOncOvbPbTvfhtMdNLCHu1VMNL0My201WJzLyHIzquGAYNs7Fzbg6EX1oDY704MDZ2Kk+kSGmabUHUF8OeWcfBoXw3LaClRz8kGnhGSyhV2Gvin+xddqhkPu1qFwOZTGV6QVoAb1lHUIv0KtmbEk8pPI9LdZg/hgx6s8Xk27JJ0x4kJWyA/1Ax+RL6GRwI5IKW3EQx7+nHapstQMTUOzO01sOigKK3rGQ/WXqPhpsBlfiftTc5Cr+G0/h7IVruHO6eognykOA8rEiFT9b14LN4YqoKVYfnfmTjt03oue3eEWjrDoGmsNoz4WgHfdlzljh8K8NdTFARXD+GO4Slw/3kZLq9cCRkL58Hg70EaFrSDdKauw3oWZBt9OZC1bOGh8vP4eWMhcUw3a4XaoPfqBSRougxkFztxX/cFHOxXgqVvBHB3ijRZvb/Af4OSUFQ6A+54LaWoueV8UXccrHE7x4NRVvCkrI/LLl2kPXiIcm9GQdeXaD52WgcWWK0DK31D+H5BmONq5GDfFT04vl6FN059C+UDAziR4tngjwD9EHSCeR83QKGTDUbMFgFfp+9cOjIFFvp3YEXjbb6TLslBt9dRwCcNOLQE2PlqHKnlq4O0eTeY1aRCYnkAJV0WQLGAg7j6n58qXX3Fqo0raZPuAbLPMQSt9Tv4UeNvxHBXPidjSylHpWGf5QlY4PcGL5bFk+UIEfBL0IKfk40gedl0av23lWJr9+HeeqYF6qocPNGXY+0/Y4t1PEkIa8KZ8o34xXgfz5TTRrHBafDfnDUQZPKbL/7O41HPBGB00UsuiNWDbBl/Ksg7BY0/z/Ci9x94w+KtzEur2H2bMbpM2ArpRZ3gUyQKddAOvgd6ILRImE5P+oR5y6ZiDNRD0456fj+8CROlRTmyUQm2VR/k0hdzOOHePx5aZdCdy5W0zaeCQyLbeWmNDY3KuIieVTZgFNaB9WJ+nLBThnUsXXBgThh2+avCOquZWHlpOJmNmAS3zC0gaL42HazMoDcffNFYRo8TP7eQ+fM3dMczFSRM7lHya2tcVysApevkIerLXdA/8h4jctfgmN9yeG2iMOYlj4RPDWvRRfISXtonA+tabDntkDbUP4qHSTqhJC7zEv8m2INz7wu22JAH0XHBEKE7FuryPdHwowLklRHv3GWFh/2OgHfkNhihkMeKP8Pp9vvPWPCPQ3+rp8L6w3uhQ3U5N9sqEAk+YJ2Vu3DMFW9uP3uT8i388UeDJMy48IrOOD6mrEgljtZ+hIKjq8Bf2ImejxrNzdcOoIlYEf/VkILRLjdARX4qPj4cS0Ep7XQ2bwu0l50h/zUG/Hi0Jjf1boagLoCSo+Fsf3Ak6WkZQ9jmVNh94hElma6lwbxDlBDhBnt0ZUnHRAVMDLRYX6aNmk8WovIhRVwstRS/Bc7D69I3+Or6dbxj2Fs+ISACH79/hJgfcjiddVm21A16F1zAudMt2N76AW6Mjubq1mY+cXA8FE1xhIpEB9yhpwedxTk8x3Y/RtYUQyKc5mqHTWyvvRZk+mQgWVSctD/l4PbTHynN7An2nt5Ml89Vs5fxQta2HwcbxvvT2SNqMC8+jZpqp9DX+pFQFfMOR5cPoHnQVrhR/BT/VitSY0gO/JJCWKE6hf+KbCDfGlFW3lpB9bsjsdduGDqtNWaxUxH8AWdSd8hEeOP2DL3+Tb5rAvdRfbIdynjLcMQjbTK/rc2v77vQ6p+yeLBsEqi65XHy7+8AOvuxXm4JBqYYw+C4A/AuKJAk8nuwff1z6PYZD1bno/jYoXpOPSVE5yNtMN9ngO6Z6nOgw3xWWnCWfANduXT0cFg/K42MZxMrqWZi0tIISjDL4fl7zalllRusXW2CwyPHUuWhMXDu83D8dNUBVSM8cMmOs5Rb+oqmjl+Kr2bm8BGzXaQWeYoWBajD36FOdkiog5ezXfhG0CPu8bwCK3Me0hKbdfQh6zGfXKIA7RcFIOPNF3DqXYOtAXv4R6kay4RpcvkFcTpxuhzFtR/Swo5MlJ8pB+mHYjEj/CzIbFPm3h13YHv0Smjy24IHLY5jf1Mw7qhJ5JcN5nBh3Bhu/yXCPGACPatyOa45G8WEG7jb3Rcku47TIccpEHPXEoQmBuOthpnslBDMM7dWo32WHY8ROQw9qt2gOMocf0xYR8KPDGC2wCQoHz4IM1OleKGMAGj19lDqtEf4KqKCnk6bBys/X6Pwb/oQP9qEfE/tgt/V4+G6njoN3k6nKu/n7DpRhbIyN/O0Jj9+l6cBtR+SIK63mW7+vkUXs4/ztHExPLljBq/QSWLFEkuaUnEWdb7Igtvij7DCqhCy0gXA+GADLk0/A1M+Exm8HkA3bRWKWbCFxwsANFxbD62Zf2ClURjIq1yD9MOioDFiLXyNlwSNg/tYuyaNiv3lIVhhC3xcOAEDskXxW3QyqQ/E8MiEMDCXnwSlM45QYfV03uLwr89zN2DsjhIouDWKnS5YwIFzHWSLe7jAwZ/GOTVRxI8m7Ogyh53t36DvzHTcW/oUVzeM587niaS1Jhj8Xxax0VUDch/3l1dnyoHC77W8KaaP0uJSyU2znIrFf+Kv6gw2OBYI8jcsUCbo36Y5YAJfXY+SzOOLMDxOg0pHHseaFVqUG1aKF4c+0rddHTB3VzCNllWAo6ePsZLlATS7SLzY/AAoeM6hD9I38ZhaNu3f+I/5rypIR04TVj6pwx4rQd6wPZPyyZLGrfkPJ/gEo+XZDJaxvUYnPzyjt0Xj4aNBCx2s/8YvxJbSoslDOH/hQoi8eAMnLlXBQIt4tNilTr4jJsJovSVcnziHF18Jo7iI56x84RRtVO3AOAkvLq9vpnc+4bTgxRgYO/EHSv91xWnea3H5nhjWTV8HXvPHgNafYLoeWYyjv4WDzX4ReD3nMPo1NGGXeABmTLXDe7Ni+VVuNFWsiWHzoiiozdbCemUjqLaejcUe33mzfSdKOqbifg8RapO4SHHVtXwneyne/VpBHktGws7qbHKOW4vv/Y/Tu+X91Henkw4NPsCBwvc8JlQAnh16iB/6zeGMXC8auW8GwTuN7Cz5Bltaf/Du7P8o2caOICEAFqjbkr2JJFg+/8p2Cu08Yv4v9C/JpHmT/DBNTR+LuvzATyKJr2sfxxtmWnA75Aic/OiLbrMvkV5mJh44IYohPvXsLVfEBr/ScWVuBBgOMETObqXda9LYfd5ciJlkyhuhA25gHh8d44GuNq/54A1R3o6i4OY5j0ZVN2PozkGeWWBElVPP/euoZbT6kwtFC0+Gve6LaShnBDSm1YDOsWzWDGlhqUmOeGhSCLgWj8VILQfYcN0HY+NU0ZbMYcG5d1hedRZ8RqVB8SIxfKNbRCJK0dCfjJTqchg1FE9ArKEV3M5whrPBCmzwXJtkvg6j1N3ToCGkn0baqUKUcCvr6m6l+fuEITNNj8HZjTH2FG/I/rdXr5dh1h0R2KSsASOrjNnqUiE31emD7jIlFgj6jbPrlSkpW5VDmybzjKgM0ttWRmMnavMtkbmoPEYCLKyQ8/ur8fCdHii+U0ijrrSwc8pYlvkaCyP2ZEHGQXHMnW4Ari6alIgtqBtTwqJbHcBlwILDS9LA+edsmNgQSl/Wx8KCoEkwmK0GlSvzwGDYGKy81UZOUuO41bKbAqPeUsVWCXKWSCedlUpgLjSLSvVvAp35x4v/QkmjzJEKH5ymjWnm6DKnEFx/muCs5klQuUCNxqUGcpC1PD6fPxLtM5Sp9d5fHCZVxVIdN+GodS0Zq0+EMTa7+MpJdZIUN0T1L5d51nI/vlG7nM+eWoqCS4ox7oYibxcVg1n3ZPnapF9gPLaBO93f4dcAA0oajvht+x8SjxSntbljuW+PKAQXN6F8eAMcO7uS1lToQt/nGmqdn8prjTeSRL8Cz6yYyaqB4vDZ/Bjqb76Ld093cUPZVrAUvk0Jquk4/sMicJZqwanrwmjqO03IdhaAoeMq4FAOtLr8FtUrHud3PzxASE+ELnf3Yu722Vg9XQWub0/BIbsy/LE9nm1KrlGG8Q+Y2+IJO50b8HOYLMxzOEbzq/Rh4esD2DgtBufEXqYdSyq59sAAhzel0Ot1cTzx1kKqeGkKKvnK4DQiCs3/jKIqDWOuO+vFDcGh/DpbhwKeT6HaH+shgvbjrgQxiPpuye2BXynszHQ2M1Ilva4ZUOTyC8ViC9GnqIPf7l4BDTPVYHLGbK6e6gJ/3KZjn28x7ZSfjm7nGulB9iGuzLDll3/d+d23MdAy+wge7lOCZcd60FN2Eie5f6bBuK/0NUyZXMTH8d59kfCf5mi44DWGXySv4t8rZ8AzSxkSVv2PLr7s4qblZeCwuZK+LHHGhCEDKH7xDq/+95VXfokgYdEr3OThgK8Dk7D4lTCvG/UTFae64d0PE+CAyWrctXEqHXleR9nWWmB2UoWnPP/neK5xGOj4EvOCP6PCfA2IMBCDRMkocjbaDJtLtGCqTTFsvbeOOi8VkNdGXX57bj5pjdaG5+M+w4YFCqRssYMlh1eD1tAtenboNWte24l1cW34X1cf55sow3OLLRRetJWDXxRweFgozF83gxbpxbIu7oG5mlfoV6gldhUqgkDDN1bOW4vjPg1QgmIB93q1kkvGD7Q+d4kyTn1Fw7PL+ftYQbg7SYaqj5qC914NdCusgYE7WphxooB8wlsoZNNt/GJ0Bl2OmkFZXi/PO5iME9ZtQE2rah7oq4OUa6+oUXgKCk6Nxr8O23jBLX1IFnr8r0em8fGoefhqrgBM1hbhbhV7eO+1nxLlalm+t43mDbeGtdKaoHBsJa85/RnnPBOnPuUJFPTyOMzN+sYXl+bh1o7vfFFGBAY/OlGXrB80JrvTuAABbtZOYLdLUTBD0YALmvfC4xEitLpeAa7JJOKWyZvQO82XCw/48jMRU/xkg9T+Ig08JaJ5bwSRtK0ivMl9CU07V9GkERYQMXcYx1S/hZas3bjqxWaa+2wKvOhfiDVqmqBuvx6/n1nOMKUQZ77dRPtd5WD/gVx6taAQWh/vp8xNDjRgJAoDUrP5aNtx+iIZiiqNw/DjdmsudV5IR0YIgNkIFxLoqyV8agGqt0fwqp0d9Mq6FvacCaFBlycw0Padkq2bMHjnI/h+ZA8VT9aHKjzJ6yUMyNXLiMXNRvNhgXEwTG45b11kzk9HmNNO42csFSUKGzq6yH3CXfKIyUHt7NuAs63AYnoSGTyZB0ulf/P6gFbyNhQEpQvudN9nFZUHR/DZhLNQXLsCTz1WgixpW8xxM4J9i3/wz2wJOHYJaYnQ03/bQZorNWXojqwc/0lazy72/2H/iiQK97/Nc7I04HHub1qawxDyThuvNb6A6q9v6U2PGh77EQE7XCdi2yZVehWtC8HLP1G7piz9nPWSc9zlaZjzFIo7dZO0LqjCdpG1uDpHC05eV4MRLXpQtvE+KUkkk9xbHy77+JqqL43E8rpQji5OB/WRV+hZkwxUzHnAUv1zoXqMEsTZrMdTN7bwnJuv0fPNXhTwq0A1jyqqnWkGRYeu4xy5vXj7ejacPTgWL6ZH88uFKbz7eRtU6sVw2O6J8LhSHNINh2PK9m627HpKqutGwyHZcZQbNREaLk9ge9ElKBtTjKv6xWGC7QrUE9sHo2sS8D+VJoy+Mg3f7TkGTw4yTjy+ng5dnIBWPbZQveknibfc5VM3N+MP+wPcIS1Ag6uG6MC3IOpObMT6WUvpfLkckI422fs9YXH9t1jywo4il//G76aXoePtTtpV/BN1Qx24SMoSnL/rsK78VGgrMYX1iY94Suxq3vetCXXrWzBvwx0+2mwFAVnKYG3WwH1RdeRq4g16s8ZAjm02XtrhQpdX3cHvZcHw5cRF9FmmCfGztpOAiSIu6tkAFruRHZ9nko1lFFe7/4Qvvd9Rc3UXxFwygsJXGXg+TQpC81tgyuRckOhfzH/8fCFbuw6eKR3FPrXFaDWTIOWkHv9JHMSqDz+g3fAanLqpg7Pytcj6Xg32rHrAPOUz2s4Wh9KODaS0pwaiHa9Sf1In9PTZszOupMq9aTBYWEFKHgq8QEUK5Javh21LO0nhli/6rH1Kpwv+7eQNGhRTG04fUiXpkrckNZuOhhN3/Ghy3zuIcBekvRMi4UfZZgy0v40zNv2C4e9HsK3QFDISVgOrwEsACQMw1fEaxVRMg73Hz4CH+Sy0zEznUKGVvKLfkR6rmkE/jKWVP2rBJEeLJN4kcdqKE6D+fSp/aI2gGZMzYfPRGNoTqAEbDyzCETp21HM/HJ+O06XorQdp2qeN8CtFHg6I5lDOnw64n6UCblq7+al7Kfo5LOHfaW38RsoLe+Q1afnGahTe4QSFPxHYWx+u1+jiq43qUPDQA9LfbKbtQzV0YIc5Sdvv5ZRvnvTOMomvJUjA8r+XeIJIHUs+8YHF9+3gz0dzHKfkwpNev4QTxyL4ad8JGtOpBpIfdVBk2UOMbMvkk1kloN/oyucXSeDPT61wePFTKJeope4SS6j8aMPm5wugv92QPx2Lpr1nFDFp93nCoBz6Xv+PeTdnwwM3TbD7x3P5GWlsdEeY9x4qxu2TS+hwpD3lz1sCQSVjwLryNkx5pgQfLiynirXW7KN3gPNcczEy5C8tHudIU7sS8bXGDhBU8MYjRxQgJEkY4sU8sHvFCVK9uxjnmSvymqXL8ad1ADb/Mub2xbYIz8ShrMiMgr3e0arJ2ZiZdha/9+3G9bIzKKgknSrE5qOeZCFVNAuDdLkD+l2qp+ysGJKqGeSVYhMpq90c3n0MZfGulZB2KwWHpY2C7gmGQNaN8GB9FGi/2gJo2AX3Ta+R84MsWNBjiTJOcXT9hCisDLzIhttvULCgKBcqbqbnN9/QR8+FNPpQN0RMsKOd6kU8ZqEZhOVG8Jo9uzhIby0N3A2nRqXrPOLjFdJYWI7TBf6xt1uL/gxZQ9INazaItQenD13wUNEDzPLeg4unHf7+T4obF3VgpO5OVJbXg5dQTfr65uQYkEUpbm7kazqTrSYbYFf6HnL8coNaHp+jrzYyMGpNKKqfXIPawU/pSMopcvMWgqtf72N4+km6+SOTTaZtgKhIYXjSH4iZWja4UVOZU5SSua9xHg9WRLDpSjeMP/wblB9bwaGmCVB8soq6iibR8o+6MFxEB7PHnoW3DScxrFYDmx//x+k70nFLqizMDZ4Emx1cSPD+BLJrUyfPCQG4e4YCjhi5hgIXu9LSRgEyHa4BY4S+ww7JgzxavgvnKUtCmYcMWMg/5pdyPaxTdYZm/14N6iuGQ+5fbciSDySpQ8I8rKGRRJoVYGjhcd7TI8Lzqy/w13mNuNDPDDb7vwK7R9NArm4b7PqC9GhHHP0pc6IKBX/e4OlDmsvf0EC2FaQYJ3BlyG30iPWD/Bc6uKF0I49flUM/tyvC9VNH0dtrBl6ZIwVdw3fw3PiPuF5an061RPOtogKaf3sRjja4j2ccBeFbXQemaiMUHFlIdRYmoDJhI/0VfoG3T/tTxXBF8FDt4s/TkQ+FzoKh9aZw33kU9Sh4U97zEAgf+ELt3x+hr1Egi5vXQviLMtqisIUkhczgtFMpZyv6Uo3dc7hc+YHVnkbxBX1BWPX6L04NPUBCEfLEJrawWXE8BMbdp5yw1+w3PBkb6nTxntkN0J3hxbO/P+CWJUgfCkfA6jc96PHvufhsU26XT2JNMSkweJhDeg7u0NYVgFI9znS4XxlEaxvI9hXAiIhuWBolAu+OS/LLZ3WUktMCxaZH0Lopk5JWTIZTEUArs5vgdKkPCOpP5o7bBqzuuoAPvorE6cmj0elWKf8nbQtLVKbCsMtlbLCxkoya70HhnCaKv3aJ14XOpnN6m+DY+Xe03EQfhkk9ItSYxGsOt5JaTxVoZDRSQNpN2Dy7HVY6aZKW+Wyqr7KGsPI0mnavHq2vxsCIm4WsZysC1gst6F1qFGTKD6DZaTnWdpIH0zsxXGC0m+pc+7m3+RIMz1/NBX9j2Dk4nssOEx9MPgOqGrYQojqOpIObiTd6caDYE0g+sYOPXF5Fvr6LuOS7Gc595M5pj63hxO8PtMaonjfIn+XB6GxesDIFLddo08kFH8F4wgne+8OBt8mowUl9Z96+7yklaerQ62nbMcJyMUrdd+Nj+g48Z20IHPxuB0mG+tBluRIF6/9l5LgtjztSwf7lOZi5fTMMvzebi1oOcKm3Ly6P0IffOiKceaUUL+3eSPvyv2HytTnomayMx4PcaIH2/4g774YQ/zaKXyMaGkRLKU0qpb1JpMjuR1JRQgsVSkoSCgkJRUOhYUTJaKASDStCIWRkJoq0tDy9i+ctfO9znfP5/HW74M2MYr55wgwcA21wl+kUNjJQxqdm3rxD9z1vXZ3JMjuuoM6Se3Bs3k+4aaEPGz6mw7U7//jE383oaTAUoW0HYFtXDL449xz/jQmAT46N4OkpCkvOv8cyCQ90uDxIt2668Plxd8B2rxyIfvdgfPqSu2fK0g5TJbjZ5g/aM03hTlcEXJ4UAyTkwGeWHYMLQSdQyD8PL35vZBF5AZB6+xts3JPgy4rTYDKhDMRmenF2WB4WfYyCgFki+NWyFAwNxsNsqXv49VAOLPkuimb6lbB90UL0mRaPxheC6NZ1K7C0jqKj2fIgHHeTYn7u4ynBLbS6L5D83wnDnq6ZaBd4l68LyLDSQSPIDJ4ACyeYgJ7DLwhMHQZvXD7x02PuFLjCG9K1Z8JL2zgyXwhQtk8IVr3pw1rPCVTY24BVN2ex4pCzfH+Xj6b7t7DtGDcaO3kC9b2RgJWf5oLqxhdo55xBu0yFuOygORsva8Dtv+7Rl1dEI2tM+NAfLSj1v4KKKQmgM+Ip/TdSjiJkXUHsvh587/pH+lWOIJY9H03/WkG7chumd9/kx3uNyH7xLUpbsZsOiFRS4sBLRN9/IKj7EoWj1CFE5TJLqMbBt70Xcc21E1xxfhQqTziMqhFC4Jx3FX5J3CO1yVPA6cFxXOEwmY449eON0YocuP0J5i23JS3WYKF58ihUkwDwzRqkNHPI4OgMeK8lwhkaVojXHdkwtI2v+L6CLSqa9P3nRV5SIAm9uBQ7v+bDnj2xdE3Gl0x+PAeFiD9kfO4JCOVdxYmu+uw2GuCSQxWFjP8M+wMDaWm9BhS0KMFetcfQtmAN7B7TCLNmlOPGvSoQZtNMLktGwser5zio0pXlX6hyQFA8ZZWUsf6fCJoTagShw4RBV2sh3sDd8LYqAarsTED+7mL4GdXKEfciIXOZOq6UU8GZ3aPhoVkCaXTcg6+vg2mD5no8s9OdTF79grZF12n/xyd0t+MEC6kPg+emI9D5mQ5MS5EGt80zYcXzRPq8VAXebRHl19Wp+J/jZopW1AfHIH/QGLSCquHqnBDaRROv3kJho3lQYeBGhqqRKLX5Nb0qGAWyF+rhavMITIpVg/QH6jh8oRo3VPWT2UUjuqC5mVekzeIt+43h65wG0Ovqwno7M1JvMWKNrrnQazGIh2IyIVpJhgIdFNkiUhoa143GsF4Tspi+DFXGBPP8mnQ4JLMKHolUgeULRbp7X5EMdgpD/rVylnzTxevme2KNzg3Mq9xHh0Xk6JupL7j0J3JxmAQERplDxOBlzrhdjQJbD4DBcVdMXbETV5+/gT//POEohZ+QZvEMAmEMaF96QQMrLVk14j90GPUW8+7rc4yGMyaIuuDrGjsWnhiClUsmQ9xTGZIdW4mWLY6QvWk0aWX64963aXxB05avu3aRj819uvDYCLYEx9GbwgHqFvhGgrtmcHRsKfn+yMMNiYcxO+YP1Xufo+fWyuDp/I0eWJWg93ZfOpcqhlHZy+FFUwEk5jliloc7ZR26zd8OSIO2921QUzmD/xlY8IY0Bepo6GUlsQzqFl3Ab44fg2ZboN3iFjApFMD5zXC2OhtCmyLuUfS2IlYd9oC1bn3GP7N14XhRPIz5pQ2j6qNY6FMZ3159Fp8sK6EH+w7ikyexEJntwzbvD6P1tRtIMcYQrneeFzxewk9195KCpxsdyDXE9htJMMJtJOgoAGNjEDoME4TN6p6QugNY6vhqHiY5GxsOf6FN1Mb/rk7FXNXP9NfgFCtdFIQFQskksc0f3K78or0G++jHgmiYIlPIx15uI/OCJLxaeRSkr4rAODdRuL1qPgvb/ePHPkZ4YvtDiHA4h5UXJTH29kyav7WRynYaQv3EaJBP2wR7+k/xy2FNVHTtKZQpdrKkkA9qC73iz6c2oOOqidB3+xWfLy+keREfeJnyZNgfGc2+l3RYXdMU1joZQsWlL3B4rTooJEfAhz4RXpNuA3cv2/PvwGV8cOx02F5cTv/W/YM+a1Wo91eDl8fU+ZjFXyxMbeVvCtdgldZuOKt4iHUqNkFSsD+2jJpK4+VFYcrfEAywCURRJzH2vRMBwZ2tONDuhn09ruybYQoHEkfDvysTQVVpH5wZvoFuTz1IFy41omOcOQiUL4DJYgtoTNFDXvomjsv1JSC+LZfTIjupYVgoh+cFwy9XXbaQ6sMxq1zRZ4gt9lq60WZZXeiZ+w+kraehlvlp3l5oT+GnACeNGkZBTy+C9IznUDmlj+m2Bpxc8Ry0tvphf6QdFBxIBG3jDaifuY8kP8hCr78X2IshjlEbDlNq/uNW09d450Y8ic7w5lfdZbyzthtXxV1A5YSnbLrnHcrm6cHX804gWn+Vv8va8/Ge/eDg0IMOrQLYfOQH3XpcTK7SX6CyjmDRvEPk3zAVjVRkSf/ABJ7tWAqC5TfRO3UT7lFPxLZpC+BAMUGPlCWkbP+Dr9VzaOdwCbwr44cJHx6gzJFmUnTJpJn14vRAwwT2DWpy/9dv9LbgL2ULisK0P1FQnBAC40iJI3X1+OB7M5I3FIRZmSvg12AT9n6VA+H2Hp57tQXGP4qHK5Pl4dCBIqjv1+fZshbgc/wnTEobYF9ne47bJAojt7SA1ydPGLskBluLA7Bu0wk2HK0OqxOAx8vHQ/H52xB7q4gVp89Gcb8+Gta7Cp+LTSGFFdmcFKoLX5paeXkTYuwRcUweqMe1xxp5oOM8T3+oAf/OnWPFSfvofqA6rDe+yTnfD4FylTFdau/B5R+lePXsRzhHrhDKDJit7uVCHImDWnQ0Rsxo55/RcbRePwVCfi+ldKNLWDttBb08cwRy39mCkJ0hrNwVDuajOykwYD68+nEGH0+q56M9LtisdJoCp3nAo64IGvdMDga8DOj2nC4Ytq8BqtYsQE1K5wTxVHgi6UC1/Ah8HF9CibkeiFmtgYlvV6FTzBlWyXkAl0/eIgHtrbwxfA+11UmT0VItXDLDEsSdDpDsNMTWblUYGVcEAn6LAfxscTL9ZsmJEVTbvwKFdabAsDvadDj2AgqL+LLVyiu0Zk0ap868Alaik/j94T1stfQL90WrQUA84sqeWlzRJUdPmxzpSOUluElOJFpcihbup6k3xY2DbYQg9rA4+m1ZTFAXDVGPZnCDUihUyKmi4xDa3nDuA+UZthgrQ9BluAWWHboPei0bOd6yG+WXC4CEayEWqiJPuPUQM8/o0fpGFXjW0cV7XLJgIOYpCZS4YIdZGIhUSKLc+T/kMfCaDgsMQhlow/zTtZwsN46VXXeC211F9vu+Dd84JXHxU13I8H/H2lJfaUaGAPyolKNbs4eTzfMVqDj2NK1fqY0p0xJgdLgJT/6eB9HiG/FQ8jjoXfWavi/fCvbubjxq/jwe8zkVX5XoYNehcixV/kMDf8/Rl4lisDJtOG2zL0DpAE90T2xFe6FOKnMYYoIFNbg14wPkDt1Nb8JoSL61Fa20VLDWVAWP+Eeh9ctPlIsENaqeQ1k8w8UP9sGqLVqwdFg4fJ/1FY/MWAUt/a4oEjOJrvjKsOfJnSx0pBEjrtrQzaBJYBP5Ez31M2nxxDTaonEL44UPsIxFJDRsKaCNfhtAetFI6CkZBiLzTTlCbS3ML4/iyOAvqDjfkAI87nFISQuWfZqESzoGadhSMxD83s50xojmKemjcH8H2ca5Q6DBdt6Uo4USG8ZBXEkEdC0bB0bTmT6t9+aaPEu63WKLP59dh3HLs0jWMYaF9CejSdhN/rVZDMzPfkOnolr4LHoL9Qpa4bxKG81XDYKUss+wtrWW5I/6kLOlJdxfXgNxo1pQOXQyv4wrxZJtjdTVWw8rd27ieL1hVBRnx06Ph8Pf94P8/nkr+o/opFllTIs6N4P67He8dq4ftP3Oh51SpXx9kiqEfhhgq9GayEF16BRagkfPZfCkH+fZ9chn6mjZjzp3LoOz31CniZ0HnYdB2O4vDUtsyyB31xf6+0AF/hY/56gjIyFs8Uu4Eq8DdWm34YutDfeoiWJ+9kcylGjB3QE7aN/Q93LclIcpqYvRe7c4/Plxmrt4Gz6S84HBuRPQR+w9Puv/TVkThLjmbSefcpkI483VIc5InMfhDhQv0qRRYS3gErINhfq6WDEoCPL6b6PH+N8o0DgMEtVjMcDlLKS6rRpitxuoZttIb0cv403ju3jzMmme0HOCzggbgVHCMriaGwIPB/xpQt9qvrOwFvZeMYHND5NQIHEib1vhj3ucrODQrUQ0/adEi2K9cbOTNEp0tfPdI7tJXbkL3vTupvEbxfDPZxkQsSihO2t70LLLlTJ1O+iDRTQdL1yM41sewqG7t7Bhz0fMuCsMpkHbSfL9DNj/chWuDYjhWcKV+E4uAm+vE8V7hoPcqHYP10uZQoHIZC7/eIKv2WfDYlUjKhaoxbNTStnS7S2kzj6M/TKbSHLncHjh2oPWokG8I/ciplw/AS9WhkPrYC2mhq+HXaOeo+awpVwbLgSj6t6h5vht5FTRwLvLyiD1wyocdeIxzOstogY7G15Rn8LZ60fAqk0/adplDzZQL6KpwciRf6eDYIYrzV4hRltmLkFtw79gckwWMoWNOXb5VWiWvwEd21Ph7uMXqO00j8P+JnBc9Q+ePLEQF0hPhnFSl2n5+hi4TC30JcmbSlamsazLR94nUsMRpXkQdmU73amRhKIZxpjR9gAsp8jRd9QEIftbfGlfH1mGn8cZbefQc+5mbG6wAndhA1ruIEH01ofd7fPI1gKoMmMfqijOh/Y72qi0vR3OLRYCwdlqdP60KCmmrEJj88O03ugV3TosSbVDLhY0cA83+cUOcaEshEkrg7eyOOp8dKPQkbFDPPKbIL0Fc+4/oU7lCpzVcR/XNwlBzN67tPhxOO6PvA0CgadR5qACGRV68RzDe2i/4wB+sg2k32+0wNN/Mr5oHgO1lxbSuNgiTt/rQjofNvGSoBLyUq7ju66LaeJhazCzFaZQG1PqNH0JjgPXqfzVbJgmdBB1Ak5Qno4Pm07IYS9dFRhMtsDEusd4pn0b+51I4JtbI+jxf0FQKznk1SjAuYbqLNykDa2l4bB5/XX2Uc/nwyExMGfnFRR2E+cN31Phtd8Ax8X9BtMDw2D3kgG4YvOV3387AKumBtLOq/lo/D4TTjTvpbeP9OlGlR3FBVj+3/7/W3XpA/9s0cebOh74YPxJvP+FMUW+jG6ZvCBZzbX4+qEmZg9YgFDCJPY6d5fbf4xBsYx8qjt4Dyc4R6OpZA64fvflp92r4MBJQxixPpQ9F78F07OKdPJzE7k/iMWPMxI4e2kSFJ/dDSWfXtKYiEkQJTeL9BLugK2tG+U6q1Pl/I1ouHokLgz+QwJBQeRn3Y4Lhk+G5o4hT2y7jgv2qZCfzk+aWdBCVusNSa7ZjYSnf4WdSy5B1Ofx4KYz5G5r82iPXBRMHbcAKiX1YIHXBXjtfxdMcs6RvHMUOD1UBreM4dCUrYw2dhng2VmDzdVrUM5oIXedyOOypK8c7G4PYXumwubJwuR5rYfCovaBU8dlag1MgoUrwtEmX5q1HihB5YUX3H5AFUIs9PjsXTVMNFeGvse2tOaMAXFdFE1YqkXvenq4KvQKHl2qB6UmDXBnxQ20aGonS6t3fNF9Df+pNCH183/4Tp4s/Nklx2MKTWHRlsfkUO1AH7ymo9hUfQxbVQHNlmIw7LUfNlnJguGLQtSo1oJNem7QqNcN/hL30OhcEmd276RlzdNx4iojKFudhxHWa3GGvTlYnNagyhW+bKHfyTEZpfBVYAUEWW+kRXP28peeB1g77xm9EraAVUvPwFOz25hodANvdvRBYrMDmGu14Y2ZY+FYzk5wMjLloyJiUN5whz66VPGHpANkO+ssXpDfzuVbFHFSrhlentvHTeUjcPFOBZALECeRd4Pg6fsPk3U+Y1jtf5Dqk0M9hm/A8/lm9NsnjRHfEQ6PKYDxn0TxVEAcx9mPJPktj/nFk2TKkDcFg/hpfK9QE0s3jQYj57M0ydUb3HuVaKDmJio/eAuJPkiOk03QdX4fyLiu4wh9ZfCP3gix1zowbXsbjRFex3XTDvKxB7XQ9FAQZy/vI+NN5WB+ThAW6ZxkF41dNHPBMDo9fS30udyDS2iMzSG3WXpqPs6/psGzZojBKM1PKKYQDTd+WZFE1H3eXb8ZZrgb0/OjO+CNZDx2XHiEdjMlwDGoFfF9BlNFM280DERxE4JelzO0TCaBb7mUUXjWKn74dThkzC6AuJ3PcKJcInxWtuAtFWNxGU+B2Ue88cn1RXTiTiNcViSQHltC8xIXQq/pE8xfuZgXTMrD+bmj6M+CGta2+okjYTzVTRKAw8OcmY+cJ99HC6AotID0Pk1hgbl78FLTQvqkoQwnnlfDnjUjITXBGDR6XOD9wCFylRJBy3HnYJ1iFTXskWVXhXHw4r421q8bDkEPBWhJyHN0rGhF0fNj+IJhKWjca6Tsrek8bVQnzRjxChbrScPexr/k3r+SCvy+QvWnStTKUITHeJEMsqvBOcSbt5aN4wqFoR2MuwwTLy6g3sWuBIq1WCCmwXOe98CM53XgnHyEpy9JpYQjlqDp74lmua84ft0a1IeR1LBkGop+DaQzaxv4xlQ7sFu5BgRDlUDD9Ci+DN4BOiGHuWisEaYcvwOfNxyHWwXddC4E2aOnlUeXjoXp27vx39IJZPH9HBpft6R9XcYw8OgJCZ6dxRGDI6mytgJUZCfD/UJbXHUzG7UFInnFZBfodimBpgO/OGCKJ6rqn4COHf/giJM8tA+xTPX3RvzyppvV0n+irXYdzVoxj1c9iGatjf+B1ANj1HkiDJu9v3Jd2nge9/sonilfSCllUeitfJznKbzlX6+fk2e9CT4oNAGbwnfgWC4CgQFt8GHPcvp56hE/2LYGbMeFgUSGMf4Y18ZyAcrwRtcely9fArWrH1L5RkfIW32Nc/EhFQwKgOqD1yT8N5sq3CfA2N5HGBMWD0caN0HYjI94KAl5xHBga2MHDgvWwCh5PxKxEIBbFxKGNliLElvv0BGZOna69YB9Pkiwh/cCuP9YBql4O96bbwx5h16z9+tUvLvemNYY6/CWD90o+iEES4RmgIm6CsiMCIB7VZpgWIK4fVoy7p0+CL9GbIX8gh/8RNWbvw2x+0qNYNKMX8kDEmOh+0khXoxx5vke5fhr3FZMPLAE4+ddpuvSctw7OxJOXuqEI4+k4UVfMcp8ccZDpwy4eOlHaG88wrahx2C2qxG7PRvP6/sMQV1BFwYr20D/3w04LaxGkW/esb1iPD+5tIguz9DjbzVdEDhYT9aNY2Dummz0HemDdXM80DQxhe/GTUNNm488KOGB6bcF+PG3Apr80Aoqw8dQ/TcVuHFzBC86X0lOsZNg2v4UqHI5xOVdzH6nDtFi5fHQ2GfMdipd/Pe4Bzt2D+NTgV5UrBtC6RuVeB7501jfnVRyehiEnvOl6mnDYG3oWpR6vBfayBr7ftbh0Wmv2FjDA2ZV/scbqgmC0v7h/Wv6QOomJHp7Oetf/ICFMwE1hSfhh6krMOXYIE5dPRm0Rrykf707wVK8iib7/ECRrmG4LNcZS/qXQXijE69szcG7gmbw8rUnVxSEgbpEAo9RKYG8zNsQom8Ls8rHw5KnAyDeIIMOy1UheakjBVdcp47zyZiROwjCgYdgk6Y/j59VB0uF9Kg0YT/2mw4Dt0hpVO5ZSuGv8mhEVizpOllAjoANHMxThfpdNXAoeAbI3dKFx9LPYHubH0wa2rWs3r28qyIYN9TqDm2dOfodO83J90zoyHhpSGktwr89nqgdoUx9Fu5QJHEG7hvexUU2i2nb+ELKOnIXi08IQNlgIvmdB3pq5gi95Uc45vcWyjk7jr48rWfvYS94Q/I/MtugCunuMrTwiR4IFDvR2BvdLOFxhjqnrKBmuel0f5Ia7yv+Bg9WqkGmpwc3GIRA+ONgsl/wiEeOSoLt896TX+53ylqtSGIS+8g6RBeG+/SzSTlxnPlfnPmhCGG0Ml/ISINzqz6AVvhRXH/wPSXMtgTPgJl0NPQM9Pj94tM3zfCZhBrP2HWd7CqPYs1bP/72rY8eyenBrvBHVNL3F46uMYQ2hTTa89YeurM0YeSETLzd68dazw1p+UMLcJ1izA+OCEOC1jMS3z6efmSWcPuWdtirXMl2wpP5wD491MlG8C+Xgp2F9WSQ95Dn7TfCvsG5MOdkKqka3CVhh924rmchv14wGVZ9XUkG2+qxxKEW6+f/QN3WAdqoGcrKXnoQpL4fhaur0bnBGMy3N5Laptk4Y6YInNAzhTM/dRFjksDdYS0ELk2iYbstcE2PIQznZozdYQLaEqkwdUsxG9r4o49HC/xbcYOOL5gJnxJEcHwTgSdYsc6nhWD9RZx8373ksxGXaP9TfYSRvuBYcg3ej+qF98fkoXphM9zWdqDqci0M/NnEOh3RuKW4EssCN6PvpSqQ7hqA80WT4aD5NZLS8GeN5McUNfiKzA48IDW7oT5Ze5Y50hnu4nVY2D0MZsu+wuaznqy9eyo8cVTkL2Od2NAthv5TPIZt4nsgdLIST7Q1g4sDy9mwvBX/G1NCMR57SOHqTV7em4T3NZLAP/wruijNYp+RcpCzzY1eOjqDtuUDiNzVBFJOyujqOxf797Vx47JzZB4rxQ4+E6DRyxQ8c4JYYa8dFTxXombtV3jB5SHb5ymSZpMHhA/bxl4r5UD00y9eVnKT0XcKmzwVhu8m/bzr93t6W9/J2yLLcVHnW7q8TgUmVyWge7ER5r91Zu3Nq3mtYxWWRPSQwT0l2qkjScG+/8G91olgTMasN2Iz+3wUwqUNfbD2kBpt/dJJNddXw3b1Dro7dGdyYspg1T8arKJN2cPemj5+ucV/PsjhXpdImuiXRvnZFtBRHI0/ZprD11I1OjjyFFXTRx5h9hgia/9CsqchTDe5weZVvVQaZs6/NIeDpIcY50b643L3UNx0URwqfcxIsuctHepB0Mj/ANrxDbwrQRA61q2Ai89us/mZVtoa8YhjGwtpha0VS3W3wNPZvpQVVA1uDsNgUVIZxeS2QmNcEe6+4YOeb4JwjvhVfnBnK8ZaOsC/S4tJwsQIfhktghdLvvEFnd88Vn4jdd9/DV8/S0GarBW5pcnQ4uWPMN9HCXb6HECVX9VUXBGAi/eb0L+aByh3IQfeRx6mjVZHMVbZF3JmqMFat1Aea/wXz6WPg7EnbsHcWkazOe58yuQd98+zIAmhUoq+IgXJZnl0qiUS141cgKYtl7A8UZWSfp7nXxXr4fXth7joxwv2apgC0+6tADPl31j0rJbH1sryh/TpuFvjHkc/bMKkFiFIeH8Uqop0wfvXBRztZURLLZz4x8EyeK2Vxfc+AHxfLsMf8Q6VCGpiR+BwOKdlxlpbb8PsyXchqeQqj4i8RHc2KoFnrSu3XVxJuWp7qLebAESngopcO76Zngupd3vg5qFCTP9kh/KBs1jZyIx9nfzxtK0i/Pe6lHPrhrbNNBE+Zf+itoIUap6Sh/+CNoHdK0HYvEyUVk6TB4f9d+GOuhiv/dVMMktiycI3H0ctV6aX5mNgSaYJCNkvx98F4+GT/TjKGivI3lVa6H50IszPyMLCP76w8qoGfL4vySNEjrJLrCGs2dXJT51uUUNbL+4VLMC/jjZ8adpWuDDuLszR2EPyvyuH/F4YonY3UvqVpeRV3Actku+pauEeiArSh60byrB4+SBXpxnjhGVyoFZ4hNb2TedMZ2nQqLqCAWUtIJLvyY5bZPAuvkNJo0rekSsPW6T2g8SPXTw8tBDNB9ZQ7bVgvLDzC9xfJMkaJ1PoVGUIr9LUAu0NaXB26UFK8dbn+R//YUlTA1UO9mNr/TP2brQm5a7D7LVnErz63Up/Og9i3acuqnY4C+8UTmPu1E6ctuY/nqKZSM2Vr9nj0wTISfYZet9EfLmrgiSNfEFt8Bat+/yBFQu3UYxIE5kqPIRoQUFQFL2LHinHQSNelb+1/YGxZbNx38IrPJUXkC0bcbJtNfhYD4dSN2DRsR0gN6uWo48o0BbXZm7IEgcNqSBYZ97DOgI3sW75OMgPzafknG8s/ewAZY9qJ/AYRQr/9tDnjYMQtXoat0l+Apehe2veEkZj22PgnOhGXiLzAB5P+wAi0x7TgchO+GHkx/qi+2jKD0kwTWE48y4IXZbIY4CKJe0Nu8ITtc2hRrsUzNPfkIq7EZ1yQAgcYmbr5RfAevx3rpD/TDZf5Mk5fDTqR3pR1usZ+O9gL+iXy0Oxrgb0m+Wi448D4D1nKdU9EyC3/IQhXtTEaSVl5B5/hA+ba8Ahiub2sYHU4abKZW8d4VFZIQQoX4JImfOUvraehv+6BnNfmYOB+wCk/5DivkUHoPRvItUoqpBO5QE+pWgAp3tH872f47iuUw7kj5WxwJ0zJLnrD512sIXvwSro9DeM1UbMg8yX+VwYeIuPC0mBhUcgycRVQsjnXsZFxZiusgFapnXQccjFzp/unNNxE54kKsPV6ALwHCiGfsnLZHMvl8b5LkXK7qFJ9dVw0MCLqj9tBqGtZvDuWzTdGXePS6Zq8rD9UtQVX01nI4VJTWIuF9mMo4icHyzXbwgVaZ2c+ESU3JcFcM+xczj2wgeWDxLnq+c8yP2+G0U5/YT0s1OhbVER/OeVDJmx/ZzUHEpec46zSPpDjvEJABO1t/Rl2WU2ihzqScOVaPZGlG66NbCtAEBWj+pQRtfizle6JJfbCLrb3/D1xwBzl2Tgl6x8knzSBR9U5pKWsheKamzH9/+F8ftdl0F1ixfMltCHx0mn8eYzJQ6L9+eBPbo0UaIf736SYF/bdXwOReF3diT6XRCAdW9jwWqSFy7bVsu28rs4UbYKek66U8DY+3BPOAtUoAyOC5nCzsuGmF/qggtiBMivVBHyqhtwTEQ/9PqYw4OgSWw0fRUKdkyBukX6PHq3M6R8PMkBOTOgz7ucI/yWUJtgFGXtGwd+f2eS+rup4P28CNrnBHPSRhVYsvABhVlsgRWlcWCt/5OUP9/CeyVGcKjaGPZEJZGLQRiPqB+ge6eug0BoJOY0WlF2zJDjXmnBmeuPYOP5sTAwkACBFI+SjwYAdtfCtyu5rLnxLRpaDMBlySb6ZroRw94ZQbqBK9zve87HjaVALEEHdTufg+8uVUwuiKAqj0vQLvIHJM8D/Mk3g0Wrn0J0TD4mrm7BPUaaGPowFNO26uGlBfv5dWctbg+XghVJW/mkewMlOjZx3Pk6yFkgBiOfJXBCj/3QJo7kmd7iqIXyoLV7GZUe3ADbJu6CR48b4clJD55sdAo2pylAj60auGZt4fsVIiBxO5v/anlw2OYASG3xAi3pQd739hXt3xTJN+VVWEjxC4dvmgpju9PggmkD6i2YyUcCrSE8q4g9miRI4slx0PkezXfl32GupjYkZVRBo/U9yq24jZsnKJDr59P8vNCLQiy3gbmGMJ/6OpGt38iApOFQhn00cN3JHHDpjuKK5SVorbkY62QLeXjhMP5+bA37DvW6nLAzrln4hR8dvMYW+7/j7te5+ODYJ6itEcSZpRfo3BqEA/qycH75BZSgsxiUypjufpJmhd+ktv9yQOrkDx5oEuKfX/Oof5cyXLGYwuJiL/iYpzk1XfBC6/Z1ePvVKZR9SfRmhxbofZ1KjVlSEFi6kt1MM7DFM572ir7G7XtHkY3yAZx9+h4qmEXRvfOjeIQhwtPPVzHP+TP63lSA5rmAPRgFa6u9KEZtIrpPnAMbtk+iNseJgEpHOErUh8NMw/meQgG4fPyCg48CabyxK69aMIDxhmdJX00QDHqSUT7enpd/F6JBnEXr5FywQucSmYwKodMxyTinpRrW/BoJiS79lOn4iHQnSpOBgDfMWBxAEgcm0okJd8lf0wDULi/l6V9U4eqsWPq3LJE1rafhwRBr1qHpaJ+1Ac7HzaW9L//C+ZmzWcRUDGxPLaFFJ8wxWs8KCiSMefWfWvIW9gCFR7IceGwm5unp4uNybbj725ZvOUbDnrMDtO5NJR+ScQC/h9LYqSrLtudcoBELceJ1E/j7ay4teRlAi2UngPL4V2z6Jx1j9ltB7X/t1CCyCn8u/Ud9fVqwv2Mv/xLpxPgzG7k+3Id82lLJ4doBatR3QS+xaRT7Wp7UnutATukdOLOrgvftrgP3MavBZZowGUmY0/7vQVzq3Qvh5e85+ZEuPLM7irU9+dhlEA7JXV0ccT4OT8uq4XnDy6Czy5/nNVVhvqosdLSeB9E9atw0rBdf7AxnAYNtZHdCmEgpimxvTqZjZyLh1RgLMHJ4AkuVOujIRMTkJms0SDkKFmtT0L3hAK0v30i3pnzkf/oSEHl6Fs14qAfOyl/oRsbQ1pjJ8MzrH6j3YSTlZS6CAv357O8nCkvmXIBuFV1SXJdG1hWEO6J20iPLOZw5YROOnVoJS8crUE6ZGsCoWH7udhQvt2aiZP5fWCxdyEkZzqhdMoUtijshu/ACr3LRhL0eszG+KZMCiqwhMtwW9nxXBPXNt2l4cAPusBnNYvsNac12E7CeP5I1w57hhqKDpCDoAPXL91HmPoSq7QhqmRtxcdQnTq5WAZdvTfCp9RoV3Enh6ZJymFWTza+WNPBzld1of7iVWwaHOHu9BYwbb4i3z8yHJ8+nQXPhKhpzEuHH/Gowrw1is53/6HTXaNAdLQEn+tup8o4ADL+pwAKneqhRJg/EtqyDrJzDFNe0BYcnNXLTN3Oo9zjOG1vmgNzzO7gjMAk2SrzHC88mgJzMOzqzIY604nLoxxwT0P/tiwWl0Rx9XgJUhUNI2buGlR1tKVVRjwNrukhhx2bYoa0EceVx2DXfkOITfsJL60k4Jl0fuzUiuOrjHvpUNhdOjzwCe8IUwD6/B0IFfOFb/D2a8PYkfm4cixvmttDcJE3+M2kSy7vdpfHdknAw/yyvEyrmurVhVKLkT5vDj9L38qO8U3MS/urKp+JtdhB6Zyqc3JwPx7cNcpF6Mtw4YwHvhaxodss82NTWhHNUMxkiX9IpAwUodtKlY7LdbJsmhdVRQdAwXQnarO/A9XuPaad+L++P74DqJICdSZPIsiIVLr+4BD/Jj+JTbqLjk++4zUSHZkfXwcSxPyknxwTCMxTozcp62D0jlAOseuFVWDqikQZ3FPqjbvkVWnfiJsx6rQ8W9V3o8/ozbMn+yb2h//HSg2dQd0sylYivgJqAERgSrQB1+0xgluULKHCVYMeHnhQVpEjzqu7hpgun0OVGK95s1+B9mEgfxiiC7KN5bPhtHPZUuaPF6zysrujBI9YdWKTRCbGaqjQqJw6Ml00FtxRZvNlhio1F5WzplEydX19AUNcGdCmbRSedldBPqBc/mhtA1itvsMmSwsMJqdgrf48VzWTopMo7VH99FJYnhKHTYAfFZ0hDtewWkPNczFLHJ+DP1KMw/vQ2yNElii7So9GSkihc1cM/NwOEKwqD/+F30PAzFbTEH0G99h9apzCCLD5FYp3pClpreowTriC4Tn/COfobML5/MY2eYEghXxZAq8k4+HnyNl9dd5HrRjugcfIIOLX9GmvFLmHY/5XTX93gHf9c6KLdYZT5uQvrn5yBrgcRmOqlBlrapuAkvpZ+ChG8LjzG9x+UUnrXdWq5dpIThfrp0Y1WsH6kBbfWZeGaOk0a0JsHFZ32YPjHnuNvxJFYajUt0mAQj37HMGgNknoTcct+Dfyu4Y2ZgWfpvnMwun9NYg64AqLjxdhM7jTQeUGQtQkEtRHxHFt1hUcf3g8H17lyivBKlL4xgp61eXLW282klCwJ0cdiaV9bM9y/VM5f1f9RQJQ42X50osSKWKheo4GvVbTQ7LEynJ6qjJI+b/CBhBdV6HWD+Ib3ZJDtRzkrq7F7vgplXPOHtK2C4CUWRusPyuBlr8/8U00Ie2unUoqsDkfsNSLvC9tgwooFcHOzLhzacQEXTZPE4dXXecmtCPg5/wJc1DSGjqCv5HLXDGoy/8MeYXNQ095M9yPtcGZVNF1Vsac1Fc08pr2UU+9MhMigUxSbrY8Thpy83maQJA5tZ8vAJjhzbh7ZL/0Kgn9vs1eBES/vFWern+MgZqQueMFWXGG4E1eZOIDQJD2qjJiBfYfvso7IWb5+ugy/fWrkquLJsM8tgLP9dvIUgyy8fl8GAIdj5731KNr9g1S+l7FwZjanF1rAqX1hKL43Daoa7Ni6LxzTjUdgh20O0aUy2l0CeCWtgY6PsIL1AqZUahFFH5qOY9vUr9CTOJz2fF2FF1ke7t//wK1GR0nuhgZczd3OohUlcLpbCULSlDj+ax/LzqrFuSqplGl+Dk44+oDUOWUY2RIEdwwd8ET/SbIYyrFf4XFUvVmCr4s2gM/bTvCW/YtfnyvA8beJ3PL9CZUXV/FhYVUaXG8A0YkfoXDhUbz6QAgyQgxhZYgeWEx6DNIB32mX22vuKgdaOleH6k/OoqjUNZghd43bLA/gjAfDYfFLczBTyYN9oyx43y1HjPV3geE5kVS5yBLOeAlzxoGzdPfKBBiU/8PzO6fCm8RSqAsVAqX5LZSaGI5rBmfxjykBFGw1mT60aoHWuSL8KacKK212wdavrzllfBcWRLpzzIUgzkmvR/NsAbQtATB18cYP03PgrLA1hKVFY53EAMdN1OGYTQ7oGGQIO7PdqXm0ArzWNgLZyL3o66OHjc9m0vwxeuCnMAF/57iinUrnkKedQAsPRTjz8iy+3HYctGdp8X5pI+pPWMgLTszBTf59uLjtIRgPtDKuUIDQS4aMUYL41csSi0wOQc1YBzL7Ywb99lOheuV2eu9zEQ9KiUOvdwXG5puh/K+HvOaCEavmaOHvHefwUdkwfKX+mC1/GND+cYKgtdeGlhr8osc7dvAhjwugsr6fzfWqoKT8CC1Y7g59ph/oibgSTJASgs0/NPig7zfMKbpHbeMEKDh4DU3teoVP1rRwqccxKP9mDCmzC9jf35RXxc2AqVlC5KS9C1QXfMMDEwRRzjUJBAsSWPKLACgc6iLnk7FkN2wxXTq0FpYPDnC6dy50346H8cJLcIP4dFaabQ1LjbfzHZ1hQ71iiCONOmjcu1ZKWzWGD43ZzZ1OAbz76E/c8VsXtDVMqS0pkgbSJ8HOYaqcopuLD/N+0x5JQdLQqoDatbe46ZIGLEmz4bJ9Hjz2zVhYN3cF3pmVyDM+hNALH3Wm6f04c9EhULMQB3uTIH6nHYRPi5ZT8vliwufZtJlb+MPJJkhd/h4uzjyG0q+sYNp+JQz9pcm7bfzAebYnfBipxvvLdrPa0qeQlWsBrUVN3D5pFBx8dRoXzj4J928k0IzDchwQXIBzJax4aq43zq6fSY4La6jRTwd+HQiDmx72WN53mAW6CNpLFlGo6DEW2rmCpyhl8jNFJ3j6VAe2uOeh97PJMCJ9KYktXMptQ9Bmpl2EkS/PoPPKq/SlO4RuxUhA2Omh9za2ANsF03HCk3wKW6xK2aHSOKNfjX9k++OuEx24NlQBSmVyKH77MLBqz8It345RVvRmCs1Wp3la7nTSOIamLMxE79u6ID2mEZ7LNLFGnR9s/DUSL+lsxNdmz0FmdBz9+uKEGQNDnn5EDtb/zOd/Y0/SDZ2/aLsjiJuMJXjC/t1UvjkUpTZqseL6qZR2RQWEWlPoZMY0uHPDl2STx1LyclcKrLoCd0Y/hRyDb6wZGYjLgobBGMdF8L1oDi5KXkN6b3rQ7pIkX20V5G8y6hR+bh9/KR3g+gfGYFJkhmVjunHM9PMovnISe15fAovdCduF3XBB59DeuZWBaxBAi1Ms+Nm5wOtRI+Gw0QY64SiDK2dl8FTrUl7u1wu33R/CaGVNCP99mZ3vRFDStUE4OPUQLhSxwHLPnbShaxHoaP+DzIOj4chJHfid3c6+Eumg8DwNwrdV0BPbMWRZF4bHz7jRGKkzcHvOKzhqNRZ2ponz46192PxBHs6GmNKFiAowOjZAp9/8APFZmXREdCZ1Xyaw1+1lkd1SdLjgE486uobPVFpStxFxn/AqjHpDkNL9BUyPKsP2vClk/NUOHoWlodjzHBSzuQbGwnk85qwiOU4bS9O1npFRsR6cq7+NocXtWHdnPe9TOsQKayM5ZZsjSU4QwzNzlCHgowE/idCB/E2rqGTkUMea9oGjZw0+f5bMu3e/5y0JMTT8ZyqLzj7OlguU4c+88CFOkyH7ad6o2jgL/hjUYLPOd5Jf+hKW9nyCyyoNpDDEG2N0zDjgxWk6+Z8UWDv4gUxFKIwZ2v48n0xsFBfDr1kbcI6XCUz9NJw+f6inJ86t2KBrQs/T/8J+xViqzjwKoZWhfCz0Go3dPxyuqu/h5u4xHPxDjvf/CeF/qg440ecnb82rB88XW3GzrRBc3SsFJ5fewcTV0nw4aAUphubSh8Kp0B6oxDwvkq/bPOfZt6K4ZKUkfMqogrM/voLbm4Pc6j8B3r3/yItKi2FhgDNbzvSlTI1NkGVrDkKu6/Gs9mPa9mILqok3sd6kAj7wbCeQfxK9Hd+PrUlRLHTKChKE7uLDWWqw8NMIsn20Fn84Zw75+hYW+u8xB7tG4i3fk+gSrAKh6v94xX934OL8DVB4eAO/Y29IHqjmH31LcMS+YtygvokezdQBIzcfyBxczKXN+2lHoT5KTSUO9XSHVzYLhniuAZOW1WOaogQox4ZC/JI4fL7nG4i1uNJK1Q5oflnJG6sf8doJS3DaQSPKLJaHcc/iyNp7HU9JfQPpY1NpRXom7ZyylV2mfcSfCoOgaNlAJ2q0IfjXexqneBPL5r2iGQISlKdxGM9F1HHNsiby/2FGBc6foV9ECaxv26DjTSne1fuVk7MBHguZY+jp8RReeRqFy+OhdEMIJNibQVP0LkoV8uDhco188YwhjPVQxvyKEXQ8dAm+3W7OCa8KOHcngtgjN/xhN4tWb5jHbyo7KFtpP+w5sBbeJy8hR7UTVPO2D536JaF/TjCGnV3J606fIzktCQifEo22h/K426cYJlWn4W4BFdivPAE2/B2AiYILUPjfS7L5rxwrvmdhsoYb6Q9bzMU/n9H051m0XVoMBJWX4fqPV0DLbhOpv4ojdZl7FLvaHny/nEEdB3da+C+Sv4cpw/3pstwxsw6tnlwEm+TN/N91X2hK2QhBR2Mo9ddDlD89mkR+jYZkORU2+5PEdpezsFXhC6cL6uBeMTeyVLlEyuPCICjLmqP6BCCn2YZENmyhzyvjMWCVEPf8h5S79R1ev2iAdiEE14964MKQkVByOZkub6pEl2nT8FlQKpdWd8AOPytWvfINiuYFQc6/rbw8ajTcmryKRkrlcOJec6x1/wtrxhynPzqDJPj5AO8LfIG14l3slSsOV85p06HQ03T43Hu6X26EC7elYkrEP5g6Wo7ObPmF6+7uhvMCSqAWHsT7pMzAvuQS+S4hGCj9hOLFgVBJ8/CTzRuuq2/mXDMFOLjlInDxDYz6fIX6Yr5j7bx0HrTLoEtBseSxN4u6Z1nQ3mJNSFypA/fGH4X97udJbasNrFuQitnxGThOeA2kbh6Pbpey4E21HNiqLOZhGRfJYUksXFwySErLFpCV/2pa03mIbBpG4MvYIXfdrQuLNQSodaMdP3hmwmMth/JZXo/vG3R51bVIyFIqYuGCYpaOZNi7fDQ+nnIf4p/P5niF82zy4zBkiCVBbeoTEOhu5r8lT7mrwhoCLqvTsqJWPtlhBx1rx+PlGsIrJ4fBpvtVNE36EF7vDCFN/UkwUVsIDVOzuLT2McYv0aVrEUc49NcVHtmiTm75z7H47TGy9GAYaRRAKqJ/MeubIm41WcMLvcpZue4pbBzew89z/kBf8AbM3DEarol1Adxoo7y3ZbjtWRF3ZifD0iwF9jyygef0X+CoXSGgMEMb6FMWyrm0Y3meHL2/bIznbURAT0SeN7mKkHbVbnixfRGcdJYA9UNbsXVyEnbESgHt2kNpS7Xh4ayjKJ5TwY89IlFw0zaOdtIG0R4XCM1+T+L/FHD3t1+kX7CV7R7r0xOZmZQn0AwHcoOppWQ4XDPxRpeJkTzYHIxn/7VTQUg3T9ofClkpeuBUJsfBgQk8OE0Hljfep3Oza/CfayFpuj3iyLc+EBd4DG5dvojWT9Rorv0F9k5Uh1XJ4+DUsgVc3TUP5LstSapqPnQUb+PGfFfujhzAEt1KDHAzhpqsMK6aX0Tl4zXR3eYmpxk5sF63Mpo4DXXe2XqUdComj7yJIOA6D67aT6Wi1K/sk66IH0ZkwstHM/izgBA6u5txvuF0enZtAtytKGSsnAyfF6RDzZ19JOReiGtkS1CLd8KaIVdfkVBOR0OGAz+0IhljE1j0sZm1hJ/xttfCfChYGYTP/qbxtpms8mwOpehZgN/xPBJoMwPRX4oke6wU2/Vn0e1za/HxpIs8f9l9ujLjFH61MwbLiOF8x+sPXDgZwjYL2qnW8RY/ytSFJ2/LsU+0lpu83vA4c23Y0lZDFsGN3BdoN9T3Bzg33wrtfO+Sc/s52u8XChPFpqHbXF34/fAujp1wg0POdHKryFS6xLNpdNUO/FO8HbsKx8FMkZNwqFoKsHkrFw+0wo2DJpy7fRNIWbzhr+YbMc75N0QIq8KWqxqQNncyzP/SQYf1ZKHC4DcrT0zD9Z2ZuLW3nlP2eIFxnSjE5H6jKXsU4W2wPzjTe5ijGUpbBbMhruobVtZ2wt5LgrRknim5D/lX5Xcj0Jv4l36Y2WB10zB+vXATLY8ZTm0ST2BVig1mherS3V8BvC1IHQRDgT9dleFE7U6oCdsDGS5dED52HC3PMcDmTyaQc16OEsdMhM//FvHfRzHkW9POw+bb0emrE/B73gqS/nQbj9rewjlrdEjVSw7GGVphRXvTEM/aQ2v1SEwRaQWvmLvcNG4ipJsIotCAA/Rf1oPvw4PYOfUfLWy7xF3DzFi/04q27cwBsa5C8nC/BFUnsijbTgzy+5qwvywEl8VUAIp0Qf8VLbq/2ZLeakylZ7GDOLyZKaZUAO4flaOIUmXWbQByTVuEByePpxmCtvjgWAfKPWqhjM6p+PwMQr5DDLrbZmDN9wAc36cOPyb5c7CYAH8Z3Qiy7tfQyXIKDJtkBRbbZOhptBSH/xKkI4t2sHrxOb7/rXso79fo3tpMCj56l9eZyQLtNcbDe/2gLO0+Kyl30t85T8D4w3o4plvKg9rEyXM2sayHPEw+6YU+1p348OBWfvG8BXS2feCOllh+8CKLrp8y4TUiSvxCSBDMYlWgPSAcJDzk8I9XHhfeToDIO8L4Y0Q9ipU8wxxpC5TeJg/nNObi3IlHeNOPXNS+MY2WlVzC2vuefMHgDoXk1fDgluUwW1cCeuss8e3mQ/ThhDPPctlHtsIitH/DkKvdYTj/2xEiSnu5NGw8qH1x5X7HNDhrXAJfUmfh1dsxeDoniIJvesPL/rlkmd8NFx0EgLYlwYisaDTPugleP15Ayyp7TstbAO0HNGBR5RceW9cLFdEGsObWOvzDSvj4428OlvdA+3ePIf97LvdIpcDCQ/u5fvUu+q4lC7+PZFPZ2g785xw4xPgGdO1dNNU9S2Dh7dNoXl4GTEv3YGktEZiomU87v6Wwg1kBPhSbgJI3kvH9gxW0dnwS3RwdjNvKH/FZWQABwSaIvIRs+SeT9fcUgv/VEEhZZABbp1SBhog7eEt+BCc1CbgiWQQvxj8mC/uHqLIvGa8cSUAqr+DrTuVo2HcF5x0YpJBCc3jqIscxqd1UHOpC6+uiaVXcOrZXKIXorYeRfumyQdk+MHGzgPvdvdx+soDaDjuy/tKxbC37lo33FOL5MYbwbaotP5n+jinUFKLMp6J1Qg/UHPOlcQub6PembXSyyItT7O7xnvKdZCr9H7m3j4eQNxew8lUeFml9Y+kpG0jNbz46zpOBrKwDPN/Bnk5vXc2WAxJwdqQddY8SZBGTWlah1aRyT4H/C17O6fP9UKlmHbUufMDrVk0C4Rof6LpuB/ubbHnx77E4xlga1zzYBlpnt2Om1hbOj8+khM+TAXcFYcslHzqgvwM2DvXFGD9H/h8F5xkP1N+G8XuYWRUZCVmhjIQiEpJ2pKKdUSSJEErZRYlEkgZpaBj/UomGhkJlVrIqSVtJpSjk8bw8L87n8zvn3Pd1fb9vzuS5/tRcpI7P1FtwWnsmSXurQXT0DtxjtBNj1eZS7Ew77DbJZEPxHNjS1o/jZhSBwWN3UuxQhuZBCSyZUAz6N+9TBorw31l/IUn5AfgNJsHB3wvo3ZRI0JSWhPX5b7l2+zWM/HWKk1YWgU15LvhdH3rXkyfivvMiMMtnLPxq0IRl0QAZNw+TqMMO9IjQ4+ylLbzkjTyXT87BLLWLGP83hbQSJsN3zUuECaHobJQKA9nTQVq9FJaKPYGPSyXBeuxxurj1N8wqUICthUfBd7cQv+jWpgzlNk4OnUnqb/NY9ulW8p/xnkVvZKBnujSMPzCGW330kRybeaeEGl/QdIevtcJQ8+M9zbBtIg8DX/S+OwrObwqDkVJxtPNICes19IH0/SqYqtXAKUddsLJnJj3c9YF8/AxA5pkrf+5dAl9FTtDg6EjweSnArbnTyXj4fVLybMUOlW2U/XIMPM2Rx8Ef6Xj5yXN2KTMEm8TFELw0GKz9HHhP1xrO+28ErI0Qh1i5aHxVNIlm6y0moSHvuT9Slp6tmMBH3O7xsY2adMdtFVY0iEN+7QPsM3PmiIp83jriCiz7p4oXL9jy4v9uwxpFLzwsPJTF9ubQ0bqIVpe2sdi5dA53OM884EqKShowapIqRvlsoMfR16jIyBCE/mXS/fXbcLSyNEs90OKSP0tgINCcr5YBLxGehAEhP/HTBBkw65Dh47tU6MkIFcJEOT6KgvjM+hP3lxZRoGMVSzkH88lfU2C4M7JF8nNubreDjYGubHB0AmralMKd+dbw8TvSnxB/NILpcA2n8ufQtywc9R/OLZwIOZojsS66Em5GFvKPRHOKXhzA/zWpg9yD3Wy0Zit9XshD/uXDP7IzMOOgHP2jKHQ9F8xidrG02k8Qzh1/RNfVX1P901cg/LOYCgYtKeaZJB3OVyQ/pQV0OeI2pioDvHsizx8TMuDQvynQYHqaNv/ewm6Ry+HZQyEymbAfk1/YUNMOZdj6PgHWjZ2IA+sdYHVHCp8d6qzomwHsfuIzqwx2UUiwHGTVykDGBHsKPLcMdh9ZgZ4at/nsqqlkurKA2x6V4pI5TpAQ8h2fXVOHBzOS2O/lB5j1ZgxZTcqCVZ4GnD/rPG1wD6ZlW7Upfd8vFABVEFwQiIf3/WG7nSYs2/2FsnWiAeWGeOC/BrhxYw7+SdjM87dIgZb7FK5csB8nn3xDArvO4uScGn4kbsCr0/7A75Qf9KLuJogMOfs8x3gMl0lB8dxAPPrdBE+W7IZNswTglupj+LhNDX0ip2LqQoIu7UK4kHcdPKOfUM9mNdackIlit61pWWIpDvvRTh5i38EZzKBZpwhm5y7jSbkFLCuhRoum/IbGb0EweCUP7FPeo3ezMR9frQ1jd90kfYu7bKH2mx8kluGxi35QvzUDPUYk4LRbETTnSzje85eCGyWL0TRoKkm5JkGpxH1aFfmaf/bvGXK5Rr5yY+yQl/Vz8jd1WDajHM/EjsXiHds5z16Kp4qMw6YrolwR/w5SJq7Gmo/n+PFXJWDxZxgQEwVHSx/T5PYV5C6gC925S2GUkBX8Gr+WhxlF8C1BbTiX5stVx1+jUW82nc8YhGUP33CIew2Ejd5Fm3QFaNqqDfz+kTTMbWihbzb1OCPpDrwRyoEdnefgRrQ+lqw9hM89zrGYjCZZCBKYrMjDUaeGs29QAOk1daLlXTWa2ZEE1c4+8KLsO2y7+4sO9QlB27UsNhxWy8lKgax/ZiPuGxjE7jsVGL9Yg/lRIKd2jUDRCAl47Z2FAnn9ZFm4HzYJjYOFaIk7v0ynUfVzOey5M4i0DpJqiDTUWh2BWx/aOD7Wneb2O+LPuKn0zHk0ZJo/R/W6YtZ+4EAaG8bA9e1h9M7/CJ2ztwb9wKf83EKFthifxFUbeujF7tusEqhBaaUiYG99mTJPXgSPEQ484NlGPVZX6FP4GlD4NJ3F1zly+bV82uZtBooeopSZW07Jwb/pSFsN3r1YRRF333PHwE2u1/TDpxcFOfedFth8vMo6Am9Z5tNL7l/UySuF7WF4uR/GnHDhOrUe8PmkhgqZovCJrVnruBCaVO7k1GP95HzyLLrenYfxyWF8YN5dchrzl6NPjID/gv+DR8cicfsoP9gQeQd7i35xaWQtxptvA1uBkfA5JANe3peHssk3qajQBya9KaPLkzZw73M52qM7gvTlNCn32QJ+Z2pP0+5IgbJdHX45modP1p8io08xtJYNeZzxARBWO4zCHSd5ctULnO1lAnqGrTTxJqL+lP94/SN7vmShjEW76lFa1BJ/7ZKCkHWv0bUBQX+WOB17Ngvv8S+saq0nk7kL+eP6Mm7ZZUXpXtU0cuAW/JmsDUJnp6O4tSROzBqHV6OeQ//QdYSaIhUnd/Mt/xmsu+Q/Vpo9HtabhcC6O5nQpTWHPAb30uFhu/FmQjaNTk+D9qJnsGFobhdsU4Cdnmp4xFgbNW6Pxdu6i9kjvI3LF2SwzNQ8bv9yGrPWfmcNBYThBVXYEd2K6w4exaWVP8D/nyv6Xj1Omw/rolDAFtb/cxyrhQXA+0IFnBnK1Vc7dWDCjq8gXLeW8oNt0fByJ4/Y7AefmjLB0UYf4lxDccL0CyzS84cHtBL5ffE7/rF+PZrfvUeD/93D8a+i4dteRXB1DwKT2k949pQh5j7ZBY81JrCb0BUw2TQL025148dnl6GyQgBCIzpoX6cNuO7+wP8kt6NI7Tvau+wULg6qARUyQ5MNAuikqQGrXrSwt5cayw4epJjRPvy+7j+40OmL2XraeCz0Ot96OQoHVxvABQcBklYUZUv7PN6QHUE1H0Po005lCpXIhLmfJaluuTDNvqYGW6PFaHvsAGotD8fmg8YoZt0M63tqMdC/BLYvN4Gog/K0QlUTZgwxQY6tK4k4G3LsFVXYHpfKud9/0xcNGTJILKeJpnvgtIgM/MzuYZ/0MvCwDqDLsR/wirwy5so7ku2UKpy5SpH8jwVzh/c4mChezpftW6l9ejkGuc7mnXsW4UWBVHCuc6cve91RKMQLrV20YYaTLiYJPuY6zkft6YgRloEwdZY4V3mZ87SNZ6hf7gCuvjMBKjKL6RWY09r6APLr6uCnS66hNJmDf9tq2nPWBWmlK25dog27ZJdAz3p1VIyugGUPpuCosh9caxiKhc3RWF61gsVMWsB4rBBMS3GES+XbydKwhBcv+8XtcbasXlxNia/kyOzzVfRPPIgpxYaw6pQ+zq7YR4NCblhtcJWNVp5GsYPLqePaNowSPk1dTRbo2SQMjfvsSLFSBeNGL8OMgkrcfW0UmXcqw49bYlTW+p33lBWQa7kmlKWehGJlVZy0axHU1jdT785wzHb044DpGyDgegx2/RnJZepyIHDpAqyuaKFbbp+hWvcCLbdmHGm9C73jTuLR5Z/5bHgF7pU2htZ4ZWz+sANvf5lDGl/6IV5pKv3VnEOhW9+wr+Vvmj76Ma3VNIIX7Tvxg9pt/NbxB1K6tbhR6TJ3HS/D9qNN3NfUASVVm/naX1kQtzTnK65T+LfE0iE29+GrSef5g8RsyDEuh4YZmvj67CToQDH4R4V80lGMMjyuk13GVQ518mOdvnxqtPSE6ak3sevDYbxxZjL825IFDqoy5CiagyvsBGDhLkfIT+9lVfqNnbpAhZn7WSZLByLe7cWMG2u5XVkTRepNaG7xWFxQnk7bDhuTxr97nDM+Al4fNwf5DhMwG9VH1lnXyX51Mu5fpA+Xp7TS3AmADsvqeF6uIgVHT4WfYmNY+toCdNtQw6ljgfM7xUBb1AiiLN0weGQOPzFthWu5xtB9Rg7ky0xJNXITj1cW5E2C72hRaQedO3UO6nb85ueD60ggfhSs7xyPEhqnadcYRl3bPbBoeiGssHgLky8L8t1JI2n5awXy+SsBSdf/o6QZa9jbaT6l1ZRD074SfmsUBl3CJtBZHkAZ7xR4QGIsODtG0Pgt1/CXqg8Kza1hrfYhxlLOJu7MJL0px3i4vj8tDCQY/PGTl6mJQtKK+ZA55S09jsyD+cajaJlYL4i5JNDUMza4O0kAkvNOc5KgLzfcHQ3iK15CxIt6Ehk/nRZJh7KlXAl0X/uDHa9FoTzblgcTQlDb/SrYNjnAsgQp3vHnGy70vA2L6sO4Ou8sH4lWhN9qK/HCk1yKOb8RdWyYgv+d4EXeNyh+riAFiR6C2r1b0K7GEqqGui/JWJL1ZFOgvuECfu57CrW5mWBbuI0H3bfBJ219OvVNB9aOkCC5vnqY33IAbsXvxUXDp6FWWiXkFN+hOy7q7HzgMv23cip4L4zh7Z9/U+HBHjwKlRRkPIu8m3L4ufk6vEgjUfH5Ah4jIgY/tCVwcMs/fPb3Np4RtWZ7Cw2Y3k3s6FFPr1tj6LOQP9ipqoDw0Xa0yn9O6Ye7MG6vCPV830GBP6aTxL6VNDaxmbc+z+WS2JGw3EgId288DH77wmnq3aX0eb01Li7PR/mpbTgYvZy+/zCHDfYW8P3mL9inL8Zmo2eCdP8XuOH+gBshE4KDSqDtQjyJtMjwe20T0FF15XqVaJYd8pLuf3vxnKoblOb7QuXNeVQc1Q7jJq+H3OuysLEzmR/Vj6Aefy2yNhsHXyTm4mXNbTA/fjVs8PJG4xYXDvklAu+0XWhiKmFYQD5ZRe7CB/oXqV6uET4dN6U6VzVcjSHY7TQczJbL8kSX0Rg2ZwT+Ky9iPdtHnCn6hA60OlBjqSP9UO+Bpix1kFXo492OXnRCUYnpxBdeUjgWjzevwVv3TvOwvtG8su8tL36lCx59w+GOQiFOFLKBU31arDahH3Yd8qYg+z6eY7kNdS61UKSlCDScaOFJk7/DcHkVehNQA/K3f9LA4ysMMX6wGOezubsyCI4whAvjBLB4xDNYV7WJO3/EYltzONllvaFLsaqgk7iBLPyqyZJ0QW3JY3KVL4WuVFWcddIbsvfKclqzJBjmNtLmMF8srptL5cnioNZpi2sDn3FR0kPeEbuINMY/Ig/BGNY/WgOb90SBZORf6FkrCs+ehqLS10x0eYJYeSCYFLJ96efBSj7pJ0GzjRJ5dZcJh2XJwK/rF9kteDx+zx5GYhEfaWpoNO1N8iEpkVr6tb8N405oomU/wwVbXdza/xfdq+zpWEASbilUgO6bt3n/iR7odU2A0c3ykJCjBFt1b9Ec2zm0f0U17xVeSn8396GcvQp3fNPnwLFr6P7zNbRjuRxknGrlmnk3eMuneLK9HY5vDBfhM+drcERoGJ7TKASr8EbY1WgCImMiKf/AFKhYPYKPFYnAibeXoU5gNH6V7MYp5+dwUG4Tj3uhDSUucym5t5OkdieDsdgs3H/VfMhnHSlLxh6M3DdS/H/bcE2wGZwyew5z9uxmTD3Itxr6yUfNnu/5rEJV3xO4VHYelPVV0ek1DEv/DgL2PSXnlu24vywdAsW20Hip3fTQRZrC30uy+3Vr/kzyYHlKDydta6O7ds4wzjoDCwP6+UHhcqAT7+jZw1aeUDeKrzsogqL5OvDP3UC+C03odGMy2b98TQ129zn/lxJPexiNDedn4YN7JmBzL4bGFHiwb8sWLomeRps+JuDJaUl0Xs+QE48F4hNzY6iWFgYHzxhOrbVH4W6C+vEWbLHpHXf0VqKdUhqr8HC4P6aclxaKgvecj3Asth307t+nglFhIFPmgo27/2LLiunQKXoZbyUV0+NpI8F91XLeIDUTn0rr83LlVn5R0EtPjYI5zXkqfTlbAmfS/3HSbn2wWbkZVYx+0hOPZvzcb8p6TikwWd6M54jMpNBpw/iJaj+/8hoJXzftgfn1GXQ1+BhOV9gDI2XzqPmNGiyZI4FbtWMwtXYyxFUYwhtDQR4mGg0xzw/CzbGF+N3nOCQqMssH/sbWtaV0WbsET7zXgrZbZjxWM5RXah3jgb1duKzpCVbquOI4uRW46s9Unibhg7kw1HcghCRfhgv/9aGJ2w36JjyImw1+4ddUK7ZTGc/xd/pg1CcBiIyaAYet9dgjTwBraqfziKvL2PeqHQ98ioIvb6wg4UUcaT+QAX0rMVB/OQLCdv1gu3uaaNvzCK+KxkJU+gVO6JYlqchA9JskCFc813LirfUw8mIvb8rOhKDqZJDbN4flHf7CczVp1pWIojOJQtD77QBlZMXyU3c9/tb7m3zCDkC15B9c4pmEjxbXgU6lGExJloeAYYLo9MUEPiz7CR9EHNg14BB9U6xF7bSNFLLFisqSf8BPFQuoLWnnDQUnqNi9jjblvyC5b6s43aMZejqMedneGXy25Qz9qRwFlhIRYK3mA9PlzlHTQmVu89xFQpJOuOJjAPfYjcOxa7ei+AgT2Cg+HvuUIqitcB7NG1dFx467wf5/R0BHJYaCc13gi8tNHnneHBSUBShtjzQXLrTmCe/MaLKVHi6658raM2Lgkctc3Hsljr9O1wYnd1eavNCfZsrsgLqPFjDzuwwUdF3i68+Gut7jAgVPc4Cys6JwVzkA8sRMWVBwFzzVmwluhyqoZ68hy+55iyWbq/hGpA7f5xHwbrUvJxX2Dd17CkwWS+Aw66V8JPAI3bzjjwKXvUCw4BIXBAiBhlMFWL+xZv2x1mR0x5XFhjdB+eKVXDP6MZ7NN2I+nINnkzVhn5MWvvCshG+/HuJkfxlWL4mgfXslYOr0aNJZ95ZW7PlN168MAxfRbtj5q41kLs7gmXb+bLxdlEvgBooGjeRwvxQ0vWtFeyfow7A3lnDW7Q+OPWcC09PfwSVZc474I0vVP2RI98tI3D48lcJmqEDUYAYM1JfxVrNB4IJ50HzYaIi1j4CJvTflmhE+q8nFVZ9EYEfhSjxevRdDj62gtYrKbPrrNSXtItY4vRly7zwlzciVVF4+Bk4c7cfnLRF0f9xhXFvZDuJHbWCK5wmKjt+N55Oi2GX9G7AbNh7urV4BtxwD4XvlEUreuBy6VFPov46kIS99gW7wAcfaxfKS18aATuq4rncEnnsyGfR/hJLS+58gOD+YGhqngoz5Znp76hIHXFCF4tqveLpQB5Mb5uMnSXUa23UJD4h64SnplWgwdA6pvao0oCoOwc96cYXgFPixyhQn/66D6x7+dHv6J5KQV8OsHmPY9eICmSXogdHgBHw4qQEbf1Sj+OBjuNI1AZZsf4WJDQ3wOqwe8uNL0a1AFnSORfHuuD2041YAwB4JXL30CR9UTsD42KFd27qOE8uZtscowL2okXjKoh6T9ENgZ0kO/if/CTe920XLFfug/Ygn0qgzpL9NEY5HicJHuSxe7p1HcRUnIFZ5BnWX1EPQ/NN0Y3Av7BtnjDFPVSFOWQMKI/aiYP48nJ+TyuclmvGE5l+Q/+ZEqQYNOEZ5Gg6OHwXPD3yE1AE3Xj5UJhkTNuHvq+bcZ7CS/yz+Rlv3DrnhE0aPJwjHvZ8MddZBujQ3mWLUS/iG+iD7397MRUH1tKrOjIq3bobhF4Th/Q8Ban8tgZEnnaD87Vhu3HiAqxxsQHTdUv7kfBj+9pznUSmyEJ+jiZfN9XmKoT7PCl4Oj1Nj2WKaDC/79oA9IiNoxx1V9OxXBIHxhfRigSAGKsVTzlyg9eL9IL86FsJejGb1Pi1aXfKEF6tbQIFiIJzWVkdv0cvwY18lnNp4Dw8rqLLZ3F6KL1tJ1Y9teUv5cLCLCoWNa4NpeO4/qJg5En52CvL97/a4bbYDw8QeXralj7S61WCtoj1v1jGE6tKDsCW8cOicCWjTZ4WvZpbAOMe3bJfxBazeMzS+9YULlb/hauYXjJljAH8GUvjDMi/wC5DmMAEt2KxnSUf/jQYX9zJqzZaGyql+qPRIlG33TUPVWYtY1zKZPyhNJ3efAbrQLgDjl63nw00DYDmNYXvHFZ527yBHyl1HmhDO5Z5PsC2gDOd7DIcaG+YZk/rgdZkPaFfLsNfzQnbvNIE/WEuvdb+jmYIHv9fQg9rJHpg6tYp2C7tQ23VlyJIbDt8NnLBuXwWEf/gCCddjyDtvClQX9+Js8Wo6YeQIo4t2kpKFCY6ec5QOiVvg63AX9nY25MIWeVhdbMnXX7fDpNlv4bT3RtJTCYTK0F0keNGQ5pwUg/drxGC9rTrMKx2NITuestEJQdj2LRBFpDMw5P1v4A9nOSw9nC/OSKHX6zXBKGocn3/Qxr+DlxBZ/IX503U46cISGBWUConbuyAsdxpKzjSBm4IxmDYjlerTPvGmRDls8trJfWPMoSUqhlQfeXDeIg+SOzkRLi6UwE1Cs2n8BQecalAGWfZuJCF9idQUJbGg0Ax/LrhEl7UI8t9N4XyBhSBbvxZeFPuw19lbLKcQiCEqL1kjSBbmxuWCQaUALElSIfe902F0ThgpzZHFD6VJNMJ9I5SlDy3G52Z+n3kI9y9Uh33qhnAjUp6nSInwkVXX+F1SK5kL6qF/02F0qlnOEoJHaeGc6SBT0McFJtIU2OIHJffmgrv3EX6VvoY7RW6w1cVgdPItpsm7J4C6hBq8TZEioW5JvuXnxapxEZjXLcHLd56k+QcySUYlgvZGG8PXbhPyUnEiT+Gx/PVsPmwZvZiv7hmOm0rvo3ZgOoavymevrlGwv7WcjZV7UHfOafQdJ0zt1lYcYHYJlA2GOGhdLX2Zex7qbljA4qy98PaVDFv5VmLstCbg8NdcmDKWakKOU8p+K+j3CmSlSFVo8AhFWVMnavTKhQ0utTSoOJ/Gl5WTUWIgrckr4J2HX4GzxmRYUHwJO/8SnIurIPz8mD8YZcHnO9dogkwGJAwcJKnrBzjUUw6kXWNZW0EPZR9LwMmYnfy8vRLpehS/VAqm6qfrqDXvMfyXOQ4yT3RB1B9NWhvuh/7P9FhykhKuBxeC5a2YvLgc9K6Y0PZfqpC78hk/MkjmvCXmKO5mwvtNlvDXOx5UO8ccujsTyf75CfzcO8Rho9/AQFciW//3iaUqr8LbhzEkv6gdXpwAFihdCc3Nm8HZ1xLu/dhD8fvKwd/tEp2BT9CwSJCia3fBw5Qe1vVfg3c/mdC2gOlgMyS7lQ/MWeLaZLZeGA5FvzrpZZIWmrfKAiQfI6Epv2DHLxkIGt/Cd/4E0SFrO7Buvo0Jw7dBkv5+EE48x9mOi3Fz9QJyWy8Jc+2/0tu+s9BVcwX7W9s44lgyKoecwobxZpBcEEYFI3eje7U6iG16DzsvTiBt/zT8fK6OZH8M8eHxrex8WQx77A/wIauzsNFbE45nx2CPWyx5XDTi0ugMOLhIn4TMveF2A6HjczfY03cUGvzEIaXNh974h9CDwTTmJTY8ZcU5NBypTtfXTsHPu8OoaqIqO743gjF2+Rj/6wS6WeqhTVIcKRhm0YUzgyhbjvgx+A7qI9KYtglAaW9Q32EMdQ3GoNDcOIy//Ylzvuwkg2x3Pv9UmR9IbWRvESG43nONmuJ+sYzlEbCQmospH0ShRPEvjdaTAo+1vViSfwFlJxqAttcH2iadznIjPaB75xJ6O8saNlY9o4Z/ASBS8hJnxUlThBuD2Nl0mhrfAYa3q0jHtIO2zwgCQcNuLPQMxxF/NfDDqjFUtV0Byndp4JZbFmi4Xwl0dnSgXlUj5uQvhLRZfzBW6SJs1D6LfxqHw60kcRqv6IhXVl/Fw2EhrBvexLb5SXwgcj+EHFgM7W8nY95XbYh8s4tua9jByxv3yc8ZqDlhCohX+ZNfwAos+umLazLfg13eCLDfkEYDwV/ohuImDpTuJVVnSegaNh/aF12h/6qySHJFFjip60NNcgr9Gb+c7iwYJME3x3ix3Ug+HzadL94WAA9POdq0vQenXDWFkY9SYW9NIHeYS8P0d6twV4sW9V1bT/GHVMg49Qvk9huh+2Ex6Pf/R95DHmNw4CAbafrxicF57KUlioJSjrjFUhHaPp/HnGATGH/Bi5ql5oBTfg2WWP7AlWnCXPBtH334sxtWB/1gn6Z6yHPRhSlJh7kwYh2oaPzg9tGOfHW7E1ldraOn9l2YKmMBf7v+YqLZJIipHgsx4/7Sz8bJqK6QDZv3DHWC+nXcf8YeVq9/CloGN/iJwDCoCQyn6/aCIBcwCh1tE/jmxbGssVCE4r5thW+DI+DpOSOSmzce+toa6T/V0dyWVUs5A8+4TiqDzWLGkt+8kdw6/RBe3bSW/FcKwAKnSLjowJhxyYI3dc9F+SVZsLRhCzs/1GIDTsMn7a742FsAtt14jQ8rjUD70DC84f2TnNbOR99WH+xq/E2TMtOhRykC9RVU4bXoGNIMVcUbuUYce3chhefOhtDo89w+7hLHTs4jr3cBIOo7CiSPiHDlhjGY8OsJHZqYAuo263mHow17rzqOyoomWLjtLYnflgfF8YEc6zATa0Wa2GbhM5K+I0GHMyfQ1S8bSFughnd8m0H/TCeBofJhWLE9jmdPO8zDNolScZAZiIzMhmHffuMNpzn0zi0O6+VVoEzPEJ72nyWvW/U4zXwEBHyS4DnFdym15jxmmtWwuKoIhTubw0jp2xSTP4K3m+zBm/s/UkStGey0Ww+VIXWouXgFNz4OhnpNJRiTsRH/dswCq+hAHP5+DsYZiwId7iRzD1k8/34SbC2OIPEsXdh+MokuHZnI/pduklKUEpY9coTNFQK0dHYoLluZjL0xc0nXH0FX9AQ4qLry54GzYDN2ObTfGQlQ9Iz6F5lwofFH+HpGF1avUgX5v5e5Jc4OFD5246c4FWpZYgGHQwP5SUEPk9sxOKcgziudpoC0dCNNkeyBVftqadR2BbzqMAX+bhjquosZrPLsDb4wfgwlazUgwLMNN04Wgs8zR6NaQCOUx77my01r4GGLGE5T6WL5hfZ8e4QZ3L3QD+np1qz8IAtmODtjnv9akAo5gKvPBeOkpxNA8Ow8eDlJCT7rlkK6bQ9Ueg3w6gAh3iC2Ed95zOSIEc8g43w67kvtwu8XpUHSZikvKl8F5nqnUbjmAP4rWYEPY8I4dM13nqj/GdS2TMCrQz2z4msmlG0uwuBN+rj3w278vTSZohSjKCxkOw8WCmFtpSoXumpBULgj7FSYwKlpBVDgpU0JaiJU23mY5fMDcfdRLSi7uQA7z5iC6YoWSnD8BgZ/D8K/h0kQqDaAJ27s5uOqxqDRoUn3c3fSwfnSELo0gsvjJDEn+TI9z5Dg8rxSDrf+RhXTRKgx/zJmtQahUZ40eLVcp6OGRfTuYCMIZU4Fnwxd8Lj/D5OG3aQd9bL0+7kmr3WZDtIBV6lk7h0QbFIGx8Zo2FysjpG+0dyV/whT5AxQ4o8uNKQKwW1NL35f7UP6GwIhsHI6OS6bTeIvdnDa1UM4qViG7AJ3Qsjk0WDX54u5Gkvhy6F0mp4xnK5e9qH1Jx7Cg3canPnqOXdnbqdf7gQ7eswhvyqNx6W1UdHX+9ytd4gfhf2jabOzUOFPMwbYHeYzuyZBe9p4eBz+nb/dT2ClAIGhb+VAK2K24vGAT+B34BW/WTeaL2xieOnmRc4ZgxhQ7cgVyr8xQ18JHSzOoMGyjSDv9ZqGCX6ClLWy8Pm3IHVkB7F8zA7+kP0JIzI/Y9/lR7zdGXk9nqC2Gfeg9I4RfLn1Ae4vDuPS8DNwUEyJgrb4oNP8Fn6+DOB3iB5VfHyBIbeGw7SnWmyzfSzOrBuFkW5nQX3jN3jurIkPxyfwvbcStPOoCczeogz24wbhQOps1ovWpe13v0IxR7GQ4xmKlFKHQbVN/LvVkwftZcHM7yVJ9Yryfb0/3F0kAIry5Sy9YgK/cq2nxFeu+KI5j5rvG8P8yXfxjKM+/Zdyn94YCsNX0/EoPuw6dqTGw29RVWhdIIK4QArC2/JQySqI/Xcps8FOIfa9n0jXBWbwrpP/qC6lDN+cK+b2uKmQoPyT/yR5k7DVJNRP1cTOiFhYNe0ZOexUxA5rH3qtuAGCBXXA4bA3mK5vpSoxS3RPfo4d0Vc4aO1sPlZnSp8NnWlsmhocNNaHCz2ClL1zGVWfF8Y8l/McqKYNJj7D0OvjZXCuPYY5BYtYLVUELj5JIvXH6TiwyIgiXOdj0M6P+GC8HEJaM2Ybj8D5c3NQJVoAHu3biYObHSAhNJMuJC4D64VPWPzNOkpdN5zeFc8hh60FMDjbALx2POH9OxV5TZQb4+hT5KS5mfM1npPImikgJZxCzZbWvOe+BQRFToQxOsdAbckttn54F00L9dhG4SCu/KSAm2+U4yfLq2RrqgchXz6B0av59F94IB7sOMD6S1+wrecxOryymda/9SIpv2zUKdKGFzd+wHbDAT609w1fC5HkDO0e3vj6BjQ+VsDW+nG8TO41vmsYC/O+avH7nTPpX/pisNKMoRX+p/lP6Cg+HH8bu1Kt2bjqMvStVAVV0yZe6zoVj7yxpk08iWJ2fsVZZ+fx+pnzKGhMHEf0RlKUigaciRAl9/madN7kJ8dNe467u1J4cGYDODXcAwXtI7T5zz/SGi0DnzrvoG5QCJlmDOcau0y4HLQSm5eEwx2fQjjUsIU2N6VSlaAWJMbVwcP9wuT+9BBaudzFPXnv+c6hu3je7Rkq+H6EHzYB5KgCIB4fDKb9lWhdJE+xOy/RDckWqAkJwx7vEl7V40hCXiW4JFQFXN5l0Yt+U+j0KKDYUiEeoabB4s2GsGSsGrUuHMQN5jG0CgSG8q4C1ikOx+9nfGnG4QZUq67EC3p+PMHJGf5z2kwvtpbzrnJz6FXW5xrfBJq6vADv+b8jncQ+PnB4CrvdGMZ35I5hpekQdw4aw89Ru+Ge3FNeUdfB0boVPGzOevIzu0AO16PAYc503lj4HwffFoWiWE2+VvMTBxXFSarAk2cVdoLFpY+QV2dBm09uYwtLKfJ0U4CKebYUflyYB+asgf2/PSniwBr0tJmJkmezYaBoOBwJMWHeZAmJlsN5dWE75Vg94Q2LqmjEixB03rsH9qqPhAOC8ajlfBBNB6bAXduPEB85FXYGD2Dz9rMo6d2IekrPcFHpJ7jv0wCFgT7s8W0SyP1YjQZWztgt1UR5G1RoSvx3ij14nfyPlLA62/LvizpQ+msYbBp9hypDvxI0mHFR7ULU7cmnV0n/0Y+vLphWlg6j7sVjYp04BJXvgA0e1rwxYwOYDZtPxsMj+U+mGkpMIZ5zjinkby+MnCYHX2c28tc+EbqhKQPNssdhy8Ugqnt5kXx6d6NpdRfZrjfFI4Pa0Hp/In/NaIBVNr+59a82bzuvgQpfe2mddgR0ui2gA18q2KBoHHSa3ueCziFf1vkOhWF6eBeF0NoJee3MnbSjIQn8OieRdvgoyJvVitRpwGPXSdOldEcM+p4M7+4ex+17NQlOXwUrdof+ATGwV8+C1Fx5eP0lgLVM5+DfhAGeMLyPZphF08glX8kobTF5DhrCu7wQXNxqyQbfxmPhjjT8zzIKDc+7Uk6/LYzL+Uq71WzwQY0AqMbn4e2L18grtgPebs7nKEk1Ms1eQZMdXMis+S+s13KlHfpiMLrVh65fMcCJYx/h1lH/0CvkH+onHMOlZRo4or6Fxt9tIdtD0jBspilrhA3lhM1vokBRjvvhTIeGZcEj03O4S/oG+Wvb0tNngvBdYimLnsuGtOq79DLChpMjasl+sSjYFotQvWQi361yoY/3J8Eq2W5KTH+PS0piwSXoBvsGDdLqGfvAPnQxvhlRyJmVHrgqXARGfbFEG/UEKBUZxgpyT2jPx9uk/1EOzn9Zw5p5Wlgx2ZcdtcVBQamP8hfZ0V77ABhpbANSfxZwu0APHUtYBQ8N12Og6AWWTJwIesXaYLs6HSelptC/RGmWH21JAjmf8NuspfAy+z2ImZmD73k1cN27Aafk5XHnFjmcnu9A60a9pTDdCHYeYsiE0HNQ2SsJGy+YQUN2Czdft4fP23Zgz7c+vvXhHJgdasddbx+y1tka8DSpZqOX6hA4No/9F2dymbs+6Di+IIdZ92nT1SZY4pvKm+rPscq2O5ywQQWEYibgAZUXKDsmnFrES+hqxUvWrJ0HdFsM9pUthNXtq6G7fRTsnVWOWSfOo3P1WT53aikprhWCO1MfUlnbT7os/Y+8fpyGoqlCMODlCQpiryjTtgWqxaeiddVFTogQZLq0h+bkq1JjXSgMiupAYexwUItxo+60T2wj/ZiMlXawe+c9Tn7WjwGy9ejkW8k5ZxShZWsbzf0wA1Z8UqGoy2vgkZgmWIh2gLD6TAruyiO4ZoKzREXhooEaet1cA/n2qpR4KI7z82+z7uwdVDgmk7RFe+GpZhk86ECYsXE0BSansdX38TRypC4cGdyC2ztMIH/+RWY3dRg7IR7/vtOBo6tzybI0EyvGtXLe1BCM3P0LDJpm0BjtNA6JfIj7Jw6S1sJJYFE8AEras9F92md8U/SK5gxMhbaB8eDbeYWnJi8HDZUUkL2tBsNitoFs1QlocfxCof0leF+rluWG3SHHl+/w5yJ1tNEZgVb7JsAcnWwUmWkMpzVbMb/iAtfOPMX/7C7Au4zTPC1iAl6crU+6LjqwxC8C816PQ82lPbC7Xw/u3A7HqUb32dDvF6rqHIKGCcmUkyADvz9qUUXnPBR+KoPRm2rx8Zd1OKt1MlasH4Xpf9qpalIAPJlvCVN3Z/GvYV9pXqMXyFydzzcWVeDDk2coc+4VlNGaTltNBannxlTILTCAwA1p8GVWJQ+fv5RrIjuw8H05uHgWcVLUI9ptvpLfWE4EfftqTnS8SaP9N8LgvTaY69gNo9yiYNtDH/iy/ge9NuiAYRaacLCgHzep3wGv2dMwzTAYA5ctwnpHV6L67Xj05DdaY7wbbzwbDfq1nWRx5SC13N9EH3LzueLnFtRQS4KWkRmcXLuHwtZ40fCjBnB/fj+n9xOcoysQXLGSTOpsKU69hBP7m7H5mAW8Tg8EyyfmcGK9JM6vDqbQR3+hQrMEtWg23ZV6holTDtDizXPR5pkvdyrLg3ToJfIpXA7+e4x5o/xT2mmajdL3VvO64jT+bbyKm5TOg1uNHuz3aIK/LV48mQBfDx8JfyXayfTFEI8k3QVvFxHWnr2KEqeawq8XIRC0pxG2jzoKLZ/N8WxoMCb8MIUvrq50Ny6GBH760NVj0vB4zDV2VRmOs7UfQ0p4Ac1f2Qjh1SchOaMIH5W/pDr9QIivUoH6oX6d6WlFLRdKSKRai9r6i8Bs+UK81u5Gq1JmoOm4r2DaNAxe/I4kH/ti6q7dwjW1h0Bb7xycyO2Gs7ukOOXbbfgyqhwxzhCE38xEjf6TkFOdw1Hmx0hmUjBmr3zALz/WobKDDaade8nlewg8O7up4ultDM5uQpOsO9So+xd/Cj3D1dJJqDrPis67LiZeYwyq+6JYwvgcxyivYqVHDihr8YAfX5Tnw5/m44DLF1pw7yY4xUrB04uTQC9iL+44cYkld2+E2qY/GMFTaMnT76ydNg/2Lh9F1UbSsHnhfroRqkLXVr7n9MbjqPLSm4o3CqLo8bN06bsRuJheJ/HRStDxah8tj3PH1F5R/Ob4CFOzc0njcB+s93PGp3rnsLNvOy+fawbP5khilRRDMs/lX13M233zWd/xG7ZOlsVdeafZIeMIj9UwgS/iTvChfhMc37wRBKcMh8dpHtS9vZskjrvxRls71J12DRSyDCEr2hgz28bhOYUxMHfgN23baIZrHEUwdmMUu0TV0oTSHhabKwUO5rIYO/YAvdkajqEl8nzEOhP/mOmgx61UzHSxhL5j9/H2Wz1oWVNGT1XkYb6zGj4IdoE2xyrYGbsCIkamoaRwLRh4m2DsTws4J95OKkHn8ZPVUVqyKZS/DZ6A38IjUeTuQj7mkYl5S6vIIEYCNBXFuWb/VW7adxpLd7RivOQl7NWXwVGaNbRSwwucLWdTis9I6Bf7ylvc5oFMJMCx95XQqlLPVj5NIKUxkfoGrDm/qxHEvY3AKuch63w2o4D652Cx2IcUjB9ClkQHPlpoRgf269KDpa+oXncYXLg4HUaPGY8zo8xp+NY//M7iAn3KG06zV77D56PKUFIvHcP3CsKRvONsb/kKXP7zBSGpan41HeCsXDG+d3jM9VZtfHol4GqvsVDyaB2qDbeDgYcuXDHkizn9G2iLTxIc/nAaXBc3UHrpEb4dYgZcE0/JGIqbDwlC3GsffDK3FFZvfQ7jWvfAlaR0KjgaxFOeGMPzkw647bg3Pr9/BS3f+5Bx+md61/kMJ48yxtlG+ihxfi4um6kADwqquCCmieNTLClU4zzfsLVl2ZYuvLIygSq0JPGdvCTdLBgBdtlWJLz3NcSdseCVzdtB71Yyndp6mHjhHVS/HYL/anN45FBOZeTZcF7JJxqpkwA7deWoceVEsv77jRZmXWSDv3XcWiLGvb9GwPBrr2jetncc/OIdRivZc27mVrj0Jgq/htVQdmYoxUStgsgKeSjtPIB3OsxBL/A0eufEQJ/bEn6SGobpbpcoWsIf1C71Q8EaOThxXBOfFrqAhUEOf3jszdI+utAVmA8CO6PhybASvrxCCjJOjgSzxXPpz5yhZw9Kp1WLu1nDoACs4m7A2Qs9vLu3kw8XFlLOYg3wfZKGga+no+G8TjqZ2ItPbn8kG7UObK8Z8ryXA2Se8h1935hDdvg2LDldyz+VjbCQJfg8nqc6hVB0UfaHOJtW8iyaBZd1J8Dc1GnwUmQtzHLOAE21Hex6ZjIJHIjl4YEAub5BaOZTzq45QuD4cyqa6IwjkfxAvt7mgH7nzejh0pX8zXIq/bi0FI0kT2HuayPQPP6BHvkUQa56AhWMPAYV+8+CY+hjihF7yrPe/0eSFxk9tk+DZQttoWVLOm/uLGavuSZgY/idF9q7wSrVIp6j8BH33chCQTl9ENt4E776m1GEix21CCygRxu3sXvCJhh+Qgv1X8rgfZn51HvcFNb9KcaCLkk+O+IjN+zrpkP3PeDyAWeIFI6Bj7cNaY6eAny8bgjNqdk0KauC7dN+Yv7qekw4vx6qnyhzV4A8TlpgyyLVZTj8vR78Nf8PV6S40l9LQxIoVCSvXzVcMfsB7uxwYJSSpeT8Jsj10wUhp34wfJ2CuyP3gI1tD5xr2MFb59lB2kElGra/BGR6teB1rirY3nbGUI1k+uD7CuecWAWzBUVJxKID5jolwFLfSRjpIAai9tNAZPUKfFI1jSrPp0B+5kVeumwNeaob4ck7MhTcH0oLrh/E2nvm8MWhnsXGLuKUfTl06nAFrPWR4MULzrDeHCUcJjMaVKul+HcOwPElGvhc6T86uuwHNK3WYju6A3bXVqPig3JOEK7BDJEk1OyVhdobS0nB9gWMnj6AC+dcAr8PBhCVN5GEpoyACWnZbJuew2GaZmDfvgD/6MbDnmf2uFxMEA95voADstMo3PcbZa5L5iVvxWmUogZ4ydjwkzXttP3pIIa+1aHzJx7w38k1NMthBa6V6ASlfWugV80A5jY74ayVt3nDn6Ow7Pp8lnQ6jXdCZsNGmQeU9+46fjbRpZ93FeCNmwoOf/qYc4Tn81E/YWipPwXm2yai09pWjiz/RW4zxsPUHeMgc/oCalHTodJt+tC2eRVUfHCBFOfxfHYrYm3rI5ysfwq37TCHh55H+NOMu1AtaIiOhXYgnixHRSsdIc6hlBaFTYacAQPM/TcW7E9lUEBpMxRdmEVmbm6g5zEAbrdcecnjFXRshCfkaAVy8MeJUN4cxW+f26L01rvkxCY8LjYMZrc3YrD+VSyqeosNF2Zwb6gM2BhLwL/xxZwT3Is/Vu6Ee64SeD5sLTU+HUFbxlykl2PWo9mZYVBSupwmRS1Anj+ZE5bPhG2lgWwgNBuH4RMaY/8dl3TJoYuiMHguvwIHFuyh4ikn6Jz7LjhyTorczZzx1lM/nNmhTxfTbHHuTQuwCGdw3dNFjxYVwatdXnCi5xylWP4DO9c3sKJ7DSR+9uTfFYrwd0IILgyeTNUzIunHllg6uKWM5Nul8UVoF1m4FoLR5T+UYioO6ZXV0DDvJTmMksMLrVXwYr8HXj0vhMnvBiBgwmrsktlEq8gCdA3jKeiGC2uP34Vxqo4UucYVhUsmgl/DIz5hhVRlVYMGLwluXc+G6n2FWNqbyOaiA1S+cyeHsSCeMq+B11cPs+o4NdyIY2B2wAp+67sWa63sIOmMHhU4/4F4dWf4eOQ+Lz4vhZbyPhQmNA7qntmTe+AwUky6DzerG3GF3G2cd6AGE6um8jSDoTl+nAo6KApnCnP5lP5nWNNrB4sjcqFGxRpqiv6CteYC6P18nAcuPefIo1Ngx+hyyK1RHOqGrqF5UQcHp+koKPUV9KozKTv9DbRWBNFjKSFY7iZJV/3OwL+DDRzuWUUDlYo4X7AAlOImQlRKNi62LUAPT4SaU93Y+OYCTHNfARelNUhm5VuckHWblfb/oqx/ghj8XYAMHwtA9+3R5GTbBdXCm6FznAiXvsiEOg8TPq3VAtr//yeu3yUY9lwOvkR7gMLpqXQo4yV/XPqNZc99pda1L0g4xw8tp/8gZa99NKhqBrHtKvBhawUc0HXl/bMS4UrWfD5ZmgNzo9vogacgL1oaz2l7FCAUnuFVqT4KiriP/iKFvMP3PQVL3yGZIgEAL1f4cu4fFZuKwi/TUFo3+BRWNwvjQEE01QtOYJezh8iwcj+rbtmCS2yXUWW0OvjrBOD1YMDBtp8cEGeHOiMT8MPsNg6ckIDetSJkkT6CZ5mYgo3qb7Ba5s+z3c2597sHVXtXcCNlwjql91AidokVo9vh7QhxuKA4DCXckzAg4iS675GB1gtTQTL9HShMauX+qF3sY3MQo+uEYf6WRNTpeAD9aq9wv/tG+lpjQi8mVJJAWBAbXPkBYR9GoWfTUPbqHKdtKh85Vy4euzqt6KnkcwjU8uXdK0Op7NoxMCpYSfteqcDaxfL8B6RhiXMSbxx/C8x9V3JpsQRoRHtx5+n97I1VtP6nCriWdoOlQBZJrXOHYJlGsGnNpZqQmdwu68vnSitB0FEddtdqwIeKYlIu/YtNhVNh//R1KBV/DG44C2OxtxkoKR7kOULL+GGaJGg/Wk+Gg14QvWsY77bYxx1Hm9hS246Dd8Twvri/ZOS2iIMktWFvnxVtvmPMbe/LsVP8Kz4Q8mSBmm/sUuwEKj1XcYKhJ1xtnQwqt6TgjY4KZsFWGl9zly8+OEEWNfYst7uWX72Ywm8r8+i3kwT4nyU6vd8dVqVmc8qEtaj+9Rs9uldFMZUDPFlWni7pdEPhBy24fNGIziX/orwwH3BtuQhHpE7x6k0POSR7Ofyd6wx7rkug2zhNuFWnBCLZjWjxYzv/WfuIEzWHQ5PFaP7htgVcL55mq7Av0HV9PJxuPoJ+3unQf/kStc54iQdCI1hjyya2DwqmojVpEHtcFx69mgYzKIEFj8zDeENxtGnRhYSsYth7fTIMWH2G+DX9vHT2DUyLMwfp3i4UyvwHFd/C+FeYE5SOL8Jw4QhM/fmCM264YqT4Yl69nGDPzg94ZqoWvQ2upaQ1r1h2chVGXrsMjTcjyTwYQVwtkLdPloGwsYUg9ews+Vh9g84EcXipuRlO/+sB5/XbSEl9JImktcEkY1EwSTpFius+UmFJOU7vXwoNykKorinJ0b31XLpjCZCmPzcYaoKm1xbYO2oMJJXZYueyMtgrKcJzVm/CMbZtGLj8DP3qbMel15RgeN8hbn8ig+lFSeAv6UGFMxLp+JEDnDPpG5bfvEK/01PgxzdLuCb4m9Lrx0LPaX88GPge9qyYhF+WPyAJ5zN86ctBbE5dyDMfTQNHO0XAo5dJaFoxZQ7L4/hdm+D6fW1I/SXF7kW/+MKMBhjjLwFab+twg4cIldUP5exOFYrbsIT2BCyF/iJ/CH52D4bJ+YNwrxoYnonlSIkmTj15hAsEdbAyxRud5KW58uxJmlJ8jMyvbcdNnQznff24/XIgRvqFw0bnNTDr9X7utz8By3cs4cxb0Syl6IMrrGThZIY9hM9xpxl/6ijaJpc9xOs4xpmx8rUNTpHJxKvrV+A8aWPYGBwORQ0p8PjKVVwi0YuPQsSwMOwKi+iloECSFLWLraVDwmpwSjMPd8uL8kZjf3b7uw33vcnDhWHenN2mSdH7IyB/+mna8z/izvsbyD9u4+9hrxBFsmVHhShZpUiRktUgLU3bV2nToCIlKiWFpKkhQqgkkiJCpSgqJQ2pFMrjef6J54f79/ucz3Vf1+t1zuec20sYYhPa4aaoMyadKcY5l7zA40wDvds5E4f96OO52wHr5AXB+D8tiLw5B7MEflPgRlE4NTGL1s87SK3moRQpU8Xnc90hVqSPpvQogk9+Nfq9tyJVy+kseNaMTbfpkEBGLuUO7ese72UkU3Kd439PhtL1P2BFwVtYd3M8njrwgzIfuZBl6yP872cDqzq7QM8RERyRrA5lCV8o2GIS0NIWeKw1ETzKPUF0swv/NPLh3lYHlJtSy7GSFuCveQkGCg9y1sb1bHjmPNfa3aRL5c+puewux45QQf3H16FfSwam110itfRGXO77HvQK9vNmLEGFm0N+oFcMQrsWk5dlBm1WJJj5diFnWFiA82IleKG4hwLjS1i4bRc3va2Dq7I1tPP9KOooGgOZHmv57O0G2PTkJFb8fAv3HspDXKM/KjRJk6pGAI0U243zK+UgOUmDgpu/k7LTLfoR3oGx84ccdc9I2ud4h5s+BYFI1Wy8GikEk9/sxylUSUHit3lE/D5WVZsEETuEQXzKfPR8+R2e5G3k4CCC0y4HYGqdBo+Z3swrhzhi4+JquK7tyzUGSAdvroDFAovwQog1tBm+IXH/ZMx8s4Wkpb7xnp+CVLVwDs5UaaJK0VQoerUUdaIEYIvzHjjesp4vaT3Ca1rVHLZ2NsjZL0WTKZnsKpWK5vPe471cYdh9HEnLzBL37krlMaZG7Dm3GJbsGIbm240g/rwtJhyWpOla4vBj5V6qE2ijzJWh7LPrHa3Ju0m7frTAn5xb4PWrjbLCvkCYmwTIr24i00hT9E/9hp8tCthm5Sps086Fuqg+nhyhwKr+inT6oDV0r5rLL18hjN1QT3F51TD/YiNMLN7Hn0x7qXV9D+1aeIwDv2mAlFc7Ri104ikFDqz/AUnE3xzvvkylabfi8a7uA1J6FkA+gWNhceNxXOChhY+kMyhWTxI6x6ah+8Jq3jHgyl3Vkfhf0RHyzRICPcNWpI/f0MhYHQe/BLMcdpDN7yoSrBmk059zoW3HE3KyFYXVX79RxVoFipwTzD9djahZUhq3PLmB/ovW4ci+WdQStghG6xKsqjoKb326WTjfFkae3cVaTfHss6mWVzyuIMN3//Gh5NHcXK4LOjUSVOG4kP57OYO22A7H8Ou9dCkgEV9/McHR+6/CyKX5/FJbCNZnLYJ1FYtw2RQL2lNymR8ajGTzqSmYkTuf+0TOotEyM7b/JwBF8v/4usFd+hPlAD3OIbRC/jhs7GhmxWcvsKR9K8lO+MBXW8eAktNemK5/gvw+Hadg1UZ+9kYJGx1aIDTMDtvjM3iNzUfWGtSHFUINMCxRkEdN0Kcy3wb4L02cfrsvpD23r9KludvgkqY5r8hhGLt0OotsDUeDF8/wTs1uXlr2Hg7KrcYdKTOwRvkpfxu4TrvPDYMAtc+sc0iTFh+oxonZMhSdNBUuHGtlv1mjWaJWCc/3PeT9BwRBxXcmTPllBDd+NcPf6IkgM+cab2qqh7iQChD45IY/5/RCf7oeHLt3n0N8DkO9nB6PdexAubUzKPNcAy8tnADN2+Zh7+jjtCRPH5zDPemyyAiQKZ+Nv6d3gukof9TarE63DG+g7OwaatDfxt89dOG+ai5tNvciz/5GcBlWxoMBt6jSLxo6V88F3b5O7NebTi3zVSDnhxo5hotC+t7xlLUZ2EqnHMOmnOCjcIG9JCeB2d2ZVDpeHZTH5dCGvC3cu1uV9gf306yQUHi9ZhDXp16kd8Ub6PPZIff/IgJ7/pTw7so6Cqh/xb+yh9yq5CWoXu5g2Y5Gdgh+Q/W7s2Hwlzm0hofzmpbT8L5CC9vmH6FZ3c9o3DIrhusRKKF+nuWlnXhRtwWk5CxDv5mb0H3rYcg5rk1r3vSB4c/X/DRGm3Rc34LkPoaWH6NA1O0tzJ38lt8/2MEBF4/yqfiJYDnfEHJDNuG7Kn8ICJuKoeoC4OgtC/l+8zB7dQgNXg5Cw+ZoNCy5iSfeMY2St+QVXkqksUgZbk/OIiG9UyRjLoHlDQCz3kuz7MlQyOvvxezPxtz4XxN99BaHG9sbqO9JDHmbtHGKbRgvj3vLGc7p4Db1I9+Z7YAeq4phtpMmCLn8oAmjVfDRnB8g6tqE6weP4d6NWfhltjv9XHcRHFYM8q41E+HsqwyaJlAM/zzXYdoaF6ga1Uyt6utI9dJf3hrZgxMlLuPnA5ZQtNoEvpopgfzHerp5dD8o9jhil9EcrEgYzi1QTr8fziYfb/3/t///ThliyqTtzVR0zoROhL7HnMq/cH5zIKfZv4LIi6von5Qk6lwygL/7fejFsUM01zAAxz1SwiWdE9gUcvGAxDMUe/6Sf243QxObyZB31I9frB2HJR+7sHfkAKwJXQTa39UgPH4SR7eqkoz6b3jYOA58Ou/BkSZ1+kyv4PnrLvDz+IDdw9wJpx3h/xb3sLfwPP5izCCgaoqyFdp0RfgV9X2eiMVvC2nruYf49ttsjnbLpvYdEZR5xwjOxE2CX0Eb6YJKJzw8EkLGlVkw7X0lJMabk4nRakDLLRB7QxxUDJ/Q4Kv3YD/iPbUblPObdY/ZcfUm+lQxjIum9sEDExWYXG4DhpsaYcKmzVz2LRfbtg1juT/PcYPGVMi/Fwdp0vvxdPsKyruuBDVh2eTj74l3744HN08NcvYeDRoPy1FaOYDP3F6Ea70fw7b+Ie7tnAcfx7Zh5JX5uKH3Pg1mmnNY0D1IWS0GSzOJPXpXYMx1DTjVoYaTLH6Bv1sRXvX5BS75alzPS+mYTCyL/f2GikLlGJouA9/uXqTxdv0sWWoLQg2d9NX7Acxd+JV6+gR4xKSzYPt4LSX/mgILFIZDgudMmlW6BY+GqXGL4Rjqd3nNufuNSeW6PQ4qTICpa6ShySAaqnTHokn+F/iybwLHFK+ntMRQzLLXxj4rdxqvr4Q+k8yBPGXY7+VhcDl6hbRye0lJ/BocmrceJDd+wGXuoVj86TVIFgmAgHISDMvaQVtl82Hxu09wJtOa94m8ouklw2GzgwpNjmJyKNYCsRgDdgtQZCW5HhrhK0G0azkszBWgFjF/WL3gEezsPEcfdUXAYOkFLB21ACYWHscQXz1MsW7lvVLhsEfEh1YbxvPP+j9k9IbhplIQL+zaDyuXfAPjo5vA4F09PWiN4vafwylIYA5XnS4go1xZ2FWwAcUivqLSdzc2awnkZyrp9LauEj78k6UVmYv5o3Mn7p8tDSlGJby81oU6/o0BqTJjLr5sj+KKWzn1wHlsMpqLp/Lf0+2rk6Gt4CWslelix1Ydmm9hT+gdR60ieWBxO58jLJbT0omDKNkhDT3pnfhL1Bpkisqp7qMHf8sZhvL/hPj5tNH4qFwMRDYXUGGRIayQVqF/CwN4jlgnjCo/RP8e7uG2xWp8Yb8S2s/8jFdfytP64tFQf2sVvY4MwAvXpqDVaG+Q++yF0QN34UxdCOeOm8UzvG3g11Y1KAjq4A+TWviA2C5uKFWmK8rSmPFlNp8sTsa5TgUsum8X3lyrCWJytbRSfyPZLTxAoz4fQ9nT7WA6MB3ato/k6oWF7NPhySmPZeCLxkywDFgIskd24+EIff6RcZCsl95Gd70ffDvFH7cFBOHhspEgaZ1Luz0+UvuzUZC6QxKeLB6gvwqrYPTwCk5Pv8sTlsZg3URTqPX1Q+4tx2OlR3HPcQZYXccu477SU99YeHpyOjxwO8VrzCxBYoYTubRtIq2dJayMO2nkuVy+YvoFnlac420hU2hDwFKUfDMWvEId6celbLb91ctFJ4iCAgdB1OAePhP/iO6+LaQ2oQtTtAhO9B6D5PJuXLFpFOWVPaOuGcNAoq8bzQ30cN+CUswZtQuEPojBz4FYnpr0Gua5OZBDWQ7M90jDd+NysP1VBEmHqkDYyGX44JMQSIQs48ntq8HLOAbOhF+GW6Ja+Pl7OPil2WPANSnasiebA4/qQZhoNTqPWoMPDnbCj3k2aC4WTk6GWjBocpmt61+R0MJAGtkvAWbVGzmw+RbmpETR74RqSPkswefk31DwU0n42zQFgtsNWOiULCS1d5GmqwyJnRuJu8IK4AG1QoOAH30pJ1IY8Rdad8bRqQxlSEwqoFW9jFmLQ0Dlsi3F2reBcn8zajqZULZ3Ch+emIZPj0hAz49uUL4oxjcNp1KlpSB391fSgpIGzG68Rg0pwugwS5o+WCtBSMZnupx6CdM2LsJ0CibbnK2wdHQSWttGc+SPXHK9N50h0RwUhWbR+URvWtzoAn+9xaD7xjqK/5QON0O/cNGKSojVv8p9u8zg7w4/EAvLZ7OR+zn7nBkcuq4ISVNvccjUxzA3LZm2yNfzNi8x8HLQQLOnzWBoMxXaNYwwdedKKogPB+nngrBl6gGkp58oORHhzTg9OmRTQNJeP9DWezqU/fHF5e3qnLfGAPI7k0Cs/T0d7Wd41pdAh79uAf8QOTr30hcHjM/hGLXnaFB5jgqClahiyjie6aMF25yV6duxoTz3fICszDv8vrueNAp14ewMBdg/3IbTAlbj2jWqsG+yCPDKy/BKahbf/riRGugKHvIz57ykKN5NHvBj6VL4A+ZQKTwcJ/9+wuUinfg634J8707jvtaFHDY3j84U2rDL6Zs4eQgPupO+467yORCpL0wNG+7AJs00+K+4luxMvUBMWQ7qbU/yOhsB2J/1j+303rND1BtSmr53qOsP8ZfMPKy/pw82gSdBTHIjuryeBH51cdDlXIyu+m94Q+ASmi+0Dx9JSIDfm2lo1TCc9DQMYZW4PuSmOkNY3mwcmKeKt1zGU++4A7S+1g2rzN7ClwP7KFQwnbSvy0DRwUgKufIR9wUcZtmzlRBvI4LhQRk8ftlLnGBzmZrP9/PoNnnY7L0DN2x2BPtDIeipvYdOHd2NBbZR2Gx7lJeP/oWrMmv5/jerIYfT4uOLZ9P35z9ojdQALoIttOuiOmmY9kJw2AlOHnGXohtl4JZwMfnrfkSF4YvA7kYJbTTNB6WuUyz7bSS81lEBwYTd5KxuAz1xb8BKPhrcFxP/oxwMLfkHY2qXY4OlA5VtzOboqfP46UZDEF//jfvibrOLgyJMv53Mry20sFU5iQ92PkKFSg2+EajKsfEKIGCzmXpdrJhjWkDzbNPQPn6Bh4cOgeWaeTQbHuNAoi3e07GCRykXyFxjCif1NMLOhWfoT0A3r6rtg7MbfvDOC7VY8d2dFDSHQUvEHzYXLwVWfoQNz69iTfIASAf0838v7/G6LRf57Ihqllk2AmJuFsJoOAllYsI8++0F/O+UDtgvtcd1Zd4UnqVEZYaPQfyRFLQ//EZzRutw3gsT7tn9CTQSuiBC+AL3Kd6jE7bjQSo/DRXuCsAB4cW0ty2GjUfI8JZSop1x5hA6fzeJrqzG2QuFcdYqJT50xBSqo+bglqh7oHDWEdXkrpLh2VGgHPSVpphsIp3PmaDmeJmdEvWg7EoB1LycT89XW4PdqydclL8RvgXfAsM8F5xiZc7zJE1IVlQCCjM8udLWgHUuBcE175lY+noRqxw+TbaecyDCzhfu9t/n4a5mUCQVRic1e0johigoPliBur1zWLmRaf68b5zQvhqdGsp5m6wgiH8+BsrD22lsyQB8y/2AsgLjYXS7Erja3AWH9/ep3riGSp8Ng1mex/HCr1LO6P8GZdF94PVgO6QqPodp5zIo5aYQzL7eygeLDWCHRxy/sA+EDA1nSh14QXE+/8h14zFKWnefFh0O5ciKk6RXPx4mJ4ZCVVAzJD+0IC37pfyrehCdX3fCrPEpcDxai0TddpHZM3EI2JLG5s9/gCa34+dlIiSzoxxnDltLlQXxGNAdBNXCouw6XR4aF/+BeyMfgu1bCbIPvUOPMnSxUfItClrcw8U7Q2Gvuza5KTKs83vA2YtXwSud+3jnyB0y1g7CjjQdVpHaj+6X9EEp2x16t6mDwuJ3PO9KMaSI/WJVfROYHYEkrPeJ5oYHUcZELTyjHQFlFcJw6tUDvhHSRN8cesnNoxPlHeaAg6MkBkVfxSaD2XBmZi0eChsDCmPvcbGZKLPfALlqPsND61XA+poPLvXygRqjJTBvdTd/LJIGl0UEd38Y0wnhx7jH8R0Xq2VDy+UwWnLcHyBOCT7uFKP2h+NhnfIe/Fd/H7832OEcqW7cxY78yryDbVzv8vbxJhiyxWDIEY3Ax9WM5LdIwLSmXRisIsAdVQ8gwOs5bjILgzPuV1FVajuJx46DeoMD7C//mj8crYL83Nfc9dSW/+YnsueFCHw5/Qb5D/zHMzWMwDNaAtxr3KBWrY3usgg11yZh2y9/iJBM58/71EFx7FWKtZ4I588ocPuACI0xlqfHYv2kLpbP40dfBP4XAHvKB1nnxmSKqpaFmv4jdO/aCtrr/wD3eU0gqxo5dA6fhnZXgfT/24CWpUJUMcIEkmcNkJimNt8anAc2czowSf0Sn3z3jJ1l77PvrzFQOmU8lVxWA4vBneQ32Rz2H7Oh+aYP6NAodW7ysgWlmHD+vHs1Cxss4Q/71aHFcRk3/uyiiPBNsMblJ2oFFpKVrjtsGW3H1x88oQSv02xzXA78a+UR3csAt+qjo5Ej6K1bCSNPW/Plpgo4qlCHB3R/w69DxnCgJwxrdTqxIGknKx/tRZdjqbB15Xq4RNvIsOcOvSjZitsilGFB9V3q6z3+f3fmAldewK77+8gvLpMF19/nS2FpkGw/ltrqZeF3YTbpx0ZA3NYgbAl0xkalATxs1QCFMjPYsf0DVKR44c9kaUhYvppL/16AFr4Aq3d4g13GAbg1cTl6XBKBsoUOYKl0A1rsLOBsnT9rbXnFlgETsbTlKGZWCpHm80UQsuMG1X8+CrKeQWBoaQz5N+X4+e5VKCB8iXVrPtB2uT904aoPlf7ygweGPjRCegndaFaCJTIXec9Tbdo69wIX/RzHphuOYmreS1zf1I/GFxJo4EcgppnqwvCWAXYILAGX1nD44e4J8Q7rgE7949dRU3Hd68M8SbsT17RagbXtdvxxfxVvPfSM9vzJgD3LBGjb/ZvsmLOVijIO4+xLwXTTyxpyZtiiYK4F/T3yhduSnaHg5BmetXY5SU3yBqcT92HM45F8bYYhLEjQZEH1Mzx3yknQDikd6vDN+HTxQ3qZqoFCRusxT8qP8/4qQ0Z5F3ftUiH19AAK85Ej69ZMfv/BDIN+zYPfRbFMrgY48pIGvI3ZwC+/5YLYWAU4EHsdbXUDsW4o9/N7vlKMsQuNiyGarGQMFnJlrOOmTZttZKjsijBJlXTBw98WKD2pm9JnXaHNB+1JZtFo6E31omEyAL1pT2i3VwJuqhyHUSv+4uSlsfDP1hG9B85x/ARRuLJGl4eHv+P+0EP4OeI1NX7U52GOj2CPmggYGrzB7Q2rMXuhJLTjIjS+/R73rb1FaQ5DgxRyiuyCmjn7/RIq9ZxHy0rs+EG2DCRqjaMM+1BcGmyDgmvGoWfgDbp89gMmeL+j036HUGOOK11dKAFTUk9zWcpCLr2xi9+duAgq7yoo01SJ1YVLoN1QEQxSouB5iyosdE/CsZp/4df0jxRuF0gJL3+i05eLnF6WhP7JXSicdQ2C40bDDZNWCIlJgS9m67H3TzZYHl1EhyJNMd8qkV5DLyQ5RqCArwHUGpnTjdmu0PdREP7qZ1K7bz0/7dLj6HBk2xfruSbaieK8jSFRYR1I/nPnSI9MtLxYBX93LoeymzHosDYbp5yfDRJ13jjq4EToerUbTYM88e4wOXQSGkNOr07hjk1C9Ga4I8pFRvDE4HGYlKMK/YfjMcFaGmvXnabHFnvw7g4deqUwDq4eGKCv657SwRPIp14pwJnzipB6QgxO7RMBAbMc0uyQ4oBH5zmq/Q7q7HtHJZJ+xCZGELZ1A0smVnLQTH1OEjKk/ROtcGbfO6aZDfRAfybNaO/ETz9EoN3SBpcb2eN21UaUP32YNn+egRPrXXja3LPUPc0eXD/9gwupGrBjpCVISVfxSPcEWnPnMdYtl0PJzcq4UHUUVxz+hI/zBrCTzEHwoRb0iJfTpLH7eTCjjHcW6vGgykiwrtbEaiELahxmjfu+M+hnXWbL22Uw6vId+nJGnX956JDcjy8UutGM5+9dRRqeL7j2AsHIZ/3wPbmPe45p8t5uNZqSbIce6y7QMm8TdA3dzibqsiyjMwHClftx1DIv1h5/HR8Y+cLDhe142P49W96J41sGxvjJL5cubpwCAmrjsf6nHnbHLsKluJUbKm6CzMVL8FFoM+WK9WLDyiTwvDhpiE/rMCHeiFdXfoe9CS0c/EELJgw4k21vE90vmEjn552CqapqkH52PJWvSSTRTV60YVk4OzSG8Ar8A6W9KpymZgsVX6+T4S0TkBTrx7SWauw0XsJq1UH8X9x/MMsgCw5YvoT5dw6wS+ZR2msqCIKy/2j5om0wmB3FMi8VyDjCm3c/l4GfMz9jQPwbEhJ/wtFbDOBZUD6q73RDmzANjIqXhSmJKtAVeB4/nf6Muoqd5FJswl+cJaDS6zbol0bhJk4cYh8FWpqXxb9XlKC1gB2fN/5Iju07yHjc0LmBPGT2/QTVM2ksYvGeGjYtJ6WrjaiVIkCfaBae+3odlHSGw/Jzifynbi9d7t/L+np3oOjSHnrTsZN2havTsDslcOTgKkhQtIaF/TNZ2fsrprat5NkayvRIZyoVjTPnrUuNaMonYfwxxAvK66Qg2K+Syl+/YJ+mPgzOseY+qS74NHctThSKx4a/ZXR0rRH891cSHpQ0o61wA8Wv7QaJUwb4csNPqpF7jAHJ23n7roUg3uOJu8aJw7N1ZXDDah8E5clQRP0F2vZ8CV91esN7xG7R0PTRio/Xadk8ARD3vMJ3nfrY89gMWJMpQonaDsSevuTfL0GHyrpQcfAPrHaXgZzdxEHe/SS7o5tuGuaBweRh/F93Da+938Uau/TRufw0KC0eB7NOnqZXAmq48NNIKM49h701c3mGL+DMB2mQ81WcvkX9wgPupnBn7Cpqogasqp/Chzyj+O+NbjpRMAYzTi+jM57qlMkdGKUqCtsDjqOiRR2oQQkdf57NFU7BeCBRCT1eHgdvtWegNsRlRa6TIKfCAkVP3ObwxG46q7cW50aoQt3TaRzP6TTCs5pnxUpgV5UJsNJWGP0qDOIDIlj5hwLYXDqOkfFXea95I4UlhUG783eM3yEIIfdEwXGjJu/09YfvI6UobcZf0l3tBOVZ4sQOnzg54B3V24lAWms270jzgbw2R/LP+o88j03k15o1Qw7ziYM3HuAjnmlYNkUSQu8e54sL46H691hKmZPJT/QtcbyJApTrtWLc3pt8x94f438LgNy2BFTduQCPbtJkmyxB4itOWGOxjYqshkGf1SdK374QPJPloUI1hXaEa+B+OX++9lCK9g2z5xPeWjgwfDv3nrclhY0aEK9tAN1LUsAjzg2dRHLxhOMbro8S4Mt7V/K4jCXwc80gpwrl4CzBMTBT9yi0l9TwNYXZ+FbemiffNyeXJyFclbkaQr4q4Zq6mezvZwALnupQxZU+7PnVhk9etrKpZQtGPwjg1z7p9Hfqd/A7qI4HDgmBUL0ieszXxwmnDCF2YhQIPH0Fq0/O5pU/APdkraMdd8fAm7PS0BAC7B85gnWt3sGijTq4v+AZdvxUg9Iru/B52xi8o+qB22KHQUdUEJ94lU/b1jliTFIknaysweKCPFx08QGGRO4Buh1KBs2yMNkhDk1Lx1JmrhYmzD5I5tH92Kn1hA39zlGN+QB5igzQWFFDuCCYy26Tv0LQlkJoPSsF02378OS+e3S6K4Dku8rQOUeAcjIVQTx2Fe8fOI2TFi/C8Sf7accLLT55dwLk+3nROqtmeLlnDZ5dIgnztg1jvb87YOfyX3BXfRYGimbyl7KlQ/kaiZoqKby0/Ay5pDG4REjwnJRgyBEhKpV/Acp/88lfrhVExIvgY2ktba40hbIfYtA1itjr+XCMKTgJj2Xeg3LpTRhn4AZRfcwZHttoxn5dMv6tAt/2ZvK5cz/5V+VXKH7iQHcHYqhz7HS44uqLCRW/2aXjAG9rGAlyDyVIT1WOq7dGQt+3QmiSqcZzxdto1TBL0Hp4BqVzjUCrZTTsscvEitQ+KA+dxzXzFuPXDGUyqDLg1lcb+K6gCfxcP5VrRljApO5xeFTsJ0XYpfKOiIXsZbsAl1flUKruNsqxDaXjmrsxsVcfEr6acsK0DgrpWEGCL5NJYEw4JBeNYyOjYdwx5LJhKSdAoXMMXB/7l1qcy/lAUzMuuzKLRulYUNv6HyyyWQ5OurxgN4GRkKQ+5EdrvtPWmBi6fz6YPqmFc9BiF7jjr4bX1RLIXa+all2vpeGF46BP5BPtG9/Eo7kUPxeN5l8qx/l1mTz9FLrND85v4U9WK2jsNROYJfgIF1ZVkIP2fI6UbOWzfn4guPoDLPWRp88iO1lAfBXrPFCElXOiOLnpLmcbI2r9ukRFPenUXDcefeVcwFz/CcilutPgVASTwtcwwmMSiUw15mVPYmGNvQdbZ1VQ4vJO+K3XR0bFBqiTIghj06/hlR+REDz+EvjbnUeHcl2IcNkE261UQESkh3si4jF53EQYl/0XvpyJZfu7w+iH62ESdlanXcGJuPSULh2L24y94yZw9GZrWCU+H2p7I+HhpL0kbLGPZuyaQ+tE1qP/7vHUVLIMmvMkcH3UGHBcGIuTTB3w4eYgcLNo4y8qkTxxczbYugHUv7Am24nfKSzIGHJqxnNujwGvlXQDtaq7UGg+nrctnoZqufaQ/lefpv/TZ23FySCiVsayC2vhsq8wWb+/Q5NDP5KDyVZYu+0VFWu3oJeIHq9+OgFGTxJEha91sOqgF65eEAyP/MV5dXQGzlZKA889eTTvM5LxeD3InluLk9YkccJDA9ZZ1gSLgtfwxmFfyabPFWYXTcULBUvgy5B/VIlk0LCD2+HNslVcL/SJRLf54A9RzyEvXgz/KW1E2e1nYMZ4UTix+y6GBecQ9O/HaeH/kXbyU374yJZS++fgxVNT6MSgM2OzPDQZP4BHO2ayiJkBHDi7iW0cigCPmVCWYyhOP/KHuv4xfnmtDR0ri1C1hOhr/1xY6KpJq0Zeos3HH8N/fxaTSKwNTtmeyRrV2vD5CYHDSQkSf/qA+m/OhZVTC9j173W221mF2vHKUBsoBs5BUyDj9AKQ1NzDMw+OoLIPL/isoTBF9gDljHMhuX4tjlx/A+UsR8GZ3WlgVN5NFglIjXsFoa9kGGTLKVLUJztQjrMg0wmzSCSNYF6OI031jsPDNlvBS30GjzazhoOqrpxreIsi2kRo+Zxy9BoUhHubznNTtwl6Kl2hyVMLwG9BGHpvukedc+9wjvV3pPVC7H9jClR0v+YB71QauWUtjVE6Qs/tLCjEIgPr1Yjy6hywT94P4IU0oHo7xYxNQJVr6XC00AK+fFtIs48J4RjPGthyeSR3J8rBynCCQPdpsPWzL596Sty/XJxt3cfg6j+mkH/wM689XDLkD5asc8QavGs7h85UhCbUTOAII1e4tfUpZ9sUUfZJf5re74HpLX5wL1cZ0tNlWNe1HPOt5bFNTw1/XvTF+GUh+H37c1hi3MLe+kE0w00Y0nkaTd22Ai6ez+KWuYLoM3EU5br/QK8b2XzV+QO9fWBENxeYQpLCNS6XvQe7L+6Ds8G5pNLRxM7b9nH7aYTkSzroJL0ShHYoQ4/MExLwWAqKZuUYvaiR1n2fhvsFi6l13FLu/283lCXXcNs0UfBwnMexX2+QVYE5eWifReMzibzmUCaee2OFA4meFDGmEI5NlYbpdnU40307VRRU4dGPEpDTKspjRhqi0n/KFDI7kIZL3MLI8Mkwr9GHKn960PJ8axr/QRRPD9sAFfoBrHB+K+YVXsX2Wwto/voJ4Ky+BeQlI9gpbR+KV/TSDJdEPGysDp/6tkLdSSl0cqvEom2K8OHtHz65uJ8cwjeR0Zpemt6YivcEHkBxZAFc/isBbtM8QXWrDcyKcsHGU8fgnG4fD9q6spt3Cep9TGOfaedgv6MziDaJYvczG3i7Qg4efwnE6ctFONk/jG/2vQW9c+fxRvphCGzfj+b6YSzzCOGxZzrvs39G92eFgsR5huejXsItcWPYkpfNITareY92J473EoHKDgUI2TYdgwM72ftmDVF2I5u1PKK3i3KgwnIQouN24k8Lc/D/tgtt9h/kc9czaHbPTawV1ULQboIC78f00psg3ycZ7oRpQZR0IzyYZ8ezy80hxSSUamJ2w/7R6lhyOwxqlBXwttlYDq0bCx92VcH1sBpuiHGC6MW53POtnpccTaKrntVw488GXBthx2E9onC7SBg1Dg6H2McOFBvdyFcta3mUnDgssbfh0oh9VChdzLGyZmAeuRSmBp6ih5POs76TH3sq/gTru7vBMj0FvU2aQPf0Kyx6YQMVfydBrtQmOHA+Brb+qqOGKxpU4uGOG7Qv0bGO/bTlkjUOqTTcOeMN/qP/4hGhIrgcIsNnb1rw/pXj8Gp2ChX0jMXQuUfZt2sipHkocED7fvAac4pb938FncwIeJcNFDyxE+54H2H3sq98V1oRqtZuRK+WgiGPvoxB3xrh8mQHXO0eS94yBnzQ8QRFh/3GpjpjWCIynMy+D6Lkl024xXMQN78+RZk3HuG5KC2o1DMm46lZLNsvBftzI6lwhxOeUTHgZv8PQ+4VA7oiUejd7Mh7ApqxKjoCDujrw7CMtWjlLA5zZ6rC2+1fUSTiJhw8Pov0o5/xr7+3SPy2AZrEC0Nsaz1klqjhZ/0xnJKbRfWSzrR96yzq1UnnqKMCdHWtBlqfUIEbrcvogMIsTN59n26nP8MKXkp1t3Jh/EsR3rk2Cu8Wf6cLLiawsekI+6pocdKVrRRnp4IzjzwB2933kOV+4Fy5At5s3cKTRQRhrdsDPqP9E8z9WpAqN5PPfWf8W1g2tIcTKfJ1K/68XcR+KVZQOqCChu4z+NjYItbY2oF/5uTzjAZrvDlvHl9arUZC/rqUN6AKxeY6+EvOB8S7DuPNxHOk8lQDM0YeA9+9YbB38QisqDBF07W6sMXMG93NF1GWfxUtcDwGCfcrMPCHFqVuPg+DG4zglbAVxynoQ2TjFqLMaXi44z4c75kBkarPsUVnBPnNNAUptanwNSQGdFaOhvXP/qGq2ib+u0uDkmwayLaiCLdaq8C9Z2188loKKI6zAkPZkaAbMZGnT3vLRvXjWc3yNl1dshHs44TpX5Aub13kSGPP/+G/SiKw0WUVnzViOPBhGWfOOwFNS87T23NirFqQiX1u2+lXVh+LyI8Ay1VyfH79AITYbKXegyYs+bMDDK7cwJ7On1hrmE6dqa+wymIyCGq958TCS/RznT8pv6wmV7N/tPLBHfxUqAXigs68tW4XGDRLwb2gd/C+4Ab6WfRAe9M2Cv6jQwapwuSdf50KP0pC7GztoQ4TAfllWWh87zWF5zVSosxGHNDOJnmlGDr8wBhu/fcdtUfqQ9dIQ5gScAANcBXfcF7G6eolGHA/AkO7A+m5Whjt3eKNmjFRuOG+MUibb6eqG5oQ0RvFFu4jsKdgH7bdecr/YDRGnHhBqx73o3+pPox5l021WffpuPBrvhEyHE7NH9rz5+IUEbqDckOFsLn4FellqkIXWkKFci0v+TKetto0Ah6uY32dfqg/t4DWHtCChO9T6OZbG+gT9KGNu6V5adAkSlONZqVaD35+JYHzNw1niwkvOVCxlk7L6YFH5RmQ/tzDkS3a9NyQaO/zatpcHoTS3khzS+vJ10ISro9TAq2UjaRa5Min8ybAwsP2nOP9v/c1r2F2/giW7OvnFRuWYX3RCHjwZgX82eVKwdPc2TH4MGdbGNCOLcb0vryCO02GzjllK+zStoA7Jifw21ETELMOpV35dTAmSBD2fHKAsF+DcHtGOhv+N4HS1kyBuZb/4LZWP19MmMqlT7zhiFUu5ib5ocn1sxTut5nm27yChR1WoJi7AtPDsumu8gg8mKyO/+Si2VpIjF1GpJG5mze7LWqHklh9sNLvw8CeKD6ZawfRd5ayk1EWpZ7L4rCSRJCm4aw39gY7jdQD0eHPMC45CwR6HfCa1nheFjqFg/WI0LIQrv4+xu6C+bTyngkktbXCuuMJOHo7sGTEGQrycuAbaVMh3zQYUz6tRBsRaRRJFoaSYKQROm4kniPMKZYqvBcc8XvdBNxxM4N+70qAph2tcBnHgk3uItw7PgPMXkwnkRXd/LTGjS++9qD8sY9o+XND3nK9mYNXa8LGdwZ8vK0Nw8ZH0rkafdze50eT17jjCOsVkKX7nUp/G9MNwQkQEFqDewLVWTMlD1fUvCfxeW0wWe8x5+05xNeUM7EpXxCueRnClvavfJT24jW3YTjLaQIWTc5jWacTdBg2sIt+GSYOj4AJKhrQIT7krLrP8KyHDtSeP8oZh+eSsDXC9JfXafIffQ41SeRkPxUozq9A1aBiONjgyo8+muCVuBZSxC4oDZpA5/UGsfZhMs3IE4Un27Toq0gonZ3TBQMW40BltTW6duTAFSdnMDf1YfPkE7CyjeH79gb4uEWUV6adR9eE21DZtIFLty6mR2OHU8ceORKZIgToIACX7iyAGzt7eXqoKi2tuMSX7z7DJItYnm+5kZ+s2M82luLos1EaQt1+U75YL081OQ/RSeIQdO0qvj/rz2k5u6lN4xZV3FeAYQoIFeFB8ErJC76+XEJBEpp8oPQIN3pp4cVxUmQ6xwk/fx0H18TF4W7iNRr4tIosnypB8dk5IHAuHiunv+dFQ++2d4ohR2dXokm1KCw6coWKdePo29gpcOa5Ghg+rkLPOEscc68S5sf/5d6jQ1wuORqerf0IwtezqLFnNrx4UYhnc//w75WhJMh61NbaRLfsHlPhfnPwlCzmmdVm+Ct9C7aIDOB3V3tyvOzCL9UM0SbFj2V0NLlzyMvMRMfQ63IJFGhS4pBzvjxmvjMIVzzhvSIHYYnmFXrdnEQldmbgMzhARUXOeCHCGWZXm8ClGe68dOJJOqO5Gi8eOoxi3wuAV42G9LURePiePiYotvLfv0FY6yQMSpNi+bu0Dz6qt6AGzUQya9CAoAsfuWi8E+42nMfw7y4X/3hKbal1qDn/JN25k4DXQ2rAIVgKfD5ug/2KGbDgzR7eIL6XLhT5s5NfC82JcuHqCnnwXZyBR7xN4e0+XfSqOAcrZsymZ8vM+ZXdGcjqKOKKUW28q+IqXlGPIpXd1tD905FKspajxqSJpCVwgX2/hPD7TzPp3mJ7UppYhCM8ztDiKiU40aYDX83vgWVfDh2xiqWTSbW0S2cbGclegNsB+6nKN44vL9CEoL43+CZzO09+Iw9v7er4hnEM12kYkoOjOEpUv4NxLh5Q4TcJoqca0PgH8/FDwAHoq5zKCcIBlOGYDsNn6XKMz0RUEzsAJYoj4YqcHG4PTsXjLk3c/fQ8xmY8pWalDZB69R5cN57AliezoS56ElBtBr8u2MZ+R9rYo2E+RoxIBh+pCtg26x8JvbkJ9smLwFtFachz2vjEsvuYXFaNL+XNMIIdsWWUJJZOjqeBECmIlZdD3XZVyJ+9n474rqbPcwzhQMxelFouiVtrJvH2dDuqzV/GGyWKWHeEHowJCadP2/ajw/I3UHN2DES5bAdrpxJW21wFV2O7yf7MMNKZqQEvLG+yx2oz2quHtNe2Gyw22lDfBkH+4Mk0Zk0BV4/6TCU+E2Hu8A30Z9cvrJ1F9OfOBbo4fC+k2d+B68Of8MzrJtgRnYMv/qlAXrgzOGR0oGpPLPjPHw5RPaogdSgZq61ceW3vOR45MZXtfhrCCOmhjnYSweeqMviiPYTvS+5Es+FmeEzzJG07dIVHT5Oi4J+jwf/vJPZ92EB0YhWeTxTk9ueXOGqVIoat6qDpV+egjkc5fdplBrKFk2EwJwX3Zv+hhM164Ncazo8vLqayyLGgW2wEATu+gaziJPhV0Au1cbtZfu4otAr6yksmIDZpS4H4q0B8pZ+BXUlWcEnAAuZ4rkCDLbfA3s0VvJVbyeDkT07wEYbEXg3QK7zNSmfXQ5c4QVHRKlZ9rkiT/pnhjDDFIb5dTy3OayFokxYbeSA3f1yEOoamMFauHNsmPucmk3Du8fcF/ei9qPtXnI4aBZNvTDlZGEnBGPux8NtalVZuno+3B/7wh8ZbsDpnD3c/HgVV6qfoEhSSmJ46Sl3UhzWzP9Kxl3dZP/crSJ2QQtVTT2BqzRd+1HYZZPMC4YpGNMhOQDi1dMh1fYjXV5Tx3G4pjgl4z3ZJO+B8ngWZmZ3k9z4qUCA3HJws9OhHjAPt15oCh76r8KF5hLrdQ4yy7y9IXPSmpZcaSWGdJGx8shZXzl3Lg0NPwrUUqjQPwk2+ovBtwSCJT/0NY+yGw4uRGjAotg4CtE6z7bNK1IxHqC9GnmaoxcPKWikxUgbr1gXya0slmHbuAIgZhJPo+/9oZmMApW5v5I0Xx7Ckfxc6aHyio/164BQ4Cb49PUc3nl7Ch1K1vP6rBYjPE8djkdvZYs1Bqo10w7qAfbT0z1iYmZdGffY6INJmQ4sHE1HPWwV9nwdBtN4gTyg1YNlwY1xSPgVSf97Fr/ef4YFrC6hpTxfHDLzGv+8aaGnlQug68AfnOHeh2vfJkFdsBS+vNVH5E2sW23wBd11bRqccNkH6fSXoPiIDcx+6cHMtwp51O/nT6xv4OOYqOA/5R5O3OD1blMmhBzqQ3j4jMfmxbG4AsGPxGygfsxcubrVicYkPeFR1FKRfCqV5lvLw+9pmjp74EsIPa4DfUOaq8xx4dnUcF8ROZ4tiwHOfWrAiO4DsDT5zUtVIip8hBI8V83Bd/3oWNPfkD7+C6E5zD2Zf6kEplZ14bECAkqXm0QhJAVjs7UWKro9o7ZUh3ny4Ap1gDc7qEsaum/4w4K1LOkajaPIrAQjzjcYF74U5pEiRjEyEIEjAgKMFwrD1dR+NVD6Jqouu42EXeVg0bSk0q7nCq7BmurPZG7Nya/hk8S62NymFBebvYdn3OD7UNwqeqUjQXvkkrkmbR5rdP1DO0A9Wiw3AdNc6Pi8jDV89D8HvE8Nh0tICuPOtiq47SaKj9FNcoujIM74gPbxoAktKLeHItgHY8ksapiv9IXfJ+WCwOxBeKqjzW60LOKbqGXd2zOXU2ECaYOPLIyuHAaa8hfJ/eVS14AM4yNVgeLcD5StMADHh51zx+hBd1BSjkw8kQDVdidYumgODPbFcKt0MB4wHYWrIeTg80AZTHk4AmTOLIXitDLQ9cEeTVnvQ77Oj782GUGFggErvzoFcoiKd26tE6mmGMDLGGFyHeP/C6gVQ5yXBrx7q8fxhrpC69yNJvriLY9c3w7yuMngyWgXK3dPgXJkpOcWs58LaEth2LgbfLSiCnEB9rvkwiu41jqMvTwzBSjcaFvwp4JNfJSDQdQTlXHhLFa9PIBXXU5zUcZYc+sZCjxuB74SvoP/oEMm6raC3hSdw8LEl9n28BqEv50Bl7VR6OXgSnRzl4cIfRZhuH8zRV2LI+L0Kl87zgXRTG/6xQgi9G3PYa0Q49ZYow8bSeqhR+QZHou6gTrQFTw5TxgHXVv58QYwWux3gL4UtHCgpDyZjfMHvYRafLJdGD9ksvHtQnK/EzeM3nx9zmYczyK1bClaFY+Hz96+wrDKL5+vkwLySNM4sCQY5C6TuySGwLSEBQlcPsvUda6CGTlo9Px79FFLYmpux3NedFid9oqi5y3hFsDCG/vSmYboSMOyML2t0LOY/muHw44A0ppqY4iHT43zGfR16i6vQW5FOnMkisOypDWmcsOPOHAmoFn9IIUkjaOnC+6Q/ShvP79MAk8Yd9PboRJji8x3GNkfC1KhXkBeTRG0t+8CNr9EFuxOstiAa3C/W83+GBvBk3V1yeD8bX7gvQ7N+Wbp3TQSCp1VQ0JVpdPVyC1n+EYQQRx0QOxs/5PkRnPFmFBZRE4a+baCdA1ZcHf8dRCN+8HyRVpzrrgiaDg/YSvgKfeo7QksDF6P+gQfkNtBBmpJTqXdLHBmkTwT/ch3YHxdIF54e5lViG0FrTQ9M6nPFl3oBsEpUAdzNN+GM4HKy6xCH/1448qqdXTh2RC8KvDbFXk0/Ou1WCnNy9aC0p4ql3g1x/NmhrkkOAdP0p+hwqoTHr5CABdELaMQSdXpoUYUtR6TRbIMj/7prDQ6Pn9EMWXU4GrkWzjSNo72GUrih5jRHjdpN+QuLeVXoDA76LAC2I5bQN595HOm8G8jInCc+NqDNXky3MuZCxsVPVGd6G7K2WEFG4W16p5uK346U8cXWv3yrSIYePGmhGdG2dPLmSV6pmICPNgnCvf+s2e3fLOzOqwQnuxoYkX2bzHR8IHn1dDoyz5zDr9tDWswIEFZ/SHlaOcD3NPliky4kDFdlvcpblGe8CnFZADtlCPC6i2qQVryHFgba0GuLjxDnfhRL9y+ie29vcXrmXBQc/AlbI8LBZZ0IaI87yYKia6B/VgEotGdDrelojpQdy7H+bvyitxXFBSJJdII+jHQ+Qd+7ToKGTwLe+JBOcFYHZz1xZAWDdB7YmsUW0Tvxv0EduKKuC0pJVfC+xQNnhoxjh9sAn39f5Zd23diQvQq3939jq+sy8LFRh0bPesf3z59C/cXTaUbSZNqzOZY6b1+klxum085ceUyzs4J7JrFg/0OSt4Ytp1terljxMRPSF9rS5MzT8Dt2LQ57d4qN7htBjc4edsvOg4W/l+DdzgMcsyQVJzdsx1Wbh2OlbxGvjTuOyjJqUDzvIkmXj6bDWR20579eXuJzi01pNQj+cuHWlVJ01DKW1vgLgMCsx0O8G8PZQi7s/NWZxi9xheJCFf5mM4VEM8ZAhvIYFM+Wgh0ltbDr+gDa3xqB92JrecN7PVadVYs2Vr2cXzcKmlJP4ZkXMmC5eCf5t4qhz4YXLJ/9CSuGl/OMcwfx8XxNWOI+Ay5fTqTomxawcLAKhl83QmH1f9B+2x5lJJSpYtom2NbwFyq0CrhG0pw+JqiBkYkKYZsEfUzUwNjQEyAPHtTufJzrdu+k2ZOmwcGIQnxzRAseP28Ck2O1qGR8lLRLKjjSXJQmdlqQn7Ashfoog6uPB019JAI7dXbTq9+38dFDX/qwWZqr3ceA3xw1nCkzltyW29OGLwG8xkAWgk+NwEnNsVCeP4BfZV+A2rIyfiD9nbTPCGBQSCBv9iok33/mEF+7C2O361Lo4UicvPshq9ekQ5yvKa28FkYmoxF+6Pzm921akGNmSzcfFLNu93YQ2jweh+/5gyKn5FChLhpTXX/iVC2dIWcWh0Nqs8nplwN/raqhjb0jSe31N2xwWIFH89bzRbt/5JzSCZt6laD6XiTcCzCD2psfyV3zN1vmisEwk064edsKyhNv0DePDkoKlYJzo+/Ab8WnlFNoRG93xlOaYjRdK8/CSeHvsXrKDF4cbcxyOwQhWmIvPjAk/jP8PZnJrwKjCR9BsEgUn5hU0/KKgxRw9Dr5nhCD87nVrJ3rhNtjYkChoIyvbb/K6ZLlbPqmhYbHX4fzVczpkRNhaZ0JlYd9o5rklTw2vhFmPitF50VrcZfGcki/dwOqtIo5XFURom+vhJkhn+japhv0efgscFEs4oKj9bTq1HW2CPfhBffmwCfxEVC9V4scx1zjqQvi8ESFKJDdHXoy/DiPWjaG6wt/cnGiNy/0NAcB4XUwq/IiZv3Kh8K+BXS1XJwLY/t494hl6H6piNMsrXB2gja4316H/9UIwqTcZWz+0ISePv2Is4KHnPvIUP5epMHTrHucO10bji3TwwV7XbGlr54nTBKHNKOnlPVzAZk2TMH0eRtZDHdgtIYVQHUaPjQVgVePani3tQUa75SkhzNnwebeNRx3M4vUUsfAlmAzWJmqxqbLx9N+qbdYGbkFv08No0fHXsAd7Zms/W8VY/MhiAnVhbOb91Kg7ke82BjJu23l0eXNc45GSUjx6aTTC7RoVekCuOxjABfjA0Do4BMoNNLHmZrdaLL1EK3R1xpiQhmuivgf4s7zHaj/jeP3ICojm1C2rKIkKzKijIqEltIwKkWKVJRKiYYiKaMptIRCQopISaRvCqVJpGG0Uz//xe/xuc51nXN97vv9fr0efSqG5kYbI94KwB9hfX7suJxPRJrA98uPObf3Is3ZGsWWZffQ6PVGHNOogqm3hSF7mymctc6m6ff9wKTAib3WAi4a+ZxWeV2FxNfeEFCRi4mfzeCD+UdI79rNYf+SoW/rIOwvC+ZXIUuxuesiHr4fhGFtutyYOwUWigpRd9VKsnHYQmcvLkBjIx2OWWTLn2LP8njNreA5xK4jVCzBWtCC/VpXYkTGVCoLlidJPEz9ZsPQOOoH/ngeiB0LFvCOkaJwvekZdk5Qo/dhM7nJzwW98kbAvBXVMPLpIRbUvM5yqQHkGC0Nm2avYfXLlnTn2R3cdb6OenMkWSVJkVQCrelEYCUL/vxI6aITIPTgQcozLIFbLbvhz8dXeOUHosWGAPKZ4UkdMg/wrNRerPUygZ4383jyjR+4INhjaLdWQPmAPQVc/8r7j87HCMMTYBtbQymyYhBpHoVO7d/R11gQXIYXQ2DCBzz/Zg5vDDaGkt278YjgaOp7NAxmRp3GsA0RvNipnJyKfnDjrGLYNuSWWqorUbBmNLtm6eH2KwrQZzkDJ09ch0+OuvP6I1tYaMooDmgPx1dmF+Drl2/wMVERvjvqg77GL87L9OCRuWNgTOxqrjccha/yxWma9TXquRiM3yyqOdldCW5u+kR5HrZ8x+kTrx1O8ObJcAg4V0xZDhMgZu0P2jj8FU//NeSNNprQ87uANlqJ0ajCNjzeFkSBcyZAwblMGnwxA7oFtKFglyW4/x0BybuKQXNMJn0uz+eTHyfzwtyt+EhchpvXlFOZ93KY88oMPOalwemAXdh11Zgm5ptzl8Ba3P0tF16mrqebkfU4SmstNenIgMf6hbhjM7O21Q94OjmH7m68RrJBq3iSjw7+3rIXJp25jxUjlCD9wCG+7JtEzS2uuKGigkbX/8Xhh8XhX9dh+OP3Ha7jRs52lQGHkXdIQ1OCQmo+QmuUHnXvKKDywlvUEhWAm8kNZ4SZYFKhLNxJnYuTDaKhU/wQ1kqUgn/VH/b/9gZtR/3jG8PGsElTEgTKDIOb1eFQuHAm5csLsHz9Udz0Z8tQ91XzcC0rSDb1xxaKQpPs8YAPPXnf0xEwTjYZLRYJkciRJrSdtBDOar8lU/s66o/3gQs3JsK7LXoUDNMwv3MyPrJ2YJ+BcBp25Dy6lH3i4hYJPD3yJz5aLQo798yF7emPqeSICZw7pwQ/uiNxX/NLMI3WosSnPzBlvQiqW46FoAwrcP7XjdNr11GAyGG4uN6FjY6akH7tIhRtNiJBJQvujJCG/JGfuUG4CAPyS/nurkcQV5QDfjONoD7wDkw4qstWzzPhxRYDCPZv5Mf++nxF+DiuDizDsbIHUXHFWi4eZkxxt2Nha9Mmfl1vCo6/jWlwkRm5nxvKr8OzOMXcggqLhEB2wQNWMRenM3iXRFNkwGl9Nb5Mv8pmgtZQcuw6DhPdiW+mA56U06IlVXvI49B9qs8WhvFjQrCv5RJkmWxgl52atCJUmuRfmiKOSSVLHo7RGcGU1SgO41uUaUSmPOwJXcx3+jJJRMcBgztusY7eZv4i/wWFutWprFseLgf00ej4J7Bt1R2UfXiQHpEQ7/v1D5+s/Aem1hKQrn+cltlJgJ+8Gt4VVRo6C3uy9TiCa81b0GmVGOtmivGtnnX4/IAAtcaJwHeBQhbfK4+as+/zmslzUCziEd4TEab5dXNwf+YDnvYmHsq/IjwP+oMDc8/BnovH+dSFFu488Qett65jsbSf4Ke2AE+vmgoGebKQvnopqz1VI/P0YyjROZ6HL3FBPywET98aDqoOwgPb3eBA+RgYVU8we4TF0PxOh263cNC4tpiv/Fc65C7hdHu2NgyeCcDyUIZ/gmqoHOYGR1XP0yivuyQwNhQNa/KxWGgA1Z2mg8ubBJzK8hA8sQWtLR0hduU39t44Cc5GlvHmgt8c+Gker9CYSXvX1OP5Iwx2+5IoSHo4rXhTRzVTbHi/oTc2907Hljl67PT7IAeKhPK1VgF4ZJoPZcd34HZRfxqfHciN2xOgX8KedzuIs2v9DE49uQ+mmwvBXcUL+P5eP4/+XQviYa0scbwU9dxPYlN/OjQF1LL5cCHuKVCEmr5CHvtMGCNP/6NFV6MwVLcL3g7expgTglR0S43n6PTR859WkJELMK/4Kfs9EKS/dlH0dPxherdjO6elxsHgUl9cmfyNvWaJgKzyWrANdcEOy3ScvMAXxH5cJO1KYz4xMR1nb02huk9jwKFcBOwL0jlR7AcdW76JBWeEw6qLAig6PBc8TPTYZepOCtd8wBUgD8LaN2jM+xx83e1OUWXveY7xKLLI6cZdus9Yeawjl95Og9qG8aDtOIa3258g53uyqOPZT9e6ZKlb/zw1hPziugWpdN3FjqdNHQlVP5pxsFIci68PsKDzUwreZkPRy76A8Nk3UHjIg4MvueBOUSPYdCKQ+q71oMtgMMuGbQCtf7uhImECtIzO4W+GqWRxIAAtpabAs+sbOEXKm7DnBh+Y38o2jx/SgqxiFlRMIN22Dr5m/5K1J40Go5lRMEquG4ut/nL3xJtYO3sdxYxZx5eCX9KhzcEYU6PMrjniENKgBwfzx0DjtNPoLfed/yzZynEPhUG9Zjft3rmcRo+UZPUMS3g34yLqaEnj4zYTnm/lxBNXf8K4oe9SepXAN7oXUEXHB0p5NRVEtjyHthJJGjw8FxLE9tB6jWGQ6R9H2dPO4k/1BrykeAaKREbC354tuMw6kB4VScGFp6PRfyiDRQ5n85FnTJ8fiuJFvXm867ghHPDIh567NjTwbhlaRC3mo6mZ2LKQ0VR9PCbeTsHTI17C30gFOLRKlSz+ZaO8lA8+7xyOXlp3GRc8JtXI/zA36iqbv5ACzTRhUKlTBomRU2jHlTlwoc0SdJT0OXuDBpxa74EJJ16wZ/MziO+bACnLP0Oc0hts3zMaPQd02euIIvxVKqYpYSv4iesjyAx8CnXbxoHeWyno0NqLa8S+suw/dfip1oxnDJ5iulgavrWS4qn3eyBTVwB6/ERQ2CeUDwi84kFnYUqYoYqbSwtoxM2pJNXykUqML2KavCE4TDhBOxXnYFeMHuyf+4uvDLjw1/plsDM3gc1/HeKX/VLoOU4E8p1+kNa/Pfx97x+aexVQyGkbfklKx/0ecpgpXs5qpQ/ZbIU4vNQ6CdXjT2LwdjmwK58NNq+XsV21GfT/a4eBw320wtEQqxwUoWr3M7qiPRs2bBoD9wWnUaNbBGls8wYFjwHSn7gD23d1UsWQx++dIQbbk1VZ+9s5Dt0YSDfIBMLqI8FWJZ731Elj4apOXG0kDM2Fd2hRUAlv1PnG6Runws1vwN9D07jCqoEzshfgyR2yrK06Afway+izWRkG7RYh1S/KqFh9G21tHGD6zXY8/3A6LlTu4/pKfdiYdBkCx7iT2iotGnjrgol24/B+TwjsTvWnLSFPWdj9AXbMtgCLehFafHUXo00yve+IJu0pJnjkUA3vDWzA/9pCYLvQMxz4MGVot3rgm6gz5FARLJ5/nmM3RIP8qSa8dW4K9DZ1ctQ4bfobowYuyY1osOUa92Mwjmx4TS0LZ9Aeqflw6XkMrDZ9gvmJX2HNEWvI3FfOomtraf+sQ1Ddc49k38wls6oV2Bo9jHdtN2WXL0UkC1Nhybk+vF/gS+//TWBrvMNlUr/5MPjQn9wVuKToIzuN3sjeampgd6KbI/4U4fcMB0hub4aVmIVuz4oh/ZUIxEY8pYQRJXh/hzb47HoNdcc8MX95IML7iRBn4g6bj80l20Az7ln3AlpS5sLroonQuuAq/tWJppUeNTRn7Hn4ZDUFRWNXsnuSO4ww9wLRjg7ot7SE36ZZsP3td/a/30WOmkt5VdoZTPN9T7A3hJ+ZK0DquhBamD4RkrY5oUfcFpC3K8TQ06vRXS8FPQoGQe3ZVHK5SyBRUkjn7WTg8btayj39nfcVu9AT7cuAIrMo9MIHFCndxnqxG1CWo/C/fANouTcaaF0qpxzXg91eUaDQ+oXkhs+C+DPTYarrL8wqWIL9p4aDAmnh78I2GDXLlR7LniGnrz95j2cemy7L5sI70rDjYQU0swH0itwh930jufW7MkzXvQK3vC+TR3Ii52X946o0Ny554szNRRZgF6PD88fsZ9mqvZyWEEF3Zu2kyMkfyORyI2YkyLJ+YiD3yRjCpmg52Hx8HnQHhvJzr07+KOYE50/4o1lNCym0fKbFJzpxJ+hD2C57UGqNpHPHczjV4iH87hjGor8O4PPsQozYchAkXv1EjePy0L7qHmc+dqL242do5hlD2tknTfWq+fhzcRQuM3Uls49i6LNhKlRpJNOn0igUqe3mzKHZLZNZzlvPxuAdvUUoADdg+/wruH6JJlxta+EnxdVQXT1As4pcyHlgGM1Wuocxq4NJx3MQB8v88WWfMOyItoVxrrYY6jqClvbOxbP3GWo3TIfQfkQPsRj+7aDMFgeUILTvJNldUECD3fLUtnkBv0uSp3KzJEILe05N/cXDN5jCjmQJ0HT8gpObPrGn3jP2XzKD+pSvonHGIZLvyuR2wxQaEPjEGS/Gw7VWJbR3qh7qgw84zrIWZnjXQZs6UFVoEO9SnkXHTnyjO+N1YSNq48bRNlj9aj0IJMnhJPfxsE5FE+tzXkLww7lAwdJkc80Inpz8j1auc6Mvb01BbHccL5CpoUMde3HE4g58uc6V517eRf6+0rBxcx18avDnHemCuHuqIA/UWZLlvQZ2mNDDXwpuwTGhC9hSMR6WWV6H+v7TfGtWOa4y8MYlq1Mw7Hk0B3kvAB4miJae1bigZyJktOXilRxJivELgUdmTags4Eii4r1kO6GJaxcew8YlYvB4lTFESBujic8TvvzoE85rOImSk4eBhrIpGfwN4GtqnrQnSYcmhEyEbkzg5pMTeeDWb1pflUYR43/wOK6gVYfWQs7sJhR4yvx9ogC4PFpIZ3V9yMuhDR9p7Md4kRaocfnA21VkyFTgEL+qvEvdQ3kVv6CGNEt+QHRqJa+ZEoIeKZY87kE1GWsaQ+NjBehoTcPJioLgdVcRHtgvomNjJ0BTTzCvC1wCxgLSrFu6iG60u1JW/HJa91cEXEyNcGXcVRRrnIGty+L56s3/uMnYDjN0vXhg0J8cwn+RzQYh+Fgkx70zT/Hqfm8SO74DEquv8kn9VvCw/4qj5g7C+r32oBU+CVZqnEeVuFMoid2045AItG9Rg3frmQoe2EC2agqpyH/Hw0ZC8O+5Ei2Zpgyy3UaUveoseC67CEbrm2GKjyJeef0N5WfkcNpUAXhutQyNNXYQDEaDjMsNEBxuAKuNDtFzz0cQ/FecMt7cAvcgOQh9LQyVV35i8CkTiEruYW+zAeYPd0lSJhk+e15FrtlOH0aoQfS1PexosYhFZSy5YWcsfbntx3fd3oJ/ZQ+3Jd/lr5GT+NZda9ikH4YpN61hkZUkKNfX4sZTU1Fh8SAtCbDCNb8OgptoKaY6DbFBfCXf6PCki3mR8HulOrpOkcVVNWaon9bA/xZso84qL2qXNIe/XlPo61Dv6CR9gI6JspAqOY8/3JvLprv3YcC+s+CSfwoTK+TAMr6DN0RYk559LInUL4dwCxn0GL6Wuz4L4Hd3VVx71otN5eThmmQn0r9Acq+by66LApCF3cjjlQXMLJ2L9x9ewURlZVSZrQWnK8fSjUxBmrCrhUahAYs65A65z0+0ks+jKZlJcMORyTNWFeTydgC0TsSUhQPgli3BanXrMPc6UGemHCxWNMCFoV0c/0oJ3pxYQ50/Osiz2IY91xnBfPVKeCsVSXW/zGD55yOo/TMdfgoBRLp6sfCvF3hF5SykujyH3ztO85PE4fzSbhetshOGiMuuoKY4Gca9DoP5wwug1UuAF6+MhZS7KlixdAPLRM/C28qFPN+zFu9o6MOJXTrs2qcLtxYNspzSNHhpZMLlm5fyaPN9cLI4lebZOvA8fwapzhKs9R2FZqMfwatyH9KenU7JksIw1zcD8x6fYH2hTFqXPwXaz58hAb9EbJ1dgnovLtP+JUL8RGw2WvrpUpfQZVJuy8eJ/jrQcus0rnWKxD25Yby7Rg+9zjZTho8gU9w82vViIbmtiEXBZQZgn+hPPknTIT1tIxeMfcwd08+hiVIllDonwjaTIzg3OwD8/A1A5ZkzhVdu5IcbpUDZ15Bm8jq0rnOjWUYn+bt4PQn/t4cWJmvC24SjVCpxDS7kNYLWZi1M35NLg1L7SHOxDU3ac4Vm3dKivPUWkONvTbfGPMGT1+7TUttADlmlQ0faopm2jeQbdw3AI3YnBRYYg9t2Keagc7Qw1YSn1XwmO9svFNnTjN/mHWI/5f944rgtNCVVA/TUD2ChWjzuePCFaoOa2D3DCeVbA0B6+W7+3qPKhvPUYYb/BAhX+cyHineSrvonvjrUBxrJ6+DeD1Hoqs+iHfkGrPDjPMndFof5GnNphuE2Fj68hT7a7eLf7vXQeUiSGqYG4hjPl7R7qR2+e2gJHYJ9XFAVCxuiI9n3iCEtC/vHskfOs+HaPL7nmIc3jrTD4eApsG/YbbC9vRvO9c0mU4/nJH8okLrfv+TMB/fosks3jFJMQtMzk6F4szwXGzuhzj6EIOluLJghSGIOS9H0rhmu3pCBNurv8KGLCohlS1FdYTG80o8ntSf/YelWW7zsfB+yKvegxlsAC4te9jiNcLilGrNuPeKzL1eyaMRb6hO9xcJ3gK5vPgm6wrYc1hoEX1R0oK12PGmdPY5r4B9qbN3Hn9uSaLDoAbDMXuhauYS2nZuBIa+GwfbmFZRV7AtZttOxPzkfK3I/8OlsZypvEcKoDiWelS4OJw00obn6NYd9sOZL141o/4SVnN8xHMuDUkh5Wy1VPdgJH2+LsMO8KWDXXAL3h7p/Vd1W9Fv3Chf9/AVKVat5U+VWPDg8gN+FOVLwZkUoNi+hqY1XYdCyHj3WTMHp7e3wpXo+OIz9C07fjMHdWRWK/cwg/noo5XRJofuGDG48qkAxd6pZ4+IpyJV+Bjejg3Dm1g3sFicBwwU6KNbbFMNuC1PirMm4NCMTFlvcgpG5n7h06Qfw2G3D8o8k4XJQP++a48JC+ldps981PidahQ+OPeaWi0mosl8NtpxcwS/OSsGJFS3oqp0AlffNcdXFtfRJqhyuCLlSXstpNvo5m+007Lh3nDrc8FuJ/xn30kI8hLnj3jM1BOCxld3o/LYWpNur6ZuzMFfpK8GcNTJw4MMKyri6j73L31B97XnaVHGARnS4s6GrDLouHuSwlWIQJX8Mq9ZuBS3vAW56fZJ8t6+AfZvsOa/tIvKiJnTsm4vLcoWh6upB/hHmwjKmaai62Zk6ToWR1tx4Kp/5kzyfbaJV23XBNM4KRtfEkX2qPH4Pm0lZmpfYfGQj9/VMheOfNUGxACg++jxt3zAMxvaOp7utSfj35GzyrRCEV6Zr8ejbFZDYtJ5kO9bjM9cYGBg0hWE/N9Oq3FC+d+4sTaw4SlqhsihXeZVNs9diakUyvLleA5l7pED91hSy79GinQs9yOFmEIoodeEpJ0sKW/acJDJKQbA6jiS2jofZXdPoh+oKCIw6RouvHKc9iQ94zp1loFDVTU1f7cByiQ0u9NCAY25WHBSXga66+9BA6DOoVebg143xFDTtLdhMl4RngXepyVsIvr0bS6P8YmHsv7vY7lIJi+yK+JpPNzeGH4RX9rO45qYjySapQ8SfTsh+IAimcIZ1fm4B858h5HEyBqtTRLHk2QYy3P+KtYzGwcgUDxKZ6EaV+0uhoCobmjw7YaRtKbVHvoI9ttOwyOk4fJ4pAo7l4zmpoRPm3nDBX89MeNKY6ZC/ygda1NyISr6SimQqfT9pDu7qIyHksQ9f+7KW8/a74tg1S8BR3ZH68zbhrbbdcHv2c7Y2N4fj7qvBLHcVCd2uo1GfVsHI5cbgGhJOo0oj6W5aE6SESgA9nQC7BTLwzGRz+nTUih8NBvAdZ0XWqH/PpRHD+YXyABmNOYz+4RMBa2N4fehOGpHeDjte7IZtCXm4Xj+Pn1vHseElQb4X/gbWVOlC6J/XHJo1jBZtWElV8g28dHkBJR9vo+JJl7k/y58dT6nB7XuCcP32M7b89R+d7l/COrECOKAP5KflAzulLuGxDX9ZjrQhNcAIyir/8mBMKH6eNAW6PT04tjqVZbeF89QGZ46MC6a3F6egVp8ejJwcARkCWui1QopydqyjNuE1OHgnH5U66ujk8UrUtxxybwFJqByjTKFbKlB3ajbPlEjhx4sZZ3u20vvU4XjD6QpEmKvA4f6x8P7yRhCdnof/nhhxVbAx659Q55vfYvnHy1Pcc3863XNx5IVmBrB99jUsdx4NAb4tvK6qeGi2Lflx2mx87OwDv81tyPjPFPi2RwEWPjgNreL5qCz8jmMmJoBU2QxQDBWGpV7xdHv9Twy6ZI9722VB+s43/jJTA4qSm2lXRRosnWWAg4tvYNjsRH7x6xIcF9lFQa8mw6q/K2F90yP29rVBm4JuXqQ4dEYedlwmcJh+H4iB1ymF7LtfB44HWsGsRE9oy70P5uE7oSQknV4oKILZ8ssk3LwKoxu2sdCVEXDbywqinyzA1oEvZOUVwUfibPngpFhuy/ZhpQwjXH1mE6QdkoSomjwuPe+Fxxpj+dqsBSCg8QfGvFjGzaumk3nwcb6WchDLT+lD6+4ZIKuQC3mNDryvrIErdpTB1KItoFtuAQnTHcFEpBjmSaqCu/JC6pwhSo4BX0F4Zjc3iKrhDZWdWGInTlZbZuOdKyX8qNsaZrmVstzshfj1bAX1G/dh3g8h0FBivFz+mjUS5kGSZynkeJrBErkYfH00l/u3VuKDSzHY8/Eq/Jx+CRpHf8QxyZGccHI+/P4oCPlz9Pjx+muo4r2J++r247EZf/FJ8Vfw8p2PNy5MY1HX25RRNhrMdDfD9tWydPRGGfioVeB4j90UMWsMSM8Xhi82MaAtrABuxxVBZIQBn/W7BOusT8KxFdtBbsx6UJhlg7kGv2GFWSOH2UnC1rNG8ND0Ei2K3MoZSucx11oBvowdmuuoRN6sa4iRtx6D36UyGLF3Cox7KA1rHppwmOB97HTq5X6fTUTDKzB4bjfX5E/glg1etHqfJcwSeAEZy6bRhmnObPHkBeWb2JDon70g802PYiULobTbnz+fmAArmzooNe8ruCeXgYeYAPlEyoOehSEYPxwFOz9t5hcmFvj0xVg4dmYLlZyTRrWfMrTgRDDL6esgyHih7Tt/POTqjmnhL7hsoRQ47MoF7X+P2WlhA6vX1ZPklf2s6naQD3vbw7FN7zDcVQFeZUrC0ouL4ajAOLLrkKelhYCoN5ksBzLp3cgEqgvWZ/G0JfhJRRKUthRQ8U5JUO89iJZ774F8rw0WKKpTTUsZjg7OG8r8cGypl4ZflqVwQPM9i4vGwZiwOCy73U0bc1PA9vdZcvr0nYvbHtCpc+YwxtsbY2g4Jr1SZ1UBAbCdZEsTgmbD30V/SefARBIet4O2vLcYyqvPVHbTh77byODdJf9htZU328w8Qgs7jGjquXr6uPgNt0UbQ+uUOXwtKIL+O6ePDbpX8OORBhDXZnT5Mo0+HxxFcKQGI7pk4L7SC5SdaYxfjsdhV2E5f3iyAa1T+vny0L+dOTEOb59+COOvGoP9aj0y1Z+GtkG/scMxC1uz7KBDgnHHxlqunr8FmyPTaDJow/SD5vx5UyzFe8XinInLQeqPBe85lUe+nZ08ovc0TGm3Zjk5fTjrvose9hizY6ssTxT6zF9nutHkO1dZY8cZGmvVC5o2ujD3ghhcuN5LYG3Jlfau9HvSMfqqYQq/tEeiR2gFLUq7D6Mn9nPuKx1IXSGEf/s66YaMOxwwcofT52xBtiabFrwn9hc4DaaDH9i6axLoPYigniBl/K1hiE3pobDSt5nNlG7Q8R9alBDqRb1n6mDpLXEw3JlK+jZ1mNKUAbGn8vm0tS0fP23CDg8i+IZMPYfJN2Beoxr8XJjHaq/l4c2eCeA4PJteno3kzUJb+eahaXQ9wgHkvQdwn4EqKDldoSZjMW56sRzerR3J4FnEEgdzMPxhNr77KcAyvXepsEcBtIetBVPj01igHEf6gvLwe9NRymxfhlUzDlBj4BCrX3Ols/b6YBC3jg30P/MmKqJsxRX4sLKCNAys0SPYkj9GnCeVthQo+j0e3n6Xoobxk2js73k8KnMTbwtSo7InnhQeLMu1+9Qxu8QDTmkqQXhnKrkO2wMq7IxubQeBjzejzaxaahL/CtKl7jix8A9WPZeCv+M0eXWbGe3yroIXEW8wTi8dvDfdgWW6w/D07u2suG02f3OTAqkIQYptn8J1ar/gfskl3KtpB6LrTmLH7LfkuaKWlwS8o4vX5KHjzytOyZjDd+2eQ2ehNLe2fqE8tyy88rEUT7/wp+0HK1i00QhGxN5gG8VZpFvdQS2zlOHLXBvuMZ+Arkon8VtkBYvUuFDgSEW4PVYfUh/sg2T9GuQz9ZTh9IuiH9fTuR1aOO5uL13XGEVPavVAXOkZoFg2Kj7uII2U5aQq60zOK3RZYtxBkAjcDIEhtlQjogYKxQsoLO8iYKUDf5DKwLUHVHG/w1Bu/7eYrOY54fTPsXizezxcWaKIPXqRpNOXQHszl2Njrhx7/PXi5/xhyOmFOGTOHFZNnQJtrdKwaksUPppyi+aVG8M6hVJ6dG0pGC1Yhwbvz7HP3488QkIXen/MpTPDPNl9kQIL0Bg0TI9FV59zuCzkCM2IsYUrWTY0yswKVskbU0p1KSft2gj3pllAcaYeJFyRIrWZf1hqjCf77RkPxlkKcMAgH28c9OOr45Oh5pIlyKXfwQsb9oDB62J+8moOP3+6GovOmsBAyyt8sS0EyVmS+mb9JKftGuyTc5wC5abjtLA6rIkJZMlGEWgT9iT610SHA3todeNE6qhWgeZmP+je2sOm9qb0fp0zx95UhORXd8lyNWDKIVOevTUGXQOieGKELj8fHklFk70x2u0AnUg2AL+JIVii3oLdoftor3wFpoZkIu2/ABf8FWDSb0Xc1nCSrlw3gwy31VxcZAMX1WzBLc8dzvzL4U8BGXDZMxvfv7PDpiwfeH1qBKQtOMdH24+Si3QohD7uxhv3m/m083jwlTxNNvdXwsvsJPwdPhzOzPpIuQom+M49hk9od4KJvhm+OhlCy+fsICuhHFz11Yj+7FKA4ysPUNb64zA2Jxk/5SzEru1DnLM8D6Re1fOhNAGKXvMA9a9Jw5l7Xpge9JYiMZr6fERpS9ZImi9STNO/BWEVzeXK+11k5yIOVVErYJzVJWj7LUCSKr189tp8Fsnz47+bX8CC0isoYHUSXAsQvPZOxPf3fcg07jOM2OjMP+X+QXtGD2v+8KfJ7kX4NTsBDq/VAcMEP/arADJZ78eHEk8Tf78IwiH+kOw+1CfCa1m++TkJHpWGvxN+QdctF5RetRkezWni0Fk1WBE4Hz5M1mKBJZd5kYkyrnWdCsf6jsLja+nU0WENux5sg9nRXuA2uhb8936lA+ar2MhlP+xUFYa/jZZgKzcS939rYO8BE9idl8BKb9pg+ewG3AKn0K/iP+7t0YcLZg/IUE6FHdPXwKllM8Al8i1c6nbDgZ21uDQtkix+HOTUV1rg0dAPT34dwnj4xFC4hF7E5sMFpdckEdHBU30f0d5nZpAqqgyjTHv5tOhH7M9jdpnqQo8vyqPYKEVI0QxkCa+77PGyEVKHyYF4VDZ6V37ihMFovuP9l7bFqLF+yXG+o9/H+mf/0aKf0jwtWRBC5gCsl9AB89NTcfK9StJ0FyP3bwI8q12Pb+zKJdtf6fh6rRBYDr/EawdH0JY/wK799qi+NZRXfh/GF3Et1+x7zdlqr2gOmUNy2ge0HCvJD6I3wXfL0XRpuznaDDNlSjvGI3pGsrJ0A7xMFIayt5fBp70VNTWDoX/vGVhh+A8cLibwcptmPmWXgVlG/vS8cyJkyt/g/ctc6E7zfjxs+YyLJXeCoN83VC2bBPV3L1Cg/Eveu0cNYjRD0WjgM63ZH4PJuXowac8kmr/xLb5MLGGFnx9os8dFnidqAnENa9B9rRc0bP/F42ui8KeGHk8XTCJBbxU+PEmVj/7pR60sc3ALVYHvyaqgdleCPZe58v1dq3DqsXncOleNxZems8oYR6h2VYF/q8agWGUhnrVshGKTFTQz04WjXl+F+Cn6rHIiHvPS9qGA8yRw4FtY/NMbOwdWw8wJ7VRwYz24tf7Cjbs7kJ9MQ77XixUzhaBZAOHoRWGWH2fPqmsD2cp4HR+LyMLrw6oxumU0Lhq3i5oWMQya7YKYCY1AXufo+/p02u0kQbcOCcGxZ4VMsdVcsapuyLcZTOVbQKizGZfo1GDjeG+S1i0ZcuFnNOrKWXIOXQZBsk+pskkY1mT3kde9+RjxVgPd219ihsor8vkRjKOPG/DeiYOcd6IH/7OYBE+shHGEoSsERJpz8GpNnOptjKB1E4U6fLEvcQ3f/dsEeZbj4dr6ZSDu34sa4a/46RlNypecCuq2dnww4ANbXemArqPhOLIIwTg8j/LbruNJ1OVpas/IKbUUN46NwtMFFjx2RxRutI6g0X1msLy6DSXnKsDY9k4aNXcPzzSeAT5LduNC5/O8K1ORlqdW09474+DJKHMsFZDnZv/7cKrlKhxsXk2648zgmVovflBqg+MLv9JCpzEwuSMea+Um0GYfW54wt5hlXhpQwKcJ7FBnQJvcCyDtri8a+ehCtIMHn/m8m7Y6hmDcmN+8/KQX7AgZzaoBr9AIX6OB/UPSjhkOn6QcUHlQkzV2m4Lm918scaCLXv6zQnvM596Fj6j6+yM+kqUJ16bbQtzFMfRn91mofXAOLU/t5LC6FIYfz3jkUU8c2G4H7pMmwYrk5TCn9wwcTwrB+sdpOD/ABhL3/mMXZQeIN7elmS/k+WWMKSiOdgPFgkg+3J0EcSszUc35BV9aNJInxW6CYu9YCrtiifNHyMOwsRfQ4bwAzuiXhzm+b1D8v6k4u+M7f+1ORIvG7Xxuaj+OTzWACflL2P/KO2qcJsK/gh/Djh3DYUFKG8y6I4/Xa4Nw5qPP4LtmiMcPLCNfwUVgUq9PTQdXQJTgFjz9czFdajJCYdVwiHw6FtoqRsGNACFcXHWTnXonoff7EdR2kmlgQiNe1n8PK4Z9BKGL0lSRbQUBr4/RyNQcqLItQ4ml8fC7eBxmh74Eeee5+FaviJos8nn198lwxL0McmVGgvK6Pp6zwg53jLWCiin70HUF4/qk+/Bw3z7QmGsGH5Uq0KIolsdkH4SgwSvYcbuA7YsmsVbMcNz99xk7JRmQfok2PMw9wNdf78cTh0PgyVDu3Cu4zHFXW/hk5Q9OcziOi+YlYqifPFxe+RMDlm4k7ffjqPGxCH7aJE/jKtdjYfotXHbmCB1eOhVjHFTBb+NYXra7CcbuvYWzJtWw8qMyfrNxEiut0mNPA09M2arN/x1Uh23frOHO+S3USvtxROJ4XDZXGoocM0Dojhn7tThTW2MrLeoTgR07D5DmuDCqjByOBd+7UH5uI66X84V2b1G+9KmZCydZUoaCHHRfz6Iij0QcI27Mpts/81+vcbDO/zQ2RN8C3blRcNHjIRqO1gS1xi5MHnq37sElnm14hXQTH7LYDFU6GrgW831FcN0VRXwgMRpaPVaS+bkZ0JnYjRtdF9LSaRk0wsYNZt5/zjNLn2HML0lY6a4MyQsu8BeXCIAxn2Hu6cO0V7qJ4yNC4W3Xatx88hOrWqRTVqsRHE0vY5sLSrB/mwJEPQ2HL2HH+PGHJVBStxY/m6djXkQLR/0xgSMDQej5fSc4WM+gq4fNICXYAmtLNrGD7z8uH+yjltUuvFtXHure2FL/uDW4sPcROSjO4BqVQkw68ABH1W/Gf3GlLHxZEibukIXRep2U8/wAXD9cRycqTuDHGl22sPyIG11kKV49FgVufuefw5RhzhFt6hfwAHPxUL6Y1gR/7zfwLk1FaF4TSGduTcer+6xp4XhB+I+LIDbKhlRNH6Ls8g62La7Ef4k98PycEan7aLNDoQyqakrBtwAFHvsnlr0+VnN18WIc8aIfhZZa8WKjKnojJoazRmykCm816DVMhcJORTK5b02z66fA0kk7yVrHBxSbZsHlQFlYoOoMWX8twDYyGITEO8k5IQkTDwXhpHAVmP7sEZX4fcW7rXP51SdvGkBpqBpipeux5WC9tZonn1wOK0ashKhUNcxPO8ynIkQ4LyQWnqtKQOzbnyz5LhsSE6+S0/BK3q7XRx+nZXOhjAzumrYGftvfB4uNKmB2/Ty+yzhOqYMyuEEiD22PddD33CQuPDCTdPP/cviFW1z1YTQYx6UTfsui9jPVmBowi2an5BBc/kNoI41T9J/SxfOVdKhaGe69bcGXKVW0QPctLJv/lhZ87cOFEY+47o8wJi+Lh9D6BnZpVYCGvYepPreC8vsFaF7SYuq6vQPWgDq5qmRRi7gWUUETB+mMh6juMCwyjgPtTWNg3d0F/CheBGILnCDb5xTHymvigkOnuPOCPOx5E0Ka+8Xw4sZWitg/j5/oOOEUxwNk/S4H475MJUXDvyxfMhEC4h/yVolj4BsVS5XXj8DGhgaKknNA0zo5ODwbIeKaLo5ytwTwvMMj0gRxZIYUHRHVo3vX1lH9QAVUZ2VxZ+QoKHziD9N8BEBy3y2ao3eGfzvnoIjeHt5usxjTHruxpEg5PqoVou7yFGgokIX56cp0QWsCq9aVgu3okxzTNomc/Y/hgrzPlPDkL7WX7+PnC2VgrstSEDtxg6PjN5Hie3M8cfwKqp2ahttC83nr4A+KfJBIbI2Q0fCXJr7rhpDgNDr07RwqDHny+m1W9DT9DSaOjGTNU3PB7YAU+B6QZNHNH3BFzhZs2RULb/rW8NLrz2FT8mrsmf4V2u/qkHfBKNAxPA8Zo36wwPmJaKvsA141rtTkUwjJZWPxRONx7LgehGpBmlD6eh7NUDuMzhd74EG1BD1tGIVuGjY83L4I154x5ePtq2HcOYA89xm46d5rqtkxyCpZp3hw2GOqKTsPlcW11K40B6SObWPtyULwMOo0enWI0TwHaYyc/gbH7pRn5dHafLbAAyPURUDqbjicOjMKLAwvsMrzq+gz14yqCjMhaDPQwQuK/CNDEUN2yLGX22za24nwQ6WLl044jdGh4RR2QgKEu1/juXZfkk14Qct/LSU7g//4SvkIeHspFCvfxAAli5H0HUf4MmoCC77TIPXvyjCp6Ds++BJB97oF4emFOna028Nu4sdBWrSfHLt+ob6BAOv9TaGxzvPIJLqQ3xjoQp1CAEYnuuJ2pwV0zKuU8v4O4ASjWlrqHITNM+LhhPpsvCopCztjVWF8ezGJPD0DT16+xatLp/DG+Mcce+k8Th5zj1S7xOD1EHJp2ibwsaxDMGigRAkVvrhEIhq60/pJecNU1jklyF1zlHHS8nFQnr2V/mu8x0rNrym5zJneKM/jO6kvYIRLHsRSCsu7L0OVUFOYV6nO+7ylqDzkIFinfQAL5UFoTKpAz351aGIB0PN+j36X1KDtghvvDVSD2oQqpLWepHH4LipsCcJgCROMtrcC68VGNLsF4NqVVNg9vRVSbnjySrunmGJZBafvfcBZ8RFcruzDYY2fwNqZQTz/AhnuteOTQkF0MP48XEt7zf3zF8DtqCsg2p6HH1YuZ5ud48BFcxvpr0vEXaemwhNThHeWiOO/p+AebeLuclcUXmCI+kUyoHtzOjg/GQ53xc2ordUCd5ochCMnwklYJhSGvThKhfZpJL1UG7J2dPC2Ew+ptOgxLFnqyC9jT1G6dTvm/C5Gn8oDYHBWhI48HQ5SPd8BGwzAbt97vOr5A/Z4PcbcWF8MDl9KK077w34oQPFJovCzR5XDHhig3o1Qjp63BuajFx9amgVGyeosPWDMBwYuw+jR4jBK2Bd694lCx95e6LkTj6tXRvOizav49MgOnKfpj09Sd2JvnRjcfevP9WcscVr4d3AsXQNPM03gzxYRktnTCmL7HmKycg4MVxviIM31nLs1DaK2LsFfX98Cns1hkYG3uO+TAaYNG+CwPQLg24cwt10HFiqM5aO+W/iF/Q5OfCyO/WJ5/ERxGpKJK0WOewNvHowEq1UxvMPxEezplcGxS0M5avs+gN8huGHrecyU6eDDOX9ZpF0DDHd6oEJUFifctyG9/fFQMEufx9czL0RHSjYO4uzZzhQ71gwmZqbCyzU3yTZHCxq6fRgn2qGb8jFMiv8D8EeAk+L6+by1KFTMi8fPXvL89N4lGNNrSOd0+/FVsiodeNqLKi234eBGE/wtLwJRuZfYPPckLF6Yg6K2klBwN5ht++X5v25lkL06nfpyDlCZpTY4Hsylf/nH4JDed3hxXxVvZr/n2f4eGFi8gIRKpgH93QUbdiiC4p5INl4WTB4zlvGxt5Gc22tB2SPecGuaBphX76cbj0eg1+dx8LE4gpXcZlDcqXNYc+IkLJ+QQ6pGd9F5Tjg9ulPOK3q/cUWZMSS+ryG7lm+U/OgUm53+wZe3feLLMYc44elesHzsBvo5sWB/UwjG+GehBuay9AEvPjWxiE7HfgfKfIbGjtNg3ZOz0BUQBu65phBj1QWuIZfJKu4Wyzz/ipox1vAm8ippxB/GGylNJBI+A6U2yILuBkv0HlVOMgoLKGKJA3XnzIZdn1VpWuQjHp72ADOUolkm0QL6NcspabcdPn4hD/sHW8k6l2Dw0Bo2SwkD0cem8CnoC2Q4S0GbzELysNkBdkFd8Ga6O+xGKchIEAOtS7cg5OhWSvy9kf2OE8g6KLKN1SW2cngChjiRtu+sopS77/i14WpSNNGHuHFRLF1kCBIjEuE/DU3e+E4Sxt28Rud2LmBf16Pw69J+HGt7BuuCNoCxoijY/auldKWT3OL4g1ee+0l2VjOx5FYwwpop8OroVthns4rWCKlAreAwKslohZucwzqbZvB1YVlc9v4HR2R9hBf1LWRssIt8JHWgNv0RbPXtoyXBjYDPPUn8wid+1rmBB3KIRvZsoLCPp2hDujQcvngEH27cyT9S2snjxU2uGcjDRwaB+Nr4A2lPGgl3JGbwp0/aMCp5LYjc6YS1amvw5KXFENeUCzV257B5/DM8n3CR48p8KfqIJHy+WAOi94bjWsE2SgmoRc0mWQhdcww3yy3F/DAnyjI8CQF79ODC2H52Wr6SA4o+8KSMsaiRbU6fuoqw1s6J+/Nr6INkL2YGyYKa7BQSPLiEt2WvxasTGniN4zNKEy/G1c8nDHWtC0+0S+JzmRNhrcRhvHl0Ai/LuEeTtM2p0bkCH2wvgT9v/6PhGbuoY6QDlHgLQ3/Zfuoq2MSD0fs5adptdE7+hWOSEnC7cQbkJZ3FcyHPSfnBJFj68zem9hzCqlVDbDnwBOSir6FI1U2onjMZVm7dhwJW6rSkRw6kCspo1al8vHpsP6xWEqJ/wloo+bALz69dzNNs5Dj1vCb/p6YA/yoiQGifEJjLD6MFI6J51MBivu4UwD8/a6Jv/TC+vvo6JZmqQv6yRCpKvo1v5kWi2hcbXlR9lLy/baZU4U4ci7/gpfFvNho9DA5IzQQs84Sr7eHsuNcOVut9pLPJxpBXqQ2ZDwPQb0o7TCgVAEc9LbS/6AhadzV47IkL3CpSTa9/JoHp+Omwtt4asN2eBJsmgP3BKAxpy2PRe7swKcQV9p8wJaubV2jkqE5whk8oarwaPjggQM5feOFzChaGr4PrB1bj8xZ3lvoBvLxUhxbcf8LuTca4uUsdLgquw8Nbk2mWNdLIAzL0T2wBzM+IxNxKQ7qlV0xzRJ7D8wxhGBfeRMLJ6fi0QBsjvvtCids+HkMJrFfxms536XFv1xqytZeG5oRaajFiljj8AawXJUOGvy24bhCjrg/1eMNvGjyPd8Wq8ZPgmlYlWX7bD0YT7EkhtIdnyWhgs9NH8n3dg3ZbxrG7ajntbBgJmZMf4i8/PSj02Y0S/ZbgI3wSVa/lcX3eapic4ABV7dK0JUAAznh+pZT0Qlp2s4sm0x2OD09h5YQYyv94HxZd9OP3o3KoJFcB3g0qcl/1YRRedJViO4c6pLABj3sEsrVEF/x36xH1yPyH12tGgNaNv1yrZcGCxd1cn1iE7jmR8E1VjsMTiumleg0LN4jR5nBl0HhaQ7FpUjjarRSEzp2CbzafaTcsJS+zn7hjogc2OragstEwyJYpR1eBQIo4+BXzjuzBtYeRB/MSMGlnPW76LUBpehdZ8o48rA8vJ0vrCC6VcSKlwS2U+zUPfu1dDNXC3TBybyEffOpCtyYBRA+rxDXbf0FHO+LUrVux6lEcvK04jHEKM2j1uiVoP9Wf7j8jsDFZRtoTB+EFfyaPjd04Tz2UjqlZ4vhXn1Bi1x4qeppPZxRHg5RoH0spHITWLu2h/niIwkHDyXDnCv4y+hRP/9MPxQtceMUbESgZdRR8H8jDwVAXfu/lB/oHPhPblcN8KSM2vKnD38e6Y818KyjZPBMtRw1wQ8Q2Nr+1HIyvuOGC/Dts/kuQ81p/AOho0bb9Q3t+cheeqt+LGUe7qNc3gHtFM7BTUZ0bX5xkGbP1aFf3laxDjaDCLwW3XhuAwmmfqco3mnF3Mih/WEHDdixBz+1x1Pj7K/wJMYcSpdfUFrydXyt6UHFBJsSoV0H71tf4n9ZvUFyyHl6Mmo/X09TgcYopf5xQCs1Hj8J4BUmWGFTj00GPsFrjNomqlIO4/WK2zdGBzF1mEKS1iG6un4nFSq9IePc6SqjZgOPsb1PDOx9QD5iKhWemgHbTJVAqM6Vhz2/B0sOz4HjDVPw21Ya6g0RY9csNKD+8CGaUjwGp+rH8uFaS5q4uZ9GXPbzpnzlnndHF/4a41KPgH6fXHgbpj+JwobGOfY/KobKjF+WdkuOZN8fBwit74fJfb3w5XpA33m7H1Ggt8E6fRcc982D3tE8wPbIamw9OBClJf56/owDmTxZHOh3G3SZK4Bony5KpVbTLxAtudiuwe3gX7TVkyPTpouamTq5RCKfh+QqwPqaJztcJwQjVpVSyZj6+uxiGYnuAV7nv5KOV9rg7bh7cnDkS7iapgE7qV3jYuQtGX5OF4xeT2DDtH76QaOCAmBoQu5FJ0fbm4KT/lX76xFCM8n+w/kYPNx34R6O9HCE62J4WvHyPrzdsh9C84dD3fT9avT+Nr9Xucf7vIJ614iEPxMtRfNoyyByMgmKvu/BsgxoYBj7BoxmZMOF5I2bGa8Hv2ByqqwB49qaCWj90gYqlI5LS/+36XzD7Jgy3VOdg6CNHLjxjRFtGFNJHZUFcvPcFaCU1cff4IDr7SQ4qvlmTgpEIb/jUzjr+XVhSGMy+mqN4flIIXXJQJYO6W9xQJAUubx3Qp+Q6Hft5g3se/eOrb72pMaiHz4c8xf6tDZzydRVUrhgBNrfvQE3vQtati8X1pXr8QaQfdEIm87eSXnz6og7XtlnBJLspEBcvjkH6mZTKR3jkhtFUrnSJpDrfc4aRE4lv+cmb6zxRcIwu+E0qxjfpJ1jtajKcb5xHqVOuk8VZP7RwGM/TNt3iY/lqLGcpC5tWn8fijhBInSxLWReH0dFUM5b/UUS56+7xW+/tHNlfBYfHasMTxae85R/hjWwrXCTRDYvsxnBJaia3j4kEzRsHaLSyJNk8UIFZybmwQtSP7bJ7wb88jCWHGbHOsZlYU5aNbTpl2OWkT2t/iMIynTq4sPoNHPWro/8eP6VXW4V5T70IVs8Etux4C2+PzIIf4tqQMMKKNJpLuerXEkrtjgFN6yL6sP4dVa3+yNu6f4Pk8AOQdW0UhAfMok8eInSuQhplb8ihsPM4eFv7mcWHngU/1McLrZm0+qkYSGk1UvD9fHhl3wL1ksSfnzmwWus/ypW5j10XZCEldi7DeAtwM2yjpvA1HDJiD8SzLeHBR7im/Qqe6lChbPWZQ653Bf5H0XmGA/W3cfweQsqIMjKyQ0ZESYiGCJW0Je2SUUlECSk0lVIqRIRCiKSSRFKhYVf4S1MKFSVUT8/78+b8zv29P9/Pdc51Ha1zAhA5+R3Xla1ETdOXcMjGBm+ZGNEEq/uks/Ad6lRsZ7XSGygSKwbvKxHtz3fTqvx1PP5FP8vfv8bS13vgo4Q8GHUNp9RTghg0ZhhU/zTACzkiYBkrj6XzX1GyeAK+jy2CurvS9PnVJv7W4UNH9ohBQ7A7eYyyoq8LXmOAfwFb7TNF4/9+05FuTdQeeZCL4+RwQ9xEOOwRxKJv1HiVzxqy++UI5UNfcUjvA39qH8Exty6x7Yz9YNM9CloCN5P3O3vq/jkSb7/ZQB2zjuHi00ncI/ocMy0e4uNbGeTkKAi6gVJgU26Mv07rUZv+XRieNZdl5+XA1fB+fPZrFbYputJPJRHQrfoD6TNP4/HHa2nKsQoSX94KX4dfxFDrSH7sNwGqC5wpaaIyPBk5kv0+16H8zFfAWXehJMsOEzy66OnpGvhmeY82t+bQ4iBTmFXVwcvGXeRr7aFg2p0E+o9+wIgIWZrXJU90YhcfPngDN9jLg8XAQ4xUiMYfV4rIcZs4j91yCaLn+mPk03g8JSDBPePPcXHjSJBBK+xc6MXfelZT4qXVkBPjyA7vfCjILpW2jt7Iu2KH/+tso2DW4kzYIWKIa1cs4u8X/enMez1OPnkFs1e40p2ISeCXJEWypvIQvm4d7kgYA5nJfrQmMpfKHfSZxF+Cua8R0O1rcOTLLrAW+Met1ne07VE11qe1UYVCGhsnn6cN6124vrCJB/5Kssg2C/gVKAn6897hbe03pKRby1ozZtLyO0Z8ZPhMsls/DQS0FejCkA2b+iqDlosLTjmqzSMsxMHtRwfnXhJDb+F33J9nixGtASBwVhGsZk4D381KoDNGmS1GNsGx0hvAn0345nAT1pu4AEu+jIRDYvcpYYIUbNnaBi3aJzA4OBd3aIfiUauT/HP1OSjKecSrvj+lO091KaRHFexOXacndTIwp1IQw+a/xswjsmCzNZ+Lim7DhheF7FcRyVUFCmC3ah89PdLAP+UDSMxyLa4e38md427RYp0g8Exn/C8nGZ4JEFxYfYiXnd2OTyQmg7/oDUj1mM3lj9Oo5GEDvFglRe3p2nhJywy24FJUXmtOprVuaLpnBGbvjoZtO/v43aVYVtpTR9PeGMBezWHw2M2fX94excvWKkHwtFasGljJf+7HctazpWRSMwUDmhNRT20sbGvRg/j++djyJY2kd8/Hv0+8oc3wJoi7xUHkqb+4UP4l1IWpwFozO05oiyXZTE3OOFFH+cF+WDK9hy5mfqC/n+2pV+4G7Zk8HJZbMVwuKIPShSrs2iKNAXtTwKDVB3oztFFvdSyUN74n38kCIKqmjq863Hno357e0TuO3BZZcmlcBC2qMwOn0sd0fMJINNI3g1EjCWrUf7HM5mwWHS7CxmnN/2bIA/e+eEzKnuu5tcueD58eC/WnjsOeE7GMCoE0TfoLJI/aTqOvuFNGfSf48DuqBxM4fkEbUPYcTD3bz/OaxHH80m+8P+E034oI4ANDUfjyeAXHrp9JLrPHw7ZHoZyAVbj1oQaPlzIi85xdvNxjDq+8mcW6KT9w8ev/cLfteMgZno76cybAHlsVirj+HM5q+MEWgwbUnL2JRW0rUa8lBzneCLqvbEL//W8wckEPvY7fjBG39vJtk0zakBqKIs+teOTGx7SyhMCixQY3ON3AQ9s3seJ4Ez7TN5b6TgbQwpE3MazlLE/VHIGCAYaQVPuUo3dZ8YxyMXyxUwZGmNaigocHONkmgRFN5bl3jsH8D5Lw+WAjXD7uhWF3nnNT8h8KlTCgNuk4cNs2nh+2RWLItfP469FIcHh5lkpbwlEz3gmONS/iwPZhbLZWHqUWhUFxoxW6743D8lAdMCxfxXMfL+bYtWFgnh4C+WM3gfzjARpRG0Ulx2bx9gp5zm6VBpHwKMrN6iXBhjF4MCee3JoOYaSLDRw+l0eHk+X4++cDeLFkNBjMsMKD++aAt78JFS6NoC1Gjjj/aDDlDL9Djs+n8nK1ZFr7zBCWjCoHRW99gtK3mHtoEz1v+4xa+pXYnfgHI3+k8HDlJBIcow3Rw8Khc94A266U520tzuwv6oA7t0mgf4I5hMT+xsPC22HJcDNYcOgwSqxvx0m22Zxrb4OxE75Ayq4hzpe0goKUbE6qdKJLfSJgdrEB4nY/RdFVzvhxThLmOhniuB1P0CGnH86ZaVD3yl+cGG8Oy8c1Yne5BP3e7M+/HsWgYUU0PfMaj/O9/PnBUChMPOjNiock4blcCWRd/kIgsQIq15/ijC8L2HFOERR+0gSdfYE0SXkDXtkmD5u+lLN0/VoyeVzOFRPWQsTfYgh90UxP/zSji5ckF+2VhTUfpoLJmSD00rnErv0GPEftPLmd2EfCCqd59uy54B40mjKm3MDIlUpg0tuKf5/O5bGJa8Bi1xFWEc4kSZWteL/Og2ZXDUDFmkbIdBcE2xezAKPV6ditVg7a3UYrV07CH+HvSachkZ7FXMY61R3wjKfDcaHvOGj1HZacz6ZJjea0Kv0HRD3RpU/pEeikVMXpH27zNYXJ8LQ9HU3fL2Cv8y5w6YsfJx3N5B+vn1JAbhac77mFK0ec5I3Z+jCvMxwfqiiT4W0LkpuTzhvuGsP8FDHOHXWaz7Z2gdPBFyDqIwd6Xyzx+8KRnPDVFlOs//DdhrN8LW4nbi0uIMXLZ+CUSjQlrpwE4zvf4DO1Ozyu6Te8W3wcYicbw60pUqg63RrtknTB/1sm39woAW9z8vHT082cNGwRd2+N53mmZ0FGJYbW5q0ip4cVGJUhS7P+mID5Q2NYlvOS8lYALTgxhddYOsHuCU04TK2YQvSPodj6SLRdLAPVtQ0YqVUJY8RfUmGGGMU0f8QprzfioIwJJz6rIt1pN3hVlhx8vVzOq5U8mTcI4iWvGPB7HweCvROgv68M79bnwvfdCdDlqgn9bI+tZ2MhIHUuffh+FjWED3L5DF08MOMi7jO9C2pLkENuKEDi6EDU296Lx2P0aJPmXrbR+0vzzU3h8j/OuE64Bsmr0qDxnx+pedmDReYgGsnaYf3Hc1DziGhSqC+VT7qESUbqGFmxh/WvjoRrl1Pwv+mh9DJ7GxcU6bDOqMkkc/UtJCrMwBkh2XTS/l8eBieCo6450fT3fGLaBbzybSsGDohTpPUPWBE9H62lA2hpQRoLTpkKFUIevPO7G/e9UUPfgungX3QHYh87YGeXKRXpLMHLl8XYSVYLbi95g3anxvKdWck479Q+dumywdHLOvDUvbEca/2cI7xD4aYCQ9vN6Txrlj7mD1+I3Qu8+btXMG0dtIburiH4z2g0p7uUkJC1OTiMvsYSv2bzm+Q2Kmr3oWPLPmHI5C8QphoAHkWjwGnyOZ47NAZ03No48NI+rnCI4+OfQ6n9QgVkGl3jZbq5kNMtjBsfb6NgNWFQMDuOahueo1TVcjTYmEvNrWrwTcCIhPonQcGfRojZuoiLHqrDycgfYK79C1eIHIa9knP4vuFsVlI4DPs0l0GqQDrK/yzF6zmi8ETaEp+aVJHzcg3UNpSmm81uHPBiFfcN16BFWbMxhWdh8nUlOKMhixnxbrzwhwrukAhhJ6ebfO9+JVk0HQW57ioIKpKnUlMjGHv1GaT826+DC0Lolpgyh0iJslmGLNxvdUYz6VFUqv2NGlVloDtlDikpTYB25Rqaod5AoT5huHOmI3Yud2Kt+he4oG4STxuvCvXn/bjs6SR277JE9YEu2LXyNJFALWfJn4DLy6ohZn8B7RmmD+5Ogph0pIdinHu5ytoQ/vQeQ+eoz7DqWzXM0n/OARbzoG4VQHTLEuwKeAM0/yIN5EyB5juy8OaDP3aNMMN5Nx3p2/oqHJc1Gla1j4Tkj92UtXsSun/TYL+1+6AoXojOtj4G+wYv+ty5CfXVRGDXxx3Ytryd236tAWGH0n89ZClVps5G/5ivcLrrPIS8mYmZn0ZBQk0UKbcJgnSBBGtI7UajyGJ6V9eH9e07OIUfQ1bjPPaYZQQjdCSxTnw+rwqRpzMbttA5l6Vkf1GdrV/tw05lbVi8ZAklDynCiaZ8fBXYyvo7XkFSSSQYmolCt9YHTJMpo/SztyCp6BZWDk2AiyddSO2NEGcPW8zxdi34NO0Jfix5zXtMdpHNWgc6VJDC//8/u0mUL8KsPHhrb0Bqg0C96nbc5pYJk+/nUVJYHFgMv8Fp/+5ju0YAHCuzwsFkERrTLI/7N8mQ3yIJir5QTx2RU6hWNpC7TijBkvhMEBAWp9DfYXC/p5R9rl3E5Ztz+cTmaLBYF4ZH5tRjfMAwiLKUom1BJ/iz1iLq6fkJfk599GDPPbhRPEj6MT3k/kSNpn02gEHRUzDd4f6/vrKJzh67wdme9njS4hN89njKt9ya4MrbJHI3GgaN8ldAIMqOe+a7U1iJBSqmz+Vj8/zYe8vNfzwTwwXl4TTumyKcSZ1BNc9nsGWQNnu0x8HeTV5Q/2MHDIzMgV1/9rLn0ChoThsHWnZbsPXXb3jqYI5dErOwYJkQbC8+y6lRjew44jLbbi4m0VmqkH14ELSDOrCm8F8Xej0S4la+p7i/oWjrPw9az/7HemlfebfkaDg84SXX9xyEJ19ewIHY2bh9Yi03/sv8HB1tUPslAdVhQTh8uDFsXdCLTUlK1HHKiMsjtHB6pC2W5NbAm4i1MMrjBOnluaOkLMCR7HWQmZnN88UW8LbTXdDoLYebFjzDQ6/Po+DtOtjyKAAOXNYCk8cZYN/zm4X019C5GBsq39UF7dF+lPHsCc/4O5llggsgL0MZaiuFcOCRMP0tfAzJTYuxQ+M09CXnwt7/+uh6VjGGts/ExobJcCpzI69U18DYpJdYcu0yJU56CW3PP9Ng4yy+MEkANsnKsdpFMQjP0cJP26PBNUIJ77SGYtpjDepJ7sPcb5Fc+3Ad56g2Y/Op6aAsFcnKJ37AXv8YOKHqzonXzMFs+lJSP/OMnO//gScjwuhOkgyUSx/DvoYKcpJW5rvh19j7xX4wOnUL29ddRefp8jy43x4XPRaEtzFfmRecJvVCJ46MO4izb2ZzQORhbqxxx/XN3SyyehdWTRwNjgcUUElxOoikPYUoqc04IfQAuPWtg+Kzx2FZ5mzW8YmiA2YqUPbkJWeZN6LLvBoc9UQA5D9uozvlR/DPmgR8taAQv5yJwwsjx8D7wnZyy9eB5iRbPLYjg2CxOPe7bYFP1x/hiexXmD7BDNnLAEojrvLx1J3gJV8N0tHVHCadDWNXjML7lSd5w4ZbkKe/jcwuqINi8XfaPWU1qBU2o+XrNWQuXIkH1n8FnVc5TMMvoNeyIr6Vpw9q996Q98NdvCHME8o+V7OK4lSOP7GYAx5ehmG999kqN4am3RCBK2vV8OrzSvCTbeSVFevho7QU2t8S5JKkg2A7bTTWnHzP1rXDIXXedZqz/SiaP++AlWJMglpFbGCpwd3+Y/BL7ULOHFjII3uFIXZsMcrYHOCYjXa0U9iWbgsFUO0qSywRcgarv5P4yGAuSP8ZATP2bkFLg58wpVqTU1U1cJ7tXfKBelw3YIxrXZ5QWOspDAw1hMNsgG//2tOkfHEUjfkOTTkqXDN5LWtzMWVkv4eMgvds/0gH1JMms6W9LGkfPID1mhvhwuNTdFnnJTfU6IHPoSh8MTGLOjqN4KhROLwvVac0jWJO63PAyS03MUTLGkJFu+jLzHNQ+7WFtySPhiNBFhjvmM7WNxu5b7M4f3MIhW9nn2BIzx84df8wLtLvx+MOulAp/QkP/h1OPt41ONhiQ0IHM+DdoTaKPfSczwbL4cGrBfj5syY83hpBok2NPLE5DSKLr9LJI31klPCNSmfNpFla16l+6wRq7BWE++o9JHD+Mq7KquKStCbYvj0P1UyPwuP3dvAp/T6v21BG+TtHg1B4BZZ/DaMt6Q9RvlGGLY6ro33JDUzcK8Wl107R3jFT+V2/MIi0PEefXVcoX3czrWiLxfXr5Uhu4k9oezEHlC1Hk5NnM1arCkLUgAofXbgKO9cswEP9r6i85jGkSsZzwOd7YDr4Hu411GDpbmnwvzsOLyw9B8kJzmxX1kJtBktJ78kM8ll3lH5XiKJYTgtcvCYAyr8NIME8CL/fHoXWqurc0tVG2Sl7ceZKB7x7uR4WOIfir8Dh4Dw0AlM/leKZM8rUvscRcjbkQOysyfDAP5g7t0lCCVyk6LN60Nl7HF6Xz6LsYEVu8fxClfFLYIWBE3XUHKHQDS+g8fVSirklB6q/H1B7xUwuTCDa/FEAd5Xdh3m6q3FhnilMPjCSrT9q4bqlonCl4SRLSEfy09Kr7Buvhb7HLkPm7INw1XsvHN24F8N4Eo4W/8eF7f/BY5OTGJUwm+tXJYFTST5qRDSBftIbvNl8Ax0dblDGeAuw95KgZfaNIFdZT8UnqjHr/HUS+HqNlY2VaCaaULlZKQj3CoFr42F6PV4OF3cm8a//llBhmRAfjzyNLx0u4OoPPng8IxkmNciDzcqtfDK5j1NNF4H63TwcPZgD7pUtrBDA/HO0FP/UP8BLnqlD1ak0sgh+gFpO70gpWRtHZvyAOdv3QdbgLjjx7R5N13XF7NuaIJO7HE2bnNFCQ43W/jXgxWLK9ChlGUeVFODi5yvJW/o+L7yqCrW2dXhjsgG/HHkRZXdZguq1NLTJsoO/V4t595xqHlvyG4vi5KB63GpWeRZIu3McoLq/Aec+cOFQ8zAW0bcC4bIGKm0zJ/s8c8g9Rug9WMbXJpahTNspihwRxX4JhrTJ9xkc8IigGVOyUDhdGQJfFmDWvfOg7thDS+e95bDdo3h2lCX1rdqM6/ujuDXEHNUUjWGdxz3sT3fE/+yU6OO/M/ltNppi4+9Q/vwNMF91P+/Oe4/vVspCy2hPmCZ2hF39cwEzZnJS2Vq0OCzEgm+m85yTj+nK9y7cOkwEatWLWFjXD46mFILZyRiGmmS2mnKR7NqXUqbdW1g4eAlb96lD6HwvinoQwdmPfdBh9DOcHKMEXcaPcM2t36CkrwMxded53zBDeKs6Co+K2PDrvY9gT78QD9rF0x+VJ7hDrIPnxYhCYpQPplwCeGxfiXZv3Cn89wv44C8HY+Qr6XPCa4hpT6S54/SoeG8BWv2Wgfq9l2ilG3BdpiRtK++hyMUPeJalGqrmzqWS77tRqlefb4qPh6bOZBJf0Yjv+texy7ZRtF7lCj6S9kIJQxl2U/wGIiqpIH9KHx7b+cKyiD4Wa9tPrkcNuPtMLqUvesLHTOPZXtCGYvbLYuAoBSiJeweDP1+Qy8MRPFz6CcQfvop2Zu+54PwaPpo4gvPGAlyTRIi8144hnSLs6OPPR3vjMGfDLlg66EYXdsTB31pXzJVx4DOrECxdO/Bx5Segw6IsYSDIG3Z+5dtqBbhlymLa9M6d9sbKkyVJw5j0dpg27yH0lzehed58/J6QgJtGzeZzKp845Jc6rvG7hTM+GsJoXynQr5GH/j9zSWZLJCoHTwT6vIwTMiIgPHUeP/05i6X8LGDEpXV4VPII7Vg1xNH3B3ioOR4wsBs1XB25uaYKhaqbWeGhAlzZswksfn3/t98KeJ1+K/6KcsOT4j2kLDYcXvrPpWEHy3i5wRjQytvO5SHR5GohS+sTE2hxmwRPUJnAI2VDSfF2CCic1+fxbfIw1CvKrpcS8E3oUdyhW0E/PI/jsVNFkPj6JE2IXc6Sy51g1ng5CNVwg43OdmR1M4Pu2QaS8SVtKHYzwF+28vAno5gXrf7Ogtvk4UnyVBrlKgR3RtXBtGdqlLmwAh6sPUWjint5qH4/PQjeBeK/BMD8yXeMmf2dqrgXTiflc+WjXTBb0JYfhFmz/NzZdPLDCyyyU4Z7tJFOXPFF09G2OOHediz7YULTFT3AbekjVE85yXTvHXv887c/G35hfsgZAuFk6Lk9gw9YtULFkuu8IyyVmvdu4wdey8ijYBQEZqbAzxketLigHVJfhcO7S334p3YaLvDxJ8mpDlDoPobS96vD6I261Lr3A8iPHU5+wldhqZUOZKzZhdOXpJJ8sDi21o0lhQIpOPahg7e+XcnLlL3IJ+QdzQueD6pKcvBePhFir63FT65NOCl/FLToPKGJk+ZA9/VDWL+4CGQTS/Ftfy6X9SzhTzFjYOFmL3ARM4TGPkcSDHmAqmDJKSN20BJ7G/5yTgC7H3ZTzWNd6n52gwKPSkFj8kzceWk6ieythg9lu2jR1h5aKJvD8o0b4aWALtS5CMK+N2qQvykGRsS+JtO2QnyxYzcdmWNPHbLePPKKCj0S8uSTWyP4uIAMzA9QYWPPFySc7cS6ucaUoCvGggr66H1BBg0C7XljsQOHKovCBiUJvH5mOqzytMWIw4dQ7GMMVSg8we6dy0FhRiuHJtriSXt5MJqoDb/nz6XjDc/hm4If5cxYgmov6unVuCsUcfEpndMOY0V1NXAIvowXqjJY8L4Tdt0wg09PdWH16jnU1NzMOFean6ichIt5clCTqAJf0lsxq1KNQoRWcVlcP5iXfORnQe9YeEkcvI3LpUOKwrDr5SZuu9GL7tlSNCpyPHgcDyThY47YYSwK0TotmG+mTrfmTgG7E08pfr4NHqocAKi7wZI7PElg0Vv08TSDq73zAUP04GWfEhxYpc27Y5+Bvr4fVintITFTLyy8XoUnXvix5eyjsPFMIoS9GQ4hemdxj1sBKB9Iwy0blMFC9hu9dTyL/e8e0+u0f5lpqeVmP0vQXZHMTsOO48czPXj1yTHQ4B+QOvQXG6R02FljKhjsLkYNAVE41ezP31JeQV7SNZw4JolPCb+FP2f+9fPXO3le/S8qPacBL5yngvXyFWh42xe+rbiPxg69bKe4hq8NfMeO1WKYe208RevFkXO8/L8esAM83VaDd7Ezr0hfCLLBhthV+oK71iriefFo+DVZFWGIYYrMenIReMu1Hx7hvY0/cbxVAbRM+e/fc5sJls+n8ierXAjIIwi83gseoSOxPzKGbC6MwOTZV9FFIxt3Nu+htLYw/GYVy56Dw0Bl6QB8CHOEfjlzbr+hCnGd40Cq0I4ul+/hzUmG/D1RA+dcV4DuO/q0R38u95qtALlnpdwWoUwDN27z/R0R6Lt1N4e01sHU2ZMgx/cv7ZYuBUPH6/j1tjv6K0Xw+p3r4eyYGmhScKWz+mt5ztgRwLt9yHN/GTReXoCF8zz50BtZvjxDB6/N3YZ/glLgfuc60BytBxcOp9OFCEVcZBxO8b/LcPT8dui6/xiqgjyxNDqbYn6twP9uy8LxMce4RU+N1nmLwm9tVfiZJkLapb/odq8tRSZ48rIl83nmoBAoLC/GNSiPg1JnIP5PDX48HwWq8jsg5kAh2/ROpqzT0njk0HiwXn2PAn57UaK4PASW1eBqnTBaFmLHRcJ7YJHPBfIObuadx3QgTe4SlwbMBpFdBXS0k8jDsRSaoz0xXtMeLp5YCdun5gOsloGbKyeAQbg2fdYaBpeynWiyzlLInbyBDr0fwdicSTcGC3itkC74OrmSyFA/DUl/Ye/u1XBskw77pf7gZYGJfGLiK0p79Blj3kmASaYdR34LIfsQQTrqkwHXy71JqjUK4lwTqEg5jvxFF9ITTYAo0wZQ8Ujka36z2HfUcxLODYTOLiVuSyqC97U70N/amj/UjYb2oztA/nAAv9i3hC3+zfuYPYP4cOwrKBfSgBXTBvHmYWva/Xw4CIh30lef/78/KkLlsH44ef8gqz1IpM0uUVi7s5aSfvbj5DqCLxPreP5bU1Da1EWVm95DYmEi+rt2Y9O7A1SZZQU2I44ijRODvp3hIPQqDVr6Q+B10Gl85vKAcvV10T/HGxzsMyDYZAahwjSIa/8PV4o10b3uw6yu1E5rM9Lp3o0Mal36ENfeSqCGQmVSVhWHccte4Inja3h+cBjf3TCW5pu509P0EajTcYG7fcfRkYi78DNIEK7rVqNzzTyYfiyVtCLdQXpZC9/enIlF7j/p43wdHmu0hf0XMPyeUkOLpr9mmcMn8G/2hH9+VoJLvQ3hJF/AUzP7SMshgae2E9z9tIdu1o/gmLpkqP4kzt/fSJLTZw2qyG/lfbdmwAYrRX68zgjubA3EYx9m8p1F9fhqcCmdnezLF1b2cfClLhi48gNkrSfC3auGcIC+U9vmVizMuAwuWAIuvdOpPs8fbt4coBJ7a+w3IHgVNw02C9XhHK/doHTPhPUTZ+LPkEJyUyjHlWoFHGH5lneckoVuQxNY8l8Qbzs7Hs/cuQTLbS2hqvQETm8wopHdthR/ogA7sobj+AAdmJw1nT6v+spTvLXo0Pl62GL+kKYlRuOApzr4fHHAUntXBFcT2NfbDtVHnrHFUVVeu7cCHznFw+lRBixgpcSdUim49ugHCvc3BoxazPO/JXNbSxo5Ov5zCIVU/mklwfFVOVSW1AXWAnq4PtoI5p6UgqN+e2l6QTps/DAfBDvPY3qpG4WvP0khz8th94pPLHJf9B8HtbBw7VY6M5jM+8/agquVPqpVWPFIwxgs6RtGH/Ijcd8nU0gY3ARBEwgylOZBvLQJZ050JonINjj15SvN2lJAKtrOMNVIEsijg6M3L4Af1u9hNQ+BkXIljo3U4TWLIjCgagX6GofgjFfT4XZxGn39WMNiOzPp+yJr3PdXFDT+CsCL2dLoU+RBfU+cOSPIBDaticPXKbNgnosp7/ALg2KnCSBY8h1HW6rjn83ycOf7KIx7pAtyWeKkkulE5R4GtGeCGB3cuJbSx9Ty3YsTuex5GU9eO4a1HRVAT0sVEt2T0d5fh36sf4bliXeZxT9jpK8swVFl1Iksg/nbxsG4lQvRIvUAnbWJw+3izfghuA58x4rg9tSTkPJGH3YYduPf2ZNBue0e5U6dCTLb7+CASzc3Pd0Md+ybaWzDWQ4r+E5/b+jzR72pcFsuCEJ/BdGtpv2UkGjGpideY++rFtKw3493YleDzRINbH9sDjESLXy4ORs+BL5D3YP5JH14GuPbBm4NfEnL+l/SjhXP2M3bHKze5qJUwnny4H5q2PKdhefpsb1nPAxzbOXr+XnYfd2FnixUgHU3xDn5UBrKZB7muIGH2F08h0YbbICr0qswzXQWh7yfAqU1w+F2ZBVN36SJ8iM6SeClPUTFd0A4W4Lv7niYkJdNKrEzqMBZDmyWv0NtCYKN7b50+6ga3jG1hY45iKd/i8HxwQqqBFXUqBsHjU5+nNd1hLSzBvFY7iaacjoIb2QNwp4ZWpTy8CTbTOuD50YEcprV8GL4NvplWk4fNfvws8ACsLtUg4GT5hL4rMFJKkg5slog4ZNJ5V7JIDOQxotyd4KT6gvsv7oac18Z0JoV4+iuxnEO+ece69Tnc5TmRb61YyrPKTOmbbMq4IDKflww/zZMXS1HZfCNTOqMIevzLO5/dZTPRxzgwxQPX5Z+xR/aZWjX0cEy65Lo8qnZNH6PGCike3LgDmXSuPgD6y33sN/DeFgcZc2lSqvpUJkTdwbl0yolaWjPV4a353rJZOdBip1jzq3DFlC1fQM/eKPJe4R20pugW6DkJQMjt0XQtGJTlnSwQPl9rpBlSbT4Uw9/hFo+N7WPzf5F3HSxBUy4rQyDHRKgvUkP++PSUORrKjpNsMZIT0Ou8vClV0ZmMPajAJwr1sUP+6eS0pRn/GzWKgo9ngcNVlk8rOoprhGpJp2u33TAxhSk5o+j6L8a5HtdG7de60Bn+xcsqPkUu89UsPjCjaB8MoFHL1UGudH3IEI4FKeNiECZoiWADx+BcO4h8ur9Scn1wSzhdQA/HhgGOnKtPExzCsgpH6BGB4ToNEFYMVqPtgfngMqkd3x0nyinxIhBp/dbql87j7Qs+2Fz7026yC9x7PlcqPIazlemNdJ170vkuVQVlp4cBl53hbmucSdci/fBJz83g6lTG2LiDKpxPUcP3Mz4wgOCb5K7yXZZIz+tLmThA5EsL1WBi6dshun952DHsCOwT1YP9tdKwcp8H3p3/j1tTn9FH5w/Y434Jra9NYLPRT/FjtxHeGDLFKpplYGahIf87KAvWeQIQ6pKPrZc2kay7sd4oPAFXz6hQ/pjWmB5gxgIrToJo2RrcWOGFe5ZdB7uUg2GjxfkvmVruMSxAFyuKUF9wGjYVTkWDTPfos0TG3zg10peP27ATtNJOH92HYf7FpIz7YRyCzVQUq6h9vLldHVXIWiY+1KIyWJYUi6OgpX//LcD0X6aFAguHA/qFe//eTnBQsXjNNToD/q37kDBhGnYs8wf+2RLofHjEJnZaICdQzT+WDGJXJeIgJqAAvXGuXKKujkoTd+Nv/V1wPGBIHuJG0Lg0HO66FYNB1VKIOW/8Ry99DHsU41i/VwnXnMwi2Ymj6KZ9krwQXU0fNKaSv13bkJiXCflndjBksuEIStmGP4xloQ7t5ThpL4BTI2LJUXtCowQrYLIig10LXEWye4/zXtXLkEDvQF+mbcE8xQsIfFlLrxx3kqJuZPoTtVGPu5RBXmmygBxD2AK+FHKAxusNhMEueByGr2c8Nz6UCyemEIXbEv5/d4i1DxvyLfsn8CbEU4gpC0Jy7QHWVniAI9wOUZ2v5+D+sAFljF3hezl42FOjhnf7fqL63MUQf6RADRGtmLm9W5KUsrnveYedLizG03e+dLBoscg8jOUhL0nwwd8zunFShRbeRbOiJjB0+XhfGavMJj91UBlCRF0C57E4TflIenSLL41R4+M5d7jVaoCfrUCjq6ZQodTVVj3+1V4+HM6qh80AqlzUjB9/Bi+dy2J2iRceauYA5oMBUHyiM3kr+RJW+dfI+2UyVBrtQF36wWSyIHXEDWlGdfLPCahEdMwPSkTt3oUscjRnTjxkSDM3S9PsSVKvK6a+MfyNhAyPAEYbAkphx1oeLg5hsw7D0LjzOD+uNN4bnMXj9Xx4MqiVnTKKcK3Vp548vV8vPtpFNm6WGJPiCak6RzCBGdpcN6pQQ4L09lyTwkU+6XCfYFH0LR7GAuMWgZdd0ZCtqED/vd3K5/sUafT9AYHlqzntxdX89LeSNxzogVToZaUpRRh+MG30F9aBOQlxme0TqLw9T6q/P0Sdoz+zmr1izH45D6ssVGB6MkraIL/I2qbVwxLrpzhnGGd+PfYDJp5NIVOTtNhlQoZtlDVgGNKLrhLSJicsqVAKmckdG6r58appeQYzzzy7BwQVRnE9gQlyE5v4P7lwXB7nyfK5Ttw/NUKuq99nIPvy6OC6FVu2ucG63fIwcfhhTi5RhgcvHTR7tczflX9kw8uy8fw6bWoYjEdE6x38qfFWtDbI0Rr6oQxTeAFnPjvDyXMOcEZwhswX8edLccG4nV9Yaho+uetj9Qg+dU+6jy+kOLF91BffQOaL03GsosryP5eNm8SbaXZvRKwTlGb1+zT5hireHDMPYwaGxzh5pctsFJgMYy1NuZZvrPQZcREaHkQxupad6A/pwBFbhKUZX0h++o7eLV/Kp8yEuPLC6bgqMThEFRQQmVajXD+gihM1FDB684buN/RG8UMjuAJ813Q1MWYJK8P0q1N4OzijmaHPTlk5WGWHFmOC7fXo8ncu+CaEMn+Y71pywDCw7/5NOXFWoger0FbmqK5xNCMzueH8MUHk7FRLQOKJ+hTlZcKPIpfAZK6Fhw2WIupPgLcb/8fKO2rhZKj5ij1bQoqBDwA7buWsObVWu50UKXUrirSe+IOm4MmcHCzP4Z+m4FtatlcG9/Df0PUYI1SAby6Y0brDo/HokYxul+uCGbvR+IjXQ90ejqcx8JwlvsoBIv8FdFeSpJuRonA1fPSXCxZxbnOB2D36jdc3BqLa/6z5sPdw6DL5R4NPHClsX8G0X3oIhys7eMDiXUs8FOZJJ7egYSmkZyjrA9+37rB91Q6xIqXkkqfDnemaXP5gCgpHK2gmmuZJFomiilnTeDcHSWcGhHEIg1HyMz5PR72QnyLzXzmaT52Z7jh+XWnQUdsKuwKsaHjRxJ5f3whvdK+TO7PrblydQMYwRAeeD2XF0T883x7M4j+sZ/zfxhxzPWVoBezi50F2rD4wQNqFZXB8ORjYL3Zh0xL5GFTiRQvm3mM03PmY9/Pz2TVmEvyh9RJ4cZeDhunB/aS/TilRx9U6qLB8fUETnRg/NFnSHoZV0DMuJOszqzAp28WsPgTIbpWYw4LVF9BTLEbrRkWDxL3UjhPw5xld3zCTV6zYfgnAo03dZD11wxUh/Q5xKKGS8/X8ufOFTBFbRHm+rviglg7vnp/HguGIUhvloaaqy2gP/obew9pcOdOWf6xqx4dT9Ri3618GJ82F3Y9XwQR4yaBnXQPvHy6B+Okv/PIu/tJ+XcfLZOXoMWFN1DLW5VTJI/Ds3/XmYSehW+H6uFgtAW4DUnRtYMF7PmrC68/PwGDA27o/vA/8L1pDnJXqlH+sQOd9lSi25eW8YfXSpC/KpFbo6fAo/2yaGf4FOXCJ8PsKE3y/WXDRrUBvOyyK+xMsIUlTSHwyOAky389iH6z/nClpCrcE5yGKHkbpS5ZgdCiaj5tewV9P96EO813ecLG8zRigQotUB4LJfY3EezXwfDsObjpYRSmJYzDxdGlWFnVB/5TDdH7/mOYN3UsbNvVw9vDDfi90zYQcj5LNzVM6Il6BHzqaCPZvB+YN8oeUNUY+nW3okDKLk7zDORGWsDdz+ej5PGd/FnGmvKDuykj5jfu0Z4OewIKYfjiSLTfm8ZFrgvxnrobRt1zojmyk2Gi+jiQubgfxcVkwXgoDD/lXiBJ35Xc9TQB01UCMc9HCIxc++Fq92u68tSUtu9iqL7Ug3f2BbKG52Jy6c/CoGWvyHNoJ2w8cwqroxZCjeRd7FFRAfebguBpIYRnykew56RgUhNyYb83hnj4HUJ9WieWmA7Hj4UqsHjXPTTaMZrYrQZtTHrJz6IQPzw5A26SCrzi6BfIjtwI80OGgf9kH0pZFwZnxDNwmskFGnbiFo8I14YQ74fwrmqAp6VW8O735jDuUhbUbHCiiQUnOaTQjz8NuXJHTh5pOOqRe0QqTJVbwSsqx8GEB6o4Re4oH2zwwj96NjB+bRHIzLTDogur6L3YF87NY3yTowWXl1XyjfpEKn4bALYfPkFVQyfv0z+HD4/XUUf+P6ZlvMBx94xBS76P1URjocZKgX8fmUXhKV742eIUdEmXMGiIAT43oYeXpSHAs5MX79FFmW4XWFlrSeWGHbxnqyA+MTgKr2UdwHjGE9rlPQpCfXV5erY3OManscgsQ3xQnoRK4sMgJLOMd210BU0XWzploASWi8WwolsQTKIfQeMxa/rdUsbDDnvw9KAmZglFmLf9ByvfN4fJU37zLpnb5Ofyjr4LA8h9tcWjpeegvcmDI3QqYW/IG9jjOxEG1tWRhvNXWBjgRZNq9oJHdD1nhL5gWasE8trtwXfnaKOjlBY86i0D32Nn6JrXKooEPfRp/U0/zDK44OUPuKk7kU1oKlUWKsJ6tyDU2rsLJrgwzJlmgiePlYLEjYn45NwQibccAXJej8cDTcGvow00lQvgYeg83B3hBVfSvnJJ8mf0WCqOKe8D4OLri3zAciL8/1uAuvWyeNxwJ1T7buA5mjWYrCjD8zR7KWHMQ1hVl0eJQ4agZrqBtWq94PzfKnJcOwhz1afgX8VVtC5ZgRK7fvBY11G0n6eA84lO1m1qB7cjm/lylguo7XjOTrM28OmGUt7spINKb35j974J4LihgM1+SbHqtxvcF38O/Cr02TMvn4KTkkD68zFYrziaHDoNoUHwIsTNGITJYlpQtjkfD0R94mTFMBQPRlxltRrEpcXh7O9JMENgMyheOA5XD1+DvZeC8fL7A7T09hLaGKhM7Yl2tETpCT7xFAJHpQCI+FxMb9dog5ivBM/+54LGcbfQfcVTDB59DmOPz8LkbGPYj75gIJIIAe1pqN21Hi12NFG88XaOmDieC72kMfyBPn5nLbD4ZEJlHoAz79ynY43zUK1xLX28/I7+bhjDaeGT6ZuECGRaI/xaOwLS7w1g3yXm+lfi2HA9jfxnvof2ZYcp0DKCw9MWUvkaYZganQBf/jntWN39HB92kcLdvEHlrw3sSLzHo9ZpQrz9XghepgQCK7bQwtQWVlV/TDf+uVjRpFOoOmYvGBZ846S9S0hm3G2q/sf9etFPXDA0h3a4v6PLKiOhx2EsF+m6UrmeBS2ldJjxWI2txOVgVdx3kozqxLkKv6DzZSSWr5yHsmEnuc1BFl8H3edrxQ6oP0MVqg8vY9+f22jx/R/oeNyDKiX7YMxVa7jZ3seDAbvYtrEZnH8bwJZjXvwpbBInrZGEfcUvIPxfn6mLr4W9qfv5TORc3mI2AdqnqME8o/2o9ySWHpz0YPEL3Xj13T06kTofdzclwnG7QYw7eAkitotC2wEnuHB0FTXFqlDhlkHct0sGr04SgTLDbezyRp0aLivixA+jQXb2buoT+0gWS37RqcK1pKSkxkMSk7gwv46tnBp4073HGLB/GigEPGbvtCc4eUCUjzwPQUm9GTAzYz/sIjdcuiaOjQfPksgCITh74yeuO/acD77Sx7jrUSB6bAu7zXjJclVm5PyPZ6tVhlGWvgxUjphNV9w8yUJ1G1vKTeTXbgtoQtc81s/pIxDS4jFLBeB2qjRYOQL7bWunEbpN/GzkV2wsPMcKkm9Zb/pdjL8nT2W3U/iTtgwER0rhzKNa5OPuAMUdKvhTNoDmtSdh1yJHflheDZfHyfGhdIA7lwfpUm4lCEoIsazdbp4RowZjVW/TiPCFXLcylQOc+zHZYwSIjRziCy3i3Kafz1HbDNnAfixbD2v4N5NFtPxmPv88EA2b/zlZk6okjNlfSf0zgvnu9E2oJvQdlx7T5GxXTfgj+YB8p/vDvQxx0IlvxBdPFWjP9hvw2imcamOSgOxPke4PLwjKlSTDv2qsIALwalQcq6bZwrCViWgZNgW/1IdBiZ7vv7N8zYqdOnBW6xyE5AlDh3ktPQ7bzpuke8n4aQcvsNlN0ttXsfL8rdT8bDVbFB1Ax45x8OrKPlLWMQCpr4jxkQ/A6kU3dSkeohdt+6D/RyUU72+A+K+mEOC+HD3c9lGVC/KY+e5YLRxGrh5BsGW1Ctx33MDfNIUx+YgIDIeZbJ24nDcPvgLP2TP4/OAJvuVvQkJO4/jH+hmQMWM99y0heCj2Ca6o3MHA0PnUk/+a99zczB+9DtJgz3cwtwhngfNbQHXMdIgRqsEFnb7gM6UKgrJvw6E6pod3voLhVkC1vUbc1V2Asp+EwRoDYbe2L59a2w2TfuSB9ZrXkJakBcIfbsL5NY5k0KlL7h9HgJnXD1wv5kPeLmJ04e5hltjiix7taqR7YymdPLCVRo5cCMYGUjBz+kwWnHibF1I13x76QB98AnGxwB48obiAX3ovhcP+1rRwuTJMu2uLQSHbqYhW4c4/z6lQPRClg0tx9cSlTNpKIGZngM2H/nnUtWC4l3qd43dMI69FM2j4hwxeJn0VLMIdYLmLHfh9FuO8q4LQo/mc0nfGg2RyCsgdn0YXogZZV66D5V4uRsPYbZBwqJRr3CZDXdkGOLdrBjy+6wDWc14B7/eAFFth2OChTk3Ft6EzejnsnSoNhiaSkPFoP60b34JnBos46nco25aL0daQCp6eAWRdZAO76+Vgk6sb+bWmktdoEfTd74mB6SKk/+cB6lW/hEP3VeGt7TJyEzMHQXjLP9cYou21hfRlymIU3uDLO5xHYlHNNfxhORwS+/og22UM3NlhzDF6uuRm0sNVVvNQv1mJpTP34Zj6G2S//TRunlPO/gtGwBUnZqGLOfjQ2ACtbB5wxMuTWGx3BPVfbQLt9E9U/7Cf1lipgdfvK3j5+W/8XLwPXsTOoFfFn+j0pi6QmNVHcS217CL7hKo+6cPYkcRK2tfYu38Cys7yZPu3/1FynxopLhpJsk6ZlNnZS3nmw8Hgwm7Ury2jd/rTIXqDMG3sSAOzS2HkPmwWKrv2gWinBKfMkYPz2Tdhu9le8Cn7BYaDTrx7sB1cj8dBSnU6ZpzKw9i+QyiUIgThh1aB+AIlGn0lkMO3XYIP5uvwpepN/l2pRQZLxlPZRG989h0h2/UcTNubjCOvv4cm56uobuyAdcZGJGm9gpw3AOxIT6Ko/6ZBz7AD9PCCN3O/Hc36Uo4KT+q41Ok8eP4egFTpXBjvH48r8qVhy10fSM9QoUwjK1q3twDuj9pHY3rzIdzFHeIOZrIi1rFJkBYc0AynoT/S3KbtBnNmEtS82gUrTq+krCn2oDC+gdYvUoaI1/rwqGsY/G7cwZ9uPONNAss4wlKLOkrecd+zdhgb1Eyz7wrAB3dL2HkglT/vV4SuzAbSednL852jSKZzMpQcT0dfv17QWLIHpn0fB9kySlDjZYZSWx7h69jLHDS7CeYN2VHdp2UcpHiOJ1p2gsf8aSDfL0lfPN5BWEkzrp9ZCFt8z9Ia02Qen6DFOg+CcXH+Fzq5UBGsHa9S5noPvNniCOLPbKEhz4guLJfibK/bNOajPIc6q+MNA0WQWmEF43z94Je+Ekr01mKSx3v4sa2c9Gwywbl7NI0Z8IbfN0RhivsJENZeTQJ9Z6AnbjZIpJynqu1TsHqSOW2UPQXGh+7RhK8EHwVm8CufJyyn+wGbp3qRocE7UrT4xS7jn4NO2wBmVrRwuc1IGDb3PgzoPCXNfR7kKn8OL0ypRqUbIZi3WZfVT+3k4xWPKChPDPjaY3Jf/400Q3N5q9sBcohzpmDl7ThvzimUXh2Nh513Qf4CUXi9pg6+FA6xgdQ2eBVkQD++ieGZGDd4rCoKTdOj+FzMUQ6SkgdXV30SOXafEy5I4/ialzxe2A12hmbTefcYkt/WQy7qqhAwQg1mKU/ioA811OErDoOZIfh9tg10hERhdEk9vCiM4ybJUPh2lWGtrQ90FM+livos9qu4jGsPjeEfZ+bS+4s28FloDfs0nOaGenH4oePGhVapPLwij9ZqNpNMwD6uHNtKzXfr4PW4aag53pD6HmlATnkBHK0yQgHXn2A3WwFOX87CK6cyaeDmTjp/6AGuOjzEFvs0QbRKk/vWKaDzif/Qfvt9TtX4Qkp6u7mlzJ3m/h7FvQr+IBlmCl65z7h60XKUCD4FE71USGVBD0cst6BtxqHocMcPzJxUeVaFOEhY/YLJQ99J+KIU7/gjzB+ClOle6GnU/2MLFZ1f4KJ6J2xcqQf2eTMoSlqSzm6tZoH1uij+8yCmXFwIi1etAKnvxvT8lCs6iljAkZ3leNH3DHqOSCYl73b8A6I4TGYLzv7vK8smFuLnKEUyCjeFv5qmkGnfRt77A8iiLwuL6lXpYvUDWH7+Eht+e088XAAKwkWhyiEbFs7cze/mZkJSezd/L03iyjdXaMn4bXzKR5ekdRpx4WxjUPUXxdYSHTxy35jkqr6zu/QhfujiToZ3ldD7mzv63/zGpi068HRyPLSqDtBAbz0pjt6JXq2jeK3IRp645R1OSHoI0vrb8fbPCeBQZA0tkQSLjnXROcWdPEzgCj6crE6Jj+bi6GGmtHyjHCxQRFANXI77qrdTXdxG8Dt6mj+0PsdfD6ShUSEIbpRq4udapt4sXVD2vgTbjq7B8ePd2OphMNbHuVHKgAQmSj6ji14L8cy0SjZRkweFut38Z0EE+EaGoOXzSThJUI3PCxuD5qYHNMTPwWMlgMI0Y0grBlz2wAeiKzU5/Gcn7+5NZf91k8Hm8CLuHSqGzz4fcJT7ZPCU3AgjM7eS8dm1qA+vUO6pERySkyW39W4QaHQEHo3b+o914mAkMoHF5Z2gCV1Z4fJBom0/yWDsOs5bv5XXHS0E3w0/IeLNRFjzZiHFvtGj8oQ8fNV2CGm0F359Ic29S67jwsJuOnM/ipMD5cDJQhn1BvTZNLWcOlY7gn35flwofpD/zHsKnwY+0tRAG4z+Lgcf9ZLRVNyQT4xbRl5VViArxBQh4cQ657P4Zlw3K/cMx+SUCRCYfAW+CLjQpzFClHpzDxVL2XPYzw74+3UWL5SI57O6nylSSuB/xJ13P9D/18fPQDIimVmhVFYSEYqQlpbILEWpRETavqW0lBSRUpHQ0tIQ2lZKklVZSVlJSZkpl9+tuO7B5/M45zzP6/n+50BoIfH5idlY6HsTlp8phK2vU+irQQt+aCvCgNc6nBJzjDtADj4kycBH6aX4QPM2WsvupPw/j2DkotfQgP7wfeoaOkVj6JLWdGhYO0DbdMbzqWW67HohmoIejEe5xjm0MCwM5ker0LjAMbjTWgaORYbw3101MEa5k6c7xIKgrhoVHd3KU2d3w741X+m55jMYNt8cxAP/o3ShI4RJaaQ7tFtvh1nylUcn0V0thIM9vWD/giP4QMsIJmMn9h94AP+OqrNdrwVdPDMdtRONARe+5ozlG4Y8NIp0gifBgWg/mrTuMOHKz2DgbI9Zaw3IWKGV5g8egTVa6ah0cQUqq06BorlHYbe3EhffO4fjb33HbWqncMnJhzSpThUktkWzxtnNGJFsAN+eGECZsRg5l7fh7zJ7qLprwHZ9Gzn2fDmN/P4PtWqOU6mXIYTaNdLaFmny/ujPQq6DnDpwAae21EPCcRMOna5PG+qW493Zo2HYsxCs1ffjmzIC6LAokef4x9Md5QG0WjeGzsTtgISxB8B0LIC78Wnq8TSld+m+1FIpTHdLbUB82TqMX2HMtfXPSLnTD660D4ffi4CTOqaDROw4rl1fx1ekF5LXidN49Ngl2q7pj4GP3uOkMoaHPxJ4j1M5ukSPYZUbHbzZ1Rz+im7h+4dysVlxComONufUKmnwiIiHZ7c2waogFbY3HsBf5j7kt0KDKkaEsfZaNbj+UAKs36vAjSsqLL3hH3V+nst2eTUwLFiKln3fy+9qqsnvxiVaMy4BgiukIFxggIIvhnJUYzQv3feNhAWtOcDNEAwMonlRwld6/G4zF+QZQsE+VWix+YrPPu2jJizE5G5CyYy3nCX2Aw4GptL+m3M59qE0iPiuJodpCjA+ei+rKz7mg+Zb6Mj3FCrbl03j7y8lwScjoHzmRLBMMubHC/ypdY0cdkZageH3jXjLqJe/6OmSbvhX7tPKpl3KM2By+AZYYvWe7z2oh8MbYlhY5yLUepwkvU8imLmmiRLPuqLndITG97UcobyNWkY04MPEKo7dKoaamYZs4refP6dpob59Fcx1UIeCigtU4CdITous4KzKPDRdXUPjZlSRb484X10UjrGPZDC43wjq6+djgGgceeb/JY+sVSzvGQQXlwbR5/SVpLlwD9j/C6S34/Tg15Uhv5n/ghy/eLGczxGQ0VwOvp/Xweh4RiOz2bgqIIHFzqiBn9x8vpTlxF6/ZGBPUDVpbr0N8g9s8ZrAfbZ3uIRPfP+SjQhD/NlAuF+hC+U29+HnYRtYGyEHdfe0YYRSJj5PF6OVXU70+PxkKD1UStu2SXLJ/iawPhXJGcffUd7XHL68KwqcDTVh2D8R/hczFQS2LISWY9PpTaEfJ35lfrNgHW3PzYbdU2fQ/brdlBuRjt+MxoG7cDmmZViD3dLf5BzbS1GZ3rDeQJbGrBdlm9qb8Cf0Ax4b8pGqwdUQ41nNUy9aY7T+bPKKKuFXIoEk7OKDXTtK6KF5DiapqkDjuCJwbirkrwOBsLBFCV5v/4O5l5ZxYmEb/pFKh4ffa4dyvxEcVzMHtbx1mHUwjpxiTGDbQhtsOyiPp/Ytw/8G33LflF3QdFoBIv6bg7fjruHZDVPI060F5y1u4ThjP+6U7eBvR0ox9j9TronRgnVCmpSzTxa1POah+TQ7Nn0eRYcu5cJ1+zx455BF7Y0n6WvjCChT6MW8fi20bp+Ei4L0ICd2NsQ/2QyF1cXQURKLB1NdOShlCiwIHkO7Rp7nUXP6uW9i+dAwj4fiNcV0PzCSQgJ0MWmIIQWnpoCljxnq6G2CZ/Fi4NhyhwPW16JXrQn07nkFvRuy6UrWEkwbJwyCBzxQIUGCZ98/iqF7jrJ/3gYy+nWQSrRluDZ4EBLXWuPsO8qw6tojNiz8hH81t/KGCHvU6tkIiz/l0CwzI5xzLI9cLt8HL115eF8ci0ev+JCz2zDqeqlHQv8MIWPUQtikaIXtnq04X76Vw5ZIg2FDLF9PEqE3Vgdhj409QuUn9uG3pHc0EAN+dNH0O3FkVciwe7Mtx8T+BpBPhU+ndpJNcSQHQQxnj5DEeal76flfWxzfIQdGDcXgZtaETYLfaWZlLGYbfOVrH8LomYkWTAqewROt+0lGdQacrDuGISJ2FN0hD46PK3nreAU8ePEwNV9diku7C0Hljwr1jJoGMmse0D8/G9DbL4MdIq3gNOUJL3l/iNcsnENla2UhvqsVF17Tg3GUizhSlXVnq8PB108wftQ2dPbXx8ddN1DinBN2xQTDnnwNMLpbSoM33kHID2HUwmIWfiqPK+9E0KNsdTiQrg4WVywRv4rDwJG3eOrGAFivu89F55vgnKowfyz8CMVt6XTxWROMFg2BubkjweCSEryMDyDpzuPwUWknXBQSQOny2xgzwQ3Gjx2Do87ooavMOFDfV0nZCb/5p/sLkDm+k0Xc/aG5ZzM6JnnB3xJL/Go6EpqllKHdupprb/yGoOxdPF05mNaqJKDnDA1cl9sKabL2JKOzmUI3y4JRZC9MnwWYI3gADZL/45DsFpwvCJh6QJvzYo6gpXMB1u9lUBBjfn7EAcS36ePo5UNeVvGUnF5kYkWrD7TtPsHlbi7w3y9JuHyzEU7Oe0qrdwWB3MkvOPHoazjY/ZvHSe/C84F/+ObcW3zNleFMYBLkLm+CwKZyij56DLZkHweLvNlo1+XC44aPAWHVliFWT4WZd5o57lYiHVNVh7kGnqhe3QM/bk2ilVpJbGVbQBMPVUH1FUloU7uBP2gcSDsfIozRY8+VznxsgwbEqvTTrvJIHCH+Dl0XD4cLlgfh6eF5yLk/4UFVGJt9doM5m2u4Vz6RBF/s5ZCVS0Dt2FiYa7MZXrbZcP9fH1YvAnpa8B95ZIvj4wcNbKK/jY5ZhrLo8tEw5/JY7OhIRr3HSyD79gmepHCPOzTFYZGnJXnPVOLU6fEsrKQLIXVmOGKJG9zLvEIX1Yrx1y5drtLcxPkaCznipxoGOf5FuS1iMEe3H9d1mlPo+2bcvfAwba+2pOCen/R97FrqS5Gkon1rSbV6BDSZGeJi+30k5rqdFq4wg6+jxuIKzS7wuHadF9S0kujFF1i0VhUangTDtcGFEKuqR6b1BBVHimnHqGacNnMp7FbyhZTJYuBmbwBGW6VhutVLiI9lFtBopQ6bRDCsKIN3R1VALL4HQjKSuLJQFeYkn4bMJ2OoyySWNMKVSa/0EqTrROHkYaZQKtjAq3a9h6nrhSDXYh6tvH4I3m7/SUvuuWLVegd64qkFfUW1NC/tD1qWXERW1obD3X/YQnSoN+eMxKcvnLD17g98++kWyJZPxa+GEyjNajT0/VCAGc1TKFdhC9TmFaFH2R/Od/DnD/+yYPzpQ9CkdBerD02E+ZctQPe5P8or6uAB1++o7PIKnlr/AMf76mR0T4xztvbC/aWHyHyeLGT+CYTg4G6SeDSPdxzYh5/bLGHPi6ckGByGBs5CIGNii2PtNcD9PlDeoDOufyxDq9cP1dVGidOeSUPx6lqeE2cBSXXhWPtYGjbuCABTyxoaPOhEs85PZNfjN1ihqRsHhNpx604T/nnnCFunIty6lAZal9LpVfhayLV+R1M3PUT3hxNoZPIteO+7gJ50vQPb4wKweMsjLuqowCOBnvhuNsJptbcUo1iPqQeX8tZjL0ls6gwQWM0QI/QEnkjk0rrDqbyg6SAezX4KysOE4RFqgt7flbiyvwHcVunA6qLxfN5hKjk+eEsvX1xCkagcvn/YEKbJJpIE1aHFngNQVzYSnllex+6xlVhnPYoXLGikNQ92o/uBJfT8RReUrOtlP+0nfDpbFnYtegETAnbzB9sj6F5rzMFOG3lE1hFU6TxEIhaP8OqdszysWBZy0k1B9IseNL6ZT0a7DnLRcy8YW+nLGRrG8OX7f/jMspH2fpYAheUXaDnpw9bsfnwQYc1/AgJA2OQ4S2inoNzpg9AuMwMO2+hAjvEG0LOthOkfa0HdYhZXTL/KhYVxsOHUFDq99hk+C9mEToUAyZ05KHWgDU9/dKTrMROgVV+TxkoHQv6ZYto0uxJ8m0ZCR8Vw+NCVT7W35/K9hD+gKVLKw7Mcqa7DEtvqR9CJzyupqG8pLThsCgesK+G+jisJH3zGmY568N7OnfvqLHn3z2e4X/w4b5v1FHWc5MB7czY82bcO3ZU+g2/oaLCp2ouL5hxB9v7JmJPJO/3cYdbyCeCQuYEXzi8im4FOPpS7gEqjXPBd805YuN4ZhwelspnPWZbpmwhSYamw6lYxWZpPJNGzW2jKsgmsKpnPWo+vYVynLB7aNheMXCaBb/sNTNPegVNMBPBn7ivenTkKT7hGU8HLBzSn4CTK712AHgGiENLQh/UCL3EcR+Fr1c+UqnicJhmc4QnD1elKwVc46ZwLj0ImQ9eWZhLR+w3ufo58rnMdz/1YjD994nDiuCSQD0iGTbrtvK5NByZL34HSFxPYzDGVO/VXMdqpwLyqYOwwnwvCkokUf9mMn2hOgaW7RmJIuwob5blSxsYTLJqlgy+LFSj9+CM4JevIaYlq+FtBE9YURrL8/Ggy32WLe+ethcWXTvGU76L0s9oBLm45A2+aRwM+1wWNAzdpnKMtxRwv4Rufu1mjFahdIgFvarpgpJgMVC6zR0drQ1h07CPZDjuOgZnl8GiqEScHFdHibCmM/VXOZy3MMEa1En+PF4FT6Sr8MfoFLJCLho4FkqDwcCL1ShTwjVHvsa9iK186oUJvZ5jB8D2ytL+nmebnfsT1737SCA1/sNP9DttnbSY1z2W8uv0/vrFQB2Q91+JbgRyyUD7CF30H2Mv2KD7dP5/bB5rZNOk6xH07xNWHpkHiszd4zeovyKklwivxIFq1ZS9XdoyH++sqOPqGLCzOkALHmQIgJRYPl3wvwIo9m+hq9QIYPDxUo4UhGN/4m4xVkunQoo3QK8TQIjINw1o/YFj6W4jXMOMTp45hcZANT8huxl4fa3h88CbK3h1yhENTyXD3PdqU+xQtTzKUzVgBI/KyuKPkCbpmytEpH0k2zzeCb+sMWfXNMs7oXAkjLWRRv1QA9wW3kVeCFf6XEkfrz2fAYJ4e3BjuxXOEDMBL3RddTD7Tya1h+EzhJc3W/0pzx7uDwkdtqogYD7OKXTk/L5J7jfNA67k1G7q3QudAPjcv08C/5nP44X+HuXC1DMS97WHzr8dAXDQXvO+/h1W0nsIfHIVryauxIcQSbNe3gc2Qb6VcC6aWIn3aMloOdlbHoMD5W5z5sQdytn6gy155uK7Egx8sEIJfTv/Yu02DZ826BY3L/uCslyOwoF4K77XewzP75nDhbE3cEiYJQhkv6Vp2OUTbf+FXI7dx2vFLXNz9E4uLksh0SyG/2BrLqU6iIL5TkevrL8CIGTl8TDuYrUqNeNknXa59cAbevvekOT/sqCPDAObZ/YTr34up6PsAtdsbg+b+9fBO0Inmexpj7q+jZBESSGVp8uCUJgF+hwz5r+QKiBzs4MGkePyQHgfnd17jR4OykNi2GRp/KMI44WDs/RFIZlaxEPevj8BuGHxqXgWXr66EJV904dq7T7z6tQWMWP8Ol33bhaP2fqKvw4qo5t4OONG1F31CBMh3ajJ9Uf7NoaeFYOkoa77sGwOtEdkYGLqFxsjsgVkPloCQ9juokbvD8R41ICM4CXpmOvCuVR6c0+YPPQbKcNzwFn/Ov8b7XRZRdPI/8n34mqcZi8D2OD1YdMWVWmVPsEnLHujRj6PD0jNh88t8EB9+j8vL8un4Fgn45FqJ2wWLeFhhBwePOIALrC2wUWaQhh914OH34tEnFGnBzGlgs74EbaZoQYeeAxmITGTLxJt49spk8ngQjhOK7am3ohivTBSGY4L34F+XEB1yV6WmfcH8wFAbzeRD2OOEGhp03oXF199zifYMGNzVxxnFJhQ3ygdTO6tQ2Pc32k//A1WTW0H37RpqntUEdYsEYK7bWB5zW4LOD5uHrYs24qyln/nqTk/8K1QFAZUpMHnObd6GWjD1xW6wFtWCuWHWGDpDBt5HNaNA2i9MerYZHV5/J+mTQ7xp04edfx7yCe8Irvf5Dr4XgnjMfwVwNXUvrsrJZonUHK5xkWHHR9IwRcaH/pzOwo9tb7FZ04xGqohxnc0pTDx0DIRbmjl8cBPe/aEJb+TE4IB5Puys8MYXRXP5XbcVXP3bgzN6W3Di3o00OfkB1XmZwIQvRWQmf46Epayg07ge3yjYYnGVOr802U3O40yxtdsXxeymQ1nERj7ZXYkDtWG0ZJQtTNUYznEV+XDXsZHkq7fR2hpFvukqDUGb5WneYjH2XuaMN5e9gUVzq3hl2Sfs//YD9q9eCLXeC0nQYDzUpx/gpzoXaeEIR9zc2APpBs2oeg/I/kocC9hlYj9HYEX+BBid85N9yjNY8n49WqXuhtKno3DNpjUw73oZtW8PxuxRE2Cv1zA4OFkSbOdXUWXnHv7+9S3LKqTDCv3/aFPmHTwzMgUWyhNf+GABkxsiUeT6bMhY8pBaflTQoafO2DjxDWaf2AK27wSAJZBW/hKAaok3GHNdBVNeT+Zy5xYMlBqNjQb/YFROPccc28M3S8q49q4O5AZLY1FcKK9OeYaS+aPwOoZRZcBlWPZJCBqrc0HxKaJGty78muMOvV+fk7tRHguUVvBisX0cIZUBsQ3f+PWnWsiX3EBSZYpQHVuL5BfG84RWs8IjgpOBMdiSew7yxzqio7A3jF1uSIf/TQbPmWdop/BmaKnOY8MLV2HCDTm4KCUNVmpTIdjpGnkpF5H1VS1Yp+JLs8pDwVn8CzwZVkKKp0Tg9fVw6vMuoBwNAbAJqqNZdyQgxm81+V0ToVndPmg97Rdp2YVC16N2Tg/NIRmpGzS69hyO22QMz/QQUz4vwtTm3QDbvWlZcDKqXOtFwcVNHJxuA1b9BaT/TRbEiy/TsNhuvH3WCfau1GO5xoP0MNYLJEab4ozBBEw7uA3+3FGG1BVjQLtDB23f3mblMh1WvSRFcnIWMEPTDKb+O48Nxc1k4GoI931X8l3ZqRA+5KJbNLXgS401eR31wcmrq/FW7FzMndYMPalaIEGmoHs+ApqGd9L9C7eo8ek26ig7xq5L5ak78RnMDFfhevGJEFW2G8ImXGbXRHFyF51GBbOa2D5NhuPf1MGC2uO8apMDzXMwhKR+Gej3aybzz7kUlD6aV50I4+XTdPnsneHsGl+OXYuG/q9DBVJ2/8eCGE0eW4OoyvomdPsHwSgpT3zhrI4f1IXo4utj0NiqDK9HuMAbJw/027GI3ijcBxGdkbQiFfn5jdMwsMqJr+n74zlhUbDP6KCeubpsuaiEp+oDp+7JQzBLoCPJZ+i0iQYWn5sOjWdNIf3QVXS/O4MyLg3A6tHp/PB3EQybcZxM/thychrCpTc/6f4xGQgY2o/arcHYss4C//qnwf3QHvDON+GSn1855PAZ7glJhP3/xoDx2jYKkJ6P2QE1ID5nOZ8N+MLF31+iee5+Oq+Sg6PPtIOboDmoRPdzx/Xj7N6ykC7ouPHgU3XwTSzkw22neM8xJ+pyHMsF7YZwtLgdP+9zxGUvE0n+nBt02IbBrJYR0DbkMAryOjx8cjX+1JGCR/q32dF/DR4ZiIezLTI4Z8k/3N5YzWslEZtM1uKZlANgWz8daodcpLdInjIxgN9JXQPt7GZo6Y8G3V+mIL/FDpfdeEAjBSTgdmAQHVxmDWHP/+Ai4SOcV2PPyrN9mQXnwSHleNo4IQsKtEfCcINaMgm8R5JNL9DEcwIP/B6akUoH8kuu4YV7syg3cqg2VwXg0SJxmnEum+22/ePV3X0cNu8ZCz0XBZXp+1FxVhWc2aoOE+JUYSyPpKR+VZYruk6yfa+w2MqA19ftYdNF7mR76SsnF//jUzE6cM1zNzv3pdNs0VpsXPoShkv7Q3XBCXrhXEtdflN5iU4NXr1sBMv6w/D4+TweTBkBIl1W9LLPiwzERSDEz4f2qEhS9MN4TrVnWHpzPk5IXUXL7vhj/pmjeKqgAt9vnEe3H58kicxAUOrzgTkyMpDatwXX6e0h47AAUCzP4zWHR0DnpzZyU8/l6EYfjm2twaMbRgGoXIHnh89AQfJ0lC37wU3j2mjaoBP8UTpDgvN+QPcvX/hUrgsmt/ajPY+mwbleFF2gjtvfrmbtP9/56BFlzp8Uj/u/zKWOh0O5Zk4a7poXTu+2ttOc+I0g+8yT5veM4AbJDzxlVxaJikxCmfPTIXDAGfeM1+YYAVHe9Nmeb8S7QuSiG3hE5iT3PxjAweiz+GfPRBAe+QshRx5uv4uhxBkIJ/L14cfYC2z8aQ57OGvw5c8fuLBsAnzPVIcZNXYswYqY2ClFPtYncWrgRUzgE9TbkERnG1TJecAIxP5u4A/6PjA7LYsXCOpwYNw5KNtVwvu+vuK9O+RRbOU0Cu1QhvdTO/GqXwU1daewRk0zuSr10EY/PbQ4MgY+hh0Dw6oAzFTVheSDBbwoNwkOj9WHqOLTlPUwHXYtdKAnR8R5adVlumvYCeoa+jDy6mEa2DkMzb6Vo6dfND29mg0fZtjRGiVzyh+eRpG/H5HTeTEwvd4GJZeC4X7rYwp99QIFL0gOfX8IDYsXoWCdkCGe7KW/P1Xg0NczMNxOi1WNrkGZnzD/3TaCJ4sOOZehELhuUoB6P0UUmCkLF3bvoMZ5p+DsljGQ2zaGtcZ9I+HHWfTh4SeW32XILTiTMnYYQf3geNBanQZroty46HoWflrVztFb78LZtM20cY88DG+2J58PyvAh0Jc9r+hwzuiJvFf3Bry6VIpXGlZxue1EqmvfgdV5YmxyZhQYhB+jx4rT0aX3HXSyE6l0v8RJRRrcomsCpk/ngFbUcX5VpQFfrM+i2NOldH5bKlCnCC49UgLLPsTgtpQBGogxxknX1mKLkiTUbPgC6YonQBDtwOL9fjg/RZSnfF6OattiafHuubx+lAnY0VT49TGLmtIy6K1cJAg4iUNCezxqvVlOUT/UOWP5J05v7WUzCXMIX6UJAgfqwNmii/M2OYPNdgnMVq+ktbnZsLzmIqjfNecsPxFYohaF24758VnlyWSqYUo3K8bSK41YVg98C10pk6Eyu5K6q6QgnG2pMs6etjsZQPpxpM9pr8lp1U5OF+rDpXtvQslYVVgVqQ57NzVhsmUsnz+Uj68KN+Ls9mn8MqQO4m79gdId73jF5xCcUTYDdsoEY2BkIQouraPhP/bTai0XtOt0p1VRKthSbAqFF8rIBoRg488EHGfhy8sWpkD/ZlGc1eUESquXc0PXbXB6pQnLp00H6X9mcPx6IhxpjIURzqIk9tAZTqvp0SMRddqcuRS0t89Eo55gUHqkAvaKcoi+7njl0DN0vylHP57u5mHmu/DhpRk898wy3Oj2neUdRCHd5gw+U3WFC4VjeML5y7Dn/QxqVZMA+4SdvEapEpU75rP2WnH4+3gcOKseJI/eH5RQvR+LRpXBtAprqHD5icufncTGEm+891cWFOUvYHGpBUYE2VPhk0i8vuMT6D8bTvW7F2PNKmEQGgxlgdni8KA7l5OrZWnbzDF88ZYLOpdfQI0D0+mz9n5ccGc2z9l2BzbhWHB5HQNH4jOwNnk+ip/bwbdvqONl+oMNB77DLLFXZDrSHs/l6MOwVkVcOloKtrywxdkRk7H+ahjnC9jA8SR5rPsdAKLKvvRopRrYl0aA/MleaLA5CrDoE78NfAffQhZBQdMhslvhw/0zJtPWGWKgfOEADT/mi57TNEjMxAddWQpNu/aDjXcPVp0rokQDCYQLQyz+EAW/TkfCwWm/YduYVfxLbA1sbwxBnfgU/DDuAMXcSoUj9ePBIWwGzJ3pwaXqQ7uppwB/1ezjkXnH+KaZBG2yaqSN5+bw0XpBSB0oZce8ERTa+4U/eK/m/90ZjhHJpPaiR1TTk4KXSiJINl0SUu+o0ivR9+Cu9JfWCTygfZGTUedyC7nF9KLJTBd2LWwnJyUhyNSzZOnzM9H32U74W7oTdW9fhwCZdnqYW0ORLROh/notrRyjD7ZCp/h9SABcHTDBC6Yp4CCwh8szEkDaVBKWD5+P2ipjaeKHkVAlrcBSOzL4VsFscDIzhLP/LrDJPgfwSBug3OYT9MPxLbQO5fZl76PIM3cMPooQ5aXjK6BIegqoaDrQ6QNCtDjkI+kLWUByggJsmdJNSqJ7uCdOCkG7kW7mj4UnQUokbuBCZayKgvvUcXKINhxKfYXBLkUYfOU6f1F5xEedfODq5ZVUIpfGIqlNdLtakmbZKEPEBHm49iOXfl5Kp6sfk+iW+FnQeAz0bkofWD5MZtt6TZrJEjC69Ck4/F3Ld+fY8yxbWVa2TGKviCm8fu90CBuacxeNl1A2SwT2uJ3Dr3MHQXfRaxi33pICfr+ia/q23HZvEM/tM+RnqhcgvnsyWEz8SVduevKJk1V8M+ow67zewTF2iiwQ1g7uLk2sGynFaCkMp3q3UHayCx1YUsuZL+8jh7VjXfIxcJRt57XtMlC6swFehOrB4FRTuvKxkOdEmOB4rUB81X6ZV0xLQLOzTei3zgYMG7ZCiIsCfEyuQPPOClZIUcb/psykFbuXUuWNj/TFMhsu/nTHKfXGvK3XEIKjI/DOl15s0b5Bnf8dwq+FR9B9+ge6YRpEdzNXQ9/46TzBXBQiv1dQmed99k8x4LsWzSwR6w0njB2xt3gE6E03IPm0HPBMEoW3vZHoNlyY1pgMR7nrI8jZ6QH0yQZznsdiWKngx3MsxoGNpyCcF22GxWk29Om2Ic7Snw7VlzVpfMBfiP2xDae/U8CUqUX411QeUtvM4G1RNvSmacG0mrXk9SCAlTQdcXTQEoowc0c7/kQB/3RgSkEZ7vq3nwfW1UOsXyGG/7oPsVmH6drpgyS6X5Fqe7JY+5MEvNTfgJOOaOPcvf+w2zafDZc64rPej3Ru+EVWz33CDV9+4vnzOlCodZiPyB6m3hVqOO9oLgf9imSPDuTKvBI6cPArpGyfTN+t1GHDhXiS1NbktC1rsNa8joTF/dB7iNOmi/bCooV1kDtvCso3GoDS5iqWqtvCtiOfcMrBIxgZ44u16Wshqv0fGyZNoy8i68n8AkPDkTfQqeuMPjnT+EPWOd71RZoC3SpR+IYOtHmfIxHjECjQk4DVk4KgReEXeQpZYkNzLOzYKs5Wn95Dx3h1/hOTzn+jonmOjyCY6gqRuUY/H/hqjS9UNmC1fBkkbPlF37Zlcfz397hnPeG2MCnwKjyM2jl5WLrdD3Lu38NZftH88VEF+U+5TepVOvzC/C7LHZWB06Ff6OXlHsybsJ2fBrWTs/NWWH1yD5yRioBpntrY+LKREg/owMegVko+Xot1R/NwUdxlOCM6hy8H5+EKDUs4VhyDSy5d4zH5RiA//ytP+ReMP58Y8b2qXFr3MQ31SveBS3wMl6+x453zVNghQhbszingC/FVKF08nD8bX4OkqBUYOioJA8z+dxO3njzkWkB7kxEIHz1F4tIB9C3FgH4IqZHFyhb2ebCfI4J64aZ3J71+20C9WxXAVm0surcsgs47r/jM7FpoDroL1mdm0Mdj1nTZVxz6pe5CedgoSH35nN37zdiwlmFHbAmYbLTkuxMOoYtZCw2s2gGXnEej5XeEhwXPMa3iFzQcRJL5E4SjUk9QcvgjkJgSysZNc+mIoQpv15UE8f4E3qZ3EsKlLSDfJ5meyNRwVgfj2blPwMBoH5+y7KLqtuGw5Z4yfVrlSvEjtHHeiVgU8tvD9W1qfKmlm8vP3KRNDe+53HskrJb4Bkv/eJHs5QO02JX4ifpnFnv2EX+Pdcf5E0dTwoFJkC5A4CT4hM8muaL0p33UO/YIasodhfghF7v2IZ7zlz6nIqvFbGktAd/ttNDjiwMMdMiS684a8DbdxKfW9PN1643Y+XEq9oVtgI+KI2Gsbx673xfg8B9j8cUXIzrin8kVm2P50rkxuNHFDNqjP2JEsibUeXyEbPuj1HAjHsRtdXHimn+0d/seSmjW4p9NfThykQhEvB4HXw2ucGqGGsUFrYWHNdUgllaAO+qlsb32E63NHIZNuefgcJIavAsSYofisbxy0ikSnniOg2c38sF1k7F5wlT42jALrsrbQvZDRRitZAmbc87RaoUriN7ibL13yGm/VENEfBSbjp5MIW6TeHC0GNzo/c3N6qu5z90MX73fSUEHF0L7gfW84PgqzAqzATG1PpBaogGn+8r447XTcF35EsYdSOPMO29oX1EVzy4xRr1IO1bs+UZ1H8zgr+AmXN8QyG9C9Sk37BKNXKWHWQFPuMXPn+10u+HtFAcOL9SEi+fCQfObBMrCV3JLe4F7+o9hw6iz6BEpALaB72nOSVeKWTgFLOrf85Ika7aInQJm0Zcw5+pabnjwE+JmyYNW4STaUzqOtyaPggPx5qwt3UA7tMWhS+ULuzUNUlmmPMiFf4TbBuvwwb5yWnBAEpasWoBdK1di47f7KL73GPwSe8FaR46worQpqe0v5aXT6+Fe7Vi4SsWg6GJF0tdWUm96CcnLroepl3eQkZgLZzkIU0bSU9jkLQW9Px3ZHObTNw9VflstxyXLXdFoyiSynWYPSgkbIX7SEJPchsOxpvGcvqOJknUfk1f8aTJUaqO4jy9Y3ms6+IvtRau1VrjBfQqMOpTMp58Ycsf+Upz+ehsfNa4El6PZcLBmBTXrHqXQBVGQ8nc8vKUX9Ex9N5y/0UGbbDuGPPI7XBXrh/X3ivBi2wh0GNEIbxsngG7/Ffp17h1mtWZg9MNJMHJv4xD7rWnj9RI0yq3kk6WOGNxlDBtVR3HX881wbf1u+HFnIwWu0KWn+iUUG3EadYKHcZ9pL1i3KIHaxF10/WoZ7tyoSTvOllPtYBa8EiyiGet1IWp2C2u0HaS1MTLwRD2Jshxukp+IHVZukMcrRU0gFCZLWTsicd/AZvZ7o0MPvJQgy0sKZ3kXsKxmGspcSoSkXfb46tFLWux+n01Ml9Cpg9lg4krQPCsa64QncP3ue2STJs6+TdP5cfUW2tJMsOqaJ249HEu5tTNgf9suzmjQ4vfLj+Pkddc5M6SHp51IgmTBTJb/0g1is3azdzuA8aebKJklSaU/S+hpaz6K2ZfxZp/5cLFwAOdKRsHtQCmWuCsA8Tkn8fjTDnrQ8IF2tm3AipZRbAKVMHVnPbhfPQoevto0NlAXzPMvQJCqMDw+S7z8hjw/6tzICoYeGL3hIYsZzmC18AZwyFEClQePMMSkgtTfBqPWn0S2zR5JJvuqYemw5zRLvoTXLliFSYJjoPJxP818XQ5n26PZTKyUi2/vRNPm1fypdzzd0WmGpFu2ILBGCp5YrOGi4mtodKGJulW1eY11Iut07gOfi1dxfMIPviDezsb7h8EpcgAFKSKZG+2U2NoN6BSBoTFWZOldg1ZBXnzirTW1VAlD1ZEpUNvzkNP+VEGdjwNvL2hjPddkiBq0pPjriJUX7+EzEX1wjJEl5yYFEioy5dn4hmfteU1CMmpg4Hkc2ppcuU8klpKnGEDvsFxY51MJcXcbMNYigacrDTm8lDL/rGxAiTwX1FAWwCqN4RDXepBOFAaSs04Q+ukJ4MhMUf7Ju9gjMBgaTMrxj44yf/0gBWsEd4L90un8dmU1qxRLUNXeQWi9d5kHlFaxdLUXtFQ/Bc3ZGlCuF48aZhuo6aoTn7EepP2X5OjTs0KKLh2ad4hg8xPiNElaEl6ECeLlpmboSgOM/W6J/4LlsLXVDifNl8PykjJID6wC58GxIC72AW3nvyT5K04stkkD89Wz0EXTml+cCKJ5p0V4Z8V6uKOjB7sjXUHpHfCRpx6k57QTc9zMuMmrgUxHLyN3MUWc8fw/0EMLuDozDy/5m3DEqU34yf0HBf++welJIbB3ths2xewBK9uH+G2XBgSUPWD1dQvgzaVj/DNRguYO6GCVmCAn1vqzy+Z8/qG/liUlTMEyT4b0R7myZMN92FoqRI2kRQKdZ2lZXzIuz32CTYNXUXmWBJxd8gb33yrgxhBPLEhTA/kDm2GdfyJ6WHzD6nPLOC9uHQ8bVITimjugvn8AZJ/MQL+TetC2oZUyVP141A9veG15Af4+TWNJHSPQrz0EJeLR5LzQjT9lRwG+d8SidBko0d7CJ6JC6YviErAqMoUdN0I4N7iGz284Qql1N6nigQgn9LxhqWs9vD1vJ47edZii8yZATXowabi/oodD3Pqe+ZK9a+7SqMAbMKB1A+cbeuEaU3WMyhwD4n8fgNWBH7B/7EV8f08LT6luh/t/fkBzrz121Rryu+w2Nj5hDNZvlGHr0zo8s3gRuQU/Yvc5gjzF0wQ9TizGvqUJ5OW1DsYmjoFJuvdpoesxXq3wCW+fOIcjNhaBb+gZnJSnidPyC8Bd4R4Orh8DVeIeXLPsN80+v5BVisYg5pjQYQNX9m86BM9bz8PspY2UamYBE6IWo5nlc9rJ3aiUEEzppolIa0pgjOZ38tP1o4ljnVFmuiTU+V7lsfPioEm/DeoS0ilO5hZ1y+4gp3G6JPb3Lh9f8YEHSvXg9s8G1tjtA5UaNuiVuB5PKM+nY/njYeG7CPq08gQ8y+ilwW0msOZgI+fPnEf+fz+jw/oeHKmyAX7MKaEBpzLobBdjO50x2Co7DZ5V/GUZNQFU0//JQctdeFnceoj2/wVaVh70cdxKTL5nBs/cNOB+sQasrTPlTQs24rqMFJad8YpSJtyg/wRPoArcgoAHUVAVJg8hq5iXl1nzLf98rDw4gya6nKTvFXO4u1SLT9fcQGHZ/71ByYOe1FOo2dYNe7PnQPgEcfDJn0vclUXfbqVi/MBa1ilvRLEbmtA6YSltXJRNZ68a8OcDhBEzK8k/qpVFUtSxPtAI8kYtA+93BDoWXvhr22hYvTCKovyv4Eefr1yZUI9vp+iA10UV/oYnWXecAgSWjwJjucX0hePB7kUP6h6+hXVPdBmmR0KjqD3MFovDv6+0YHrzVVq0L51u7hnDGp0OOFXOG+5Xy0PQUNa2f15AGSHfwKZQBWabSMDyuV6o1rAAmpTE8Vh8AAPN5WjfQs4LnEt9y/+jyV9NwHOeFWFvHMfIBoLR/W6uCJGG7ZYzwTT6Cm5ZK8bKacd57s1hYP2hhb6XLKDAPZYYcug92F3MJNVLOSiZMQfkVWxgKyrgaHtlkDW2o1fLUsnosBQcuJOKPZXiMCeyDDqCBdEjth9y/M1x+C5zcHgwHiIUR/Dg1iyStPvGestLKffHDgifv4OaFfOhq2kvBA65a87fbkpYc5pCcBjaK3ZimNUJ2KIvS3av79P9mMm85OtNPNdnAt83eIJT0FvUW5AJX5d+o0jLKu7sukP+umqwaNgtOOiii7duzYAxDT/44JzVvOF1LB0YlwqW/YGQE/uFJ93qho2aA5SZ8p1j7bRh8bVTdFn6GP+p9cOApBn0yr+O5X430rn9FRTqa0sLX3TyuBeKEGwhgjl3z+KhpfqkrBNE88vvsfQ6a5r4sIHXZI6g8rv6sFbPAswcdmDV5VJwvWSP41x30nZeix6Bufj9zBvK+vmYVuvZYKP/JAgUq0Dtui34xEUTrx86iTU24rDQdiRJt97nh05JwM7xPFFyOiQ6r0NZ6YXQ3eUGOG0d5iSYs1i9G18aVMZ92j7cPqEade3koXzFAK63yOCEtqO0M/A8hd7LBeEd70Di4iqqmyRPTuLz+eLQPn+8s4Hi9w/xfpU23ZjQSqeshPHghXBy6VPA6sgWvLJwGU0bBAgCbRbobaOA3BZUPraTo9SWU/zW15zyegv8tkig4z9Ecdb+sfB96j9UaleHk09fwvZ35+DYkd3gHJoA5z9cwrsjI8B5cRSfilMGSVk/3HluMg6yBUZ8+DnETH9efXUxvpOVgPCsmTxQeJk/9qjAec8IOnh6KfgvNeB1xtLs6rgUzOWaofORGtV/mECDNw3Rd5UstMYvoPAzx/HvyWcgkp9L/70pg+pRUfx0iyld3mKGS622glHSRCh7P421K5YM1WklnRrjyxPX7gKHA9fgXUsKX3N5z5nVL3mdlgjkdtTTTIkaeGwTD84is1iiZjtseDGVrx/dCdMcd2JPijCFu0jDjKZsSgvcCndF/CBxxzVorbjFPafyaDXZkr3MNHr3eiouGq0CPiZpmH8xB9tCUyBvUAULOvrR8uMSXOEehK/Tf8LW3DMgJaQKK3dK4zcrB94trcRKktks8i4dy4f5g0tjGtSff4zmZf+wZ7843FR4S1iuTcsk67D8iSGOcSmguvEdpPXzMfssCIEffol0sF4G2rbmQsG3s7BypCkLHRmPk1wuUOMJbT7C30AhdxOdDAWOb5SHW9E9SPNmQU5cDP5U2kLtK43hytMrGLwzC/IvfKHDpdvg70tdcFE3473P6iB5qx0+ftgPmx3ToX0o+8y8lI3xpb/wdP53mlKj+v92/3dj0nuedeUx/x1fz3fLi6DrYiEvySxiLJHjD4fO4a4Nu8hsiJtFi79Snssiun7bBwLuIoRPrCfvlA48qbIOj9r+xvNOhRy43RzcR9TCDjQmq7Cd9Av7eV9kM6VOlYKy/yopZE0jr3eQBjsrdYgKS+QPS02w7rQQxVz/gYNbVkD43e1YOz8WpOZfgU7V2Sw3UR/eTFDiBUpVqChUjku89OGkdRhYCU9nMoqDz2P2o75wLchflAE3G4Dc/x5A1npDUM3bSGOWz+FAmyv8N7qO/av+4eaHPyBGUgmgtJpCRYtppGMYf5TXo35/BfLyHyTPlaU8Vekeb7BaiX1do2Du0XcwQsGdBscM4Eu5Znw7PoOqJk4Agfpr0CDaiBKxv/Fb2wj4sUsWQozV+O+WDqoaIQpnvvXz1uV1gPl1IP4bedrwBlIXHQXJ/9aD26PblPHOm04qZEHQZH9YLpIPA1dWYHB6KpQ/OsO71U1gQS1i8ekumnbagfYVvgJjn5cgFPeLuiPNYdXzGNBWMwG8Kg3+3f4Mr0dDy6GPFGkbg48+fOHlH/bQRPmFbDvkOKUeApSUqAsWSl9ocNgVnP2lBzIal3C87BoKr34AQd3rAVdfZBfPb/RWUhhSzs7ET95qGDPNm6umhaFMxjd+kPqEIiJTYU3oeZZzU8W8E1JwwWgshg7bwFHDP1HxSTsIH7mNi4yMoc7BGUS2ScPf8ipUTtCBfpX5GPprHodKenC24zSu3X2Ovpzx4d6t70BWNAOmV9bhUxSFQrN1LNtpweGaDeT7WgnK9Cdy9aAPH7t3hdc2zeV7jp/xz3BNyDb7DYH69ugan8bvVazQO3MNrRH+Ae1V62lY1yBVnw7h5wEiIP/OkhdsK8Bchd/g/SsZsgO/8ojCMxj++y5edoiAJ553aZuiAqhI+VJQ5XPOLMkghWY5iqwWIqH2sfzRtZL9TnvBT7ersL9rLDRFf4NiM0+At6Xgo6AMfi3a4CRylmL3CPLx8Al8r2cD5G4WApubU3jXbWdeJHCVA4MTMPXrClq+RIsHZt9jYelovh9qjWNW6MLwtHuU7hfNcfGRaMg1vGuUKHWtGuQqSTu83t3DW7R+UUu3HJhtdyPHrrP4VPceze6dTSkx9rQ4+QkEZEWRUtlRbvHwotf/VKGjzwxePbyFfs+CofOrJXGsAi54vZHvXNuK9btlhzK+JOn0TIEdyc9wilIi/FbOhSc3FgLFDXllWTOOPthPrfeI8xL/0Jf7avDa2g0CuxNI7dNVdtJ8AAW5J8HgURcuVhTH1e4+IC2oCE1PJ4HNVhOyW7KMHIuG86ht+tT4JA7KJs6l6YbHIe63GLVXjoZzQvpwvTGPY0/Jo7UtwBbPSbQsdC5WFYjBzSVGKFtnADYSZ7heWQ2aHbr4z6cleNOxAIf3TaZ5P61xSvdpLNLUBIn6H3w4dBxdXSwAWxf9Ac+cGfwn/RfJR6zDvjYdlsBpFB4uT1ZiHqCdcxMV5Awg7Zoj3D6wHSxOnEK3MRP50KdrVNWWSj3fpmJD1j1SSFOmTbtkQPZoEmwyGMpe0W/Y+HIHvFQJ5FFjTpDlLWV22GfEIWOFYaSAFhwVT+Id1v30Ofo6OwSN4oZJl/i2XDjcLymkqnOAy57L8rRgQ1i8uAp3ZQ3HhvEZcOVsFhikNNBBq5N87+omHLZBjBduekGR86XAr+AbbN97HwJzJXm3wliWS5hN41mS6o4q4mP5BHiu0UGCW3TB9/oe1hkRSkYjV5CxTQusDEpGJc19uOG/8yCyIoNRsYVrnQ3hjn0bTW7qhyI9XbjVvICb281h76SNIHa+nA7ckiLL1vPsbagAb9Mno5/xNpR77IViuVUgJfeDCn5q0YPTlvzgej6+Se1DGcPhUFMlTJFWdehoMIqdb7oN+foCDN9hhAu+z+frpQ5DkCJ4pSwIV1te0D4ZR9I6ZcNaYQMQoNKM8n8byWL4MwiNP4cbq56g1P2JMMF9Jv4Ky4R/KW5QdE2CcurlIcN3K3vXZ8LnfzNp7+0APGKuBbEeAvhzoTlq7k6gUvWnMLB3Ncy2ziZ5u1bwZEtoSN+DZ3cPg1M738Bcu4/wcc9wGGFZA0fLssjG9TPYHoxDKdkw2DjSCO4KjoBRPqmQG2WL88+fh8mXDlH0rTe0xX8S3SoxoA2+UnhYYRn4eihA2jYFkvpwGSysA9EOU8G/tZjOCj3kHHU9OuVng9Wmt/By6wyomLYF7n28QBc+mFPYn6kU2/WUkzP3kU1fJx8eG0Z3QgTRPcAcdONUuC5Skc4LroKc3DDarPwdIlwGwG37VWyvmgu/V42gEZnqQIVxsD7dlCIPfMOwc8q857gcbLxdSGOcxkL++vVsbXmIZXfLw8T6YxhtWE9x6dugOfUG+FYsop5QBreoKDaNPwK5U8Np8p8xUD3jHFvHisOKACe+uaYMslLSyKZlDTwyC4K16dfowv4cWL5QBYp6luBt0fe0xKCbdm8VpQVHU1B2O5FHpDa8aYyCDcOWcILWFIi7aEHrolKw0c2VuxPe8CfniUPZvZ+rnj+FynH3yLXUja2yJsAzwfl8JuMzvnT5hlpvSiBtTh96/C2litJa2O+9BCE5FQdipkChfQrt1XdGX+cRXLjPnIzt5/NqmyyU1Wsin4g2FAnYQFlPDGCLrzbKvnGBSWeX4p9d3pgSL4C6JxzBdWY53FQU53ClaxBqOhzmb9+FkxKW07S5XjwvS5K6TJpQZNEb1tJKxv8eq8PymlAsejse9usMR/cIEwiKrqZZOiMwd8EHWKRqzUenx/D2t0ZocngcfxARhOgN1rx3zgpMiLzBehcc0cOtlo+GSfINRQEcfUaD9rYpUe9CEcjf2U+hFybwEp+xtE94Cl4Seok3tWrok9pf+twjx/3r3uLOXcJQ80aPjKef4RfrXVHkIUONdz0ssLvCnL4QlGs2gN4rR5bfqAq/TxTyUCOQoO9n9plzCcInT+TDgkXgfXQeFaa+4W79h+xrZQj936RgcncfGdm8pTAjZTpxUAWz1STJToPwzVM32DXrCr2VU4NJtqEsPz52qI9mUNGVPn62/z5s3OTPGe3buWOtDysu1obIj2KQsf0Cmy6yoLVGx+lRnRDOKdbjpu6LPOmMMU17MhoW62yjJ2qS4Lu7F6e/ucdu7zz4b7g4n/N5xR8s4qhSsQUFFTs4du0K9HKQA9PxYqRz8R4H/u6D2X8ywSjACw76eIOjhBOus9EAqYxl0KfAIHRMFW+4V8GKK+KouK6CRs+7DCJTn1NbvitK3btOQdWMTQWCoOK7BzwmqnKvwn+Ueb6D1k+NZrnwAHxdKYSnTMbg19zfXHLeAsTm+fC0fj8QPPucrdIU8ZPXAnpgcIvG72+CcKV0/v0tkQXLRGHjFUsu7wsCE5XleP20CtskrcObZm6Qor0UqsTOIEyRxIojU2HC+dtsIfoGphZthxcaS3lslyfVl5jjdKlEKnn9BW8W9cL41nEg7VRAOzLng0njcEpaLMt+jd6ct28Lty6tweqY2xQj5wIqD8QgKVKGH8j14+GOsdCeOLSfVtVi6bvv4JDwfxSadzgWXhvH70GJMkJGiMgKGSlbKaLSUlEoRYtKC0lpi6SSikhGKSRJIiq0lNJG/YyIUERRiTJe79/PdZ5zzn2e+3t/Ptf1mMAlCSO2HD+P9o20gAHnYfjayR/KngXi9u3xbN4WBdkh0zFvRhq1Nxvi9rXFvHOiOixR3MZiBUmk0/waZ47fiZqXhbBrqg27ffXgVZp/0UfYjG/FjIXNVo9JJLYHzEJfkcpAA+0YKEVNu3Ro7G3lnermdCtwN0lGaMEwn5EQtnEqaJg+RuttX0Bkpy2nNYpxWPI+ctL7jl6XM/lLqgT8svDj709XwXSHIhRc04IWB25RwAl3rJ59nA9vc6aeP76s94lgR0s1VCun8afA7zj5jh9Z/FsNd8IY2xcvwmlHP/LDFXPo3RwDSCo7CK9r/7H9jWc0/nAKd7pOwywRE7qyZRJVezmCev8xdvunBhpXlDlP/DY53DwFwnrvaL3UXx6s82DLd0fRI3c47jc+DWYoBjZj9Fl64nv4GDEOAqzmcJNRBm64uwfGGP9AchrNzRpi7D5TBRYv2k2LpqrB3AlDdV6vR7/U5OCziTSPumrLTUG6cORvGHv9UIH2Y+mcMe8PvdhWg87aJbDpqB5qjPZna49fWLGzE+uCToOAiyK4664DWdlTHH4rHjb1b8WbItZoi7tw6RxzdPPcBPlKwH8NRoJvYBCoVN3gK9/Gonf2fnq5Tx2uLc4kjdCndDomHX5r6+DeWYagvecd9mXV48n5a9DlpTo2fZqII3/Uo4r9aFgoKIsX06+xdpEBmEoTfFT9ghWvF1L3mR/cMe8mPy04CUtGL4BVkTdo+v0ieGFhBCvc/Kh3/k2+rzQDNxrJc7WhCwfn1OKyTYFw28QWs3UDab6SFLg6r4JjCR/ZPjeIfU9bsMMrZSiomzg00x3QftEdejziE59PZljn58iv1s1Cl0kHOO3YCz6vsYbFFyTx8ijCvffd4eOHJu6qGQuTyxVhsn8evfQd4LpbcTzvdg31GI3jkZdtIc71Keq7feaFf4Tgmcps6DMSII3h9+CgdREVfOoFl/BNlJCVjg9vuUHetRTa/ncSdGv+4dIiB3K3zaGSCT34pGsebp6/Hsf3afOyAXuoqv3M+6+KwansCEgbMOBnQhLY2SrPWckH+f1eZZx1t52OZp+hw5sdqe2bNKySE8QUMTnad2E3u4ku5tIQCSjaMIarM5eS6PnlKPDUgS9ITYaPOg40UiqXq1495VcBY1nN6A45akhjjstLPOXazDcPZrPiemkIt3CAxSZqoF1nABOa9+CCc2fg1rg3tPFJA/259RMkBq/x2y9ioFLsxDMVRWBH8SeW8WvlSYZT2ackkbMrxpGHjyn8udGIV3xVYLmvP21JF2NzXAhXL+7ALd5R+FPlBdCbNoT41VD53JNjxERBXEMRzdLV6ZFMG3X86GOtJQ9Z3/gJ7Yk3hUUZZ7BN4gRfPDQeqhyJww/34Yh1srAsLI5Va6xJ8vUY+Gk8AjvP3kOJyI30dLYk5M0x5uUrJ4O0lReYPlQBN4nN4HduPNkHCMPWz0th+ORevv5LHtD0BG0diIZNyoos/aaXS5pnwFS19TRl5ycut1syxDQe2P9VCq70H6bX6/7S25pynlMO9DtVlIJrLHBsixGumhHDFrrpOCVHFR7LLob5Sy3ZbbCFC8Pm4YOsc6w9qojeZz2AyTOFqAjGQVeFNKi8M6Yf5T1w4NwQVxiEkO2CNnxb2ggWLelQNvcbR24NBO9H1lDS9x6tUnrh+EExLKkibHtzHKLMz/IrF2/w6d2DQX2e8OmNATjN9UQzzRVwoG4Mf9DeAtUOXTBTazS+8JOg7vxPXJfmTxKxVhAGspAYuoJLHs8AuYZ0ak5MozU0GkKG+0C3ZBssvTCfsk6IQkz6ArrqdBJW0ips2SEARsbv8WZ9Cx2/GkBHrufQ+IivOFJbExxfaPDq71nkTetw9E8vFDs8jx/tv4dTMlNo2elOqD4jxY0fZeDGtJPo9PA5GEko0crUAZIw+8UKUx1JIdeQswJ0yM7anw7PmAByi3zB08GELN1jIUZgJO1JyeO96z6h+92VEBuvw3aHQtFl4lgoOlvCWxLCKWnMAWhKN0fDVc08X70FnLZNJf1Wc1wfvQ03LhkFVW8i+c6iQI665gtfXsThCrkjwKf8oNf2M3yp1eE+6xb8OcIQYm6bsOTAb540Zz5fV+vi7NQC1NjhgSk/TlLaL2leLmICt/NFQEJ6N2a7fcJP87dC8IlD8O/AChyWGoYTdIpp7wQRSJ3jDqsGRGHt1RlksWEVHwt5Th6fjVnqqhm4l8tTQGUZPHbr5kyF4ax+1wI6b+nx5P+e0stAIdA1LKf2rcZktbCPC4zW0003eZ6hbU5i6mrgqjjU91tUoWJqGodH9rBRTy4v3eVIXlfU4VdVC323r8a6kHGg3xBMtT/LcI+VEW0f/hY3SU9DTGpAIaNhfCvjKYwJOsl5P9QhXl+a6zXaqSbMCH5ddKCulOm4LLWWbiy1ALuIw3Cm/gC3lupCvPVSMtZ0pvj0n2iluZTWa2+ld1IDXPhrORq1fGb7+M/8IGAK9EXu4xHbDDFr/hTIqJhKGcMPcLruD1S4ag0jZlhTj4MGhbRLQOKFFpap/EluKiaw5O1faEpbwbuPNsBcZV+wfLUI6mvk8XauBiydsAvmTfsO2wy/s7GSNtY+ayejBUqYddcQQwRMoF1ABhRLzSG6OgnKkg+BxGtf/l1mBcYW2bjUdyvErteHe/2i1Bo2DHRcVOFBdBPJzBeEb1eROn9fwI2rlNBlzzSWW9FCW/YlQGHRTT6hrAuq01rgT+JLnCv+HFrBhHfhdfJu6sHqt454MmY2DLPy5OrGETDu2n2Ms5BBemUKF+6JcymNhGZdRQrPUCetOR0072895Qaqw8cJdnTG4yTYfxZBgQUfabC0mERT8+lk7y6ulpyF1UP+EtqjCt9+b2WPwwVY8vwzhkY10/6jBzHffwrXLFiEBQlr4TfdJ8epEmBgOsD2F8IA3pXT7Reh8MT3NTeIimNV/DQSWcLodVeCf5Ap/B7eAcITxqJM8XMy+E8XJIbt50dZC/jCw2qI+t3One+6sHycFmjdFOdZK4buolHM3WsfQn+xCfqsXYevS96T8Zx/PC8gGf4WDYPn89Ox9pAepLQ2wWHVd3jvwE4IWGlE3aQL26TUaYGSB9n9BzDiohyq+W3Da88nU2pHDAZomIFUZB965GxGqeLl2B44CiPGSsIHx1lcF+lFnuqlYBeZzMufXadFMfd4k8cx9jo4hur+3mZIkIWBAjuofjGdNcLauVzOmDfXFLHpl35oeVSL1aXpoPh8HJQEWsPs5lc418QHIk+Hk8TWfBx8OhkGWm6AmfEurLyYxj3WEWS5VgeCz1rC6jgl+G2XxOENDvhmhy9HVNzBt+c38hPXIR7ur+M4YSv4XFRE1Rv+cMj7Dlr62Z+n9thATa0zW/4aA9Mv1/OG/qu8p38Y9N2u4mliY3jDkjQKsVqAWuft6W14FavMjeR49Zd4SCeD/sqpQc66HP7zVwHfC/bjSYtoetOZA49vdXF5wiLektwKCodd8I64HkzPriUOmAt+V9+R1KNBetcTipPjjChe3IRShhPlptqweYsInHy0AtzWXALbBcM4q/8cHxY5w7PEFqOdtQuIXpRAK++VmEmSsGlBOsbL/yRNDSCNLwdgpGcLCW//jrLTMulg0F7M8nHFhiZN6H8nw8kbd+Cn492s611DZUvW0XQlMVhx3WLotzUc5CUC4O5oUahwnQX/lQ/wiMwivnN8FY563kzGr/VZZ90Behbhj2arnbnlsDqcqr6HH18ZgZfVEr4fsJYaFS3o4AEnrpzrjXi4Bo9vFsDGQ6ZwKMMXVRIFyGD9FpazTeBTfVI8bOVfHPH7NHc1SqBQ32V2T5OH6+NsuCt/K16ZtRCPLPZlg9owvLxzHUyJFeE9cYOYO+Ucxbhrg5SJCpxMKAHvt+6YMLiI6t5vYpGaD/z9xDz0lIoghbnF7J80Dm6N/QhFiX5wPPYIVIdehpuzRsCPEh/WjNbG6zcf8EPBaLbqFYfbfjrs09aGdzcm4tpTqRxfcA/9+6YwSc6D1WdbocZ/AdDVSeAMulCp7s1ySy24bakZ9R9ZwwJ6HeT36DdvXlRJoXr9/KRHES4cXQMV1Rfwd3YZGtreQKVMB1z9Rxkum5Ri/782vlVuCTMvAkidu0A3XvtT6Q+GXy5PacOTNVSSKgz3i66Cs6cWTPvTTIdVTSDLwoZmdcST2ik1KF97km3O++Nv3TEcEhzCWat9MG+FDpDIRJhZvJV+91iT81w9KrQr5WzF1eyWH0YR5zpg0odcnCdvxGIbJEHQMZaWix+AqQ0b0GHjfDikOgMnbtACv78n+ewyRbYWTaEJsdpQqj2U04HnYLXLSBI+wFgwT5WTvp/GnE4zSNu2hFJsf2G62AQQMk/j/B9bQO98Dk5SnsXnL+pypnwfPF0lSZflF+LMyDmYdcsQXN+/YO+6RLI6O5Ui/5PlFskdIJB5lc9azsRp086C4MtVrGFsBTek/EB2ejWNOdZHLzkVhM5LU5zsGBSsvoSRg3Hw3nkx2anIg/rXeogWHcV/7l3laYUTYVrQY5Lby2g/OxeDHffg18NHaP1eIRid/g8Spo7mccdLSLnxIUd/+Yz/5QeR+fRa1PhXS5Ube0hojBjc9hWD0Jtd1Cs/jEouWcI0dQ+S3e8Lu0Pq+MVZD6i/NY4/jJAHn9jZ+LnjPfuP7aLmvGR6ryXNKz+uYZk1j7lFyIQsVptQw1OEZpsKCnzZTTtnrSVHxxV81KKCNvFPrKiRphqjQPK0n0lHouQhqqqT+pMjOKlUEtbzBQ4+4Mfedg2geiURu4bPwfEnjrLIOHM4+VYP3ypl0a8rubiosJ/99tuzdFcYBt+oQH2fKLy/35Z9CtTAe8pa2mN9gHbobgJH+wGYfCWHHjsnAH3MheSBLDgrl85h/wTg6+VmHNnygf92yuCzEQ/Be6UAuGTegZ7viqScEwAhyQ3kdn8CbJH4BEpqRZzVeQe8j4/HDD1hwoNHUMKyHxdUbiH54nP8eoY5fL8gg6o1UzhlghZo/61n4f3bQEx5OJwcmYqGK+Jw9KFG8FMH+Gi+iWQfTmD/3sewbo4a7L/ZDD4hASwYgdA6lAtBbzaxZJYUqIrNwg/FEdgveopfZKzEN4aXSEbwHh4Yu4MGjI0gWT8UCzyEQffZZyQdYz4Yn40BTXJQnvET0i+UwuekZJY5GgLiL5bju/9GwcGd7+iOUSIYz3wPCcKnaYBbIbzFiDqMfLk12Ik3Se+kFzMJ3sYZc7jWC77924zLgnW4cuRJXFvUSpeLTTggJQEfLYjh2RmCoCnZgzsNA1jgiinLDhTBDHgL3RN2wghxbTB/PMRre7v5ysRJsPRdOOSNreaOFlH8Om4rtUy2JV2nVpBpOME7AkPpr0wrXfkhCIWhOTTx+R6sKAgj7/JT+MLfnO7aEJY+WYo6rq8RVebS0oKJMEZADvxn6+Dy95L0YaYILxBaATkTaiFQ/gQGTZlLe732gv94K4j+vphjDu2F8KZqSIlrYIORY7H8zy7SOWXI6lpH2URAj+9JIMzvCqK16x/TwQWjwbNeG6QnmvMSOzHwkLkMlgtewHOegg/uaYJ5kjnuXAgY6PyB6joDyCo7k3cPnsC5Fwvxx8a3aGSoS86eFgCDY0BLfzi/1L4Ick774fizt5j06A+a3rUn2wPiYHTvO+74MwIuJy/jk+mzaYfDIozoEoKT95RQ4+UOvNC8Fz+fM4C45ZP4uJM6DDhc4/6Z5ui/IQXpSxnoeveiwvEMbs5TQbddq8GzNxYynw0DcaN4sM26D0+3zIAvAQlDDWgHS94fohT3HlAPfsCH5hbR535JsHXcx3dTD1D/sEEUaW9l/SRrenzzNW6OzyDNdR5Q6a/EBe6WcGA4UGr5NljxXIF+l+qAjOBpGJf0nLt3WxA3PMYjzRK8eb419G0fwFVTZNHHq4FWBs+k5K1xhKkdbBzmCdtL+9ncTp01702E+U+PwR83PbqTXYSCradBV3UVRugLgcK07aByWZMcs0JAdpw+mGxKobxRV/BS6BKOWZdF2yQa8XqTB8tZjKI3ygYkZfcRBsNUgaVucan2fVpW9Yn2zErHaVe+c4fVLtSPTMeQN7tw97wU9J2iARvuuIO7+lH6/VEWPCyd0O97Lv85d5UstmjDvkUCeG/GaDieOQXUctr4r0Y7zp0jSDvSjEnLTJJ+pshzZuhm0nmdSpuHv+L3ZcbwfM8GSnX+hMruInhp/xNIvrKLG+0D4MEhT0y84Yq+h96jgo8hlPn9w8rHL0nqbgdNuP8Z3e6Vc9VbQQov6aS72algsKUfuuoloOlpF9rvS4NFSw7ySjsR0ipQhCjTOkyx9KBRqyvxteJl/t45HPxra2knmVH0jMs8unU3tkYtxMbLO+mP8DEq9r6B61LVQGGlEYzaPpNOBUfywRQxnhT9HK5FlWHMMzk4rXoex/nk0K9hg7BeZATYDA5C0Vsd8pqmCFbHzWBrgAF1CCmjeUEXK837Rlae72mhlxDsSbIDuXOTIMhLAA5la4NATA1MO/WGtgocpI4v7pyyxhDvLNGGtGk5gHIZEHXsG9Uri5F671IOO8W01GuAzkwvg0gtF2otNQCd5vFcEyYIatbW+FZPFnbmb4HrLlW43k2Bt4+1hupRzWxaJg2zRm4CgSvZJLL+JNbFD3m5vAbYXrHhqCOBsHzjROgsOw4FX0dD8Th/PDn+AtsYTYUVHvmsc+sLxDeGc6V9HcWIivK3SkH4+E0K5ozqxkHnQRTacYFdlF6To605VD6RQp3peeRncRNtXqVj3k4ziJIVwY+9t/G3ZB1bO66l8rKlsHPjNVIVFOXtZUvAcoMkP7FmOOL3A0/clQVc6IZbr1tA87kWurxOjSXl11FthhUeasvHYxOlITcgBrZazMK8Ax9AsTiJH975TFr8Ds6zMCm8aKWZ5RPoZrAMXCkqBlEPDVKbsBmUCr7C1s2fOERCAd+6LONlj7/zY78o9BkQHpppPTzulwdujWgkTdHH8EV0kGh5HpTYO5LNGC/SWiuEaTXCsHN7N0fnvcfISY/QOXYb6MiNx0Kxt7ynI5t6PY2x6YQ4SCuMgv6kadjzsxWdO93wyeWrUBAxm5SXBdF5f1FeEy0EWvdWo9UeAdhxNom81L6Rzd1wnvxqJmzRn8Db4tR5lLAiTtwvSXqOnRD0nwksFr7Dpw61UMX5zVysdAQVrZtgmH86V3+L5tVVIzmjDFi3xwJm4Q3QHi/G024bgfK07XS+tg+ESn2o7IQJZqS1ssN/2Rh30QgqFAIocsNYOr2nlOmbC9S8ymXVn6r0pm8EnP50ERS8VXHxVFHIEx9yqXBzDENFqnPXoUWzlLA5cBgGt80Bz1chcPTSY5zjqAyJZY/RNa+JXiR/oHkCavD0nzx1K5TQJFknKk3TossVg/BszcihOtfw74FqMjbxRqnZDyFCYxa+jK8gcLpLP2epQHa0Ie0+qwLj7Nez5aFk2PVyA065ZMvmARKcNkkbE8aJob3WHSxK2EfTS4aBU8lHenb1Ky6q30Keh57AKPlM8nfdgT1fFTDmcjXO675B0y7pwV3vA7zs5zp65cKcnt0BP4ab08vUcvx86yp/6wmBGc53Yb+NJKhUBuO+FGuaIzkX6za2oiG+QZknh/B4sixut66gkcvf0hIxgOhfznxDYTHmjD9HdP0qi4bogK9vFyTKL+ATbxT4+FUzEnSShHlqQlTqLUmLt3zFQIu5sGnwDJfLmNHE2K8wZc5JOMQO8MZUHgaO/GVLtQHaURcBYsmHKXq1HjZLvcNt9e/pe9dmTjm7Cj8O5X3kgjOwoFeQF13YDCHftqFF7E5cGnwXbxUEwYF98bi7fA81rxoHDXX/kdqIe1Sw4AMVi9aiyuQr6Lt9CkmFzubzKzeCQkocprYYwjgVW9grunho/Vrs0p3ADo8n04aQcbSucAoIhb+gA+NjKMpXGuwjMvDdlCScE2JN10MyENfd5KCpNbhixUx4F/wTHmQ7gIy0GSSIX6VPmlmw6Fw1vm8TgOTx2hx0rRK9hI1hb2Ud5F0Igfn1xvDMu4oP5qhA3MrxfPTvVLz4Vg1dRtpC8qI7nKIRR0XN4dz5dyoE7xaGNCkrcp8+Gtdtuo6uusL0pScYr+d7UqPgco6SP4NxbcKQXheBG6q/gFuTAstGm5K4y0pK+/SMTD/E4Sf9o9gg/x0jRQgeCSpw0eWj+NIiC7vvHsQXfAAmFxbgxxNOsHn0F8z/fB/W+6pBrs1L7LLsh51CfRyEegDLR/PNS514oq6Ruv/exaOtA6y9UBySxyzlGt3rNG7efYyIzee1Ba20atUzzHLK5P0/tuITuS1QfksDZD4kQp5THj3Q/IYr1N7zvbNeQ31qwzeUV5FRZBOutvemZh4NDiFPUDPvOkhqfCRz70t8/v1x+HpFlr5b/IcO4k3YMaUHo/REYUFxBImcKyDTJZ0wPXQFyn7UA810fdyTM5pKfiWhe9phfJkxGn5s2Qlzrx2hgUdf0HzvF/6cu4YdMlUgZuZUjrbpxk0rZ4KxuQ4Exxzgf4FveN+JcOj/tBccIwoxaaYHO187A/OMfCEsjOH5KGkIevQG3XI7cYudNGhMPIav7x+jpbdVkZXv446uUn5uMBPnnDaFyWl+sKvgBK+JmAT2s2+j5xMxyr5uju8l3LiubgHdXikDEa804eJcVWz6kc0R7Q1gVZHDkTfraMWiLfx25GQ+bOlK9qNLsf2sLuwdu5YzTH5zb+UD0jc1Bt2jY1ha7iKnBZvihu5gbl6lCiMNLOG8uC9410aTd6QXT9q3m0q2jWfZa7m87KY4R2ZV89SR1wG6hoN270L6ZHscvh+6hxdrXMBuVT18Vv7AZwQy8Ur9FK6dGQhzHGSg9qw3L511ldpmZOCd7V10VtENq/ZZ8J5lRiTn8YYf/3PFZa+twVUwk/sG/9DIKjH6MsePP+k3wCr5X9ym0wHDnc3o6b5KlhhmAN6p2hg/5HMZ4++y6Vx/XPzMEBe8UmGnn7okvEoWDjolopvfODCLaIeskFuwWXELD7ruo8WxquS0RxyNtd/S7tE9sEjyND+aMeToBkJUYtHJy/qn89vx7rTHfCNf6HEm0cQOWjBhBPunVONzJyloPPSElBQ9SNzyD+DqtThp1V8Ok2mDzUuFweumMe/860ziO3Xh5a7bGPJpBon+nMLj/NNxX2wq9T0uhm2ahpQ7NgnDfkqz3QpLkND9jhZTN+M905V899J6eLXgEDtF7uRB0zO86P1yerTBGo40S8Fq+fnsKaSFN51bcV/fcK531aZrYztRacEAXFzYDSE+e6BaThNSXrTxC5FbODGtkVIzzuIFXREIcYvF94uq0GrXbq4e8i0HaYKmu+eoR/I4B6k+hhnJCXAlrpz+pn3iJtUN7PUhnkvdj0OkgRk4n8mBQU6hxtkvcW3rO5w91xgXbryF5cK6MOHGCs7tDOZDUoqw+rYe/+p7DVPOvKYy1Uqe/Wse/5UIoJmFOXDW5TrYWCeBzWUJCP2QjvNsR1D4zrHQKBCKTrZHaOmOz3go0xKm+8xD5Z3zeeY/CThcO48/HytE2fBt9Fspnk+t/EKGhWUYv0kTRGQa4Gb5YlCJFIAf36Nhr6wEzn2DuGWsPmeVqXBCajF7Tx+Hx7OPooewDB/KUISqXwmoFf+eJBXV0Eo+jX371uBz20f4b6kW5K2cwLnZc8n7xkQ4LbCRTzoe5UMvJeCYYAVnJKpzzow1NFNlH9QmP8SUwDu09sQYWBYejVveBVNTYCS/spFBAanx4GRSiVtS0tnX/D5vrPGHglFa4DDQR+f/zuSS6FKoHFSkzSY9NHzBfpivNAj1qh4ku2ToXENaNrw2Buc/qabtO1qBDg/jNL8Iyvo5gt3tfODhsotcctGatM4Kwv4EG3baeRn3PTbERYUqUFokwDXRF0FxbQQtd/2IEtGy8POUOlyc9wM0Gwhgtxjfu9UGRhr70L1Ki/K7u/nVt4183m84+12RA3GTdVyiUkSZhSLU+fg0TggN57CkJbzzZsSQ3xfRw+mDIHpMEH6qxaLG1FgyrIgi/f1f+c11MRKvncS7TfxIv7qGF85UYIdyfVipOhpjJ8tDlZUNq65IpUHrWt584DWH1OaAttEBKnr7kRe3T4XdA/IgX7aQJnIsdCQ+g2dph+h0rjeIq3jS97MF6Or+ADDCBOa598L2tyvQ4qAzZqeMgZ+Z+piFZXzw1leadEuK+moWIl9ShlaLMLgSksEqDUXwa/k5fHBkOP5I7oNFOl44d9Q8iP4QD2YDqrB6/3iQDTqKpSnKgOXS+M8EOXzedIz6sJ40Smvxi2wfCepPhXcuOZy2tpIyrQz43kopRDsZEq1Jg3+LHVHhwRzyLE/lzd9lYHiGLKhbPiKVtpvsNiYY5EXrePqqF9TXpQxdjSLUZtDOa08owMtfsazc+B9v90SwWanBwQKZ4LLFDscHTqB21xrerywKjV/F4V73NLhUWwIniu+xdl4LrV85hm52H0Tbh3PZMSWZLzpa473PCNsnTcJx059hRbs2rJwejaNyk9BkmR/euDgANzZcg8BjsnC2QBKeBnThIm1Rjr8/l2M6wzkhpo3slonx8QOTYWDvAOS0xfPcD4aw7q4PPBUxwBrr/Zz4Xzrvv6/OtenMfZuPwNqjZnTO1AoazlmDi6g8NC4th/6bevjtXiU8lFjBSlMVyMWvBLe+fMc5JtNoT4YyOK11g7SzBmjUtBbC0x14TvQ3nCScg+22mvxf4SE+ue8Tw0ZTyHyhB7jcALqn+7JUij3vOzkASzRqyRMEObL3InvzMrzxczjIntMF01fubH9VkE5dW8wrMQX7FztzT0Ml1FYGcmfeKIwSN4CG0LuwflM6um88QJf8HPGHiz1/9e7nB6JTyNDRgUYkGPI5fXlYfDAKjV8mDTGrC2dO/4iHjxXgxD9rOedIEUce/I06hQqwodgcRlvU4OaU62Rw1pJOPVuM+0038tviXBrF5VDtl06L1zty3SpjWPk1mos0z5BdQy7M23qRQ+6uxpebJkDrYk/OlZ7AF6UtIHXmZDgScxCO3bHGjMxqWu35mk642OIdOz0ozFtO87aeRhujYgy6KQVK7cchoSuIn0Rdo2PxHVS0aA+2LdoOU8tWw8v9vZAgKwkhjpPgv8rz6GSWRb83Af4YaMUnplfgXPccgjkfsf+gP0+wfo0vhhtA7Z6NuFdsKusNX4Db5IZyVDGWvC7HY6hHLYsZArsJt/KLaEXYZx1KI3aupQ0iyE4KmuAdYEV7tyVT0LOFuN7zOJ+WAPZXHAFv78mDi6MHDyQmcLfYJoy0LWH/dwRFrZe4/2kYmMsK4OowGOq5yfBm+31ct/cAbcwvodi93tzSpsZF6vOxsUKc+iYHst1/pvDmaybxARs8Ih6JJy9MgoGHJ+iJ1m+MXj4KzH+swWVLGnhZkSBsiigm5+EP6MS9FBYIS6KjhaGQf0CTJjo84xrJt5gv/4EqruiCkP8GwjlHcJvKC551oQR0+g+jxkRZaOosxS7JWDYNyiEPO1OwvzzEebOfE4d3QoeqJdw/Yotx+dUU+eA5b4xYxnTvDxxYZw22StH4fNdzFHCdAks5EFKyZFFm7nI6Yu/Eq07OgUXKM8muRwN8Gu7gzeYOqqgfxbMuK5JSUQvpZY5AeZ9Ceu0UB3fDcrg1Vgm+pwfjdu8y2uq1e4jV76HvUku0hM94Ykk6mBa/gGgNJfz00RRGzPGg3tYgFhtil1kK2zlf5Si8i/sLuz5/wNHvXvA75W4+eNASKkPqwWLWARTRMaPI7QchbO5+2t24l+rrxtIykMZnAddg2gIjuBzVApfX78Axp5bQpO811KZSzSB5lCON41E324vlKh6zh7gYGPpqs0+4OtbfOcf7/FTxQVUXPvDoRINhJfRQeDaGURM62WjCyBPNlP8wkofJIs0MvszD0/rRcsl1HN0kQOvHXObpWv50/MQUuCurA/5FF0DGr4S2r6/GlPemLOL6mEVGCvKzuaLoWaYAp4O0QeJeHiwtLaaw+tHQ/GKAdlcIwp6yOtxV78MLqkZj95SNlKGgB5JZpZB7wxwu2yCXjGjnvl/n+JqWIUuKZXHnYU1eHdsCRTLjwfPfDJr8bQ+a3ZzFQpsHcey6WLrtrwpnzbbSfxumYuPhcUO1Hg73fQkCpray+qjVXF/Tgp0FS1jkxjMsc++l7SXbqf56IbfFKENOuCMV7jwO+bu+wEaWoDNPa1kDX0HU+H48teIFen8UgvOtY8DEXBlXKaXCjCuR7Db7G0fLlEHL/QH0lj6Fj0wyUXCtCZctGQPn82MYg9PpP+/VqFOmzSdblrLAtv1wZnMLrquJZi+1PzA8WQ4MznTiUZk9uPngBn7W8IE8zulz0L5uElcyx6zVhbBjpiL3mSmAlZgX28nX4oyYbNzgeAnzH3iCc6I1qk8qxdoR4jy35Qh+kTeD+IjfUDLsO2nduYCXUr3xWZ4Y+6r549t0C8yV/QyqDWvg51NxkLA/AUbaFZxTFQnt5Ubw8VgfKFaUQnzGdC6534RyZwdROVcXJt1/yXr/7SC1ifcJlK1Br6mGPixeircFCrE48iWM3PuBpE7//3//X1HVpQAE/dTQ7ZYfeXwVQM/dDWgwNCMFXFZQ2MAc7HsuBaN/S3JITxoZhKSDc789WroEc+u3P5hoWEq6/4XRgY996P9vOLy66clJ9Y4w6+cImCCgQS0VbaC/PhHCTM9gmdAqXuF9nApSleCZ/Gd63OxJrcm91O1xHcZX1vAv1wA4lxqP4loxYLvWFKLaZCEywwX6HhCI9sjQs/Kj9MUgjXfJF+KE/DcgPyAJt1XbcewNK9jmhBjzLgtGL5DEthJp0s98APmlQWQYOJ6bZ4micLALicUqwEdPT5Zvq4SsETI8ZU8YT83KQrtZ8Rz78RKdmCGFh+zsUPKTFsQf3IhOoV747G0+yb53xrtN1lDw14rnC/rSxcVy/H3BOz5YrgwvnZ3J/po7//09gaZ+PIZhnXO5wyaPUwtM4cy1oe+eGY3N8gKAkA5jr/6HEjYfKXDeJ5rz5Cm8+C0BLTCfyyVsaFNXGn7MNQbXqp8gcz6S21VX0d93vfBnyjTY2CrKqS+f4CTDnSS9NQ0KsibD798bWOeGFj+7KArXzVV5fsMwgFODtHK3NGfNXYHywVHY2isLC3uHYfdDYQi8Lg1egVfZyNIYnrqYcX5fEs4fO59/zc7Bwf+MAGxtUE7ckTK6VpPyynIW9h0LYiVycC3Xla4uOABnBGbDcQF1OGchRQL//nGe5hmsQ0X6d+MUjWh1hervh3hLdxcbeE2F63fFQK2wFryK5/HDNkXYPho5tv8PqXcno5rNX0xa3QInLK+zq4U+rJ2YgT7Wj2FkmwpVHp1KHi5iWJ7fTUuld9Io3Tq+nFuAnpYmsO2cEvTu38rC8h14db0Et/73DRdc0OSoGCP8UFHFy3pDycpsMiw4UYRr946HFbnDqCFOHZ/EPsQxRSn4fcsTDh1ewLvSu+CYlwWE+tixkngj3D9hCiJZiZhTuYASs3zI794/LF5+hGQu70eKYVA/5Msznv1kOPuevCaeJ6FhPdz9J5ANNd7zFAXgVOHbUOqrAj2D8TjeKgS3TfjBqscbIbbXFWadPM5jbArZvjmNHWatxiOTxGF1x0RQnriX7xTdJNFWMXAUfElKzsdgxJoZEP9WF6OmEY+VHgnZ/aupyvY03PllDucPH6LprTIgMEGYT3mFgIPCcnAIkGTX6RPhwL0EPPbrHgj5JeBUbzfuvCrB+oaK3PIilSLuBVHrqhlouUYYaku8ceTHsfzcwBauKy/GdbGPqTnQA8MmJVCx13t41JsEpz4ogvvgazydJIYKag50O8kEru0uRoEJdli5dANohapi4ahwxmvK4Dk0xUa0mGL+FX8sXyEM1ila4GQ3jGNsm+Hs+bH06Oo9WPqXQfqWIjYaegGNPA563nn4PSQVRMAYyxPn84PXcQivq+nmSkEIF1sKty4F8SvvDLCoKuYHG03Z6/tX/rIljoROZDP1j0fH0ZbQUnARsjcZUt/fAFhSU4a6PRE0b99PmhUlzUm7c/E0z8Vn38dA08BlbAlDiFfaACdLfrP6hwfcEzkN7385gs5GzjTu9zJY2GAKhuv2YqOQPP9YuJA1jLfQr8xpkDdrM+5zOM51V/IgNfY+HZGRg4QLW9hP7gLunm/BkU/cacPv4zCmtZsUvmVB0wwimauf8O8LEXiw8AM+V1/F0/caQ8jXvfyn/zjuj3Hi/wLNKLv5J7i8ektlW9XBuvcI/ercO5Q9wXR1ribNyWjjpsYp+NhsPy5ZLgjbnS8N8fpk8PmtSWJDfVYzNgJmh+ay/ZwssFJaxFaLnmK192i4aGyCnUnmYHZxHm/2zYan4b/4ddcjaPCcjXGL2vCA3W7Ml26kJ7v/YdgPQ5BTrUKTNWJ49r0CWfb+BOfXXaTju4eKVmrQqWgRtpHyhtHuWuAaYwP61zbgeG8VWin/mDvyvWDZVTloK5Mmv5/32V5RjloMBWFmRRZPramiw7azUEwtl9YkWpF5fh8dEFTDM9u9eKfYA97bPgEGzhVQZpgnmKtYUEtTCt/33Eg1uz9DocjqIW9Zi16vEmDH+alQ0FAIBtYn+cetQHCSnMBKx8LpvrQs/VXuhXTF5zwrcAT4TrGCFcEV/MijC/y7d+PjukYqfvgXnhqMRafpr7jpbyqVvw2FuhdaoK3MmD5ZH4IDNlKEuAaKJD7kUvsUwIch/PlMNL/5upcufjcFCcdWahxtg4sODeK5ozG4ft93KCqspIY1tvifniQWT1uCwikm0FOyB20NGiiosJO67nnBrr22+PFKFd1SOcnm7f+AG+QJXGXgUsMY+BV/DOIF38GoZech/FgVGh6PgKYTo+m5wWlY5foAQkdMAXhymcNLGsgp6jZUVcqQb7wNbk6bBsNOmpG0hQ4XHL4KpfY6kOYZC3ceH4HMr20wYOdOcVlR5Fu9lce6dLB56jIs6nuDfo8NYIbNecwd0MGchyPw8a8oUD5ohezuBVbq3zD/nSE67RuJvaqakOaiS0/++eGLxVe5PsQVmjRjceajQg66IYbrLBDPRCJvc1CH5hNL6KrDMs4Nv0wnxH/RGuELFPx4O26LXUNetnJg3hPNUgmWUOzVinHniuHLjVbw7z0GO7X/8ZLwx+iWZkUdfqb4rSqaTbo0IeLlOJ5pGsFX229x6wM1Ft1gQCKZQfzj+wJYVbMAXyW1k/ZRI9isp0+Nbq9AzWYfm236ic4ng9jPVYgSS+pAc40F7Yx0gbRBA9imuw2zb0mRukoK2kicxZCOZHYz2cy3uhLY7Zkw+FR0glmOATyQEQF9Pzc4uTeTV80ow8Al+3ndLGeOLHtFdgMzINryH/VJ6g/Vdx/dSb6M7dY9IOh+DvUUnpL5vipI0e+GwYFgfGbagwu9lOHiFFccJaFL8MqX/3rb861bCbww/xHX9ZRye0w41+QE8DCXybB31RVc9Tqd33YmYMUcATxsZo4Ne2bA+byjeGJ/Nt84rMfvh3x/WbsxSzRZ4yjHFdzdP8T415wpb+N0VNAIx0/ZllA65OFLdfRBuz0bZ770RruiTXwp/Aq/3F8GZpnf+BS/4GOPJkKF+3Oof2ICzjXf6NGNcs7QWIDa59Ix382Zr3dfAHnbMAqumQ6u66bxcyETmFRwn184PkS7b/U88VgKemSL0MFxPuy4zgCrGn8xX6hmtTm6cGXJXA5eagylQpqQNLqOVn++iiVa2yE6rQMkhGLwiuBqkv6hD31D7/J2nxYbyn6jY2aBcEoqFDckPIWwd/U4YcNqaIw7Df/uDgf3ogSQa7EeYrVWGNf/gmbhUey6Gwsz9h8lQ4k2XjIEDXF/9aCMTqPApbv8tFAKvtSFwbwrriCs7gvecBC3NY3g7pZW6lVWg6/SdSjcvp9zagJh37p/qG0tj8PbY0l++Fhc/nM6P3RwQKetxvBarZ4OVW1np5up1JcSSmIvPtCA2TQIKjvGu3ak445ZBdBhMh52p5tBitQH+Pamgk1EG0EjNhrOuwhwx+oMODReifPap2Ns9FRISNDCW1JnYGPmHjQ6HMw3k4MYXBNxfEUyrPk0Cr6+SsA39qZQvfQBTQkYAM1zaiSRU815hmJc+XkxOiv4kabVenCoE6LqlGEgum4vT31VyKa7nvGCjskkPK+Ovx2Qw2vB+WA6E0kzr4fyZJRA3/wfTWrVBM9fthghMpIr/czx2cU4NJAL4eZN9dyml4gF40xAXS8P8qRlwdrXA4Zt+Qlq8zu50uYufKq7BV0mBRyV6oP+ahOhK2kOR81upqTlwhBr14Szv9RSe/osoGm/cautCVg4V6GaoAnspTq4LXidulruw9bSHahQN0hPny+l3bbnSVXiKAgk5ZHGGh3ovmiFoquv8pWM4/Cx6ReMcH1LJ2rciDOdsDEoCMJ/B/Gb22NB1s2NO1Y0Q+GhI7RlvSHrv1IlpeInoDxdka9ZHsaNlztJo1ER9lw6DDlOiXzpZThpiBrQfavt8OPkdQ7zu0fl/h0w3VwaDk0XhT/J0rxwqxfll1hBtH05LUsUGNpfB/bu3YXl4rVgHXEeXe4qgqOiMuaEf4ABvAe9k3fR+hpt8n9gTnNLkuFH/gwaXnwFVNYIQcf3/3DamibUu2bEH68I85lP01FEdz1echNClQZDOuzoyoczjWFoJ/QhHX5EyRhHMjjmfQ3NqRLnaweHQVfkA9zyNwaaG0fADxVh/nDpNe5KXoU6sQ3c2ZfB09sDKaf4M/kkSXKD3HaaOkoQGqbYg4RdGf7ovYDNR/5C5IabZPbpKw7WR9Pi/V+p74kSj7toAeHfP6LsgCCZ61kC1Dbwq8QPXHd/LU1TFYMdH3Mg7vQ9nHNQGhwSpMit9SqOyrUmtS8dmFztxcUXKzh7bhNc3Jw8dLdc+B1iAIIDq0HoUQqVXvjAr2/MIjWl/8hbZgKUDEbxaL98vNi5iJf5MfTceYMZLS/5cMAJNp9UBkHJ2hwSeo7NRh/F4ILt/LP6EL02GgMRiYtwwdg0MpnjDasK7lPTcWnUW3Qak/O3gWhEBzqtMKUzWmKg25aPf0Pb+FHqUb7304jmTsqgTJ+7aDjSmtGsmqecKMUtJQIg806eXQwbuN9lOPxraacViRtg7bw4WL+rhBxmW/P8hSawSkcNkq9nUOVoFVp3YCpNP/8NzqAAxLZ5w6g+QbobkMm3Kk3QVmMczKu/SQ4bE1niwyPqCPjAgTIulOF6EzGwG1UfG5GB71octNWGyPlulClZRFqD20ExX3DoLXeCoGMCv7mnDV3XZPiGwnhqjdODaxX/SGPlOj7cOxk+C7+jfXX6LEFr6M7lFZBuNZ/UfZ6hu4AknGEhni0zGeavLoJhMSvAYls2pLx6SYHHNWhEgydUebRx7xJJ+LX5BtjqBWBikS9XDTlO0Lo3MG91ALrsq6WE3Dyeq/mahPZrQuJXwvqiABQL2kdXqirRbd01jpQ8R6bmjXgsdxiO+LCQtDdogOlqOfht+4ZTdWtpovNSFN2fwu/TlXhYcCd6R0TC5NogerFTCvzSsrHpVwUILHGiAx2zaUCwElLVg+lIzwsMrX1Bf8ZP5OxxejDn7jW4qbaMT0ctp3nJDQDCXTRT6Sf4hWtw1VNbPO7mznpy46Be1Rc26Dah2NB6gdfH2TH0E6zJsySFeUOhtuYfj0say5sSx8AkvRPwceJiiijXAsMlV+jsiRjus5kDzUc84eU5WThcEEk5VeYw0ckEM9ZEUtA1R/qSLsWlj0ex3ZId1KBFNFO/ldrLlXGRkAasaWiBh6XjcJr4FHZwSAGxpLP0OWQ+LoyrwBZfa1q3ex7o6E8B7WG7sFdUD5cMvwCdTSmwULsDf709wqqhUawRcQi3NH3iFeOtYFxhL3Z5GoJelhWH1z/kQu8u1h7tAecKQrDy/TM4WpDNLo9MIP3JVPq68xlNaRNgx9RBfGh1lteI9JPpuBLactAGPQ+EoEGh5pArd4JE/1SKORWHc08K84ziXxjw4AaOinHABRVxONBaCMt3iYPonqsUH/oRbCauBQcrT/jRsAv3eIfRjsDF4Kt7CzZ4HkCl4+Kgb3IcvhTd4uots/mQ3lLaO3TGFHCFrWemc2avHXuc3AI3s6wgtfYSLb5wjZ74KMLcM22UqVPKD7OSyXlLLIq1PMK1lmFUekwI+rvPY7hBA94Y2IlmyzTQ+HQkx/4W4pW5a+HlYAKdzhkJZz5LQrRSCZfv3Q8rn/RjYX4ztbIFq1cU0Msdv/ntfHUwHHkQ35vrwjRhUfyXVQ9aIcHkMOY8x+6uAukDR9l40XhW9bwJRlJ9dGqrIuSu6eOZ34XxSYUM2URJ4czL3qBc6Qlvcgm7prlD6NL7WJStD3V9rSRl5EJHXc2h8exbHHPDFRRTlDBZZQ20f8qmLfPEsUVCBM4PdvDaYYdRu9qYxm55RmbFszn1ewmsfNQEOXedsL0mj90PjofKbTe56Gc25v67Tb+erAKFx+mgdlWB7+j8pO8O5+DJz1MMzUrg3qZKiWGT+VWwCxd1SfE/xb8ksvszbZT9TpOsbTDM/jwEBU6BZzFzude4kFX+LWazc2osPHoMhiS4wHrB9+xxPYgnmzfDSSUrsL0ym9YmpaCJyn28KnoMfc+Zodjds6wT/geXpC0hl7U95DzNBLI+/0HFgwY05lsU/rvJlPnEFZLV9tG418dh67JuDi/vIpXXU2Bb4yO8+NgF5b60oFnndgxt6eTwFi/6lujJc4uv0YaHfWRaLA4mATNoptlb8Jjmw24dziCxaSJWPUjF05FFWBAwnAKNdGGhkT4YKxyB/T4aUOoYCmMbBSk5dyaNnOQKIkWjqXLUA0xYv4ZTZylA+I+z/CriC5tqn8N/v7fh05OhNJAThNE+zSCx9wltkdUjn/mmoBS2AIb574PxV06B+4xGbHi6gWZvzAVhV1lWuCfBGV064Ok7CTZ/e42yZtdwXeUzCCqdQPPPOvCZoOUUHWeK8/R0oTU/mmdpyEH+63asavfhtWahOEEgGRXrZqBXhRpkmEWhWO0CMvD6zZdNjOBsYBKsjrhMS1v24VyHIK4uF4K4a7uwLEoHS2skYcqIGVB4C6B79B7svlZCunM+Q967Jmj10uJdB+/jXfMwqrO5j+ItkfTOVQCsWupQbrkVJ6yvYo3/Qmmb4R7+J1bPV0+Z8Nej6kT6+iCVYAzj8oPRIU4IihzSwTE3GGuGabCa4CmWtDeCGNtV4HPHgeMdZWD3cSuef3oiSsjokWBWF5bJLQMh/dV08lwErhkIxJDZPUOfa0CmliAr5SzGrIfSmKB1G6YXNuKOH3/Y/vofcp22GD7NbqLTc8ZA/NfzvNn1Ge1ccRQVOs+wkcB/ND45Bu8b2LLZhjNQ4NCDGfON4FehMDuNycO62cWgHyNEAqb1FLZ7Fw6qTMPafVchTr+Pt7dqgPyDdG50caLmZVVUudEYNFYa0ZQLebTxyGvUnL0X6mt2gKX9VBC2P4O7Ewdpy8Jy/hK1mJSXVuP4M+50eBrijYmNXNs6iWcxwYMHSdynpAEp9ofpZ3sVZ/wx55MfV3LpaztO1RKhtOvBmP9QF+If2UN9wxraWxJIs4byYaD6K346psY/E9N54brtUJzgDM8DpeD0C19abOTLys/dcf0hT2iaux59xp7k/YHj8fjObpz0dzFcNNGH4VHhfCxmNi5ZXA95XUdgasBTDJx/keq883n0Nk1+Yj0W/XWs4IWUN9w9PxHlR/4Cne5vNEziCN/+noYnsBvXv72FSeEpSFYW8LJoDAcc3UwzxVVY88F4/N2xiNXUn+KveC9yVx/L6mdC+dMlCSgq8+LTD0ZxVrY/r6bZ9GjtX9D/LgljrgCxshDbJHbwFKUx0LH3Nok774OJx97h9eDF+DT+FJR0LgGPOEtMPHiAD3uFDTG5IOz/iTRrVhQOfxLyP+LOux+o/3/jr2FlbzJCSUZGyoisNBUNIqX9MZKGKBWpKKGoyGwqiTQ1lEQDiRaFUqgoK0XKaOjX71Z878E578f1vq7n859z6MyP4fhzXgTujV/P9ocV4NSVUJyuuZ1/qo+CC4LhoHzJi29a5PO8o3pMxT1wa5QeeQhowHPFX6glqcmrhKSgZNIGUL/sD7LQSzdmD9C7mw44YkkJv09Soci9H2jbtn4YedoadoEvHPu4hndG2SO/yOWUiQqwTUMQ8hOn84nrKtCg7wnm04zgUnM+HNsgy2fzf+KdTYyl9lEYNmQATklTWH/0UZhZMY8KTwiDlfdkTFyyEBdbveVNxVIc82k97DliQLpfDPFrTyD1fr4INTsmwJ2tWqyqKUudGyP5yapSqnpuBhsqHsH2hgPkEFsD3osiQbNsIlTzTbj8UxTjG8ppWXAYrB5XRtlbZOjI771gfaqX/uzSQc8KIzgidRYNFhmwzgErOJTpxz99kftMXPFF0gXOjXbhkAJNsjPUAlWdHriwUJrmzijC/Q8e0plyLdoxqx7tPGMpYeVS6J1sgp/1TeCuSRDEK1fDt75F+EPgITt7XGKlNbLYp2WNgr+04Yu8IMzcqACLCkp52dyJtDx+CTQ3e/CC2afZ5cYA7WUHanbZwnYTo3haoBYEWYyk0PJC9g+Tx3NuzXQ6cg4ezHfjD8vH4d478zgxTAxu1ZnDoeFziSK9qNlOioVFLWlvnh43TPOgtXlXaPjsNnJIVYQ17fqgeeAVnEy+z4eE94G4/TfK0k3GEwVNpN8ghyG1o/DHyXA20RsJGS49dGvTGJqUPw71l1+kzeoBGBe2CbLDj2NtoDkPF/oA/deMYY/RFowY30sDDcPQ3CiKvv515KzPIdxQ6ciVR25jX1AIVzaPgUY5A7iXksVOPwPpvxglGpnuSIuntcCL32dp8glVnH2iju8tsoOZcn/gj5MqTG45Bn8it8DTE4ropn8R7p43Yq0EF7474ya7qujBt4PDOMOnGaf7P6HX9yRAbFkmNeiHwueRTyFj1Fe6pSFMPg5jYMS8v+x805beLQ9l802hZNEVgU8FfqDAcGNe7CLPC0++x4kf1GDY8+34TaSML7gm4/KL0dBT8wAzbDeyxrUXzJrR6PHrDeVMJsjyXA9lLR/IMrSCzms+hi2Lwsnj9wfwFHvO4Vc+8pCBJFhVisIBleGsN/jPS8RBwKOzgxq23GIx8yDaKbAKHMPbMNNgNhzU0ISRciu5JKAQktb6gETyfhS7LYQK2SHss/UZVfpZ0vAboRC3Rgzi6DB+yjHl2Ho5jjoXz/c8xEjnWQBJ3BuEqmub8IzObYqy0oYRwmFwsMoGx/wyg6nP9qL392QedXcQQha44iaHL3yVwuh0MUGl21ZOEqkH884GMKicBVLvlXHRsOm44NoI3ImrcWHuPBS1U4NPLdfJKF+B9q35j1abp1DK1CYc+6cTPg8Tg7DQ45x+uIEa3g2HD4uUaOPeDeRo7onX5T+goaoODZ/UQIfynHCPVCVWdcSy1hsbOLLbjbxvjaa7k5dxhm8plV7MA3VfZ7RR/g4xo9UhKkiP9ryQgJtKN8Fl0nEYIfIKih9Iw8qCUdRfPggzZwnBotG+mN/XDWHStnDWXogObI/n/+gkSw6VwYNdSvjpXiTvWmtJVy6nkGXsKRb4Kgpjbt4kqvTiY/em0MfmGpgzcQC8j5RAUUcBnC0VR/GFErhLRxYMAxrRxqKMRq6NgNG7N+B8k1QeWPAWO5624pIIK5p8355osyKYzhhPz3448qlLauT/8iIKOezhkTu+sEKXP1iczqRVCnq49ako2HnVY3viJK6PeA/HQpfjj2HnKWf4dzAquULmyl9hNT2C+lMyMNRuhs83GvGyVwZg6qqAMnfV8YRdBTutyga5tNvQ7fGQZbYNB/HhJRCysAVO/Ls3DorJGGutgN8WVuGnzRNoWtcU+BOyCs87qIPAByOK704Gv95FMNkml3xcL5NQ+Ei+UXeCGou2gJ6tMM5KHgc2satxcNQUdr7uz5FSe2hslBIs/pGHl+tWQfmjo5C9s4GrEeHH31AOEr0JE7/vpvvyU2md1hWunh/JGre04KFuKDlq7sCeCcpgFjmJ77/SJpfaFCCZXBZafB0sxb6RyaR7TIdH8PV8QGEHcWjJUMPqNUJwqiCbYfAL79p7ESWm/uOR+37ouLwLm8TjKHe0Nkx7YAVJT7Th/ZNA2jYwEq4ZfSTdPQnQgG5sus4dznz5S3DCChb1fgHnk9ewKH4ClFirsdSzIpLKPU0NJhXUPuo2P4yMofobctAakImLtL/A+K3SmC9xGXrcEqkiwx8lX/+iT5alMC33AqTniMC1jBqOp9UYufkF8jNPnnK3k9/caEPVvlbWzNCju/Yb4HeoAbQPb4FteqIU2PoZLJZ28luRUmj9dpdm2Qzw6Y3OFKA1QEtFNUA95Dys8zzPZ45X0sUd/nQ32o0kZ/yGB+vbeLTHaayxqOIzrAMqoX10+fsmPjVMF/wy9tHFMUt5hWAzWP1y5cDuf64ytRvHtpnB9rKj2HvcjDtq95P8mkTed6McdzrXoalHMbYL7Ob5w2T5904CNXE9UGpTY89X6SA8XJ1+jjDkpTVGGLXTCoJNbkP2XQPe81wF4mxPsMq72zzDTZyVe5uh8/RiNs3LJIO/kbzhpAjMFdiIK/eaw1jxeJ4vp8OWPeG8d9sgv99zBRSrvXmc9G/Iv72MtVUE0WiBHWR+MQWmF7jXV42tfynBn9VPeU7rFvz8XwEkmrXhipJYjkgShiMJE+hA53F01XmLZ5xNeEz9KGaXhbA5OpcC4t/CJomptLfXEubvH0EvhG7S84htFH1tJzf33sXg2i84YOyGR7b/4fSBLbjeTgjO7DzGblPG0ChRfaq18MMj0W0wa0I5D2wvh5lpoTw91Y7qBFXhYtkIuPHiGqsYi9OwVkXwepsE5QVVvD6lBH617mUzeWcoNbIBPmrKX07kg30NsWi7JR8w+AkvHozEdY98cbdYC5V1buIlC2xBQncDLrVtoVr2peKAWnRxrsddHSa4c7MvZibOhNtlHzgxQQl2ak9BSU0VDL61FYO8rfjlPHMyNfmLGl6L8G9cJOzV1QApK3HYetCBQn6MosXy13lJSxzM3u9L0c4dlCnmT7qK87Dk6E8UTpGCwL+3Ud3wGye+MUVJ8ybaOEuBjr+MxRWdrvzYT5cD1xhQiYECiLa1wkflx7DjWhKfHS0N0VPE6X3/cpoW7M1DRbno3z0PX70QgCVuF+lk8wcc47MKD9wJgITfVlx5/xPmHWpj8eh3fGn9V7T4MgLUN+Xh4tqffK7dilsrG3jKg2xYUunCzkLH2cCilJw1Y3FJqzoMA3dO6tbjzGlSHBCzn+uCvLnk7XgyXviWGm1CweaNFP+8PhpSUibh9Slh2FqnhF9/JkCokjTbvBYAjkti7ar3cGNEEmSk6kOplTAtE/4AbwJtoCV9I2WlbaDWU7Mx/eIsWvhkKxcoj8Kcq1LQfHQ+pVz7RTc3qkNmXC5dnjyRRFUlQGuKDt/d5YP3ayNZJVYFRjx8C+mtUpBbHE7SvwvYM7cTpnrn4vOBTOoXKaKqDD9UklUA17thWHTlEcfMXoAfjjjRh1d5MDhtHyqMdwb71tl8stIJxvfrwx/p9ZT5/jBFnDHE9OQOvOGTQ8N3JpFiQhfNmRUBFZKN8HutLrSeN6WFMVPp0gVZHO7wlSoeLGfb9yPh9J2NLL5aFyry/XC241hQiDqE41pq8MpoE1ZRLYebk6aCT85TalJthe7cdBzRKo/64mawnLsow2IyZf8EMglbBa3dObT2dz6vbTmPlwvOcWzSZ1YbMARl1228/8t3qPJup5D0S1w35SGpLl/DTdfj+M5HpG35yBl3zOHjRzcYnSrJix/JoJC4HDvaOvDIL7Jkb6FNqW2alBq7EnqmDINT8gH4Je4h3qq352rdo1A1aSF9nnUGZv9NwblCMiTz/iOmGaqAyPjxUPRrAXJpFeVWe7HY3jgy0lrMKnwBcyv16Xr6vx4vHwGBOufwZ8h2XrdlDzz49RRheghFnj5AMbJq5LxJl0prVWnhOn3wT5CDVwmSLLLpDl14toSERgSgsGMtfpkVw23Rt6mOglHek8By/HAsmrUPZga+YTP/Yipf3oqrreS41oXpZJwhO2hYsET4RPB8psMjFgdT8OwbrHttAf4Uy8Tbj1I44dE6dPR7QR17jlFGpyWICKSyyAhlqJhzm5IOjSGd9bsxZddl1oor4VH3pVFa+im7y40HU+1PYHjrNj0+qYDZCbthYoUO3ToryVr+oqhz9hj5GoaA3ikpGLZSm17ZbSUDu3YSa7amuqjpoIZx7Bi/An8Y6sOTkXIUMVYHJtxLxgdPC3DzoAsF2R3FVzXJ2H8ljSOMw9j7hzCMX/YQYzMZbP5uAJPrp6B8yVRyHL4Pe+xS+a+XCfRl3OdrKWJs4WWDx5WHgdIbbdhktRF6hYO4RTIH59RIwB6bKnTeMp6rn3/jYMXH7OEqAu2LvvDimRlkMWaILd9nwbhPa3lDGHFWSgENVP1HL5yF+PUdC3iRHQbyW1bzLi1TtP4SB3o9DRy1dQbOOZDGS5e2EAgsZftV4+DjmQ+4R3UF9szfDj8KlsCvlkjaeOEe7b67AjrNmBrqd/LHMoLEri4+o3wM3cOL4KFvLKgZlcAcXXP4vVieuo0MQLnsAd7pFoLvA4k8ussIV3i1clG0Bi7088Ku8jI+1mxHMXtu8qnZORAePwb8lW7S5nVXWNRFjCs2PKSET1KQM6hKu4fH8ofKxxjm/R9MfKoHjSk13PBQlYR2JlPdckEoWHwSGr4Poz1ua2CuTAWKquiDup0ubE0w561N61HnX8c+SZmD9RljUI012DFLFKoXPiLJzV4kVoOQ5fuHkwvf0LnyMbCjMRv3vfAC+yeFsLfuCZ7sL4TfCnUs+MkCkr6aYuL+ClSYuoSHRnrS5b5k7muZAsczTDEjIgmHPToDRputQLhThkNn5lGzgzDNLZ9Gwp2vwanGF0Z+2oz2WifJfQFh6kFD0PYejr1nH/G80Pn483ASDvgsROGHn/ixnCQWDR8G79V78OAKAum7r7ix1gCiqQWpJgyf2Pehfl8V7tgiz1qDB7Hq6wm4MFwK1JrOY8OSMSD8jwe/pL5i95lqsKX7LTsq2oG7vwCNPHYZv2iJwtQ/2+Gg8w5I6JCHRVYVuO+8BqXciAXn5Zb05nEmvnyvA9OWTQDnEe/QRVKYckMHWF3ZC6f4PeQCXMwLe/p55tUGNuza9C+fuiB0SpA3pUXS6Y2ZeNmqnXW7IylmogzPmfqa1IOv8buQLSxpogVXr7ixaFk/NJ7djPsS48CwPRMyLr3C6OXTaV62Gm5qziQba4KWC2cwdpsB9h4cy2mT1kFAsgP9eRWNXlsngVviK7gqLQzvjTXBOXEHHR03BfLEJaivYBNdP5BFe6V76HXUcugt76UzV1dQ3VIl+N68jjSvX6AqvSnsIVHJt+f28Y453WiBi3hRTxzJBJbhfQVpsI0QppDA0yzxNAYFVxrw55aJpBJhTEtqMsBr/zx69/AHPb0A0F1xg64f9SF13UWUpnyIR+huhegUCc4eFkZ+8g7smBBLI58JwzK50/A5aiOZBM4jnbO1oFKhRorjqjF4fwD8HPvPS8c0sT3qg9iVaHyxKZKHT1+EmkFXaFbwbdQZpk13P3yGueqn+fNgFjl5Dgf/hT7w8cIbiFucDzsUlVn3/Tt+f1mYtuw6i7LFDtQYZs7lG8VhamMp/MrezCtEGEfekuDg3YzFq7M5edcz+hHkTrLimzD4vDhUdYVBkY0svBYdRpdHf0HTsamg++/Mmp8i+TjV0FGD3bw0Shx+/1Vjv7eh/Mr2Li74dZq+GlWQvaM2ucoMcvilZninBCQopg9WOV00rl4dv4UFkfpqJ/bZrEXylQEkFG2LrkcX4rIZi8nx70RQ8tXGz6E7+POmzaR+/CnvuSfNLzM84YxeO9rf8OFTamX420wU3s9LYi4aD61GhbTfLI9uq6+hud9WsNnRNBxrsxRwZCAJrbMCdeMQzHmP5Kq3Ch6cW0dBaz6jW+EuFA2v42/KOtAlW8HfEkeA1ONqUh4SQX/jPJ5zcibvHXDmiqebMVDTnoW+N/K3aaXYJy4MIb7fOPLrM5LztOKWtWJQ73EULrVtB/3IQsqMz2EzuRT8oCcBTh9ycEr1NLxXto4O/T1GhxP28spdw+FM8FnQzrkHOVd3wpDbRHglM5fnJoiy9sqd8OyCBPpM20cJuodoX9pF8A57RC68CZZaIhx54w4+taNpRcQNaPM9R9prB/BC/yja82cfXN4XShH7bXl+lBBoyXrwPpGLVJizCiTj6ymt5xKM3/6c6yufgeKCu/DHIot25puDin8g1Cy8zGZHDGEgXZ8LK43gwEoBVt33BS1OPMcD65X4Usw4SHwhwmavLpLahlp2t9dBo/FxrOyvBQaJ9py+Sha/W+aibqwxKGV78brEF/TDRodqu/IpzeQNfhZxY+Hkr/BYw5DhSQ+EDDMARWVX8LjwGEpPCZB9+lk0U8gA7WlKvPzHcPCalQWS/p04ep8y/PxQDV8zpvDj2UE8MGsTlNUqkMz9fpyVW4R7S4RQX8oBl/43Ea48Gs8HFkmA1bw3uOllKU2RPEV+xwGmz9gNX5xmc3hBC35VHQHLDwSSoOoV0E5djiv32EODdAs9ks2l7pxW1PuvmOtT41nxoRREWjnys20jeOyuQNiSE0Alz7bxz6JBMtCZCEJ6c/hz/QEYfVIGhH98I53UvSjcWQyGiy7xzjkbSa7MGdRjVlDbwT3ke0GSrUYAbBgxwLuv+9LQrfNcVqkCfbGH6U7bEZj4JZ7E+9aAXFEJHO4yhg3jjMF++nYof7GC1Q844ppDvnzoZAmFTXnLaUG/2EQpnNXqhSHprw/OlrfBO07GuC9ZgCu8pGDVwcN4fUYEJK37Bbq7RWjyOksY6XOaPDSLISLjDefNd+f9i+ezV+t3WtFpjqe/KaPir4P85wmA+OYgdMvIhJx7qXx+2nMcXBNCH+s9KffjV3DuOMWZ1cYUlKgFuqKa5H2jnuLmXkQ1mUqsj3Nj7QclUFL2DE/a/SXLZf/B70ArWFhwjjaOy+MiOWcSkhvH83JP4ymfuXhwRix/SdfEmn9nFb9jDJz9mcpjLjbRQ6FjcLZoHK19haAwqgyDV93C00b/3tMvhtxjBGBayBMqWRqBy7WbMG/FTf7YsBi2JWiQ52M7GnP7Ari2qEJRnjgslP6CJ0P3okmjDEvOCCVz5fWQKvQWvJKRphTGsMhWTbifLQCjcnIBlpwngZn6KDLkBNmPfFh4VRckr9eFs4PeWLg+GJacZDBYuhWKHppQ8NtgjhLJJ0kVfdLRLsMj6iJ89/BYeHj5DxmOBDi3qJLkPT9TZtFKHhtSDe9N7/OD2ctxbXAOBXxKpk+5GyFhO8BzDQWacmASpz9Ox0/lrrBQqZ98l6+GnLpaHFlvDbJtv1DDajxMiJoLa2aa46W2INao18a2im7wE1iFKQqbadKE+ai6X4JaT0+ABhMjsr0hS9UlapwKN3C4lx0ZXt8Ntne7qd3tMWjf7uegHBloXxeJwT26nHB+B4ltNcTLt+rohpsP7I/dg1aav2mnUQ1n3RkF5Qe20ZT73zG4dxU29nWg6NJqdsoX5yf9PWw9SwfH2H5FfRM92JwYBZWZZ8j4egJOkOnH4oyzXPM0Fh0l1SBu40aU2XKYGmImgcDFU7AyaxXfCKnjbcvj2FLLCW4X1+PItDNcOTWQ7TSX4ogES1jh8oijLSPx6Yz/6K+NDIzrrSQXhQpWO3eLaq30YfOM5eRmoQR/DytyiqEjpe0UBt+sfRhW2Q2bT16AROtlGJOUgJd+eHOrgwFk3XHBsyUhmPmgiiSikim91IGLX86hb+v+o+o9mtgpcgx62zXBb1cknZE9zDyrGhwrpWBqayuO3ryObEPDaO+RcyTRFgIpgRPggMMzXvNoGvbPX8Yy7ybTZqVD/5z+BQWf7oTa6m4eIRNHt0okQbViNrvU9rKMshvLz/pEtU3xQDtcoGz2U75u4k5+BUch2twS5D8UwJjrG7nsoD9+tV9NKyZG0GjpDsrW/w5P/wGnyotxNHKpNLTOekOtRaY0J9KSTt10xhlbZxIsvQNBrZmwePZFGmXzBNce0YDCxUbg/jYOdYW8+JHyZI5VKGbbhe246JAi3WvdA8Zuc1H5qxEEFIajXmkTnmw14pz5u2hAMpyq7u2A56qJdKl1MtfujqGur2JwwPs4bKjShajZZ7lN4xAobS+HyrfHeP/eCVT3VJ191oaSYilCxpNcXHjAFxcp53Ci9wR6d0QOf0b74GrrG9AUZEdd7S0UfpVhf0IQeXRuoRazdBhZKg27pu3lhEwH2g2iaKPVyFXj9ChHzQR0DD3Q1zkUhuXNxNSrY3jgZg05+e6ErbvdYE6uNDrst6WCBkHQb0zDcef0eImxN9c/PoUnDx3lF/5iLNAoCIfoPO9Mngi3/xC0tfygu/YdfOJbIPWkzMLrE4hWWz3hP39E4cj3bpDPs2CxxTZg/KWVyuA1q547ia2exViy8iENZIjwNBCGll/OIBP4H8z+Pho0ox7ww1/iYCHyDNQua8Fdvfvgfmstr2jYwj3zdnGU9yQOUh0HdXOM2FDMgJ8uksaOySso6Nh2vqXvSFsMo0Hl7n/wVq0adgoIwsIiNZpeuBCLombScqf9ZBw/m+3mMjdXv8Zp7m+ho3cKzWhSh82pT7Bgw0Ja/beTdjmfJqEZr/lMdhqG/zQFyY635OmUws8yjMDpdh0U/zmAwna1OGjtTffUTvC+L3U4FsVgl9oCnlfQj+2JivCrxB2ltCNopIoYfurohWV3rHlJziw+nm9C59XsMT34GxY2y8DXagt2/PqTNBZsxpAjgyzRZA/c0omtb2+h1+EsntN9C1xFEO7bi/Ki/mVU0tsMmePVKdu/gXdkLKP76zpISFIFa89Pwfn3lWChwj66mCJHkWtvkJ+kB+579g1svIPpSKsbuXy4Atl1QiCoIwzrtnbR+z1tOL1wPyrPO4gnA6Jo2948/Jz9ne00pHn7hfmYsN0ULqTEQtSddKgzs+PIw+N51RkpivTMh82GWhTxrIr+uLehRpj1v3xfhM7Lx2BCowolpM/gbWo6+H1MM0t4PKH4tc+xxjyMu8L14WPCeorIKKAnXQrQtyaNje6uJpukBPAJHaBhokP0+9+9F3svDx+nXeOqI1Y87o4jNIQl8saFrhAwqIYHhqbSFrNGbhxMwrElANKWS0huyzy2+bwFz5Vq81DiPD53Xw7tnk3BWVcm4TKtFbxtriAoqFmB13IvjNq/CJJWKPLFY060+l++MVsIPSuvg7XqddRsVISXM7aDo6UW3e51o4i1FSjua8aP/ihQQ5YEeSQ0kHN9KIlZm8Hxk1F8SDEaSvbWsMrOW2Ryr44NjUvgsakKe3qI8cqeifDpjwls3kI8aUEnK4n608iWezQz1RZGnx5Nss7TMeWoKYprHefw9HGwoPgQWvY8oY1LvTh65lz6PqOMX9AhVFs9hrTWbeYe32xs+D4KxMbqk8k2fTIUCQJXRAgItWN3u2qaGu+JKxYpYui4cxDwVwd8h92lY/P98ISrLEsNXsIKz9+4SVcKY+eZw66Ezbj+hNI/F7CG47E/6aTLSr6wpAqeeMuTosk1TNCzZLsve3BSnTw92RoABfcMYP7kJlCeM0h+L5N4Z1gtnNB9yXpLb+L1zwb0dt41mJ+ajj/uG0PKez3sf7CRp+5M4VMaj4iNNVhRXIeMVESgM+AHOA+rwSNTVOFv6nlWePsRVdrEWGy3HOY7XITFigB2Vod5x7z73DY7i+U3G0BD4DPUvu3H78KecuX5LI4vSOVRvYwKqd54a0iL1R4SHtwIMD4uGPdJTCdJ/dPwxvssphR/Qf11jTBF0I+mRZXT6Yp/HO5iCR+WmuLJ/VM56PplmlH+hnZlysCOPaVoeKgZMx8P0WQdC2i4hbDW/DFfPWlB347l8lKpz6Ra+obid+uDnKMmHm1cyddKDuG7LWOh4HQfqmrEolRuATYUmDMcKuQw5X98ph+C9Poqh/wuxgcDDB61Aui6dyo7ri2hHrNPuKLyOr62auGdb9XotoggmOwu5p5bijC/o4R7rTthYcBZfqYegtEF5/HxvVP8+fojNqkZwy0ZgnBpGIKSezv0BdxB+5w/MNVjFW5W9WJltcPkOicUXtyTAK/3k+CNqQmYNi0B2y5nnDd+I4rVCtM9/1Zkw1J8Em5N4mtHUMiOvxjVpwOZJwOhedteth+4wm9jgjl+22yILFOjJa8X0fbHmuQ8qxjcUQ0EA1WhbMV++v6jDUfPXQ8pQ6G0q8MFDr9TY7F0WRAM6yZXVYbTIeX46fdPjBwYyYqTDsHgwFl6+/oFHb7Yx3o2zdAqkIbuahZQfOwoig6qk9RaG1I7MZy3Th8k+UsPaWj0ZJLe3gZem1poaow8DET20Nx9h2it0xa27h9gEvwDe6b+5IpD+mh+tILDdUshSn4YdCQsR5unJbShZwBd+7dwg/KEf0yXzws6ptGnAXeeHyAJr3eNhrsFcqzuupGXu85hneHn6Gn6BI6faYA37Yvxs1IuJ/gmsVq3IuxeLcU53eLoM3SBi2/4UJngbDa64AQ3tT6gg7YTlB0vRr+oMWAyGIKNaw9Rza45VN0WCproiovNvvN/m5x57bpzmJS8CV+nmcFEyVKK/GaOz8ZE0rrwWgx+rgR3l6ViqakRdD1ZDMrrq0j6mDUsC8zg87+JPRsvo4F8Ku/6tRzOh4fQrO1boPTWByxJKOIPZcMg3eseSnlN5r91BB0V58Ah1oF33NlEpuF9cEx/DAf/YwHvlVaw+agG79+vBQ7Dd4O5jS1kfrgBgSGKMFcXWWONEQ85prPGfiWw0HtEw55OxbCC8XTB151PtfjDXA0dSL3vB8/2TCeR7/PxkulIeBp5lCdfPoy7wArfFC2nehFr2ntzgAKfhfCPQwLgutec1e6NhcdqQbx+80aKtEvCVrW1ELrsIU30HkYvFWrpwuhwXFbczJfmCMBhXy3eDMMoqV+FIt/0wZ/nRfgw/d8G+BTjyeYkMg18jIvyxGBS1liKeKlH1g/3wGaHE6wqUszKRWdx8cWpNHJqFv9aNwXnLFaCgStF/F9QMhwbG40SvTlYKbQFN9jN5p2Palj0Siuc146no5YmsHBFOoXsGUcNl1TQlGU55m8OXtvlBvgxA1ZOUybHtX04+p9Pb9pqBEqxw8Bi9zQadd2Qr2zpg1fByykjdiP8LZKjyjHG1CCjD0/ny8MPxWl0y/0Yfdv0B3S9BcH44hDOGuygsBs62N4ylbr+iENk4CG6IVJJFt8/0pVXEXDHfj9eFTcHof4LGGTpTv67QkHaWwTWOxvChNpafP03kX12vOITWe/5wDdpuLrmNX4+ZUdDuzbzwXnSMK1PGcv3uFBsQjiJBx/FopjP0BQVjxlKm6Bxjw7eGH0Nag/Lwbl9T3CyxmKgiUdAIPMSve6uYymDt2B2IwPGeRSzUvY93HZQGQbPemLe2MX4PkcUrhoIwcrPgewT0Ao1y3Ipf84NzAi8w2NbNcDAaQzPFOin7l9/yHvUT3jrH4WtS7aR9a8OPDNHFDd3fIT4kyLwcuNPGtvowB81PKmy8zlnVHRRXPhLTrxkw2FKrnQ9Ip63W06A58baEJ3uQl3/faPsUmmUGvTiwwYz+E1QPjcveMS938UwXlsV5ohY4qsp9bxiTyscNncFnveerUUusE+fI538cxEu5J/g9NnKIF52k53v5EPDWBdYUP2LbsQt436/Lpjf28PVTa7srlRATWwDpL2edP8xildWJZwSHskvovy4pzETZ88sxC/W2piY/gQWlRvD2UAnmpUtSKM2a3HlqEAQEFwFWxamoc/ST1T43JokNL6xgPkYGD0hgcq/NeOce+LUfreNN92bh5MvrOEbUytog8s6FI+5z5c/W8GNNXlwMyULfW/MZtPEGip076GMoAF8eHIYLO1ewxHPpLjOZgIMtqig5NxoGH5bmuvt3bBdPQJs5rbzLtEOeqwkDik3v+HiZAP45K8NKxMaoMT/PaksVCOR3mn85vMxmrS2h6pcv8K697WsGiIFhV8KYND6D6qMM+MzKovo17tOFtsZzY0vYqnR4jueKswADxQHqYJX8FbVB1MaRfBUqCA1X77H5+o8wexdBH1csYNGZewhu58EE8atRoVvx7C90pRj7HPpz9l6upOaD1ufWNGC9kaIFk3CI3q2sGp9NEz4OsQ7Rd6A/YFIyC8wgl2hJlSUXIyeYe5089F0Vo60hTWaQzwz1YnfK+aR3sEmkglq4hgtB6o/XkhG66P5iuMnfqBGMLu6BDOj6yDjbhqkL9lAchuSUUxCgh1yQmhf0wiWOn4GWopVQLVeABqrGzG3bA5PuzEMqsfL4hnPV9SUYUebPnbwcZGD8OyKDPhtOcXJn4bQU3s1t+Zm0NDs26Q96wdc3Z9FLj4CvD0tgHMtpaCYF4Pv++/wZ8IZmt69G4M3OeJvsQEsuzAej0bP/8fgb0haRRHsHyii5VNhuipkzX+3ylDa7Wqe5LCIrmVdohdRyfixdBFV7hgHRY1umFp3Dk92FNKYpedh7PF32CnxgS7E+MH8sjg+mHsBVs+wAHepBliXmAx/FGLIXW89YZkxGxUPAX+YwtcfFcCDswB9SeYg4RkL0Zdd2f7OCOyuv4re/nPpVXoHDidBfFUXw5b736NliDhsOJODmQlHaVLidjxhuZ0XL3sFVbf18e0HdxwvrwkDCVNxzlRTCJNo43Hje8kx4de/XWshsa6luOX6ZmhMkuaV/ev59/VXsOObDAgkxdE84TGsJniV7vjMYc9+oBu7MzHJs5yCLb/D2kmb4c0UC1jSVQWG4ff5evIkIJEzME9yGi/1/cXaM0cQrkmnpzat2KoM8GVRD4adEaP9xiPZbM5juHuwhi/5eaJQyQwIOrkJQyUU6NRoPdgg/puyB3Jh7zlPFrGV4r9lP3hRzHEcWC9MBa8mQ4XmFqo7YAiHRgazaeZpygiwhGord7yvN4pHt4hyxhw5mCFyjCZMSGYLOXOwfzsanOPbwMZtKv52FcImR1Xo8lkL38xVYWbCH77zpR3aZGSharIIH3+AvOSEE9vaXOCO9hTWvn0bP+cqwcPGfKr+OAvLEs1gTP5SutU/Dg2GJ7HWdne0PV9B119uQmPnIXy+YpDHz97JYZGjYGTmHZb9eJOSOttQxU6MkpUDYPlGL9buWU/HTB/AxO9r+fRCLRAWXM59G/wg7e5x7H5YyqYOk0nDdhXYGvhxx6olfEbHkQL22YBKVy/6vdTBU6ojoPWDKW6rWQup+tNo57cGBAEvKh1opHPPRsDWiVv/7d81nrnIjX0mHv/n6nJYWdFKYh8HoPRlGGw884vK90rBg91nqWnjFJizOgtdWl+yHHvi6MGFLDJiKzk69kLalV+8ykACNolUsbXxu39dNxWaVa7ywkOieM3gGWyRC+em2gEQ3Z3AU4Un/s/+/yvTP4Hmzx6i+fvXo1LgM4jbN50bos1gR8oBniEvCJPBnZLNbGH/vlLI8NuAPnI2EJfZS6+v7KZ1e9LQo/Au7BDo50ZHIRZxU4YCzQh27Wngq/N1ySNmBA2MN4dqu3j8KhlLy0aNxaEqcbp4QRMCDNIxq8Qdq/ZKoIL8bwg/lkASxwZpXrYZS/2ay6XDB/nURivw+PcM15PDcZPKv7xMfs/qjzW5MrcT5n2PwLFjptFegXC8nGUDD8N3Y1tRJy9reoO2XvX4+PwNbnt/G2bXbEefvktw374Hzy8DyMmTAJd/DC56yo/jV56jR5ZFnBa8DXz8Ynm0Qxfn5t9muwAxsFj9Agxfn+fe0wdp3sFOvKWyBH/cu4i/wz+xU60At+xKxmcO8nDy3AmOeXUMdfYb4rl7B3HmkdUQE3IEAu4n0Oe3czBawA07hmtCpmMrZAgpgZP6EMhNaoZjUnFQ6HsUXCd/gXejD8LFA4/Ab+8Y0FnTjYVVjhjrdQYLywZo4yot7FY0xglznGD1lLekdb6PVxwaDokVm1C+uhne7ZpEThmTqfC/FPbsNaKFGlq42kwbItZIY4aIMvydX0JCiod5ytY0uGW+DpvOzKLrhUEwbeNbtP7vPtjuj4eaBCX4/egoT829CD/PDKPRvikYO3kNPn5bQmNF4rgstpc6j86E8KkIcVETOVu/giKzT8G1xF1UcVWKXuVOgZymJLCIPE8nl/WBzhNtuLBzD+255oV1iufYYcUGilzSBLa6fiwwzRnt9D7Aats0ehduDXWXz6HuGR1USV9HNWEXqeTGJJgeN4Hffl2JI+f/BCFjOTjhNwlkJ6bBJqUsjKrsYlnp6XT8537wnH6YpT66YIl4F9XIJtLEj+bgvewRxfr95cEFM/Da77n8JuQ2jOv6SQXBThy5/BBoHUyBgrFKELk+FbYLHyWJtGl0pb6Q5Vd44KS3xuTx9hVZT7vJBvwKu15ZgVl8LDTNcuCt5tNI/sN9bprzGhuCflHX6jbo9/2Er3LS/zmkAKTon6MP7Stg25/V+NNdmJtyFtD2/ky0UBpE2aCnnPhBEvELwC1t4sdabfjDxR8zfwjDwwV3KPqOK79+K4sj+16C7Up5iNutABe914Hcm3VQOMKcxlyuwpV5cWx9IoL/Lkni5X+7oGeSHAo/FoJ02aUUndFD+ZdH8OuWW6CnnU2jyqey6cTDtE3Ii6dUB9GnfdpguKcL2tJdcMt2KTzSnAG9E7Qw+L4juz7azbvCa+Gwy106Pl0BIuoK+WWJLs7K/AOpGrtJelYnC31vg19zvvE5qzxePNXun8cNg6w6Sa7vXcLCm43xeVUPHb+qCmmyWzFtjCvYxFvDPnVJiMgyhhr1szDPsoaUDxBeN9vFt8M2cJ5cClwyHU1ZJkFUK1zOJvV2cHp4Kdq2PGffE4nwUnUUC9Sdg8Njq7FguyCtPHqdnHAcla6Vh9ZUB0yK0IE1Tp8x00KZvN5FUbR3Lue6hcDOCUCLtnXjbUVNaH6sjTG1kyHJ+yEtT01DnH6DHj6ox+PGPpDdpQrbRWQ557sN5On7o56yGS1Vu4RbL/rxt/1HsG+PJ4ZoLqXwElOWnheELnMmgtF5DdTwW0grhrJAal0XXndMJJfFA3giWgdFMiXIIHE6F88whL5tB+hu93G+nCUD6z838Y4FY/m9uhEHV6WD2b4eWDDYjv/5jQarbCM+kpbFwTXJVNf6Hx8ULoHpVh3Y434ZL0VkcteHF3RM8R/XyVzizk/9/DxHjUYlRcB/qa9ZwccftxhNxiqXkzj99Tiub7CAiJ7d/O55Cmw964wh7eM5/1sLXVu7Cr4PZIOu1D0Oy2yFEYsJTuxUwG/nvLheaz26mS6Fv3aPIcL1Ne6+uwNigr/wFYlrtKzZGIqc93OfxnR60f0QNkv54P7nj6kv0x529oyi9ZuQ5QtWwfRyFTgXYQ81nSogseoTLzcxo+77+hQ4/gG6rM1AzwdVYNcaQ6XmFvDXfAO0lQrCymY1dNpozMOOOGDJM1ne3e6E3ooatErrOB3tU4Hy2C7e+WM3LyiPgfKLbf+Y+T/Y2r8a+6ym01nhKhTfnoW2q61B0KOM94xaSxlfJaB473IUv/QfDQRWgoPsNj7SFsYlo8w5+7ou1LbWkXtaLaqPTeWY4B+8NfMaW7Ew/JLswtdDeTRu7Wa4NgEg2r8Xbj87i3Y8i1N/RFFduBqffp8AUs4TOeX+EVS95AZC6qrwZtJiWJl5lq7NeoltDl9g+MptrGzvwvLtkmxyMBQ18maTxW0rMM6bhS8frKHC1V4gMS0PxQU76NXkIT6iVQV3Rjtgnks2GBXLQN7GbxjyS5njC6IotUAHLq2Vph+6I+BnnRJujYjlY9YVuNSHwOHKeWyqfMerLz1lM6UGis4PxSTTp+hsOpY2rWwlwTv3SbpYDX6sYtTx18IBlZ0kOZTN5VIv0D57MRi9EaGJTTXY+9CdQ+VV4fDz2XgUW/nqYR0o8whhl1GNXNgrSNuHTeOvz7thm8cyXOaoBtoNTuD0fDIlP74Pgzv7+Uvxe3zplAgceAtX/JWCO7kM18onwLDtU+Hx31ngrtmLKRtPocXp1xTpfYpe5xegT3cA+FbegHpWhUrvVBjZOAluDc4Dr649OMvvAT+f0AhBCjH45MNKSAz15NI1CmDhr0JdmnXkfegdVVxypaK4mRR1LBGt8mzh/OnfeMksnSKfi8KcjAGes6Cbl+vW8xHJBJa3+Agp2y7xLu8FWFQ1jQv1RlBlKMK+K4KgPCsNnTcswVJnEzgX9YC2PaollfoPtPbgNjjokA+5cyzgQM1Yej+Yz9uSevDI+hc48pQ76Ih9xznLq7Dww1OY1zQJPWxHQVXKS/bLb6PHD69w8yZ50NF9gWWXV5GhwVYImKKNtdem8uhPABNi98Ol7wPQPr0dzJSCqTz1NyjeP8WFk4PwXU0j+b0zoID4f/6rKE63r5eQyewlPNqxmW2GufEopzNoNt4HdCMSITzjJX2PtoEPEUfho8FFLDt6E53dmljcpJS18ypoxUNbkGm9AVo59rRwpCqMtfgF8xNu8Rm/QHxdsAkyBXt485UzGCNvAcWxV+FO6wh+YWAFV607OGfubQ6YNoSd8wPorqkKRzxUw/b+IdpRtxy712jxZ3tbUDB6zA83jOa5H40gattUvnmvjw6+v40jAubDXYdUSF0dwJNeK8JGmSxosJlDD2Xf8cylW0lYPoPnTq4D0UFz9POOZg3BNs4/oQ+GZrL8JS+ehkdrQb36Tf5wfQ/IzBtGMxMWw5TIQXbt3UpxGxTgV6QO+OtOg9Ctvay/wYKDRsjT/ichuKWwGeSPqIPFtmVEj2TAvaiNp3zsxHatk7ShtobmaprjJ7s3CI5VbCQwl+3kkUbJCYONrzANeP3h/WldsGToLKzxdMYFqqvwYKEuZjhl84HERbT0sw4saGgD49Z0NjZWQ++cX/RN2oM0ikRw1qF9bGg3Bct0L1H0SVNQXB8CIVkDtLhzDBlXKLJk41j4c7SLPKoPQOPQSXDYUcQvdoyElQutOEckDVrmNlC3kw7MDRUE2TBx6rf5CDY/NPhO/mFqHDMB7Mc34aVIF9ytchviSpfAygcn2TvNAkopCsYcGM+9753J/+NokA+VwT4FRRLVDcb3uw6S3f0lMN5lBXRtfc2PJ8yFlmYTnLjLEsRKbuG9zjx0gVJuv+QDXnLzYUbHN85v6ED1y/82N2wPHTgCsPWMMKh/vAreM46Q2ZRTmCu2Bg2L+wATJfjvG302mqXJLvaGUByTgzpP3nPTuViOGXWBX54L5B2h18j1/793qlmLS6kdGl6rwdT4Hv5b7o8vX2ix+qohHBzdwg9TJtPV3F1w12YNB7q3496zBDezDlI7n+cWFX8KSBwFcYHGID4/Hv1b3nLOjt+QJ5WP9V8VYNvRSaj4+TM9274akq0fQYq6F54tKwZl26/gbLyLImyucNcfG5j8rR9ip4qjhkshdW5GJJtg2DgjCVYlZoNF2TgQSHbmMid5EByS4Ao8xQd6NUHWfDXZXpKgva2GcGVNHX8v0OdR687DuCVCcOJoEZ3b8Q49HIKh18Obt6Zm4Z7Uegy8P5vuziuC9cmxVGIyEq7P2IeTCvohu78QTp6SIpXJ0lReeJdiW53JMDyLs4viwCFrDCTusCbd1iPoILUMG8/XgP+hTCry/clBWz6zadFhPHzFAOXny4G6lBZvkd7Cb+bao3H1Exz63sYkJgWOH8/h+OILFGAaB67WypDjNZ31Ri2BEQ8kweqVGN5+sBZ8c46DiyxCk/AzWtm7nxc8mghiJufpv5VjqHRoIducKMVEt0G8eu8BTtyxjtOPilPa4zsgc3EkmEcA18Y8p9uFv3jnAkloaZ/B9UprYB5+5KixDqwyFMtREyaA3v0fdC7yCD59fh2crTaS4JEXMNmyAFaEWdA9jWVsle+DkknW8MZqOnptC6TZ1p1oqrsa40oSISAjlra0+lOiqizrhtVwV7o2WN8S4nvzqtD68DvqSI3kkMZUePTYAO6tryDr84VgKJmPd59oQL1oIS+cfxESbwjSu/kqGPNsFqnMBPidn8/P42eAtk8D2K20hmoZCS7sLOED5cp0WeI+7j4vgi+7nEDlrwx/ObWQvAbH8tlmO9AYfpxFJN5CtupkWioRTjMM38Guvr/gLpmDGuNlYcngKL41YhQczvhNJ+Y6Q8r4bj6cKk7Sv/2gsegxtOaJw9hbc2FS9SnUOzoMWsOSQemHOL5/MpKCzQYoQNCdNgy6kLN2BeZEvyH1fw7VMB2hfdxRijl0AHa++MeRCzNR7Vol6ArdY+u6LRj/4R0uvqDDhqt1oC7AnwSbmlGrd4hOi/+hN9fSqbP9NbuVr0fV/UvR6kwArtdRhwcdF3Bs1Xe+qJTIts4dPJp8eXZZI/4X/IduBa3lPac9Qf8/gIc/x/LPhlX0UE+XHbxO44eDvuBz7wbOc4jmH7dNwbZsKXvIqIHCTEE86rmBj7slwp0Tn2CbZS3bWBtC/apv5Cx/B5xk03npBA24avwWJ7SPo2cZEpB6yxiWfSqFuzH6ODwziovlt9MDj0X4+oEt6P/0pmNr1nDV3BYaE2REHffVYWy2HlzwNwbhpXZo8lCb5/7by9BxS6hQfCPaYAYKlqtydHkA9AsmkWNfDZlaO3B813BcUGQJKmu+olrwEVrqPB4bWvPBw+4O757+ibcv+48bk1IhLW85GAYhqCnk4fUF8ej37AF8v+BLz38nw0Lbi5CzMQ9OJ9dDt6YTHlisD1r3v+DuSyIkMmiIFtpeHGKwDBzzS/BQYSbBLmVIeC0JJ//5+WIncVSpMYcDc0pwxM6rdCc+jfybS7F/0X0uqbzH60K6oWmjDEzvD8JKNVFutThOwTuzyE+dKPijDLUfDieFmhz85j4TslPkINI2HEeaWcCdiH48ts0fv6W5sbtfNvpnvaQNVZq47/pofpouADK/Wml97mVKVllNRws/kGXzJT6RbQvZZjk8RjcHTif+Ic0t1tD1eTgKuafBsN6b3Lq/ByelJdGkN5fpa/Qo4tjXsM7yKJ2pIvgZYYNpWWGQNM4Ax24fR6IbNoBozynYdq6A7nInG6p/IIcoAQhvf42c9QS7CvXYRsGQfLPzwL7jK927r8KHPybgy5eyHNUvC3z/GN7bJwAPn4Vgte9zHPVxBeaeCCffh98odooUGk5Mpjx7QTh7uAxvuy3l6v2TuO6/K6C6fhz3DXniU6ljWJBmgQtWVZCdrj5IdydwnNwsat42gvrW6XGNdCxeHhnM9W/KYPrAII2ovkaLm8XhqVQe5kv1o3DkYvYLX0CTdSJ5vFESe7x9Aq55YuxRsQuvZquDcocbCg+sgIDDT7n8bDK1dA+h22tjOHZWgU6ef47eGuPA+MNEkLoaCd1Z49H79Us4MLiY8e079hd9zHNsrSHgpz5V33Skm49s4P5zI1D7YQaJ6/L4RocH+77qge4mUZi1aDPW359IhoeLaLKRNUj+6+Ucqct8/814Wkl7yff2IKx4LMczPu7H7QubOHHUf/zSxwxYTA6XW14hpe3jeUP+V4gs2UcqTVOhUPYlmvo0UuKiaxyzTgRuzVeE52JfqP1iCu6NP8XjN1xEMaOx/7pkFXVojoXxillYNygAJVoW9CJ/Ndf2V5PmAaBx0mu4W/krliwQw8AiQdqWdhD+GJjB3txfqNn3ALf9vcpptwZIrHwae/4aBu2aHrCWg3BArZRjNIeB3LhF4Df6CoeeX8C7J8WTSV4oNkv2cPL+1ejx/hH62ZZTWv0kmB0cRzuFXvOloXWwVzWVN9n+ZfMdGjR38C5ZbF/KU4/54filZjB++Qp0LspiHfG12DbBlSZbXMXjEUAve1fD7IOm7NTXz6q/GfS+fcejLmFo3+9Np/Vt2TEjmGbMngdpDy1RTewZhBQE8ZbzljDrvD4Um36k/6PovB9C/Nowfg9EqbS0p4oWSlNlpGE1KFuICoUoDQ2FipAiEi2hlFGkolRS5FtWKlJSyMwoJKTy9v4Jz33uc12fzy/PKc2ThO0ZD8A+bjFI2cljaRdw258R8Lh/NyxxN4GijyfZEcohb74BhBxwQNOGe7TxvRqvc79HDRP16IK+JDj7q0CToA1/OZqNos5b6ciqFE7cp481Nx9jkfkIDNT+yi0zc/Ba7JAvZBWAVFsFtOSuxjOvPLH4ewxdvdKDe+Q04ebhKLj2eCTXXR4DUv6LocYnEu0a6zhhUIm8VihR8pF7GPDMkzOSZrFt+mMaZ6oGnXe3gZdLE6zq9IQPV+RpdU0lTFE4wp/Sm1DK1oYvdctAQJMUyE2UBwUvJ1Z0Zlq41Q9Swj2HHD6flZWT+cW2B3wpOwH7YlQBJjlj619/SnC9gD36buCZ58oR3x6D3Mn1WLPuNzZ/WEY+6QYwer4Zam2Vg7/rrUnl6gF+/tiY537YhBJeLTx8aM8/ieazjdo0SNkzgR837oLMtAhc4X8SH7AuXrqrA/uD18IafR3+3lRLyseHgVJTB7nI/uPFdh/gyovX7BL6mdNmCuDHkTmwWTidfJOL+HKCOcw7txwdfXbxjRuWEDHEUuGLnXlVuhFFzbyOZ8+UsZzMEZ6xUBscrs6DRtXpcGH3V1qrGARtQWbQe2c12urGQ+WUkyh34QvMOmkB5+5MAptaIVwcIIPV09MoDAXxhJYuNocvwRAxTXR7ugnObxwHRXGCuMX9K055Yo+3vH+gzrdyPHI4nzIF8vlR8AG6t9ab8/6pwnatYMa2djA3D4INCVl06NtytJHcQjenzOZ1LaoYbaWJT0dKwl3t08gDGiynX8FhDj3oNmEnzskGnvziJLz5spvs9k6jF+PHg5yKD+/sSIa3a/pRSkIJdvpfxJ8SCzmtSBYdskzIQi2SfqcTpDZdxK+jZ1Da7gGcrxiDFVXRsHxgHH+sPY/J5x9C3/xSHi08CUZuPwBnnVzIOiaGYg8KcOdgPU3d840irRjj4hxReOJP+i6kDg81f7C+zw1eo3kIF04toJLDNfByC5HNpu9UEtbPM189IvF4ZViw040Err3FgxgKat+fUbRHHfj0yXAadkBV4Hqkey/wiZspDHN4w7XR6TR7qR1n92nAnkmbUbrmGngrbOJYjWx4eW4NqAYowbVzGdQsvBoWqe1AGXtP/li5mswK3rJcpxROdVwMbx0zUeOWHqxb+Jeiu/RAIbwB+1bl4tOEm9BpAniqUxKKamTp14237B8hD+bPluDCSicasSiXx/+Yg81Fu/nh3dXwL2MHdbfe4He+5bDCWAIaJm2jK28C0Ns9Dca2b6do+yzO7H9Ox4Iv8u/M2SipcByvKmiC+i4Z2ipYR48DxtPN15s57qgrBD67xXNSzuOZ/8L5qmApPp6GILdzFKh9Mqfc1tNYmbAE5q8swZox/1j+yhWsH9v7/3/kQWymBhxpaua1KwyH5vMT7COMaJxVLE9TUIby587YceE/LNb4ASY9w+FJ9meIXLaDXHY6ol3/GVwY1Q+vl6WwcfN0MJosSxAiSHEDCCfNcplkx9DKk5KgV/UeU9bb4Y/0SDwqHMM9Da448+sniEobBXBhEwfsNAMb8zxeNdeXm75vZtUoQ1qs488yx1NYReArGimbg9JEDVY0Y0p7Mp9/lnjj1cgTYF7ynDZXv8flfYpko/4UxyWIgoh+Hoddyadn89up0nYyymlLgmPhAnq35iPPWb4W5ldJ0+EhPv5gtQjfnw+HqZ2l4FeSQM9fnIcJMi1U/RCoamQH64Wl07pX4hA2sBlev1jNRQ1KIGdzkMPnqpHD1iXsF5POO3tG4PQ7iXCxSBx+mtpzyIc2FPwVQmXaeSCkCGw8w4vmpFlwq0E3rku6jffvjYaspjTI/3aAHulYUHXiHW501eDJ+QJ8P0Mdz9Ztg+8fiujc5ykgM0+CyzfUQcKAEMqlBWBOSi6Ft5wDV/tBTnIrgdMv7HFPsxAIt3nz0xGu0DsowhpW2rg7wxM6qos50PkhZZU6Y0xMG2+JUIMFkn0QNC+eXokN9YaQCIR+vo89XTtwzhELClV7SuLexVxmMx2ue2yD59tOsmppGKa99eLeS8ms3O1O+iKvsE9hPcZb68EpX3nw9q6CaLEkOFJ1H8a3TUGBwyPwnkoQiEzxB/ULbnR4+xLe/08L9CRN6IdOMCyDLoyNH4/FN7XBzmMY6n2uJQNlRXa11ISzOVJgmCmM21YEYezdiygiZsuxsY1Y0qzO/K2H5s1IR59RPQTfpeDWZntSOX+Dpsn280KDW3D6nA/MHoMQ958/a/S48LB+aVQqFgFDg+dUWSfJEvWRVLHiNT3XKsULOivRNfoi/n30l/IiZfjfKC3QPdWO+zW3oYP3KJ5XhzDP5wfLb8+AveVxNOdsOC5ccYc3TdeE9S4Ih+f+xAebH5LylVa40B/P86d7wzh5pKBTDhygPpMbHguARexNfiYdR0UzHMg0oYeHzVJCg4NHeLB2NenOfknjzt3iac/N4Ofz13Qlsge1Wo/h8LsG5O5TDGctg7gjJxOMZ4jwy63fUTvYBIIam/l27RwUD5Pkq3+fQnHgJzxT1YShrichriCQjAy8KP3CeCjb6c7iPpKwOEyZHNeI4yaDKH54NRnmC3+gp6bCHH/akC06hWFvmQiJRSWTz8FUFn+nQscD/3H4wG/8MvEvhscvoMUlLyAqbgT8vLwKz3yMo4zOPrLsjITudZ10y2c6bP4ZRGB4D+LWWGFYvgKs3LcTGt8nY9aILxDyXzUlmtpCQYsNjVVYyTqz/eBwRh3YvdcEg7hd/NFTjXvPW9Oy8LvQvXEyqvw6zgYpYrhOYTzo2oWh6SILSAtwJve/C/jF2CmgIldM270XYE9DPb0NFeLNc/bQjCddmDlJDmapHaeVtke4xO0ayYVvJIEAdXo9UwQm3TCEKitZ9jl4HytuIJgkmYDt6gT+GVJP0eUb8OWedOx2kWOdr6GYq5uO26ZpoJORKnzzZ/iy/xPdi4zA++9kcNr6RHh6PBc6485Sy4SF2CktCWnVY6Dzxw7UMfSjpsEKHrSfDZMVX9ESkU/8UXcPax3VAHVNf57+Ziws8EzEe0V+6N27E27tCsKk2BMg9XaAlH9rsrr/E9QTa2XfqeqQE5QATXPPYnrkbPpkMh1uv0yFrB8TqDbEDU5fOAV4dxJGzjUBz9s7eZdUB8v6zWS3GnEyM9GnL0FSuOucF+n/K0fdkh98q10botbZwf3THfy97yC+kGyD3/tP8mrbA9ht2UcSc9dyjXAa7qgXB0nrCiqUeM8CI3XJe6CfT909Ac1X7kBb+RESXbuSdo0z5YUPRSFPdiHP2/kGjy84A6duF5Cj5D3cdywdqg5PhkqxVTxPYia9bpWFlOc2POLzCbz4/AG2Gz0D/e0emDIqhs6rvecs8730a9dl5EppGD/cgBx9jlCDZg85vHOA6PpVYHNXEQ4usIXRPrLw5+RBFnCVgVCrg3ArWRWCJRLx+XgnvvUsm70uJdASQxm0dziBvcJfOfWeBYxvqMd7blk0IWsT/am+xZl7V/G1M+/AKmEtQu49fPtFiD89kIDKcRd543cHWKuVhAldW0G10Jbf51xk8ZG/2OfiK2i/H0rK/ZMgxgVIOvIGznm3iP3TjCEqdD78WKcHJSmL6I1nMS46mY3Xw02gLr+G3MW/QUXcWvjjsRLjpoTy3anfUD5OjqKHP0SvTlFWdRryqqc5sG2xInfHmdEv6WMY0JkKvnX26CWxAnq3K9KS4Fi6vtkQJNocOS+rFaV6GuGgkSqLbfBEr1W6GHRpK9qqDOXvXBW+VWAE8lvayX3pJVTBOzT78GM+3nOMc+rng2JMIP8RWUe5K3zho7gynM9zB5ukW7DUJQk2yaYM8cIEdJWzZ1OPJThEinTG7hSOdZwKu9b5QGjADSpdr4/KPldQx2QUDxvhAKnvXnOHx006tSmZi9TkYKn0CDC508uzYtP4P8tQqs1eRx+fLeb9sXb0dl8iZvhvwcZpWtAWNwZ3uG9i1YDT5Ml3+XSPMlVvsMC6ODsoCvwL1KuBmtUiELllDD0aowkmI5Wp5F8fft2dj32l71DgzgqqPRgFJjMEoOvGVGhsLIPG3NewJbYGF+dLQv8rZ36qX85vP83F7BRN3OrQCD+TxsDO9Bnwa5c/9DuVQFGCNR1akkTgi1BRdgCXyKpBv/Mh3FRoACcnTkEycwXHTcLUXZ0IC1ul2a58MsU0BED3gj6+IdMFiW+0YdHqGpC8UsfPmvLZXD2HlHEnxRQ4cr6qB7rMv8yxmmspoY7hlOcGjk4Th20FUtSjfY4uPfoGmc8sUGVVCA90KMHqS458NFMCDDTcqO9MMH+z3sijOiLgh/58Kn4YCQH/zrDco5XUlnsBn3/Whbsqalg71YlfpnuQdE07Bifk8u2VNyircxrdjPfA6JATfM9EDQQy9lOFTgoOyLzFc0ZC5GM0SOHdB2CB00rQn/+dC13s6T91BThuk0DCu3UxwGQcexjHYk3RQ0jXVuWX+XswrycdN465QLbxcnA8PQN8igXJ83cn9hpbYH6VO4Qm3OWAVUWcNXwhW5zR5OSt8hCQ/Jz9PqVSWWYhTNmRhl2mQqAdd4LnrJsFl/Z9pb1eATy6SBWWGzTinYJz3NfQwkuC75K/7jCKspuEmS31KOy3h6wuBGF5uyVctjkDWd6fMa0liMctTOb2DxdpgsI2mnrhG+4JykJT2yZwExwLn15W0iKlHbDzlSTXaWXQs+JjHPHsCfcGzMVa60BwF/AEJWFtCHKRJmMXT3QRr8PsVEabimEsFyvP/8xDecaGIJ4z5zHoKhCEDhjx7LT5MEf8ANI+fUgoHscS02PR5ngaZzTb8qiUHTjfaBqYP55JW+bdxczaFBy8agNT1VJg+qI1rDh0TveGOr1xlR8Ge1mC3rmFHP3vGyZqx8DxWw+hqUKNZ1Rvg32LxLDjlS6ovvmGI0VEYdluEZ7cfI9UcoNoz3EPOFPnB4XlCbzldi+MECrF/U2ilB2mBnfU/VFaYxLLN8RB4eNoiO4bjpP/qfLZog3Y6nyblQbbOOGdMBz7z43OT9pIRUcEwbxbDfjHRVQf6wZOg/Pg6XptHm3kS/WNI6H1ejy+u62Ca0qWQafAcP49v5kNTS5QxU0ZzM5dDldtfqC9jizIVTrhBuslaKRTALmfmnimtCA/fTAH8pTvw1QNa3JSXw45N8fCpfSNFBDgho/sf4PYwHDa9UcH2p8tBI9P5ylm6WyUfjGJBn+rw+1XS+Hv/tvsPb6CY8otYKr9QvrQeJuv7lnNCYd+0dF/O0B5tSXs6Z7Da65XE1x6iKRwiN+bydOV9baYu8STv6wf8oGEIripYwyjukZDq5UGpXfowK1DwRQ7wRLlVwRQovxeOiVVBsHPE/GKxZDvq/mDdsgyniZcDZmlkeDemMEHfJ9zfsQYbtz5k6P2n8flwiZQ2fqZr+bkgci/FaD/CDBy0I5yL9XABZNKVjIu5eEvG1jYwACu3G2kjsS7tCe7h1dLt8Ocp/q04ttiPOiXT3SsC3Ruz+bokpEwK7gOfXOO0tHmR2i/9iWGbTuHyZGp+Hv9adpkugDf3KvBig4NUDV3pSnql9CsYywc1HrGS4z3wotDpnTHPJnvbVhCvYqvaZYng5JsH7032wQdC0ohWO021LzfhJuHul96USlNz3yBg7cNIXqeJGwnf1jVkQJiZ2fAU+cPcBrOoGj3RIjMS4daRxGqZwN4pK0Ii21/wRURDeBTr1mw/BiaCE+gZZ83wNrE2fTF2hbUZhVBT44ebPhvCTQWxFH2owh6YjSeNnZZUobhH16lII/+HrV02+QaRXTqgcm2OFLb10Qqb2VRomI6/xKRoawGO1hv/wUVA06A8+xoKKiWBhXJDRx8cRBagqSIKz5A2IsiTj1EOHvrbY6ZuYli93/jhd9NIF2tD6/nKUGg6HXsr6nnKyeLwDn8IhY8GYGLr2wEO/cyXCAx5BUyz0FIqJG+jl0KKyeehprofviW38KDqTshPkwazFOAXo43gpwUd7yquZlrg52gNtYSPPxMILXRm0o0NeDyH0G8tmYEOL7VhWNfg+GRzQPU3H0ZlH3q8d20ZyAxVg0b3uSzb8YpaonJgOzjE6By+izujrKjv6YXQSelEuV8StGsV5gLG1z5uU4aLPNq4mMFAK7DAkFZp5zWvpnKNr61nC+1FbZu9uSvjuJk/dCJ/Lx348vhowGCakjiLJOvpRVHNxtzuKsJqjVZ4pblG/j+dHt8eHY3C31CIGsh3DbLDav6ZclNZB/vkasGXRt56NjmjrFCrZgQXsQtNzQhtvc0X5ApJKspVWC4cAtKxIugunwZ+AuepGvBkfhRTB5GiOhAwb2peNHpBKTveIFmY79SfByg9de9oPXkMY36PgjD1PPo2EszkEqaCz1d7/iIjgT1W8zB5TfmgMSoy3SWTvJsw9/4n+cCtD4yDP4sdqMTd/UoJdWVqsOEIazPkXub7/O7/P004eExvp96D5qkVCBHuRte/lOnxXNkaWpWLf5tG41WYzfSoyeXMMnUnLO2qNLKvbqQXnEQemUnQauyMG+K3Y9BB8dT1oOn5KI+nT8LrAGt+6spNGAqfFE1gh2qK3m1zWdY59GJt85GoaHlOS48PofnRSyk7G4fGlghCb3LD9Gn6Hd0xzoMyt/fB4liG3A7JYY7cnIhojUaD54Iwdb1yuDjKI3qSTt5z49kWJutgtbvjQjzOjBPSx+bjswlr5l/yPL6GHg1chsFlV2h/04G0L2Jd6jabgvHJh7iOJ6Bi39fxCvDdOHWPxNwOGUAvC0EDX63w5SfCVTilAK64WMo56oM20tX4kzHcaQwRgfGDyvA2Z37YWH2bwx26sM/Pg/YLEgUn17Lp4FYG8odNATZuUowL2U7ZV5LwsnCtZSabcXNeYvYbecKKsy+gN9FvPlZZRUucpGA8s8n8aTqaNyzaxOa53az7+cEcEhdCJPP3kQU20V7o53RtkUG0u9OwN0RU7hhbxlgVARta9mO6XJJ0LHsAYR+OkRiMwLRSm089K9rpH3BpmyucJ063nqD+N5I+HlkHvhI/MPdGYchJ68RVkw3BfOsmzjBygD+e2WOI0pEOPTdQchV3sMJ03Vga+kKGOZig8FxhjCvcxxmT5gJdecioNBpaB8XR0Fa/yOwMy6A7Y0nyeGkAx14MQbuCG0mX6VnFOWmjf2KThwTehVWLrRlI1sNDtqcSRJ+W2mUlwy4n8nBq49O48wkZ5ot7QHp21aSo+wIGPU8BFfP/kUrkof48+5EeGOwHmyMesDvZyuVr17JkvZDTLv/NZ1+ks/zXPz5Q9FNtspVgi8Hr4BiyTZOnHAFXqyTgW8FyrhAppKd+kRopM5TflU9ifROW0D6kZ10uVOKJmrnYHLTUzI6pkodq2R569cfYPHWmlq7cuGZ6ATYMms97TxziXd2aLG28ita2I9U093EXiMe4e6l0mhNX+FA1igIEpkAIuoSXPx5LDzx3wgu85p5plkcVM07Cr79s3iLbhm1mJuBy0EhLlP9QKUfr9HRHZbYUHuZtJLMKe+tJY7WfQUhn29AQ60EmOrIky/sYvfqJlIbVo/Dpg6igxJSRYYzVHkzLXifQIN2ptArIUJnVIrg1qolsElyJL5su0GpY3Lpmt1lFnpXAQdKTrOstBnoX+jAqWWJJBNhxyP+3sWc+BBwFDkPe7zXgdRla3KwP4FzJabC9T87OEV885B3rkCVeUc5/awJ6N/ZSSuXhLMipmDJ6wXspqIEFqsGWebYHawvqYExwz0gSeoWrynO5yoHQ6yxbacgwQ00MlcDSlY8gK1m04CCgkFpyEcv9i+Ck0ql6BZyB02lHmBz2W+oFVcC9WvWALOmw6zN4Sw8RpHCA0/TRKcgrPVfBQNT/enNEEP2rJWAPfO34Hl3I3qtcBeMYRaest7OG5M3UeFSLxR5dwcmaB/nNhlV2JpjCn9a/UFrRQSM70mDfSYLuCxyL6M4QOJwcdYrHcvFQ9wUNmovChg5gh3u4xE3DPlMfjZb6Srx6aODLKfSz2bdr1A82hzCex0wPXg4X03cixPlgkn16ADcljOHlZtfcMv0t/BR5RNPeqEJcl736b+yNWwZIAbuvW+p5FsVCz/ww9PzHuGd/66wl8cr+GImCWcacjE+UZX7ZzvhQaHL6HuyioptLpDcjRmUMUuIAlymUuul6dCcMIg4Kh4UWwfg3FZndH6YAOrXnalpzE9okJXDqZKiNPGoJNz/85A/FZ7m3jfSuKj4Hn56vASFItP5zsTPrGcTgM+F3nIDG4Ku/DGe4aAMqa/loKpnOcdenwnWec/5Z95b2rGmGYrqvWmnmBYs0X2Jy31c6GOdGOTFTYGfA3txYNsubLnlR6bWGjg/3pXbhJXg828DdojfQeupDMWC/dFUWAPrRWez6AxjNtI3gsfLZ+Hps4rwsDQFpCar89hbEthk9RwGf7xGl7gfcH5XPs3Y6odWt13pN2iCfaIkny6XI5PZb1iCQqhypy/9d/AJtS7pp6wVR7EqCsEuSBkKysrwdeN8qLetJqO/U3ihQQFEqwlj7LQQtn/WTRe/OlBTpikkB3tAxuRavONbhLm2glSzI5yMI1R4kYwlhvRU8Y2qaugvMYbXm21gZLIDaoo9offmLynkvi6ffx5F+3e0YLKhFdinuOHZZgMQdvXlWfdaMaZ0AS++Mgoyel6x6PFLIJtHcEqkjQtLxUg3ThluFIWwg9ZFynpcTHP2/eJdinOYfRXJaNU4oEBPvOJxHF7UE1z4mYkfDMJw46lauiDaxSfWDFKnwAdu0Abc4ZIEha5C8DpZFuYZDMdIsd184eRnMNBKoPtBtXTCfyVLTciHVU4N+CVCFR+MGg4vJ+lgV4wx2unV8nXjSegdHQsfPUtA6q0gqh2xoFSHRhSsl4WNbmdwXlg4HRj4BVKSkjj/K7LwzdPY0NKMDTNlKSKvFMdulwLRaUfhekARF2kZUuSwG2ymsJ20hN3h3Z4DPCXSDV56teBScWnQ7PDH0KRKEH5mScsk9ei63Crocw5jpfQiFK+KIrMoDRDfMBnspp0h7fq52KJ+n3OetFLpy03ksmwVXP1aB9OUT5EgKXKvsCyMW1qJB8wT8IpmKFbt3M2vjseioaYSFunP4q/m2jDL4zNN1RkD8TUNbKm4nsJ8r8NxtRLupjtssKUdExb54qWsiazzpALmSqhCyPp+HD8/ECvUbOHDT0Po+h3AsjLi/E6yjg9a58Cf3X+Qo1ShyOk4aISsBGGdHTQ7LgJzF9/kA5InuED4GFqIFqBa5Rl+OB/hfM5+vGJ/DFYoDqdXS3div+A89H9zCjZdrcOlkdZ8PrCYCko0IMpfAFwy8zizbQRU7TuAgSNU6Pz4VN7/5wtZXfOlFQ1rYXj3aCiYh6wh6MSHPumCnH4glWQX4o3r8hzUMAeufHBlXSM5FNyvAF3lEzHxfsrQ3qTwjs48mvB+NSTpHgGjGxfAI9YTpryOZ4dPStC7sp+eLL8Fi73D8IdZM1TK78aVbXd4ybKJ+GG3Pg1rOo8h0wjem0fhj+Xx/OpsJA76DECUwTR4736ARzV6oHW3J9WubwXVcEV4dHQ5FIr78oiNXXjV4QHutxRli31S9FhuCcTWGLD48qugd53hzo0Q1NZ3xmrHG6AyLZNHiufCIr9BlBLqoEtpI6imegMohErB9L7J5K+Xwu0/h3LkcyGPdhGBEy13UOCDFj6sV4ZLoqHgKyUFn2L30/AwK6rU1cW5C5vxSjSjfOZaolBByKmIAKEce2htYhirtJ5hbiS+f+1Iv6dfB1W9Bp4fGsbXPfzhz1/EJVNqoIyMIMNjNqXuKsWQ1IVk+UMbmqcL8MXnY1DijApsLvZlT9sS+P5bH2yvraYSa2S5O/rwdNl+tF43DHybltMHyfvwcYsSzR4dg7vmjIcD7r3UUbWB/ZT30KEADxi77iY29gqC9MFrHH34LomTBUjpqMCc2mnUNWEtnlkTitp2iZD1SBX+Oz+KjWJ1+HeWEDZ9PAsmYpPBfd42epAhj1+8DSCwfhYL+rqi/s7HXOmux5/OzoGi+E6aN3RuXevmo+GxBWD1cyUET5FimbG7cfW1z7CyWgWzfjRyj0IMNDtpw4ccRfapXMXWw7XgzRUbEGu7xlI7HpDN2j5qF5oOkzKlaHGoALwJmsx3tzeS8NgJ9GPrGbhsMAtvyfWAp64Pg1HsELN7848QHVCXHYTyGdVYb1nEC83PwuFeQxQ6tgte2ouDq+Ne9Fm3C9tDDGB3fxq0ys9mu88NnOdymJbP3odTTbaTQpcjODuM4X6xW/zxgDBopmpx0yU/cJSRpd4/jeRmbAvP/d6ylcJScJ73lhJmWUJN/jCQXmZJs/M80fhEEFvXz4axz6Rh0wJvLJRaDTeqHeneKU9MNTMD/KKLoxL10e3AQXAYnIYxRRX41diGjm93BpuAFTBzVyVRmAFs+2vPN2ds4vI9V2Gr1SnqmleL19K7MD1Amha/UYfyrCyqSJQHB/UyTiqOQ9c5PbTePJ/PnDcERfepIJ7WTPo3H8On0ETUD1SHC6+2U/7wApp8sh803NfA3wxzurV+9tB9T+JnEbup+HojWKlOAbHSOVix6j8yjhIGCc+FJPZiJJ1M34Lf98bS4Ja9/FdQHdPQAvqTRPixoAJdVyunA//M+FvuU7p/tRXfbdaisKNutE69ji2/aYLvDWmuNZTFjZeM0Qb7UEnqELeKHwD9hBv8OPUTLLjSCVqqglCtVMZuwsbgk+iJl5XO4TvJYzjCRhi8r9bx3NW7+GnXafY8bQm/K8w4y+8jPfxSxaVB6qxibUiPzD9T2FMdWGBqS0Z7r0LNlxEAY1/St1VP+UD2MxCbJ4p1/oE8z2gNrY+OhrtTj2GwuBVuMjCFM4HW/CjpBPxUzYbre00wz28H+Cl9gbfNhfjC/AoJfx9OY74KwLgFNph2PxP0LkyBnquNlPN0Cqn+SWDJ30UsMpS9vHwXFYzSBYWtu+FT92myjVKBE+s/c46vLPRbVaD8sAUYGLuAp50cR+3vpkLehH+87XY2f8kU5/NpgWi3ZQQfM5qDOcVmYDjkFa6H3WihugqEf6yhsY90yd8fsMwgFlVGSJFZ20NUWbof/+w/gTOX/ILgIZYM9Gxi+2+2NPbaGnqv8Zxl2xG1PYZT573f2LvSn6UPi+NxHg7GZ71wVu1LXu4kzz6Jezjjix+EVm5i+8cn+JDcZZ645istSWB43kVYK+FJTecaaLJUF62sSqfXdUEcLBnCSY9yUMnMCgY/icBTeT1KMHqAXhssUHRJJ4bP0OCl5d40viEPg1JusdLxGPziNh7Mk5/hqjGPILAik5XW7MRcNzOaHGAMz08OQ+daUwSRvagXqwo5W1thUswT1tQJ4hHbJpDNlhTQrp4N8fVP2TBECT//mcIbm4xg7flDdENnGUbONIOPaMy9aZnwd+NtalWRwLNeAmSSmg+hq8YDCzqg/zkl1j4TyrGjfpHHSB0au/4hrfnQAg3930FLfT36GMvAxKeNcGq7Lm0U+glZNnmg9ciU3Sp+8utfDiBwXoW8rmrB6DW6YPz5PX64qMC31bbBkvpVNDLxHvzdNpWXPviM+pW3SW2VKBbcGAbLfm9Cs7cb0c0ilwo+r6eMjyLwI+UvzfDvopz5p3j5ZIbFCqpw0/cx9+eHwB3B5XhtrhcafqmC8rOpFHfZgn55HwWbU/vZ0ncMHM3VA++oHNo0VhK1TJZBpmY8zNlTxuKDYTQ89w0Ylq1BiUwDsLNTpezYfHZc7ELPnTpAprOCRg0bxa+KHODjr2HsL9bNixSUIOX3eZ7uPpI/CMngyVxJsh/8xAe7JsP2DaNAY9oE/k95P4zxHAk+e0o4NcUPR3mcpQubx/Hg3+sovn4umdx+AgLey3nf2yHP3TgGruUz3f14kwrD2mBGmSkPlo+AdQ6F7CTliBMLN4LMk82QZmcMT26Hw81WXf6WoQGuL0dTNW5g6VhNslr8mf3P+oGm4Dw6mC4NE+ANaeTc5hlm4+hgWAAFDfXT315fXikxhQYWfedW7UZavGoKlJ96Qtu2LsCRfvl0y8wIO5vFKDvyOz+wmEPrvr8hx+Q9POI/VXh83gFsZv2h5kvR9GV5BrvNCoPCtf4wcsUMjB05hS+O74DtU0zg0se3VO3+jYslF1Lh3JewtXENrqG3JLngNX/ZtQe2emmAh5Y2tHrO4tikKG4L20OP7zwhpWtpVO21EVofPMf/jonB589rSG7DRPh+YQZd1Yln77TNVPrqAu1aIYB3DB14V/dYdjcbgE/qn/nH2iGvNPXn0xEyNPdYJP0Jm0E+kwLhVpkaf7XQAAFYTacGKmH7xHEQ3O3LB58W4A47MTA3i+PNpmoYvu02l1dfguCtwdy6rRM6JBTg/bRKCmysgobrcXRKfi3vMrsN/aKqJLBBmtScw8CtYxbLxCuCQ0sbXVWfT+7nHg6x6G+8WbkQ/lOcC6mXOymkxA3k1trD9x+KoN52hm5Pn8syldPw7NQzoCoXhT4vq+DMkQ9DXJpMBdduQPo1UxBvewougZnwNaCZ9gwx0ekIAYhW3IqXFu/gIMlA+OFxlQ7UmkO77wX48WOQtntdxHdGKynyYRemlHfwwtdy+MPgG2g4/WLrTdOh64QMFmVEkaj0dT6r7gCzTs3gin+uVDURsKIvho4ZmUDvf7Ig+Swd7hw4wtOSW6H5yhF4KHOQd+Ypg8m7R+SXOAViNxP6jJ8A9xatxtzjOXA3h0D+5QUI2m8NJau2sMiRZljvn0qWSquxc+VIiIVU2HxpO5d6CqDQmot8/8kvtPnezpvMEcsz0+lgykLeGScAql+PcbzMajDWPMzv74VAe5swJj3bj1F73FnE/xs1DGVn9WiAPf2L0HlcBn3T8qJZ8sshxt0e9s+VpE0bhsNZwbW0MdWPLscbQs3L0+hzp4tuzxwkizUDQPkWlLNtBvrIVaJZ1iDYeq/msCYTqN6ihWUPz4LluziA+joamHKKJ9oeoYzdoWBY5Y0Dfpo8vFIbLnTFcru+AvruicPTV+6yg/5lrNb9SQXyS+lU6SNs3GUKGjFmINhYipFbTSjY15cOOzZwWcE7rnNSQJeNA3jubyJg3n5aEzAatNcLQ9EAkYraTTJKyYZbI1Oh+YAF+m8dR2el10GVvB/82KsIbr4j2G6RFRsXfMeWZDuyrfoIqwtekLNDHW4fml32xm5WXGQIfe9SefUrQ3ChOTzTyYZvN30jOfs1cNutCTurG+j2yh08R9YSLj5OQOFqU/6VY8EPfsriohkd0PNFi84b7uHLplWsUHMCpH004Vvq0J5Xl+Jmx89ccrcU9vt+A6kh9v5iNpccN3yFUdPlOHw1gzO+wMen8vDeOBMQKjrKV0SLMTNGHCsrUvnXz79kM+DBurNGQMtGB/w22RS2BGyhquzdEJ4pxJWXFvHNtGd0d70zBeq1oIGSELQlqaCY/GOIf2qOP5JMSPG+NC455wXfpW7g+pjD4BKzF1w2aMHmTfdhTnIVFmZn0IOBaqi6qYVLnilCiY0JLd00nlQMt8DTqQJg5naGV2g4UIGvJUlcO01ajt08Wnojiv1RQpfFUyjK+Swkj7KAk2uv0xONehw58QDvFY6kvmxHitLvhvb0s6AqeJXLbGbyo42SMOzhckjY8JVEmjyo++dVeD3VnN5/eUC5suqYVCQ1lJnz6XmeGKyOVqbelnI8LniO4tu76D/XqZzbpkmOD+5DUEQw++q/ov4yQzhqGkkL3XpR5d9YDjgrwjZlH9jByZImHcmib5NrwN1UhmMExKG/II1cPjrCm1gfSCvQRrd3DTQyZCT+2/mKX6xawMcG7/CH3yOh7K892ORsoBvtFSQuOh9j/kShyL9blEGfeNmL6SD49xldH0/gvt8BTJaVw4zo4ezP3qxpWMRhTi74ScGSlZ7mg+DItXjr4ET4UFoI0sb/QfeLO/B27XsYL9ILOlq7eVn2V1jlVYUPdipgVo00xO8b4L9Wiiz8+iXZa0xCj3su1OatyK2DXUMuPRIvPdPGg/N1wdZGny2vW6K2VwFdWr2dtff64NJDByj9pySO0LXna2Pmg99WBZjjV0xRJTdQTnQxFOqNYJxyF3HjNlwT5csRLQ/YuH4Gt30ZDbsKdchXOpX3WC1Gs6tC/DwxDXvSjsGL1sf4Qt0Vk47W0Xo/cai0FcN9Nd78MfgULne6TzorpDjQdzI8uboBytpj8ErEC5riIwIHto4A3xU2dORJDr1sqcUv57zB8PA/qnW9jHG+C+DdQ3fuM5sAEf/u0+qj+rTT8ih3lxSR1aYQXu6fgLIthyBjdif72jzgxxYGkNeTgGqTB0H3ugNbmjjB8932YNRpDOZNV3FHqDuuG3yA/SMkASJHwNjAJXj/zQacm3kN/v9W/akjBTin+j4cuGrNyg0nWWY4w4viu/Bo5xpOC5oM//QFSfRYKMzV8+Fnbx6xpu4Caj2zjX+kWwC/nMKnrb5jdMNOaE1LoU9PFamv9i+CQydeBk0kxy6K2WMI3z0F4PKehZD63ghCPxSz4Z/dZK8XQPEnluGqxHTWs/ei7Y+H8jSwlsM8TtOrnlFYluIM0/zL+eKbOvgi8QB0nbbR5jlreL7WMHg6MItLU/aCXuRlshOZwg9L97HslwfQsiQNl/kHkfwafdDomgT51oyxE+9TUaA2fR2ZwiEWvhzO9ewgFAP767bgNWVZUoxWgzzrRiz7vA87lNbSpOGT4YfAC2j78wjqx1ZAQdUENN54n78fmAInRsvRpxZ3uF49BQ9/mgDHQlXBt38yZezNhku/5bGwLoHUNJSgWUcI0l5H4eNjzVRZ04qXyhz5wp9GSJsuANaq92ly3QiQH5gAQpOloMRjJssWjafbhxSw6rUKKw7l64YPplBiKk7T8l5x4ljtoT4UZsvZl9l4hQQfD7hNdwsnstzC52Ry/Du0JHjxvWl6mKwiB75vJKg7NJUrx+dxSdQgTVW8ivsa2+DUA1N6uOQPxghfJukvo0CxWArcU1dwVIsUJ1wYIOMTnhz+U42EnBbzhjpVaD/DoDpsGmTfrsLFun8h4f4AC8FtqKEGPPvWGEK2DHH9y5WstdECS9pHwr6TAfQ06jwmpipyzI4icrEoxMTmq2x1axqI1j+DNenO9LZODeYPM4Kkj8dYpbmbXTLSKdxTD6yezMW6KTnQ9VSBs4P/0v1DRvBy12Ps7JPk0LEFPPdIHwp3/KH2y4moDUGgfHgDVk79Dn0VU0Fs30Uc9f0Q1Ty5iHZ2K9HrxyQcmHYcxyZ28qTkMViNuZh/ShPEDPuBzdXhln04vN19HlW/B7JlRRWfSomFqEV74X1KIFl1CcFFo0A62BeBboZi+CDzPNcfN4INoSfwzcA1FP89jfbfWDTkxvKw21WRQ4/G427HmZBX58oCF21wa7Mi573L56y9B/GrySG8v9YShmsN3ctb+nhjtS/evvaLD3vNxeMJyqRZXg3LJRWRfD2pYYhRlQWVyb9PHG6Gi9NBpTrSPSsC+iONIBFP86Xbe6ju61x4cY/h9sszaGx8C17KR2OgejhNWxsI63I94bpBHUyz7aBtRudx4y51UN+RTKOf5qHzRyEeL1IEG0bkwyx9ZbxhmwhtziNhy7dPFPR3InjlJ9NH01uo2jqI78OT6Czvx7CER+xjnUGT9h7AjKl/0KFADCbK30EVhQoy7BFgi/96sOA00UDQXjB1jEDXyFp4efotJRydDBUnB6AyfQeGLojlx2uPgEHzBTgs4sjD34jS9CgJqhbbS08bR0BxKdLO3Rnk5ZHGNQXHKS96K3wVbsDJbZY0+X0L2/ouxX2FwjBerhI29c/EZXMdcdL2lzyxKxaLGrLZg+/DyjPNqPbmJHp1ICRY3QQZl7VUcGU2Rk9+RXIHJEFmnDeMYEfyCQ/mn/ePQcZWXfgZKoQPg3+A3Ggz7FFeA+ITB2lkQws6T1oDMScvoF1qNU5Tl4AJ0lq8/QvBZ7PJNKCwiaWdH3P58AyQn7uNNe2U6NPCzbj/kQAEe23Ep4h4e1co/ur+TZ8lWjheMI0+iEwg9ztypK0XjMO+qoFWuxE/lIuDGV8Wkut8bZq0qx1WbPtJF4M+gaf8RErikdhxUguivE6A2rDNULz2Mt9NXsKi+Z209fJidD+5Cj8q5MIUURFaf1kFDjhXcIiQJU9aqseJN1PRPO8JqEpcRmvjVGyt/wH7BK5CwoA8nOyej4bOSTx47Df+GOLX/dZOlAvFdOShHI899BswbICu/x49xBuGVO6rQt1xTrAQfDBMtwlyFrzgJx6udEPDB3uTktEpQApmJfdjcP1ucPt0CpeNKcK6a3/4emobjTOuJ0FIpPHvV/DG4CmQ+L6MjLT+0d+Sc/w6og/Nt22kkxdMadPjZnoRtxjO9xrSz2ID6Ip/SL3PPpOFYhAahEbxJb2PNH+kH2ksuQQPTwXQ2uOrKXy5JXzrfMFFIb4kcPYPxh6vgFU5Tth/JJiz1Ippxm4JaFt+hzNdTGGpzmIOPFrLzblNtNQ8CcZvaSWN0h9UdEoIKiXyYdzdU5BoJAN5i6qgY9havmx1iz4sWYlLRQPAs0CPVAQO8qdIIWqI/Yym22Doi7biuAnhvGFrPgWdkUfnlYCtax9y1eePqLY3A99nRtC+wxbw7OAUfuemhos+LsRFQiOo0q4RMotEYNuDTIyXjGPpkOtY4DQMqg5t4vKx7ZSUZYStF+w5xvAXRJ514ukXM2Fm+0meIC7HS6aMBIknNlDabEp/j61E+2gH1Agcy2NTovHU+NdQkK6ALX/eU+lDRdjnPItazjTBaHsV9hE14/23Y1B4IA8MUpy4ZUQ8K34XgzUmo2FO/XCaIf+dp7xbyRI/ZFniYBL1j7KBqKOr8F5NPuRpr+MXHhowZfxMHEfyOCPant/YrudOh3sUWmfA84tNSLC0nGFzNrWsN4TLLyXZrtQdzgs1sfGtLazVfZzPZn/Dv9M9OCzqL4hJyqGLlCBovLUEw2ttMOHYbq67s5UyHd5zhEYF5F/rw7PXssj0qQfJrlaFp50/oKHNF3XMdenDJVuUXFRGWBaEsn/Hkt/rdBC3WMaTt4nC3vgOthi/C0yUhvrRppAOfnWneJU3vLUzHx5FnmGfNdkklGEBw0qP8O+vejBVaj3qHXiIYzyQL533wL0a3TBWcDIGZFeQQcZ4qFWrhdb4dzAlIIdublqEj0YJkElyBO9Sn0Y5ue24RW8L1MmJwtjWRqwvtQLBImn8o7GOI6R+0zmHHXik6BXWHX9B5w5fgHvr9KDW4zAu39jG2UcE8b+uozQyTwN3amiSgIEgXzgvw4+NEsguVBKuS8ZQp+thDFwoTuXlh0mqbRhXxKzH1W8FwLzzAFucLsP9VqNg5I0buN3pNC9ZHcpmxRY0zXMAFnxTZXuB5/zkUwIIxHRzd6EOZK95RL3/snHeDz1K6vkCEv+e08femTh9+nYSytpM+/4eYWfrydAUP5xPJsWj3J1/WCSQwjf2X0MXpVfo+foS9X0f4JpyX3QqlIQy41C0mv6L7xXfBv+OB5A3zBX+uc2EP/nXOWW2EF6VHQZOgQyjXSsg5uoYalKSxtVd4XxoIJMkjh6lySOnUs6m0KGesCbrmyPhVa8LbC9+QIZ+ojRK/zjvOy2E83OCIDJwM9dlTaXX3y/T6scy0DUvC7IzPbHU7i6FXb/InmHXcZHbaf6QpExXLyWBn6oGbPxmBqN71+A3/xLq85qKChlLaf6GAfwy3ZKqH43kLQciKKL4Fx5ZawoKX3L4fFsUXBKpg77lqxkTPtPH42cgz7WZZD+YYU2UMH6pVhnKvxKc93s0u685SMO/JrPOqHeovtWKXg1IgmikHYgcc0bXsqlDM0hCN7ErcHD6dQxves4Lba9Cm/dOKDVsBPEVU+H1kb+0+bYeTBjlhTlC/7C98D5pNdfA+HpN3vL+A8nNkmBXvZu0y6mfE84qw3GFpVRQJsGhrbV0a9ZFvKKlw2P6KuFY6Sb6dyICNQ58g4u2AKP6T/MGG0mY/SaZni+zgPCRvzmiNo5UIv5DZa8cdq/dxbZVUiDaLkUirwxpeYEoxHglUMkMTYxsmk07TpzF+ap+JKGfS3aiRqDi1ozvNiTyRe0A/n04hxzxM0777xjO81tEER6tELfeFsXDlcD+0VFuXj8O3xRfQs13y/nlrz/0cnoLLtTVgsPfs2nCI1WOiDD5/1s8MPZ4B+ZnLqWJ2q/R5UENhLcaUmu+Fz1KnscvWyZy3w4lMBZUAKG81zTHXZFnnwhm76tR/KDoN732j0ZVzUWwe/ooXNpjCFnqoSyycDjFZc2EtTpvWXBGOv+n85NnSqhRjvJ/NO2BDsW+nw6Ny1Tx7u+11KX5Au4HBcFv2c+Q2LudNfQCUC2wAa8KboKVkiJwUyKMnJOfU8i/KthRi5D+T5zrNVpor+I80npsi7d+u5PrZIKs40fRQ0IfNSLMacXScfwmU4m1zrWA2BUl/l58BVWDNOHTSxE4d+QQi9YL4YSkaJzmNxHWNL7EQw1N9FBBD66PLoTyz3touLk0fL+YwcGzD9HX7H4q6L4Hi3+Iwfif+3hvdDxv6lsPEktiUHSo304tiob28R1U7ZQH6/cqoN2386Cd3oTPlI/ht2+JeGiLGhVaG8HK2gfs7/QPJWKGU4x8CZ7K+chFz86w1o9BTFkWRdHbpDCsyxx2fmnmptfraIT5eo5eup5Qey4s232BcgW2Yr/AfL48dQKuuawD9XWFZHMoAieXTkWBC3WsO10L77fug+6QoygVM4o5MhpdgybBc6nnPP64PVzrKuYKsY8slvuHYqw8QTzQBHPG2eOOfUJwebYMlFbWYWjBdlhV5UnLhUZxf/taFBMQg1z5XeDmEM3C/6mwX7sRVHRo84ewu3QsXI+yPrngisdLwUYqiDxTTVDbOxnm/TJBmW4G3cgknrh3OGvHPqZrhzfx7c/T6MXcydwtYU3xCktgs0IM9GhrQEBzIp+xbeLH64dTsrcyFA6zphhpCbpQshfivPN40PAQHBdVhFwRE9j03BGKCleD7zdt8rE4jY8lEL5Mv4jtJ8Ro8PdpfFsuAglelhx2chuFBA9y/LStOLtpPPxdFwJBmWJ8Ntmdw45VQ6OTGAR5PWHlm90w9/1q/iL6gB962EJryhjSeZaGaTEasMsQkL6PhgmVCyD63nzyulXL518ps5v0TPbp7ccEre2cqetKKnMC6B1PgXNpQfxufDXnnzzIR3Kj6KqjODRLieMRz1TIf2GK3z0zsdbBGARu7GLzO94QkXuZx/2S5HWPFVFpVjCP2/UFE+zcYc4cX87Zpwc9xWmQJzIfbpaXY5pKAC+Jr8HB9An09VcSvAz5jyokT8DscXowXaiX2pdKc+Xxv6wSMoeKb2TirDRxbHkpirIaPRSreYP60qeD9+HZkHdmC0ySmISL5IfDhd2MngpJcH/HG5AUmMGbzQZQV9UUlsXeg0jfEH7tSShRJEp+kWr4+9wy9uw5jRuTvbBeIhadz02D+Lcf0FhEBZaLNLJo7y1eeHAe1NxeSwfHFHFr2zi+U/ERkod6a+brMFz3QB9DSraChWklrOyvgQX/9KllVQnorRPEAeV0bN2sBKP8ZkDGoz72nbOHB8bewfzXl7ldLAvpmAqcCgjlpY92UGCmDig8u4U/sgjPy3aBTcpU2D3ZEOcqA+/KrMZCN3su71JH7VQzOPbsNMDBM9z9DqBdajLs64uEZYWfMGtrBam/leIn8wKxT98Sjvr+I7XBtRQylVFGophX1FzhX/svYPR7LWwv+Ima+cVcM2wU7DjaQ26DrmAXdxkbNax4x2dZPP9MmqJHJYCLxAC+Xq7KH8Q1oX5LM2DEBJS0ncOPHmqhQ3g4dHT7UOLKeFx5qIqrP+zBEMPRIGqRwnuuHKLCpbLQb6oG+uX/sXaPATq4HeN+2wV8f340mtePBjXLvewYG8KOrQfoSqcErAp9gBU7pqFK27mh/tnGOqq2YGyuA/lLAv5H3Jn9A/V9b3wNIXNCZCykDwnJGJWiKCppkjKUShKpaFSiVBISoUKUORFKkkpUNInShIiUkGZKRT+/v+J7ce7OsF57r/U87+fmbCzX60P5uBK2iQqB36VB6KvcDL6xDihlf5J58yd8KmkypHFjcVj7Pzhi9Qu1onXZXKketJNPw9v2x5y48DD6Vm2hOgcteHRsJC3ROou+rx6hTcdX6vZKAolLwwHWh+O3sGXYHOECehemwt7OFyg1pIMt1xaSlmcUHzqVyNkPkjlp/Wy270zDy4bLaWqIHPxQM6DY7EG691SA7V7H0afQOIiInExW6Xnsl/UPhBu9eVcWws7usaxR+AkqGrbwAqMjGHT0KvuZO6Hu3i/UfnsnVymmYdgeOdBsvERNi2+T1GAsecSaoPLe4Tj71x5WejoFrZakYed7Pc51GuKNpnV0+oQ/lkWfoPIWWYwJ2EtfT5tjRZoUus2Q4v04idd6DvnKkWHoFhVOLzYeAvODrnS1aDiXfPlAJWPjeG58GBxUFOZ2p6lwOCMIHT8hYPBIFN0UN1SrBGj4CmFmtCiuXFeEFVeO0pknStAydQcmhYrSKbrHC46/B8szFmBaqEEFWa04J+YmTetfhY02Qxwm9Q/qFzdBpWQ3VG11JV+VGxiWUMifEj5yj10oavQSvmydCFb2Azjx9BbufXaRzq2ejad2f0KH/76RcvMnLHvjD89HHkDZ/CFeW9TF3yZY4Zm2OiwL20Qulrlc5XUaPv/0Z+PAPP578hXMvDAROiWLofrgLSocLotSk9+xr4Et7Zfcxn3/bmK/cR+9nKdFkz31YbrKA3DRX06VSXU0yVaJpkSK8Y6Xoajf20D1V8JJSDQFjyurwParalD+yhBqPENYUbSO8+b9Ias9vRw+3gFNR08B/9Igij0tDZYftkH7wn6aH3iZviTa4kTdfXi+Ig/3RqagVYYeJ7wSBNdmWfhjZgmT00eT8tZSVh/ygRMd23DtOxequ3mX55cLwbYhlh0TMQ46RvrwxY8qJP3jI5nlBuOpk7r00igYZr4Vo74LhqRW3sVpqwTgetBefhgmSZVtCfhNfwq03srHkIguCJvYi8Y+UzEx6SCMTJ4MlRMzqUf2Co148oamPn8LYxtX01bnuRweg9zW8wVkt4/Ew5+FYEOGFu+1H0c11pXs/qEdJbed5f96n/Huo4ZwN/wQLPpUh/sfmcAc4/lcmxLP7HgIdc9pc+ljHZp24gLevxEIlnFiOD9pAFJXmkL/lFI+9KSBs/YiaAo95Wm7fmN0riZvPVBKO0d+58Um+zGtUQPCQ5R4ZE4fX95iAs2NdrRQsx0aDmdy1sFCfv9yPdhsicGyIkOQ/VtOt/M7eMWu/5gz1+LYee28ZcZ4TPu3i6i+i68tOA+DETJQ8F8WXhSNg2uPonHdHjFUbKlDbVgMzh4BpM7A05UrUS5KChZSLAZV34Xbsnsg7D9HklQLAg1bB35aOZNCErWG6hoH+S3G0Dz7DKm9TqM3HwVAK9SILzbPponrkL6/ecADqxBnxk2h1TYakLPNhsOWTwcx5RWYMe0Lbs004OpgUXrb8QgSV+jD9c0dnOMuCjc+pMIolyuwQ8yWlz25Rc9GbEP9qlq+/nGQeu+ak8WqHxAnPAp0BLK4vDKbshOfkexbXRboLgYX92eYcSgESFQXd0+/zALnJeG5dDm/sd2I14yEaeSpu5jQVIJj0gFTNhbwzVVduDj2KVv1ikNJVSw37L+NduVP4NZzbey/NuStm/5jA8FePrfkBsrutwHPDYYQ5PWFh58e5BHfzDhUJ4yinbX5q0gg3z47n9TVV8DZlKOY46sORkLKcOewPvy3by96j7fiU/UquIOv0tPot+T+qp+Voo7w1Hg9+J2+jXp7DmK39xme6dtGe77sBzsFNTQ6dpe+RKbyLfkkLjxBAK7XefiPIti0xxEPXplEQna1HK4zguqbR8HESHn46rEHc44rg7/iTUwweEk+pjbwNMicLlR1UESWL10XEmXrnma+8NQDuwylYU5pA2TGyoNJQS0/DBDDia2CIPCuAZKbhGlFTgv70i1of6EOqyOm0qs6HV4XLIsRV4jiNQfYe9cG+FTqCjxbjpa8ecESyyxg82knFH0njXZFjvQ3Yj5YnW3g7//uk1+GNJ1cv5cKYzbD6/vq8PhyKAXnz8Vt23aixU9hrD1lwZmOzviNBuBO5WuKMbgAi0JHwbiRO+mJhwxeklKCxRKxfEh8CYYe0edMxclo9Q3ZbvJcbhAWhDvwg8bu6KCA29GkVeTLy0fKUaGrMLT5aIDq67O8wamJuiJNYGauC3jJu+KSlQkUUPYWn+rXcc1RGTA/f4dTEvVo/PAkvOihDQUBuhi2PAHrGwmWNAnw+qLtKJ2wlX2n7QGr5khYEnyHwzyHeCiomGZUvsLIoUz0Dayo6nwX9a035X/WHyleLZhdPziRZaAsaLtp8KUdp3nDGlMSTLHhMUNZJ021Guq5Fqqlr5PFqYn8y2Uq5BkXUEv9atp4JZaWqRykYx07oG7uL3I6ch+CM26CTmkBBcSZwkBVOln5fCGzPGegxDOsuKMTVGKr4VLicew6205bar5C9g8VWL/wGxvNH5qd/UMcIxaCWTOdOCzUlh2f+1Lplmn07fVH2uRpCnExKzn5lwacrznLDnCUt/sp8BRaiJLho1DoshonbP2NU4ONQX96AAWGLaFX8YEcrHqJB50Kec76+3xxoIcHYifi20POfGuDGSSkepD0lsksb50O4++lcbjHCDDTrqVzMYw3P5fjhs8OvMx0OpS9/Ad7Hjay/MXJXGlfxtMUrOFiuAvo9g0Hn50imDtcCr+2TofDIRO5YGcLXcnPwAiLe9CaeJFOTarg5yU7aY/9fJxBz+FrvgUYLJMh/U2l5KcZwVaftHhpoR8cyLCjBSV3qWK3HFyt7MNLqjrQ0RQKLaorMNaynNNednO2yll+YbGZFlo6UeHZ8aATuQg9/VRAPTGPv77/hHuEt4ON0GlapJ6Menol1ON3BYoaV4KhtxyLHh0LU6pXw+Qw4mW6F+DRZykqeH0RvNVkUWBpPz5ouMZ1Tgir30nB7B4zlgu4DrH7N+KZHH2AqhhYce0qHywHsOn7QDpDPLk/cCLEl+zE6uA46j4+C+IWTMdT/TmQLvaJbPTsuP+oBSS4OZD/HoDA+nEw1dIHl7ZPoYS4Ql5QdhlPRO+lj9Gr6fqlC6RTchziWQ6G9V8n69ZYOi1ymFobDqCIzyZcOkuRlCOv0qf8zRxj4kob146DJamVsPeqFxTEPaB5iUlY0T8GWh+nQvDdAZYtLqKV++5xQI4WHL6nj0K/33B5/VlUtEgEuPUe708f4KAaSaoYp0hH+2S58eMEWOLzkxtz99J+v+e85OpZyioqh9zKAcAZntgxxZ35/ScOFpwOH4ML8ctDf7wmIEH/aZrgvjILOu64nMalx0PdHXvaMioF94nLgpykO4c+uk3HFgfS3G8uQ7lViMVHDYepVsP5mcIKOL93JhruV4T+cSLgaBeH9vui6XiyO8dFTYTnQz7953IIX3sjQ55/w1HWSgUU4CJerRpg40WzYXTYSXjcs4S+Zf3loguR6J32gY5JvmKzzZNAt+0Zeuo8gakiifBu/i7Axl0ckHKS3F13oH1zC2gpC1PzfWFoiP6ODVU50JTWjiXqi0BnQJylm1zpP9l3kHY3BX0Gh3RCRQvCVC2o5uIEplMDvPWWLbfIHgSjj6nUMPst5MhtZ5G9VjRnsiI8uN9KQvYHKbjIA73sc2Biazl+JxfAhBnY8OcpPsrwwPsb1OFnfR5H6NhyU9ZtzJFIIdUsGV62VJQ0RMxQac5mELYv4u3+JjBh9Fb+JpNKyeXKFPvvCK1tLYKYbnHM3H0OXF6L4opuQY5aawxWec8ooOkpvt45lU/eeUhTxQi+a/bAtVcH+IzZSOg56wzn00zh2sFsTFt0kqKLMsC2RgqH5z7FVn9lDA/Zih8bn+PNj4m0zEoZfppo0wLJKXxPzRtjHvcjRj/ltVmqaLxDFidmGMNH7UC+56sHwg8zIGjwKoiczKSB9C72VermbUJr+OfKOjr+TJ1Gfi/CI6enwpokNVqwrg6khjR+V/NOmlhUzGJCRwDlDxClT6Qtlpf5u4wR2GvnsGd2BA27qQcxc06TnqQz2HxR5wvTm2Cmxgc+YXiIFay14eKZUDhs1Ee1Hk10rmM+pRS5QPgDVf5Vr4AN6bY8SvM1Jt4UABvvJyxSvZbeaY/GZ1/cQODzYWyqa8flirew9+x7tPTpBNPxUjB3VjCLGSzH1ye8WL3lI8mt3kez9z2DyhPVtFjSEpzFrnFh90Twj3ege7eG+n/HFrj4wIbMbaqp7qsWJfwRgNML5XCpqg4/9xeAy5LvcM4ea+q1nokWDX/4vEEifthzhO8dfYmnG6q47J4lNdQZwPsqaYyPnQd2Zu5sOq4c7hZaouelCNp7Rwa+pxfRuQmdeCJdDNau6MBRDj3kZ/aSRRITUTPkDMLCp2hs8YMffE+DxOHLYfMWTXjr04HfBz2hutkL7WpbYQJ/IUvpRqoOGM/ryh0wLECSAndKwFj3o9zzQgp39f7AxaOl0NJqLKvMzuJx+z6DJALJikjR3kBJeNohRCKVi8jRpYj3Js3mRb+WoJWJOe2abQsfok/jaLdreNVPEBRHfkOpjkVQ2enIOh4eUFPZDfnurviAZ0GhzDPscgsFyaH+Cy8LpfbJI+jHuwzCw3VUn/gBNBQyQH7eKjo3z55XjS3FJj+CP4tWgveJ4fQkRxpj9ewx3kKE4vdVYMeqMtCZa8QLA+t54SKCWO05HLFzF19Xu4fP+n6QwIpIXjnKgMautEHDzUpU3GYEeU+EYZFpIqje3AhXijeAQtcwNlNwwllVVqzlKQn0JZ3l/1tLQf/MwWPeHRJJM+O7hzxATa2bMr00aOf656xx8D2Fxu1DoYq1fPaiLIRJpTAeOU4r3N7zv23HoPrTPe57JIZVyul8bUgnlp1AyBeQgEXDl0BDxnYujkqGtc1/MM0xEcXHJ0Hc2md4QvwIan4+gIGVcuCsY8L5F/N5QvMtmHx3DVso5YFhcQVKrF4I7xYW0HCBDJxyVRbWLx9HRx/HwooLZ6BGu5AF/q2gDWYBYKL4jnN65rGrz28eUFcEzXFCLNQmRgEKH+j6sd082sKX7viFgEq3BtiPGNJb/QiYITQMHl+Px71fd6LaryiwTu5Hq9I/WHJIE0U36uGVrt80WlcfnkpJgOCXXPyggbB+gSPNj/CApc6W7An+KDtUi4yjMFYKbgC/j4Jgf9MfP+5cSetuOHGS8SkQ+XKU/oo/x/7QPxwL72i1uDvsSBIAAyiC2Z4luDzwK8uFFKLF/RQScSMO6vXDY0bd4BhWRfEDY2C+43yUb3OCPIFYLrM8SQMKumisIYmzMpfgAd0CbthTisG1ABOfFsPgjulQMHcWOPm6w8lXJ/CXbSWdTeinwY2HWdXyAZkMjgN3hVqwCzxIMjOAVMvVqFDJme6d1aBEZ01+3fMdNzyNxqRXmtD0bSnNnlqDIqcHSXjKUnoxeA9NfbwhV8kfddIPwuwzVRTbh+D1uBG1NBJIkyfihepqHrEulb5rvYboiGKs3uDFPzo9Wem1KUyvzwG1D25suWwx7VXMYnvHdr5/ZRsfeuuArx8k8K3Kl9z0UBv+4l4SPGDCGRGF0HfjCar+6+Q+qVXQmz6SlpRq4ZV9GXyrYyLcWV1NSx8Z04cGJRiluJB9El5xVpUMW7634a7yZyAlf5suNBvA1phAlt+kRKdHVFBvhCQtWtwNuR99OOd7Ho3RtubNw47iF88RsKlbFV/aeOGfgIds9COZ/MYlwWyFddzZmcvg2YKFvB4vRIlBjlE77nh9A+pF5qFfZBSNVVOFndahNEnFncvEL8H6H8b8OFUPIjVdqaroHOz99xxVY/Jw0sgcfPesilbkXYcpV7xhTscgTRqjAD3vG7C14gBGT1qGB8230RMrETgW9Ydm5ImCqOx4DP6bCxNMBUFUwIbPR6znHSUd6PjtDzy+ZgnT/j0FS8sKbMntBd0JhyHo8VhYdksHTq7PhiljAmnv1GJ6lCqJAWuc4MSzGpJIrKapN3t47EdNKJDZhU67erFzKEdYLKkiDeMual65FdNrtuGnH87w2nUcRD5BkPPpAiOHYhgntYvDVjhy7IEFbPpOCOqEfMA8UJnqRKOxq8gI5KOa2N1sFpQGiPJqnA6HNmwFW2UvvtnzGnVmlqJKYyKp1QGofPUmdZFyOD0uEh8+dqXoc8IcLjuM9T0rQC9zDBqXWLJl5XDwSEnkVfdFWHLXWnI+dwjzDB7g+SoR3FY1i5ec0YC86EEU/j0SCjb/ALEKM2retI1sR7lS1JLDuO7IArr5qgDzPERJYON/UHFrMhx44EWLf4bBQNhmPrdwI91eZUNHClfApeAJBN7TSUzoJV++LgwOD3TgxoFjHHHRjebeB/C078H3bqNgodtCsrmRioJtwL7mShC6agtEZBBMcxYnu64zNCr2Kuu0FQFs/Qs7dyvC9U5HOJ8sAoeaq+H5ic0UJE1gmDcVdy8ewxUif/GU5Cf++ugcJYtmw58zkjD1eSTLreuA2WK/QcwtmkxdZdCnr5gFtt6AXX9HsFHqMLy5TBtEYs/ig/IgPC5QS9PSbnP2HWfaJX0NJAyNWNZJmOM+hNO6FeNAoz+NE7fcY8H8Dtr57yWrx02GiYmSEBT8hz8Fj6eysSE8O30MvH+xDl1eq5C7fwLX19fhnUZt1tv4nbZJBUP1EgfMSz/PVVPkQLS0kXWOyLLT73j8/vIMzbgzgMFlr1BYYA0566pyZ9dNVO6aBndfJuNq4d2sVhlGkgX/0cbxxmzW9gIuNqjCnDNbYdCgh9sMBcE/Xx5X+P6l9vpeDKpIpwpTb+58m8w9Gl24PnoZteR1oLWpJMyYdAe3baxAzQV2vH/nMBjsCsGNERfgaeEwbkr8TGdSd7J4zBTQLg6D/6pCUE10JHwxKcST5pfwxqdyPD7gBVejZMh3+jR0CzGEU2VWtGSbBMG527DxnwyeTbyEk5Ys5CMKrXQvwYi9pu2GTlEL0NRJZpvuubDh1SwmdIKxNcIUGdzOg/s2wd3rY7jVOpaXmzCUtoxGhUeHoEbMHHKC3UjRoZGnfWqh2Nx19OrBVr7ECjRn+XDQDIlDw3XBBAk5NHJOKSZIAQxInYbkwd/8S+4ongs9ymH2OvDpXwztF7Qgn7JDXBJUyOMllLBy3GPQ9nDCJDc7MPVo47ntIqAQVsBhkqOoebIyPFq1A8IbjWB2vDls79hAhfY/uf/kFDxXMAXmbDxLM3b9A5GsbtgzpxaMpbLwXsoTHvephO69jcT7rVIYWa0MNp/eQPzrT/xIag2sPNXMvmWFbL7TFS8vs4EWhQF4ZnYKzrwdB7dmLWRV5ZOw2voGO4Y0oJClN0RaSeLZAGXuvfof5spYkWqULBQoH8THiZ7QH24HyoM/yKz0NJpIPKHk+IVD+bkL3gffwjEXxkHOukTe+9MTf2+0gsPDLsKVgRgcXqgODi9a+XdbCH2d0g7nl2jCtUQvvlH/gC5N+cHxI6+Bh85nlrpeAeEt32n3QwewvqoHB5xM4MrCfjr53Jy2npsNHz/Fk79rGw7EykPW2iScHywLa/X78KKMFHz+18oh5gchf9o10piaDoXy+7jp52Nce7YIqxyaaevbtay4VBwOuywhEb9U0r1iQJNWd4GBlA5Ldb5ljXXd/MBnBmZL36VMf2noGfMecnOlMaHpCN3bcxRXxRuxY3wATFnbw2H65jTBqZG3RWmAleYCEhh1DG6WT6Agb0tc2aSF55PVuOrxNLQbtMem059xdKk++Dx0waT9ErB2tRRl2NvghQWOeGjBFYqaWYUPb2/k0HMhKBE4DSrT55KeVxm9TaqjRe5u3LqyiRLvq+C4tcncLnuFdIIvUuoYHUjVVOL3k3LZZXQ+FjSXQvjWyQxKT3mgXh1vtgdAzepDxBo6YD1/Avila7FVah/IDgjyvPOvWUoik6Z87sfR4IVO4a6wxk4Vet/5YoB8DYcb3CG3Ydv57tYtOD7rLbjObeWc5eGwYPMoqvozCrjWHE0c/6J782c229ABS/fHs9GsazDh7mdo8fyBdSkNaCKHMBgyBRqC/+NrsqZ01M2aj7/+ACG/zaBT0ZKLCqLgrpk//7s8CWSH+5FdST6t0n+BSx+pgSvOxDUTziGv28TTU6aD2M8ulpo4FvLWisPR4NUEWRtgtU4f3bP+gmGnOsmmLphWrv7C91S1KEtKDd67BtFv1XwSqlxBSyWFIDPAg+uu+9O0Z5bg1WVOI7pz4N0vFdhwzwEOXPnO0p17ILJenWOXbuWoq1KgtDMX1f9aUmPZLrweIggrc8T413CCIM8zkC5+AyS3voctpu18TToYIESNxgTupLeTJKDB5xd0jl5BEzMJZSZvRMdQOb4ybitu/M8T98Sm0RqbRvijLAgfQ7/y6RfSIL24kW7OlBzKsJPRraUf19V/geq/bXz15mwYGCkPV2vkoDj4H3rv1wbzNfOxgWaz5ioZrN8fiZtHbIHCG768O9kYVqT+BVUJE3qW/5E3zZSgms7j5PYxjvDEHLr8fCbGaj1iIWFT2O+pDK9fKqCCbyvfMhzD6mor4eKa0SwVuQfkZ1SxgUI63nslB7GT5tKdnzcpN92FctPmQ0/VMw7xWo+J01LQteUc3M0IBd2kaeB+RpB2PVFHXfmRVCvizhPc7tDJjickkvOYi6Z95xe3pfGf1HQIeX6B82rO8YFLvjTe/S+ZzT1GAZonUUrkECZN1sUbP4TwnZIeLB9wZZnlj1Hs3ES6vvo2/ZTx5jfr/7KJuwm+fLaUO8zl4bLZVLDbvQLDZZI438aZ9r22h9aIHgj8mop5PrnU5lZLJTOC+SfLAYwQgN0el3Gz7SqMfrafs5aGIc0uhdByqyEfrOaznm+5+Z8hpDXU4eQ7wujV8guWOPtBepIlrPx7B9sOKsLIwt/gtKkLUgWlYMnUTkg9mE3OenncOs4PdwX0YveIEpAT70Tb/eNot9J7rP9lBu+Ckums+VJoOLIM97X5k+5YDfig6cPnPj/HDytekqdDHyY3KULIpieQdk6d1cMNyPyYGCidSqCnncfYrikEgnuH9nFJN0Y/lYSvwrsxetQ+PvZ1FgjMlUWVa7/JffFfclU3oUPCYTwx/BefyhYDW/UQlNxbD0vSanFXyxr8PayaoicLYP7TFrghWIZ9Tn4cZGgIld0z6fj6VEh+f4sNTrxiqYgf9LBIlM2sXSjc+RFnz8pltQIBeF48wJ5ObRTxRBy3THpJtybl43GR+/RmTzNpbK/CrR+XksWTKXBRSwCHCcsRb/2ORcPDefPHr3DvdD5GvL2HXp4CcM99CuzONAHv4xFQ8qYFCm4/wOy9gtDd6wKenrG8Yu1dNhKMhZqpc3jpMUMYFWwLf0Wb0N1WA5flr4aKQFXS3WuKd/+dwm0G/0jVfyHMfGkETy/u56+HO0DJTgc1hp+CIvvR/HuLJZ5dnkAODnuQJ3yjrgVqULq/EV0+XuY3553wutZiyLSK4ShdcV7cXwGJ6xPg33zCB0YGsOTJYlZepU1W7Zl0b/Mult3iSwqji3iZvCpY122g4xeUaEKSDHyBXgoJ2k9Z0YlUAA0YMSCJf3OH7hNZhE9/D4PUOjtyO2EIG7ojyPhmEsNsH5yyPpw9vc9xf/xjaLrWgj3rDemnwjE4ZD0d/Af6SFFVFjY8OUkrw7U485ESxrmXQ9tcASxPdYMnsxaRWI4orFlSDLv7zFlTcjPfj5SijqdAAUdKUPzyKnywbj+v2vqOD9lLgvrUDWD7qxilvKdxjqQrJGv7wpkSf+gRu0kB3zzYcUYJGzwaDTXzMqHu8DkysPlOa/dcgRsfuvnVu7G81EQYj1r+//9OHak6B8B0RzQ/EB8zpMNL2b/RnowOlcGc2EqQS/zC2+U2sYCPFGRrK8ONjTs4zigFFIZtAmlVXdRauJpGTCgl5zsVNLA5jkYKKGKN0TjQVneGq0+2osk/OVqw6zCPKn2IeyPmYOyElVD/Owhm1hNdH0/gbFLPY2um4ooEOVizDjgyvQ3KDWZTWUgKVIQYwIBxDd3dJQHfjlmwoedwNPx5HO1GvmPHEansaumGeUberMti8ND3OPIPYShddZFHFGRAmPYclKBHXDehC6LiljM2/IRblll0+b/zLPtIZkiH5FGG3wKVL8VbqrOgPEuZrkeZsmNdFAZuV8Yzxx6zeaIceK56TcKn12LK2TiQ13uIZa6/yfHLDFSrH8B17fKc8DGcs7sVQTD5GsasiuYLNY0gaysOqxp/gdHSQMaTF0lGTRUVBhfhrZsi4IYPyGr1KVxUO6RbQRYgW7acB9R3gLDUWLStvYYCe10pUnMEdGrngc2IRtxQO4LbM9K5ftpJtFouBMpbt4Pph/Mw1V+X2uIlQW1cEbBeKfTvyuB1+ob4ss2ap09xxb2WKRR14QZJZRWz1dpJsO78W3JLNaK1Dw6Qxf33jHmSnPEzDTuis3FjRycXlcjAKTFJuPPZCa82CqD98fEUUDOOP0aI4kedOJSYsoEG3yjSj6bvQxlUBX4YD3HibWmYqrKMx+YdQttuH3J8eh4n1wG5BdjR9eeytNNP8n92/m9eWzulbDnEhZ2RNCJyAJ/elyHB03dBxec+Za8soqDYRHRaxKDjEYVVErt5leloGvminS1d0nCV5Gs8MmIZzDuzn4fdW4afzqvAgSm2IFQUg/PuPeTW7b4QVLUdvjZXY5DaXMqvnA+Dx5wxjEShQKgARR1SaddndZg7D3nfMTNKuN+BFVFzUKV8PbxwSYVxJ2TBdsFJiGl/xI++zID1Xhac3TCK0+0fosfO2XRMsIL2Wk/GmGNjQPHIAk6cnoO7ZENRI8EDb1pHUb/PLBgncpQVDUw5gFeyd4YmZDgmUNU9XVb1VaL5TtYoWnQCInPtuBJesV6/P8840Qyaa4VAvmw91E/6haaVq2n07b14acx12O+lwi2n0+jWbjnIfZSIjyOmw2xDa5ju2455/8zp8eVgTDoazN47feDO2L/Ub/UdFjYHcq/mBLh4V5n3X/+NNtP1eVhRCe3sVYXDaz7igdx2NM93586JHbAnTQvMDovjC+kJpPtEjOpzDfHXbiN6YWLH4ban8WyuB2jhAy5qHgZzbGeyQlYjB+09T7UvFBFWWeGtdZbcNMWAdLSC+dLyxVS4cQJMr5OHmmHz6OiZG6z1TJtlTLZB58JCfltxk37+PYGVsX940oAEdOrrw7o/yzGy2RVOrutknW392K0kBTI2Mjy9fgE/3PuUBVykYePoKpzUrYtigcNZ/kQwZVIw2Zl8gNZft2j6GB8cXVXOMqM1ILXZj19+P4k3e3+ju+9FNP405DmWzryg9TCd6sni4xckqP6AAvj+/UAKuZsgqbuSjwicx80CM2FO0iYUfFSIh57K0obb0dxnOxo2fNxPfn+O8h/Z+zSqfxCd83PgptIB+M+sDxcFGuHN90vghpEo3LL4gMe/z8TGZCn61jgP9N9rQ/TI3zy2RJv3isbhmKRqsPGVgx2Kj9hN5iPP9buOoZdEKDZLCEImfuY9JzxosPwSTI8N5vQyWXhdMxHy0BwcxxvQfes2ODrmFVRrtsAeq7/U4VDNDyJmQtL5qbBfaTs2yavi4aoBXJ3/FZVkg8kkuINF19zjb3fncezLAyyqKQPCAs/JUymJ06UHaM85Y4wxHIWXz0RT6YsocLLywa079oLAKAso9WjFwrwi6uqIgpy45zT17j+cX/kO3JriUF3iBiyUtaSV9dpgIquFnkXtFCl8kadgOSv6aKCM4hYef3ouvv9vO1sOM2K3SAG4+G0UnhjpjDn7pOD5vkFYdkF3qN/3QeeRLjrSDOjos4qu2YhBvXQcJqaNJPmwn3R3cSu3jZ9Gld5FOCWqE+/6ddHm4DRYZSgKb8p/YPwZc9ihUQvbZU1A+7ANmJQtJ8X5W+D2Qmu6udyOp18wggyv03zphh46f1iB5oKhMDDgS3FWj+ho3B5o9i9GY0sRrjBXgRWHt/OjLSfBI3s399XexeKQOJIqlSbZTGMWObMXnXMu04xsAbh1+xumSLhwrdVunB8kSWUiShRhK02FqrLUtewsnbXr5Lvm5uBmuI78QvfxtTQneOn/l4r/OuHrzleweOc4+Kmmwmb6l0CzTgB+e08GFWFBCCBRsv+xk1zDN+FSdWWadqcW/3u0EqR9x/GP2hEwadk/DGm+A4Kza2nhSV1o2lKKVwft4aZkIggfMaDm1Isw9c8k2C7dSSpj4mhLXCreva+LDWO7UO61Na95eR2vJMbBsR8X0W6qPmxcuIAEJePp8boZrGEwDRUvpqK/5TEIyz3NaW9mwBqfzbjjnD44ecfT+EymgydceX2BBZvvP4LWApY85fJqfrQ9CLb1HMP9ymNgy8MHtELjJSRqz4PRwy6BwuJGjKMCXFTyBu5uy4Qwcy+SuC4H6vsEiCb1w4InbnR5M8Ni8Vt0MdQRRixaC0+3RWB211V4rj0VZlVepNZbIRRisIa1bfJIVOA+fO2ShSfiqni58CenfA8FtefD4GHQY6xYJ4Odl7xobeJpDl+ZB+uElVF1XBe0uMiQxRct9nw+ClazFL6Ie4c7fijC4db7HKYYAzaZ27BD3wluZXfz6KdSqOIxBsy2PoCA8JM0781D2rHvDGwqeAWkH0V/NpjRlz478AisR7UJo+Go4hA/tGbBIUchLL09laukrFFOSgq9Ryzhq7tcyHPSClQepQE7P+di778pIB+9g0rqTvAf12sk7BVG46TeknxOIBocEIOtqybBEU0VDF9cDGfCTCjgTwyHFESxvlgWqSsp4LTE0yjXl4tS+qNArIDgwgQvTCqLw/qbCuyU1MJRhRfQKWgGTtDZQBc85vCfVQbw9f0LKkNldF+sB48Cq2BxmzmEPH1OVmJlXLH5O6rnh8HXUwYwo/IwKY7/jLeSA9gvbBeuy05hU4mJ6GhrjvsqBfmz4HL+maEPt0d+oq/zfHlAooWOb94N6eU5PAM2crP+0BpKiYN7zW5aoKQKuwdeQMHJMxRb5YuBY8fQwruz0PXmKJzRUUHXDu+CH7V26PRaHzwVGvj3tBpqmCuDYyM/kObDTNhjIUmHTwnyMdtouCw4j2m/EATc6Cb3pFJaONsPP2hFwqDDTHh2aSk9FSToTMzEvU+/sV6cKBwRu4aZ9hthj/USOL9lPLqd1OHm7lBWuZTBDvK5JDRPlx7V6sCKx69R9J873t17F219R4NMUSIaPfTi2x/dYecGHb51sYGGTTKD2LrjtLpraOY1ZXBweAyNOCEGu6w1OM5am1R2P4fqD1F43UkQUmc/4wd5+Ty/9Dzrpc7m8Z4/8bFtMkQ5AqWm28JLWgpnNsuAtoE+e4y2Y/l9bmTT+A1nDeWuW/b78Mptou/NlQS/y1jTa+gbd9oxd8dCNhTcxtsyK3HMByH6YZWANTnLQLJXgJR+9sOXn1Mh//ZS2u5ykvY0rOMYk8dQ5h9P815b4WdBaTrcmss6hdMx74UAXFp/GTOsi3HeMWlQMD5Ee6eacqVMH29e6kDGNf9o9s6bcOuWOvjPq6QNnq/xrXktfzW9ywlVC/E86bP34FAvrBkFzQpytPLGVND6XQvdl1fBXIsbMFY/FleEROHRcwegbWktZF0+wKpSEpxIepCpPRHOPqrG9swQ2jtnDsj/tub+DlcwKu2DBt1cjvW4iV9GqoNP5lYuvJjCm68sBpWoX/Dyeg+qGQrQp97lJHIqHeVGTQfVDl3470gbrxERh3cau8G+KIVeGLlg+E8PmLPnMLe8nkDJtqXY1T4Z3O1rKGCZFHdEimOo1y1280qhqmUX4P2xizh1cy8KrtuEfW6i8KDKip+8nMlnrnVSafMtaFhRRI40Bf0qFdDKSAlfSoljtdIYiLwrge7BR1jsqgbXPJNFo+TnlNUTRw6mq/H98g5qlRpGNl3acNPuI/T0D4OwyEiQrhcCD4f/OMnsM/93zo5LDavZLmk2KoiawDQ048Fn52lr40kq+J7DhnM3gq6TAGwW/Ts0C5J0InkMHDujDM2JV/nP4vH4z+4ZVYt/ow9bjUFJcBz6egXD8byplO6VS4Pt/0HmlJ+obVONf4Ty+E6xIDsIFZP3nDlYvToSngYsAaPE3TBDfxyoDQuBB5mqOD/Gmn+bC4NO1gD5V+xg15hTPMquacizXUm1XQcOJJxF2fiPVP3WDjKGLrntMninwo7aLr1ms7Lr9OhKPX5+rgnjkuaB+ykF2LDYGT7N/0o2k25B4ol+zJBUghE/N8DAw0yOP2kGx66GQDgewlX2r7hfLgJsVs6lhuNpkLSlmnyfH6KYriuw8ct4iJC/CSH279g+Rohd9/3mgqgIPhxwCPyW2tAfl9fwtPcDykgOB9/4WYx16bC8WZdd0ybwsUQVDnqxFNcGfsfzFkXsabIBdonqguGENvq40h4jPPqhMliCXa5EUMr8VpqycgqqZIrwmzdFFLd9BJRXfObBBzY4fFYtttedB1CsopgbUrx+YB282mHH+Ztb4EfBJLj5Zxglml0Bv7XNOOG8ExprusBng1pWGeeDU08Jc1/qZD4VMwFMUjNw9vhyMFBcCiv+DK13hgHOva+NujLXaZrxBfS/rEz7ZQWBDf/BPomdsOqVE75ynQu7x2XjnCOzSO+DNuXOvAd18/VA6fAk2CEbhINjQ3Bx+lJQCV0AM5yzqXX7exB5WMA/Xrah18VoWJ8vA17bnOma4GQsFBFlzYFWnNZ2CQUWKJGbxF2wv/yCtK/Zk+Z+VSgxAG7390CXznS8ePoLydnPhWa9eMw1tMcCCS8OSzgDzvliICfRBmqmFugToomrPnyCpsx4Lr5wGkOtLlOArw2dckvh0vHTYdXzONCuNCNvCxV6pOuMOiPsoXnOf2Akmozr/YX5yaQ07t80CjQvTYGa6EWUn32Sel6V09nORDhslErNtiN5y959uGwoE4iUjIB8gb9UP0YaM+a+5rQj77BESZX+qlTBOJ8UeG+EMGupPpsU6oOfRDglHBSCGp1FtPDgGtAp6oUt7/oo+6wXhFYeg+C6GN5cwDDW4BkHfvpAnnt76frlblodvBZTP12luc2OfKfzAVWf389bBpUgxW0PdHstxivV9mB6YzZEvj7LsX4r+ZHlTi67WgivG8Zwju9Y+HymhMaW9KGVTh8lRbyAiNOLseRTGDU8SgPP0nt0RfgBvQkDSLgtxgY6/TD6aQofbHhOisn5LNNvCMkTazlr9BGoc/oJB3aPgtG/F4FvcCu55L9GM7+dbPrdjfJrXoPkx3aQoX200j8J60vGAgxT5JZWffz9dCbsCrXlnbCeDs8dxIWmW/mdwle0mTQDVC4pw51Xpzh0piwMerowrBoNsVLDsVr5Ai/deIc61/SDi+gN3pQ9FcgjAH6vnAimcbWQHz40z/o9nNOiStte5OBbvf9ou1QpCY1RgWSVK3R5xBN6dXQVv/UW4zEm+nAuRpkGv36kc9NqUOleDZ6LUQGFrQGofzWPpq3UgvcRB0npkA9tmdjK2aIz4PCFOviSt4ha1+nCsr5VaJAkwYMi2nD3MaD19BCQcluNrf6/IL9vFQXqaZGu4CiQHbGaQtNz6Lu8O65c0kHz0jZA1bTdECu2EgImrKGtlXPBZ+8Y2PzOAY1vRLJjUS9+rWrhHy0PyPh8NJS1XsAJqRPpxs0LrHdSDUId47mwMZb9utv42QJn6Blxk776fmax5W/AzvQxJfkLUE+qPFya5ccGKe0U9dQQn/R+5gZ1YezJnsiiW0oosGgjXaLhbHdAHcyqsyk7+RE8aZ6Aie4qtHFqBo1f0A6nEnvxnWUFnh5YT2NUpcF0YTSp5B+m+8oXMbviA8mOrcO3QTG4pnQp+Z13AS+3ULw0xGajK7JofNsH3KlnwEkK0fB97gU8N1wFckQvcI5WJlwTl2KTawJwIe8Gy8negaP/PlHC7yQciyJULvWCpjuqU5TmSvb8+hwvFAnBtYhenKW5my10l3BMtyYpVTpAVPkwaDUeywU/I7joqAv7DuUosftPyDC1HJZUjGZN/bV07PRwLrD7Awrh/zBFUB6W5xRBh4Uo5JXX8eXJL/Dj7Uq+7lsAsvUXoapj6D0NT+GZ/gY47D2ZUz0tQF3sOT5+FoHnq77DrG5jrJaYQweHDYDdxDbI3BWNi+Ia6MnnYXD8RAS3nv/Jz16epq7FFtD38RGon13DejWj8Lb+GmoX/QrFgcMgX3ksrSvcQ/7eOlBn9QY/PP+Phb+J4dLlxyj7pxklly3HfsdJ4Lt/NferhJD4eiWyHmLYNROcQHnPfY6VPka3JFz5/JA+YoMuJJbFQ8wsPzwePI8PHZsHFZ/eUOHjRAzOTIdFWpIUXuUNd/LUYL2HKCpFGZN/rTgt/HIfo0Pmg9GXaPLw6KU6x1541/YL90ULwMOXB3G4bQ9uSjPAN3FXqHGiHUZvkofK3mo4YV1N4ifyUXqfOJQ4TqIK+em8W+QNnplWCG9N5WiCkgyvaJbiuRuvceVxSxo+TBrEkqV4v3gdp/g7Ylo3gtslE97oYg43FlznwdWK6F56i9yPGkOxjS8K2nRyWZEuGBf7U63UJ3Q/8Red/rtCZ4vS+Fn+KliULA3i2MSb1uyjOc/vcN0YKUhKNcP7xW/RXNMS9qUcwtjxQ/1/TwKyhpjxiEEk/1jWxw8v5ZO/VgpZfZ6O88TP86vv9Vjz5zLbnTAHmbcvsdn2K4rtWYPXHPbCzdTjZJ32Aw7OjoCFFIr7R3nByDPjQdV7H3q5DaDHFRmcMOYGur/8zB5K2pywsJysT+5C7PXlh98UIXn2WwpWc6HGVDeukNXChRcO4b8bi3C3cAFfHXrGyGMUjPwwDeQHQnCZWwhN+52MZcWf4V6KH82Y3Et6gVcgVX0mW2n2wjlLNdDeeoZ6c/aDwu11kPBeABe+Qho/5BWT6kvwQ88UMhBR4zF+GjAhe4A3Pu0i1ZJNGLHyBcb4PIGDWb9YLMaATja9pkzJ62xxQwacU2PQceoXcnZcTM79hngZzrKMnjlorw8gMf1VsHblfnymIAmr1o3nisgDLJ88Ac5tKoWGr1Z8HE3g0pcbZBq2hqZrfMSGEl246nEA7sXX0PhN2pjdEoHKcqXc+WwA5m45AE2HczGk25HeTtKCxigbvJysjJt935F9qjNLOwvxbq9efGVjSjbParDv+BWMrTKGD5HVuFBMGA+JWrCa0R6eIjIGZyRt5xKvu3TfZQFqZ+fh5qkKMMGsGoY5GGKl83jMr6miRZWOsEwfIT3uNGgbS2OW4gl2my8AH+wj6Pq7fOSlwjjrrATfbDXivpHi5BhsSIYLurDnuhDHr58GpVcP08rMA+za4IIau0SoNvk4KYtNw9Q2Udg6PIfykhtJzEQZJKoOwP0HFVwZGM8t7sex6bc+BFv+YsWCKpQtXsIljgcpctAUdJ1/wMhiOU4JTuKHlRZ4cv8YFNa6AwufECwSvwS195N551QLEFBehoOT9KF6x2N2XXqGFMRCsVIiBTPfWWCQwnx4/mU+j3WdAIbqGyEuZyJO3jMDho/SpxPhLfgddpLeIwcONE6Gj1sX41M/Y0hbngqbN2Vwz+wVVKpmjKrWXnAqLwdiTg4HWykDCJND0PQyhtzdAiCZgfCiXZ4GCy2he2AUH+0bymUW1rghMoruPynkXlUpWHu+Ek2utHJzzXHq96zl7BHLePGcTfhloBQNxspixpVQOpCoBYWntMEiqIfz7H7CsXxt9jLfRq9Nj/Jc5zJ6X/uMi7aLUu/yUTC3VBk8Ry+h262H4ILQJWwpBVhrYEuzZgOvjc/i6KXuYPlKBWRiRCih0wotE16R268tvOX3DIjviKUp3ba4aNsDhrpa8KuRhc1OOdSoPgIVTU9wZksBvip3gwNRsZg7ph2LBz+jlu4hNn8rBmvFN/DNLBcMKGzHnfbFWBRoDVX/zLFl9n3o3nARPooLknOb6ZB/7MKit1e5Z4cUr5tpgW8GzrLZiG6a6q7Lf7NF0CD3BxYnTIef4WqkZ7EZk7b+IoVL0XxK9gW9+3wIOr3d8IqFHB/UmMipSiqAMiuGdKII5itpYen9Upj3axs3fbFg2PqYrcofs7L2OXIo0oDm+w2w+O1ddJUvwRSHQ9yTNw+H71hA0i65/LfwENSutcV7EyZC/QR/yM4Z4D0zDMFn8X6MOhRBo2s24KDmMH71SYZ+wgXwOm8O22cW0bp/kXjgaAikKq4ATftMdPz2hHuGOYITqOJLoxOsulMUOr8KgWZ1C6PLRqj0CyE1k1iq+XafRngO4LeyNjRR92LZuvEQbPKTNY7ogubJRpy+r3to3yQgbrMIfhZaym0+k7GhfQ6leEpAsXAudxstQMfqJMo5ns2VChmgtGgHbZ1hhCe/XMe0rH6Y1j8WLIa9xemp1Sh8fjGqt8zgnqLrXC3+ixq7BWmTqgucfK2MG/Yow9/bTfCLd/K6Q9tg5tnPOOu6Pia47wD5dCHiwtHcEaoIIYri8LEhCC/eieCllsWg+H01y53qJ79jZkjSSmg1rwOXBufAf2EIIz2y0TNriF+cdxPfskCHgkV0qSoddjq8wmfpzJUPrlLTPi1Y8zKaSiJ+ok+GO898UcC/3jvA+D0/eFS8Nwc6DTGo2xT2fgTg0HQGUj6Jk1H7Gba7FoSVz7px1CZVjl83Bf6zD6Tr+d6QfYehXVURE6Z78IlPheTWc4knmOqAx6RxUA4zeOO9SwAt19D5qjo0ND7C9Cve8HjHcT5UbMX3f0Xwt/GH4YjKTjTU3s5x63ehbY4CDCu9TFe9JSlhSxGHFAhScddzmq13B1IW3uWZ0o288VkQVa8SBKN/zbha4jNuLwtDo3uFkLY7gX9+ukETi5/QnsCrqPM5jJQnjQabWhPMVxHmgx4b8Ue4KhpvzwTbT59g+G4BzPD8CYvrvfFymQIcGj2LPlx1gmlHn5GQ+SDuUbvAd/e9waRFKRQuWM4KF46wwigt+OL2Hh7YCVFYTj5V3NiHepUOfONkGrQHzKI40w/Yf3wFyc8yBLfNm2l1zRLc2hnPUpcdwEM6glKdE/h5mgQO68iFkBnX4FGMPGy3cucHy83p2oFUHL3yLn+VvUy+sxfj2ANr6bVzEPci0987AI/MlMlYbQ2cnX+SFILW0aIbNlwlVksad+Lx9OdannLqFt5bqQcON1JB4E4Zuj6ogya15xDqH4r35+eQaWYt1b3IxkcV67lZ0hxCDLbjb9cIOPfCnqSiI3HjxbVcdvg9aae+Yb+G46SVrMd7HkuCtZgE2ykLsUHyBx7jsAsC479yUlccmO9x4SPHouG5bgA7zxWEZVYjcMSqDNyC0iB8xoi+netAhaLdVNH7D0LCT/D6Zztp1xwZwF3a9GfEKp47WojGuoaAe0oBVq91oJhlKbA6M4leNEbxnUljoUzjMg2Y7IK7phNQdfwqCi0tBcXIDyxR7sl5/W1grvEbileOhOWX1+No1UqaGBzKOQclqN0ogBZMy2bFaSOhT+MvzBILp9IsEVD48JILDD5C16IfHDs7EneYLQOlilaoehGP3SldvE/1JCQGScLEe4nozefgWtodNld8Dj9jDtNflhxijTzujFjEjeU/wUtED/ZtyKeIrJ+46VIxNn37yh72Y0hrrDVrGuTSpPUzuXj6HdBjfUixEweD9vN45Z4+Zk2QB89xC/FMtR771xDoDmlH7xZhkvDWhOJ9pzBpsjFxuDa+sbHAlgMzYYTKfXjl7Uw211yg4ZcABD4xhSTPPC57J45SppNoVN8SyOtM4BFLXVBh7SeKaiSUOxVOWQJjIW1pCqct/sHX5dxQ/7QT+kktpjYFRZZIE4LnbdXsLHqWam8Og/6aa2ARP5PeP/zFRSfM6PW5E9xUcoEUapaAV8Z78Pqoj00BErBItJ0XzEkDpzIvstT5hX196Txnti1GidmzcNwM9L/4GXebqMJJu9Ek6TCd56zdBl3fxNlnugvtm1fC3RLraWTGKxzha4Xxr8wh11aDrYaY7v8oOA+vEN82jl+jHSFtlVFRaWhqKQkRKioNs0gkhJQQQlRmRCEpfoUQlRaS0qKklCRkhVIoLUV6e/+D+zz3dX2/n895zrnnedtQxz5Dqo5fStWp+bjs3FmUTlCmn9l7+NQcI/C/J8jeTuKktS5yqKMjye5YLpbn/6CHP07gZaXFPMF8Au98qgkTtw0QqAKGeH1nBd2p3BYigVUy4/ha1yKKNHXl56J2dPqSJayccYKDCyNBf/Nj8NBogJR4R7waXUS+XjswONeewzaNoEEHHRAwtsKgo8FcW7iJPcxy8dPXo+DW9xqeelaj+pUhBjVVQdX7QjAv2Rgjp6XTDKWrtNXehpW0/+OC4c2w45EGvvRS5/aFqZhULwQee5BS1t6Cvujh4DTwB6faLODVVRPhpN5FOmjRh9k2V/C+oQ5cWDCLik63Y6SYPlQ/u08LYj5S+8g1eND9N+ZOr+OM5FMUoy0ClVtXQ7V+HkZY/8IVC0IhObsORU124/xrGdy71hDd9tvCdkNJ8P2+AO4tYxj76BiV3J6JMR9esK7aBMifnsc9x92w9Pl8aNQRAv9EO0rxbmHls3eoUjgdzsRb8HZZ4hGnH1NFwBguGONIVheVoSF8InS8/8NjFmThslAt0BLU4y6rm5ygsoxH5/2hjqe5YCY2BbSPK2PYpOlc15XB2uOMMF7/ClT93kybe2woZrgbdMZIYliNGiwZGT3E+I2YefwoxCXPQ9n5CeQ21B16o8/Sr9F/YAX8AQ8nBsPyg+ijOhc1n3RjzYhWqonZPOSlCLlj48ijMA2NJlaD1m4ryLL0J3/pVFzhdIUuS/Vygsw3DN5XDdJzrsO1n0VwpHo7lk03gGEpJ+hp3y2wtXSDzE4N3mjnRl8MVbAteh+Ynx+J53ZKokGOJHxrNuCsyjUQ+i4dr7WVQs9yXxJaaItrnUV5+JbFGGHynCP6TeHT0FxfzmmC3NLVnBq9k3IPmNIJCW18JuLIqa4v4fEnYXTLU4dPP8U4UKiCb6nvIgX3HEr6nYUPlLbw8UkvcXndGD7haAz5SlrQe2svrtwuit2HbKl3UiBOC/tKd0/X88sh9FLXt4ZmxbcY9hpBplWcBDX24t/yYog9dYeW7XCjXbJG+DvgFxWZfoO7zjm4vH8C9BYt5PMQQqJenTT13kmQvJSKznfywPvSKA72z4eFR0aRfr4KXKm9Rg2NX/l34AN+OnU8751dgs8NDuDkpnrsGNOETpddcK0jgfrYIaa4kg2RT79x69XFPCe4ncYfNoeaUYPUMJAIKWqpdOW4HNzN8ofdkUE8yt6eCuz/QvmpLuSms7AzbQtLhXjxrxNCbDp/JHxf04Ke9/bygyUHiK+I4wjfJzg2fDde1Q6gx9uuc0PLGly4Vw8WtmwDk/u/sDFqMjiNicHu/khanfGaT0wopqaGx3jFJwO1N42Bc0tsMLNNgU4uFwTpj8Y80+UiZX+8jip9jTzYPQJ/DCrjhw+CsPX0D7qgbUSXf1VwyQERPO3rSb/d/XC31Xqao53GpZnTwOCYImxJyMClezdzdiPjydQvdD72DpzrPo25g46U5DGTTh4dQS6D5pAnXYQSFQ9hZ50BWYZ1DrltAy/78JCsjy+CPWpevC7JH/c1iIHM8G4wm/uXDpv/wrI+A2oXJ8ytM+UNxnoQYHabRS7dJ2dShI5bp3j34ZcouuMlPbEeAKtXeyDmahALNKRhtFcCSaeM4spFCpCXaI3CdQPc6FaH7RMV8UFIEmxU/EhJBlv46Poy1BuYyG2rhOCqy0X4ciQN55z+SfNgOgpqJaB+wRE26rdCBfgB73SG87zJuvAOJ4L5Lnl8q+kOyi5XwWnOG3ye5wgZZ1robMU3cBaNpc1fx8KeAltwsJGgCAdvcl3cCVKDK+Do7WJUr1rJXrmpsMRhC8jJmoLnSANIX7oXfKZ1wPzQSj6iaA7S2yP5XOVEXramHYzejsQXRZrw37osEjXr5iUOBzBtVTOkllzAN5pF9ONvOtjNc+DJZgu5c9oUuD/mHeflzoFNPlfgeu4I2iRQgkYpZ1H8UgpfyxHFTLNv9HaVJNg+y4QzSzeg0BZf+JI5Gb6PnQ7+EiowtfwhTz33FW1GeYNshQGsGXmGbfxDaMXterIfZQL+MY14YXcVnAxeQaOPifGJpmNYctQY1qb4QOrWaA79U0AHpm9DbwtJ2rBtLqz98hZjuvrQLDUE4bguBHnEsb9XNH0RGAeLpE/g/PCbdDZGE9UidXml8zX87z9fiCuRgOuSogxxryFrsj5C4yiSmy3HbT9q4PK5oyg/5iP1Gm6C2G+m0BH0ivTmm/H34bdA+IUb75B7gGeVm+lDRC9svWjIH8Xfct4DhuEBIlDT8g4yZv8mpUvb+FLjSpaPsQS5I0l0PG8GaCQsJUdLJfjz5ALr7daCl96mnDPNjBfabMKAvN1Ya19FTrKSnCNnTz7eYyH+VxT7bwqjBdaZOFLiLjbvDOK8Ie/74BeDiYv+sY97GfZf0YC/i1djUEw+Zvw3NHt5qvi4KRUSU2ZikK0Uey5GKDjzm3LjzcBlpBzt9m/kqd8+UY5/PRvZzyCZ1xI0vo8Ydoyn0rn7sdTHHAoetKD/0kbY0LyYnlW+ZJE37vBo6l3SvBDM+0+PBjXlpSCRPhzOS8zmC0lO1Pp0HsXeisKjxqVY21gKx9/s4qDuiTzT1JxTarRg+/UikhY7hxW1/+H9+vM0TMUb+9WKKPDgXHy6eC7Lv3xG9+YqAX0/wM6CtnTt53iY7RSAjxIO4WbaQa7OcaS4Yci3znqA1lV1GO/9gWuK9El5oyyVh3Tjv6ocjrcShKUpOlwZrYb9Gz7z7KHvMun2PkrEn2BvrgwiC6exjCaikNxILAmzx7ubHuKV3SJ4R2gs6M3zx3EWoVA9JpTrFwyAvv8otIKvGHqrGVXzRpPLtLUweFURav9L4kHjWnRPbWCly0C/Je7h5e2ZmKd/nTZNi8XlR4thCY2H+S6OrJg8Fv3iI9i9eiMrqkvz7mnjeIrlAdYPKaacn+/w6BYlQPcMOqEuh/O6JsPrc40wWWUK+voeZg9zK27c6siO297Ayec6YPFlBIZmeEMRhfDJ5myyGuKluzWbubvckW6nLMfH60di7hcDGH86Cm+pPaMgLyf8ekoaL8aeZa+/Lfxtz0re+LQNE1c+Jg4cBruXLOalZ21oZFYnHXn2DgLPPcGt6c8xbMY5CG3Kpozly8luuQSMvlNB+1uS0PdiJ82feh0++x0D4YgSXvvFmPYV5HD6Fg8aHiQBfrnn8MihLbTUKhb23k5kuaWZEK78ALpWV3DF90oIlH9LjvnDoKvjCj7TjoNDkq/w/rRXtP6UJrX+Z43xrAjfxI1pxeMO8guZCgf6t1CUyDw6MsWavLau4bu9FaScoo+KP5RwrYYmzJ4viPVnNaFYZA8/WxWHuplx4Dc9l9qF72CHfBWUrj6Div/VwM2sY3Sr0Riu1H/mGtkrvF7BF9vmDKMgaWd4ryfGj+M+UXK/IgjG2aK+7Vhw3/OBU24K8qnvD+iBUx5pDirDr4tX+HHICEB/bSh1PwiD9uJwY5E9bFj9FcRmHoG5dTr4xMSeLn46Ql/eh9LlabfYVGAddl+TgsqVPmCbNocuvMmg+vxqcFwrxrUdxmQtv5s3t7RBjUUfH1JE+BmdDqdkz+DIlK3UWSHOqTq63BSpCKYp31n68ngyri1muZda0LBdj+3lHfCKsQW6NUlwd2IEJs5/hannvLDwlzvfuzMNJxXIgnNpFLeu9oc7ZpXkeMOcLFZr0OGE63wqbpBvfMiHZR7jYWr3GFjvuZcNVx3hjjVR/CT/N74Pv8EAL7lmK/Bah0TofJjFYTOE4ZCbKJ97aEbDrV7whEkHqDg1iJdrKbLnoAv9MbhGz5TqIeqKGczMi6Te6gZ2GBYPSfajoCu9gwKdd4GAhjEGNJdQ6YgXfLDbHMbbGdBlPxss2+cCsc8OgO3b43z7TS3/vbGI1mgdwg6/r2C3Vgu65Gvh6vBa8LFt4oEjb6m9fD/IyJvi5+os/BNZwNOd4mBRvDHITXgO4ndNyNy4nyTD2nC2cDiZDDfFBwI3KCPME6oXdsOwY2bwYrETFJ4V44LDdjD6ixK/HcrpnZl6ZKKYg5c85vOYCz7Q1q4AA9He/OloINjjRgq0vgfr6nfS3sW6uNnzAoRbHeTktzkg1ysBq/YNUFjlN5ostwU62k2xKVWfQsK3guL82SwjPQl3B3pxv6AUjPBJxmjdckpv2sejByejp9Z2Gr68E6Z513LirwUwdYcGqf8zhvUjlvLrteUg8HkhzMxwBo2xdfD3XRz5BDdixQx/qtf9xXcUhCFopTINtx3NbZEFuM3kNt3VfoIHM2fyKycpGNtTwzliI1G2TQncta5zYcJtNOobh+3LABsyNblN5Do/uaGI48YKkUG3FCmdN4WPeYFs5l1Ip2Y9wvP398D5Z/PAyaEcvgeL4i6tOSAXtQ9/5OvDPjEV6prXzsejBkDkZAsrWSXQnAgvTL20GX4VGEHtEWmacpJh9C8NPPJugLf8qIXJpX50z/4ZtofK41ynHmjxlCUZvXTaEaMNwdsd4LZVKgScTqB/Q7mfNz0A/n1r5e2bT+Me8duwQ+gLaw7ThCCJd/S8qIuS1+zCiSM1wMw6ABoDR0DJy2ieVx5PM1r+8fRUOZBw+U3fj+4l46/78cVOKzy72Zivbk3Amy2r4O6XIrgXKswHE4WgW12SYyp2QbhhKTZEXsWrz0fxyinisLr/Ilhcl4CiQgkQ/yoMuwzDofqnBHzMOoF5C6eC9hEZRpvzWH3Ni0+H1tLA3Qq41z8FnpzLha8x3jDzXROqCN2i2XdP4N5N48jhcwDYSevTn4uSdFFJGRwr71PL8+P8UX8qXFVdSAYra8Ft7XT6vikZp2rKQpNQC43pM4AwNWGeE7kex8cehrRfp6AzspEbx07EbvbjzQNjcdGEp7w8VBA2962FBYVO4FHcAd1uGqjz5gWONF/IT7Z8hQ/DQ/nHhGpu3zgRNrQ+xgOaUlikU0lUcpjf1iagqn06zpouQHF/1ChvylfaYzAZ1rxzxpIRElje2k9FWZNYK7mI2619YOLl32gZcgvubqiA+tMEOg332LhmOj/eeI1v1I5iyboD/GK2BAQG6HFlmzA9iq3HyEvSkLV5Fmm0G6K5wWEc9u4XbLpLpHnelw7PiIa9SrNZ7ssM1NorAVGCzRy+wJdH/zkHL16sgOGpUpCtaUtrM8+zX5gqJrbsheKxZlCl+Q+yU/diPX0jH1t1oEQ3TP4Sz9EzRnDQutlsrHGGBDZIwsnzQy6m+QAe2pRTso8ajQ/cOMTeTjxssT73NHjj3a5nCH6TwM8hBL4uMWPt/c3YE/kPvC2l4NoQl7yzSKdzuzopVtaWl0dNBZMrprCeJOje5ESYnPqN0p8Xk+kKUywYawt6t9upa9MHBgUDOODnxF/KNWFnaxy+DlYlmeI3WBlXjb7hK1HQ5yo/iY+lmXelYHR+PryrzqT960LZc20Y5xuspALRFHa9a0PPTvhxflQ4Cr2ygIebDfCx5FLQDnxIKlMjcSEdh6iDHlzTkMbX659gwdt9uNlnDNyIfs3xl+7hiWl5WHV5EfuoV/GP1h64X9gE7zf8GXK0FgypUwGBoB6eMsUcHOyIWjWK0GhOGRe1/UfTD+RSyvuX+EL/E0t6TgZr5UysOJ8PEVtFWdY0lJMtckB12WdYI/COX/RNgJ2fTkLlblOI79lEufUruP3XKhrmuByqwmMgRusKWK5PxPxdqXD17yQcSJGBrt4//CwxGFJF1uPR2sd4f1sCug859odLyTRWUBMSl74GLRFV6HK15Yu6Czly1w2+PteKDRW/kX7jA7wmrEpF5X/5qpkSx+lowsZu5nftBvjAknFJnCI8+FxMSr0VnHnjJw6c3chX/ETwWasVRDaPp31Rjaxz8CqF6hnwk28K1KerRgEHNvAVvslm+y7yiUgVGHN7GcxzaKea3L98+I4bG099g7o9gXx87W/M8ZpNs1y2ssY/bTj9rhR9lnoPsY0MPPbxBoE0UdTK3UkP/Bph1MUdKCtkjXoRKlAt+AQXHvjOavrt1PT5BT1wWAZFBmX0flIzdBpuIusnvmDuPg5EInpokbQ3Wg75wWPHUArZYUmBcmWYK7eGBkO3k9OmBRyyUwV0xW/w1fWxVF3sy3bGptCjUE6JPdXcs0CNfr9V5eXvHXD3UiXIOfePUg7ocYSsLEnq7udPTjK0ac1JbAqcyX6Gd8BlehMEH7cE7bIy8FvUwTHn7eCAkxcMutmCcclD6Cgahhb7XVix2ppWKIwAn+w02DZeE04X7YKVdfn8bLY1HtFHHiN+iPru/IcPNIyg4JsmbO1wgYr8M/zkWRVKfTNkVbdQ3GiuB/vqlvKzJwrktDiMJtiow7AuUXSr9ofz/zWgdEU2pXEc1K/J4Wfiupz5PY1iaw+TQ5koeIa0gdFLKbZ+eRsDbLUpe1IQPxy9CNIeekK32SP64yiHRhMloCN4PfprbCZ1iObB63qgXagJf8vTcJHxUXDVzqebBUg3MgGUGrRIqu4D6E6aT26Ja+nIpL+obrECd8nuZ6UpC7htsxk/PacMwQrXcPfeWpZJMMEYw0KQSwhFPd9lFOHait5V8rRVuBmjkyzgZ6UGfne1RE3Pibz2kgQ4J/wht3+eVPmhmvscfvPCl1W0IX4SHJ81EbT/7McFscqoOL0SsqTvkLHkE3g+tAfHZ6eD70RXvDxTGLpK5lPSDy/6cnc+hkcYQHZPL/pkVdDRyPUQc2wpR8d3kpqLFsSa7uJCu5VkHCkCdocV2PLdc46Pv0xLHcZwvvdMPN4iyl/ttGHFr1qcKt5EebJtbHAnGVdQH5F8O/aXH4V+IQGqCZmBch4SYNdRBQv7rdBWIAZKHy7joo+z0aryLW2LE4Y3++agemMTrEhThodna3FjVwl3G37BpUHS5G01h95sHY/vHzzHLd/n0ZbrWhRzRA2yXDfjiRGXwFI2DIQ+GWKW9m5eOPcJn/t4CnRnGLOq2R/qa5gAjT8XkfEPFzgY5wHT5Ayp4kEf/TjkB52vPTj6cApLOEjg6AAhmHJIjkVbb1LV3gxYPcsJ5CfUgezgF06/MJLilJ7h7vMhrBIqBZ5jHOms/1pUPXyK17Ekf1o3lXLDq+jhbTlo2RnG/8WGQV6DMLRIP6fLby9xp30NNrqO55Kzh0hkZSGbJUwgV7ehc+6VR5UQcZBf1MCJgRbUsewPjhEhVp7jzR1jfHDDsTWQ7fgbN0xw488aIlDk4Idpq/aQllc33+9fCbu7r7L9DRtcYz8Hu0TNKLz2KsV+tISGS//P4A1UfiQWjB2KKGpWP31coMpH52XBk8p1HBs8GrpjpkGe2UpsCTAihXAXiBN9C3TbGuTEDLDrSyPOG2AQGL4Sf1QpQ5NALnm4GEDXkbfgYlKIMUE7WCXNnXs/avDI4DVw7k82qo81gYkJO3Ch0GqKLPzJIww74HrtCcSIQQxIy+Cwvx0cN/gRk7Ybw9+HH7nS9jMfmr6aAs7msFuRJ/0ULaF/T5eg2LcqqjH+B66O4yFw9yt6m7KKNs76xbGa73GtwBvcVdJAA8LidELtIsDEkWDuSZA6WwyFlynBeZ90KDk5BmOnfWb3kwIw43AMXioaCzejb3Lw/9/MyQjHH7l/YX3FcH77VYSMV6TjwrIluPJPCrSMS+L2UdogtdcAJD+MhhkXZ4BL7SALsBT8q9Ih96eymDpuLK94WYSnvb1pzU1D2B66Aur2NPPA3iryDPzM2Sc2kVvADYjsqiUnE00oSS9nN71xEFzlC11mZjg39B8NrrrJ0qOGcbywNDmOm8kajiVQrCZGdoJWcDmnDnuTS1l/9QH2/hHAcdUdcGiVFMxZWkfunoEY/3A4rvssBFX/vYMDb9RZzC8Ll5yOozr/gzhZQY2yBj5QyihH2vlcCPPkjeH6xVhyehAJpU26LBFfRvbfNmNaihXXXhaHaSYnQEAkERYdGOrVQ494hqU6HPL/Qb86p8NIoVp4M+4SG76sJuWPkbgCBXn6Rkuw1/nNXSNXgu5APS37c4pW+DvTl8ZV6B1uxm4T77O9oTkXbVaDEabv6Z56H7iv/4aXnKbB1Ni9uL5WG0sqU/nNVW3+fOkAxzkrQ2d3Ak64akJh7cfRysuOncdL4pEVvaB51pc07XdifdQPsH4vB7GZodCpdIuPZcjz2DIjCJX0RI19TvRCQYjFZ3ThgmfqZFUpDLop2vxPa4BCDT7TAu2rtPWbIdycvp+uFypBwwMZmOP8D2ahIST0Xoc9fAGaD5vxxiG/aBUXoT0Zpui2XhY3Pr5HHtSGD/arg9yhuQB9p6Hfwx8yV3mCwMtO/tTXA0ec0jlGcBuIr/3Bg0my8N+yclbd14xGmhd4VOtHMNYXY90QI/4+ywXGColBlI4Nms1FmHKyiQJPqXKddS/MnJfCU4v+stXzj2w+xgJqjH6Q9eLHOO2jBLwbZUqC/ltwbJwRTPWv5xvu8+nbQwcKfpWJF/v64fBCIf7eJgmuqQ7cF5UHItsOcIuhNGRq13H76w+wfasDr5V4gR/VDOFUsR7c8x4GvuJpZLfsDZdX28Kmw6pgN2omTxA9Cql9XVAQUAUm94dD8fH5kDb3JN3fGwvv4xJonwZzclEGH3trwE2zrrH37SpaoT0OXp9qwLI1IZjo7AQ7vlZgyG55+J48Hb+8ukfGjwRodtVwaPMeBcsGVnP4hnwuy/SAU1ZGJKu/EHPDUhGuGLHlv++YdfwxTVdXhU3me/HNukLKPpPLHVekoeHjGR5pXoquL8JAT2cXFgYt5LdJujBH+QZssJhE8buU+JjnHA53GfJTu2t84v0TDE6VxMhzLhB1ajSs6o7lh1lJMGXXSh68dp9uSG7lZLsfeHTTLfQdNpp31zHVpAkAHTUbOosFHf0qjNvLlwO66VNp+iqSGW0PWpdfsMuGMhxzbAxozghFhXVT2DXeFSZGv4SE7ASWE/Kn1Usm8ZphW0BzwIRsz6vABZG9WH5eHYTr3sMImTyWubEE08+Vsf6SFWSTXY11va+h/rwJVDR607Xzc3hySyk+//v//+K+HDmhgcw1nElD5w2uffsG1I4pQMi2WWTRfQdzPkwAgaH8csv/gefbbNCzwonlZu1HmT1F9MJlHDzMFEaZZDfS7VlIfyujYY1jMgdkSABgMBpv/wWrFw/xYupICPcKhk83xtDUC87gcncM/doXSN8Eb4HlPUfqaTbD9c51PLhsDBwW/kBtPtvJ+sVltI4bRrf+mGGegCyp0AcY8fkA/nnxi0xTEDaKXaSaa0dgcYQutz/tZ3z7i3dQBLwteI8V2SK01mwb/lmsCMazZ8DGRUthlkkPaR/P4Yh1DwCPOcDGKa54rPoT/JsXgxnyihBb70+msp/41cPdbH7jJP84WY/a1zxwg7cU1Fbp8oZOI/ZYrAYr1vmwwjJXkPkZhGGBz8BYohlkI8fgS/EHtOBjF3496kPJvXJgKzaXajbtwRlbZ1K/Szt0mkujYWoRy1V7QJfgElp8tpf/jVKHnCQp2D5pyLF9Myg/LAYyQktwYIwsqsiJw0TJMGpwu4akD9Bu1wqzshGEIkdi36l8Jg0PUN26BHNXNmBrz3JetHgVdtYpQbzgC1I+nw7bJFNxSc4o8FlbjHc6D8O75Od4f9ce/jzcFStaCezy3XiOxCLYOKOZE4WP4zeXYsheWAZTOhLo5/nvMLXQGOek64HCb+CYmifohiIQpbaMvh7TwrExkfCh1oqybrnixv1L8VrQSFC8OgOOWMyGfXJbUH1zJd+aXo2lwq509lg96Nmlob//LoJ6XZCPH0WNRd5Q3R8Apqd9EdUWs4PUWnp+cA213u6Hae074PV5A+heWIWUrsomTmE0/ulrTjvwFS2ep2HT+9343GeAPdV2gVylAMw/WE3uxxpB+vIgDwq5sOjUGKLKdLz5NJGuhNygsGN9LLTCDEZ/8+dLvRcgI62SRbcdB3d04Sc+a8EyMpgdLlqRveV2EL6iCX0ef8nmgBTey8hEzbvruETLhB7tzaAn3s5Ycc0RPGXuU0i6AgQ5y9PXLd2gG/kfb1hrDQKjLFFFvRimH1bm+VdycOuxA/y7ZShfIgNpYL0mWOlpcrfrBxw9LZzK5SpJJXcXXpQRZ4VkBCkLeXi+eiOXzdhDB2aPRd81IXDB04buDq+GS1/kUXfFaI7RnoYOk41hzuAh2reS4ZCHHmjmzoADg97kft2cm9SWoKL2KfzrfQzwoSD0jGqm+MFIfpflhbpH3XGdoRHE5PhzUFww1zzSRvmZK2FRoQ6ImjTh95VbsP1iPg07cZt22xaif+oqGpTVQsuD4nhPZSeItiN4zxLh1tkKNEl/gBfmVuOWLQtga18Jqwbq8bJn+vjr1zY2n68BI1+e5+zx9vxw/hboPFTGIitqaYXAaPwq9QdHvH4Px8U6oHSEHISW55BxRzc+75IEVU8TVFZ4g2OM3FA+p4S/6c7GqjV69GyFIfjWd8H0uW6YVyuJn7WkcEnsfhLuLwQdiIbtmrKwVOAGjl2nDR6t/+H3ayO4+oY9rZJx5r5hQpj9xgqkNCbAf/1DvV2qAaIzRkOZthfP+GeNHwSW0byvp7DC9wKPH8jkj+157OZzmvdEZZKB/kTYsryBsvKb2O/pDr52SJZPKu/CiqvXwb5kDs8pDKMPT6VQwVETPun/oql75qGg5wkqarqPDUsOQ3lVBwhq/+LsKHsQvqNCci/0QEOmk75MmcO3G1rx4qGTsO7cJjJ67YeOBofI7HEGXvSZyv22miB6uZSCqZcu2L7nR8G2/FLhFj6VKcNio/10ajCXQq93cdUdTTA850GGR/dDc4Qa3E2sgkqvG3TnqjFdS9wLUY3e7Ht1LBzbM8SlJwT4qvFt8HtSyjKZlbj54GcqEI4kh/NKWNI0SFuG9t7uhQpsWPMeXNt0YF2uP7W7RXNkz3VIGG7M1UaKaGCTz/8ZfEb55bKQtvo4bRAOAIfUiRS9P5hfrT6NC7YkwcPvbfwkaR6/dljJTsOEwOuoCCbmaFBL+2Iuvt8CqysToebHCbquHMTW+zrgwbbZdKtPHn4XnuPbxh7subaLZpy5Dc56rqghpsMjV7diko8Ar4sLZB0ZIZjxqgZT0y/xMMHXvK/uJxWb9aDjtkSE0vk4fbEUyFcuwRHPx8AqIxkssvsNt1s92ODyU97wIB6891kSZS9Crb7XDDfSuW+Iwz68UgYb81/0q0oZQ1Tn09TdVhDtcIlTHI/RQf3VrB48iJK7BODdqgbOWlwGXjFPKfKoCP2RqeN7s+5Aap4zPrH3wW6Z5SxQIgBR+w9h4YQETN7dTGtOAuVkVPGtwkDSDTOiP+1KuPieDzyePxG2lqzgUgUT3Jf0G7/3nKNr0leoPaEQi42vQ8Y2d5Acmg+nYiWYej+RryW44/zwBnx7ZC9HXWonpSf+aHa0FqP0WumEVAQFZmrCib29GO6wCDdt34cheY1YZXmV56Y94JPT/GDM4xRS9rqBMzo14X1BEZeGC/LYKcNpxy5FOni1FxJPytHL4SL41iQOp0cbkoy1GnyhbWhwsp1lcqbgrfVttCNDka69lGW5vb3w2cIFxaZNpiXt8rAp7CK9/O2OYgr3aOZGK/QVDmTPKZosaerALf1/4aQs8h51MZim/ow+tTnAulFqrNAkzGuvzEZPHzkquqROuQGi4FDQiq/CLUFFzYX84R0v63Fkje9iuObUTcoTfs029gpgY1yJl5tPgW2jBMh+WgY9mx+S/8M0nrdgO/a+Os3RR3Uh5eIVnnwmCzv8DuA/R4DtZd50Jmc7P2oYR5ZDPd+RKMQJbja0f3IjftkZCWfuN1FmxhgQ970DX2YuAfPCqfDu6SbS9MwH3Y45OGBQiL0nqzhr7USunWgOs6dq4TjFeXRfcQG3znXg1ZPj6Zj2cqp/1ACnSxkuNz/kqDkMo77Ks1fhHnD7YgUSMrtZ71ELSa77ht2lI9En7BDea6uGU6floVVCAgw2p4MuTAHFyqHuibMkrYJ5/O3TP9ixxgtrxt6GX8YMFt6/oOTOKP52+wUbKt/C8VK78I9pLt44tREV3qxDqxmT8d4bbZgUe5nulM0DnT+pfN/6PSial2Dw2qts0FwLWVMDIVxBHjuL9GHjhOMgv1+RrCsqeGrfBD43txhDxH/iwYGXuP/bUVzxxZFGhcvAqGIdrEmshH+ru8Hf/BjHRTbCudJUinmlT3z/FE67e5gkXg2DFFwKmzc/ojFnN0M9nee0CE9Qd94CZx8NcmLIcrr7ZieHz0AQ+REC6tY/sPxwFAcfF+ezO4JwR/Z4St6zAwL6L+OI5c9QM18N6hu24d49ntS/yAV7D9/GjK6tEDVfCr+L9/PDyDdk+e4ju32UA9elBlj/9BVAbgdVdHRD55ZR2Nefyb5zBOFSaBaInm0gxZVCsH9xFXX9zMcds2UhuHgfR2Apb5eq4dtRK3GDVjNNGxXOs1YRjLM9jAWtr3hJdQKMlhoFHVsdOdgojF26HqBpZyUv/tqOhjnDYMSKQVJ7NBlDRynhypQOmu7/GGV9GmBxWQ28/rSSrhZ+B93ROlAVP5ykWn/hqdhO0HQ1BqcryzggTwf//071MmkDyi1qJf8qLYjtl+CTZQ/Q2N6Jh3034Y1zlaivZx9Hi5fC7uglWLTkCek81AGnumTwdi6GyasLqDBnDZmnimNNmSrr2FqQ8X+jQeCYNqUdVIRL/QvYkQI5bao8Cv5UoP3l0Vwp5IEcqgBXA39g9I5u9PgsAqr7MkHm9HswPV6DBuZ7eMmRHvwU8A50FzKIfJrPDp938r+jGtCzSQ94RCab9GbQ24ctsGiDPrRl2KKLhCsXqGyGqvxlkHtPBtQXDqOMU3L8WYpJfWc/iru3w7cnPrzq1EL8kTsDk5W2QUSmHBzcPsC7Bh6gSq49HpJdAXuTg+iY/EmKf/4fGXfqg0T8FbJdOxXk1tnjI8fjPGp4BXmN8MdVj2KotVeEKoKVMMQ2m+qeVKH6h5GQ79VB78oCYPfMR/C1tIxOTLmGH9Kn8MH2dWwn+o3iz+TBr4PC8CA9AYSdOtG3bzZtTzQA04EXIBslQFfHa8M1bRtKWfIGvNdZwJU5B1HIVxncbkZRWbQ9lM8eSX+ir8AWj3JI+Taaze9+5gW5AKmzF4D5x/NU7RaAYeI6sN3+Fh2YL43Fe5vRynQdvd2cAPjEDPZmNJLCjC7q0oqjo7wVbfbZ8eVTR3G2VTalp6yiyet9oWj3GMC4AKrxdESRxYYYHKRIr8SCWfVsNlpZvEMD8dN09fgZmDxmPCQO+PI0Y3eOPzTAXucvwPkPC0H3TwCd/x0Nv4LWwoEpJnw7azIcN/vEBVPiUVbmFnv75mFEwCQUexfANmIRfPvFDrqe9Rcab+mDp+ZeXHWkH201jfnZaweYJOQHmw0H2XKCOp79fYifVz/hJKGpkDulHRT/GHH5MCHekfQSb2Vo0YYfhXT5wg563pILd1OKqfgWgejIs4Azs7jn3wK6cHoiu6d8h8rWZA5/GYnlq3Ig9GkB/HilCp8OD7naQjt4KlfNKtE9HFAO1K/yjovK10O+3SEUmqgI14aPhL/h01jn4E7ujWiESW2P+Nm+Qgp+8hYEZ+nQX719KNDhDEoHCe7qDDmZyFW+ce4CncvSpLPJStQ/cReFbjMA+3plmBd3ggebjeGAUDi91SmmT7saeUuyDtu0fkR/LQ3IDouClyLPYM01CfQ0mAw3pR0h4vAofHjgKbz3rmPs8OI9H+bTIXjGD3VfUdBJRV73eCLYlm0AM4U+MlaVhCOiz/mk2x/OMmmCKj11DPE7xr//uwH7p04CsF1CWwJyaObP0/A74jpCzGLKGHeXNzwypDWHV6HOkk9YVqcKC8p28JYZnuSZpg8LNN/TU4UzEJqlikXu7WhKYTAq9gxX1SrCIr9//OiNJPbfaeH1HfexL1gDk3+/pKhxp/FfoQS8lVgACjwNjATrYF9BGA5WB0P0hZMUrDSVrg1OwICYRBxpuZkVDrSwt6MceL6PZ+uDVvRydz2J6P3DNt1y+qHjD6HvzkDEtB2oah1PrslTwGB1Czg7OKP7bSEUO1fIh1wbOehlMn0/4069dgHUEnUQH79TAK2XrSgb/Rel7iziBUovueSMEBVe62ajJQYkqkNk7drDOW3isPhxBRRIFcCSw35k0yONHzeq4YzkDqpcOBO9HzyAt+YHyclbAU5YfgfXccZ4K+49/K5Mwovj73HFGS2u2vMPFgbPp/evY6HUUQEmLnkFhdYe8LiknHPSe0FwzH2QUL2PcnamzLZmpDOyBBMNBWFU/mh4WLoPL94bzeMjYkl5fyi6PHbFa2JLOfDnc7x9RQRu95lA94khDv2XDV0x/dD7woQuPlGl2xKLYbazLyifVsczPsPIzUMVHqgL83yygCNi6tgs6g3/hFxZf9UuvJRWxY/OL0L9F9vAaZI6mE62RYnkdFCjDvzZeJnbOzPg3TpRrthnDcceNYPP31SaWDsMrtyqh1WzkuinvBMp5HvQmddBeCjjPe3c7gw2MbZ4NGQWHX2oCUb6j2hPmD3Gl7wGb8kAXurjC01D2ZC+8w2bdAbhvHplshwxFa5ElqBgYQFKjRxFFsNX40bnSeyR+hxN9eZAhs/lIX/cjL5+UiAS3gzrQw5DXuky9tWWwdaPp8nYxAzNftST5tEPWHPWlKd8HA9dfpvIrlEX9nqX02GZH2z2CnH91QyaFaPAIleb4eCHJHi2VhBuSG6n6baN2HU0EvVlq9GlzRpjnSJAvboCFrEhy4eNZWkDC0g6ps/3BC+wxDZL7FT045IppjB+RRArSwjQuHdfYfGlz9gxkyHo9T9qOFvMfoqaLGy+Ho61arLC+IP0+G02yUk4oZXDPwxfqASRtQXss+c3rVuvxPvm6GCmQCrss0yBH7SKiyqboGHLT95zSwK8ntrAhzAXSvMIZbFsa8rcrsMtAqu40/Y5zfEuBpNIJc6qMYOCaWYg/OgGRMbbUl2EO9a1naFl47Sx0uIk7+oRo1cak1iz0giydy7EY5V1/Ol5KO0zcOOsCn8IkfxLbxLLWa9yLx2Zaor3PglCqd8DiDG/RIVuX0Fk9WP8PHcdfT1uQqK3m+BagzSYdUnzJwcVKNZJY/uZJSgd/5iXqrTRyqUX6XHmCjYV1aPTfJNOt++iuc4W4DnXitZPSYfX6XvRue0z1HeawcpbGZzy3yFQct8En145wVgxXbCrK6T3un4cPnI+X5QSBLtgfy4dYrTZf0P4bJomvlmyifVX6EGGaiEq3bsHKaOicPXHKlySSDAsZDJ3rfKjz7e34xHr0zwvUBv0rX1ouOU2/jW/CWfWNEKSjjPnOY+j5rlr6HXrefiWOAE+P1eE/apFGD29khMfKTOFdPG+4dVUfsmPxR4r8MMzu1C3awqszZ8Ab7JaKO+4KcjamuDH/Rt4tkwKR7geBcvDarydWrFZoxRWBWlAYsI6DLm5j6t2VTI/2oidASfQ8Yw+3P2yGTdJDJDiHB1WTZsIF0cr8YglaWA5u5snrRjPvS/z4YtAOQTe1cJV9ndww3Qr2JttAHM8mznmtQWj7Ec0unyZ87yP87vv9VC72oLmNXpQ3clN+DhcCjTm9oGLczwdalTlWZIL+dmhW/ilsQxbRBfT5PRnoK/tDoHKapDzfhxHG2jirCOtZJF+Ck9UWVPfiV1QlpRI45qF+GDiABgNGsH6T+Z8tuk4R7xxId1Trpj96ShpT5+Jo1eIsMzTEBKXKMIZ8xTgm0Er3JjkBYJLB/G/QBV6mi4ArwJysLl6OZ6REsHYDX34PkoS/Ew+onnIHbarNaeg00N3qakMP69no8ClgKG7DeCXpeNgdgGB1sAQb8fGc0/iRoh884Z7OnRg3IJ22K+TQpldonh03378VjkesqMlIUoxEtW2WdCNa2vp95lg8k5J4Y165hRV/Bf8R5Vw8iUAWYNSXjUynE7VLuALzvUgr7sInZdb4ISbzXjTPIF1Zs6l6bWqYDPggW4bUtg24zms8R4Ey8BBjAzXhyMy1Xz+mQaoFRrS8nPi4HSzD3Ua/KE8SpvL18fS2yJpmjjCATbOGIHCH+Xh2Zzn8Pf+eNDo+QRpfpV0Wb+bUjbupHgtgIEnldQdfpVfbVoHYj2eWBAzFjo+TSeHG85QtOsSDP/eCifF/kFZ4W9uFRUk0SkysM/vDAxLGgfj/wSwx10ZOOgQiHrd9nDh6nW60ZRAnou10OjoGCqzOQcfBbUgaWhPTm8d5KVbP9OnFYdxTdk5zEi3wZqcRXi90BJtZolQ2xFRkDz5A62nLYf0GTKocb6UxVJHcPyU6XRh3woqTvvJ/HAdLwmdALJPzvD7vCr+4+zKMxePZ+NhGZy1UYh8j7bRg2vT+a5oBZRIqYGIpTBVu1ziJx1GfF/3B3/y6IDaETZoPHYlTEr9ik9ixvCMuPGwZbYQjkqUpwnnf2P0xgb8vMwOcwPms6RiFC7Z9ItLG7/Qi1njwfnBX5A2z0dBOVHceWIiH3p3g4ojG2nVSGdycMnnC9IvUKzPCE5tTaKxv6Mouf4JPslKpEzBapBp3gwHDhZw6cwF+DL4K/s9VoJXE1fTlguHQPjXIt4waTYOxm6EB8vCSLxnHhe2CUO5iRqGKMiC0uup/En1MdxZ4knlXZdB/nEveRm8ILXD79nOaSTrfNsE96ulYO7kybTNSgVAYg1utLiHitvfw6oLQy4gV0Z95/7xdEt/lh1nCvFXStE5+gE3l7WT6+urPDEll+fJAji3jwaLbX2ssmA74rVpoH1aDY1GnIU1JyugNuIsnvfIxrrNP3jvzdX4w3kbvDz7mDyrJOHgblWKnVAAn4XaWOSsL57Vncn3Em+x18X/IPxrJn56eI+kpMfB+g+qYKa1E+ZvsifplDese6YJxN+9p5k5YmiYXc8qEeLwcCnBHfsyqKlbR5NkHnFa02Fyiewnw3w/SAocyns4xQphLWDcowQbRzBZXp+M0ncN6PC9bEqJiGTRmYtx4SRBXLxrAiRIL8KHVWNh98p7xEH9kOFQwKN/veCB1T08puMLbbh0ivIu6aDo1iU420UeXth8o0ZFWUzaUoLnXiHcPZPF4UEG9FtNGwpK5+DAxgOQ6KoHsaeuY+j9YrocYQIBz0X45xh11Cg5xP8OBlHyTCM88vw6vb04EQ7mPKcj54LoVbYuWrlNwWcXHDgbr4OD2kT2aonAxAmxlOArC1dahvGtA7LwI0KTDd3/YWeaOeQHyZLBcmdIKLqDGSKTYFyKCKxdpUUH/FWh78wy9n89Fyfd86Cc88pYc3c49uk0clxfN939rgRu0vrodCATpC9MwUKLMpx6OQL37LtCj/p64MWicRAuFAQLtiFMiySaOTEKZQZucoJ0JTrueEWFauU8vXE+ZyiPpcj42xA53BKM0xL5mzGRZWU5bi2xBtF5leRUlA4p3qs5OCGKQ7dMo72JlhCxsAB/L9nKxWr36fSd71TvaQUfWzzIzKmBI+Y64B6REzBMehjMadtA7+8ak5NcFa55OBk7Fwbzu3nH+N8beSBZa1xbaw57rkvBCZUYWGX0E5i1qErVkg699aLq499x19webtjmQaaHRvGILTqwJuc+2QWbgJTmFZYa2YB2yZNAU9SSLf0UUUs6AXTT7Dg4Zyo8G6FJMwqtUfm6KMq1boOoS+uw+/MHCrISwxh3G7o/sx3MJbShzEUI6ie/BXH3fq57ZMsqBsOhtcsdU29NZY0fAfT6WA09PiANWY+vcKFCAZjUBdKQc7Cy+2nMSfQgtSEn+L06CW23inHkl2ngeE2Zp1gng+yVJKxuriUNUQvKlbenU8Wp3Cnyi+9lReO7+fIgoGFO8oJC+CqpHqUT/uNdP1Vxzk43prfHIOX1Ozzpd5Ie/zceZE11Mf95OHpFi5PzDUa5zaehyPYj59/fgxuPfEHTQWuskh0He6YEsWFaHT9rsofFRnNI3WEpOF86SIvGxWFdtSgZ2TfjIh2AGYU7oSDkKewSyIOVpx9S5rMxME/+Nh4/94q/ynzgnuR59M52FPx7MhmmLWumF9Ei3BJ2gTflyVHiETHa/9KO122fR66f1uPuSaNgnkoidpav41erO3mL4H/87IwYVB0Txh2KPxGfVuDPDx20xkMYZD/FcOQ8H9jjnQEm8hNo/eaX3KSiTnWBCmzu0Igb+ppow9dpULzjNd/xb8PdIiJw+utGeNWQTkLjs3F9aCSHtmdBtY4rZ+UagvM4bToXpM9f3s/F3uVrsTvBELa6TyF3WRc4WJnIek+GcfcoSfC+IMit1cThSaUQ+fQmGpea0cScFdQ/ogNm5b0Gmfu9VCopDElay/mMchlenqVK9zpzwGvyBCitnYOy/27C8P3ToGu8EWkMzYvn12+4e1YQXpixF776aNPJmO+05UEvmK4azkLrEP999sKO/0bD40m1UJgnxVHXduA7PTOoCLAj8747pGCwDX1ndmFVxVpeNdYCHIcZUGWyDq5ssSQXLSd2Eo8GUbFZeH79S4wxaKCtGfp0pUUWLhhk8/tbZmRp/og8tqmR2/ypWHw5ABPy5uJxFORxFS9oRrQWKLgp8lELPYT033hz5GpeGnqZhFQe8NJbfbRs2W202VUAi2wMYPndNmwv7uKDIYtJRfgTq78/Sdbjennb+EK60DIIh+cLgcALAM3pbpQ99jWUXSrjA8d+4FFPTxLQyKC9wfehaMyQ775fQsO81OByvgR3OccjKrvi0kOfWHPXJZp78y3OWmHPRdfsUVpjE5wfgVC+bTsbJL9Fz6dHQC7pKJodUSb3id9gn9okOlJzHHy69OCpOINkoxAGDf5Hx477sonQB0yxPAulsb+5ayAHTrwJo8qaR5TJY6HHqxf1btlibVk63fb+Aebm82icZBz3f5eGY8ou6H3vN9X2WkHBmgc0J3cqtQ1+AYtZbXg+5A4e37ASIsoL4NHavfxw9moQWjIZxu5+weXvlPBnVwitGL8Iuoby2v6kF9fu98X5hZ+xUjyJg7NFwCpdBGxPmZFo/VV6fS8Itoh48E0hO8pdEwzj5VfBh7++oOo6EVTCQvjfjl4+uaEaTzZMgpfNAZxUn40yb/y4f5kP2/f/pNmgCecLYmmWwlocLabCHqPzwNsWMaBgIb7S3Y2bbkrgxj/xsHSdOihtsITEmgk0u+wr6fXqkoSOGxx8UY5jfv1huw1X0evRGO5XN4UKrZ1E8cJUEneIPw5Y8IK6JKixP0yv27dh8qFYyl/TQzvXi4Pqh5U0ftpOeq6VBptTx9EjI02MXt6AT9fU4ok308iv+AaNCJwA91XKcfH7G7zt/jIO/ecHtq32vHGKH8Q3daJqkDC6rjiLnz+PgYkPfHBvjRiOz1jHbZrVFK4RCmeLk1glZgd5X0qAR59iaeQaUxDfJQ3Z7n/pjFUcFf8q4FyDemoPacRvcsFwtSYcrJZ64gUe8gqRVs5QvQlHH66DgLbjmHdDl02MX+AO23p6e2Y7RqrcwJdbDOH9gpV8WmECv525BzTj00ml8AF29L5C5SWX+AIEwpZbVhz3VRduOdngsbWSVHI4nkwsXGnhiQt081oF2X5UQsXsPkqZpssLhPRg1MBBGBEkj890K9hR3oiOuEmgwo+dLPTcHeOFy6lgXimn6xjAfbFHNPy7O1SY1NOK+4dBMGcxHQqrpJGHj+CxTTpkYnCXnQ7LwSsnFdy0MJcuqWbS/YIk1LMXHfJLAx7b1cQDb/V5emIaBPxUgWPbf/Ni6f3gaeTIP39rUI1SG0Q8qGC55dNpr+kINih8y68GBWD+u1cs7zkbe8a7s7jEOf6QiGij3cGt559BhMYxMtn0hV42K0Lqn1z8ORBAupolMEW9BMfOV2LpQn8sufMcEzu6+K7RMJDeoQ5fwqeDX8l5ePRamW9un8LnQ35DoL8NdzdtZZuGNjDsEaQJg5rgZmgIR+oiwDU6gDItl/BdjVUkbyoNLaWTMTdlJM+VF6fO91PA4+R9lPefjls+h9H0U0n872Evh82KQo8Nq3hEiSd2l0vxl9EmIDf9f8Sddz+X/9vHj0FGKJlllhHZWyKUhlLSkIZVGlJRIpFSvkohFTIqWiqiQUuhQlokSVGolBUtKhq4XLfidwven8/7fB2v4/l8nH+cqVj3vpKf0ykWjgjCVS4D5PP0HMxMOsIffzzj31LheE1ODUJFP/B6+9vgr84c8Ps8WIRocaduO4TucwfjinJYcvwe782zAueCAni78SXlHynDf2lN9MTdGQbG2pDPt0BKfn2Rz5rG8p8wYRB8Lk9afY24490S3mifD7U75vDYkHoKjkSOvhRK4wP3UNw8DShbux6pQ4Dl5oWQgMEwdlJ5g7odfdja3wdXfxI9st7Ndq+lwH7YIb55/hc9G9jAHvsVQG/0kN/vMYTDE5/y3JsxXMhdeHIZQ4SpL6R8ncZeUZUw69kazu9owwc2mjy/YcgVVrih3C5TPvpCFDT0NWmiSwsIDdyiae5H4WSiMW19dRYaNsfz4gltaDxvPQjXK0K09T106ChGISqkYPIBJSN/VN4kBXa3HCjSOxrv3nxLu2v0Yd7oIrhyc99Qn35nWZ8i2lLmB4WSrvDQIR6fH+miQL1oWGtFsObCN7aZOohrujZAvZgx2VcyvQu4TbMz9Kn7QyTcSp0KXoWWsM5SFNRE9GjJc3Oc+Og3REMYqO67CPKVWpQ8wxsG339joZOKsFskAHIv5bJYQhbsVBwO5rX6MEHgCcVfscYI72FwQEQOAq0MofabDux8b083F7lzZz9y3O5s2BmpCr1e07h9jAraXsuj79o2MHyPAdpnjuGcj7FsVbCFL+hr4V5Dc8pcvoaKpz2ENgslMmYdWP42BKfWn6NMyQVs8OsmXalQR4FtHfy2WZbMwvuxN2U6zQy2htWZT/hp9DK40itDvZ8c0DT+B2VAKmwfdQVTXQbx5FU/vKVqBGGn5fHOr8m41CGcY8+r0yItXX6/SQb6KyaBXMlL7Liahff7lWGKiQjtL11Gy3+dJZ9fB8FCZhMkSpiAdt8bnO5wi0qWeWHkt1GAT/WpZosQCKio0dzmRPDNNKDD9WNxUsIrPFz8l9ZLnYT/AqxhV04NrNf9he7XUjF6PvKwqcb80LWLrh/QhaWZtaBxcBkP/gG40B5HsskJaJw+kw0390BrTitmx5wj8Uc59LtMBpoH9lLA98kwymkXPT/syJfO5WB19kvI6bmCS6bF0Nw568mA/8HmznY+NkIEMr2XsanoCoi930une7rASyUEPMfK8vu9nRDtsgO2Cb7lcL0xECN0jJ5GFfPc9fLksc+Mtn6+AHfPisEkjZEk/PYvXH9xllbKj4fOhsu4v+clb5y3CvTvLcaG1Xuo3N8WTbsu8zhhBfDt1aQwe2V4V3IcfkduxZ/TU7ik8DU3LryHzaXzcVTqNBptoQOG8cY42UsSXE12oK7wcpymfYYiOidyjpE1OOS1YObtBygx8S66iQmQk6c0uP8VJ4+5s2nmgi/0tjoAJv8sY5cxdnT960X6WWzAq+QK0apJbug3vYZNfJee35yOoyMPsYR9Csu3XAfv5Qvx8yJfXrRTkcYpa4CTyTw8OmI/GW6bBjsTbfmBwnsQXJJL2R8fUXG+N58S2UV5yxB+yBaw4d1+bso+gtNXKOKS1FNgfW4b1PfI4M1qQbpFz1C6TRV+drqz4n/TIcvqBn3t1cE9A84k/vwDb2qKwqj7vvylO5qMgk3Ba+t89K/QQfXLs+g/v/WgtXUmXvCU5em7L/PBCEtUWp3GV2snwZej9yF0tyUbttXjx5l++O4skm6aBUop+LCvymn6ut6KDozSAgvDVJCfAvhA1IBdz+3jDO90nu02jHhKGptuS+WH9qGQmCAE9iOUYaZtLP9LC6BtdSdRfpElvV6fj6/HbEJtzMJRKm6o1yIHRQc1cO6jPWy2JgT+VbfxTV9fnrlGDnxM+yk3JxPLo/7jNVeVIeqFIc4J/sSGakdJr3cmXNkqjZq/qkBqpSkN9yjma/kCQDmqsEjtBy1ouk0DLrJ0L9Ufx6wexv/kF8LAmQWk0nCHv6l/4i8TJoHkdS3K1nbD7hgjtLvwl6V0n4HPj3ckN/E7Zzosh77FodguagilT/ZQQvt1sJ6zGZ1vxfGb3lCW83OkkIhh+EPZBwX3eoDlH21o3vaCrVpP8K79c6jTaDrnGS/EjRIeuDGoHqpq8tDdXxgHtSfDhrh7cGd7Iz6ar0kBFl7se14G9g5exw75KHyR3ohub4vZ94EElBxNB5t3RbzFM4Tvj9TEmo/dtPK+Asl2H4JROxbAV6FSdFKfCDPbfehqqzhqOY7H17IfsG7sV6rpisC9kfsg4nc2rZFuAJs4VfiXacI5bzeBxaNydN28FFwOhlOnZguOs55JKzy8ufunKJz+ag7HRJfS5lvvyDfmH9lm3KfLHICOk51pGqTQw5V6rNvxlhOlxoGSuC6cnmuD/+Qu0OkPBvRtRCZkipwGjbPHSe9oLIh4naKrR4dB4u3doGW7BVZ+3s0NSjXQMM4eOuL/wByblfRu4QzQW/qVGwJsIdhLHEMzfsG4faWk6HgE6kX9yeXxIOocecG5dSEcqd2P+kUqEJ+xBHWKw0DcpQFvrhaEkts7MMxtL5fFncdT4uV4+MtkqlcRgWl1L0HAyo79H26ABumXePlxJe0q8KWEZGleVa0L0vXnMeacETRtb2QRAxs2sbJnn3IvvHi9HfVrZkFAxCbedUaETMddgZsbtSBdPhDvi0+g54lB0NEVzFnXZmNxchBofJ+EH+9Z87/ag9T9axycVWqH2pmJ2OlZB3k8hlUr47HVVoNbf8/CrV1JoD1ZA4uLlUFo2E3KlB+AfMdmTH+5AROn/iOTyU74Garh/bvxaHI0kzffGQ+7Z8bgRC07vHlNAOa0xqBalyltvxQFEk+bIWHUe/hpr4YLl46AlhktVPQ0BQtODOCJyn46km3IcSPHw6iWc7hgzSoa2dyPwi4IN131SKf7AbYHl+Lg+fcQozsZPQ650dyuRP7XvJZDdPazbZUmeB5OwJwbrvCtMp5+7xwJItY5KDfVilUtv2HZnFx46TQegvdLwb+Mw+jpu4kTyoCfFhwCtU1z8JP2Hv426xDI79nJm9qc0EdCGDb36sOM9bKwyHVo7n7NgxPbxfnumFhYsdYRjIddgkPO/2FvlSz0Ol7BhJHX8QeGsWjeC5TXFeTKl8JDvajEi0+tAv/GV2jcKQkflqShp/hqmmyejO7nbHhe4g6O6fahNc+zhuZYCX5VX4aFCWawXzKON6+8xqJd2RgToQQZ5ofp0565qDGhlMXcx+K4p79oigyCp6gAND3Ig6cFYSB0OpD6KoSgV6uRKe822JRuo5vPZ+GoT7ZgnpECkfEetLfchM65tYDCnCwYMyuXtPX80Kj4HKcb3cTT5+Xhbc5ttBn5gK6dPoAlsWnolJzBW50qoUVPj7I7ckj/dTaWZqpByLwV5D3PghwbX9Kiqdvx0r8P/On5U3hw+w452l+CZ73MnZfVIR980ETuJV9+4s1zkjI5//cZzJKczBnVkbh8iizt3tZE2+3NwUblNF7gZk7d3kPPnkhjzO9L6JNfRVbLX/LzyhdcoHMRA19JwUjXWpgt4wdTXRaTdjRA78d28tWO4+Aj81HKXZoFx7TylUgFONJ2E71ZlD8dX8eSV+MgbWYZjdHJglkiUiC++xmfrRmO8Y02IHz9EKbZT+VefyHAcA1e4FxAfp8341uNKRgu+BuGrzGiu7sJ9swdDQ8zgzBZawEN1D3j4LwU6CwW5nnTv+CM/SM4MF6UdLRlYJvKHpj1u4C/ZqxD9UW+MExgIdnWW9GUdfNhfdoXCLv3A7wjJWDn7K1wUzQYcx8L4YbeM3QhUJMXPvRmtxQpnO2zn26tfUApTtKwVM2NrHYdg31Pm/FBRzQ/+1NJc+1ewc5LYzG14REUXR0DF3aIwtS2GLgXZUQ6L5fCtuTHGHltBO+9dht1vj3Hys6peLvLje+riYL/LEH0796FElft0de/BxcEroDIliJo/5FIL29sQ78+OzgXLg//tebw7W8/QHCMHEXPsOPOqV9x+vY12NOfywKhaexW9gcMpBSh+7Mfbe0K4Bl5QfgtO4XsW/3pk/0mDJ2QBfe0VbCnZjwaZ04ClxFA0YbnYcqpbgjzPMiusq/Qz5CotUQI52rMxtsvd/KsRAkouv2Erzb5QvX0N/Dg5w0a2CgC3xobMOBSJv5NV6IXz6/TVzUT+GKxkrQqxLgmQoz+dh5jqT1fUL3Sh0dfl2KBQ2/grkcYHVw+Dub59aP50dl0aZEYiTUnkvjVNcCKs1nJkTlHQ5yb6mqh+JUK5B51gz2/xGjesQfUUFBJl2bKkFXXfyDoHwNNGjb8UrSAHhgOh68lu+G0cQcuLQ/DhVee4ofEYEy8ew9fCfTQNRV7fF4oSBIjJeH48j9o/tcEDz/QwOE+2lzXk02VzgtRsnoqrwu7BF6uC7B+qiasQV2+kbgabr3UIZEZSWzjNh52TAkjobmbIfNgLkZ56lFpmiJUblRD2Uhh6nmjRB7qHvxCwB1kp6/ifdHngNuzeJ8egeo6QTiQXQ4nizXx0jJRziApMGo+BVG7j7Dz1kWkt/cx/b34navOMxxxGQ6pYUfhUGoqOWoL0BX7O3D6ZT88GXYRjNPewMXNmxgFRGFAJou3qRhjZcZ13LhxHt2tC+SgcS38ZKoFdWaXwdKCjzjYJQGmsQtB7dY2XHw9AFML5/Nsr+uwwtIRrG5lker3ZShNMXBazhBWjhVF8b/S9GHDdK70ycUVomvIKkoXrHc283Y4RUrlH+jmVSMwTbcBSZkAPrHSAnIDhfDFlBbK/Dka53iOgfRnEpQcpca/7CdCc9lF9v8yiDMmfqfKtp2UPHIStrjEg5p+BeWIv6Idl8PA89IESGkUhapPanjPO5l7k96hxPt9ZDW/BhwsbNFv7U/yClKhOUYTIE50I9YvCqUTWyRJruYltMW2QIKVHy3sWQsvkcFddDPo+wqCfvgMtE8JZsHXcqR76Qlu0CzknsfRsCdAEs+tNcIb5ZmwbUADwib08+1nKZziPo1Kdh9B9+h+NPnyHAtmxUBHwWIemeyNy1xsIfpcMi1NtuGNdoZ8y/84yo1pgagsASzryAaDigZuupKFlKANqh6CHFUUwtsuOXH/gDqe6a+F2Mn7eVftCNRSdSC51QK4eMsksPwVC86C1njYwAVOJwzwksKR1CjpBmH7DsAN6yPg6P8dJq1TgpW+82GT/n9kUO3J4bsewNd1S/Gx9GUa1iAEB5V/sNgWC5i02AIOD/ngkhuXWcz5C9rOng8RCZPg6icjeq7gj2tDg+Bo4g50H2YDoa8q4cn4t6z5XxTue9aNGh+LSPvvb+y7EkMPmrpp/dTzbDlnGKgJJrBeTRHn6yygg8Om0yLJQ2DWs5Ky1ErQeZ8/VtxwRDn94ZCRsQbP+Ouix9aNXL1pDUv8qUGHUSrQbVuKVo8fcFJVICa1jIYDu8fQdqebMFd4OQzcPE4f5orBqPmjcc/TLyz6JZrbBMW4ZLkg2JUCzh+/HzbbB+H2sYSpRxeg9xh9tCvpwPim4dx+4C/sCpkA12rXkuvaOBL8F4j9N0Wo5c5XvlGoy73rG9Gs7TT6OAZDqJDxECOWcHZNC+qVngYI+0GBoo+5YVsVTpN9QmNEf1HcE3nomWQAOqL/sOrTRm7RkqBz8SV8K/U6KrjnYNDy7xT9eg0VrtsNSiayIOTYQFX5OawWcx2V/htge9vT/LTTlWeJfKCi3aVgRbkoc1QFhA+XolL7fYju9gChDV6UPLkD5s2OH3LdarpvmM1uFSepVF4F5r+KRt2PI8C7czNH1JXSYx993laoAj2K6bQj042XbWrj2ovK8EbUmxKMUmHNkjI4VBeKLhvfw8oN79GwQIibzjxlUa8KeHpLGtwyrpG+fgPt0kwj3xs/ceaOZVhubUX3B634sW0ie4ab0KVMG1i0/R05aemRc+xTlnw2ALNu/0KPojjsupUGrwa8sLFYFfrshOD9Jn1cuCoTvK8/QY/CfvBf+hKFrznjDp8neE1cH1PTmlDOWw6u7P2B6hPFh3jlPxrlFA2DlsNgWwjjJJ2DcN94BI46JQYuRRNBftdXVgu4h05fPHBkXBBlbHPgm6OU6ZmhOVTpfeeWDEk0/6ML27P0cdAtAe1HWNLfMiUQPyQNUkJBHKo+Bw/P20g+hY+w2g+hJyGXPySY4ZPe9ZTzcjhuzr5KiW6FQz1TzY+F4infrwa1u6XhQ9UZWDNXieb3z8Cwp918ofUlOj3Pp5KNu/Ha2jzeWzeDYpokIF/vGU9d6sSJHZK0O3QCqFa3Q+OGsfTSzQSNxp2EhiYzuLlSAi68nUjve23RymQ5z/hqhBlJTjDsbjHNuNpOEit3wYyPgSTpIwO9ur95w9IUCioc2vt3qzDxvyNwqTiV9joEYc6yS/RFaReVd2rCnAX5dPLASXraMxFPbsjGQrRgLZ0F6JdvM+T5AbC/i9HvuCTsvRHGXf0WFPHTgGZJ6+CcsVdh8bJFPFdKgZU+L8cv0w1p/LwR8Kn4JHhZnsY3lfKIsfNg19JvEBx7glaoZkPyaEXUcUzBgztU4ZuKF6+d8wg/z7kIGZucadBmND73mcZCW7IofVcJFf9TpuQ3WnBlxUF+M9TBkWcdIKx1NvhvUaTio2+4t+gUHxr8zfnTS9D6/QS4sf0GfV20DZ+u9wEX0T9oeVQAqiWlOUdCiFa1haIxFdLNEBtQSH7LkWkacE/vNTa6V9GA5lackZLMQVZyoJC3kda7pbD6lREwK3IBV95vRLtr60BIUZTnBJfCZbcnODY8gi6tus/mZ6IocaQCtFXtZJl1Q4HIHg03LwXBhN7VcG7VAcgcXcN6f0tx6w9nKP4iD74uK+h5bhOWfl3J7kWWMGPVJorTOYLXMqoxz0cKc4TloXmUJPydPpM+r9Hjjl2ZELb4LZ3NXwDPPhdw+WtT/vkhDm5b63HtMhvIDRZkj+31OO2fK453MiU7M0/aYniXJ84+h65SnnAyNxLdhotB7LA4Cqv24dlz13K71ToQs1KiY69FYf9/xdi05TkOiiWT3psJsOejG86Mfws3mhppysSnaJ3ewXpl68F1rxULyt2D02GjSV3IEuILH8O0GZloMG4Sa0hYYm3+Pwhq2czOhrPZQ/sh3++rpYV9CnA/4Qo8S1uAJr92Y0RjPYpoLeX1BregeOJcmhN3hmI/lICMjSyotj3BNcJSrL93GDjW9lDU8ZUoWaeFp/I76FtMMg/0XAF3RUn40baf9+/O5v7wR9zxYw2J+geiS1A879qjhQ6fNnHhqV6scbSEC21/MGGlJ8sLmcH2BdNh/eFJWP7dmq8fXwz+H2dhfmMq6AUowJNqb3wYpUi3GmLZNnQTXT/nwxKrO/iRwklqCUF4sqEejVW0wD/5LOU/1+GsfidykxEF69mzQHDLOapNOoWqjR9h/aQg8P9gBu07F8OtO6M4K28rH2n+gxUJS8li+kackPWXc+qH4873AzD/ngIMGrymT7LfoOH1AbqReRNErzpCftMijH6kgwOWBNEWc3naEnnYbVwHO56K0xWdP2TXrIp/e2x5i4cwF64aQdcWh9C4KUY4YsjpEpSQz61nknyVzw01j7BdaiFi90VU39GPLQ9+YkPvDirX0oZq7WXw+tkL7tvxDYNFi9E2vwD+WKdgVsVkuBU7Gm+1CJOr4BjIE95Ie+r1Yc+RGFp39ggOqoWi29d8LCoSpzEGdrxKbzi8mSP1P/v+b+H072SKP9mh3BtMj1TghQZ3lu27To1b1WhRrQg2atlBSp8I2Cd5oZJQPWrVb4RXOxVwzJ9AWHpnBCyYmIy63+bDgdtHOMVCBTxxFDw/2EF2mkfx0EMZktihDpqzutB2ejqIvmA4oyZCx9fowscZCznrzEPst3wHX4ZtBY2k73TBMJ9v9njyynhd2lGVSctkZaFkazi/nXGZIncHwYi3f2DesMu0YHgVfQpsw6Ktutxy5wnYG4pCoOdmSnr2EmLdXLCt8CqOKHhISoZneVHJI7zy7zu6bz6In/JNwEAEqT6tneOkE/iW5SfuVBxOIeGrOH3mKTRAWfCwe08P1EZCp2w7x7s7w/GwEaSiOYLN9pymmgfEPwKMyUm9DzuE/0JimQr8895Hbb7StNtrPsqKj+TT/6JZY4IYzdIcBaXuy/BsTAIvOq0I0iqK1Ir9uFRRFLeKT8GBKluWSnbmUbduU2voVTQNf0gBZtrgWpLEpatLSLYgDIymiHDb/BW0/ZA9asBlbujOxct1xyBxoi48BXPaZ2+HOx6bkrD6KlyX8Jtkbv/AyJVjQWz1cui6PDTjwebwIiKft5oms4zfCJD78pptBDfi6XQjvjOYSt9XrkCfgz4QGDAJ7n9NpfoyL8yO94UFPxXQQrEOXg/dS0BELEimqdH0X7WYO2UUNGAfZwu9okNJu9DeMoUaVyahsF8k3fnjyhaSRZw52gD2CirAv+pBmjnYDovcztMjgzgYEy2O9bWa/PzcMy4RaqIxe+5Q0GNziNX1RcVLrdSaPIUnS7ij18531HIugD62a9D9ZmX6u30eGaZog0T8djz2YQs+erccDwc94tbqW1TfFAFFk8dRnnYVxCx7BB/+SMLdWyOxvcCC/P8YgWb2e/JcdpK+FKky5VXD26iVbOyoR0ILEJpzrfhc8lVUCRrH3haOHNYdio/uXKDf+3bC82kz6FbISJy4xgAS9t2j1+4X4fF3P75SOw+2HIhG6522YDZ2NB5WEqf8Q+mct9QWjsWcx9qba1hpewaJttajj+w+zns3gu6WmVJs6TgcKZwA70/qg9nmf/hYzoEUzMrYMvIdZj//RF7KCVh5bBNm3t5Kn5W7+JudFDTuv02ny4wxrEUVF1q2odLdU/TKbQqr7xICkj1LJwfnkMthMci/38TWiTdA98kfvFaWQL/NhVlzyINNrznRwsiJ5JlTDIe3T4Jtryppy8oyShJ3Zok9t1lCxxMtGkypu/8BFj4URZf3T0FCRgnST5qx8rJuTNWeCHLuv/mt43eaW5/GAlXj4UjZMbi1vBJ+jBwP7o82o0hgAM7T62Vjbc8h9haAr9cvsJdwHzdfiGalh/vovocSPKx+xC0C3ei+Vhm9jN+gXeo72pxswU7PvKlYYiw0rSTUFDeEKfESFDDsG/h5jkPUTaWS+mgcfrGXv741oVNLdmCn3ZBlXxv6v4ueE6ncxR7bI5x5OR1uRsSx7tNq7HkfCWox+1jN1xO0UtXB69EWUto/mg6EfmbR5gMwdW4gJ378Avs7FcC9/htYLqmHtJCx8Oi/T9B7sxFiVZFvSoXTofwKfFFRAredOslysA+yfo2E3e3j4MTWVF7b3MO2QiaYeX45HJUSIV3XQhovGzF0hjzeexmMux4qg4pAGdWY34E8mdlUvvIGVqbm8rHX4fRBoIvCZtqRbsB1unN9BGi8uMqLRgOOPlwLN0wf4SKrF3j1AqFIWB3fHMwGx0FxcJUShBuvDnDGbWt4PWM7if00omXXQ2l33gmM1p6FTwdkMeW5HfTFKcEdZSOU1O/E+o6dnGq8CWe8UaOgpNP4/uxsSr+YSh3tUbR4PcFg6wvMCNiC40Rv0JScl3S4dQsZrr0DLaJueC8kkOcdO0ELgibA8S+lWO6wCdNnzgZbUSuGY+IY2ypCi0Zs5tVmfaC5bSm/PK0M476Iwf62K7xt7ziKXfCGJ1v/pNAzY0BF8Qakzs/gBaei8fNteVjVFEWOFdE4K94MPI48RH2DFho59Sg7uI3lqb6rKe3T/aGsq8COr+lYLnGIgn784V2DObyJ38Fm1yQsCjjEqXLmcOvxJ8hPkYBXq19wVZIPV1Z/4EeiQaR0JArShrI2/eQgLHnfDA/cnnHsnzHwT3EU5VpFUM9RW/pgWU4TdbVpyjpD6LkTSgXTY+iL42lS32oNz0cpEUb/gP2ujyi27hHdFZ8Fm/LXkoLVHXTJ7sUI8RheYSkAW4RzUc5KC3LFdDi5zhIffzLjw6mhuG3wCGUl2vO1+atpirIAyC5MQ1INoOoSPZAaf4g6Tf7yk/I+7LF7yA+Pe1Dp+53wcKMmPHqoSLsz3aHIzoZEDmhAl2cmKa9bjKffL+AekxjOMyimJ7V6sCH7DE+xbOWXyqJwQ1kHHPUKMOCaMRTH3cDWBYNc73kENM2V4EZ5AovoB5GxlAV1GOyEuBPugBlCHBRdCqFHzCBXWBVOD/nv6V+TYI7gVwyoS4QlKbPh6WMXdNL3wdYl0/Dj6Uo6bnMKQ74pg7rBEy7d48mX2k+g/CInKkgK5Ic9NuBcZABj5wVTSMsAbtU3gp2VVWjZvQkudi9DdWkJUGszplaJFTCxq4paLc3B6IQpKH/QhEYjcypWqabw1uvQI7AD9tYMuYT7LDCt2A6LS77i5oMbscZPH/6K62Bb+i5YFLORGvQeQfTzLLjtaU7KncvobkcHZzw5gbMUhGFtehyP91kORVpnsan/F1wYNoGOXEqBINk2PmebhR53/8ODcQZw73IePpi8AvY9tCfJop3UeP4L9L5KxA3L18Euu4XUEXQCrmuogY1HC47V3k+2S26TQlAlVs8PILPauzxzz23oMNbGBt7MLa7qMD8ih+eLDqep7svBfvdVvPrhA/Lji5CtsI6bzQZR59UotPo2GqZuOkO7pX/AOThLZXXCmNq/gSq3i+AW6dWYNeQAIV+X8IcvEnBVK43+vFXiGisb/GS8FTKf5HJAyGI8vFWIdj34j9fH6vFBPR3YMXY1HxTXxiuhG8hXeTfcOmHAC0370WXmRjy06y6/vFDJ0heF4NBCZdaOiKUy8aV02fUjTQt8C2Gh3/BidRJd2vYOBNp0+Ms/OfD8sBGS1k3EFKNN6PZkBP5SreWUSXbwIfgjVL/eQa/W91OjpwI8DfgI/pMOsYTxAzw7wQGMyYwjD3pgg+JXyDzqRUdPNMCMHHMYXdjIc3umsIfrNfx27CGZq57i9Xal6BO2jlBIhZJmBNPYhEkgueIF6n+7iylFCqw/7zbWvHyOW3uSsGKWLEo9asAxUdE0oK0HuyQa4bROAqzdspmCXubQontGvDPzHd3/OY7uPVJm72cjMXS1Jlx+X0D3TxMejmyjihBXdNxbyy/HzCPZuXPoREIoHv/sgtLLFOGPXQuaLcmj3U2AH2tc8PLaOdxidQGnd5eixsq9WJH9CivWCYBX23zUWIuYfX8ij/a/Ri4zPTnZK5xshdXB5XwiSFeq0dcsgjFxgzTh5HKe21TOrR+aoeC8Kw7IFvDetCSYc68Oj6tEccMLLVCZdofFnhZR5Zmt1Nq4GX/ZT4ONM+Zj6ec1dPBdM79KfUZVSuPhRmUunY3aA61yHWQ6tN88ZLfh9k+f6euv/8BPdTJEfJxNWX8V4GpsB27xkYAVy6T5qpcOG8pIQcItR3x3tIRmFM+H3UXTOcBPB3b91qb2wlEcfdYaxsusw16vdAg3mcyDR7fAqV0XccN5WVw9k0GjOAS0jCsg3l+bXlkX04uukzy3/ABsGleG9w8uxzU9I2iYxygY7V7GwQ1mbPK8ETSPHuTwSD16/3UrRd0vhVbPEVQcO5bGiVlChfR4WpyxFlXEe8A2KYf7Nz2GCIW3XOgbRxU7y1l2RTC15UyCmjOtfH+CM7dvUydv39soEq0M/7V3QLhPFviGfeSJCfvB5IrAkNcJ043K0aBlbs5X+n6y+/cQrqrsgx899ay24CK9DLs9hAVC0L0im5/tNaG/dpPxsKgEOKj28eqIzXTnXyB4VV5hR+ffGCCpAFtv2PDkkcMo8sZUbHO7TnZHa1AsNR5b3hHd3NBB+mfKYflvfdD1MIJnDvlsLdcCn08ugemSo3j3yPeQmv4e20ys8NGsCo77YgBB/WF4LGMp+/qNhcy4mfzTfT1Jrwnl9VuX0PfeWAxr8OCYVRZwetANVhu5kf4/JT67Xn6II26ztJ4tzcp7SCe/6GHp2qMw1VgUVscwnk2tgsHg1ThVVoJ+DvMBwYr3FHBykJLfjCaLBVvgXIEKeIXlk3FxE8/4+Q77FI9Cl6MryN7fBD6T++F40HVqb9pFJWnWcD5CmFFyFjsnRfCwCX18vNQUTkTcwWmDQbBxzhZ2ulLHNmLiMLtOgSr/u8gJk9Ron+Nkhpw4HF6SDpq1BWxyRwum3hsJEePGwdfIMrLtc8dvjufpTdwHel3wCrWiI0niejmGTLek5O44nOSiDTl/sviKWT36vf3Hkn7OsE1oIn8Nshq6hwVYUxEO5/brs26PAViLyoJK32TMFW9nyyU14OpzBhZo3uM1ojlkdVCXv7tagUj3GJCLeIHmEyK497Y+e/fchhl3NKHM7wWFhCzBqHFfUXeCKf2SFYVNNW+5M3Qkd819TWXXuvl8chaeUS3kNWePg/D/v0NVS2DfBTLwfGcaKB4dRtmX1+C24v0QPukiWBUo4jCHbXBJ4xfEPlAB5Q5x+C/+GziCGwYrxqHaMR+0DL1GUR9+soWtLstdK8cv2YtxlP1IELw8FV2l3XHh/mjqCPmHM9ps+UvofJpQawmhzzez5M7P8OqbFZj/bKbq2G460rOPD2/Q5mORDdBj7cJX5d+zrYwgyLfch/FD7Pkv1xSGtUyEj6JhcCXsJC3tF0bjkUcBXG9S4eomvi2YRed/KcNfYwv4kVUFySVrUMBzE/6QvYOzXAPpcHcwLnmZQHmn9sGpYBEYnPoVaw+uJv8Cf5qdGcmXRqWiy59EsPYzod4NbmB2IQE36tiC7rFgnKemN5SbaPpcvggKfrqjlN4p8my4g2IfL2DDcz0u7pKFX0uSsNvGgobkH1UO6eOyhx/h4dwPeCDqFywveQvDzv+CCnctWPXUGbQPF/DwHFl6NvI8B2o58XspS3S+4EzSdSepvu8iGsXrQsnDUSB3SY+6vsznLU/n8dUJ6qgS4AKi51cxS6dR4flkul6qDQZlojhwTQHDZtRi9+GjbKmgziGiOtz5IAiu2cpTtq8O9FzVgr1V++haRjLYz68FlaI4iJGzge9aKTRzvji6Rfwmtfsz+EwRwYQPa2janVYwd0hBzuxj8ZbVpHlQk1Y9/g9nHQznxspUzC2ygS/np8Fc605e/icPb4nJ8DfNWmqW/MY3F22i3lv6+NEtiBes0ATHG0XsPM2MR5R3gon9YbTMDOHV32rR/dJLSgl4h86n/sCJbfLwquQVxg2x6YuiNOq39OPlK7zhwLVLOOrWESoMc8exp0LhyYiJsOvEds53iGLZA4GgbR1DFQXNcCZKgX235+PB2evo/oL/sMZAAQx+hdKcpgQI+eaABTYO9Oe8Pi70v4cpd3z4COtBv2wIPNqsCmXKZjD8fSyLdk4H3zg5cvgYy8ZhGzjw1Fl2bLuMqRXuUB+oDtrHqtDpwH347CKFeZO9KM/Ib6j/c3l+eT449MSyjvtWuDhWGmInDUOrxYEcNmkazrqxEeffdYSFb0OoPmM+Xmc9Up4njhLOonBp+m5srxRlYblM0BVQ51z5kbQ/qpa9JJntrwyyRa4JR0gqgmGBBrlGTuYXP4ejTPUpKuh24hNvrlKK3DQ4KFWPjyLiyfHrJChdM4L2WspwxcM5GPeyk6cumkIPT+2lsuqD6OXgyg7Z1iTzUgnCG8/R4tl2+Gj0IOgOH8rL0Cx1aWnxItgH08fU0cfOcjgTOhy+Z6tinMkWts39xapuZ6n6aCEJOiRRsVMUmTTpoN/jGTQvxBR0FtqA1GdzuvBkCT6IjaKsi0F0+OsEmLYqA1fIK5G/ewZLrzWGVFFEXOiIGTkr2PXgVgh77cgLY5LwrPIsXL18NKoIN0LSFCnQvi5AuavKsO5NIpk1vyDFNZ/o5P10fGtxkUdVJbJX5F7IKRwN9eMkQcljKu9yHcY/79vAYoHzKOcdwmpVk+GdXxd+umWK99IsIDVHFFeNu09jNucN9f1J3LJSCx/G24NSkivPz5nM77esgJw1mvBd6R27lp6h98cOcIL2Uzp/JALTjwpSsNJZVFMQ5Wmuflw6fATEHHeF93OyofBOFWVdnU1uOYoo2mFOe+1WY+TT0bRT6wuUGplB+u5gPnxSnzfExkCt8APq7lhENxaEst5yKVpvb82B7rG88os1/NnsSmc+TqAam4U4I2kd/Nu1Dpe/HQ/JVlq0qsYLlix8Sx9DRGDEwSTYd7yZRNLuUMXWSDw6z5GGBoA00mTIsTmAGqb6U+RPXWh5ewP8jm9BWYVmsB8cwd3R/TD41Ig9ffph8WEJMl4QSR5HrUDtwCYY/30hOu05QoPHNrJ7aAGM2z+by+b+wd134tBCbRTQZkUwyJfBoOp2np21Bd1uxtPVr+lg8rwZD+yei3OWmfGSAjNUHG4O9puWQv5cZ9rveB9XXvFB7ZQ57CUyCdsdJ2JIwj/wPAH8slgZUm2LuOz0GcrKiwbviFxANzUcUPWiytAj0EwX2Gi+DZh8koALO0sxuaAKUwsDSFXsHk55v5Ec/8XhYskyXHh4JRmtQbJiafi5fxysOF2KulsC0NGiAWvO1LF9hzT6JjVByYLfeKH3Km8vkofZOTvwiskAvd0+jqyEHmF2+kQIrotA9VQrWtV8h9/N/0amaVZg1CVHmaOqMOl+H0l8v84XL8fxW7kQjBm6+8aAEFjvUEui0uLwZtcPOFHTwTkZG/CBy10ulY4jy7VpHF30jJ6+SWJZQUessBYD97+e/Eq5HzWuz8KuI5P4cs1Xujb2H19SRzQ6+Q3+5YXSn0O6kBAQjIqWkeTm3YeWUWno3eVETSPecN1+e/5jHkzel/azoqMBLB0oZfHOd/Tj+ScwDA+j3o/f2VphiEcn7EP9kjzc8MoWqwJU4LDZBHysXAHqDxI4ql+D7qbrw+1wM8grvsguOttg+9hE7pdRgMLAZhARWE9HgkO5XjsHnaa+oPJZ+ay6wJ88agRg053XuGT0ODCsW0xPyhshr/4aCFWOxCUeq2klVfLoufmctNSXfzhvpgW11jCAGXR21R/YttOI/6zN5ONDrBQsII7+U8O4LmUMi6fehC8aRqC+SRNFZ1tQuv4G/nqyBXasm0h7o87jkR8V0FsTzysfCwIaTIIXzslUNnIQpu935s4DTrRdPwEmghuMR3sYKC+jn+YPKGyEJmgnJ3PkWUtM2GcAJ5qRPi72YiuXLBp3N5vvmVVQm+Ex8gpVhuIniWDjOIBw7xhFBr6DdXfPwRWvbJYze8AyeUM83lHNmtvEYXPENR68kI+VgcdZzFqAyj97glP8AE3e/A0na0dQ2B5JjvqtDL+OGoO8YyZ6jx8NFyslUXfZWloneA4s2xNY8ut+6M7YM7QnxoNM/yzwWP2Kg8YbwaZ1K+DgmnRYJvQJNKecw+2ZDPJRdbzzwnAwf/cao6+78QkHVXK6v5CqtUdgivkqnuPoBIv2KA450iVafMoImp894BLvLlAsUoOXm6zQLnIm2B5bRRuF1nGHrQc8iqkjgWXy4BIuwC82O9OpC4fg+mY7ED3mQ/qtJmAiMJevnS/lpmHl+E1MCfbIPqXvwb/hydlf0D2YjyUPvsDq6T7819eWGiX1yFo2l9eEakH4wRkUcKCdul89Z6dQP7Ax6MT1z46z15p+UFHZTLPSrvIfWQsQ1s0gvVuSnNpzEA9elIFcY1vc+rYbFzU1ccbY1XhmxUqYF2cAPWM6ebGWGsWe6MUDMhch6dpJinpnCHhzPXsE+nJStxibXRQHVQclniJnxldSuvCnXS3Nr/WmvoHDJHC8HcbPVsYe8SRS8tGFp6fuQUJ4PCntOwDGw3tIJvsw7M1bh0F313NBXhn89/AFZ8oOgxfzV8LU0zUoPzEURfZ1sJLADkz+cIR6ZrwA5TEx9FDmNd6YYAbtIwUg6IYHP9FOJrdEWcza7wSitsVU/qkFK7Mj4PKOUAy21IPVMy7CklQjSFzVT6OcG2iQv6PEaTXI6M3Ajrd9JBx3HkRzxSApvZj/zKhjz7Z4bjM8y8tbZlCDwyGat6kHQicW8LmNHrzYwBySPvzC9a8WgdPnKrqx/RhO8r1MBe3uPCX5AVREv8H27kIKXy8HTdVdKHKxA4Yf64O2uvlYtmYZOaSEU2ZpADw7dwqWpnijYcs4OHBgO794+hYlFwqT7bLvfHblV4ohQc7P+E4TdrnScr0XuGUhgVyiAGYUzeALVfNx7PIBkOjuovIpLzF8bSF6/UoGhyAHmjPSCFQLlejp8YuweeU5llCIggrnj3S4fwcfDPXHXcVVLHl3L3zVk4DwfVNB72ogdQntJFv7YCp+8IbP9B1lZ9N0KLriShM/J0Nw3lhwE18IFUd+0D+rtdi2LQxPzdbkGyszOLCtBnwVvpPv9MUwNloWxvQ95pTQp/jwy2Z4atBEm5Z3cE9SBT7wGsDYvgvs2nmG0i9pgOK5O3x+Uwbnxa/HhoUh1O0vzdNnLyWfx0/BbVwzHvtxkf0Py0Pz6TJK/lcIQqOm4biFYnQxvZSeaIRCTP05Gnixircsfo4aehogkvIJWmNC+PKe87xLqABX+j0jZeVqOFr2BgJeFmLsmWgId7MB3d+eOP+jCdztTYPu3S0gmX4GdTtrSKyrkG+nB8HMQQnUS2PYobSCZi7yBcnkXPoV2IH/cvfBd38LlLl+mS68yMAdC0fB3jRNCK7/yCtUTVG9PZH8IudC64S7fCh3Jx/c9Ywcj2xn2b0+MLVIFkTmXQG5KRkU6txIM0O3wn1LZ9pqoUAjVl+A4F1H2ar9Fb8crQe3Ov3YusWQVpkmkpL6B76w/z5Mk5wAkreuw2SRDKjxzMPX17ThWvlM3DDsDTjsMIQRApJwYM8nctT8BoEXNMFUbC4JjCnADyrisPuBASRE6YHXAlOY+6Wa6jJPsEfqXbxxzBdEK115idc6+FQyAn5kRtK9c8yWM8vgSOFJcujWp3SBFzRu1GU8qxHMGzZn4Jw/6lBy0ZM98vO4Xk0bH00swydRk3nFu4OweFQMBu/YA88TdNDlpgScqdoNHaYLcI73PZKfdhnfO9pDXtYefPxBkM9rH8VY0YlsP6gHM9rNafdDE6zeWgFnt9zBKrsd8G/qep6u20tiOw7BGachbnceCapObVT2XwebWbxi/YLxIHL9BSkFV5OQmBFOe30cHLOjUfL9MJhzw5LTZh3hlT+Tub5kHEpNbSSFddeoqugIPs5rJFE9HYxwGg2CQS30/KQwng1ZxDceVsDB5GbaXVmJs5TF+O3G/1Cm4xjsaLWAvKYxIOzfig6XQijJ8i88OVoArhLLeYdrA12xWAXZNXH419IEhEqiqSU/hR84jAQX17X49/gmfPori0v3l/EGz0z2Wn8KvN7pgesoO1qXpIHbHxwksR5L3Jt5GMZ67IU1jtHYfqMMs/79QP0dGhDq08qef5fyrqUSKDjzIZ+NTcVL20bQOGEh+Bn1BA3Dz5Brjw0cs0zHop+GsH38XTKePZ0maW1hF7tXHL0sDHYLtbGY4Qn8O8wYqsWnoWv3Zz77cgWPdbwEG+QsafhzA9qjO40UPp1kx4yp5DyPIDZCGD5BGWurH6Cd189hyGtfGLa/Eb67TgFdj7Mot+gerhC2gbQyAZbU/A/U87N5dpslmmgG8uBeVY57Mg8vBM+H1lgvsn2jBdXuppB4wYpjEqag7E8V3jxhO6RIfcCZUn54Yashya2awvjdFj6Le+L7iBuoaDLA9s3nWFXrJiw4vYO3GQrxjddGqLTlPE2N14HLA/541DgQcv86UF/tAZ665Rd9swyFsNhajFzVRxc++pLLShM4HG5CuXL7Kd37OIfvdKAjJ6thTFYVGp0rhvCR8dC44Bs59KjDlql/qXVoz+4OW0WNfYMsefYM3VnkDbo5wfCvXB//rA6hkeYKILlWj2Z7x2Lqfxa0SuIA5UImH076A19uOIDA0MxV+qnTeXkFMIz9RZP+HaFPYjd5lVgk7Pw+GrL+rBziQDn8dLQQi1cm0xs1guwdTWwSsgwvVs+iC4eUef2BNp6wwRB7gwMp5pgo/iltBRHTsbD2aik/32/IRT/G059L2ey4+itOCS5Dv/xWrq7QB9UD4Zz9XRVMXiI9X7mNT30Xwn8rXqFreRkIigTjngQ9nL53Mbgvug/fd+rBMBcTlpDYSmWFpzF8qhJnHlNj24Y4bJ3iwe4eDlD3QxW2fAWQSKnkVRNWcbumDXnvk0PnrNNgaKJP/aOWc6+OLFb4robzwxCWbgwfekaDaH98LOlPjsToJ3lY5xDD1c+24seAhax4fhW/sxGGPmtBGKZYxd/NvbAy5Qp9nrgcUodF4KZ9LmS2OgM2lN/FqGozOLjpAM4y2grqCxp4facqn2ypoMC3t/j1zWb0fOGNJTFVFFQ8Ft4FlbKA92pekljOgWwHVpdPkphQDtZYNGHvB4L7L4zJIsgYSmpCoa73AB45rYdmsRYks8WbCn60kdksGZKQ8Ya4svMwu0gA5NJfgVVPPLs9qYOR3QfIyMGcVVLF6ZpiLUt9y4e2rgd8abEIjHpUjhOVK7CtyRWdlfW4x9YHp6+eztR1hk9LJOLatMuwL0QBvOe2gHtqKKrMWIfusf/BR58wUv1Qg6WPn+OlHjcamxADSS/MYMa9Hzhl7W+YaP+NL1/fCUunzsPueh1YXF0GYj3WQznpZmFRUfBrVub3ukp4/UEfZMa347QlhmS8+i7eWn4TByOegJKUKF4wlQf7hdWgabGL4ZII2Q348feYw7i58jJ9KVHn+J9x1NpRBfW3TKDbdjvPTNxGj0LaqHJyJMXMeYbSKgpweF8ipkwqwfFTduCDLZow6e4UvtkwgcZ37sM1tyRwr/442mvry4GL9rNz6Wz0ObEVG16PgtuCL6BQtYBkpw/SG4UzqPRuP8/RXkaGr2PIqd0OpOEgdQqZg9+QJ1kfi+DlH/fxmLP61L54BR50dYLwT+94jYY5FPtW4FoxWejRGM7t2Y4w624OTarcwlQbBrccdTBKJoXFJCJ4ZloYPBPVhiiphSRVNA1GTKrCw4LDMeHsPWr+K8ZpEy1gQOY4/Ji9htalmoGN3kQa0SI+tMc/UpfOXvKLCyB36ZkoefETptw+ARc/+5FGjiE0/c3gj7PdOHu4DrgZlICrTxfVOy3kmlgJ2lYbSEWvTDjGHMFFfQ+EDLmq64HPuHqmMDyRGctrA9Jgy55mWM9tsFv4AO6S1oR/FvHwbMUIfGj5Avpc7TnB8APJVo1iDyPEhJTb/GCbFojIqMDTnd7Y9+stgeJkzunzgK4XJ3mZyhf85roAzD57YNXo+XBxzXjo/6qM5TulcXObM0fE7MXPZxZjwpVC/NC4iF4NMtas/0uHDphCv2AX9gjXU6K+PL6zuwvny1rJ1Wkslc0QwaqP4hDpYoqyozVBfL0C7fV2o1tdjmSs3c3p5Tfh004V0Lz8G0ZIr+Dgff78NdQcKtZfxJGBelQXoYHX4qdid850Nnr9hgUXqVPvIVFOGD0FvdqNYFZRIZxXcOcFZ9o4ZnoWnohazXUxDzg/qgPlDvTBMF/GqfLi8DzOlZJVs/FN7AaIHzmJH0tvQ59bJ+mV+gdKWFGCtf+y6YeFAjz87IMR8acwtkGEA2rqSPtNHDhPyOUwfXMamL4SJtSHk5C1FQT9EseEidfIf+RQjsYYcfwXdSqL1OEfUfth7bsxnC74A3Su6EHW2ENg8Mqe8qYT3rl6gguD77OhZAv9ijtPc/zd4OSjDaD/nzwMXBgH5+9W0sradHI398Nj25ZRZ5QUHpmQj41zLpOhUS4uMB8Oog9LwXTEcJZ8LAez9vqDxnZ5TvrvDZZ4TQN9FWXw2nkHn7YimGzW5AK3Ctb5FgQXViVAzeq0oTOnQFSdKVi/movGxpH85LQ8bPfQ4hOabnDg9RgOX7Ub/+id4qy/LQD//HlnSQ7kJmXxkvLxUAsqWK2dAednL8Ttx0/SxOpdLHPSH537wtngmBxOe3EHw7xHQEHnNSwSfMJaVhPgkaYl1dcKYUrlFfxt8gZVdZDaxS5hW6AuKIq9YJklz+jNiUp6JByDbnaH4aPMbHipf5TN3S/ysUvN3PpLHURbEqBi331s36BI4yfXsvWXtyR07BJOnNnP8icK8Ny2bXzMQguWO/SQ6rYLUDdnOEXtiCbhiGE03MaJ7R5thav/x3F5uIX49WH8O9LQENrapT0opdISskpIZSQSoaWEkshqEEIpEU3KVrKlUhoivySlMiMJZSuV3q73H3iec13nPvf9+Qh2ECbfhs6+Ib6PqaZepfV0+HY8eiVPB+1VpVQVGYrxRudh8H4WX5du5UeeMnB87HLckBWG6w7uI5eEsXBjRTUL6sminPM3AoHXmGtdxN5aAK57xuGr3ck46ZY5h3hF8tFVZaRSnIbji3bR9e5uhGALvKNkCp0PE3mpRziPSVGhMylzqSTqNrDsXDa+NJ7Of71Gh+ossfnlRJh6oh0v6smyzQZdPnn3B2blirK2awzKuIpCprIVftUaT/sfa8JoVGbXkpvclnaW8xznkFegEP8wsIPr755w22AzTJjVTZUbjOF7508y+BgDbVqJ9N1gDikd9sHKaw6c39iHsxIzeZjPLLx+wRDU5uhhqIsbPak8hVqKj2Cazk5ShjywdVBn39ML6Ip8DWj5SIOjVgwZPnSnCY7e6LbqHb45/Arm9x8lx1cXsc8yglNaRsFVbYBajf10474VX3jQTG+/RfED4ddY+2IQPkAFHbWoxDe+DTjHxBAexO2ksvXFFPzeBFxunwNRKws6Nf4KLlg5CNk3A6FQ+TBuyNaEd59lcPK3e9Qsdg1PFGkyN2hRteFi6rq8HPdLK6FNwgrY3jcSdGYPwESHEHATuoWX5/0ED/NzHFO8nIc9XMI/h/2BQMVUaPPWgJp5T3F7TjZP/pRNAqJFENHcQTcmM+jpCkH8ri5wODual9mOhwcj98D21M9senAvq7Uf5ln7LUBzyj/E40t5pNNDGjTzILO5yhC7Xor6PTvZdccViBpi58kyI7kgKgP8lr6CdmVteBX1Ao+/NgHTuD1wcGwP9Sd9ojPnjpM6tKHI4g+sm1QOp/Q9IGRsPTSYWUHL4Tis7wulCNeJrGV9B3XPeYHSGV1sq3LlnGGT8aVlzxALKcPMjjxSTLkIBfYr4c/rp+S7Pw5vBRbB7bY8fK8yEa3T+vmJlhTE5WRirfJobvg6AdbOtYPdcABnejyELaOJgpVsEHtV8OcmHWhS3c9nWneQfJ8aTFWKRQ1VQsvB/7s0RDzdACcdbuK9pcJg8mA0vFz4DOolGFr0gijptCdP0HkEo7tisO/9Hd4+5hSuHVphmpaFMWpCwDgPPs59gcHR++H0yFcsKyPJA4IBzLuuo185QJO6HkWHeHL93vn4Ues+Ne814eBxqvRD+hme3GHPW2pk8VSmEUx4dIYknixCyypBEnkTxE7ngWedPodkf4TuKnuyqN5wPrZVDIQzXaAlVIWPaiTTeN8pVJ94H/Z8DofMd9HYtOUTRYhVgNHgRMiGqTha7AOFHfemWEVZWnjHD8QOzOG9QVJgkaWCly/4sgaaQuTW+XDg5OWhnvfmibvzMe6pNynbxfGSW4vp26xmvmnqjh971aDTfB2ZnsuAPyJxPLLIHH+GetGBoD+UtlCL3Vr3g3XEC45YJAmHXaVROacD9YunsJe1Lr44OBEqerr5gtcgFyQg4BQf1DccBdkrNmKtcTbXvyzi5mNbQa3pNuZ9c6f5T04z1fSh3EY3zhUdB6p21bxEOwHLD1axV/s3CFDS5RaPmTztizMHRCnjzNP3WUFOABL2zADHSXOx+qEvlTz+D803lvL3GC98HVeLHx4GkIemBL/MF4cZaiYoGbKPL+TPpdrZitS60BDsD8xD5SoR0KjX4vZNA1xfpAqvg17ynbhVrJlyhx75lPAd5S2Y3P6etsqsBLeEa2iSqMgruqyg0eoXlb23hZdpx1Dl1JCPrTAjO8/dfGu5N+QbynCoXg4+UZgA51N9SCTeliXFZlJpyXJKKXnHkyJPsmfMXbTMrGYhd1k+MtUC4hxG8LhWC17powc2d1ayrNUAxLg0QEhNKPv29oIva6Kdnijs/dTAL9+t4i3pEqh2bx4G+vXgkYorsHzRMr79tYxT9kVx4iFNMFS9TVtn7eHnd5VBpsMPCy9MQfs6G9KdsoCVtnhD2PuR+Ge/OISFfOIJK8L4dPtBeup9GqpTNWh0vR4Ge39BybaNFGRYgE8PCMDyT8qk8MkIJUav4k831/JWs3LuME4k1+TnUPDRlWumDMPR96VAzmQl/RdjSr8lMzHzkwlFWOigLR5iGbVqmNH3jG5uLkUVSwOIe76EpG5J4h33WI4tGcvVC5ivCAtidOkrfPfBmHZ0POQn/1mA4ypj/E0LsKCiAO7s3Yorw3woUNyHpX36+P6+NNJMlCE6ZQRnDtrw5vrbMDg7m1NPzaExpvksun+QwPIC3V7QA6vnjkf9RBkwTHkAhXVL4fH9FChauZpXlNzGxm1J7LD0Pfe6O6Bvuyg4m0+E825/8XP9E44zO4IbnK9gYboj58pO5voGVy6xqAGs+01tKlLQFhNCO/4bDie1ItlN0o6eZJiiUJ8LZO8uwYb4Yn638jPsq7SAHwlKbP4sG1/onAKD1BRsPiBO6DyKFisNg1rtYE6c5ksacqNg2NVFaHc0hppyjqNj2jhclt7JNYve4u5WAXKJDcRRWs/pWZ00fGFVFqMBkD9lh9UuC7E89Cuf8FuCJTf/8PeT8fR3Qxv5fJAHFI9gdQkT/He9HlMjAO4kl5CeuwffObUFL2hu4LZ5abC23RJ8TkTDavdV+F/wLDb+e4wf3DgGN1tlYapsA+9wfkvnQoL4DIyC1Ydu4qfkL5zRLAKfg46SywhJXn9UlO9L7YJ5SvVUfdQWKvykYfLfEdxra83PMy2o91Y+Vbt/I6Mps/C97RM+XfyXDshOxTFBplAYuhEXmGzhPJSjd2dGQcwUC1Z87oZn+i+SopkUvjneCaItYhA7tZRvnv4HiXkvUdZrD7lFjCThv/Kw4YMd9ru74ZIaBXgbJQ5WlRvQ4VYFrS04gU8vD7D9w22weNoGKCp9joORyTQ35CnPbGNYLmaGN9LdOa5Kn1r/XaONnrUY4t4LSycG49Lud7Ap4xwYWY6CjxF/YGb3aLbYqwuvqwcwb7QIDp/YxRuqYuHj6RhQc++H9YusoWBzDr03LsdnL5wxumMLFeidwrlrI7HgqxJMO/eMZKYV4/EuBGWJWrimeJsndt5Bq6I5UCvzhueHfeJvSdIYdiIV+Od5KPikDc7np0H/0mcknxpEt1bLoa/pTZp26CdI9I1FO+VXPNx3AX2wFIcHZ8NRofEgDvx8RX8/pJH/xId0X8UGGsNlwapNHQMlPlHSSSEQm7qT6GoOVU8/ApqZQ/eyIBW712qTmZA57ZtxBn/pDtK8TilQ3RlFK5O3U8lMYxrdb8N5AfZs7SsHDW4BZDs/g2dFO1HbSnlw2/mAj83owQPzj+G/A/0o/6OHRR2OcWPOY36jtZZ9X6+ipPN2EHXsBmipSvB/3/+x570SmrDZFtuEBVl9zzsyCx5LmyedIbn5kkCbpsGXXXvh0hLiPy8ukckhWdZ+uQs+Z/6Elaqd7Fk5HfTCDGGzmSRtN89HvU2XOMtfh1weZZLsPjUsU7EkR4s9sLnDAtcmy4Ljp4eQd9mHBFoaKXpgMdrVH4Lk0W954md9nu1/AIuEfahfQh30PiOdCDyA5eMrYV7lQ2xoDMYtU0qoQ9Cc23vKuSs5CvI2ysPPL9/g9qAJFUfE4cstF1Hv1U/+YN6KDaMnYui633h6uy30dquAzIldWDzenf/ckOLEH17wb9UyPBCfBicEdShwbQv/kBkODvOMQd5TEN0FLnCCqwM5yi2BGU/Og+Q1J7RZEoQSP1bj1RwPvlEhBtYbPCj990bSv24LuveyQHbFJpjxYDqa6W/HbfvPsFD4Zfr3SADEj7yEnBHn8fcPeXgfa0HD2yxhcIw/FxWa86JRyfgmwR6vqqnC+VJvyB7ijlX1HeR6sxyFWu/gXvtYvFtZzSp31+J/542wSFwYbsfFQHb3OjRYlowjY1aTd1EwB1QDyQaH05bTfTTJyBt5jRxcWxaL83+IYd2kvyx/whN3eDnherxDu3y90VrPF4YJq4NjjwSMbP1IgdF19PCSE95rDOWTWXo04ddv/KavhzkOR+hapRkqC4vCDGljlIk8TcXPMniTuzB6+VzA9rqf7BvZjnpPJvACY22akqwBAuZMjwv3c+kJAzR6EA75k7SxQPYg5Z36j1hKH0u+RHGWoRaMWfGPzUqeYnrsC4I5PvDPRBLGNVwhg8GD6PeljVNmWnE+2MHw7zthkmUXvnAz42yhdCiRcmEdvwHWnP0VpW0yUD4hinXvSYKAbAYrCBihrmY5i7l40tjnGqx40x0fBNxC16ClPLzLE2fdHQ9+KvPZpNCWG+QvU9RnSfD4q875UkvwqfFI+jn8HgrYhfO2eC2Yp7KMTVq84IP1YraSs4aJRt9gQcJeypg9En37j0JYlTnZrbUF8yH+rY7UgLRN0VBe74giqTPh+qkgmD2gi3vW6MPb9DyWWywOHibxmOR7A3+u3MUai3fxsSMhnOY+BQdhBQocacKxf9Wodf44mKe3nC71i1HqfG0+uuIlt32OwcztXqRx0JM8NMLAO28bxi2yA5kuEX60fD5Uu/fwxMCNMNqxCsd03aXGUW7YpyVFbxbfxTkH1cFhRAbuIEOeHaHGrZdsIe++EBvYDfBLJSfomyFEabOkWTlKCGwqonmEbjhWvF4F+5RGwf60x2T5so4+WEVxxJdPdBwycaOTMKSInKNF5Zegbv5J3Dq9jo5HJPGFtlaU3xlMPN2F32uKcu8aDYhfv43E13bz4zQxGvH1A8vVTMD2hWvQT3Ae1f9Ngh7JJbB+rCEkZ3zmRnsPMC46waeXbITllk4Qd00KNy3bRI8Oy/AH6c+4WWYc7Oo9zp/CYuj0lS+kEFRGDRUfeTBsDecf1eIVGy9Q3oFUlHOUh67Z2yh8UQS9uLiU4t0WwY0tb2HT330YZREGw0IfsXGdH7y4TBCqPxVvCiexXKI9qzV1cIJJE0rhTRo5cB7VG1qHrOU9iq6ZCILpX3DPf3/I5tp5PKBSikItYeR9SYD8T7Wgy65k/Dd0XnkRASiYq0Z1M9M5+XMwi6vcB5f8Irri/ht2O3XC95c74MK8BXzN0AbGfc/g4f+UYZ6uASa6DVCSzDg+MymMvpaPhW8Zk/n7vng6c3AU3Cr5C8tFF8OC5b9pptR+HhyTw2YpMjTu7RoObE/AsSNjqGyZBMhHLObPwmZ0ZtAYpAWscGBcJ521LicFNKa3WZewwc2en7eLwX/mOmCjMtSPkZm0M6SRJx6O4F3Pj7NedS0NLn+FY34p0ICPOdySOAfWIUVgbxGHBy/bgmVZNjm/2U79Is/Z9FQJiizQxK09Y8Eydx7ePOKAu0QV6EbrNtib8JQ/XnjL9Ys/86pAS85QWw6C7hbgsnMVm49ezpqlruQikYu5haWcuewYltp4g+yu65xaUcEdH3VhsOUkH62WwRz1fNy+bD1o3vTkDg7EK4qjad4SH/qa+wuXPjaFhptu5PrJjO+KzEH9jr84P/QuPNs6GVRjNNEg5xP0SYTQ4uWasP39emqNSwNUPk92W+bylRcL+dHADswf1UOLlIXxXPQbnmwsDArRX6GvYID/BhuBvrE/uLksoUkLF3Pp1IWw20yA526ZhqfFNeHniFs4J20xXI0dy2WjbGBSWT46CjnBTLWzrH9rBKqnNJO7oDrsHBnOxtkCuDGqEgpXamKgoxPN2JHMrumu5LrTHkMvTaGkVFUQKUasl/Ng18B9OD61Dmw2BYJT5xu4vNEeykdex+v8Fa1/CoFXuzcadm2nwYda3HFtHNoF+VDM4U24+2QrLuiVRBmezF9qbMB+6W+KXVrKeNmVr6zZyJ7PqzBbQp7UxhqT798W8AscDtPKDIbYYxWq9HfwOzdjfuK4C6Jve+Cxo4VUZN9LB99GUEK0MEQPZeXUXlm4q2SAkyPi4FDPJ9SNXQs/z9uSjtEqODkpgESPP6AN+qIgPU6S0wbrOGJjLGQue4BKuv245F4uaz024sHGGPSHNdT9SRBC/PNw2cUhFx4nBN0X/1Lkn3R2dfLhS6nvWDFpGE4UOURnleRA7r9nJBlXzY7P7Sml1AIy/9rQw6lpeNA8kT+F/uN0wSKK+iIHYqtHMolPx9uvbPGL/l/4l6FO64x06dtBGb4iOpE01hyD00ka8FemHNYsCMPhe5fyAQUbbrrlS84puVy5NhFVpewh7G0FyXTrwSK7VNwVIQqHp39G+SOZ/MkuF0sNh0PJg4scveArnnv9mzQXToBGcUe+ZLuAco1K0ShyEuq7G5FX3TZaqrmTv02IR6fxueirYgznlSzp+7njMFeyE26WfkA7boNHXs1woKEEbcv68a12Pa6INIeptz9iv+ZH+KNsjuERTWCoZ8dlcuPBWO4QWHlZc2zmYpa9YQMfHEdQpmojz3Ir5bPu+mycZcnO99fBpqrDNE83HyOai7n8pCmsXOtBgtl7aSwvRXBdQa7j+ijqSRj2tf0m7wOB9PZiGUodtIYv1ZNRJPcZeR9aQo9+joBvHwp45fkOkL52n8tGFuO397dIr0EBpkochdK1MlimXUcWlT/gwUkhjDjwFmKft+JC6+3g9d4Y7mWKwS1nA5g6vAp2mm1kgxx39FJexCmzr9MXgR60Mtegx2lbcFiOBVS5W4GelzZn/jpPr0zewomhDTo66zEVLd2NjXndkPTElx0vGME/002gMrsB0lARpMblUPDtv1Tf1Imvls6D18am8G3H6KHN1gITTW/Yo7gP9fVVaefrTM5fUYBX/4Zj1LxArjOLxLnnDrOuigWoLzKHN8JCVN2nSx6bx3JITjbdkthGG998pX1Fyzml0AMvewJUK+ynnyEn0al2PhfmFNK7xFW8YIk2XtcR5ntuSlxz0JTtBWxhpfBBXjZsNy04dA9iAgEW2UeQ87MjdLvjO+nm+dPxZIC59SKwMmMvvNhjDF3mW2C2ggn9iCzmXWGj+YKzNpfvXgQucg6cGjkcbBreU/zMAb46XQetBTSo6FE424E2TV5zk4z8N3PKUSXWva8EM6q8uT7gOrdunDzkD5l8qskMDS/mQR5eos7N7ezq7IQNU+WhoPsjf1EqZN3KjVQa4MpzpDtIZJgBezsGwaVnhjy/yJUnKQrANM8+Op1rBVt+W8DGRAQBtcXkPzUJx89/C6vN/sHsCf2QpicG6euYh38ZxZMix/O2uaHwYJ8Cyx66QsWpl8GY5GlkNWJy2Qj49MiQd7/NhVrbkSDw5RC3qtTyC9VM2D/vDC9eo4LTU7bCiE2q8PFOMBcOxOEkp2V4b3cyvJ0eSEISnuxZrkw1j+vB42A93Uy2hIzHRVi2y4cHzEZRZ89iSK+wh4eFbqRmYEU/g4Ux+u5bXOZmDhclvPmxdwoOKn+j/ulLsN7gA08VqUKXRe18PO4O9M8ZR1OHPCrfogEDyJxftLniyM0nsHNFCC53vMxj9kXChylW3GWxFX7N1YA5eWdJd8UIyoi4jycbfmK0tj/rqZezlkwr1WsvoYOzitlHYwI8jM3lnOgxdD2vkO/H7OL0Kb9wln8q1SyahJq283njt6/kFyYAZ87Wk2NwCEfmGGCY0ll49nsxrKmthQVztWicfCpURG4maTaBt6elYZ+TPd8Ik0P5zV3sU/wfrzNugaLaThg8OgzoWgecXGEAISMtaY7tUB4DHTgmPpd3V/0HAUdP4XGtp1SVacSrWysofzND9oppkDogSCW/RGnD56E92uIPNqVT+bWAJX94PopcNeuhKFIKCod9hujpDrBjoiw4b19Ikpf2o/vfhRAk7IcSbyyh4Mdc/n1QFw4SMc2P5kG5BDqj7gdznnhicuU6WCO8GrqfxCGkH+ETabaQ8CACtmQGY1KzBqYfNIMREzMotKCKb26fjONH3ybMP4nmolpw+/1kaIvLZAf1Jqy53QUjkspgQaI+TDI3wGnuH2me3Q5e9GEiBKhU8AY7XxDuvoGm767i+feb+HW+NqTeEOEKBR0Ye/kzFF7RBcX6Jxhb0Mu/Ml0YhnpTQ3AQJSuWY6exCEYGR3NQxXB+HCoDyx1f4TdDR7h5dCvd0TzMq3JFaN2kFXyj7ziYGCmhos1kWBVoBxddY1nC8CvsT/qLQY8VUdD2INhdAbC186TNexzpsMQ3jAgVAKPlLnh0RDuPvpxMk53/UOqeZdB6Vw53fJ8FypKn6IPEe7SfYgSb1t6AU14S/E83HkXu2UBH11VarmHF0zoq+PujJp54aDPPniUCi7IuoOm8Y3xmSxet2zD0P1dfDu4JgQHZCazSETDUZdKQ3KIB3+Ov87ulnSByfAZlaVfR4ZkreeyUQA7e4EzGAsL0oGMR1EWNAPsgOyxbXw29P2tpy8VWtKqpRbfGXOL4Sl75XwR51tbStP1qEL+mhAbrCyD5UQ1+nyNNhumakKzYjFc/e2Jd4l3ccaCePJrHQHXfIa6TUeUFyScYIu25K2szuQp7kKTNb+46G0YokM6NpQbQ1JLK7VuiuGODCZeE6pOdlDRkdw2Hiqoc2JyZh5PzwmDOWkOIsCulQPkU3lf+mEPO98PI6FnYe24OJLd6Um9iIcZt+YRPz4iD2zI1FnZ6Do6Xvw3lcxMsuneR06VbeenGXJodLAMJEUkwvcAW9nwMYoUNN/hD9zkMbvCkn2MCyCluB7kED2OpnqsULRLKi0YIgsuRg3B6wV1Q8NyCC2YIcYXcG3qg/AF9CmeikJULrTtRQemSxmDySh2uvhzyZpHzpCu7n1ZYD6fUeA3WnNcMDweN0VjSnMpcAMqH7uKM1mGe2ncKBeRtsObuEQ4I1oYRtfY0X9YO+kQAer1UYVVNKZ7vvcRvcvvgn1c4N4wMwM1CByH4lAs4GxTz9fNOsEJbAGz969Bs63LeO/cBVPS7gPFuZ3QXP0IVzsvB/kQIiGvX8bd4QfCbL04ecbXsZ1mG8s+l2Em3Cp/HvwC5+eUUuf0ep0Wm4/ZFiiB0y4GTjlQiLU2nswblGGbrxWV9kpB1zhc9k8RpyaYJGOllC6Gan9m/0QVe1zSzxeEUNJsfhg5GKWzyXzkXBz6BpUJHWeSXIPSfF+Nbynv4V/10ysiQROnpZ6lN5Sr5793DhwKtKMAnhj/7yoD0je0smyEPgf4j8fwUZ3goPwKKDHppao0AFG89Bme3VMFTLWPwFFSj0c2eqPpnH3WPcgZJGV0+YzUCnWTUhr6nzlkPNtP7ejOg4GK+4DgWL3w/RR4Kg7DY7heMsVqCL87o8+PCKKr7J0qgqgS17ZsxpXEz3TO8CJ0pO8FLbwbnBuTRpUZZrK2YxXNaB3B89kiYs2EaT7KbiVUVihCyUYeChZvY17wGF4qdwgu74vF9RxpJmdjA8bBeqjRSoZrej4iD1fgzfAbde0Esd2MWB66rYWfewsOvycM6Ax1yrG7iKYv2sYjeY4jUmAV/Xk3mry21fK35HM0pkIa9/cNB2fwKXTSMwLuHH7GXkgJ0Z6RCl9wF1rjdiJfiKvHxt0tcN20SNB2rx+5yLbi3YxGJjzuFompPOGTGcrg89wxZbMoko9ojrB4rDW2ROVg7YTq6C2hgd+p+fHrzLr9ZgzzWvwhLHUbwz7EyuHEfwZr3ClyyqJ6DZm6G4ouqcG27PqtO60anjAPs3y+JHqL9mKGsDkoia+DZgkAQzLpDL87uQbv1MnzxUgLGpJ/jc6tMCRZf4A/BBMa2ubyifREfIxdysSunD+vLQNI/BN2fTIRqqXQg7Xvo8FMQpqmsg7TZ9bRf7hJrPd/DVg3B/K1Eiit1IvibTSo/WO2CKtkIuv3LSGHIFeaecYPFKQXo/E6fVmzsw6r+bk50eIsPhN9RmPlosF91javf7OJ7Ys6gN/AUR1mW4mBCFmX8FYfqxz+xdaco606Ug3Hv0vhUPaDrr07672oL7D9ZCvO3iuD8za9w7dunqDw1jRXvAFTMb4eD+dKk9WEk1wbF0+2HH2l0kC36bYpHCVlJcD5xkktUJ8HNu0/ZMKqADYMNWUAyBkN0d+DytCTU+H4UurRbUO7yd5yXawi/klsoK+otx8YbY/NNd/AoPMZJPbOhIsWKv+27h9bjEyDExgyaxvfxKu9B7jdEPOuUSo6Fo0hh9RL8dXwPl7gPZSm3CJNemEF71ydYoTSTC0fEwdvnwynv1HTYZbqe3osl0gzp4xizbAE/KJcBxQOXcf/jULyxTY90SI6PD5MgNV9/rt60nuOeZXL4eENssFWDxnli/OpdAUW+OMqHNhfwpsN3+FJQCj+57IY/+vfSBn9VtL1gAhcOXcV3MmJ8R+MJ36sqIe/F1vjxzwzqanQYehMZaADh4CpnB8V2EWw2kEGrezbRV431MEFHiCNOmrKfkjcVz43Cq3EmtLBdHi5Ia+MPZ3OYd2oxPxY4yE+KhCBs1CHQ3+bBUxpTobr5HTTpmYJoWgT7x0ZivbENHov+A3uLEmiY8Uo4kJdD70SboHRBMe4NGAYOvS3Uk2gH00/vhhGfn+MM531DO6NEAjtU+JnZFLiiNAy+/rWD1pxZYL6jAJs2fmTB3uE43cuS7k4qxqRx8ZQ85gamyL2jcFUD8P0Xw5tvjAS1l5lYk30TL2hOww7B2qHaFKWktvfkEWEBDcnSsHOhEcT8smDbvS95WO5WNnWv5HC7X3h2qAdW98+Hh8edqWGsBUjvcOePlbMoruAl+wlfg+mDcpgjE4I7DS1g3KgH0Dbwi8qyVKFafQs98LMjy91TQLfBim1OLCFhj2TKa1en+q0z0XbtUfQqtIbhA595mJA/VdFbthC4CDkdo2j1WRlYnWtIU0x1eL1EPCav0oPRwXbQeOA6/qXVBGeCcIGXKt6KccPQF1fQ53oT6HWKU6DyBPBX6kBxz0d08X0ZGN2R4MPjV6JvqQqWahWyy9UoXN0yjQqn6kG7znUusDxLjiHtZGy/jeWz34JWeh3EuGjz1qB20tObDJdcTGHh2hUwLb2Et+U48ZWAAfYTFKK6vLtDvLgYz1w5j/LcTJLd2uAYYYZeB3/Aw13jaMWiDDqkf4GaE57Cm1OvMclqK9fp5oFBHUHiZCfUedTGgzYl3GLczR3h9ThTJJCeQiGHmemR5MovVDxbAvy2KXHLUVtcovYeNed2wdTNr6l5zxRc5XuDvq8uoKbxEejbMsQlYV84d4wiHCs/youF2uDQ2h4qPCzChbfSaPKMTghwc4aXAtKgqjYW9cYm8K9RC1nmiSb2XbSG70904L9yW9ZTSMSx085Rtc4EmJMxitcu/gHiaXfAqHo5TNnqT07YiAvOT4D5v2PArV4N6gImgnfVAShfYU4tNZup4qoxByba83eHVJjd6ctpF3Lp6eQsXrN2LEwInIhrw1r45pQ4GOU6iWuKs1nccwH7+NSSUslffpcyi8LO6kD7l2wIUlLBxtFjqHlGH37c/xvuVWfCnmozer36JV36bMlZXwj2b7rMzcMasL31Fmp/7uVrl0u4WTmbbAUicWZKEIW8csRkXz3Q3x8K28t2o4CxLX4oqORhpzXowozRNCjsj7LHm3BOrwiHBVuD9/FUHPnnEi11Po9KFVM4PCwHo4t0MSjQH676t9LDlWbwYZIprDPcQ3uV7CkzoY+5w4O1ClZDcKMTvzzgyPein9Mew7Mc2i0BXouPUq3mcPx6F+BTlQSPfmRJk13a0Y2EyevKTH7k48Tbr6jBgUsR4KOtja4t5+jO5Ansl5YHO4KDYbZ+OqaudOa1a2wxoFEMEvXv8O9EF6oUvUJ6a7UwXbkBMbaGareUwx7PRSC78AGJSVtB6ZKz4Hw/DPPanNjcN5b2OhJm76iESx0P+Nev51ToP4kOFIiC5KOP6F04hc0lTnF3TgX8NP5Mjzv8cfGad5whno0zEkfTcOkRoLnGnzSObIEFuZdYdeZeuMmGkLvvKm0NiYQ9s25y48JddGKfIrx7rohqw9/DxHerecL1qZwbHQYZP9Ow9vIgxW/4xpIfb2F3vgWMaWzAk48CULB1Jngl+/NOgdFQvSoUs1J3c7OCPTidfAiD96TAc7Ul7vGaxT16H3D+aH3E6CPgr5yOA/dT+Zh5ABst2EPijWPA49sWkBqzmjVflUFr0mL2TT8L33das/m0Vai6egqI257AjPUToXjMYxxfyTRN/CEpm9WwHt4A7f16GOVizFfLz6JwhDicTh9ykIiV0Lt5I5fYCmH5em+ISg0go5J4DA7yhoAvS0nK/wJm/TSBujYfuPi1iGixKL99Pxdnar+HJAMzmKExDo9pm/LRz1GcfEcYfE4Mh2P52tw7WYlnXBIC32RFHjfbh46PfoRFvccxc9weSAk3AikTHz60RhnzE17jAYVXKO+exQpSf3lZ8w+YZPSHFyYewdnuqqBUmMI+Tz9SvvJZnPjOG3688Kdrf/6gRIQud87U40MKc+nR9TGw6tYvKJzsDHMCbmPVrxbKKN3Pk2Y8YsHX8fAdvsL1sF10uFoe+iT3oOq6mZhcVMS/759C7Rcn0FS6DKz9N+Nv4VAsG8yDytN64PLtJgxoB8Hf1TrQ5bYN/PzOc/KJy+AmIM69UxLg0dmNdL1LAq5+tsSM+HvsKf2V6Lgv/3G7wV6/e+h13zacMcOS+PUIbrojCgs77+HHbRJ4Kf8uxV0sgdbMSg4ZLwozDZfT9Fv1qDk9m2a2SEIeC8OY0PNkPvkQBk+ZTCXdGfz5WinH9EnSoa/r+MLVcBhtaQEjvghhSN0PKjyayO9ijXji4GRc9iuf3s4W48Yfwvz87HoUs5eD4ZF1rPvQhFWk8iDz11RWaiyC/vZ5ULxxNoT455B6mhLPLWfwfrKTP29yo9mXY/BpvhBvXZdIs5TCoEl5N8vcUGerrN8gcWsYuH7q5d5depBwZCP9d+oQJGEfvNp9D64/WgKWnIu9bhuwfmgT6XMsrXURge6ce3ymfT08PBWC4TvEQdJbEs95+JHz8XJwr7KCV5IOsGCaND4uL8bbi+ew40UXSHhpDPPHveSpDrfhD6+A1h8T4KeyNAv1HKH102tRd+R1CC8Koe12qnxzkRvI7w/g+eHDoNFVEt6miKCtyz7apf8fqwrNhv5/3rym5ijmmFaDoIEmSGV8gxWXxEGscypumjqWTlUXgKn8MrAeJcn5pkrwaHcWKMm/gO4xA3jjwzh4cKITThsWg0riLcpNU2CpJb2wLrMAS4s1oMtkOzpnT+BPyTpQm3YANyqrwRvRLNqiGAm18AUGHvxjCquC+oF29Ezfg+9yBeDtRx00iHkDxR+fYlHxbDYYo8VzZD5SS/pNirVK4ovhyHdPSYBozCEqjPXEPNyH2Q6XKFzjBcmPl0d73QD+Y3OY3p/7RG8ypOFOnzYbxb8Gh9I22CNkyhlagyTTrcvx88QwVF2VxQaqyG6eMBwBHUqwsqPiaU/BuWs1nlObQfM3h0G3/WPYLF4Ml52F+PsQf6k0JeHbG6OgOvQ3GkIlReQ/oWFjK/C86yL4/vwXvF9oiCuSR0LdrzH0eNlHip50l+rPfSfjH/a4pOwJRZz+i28c5bFB/BK3N1tCcM0UqEnfzK421pSZLw3vIjNhjo4WXrC+it5yw8jEeAV5bJOHX7XStLL/KVcZuPAI1262Cw6DGKnXFO9XgpvtzqLiBxPWbR0FuyfNx9ezdWFDsS6K3bXmuJ1/gDQeoldNAY+W/MLPf+9EvqUIupGPaMzlCKxKD4YzDQm4680/qjFUwiwZXWr8dYK3pjSwqhXAcI00SEqzppPRk/jylTEoo+mPkY9swftPOE+q7Kbtz6rAbPw4ODviLUdQDf/uWwYfvRSot60aFbSd0HSfK/6XqIpduAP0LkuB26xa7r8nwpabHLlHZx1VpgSx9eZGHF9WxmX5eXR9Uyav/2/IA7cdgXbxKp4qmkxFYw7gGeVLML1BH+Jsd4JWpjlWJYwC8fEqkBlRi5LdVVgyfDWo2tZihG8g7/XZT5of/oPHOt/hhvV+0PZSBck3E/D495P40Povu/54wY2jhnNzkxkvuDgX3po7s01/MkwRUQQ10XU4r1MT0oIX49EsE/rx5hp9rU5GVetT3NERhFsmTiSFm1Lgp/IQM6a/Ib/vehxecpD93+eA/bmjPGL8apgi/QDz9lqgUtPQlqVvhltSZfR1VCgrDrnq2jF14Gpxg2bO8oX2uAw0O/WaZ4xUhGvBvXw29h/7Ov3kC847YJj2Wh4uOw55eD+eKv1Oa/qyIWc+gsSdnKHdvYyCPXNx+sPJEG05D0abX0ODkT3UsfogOwwxdVyBGnQmRJGR1WcSUmfaG6rLfoueUYXcTho7N461sg9hVPg6nCBrDA4Nytx+9BZOmpGAo87b8tya3dCTgGiR5QkHp8wk1cRIOFCJMD7NA85FlHGkzBU47FdCCvt80TC/ghYMWwdXpZ9QnmgRLFgrCgcLZ9K96+1cHhEN1+g25e7/x877zUlBKBI199cQHE9gmWZJuHI8Csc92gQjHqjC+BlFWKUlQjknRvGwst88ds81fHFDgfe0yoLlswswrSiZHgkwSrjPYZUHq3jTpMVkUZQIrzb9oFs9s/hAqQVIHI4BlfYeytKL4Mdez3EgvQlaWgJA38gcPlc08GdbObgTLAMW39/T5l3O9HX9MPpXVceK1bv4NSRQva0jh73O44xR6yjMUhrm/ummff57aVqaFleZrYAds59Dz+BGNr/ymKVXPGG7H4dpUrIxlLycwhtChnzx0VtEzR2QODoOpydo4rRv06nqRCdr2cqhdaIWuAuVgvyxGZAs8JBtW+Uhye08nLDdyh7ulTSQZoavfEvRvXAU3F3VzreLpsK0f+v4p04b7h/Q5L2uZ9HPNgdklcvp1Z2tpJwkA58dbpLt90Y2yH/Ca6SX8otPTewrJcWm40vhdJYWby0TRu8fEnBb04OxVh/m6k+BXdlatDLSG0bOEiDlg+Pg4Kap1CH+i5VzR0KukB8mDz6FZp2j+GZtIeQLtcCXp7osf1mdBran4Q0xEa40N4BVY76yrCix9gZ7cJy4FNy2lsDDmFgctssJupeY0n4bXxDfoQ8RRsMpTVcF9FZ9YUhNhZHX91PzZjl6XCGORR05VGgUzWoC4nCsNR7e2OZjTlAzxd5S5hFxKaw/sJzKvJPQbHY2jFq1klwNrSD2iBTMGx1PRsvMYWdLMGxTHsvzitZyDenwjgfhMLPmM/8c8unZnaGwe4UCzxn/nKZIPMGxex6AVdNmaIuwxQWmKrBynwb9/TcJxOok4fQjB/AbMZbSDz3Bt/O7aeKDZ/RhSy7bPlSFL3OekNZVZVg3oASbfn1lgbtZ7DdCEqRK1qOtaCc+5BhI6G6DXI0DqBM3HP4E/iGlNh+MqljHhds00X6HEc+MH0eOfmW8NOAqDMzdy9L+InA6LBy06qbj9fQDvFo2mhdOKONXH9aTmf9zSla9zgt+RNBmEgGV2ecx6UchTlFURJkRa9Fi9QCrqH+h8q5juE3KnAuODZCpryFUtE7C19MWw/P2APSbfp0Pz3/Px3cXg/Sk35x0NJu6WwQowloFLhYu4M8F42n0gDOhqxUEXgpmncnD6cL4M/Al5wV+v74JSkusYJbYJJRQvsxjBQug8sw7rOvPB7+x9mRg3MduTguwLTGW3KIIGhcq03Ll3di6fD/s6gHS3vCT738Thw0tT/mhUhcq+zDu3CgIyS+WoNDvYr687g5NWUOcJaPFv+PSaEPHryGnmQZFoR78WVEV5IYlYIvkc6yf+5zNsxRBckne0HllGJZpgY+rKreoJ9LuKGkw9M0FXa9msB2jxK/be8Bj0hpUPB5K7p3PYEzdNZwdrwZ3ZmjDXYOpLLuvh/ZciAXXGAcST58JrUNMKv7DhhvD8qli3i9S8RGE/Ub70eRnHwSnb4TE4CyIU1wHP2qiadOWE/DQ/TQH4w289mAM3K9bikuz3uD2cE0WOKQL1dHPUf3GRoTbR7Dj8ht4dwH5lJgR7NiYQyE0k5aesWX1E1YgY6SNcuq/KTDbhn33ZqPx5BAacLODp54JIDwsiQ5JryK5wGeoGtRDUTptECXVxEHvB2H2kkv48ZMQmBmfpvLgQpglogmrHMaR8IljqLrKiS/rC/MoKSF6e9IOrPomwJ0fN2gsIkvYVqHq6WeIAzp0MvwBV7mcpd47kWimsQjySmzAViUG78pc4UKZVGhuicacrip6Jb8azhXEwxxpMc4abGcXN3EIKLpJzrs6KWHjCdrxzRpFtf6i5Jpn9CnFhb8ulYLvTSZwzccUngomgGGqCjxK0mL9OkXetUKIeE8gXYuTxlSzzfyn5DwEGsmBhOMh3PtjPfqVpOP9/oU0y+gkvz62nmK7rVH9YyiWv6tjtW5z0A52ZAe1XzSl8hxHlb7B9UHCPEtlJgS5VFOM2Bh6WVeLStvF4ItQI8+9D8wuLymydCJYHxKmpbJVvH/7ce6SyKBbK37iCjNFUNnlAAOTPGjgWjM9rImkV1Pnss2Pm/DjkwKndEShcqk5pj0DOFkvzypephh3y4P3PlbFs30LoMDlF28dN4tKM1aD3zkhzI8xhWfvLvHLcm/sk36MZe4V+DpKEdzS/DH2hg95jzuPp0eHoUHRcDhcKcelHnas8dWGpgQ9hvHTtmH8tS/cl9VM1xoLSeijEhz0GgXRc09wQ54OxPsM8r6ev6Caogu9cj24VvYvyOe9p+afF6nBSRhaHpZA0IlETKdzZJf5G0ue1GBg6x7Y7rmB0y9chw9LFoMAjoDdXiosyMdg1cmpGNM3nHYlX8D/lB6Rpv93LrSIo6tCozn+nB4c+r6QdDbtInf72WxZ9gXuh6aw4JJQmpGylB78YKw/8JfVv1vDM3cLdhR7xW0BJhgQFYa5IfmkF6hHtwWRdn/Qo/7Ov7QnXwG2TdemcQaTWc5gI7UIZkDu1UGsLl9Ia+fVstAYX6jrfI/eX4aBnoYJ/X77Cw2DFGH8iX1wdac9h/+nTQcP6PHq7gB4XgmsfksY6nYwbhCYhUs3XCbJW83UFeCH4vFfOXvdYf461xVzp/mDbKowoJwyrbh6GfSfZlLT5AiatnEKfo3UgC+zhTlB+Tf1xCYzJFiBqcUnKtjbCMvbBkhGbyWqXWnj0cd0IHLiBD5vkgrnpC4TFGlC8lqmux+38Nm/ShTxVgWMY8xgyUXEIyr5vP3NX9rXFMGtyXow9mgfXTr8iVfZ7sNgI3Hae0OLbdZ7Y/jYsXRO9DnmmxdSqaMuqBf48w095qJmC/x9bSbM2X6HvGU2c7tDIsy5eho7FWdD5nEpKHf8jstGKvK9r+E0a+IWnPxMHRIKbNiI6zjJpockmzagcIc6ZD6fwSZt07n4gB2tj80GlafPwHPLbEyu7KK+yiOQcryGCqImgfqOSK5wWoRpHxfBnXwzfFnwF0UM5UDR8h69yGgAvR9+rHxFBaS7xMkwSZsfS/xkwdP6VDZXGGZ+vELDTqtCXcx5bp43Dt0/DYOoUl9MkpCm9IctKP7RGOYdvY0OTc/QWlOQkws6KXhZIJ+dOQb6Ng5Q2kNX0HO9jxy4DWJz7pNmUwkLTiO6kaNFM+IDUPWiILzce4O2pmzgo6d8OKk9lRfviafY1Dcwo6CHtZ5rUn70LzjxVAJqdPX4115T/LPWlBsuX+VrQoRPf96jxvue5FW9nI40C0GIMMLLWDVOVTPgvWOX4oEyBzrnvwNSH7jQoY9lMMpMCaN4I72X1IJNhxVJxMuCH8VJwAddb7o9uI661bv5y9lYvHb8M3xI34Rdb6zB5bcRLZ4qzVbrnuPknlSSXBZICibK9C75INkkqdH14d845SyB34TJkGb5HiZelITLKr8oliuHchdAxw8L8de7x8j1gD5Ml7ACdc8iyj6nT91tHTTgoUgZznH8n4YWSr9PgENnF/FELRn2vW0JDQk/0MmgGuYEMNfWilH30yw4tOs5y01RwK5Z4dRPepj8yBIWLh1DqCqMtUq38FrvNJ5YeIMf5FTQuTWylDRzAk14QXinl6H3eTcWh4biIzMj2rlCBlruZIC5+SdasnUcqp8/xCtzpsGyCG0o/fEGNaTqIbz8K36v0KN/Czai295z9PPuacg/KIzLFguzf50ZhOSr8kehZ/Bk9Hs+rWuE5b7fUKXTgnuT2nn7u/nsH7CT6gwl4KpHHE4+uRLEFAhLDulRUqQ5H1nrixu+psJX77V0uOEwVvYIASbswo4tDai/bMgj5TeAjHUmZZkfJO26S5zYcQirnjbx5GXa0NUTTVp+rrAzYAlal1mQ0d+VLLA3gX6OOgzDLObgqTvCuMttEozQyR3qAXXe2HMYTxWGgP1rtyH334Zb1JgTHURRGLr45ApBkNSqwuLJtXzv91Q6kepN2cWngOzFMFHsBqhUesF8uzYc2WkB9zIU4GFCKR8W3QEDRaZwqMmOqp47YXBJIa/d4Yi5JfpwutAaxl72JO+SEeyb3cjZhxfxxeEePD2ymX4m6XGOggY9u6gL5dNNQPK/FICfS1h+6gfqSR1GctcX4HGd1Xi9bCTbLzsGksn23OVlDYoj39Cs+TJgqmdNU3UD0eHcNv5T1ICi15zI2SkIV60yB/8WKUi5/gkP303FhWHGFO6xgiX2NoHLvlSefzEQho05CvOCqwGEx8FHvwe8OHcVlFwyY5/9J1HTO4Yq+jv4Vc171vE5g/uyZXnWd4Q5a+V5ZPQLWmRsSp2Cjfzaej9eM30Fs0+Z8lWYT88L5pFmyBj48bKNtg0xWtvjgxhkV86qslJ41Okj9MQP0NnRz5ANzGHibkmYJ3UCnY+VYaDqNBTasBKWfp0LN+YVs2TXaW5Qi0SvIx7UHicF0b0GuPWGGQf4/MLkF26wr8sFRjTtgKaJx8BKKRiLLolDwkFpaN8QyCbG1+nDRAlIyRmJ27eZ0nadGiyr1sdOmQya/i4WRm8bB3LLX5O45wiuaQnDvxsk4dDKHJwWYgtmV0LxyL8MnBDrh/diRwD1efHXqr+w1+khhPR0wIa8WbzrWz/5Zf9jLYUHaOPsyTuKRoOZWRD9leiE/tmP2MPqBVebFWCicRafsvLEz+r/4NzgaT6XagqzTKtI94sYzf9UDuH674l23Ea1fD2+taOVXRefRL/cdEjIGAvfX/aBzGxrLDg05Lp5NnBIdj+3STVhaNs4OK5iwidCK/nibEtIT0rn5CNZGCb+AueuKeQWgdf8/sYA50VrwZuEhaxWfAzCWg3BHwV58FMapvWW46OFe8npvzCcfaWB3hoF8Ii+w3B4aypP7NWGVWJpmJTYAt8VaqD+bj0aPQ/EOZZHeZWJGZ+cJwBWtrfwo6AEPDD5wB6f32LrSxUMGX+PalgImnMryf5dIY8/+Y3Cf0bTv4/isCn3Mz7tj2O30AE0lq5HFjdgo+FxHBHUSy6Z0fjQ+BCtNbWAN9KH0W5CE+1TPIo1K9ShN2sanY9Uxxn3Z7LV0wEOyrzNi+aMh7dye0Bnwgbw2bWXvynk0+JRrrxG/Arse23D8f5zYPOODDw8DmHFlRE8/64fZBTv5+koiUZCBTDjdiiorGkA2dI/LDvjPwhyUIXO8BwythOHoG+htFstDRVcp/JHHwdSK1XBvZbjob4iHwW7dcD51jmceiGW5kAg1/UPR91vliR/6Q8KCf3ATNHDOPDblwZypMDVQpdgoQSNt5fA0Zb3aUPubtp1eQPptqwDi8TDpPXmDYY/FQSrm0f4aMUBNjySTdbCL1nFNIJqT77jRI870PxEDjcELhniDVNQNK5iR9MSvqK0FfSdh9jY1w2KJ6TwG/lXVHb7N9Tbv0I5GXFYl52FJffMeeWC7aiCtSg2s5McDowDTnpGF5SaoazWn95tUgHVsnWEQZNpYlIU7LEIh09yhWRn/pmn2qeyNX6lO8ZC1JQpAq9WKvD82tswXWMuK0l9oy6dKvh0dSEZvx0D6x0b+Msdc3SoVYPNPZvYdeV6lI6S47TvBjw+YhkezSokOBvAnp6LaGbfVtguawX3H39FCc9aFLB7S6tD8sj0xzK+HClGBRtCSW/sdzj5aw8drBOA6HMdUFm4jfYEvoNHXWfQ97MWuE11p3zBudxeHwDq/x1Br0EdkB//D0VHzuN19878j7jzfAjpf/v4NUp7aWspLS1pK3u0JKFEKbthJKuFSFGShhDKXg0UUSqioYEQoqX6ohKyRSluv7/ifnqenc/1Pu/r9ToPzuGpL4phj5Ih6/w+A1bhi6BAqJYC9qXgtSYr8Pk6iDsVT9LyIk/sza9Fq4dS3DjSgu0z26E514smeivi95WSUHpiL1YpncOSoTC8YiuIXodL8U5yMDtUOHERDsPNq2x4VZgqwNIWdljogQMjzDAn+g9JX0/GgSurSGi2DTgozIDOPxHQn2gNOrr7MW1nHTs3XceT52fBeytf6Pn4HD4NjOElfYrQsWo/0wWEjV/eUovTfoArfnSytQG+praxS6UnRuUPwRt6gtLxonhA0w4WXahhZU0PnNpaC1dnpSHmL+PQ3t0w/6EX1Yc10uHoz7DzgwoItY8hkc5m9sq14GzRrfz2G1PV3n4Q1K9hk8ybjKWW8LPcBhrKK0D552G8t0YCz65Xwc5DOfT0pyVKhK/Gq2sLwOh/325qQfCR14SSrCBqXbiQT756S6Yz63CtfyVG7/vGKk9zsGCiI+ws++d639PR7EkSfr4SBNoOFXh8uhtIHnhJsZ6bUH/RFpi6rhZkP+tBdddVXuQVjHZvE7lohwkeTHvLKzYdwLVjl/BJz11QYWqCfxbpw0N1WQoIlobuqBOk8+gYfREpgYGmCPrPyo/a5qjSyO/y3CttDnZlcTA+9Rc5m56gIv1pFND1z31aCjksaQ8UZ0pgSNtd9JVShaSvVzFlbhRvvfMXvOt30lrHu3je4RXq78/mBR8asP9pBW+rHAYGvjUU9yqGPYxT4V7nAToztpE+rJBH+UPfqcNlG7b8deLzRaJw4XY0S16pgnPCbVB5cxNUby3klZpJ/G7LB7xS8wpqelToSssEGGyTJNP7qbBB8RGunVdBqnt9aHbMUX7nUQfts/6woIcxvpa0hI5xD3i/eiU/Mt4M86fW0VnXM+S8ewb3pr3jNc9jacIhQ+oysATV32WcOysDzp22Af7nYcL2H8HwbzvcebkOz//rvFOJwaT2whhau0rpWGYy2m6PgOs4D89W74CogeGYcFiORbvS6bFbP0xsEoPMZBVI0vmI24u/sM+iAtb8GkiW6/7C4oUzoMx8Jb/2kuWLV7Uh8PcfjAYvENVhuDTZBv1CYrhXIplfrFTmBese873xfTjReCz8Z1QP1fbR5H5Pne8+/wW7a96CF53DVpUK+i5cSHcU0jmkWhjmHQtB3UVnOXj3Unyu3MWHY0/RtJbN8Nelk98berK1z3842U4VVnw+zXaBV3lY30p0TB3LE/AWz6xsZmu9cmgd18X+R51ge481zLc2ojNPwsH0cTDFhMrCtb0V7Hkllr9rjMT/Vp2F6OAJ/xxzBNzcYAq3g8QwdsiQTiz4DwPn5mLyZRMYGl2CzwX+UFapMt8XGQ6rN0igucRl3KAxB9b+J07JFi8wO1ALFqTlwPWaSjywZxbVhEuCPXvClwWJFLtakpZWi8HrFTVo2jYM1cv38BGzxfjxqw8IB6jBT7lQHkpogyd+xqAsv4ZM3/6m5let9LVIFtT23eac86JQr6gJk7YEc1ZzOH48b0LuuI6PLniMNctduM/YEZW60zA2Vw2DhxRh4eLjoD4zktQxH6VDt1KPrR39Ku7i/Bx7mD6hCqe9u4Znu/45Ysgb+vTdmDfslsar/T1Qe/IavJmzne3zt1K26Soq3xBNsFURAl/OhDWZP3DzvstoXdgN+t6/eZ5xCJ762UrvLx2mfb2f+IasEqyekY9ZM9qoc8idDja68uHI5yBPZuia6cbwRge1C3vwYoQclBhuxMqA9Tw8k8HCLAIP2NhA5Yz5EHzSEQJlYmiJxL/77JKB/meBYKP5C8anf6P4pcfws9FcPjfyDz2VnEIucYGY26kFP++Lw8u9x0Hj41v2tN8NDvsroDToF3+dLwzj5/TC4yw/cHuylb/9lQKhTwPkKrEYFtvPxiV1+rR8yiOWj3uGC/fuB/uIUezz2ZCnvBoDDXG6MLrAme9a7edpSnXo1f6M3qaOpa9vDKlYuYcV5QQw/5sixBz7QWPDYnF/zCCdte3He8U5lF5mgC7f7oGc5wu6+vATnDxuA38CtUmydilGqV7m1Ssus8TyBdCopcnGnm+pVlefb5/4xMu8FOFUwQOImHQVsws3cOPvKzw+4hQHrfLAY4b9OPmQEpgMfGJHW1VwSVxM6p/3cqSpKktHz+Zdxs9o1Slx/CT9hZYUT8dNjTr4+6sAFKqrkVapO1ea/0TN2BkYMiOJrulHcw33osi0e2wy/A9cNVeCnEpLaivdhAurHuC62HRqS3XFxoQJaDIpD3WWfOL8k7ko2jYWWFgDCuctp8H5hnRrTQ1JBcbCw5gauKthzY9DwjDI0Yg12wCGj3lCVQdu8UZ1pImTnHFbyCLSPbOI095ognyPCoT8ANScYAKSzSPhzsVwDL0uwO/3/3Oloik4SvoTKyW9xg9bJuDkp8PgkKoc6FfPotKiRfzcvBOyqt+z2LbntO5lLaQeHs/fJxmybY4ktY+fADdlesFAWJvD96dT1opt8GVPCD6/UAZW4p/588pUKplrRvc19UH+sSz13ZAHCz8gpcFm7DxeyBEV32nWuBuQ+dIRUx5/x/1ZAC+XdOJ840QaY6TB7+64Q3deMRqmFaHiv2ffb3kA+rlOxwe6ZvAx8V82hf1pw3k5Tt3xiDYfaCajqF6+9O0obyuU4mlq0qSwXgnm5kVwnpo4veyohdZ191n1RhA8jtBH83fjUEXoOc1LkaP/Do6E6vfOOPpwHs3zySUdi9FQH9rN38ZJwQ4jfZSMModNQ1Mh4ZQszM5tx/tRH0jkxnXWeXwDDm7ai/YmqihcGI8V8X50xvMR3xVgcOR3VKq3DqMKZODRn0qe4VoF77cM0qT5D9gofwXrXluOSnp6sL3OGHQqjCj+tx3Z7NPn3+InYfPbaEo9XQ5udi3Y+sOfDx6VhNaGLlSbsIBvz3pEfK8Z1pcp8tvteyjyaRu9fhDCrWY/QE0RINjDDuWG66CjgQhFyU/BcKudPF7VjI+0nOLB+ZK0pFYHC6u1wUVoA+tJNOOgyWMU8yjF+qxgVrpcxSvu5kFz8BSOfKQG2xf/2x+1OfRz9SYubB/EeZutMWLrb7I9eRGnCYdDlXwIJ413pSW6djD5sizPrj3M2kWyZL1FFuIH03CKbAiNijaFpbdOQsAlXWh/qwiPzBxo0Y1fNE9/Bv+nngC/JyXz2swJVGR+m0s1NHjf6pc0FGoCOxX6WDEhE8xE7SnL9Tm7tYRhR8ZuLDD246ub2qHi0xHMXqcGRTPNKaTjGKtLmYFZ915euFIU9tqNwNlXhTExugEPLN0Ax+4Ig/JrMTAQC8OdTz+S13h/Ft0ohXpVfWjd7sGnjVooXJ9w6zNjOGbcxY/PjsVGx7tw50M1HFZuodCUFPh83YHsd0Tgnvc3sEBmGKwOSacZAVJwedEwOCZ4Bz4/bqWl39+S+Jhh8LJ5Nq375Y0J0TZgc/knHBu6BeXPfHB/SAwU3Qzmpvst+Hv4Qb72+gEP6RfykKoe3LubzceKd+G+F5EUdhzAKfAihtQUcUBVDdiNF2eT5Q1oOwBQE/4Vnhq3g+SKOHAwyYaoW5n0MTMTIUYM1/51JemseNjySRPmOX+nHaMC4Ln+FVAzFuYRLo9w1jJJ0P4gRAp2ETwDo7l0mTXMexFC3/JnkrbJBdxXNgIdc9vQNusD331xGe4JvOGzit/5m4QyKJSK4LWrP/nImGh8kCRPZTq2/FvAiuL2HoAZM5N5WN06UkwZA3PuXYGug9d5hdMdOD9XFt4aCsFio+m42BsoankBF+y5w2/NBaBhWDskVDuzmVYHbZA3x19J+2DH5ENcLDafs8NiYVOgAgtuUoTdyhdYYFsqbVl0hmKWjMGGbl+UOfWO45YehHHOd3BnQh/cXoUQtV+I1uxLAKVzfynscx1VV47B1UWXOelSFVRN+I/K7rqDcIgWFFpNg87v33Dw7HOyOykAryw3Qbvqe7ZdvpBcbNZy6bR3DGFS8CVuAI51fuO9KVa0uPAg+T1I5hMTbEB42EkQefaRBF0e4C0XA1BbRfyh/gK8aO6FkxFTqbr7NX9ZIcVfHumiRKYKOzqvAPG+UeDdspiVDAIg/4Y/f5gsQNM/zaTSlgzMUjbH0PiZ5LbNnzeljoWFuZ6kvvIn/mwPwIzinfTCNIjvxgiR7chpSGvj+fWLcJp9wQKc1xljzkOg52JjMSZiEVpe3oVLbwZBr305tZvP5DcOUfww2AyUxdeCVb4Lfp8Rh5vdlGHyhSWo7nSSfs1Ix23Ci/jYht306awU3Hb0heS5ARhmOQbaunv4neh7CFW/h2Pe17L56F3Y/aaO5nsoQ0dRFE9VVqfROYtZ8v49TnmRh2mZjhx8qYaeHT8Ob70rEGrsYK1uIaucqQb1ou0w6vAeCAurBH/5kezmUIpddud424bFVHpfHWQ150D4YXNQdh4LMldHQb9xC0RoxNFE4/fsv18ZLw6eRhl9BagOu0wXrKZAXIcDfCwNI5Uvl9nOtAvP/DGC9lOiUKqyD2Z804KSyh3kKpSPy28KU6JGAUyxWoapr29T4rKjZKbsAAoK26hrnzqYlBBL2hTBPgdRVG1WAM3MQ6zZ/Jdez0TW+LKP9LISIM5aElZk1MGdqgK4WfeW9fLyaFL9a3hqLsMON4rBvUeUBf1mQ9M4Q8jsdSdXrzRwv631z893UOrSpxDj8AQPtJ2HvT8qIDvnPutmy0L9vT/sI7YefsuooNjzdI4VlMT6sBRYplyIky8+BVsdD6o2Efh/+//vXNt6fjc2nu9Nf8DOT5A3ZS2ET/9Y5tDieTjm9RO0yTkHk6LkoarpIf04vgsEFXzYeKQ/K6qY0+EdV/FFRiIe26BEC5Kd6X6HNewZ0MPFbyN53MB8OP73JptMfIihAZE0z14FQdkTz7us5Dm3tYDO1OAWbxPKKJ5MK7YWwzin0di/UBbjH7zhiDgrGpQWZG0TVfhgxDRqmDvHOeqDk+Ritj7/H56dMItXicXDgqASfvzIj1bfEIa5D09TT3QfV9bF4IPdc0H5YyP1ntvPG3wewsl1v8DzeRVIrDMD4RHFcKRzIeVHRkLV+RgyfjEcbpnNoplrP3FHXiM/1zxMualW4Hu3mv+rbwdpdxV6ZVhBnjoqtHzqAGa2xHHA7zsY8SgVV8WoQsFeWRyX9IsGc4rp3q0icl5eDTWHlNkpNpS1d9TyxEIpWlgJcPHyQ/xyoA3fNRtilN8mEF9fh4I2j3j4jgKwLJvJ248b8lsNG+i1ZYhfJwOdM19gZcMa3CX+hYQubueX+x5C/+VDsPzNAvT/MgJMdb/A4jfT8ZuDDY4+FIKJsfvYydEARk18ArlFt/nQzCJqemUJok5ulBt4gvZ7Mb+y1gaFd2Nwf4MJTp5xFiBsIe62/E4WyzShxX41m2wOg8gz0ixybg2VdLlTwcpMnPxwM/kmdEOb5Dy2MtCAzHFG2LjlJ/089g6P5hiC1I6pvOfTBzY7+IUmvfuLmYqTIdJMEY6+OgW7nlRC5uc0lpQI46spuznfxojko0J4vWwO+X9Rhd9iBJfEa3m4SjH/fTid1y96BMq3ZLinpBx+KYrA83i9f7s6H2JHKILenA783hwDXyQi6Y+SDgc+WkDRKVX8gKeBoY8nhH7WpOkwFnbL61DliQ3QfdEQymz86KX6XFRrS0cRt9//eNkF/lPfgmOmyULaMF06bNrLQie1If90O22tmwBLVvnwrH+sbbd9NxpPriTLH0bwofAoBysbU/SJuXRy702wkTaBn4qL4ILvH2p2dyG52BXYrqwJcRo9vFR5CZ+STUMrxyKyOfEI/Y+I8rsxN3DArI9Dnx2hsWIWEJT8G9ccX4rng5eAZdRSiB+qx5sTAiBu5FsuSrGnMwYrOfuuOsxXn4GXhs5hUFkdBFuI0u6nvuy2Q4HVXE/AE58F3BAbhC7OynB73HuU6JgFa5zyYFeHJYVl/TsrjeE8LeM9Lpt3F2TWG3CtsSyMy5hLglpS2DbdhvYqWdOPziF+uWYmeqZt590qinz1ZCpXGqvD1tFjMK8gjsl1JDx7/5OOe7mxtXs+Hdu9hKYGCaJy/yG6dlcQsoaewqw4DbhYYEWNK3bTsYJ1qK+SjzpRjbyz8zYJWg3RLmM1YPOtIBcYjXOFf8OGxBH0LDCJP+WvwR8lgyjzdRquPxqO7fekAKSGcdPPIkronUZ61R9x+aVSsq4OQeGzDTjeL4jm1VXAEYHhsHxDMR8I2M4RB6+yQmkwPBHRAclpHiD9z4OW/B6JI9ZH0LIWGTiyO5wnvXIAk5FVfNtzgG5PmMY7pM9wkddxqDGppFD3PoJPkjDe2RNVCj2pJOsjJMz8SPei3KjI5C9PKZfB6aO3Y6bdOTqSMhZirPzBJ+w19zf8h2dCFrDumqmQYjWddUJe0iGLVXzfuxgqxqpD3BuAB2u0OGqYEK5Vm8W5CXOoPG0UehyxIbZ7gG9W2vK9azLQWDUHi/a+ZAMpRqftHnzxdxCtkMulsc8O4F/XQE7YZAgTpQVg5NaRFGB0lJaHNkKtqCKtiFiJi/ZI8O/L8pg3u4SX+41DfTVzeHZfBaxWHaL+3Oks0jOFBDqLqGtxHthXjQRLy1hwO5hBoTwa1vz4C/eXHaGhyzpk5DibrrTE8/iBeSQ/0EUR9I3CNGPxmYMcxOZ/wYd5I3BXRg4a7V2NF+4b0d17ytBk/wUaDWZAo/EZbnypAvviwqDw3VNQnmjOkh88UTdSFl2O/DsXLy+y+68Sr4tW4uGDCrBzwSkIutX8L3f7WSwzBW+89qVunzFYeOkVaEZoU+vVFWBQZAaXtbaydm8whbivhuT4JvahueQ4eILXHVNmT6Fc0DcqpNMWYmDq74PCV4+h5PZiDEmdT67G9eweeRx8OqSpJF+PbLRXQP1ac2jvc+RQ4XEgY/gGy/29yeJlOk28EYlTHD/ilStuHPbgHP6Qmgjuo59RgtE8SpZ5g0mmB9l91RrKfq7F1mrduM8tkoWjD1CjszUYrK3kjCBpXv7gIqvVG2Dbkn6WVS2Ga/K20Pdcm45K30Xvv8ag+vIWNJX+YZUAD263esNHwi9B1MvpXKT1EO31ZMkUrsFShVEg4hhOHkmRtLvPBga0bFlkXTI21v9AYTtXWDtCH3TzJbFvjTjE5S7mI4oN6Pz9Lkj5jKDhNsZ4fpQlDXP/AJlbffnTnp/wYbEIeA/fD9eCLSj/9yY+lwz4yGAGHciQxaREZ1jk2sb+O5TI8xrAWgFx/HmiD2FWI+s3mbKHXBPb3xDDLf5T6UaIGDy6NRteHlEHVVt1roH5fOOhIIyNPMv6ty+w+EWGD3tuweibTXw1MJvqKixhd3QmLTsYD2Buhv4tQTzefQG88ejmTScjWaf6KO64MYABfnZQH7GLl9i2wuGbtzj/xU64+/c2Pzo0AXaulOGk0wdx4+A7nHRRBhL/JpCTaQFlet5g/fJatLQpoMUzz+CS+d10VasFb6xsBJNegtYsQZb6/AfySxpolD1yQWMHFVdcwiCRTNgSOpUahfMZqyaCXF4Mz9o6lR9+TeUzo3KppPwofRsei173X0L+0iDSrDpIbs52oPR4Gh2x9udb1t/RYcE5TF+7k9sdL5Pgj61svbgWQ/IXc3uTJKzMv4kXL1RBcOlPOpZjDx4+XTj+BjI+L8KsxXEks7GWPu+QAhmLJ7zqrw65dpegz8UVcNFYAcfFXoUsiVkoqKjAS6oEIdXWGK6vWMF9y7pwzaaLrHIykR3NTnGj6idqOnGNbu6wI7UyWeizt4YEKQeYHBAKzQWpOGDkQFqGtngr6xxGqOtAnGona9oyu4IlvAvsZSUZdbyXOZYOFO2FY3EyUDnrK305dxvTk3zR8ZETLgo0g615WvBi0m309UqiVrtpcKh5F3ku+wZm6WfAbHgjl1toYkO9OlyIvQg9ysIsOniTEzKu8QKv7ZR9bh6V2flBRek5fKf7gy2ejwHHjX58qc2DL8nKU8zDaTipUh4Du7LRd0sar9FbDx4HE2mPJMKTiecxf74bHNXu5JlO7Xz46W1A6+O8Ri6DO5LH885IcZyeIgfaHtV8X90Nxfr7+dYxO8otcqMDLqOQrEL4Tqc6BM9Jg+UvxaE1zJN05l3hD4SU6FGKA43ZcPi/vVCtbsy3up/h7qxmMHD659P6Tdx78SgppI2kh4/y2KtXGMxv6VDeXlFYviIJA6ZNotntViCv7kG2DevItj6RTgxcArVnOtwXG4uD23pIyuoYtE3To97Fw+DeHWteVlHKZ6wS6enYmdgy+gTJPzQlU8npdOm0G5utM+GhjyrgFnCAVdsKQEojBoxDQiFHazXnVUnhJj9RuLBBiCYUMe1Qt4bLEiFwamkPyg39pWEfLnOKZBYoFPfzd719MGF1PttrW1GWkBY809uM5gq7eKfVYjabeImPtywje/Ljsh0BfPBqGGwvdoOmOEOw/qSGviuG/fPPbNTqeEOTDpnTzfoUdDpbiWJBYRhp1k9Ke43A39wJ8nd8whuJm1ngqhblhnVT0ZMn6PzUG3zzlHlgpQa5HZYF+b97eIvoXkzbKMDSblr04yJRhcYW2NaUypu81/P20G1c/VkSMq7fYxsdb46d0kcHY624xHUrGEVm0aiMx3RgwyZanXyKwiVHQvGPfXS6+D7dHX+K79/tQN2nO8DbSw0e+UlTi8sA6qpp8JzESfBKIwfaQsT4sRzB5cCFXDPZFdz2C8MhJRcM+jEFP5mYkKGHAgh13qT0vC38K/8S6y43hQ7PG/if1Qgodv+Py9tsUa8xiuROK8Gj0EmwJsaO0kZvgHAJMZw0/Toqpn8m7eADYPFrBmeNXQ0cZASzVpvAxmsvqPtnP/7VXk3+lZ9h2XpNOOkzn1vVvUlquRFMGTUJVBeVk6vfJbhrUw7xHUfpWbQGPdbbTWvwJPf8WIuip9L5VIUyjAkDPFB1BUXea+FRkXhsNTKDBQ2zST/CAc7O1sGrsxXhqYwU/H6sxKtankF//xNyD5eiApkKSNnqRMcnD5HIiG5YppMLe8JHQd779by45C9GdBTBl2h7UBFtIIcBA57dKkJR7g08LWsEPMsQhwmJIzC0aytf/GlIV6MbqFFwFX0d9wKeRU3jPBkxlrMMhROjJIHcjoG3WCyIfPuAm9f9JP29kbjqn1eo+kTQTPdnvLZ5ES2XnQDvxiOHNbjy5/d6MHuGL/1OyIUr76VY7agKSE6QonUf9sFWloRv/lv5zdxZqGk2hnrtV+Kf7AFMv/eShg/uhWCbKF69IB1txDRBdrsnFZy1oKc9l6DokS09tb/DFW7RMPk/PdJ+pY2jj82nZyn/eDPFA47/nkdvjuhR9kQhvFebytLUjEuTw7HjsAO+Dm1jr6yRYGL/iBsE9qPEumUYLmUJMs66nPPyGeck1LD3mPuo3aRAjweHg7ndfb55Lx47h68Hk6I0NtrszgfOq6LClS84PkOIFO41c43UGLhxspIqjU+CwZx8EL8QRvpuDbSn1o5DmoRoinMJjjEcw5ktGqCW9Z4m7nwCIdtloaj8DQ18UYRDrx6jGnbwpTmNcPv1Y5LpEYRb+hrsOLIRim+mw/1rvrBzYj3ku2WDwBsXqngrQKaNjtxiIQeGh11JCa143afJbK++iW9blEAzZKJXXTF17J+Nozvj8H/vvQ1LQsFmvz9aLPOmWOV2dpp9if7rleFf0Td5nNQgjDrzFxaHjoCwgRyO2KlEH9Y4Ueo1wkjBQezPmQ3GZ2spddFkGF00h7zsxkPmQAxJlXym5MlEX4oA8IktFy9T5uH646Dz4RcITPlGu8uM4Mf1kbDpzABEHSFaIv+STji74bD0PVCcFQX9t6S4bE4mtSSLwBKznVzWLomPk5zwbM4PHhFwjvc5Hmfbh+U4+O4XD3mNZ40OKQj/Fkvbur7wgZ6HPLjuHfRW/IEYuzKQ9A2kvoBToHxjJiodFQNJHQEcmD+W6jYugwknDPFUQRpM9e5hqjBgRdt2Gq71GRa8Bhjm95uMKqbSBTtBqHPNACexbPRq1qUlD6di5a9/rOEjzJ5lo8Gvciquu/yRFbY7cLaZAKRV/kHnTnMY+eooHS/4Qk0pKqxtLww7t7WTRfNxXu+6E3XyXoFwrDL53jyKkffyqP5ZNmwPfc6KIWow4pQWTR0cxVMlXuCcM168cIUaJDkl428XQwoMTGGr/1pBPs0WXrx1xvlnZvKutPGocFAbXMaYwbjbZ/H3viaKEd0DEpfXYbuhEdRvOY/Xpjbgle4dLLFgEit4d4Cm3wnQDGihWaFBsLRgMo8UUIXUiU40bv84zlFQItmY89R1czbc/B6Av/5sp4iqIXgf7oXBd9VgSI7x6AwjxLeLcc+1KEpUK8M7D7vRx9ISkwzD6VWmEbZIyIHY+d3sL6sLN7ZugA0WYWDrc4u0HnyhbrU8EPt7nr9cNoPAMHPY+3kreuwJ59qYS/w2+QfP2eiGP/sK+dIoMXg8upWCRgryiQCEeBE56hRLp3qtLtCpZdZqTUKnvYmkr1KPiZFiZHlZgbT+GwmHFn3BTXkGGOYXzXNK27hGsBVTzXbSl6gWrvkuw8mn68ijWgOStW1wz3IzjlWvwlkt38m1oBhavy/D9ctreG2tF07KG45ecgCKbp4ccaIQ5FNNwSpoGZz+T4+1xnjDzZ2ruCnPiDOsJpK9yRj4WW0Bvk8yuHqLOh4TegzPPCtZS3Q4/ZFLB79Fjyg12QXGVkvDIvkz/3LezZe278b9E+7wLkEX2ig2AQSmXaR4kRE0568rdkvpwjHlISqon4kl8Tqc4NSOxbYrAAOWweLpfpAouIauyquQqZU1lFWq8tCpubjB4ze3WC8Hk0vdUF+9mzbvmk8K563hzmZ7MvA1ByWVGDbbLI4id4ehz9XjXKvCJCH9nB0HxkCZtDW+kKrjAhuG6x3uuO11BTzVc0ahFHWO8PXllIHlOOpXHcf9u5Z7KRfPnBgFJp8OoLlmPK23GAuq27Ph3NE6WLJbgt1eZkHPe3X0FlDi5omCcD13L1TWDYOiTiV68OITaaToYF3WHCiQlALjdGm81auDPmQAMud7WUKmhj4bOtHNmbOx+4wmR398TmdzJWB2AOPB9z541ZUhzXslTeoe5MM2+VR2UJQ6yv4DjQeHMS5dEi7rWNNEl2W8KMcIxh8xoksFWzh16Vxy03oJSlOmwbDoCEq/X0wbU3Ug9kgz+2iIwWD9BAxWn03fCh5D6+GVNCs2E2ZtuMz1m3KhqHgGjtkdCM7aEyHO350d6t7Ags/feb1BAe+995oeZNnio9sfyOw9cVCZLkwxVQPr0A3gefEMH3pnQT1ZEXDM7Q3vWv+ML3d30FwBVVJsuIsbV8nBxJWOUFQfRdyxHM82dIOqVAd3fJIA6YV9sCg9F6SmfoUydxuwiXLhxHk3uK0rlNbtuAYilwLB6MosvDh3G4e5q/IUR3Ne+YvBv6mXp4jqs++BKZh8cQ4IjRvFYj7qrD7GEMqfT4PFs19j18xx8EN6kOrMc+hO5zLiI68wY5gb/f4SA4cK42BUiCTLHv2PzqWrQ7zsR5DbIgGqhuFYrteDja/tOTwylqKUY1FSdzkes8xHRyMN+GL+BSavtMGZiunsuziSF8x3wJzuWbxmZB+9W1FOsfOdaMNsCZjhspQLxwuRpkMcfPMuQf5oBuNvOmJr0hEuOu5FZb2RHCquCA+Fn4POKxt4rvOahfUCSJDfwsDZCVA6YxaOeN8Pk1tWwIsdphC16RsOWQVB07ZYCnl3giRu2fG2LT34eXsMTxEwoBEjfsEZERG4GyZMQcHSoKewglL1J9Lr7S548d1mWL51JXxs30fumnYs+NAIhs17xB0Fv7FCMwCl/D6DVdNxDtk+Ffdbjcev5rtgr8oD+HxoFIRlNOA6PA4/OzbAxURZmIV5GHajD9K2zKeUe6tg0doGDjMeCYIW0jRDYwmHSb8kl5c29ClbEPD8Snq46hyXf7DhJFMv+JQtASn5hZDeE42dc9tpRcIbbHzfjjNTFXlPZhLYRQ/Q7b3nWGKPJAiUFWHvc1/UjBCG4ounyXFxPKxSjiYLAzEM2jIPM27c4LmJZnBJphBjbFOh1EWDtjvcxGFx+7Hsyw2ctewdSPZpk/G2bhStN4PblUEotbeXk5MTUOfWBrJLvMy6m4+zx/RZYLBKgh7OFUACA2hXXIVGE6egq7kDd31V4cvJM8jb3ZNPv0nFkS29dD3qHhweqwVpHfNwxpAXhE0JQsUlX/C8jDZrXN9DP2u3wcVaFby7PprOBShAt9AUzp1/BgUkg+FzjyDK912myroKfOSkw5eT5HlfijeIXtUG2+/qWJ4hxXOeS9GotRn0eZgaLlk0nOrGPeHqD7WsFjwXqoptQHHSRug5XgcTfihx0UIRmtz0nIdkDHn2i3H0vNEBvlbqwtTHWtC7zAS0DR3hmE8hq+zUpFgNDwxSXUKTZfTBZF07jrcYpKPDNOFt30ve3eHBJ67685aWBv5PeT+VSm5l4dIiyGgXwNNFw8lL2hZEnvaCrrwHtU99B3bzY4FM59Hy8038qngMSW5QgWDduXD/qRWIFdaCi/5CSMM1eG2uN7XHmoBDziJKWpqO4Q9zIVvFlS+ftga3VgVwvp0CMU9sQfCdA1+4/w1/P21EjZE34FRfAkic2IHz3axBSH8HPEl7hEeVQnFwQj1tWPCQLYW8IT/mOE/3kGbvj7s48p/PTBcZjYvniNMjaR20XhiMem3f+fi9OeB6RRSGjp7ir85JdMHbDjYtVeQt70/i8d0+tKJgE8z+FYm1ugdh5KkCMNiTSmrTE2j8KgHIyg3m3Z0Led/BKogfLYOqMJEXvCng2inRqCwZj5vbDTFjqx0Y1KizqIIAdmb/h9+cj6Ib34PQm+NYZ0kpLcjzh/m70pneDYdf5t+pyD0Vdm9ayrcT/LhSVhKPrO+jSVp11L5wDGz53U/DwtThQMJtSCsNg1jVXgx/lkjjRGroel8Bjup5Ad8/RPFhlXl08bIlJPmI47ugdny2ej/0y8/FA03L6ETVVYzbkw5lO+dS86wEGPnVEsJqxal9VQevjjzP7yz+0OWZX6m/0BhijbZy2Clb3NHkBnv3jIc1edagmfgIHcNHkPSbJTjLaw4oWCSwUWAMVyf94FE6c8j6mjGofD5MW2dsRMEkDWzLWQbF72+xYtdlfroyEgwe2oN90Tf+LaQH6sqS2BchxZ3JiqD05SBd7/bHXQNB9FAnFi8WtvMxhz205JM0rPPch9snp9HelR6YaBhG2nFVICXfAYEOQObzz2LXtIk4eiRC/fZ4Hl0zm+PO78DzHaZwctUARU/aSGKmh/F38Wz6L7mMZxlYQqLZb9i6KBl+Fidz2mElenpUDn+sW8hlkTWU9TabbLb3UUvwJNgTe5PFnadC2lI19EyKg+Ebh9HeU5No7tNqdg6JpeFXLnL1CgkoMQmlbcBU5L8AI6KEafU5F1B+9xTfZ2nBM7koNsrPA+fR8nDTL4QrOJ5qTpmh86RFlKjRA8JLc6E82ol2FYzhpO6NPPJfz/8RXEcqb6fQVz1LFNq5GZozCY5P0uFYyuf6XnHsqJZC/dvj4OISLb5jFsHbW6dCy7af5Fi4B5bEDYOun59o9eteGG9mzSUnVECswg87fTfz6R2jYbLcSDpX2A0vf/bRzekCDNYncJ/cADYfs4KBpQz3R/pysxTzRTFFLs2YyneFXrLqyh1UHaNDwjkr0VRKAPY4PqRZOW5YclWI+vscwXjlOTq3qIRsrK/Qs3h/WEF/SPy1MpwJEKGinY/YbUMAi0hrc7XIeb4iWEoRfn9IqSOYOh3PgeDOf4win4c9PyP5Q2ISJCcqYVx9Or4+sZNrqh1gV8Z+aE+v5IBEVaiMXoDDtq7gZ6tUOOWjOc/b7Q6ZSQL8a3ALf1lcz3Ma+kDOliDoQiMNv9nN1sNdQc73J4iXGLN440dC743sOD2Loi+NAtUwcShq8aZVk0Zj67NL1OK4hXN+9uGvMaYg35/LlRPm4OBEGbgVKw8NK0UgKuslpubMxMX/2CwzdCtazNmGzq9fsvzqN3DdUZE/J9nBfIt3OBR8DWbeesjLA4fg0Z0mXDCQzT+8vrKu1jYqVzkEQ9vGw32tQe648I3NRXQ5dl8wL5G5DzUVQrxxZw5LrE3hT4t20a63iiA0NJZijI6in44yTBrTxf6bn3LHQBip1J6BkvsF4OEbTmVaitA1FMIWjido6Vkp/nHBh5VFbHDfxgL880qY28K6+dXIFBKtHwnDj56n+18Ro9b+Jp0YZei7uQ2c5o7BhT5LoMKnH6eULSHbHnHwWdXGa1racI6aGL4XEOVDpxLxjuRFurXHm/7c8weDU24YWm4J215twKuLA6GrxhU0Th3AisF5qJ48GQq8smnlYn9IqRwNdeOUYaN0F90PH4RfIslEaf8YxrOX2i+FUdWwkeD9RhDU3uuxwb/cx8U28AeJSH75VAfQ+w/ojvyAy4S98Fj8abiVK0CvCmvRLF8RzhipoYXDZw6IeA/PhObioUOpUOukDe7icyj+bRau/ymNG21lIbEmA11Dr7Kv2R7MH0qh7bESILFOAZP+rqOyJ/N4pl4FGonaQKp5G87VP8V5ZmZwpykbLx3Xg+6gVJIZsQj39tzAphO7cLKlMQxz0cLqsN3kYME0WzGVVwVugW8rf8J0mxN0N7EB5XUr2bxCA0wHitiwV4keFvdR6Z5FbGa2HebuL6b64ghQrR9NT97/oF9sBR8e/8XWvbfwVFEoVLZvBMfVWhDqkoAep9xYf+4mbm3ajB/GyED0ptscLqFJN068Y6G8EyheOJx/nnhEOkcMISXNFXaWVVNx0ATInvGWxErU8XppDG5ZbwX+J/thMEWCF45xQ7v513HZuG6ymqwOKzPW48Q3GjxDdQSr9+3COaod5GcmB7syb+BG/UgQlTIk2ypNuJD6h2s+3qCvjdJctk0N1yv6oXexIp+r3USixgrUc/I07NupCsseF8OZCzvwwD5VDL32j0lml4P0wDR4Gv6LJeRSUXbUZpoZPhKKsy5zru4S+LzzAM41rIQXJ4FnRB8CL8+PdKJJHhyK8yjmsRTkuirSr0OLSMfuPci8fEk3DhWSff9frJo7G3tcmWfazcSgVwqgdHQ+qKl9xLcJxixWvo4yimWpS/Q2bbUIw/wZwvCr7y+NUhoBs2AeBuhIwuYR6SgwVobcXY1JYe5+KtRPgojmpZRweymaHxMEcccOFM3eg8J1Z+H0hNM8NXc2F1j48YabRtwvnMct0r00c7gYxKq00sOuuWilCji65RUPHPoElTX9aCHrxqLjbKHUZibISIn8m/kvDqLnNKktEGYVzkCj/GYam5eCn1V7OEv+JZebWsEzd13wazTAP2rmUOR+CgYC8uC5pyU3nF7CDvvuwPtfzlye7cQe/zHElNxjF6epYLxrPaQpi/O+o+ootL4SRtjPxoErFtBfKkiKpAexsVcZ5iqA/LYFmDv7P4oUjIXs2Rr0bcs3lOi+xjKiR/iYuSDM8M7A6aKNPJe7KE3uIm89+4PTq+Zh2Tp1fqK5EletqqNNpyeBankhVtu50h7PGqxamY+HRxazk/pohLuSYCnXSqnDxeH8fXNoW3eWGp9ok+ZgCwfsngjwJwEl7HcTLj8DGx1lKGCaKGQ/EoPl/l/IYMcenDcgDTH5DlD3wBfWJT7i8MxutHUtp2pLO/i+Qg+Ufg2Da6/9qfBgLcfNXM9vfh5k2dP2rLNtP9a4zMdO+S34ulQbRObLYNjiz7THYRj8yBHF/OB3sG3eEn6aJkERTfPob04wCc1Wgyq1qeC+PhOtcjfyjTN6lEdB4O9czCtdzvPTwAhcWiKNjzchnHEdhfoTxUG79z64GqdDpMhzHDZGHt2Gt8POp/d5Zoo2ThHS+bdrnkPGuC8cI7OV7+opAHlWoJ2oCsHiEzi4fA1d0BAC8bHqcL8vDjI+K1Jr8AhKKJ4DxvoXaMmyxbQ55ho8i5HjlNYeCjQWgkvq5tCauZjKBU8z13lw+dRTrJi2g8vmB1JFSRCNXfwD6iS0oG2U+j/33gLCXZacme3Of5LLSWB6DgdNbMDz/eUgoyIPb0/agbl5Ex/6pYnjw9wwt1cN1D+voqHHR0lNez7ef+CDakeaIcRLAQquf+JZYZGo930PbtnsAKXzx/Iuq6W4MMKVLuv+oRNTZ+NSITuYeaIVXn8qRK83CznRZTuC9xjsknZmSpeAyd1rMNjAjoYd0QT/fhOYp1tGcssSeP6Gt6hU5gVagUr0efUBSE64g7aLfnF2uA7ormAQUKiEkd3D0SNfhOOon1VPpaBv3XXO0SqB+VU76VK3MKwZXMNz0+az1LZl/OvZFhJ1b6dpCjcpfvR47r+uT7VXFsALs3GQfvcBvLb6Bmpa/eT9fCysUnKFA+/EcEBXBX3Lb0Ox/Hme+E0BrL1i8Wb3DhwpPwUV9gviIc1fYI/JnDFoSsFDG8jy1T2CIoBI80pylrDC53fESK2pmByfpUB4wijEhAa8viUBpwrcQLMGaRhneQhWmgRyovMtUglv4NxD59gy5z5/0DrNq487orn6V5waogJJwv2sVz7A8T3/5lIwB3wDp0FVVxv1n/sLG3uNITg8gRpWGEK6fQdO2jCVt/+VApX2MBhNutR5OAQat4aw3koLSD5XwkW3rGGdWTVdF9XHQ6aryC3DhgsFVXhZXz94XlzBf3a0kIVvO19oMIPDT71o5YSbIHLdFC2Ft7D5tO+sEjOKFmbfogtPcmh5zS8yHm8Dpb/jyCddET5VlrNagjtcmKrFVcrrWSY2D9qEt1Ob7G5SWTMcrksLwfzOCzxNyI3XpxygDckv0VniA5ROD4GB8mw0rI3j953msH3GYzpefg1GfLLDUPYHq6vDaPeLqRC75RRIT/8Ih+JbOP0Iw5XmKeh4bS7rDthBme9RNBI7iY01bzm+9TnNNXnMKUkT+W3eMPj+wxjc9pzn3aO2crfNRrYcaQd+9ftBZvwn2Ntay8ObtqCRvw4Y8DDQHTsVmiPKKSignyvbnVHo3SjMzh5DGhYl+Ga357+eHg4iu79iibokZHkM0Zuem/wtNxLPvrSA/Q1h1FDVggtW1mDlBGvYeOAb3BP4g33ZL8BmnQ5LDA3BzV0ZvO+XFR3wf4dKwUfw3AJ9SJdZz/Q0HcJaZ8M8g/UoUz0Tks4lsfSOfRieEgVucors+nwS7FAwQEddWbz7j/HGLd+B6c6OFJ/0GC/8F8e3b0lCUZ4c9CYbgknEQp5q4sq1+wZowdIJjPv2oX+IDwWNHmStFcF8oTqPZSX1oC3uPS1kU9L/VUoeK3Nxm9RG+HT9KDdr6eD00G7Sj+7mG+tHQ7loP0iffcqjQnxB+Pgl9k1MYdNpn2GPuRKs0UhjmxctsFqQ4U+TFsZnOKPIySfY6yVDaRWH+aBJO/8Y8mXPKUgLS2Q5VlQbGr7mcuOmcagetQSfy/lC9xxfOq82m4YijsMb9RGs9NCAevL04GLfUjIdfoi8JcR4nFgBjXhnBjfsN9L8/suQUReJ75qO0UEvS1A+mgQW4bsxuPEpjtnwmbbky7KQXDxedDWBqSm2tOiOHwU+UoVDPmv5y4VRULRMHPqt86h1ch6bLtyBCxueobjucG4eaU/6ayfCc419vGLVZnZXteSr68v59ZZs1Poxhw8IjOIEu8U07sAw1DDThx9yzbR79gYoKWumK9sugOepWTCpfBdreh7m0p0yHL5HgZuWSUNToSgbqvpAQskTPJ2whiZZD+cv4jngtXg9a8SdxdGJwBu+ioDgnA30JbsCE34f5Ni+E+i9dhD7Lw3js8dSeJ6gL6sdWoG3elTgcbMDCy08hSHif/nqGSM6sDqMzaSOQ2iFBO+EsfzkkhoO15wEZ/d0Q+ERHb5f1An6Sul0k+qwol0Eyq7MwiF9J0re9pr2PNeAD71X6cETG2yMm8Qqa4u4RmUWnyjZwYPX78Pj+2b8/Uo72m03hy/n/sAKQXfafSaHzz/2pcc2a3G++nd2W2uNHsK9YHA1H029zGDf1sucvVqefRobecqrQ5j68zCEzNGlH5sb4dHzRaiYeJ2veI+CPKvPFCDjQRuTG+F3ezO+/HCbEq73gndDIK659Q5nnHPFn6O14Wi7EwmYveZ6k1f08m0Y3e92hJqn7Xy++Tz0DysDzU/uKHtkDMTJL4EIezHobxuLAkmTuVFoPE199hovitXRLtFTEK7ZQXLGysB9Sjw9qQsnHV0IgsIxXOwXSl7oT9YL5vBayIfotZ586I4oNPlPoeDaQj5u+wN+SuWxa1cbvycRfjPQC6VrRfBu9Rp8a2EDyZ2qfNeSYFFVABqU/fMv86s8v/c3vMuKouqAPlCMt8W7ssYQFKyDX12cKGPleTqWrI/bnp0ka0imv8l/qObqYX4QoE0iA7oQZNXHNZkIldnHQLI/Ds6NZdCcuRINYl0pulwF8mVfwDVjc/AzaOZdVWqwqXUu6h5YCM8bYrE5Jo2UPhG7rH+PPy20qOuNCIgUZ6BHrw2VekzCXANDvnnlNV71rWCn3Xr/2O8t25cfgE+tknBWOpNcwuU4arkY9ioWk+1wLY4eMkYtq6NwTbIIh1um89AKXfAXmsdtgibsrDOJTF6fh86dhylCcAQ/OH0Uji/8zDHff/Dl9aLwx6WH60Y8xJTmMGx9kkhdksq4/KUjF9xxgJ9CQ+hXX0DaqRMhUrkSAkUv0kPt2Tj9sQs02YuCt/oHnBxRgpGWEZwieBPGGJvAMu3PsEbqFLuX+uIf6TV0pn4f/lxVjuPm3sI8/92wUeQNhJroQturMhaduBF0f9ygvMvH8Q7N43kVh3CNz2oWn9EIEx/IglicKIxNSEezvb40XSGIVEVCwadkCr1Y/YneLp0O2tfHwo7izZwTZQj1yyfTtqlTUXJzJXaOnQXul+NATMaBks6pwPG1n/C7qiNc8BGHh3d0uF1dCKw2bacC0+OUcT0GBx4cI5OEFeCtIIw9jZZ8X45AY/Y2OpqVDE72tdz+7Bh8hnhySQUe6Knh9Fw9ePJXm2JHEKxzU8YFE3+yR7Uaz7wxkR5eC2cz13F07042Bya24keXeNqoZw3fxr4BBd2v8KH8KEvLzqPH5ABlx935m70mWedegu0X63hutzV4LduPvmJ5VCHbi30pPrx96zs2jjflmHxTjExYQj5u0ZDWbwimxwphQU4J2K/SoRbNZJja6UNH7wXA2hhL2vl6NTX7MatWjIYtVWMgOXQLftt0BFf4BcLpwtV8ZNJi+mFsgUMi2nzPqgTDrpnDiJMzaE6sPxb5VNOvtCiQsDyGC5psUVz5PK/9vJbf3G+CO1MngVjyAp5nOZp6TgvgmwkHadGoDhC/uBmKvhdS+CtxdvB0gYWWpiDf+I8DD0/j707bqMZVnoyin0HpJAPUvjuMQfoVfFg6C4R7xSFywjk+JpZFu/TduG3CBFhhr0sn15azfMxmnH1QBVu2DpLTNjXwev2a4zsfsEpgLVirpuH2hmCM8dBG3U+/cHrzFdy48S9OsrKGvUpteP5SOaW5/3OXsHJwmjIHJL9Ox+oQSSgp2Y9PTkXzMns5uFb/r2+oCr42NfLdH1e5ZEMbjd+8C21Pu0PueG/6GJ4MwTLKsOpELzjUaqLuFifc2zQRPnwJJrnwVrJet4YK9eah7g81+oEjYPyFOHpj7Qy/3b7jmrLTOK75GOTVTyNLz2YWFxrJdWET8fsVc3j09y6+lKylG0d64GKdBb0dlMC1wo9B0VgCrfZFUaB2HbQ1akD07UIeNzMDlKWWoMe1SrzU+ZEDn32EMfMdqPirAD6u8aJXqWNhw3QTXHQT2E+kDkdpZ9K15FX40FQKFUPW0KDaXch4l4+vjgMUOFTDqNcmPMo+Fc8t7CSxV+IkoStFql2r+WuSCTgt6eL78rJwz0MWns/1xr7IFtx0ZATJTWnE/aP9+NfLUtaaxtgdJsjxKWpQ432at6jrgEPn5v+j4LyjQnr/OP4ZGtoa0pBKQzuV0pbMzJSEBokKiVKh7UuopEFFRpSRUUhZSYiKBiUkKZQkK6NC+PX79/7x3Hue53Pf79frnHsuSjiU4/tPvaB2xAeL7y7g7THzYNmzTLpfLw2nUqLw7PI3NF3wCdgOXdv2JIx3SE6ltFmv+GaSKH3xGkmlMeYwIm0WRQc1cfXAQvql+xlkqvOwZaM4mY/aDv8+ddAR90VYO8MIYgxfUkOCPx5aIQEfPf7RDLct6PFeE0pWFaKyZAdOUxFjf0Uz8N7zC6yOqbPEchVqn7MC/3xeyNseVeN+gwE6EvSC1ytqQaaTKBwu6ATrv8fx7QRVdjfQo4AP0rTebxQ+3JqCU7xXkZ6jA78eJwx9fxdCs0oBnMw7i9P1E0BIs5aq5KQ54+5ILK4Lpi2zK0HpkC1sUUnFtWo3+IjDP4yddwjnDvW0yJb7cGjMH9SecojMNKdj5lwtCNygRtej3Sl/vRz4SwTA9MeHcU7RcSjXPchf/s6nTVNMYZ+1DRzsu0D9oStw0bZzsHKJPTrPSSD5vp8o4bwdL3kewEuxttibMxKirL7j7OhzdKj7CHmeGcSX+/s4IGYlPvMUJisnZdqxdhW6fx0DfZKBPFiQDW9VM/DGsEZuPjeAS1V/8FR9d/z2QRr3uVXT4X9mYC2gy+PzRNDbsJbeWAnjha0P6eTJbPiXKIk36kbx9+5X9MhnOGyCEogtm8uNlzPxYmkhHMwPIatD/uD7TJ5u/zYHRYgAHwERWOPbDYkr/4MKcRWw+jofx1bswgIBMf604BEpbcpmpVvL6XaVNTg0dnGnzFhI6/Ul78sj2CF8FfZmn+KaH0W0QOkiTfieidJDTEsqbhA0bRnvFpZjd1lR6NieR6Gb/mB/ggrmhvZyjPlXMD9qA5cWb2ezq8683GUzndRo4pgpI8Fs5XVQd7rEd9rns+qYK6AWoAOTNguiqNNrmOSxjx9V1MItLRH8VuTAYSPUSLj+Hq5fE0TgowR+kYJU1edH2Tta8XBHAJrL9mK/8U2WPmMC4bkXydw4Al86ikBaSSKvN1CnYocgXh59BkctTx3yxSMQOf4YD1t/GQz9W+GuhhJM07rPVw+ZQGWWL+bvH5rf6EwMtCwnj1u/uKf+Kx886YM264dBiPER/myShW1OAnBwjQOnGb+njsQ2MMk+hXu26vLw2mXUtlIGHh2J40MPX/Nrm0LeMekxBcwwoAs7EuHT02kw5/A0enykADpr7OG0DPHJKjN4f3g9xwow7trvBWNle3lQy4njb1bgjWkFmFVgDIu0FVistgT6inRRbOtxxhEP8PV1f+w4Jwm+KyQ4Ynogxn2VgyV/tKB762++98wT6l+vplr/vfRMUxy+b7yJyy4/R+tvspxVLQEZ2+fSX5MC3DGe2WpoH6Ml9/FEk0xWfJsPiyel0bu8jVCZLAMRv71AaGozBsieH+r6UHR+MpUVw+bDW/bDn8od1DesEt6am4JV1mfaZRPLZSsdmOq7yXRCGyncqqO1yU1cFeNNWzx7oOqkKrQeHw/Sia/J2qWZtv2owEWBQnDmhhF/1/GD2Q65cObWdcgaZgEHDt+ANyn5AMt9OPvNVnCxAlZ/4EXL3gqxwJdugA8ZLJ1vAvItS0kyPYH06TsmPzuI4f2XwXXSTxh2OAiKs57xQc2xXKmG8FklHsrPjeJ6Y01c2r8Nl08fyYXa3vhwQQlGVYlDbdM4nKSnDAJvG2m26U44khPKp45Xkm+ONWcNc8ez/pLktUAYjz9QoAppEdCWN4Uw+1A6mb0DxMwysKbuFtw89IHtkqxY2DeH5SeZsvpwYzAUOA2BHRvYLqSbzN+lw2TXKpjSNw1XtYZAmUwtlhjrc+k9cdBbHcX/EseCWG8Q9H66DRcH7Tj1+A4yqK5ggcb1nHfRnbfMAAh75wPiMy9R+jEdfnHwPkqOv0YHvkniL6sw8l48lW8lTaat62Wh61UE3I18QGIWleQ/ezxYPP3HTQERsPliG0qPiGGZodz/vnU4iEdsJ1Hll/QixxDhRCWte9BMuS9f09Ses+gTPZU17wrRbVeGj9sJ3oxv5nXpm7F/1QhojJ8Ex2rvwesjztz08gRJSrvCR4exMEOTSXF4J56BR/ynbBB/0AoQ+G8E75BaSFWrk1BwwyvWcLEAcx4NE6ZGgmEdELvH0lQppuCf87B1qj3PytwMTse3woCXKryxuAR7VgeAS8FOmnOvBy6114CzQSBYhy6F7XdP4IW1SehiZgzOa2/AtuZRKHq8gsKtRdBQ7DUZRp3EhsBSzt+7Hdykh3OTuCLY1VVj7BIzPmIoSMv2JfK4J2oopLQTu5SMObjXAVuSd/FDIyn45vACZLpfgW7YuyGH3YsbJu5h80tpsGT8PvqyLpQ2she+O2sJwZlZGHbXDp8c0uYCOXNMnH2BBeItYbrLSHj1UZL9sqehdrkOPHLaRue3RoD0UNdmhSewl/gTUl1ahIop6mCR7gKidgVsrC8Ph9c2048ceVisfgN7U9N54W4RPCu2gJbnnMH5jcfY+F4BJhmOgZchw3FmtR/e1ZCmUYEnsTnchZ4/q+EO38O8T+Ugv20SpO5oTQitEmaV3iz8FvAURu/RooC/myBfdwaMdl2D016447nYGihaZQO/bWU5V/8hnrRx4p03hDhDIwnfpQzDmsxxXBugBgm6I0j98wQY7dvDS5dcA6mrKWz8ImbojPZTVslpTqmtpuFf/qF4bSRJNQpAotpXNBy4TqvmGOHY1ao4u1kLBpYEUG5qOhYcOE/PRb5SzjBVCL/4B7fqBGFR+2tQLdbkgmtn6MFlM1qWJwnVwWKUJu9Ihb8AdPJKYEtxAD5sL4GmgVDal1xNZ5fMp+i72TR75C66tcmNTidLQYVzInjJfkQV4V3Q/OgeJN2V5vlb+rFZfBO47nyLuK+WVRchHDXZQAX9H1Bo4A16ZH+B7P23qVNDDF+MIL7ZUUBj686xTq8k6F9pguf1k7h+43P8ktUKsbVRLHn5E+9pz+B/awTgbNBvsJhkBv+lviI5173oqXqfv1pH4r3bE/mV0TL6pd8A3uyLaUv7YV+SODhtqKAqy3estUaQrE3jwKfVAjtD2zjA/i5kGjXQpaPbQLlWC4K7P9PJkmZ4ExgAJnOUKWleEvbvm4Tv1nuwu2IqnvWbgIJnDOFY+Euc4ZzM/QdtqPnBJl52TJi+TzsNlf9VgUjvZkx6sJo6m8XBYEcmUHQONGfH4J5JszBzfyMX7ejFi6Ma4Hz5fXz6yo+31OkB9wwCevYO9UkR9Ey4jgeDOqkuYxQFze8C2W1mNEwqkNoaFMHsWyiMvVpPYw+40SrTKH5R2s0heVmUtWIX18rrw/S/USRVoQ/lmx/gkpjnWNo/mdsKvuKp9f7MUclgGPEd5qTnc1PzaTjuPgH2bHRh/6obVFxqRFrqS3HhDycsPhQABg4rYMGXs3jVYRrtqhABN0dTnKscDF+DpCn/0AeQ3hIAC/a1Uoj6d1o1agc8nvcLr5aNgFWFcVQtpwE3yjI4J/QBGimHU/CNDq7cKkims3ai0vMmiAhVhN+zA7l+zC926VtKgmlNOF9FHFss38DwtXPwosFc+uX4jO40TIRLdf+obNwl4vM2uEH4FYt3FfD7P9vgq5skfBTaCD86HDCx3ARm7DSiCeYioBG1kVfIlPO/6/WQs6SE9b7K85zJ2Ryo1AHHDgiCqHAXf5L6y0VbhLElcSa/ff8GpswdAQoG11laMQdWN9rQ1SIzOD7KgwM/NnPSxkp4/y2dC7t1KNPDHwOehVLYHVWKT7gPY/4NBz61kgPtrrOenhaUxZ3mmM/raNzLr9hw8yK9L3sDH5MtWGytOTy7mIW7F4bwoR+j6NmVqdByL4OSa+6TUF0fX/pvBTSYhKJXtBTIHvMAm8BLUHx/JfdJ7gTXE5ZcdG4Yy4SOZT+DTix7PoAWMUP3Ur3IX+Z6sHl2JgQWdtKOtkR4/0GJU538WCjEE/5eeoi2ltow1leD98XGw6kQG/jmNB2ynm6kKT6vKP6FKR1S1mWXYGdU+yIM9wUXoIdVHyTf+IDLLgJ76gWjvvdL+nj1DjxPdMGouN94bKYOjD9uSFK3jVl7aSUdqLGj768WUNsVaTA7s5Scu0dw88f9XKGuCor3XDFHsYwyQrdhd0sq/HZSxm5pxLudyN9VTCDfwBrcY41gID0EHedcAOOSCjr+0BS/RS8mg4lKeFInn9dG29Ffs1ia3SYNNU4RoHBDgiYlHERd51Zskh+GF97NpKXD/7Ld8gZaUZVJM5wkwer4BjAZMKOSnz0cecMLep2u4AP1dKjz+E2BZk705Pc77ptsDsGrlcmhUZt99euoaFcYrDdy4JvTDfhLTjZ/7UiHvwf/wuWVSrBxlRemQC9a3LHhbh8fFgqwQUODWbA8JZRfS33mloIsnqRrBbWzNTirYx9U7bvGe64sY5ODEZy6M5MD7GaCRclBfFYwg/TKGRYIviOzh+1U80sOvwUnQr6pCI2+/wf/zW1HDfkLvMy/n048swJ7g1SM+tdBf/SVKUg+AJvvjGNLg250s2qGw4k9OOXUPay8rwOy8xNhzJhKGPkqlPU94+B8XBx3SGTTek9laq5ewk2X7CFcRxf8Lvegw7/fLPSxk1OvnqJqxyXohrtQ16dpiFPnU1xiK/aLmsOwtWqY2W0Bm6VMOGCDANRlvGe/TkeYl14Cl8+dI9tjRzgs2x5i3mrAYMZTDDGbxQudL/HoQ83wK203iBkvwAt3+knScgn3yttC90x5jjcfwAsms/FemRgGOEWTTFAK37aoo0uZa7D/+xUUeK0OF8psOOLnEbA9K8SHVW/zq10BfE3ZEjutTODY1m74/liSi72lQNvyFJy8IQ2BS07Bj/oo8IqzwJ/l2XjBvJC1Ldu51vscCVywgp/JRmT8VhrrV6qQkZYn3jkxBVbsGmK7U824rl2FknxTSPiNFCz0PYQlwaEYdj0cF6fegi51H7g1wwPlZQrwj2oxOn7J50+elmA0dT/OeVJMcwsqAaY48YrShzz+nQb9PXOcpju38aTKTtzwZAw8rJsLNnf06ZzRJ6xb7cnXfF9w5J5krswtRlHx3ST4tYgqHCZCZV8vrU8+AC8CA+nsmwf4VMEJvD9vIpX76vS3fC8nNY8gI1VDGD45Gad9FqKjSS2w9MB/sFHyDyyQsSP8NZoeCqVR3kZb0vw9Et6dFKHYK5r8c8ww9GwG2hmdCFNfmuCxFwW0YZM5v7ovh5V/FKBIWHSIQSdh2I8Y+t34kL9pucFT5yusL53GbtuGMbT+IRMHIyicfR4nj9xC5kLWZKYvhvTzEWh6eeBs0T/8ZXQinEhfQJG9CEFzE2Fhez2KexmD/95UePguFh16Hw3x5SIK9dDF4Kl/uS/VADS0mnmqbgfOmiiLKSPMUatPgZrjVEnm/RyaJyTA0sX+PHCKwGnVLV60wYkM/uwl77wkdntXRzKNA/jp4zlsdHgOc1wk8GqFDmhWd+FKpdFwRS+MQ+rPU4i3MJZsLubNo+UooTyR3p/14pJiHQh6FIKL91+kARE11r/+nRPUHXiLRRT3nbOiBwElONV9KuNzYbj7NA9/uQSDye45uKNYgl/ekAVXCwnoENxK58/OJh/ZkaCaPwEc1RP5edpp/GcUiFl7p2F2VTKPmjiKE/f38N+aSHq/XJaVXNRh1RUF0P86BjNqVaDnz05o2rgPnpjG0Id6TRwfdp2bjxhzdq0RSG33xNv3PDmo/wmJTdcGxx35cHfTa1qWUQbq+t/pZoMTDO4wgPSe5+R8eyEs/eLEecapsO7kGxJXfw4ST5FF6/zo09inOCVJB66Nb+IJi3qotu0xHi0f5A7nXrQbP5w8dgjDMaUwCH6eBj7RE+F+pCx+yJKlkf8c2MX1BiVoCmCUQxfUyAlRXO5rjlt5G0X6TeDqqnn0+EIB+Kz5Tg/Ol9DeGYbYdC0RRoSdRaGolaCgqE6jdwnAwlkyYDOwn+Lff2EjJ1dQ+W2P7XN0QSxbmGd5G6LsFjHuSwDYdWcXDLT84KupeWA85QRs2PqP943/D3Wc9uORpUYYMv0HXVltB8lffGAw6zmUSEwjFws1SlyuwwtXzqapapqw/mk65U+3wnFmNnBd4g4bfBejXer+eOBaAL2umMGl49OxP2M/20UrUfVbQIF2RRiomkMHbwxCh68t9V98hs4d0+nobRl+3G6BAU+WobapDK/wMIbGT2fIIWAjSE5yoHsT7/DWy5cwfuY3XvvhARWd7eNh4pKU+kwTagqT8ZTCFhhV3kzGP6P5QOMkPNV4H71Uqvnw3y1gM8S+ew4KQ6xvGlX7W+PIjhXk9a+Z3YI9eMGw0XjZ8SMa5/SClNB9fjlZC6ZcbgD5cFvc5K8OPboDKPA3gv48nENtzpcp7VQOhBulwvpkZVhYGsH2I9N57+VhbJP3DY/fikenlyN4hPNKWgINPG/TJtq2xhLExFPh82IpGlaRQGUrNLDU1Jpmnh1FzTfL4FC3PXReNYVRLSqg83Iqk987TlRxIoGpzbhqykeeqXMRDAa8EbU2UNorL5yRZw8/dXzp5stA3v85lao3GuLGrqkofDCBfCT/sua6SP57egHdtROCZbUT+HT4d3Tt/wCHx+dCYLEarCr5zYfHC+AW4VSWu1OO0+wEwOvBOJI72kqPDxThvMYkmPmhkSrb/qNIly80UzsPI28GoIHucDh56RuhazIeudiLyaIJ8OxaCaySbwZraQ8+XxhNJ6JTaa3/GHg9bzIaGPrC78AvMF7+DLsfDyDxdfd4/NxaODHClObOf4Aj1RUhWzcYVgwWwdS+Xvzgugd2zGihlcm1qHNZjosbMkjcsR1dFijAwq586vz6Bx89N8Fkh1Vwvuc37S5fw9ZCCnCr7RKZZ17k96+Gww0hWVybKsQCt9LZN8EVVtu8gL5XNrhw2ANSCTxIa6z0YY6KPHh22+E1u6dsuG8/Fcuug4my6uD4SAt0QyqBqk7y0oOncftHTRCbN55mBGsQdL+jA4EpODrMkd4NneyP9S20Yc8Rys59CibeMmD2WRRPT1iIq1P/Yd47U0qRWc2LgpfS9ksx6OBTy0I9jdRcZQd5GmPRoToQRi3WxMXqXyFqQhDsujIcX7QT3pvhTkW1xhBlrQ2rgz6y2oYxPM/pDbs1RKJA1gs0rlXHner7aPHhiyy3Zh7FsT1kWWyDp0cngOzFBSwrMoCP1xXBP+cPcPHqZny1PREfNyVQ0bexcNnUDLZJrQC1//8nFrbTlyc/UE3LFWcp/caZ60YQqQyibZQqPLhWz9fF/+Iv/QK+/KkF8vb6cJKhOXudKyB3y6Gc9VLBYaHycLVLAhW9k+F27B4yf/uF/s3aRz+mfWShT12gv1QH073P0pqphmD8XQzj3H0p1HoGjGmTInnPO9Q7ypPPaRdROZ1lyfrRtCRRBxQnNMLonR7kZX8ecgckedKCH6SwbR8ZT+1C9xWROH3UX/AcVADFhs9k7VwMCZc24clbZWTf0ItfPQzwgUE932r15y/jB/CaykgYbS8PywNVsCbXkHUN1uBmtSbQExXCxu3/0VovS9JPbiCDM2NAt2gaP3mdQG/sszEt7zAqjfFC0CAsyFHnmYPbuLarFfAcwJzkPD495EXz8gmXOa3B5ydesU/0UUp5MouTfxL71diC0bSJsD5MHls850LW+RxYKv0aHO/bUbb6UZRdWAodk+vBYPAvPmkUg845AvzI7wcdTfPHc7sTqW9jG4VulsfPCwvhQeMVsrNtpwdrDGDBj0vQ3dmNuen5KLhrGHd9LkC3DfJk+G81CX87yjGLO8H0ti54Co/j4/47Man3BzzpE8aw9Kk8btYf9Eg+TxLJ2WQ8fDervRaDmReXQnu6CH6fnEVvfL0g96YXeWrI0J/HR+my9gYQtBDG+S1GsPyUGGSsYwr9hrTH5SXNDHcHoXe+KNkZxvLHbuH+racwMVwOdsocYftXojTScja7yXaC0hZm343nqeJQB67cocV9611wxESA1L597N8wlba//khKNhp0x7uJlU46Y9gxY1bpa0YRsWmwyXcCHG+bSnVTV/EE3VBaItNFPoYLUDZdkM3/TiKbiwpcPlyE/kvUg5m6e7ld0o6sBUThxtZt9HjrSh5hkMmrRBR5mJsbLL9/j6bqaoNs2FQcsdIVkk+bo2Z4Cz17u59U4vNJzSue7m5w402plyBriE8/JHrhiF/ROLq8j1K/ruLW/O3kErOdjRpzSDVtFTp4u2DyrjFgqjqDrU5rUq7JeTqRep4Xf92HwaeMyXTrTdyaXQ9mm4fe9aMwxF6T4fzJYyS1czOs8ZhPG8NucfGlRFTKHiSj1BCqWHGTN7zSAbH6a6T48yvNN3Sj7cs+kHXpZxr9dA84Xh1As+4W+FsbCcrf7OHd7k90WFSdlrZXwsqVvqx8oJnKjL0wPv0sLJmwnI0D8/FP+ATYtLQclg1IsdzYWpSbNouCDtWh8q5IrFzyHb5VDMDbntH0OsN2aEY6UMmyhDYqFdGg3WlOq9ACjZFW0K2qDDFzz9BJjeEoNW4CjHvSDvWv7fiB1hmo7T4DpsYb+FZFOoVev4rXpnzBuOJi+Pl6AphINnDI1kvYWiYJ3WmyPNCiytPumWCS/1y6YbIC5/Uu5sGyYdDavp/mfH8MSz0ukdjOcDRt3AQRDUGY8GIhvlK7Bz8en+AlC4RgfV8QmnQeYNujN+nplHc01jYEI+PWcskPR3jw6RAWedmwnqkF9JfZQ0L/Yz7psx5GnIvCkprxbAIt+NEhk1QNnsMOQU8+sn046C/wpF6DS9DcuoNV1oWSlPYSHNyjg7cHluGMbYdJfYkAh4wbmvvEdlye8A/E3vnjdW0dyjEw5o83LPnWvWbOPxwJv4V0YXLmWDA+GIY/NlWQnqk4p30QId+wJ9TpmUh6n3bDeGsr8j34HBKbRODtwSY4hA94UncZtW82IYlt74fc4j94/1wRhlCX/N8E8mITSzjq0UPJPsLQq9FCCR/+kU/zTHb/aQuuuVuxdcJCeFtayl8VtGHTpRbw8vyDFQcqQN7kALSXrqZNayt5T+fQYu0KNNrtHolckYB3PzWxeK0cKB5m7h0VgluDM7Et0YNCR5hRbWw9PpgZCv0zNKH2gxgJHZfAiYfL4F3dW85qXY/Ri0NQwS6cf6aU4fwN8xCXiYCn0H2qXJ4Kmgkd7HEumnUeKYGG2S7K24voq8VYXX8S5LzGwr+pudBR+Zh7fZtoza5JMGbeW7h1uINn6MZiWJwuHYm8ydU7xkKAnDYeePIa4jtOkGnyHnDO/IRrR2ZyyzFXOP/BBR6nXeetbjog/X42XPy8AEJO7+dj3VMppXY1PnR+walnbtCN5bZw2v0ObRklDCYvf5NDpw/2vs7gGSqreXCxJKhODuLpChk87qAM7euwpCBRKXAckcZmCapYOy0enMeK8YlpB9nGZhD+Fp+h/Nho3PP5GgpsUwWZ6XkUZOFHpoprsHRaEvhdD6W+VxrYtOEaO28OIIutC3HwzlhI+pBPdUWNdDfBAMeVDGfzZ9tg05ZQUFRfAoPOuXhe5y18GT8SKu0jOaIqn8XvW8HenQrcP+4ZvwrvxRnOs8GI5sP7C8M4Ipthh/NdKFiTwrWNYfzr9G2O6h3F9jaPYF34TFJ12I+5Ri64NZogZpY952rd4WTazov9xvDVYF2e0e+C4jLTeMbAcv7V6sxpYxg0lpygKaVCFGX9FMTTH4Ot8nFoKR7KmJr3pBhrRmPjHmNVrAWUTVHA8IVpMMxnHnaGrMYVFMmrL3hz7J8PtHfES5qx3m2orRneJ04Ey13hIHs0iY8X+OMCzwX0BwbwkVgQBvwYg+lF5XBnhggUBIdzh54FivxqRSfzGna0NoGFq+u43VuSa59Mw7rPXyCwUxE25Hvh3ncFFFqXC8K6NjBnTQYfffIHz4bKsM87gB/XJ+BxG10QcN3NJyUv4ah7grCp4CI92hGLbrIKvPVFJ9PJrZC4+A18nqQEPZ/nY0hjAR3JMKTdWVo0pCzw5ttkfrRxFLyvk6CnzpM5MkoQDqVMo70m3pQ1rg52DdjQFhsnCnPdATO/1cPjISccXDQZF/uPBcVWfRr4L52XCOygzvVWtNDrNLraXycZ+fd4YlYOKUp9Js87wiCviXDoykl0Xe3PB+3K0MJbm6ue7AGRHTX8KGQyWgefpdivQuCqnIZK99bDVZ5I52L+4l6ZSmzU24t5xoE8RZP4XWwdzGgyhUTvBPw0ciuXqr7nH9W/aaKXGy+3ymfH4ETo6/XApfUhrCOrA2/eqlPTp1ZuSFjEWvtEaFSzHPkFxtBLj0e0a2YZOL2zw3FDbrFisiB555qwU/96ssz9iltX/wdRoeFYZrQQp627Dh99PKCIBeGkzzg08kbe2NDCOdJmkOAVAMu/PYaN0x3YT68EL848DtOu6sKa/3QpVvcJKw+F2EURH/pu685vLk0mvWOH4a11KVudreCtQz2YuKcdeiaeximFjfj6miTNywxH41FLKfSdJTd1jqJ1Sf+RYqsNvBL2Rl8jdVrYs5Nlzrfgy+AaCpgrhwEvc/DJWBGIG7wPbgt1Ycprf3weMYUjvo6G0LAWjlOLx3UNyzBpnC69F5alEQ3PcTDdDm7PSeLubU9JK2XvkMO/B0NW5Blvn/MHlVVsbK7AjuVeoO02EVp9teCG6zka1ASsCBKEWpVsnBX8kja7m7DfJ2nwrIiC08NMIVt7J5jHEtaM8sRTlhV8aMJjvJE5irY9LEPHcUp0a8s80pI3Bm3XMA7ydqf8O47QHr6As+d249m593jTBS3oPuTO8x3H8esUURC8aESVMn6c5rybBfd+hLe2J0nhiTTWhPzGX3//4wb363x+zASoiIgGuSRFeNbVRTeXTYHN5yr5U+1fzJ1UCzcsv3JytSiNWjcRfku+RfPDz1A1x5kdZj+Ap89l4dmwPFT7gVipvobellfjUmkpkOi5gQFfR/CJ6st8pj6OYlzPYqDNft4xP4EuHrzJzmNd2W6HFXyeowuzd0zB3Q8vkM6sCyxgboj9b87gg+0+fHOlLKg9mEltgUaQWHmH80MVcX50F2+YfxNF5XIx5sZT/rMvhbyqg3nH0m1oWyULLvY5pPSvkb/9SaexIkkopprDCgeDSSrVDSYNd+eN5+vxgL0tCC45Dw0xdrzAzYPuKVzkrV92DrmHBfs+3kXzXh6nfecjaWynEWSqy0JxVBCeLj1KSS5SWO9YykeO76HQWlE47BiIIRHCtNdIBUYeeUoRepE0LP4hVlMmfBuxBw3SkrDT/yuIG/6he5l76ayTFbRbL8RFkbJg+fcTXdArpKKUY3xS3ZTni1TBXzbAWUdzYYmlIUgUWrCm4CC1B7tR3R7gK7ck4UHJS0jY8ZQma2XCv89OpJ9vC9+KI6BpcBPejniFbdJyWJLURVl57rg7WYyu7xlGihZ7UAuNweHTOejo9KR/d0so/fN2Svv2Hc9G36WfgW9JcV0pz0kM4rxuE+i3Xkz/3Z0Gugc1WCVyNQdUr8Iv7TPx42HiD//sKGypJc32t4JwoXDQ8Jflm68X8HVnVVD/lwdrTZmlZ3uCwMlfsP5uC66xHQ99X3IhbW0kXFEMQPXnlykXslj6WyYlbx9PTwyreFLSRyrOMIPuyx9huJ8Ctsi+B4tT2TCh9Dt89J5Ohlab8M4uQfhvhQPcfyoP6yw+kLxyM58hPZxgeosubDyF0TYa+Ml2K/0efoH2GfSzlpoQxBUeAvmO21y1ZyZ/G/+QB2tXwvPZ0dzvv5vjajNhcfoEMDYaAcrNH3DH1Bx+azIflW3OQURCEo36bcXlpcBi4cJYqzyb/fLF4JWqIlTl/aRVuS/5ipohjtf4QucScsBk1whSfDXIY4ZvpoflAqAqXgOmaoDzRRRprKc0GzYn07c1s0Frpzso6R3FB9aKcDVHDnbbJtB3qzOUFj80/7Kb6diTCD7rb8JxMUdpfu8TnBy0EuYGiUHP9pXc/X099wkPeVX2Ub5x7RvMa7BEq41ymF95C/zMU7i/RR4mGajD1MOJGFpihbdG3qRn63touiNQzxgRejf3NvO9TkIHbZhg9AuvrlyDK+8VAIZfIDHFQNar+kf7ppbjk9oeDFaJR4k/ihAXNQhJi1roTrcLmN+bO8Tn/jBz8mV4Nuc5t0h1kdTtStpQKAu/foZAUJcwl2S4wcX04ThZkVnczADTjtpjYaUZFv1Jo+5ac3BBZVYd18cNsxQgJr8dkrcgbZZQw+WWTtiZO5MFp++AmkWjQdizgdTfV3K8uwSrPKrD1dGDcK9pJ5SsiQBXRyO+NPUYjqowhu7iSLb4gDTRTwg2x1+FCY8X8dOs7dTc2sJee4RAJMaQVoECPLrZxVZr7fGymjlb3R7DyonneOqWGXDk7Ufa4VIHEcHSHBulCzM2/gb3r8tQ+FMQdd66BnelTsLHmny4JzeMtt5rJAFPC1w9RRVil93EwzWrIMBWh/OVP0GkqizZSUfxTPELlBM3QOtNh0N95EQomu+B6r7n8L9h/1CoxYxLRSX4g/4aMqRh3HjOgR3ULoNJjw60mthicM4CTjQKgguXNPmpfwUmN83ja49UwPmSN1taHeGNZgZQ2FQC0xOq4JCyIeyct4SljYZTcLAY67w/Sbu7XOlfqDdc8VaDGDsX1p9SzfEvvLD85y7K/rYRwrwc6fGUR3CuZxnO1wB6+AYg3uYL6zTV87Qv9hQU8oPi4r/iu7Pi/N7rCDs89CTDOgXyHG0II+cspuxTEqy2RgGSSlTo2stonFz9iMb6R3O7yhQyfJMCDgoEj9/GoO6lLuwxUKTlqsHoJb6O1H82Ycu5clZXCkClPE/YedsaakyuwaoAe7AZvYx7NG/QeelvlCVug5ozi+jJrNMk0B7Mq81s4Pe147zkxik2lfPGD1eZlhp3oa3wObxns5PG2NmRgeMi+FmoAmsvn4X+74148f1NqJG5ggJHRXDM3P34cI0RK4r85A+WAjRYJwF1St3csCGYPqaKc8d8S/7bKgkjM6Ro+mQdoPif3BdWSZ6VarDYtB+XFs+HTskzqMoPqUC9B93umrOSvCYdWe9Kj0sl+YLkcJDduRLjOy/x+K5I2tY0l0pyOsj3/Eq2j3zIoion6eLfXfTjtTH49m+j9NISclMoA1P5RfBQbyYscLLBzebzoUTUAIRyG+Gkly7s5Et8Alezx5En2P4ygXWuXqAfXx7Cx20S/MnLEdK4DGVTJKE9fg0q3tmDJYtWgdrFLtqsVcE//3zgfetHU8nFjXBBcyp6fFCH/xIlcPPR25C/KBJnnm3A6vxnoHO1GtuPxlF66FM4O/ERPA0l+GGjgv4v7oH9RDeu79PAcXkfhxxoHV8vbcB3q0xoiuVualkpDyNjxTE2XYB2K0vS7YHVPGXCFnpsWsTOAU08MbAHHy39RgU58lDCl8lh5yQqLFwCsj47wEm3AuhMOfKDx2CeJku+bTdw9isBGPHkOh5IvIKebZ9BdoE6xQ9xcWTYd+KzyFJzrtLrzKNwLk4bLny15YDz1qQsV41/JmhjR2E36/kzhBk+ARXnJ2gg1MmhZAtdWZ3wPvAQ7i9ToAUpxbCoYSwdjI/EtxZ3KbZiGJ7+sIcnxWrB84h4alBqY1ef5/hLqAwe6N4Fl3I/LqrSYK+REkMZbIqeRTpgpCBKhxaf5gs71Ojo5pHY3d2GsnN1waNiBbeFrcF3Z8K4aZYErLQugOZ5WaTZo0mj0mehRk0EXiwn/hlwCNpEL2GXXQTvz5WAAO9vVEfurN/fQ+qPvTk3ax57RAWCc7gohcpnIazt4nYvNbg2/xIP84wj5RX/cdSOC2wlXsVNFMKVhSHs23ML79n3wyJBKSidvAqrq+u5R3Y/h0ybwm+/dMBXn2LaH7SBtRLV4PVpVxhuMgEexBXA9Q8vSDq5lQw8vOHnl3zeLOpLtV7TScxLBi7Yz8J5t/XA/sdquDnEwzGhGWC6Ro7LZvyg4ihtyHb8zE/dHGnxu7m0SEYNHPUXg25BNH6QOEuFs0ZCY4cnSQYznfOTp4xYJ2yb1MWK+pYwsPAIB25YwL8tV0NtQxe82UA8Y91tmKBghHeysuix4H+sO8YI4tNSIWDeEXyGiXx2vBpbzjpH/mciYZN3I3uFrsEIh50Yfs8abttfoLeLN/PKTj/uMHajpWEfWD2+lTLL3fHMi638yPkgJBlJwRNHISqvkyODy9NJ/aM4zIodxzmZpdzh+ZKj/rlR1I8DaOkC0LjPAL8OPKCvc8zYekMt253pIdFAYQxJvk3GK+5DyifkM5NUYFbDdr779B/oPtnP1x/dhMmCNbht4kjOG7kM5W+ksMBKZXRbJA+zfYVwm7o0GE24R5+KYvlY8H+Q+SIdDtnVYmrkSn6gO5EvjDAGkW93uU1WG49LFFP8wkH0OVvOEcP72UUqlBZpZoNAUz1+rx8N46vODa0Rj5NfXIW7SzbyBPF9FKl7mSeluEGnkzELxoTAy/DRMFr3B8g+nk6Po+ayyYZ/dPyHPJzNSIM9QcvRIVKelvd00NFghLSeekxucASnujiIC18ErwP1ufZ+I+1yccL2+pOoVL0Zcg9ZQ7X+dLh47jE/XXEA5oRXc/O8U+hn8gjC8tTBO3YcheqspMIhhhloKIRL69Rp3+evtDekDP/YC+FH16WkbmmO158OcOuFw1hdawlib5eC5HI9kmv5je6ymrDN4R5rFzjApIpgLIk4j1HzrvPFSbZwUNaRHi0r53r/Oj4ZOBGq/6TDr7eCaPOmHnW37gU/+VQ29NCDNyKz8Lz+BYDT57ElwwD2mUwHkRRHkL8+gX8f7+PkD6JsaqcALr4RQ3tjBzBMlK6ejCPpczfAbngqVa29jhc3X4Y0dKCds4Vg7hM9/v6fEEhICfMbtTNsd0INY+b1kuS6zaybJU155VmYetsSrrRY08ZLlpAX5QbPIkTxYOFM0pizC2fBebKbUot31jbyT00hEL9xAyOCpqCRiRIGHU7D7qpmPGURwkru6RS85BBs9n7Hdh6isKYrFv2mXCHbh3ZDz3YFXzRs5T+bc+jqCaSdkQI8P9MDdj/WBIO5mfh34ijc2H+Q07zlWSasB09/PsOj1ObwrLvBWNqxl1W7hEEz1xwUNo6gl2oLOTV0Ac5rKwU1eTnM+3UX/Ne+pY+uVrS7SAEuFCMvtCiB1qotbKU5hh8bfaS7KfVwpn4G5iwPwaYpmvyzyggeCQhy1yRjLBjM4Zgzm3DtpR785WRMGoo3WC3VA0os9WCevRkUPDegjxRIWv67WOrUFnwxzJWumERz8Es9WjDeFKKLHtHJlJHgoCGFgj69IJU0HQu3RJDweS+e7LYBQwwrsDB3I+f4iWPGlYmgquXDAg98eOwGE5Z/ZMpWEnas0i1KDQv0QEQ9DmusHUj/tBRcj7kPI5UOoHTVbXq78wDJWSSgwLAIvqDQBJsGI+D37iVQfMASFu2U55HbNVHMRZAWbjWmOy4euDRZEyONDvPasj5oXpnPoGkHq09OxyTTx4Br4uihkjd5lyvjoWdy/KvvEm1pGw4BOIknFwpBgfJybLw3G/KH/EWrbQBt3UXhS9kVntWgAjePWWOG3hu6fGEcjK17A8qPGuj3SxGeVJ7DtiGd0MmrUXt9Jt7ON6JBz9NQeNsebqgexonFAqxcV0T71FNJwn0xqDXPh+klp3hjzjHavGIVCY0gCD7RgffehdLf7u0QmT0WzHE1VR1M4VnCpzBz3R5MSNbkompx2H0lFd+PNmLP2z9p6bcrMExQCAN+roHxs86Q2UE3yv15hwMODgdDa0Fu9tCnV5sjIG/vFIqs0ofDLTd5eU4nfdnfBo87FSGwUwKqfx1lM6c7sNb1GF1pakR7pxr63VtPt63+cfaw6/ArKhQX2Q6Hwq4D3J3URoXZHRBZNEBnsm6hLe+gXHxBFfbXydy/Bu+dEoB5npP40u7vpPPpFOa+mUOF4XdYriAV/X3zsXnbHZ5fdZ/f7TaCE1UpIPCJYPPdXor/D7jUbhFNz/JmRZer1HD/FC7MI/6v1wa2tX3ga3mRoBp+EmJb1dByiwtsh3BO8AiE+X6x9LsqGg6rC8AM0RoSWu/KUjLaOCjaRJMnz4Cdd0YgP60As2pnSA/ayNd+mMKtdVfol8ZDsN1cCT9z/9E8g33gu7mYUHclBoq/gJ+GbXB1vxysW7GGPvcXkdzIz+gc/QqtW06hzOfhQzzUyjPsxuEsVUcqEbCBcZb/KPuONzw2WYJmjpPB8JkgbEqZRVlhq3nD1G6QlrPHQBULuPlLGYPil2DJobFc5DsIdiMXwJFRX1hwRiqi6xW43rCM9U4ogdDNan4kmkOPcuIo8/MzTAsf6kizLbg3URpdV17EdrMMNBsrB3/1drPG1HSuFz5Ag6W7QGZXLE/I+AWVtQ3gtjyLrGKzMXWjNXjubqfXWW/Q981HuvooDtyXLkK/JT64LEWbrokEkcPuPPa6OBZ0PijwguhrtNcrGQ9EyZGr03daU2vOWUJ6vLuulSaNz4PWiZbwNfYHrX5jQzMvmw850nnQmJjJoV9Toe3MT1hQYI35j0bC6ThjqNCzpKaY4djzWxL8h1h0ocMBeHrCHoXaPGGKzWXUXbEBPJsVQSXqCr6t+s7r7m9DsQcZ9MZxLz0/dBle7x7K2G5jKP3GoDTHAK4pOvLOcm2USDalW0Yl8DLnDkyunAJx15PRzcCJbZ194PJeAdh31posFjznY7tsOEjYmppmJ5Nl6QtM/rUZRL7n4sr8AMh5Zwnz5ulixdrhbPxiAW7Y2QAu0SJU4zcBVpgHkqAQQ0TYGuherw/fIqpY3XsaLlyRyTlt3lxcugTzpw5iLizCeSsHUcJoHv0uMITi5mHcrTUHA9eeowf5Huy3WwWWq0bQA8+59GfXeK58Px+ePbSE3+ZDjnBZnz5c2Y4DnIvH97mj+jcB6ElbRaYhldCx7DU69oyHcNcU9qhYT14JT6jWZwXeyNxCIjr/sFR9JNVLGIGS7EzsmTYO8ttccdqtpXC1rxb9hSvBI34a6mtehRS56Tw4xQS3/LmKevE2sPmlNc77XMbCDUas7JnLffuUeLdTHy5/+RmOBRwHg21WTJ9V4PauQGhYgCB52pyWC/pxdFMBN0hZYfbmvdhw7CBV6awBn2XWEB93izIKJeD0sCBaXxlNiQNbsUR8Lnvf68Je9y62xGAsC5CGjDuiaKN+GfzVPUnXYQQJb98Loka1EOEwiEdlTVDPYzS6HpoAM7dOZz+Bw1Rq6IZ7HUfzfxcIlR6rU5JKM9w1vUPK2mtQfaEwFNyxx8FTRij3qoDqdqtj6Q4hWh11mxU19TAFd6NMzTToXK4AjeFXuXXsS1742pbHbqwg1x9jaM7iJdxfPBukDZeB06vnrL1vImyKXQ2xvR/5ZO85FO9KoATF8SRnPo3f2wTBesV+Lkoyp8FtumD3oAbm5EnTMY8gUg2ogrcizVy6Kwp1B9bDnDNxUPX1Go/S1AfdlBmgPDoHquYlcFdNMib4r4BFR/L5WMcRKo8R5tl/fXlviD4otUZwi5UMHN80n/wXn4TrO9/CllHfyOWrPRRaINR5FtK4hUawaP0YnndsB8skW1HZ3s980tsOnsqm8lhzZZJ0X8YWpzYizrUCoXHaZB8xnBS9K0lcYgVMzP6Kb2/HQFd3Kf1MjqJW5UDadNQWdo5+xX7qbzDzQRlUfv/Nq2oOc9Hgd8ycv5mFjawhx3o7xqYZw9m82TyQ4YCtcWvhWuNCND+RxPf3+iH05aBXzCfo0D1Bw//aQtKceXy9o4/HkDlEbfSh+IutZBdtilEWbbTqlhiZHntA9SMUYP/9STzQ9BR3r53F2oOF9K0M6Uu2IdREpWCO2iuamL2CP5cS/FPthmVaEXTirChJyK3niZpGIFYnxVt0w3FX02h+sloV4qeYwRrFmZSyLoTFsB9f3tbDppsnYML4Vrg+XgEenSvnU4MKtOaKBXjs7yW3/YP0qVkLzXoP4K6va2BJbQEfG/GB/1RNR6P88RT30BrKfqpilc3/v0UUpiuPvDmsdBqdbbpAs/5zRQ9XZxzpt40n6o2Fpqx8clb+SS9CWjjs5W2qX3gdN+24gAo6Y+iFlgvPDm3jviJLcD60CW5qlNKFj/osEX2S0l/k8cOYCLQIWomJMp8o8MAtDD1lDpLpX2HLAwPIOGgBo8ZYQ7nJT1o/2pW/K1nz6YSn/GLYUzw5Ugkm66nQ38RmHHazA+JWWXNo5huWCtoC6yq2oZWHBbomTKTJNBo0LN+ATuFScJYqhi0panw9/g6kHfzLP1pO4xyv4yA9qE/i6dawvaSAc0e+pJwkETy6CUBlxlmuvzUBntSMhHe/W3jWrNE8tlwbjv3QgHCDTMorXIUZniPpTmgqXo7K5SLDGyiw7grcnniFDIYzDOrH4/2YXAz1D6KcQ7VYf2QCHdCOoPE2URRjtZYHWzbgUTUpGKt3BDskxKB2zAD2blkP6ju0+YCDBk4vTsMLOWMxZp8UhNhowsuDzrCyeA4IndvGUX4KLDvGE/PFjvH32LGYfvEwWPhux3af8UAKL7jvyDOU+nGWr1VfwNBOZ9qlNo0zXMU56OEqCnI9i6wtAb8ja3GnUyetE50Es5vk6XDYXZa0Vge1dnN0z1iKM5a18ocDWtC9diItm3uGDws/pTZHRRCWnsn6CrNBd9k4KNOMhg3Ks5DLR8LMOUY4KkGDy0JXkH58Ir2pzsfTR8LxuFINeUt+w68Lt2CdnhLcCXnIUz1uwOTg5WySVQ6a4nNh58SrmK08H3Ri2yC9LgiTdPShStsZ5Oe/463FU3lX7ypcOjUCfR3PQ5XZGBK/NYJUbi3FrFOG8MWmmffou9KDw5PpRZ4pF5Yl8rHQJCoMKCTRxNngvG4PLDAaDfrVinR1/0449FUJIlZOhdSvzTTyYBPvSWqH2RtkqexmAoSP0oHe+GBYrOdAf34E8HiX//Dp9l8oYH2BFWPs4XW1KjRFEXqVKoPojCPQn2FHI4dvxxXPF6P26dVYfkAUowNWUBweptZ7+8lm9AjI5EFqEpOhFJ/jeP+pOmUnxaDLRWFq0+8A10cyeKfUhZp6reD3rl+kvsQKJJxTyVPDiJxyOwFDRCCyOwf39gzSMfqEQi9E4e4VU7p76CFdy2jGxScseI/LU/J3X8SocRoizP5RqXs57/ZVhYzFabxyADH5bQt1+mxnX8vdMKMQYPsWW7B1GYDjN2vY7bE9JPc/R4GLI9BiewcZLa/h8BRZHCPyHkTnb8b11hq08/hxSrmjCgvGiMCbgFaQn5jPIf5jMC3uO9x8OcheVgu5Y5ULjF8rA14BotC1UBsTvb356Y4B8tBKgZmfXEla+xa1Lc2h1z0P6f38w7TllBRkBhpTjIcc6+bHgAqUUu2nRSgBmrhh0kzKc5/G6ZEDvMFMFebrt5OiaCZ6Xekit7cZFPqugO1TblDxTxVI+HIbs2USwTZ+FJxed47fO+zDp/fucupgLRSFueEjsRFsF72F749zodN/f+LCYSLwKT8Ky19YUX+pKH8flQxl5RY0svsFmsJj7ufhcKt/GTbpS4PcI3X+b10RKO3pQ71pvnA5KBNvvrtFi6NW8hzDfbhI8Tt2xAEILFfCFP+tYJjWDwKnBjHa7zH2dnjwn2XO1Nv1h9O2XkGfK0rQvnE0XvbN4x8ZcdSy6zU71Ami4nZHOnv7Lf49oEJh0z6SZ68KFNnnofv98bju0giafWMHLrb1g1vL6ljmRRWZOLdi0vRGnqg4DJpEtNiS1VFWUB02UglXfUhD428hqBz1EiZF1vCcNT18IFwQSnffZ5Vvgnx4Sw4ckCSoSs4HvedpcEfdBsa4LIC0Ba95UaEIHLQ8QqkzX8Kr5Gv4c2cw3mWmyiJbKlGuJpPhwqBV9RBNvSfCpOx9UGL4kLuKBLDUbTcvdR7E0ZEaPFUwhirTnsDfIX+rOT4aHs1fixZX9sFcG8aeMHGQkW4EYTIi6cEqWhpxkE6oGaJJgxUIy+/DQIlj2LP6F1WcEcPb+hshQ8sKipNv4u2EFOi2uv8/4s70HYj3bePXgiREyprKLhQhochSKimhqGhFVFq1EFKhklJKhBapkJJKWVMSFaWVElEpW/SNEIo8fn/F835ezNzXfZ/n53Mcc8yQj9tMuPEtH92OKvKiHyNh/oXh6LSpBgYn7SOB+VN5vZoyn9ych1s2y4Cw4l12d03ApllhtOmGKw+XM4ZvPIjTM1VBR8WEvxc6w0NHgLt1b2hX4iZcrbGckxbu4YKmEry+tonuD/FFn1sqWpg4gUGnMLQ8XA0+T+7TuIlVGCclwKfNfGF+6GJcunwir5VuohVqBbRx+UwwGH4Fg6zKKKA3hnqvN7Dm7UhonnYK1RZUwpWgQmwu8wKr6eLg/GMTXhY3w20DToSb6ilmigZ3/ZbGU5PMaZ2oDhnK52NJqCLsWjafRBvzeKSZNWktLOND+8p5Td4wWuepxmMOisCi8EHcO2I6HHjZTd4nZ6HkqQ0UmDMGBReo4WzjDvBLXkbnttrw52GjKSibYQXewEdh9zm0fRZlWp2mwIVRUPzKl3qy9GFO8yRMnejH4ZkiUHPSGW6KauAOqcXYtmQzpxTsRR3LFhTVyAP/ubvJftg2CNYwhAPjvmCFqyS1vEvkKQojyVBrPlyWFgOt4CNUed6D843qMElQHI4qOZBVsgceonfsbHseZtba499T7qiluAfkb3axx6svvOnsBLhxNRH3lhdyz9l2kJvqADMe5kNu8w7+rCXH990GWVVFgVT3TYL65DxeoWSOeWO0uVe3Aq+JtGLkL0MaO3TmRhwuhz9GJlAfbQZW8wxByMOT0i+3wuLsr4QdzXjDWQksbdzpn9lbdH2WjOe+jYT42gY8n7sJn5yfBCl/BtjSJAEs3pkxZCTwr7PveNicp7wuWAY6G2bCxthqSjvYj4c8YtnhxCqcEXGNqjt+UYPyUCd+UYTOYA343WLC/V8HgS4+BbsIMbBwz8OzkZV4ceZxst36jGy5FjdKGgDSOziyxBS3zzjMvuv+0pycDj4/bBHJfRtPo7+7gPakDNYrMIY9qfHY7F6Nhi5h6CN1gLOvzYUKaWmYduQYLjrkA462/9B931gQeTmNtz0VhLX9d2D2x3vUPfiY3/4JxeqhtZGzWMoqudG4XnEo15YE42fXEaS9oIacdo1B71lDvfTrAavp5/KUX0nw690AXrMxgxFJOejT1It/tVMhbtMUbl2yGXqeFXNa+kFyzNTGNaa1POOCGOyqt8YjdzK5XvIS/hzvg633flF3/Cp4HmLIT5f789GoYZyopAF567ooc/N8aEtbC4ZvRVE6gNhNYzp/ddGgGXuWw4J2Bdz/WASkBfNgZOxldlHWQvdPMRS68zzNP1MGIRbP8e1tI54T8pDG2YvCtB8WZNfmCkofCzB7YSDsWLgTuhK1abFPEpjdaoYA/0zY82AyzDl5A7qXNHCd8Tie1tlPYzZU84y016jtMwt2jRfGvLd7MX6MKchOuIBHg4IouvINPN5UxsveW2KG4WJcJWXBR0yXgOHuAVgCmrDhoDw5Gc0GufIcOpfuDXf1S3CneQHX3hrPOXnXyOrEaSys14Gl5Uv5UmA0+90diR/ebUf3HFOq8euFUGVZfNSqCjP32vJoIUW49uwc7rF/zOmXynlytCLb7hVE059R/P1FHLZNsoJlFYbwU1IPbpwVpTPW52H/qnwojF7CewTzcZV7KnvUJJGf1EVQ+G2LDT3S8GyZOF8RKsKBI49ofMcdHJP6Fb2VDFBhwQm6KlpP8y0lYUSrOiy7uo7WnFnDd4dYfbFHCuklWuFMU0kueKQFsUfasP+xEQvdHAMxM54wn0ae0C2G8nqaKLFwBZ7QbYGG4vO4ZSinl/ioY9PS8TA52oRHR+thy41UmPjtBWtfcKeHsXWUIv6avlRL4oN1X2ixgiT06ZWSZN4/tM1PQtEiBzL3kEfZnyPp8ZNMKOoO4m1+8uApPu3/7f+/1hOK2aJyDdx8m0FjlynA9o3tvPXCQbTrFYKBpW9Ju1qSfR+rQ9hTeXyj/Q0iBBup3Xot9QavxZdv0mFsSSZbXfaF3sh+UnsiAlsFR7Bf4i/8fjyDWoM3wX31ZaD11ol6FNv4bnoQhoy5DpHuQhAceRzsVy7iZvtu7I0qxq9XYiDMlPDO6mE43GoCals+ZFs9AbD26KV8RV8aW4jQdM2OFulLQV5BJRTGzEWfxEG83bIFGr+YgUL4XPq9fQbpJ/fD6ygz/P52P308cQivqB/ieWV+RLL6IPJiONgXZeCuti6oi5pMS4O/8yThrZQzZj3+y22DOW+Qfzjs5wwtQ8gsbsFj50eRasMhuDzxBmeNfMjWEWtxz5V2vHczjm409kJMoTY0ea7D8rwIPPVjHoxb6A475jtS6qgwVnzxBSfc+0grOxVg42lj6HW2RblXn3nz3SDouNWIp+YZkWjGaNAKeIZHWxaS5r0OFpOQh3ltLZz/3yf2b5biF80p4Ml15HGmmxrz9/Ftx/s0Y8tYjH4zDt4Wa4FFhg8q/lgIl1LXYdjiYFze6YDziw9CX8Bk9IuaikpzFaF0jAnfchqN1THLcKZPFNjod8Gegfu446YBLdIJYTEbc/SvFALhV/dpoYcFNK6ug4rqfWCq/Zmm7PQAq83RNMLbH271CpOLijD8UhCCxA8d9P12FM6/VsvZEcmsFfsA3sqU8ecDR2CZ9DJ49cMQrlRrUbX8UfJ+Jor3g334c0Y82Ato45dlCXBlTA2s393Pnw0Ium9mg5X4e0gZF8DeESvgpoMRB6zeje+TtuCKDdeIUk/DB2NJmBscQhnj6ujXTVN+efQgNTobs/vsszDYm0jRoE8VaxbwZxgLks1P+Kd0B00cuYO/5QiBipMe509Q4f5sZTq1o5w0I1bBwXejQG1rLL5e546XW/toZo8u2pVs5y35PeyuNrTXkpM552Yp5Zmrw1zPUljZ6c6+CZFcsTeBKmpHslvDNxDtLcc3uvf5n/pWGp2jBW65jTyztANDx5WDjXUJlhr/ZbtT//Ct+UXaaR6Dvski9NgE4cMJBzazVeU4VS3UX1JCO6Jnsdb8Iqr1F6SrJyzg7s7f6FRiCmZZbijt/45eLxkNjvZFeMp9OJtaqFK5zmxynBTFTh+zwTHOEA6+XgRWs5pZ+5E7mYcfYdmKi5So95jzrV7RL+Wr4OWWT84aGjDz4Fg2H2dJZX3T4POH+aB6ShIm7HiBJ3+lQIXvXLhjNQb/jpEAGf11MOxSG0+/cR+7P0TANxJFk4dpMFAqj7NGvKSTJ8w5+6QZnDpdTfsjXYllS7jhixu9SP5GO922QImCMQvVKrBXmhAmj5wKSm4rsOxrP4RlBrB+iD2cnfIODJ8awdKkC9w6XAErNk5EuwxtWGMgQSmbs0lZvwm+aAzNriQG4/IF+O75bpQttwG3g6oUGE8weuRjKnkYiBYy8qC3IZFj0/1gQ+5DMro7GbdKemF4YTDXbFeDuXbz2G2TD9wOqALvfWrkvKuaL+YswclqD/iTWxBJXYsGo15TuDXmLH0TiuQ7F+/SXHUr9tA2pcqjL8Co7jEH5Y6A7tgGKpg3DeZvvc7ix7Jwo/FyfnojBJV/pOCKgz955LrdeOLcS/jS5M8jKoVBJ3KAnkjcxdetOviqcxv5fZYho4VS9Creh14+0uV/ge789ZQ5VKn8pvUiNZjxaBbfejOGZHeYck3wYyx58od2n22n0oIWWlIhDjnOJaDfPEhHL/rAlacSPE/lF23b+4DcftxFr+xIOt31lG+OFQW70oekmqABMpah1PdUmv58jYNnucpwUqqR6JkBaSzbB26VCrAhcSH8816GrdHDYW/vIKySNcXLZvlYK1yFmnoT0Uz4MMq3DocXLEZqAnmULnEHZl4PoWSHdC4aXkpyg5/py08ZHjuUiT90xUHXdjTMUbIgv/YLvD71ARoLG+HEgGv02zyDE1vy6cGGR1TcbwjRd3+TeKkbPV0kwhZ24fBnkysvPRIChkcBXxY/g5GjEnH4zCmgUu4CYTGvIFY6nk1nl4C26mPIEykFKQM/HGszEpbrzmTNHTLgXr4PXT3Pwo36erZ6tQD8reVoo5UOPJ9xkO96ZWNG9V4c7SMKb5rdKUV/GGeYvaSx/WPQxSebBReJ4BozFbK+dRvXnHqHA6lTwdsf2Tz/K9uM0eCncybB+fQXdDz9N7vP8IJ+KYCbankweos5jPoRAx3/3aLytxU0pl8P4eZBSnKWp9kjJsLcPetZul0HdkarQd/2DNro9IRnSyjR0kNvsKlSEvLDxang+AmwWbgVo3dvJTWUha3HS6Cxvpmv+hF8cXUCOUNB7l01iml3GhRE/aT1VsVYCYIgWlSLfotPkttQXjVWXYaGt5osdN6EfcbX4B7rQc4Pr0aZZaNgvLE89PFEmHBKZMh3HUjG8yNabHUCLb+3uLItCZ8c+4jW2QIwtcCbp6nsJpvjEdgQ+YRXClbg33EOnCWiypMmnSHHoZ6akmEAf8++QyfpHpyz5xnEKS/jEzUHuV54HZz8NRccTzwiyWZx/LRSF3QFR9GsoEN4WWkdzX8XQ9lRY9jhVykoWq6C5iVPyO31cB5ZqQ/XA+Jo7aLxKGDiDDOMPuDlh7dhT7sIyuQN52v7WvDE0hYa90cW3qdL8yTFWyQpvRtEjFXIp9aYtlyYDHEJd2hkQwZXzhChiI0Mi9ymwcuVtWgQEUjtxcNpjcdrnPpyEsqIiPDT3Sm4V/UFiqhOhRrdM6AQPUDuCxxALT0H12XkwabDh/npo+HwaZIV9UkJ8qfKUTDFP5+Lxxag1oqtbDXmD2sJ7sGoFUrgfOwlpWuPJffmHO59PQG+x/7BiFHbySd3HetuawDF+DuctPk224xcgAc+K/Pm+r009ZI62C80R4eq5XzWfx3K3pImm79PaU3fSyzUuca+rs4Q2PmXvP9NA8erFqy/OwwNhk+Bf62ZuO3yGFx44BZ9KrTFG/bBnPDpIBVrApTMr0O5XE0KHzeZqFaF5tpbcsKBhaQo70GjF0wF/xk3qcrNHO6+7OPCCQakvHI1HQw4RlWe3az4xJbCnWpoc95zyDN4SvlPNSDt/F+qUB1y16MO3Fhzg0avdIIr835CosV0DB02CT9O/sQnjg1dl5dGMn07eeBXPZbnpqDypH9wgZqB9daR6OhwyuwpwVViZhCiuh0zl9+nkqnXIOzqN7gX9IWjm9NA/3IhfN0nxbVxKvjFieHrtmb2FZkByUOsdSBskF6Y6EC/5Dve5nkRtz4NZw/lS2BpbQpTLBLY9c9V6Jk4GjY4fwCPKzNZes4gWFbo0JyTYZhn0Yf/DR8NQrWdIDDahY7fGQ8g94eCDmmTnZsie+Vb8vjBWo6TOIqnN06E1DvXKCh0Dceu34eLk+zpyWF1cni0CaO67rDYPHtQk3Qg42RBOFH0ln+vWY/yjyUwr24ReMuO49lOmvAsKZ+97h/iAM1TcPLkCDAK/wM7XohTfFoZiCaUE005DQZdFXBiXB55n3Pg/lxFSto7Hg76f6XVBl/A6Oc7NH/cies6LVFQIJkrhPZxxe8XXJ/qQblu4+DJ2uf8Kj8dxCy+w3DrH2Q9LAtum3SCVZgiWK22Ic9oYXbq04e7ntn4cf0bCFpUQlaXi9ne2hMHR8jSc8dZ9L6mmkcfOQMHhk2CAbN5nH4wmgaCEinbvYvfCt2kn3eboDL4JNyoycZDoeHcmykJY4MrqXX9XpA8E8oOEQPQ8nE7fAt7Tmuzv9DHkwb8OdKSwlWnwPVzWlCx9zdIxhmxl70iuYup8K78U9ARIIbxB9ogz9QW2nwkIajZhRqaWrBI6Cxf8ZQn0WfjINB1NdtMOENjfrrQSIU/0EG68L3Ig/co1HNqZRXGfQ6lv45HaNzhH7yhbxeNjFqLz1YNh4t3BcGxZwtpLzeGHuV4qrN4xxlPZoD8Szvgna/59UJd8Km2IIk9I2HO7tf0QGUWLQIn7ti2mQU+/gOTEjmYF7AU8mfmsL3mFfjiIwwbC4JJIn+IF9Yug5W2lyh7nxp+2xb1v3f7IHFhNeREXyR+oQ86TVZEFbm4OmgiWoYtBPmI47B1Rzje2TYHJu+exrJ6O+j07FFQWhCMazWu0+8Z0/BjxgDvHfmF1nbZw0oTcf4dasO6MldhZbc8fBaIwh5ciBuTZdBSbgUv+HkaxooOMk3dz2H/TqGwqi19lZeE1iNncVpEAoRrVZLI8Wto1XQP1rWexvdiUTx98inc37WJL0xXg/szamDs5wKMu/kD6xOIPmX/o8+5tegwMIwCw+/hqzdv4UHfCHCMtIfJ9+Io6NpBSCrNYdcPfrzsfgAfm7MFU8MtYMe0u6RfOxP2Lwmi562vYGb7N3CcFEhSQv74xew6jF9UBJHLRahd5C3v1jSGh1DMxYf6wUB0JB38YoAWYfYsfSUOXqwV41vPkkGu3pWrtYVA5kkoT7fUpLzELsyMUqR33UlkL1LLb95EY8iZjVh57RAn2QyDosgCNNY8ThlPu2ncp1M028WHfo1fhEqkApGBjjRZNJsE7IUh9sdWnqh4G6atcafnYyXYYnA7du69CH3ZVeRo0E7ehQvIeoQurM+/DX+/Ds1ssyW+SojDxeec0NwoHn2c/1KfVhZPE/qEc60lYWD3cpA48QwzVGazjXYdTDs6jLr/uGL183M0+4szzdxby05rRSFFRAkUru6AibOZtEOl+ZKfO11w9OM51xuguEkRTQsN0SHHCHJdEslG8wbM0faixZMeU/A6Dw68uB8WGQrh7pTDbD1tBKXHaMB/h3Rpl7MaaZpepdIiXTy8fAmc/W8WjnO6ia75rjRSSxd2ThgBbn7WNP9NGu3bYoau52/CHo1a/uXwitaeuQVtbsEsV5jNQmZ6kOswCCrJAfxrpzCEzT2M3Wf1uLFgLE1dfRAnpB9AA/H3+FZGGU4MtsDyy9dwkh9x3w9zMgy4wgOJDlS04x2GLQpGrZOvUfGyDPAqF/oy8zs8XL8Ar34SB5+iZRSVX06+bcak0JKNM67F8d5MHZjtVEGnv6Viz3hzmugYx/9JB6H96SgKOuaP88xCeZTfAoiWQXi86jVbK8/DgRNBOCVQCxbzBojKfwbWSmZs5llIu6T8uMdMFur/fsa7pcV4W8EBr2l6kO6SaexgG0nxeleh6uF+ELi/hfiiDCwVJAravpP+ODph85fx9NHZGd1H/+TqtCwO26yKEd8MIaNRGnbE5MEsjdskKupBMfVP8LpWO0h4DrHy0hLuFu9AMQdXuGBMsHKrJGiF/MHGkabsMi8Wg8Z8pZTfjhBmJcIfJHz590dP2h6lC7JXwuC/V+Ecr22Gx2528Oyzb8jkwmqY/zR5aK8q4zpBcawwk4actCN4KUGIrX+lcrLQeKwPFoZDysGg8D0UPpU1QHj7E5yXqQJ9+mIQHhdB27550gaPQHqpYoDFTq+o/dAZHmU6CeTmNdOy32awfGEme+xq5nUvQnkwWZ9EhLJYNEqNq3/so+UXYqDiRizIaxiD3O9XEO5kRYvq+ll9Uyf7Rh6l32XPSHhgJscKreU5pX9521p5sPJxZKHuTH71KYf1twiwIx/Ax5+n0pE98vgxfz7Pun+B1lYBxDZd5cWOc9HA+xsa3i0G09vV5BTxgf7tMQS9xalwNMURb9ebgoytNuo5T4Ny10psH9/PgZ6TaUJOCRzBFby75DeevD3AO7VFQP7+Myz+Z0X/0hp4WOgDuL3rPn3N1ILrduZw31gFxM3rqWKqONQkZYIqHOCWwwd4vL4Nqjn30PT9p1hNu5cG47/R5t8Tob9cFsKNHWCDrwrOLCqB+WVt8LPBgDfticcxt0WhTlILv8iU4OocOdj3yxLCEn+yQMBeelV4ixbXtsDBw8V0+q4Baw8fQca6fbisAmDichNaYrWIP/VJc6v9BZwk+YHK/zPDE7430PRfFyY1FtHbqgmwssSU8jedYoklS8Ai+BuHvNzElwfOor6GEfuuvkzztQ+BwFgVaOhcxV/tYihorShfyPXE1tKZXLEjjsb39KDc0ZEsvyIfBWaIQn/UX/7uqYRL66fBruFnIfT6YdBftwRv/fcG3q8ypvefalHPbRKkz3YjWfE6DHEI50hlLW6IugKZ76JZYlIPW60NBr/fWaB+aSJoqFbAzngpmn7jND2xz0eLxGF8d5UkSVpfhi2Z3bA/SgtnNTJ8EDfjRafu8tEzPnzD6DvNqD+AjcMOo+rDCVBd2sbWV/7jkncTwHSwCcXsM+jIkn8w96EPzrwkw3G1/7BD+xQLbvHmiA2p5GEyFtJr1mPuk13cnHoYSiI+wde44SS5dzsdNdqCW52jMETSAQ3tRWFryi/eMg4gPdsadmvO47e1WzDJcBMn9K3lwJqLqK+VxpHSRiB/fRcO9t3FVFVtnjYil5ufZ0DtrQEIc2nm24cO80Y/PTSPV4WO3oW8VegoJR8aRcuOFPKku92oPeYYhx+TRbshXzk2MwGXHFcGdbvXdDSohfx/3IS7733hhl0auI8OpoeLXrPU9xwUPb8czENkYP/Os2iV/QDXPnyNkooZ+NROk+t1Lbnrehfi9if4xT8WpiXowLyXaljp7Avu9et56yMBNHUtwqj9Yzl8uxp/2f2DD9s9gWsHtKHj+2Eee7yBNhel4t7qTm7mKNh37CfkyOZgWswZLskzJQVhMfDesJBN7ZT5i8KQa0Sq8XiHKF7f+YJXrJai4B3i6CfexA+0RGCWxxUwf3Cd9ctm0tG1dfhOLRAPXOmiBo8alh6hSAlPczFhlTQMPAui80qeeC95Cx8ZXYdmrv58fGM0FH/p5P+s15LwrpM48o8ylLdks0ybJcVUzIKWc4+x+NkmTFG9hJ/W/6K4PHF+/voUj/mmAI/XO8EGBry0YD9KJtVgnKMvxcqVQtY+ZTqp/QS7wk7S509TYLiNIsZPUaH9Qefwg9Mq/LEjFxQWGFCN5Be2NfDFkqWRvHmsHLx53wVwrhZKx4RSXH0U+msmkqe3DYasqMW9J8Mh6qAKRRsOB+M/TqjzYhY7yyej3XsLTvshwXP/U6dsUVWMdbkPL69U4WcjOfB/dwNrVW9BVfoJSMn9SBsTV6JUtSqkVbtyjepdSrScwyNkpKDtWjQlqHVS05IARJ0h1OuuhbN9f9hgNEJd7QMU2vqR0swk4KNjI2fl1WNwmBA6vJCBmx4vSXmCLguEboD03AweHVKP0kn68OXRCahK8YHrVt78rnM+lZ17ilJL5vIJkXBcHfKKK73KqEfNEB4GL8Th+xJY70QhHwjSxsSPYviz6fgQ7wrSib58EOlqYKfD06HZ0wlDbieQxakk0FxRjwff5NCZY/tQx8Ic/rOvg6fqs+HEdnVYtkuHzqfa0RSblfQRduCpcab8qjuf9VtNYO+dTZS914JVD4rB5twQejpUxAp3WrCqXRVSZRm9quK5cM0ceP3zGS1Q2sDbT8yAkO/PqSD+CKRbH6NX89owwkyGUw/PYUy8QmZZf2D8GVn23z4B1l79RY2P3uKI+jVkGHKEeu8c4cjDFfjVxYhWzyrFf/WnKeOAGBxSOoEj3Wvo4JgiPJvhDoKNq9jKejH/dH5LNXPcuVwliEe/VYZCqWtU/FyRNM4thP0HjnOltDE0Tx8JHcGbMWlhJ5y5psarx8vD6Sl69PN4FehluuDK9P844o8fz/o35BRPJ1CDtCAkbPTAypvTwapNByX7ROH8fDV+nlEPKt0PwNDmIknPHU8nNFzBfFYBvpWQhy6pa5iSNhoLInsxu6eA1tMgP5jYzRHxYtQZ0gJpPfm0s0IeVKSr4Hz9MsrFcbxwtj1JnFwGSo1T2C1yE2r7HICvsgDBuiPhrdBG8utdg1ed9UAoPYxrX+yga7Ny4HWKO3369QycUqMp5PcQ26knk/usrXha1hmLTOIx2fEQ92sWEm0PoANNfRBu2QcyflLw8lk1W6TYgNTqh9Sh0E5Www/DySHfnjnXHc+0R2Pja3d2HXrucQJRfG7pR9KyqIa8oo9wI20RryqxxtbG+RQgGMVXL3zGpaIjYcZwd/DdLQzHjP5yqcBk9lpVQYZqWXheooDmZHrwMMnZsHSFCcRvk+XSEeXcaKtH4w+N49Sxz2lU8h4ymT0IY3d6U+VUE7gQIAb/zT5DAkXPwVRpGpRIiMH8O6Pw4a8KHhPohYnr3qHLLiO+vlcb3qm0ws3iOPx6eCSVdGTiC8X7eP/iKgwtPsvPaqqx4Por3DRVENQ7P2GS6wW0VfyJOQoH+IBxPj4Ylo75j1Nwq4YdrVK5huFWI6A1IBCE9yeg16UAOBWfyxE56eS10JFrlS+Ra3YhBCk8JC3n0fCxzghkZF4gPH1Mt2A+/tq9gr6ffkMr3aXIJNYYN3e8odNnjcB8MAJlL06jxBYxaDZ8jA/CEjC1dCGtF9zLdxKSIDtIGCbbqEB1syMn2zhwl4YuKQk6w+eQ1Rxzc4hNdtjxk7F5uDp4DtT9NoGmiU8h568VZdp9pTNWC7gttw307sfhvYZLGFl6nqZfVCD5c0pgN1+HLKMc0Le2n1RjLbBkngGsrO/kz9PH8R9rR/QJeU5t8xgWrc7BnYs1WC4EkAMLQOZPB+/tHwY6kzfxNLqA2xSdId96GGwO3YrhNdaw8VovVrx0oIO/5FhaLJ8C/kuimw63ye2nFNzunw4il5RRvPkY51UcAYWLpVgvqgvXlW/R0rR7OCqiDr8nFgx1uyAIjGun5UtT4b+q6Vjjshgajh8EeQMHXrP3OS5xboApURYsOWkCLNrdRdghSNV/HsL74qMg/CUIX30eBn+XnALLzYGYtv0FhxZOhwtly+HlN2ve8l2VFYUvkfPzHE4u1sPaVHmUMpCh7AFnGmMnAcvX7WfVTYF07lgsvBw6Vxav1dHWfzN/LVxO+QW11LNLgT0KJ0Kvzn0+qTydVfYdwi53X+of7Q2Fo/Pgnuw07ju8grS+b6a7jrqwymcePQ9djV3FtnALJ+O0tevh/BItMjpdADd7q3D2mhpM9R0Hb2cJ8em8w2xss5bfZzXDHVKmXc8f8I9vY7Gn/Ta/PCTPZ8rlQLDJDRdnZ+L0H754bWY9CbXWQV5tGOSqI30en0LiJokg+VcVwpI9yH99CT7AEryuK8v6PcM4t9ACY8e/pX7RXt666j57PxCA3RfH8/IZ88BGSQw2nHsFF7Qfk21MMMo97YDBI2tBJy8LsgpmAgTZ0vKaWej1Lhd0c3Xwqag/5n2/DN3Sc8Bgy1G+PhCLjyZJwSjjBLjWrEcNJg5wyGATzCyPYJVKHWwdng13ch5hiN4o4FdTwFDPEjl9H3Q8mMdvhs0gTZWLaLoln07OfE8rBtJ5nk4whShowebVHvBU9yUnBgXw38Uv2GzRTnpaPjSL9ruQPDMEfa9UwwcHMfBVn8Ff4pyZdB6hQmQaeKmKsur8PFDpd+Mxux/iXAkbEOg0hVe/juEOy9/871UWuv3vOxP7IyD+mhl/Wt+GMoePQU/6bYp4PgNaVuZz0FtjGlOUj6GVRiC0LRkdlDLp7UZNOEOd+KH5A7h9NQdv0cf8ZOcDSBSsIYufcvQmFuCPxx6MvneAghyHU53BPdBdLgD+L9bT3S/FtOdmGl9Nk0DJCRfowhUtcFGby1JO/2Hs6v3sVykKZqOaQcdTCL63Z5H/DhWQ/3WQTRZtxdf5H6E/lzm3aS36a6vBsS/zKFB0FK/SFefygzU8+6oKz/paCosPT2bfCT+4vD6TUodPB3WXfeCSbEhWArLYeOQ3pMQaU/ILHeRBojPrb5NuRT16TB0Ln5PW8MbjGliSeReD7xuAQmsUiT7sZY9AY9Lc9hpHjKpkSZExsFFnD1t721GyeRKe01/Agc6VtMtqD+tOkqAFgx0QExMKjrMEIDnaAz87jgQH+ohGxROhLWEF+51Q4tw5HyA9chVJtE8Ck1gdaN5TzAq746F+6Q8+oL6f0802os36LeDRlsge1wshU1qFE9uHQcEEdyqpWEHOMcvZfqERRr0+DFuW/mRf4b2osX83J7jf5/WVpvDVuoffqYbw4R5bbtiiCWY9w6HFlXif6HluWZTOX4ODYM0XVWjQLOPslp9g5z8LnigEoMc/Qb4gv5cFA4bR+tVa8O5RJN4enARxG99hulcopA2Y8P3iFOzat5Pl/ubi6wkx2DV6OFZkNlFLrAHoGr8m22UhJLHEChdE+rGA1TsQVniEN/ZdJNXLW+m0TgHdeToKfCxq+cyIPhoVNp275RYPMeo9XrReEo4Ou8cDHRdh4Ng13Nk6HCK63/Pqa2n4VKAAm242IeXtx6rkFbRyfBEJ6weRxv6VsFTEEK677kWx1qNUvnsqay9JghqbUyS7RJGnpBRiQxSi1c6XNDWEwEH2Il6qnwjpp4RQN9EZloZu5rGnj+CsLw7oKnaNikrHk8656ZBcqIvqLldp9fhY9JbV5ODDc+iUcTN0jjOBil5FLOs4jg/+ScGMKHWOlx4Nl6gewjKEsPfPAErdUgE/g8mgeasI7uu1wm8dAtuQcPIStCRLm2Egpr8KG0IK+Nzl45h7s46KdknR8gtlsMFdDl5sYjx2uIyXSNtQeEYlZly/CgnJVhjkuBHXzNvGa5JP4qGTRvAtdzjH+c4DM82PoFvahXv6zPncjnh+fscGLSpPsebmxThVUwcM3kth+MFmbonrJ/tnKizxrhembkhksfNyfGbWZ16zbQM4dahBxDVNLMuSgn0d+9Ay6C7oa5zFgEA9qmh8QLoBVyBi1iMQTheCgp0xmJNcRVmNI7Bs8ihQ/V4JkmrpVOj2ic7p/CYzlQdQepXh6T5/ung5CwvLZqHbECf+iCnG0kd+oKydSBum5dL7X1qsHjgJdtsWcFelEKwXPwp+TTdprdg0evLqA+y46cddO7N422k3fGurAi6Fway5zQh3132lPcZibP3XCx63xECb6yaY/cyOA5+egMUWxnDbIxki5Z1ZNWMqP4p7iVE/iFYYqcKayAUQOKMRUCIFzTVUQepPPdZtPgVnvAw44rk+Pv+ziNrNxHHDYgvEf7LwYfpiFArWAo+5rtiTcIpsbwzw1Qlr+KJvBO4NXw3v+3x5+6LZkOA9Cgd1TGH0+E1s5Yr8zkYe0+PrmL7rweyrqhTkfJeM7Z/RjuI1OOitCav8p6N5iw5EfjwAp29sg4iv22nToV08MPkHhnY04PFbVjylUwcyXnrxYpmfoPjEGL7ZTsJtJwDVlguhWXw3HQnqRackHdL9PQKKO20wUyEHN8k+Q4EZTrD4TwhfuHOKhVKkcE2CFEZU5MAbFoKXU2Ow8Z06KRc5UPT0NXA5tZnVZGvhyesGKBtiqEOd/VCxWwM+DoF05NxqPPrCD8ozVpPtlKvkfGI8fJydjyqO/7H31iJqzJgObQMfuC7kJemeMsHU/hWw8KUMqxkYY+ObVxhro0RBMb7UISwAkjsVqelUDwfsiMF/B+Px6pVYSLb4BPMcn1Cl43P80C0JZ18iREW208bDC3lElROZyrTAZ59g3Ff5mLDtD/q834he/q0o/cIQ/v1Lw7at0virNYH/6gRzV6oH5F1bC/7VXdRkHsgGFyoo/bACFByUwFfS6/iUpS7HlEZhkWIUNCV74TRpZRIayoLdTiNhVtkY8HKYQOfejaJxlUXUO7aGd6o74MrCPTD22D/o1L5KN2ffA3V9WWhqPkWKky7xwkkduMvuOF9zXkpCpuvx39suai4XB/X5N0h810R4vn89nR/K19MuZ6DMJYzi7NzpiIMOZbve4XWaleixQp2EFJVg4/UOen1yNBq3VLDgu/2Q8FSEs1erQsehGVgSXk4dQnHQNEoOpHc4EAUY0KQNl2lqZzJ5mCni+r1aOEpyDm5w24gNz0/C3+vjIPWeNvi4WGJalh8usXfgCs+r+EvNHRzFH5FsXDm3Vp/E4mgp6C6M5W97f9GW+Rq4UngNH02UoI/v3rPlmI+gXqtKM/EApcmZQKzTGlIZn4Sj/7bg0/Nzce39KWRy1Yd7HuzFyW73cW2jFJi8mw5lh4Ycde0o+tLvz5N866D6/iUYPtkcStcZwYZZm6B9+XPcgLqgzNMpdPMAFumEQJH5U/I9V4sGm4M5IGAD/auIxy01vSi+yhDs3yry2tu2rPfNEOv9Z+N/Y7PwJt3CkrI6su06huNvTKNdkwEGwyJAZns16/7dT/86XDhwTDhLnXJjxT4/XhDcSqvE0vHXIkkoq6rmbX++837PMJKUvIJ3DZ+BUOwo7MvNgVmmXpDyQAdqnWaAk1wJfo6OphNJs3jjmCQ82tFG3kEnyaZ6B63qrKPi1dYcoy0BW+TfgGHKZJw/fTe/nn+LJugOzXBaLYWL2EJs5h5IKjjCy78awMwyP6q28aOoC6NgyssSWm5SRumNVVx+5TXOibGA5uYSmN5tAsbaBng8fzg39vaQq8c3uCXnTDU8AvWGB2DwnsU4hfVwylglEJ6Tw64Bc+iaQzuPf2cOwSrH0cV5HPwt0MBZsa3cUmpJNfuGwSi5D6j+WGkon5OJ/P+izU4F8v3lix5GYZT1+AEkGI2EQ9LmcCn8IIi42EOF3gd8W7YNXUuKOK35Et3NvwhBnVLYpLl2iBVVIM3GnSoOtsCS9/vwx7ORdO+mMIyRe47L+0+DqmU5NC5UYWdlQfjir0lmskq0TnU76HbswvINZZBR2Qo60Wp8McKFJa0O4LSmSfDeOx9lu86hfOAb2nNYCp6YIug9OgPHLuTj3sYtaF7VzgrLzWF6TCcs2r6b+nEdc7oJvypeho2Clvja7xTaNkyiuT4r0M5AHL7Zd0L3+wmk/PoH5LSk8X5NW/bkzSSwcg/lxwNMlVDDbav1oWaFJJ9z+UIHbMJw2S1B+hF9EMQ99uLw450M8/ZzSdJVTJmiAP+uH6f+/Crw1MiBXdau8HPAjS4ucKA992Jhz0gjbhZfS8I7tcC/NAbUjitzV3snv1Kbgi6rfLDJ7iT2mrhy89NAblk6hjOG8uBb3G5q8o5lseNRmLh0K/4JWM1pE21Quz8IhM+ehbT22SDgLQGG9iMprnArZjocBDOjLrZ4Z8dXTuuzlfUA/ty+HJsmLuYTHsaw13Iy5c3yxcnO6bTtbhZmu7+nj8XLQOxkH72e8wKr1pqwZTWAjd9NjLWUoq5wS5BvzmDPHZO5+WQEHx/tBW+Pl2LNT0dITRGHIwKV9E7QmGxyXmNBUh7k/i2EyIQPQNcmoURBFL/eUQf1aRow7dsUVtD5BmEHCnnaywC8NSYJlJo+w0Gtg1RqGAtVw7ei/k4TuCg1gKPUTkF3mxkEt/wZcoVqcNCsgmXH66h5wjP++9KbPGyHQ0qwBSkq3QEv3Sv0YIMTbV79Aa4sOwzzR82go0aL0TDuMRb9GA8Leq15cNEm/LBgBOiUevHIE6msaHiGpoW3o2BDOdnklfHsYDFo3q+BdgGi+MIlAC6JDFLJzyy+03YW/L8eIOGv96D0Sj59PaoPtzLv84d5ibzPwg1dK1bzs+yjuOjsCnrheJjvz8ji+JIeDP2mBpI1PtST4oHWE8wgKHUiZWer0o8kORjyPbBszqXinKvYlSUK82z76LHNRZxT50dKwwbga8hZCvLz5c02DWg28gWWOn8DrpwKU/uOsJ9mFta/EaAT6ZNx4zEZeGMdhVo73FCkIpuDP9uBKinBmxONbDtcgxSL12FShy3vcpLH41WXcI6tHeyUGsr33B+geVQZQp+vYb1jJSQ+OEAPZ6cyCwAn+2rRgczF3CU0iVS/+2K0HcKpjX1w2no0bD3hguN2bOJznW1gNaKXFc7WwKGfH6n18UP2naoJU2+0QunWwCGGms32V36Ds8QFuN9dxc91Hej22WvgUeaAp56LQcVyZyxb0IGClVso9WsR7l5RSHrHdtEwtSy0DU3iWy+mcfsRMzikfI1CtFxIaXktLtHvYslpuhz76Shay2tzxbAGcjXXJ8vRUyDgkyHuNTsPG+aJgMQCT74jrkWdqrcBHURgpn8XrosLJJmfgrD4xWW6UnYbB+3SMCTNmYdV/aD9e2zYzP0SJ6ee5tTlnnjFVQHWdtxiwz0XeZS7OG7fUcUaZudgUe1VuPB6EnoqKmHJjMeQsVIa1to8hXRoR6XnD8lB5hfVZ//gqM/+fDbZjbJ03fmO4n4yGFAHv+PzOG6uNmffnkplsid4xlwbmiFSQ1X7DoF2oy9b020OkRKFn5bRXHVtHpbWT4PfswS4QFCfhbwVaaKXL+yZYsKzpmpAhcgMSFwYjtqRcnCi3ZDXTnHngKx8wIg4ODOxiv60haPpk/sYPEwaPL1zaenjMo5fbobH++TpQc8GPjzkslZj1GHT83J4+Zv4rYQyWFQrcdOLcejUe4KDLm+gOK06rI9OYh32xu1XdNHynD/l79OG/F3nOar4NLx6ro6ap+dQcLY5H7pjTy0OGTy1bCHFvl5P4bs1YcKZSHq+VpTrNu+EF4s8oX2WHf/onolZIsdI+tZrlFqajM4m4rAgWxo1H1tgk4kLMHqwXXcLRk/N54O2trhnpjgbLi+k4zMEQOL6EOMqv4DLkV9Rye8Iysmc5QSJddx1oBkl5HZj3+zr0Ow2FTybr+NTXzW6OFgG3VVV0D6/gf9DtaG1i8dz1wU4aUQ3SioIgYmrBZT2DWNdA1Oa3Z4J++J/ovC8RlqaJcGHXgqg1P48nj1LAYY3e8O3nya06cBUPPQwEA6W9/DMXEkc6z0bpldFY6FlE77xVILLc0J5pOFIknnRDqa52tyknk4Xu3p46/q7OH7cMHZXGMEfFEThvogsbr8Rgy8nH0EFWoPj27J51YWhsyhaBv5xA3DDVgqwyRQaymIg/lAVXbb1ou4UfTDMcsLAmRlsHlwG/9UHQmdyG6UcmQROSQP8c64pdRoH0bOcSgh11MPXMScoTzILfYR/sM7GJbA3URR6RTNx5djLdCz4I6XrHORRNU1Q8fglHkgqx23ewjB+2xHMuDQe3mbth13Xx+PjZVdgyYQb9C8tFh78dcQsAQ2KEB3GGvN08FK7NmyIN+PtI8Q5JiWRjN71Yk7nC3Swa8RpS7bw1Yc9YLi1kcODhUG2ZiTaqV0AJ4EH6Gy8AJQvBbLvZU1aJTuc7E8fRsMgcahL1IZda57Tou21KDqulXQfvMTjH6T4VVcgajUwat0lKF8ehmIHp8CyydL83uEyLju2D5PvXYfEw5M5zOYKztyph/GqtrBlxzf6k6QDwqM2smB4PX2abEJXHYBbby1DFfWTVClpBWeOIuTOXkBJP8eCjtkyDrDax1ObSviBeygoX4jn31G9cNw0Bd/vKYbQf7s4sg1ghATy9cmafPvSWfAOT+cpzgtBMtSV172egLVtfRy5YxyvqNOHS+mM58OWU+xKAw5fvoTl8gchaX0Sj/M+yuLz3NBuexZeEFSFZdCGR9wrYdmECH4zaSp8fhsJ09wWUlR0In3fnModJ93412IhCJhYhD6PPsIiGGSrNTuxfk09FP2tpH4bB9CcKovOaQmsMH4cvBm6bxVrAZDbshUenZOGjAP+sLTwA3c83IQP5odx1qoMnq4+FlaNJzqvGkRpYbGcveMTJ/YZwnCla2y3VRSmGEnBnCmxfLRfERy7b+OxF7s5Ue8Kh+z8w3EzfSAkyxRafGfAyaXjwMvsL3ZulgTFwYX0dm42rBO9TQ+iLNFn4zlcPW4Uef17ga0HZ+BFvW3YttkAvGK86FG0DC+o2QHs+pBe1wnjqYB4jhhbBp9aL/KytXUUpaUKAxt6aOWauaA+2I2Jgn60+40DS/aFQtrGKTRqwyiy/RYGw3skYPNKD1LdsIONhu3CZU8KSMOyAeTursQB6Vb4FzkWYiYHcmPSDFhfso15nAdYRTSgdt0uDIs/Q1O7vWhBhgQphCvSv1cViEpi4AN13DHwho7FnKLDXU9waXkKu91txFEJgbhmRyNP1Crg1SFqMMauH8Vtuoe8V4QwtpxujnjGGlLLYKC/HqbbvubpSjf5Yro6zBQ7Ae8zmlkzsY7uGc7FW+Xn+U/EMjzqfRb9cyzZY9Fi9C8RB7+hGVgInqGL2Q08LuweHf/dA+FLp9DzzCos7pkDg0V1/CPbCLZOlaHs8qnY+amZDVK6UfvcFFK81gVCSf54ZLcVnZzgzpeXKEBZuBoo286GS9n91POibcj9tnFRex3GhC0j2FTN0subeVbhaDC50IIhf0/w+9ceGGK2irPnxVNX6RyS0OqGVWci8GGLF756RxBsnUiR77XxuO8Cep0hxSt7guh2dzenKlyHk/2ZnPRqLi6bMgleT7xJqpe6scnoMJhHbaF/80Op/ctHWpqyFYxlxWCilwq/sDeFNYKNVJWxC2r/LeB7Tol4wNCFw+UukNrYemwu/0oDHSlwQGocvHL4iRvrTOnJjtu88dFRtLT6Q9d3RQGlNcCWda4QdxSpLVIZzB/YUEq8BYrfS8XLVz6T/zcvyDtmDZ5hEqz8PAQdxt0CEbGJIPqkDEtzQskhPHooa27StD87eMzqd9zi9RRCZ/yC4+JG1HZSBv5bn0W1Gg/pxeJgfl64lOY3OmJxrxV5rJXCq+/dQF1TbqiXRMDNXBg8277TyinB6Kljwv7yPfijdgE9OH8SDnVJQMW6HbhgoghAoyl41bvR9tMGvLOomiTv+KDCAWlecWUTl+c9A3vFNWBnpAi2F9XYd9Ed3DNmA8esugN7Fd9QoNEcsJiZAH7ti8B07gl6Eq8A5m0iaHNGAflRCAisLUK1/ZW4sX8ey3ZXoYOmP808f41i4hC6ohKhaOwVztIk8vAM4mlLgnl6excOeAXQj+IG2K7gRV9KDSHUyZTenb7JR98P8uGLe9hb6AtIeXtxZr8Rzw1bic79LhQXqAZ/Cg3o8HpxupvZhbfyV9Ccnnye/uYPFE0vghkxt8hltSAIvdKEk8qjKEtBAERs7ElFsJPEa7bzGfV+eHpaC1uXjod1v5oxc4o0SMqIcdew8zhGjEDDMAeWXvDh6j8eNFcpBRffkoOHjcUo4T8Czp/2RONVPvQk4Skcqv+Ivf32sF8/hJLjdPjR90O46cwrVMxSAGsxG/i7z45uvr3K230nwjIZS3RYLMhZYnJwyfwpPu+ZRLtOKoDqyHtUaKBHUzXb+VtiI325UAhbe69S2PBCsA8ZRR39cjD4Zwz8Ot/JHtvHoonAXTa+6YJQswRvNzrzttFFOMtdkkUKZuH5D0rwWfMC3vY8jyXb/DAn9TTVbRSnx0IZIKrcBi/rI+EOuMJxyWnwUd6dpul68sKKfFLuV8WYOQNk17sC9K6rwwXzI3BxgzoeWi8Orev00bh3JgeuU+Zu7Xs47sUCPv5wDW9f00apn93h3ElHzvTWhq9Nd0FJbzTfWJKHwhd+ouOHBdSxw4t2qSylB13/+E6KC/2NFwdHmxnccUeFP80DFPX8gI4RI/HGPW9e9C+eJ92U4op992C9oTAU1JphwuYE1BFXgpPRAWA7X49Ea07jfw8O4Hvdh9BhdpwhxxCmKxZgX/kEKuT73BXuitHTk0lT2JqzdZ+RW0UwzwmL4m2SCvDuVgFZND7muY4V/Nl3L+e1EjU+2cmL99egyvlb6DE1AdTVx4Hv46nc//MHdoXa02YZbYr3t6Fhu49hp0sGHb20ArUCJvCRRZpQ6WmLA+Hz6E/UZZJYYQLaI1vx5nwDivQcgRfG2HHY7SPcf1sc7vxbiDbS6eD8Q5jsVyxB8ztGFNH/EZpa5XHe0ylccKSMN1YYg8EuP+g+L4DqGp9wRd040ip9zF2K26hz7CYs++8Srlx5g2uey8JP61fYALroKb8Sdl7K4yXK66HqlgfHzevBuu9SUHTBmN+m6EKbzhmemTkDR70Lpa0GjugVn09Zvwf5S6E6q2Ztp4vwHFYvN4FgLVFaccENtLOq6OVmM/bN7eDujbXk9cySvr8zgjUuS0jstCY0zK6Bno0TuVTGFmMr9sJUu5dU/UuAH70Mg391l7m07yMn2InAuT3HcOScWhBurYU6rYucabAT2r/kcfGnTbBH3Bt0InNI6K8YOLtOhq4la/CqvzHqTk1ir77LINr5BAMC6phcXLArTYvlXUTAxLMPdAdv89i70Rw44SRneBHP+GmKw0YshO+yR/nrehf4ulQDmm4oYn+RB2knPqGCxW9pZnACd/z+93/Enec/kO/fxj/DKqOMkB3ZhYYtSUlDqLS0pDKiJQ0jDRJKAxWVPSopbRWiaCiREWkoSUT4Jqmo3H5/xf30enC9rs95vM7jeB/Xg/PkinuL2GBFHNhum8B8axJc//cE8Ph5PmW2Dg7EnsLs4GCo+3KGrM2AhsVK47Y1+RQ2ZQK4j/LEiHmx9HlqMlSW2oHqxMnwOdKR6+ecJMVDC3lMiDMoFhqDTtF4EFKLxH9qcXAxfxg1xQyHItERdHbHRDrdYkZCX8ZxlocRnI6ZzOmyuvDDIQg07e/SxriNcONPJJUuWwdmaa8x+pgOLV2rDHvsszD65DhouTuXe3c24cb27+gxbi9dTo/GWR4beIeME9qWS4N2ywFOfX4NDw87zbNedHFi03bOnhHJ6T0t+LTjB7us7kELGQlIDLkID72W8rGEWB5cJU9OR47D3PH7wWF0B9besyXNw69IZZwlnJizD497pdAZOxsuUlpIn06LQoNBHK4PrKCP9/w5NKoM6kpGwTnfEEgWHkPnJ6oRXPsG37T3UEv8QjyqlMLJue/4TIowlQsA2LV64zB/Dfi4so/7P7yBR5TOToc14ddaYbL5uoMd74oT+plDVv16WrfdiBZFMgRfvslxR2eyfmM0hYVnQ+LrcNB43IlXDCRBbVM3PNzUA8O+96H8bQ8s2bMOZsJ7jkmtGGLUXM5IvgqS54eDOHTTf8OfY06kASzaLYKBJcr0rmoi/eeaRX7DZpO9rAiP+SoPHuo+5NDQC+F/VpKDiCpYXfCifs0+eGpZQO8H+jgj7TqHjDCG95kl0G6QjHeyNmJnrBtX5CnybZdKtGkbRpd87VH1+R/aG64DSyX+clbCb8xf5A47ZRx5yVFr/Fslg+MwAZUf91Lup3V0sxkhoncpDy/3Yq3ACJKc7sok9h3ejS+jJxvHYdHuTBQTmsUZEjrQnQfg7yxE/ss1wO7HA1Z/a4+XN9/guhXHqD4piqK2dcHdHyJQ07Efog8asqXlXB64KEqGR0eBW7gx51kQn3+hRFdWr6cnK9Th2d4k/tgrg1bpL2jVqDv8YfNOMpr2kn8ejKPSBHUqC1tMwgGTQD81Fz8F11GDWDTFhxjA8e2qvHOuNi1ZnUQGu+txzPQU6BmlBJd3AocpeUOPymvwbuznBVNj0a/YBH6evosH5AJoupELjtlhCbPHLMNzr+aAfqAORJW+xyCJp1Tx2Bbqmr6A876rsDz0HOx2UoHpIl1o5qyGLms7Ubz1M8y4shV6fxuxYl4RTy22h/Uz63B0hjikXWtCtywXqN0tw9HOW/HWn2zau/4Upz2W4vRxzjzjqiO4bzCATCcZWBP/Cporh9apYBKEue3lH6ssUK17A11wykOPqslYrqsN69ous0XUJv6S4wJej3TwedFafqc1B16vzCQXp6lkIFyIn7JGwfdMUbCPk8MwRRdUDhzGyhEncL30fzjqnAcEBvtQeKk21lyyhiMb38PDvzp0+/EWHj4YiFtH7eKq1KMY6h5Eb95W81nvqXB9qE9fPpsDSrKItYPLaPFyb7ry0pjconaz57ZWGB1SzTW+k9moCkC1yYeljRfAlYkx1DInEA6tWoRFHZvxxs5RIPRdkv9lFnLZGV1YKpBEj/IS+XZxDv+R+Euuu2byr41zufaYAgT8/M2T7txHlx0iUHouGtf1/qH+BdsgwFcHLaskSbfKmDe56PCZs3lcttmSi1bpwzEJf/z4gOii2mIMSv7G9asT6aOtG6x6FoMT1CqgvPQg7ujVgHiJN3DZ0ZlzEpbhhCNCJBBaR7ePGrDoMh+2nviAfJqnkU2lLFTJrIFzuz/Bdc99eOrcQUr5ZQ6dD6/zjfwWUPj4jVz117B1kADszDvHsc5J7B00EbfvzcLS9gC89kIf3V6sxT0tobD2aCTLq2jD3S1aZKQxA95v84TayYfYoEqYbP9uwE8nEtBfzI4aqx4iZikDXp6HDTqe0Ji/mUZH5GLnqDra+kCPtK4ks4e5OMYYjuBNQz6UZpACuZfMccXOY7RRPZjvnZDiuNWr6f4BKRymv4KGH/BlFxUR2N3+nd7t2Ie10YYQvf0J39j6mQN0CznONRmcI/og8awTpTVNghGrWrnKNBGfbD1Jk4KjUFFYn9ptP8DZPzvwdfNRrr6IuGCUNmQU2qPrkVQezE3H3lZZvvBvHrqJvKGxNkl8peAvPUhNxd458vCyuJrz+tbz0fQrKJJ9l/bva8aT76fAiO13qK2PwSk/hOrjBcHDdgUkaKeS5VNLWDtlGV/pjeXAxZ0wXHaAfp39g++3L8SIajGYNc+Kjjc2gUtcKus+/ohaIzJwU/x4tlBMJuZm+OXegQLC+vA6PxcnV6mA9UKGb6MkKXH6aq457YILFBbB4xofzD16i/c5WsPPtNHc6L2JPil3QMjibGKRJ7xdxh7e5t/Dpd7W5J8zFhX2SsHIIz40ZdN7GAgZYuDHQaRudBHMSmTxXt8VHExphuR1vuB/ywg2rWmBfPPPcLuqld/8mIEfta+DpbELddr+hOCnc/nS7VbwFNSG44nz4YCxGMpWCXFqZx7GLttNMx7MYM0iITJVruNLqSp4LMgY3LqCKeyVGbQE/6Pl1opYbNqB30ZV46G+I/Bnuzdu752Nyev0IXjfH0j53sUj526BwSRZOqx/nWsculHIWgUcRbeSkP09eBqiBrnBTvhcSJjXnvPCSpGPNOzMFQpQsMMz+33YSqmMR2bq03htIdgtkAGXajLo0w9hlMl4CXMnPOQtXcPoW/JKoE43yvEETFYRhTlJg5z+SAuyJhqC5rHFsNHzHrhIi0Ip7ECnBa84Y24MSy4GKE/LYYG4fTh8pwS9U5DlQpsH2HX6CF369IfeBbXjlxd2uM5ea4iPt/PPyEIQHzEHF0hdhBOzP3FXQALUrh2OTmVGHJRqyJo1JlBV6gzzsQjOWKnx76nbMepmACSY96Hnowj+t6QSYz1n8tIkayj6R9TU0k2rbLfwe1UH3j/EZSf0pmLbsNUUeySQzupo88XVmhC3fhoFZbuxiUM4RNZ8grWvhSguaS/q256F3hMnKGnnSxgnPQrm/R4GJ6/2QGTeQXD9EQcDR3JptYYX3b12jL9rGNKthEPc26UEosOPckbIeGzrWwLBpw5AqoQC7BhrTfYDFng54Tvd7/kIEjWCMC9SDUa4F9GJkAj6FiZCnYEpZCv9AbKuPuSdD05AXGkUJYEcKCo3Y7jITZ5f/QwUSp0xO7QUqsJ60VOkh1Y9CYJ3HuVwxZ3h4P77nFfUiH+KVuDY6q/4X8Q/OnnhO/qvMKd3U1/ht6kjeV2bIUyfKwfeNW8hancoRF325B7n2zjbeStJnRuAET47qfxdFJpHisOES344Nn8QUXsHFJ+T4D0ONijea8USzYFYM0meWicrcv01Swj4kcreO8RB7hujdWMYrg7PAhunE5h3zgsaM8PhcX0FWeuNAPH4DJp59QUaHxzA0X7JpGw7AWX2feH9diI4UasFJ65MhwpSg9vDxoO623340aWJ2w+dRAHtZ7z89XZcr6qN0fm/YGBTAQnYyMOdyMNgq1fOG4sMMF6xkddO8gLz+AWYddOL53dv5d8Jb/j4dYQ9UlE861gUFmfo4Q2NJEo4Wsmyyia8f8oNeFtzgDHWGxp8lUFW4TSNVtpLAmHX4WRPO8y/OhFM3BupJ7yUJQtzaFr3XZy5XAT8vRxI2F8DI6sR7aykYf1yffgyzAWW5/qiz+55JNJkyA1TRsJesiWR3Qsoec0DqP68hk+MOQwCixZAz7+ZdOhDMAesFaOTpxD8D/jh/PNlsPbOF5y/IgWGWYlyYdd4XjF5DGaNt4eHVroQ8l4PnlTYoZVzKvWk34Fly7N4nN5dWL/Ln0+vaqIzP8JRT6mPK4oE4FJtM+vujKINt16hi4wyvz64AdZop1OBjSGE2A3gb4cJNOWjGhi9HACftkncnGmEC67nknZoDEdXSFLT3MV0rlCGpN2fgKubNGjqfyfpnxNos5QXh41w4tQ9Xqim+hsVZljT7gc/QHjpEZT+awrt35dTxEJJPhq1j1XM3rOdTT00K03HBdIHUHbHCRKszYeXtVpwfU4Dtka34pHsQQxJHEGx7a1cWz6Gm70OUFe7CvyRX0mFpiqwZO4kNMkRRJimNdSRTLnGbT4e1DsCY4IDSNpTFN5FWWGimyhsGlwNb4WXwLOqBgoJdMJN3QNgELGN+MkgH9rrAW19xK+ui0DYBj1y9p0L7aqJmFkgxo0Hq9BizQEsMLSggoq1pDg1nfSUJ4Fq3SbKNG7HLoc4tNA+Qwo6ftRz9x/kHhrazyoOfNwingIfmIHzmySoaLGBsrDTsPywF0/sE4YNm015c6wBR02Zh/flmiH1mToMfupD0dl5XPdpKjdltOGvE6WcZ3ABr7cXwE+Pj5zu/JQny0+EY3n9qKFfh/Nyj/P+8kcUsuY7PMzXR8M8oth/D3nfah9eaToeojsWcrjMaI6d8p4+9+Xjh1FTudj1MNwb1kQfHWWh+HI9B7wxgrSVuuB3/CMIpraTay3R2oY4EPs45FlBqhCzQgP8lQ7goXQd+HflNRokhMAvxb3o4fqELeS+0+R+P0oJN0UbV31cMz8ckqcrQPdcB9qzrAls4SpnnH1LJeO8oPXHN/K2TKOb7k/oqK0rrQtXhGIrR5J9fh2+Ro7Ce/3EfzWTadLdPhx3DXB53zwyWrmcflWLQknVErQRD2VNIUf8ErYEitfchGVfNoD0XB1QMdoOAaK/eLycJIS8cmOZN43Y6llHFpo36HDcPc6zDuTKBdU49WAxDLPX4d3PCEInnWABlzGcNdIPz74y51931bCoyReDVNuhf2EjTVQrpYMPRoKFZD5s7jBGu+VzOXBZKhgM7+QpZnu4+HA/n97eCDqrJ0HRQjVo+WJJpYp3OVVKikPyq/jQzxJ6fOon32+ow/2aQrD9uhy1LB8NK9ek8bhdc4b691C+6D6n5Nvr2FE/grb8zuHRr6+xmfcPVBG2ACm3CmifIYSnHII4obOTHAqVOE1UGe5EZGDwtLPgmV4IX0MVIKRxHzYI/KXsj9m4VWE5BDUWoMSdC2gAstCk9I2affxgtq01iHhf55WyYZCmZcD3Fm/FXStH8Jigq3BUbiuGSsVA9ox9OPd/5yzeUgYJT00W3X8IMva10PyQT6z8wQKXHS8Cp6WV9GTqAfBXF4CN8YO0s2sWd1SsRudJy0EzajlZ+zfS4gpTvLCXAR+bslrZCJDeHwSdXe2smdFFX1Yd4oK9rlxQgJyd7Mbel+V4+ZpYauxShPvqE4d084Vi85M4O2ImJ6ed4rdOx2nZiRqmX2VQnV6B06IM4XzmQjLPMOHb+1Rp2s8nMOaGIaUFlXB/mzL9mT6ar6l00LZN4mDxvJZyY9/jPhDkee3qZPhVGzY8rQPhRQU0w3c+PhUdBnICY6F3NOO7ZAs4tSCD191RprqyRnD0FYKm+o2Qr/uWqhyfUfsmadBLT+MzfchFn5B/6zVwWHwNbJz0EEoM+ujEnbUcJvAOTA5JQ2l2IO3aFMaX2jLpvxAN7gzZB2IRfpS5JRYfjXAn+4w58GVAAoqmTaK0CaXoCiEUef4ql8trU4u/Lfzn0M9H9hWT1MtA3P3ZGNQKZuD4LMAnBjHY9OMYNjxZge73vVjJ5wsemPmb/9bUwrftqqAw04zP7OoCh8EyktvvwCnLvfBjji9MyF8FUcY/8HbFEq52HAsDjwFe78jj8euNyC8yCGWnKqB9z3Yc1ToZulLa+LH5WwifMxJu3S2H0689wGdpDTuHnoIpKzto/tnHbKYgBVHF2mDskYOwdyQMuj/C1I2h1GWlhsEHjeiHiCAFmdbyhN1z8EvBLTiRG4vT80ZCfpwgrzDbRHNP54Hv1wAUcB8HbabJmHx2ED0rCC8451GnmRLkBr3h6UW+YOB2AVudK9HfsBH+M/kDo+rn4a9ACT5bYkWJhaJwYG4f7R7O4HhJGSPGBNKgaQFL+rTz2GtfUVj2G8a7e+C9XBPI2hoGC36/wZBzJWD624msra5w5V8J7rZ9RrPvtENw6SLmnUPzfJ+ILxa1ku2o/VA3LIUvDRNn9xtR2DPuEYhvsOXq2S0QtlkYNhUbseT5qbj1gh2LvRaDfUcm03Z8TAsj3cDm4mNqmPQBQjonw5YTXyhqzBu++X0JvgA3LNv0BVN/L4OyaFU+/CEWNaMPYk+VNaR6jCTpHj+KffkI92Yk44a4WdRhVwm7xBTxoWMCF8/PoaZWfXiXG0S147LgeM8pvilXBWUThmbXLMbM+h6aVzCTVs09jTd2G0HTiTbcFrcODDJWUr0z45RRn0FU9QNcWudNo7e5gWlbKEZ4a8PzkwtwIPAvZgifxCU2K+Dcjr14oLONJxW50TCpuaw+QZ6jDjM06mdi4tIUcPE6zlqVMhg6yRqXBT0Fkk1Ct2vJ5BSrAfZl+nDjWAV3/GeP6UFEGYvX03mbID589B6PDhLDROku1jX8hh8SRkKp6TG+k7GU5pdFcrRWBz6fXwALxerJbrktDdshzbaStVx9kEC9X4MbR3/kf+W7een5nTh9WywoJufzwOfn1LtiAbyc0Q25l+VBU6eeTcOD4egVC3o0xHb/FnRxrXoj391yB73NZvCGI7vooNw4eHHIAbpD+zgmtwST41ewh2o5N/vtpTG6QnD82Byur96AOaFygEay+HBJDvJBO4jNa8DKJeWUWT8f90y/BdqL71DTOTu4NMS7ltHeeLCwk+er32KPyt+wSqmFBzaPQOnk/2CJ5kTuES0C2VxRuHxmFP6d7EFjbK/xxvXlcK35Kaw4cAcNP6yko38j4OCIv1A2ThrqL4RC0Xl1VM4Xo4tXrkHtzH/QEz6ZdnlPo/VDul2o1IPgaWrw5KYuuYqshs6317F46WF+FzcPs0Tt6aFFLawSDscG/SRUa5sAA20eMHr/J34e+oun+eVC9vb5oHV/LjhGFOB/TrmY2yYBvzZMgOL7pqBpF4S3/rShJ6Rz0qnl/HvaKFIfHIDGyV9oc508jD00Hq6vn0qbBf7Q9xx5bHSTxZJrCGGXjPGCVQl8dYnHUskfsH+EAQg8f8R/GuKhQ0yFdru9wsBrw3jMrZd4tnMPnNOazlbz59PTS6rwghPhu0oc1k7+hcF2EVAz7wsa+qyiCsGbnNgvCLpz+kn17XDIX/8AFe/Nh+Ff7KlxlCxkxi6mqX/FSCrrCUpcewB71Z0gJ0IA6qcFk2fREpSMfU2dmz+RMT+in47iBHsiePhbTXx4JhCKJgN4tTix7clpKKaqykmfZ/GyXRU8IseKAjOdcbBGE5cNBFDZrzHwNr0ax796w9t8Ikgj/DSsrxKHw/2KENY9F7TFXXnDzW7uidCGWafdWCxNBNZ7dtJl3d8QYD40x7p01NpgBXrZ3dhfeID1ZfUg4qsRt8fMpH8TnsPKkZrY23uahovL0XZBfdwwMYJnFdVh5Xxz+Nd6n83fTYc0Mse3uachdTNDkvJa/r0xFh4PvOXEy+ko+XgiGIVOoICD4TxyFoAR7UL5xBBKT32Ccrsc4O7FEphU/glcQmRg8HAHDX5uwVvnyni+XRC0RI/HU9sHuDDqOhXWRfNZky3w5pkRDM6/wsvknXmpZxIals2HG5ZqaL9sGxarpdFBnTcsLxVEoiPHgJZ/KGj+yaRVaMseurMoXk2A7ywPhvr4Nl75RRy2zdjCN56bwu8qP6TftynFaQ99vxvMoY6EPR3i9LheD1PcCYTnSuL507Lgp38DXLSWU+iwo1gy8gHXFligt/FjcA//yu5//ajELIsz26fAucWWvK5JCyN9FaBDKx/DexLI+uV5GFWSxjderSZHuEXa19Xg9OdO3DkrkEcrbsCQ5AyMc19Hy0vFucujES5Pj4E2q6kwYpM6KK8cBYLxLbC2yoai563H/zb7YMuKdJJYew2kvEVpWvokUpKxhpCV13jG5T+829uUde594EN55vjFth+uHh6DwwVMsVbvDe++IAxjWhpxunEy7cnwgpopwRR1oBeeXdICyfk1ZGWdRZqGT1A52wLiZtwGrQmXYcnZ/XQ84yTZjW/mN9nOEKcgAB4XJWHlBgfukTcHUY1THNj/FwviM+Ht5THsv2AdiOYxqRRNpQUCd9ldV4IP/NKCq8k7abXLAojK+0iVQTvp2PstQOs0MV3xE+nOD8J1FuU484wOWLaNwJ0XroHiwnfgeksTbVzmY0r0J/oz7xJlzzVhj/2t2Nc8GqpiwmB20Va6nlOBT+7m0tIld3HNhiR0XSdDFfZttCDkAqYsGAtRN+dB8Kt8vJg8Hea+UaO8JnVKuDEP6fUZCBjmRAW3xXl9qSVszb0Auiu8Kex9HT1V20SXy0Zx9S4J/Jiaj8qKmVgS0sjzSqxgh80DbPG6wdN2CZHEbXMUSpvPY6cM4yun/7Jx01suO1/DcU2SECjtRK9X6PH0bcvowPTtYKJfDk47Z7LFwosQXbgefuV4w4COFEjeBTiqEgS1EyahyMpwrnrYiFfEEuhwawg9UcjDByfOoruZJlREXx7K/ec8t7iFb7j0U/lGQ042NODAMypU93EFV9TrsuE4Vdj1fAJnD/RCx+B7erVrKc+67TbkX68hpuI+/rdJkMZ+T6HLByZAV3girtnYwr8mdeDFe4dZ8mIhXnJZDSGzJyBWCUO4byf8cxeCE/0/uNunjYIftcDXLE1aMm4sy+u+oCkv53Phw1rcU70LBRunwGsrHcIphZh1vB0yXT7xK/UblFjwHBILN/MFue+cbXebz1pYgt1vPWqfOxZnFmdwrNFj+rxkOIqc2wzBnQ8gMhNhVoI/Tv6mAfuN9lPXY0ve4l+OGzeN4TmBRTTfxo+UTwRS2ZZmONW0HgbldED4dCFHKljx2/nyFJ7QirXCc6BF/RA4bBLArtRQ2D9wjwy1TUFB4TXM3vGKuuI3wluV2VznHgSv3J/wJo1LsN9gJi0IXcebHxmDddIGWK/liJK9PVA1QY5D5HrI4U4k1f7UYFX9r9Qbu4GSo3RgvUYBTnl5HBbYb8P9Rw5z5ZzJeMP/FN0YloOytX54Q0qclneOAIUPV6l9ixHNfnSN+p78Q2+tfzgWW8HRJwmq057jLwMbUnsEkLXpKcvZmUDM5sP45OhVnG5oRyIyY3HH53puyB4Og+qV+E1ZE57bq1JXugxeO7oK/pkH0IO+Q3RpKOvMK62wcZUrNuANPrTCGuR22dI8vwxe6J7GB5WW0BnZ8ZAzag0JbzqOyb9qaeSW93wsUgbuu1biiTXj8IvVbfDOy4GorKNDHViW1OoVaUesIXUURNOzzElgpGSC+072gJ35ezh4uIaUhvqy3tQytpw1mfK+urBKhQiUnkdoDVrNJjUy2CNhT6KvLsGpoj7q1vkG99Uugs1odzD7E4kt48aCXsc22C72DVfcdsdWnQuQZfmZXiS5YOw8D+pY1EOu/tJQKK8AZsev8FPBUyiXYMv1FQJ4TOkK2zTP5gse5fi2x5Du2hdT/3cxMC++Cu3qlpS1qhzVW/7wwtQduHy1FK57LAczFn6nQJ2VLGasCy6/0+iLyQqc1+uGLTlqnBi0CNKCVLnyXgW+G2lJTe+94GqMEShF3kLZImsYl6ZMPiob4LqlFy0/VsWLP55h279TaV2TCKZslYYfVrr8yzsZ9H1yId/JjxZMTGWTniKce8ee13Yt5FDNHlpVJg2f6heDdksjjcpTwJVdP6D4YzW3G7dCmdQ6uBaiBQsHgqBRazioO+1DoQ1rwbm7Hf1GbAH5AxZkPV8CondOhBVfg+jHnzF0c6MgHPr7BFwSBWl0zSh+Y3aZQ53Csab5CBqVerHNDzl23qLFW24jLFR3oBuPRCBGcSnP2/QXT2yrJ6G8fyR2+CyfmzWIewQFYc4aFSjLOYsnJFJAweA1FR0NJGF/ExT64IhCvJwOz5bmSZIn8G2fKkwuzGHN4wnw+fliKBx6v3OKNq09dB2e2WWS4B41nBm/lTZsFAeTLkWe76tJuXre7FLZOuTJTbx8+WRe29pKWeN2c4llBLiSBtQd0kO5Q2U8Xr2HEieIgdO3NXxhhw39d+k1ip6VRsWrWdRcLAc35WJ4v8lnvLI5ACRrYrks35jv9Ypj8qht/EbRgqfrZtJzJR0Ii1lOJy7pk0qdFcV/18MHBpWQKnwEEr8KcI/mJZo4mM6jL4uDuPE27P8WgPdWN4O0czuNDycMCw+C5Old5OXVy7LZAbhlgQIIZFqj19ZnbPpvA7+5/JAU3c3g16dC8o1dSu0rh3hhRhi2TUJwq99HY7MHMEYnFVcFylNedyleeNVMDjpfUMvcHkb1LCJBZUVYHOeM02NjuHxInBjhm2Touh42L5uITa0mVIAfuNz7JzXUacHGAzYAJYM4SdkQv7Y8w9n1caCU+ZZHa0qy5sSN+PdIK3XIKEP15K8wzLET2LEALrzfAwE71lBtpg/snHMbo86dx1CxajbdaAEOFsH810iaoLMfPPeLwvdbabikUxB6Rfbz7otKWDVhD3bPNoXTeqeg1/0ULvumxeZnMrApNxqj7/nj4yuVsGhyDgfNW0mnDmvBnZcDHO3oinPsrXlAN4mkJOpY8XgBN/j1oePmHWAcnwVR1bpwYL4nyresoth7Nzh42Ddc7huF1pEW+Fl3ALK3fgF2LQLP7wiB26px1dtX9GeVAVf16GNMXCfYRpyiH/GCpL3ZhQ3MmljlpDAotVez0CV/zDn1HDsSJcHWbQTs1i7FYYm/eUbwFTogr00ZeYrg5qOBImpfwKlNCu557+GMthd01FMQn2x0h/63skhPIiB1SLc3979y+pZ9+GwfQITsK65p3YqBS5Zgy9C6PRznzmMPNNO/f2bwxdiYi3bZwT+JFJK8NhqbNzVA7NN/dOrDNXqZ5oUlqcKsUaAJx5zc8F+eM0ltaAXNQx9gyqWdpP8wnGv37GAfbyfKK+pBR3sLqItx5VG5AugtNpr/js2FgguHoHS7I32lbPomb0y14vqw+5oa9M1rR8FUM3ITnkNy3MdVH4Voy5ZEymwOxRViJnz1mAqsTWVYlnMOPF6dAZHxf1iwYisbjPXFPSGhuHlaKsduauY1HSfRvVMPkveY87ifPZwJtynTjOiukif5Np7ntfsXQ8sZX5w96ABZy+Qh/MsL7ju1HnKisvBnZhhlieuij9E09h2Ih3z7tyRZqQINU8aCmd1Tcuj6BS+DzDDcbjW8FJfgYdu282qri+T93hf2dZTzw0YTcBvirxey22lK3Dnc32mI1b+essgJARit4khpsR1QE+JP62+rgYjVXU7y9gDHmbp4dWhmL83xKGDqQ9L/+ZCA20W8IjOD1O6rwozzN+n+0jdwxU2S39XEQVjBZhQOjkHX2mZq2+9Cre0fcWzKZAi4LcsHbpsP6awAatk34Y68EVotWg4VyScxzMAa/mgNksJlTVhxsxSaql+wy6z7PPt8Afnu2gFPZU/TQuvt6Ow+nQudXvNhD2vY1rOQntX6YkCoDfwon86bx4ijxrluHqOlzFols0h9pz/LTTGHeEcptmrLhfY/C8HojBx0R9zA7LeCYObugPeFnaHQfhFdGK4H6wTP4q13WtyfdR3vN1fCfxXS9GPOBfa5FcelTTp8XfgsepcagoGiIDicXsgiWatw5dTh1DA6Bt8kbcW3XAzC3l2w9l4ifJQwgZHHIml2cS4ssmojh0cfccXzg1BV7Y3730yCkJwS8FbMod6GifDX5Tpuu5lKfb80cExIAYl2TSd0+oTantmcUhIHy6yy6W7bODC2+0Bjru0CT5OnfO1HBCyts8OymQrcp7AGf05yw+6rL+DShlGw89cDDkzdg5tTlPFA8QrU2FtEp8xD4M6aEswJk4Y6pWk0cq4ofNl3nj5cTYE9LkgCFalYtHk/brR3obwdt+ATKnJnUwk4ndeBpffi0fxdFnfcWUO5KrtQ1jKJlfMjyfqBNUSuycEWyCO/IV5aLFKBoQf24g0xGeyVj8P0nkhQVArDFRanIf6UIo58V40PzmpB611dHBjYzQ27Qmi98hf6stuBpSovwKLXEWRiH8TVIZ+oa6sZRNj7sueCPq4ftZL+9CAferwMzcWewbLxG/niFyd4E5+NS0YKQ/PwPbh/cRxOft4GPW57INxWEDKU7qC930w423sDZGur+JnT//6zriAjhR2c9N9Bupf3mI/L62BS7znsFUrCtbp/+Xh/Hjskm8D8dzbsNTGMA58q4cGvcvTlXyF3zSvChhmW1Hh3CQ8eTIH1T41BaEATtsosYGWtd1hY2cZ22vVkKKCMCR0CfOu9LfunVHF6owWs/x4PGpX5kClmCvfnj4JPa25x/ot+SHIp4VNHyqkx5hC3HVeG3JNZVLf1JH5JyeCs/jbcWHyYNhc3oObbQgj9o40lm15guLM5dIv7Q3WIBAmOyCBzEy1a8uIatqwtJ4OPOXTFaSEfDw0F1UJ1ODyjhHUGD+Ay/wiow6NwaIY6Z304j0tbl9KknxqkvcULxfKHOCfdAR1LV9GEzbcxrG8BzTC3xbwLeiTpps/vZyEcH6Lkqc+l4MFEWUiyW4xKMmvx+VAWir5K5u/t2bDuTQi1Fhzg3R2CsPG2wlDuq+PwHyJgNDKT5/cP4+GWVfD3fBw8qC0nYdMHuFXnPp+xY/imsQBkPl8kLfkADlByZ3HVcxB2y4exOoY9TuiT/8IKOClpCc8smlFxWg+KJb1k57wtWH9yGqv0dcGBoQ4Fc+yhNloYryQwaHxBXl97nx6dUKJJ9ndhwPIsZogL4ofn3+DchWCerxrAws9N4a3uJZ41uxRzzr9B58lPqaFvD34MnEJbH0vzselryDduJf8c8vLPR13RqPwDvb73F6wMtNHt+TWuOuxM5yeK8d8/T9DKT42ufDCDZWYx9CzcER6cW4AVZQ1sdP0kLFCRhuEef7jmriMkvr0AqRMB7vybAkZT61D3UhpV2jvzJRtZLPLQJBW9Fdhxbh+ecD+LV+1EIHGqHDoUarCzdBL9NyuC5mjmsMC0NTT1/gQ+ElzOvyW3wWITQWiZ8RebtSV4bcBt8v7vIdd1mXJc4l4++WUTL4/SAL9fB7HkuQL87QngcYM+MMZiJGam3EGfy4ZokNANkzY+o7wRqRB4q4Ec/gqCeeEF/HT0Mj+ZvIkklR+Cnqop0OYZsHmXK4bYyuOhS5q8IkYUbjmms9/NS6Ai6kofUvvx6QQr/vQ6HW7e2Mlr/f5C3ahoUt06Fn6duAZFW4Mh9PpI3PEsDnyXz+O5DffomPdcequsDzvFftOyD9JQ5TwRRuVL4JviT7xLZh/WLlgAbQmSUHzcmbumnqN2aV0eE24Anw+LYe2lflrabs1Tu1wx9ekGZJEMCvwqjoMR7/j4o5f01lMJ7rrJwMkJ60ndfTHMvprEm0pucaV3Deys38y1RbPQ4UwCvlSSh8yOWyjluRjE+n3R5w7AP+dM/iV6m96lGMIt8Ru8oNKM7l8SB/3jayFIuRAUfr2jCY82IoqrgtORLFDaPYZW3LXEGDcbeCcqA927m7hX3gxSfzzAmkMj4TMswu7tirTh/iII+rCXcEwvC12UgFap8aS99CIsatJlZRN1rM18Sb3vQnDYlNc0L+oaGu4aDadkRKGKjDHgvT4FTVuPkgGF3PvrKexVqIZbki/g3a4wOtZwkIRdVGDNlP/IK/IhrPknTCpnJlHZjiZ44/iBp2xMh8NmlVxWOR/GX1WDYCExXGnfj/6LG1n5Syf/iL+EfWmHsONyNc+bpYwrV4dAFiIMS/fFyVWnOStpJMwT/8qPvuRS8txbjIGAexTUUCSgHZbtVQfNsEOU6bmFZzcs5BrNQbSVHeCldRrsO2scTLNdTBpURdZnRsJLvTuw4LQ1TQht4K+XrkPKm3B4VPWBPKN6+OO8AtxtdYfjx2vCJ23lIb9Qx5xea/bcFgr7RUL52GtTNPk8QIVJ90DDXINnggG4eJ2Ey8FhVDzJiaa6ZjI4O1Ni7ELaKnwXf7QcwAg/Y9r6QRNmWvvTCocPEBjxjdNue7BNUAatu/QERJaIQn/DNTZ5dJwDNirBqmR/Dq0/youGclMLVkJQsjaeXebLhi2qGO3azGdTzUkjwATsb47nvMCZ7B4XisE3TaDqyCAsmm2L9+XuY9jpFhYSikXdTSaQfTgMAiCPhfZNIyiIxrgQT0yMdiblN4MQs9eG+gQ+gq2fPGTF6aBKqCfke/UBz/Nk8Sv1VKaVCE2NrZi8xQIs/n4keS1F2LC4myoUl3Hm+ht4arcP9e/OwSf0kP5O/wx2r3eRzrP1+OSFIlS5nyG5/kJQWylP9PwkLApT4xVLz5H5l3Te7TqbYj785tfvx8NFHy+c7nUWzBaFw2fJXD7qEU0P/9iToP88jLv2EeuKBOG95xQQ/htFubecoDZgIrzfcZIGVEz4yLHh2HRZAbS2i0O3zydqPDYFFpvFwMXVSRynnobYcRrcK3dz5AcV3r1nLx5aEQ9Rv3eBwVDdCZ7awRFamfxvtjvJuZpAwMxeKHIbg6+9c/GZ1gpu2jwTPpsrwupDC0k6ZDea2b8gc6swDBrbwkkzjtPfK+kc9p8xb0gNQhnBIc/QmYYzwzrhj8lMyBBxIxljXf7sPBKOZleChdk7fmalh2lRE0D3xgN0GbMaD+68SRNnL8RjCWd45J5Cssz4DgLDUzG8ZxX9XioIfUUp+ODzXnQfdhdUU37wJfPTIOr8kevvx1K/iDVGarvAtHnCUFWzA0ZqFPOOu1PhQaYL+02KxKD0CHTr/gqqUt9wtnoPBoupgvS58ey0wQeXa33CPdNesXP7U66MOYIBUz/DIc9F4HyqmhevGgZxGstI/O0tHpNUw7tT7nDHjttk9Os5Zp6L4H/i7rzAQYp3rtKA8TrtUDL2FDlHG1DstixeJzoZRY3H0FezCvrUYIwyjioscFwCPO/uJV3HbOh8n4150an8vOwQKo2/hhbWz/GWThFk6EjDvoMT4I+uF5oKzOHIYT5oU6aCbzws4MNAPyz1lcPfr6Px5eF62iYmCqELZ+DtyWV04OIGmLT/BzSkvMRRT4v4Zn093C+Pp+x9O7mTlWCGpBCfa7Ub4tUPVOYtQAt+/wD1JC2y61SiCadS8HP6RRIGKRjx5ig5uYizuestaplQCgWC3pTgLwUFjobYPqjGChens/wGaWh54YkWPt9RO82d2MkPPxR4cPiWbggqzuEzaZ9gSlctSccaQdSpeXB42SAszdLn6z/C8Z65GQ326kN+qBJ8sBqks8tswGm7KnydfRXFL+xE3+46NCyzZRevOG6kGnJL1mG9fYEgumoJrvg2AY6oOXKX5GP+2TOR750QY3NjBzzw7QI+3NVPGT2dGDv1PV0SU4Z+oWYcC5r0+PkV7B5xgRenf6CU5e5odKUZVFa9hz49QoUhvzrhLkSLfmyB3As3OeaCAUwdPxnCDOtZdkYuHe9T4utLCxkUEOYtbaDUXU957Ddbfv2sGM7fqOe1VufBOHgry9z6Ddf25fHPVlk4bOGO5TveUfetzXR83iOKTdwGRrePoG/2d1689ypojBcF9BOGeIGlYLz/CV0uC8JlRhPZ0SYF1fMCYHLGfMrWeAVP5y6nxkhDGK6QggrThvblgC2XzxkBU3g27n3cBHVy/9HnnWbg898qdH1kCvPVFkHJ2hM4T6gWL8/oBoN9RrBlrgQcfF/JYk02WL74OngEKIJ1niRc3lsGO0StWMZMmMs+JpLNDkX+pJeOqyzfcJr1KUzDMbBR35mPS0ji3IqZFBAwAJ8UmN+0jKLHu6Lwre0h/v76KBxZYQrp/6ppa3gppMdYcZu0DvlLvYDVR5sh03YaSZTf4cP+CZg5TgxWGz7jyU1L+fJUccxy/crDfd5AUacLR82Ro2NfY2nbglo4+nUqpK/dzPWTSmD4kwOYYu9ElrlmEN5cgmO+fKCE7dehVK+LovYyyIzcyldT92HElLnkumUKmFwSYvf+b3BR/g1Evj1H11/k45WyYTDVrwpHnm+hvSE98O2kCM9USWXoU4JhZ8/w2Mw8Xui3Ag6us4K65Y/BK+oMHXxYh8NPZLPG+VraGh3ND/T1yePEZPSwsAI3RYAnB2/wRN/XrKeUBa/YmED/GAqMruCiNZvQ86ge6Kncoq5FMtDzXpgjTi/Bv+3uLDSmAven/8BZt1/SnxQXCnLeTp7H8/jkDy0wV75N5WVy7NhaT2syZNDM/AUkq4/hmZuALjxehzP2dNEX5eHQnVaNq/5kY8/V+UwlJ8i5dRq+14tGP2MNTih4R6P618JqmbFgs9wR4PBKXlO2Gse29NFKa3daeGUtbQyLwsgGH1wplA+P3Czg0rwYOjXiKatd3AQzH4ny5q9zWejaHXxbaU6HbxhgZ2gxTa8whx2b+8CiXAzE/d+xj2stiSaX8PTH30l63wdQtXAAmYATVN46EYoaMylATpDFNl2H9Jk3Sf5xD70N+Y/uv/qOBlE+HBK1Hqf+GA/dqYcouOI/ehplCrseBUNU2xdaV7IIzjkGI29JYIErNuhvrQWBxcpQfT2Np8FwPJb9kjbGRNHevHRsfrmHHipnUPwOXRDuFATd7lKcESlFLZ5SLFc/Gxd3V7D4Dg+M7wulBZVXscfBi4x8AZZYnoS1AzkU4nIWa1sfgsR4dyp+upGvmLaT1I5t9K1qGQc9nwBFIUMZckOYzz1zwaQj+mDxcgktOhtPVQ/2ouXUkfBubCu+GhSFkKcj0aTGgQrel6N2dCBlj74A+fIq6BXcxfWrWrk1r5zsRkwFqYRONBJ+A82/PWj/ORsSY1WYu9qId8zRgpnTREjpXw7q7rWEBxLjOVjVknsfnuZZgZE0oiaBH+uextgDYXThbCwXGvjz2VmjoH6yIE+8GsPyd+woZds1vOjugD9qXPC+vgZdPK5ODnvXs2K5EBisvEFlVsLwbWA8u/i9gb65+iRYKMTTZl3n0y5v8PJ1BwoSJYi4p0IdBb4kKtkKBXf+8sytwLGfFdFp8T/a2WiDExr2cc+VsXBg4BR/9NoCyoZn2NuQWfHhFJ46XAQOmC7l7ChXnv3JCwUaDMHeRIp0HTZTk/0k+KssQcJKivwixRWMHwthpGYLx8z1x+TtglA0ei99rU6Ems+aKHnpEheNnUJ1jiNgrHECJswWQa30c1xcSjDu8FKoMLlOwapIPXYS5P9yJGntKUS3bII7rSos5TsZR8TpgeroEvK/OgL8R4ax6vcMzEyYA1KHX1Du2jzqD/Vg05mT8WGaKRS88wNF+4fc8Oo4dZpJw8eEWqxKDabiRBE2lXrAr1aNJeEjOvAzeTcZaH6iSRoVkKO9i+7LCPLx9U3gHlEGy19s5Z/t2nxssiosHTWDt0aFwrWJt/CRViFLnbhN448e4vNfNdnOJQs8Tuwmt/RxIHLTGQKuTsTI8Uvh+/bVKPNuLi/xyoHfff5sVbGUqufJUFTOCDidfI9PifTxrv5OtjuURHMnZ/KOwb002iydiioR9ni1kYypLpTlP4L7XSoQdjuRVceV05kpfynnQDQtGPyBRhdu895gWTz13gDk647gzAYiwetHKGd1PLbOFKaErB1w5+crfltrDGGfpGBnvjFc0j9MLsZf4eG/M/zlRTt2TwcONtcglZN/KVneFh+sSUHp0fLwcncvzBUbiUEmN0Hwdx67KfeydP45/l0sBueuvAeXT1F0/D8xsLtTTad0NlNikye2BO6EhrwgyPYshuzZw3Gh1TFekiBBOFsZpuTH87wkQ4yyU2YOOMzxtw+Db68Hnlouzl+7rdBXX4ryEqdC9VILiDeJIaG1pSh6dwytMpsFU6qa4GZSD7yU28VfVv6mt3cmQ27bDb5TN4B4U4N0t80l5+Jv1GKzlt68qoP2aVOorSKLtlZag/OZFmx61YaFlgv4SPMWzN1mAU0T56JF92vcsKqHtlR3U1qUAswM/8dmY4/B6qBRkBXjBFVyv8AqxoUS267CnfeEt8c509sOfRDyKmBJ0Wegl9EN/05HwrfmH3ztlRy+K7Fg+bllOPOuEOrUTYL+svX8tsKG9wiIQ6PgMwzecIjsV+5Fs3WimFH0g5p/HWXvJDmozPLC/fMP8HT5k8Sa3njqsz7eFrGkjgRtvuoeCS8q3OlYs8j/7qDEA9FTYJJNHypsHkE2jj3c7GmO23kKevgd4bG678BxlhqMSS0n17XZ1DTLnZ/WXuGuvuMU5j2HT2yxhPeObTzdYBvyVBOw+5FJkvs6IdNxB7ecOUqxI8byUuHDbBh2kSa/iufItOkoETgMen02o2TiC1batYJmgixGy0fRMachC7+qxYu2KMOb6vH4Y60ANCXqwrnxNTTw1h2Hq9wB3egIWh2ygUQEjOiupRkaNMTSecexMLVNC9e9GcD15bH89c557jYZpJEKy2CEsCfmrMqAh1JPedUsC/B4WQ6RQ73/tpYxyLkF86Is4jzRZPKqUKZMl37+nTqA23V0wTLWlqZqyrO8+EWwXmHKVyf8g4StarAk1hdTxpWCjP069Lk7CgTX17LEvQ4+Ta9ZdUUnHjFZBCu3i3IAWNCVkiXoYWrKTmAOH/NLuXzpSnh4Rwxa1u+lqPddqC3lQaJTkiH++na2Xu4HX9kSXr4L40U5znh8kSNOGJVDck9c0FN2LVQqjkORJ2vA5nIqPDtIEC/sTKX3l0FeoTS0p5pgiWYb9Pyt5rPD9qD5Hw9+8TWEZXcTLDtuBtIbSvBkuQkmiD3AiRlrOVXpMg1sUIdJYx/hJNNrJL19ONxsSiOldCt82oFQq3AUnvfrgkKmKZnEVMG2gtvwXzRQ+X8j4O/TfTCjKhZ8b2XTHFUp7hIfCVsvanONYT6JFjRC9pZ7UHtQBaxMu6Dm3Fl0nj6VJP8xXpGpo4X6KiAW7AmHlteSzM80VvUfC3c/WfLBZ/cx5txIOuN8jwZ+jiff70cwenExX/0xiqQ/67HWgDT0jK/CLPXF5BN9Hj3ufoc+qRnYeOkRpa7Mg0Z4RCI221AjzuD/7f5fV7iKKpGFtOTke5ZZ2EQTqs7CjeAd0ESdON78PF/uSuSFqTLw4H0y9p+TIeG2RdywSgJFckbD5RWxfN/IE1+/z0eVCQqcLTAcHMvV4c76/Txs6JlEaDLaO0yEQ2dr2GT2A8zouMRSCctwn6sOZOWZsfh84v3fSvl910KUmN3KjrXpqLNhPwQ/vcrF+bPA7cI4mLN0Aun+UmX7veO5aGkV+FyL5tFp+RCn1wlJ38XR6vlv2jBNDzT84vnd620w+Ys7RoyI5IDSDpx1/ia+/PSO3F6NBo9ni8jqhCycylxNznrymLQrgK98TCKB9mZad+UzDYZH4/rsQm6IfAd6wUqw+Kg6rh/chteqykCwzQNya+xYd0oz7o76jfJeyrS44RzFzxsGpYOXQSdMFgSUBXCgoQO3L8nna0vb+b7CCVoYjCBdFcMbhxpX2UYgkx2GZOqSSnf+VFLOMBdyDJLkTePk0FlYCFKsNuFwVTE4LVyBkeIEd9MvwycLebCwqIMRzx6ygcM9ri45w/Ms0sBN1BxW13lTyH43sO/SgV3ZtTAx2hakDjiw3akm7pS3hJ3SgyxaJQPHPnbCkdUOuEptBC6oKqUcjUVse2UAim8SHCqShwTPSK6TVYFFvjG4IBXh+qEDQ9/WierzVOBxryuImYmRUYsNzzq5gLP9dMBsnztq/nTgK/8+YFqJGFUQY6/wVtzsNgDuDWextXkbkp8CTDPI52+3pPlpdTvN2TjUOzcJsYfOJ+y+tx09Zn7iKY1aVBogDEZLn1FadwvE9f2jjSt+cnniUCee2cSGtzPxpOE0TFJezN9vEDz82YSemULgkf4OS+61Q8O9e/jK5zh6/7WFNzmupNw0HGYkGIP0zxaoMgviG7m/yajUCp78uoOWezLhelYOxeyfCbmnRLHoliU47d6K1iVx8O1GGmRdD4erph70eN57UrXyR0G3AP6v4yKIBsqD9Dg//Bizi4KW1/JRp+HwS9iSqdCYD0ZOID2zCHS+fxxPiqnDqq9+4BNeiaPrz6KF0HUYPNRGc1q60P3pWFwU9RgNZJ7AiHt6ABtXwvf3/0exeUcD9f9h/D1UsvmSUPYImQ2zUoRKS5SWRDsqKdGSNFFJkygl2aGhElJmtoooDVtTEQ3Fz+//+znnc9/jeZ7Xuefa49F0Nd6+YhjhPBf0/52AJ5vHsEGDJbhcH83jgkwh6N4YUkMzdApuBpHer5h4ZT2fmjOHcx484cQz4yCx9iHmX9OAtpCTNGBYQVI6KfRoijq7fzdGnUYjKkh2JIsx6+ibmyKr55iAUcZcClpciyW9vrCoYDe/3RQJK9bXsPLtXaR2KQRcdw7tWY8cfHpcjTtnx7OO3nKKvtXEMrMrMKevhaImVPG62OP0Jug2TNwkBGceuqN69Wq2yZqF1w+K4ozfhhy/sBQDVkfwssYkMqrzINFuGZA2KcXBxxv59ARhjgxupxWXE3nNbh0+E2kHzTE55LpoHcZlDYPkhTfw7eu3cP7efLq94hU3GZyHwcluUCYhCLMn51OTtSVU3bWA2GevaLugC73tzAK1Bgf+O2o578rbREfb1qJjwglYlFdJn8yMQXWHAr2YMQgxU07wjhYh8DlmDJ3CB+hutT6u3SlPL3xDmIcZD+3ZR1ZUmwOuaIMzko/ilMPzoNhVFt7sfg/P14fDCu+D+Gj/NLA+pgedQnnU6rKEL+mvoWoRF3CU70ff2AFQ3SxBJ0dfpLYXpnAn4AMHfMyGPYskYPxvHYy0tsBIkTvooXACE8O3cbNDMiaVq8PZ9gCqsZ9BUxv96OlAO/hcHoF7rD+zRIIEj1mhRXeiovncBTXQDz2J2lXPWPWQOU2IugXBe3vg69I3bKa8Gkc9a+fiNRcpIdoE9POKQM01kvY5/OWMxbpodXYcbStuYfc3VnA4oZaKS0/xwCFxuL/ZhHqPTeP6gsng36hMKxsm4zej73z2bSHbiM5gLdctJDx7FNQfOgvH7a35aU4g3c6MRh9nBTbOD+XD9z9xTFQXVbyOxZ53evBk0h8cTB7g5Z1OdOVbJuSOUmSrKdsosmEvSpYc4m0KK8kwWhzO2HjT+Kqkodpfp9+XEIQzVTA+1gwWhLaSnNRUlD0yADffysJoU30K7nxGOyzCebhqNTioHIfwXDvQ2mfJw9bvgbiBf5DkPaTjv8Mg6NF6znl+Ew6MWEOi87+iy9kMrnKzgO9GAfDLxRIMX4tDV/UX7NFfgNGf/sKL2jZWqSoEpZJivpXsCXuF0nBEuweFhY2G7IXvMXqlGmxwnMNLr+zg0t1GsHRcORhX6+JSrZ8wPjeYdf+MgfdFV7E76RU/1DHDru/quH/zbBjfKI8TnhSS13orcg71oPfHVGCm83yONdLng/699ChgH9brvcTkHCuyux4Hb/PaybFUiZyWSoFvcQ1GHn8O2PgQNC0d6Ui0NSxe6YI9qleg4vI2PpgUxLmThEDzRDZphmtxS78HXH/djmMnylDSBle0vbmCv5TrYdUWbXibORl6MzSQC9biBHFFonNG6Pb3Nbv/kqCKRVrUMZBIM8Yep+G71WDBPyMOuheFc9c2glbkJRxbBRhat45i609CougBjN3byl9cRGEWRsC7iWchMG0i3dG0gLXOG+Fw22h+/y8Lle6qDZ3pgS8+qvBQvpBidF5hu58WZix4BTYBKnRv2lfe+PUnmtxvgzGbP4Oc92hwqeynlnmIOvJZ3CEnyYtfPCfV/Jfo5neeQ7e5YuK12Wxybxr4vBrKGxlv8dDJLCrJT+V/AolofjUZfVKmwvc4NwjODuKw02PBVkSbvGTTWOCqI/4QOE6yI1eg39xvsKfQmR6EiJFe82h4kTsZqs69J3WNl5wYMh+HeV6Cc8OFsLxsF8yuOgd2pkr0UsqEoHIMxEm2YH9UCy/KUQcrDTtMboyCQ2fWQ92teqiavxeqqs1Y+YE0HHh+kV8KGkPYwFIcVNnAJjfOQ3SlBaW0Z+HD4z/4gehp/vBkInjvEoD4qF+cMUGeoooq8E/aLB6x4CKcXfIe552oxDf2PwneTgCrcauxZncyh4h0g7RSLd2aONTH6kJ4IieF0RMO0SFBTz6VpQLjovdyq2I89/z/H6K7JmBeKciiiy/hF1dgab9oiiucBmtcVaF3oTnu0DnI1UtsYGLxXXzZ/JJWLbsONjk36f6KGna7XIVXFCZCd1U8CNjbYYVANf/NzwTVJTlYf8WZhOen49KwGDCV3s/xZ4dBjagIen67TQ4O92lgjhwdS4pChQxfLJjxB2a65vImsQu45xiDxF5NxAg5fimWgwpXiilaZxnY+33lFO+xMPf8d3o75ElFg0O8NXE2TJ5qie5hyXQwbgZNdzCglu3aUJFaRiJB+8B6uhvvfysERYv3s/DnS3xGYzkq7lFBwxWG/Kxk1hADWXL9vA+w+XM0XrUzBh2BEVwdM57rzI5R42YPWCCnSTdffmJL6zEcpZHLZa1GNKrPEoTt9GnOOA/YPNKLPLOcaOr0RJRzaKBnyo44KGDM1+sz+PA/Q/Ds24n2Um/xheIZDsl7x3/HRtIOeQYV9RM04tNFDPOXx/pBA6iSd6ZZH2QxuyiLnmo/gFT5baR2P5M05TazSnc6n/dKJCl9c4h9ZwGPBmzAd/1baqlejLeSAlh/iR9czmhGW0nGzu3e9PfpfyAxeisY3q7jpbuK4WttH35p2gqXvTah2EInqGyYzKoz4vl8swo8WRgI9y8exG1fqkm2KpATsq5TUfUuHKwX5rkTUuCATTlliptD+sorlLdjHcxbibw+sQR6znRSgmUwT20XI9Gkq1A3oEa3OzTBuceN6J4jiccdxgcOzvj0ZhQnuLxF/dxdrKh8iz8vO4x/2xkCFjiQ7/BZMP1uDdwYNZnD+1WgYdpGkksYC6Mzy8j693Ectk0YPDydYPWFTCw+rYKOdr/42uBUWuYVwEnFXcgCwvxnKD9cMZCEOwX3+cvnAzBjwBckxsRyzSh7Vtf4D7fKNUPF70VgUd7GPfaT4NtMaTw4eRkWjw6idXG56Ou+kv67nkppH+NxzHQtMBF5R5WfJsEvZUtUztiPr47PQAXjHCzxOo3Gs1UoY6wWbLgsCm6WaTTq2Fjofp1MSQsrYeHoxXy07wxHLHLFX6++0/ZaV4pxaySVb5XsvdIA7l56QBvOKtOUwQzSVUzCudt1sGz1Ou7eVUpfDjuT2ZskKNihBhtvxACrF6K2fTYPnyKC+j3LUWVYN698bQJxj+/Qx4uO3OKuCCV64dRVcZa9dqyBKWZ1VOO0jR4tKwYToy3Y0vMHncUfcvNQPlXvsUKZ7Za821UBLxiK4kCkLtTUefGvs4WoINoBic/V+VW3JaQNtoH14jR0nbkbxu3IxnW311PqGAHMeBRFw8fcoJUOMTB1iyB8EnCGdef8SDpTBur3OpO+vCC89Q5Dvwl6aOtfia4CYvxmjgK8VFvKkP+NpWMXkbjRaxQSPMQFdoIc5CsOGx72UeiwULoUPwq616WReYEjC+ovgf90JXlTegzePvAQxltuxb44AwhOPI7C14ZB1sv9NN9wM+ysm8ZeVyrA28eXdiVIUuEPTQ4MBXp15zWvtjeGzWpdfPjyNdqx9Qsu43Oo4fkYD6U9x531s0lwURBGTumEEz5j4ecxcW4QeogCT/J5RpM6T9vXj5XtQnQbXEnZOhDazqTAkwVy4DSqG+Rbn2FshztfaMqmmT/sODCgH78/HU56407j+zsruKxmInzejXzr7id+vtcWb1ce5wD9hTz83EUU1FaE0qIC/hsxirlRFtR3WvH6sg/caTEXerZ4UPvN+5DbtIxENaZjdrssdDfd4ZzpynD7ZiCeeKHNfwXG4f0kX5wi/AcbN0tSdlIheZ8VB+8FRnglTxUOSaznyRmd7CrZDM4fjuBvkxRueutH9WaqkHNOnnOUBbjESh60B3swbdp9elighhVf5Cg27jfa6s/mXeOyIKf+DN58bYRetfLQGgU021SapLqPctWwg2w5U4pWLkhAh9l+4NO6Gx56bqALr1XgzyPEhncL0XzwIUtCGWz4nclxad+hMa2XL+xZjecONnDpXHV4/30NLgt8RBOKf/KysmsYee8ifdE4Q8/qG2lb5CZSeHqX6vMnQNJ8eVKdhpS125qS26Zx0Z9PcFqwA5TrfdngkwsUdlfggUeC8C14NsTbJJNalBnU/ZBGT8upePvTO1Q4nwCf19TRwWnBVKkjCF7aU+iunwB/P/8IZr85hzW63ZilMYD7xuyGcjc7GG+jBQM2o8EpOhirHR/B+PGKMEL+N2vp9FDAnSJa+2k+1U0IRXunEzDOTgRqfRrpXo4fP7+WgnYDS2jTjhZ06hQAfe95bFvsA8s/t+LTdAK1kVr05uda/rPsEV2fsxVnOTtgRbchL8j3xacusVzffptOu4lDasUTuvpXDtKtBWiifBCPlQnE/ve/aILCT36hNJTVN+tBav5UkK1Yjsdu1eK5+RM5YVMZTLFEvHnvKV95dgPl0vr4Wu19fpUsDLOUXNH5804I2zGMvJeY80xlIZj/cR9lLZwI8/wOcM2HA3SqWwGGvRnq34Apbyi8il092jCm+hrNqO4l93WzsN+wF0UfGrNm5hRwdddn1bLDNFvpGWR9W8gteTn0OrieBTMyaM25FO6omI/rnRgetx0mneE+kBcQS2MqUrgcHPnYVn085WiJl7xrMV6QULh1DGxoLSP/7d5QPsIAex9nk5OjC98SNIfDGwfQZP5jenQsn/DcWMjadQQeKm2hXxqRVL/EnbfrteHI9u0gfWMudzmKwOXtefgkleG69yCGPjs9dL+xnDbyNQkpDGB5zw6S2pPL6mM2YYP2AzRWMgaFfE30XePFh+x24J7AHRhj9QJvNt5nuyx9ohHz6P0/pKY+Nch0e8JnBPRRwnsyvFBrgGihpTTraTrbJt/E8K3PUeb7PJ47IAugo4QR75U5xIpAvtaBf//Twdzm3WjzTgflbw7VfVQpOcQwNFi/5HlpP/jUl/ecFOdLx5adh5L5ISgS9oLv+45ns+uWNP4VAZc+RSWVzzB1hhs832yIji1+HPUrCX9sNWI5re9Q7XyBM0I1wD7Ug/VXVgCm9VLYO30OSnoNnsPkOeJSJw4+ieEvjl3wNUgBeiIFcP+jGJwkzpwqdotuFl3CLc09NCxuE3w55AgtI3JxCxvC6qs7yTz2Ib6bmwRpXT84o6sLfx5ZBF6Rh+jZifdY+D4MFB6bQc3c5TRRyITTJqlQXQDyCwVXyOXLbLHVkvJvneSquUH0HSRBWvcfs4YnzNathtWXRuLSUDteVR6O8cHDQPt6NQf338aqKpGhHZXGz5vS2bD1LHV9GYug/ocbylRQ8N1hqGr8TL7O2axXoAYfEwNB5Nsc1PPTop2pa2hu8Ai8/WwLV69ypLmnEvDrNGnOdVaD6Yry4DypiJ4u2wInBNaRTcIpCtL+jc+OBEHE3J/UsrUNZQX04Jl6LHiPn4lprzeTxI5qcBvnxTNljCG1kuDV8F4YlraG+s8pQmSZFMxtM4Wy6Itg/0MM6keqYti64ZhxMQamwz+o3mfBKulCcG3fQ8jJ3grij8ezyeBxHrUqGPWbfGHOuW+g4zVA4fePgso4DRjZLMsarX509loMqU7fzUHu9+FzzE6uyhhGq9xahrzpNRU2KUDZ/p8cceEkSy5SgYWq3XDKU4snRhXCPEumAJcNFKSuB7lPJ8ESKUVYdDEfN6y7xNU9SRgglczKqbkYIejIE7t/04T003xkijHc1C2iTeUtONpVERq33Oa5Dm/hySUFtszJQSHJlbhmw2Ec/k0edo78Awu23mOjcUvw2eeJcDp+PWHGYxY+kgN/f8xFu6VxtEtTETbGB7BH+y5yjHvPZBEP5TKh9MwvlnWPFoO+7Qyeo2CMCprisM/PEJp9DSCl4B3jtELuOzERvS8W8fTgGj7ZMkgqHyspXUcHVh1ezh9tK1DGsIwOqhjB6SdKtGBOKjip7eHJnntQW/syFtpJwTjnqTCgfx9nX2uD7wJBmNKWw61Ds1oOynDRVYW1r9tS7GhBCLTNptGmvhCidRHiZCRQLOYWHBBZC99L54PErJ+46nEX3nDXhb/Xd9P+/ud4Y/5STE0T5o5n1fQscR5/OS3NSd/TOa43hmLqEPb0rcH3Zyvok0EGLbhVgD9IBH6P/EFCZcL4KrEIV9YSzzeQgBilmTSrrQEqJ0xjP+l8XpTxloRrjw/x6BsSSBiPNvevQ2aCLnxuqcVW3zUwvXQBtU824jOdNtgnWIi0shqut0lhpm82RB81h9HX/1C/wvYhDu2EiM0zWcFoaFbGL8U9DRaQeqIWNefv4jWDUiAv6Qd9PSswJNKCxw8X4H9JH0FcOZyrxy8m+cV2tNH4J57bOAGCeoZYKX4+x3u+GPJmPx5dPQZH5jRxv4sqbrrugulvNTGEtCC1YRZJOBZAnlsMfb+RTw1N3mg/dD7FuJSTJhXw75BGNvcwA0v3XK6JKOGQvW3oqhvEn87uQzN7YfKO3wp7th5lp+w1bB5rAptf9lHOCklKnFEHgTX23CWlhP6iP+nH2XwqlgiDLXNfcbacLrjejcIULRvIPrmUI8O+oXnIacxvU6NaNVUepxCK2kcuo0eTLji3nATZjMugJhTCCnlt7IV/6YXtcSqYqcCzjgrxarU4km6aBmb2yrwzLpRmi3vg529Z1HR/FtcGlNJ5u6vUvi8Le5IE+cdKCTg7bT3sifkNAukyvDY+nJbo/sKja7qhrucJB8d4kKrGCR4rogvbD+jy2lV2fD7GAkdpbIAaT1le2lfFqQq+dK2qhOYN/GLjNkPIGz4NUzysoNBclnoPeQKsmwEbS+7RiznZJCkeA2u8zPHXozEw4dUUyucqnq9eCW7GFSw9op0XgSbKR1+iS6mZwD83wP1IM1AprIT0R3rsJRgKRXJLqaJYi/8JncGdRXXYOiaSJrla4mCwAWg9kQSK8iQVnUxaHb8Bfb7loUW9JM/aJY4uXZJc9f4HlLdoQe03ez7yoIHTGjW4J/s95879TArORqyqeAijLuzmfxcL8XnwCLB7mQNSyybwU/878OmoOlyXzgDf2qX4PlQF1PwFUdU1G4WumkHniUfsOXgI6v0ccd+Ow9j6Np52yWZjvOtjWjLSF3KPSaFc2RSwOTobRkbJ4rc9abBpoid5RhihfLE1iSnkws7Qfhy/qB7eeelB3u/bGDPggTtTVoLwEKfe/u2Ku4J/8eUbLuh/ohl2/veKP6aPhobB5VQS74p1gatgzAhl6N0Rz54CL2hzylHOiNKld6l7MVRKAzquqEO04lZofTwIH/bW0J0pe/Ha8kC+HPEdnZ89g7uhCXRFWgtsL0zg91/3kMD5ev5hdIqedgDJpMqwub8KTzPuwyVm/9HxtvHws9sfJ11Ww4Hrd/h8SySfXm/HDZsr2XPeBJ466jRknlYAzQZtsOm+S6Mtz1L7iEGYWzuaBjYW8Bvrpdh41BoS5tfz8XvatMNHArRfX0KZbB9IE/NFs+4KmCCbwmsHH6G9fR94aOfwXHlFOqIvBGMnveOKUfno8/UyqHf8Y7f4VnJ8+IVG3s4kf5ftZKMnAqMtx8LeJytx3xZd/lFfituE7/LCXZ68PWwBuRyairyyAebaFoDk6QkgZeKEiq+GwbxnF6jofA1HeIfQ6nX38fB5Lw6JW45ffyxHh92qMH9TBcSVH4MfczdyrY41fI0/ggkyInyiVpVHDDvMnyyzqcjKDE68ec1H7CfziZPlGJD/FFZoP0bXVX6cmTUbD36fBHXyV2EgRQgqVd/wsx9SAEUd+POXDjpu6qRL5l7YXBbPaavqMZzEYewYS/DpPUhBU/ajkowqp6825OAicVjmwjjHYwk6bFPjry1ZVKmiD79P59PX4nkoM3czDQ91xWH4gm1/CnN65hb49Nqad2suQwlRU7h5zg3dA53Ipf0rjJIc0t26EJ7zYT3s1jnCPpW7QHMBUlmKJXi90qNv3+5D+theWCgogW/XH6DEvHrQGnWSpezHskVJK2QsGgY7l8lSe743GEl/oAgze77U1c+r2YUy5uXBxZnKvFJOltWDJoPW3skUsV2M/904x47iemA+rZ429mqx+nEvdKmMoUd6Czl13ySonP0PUq8EwqYcJXY7/I9/WdjwRYNkFl7fzZmL83FjxzmMXzsabh/Ugj9XhlHWb3N2P7YD/yvXo4vH5bnEB9jsnhDH12mRziZBULEyJ/d8PZ5w0oq3cQCPGFuA1/qWgJlRA8y68Rouf7DEfws14HnJG/TIPwP5sQPUHHeJczfuIazVBcEWU3oQYg1xKfNZ8uwY6OzQ4+cDXaw4axSb9GyHq2JnsS8T+VjYdIak2winU3G1kjS0bdYEseWBOKgizFEKH7HV0AGGvR8A0/QP+CvoDiT/8OTuuZbQmTCGbu4zR9f+Kzgp4xQdFPjHE9+dRxOpN6h18zVox8/BqsSp8O+QJS179YJmPqihMdrj4CqcoPH55XRqrCj4L/mEX7cYw3QfQRDf6sHCY5r46rup2CpymU4cqsCPB3shK2oCJ9qex6gsAVCP1gGz6V5kPecjnZ0YgxeuNdKk8R0c33sFs+9PYROnX9R2bDb1nzAAV31TGlP8i+XN3rFW5V6gl8thd70SjEhPgx77QZQpFGPPzqF82JsEM9YkUtl/MTAvexRVf3LGlC/msGaHFqbXXYT2Yllw7BcFQ2tHyjkSSZfOjAO7PSdJ0bGb261P8e3hr8jcMhnGuTrAthx58PpyA5/7mXKniQlYTHwN60394dO6H9g33ZcW+zKIm+dwoos83Ji5BG8oj6NXf6pZpmsj/Lv+l0bWvEHh+mpS1QrlNcW+rNOoAr0qC/BI0ko0rlclhZ01aF5ugRXh7XR/uAf7mGyAG0cccCDCDATenoEfyuu4NHksrggJQ99WG5owbA+bqr4hlRl/CP0t+K6ZBOi1XsHO9E1ss3gTb418hpsmJKNL+1W89eAXO2bU4PP+i/CmQRA2qL4j8zQ3XpVaCC0nb7JArD2mHjeF/RfjqGzFR+o7WMQFIzSh3CQfun4UoJjJJk5fPIV+XN8OF6Y9wtcj36Dg4Sps1LblhrHjQOfYcP5X00pKi5qwXSYCxmQhKUQ9427lcfzI2g1cNIgFVljAz5+GqFF+Eny6frGMwCpSm2bF8s0VZNqZzBPnqkG+xF3IniUOXx6WglbqbzJ/YkvjA2dQ2iIV0vK8QerzkuGCtSqt2mIG6ycawLazo0Fg3yEsix0Bv+w0KCJoDgRW74ZL+cz6hT7kERXOm4omgskOU7LcYIz/rlfCVqFcVtzSxdJ6DlhXmYo3/3lDdpo7uQmZwD1JK86W+UIeksps9CaUa2Rkqdh1J3TeECKrjQt5kZs7jvSRhzKpRfRT9xB9/+XJBovUQHDrBnYNVcKMndlsaupC2+ZqgNrsadC+TROW92jQ611mEPczh10C3lLiEwD1UeIYVHUAEmcL02pVXYhJzkXbzaKgWNhN7UKaeE2pAc5rZLCY4xdOfR3J7wWy0a1WDdbbLOFDJ6pYd+I69LgkiRLOY8EZtlKg/iisPt7OMaJFbBSBsPVNObRMjYOa4+84VKAZ3wanwKs3++DOpwEwvybOKyN/k+C98fAo7DrsbmgG18Gx/KFFGmeOToetXiNZUH4XvfSdDod+VsPCId1NS4qApg1V0BXgBtqXtOndxQT03vKJ6i+8osu7b3H5RoDf7yyhsl6d4eAvLPwSCYL7FKnLboAtft+G1sbDdGhYK93raaS2ihFwzCAEZzjNxiU1E+HOeS1uunsdp293xMUXQsnsSwX+FT7ADS5icCLdBStuDfKYJ4Z4nkZA8KAPXLO/AxuvDwOheb+pd6IgXV+iDsGuTWDdXgpuTVrcYXyAttNGiDNJI1PLS3xewYlkvM5SzXpFuCjQjktuW9LPYhlKrpvGMrcfY7joCTynEgTrqJpMDx9jz0gT0LB5zw9EUjDp8DrovXWXBGUF8byaJdwcDOQbqeX0TkwHOwYAVq5MwrF/JdnIxZnPR7ti+toG8CvOBY11UWhwWR2UNW6yc/00WPz2BXt0SrDJjAxYpdtBdcG3+Vt8NEevvshP7IY87OgaGsuKEJ93mtyXr2ZhiyiYPHMdzXGfj31XmKxOxkH841jsyHHHd6vHQb++JiqkFmFL+HjKjq2ijbL+nGKsAAsL7OlufStM9j3CYdIK8HhkLL9kLzgzaQ28VWBYpKDOk57K8tlcPTrcv5WsVtXz313a0O4IkNLgRl63WrDqhjw6Z24GU51yctIXp9eXT5CVSQR8eqMFuw3TQLPyFpaayIFUcQ3ffXSen+z+htFP/CnA9RXn/oxl8etmkJ4Uj5trEth66h4W6z9PJnpGfIpE6N36Hjir2wc/F9pQUxyCkp8iP1f9wpeyQrjYejef0LKDGRqFwBlA8yc2cuvBJCyzmAomvmfRzX8VGG/rhMzSdFi8O5GKNmRA1/w7vG2TAezJtAIFERHYiLVYf24OL5zWwzkWvjTF4gdrmDj9/1su5aSKU9ep+SDtrQ4/tcKo6k4sz+4QY/XySNKVEIDrV6UobZY4xs/WApWmH/C4aAyolDajIqTBPdMuuvd0DN8ddRtP+z6i3rCTdN9pLmYE5nPXWx04GvkdosNLSW68LWt0nYE3Y5u45kABTf2exy/M3SEuuhQdD46E+NItGOniz0276nhagz0ckTYhRa0q9NqlQG6vP/L2wPuwdUAfbt58y6+XKdDkCE02DO+kopVm8OTFSrLcEYC7sp3w77hqtImVhuyWI/Ql5iY/McgkHXMTcg62per43zhPVhITqhN46kA95twzhfczx6CjSAONNfpDPTPiOF2xm6yCZTn0aSIl6nRzzR0rPmglCslOwvz06D2u+edD/bNHcvvOdfBLIAjGG0nzhtGP4ZVsGmuby4GVyS1avjWfjyYGY83JYDY/+ABkHswi6S8PCFetBbN1bvTaQhXmeN4D4X59PPtBhRrYh2KvXuPm8zGssF0J+4flQEnRSNw38T94834Dr9o2FvQH11HYsif4bL4Nio5/QC+tPMh58UloG7ePSUcKJGWiwbdvOAn/W0cCwzrI9aIdjDIdgT0ft/GpiTp81mQUj8o0hwO1+bB6yneUmfgNnmRYo2jVDTz8uhp2/tmEtqKLcHPEevYtGAN92w0hVO8TWbRo8PTVJSzlqcf1OZFQONkMfSwGuNsumtX/jIIunsatX8rpipw4RoYbwG6jHjjdNB+OfFkJATWz2EjKHUQ6VeDeizNUu/A5ic+7QG2RYSQ5JQzqP/dhSH8EqpuMxlnvfDD6kBI4vLoJiq5V8OLqIH9om4oDa1IprfY9/LGwx5Vfi3mnwQfeoGMJx0P385tQJ7r7iEGj/jVJFm7G8c9/4oGMdyyS0sAhVqdg09XhEGV0kg1Hf8OLc08McVsd/LaaA/OmhlK/jTEe032DF88pwINiQ4jz+U2vpl3Ds8v/cqn8V7Cdbgck/hXi598hgfJ4Oudbwjtt/oNCqyj0Gl2Pc7xewOGkdXDOrwDdnmvR978DtP96FxiVl3H0kA8ueeiOzp6/uHPKZthatI86ZK8ANkxjg5nq+KE2iANPTMIx2VLw+eNythFYBXUnm2DZTzMcXhlIi2WQ7q4pAb+zyzBZpRCmLTKCpzG1oO0mxIYPd9C+8JMUFPCENM0dwdP3GLQ2LCe974Nwx9ASyuZ68S8JKe4XGYOJNiWwfLUVWzb74d+vP8lwji+Gha/DomQ1aBa9gP77bah2Ui/cHL6VZMrmsbbAICiYZIBYgiYtlzODzE2T4Xj4I9jtOBb2T5zA1vfSoKFRgmp2Ee5a04ci7tk8d+FulC1VgK7Y9ey09A8ETe+jkOiZuO2xI53tC6a9A/Iw4bov1b9dD7Ey0+DSiwR6qPeUbPoFuElAk50Uy0A5I40bJW/wcK1VZKOZiRlXRGDRlxqY+9yAxgZE4pf6NfT5WjhNqNzLIW3+YCH6lec/NKJBGXFotQ1m40dbMX7EO8geEQs10bYYvUwQtv824O1eX3D1Fn1qyFWDjqspZNKmybI2mniu6Sqb5b0kwYXZsGycMJZ7pfIMq7tYM6S7ogkHUFAwlHe76OOwoDC8Rq6833MW6/n8ggHDmfw7tgPl4xlipdeht4QYOJn8AqeIWbzx8VRaq4F0/F0E9rQVQKNZNc+0VIejjcXw64M72Sr1UP9zJ26V24ujjkSTlPNmHvsrkJb+ieC94cZwNCGL3f7Egt5+C9oz4jBPmLsA+2eupo9OrSRy5hm7LTxCEwyUQVxZH+4PsXHXSsL3yVpwaM1Isv/gQIu8n6GdyxCDpC1kBakpwI4PSOrAdPQu8Yd7TlPhdr0j5h6Moq+nXHGbwWfoglpWfDMKQn2C+WCAOciOq4Ptxh6wWG0ok8iNhuAl8fzQ7CU9TKuHc8FDnBe7iGQ++nGegjiXnbrKzrOuwrFbQvzGzB49pvjD0qQGsJwhARuEe1guxoMOFjzFvqT9XKMuD2tyX/LAxduk572L1rYcxuVPtcDtYzd9zLLmpvn74bzDSBR9nY+B4epYFfCKmn804rpN+7FkywQoPSpHeL8CRqbuQXLewgHz5oDyMXEQOX6QRGA+zjj0hGzztaDboYBzpZuoVuIcRuYr8Owl5/mC4hG0t6ljfVkJvJxzg5QfW4JtzXb41KzLTusOwe3HaZT88jxc3DCkaX7eVFqwiXPCe9E2Tx5e7lAED9GjrGy0nW2fA5yc4w1BNtswYHkCVY8UgorFsqxZbwo2857T++rP/Nb/A71cHccrTraD1S0DfiPVS21ui+mgZwtX75eC9oMX4GX1eNiy8QvJjjoARQ8+0KSrShgffZgslqjgtSO1eG28KuSHaqHZtRMwR30c/tsYgi0Z3Wgm6s0eCw9j8fQ6svveDJZHpSF5oy4kq1wkU90mnq0sTYeKT3LKfy2s3BTDTZqy5BCjSP+E9EB7/Ba4FCiLTnolvKsoBL/axLHPuB/0atlbUJ58Fz/mGBM4KoK400N+vmEkRLWuwYoYMbya+x/7zJXHC517ePuZqWCw7iEIZ+nCyyqdobyrSnUpO/jjsqVgYp5DGRqq4CjzC+ePjuCw4o9srGIOlj6+EFJ+DbruHIGW436wb/df3lrzGn1D+0Fl13hyfxeC6z+owNLMlZxzshj/uzyewpRm05I99lz1vJtErrZhoJUvS7w7yKElYhBzopPk/LSpwk0bVMNLYP2UNdSx2RMepR3BFrFJ+Cisk5STNCDwpQ/1RgbD+W37IEh0OXyY+grXJ86H9bld3PwsADObzClnJ4PWqirunCZDRaWj2XBFDWae+8MHLl+jmq5g/uLkBcILArFxuxIcvBnEDl2TcW33GZ6wqQqkP0zm5atb+VZBIv4+mE4hj77gtw0GsP31fIouOYR7u83RdIYfnBPKpSohIT5+q46khOphf/B3Wv7MDFoPv+R1JSXgbtuGWWEZ/CkunbrUemlY43P8dzAArAbscVKENigEenGGrDXOaFfk1L5sGrbUjqUDhdCm5i9fTvZn6+/VpOI4Clrvm9KqjMVgk9NLM9U9IaU8gjsKt+HjLWLwLc4USmk5WGpagudDDXY3fobbZY9xreEDchCbzv2G9pBwXp1eJZTj4JOTfOCeJcRO8sClrssx6Nka+jdGkJOcAxD2zkG97dLcHKDHGtsf052BYRBRfJymjFuLbduKwEAng7aKZMO8K5ZsXdyAkZq74YngJ3DWMoZVDwbJPhbpe3Q6XHdaASufW+KK5Cr0uOzHlYoL2eXpGWh8ZwSjOv6ja0N+4umvCaMy9XBS81PW+JGJq1P8wRiXY5htNvt+/A+8HRN5ZGM2fNq3n8uPZKNS/l++f3gedTRF0zLR1ZA2wQH3lY6GqmcjQPxhFo7+MRc6m9o57ZoFxN4rwTDrjXRtUIPr3Rt4lIIwCK3IROVcF/yePRN7/kzD+tNWICVSB9JyVjjucDOdve9CV5yN4VF3MhbWn4fwhUEskZ+JoVnnIaZJFnhlBC922cLJb4xh+bqRILhFD3XNT1HA8jns9uAQCbunk9QjVz5sUojlT8Nxmqkqton8B/jAAhVDVrCO0HkomrqYtksUsZfkFL7huosUG0OhzqcGJw7lutjnu7jtjiFYHjqH6lrMU4bfZ+s9x6lh2AqeP14e3l0MguiFpmClnU+XWozgyNyPPFt1Fl0WnUMpdU4MDVMopEOAF3R4URGYgWbTf+ThOZOW1tdghd84SBvnhtEh98i7+xIMv1mOYkL5NPkswrAZH6jIRo3Tr1VD5QMT0tuTxhvH5kJi7nGaew+gs3MAu9ZKgo5NCQlsXMqK7jGoPX853Un4CUnJviBAc3hGJYHz3yoK+SsA34Kl4I7RSuofFY8bxolRhaoZVqxuhVMxBvhM1QZftGXzJwUJUJj1H4o+lYBh6UMa8V8Jl094hDO0lKn8WjeZlN8EtbzFZPpOEq6e8IeBA6ehctCK976to6NSb/HcLzsudh/O5W++o9fGs7DIVB/sl5fh+5nXuLLwIGUXncXIuiLQr2/jstMN3Pn6L48408sPVphB9+sZbLS6j44/u0XyYh/5kK01rpL/StpLPLHS4RRtLLgDl50sAEMW06SSTt7luR0Stpyk1MeXaHX8dF7bl0u/3Buo468HjT8vA8Yuchij/ZPNpMNx6tbh8HBwgLtStrDOwmc49eczqopegnnNRrClpoNnT06EwpXTKXHFD84aN5I6v2wgmRwfnLxlOk//akC7JUyhXPAcNHqHwr0tn1jKdhqnWB8kp2l3WUeQcIPEA3SJPA7Kqjowfp4NuhmK04cz2nTNwpxzZp/G/kxN7pZ9BFceCrGV6QH6eM4Czq6sBdcb4rSp0QHdNtdSQ9R6KhN25Rj5/XA2SwSqm9dx0IgRMHLeUTpSHc7Jmv94wxo9WrG2Fu/eRhZNNWRRoTJySn9KrmkjQM6uHV0vmrPRjttgXheAZ9fdwY8CfRA9ZTKL/QrG+g3ufDjOHETV9WmyfzRfV4/A6fGn+T+9cxCVfID3bYuno84MM/2uwLifclASaUSeHnJobbqMytzn8R/VxdTvNJmPtvTTgvsL8Gb+bTzYIAlxAx/x+pFN8BV8eFWXHkhVf8PSmwZwInAAM4saaJylLosUiQD6RcOM2UEY5/keFEUY/I7sYUWHfjZr2A25VpLcMk0SM3WEoCVyK9ysD8KpDn9JNPYpG3bepBdj38PiE4r8alCJtvemYbGWARgsm4Mnax+T/M9VJFrtj8swFhYZn4eA5MtYJXERez+JUkboBNifXA/PMsWgMKiE/WusuaX8O6htk4KB+p/QsWE1JP/9huW2KnAwMJOalH5RarcCPq22YPVfc2HgkhsPWxrNmrstQLZlyNvuq0Nu30ryqz6Fp/Zm4oWPf+ho4VWa/XsmvruSgndf2FDrDGN+VmsGtu6XuOtZH04/FUqvvfogIt+dv9gdhedLQmij5UHQ+j6eNq+UhOMdbVz3+Ai6nH2DvsMngMlWKf4j+Zc/7nLh58lZYKP7kUceUYOb/9ThzcM/IFtvwMr3/FjG6ikbJavzmu/1fKCtBzqC8jCtwhJOHVDBapNJtP9xI9cVWKGoRBqktTtTrVE7DSjug4aiaxi1WxwijijBzFNe/Kr+FrUVHsCeyg/0pTKG5BbVYN6LcC7Nj8H9U8RAP8CMPI3E+OGUrRi+YRUeilAki6IpcFhsOXKDLTYeW0nlo1Xh0NEGMpe9ROE9XSRj2ggbJO15S9gQE4UJwDb95ySidZP+vZkAzcMtaXehJrQIHcbw04b89FQ0XH3Ugk49C/m+hRhN+ZWFGs8Z5GKRlT2ruXBuEmdIR4Ftxlwwv7uCLEQlofbgRi5Zp8o7nfXhhM8qbO64CTVPGVdKe3KavTLwjfM4770HrBiZR7PvjaeoChGoSjdHb8sw3n34G9/2HwCnvnpylz/LvRmKdARGg3zzA551fThIyOxHxR12Q+/wEu3Cx0KqRSYvHFgCpvtGQuv8jyhcdxlHd40HvX9xPOP5VVpQ+pBfhc5g73fNtMnyF60LXMHHgjNwZLMS9O4aBY7TNWjP6AAKeCMGUm/UhvKTMipmZbLMvzH4UG0UbTt8g/7PPVm2ozhqeh/XNASSpnYURR5dxVkKiynsXj2b7YiAqKbx+GWeIeTsaWPJtRfp8JcGNpgXjYPfDkLsDAPKij4NQSWbOf+XNum3jYejImNxlm4M3JT7Bj/T0+DoDmOQNfsGd0IKOUtjGo3eFcsNQ8+9HfEVzefsps9rlHjY2l6EEEn+dHwm3/HvghNCa8ni/HG+c90EanNPovmZNXT6RSl87w6DuNBL0Bz/A2PiA/mH7GTIdP0FndXmcP6mIz50m8jbfktivVUayWTJ0qV5DpAXsQs2FXlyg9YbDFwkAa+GvYUCioUmSQsMDzsHqSNT+PqleTD+jTSLd5yjkLLFOGPhFLBZcJ03L5yNexyCebWfK38Ya03VZ7rx2c9Ocj+pgXUXbHFEhgx88P/IDxcGkveVTNjXWE+LVcPJI0QENr98Az55xzjjdjC/lpwGbOfAeyyCwEH9D+icnI2pGZJYkjeNAyJ02bbOBUbNugtUPOQzk2ZCc+BG2jZTBJ7+9OSc2jEQ0X8Rv+jshoNltpCtq0G1TUYwQS+S8vqFOCRXDEaG/WKl5cq0Wvwt5TwW5b1XX+OTUeGc6CQAuos/kUfrRfA3tuAr27L4UXEeN+/QwuumU/GjcDxarfyLQTcFIcxmPUOwEmd+OcBHu95D9XI9ejRvDJYmLwRL39kA8nL495MwvPWpZu3RA7TN3QielDaw2L79IABCJHKyD1cZx5HNegG480cOur8q8vSlEhR5KYUsVpZC1697IKtfQhErDmL7h2Ogrx9BXtuHQZiMB59V/Q8OFLpz88N8SpgRBaHeJ3BHuyheO+OGjuHuFHfCErQep8GNY5t455PbUH7MD5z3qOCZwrmYN6Rjso6zuNBtF7t6joWXWv0wrOUznR66Y01DHpln76cF415jp/MKnDWhH9UibtD0LBWoWqCOnaGJYKt2ZchTHPBY+g+Ok7dnsbSn1Hb+EB18l0+rJWSgU+sJyBvVgM+4Izi7fz7Yjv0AW+MNoKn8NdUeXsoBhzPpjvdk2LGohDPDCsnjhh7/vGAJVXKa5LjUnxtHnsQexUy+aZpHDaUC8M7lCiirT6WBb8WYPFKHwrdYwXaVLxjrtB57YxTA5bMduUcIQvYWE9JsGQPmZ+aSf9ZumpesCydSu0jX3INmL34EtaITKKJYBy42/kDpkSFc4aCEZfeuk3ByB9xrRoiOscRjFt8pbHAtDh4xgcqjMhhRPIuK409QguIFalmwmiSv2ePLawX4u3EHWQt5QECbBuSs/MTqr/bQN5k+VJ5sCxuerYWyBBESODSVohsaeZ/vD/Ds1QfbYk9IXTEV91004K97i+nlqDwan5hE/q4eIK1bzJqeOWRxUQMObXeiY05R2PXRk741fYdx0ntIfpsax2/txa2v/qHv1AWsMUkBwtmG4eN/1Dutl8tkLkJeQTsrnfDEEU+3kmzwEwoV1SCf1ilgLC0Bxz+85F3pxjS1NW3Ie56DuYsk4sIoeuWpC8OTzvDxOGEQf7GIDKx3goynFVa4N+PhhCo6uXgsyl1fRCmPP4DFyznorKkKOhABG5t2cozFRlqys46Tp48jkxeEF8IdSXzaAQ7wieXYEfrgXaKFtzr+cWDZIJ1ao8wxgQmoqZyA+lEG4JdykP6WrILn02Vh4tfLfPWHEorrP2GxT6d5c+oNLO2Rwkz1mfzw6ANeti8IK8Yow8JnJmwQ1EF1Te6w+E4ZvapLRKX/wjBlmSe/EU6nzB8zGa9Ogkdmuixb5Ue/H4qgde5HSEl8x49TP9C2cdshZv1xXPT4HdrI64OGSiGIL93LfoXxVDljO7usekhq2k/IrW8B/tm3hu/NLgHFT6YwccNL7vP+yP/NC2XpJcMofeFtWruWqe31JIqP28SJTy35yhNVcKrsQOdSV7pjLoXKoxTJbp0D1Y5v4/3xTXC74BvuFw6B6Y9l4esSazpTuxgfdi5DB6/hRDklPE5Blldk9fJCl3s0r32o/+1mcLT8JonvD6F1JzxQsyMdT2vG8Aupx+iU/xnXd3rw91OKJCUmBNm9xmCms5L/pG5jvf35+ORuL6yf2M/L/p7jY9wKqlIrYOJ+DXivlUh/ZhznUx0L6EbKN7pZ/RhezLoEC+4MZaXh+2nyBBlOHfLOrqIJdG8ys0zoRp4XMpwvt/4E+1ZFSAodC8L6d2jS1yDMe0uQ0nMU1Ua5oGFoLXj5SXL9tmJ02GwwpGnBVOnfCCLPD5LtSRE4LBCPTzNvwdrNe+nwGqCXNQjW8/fijbZA2lFwAHdMnMT7TxtBiX8CJaldoM6rSlj8UAiULdeQnsxevBC9Hn30RpPGqcO0fLE6bBx0J0GJp3zs41V8MPY0jrsghit3S1HUoDN47iig3MUmnGIxCRI1VoGxgQbX5EnDwLA1fGqRP886b8un/c15Z4IKBg7MoFU/hMH89H2+GjeDexsMISQ1ADQrTWFhgAZJTvWnmc8kwPvlSJTXEoXk35l0K2A/Hn4YQCe3biPVUkbLbbbYcq6Dz4lchMIqN96wQQxETGfSKoVarqpWR4udI9msJInP38olw2kRLHJ9Oyl+OY3tWwkSgsphmK4iSKg2wVeHR7S+IxH3FMti2sSJuM98OY7T/o4H3TQh480HUn3TxlemK7DuHWsuNIwhh2ZNjA72xo9+s/HdolHsd0MHzkwIZudDghjvW8HffM7TpCk9kDfHHnXqE7ilcRNVrA2GnRf0IbRvGccX+pOm31yInTiToP8SZ66bxHsv2sOns1F4YvRYNNfXAQ9NJZRQtCeT45/oZPk6LOq7h1Fji6hUL5mvdxXDSdkttEhEAGxP+4Hqos/4TXwXZ3ZmcZhcAd28ooK2/JSmL//JpxvN0LBKDbK7/vFSSTU8V+ADVb2z0ce5nr/9t5F/qijR1fuDOLMkCf8zUIRVOndYqvIvHB9+D0qnB8G04k9U9LELqtd+5d9xeTDaQRNlNk4G2zUmWJ0TRb+3D7DXhcscbTiR7O/Z8h8td3q34BQcyhAbYgR9mF7qjY9Vw/Gq83PuK91L+s6u8Hq4KL7JLKdS+zIOqYiCDDMj+PxuCoSYfuP7pqX4H6jjcokfJNZ3mXU/dlDZnfn4acM1OtRpAf8kt9Epu3YQnbGGJsnZoYzKHPjoIk1Ll4wFuW8NfOd0GE46KgXzbO6z3bkh3pdzxUPObmCuFMDaRx6hpoYRv1TMo/l3ftKcpePA9vF7eH1MGHcdz8MzeqnYsGcPTU54StfHxODlXiXY+f40uNzVBPeJD3nwZCCPavYGsyXT2bpyM6+7+5jvSWng+5Rmik45gaellGGK22/aOSIfg17mAfzdhEtTW+Hvi8ek1P2KUzcEkFnYKdgZLQMjz6hSdp0L17uW89ULB/lB+DpO6l9Fvd+nUEGNDqWvrGbRuRPgyScrtm1ax/F/yznE7gzlnxiB6uc7Od94Mf9wLiXdTU0oXKsASiFL4cP09zTikQO9Op2LzibpdNUiDV5elsH6VOQ9a77TxlG6kHJoC3r61WFS6z4OgUO4WXc1HZr3nQ/kDs3YeRO4Mv0J3ZgxBkQnjYTRVx1hZrg1GRkrkGLnEG9ly0Pb5D3wu62cHR5oUJ6oGiQFX6REx2rorHxC2kHfeOnQDu709R/KqP2U+30X/LaXI/WbZqA4JRGHmYpB2MIddHL1BVZ+bEheCaYgEh1Nf0Zs44JV96Ey2Qz8U0P4jbsC9799R1MvXmUb74ewduZzTriyhuQb7+GP5Wq4U8IS1v7NgaWz12K/WCVsGNzLBcm5PP7bGjqhtIoyK2NBriGFRmdMhdVVW6nk+AxaXbGd7rdFQfbWlVDe8Ae/ftTF3FX7uTK1EZNrCXYfuwbfckrodJkEnZnygS+MYXieLsLiXhmwPTcU/5QeIFNXPdgqHsnFJxdBfF0Bu5VFov/unZzU/ZPzBFLw+Asx8C4IYrFYTRgvdQYyPYuoQXokrlNK46CToWgvPhdMU7w4paMPCuolyPKHBBjqjIFjnS/51r1d5Hn1KGvF5XCs7S0YPLYZHpUrIenZUaa4HBjO+fs/4s77LaTHfePPaEhbtEvRHtpDpaKBhnoLRUVFlMwUJUU0rCREhRJZlYgoI1KSNElkSzYpicj69vkrvr+fc67nnOd57vt1X9c514GGPzvhRcocmt5py4Z7UtEqXwLVH63GU0llEDKYBhJsAeordsNycWPKO/cDQjM0GG5H0JReIUwoXE2JDSF4/u1/EBYlCilfFsJg9iwsghh8d/o8tcTVw5SkANw31H9Bb+TJh3vR64E5LFe7ikaR+njKKwpPK06DZ89k8Ol0SXj3toLWtp0h0S5FvNYoC5vRgFxCLlKMxXwa+aqFM6Z0kZy1CM1X/oKt8sexr3YbfV2mDOPfX+J4PSNYnigHX2p92P2EPC72bIKKY+Hc9zoKHVQSWL12PKgJWZO7ZjkNav0AzdiheS4Kh3H1LvjBO4R2NU/g/MlBaDRTE56kToN5TuL0Y0YB7jFXpqID4Vx37SOlnlgKY2NugUxZPeXlqsALtWrufmzPZx8WgFhHGUloVMD6/W7A/BIDhzxax7OMGw0kILfImb7fu0fNT+8OsbkSHvB7Q58sDnDpzSA+/MsSGqeEgNjocXCvYCG6XlmEFekGtMPeAzxjHNk67CQu05Al+yHNNP+dzDlkD2a33TnZ4S/JuqixZrIy3Wj+CNdmmNCJZatIO7cI9bVH09/dyvBPzJkkv6mxSuMyEn25iK58W81vbL2o7IcFWxsFkX2sLIaE24HuNkscU+YG712/4sLFfhDxIp2CVjngKJU8Wuc9gR1OXEGhcbpwrPkG+Y3cCXEbW/jTz2x6fEOD6+YyHF4thAc6YulrzmL+7GUPo73mw5mkndgguh+vSglhUq473znoBtp7bsMuKxGM7N8A2iVi4CVygGU3q1Dqqm46NCuIwPwVLA3zJrEuM2rZaIqPVXrwQbk4JOh9p6qnY8FgKAO8KhakLMM11Pa9mwS70lDW3ZiMdtbQ5P0a0Lv7OshvcsTfU4JQz2gEjnx7jfMsuqkt/CuFPLDEh9lSLO0H8DxqFmolPMCgB/f5EUlj95gWnhMzgn7cU6Z3Ub1883g+lBoowEsHPZ4c5k/BSw/yMHVRbjboYP3D9nzgqjw4ytjguF2+rFojDJpBN6H7bzx62GzFwY5HdDo/mtBlOkdpvcPBhZs4YvR07lkkDl42snTT8BzS0nPY3XUJOkaI41uHMtwvKIYnOZW3bGmkmz7CIDhtKc7au4El5tvzwgX+uOp3JV/Ui4DfURNgVXU0HT3YSmb7GD5HfqYP9Wa8UjIBd0S3U88YWV4p3Mj+0xZQj3g7LPn+E7J2GMNHs7n4e9ozPP/mJq3SaQOVz0k88uY1thMXIuNP68l740pWmy8LE++YQWZ4LFkEXwdZrRY0f9CEe2810SgVOVIsmMvy5YvovpkWfDs4hZ6oifPJTW3g1Lie/90S5FWrwvC7lBcIWO3HWr2Z0DleDhIPjkDPi80Y8UwQN5nVc9Y7fx5o+wPj79rBsQc6pCs4DHKH5mpLmQHum72BT1ruJ0V+jLbPl4L5EJO/1T/Lumfn4gqHGMJ/Y2D0s2iYUV/BzfOOcmXfVg4zGsAvCf+h35qLJHmgETS8DejXghEA2l0gGp6OjRLfyZTPwrZXJ1jQuRBFndZTfJY9KPFisteyhWm/PpGeYjlqtg2Az5/7kK0tjNuXyMF8/T3sYtsGQWkP+KqkBKxWn8zSpQb4Q/knXC4Ipo7KCtLO2sVJRqqk0yxK/G4lZW+Qhbr7S6kmQY0eGfqzoxqgvnQhncysRdOlW8m0fAVc73iG2q80YbJFIXfH+KDKcQ1WtLvKH5YrUfhHK54XaweHvplQ5/f/aJqxMGQcCsGbZ8to4GMFfuttgG9WjTDSfj3c31VJd+WWgPu0GWyw1xD8B/up64waRhy3gHtVTrAptp5Ft4bxUpci9PuWyXuvNPMYeQmImqCK5Yvi4MxcM6r4Gojbzct45NSlUJnsQd41B6DGP4MUi5XhbKADr9n4HV4unsDGQmUctaYTF71cxPOlHHiU9AT288qlgO+iYP0MKSAmhQT/S4bTa7so+ao0Sbj5M7ytZTvL//ja3Bo+WzwKhNcVUvVl5PC1Jhz+JpDWqXnBcpGtqKStSM25CliTupM1/5jC9LIaHiH1AvclX8MXM2eD4LJvtPW7Gdpnq0JwHEBk9xb8ajocqqYUgvn4HWj5NBNzMy7RB8+lMK1YjUvuZ4FRwyduWC0IOxqUwPzuTNpPn+Bxwy88J6dII1VcsKjVDl3mzcTLM5RIWf8+bElUh/SPq6HJ/Rg2tHqQsf0HFBM5xdZxuaxoH8TTuqSx5LczbckfDytPMQrxG969y5YmnSri6yOSqbksHyaGBFDhSBEo77kCMiaCUPZzDQxDY8jbEExfLVMp7UsZKa4bBm8n1uOKUR+gML0dlPeogUbcDPZIr8eHmj18eG4a7Xy4Gp+3OnH1cG2ISu7iBS0RoLtOEfwtXnBngDUsU5FD2x0NnPT4PrSOl+fP1+2p9XUGDUI3fxqlARlqfVBz0gIepPjilZVP8JTuOezJnYdFCf4w7MRYOtI4Dfd9VwEljZW4LiWeb7WPhVc6R0n91FaepuhOY/bdgqhVTrz7hzAfayao7NOglDWy5PDdFjtMjpDXlh2Yq3+Zrx0zoJgYaVrpeBqDKkVgnVkiXRLMY5c5pWBalclrTyjCv57jWHgsBeYfPsNZE1IoXkkEYizL6LlkBHz5mo63Wq9iRvMmjrG4zcdPrSbxWbfRQP0RZcQaQb2RLW7IKOCg8lb43SIJx6/dhLmHiCSzvg/poD5tcdLndhSA13+M6eMiQ9i9+yKIK0rgsILHYJQQR1PoOghmuXPYgyg2qh06boQgiboJ0+KAfvgsoE07wso4V3gtWrq7YkqmOaY/HI05M+Sg9rA7utql40Ispo4bwhCTXwF7zE7wel8DllQ5yRUr8jC+WAESFqyl9y19UGF6jSo7Hbj9eit3WrZy2cUJaPb5O3Q/2cDrmobWYNgHNJ05EWIdfsOsyQ/AectD/N+nlgr9KdSd9AIXOs6B9mhhcC0pAAObJEp8sBkGxDzwt/h52uljCG8eX6Ue14XQGCcAy4Z2wGzRDlw2dxIPhGThts5GoLIYFr7kSa/c1uEfQRvs8xKmhZMR/roVgvYJQ7pdlsGqCWOg+us+mnu+khZ+smLJ7KuwuTsD/PdIQ8DCZfzu4B4Y+ZVQPPQgn0pIhg1Jl+DCNBVc4/ccHoysp6jCsXDr0TEqv2fHW6seQlimIzsabaIrWv9IN24pn2gb4CDDnyiRrQyOV2uh6HsKBRTq8+5FnVSq4Aon/onA5uPp3P22jdU8muHYXgIf1eOkMa+LazPa8LWBM/2o+Aznwjag5WQ/3vjuHR452ISOOvYwPt8VrvnmgewnVbrXaInBantBwKKZvD8G0g0zF+6oWYpaFwhuaMznka7KHLPrJ94pn8EiORuJrgnynb5VcKJFA9X/EO12F4XnXs8oIHkYyrjlkIbDOTa9lUQRf/aAiHsgftRppVnHp6NngiSsl39DY93ugM4wV3i09A9rBc6Ex5JpsHr6Qx6xx4yFZmTimvXy8L0rayiLnSGpUhWIfBhJ2annQGLJC3o9yRpfPv4PNouMI53HNkNaFU77tT/ykZNl+ONgH3RuPUzGEiV0276F/L/fQ/Fb9TRZWgOqW27Dxi+3+E/nJJrQfAYK7oTj6J69nJ4XTjnjtfDrhKu0cJYorPhej3e2OlLNr424W3EFSMYTw7X3rDF5McRuD+FGk2C28NeG7YZHeNUpVRq8WMttw4/DlEXeHBEWQ3Wdv0B29U+Mj94PkQvEoUTiEEWMeYPhbu5QlbEa/4begX0rnWhmaxxHdXdhgnQwGEYJwvbTb/DPU02Kptn49MgjXv/Zj2VHN8A559Nce+UDPt//HLOnOkDbVlVSfToMn5MhkFQz5AT+pn+rDODfbSfWq2njAZGLuF9PG9paVflk3Bva2toCRk+/4tH3QbAsKBn8ljyBqYVe3H7WAQPshvyodx6ZjPCFhGMXsaquAIqlHuHFY02sbPCMP60s5aOHR7DMZlGI3puIs7tMOUBuP18c+IrPfM7jv7DH4HBgEfSZn4OvhQ857qM5mP+1hyc+z2ns/RQqWCvIayQf4eXUDjaap4a13uZkKPII00cqgsKcLHpqlUTR70Uw98BWNjinTtYrbHnf52FYOUsW1bftoulGqnDx6ki4ZlDL+y73cvaUuxi/YR+LBcRhuYgdfoTH4HJ5Nf3cZAWbOpjvHPsKj3/cw5dmyyn2RijMf9SA493EiNMS+PvNWvLuMQVhu1c4MX2QBZpTKFRvEQZ9aoe1ERm0Ym0HqHaOIaVGY6wxkwEtwS2Um7MTPexXDuljJlgnmePmwHhumVlN7kELUSFTHoYXDIOL0tm457YETvdeBLN/BbCgYzvo/l0C2VLyNEt8DZmJuMAWQ3Pwm6qHEatW4pTiJ+i79yFqBwuwpJUvtQ82cXz1LfhwTxenb7OAOTv20tbD+ZQrUY3VJTWEG1So2uMXsdgpCPKO4sYXA3Rk3wh4MVyYLqi/5s0v3Mgk1JDTqgZIxO0RZhUyHs5OwnlfZ1F3nwwMTLODw7rlcOysLk0ONwLFX8bYsNUE3n1/g/umP4UJWXbQf0Ae1piu4dmlGaAknIwrLdVgkZc8LXG14Y3tDTj/WRCz01hwKzKFRvezVGWazhurMsjvwEu6cuIGhwyd45boyP5PDOHJxwNwvGksTDYMYL82A9R+oYQx/90An5s5IKSVhguvzqYsCQ/qOXyVz4tbgkvBI1hr9gUNL16EL8vVh/KLP24IdYH7w9+R+LQdHLBvG5ULGcDaF6fAMOkK3gzOxtoNfjx1VCJtOedPXudKYNZgF1Mc8o3eYRC4qoB8H/3lnHW34FLUX37h2oPXp2rBnLRP/G7ccIxZn80hn2TgiPVhqEnehMFW1yFW6SsvdHSCpoEItkoow9rV8vgrsA00Fo2G+2/cedb8b+Tmcod7DvqC1P5WTBS4imFBUrDb9iIIz4ge0khVSI8iPni5GY+dGcZbL2bT3WuX0CR+Lb9Kegvbpu/g1qpo3J06Bt4JX4CWx0rwJkgTg0fupc4NDnBxbQ7figmGsTlN8Cu0h7SShoP3psOgP/ExaB0MYe8ZK3jRomZa3ref74wLw4s3UvDRJWGonKcPaR/us+4SxKMjDPlrgCoHTL1OGqsEYfWiibCjbiyWeKjBbUdxGP5YlJ7PSMPzDjcgNuUT3LMTYvnHH8B2+FRQFrfkla13+E69GrgnReOJ+CmkYTAJBFcjDdfYiJ8EPaHq2jrq5wmw4p4MDzbYgoi9I7oLCOP799FoH/YdQspN0TArincl1LO7hSDy6hPsUTEBvIsC4OfZ6ah1vwEHHr7hQ2MdwMtXELyfz4IRdz5hY9Z5VDXQhinmR/FkkAtsr8uFgrAugPQX1Nf0Emd1vOVzX+bjwfEP2QsEoTBtIX36ms27jr+j5cGj8G6+OMjcK0Ol0QcpdbML0q2x1CFjCRZdKzkwRIeezE6jhrEtdGvHZIgdlotpJlOpz+wJmb3ug6aFUvDrrz+IPdemujH7oMLsJWjvq8TQW42sGT2b+sbU0bQ1rmyZNB6uvJ1JO+xmUkblRCitEsauBXfg2EpdygjTBD2jHC6WzaAYbWGQBwN+WLmSvnuU4geblzR9zUyUubQO3v2LwmsqtrhYNII2fJEF3RXroMU3EeetvcfO2do4uTmACh4/on0by1Ft117stYlnhW9ScMTGFORkjei2YhFGNVfBvSH/3LRRhKK33uArUudRtywP9vgKwfmSVJoaLEqK22IxMlIGVsV+x1APARiYtIcueR7GZRrdED7OAD6dq6CLz2M561M25s00oqxXIjC3VpW+1V9ltQk5sLo4GS6+NoLaRxUwVbmfpyaqUOFKff6wPY9L3ulB5PULVJ4vy1KG4pid6ADP6zbyb6nt8Pzgdp536RLeWPYK3PbfR/PYWjDeXYz77+rB1A96cH000G0y4IrKKhJ/IYqVbUH8N2kY6b05i+WzmnFKyh86LKkHz8P/Azs5BfLWqIad87fAyJ/raY2QEmQWzwPL2184P0QRqpWEQXtwF00e/gqcF//m+YNVvHtyJ8fXm5N+YS5NLd8MI2oNOK5bBmTam7hROADHhz6CpRI6KNp9kbc93chin2UoKWYV/1U3wr5eUfATFae8rYrc7Eu460sNzJq6Hf+4NtBX5xyUXlNMr35KQL6KDnRtKGWLuM2w1GouTPlTzfomEhjReA/3XRABhalNsG61LSqqCMGTyL/0dckXdjk2Go+stCPvsd50fW0lKHkug/C/+/CSSR1arVCHRONaWNF3D/Tfi0K+2DluEDoI46PzeI3hbGi/1Y5JJjackKsJN8UMKGFYM72VTUPVkCLGbYsA3w/Hvr072FXGlf3rXnMSDNXXf47KVmwj7aFnMBa86U6zLBx79ZCEg6aSX60M1i8I59Ixo8Erbyokf5kER5qXQ+7iGnIrrcPu2J0w+dBP7t/3mo5sH0CB0yNAj5fzu8GpQzXLok5TCX+a4oCBFXXg9rYe1LuZgzRyMXifKaQsnE77V5jx5KP/Qdo9R/y2ZxX+XL2NAncpcZGdI08KfYjFslawUmQlx1a5kVxaHzzYq8WTplzHSWKSJKocSYuLlXBn1X/09KkiHH6xCtIWfId33lpcbHCZ/F/GYndtCk8UCETxSA9+NviD4gTVYVimEEy6eoLHSSwjNouDPwPfqcrnCgpG+8PjOHsqv1LIO4/rgNuhSPb/mwHTfgSwYYw87Ky9S5HmefC2ZBWcVsvg5JbNnO6gDpvb5sB3h0q6G/kORJvX0bI7Z/hLXTX0PB/ObcrKqCefT3l37MFhZiLtlriO011Oobe8FD4wuol7bZr4mx9RyDQHKpUPpPa5urB6XzaLTLwIP5rMydi/i4pUS8GgYTZOK0/Hz0f+0O0LTbAwywY+vbjBSc2LafZNSzodtQUMrg2gj/QpusrD6di9/3i2QQBdsZGECkF9qrv8lgc338I3GhGof7CVpwdVgoCfAoqhLh3OyaFZEWLgfskJj7Wex68/7/PYuk6aHOWMyhdWgHefIpy1zubXafe4+vkI+NwgRHt1J6GGQh6YeHzkiKQ79Kx5AxWuU+JKs/1QVOoFUSUIa0oSeFe1B/dsf8vqeltIOzMGOP877fo6mn2rJOnqqEzoemwI8+p+8gw+R/Eb34LblVgsmZYPW0f85roxb8F+twBeSKsHmiIHmgrb6OHBagxVP8Xe+jvpnLs5Zuo20R/T96ytsoheD7dArdEasKP6B468iOS+35pN3k6DfksJKtbMx/YpHbgvYC3717yk9aWa4ND8hFOOdIJr0wX2KBLl465hpF9TRh+ubWWT+xl8uE4c9bYRVKyx433JkRz24S6mvl9KYf6FeKnRgjp8z9KfImf+sHgNDvYZw6OeT7jeowA7xG1YYJISbVDWpqadrfD1ehi0+Ivz2zMWvDBRHCamWNCok6IcsWkoP8x/RK//XoJZe7NZ8M04aogX5F0OFbAyZRRYyBlRf/VOuNJdCE9uxLLhTTO+sLcXAteP5UC7qTxlymJunCgCjVJmlLrqK9S3fOHt97Jg5OIQtNzvTK2N7Xg6P4K/LXKF6bOtYMfCQo5d5cuZZsf5tk4LZ735CFeDZ9M+yUR8/MOTbLtFKUpTEBrWJ/D05xeh99p0+vKznd/tXAYZI9xo9oyDbHntAEmke3P6ZIZiHR3Y+9mZll2Xg7b4Sr69xZNV1vhSeZsdnj+rSdt0vMAj0gKiy0yhUOcZ1F6Txzw7Ye56OYOu5d3GrAlemLboBr9fl02j07XB1bOK5k2IxBOlgQDTw2lfB9JUiSiQqBej2Mui1OC2FYzN9eC00DZY53aBxkWlcfvMSnx5yBcyqm6zwrEu+LVNlLOn3aK+BGvw+pQJ9j3m5F3YQi11A9QzkMC+Q7zx2vs06OekUGu7KzzIk4DgBcd5rmUvuDSMw+1+lRj+Q4Wne7Ris2wWfdpSiw12L2G7vRqYn9yCh+b1oZv8YZ5pJ0Encjbye91vUPFVlENOraQH01Lo8GZTUNf+hWtWBvCVo2M5VKyX5NNkeOlBL5gXvopXWO0B25frcdKqEdCzMB/q6yfy6y3JMGJlDk2ZpoFp7ln0pEWHDj76SzMqhTD3+kg4WjoWO+zyYFveOP7Bwax0qg32nNiK1XMOgN65hyR7ez/n6FvB3nQZOvahjDznL6DlJT9of64COXoooFDzXLqpcZ72z4iApd5KUHjsB8uq1oDktFyOvv0JHy6UwRlBkpjV7oE5f2pJZstN/s5ycCzBHeKvh9HqiPFYcL6LptqfxTsGfWx4KoHH1/rCtg2aPMlAHbpvR9HAFEWc7CNFLss/4FTB0XxcDUk+KQ0V2jxpSs96eLBKCbC2hEy0MlEoA2lz+x/sbx9LqglnccIvU9Sx+wD2ylZ8vt8SJpWG0DrvbXSxTJV8as3YL/QLPFP1gci7eTA4LpgxOh/619nCBGNBWBjrhMtvEBQMVKPbGQNsm/SFHcfLo8RWJRp3M5dHq5mBqk4JG29yR7mdR8FXfCE/2Z6FM1/dRo+ySyDqHYMSdwtReuME+FKczxPnN2H19Ug4s+EfXi9tI+Up+Xjh21IWu7IRbx1XoPsehnAi4jV1LXDFi8OtacXJPjq0ZyaKHFCmG8GX+dzNRsIHlzjfQwTURk4HW0sR9Ly6mY57uHLPvBCI2/KcKqvt+e0THao/vRNH944BTY0qePjdiW8O60RzDy0qsQrHqqfNuGFpFmtfEOTsubIsF28O6StC+LKPMCR12GF2qT+M0buBK1Q0ebm8A2lVF+GZvGV0bL8W6Bn6oVTVL/wbNBz3Dfle4LkA4uefweH8TmadV5xcHgIZFwyh+UksZaY4g1h6MTaaTQLckYCzF99kAanjkHxgEgcfDCPBNEMYOKoIo5bpY/CORrxt/gckfofzGbmR3D9PgKIeuELI6GQI8FeA79dDcYHCXibZpZz8citYdFZAhJ02ZCZbw2ETJc4z1wBFm2HQlFADUp+fwZXGStSO3k6hdf70S0KZ3rv4whutaPBc9Q/lcgRhcI0LZd3cxCM/bkW7zlBouPsYTSetQtGnb2HEo6VgnXmBLwuIQtGxSK54shBLNjrBupYddODOBjx0qpVu1qTj3LLtZKRmw6NireHf4F+cHJlLFW8k4LCjBOZ+7YPTeT7wY0cQBR6+hDmSj6BtuTSoV2tz1EVjlN62B7a+cMS4ccQxZi7UWH8ASkoWQsRrLzgvJQI9d66j9Z59mHpsJkX3lEJ8ZRHYdS+AyjP3IdQmDn4X9PPk/FFgamXFZkOsNiltHIwNT6EKVQ9wvSTL4RtNuUHGms3hMAnGAZTJeYHDuPU8/Y0nK3sO8IdyQzgL+3Df435OPCWIyXWS4OxuBL13D7GM0VDm9rHlXykmeGJdLo5bpwpCjoZ07ps93Tt1gwanSgIdLeG3cQ6Qurad+u6pce85DZjVHA/+9fYolf+HOrOGcZu5MlQq/6FlPzqh1H8j20XO5KPqkqwQG4OPNOvAXnwY5vtEkmvIOLji/B+aJABZHLrAVqcXwrileui3s5glu2ygTmM2rLhcQH/kAVoPjcLrnndpmskQ89sews8620HVaxxzqhm8zguGvddXo5mTELyYdxRu5r6C1U53MXzjM9g+JoC/PGki7dBAKPLtxoGz5ahUMAFeLhGEzjAbfHvlB4ydnYTg6MLu6sMxPHUMDmofJ5VrY3jpcdOh+1Ji3/osTHYKhFHRV3nbvnnw6fIRPlPXCc0jXODAkTZ+Za8K071mYeCq6/A0z4f9F5jwgTc/+dusx+QZ1ormi+6w8ggRNPyrBN/kzfnep+1YMhAOy2b24IgkAYAJOvgt02KoY4TPpv3i3CI7SI5/wD7/vuDsE8a8dZ0Zm/9XzR8FAmHarp8YYpTC9e7rqcbXAgQlT9CJ2YwTVZVg0bZc8hMlWCC6AjxF47HAdcjvqo9hzyhRWNuGYBVdBSeyhkNMZyGMSTiCW38cAdkPA9Ax+hi/+2FPXok2sDQwkX4Y+2GEaB88TZGg3XfOUE+gLJv1f+SfUv+BN1Siy21RUFcKwrAHjdB15CSPSt0K0+VOg/IIWx449xiiRolTyL5DMLJRERbscAGJtpF4KC4KfMdmw5PbK2HMPDN4pGKFWvk5MCdmDjVaqEPAv256+uAl/9k6mb9fuDvEnh/BbNd9etS2gSODzWiegjofvykPmqfb6Nz1jTxa8DeV6pWwReEenJOqAzffr+XxAr8hQ1+RQotUYMVhFxQsWQPrLG3pyatXeMt4NgTlGrKDxiy6I61GKcFXybZQDFJjP9Gm/StZeuopVOzrp+IbgbjDfTiN7LFhA+ls0Hl5c6gn8jD5/hda8VIHVXYiW+gIwp4Me5RvXo2/da/y+71KuGBVKtdNUIL43O3gVGXP37vnY8SVJxw9kEO/c3/hjiPVKJI6DM0jBGmP0lj4/P05Nu22IqmjpXQvyRSObZemtol+5H9alEWzClH8XxQlekvDodzh/GdZNJkk/6PdG8eQbYYJ3Hh5E1zbk7Bg1xxyP5FBvcfHgrXzFV4wajzWbz/DP7Rmsp36FZ5dKgDr3dfSDI0oKG7RpustkqBvfZq93G5hZ/8/GjP3H6uCIR0aXQCzZdR4hF8DGN98TffyzeBHWgXtFUhmXGLNXlu3ksr4O1x48xmEb6gj8YJCbLj+Etq77aDKxxm+hfvAGVTDwAux+HP5ZdRq/Y9P3Z5BWQUVYN/7AoeNNYOB3G58ObuVH7l4csruD7SxrYzMP0awa8BbVHJ7T77Gq2GvrRkkzNmLPy0m8yHZh3Bd7ARqjg7lgps+VGUnhvXxI6mmto/XlqhA945lsM3pDKL8O9DpjqE5tgcoOdESXzZPwUXestRb24YWM3WhaPgBvKF7ixZ/eAIbBaehVf97dn+nDgtGB1OI/A8AlR/ooGUDqW/jSQP66K3hMsA/MhTvchIUOZcWL7CkmONZ1IlIrY7j4MvOS7D7zAj00yiGvlVZfEe0mjKbIjHhwXZanalAcw6Zsv1VAwgZt4aWX3iC39uMSH9uALlsj0bdeZGQdv4dFm7/jz16RaDpLMG/uHIw8fbF+8eecJ/PTCo18KeXZc/ogEIGn9CaB8Pd62HtRiVYXl7P/QLL0eTmLtTU1eJRfS9x+Ohwnie9i545ZvO6LyFUY0pw/2892PRVY8uag5jpWgjKPhPw0ZRu2idxHXqNPSG9YwlrGUhCsc0/7hUagUK4j5cbXCHTaHUS3KrG4jMC2T71F+TGetN/sYrg/tMfhjWO4dLphXjw5mXYYjqPe4fd4qjUaIgR3UIWxfZIkZLwTSoInYoL6EaDLLifZrgh1EJZyQd5xZF3aNDhDWOXBdCE1Wowsn4BZQWfhgIzEXi1WRHNncypwgToQ2EGjdafRldGT+CfIqPg8tNUkPwRTOcCN+GXtIWY6vITnYcuLN95ijuSH8HHhxsIrXUhf50WuvjWgtNiWW6c7EDb7uwmiXmumGfygWdZRkHOGFvYft8Axv7Ko543bXz0+GcsVD8MiVkeOPHeafq5WRrh0iL0Gd1M6ctVIE3QmlfollHm2UG+Ld8EdWND+dK5s2zYsJN9PS25/l4YLHotAWcHtFDOMATl960Cj9OmKK/0jHNy8vHYhRX0d2AEblSbybsOiUD+pBTY0DcCi1ZX8IX6aI4IiIeCC1noH5pK6XN6OeV7Nx19oQ5LdtnRt7y7eMt+FQaoWaOnpy2NPD4L7GvdQd3MA81yVED8vjjcdYqlqv6RtO13KbZ2t7DzXUusl9GDNx42sHaWH0ddqma9kYrgGekJgUXzSD/xFPU5vyLjJ8GQp34Clz0kNIhOpOBgQVgrIACCqTtY9XsipCcHQo9JLRpf7mVpkUpwk0uGGtwIB2RrwDnbEpyjnXnLmErS3pRMs/t86XzxbV5zxJsmiopAUcxFLMoOwxEZE8Bvki6kGJzjjS29nHEsjEXTM+GNlThqhMqhs8B7eBvxglaHj4Ctcwn3DytBmSFPmaYQzmXtCfzj7kuIEhBkmb8r2WhiIJ4wnQAxo4zBbIsujLP9jVdex9MVq2m8v9cMtpwkyAoe0i3f4xBmpQvxmTlg6fECWm/sQc/WSLa7cJneFUni1L1idMbzCDZpXkIzRTPQvTtIyuGCyF0EOgab0OrwQzj1WQDGVE9BQwcBkhv/hmQWqsGkFYJcavUT11SYkkfxDji07QoWPE+AXUKZ3H46lLYIWKLoRlVYWRxBm3+tgdNtBqTMKqQ8pg/WZZiSqdM9Dp75CONsh5iwQx7uoz3Eq/6kpLwGbn5HqHX3M6dNHOJL6b/wx+oO6ivtheIHBjCy04IsNp7ByeJ1QGKB8J7zsDI/jKtudqGE2C14fccWxfbYw/JZ/1Fe3iv4LLGEKyNVof3KGr5vpQo+a0xxzMJa7lMbhgPReuCm5MiPzCPYn6TZUnoaa444DpIjl2Pu1V6SO6NHJiiKFaYWkGEUCnmpu3iSynkuzlZEeY9cDPvuRZmXJdiptQ4vHFfFnCNmoB39Hr5XZKL1wyb+Je/OuYfeg9aPzWA+5iMufNxDwwPPktoBB4jtkuFnafp0S7CHnoaWY/q6+dgiYEPJVwJZu2AMrh4/nbP6CQb/E+b+VkkuunWe0jdn8x5YCAUTumGmxygUf+oPT0scack+S2h/7sa6O0x4vv1vOjc1ky9k6PPkvvG83XI/THXXh8OCJaAZMx6annVR/SQ1eDCrAUfO+oi9NvPBQng26qps5L64tRw/ZwQN3mW4rOTEb//NAhWvaZh7uZinZYSjms1W/Jb2gFrvWWL3WTHuniEDrxW+4fiEi5jlE05vMpoAYtbD+Ip+SOrMoWCVWM7N3sedfprwwbaGZUrU8F77LrIwdgSZrxFg//gE7/8wgK8O3oI7VmL8e7g0aB7yAd/xS/HmxC3w6lMGyRWvhb9arfhg21z8qXUZV34shBHP1ICzLcA66w7P85nPlb+cQcOqniILH7GG7TEWMmlGj2/zaMM1hAqVOpC6NQeM0xeCeto/Wi7yGZuaJPDF7Un0uGw/fRsTyK8LzUDUqBdiB6L4h6gC/9A4CTGn5uGlsy0sVmdCglu+QM7oh7Tgnx1slJvLKiqZeD/tChie7cWoUdb4qXg8lhjuYuExBM6aBzFMQh0mhl6B83fXgOkIJRYLaUBbvUL6PSDKdxbMYWPx97zx41sMrJKFZT8doG2qBdSqSmDr437caFYJqyf2IigcB8saKRTxsoelPTpwXeIn1jpe4fOmzSzmb4Fn5Y1B48V5dNsQBXdKE9i6R5I3jVEBnfPaHB13HFatfkZ31qrD01nr0KJMF/2GJdOnz178WyaMsgOk4U7wGzQuPAlTIjuGeMgODx/4CjN+GZDcoXy8//YvKRxj1K/Qh1ebbCHIsRVf93cwGRtTw4kkOuXsjInu6nhPp44/X93FMy4JwralmZT8fDE5fFVE/KlAg/Pa4Yr7elbJeM52Izsgr8eRmtYrwIGhDKRU9hBj51dDifJzCEvtx99CKpSStgQfz1gPeyPNwcBIAKrE98J9zS6IEXuMgTmuaKIhhOUxo/HEvnL6MzwILi80ocP3hCF+yRsUdM2HmRPN6eyFRFB//BTODfmx7OB9+LCyEwq9akDsixHcnKiNB5M/gpFALnyQLSKn2ZdgcdUoNB78CxW39/K75GX0pEsT0mf+xe68M/hU5ymcPraD5Wv9eVyHKl52yMOJosiBqELP+keBy7rdrHF4BKmqzKK+04Fk/FQa7+eNZn3hLDb+ogY2yr/gb6gceM8Ppt6li6j99xhYULyennn+pVOj+6DQcABmTCmG3Q/DWPiqJPhPCyKXfwe583ED5AYM0tVJD6kt6S15Gsly5PgWcr1YjweFxCBxihGYi7XQdTlFznMSAfINBMVj3VTiEMl/KkxwfVUJZeoKwr6gZixWLcK9pgKYmTGTVi9qwrEzM0EysYSmHuugpt/z+fcHbYhPjsYds8pxl3gbl+68wJre+eQwzBqh5SpC7DTsNtsFTjwaqgxVCN6eojUfftAbydsY2GnKqo7xcPTDU2pXUwKRe17gfHoc7JGJ533PKqn7fhS2PfNmZfev+Od7Bx+//JvXv3AERc2VsDZVCvoXCtP8Vmve+/Y4ZVSokFLIEZw7MQ0dd1jiRcl83trcwPzQCHz6Lw7lEC9+/zmURD2raf+tQEoSdSU7vU6Q4S4oXeTFrd9V4ZPCZYgMMcbHi/thzItRaHZPCM7s+4zjtQIxZso5aDw5FiR2qYPYxBUs5anKH/5MJw8fVc7/lc/uk3fCs+58eOF4CFaUlPGDgJFgsskadpnoofXoNtquD5RwaBfE6Y/lFD1DLIROfGOmgE5WstB0xYjeGBvgweq3MLpoM+WFjONJS5zRpjkOpZ27ODFLGdYfU4ae1QKQ/Oc+1cvfoPp1irBGdRSpn9SAaSWW6Pp1OnVxDbbVycFXz4eQ6P4NJy2zgS0zwzDOaSUor5WAz28TeEBgIggKjAWjXBnQvx5PT49foQVrJeH4tIO4QOoaibqIY1mtDp8uOIErxh4lvZujwBI08NbHSmjVOUQp755R+9sl0F9syYLTz9O4td+w7vomuLZbENIPLccjsp0oEe4Po/9084m790jm3x1SnHUVLpyQ5uUPNHjR0qH6DBygv64J0oPTqd/gJjxNTOegtn58+TAYksUmwi5VHex9ZwCa8dG8e+kByL29GcvrZOD+qljqiTnNzD1oP1wTFdsfQa6wGfhvVWHPyZ2ENT3gNFcWE/oc+HCOOea2DNDmrZ/xjdp8DlW2hlP2lni57Dxc2vcOelvSKNfUip+FPYMA6TUYt6YSHc1fQ5K+DIzHYVC92IuM04Vgok8j14U9INX4Oqq6rM2asgF8dtV9vPheBp4ml1LHe2NKXfCG02fXs7XhBv6QvprnNc+ETV7XqHixAm5q04OupDj6dcUb9vcfwQcvPfF3pjnMeCUDc3xi0DXjIPyY70X3dzK45u5n1YBofD1Us/M3a5p9nrilWACW/fUFk7TXuGnSeFr9UR/qF4pi/4e3cPnGLzbbOB1uNh2gpB8z0FlzFvrGLuOkohYco2QNCk730TUmFVyTpsOGZSq4SFgZGtX0eLDRk9LPK3NvyQI6Ps8IRBQu03qhOZSWoQM5RSdBd48ttU68hJfsa1F1tjXHiyH6DprCuE9HcLz0O9x0egtuz67Hk7M/4g2LXah6uIbGiJ+FvRfTwbWc4d63I3DMMxIyHwzgg/AT+NtIkN9pWZDf9W/8aZkSfK6u5L4dVgCzV4C8z13khnecd/QY8Yh++tX7C1wSz9Pc8jNUKiyEKy9KgekydZq2fgkLzf0PnV3kqNPXgfMudrLZC2/aIP6ZU4Y8ylFZG4Y5FOP8+r1w9MZZTG0wZDnbJiwJqOJWixBOEH9OF1Vuwe7twyDlxVOsXf8GTllsxe9DkGwe7goPkoTp2zpPTPodwKkPu9i/zgQOPlkGRk4OLLr/Kd7fsg6mDtrQKon1eHb4IhL5Xk0RaZ4Q0zMOBg9kkcLtJdiz8RsZBWdybGMBhgn2QvGHqfRSbwGcOydFvo5G4HnqLR62luP5g/6QdFAPS8ZJsmHmZnrw0o/uHz7OklrWUHdNEwILP7Cm82Z0KvGH2XGlcOPKZxy38DSuz5gM18zk6eKnc6gTOh7Whu7i642LOS8hEof5XYZPuwPJRHMUpt/Vxs8OCuwUsR6nFEnAayFN9H11F9YEVYPivdEQs/cdHIkN5hnffoLwzYc4Pno06q0bC1mlS0Bp8Vq8HZAIFu0ToL3wDo7ZcxhP6/ewgdhnVvBtpui56rDFORTjdonQiOoseh8/xNc/zjLb14JJyGbecFkYf26v4D3JdpDVfQCvR4XxhvpOXJpdirXnfDim/DCv61LDyC4/WisXRdO69cDPbD6cqNiCWc01fPbmGO7a6UOnRxmg1o+XOHOhG6Z1r0D/GFFoKLIgw8O1/DwuhkWf5mHCch2aKPWJ9pash5VZr0F+ZAuV+on+v/3/94HQIbi9Xpx/2syEDeuW4OaALvq3eB+uUgygsXXDeNZ2eYzUtYWWwRr8nFwEZdOeYUHkF9D1kmazjlZcvrKblCu7aI6KL3wcBzDcVY1UDsyAnpPuMFj8j4477Ga3mTGcHZSHYVN/wAepGOjSFwep3/sp730/9v4ph4s3tHHel/+9IjWJJgyMpJZn5nAtYi2sD3cY4pdSXnLQiaLvfCSLlBXsWGBHqR0eTI/KoFo4Ct5puFOOlSXMzBzkqU1DLHd/Ca8btwqF3xzhoDNfcDXWk9RADsqI5fMt9VGQr9VKBUkSnDZdEvp3/GS5TQ8pq3whrtfNgLuuglzecQ/F/BTh1dhttNrPGw5tP4IinYOwxe8A6tvZwJTsFHq4fCHfMz3J8yrGw2/d33Sp8iFvVz2EL55fJp11+pR9tgbtozTxxoYcChJ6hVWrDGBu9S3aLN1CVapZmKYyAKt/TeRV28+zqlUzX5mthxlCHzH6xkho3/mDM/TtYY7cZoxZkoyfLD2Yb6zEJpHHnGUtT6alj7De2AHS3kVQaZklxt7fA6J/FWD5aiFOD73FU9p08FLCeqzYOpYLpBXgxbIPODn4DKUGmpKd6VnSfdeJSkXHaUtpKMYqZcH5kzYsBGrwaEEob9wrALveFdHEeQthbaAPnhF+xh8Tv8LcC3vB3yqMdHqEoePSCJjUcIba6oJQ760zF+7dDs+a74C8TgQ8LBLG7VklPMdUFp6yKSSNzqQ7b7tg1d9OvmIZR8ulU+jUkVj8cScVVROXgmmIJHzdo0cdOt/pyEs3mGRgTXf15WG6dCEVbxCAlmVL8Mnxsag0YRgcLJ8MSa9vYLa+FQ4c6QXFwBSq3P+LpqscA6EHLiRzUplLNg2DzPYOaNUU4+wZPnACdqBf11Qw/LkR1xyexONr8kD06h4Y99gWRl1/hm4FpiQZ8JGWzL6O7X1j4aSqOD2/LAcdf+dj7A8hWtBsAG1WxDLG5uC02YT/rA0Fo3Ed2C5hBX6GciQUooZdHe5wZI4o1P0nxaP3HyQRwZdc6ixAsReKQcrQGp0OS/CXv9n0o8+WVj4VhXNL3/Pv4EaUiNhK81VP45i+kXy1/SIJbvJileZaUsoeRmcnjIfmfURoWYBffN7QMoORoFrvxU+sBHjnRw+MOf0drGZOpcUnEMb2yNOv58GctLSNWNgWLNtcwDfXHWVfT4Hl1dVwVWM93RyUBvhaxHcXXcY7EcmQtM8Qev8ux1SDTJRPMR3aS1muGp/PmqXK8HytHl0ymAlf/fbDubbfRAl7YUNsKc09G4OJSrN5zdNy9H9qAe/npiC6uKNbQx+dEb3BCbmDdGxyMiUe7aKypijImuuNf1uMITl+EUX8nodnG8/C2b5Eru3YiTvu1FCn1QQU9vxN03sFcPEiC+h0deHAW/epcfAzyQ0xlKmfDy3ZuZvdP+yA6ILzZOZqRdPqEUQ7tvK9tdFcHXyAx+uaYMmMRK6/Egb8+jts61tEs8urKHHPOKibcRgejFFjd7MMkkzfzOXbfg5xmhsUbhfirLxgLsxL4l3dtmC73AaNfdSwxD4D7Z7V8fLtfvRE6zF7Z6mz6u9bbDsoT9c/j4e/TR74K+csOS3aS7NnisLa/wJxRkErFbs8pd8/P2JkZQeeMxYA7VlWaCIWRv2DM6hacTU99FGDozpGILq8C9PPdeMvestpKmIgP+MgB+sup82pnpT18SoK7rWF+JhQuv7rD8pny9Jy2WNwm5Uh58JtfOpyhOauSEOZFxfo+Y1TeHv2ajjVv5BHbnlFg+fu0a6l2rA5vgTFr0iR844CXn7yACY6ikLQNTs40xDMoZpOsDcnlh61KMLnr4UkWqiL9HMNrqBS7N0+g+dW5cPu83V0ekEOh/53AaV1zWBt1TsUWhNNsf0TOOP1LdywfS4FrZ4C9kkzyc1xLFWHBeONoajUFKUNlcMjIFOpj5zjXtEp9Ye84tsr/mW6EkZbnMPt74243A8gYs8AUkw8Pkmax0fVP+PGngrsL8lF79gTaNVxgdyULEGpURfMG0eScp83eb9WggMjr2C4wiOY/K6FHif5whsNpodOx6ijTBGyjk9i1XsheEIgiAqXhpBWzCJccCAO8sd4s85Ja3rZvgGf+SnDh5SdFLTJlzRybkHSczOK6P4GSlHHuNzSjcetnEuremayV7IA+G54iPMEBvH57J8Q1y6FlX0JtODeHNzw9ijGFRylBKdNsPCDMByJrKCtuXtQc40G62Sqsd7KBjLMeAHPU4eze6YJr5vjiGMfS0N4yHn8FHUZpUUKacCtgjf0n4alsuIoZpMIwjO06IY30OgoMZjau4xjZ+4nh0e/wLpmPAz2N1CgkQna/PWH5Jct/Fglnm2k1eDG9COc+GMSWlyQQ1WVizSsWoomyr8mv5799MXZhXRuN5O+myx4XLDHqzYuEP81jL5MfY4umrtxp7QBRjaMpfIcX66tOM3S1mbQOXkE/F1bSXMPtMOp/aNJsryI1py+RivLM6mjbxz6tsZCid8EeFwux+/81Ohy0A1+l/yHBL4QbWpWRi3vUaxTHQAhmmNQvlMBcjcV01hnf+w2OY1Lc75RjW0hyfoLQuzE73Dw0Fd+PjCOgn/agY57PFhUDYf35TVoI1kMo/f/42U5VaDwPRyqD6njdY1QuFczDLJXjOeBXXuxzx/x892PwJsV8ItQCaktuogqTdmU0tlOElN1wNHfgLQ9XcH40Gq4kvgUn4adhH/7beioTChqe4ljYN02pG1yMMdJgWrqIjGpbjcfSvxLisNjKTQ2n6QSIuFLkTjHe+vyzWAp8L2gAQ//WdKhh8J8Z84tCh1/ie23Dwe18BlUFzmKTDcYQ+kDUQg0TmGUeoJtT5P4j/tpyLnnQ4JnPei8nyZNLQeeuK8QQneZA3QH4JRxoiwuZYrxHidhQsQMnPF3E5a728PGuqfcF1THtzSUoXDgDW6bvh/mqy4EH6nLlLPOkZfeGsQHaanM1k94f7gCWiyQhArnDeBSdI37N+pTmJEyPFghA72XDKDc6wMvl5zFf5+No/bPyhCYMgYv1vSRa6Q/zRyZA7nvl0CH0Cq4VnCXfOIuokCXOFbHCYPb5SoWm9TNum0xPH7mY5SKlCHby5I0UziGxtokMF+dRqtyJKB/ZB3W62piH2ehykMZyFtUSykZs2GTz32u/vKKf6zfQ6/+2MGI2FBq+PkZskOnYcgbczyn6gT+MySh6kUEDI5TonnviTPlhsP0lA6qym6FKXmaoF7nCdceJWNXywV4JWJKH24Dy6nu4aL9FlCkKEIRS+fTlvd+2DNFhVInBeHeOCnYGr0S18S0wRqPfGjKM4FVHSkcYrCJt24oALmsQ6g39QYf+rkIOuybMKDvCcV43Oa1NrbweqIcnNgsDb/KkkivPQzobh7ddFlLDa/3w+YDf9ntLaDn+jEAY27xz+wIPC3DmFH/FA7H9GFEKbHOk5dYn/qMi+SWgZb9aIjOl6KOutXQf2o71zg2Q/OTAhCaaIXxw2Mxf1gr6x3sxbcNNhBT2s8XLFp5dUg8tqVXw9xv7wFSpfDhg3AIWPILvJ1fc+IQ1zmlvICMOcbcdvo9mMWU8sBHZcr4Z0cPhg3lPqEqPuT5Hi2XK8CfuIWkv27IZ2/UoHfFZJZ134mLXhaQ0dT1rBguzf7zlmJINEPrxPdQusCN/04zYPMfsrRs+Tgef0ucR3SpoEmhLndNtqXD+gaw07CWzUq20bljdhz2oAV0R9pTa0sHXa06xf+cTPnGwlS0iROAnd6NvPVAPU2MO8mOx234boIzim84z3t35lLAljrwcbbg7JnScGdfOM9V6WWcVkG/+0bBO3cFuNpYR6+P6uPa4XV48ckwUHU0gA95rsj8BsQ3nsAT3oJ45sViEDvnzWneoTjnnxO+dpPF44PCoNQwB/YMaeYxu8/guriM3A+Mg0c/f5HWjg14x9maeivtkBUVoGKuI27xcgeVZ3p0uuYXHjEOpzPR4uAbXIE1/0fReYaF9L5x/B4N7VJpoKJBaZfSlpJU9shIRKIiPyINJBIiQmRWKkpFw4gkSVMioowkozIi0hT6939xXpw3z3mec9/f7/39XNe5rnPpP7RLVaALFlbQ8zWG+8++h+/8jH4JZ8PfCwboLXiazrwURGOhSsoZ8MZLJ8fBy4FGmCwihXazonDjr6dc9D4ZwUwYx389zEWe9vQ5s5QPVg+dV8KFL20X4NWKE+nw7Fs454km2qAD+z50o8keTlDr2ErX7IThS242GAx5gJpgGF9hSd5WK8nO6q3wWu4Ww0ZJHGe0jaUEBCE84wx8/tzOU+dX8uifZvjbaCMfu/ARRkwboBmGunzDO4M6rEbCq63b4FgckYy0E5l4pIP1lWDU9c/nB3GNMCu+F61TqrHrzkSY41CCtcFqwEOeNbozFWY4bScx6oF/5uths0wB7BFNhvcfxoC2fSXbFx3gG0UqOK0kh1aLPqMryevQrX8aBt6YTjLzrOG33zBwOiJGRuMbQO5nAp822QHmCVvon85rznZowZCjD7CsUQlm5oyHgBo7hP4RsPfXA0y8fAeXCFTSmUnf8KmrLIeJeeM3ESf+XKwML2dexX7ZJdQk0gC2G/Kg+d4jOjNWhVcPRpKz/XkU971P+36JQqrGKu5brQSbdK/RTbMKHAgqwKNycpCq2cl7igsoWtsDkmUV4PrcYfhBLJvjbCTw8FIvEF6zkR4W1tOSoo9QVeyJ4tmqtFxCFxo0PalYzR+bF6jSfPNaWnzMix64iqH7zgwao58IzYoSrHzPFn5ucYMJMeH4QG4MRgqf4L6LtrhoZwXFv0vAssJa3vGti+a6akD0IkPeV3eCP8kpktmSKXRCTAuzhQ+RwsoV+PDCaxwW7kr7NwuDNLXA96F7iTvdpDDtCKm4GtHVGXfpyPFoOHIznZ567weXYEGY3zsdltzypQ93/nLm/AAqOLwdVc08aOrx+SRJglR6UYhzWkeDnnYmRxZmgaSLMZTLhoCdgB5kae9ECy8J9L8dQ/cnXeEnG6WgqPolre5I45uSk/HbzFw+FKDBEVOi8IGxNWVGvuZhDtIwJtsEelffx65123DzpA8gbX2bVGpVge5uhpLKQDbfNhrEh57z8KgNLEs9ybVpUyjD4hk5Or4j2+y9fHOECxdWixM4qcHqKj0SXyQP/kvGwI/pvnBeeBOr1I2F5Y17odLrN938vgifXgnmk9/1SaPKGrJ1k2BKzX9IsuaUICqKbYYnIDxpJPekG/IBpXpKNleHKwEysNqlgrcorGSVS1m0xLmMeg94ksCmOBRrOsJ3St1xyvIEtHceBUldpaR45SU+uyrK4+5K4xebTzz47R3npGvjkj1bcY3zZNaOMwUbr2TunLqU72+2xwEBY34l3M5+h1dw0oJgMFf+hJpzw6io1g5+RpTix9a5HHZiBObjGu4ZVcgJsBNoG9NZ/3y8eaMKBTaOgIo/DrgzbTafGPzMc0Mi0WudJMm8GaBJCl38W6IE5F/mk/BaURjU+w2pwmUYGusDw9CchEbro6v+D46PdwW1iEV8+lgDxJQJw3/fW3l83Vfq23aIXmkbQYCqLlULjaT6hokY+2oJio1Zxv81acIxhTkY+NeXLspcgSyThzCp+xFOvxoOJ2aKg2iOCZsnJcAUIXPIPahCP84MYtzG06jQfJvuZPfCwyebKDtzKaidGQcb9UU5vwZAV6iepMXyMUlhKS4sOk6nlgeyYvtCPNMyhu6xJ/9e7Ycxo81B+cp/tPaHAjtv1+LY/a4851Q1r7S6g9M7DbhKcSWXZR2GamVlkPNLgljPxeQocIF23vXA1JMx9PCTFgc56DK1GsL0gLOw84IupA/7DjY/NtKOg0o4Iisb1jUns9bEoeyySYr0TNRpw3RLTg/VgrPKSzlCeRd6v/ami/vGDHGNO/vtvkUOmW9wn+dvDDinyqLihqBnwhzsHALJu4IpcZ8jWtIZyM16Q6WLV/BUmSHWHlFPvFEXyiOecLbJPDpwsI2NAnxQYMEM9rTOhlXv7FEqpROq1B2psFIJ1uU84Gv77ckrIBm6d1XzyetleP9uDhn97adM3sMXxa+Ds5k1RNUqcuxNCZyoNY8ubXhHTx5EUfQdb76zxZjW6KihSO4nPK8/HuY5t+NW+Qd0xECCs7ub8GrUFIw8+Q1HnF3PzRKDfK/Gl33dh4FD73ueLLgUW6S92Ov+BTRyS8BzM7/jgQ0r6PWiNEy6v5mKixFs1X5A/oZSVt+uyk7HJuB/Vbaw510dys4roSvB9dAoNgJXtMjBss9IbhHXoTlEm5/5p0O3bD7Ya1wHx+07OSamn3+7zkI1WTEAqee01205KfrO46vRU7j0pimNS/PH88F7YfD3LjQzX49KMUP1bQ3Bp20/eEOdMev7fYEJXwS5skYaYz0KUexVM5ytnUg+E8aDeFwba279Dfc0poPnOAH45KVH6dP+0LH5Cjw3zxeSDt0jk3IlcNsoh/+5f2bT4RJ0XnEGi0tfp6zRU3HL3EZed3MFFQ07BfmSshDyupHL5wWCyejjLJMkT20XK1nhyCWUvS1Kcys0UWlGK4VfH9Jbx2uWDAyH7i2zqHO9BB/Va+FDq8Jhi3geiradxdaO17A+wBTOPjzL/+4/J7kJ01HkZB6cWpMBdjKa2L09ljzt1tEu8sLcBaIwWvEglrxoJIHd9rBXoJ52Pham6PhWKP/mDhF13nTXupZ6a43g3ucpHHZwKQXbviIzszgySKyhsgFn+CoSD1qxM3HwSR8sfqYOGg6CdHftMezfZgfnEqegjsxYXNVXi39bG/lT1D1cMWYpyQeNg+3TX+HdD8Op8eoFMjAXwKLns4d4bwZ6PjnCqap7ObCxgx4IaMCXMD8qfaJI3U4pKBiwln79ug8/qr7jZFEF9HyTwO5HpkD6DoT3NsZ8008Quy+tY+HOIS/VNqSuRDP+KnceBN7vwXtTrsKkrwyhE5wgRK2Qzv2zwvghnTs9yUBTt2H4emY8r9fNZfMtCtDcIQ07fhWCU7IgbbrwEw1VR3PQsaukP2EpbVg1ltbem4NKpyLRT1ceNIOOcvsOoqMrTGGZ6xc4sloLt0m784nmLizaq4LPhnp03ghRKFxbzAk9HezocRFmGs0GH90/0H+tgo+aFdPrRjmM3bcLzwmpQcLgCcpwccPFixfwk92R1NEkjzHnm3i24i0SlPcbqoMTDdsPYPo0g5STJ4D2x8PoLRZHn1e20/H8j3DMeReV/8rhS9qaILbPFM7cv0cXTO0wIvY3P6r8j3XHq6LQJiE6fXQARz1RIUfrcHJ/qwQ2op+oUywc71/3BemUwxBVqo9nzUbDYQVhqpQLpnEiQuTdMQ7GRxijBXZT4N9z7HRGBBrkz1C/0l4+ZZtL52x3UGOkHQa3C4BjqBN3JXwYcpJPeENpB/d1i2GekhKtrrgPX+cbgNCMDaD3fhJcFO1knXXPqfi0A+4JvUbjPudA7tdtEAi34Mi3VO6b/hG7tWVhm6gbOCf0UVnrMhot/w5upDYwqR+hxlBVfF++jaymtMKpe+pw+fseuPJ2Lf6WCOGbSSUssnsnyVi5YffGfbjrQRk/e+kMP+LHwgn9Wr6rMZbu20+nFS0adFuoit7HH6UX/tEY7Lka6wMe8sFwQ/jd20Nvf62D/4oD8AAOgMLxw2h06BBsvVmA9XZq+OHOL5x1QxN6Fr2klT8z8cknMxDamc7rKkp4+ve3PPd5Jf8e70LLtv9jEwMp2DnPldaf6edtn29A0Ld1uGq7PV7VTMKAzedo6rWDfKHTDbqXGECcohyUO+yg5Y8+0+rFs8Bquh9LzUinN7v/YsZAOVo13AbR3TpwVvMm5/+aTUHOL9iGprGg8G04XXGR8g8fRmfshk9t0TDTG+Hm0wR6UDUdvS4gzL/oA1UTTvC9GHuUuB6LFxZ9552PIuhT6GgoMjaAQ9LFfPnWIN8RNEOv0+4cZ5SFmp8JOzb20mPnK3RwwXj46q4B2ecmQ8x7M7I7XskyDzRwmUo2Xjt0jutDvXlRTTEqbx4FIyrO4nv1HbR0eRX8mFPA3YenQq5DHI8JiKMN87N5r/d+slpsAHdXyGDDrZu0eZ45uGu2Y29HNnyOWsXHvO/jwVwlTl35FPbdmAB9Podx9eJ8dHtbSY423zAzZw2/V0uCS8fEoPTARFwhFgqT/PXh88ltMMAzyL8iGFsq/sGpoHj8o3UAj7z7BtcfWuC14l4+ryQBGzfkw5OVcqBhYA2rzaUxbeYHiuyxoTXJl2jc7anYq+aMyhNsYbNYCdRPm8iDjY9hbKYkndI/BJdV7uDmo1GwYFECits9w19KBFceL8QBEWX4CFPIZMECbG78w1fV4zkrrYOWPNtNCr8uo8cCTXAf4cS+bT30/JMxpOoBuWd44tZju0Fx6jGSUkxn80m78dwhfYjcfISPjY0Cm9ZTPL4qlh72V+Jr72V82nEmnVwdz+FdZ6DmriS4BWqy0d894BdSyNb2EyAvsw/2X7KlRw/MOMbEAXeNzsUGlIb5JRasNbWBZyg9ggOCh/H7pFxQv/UP9mTWkdzAXBqvGk8Tg1Ug3EUe9xkeZpMCNw4YvwSXqSuQ12RxuPhHHLuU5/FrMVfAJl2IdG6GnxPj8BTa0/BDV0kt/S8VztmL+dvbYGfxJtDeWkSOwyZBKeZyyYeFdOe+Gvd/vk1v16aBqkUG2cxSZkURYVxpWQqN8Tw0P3qoovAw5C7SxpTFQtA8dhi0D1+LBT/d+Pem95T1URaTftqAXJk6R9+0g4RDI8HYogAX/nEEX6k0/rrKkS093mB03w7SXoWwXfQcT7T4SHHNcyhUpAvn9VRR9ZKv2KQhSbvrLtNVwXq2WKUCC611UHLcbHCha2Q0ph2/fevn1686h/Rbw0WHIsFDrgwnH5ACiRWjuPzxNZ6d8BX7TO7SrlHLOcLgPrhuPAdapwPJL2k65962geJH3RyfUoEX2vrBJuYV3BN8i0c3jcbX11fQV4lI3HQ/jVLLh7Qmag2iS5xQpe0Ue5w5BR3pvuyRcg02Lyiihe8CKSvZh0KCrEHjUj0ePfkHTPNfYM8XJPPnU7haoRmsf10CnxERZCsvzyGjdOCMYDgavz4Dx1oOcPTiLWwcmgNnZNtwYU8h/d6RSrcWTIMtN2TBu86dX8iJsEaCOkWVf6U1jxVJM+wxlRT38fzTS2AwfC9+shcFm629TDcngNz+F5ATWMxutk749ttxjrY4B3feL8Fp1Ue4eS+AbcIfUpQNRZEsB/BdJspyq0qx4sM/evliHi5+PEiq+4gH2mxA5N98rpAqg0MuXZS9fSekbq1Bm7IvKCE0k594lsJwxTtYc0UeEoatADjkRcFVp2FviTd8Oryb3vSchSax/XjSMgjO40b+OEUHss6p46ulY2D2mgUwxaITMy6qgrnKcZrheIHOWx/h1xL1UKhpBNO3lUKnzGwe6P4Ot1RXoLxeM04eeQ7/fZxNtXrrwOjZNf68QhZk4n9DxMkYjggTQCtfRzScug9Vi4rgxBIhmj7OHWykS3ngrzjUzdMiyerd+O62D3fHSuCkUbfw8flA9nSaC88UZfmydgKt1hsLYyy3o9iFFFi28z0n7B5EKbkvMHPEXspNDKDbgUQ5Sr4wOUoTio++pnGTjuLRIKK1P4XwqE4MKC+zIe3FlnQosopdx8TR1qjxcDfMDgKbHoFrVh/fSE8jmVcrAY8Mx4L1X9k95iL4bglHnUdyMHPUHR5nX4XZ/abYcUAYSuzj4X6AHmUO96S4rwdY8eZx8k8QhH61+zhX8Bro3Jcj4VQdVr26HC8d18Iek0b2XVxIaiF5/KFGG7yi1uBvu724eWIwGoTlcdPDECh6FQ0a5/L5belR7r31j+RnWkJHF8PTlOU0NuMD1k0tprfnS1C9vwLlrjXD/ucnMF+sAZsdpeDKp/2cfsEWZ7Tn0bor18jthiMtcDoGbwNzeYSoHGJsCgueEofm1lpem9pOPya+Zc+cctYcfETX555lscQsKio5B7Pc7Vl67ATwkKmDwC0J4LlXG6VxL1tdDwTFybVYbH4KB4zP0P6JCqgpNAw+VdqAlZsfPTMZxiv8C/ipsh5LP8jnQ1qDXPZACP702cORMjOI1bYh6RdPqfV2Of6SSgbsXYvFSpNo/uImNujXpLD7VzDvlTRcirUEscguvK5mx9NSdrFoaQONW6pIsgEBKHagES/VdvNwSwOAUdtombkUTa1zpeUOKuRd18S31nlgkUYHrugVoqjXm7DymRQYT7DGHftzcJySEcs3RMIl1wXs42aLxfvSoSE3ii5qRNCO41Iwb/xwOhuXC4VDa5VV9LDp28Vc/Vcebh2Mo+BeV6gdGYixguPAJGInr9j/Cl28dfDfbXVOfuOMBvO9eJrDMD7dnkNJZe/ozOSJsOiFC69nP4y+ogFetSM4pmYZF+0PpTX2duieU4uLt6bBwaGz5qSoQkZfI9ssdUNMeUTJR8yodOoNTPJ6zlpH70GEkjrvk7aAb6NMceew63z5wioYK7qcrOoGWS/pPjRM+gxS+jG0pS0Z4qUBVCIX0fM5/XClBnnUbmRJKTXyzv7JL8vmkcD49eDXMw6eektBfdFj1Mw+jXKfL2POvAZa+baY9CzWws8l+hDy9ig2ab2Are8V4WpgL+l+rIDWqEp4pBqGj5ZOotGX/pDwuz+4osqAEvgmzh+wgzC5JuqIH9L+9jD+sTeQXfd0wY2FVXBmbBgGn6ilv0tjocpOCYpbtLhwRz6uk/bElDpjlFZ3gx+2b7llzg/+U+RG8n6JULLZFE60z8FcQSc0EG1D/falmL0kki+kh0OyxW048G4ESZSXYJ+w0f//S4zpnj4gu8IMWh3PgN2kJHT1kOLsvU6kvOgg3XgYCq7honAsUJkcM8dAb3UcXHjXylfbvWji+n5W9l5I0pcTIe/iV8yXYZhezSS6z4mWlz8Ae7n1bHWklcpXGdL1ICMWfOyGDlmn4VzeODCd94i6Bi+SSFE+u6yqo6fXxdjvxVxubQlj519FKKPzC854EGirXmGJtlDun14MyxzyUC2sgFfMnE8SZhmcV6JHq1Rk6OZyJWhPlGCRnq9subeRRgt0g23uGji+KQl/rd9E377+IPOGSr67RAkcM36D8FF/HJ/zlnMMkqDMbwGNcXJgI/tf8FZKEqYcKyWBlkkgXHAWLn/I4F97n7BULHHjpYk8+updPFtoCNG+LVyqNpu9RppB2O0zbBywCl2mzuLzacUcWSMM65dL4TOF8+yxoxUrklrY9tVIOOUrwWPcF8CM8za4+Lgu8J/rvHHJ8yFPfAONBrmc7/QFGqzVoPadJYx/MZu2eqzm+cvVYF73fLYeMYwPii5jt+8f+dHaJLpZIQrSuX9AsT0DRHvs6YrnIBQevUGty81o+GmJIV+PRB21PAw7YAMPn88Aw8dvAHddBi2HajBauBaOaWzlUYOv8NbcFqgUCuC1O2Tgdn45J0e2kYL2A9xZMYuaOj9iZ3QLpfu2YNUOMbS30kS9kZbwW6OEp6oIQ47YKKrPLQTXiRv4WmQS6z6dBAXJ7aTWFAp3i8dAU3UuPrtrAT7eBfxvYSDMLJaGslop3mR9nSrMY1jqQhmLN8vCONdHwNvfQsU3KXZZmUzZ/+rweYUeXZ+lg2EdZ0Ff9wY0fDGD2xsUSOu3Hac5vgKfW+Yw81UG5N5HKkiQh2neZ8hYcyWbPTEEpdV1kK8cDPfW5HDjwXAWvDGZpmZMpwnrTTFkyk+WrB7B20+NBZdZReTStpKvvRFA400LqAgOQ+Lmdn40cJg2J9aBhvlRnFk9CZ4e76JNS3ywzPEbKoUEgla7FDcsqSCfm2sx49EDmjBlJq85YAUtLyeRbFIBFM9Mw0UvL3LdxC7UN/6L8aGS9G+BA69VEWPVbgtIehaOetNXQ/sUEXqubQXjX5nRG9XzZDG2GbovllLirmrq0JCHNz3J/HHlCvSweop/Gxo5Vs+ODv6qoie7mjDiwTQQicojz35FmP5jKrjiNjBwq0G/25Z0SiIdY2OEqEKhkX61LCLnO0owz1gZrFe3UuNAJm8rHc59d7ZzxZT1pPo1iEa/M+fbU+qo0msntX+ThnEGz+DfsTNw1OQp254D1Dvqh65PQ+D+zY20WUibt661oE/Hx8CaHGtqXjWNO8ciSIoGYZR/Ni1ar0WLJjMr6PjxvrJwNLIygw9zQjDKpZkGz+7jwvUCnFkvQyNv70DthO24sGE6jVy2bYgRtMBodBbf+bWRvsmpcVvAEn4x8i6njJyM6eRELV8e84gR8vS7TwTSJljyPec4fMVnueeBNRy6LAqXtkjjxtGz+cqgKL4avQD/TtSG510J8GI44b8rCTiv6BiLXzmNtn5RJDW1hdP3jsL2RQbs+08borxl+bvPTVbL2sgdcSM5e5ENnH58nm0/zKdkYxX0XGuDa4X14GH9HE4zryFv9Uq456ZDP5bPJWnzel588gUcV4qm9LTpcNRZC2Smr0ATfzscVydMHYVtrGf0Cb/OBh7cpsFX5pvx4VsG0BhoBg1Tkxire7ns5isqk+iiOQ9u0IJza6jGrhuOyXpy5NaN3LR/OAxLyYJqxcvkr7caK9sm4KWnYXh6giMWvnmMNvFW4FxnxOschGDuXnny/jSdc1wn03mLcppUkgGT46fCsQWW1Hv8E9yQm8WSpqNAQGEo924vwLleBXyvJZNKLc+xRpsk5kx8w52XNlDp9nwOOawCK66UY5cP0b3La3mUlTUdHlhJtd0TWGZCOg52leG61bdx5yxZeOj1hJIKYmH5pS+wOaCc31l2c5zfcC47Pw6P3RfnAoV2rKeRkKkYwutFPUjvym74+v0OC7cJ0exEN9r10R4O1Ivggx3naKStGQzIP4By2SI8ufwvr7GL4Mtq86Aw7R5IR96iPbIvQel6Kgse0oa2udJUpTcAw0zn88mCJ7B+6ybslqlii9SDIK4xAT3FJ6KJ80S4u0sC1m8ZRY+ippDe7QCaUt4KZ6928rU7Vej05yJoevxlX6lJcPz5OFDpGY0nZ7XxibPWFDOulPuCtsD1PdPJ/L8PfKAzFiJWi0DC76Xsdyaez85fSP0u1ahcPBbW+ZtT9C05qLYZAMleV6ydOwwG84KoaPtlSBG8QOUa0Zy6fQm83b+HvLX6YHnlQey7bE6pyoog/dmBP1cjhRgXoujBUF4ncxmSOZxkG8TBa95TeGP4AMpGTwIFQRG6mxqDAykaqPI8hnNiwlFtaE4rVL5CKcEaHHmgkRQCjKCi/TuHK7jQ2tR+zBhzhzX2tXDuEWkc9W/oDIf34dcZf+GCkRlkXfoJEYWh+FJyaA7NsEKJtaNR+Y8+vOj9g7/E3qAWS7OboBi0Xi9CjUvKKH/rP5brHYnVfxewk6Ikm4SY8pFJahhw4yLPthraa1YXRW2r4DK9u7C91B3S0t/w09rxlLFlSMfrdvA+52v0vUAXljaNArtXBpRULE9uWQnwofU8zXedQY+cbvGPbX/w0dmFcDdAB1yGJ5PIawWc4SsAdns38/5ZG2CB7TsIU9rK22vMUAsO8rNmKQgKtaFzKAhxBcFw5sIb9s1dzC4lMpjcEkBS1bvo44vp7LdSCz6ar6LwHiP4tmIb3olYhZOV/EjX/SQvuwTk65cBNbc7cX62HZRM+U4nhxhGe64LrF1agYdeCdPEyb5US7E0enYcKF9YgynnRMHHzAEObWjBgoWmGG2STr4Dz8FWwYi84v/i0o0FNNHNGgZKleBgcyi3WAXTvb/TYKpOH/oOXMMyqZe4LgHxmucCangQzg2zRsK9+ttomTcLNpfFwosFR+jhxxrITEmG6eKXYdrv5bB1Rygb5xmCbcccfmsfg33Sv9BjzGHoy/IAmHMOrT8Eckl9MtdfEeWZMoLwy3QYvmlaxaE6ltQS5MV+Umd4Q1kyjj21BGe3HaLEi668zAng8ZapqBo3EuVOvae14wL4ioY7+sx+Rv2xX/GjXQ66PwoGvV1mIH6jFf+DuaS34hEeOPcMRk1vQ0e7HzCyQAH1T+jyh5N1ICVsB0tOKcGtt1doXq4cxe7cjxah2rz2phdeMyxAh1O18O7fXZIVtgIn8RMwXiGLUsdFQtQFTzrYQxBfvAWzXMahiOtkqMrdws92i0HVDns+8nUPOUlHg1DCH569aTguNnxH/nHXuGHaeDSKe0fJ1yVh6XcdnHhvPllZzoLTBb+4PWU+rZ83le9cEKaIa6n0xsqdWvuFYMB+AyadEOLNN/VpTbYl7nBfS2HHr9DAnkK+fvkSBDzRhJ8ao6E6Csj/2Vsc1G2gayu2kUjYTR6YWo1tDen4z+s3CKQdJsdgFfgU+AOb2s7R0r6PGDlbgVtyb4GdYgVsf1QBB30f4fm8Gl522RxMzygCnAuDO88tqPdEOUpbzECpm7+xYmo1z29qwJcDGRTiMQZGznpGnvPuYrbeOHw4ow1SZmwGPe8aShyYAof/juBX0sVweLEwtN1XYo349bBIvxWTJ9zlwtBNJHfqAQSXHeIml7Uw+E8URWsEwBpaYNGrJmxVz+L0g5MgoSQdjIYX4f3OfbD04Bl6d78Tl28Qhn1xTajTr4pfjhNdndrAm/2M4YTLHbicJstKc1dTdPAQt5SawL6N3fRuoQWM+ylCTmOHQVXjbLoXbgdPg3ZznvsH/GaoSbfsxWCOqy/cVviDSgdHQWm3Ke3VaYF5Fxow5cR+NvQfxTK7p+GFOjvo03xIcYXlkLLvFoZFO8KW8dYYUbWNlirdhEGDfvD94oz+j81A04hY1WMZPlgsA4vEn+DkZeKwU0yXQ5I7IVNQlJoX+5NomhmM29KF5r3utG1aDx4Ung5aJr8pQGgol82ph2lhqmykcwR+JarAwV1ZJDVHAi/nluJHS1d+GuhDzZHDcN7vB+gyfwPlf2imC40S0KJfTGkll7huijF5iq6HKp1jfEdeCpsOzKU71oGs/9cCIpfrQ9wlfcyrTCeZtpXYE6TMo1ZcoU9aOnRTew0cqYinudXmeGOfCYR0+rLJyT4O2eKG9y+EUo/nXOpfMaQb2VW0RLQbdmePwhJFBM+tWTArMgzEzoRSS9kv+Hl3HZp8vsia4r64Kj0F/e57UdEnXSj6KkBPHtnAMrlwrtGzRen4PHbanACPahsoZ2wKO/67CRFPGNI875PO4W2AseJ0eqUqVua5YNChK3DsXBNMElwCXdf+41WOelC9dz4uqQzn7xf3UO3WGzCrKwQXiLuRR7YP/fw8CUZ2mLOsozIkyjIYW8XARomL5DD1OZ22yeaXrdPwX0gGP5jUh82bdkCBkxDYmi7FRzm72c+1H5t0M0nf5DFNhHYISsoEnxmBWKCTzu89Rg2tNQE0JxnyJ8mN+DRHjyvPrqBA0zN0uFGWb4mcRLU9qrgvWw8SJDfAKGNPjA44jfFzJ6Bq03boTPjB//bm4PaABDpheIHqtI3B60o2bNt4HEwybFljzgYwK1TmhicJ8Pzxbq5P0KFhUZakf9McmpxTcHaYG7vNnIKjLruDzaExbHTuOYw7as3W2euh/8Aj+rp3HJyYmsWGAhdo08qvrHNjPc9Z+4uqfTTgUkEMBM63BghYBYorZGGWxGWIk9mDoSGqaHW7Gs8fZBCse8GvV7+HFI89cCflGGyMV4Z3BwvwkOJXfFIhiKHJs6jraguE5rYO6bMe2hIO87XVl0F/yCdNgh5yyvbFEGRzETzvKcJVTVd6JJ/OZxtvoU7NTygs6YVzyrqw/OknCvH+TnWrdmB6jBp/7Iqj9Jgmssp6R9vV5cDOWIAVn0qDbNA4vNFVwO8qz9Dv/mdg5Z7IUjH72M/iHS5p1QMx0QVwpkUMlEtn0aIjaXzcaN9QXfTJyKOU375TQcttebAz7iTYny3hz18N4cJ8YrMfTOX1H2DXcUUqkGPoKHDD6TyIi898oPiw6TyhxBIOXbtL5Rkn2Wj3cs7KXkBRQ+86r8MbVk8N5pvdBGe6xMDY3Ah8x7SAoVsaSX/opKlS58ly1Vg6pdTHzZnX0etDAby1+49dIgRA/6Q0nNgVwTtdttN3+UL63bIQq+4F04OmGfxp6wD8TEimI4WS4Ppag78lraQoVQ9MT/HjEa/yMLvnIe22G+plEYKDi7/ioIgYrP75gQu8fFAu/htH722ltAZZTq1zpsztvRTx4TNFPWvkQF1ZmGtfQeZbXFh9iL8v6ZZR/Ut7fuajQPNc01C7XQM9llyHheMFYEuFNzTopLK87kN8NjsM7bsOwBsxGdTeJEO5YnakaJUO4bcUIXL4Onyh2UQC70txfEsDp9WG4+SjBzBypxeMLe9A8W0O+DBKCaROH2Sdrh3wd0wiCfi7c0ayG1fu1yCtxGY48OsGdYRmkPvFYTBt5FFqWFDJdmG/SMpzJ7NZChbMeE4rsi/zm9Z9uDpamOye2MKkEAFw71RFFcuDWNyZAL8MxUntww7YbhGPm71TIGBwLDQNWIOB3ga+vtGCl+7ZSY9jpWF30VjYQLvh7vX5FFlvT/ekDvJyH9EhBhVn9+9mkPvsPGuJeNLprSOw+Eg/qb4R539LtSHcvwVSTxO8WbAC9lQshy0OpewYOx5vPf4JHnHTIK3oCC+bvors3X1oZK4NLL2yFE6s3ogzGq9jIWykhqHEZz6URRYLVrJjXh6fTL2KyffEwSM9kIO2adGyO+H86Vo83/4oBpd9uvH06/3Qdmsm3otSpRvLNcB/iQOMWNFAg+HZNFP7LWwNj6c/dZ1c05DImxJ/UIG6GHaJSUI+G7Cceiw9zXoJ8dNv0N2Cf6j+yA3K6jthTTtwRqYjvF1pDU8Wi1Hf29lsVB8EKv3K8EG8H7uumSPvtebxnWepNDYBjPvGQsDBlRxafYzI8Qx8S0/ncGsHNFk6DV8Gy3LN9xB2z7PCsc7a0HfUGzWG5mJBSQDH1wyHQe86TAx/RhVX78MrG38sDKqBVdUS4NWSwWbBB8Gkcy8XmH2Ag0k+dKN5CtQfUMYJ13bw29l3+WG+PIQ+k0Z5zS8oMMafbk4swbrURJKNsuOe35FUermCpmSe5JmP9eBGQTOGTQMWPbQZND96YcJeHdSrriPTp6lMIw9CuagcyJRqgNUnC5gkOQIejR4JH8XOEV9OYuc/JZSxp5fvGehCwoAm+3ojSFx/j4OWO7nGYQdq+llCwdde/CDvD+q7dtJ4o6dsq7+dC711YOTmdkqvqMCUhGcQ0X8OvaVuQOWj/6BZaCTnnxTn4MLx9E9sJHzv2AM+F03x9YJn3ByqQTNjIuHV+o2suX8CCeVdYO2/i/CNrAKc8TkEj/kQHPAW4cDUZLxZ/ocbXmXhLQ7FO4LZ+OlqAem/loSMvGbS220FPXqGKDesHMvfjcU/G2rwttpP8rPcw4nefbw0TQ4KDNQwSP8XhO73oODLJWziFUv9cq4cEx8HqYnvsfj3QqpUUIDedz5cM30Tm618R3MTx9OlNT247O1w2jFsAeY4tdLmdefBb5gIHH92locHfKerVR85JyOTpC9/5bBnmXzRLxX2H82gnq1z0X4xgtbaWRyeYk+31aUg/slfEjvqy6XBu1lG5zNPWDefx9SKgcdPC5Cr3IqRv/ppoPcfDz5w4dq/sbBtjAw7jTJmTf9cnteTzSvD5EFhsQg6r9tEejbL6U8L8yXxMJg/1Ktz6nVhf3oyv3F4TcFd6jBV7jFM3KcC/s0zSdhZG1elrMVw9430omQ+KMZUANs8hPA+OzDqaIGU5zY8b3oB04YciBnS1uXT+0Fn1Q1UlxoLdWGdzOdVwO67FYw+a8rRMSspe2I5yu7bidEK8dBe9Aen+a6iUvFifpc6BtZd+wBr3g7gLK/loGt6jqflz8F35z9yhP4dxncW4HNzJL02N4SoJUvZ1+Iq/acfwpsdj+F/O06T2H+3wEVmK0aFjQXlzFzcf0gcQDeCpPeM4VUmdhSiJog4vA6yTM04d9gG2vZxAL9rLyIVfxHYO+8bruzZTAY6s+DKUA7mO+Xk3TQIy5658R77VrpVKEmLZZRgg2UH8Lw41n+4niJ7m/nVlmlD8/0lPf96ALyu/6TlL7wp47gpONx4Se5jK7AlcSpZZk7g7oJ9JPlZghWajclG4hF/VPOGDfrGsFwqCa7ecMURenZ4ynYiVR8/jf2uvfSy3A7eTC0iC9cwjP8rDHIayzD16A/wuH2B3krsoZz6cu6fNhn2rBvLi8pbQdY6E3uXqsGRRSUY2mUDxdWf8Pn9r9jnaw2vwrZBd4suhUwOI9MlXfSgeRyEHlXjKo23pGv8iAz3nWBNndNkE7EBF9wrwfJTLRgu70iRSePgx8bj5Bz4nq5bNKF8dwurp23BRO94VmkTQe34z7T51kT6MqgGSb7hVNA2naUIUb0/AopqyqlCXw5VDxVCRtdcdL7vjvvX6EGwRAGNWH4InpjF4t0vgrRugi4+99kA5k35XLHWEleWVJBPkiqc0xPCeN0VqFefBc6xO3D2+iPw1/kQyXYqwJwtA2AWchRlTMfDyrfPqb5jiDet6iip6DfsaszGEHVvStmoBGqcSnYpZnRZQwTEyzSoKv8Gb3j4B7eciOdrb7zpzMuPvEniBpxdXg9BXe95/xhBWCchTDP5Ib/cKsTjZXei+89/gHqbsL15Oa49vY38Pt4nmV1qUCb+B9+mDa3ZmAm1i/7D/3/LPKznM0QJGvIicXnaWepD59V0IPZOIEeI/yPv+QnoFloLn22KuT1xkPcIW0NyJvNPnTX40t0cgjZH4Pw8fwi6tA0WNUbTf3tnY9RxdWhb8Zp29/pAf+lXTMgwBMNHP6nY4zorbrpNBc4e3DbWDOYdbaGHmedpa5wxafTNZEF5FYg28oaAaftQ6WIEfLepZjWpI2RiagIqmE9Wmy05QdYOVisqwZilari1rpajpyhhplTwkN+vheZjdmhkE4ZZV7txw2VX2BqiA8J/DfiPbxVqFCfwS5chL9DyoqnFtXC3bzqM+G5MFg96WHWXJAw3XctPTiSgy/fjKPVzFNqqVaF+TTzptghj37P9dNBXBF5pWsOmsCusNVwDX5Z4sW6mKxQ9bGW9VBtc8F6XyvWUQc9uNXb4KkNu9C6QDGygzF4VdCidj28llHjfqd2cfu0RvxdqwI2nBdD0vTZ8fzUfVKuO8urmkTRz/3c0sqzi/jpznrRwHVpW72EDTdUhbrKDDRcMCJ5kwocDC1n3sDZtr3gLmBIDZ3O2kv+cR9SpnQDRubJwnnr49l0DKqg/ALsfToJMVxsKizZhc58CdnltSeel3dGnygymO/rimaYL6NXYzok+SuTb+gl3D/Mg8yNAp33mwfNhqny3xwKmqqbQwMl2elP/gW2NolhBeQyaNq7H+RBPDgeqQDx2F5SmC8COfQJ4+qQP/F1jSHZ3f0Ow3CzaqZUJCm43Ie/QMw7/68qVR6QhyCmdlRVOUfw9f/bZ2oybVk2AWcGB7N2XwqELkCpfB+Oa0ebQnNSEWb2H2SN7Ispv/gkTGs9wOL/AwcTpcOzEGq4OGg6sYwtBCUL8QHsv6X1w4OppdqTx5T3vgyYO3D2CLCIyKfa5MEV9HqpHszAK/juOh958gpOXnlL17RZ6N20Gqw6ugbezn3I3HaMqe2komxfDn97r8V2dODjSnwgzfv6gaNN87oirIfN+W2x/3cKvE0fDNPMx9GZ5Mgyr9aTFNzWoVK2XFDbGkorcWvo2wwiKw57RGFF1CNM9j7LtHXj88Tq490aEN+xfjapb1mB/hA3ayrnDrpCbeBKUYHjtPRIXMiRDxwBcvewfaJ1dg/JzTlOBwW0QubgXyiTW46M2VSjrfQ7PXP25SSmYa7o8cYKoNv20LYMSqbvUNEOBczd/ZvO1E8H9qQNdmPoEKm5PhpkhL2HZZlGcMzDEzdFDV892MI4fD54LhOF4zWuaMncZ3MsWxqXj9qFvnhS2FQHEWRSiw8m/cGlwAUUMA9CenUqfGvrg5IHD+KRbgq/7j8Q7LlsgT2UuC0+V40+yj0AsXwgOW0fR8JajnBXihGKfNeHBcYS31qN55yRd7A2Q4tK8S5CpZwfpW5V49b8vPHOeOs/QvoUHGpRArOMJKYZqsYGBG9BWC1plIQbPAxrYvViWFTybKEbmNYpOceTLfuH8ZKM5fhtUoFhtB+7aqQxBPh9At86SzP7akv+JrSj/ZwxuyBGj/heqXJl2GotTZsEHHAUnx5TB+m3JMLlKB0cJmOB0F1PyV3Gm8DsraM3M9yTrqg0zg4RBWUKPlSkZPLEHPd2OsJTFc9CQCuapq9R439K7ONHVBFf80YX3QV64U+s5hida4Xyr13gr0pXaXHOoMHAGW9Fu3uv5BXY1ScHt4lBImL8d3neYsqnxX/pm74d/TmtRe3wj1RSPRDGJHDYJF4A5Mj/4R/8jur9fjnRTCvFI1kL2v+JLioa/aG2iJtrLSHCOkhXM6nVCiTsCMPKYO71ffZvVPqjQ6dAAFtd3otlbtLDDYjOMvzYKbD+sowQ1cXpZZoifeyZiWscWPGHhwkESw2BgSRyuGBkK458pQEqVIWKAG5nIbAXj/SaYIS1PZq+B724ppOt9zjzyiCB+8JeAO0LiNCz6AERZi+LYpQVUeXcWbF95lc99H8D972voqGgZXn6tBCvmdvPvQ5Mh73sG9fos4IlWVZRKppz1Kp2lImKhp9EAlMcpgsHxRazTt5XVLesgUecNRwRt5Bq9buxN7+CQxaa8dfx9nj/DFqIWrYcXj8NpjaoNa8cfgCVjhcBlsxjfOeWPVVP2sF93Kz57LgAR3tHYs66BI2adgOBOO/ixeDauN5eEirPd9L0lCu3U6mFqnwa8lxpG9XN6aPGHlSz90gd4kRqJuG0kRZ8BCPo0COaOq0BQTgiaq/YxKjfD1vN+0OhylnpaFGFC/mpyfXwQjV6UwMFOfw5SV4PvozdT9pWdJCs3nnqihSh9ywkYvzOFF+8YidXuimjDP1ElTxe2NRyHVGMPXF6/DiJ0d9EHqRHUPPko3TtH1LZ3H6/ZqAenNWSgp3091b9ZR6fWxONuxbuc3fwAfqXt4V3WFkPcmsQnx74kXKcNo11tcaCyBAUVj8OoU3Z8QncThh5/zxNG5PDSzBRU1bXFDTvMIFpvIZaoLoYm+w/YN1wJF/ycBX9jTHjdJwEcO/okCGQ48x51c/idFQM7fA1gzMVoyjtzl9c5BaJt5iYcXOaHw7cV8/ruSfR7uiREvh6DI4f4Uv10MN2oewlHzplR4JCHqC2IosEp4nDYPwBWHNOAgIAO+B3jCNbLRpDvkySqmfWHenz20vNLptBXVkPDUmPx3Rgh8JCNApFbl0ExZT82rRblPcM20nXjzyx8sg0F9ueTz6JF0JliBJ/O9vG4OQ9oyRE99Dgiys6RIezamQZ1Yvl4WbeIttq00UxXUWjeZMclnQ9xfacU7RRNwYmVurC5QJmDN8TTq1YpFjm0H4dvsgT57kr8p+8CMsErScjdA6UfjYfA8Fk0XGUy13Z78irhFrZvQOj5/ACWXXXhW+df8SIrDzTZdIpHHppLaqWfwWrlbRzs/Ir20SPgZVUiTPwWjqfvZdC/0Bs4sycRlEOBYO4ECpCMBm97Y3SINId5F5+j7XcX7i/SoNqZ53F6fhq2tmbwqegxtP/cK8ia1AlVkUKw+HE0Cga9hhnx22Gq/w8WnRyGI0R0eFhaJXTWCuIPuVEQbKIFy3vt6TpNpZvmoyF3XDOO0fTBhujz5DxbFCojo3lWsjj96dMGH4GhHBcbRDj2JIUUhpNn+jmYecUfQ3d5U4mLMFwXmMEjnZRh/aAmGD1U4dmiE3Cm5zE4cMCQZZsu81iVDaTQOx7cDxZiv5gxyNdtoGfrbsIqRWXKMO3Fn+4dcLlhFTw71gZ/FI+jxns7/nJACOoL9gztNRPCs6zZc/UZVk/ygZkkiSJb35L36iTghHWU5joJ7N3z4H7IbjTrcOHzOrMwMS6EHyV+A9+iubR3kj01X38CE70k4E26GOx12wN8ypmMVFMwLioU6o7uIeXkzbi2SY6tnsxk20JDaPryhfpNe+iHYj8Kp2bjnEvKnLV7LdhmLoPqpuF07JQljQjRh+lvKsDF/QbETymhXX/qKPvUd5Tyb6GRGiKs13STdnh68PnXBrCRVDBluxBpfxSmlE1BvCf9D50WvUJ7d/1AixN9kHDEgPME9KCn+jMEr/DDeK/jkFysA0kKsdT7/iXfrRvPZbsL+Iv2YzqgYg6eOdH04ALBu8E7sPaOBfv7nsK4n9q07bgddrw8D3MT6mnxZluQrFnNU9R7YLvHVdpfehXzNLU5cu4pfJ/1FU5GiEPem690/qAyiE/romkh3uRib4jfvklgRb4T2LvewBeuhfB62kt8ulkXjv2nDQkP17BHZwMrVWnQBpG/NHpXGk7Zbw/Lnx/Bue2aPMxeicrWT4TRfgupykgH700+gev8JflpVBOUOk7DS7v6cEadI69e8wO/mutCdGsDD2R74pbXbyFxhzMcHHzCy0PzqX3SWH5XshscBDPpz0YtkM+Iw7TiSJ7pGwq+pp9YboU1VT8HXJzSS/ebEzn85wn2NFeAQsUuXrwgEhtS3sDa0SI8deUBXl82ChOPRUBFdjq+6DKk440MymuL4UCQOydv2YDfJZ0o/2wG6Q+LR29/RXxzWJ8Fir6x0A5RmGDrBsZH+/Gmoi+35BrggWvSIOTkRuNdjrHfHD/urghG0S3C0DZaAUdOXMRWH8JhjJo5vWlbCvZVm+DEajM4KVfHi67fh850IzhVcR5/TpVnH6U6/tVbS2lxWygqtZWDBI7QxMmLcOHTAbLbPR5OBZeQ53ZP/HN0GR4Knw/rTmfxibwwSpt5kLtSTCncspba95iB9Oow7MifST8dR1KVgw9EmKtTrGMbjjMewWgizMaO6TD8pzz4Gqry+ERzfLqkh95+q4C4U0uh6nMv+mTP4LYRSnRi4Av6sTa8StnNR/Oc8fZQ7vMbsYTjOh/QuyoHmPylEVR6O+nn8FroyRAGhR+1YK5QRyp7VUA85zF3tndihb0GN+tXoFfHMhr9fjj9e2IHalXq5LpgCQ1DS1R3CgS9diFSmBvElzI0adJ6M0rSOwJxugBvvvzm9DJ36lO6j433e/nzzQYe/foJdbQupEvqtXDvKpDjZzlYgy4w9Wwtf95+BUc6e7HOel1qt8kmud63UPomDay5lDK+SEJ7fxzmTLpBZQdMQT/2B2zSiqUKHx/q3hJNZ7SleFxNFXdKDGU225e80PwpNtYaQOUtOeqau4HO922g9WkdGIK2/PtaOcM8G3hnF0/pFc2gcNyBbbbcgEbdaJrkUQ90xwFjPn0Cy/JUiJmvByoOlhA2QRvCsvbjoW4NUgkYz692W/K21c7sRb3w6kYduMQMA6WtL8jKqQ4j7SxpzaLlWLWymGVVLLj92iLa8jYVuFwJH9uIwrmCn/hhzTWeO7yc2t4bQpndQfjV5UkzA70hb/to+GDTRLHykyD9WTLNLf7CVlIitGu+E++3u0G/qprhgvJXmHpmEkjq5WL+9jGgtXgfW6sNsPyp8xSp/4OVjZ9QZr4G2ExbiWWyQfhy2lusGT4RBr1+8nqX3aQnmQ4Lbj4E0V3zebeMPQkpSvKUnGswcPkNvepXhI0LXfD+cU9ur5jHk1MvwrGP9XTq0AbelZDEh8zUsUmqBXesHwuGMT0Yt2oSPz4zBSaffQhbW9VJ3yqFwsZ1I3v5UKfjJO62UICsW+bkkaJOUbLn8dbcnbAt4xNpD/uPl6Qs57GO8aTiOQWXaI+CCJcdMHnsYbxtHQRGEiF02/gFek6Xg6acIlIQvwYujQUcuEEb3KcuZ/Pc9SDd7QApVvlcJrSOWxSG0/VKX8idKE/7k8uxfIIWSF4X4KRcBzqv9ZXmFn1l9YRqMqwxpF+hv7Hw/Vgap5iLSy4IwdKRD1hDRhVOfk2h+AtzQaFYn/7INvMtgXD+3XwFHknWwv7rDBtj03lchDGqOczBMW9GU9UoHygVLqDgQV28e+cPP1HYwjInTCB6rQt+9QsHrZiP8ELwLXZnPGfpliDePBCEA+UBqHGshxfZqoPui7EQ62bKCw0mo6fDZt40zoBOX/7GiUmJmPk/4s67LeT37ePnaCtNWqSkvTSQkiIjK0RDZJQVJSr6lhlCoqUiFGWlUqJSokFGym6pNCQzUhHRuPs9ivsJfP65zvP9fr0+x3Uc11JbOrxFBNssJ8Nmzx/sULecXQvjwNNnOE+4JQfx21WpfGk1P5PaTS8vzOFXRy2gbGMGSIUE4L8cJwh3doC0YUSrD57nR4HHyG1OM7+a9xlaCywh1vYXhirN5Ij1eiil5YQTjsaS3UAE5057B5YZtzh9/CT6Fi8JlzVNIH3hJXDyycHWpZbU672avojlonL+AziKO6guvoBiBxXgrnwPbp+1k8Pn/AVRYSuaNVke9aNWsV1MB9/7dorqruej4wtJGJXqyJZm4hB8yYY8jXUwYu4Cdg+p4pcCV8FYchw5SzZhh8dYCOCDNPlsJdVcvcTKo6fRxINqvOPbN7jy6wHPnSbJYU+KqMtnKCdF7+HmtpVw0dcUNc3HYqAj4Ihf6jyr5RZt6D8Bj6ZWAenoQ2HkQ6q8+Y8al3hgvV8VrIiL5/pl8mB/KgW9jEfz7tk9XGFoBhs/WnHZneEsYxlFQlc/YLBkFmn97ObG6nb+cPA97nlrS2WO2rAgt4EePh7iOMVF2Pz0O6dK3SXh2qH8ttRFkdgcjHO1g58T5KFzw37qc5CnxTG96J51EboiIvHBLy/2TPXCzVWzqMOnnQaqFOBMlCMd76vmkz7p0JN2AfS3FtMyk32coXsVPkvNoK97TfHRJX2YMqBIy4dnYortbbTOjYeExiJWnd4DF4Xc6ITaV7w2bTQuXiIKN8RNsFSvF8WPpEHlsrsYoNdFc2+K8N710uwrMx+vipnyptXD4XDxAjicGoTOpYvA518Yz9wuz0uql9DFs/Pxll8gPPJr4Ys/pKBaRY0mljwmgyPPsbxiE+vuGXL1+Jk4UfQHhnv/YAqJBDaWhjQVbx58akzT1i4CN70WDmn4QRuORuKUu9/hhdtiSr7QzfYmBhDwB3mZ0UbwU1vF6i2eOK1FActnpWO590QO2loOG9WiMePYSHCR3cvjGybQhRCCYuEtcLlTjz0HvXiwtoDNr1zDq6pp9DueobFZm9a4F7F7zUNYKxpCFsKqlDg+jc76VXH6iFVkWn8CNL7rwNHHTXRSzAZr5i0mD1GGVv9cUHnxBqNNQ0G4qoEkfBvo2SFTMHq0F+vyd+OznS8hqfMWrm/4gz5GW1HhcRxkzLvMhodV0c2VQDLeFo2TF5GtaQh43N6PCR6Z/GiaEiwPuQRqHMPawTFk2S8DiX3rMehVNr7ZcADqtAVo7SxXUiyro53eN+jZxGbWX+gNUaNUQE6uC9o+TcYFf5xx6s9JfPXxOf6q9Qt2blsKi2eNROgLAaHfGmCYNY3vCbjy3eXRJL8qit6vrCS9+TV0R+4xTrjQTWpllXBSYhy8f1QFgtPfUXgzYeJdfRx5bRs4n7aA1lOedPGvE6VO6CBrJQMYN1+RBDXqcMXhbST9URmdn5aSyHFzDGoZgC7PG9ikfAWtWyQgxCoLL0SspA2e67D8yF0Mz7HhkaL50Flhh5/XN4KZ3EQabBgNosp6JCO/FiYlFPA++EqD//2H4esH0TD7DGr9HIAF1R/A9rcWJKgo453ThbTkawx+XJYPNc+iuHF5DLpe+0sqzmp4usUYdU6qQ5j5VT7i581baxUx9L0zV+llQFJLBx4NiaPrKx/DmQ2XOGmePtx2kyL5h2NIO1KIlBefI8GLLnA7UQvNynvosfBa3vm+l1+eMIFXk+rortRb7P2zjl+WjYLtB2pJPukae7u/B60xf1FpcwC9NCOwcBRj5YwYqMvrZes7UnQ46huc0f3FPbqKMCfNkpeqKOBKfTF4YJDJ6mOE+M01AxrrcJLEJ+fCznc30fX8JHDO20zN1WI03UERpt1/DEaio6ld1ZUzfK1RomYmB6I/nJhjCdKq3vhlvRTENcqB1JpAjus3hS8jr/LfOh2SniEEsWuzoSXfEfc41aCdYSMOeirCNs3v9CS7Duv7d3GuYREd+zCCnQdSWEdBmf7ua+Ntx6fABwcrsIAYsDkShgovP2Hm8zAMXXCGsnv2cYdhDX3McWXp4GKabagPg1F6oJgdBZ8XB6D+syWY8n4Cv+u5AUnPc/HgORdaJufFG17rwczC5+TVaA1T0yUo1iqDy7a4o5Paa0qKuce55e/g7J4ENIw1gO+hI/j++tWo3R7Nuv27KPufPY/5OoCLeiczzTkDL7KG8+WmESA4v52nze/EtlYN/BdewbpbjpGS2XNQkVkMDhp/QSbsMR6qHw6x/jtI8NoW8lDsJo8ngTzZvAUELtRg7IMwXHDpKydnP6NsE2M4+fwtHw4mzJPeQanStbxo2GYct2kxZSs3obaGHL3YGseFkfqwdVUsTvkwBqyL0uiF72OsidPEsiWjyD9ah9ynCEFTty9mTZKCBwtWYWufAbyYLwUBdWu5GHZQ/PMULFxkzH59K6ln3HD29paAjhE5JPzsAE9Jd8ZAr8cQcjmAjFUCcIxBPhSOu0ve0wdQaYowlARPAAWxEF5jFkDP9tVB0+rbGBXmznsXSuIWpybcoDkDYls0wFNKCcvvLMCIS+PJ3F6KDY3y6flSDa77XY4PUu+D+2of7nafCJuSvkG+rAw/m3iez3TJYoF4I/oMyLGSYSo4TRiD1nvvIA9TBv8/pSjaOIZZJhv/Jv7FmfljMX+6EZTaXaKb6Utp/rYBEEhRhnsqJzFrzUkM9I7mTIdylEu5DROTI0BAs53fhW2FgNGroHEeQMTRZN4W64+W0XlQvS8fEwbCKbf4NXv+voBJKWkUdkgR/I6rwbotkpjrcQ8PztDnotufYP23TPIXmMuX3gKrrXXEsqoJPKxMArq37Mfs2Wn845UJp7xLAe0NF3lLjhntULwBrstVae3NEh6dKwvCV7eBXChAYn4/qWw1wLYFs9Cqxh2GaQqy6PV40I0ezTFflcD6v4UsvScA3edlg+fIFipfVMHHf1RR6WEByJZIg4T88+B4VB06KyMpKToXqmdMgSQTLQ7uHkXrp47DmJGutOvPYhT5wlxMKmAbNMRECf/Rxx8NMN/Mn10LVvP40ARcGTERP1zLgGE/2nFsNcBIt+U8Ir2c3l1qwU+2x0gCj9G1+FoOnDufJp39hurGFih3SRg2LV+LkQGHcMvxpVx2bjgr/7rNeQUleGbjdJLe54/fD2fhDX0lsDtRhQtQD9M3F4Pb2yW0728Klo9r4rH6uZTZ28Hf2szxQ+1EUGq9CNt7tGCjjAkJX3qBvwM+QvjJGVS0cwwmvrvMQu/TKDhHFeKHL+aJcleox7UdA35ocfZ0HVw3SxMbIgbw3+xxsMy2iD7KTwWLCSPhwDw3WPrClYIaLSAC9oLIkfNUEfwNU/1DKWvIyTp/6UKb+lpI0TXnrV7eGJKoifLeojjt40p49uwXTWl6hW2my3D5Y3kYrqWPB8JE4bWkGKdk3kC3o94wM18LbnXG8mLrGHz2tAsHeuVgwXwbWCbvj8N6Iin+dR36NFaDnuQbntlUzGELk8nmpjWWtArBrOQOaN+1iK+NlQGZvd0c0bsDxW+XonJiAvbItlFd+QkSHC8L18WfQquWAa0K90Rx/TOwJ2ESnHs7AJUdSmxg1M6HHPQ40WFoL7Nesl3SarDOUefWJWMh7us/ijxcDMmjVlPDFBfS1uxgrYCxsHDNMHa60wOpj0zwy5Et7Gh/nhvoGpQZ93Jz/G289LkFln40hLXdGXDlaCz3r1bGfYdM8a/vVPoyEEafR4Xx7bMWnHbfGDvPCcKXmigOcWFqWlfFJSEmLP55kK+d20IWe9RYI0UJVzoXwrA1VuDwNxm6BF+TtLMYS2Wpw7rOt9yemsl2sYosEr8EjMxtMUF6IphDANYrvyKz3VNxxfU/cN73AXcl7IMNai/gfZEMfXLOgL48YWgQXcle224TF1VDuWkXqJdYkFLEarCP8oSvcg8pzv4h53bqgbXzfj5w7wPP/7gO1rwZDquWVdJuaobO1SokVCdLZX+S8WygINTMrkTZ4zv4XPlC1r9ijunTtPC4gAVOSz6At1ZeBRPJb3xqL4O+w3+w+ZEVPh23gRT2TOCGgTd0aPdTNH+1aog914LLCw3Oah0Ht5evhYakRjh1cStklf7i7Zon2e9FHxn9TibvAl2ynyEHXyVkIN5Pk/+pbaWH4y/Cs5ajVPm6GL1ELtA32Vx21PlAK4MksfG6ACyJ1aMDM4pBvuwkXP5bTc0ONizeEY73u6/x2m93ecXD6azhbw3j7zmAhrg9FuceJxMHM1Yz6oSX9Xtx2+4U4pgqlDC/SMb9VpC5Q4eXLMjmgIOAr+S12GbqOhrcDfBWZ8i3loWg1+wu+n1QAwRt6nmb7jGqnxUEKZ2G7D7UhZNPLsQzYo/5wSZVqlgYxvoaRlDc8wRvpgSh9Y4UiMj7SYYx7RSdvwntIi/zH+3fpKFZxhsNhaD0gAXfyU+mqT6p8LEqFWMUztPIp6F09HE7TsuLA4wLZytbcRgv8ZyTJOT4zZfxMKPNE+o9N3Bi/GxMzTCEhJGxuLn7KYT/1oFnOyIwz2sZWellUVStJzotbOKmd7t5pekU2HVmJrqcjaOwZhUIdEznX3FldNJSl988mUnLr2/kQQdnsqquhK6APrAVTOAV7gQyq+/DMrsinOD2CL++mMjFCxqo/XYhfbz1Hm2vh0FA8mN4q60DA8HCbEAn+N2T+5yxTg8nj3oMbtfccKRxHXxZ6E5Zo7Rw8pdhEHe8jWuPxKNe/Ar6OziKsipVIdZ4Iqc9DaYVN7/hmmgN+uqpC1qbfeiQoTFuHPkW7Wf1gHrsPBrh8xPLtt9B15o/PFCTBamzNCDt3iwKOTITmo01ISnXjdYcrKQfoqKY7TCDNnWepvDhmhT/RRm8Bh/xWM8j4DpXiegIstvcemhrlKI5T21wj9ghwt0KMHuyJuiWvqbAO+uoqcOTz3g1UNTFA3i7rJ98/HPgQnMd9RTNJNOhffVM2A91dpoUd6gEbqZJwpjMZTh2yn06bGFDk2Qu46Jfwtz03QLCC5NZ3Hs9VTS3YmZ7OQf82cybReI5JsoKwxUz+Mj4aDo3UhYCLc7TPLEkfsh/WSNvJXZckYT0axEQvDcN/bqfYqn2AF+/ZgRJ/10F8SZVUt5swMOEe3Hxi3SAytU0z2zUkL/84s8P/4HJQR3AAhWcaLqBSgd+Yvmnq+R3zxrE2k+SodB9GGu9AHo1a0n1wmiwO/WRPUWW8mfvi/zh3TAKThiFvSIZ8Ou/ZpLZvBRPmC7iRWANko+GsflADhc1b6Gkvm6y2DwfolsOgs6vfJTzrcUesRRycVeH3XsecXLQbDhlJYwpNuXcdyMfv7i8oXphH16rUUG10f/AyVQV5q0qY3/tQLgz4wh52ObwwJWDvO7KarY8nUk1S1eAfNINGL9TADQfnKH8sFd89r9o/LR7MluuUGUv0xb81bgEaU8MuwsWovAuefC5Hs4K/roYn9AGCY5qRIk2pPr3A6dsbaCuliqsnZiLmz5JgfGLeWgo4UzRaVYQZPaam7TL+W3FfBzpogXXttaDzQoN2oAIJ4/bkPLGC/Rl3U5KfzEBfsf9oXdPXsM21518OvIp6QdLgdNMCRjrKET1ZRdoe8wlLGz3gJdPJ9CxPftpReUBWnboHVYvs6Xp0QIwVuMUrzSRhgkvT7HujKP8YdJp/Ln8F0vwMw5p06b9Qql424BhdrYbLV36GDdIN8P+5KOQ8C2YvecRd6gm0pauCPDS/IqjvhgDDA9i5XNOqCG2HF/Z72CVmE3Y/NYQAu2FsaNDk8VdrNDNUhg87mbit93jYNWADUr764JfnzIvufMELs8e4LPnWyHOwQ9PBI4FSVYnjW/ZyH6bKZdX4rnkVyxrFw9hyz6g5bA+XlCex9u6jOHXgUfQGvCIsNGHPEUWwj6r2Zgw5CHNBcUADpcpfq0DuQyIQv6HXTRacQ52mS1jqfwU3HxhPeOfBr6R7wKl79aj/qR2DBQcA4dni2KMnR0tPL4N9hxWQjubhXhOLQn+ZR/nTYPnSUZEAAOuj4KCxwe5rDYTBB3lsfWAOKyVEoH8wH+wQFqQYYYCei2+TH3G2pAw/CGVTT8NzZ+ncP3N53jlly4fiSsC73fnuTJ4B7sMVOP+NSYgPOU3kusCypJbTKE6d7DIKR29lWOhVNIb17xtgk3LDvPcJANYNWw6vHgiBrf6T8Lg6IfcJO4HvVknMUDeDP8eegbak99AXT5Aakc2OU+0QuexiOkvByivyQ6lL7yCEfeaaaRlJYtX5GO6hQgYTHwNNqHN1FTTA79H7SP3P47c57CPLOWm8+EBBnzRApZOpuC79BCtaRWlvdeKsGhTGCaG+NPB6kx2KvrGb8cngrJ6PMyolYY2QQP843yANcaUgvgVV/gnOIcmhZTRyyZfyD5sCQqObmAobA4lonrodVWK9xXloqysFTfYeqLWgekQs+MmKLiMhcNNm+n+B4ZLr5/S8zFPIKBsBcbN0ufVsY/AtUwXs51fwsZtgmQ7sglXXZWDP9ab0au1EQPOTye/mxt4XGQ22uwRwoKv8Th+iiR4KfdRU70yiOzpxMt4hIYtq6aQQ4C3bpnRCIlvMCK+krvNx1JNPPKKcwxd94pBy6iR3MXS+bn9BvgbZ8RyUQrcky2LMstP8+SGTKiJFIFVB1V54JkTvRCaSALu2zn3nCtqh26hX+WfME2jhJ83dVO3rwDkfonnhkJNPnGzCL6PIf727jrN9fgPrqkNsH2ON43bp8GLj00FN/G1nLH3AfqfP8B7dRzpTFQNzs4eA8Wlt/Bckz/tfj8cp2YZw9e7m2hKbjQbrqmlzp42kEkPQOk55UC7VMhmwnU0/bcSZ0tag8KraBKv/MdLCqeQy8npsOVMAY5UZlh5zZezvzvCoZeFfHLfVBjs8oIjhqcgWyCNbgS9h9D3aWiesBKeTq6hvlmNsOxOMHppiUFCZyLOfnkPvus24d3P3+GT3292MJOhf3Ee/GGrEo7aXcN/itWgZl0nBMf4wLtLS2DkWhfu/H2IEpSq+OqCMnz8Xhg1Xxqjh5IFyHlJs1PYAtoWVYqvug1pZrogBE6ahxdgI/s9GsF9FXWQWoEQ8iUU1GXm0rUDv7h/3Vfc5G2KbrKXwehIIdFGf1C/upG9gjWhbqASj7jMpjpPE5QKTIJx+81xw6tx4HhLEVq+XaSBihPc9nI0qLxXwH9rymmVxy262T4JVlrGQMcxe7jqOAtkr6hT2i8F+nF7PMx2eMr/rkjQx/F19CJUnYKmm4LAjkto4bOUczJcqfueC/xXawlmM2Ip8Os13jlWASq+CLI3xfLB1XshvNqUL2+fxZtb9OH6M1VwvdCLY06GUsudSpY82wZ57ftokq4POBap45h1k+Bx8zlIMRkBKjo2rHJJBDMn6nPxay9Y7/OMp9fvBSnJt+CXVU9y1ldprakmGEX+APUIF9qvqwzLA/uhW7OU3rlVQtQhZQ76rkB7P43CqZkmMCC1BS2t7/GMRVF006CRBF58hv6l08hecAGdvVNJbfZNsD1vLNioGIJ7WxnHPqjmlr+f6YmWH8v/TuaRG8+CdM0F+J34kBY6SYJCdiV5S1wnLbG9PEOvn8YFEq3r/oO+d8/jlXRv2iY7QAI51nCP5/OSAV2qiKzArUna6DtyOYv7ZaOuvCBS7i7cyUtIaZIR6Gtmg+ivtazWpo48yZmWvZ3GMbZ3Oa/0PAnHnIawK6E8/rUOvHxtA2kbtKnZrRrkZE+wZ3sgzjeeS626Z2lyeCqEp7zCn7u0QS/8OK7ZVInjjqjiQuXPPKN5MUSLT4MDh9W55ucJvJHSxCavRoHmiH2krJLGq/5+oxUnNrDU5qqhvnyEy++r8YNEXaw2H0EhKaaQNPozPNj4jw6cHo/Pi2S4UDEJ/4wopouxEhiSIQ5jbAOwwNQCXi7rpYhFfkBhH2Bf6EWSXvCGt6pG0AM/CdZb58ot/ylShrYMJAeFY1txIcfq3+d102bBfXETciq+jo4zV5GybTkFZ8jRtffD4cpTIb45Mxi/ijBWZBhj1OMA3lWzBO1WhELwqFTebh3K3zcqQZmwLlr1qIDg80cs80YFpHe009KCzbgvygzfjJTD2jR3nEwIW4x/QIV+AGVrX8IVxTJ0R2Qr/+8RYZcJMyinRQ62zBqG6QN6kJZiTBf6T7Bk0Sy2kF5COw0W8gupE2C74R1HLx7LmcHv8I/TaJjb3MrK6/MxvNsM/UsQRK49wpqPamQVaYrLK9th9zVxyB8uC4lLr4CBxX70H9NEBm+M8LqoJHf9zcFSvyNw4MgS+FT8DBVUzWC3aSCLlRyjVRBDg9On4h3dKVR4tABXTk8d6pknNEJqFh6rnQQ58ctoMOAfWRrvQPW5b8Dy80XWu/AAfG9+gLr9wbQofy/cNRkDn8848amavSycmgGh9VYwMlOaXc6d4IaMC7xNrhuk9a9TRLUK1N6Ros2SO8F3tAt7qwTh5N1BeH9lHT11mU9dgb8wlbbSomgCX189Vp+yj4tVXlFW50p0N1KjJV03Qfz2S+qPbieFisU4T8MEVsg2o4tiAP/6fo52P1kAc+6PJxD4RO7PJuDdb3acrJ/NMxWU4eGUPt7bQeC28TVaKRlxr3whBftt53OWd2FG5D9ea94DGzfIg3hiGm/7tBwaNPMg8xJjvUQ5yhe402HlaJp2YYBlWQPvlJrAf4IDVJXVDY+sroL8tnBMXH+M9Q9WgW+1Ke69lwu98ffIr1gBenQzaduoQarLWsWVqoqYu3837BTYB5/8Z7NV8gP6/mYk2asNg96jh+mL7nxS2NaLZ+LV8O7zYNzwzxkWTdWitLnb+Zn/Q9o8UQtmhwZwUqk7hOz/hA9HHWLJi8xKShNIzrEUmkXW0sbrGSD3UwFuf8sBhYteoHX9M6CpJy4/cAfc2x1w4FUsDMw9R04239i9fTLsUV0JuzuGkV/MKdQ26MM5Vy/y+mgFfDsvDCq8g/i46wC+TzQFbavz+HWTBg8+b4PpNdvAJnAvaB95RtNHN4DGDV0cPvUiFh7WGWKzr7S6YAdazNPhMSvm8PIVmeCuth/E12bQmOtalHwqnC96M6y9sAsTvD7yxbK78LrQBIuPuVO/QBRFbU8nN7XXIDLA/HuBDqxVDEAbs1xu8nxGD220QV/VDUXKv+Ix7dV8cnQNrn3vCcYftUCk5Bgc2L4RnJ0MOP1bKm5Kd4db9WO5I8wDQyfkwoCLOjSpGUH7ASl6gLJ8V+4ubZpyDQ+V5LFyVDi9/uvA58cdgHsCu1AmRQuWLVvAd1sAU+Ye4ZR6I3wxdgFO32uOCtGfYcGCi/A0K4IN7w6HzVm/+Eb4NRCy9EShhPO8ssUG7i54igr2raQRLsSrI8fTipfjwOPkbYx3SaenOd/JXvQnTVdvgcHH4ZAZ30lCTZNZaFQsXJBQB7fz/ZhV7cf3nkrx4syVvCT3Dg0f8Q7u79/B4+WHccWYdo7IHQZvx6pByIUdoHZrA6fJjKLzlnt5ufZ9HJk5ETX3jIXK1E5+MFsdZny/gR69+dRrtp0kPp9GwUdKUPTKERenmrOnuS6j92MYdVEeGkaI8MJcbQ4vfIJPcueh2R57xNUGsMzagiy3SNA00fFc4jgclpfOgRVTa1F/0IanfBLElY8/gmzuO47YPopGtOrx+8BDHPVeD1arZ8BRpbHgvPQ8PKp8ABImPrzMMoZXXumHP6Y+UDI8GsU1NSHnmyE2PN4Aw2NmsPvgQ/YV6ILIlMMY3GEPsQc6oGbcIlr1WhZiT3txmUkONy425uhV89FihwBceWWDKe6OHCBZgBVwht50MBxflo7i+xKwRTwTY8QzuFxzLti47iSTH80ovFyUMDOP2tr0QKGnH6tKy1Eo2Iw+bOvkPNUHaDh5O36YEs6yo7TgesU7lv0zGna+uY3SG/Zi4dNJJHkuHbjgKtSayuOMjKscLDWB9UebQpveEEc4NpGCySuQcVGg3uHIw5J7cE7KLZoxVYleVQfQR26HyapjYXeoBcruuUoNap0oeiiMQ2INYGXjMOrMt4GDuaIcECzHLx9JgMWtQLqiJkPb8D/YHOmBNw4d4u+HHfl3XB7OW51GGQufo1jBWBgn6AbN0ySgYm4cLX0dQ8viL7OIxHsoXeiH99abks+yRJ5/UwTiNHqpPXwOWC4UwMGtwKbh6vRNfgQKH/OmD45ZrLI5Dcr+M4Lah0oobTR+KDdq8EH2d3jwNY/WvHWB8GlheGJMLE31lKCY/wSgWaqAJyzYDjVXZoJl5CrsjzBE5dqX/E9nG0dEddCSRUfRRHoihIboo8HXOK6NM+PRZkf5u8QcFnfagE3xgNF3Izg78B/K2BrC1Y3/ketRU2ge9pm9jI1p5PcUqKk5RVf3/qJVwq853r0csxwV4FLYBxxcOR8mVClymKU8ZmeKoWzuGDbMrCKydWUpBymuLJOAbL1PZFF6mkOEZsP5dGOSGusFa1zW8aHglfTonh3eMi+E2acnQlBPGr6uMeMigzM4TuIcCeTVsNlQv1174wyvV0XRfJHbePnIJJhcWMR/t2rQ6WkLYdXlXL6leot/a9/G00lI+9bqwbZ9w1HUxxxWbHwD89abgtCVPzylLBuvukuQ76Y3pJy1GjPrJTG0NYDryyThme5CiClI5T/XPMiwIoWtH1/EaF1NeHxjIWnNkoOtPoWoMKgEp6cqorL2KXT9rMcjl+5i+0PjKW/jc9rv8YweyNhTSfdl3lJPsHRPBbSGu7DCpyzYUaLI0x3zedeTSfzd8BIcOrcYxC/o0QE7dfj1JQGnvxyJbTIluO+yDh6MW8Iu73px71ZpeCY4H8R/1ICJwXCAzjQ8ueImtwV9hoquGjq5X55EGqVxbNRcUvZ9RZrlSXBMTgsUbDZjpVEmzNE0oxeFS9E/IYNTAltpwskwHrbTnBROxhHfHweL1tTz6GkiEF83DjSaloBc6z+OKVpFX3aV0+QkcXIpDOSdDcNg2KkuPL11OgjEWvP236EkHPqGj8pI4aGZr/i/tadgzt8SUhKXBevPh/ianA/N71CiJ32HOF4vlk/s6qI+lVQeaS+DYzv1hxjLEEbkJdAENxHY93E17XF15OwCIcrsfsulDh/JTukPC+cL04puMxDMeIuFzucgdWoy//dMCRVEaqgg6AYcu3AQKVWTM0wMyHuQoDvpD1XO3MiqMXOQT+5htBJD25tnOXnPxaGOzqMNgWsxqcUaPpkN8OYzsrj83Hs+qrqCX2/8g+tverH93L/4bUEZhcoJgYnXRPg635ai5j+FNNGfLHOqgG/G/uBZautoxrEbaJq4Hpzev+HWHgnIy5hHi2da4KjXIyh36QXQkSuA+SrbuGj5e3Z6mAD7pIZRxIVxMP9HM+klRZOddx7vGOPHLy7HY/HZeXj40hEQLxal372ibHFeChbJXEVH+y6If5tE+rc66feiRnKpHstvcj7g2p4VEGnwF1KvicEe508gmm6IDt8W8HWLBn4/4SEG7dpN1y3e4f4tDqCUPAzKuqRA7MgZaAxTom+591HC1JIH9KbgVasdOPLbTBrplgIOz0dxVacV2CaL8vOSVgq+J8d6FZl46IYzDZS7YbBHJh6IqOe2qHK0l5KCkHETodeqEgb1EyBOppl1LFTIa2E1brgzgaPt2wnnO9HVsQz6i4vwk84X6pUrhls9f2iYTj/uL5oBdgrfua87Bk+OcqUgGw3IvuoAPUr29LLkIo37oo3nRiSSQroP71Ycjn7PrKigVhf7J02GuH36vDnyO+RebuJTm5O4e8N1Ehc4w38KFmKkvzS6K1/A8tiRIL/eElVj3vKvcz7YN8oGJQSD+Oqt+6C2dBddrlPENEdRktafAMpfT6CRVR3G7PGDhb5F8Cl9FK069pFO2deS84I2erP3OEsuGgaHtUXxfJwKK2kE00jpRywc9RL3lHTxjDwx/PJuPQuP06KK77Jg8NqHFimGkO9IWeh008TvDyvI12Y+lDTHcla9Jv8RP89VL8zh+PpfOLX5AHo9FOKJieZUmdPIjaI6pJIth65HlEDM4ysJTZCDF1N2Q2DNXbQz/0cz+ydysMAKNg8ewPU8F/uGvyYZk0q0i9MB+6L9MFnmJww43B5ieTEac+4x/JOcgnH0ns8e94ECEMI7D5Xg1uMCSk53Z33ZXfBhzwvef/kM9u6qxQSVaK7qRRas0wfJAxKQWOwJN83v8OEKA/YQ+QxPj53kXMfT1FqkCumVN/BvkQ62b1CH2bnvSc7/KfsPv8ibsv3pU601/7vwm/U3x7DM/Vz0PjdIHo4WQFVm2HmrnfwKy+mgzBJqatrN0WOb0PTpfhJyeEc6/72Cys0MEounIqQOsO0eTVA/WYJNS9fik9X6+O+MHD1a3Q9j7KNxwBrh9dMyvlHmCWE2X+CsQix8JFcIzTtOFS8eU7zjZz7fIQYnErTgTsss1AvJgt+hZZC1t4cq3qfx0kEJ+pKyFvW+fmOlzUYQtVINcjyj4WKQMoxonUWKJXp4zz8fg288xkVnJvEyu8c4IiaKt86aDJUtj9h89whctbyHf60Q5tknN8JhtTx+t+ohKOROhfm3qrhqwBKSz6dizUwzemISxL7bTvD4JhucMsKDs1ae4i3v/GjHzmFs+Bvh5ay/7Ch/iu5ZnAa9umK+9uUfVY5uwbFbFNB4oARxohUcXKUGvfq9NLj2DMdP7YKMbY487clx8A7zHDpjJ75v95dmbrIGUxmA8t8FTGvuYuyABS9tVAMxHW16/2sQUkYifboSzkdbtGmyvz6cTfuPz2gJgpzvGgj9aQLls3pgi0QHbne4yfWTV4CmwwNu7bWE+ul+6PimH/LUYhjim7k5xRW1Oh5QaX4pSYnJgVvsAZwgNgXW7NnIosUNpNevymp9P/D1tP20/8YuqN31lE5t/g8OLp/Lg3OHjna2Csb/SIfHDnch4H0jukkc560+DnwpT5J2G7yAZa2D4HlEGty8rqHH0iW4qs8fNfo62fFcNdtdtUdzy01o/M8W4U0cWX6cDJFTE6l/fgscOCqAo5vM8MjrCngUu4T2+NTj6OMT8PlrMfKNNQP/lzmY/DAEtm7KBi/9aprodBq+GoqQ+Ow4/HTrGakI7sfEo+P/397/7Rr2jvJ2r6GRHjHYpridIxfEQVreTkh+eY+Wbwvllb9+QL2BKniEa8KLYX2UFjEdN8bIoeC2uTjFTxvizzqT29s39LDAkRXblCBZcyHJZh8kBbFItjvxBNfuT6aUE8Y0W7cG6npUyS7lHF48Iwx+Sb85fNVl+FzygS6VtFDOFCtas5NAdlUYPc//TEddQuHS89HwV9oB9++8RiuXGvObIZfvMlmH0+AgLF0cRx3WlylVWBU0/E1hp34Q7viujRsqV/E5L2FKfXmGYnYpon+tD0r52JDXKWU4d1MFEgSXscitSdhfYsVjN26HrNoaNvmtzslpSSx9Ngwvff2Mi05Zgs3sh/z980o8+foiC0TsJLXrn9FWZyr+OveG1vV6sOnTVAraOBw+9hjgE58p7OUeAh6Gj9nY6B5Z7HLBgBEhFPfoJ0zaP4LrtxuC/lcp6FjQxfPGLGWHhTfwrkMiS4aeoIEV/dzkPAtE0vXIxG8SjDrwj6stjvPOC9o8cXQbfRmcA0eeHgbBUwfx/N/DFO5wgcpnC0J0IFHxglqaoVfL/+Lf0eSthLaR1txQ+JhKxct4pLwqLjmmDouHlUDd5clsNfsBJO47wV8MFHmC2hPmSFsuGv6UjxyJw6AOTVBdm4+jli/FDTn3ob60g6X8THD/dQvSftYIq+/IQd4TU3jrIQiNFonY8sGC3ZzysO5nGOloruPx0r84vGkQ6lpiYe/UdChK1IbF4eUQuruL7P84wSVPgvIZ6tjxPZL7cz/y9pZj0DnPGuapiEOBkRNX/LSCyEuBmOG7h7ZuOUCXpxVjZsRBnlDsxvcHhOCCszlMqkxm2dK7tKGlnE+tOQrth07xGJlxoKd0DsIDjzPuFIcri6bC4bs3wPG0FPiOqwKrDaHUa2XKT8LtGT0qKHbIY7fLRKDaYSV45XgK7o3bzZs757Dwe1/+PNsYHrj2oGGyLCwpPQNzgm6htJ4C7J1ejB+dc6nPdjiJfajFThMzTrCO58if2/DylWEQPeE2vronDDIeSugeYI7SfvbsaRvAtyNDeNJWD3ZrkKRbr60oqqCW15tow8u5ZhRaR6C77SFtVRvGk/f4kNDsUpr01orflgBU/xDFJmM9+P5ZDdx9t6GH+XocdtuKd6qOgQvhE8DxXiHOnmpFwnr5oBkzAjYImdCtBZLsOVqL560bj1KBatTjIIWJ852h67YPB9k2koawINTlf4E11YWgeuYZn20TpIfZE8nxwzvu7rXHvNaL3P7FH65XiYC1RRTo7O8DscTlWPPVBdJPh0Nk1JDn9LnyGZ3/sEuvj1pzEWavO8dOm05iTlY/lO90ZuvdOWgeb0lag6IMhaWo8qoJ94sags3D1SC55D58qM2kB9RMVQUPIVh4CY/5O5d+uXrRwup7KG8lDIJvf+GL0nUcJtxP8cP9Mcz7LHPBR9z9aQuFz7tLHt3HYGzrBDjw+x6d2dZLM/NtWTEL0eaxEbUYTIFPH4jP9qZzvFM3jp9jDC1X1oJ+yhTa1XcQ36a8w50fTyBFRrD8El3ePr2Fz/T50qPayfDhnivL1mei3mApDkp8BtHjIvTttz+YyrnB5Ofnud0+CGTeaoCH0QpQeqkE2fGadMTkD/voOzDPk0Opf5doUEaDwo7a8w9bQbg3/Tjs+rGa1c570LstXVj7nxsZ39LG95+uY1nwC3Q9FgkaCQAe757BtZmOFGsiwl7Slpg8JYrdjPfTtE8r6NExOfr99Rd77RgPup/yOSzbi7eMzecnmsdQMnUOqi2/RL+DWvHl05Hc9codm38IwoJZQLnem9jj/En0MwyiaaXLMPqlOH5Y68SSuTZQGKcPPzLM4Vu/G+cHTaQt1X5cKuMILUJV9FTnBndIakN36JDfqQrwe1KBb8/dsXGOM1z7ocJdBRMoPnEPTo97juG9CtSm7IHln1Xg4aAw7LAvw/qL6bj+kgV1XZ9El6Re8TyJJqjWb8ERruupMtMcEnYqQuFxSdijv4zWOWfQ+8hy2GYVCVFHblDf2Y1gKZuHTwKjQXuUCJyb/hhkDIaxStVpSnNoxjd6+pRTrwgjv2wh4zfvqDGvAOdZasHyAGfge+VUc+k3B8h/JKGl4ax9ZA5dy13MvYumDzHySX5fNB4Ek2cQH/kOIX+us03nUu4w2wT51isp6pwcbfvWQh7zXPjlOjUYyGuA0MKhHFllDFHNb7Ai5jlHlRzl1i0+9P3WTApIGw3u10RhytZiqJC+i7vrF8L12fk8ueANG0Rn8ds9t/nvGVn+b1kog6IuhCRpwLQ1gRBu8ZBz34ezxOQPkHk7gwTeCJHBpv0wIGrKEhEIWmtf0pOaP9xht4YsTh7nk3+NaYPxBbK7UoJHx6vgg7IciFUjuFPugF9N48HqifrQzORgTJcbXt1ZQ9NPF3NZSjZLTnnCe98imKm+hlmzRmNUihQPRu4ly2OF9DcpklsTF9G44h1DfvWSBcVHQ+8ZMTztPIp/OZ5mF6ccsn2sQ/mlJXBMdg3v+dROsS88QOqiLtg2jGW9jUKsp0Ys/fwlxw7cph9BduA33w/LLtuxyHwJrNyoB8JD87WjWxq3LPjLC/b78+e4sVTy+z0cXuNPIlcM0SJZAX1jReBYkT02zthClHIQ94dbUhQO4wDUoI7BVZzXf4r7Y5eizB9xyEjcBa735tH7WRZ84+8r7JvpgGaLgiADjPl+bBPPi3Um5f2jYV6JAyp+EyCTU024fEwVtfgtg/Oz38LlDVIQuSkCvjn2sYO+PhQ2NpFBpypZN24Ec8kcTFe5P5THv+kgLOal2xMg44E6/HUzA8MaadTfuh62Lk6iH4GhhGuaeYP8BQpQWQPTxhdzQukfOFg7Bi5JbaLBiaW06eA9sMt9iK1OViypdQf8ayTgkpEEjZqUzdqLxGHTDEOuGvaHmoe8Q7rBl4r00vnosVN8Jec0vtt6FU4Pf0snhiFMD02A04fa2ThrC7sHBNHnneM4c/RsGG9+C3w+zUfXt8mc1S8KQj3GuLrQnOouTORq/UE4ZxUBulVJaH5zOM3yM6HvzpOoaMgXXHo/0KppVSie5Es3fr6iTzO/o9fvddjhsJRaPd/C0u3lIDdRGkqFX+Bhh8WsE+FJRYf9YPCcOe4WceI0yRloOkELD1UEkMP/7p0GX+OZL/aQWs93Uimp586nA5Rp3INj//lxTcUm6kuZASU3jMH8Pz/crXSRSzrW07jYHK7wHI22Dc5YNXiH704fg0L7jdnoogAY1eykmRoHwGF3KI2/pUuF9nd483IrCtqxB5R7PmLOkgSoUlSEhoVCrHD2BFS0duD9OQ+58ct/4PdTC5x2prKa01E0PtuNfnZiYPZnDlTM04XmSet4soU86nywwljDepKIK4Adiltxw6uJfDhfCqofj4dJZkG8MegVLC7vY4uD43m/giauO7UPQ1KMOaZpFgs0KkL8l9VkdPkQTbr6mRQf58K723Po65odFF73ip1juvE/JUeU61CF+rM/seZTIOwMqseYcXNggsNPnFP0HhwNutku9gifaFjEhU5yMGfWDUo4UkTLpy1ECUk/uu+ki4krlTBi4Q1ojO7B4hO5kJSmDpe1VXiv1kw2a3Zl0UnLuKTv91Bt7eCf3eU0xeMg5d6zpVRZE+id+A7F726GhQe8uMHHDL7PrcRtU1+BfPktmmt/nooeZpGzuRmM/JoGDUGhvOudK8kXJrN5xzS6ol7FyqopcDNxLEu9V8TkY0Kw/7g3b1KSIp/QJH71LR9CZz1HYd9ZYPruC4t++QHpq9eTrJEERB+UYunTApD4QBetBL+yqsU3Hjmnnh3s8tD/STDGngqkXmEJuHlnF9iEPoN7eyU5Y1sMND2JJJGhudr3UI98TEezxA5tOrLQGM5n6lGo5zpsDzjMNwy/4MuzI/DBnGrcHqNDPW0dlHfnFeaPMIK5agPgfWOQtfNXwYEKhHWva3CsSCB0LBEmqb4lvMfoAg7MGQXWhY9QSbsLrtenoW66OdDqBRByqRG9F5bhsaatZG/cSdNfaEB/5yQweT0Z74eOIwFbX5ge3gGzt+TymLbnEHF6Oy4dP8DmHyZDi7INuFz7AWv0qnGKeRcXr9tHtl/O8JfrwnxWThr5ly4st1MB9x37eBTfgl9LluJP3Yfo2qlILSo/wWO/Cb6t+gfnfC34eKYK4C4H/rQ+EV1TL3NyqgAmPXrOjRMc0NxjBhQHrYC+HTsoYSRCuFQ7hvb/5NiIfKxImIMpDyooUnMFX9xoBGHemUPMcYW6n0vAic9O6DBsPR+LnY7H38ZQquN2ficsTsFzllNBhiZHbx1Pac8tQK3dnpKizLBbtAjLTIllVsyA9Z4POE7yDBTZrgPH4b9o10gF8Ds1lzR2D+DuzydBZKw453cqgNz6cbz3/U/wrb6J85yv8cRARTDQCuGuIW/8vXgvGijtph9rHfFk2Tt8kxlDjzbEUb+yNn6dMhru2b6jPVcWYHerOcqJAeppV5FI1WFMNShFo81byO7PMRaeZABTJPsgZzCVNUzuwak6BehfZ44Sk4dzVrslBqRdp5UWp6jbXBZcXAzoScphCjFSo8/9ZnS2zJ8F5ZLxR10LzxYRhRSugkkB4+Aj/4S0F5M55rs3yJ0w4PwsFTi8Tgf8/uVDwl5Nzj30DGprreFM/ARo7RImZ/kDrLYoko/7X6X4NCUcb+UKHe7L6PPTWfi5Vhq6Z1bj8ccqsDJLElb/FwgPN8nxsecL+NrUEKr87y1eFyoH9f1i0NzuCzXz+lnQqIG7lRvxdXYBCdzZjWJfZrD/2Zec136Zj7yxAH9rKdbuuYvNCq48NXs95xRvJhW7S7SrXYzazjRA7rJOND5oDGW6rZjxaCSGvGmE5P7xwD/L6b7nEbwm30WvL9jir4QksBltCjJbDelSszD8hTkQOvMfhc9+gFfOxtHBwM2w5s0OWGXdgmL1stC1YBW0XAc6phJG5aF/uO3NJdh//xUJuJlhsbkIvH5yG9p6R8C8f7Ng3vqZZGKdS3M+xfEfLw8yPb+R1vfX467Xs3CdihAnmimD2LoINLMVoAuPNnH0NznOzhbClvEScD1/N5OtNxl++sw/bSeCd7QpzjVfwC9OmUBMojHGzJ1BUtnzIXJPO975GwujdY1omLY2bLHezc0DhiDhX0xJb/Zg7rxeCjlYQMor3pNufRbb/e/fYq0YbFB1xSUzKqDt8QuwVh1BCXtjGbdPoTHlXtyaocUrx16GfY6aMKVmLimeNYWy6WXctiycGjCWxV8J4OiuFzTruxZnXe/kckkp6Kv6TdtuGqJ82AYePcWWlDzl4Iy3E0/MyoXBvoOculyetY7LgMLBregyXYj33L9O5EG8V6yCVl8gXHVoNfTWS+JShbWw1lQIoq5r4YHF5TRseRX2L0uA75Hd1GQyHmOi15DSPGWceNuC5o42gdPhV3HKzX00fLg30YWjrGPvBjR1OlRr9tOxy658//YoPjZCHHbGTYNTDi28NHo4WisewFaNEJw9KQ9nWKTyvm1fMdxBnn88l4bZks6oqa8Hhv9SeF5OJjnrqLBpVx5LLLyK0T7nWD0rmL7LmIF76hYWlX8OJ2RugNNWL6pWvU+1Mc34dGkiyH0vhfkev+lI1UionLaWBQO70Sf4BFxTvYXPZo3jJRu6IbhWkE9vHUTno51UNgMhXlSdZgiqcfHDdv67qQKOTpvEQo6jUD/GAXdfLKeGGYm8ukIGVBb70NNCCV4gms8//HZw/teD4FtSDLMVptHqwjks3TMZJd7Lg+yiC1yGH9ChzQbPH23h/wREWfqxPVvuFqeq8SmsY6BF/0aPh0zza5isNxMcb4vQvVQv6M7OwZd9L+BItwxN2PGI06YegHFnxGDggwfbXI+C6/bR1LG1nqtG6+PP1DH81PMiJg/tYNAMYZhWIwbKtz+hSkkSdRbl0KyIrRQ0YjbZh/2g74ctICAqAPp395L4KRHQa3WBuA8HMKViDNlPdaHbudtIU3UPmLnm4IZ8D87ViaJpwWPhwZ0DIJf7GzQfnYUWtTRcMuTZjWGK+DpYDOvWtvKYV6PYdKk6RIzZS24fz9F8JRs6tPY+qAx34wcDC/Hu2Wfs6CdHLe+2UGyNOgSOEKGgC/NoQ1gCTte7xFEnNvFMCTU6b2wF2pei0N4kA2WqjeBpzgAH/dbEh/75fCpBB84P7aBvbgk35sijrJw7+F4/NMTikuA6TgyeV6aC3H0ZPr2tDj6rl5FWcQh1t1ziI0oFvKw5DS4+ngQtNwHOn3iLAqpP4KlhLLTaZbPLVTdeOO0b3Y9OhNroXNxeOQF2nfbFijXVZJF3gGtwMi8/MRPWmWjDFe85BGNKKGHVPuyNHgknPhpxadc6SH8zldovn8Jz1TlsJDYXnEWuwMPplZgRL0Pv680g3ckILD1vkk/JZV7i85wq243wbE8QWAy5ocvHOHbaPAJGxI+G6zfcKfpoHybtuoUlt9tpt28/3TVOwzkR7+lGegBa79NE3TZd+PrgArjL/QcRxUg1w4/gsl31/EEmgsOqXenOswRoSLCGXfPUoY+GZtbbDA9oT+W1U2KHvtcIZy76km/4GtAoNoc3WutAPmAY+K32ABGZ1yzg2Yr9n7aQlEcbP1rjhA1Nf6hO9Tu6KD7BK5ajQfavC5iXh8B/917wl8wsfLisi9YcyUPf4m2QEDCJxft28SErXTi2J56Thv3A8I51tG9jD8x4YsZtr8ZTnVEKDleoJYp24XMO6hAq9ptKn43j8jvaOKf4IYU3yEKEsjy3DC8gGQEx6Pt3BnOahCFufgQvDy+HjEdmtPfnI/xQUQCHVsXCp5+h9LHyASVf94NtNRMhfbgwjLdrJW8rCfimlgpOSrK0/1Uo+V2+ir6rX+FfqQzyTR8JdjfmwMzTdijzLIt9RFdSpOQI/D1LknM2amCwMYLLn2P4fxScZ1hIjxfHz9AWDW2J9i4lKRo0pJB+ZMtsGA3KzC4KSQhlpJTSllHISrSs0EBTJVEkRCr17//2Ps99ce5zzvf7+by587PNQCxdAFZnn+dfKw/zghVzMLd1Cdks+Q5hX0145hNtEBy4wqW5ypD2qRqKvzbDsLHCOE8zAZy6Qtji71RQiJjNqhE/eNomE85aMgy0ytbQlaE9PPJHHTqTNrDWTHXa2H8BMj+u4uHrjoL7XkV+HigN338CCha8oqqUhRSfUARLmyI5p28b/brhjp9+dPDJ3N2kKywP1oIm9CXDAg2tM7l+uD9nD1/BD7dEoa6mCm4piqc97eZU82ACWPTUs8/hI2jZ5ge/1wfBAvPv7CVXguvOluHX3h+U+uUtedaYwxMxNdDqnM8G2vP4cLsHjwrS5p7IH7zuYzXpZOlxaLQLawxOAJPXI3HUbX0arNHm2qKRPCf6A+71S+ONj61YtNQVFbxLMOrAFPDYspJrt7ri50+xmK7wB379TsFj1zYCeA59L+t+LDEm3No7GbbrRcBJ73T8db+dTtQnkbqCM+m8sONDmXeg69RssnPNw6aVmvDXoZUPmfzHFZtG0OzYSlY2Hk9nhn/mLs8aDlVI4aNbDrHSE3nIOJ8GP3dmwfdpj1ByXAGNPOfJ36aWI9mMwZH9yRDQs551g7TB8CPQnZ5t8MvHFTrOh/GENiXOhY+Mza1YTEXQLJTJEqWiMLo5ng06WumS+EW+fcmT9jfepb2n5EhCYBfv8LVEQdFMvvBRHC5YVsP2/5biTa14fLXbDct/72DRBS+pd30ByU2fBtMkn5DgA2WYHN5C9U+PoVKRDb+6tBELqu/hzeceHLMpF3qF5tOBPAOet04aevVlcbPsc6oztoHFz9bgnH4p6ppvyI8nhfMah1i8ONcT9FonwdGEMgrifChoysPxBxLALf4ETpqXygnSlRSLKeRW1QmzvARBu3s6/00Jo9tbv+C7zXnYcu4mH98gBuYjPkLrlziWH56MnzTHwLyB9fCcppOLygS+eD4fIlbdIMHMYkyM/IwtD3WpVEsV2owBLMokMG9LM+3cvBpmBHqyftwMsBw+mQKvTMQRy9K4XjAWbhQRUEYgzXL35b6lB4ky6+iOYgdZ2kqRnpQ0v3N3IuuchXTKUQi6jn5lje19bCo/CfyDlnNBTS59iZCmCJXJKHy8HWsbN3F0/WQQrfxLbd7a9MhtNnw1DIb7AeMoX7SfW85GYrzgAOQ29fKuPAQF51vodkgAhaXfsu0DPXjZ4seFm2agrOJqXPoJIPrfFkzYMBpmaxdj3aMcnGj8CTZWxuCchUPuvHSAx6TnotmNRkiO3cHaZfrwtf8Gj9+5H04kTOdzAYfg+tleqmp4hV4tp+gb+1OK2Q9Y2DYCvj/4Cv4zc0DGfBvM+2LGBl8J+i/M5h6NkZgz5wC9XCALq4304IilFlx5U00rokVIMOg0rhLex9bPcmnZeKGhjHuOlW0W4KQ4AmRnJ0Hbgz04e9hX7MVD+LNnH6a4KcLc9OHg7/WJHk4cR2XjteBytDFHpbvzwWNCdLp+JbqoHacJ905g055SsJ6rx77aK3nBFQY+oMMvq2bhqxVvUL9zNOt/fwHrvApx0t+RsPPMQ+he645mu3TghmMKfirLw6VHjfC+7j6Oez2Nq/eMRFMzZ4pp24bqf0O5MXEKlKWcpIhxYVA3ooYbvWPhUtA4KHi1Exw+X6FhXz7QVlllCDWVhFf8B3tgC116T3j6eRCaTk2EqWqnuGOfJONGMW6eV4JK8ySG+siPWw5OwLfPa2FW6BLqHrBFsYc7QfXubHhYfxM2SldT6H4raF31kmQOt6Pt2G+8oLKJK1fcB83tKdQ7dz0oPovm5aMKYNk3cTiVmMNPXJKo3tmOtD0rMd1iETgFeoJMyWbc8fY8O65r5SnbRoLUJ1fINxXCqeVuNCkmlSznP2KjKln4IjsfP1t34CKPHByRNQwWyf0j98ZYWuqrDHPUJ9BVwQqwlxtGB368R5HqDFrgOYPOjpGDE6LdMOmdBfbOzQb1BYE4cPol287Q4dkHx2PNYDrmhJXCq+XCEKbsTvfSiuEkhlNv31gW2bGaldZkg3TkAnaIuc+/FMLZ96w1PDWbwppPvclxqHOFjNP51dB+74taxHN/1PCbt3chpNIck2tlwWf2Zz4zkmHn9BoSN8/iWD0pfrnoEU7LvIxdYfXsZCAFIgKjoEvRlk92e8Cc+M+8W9QI4997wrnLYXg5uZ1HbH6Cx2TNYfxvMzAQWMMJBhMwoaEf/wT5onunD1iOGwWq0dlc0bqSb4ifo/TF0rB2yTpckvkOzIrDWKjjH4WfjuIUkzNwwPAMeuvq4t5b83n10P7tvfYXa2NPg2aoPiTnyJHg/Gw++GwyFGlOpSlxEnDtgAQPHhGD7j3vMaU2lb1mL+KFzqoYaWcEi2cMkL/VUjgkoU+BBp3gICQNNhreELqlDqJOXoGMK2LwMtGbpSTy6VWPG8xZeoz6rFfjtgojaN6fgX9cXXBPQTcIOBrzlL834MS93+zsp45BHW9hn1cO7I4Wh0FDTzogrTR0a38gc+Iq0i+LRJfBnTTVcjbM0X9BKhezOShHAZYob8cVwn5UWnmBhByaeJjWFAjYch+Frt7B3TvkeLWKHd5ZpgouY8RJ72cl+qsmgvbJNvb1rwXJgaO07XcXHhxzAi3jvMC8WBqC3MPRXHEztrybhGLPh8M0jMHsxDC2dUJ8urITS0UfYsUVHfiiPw6nr9SgzFZTniPVx2/Dv4NUz24+9DaNrOOCOCI3FD/0WMNj/UR0ySulRedqeWD3DAx7tQn74l9gxbZa3vVmJbULviDDiIlgc+Mv5ipepJh9H/CaRwwfNNbGKdNS8fNpTVR2TIPD+x7AntsENk56ED/+E5V8SqGHL/bzqZ164Ow8F+1kD7EkNuArr0GquGAA9vN/kVVaNv/3biPYnXWCDcsc6N6O3/xgZCi6H7Plvrg07Nk0DK6EbmarUzPIyCYUtOZH47bRz6DtwheSPRQEidOmEnkE4A5dgowpD2iVdAqlXA0jc2FvyPc/RftDj3BKTRK16opwx6xM0D1uDrOUBnC3rAPaFStxaX8wvKv0gk3j/dD3pyx47R5PkvUjh3xuImzYdgX2PpcAPnMMdnlH4M68cXRYOhQvu3fD1uU9JLFlN02o0gINy7vYMP8EH7dcj1uvzaGi29twX7Mu+Qg1o8GUCni6K4q6eiXgyS9vkrHTQfmx0ty9QpA1MvtAwqeKV/qd4JN/z9NYu2pQ2C4NA//S8Kz4VVSzPAE7DgTznfU1OPndX2yKOc0NN6fy2IYB3gdCsLqvnyZu/k1a06ax3GAgTRrWy6Z3HKj3sjkvnXQCL86SJGtRcxCtegfLhNeBt+wDVq/v5oqdFpzqoIc2+w6AwuxQeKiYTH6i8hD2ax/lhMaD4lgzzqubxrmVKihwPZO8Ep+D74k21nBwwqYfovDrWQN8CV1NTrEB6PbjDx+tMQL/7iscOKCEmbpVnGp5B8WGSUCt0Xmmj8tQfZIjtsgc4Z8BpWRxbQ08emXIbULn4ULTJJadPQkaI+fgodV/wOFnA0mHP8e4JY5Qs/QaZ+yxxO66i7ikUI/Gmk6B25eS8bhLIKXOVoCO/Kes5r0eFS8H8jhPQz7QOh7GvpmJI/WGg4BgCunZK6PYh2j6nSUElSP98IPjRbDukMbTU2fCnOL/sC9cA2zDZ0Blw0qcUBfPqxZ/wPo3RqgV0cNbOm/x8gFPyDe7xXHzALSCK/ipyExcnXINPOUfscIlYZJ7kk79f5IhKCuS358z4bjtyvBhryfX3l4LaQ9ywXVaJYwxPsyztYrxTaQS9QirosTxcJ42diQ8KVDGkx8EYOvemejtEQhTbtyCzy+r4P1/d3nU0h14qSsAq6aYgEc18f3JBzmmYRNoanvwy2x5nNv+CyYk7OBjkIJhK2+jQoYMdAkdw8ITFzj1jjlt2zGLHuVmET7xRPevuexSLsOuCoIQM9oERiVKwQo7SQqoGwUKBTdA6Yk7H5InMNuphnVSOpi50ZwOPJsEqdaWfM8Koey3CkjtW0eKxx7xvkn3IKzRlt+OcUTZth/gO2gFUotKSVFZh5wkw3HVmZOg4FgM/esKwLM5m1QyZ7H91f/wqLICrNqdg4XmbyFMrJ3qO0xx99JqeH3RFqQX/eSMGmU6+GAdzN9kDGFVJ3C3kgd3FKwCwUmr+OJMVUzrKIHs4oe8Je8FbvvqxkGto8Bs8hSoXPiejy+ThIaSDTj78X4oF87g7h1dIHxZjuLMG/jLlRGwdWky3l7rStmnvsGi6fdB/X4j2W4YhBZnSdDOuwArUA3v31KHHa2W0DjEsH9ynKG/OQuTrg3Hw5ox7HM5grqFN2Py+9Gsri0PZ311qNBjP89KUcfG1Ra87MIk0k56hz0Lj8KT3hiYWX0fq+4Kw5/fSVyW8A1vyEnBgy4pSt/4hzvnSmHlyJskmHOatwzT4XfeZnBs/FQS+T7Ilu+mQ7nPP9R4NJPa3YXgQMVtpmk+tMZzAB2PCELyHhEo/n6SfW9P5UjDn3S1VxlGK7eDvUgImr69Tgv/KwcHNIGTAcVwyHcNKj47To0lFXD2qgUFmX0ip3uV7BX3g8qzT8Hyv2aw1+sWrH54AUdqVZLh8PWYXrETnw78wKxlFtAZ5MgzK9+xwCwpEJ6+kNIOzIEnP5fzVql4+u1qyx8lJKAzThFGN/7HLX+XoO1wG5CbGEtrvQ5D4npBKAJtUtg0maUMI0ilZDc0XymkuuXRXKstDnOqg3Dmt28UKqJHazceI/PJWrD2ygXOPXub9+SasqhvMs6ZIwiXPEPRZdcP+HnwAE02f0linRcp4LI/mKQ+pMU312Jw1UFUMVCBmetyKehjL0+4/hTmndfF1ddG86M5ozmnzhcmh+zm6XEnWDNYHM7fT+Hk86UUdnkSGWg54ZRbgfQlOZ6mp4bzwBMJzFo7lyWiR0D6jDj+pK7La5w6uX2ZAH/KsIRn/ZvI7GgLa/XI0oajUXD39mjo8hTDGMPLGF1yG0Jbf4LBs/9Y5kYgz7VXJ6/u+agxrQPLHk+AdTN0KFtNiMee0YQL1Zn4esgb28eJokxcK9ut0IZeM1mibjOYXOkJmm276WTCFKidVArvRMI55JkZKJscRq3Z5rRn7Q740z8KXvvX09XP7RCc9h3Sltuw27DZ/DpHHkZV9HFC1hEyigmhQ2eFYIqFGM3/pkPXXlThx6tB3PUqCKsTAymooJsTX67ApS/3kcUlRTisEk/S/0Xg6f2D8DYwmcMEXcHxxBPYrn8GZIbNY6PF2WhrbARPtV7w8oQ/9EI2j3fuq+fUwvUwV20yHzoTAv8UF7D3kkn0z0oBvuf48O0HDuS/6inlxBux+/UueFqpTxl2vbRMOIR3zjwC4kqCYNdvx/Yj99HdSclQaDEND8asG2JWTbqX0YMj6++D6ANtmBcqAM+W98AJS1NIcMqjf4VdYObmjZWJT6GiawQr3WyBRceWYa+pJfQucUfYvJkWZXqRQ8FU1v6yFrOOl4PHyEoQTZmOqx7WsJ+XEMx2asbYiiZ4+uwtiT27RxcTr5Bo/XWc/n0FtIT7ks8RoLvvpsDAvVDwGKcEpnVTOTC+m6dUu4DwqM2Q0K7Ig/ZqML4rmPef0YWzt25AsrQ3bJ2XQ8OqN/AwwThya7wEJVOUyPmsLEZ3tfCekbIgnBtLErb3aFT1Ydabk0GiVwfwyZUqcA45Ah8S41m7zx8HG7XBtzIAVZ46Ahqa8cITerTB5ARld8XSoVG2XOv9Gy9VhoNfO8HI4Au8oWwL9BsLsr+wHu7rmwhqBduhZmMB6ZjGwfT8BDI6IwP5t83IMlMSau80Uq32cF5ddAk3LsvAxfsfo/s5X/DbkQabphJEl03FUXCShPTN2fHzfzC3YDweWO7GLqdvoqU2woHNimBdrw2TgwVwdoMLvtZxx1UCPnBr6kUeNesR2OodxRXGP+BVaCf9zDCFW8tO4nOdjRCb5Azfx8+k/4byI/NrBX3eZokXNUJQCWzxxS41WLbyGCiMycA7Cq3wsPw2Os38g36qv/mkjwY0KnhTx7YELng5Fv5mm+Oe/Sr4OFqDUl+MxK0VZihcUwp/Ux7yhXOl2H9ZjV1GakP1NQEKuFHBrhOdYd7FCLw/2mkol35BtdYIbD1hCSaLWmm6kgWsdnyKKkdPIsdsJ98aY3YZfIaD52S5YfkyfBH1AoIH16C6gSQ42snRtzXheCd/C8g9l2CLk0l8PGMMdId9B9FPuRiy3Il9rQRh5pNE5lWlbF+WBq+Mm9HVM4mKlyax3LEjcKq0FTY1ES95KgjmJt/ZVGobjPU6SwvvPsenn8IhuFiAYiga233eoPgJS7xlqQZK7dWwUaaO/mSKcZPqchyd24MCXZtofchIkBhwHsrYPuzQGAtZbQug/L0zvKzsgkVhnzlo5je8dHw9SNplcLO4DDp3d8BKJxvYoJeOVaUX+KtRIZ7V240nR3fBLkt/+HA9EBwyK2hHYilkWKvBNnkHkFJfAjJZfiCzxwh23lOhAQsVbJW7AMU+dSSybi6+nzQGptXugq1RfuBWOhJnXF0He0y/YcWJa+Dt/JW3ePziYisLlnytBnuCmklxdjHJmI/ksue5ELbmFj/Jc4WWfXF80MmNRu6NQAVHITBvE+P8ZE36U7IJrY9W8+eNR6kz5AVM/rUX1mQJkklmJWq6CUNc0wMwf+uOTnE76cIVN1jm852gTR0dPU1o+ozT6HFpCty/OwLyC0fh5jGZUFIrSR9WF9PO05P4/F9xEKjZTQkXX/CqedHcVzEZeMxeuHTBnqNjmuj1/EjOlGmmureTQf2JKX/5F4jJC16Reo4ZHC6/xH0ro3BjsghlzNXF6l+nybbrIWsKfMUVMRfxvx0H8eMdG0hxWYKGKrlYcG49NV3QgDTHMjSqlIPZFdNBaU08SGaI4hw7EchW9oJ4y8O8yb2Uheaasvn84zjlnzIoi41hwZG+tFT/ND4SVIKCghT4M/0ZHJkdCbIFIngs8DR+UD4LS9b+IvVwMS5PfMlX67Sg4pA4a61Kopdm+SDjcpBLK3Qo072BFE+pQ8PZRdDlf5u+H9eE/sVX8eIrH5Sp3cUtiVZYuroUTLeNQr+Cu9RjL0QjS2JB5aIJFET+oRyV/RwpvYgWe32iG6HnsMZ3DWe/uA8hKsH4YdxrCBAQgZCAbhifsB4OmwhiwVDfFVskY6fIVTyko8SVx8/zDSNhuqcmDpl6KRynuJctv7fR6mGnOPFRKPbXnIZ6rTbIv+7McnM3Y6OHHJifsaePDvJgB6WEM2/zLUd32PHYk3X8dOhLRTU7d7wmucsqoH+tnuFVH4QURqBa/EZoGGGKB0fV0ro8WQ4q0cDwcXUc8dYI+gw9YLT7Ix69PRPX6uyCDavT+XVJPrkrnUfdzGTYesiIUiYbwN2nj3mJxzMM1vkPLgarU+Kt6TgxeRIqhOuiv/A80JVegHYWUtBxKBqvprdCSYAXv/8xn+vjxEFNZA3JGk7kn47/SDDvNDfdZDhYZoUtmyxhlvEweLXADbu2hOC/7TFQqVVEIP6bNskfpL/OBrDinRs0WClxQqsPB5zOABfRAfAaf5Zdtk3nrW8tIHGzKkqaEtS1tqPU90r87lcF+xcL8O4tr/Hbsz903sYVFz/Rhpeh18Bi1xhY+uQkGG2cSHcmJ1Ej+tGoNSUg4ZhECjM0IdougpKuvRyiMxs4skiC1B3tcHXPebiXo0KrPoWSzQM7dh/1jxQOvKYZ7yMw7YQYqJ/Rwfy0VLq6Q43G1n/HU+Ff8dYhgMBXOSQgNIzd3CTZ44kwDC8bBUbe3jSQpMJr25xpib83SAyzIu0xvRi02IE6XBphmrs5FHkZYWDWRJy1Tg5rLoTij/lP6ZJ7CVjMl0PdZmsKeGtOK9TNIXiXM9p2mJBISR7V7+jGCw8suOiIDa9qkeHRp1WhN9MQXj4TgctxuzDLvYasi6tordk3MEh/ymfX5eK89i4yctcE1a+HeXesDLTqn6JrJroc0rEdeuS88YyiPsS6FEL6p3i847sYxBWVeNRjczD5copv6pzGT2VV/Dm+jY8INPKZqh3srZYF1+wWYMmSMZRYZwpG1Y/oxY8E2NfWyQ+FCFfY/YW6qbbce72RIx8+5b03OvnQRUEoHrsEL2fEwqaRy1gl3BerK60wyjiKVadd4suzPEAat2AHqcPC6/9QzEYTcldJUbzRCfwQbYPySlXs7TEHbqUWs65LBeSNMQEl1ZG8p06W41fk89GohVC0SR50pxnibZ8EUHC/Qws/34CVXxTgnvcqcjtSzu+uL4e+VGdsklZg+xd/6JezLI4+X0F5Wq7s/94CygxcSK88BWtWt2Jp3Cu8o2uMXiVrqfitKFsHKcPY4Q04dpomGI1WpJab++hKaSOHSYxgU71+/pnwjt6WHIM8GWfylbUFhfHi0Fciyi/uy8K9P9E0wqYP31Tdo+UhdihfKUC8fS0Khu3GaX6acOVFHK0UKaeVjxbB6nMfYbNSHUT/VSexN95or72BmqTKYVUZg4T3VpQa78c/poUTtaaD7jM7ePn4Fe1fH0VJUY1Q8HQO13RIwOXKBnpwTw3W5XrSy7wrVNx0iJWDDuNDmoqxQYU83c+Ky9oEwP9TLLz51Ui3w2fysh/+oJZ2ky3axTnjcBM9tx7NM7e/Q+0CLXCqtEVL4R2s/6WBrkna45xvf/iorSHvtPoLFml3MCpoJokO3YHzXWGadlQG7q4UgatD84jumQZhl6bj884B/rDvA2UrXCeDBEtoH9MMymtn4IKYLWixJI9WCb+H13WSEDLSkfo+DeNDUzL5dakERKbuIamALl7mMo8+bDGkNJ+LcHNVEG7wnAfjy/KwvO4lTexCqK+XxpSJU9A5sAWlJ1XgpTdCGOe+FecXZNH7k69Y1vgS+P2RAtG/37At4BTcOBrMZ06mw57JsdSv8RC7ddQwU1gBtXJPwrBEYei/F4y/x7aAk8kH5mnzQdNSkTMm5YHX3Fe0eK8I7NsmxslfAJ7I/CGDyck0duIKvG56F7rff4Tlk+bAmqOPMG9UM5VtGY/P11rC0aImTrmUCM4VYvzk0EIY7P2BDl8fQ7b2bfaZL8LKR7bBhlZr6P16HrXuFPIeXyF65t8I5aU3weflfdzrfY/NH8vC35C5VOmjCVnXLckt5R38TtvKdunDYKqXFMhMekcFd/ZAksM/lnm3gALGMdzKK2XfwdVsrV4AguJJdG3uEZS5PJPmJRfyMc0+3FLlya6RUhBkNYmKqIAU/L+B6959ULwki7YlnoKdlV/479qVFJb+lkpTDEHvRDKbTlwHX6ct4XusiCbcgya/dWkbfsdY3UbqOmjGaYc1YZ5bLe0eZ83/Dp2jY4d0ILvXGNOn6XD+gz6emvQYNJQeU2iRIvTM1YTL66pgvHcz1Db3UOqPwzi64x0PmziCd3fW8b+I7ZypMBIaKsro7rOtoKHezUGTffCB6npota2gsL19eC7EEAXnf8TRfgZgmn4Sz6UR5Ebd5DKdg9gxcIDX7n5OnRXDsOLSerzKBvRfpgasMS6AGXPVaa9fL75YMJ+L+qzgNTTwnrC1aDkxEi4kZ/NNK32Qk8umlqpy+LoiHQNtcqDK6wVYLK8F9RupKCiym7Y1nGGl2aaQIeRPE5XFoaV+Pnz8FUL3TEx5+5OvnA565DXclwJybeDUTmmwftLI9kppmFmYxqLenqT0eSrsD1engDcXsDo1hiUWLOAXQ96zZb4VW4iZMdnMItnoMvD4rw7/qv7k16FzyHxHGLz9sZROKSiBR20mj6zZRbnqAvTEbSK0vT/Fq/0U2K/jJ1x+NIOuWsXR+ceasHNBLSxvNqbLMY9JprOLzmw0pzeS43nDZwW+KnMRju9UpGfP9eFUtROdbo2CzW9WwQ7bYBq1fpDadbRBY+kZarbSwCcWO3i5jgBseZFPL4Jaye7cMpj1y41PqS6B3yW/4FDzDbyW5ALJo0M5WcsQClfd5GtNh2BquToWjc1kla/f6PLRs7i/6hlF19aj2EotUlmvAqH3QoB0RGiZhw1EinzmOarm3P/5CbSENHPBugAaMXI13nqoDiKpS1HkigvIm9nSLNGvOHNDESxyW8BbLathXtQlmmhjyCs3a0OjjB5yQDUPLL6LK1YLY/38mZAdMw6KxAxozukT5NJbh/fnAaRV5dBbj7HUF5CPOXNfckKVCe3yXw2eAdlopKFJg6VR2FE6DDTTc8g08gNuCRmDY+Z/h6xhR+GgvS09dVwE6kmJNHzRYRaPEoQz0cX4ciCR9nVP580qUmB0yxGoeQaGpe1hZVML8knzwuuxFnCu1J8n6/nwPvmzJP/jPV7LQqqT+o626dvYf3Q8PhJnyrs7CkapzofFRT54avFF1pQ3ph8Lx9IW961U1ygLxvsvQnK6KJe8UoBzL0+y6XJZVvj7FlZ5q1FdcxhYWq7jE3YtKNkWjFu/etBUWRPo8XiACwyjoH3bDX5bPgaTfdrIdnDoKrYO+Z6yFrWEFrCWrw00025SjgrnfOUT/Db5AQpY51KCezjXHnDlXYPK0HZZgzTeSMBbqCdVhXd0K0kd3/XPwMVfj9G5QideeiaZ7aas4hys4baz1iA70ZbG/wqBbMfLtAdy2TXdCyrcden12h4I8wyHlCmGcFNeBZY7CcHD8GHQYDjkYqflyO6nDly2qwX9PE3IWR6KWbpCsOG3Lvgu28xbl00D/eU99DchDDeCLcdZf+YXK0dS249V1PI8jjyeGkFVihsetLzMW8VOU5FQFiWLPaBA/Sn4sSYBKxeFk9NSZ9JcPBzKkyVgy7Hx8GbFMZbS2Y+VeffI23Avjf/2ksIXWVBPWA7LbpIGJ8fPLJWtAbarL3FOrAfeeLICFzUMB8G/n9HTbxxKrk5GsYuqYJgWw6mmJmztZkLd3U6Y63ycLy9XYKVlQwxzohD/9FWhqboBpNVpEG3o4O1nk+l1pxoYmD6FyaP6OK7Bn2qt08hvsgQrq6rA5/Z6iJFOpVK7lfT0uTA3XXfgWFchrDcJpme67dS2YjGZ35wASWpv2TvuPc9siYRfNg64+epWmpSBfGnZT7g71ZJmxfwhCR1raHVVpeRBU3Co9WebK0HYrKwKTu+30AzRZ5T2K4Mra8L5yb/hYDpbjnX3qhB5tvLxyUs4XXQ9VikUwVHZajhVoIphxYo09wGDSHsCnFdIp/7gGrg24M0+ffr0TUeKQ343wonqMLYqjyfxpNHwuXcxv76qjs3qx/i71Um6YXKWVT6+wyxcDW272/CgoBdHr2fQPyWFb4zS6M5NT7yZ+ZWeB8RhvIkpOUyQ4NItz8E84xidjRgDn/ciN70+Rv2wleSNJDDcfhx4lKrQdjJBn5dDjC1+CiSNtWCDqiWZj92ME07Lg0F0IO5aLYI/jtyhroGtdPDyGfQNs8TrJiJQ27ADAvdU076Royn75jnstWvG+YIPKFv4AT20loddXbm4NX0KFE/QRZPjW6C9fSj/t18jrz/SpBl0l5ffy4O9s77RQGc/GZebgpXJFxK2HMFptRfo93ZAt2GVcBTrOXT5Tr5zsA92pLhS9RkluC8gDl/+usCgwVZ8rLaFpWyP0aH1Kzl4+mjqmP4MtTYdRdUhfnk78ir1G9zE7NQgfGHzGFXyzehR+W1KWDOK/738RMCW5HRDD/om/qUVnyeQzeMLFL7Hhw1eLsOYp7NJ4E8Hb1WNBNGMUYg5k+Doink83kcBf1/Xx+cbREGg4CcXPs+AfXlSdGNCMRc7/Id5wSqw9v0Qa9x1Y4mfZ9DpxFqyG+7I7vbbcJdPMFeM8oXAeWZwOJAhXesGd1apYVnreNp9J55uGQiSntkG1Dz4B2KTH5CtRQfdPa0PNcm+MGXyQngQv4Er/YRx1D1DPB67C8/UXOeJjdUQYdhJ4n8VID3+DghJLcK09AweCkI8oL+YdbcchshxcXDmmi8n31hGIlvHwtXP4lzU8xdNt+fRv5+F/F73IfUIyFJcyXVIXToKLROm0dXlIyDQIxDf3NlAQtW36XHNblyVMh9/lGSiyGZzUhBfgau7EvhgqyKsSvbDJU7y1OklBp+vXeVSb2H2Tw/Hk84O/A5/89cwS1Y0Gwbn7AQpRSCOChTOc9n6JSDgqQN7zgrynmOK/FfLmB/MsuY7m9Rhy5hDuPJFFVtc3gMFuRlcfvgKHWmaQnjajq8HxVO7xwHqwIlDXLkN5F7FYrHtAf5ATXTzZxY77SoacntRklkzCULPLgbB2RMhMbFjqLdv45+OmRS51J0OnRP5/z/5UKDrPrwfqIW79tNBsVsctj3fRWkl2lh6SgamzkqgT/fusduq19h6UxPbzS+j7itDsC8yhmeJzrQjeQ3KqVvT1atvaVn2HIiIikOZ8yLUpNEN2+EItlubgwDFgvsbea6bmI3jBSLhtsEpEGwxAiioIf+GSritEwKnHBjmLq7HroRWmJQVgaNycyj5cz2Nr9GHQsnV9M46kC+OKuLrdyeCsL4Sbh9dxhPjj+Km/0yH5r/HN96qg2BxH71O6aDGjE8ctV4EZpruxeTruaAbEs+/NAop3VoHJX64sb1tLjcuM6cdOWacYTgMHJw3cr+IPDiekIMHDy6Q+bQsbGp7Btpr/tB+Y3s2XLOKYxpEYFXrdcrWtMO42QH8xjIf17WcxLlCZ6Du7i1OPDNI78a+BZE0XTCWWU9jHF3JhgZx5mYp1rUe5AkqzjB7ciuDlgptGXYJXSvFINJTFaJNjcks6TucDtsN0bfyOChQHEY8SAV1tVr+FhjEpa+mwMxIO6zzFoHp9t+xd1kDbyqdSHpvbXiWPdIi242sUnodX/fKwUrVqSTC19lPaizrOw+jmS0WPOHFOjw84Qr+fuOAJR+/soyQESRsEIR1gu2w7dMZGnFrDy4LDqb2UbM4Znwoz4Ip9G/EVbxeYg5eHobQu2KQpy+dCaJ7PHCY7H5qtrzByu/qcPrT2dDgvY3FF4hAc8YrUPuuxT79sTBGu5MaF+VTnep31pOMJHNIZqtJziCTaQPv4hwppi+CFm4ThwufXLGQhTEqKhWwO4evy0wmbwtpuHcRAZ4DuKkspv6QEbBQSAjEwo7wg34HzsqrJvdx2mCEidwwZgr4fz7BDvtnoEzTEQi7qQc786upPPcJbavP57OH6/DP0VKiIQ7tFFwC6/EKvGr6ArH6N0H1tQypdQ6Q3JIY6DlqgK1n67koeTzIDe+n+3WW5LKhiMtudeBr21+UJXeI2vwCae7XHbBeMIr7VkyB8p+P4fhrNVqcNJ4KMzPgrk4e9EEKL911n+8vceXUwQVc7i8GjU8/U8RrAWqeagmpGxdy/jgHcm6/zO2J9+HhyzyObNvC5euHQe754fz1hhedLWlBHx3gqZeD6fmsOXBitwms642juZBOfsOF4Tmr8wHL03Q45y6pGY2hZLmTrLBCERK8IjhnSiiE3P5Dq+8Yw5iqT3DAwYlPZ5rQzWufsMzsCrQdCqFN69ogcNwISriYQE3psvBsrzNXOzrwYG00SGYHg/utqbChUxmfxmTx3ZwbcHyJPp/dpwY/bA5wT9QdupX/Ay2THGBfXytVKi/gI+17eLHqXrz/NJ02DY6EGyfCeNVcGZ42aI1jFXfDME09iAyfTb3//aWR8mvheGUFPikxglt7TkFcRyesXzGeskSqYfPEDHiwrYh1Rm8g4bpEunYyk5deUYbpG37Qo81rWNLJj7c2zsWcpZH44W4QxPfugGCNCJa8+Yy+xkpA9zBfzHNU51d+ARBrXwWTX/rQopDRoKN7CV5cnMiWZtehKFgZ1MZY4fiMzXR4gGGdsT7m74jm6bbl1LiiGN9cmglrpjZA6BlBmD1tB8J9abJz6qdFJxLYzVwHd9RshlTphdAV9RsraubhugiCgGZFfLATUEdUDDfq3mZ3tVH4wXQsPpB+zoKXs/mA9SCWLjOD6R3PIOKIMf7V3ANjPVphfEowC75xhB0+xdy5ZCw/FnCHj4kE7W960D3FEc4fyORbGu6w+4ELamxwpXynb6hfHk4L9WVZiyyhZZo9PKyLxSk/3mBNVC5PNU7EwAPhME9Fi6rjr2C5RTU0xiCg43f64D2PLM4pYZL2G/y5WA/S8or4kPIkHDXgS3fjjfiW+Gg4n/GClGMKqfnJLlqpZs+F557Df91rYLx5B/vdmUGGNSt47GMpcL+uAv32v6HKRQMV7TrxhOlWTFnJNHaKBdoYTcTIwXfoc8UCMiWy6Yx/FsZsj8fEImcs+DiNs2JrcGLfJz5aXoZ8tQzzSwDq6qbwpo0yKBf9DlZPy+bp5+zhi5wUG5UoQtrDw5ychPR4mTKkFEyGTR6x8MhAjj0WJgB7AoQqvsUd2+UhsNWezqUu5bt2VtDr9g3tx82kMkExPKB3EDVPnES5rwU8/Bvx2P4XVKD0icfHysPoytN8esJcqvcay7OF+nnO81gyaM1HJ+8EOJRvSyPSrck2RAak3v9DbQcX2FATSapFKbSurxbsotvx+oOJOPnPVmwfswt9NFQgSvA2vxUrxKqYq3h53E8MNDrHz22uQNDldZjVuIgNzbrgnPx4aK4cRFdBeX7bm4LZC/P5sL0Vl471BmZ5fhafA9Nz61l4UAsehyxA4Wk3ee/Bo9invxzcHrrizRffwTD0Fh8R2IiPvtfj/Eo9sJyVhKA2nfzsZ0KG8kmKWx/GK5IW8Z/0QrBfMBuW+/zjv1JqEHvuAYj2+4LxhBfQkWqMRwJ+kc28KHD18CClmLs0b/AKf9o75PtCkWB9ZRB/2UeRk5crPTp+H66fLsbFmuXwjpIxDMxI6qUS3IzwJsGZzzBxpxH9vK8DAUrbqbcJaFmEMKZV1WGgkysZbxkBO1yr6MJiVc7av5K7bjxG/6wVpPRWEP8GlqJvozGpjjqKR4b4OfKjC20qj4RN2yZwmNE9soyejEVfLTDr0Xys8L3LaeZjgO1VIfU10HZJB8wyy+OKh0MO+lMSPCS/UuL1JFj04w98jvuCpaOl4U1kFpvP/Q3ktINuS5+GUc8ywaVBABZFviC8JgBPDkqjV4MgCPJ7rszYh/o7j3JNyEx4rb2LMW84C1WtBZfG/3jcgqvQY6UKOx4K4+TifFIargjKolVs+WI+ng/1g4iXRuw+6zcZrhyLLomWoCp8G8fLDdD89qWs8mMvG96op3EZO3D4gxqe+6UN4jysSEdSFMyv/YHHYvKkJWKF2OHKegNH4WjTeFhnsxdXmW1EtyJXOPFYAa6GuMLhNjFQeTIW3Y88hg1mTC0rESXuZEK1vxfVqD+n3lZt+JbwCiQDFsDDZy+oeoItu5Z/h8v2LaxROTSvVyfpSk3n4syJcFrsOqQlFLPhKn/8/cWFCwt/olpQBnOiG3nOKeQn+pXcEm0CHbZpMF1ch/9TX8Ib922mbV3mvH/eLDi5fiIZbP6BxRVNNPWZIDzqXo9qyZEcmbuEksMbWG+9CXoaf+eUBfNx84gv3MRT2chDFrIVmzA5agO4ZZWT06Iu3Oc6mVwftFNvlDIHzkwniSNX+cIwXXCL9GX5DS4UnPSV/F8rgP6qVyTgfgw1h3Y6apw+e5Y9ZIdp1lCMD/FfhglPetoCqx17KG3dMJ536Tg2GXzjdUIq3KEyl/6NNIA/+YrgevMVXN17FP/9YboWdIfL0q/wYa04unHxFKqdKaKe2Sow6ewgd1R9gAwfX2qZW82b5mbhZak3uLx0PV1CO6qvlaQZs01A+ulHfvX2Iv8qtIIfC/ZjwfEx2N13FQNaU8B2/yAvV7Tn0LMa0DvEqiNnCpDUjFRQUIrg0w9VKc6tCt4vsOH4exfJ958lWW6UBNOqVRRcUYUWOQfQ31QALCSNIW7XLCrIlYPPXrlUu6WbAoUngMejo6To1Q1X49VByC+Zi7YLwtIDk8Di+CpOfdzFBy+I4b4ccYhaYAepP8sw2zkRDjxxQ4Xrb+j9dWsItLLjvcbj6FXJGJw1xHUtSRbUXp3Dk8N2kuPhXdDfsoCV5zrB4XfnOGduPq6Vk8a6GRZw+/YlKshYTn5XpmCx2gD15cuwpuoMDnr4EywqFaFLKhLH7ZAAlwoTyg/049vbhWF0TAsmjYiAg5aP8KDNPJzVs5VvfcqkgK9KMOJKAC9MCoCA6/Pokv5oFvMbx836NyjwhAkajKrkwpHn+ZTQOFD6/Q0jAgAOr/aAmMJMnN6tSWd8YlneUIzu13yAR58+wLXy4fDq0lV4t4pgm40ShW/PB2fZhbAMd9HdQiMKPj2DaLUAX7plCPFDXvg3eD2LzloINUGxrPLgOL0Oj4WD8U20PEAWpg8cx0QbHWh5WUwbcm/DCoNuHHjpQY1vlvJbSX344bWHUh4/4jF6CXw2yAaixNvwQ+ZkvPQxDz4vfQp/TVeBxRsv2HxyIU/Zz/D8tz/N0BSEJH8h/DeuHf2iI4ZuJwDvr5/E8vXPePKup+g/dQFMeHmS71eOBY+SBmwMeU1S60whUHQtDBPv5TtK7nx19FvuPquDawye8u0RFnBrUJfPNNfgq2mJNPAzApW65pCDXzGJSMayl8VFGpP1iSd8EwPhrE4oHZVNFb+OsHHPCtR9PZySQi+x4vgwPndQhqu16vHEYyWQjI6HpqRjpLCtGwriilj1ZB9mjpVm37lzGRf48sArCVSfKAL/tF+BxNAu5B1+BqFK33DxP0l6fuwFms68BcUXOjlvaTflF46B4J3beMLVApD0UOLvnQthqvceRNVh1Bl1HxQ3vCHd5HkQG6oD62Ks0V/8Iw8esmQZi4nwnv7j/67sx/miVbBS3Q2SDediZbgkqD49B+2eKmwvGAmd9TX09ogmxg6sZPeABK7/IIRi53pRWUsBSigaBy9KUaFlKN78HIsDbq6MRuNg3VZznNPyGh0qvDD2pRlYBJSDqPQvFrqQhMOffwAZ1VU41cOZKeQ+lvtEcntBL16NsQS5G5a4/sAXGHndltKs83BTfxuaTM1Fy4SraDUpmOe7ruEJPRNAVOovL7+eTFBdS7seb0SVK134IkcEEssjcImSD+Z93IC5w2xAcvAY2Y+P5amCG/j2o49887IHwO8QHlWnC4v08/jHikV8X0MR5qe4YWSJJqp6tpIty2N7TDA+vzeLOoot8F9WDIs/kofDjw3Ar7GQ/thFQGRHDfxz/c4+SYXoPiua51x8xOmxWWS+S4rtp5rCo4JvpBuliw4phrjRI5T39nTj1g8HeF/YSDzbeZ+7d9/CvrUacC1zIp/pn8Zed1+Q/hx1sjbNgBNlU1FTbIBOjJpHvnMdYdYUU3gt4MNvnPq54tALmhd7H+5fbqHNS9OJu7WhT0h+yFUVeI2WMXxf1sonDtvwtseX+Ol9U6Qx8pRhqQpXRnfQ/nH9VNIXBY1Z4tCZGIKXvQPRc1c6/6egxP+F9rDo9O8oLXWdBgRukq9cHciMs4BftnPIw08dHVbqQerHy/hkQQLt8mjH0Y45lJhWikbTIuHqTn2QNW+late9GGXtgqn/3aZv9v1kN8aYSM2P8nfHQsWS5VjdKALyZgFQKieLDx3u4e3PqlSV+oFt82ZxZxaAdMM3zL0uRPkOU6DapZ094wv4cVkj/M68x7NKuykoPg2yI8fxrNNalDSvEI8vU4Jnegb0beJqSBX+D556ZVGZZhCvrLsAw5Ka4djhn7imbwtNL9IEQRdjFCk5jheHssqwKRcMDIheJPlR2/xP5FCkjlLB66D9sxTEdoVzTWo3VpT9g/Xft4LXh3H44+RndN1SzAoJPuSo7UHuh41B76Q+TL4xjkssBen2pnug4/uVa2tXkrF8My9YwXTYNAHu/jaAmw1BOPv1TtYz2MPjjffhjBOPSEP7PU8rzMJMQRk4YByFd5jg0MEZfNBOCY8f1uWVB0PY95YtGHz5TBqSM2H5/kzq23YUYn2lwHP3fvJ/sYpLVRMgnz5RYPd+xJCDfPzXa7yZLYELHl7EkvmWkIyr4VS8M/fnbOFjPga0MLYdUvYO8pswS9b/pk1egmsg33ckfLsWBe2PhWB243IyXdGPi8NG8WPd4CFmbWCwfw0foqPAVGQczCg8yS9KVoHksxLo+zwCxb0s2WrZbZDNDsJfwTvwgpwDaCVKg1ZSGGgrvYa0s6vhZvQyFBbeBF/3DYLDvQ2sqtrJlafu4a1oS5jtLgdf9RRhQUoG7knfBl99XlJL7yywX3UYonsb8EegL144irBmDPOiczt41vFwUI+fiUvnRUChhhOPO+lME8bEDvV9D03ZqAv6Jj8ho/4sdjb/hfAgfXils4KOnRLlf4ZDOTXWjn/IG+HRPH1w0AiHRlFV8JxaTi5KT1FEUJE0touTlNNTnmVyg0avvwEqlWrgd1kGGgzncJhoBBePWcojmibR7saNPNbDl4KmhsD3VVsh6bwNNJR1UM3CDn65nWn+7WkYp6nBejYtJD37PDc9CYW06cFk9UEGfv23CyUPl3G3pQeoaq7hUk1TDHg6j+UTcvGY2maeHvuMzR8JQvchSzL9tABmpmXgWGdb+N1vD+JtGylTegnqDZsNRXo2JHNDCwSElahlsyG1t++E/T3JtOiYA/o/06KYcsKDwkPPSiqh5LgJdEbIwX9PROHnZndwqJ2Ga5a2oeTqJn5kHgkxWW7oLbAXrq0UgpH5jjR+Ryyqfj+Hlw9Op6yN6rBB2ZG1Tb/wVocG2rooF5eGWsG2cX/R0tYQtZesx9qyQlqj/5ae7WpGoyf/UeziSTz3fjSv9lKAR2ap/CK3HW5cGA7eO9aD3/aHWHh6Ak5weEdKkutgoPkEhYWIw/HSEDZzSIXdymZ4dtAHhbasg0BvTZ694jq3RWVSR/AZstsuBwecp8K6WFX6+voZ4EWgo0HN8HLFETi6ZjF4xZZS7kVpWqBoBCUVL7F/4TmeKzQBokeEQdHHa3RshB3E1emQ0bIirAz+zfIVMvCw7BY5pg5C/V8J/DqlBEvE1rGfyhQoGr2AbjyX59DpUSzhpQJ7jKQgmsPp6YOvQ+/9x5r+Kmz1aBSlnRnN4q/refvFBNR9og/br0riufRHnJjdRtUPc+GJRCGHDrPgVGU/KJD9AQVpi2CzuxX8ElHgV7n7MSQhilDlN4ywEoc0lTNgd7IGUobXYLpcFmxVVoaIPeNxqtc+ctmcjNhfihflgXtNczDQpRMOR3+BmTofoXGGFVza2EOnJr3EV+vPw+mBJ6wvsgbeL4rhP8+3UMjXEto79STuX64A9xMm84dfHqyckA2dt3NwV9gHnpy4nItuvqOAwR9k46wDx1InQfiaXta8QXT78zw+t2Qt2X/cSx/GWrCroTvOW5kHB5ofQwsrDvHqWRij94hMx6pg/YHbVP5wNQx/oIGuvdcoqXEOTNldwip1JiB8TocmBnvSI7FMOPWLMSJQA/LbZpN/GKDXg6mwY3waTp6hCPkSN/nKtFra7FODET1f2fKBPNaFHmAd3ePQ/NQF4g6FYHLACNiS4w6zrI5C4sdqslUbzefZEVcaF5DVYSesmPaAb5troucmYVgbWQA+eSVwVM0E/97fycMO7gLFli7c1HcNTplWoFzEAD9+qg/u49S4JGUX/9FIgcSdRXiP8rlg61XCWjnIHB0AHvscuDt4NJjHhXHSlXk0L3ceXj/vwWvcVfh3mRCfa0xkscZ9ZD/uD+7Ok4Btcg248m0O7Sw+zJ9j+rAzqxsC99XwnxJPSpZ24ODUXEx7Zw3XBt6T3bhiqL/WDN7DVenEK32W3rceo3OayHDyeyrQ3gg938aBzJhvvEmgHNe+HgFfqqPRLyEdtJovcVPsZGzfaIVRGxW54KM1hDk+AVJ/jVnK86Er8jjGBp6kxrlK5PrvCkzQ9qYle9px91hjSL3zhjaMO0tX2+rwfp4Lfz9vxqnnK6DjSA3KtH+CfaY/aPZlAN2DXbhwUzdFP0oDS32A1v3rIW5NCG4rvoApN2WhQS0PjmwWgE+bf8NEq0SSz5Thx+1KpDD7E6b/fIs3AsvB1aqW/GYsB5tLY6GpzpPbPZL45P+IO+++ELz3jd+joU1GUVrSkIaSikrSRCghlaIopRIqIZSIhAbtKJSMygpJVAopVFKSzIyQjzJCKb++j+L3DM7r3Ne5rvf1z30OhdLShWIYsqkX92wdxTt8/9E/5TUQr5UJVn0GQHP/gv6cu7B7w3rwX6dHW66OpfbPK9n+hS26a/3iq2sf0WpbDZgtv5C/y+7nlanauONLEj/QPQn3dY6RWr4511zdR42pJrDOUxvS/LK5LNyNosoKSUDoKwQ2JcIZi7+gsaqNsm7+AcUTcqBvoA+yb+IIVEdQQUUcPH3Ty8N9Hamn6RWa+2bQfhcV2r9sM26ykIblp9eBRbMhT/FoYMmIHkqrvgsLtubR/SlzobyqkyLuHOTQJn2YLeKKD2LqaFXtcpjq6w9lB+eD/D5zDrkjRVaTJ1OuxHB4dVcOUksRDfZLQ2sWQV7wWPIK14BsiZdww7qQJq07TM7d0vBhjDAUq0mRdGg3SP+3iCJPPKeOOQn05nMc5zrV4aRRrhx3SwVvrFCCpBX1YPF3DfqmucLAgB2dmVcAz80LSCJrCaRskONzRvswR1sYnOsmYp2HLaQrf4cPLQto0ZhLJDTqG7PBK9b/5ALzqoTw0tkxMHVtPbxWDKGO8a94uPEPTF84mkrbvpL95xqW0BIFzbIEiLgtB/scKuDEunsc0ZnHHee206TWAO6eNgsmOt4AtzstsGO8GziONYaanAH0afsIiiM0oHVSDJ2IDgW/V6v4zLKvUNbZzyHFnWCTpQsPNgexzL7HZOV0mdWnJcGGRfOgMAVBLG0npf7+js0W3+BNvhiM3lBO2odEqdDrOIR/yIP0Bh8Y8y2Uzp1Mxip5PXZ/1gqdA+MgscMWZAye491r/rDNtpXG5W/m90l7+K/6H3CE7VC0o51+2RG8nz0Wjp+Opaxhe6HCaRL0SCRRV/VtKpmfD3J33OHgj4VDHqgGFWcrKDZhNn2uuYXyA/dAueccuGos4y9bXsIdq3BueaLOUzfqQqWIMLmP7GPBKabcv3UkDSsRhk/7pqF55B8QkXCiusGvaLJJDuZ4LoI5qlvp4gYnmGmXRmIhpWQsqg0vz9+F6J5sjD2UBgEKahBWfY8SLn7g+fSETpktpZE1TSD6TB1r66NBS8GPBEfWcv58PXhtM4CuClexoH85npupy6GSJRxTq8y68zJg8bptnGfWjduOTIA9doFwyqEH5L4oY+GZ1XBkKH/dZxbCgqrPrL9tKWsnFuPIMHP4dESV3OY24pVbb+HFdGfaIIg4f44B//OzY7n2XySzOIRK1giDUJ06OClH0s74ueS99jXkLKonwx0CEOy9CEccuExuu0/TVxYGJ1U77Au8irteviKV5FY4kWHJx+Y2U0S5N5scyaENFnvp89Fh0HG3jyRqRsDYrQ1QNkGSni75Bmuq94NISDs/OqCMy18sQrVHKvBO4hQJ1Hfy9HGXsWONKPlmzkBPlyP4y2Y7ZSgzDSv4g0drjKH172PuqGmEWU/3s8P1b9Ck005/g2VBTUSQ3//spPUJLhQ73whSZDpA3TyFNcs2Y59+BrcengYlb+eDg10XqC/9B301qRjoowZUMpQBajv5/uVC2rhiiBmHTWfBmesAa77jcK8Acu30wdrb4+GsvT5tDFfBYRsT8FjwSxy4L4I3B4vQJiafZJevBWnxpaQ1TwlW+pjBzrtFVMWFbPrGn7f8dwmH3euBC1X+YK1cSTvGZ8KRnWYQvWsPGZMb2O94wL9dipD94/l0vSYXTJ3HZ4tf0mHDfvhmIwPJOm8410AHpvl8oOGuYrzylTYbbxtON4+V87rpFaj2N5fkpsrB0pcvMTZRH518w8j3hxJNe9eGok49lC64i45ozSDRdE3YlycI9V6nKctCmhOjgmnB3c3s0TsbwooEMGZKLWg8DMJBD2d0SzAHw9ILpKYYjR+ntrG06lIw7lrNu46Xoaz7arA++xbV0sUxx30iPH8rwuvmqZCzVjcmn/qBV/NbUNV4Evc7NNPbil3suegn7ncQBMnCZzzQ7I1LnmZw+wY//v59FdbmFOD1wt1U7tTHmLSPtv0WhDD5jyy0fDVGzxzJduuU6JdJBhjXn8X8S/tRtWs1TvprwqGmM0E4YTc7jllBMZVNNGFzGgkKfMQDjmdwb+l2uLVnD7iTLLwabwrPRn/Ci7/qyNdoEvntO4bVn2Pg7ruJvPflc0z9/B5MtSQ5xVkAph1owTjxNThefQrWKkzF0wtKoKjKmW6u+ss48TRdyDnMuiUzQPJcOpxeGsrjW2ai5FjgNx+egn3AN9z2J5Acxy0ApVFS7HhDEgwfjyYJ+wV0LFSWC5/as/VNFcw5mEC39MbB4Y8bcPtKedZgI6g+r8bWH2ajdfJxDq7agXrNdrQqeRpU3V5PL/tHQZXmRDw8Sx629m5EHw8/Dl4pR+EzVtLHl/P5koQLXu9YAx7SsZjx3QlXzNGCRRqG2G0SAW9Xa5D0qUkwu08JpXwu8c7gBVjnZ8KSyk1k6g/w2ceJvP87RZ9/f+eZpwRIzTUMTW83QtnPVsAJW2h7xUkyUDGE4i4TPtFdhBguRls6t9O8uelgVhNO1bLHWaLrHr2JX8uCR0TAYcoarFntQZMWhlBdRBh0lw+nNzEt0Hc6FXLG+LKjlAYWz9SC3n4VaDXaTc3p1XDC34XkJMywKt6MrC+0g1+JJyVOcaWgQiF4lxWHhwxG8fLJjag/7AG6CAVSzN7JQ/cWx1+XWtHDlSpk1KcH++38Qdn/DhepZ8BLK3Fab9fKN8J/sFq6BFUXWcKV5gcUNmEk2OxQYqub6ylR8Aw1Bv4hST979sNI+jsngudGR8PPpbY4a6sgfFIxJbVVr2i6iSWdLY6AydPWc8zWYhxdEMS/JyaQwLZXuDDHHIJiXEB5njQrC7bDT/sI1O0tBfu5pliwvgjCch3JVPQdR0saw1zBL5D55SiETXk4pHsp9JHsxeM6qaRY+YMUBuoxJEAEw1o14N3dV6T3+wwuzu3j5BvKfLXtPC43NYBtE//ifOFBvNMYBZuN9EFBsQQhopYr7HphMARQ9NlfjuhJZ7/06TzqUyMcyirkwbxJcPatNl9timeNhW5kuPI7v08rJR1vK7z/fOgcY7dQtN5DFkyRANHUWzChrBP/uo2iNtc95J4sRIeynXihhy+HzevAO573qRxngsyoUdBhMMiisQV44nUr5mzaSiuV0+i/xjb4L8QBaYcOLb8lAUem5WBSfiNv3LMIymaag91VoBsGhuynosVVL0PwdOo5nFsqBf6K2+CReh0f3piMSjsvYWHjD/y6/QbpuWyliZHrcebWM/ygeDJ4blxOXoWn4Y7hCzhZN5XWlTbDo6wEvG75DuZ478RUiXSyzxgDGjNdaJXlBZAarAK9b8PgsPVFunDJhTtf/sN9CY851GvrUHYPh+15bSD7vpTOD3mxn9JXmPjEETs843DrtDaaF19Gkyv7oeAdgmt7L5ts+8rfpWJR5ronVP1cyjV1K8ClbgpPPTcJ1h+bjnu9ZsDS1UdJMfsNLLzxBrzsG/GRWQgtTtNBi6lRVP45iGdu8OW9HiPhz2ANjQ5TxfFRhrRwRwZ1UywnJv1Ah9LVmLdGAdc/vwS2+eNhSvdRGBNmhrOuP8GFWWPg4gYz3rpYmdVvP2Y7PzH41b6fFKwIwjLLQFX5Mq5oOEqNB+2oyPkMX09axkumKYBdmSs1/ZIChSGGztqtj7O6LrPdnb341rGLDtyuQuVfUbA9SJYWxyvBd9/ZtKLNDHpEgvj2amluu3iQ+OUKPt8sC9qeHeSbOJG+mM2Gdzv78EKhOViViFDWghOwLUiafu+biHsWRaOa3VN48OgvCmpNBcvDaTjcZiTcx2fYbq6ATxUlYe4exivyPmQp9Z2GpdjiZ/WzaBJUA9VrNEGoxxBHj5Ln9rUmpGggxuZLz/LZv97888s7zhWwhM73KjBliz64jbiGOcsnYaUJ8k2nOna6Xwzt74Rpf85fro0bpOuLVnL+Wz1QaZiIK5IaeIPGJ0qZEYmW3cbQd7yDFuQ3kVvOIHUt7uVXeWIQOiaI71tOR/mUYHLXM4HcO8egVbEK3j0LhNgbS2nZ5dFU/kcEUkdYwcJ163Dj+5lsOXokNjQZ0eSCCtw84E8HxidSbukEMmjXhrtZW/howFRukWN4EPGbVus706/DhZgiMwKNE6vg85IEypQUhosFW7k7ch4HJJ7nH/+ZoeHAffy0xp8tuuPg2a4R6HpnH01VFICsJ50wR0ePlEs9wcc6kELENsHTGQ/JUMgAHjg78ZOikRD1ZypMVY/HtEwDaLAtoGdNFrjk1no+m3ob4+z7qK5fkLwaV+LR2cZwuksWVvrvgXMHUul80248v/4kuD2XBYH9AVBnLQO/Q2tQ32kihMrUQ8X9Cjh3aCX7+hOYrN3OYYvnon72KgopK2Y92Sp+qCMMc2dHc8H2BWRkpw0Rn7ehRsFtPPtvP+SMPozx/nIA25zAQEgdnorLoJzlXTz3zJarxt4joxt6cLXWlp9UNsGMixv5yqoPQ9wrCD9zTWHKdX8Y3vWHh6fG8btDs0HVq50u/p6Gi1qc+NmCJNyrOxYSgiRh/NhiyjQNoWVvsmnS3G7UPFNHXscJYx5dG3rbuzjXZwxsdZZjxScm8Hv1bGzpjeTOxEaM+LiSy/N/wrF3h0mxoJjXzlCBc1OUwGjaeNjSHcWKFccooFeAbvVqsfWVCt5+wgR7Vq1H2wSAlqQBwmVHaW9eEHsXKkBMbhEv1RoAPffzOKcyAldZTyPzzaPhlFEBhjmL8EtlaVqrNI1nncrlrF3Mn69m4tm/miyzvgm6J8vCuidScOCCDD1Tt+COkDjSnDEMXF0U0botCHLqL+Lat9nw4vgocJbuABfjWBr/5jM9WXtv6Cz5aGEWASOlI2HP3ed0R8Of1kVMBxX/Yby+czRozLmOtx5mcfrgNyjWz6a55hl48uEG3iyrA4oSWnDdKZ1+tErRxUfx9OD4AZCNv43f5k2ngI/WLDRVhYS8//GoFCO44C7E1oee4aCmM1cWCXPMgYW0r2MX+3ppgvNEeY5RGQVhHgzP1dfxVoMcfmVTDs+uaoM97+OeR4fRSKkdje9uBn2RdGhWEwf/05Ws1NFBVfmWNPuPNZo8d6adsiGk+GYcGiQY0hl5U+qpkYfVn5+xi4MEL5EGeLHDEsZYLsDGrVOxPVOM1Apewe7ZiTR3sSk8GvxLXl9/gk9DHboFW9HrBR54quURPL4dBBJQhw9WV7FWEcE/dXWY/3wzuCaFYFnqEdJ+u5si7//ks1uW0KPh32AZjwTVfXpQcj6H2lNyYcc/B+rK/w1TJCeCiqkLWfnZQZG3DzqrroH0pQLwsSEIfio30k7DQRyupgAvbz+Gp1PMuHbRMpJtOMOrRVZCQNQIeA/5aNY1nAYa9bjgVjnunl9Br+udYd9OEZa4sJECKvtgnf8UiCruxfJFM8mqcwc2eUjSS6lfNHbPa7Z6weSyagyJ1gzDvZJy8GT3d8z6JYPSghaU+duLMl6OwzTLZ/xyDPGJWSfZKMeJ/shrgYH2IdymPweSMl+DfNImvLQ+A8qsZXBdwkxy60nlsTZ/sTxvJBx3f0SyDq5s1ZLHuQ0Z2K2/EAZ0LpNyvTn/bdwEC9YegsqpRjDZoBxO5amzdK4nbNOWJVOvsdQdq0Hej/pxf2Q9DF93H6ulRsJoA1G6s6YK3j+5AhuyTHnjlzQYuVUCJ+68iksl50JHxjmMExwHJh4aXOIhDq+fl8Lg9V7Kkw1C928X+XJaOwoqeNG9Tdcg9IoaJK5YR8X5vzn1nRv8DCti05Ua7OAPqI9W3PNPluG/H+gogGB1W5OchvqpuXkGO5Zo0+exOhw9fiirl44Gzl1Mul7LIbBcBF7Hv8KaZQzkEYe30+Zy6AN/rjqwBV/tdIDzw4JZM38aO8ePgknJnaheFYCXynXwxPUdXCefzAGjLlDDAw/aUaCIO5d5Y0OMLBg9dKdNMldgIC4Yo/bUQOsEZyzdZEcyT5Vwkq4rQZIUZ2QpwL+9pdDTFgM356ejzJNXqB06GUWqttJYOUXW0e3HH4vOY+0oXVgxVhzm1++n/Y9/wOGK+/TAUxZXyrZRp8lzPvJLBSPEa0m/Qwk23hWE/vBEnN2bxMcVbtHUWj8y03wFDtET0D16GCmkHITgIT/v+R1P398lwO4btyF4zwwujFiImDWSN2rJUl52Aai/E6U6a0UYZr8drg0LpcJrC+B26n3oKfvHl6dvp28ayVxSHY7/7W+i3ZIz4I7AXYwffpvfdr6ksvshHCnqzhoKObw1OIx01uZwv3gtnHUdBxIDHznh3FEwe2fHv1Tuw4txyeS+dgBu3UqhY/nycEHcig92mkNH7DFM0BKjp7964PRYOepNXkPVa01AXmsUlMZ28Rdcy81iUgB9PWTVkc4X3K1Q8qITR20XJgF/PzhhVQZ9as9xS/NVlFLQBmc1c/oXYghh0/rg2oQHMHG3DHVttIJw61J46WKAo580sID+GBinkoUzd/fRXalZ8M7sIke+yoTszQVw42Y2yZXHwqUFwMEpWlCqNInX8iY+d300lSZ3wmXxlZj5+BkVdneyx4/ffDeuGq6PEYbtMcF4rOkaL0puxA0BM4kLRPho2mdWUz4PtfGH6P7XeorRVIaGweUU6XgMqosy8ejwF3BouDF/eFIFzobbsMrEgAbezsNBVz3QCNmF15/8R2ua8uDoFi92+jwS+1zD2O7zL6aD3uThcQQdheThy4i90HZnMhRP7MDZVQpcKPWdRRRPwy2Zy2T+rYjNvP+jTSGaIGZ4ES79NmVvg7tsv3ULyXbXk9uFSPrxRZEFvtUiPoyFPbtVYNTMUlg13xqEleV51L9f6PyvDcLULtNfIWMeNlmKWppcMOgYgnSxBToEAj26XI3pLk2wLPEVPH8Wypfcq9E96QrTOGlofjMVcr1k+UBbPdjNbkAf6Um4e58SqRn6k13rc7jXpwhjJ3bhucOGMHxjJ+Y+cKaK8jhQefloSEP+UPsznXx0t4CzaDBeHilLAWMkobBrL0xIvESPip1oivAkTNL9yzMEr8IwxVq+lOrMPnvM2FFJA2o9jCmxeg3uPZPOSj42/HD1VVKdIMoh7rcRVb5Qz45GWm8+BlYmB/HShdK0udmGj+YQKwSPJVn366Sx/iq3uAQi6Dlw8eHRYPv4Hh7r2wvj8kvATuIPL6+0oLkz5GlyqyxZJJ7GI6s0IEPTCN4or+S0rapU/buMF/keoxFPJGDzHGPMudyFZYdK6Z/HWN7SLQuVT8UYCgXJp2wrvDi7hjb8+EfZfS/R0uo9iOtIUvLTDTQswhC6r0fB1qGMGXawGrdct+aDkhWsYN5O1+9OYYWK49TxLBMvDk4EhYA5OLJlOPcpToeJdaeATwuB8D5H3tEkBMaGzlA5wofOB0vAmwovTA6fh6tm/8Q84SLY2OnCjmKFeCw6mq7ODOFOv01YMkYIZBYeZAEzZ0i8dBzs5zwDp28DVLtuIhVKR8P3sEoUuv0BH6SawS3VIPYbZwvJVWLcHP+N1LPeYzwf4BZne7g80oQH7p6A6Q6y8LomAUWX1FLF9m9oUnEYl6y8zCMG+mn+az+4IFaJ5Y9lqPWkFDhoFfPvFX9hYsBGcFUuh8cud9hvmiaMi/UnMVfklsFNPEpVCVaFFePtC/H4K/0s/QezIKP7AF1qv47tnUlUY9+PEZJLQHEoZ9wsa3Hl3zdoNaGTV8w2JPq2kQIXZNH88DzaPfUdnRZsglF7TGFqYghPWayHLjff0YfVv7GzPRBJpgYiPeV5Vo0kTRvdzG5XdaHdQoBfZhjy8wN78J57LWXuDqR+14t0ZdYPDrIYDx7zEvlk9Qzw3ieAL9KToWv6XOw9dZIbHoUjWA6iyQgjNEm8S4/W76W8NBPo/zGVzQsOUNMdQRjwNcCGPTuh6lU91K45iEHT0mA0xdLhRCEQ971J9dGyoH9UncyqtlP19jpwNPqP9KVHwL7Q9bTk3TJ6WCsOSY9eQ/GNhxAzfA2etHWDkKoj4P3qKhwP1qcX+47yomHxvHuHDuTvb+PuHBm4Pns9/AiI4uFi2nRGbxF+W/2NJIS0UEZpDNzrVgfRn/F4LFUeJ12bjvn926mkeT7bqIvA1dk2ZDvTky/uMUZlKzHITts85FmDZNvViTINycxn/mP7FVXw6V4pTWi7Su8b6wEOC8B3MXeuPNyL2fLhICKijc6fImBeynd8MlUCll2bDpvmOFLhq+HQZjobt/Tkw0fZcha0tKTGvEVw4eQ3MpDLx9wl7rjOvIPEnw/xxrI+Uj0QSAVO1+jZvmSSVzmOJyca4RWhKuhX/4SWtxfDW1VxiB9eyWrjzlKthAG2rF4LaLGJ+/0yKVdBjtrEN8Fd0eeY+kIIdt0ZjrkvjqHZ+wm4+VEMXp+gwHpObnjYexhc/3wIPyi14ddKUQiPGcBTmd/oTI4sFKlcBSdNCw7pfU8NYUtJvr2Y/I06sKebQV07jhb0jKbP+3eyx9qrUC5mDnMurGKh+dcoJicLTUyeosxcQ+i5d43a97+Gy8taMKHUBwwePcfGe8JYKeaGklnm9LBkIeMnXQg2lKDPvp7YuKmKLLXW8zORcfDmxCead84TTlWHseLf86zgpQipI+twdbcKXTlVzLyhgARu1MPsOhlKDbqBTzK24YmgTPZu0INAuwpcozEfojo/YfojM3Bpc6O3Vt74t9KG79yW4Oag12R1dRK8l5GGWzqX0djjDP268IQ3fbZHOm/Jz2ANvln3FFVv9rJm6EiwshygHZmB5Pp6E4yLk4bJj6fgy8RS0PnbDz/NzWjfr8es8FUaSm98ZfuSO5A77Bgv/iuJO6/LgQeO48nt+iCRmM0f0q/TvA4jcHuaSzuTnmOfVxNlTp3GukXisL92LnyIE8XwBa/4070FLKs+BkYWzUY9s9kgeu8gzOkyg+j0SaDolQmyIbE05Xw+zA9Mp8oDBOHNXhxy3hXeyxVDnkAiqS/owJy6pXT65lyYGTQBJdGZ/BqGw/MRt/hwRxVbf2gFD+Ev+GifLe1b64g1i1tx0s1vdClEjbUSdOGcWChGWjfx+QbEYunX+MhbDwzXPqdo+6kozEFY1SUDebZiMDLcljyCWrFA9B5WHJCkbxddoG1sEd7/EcO6pRf4hs5rSE4zhnDtAgg5d4PD9J6DxZJqduv6Dydf2oPRz/MxpNwdxyvEs2DJBFB0kaEx6z5h9ebTcDxPDy1fJdG86v/opooGj85VgT45Gbp4Vx+iH0Th35HzIc+rhirfXaBtERYw9bw1+mi+ocieKF47Po96/5OBJ5Em2LQ4gnW2PERJc2GMVD9GkgH7qfFSInhIacBfv3McPFcKOndeQ1GLhTy6/xNa3NhKHQsHoGX5crSecZRFh+794rFCVDDSgMp9wrRU9xEOXt2OA231+OPcXFq4pYrl3+7AI5tE4OHcxxi0Rh7s/61EZ6FeWGH2HQR1s3HZJyUeMWEjoU4ULJgdhD6TS9lhxDS4WpJCxu8lQTJuGjoeQNaucQWfgWe08X4StMIWDvu6CbByAvyzvEhP0tZjlt58Pq90Gie9vkYlR+2hWesI1bEX/7i/HZcpT4YdNipsbvUHF3X/w7WjBcHpYz7t0gvCX6Gu9F5jgGO2bmIFNyk43DbAb4U8eX9mDdtYt9OixTdxissj0vw3hUx1faBBWo8EeSYs8duCNwq80bdnJN8SeI8u73/B7u3KcOKEEugrCuLvo9rk3GEGix95wNIhcCpQN+d0X1luPjuZ1qXl0FLHm5h+9ywsqX+DpmOngGbOcw4YeMY27M7hvrV8OmMEV5+Tw9WVJQRi39nr0E4O0RGDq+Y3eJnnAU6IvIkrJPfzofwhVmgZIKUR98h3ijc8OzaPlk8XgPXvD4Jmgy9OPkq8S2U4KLuE0YlxyuStvQ6n5X7hO5FXSO3+TODJzVSUPjTjgfk0fN9tEsV2ypaU57Uxm3nX0RAIpTJU3aYNz31+cs7CJp75nyJ+d8jA8rh6NHQfjh8VH+P08ijsuC6KHgmiUHFTEi8pv8Scpy382Oozm5zT5BdZdXjXpoE2zi6mm24ree8sVfiW4UhjIjWo+OgkOCVpCRb7ZOi2YBXs9tkHk9wjKfxgF2/TJsi0LOAu5zGsNFWfrMbIwPCBaFyjN40TVq6A70dEoXvnf7BD0BAax1yDF7Jn6dcjhHHrBWm8mwcHD/ygj3e0+M48c2o/5kA6z2f+v/3/u/PcMh5xuxZ8qn/x80ZXcvx4FBsvh8CVrLmQpBxLtSub6WLZTFhRGom/RWN5xuqTqCd3g4SM12J3219+3DsAlzfvwnXqYRw2axR0sxpGnXQGrQ82ZP5VmMz7p/C84ncQay3HweUmJDfdGDKH6uivc7V0TqWUI1vv4FXlNfAi9zQXFhqBt/5tTIvbRG2L9LnskQk8PeDK54z76IKAJx0/eg/SHsdxv08Cydrvxch2NbqkfYyW35OFbfMsUe6FMfziaCiKvIgf0oOwLVqOUy3tMb31HY/ZNR3qDFVh5KyPEBrsC4ndl3lv5Wy+8y2SB1atAv0hBoq4lwMVn6X57nopuF1+nb2v7yXbEbWk7RQGSWl6rKN2DnWb9sPyw4K0qNUdhEM14ci/G+xIm8B8ZRp9iDenpcHH0OngHj4Sc59e4X3Qa7sANqvGQed5JY4/shlsmu5jvMpy3BSVyIoGHyjcWRED61diV6YHbPylAsHhLVDyy4hvbhpHmh5mWPJcH1JP3CaFOaq49P4MuJ4fQv36YlD5w4LOpFTgofdf+d32MupzGckan57RwVkV8MvhLgftjOMwGQV48O07FxWu4808QB+LS1kq9SkWW55CzWFn6ZR4EgiuqYApGybAiIFmGrdrEBbObqTPXgQ7bxiRg9h2EFfwxRfCDmSAjdwgbAhmamcpcVEbG3pH8Gj3fNwfbctPdf/SjiFukVVypTfrxsGGLDUoOieFzfsq4ESrNbjfGgFSOcbg/+sHCWZUgnz0UUhNkcKvd2bCjecfsHqvDG6fmMNasoizKmtAR+wQamVfI/3rWaDTZgbLJURB7eNduh6ox2pq77FpkQKVNshBUJ8afJoiQQ2ScXjlRw/NqREFa7OVVJ71nJ0DbShtXCg/2yPB1fsu8JcTY0l11SJ2H/Jj7/TJULven5aleNDBzEa2/KpCDa+b6Pd3RWp6YotSxuPpT787TfI3gEM3pjFYp9PS/rWUe74NexOCYWG2O03T18G+qOsg8b2OdksKg7GfNcofjaD7saf463h97BWbhymNB8k8ZxxotdygLyNPQPliM9i3WYJ/XZqEbr6pZORxHxwDzCHudgr0+y1hn0PCWLVaALPGGsLc4cK4Kd+K6zrHUGrRPjj9ZhR7ZxXwzwnfqCXej7ad3EKed6eCjm0ftMT4stU/fVyjnYZzXmzhDd1VPE4hjz/Kp9O/ziLMkpED47QG8AoUo5U/F6PvmiSkFh8OiJ3PcfW9pP+uEGKblNE3nCDmczI5nNiDCdptaBFZSU5mZ6E4qwKH5doxj/WF3/+dgX8xM0Erv4vMRHbSlfLdXCicDl8Lc/CAOQFnZvLgmkvsdfoqHi6UhT/t0yDpiiqG7BxFZq3n6OZdWbr9XQ7dUqLB5dNyjjv5Fj6Gy8DAt0Bclf0GjnddJ2f7I9C/2BFnh8xDRfE5GJEZzzczDtPXyikwWlwdp1qew9ArvfS0QwvS0s/zCAMZvtycwiamWfg2oYKUjgqDeJYtisj3ot+0iyC/dCzE1zwn1zvSNMZ6GIyoEmXeMw9yPojB1xcFuFwjD3dourLnxGoyXVLD7Zcuwslrxpyv28514bqg+tUcIvwW4Y3I43haMYiPDpfnrLOq5FCSzDbOvTD9qBlGvSsmm6opIB49gjc+qIdT6z7gnVHBNHO9IOfJIA+MKYTM+0q4r3smL0ExGAxzpeD1y2mzpi2c/VWAOb2rOXCzOdmJFcJrP3kWTh2De83GgMsfhL7kLPQ99AJnzLQmv6J/4Blaj6t/pnLRvw7SF5oMt3ukwb5sLnokLiDjZ2oQuk4Y3IsGkF68w+MGnTCvM59+x6znLZ8k4N7CT7jx7AFansy0o+429Ro3wKualaj/YjpfzZ5Jb08ux2n3GGx9l8Ps4p+8Y/ZZWljtA8L3H6OdZw5XG9/AF06jOcChBz13EKwvmQfi3e8w2tGAYxOj6IfQTfIrM6HGtBBavv0k9aRPI50KgO2bvLh/7BtQm9+Cj39thNr96zlxojVVbGjEsPsePME3iWsEDSCqwYJKinPorOUozlROwsvLrmHihGReqVtAof21qOfgAe5dWrAp8ig/6I3m+KH+6h72k0u6HoBpnjNdGNLvN30TcD2+in2GPOfkGRtMO3AHW0d3wUX/QxD/+DGJGf9vZ8VSEvgpy4e3SkLVN1UIDXHDu9G/yPvSahiTchzbhz0HbykBdlDzg4jmc3hfbwEczB0/lAvTYWSbPp422g23VLw5v6sDRg6fAIXjjGlPdTEuz0tByTFakO0dyA72G3DPjO98fFQMN5Wf4+qc9RDhTJyTLQf2gZ4kJC4IGc9OQ0VfNn6wPADxpllsFtQPX94ok4tpGm+cnkjXBJ6CdrYISHccwO2SA1RxzZQUZJtoTH0yd50+waG6w6DzZSg4qa2HoPJJkNcynX93/CW/nnj8OWkybzteSstdBUD9nwDnL/bnktXmbOWuBUa3XoPerQMcsrYAFn/uJ6VHvzit3hFEvLPJ/kAQTbidyoPJDJVnNHF/pCi9jPsMgo2pHBv6g6VWyFNlQy1XV+7FuBgNXvF4Oijv7sbsQnt8GxZMntEeNOz9mqHePByaf9tze7Mbui0c4Dd5elC3KY83Vi2hTQpTIXBqHsvvvgB3OxJAdDrBhf4/kHmwmI9Ky8F9y9u4/L0Iz/FYjE7C+uRq28wqc7Jxmmc7mpYMdZrKbpQZ4quSPhUYPOwDT61WwGInaz53zYhG1FRAcskLFjIT5ZVLXHDpXB3A+jX0RGUJJelNYPGCVGiQciI3+gYH1jVx9ZRLdGqSHy58NgxuigIsf/kBC3/lgZvyLQgVD4Z03W3gGz+IXQH96F3zBiOUtKAmpIFmvVZg5X3tbD73O8osFODB3EE6UAHUXviUpMXcUVl2BDwMcYBu+8mwdttd+PyhDHmvHL8SX0L5q5/x6rJhZHv7Dys0qUCQfgIJ7p5Ln/rEuFZnPqZ8NeFWW024cnYSTf2XCbGzfOAyCoD5tCVo/0iUFgT1DvGRFf4s2o8/zxtyQIo9eGt95C0pi+n28vHwMPgPbBdN4f7EANoysxQU3hG2zPkHN26VQp/2TAj7sRB2xavAusdToNcxFT8d7ORxG8ZD/J3TMMFo6A2kudK46mo8I9cBr4dJwMDBC7DyvyioN2vGGZ6b4EhfGf0bZgCxq31A6eMyOqp7CTzllEHRwJ9XfNnG37/+RaoJ5HvKKjhWRICNgu/i4jlRHO4kTeaS4vAwLhLvTZyFF3tcIC70HAnaDfFhxHiK9UyEC7qhdMy3GSc9FgXFfzP4xfFuXgHNOKe3Bt1r10HJrO0ksns8HVo6SE9ep4P/XXE4eW47P/zijAsniWDAk0t88lINCEe947tBJRxUcArsWpMpoFwRKsJawKY+nG2VQkB1xWdKOriDftTn0/DgKbzksTJcboii+T1acKo0Bs98cKPcuzZ8U6VuaE5WQ3woxWljTnPHsDm8dsNYzncZBTVmB2HbnTjgx/XsdD6NzaLEYetoKUiRmYSX4+rJUunqEA8LwrsN29lrcQO/kTqBY+cZQuaiJDY6Is8fWg8xG2iARMoV7lPVA6ktuSAofBIXWhTjZpfvEF6TSnZfInFr/g3wezWGxsWuw+y2GbCqMhafLdsBI8e9oINB6iwUvBh0L4hB/dfFGJCwlVoLDuKwIS0Hdn/Gl+KrkXfdxLcvnkNWoi/HWDD5ve8h6yMacGtzNF4JHgdfPV3p0MOlEFuUSP01B2hw80g46NjN6x7L0BZJY7z+tI4rq/VATPIWzpV+h8lHmjni4FeMW7QCcs0jwU7mOE5ufU9WQcNxQ70hrH66kWc/qiW9IGvUGvUPm7SOQV9tFYzP+UJe/z3FqzP8eFS8GVz3m4//LRClKIGx4HNsEfue9+avhvvZfJcuXuycSwdGyvGJH2awe+JXTvm0H6qOOMKXZk/+IqeENgGOsO8MkrDberLw9YIHv8SgRzwQPf485SVetnBCxQyyO/fzuJsvYeReaXhs5Qw/78XjiNcExYffQN+jAKwyfAEBN09zgfIwKtpqzwOiL/nJtxN01mUm/myRBdIpwxTlJBDG3zB+wjfOG/4W4t58pr89mui87RXL69uSwANtqP80lqor7sId0Z2Qf0uVtnw1pU2vrmGCcytkLDXGSRMaoNhwPJw4c5Lruz1o15e5GLD8EO4Z6s3rjRNYILEdjC/ew8t9EeixeTocXLoRwu9XkQM6kupAC32+Mo8qzn3n357r6VeQDyka/wADYwbIuM+jpjxAf7sztJIaWP3uQiryegDq9W9hbqstfJVvpS1rxSFC6RYPdrZSmsg8un4liwzPbkYN7Xf8RuEcWYtZo0FfJj4fNIJLl4Voyesl5PSygfVU3SE1QwxUbvtTwYQFIByUSm+UvKg0dwI8E30IUh/NqZNfs5ZQKKePG032iZN44lp99Du0Al+/SMJ+7RGgH3+UTvaqw5srPmj3rRvAVYvlas9jygWg8E//sW1FDl3+ow4ju+s4qjGdw0X9KGifAHhdPw+JrxT4vdli1PylTdM9imj4a01Q7xlAIZt24IO/ICjXlpNEN0FlVBOPUaqn/bZeIBk8xPi7h0F8yBeWOi6Ld1p2Y946B25V0kADg23ouzsMMGIQoltX8i1lbdiqJAfpOakwOfANtB0bwMLlG6m79xPYjt+I+7c9xCK/oxxTOgmmLLOj0/+CoVblNfR2bORrkZdZzlKf1+oQa57QYNGWcFwbKgO5G5/isAPS6CTuTHG3ksBf9Rj4x4wlT7N3fMPGGi3WxuLGsQg3PgRRN/zApcnIU6XNQKgqGrNqlvFFU02+H3NwiOO+4qgaOZB9uh2aL4lDcLw9Z2Yh/UeW+GndLHiy+APftSsBy++meMxXAdb7PKbPuWkkECbO4hZvqW/fXQw5YEXZBtdAfsMXkB/IgHA5Q5jnVsr6G8Kh4r0+9k2R4XV7haEltxg93YXZ5qsNVdxYghu/jgTruPPs5jyRvz0coJwlnVA5GM6y8xowr1qXor87Q5NwDv8+JQxf9lqi2Gw/HvxmiwczEshseRlXiyiQeuZWuGnfj6LKg7SrBSDPei+skVtC42tWwYMUBRSLd0Iv6CCrnALQPnyTxe3WULmOHlx5HAaNPRLU/72JIiYshNuXztOHqiVcFaeBrTqZIHFNFc1+a0LroWK2Mb2IPgUVOOP+driXm04LbNLpRGoeHvleBr4rIll/vi6Y/G+/4JY6mvD9E6meKeHQdEuQapzFAkFPQbcikNPMSlhnrSpojjUlgRHaSJcywORNCGgICeKB9+L0O1oXK8KL0c8/hQtODYfhUwZwS+VEvnZOja5X/cGjVEHJo9N5221zcpBJQZWx5hB8TB/W5KbCtMm9+GN/K2doFWL5vy6KSHPDFCFHEL+aAWekJsDZ97rguCUTvq39QHOTark9cTg45haBw/cpLLN5Or2pr+TTr+rJ/rMe/K1fyY5BpqRehaCSPxYSNNshrfQIPtXcSoXlVyDPUYlMdPUhdJsLOdkc5+wCA+w/MIHL3c/RyXtfMCCtlIscH3KXwh36+hZhmvdjFFgTzm8CXkNmrAoXiJaBvOJI+P1IkhTNFMn9ohrNLhwGMz6kk++/s6hm+Q12BMpB8RwNWK9nxUH18fRivydWZE7GU01j4dXSLAiRSyHjyEy64roGjBM2wqknz8imOgRN+kV47GNJXHxqBChVC+KzKbXg/tqfJhScQXXzLr4TdhmeRx4i42gn3Lb4BK301QUV/TPkm23OF4R1IcVDg9+pR9PNT6MhyMqWvHNledWdYsqYqQK7daIp53cgR7XoY6j3NnYKCMcRiUWQuUuPttvoQm5zB0mKC8MHg9m0QGYCORivo2dloyGsVpONqo/iOqVEVBl1BrvXKcO0Xn04OVsDH7pl4d7OAMzePJ4VFk/FiAW1fPjyfrY4rk6XT77nLjVBGEiLHWKvVOo9vBzy3Edz/iIJuG2gDBqXSzgkZAMLb3ADyR9T4ZZPBFO0Bi0MW8h9ujnkrFPEXd+3ca9ZDM06uJuqLtfy8mnicLh8KyuOyaKvF3+ii2ogXSnuYDuxI+j9uRjPrJrKKWvKoeDqKPB5EoGxHm9YWdcDPjqmUrr0EV7w9AO+DLoDW0SG5l8iRQtltGH1lkFes38Kr3JohpaYW7AodCWv7PpINZ7ReEm4GCNCtDknSxTsJNZg99UPHFmqRbjqKqjr3WNr13IynSeIqmktGCY5gEb1SrC2UhQFH+3EUOEivkeCuKNvLvrlV0Bs1E949csGdjqL4OrDUjDKohk4O4iah7rl2idhULnPCb9fvAcFCvWQHdtHZvPH8SEtGXgaE4mvzm+EL8ZtLOargIGnR+Cl/WZ471oYefYng3ZYGIxaLQ7t2mowekkyHgnq4rsbD1ObZxPuWTWPDkt6Yn5eLP6uNKEl3WPA+N8erG9Qh2OzYmjOmOEYL1fFtqab6IeeAEkIBpN93xlUapkOp0ticf7XbjIb8sxcFykUuca8aXQbJkqq0zuBe9xh+pAVBY2gfu5aOjhxNpkW7uUj8zpohshb6G6fwAdWHWIts0+8IuAxWMmrg4PwZZz9oZQfSWWh6siL8ODVNv5jtImaKIpHKgjSwj4HjhihDB9eS6N1oD3Hvro0pJkFGLXnHz/L1oBD7gI8tqcYd+6uhrod0kDZyWBWMUhtPytRZ9oG9Iv8BHEFbyhq3lHW8ZKDETc/o9FvJdjQ6Mvn6lsxf70Spw8XhYk+n6AWPpEBjsYc7Sf4Qeo0JOYM9bzAItD6uIu0Q6LRouAC8jwfdl18E2MP7KBbCZs4anQx/F2sAtcD8zCokemo5y42S7pJP9138/6fffhA04aS71aRCK3E7i4NWPTrAxR4KPCKM/70rm4i3pn2BhTaxPGnsgxuSBzHIsbtUH/PAL5PrMdVwbboFeBIFVrV+PrfOFzpchZXPdhPh+zKuOpWK2ioT4bVfSroEbwZ8+1DyaciDONud6HIOOKAH+KodfQlbm00gtt+orDhWBcr/TzFU0Lqyf+7D47xmoaBZEErVBzo9A0JXLrFnHYv0wWhrUL4UziQn2w0wYayBIo6ZspPbWpY2D0GHtoxiaRtgktv1eDsrDJ6l7ELx+uJ4LiEBSTz+h1KH7pDnW3juajrND3MHsRQX1NQvdkHyYrhUCrwCvyymmlS6V70yO+BCflnMd2qmaVNw2HuholgEfodPmzwgJf7Z6DisRH069NjUMjcQbWymmDcL0ldlqd4opYGrCk/DejiDc+0H4Gcxj2aqKGDG5S9ISegADVXbuFNQl749PUMmK3rissUR6B913nMlF2FJ5TraFPsAnRX0cQqW0W+lhFGUDIefPLWYoGhN6o/zMYny83wpYk+fDg5ggvqLlJ8TD7MalHG0RkMTi4h9MNDE36cU+Ivn6Jx3c44aHD1AI30VprNS0jmzR5cvUYUkj7F4NkZxVQ+t4McVOUxuyiDqu+2sLBEGO9ftQlig6RZW1EK7ilY02v9DIowWsQ+2WU8yuMwx2l7gPKisTQ+6ix0R53lh6enQXXpe7ax1iKtDeLslXkHAzKE2Um2mv9LTGE5v8m4SPQ1yEWLwYdlZ/EJH8ZFM+fRLPTF81XveCCvn0L2JLPU3WrsFFKhmjIt+EhKFJyiwaMFjPHpSQ822jqBJC2kYKITgo7oY07bIwVf3yN8XTsODux9SFfmR7O8eh/UvNuBI51WwM59+RwbU8GRv2NpzBoEl8SzdNh3NXnqlbDGgmRQT52PX+JGcLS4LDyWHEdh7YdR54Ee2KbN5r6Jmzkq7AT1JIfz7onfqPlxMNvvFaDSLOB5NsmsNEMPSjXk+e/s19B66jWIFzpQq0MRl39/iycOSGBnWxPulFDgBcGj4d6lUbjb4zInT1mOBiNGk4TWN5ae8Q06XXfydqtmkt1RiCWOQvBgmB3p6JpQkmgi1o4IxQ59wk2VU3HCiof8vjORf4gmgWrrdFiovxU3qzeR3I5MiCk4AUL7U8jjuAAsWj+JBlwqaE2WLTWIi0PCxnk0cdd72lDfQpcblmHtw1FUl3wIzVzek9/e+2ydKc1+5gIg/bkThKIaYVpZGH9cYQKWZfn43VwCX7hYY5ndTTQVHEHBVTPhl8UXWnS+ml2CD6BrvCMkxK/GCQ1Icy7eIuU6V9y1Wh6e7heFH/smY1NsOGmFNVPCgmbyCmwk8VPKHGycTMoy99G2z4Fkx4tAosstkpM9w1IhfXj430u+knWSYxZuwwMnfckuYBuVux5iizMjgXeXgf+8dqzyYzIQP02/sws4a0kjzvjfns+/+my0thwzzdQgPW4yfhl1iK+XSLCEfC6aP+rFFS37UC1bhyar3EDTyfI0Q88UjiZ1U8HgWtyzazPXxZ2ChWGzsF40jDYou/GqLyeRzw5AzG0tSC7+wzuGP+AHNbL0d9tLkBm8Rr7zHsJyL18c13UYrFKvc6iLMjxweMg95YG8dQbBoSWy7PvpJUVJd2PLWxtuaD9NcX8+oHzeVHjt/oj+Dsvg92GmXLHKF9a+LObeJG+2y/+DufmlNPfiUrD5KAJl7cvAf8MF7Go9SQ3TVeh0vjgstj6IRy02op/JJE44UMPHYCyEi2WweWAtq88h7PntSaU3F/KoBcXwbJcQKikdA++xnvTk9ViI2KfJf0TksX2WDQ3svYAWOwT4kWE6Vlxaj0U3TuCqd6vJSUIRXgq5g+N1MQjcEUdbbbPp6c9m/tc5ESvmZ8GKiy505X4Hlm4ygZ6MRVB/JA1b9Yz5SH8R/ijW58eCxZQ4LgRz2+fAxSMesE1WCk5uNoVjFaO5/slSerHuMTlEprFaWwCs1vrOo9uL6XDJUVB5owozrgdxQsF0PHHWHVyDounnvUOcM7AOjwz5xPyfqaDYVI95d4ShzGCAva7ZcZHYNPoWqUKxzll4r34JKY6Ih5XCtRw/aj+cuCMA73Kew4phNWzx7TFUPmrHBb0iENiiCBIqbuT5/ji0bgnFNUUKMC1Ji9UCyklyZiFWbo4HVb6Iu7bN5nfTXGHTlRnwvn0snbolARJnBLBxXxN6T5ZDC/XtWKHgw6EKR1lSsQqUa/6DzZomYJyuCgGS91lMsos+Cubj1MPtvEhrBhi9nEwnWs7gTP/HbKOxAnXrADzOy4JmWy6UHlzA1cIPSfd6CVX/u4XtT5/SrmODcL5pGwxTEYB7heV8X/MPlGu3kJtiDbjslMbnXwZYSUGX0q1lYPvVPDC8Ig9GPpWssDoQPI++57e9tyFMPgSfa7bRdXtNOjr/Cik4qcCwVFGIn2TGo4IvoNL9K7Ts11xqevmVPfI+o9QZAXDq2oJxySnoulsahDYOQoT2GW7pt4aQj8rg3x0Eq1Ii4GKgIX7M1IOjO9Iw4JAh/Ow5QR8sn9KJF+Lwr1GWT701g8jGfsj01oG3u+ZC7utnoBcyCXYKR8F7k6vodfgPTb8Qi7eMUtH+zElOmmRD6tfCsK2yiQREJKFf4StrOtTxa/caXGR4Df711kFmsCBvtbcG0St7yNXZAj/oGIHXntH4cNZYcJ/Xw453HqFBG6CkAYJmdz+HnPhLSuK1MEbMGDyy3qLbvpn0dvNS0ot+wa8PPYOl2+5BbJkslNpawHypevybJgmYnUHnmqPZMyaNIg+G86NKSVJ9GwOHKu+wW5gqPs9v5WJHY/gZ8ZzTZVRh+0sfeFi/Fxb+tx1zJfvYvcMPunu16f5nDdRwnQnZok8oQ+8QjnUrRV2DJn6Wt5RumiyAGJ7FY04nwMbCNBgU1Qbz3igKUviL3857c07NDZ7kMxnbYpzxhvhO+D8KzTMeqLeN49eQssnM3lv2H2WWIqWhgaJJIUqlQdGmkobSVEmbSEIoRUY0FSHaQ7LKKNHweN6fF/e5P9f1+32/n3M0z6jgk4rL0P5YC4q3yPI0LzOqlU7jO0aPYXvFVNz3RZdSsg7R09IjIBu/kYbpSYD5qCXwSi8aKpV6OXjNKejVjqW6HGnoGu0CZTKxdG+3GqdfkAWzk9fAY3UdPPs7DPR1GiinVICNUt/jrKNTQCkokJOnH+bP8sqg8fIGJwl1clXEC5BeUkFrEizI+OBwqj1ygruro1Fj0SrueYJAR/aDnmMNYKwuSmb5oOcleVrWp4m39klwmGwIbjT8CwUzGTROJ0L3XHdsdCqjxOmSOKx92RBTmIGrmii7rvAfYvA//C1EBK57nYXveY4kWvEdk0vP4a/eAMoW3486I99Qbew8HFR+Q6evDocFK53h8fYecPwSRVLdclhZsAM+hElAWoMvXkx7CKRbyHPSGQy+GaKc6Q1Wc1Xl04EKFCF+imSeveTrx1op+XMmndJHDllvA8FC0fg2Zi9cNJyFjr8O4egALWo1dobJpU1gYaHBt1VDWGarHLwqrMXrQy4cesKZbFvmc/UxQe54N5VNNbdQ99HxIBEcAX0JeiDm00jLZ4tw5yNlkHEvxIDcZWApI8Sn/YI4P+os7RIay34KYpButZ96Cw6Q+kwF3HNOC/9EdFC/2Vuc8zOBvcICaMDkJM1TEIJbCTMZWxGdrBtp0gJLuDY9g917v+P4xHX4JFCE4xWecsZJLSias5c3Wt0AXcqgY2bR/KVdg7bkvKKjR/xpCoVj05knpCRnBj3LY7mw5xDYD3ym8ofuNN5Ng0RWqkNDiA20PXzCcfqxOIIYXuZ2kmiGMly4KINf/1PHItaFpa5qiHN/UUbHRYhcUo85IwRhs4sqS5U44pM5w9DnsgeEz/GEY1pfQcIwAWwXaVFFrAu4PzWE618T6dnZImga+YOvTwrie9YroaN/PDy/Po0dajvwY64oLqsRhq9TG1Ba6Q0+vPQSLz+LoKbZm3nn/ZV8q38FrUt1AYHWgyDuIQcilZ+4e/J7XiR3AYx9W9DOcAn8uh1DlksPoelhfT6wTB9+Dg6DjNRVbPT4GMfvTSet2CDKqXaEwz+zeNhZE766ZgCs3/jBQjMnaL2cTFavtkLR1tFY0FuG8KIDXMv+ovRfIVid4k2XbZTI0c0eKkK08e2GYmixCoS0vmuwK9KBe1JbwGVdDlvcGQV1Fy/w/nh9cErVg29GbdihXEsLn98Dt9eTEPedgXV311CwezOK2t2AyLEjIH+XB7pHv4Y1DjHU4i+Pzkq1cF0hkLc7++Cuj+vp4OzZ+HK7OZR6fcFpe7aB/oMutF54CT7edYKAqj6UWn+Cy17/oW79eurTGAUeHUq0USyIVvfs4+Kxh+COwk2WTtaEiDsXMGxcINSvToH2rOGQpXMUjypasqthPl+IB15dHAe1+ffhv3ZhEtpyBx6FPSTv5SOg4+h8vFeVC7fTvci5Tp3PVf8BC+2PHCSygWQLt9FYwUiQrbOCa0/VqK7GC/wuWoKey24qq98PUzZ549sn52kgwweWzEe84KcBz5MS2UnKBwYEl0J3lDeMbg+mWplwevXlFj0sS+HyoY5UthsJK5ImUX9jKb2/chKLa9pQ3DOB92R088+v9+n8rj84rFQSFy6Qh/OXRGCfVCnGfGwCify9YGr4mQu8j5OE4RuMezGag+qiKdbPCR5eU2TfS/W8yFyE8yQTYGNRNs+XOc75otnkXXwec3ve4ed3w8E6qgr7DC3I9eoYeKwvhG/eEutU3IWzW/rpz7+N6BgijP9e64F6dgzayuSAy6MH2LVrOobapMKL/kB88sGKQ/JXsK9nAq7ulQOZFdnQdrIPJidtpkuHhLnh11JuylhJI93+ka1rFt7tvYpkKgfH1EPRZ/gNklA7RFsz/5J7/iku7duKeWW74VLUTxJa4cMln6RgiWo1h0RfZa1qbZ798Qy7zY2HOrFL8OKECh0dZcNdF56wZaUqFAd3D82aGIxaH0paWW40vUGDpzj6sd6jM6i9Vw82aLqS3HAjWLh2LXUrDPnzLsLLKrdYUKUVNfgYOc7bCVHb5/H1EAN2VZME75vJ5HFDlaplB3DVz1w2Un1Kv0VH8aLBTBKc7YcT7BVhsYwU7Eu+TXpVCjyz5RwdP9sBVmfv0Yo5FbSqdiptxjukmumNHzSFofheLqleuo1HahtA8NkBUG15Tk3m2eTpNArsVRbjiqvRfE1dHm58b+BxSapgkTYCzy6upx09u0AzKg4yJ8QC2Ang84K5kHDbAv5IBOOwtg4OkJPm+PSf/GrzAV7TP5X+PcolvYPqVKt/nw4p68JD52RabL8NQ4fO72ynh4VPemHLwQ58km7NqScB7DfXUpzgcNj/6SdvNKqkDxsy8cLxpei9sYhDzs6gZW+WQ90CEfAbE4AbFXVhrfVCVv/2E6TXlZHaPxUc3F1Ofe1XCLYFQ6jSVv7Z/I2M5piB6skLJFvWyeH3J5OO6FyOOZ5LZk8eoXeONcyIC8Ld1wrZuXPIB8/84Enm7bBBIAAXSnaD5u3vfHSLBT619OT5bxUod9F73HLAAf7c+Y33vkWy6Y/rOPqYGxdBJueOD4fHFs0ccFiLEmefozcHZMD9nCnNkFpF3vXL8a2eBYZczSTZNFk49FeHv3TMog0N52GnjhrYJG9G34613DbwA8tuBdIBp5EwUu8sVsm0wqLnh9Dy///LxuiBj6QuREjchkDeyrPXd+Kx6jp0ryiG89VMfWGmNFMnmjQfKkF29A523mBCYhd/oeTbfoxWrqDX1mG80DqIf9xsp7JnFVDmpAhfz2vylbtpbDzQw1dHfcUOpUUQmPSVYoey/KbEach49pdUt42Erm9VNLXdidNVQ8n3QQKpe4XzFqFJcHMsgGhlPm0JreO4W+pgcnMnSDdMg1sx4fSoaDSbna8GehYCrUM+7/22hFe2l/DGWj0oqA8FI4Ot0Hl+PKeLnsWMF99h7+c0at/5Dh/fvYDD29PoYJgpjNqqhWuDpgyFVxzLr8/GB5IRVFH1kF4MX0w/BoVg5LDh8H25KuQF58BprbGoGK+GG/wvsO3lQ9QhZ4YNuf/xNvP5JHBqPU8pZTgUPBsHpgyHWhktGvCwA8tX+jzb3QWDXzfTlL/TYKv2T7qp6wAlRiVkfeopenXZkaLDW1T+sZl6arsptPI1X9rYwe1yafguWglWqbtS5WA+qHa70ne5flz66Q1sqLOnHa7V6KNzAh+UjqDXbspQH3sLbm/5xfviZOnism56OKCDVan7sF5Mkea5PSA1jQ9YpWUIB7+LwOldObDr+xwS3buQa/500681k8D3uA7MK8vhs1nlMPufNJzWaICeKxMga/Id/nHCi1NFVXH7j6uQuSAMn8V84+z8dSC4WAXsrt0lRyVfiA4K4lddq6nx1B6+57kHlMZnDt1NB34OPgFPGlRhd/0WuDjFGDcs98egBQHwQm0Tlib+RZv8czRTuwmg9xEZSFrDi4itVPRVDV8IiqLOp3UY/EweH2jKoY7dU1TKrYWEplew66IUTP5cDF0P6/E6NNHmx3/AaXwH2eteY5ebnrSjexRd2voflDfpg5t4CA3eWMVPFgx5Uep2LlA+BKNXqpNwhS4kZ3fCxxBX0gwzARHfPppkIUNxqUth98VuGKhYQr66FeA96jXvfD9A4hMGWRQdQMTzGbdfjuQDp0VIZYwdqPfqwuQ/yzDi6iDnFN/hMd/fkZezODhtmwC3W52pqEuERjR8B4kbdvxstg3f+yLLdk7P4Ov9NC4vNAMx1Qt0L60PmrxTYYmHGV3SlcCz/wK4eDXBTo8aLsv2AAQTeFfnT53xTvw5RYbudX4EzaxfsDZ0N35beRBnxubToSNThzrBDjRHOaDhll/I9sO4/jpSYNZ82HdlGM0S/QWLe36TS+hUTN6kClqTy6ExpodNn5aAfEwQBuWdR3fXbdT6LBlHRGiDw6o5KBEvCJ2KmaBq95MsH30Ch6W/+LHHeNpO9ngr+hlOvpgHL31X0+Y7o2FT72faOS8QOq4E86oDi/DAHxdI0xZh0fow7vf6hKo1XnjKm2CcUgE5tJzG6akGPLi5CN6hFU17K08RW0xQapwZpHZ9hJqZMiCm0Eb5JZm8VbGHK33/8PY8aaRtVwBsL0J4tT5tMdnHp/vFoCbiJM/TKaDFzq50NdQbxjU6U6FCKFxLcAd7yyl897Apmpmpgtm9ZFrk2U9l63bxy1l3AFN+YOjmDDxnV4r1k7XYedpiqhWWAz/VJP5mfJ98W0Jp+6jleHr6Jjpq/5mmu6+HqaUBnDHZny69MgRLEz+a026MFnc98Pn8Ddyt5cMLdp2hF+PXUsGzHi7NNwEXRR2YdbkZfU4sBN/FM0l+eyP+y7Uj/00reX7XVqjSGAmafY9gpLkChPukgpC3PnqFOeHRfRl468xJiJaS44bOtWyonsKqbldx4KcxbDnmQI93uMNrPMBCptdp84zHmPdkOAVLd8LphMW8d14L3QoQhbvFGpAdegalfavRviMRYlzi+PePRuyb0kPZ/Rth3MJY7jolDwsyyuknjMS3R9WocZkd5TUF0Oagu1weFYueogaw7oUGuGwUhJ7zgag2zJ/DfgtDs7cpJCwfh27u+dRjb4tL313lfeJPeYmGCaRE/yXHXDEuiLfi2UvuU8bdrRhZLUIlb76Sb9RDWLrtNq4ZsAEPiUV8sWo33xHdQb4jg7BR1hZ3mlnhH8ly2r7Ugqodr/GXXfLgnmAG8f/G4PYJ13iSdiBnhcyhkafi4ey087xq5RE0LGnjNCLYsu0iiZ/PwHHBWqzm7YN1MZXcNrIQ5FZ2s/0NP3y3xAAWbBKD5etzINbyLiWONMDDuhU0vzmYrs34iUuXd0H9MxH4mhPLaz00oW5xPN869hl303J6u3AD5w9zpJ5TqvTuTScefmxIbReG4f6NOrB0uDnYtt3BoEvbed7oRMwyqQTPG06Qfe0HlZdeJqWcRFzcNBzm6xtxVfljrM3fDa7rduCS5yugLeE9pweMp1oVSzzaKYc/fAxBZlsLSPyopYgj0Wi6JRiGTTaCxRtUSHTbTpjzJxbHm9zjJFERSJa+hscHy9Dgbg5on2/AR8J6FOf9iwvHrqWdf/dAbVEkDm7SgLR1B2hRtC0a3ZGgPBtkLcFIendYFyNGlANbiZJgbRznhY4BqxVqfNt5Px2KfII/Ht/iG5iCwodvDfFrNjdn3+DnRzxg1BFD2FZej3KjGF5ZNIJzng/c25MEUPuc/vs0msuPnYeuB81w4IA0dP414/EfnDBw4BEcixaguxKecH5xLpvrrIE7m+aSSc188lCwAVvZz2Tv/w8VzxmRa54qlGiGs57jR7h+ywwcv1vyf7viybsG4VyNKQ68nEQjIvSg6MU7mmj+HX9uv0aD1zX4weV5nJBkj04PVMF+vhINtxTn3mIlLF11DpryN1Pp0wKOSXWmQ2NcKH5ZHjQ0D+XQnTyQe1UOzVLjaPLitSCctZHfHvkKRVMXw6d5Mznp2Bq6s04VZrY/Z/HtN0D9pR1Ml4kgj3PHYG+8JRudvcGL5j5ldZ2XtL1MA9Inv8c/F67RzheOdPD2THjvFo2F/g3c6a6F32wOgvYcd8yOsgJH2Et7lmpC314D3FL7BfvD3nD40DvlxplS9etCTlvxHWtytOFIWzqaz1fh0oOqlGLwB+8/+Y+bpG7izVVE/hsKcG12Hb/xk4X7KTd4h2MCnMj4RbJyt0G9TZuCTsuy7f4Azru8lged3Xl1CEGFsT/mrllJZd56dP52MBdMU6HjFf18zrIcj51cx3qajmSjJATv626DrdMTsH+9BsbcLYHRCrNRNzuQrQZk0TptGx2LrKBFJVYgdeIgiCXL8OrK+fB6w1lcIXsRE2+L09JQSwq8YE/XxsjSCBlFOL2mBqO8E2mC3UJaNn01iaau5dbKA2RrPppnfVcF2SAliBaWBceJ30i/6wJOdA8indYhVtofxeuedtMD82m0z8ufFj7dhAU7hcFmqyunL34N1scfQqyEKvncOoIzv3xHYdudIPMxBJtLvPjDbk0Ik5mG0v2ZuBy3sEzFGxjRdJ80q65AQoM0jDI9xhLXxOGWtBy47VDmr6vqSbRJiWMHC0ChwoNK3Pz5a912Kn1oAkmx8yjfW3yIHf3Ip+Ey6XzK5ck7JHmyRR9f+bAOrx1gfODiiCcfWPHCRFEIOkrY37GJrX89g223u0D8/gi02SfDVaojcIR+Fxas30OH2gwgytgKRwhnYvWECbQmNhcPOR/jd1EBZOxrzYsTPLFMtx5kP8iBadYI9npvQXNeBGLSUn282Ap0zHMmTd+3ESJke8mp8jY0PzGHuJH7+JvPBKgK/A2/jp6CKYHrcd1pQVhg3o0N+na093wqPz5lAZXui9CnVAxU1m6n3StvgcUEP+rZuw0WbxRE+7lKKFReA/MsAapvKlP+akZs28DFb4/Tm1mjWCTlG8lIbCW/speobpLAjxYZgPmdQajXWcUyJdrYm0m8bvpr3DTmCoh+H4YpzZOh2tgN280NQclqF1R8/QWeT6zI3eATeFqqsoymHgcUjobImWtQTGjbkN8YQ871M/g0K4/7QpRRJS4COp0Tad2CR1hweBBF1/0FgftTqXyRLuxu8gXFpncgIL4MzfK8aEvRZErN+criM7ZBiVAt6md9xZh2DcgzbsJxsyywatxaulMuwQ3Vh/nuZhk+gFdh9X6mnLOf8HasLkjs+Y8qLS24uvUNatschk7p05x2v4JPbBVGf9/7bOA6ha/pmICM4SMuvDKSvoSORvHhMdDXtILzdcvI9/Rrujz1Ky2QVoQdX4RA3CcFRn6aROpbf0Hy46soXNbGh60mwucroRQ/5QCt3reI/ixzgHORgrzzwjR2vuGAtZ8isAtKYeTuZMo3twAT090sVukGujUmkLvLhkKyC+jV099QWpfO5m9sSKJHC3p3HmGtgs0gsOUDdEfKwwbDYAy9KUrKz8Nw5fAbKJJ5Cv77m0Y7omuxrvAY+1/azVkjzWFu9UR45uYP68oTwSLOixfUzgCJlOn0Nv4TxPwYmlOd7bDfSBrOPnoBMYP6KGAZiXIvjsOf6j20wGE86XnogGTvapaeHEoO37WgR6uCHytKUbjbUG+f2s7jXH3h8a2lEFU2C6e7RkPv8Fe00WoUbJDaw/1Lcmn631CQL7Hg2bWbYW/lc7ijOwOnxC2DrS8OstIaQbB54Ezn9+3DybbmoBR9GGS+D/KlyBt05ls8F56oppRRjfTlgymEv83mG7+rUck5HD9YinBFmj0eGdEFFXsm0P1vw+hVSz6KLVeEs1uQFp8xgHMv6uBSiSY9oWFY2bsSfylHwtg1SiTo+obrIiSgemEcCO2zoW7j9RA9+gWnLXtAnmIm+K/LhJ43reGuL36g984abHzeYFmtNweur4HTq3yxLLWNDo8oBNexA2z6oIW3zX4CZ9bKgOyYGBg7MRe0PylwyfW1VFL9gd9ONEZZtSNs130VjS50g+wGPdhGkcBFzmwdPB0N9BPwGG2lI8cVsFrxPz55kEHEYCa0iivBmftXcM3BmTzsejIuKPGCU68FqdFCHK4KTWWBtQZwf48IeJQ4QXTtZnScdYP+xPhxTv4w0N2cxB27NkDvl1ewNUoNBS+s47INUrDhsTGPmqaG6+t28z+Dwygp04KVC9fDm6IJnJXkQ4cye9hqmRKsy+skiq/FaJFxrDjE+WouKXhZ5gV2FKrxWBngztbdUFNmAWHNLTB/tiqZwRHaaqRN4nlK5FmSjCsmq2PZd1dyDc6gvnZlCE8PwMqf/3jC8i6ucjjLl63E6dQ1War06wS/9w/5a2vGkPuqQOYlSz7yeB9O9dvFnsvOwOVTbvBO4yoreFtwc+hqGtmRBZO1BcDdQgOju+zZZWAjjd3yCoK7k/jLtG/YWfyWA3XWwrRl/3D9a1u4UfyXwm5ogHZiA0Ul+qHOtBXsOkwET915Qhc+TMaJ3jK0VcoAtt+p5B6FD/jQ0RmuVeuCYGgjuFoHwuID9/jSWku2+88P8/brgG7fQ1idGc7BLwuw95oK7dZuwP0uuXTmzFT25eV0+EwbupYoA2w+S4rzarD/kirpmArD/uvHWPDoHb7m+ZJEzr5nzUcz8b6ALpz0+osbY5ZDUtRn8B47Bm1ffSX+EoXnt+dR8tAzHBtH0x1sodhuNbQ8Hw5+hncwLbAUxTsL2ML/LRppHKaQ0CKS1zuIkcuHQ1nEAvghc5kjg2LA4ncwFf7Mg1kiKZB+JQ8SjDdCz7l1PArF4dDSTjIZoQG6nuIYWPCagn99gfjRCjh2Sg31b9kOu5OycI+kA6xJPwNnFKt4Y4Epffn2mMYaJvLY+R0Q6ZdIRueU0TbwJ2w/oAH3L2+mjTpbwbgiBEoP2INy21xssmyh8sv1kN0XBAvXDODrpxKgulKepRvvwq+leeSf68RhqsuAUopY0UcWPHedRpEZA2xQKgvFvREElfXg9NmNyjdo40ZzP7iY04hln80oKfo7vT3fT+5FVnB+7j32m+LBYSobaGeJOhr2z8JZ4jModYch6An2YP/tn/BNeQT8+ZlIuW3TYPyqYfRvhQPaCU8G90OraDQsh2nKrZgd04l3X2uDqMhXCjf0R/utTvjp6CbsE3vFDimjqMcrAJRMLtOufzX8xksIYnLqYErWUx6bl8QLtd6j89sbnKLN5FFylkxfa9ClEm9MuGoKFxu/4vWNXvTEo5LmbJqGVfci8NXsGKq4fp9WO80DT1FzvG4oCFYr//CZMRlQd84RHoZHYk2kPf2e2g9FT2Vpcs13HlQIIAEva+h0RC6xPYaHV02ECXAFTs47AouGuDZnojRovDtPknAbl61wAJE1N0lrYiRnjJ8BeYG/afrw/eDj/h63tTZz+9oQuHmuDnUbFKDL9Ar9d8QAqlyj6er4n+gzIQ88glrh2dSJqMHl+KFwHMw5IAopRwv5Xb8E7d3jDiPM7DHzuD7a6JXyXMcMPNp2myxbCyg3wxrKB19BSW4LCWRMgekBgxi/wo1GJ/fhcssY8rj1A1xvRfJMq7FQ0bARHw90otCxQ7S4sgY2YxVISh7E/MxIeBlUCW8ERFmq2BCm7VuD1r7zcPb6CiobexbFHv2FaSCBy9YOUMqLYRAXcpq8he2g+e1n2DQshFW+J1Fc5WeW3FjDPZVDbHjen3MmP4Ux+0PQN5OhYOF9Op5lhFEqEvCf6hK6aLaZV+zT4dUTxjDNVORb/pfRy0ELxu28y9sub+TplpNoYswcujhRhLzdHsDWKQfx5wgznrj0O8W5KkJ1VCjdfD4RZi/y5nGL03mgop6X607C3/7z4WbsJdaYEoeSZTLQ+mcQdM8cAZGcizwrr5uXrSlChb+a/G3Uf2jaJcdVHQ/5e7wjfEv4hvM/emC3hy2e13pJHdKLyD7eFVrD7bl23Bt8lLgGXvsaQDltoOfXjbg2Zxjft/lCYVYfqVa1GAfvboRp4dchMGFo91xMwbRnEOsTF5L/sDKwna6Bz+72UrG/EDbWFfAzm2c48e15zn2lDS42Pnjr5D34susnNZVZoUTSJprp7AMie4f2XLkBpBRucLimEshd+wjGfzvo5kRL2i86C603FoC26G2YULyKW4QCeF6nCmnOUoM5STPoxttWeuUfiC2yVlTn+AhETKRgjU8SpG87iVEF8nQYhGFmcDwemi6Pv7K+oOvkJMI1zqQuBdQVF4L9K66RsbIM3F4iBDl6MynmjjhfXVRENjqVLLd/HTY6vMQwsR6Y420L22bMwHHZ1hAQvQaEN63j401CHOMxFx9ui6RxP+6B5L9j/ObmAbZxTKVLasYQZz8FBzNc0KNLCzKu3Rjampcor2pO2YnHcOHvhXTM/wH88dQEBUsPvDQlG/jhKr5v7k15a1dBa8RK3nvvN6k9C4cDhfWkvEkcflWPYg28SGvW/cRem49DWf0Rs1J60HmGFvmmrEDh6lN0KlQOUhf8Jl2bd9iSuAuMWw/x+1++OHHOKVqRMsQM1uaw23sLqkw3gFsfd3B42g8Ia7DGsbtngsUuRbh6Cyk67DkI7aiDKEMVXrZEBZ787oEFvAeWKVRB9tUDMOObG0yTCOawEIT4cyIwrXYWTlYBMNoRzN0rnuPn5RuwxaKA18t+RYFJp1nR2w3WiA7H/SbCdPe0EYS378PDP6Wg/2oadZku5JsjZaAvoY28uJBMpQ6iy2t3TBLSgJ5R4diwUohFHFw4dNpR2FlawVG/62nYcUFIEsoi67eN5HnSEDLNi8hz/H28NHcDFbqvQ6+l50A9eTS6Vn1ErxgBrtjfS3MarOHb5kwMqnejffq/IDTtJ7lubID9ZnWo/Owa/vqTRYorA9iwTQy2vejA6uaP3GtXwGVBfSBaZsoxR/7BvvfWcNC6EAte68CPXl24ouRBc0ZdoeEzLIjenaSa5lzIzLHi/cvvg39XEf2L9Mad6obQvnc6ikS8oGlVoogHO/B24hi+keXMWUpi6DdsJfqY7MCTM4zhSpAJa9pcp7J1P3CTRxv2HE6lyye+QsuF1ZQUN5b19cZzoYM0iHk0w72IXF6/fwaIzorEO6PKWf/ST1AePwJuPxjB/0aksOROabhS1cbOLcUwodcGNQ3m4fsXP6Fe/w8PW/gCOgP3wP4V8XCkTBrmlq+EgcCX0GEbzpPnxIBgvzO8ah2AcaVn8arPSfTves1B/mPA/NfQXSf+pDiz92CX/JDc3prC50XK2PNnEr89weD5/g88jrEC+xx5XhReR3Hap+lN+nMSj5SA4JMp+DFai3cF5PP80bpQI6sEgZVieNJsLAvwetzlaMiC/mXUFtvPnxSO8zeFKdj/PAf/Ex0JP4RywKGlDVLeroLFbQkkETSZ93utoge7ZGDd524Qow2Q5KkPAYd+4NgtxRhcup8lZ/hB4uuZQ30jio8uq2BNfC27HZVB5+PKYGS1hxzupdIR1YtsuRnou85UcJR0gq3nYslae8gZLTrIIVgYDklIoF9pERSKr6VD9+35hPpLsE23hqPO7+hB2E4471aBHwWVIMu7ic2cc2mOnCUcO72XGuokcWNbHr5qqIIDyRMo0WctTZKwgYEkOSiV6GLF25UU8NeBn/pE4uOVJbSzppQbVk5D1WZNni9vC18i9cA35j2qC8pg0fUumKEVSAPph8Eo7CMaLnBCzkC2LJGGpolDZjf2L15f9Q8/PG5AL4ltbJj+F90yTEjbfQIZbf9EVaNkIDSmm+xLEnnOjwZ6Z9ZAC3bNp4bBYD42tpPaLRFyfyrzwZviUF2TyQIp5XinczG+NvkNd86fh4cCj6Fk4Uq+Mv8RNkQokrLEcEg55E8+8oE4sEcHpjUowfFTo0m1K4Q+nPKBmw/nodSJDMwb8jyn0yno2bQI5b00cLjQMnq99g94/LxBXbVJINc9AgwDG7jcVh4irMex3p4yHki9BHO0p6GuTQpvWezAzR9i0bLoJX222QICs63gv5JDVKK5lnN2pcKg1V3OSz7NNXpjwCnxLtqkFNGxiIMU9EQPrF4rgPXFI+ydGAudLUwh2p2w6HIkGYx/jhsuZ5DBF1+6ESUI7j/WsEv+Hf6gKQPx76y5a1UZR4YmoMTQ3pYUHaU7Y36hq686/LEpR8XvgzDcyQiE7yXD0fo++lmqDRatESwkdQ2a9HfQl8kScPt9OLoXa5NxTg6+3qWH63vKcHTfJ6iQT4Oi//7CRnUznD80s8nPT/Dtsz5wROUDXuj5Rx84bKhHV0L60nR+3OiBNQ9WYpGuAqQnBKJ5ZxOlxhZD2IxODBCMp/R5x+n79VHQeXoAnihak/RcVWiKsCXjq3Ew4ByF//KmkdzTK5x/bRNLb/TDtWUPwKgwDpaVGUFpmCQcXMj04P5+mN6oCKW5xqyxSYsarxxnzahq8PhcSTnjEdoz5KB+52NaaeyLPlfEaLlBIK87txxu/v97xJkaiDxmADqWY2GeeSz5/hvPn/bUQfcZaxQ894iFgxNR4sMCENj2FdrKl1DyPFHQ3HkPGh1vgmWEFAUWGYL07BHwpEKZXj0fZGm/X5QssIoTtQSgpi6Gvm4PYy3Pemp9Fo6+776yRZMaT19qyheTpXCNjQ36OAlCv2ch1OsN0qgDh+nZhwsofcoCjg4bQZWNaiSyLAniPIupumckjDwzic3OvYaZTjP50rirpDK6mCxim6l6YhfOsy4F9cl3YWGkE0ieO065AduhOd4N/ku7yUWiUZRpr0BzlM/zvZvPIMHqIfrKSkLI/iCS/KzHtaoytNihFqduf4izzMJh5qS5bFATTS0qO0FxlRkkJtXy2qID+HpNJV4ffIXjDg+jIx7F7NZlwELjVWigbjyU+2tDlWgITTP5hudf6+JUnwZc325O18dUkcTIIAoOlwSn4DZy2WcLS3LtqTUhAwxuToJr96IhxiEcz6/JAqHL62lM7hYoja3B8ZcQxNrM2fZzEk14HcChlk28PyQJrb/XceP478TRD/CxSAgoPDMFibdzwSkzhpc9nAf5Xlfwn3opZs/Nxh68BzpZh/G2tTwWDSjCiDm23F2kQmaXloIzS3HxDCluV3iDfbM78NnTbvxmmoYi5cPBu1gAphbosWvWG05VbePvNmsx/JcIhWhNQYvaKDLdLIzxQz1d/PoTpuh3kZX6Htq0R5FDtD9wcs15OFCVTzpVC0A86guzowSUCsrj1XorbJwghj/tfWj92yTozq6HUDV5Cj9ZCr/7vbgtSQcEXN5jnPMltr3gwmNXD+N9svkcNtCBubapZHiwBifdvstaCxmkL4+kaHU3/Kw8F4+tzSDH2afJI+o8dbXvBimt1aDjbY2rj2hA7q9CWuLQhE9CZwG8uQ5v9fNZtNGfF0Ad7b4QiVZuLnBfSxsCRK1JqoJhy6pDsK/KGiY5KPD9kaL0Lm6ISxTOUajAQjxorABykrlgqJHNjs32nCp4kE8Nb6VM4xlwObUDCzkQGzXNWWCbFbxo+cYnhF142RlR8p/4A6xc59FetqB5g7to9Zc3WCEym13XqcOZR2JQNGk8FHe7UulINWrQN+Jtk7LIzd0VFu+PgBmWliDiJA82rj7QcCCD5Y8Y46yjLizo0shffC1IYl0bbvv9GeON3sLAdFOYHAKgJWXF5wUO4gLlRpTZ8xgfVD3mLb/7+Lu6Akd4tGPUz9HwuuII2xk/QYWlzTBXQBf23xKDXtu/EFg8g288kALNvR5kuEANbjw1wvXGU6nuHLL1pBDwCryFx3ymQrDREFduXQQmaVn4YutQb+02IxtH4GX1ziy44RW+GrkMV58LRM3zZ3Bb72KwOJSJznZCUCgrTv/Sc/Dt1mw4ldeBsnOX4/olXfShXwh9S3TwtL0mVihrwaqzE2n2sgGyuO+KwS66bLlvPS3UmgotH5vBo8oezgrOwt9LxSDK4QUbv4rmGb1K+HVuL5U/16JzXsNp0pkwKjyRDrbl/6GyjRG886vjM2mOXPjvPvc299DTTVvQYjCWvn70B2Onrey4oJXODNODk/9yYMGfWiqw8uG2fW048p8vXL6nAjq7lqFJiyI07HwIQkdsIaKPwOlUPR1yAb7zZSJ2rKrB2JWTYGZYFMzPnEAuG/oh4cEY+MZG1PvbkMYOMcLivaVk+HoKHAwdDULsRmorCGf75PHJIushb4xnLzczdOveyr7tg6yWewIWexvRtf1BmCa8mDpHy8JeMzOY1UOcP+AGOrId5NTTTLu3uvP172Lgt3IBnssdzqUSlRiywQjGJmzldsO3nISmWHT/I6+foojmrdt41GFxXlQhhhMqTUmyVwgGWn1RdvlzCo9IZB1bBeoI/0OlAfIUdS+eTv1KGcr2EzRjmhU8vBuGXqebQXGmJt5ae5xTR5rwSsWvoPc3HN9IfgSn8dM5wF0BbK8mwODxsbx6oweoGASj+pB7zlg5naJtzbHkmQLc/ppK4msNQOq/I+i/SJ0C1OdDYG8anskTQ/l/TfBmTD72dwzHqxbFtMleEwwfqEBuw3RuDagAh4y/MO+SMB5v1OBx91eiW5Q0X4uxpjejNSF27nGGVwfZBJ6DFGxEYbmfPH0W8I8DEXRseznXNBbzmmY7GHZuIvGhsaDy6STu2VsG54NyyZZWwpl4Ef4TeJuiauohbKkgqM9bz9dqDsIqrWpMnzmZ1NQX4dpWX04tHAPbMv7x4A4dFq3UAtuwDNR1f0zlRf+R0nxx2n95EcxtbwT9g7Moe/kX8PknAA0y8nBZYBuPkUrFJEN3aLw1GoLs1enXKwMofT4Jw5VFaY9kIY4/oA6dhdMx+epXCNz1gVd4WLPkshU4cYUh71s8imcE3uOvo3vRarQgKGX0c+TvnTRt9V3M+y8Gd3Y70u3ro7B47CdujQok62drYHi2CERXmpCJpTh2+DziXWUfSNJsB94I6+DKNwVw5Gk57Y4uI5tJQqCS8QnrQ/X45fxAuNAszyN+rcdR515gn9RZlNozldxyd4DSMUWYNaIajN0a4b/7nyhMrwQPrlrClWE78b+TG9DlSBzuWFoE0/W1wCKykwMW5yAYF6FSvxTqX19OFwNmUoh5KMllR/LTwDTu+8WwSOI9pn7+gl83msODnZNAe/wVnDf8IWSpKoCp/AsqluilyjGC4PdqP4/C5ZxslwgLlp6jVQUHcdmmXxSEH3Fv20ycUWkM6ZfNQN+0E3eZPsWX++ZSdfV0uupoA41r1PCTrzJG1kWy3TA9Fq+1gAiXD1ClGMa1VT9J38cIpQIbSaD4BAuWLGWVKbl0TzkWjhhagQ03YsPTMazzluhirBLrjvWD5b8nw8xTV1n6/WKetvsapPbowtIH6qTgNTQja7KpPiiTW1t0UTBOjBKOepGbTDMZHTbAhC3KkKz9gzP/G4QFORdQqW0i3/YKQ1vpHyRdG4AXj6zkHZGj4VXiGOh/8B1nm22HuwvXQPudAhz9Yji/frIQV1x4ii9micLOWfIcSgg7vHdSVNt5TurYwGO9ZnPZzGxSOSDM0nVj6JRzGB9ctYe9nw3d3/VOWul+jYuXZHDKvwraGV+DP2dpU/Cqcfw31hwcViSDYoUanH53HObNbcCeBfOgIjgB/o0SoldLAnne31cYF6oL+0yO84ivw+Dvxzoad4axxKCJ86OL8GKVE+Wabsa6zhto8k2Sjp3VpF5fA/A2HMRvibd5sKoPxxfakRw1ksLl92xpMwVicQBjy8NwS549fEm+Ti3qJ6EmaC6kFRlBhosanHu3m5IHrsP1sqnss+MDRCRLwcsx9Rjq2sV6X4RJ0foBdg5/AnFJc1h87GuoTEjgX7tnw+OlQhDQZoG+Ayd42/pVlGKvwvann2Cv/CjOtLiD61KtObeJYVKaOGhZjsa7r57i/jHpJCecQfIz2kD1ox5KrNwDH2q9YF3RLEh2M4OEf9JYU3iLNwQao6BaNGVUrcXybB3+ERVHE81305upIqz2zAHCx3+mansBCi64AnsmvkLDDQq4qGUHnq4TI4WPEiRbkw2VbAZfjz7g0Rc3UOw6Ld53ahRba33iFz+7eb/oS0qzioCadClIWG0AUR5j+NYnQ17RPgMlpx7kNamf2FS2B9P6/vHcvrfUuasDHH6Mhq9Wglgy6jM75ASC5+JfpL5pDaad2093Xl7jrtnKvHNKECz0FwHdQX32NwnCGaedMPFZODX15VLyDC8yUtTiCazHJ0Pb8dBXGbikcxic54jiNtEUPvL4J8zNt+U54u+52SCTM3Nc6OwLFxw2Sw4W+w6iStJmtlqjQCXh/8G+yh+ocVeTzFZZsIxEANpLdvBkv5Gw19qXN+pPoSzB+VATuQRD09/hSZ1Q+EcX4YBnCK8cfxWHpQ+DL02tLF+9BGw2fsOdeXMoZFEU3FUeA5wrDk+mIS+6EcFxBRow3/0Tuo6TpYvzV3OV+kgsC7zLV90iqGSsODgLPKdGteu4+KMSyOQLo1phA8zY/5wXa9/FDbrpmLb8CL++XE/WNeNofkUlwtExcFDuCfT/95lfj3HC/jl3qbRJANfVNWCzmQL5/veCXeWvwL4sKeiAHdhq1wqy4zz4VoYXzPlogjsv7YH+l+fhWJ0CVpZoQb63JkyKuc9S35bS3LJ4mLHRHR4HBvPKjlzMcW4Hw2lZOP/BePRysweldypwpU8LT/44wyVjFtKubS+gKV2YsgZ+w7n+EZSSLIj6RiqQukecOtMk+FJlPdv/SsLVMWq4sGwsfrq6kvdXn8XNs9fxzf2CEFpSQi0PTsCLl+so4N9CuFK5Br9cbkDzB3G0NDyDT1xZSxFnrSF091vu/LGX6+6544l3FyG0tZIWndTiZ/4KGL3Tlv+KFsPJHoYTQU44X9wX27MDOGZxEFRY96LM7xkktnsOGmgtgT2DS0naVQo29xAcjJJEo7oG2OHWCfeFMjnigBZItfvjFGOCG417QfigAdQYtOOFjBwqG7YbXS48QPlzd/i8zHDSf/QVi55vwr0cxKdfmcKV5ngMf5sI60/L8o0JmeBcdhumPRPDtR5DTLT2PF9KnUBlf0VA7Mp9Wqzcy/0mt9gsfTwZOCpxpvgV+hSylgz3hfGUrib0CdeGYIkM3NQeSPmBx9k77w5Ju0xlvUpZSFC5SW+85LBm0Sx6s+Q/KG6aDpOcJMDbu5BrFLbRhkx/jvkdBoaXrOBe3iKauauMPGcLQNUVLYjISiWxiGQ4We4MSsN28L2tWzjQ9jM8qHKGM3AHcpWHzrfOlQPSxflkwx1cH/uIXmjSUFasxgcq4ZjSbck7dX+TznpteHJ+J7iUdEP66wF8X74NBJZV4K2KMDCTDEA3JVu8DcPo/Vx12OZ0HFV363L/lhI4+cOJHVN8SWFcDgvcfEw+mzaQwtwW/LjGBKLXrQblgKvYcPMDWtdW4YLQDlxuOQP2312MP6Y94x73bJCQHA3m6wY48UY9jd/0jlNDNuA7s4vYeeEPPjo1GvYuL+N7yrN4daMKSGYvAyo/TocvX4N8KXVaUpmMq4Is+O6ekaAW2oZxu86C5xMBWH1qN967n09bC7eRtm4N2/UNQtCcPux08QeThGYMsn4ATQ8RbAbGUb+nHcb/u05WnR9w4sx9qG9lTcmHV7GBdSikNJdgj5Y8VA6x9iO1udAxN5H95xZR8ZcVbN9QzX8WJuDlaYvAd20BG0SIwMhv+vTxnQ7Fj7dAAbOTvDbalIpxPxZ/nsUBv3/zoPJLXnVXBmJSTFjs0Fe4UqTHGTFx6AW7afqP1Vz0shknDC/Dy1Mr8Os+KYjveUpnfb7gpIR0UDSZh1vSr3Gn5zASWj0FlcPe8fyHq9EhywqOaJuA4XLiKzrPQVYwmn6tXwpaXue4WvoDbFzQz1+nn+FMYTt4u92TFTJzaVnsTyxOU8Pr4w1pzmpdnrJ8BtmrBMDPPh0mPxuogWCMWbuWjrxbgu46w7Hk62X4+GQTN0+9Df0RmjxzuzdsfioJ0geYhWfKQvpIbVo9sYTWS0iR8dIKtlp6if1+t1Ga72W67CMAKgU62MQO+MB1CQUX22FayHDeZzeVI6JC4ZjFSoxcog6Vz4bD2lZxHlOewsbfruCJfldyf03YPfCKz/Y4s4jwSO5JsEPlqUP8vmEHvpugjeobwmDsLDU2ndjJgbHCvN6gl2dfVOKHp9zx01YRiCz4h0vv9vJtK2F6v/8T3p04F4P7m2DXNCV2VdTAX7NO8pwuYZB0uwRlJ46Sn0srRPgdhXkjNbFwlRLd/n0NHvf2wuyy+fDiixQUnyWyz3xPDXNf8HVPSTzz8hB+3JtAKl6NvHVpADr0TqCKGoS9gZ0w8vl7bE/di6vfPafvlgNo4PwUx6ueoYl5m6Huw0+62I1gKHaV4pp3sP7w06wzYRwcPhHJAWW/Ydl4CZjc8BKykmOhbboJpP0o5oLNnhBZrw/2N+YTRL/kqSPUQLf9EfnaE94fHUpGtibw3wsVkE50I8cn++hL/jfKMnSFv58zePu7Hm73MoDifVV83twUmjIWwaO1TfjxuwlWLb6AJ0qqcekmDd5Qfw+q8sah4/hdfCTOGAL3i7K8xQz0eRcE/lO3wiLdQZqStokOpg1n1UJDnOWmyP63rOFQbTGo55SS0LFukhgfhqYxBmhw6BVceLiJWp5XstrMpbhojTiYXlKlNyVJ7D09FbYfbeWdaafI/sROEDpnyVOvFnDEmCccesoO1pw9TmOz+ijfTgI9DqaS7LMITJk4n+9u+gBnKBjlR8YhtmvCrHEt8KfeDx8/KsDD7Y/R6ksEaGk9pAntR3FwxQ2Oe/KU9e5pwyfDC8Q4gcZkqYPgSHOs2h5JHSe3sNmBYdx5chGdnDIVPd4qQt73cn4kpEh/Pveisdd5CnmvjWGFEfA8WwRnzhjJtdUH8ewseTiXDewYVAwOMZ0okdHEU0blQ/7deDKFH5T+2Rmac6XJZZYU1Mlq8VGnb9Bsdot0ItfzTRt9Fhi3mzsMW2DEqdG0+5sDB60bmueYetb8ZwqaYX9pddRdeNlUDWmzt9PpLc2UZJsOOvJp2D4RQP59EglsHoGjdLrIR6uPB6aYwU9DZRYNTuYJQc8wJHQ05alZgOrvLZjx9hbhfF8sf3+fznU+IunEIPyj54OB051oqVEBZGVIgf82Vxx3ZC/LmanjuVg3rjV7zmKnB3mkujFeavzDx/b9pvAGG1jhr0GOmWX8/r9fVNtylz4OMaTxhtuQXrGXQp9L0AyzalqX4wjSEabQN3MeT1xYDLd7p/JywXR48TSAQq/N4pU6grinL5gitmlA7LdvZOFuQrhgGShLjmDFY5J0cZk0uJ28jGNObqeO05IwztQOkhJ3Q9tpB8j9bUJ6s0+wwPwuyO3QhxZYjx90S0FNpAv9pumAmXwLJZvcw4sNE6C1MAjPx9/gBR2lLOA/E1uKTnG2Ugz1VArBVqUUGN13nKKDnKDc/SNuv58N3RnRpBkyB7zV/cFcsAB+75YDuR1L+IX3Rk68IAcvxljzxHE92PWjAO4NyNK0Q3Yk3G/Bz+c5gJl0LFPscZwpup5LLVJQz6eF3t+X5sNaj3jeoal8dECM/d5bwrIzQ864t5crSh7gylfXIfNSCN0tTuIjzUvA5P5h+LY7gbKahkFvTSXNXvSHzP1u4ZSGhWCWHI7vB9/AJ7fJ2C7+gOytCTbfU4W/Y9row3IXHD6/bWh2klBKOwL+LjyJKocvc8vZ5yhdMgvq5ijBhH4TPKc6ncr2WpPl5FhYO9AKeWJyoGfjjjvk/PjPdHHQuSEOy088RQlXMVSLjMVLGyspp8KItQ+X8b643+Si/ArCFptxcq8dCFV3smCHBn7IecMKtbPxk5YZKm+Koub+AC4f5UmCr2dA+yMl2PPFC2JO28K7MDWI/3iIBad0U1T9e5hz5SFcMDgAH20TSfy1Jmh0CMBUkb8g1i0JTWcHSPq7BF+YOx3Tw96D7wxjbiHEmj4DuPlGgRf0CvPMkRGQKTAFa/ydKVbfnK8+rYDYOUYkf+crJ70XhuRAaXpp+piK0x7j5fvhpDnRmLf43YLCyg4yuz0bpj05TTvBDPoMV3LZGVfY3f6RP2rs518LBlDy2Q/Iz2nF8YKAqxrT+GkCw1/3dlgjL8R/ru6loK5C7rFbROcE1nPE23U0f2I2OK/ewOZDebrrzjBc9EQUy9TL6bTRLV4/8hl5jdoHcjIN3Lw7BZaNyOI3ERKQ3X0db7MPRtjL8eTXFXjo0xG2HPAEk8oFlHu1lCMsTeBAvCwsnnuAtz86T4/HBOLTWypw4OV2nq04F2MDg8lTLZ5l+/N5h50IdNWEwsZzmSyjVAk+CxjNp/wBXL6N7JrvkI+LBLbM2wK3s4aDc+d6FJi9nLezEM0/N4w1Z96A5W9aQGFqJhx/9gU0Sqai5iGAnXu20pdMO/B8MBPc3h3B6DAHOGP3FfyEU3l67T/Q2ZCHBcUaYJE9nZbtXw7rVyhSWZEuH7V7wuZHHVjUJh7Wd45Ar0NbqC5pJKyWPgaHo5J5UXwPP/I8Cys/rYeIxkKwj7fEayl+OEpABWU8RSGtcgQZu0fwgHcAy4caDpVsJf+PuPPuB/Lv4vgZimSPFMksq2xCZkg0KBmRGZKWokVKRYu0lKa0UIqSihQiDTKaP6OdEmmgFIrbs7ifwfU65zqfz/v919fSbB0ZqWqxzNIlHDJ6JlpnK8Lkp1Go9f4QFUfvBzkXO068LYwfnyRB3tZ0WhyYSmY227jOeCKcLpiDcWkHyDFZgccalUPrQyHSHnsY64bdQueGM5x59g5u/TkRChYmg/OqG0PZdhhP34vg8AUlJHsuhgoORtP2xgW8o6MTc/p1YX3pEqh92IoxyXN5q3IF22s/4xXbppB9ZAYFpceQ2dLpeCh/MrzpzIenf0Ux1iIE97YvwGbFo7jYuRzOOanw5e0uGBX3Gu6vQthRfIPHGQlwpN9ujBPcxtA0mn9eTeML/65gnuAW7NityXZjzGFyiy6Lr2zEV7uTeePQHcWaG/G0tcupzViUZ+1+zjlfF6NXkTVsfyFNsy89gEUHDHBnbCW+Y1dK8TiNfbc8SMnqB4BOLcl5jYIm2z1Yc9QWhCfkg3TkIn69yowTgh+xkKgND6a7wiK5D1z0ZhQYkCQGtAnwvfOj+KH3B9x84AfNtWyEKTf/gpzjfu6wdie3vxqQVrcbhf6NJxFHddZQb6LJaTUwq74UopV/c/vpZxRTd4fPmQiCb1YsvPxcCc1ls1huZj0sU3iBx9yycMRsGTbP3c9pU7ooTt0MvJxNwD3GDfa9OUwrdvlC1vA/FFQTAlNXTWLBfZ/hicl6TGxncI8MwrkTPdhGfCY07rjPenu88Yy6Lrc86IXacYJYFD6L/vjYwBdnU9ST/YAqt6/SxH8u+HRmHR0JPw37jzyhX7v7sT9AASvjVSGxvQxy7NW5KkScYny0uC/YFeSed3Hocgl0vDgIr/RHwCvf8aDh8Au3ZJTSJSMJmt4YRn2/nlDYNVWqWGANn295YtSypySXKwTrJwBnrathU60fuDpjJonV3qBEU1e6aFvN5cOa+fKXWlBpMYfMki78WD+PX34aASebb4Pnw2csOlgGr1Zexra9R7hk0hvIG2EF9VFCMP6YOHg4/YAAvwUU5rMFJsNM0ujbB5IPb+PxZ8vBOFwH9Of8wMyDJ9lHLQFvLDyNt7fPwQ7BIm58eh7nSHniv1WNeNteAUILrwEMmKLb505+tbcHXSQywNBvF52u9Se+lIkH3Guh/58sXJngg04e92CGkQHOqK6CAZ3tvEUtg6vj57O83Vv6blFAky6ZQc99I/R+GoNd3i+oaF0l5+aWsptqF3aOq6SDm0OgVVuNO75Kgtz1HG5o34ADs4wgvOovhl9pxMq9m+Hj26HeXqMN7z6exqIiY9A0l6MvnywhDTeQgLwsNMtvwSIRKQi0bsL83HaOU7Wg0IcW0PnvD8mOsAP77lDufCtJLW+TUaO0DT3etXH6HAvWf5RFeyMIeuaXcOHiZv7v8n9kF1CJE2uTofKgJx+c5YsLI2ZD5oMf1OuvD4EHuvBmZhYftfUjrVsHec3EEnhyeAruleyH0X82UYfYXJacNgFoghh0zVkNkheq0TE4im65dVPxvlhyNv7Lg67fueMk0WozaZC/Jor5hcfJb/p/bPhhGgcrnKJbdRvZ6bEjvSkcS81C5+h39ig4tH0SrzHVgWLldZTV5wObe67gmHljWf7ZU1ik70yzjKaSyIxJkOR1jXJ+ZQKNmUbafWk0yaOSbKXMqby5HY4FRNJwpx3s3D0BEp8N9ff4IsxwDeX2Def513wFTBK6xQKS7tTQ6AqVRzZCqLgUjD45jC2lP/BdHwtyljHlwZfDaFa4E55PNsJIqUr4UnAX30SKwdyaRPJaOw9s245iePAm/nBkCasM24g+8nPglKf70H7n0s37k0FXsQNO2Z+ggfdzYJzHB4jenQdmE5/BpptzsGh0BYUHOuEKeYbty/XAeKogtV26S+sS1/PZK21g/sCRPq7fw/5xFUM88p1rrijB2YGVrC1yitqtBjj/uDA97+mCndse4OyCM2DQMBqev7bE7LkyIBObA4sqBKlz3kiY/uIdGjvP5H8bT2HP5kDM2FqDMwsfsZcYg5ZWJk4e/ZJ9r5+l4aLz6PuABP+bdwSeGs3H4SaV2FAzige1psD+R7tod+o5+lSrwnXLdBDjL+BMu51wO2Q2Fiy5gDX6cSzdCJD8UAMuj7Knh2VfqMZ2OoQHHsAdVxvReO5JHK2XCC7ndvC3NzJwMusFNBkl8No2C0zdWIzuqh9wQt0HbFf9DtPiL/OwhkhKWGgE76am8I74eeT1MZoEN0ZyV5AtLt5+DRqcNvOh6P1843QeVWmPgHCpblIZyqjA6plscsQUzBT9qLFfgONU5tMzud3UEjecZ05VAH3fMviVqkBR8b1YrT2eL0zZAvZjf9LnTSqw3KEbhMN+84k6K7jiJAid/+lz6vZP9Oe0G4hNjoewRZe5QcqFS3UScfTXFsq0kYPRff8wJswDvt1Zidl5ZZAV8Q83+ZqjQuQ9kqksICF9ISj+Lgn99SOgcrMya+r58O6ZmzjPxRtutNnD1unRpHX1ATfduUgag/Jg/UYV3dZ7kkrQUbj3K5+y+SU1PLWF2LBl8NLWgg45FvPHB3rQVFcPvxauxJc+77Da9j69qu0nl7QZ+M8jglYafmdZt03oFC0JC28n47WWYSTqo8642B0ywgrwtE4h268PoHJawIf9lLF/nyYUvjeCuD8BsKPbgTqXboVpLjewcN4fuhQ9jZ0MM+j9l5u8C80g7WUeDrs6CCYdq1G2TZkjtnhg04x1GJb4A3VyG6HVSBFjFbUg5bs3dg/7iScCujFi/kg0ejIR9jv4U9XFd7wzRRL2XZ1MtptHQcEnQ97bsRN0sp+Sc4E0uF0XRbMQY5pncY31Y/0oafZ1WOmgDVlj2kl5vS097TKmstkfuUI+EQrV6sDj3iI8YnEU/6QtpYh0QXixVIbjXh2mKZfCsOTzRVy10ZssHLNgbqcLuUrt5+bH1/D38Mlwa5EYGgkNhxcFl1C6eAe3PdEnz/UTIVXLBYrSJ/OdCmWafkwNpq57SEs3acKeqE4c1tJPquui+b7Jfbj46wVL+7XA5NV9eMRKBv7FNw4xuxmqF7zChx7RuMnwPG2Y0sd/X7+gk1tdweTBOdp/Whw8T7nBJZOJMDNDEIdFHkI5/y9Y1DCVXXwC4dwFP9z7MJde2glDYHkydW0mura0ARfc2cK9GXZgGmHAvhfreaFnMYTe+EFO4cbw1FsaBvT/o8zgc+wXrETLr8RT58TzFPVqE2YEaHNRaSL+/iIKB4Lnkrn1A44frMKPu6PJtuc2Bbs785ctT7BBeAVNPaZBBbY6kOk9mSPtLuL5NZ/I99AE8M3/zAKxT9mhwxBSQ4rRibXBfrYWzJ8yAyfd8cdn85/zCNuZYHfyH//610DWb904L/08D6zwod3vRsDRVSNRUtWenzXX4rEpGyk2MZR2bWmBbaOcoUnoPvyMteb4ZAk4u3Ul7H/ymxd8QdDLHnLsj0103nk4pvfVcfB/V2ChQD4JPJ0Mvet2Y6ZBLh86Nht/n72N3eefwoG4LPxxfR+YhJ5D87XX+UStEGxZgTAuKxIX3O7iI97x3BkqAMOHWOeykhzd21iNw587o1XVGLhV9ZFovh3dujuFHz09yfuPvmcfyWmcU98A1+9vAljeDC6/ROHfiN387rwcdzf9oCuH5+Pc9T50AUxwwsAuKHGU5OpvPvj522hwvHoGU8b+5X1v17NyTBLIZhELCpfyrQjgvIbFqOikDld7TEAX8jHlmjzKOD5mknClr5FalNV9Hq+qzoA9Z0fRjvAjrP5kDNQGPONlFvPQ/4o7hYUr86LRotxyZSz8J/sC1T+7ofmTVXj9tQQIP/1DGrfDqOK7PxZnXcDl63wg7kY+xtcso3MiR1HcRhrz/6mAruE1MMsowFXTpsKfPwF4+eJ7GKixxjk7TnDoDQGsjSqCpX8AAn67QpWmOvu318DthlR632xHCZMXYuTsDHT3+QYfFFNAavoEULL7gMd8XOh8gQHWdyHKvgmjW7GGdEbuFM2U7ucOV0F8/MwclmgZcpLeR0iW8qR006Wwtsmd5p/vYbl13Ww7xok6lWQ4YY802LyazJKhHSBGYfhkZDuNjmjF9SJFLF4SDrvVX/DhIytQT3o8HNqbwC0irmTn/xO+y8ynnXanQX93NzhJ74fpXRZcU1QP836KQ0wQ8cxoPWiU7qA/xtNRMUgTg3bZ0JVoA679t58Tlh/D9iUToP6yOte3ifJN9w7Y5xBOiQobqGxRCIje2o7bV2liymIN3nzPBiYc+Q5ejku4vsGHpQYv8mPpg3xI5DrsrvgG36sjqbevCUzWWIGDYS/sr34PC1d1stZkR8j21iLlyAr6kTeezP7mob3YVfa/qwPRs1bDapF46l53AePvj0RH/Tae0dXNeXkj2aT4G599Xc3LZK0hM2kmOmW205Q2dTym0Q3+vamYOzR/yz9efHLmfnC9bsRW9QJgUjSX1MGG/UOLccG1ItIoKeEz32eyuewtnGu5FzbL9cDrtaIAN4nrYj5hbGw0mC//CHMzM1j7lABciQriYd51NHVNPBjNk4fBW3eG/mk9PDn/IZYIXeL1ZW/g34EykhK6gLEjHPiI3wBOnGgCn/4Vgp12L34sGICfHR8p7ZosHL2XQ6cFFXFvTxMsXq0HN1LlYNgJSa7LNMNW0RwIjRWEJ1M6aY7aZl5e/ZQztkWiepsT9n+QA6XQfdggdxs+G6nRG7lWnnR9H5qWidMtxzE852A4P3CQoNVJyjBzRACwYTVK+YuB5fJxWB/uBvdNhnzYRo2WeBXSVM0cKJQxg431G2BqgDU1SZ5nD6eZnIQy9DB6IlTPzsVPZSO5XFcdZqQKAJ37hVeDi3BTrwg4hnrCQPFF3OgbQomv3+C++3tps0EniUhYQZHoKpyR+5H8N2rxpUIbCDK/Q0ucGK/9FIEVJ3tp8tEdNKlSCGCnCjneL6JLzUYwz8CKHzk1sZqYNZ/Zep6LBpfgRJl9mBk8DoT9JkJEkQsbL/CHiHEvwSEuj6fvDaAYhQL6vDqN7249TpcmAXDrQdQ9twzCG6RJ40IS7x0M4bGap3Gd23f42hhKbSYj8FSlNZS0fqXhdo4kqafDiqmPIDg3DQ8tskKTsZF8YPx5/mR4ALxRD7zzSjGiYRJLKspBXWkS7dcK54VGmpQsJgVnLi0mkUgV2j5uKF8yxTg//i/d8eyh1KpK3PF2FLo8GEEbxswgxSsb+IVTDJzLHwa35muw54kK+jmowzeO/eU7TVWQJJpJ4it2Yr5BBEYPKFNfhhWM/a7N51f9IevQNAzLeQWqMnf5w2dttjFeyyXOu9BkSjwN36UCZwrG45HxVuS/fAMN2/2FNo99zTnbppP9XlP+FnYdNLYzCGvIw/5NA5Sm/g7Oqe5io6RR8GRaAaS+Uia3s4XUb9XLhtHLsMlPDkZZuZF97kWMGvYIHHJ38LRt5RA66Ihje8tYdlUv7zctp09+gpAf5UBb9W+D9OmzLHNTHVw7JGBjdhOsGybHE9UmocO157A8bQQEyQ2Q0DFJCBn/FebOq+LfXkkodqeLQ2aFs/uofOr/PB68cmRgTPFrfuYfT+/mHQStw+Po8r6VFGyhwHcs35DFi3t8bet0MNsiCEa9jbTTWZDH6uXTh0fzKHv6cbomOBPwahZUXkik1CR1HPFaBEL2z2fvOT9Z6K8UTTmRiQ4VT2HnCgfMa/8LhVETYYR5LLYm20DO5FXoJBQFf3eLUUEnwfCKeRxrY8Hj1PRBuvYluyqn4MUWYbAc4vDAhUY0rioasn9bo/oVPZq6+wsG3ZKCwzvW42PVtxzoYQXeHXU8N0OTilQPQsr4WxRjNYb0fk4FFyVZEgi8x/BgCSbEK0DHmxJU6VoOCvu7OdJfBb1OmWPldMLod0/48tqn8DdxNyutEAefWT/BY9tc8pBYwYbrVnPlw5G44tsNzp0fRwebA3mKbQQ+GjsckvaexNUKt/Dym/vQumAD1Di9wMk6OxmWnyVKPEOv3ldi1oRJ4FkSweMb+rBozHVclDUd39w0gidi83iHcwXrfutEaadzdHuBJlxeIICme0tRwuEUdi1pxeGqXvi6/Re5B+bj+oJWSL+5Gx63CcEXHW34cWoy3fEw4q8f93CQqTuHCXuQ5NulOH+MG6x3uMdnx0iAnAex1eqHnDXJDfz3Lcd/crmg39/EF7a1cnjiDyr7p00V92TB+IM8CGv3kbG0FBVbl2PduVW4+L+JVO4+C24P62aTxEioiLIAvTPy0LTdgUo2p0Gq5GQqUQhG3C0H/Qdu47pl8zj8vh039Q5x9AVLupqSxhvAiM4MFtCExndQ9zIQottHg+Wnu7hixG0a6WEKA9tOk+LXmzB1yThq6tpHKZmKXCL8ERYM8eDJJhdo2VAD5R+0YM764ei1uw8vbbLFZ3XH6fCyaaip4Yw5g5Owuno3X1Uo4HQVabB1jGbBTZvwW/JWfvXtEg1+SKGm1Bje05hON+xlYd2fr3B1ng0I3VCgyFRB6gq8R1Fjn+DKE6moL2EKstPnQcTFI2DnVQjfFhrDvofh3O86hW48H4FXms/AvewGtt1zHP0FkiESamBZxAgS7NEExeAHJF5+EhzEjvIyv+no/bERm3+3gBFuBa1FTiAXfgD+3lYDuVWjyCgggvp8+nGYqzAkPVGD1U0mYJA/Ez59XEAC+VModPZYuBemgMZ3LYCyRmL1GVleGZGP+09FgOr5Y3hBsBcOvb9MKlNMYE2sAZu8y0Sjk4582mk+dvp9JN/EHJZpk+dFA8HgtasVivImwc3/QkH+SBqN6rLGYS9lOWy3Djq/AgwIzUNP1T9Q6hiDtTWGEP+8HmZnHoF7btNY+Jwxv7YUwD02Z6HibRWv3HQAuzreUPAYczinlYtN2xfz/IexINbXBUtvdeEuy09k+2Uptm20oId5Wfjh2WSAnplc6PqBKpN/8BKXY7jQ9CzsSfmEUqzLbe/sMGfxA8hMUIFkmUZMnCWCBe+vQ0txEvhfbsPypD0gZnqCNKZF4V6FOtTPMYAlJ4ecInIPBIy4TDcdr6PzoCEM9/OCTbWZnNoYBkpzbpJd6kQ4OHSDc6pvcoKiB39behpqPT6Q+VQhdJo8CJYOC9H23XlWmcZQ8sgCu8MWk5bSONB1lqN6tZ3UqLUdO0NaYZVzFrnNPU++U3WGeEOIuy1DuejKfXB7u4mH+86ipsaDmOdRRtUH1/E36fcgIakKW47lsGZWOh6SVMK3pqVUXm7IPcUK1Db5CFwXXEknFBpwb+VIqFnzEA0PVJKykgid8D6FCloi6DjKmN9NzaOau4m8tHET5iT/357/hVPLRWiskBAarN/IMQ6t9HG9AXrbjKPDB53h6KVukPQ8AzO/qIBMoCRr7H1Bgf5rUMBvFHRYXcaVNSsxpdUcjJ8mw7gxOXhsvwQEG5rQuZknWK2sFTYM6MC94RIcPPwT1VbE8OwGDxBWX8IO8qNg5+9v9Iuf0GVtKwhvrYb4zHISzG9HqjIDmzmzWGHzPBxfog1h7jfwelgLrH1ihv5l17FrThluHz8O5OAiaPe5YxXcgeW7ZOA69PNKXTcEjTMI8zfzxoHX7LjkLaeYNcIM2+/0qs4dJU8KQXO9Lu2iMbwx0YuUuBtil2XgsYcqFO+mhCZe7axpOBecZpiBrHAJp1wRReWTUXA3+w64FI/k/uAo6rrVAsNsusk6xI4MrpiB87RYslo5HhOD13HeHmf0q1DjxTqrcOfnbJDPvE3Jtuuo8MuQnxfk8zqbHDwxr4vU2ZXjIqbj3wklVFm9mUrWrka97A766TceInwvweEnF/DGkQ/U9WUujllQi3EVzZgxeJsCGjpxq/FfEEw1geyEJP6x7yo1Vzyll2X5IPx8NwQWzsbFSYE8dsjhHBp+4JZLErC8fzK9necMGnE7uNS8nCN074D63EsovP4bXbQBPq/ZDBVnzcDfZTtH7Rz6vtqLXCC7AoODruBOu/24fLo/pNqcw+m7zoGFphH0RK3gvSGbUHvjI9q7eIBCvlvyMKkhRpVYQ1O3vsE6hzJ6uUIV/mZtQrnkGUjaPXzqxwAFdoajrbYcVUSZcmKrCvhlR0JyxBgIlnqCFXCVR39ZhI8PXwAdzVnUJ+6MO7e94dl1+VD0UIEe6KrBk6CxrFNlQg2/nKiqt5J+2gtA/m0Rzj1tDE+yXPl8SxqOkpGGraVTUdwnlaPP/sQlGpdZUO43N+lOpRoPU6p4cBk7EpzYcIcMeLsWcsAZd8wprwX9t5Oh6NtjmvDrHI9qM8eo18LwpK2aVSYOh98fZEHxoiP0PfXBwzbD+LrFEb6aEkMK/7K5oyiWHnw6zpYHBKH3/Eeq9gsi8wkrqSqnlGO/OfCdNXvY+VUuv5HKwzsPRDAqUwu+T0K86mwABdsMUKL8M8yfM4ekl6zFiWdEIVSll9paReF+ni54JElicH0yvD/6Baf2eSJMVYb3uU0cc6QYdasCsDx+Cin+M4DF3bP5ZMsuEr6WinNVRVlG9Dv65ZzCT422ZKmRRnP6E6kgQAeOnS8ly3WvUXvrY/DUPADr82Ox9uwh8DQbjwEPw/im+LEh7x4PJ2QC0PrgdDAlDbqDI7mF/Nl3VBclqt7k3FYdtE7JxtcWk2D2z3oaPGsOv8ZGk7zmRKzL3QjG+1ZyruEH/jNPBHvWprDkJy0oXS+Jh4YfgYPHjVHD5Cxs1rRF6TNHeHiJH8j88cK4jh08a4E1fEyxwyDjGjh+VoPaVRbS4b4cvBygRiq0BY9l1cL2kx3ckyMJygG/afF8Z3i00pgOPJehrxpfKDPaAAWyr0NNjzLeS5jBY18OA/fkKIjLkyDbvxUg0KQLrQUTMM8vnwJLLdhweDxHRZ2G4i/y8FZFnKU75TmtJYJXTl0IzTUv2Hv1BBSuj6PnufPITfUJVG0eDmWJ7rCoy44e6inB3+8rsOKaLxTYGUHL/U3w2S0B7WZcYflogvTfO3GH4h88us8CzQ11abriMMz+3A/+IzVgY4QI/SnfwcPsrGGMvxnzr1FwP9idZKqS+O60FgJfQ2QfTfhtu5+D1ULworooxPmqoczqefx5ZS6qrtTDjmJdfBuSioK5a0g3TZq+HNoHXusEIOmCAtDZYFD9e4QSDNR588duOqk0k1elq9CXTafhVnQUXhlO8G78C8xdVUZb53uw++UO0Oo8TLul10Lpz42s8MkS73eqQEG0Lqxd6c/KH5fCdwUXUi0J4XU4GSwSTqJTeiHABCuoe2JEB9fKgaDIPHxW4Mtjjpaw58qHMHnZST6grc0HhIN40eORlNiWhOYPTGCKXQxHK/rSlXwDflFwgquElOhr6FwOTjiCYt+nM+e7wK5YAUi+xahbbIDHPffCDM9ccMNs9G0yxjfKFgxjZsC2IA2UNZCBUIFTOC+wC+Itw6nhwksOcs7luzrLaYzsaSz6EgJd0+rh610tyM5ZQiqLl/Fbwd/cGPsSTnpl0d7VYvCt9SLLn7TmdI9b/CtMFpLWnMK5Skuwe4gjJBPCWWK1JRp9PMg9gY9p8LIe1H2KgYRbJiD42o+uFAvju+KzWLI2GdvxDZf1X+VRxsIYrOkAF2wlhphtPIQX9cKHlJvoHc1wwWMhFBl1s93L1yB4tBbSrazgfv4BWJSjDYo2eWiSZ8RnY9TZa4MUKJca0uzdt/GvaTFZTPIkp3ubaK6/IgjomGL1Vm0SgEhOiBuEuTKf6Gn3AbisvxnCwo3h9PQE3lltDhn8jWpldpG9VAb8atSnpKjLKC55kqZPXk+K5wQp6UwGhWmLwchQD6xdZk11ica0d/I6cvn2g9L5NRpt+8oTl8qAiWgla4qIwkvvNWw7R5dqPZby3h93WXyfCdl9r4YJI7NA03cfBJV+4rxHDBsuC4F+fRCObGjHC/LlnBdkwPlfLHhWSRz4F2wAy70X6NJBNbCScISJhRvZap8Y1ule5BX6arjtkBBXXD1E70s6sLj1KcR0Iiz7/pvFnyzkqBHl+OdgCxx6ep6fjHhHKz5PhvnnJpDzpACYHyILglJh/EhMjS8oKkCVtgV+stTH3kleqLx/JStK9LLOPGXcbTAeBBQRYaswPfK/xZsfdYJ6WSSodd2jlJ9X6f2JuxhxXpZttujB+i/HQO1zEW34LEKqY6fCIl5Ob0Wa2H0P4YLR2ah6NxH3d+qBZ6o//3X1g2OlaZCbdBmNcsX5i1EPKJl94dkzZvKbiOkkcNMGHObvoJ+R9yHb4AONWOOCitX9dDdHiv19H9ORcjN2+2FIloYi8K3Qi9Qc2vG4ynNeF7QRv6w1ov6+M5AXt48WwBreZF9GK5xk4cI2dw6w6OFlnk34n8JzOFC8H5Uqt8F8p4eo+c8X1bdWkL25Bvz3JxRmsTdqXgSekbaKlXw+gPZXZ3wVVA/HiydT5Vw1OnFGFb79Nx+/FIdhyPjDUP58KuwxW8bfHXr4bO0ccDRUx3GVPqDaPxHeL9UgeNTEvcKThtg4Dt/Ze7LCr8nQN2CPIS49ID/zHkSvEwb9Jg3IuZhNsGkydB2Ug7ap5/CTWzI4HdPGYr2N0DrFBbfdMIBhB7tAWdIU0l7oUvq3Ao5dvgubJ8zmnyuHD3W7D0+jN6S6XgscZ4wE2fFGEHQgiFNmnIDhRZJ4oXsTTBuTD5NsXlH7g9389ZAMpAS7svuG8dhjLInjjJyo7VU7bK9fQS97HfCK3Acsu2DBxRt04Pfqi7RvfwsGrLWjxqNDLv33LgUKM5Vll7PYSWCpGYKQnCAEeECWQn+34/Tn17l7diAEft7JD0b+4M3//QdXTbNZ6bQ6fTYZAXnX89m18T3O+qCGJztDOeF8PO7dq0u5s9RQQg25ZrUSK4spwvsRsRz5PRJ/9LpS6VwjiuhoI+3fE3nCcTtIPSTG/67f4dxoTbg2ooqlpk3CYPbA3X6/Sb7ZGReUn4McgXb65aZAH8vSOd1GDGyOioD4Y2ea0j4H7hT5oPF9ARJuaaP53kG8y30BTF+sAo2mCjBkvXA5yZmTghkFO4FjMjVpQrkJWbVewbKyfupXvYTL/srB46/6UC/7nrRb3uGxowOYtPYSvHyixdIhV+H1pxZ6cyGdKxWF4eaudrZfJwsu40tIbLYdygwkkFL2Vvza+xpuxGSwtl8r1w/5UVKCM7jdjiacZ4Pzh3JreEst7RNIwW5pbay9mQIjznzBKJWJoHLrLRye8Qr9BF+gWo8JLr7zDqQKO9Hx0ksQmWXN9VG51DBFFhw9RelB3iKQ0TvA7238ydDFkc5+eMaTjISpcXkBF7TmkfJuKfBV9eXPXjWgu3IpViyQxPcxzZAWPoqKBXpod5AavpgeBRvPCUOmowlO8f7Cj/Q3gM29FBr0zIHTvvLwQ0aEFxbHc5xuEflkCML8mD2csrWUNl4o5tervqB3+XvwOFLKZ7cP0rScPmhN0GSXYQLw11qIhptPgsjJU9Hh8QOy2fKQdrl8pd4lDTSrUQRjo17CygkEExUPss7Lg+R414JLxHuordoGxyUMUhAKgV3hczqs7osbxqjB6MEy/qFaSPmWFSx3pwfKPz1lty+R2FeqSGk2iJM6xvDaKAZFMUHe8DIOE3OT6PRScxQpkyXJW8KgnRQI7qZu6PJzEFFGDvbtV2YPi3oa/XwWKxUdpXFLs2DlGjlyXeYIgjVRPHvuCn48jsHuRANXbVuBLorKeDfjCGauWY6iL4poy9dBHGiZBvZj+tg7VR2UhOSofO1s3ji8FGSEzpHr9NfEF/34jvQHSDT9C2IPp+C0q+LweNYUPrJtJq6cdp8vHmum0beSSLDqJQTbpWJpkwqsLI+BQhkJ2BWcRB+Pb6errc5w5lkCZprEUiVosP6T2dwKV6Ao1RQvFkwAIaqGWN9psDPuDh6cjPDtEINHWyQH2u/mvnOhKPWknEulh8MTsY9DTbmZHo5I4S1jK+n3s9c4N/Uv/ArfwYGtaih5yZN0BIfB9bP+vEg3mJVL00j4a/wQv1+H8tWT8GXQJLC1VGOlAW0OOacKt6U+43J/OZZyaOKDsVPZPVgd9EMmc2tUL+afOsWpGb2wP00JXCeXoLyDMzk5TMBZ7hc4afEGOHbsGydlII3c1jrUKZfYOGMKtFaqstqRQnYeF8Ktjdu53W0D2nmYo8ISKRBbZAyXip0xcosFrC87QiYlwvhd+yds29VEUs1SXKJ9HtKrb+CrNenoFvKS/lYOAwX/lXgobBPPkQN8VVyHi437cPpWHexuDCHVqJ007ZAd/I3TB4nm17z0kA6d6n/Aesc30aQPI8nwXjx/+H0TDW+8p8KGOxTUIAiFIutAyPgUpM65Q2J5RMPuh5H4oy5e/iKdhNPe86wIP56aIQ7T1/bwmbnucCz3DIx5PQx/DFPgE8OrUGVsHYxYE47fpJfAxd0AoTqG8NC5gB8cmIufoiaCPjbgqPFbqeTVkG8fO8knq07h/TQDGLXkCH+sfATfU/NIr2k0aHZNJb/2S5jogDxXPoaCep/jriIT0Bxjz/fPyUGSYChvDdFAdZtTeLllPNWOGsNqyoJoVhKLuQ/04HRoOlXffQMujXHwe+A+nnpgRelBXZSd3IDtqVU061csOd9WhxNfH9KVzDlgt2wbSb37xyfF63mwL5QPvmkmpS9KUAo5GN6jDGf0T8EbXx1s39LAmXZAtcbLcdjoKbjy7m9e8mEHVy+7QMt8reFU3jM6fXL0UObchv75T3FErDv+2mXKI4H5YEUT/HQQIPFmazgoLomFN+Rg5M1hHFnTRKW37lCqTQ+shc90pNSVTWqXY9EoIViTPAhNS+LJeVwNfgqJJsn6ENaNzOA43/WYrZQDRvci4fYZSci0iqJvR4/x03fTwXLxFrxgIoKFPlXA+2xoIK+Ryof95bcHjcFQ7CnKqopw5FFvXrzzEu4Jzuat597DgbcJ8EzoGFms/UpHr1jAt63+XOO3Ey/Y2XJ32xjMn9kCaQ2fMerHQtoQmct58Y8hVdgGNtTr8fyaBpxmWIhuG28BdPfQwl4hjBja05i2m6g7YSoFORnCevE99KYlhkT6MqjBNhApuB087gEeWXaRT4aOpa2Nb/Bt7ygwUn8G2Z6D6PNQCg41TOMpl+7wyXcDPNwjkiMWn2PBnX1clGkDTes+wMv8EZztmoZTNjvj00v/QPHYFXJwugsJZ7Mp0TKA9cbKwUe92ahXGYy1A9PB6F0gfPg3lafXZlCdvDBKL0mjA3GHON1UBJaKTuIFatX85mM9ptnu46gZ4nzIYzUUOrSA7utK+pbkhQEqE2BXoSPm4UgYGP4TErwT8ML6M5ypFQDJ9jdo6cJHWP3xLNywAHBUbgDRjArQWrMOrG5fgMpDthzYbA/iLp18I0Ica8Iq0VXPEg6rVKOBTRbtIg8IzxkGHw/NpDDnY3wvxQVWhzzAaw87+UWCMqx7rEirwlaRg74iLW4e5N/S4zl9uzcZUizOuDmePqfMg5m3xGFWbx3pXhKjpvrl3Km8ge2vtJD6oZkwI+4RlC97N+RrlpRUbQA5k+NQ/ugc3L5PGa+uDMDvh1vxuGgKiJRLwY2/C+GYSCuPuz8ZZqa6oe70ZhS2/YWNIx9Sc+cr/By8hF8VLePF145j/Kw9mHJJAMpy9vC0hdkw8sYJ6jxEEDNjEYqYNYK14gVc9joMFDpsMHIGwZPQRyCh7g+8YQbtym3hZdXzWfz4HTCvucxfbwdDZl47PPO0hgIzJb53ohy03Ls5ISoElYWaYM6AEdtfNyavMj3IXrIYLi83hrLb1+jtlc/0aX8Z+Xf9xZ1tddRGB3Dhk2sQZxiGsRsIbxgIQcqAGl05cY5/f4nix3dXs0zqBHiduJztPV15Xm0Y60aPx6C88dChk4ajr34E3+ItsC/tIv1co0LFi0dx1jY/CqLTJC9iRkF3reCqxVjcUPMUPdbtw3TDKRD7YzYdU5gCW+2egIOOEJZf8iZRZX1QHGOIPTrf4Ym2HP9ruY6z9zN53X/HlSJx/G1WEA6eFkCVSbJgcvgl73ygjqUTNfH5rYOcqtxC2QmHGDfcou/dXaA5pwtaftjAO7+bOK3gO+/0iyKNrX70ynoa/pvhAv8GfnLN2GfktXkxXlFSgQsd2aSkl8s1a9XAI/s5zUoIh3kS5mQ9dxueGNsBkuc3UUE/wC35TpoidZ1jHf25aaMovdoihmMdDeC/xjEw/H4M6LQasMMnS3BUvA6zl33EquNHaNeSABY/VwnPZMooa+UZ9N11CDNEzsI3FSvwNnmAgfdWQHeiBjsaKfIF4wgquppNPouJIoLtMXb0Y0pcYA1KWt343MgchQMe8j2lRzj3YxP/m+REP+va4ZVjJ43fMx90DDXhRXkEKCl+wWjlDNgnJMY+lpvgfHsoOsU9oeamddCe+hsdb4rCnFI7jok4TSkdB3nCpkKwTl2IF1cNg9SyaH4j9wlthW7Q+V9jQXt9DqcELYB6pbd0MMkGjqSc4J8xMuBjlUaqC7zg2IyR9NLHGnoE3FkyIpA0wtXQSC6fd1qGoeXE3XRaUp3vbb1N6s+zyPiFJqyd5UjHr3ZTWo8PLX63EHK7FnKKoRp5znmLwytC8c8Oe9TyHw0Co/bSpvyt/N26D1UvinChxCmqitvIpxxbYMOTg3S7oYDwpyqIbnfmisMjONqhEE+2puDu6gdo8H0v3Jvly7bb+7Bywz901Ec4ssOMt99VJ43FXyldzwtGernjh50rYNhpORDVe0b57jY8MEwSgk5t5+BtAuRS8AOmzjDD+TrB4PKoGZUbBHiadz85H3LmP4eFYF3FPo5cHkrL23/zITcLticPfBHmTJPGNuC3IS4K/CIGdT+EoPnzcBLa/guVs5p4MFoR68p20sUlaTDgHgnvnsZzAm4CY/exsDyiA2K/nwDtLgOa8lOar02pwbvp+0nqdRUdTgwiMYfLlDF+FJit7YD/Bm+Srr4GaqoE8dtrm/Gvfg79qi7B40lvwbztM7xSUASHv7LwW/A4fX6hR5K4gOb6j6aZ5udg3KhHFNtrhCmz50OXpglcXbwTtiTvwuXbl/KssC2Uo3KUzdZ30py1O3D24vXwraIL0x8RrPY8joqb52G3lSKU13vT38G/uG17MqXlG9L3ObJ4VFoXeg/JQuCTal4pIQUJzv50I7aNVv8SYLPc62SWX8sjuheDYaEYTpitAH2TdsHnNmMs7HCmcLMMXPBIFvQlfqDCnOk4Tn4z2Hl6kr+kHpgJ1VJmny72rz2D6bv+I0FlSRK22wL7vyXw2S2aECSxmld90gCnxRMh6FcA/ShfQiMOlcCZ9jZusfuHKYbzMEzXHadvjuUzNAE2Lc/lnw7dHPLGkqTu3KHIw6E8euUPDH+7i9SDC2n/uBX07bUYNOtIwAzvMeAuaALPH/nji+YFXFm0ie4HSfJrjSXktzYYv+yyAZVHzizX8IaTDwrBCs9lHN3/if4+9cKSrJ0caCELSrQDLtzUgmmr1rDWp43QJTmaZXIzMeaEJdwt7kfFzKcg7CLMblULwbtiIvzJusR005b/uDGNrK/B2cpm2OrkiOtqPWjCexXwPD6N5563ghn1a/FN+hE6unkuXAn1gjtRIVxz7xl/i2vnd7XE62+95/nl5lDS4IgrD67j0V+nkdTuKBgt/I9KJ1lAufVxUjKKJNdNzzBsry68cv7F62vSMWfrDlbfOxEmhSuglPF16HikjRUKLmDuVgrezvpD3BPAo7fq4XkHSw57hKhtIQxbD4bxm8O9bBCpQjunJVB7kxp0jc6DA/497Bevz5PmzeGI0U/p4Ps9+LPrAfXpmcPMR6J0YLMZ5FqtA+UzFuj1KZke+Blg7/erFOj0nD1TiwGbToFF7xqKMLQC890HyMTjG+yY+pXWXerk2JHVsCikCTKLm2jhl0mgLG/O33YJwEvpA/j59mjwmDaKC19corjkCN5veoWDSx6yfb0529YowsQDmqBkq0K/VyI90ljHc8VO8ULDbjR954yiv3PQNXQP7shTAf1nE+C8bT/smVhO0DAWzj58iLazp+An77d8a/waUPY5DeVFYyG/2BCsJ/ZA/b0p+HjCXTQz7eDQgH088vBlyj3rzMtsssmqywJN9iqAuuRdumSuwhfvSoHHa22sG2IdsypTOttsANsHp+O9OfuxaoYBPJojT7UJ1bjgO+PNu348mFmK9PUDxk8U4eGZo1HIQphPm8uCiNJ8HLMkgdeqz6MYRXXsOl/HF6fvZ1lIhfkHGN/stMVNq6fA6yZxznhxh+JuXaIb5degxDaV5t3dTOYxG7nP9D6vUCRKHzCFv5sXcvLLV7zs0QmU1FBhM6zm09qCVCm+HOWjb+G009J0SnEsiG9xgHeVIlA+TpZCL/1Hzw5M4PAn1bivSo6qJES48fFoOuOtBj8yaljEzBYu7E2Djb93MvY94BbxdOqIiuJXdatZy9SbnsuJQs+KEq5ZOAJePZnJs0tncdMofyxPPcArp3eQ3MQCOrn6D/f3aQHlL0GB1NlQvf81uTcwap4opJTzxfje+Qm6dcqgwfYiUNBSAuuP06C0+TdnmdygDdr/6NceQ0wbYwmvih7Qbxk73P1+DZaN04XUS17s9i8VFFpHc9ztZCiRkuajf5FCFR4MzbCZx5ecRp9SQzDdqs2PvJ+B00Y1WiQ/B5b0OVCQN5C1wCl4ZHWCTl23pYhzIhB2ZjK9C3TietkJ7DC+hT7X3aaL8//R8/8OUaqUF8iVuHLpTmU4u+IAHJ3iSNnVoTR1xVUozpDjsKxKSrSL5eWzPCil6hecrzeD3tpWSI4fwMREKdZJO0BBtdt5e04CTttrA87r+7BkRwqbWelAQ4IXhc+u49uqffzP4jX5Nbxg54YD6K/2mfWSfXn0c2taUq4GT80MGO6pc6X/R+ztHEtrfW1w04cSfrHmO++944w64EIP/hrDG52neG2GIOjrzYYXeaHskR3FL15a0mDfObz2TYKWBx7j01ISIHK0kIzlPPn6gQD6c/METDrO+PH5Mt7x9QuOfpLLCWNHst8iVahYIgfN1ttIfHQNub0voNNCZyFduJAffzpEb99fRYepj8muSRx2+y6C7kIPFNmlB5rx9jzr60OQ/vMYF7SfoOeN2jSjNhvsLTRgiXkkfBR/zdrzrFhcTgLefWpg3/92kZV7KmtceEdz0BVOpUhC+8Sb7ORqBZ0/BUk5zwbMzdrIUHwn3VvoDrcmJ+G2mh5wO2oKDioPYEvMaHgbL0LsGQAn02UxJF0DZKcs57UNKThy3AsYWT/kZVbB1Dv5HXxdrw9FsyZAosuQgVbKQ0++EQ/PEOYPa0bD7d2WYGmBuHhPEgz7rUtVN0xA+kwybCrzxVl3LbBf5hb6qi/BUSsEoSPNk6O29bK1oDerx2ZzxCZ/vi94DTQ32/MFwbUcfzoHv541hAeV0jDcWh90L/+Al+kHSKB9NGqFtnD4qna8UH+fHd8cpY48hMuaz+niY0J5rXd45dAb7PXsgt7+JvZfYQBT5Rfyl/Y+8i8dC749yljQ0w1jhm/DRU/vgJVJGeW5luACbws4/EiKFlXp87XHE8D1ZxssLaxgnb8DYK84lleu+QLBi9poXZsNL5PYiPE5U7kmUQ0OVSeicq4nOK0bhrl16fTV1Y3tKsbCOeUWpLpWGitRBxntAnBi2mRa+usliw040JULE+jqHUnSHq0O1wXMeFbMTdSb5YqL74qB85BXZgz184LfDRAgGE+rm0fia+k99HDkVUjeNh/cRATwto8lsJ8f+6psw+iXt8G0ZxUkrY/DgJS/sChLEwSXpfPBwS3wb5YmTDntzCYnluLR+y85b+k4/JsbBeMyfsBEYWM+cUAOLz9NxekfxGFTgB6g81cuDZHnjGNnuEl+AM9F2kNNgADryHyGn1NPwMbjhiD8SZFfxt1D5YqPaJ8ejquyZvLI26q0b/gaPJgwBWXuvcJ8f23QSvwHmx3c8UqEC4ycGMTpWdfB6nMk7cltwlPWMfSzU57SfqjDILdCXfVjuvh7I05q6melkGsc5VRBlqWi4Bouydf6a7Dtsw0IpJ/hkRF58Ff6PXhmjoCwD5vB8/0aKtt2D4a/ugzHLsnyTUUNKPIwxZvPRVFhTB5p1Pji5owUvBSzmmaZD7FMjyJsDa2iQV0xELGvpsx2VzhwvYWbN8WAwoItOHDnLL3f+BbGyJTSrZRcqps9Gs40XofFslmY23MHLNvtOT70DfQdWYFV6vF8dPUGHlmnx/uFDGBkSAQualqM6a+sKHxbGJUUWNFG/zDyPDQH9lq/A7e9b8jBczw8vt+Gemt/s48jwa/yJegzKwGvPzLnQx2BKLNhN9/tqoOfSybCjO8ePFD5HE+e7OYA/SL6tdKBvv3JpCsF92ibaTKVlWrB7xhBGDY2mm6MzEGlB/u5plcPLk0YgCLj56zZrE8BKkqsIjweZ5uOh30vaknfvYemV41ipe6f/CbcHddf/EGrn/nzcFFhEMo6BcmOZrB1kS+OyHpM//UcxJKzXhSz0RY7zO/RfGMfYlIEU3NLqjEWBU/nOExc/BinzfRD8cyPUD+4HWfZB1J99leCSaH4t3kRV1w1BdnQ8yBYLkjDnrvw4xxJivpPlLhRCr9uO4o7Vobi7f4q/FFoDc4Z0+CY/mQKFpsBXvbiXNdSBdr7k9A02pKDVz+jmXc6qbpYFPwdkrkjdxHo2ffS4eBx5LPvDnW5yMHRY7+5fb8qyOy/jjlrFcE1qJ0frw3CeDNLHOwazZXrbmPAUUk6a9yK57I9Qd4njQOsx0K/zTVQqiih7xX3cNrIq3zygxLp7PiDEReeoY/bMyx/JIdllVbQHSgIj71fY4hpM4irLMQbi6/xUttY/HjTC4VFBsCnYTWU/CcOg6IzyfDAHtJdEsISMdkgkGqNFsPP0KHYdSgXUEZHJwnil9lmkOF/nD55+uCf30ZQl3mYzWfa4cg1N+CdSAwsK7oO4t0SKJlkALVj3mJqzHKS8Tfgq9+nUl7Tapp6PZOWbRxPBxMug7K4BKkmycOYEC82tzwJq9SiKf/kHlQOkYY0obvYUJsIoddTeUpxJ69frQapcsMh5dZavH+riH9118GfI0Fo9Wocj/puS9nl79C2bR3MGBwGPqqPqM9SiaNFukHkqw3cUyyAbfPTcLZ9PdXmjYDaLEVa93YcuA17jcHRS9F4iwsoOuyi3ute8EssgJdZTIe4nSGs/LQbq4Z49/FLb7488SWsXCsPxYvHQd+fdlI+/xP73cfSOlkfjC89BluC1GHijp+08MVG6NRewlpf+qFs6x2KSS3GgrcPeINWFb6WXET/7IThfvY92J12Fyac84DvzSrot2sGi47/jRbClQRPa+F1QhePEZCDkDxfEFgwG5VyDLCk7AQpl2Rz/UAC3V3xi2OGtfJ4m9ewXkAGzn/T50aNLjIoKwX5zZ95adYmfND2lffL/WT56g1ktqWfp89GSAmyo/46IzBKXcI9y17x3u2W5OwvA763z6HxnhhqUInEMfsQvD5tw+R4CXywK4q8E+P4tmgwiWxAbBP8D88GTmeNh41o8GIE7DLx4Yv9t3HN8qmknnGKA0XVhvJtOL/bso2yDu/AMy9ewfhWhACDG2B96xdvPBRNQWcegPKdTsw6lY/vPvtS+b01cNGxlp/XaMHhZQGwad54cNxuA0fWHBmasz1NqvgGY5JDUfqgDUfvU4DL/sZwZGsSa8VUc1egOJomK4Npiy4NbpzLnxRMMf5YMy0+vZzaUiRAdn8354XPppqoTFYecxSeV8/nth3Abd5uvHttA/ZsGOSDykNcfFaH7RZ9IrNLY/DQbCN47qNI9928oMh7Le3JlIVh1Y20c6QRNOV7cvLAG7iR0Ed71seQXNlCfJLfBCUrV1GahBMse5uDYaLqsGG1OqWmibPNs0kscySXa72mwuvQFlxufZ+rTTzIZWIFR1y2AKNtN9BVsoGMHBZRiZwKWrnu5glDPPhMaCzX2pqgy003HKc6Cf7STRT1VWKtsQ/wy5VpoDW+C47JGbDZreWg/swToz4G0sU+XejyykZX3Sq8KrUPJAJ+QWJDGNhH7sTRrksp9YYU/o+i84wL6W/D+D0oDQ0tpJSkVLQooiFFKKGlUCIJJRIlSqEQUkmEKCOUpKG0iZREUhKpFMlI409W5Ol5fV6c87nvc67r+/2cF7+Zm6qp/YcaJPq2c8j1hWSy/QQIudRz7Omp8DxoOkYcicJzbdbQO7GT/jhOgBrNaB5T9AbNPqRj6FEJjKxqYrWoPC59oo6L3lVSXdJHXtkqAV8+hJFI1SycMHECjqVCaENfQKFOPqiZSpKWf8FVq5A75TSgcOJ0ij2QDhNm9OKvr6HQbvACozsXgMzNo3zWeRJ/WShAmxZPgtffBnjDsgPYdSaJMzI7UcZpGekuWoe7rvVRZugPqDpiheru42HXdWPsYTEsOR+JnZ4i6J2axn9X6bHQnxGU7NRGVz7vpZ2FkqCstIxyW0156chzLPTgBi3RGY5fY/fy7qwVkO9bRobFpWSbqDnE7HNpmoYjvC24wQ89h8G223n8e5EUb327j4yPnufssHTepjwVwjJm4WS3Y7ypsQqPy63k6t4YbFFeiWUPjCjthDI5C/dQ93uAK/sKafCxKI3vlaKQKzPoxq3FkK6ezSu2bYITj89TgcRKund6JtQFf2bzS86sfUIBjqsVctzgdVoQcgBGzp9De7VSYfHxUvyRJQVzdTVB/ckApVlUk+uqQlD4vpTG2+/Acz+swcHeB0yzltGiBEUIGK7JZsoiJH3fkJXE+zDmUAcEX18JoiuDcIS1PeseGIkm8qpwL6iFbjQchv6DP2H64pXgLV0E2p8Bl+wbujbaigYdPpHpgCAMrvDiVW99OFNpL+Q1epKXzDX+q2WIBSdH0niPIxgV4I0yvgKwKewRtK6IwSszQmF5fBgfsDuAf55tolrxEDDSXs/Wi4pBbKMglGqMw2cP7ZlUPsDod/kwuuMcqH1TRFy0ktzsxOCq2QlIZB1Q26GD5XSMo2UH8biiBWtkzmDZAw6cnGgJbuNMqH5cEM4JMIFdzS70RTMBHn9NxINxs/HMExs+vHyQVyXk4VsdW2oYNo6MLcTBsPEYNu8Mp5mqO2hQ5CXedZxGYh5f6OIsQdw2v5JmRDylsbfUhuZXSq+svUnQIQ0iJVThttQQD+0y4SXLj5NHcTZ2FXWSlyTBUlcrEE4bhy0ZcbBrxwwILNyC35TK0PbmRVBMVIGf+qrwoWc4VBkSNG+bwfnFipT0+zAe05Zm04u/8Lj0Chp7+Bystx6gAxemg73Ncfw4fiJqS0RSj4g/uJUF4zwbFbC9EQS/hr9A+9PFGLVXDCam3oa8uIs0P1gf/7PLB8VmfZTfEIBmwjtZt+8KvBIXg4rfsjBruxvPeZeMideccJHBUdaYKUgvv27nBQfD+EylE9bs08bK8Qw7RLI4NDQNm7p/wu5hN/Ce4Rna2nkRjxQF0aSJ0uC4wYG8ekTAaaMmHenOwNXRAfhwxVkM0C8Bx1vK9OD3IMybeZGbhu+F/EgVEOhfiP65hVR8SZPujHOjd2e7cH/xeqhwzOMzp1NpZbsSZvgBJBtKob97H84/2Yxf+lpo35UpdC5iF2y+PxFdWipJd7UY3ZsuBZ5/N/O/s6OH3v0c2H81DH78VYN58VfxzvxnJGl8ENSDx7OZkwp8OhwJIZdmcurXIc5IdIWj5f3sPGcLDbaI8zM4wA8KlSij2wh2Te6DGzHbQGd1Bm3tSMAYsVRc1JxFv89H0NgT4axv/Bj8Z44A2WVi/BqZt0n95ffpf/Daxc+k4nOVP5x/jyJtUqR3YgR8MpkJUxcswEN/9aiq6y8sCFtEVj1dsCwtCavqN9Lb60ZgqTkIh+YLwJljL+E9l0Fm/zxMuqDBl20lOKNvOpVE3ISaW/vhapEgpm2YDukNKXD5xxS2OO1M+WmlNL4inm264/mjUhQdCKoH9WOlMC5YFfpWvoX590bgprDV3O16Db6VeIH0QBIs2GFMQneX8G8hK95VLQf7JSvgVpg5pH41J49fdTBHWJed1dK5e89zSDFfj4Hdq2iK0EgoHf2LFX8agFDybSpdrwzlD5+B+6Et1PvBkn87bUfh8pVwNGQEiA/vJrugyXyjwgu3iQ7jRI0bVDamEvdMFEV7SXmaFTGJV22ThHvW96Hn0WoQKkBqjvLnhwpN0B4YhAsP7aWl44fR17Z2qjuoAilDLmEyaSydCptHb6z+4J9/faS5TYUqjghi4+VRGPpYETSnTIOjIu6UadcK7wo+4M1nZzn+XS/mb9oJUokuXHJwEZ0v6mVlyTFQ884LzG1KcKLvQeakHVRZuAbbK85ATKYIFIQPeViXChiPl4CN+37TiWHjuHNZCKOoPKwtlsX9AXPoetgM/Hf8NQ+7OROfXxUFtU8bSXSaJxzc6AvFM15g55NH9OJHLI8OEqE2wSvwQiCT7bUNwfbcPRwWFIK/H5qx3+pkKn2hzw4apzku3RPEakZQmUAKnTeeBhvE9uJ/D8egyvqJ7PTHBtbpzYIyTTX2N0dWV3TDeztjyCJeHzaEZPDXcVYc7nSVl1vK4JTPd8HXSQYUqt/Rh/sreVR1CeSsU4Swa86QLzgO49fdopFf35BF0ETWdismm5UfcYf8XhS1+Mli2qPAa+dXmu0pCXpnNOHht0+0Ti2KGpv/cIFsGuwNM8S6owVgnSoD1rvV+E53Imus3gpx71UxtnovSAnsZvNFqjBqwX1QnX6Rs37Lg8Dyp+S8ooO9NW/y02UX0Kh3J7nlmeDarDp6/VeMT8tWk3ujPqg49kNn3BbIfz2Fv93xhqsVBH1Hj8Kft1lQ90mTq7x3QdEyE2ie5ssy/guxpSkfkg9W4N7Z/WBn3QN2N9/Q3Y2H2ffGZ1o5QRKaSk4zD5ixiTzB/KAI+jr3IFYcmcIr3u1gk5M3eEHJICyyEoWRV4nHuRlhp6ERTB5dh/8+1LB0+Qe+JdEH++wqeKf0XbQzGAP7ThaC+s9TNGZNFKTsf00DsoU472YV6Z85ylpOaqyw0BbfP1QA+0dH4cC0dN7q3IFb/L/jNQ8xNPn4HKzbrXCmcw7kjCsBBz9JWBaxBPZuXEgHnvdB1+r3UF4miQUdkay1eylHb17MCvlV8LpqNKyTzkD5a78wvT6Ex6uIUlyzIKV+u0uZy8/Q0cKP5DhlOT8dYQKHtt1n13hVWFxVTv+NDiXjyDDSevaJeoUc0H3ACBwXnuNFe41hgnAVifR58Oh3pWD45S+eiF7Bw19LkIKXGF1RC6IMyWH4cYII9M4oop/m5fjF7g1aH5yCaS+V4XWRExgW9PI1C33UkFZjgYHZENz4lP9emg7TMsrwa6Q5xO8c8p5kN9BxOMX9E3bAlK/tkLdQDTZLZaKXdTN1Pg7BvbNqaPbKobRtKoGD23OAd+8AjyVXIdtwGqhEH+MfO4zg+nE3cln5DWdPuc+vno2nwpOO8NjUB7hTG47ay4G4RxQpd63mrWPkSJXcITllFs0NO0ypyvPQU9MDlnsYUJWuOvwY7Y6XZUR5vvIj6Diqzdsfb0dxnxC62uKKxfdS0XTMRxxnZQwD81bh0py7tDRoCyvETsNdcYbcm72Lhh18gIUvZpMy+tOi/qkQKX8GRgxo0JUUDdg+jmi9fCv6jblJSbHGmCM9HPprg9ggRwYGck/BNJ2xeH4wG7ycZOnYgiT+8HEYBcefB62/K6Al8ggoDmiBm8BTKgw5BL8v9YJEux3cLuhhA3Shsdq5ZPzdDbimHjoqtcDbYjO5ui3hEs1VsH/fEt6plAN3N9TRyj05MEfCjR+M8IMU52nQ3vQFZD6pc4BIHE4K04X7E77xLtmTGLtJgdseraGTWeFoem86aCUUsPaoe3yroZLOnoyEfB85mOw2jq4Kb4ZPW2/j8VXrUX7aFPCKU4WEI4zKZo48oNoIC/o98ZDEKay2HoR9jVNZSP4Vfg81gjyneTxyz2o2b9oBajJGlA1vobu2kb09JemYeTE8XaPA+1sB7GAcJ0/p4DXfwmmW6TW03fuMfQI+cEPXRSi93Eafi0cSrBYGk0/i8HX/KbjdI8u7an7zR7ubkPPSfMjFrcCkYSO7VPlhfaE86G1pwqZ3/uSwXm2IC86TkpA/LW5L4U8T0mCC6TvKUAI+eGE8HA4Tpi+RqyFcpZafrhOFmYaWKDVXmj4vIpzzXzdfPd1IySNHwX/vAD4dewPSNgn8I/wYdNV4c8v6DArvKKa1dQ2QvD+CSpPUQdtJHq9/6wL1TTEwyW0M+VvvoBdlYUxJhzmxVhjL73hS+2pZGGfsCxMX3KSV+Q/B0k0WRlRlotsRO1yraQP1Ps2gqFRPxTtkQfLYd9j45BkdfjSfZWVaWS4ngnIaH7AFR3Hfsqn06PJaXm7LcGvtcT417xFUpaiiZLIF2Sa1oePVBzS3fgM3VJrDXc1cfCw9BfR16+GIlg+p9/qS+T0bqnY+BOCtRLtGpdB38zyc/OkzXdsjAkekhUhscyQE2vTz52V3YbiTNMvdKEfVDW9of8FfPFUfDytcJeD7unqcdt8Npn1MZY1sA+q5bAeh15po8o9esNozi78oXsHCdyMg/EsYFj9RY7NUK8q4ZUx37BO59G4KnLNJhGlpPZxveRx2bBGAD6qmJD4xiVWqnXHM/Aie9GsGfhFdyjqPfGjL4Gg0d3Ll2+pCsGtMJuwzUaB5O+NZ7pgubzolRa+DqjCrLJqjHiyFx0PPU7V4Mmgd/4wnD7lyQcxxOj1jOy0PEscCfX++8EQVjVMsuOXwJ6ypVYZjLwTARlsA7bylgJ0tMDZqObWf8oD9QofAbaQglDiZYWmlAOhsbGSni1/xtnYj1hytBOtnPrTpxV98HPkMbTEdvx9WgrH9KnBs03h+4yPLEV0ubO+2CS+efYaPL4RRdJ0tfvRdA2s18kisThvO5gmBRsVxfjlLhu6pbwDlJ9Jk7xDLLku3wcW5tbiqpITNpoyAJeHbWGONPJ42vMlCVEI/7D5B5csRfGRNIOU9eMpz9MuhPnsiJCgWkefCx2CdHICNfj44amcqbZ78j2fbqeK8jwGwr+wAJ8tPhr9VDiRYPBoPlr+D2gFfnCz0BTMOV0LGi7P8xfIFNz4VQ/8vUyC4q5hj+i9D/ZpXPG/CM0rIu8BGa9bRj1hXpHWONH7+eTgdOhLG3xTictHFcEVdiE+IhnDCxDHssdCOewsEeMfhx6j8JQIiYseAbGEKGx0T4IhPQ0nwQJFq9wxQYFYWrNhihwEiG9h4SwYfFwRQjplBSyERrIydSbtWBEcvecQ+4oHg8e4oXgB3OnnHnJ/mKcJPg256aHSHUwSms8q/96RUqUGGz5rorNks3DJfBQy90vDSAMLpPyZwa/NJfLRrAY14YM4NhiYcfmszKY0NovUuM7HM/DAeMZaCYmstnunXjjtnVzGd0oeqxDZ6e9eaHwx+oDW7/pCh1iRYHzkKHFeno/IEI07UcaT9tYN8VKuTt376B6etilAjyBLveyMl5ghAkp4bmVMxzDjphlVmUbxGfwcuSQ5Gp8E6VnEoZLWFHznztAa8kf4E2w5JwaL1h2nFuwdcmjgKxucKotSD0+z54xv3xAmhc9M4qMmZhDkHRdgspx5N54uBbY81r5W/htt3maD5kWTO9p/MsnM0YKLTUXatckUVSz92MtnNuclJoHlWAqqlY+lGjDutueOHxqeMYMu6HhIwCmPx+Xc43MIVimPSKeH+Wyy6eZSFE8vgNT/naHFDcDyyk60GzWD9MDsSHMpOj6ZzlGz4AbLb5XBu8SRYMvYsu9UZQPObSFC/fAI6NuthhcY1EuifBprq4+DC9TB+kaKA1/aYMYhLQP/D21znFwW2awNB5WUpj/ltjFMd9+Cpy6X0QuEBjH4dgDF9U8H7jg2cz23iIiFDrvqZSs0yHbjy4ihOlLyIO2M6KCgsjQuei8BdjaeQYCnIF51H4LHA9SDlsAfyp7mR/MMMuK24Ek9+P8gv+vTh4LRSHL3OCpvS6rgzOw6azyvy/UXRID7pMio8dMcsmSE+8ZKBwiEP3XQ3EE2MrxF8WwePAmdS1awxWPYohhVv/kfbxH6jaL8G/On8gAnKOylu1QH+Y60Hc4NNYFRWFbeclxvqxU/YYvGZnv4QgGOedrR3ZjHe0lXgLuVsOPOom9+Fd8KsY1XY2niTko9YYLrCBFA4OIullXPB774BrRUzgQFPT5ocZEAzq/9xZsoDKnv3m/Nem8An64l49cBKPhUdRuHi+fC88CJH/zEfYslibC1vp7PazK5eIpAWNI+7KzXRNWQADWVq+dW3FTAx3gwjZv/Bs1pXMKL0AvgYzYQ+9WU8ecxlTh1vSisKjtGDEhPepS9JCR/no8KiBXz65Rj0Pq8ID17H8rYaW8w1qkXLE0U8XesWB+7+Sa6rklEhNQPNiKDj9DhY1m9O655dJZvSczA/5S4f0j9CgvMlMf24N9y5P5W6Bn7i/Cmi4HVzAISFN3PM1HQ092nnpdWbsaK3G6qyW9HUZyGOOCpJsSGS0PLhGvXcmwrrp4dyp90paJN4QTuK/uOUec64rVKL2ygMBSbqg3PUOS62Hs1JHxj8O6I5p/0TZ7g0k/cZVbIvWU07H93iLZqakHX3LReNu0N/vhTz4ocN4DErEKZXrIaMdkf6HWoNH50GSWqOMvi9fIhnM8aRZYwkzbBcDxauVXThnyOeL//IspdLyOP1AP7FCdC+tpL3UDBkqT6j91XevLUSYN42dwyy8OGG6FfU33eVt5irwYP8C3jO4xf5Rx0hOVMxGitwimPcremGtjSgkwWeWPCUlpXLwKxaIUztdoWusw+4pyYdr/nV86KcW+h5dSM1VWnRfIkXLP2PYMKIyZS3NAE0pu6At37q9OmuEZ3YdYFW7pbFD+tvwzv7AA7foQ2v3l3AJvu59MnPkgRbrpHruJeglgLgPkkHPz1t5jXKM2BnuDhMeGwKerrhvKqyEuZEquDurmtQNGBJ3snr+UbLbFxkZUDXApUg681TDPErpOILrrTpoipYmowE4Y4dfCarjAKaZUHDQwnKHwLsSLhKe5onsYjnUoi3b+OsN/Zg3yCLdiKr0eK/J3Q8/TpNlSYoF5/ED97tRusXc+jS/8+XeJUFuls30PSLsjS2ejIPT1vNuQlaUJr2FiO2mVH9qaPMbi24f/4vHJASgK3zFNBphAr9if3Medt0QUtQCF4uKUeLfR+oUOk/trIM5z6qod5hwZRsWY2fs1LRP3AGvBm0RcUXgnC9OY8evnzPp7ovcINvLI96PgBFqosh6UAHLTUQAJfJH/BUrh3nHq/jXUuP8zeFNSjgOhEuZprDEatVnFivi6eyJ8AF24nwKryTWkd6QJLmMlBeORqPmjbRpp+bWLjoFvxMewDFf7SgPTgfWrXew/2OdGo7HkgjIm/Cvuy34LRbH4IffmCTUyUcVCYJX/NjyL90Gd1V/kQjg5rodb4NGOf5Y8rlYMrcOEhzEmPo1m5RWOktx+pKIiT5i3B5RgfNmPUUMz2FYaRBEY7b0gY9H2Uo6pwJVK4sxQmzhsHDgNl0baUmBkoOZ2ntSkwZm0Pia16QnWcXH/SVAU/hgxB5eiLqtg7giLU+1PWmkrdeXgjdB/rg9+0PnJQGsFx/Nnx7WAdvN02ET8d10aBhC208swvirc5BXEwHDmuYjM+WfYY7P1RAR/AVvc9czQ2hFWD/po7s6rrIQvcmyfvs5f+mCuHX7RuoaL8AiA8Poin5o0izZRjZnGmmgIPbwPnLXdhsFAPn3+9A47cP0UB+JpgWdvBX3VYqybxGdWrv2ar1B4SePMhy7Q3cs2AufeRvaDBoCCPt3tCCz2I0UlUYYj/8ZeGTszlQ7ibdMF9DgVarwfKaN6YFG8PnmUow17aJ/2Xp0eOViOF6I3HDMi0an8Z07XA0Jk2+Tga+U+BIYCt2Jeeww7zxpFw21MEDj2FbwG3SXjcNvihLw8i7sZB5UxR8TOTxwI975Fs1Cq0D7nLG3BvYO2kB+LxNROnjAdj3XoQla4Rhk6kkic09gnlTvMjp0jTcO8YOYwSU2HRMB1nRdehcOp0mXlKBet01/D7Hnd3mVMGc7QWcsnsDJgh204Y1jWyzYzKcKeukpIUqEH/HAGJVqunMzj9oNtqSvNRfweYCdxylfxYvdCyiqnvHOPmVAajesEQzraH7+d7CZTK7MWPLcBBcIIm0Wg2yPTp5f3Qevq4CMG3fh/5n50LWNj2ceVKZ96c9IaPrLzFc9jLpiQfze9jMCwVkoPp7ENclraAjZaNppmAbbXbzwa1x6Tw6fgqUzUigqS/bYc94Qzg2czJ4Vz3BAkt5kHdo4jNpb2FDxD7+L/YcWXvc5OSsRxjUNRXcNLzYq94c1syLxdtn9+BA+iD9fvqeLdGCuzZloNsUG/pwRxUkP//CiRtcyUIMSfH4NJKQyOdgMVE2fOtOz7+m05x0fTQOGAb2jSbsSOt4fsZuin4zH47PFgeF6Dp66P6B2kxP8vongbzAAKA7u49/ZoTgtpNWsOFsG/6IGsPdwe28SlqEt96fz23XzEhr8wRIGPmehsWVUff1Nrri3Y8fB6PxfqY7+H/Jp9yNS8DGsZrUx06Fij9bKdp0Gha/FYCXZ2rhbMt/OHthEU26lw9FVx3pfFcrPJObClJPlpFfkDJVW3eAqN9Y/B75GAsG13JTyCiQrEvFj+Ey6HVOF77dzabhX9zhwhMdynwkADMkfrO6xhPsFr7Km85kQ/IOTejNlYDhlWq0cHcD1cxJ5Eibk2i2y5zb1Hbw3s/TqVNoHbhnDvXGLCOYVjef7Z+8xcsCLnRgRyNEbmjnS5KToCvAkMapO5GEmSeIHxzqrWfLcPXTAd43TI1v2h7AD3XC8F5tNnp/0KH9h7WpS6CdDm4XhIu5c0BljQVkiN2GGdvzsCmikGMkPlL61N1wtjgeVj/Zg6UHRkC6owCVhClj2ZY30DdrPn/LXINbxnxH7xh3KLouwMnXz/CoU2LwLfEFjq0IRl2bLP5XM5qXUS5KVJ7gO3pnSL/8Dpl/duIZc+Wh/IYSGbo2g9z1dJZLVyfNJfHQqGOGTi2KUNo3HktWRZDHt+ng6810+n0S2ehX8KKx97CgpAJbZC0wT/AkuZw8x2qB7RSyaxQ8S5RCkAuj91c82WbEdc7vXcNL0wto4XgV9iyN4i9jDMjkzmRIEhiFqbIe1BvzkjbEZKC2XijEF6hwedQc5NU3yXKBFLxzGgvvzYbhuioF1jGqJq/CZDrR6o3maE2W61XQeV0B9N6OgGeHDEDe0B5ThndATttIknoryxplNpgdMZ4XHS9lQ8MLMLzrB7TFIrya+4++OQagxeKl+LVDHxXrz8C2PE+u1FqBFS8lsPhmytB3owjds+9y/Q3EPU3X2bR7Bn3eHYBX899Az8VsDJWrRYkoY4gIlYL3ieY47IcDB8udxfZoG3i7NpHUIirA9/VFfvt6GCsn9sFHT4a2patR55Y9LL1dwKdm5IOD6QZe4VAJG38KYtuhRUCnP4FXkBRMzvDkaOrB2CpbOrXvGhjpXAAL2VWwoGUrjvO6hs+X6MLypGGgsuUU5D6KRrfYFhh99z0K4yw6aZpBdkNuNHDoL+eWu1BWxXSwPu4BkXyaPpc/hqzm01yjGQPPJAfg7mVVMir4C0ceFKD7JoCrAfW4VSsTwX0B9m8t53nxAlij1IMDX3R4U0vqUJhPo0CZ2XDaYwnH6l3mjjmfYCDJDO4GD9KAlTM+SsjnqQtmwfLWJ9QxWRi2t9qwoNENDAj/xoeSxKE5YTrE6p1m57lZOPhvNHq0lnPPXEmwe+/BR7JescqB7ejWdZM+lSnSuf+28eVb3yFQzp2V/a1x/QsxeHHqJgcbv6HXn1dxWf0q1rvzEV02GKGfcSdrzbYgBwMravkyGkQ+BYOJlyVsttOl94Ey4LRyBHxO0qY9l+VhVqAAhzyVoPN1ArD7dC6mzJsJ4HyNVW5H0mytRKoM2IPujhP5aqsvRNRE8YJWBVB6dJgVeQL8+nKOly0IxXrtXzBj723+T/ICVItcxQ6fHg5bIQGyD7vYyWsfDF8nRn+HB0PdsRTYVCSHxknf0ep6Agz/Zo77T+lBdPBVVKpohD9emTw1spuPq8iTrrEP8NEaduifBwlC8exeZggyx6rJ/3QNTRniivs/K/H7SBUaG7kJZ1dkgu4mV1rbBjR9piGsfxSPe/ADBtRNpbnH+1BJzhkt+xvZrPsYHs1cCrsPfKcbq/Wg27EbiwUq8OL6cp4k4YFKIf2kmfMbU16dRckafbbuLeMT401h908JchE/gi/PB/OfSHPaNNTvIvEWWFS5BfusslEPOlC/Vg32/VMA05OCGLLNgNLnKJJb20b+cHAUyVeXwVgzJTr7Wxd6R2pAdPpzCNRPoJShOa340Ag6oYvwRTLhMbvzfENbByaQOgzfyjCpMHjIQyNgTv4gaW6pxNv/rnHRvLXs6ngPnTZ/gwTdGCjTng6LG8vxd2Q0y9S/xr/R4vyw/ghOMO6DRTtTMM3rN/05th/fHNSByMvfSLW8m12KVAk/3YE9tSkwY6QdsIIRx7+IAc2ToizVpA9Hs/xoTG8UFFmNhQ0OEhzaYAvy2nVU2txNT0alk7bQCUpzGwUSrvHgdlCDLq6yRT4lD8OPltCVPfrgk3UCesYD3V+ghisfSID9Z3V8MUMWfUUTOOHQGd6tlE0aFttoa70tnAmLxdlTH4DgNYQDYoNwJ9+Zrn1pRgmx+9CkGwylw734yOrLeCK8hRz/fMK5z6dDsmomtvRIDzlGEpXsHYnbkpp4ndZaEN7Qga/qgrBnixbM9zaFdqulnFP0jAL6JnJ25ndWs+jBSrf/IHFPPw9sLofN161JT2A2jExT4+XxNvy9WpUTrxNhkxTf8VyDnhsScXzYeY787w/eSVeHiCJ7zljtTZHzY1CvbQ1oV2Sx7NchJ5XJIB+TZejqieT7nyCYj08Hsac+WNsxl5xixuFj92Hg9yyAHlo6YmqjLc05Wcg/bSZAZ+4t0vgyjMYVi/HYEg84u8mPe2XPYE01QP/ebaw2XZn2DejA1bhh/G9ZGcUsvgyuu1+jcX0Hxy67jgO3gU/KudHx6iBa1zcSDMJ+475z06B5eTAZ9m7gtc2v4LnJC9zs9RlcsQ47HkZBXK0oXLhlRA6dldy2fzNLBHpj3PtQTKwaBnMla1l3gxg7yEyDcXIzoPjMYyisfwvPZEbxkw2PeaNVGti6rgLFESlkMkUSSsLXs6nSbNAd/YtOXPtJOlMW4F/xIFZxdYG6E/Mof/cY2Pi+CJqWjMfDL7Xh0LQSElW5TDn5RC+m9JOiqD5qJE/g5UGe6BItiDJqS3DwjgIU9CsPuYoOzIvsQt+0w7zgkimGF7/kXOchn6rfTiqPN3G/vQH8dFqAN17msemvCjKJ0qb1wQ841+IAZ4a/xO4YN/ho9oQH1PTAbb8WNrqfwc517+iNfBoUrM1h8w/1qCeVDPlDHvRqZyGcCtGEFbObUKY4m5+8P8mv90VibaY4qhfqULaQJqR4GdPJK+PAZ64WuPvVgPK21+Q/2YIlL4zjQklFzNroAtH2a6EvR5Iaj38ERyN96H4eTsfuR9HuoKnw9/sP8Kxt4+m+o3mFwiyq+ScGIka74VX/FBhoOIBpmbVQWCrE7RPUyFRYDq2lk6DOShAz9jyi5gBf9tgrC9XNI1B3UTQPWzwN9EOzYXJwGUZZF6CB6B1SX/eEFk9aR1K2+hAU9Y1bE0O5SnoTO5gHQb9DCUXe8eamJb/4jEgYmHXFcPBWJbBcmkqe12Nhqq8hbMsY6sgr0nBf/QG4GhpgS5cXTYtIpPchEpA4IwIsxfvp38unPEZGA698kAbPlXLYafAPvzXXQ8V+R4jplof8XxkY3NULc1wMYOyiWLj2Mxt2O9zkiIWONLakAR1NnPFBmTjk9Jnz73V98IIN+Y+8Fnu7LOb0LDloGaUKJZP1+aO2KW5RHAZSYe/I9ukzsp3twL7CTfRHfTY9/tQEkz5v5dzJ+mh5/xiYNArCpd269E/qJ9r9NCSTnEJuvTWGRoTXotBXM+ww0uPnfp4oVzcSFkr4Q9is89j3s5O7TGvR7EgBh5ufx/jxr3nviYXsluUDRmOHQU1gEZ0z8UXtS830xNwRzO38uSxsBQ6uN2KRsB+U9nUJh5ybCaIWl7EudBSa6e1AoeUHOWzgOP88MZJbFh/mahlh9vzvCSyymwFnLl4D1YOFEHD7Di9K0SCZ3fGcKKuB8p0K9Nz0FUfrG9C80aPg1e6ToG3sS7d7GALGOVF3uTncctMk/fr39K3mCz0+E4GeC8fCgUX7YPTl3zQ7IpaePNPAtYOemFNphns2tLHpv5kQv7ITPz7TBdV9x8BjdQYrdw/DC0kNUP13Mh9agvz0ygEWP/MRH27/CS1lxjA/OJWMwg6ie/Z4OGTuw/NyR9Lm7clUYtUBLkfPYrjOUdx9VQuUX1/AwRJttpP+wS6DoZTudwHWuK+FAnEl2vxOF2SmP4aJn+Qh0+Yp3jM2BYWx+Ty2QJrmHzjFMfetSH36Lfio34tmjxKha4U8rBTdhKfn5mLF8nu0o+4QDWsqQyWRj+C9w4zgZgvGSHRRs8Q4eLrKgafna8LmffcpKd4Ify0oIp/JNdiyRZePZtTjKS976BsE2Oi/l3stX/GjkBE0W9KOuwPCoMpekzweT+HZ50egSf1DND8jA9NOZOPDgAxsEjhG+7P30+kVZ/lTSyr+PacKynHl4GW0jot8BOHRmXi6mFNEsaL3MS7iJn8/uhWDb+7G7vB9+LZ+K4Y02FJQyHTYejeVJ5vmovCeH/A0eQXpZujQHhVlFhzlyOE3XMnIZSPK9EyFnaGz6UfJdgiP/0DfWpPp8+tMdp9cAMYmvZSp3cpKhtO43EMVdMtzOFflEPpWG0HiXWuCualsvnQ8RqdpstNCP7I5v4E3usrATMktNNFiDj8Xmgiak9+RlHEuNy6Nw+uf/CA2ex3+6xCl+dWGYD/YQebbczD5uwO9cKvCLY+e06x2RYhTCaaW4wHsJBgOx45KQ6K5GZVo2NH8Rauo+6gLig68wcLyTMpukKUdAxLsLpdKj1UmQmKrDI76eBtWvxrGatkVqBM2gO8LRvCjSBmuv+VHqyY2wtVuCdDLE4e1FjHwPGsJSSSeBreGTjbfJ82vbZfxg+AnbHM9l1SD///fz5jKRJRg82I7sFS4jZfVmlH1TRT54ABX1U+nMcOW4mK3YfBCdRpM8h/BxucEqCyvEaLezEGN1B66JXWaZo5SYfFoa56sJwrBPa8oW2kWzX71C10vOkPA/qNoMkWJTz02AwW9XPI2voOoPB0OjeuiT0N5QZ3juVPegUJ7PEHW6wa1qL3CnIv6YByxEyBJEApf7MS8vDvk49ZH6xZksrhyBWXo3IaziTrkafsaZr1fQuPc5cGkQRHu77AC/+4ZqNSQzzUe/fzd0Zjv9zjQYuswmuw4hRosRkOcYR/4/3Tjpo46qjHUgKTqUXDefAHa+v6Af5FbIeLfRgo5Px3OLllH75bYUcyBHi7e1YihPZdoi3wxlBoiag6eJt1d73FLvyA8SClhPR7OLrobWWFUDWhc+U3Jt+Mwz60bVB2vUmdsMNOa8aBo9ItDFy8hyXgZ2FTrTBvO+XJh6BLYszCQ8nki5+8Zx2VxE8D7TS2NOSNCD2+3wLIfdvhwLdObM4softlwnibhwyNmJWBOgDysjjsHqrfzoWn3HqipSka/GbtQerIJjWqNRgmrfew9vIjOaInA6JUvQTIhn8z/huNCWX+c0laNx2+54uaH6zB+aRarVm8l1xm6EHTDio9cCGbL7xn8pseO5w0x+VqxyTAhdA2kzVej85WbWTt1GBjsieMIo/nk97aMlVLCaWPuY3B4NxMDBZLAbssPNv1Pgtf9ZwgJD5eAwA97eKtsgeNDP3PP9j+wvkAG2yVeQfqNSSA1axi8SVMAgzU7MdDqF6xfpg5FAb0ot/YSX7y9gEQKa9i89RQqf99Lv06LQW1yPFk+LeEUzkW1XY0g/SqE+pryuSB0Dk/dKIOpumEsvWYqHF1zDs7JN1IZ7WLr9ykkblyHlv5rIcL+GOfo7OIEg9e4LNsYwqxKsPPRW3wz9QrGiE+gGRUarCpnRjvmLiONv3KEhZ/h/kVZ8Nd9yYeKc2F5+T0aXPaTjT7Y48kJx0BRX5ujBm+hnUEBJl9Whof347FHkKEoqpzmLv5BoWe9oKNkK+978oCOSR6gsXJZwNvl4bp8Ky+umk8SBm7YqY4U/LAaOl//gs0JkUOcQ6T7qBmW22nAlWuTeI1CP1i13h1io+28q7sci58W4ejeCySVvwnP2UqCxDNNELXbg2UObrB+Sz71KSyk7WFz4Wd7KP9+cIsEKz7Ar509mHRbAq6PWc3Czv7cbVRBD0QYDHcugbEntGHD6hCeGrOaG1RzaMp5ZSiYvoJsayfxm7yldGG+DG2QN+JVPSEwzFsD7P8WU8O91fRnFEFtyhcaIaFLARMM+E10AWbheZIVX46G54/AhItyWHXCjwUbDSDy1WTsmxvIkwo+s8SNUrxcIsJ7AkXg7K4E7ltpxcvvzKSx1ibg4uSBWcFmeC83lV9LBbNriQvO3vaOgrVS8PC+O1CSLAGKh7RgTtkLqPxXyM3nxNlu+X4Ysc6Zrm5YxHMPzsVdA6tI7PQj/ocTIHfsc/D8Uke5O1rZOXoqLo+KgKQ3J+HU7w7Sn6fDue42aNw2DdTbi/i7QQ3fcTmAajenwuS3h7j07jb4418Iu5fvoSvZbaC8VwK+RaTystQAVu+twhufxlCf8RFIXJFGF8+956g/URzwRw93vh8Lc17Y8LGd/mgeNpHMxNT45vvLnOMcBL1bZmDNcCOwmr6Qo41VQcPeBRXbozCmthDcrp2GisBBPuLfip6zffBp+xNskS2ljmxRmBOnxbXCGyi4Yzv7qSTglofz4Gs7YF36IhSuiuLdA6NwZr4epDtok9WdNXi76ze56tygglTVof1WcsXFCHKXEWfNtEm0z1wRitJX4m2x/fyl1h/91OrZs/UsH7iexgZKSVD7dDxuE3KBmHlqMNMjiIav2csJT0So/rUtyx8H3n/lK5o8+wq3szrgtf0D7o8a2puECZmOGeDX5mF8OaUYwm5VgM/J6xihRnjn6DOetkqeLj+UA+FVo/GHxxial2pJ9npHwbh9DwhZS9G9OR/wP6ECCHykR1LXpeFg8ACHv1oKjfXZYJVRQidP+rCHbge+lHzK3/bP4IV1KtRqKQxb0lP4X0Akjz60h1sTLlPdfiOYE32Pqt03UlB5EXztX4sGp8ZAWFouxdk3QnKHARda+XBL5wCZ2qpivq0j+/lGwd3rO4nn6sGG+xlg/3gifNfagUtSk9Fy7iSybV5Em123cc5u4nRxUXr6Wh2CWyeAv40MuhsI80DmVi5UHs4Xf36ASvGHMFNnJe3/qQjZeSPhsnw/tI/9wgr+dWC1wBE6rXbC+KxjtGNW7xDrLsTo6yFsOl8Bgh9XU2zMA+Ls6zhNJw3P5x7iL1+v0KER/rTe6xXZHYsjt98jgBWT4VdkBdtQGfZJ34W+Mhn45jUFJkgsJB+D0zRa/BL73ZUFVLtCfg032dUpmm28R+Kq5q+gJRSDEmUEXdqbKbXsO4U0KcDm27kQHfiHs7uUiexUUUcF0NK6CKzGfKSPHkWs1lDBpauNQHPeNKp+/YXeCE4iTWHmruAP9LK8GCYcU8MNJmdg1isNiswYD62qx1A+7xiFb57CCTSW284N5zmbbEC7tg/NZo2j7uV3sVFbEUa/mYEfenXI2O8LVi9Zjh8TisDaxAIejtBBoeLTcKrIF+Z91ACndRsoNG4T79iah2vLhmaTsoU2CL/lFRslaeTOEBosiULvbUbwsvckKQ+uoaOxESirrkiO0r8hw+ESHrC9hW7pi9nIN4C/lytAwkFgY9+feKtFiAIO7iWX0ghuk6ogvhXBmtdHw6rYGtiZpgcNf5bCR7Fz3H5bCfq+KKGGyRNw9w0DC4fldGnsMzyxYRr62grDrXO1HLD/Arkar+b94l1cvM2UNZ4H82C0CtQ+/INlpj/o924BSPcKAXj3FoWHu/OS4atRZL40hGiXQ+akC3yvYAmIPfLH1Y4Mo68fI4eekXT5qCafGfzFR8qyydp6OW99U0T3hx/kHeYKHCwoD7WRmXgsQQ26fNax3/p++L1EC0a+u0+lBZGU1LiPp4+eDU7zTKF9fwB+eEN8864/bi7uxIWpvjjPayzGi3nD1dobUPnqNnvuN4Yjdk14sqqKrjoIkuy+BtqlHs7Ww2pI6f15VE3QpmqxJFJxlYSoYA/ckqJNi9/+5sU+/mhmMYaa37wEQ8O9ZL2+CP28h9x4/yjomnYJZgkKk8jvZyja9Aa+6XVSqkAJo/8KHvs4HHYmeFBxtwIcl+iDCXekactbVbqx6z7q7mgkPV6J2poW/O2lHv2xTKXzLSKwVDcQPo2wZIHarSDZ3UD1S9ugon4vn7gsipJSRuj8NJnLjbVAxmI4dLR8o3SDXFL+FsFTRSXATA3x0cRImPz6B8yPukLrhvI3dbQIrDnVhs5JGei1sxPlmoVx1ZsLpCO4gvWHvHfd7hU4yVQBrHwv0OWlX2mZQihYX/sBE1ba4JsqBzZx2oy3K/3pwAQbGj5RBiaMioGfOw6Sh/pLHAjyxLRQM0qUT+PDb47D5QndVPcxkE9pGkNN5GTsTpShuV3CYO0iQgsv6aL5vhrqE/oA1yyzuDPhNM1rEwGjVzY4RyoWfuokktWeEv6dpw+/faXYdfoe1HF+S8b5Gxk3zIZxc4a6620DxMmNxJJ9V+mI7fMhT2mEQ6ZxEPPbnh+aStPAtZkwcm4ltupI4vKyHaRubomTrt+Gu6k+pJO5g6bcBBwXJUlJX4fB8F2iJOjlgE/uOUJpNGGvqCM4jBfj3UfGUvzcWJh4wgUNW4Rgk+ZtPFe9i2NdlOCfzl2Mf/2UtgqPocPf5oL5ET3K/zsH5H7owQeNt/CuKY9tqr6RYp0UzzokDlZgRYEH3Em/tgvtJH+TgYoxfDF9Qtem+5HheDf6Z2POLmVf6fV2N1b8u5u+v3zHG1a00NZZarCi34XPnndBmyA5eDasiZ0+RrDsD1FWPOVCf2ttYa6tMEaOV4bYcd0gKHyY1QUussr8+7jPuQ1n1Q3DPWFeIPBEgHVyuqhElKBVIgWF3ufhmBPRHDwlnv0b16N46V9SLZch3z/WuNsuEsWz9aB+2CP29unGhvUJnB7hTK8uuZL89uXkMbSH0S8V6U5FEs+Q1wKDFaHgaX+IV6/UYKuMHnps+ZUWD48AkcYH2DZCFP/82g5BSRJwtWUlH4uzHmKlaxxoYUoLzj/mwzqZ0JV/id52L6LejK+0zVocRnxx449fbdFSIhhq56iS0RRbTt1UTmeDF2JgkS5KW/7lBb4mILZ4EJVWGUBLxTScuH459n/bSKovcjF+dAL2P4gD8SpJ0kwCMO3IwR2TvqCeXiR5qMkP7d6Ljlyqp3V2h3DngcPw7HslyESNhcvtd7ih3oTsNFU4uvcHqiZG0Nx7y9H++FkO6RvEhScWgru3AEDKM9acTdjALrRNejY+sfBHvV4h8lO15BNdVnSiRZ8Er06H0+cv8Y/vGmAk8o5TPz+h1uZP9MF8Ml5RGIc5V9RpTmMdVpgqg/MpX76wqRlPrp1F0Qefgu5XJCEPO455d4GMU5O4ylmETP9j6IraRIndCFJ3rnPgLx8u3DyGItb+gU6hs+w7o40+hZXgxeLZ0LTrCRYZq8DP7UtBM8cPxlQ44TvjSpZ7/w2eDM/ja/d+0M2zE+C41QvqWe/FiV/FeeUXC9hxJgYE/xVAfpEuO13fRjIvRCn1P1MYNdiPP8dWcV34Sd4u143eGv/g15oRNCs4HA9IJZF6RyfaTpwBcXpnMXqnDTpIGLPK+BQOz/lKL3RrOW65CJs/OEPfHc3xj74IpAo/JbP8L7Dwzhg+uQbYcs4Liqu/CFduxfHMgHr46TSZTm4cBSnjjbBl0y5WunqZqRfp0KUoWHeiHC8HEU839oPPGVdBVkcPYOcYCsN4yoto41cLV+M9t2ks5FSFV/X/cYNELjSve8lKgabQ0GYIhw7JoNe/FFpd2M5eqwZpj+Ji/CduMuS/k6BfeAVZ3hAAu6YyOtTnR+reheCTMh0ubvyHTq+F4WOVMVYZ1sDxJ62s2ATgsW3IX3PVMWa+AgXdVIa5ex7QcZWjXNpzBUJP60DvkXdw85XOkMdXcardbNaMbcGOjEXg7PCYy0cs5YLxYSyDHnRYw5hu5WhAYuEMgl8HUcpRnNsFe9lGYy+VmM2FxSVaEP7wMHffX4w33slAw6F5tPZ6B+ufrcGaP7Io750BGS7aJPvCGMSGZhVRLgiPPCUgeGYYrO2PpohF7bRG5ClO/68QUxXFwcglBO2XlcBEdwNWch4BclnZbDMlg/ZHtpNZ+BfSHNyFG7eu4L3lD0jTdjEm+EiAafl4YNsBPqD5l5fE+Q958H5asP0Tryw4yNv6gzn6TQE/OlDK3b0m8MIwDtOc2mnm6FEUZnqf1//9g6F3PvGNga/s93kBdmx4SHJaE+CoZj7GTrbEBQYn2H2iDc1r7CbZjGG0x+weLO0TxKi/H/HR+JGAr4xRpswM5Bwb+NJ9OwpuDMepO59TkuYkwEfD6Ogre8jdOwXK7E6h58BWOrQ0FKeuWIm7ws14vmQiFm8NA8c2czqVowjLH0yC2vWf4IhTEjy3M8WeJ73w1HsDhnfEovnZLFZtfMIzo56jWqAcFAb+gasd1nRXo5tE7W5gUVsivn2BoEb6+HBGOTj2p7DWzFGQGNJJb7IL4cv2+XDfaR93LnLhLMlnoF0tiKcvJcHLaVN59EoTEPzVz+7nK7DxsTKP2JXJzVMPYObTQAxcIo3beglD1f1hm/AE+DUzYYjDAllvuQ84GrrBi5/xWOsSCa+0HRAOOfOBsdrYyDqg8SAPt47WpuTuEMpImckLsw5DyLWFZJRXhDJjHMnc+yIdipoBStqhaNNzltcoP8C3pQlkmL8Kf0ZPgjX+pWienQJvfjRzJcvC5Xgz6nOOwQXRsbxz3mEM2WbHIbl/cOqvSIyZs5J0P7jiLEsxaFuwCZ3CImnjwHAw8UpE5WUFGK21ENU114FohhfdXC3Ky48MB91ZY8C6RRptWzdB/5JlNOPdZz5zT5T9xP9Rzol8PhkkzufNh8G+Ix0kvCyFao550zmBbPpxNghVyjvx8r9zGNc4m3b9zIMVT8aCdI4sqVZHQULmWrxnmEPGFZdpsLKRp0wldpV0oMkL+jnIUAReyb+nvymWVL98FufFiKFZrizJ+92Aln9+WGavQoWtXni0Wh+Er5fAT4t2ump8iPb9Ok1/7tnw/DuTyHetGKverKBZzt2YfWocGF/NxX3DGuDoFkdYp5vHA8ufc+D9BTxH8SfSwF5q0JnIDcuV4OCak7Cq9jC7CNXTFtUnrL/vG6xI6ESlE+vg3uMLmHclFedPnQJR++bR2PcJbNDazMfThPGnlDBUBSvwq/sbWct9Jw9MKqUjqmJQX6uFv54Odf8hW7rlmcE1q7/Bll8LaFn2Vu5bJ8cddl5wZ7EYyFarcPbTf6Bit5dD7hnglu5i9pw/leL6JLl9y0E0fi5NnxQEYf+Gx/jvgRvdtF9O7WKqsFbRlrc+/Qm/Mkv5cqYA3RL6h6fyAWykDHlB6AQ8uUeIdCaWU+WZn7Tr4i88mueLK7suUdapXjz7aCJckveGCetE2PnSCRy/Qh/FHYqhqbGdblE/6agvwgz7WLDTnQYXNB9DeaIECO0P5z2TguHhI2WcOTidYp5ogFZLKL0c8vAQKTU4BK3gsSuObMSPw6jOBHR1uc9bm8yoYZobpS98CklZyzDy91iQGh1Amz9rAG36B5YCifRMCMDSfjreDtoNdSs0yPbRcQ5+Q5Cg84xGPetAu09JtOrtOUy52EFh4j4kHeuAdywz8cgJd2ArETgVzbgsYgHeUJDitPXp6FVdCotLjWjGPKKN3zVY9+V2THMxhakV56l3tjtGHguk8xKzMb5EnX8vewLtxpb4tqKZhz/5QMsuToHqvCq6sFOBRd9vobtuF+BbfxLMj/sfcefdDYT/xfE7bBWRmZWRJCNbVJJQqKSpstKQaChNo1LISElaUkRbqYTSQEYlFOGLolIUpUUp8fMsfk/gc8495973+/X66zOb7yzyp6YdshwgtAo8k+SgXM6Bpva/phASx0Dh65SSvYOM8t5h3WgpaLC2Z8WWZtpOwyAs4SUmZ3XjvCY7Hjkrh3M7pEArbYAiJj+AHYJToPV1FyU0CEFvuhjVp5iRVehw1mxL44d7d8PBvktw4qwRrL3txXpVajQ6UwIgxQafvg9FJzNLmqq7Fdf/UwKVsK9MDa5cOeIunnu+l6ZmmMHw0+M4adEcqr11m0a+PIAdL/1Z4nw0TH88HnsUD+LdxSFcKKMBmwf/oOK59fjlkCDoF8Wg3JhrdGdSFYlMHoftyxWwz7oZ284bwi+WAN+P6bzm5h/IupnDb489Bw/LmzhingzuXniE3i4aw31rJ8Mm80S+E5GMGW7LQNw+iBK77oBF12HYuKwTN3h2DOX/LJAyVINb3Tr05n4ZKP2agktvWEBYWxAmhF+DvOIpvGThTrDZL8wfb4rA+8rxmJS1nyKvm4FPhDyf0FABG1cF2CLvCTrGj3D8zQosSZGCb827uOnLCzTJSmJbUSOqNBvLZaWfYO/OOhp0sAOnU0aYrWgC09Ju4ym/DJwQpsen/lqjWpokP1lXSh4LNxNHb4dj+4RJYYYGpKc74xMDabwsL46loyVg1RZrnKVfy6JRf9DR2hk2ppyG4VKqoLlaDzU3rMT4kDfk3HmdzqbbwsE6K9ijlEPhdm9R/EIpex5G6L8QwCNProe4XS/w6MBfMk8wAotdB3jJscnwhWdy05FMcDotBNrHm/iBcTerNJ6inkvxONEoFZxmrCTdlYPwvv0Wfj/5lp88EwbPd444W8KD2i49IKMzNmyzVJPSNNNZ/j2z5pAz6vyYgQe1ZKGhYxVvjfTjylsSMLO2E7y9O+CubCbd6akF0z57NDm8mN5ri8KaZ/WsPO8Qr88ZjUUrTmOw5ENwG8rZg6lPOClYH/u/e+Mme0EIubYQgp27cOCuPTYvHIumX3vAtlqdewLL6FCrLOUmdpDRYlWY7vqJwxecY8XL+7m7eQnfSCnhgEP74KbuLz6+boDPLu3A9lPCkL5ZC99Xu+Do3AROsLFkqdJV/NXBAh6sPMLbW+bjoiZnXBNoDoVRNbzm10l833SFsneq4fY/C9CuvA0275LG6uxTcOrnMJox1QCKKs6ibvcEMr84AdMDumjsd2Z0jqf4ijYOPx5ISW9GsX/DWDi+dQH8q3Vi4UfJnJAlAsHTakH+/CQY51aF+Z/iMCc/n+y/msCmbi8uiKvGjFqEw/lnMLhOje3pJT580ENbbSNZKCILlf7IgppkNa2WucbzG/1gS+9blvs3BtVsCvDl4RW0pkSAhZ0akK2mwsXb79hq/y9KL1xO1RfOs3P5O9K5MZOPr9DCfx4VtHKCPzbeMgdjxyL+N7OB7oaOBIX+vXhPYgcI0GO4ekiXnpYr4PdMVTyWogwBa7q5JasWQi4OwOuBpXi7/wnUfdoL2SsNeaTCbpyaMAD7LpqAFDlTqt0/2Hn9Kz/ruYgxcmM48NlsemS9ka6ffYelH1bieXlBAIMR8NI3DXsPRqKX7034WKJNy+ao4JLOE6znGIvbH2wn2zl6MGPjce5ybSajd985NmQ1zH12BdwnNdGfWYvI5YAPKR5sAM1xCnDvVspQvwMr9SjhB19FMHoiSVrRbpw2sZ6f3BIiV7l21g4kCNgdSJ9bNsKl4RPISGEE7LvuzT3fqmhVgSIPPtSmjdYn8MNsTWhYcBSsCqaB1p0rtHfjHO4uVOX6eT3glr2az9vfwuzVR7CPAPyiN/GXZ9P5zbtK0j33ht+muGKDw1ZQy1gEbZFF8EPlAN2WlYFPmxxJ+/ZYnBa0EcO5hR67J/Pi6Pc4d9cZGFT8zss9hFC9SgX0b5hAUn4xy/cQfHIfxwPjlpBU+B5CK1vi+kzI7t8KPvet4HNzIPdecsGATzrsEPwfbpkkT9A6kpsvH4ckoRus4RZOcjXy4JFqDylS/ah7QAtL5vRz6NH3mKnuCxYLVGFL+BZy3TXAyz9qwaYLl9lodd4QK/fB7cpqCp0I5KopCMmS9TAlZCq3d/qjVNYUMApMRL+AmZA+fBpljEK4+HwKjNwmBEFrj8Bf1W0Y8VeVHb2F4N8jYywf2Aeto57gtTXeoKszHI+8SOGnWS/RMrYDjKfOoBXXRgx5aSYaXi0lgc4bYKV2hgZ1C8HGLBHbRu3k9Oo0HLDdDCkXR8KVuEr8MOcxvxvQ43v+juzlXEPzGytw7qwvFLIviw2k/+PA/KmQs2grjdb0o9NVSlyzKBzX1z9Eq5HVtPmDFCz4VkcJafkk7KUD1Ul+1DLuGPoPZoOs5mJUW2uOXlpdPDLXnWWXrcf3vpH86MFo6Ao/il8DZ+NPg27wzXqHqzoreduxN/BpRCQIZmvgsjM/UK1UHta/2ASu/c7g/uIfHj7iQJ0RyyBO8ggOuoRizpxl4Km6gOOOKMAKcz+sL1qJH40E4URTHTzc28wJEcfAttYUOvAF/jt/Ha9dMoDxTUIcdDmPTuRM5TGW+UiOBbg0UARi7r6iBaYRfLAwgM4uHAtt0bJ4asCZR88spxGzP1HOwShUiwjntt8T4KHaSR54sId9PplC3PhkiI8dx5YP1uFU/S+oM3sYz13mBz8n3MC0jArsCBpB05wmgfW5+2RfV8tLrviCE9bDpW+nmX6+oDmhN9iK1DB8Vz/7V5jAZvEt4NqpTFqJryDA/jXua3iM4U2BrGCtTUp/j5LKaEnK75wIR1aGUEGBC2KSIT0Tf4Onf/fxmN5yMMuVgUmrzmBK5/yhnh4JWrIInjIhuOypMy9tMMKf0vcRPkrzr527+OT4v/yvNosmLRgGOUu+YdmeBCxfPwOnDKzksv0PsT5cF36fHISuK/6cafwFnk80gJ+z1Cn2egv6DB9GgbH5dMPgIsQXJ+Pplwq8fmMyxu6cQf7ukvDidyubeavA3+Qu+C/QmdpMfsOc1HnsJLUAbtSP5M43tRx8Vwiadh4F/6cbyN8kAlxDF3OF3w4qsdtPYQ8+koz/Z37mVMrVcrLwzrIIGoQ34KxH59jCejjcDjOGEV+Xc6VZAgsp9/E0fW+s2KMCDrdcIGdyCfedV+KA5j+8f2QBnMr5hf0lDjg3/D4GndsDQY7DYWFbKtev3AAHys6A9Ics2O87kz4ZR3DnmFkcJ3+Af1o8h7L/NOCA+mW8dNiLYmUVYY90G+XbTaYvWjmYrWCPgZkV1DDuGX6MVYGpX0VxfHc7bx+vihv8c2iUxyccGCNN5fFSEIbm4CneDdO3WkO51yALwQIIjxjKwJowWlt3HZJtJ+MS1RlwvlMQnJ60g6bPZPiVaUYbAoE/agTQu9pPsLT6BJhNyMTyIG0289tITZ51cPKpLiiVusMrr0QyLImDA3GukC62a8jtC7ihazSLztxOXzwM+Lz4GFBRt8Gxhz5wzVlT7l76iYoO7qcRCzv41UAM7LG3p2CXo7jsyhiwdVAD/xIf0rS4TntkvvGkzHFo+ncF6vzIxiTn4/iqrgoSPo6H4jvtFNG+CGOqozDJpowE291guZcsXfbYDZoOlTw7ch3Y31UEBSl9/DvzLXg+1mRhg520NCOYsltk+a5CJijvT8ZLf5NQ+bAEfNkxH8UCZ8H2uLGs53OPS1Z28teGRgo2CeN+5yf0/Y8wev2cBI3vbMhtaJ9WmU/EZ58u0UTJs+Rw/yZ8nuhDwlMnoLPBVThTNgx61EVhNXbibY8e8t4bwT+bE8EtxRfKFf6jM461qBd/jx93I0TmJVHxwsMwd1sF39POh92u2RCwxA4urLtIgUdM+azJTG49KgYTLd0wihzgdv5YTG8OB6mrP7kqyoe3LlqNNinOqN4diIcrteCghRyPPhHCz4630ORQWWgd7oGfOt1htuwxEphmgEql4/F9swLsXNwPhpLP8MXVVpbqHUVH9z3nA34tOL1bBn02AoZKHiRZYUEITw/C8C2zyCUmG0N8aiAxZBH2aR5lvX5ryE03IUf7MhbeJA2i86fhyHwX7LLfwOG2pvCdCyDmuyZaJ2+BPAc93vb+EX3YoARqycn8cFsu2tTNpG63kxi38yK+ONtNFeaLYURHA9g8XE2Lo5RgWP9fWj2rlno32WNoXAH51PiyyfRR6NR3GKTDl3CHog3/jdYFqVw/HnYhlkQeyMEInQK+274CzuVdw3GFS6h08wee9nMjXDujBS1Oh/nP7nrM3ewG/Rvugaj9HRCIyWKTPzchSCeX8sfs5LVDfp5Rp0AZoRsw7LQPTkvWg2uJX/iK9QssznkJuf2n6F5AC7h/04BLHw2pyvIH2Eco8bCxl3m4UjNVlzVyxbrdkDE4Gcxl9FnPxvj/9v/vZfvzNOF1OecGfqP3BTIU0K0Efjo78XvgKhRQFefpBsBNkdZgeD+do/MKIT/FmQwynVBoIIOdzruzdZseVxyYh0L+R9m0kWEgKpjCduRB/GozPOc2j9f0nAOre0UQlJsANZUVYK3kTvsaAeyutYOe2yPKO5uIX1578OyuAtZ4J8gSI9by9wUpLDS2kD6EmICx11H2eXKEfp6uZlvnNxBgFgf+5IrjrI9io0QPp4w6COXWCNvFd9COKdI4V8ARw3J6WXtwGzl4T6HlC7tgTosL1O78h8Xiw2HAs4zLzu6g3s/D0GvuKZ42voGWFR6FKklvHDMzGJJ8gmlmqSh4Pf0PpoXs45hNuaiTupdiVHdCx9VlULc0iMM0NuHTF/Px71sLWBkawiF3j+LEYTEYcWcZx789yBblM9novDAN6CiB11wH3ltlDRpSyejw1BqSWqOxY+JdnnHBHHuvdVKH1HpKbEin/0Jn0RhJUxDfOZpvTVKhs2s1MHY7gk1rP67XXABfXinBNV8iYRd7PnuF4LFWKts+98E5T47CfZv5bPywnxyt4ik5ayKWxIai+rdfNHeHKDStWYqrj+/DQidJ6vsszcUDP7hg3Eyyu5YINcsng07IBJo8fCSs8lGi8UbO+HiUMPpnvobhVRVgtX85aoTXgv2VC/xcux3XVBhArfwctnLahU9vXiHH4W1cmTwbHr3T540mMnR1ZS/Kiajh5uqpsA8vksR0XQydokrnt9mQyCMFGHnHDWofGtFNlXhwHP8ZKg9agKmLHRyVLWDVIkNwNq+lNOfVJPFpJXlLi5BYnSYMD6iAb/VSECp9BgwjHrFLRgHcvficsgMs4KrtXFq8XQ5br6zDmWvsKW2WJez9ZAbaaVvAWyoC6/TE6Y51Eux1ssKrK65za7QJGOrtxYsq+pBaNR6NOm/z+X3i6Nr8i/4unce2cImjkyvJ6oIYjOqawm2y+hA314+Dn9TiH1tXyA42w7V+pXQ0uB5PTldGSxlXyjrRCh9MxkCkVCxIe+QiCcVT4OX/OF32FF0KnoCyo1NA83ott6sjihwxgvhLmigy8RguCl7MC5KsOORYD2s1mdBc/5HgNk0Du73EsbpEDmRnxJBTz100P78Q3kv28InDE3GNLoBryTRePG8zdcTpwHsYAb8i9WBLsQvoPmVoEV7KC66e4bSMGnjw/jn0KqTzcmkjnppvDB9NbLFEI4O045Vh0cG3GFJxGhRlpanlfCxe+9UJKvOqOemlPoRnDmNHYxMqnyRGXmZnKKFmFhcYhrFq9ARwMjAl87BcevdIB3z7G8HeXodnPzDjsZXvueJDL5fKrwezRbs4aWAsnevSgHl1APsHb+Hiehfa73kdwzIP4dWBRLh85B1Mr7gFW7R66Hb9FYyrHQ7uWb/ANPYkqn9KxDXnSlFn7VJellmCq4IlaNmJN6CndYwfVQuBxsUj6Ll3Kn7ctw+ON9yk4PqbXPtWGkpT+/Hin7/sslybRO1GgTaooENyHi6X1KEt0d58xlkD4gvl8GhLATrKJ1D6uolwRt4cXHd2wAj7k6DweAN/U9rK2DAJV8XWUvZRa3pweSm0ru6hhg4VEKpqgrST9dSaJc/pPv9hwGItTGwwxKC55ayXVMzRlrch6M1U8Pvxh3PL59DRln9k9E+QNuwqhovT9tKmfy2oGFgD4xZM52OtY4CHB+B31y541JRAB7Miee+CKdBppQBq8gMQmTAbHm4w4Tuy0iB2Ix9eXF5M6WZjhu7MhwLM59D02a+p/MMC3HzvKTqk3uNjTWNg3pqbLDpXDw82f6CM7u2Ydi2fHv8VgpODdejJNfhvRA0K1ovDd6MGXPizn9uuC+JNWy9oC1xK88Y/4v6I42RzKJ0NxWtweosa7Gi7wwpjRtO3ZSWg9fwNpLYYQUGqOtZ3OMK3BZFMC03BK1EOhikbwJZXWVi8oo1ezj3OX+dl80B+IdQkCbH4wrX4n8heuuAnDROnzOIL16N51ZGj1BN3hc8pOqOlcyW1LP3HOZVB1FD4D//t0YewpXl8uM0Hltyx5PGz71CjZz5mt4qRvtZuyg5TR7/vOfTgpiKU+zXzki+l4JpYjdU5q6Fp/El4tzCREu+uAOg+jFO8trNclwm8dB+gO3IpOK6yGIweL0INkyFm+eVBd8JHQYznYoirWERpz0bAwa0lXLO5CJceW0Q7pV3x4NmF/NxqCpzJ6OM+l8O0wGQfVlhpwNVqGWyO9QPPYBsMH/+XtJvSOOBYI40+uZI2/kph8pem5TMFQDxtF8Yon8Jd1T2Um2IGmm0x/OXuJfIqnYLq3/uwYPZfvKAhD08NHsKZvstQeOoH6ZpOxrER8tTsyBSc/gp3jukGA/EsmmOvAtqxiynh0XfIir0Hg48ugrXyVA4Rek/ZDwpxXH4lvM8fSbaSQlC71Ro/zHiBizba4gdXC5Q+aMtRqYU4DYdhUZU0meabgcM+C9i9qRI7DgfQV48WEk0K5V71ar59fyFYrX+HM+/t4/6RH8DVYMhXN22lbzpPaYvsDjp+eQYtaz7OGT3h6LFkKY3q04TtN27hvQ1CcPHgSdCoeM4BCRG8yMOWb8XIgHnQWJT20kbv5OegfVgCPa+Mgj9TdPF4vwctVyqml8Oj+PTNs1A7bB6/9jPDpAtW2C4pyQEvjeDAlq9gE3SPQyvq+Nb0flxb6s+JfSYcoC0KyW9rqWTUGhwQngyq11LBxUcUAys0ef37dfho0ACM12Xw2AovMDC+By7yb+lsjBCMNhDge7v/Qtzhl3gq/A6JLJiOUttXYdXXKtqTM53LghxYKkgPxvzxgIW7iriiuJxfukRiwpn1GBkYTDlNdaxnFcmXFEfRgzEioNevR/9em4J3jCjuz1bDiAoTvqxmgfpKvtwQZEDSP8XYZrQSaKmOBOttz/CPUyosC9sHJ3ITKcr8F8o8S+Y1Dz/RLuEpFGUtCg4TB+HAktuQ3zQb4y5MBZM3Vlgy3hlPLa+CtJVesPVBOb6IHws21nZQEK0Grf6WVDZ2ObUUxqCMuw+VOmihpW4W5n+/CiZrjCH+XCeLbt5ExU/y8Mw2d+qzScXf2UIc6XCX9iiZo5fHVrg/3BDiFvnwzhQZeDLTku7Ki/NkmyKucztAvR8kcU+QBEw73o4LZinDlbAHtOGsH1w9jqSdu4laqv7if5mKoGwrxjv6LrPFm9ckPlwZXEyNoSJzBtX3uuHNm02s9K0KKkfos7CSEQVXfMM5ttK0+Zsq5BwQwd3bcqFvhxLPKyvA9gtzaF2ULkZKHaSMV5n0uU2brVkP/JeG0NW9+/CTexn4DySBSelymGh/i14Z5uBy64scdkeHDnwbBz8XzqXWbmlYscGZD2R9xlf31vPEmT9g2YATH43qhOKxk9lFTxJ8uyTpzMwcbFO/gBs9n8JruTe4zOcVxm+pRQl2RvfdmpgsNRqs8DcOSA3txhUDHre1AV3MLfjNxF0YFdWJhgYG+GP9DqgvNoH349/RK/9l6BUrwaWFyWSa9osuicwmqWURkHRykL6KDeMLjlpgwl1cJOBCcv/64bKsPF5fsI7STr3B1NAJ+NN7JZ+9W4qVRlMgWEYWmiVes+kFQf4WNIG+bInGfZt9hvw4jxslVsHw14IsOs4QXkndowvRL+lNlyrs7EzgDRanKVjtDQd1i8L2xZP4jlUipTmZgdULoNdlhnCrfy/qukSw77JT5L1mKU1UOAInd36mupx+6l4xDl6/L8JLb2ow5pAk5cv+INOLBVgXVME76yzI9+A9mG5ZA/9sheBJ8wq+WzkON6xO50MCW+GdoBH9aDOB7+FasCnxJ0bU1qHfawHQt9pOZ17cJSGRWOS6M2DS8Ifcjktw9oHlVHPQjL/cXMfCu+UgznAUCVdEU0ujNm07fwNbFl/iL13S1PZIBHu1X/F2xT80GGIKlYK1eHRZAFRcPwNvZ5fBnIum7LErlSSrB/C69To0cWmFHRmKMNVRimz+3KU17enYLHiacFAMQ12jGGdYQOvzDJpetg57m/Rgzlt10vryDmNjwvjJubsQ+ykOnc9uhrUN+2jd7EZ8HTqU01kAGV9FwdPvJF3MXwsrh7pqq/9kjHqvTKdftfFF6SLStnfh9GoBKDijCg6qrfB5z1IUa3TFHUp7+XPkS8iUuYJqD7vY/mwciitMgoKyRKQ7d7hA8TK3aClyWvEDeBUtQd+Funj0p80w5asFJI+eCNUuMdyjOQCK+Vto2Sx1PNFzgnb8mQFaQ92ncU0Cq6O84flkXZBsHw5WH/x4g1cm7ejQo1GJdnRuljI+v3QHN+mm0mDkLu58bwLJ4n2ER/X5yrdueDw7jUb0u+O5/T/x3sGNbGhZzypvavHNWU2Ypi+CkwMIZYV04MrKNThXZhml9juijGsVz/rhBy8DA+j7ralQ2FRP82Tn8ORvIdw58ye1zuii0sa9aBlcyFGfxoKjbyPghXFw/GkPN/rmwWutALrhIU/LmxN5ftI8mDfELvOC78CulGUcNKAPAfE7MEs/jh1UJoDqHF8wfbUDNc568+bjqlQqvZfk2y+ht4ERaGSbsdtbYXa7YQJKhx7QRPOnoKa6nZ2E42GYUyYefNGHMoOKMD5JEk6k2POFadOh7Y41azqnkP3p6bj6vQI13poMy8+/BXdVfRiu7IEvt/zjS98nIUxtx5aDKjDQFEuzo2bA1RYTWp56jvffVYfIUWKotViJu212gnvKFhi2f5B6qx6CeXgcav37hJH1JfBPQBfGL7jDcxcXUcthE2htLMLNe0ThU2oiTb4+Gg2OeKB4bxaI2IyC4s8OFHq9H/qrz0K3QiTlW/+CYeu/otKNLlh9OI22/TgPLToTIS4plF56qnP8s0T4/mMU+6idBlNNLw706oaA9Fq+rLwCfvwcB50W+Sh0yQJUUuaSWnU7+jz6y9a+HnjISx1MP5vw9NJM3NWnB+6Ncbw7uZzERlaifXYY6RpkcdgSZ6jtvcyv23+S/3ErWGepDPdtA8DU5yePMjEHrxJjiJx6hquOzSfjzK8UP00BXEYX0n/LrCHn5W8yychFqdNqJK50ibW8buKPP2I05+88Hr6jg3umuEDxUSU4YL2AN1X9goU7c2G6zSvSSaqC6LJ5XBq/nH9VS9MFAR/SttSCXRhOl0NW8tXUZ/y91BVe+oSD2bR2tHB0pl0PHlNChQWJLxWEYfXR7KgeRbaFDPKfzfDumKH9G/kf9VR64Z/3D/mfkwmODVQe6qs6Frw3DxWl3lJA2gDOqXqBZ/9cgaL2RfRodzqux90Yd0sMwtX1aeBwDMcX+ADozkS34ZMoD1r4xpB7XwkbhRGvT+KdUF3YPskBHnjl8P0lpyCoeRsb1ogzdsuiRaoICjz6j9c+XAILVYVh/jwliFtvRu53YzHjjgTuvbQE13oI0O+rlfT7ch2PSyuAq7kq8KPJDv6r0gGXJTV4A0fQ/Lxm1Bv2CfTOF7KflBT6flvDQYV6sEjuFHVP3sgpY81h1vGjZDbHmVav76ZG63Z8lHefl/oIs2LNZJhSfpZKxSTwIaTBjXtLqLseuaa1iJ+cjgGN00oQ9OctLt9hDnd6XVFOWhsshpvRbNUE/DhhFtf8DsQEkXccXeYEdi7V/OLnBLh6pQlUw2ZS7tgfIKA/Avc7pLHUcAfSd3lNigrSuPzjA1p7SAss18Xhp/GB4NEQw/2pJfzNJwzkSqowN72ElbNOY4KDF+kGIwysHk+ZvuIQOt0JNF9FwRzsInfV2Xw5cC386ivhr0ZncU7laHgYtZ4OS1Sjy08VPn2tmAV/15KLwga8+kOSi9JqwKA4mC9fl4aSF6PJuaWX/NwH+e2dWxhyMhTKZ2az6whfvF/+nXW3LuRzz/XgUGc7hISG0/MGKZRMkqLmdkH4+uI1zIr7QZ4Tsikp5gUICCsAVYez6b1XdMvXAK8ds+P2t9/Acn8P9vcHcXJrNUwp6ePPOcNg40Ft2F1lDvfalKhupgzIdmaij3EMrBL4CVfGW5LuyaVUKDQFTrl/ALtVqTjS9j4sNNzIj5558/2MNdAUqA0rlzii5plFdPvwOIho/0ynJ2jRM4tq7HRajIfgFWeEaLDaSD/wujgcjguupGWuYpBY94GPisXiJflG1Mnqw2ULAsA5XI7yL24jCS9T2Kh7lRNPCoPws1LSlPhBK6YEwKYvV7h3zURMzgnB6Qs8IU97BNbGttLm5ZrQt0gONk4PZP+oB9hT045HYggWvd/KMwy86VxhDDw4MR2UR6jBnWdbqW76Ca6Yr4zvL1SR78UrYO9wmNec3UIx2tU0Nnc5eJnKg/2eXqpY+Yf6ku/zgw4x6M5eTQljpvPp3QmQHF5HvL4GvLeKg8DLGTTljw+9nPwEfhn85MO3lKlf/hkdPFDJZRYV2CIkCfxtEoQ5bsa0VXl8R2yA59+bDHVVBaw4Zy4Vrh1F5lfd0X2MHXeqm0KDhR/fNjzGp2QEwHFKHRtdPQTxXy/y8EITas04Qe450XB3mjhskB4O3VltPOUqcvFjAfzBoqBYpIEi3pJ8uFUEFgRcgZyhfGn2fQbOzrk8tfkjTKy4jXBrA0T2u5FrgheGFznRg/enuP/KaHA8Npz3uYqipeVYLG5+Q9fO6UPpIS0U9PwEs+/LYPGLUhitPhnWuMTCSMkoTNTrItXaetZeMIk6IlbCiRhvzpT+y75THbha0BzExm1jj6FeaH8cDH363WT52YD3xh5C47cDEPU6nJ/Wr6QUb2nQ++LAZZtnk9Ly3/QeTtPitFD4z0OSXv5cBPWeSqCgPECJkmPh0JZ52PzAnR/9OoHWHYewosOeersn8obp3SgcZsc6SZfZ+/vQ3P0DFGgVAspWW1m3WQ62dNRjjc1bmCP6EXa+a8KmNRPQZJIOFMz7hJT0iJ2v5aHjqkAwLF5FV3994UMi29FW5RdeDtpE2Y4a8GfVC1515QQ2jfbhYwumwowRj7De+wc8rGqC/r176fOHY1zzSxPsrCdTU2ocnjAZy3cbQ3mVfSIdG8yH0AWpWByxAK2+NcGu2yOgoDkAxixzxmm530DedzUlDTvBjo8zYL3ADAyrAnJRNYAIg3GAbmvQdvYxDHJMhi/viqGx+hzK9IqCvWgE5wSPBP9dCzn9sQ5IbUmGO2OqwFzkJwwIPiJRsRaIyX6Jtk8eo8iOLSxUJ4LiR4UgtN6S3/3tAFVJIXRM2seuqx2oqyGdisyjSKbFn2oUEkmiwwCOTi8hO4hGx8r/KH3mL+iYp889ivMoYX0vr6ou4Flf7En+21jYgYexYsIqlLw1GvOOSFDis/kk4+OP3ncvo4so88iii9Aepg5+Zc9g8PVNyjSXgBkOpaTu6IvfN7/HFY9LSK9QlE/YHeIOYgh5Z4B/ztylb/6bUb77O/20XgnnrSNhzO5KiBCxgPY36ty0UBlW9o5Dz3nuHCwdTI+sFOhU4zletU8eLh6+T4ueLed9DqfQTmoy7LX5BR8OtULXVVeKHVPLQWeVIS3vLK15moRPG924yewChDpbwQcPCZTGazzLKYYMij248OVx+jJShwI394CoRxvPCG2HeH0j6LWL4U7BbWifao7rA49BqoMKB0R3865l4nQo1ojPmz1lNB8F6cqNcKGsBfYeScSa5vf8RPA7rTxWxmcdCodYaYC+HzgJqpkI+/Sf4Erb2zhHdCoHnDElvaQanj38PsFDRc6svchaPrtg/PDR8GZnLxpujsbp7afh4oRbcD5XBbW/4VDOatDSb67saW3Ob7P0QeVKHgr5zSInXTnurfLEdT/XgK3eAn5YksD7Zabx4QozOC0vBxm3DrH0AguEzDheMfUd9Xo4wPK606AjWs1KykbQPnc3XnuM8OfqX5iXJ4WiGWLU+PEmrGg8TkWVTRDjIYZpv7bx0rCVJPvXGlaeHAtTOrVBLkAZL5xX40kBxux5aT+tr6nkUrnDoPPUh+WfiIKFQRpVejbzfQVJ2iS2kIUbJVnLCrnHdSnGzu+DW50tdKFHACx/9ILbx7/Q5bwF6s9vALu9iRDZGgDn40vJ68MwnHL7PszN1oPuUY14ycQFC4u3sIx0Cy2uPsxWSyJpwyZn1E2TI33ZMjh5wQR635RQRWEZRc33pNdjTVDn0V/sGxQEq7szsODfJBCU94KC6aNBpsCXlCtEcFPHa942Wxw61sdh9rUETrSJ4wnlkVgmNhu9z0+CjR8z2bvtLqiK38PQkgWQvlsedtddR7HJZ8HIJpDutLty0aqp4JHay+JCZ7jVeRdOPJPO65eHwJRJp7E/EvHlw1+gG7idIxQV4OOuRZT7you89Bfh5jnrMfi2Jb8y2A1vEoQh6ewSOrt6N5TyKPAzaB5iQDdwWLYNFFLkgHZ/heCZE+G10W+YcHUyvrJcS+UhE+DtpImkW/6L/Ob40Y53sSQzWM6m72Lob1EQGTw6ChYJJmR+UxuWBy4D6ZX1bDPuITQc0aVMp1x6+MULopzXYOu3r+gt/xKfbDKBnStGkbuFK2w6+QXX1P/kpQZxmKQdCZuefqMxNnm43ESbZ+eJgFpwJ756fw0do/XxutYCqO5P5vPL83hEhC7Zhxbxx4eraaOsOoz0CMNpqlVQoGIFbd5bOGTSS7Z+tBQlrQbI/+d1znONxr9/jSDoRg/IbPGm3E1tYN1QRIP3jfGzcRffWzYXDian8fzdebi9QRSs9WWwa74nmhd44zXjXowQ2wVrrsXDLNkkGJl7mF/G9cKuEgn4EGqCfy6Gw+Wdv7G51I0EXymQaqwj3L05HCa+UwGTuCFHmycDnrIP4eGVD9jD8/nEvyP8QqMVk44D6F8N5Id2vzjiz0SIviAIFvskqO3LBFIzymHL30U8rGci2b1OgPmxFrj1shKcHDedsIhhmZ0BPr9QxaWLhdHJKwe+uJXiOF9fzBG6Tp8Fn+C/9xX4O0IEDC5ch4HzZiBqOALDTK/TmJ6v3Jr+G3/71nDGTC/evCuNxn9VBim9EPg7dzb3X5yMwal/ecHPh7S3JQYkbspRy8sW7Fp1nL3LpYHdrsFetY3YdlWOBL/3YczwZsp2uozJp4p4YWQkFbv5ovAmMRhh2sR+rk04p7QS/wt3ZD/Np7Rk3GOKOl8POSNKQTfsK4TdNQPt/ovU1vWC8+XkWXneKHbepYQjjR3xyY04ujDE96qp1nT8jCiMNArhzPYuNG4dxkqJ0zB0xi/cLKWIv+VW0Fv2JMUpV+lU8GRYaTiDtRpvUHxCDyZGf6Zng7EUK6SBrZ8Kwdu9h3bGB9NwW3PwP5FFsam2OG35D3rzRZHlX14d4rkCuqEyit8VetBVkVDWsRgHRfYjueTgVFQob8RAuAX1y5NxzuZrgEJKYDO9DV06YjA8Qx60NLfBoelD9z31E5weUwnjRQ3Y9FooNfkKYFnjfThUPoKNlZRB7NhmitcbD7MkTHmfMHOzoynsSPhG9zc/4dUj+2jZu3b8OFcJjqt74GPpKTw9z4N7IJluHnTD0zOcqb34MD+QmItWHZJgFCsNqhOMiexGwb20JD5n5E/D7sWw6w/mm/vnkZKXHWu8LKHtPhbgF5SGLV6e7GOai+tKxqKVwCM2lBmaeY4HlYu5g37s0F0qyYMXKtL3M50wda4AqX/vgczZO2nDmCr6XPQUZpXoYfg4QVQ9rQ4HPH7w0npt+jV5GZoWRHKRyR+KyrLgCcbpbJ3TjOuva/NbHREoVmplregYzlPowuEGUbR2tAFkJT3lL5pBrGKWTf8a79AfcUsYLDxBka8/DrnOfPzXYcsqvqY89+UxrI12Z7UdD0By2zb89EQGUme+ANVXzEfP7qPlmarw8eRaLj56AQxUkMSsisjpbRfEK+vD/rODOFFAgC2npcL5lGHcUzSI9xe8xpyuAND/t5llo7pZ9ak43LMMhG3BZby7QwboyQfafyGT1otOxqkr5lPpv8nk57+DJr2ThPqUGRhkHonVXrk4fEMJr/jaSTHhXhAmXkQnWk9g9IxYVv0OsKu8HcbEOoHWUP+9HNVAovuVsP9QAF8IOA1OD4HUh95euEgMdqdtIZcBN+zND8PRHYHg7qUJvXX76Ob5buo//IpDtwlxzRRhsNu+FU7m2HPGP1HW1q8l3SkdPFvMFdY463CYZyGmnh+EC6fGw0KPDtq+IoSUqo6Sm8IbSIwdxkLFf/mR5B9+ov4L3JbEs07tCHAnS3IZ74nOvr4wX2QeHJxEYJosCO8uzuQXmT9hZFYKvP0mA589kvhq2yH6nf8THCMk0D8mAR5OPsfi3rfo9gZL3hI1kVTXGIP10Ju5wi/pVp4EnfArAp+EPVirVc4vWo/hp9QJvD/RFsKnqYOQzR2sGbmS/eKngF5tGa1euA1SYvrR0HERBKXPgMxtmjxbSwbc7o3EBINW3PFqC3hf8uK/eV953w55ni9mhl8uT6ZeSUNqj1SH1BsVIDtpLSfuvkNHa9poU7wqRjwVw76C/7BYS40+/XsFH04Jwdv4GDz39iI8bvODiBVHSTD1H2V9FuDKde+w+ccGXOtvTErWQrBZsor/VC+mX+O2w5yN+ZRh2E0it5ph3pV9cC3mOqnpf4fg46KwxC2G9RLN4Jh1J5m9+Yk1zlm0rTwDvnxRB+Oq3bg9aTxkbFWEXOnZYBGwBcuuJ9MI4TZGrwsg7NTBj55/YIv7iugXJU5CCWbw5W00ac2Kosb9OiyqVcOehcHUG/oQ3G6q4c6NE7CiaSlcjpoA31pfwphbp2FdUxO9MNtIpnO+QeOkm7TwnQWM1M2F2WyJeqQ4tOtidOPNIwxoEMa8127gf8GJlaLaed7vXFp4XYtsRKuhTUgaerq9UURUGrQL/4NDmjXwytAY8n6U0ka/NMhcYMIX5S/DOXMNaHQ4SyMcb0DqNhsW7mql6tpXuMvYguInjKeqjKU4pXsKP08ygsBP/wH9VwpBxm8pYKcFzd81ClQHX6BE0iD67NbksODTcOGhKXgubOTts1TgokYDJ8w1hB+lE/lqTx7OUTvBQt7PSC3rKM2YOwmeOKyAv8v20NuAsRh2oJFGrSxnLxsvjizdjIfkVLH30m++pCEMfnt+8NVBb4idbMdLwhdS8Fc7qp6oTH3ro2l0wTEyvfaAx3kag/ssJZSwM0PrgQPs/msKyP9Shh2zKuncQle4MSeJvQ3X8DFXQxBWfs3PFX1Q/E0gWs7SQZe1OcBB2fzvzitKMBWnF+cNaTAMIffbe7AbY4C7nrTRs3Xjse/pYhjsG+rY5RfR/U0CH7EVIvcsAuk9weBcnQ0f3W6z8zIzGLB3JLofBR8aFhIaOkHO9LM8XdYEyiy6KNBiOGdedmNZK23cfPkjPqPhsPDxMbpxXhPVT4jxvd8KYC3lCnHTXkEHRdML9yL2vhaF8klRMDNSlndM+kyGyqc4fgjDy5TOsIO+BMqse0YZUpsxLfsQ//22GK49LUCjHXtY1eM3OERPgCLNHXxdURpf2Fbw97B8OqnjRBWj0ml+nwz6rctk7bxgivxDkD7vCDd2LaW7OJPmX/iHK8U+wpi18rw0eC6KBXSB0tIPLJUhBK4XXTF+xhi4X7SCrgcM0JNLm2FiqzvJXu2nIzZ1dMRDlkrzJoCNzls4d+M1Pi+WBLMvM3nq0s1okb0LQwpbKeiFNU8+N5GGl1vC/Xakb/dmkoCXAZatfU7H3c04Id2eq94tgWPecTj5cw/MiR0N8auDYWvqJ/hypAyHxe7jlWMkYH18OTZpSaN19lCHixwn91YlOB0hS/9dfYF+IZH0b8CddcN3Qb1rBT2V/oKmL/LB9UQbc74W7F6lAcMWbiZ3HVeeewYoyD0GHNMnQoRXJda8/YmPtd7zC2N5GC9cxyqTYvnB842UdVQVVyu3YmxgDumXLQOFsJ0Q0zCFzwibgbWBD3zYqUH5dmXwV2gD++3wgJMV2hh7xROvp8zHt21H8GmiIli2jsc9S6LwmHEGLj7xDvc5nUUBVzN41P+bPOzTwH/SeVhmoAqbzlXzKKk2cvh+nQOeypCgtwkqiuyD27t9MNXqMEobi0GQpR5ELD1Ib8slYaDXg9Ys/cH3XEv5mUEXqlctIskl7+GS43HaeGwiaJ7aTkWztMDLQx5Oarmg36UjJLJWA++KhqH79nDQrRbnovkAz4fdgNsHtcF2zjbIWRQEdmn3eckaa6pTdQC7UVdY+FYAyu2TBl95GTh9dgKW58WCltQ7pLRtIBOsQ893PUC7SneYanmZxilqQ/aB+Xjd+ymPWvwZxU6/RrtbQXzh6AAIWDmjSlIgKNi9x+8mRjBTbhglFc/ExoLXHC37EMsqd+HYIQbQmBZK3nsMKOzxS1SwUYPav/9g/c8NsKfTksetkuUzn/N4xclDNKz/Cfb8vEy3m47RtiOC8N2pg6RufURf+QxS/HaJjQfrec6Q86TqI9dNGw7q1zbiVkU5iL68gvxyisClPRysSyVxkmkCpu7Q4V2Fg9TZ/4TXPZJkh3IjcAo15vjO3/hK/zlOUt2IxsG2+HGEBKi8Qby9pRir4gUoeqUyxK/5D/ZEdkLvEmcIjZqCIcYCGHrRnw9vi8fByOX81sKcf9tMghVoxQ/kL+OHVdtYKl2Sbs/4CXuPFXGfyiT8e/4hXEU/Sssxg5EDx8hF6B4PHu+mth81mD/xEG9zncJhz1tobPZKPLE3lVbUqcNGgUy+I98GY+MqMbl0GMqEXEeHsHLuFaiFqp3beLR9G7tkysN/MZ5UkDkPNl0KAomCOrop9xm3+Ddg7aapPFregi+VvsCUXFX4HZpD61su4LUb+8nLtwrnVLmxpYIbOLWFkeJiUdqxLho8UqaCiJYxWXy8DQJzmmDzP18osXFEw9l3UcumENWSKnHLiCfwfqsahNnWkneSAyX+W4tb3aVpmpoAPPh6jmU1Bam9fQdkDY7ihkBjGGdgS0FHlFFs3DH4oSTPLG3HXweLcf/DOLpb0cdLnB1J5O1U0BIo5gsmijx303PcsUoeI+sW4726erzXEUpRwlGwzfI/MNcZBnOml+Lh8wOYpFOCVUoirFJ+BDZVO8PCFdksJz4Wfus44R5JeZgf58tvNC7ynrOD1LMHsaYqnITXZsGbele+pvMaNFQzybLKFB5Jr6CZd2+S893FfL13N8SJz6fiwqvoP5APH6/WoM8GW96/UBSexryl77Om0ZLZ8uC8WYthdgPdPUNgfK8Vq8Y6gkpqKHzYbAB3Oi1Q7r4xf4v/Bw6tn2Cv5mnqn/sPAserksLHs5Rp/gUvpI+HHaNmsJzlanz1dzWo7i6FCulX2LXrN7sbEx5dMp+/rmuBadNGQOD2WCh89Zhzu+Zw/twu2G6ph982PMHvY1zgkNZ1ktFYzCleciB8YhaF7NFBz5/B+PLQL7hp9hGubIxlnT9lqLagDgbEvclxiSSs3jqOpr3qxIPYTmoVl+n53vlQ5vyFY7MNSLDqCpyqmAEH6wAaFdpJtauZViXWcs+HZvT7wQjv/ODMortcnR8Fk6/t42otI/gU+Auf35uPVzSFcXfSZdz/WAb01a/z5MvloHgqHfyuirHHcS3o8vpJe5WtOf+wH7kO+qGufTKcchvNETOewNRPRRhqcRQt5cxgwYeN/GydCrd0CkBbqwDM+lmB99Uvgkq9Ilk+9eLOYE/6fN4KthTY0sVFniQcq4JV9cQi84v5o5crr7mlwymvqnHM+0TQHCUL62btJKV3CzljrS0qNl+h3jOWsGXGR6y8+QQ65gezymgdrtg4GnQHdgOfnMghX5vheogHfSi7Tr8Fk2hqUCIt+vycP+pG06q1KvC86wa0PQnDoqF+uvlyExxcPpVXqNxE95ltYKcuwikufTDrsTy0+rrSaRF9GtYYB1PzTFnVLRaaRj3FiyaOMO7DdxAV7aMDGVLwOGA+yCxRpD3rCQKOTcWbz+JRZbQTPveQJ3ExhlVVa/jxaE0weh7Ks78sBYu1l3Dco/H4fuZO6iq+C973M/CppBP3tL3G0bmjYH91MBlmfsYvq7ZCRXUqPlFQ5wdtX1H/TAEcmJBNdG0+huwXgDrfjej8JBKEvAJwotMK+qmD9DK6Bks93MCjaxoeGF3Hl7wEYVv9XNweMBPvhxSis6UbSs0oZd/yRFDufkI3gzRBV3MfXP6GcGzTMTr59BMvmn2KvKd/JZHT5+lGzznsjNhGpruW0JdiUVqfCbBB+Q0nO5fQw7V9+CTnLeU2LKBjmakolLaV1765DVnr0qj9rBD0ahhw2j47jLuiwcMWxLPtdC0YY9hFJWd2cJbGCZYwV6NfZfrQmVOHRV7hUNGbQQMCu+n1iEiyXN9K3cNDwUa9kaumvOd9kfpg/dyW9sopsuHKTeyhM4ufRf/CNhtD/qRYgFKFz3FJYyWJeGrBr6/uRMFj2aYhFcWXzxziQRFo7lrNta1naJ1EGJc+WUf+Iw3hBNxntRu7+aKNDx6e2gRNdfcARfzRzjaOXXst8Zp+CgzrFoGXLydTbd8AvJ/qj4KZivBlthft+1DMNb/iOFI4nTJXX8b6cVNgRzNR1apg/BYgDUppzOFH5pHIwmfoUecHAaccYVfhUfi9SQd08sfw8zYHlhuFfGFRFPotsufnzqcp7vMBUKouIUX3I7R6sRXcOjiT6zKC8cCQL53ZaEyWybn44NdwVjp/mB7oPcfqvz/w6R1dULOIoOv6N7j3w1KS6vmFJ4aFkbfWQ/hbMIqe7vfjPqHVqJUwHhYP+w/Xrx+OGT8+U8rMTbBhdRXoyuRz25oRnPZHjs+HuMPhYdrQQmXYmeIFYs7GGBf9lYpZnYXMeyAlLp6DVRs5u28rHQ8ZBT5OWbRcIBsC352D1VYGdMnWhw4uHsl5jXNJ1D8WjzXU8fOd5rB/w1jOu6YOIl/3wG/bGk78+B8VlYWxuMZ1eNgRxrc1HeinrTG4dIbCyjxrOnLtLs5KecXr/1lji9RS+njpPs31eE9bfX14rYwgWH7fw8flXKl+UAdud2uA1jeAE7cVseLcW9S9fQSU06/Amy49qPstjWu317Lm9S844r9PTC5aaJ5UgysghT4+f4i27W9h06fR4Duigx2W6NG75BLsEtmHNqNrcPEbbczpysEDjUtR9s46zhVTAt8HPbiPxLFl3XqaXRgBDWuUeMT+RRj1Ixf2z5Oln1rlpOVkBG4jF3L38jN4YVIASi3UIPP4UnoqtIiSfh8mrrwDW9YkskCWLkjK21GmkS+2nziDg3mh8Hz1evz+9CHuvbmdtE+b4pZxV9CzVxEqVMPgc5sgVT1Pxxv25WCTUkLB9U64N3oln89ZiYGCk3BMzFgI1v3ChnnzwPWSKDu+sIaSSXdoxXNBHGjQwmv2pTQz2wg2W0nAuSBBmGPXToscAynvZCxsVRfCqR8vYvHSlfTliRhVRuRRQ4o+/HsRzPNWixC5XsXt/nm4WuUhCY6JwODY/Zj6zgkKSudA30ElmF2yDNYdPwdZ8S0k5reGXwm/wkcGG3BJgiH/jtKF/xxvoeYSQRBNbuOlU7roabQG+jqvJbfpAXx96TSWl73PG8cL0P3TyejePRGueIaQ46S7GJ0mQkt+vmGJ+ZoQsqEd6xQDaNjvRvzhoo0D20zgwiILMFWeja5/O3FDWDDs3HOWTT6Fk4y+D9dfXc+T20/x2imTIXtrDrj6T+PdaZ58/bMOawlc5p7M/3F0nnEh/l8fPyMtVLT3XhoaSloSESEiTaMhfpUiSYuMqCiJQqEhe0eR3bA1yIpIS5E0kOzu/vfD68n1va7z+p7Peb8fnXf05tFj7vu6iiWOy7M2yUC63isIDNhFkrdv4sHHrngweD5LrD0MxcFKWPpzNM9qH8tnrLUgev81Hi+Yx2rHdkKrqB8+i6zG1Tkh2HdyIxQIz6XNy9fyDENBqIKHFO/vyK1hkTzG4Sh+bFJFY+17ZBu5GcdXqFPGBTd8MXY8TNOay9OH7prDFHOSK6zCdr9tdOj9MH67+jqFey+Hh9bW/HVACnomCSD7zKHch2Mwo7uMRC+m0uuHztwkcY91gwJAvUmGrcqF4FTRVT7kLM6O2tPoJe8D5+5TWL16yBdNArD6nRqE/zXnaVFW4DvkC5u9r6PHx4808tUcblMMoVX7SyCj/RRd73SikrwttL1GDaSNgknaxZeqYglLOkO436OUZzxt5ZVHBzjh8QJWvH2Vi5oIWgQ/ELtsx9yDS6ll9S9sUfUAizXWvNtYm446R4LclkAIcRwJca/HU6eELniEnie96Fb2Hm4Hjsbf4M+un3iqORmfX3yIPuf1IfDMAF3fsIpnL9jFz+gcrds2kQ+o7eITb6Oousifb8TvY8U1MuC14yUsFdgFPSXFJNZkTeXbzXhVlgOJdirjL1M1UDgvgNleAFuOPgDPjDTS903iXSPuQuB8T9yk4QNH0gf559aZmPfhIvaeMIbMpGq65KhHTv1nueGTLSTu8AC9zoXge3UOj40Xh/cjXOiagDEsXLsDUiKcYZPYZZz6swWWf7dE80ezcfK9rfzkyk8wcz9Kw3crwcJwR1i0qpu996dxvaoHyw6bSVFJh2HFtq2wV66GrWYsgU8rJsLRURkQcDEGo63eobvKbmhN+4Xv09+xk/sdPLi8kMQn/kcfayQh56goiZxLxN8K/Xx16xbW6z+CfZqHWaR0OOlduUJztl1l9fvq0Ogsi2ZSrVhrmAYmHSOoWECfsu4+hVe7UrgKJnKm53KQeDUOlqwaQHzlzDNveXNliSPJ7QyHJX8m4WrtzcRJ86FReitIHzUc8twWbJrdSCNcrwMfuQWPzVdg8dZ4GG3zk2ovdWCby1k2CtKD/W8XwP7Je3Df6UdULXqPHUKfY4VVKTgXj4CTjvWsEqUIFe1icPBbMVyYuA1C/nrib2FTqhjlCEETXvGVrxX0JieL9+AuLm80g6fqp9BlfS99qFJB3zAZbNTdCE+PLILkAcLo2a/5xbWbdOecPsTMuUwbjLsxvyKCtn7PRus6O+r9tQVf5i6hZ7NH0xz9DewiNQw2FfTDFimgJ0mp3Dwygc4OU6GjuyZD3HMntPmTPcT+UXxWbgRclr/HU/sWkM3fw7huaRv9mdEMA2GlaBTQTQllo3mHiD15JSjAzhkWnDztDJ2bXM7cuIKOVXwD1XsXyV0jEE96rCb1L/NwjBzBt18GfCXLjIXuDXGl+0QQGpHAx5/UQFwgssSmNdy3WRbPDnFi4RxtzJErZbfsKtC6pI0OO85Ck8kJWnVChzTmrsKQxCU4XMkUJptfxKRoWX6odAuuPA/nnAxh7vF6CmM2zEVt72sU2JwNEvIMN370UkTdEfZ/ncbRRX/wRWAivPsWAu/7wvnA7Sbw+qqNepEqMOZvGLn1O3D//d+8cVId53qI0KPdnXT+8mGes7sLxY/fZVErQUj4psrlvmYkvqWf7xZswpna6mC1wApEG/7gsLvN/EljMSg1qEOMgjC7nb4ILj2jyGGnO3wf4oLluIQH7qTgksklfMx9K9sP+dt1h2RIPviKDQ/+5sjltyj58HNuvqKDC19eQm1rwMsLLvDF19bgffYplLo8QoccIoGQJg53sQN1kIKuxWtwwi4/6Au5RStXqsK0I+8oe81KnBcvz44/x1FkpSQk+pXTadEOFEzezfGmKaCroArqAfX0IaYYLR7NgCAtSXq6eRS4yewF7ZbZtG6tBT+584eMewE8pl0gqac/0BglQaqoBeQaNsK9jqNo/94CCkRf8+sJNnwzWRt0e+vJ0U4bEoz9IbxnOZZNz6fEkDTaUPCL9mX5sPCzOprXag2fvasoMz8FfXpl2S76Pcjt3MCw6QH8++mCH/324WX9MLYwHg3Q5w1C38zpRGEBueFK6lnyghep7OPOxELuXK2MMwN2c9sGM1Bu8mAn2QWQVL4R2xfKUsAWH7BZDLRWV59PV2dybKAO9R+wgbnJv/FG0XFQOb6MzXLGUMlvEe7piaHtoMyOstn0cNECevtPC3ZI3yLH1/th+8V3PCzBFMk2CXzXBuPNhSLceHwstv3nCk6HxkDthTK8N28Jr67sYPHLO2HWZXF6ndiPjWtaOUvWBuaxNAbkWUC5Zjy9krTE1dc30endgxzz6hd4rugmyXJ1FB99DH1DH/Co+ZbQoNhJnuknWJ8aYGJFOWPXKXw+tZDWZiXD0+/h+Fuxl7yGq8FaMwcKiRnkje8lwXj/aSi5oMMfN44jq+kfyWPmBRRokIbnkyzBabAODBIX4OfIILz3toD/9cwCa98KKJG4htEbijDSajtGlMpBuHQNbZpuxsqZtXhbZya62HVz0LlQuvawHSRbg9BK4ihJuUlAw1hjTrtfyuOEp1GEhj/suv6ZpWZo8fdzrlgx+h77m++Dvc/GgraKD4l6qpFhchHuEPCkCcPWQf7dG3DAOh2WpFbDrHdrqHClNWifcObdx0Vob/ZqaNz6gUxHrsOlRtb43+UilDJv44mPw6D2CMGXrGgIc3Ggzs/JpDdfAR4Gj6GGKe4UemYKRKxK5luVCrAiSRYSK3egW1g7XTI6BuudOrFVx4ntpYLooZkNHvj7ifdq+eObd2bwr24FXLy2mE5pbMGd67Up+sdBaJLpg/rFU2mqmie4/+1ig9Oa8EazAQOPr+YmTQFU4pt0SPQXpDwPpKlbO7k6dzQd3lYN23Ms4W3dRdjVawwloytYY4iLxS6IoZqOINdXFvJ4lzAUXyOEJoOS4CXaSZ/Sz1L9sQ7an6LEr5q2wmRFQw4XPIyHt44AeYdRtH3cGGgJkYfxKXF84EUDx/ciNNaa0jvZOoqqyIalVaZoO3sOjJ9qBFw4xA0JaqimqErc94Hm7f7JBY06+OJLJxyXcOJN9Za8ylofrPd8hPKLG3mzZTY8kgUYuTwJlCNSIfjhE1h5q4AyUmMgu8oc5LtCUb3sL061aucd2bNhddUV3CWVT696+ki3yBEuj2So2CMCLYm7OUlcilLsnpPV49WcgD/hZ/Yo3LhzO5lvleOLZXvp2jNdiL4eg5Iy5SRynKm4fBNOks2Gdod+dA6PQakZ0/ldfRTPlRSDsA41Gq/uRMumlHCf417+c9wIn16egsfHufKauPk04oAvW5ZMhGs5gvx86nlIm7wfnwts4Qez8oFwEbZHC+JCHI0SI2N5//ZRcGW8DwT6mdKIq1pcdcQSt+5rJ4XSBAoosEWXURakn36f604qw4F4BtHgZzAQNA22/30C2eJNlPVnIYgUL4Q0iQ4Y3FfEV2NHwd4gbZr6Ixdo+AeWjtAFcT8helTpDYa73sC5o/f4jYsz/pg+ATLKl3B0Uzq8PT0AdY/voKpjF58848Fmr+3IJX6QSux6iZRFYM743ajdiyw/yYInSIwiiRFaXN0hzFcbcqDa5B55yxbTEisZOKo1DKIlh+MEzzBOaLUE64ElOOxaAfuqIn6c+xJSUBz6xfTAxuQg6D8NJ+lZy8HGvoi0Zm2BY9VmOCH3PNYY/odCTqqQsFEYarfOwlC9x6z6Bnhzvyw73NoImmfL+ZbkBXyUKIZ2chZ4z8cSyoQMcHamE+P0A6iVpItPy8J5RuZ6mFeoyuNF2/Du313wrM0MajOHccN/qfjibg6/N1RE+98K9DncCeNOt7JyUxn0ON/AT1elQNnEnAfbnNFuRhtE75zJrsni+HmbE017pMef1Ifj/YYsqKk0gW9SnuBifQO6AuWY0mbCIv3XpHIoGwUiTvGyIW9tHbETVi6RhI7WUhp/3pQTZ1eg8mNCeyclvKJzGbt+GcOKvgf84UcAzk0yBVSdhtGNjylp/0IuiWzmU02N8GK8MdhDPRZOGEdKYq8o8601/LNeDXGdx9m45hbKzO2DH0cG6JjSMlSd7EPeWYlQnnAIVj40BrtQL945oIPXb7xC5ZKh/3L2oKl3+nBCggh+OzIJQh7+4WGbR4PicHd+fP8tJyRboZNkDoxz+wP/5E+jVMod7m3rZpkL02j+V1OYKHuCT+5UwcWrY0F4uRsaDBRC7a25tGjsP7wAj2lDymIao8PwW7cOFyYMA5WT72FNWS50fNgJr0fMJpnKJJYcsRz3VaSQpaEuOBgoU8sdI361wIw6LiSjSpAl/JCahCZTBdg26Sb3v63B5zZK8KNPCjaZu8CrmTfYcWwvmvtPYn/jWVC2TwqOrnbgmb5v6dNDK/gz7C575lrBxyeq9FD/Arx+dZsUj53Dz1fusOb6Wbi+OIutx1rBqgoEySvR3OHwAj0XNvPngi4oe7qTF4rpo+UkdTKMX845xnLwaqQXfCpTxXOZ5/l670YseXcMp0e0wK8saYL9VzHsZAGdLJKCgauXKSS3kYwPheDOSAVaUdJLVTctqDfaiA3SXchpVDgr6wKcTR+LT8lqyA2Z3maVs0+QHMQ++kBi+c9AeFE4+qYMB/GD+jC4NABNT8dB5NHZJCGSi60PP8Otxnh2SvuBH4vMyTkvnOonCECDoD5O7fTDQ6bykJcjx9bCxB63RYYc6xApJgjz2bzTuHedHjTaA7zdGIC3PqXiucdHeXGxMl5bLA56c7xgkXIU27x+SJG3hEGw2I4OnjOGgutLOC5kNzgLSWLYYy+QSJ+FFfe1UOruCTqvJQpNldLkmbwHm6pO4FeFBLqU2Quukdfo8EIFkjn9FZ20vaEz3RZuv3aED2NmQNyjcFJ7NokL6Tv5Fbain9oByt8kzZILHrG5ji7oOojx39BSSvQ14meGglhzcymEfF6Hx++Zo/PvaTTx2Gd8Wi4Ad91q4dDU66DmcQqeTnImt08zIblDn91vqsJN+1QcJv0N5f8Yg1+5IAq8GeT4+b85seUYd0YYk91SE0q9Kg3JEIT1Jl/JWcsOdoZvx5Jny2BppTilZxdzkkwoyuY/IW/RsSTs34GT/Yzo+wJ5uKo1HgRHr+F/x+N4mbEIxI9bDEmDlpgsfIrTVgvAX/dEjBWzhwsH9tD17T8hPyQRS0qf4o2JLtRxMRo0VutBQJYdfHKP5B1f9cDngh75eLyg+6NKSbqnE15PF4FVm9Oh9NMdVhVwobMSMfRMzxK8WpRQVkQSrpUYg0z5VZ6QdJAOn3oFGRRBV2yr+OCKr5R/WhIOri2EgYRvbD5Ut+tGKWh57j/WnmsKU55qg4SYCyvgTrYbORLkDgvxL+GR3Fn7B1ZZytKXrGVYmiFJIOVCF01H0E6B8qHMsIf2z3shyC+Rt7+fwmstZtCyGy4wek8UD6zPY+Nve/iPdxbPNjaGRmtNjvrmiZu/uUJHmO0QV++iR8dj0cTsCi2cXwPJy5fikkPG4HDoNFTLh1LEgAP0V/rR2BnRMKrhGVqOLxpyzwj6WnUKy8TkIWNwHPuuekCXhnWTUIE07tt8mb9ZXoO8h15Ydvoillr2waNRRhB42xwHZwlBjbs0S4THw9qZTvz9qgNWr74Gh32EwHrXVX6wHuBPaByccrjPc91y6fi7IrIYVYf9Nyqh8spd1i4cSwU249gxWwKeegnBiQd32LXoCYw2+IIdL5Oxr7GZPiaWcZDFMi6YOgUvLRaEyIAyujsii3RzD5PTgXvUcX0ZPvp8HV84tMDuT/mAm5wpxUcEQitzqeiiNdZ7asKpr5rwaZ0UjLqxl+/VC1PXqYfgrJnGXnpS0JtbRHfNdXlGxmd+cPAota4h2Dg1hfd8t6PSGn3ctzofS5aaw7bfJbBm5VrMeKUE7578hbob1nTT4AGauC4hhytRaPCsmMUiJOGWtyRqzItjLTcLmCuhzduObmafY8v4lsFYnG8UhHqFU/j5fkGY1DIKO6Zv4alecaAXsgtF59/GL5ff05qL2ezj8Aqyb8bATrCFb1OrsOoSEr+ahjoRMbj8F0OG01ySU5DCG+cJSj40oYg+wZPzl7ghQ4P9fq/gZa3i6PBjK6l1z4R9g0qUYmoN8CGX5qRbgNcuoLLoFP77qJy+zbqMMmcOEi84g5fc9kDkp2FwMHMKvJqkAj11R/GmiT77uFjT7aDDuEL3EPftUqdTsxppfLArLrdXojW7ZCFCMhPNw3po6uxTQGa24DQpgarJGme7F7L13wTqfuvKe/NlYUPXGX6oYk+HLd+TpF4uTXhpxMc3vYF7I3+jr2MBRtfMwBsfBWGrtBq1PzKAGjIFmw9esNwnB7SSZoPl3Se47M1PVDKLwuG3BKFHMgDcBBvRamQofZPOZ1edVWCUlMwhFYIUk1FCC+oIT44Wg7oD7+nLvGp4YPALdt8+AnlZi0E1XQAym8VhvEcdzuk8jfdHDXnFz9XwQauYpIM+8Nz2IcecKDzU60H831wZarVXo8qC6/zlkChoVI6gqRFfyLdMlIv2LqGZ8qJQ+vYd/JOpgL+penzY9BpeWGkIy8ROgec8L7rvf5uPtkizkFYT5UyfwFJ1R3iJ9CT8U72CauZKQ9kTdzpjEoavemRgmbrE/3qYkiU7cbbUQgib6UO+MsFw2tgA1EJnwsjrc7h79H6oOb4epwRHoERwNVr8945Pjs7BhZMCYVYswGjVDBqmpwbGwjJ448Ek2hBymz/QIdq8PBjuJWSAeYwpytxVB/VDukPPs3HakS98JW0Vyp2vwoobyXyz0IG+HtzAOrmWuOu5Ftw+soUlNunD/c9acFloGd4p7gGdpG80qy2eN4iosI1CLZ8hS3i5cDSLiDfgxDX59LSeCUcT7lmtDVI+C8h7jwiPf6PKJnk28I1ewWmRKnzy2wZHL7yM/9Ja+K6RGAb4jobDv7+wfsJo1j8hCRmu12jTo0KIVXhD35a2QWrmfGr9GYHul3ohS9Oa3ER84elHXTjcvxbG7PwHmwXGUWPBXThgN4bH5XWyoOkmjqVvsOBFBg8sGAttFzLZ1y8B/fZYQtN3Z5yppsyhNQfIfm8N6CcMh/yodNh+nuHD2qPYft8UgtqOscgRZx7e/BzV5IxpQFyDffbewOcH56PhOBmoZg9c/uckqm1IwaVnvoHCmiryW/2FXh6t441FAWh2bhZmqinDhHpvcp28BCWOVZLrGkXw/6xOXYOj8Oe3dmpMCoUGCUE8pmYGcZU3+Et6C7Wn6TCtjqEkMXdaa7KevEce4Q7RiXj+wmjsfTgK3tdmoPGKI2h8sZJa29tp+eI8uqnQQbpCiH+CWsFtcDPG3LIDq9LXUJTxnBZceoBzgqfT3n4T2Hu3HnY5qfG/TZk488krSLRk6DufDzUhLylh4Vf+8WjIJ4LPwzDNSzwi5BfWufeQs2oOvJsmAC6p82FYXQZGj73EXyW9wcY2EBTcL4LMBSlakvMFg9ZuoY0oCGma49Hxui73zk1Dm/l1tN7iHYVqP+X9VZNw7GARlpd1U4n1cNiuso6O6Tnj/t4y3vzUCuwCOlD5SAxFywVSyvZYWuyXAf0DluD7Qoefiy6Dc3tf87NHghh3LA6KxmXgPUVzvPd+GdtcS4HmG5IgrOiEIhNzeOmHBewWaYQN3o9gY89CPjm8B1R/OVD9/vVo+UMBDsiGg9ZzDYhsiYQ5XlNZTec/6hmQ5ifmEqg8bz4c2KNFS9cZwslnMWC3fSlO/RnLWyaspvnjDci23IoXPTgHMqlR7N12i3uOWcCze7ZsPVMCFp2tRg3H4/Ri0BjTNp9Au03bUPvEa6xQ66P1tXaQqCsKPeLzaHpFDXnuysYOmYXUa6aHrRXl/O6kMR3akkURkbKgZbybdjivpKIrLyD8ZxdmC1xi8YZ+Rs0tfPy1EAyObCdrKTlYNUwbDB548WJXKdjLsSDx+hqtDUuErPomTp7uCWany3Bqqgms+vQFyvaOxWJRB5KYfYYWil6jyEB5PJHmA3W5v5EDnpLZXwNQWfwQKyytIL9pH7btdaezpV/5870QGvFxKD88M7ne4wJGvZWH9t0qrDVZlQQyOthZaRQ/ymmhbx4nKLTRC/YLpIJsugxfPCkNxpI3UHjTMJS/J0dJLsFkZGtNy2ccA8+kG6wRVYGdfutgT60tGOcosKSyExw9YUOLyj5DXZoS0oPTfF/Fn7OthPDduqc0+YMJ+Fu6scSopVRfVkuiBbFQ+6ecOibMg72rj7FCawDXVf3h3hIRWGs1gf8e8GCd3m5yaFeCBClXxP/SuGhEFmqkapLz8r3Q4SUC5d+yeNM/cegsnQDljz+w+7QdUOxtx4OSqRR0Yh/8zrqLS/5JQ9yE6RiHF3jmBF/qPS0NK/y8eO35XAzK7ubJw67RuoQ6kI8kuD8zlE5JX+P28f78/OYOaswqp/s5v+j3hzl85L8m3PvsPZsJisGMv3MxNQ5IOXga/jsiAx+WxNPCwQDybU0i0R+nQe7aA3izXweOT78P02RH41j/Y+RZWwI0bhu1C+cPZbEIbxVT5v/mC9H2CQiXVyRxmEgNa254CyeUo8muLY88vEQhTFGYOsXe8J6Vj6iiQh8mNI2kigca2NZoxO/KV6Jp9TnEllw4vfgBKOSU4brCWhiZbQ2XDhqR27lYft90iDqjJpC0423MSzHiyDupXHush/JLZ4CjjgYI6afytvYSiE2bDZu8GzD3lDW8MCzgEo9syPP8CF89hEn3lwQ8LlkFXR/X06xoW2zZMxWKnoWzvqQ7lYleoMwFs8A1qIVVbojDnL/mdF5kAUb/uoCB4no089pcLtlVDeNO3STbGVp44fxjWKCsBlleprSRBqjW6zyN1XMEBaMkPPXtMh0LuQhBKpVQdkOczd+KwKcHe7lFOh//Ra+Buu2bUM9eDgwjQvnWsgTa3VYPs7UjwEtDCR5F3oNlDT/g6AIrbJkuzW33a9Bh5GL+tLxuyK108a1QNXnlq0Od7wR+7rcQ3n7shj1LznC91kj8ZVnCute2UmXSCPxvRDbU9oiCwq3X/FpgPzwJdoQGt0zCJles9JuIwwZm4vzGVHKtNgTvN8YgKebFPpMCWWT+Uljg84GlLONh0tlruExQBVuiB2DXnIu40V0ROs5d4sI+SwhdIUFpJ8vw1s2XPGr/H/7lepryTFTY4J8KV4RaQ1vMVdz94SzpKVlxsqs9LbRpw01DfqZwpptG7o9GiWdvKOcwQ+nCf1i1MoNnP/lN8bbm4LnlMLWETQCbl3u5t1mYatPH4xOd8ZDmOB1k0Jjqxp4Gv2NKvKvannT+TIVO4+l8KyUa/Yuvw2ENMVhwdhv9u1EMpatreenKbvA9Gw9Vyz/iR6EZOMFLAOe8FIKE3LFg8FSIQn6+hQdaE+i7TDT+FalliwgD3jF2J6dlX8Un8slwr0IMlqep8LuuZ1B2ZQNcbD5KimIjsXvvTGoWsaK1y2XYSXUq/hjysb+hLtgz+IozV53CBsdMbnf1QEOpd3D7TBX9t/gZnJOaif8eCMGylz8ppWQxfjk7EmfpneTknxshcpgqKmfKsG5IEGlJF8MsTytYLChPUV3bwWh4Pof6L8crvfv52pqtoLKS8evMQtpVr0+CE8VBe2AGSScW4O4OEfaxeMhJiq60/40sBZ3fD3sqH8C97yqkp24Mlk4PMWXqLOh89xpVz2wF7WM1+LtlEz3e/YJ+fiwB064+hgXjQV46CZK9NcDK/wYYNAuzWMUwTMsN5IP+ARh9fT1s03YF338SIPM3gxfXKFPcXk2K73LBUYsryTDLnrT32sLFCn2c9i4Q9fzNQDF2Pfa9Xcwa/92gyKFv7979Ea5eFobJ/z5Cv3kMjDG8zQf2MQh8FaILntW4wHYmmX335tsN6awnsQUyLuRweV0jZhY/4NAR46C5UYg3apVx7IeL/O7pNQweb8ATcp/B++V7QHPERxafqAWqXQxLpznTjnPnyc1yLXL6HH56zppqpuXSoyWavCrJGVZ/z4PNVWIQYegPKgumk5UDodf4uzxToYYPBpngluXxKF5cjhlf+8GpQw7GjGpEFxlL7H+zHFWfK+DwBVNRJvcn2VjXYuK/o2D6NgdK92hBCNxG3QADlg1UA7FLU3D3qtE4J3AGJWUroqawMASfawXZJwrw10QcljULoulTU1r56Sz83XuO02V3sP5+wvTlt1j/1lEKuqwIa1yfUf89BRx8qMiVicN56s0gUlgehVtGHGWdQj1SjEnnTQfEYLRgF5f/7qDBz/KQN3cHP5gUByObhUEx6QM2P/zNuRI+dKAX4UReD2/aFMy1MQJktPka0cjt+GauFktpZMHOtmD0VDGjbQ7qoCy9hf49uMH2a+/BDJV96JsyiayXxsCneAkItmhGpxHTYWurJdwJe43VQ2dsVnfA1LsraGRhCg7ra6fsqhL4JuJJfXZ5fKRiOGydtxLk7VXomIYehz1TB7nJe7j58C+QuVuJ8nfOo8GXKBaTVoZO63U0alEv/W+nh3PtWdR6uQ8NhGNpnO8p8lhpRHO0teH+PRP49/wwhRpr81f51ew0YieGVh4ih+vHMcV2FXV2WELdJCtUnW0Hxto2/G/lWNiRAzQqupmuDc+kGtlZ4PLZhjPMdhB/3sWtyjqgXK/FFTE7aNq5fpibVc5zCzfRfL1bNLG7BYvmJXFM3z3+pGIEuxr3o+UvWzCcY8yLeg/wd59VNKcnEs/+esSRHn6QpjMFa+ePhqlvN/KS2x9xQZk6aj4YYvOPhiQwV576pC1Z+uUi2NawCENtzEBHJYoknKLp78IftFimkOYVv8UlgQd5emwi7P10isdoLsQSRV3wSVoPsQ63IbEyFaUvioF1dyH2birixfun05zWRr4k9ZG+WQwDx9BlJHnmNAgumcJdIjMxfmMinXMkvrHWCMf+fskhGRdoc5IIfOm8DjMH4lHMwAhST63DaQcKUXxYKbw83I+cdxK7PmSi/2sz+PjwCHgL7CGlNc/46utG9u4+Tam5WVCsJwcZDdPwt/8Ekj+uBmF/NUDizgcQGNdKranAA94mWHNfhMb860bRQCHcotuK9ToCsE3hJ21444l96rV8aqU7Flx5xmXbknnzWk2i5fK8z+URXy4xgj7pVFLMecdCD/Wxd85xENJTgEqN8XS//SU9W9cDqbOXg7yoMVyw1eKAqR3Ua7KR5hjtQa0rK+jUKgNM+q8a3TZ1c52vB0+OkIETFi784vcC1Pj9mG100sg9SJvVCk7g8GNuXFp1CBY8mQRnBs3g4LxoMLZ7T89ThSHlnymstL8J0/sH0XPiGkpVrKK7uYOg+VoPtAaKSddGkP979IL+cRGO+VdJV3/OpGPeB9g0WBJyVl7EHH9VKDhtxkte2WP2+nmYIDccOvuAQxrPYI/bF4gKGEmB1R20z3I8OGSJUvumXuj8FArZrmGsVV2Lw4rNYLC4hcvOLcGm3z+huHw4OI+qAo2wQ7i1WRl8pz1nmwNRNHj7DP0xKMR7YeUUOt6XzdkQ/IX343nzONj/9BxsqbKEFSu8UdbyL05bW8+5q7/xfh9vWJpoBR/TXkKH4SX0NYrlLru5cKfnLwc6y6O9jiYdFBIcYuhJcCR8HFg9/Yovxhii4pf/+FvIb7i9PheffnmJf1de55nZU7BKKgXvZsjBu+J8bgAv6tsiCh0dIXjebDjvv3MAylUSoKrSkdvS+0AsRxwWvYpD38tJJDl+IqR+s+H8/SsodupvHjM8DC/uq0Ctr8vQUVgIEm/6QbH6HD7UcAaMGsbQv8872Oj4bkhzduN5c+5i2fQy/jhJAlrC9pN+dztclJlJqof+UudjFSjcVo9LDBTo04FsFJiwgHe9HAti0p94eed88pAaAX8du+D946tDeedCuj8VeMTWTpqRIkzK1w1ANjWcJsvK47C9muhW1EIO5tu5XFcGNsb8R4+dxlDx5El4PUgX7n+N4wvr5EhIvpoqAgtI49MUMJiyDpIDqnhS1F7ueZdHg+W6cPaWGWnVthMk3UANnwVQ3+w/5Myj6HdgEp/cspkCDkyBuiaA+sgi+hd8AovClNm+xpVyIr6it10c3siphxMjvfGc23SWviIGKDbINzWVqdk2DWoWtkH8tzjSuHqI4nodSSR/Ndv7Ej/OVgTh5HG8xMcDnX510s88L2pxS6euhbPZbKI4zrNIgUvDj/NRWVtQPiNHnxWfcCCIkeHtAPzT9hGffD4C6QV36delJiwFb655MxHULIspZOYJuLv2Eqq4zMRXfqKQeW0enBsI5kPN5iyYuBOF35tD8RVh9Pc8BFsihtMfq82QckSffb7vgrNrTrCSTS0U5edicYwtmE7KoytzSklhTC+lxfph4diHYBtbxatSllL7u0rQiFZGmqsL4poDqLXSi2Zs0eLrkaNw7PRgXiMaBtrzPehUVwSpjZClXw/0YfttV9gUo802BVvx2qPlEG3eS85aU+ln9zHOKTkNJzvWQJzmaIiPD4PGK5J0xPM3ygbvhA0KV3FV/Dqs0VpM84Si2eeREcQLqoJb/m86WnkWSgLk4dX+5zw97gOTYib3LVOggUpi0Vub4cJLXTiQ3YwT2rP5mtRwnLVkPN979ouWjtxCaYsieIJQARZpB0DiWCXY5LSeLVtm8ymnb+QvlAbFAeNAoPssNHuFUN5xHXzo/omMXpmAqa0/FOmn8ckHRzhjhRmkuW6Cpn5nUHaT4QK9bTjrmSTlNVpB8sXJoByjiTP8QyHC9xYnzFjNZh+68FbmHOy29Ifozfdg3kdpqFunQqkjIrg6yIQmxx1A8HMin8jn2H1UGOz0b+GTzDNgsFkBOpudMN9PBuZkCJG0jgHmThPB6m1CuDfJjMLnCEFRRBt9yDSFWP8/GPAwB5KbMkh+11RutkxDGUM5nrnTk9eddsOfdddJLo/gQE0M/hljT/MV6/mRzRiqrjrM2/Tmwu6EubjkZgf8rjxAynXD4e4rMXCep4jPdVbjj+eW3NVygv48G07vpt6D95ltsPDXGfJQE4E5+cUkPFiDBrk3qNr2PttK52LTxSXYfsyOrhx1RN/Dyjx3pBC8zjGlnR8n8dl3OuRW8J1PLZMiVadBSH9cz75/ZrP9aXUe0aoD9S6+NOqMN6u0x7P1kx+kWxIHX7JKYdfXsTglTorqZhNt/YGgI/ebJqk+gY1XBSkufiRZHK8FsdRXXD7sCIo7h7Lm8hMcFyYHj7a8w0djbvPk/ACY+J8uXTGIhLwNi3ii6kc2VZhC0xs2QvN6K5D09Oefw4LB4GIhb9f7Q0qKy8lW+ADa9ohB6eWDdFbJCb+Os4bLhYexMXfUkGu5Q7buT+70+kfHhU0wpEKbRH7+46Dt2nAwHeCNly344VJS3ggwd2U3SxvZQOO5NZDL29nxnuSQg85ii/emEKeyijHlFNZcryN5MQ8o3qbA1CmJwaWHQCRpMafcX8z9ZxSga9VwKvmui2a7LuG6pXm8JrEHVQs2s+vdGLr+SAhbFtymDfaqsPCcGjuo2dLc4E3YrpZLN2yyMByec3jvRtbrakeN4b/g4mppOKc9glXl5lGD6X08nH8QTsXU8tFKFU4Z9GJRew3cfV+GkzdawduRyTxh6UqudRuAkb1hJPu5EqtlCKP0wvD+lDt4YUwM/tQWg5mlgBcjrmNnUhv++3YUokPvQ/qv7TjMMJ6a4u1okVADWhvJQ0v2BPTLr6GaqCmo4vwV7sWNwTP8mVetucK2VrJgU3oSqnMRRgTZ08O/iRxx/gTL+L/gokmPKOcm8Ne/b3lF8k0WtdLDwYMjYU/eCNpwdCa6Tk8mJf1jmJMoC110gqYX38Spv/Zh7KFc7I4yhR3PZ1GM/CUs8u+E3Q5z4XnvE1K/5glFVa5wLucstokLYXi5IGwyDmJhiWV0fO9aNJycDqeLsyi9JhBu/zAkcRNJauvqBovnOnCgfIin9teymlffUH86QvtiC8LB7aA2vRYemaaC+LUTMOOgEjT1bqCI7gnYeayUDnWmsNMdO/quPQK6xVvx6K4U2PjxIXc81YO563ZSVGcQCpWo0IGGYnx7O5xHNOXgqABXtl6mBbsLHHDaHlM4vt2YHZQ/40Ph4yx9zZEbjq8H1aQhhp8SCC1F3RzWGwnfWR9mmGtQ/+ej6A//kUFqAiz0bqGoBa9RpiKbl2WuRg2HFu7WHgMenxJJpn8quzh95GH2TiS3QAwurt3AwpvewqznjjRixCiSUxCCEZ66YPk6my8lvoepG67Cl9s2MDy4BQQOyuFVqcvYcKGAx8WNg6SRqznWxwlnWYVj9B0BNMp/x4efruHC7TpgOTmFTbJaWPmrMAjOewhGYc/hhtNInHfFnVMPmPCU0aMhs86QigRn4coQDXp3xgSqI37ysPfxNNmtDDuK93NZ8Ej2q2vBRdNiUNhGgvpqj+IHRyP4kSbHUYt+gEJAP7pmPYSctdNxfudJ2j5pEQdkAO0+UUxTK2yg3GIqtoq0wv2Fy/mHRgMs1tcjz503UC8dYZzwdvj08DK27xoLCiOd+PaXNuw9K4/vStNoDc3ida8LoFEsgmPlo8H/TQlUOg4HyVNzaLD1FJfXzOcnYnbULd7GK9NzMTLACxSsZEipy4/DfceBlOUx7BrwBO+UlzD7cTe6GF/D5GNS+OFlMu3QHAerF3XhQyt5eKn9Fs++MQQzH21MF1hIA8WTKXDHGN4yZiFOm/QP3A6L43ZhVXgatQvMlzVB5ovlLF+bQWWWBLOEbnD75mUAeVr4wscZvp8Qgw9ifnxMOJ5Xq7WzTfA5Skx05o1irXR/whzYs1mFivUlONRSFd4IuENHuyfsuvwKCse7kwkU8YRj9lSy4RIbaHWhXqwpno82g6Bba0BGOIhW/7XAgZW6kBTUxaHq84eYfwffDtrJnru3wIQ6e3Df4cSHCwgCig+h+hCzRI69zHoV02FG90wyGdgLVf06OPe7PJxZ4Y/SixfgrbAe8HYUAb9xp/hkyFuyKM3FezkJNNLCgofPs4XixjZQ2euBlan5uG9ePWWevUfy4bMwJdUDng+x/eEZ7RxaSqCWYMquekYwVuMVeDhNwB2NfTRbZiJfGFZNi2u64dNcb8wvUYA3pkNe1XiJzi+5BIcPCZC8hBrfcsnAVK83/DbiMFgHx2FNrRg43fOD4419qLDLGFMPt1AW2ZGIQxfKdweBzRtX0O+VoYdrbODFJDe0ly8n04QeLJh9C//NN8BP3Q1o+mkpDLNMxHnvCmnObobQW9H45LoPREVegduGPdj25ypeLbfhUWaVrJ+QRaPKX/K7GVow+NYJXffeIvvzM9kg/CXnjhmEI+KMcRnrKHfqNtR8947O9UrAkzvDOcOgkx/b7cZgRwOunveYjS0u05WtOmDW9REr0k9htfowOJE7kv7LC2Vf5RrwsN2AJ9c589Sw95D4UhUuzHlLoddvIEQNgx2RZzlHLhWyTp2mop2zcKDZmKy+FVEd7oHhdQ2klrOY2iaMBMtPVzntyANYN5RZeZLtpJJ1goQ3noTJzz1wgdZ5MlMdhrbDpKHF2Ypq8zQgK76WxJRWoq17IGU+Lua1s21IYEwvHjFxogcJprC0bCLotfmCrE8lCDSag4f+K7q+wIYa28fhzqoDFNhylW2+jYNrOpIo5N3Orf9OkfCfYLritJRPVtni8BpT7PAupQ9D96fKxAgUSvo4rUWXt3ouIeeOG2xoepT6bC+Roc9qNn3zCa4kR4FKgTrcKk3D7UI3sLz+F4fY1IFjxgHw6dvO+8ftg+FWa9Dscg2WV1qDT38zLnsbgFFCCnShZT4a3l1GEtk/6ULTYRj/Uw7tohfxt88WMDysC/4cD8T8MCP+b7IjjV9wkRQylXBZ8WTUiF6NZxVewodcO0gR06M/eSL8tMSWIq7Zs9TXYEhSd+WJX1eh941UTHcnmlwlCrobMvDVwAR88sSJHo3zY7v956lM+yaZhcdCxY013G3Ui+Z5IpDg1EC5Ui9h2qLdtPvdbI7aOUiOV8uhMECPVn+OAA83ddprMRaqd+zErcrurHVED7a9MKJdBmfQ3U2ePBL3g6n6RFrTtR+TEsZAfc9H8i+6zE88bnG6mw/3JJZzsuwvLncuoFaBNlz73QtjMxGu2jeDn/NX7t/7FfUtenDx8UhyGW1Dn/ylwPpaP/RdsKXgjwj9w+JA7oI3NUevw6sBllB98x92v50B7rFurPk2ESThOn4p0wT7O28RVwvB4T+R9OBGMeUlabKKwHS6a15FY8QNsTQqHxV0JMCwOYEUlqfDr1YJDBR8DTPOEPvOTONg8ITc3yu5+f5RuOotAI/PvYLrIf2YFSmJPl/NQfVsLpup/Qf7r7TDBJlkcJ72jKO/GoGKrDYGz22CA7J/wSlQmPsOCpHn2Kk4Oy+Jzq/3oHOfmRctUIJRvi9h0w8RLu5J42Wig/j6zgYWyXck5TVROPXvS1rzfClPR2V4tNOC6+vK2XXecczKe4Yz/vRgsmAoi42JIuGIJv5ikEXvw0VhUX8FznCt46zgqTA+xpqeBJmj5ovbtMQpAfs65sFeyZekfWoEmO2OQd9Aewj6mUW1AhGw72gj14Ubc7zfDRi0foIvS37BfA1jqF70jLPcCjlMNQKdjVVRYcxekrqfxuc2T4aaurekL2FA6R8kQWeeyRD3CWKvpD2a4UJ8+zEFZB7HUuRt4OPzDkLK31c09qw4hF7sZx0/saGzTmCfbjP6BG4hdZsy3uQTha/nRvIv4SI+VjQKGiMsecGrDpQtbsfAohdQ8eok9bqnYt3eJyAY+YZfxvfyhp220FE/n6U/u4PX1nbMT/3BFwKWs1rBRlCesR+/Tn/AB6MfkKuZPQgZ9/L2ge+4UUMKvtbEs4HQfTpXe4ea7rpiw0glmrJTHnZLqoHd7QX8ye8y9HzSgSueIpQ8zhpnNsViy8R10B09C7UEvuB3EXsYN6mBam4p0Ni8AbpjbwEuM99xtsVZnNHRj3fj0rnbtB8ODQz5easGrXoghnrvxsNqm0fc5LKP7ji6oWO5KLnctmAv/UtoJDMBUtuFadeInej5KYe/zK7mS2JhfOCWFK8wEeWrBwIwb+J7jFlnDTOStNF/qJal/hfZN8ia8g0scYTSar4htR9ESszQZXMfF7cZwYawc5QxYwwuPfiEuqbUsvk2Q7IsnEEXpC9zd4EhX1quS4Mn9cBeKIk0HReCeGwtomUzLRY6hCsejMH9niu5RK0KF/+2ZLNTcjD9vi7L2U7hyBG74bPwG1Y8LoLrXOXhy+eX5H1vL4bUy1PbPTuod1bmncPvUXLsJWj3lKXL5hk8u7kYRC9OhfTfMvTY7CBrZFtDVdslSpgQBWbdzqgzXoGe6VujZkQaunZG8uVVX6HsfRBUN2sC3DehB8bfMSZ7GXeUvoULjXfQdIEouCqfJIXJLfT42kdKdx963/tQ+HxhNke7HeBph1Zxt8YQxzR2YsG8VtScZkN2Jx+gk5E5FDSqwpfXKvBStZUd7/TAVTlvdhRXhMLr/2DrYX/IF3lPX2JNoMyb0XmlO0s5xvPShA1YLygHZePjOMP0Js37V8ZiMglwX0UJNFdeoJVbDXn8HG14NE0R43KWg533R9ogugYGW2Th8VIXVPutASbNITQwpev/d2YsvRoDQYnzSao3DlW89lDFwvskKTudKr7JwJhZnajc20W3/PoZR41gCUVDzjzxA01EG7An4RrYT0+Dz9PUoSBGl55Pa2JFyQtg/Pw+vVQxpbOj5bh29m20jLyPdq/cIGZovsloWlCOYSSpluziY5nb+VPgXfIqW4/v1C+D/L52ntNriFq3EY6Ft6KS+SR6z7vJau1clpvwjDNy/Ugo8RlueHwCck42g6SkEfjXLWArxx34zSadhzWZ0vjPzfDm/FmOydwI6X7Z/Dn+JV3fNBKO23Xxl0t57G6UQncTy0ig0ID3z4jEc0uC8PD2cWA9splifgiByMPHGNPjhvHuz3il3X7imAcoqLGNTs2NQf9fDvTSZj1/vm0PGSdn0YknqqQuN57yp5+CIGNvuGGvxZmnN+HoP2IYcGUbXSq0hKgrc2lSYDw6TxGClaZfuLi0BHaeqmFP9SKsfBSDkwK2YFCXGWwMGIfLGsagkuM4KNJ5xadN91GJRgzMiYpAmStb8eF3W158SBEat0Xzf/0fycFfhA4XpOOBi9kAM5x53uTR1Fw5CzdfDgJ3JV2or6vDXe9C6FzXInr8LxziDZfQkde/uU/xLdybPIlJ6TSwiDVITXIg873bcIbJJwqyHs+LuteytOtY9HvkB/7NOhy83QnvlViCwI+X3DLnMD83CiXziR7cdGIQzWvCYFNGEG5/0ARL+7NZyQCB2xppYoYFbTSLoCVL3nJ9vhKUXeqA6kf36fQsQ9ww9yqcn2cMWxdPg/dj+iD4nT6I+x4i7fi13FWkxJnvvXG9rxOujLemd1ctwVr/BCXGSLC51She3XMfRG+do/rSI3ytaTf/OFFCD5LsucdIDt64ZVHPQBv49o0H7UeB7Pe0ixR7nkDa81qWmaMBupON4LyDKCRpNfM1X3X6u82ZGwd6cfaJfSgX8pk+jJ0GVhSArnrVpCWmBJcXh6CLx24++LEE4/cdpJa0RHAW2QzrtU9wwWsh/FZ5hk//loGkQA9wPHaQq6wv0TL3oXljFIlt4c8o6nssGrkpUs5cK8IhT3lQf4er1zzjvzrq5DzQCgOK+aRmP45PViwjDvWBYVcf84rvArD+syjGh6pC2PzhuCxADAr29fLwiE000Psbpw84cMS8I3DLCOGcVSHUfBCk8LhsCFh8jYWHbQFYYY7BW/JYvmIad4WKcMDR0WCytJG8VRTpimUiz0p35n3DNGFasRLbKhrS+JyHpJOrQuU/DOHKzDgQjn2MogEPOXLzDhx3ZBEf3r6UXzTm80EtWxwsLORJ6sNhY5Y6xMbW0+3aJ7Q01I7GDpSScuMZUmkYqnuYMY3c8ZOqPwEoj0OYX3IUUrQHcNaJJviTUoDvX7ZRw3ZN2oBmYKasx7bWMjBlgyMbYTm0b56COuXLwXC0F+9bsxekFzqAn9Q8mvynBW6hPMSXmnPbkue4UaiSZ3fsAFExAbIQf0/vdX6g+6p2nPSniBdJmID7YCyFGDiwXtwc1M+OR7ll1ZjSnwcj4r6jl3IZXrAW5iB1azi/OAFUxlqj1+9+TLrjya/m+8K45BkomvkNFn2oIbnlc7DGcgw8yf4Ip1/PZfNuC9gd2MtP3/jAh9mv6efVzShd9AAEy8dC7x5buKkdA06pl/nu9qfw40MDjiw6wZ8yduK+sBAe7diPgu/rcI27Llx2DafYS+U0+YEIp7basEmFM6kunAoenTdAwcgJnSImsc4iaRBMqUf/LGueceQ5JCsy3bbx5smZfRybexj2zPWgpDxz9vqtB5WDZ8knvBK7h+9A6fFmsL33KxT8ksHlWwvhvxBDlhUPIVUxbRBOucQVxmoc+TMXBVu9eHbiV446yWgYEgxhx4dY/pAQbJ1rATOyQ3ipyWOe1deNXWs24kn3AA5vmoQdmcdx67V+vq66iVUqtWBYmxm6j/2PzgquR4u+VTSq/guJq6+hhfeLKG/xDvbQiWIVdzOY5i4M+SWtZH46Bza1foAtLrFQky/DY9eNp19RFvBbtwJGXlAHsWBZeHtIF358dMcrRkqsOcuAJM/fpd87AjhiYiLu1ZoH4WsQtoyLpDUHTlHyqCio/bIWK7YG8+czKWhr9ASyVgny4mEfIDzQHFwvGcL37HIUC33KOjlb8WqvOfmHnKD5mZH4S0aMhHNW88GdmrCj4CY932iJumff8hGRZLri/oVfVVlBxxvgMTejYMToG3jpriEYNXRCeOw6VtvRQ1P+fOYj1rUo9fAldS2WJIfEABL9NR/LX0nDbld/ClbaRxqhZXhY2YUjnf/yHOfz+LbTBuY2u/KvKFO4UzceCpWcKfXucBpBo/DgQCYVbJqPebOng4LpSzqdO0Arhh9Dzdlq0Hd6JMWlVFHaj/8j7ky/any8Nr6HokmlSZpHpTlUUkqZlVAiIiGiSUkDUoZKEhmiEDJUpgYyFQmlCEWRqISSSl+RVAo9/f6K5/15sc86e1/X53PWvdbtw4F2V3jEuL18bH8vf8kcB5OfZQ2x/U102ywGsxqDIGW8J+bWR/PknI8gcd0IzslZU/YxV879OMjZrxqoQU4ZMvoWwuLBTFyJWqDg8YWefyQOEDlBx6ye07K+ejR+acg/7WTgXLcgD8q95Qs/hUCyYTJr9vegwZwDyINjWOCKFK7vSuFfX1RASMOXvki4gdCFRdB95Dz+rOgira8rcN4TXSywu8uxp0eBWb41jDpGUN63CB2zLpOTzmU86bAYA6b7kkJwCH6tKEJN3fPQIT4clN0LcGWsGCWM2ct3UnZA7CwpahrqFY+sWJbXuMbzrhEWfBOEq6PjuKdxAzQ+tiS8asJj2q+AxLNVmBI2F76N0IKKoTz5vmo8fPMz4tKVW6EieQGsOSoAVocz4V7iYnzrZQ9TdJF2xhVDo6MQjJBIgVOzdalgehfl6SbCkykzsegH48HoN2Q/bz+2hcuh9HILuOQeDD2XU8hWQRQuCq4lSYFI7B3mjQd3bOB4Yyt2772B0h0mAN2daOGyBrdPGEsqai9Re/0+yHTMxJeh8Tign0Brro6ikZXj4cvorSz0vo79lujQnLVOLLH6CzjhTuoqvIXyq/NJpl8Zpp8bDVPL/8DUx2PobvNH8o0wJ4dNR2FOG+DxkYb0LvISjN/6H400GgaPvexwVUEcSb+L5MqYX2hhaYzrl7rxx3FVuH2rPNct/USenYYATcrYIbaV0xfpsMCbCfBM2gkfzD0JC1e74g89V3bSzaOJXtJwa9NqXntt6AavX2Tt41vQcc1burruM0/uWQddyZJo4D0V4nuGwfdJi9jqZSl49f4FH1lvdNu7gR9VX8NDK5Kh9FM2dyo10a8sOagcbIEvqfl4PH08ySaZ0NlyV3qbVQt9FwvYQWjnECPc4i9/GH7HI2ZFT+B78xfSFhPmCat6weyqB+uqhfC02lWs5DSWlhdbA76w5uSev6SzQAW5QIcLsurRrf4mKL11pEZHO1bqkuQ1YUowTG0Btz9cA6pjZrKRth+r6/vAjAJ7GPVgHbfFr8QLt0wp19oAtEK+42znbeRSeoLFhz3jMDk1uPvQkJMfR/O2GWWYsPcgr4uxgMM6kRAYcp/SF6TgWHdNeux4hSNa7+CETW6MXr/5W5cN5tyVBLlflnxxFsPr4dYY+ikba7KUQX2GEFRtNEGzf3o0bsIMKk2whIMTtXA56UN+jDk4bUzmRbqPwUlMlBLznoCe61OY+/sWdE2VgeIZ4ZATFcaK1mV4a+kVzpkqhEbOl6FGxoREIl6RYelnXDfCGkLenWOHuWo4X3smTX8RBlyeCyqvs3iX3nOamH6JcjbGk7a3FWDHJrTxvod27zLwr78GTCnPgYzV9bQw4hR9K4uhXH4KEz3MwaywBGR3ZsPFr2pkXfEaO/ZLcLv7cP5Pw4E+zF/At2OFMXGh3P/b+3//7heDPe/ieN1pL1gaE4uVB39zWPIGWHI/kbdb6DK2e2D3EoCQT1587XAIDOxaxvemlOORy+W0pDUO610v0T9NU3pstZ5VuwxB6PEcjrarQl0TAX7ytAauOzzlE58NIOTYI9h1eyfV7cyDPimAgPJN1HDwE4zjTzje6z6drFzBNv6x5LSogbKOGcGMyEbYZq8LESnvSVu+nY/MdqTHCoWY3x5Nuc1voGf+OTDulRrajThoGvq8ltkiCKrRp89bzoP/0iW8a/pt8jtQRNMkp2FMtgodVjKFF83mAC/1yVcojp1lPWj3ts/wdf1t+D7qGXqbLccpovqcOnIvlM2whqbtMuQzPwr/TjPEimAhMIm/QTJVefzQ7T1OK/5JZ7TbaTBnJKzw6aQ/ValwYpozmdcmUPbwFRje3siWO3pR+0kaue/UxaBZ4jDeP4lPfLOgLzv8KaZNno6f2UUu6x1xRuZQ9z3yAtMRPZCRIQAR4W95ss0zuLW2AK3PplL5qmS+V9/P0Sm36L2BOHgcXwvNypKQV7oJrjkvpuFj7qF9qxw989sDtx5PR6uJZ2GT+nr0dxODogoJaFFbCskiM3js/AyYs/kMGo8fzk/FQvCgtAufyB/Esn2FFLnbBKyuP+SLPkvpS+N3+PLLicY+uYnrUjV5YesZ+u2zk06NyGClrUNcXVVPW/oT2PRvNpQqWsG6XQt45SMb2OoTQfZvwqHX4xtHxynCmxOdnPbGGD2H68OUqWPgXoM7H96cgbmyMzCmqQtm/KmjYYY2kLPOgn1XRuKH2E0oEbqVfx/qxV1Ff+Ck4SBozZ9KoXrTebWdMhyc84SEG5lOgzjcKflIuxOfcum6VHYyauZP8y6h0XUzdLppBQF3wmH7amcqW1VId5+U4f0x99hD6SK6Ws7hct+nsDSzBtJ7bUH0lixp3F5KbTP0+MYxZTL3ioZ7B/uGWOMcJD40Zg+tN+w6wgwmdAnTpbkH6OW6r3Ry10140f2IDxpP53NlCrikfh8I1jlB3QMr2CxYCdGTtHhc2jP+Ov4vvQkQJNP6eFzTrQN/pRQxdedF+jVZDi7NkMDaE420xkacpjUWQMlCfbJ9Hkp7982AlNmP8PyXPZSooAbX6lRRdGANSNdFYPawl6hWq48LTujyPWlX8Jgrx1OD7sHwHkMoHTudrxUnMi74RyUbrGirQBFsD8zFMVMJVxwcxKZVujh+ny6IvH7E1hPyWb4kARSmH6Id7+bAWYd6OJqaQwe8wjnb7zcsDwI4aLYCtt+bhQ26d9Gq7SdnC3iB2tzDlNl1lKRGi1HsqwgwKhGC++/cocCgDeIm7aBxIqV4LdYQ3MViOGrKYlZS30Wy36/hpdThQDWB8OPhIVTV84B7ha+5+N5dSpJy4HVf5NCx7CHLrqymvRN0IXWkJm8sqOEoUT9uq3mDjovvsEOlGy/M0eLI9YU4c045fY8fyvFHOZBTeR+v57ayTuF6il8VSJ4CH3hEaAe+n7ONRg2IwNxZauCSMEjdq1ZwzsG3MDKikU4degzV9yVwlIMoJ+gV4EMVZXxvbwF4KZ4t1TXpRfN1mlAyGea8Pk6a5grwM/IRHlEKBrWnM8BqNwGrz6T/SqJB+9cfvO15gFueTKKw2VOw2sEJZwZmUvmFfyzuqQq6BqW861Adal8qIJd2Y64QuIgCSW/Ibr4nPPw9GZ9NrIQ9FYpwPaCPyw5NoK+6Gnj/hQ74OUayV1g3x9zfyVUHFvGG8e+hLkQMauQW4eQlOfijO54r8DOaB1phbpI6B3qa8mFDeSp5+Rh+rDOFtT0HuPLRJBqtoQnNc4aB4vMBKDJQ49g8Fx4+QQj+XhiEG21aIHoQ4V2vADyJ98aT89+CYVgplIMLvn3kDhPOqdLCpp20PM4GHt1zpR9VfdT3TJ+WJbxkaR9d+KsyEl50/Wb/bdE4U2Ey/E1ShHDdFhjhugU8dYbxrnIn/mHcyiXCRqx98gKJihzh7vRkfjteAq5v62fpBS0o6hZAZ++shGedhRxRZ49j87swdaASxyw3QslVE0Hp1TWM+zcOu789w8tCAVwn9wJMlH/yxRhFhpECuDKzl69clodZR7/RqYUVMFlvFfl5zaKg36JkfdELy8/tR7N7Cby1rITHjZkELU5nKP1fFrg5T6bDUIlvL5Swr5IAa/neBLfgGoBiLfaZMRHOPPTGLrVsrlxwHP0eVMLEmX68bGQJ379rS6uO3EJPqyi+Zm0NPqmpbNicCk1zxoHfkNtZXHbBAr8H0HUpE1XsJuOO/EyOQATtG66c8ECPfV7n4eT9piBG7rBsqhSfSXpO/Sbe9FD0EG8QMwb7tGy4de4KZiRcgMy7pyDxSCh9dXyHdXnSgAUvaUWsPAsWC0BlexSGro6ATy8WYNvMqSx4fRoLSU+DiDjgvdMKocnzIm0FbVBfGA5ZA2vRdnonGCc9wkmpBrhSXxIOb76ODjXWvFGvBBeeVID7MpP5YKsChR3V4tPQQVrTN9BekzYY3DEHcxOW0rXv5/B1lD6MWkK4rHs0Np1UwsqNf6ChT4zrj0rxNl956Pr+l/SeX+WvF0fBvMIneDOgnjRqunF0ZgtTWRz+W3Wbf6qdhmNmxA3xRhhcPRaWWobgvN2tIHX8Hfp9UoOW5BB6XB1OPwXW8UCYLKeMmwAbkszghHoSu9UloEBsI31ZNwxPjDqEZlbDIDZIH3fqxUB070KWlVWEgueq9MJ/Fi6c0oh7NRbj6MOBJCFczPP9TcBbfh2Z6cnS1NWyMNLIFIya+9jtVwOfkwoEk2oROrHCkG/sOIuyLyNJNagd4g+pQ9XaAl7SoIcnuyax3kNVKigYg4+7O/j51pEcf9yelX848ECJLcw+9ReVSYgvzt7B7fZ6iA/D6Ep7CO3bdBjVXnzji/HV+NzbEs6IXsFK/TTw/FeH2z1tKTXLFprmaaKorwzVnNQl+Y7XWHjbAubrp3LhXztUKNdBxY40mO/zhHdXtbPp5Uesd+cfRK7NBWHbiaA95ijqjX+N55YOkoHPR67y/wNbFMJ554dfdC3rFXzpTcYfqpqg9KSbn+cFwKZRoZQX0QpFv+rYK/ctLE67DqcuDM0qNZqOturC3inv0KpwiNcefKDRUXHkrXyUA0EUN6dGwpO4IMKpgzh5ghnoSB7gT44jYPT1Psgfjrx5+gxS9B6G8/bpYZOiOHksPkappdow80oB9o8KIO8UM7bo8MRlySUoUSaKR7WMSXr0Nrrc9xmM6gk2tiBtTHkGd15V8er1r3DPE1F+H6BFdVfH4KEIBw6eNED16mPh4csPbOUlgiO29HDTqwvkunwW1VU4UdHOMWS92ZTeWIizYLMOXGtwpTlPRtD+t61ooFiBz7Pj+N+Skdyw7xftW3AXT48dyyduWQEPGrNwcRZlr4nHyD3LQVFDEcOkFehIqSnsbPzA/zl0w6UDgiDcdYtuPjvCLzW+4cYsP7pyIwfOnekG0fV70fLUNfQNqOdp4wGcdU2x5tA/Cn7ly4uEtg2xRiBl+EjTmjIVGJaYhJNWzOdaKU1orZiL9kmr2betA1T2/4CEkOvoZ36NF4ftxBsmN1hsN/LIXGUQ6bfiiNUzsefSAjiWEUttA3pQMFYH1sxbh8XHu3HpHyX4XaQINUZ3MNygG9Xjd5Olry3uU/eAwlI7NGp+wNJtYng+sRTbI5Th+8AZ3JXjxn0ukbTGtJHGb3/CTwZccUoAwk3b7dSXuZqX6wuDi9UxrDO8T5mv/rGQ/D9wuqsDd++1w7wfHlzb+QHk5LaT/A4V+Pv4Gr1wbIFEpXjusLHk4eL2dDLIC82u+lE0u+LJprfks9scPn605TcexTBNvYqCDsyCz1ZDvy0UgO2R6ei6wBNVNm7EvnQViNk7Faw7JfDuxZMwdWkWVH5NZ5MuU3pRugKdwA/+9K/irAZdiM/zAW3bn5CUM5v0Pmvg6RHJPLvCnd7azIQNIrac8imUwhIMQVLtKrxzmMJNTitYYWsLl4XIou48MTY9kY4isaL0T/cU55VJwS5HBYhbPI+nTArEhY+qULFzyOnDhNi/RAk0J1xCtylL4f4xU6gZ4vSN7EKaYlPpudsxSIsaQ38mVLCk2hl85KlFR3euYsuvKhDwJIV+HXuDmRUB8P3pNUoS3QbGqeMgyKmahcI7ccY4QfhTogG36qT5wsjL8GKKAeZ67kXB1c1U9Xwc+K/aDJGzVPjZWX9yEDWBCY8UISlBGXT/K4ILBjrsMiyXQ/ONKXHaB6idOAUnC5bijqkTIUUggT3kDpKH0H4wTtdhbYtMStkwjb0zXMHUoRAFL2vzcjVhGCE3Bh7mXqSBdBMctfMvVU+Ohbe7jvClGAlemzgZIyuSsWm+BNSvSqe6EZFUVvWTbS5Jop9DJPf72HKT+kfOPnMehbRb8KeNEFRo/+P6FRLYXPOHmzWjcP/GKjx+7jseCtqJodOvU+wJG3h43RY25//F1247yKpXBnxwNiou9YRq16l4ZaQ8tsX9hJXSveDx1BgEruZh2Qh5Fj0NlB0UTO1BV0jzv3X0Ov4Q1B7yhH2h3vjT2QiclAK59sYLDlSIgHINcV7v+wI2d40Hrxlj8NlVBWocn8SKsSpg23cKL8k6k9mrFpheXkITl8TzLpHT7F9kwc6F4mR99yX0l+vBvoeZ1KSogorhC7AitQIulSxm1/ftvOeANxl9j0WhtlreXKEE21JHYIFXGQtl7Ub/FzFoPXAW/tN/iGkBdVB/7ASILxoPqpqTIHScF/e4mVLk/Dkw5UM2z5C3Y3uVAHZ78hXP51bjx41KuChpApy/N5eHh1hC3s1sKEs0Jf8p0XB4xGbo+CZAtvO66Hb9SfIeNIQc0x4KqXrDjVGydMR2FY/oiaY3XiEcO/0guxyeDMsLj8K0BzIwQagH746KwGcOxynuf/+DRCL3HFuNv3a58RVxW9AU8eClXuPgwwMtDDK+jl8OnqZTCVfRIO0f6tbOxvdZ5+Hlu12wyMgTnwvqgrWcB6/vHw7jBBaQSUc1vO8JYTGBY6B3qx7zz6mgw9wkNvYRgLn9Zizv3A9VeXr8JVKfPM63cQd/4xXnv4L9WAl80ytM1toTQLjGGSXs7KFdzRke6Q/HUattSG9EM+ckR5B4wgeqLnxL4vrasDI5CoxFNwL2nSVVl7tknvMLRu9/BYNOmrgqoom+SYqgyT0TeHdLFkyDsnH0qkr4d3ELuZv9xlXyofB9iBnx3hp4uXsru68dAf9d3IYKg19AYkoK7XP5wu+udFKa+j96678OR/ubYsT6s7xCQxnsU2fSlJF36NVXGVCe30zVoakwV9ef/n1N4a65/yi7x4b+izCH2JhB3G/Shu/XbyZP+zgaaiHQ8jvDdu3hsOfVT9K6vo9vHNYEgz22pFuOlJpuQ1OX96FM/HSaldfAlU8U2aXVhRLSbvKOIf/QufYZjINFsX/Pd+4tSsP8C70U9fUHvXb9yIntnej2uZTG7FSD1vJ1YFWdiImHsulfoCL2dQZC2kEVupeaBybPK9hn+ye2WjYcRAXukMCDrbjQvYzr5I+R2l5JkJxRTBLGqujht5dGLw3lFhc1ON6dQF8Pf4BlE0bD5bpOqnofQmqSbRD/XBgGBKRBZN52zj5rDRFtSylmby6oLU/HVWKred3adMp+/gldnqliyAQFVMxeCb1eNvDurgSwax1U3M3DnlEnwHTXSFBPDeLjc7dS1pJwTPu7Dt2fqMJlp07UXj6HJ5nKQIUg4XrXYh4h0YAzfwqjvPkdaNhmzi+2aUFVwwWOM9nEryOqWfnPMcqQXcNPfoaz7tdCLLophQbyWuhipgl664LZ/T9gs3351LzOGvwN9uPb91c5ZssXaI9YP8Sihtxgaws9x25TdsNf9O9ZiQbjfNDf24E+ab1CU8+PpLvCjxec+QCvzTXh2agOaMl3BCPlfLLq/8G5fuNJ6vhNlld+RDeH3EvD7jwpvzaCYOPp6LDGAH4pqIPUvhP0rM+Bfwfo04/DmrTwwko+PsIa3VukAV5Z03eDe/TWYh7WyNRweUc0dXjN5P0Kc+ld7Vdo2JuNve3q0HpVFWzex5KYczrUJXbRM2yj6VWP+ZHgbYx4Kkc2LtUcnSEErxXswCHPmaeubqOk79fxxM5luNbyFnDAa9AMXUqLRXJ4qroynLGU5TUpW6FoZCJ4rPIHU3lNyFpgQcNPenP1+ToO2nOct6sIgpOBBdoeOoSzduyDl4cX8MiJcnDzyyM6oHoeRCJmwsUfHdgwzQbeV6rSjtmaeOe/n+zwTgf2F67Ft7u38etjXXghJw1To5/h6YkK8NdwOvjlu8N+H2dqMW6DgTU3SN59Oau9+MG9F0z49Y1f6HtJCxZruvBP6h9yVWFK053Fmo5vseJgAh7Uuwrif7TZY955Hui1gfiSGnpleA+eKW0C5RgRrL+/FVvdO/BgYAIeXiNJP3N20Ja94rDgzXTIEcqgt9BDL7sr4cuwQ/RdJgFiNimzjtdt6Ny4DwXr5GDvjAQM3zKIu4rraNfxavr07B1bXC2nAN+xHDnnGHhcaaUzdwUhPfgQ16h1IIgNsemiNFB3l0SnpHA4GPOY/pT5kLaMKq+ebgGva9+DVf4aLL0WyLkRZ8GyWRVe2mlyeN9WPF8pBTGez5nOqsBcb2dMtrzA/Z7bUe3JcFpstA8vC1rhqCBLTA69BH+srvKOLSaglqHBs9w+sPgcIXq26S4YFM9F290S+FjJji1K6jj4gjn2x2vBoSVDrHZmEzQPmwhOB2RIXnMRPdjURXOdP8I4ixj4nRGJo/MkQEr4Cr2P8qIBjeug3N7GIXPdcWXgb15en0ej03eh+mpN2pUrDKGSi1jzrS+oWAewwphpdN5rCiw9J4Hjd52D3pZY6E0pBF/7ieA5ahUZGF2Dmy3FUJP5k96Wn8LUZKTtIvsBpv1A6/YlONZSD6af82U41g6fG13R81oyJMY5Yfj2Ol535uXQfs/C2Et7oHW5FjRvUqVgZRHY2dVIPb7DIeaTH1t5n8YxRQ9w6TtfuPI3bMjpR4Pgnpms47OLne5H4YFtaVAl78DR84eh3Fz1oV3rItdDJSCuIQzrKg+wi1MhjDkhShH/PcTMJ0Ggo5KIOwKK2MN0Ey0tG0k+50QBVG+R2rgOdtK8wg6HjqCUTjt0fXjLGaVZMG12L725dYaPqliDTIUzjrjWxnFzjvHA88/s7mXJ6on3Gb/uwooZyyjH05569aVhWud+nmGYiO+PS8PuW0v4VakQ6v54jBbHP+G5rqukHz6HP5drwvsdg/hMEGjic+SILwqY7aUJd9zKSeN0L1YuGOA7m7ZT8NNxsOtvItj3HcerFs9Y+pY4bp22HA4pVJHpnECe7X0L3xd2s0nIWIgwU6MX22YwHKrg+1u/cqltMlhb78Nr4VH02GQAbgrtAslsW1CRiQON3f6wSWYbd3/YDxZFqaTa8AbPTdhHWe5ZtJHceV2UOjinNZPb+KEbnbCa+/ktOZZ8hIh5EXTG7BF+UlwHWzyCKEV4OJiujYLDJybzpNoY7Db4gSMWOKCAYR1F2V2CcbeS2bwUMTZdAujEea6dchsUmiehwLI2btWso4zlwXg7cR7cq9GAvSev07YdY6BjTQnIlm1nwd1REFC2nJ4OGwG7Ta5ynsgxPuR9AxXOheCFg3owQr0dCyYbD80qTF91xaDWdhJ4ViWCT6IJ3B9zEctq7+CJCUIw0VEM2s06afTFp3RvWRMtfJADPUefsOJALW5VyqT36Unc/0AUvC+v402SGVSy6Qi5nD1LxQ4/KXydA3CIBXTbNtC2YRdIGSdAy3FFenbrBB2bUwz5F4Yy1SUXloXa8oeICNw+OoEWzCqD8AaC6ublsDrjElaMz+DnZuOgdekH8G5woVUrq3i3WAmnNs3DyO2ykPX0II9pyYATG6S5b+4NkjmkwF0LOviz0AbqST7Kcev9US/OCnrb7FGr/gj90HTmpWqLYfz3TaA5PxM3H7wNWw6eQOH6crJOswTpNR/IZ+JVWLN3gNZ+nElVCcFks0gHbjTq4YXriWQ5f5Aj42VgtLUNJkee5it2xjTwLgtemSDFK6fSij8jMVi4G15aS0HYV2HI8rGnu6ue42/dq7itsBH03n2G3BmBaDajHqW9nPnm2xzYIS8CgZ9aMPfZUdo3zpLD3pnxn4QCrDYoAd3nnyDTYy9HWXez5hJLEO+fzR5r/3LSlT1gOUaau+9KwhbltxzkaYv6f1R4ofAIvmpuCc8MCjlIaRX3Ty+Eu3cbyeNsO4yNbMVtcrtpboAfLOitpC3FkqA5NhJPXrqDT1RbYf/pgzzvWBKHbJfH4f9iYPPkWBav1cd5AiNBO2UCj7zUCean97G9pxEcfiwO3jGKeHbZWnQ+30/5c57j3DsCMC0yllI3+uGX6lY+dXcd/DRYwdKpD9Ey3If31z6nFfabKFVpMuQuvQSnb0vy/Ani9ChCEmabp6GsUTVf1R3HbvE70MnTkIWeycHUPaswbGU/fiURflkRCD/ubcTl2YNYUyrCb7Ju4cp2XxgbYgVNnRtp6/VDOLW9ACKi1eGQ4hWqJAFufpPN1yd3QnR+CHQ4q8IjF204/LCL57jlU6/qVFKYZY/xle040C3O569n4aQgbx5vZgKbI614dfJeEl1xi1R0MujlkRCa0FMAQtOvkckbD7ggfYT/XVGFSMUL0HZFGN4dPM8tPRbwoi8KI58vwcumJvhwthGoiJ2CwUyG9NWzQN7hD8P8/bDBYRluCd4NWaOtecZoc8zxNsF4oUvwfqiDctU2kf1rB3i8axgvVcyB2i15GLm+EZzXdLBBQieIWnji5BOy0HhWksxFT1PUmybyTXmKIVZPScOiAraUrYQPf/zpcb0deZy2gGTXhbhRaieWND4BW4+7FNJaDcL91zHX4QLerlgHXr/ewZTlguCja81Ny7bi8Gt+YFcqRCMFb2HLDqLKwWjIWraYP+VPxBwZazgpO4N/up2F8rpH0Oh/hoMWT+SIW794l0Eo5Nup45uaMrA4JQ6H5AKo5GImDyv0g/GX02jz9Rb4cLWB32cfpofrOjmtgChd3AxqjE6C2lB2/NfxkScejUF5fT/Wt+gEr/4O3NuqgAvUltAieUF4mpvMSw/q8+/lt0jxqAzri53kuLKnkOK2GP406VCN8yyoDZgMOruBqoa63WvTaCrN1cJJ5v7Y17Uef6ds5Kt/xSC7aBIOmzkWLGRLyH/2DniwypHCFtaDpH4x1UR6QarPJah1H0BXvwtgvcoE3IKWU4x+POsvew/NEz9j2PXb1LNtMYZ4qdOy586kp1aJHbliMGl1Fbe/CQLz9n4SXSZCRgb7ea7BZDbx/Ye2Ume48LAcb51gAamHBaCy8jmsSo4F2DMCnGZ0gkmkEB1Jc4SRe2u51S0F58UYwcjT3vj0YDBFyV3DKN8Oui2uwfvNO6nS4w9+UcnEc90hfH27MZzAE1zkkYEC2Xt5WegC/qG+GJdFjKRP+wRxFl+m+FOSXJKoCXNsj8KvFV58y5nwaU4njpily4Hl5/CW931YaOrGFU9CcFOBBjz1y4KTIomU/W46xUxcRH/H7uQbjoLQbXyPj8Xf5fUvb3HJOklwb/+Dg2UeFEC/sbp6Im5cHYW5RoWgc6EAZeSSwPTMaVbbrAvfU8Rgxb799PeiIA/e1gXhbjtwywimhvveNBvHsusSZWoZ0IALv1xgZvJ7mip5girjCO1cIqB8XRPOtlmHm42LONbXih8FWYDhOBU4POMaJkWIs8uw55BrXs2zn/0D+yWB1H/ZnC2zvMG8cTh8yXclOyF/0nV1gLm/wkklQQUaipeCbIsvTdNfiNXptqg6ZSzUttrxkbnJuF77Np45acOmy96QqF0k9z++BisDSvif5lQw6lYAh0ofmnHzHB2+IAEtffPot8t1Ct1nRWFjvRDsk+lWeBu1mBmBmeIonvo1nmuTavDigUXYoh3CDROESCZqHjnctIKpraNJJHc0bH8pgLbVl7H23Sl+WDSRXfc44GHL81C/YA02vphAMLmcb1qJw2RFGxzdrMu/Hm7CD4+XQ86y92iiOoktd4mT0qlEXBq8De+nD4O6E78xzCUUUxIH4WiJK7/8KcyROvU0rYop/UzwkNfMJb95xpBa+IaOedvAPJWteDmnnPeW7ESXCfZcWe6H9x+vhLWnNuDZtdqw/ckeKl4ljiuNdqCj52Y+GbuSDeYL0/sdhBsHlrJ+XBM3/1GBuMSbeFrJCxZ9mQf/ilbDxcerMf3WXcqOfQl+/SHYFtvE77ZbQ5iLKzgEzaCVUjVct+IDPl+/lJf27MQ+AVtsju+DjIgbEHUFIMPKkByHbmDuAS2cr1zC8+f85Q3/BDHJ3I20/glSXnoNnL8tDXLRZ1HmtwcfvutBI4NSUTsqk+8+qufaWlE4/D6DE3N9QGDVJFB9k8g2nxUgd5YrL5g0GtxkFehB8SN+bZHEZtlR+Cy3Gsd6K4EIliIFr0He8BEDn8pC5CtbdPw5BT7MPYnfTItZRE2SHQPM4X7kZ27qnw+xn7JolN1BkqnWpj77l5haEwbBq0byxqVXwOvURNAwnY2Pu69iwvsyyLvTBMlawlzx31toOytK95R1uXvmRXh1QR+cgxJJBnfgsoZE0u/NYFG3A5S1e5Civ9fiDNd5tDuukhPSAC512uJHHS2aIjAGxsaKwWxfD/T9KA5VG8/TwON6/P7wE+fMlwH9lV9hWUUl5F3dxMXhaqg6qpj3+oXy4p1r8VLTe8r3toOCOB2wWjwW9ieX4ZwEaxJSR6w8hzS/op+OFHVSRIkwvK3IxaYDQpDc8Qe+penh2zYTaOjygEDzlzznzFL+Uj3IJ+oWkMXHpzhupxW0TVIkv3FAarKfIGr/Evi5MYQ917pBT/5V+hgzA2ZXbADlLAlQantB6wpO0bClgZis/AX9rihwnKMHv56tDRH3g+hmqCosfCMBBXajMEjxGtulPaO/ew0o8rQhfVpfT9fPD7KRxWs0X60NLRvEIMeyEYoiinFkRxXsUB0ggwBdaLHrI4U7/nD8zQ7OWryNnGrV4LevHKwUT6bQOZ/4+x0xXHBiFs5q8uCmOc/hgmEjJQ3OpsPtQjDuvALOidlOJ0yk2LoS0PDoY3g7yZE0jh/AOXp7ONrZnAILx4PMd3f89WI9V/0cTcGODyBG8gC9jTCCG6JP2K5Ng4rcJrN2ijq83iTJ+lnTKNJwOz3YlYdL/msm+WvH0Tj/JvvkfoOH4oVAKpKwpzoQVd3E6bxOEIzokifdjl24bYU9p2SMh8yTp+Bl5Qdo+CUJPxuW0hnPbeA45OSdwcX8POIYfwp2Rrfvtihi/A/+aFWT2HE9+P1xI9RGx+OX65PxW0YpLXBJ4tSHhnywWg2077VC28wv7GtlCCoJB6DN/iaNONuN/8mWYtvDcqr8K4gZ0a54P+E2Th35GvZFKoDx2RZ45LaZDKPKOCLKk5XqW8hh4BBK5TtiUf9YRonXKCRpCqYm59DVdwgc7OzhxiIPCLNMhjf2olQmbIqeHu9psHU9CTyyhfiny/D0rYvk4ptHcm+6cVZtEwdmSnOsag6uHSjl+2lI+o90IFR1G/R3fQeVN+q03HAS7vZ6zl6mz/nIvIN0zUYVty0ZDUGPDMBS+z9as+IifQ3PgJHaxrD1rSY5afyhpusr8V9sLI/aJwrSdxDm3bkHmyZNhPGn+jnYYB3nfpTFyD0HIaNuIV8QySbtWcFgbmACZv/1wl/jB9yYlkwhP66C7Pqb3J03HtpPfuZZxi34a7Ua3zw+GuI+F5PgvToe4b4do8RS2Z0UeMTD55wn1U5tt0U5flcsuX9XhaNLhcixYhGfrn5Bm6qTufqBNAVvuIAJzqs5JCYRHzo3QO9qQzj/xYQsCy5ChI0rjXkxkmrPy5Ptw1aQj80lT+tgvDp2Hx4crg7uO3W58fJHWjx3L39Zn0ax28LhZ+5Ljvvci+PlkPda98GkYgD1odlrrHYyThUkLeVbpOUZiM5eanyq7TyKd7Wy5MBwsNoiBJ9vPCf1TmHSnnce9kzVh6S0Y7Qlpg1a467A8GdP8fZEbbASEQI72VbuTzMmqZsGtO9mOd0rzOfkSaGYNFUD1Ap2UEHOBuxJEoOTMo382nUL3q5SA8G4QryqH45/dkmyaaIyiZl0wp6wH7iz0hzc3B/AnFHeFLV5HMU4RJPHRR3EohmkMu05hc+3QtW+L0DFAvC5dS37TfaDsHNPQOrBGx7Y8ZvrV2bByItW/OSHKe9fMosVe6ygbEc2xYnF00JJSwrt3kvD+k6w3HY3iO4vgXXPp+IZtSH2KLeCeXUpdF76M+ya5ABqwmN5UCQQ9FW9YHnNcJh5VJ0b0jzJoG0yZFu5sNWbeZQ3IgvmJ67ia9NK0KDOCIUNk7nQXhqSn77G3VOUwHj3cayf6I2WyooA5mXw6OMLaPO/T7/kb5BhWhbFRAfAzkIBEHzZR2blT7n/hRmu1LHDN+ND6d2wh9wQmU71O2JZNzKTTo+Xg0wvfd4rM5tbjpRhi8NqCrMNwteW7hAdK8iOtldByS+Jlc6Ng2XmS6DOxpj+FE7CsGg9eBfvxXmnhrFU6VdOa16JUw8idm4Th6aQIq7RyOPZVolosXgSqz5SRb33DpByzhdypywkjXoCV71JcPn7Qvy+WRbW5TigZPNuXOz2nY5nZGH3+2Yush+FBy44o0LJBDC0D6G0L1soes4L+lK1A3Xm9tOLFWIQLFIG9UFPcb3kNVjQKQY3hnlCrEQmbJJNpO7Lu+FoVSf/GPUEU0YM8qSwKHre0gEeF4xhhL8gj/sszfJf5vJDy+G8f/ZWmNLrj02S6nzglyN5/hhgiw3CsL/jLZ40DyDPjVchJFcId48wgaN3X5JnqSnqtN4l1x5tXLXCBi75B4KB0zE+fvY8bXacS9nHCFb8lGfByY4kvWc4Zto1k3CQMeg1/CJDgyUwqqWcjwUnUafoV7Yc1UczBD156WoR/D3JhyqixgMYBHPHsAR6/BUwSduTtXpW4NMRFTBMahlHq/wDEh7HcF8Rej7FEcsdhd+r98AyFxGQ9TSGTfk+qKh0FUU9rejkr5X4yVQPjhR9xBZrd94lTbR49SGICzPDV3eK4XrMbIg3D+PiFxeo/68QxCyW4w26E9D15XW6GZ7O3zYshJ8Hajnokhyl+erRccswLErQg2+xo3iP4i/ws+2hRPO76F9ylEY+zsOs/z5BmrMv+4U1QMZHAdhgP8BT/h1G9awVYCl2Dt8fs8V+zbe4U7KWGry2cFRVKK6XtYU1GsNgv2wzRZ27gaVjduLUVWV4XvYtWnjdo6b5p7DkQy+cyraGz7Fz8GnANQ7+rsLD71SSh3E3LinwZ4GxSC5NUvxfbyvhK3UwWJ/Do2ccxI7fcyE0bzkselKIg4n2NMr6Be29U0tR961JcDrC3c4c1hjYDeapY3G7QhHq2/jQze3ddGxyKv0NFENsLIBmXWVQbj/A5j+KIHGMGOkWn2Wpwn+8ZkctF4utJ8tZA5yQYU2ddeMh4coUHH8YWb1nHEW5zKOJ9VPo/a4aLnHxB4XUa1RQPBd8LLThg3oxnVcTwhl9Wvw39STP//KDS7Zlwg79i1Q6uwcLch5xQZA8DGwLIIO5W2jBnvM8bVgSmR97inoWFbi1JwxTRydAxNUYaMiyhbxtYtT67TjZrTgBHW3KNIDCmIcCoG1ryA1/KmjStk0w540JjJg0hrWzDCmXpHlehR3Y3u2CyrXEfiNOweGoRjYTleUGI1PQdNJAm/H5WObaxZr1EfD4vwDcVq2MFveGk0Pq0H0LqnCIlSxUuBtzYM5GSnL+x21RafifojEde1bPgQnXMLbmBl+1f44LyzQBL0nQtWEN3OuXw6cfyfDBgA30XewZ2My6hqPCl3Gf+QG+8NsMijSM2TXLCT2kDMj8hR7Nr/0ARan5dO/FMzgpNRpK5xyGfEcJWBgbgiVCXrxLYiJk5xLbymzlN3/y+DwAvz0cy91ne2l6iCqsdjPn3x2j8aJrEH8YGQ4bXmvS4wvT0aDxLy1ebwI3Ag7i4t0T4GW7PMtsaIRpT7zxVNopWpNfRX8Ed6HfEi+coaQCw+SjKEFLF55O6uHPyxLRy8KfB6y28BizKtTdJk7qH9pI8mgmFrSegWO2E2DL+T3k4X+OzEJmUfEJb3IVcQKJqnLcbVQFN1+b0uod/eQ/xQKiK46QVcpkiHz+l9fIK+O/O6PY6bgbFF30hMPLLMFW+CLWXBsFwQ6LMF3XFKNN/Mm5XBrf+87D6avXwquD1yFwxDzaGPaYL94UhuS9+uTocp1DVmex+BozjhPsx6+VnRgbOREHVWbCZN9h6P1nEki92gWn/C9R34oMkg74ixo+BjR79h4aG1qF7h9/gaLxKGjrUoLNv3/Dv43PafZMZZp18iPkGGpQ2VdNTvlPgn/8d4CON6tibaMkbJg/E/JHS7Kr1BKqTp4OclteQ9PWIKqtSefm+lZMGCPKOwOkwR9vcsYEVYzDPzjVSAI+WIjAs92mnFJSTwKHeujzaEtWn2sBjTZaFF6rQquW22HH0UDyXavG7yXmUYd7KqtHTIcxvXJ8JFAKNIzc+e3Wl3zRuxLr4kqhc9pPtHENo6+LvnJK80nscNmFsnLjoXH6WFS9MxzHrL/OXyUKofqAI/P1NYTlu/HdkRJI1jwDX2+Pgkk7DanrgSoeEQ8nMaFYmG0hBY80NtO96F+82bYC89+r0dEBLbgUl4KCOQCbnyhTwjfgH5EbqOmbM4T0fuaOgZG46PorWNyiBUW7h/w58jR/fR2OFnXf0SH6MY1LnUHiPe4QbC4Aaj9nUbi5CJTMv4Vrdu/FXq2n8DTTD3f/AApS0WGyRt69/RPXNQrS8g4rWNhgxlpN92jZe2nK64yFb1gDd75Iw1NXU5prJUHrzIrZ3sAQmqYJ8KVBYfr04h3JdN/A1vRTaG65F7Qtv+FKaRuq+NXB/0xV4IZvANx6tIzyW6vwaPpa1uztgXNqdeil9JQv1rym3nsj6eF4EeizSOGkUlHIs6uH77kfaP9BKa6WPkp/xTrgwC+roZzbz3HCGrBzVjxmLDPBPXrn6fXbELrXOnzIhQ1oa4A3TrWdgS/PHcfPsbpg82Ymr4tK4fnC08D7/mr6bX8Ix5Xk41jL8yzTnMT5VtG4X9cE6jCWsz2iWGaYE7lvW4srfTeyZZMYZYp9B0HuIWG7cpiSoQqbq3fTvZVRZLkwF5Y/FsUkPU8+NyOWxq+1xMZ5rjDyphS4FDOUOL0nAcNSLi3uwoyxx1Fv9TTQ39nCa8uW489lWbzivRO5tVmAoOZiONyyCaICfsBgqhAKWvzjm2HMffl9tNC6jV+98OM/r1UgSqWekrob6d4nf6p0qoPyPScpU6ULF9jOxbhwfWza1wpH7UbC1tY9dD8iluc8MuTGnQG0acpbTPxVxSrVLmTZMBXlFe5DWdVQlnkc5335L+Bl3gZiiaFOND/Pv/oNyfpwPj75eIo0CyrhFsrCjdQlnD6oRLUzrbGsphzOOq+Fab6b4PYVH7SRu02fLwnAtN/DIH3tTNhQ0cp3G97RoY/K5O9qBF/vKoA5pnPVy2L4OPY4JURYQkuzFLxe7wU7r88BetPJyyQVsXqBMq9bs54STAvg3SENqjhgCZdExNH8jw91fKqEv64XuMKdqHDzOTp7QhqWeX6DCR5vufieFjxa7kSRZ+TgcZwaiuYd5aIKYV6rex1+KM6HL16v4EVcDLeukAHTdnuICU/Cv76ZLPdmIttfiMDFga587HAbh0hMolTNXxB/ZgTMKA3kt3m9kLw6G70Pm0K4gCFfNx6PNYX1fKsMKGzTH+h9MBG+33/J6U2FAHN9ecXYMNrQ7kxpC/bArud9NF5PiacumcZ3h6lC8tVRbJB6CS7EGpKU2kbaV3QCfzktILN3D/jEmKNkqpXGRStFIa7QiW5FCZDuZhE0EtWALC0hWrspDV/onebe7CcEeTqs620LPyeJ4LQHarxUWZHWijey6Kd48n7WjNM0b2P1Xne6ofmLFtvawLhAYRib/gdPzr2EfiNV4c3+BNqRvomGu4vB5xQDnL1VH79GjIbtjxxZOfoS7B7qlnkWd6j0tDGsmujC01JaaVOXLA+jBBq+SxpMvVsgLUqQu+7MY1HzKnAsyKBWhVZYLLcI36VehpfBStycbgUqP5i2lRhS9F5NGBeVPpRLmrjwhAhluXXg7VkVtFhUm04NzfArzwWinbbh5WPK1B79DDM+utOp2jckOPwrFtuHw+9hflTH8pBRkgcfzQEXvL5PR688YdsJGzlztBPXu6agwdbNcGXNMHhpPgq8nxXhgyctcGCSC2xd40Ph2QdgbVszP/RRhwlRUfB0YDPoxUnCnBljMHJ7HSrNfEVRhSP5yD1H+NgZzzJK33nhVEnYYR9GHgmjoLx4OacLdpOJzBQMklIi7RNxqDXzCmjoLobG1MMw0246OhdOglNnQkHONBX3FhZw5sep4J9ynRvtJMA2xQOHJfSTwNVAeofaIFZYxE/fJcJKn98kolgC8IdoVNofzrjpRG/VrelmSCC2z5sI+7GatDW7cHj+I5j4nz77ZjojXrhBdq9iuC32Fcm0fIKNbWbQuNeDQnUP8LjmazRp2kVQXGiF+YOKJLF1Ocx6fpLkk61guJoOBKfux7/eJ7nTMQmVtT3Ab0cfXXu5hhZ+MMOnqgjpiitonv1YUG70o32+B8FFrRt8Dg3lW301bp37jHeXPkMd9XPkViONtRWWoF4fhyqTRdnxdDB/ezKVH0UK0DUlR/jR/JSUDhjASRsBCHyiCUa9gSjZ4E3OB7JxhbM8Lel8xBg6Di/1XWHXtVJg5N2DtoXKYBqtSGe6i2jQVJIWjLGEWvPV+POaIpUvvcAjcjqo9GMr/ew2ge1zQvibuArKzemhdc9ceLyMLKd9DoeObbW0w7EJnZrd2U7HGkIXyHGXUyVJj+vGRYOvKHZ7OIC2DKgeuYki0rNJ5bEZ7D1hBZZCy2GuzCiSU1vLN0ca86n7Pny5OJVqZh9HS6lRnBl9GlRDtCGyQhzmtsbD8i9b0fvnU446ZIJi02Lw2zRVsBLcgzbpcTDVRgfK9cKoqNUTH86y5rFf7MhUIZ+OqphD65kuDjrsDvJXOnF6gxjM/G3Ft2sj4FakFsgMs+X9xiNRteUl5Oy8Qs+qbnGWZiho7LMAU6vpuOTrT9IImoaSFpe4aIsSGiyLBDUWhNpzZ7j6VCQ7xuuC64WblBI8CMdMnCFhgif574zj/eVXeeWQ01aXB9CgqiOvEbIB9a9Pcf7nzXBqrRlu4GFYMVsSG7d3QVcY8c3lxCealTCszxiyFvzi3LgkEo/eicafr9JuS2kw95vAfxbF4Y76UMD2b5gdpAN1tll4enQJCIy7TaM93fn042z6UDsReivHov3ALgxI7QGDbRZgOOUU7oiUYzOpGE4ZO4k/ZzYOfWcmE41NrLHMBCaTIisGGkPp57vUVCxDwU+fkbujJ4xeq4Xr11RCzj8TODlzDYf4qNLhGmG4s3ANGyrn4fW1FTghehnUZPfSiKKV5K2QD67bbdgOdak/dQK8GlyIB5ccp2zzAR62oZEy90rRiJe/Mc+tiIteLeBTi9Lw1GeExKDVGCzzg19E98HBfXnYbDOcP7lKw1n7GyBx5x+PPiFJ0U/1oO22NqlfYDz3Sx8eLyvGrfmfWfhfJnffdabD0W9h6trPpD7dAgrK0iAheBuNeZdKsh/10H7POUyePRNTPKNJL7SNVD5fop+HLGHslFrMWHgK0ssiUVVMBKL/zkbxzptcJy+M01e9g50uohzeow+t53RxlsNSKPTQxAvNYbTQ8jd2xJey8nVPXC/xgatKrCnpqjacbPvMs2e4g8gqay68JwHhW0PZffsNWjFQQPtFlahsiQd7SOqAalcfLzj7GlVbX8CaB4/hxcoIbjaygVt1YvQk5QqEbh6LX8cJw9ypoai+5DeP2hUAF7cvZXGFYpi+whwET30kr7UBmFJmhie2joWR2Z9QPUUH7nk+51Crs3zngCG7Ru6A3k/D+PG8MlbfUwhr3LThauVLagtdD/cd7Uh/+W4U7llGNeO34ummfUzNc2lrzHicXSAGi83D4eu6Ntwz8g0eVJvNxeFTqMjxHadnbuYJB2O4q/kSqG8ZD9N1DXGvtiHsUTiExqcduN1KFbVHFA/tSiD16+zGjU1DTrrcArT2r6Nbt3Q5JiCNkl3D4W+jD+V5H+OlPvpofziLL0a14G+JSXBo40yQzFsKW7r/92ypKagn+9FN59Ew9XswaE9258UXyzD7sSq8rE5Ch84X+GmLF6yPeULpMAosrk8Fp4ZgjNt9gB9/9IPBzOGwYY0hCiXZUuLPVMw/U0f71JJ5jrop+ruXkvdNSeh2WIu+piKgox5Bkcte0/Gw4TCqW5bDr/rw0VANXG8/i3Zq25PcxZOQvtEIug6N4tyyQcjVcaUPRgtp/JuTsHlMPm0+9RvPVmjCYJYwfNumDC4lX/nAlkOwUCeX3bxn4EP/UAjZsZvfqOiRSsb/EXfefT3+7+M+ByoqRVqKlIaWkqKBkNDkLSmRliS7NKiEqIQkKiGKlKxSSVFZURElKQ0VympIVkT9+vzuxPcWvB6v63md53Ec/1xPHTJ5Xk07HgpBwVgbUOt2oX131mD0KF8IetACA6Nmg9lm5i0pebRpII02V02CMWYpKBvWStJLNEgxJwh3/ham6b7h1MPjyHNNAD0L3ovjVkpB/QJl2PrwDw8z6sDL12KhO/42HVg5lcPUmrhq0nXcIJwABwUUofPPclaSEILos0e4Y2U/zjlgCHc9Q/DE8nNwRW4i+yYupIEVU+FFtRpvtm5j4dBK7C7YwW5PpHAgThdb/CZy1sKxcMrDBOZ3j4Qb2jtRS7CeL0h1oGKSGk/PloFdmzzIqfYh+DaZk8TJ8RD0fDgUzb6Mp3WdcdWyMRT/VpBH70zhe5Nn4Hz71zgs+Rk99CxA6RXiMFCUTlr5N0izPJpNgn7ymvp9PLehh+WbVHBCVz42/ajHkQJSoDJiFe+68YiGp/pggKc7NpwMoedXPLCKvPlvnjg3qQljxVdduFEXwKdrRWjWj9tQnriHc+9uxmut0Xx5rCZeWvMFg/wK2bZUELL6jtL4ugKacHkbZrrFwkmypoGtpfij/hNFLLan4tYmPh4yDRzOJuHx/nJQCOinvtN/Wfg/a64KyGNF33dwsPAyafnn4EtZDVAY+5Vub6nGKe4veNShYHwZ/wRb7O1RMSUaG3fnov6ZH1jupABboxtofs1kFE9h7HEwh+d1gxArYI0/dG7gxA8XaBu/gSWNglB86wLXFZyhiPhY3nZ5Fi2M18LvMW/xn+ssii3MJrnOfjRVnw7K5sGQPP0l7NgbDkLz56DIo9cc9TkNkzO2ss4wUw6ZK4ca7coQ3R5KicJh9NJ8JfzcJIwrFDrpe5sVK3MHmm/KRbNVi/lXmzqcMdXgD/SCJd8PceRWANff64MW812kEi9EYWVjedYhwq7zwpBUE07mxUrgsH0TaTcE4yYZRxj4cxtL2jZjyeQWVNm2n1xrFOFgySH+HNKNU1ziYfxEDV4wKIvpGIr1boW8POQZZdWuI5ctKuCyXQ25URlfhIvBorDtQ04mBHeTHfGlcw7d3BfPLqptsMpwJKx67o0BsYRABZSQ284busPw9AwHUumvR5sVYTwntZ3e940HSvzMKgLhIH5rPS6f8IRcn/mCpgzBroOa3Pl6Na2VroCqPzog9ziNzAU1wanzC8h1iqDjNhf6sPMJFKgfpp4vSvTf8QFcIWgCi+z7sNr/Ib7bsZ2uDTDMrWul3FfSpL+oA57V9VP7kkjYoqQM66xOY3H/Aly3fgQdn3Oe3C+7YHOHJEWHXuT2B438esIQm0bqweqRitA2KY2kDa1ofVY7HurKpQmj7XjJc3k+GysLt2ZNh7XBw2CTUDgcKDsCxfETYXJXKvf5bAHforMcPCuPpPz0+NaFSuxjI2jZcx6E9wPLFuiRzsUhl7rTBmMvm9Pa4iuQpeCL8fuSWd5TDSY0j0W7w6s59mISLBX3IXWZWZj5xJBDjWvgqtQaeltSihFd0vB2Zh7ee/kZWueu4ryf2RQ4v5R3e2vyaY2XHFI81EmCh3jb/pmw/mM56xk48PHXSigzLhxMHcLgje99OHTWgYfpTWf/v7kQf3AaTGpcBe+z0lFmcjkUqrjzfcF0XFB4kd3Ed9H3qKvkud+FWp8zfJg5ngY+TqWpLnF8MKibkh5r8ZyGvahQksS3dsTjbl8pPvduMnTI+JFC/QZym/6OdSdvpPAIwNUBP+jYvU4+fk+dz2Vk8fkGgn0/tqPz0iv0cMCPjiRk09K/n8Asx5qNfXLpdZ0wagyeoAdlEpB6eixous9mq8XeeCvWja/dO0Ueh5IpSzCVHMNXkzbOgFXK4jAyqxKet5VAkGoMehlvhct+PhTbaEr58WJ8wDcSmkLSMG65KrT8MqX/fTvVPm0VxxRGgVROBB2dBVRZOZpuPKjkhGXtvEB8HIh/6sKKGgXcsvANiyzw5Hswhe27lpBodSJU5Q1nVfdzMGftTNga+RZbBjbAnoOtXOCyA2RGvqKa+BQIuigBtZF3iMdaY6CmDHy0dOMDb9t5ydoyTBHawSorP4HMgV4IareC4CHnerZnCu36rA/dE1K4qV4Z91jJwOa0haR3VAML5m+FTcln8NySUI6bC/C12Qh0DWTRtKYaDCfV0c7HD/lajRzqXRfgywFVdLq8gX3MvWlEqAb86ngPvmJNnFTnwK1P36P2mVoer15BqiQMypnTMPPmE3SZogorcxZjZ9conhMYiS3iQvSmcTML/XjIc7o6Kb5JGYICl9OeoAmwtkGMxs2U4OFtv7nPNoanH6jGd+CDzcvzeKKpM22ufsqWIWJw7Y8eThyWA+OtdUhA0RvsR/XxuFsqkBG0CVKUfUimURj0hhNo/dCh5qmVlNu3jx2Cz5JJwiqavEqUkgUToLgok2rrVPFr6khI0blBBdq+3PR8JXzoPEmxOdt4vrkYvtmXR7Wj48F/uDk5rSXwEEW2vi2D69W3UXGdFJh4edB3yVss9yAHJJe58yNJVUotNoCX83bDSnpLum/O4nqXiRzS+5iCg/pZbncv9kRZ0svUGdzlPw1EfD7wJA0zNjvihFESBmzwKIYj5Zbg5UWduOLWDqxJkwHX5Nkg+ecv//7ZhhVb3+PG19LYVKNDez4+ZDMvLRjrfJrPdTngwVpZ+H4jhmq83/M85/W0Wb8XV6nXQ2D1LNxdvRjXlUtw+6AGtV2cAKOFLnDl3yr48fATD9ssikUjLWnlYkHaGChMhisToDNjES/xVYdj5em08mQ3G5wqZeV5L2mdiSAJisVi10UvLj67Aee4bYLFi3Ug3GQC5xlc5JyT5VTZWYZNJq8pU+88ao8Lxbt2prjE1gRf9EvDwlEeuHi/JhYo5fL6/gT0b9oPK4feOaGKrxRR/R0LnkTxZeEZMO/tRnrZ+BwdOtTQOkAbX4+Ipbma1/HnPAPybV1GT2ae40n7DaHZxo0vHymgL8aKeOf9F3pcUIBxJUM72yADLZbLQJ+uPNqrD4OeBmea2axLKsNNSfXGMvx09DdvU/uMWjL76eV9M3r+Ppt7FqpC+KTVoPKtC6a236X+Pj+ILM/GxV4n+GL7fHRqOwDe1kkcs0UK/kUcxb7WBXT3805ec/AwH4DTmD8+leUW+sHW1/Zs47EZRU4QeOs+wcSh/5p9L4obI+rIfUkQfo+yxkyLDXzi1HbQty2myuN60KutS0Fvt+H7UD9wpImUdek4P+nxo619W+HvfxvQ7fsSstptDHtEj/GyY4HQ2nMBNyQdQDVBwu3V7tz4FuFH/zf2k2+GgmOaYP1Hi2IVzUht7ERsiXrHrzq9IeCSL4nsbgev7k/cfvwxR39S+P8uWbBjPx5/XsUvOndRlfBC2NKViKK/80HTVpfLFF35zzUDkBQfgJ/L/sDaFxMg4UUZrDr/ntun2LD2jzbQr02lnpwGElwyETSTHtCtSyPQw/oHSVbXksyH8yA0fhr/u11EGe2G9DZIEx/ZiEN4ZiYKxoXwu4AtsMz8FvVmScCGGWNAsrkNR4Tt5Wk7VtPXFeNh+8xEeuF+h8TWSKDZnI84b0Y77K/3wjkDzjz900WouViMGwWmQdyBYZBcaIWflp8i6/128ELzAzzb3sBu1mtp3PgmPCkx1JezpoDh3TP4xeUTjY8O4N2OcfSsvY0unfODvkgN1Ji5Bh8YHQfnkcLQW3eKYx8hjNIegMFLQdg64RJGPBukV8mZbLLYjloj5/GoGcowb34F75Lo5NbmnyxjlkT3hWejWYwbC8yUokiNRzjz0krQMdKF4cM9AX3y6eIIcZpVrovDQy5Q1aZbHDBsC5xS9kJJDoKOfmOY3fydLQWzWVIgkRWShhg+8gTVvCMs7stn4alPeUN6Piw7PjTnjgexvfkBhxrWQVn+LJzlx/ArcAqY7gmh5VOKUKynFzWujIK3LuXoeKUT4gQPgtOBbJBt28OjlbzY5JoWe7m6YUiqPxa5iAFpL8WET3Ew4clDHohWgUMnjMhg1w1yvlqEBtrFuDavgComaYL+pdsYfjiOdVvn84KBWGjQnYQua3Zjlbcb73kgg9+vWGJxqAy8WpTApZpldPX1HNB32cL5z96AwPuNrKSjCNnnJuF1yxlcJC0BT42T8cOxRpJZUwsBju9gQogdKSs+JZ+0CBD5EovnTf341XZ52DzsMTxOuAJ5s69hpIANiv65DH9sbsL50j1wRzIR6j2iOfgpQ+v4fax5R50EnVfCxbSzsPSaFIzIdx3yj2J6eugIORcNcPAORdj86SIFb06ChLho8DWZgyHu39hF+jH/N+YOa7yKpP4xK4e6QApyTBeSWwbjgFQsHB+lBvYp6TglbwTFLxmD4dGN1JWyBu5+MYRHO4/hoWUHqb1jKyZs/IVLX6+HkWaP6MsHHfZv14JrAws43J5hm1UeSq56h1faSoGFd7Hu3GuwZn0xCN/dMHTW42CNgBy09Y4HoRPCaGY8CjThGo5LXg/1rqVYKfOFP3Eb33rWwZLd4dw5IAufE0bA4v050FQkgIeyv0Hb5zAWKA+BwGt9dK73BK/4+J4yU8Vh/EgruvpBDnWm/uJJq2NwSedl+vfeGsRc0yCtrBNHpDzHE+8nQ13FQfwYVQ7X5iZD1LppkG3hCnc1vqDz5+24onUtj/vdz5NcxUC3pBLnWz6AxgmNrD5iLxdOzMRWy37M/uOONf1l1HV/39A+k4HgLVKYI2QCjob6pKc9hvouaYHOehmaN+TWN0TS+EhNNFebIEw5NJmENknwW7mhsrs3Ar2sJsC1b5Po6swD6BKSzAO24mT/Uw7k/O6DRmUldPcpQbX5Jpao2MUirybTheX6eHPaT2w2c8Dr/lPhZOUkEH3bSW0vdrLF3QN00FqTNoybBSNPCfOp6FOwz7+YSiz1IanoPG+q/UmzJSzorqIqX2vr4aDEM/w6MJo7yhM540kzbfdRhNfBY+nlxOVsZWlOfycX463r0zjp4gu2HdtHo27kwuFWM3y6VhHw3zPUm60OcWZqtKNjL/5UquQocUnSDjSiVLk7ULC6ndcKKEDoXjMe0xXJ+T/+ouVVWQqdl82t6ac40tMfOTIFW4c6unLod12WCvCo9yNp68mPcLbuLR2KK0DXuPO8u6eYLnt9pC1rZXiLjQiMuT4f3CxWov2Mm7S/25981t7EmapbOeLQT4q/4QxiBp4ovFYafupLwLlRm2lOwTi2ui+HouNyYEKRJz2Qf8QRQqUc8qKf1G0Ynqt+JUcLDTwrdpxWHdnNNZ6DYGBaDP3uO1gpTZ40DQLo08dZsPJUOU5POgWP/zrA3ouGlK0uxi2LGmnmvkQWOHud9h/7gqo1c+CHbAc//3WUp6z8Af/Ss8k5Lo1PpGew2Zd1NFNQHnccnkzFM4Qget1XLBbToMWK8bzCbTpvfnOQ7x+KRwnzUEwaVk9z6vbh1xoB8DzayxM6f2BV1kh+d2M0Pd8cy9UHRFg2bhb/SrvBp55vg9vxatC45QPP920lr3uh2FbbSHcsXSBK7ywNuzQVujJUWEYjiiJaBGDgrAB8f1TIthla5DLyGCf2Habm5+pst3UsC7ycCCNl//CRD3pQ9q8HF/M2mOYbyydWm7LGqc18z3A5bK5KB0GOJFH/ctDrEwY48gZlDPeTjYU3LpmfBA0n7DFs1DLYmrcR1+VtoCUb7mLHRB2wLlGj2zFStGySKBRMjcGNziPQvrIbxRtV8bu7L62uTcVHDsPh9Eo5qLjtSgYqHdg+J5a1F6eBu2UnL/SzgWDhDt42vxcca2SgaH0QVNjo0/afpiRdKjHU4lY8yjseurNPw1PJl5yw5hE+1FeAsvfheCN1Dr/yc2HrjnGQ2m9KJl6rWDX6PjUEl4NNbxLKasvAnc0Pad/IK/yspYgP1gaDfucOfqZ/m27GeOCbO/F4NWEdxdyeAzt37SSfGUqwJVoV1nxZxyMPPQHX3ja62ldLKkpd7C+1mMa8kYUvoSb4LrGIa41yQe+dLTeEvMPGot2kptDJkr2y6DPMHHOfAYio7aP0jMNwVXgVXvW9C6aT3aBojjo8r7qJZ73t4aqsE5eETYPVxZJ03nsV1YQc59woJZxnGUoaFeLoubCP/1z4w3p+cXytRwLORnTB6zjE3jUSVPxyB3s5VtP5Y1fxRVwN/FsuR6MzQlHpmABcXG1OPgNRnG9my5txOV2vCqHNxkeovmAzbbddQq1XR+D5Bh0wbHwMptt7YZmJNOv1qMLrKcmoVdBJFd/8YYbpZeoUnwvdJopQPsKVLXzD6aRjIRaJrKHeSjUKkp6AFVov4fVLhF/92tisowuW97/Q7aH9NbjuHknOtaF84VIO/+sDIjFrWKNuATqUT4P8swZg3noJg4OdWXBODRmpLaLg6jn8N+E59quvJOUR5bBF2gsPSYuDXed8zIxYDKuFheGVVCWsXbyF4+cTbau5TyvqJcknYAd2thBsWRqFAQKCcFhmKc3YyjDO1JpE0rIpStMYRu7YBFmnAsEnTgUMT5iSO14GuL8RHl7fBREbjPhpDcL6r62wc7EJRPkdgnyV6bA7JpiEFs+mu9FObOC9FKy6xsJlFw2em+IOgak6CE3hdPnkdHC8c4WPxRhRsqMnh0TMgHB3DUwVssGiI870qrOMbr4pgAO5kqCt/R+o7ZPgN5LfYbTrbqzbvIamvtrEAlf7efjrL6SjvgOfq8+GxOGZdPPXYjr0XghLVFLg5wxpvJchwcrDwqj/eDNdrRhB9+TFQENiAcQF7sUdc1rB0iIalccb085lc7lQ+ACemSgIiV+XYmTAHLDTLccPdfWwe3MgJZqc4zuaZVBpL0Sqpx9hQuMn1FrRwPOvaYPgKn+MKiyCSu8A9BymhHPdS6ijKgKkrAbwTp0lTPxdgZdOGEGZtxS7e9nCFHV1Eiu4B1/zFnCq31guXLIKn878wWorn7ML6MPL6U5Qnr2BDBca46gGH7DOrsV2uXR46mGAkyfrcEpuHZ4dpQq6UgsoafJ8fCKgS3/Mb9CdkSsw96QLnT8oyr+LTnCzczv3aupAbVYKijvNpF1na8ErV5oSbzpC9ucQzHH5gMcVnfDV4S5SdJoImZv+0o+3zRgRlMamXhfRxHc59ryYgkkHE1hl9QDsyprJmD8FbEJ2seZAO52sEIOLYpk49+1tEOj9Tr4TIvFwqwpMi7pDLqZy0O25Bi2y0uGx/GGeLYgQ8GEXpEV74C/j5TDhZj4HlTfwGzVpKFe4DrHDV7OwRSWGpbjC70tuPOm/bFa2igPLI39w9sM8tqoUg5V++7lpy3fcIhUInaIiFGFsBKvPD8eveBoDPGsxZHspFSkYQVjDNCaXblI5uYQn7Aul30rZ3B1iBV4erSCVmoqThY/T334xiHuvRrLbptO/O6M4pFiVN0/3xXFH39LM6Je0bV4WGfb9x4VuSlDGzfzi7g5a2DMMQnK384IVTvz2dCrHP39J57/+47GxymwprAOxvy9A7LMX/NBvJkwcFoTWq0NY4FQvqj5Yxv+m7cLK3DWUU64PRx6H42EwA5tLoRz/nyzH/ZCH6sNfqKE6kk9bnYRLh614a9MYMHrrSi8jjsFF5+UMK1Lw3wR18GyXwAfz1ahFJJM0pObQJisEO8EgWJMoyRpThtHzESmU6aqHAhoTycKhEv97+h13h0yjiOEKcK5iFrzTDCXhAwr4IWICWZoncfd7QQr3mQtO8sdwZIU9lDjogDA8w4NVW/lv2H0K63kGg3mfuGHMPmj4dApmBc7ljxFB2O9AoGvzhWSyBiA+9ANneJ8hpzwtuvNlqIP9NvApp+tcvkuKF5eqwVf7Clw16zUF5zyBsOo9eFrwBpvd244JS0WYV34gXOKK85+Jw/GBBsjVOsUOR/Jos8J8fH9HnB84b6PV0pNBZsJauqsZw/eXToM8c6ClvxL5o6jX0DNzhF/+Gdi8XZ2y00bhpILRMHuWB+lICgL++AvnvBpp7St/irHqoX6NY1j9Jox8LW7St7BfzNsN6cPTyRCfJ0m9h25weedMLOg+DB7vHmL7t/+oc942Gut3h/U85tDLBi241OaLzy3K2MM1jVz//YETNx7S/+7kvDvEkMTSArzw9z43+BtDwMZp1NmaDe4PtXnuYim8p/udfS6eYlnvtdzQdZHFn3bzrAolEP6dAql5fbxm8STwLXTC0VuQjKoW4cjNe9hfJZSemrdDYLEQDE5NQRmTufRRaj3a7E6EVxoaNC9aCKO/q8GDkRFk9z4UEo1nwpJ9r3nYEE/s7ldj10ZN/O94De65MkgZN00h9tM6nHvaEY8/HQbdFwwo5WIYb8EKdrDYwbkOU+Bo7214J+LDN35lUEJfBWY0j4E/eSvQ9+YFehBmhJZ++3h6+iU6URTPXVtD4a57BrcWTmaf3JFgf2oqhedV0orYICyfOI7HCnnQCjldeF7WRkqfhnwwpJ0eiQrA1A0L+a7WLZTxdAXX9+34QqkUNl0NIaPf1vD3vCQYpjyCcqOZEOAiCW1Pg9lHZsgptmfx5EphmLYCOE/GiVYMd4Tjgs7gPVkb2hQ8OVYpD550HMfv4v5gvugLrZ72F9cvt4KFTUnQpZMLIxYYw14nQbA4OoXPpJWy8pVrXPzTh0J+/ebqf3LQcvQdHPyoxbMnTIWX/53lgRIrPlw5jGaZBWPPVzvcV14Bu20vcFJ9JD6evhR0EseC3d3rYOGyHyutL4GB1xDPW37izmm78Ue6B+89qUZp0xfwBnEN0Lqvg+b2WTyQf4abC0+iZlE3hn1UA8cQfXr/4iuF6qty93wNeBCaAxQ1k1brREDTjCzoKu+n8mJ5LLOcheZpwtAk/h3nSswGV1lhfrVLhC7c1oboa1UU/9yIY0zOYeuME3T2xQ+aVG8GwhoSsFF0BHnubqGYJgX8FCyMT396YYaAGqp2B6GQ4ziSuPYf27YOh8ptFiz3YDMc3bORx49JBG+FHszb9A7z91/lis/11Nt2DpPsVOHxhCU0KBlOYZ6T4c+tj7Aneyy/rZvOoatd+fueA2TiUMq3KjXA2uw4S9w2hpuXv1PWxJUg47EdxWV2g9xlW1Y6PBoddx/C/I9joCg3DxeNl0eBG0Jk7J/LG28E8IOidCpMfUBrs8bB59797N6jDrdG3+VXAe00SzMOpnA4Tp9txK/Tl7KWwT/6tnkJzOg5THujBUFLbzwvnTuOk4Q+8IKDOyDFw4X76jLp99lmWDtsPJ4VWQy5+6Rgha0fHZYMgr6dZ/CCWyM1uElxrY8jnYaVvMu4HiVCllDsCTkInnuFJvdnkZPwUxo+wQSEyYZyVx8F4a968DANiHZ2o+REA9g23ZgDldbg7GVGaBh3jPcsMKAYqbfkei6chrU8wZ7DxbAsUQWSn+zgIO/tHLJ8H1PPP/6oOg4d7jqzyuU3nDh8IS+uiuTordpwTfsu2co2QvKcHL77RAzN/kRxReh7aFDMBeOTQRC78jzfuqwOOeXqkOwgyZnZ0+nR1zY0fp+Po9J+YKhsEznpq1PoxioqnScFVz9oEtttZgn1d/xVLpPLL+6lCVKxMErRmd4+8+Pfpm3wUdwYwoZYKxZ7CnaofgCRJZZ4XyOJzvj9oL7RbVQwajxugVJIrR3yuj1z0DH+GZjKVJGMSSSNUM1l5S4fzDywFaqsKrDDNA+S7kiAaYQhphoY86GbkuRyYg4a/6ijjabrsSdxNavYfeVYYXkqGy4DKjITWM9iKWkICuNEu9k4alESRAjpg92Pp/BZ4y/vzX9NttukwbLFkbeoFmNJTSN6JChwzpKfpKZoh0nlC2F+8nVaQE44f6YhTBCuYOMjqaAxaIxxqWdhZ+RD/BXxGRtDH3OAXjeo7CrE/4LGwLfUq/hoaGY3u/TweqcRXKXZyw5uHqghNADVv15Ba185tVirgmGIOiUfPMdPF1Ww/ItVMFo5B1eufUjlaRqQcqQOrA4LYmK0EWQszMRLvVNI9lUq+H/7y1nVqSjea8WsF87apuugf8cllJMeA/vfKKJsyVj6aGUH/8KJbUvLwDp/Mvv93g87g39j67YprNU6FcY/DCCnKSV4QVMG5Gpc+GviKVbysKc2/el41mAv2wpE8eS/WuC9oIcGrywGe4Uayt+qwQLbkZ+cHI9O/Z9wXOhSdFyvz8qdmlC/MpWUci8xDyrCXhNPFp6sy2YuT/H18w+01u8ZvP/5Gc/fM4Qw75k8dfp6Wi8ohYpSw2GrhgOcaLaCGSOm0O5rx0h/AkNZrhFMfmFAh+IeYuDkcBg1VgH+K92Nyp7r+Jz5LBoln4VxFkNc3js0l2GDfEhqKyQt2QdeYTdAy4JoaV0oX4M9+F90P5herOfva2dAd7oKnFAt4TfnV8GBeCUsPLwVY1pu0KNgKV7+ewx0LTqL0V+N4N6gEdcYa6PmH8Qq5WU4OLaAR2VL0oudfRT8chG9m6tGBoEINxSlWWLvDKhyG81KAQ742DKFXwx1ibdaGGw6ngnv6jUxL0UQCrUy4HTQKny1PAZtZn1FoYg2iLpyBpeOOUWuUSWkUzWd3hqNhwO7f+ODTFesXlnM9y840qLf7lT7egFdOqIGzp+Ij2lGobj+VLBx289mhfu5Mq6K8qcfYg3nXprac4DlO1pwi+UaMNncSwfjDGBX3SS0MakCMzkduu+1BM+Fr+TmWVP4/glVNh9tS79vh5HHNim4/a2KRr48Sqvdf7GC7X848fVPXrNLne3vZ1Dlt3EQObgHnZw04YCaJy+R7SIxPRGUut8J/X/aSeawBcjNu8fCZ1zhevggytvog8FdeV7x6hGWL7SjppZ4jvlTQEnT5ND7Tj2ULHxAA0dE6XHlMNhdNQpO0DGul7MiflCDYe0xeK40hvU0jWDp4CH+GNYFJx3k4N3LY+C9IpknB/rDH4FbOOck0/UrjnzQ/Apb5iyCXZKlWCtoCBIPKlE9n9mzZxZd/HwHi/0FcTBDk1ptp/BH+zDSCHnGy1RmgXLYNFT6tI58nedgh+8FCv0khX4Bf2DjDAHwH/Kd7BRZCFwkD3dMiunDeg3YaOBMS6N1MKHiBH+9eoM9Yp4xRG7iojZv+vFIB8Y1foDgnhF4xmIDH5fPgj+iXXCkZQ8dv7oRPL5fpS0oCFYuOrDxtww3zHkAayqNMLRCiuzEZWDi0+8copiFp3/rgUGtA12yEoJpzwTg7toHKPRwBp0IvwJzohTwzJENWCizCz+b2dMlPzna/VABtFViKKCkkXJ2tdP6vjI0v/aZLqnVsYO0GdvtyaUXw9vQcK8qqB+OovaSw3jumAVz8Gx4d7KTyrXW8tmYCDpw9g39HPKbqQcUQHxEIdsUtbJLojmJ7VOiYW0riMe64/mTHXgoeqhD7pVQ5r1J4HAJuEjvFY6MicNjw0bAmvR+uOL+hBpNX7ODRwW6G/2lB6Ej4eJEH46XDcU41fv06uAM7j6xnw4NppPhT390SNkOc4wk2TBRHJoKlKDl5AkS3rwMrN/9Y2ULW5aV+w9SuyfSBFdRmjrrMNfWzgAFvwCKuXIXumWlUSMsnDcndGNiJIFPXDRsk+rAnORict2jBPeKo3H/ChkIn2qJFsvDSfSLAYWW6mLpynxa4XeApOrSuCJZHDTqqmH/6jkQ2bEQjcJewtCk4x7xSzi6fy/c7jsPRv2SqK6JUPpuPu56LIVLdVpwVGYlfTxsC4tXmfC7CY9o1ctDfFBKlx4pAbhltJPE3eeQvnwK9nw5SK0F7ZQwMYpGnpuOPQFZXLHPnm/bG4GFQAdbrajExX6LqOflP/xP3ARmTijB+PaReE1tJD4teA6j748G2SdKKDEplQXfvObhvQJDZ/OW7uw/BuONI9j6dCbSxnP0fKh7xn7Ow7guFxr1+Dw89g6EQOMDrFm/GbMrR8Kde7mkEqNHu2rHQUBAFnx44I+qWmfgiMlx/quZiOfSYylLRwLWBVSDpOgrcBIRgVCZ0Zh2wxSztE7hvPJIGuxNobenAkA69TQ5jCrGT9a38FeeAJilP8HL08ZSQX01H3n3hq8auuHZE72sB3/hiXwGPxio4/JPIvCobD5/n1IBB9+dxVdqC/iYpx7XVFzF9uhhFDFJnKd/2ASur8XBc3EJiueosITaUjirZUe7Xx2mzzuu4K74dNz5vpF946Ig8sI4MFK6xx/lduMfu3AOO/8PIqI+oaRnH/+oreNoT3G0OCMOx6RkQOTJSZzRYInJnvvo+JCL6NhGUMdPTbpqm07qU8/Rs4Em+B08DjJmFJCV2X7sLaoBkd4NeLDDBzKezKIRGvPoPyNhKD5WiGOspsDBGyLcfMAZY5d+wMCccXy18Cjqfs/GM5I1hGe6WGG5H73QGA+7nthzt/xePGR5m+zG3yTvwVKw3pQO4reOQtjnebx6uD6cV5OERd89OOWLI2S1SrDw25tos1aVNP0yYHOTIPSPFqPVpudwXSVArtICjLe9g+n7zTg0/Bj3dgmTRLkn2q3P4isLy7FtcMhRpCVh2EsGiaM/uGzUdtTPsaLcPyU8c3Abms6P5oablahQIYdni6TA/u0OPL4tBaZ12XDrrSso/q6X/Wav4fj2UaDpehNlzSP49nExOFxtCFv/PkcXx370cBGitaEmVHzoAnYWumDX6/V4/HYzpw0XgppTb0nm8w9e5J1BVJ/PG2pLMUn0LcfZlVLvhDP4+tsgigvKw7esod2h/wcc/Xvwu6w23nUqpr5NolSRJEwDr4ZRhUE3dnyaBqIClVRZ9hjj1thS+MF2CjTTgsM189DuyGqqqdOjU8luVHqOoNqjjDU7r6B+izlYls8kdARMG2KU4+Bi/Pw2DlenyZLKqhFQPnI3HNtwhGUXSqB4URG4b5nHBCWguvEYLlKOxYNRQrz29ER4JvMErcNtYc9cd3boOoqPV3mih/FJjn1yBHZ8LoB5cmuxf1AedlY542/tEFy+MQKkvdRwnZk8KU98yb8+jKMUw2zI2PSFL141gQuhuuAyr44NdPzZt9oCz6oP0tFvBrSzehnL1gjQDOe1dHuILzezj3D4Tmt68vwj/tV7yfmio8AyqIpbzi+Cmf0vMen9N7YJHwvBPw7y96/JMG99IW569BB3BQbADK8E3P5aBweyjmOCxkuUEBsDYip72S1yGtv7iZLPsG+oa+vJxgs38rXbL8A9i9lLbgEnK4+ECV8eY+N9bS6/ZoqZ66Ph3z4Vzp2pzZEJYTj1QSXUlVmgT6YqRF2vgcIZNVCzdzsJHF+LbluWo+GaJ5j0KY38n7xm/SgrvqkmC20FKzggqh96JcbiErFeWu3zCVaPeka3jl7HmF+63CQrDqa5Y+BUnSjK3z5H198gLxXT4If6lTRToIberJ0HGjcbqbNlHrT/MYFhCTNxVNUxvpYQyfomt2F75C7++us3fp+7nrzeRaKtjCIlPpMCG5/ZVPHFDQxubIA9tlJcf+QDLrXURfJzpclq9fR5shcNmSo0LoiG2wEpdFTUm9+8F+ElXY7gPl0GOt/WwOdfS9GpthCLNE3gzkQVelvmho9Lw0hI+Qqec7ZHjdJaNvpQg26qwew2tZ5sDbRhnvFNepz9EGwqCmDtQT2webSYDg/68Jao0ZhankDaQTnY+G0CKFocxeXeS3DSX0l+rbqK47/lsrpoCrZVHMH3EwPZOiyXPj2eBOMmJdFImb1wOTMPzg8Ph9pNuzlnVw//0HVGTfMp+P1IK1UtF4ICzeHUHF7PtZvU6dRJR0jW6WQl2QR2g1vk+FcYr8wrolW3poDtLDs4ZOmJY+/sQ/cIGwz31eBxOIb/WvbAro2qsCNhLk3KV4PYBxaUOFYcVn+To1IPSV6ZlIgqbTfIwnMhHG4K5OE3FfHnVilQkRRgTe3xeKCvnvIsXqO19nzasrMeDBcXc7HnQ3hx4yA96ZIAlwF1LjFfR2/2j+Dd76y58b4wfhHZQGl6XrzuvAIfyzrPeFsd3Cafw1KbTZTZ3Iajax/CxXO6OLsjneIS78MvjSm0/JI3RlwxhBVmtyHr1j52+qZFiW+sUGtqFtYE/KSZX5aCWs1+Hn8sgQY+ykH1gxP42Oc676+rZMf+s9C12Jw/YTWWh0rAUbNomNF5ChqNJgIs34Qn5kzneXJ7YfdmGVJLv8gBzhMpSQbZ7sok/nd3McC7KRDgZsUqxyOpauEu8gz/RYrLXSgqthr/zDNDzTMq0CR1hqXiZ8PBvb2cfPsv7ppgiw7GSqQTexUGzX7SnEt1JNP8H5QmfqTr65RBZONfGB/ijdazXXhw0TQWgH6sXB3Fdg4LCZc3gGx3Mbhq64OX+VsSHltCz8yu0LccN05L3ELD5kmQW409X8w0Jw2pTLTVGANGuvZoaD4LQu3EKU+iApsH9/D7dOCFlwKg7+hzEqgNYvVzU6Dp3dD7iFfweQxR65RxaHd4DV+Kfwsf/B14pVQ2hjqG4ORmhhuNNVx+WBW87obytuXn+czhSAxMLscl/q2wQfk8ao3oA/tcBZhek47OfI6kZ9jCn5oukMEFGDlrJTc9smeDiZ/hqv5CCB8uCGu2fORCjUV8XmUYTW6eyo7zf5LNF0N8s6QMXroYQmF4MMzwUIX5LQ6QLfedR6ZHYOPsO7zU4xD8WRBMZfONaernDPqbfoucTgoCjuug4t8baFLkJTh2PhBEVu7ANxutoWjfemzVW80LPDNYdKsBmNWH074v1fxlxV1YKKiKK40duWP8OD5efwT3OO+g5MImLjMThl8O9rRlqQMuelQAM2ticeIEHdLu28T/TIeOw0CV775poF/ftWBDZBeIjung8dLGpG4ewpq56RxcoYd3kuxhspIpzSldweXSYrBIbzNW9qTSEq/poKg1ng87NUL32H4Mu2ZC03qX4OodY3jTak3Im3mAJKsOk/J14ryQTTC/OhBebLCEjMv/QGlQn96fGYlKxgTvP4hxvUwKSy6vwOV1ArC6LJWbpo6mLeo68Mv2F6r8lwjBa3RBY+ZPNjlVj4LLfNCoLIZaXrwHU1t/PiL5gNzvPYcRjcYodmg0aH07zhcP7aEujcMwp7Echc+8wQXfTqPXVD/4zPfg9K/R9Np1Jjw8W8oL17ehsm0uf0lJwz0N11nxmx5MDgimJsfdMGnnO/j3TQumbQ6DlSJrwKKzD2Y+SUePifUgopDPnpf3c5DvAe7LEYI8RxEIKhpNrb+aIRJ3UnqjKKWMXomuX9JBfnEtzvvVTdmh81F/vD4syX9Gc2WNebzLRxDcPIrTIz5ThkIg7twnBY9KQkgt5Q1HLhODaUq5aOCiwYfEJsHhn9P4h1kQvY9txaM5Z2DquDTYs8qWnvnPgH+xn7n+lTUZistR2bJCnOe5gXuokjUtrsMd6xR+8PQK31iiA2JbZtPgmg4G23UwTUwZDeKSaPhrUfCKn4O33FRB0bsWUl5Jg7ubBG+xEqCe9CyKiVnOPgFB3Lc9Eb/mKNJ8r2SObJ7L81vkQPeZG83cNRxnRPdRrVsnq806BA/kijhBFenovZE4Lno46OrrwZt5Xtiie5V2rj3ACiMOwKn7E1lWKJM+GOmjurglZGp/H9oNRjCw4Arr/N3DBm3tbHdmAV/wkKJfi29xvngCtFRPw1tD3bbvx0S4dOIYzJZsIo1no+j7/A56XDELvL17+fIqS7xhdRE+Ja4l0ccqoF0iiosureAvAj707vMRMk9OIro3wJq6i3nDtaWQIvQI5bNHQPaTz1h4aRH6zHuBk04cplXHx5DV12TS9ZyD5wLq6MPGFnBfqAYLumrAYUs1hi0ypdV9npB1TIA0R3UOMXg4JVxpgjlrgJd+14Qdt2az/DzCYYIZLPfHkHJLwik9bit1hkfR4KN/WDL+KwQKjIWtCS0kPmEEVCua8MsR/+iKeTGILWulph276fp/RXS/5C8mp8mDy9NgEjgbi4MzN2H41dn4Ynk0ukjt4YXOHmjS9A5Lx8RgT4gqXL1EAN8W00CuJPqv+EFp/jsgx8kB/+QzahSGkoLIJbwkYQQ7Pi3kUQK9HGH8G5aL7KbCGyU4604MmqT9wK3tPlDarExOn/UgzyefA502caBNI++1HETrgA7KdhmkdY886WimD/TtMmbhUzOhzXchN3ubcVqpBr558xY0pwuA10orqPnuTpf3J/AWSyF0ejkBJNsPsMCWbP4Z6wALNzThr5eF1GakCrZli8k4djQIV49HSR+C1rqVaCCYSmEbVeB2YC5Ju7iA0xJbuCvwEd/030d9UV8oOw3wMCKZYrwTKHueEJk/WsVpijaUqfsKhI+r4gnDzdS19SO9Xy8AzsI1MCZBi/xLRdBMwRtub1yIksM0sKBWBFd53GCvwJ908f1wSBdVg9VVyTQqbSa2fnkEoZufwU/HSfDipjw27j3MH6K2gZeyIQQ/28+ND3IpTiuLn9505byEEs65McSLjAYUXveJX7rFsXihHDxZLg3t4+by4Zp38POEO0yImsyzjOw4e9JIzOsxAYmnLZR7keFE6S5OPO6PK3Y0UZaCOF5qacZ7K13poc5ivpwsgWoSpWw+1LVuNfGYb5bNw41CWWHRBVz0zxqtk/6Si5sTHxFMgtFyztzgOxsWKpzEu23n0XjjR2yue866uWFsMUMafslK8LAQKz7yqAVtN+pCwthgFFzjhasV7uCloeexcmE8aj8VpZuTPvGFnddxUnUpfrHUAZK8S3ceh1D27S762HABi3SmkcnYvygoMggaqilUUfeQDjXLgK9GML3cX8Xn5HLhwaN35P3HDI0VxDjz13Pe/6IHutx/wDYbAL/n97AnaBEZZHbDFO0jtCf3NzhOS8Mzo0Po5tMUev+7EcfoS8LohhCIsRlyGaep8MZLFH88bsHmK2NwMK0Ib3Vbk2SSDcrZTIFVmTlQeOg9nFubD+m6+bh1pBU363XjNd0pVCYzDw94fMBHcUIgYjuLcl8VwCRlXU7FI3Q2W5Os1xuA88M8+HjUBk40juQvggzR+w+Sxk0LPF89jCMdibbkO8PsI79AbrEY5Ui34u5FIpQgrQhTyuQpVnArySs0ocTzXFbYVoKJV2ZS74YCPBBRgJp+W2n/BS248Hw9d+Rno9jw9ZiULMqzJ+tA+7Jv7PlWE4d98oe+qknwoGwqDGYchYEhtky2U+GS3TZwc+JDqgtSxuLAU9C3Yj1mayjzC1+A6IdZ6GOHFJkdSAoOHuinbku+AZps7CNPdqob+ed1wNJPI2BU+mwWPVrFeUuu0PQT18ChxQV8rcbRuTIl0qpBPF/xBLPXqkF9szmKVzThl6OvaCl/BnWfHk4W+M7VM8NBIe8fvYbvfHylEhQFSfPRN054YpIHHDsciuXT47DV/hhsSy5iPdkWNEpqJa2/EyFkXinbPVNEuyc1mKa4E+MntaPa/MNw0EAeR+Br0jg8G3PCRKBKMJfbI18w/9NDlVcxfEZflRfEevLLYdnc7Xgf9yrWwuh6aTAwfMe73maQ9JpR/LVdEQ67ueDfI1EYIRTFCi4ZFJtujfJvx4CbaQ0t+LESg+MTWDLaBATvzgDzax20pzuFZmeu5PawPlgsqge5v46CvqoFRQ6OItHsAvrQsIZdnXU4xqibw949I6vqXaCmqAfBpMH2OAlcI1yh9d47uv99FY7d+RE/t0dDysY8zD7qR2H3tMFfzHDI9yJxbKEnxT4s5W2vNbE14xAHaW7ho149rD6mAi6/VQAZXQbB9kNQOlubng6U0rqeW6jcUMJK6+zg1ORLuHXPSAqJ0YBK7bvoO+k3NstXs7tJKJX/NAOhNCmwVJkNT1UOsli5BT3aoAIfH4xhmSEPurf9HA+cNIHdGbdpa4UEnE/+j7ozSqH+oBoYNhjCvGc3UXThE3RYd5+iF3RBxEdnWBBfgsXtq9hCYxUWjU6GFC8JmGJ8kzUyfdhG2JfStY4SxwZTpoo53Lbr5wQPDbCQ+YL6J/VgaXIDP/Sx5rW2qUPOvgeP9b6hRZ1nSd/lOPz70gfye73Bdusc6JWxpuRVg9ixvIBsJPPgm+UhSFMqheTKdlb7rMNH9FOHXEMbOrSk2V5iK7ZP2USrqs/j+N3F3O07jARN/KHunCofeZhJj9cJgndiGWpkymORhg4aPqnlLtNzaHklgr1yZfiFcxIvT3fFXg1hmBHjjraNdmD7LRUbp/7htfuXUEv+Q/yjaARhA/vAaLkJXLaQAYPejyyYmUNW7eLgFB2HG/rE4V7yD/oX7EfN7hmgWG+IApWy4FFZhRsmPWV7GwN6k2/NXWXWWPMwnTuuvYCHcks5TKGIFBsmg3vENupw64avfUHwV389/ZdXC3LrmykxXprmferkjj3GJKg/DabmZlIE/aMnjoM0JiyOwXMBPz4XRFqmu6Gh7x36Zj6n0psjoHmFB61iX/R/cojdlTdBied8uHA+HwIfy4NTsSPV7hvHoapjoNKplPvFnSjCtgUtps6gGmVFLjX1JY0r8yF/uDzG3BlNd9cC5GmPodNty+CHsRRn1KyFI4VVIB6yh85drSLBnCvQr/aZNx/VARfRHLhumsq3R+8Fl7+KOJA9D+647uNTUib45GIdbXKvxIQ6dfi22wwdJI+ATZUITIk25TMptvzl+iDG/rkISl0huLe+lM8ZGv6f3f+r8PAoCYj/haUXH9A2xw0YNdYU5f2juHdSIqx7cwOf5AnR94NT4UxMCIq5qXK3xApuOfMUytfth/JrV2BRzC7ISVPGC3+G+PFKHc7+NwXfHVsFUtP20fVcGxC9HsabtkdhgFILFti/oP7d+WxvIAVO4tbsKfkeD1if5nG15qSQ5UUjMuXJvP0L1C3JgdYkUZ60YTR8TA7k+9+SWehuHxudWUZig594wtxEEpryH+/6tYkCL6zFObYCME7fhN2sFrIKeqDataXUlfMcVQwvU9/3vfiyXJvfaK9H72UjYMaxXdBeqEbntVv4TZU0ULUWNHoogv/ILFSxVeRX9/0ocWAMnIiPxJsoSzsLx6HTuwmkEjyZkk8GEB8Vp0d5MtyxJZUMUlRhe9gr8nkjxzEyBRwrMRdLit/ygL8rom0njiQr1pucAue/zoI9qp4Y3mOKos49/MF6A5n95wj37n6nZ22j6IChKrj2r0blMwqgrlRPWf6WIDlLhXZuWk6HZr6n6GhvHFN2h3ZULyDznbn886IGqKYep7S5kZxetByaDtrALUlnjNV4RBZz8rm3T4ueFmtjRuBISHxTgh8sVVF1WQlIfT0IznWykLzEBpb6H4GD16xh/mI58t2lAY3RCpgTfot97QN4b7gXaK1YQ5vflpClRDKf+vSMbGcIgJOxOAT7yODzf01wX70QNgln4CLpZLDJuISBj8rY0jaHjXxuoF2RCMyYTNxj8Zqlnxbz4vrx9LzEHafc8QG1K0fp/IgCutUSCpsMjSHlWD4czH8EuhL3sWvsJ5Cd6o6Xpetx2oXrJPhGgCZbtbGBxDRYP/U6NMj68TXtPIy1y+OJtx7S2+TlFGK8GgQXt6Lzn4nwL2IS1O0LpKDV46D++RTeZzTAM8V0uWy/Lhqo7Ae3qyJU+/gPiK3WgN6bj+i60yDXZ6xhjbgs/PD0PR7a44tzgtRxovcZSFkkjq/sxGCEzwRYKnCTz/t3Q4C1KwhIu0NUbTOs/vGILs/bADal1riuSRR+lyTimanVNELelDdPDSWjFfNZVYJR3mo9aWbF0wkNTR59cxa0LKzgPfcWUdjmEewbMhoPPlPFfwcNePuJNLwt8gbEx+fR2QAROH9XiTokxPh1sx86feqC1KZmrmtuhcB4X5BenY0qJn50ogjhScwPuDvxIo69F8DPvj6F6h9jac9YDxz3aw9P6KpgUa0i3Oo1DtKyqyndPA/2p12C44ofsSRFeKjDL0OJzTpa/+os2y1opw49Zbi38ynX6r2C/V7D2PXHE7h7swmUx67DpHu7eYOeICpHioDeIiO4kL0Kvhv40/g2T5BIvAdH5/5H3hnfOcHsBWhn2TPnNlGQhyHcTouB+MgNJOZ9itd4uEGaSym9Uw3l5CuW2K2ixxFKxynoiwZMP1XK1b0LIWhLLm67d5/rFRh2XVgJDat+w5TCeWBhJ8Hju8TgW0olTRvpDaf2iNCYl86w7ukYXHnKnjM9J/LbsP9HkXm4Y/23Yfge2VsqqyLJFiIhUdrk16ahSGW0KERlRaKB0EBUJKWhRYuykqJUKoQolBIVRVG83v/geT7HdV33eR7fkzQQOm/IxXShzKCQf047hJM8WsFaqBHrxVbR6xMAxhnO4Ls/jCo21pD6US34enI5lj1nyFLwR4fvsZS57xs61J3BunhpNh78wPaZ+9h6kTbYbvajG5KKMCbuNXDtPTao0KGxo1rp5++1qFi9HhM7f5DpVUuYdksZXn52BhKzpFslzaA8+cMQ/38BubAhVnC5iSNcBvFXnR5Y2EdS4Y7V4PEnbMizpuI6qzj+eMmE43vicff4ZXCpu4Qjto0FuTEuIGsnhy+bHGCt32Y0qW4E/VW9jI8zyCR/BM8qcmQZMWNwKdIlcIjltuX7Kat3Hw+UHYHRA8n0cO4O9Bk7hzb3vwf1TQx/L7RQrrQlW626xJ2uphw9zATKdcpIrKSDt3x6j2NfxeHRX2IgsiaRW4/0gOH6Enj/rAXvRJ/kjgwvqGqOwjbpQzDNYx70ZOnCB+8Z3GXRhI+rvEl3dRX3jh2Gnibr8VmOMc6wt4egLBfWcB4LN6dPh7x/FbBn82GS+BsLt5LD8N2vjVS+4Bp2/HZks58PadYFZdhfEo9XYCVX/FfJu1J76ImYHGX56lFfzyNOaF/CBZ8fgmWkABwUl8WMWgFc1beayms88YV1N5f2F+CCUao4/8pTWpm6hVcoSULGj118Ym4fnvxvLXzq+8H1h1zB4ZUpJ+aZUMznQ/TsbhYazDCDDt3FIDV/MqUN+BHOZCp87oh2DstwkfFjqJDwx/O/BtHc3AJUtg3Dyd838SaHdhaQ0iILbub+R3uw3q8JbLYC3/1exstfW8KS/GyIvzOaL73ciLXfz5L+nDD4tOYYTz5rwZbJw/DICjMMKxaEG7r6aHBCFvf9XIRBij5sKXcU9r+8A9sMM0lvyVv47HWU1mnpgZ2LFY49VkBaMydytJo8tl6cz8eVKiljjwFtM3gJhin7uDxFDpqCVsDBEwsp1PgJRbacBmPTPpDY/4fV5I+DxY6L+KNZhVbkD4dkxZeYfPQ82XusZNPnv0jwlxsHH/Hn+rclNL3SCx9f1qdWQYCfe5yhtKMbCnX2wqUSH9yz4Bg8Cu1ENasG2LBhO55qDuHlf4ZD6sUoEnp3m2O1j/DyZyv426k0Tm49DpsHzVm1VobX3bjCP9UNoVu3Bg8df8hvcp7Di99rQD/9H5+JmQCnJr6AppmhGDQ7nrzWGcFjiXXsZeEJ7+aE4bCsZXz8iAc90PMh23RzWh/wDXXOOPKaDxLQfl4Ab65WYAUHX3rdNwMa957GwHJg7RwRnLT1GsqWjsOTMQRjgufDjbHRtP76aNzVvBD+RG+EURU7wf5VNvgYzme5DzvxtM9IuPXiPt2dXc9jpS7wBGcbCrV/xhIn2oFn3cWnTRU0fzCHQ7SkYdnZi2iufgZ1Zm2giWJ6YFL4GdrOCrDlmT/4tECcL/BUfC0vB1/vxVNJ6xsQnCHNtzY+oyqXNtroIcXNHUbo+ziEV1Tv5zVR5rBdyJ3EszLx0Tlb7n0zFY9vHsSnAWYcE7IJkoIkePicAj4yQRCm/m7Dp65TMGjaBhYPMaXZ9wA1V+/Hkv7bjCH6mFpTDt+fqsD8XUcp4Xs907inlGPVwTY6E/naPj1a63qHXvaI8C0zFU50N4NTaUtwDArDDlslPii8g+edTuRx/j3w2WkOFm2fgLNMJoO2iAwsyF/GodE3AS8vQFutn1RrNZ5m/hEitXel4HHaCxXd/5JLBYNMeCNM3x8AL+Ij0Ou8ITgqOENP8UGyea7P9oHjUWanMb8brQ5fRZXxmGseXemuwsmv+lkvIwkm1PeyxcAw0p3xkj/sAVquYA51i5ZycOhvUh5VQ3N6gtBglzUo9l8jvXte7GR+jq4unY55ARrgeX8G7xbSxp7an7xIZwWsubkNj1R3ctvsZI6VSMPGaXIwYKQJS4Y6JOi0EUuS5UBu4l1Y9uwluwg8gHe5D3l74AVY3vULm8LGwiH1a7BYvpIDCkZTei7hKr1gvLtyEp51XgGUnUwLiqdgSdVEOP8qi2X2jMLMwP9on94ylt3zGLIjnpED7QevRdfgmvdHOuY2GbICzFHFSpsPTxTFY2prYLX4XZbLns3hvqtA4sddLjUJ5tvPBGH5qcdQmy0OtmMGeA6cZvGXlvyi/ix/zx/ig5oU0v79ge+3CkHHI284FqrGV9/4cAIcQcXb4iTSYM/RcW2QYZfOfTscKeaOKdTUWJGoQBOcf/GQLqpnAL1bgu5ltmCbG8QPtcNggsoafiM9Burv/mUByaEs3FeBM+P6wOVdP+4uTac7NiPYEXLwwVfG/SkTIUnZk3v/LcR7CzP4jLoGPN7ijBqne0H+rDjOle7j3QfOkwXKw7WRhXx199Ae74qlDbduo/6eSg4L9QG1ZS+prm0pm5ZdIJU7FgCr9Flx7zvakp2LA34TUTNrN0l9reEZrqZYcT8dzp3YAEme6jC/+BhlVKtxtM0W2pckQuF1hWyUYcIJ1fIsmBnP4XcMaPCrDMSU15LTeCHQ3z0K4lvMSGHVDAoKbICL7VchYsEj1rTWgL5jamAqIoRLPnpga/Awflg0gp5dEMfpt27R/Vc99G7nWjh6SQNih+7W8l2XyPr3Q8pxe0I7Hk8lwz5LDJ52j/ctmk1vPydT6oQ2fjVbGTTzPTBrZSrcCrGHceGBIH9oHX1JX8O7a9bjI6te/P4d6JmrEfypHCCLCZng7ZGMkruk0ft0GgSUnsezB2RZ6kohuSccxcO39aB7ZxX4dUjxvGhH/pR4D2yDr/FLNzs08XuCKa+7qGj1MvrWPxImxYji08Fe3n2E6FLwbapsu0c37tyjdc7pbKtnhTfGv+W+eHHY15BKqZlz2fx3ANdVBtHKN5Np+Jt+ND1hSTHHv1KY/Vrc4KQHJ3RbOPavL+Ye9aELFqcoypNJc50pjNgiCf5zTCFN3oaFOmXgtI8YrZQup3nBW0ks+yNobnmCSx2WktDufRg0TpmLpVfQ+P7JMHXvVaqJdAePuKWU8uwLprT+xymeJSAjk0E9btogeWoyXyidAGuzED0utYHvondcZuDPRh/OgWLibfBrHYerK8J4ZLk9mFQoQXnAbrhVLwMGRd64THUj+NtMpPbZtnT3cQ1cJk/wDQym8hdmoPWfFgvHCqHo4zh0iAmD9XH3IP1rOtTP+sLpbTEc/mkzhSmrgaqIPNg+Og/7x17BFWNewpIDV6Dvy222uf4Ejovq0t2iNfjsmQLE2ffzHGtBsBhikH1uX7F/zz10F/+FkcLdKNjpBNV739DiIU7cE7GTfjr+pbTp7mRi5M8iV4ahcY8Ee1qOgkKfXbR6ZTa/yjCCzsvdSLl/scjEC97/2AYr5quj4ukC0O3uAu+Mhdx28CLO/6sJo4N+0c8bdXA5+hFkCV6h3x5vePTNQtiw5Bn6hCXBh4ZlUNChBEdEurCoqWTot4wEDXs7toyVxWnGWjBu9ztcrfSPFZWVOPS6MrQZK0NZfjapFKjxoFAfffNsxKtys3h2vBpqDkbg6Ao99l42ESq7cphzBci9MgYFHyJlFHbRkgO6eLDIE3yqIiFpuzUukNOHFCFF/iH1BDvP3AK3KSvx4NtHcNEplYPbHGDA/wuNKv4NxT8JRC/nkEL6dE5LM6DrB5GOSSfThdJDkJQzlYL2jaLDva/hQYguJH1jnlumDoEtE2mx7QO+kCkK2T97qPpkPgyMCQeBvMm4VcoMojol4YVgPCp7yODantMwc1Qc3vu6mkLPvkL7Y+EgXXIBr56ThbrTC7lqzllq8RSkXX8WMe5ZzEYTvuHP76fpp6cgjrEMI/WXCJFXlUnsWDmu/WTJgpOd6dBtLS4+VceewZFoHbACZwonUN9mQ3g48IaMH7eygoo1PjQZAB3peaC8diNJwiH6mrkFfLeU0JSbBvBx73yam7SG1lYtQ4PuKaS+4TCW+Pwki/X+YBd4gh8656JcJkNfUCZezqrmXO8YnLtGiNyfpkPuy3oYf+w4hsRYwCzWJetCZchanQNSCiFsq6jDIgY76ancRrwZHsKv91binK5EMtNRIcxUh0Ors+Ba5EXWje6l7guzMaflPI29t563ib6BM3q76bGBJ0y/pwqC1Ql0aHUh+1k8QYFxpXh5aSb1PjyODtYn2ffjRL5YMBZ2/DEB90QN+LzICVSyfpDhAS+wWtLOhUqp2PviCKYM8YDt8lE8885wiMgUg7GZV8hnrguViT3AuHVVkLZ4Ex2+rEMfDiyiAw8OwIrhxpDdGAmOk41Iy/IzG5Ql0PiKtdS4p4fWjtOlqHPnOFT9EZ+cawUHG6VAPjkWG/aG4lm/DJTR9QZ+/4jGCf7l2t19fPZtNjnUTwEhqRDcZncLc1+85g/mtTjz4yFYV5JAP003ccL3Jppa2YD6UsIQsusxnqx5zEaFCexK16C//g8sjzfDqx55rHXjPN5IHMvSZsaQdG4Tp5vl06B1PNoFu3KBqTF9n58Pq2dL0yjfDxCuH0b+BcIw73ASfZI2JR5zAbZKaNOwVmvIjJEj0VVeJFu8kxbbOfPkAhEwtzPhFzoJ1LwMqXRCGb51vk3mxpvwRvdzPnb0CZl8WMfnvHRB4PR0uO0wF53eqqOfEZODji0nK6yD2FHjSdrpGU7V/0mTE0Vh1pUZ8EinDY2KZ5KNfz/png7Ae5Nj+fK1Tup4N5fvaknC04VSMMW9hoJuboE/7XUYoBLPbmIF2C9RCvm6bmguXMlJq2tJ2t8MYs6/5f+urQHD3d04skcbdHNawb/RiZt2POOeuPO41yeM9IzHwzurA5gYuBQMyr0oebIMLKkEmLfuKZwbcjD/rFKWeXCWzcw04HW4LA5G3WZbT3WOeBuM4SG5bGI+n8SrxMi/qAFS8jTomuNoMPhUDPcCl2Hvu3h4OmIyCu0QgWDHNyS/JIpgeAhnDJ/NemVGoKRyFw1ke3m8kMsQ828ju/XfsHn0UtrX5MiCz2YjHsgipwIZWBrVDuan8vG1YwEJPwumZLvhdEZyMfk7NULObEf2CdBGK8UJcHpSOjftToS6Uksatvk0Wg3djCDFS+DwrZM/OUUN7X8au62ZApclgiDinwR9940h/u8Kvh2uwNP/2cAwKgff3dUUrjie7vTpwuE+DbwQ3YB7iw9D6e8izuoawKtTO+CdVhknflvMZy9+oGM7VaBxqTcrVMXRrqLNoBY3yLdKRElpMB/WJWwh3cpwPrO0F//8VgbdhcPpweXj2Gh1gG59TaLUweEc/92XH26rIVGfUl7oZgBBP8fD2lHGKFXRjx5XGtln71n01H1CgU8aUbMW8E57MK+9Ys4ZUw3hfGUsxnw4RoemMP1Y/gj3iN8jieJDvOenGkvLzsLzjboQFCcL2hc04LCCPjYOboQ57Uwz8rRQPSuZ8jSieaZNC4rnCMH6EhmIFt8PzgV3uPeILOWIBpBUnShKPa2gYW5tCCvlcbdsASUGi8FP+WLSMo8kP9+rtOi/NJRLVQbc94lHJ6vSlxsxMHK9LSs/mwQPJZfyj+LFFO49jwprptDHgu087mEw/mt3gfDO1cxBeljfJgCxSf/4yKjreLMjgJ/SOzK5H8DB98qgYfpsqlo3jNLe6dDnUkv4HGYOUpVzQeL5fWyyNqHiOGlWfPGLLxxKA/VjTZz4Yhb8qjAD6bMTKL56AKLkD2Dc6pND3nMGe8dP5eD7b3DrwQQObInENZ/FQe1nGYt7anPWqwa899YfUredgouxPhS4cBdGesyi6vxX6Cg0GTzU03Fy70KU1lmMwSpxOOXXODSbPZyX9pSDZdt2iKtJg+z9ivCyYTzWeq2CPdOnQvjntbx342fIyq6FA5aBQ9z8nrz6BLGxTRsMdR7Q4l8rQfZmK/bUrcZ9t+7gqxgrXFBxievsbfmsUS0UVUjAvryRZOxlTV1FZSSnGUZNCUXgniNGfvI5qKa2nw2dA9i8xAzKxQYhY8ReblUeSVe+XaRR6btJ+NA8LDZXx9vG+XQEdVgySRJKkz3oieFlfvRdgGwN61l5xwdybKjHiTPlKGX/ObKX0uWn6+The4g2SV/YRPujn8DjmEkYcsydujW1ITroEp1vP0uW04dT5icjEEmRA7FJR8hTbxBePV6LoTNmwKVWHd5sWA5uZrW0ftld8EuVg9pvfjhpRAt8fGZBXtNc2SZtPi6JXk63RGW5OeoF7+//hGcTVcB+ewL7LCiD65LRXBt4GMyGmENfaDqXvtNlzy0VoCVUhB+PisPwcZvg3bEG+P1RBW6JmfGji36EnmPwXtsoXn7IhDTk16HJFQvIOuXM+xwf8PqjdaS84w4KLzxCv+VmwSmTYfB2uTlsePaO5902hj11z7hq9nYuHj4L30va86mwBTQx7AVg4WFScJoN9lnZXPTdEs4GvaOBK7d5zQFNnHJ/LRaEj6TZb7fir7lL6PjNYJwgIk8ZM6Wh+W4Qd1/Q4cWf7eib/DhUsN/Nc4KKYeITItH+e7xWuJ9rBI3BO68SYyOOYsJnMT5m4gTvE9pAQe0pRokOgEWnHiSME+bnayZDrZch6FT9Qd+yDt7RVIQWr4O5pXM/2mWdw01zzPFWwXEotFCBQxrd/C4+Ea+ISA254lTM3LodL+rvxDDBqqFNCKJJJvIk8UMBlB89oLaxo9HD6TxNLk5gx1F66Bj3nfSX7IXXVfKwXywW17VMAGHYja6Dq1HwaxvJ682h59cbKeLbNVilg5Q+p4g9HGfwmSuKMKfkG8zaYT7kkeEwYDcDBdqqIPCqEGT+SwHNcR9BfcklOLlTGyTMavBaRiRHxN+AvhWDOOXCQRwb4c6dFVnoe2wTf7RdSMd1JsHTmSthwXFXHpPUgH1hatDY9pefHNVkO91AHtM+nAeDjZitRCGo8za/bj0OrVvPsttGRSiwFGOTtGb6m36MIyYokpOUMcbkCcCBuS3YoFqN7bMW0K9H2bxJfBw/9l1DIJQD6QIWKCbjyvkeliC8pg0LM2bhiJFuENIXwuNLuujNxmYwlGnEEx+2ovmwVl6wUAni3rSz1HxRvl/oBb7Lf+CSmJ80T0ILJllIsvKHBaTZ+gm9g1Ug9EESb9ZezI42GjzXKQ1udP5i64cxdDElnZq+9fDYEZsoS1EH7O54AJ7pAN/zK8lPKYakJCw4zqkJtOVc8YXNezBfdZQqQsXANVOO/cKDIVd4Fj/TDmT9DVpckX2Wmo6Px+1laeQ2uQi9y41hIO80fplfxqYNoex93R23yB1FkTcF6DXSBX94HUXXqia44WUAlmtMMSynGf4oCoKIcSvYDusgq4P7YZRyLZrla0PDaEdKiRaBBVG5IN9jCg3J/Sh93oOmrZoLxoUBpJouCmpLl2DTpWisf2QCpWYTUdroLr5aexbqSixIfoY2O/QbonH/Vky3LKdTz/fSmrcKILz5JcT0z4MHKkch9P4nFjDyArP5C3DMqUhcvWoZu3Xso+SGETAj25ZkVU3QRe0WfXpfgbxUDp+2r4eti3woqcOA/ZL/8PjX4hDiqMk6ed3oVxYOiQ1xoFn7kzdcj4F8mwoKz9gHeX2r+GaLJfRJ/GSpJYhjzyZhr/RxUlc3A7/4g6gh/JPfC1hCi2E0r7quDakus8DslCoH9URyV/AtktnbyyFDHTlV2cqWD+rJssoe3z6fCqt2zMGbJ87BgxJLOvF9I5il3ULp7LesPEySDz42h1PnFOHBEytIN1aDG1a5vG2TPzenTYUFK6JhyQg9cnbSwOp64pftQ7m+Jg3/1Qhi04apYFMiTttfZnPHxWL+obGFzm85R8v8G8nBMxfmlwgPbdd1WPv9GBp8WQyH69/iorzF4BEsjmGrlfldrD0PKhfwRUtj6MHV+OJoMl4LsuaHLR10YvEDlF/7CzdFDvD0wt0oKqME2npaIG/wnEMnZcDJwUR8pRlEESeHYdPNBXxT4S+/WRoCSXu7odfLHOa7e0Phufd4y6YX71f18WrDYMxdnI3DNO3o99j3lO+uTBNVjWG6VxjsVOoguwPuZKOH4DJ1AstseYyB5yZATEU12Ob7UGWjAvRt+oAXo2dQx0UdGH94DqquOsC3jT6wfVQTq69pRLk3xNGlavD+4yiqnhCK8WuZE/RLEVRiSDnZmxQOv+fjDZ6sevcNdVjKQcTcjVh1dBf1f53J2yvP8N55LhBd5In3FsVyUsZpcFk6hTU0RsIh3SKQ4gW8tecSes7YjWXf99F/8n/Ief17nLVwHYsIumPIm2lwrWs15P8M52OjLcl9uxrvcnCgWqu7tLsvD2dGWePXIgl46j8NRKscKX/9dfC3z2Kh35dx/J6jJG72FuPauzEtxx87zVxBywtB3/A7P1J7SGnN9zkh0p8rTK9xj8hwDpPZQOUv3nC0wix6Ym8Elm5h7D9dhhaaZ1J1VAibhnfhshE7aUr2bz74nyfnv6lmTZFRcFr6FHrVn4ZRzV8pU2o9R74cTtY3VGneRTV8pL4e6NUtGrZGAK7NtWT5ZbFodWE/dIdfRRP/YLLIVmIRoesYfbMF3CYZUNB2GVA8kMPPhghMzsmWZ6wbgKMfpvFczwfspnqJFvxRxoI5p/FHkQqEjFwDk+q9WGS/ARhsGMuD98M57ONGTNqhxBFxErypdi5NfawKW8JS0TV8NZ4JfgL/TieDjGETh8kGQtj+SMDR8kN1zsBVMAp2Cjdzb3kI6rtsZnX7BzDWYZDim8t5kZYRxvQoMky3hlwNhG3eJ+F18GQUH6VL03OTUdBgOwRozuDXKUmgsrwQPM5lUXH2MDisKEsDN2ZQXGDP0H8cMeTmvbTFXJE2ScnTyfKXnPiykca+04FuezGIPHYNWxft4+0FAfAl3pPbzj1jryeW+OSPD71YlkUyx9VBoLmdzHZe4kAdbd61spmjoiyxSX49nTN/SVvGMh0ps+DTz3Xgi7QS1x7ThJ69RqS4IxUP/DwKrZ7dFLjiM8kH3QD3xe40L1EVul7vhtruK3T0RwtPSKuGArVtVG/qh6ILd8Hc9f/Br31JuN9QHDY9bSKrz00ss/MpHctu59o3AXjd/AJrFW2gMQv0oD93Osh0iUPTq2H4Y14xBM7soKP3BUmzltGuy4Y+u88koxXdNG10DnyvQqiI3U5loQfBbt1pGLlsN6UYCMHJDIYp81TworoE688fZKfpOnB4z3o+NzKGN61aQIYiLuB+250n2XfC33dukFXC9OaiI6UJIJx+U86+v+NI+uZ0CG3dTqHRJnjY9BdMnelGy872g6LBSMj6KgzJUmL4+HMTtt03x4e/LtL0tiN0PkUKla3+suKtWLI92UaSD+VAPKKU0o3f8oSTmvSuJ59fXyc8Vz4L9VX72StGlZ6aVlPsKQuINfxHak4fcevPPNDctBjm9YahjXURLBZZyRl8lKWtbPhU8Xi4XP+Q4rZuolWBYRQy8Qq8tJgOK5ctoqW7Ksi0VxJuRunR5x2GkP+6ku90/uHlc7fDO5YgE907FHR3GurmzaHqXWfoSoABbAYZyNDX4qdZypy5VRLXXrfDtnR1/jndnwsebmP7432ofXIDdt2WArMn2dRxPAU1/kThmIgnrGh/C0Nb3uPuiHK6s+E8Hu2YizFqgrCFxHhfdQTfH3+Hk61d2dxtNi9QKIXvUtcw0DMIahyl6XmpJLitz8c5t5bTKz11UryUjd/uV+DN9tUw2f8Qy9e10NdLsvjAwQj8vZTQYowJFLEbTNqaBWPDstixIp5vz1WG/qI6PvzjCQoXSsOZjz088rEWF+74RM5WiMcapvG2zRvAPBlRszQXHs7eCV2HJkLqAluuVi2mt4oB8MNgMUY8/AyqRyLpw/Nsatn9ifvDFXDmTE3QTrWBWRcWwwybxWietgUXLvgHR08W49aSTNJpqcObaSNATkse1N0DwMB2Ho58CrjcDEDUdA+4StiyW9AGzJkhQ2J3TuDl7SPhku8QM6q5ctchIZpy8BzNeXeNL0e8xtNfkrn1VTWrq6rjqAJDKLwtz2dH6HNl+Dn0+6SDlxatJCreSfFbRvEO01OUIxyBI9JHQ4nuGVztXQ2plY543VATar6645gWfRglYA5jiivI33gjaVQKwumtK1gfXsKxk8tRY9UznmX9jJJkuvlMzDJKO5sMi7NHoKyAKDQrV4KxmTjOujfkK8qJZPjvHMxN/Y9dpe/Q36wYkP+1ltQCR4G61TH+NOkaPvSay58Sm3D2nzH4qGU7X7oaxjJ6F3CM5R4OGxwG8oeKcbHNEkjzfQTDZ6dS1dXtcCrAl5bJpUL0u3Wkp/USbB1N4VvvCAq17Yboq72wZ5os7n6+DOJKfTBg+HLwjNsEXWIq1K9uAD1lCuj84TBtPCs5xJnhcN91KaVP/Q607SCrdoaCUW0XDb6eABIHj5LcoTzO+GpNRvtSWGphGeRdiqcN4a74pc4aux47sE6PABzJaQF51VyaUSsM96vCODFjDSolBGNB1Cd4sVaCNWqnDvVdEYp2vcYvf35z5NfDuH3eNm5W+chboxLofsNwzrrQTHp9TvBLBuGAYjmvuWSL5TlFfOlNIz3RGEe+UMmnrihTYO5yvPrJn5cPnwrxj2vRWHQlLB02ihv31nLChxccfGE91/c+4Rk/69C9eCLa7BCBnafe8tGGFvgrOo5f6r4H6yv6NOjwl/4TDGb3HepUmz0DjIqkQffeAlaiJsrfN42/qCSzVdJ7OvvCGipPF2PwuC04dlU6/a0fDzvlLvF0TGTZSBf0WqpF4S5KkDkhBdRf7GIf62dcBlJw0tMAXMJf08GZg3jufRCnTuzGys5duNriP5Z8HAemJTZ8/vYDFhYYBguK/oBX0Bcsbo2k2Rufsu3rmbAlUYw2/R4OuV0TQClrMeY2q8CG33JcOkmE4r2VSVBlHd6SfYMxypPYiWQhWecSNy1bh57nERT+fOSdu63Y2lYUTCbMpIJUF74U3E5uW/7DFPEqnHpYmB9fk4G8rjlQIlkED0X7MaY/mQuWd+Oila70pzmdstWN6LKFBy3JEYO0T2dQ32sAXMI2cs+dNcBn6ihdywnXCgmymlgIeR04Tp4Zw6HmhiqWhn+DqyM12StsCga1W3BKgi08NiukhgcvyOT5Op4wRg9yv+5B++M3sb3KGndYiKKb7GQ+LD+PdRp3ke0cBdrRL8GKY4zAbcZ+NnU6D7P0i6kw0RCeZE3kwUxJPKJTwznOxpQzYioEZ1vCcfdvNG+rCv11K8P/UmQxSlKbNEIfoqTOW2wLr4B3yh0caSIO5ypqYdA/Eh2v5YFq1EKUrPsGM7x+gWzySZ605ThYOJzCsS8nwavhw+hD3H7IC9GjUhVDDqxsgktd9WQVFUKV8j2Mr3TBV1UQfou8IIun1nzpTzPMUviIgxlFVGrRxHtlAiHw52Ms1t8KJgfV4MsdVUrKcsUDG67QmtC/nBknDRPkOyhV4Tm90RQikdTvJJaDcMN+AmyTNoQ1VQ+ofqoIzRbpgpkBuVyy8jG1wWROueuAGC0Nzm/38SojD3xuWA8yetMwaOIUjPmZDuMPjqWINSIo+mopPTg/Bu55LOR7rt/5uIoEjE/yYLnMF2Tp+5lznbfzlyYBdvgvCUdeGQflutdZuW85fRrdSnVvbPl24QBWnl4J4fEzsV/fFoUejIX9K03gKujQNqddsGRuNGr80MLD+be4otEM59735q1t9vBuSiVe9JSENxbuoK8cheuXpPDOml7epGkBjRXmELq1mssuStGuvjMQNkwFotx6SejbLFg7r4RTfH+jUOcEeCYgA2erjfjP8K+YK74K19RYgm7nM1hUMZojsqIpIy8RHC6P4EozN/qw8zUnNkvToZS9/OC16NA2HufXax9DS+kIPm8xDp3qRGBC4w+caf8N7+NbcJA5SBt1pcHj2G9ScnDCmacmk9+4bzCm+RO/9Vak1Y5i7BPgyCqRCEbGY+CQ1ny+k5rAqyem4vD0d2y+4Bvox/+j86s8OfaKLSccFQKOlgCJxI00o+wF703ZiUm0iA9YRECS1SzK9alnrYFSmt8pRy+y1KEncgKmJacxP1DFiwFB5KpkAMue2UCkcDj40BV+qLGWn33Xhgvz5Hlhzw26vtKNrRcMdX/AFg51G0N/bAwWj2zDJLcNGP7YCFwMSqFDq4pjRxijeI8hjbRaQHXe++ltnAwcfryb8x3n8NdFerA05AonP/DFA5a3YfqKlbDxSw9tS/HkqwNvIKc+h9KMu8Hmninc677Jsz8PQLLMVvi724JfepjSxr+MBjqpeEvQH3+/V6IKkgbh0iwwc/KFJrdFFCx9GYu/vKB/edH4aWArrNcwort1E/BXgAJk+d+jIMkdFCxoj/NrlGmw7z03uv6EXL1RcGq0EHxrRdr5aTSILsugCNUe/mQQh6naLTTqfRI1tMyhjd6n+Gu5FydeEuSSUQjbxeN40/s/pO22EL5eFOY1O7bCxKsH4UXvP968/yEoFVxF85E6sGK+DInu0+ad2/Tg06wzsK9lBPPvExyoDTA95yS47jclE7txMG73eVw/GE3TrjvQvdWO1JidgAJ1fnQuXJ5ePTjPtVLvIOvINHDS+MnKPyMwsukftzeLgNKFATrRlslrV0VStcZV2vvoPN45ZgZiJYHYfyIIrcQV+IWLDvXxUBq6Nbl8jD39CHlA9zRPsgIy8NY46s7z4WsGH/Hf22PUUDKPnL4l8tfrzbhmUipaz11LKY9kQOKzCzkXD1Ku9WWu2FmLrRWtuPfZZDKuaYB/Fy5A04lNnP8cYdy/Y2hrs5qC2AyScAOkXs+E5phjkP7rF03uN6VT0mWYsk0QCo6shxtRchy+uAJDap7CqyNjOMrrJpu47ySxj9W8ROM+5SsJQKLINVo++jjeNC6CUTq65Bk4ir2TNMCvcCJ+/vEQdriZ0+PDOlClpALazhI8y3YZP/F7yteql/Lt+e2YO9ELVstXkDmvQLtyZdi5sRbiHlnRutWX0fFoMY2SmIIvTt2nrspyKP07B7fVXga/FXqgMXEqqK0KRRuJTjK0WctvkzJopAlh+V9v7nRZAKfLF8P2B8Mh48gn/PDhGImJCdDv0XH0X+4IWjb8ElwqzAfJgAVwwKkYpllNAZ2pA3jtdBLvzNFG5ehPtK/DjkJFR5DxrTi+8aKDXBK68N43DQjt00Fx+xI2LVeFxv6LrHEmhw22vec/Vetw3PcRqNHSD6GlmvAquhgrI4Jp98S/lPhKg870uWHh9S04S7IfFWsQbk2Q4dAeURDb/p4vSW1Ck4Bx1NFeje0HksHzP1G6MO0cd098wBEvzlDOPimYM+QZp+f4UVvoPQwZ/wOuf0/FNr/fvMHfE+cckCfhsr34JnoayKQ6YmZ7Ov5a38lFiVMxafkWtrX6wd6u4WAjNx6uxxfAzfNisC7OmqdeBZ5Ul81eqyvYbNJ1VJHbgok3Y0n51HYUGQyBxLnC8OqLORT2LCEZ9zw4/OM3PoqdhbqHb1FsowZfMNBDRcXN+PToFHgpsBCjulQYnm5irePT6UTMfnx7wYjttjVz3atq6tr4DGDxMMhcNAo0TknyzEkr+KPQNF560I8e758ON25boNiFYJj44CkM09GFi1ej4HLTafRx3gcx9in4/29p0yZs41XT0qDeso68D6Vi6QlpcHiyBFdkReH3pwK0uv0dHTV7Bb7fsrl6wXos3afABbI3ufMvwwivJ7ApYzb2Z1nQdaphbI/HOvsfcNJgLjYKDyONiFJYVKgHd+W/wDO9Y7jxlS2OeVkHv20bcaOKD3l8NOW/seWQlPoapmRqw71hx/HsmmtQPn8Bl3WdpQNxOahaKMQyHjb8plYJ7osdR9WblmDeeQzO3c2mjf9aQUY8iWKiXKjTKoefZwtT4ABy+KAR3HUyh+5XjZBzW5TklLfBifWJuNJwH2w3Po3TKkag8rOTIHljEqcYi4Loz0QK67nBs4dNJyuLo2y3KJtLI2UopfsyLK9ZTHJnL5OK0hRY9zgKi56do5shW1i4XAIvdmxjVTU5iNtAcCytlcJzM+HuJ214t1iIfatM8J11GkaNEeboN39gW/oY9k3zhuzK7ZSnaQCC3xB+qVdzYUgOVYuPwk369+HCOCOyzl/F18oa8KdjHPc87ESdkNFgJWkCm9cfwu23ftAFGXeeb/kZ2/PL+YCAEy7yrAODMzEQMVYd2jREaEl2Dfj894ErK2TYMfcsKcxy5Yzos7z3lDM3O9firFMycNksnk0TXtC0gXI8l7QVUzuFePXvKTxs4D9KWerAP6VLeO8YdbAzfw1XXBqpOkEB1xz4BIJvf5CW5maSqDflz3rV8OHZUtjeYwyKct/57aKVMCluL4gGjIZfkcALEqTY3bUQ1t4+C63Bd3msKcPdGdUsqaaJamP/4aRMFzra0Ig7JPVJ+Hkt7jJvp6M1irjDUQSm6jfjFIUBTuzajn4tnawVZYCnX3bwhchMyJcyhrLsY2A2ayqYq8dTSW4rdyp8YddV2qhVsohTDxIEnBElFZdBCu9/Aik1ujDR3h8lvo/BgBHf4JNWEI5JfMn1v65ipclHEvF4QAJ+kSQprgauvI8tKhRgkqgI6s234Q//vccpludR/dp+qtv8Ezf4b2XpicNBZF0q9TuF49WXf6ChQoP3fA2BEse3OH6lJH0FC7zbPRJ3malD2eMasPQrgdqcerzWo458KJJFzTdTccZ7CmvYg1qR91j1lSHoHk2DzTYzwWjcQRq9ZgkJnygF+bq78J+NOB3UfUYRv2LxE0+Ei8u9uDSjBhsnHKC3AbPo2KgqjvAvxPSxU2H2eEtsN/6KIwR0oHydB/8uFeBt7WU05pAzPviyCfSdV1O0nhE7nvrLMQX72c5HBBwKT/FjpcV0MKoOL6/oo93bC/CfoxR32YxHqYIKnD63l31hPFQ6EU1dNxXcHfXZIWQHzOvwwdnzpWDA4Ta9FFjMJ+kwRGkaQ0qiLFWXfsXKMbvx79svqLDvKIn0HET97x/5V98RmB42G9fNIvjk+Z4avIZBp8c8LEzr5RcnrnPJ2ADaMMELMkLDaX15N5qNGQZbXtnw/Dn+MNsvAaJvv0KHpvV0WcGXRo66zGo/knHz96PwRU8Nimte0qmd/fQrYTsOdHui8AttyPPrZfgVRYvMfPhNpTfPGLSAvPhIPOimhxUxk7jp7w041h3Kyx8vwMING0nuxULS3n+TP7logahOGMTfXcGP5tTwm/JZoHJ5BLTbWfLb6/tIdUU4JGkXQuA5Uzhx5TY0yzHe7/2EARc+QIbgHHq38TR96toFqfcKcEB1NGz+DaCb4A+/AjvJR8eUxp2/BpEUyDsX9kNejy6chV3009qVpmzXhNlSJ2meywoKltyNpxaa4Ee/ROrJquJJrusw3qwXX0WJkMFwPbCRqsTuvRdhReQA7zmwjj/1VPHy9wqQL+dNe3p+gu2ub3DloBlUzv5GU9aNxTt7AJVPBePbExL4+GYCS5/IoeiPI9hB0hZeB+iD7XNnnlF5l9MNL8OOhBNoJ0k07sMB4BlxdK5pB0XsbccX/gSHxLuxdlEU+o3z5kC9fnha/JQGA1rAZQ6TXt1oXlN6mhpmDjGebQRvuG/Ci46/p9bhL9lh4V/22feGkt+d4KWe86lY+BFuXKAFYccSWXTwEUSvdeZh023xP2rgwQV7YOSRahJ4GcK6A6vx8301SA5yZslSZ1ilbIEPNjuxVZwgV/odADvPDhj73AINzjzBnYbjYPjjEViUKoylhko8M/bTEMM00Z3+s7hWexPOyMrltohMuJlrBteHOQzdxTG0dzAKvtoJwnWR9/inSw16TubQhIxwPL3+KuqqaoHUxzr6pDcXLbNaqUFzK2vLu9H7hwPsq6NKFU88ebTGIhitqgp/dzaQtF0XSX/4iA8HZtNT2IMu3+u4troT/n1xBQGBXbihXgRyzvpxTOdFVLseASdlisjpyTeoO3Qc0pVu04iqdVyzpptmRUyGkFuT2LrACVqHm8IyJxfSa7mKpVejeaptI/UZV/DJB4o85/VYiGm5D7E7bpK7jz0Gb5zHrS7WOP3Ua4wJO08e8a7cHx5H40LEofW8Ay4qyoGQJGM+83o8bMpxQ9XSIKIpN/BxpzdkRmaj6jkT6E/3wXUvsineYjPm6o5gEeP5lOdkDTeGlZLrmb/w8c5R0rKShMRhv8F9+QAcHb2Vl6SIUGVNLN513o/27Upody8bzR+2IpM+dC1OpTzhh2QvFU/3uuNQVXADSkv7sbllM158489jGurwqpoJpD0v4YyLGthm5sUxq/eQq0wdTWg/xjKx42D8HQu8JB+Etz8rwC1+isNsbrFVUBmFVu5AFfkwHD9vM1k5OtDWvyHcrnkD/1wRh1fj/mLXBmtYS7foRssNWnEwD0z79uDy4mK2yrsPA3u30O9UdRAeE0nWy23xz5LbfNf0PgfPHYApydU8Z/ZiyA9OppDb7iDjOx5cLj6jOpk7+Lc3A0xEX9OUkDlomXOSPNT3wkk7WUpTTYLm4yNBIikI8zd/570CLVCp0zPEq3Kw504/bpHVwzMfJWmMkjEPWgLEab3F57HToSxxKhzY8xJSd8ykL9l+NNbICWv/ZsDMhgSwHCcP1wX66dvpsXRN/Bk++F5HtenxnN5cj3eqm0hm5x+scDpMrwcEQP9tB1Q0B3BOnjGtsRdmUfFqXHVOhg33OeP+IkMM967BT3esYN3TufBLYSfd+zoCy9WO4yGtKvwnl8AXD7jg/YUbEX9K0S0hfdgoq0cc9JxHdCXAK9WtuPa3NItYG9ETKzlU79kADfLl4H0W4dIxR1S/MoCyby9jw9twMJy/hpf5SsIrJV0efycYPD7rwcwcUVC/NA5nTrkL2RoSoBkgC71THEiGd8GwQy004H2X1XcQ/daWh1vV5yi9/Dc7XXZn00p/vF4vBpukC+Hvks3s6mcCoWt38ff5srDEDPFmyAY2b6/iuc4L+f4DFxj/eh5Pm2POLYXbuXSSP29WHgFBVju4sHYh6ey3I027v3BdegFvvrERr6lU4DozYWy8FQzj7eRhi4sEr9Ivwm+T/OHR9vFsYr6YLzbbc+HhADaVkKa3l7x5vIIl1AnF8gjX13BgySEoUOng0/XlqO/eA/N0X2Doogiq2piO37rEIXuDPfRNc6P945kWfAgB4XM5MNv2FCyePRqUFKro06YWWOtuDMF5abBF+wpGXs7jgJHn0MP/LNm717LK6UZ6WFcITd8Pk91WhoPWYlj2Jgm/DDHV7zVNLB2bxu90BLHO1gEbpd7iwXvvOLNXDmY/Pgr1KyeS15I/6NyZwfK8gW1KDnC9eSY98Y2EXX8DEQelIXyuIgon+EFtSDvKPXelXtcGXNKRB7+2baM0pU+0ous9xXWNgt96aynyvAbN0H3ERgH/4fxZbvTpTycHa7+HJvF8SBaOZZ9v2lC0+id21RdBl9AdePijkxIrBCnHdhvPPz6W9kQ9xIlTXMh0HMPJWYIsyt8xak4lfYiYCjk/akn2309KGyNJKQlRLPljNlX7acGejGQyTrbgji+iKHVIDJ+cewtnbt9gx04nutK+lGUtm8hkvQFUDd9Ip4uUoCj+Nh6YuZAzXUXZlIrhx7F7fM5XGL6WbaENMUN76mMNBb038POXP/y+5iMd8rgEBscPUsQid0xNkwWhF1dQOt8Q5qtu5hwHQ55R4YmTilMhatNdElC6CZqvn1L8eWE+v96Y67ZLwtgpp3Fj/Tq8bLGdH9+uxkltvdCXbIN/4kdCcuYFKuuV5Jd7jUDtjikFTQvHX6FnQUBQAYV+T+TZngfZt84XZ1fMp56GYlq6zBiKRo/Bu996QXuiOD9qdkehZy6wwPkDlfks4QfRB7HXToIdNHThR+xxSlmfwz4zXoLvp4lYsGclbM21B//7IyAh/zvH74+gCReHfPTCDX44xDRdHSo4siWLM65YgpZ5HfWYy6Hz1jPsu7iZzokowNTr0fhq+HD4UfmOkz9e5NES98kj6A3/neDJKzI2UPmvXHx3ncCsexpbvwtDeb0NRB23MXP3CQ4abkpy4MQ64X+hL/Y/EJEZB0aKChD1QJkDhY7g+ge5NPWCN5jUXYDM/J08PtodrbpXwjopKbBVfQJqc9qp1ek77CyaPpQZNRbyXg039WRhENNhqrsRtY1ShX9L2yF6yKvnCU0D+ywPoOvn6c5kG/reco9G73HBp6P2wUIrebA0rsKeJQM4aH4aTRSek0iaPnnLv+b/Tt2DZa9VQaZcl4PyjWHWNweM2mACwVIr+JTDHO4SNqRZHwXBTXMi9J6dDlOMSwjOT4BD6T9wmtBQLnTWQN7IYvh6/hEpN1zEhugidIwJglUm+9F5shK8kvuInnedoWP4ekya4smFRXGw18QMHTy60EBlEWYIFHNKnRKsfIjU4rANRu9tpNZllSz0oZmCdtVg5JRusvOVROkAO/RPkYGJy5ShZ143e0ev4iXG+vQsdj3t3B0OvjdnQ4zEFLgmt40mSSmAv4AXOXRdhssqY9HOfRaJakawb2ExxKxtxV0PU+jAyGUk8WsCfK5eBFEVdzBv7Aa6bZmCzreUqOlABiYs8uXFWbNwtFsV1zwygGU7I9H1Zh5Y6iVSx+5GLH3xG697HMbzty5DZsFetMkcT5L7GRZq99ES63IWGWZA12dfgTN2ORhq04V7BQ7B590vofl+Hx77MwV8D0lwn9g1dPj4Ef3C/UH28WK6dV6TzrpWkZ5kCQ6rLKG2KoAzGjNAdt1vKBWzgY6mP9AaZYrlWo1w/9YZUpqxCaJv7uXQnZIw49wYfO0ih9p7jqB74yhavkUG65fms+MXEYxfORtb70Xi5e8SIB36DZq9DtCPb4vpQ6gIaB3PB/73m7KuiKGXSRkGnyvmhjsyMKb+IfeOGk5tA6NJTaEWnEe40df+UbBlsywta59I3hl7cZvjOPDLG4e1UUls/rwTQ/+uwbq8eDTs2IvL1gtTnt01euQzgb0Cx8C05eps1bkZppd24mrL9+gdmIvXT7hwbehxWL/9Oj8q6Kb/WoaB1Ak7rv6zD3avySEZc0esDylimasfoLevAyKe36EeR2244aQIs9W+gI+QFrw9nEY3dtTAU+Fo7nCIhX/PlGgwWAhjDddwzZPRkPmnBF97ddOpikqa83ECVC0egb5fRSlgnSd5tyrwdKHnfMZcBfqcq3mg8jE5D9+LedvrQNozFYpa9rGbkBq/CtuNkcu/0lgdMeC2OViUn8va+eF04GgmZ0T/pfSEGXxO6CRnJCxBv+ADKGEkCw9E9aFDxg7Ha7yCD6unwtxSY3xkPI+mB6ziv10a+DAuhL+OFYPDHw/TyD1nqGx/ASuVrMF0l/N8TeMr7zI8DM+bUklG8Dktea8Obn2XQFk8AnTXaIDHuwmsvPoCqL3+C+M2l+Mu3QJMSbTkeVlmkKakxD32m3ChTDXUR8jAMilFPjO6Bkt+EpuHlPH4tfkUvlAWjpol0+dLv8jvlSPti/GjYe02kOh3jnQFRvDbTSdRaEwc5W8Qhpm7A9Hu+AmKKU/Cpw2VaCSbg6VLzkLamUAunraEmpNeYvUGMfDvPkvRUqtg5bIv6H1iD3WdWQJtIS0skbGRfrr6wNLms1Q/RwnujdzL13dakmroIfiauZzCB51xQ+JuFF3ejO0i9jwjcCeoXpQDjjVHudJBPGl5g25aFrJX4xkUflKPeS//QMCGyVyLwli0aCS0lQvDug+/WHDCPxi+TwgOplijvc8e2Am9qCF7Excub2WOFAAFa1+IGjiO1nH7UdVzO0w4eoqeDyTzD71lHOt0Hk7GPICdJ9Th6/NmsD3pgAlf1FGkPwtzv79mt9J6vDgzDy8NMXrB4h1o164MQR3r+IzsF3YUquIZGY4Ymh0OEqWHyGGYB1od3ENS+0qw5Yg5KA29udYtK4rTyebDku8pIN2DFzuM5AVCgtjt7UEKlvtofp8qKA4zRfmhN9ZvWcgZW61psZMmL80PIitlGXwvIsBTys9zSoAY/LmXhab2gZgr9ANnS4Zj6bMZsGSxM6ht+o3zMi6RopYXrNhhBXX/I+4830L+/j/+Gu2pKGlIqUQ7DUUSRQiFrMpuh09G0rCSULJTMipaKkRIKqKkQkkZRQolhRahol+/v+J7831d73Ouc67r9RyPW6fmNF2668ZJH5LYvjOGdHWOQYvqCQh+YQ5ZviHQ5d1PlVLj4LXVVLxWaQbzpK3w7VYZumf5k73GJZCeoiBEGatg4KJIjk03hNP3B6i9Sprcr5mipHA713Z207/gJHzyWABd166n+9p95HQDIF7LF8eeEMN9m19SafkeOpO4gY6UOkLCjCGmCZeC05+jeNK3UWBwyIYXC67n7AMteG7mMLg1V4eiG3bThY1JJGhrDx2uy6ltvwQU4E8OOW8CxpNOwp4b50nh/U2IWrSQXE5/GOrTpyjcSgE6M81h2hJj7l5SBYlOO+lRXT1UPRtg08SxWFzzFCObHrB9nwF2XLQGNalEXLA8i7RXecGsCGKrvKl46YISSTaZoK1rFZyL9WKDmuGgKa6IHz79ZIueeD5Qr0mfCo9wVl4z9X//y9N86lE/z59YCSGrTpeSXW1x3LssKHBsBFV1RwzqfYIax6bCh4VV7KmdwO8jpOCNwACkPvwDYZmCnJDxlk7nHcLuM5acnSTMM68eBtXehxwZNBFu+RrxkX9TWfKIOj6ZPeQVs4Xx2sJ0XDCzjDJlYyHwnAYXCwz1EdoLb55k4RElW15y3Z7PaCpz1Npp7OPlA+ej8sDQOwKODRB0VS+CfI1L9HBBIKo7bsL3P+ZQj68dpMr9IM9pb8FYNwwPqupC8aJTuHysEJ8/9B2HFwZC78zjFO0XjusS51L/nZ/0W7yc/uaJg4PZZn7Q5QOZH1vw4LSx1LTtJ7atWgXinzSxYl8kn/FyoA2G+pDlLI2uGfZ4p/oI1+u34Mt4dZi3M5VtP6RDencOJWyy5tS9mhB85DgUfFHlxvw4EthqDwoTeiCmOxbKzdJItBhpdXs6W4SrQc7tMfh3/g+eJtZKWcF/wftDFWwr3EDyZ+/Djz/a1LZeBsPvjAaJcmGEXBvUDPWAMsV9vO3ScPqhfI/cvq1i30W6uLdPFcaaj4NP67oJoj9irp0KRL6yAClXd7b2WoQVEhfx/JnN6NUwEl8LaMGkI0f5VXwkbjX5hXOy/Tj0qTH/qrGil6rB1GcagDePPMdDuXoQUv8FB5wv8mK/AXp8tIMc1QzA9JotK6ISNGbKw5QfrXz5pjQsbdjLikWCXJzwEHr9XHBawnK4ZfyCC4pmwGe5c/RsmDrM1VOAvQoLcFNJLndf2MX1C45AXsonzPqQQrtsRvGDBac53ns+5dYLwVd3Mbj+0RQEp//GhYo3+f3kX2wQE4zGBWow2akd03/Z45rVJtBJ2hQkuYbWOEkB31tIHnrCfO2BJJv2bsI5keEwtiiQHx4Wgu1qvnT6lgPPv36GUrJGs9CyQl729iQq7BEi99kf2ahcG5ePnwSLfwBqYgOvWvEWDo/ogCeCOZTX68Ent4vw947r4GTxhJ4XakBJ1mMS7e3DuKg1pLbWmB9s80Wf0uX0ccwuOPhhGK0aMx16vo+EnldPSUinBWKl7clpZzHlCWWhj1kWnpHTB9OCqzz2pgD5T1YHhcgjaB7Tz+lD551YLooTshLQyPIQjgqXouTf31g5djXm2zE0HzLHNx+8aKlUJ82MEuOJZbfwwEhpSlzRjMKTFCHyQy32OspDhS1Tp1wGNEdXUk/wOrQsaOW5KkVw4G8A118whYi35/l+gB7UpXyC4hFCXDfbEJweimDDJjEYPD6H9DurISplLiie6YPEPi3oyTmCxQrCbOMfSV+NiyH2cw4VggW/S59CnvZpoGWiiBtvScFzo2CStkjB3SZF8MDpNtYei2TF/Zug9tYXmuDsAtqCwnTinhxsSzuPyOfRe+R8qtTfTqUjbWHvhCje2rMeKg46kIikAokqTYZ/Aw5YerOSb2WeBvfNP6DDLQxNzlvTmHwXlH/SwkmfPElmtSXcfhxDU+dewEM3m3nBqzP4ySwTX06+DEsvz8GBHY/A6L0LH100HoLv3sS9yonwo/IXeqor8v7NdyF6zRiMCA/AVPkg3i8vCMF1BuB9dgPoCDbxj1m/8dTQPc029uE+vWyQ3PsETqS5wvBftegirQM58r9oY8UCOvuwgn4pS5PNSR+qtvCi0gdmdMzTF8R09oB3P4OXoyW8uuCBy7YbYMZmfRqssoOmBZfJ/7Y768x7Cbuefye5Mj24LJPCHiXp+PONFdvrNcBUWyfQ9noGy53eY8bFDIqb8QLnjlQBPWk7fj93EShsnQ0+Nj/polkGHXT9hHbXzSFlrQGnbd4I95Yowuz6EIiauYeuKXTQydmLIE58Ew1IveH2HkvaWmiHjdtK6dtOafhgLsw69utY6j9zmhOD9Hh5IT3fI8et8fVgd9ER/T3FoXenAuQtlOGwaYGoN8+cjuX409OsCuT7cbhv9w5+P6qNp5zYj5bbJGHMrim46+ZczsnbwyYLmNX+pVLN2Ey2i3mBb+5nULf/Y8yPAfCKXQxa8xq4aKE6vtpsg7K5KWRlchW8jz2FaIEt0Pf2LOvJSsDB1xOoayfjragAvh7oTLrLJPHFLlGIrXnH412O4+WjteDvMBqeLJAj619HOW5HHawYK4xJK6ZijfV9jh7miHHH5sLxfeq0TFYG7NY8xEeSrrBP7h8E7BviVf0Ist/mxdniTTxn6hq6aTAJRap1QXxECCv/aQCrjXI41XMn+Q/7iwkjX0OfbiXoFZyh2HzRIf2YQPbrufjqcgrJvZxD1FLHHYmp1HzUHnKinsD2S5r47spC/rNWGU42hfO9J8f4foQdKDj3gbC1KFVOfwWL6qfBUttats9WhS9bdKGu1Z9dvW/RhHhtvJ6fibneA2g6LRlUva3B9nAZhDw9iB1mZrDg3nJW3z0GO2RmkF3OQ6Lfd7jXoYhOvjwJW7tWgeyVGWAxFuFu3kUw1llJ+3aMorStgrRP/h+ZKi2j1X+fQvzD9ZDxsYPKFuvD77oNsOvgdrI7IQzSCzZwj+scajIZ0mutFi7wX0tjjgzDOCmCo5ptsEVAgPq1eik/XJcNrzyCRx8FYHLzGL6QUM9nomR529mxkOZRxtsnzYTPs1biE6uPFG4ezb+j2mBt4GO+G3WD2mLm83xnDXg/8wAVafZgQzWDYdoiDNRuILvtKrA2Yxm3/Y3ARx3C8LTDAsSOvONXmwxgZPsFlCvwIPdRKiwfuI7fe/+g11aWcMdMAgXb1GGmkz3P3FED4mKlnNAYQMdkcuDCgxyKPrKfyhP/4/kSNRDTLw9BscW0w6MYJL8mwhxvdT4Vm4NXL8mhclwNGRWH4dVMJRx/dRxsDuuis+ZS9MAyiTUabtGJ2suEdtrsWjbIfY1SWMGrofemHkgFdMDs8GHQr1kEUf0HqE1uIrT/jOOj94mUUqwxdtkjVrwzFaZbfoWSYe/p9pMsuiV/kctX5/MpgUvo+XsixfR+QcMR6rDx4SR4v+YHfRgbBovkk8D40HhecbCKPdy/cYWIOYxOtQBXyxqMjxIHX2E7avMnmBc1hX5oddO3OEd6UTQf7r13AZldYSi8bBncGAR4nS8Muhtl4dJsC46/epTr/tsPb7dYs2bwAbiQb4irpCRpWK04ZJe7Q51YADjN2E+WgmL4ZYwvX7fVgA+67Xxe0hImpOzl9WesoHWMGF49NgGPP+0DV9X11JMkRGfqujlheC44TC2k2mM3IN/FAuRnrMMxayVo0ThvciuxhKchWZR3xAZVUyOg5MgYvvH5JrjcNoerNX5oufY2+fz9QrVl/0HV1Rm85twEnBCTyGMUb4JfjAdaSoiC/+EFPG5pE+nlbOL+rX28UcsJn84r5ReliWjz5z7NMDsKTxpUodnKit/On8WzPoTx/rxoml78YKgbpIGscyQ7/y7FhjpV8BoYDkvXzISOQ5IYduchBr315a2JWmySs4K6UvUoDTM5e2UaTbyoBX0Tj2H8sc24IO4my3fns9bkLH49whnMnIQx9UIQVf6bTpKJlpCz1YGE9e3Jes15tHZoglJzd1wdIcRX27QoJmIiNfZNZ/sOJVii1AU3zBbT3Io28G56BtfefOK+hMdwg0pwDIZz8/c2+LlpLOyPuoZj6zRZpu0zejcUo0GnDPmU7IHLLjdIvlmR92XZ4KF14+FywxUQS3GCXaq+cCbTjlYrbuTBVbNhR89YjN73Fd+LudOfSeOhfVogr4z5DmkBX/hKYT1O+a+ZH6rEo9uORTjpSww3de3gjF5FeOsxB+HiWUy4WYYhiY7wVbMTY3bkwtJDVUO5lkWWj47Sj35h8Be5Q+O+N+HS/gzyf2nL3RM98cSuT7BITwslQ8I5R30qyGkIgrW+IUYLfMINpuGcrlBN860vQe7Xr9D6ezj+zb9OW5/vIoXZQpDlMgE7V76hkg3msLn+GYs/mEzTfIIxbkQqdJ4R4lqzH3BuwBK23VsHR1/JU/zXk5C3+B4nbx/KHL/J8PCuPFycUM3S9nPgBKnC5aoO/qEqDXZhKaR8NQONw8ah++0drEfRmJjfybv7L/D8ImFY+uQ2/BnpR9faNcijS4D0Exbj7g3bQSbOjXbFKkLOhQPc1zsVIgtK4NS6XN5vdQGDStxxlI4HhOz6wOSwEPYeWIdNe//DdYsEIGnKbvjdWg4ZDxW5oEqUWUkSjTb0s/nSSRwjsZJkpRbAniAFWGX4B0LFVtBql12UFPYTOx49opvjj/C9E5PBR64P6Pdq2G8uDDsVJtA/h0JqavpGyT+fwpZjk/nDlW+QeMwbL425DC+c76J+pD4YWOxEQYePNHVVAC2860s/szV4yWItXLhQgdvlskFdzYhXbheDFq2VcEeoFyLEVpNK5UTevfknXAlTwbQd9pzWZ4ETIuSwd89wWGk7joInL4MySyc+n/sYnnvI0+nWG6RqZ0enNB2529eWFd5NhW23PPmvdT9eegv87VAxbDn7B4XflbDJpNu8SdICh5+YAC6durDmdwjkDYrQ9oAsbJOfQYPXs3iijilsCZLFpBIjZuFruPYLgajyG5juUAKyuUfht/QYjBU8BpurP+B1oTOoIHCJL01Io6UGMiBISjQpIpArJsRxR2kVz4wrhYLso2BxtQy8B19SiII6f1XRAqvJadxaW8QDDb+h3tAaG5/4UciZT3jtVxnMa64DmTk2eHedLPw2D6MlNzJ4XW0vpvd9h/VfGGQ0HXic8TU0DG0iNSrDpmHjQP+gE/yw387D21bQozOeWN5RTtLyX2iVuz6OcWuFk0/2k0cFQ87Mw+S9R5ifFudgrG0DXnK6BA1HrPlTzCBZNHnAo1UttCtaHNz2lGCycw2M8V3DeVfrwcBRlqTjJ9Ha4mpM/KsEbxqK+Oc6IfCOV4LVLfsgQnAKhZlGoF5eCa/bBWATPhd3r1zGM3zcyLJVFYreb+Jt8sGEJ9ehzboRBLsXktsSdVwzWYgqxl7mD4+ng3i7HiyxFoTwxcBeocswckoV1r5KxnuX+7DEyp5vbtCAk89HQeQ3SShVA45dbkY2oZfIq2QT7I33pn0hDXhxeQ+aW77it7eV6O58KfAOmUu1Ko64ZNM60i3xYdCowV+Duqg1TwXbXX/hkovXYYTNcKifoEWe1aOo3rOT9zb64eBkJSqM64X1kUi7h90gw8SvNHGWAKRM18F4vkkeqTLwfZQmWW7ooBtVFfzl7x8OaXtHH39X8cmNRiCTIw1HHcTZq/IULFmXRHZiF9BJ3x2Hfz0BhzJWYPe/ejwUN8Tn/dVsmD0X+rw6SGNrMM2SW8HaZRk4wkQFp07xoHXWg+xtbA2ivIsDHSRBQu4l9ceYYeyCZnwzTwWyR08k8W9VnHPUC9eHKMFM3zq6lt0Jv2ru053Ni3jkof9QxNYBWvTvcrqePpT7/MBaSyPQ9JJCIde9VJg4BX0bhZj/O0RbA40hV2Mypbjl09LgFbxqEcJAbTTIHzeib8F7qEBkDRxYHkT2Z3+RWKAK78srhdwCOdZTkgDPph6WNn1NCRNfgGxjEw30nKVzY/pIMVEJBtuSYbeqMviROqjIPYDAcjcMDXoJV14d4faEQcqctAWDkq6weWAuKZ8cxG3jCFpj6qlv+D4YfdoWFo83oc1vLmGq2HBsNN/B/iWx8Nx/I+lVyIFItiOl6DmRa1EGdu4rgORRltCNDiRnLYEJA8ZsWeFM+1aPgKBryjytuYhc2+1x2uGz3HNlCW9ceQvCDrTh+Ctnefq7Xv66QhaOQhIX+f4Hcy1kaaupPhxf8Q1/xCzlmtoTLP8xAk1C35NplgksSf5F6QuQwy88x8cRc6gsdyOMnC/JS0ekUc/fcxDrVMmu5+Vhxlp5mNNaRVtLdqLOg8lwkZ0xrOkCvwwOpMWdH3lruxScjDcDU9FWkqTtFH5pGwjmK/Gb5bvZ5tBqNipNhniFZ+h6aw2/WqEBa30b4a3RAPTki9Ka56/Z7OJbfHtlLQ4raQTdZfMoaZsybvLRARnBFv42PhvHOV1C+whFWqbzGWckMc8NlqQ3gr/xnVAo3D6kDmFPU7HvmiU8PpjJASNbcea0KjpaF8Et18xwS+xzPtC0BHvuSYLS4QA45liHK8SP4dU/Ibhl8BJOVHjM82++ZcWmfyS3axXOipeDna2VKH3cESvlVPhffgk/Vs/A0Y2D9PiKDD5IOMoObSPx2gsNyMoowZC4VXRh4UWO36hHww3XwZ6KY9h3sRHWHIzFS/u306oyFYhZthR1ezPBY547zL2+GZYqAQwPn8GPK0/xuKcn0X7BOzTeZAjvpxzgkZ+VCUMfU8XJZKjUX8W3259jXX8p+j2cDZpLjans1lTInnoOJ2r9Quff2zCseBMum5YBgTeuk+6NTFp1og+XFiwGPRULmP3mKb6MnU5POkXwt54kzEpOpQ/nxHm5ymc8O06KMjRPocgfXVgv9IPW5hlw9/p7eHu5O70InUi1omdZNM2Qy8dkwxT5n9y/Zjgs+bCba67thjDbnVha48zSBw3o5UEhRr+PNOyAJTome8FoexUo0azHw62t7JsdBlr72+Bggwy7teay7iRJ2PHnNiQV7KSiNA04bSCFIpbKcCK8gGeVZ9Mz0KGGEGVIs22n6/fGY0nYV3qlpQiPzObzsePBPNXkDzw5HApOvysh6+MUqDp1khzdzVFPogO1vARhzoOZXPIxF9a8zqMZSHzKpJ0exCux3taprJZajPv9hWijvCkoiJxHjSvBEJ5Ti9u7b+HbPZ64uGY/bxSOos9F7XTy6gYePsUK3ALd8ObeLnK99hcH7fTBLeI1mtrEUc3wVlJPa0IXq6UQVWgJVsplbPXfHRjBWzhg9yyS9jgJvY80+db6AA479BY1prii4BhxqPPdRzItGzD15ixY+0GVfsQVce9lXzBr2U+bgt/SfLVpPKrKABwdisDymDjMlnvPahknaNhKO7y5xpkn+liBz53LeEWgHme3S4C53xe4IZbOzm4r4fefZTzFeBSN3V5JszzNSW1BIIbsOQWX/knDa6P32KWxiGoEV/KdCXIgkDqO8lr8cYz2YrIJX8HlIbM4O9QcVO9fxM/R5jxKyJlmbipHpb5nnPusAf+Ofse6if5Qvf8TRyZpgm9bB3k1FzB/c+GPpscoXy2ZxTc8QzUPe0K/fH694zXut1OFrnPGEOvfBOMm3me99RoU+7ABJezaaMLIAQhzf433BHaA26mpMOXOSVg3WAcSmkGYvnk5mFrbY2FYO3t4zuHEl6doxU83uiJqAWdOPsUK8xpK1wzm1T8NoGHfApLtN4NPu0uhLUmN79XZYNUKawi5E0Ll66VhnI4qBeaJQeOoeMiwlQd55Sm88d9c7FS0BqV+hPXGIfwi8SEb4EicrRcAzjLZ/GmDO4n3L8A9Xm3g9qkThytrwLZeBcizusUT363i96kf2XHcXzwlEwS2JR0sX6iD1X5dVPIMIPeDGjSWStKcJQ/ww7BWts5wxfDobJT+PJRNe2binxkr6TaJwexhgVhsPZt2CVmA4nI3XnTVFU9o9cNZuTWw5LYS7nNZRf1jDWHqjzukMrcfhVgaS+oJPzzYxcr7dHl+ly8mSz+Cw6LmiBZikFRuz+/3m4HIDhtc2eRGcdwCVvnlpKizHeb7HqdhPirUvdoEDA36yV9yOvTlCcCVmEPsYB3Aoc8Wg5LiHY7+8obSLtbwjAA1EGj9R4rKJ/l1khWmaSnBg8mD1HpUh4QffoDt3zJhQ6Q7Pt4uAypeFugq7gf+JrpUEPoUsvV9yKZdhaOteocypB3U/WajjIQsRPZMYM8bDzDcrIkflrXAk+vaNEVHkUKNSnHI/PHQnByafF8MTnxejXrLfoLZ7RbWvJ8KS27sYLugJ1TvNQ0qInPp/KFYzktRArXhT+DK4H8cppZG0wuGmK17Pj/kDDQgHaod20y9qvPx5BOBof0uwfP0RdgblkPXtM9x+YUuvGdaDEbG30E1ppkb52+nnstjQCNAgVxNirFzZhhVL2uErXXqUFR/AzS0jkGKqRzOlyknofH6sKLyCe+MeDDETWXsURnPkx45w/AzESz8xBdeH+vAhXerUFpVCkxv9kJh+TqMfCdAY/86UdnUWtL5ZMH3IiXxkvs1uOvsia2FKiDpUkl7e6Q56Go/BL34TiELAN60t6HgPHXecHUqNF0PYK23oyD48yq2ep7PY8xP8rf1P3HX6houWGbO659W4IY5BKNcn8IGEV2YFp1M9XEBaL5/PHUqNkP9ss347NFNXKwgjFdKdSEkKxMyqyTAKvMJpcq/BqeQIph6H9j42hx6Os2aE3/HwgnnddAsc5G+VI2BaHcdXH6zE1Zo6VPY9JG4edUSCF3qylsK0qnyRzdan1xD674A3FKvQfEb5jwlNBktfn3mxpYSUjXUhB3XTUHqkRsqzWiFd38sQDdjGG4DDXIYmQ5hqweo4moLackEs75SCG/pC6HY47rcPMIQIKOPj2htBcu4JthsHAJRLEBrD53m5upmlr0TyParTuPGlhHwfvQ3ysgsQ8lTr/HjVn/47tcP9aHTcaebOdVJDNLqo6d50wtZ8Encx9owk8taD+PDcC0+dS+VQrerYut1onN4g9UbbGBXlTRcTFjDBQvP8Tv8B+8O+VH1sUDuiPdBt8xZVLfMEA+EnqdxOBncpKM4eO1/EKcjN/TfSFAKaUSf88cgwl2f3kYGcrxFPnRsMwFNqzvwcOEZtIFqUFp8AZKSgmndnhVQGLMEQiYsAP26WuZT4qB1YDpGfQ3H9VEJ/LnuPO+4MYs/57zkautJ3HPblA0uvIQ/JcKQ/LGY/HQ/Yu/WC5h+/zjtXDObG454QXjfY45w+gtVgxk0KKsOqXPjSXNYOS89OZefFl0BFR1RvG69gFrLJfiemyeb9H+HrDyFIZ7RxDcL7bjqYCtIOeiAiMgjMCooooNnrpGHtQdUGtWShLcubLwpRbeKlGhQypMEhvK5c/t/bD8+mPMrnEhhfxPM3LOKz5nIgWvrbdBP+gIKiZ/AVPI7nt7XhE1fQqm9wIt6wo1B3z6HYvW1wGF6Pm3a4UT79Jez0KhYlO7VYB23DOwLHMV71vjCRyEjthnQAoWo31g79iAKp6nByeyrlPnwHl17LIt36yVpxKtI8O1chrPtlKBzsya3R+liuMMUfOTdChrR8mBV+AuHT1cF182P2F1pABccUYKb7+ZjWGMDzT1UzsEpnfBZypakRjSSUnoldweF8289D/KOFIZ450J2r/tCFSJBmD3nI7552UB3nWQhZZIBWq/VpPogPdwvJwT7N38A7Ymx1O39Dj8NStPInvEUNHk2rW8Yxvcd74CtmQIuFZGAaWMW82XXm3R00lRQbEyny24zUd3iJEm2p1GCx3u+ckUNhm8ShL6chzCQZA9VhhsI9l5D26nvSF5qCrTiOGwUPQFoJ0v1Z8fAhI0f4FfqLVa2J5po+JeaVSRgR0MAzdgYjfN9zChlUjZ7frECG7NZUBa4Fi7PH8anJ+0ij7+XaOExe/xv30Yu1S6AhQvLwMFUGbSy78P2bh/I3VHO+0vy8ffAbpC4+4fv/8mGj4WtIB6ozE9HyUH4YD0+pjRu8NnB7pql9Mw5GZU9GiF6WS8WH66FTe+noVC6Lmx9JkzXBU/hbPcF9O9eBWb/tuaPBRNZZVYVPgo5AoKxjyDu0SiYpr2cknzFeKBlOz/LHET5Y8x4+BHFimShkcFSPBe3Ex/rWENq2Vz6MHwJihjZUEywAAWBOTiuNebCGWn4LUWGrS8zFTgaQPH746Ay7Au5+kfh9T4DDDZSx3j/dvoN17E15Q9JmnfgQIQYJMy7xSMvtvKMnTkkfu4UjvorQVEPTUh+qMtIsiFmzBCEQXcBGBRcQwqvjmPQx9t86N0C8ldu4t2PXeCO3Hd+IGwABTvn87KdDKv/fARHSSkwslNBi31JNDbWl3U3S4JetD9+af3Kho8jIN1zJPTs+8NzRx9iiT+eaJwZTMfVRSD7RBMb3F0IKy8soo+jvClhihn0yTSy//dpIJdzlO9KTqPriVE03HI/Ob5/jzc8FDimrQJi/gpCywxnHjHyEp3xk0Tvek8ICtlNEzNOo9QLCaxIf4NrXVVoh8hkeCE8lcq/f8HX8X8w9Es9HAt9xS13pcAOi8hZbi4u8vkKqQPW0CETx1qQRutHRcHeNgnMfeDIaoYr2XC7I2DXWDgnLcObbjK8uOGLS7IP4rNvk/DsVX1mpWqI83zEtlI2vHqIJUMj4zmuVBriqoLAfl0v58Zex6WZ2rSmsZONPC6wiXosXtCaAr35CpjxWQr8936DokFtbD9ziiM194DXJn/wnN/PjQU6/NlRnDYpqmLcTT2oeVuHas5+qCfbCAKvqqDsoBWV7zxPumYiVLB1CrUu0EKJQ4Kguvgt3Trbxin9/vhcMYa9+67RhQv+mF2wH6/N/AbnPhTg78Mj4Ur0LKrscGbn2uVssGUzVDrtwe/h8pj1bCSaJ82BcffS2Pa6ORT2t/Pa87lot+k8j/8XCc92abD9+ii+Ue9HWfqt4BL8CW7/MYVHfsGQLt3CkrOO4ue6Zlh1NxdHGMhw/voXIFJ/mu1t55PFHjM4vzycpuy4jy8zJvPCkOW04dln0nhcSUouCzFlmQNGrT8AelFjoFLzMWj4VfH+pVcp2saOshbcJqWCUajzWYFDrUo5wPQHyP5SAirWApvTx2m+/AF4MqcFNjs/BJ031VBvdpnnHtkJ00Wnot1+Q6jIVAGD5wPwU9YPr12OYMuCDXih8ARd/jOMGgN8ONO2mk2+WoDQx2Fo7xyIe2afxikRoxCHG8Kew+aYDZYYtZpQdeYNtvuF4LJKgJ90vYBuOEUmiafhlnEqzJ7hSpN0N7DPx/34Vi6Rjd4hjPVxYd1fBdSnfxECLq7AycO30KL72XjCKgo2beyimNbJONJLCewvGvODbm2SHHAG8S5nPJEQiofuRaJR6nVaWqSBTt0BOPKkCGg8mYEV36pgSuc3vF/yjz/278LH5+7TYKM7Bf8opTd+prh9pQyktOvR2scGsOZRClSVPuG+95NobFI/Fldaw7qIVPy0LA98HRngw1uY/tsSd185w4v4CDgnF5NY5RZOWShK2Qdv040v5zCyQhD6Y8WwRX4ud68uxskXhzz/eTV/NjpMO45m4iVdQVr4ajGNX2sB7Y9nk/jm+TTB+ykfm5NGBk2PyfJPF2mHvMaTd7RommQSnnO3gLVRM1HqlBot/vSV6i/74ZflxeQp2oEpuV0k8X4VdG6s593DTGENz+EEwRY6EjkNPXqfg+mLpWyq0U4NZy6D9NhR+ExvDYU8F4fhy6XpYlI5K2+NgV8Lw2hX+T2erpWIJd77ICBTg7Yv/QWPCpXBfWs/Vxcr4IkXh1FVpQgVj2Zg/tJxkCS0HmYs3AYnr+bi/J+yUDFRnBqURKHCxYueHzgCd3YmkZ5/PiXImbPCqAJqWSBPbzymgshbAay7/Znj/fahxsBW3Dw6FGsqj8BgoRZ4tsqiYO4k2HhfAW47aoBb7xvorb/ECaEXsFtyPq70OsM5/BU9bgx1j+Q6rN0yCkCqCoTH6dI84U4Qqs4jSbjMSjX9HCGtiYVjB4f0Yoj3HoqAXHIQRIg6UH6sOUREbwUzp162behhbZdB2LPnAqlm/ca492Jw5O55sms5Q2ID+1BpryO75FrwohQnrt445IBPGihW8hVMi7eEkxfKedKrMTihOYtNjRaRa3YpG9kd57NhyrTyWTVfmFaAN80FYK1wBXveuQMnP8bx/NMNODBWlmznfMLI7D+8UrkRhgwe74iqwAPeSo5C+UNaWcJhe/fw6SoVOJn6ng6lh2LZA2Ma1JqFs/eMhJDFnjjn03uc2LaCOkf7sarJLRhuZsPpn7Nh1KIqvrtsHR/JGg/fd+fRf3/+cFrQOP40ogOE9urwD/GlOGKjJi1pvoBBd/4jxzIDEP2mCzoH3kJg2ij4awsoXb0FFqzqo5HGWfTVaTnNe3qbls7Vhs6uLvTf4scZLyX4cLAT7+1uYTXXqzzDy5HznZ5winU+yZWZwAfRJPY8KIcbXQZYzeQwbl1QgLtMTLG+NxferK7EtRmNPMvIAiB7Avy6JYCPzs3mSzlpXK/+F5P2ncZtK23AdII8bP7xHST3WUFQayJOG67PGk9W8a2enzRwJh4X750Gi24Y4nhdUUpSEqYUJzO476wFRjMLOL77Hfu/l8fsY9GQvOEnrIgu4jofK3QVfEE7DIRBNE2JwtWLYIZdERZbCFJ58xu66PEBzK7GYvLgONYfsxhrcAIsP3saNY9W0nT/U+g46wleHzuaYwqP8Rfh73BpzknwHBEILcuMYdjqXq7a8IlSrjdjvkEMbSx+D//+pEPukvXQ/NYGfhbbcqMlw+OAH3RtkTdLa4uB0w03ropzolLjbl5bfQGbZv5gI+tAXqipAE1h82ilzhdcuoNR7uQqmC29mT8+34r5np70SjsJ91QJwPnQMRA4PRtKjJRxIOUPq2ycyov2V1GqCqCbhDab3NaB+28b0SBGEtyWhOH0NymwL06UG+9b0M5UZ9AjZ+ZhNngpppD3ryrnWV1yIFrnx9W13RR+ZyU9F93B+9fbY5JcKN2vFWCnWaFoHivJsutM4fy/CBKKlANNm8kgcMAc5i14x3o712P4NW3aJPsU4tSGg4XZCHi4IQa2j/+NvXPWo1SDLn8/UQ1SCoXkEJ2ArU1daHZmF4clTIHi1XtQW308VPwejTteyfLZKDVK/vSbr30Spo9JP+CP1H0syJKBK7cz4NSkPSyrMxcPLReG1gufKMiyg4f5HcIT0wzh9LNwuKo4Eib6RnF4DaLYESmYV2NEecIlcFbKgX3Wvac9Bv+Rjtxtkl0jAVHe1Rwodgv8H6jittpMXtk3HlzWD2DLo1Io05MErZh9qB4rCtOvdoBqZxPdsciCE5s18a/0fzy9uAL3CxNuS42ic5Y9sD5aBnbfioE+1xKQMj2Kf25/oqOdFZjQJEHtYRbYIvGJu707Ue2nIly3v4ki/c3o9PYM23gp4LHto/jBnCWk/7oE94s9oNKjc1GlXBee7xoDTgoDHK6xhi9b68Lu2HzY1DMX43MWcmf0M8rceJEOVIyBjh/psKpyFkntXAfud9RBUUqCt9gshWVHXzOIB6NwdAe0D2HyxmVCsL5MnZuczg6x7gs47lkAahfz+VxPB9+rfsruDuehfLUE9Iy3ImvzKCysycKUd/mw2XUXT38aieUli1D59FYqnCHOt9aoQe1QbkjpzeD0+1Hg9nkcDFa6QEyXIZg5eGKr1G+KbSlkrwYdeN5txtPcc2kwp4leR8eSUfJP/O/7KpQVRhpedoB4ujec3T4R/GQLIWLdJdAa4g3TFym8uf4HKqQ2w7Llz/DU6N3o+eAmJBgqQ/6CPth6QRfqACmkaTHWu6ejWG4BzrU4RNq2tnBC1hoVV6tB1npLbL4VQdOzGyDY4ik4JbXy1BF3qOmCFB5S2UTiBcfw40pFmFuSSvOsFrPAikk0+Dmabp9ey7MKDqJK9nIww1TwDHmPC2drQYbFDBL94AUW43SIizbgH9/r8K5IiPo6ztKvi87w5uNu3G9KsEU8B970N/LIia48efFfKPumDPJP7ZCPX6cZa+xY0P0l54tZwEnvE1josYrevIrH3M3bMNh7Aq1IC6X/JK5Td/Uj2u06nub8NYbw43shIP84WK7bA2pxk3CHuhpaVFqzyYRSfmpizD9KLtO302PhgVQ7l4TLQlbtHspQr4IjN9tghbkb2d/UQNWXgXSkTIxfPTOE4mNXwXLyG7IqzuNNSZEockaA98T4Y5NKG54vuwG5B/7gv9mK8EXIFBR9BkFbRR3CvlaCaFAoeM+LpT6tZSiTNoONDmihXtAEuOVoiV7uf0mlqwAmtBjwPs8syP7SAgMnVHmkphBVOVxir2868KlLhNbs9aH4qjLI1c0DwfUauMu+GwphOT1fU0rDVwxwzZaJ8DKrHu8MzUHjzUzosJhEe03Hc4WJH9ptNubpVi9p36fv7JAtC28DnFh9qil7bxn6tsuhoOTL7LUkkQTKc/CoYxWd012BN9vFoESgmXbfXkhCq0Qxj1vgfNs5MBrnBecf5FHP8GT2SU0Du9UM5nv/g0jRaFbY/pYsfTL5SNovKHv+GH7/LcXelZGYaeYI/86MhrHPlWGOx3ecdtAO1aoFsK3gLGVtducZHRKcmt5Moxz3g4+iAVz0KOJhjSOhuUyEttp0cefju8g/k8lodyXZFwtRbJwOHXuuCWdnpJDRGmluqelBT09L0BZdjSvNrOCauwHeWFnNU1X+Q7lKfVg8YSmNeCuKo6+9BNsnnvBn1giaq6bLMsvnUGs8cpyAOlctGg59Vw/j84F7/FS6jDKttXDckR9kKYPcGvodtz3zokP6vlxnaAHJaQGw5Ko9L21dQWNfA+j8eIFPs5rgZZoHLjSOZf3OaTDBXRIWM/Ar9680tVMQex1q6IbCGnD4sZNvN18FW0VEwZ/j0P3keDh/fBL85xDNCXWp/K0hjj4M+eynokxyqLuGiX9W0rHU7/Be1hDm26yHiLgBHqPjwzG4BAZvBYD/iUhYcJxocK02jSjrwCIbWVB73whLM0+gi4sbHne8inelG/D4ugZIFJVmjN6NR6SPoO9lZRh27Ceff5aJT9Zq86NX7+mvmBRt2xoC2o3+0P7/fT2hBNeBCNScOwI58jvp438ptGDUap774CP6X0uG8ZoV4OC6hEYd1ASzwNHwZnIC784NBEGD9xhy5T2ecNXEUSsW0AaPbnz79Sjc/vWce8yFoTLAFv82ZuAlhYeoNZpofPs8kqtbhcIZNrja6CKEn/WBVBFN2OF3Gqwn1ZJrnzaUJU6CeYKjqXbjJdJRFCHbzZqQP0yCyv5qAV+aBn99D/OurFVDLDCML/o8oJE503h+ehCusLtAy0Re4JaLDMN+pfFOiXT8ems8uq25ReLeK/iJ2mjK7vkO2bpd0INjQWmMLLgHeGHRTj9Y3/aV8gZc0fdXBHfUpoFUCtHGzTvY0mgbpyJD0jHCgcUCPLrbDfdGtbLOr5f49dVB+L1lNXcpfaObo56w13cFiE04j5qnSujOVR8utxRHdVhDJ/XKOfjiHCzcmwRJlb3gOVsTtv8O5ZnDvMlUK49jJk2hd4dyQFhsATu6PEf5S/nU4tLDxXHG/7P3f6Xd1FHiv0XQWzIdTqQA+26Wg6sN0Xjp5zCcEaYB+7Kl2D9zBFSmZnNklC6/vBpNYW89qH9nJXxfosN3pt+A2qhBTNlhzr9GKMLjxjy60jqWTh/PIZH0azQ10BXPOa1EK1E78Gq8hlrFh/HnaX2wNsnEbOtN3Gh3HW6oTOIDqxr4XvlBvkKr6ZGxO/NQd+8TRpCKns09xYJsadqOsllGlHhID1Z+vM39lQV8zLIRjjZsY9oqA9kLj6PXw0YwcTOktYMFmNg9juQHX5Of/1rcVnSDJO6Gglq5JDS8HUmSN9tooM6dHCKGo/riLjjzoRxGdNrDjyYd1jnpTHvfCoCXoh/0tT1glQdfceXwv6hpVQlW9+eT1YSJVGLjhIdefYZNGeOgMHQlbJm/DteNeUvOe4e0dVYGv4S/Zss5hhhY0MqxctI0sWM8vHWV4jUPwignzR5edCuQnoE4pmAS79pUxO8i91G/nRQvNBIGZ5EzJG86Bd9lzudOldXYpvqCrpitwQPLijgv5RnOLp+COtfN4IRUJo8r1cevP2rRtMqMz8+WINwsR48nnuM9Pm6o5BJOE7QU4f3VUFxmVw9jpI+RVHIiJHbLsfnJIHjYK8WDx8dR9fl08K2QgSDbJjK69xhXxzxE/psJKVN200pHF5j2+QDPGz2efirasdIjIZDTGEEyUp8p/1cdCGTYgXZ2Aq2P2cnadXG4Z24YxU2KwlJ1gLBzzmR/q5TjLv5B0+t/oPtDPR9THY1h8f/wlfxuFPyoD8M6DeGpwxV8JC+PHQ9Hs/QtBVjo/5ddpztx52gLqmj7gsWPtlCWkgK0HvuAo6rv0utn3vD2rA1ITPABv5IavpdczA2R9+nbgSk47b4iqETvxPPp+RjV9pKG3ZuD8V5pMAPW4tZoGWo8OgPyjqTC9KVKYLLyGaivuMHyjYYYVutGAhqtFHjBAo7alcAt8QA+fwdgw7gpoNiehm+vLqXS43Kg43WbikYswwcmutyKCeT9VZDM8u/Ts2kj4b3jYTjkNIWvXImBYquDGLLoLvdsdeF3utW4zlcTUlVNePU4E0hMdYFze8VRYoUcFM88TMojDchyby3H5IbjF+0l+D3PC5sXicLEuBFwxioA/NZdg68+BrCQdvIuZwdo21IJS18/gfEB2XDk+Xh4cfE4Ok8aZKGVMpiydz4oLXHF5w8WQ/KB2fR7+gz2DUzBfWAOhX3hNLpEEB1aMmjR5D4cVHThOxtFaJaLGDp83sdvLO+zyYAJzL9tQYvdTkPMhTI2uqDKCrd9yPtiOWxNfwZ1K6/AjFptzHqpCzvFOmj/+XPY/MONlhjvp1YbffS41gEmggM8eqsPz9s7D78eVgOntJWk6WnKs/7rwur5VdQzrBzGZ7ZwkH4QLl7+FJsNNsGhXH1wmedFhzt7eXRINAUf7aP4sSZ4xmc/hLUcpEIbRVqVrgG667RB1NmbVmecBv/DNnRg/0mi+AbaNDUJn9n+419LbfH43kLqfTIWyv960rpjEvRYMRdyZkyCazZd8EQnnKLNuyHFOZW6ry3nV4t1YLLLD3y87yM3GQnTw615MGGWLboIB9JPTx9e4WNLwse6SM7DEIabeaPcixAoa7eBR74LcGZ01hCPdmOAzBIwPHeGCs8GwNIwc1Bo+sqnMsbSwMPFVPAmiCAnGwy69hIOEyW3J9p8UH8lvOyeCEIf09jo/EQ28v9EMxSTQHi5MgnJy2Kb8HbYYmZMtSMcyEXKGK7Y/YPxJfLI95XpcfXQfGifgdC/8+j7x240mRmBP7cb0xc3fRi5I5Bn/FWlb1O8OP9GLXvfU0ObXzt5SepYOHUqhV51NZHWJgvoNfJAiS2ncO/hWWg70Qc/PZ1I75JmU3qXP9SIx6JszQG2vDgavOTiOUIqEY46bMPN31uh9HkiLK4i7PmbjEXe6rjbJ2FI+9oQeEsTAysm8rygneg9rIKf1YXg5L5MuKP2HdO22MGu4K0kMk8F3mh9ZqmXydjV1Qepp/MwJmE7yDuJocKfQk74dY20l+XCg6Lh4Fd9HGT79KEstQhly4NIcHUvPJ/wDr+fa+bCbeYUXalJ8kYjYPqFdSh+KY601Du50VgWjedIo7hIBG+7GYme1v6U8jgczulNBY2Rw0kk34UD911GO+ks1PiyEqKD43jnfW+eqKkOB7MX80gQgqeGjPI5Arwkxm3IC0eAmuNC2nRlFI1d20WtXjMg7Gk22x5Vhps7V5LN5+uoFxtJZycUkXjyCbjb8AjYsx7HHHyICYVXeCBSBYw/3aXZzRNQRe8e5odZUP/Uu9R0rxYX+TnywlE3OOmsDN+qmQyjLELB6vRyDu0yoxcJWxinXcEXOR/owb0Z0Le4nVz6OshedRjEKIygCks/2pxtAXp2N9En+SWWLkqHmUeb4Li+J4rI9lNmqwZY3m+lHZ+3wKxVGnBx7z+cFq1IPsqHIK+mHDTGyFDD3CxaXCIGkbkW7JQUT/eWbyDNt8HkOGYfJkS+wJdnSqkUalDlP3+41KgOsru1QfWKMa2wlIL4qzXYe+oyu8a3gHJ4EQ9c1qHbdx14/Nkp0Bdsyz3XpenK+T5yDBhAsS1hJJkUxA9801lhVwH8TajHswdkoCoklIcfV2LfvWtwwvqpKCgRAKfH1kP/TC9yqn8IY7qqaMxzPbjbc4g/WcexV8pGrOl7Bavtd/Ft+UuYKa4E2xZ8w0SeA/YoBxvkSog7N6LNkXvY+y+CGmXX8BQJLz658iRKuU+Gp0mW+N9uC4iflwO2637y8+1b+cuAOQjdXs9ukX95b1U/7hKMwoU2iyGzXRI+ho2n3+PqaUk2cfP2rySaUA2Hr4WSY3I5V3oEUP3SWyCrpAanf3zEaUEn2fXZIewSa+OGyuk8cm8SZ2xfy3v0jCGoZRX6rjMGZ/Ml1BkST9PciHXVSnnHjSdw1FQFR3Q7o7rCM1owspdPKY6HSZKeYFWUx7NGfwXr9j6e6lXNbniONcQWcVG2Ax+Z7YqDW6VBLUkPR3TZw6K5PlAstxlbLo1gw45DZLr/MkqOuMLqSy6Tyu7hIDZMF/ve9JF1TyCZyJ3lka5DGthUTFm2J6B7+mmOS99BwuUCsPHnblLy+4aLXpijsIILGwalUnPuTHh4ThpnBhTyXLcxVLJeH0J0JkDH9fGQcuENds9R47oR0vyoS4fLPWwxu0OAko9H4JqzWvByjDCufvYTlAfOscCMZDq+bi451NRzX7QiOoSJc6HvZ7pjYwVx+gHUNuc2gvlkqq/uoktL6rDtw0SOxlg4fzmX5g2bB/u+6sGOUAWK/RoKizaGsmHXZ/ohb0yrfoeB7tOZEPpLHV6M+o93vRgF7iUh8DX/LXrOHQkF6VNZcNh0XiFrD9FTaqBudSmIVZjy6w+GMGOYLTm0j8XkKUmc+m4zn/t0Fzvv+kBYhjluVZXAnJLP8FddFOI+9LNQ8C78nvyLwr/+pJenTXGE0xhO2F6CXyY00PLXYpSlKgu7nT/j9fpQjP01FVJ9E+lxcyb905bhzOwI7P5eC7aeo3j0PxPo+dMKAgdfg85YR06uuU27zsWw8tRYULl5iMzm36DT7THUdUoUngaUYfeWQZw8WQISxU9QfugeuHVyEdrHD8cFuY/pu+4ndqqZCAZbItBwsjVPNJLg7hXpIJ9bzPlWlyAwLgo6xJZx63RnXFQmC4Iq16n5SCRdvt8MCUbz8f7NVzy72Q6lvA9C/6nZsPfiXXggqw5v5hnA4IE9WOMewbHx7hSu5sI234I5QnAirhZYwpdrrFknXws2HidcXf2VCtb5w79MaZriIUjPixTBRDyZy8CDM2YK4S6QgzN2D/iWnj/+jHuDfTcUcVy6CGb+nYsjPKeBTmUFfvN5RZrZEqB3M4sNP4SBxopK/k95LVZeO8IHRtSC+MLv6PAliW7mzAL10ZoQ5xvNnWf0oLdYEUu2/KaJOmbwPkqUyoZfRpn9YtzX4YGmNXIwd7kH7gj/QIdHvKBTnSNY87cwxIjEcp6jCBlvfMi3bouA3nYFMPilTsvy5Dn4SgGKmRuS8eNePjqxApOfjSBrp/nQcieJbmyThCNXEEaePwyH9eP57rk29rtgwsMWLkfP1mkgrzsIz0pfcspBMzhzPwGXifpCFz/GK28DKbrxKD/abQIuDQd5snQN6DysJbX5euDs+IG+Ha2BPmVTuN4YRG8fefKno7soQS4AZYQiIWumCPeMUYXEO378RMYPsiYFgPaAOa45sh5D/LdC9dIeuNCRiRsfnMeSfeqgOcGDJuQIgKjaZbq+5D0NLBhak/6bLJRbaEp8LCRWKuKzoS4p+wFx4uNRcHtmL9uJdrBe5RReJVmA8UPenDssiNnZkgaGT4Kpq6rx/yg473cg3zaMX8MuJJKizJBNosxKVKISikgKFUlJRkmiXWigUvpKZDWIFg2aolJpKEqFjJCoSCmv9w94juc+rvu4zvPz+eUufWSH364cJv8xuyjQ6wAf773Hrsqz6cCjxQDBCAZrhmbo9p1uSFljpn0zbYu9TiidCcejzeDp5/lY6XATQ4vc6KyaGsj+Osnv9UTByd4ejtrPoCgbeTh6N5Z9vbIoKcqOfoYawtJwhG0B52FDfTC4P3WBt+ujKal+KRduvE4mCyWpvOgWOy67wTa/BWGu5DFQLarF5zs/gEZbPc1suMnLz+4nA/k//FBiAq4SXc5XlxK0rbvJ7vHJpC7dhXF+7yDxTx9Jn1oDesvm4j2Vz7DWaJAuZSiB89cpFPexGG0HJWnKRx16IzISLi3cQUGTL+M77Uf0Z9o6CLIfCUqX96CH/AoW9RhNwxK30lRpMzIYYUYxpeMxfmAjp5eG84HHUhDf3AbNnR9pc5UuavhWgWRoFZgmnUShmSEY/9MXHHsdcZP9FEgUykS9vCOYG7UTDgs4kdOTKBg8cIjFrRZR+6IjtGSaBXgPiZRd3iMuHjUZk2bJo1euKsjcWEox2UrYo/yMJza+p8M5NpQQZQZ2MYOU9W8bGLZv5+qIBD7nKY07VqxjI58BEj2ylSLdH9MDTwVoTDbndcs3c2JQKLa17sbW4GZ+mnITTO/8YdX4o/Aw4g6m9I8FGYUkfqy7ix40NVJAzmmMTXrKhUWGaDjvO35qPQxdX1I4/J8sXAwOglyZAeg9/RH2WF9lsWpt/OuqiXffPICN/35TirIdin0cBjPve1JA5E6OPvmDLRpz4eY0PxrhLUnqeSLww+syzRuxC/Xs1UBN8gr6R1pia5YASMwI4Lce3dQy8jtfviXLjd9DSc7pJLcemwymDp60dPUhdiyNhblnVGCmZiBf/XQNP2+Owynr0vHyamcwzlaBuUFR8HruW147aMLPwifi+L51vM51DBbPfgBC/ctg/Mla7FCRhboJ/XBznBycf98A5v2JsC0smnIyo9G+7gJ1fapAccUbOFPeFGRctnPQUhFQ0t+CP118oWJ+LHVKV5D9kXi2UwpGk5EtNCbQBC68W82HtJ+ze6YvHHuyhfraD1HeZDfcHduGY782oIvzJ+6dOB4m3QihFecd2cMV4VboTrSdXo9bOjN4pPtOfuyaiA0/XfHRYhFY7q8PSc8U8cFa5gNRFtSyXAGLxmiir2QoL6kZ4GqledT1ciSIROpQSb4Z2K5dhlZpprxU9C7sGh8PbV370XqgFR8HtrDJGG2YF/yYEu4mkeTABx62RQtL2kxI/LEuB2r7YfxTH1C49YOWeVmA5vA7REKvoHrlAKUJ3KG9419C/VHgle07+PCKfK6FfXilBWDZfQOQPWxL2wID6fDCVzwEZ3Dk5yQMG+cEsRMFaELiIeorUoPT6zsoROIPnb0gxirnl/DKwnIScf+HHorjeEqwA/cEXgObTgIFn3JY13gDNYZmeOjITPhmGUoGK59hwZ7r7FByi7Tdj3L2SWEoKLMBiZ/n2XSmKZf4BtCHxXUQXHgDXudM40X2pfgs/jkeaBAG6cZtkHF7OQkuV4fZvt68JKgLn/mnwuKOPijtWExq5auxQUoZZIs7YGZML3lkPaOZIUK8JwD5r9BivjPalgZGmrDY5vuUfRTgyJlYvjHMjf9OjYfY25dR2jkRet+o4agmb1y8QIKC2sLQepcWmOzUILMHnqxlpc/+Pdt4zRpNSp2jyxMWWLLYXH+MPrSC8taKwVH3PC5AWe7t1yMjWQf821aGBmtWcei323QMH4FYRCS0TteGloFv3GkfTR3hwNHjVoGH7lOMzR6L25u3w0K9DlxdrU9NOpPhh7U9eL4cid2T4uDeM3tql03Fjn8Z7DXmN52ZGY4PSn3oaj9Ac9wzrnf5D3f/rsdZfyZSx9B3mx+nUeZkQ/K+YEhR8iFcvksFlj+cxOcia7nYJBtO1pfD8ZJrOBifS2VGuhx1Shjsxl1Cr/PG4PpWHClQhATmbESNnp/c02qK5rnbgL4cxe7cGN48UgZrt46DKz6hdFzuJJk9Gg7Lz7/GvEf72SQ0BVB1gKdZx5OSqwb79FlDV/dB8mruhdDI1XRWvgVfl1ty/QFJHN9SD8/842jEAXHQclCAkjFINTpnaDB8Fc5odwDtD3kYfOguzBQ1hJsVj6Ek2ZV7KoWh9+l9cJhkDsX+vbT79DWY4GuGJxwvwD7HK2R+ahdEyAyy6CkzWGh3Fh2TCuiaWjcmr5rOh+4Y0eU6PZZtbcMTwfE8IFOCc+aYwcr4SsqIdwC5LjG8138Kpjoi9em7oUwI8ZODXzh692xeOtkQHpoHIz79jSmPcqHB9yZmS8vBQhEbbN8ZBDrFbfTt33SeaDEcjk5xxdlbTOGgpS6sWYgcu34ELfE4S8G7mdNvuMKK5g784DcVYvx2ctXrbxg43YLdnZwg/pI03P0VivozEObsOwUW+orQljcJ9s1M5WCzBDyy8jQMllpjwdHV7IQC5HHiNS/6a0WPjCdTwM8poBflxTBnDZ+UuAO3tiOufrIUfFYmU9kVQ/B4EkF/gw3haqocKA1Xwx/tJXDaYxM9zDGhHTpB7L71O9Gyt+hmvpkCBGeAg5IcvPM4wT2p06Ex1gQMThD/nW7LpgEn8ZlWAMpproWrPbmgc8gCYpfcILe5s/nKkQo6uVoNX1iUselzS/gwEElm1VchfrMlpo03BpuCdry9IZdVsnbjic52Uvinz6PmxfAu/0t8+HMgf/qyEV1/64Dh71SOrJ5NaacP4uwZUuz2ZTEptAxAuYkNvGAplHDJoIG3yhCltA3C/l3BaWJVuGjeFVgbns4h/YJ0q+c/OmEoDWEzs1C3cjj0zkumiIB8Up+xkbPNdoPcL3+ueNkD7zaWwjfVB1C/9irWJ6vA34I+lG9fTsdvM5n9WwSXmmxoaog0nNHOAZi2ja48bmCxlklQ90qO5NctgP+q15PfHx9aGWVJ93/lQ90bEbbJm8Q7KY42tkhD/ScVrnZsJiu+wtu/CNOOrwaw5YsOOE1byNGjjdD2sh7pzZoEtzxTqFY1nKtkKvivRDfedq9BnfPVGLkqBa/2IW1ZMAYVNFShbH0bT/EuxaS5U2j77sMkPVaFV+/qoTJXFSi9kUR99+1gzu1RsPecOY9qtQGlrM0wQy8ZbSo0SXXXYXQKkuH2fAtYfOY3RIZZg9f2Fs5XsAS17DheMuUQbBb8iSr1zlyz/zxPXMV40ViZlwzx7+O/zyDEM5o0NMLgRuFMVm28iUdEclDV7ADJnR0N18TNsKNyHKgoNaDWNG9+Kn0Ya27rcGeaNFwc6UrChlk4q6gGm5166d/jceD+ZwtsflaMV6zKYLvPbV7dtxUlD/rwsRdPqeqNEKQMOfVjn2EAHUqYZFmDWf3CbNe6kPcXyrKmYhy5JZTQvph+OPu9FibnCoBuwgiqPDkMTo9P4aK0M9CRLkSzPU5SdKQKD/AyKJ8UDIaXx4H8na8wXkueP95fg0pnQilx5HB64JBAE4cYT9fHkazepONvO2v4oxnCoROH+gdEWFfEn872SIL4N18KvHQKq57Ks9+aOD5WYQW+Wx9zwIc2Pr7HnS7UhpOOdixdLJ+F/wm/gdbFQ70zJodi1gjAuXtLUS/EEhO6hcF88BAqPM+lzQuWkcpBd0gMmwuxA1bo528AFYvToSXzNPw8NgxXD1uBYXZN3GChSOe/yYB1/0cINf5IFbMBlCwfQfF9DTovco0LtHxB/PVZTI0b5Et4DbRNzvFokR6ydrYGg+4hd1t4kNdoJFLYhRlct8mMdYMiYH+aM2fvM8KEo+LAslawLykVLHZOxQe+XvByuBKxegk1xuhi9i5dOhY+1AuPF3HGdAsICLyGJy13oH7TcxTM0YTGN4aQlr2fsh7OoKai9zCt+Bt4vRSAO2NPQe6jlfjRTZh0PkrCn7wwmHPQDhJfb8H43l64HRcNWsdlQXjFQzgOhyHrYjB3tt+A5wUHcfQOV96v9xV7HqVRal8LR3mYwoajHiScvQjUd7uQkeQbNjwXAV4TpuLbNZM56J4MlbyRoXkfAT6J7YLjRROgJXAllcS7k1B3C19f34I1QVup58cDdj58AJJBHaQtXfGg1ik+VC+Hp0S+0e67XvBrTSTbOQxy5nQbsJJXA88uLVBR+wICTS1YVPof/D44HhffzyIXZyHuVvYio7ix7KN6gR4FSYJo90bsEF5EEh/KWf/jLJDVzIdG8VIMi97KL6flw/bC+Zh5UhWcLSXgnaEq/LrrwMP9x0Ke5AQqXHATwuKNwPncXrqnEYdNpuNh8IwrX7GbxRrBNaRYvZpHRS9BW6UfmD8wGrsrtMHJM4Xn3DYA4c8bcGr5Mgp/64JNjtnoKO6AbUsLcaXSJ1wjPQwrAwf5+jojoPzpNPxRD4X7veY1nW705eECGndPk1/1LmMvdSc45xxOO5rHwLjYa9gjPJxiZT7xVPFlfOiqKf/+nQiXymbD7YLNrCE7j5u1x4OkcDZQwULWV/ehuPAtENc8nitO/MCOVSEY1fIObBXyuezNRFDTteEpb4fjj9oErqqMxge7M+H20jUQMPYKae2zQTepIzyvTAiqBq2xyKwVi2MlQcF/IuloJtDAn/e8ym0fvP9ygF6Z+qDTkNNF1//kNV/lCCwt4MZxW5AYkOQxqvt4wJZRd7QVPjxmyfc/jIf3do70Y94p6J/YScPbZsLyEQXwcu5X3Lk9A2c5J/NSkQQo3T4RAoMUqDDCkTtrW/Ag9HOwbB3XLBemN+cnUsDpED5c+ZJTTEfCp/P2dOrPMKgW8IP1Iw/RDMcmXut3GfJeXeAqOR+as8YPKksRSns9wPH7K7LcuwhMV2uTce4U7Kh6iumqMlwqJMIl5bvhua8yvFAaxYn3arGoeQnO0+6nf5eMWMksgD9ebaNjaQaw9UU0XdyiDZLe6Wz28R44C5eSSIAcSim78WxtV371wgkqt+2lvnM+2FVvAKnTd0CoQi0JhgqBzeBqlIxRYp37AbDNxxgnP7PC56N1QPusEcj8U8JkCmPDFxfRY7w8Nwb2wutXB/FJXSLrHO5GNYPfdHORGTS89IdqhRu0eNV3vJCqQ1nNdVgUUQTGgTb4rVyT581owANyxqCc/YBlR1XBPIGrnAFdVPHiCbR63IRHn3s5zl2Rk05Xg+d9KZinoozauYZQOrAJRpZd5hqnAhz/6CJt/mEJJb8Kga714+LlImC9KQZO3/9Fe/+bxc+9NmBbhhn8nLsX360XBNvyOaD8qwwnCBrD9fcrMDtgIe4ufksPitdC5LvTPFvaGKV8ojCszR7zJ3TBgSIesppBvlL0Gt8XDuC6vL9YIbYHCg+dgaO5mhxZVk/f48RZQF0TxlRpUYlWAdp3HiFZj7t48NQKltmRzx/mboJ/d//CvEk/SGOou03TE8j2thq02efy3Vf/SPFuIP/+tAq8E/eTzBUAjelZWDRWAprkpOjAcGW6X7mbVyzdymZiFYy2KnzSahecifiKWdPrsERBDKTbJ6OCnQj7npkBsfdD2Cp2Fuu9qkfpc/N51LN7/G6tDr1dPwnC5g2D8LCX7PdpLHZ8PwObX7/nZ5W/4WPGAPntHiCj9v18q0cEzunPoPCqMzD5ymiSs1DHwDY7dPb3ZDXNJqo+K43HTxZi6RRD6PgURLXFm7FCaSY7BuWw08NG6j3hhI3TiyC+14vUPbfAtzRLmJidx+fzO1BpmRc2Jrqw6p5mnFJaSOf2jSa/M+V4+qI729wluD3PkA+n5aHL5vF8UWw5tD3cyhvcbaDqyl6ocfWjkmRtcHukAwe9zrDcgVHomW2Fu3cmo/q1i/irMpXt4wtp/CgLCI1yxfyp0jAxLpLdLDfyvstX0G3fP5BwMODtz9uoMDGUN+sJ0433JylQUxR8LZdx/7uveGLNWZpR8hmyv8qAfkcaTl7GeOvjRcqYrwfdAYYgsXQWS3yYD2R7FE44T8bG9hL0fBHJpRNncOGfCLhteQHVLxjABnlduHoxGfX/GdFh+esoCZPZTO0+HJ3+kAxTMlBFN4dsc9VhzzcL2OE7l6OSm2mm+Q+CxTvxVoUZpjfWwNTTWVhlFAzRZwXhyWcPtlyhyA/92rgpdj/5v0gggwykql9S+PtPMneNfAadT5Th0M6ruCDajGKsyzi92gk93VppifkaSIgQ5XKvmczOx/jT2qnwIrYb3X6+xsqM33A2ZyPa1uXyHrMCdv1+nt44IU5f3oqvTA2gR+kyfvN8DKs9InB2gwQbi53AWdIP2f2WFK12uAp3h6vAktFyEHD/Fy84J8FBcQn467I5XhwbyCsyptO44Ep2SLKFuvBTbHVDHxT1xpPD43qkyBY2qPKFaTV2eGaNNE8KzaLY+ZehZsIYXNsrAYWud8jzbSAa327HywEHuH9OIC6/V8WpPIHNfoTQ0zPpXDGUUe+dNqP+0jBwcDEE68RbaJ+hRRq/TaB9N1P/vJ3U0dTBa85pQrx9Of+yfAiZleoA/rXo1G0LpmCKL2/5Uv0VC37kWQvGmuJweL8P14r4wn8KA/BNTpE+a88npfrFfEDjBfk9uUBVLnWk5DMRem434LV2Db4Tr0Cnxh2g+t7JLHhvFVdnGMCRyf8otuwNeMgZQuMYIbDLNyW9cQV4eGI1qQbO4DlXGWmpGibrv8f5kR95ykVhUH4sxbcNG1G2sA39Ai6wbt1utnu2h5tzM+F6UTrbqtTRy1JtyF3vhMo9pvBf2Wl4ZHEY9ff64vYxxhhZsQ4c/ibx+sPDcIWaMdxeYM0GX1SG+k+X8l/sgjFrDWBPXRQ75qvjlGgNuGweA4MOgtASHQm37wrhJvVZtHZZNjkduAAC+6r4tKEvD54LoOm+PXRcfBhYbi7B3nMbsWvxVXzrkMxScZ/5dGY5nw1ZBV0/nKDg0hPyXSANWTuvssq+9TBFaCM+u/+Nlut8wZA5aeB68whJbBbD6V3zaEnlJPh1wJwcA86SRO9eULYQR/tiW0ovs+A1xk8xoWIc6Sve5tQHo+CuhBIt/CjGCRVKENjygcZWp5FbwwF6nvgAVyaOYpdpp/HeyylQknMcvjytozmfRlLB0mr4kBFMa3ECJgxzRdxyDzsSPuO7LCEomiNA8n5z8VTSQYw8GgfJwWPA8dABTF8vDbaJkbS/phajlExhaWs6/JvSyArio3D4QBW7bXlLxg6/gHaJwukxsVxg+YjTqqRA97kERN5+BAmyRbD//CZSlsxlCVFr0r+6n/ee+E22ip/55L/hUJL/D01fbUHd6cFQqAPYVjQfhNtieWqPBcuEZpNl0mpebToZtLcO7Y68NTy6r8mjHfdjpcsgH4lbRR8W9fFR93mgVa/MF/vlQCBel4/ISxP8sKPcJi3+m7ybOjuzuCBqGb4HYXJwTKIv5wXhU2waDV6ahB/HVkBRx0uq+fyaJY100WnzMvY42QgXrP/BsLEToPSuHq5fZotT8w/B5MVFePBDCR47rs5iNT4we+1a3NaYziY7JsGRCFNy3vabfq6VAUvNG7jR3YCiu5JJPVaVD3tIDbm1DfoEqsL1Gz6cKQAsGLEJju3S4gtjL8EivxP0d7QTmsakwl/RGPhipgI/PgqQ1NcJNLCul5pqNWnGNWN85VxC0b/9eM3Yd1gU/4uCIseC9+xFcGTfJxwxuxVavYSo9NQO9t5Szctkd4NE5na8mzeIl72MoKTwL4p8RNjbFQBz7g7w4ZgT9KRTB355G/PWP4Xw+e4tWDfOBKbbldLhxgKwHt6MjXctQfuDE+oVbsKHlcPoV1glrm0xowl9E+Cbywg+EnmQjnvX4+oXPhQhbMfz/m3nUHEP2LfvJUWlPsDVq9RgW7My18Tp0s2qLNJ6K8mTj+yDC42eGN+TADkS4uDyspznS6rBXuF4DFb3ggvFjSyRWcx6iiM58lQ0nPKdQf/p3AClykm4450ZdLxewKcWVOOgjyl/GwnsO3E7iZQuoBtx0lA55zMXP3+J3ab6cHJdF8u8XUSOAi58y/0z9jep0YfhrrxVowgX2vhh+e0R6LZ/Crzw/D3EaWbwJPQ7PPE/zWMNW1FRdSQ92PiUWv7zh33FYdDyRQpWaTXSadfV+P2SIh8QGomF4dZEau3Q5O3OZz5L0obOnzC/1xy+zlHFjKWGfFJzKk1tOEgbEo3pS/IoSPqbzwZyYfhR5S8JCgpCpp0LjfAPh687p1PZmq/sWdtBMULW+ODTfnYZOQlv8lgsb9KAzR5VWDtsAZ+ABzxFIZsNDmSClWUmpqz/gEtVa1ilpZPqXqlC6cz1NGAwApe4r2HLgFuocS+UV8ta0bAP79nryXigjL1YP2ocuIvV0fFfy6nkkv1QNktCWUATZHxs5bj0rZjQqsJydkmsOMSxk3M0gEeuxr66i1ATIoR31JbQs+wDBJ8Xw7VmOe6oug7vX8iAqug1nuVqBymKC/C+8naes+YzaqmNos84Axad2Y4KtiuhW1MDzny5ACXOKvA+qQ4UJy3gLcHLuNlpAjuvH8Fz1y2h8SOuwLIpItCdmgqfx80kp582eFTWmdzmOODuphOk0l4Jlzr/cWraVErWGTWU07fZ7lYeUuJJqrB2gYtmBjRz7gEI7n/H54+uxO8jHTBOawRInBfB8YJX0fv8ddRbUksJ2UIgGNwE/WUriNwMSPFWCEqv0gOHiWLo6zMBzzlaYs9+Bfy+JxHbxiZy66nrmLNXlFdN3cqLVgmBaL8VrLm8hmsNR8KLQwLwPe0tH3vWxChWwvN6ovH5pQysviMIHh3pWKzZyQYaeihi3MiXheTpxNPtNBhzHwZc8mm1Tzx+SjACzSNW9Eo8gxesA0oZNgul3HNIrmQ8ta70okeNV6Eu7AV33NQAeyMpGDVREVQ3tlKjsxJOUq/HJc7HofzjcxhPm2lz+VDmT5kAS2/V0cVjJnDrhTucX5CFFh7B2C0/kpZVykBz6H7yyxTgtkIRGP6fBpUOW8kZDLQ9cRFLRhP/xt0YYK5NQSlifOpjG/53aTykjzoBQV9mw7yQSfDp1S7ccuQZCGV5wq+yLB6r5cJa+dH4bqsCpFmcoc7oyfDv2mvY9zCCp07dSAn7ZtK1mTfx++OpfJP10VNdEDqlCulX7Fea2j2TviuKs/fpnfizb3AoE6R5yqaXPH1zP5pfFICkwi08KjQRbmplosw9Hbiwp5JsfixAT7ld9DzMgnfafKJlzQpgNobIZWwdrzJwRNvMWThdbYBmf3RlMJHku10hoFeSTut36cH4g9M4Z9cZENb+CL1vXmDqgXoKPSSBqa5j8ckVP/xtO5L7x+hBA8pCztlCdFu4iQ7/HoeqDvr0p+oWDVg0sNnww7CmN4MP5wvA7PO+9FQ+Bb4uJBT4rI114R6U4O2IqlKuGFYvS+8uKtLZACMwHhyO23syQS+KYbGZGawvPIAPrhdSV541a2yqQnYTID1TUfjlqI5H5f5iu/N8ztnnDxmDA5jqfxb7fujgtsVy8HXFcICJonC+vJN8da5A2GctOratgN4/PANZI++zaByD+GobvN5ehJBnBGoNRQADizlj2lM4krwQJwjU4ec6a3ZIWAO26do0vuk5pD5j+Ng8EQouVsCWdwsxQzKddx5LBn7cz6UZ8/Gv+UzI9S6DuRIjIEznEVnmR5FFoTTMeemPgSH5rOn8FeOl19CnBefw3snlnLlGDFbvHA0/dhxiyU/LePoDY5J3HY8btdogKKAQY3bNwO7qYFxbJwrixR0cbzWbb+Q3sty5euxUeEx1dSfAYKswlh1zpIzzk3iVmzBEVlXQhOMt1PeijJt2PQfnosu4tuYbaPEvmjvxA/Stegk37UTghk4MHA7Iw2nqf0i4fheG+LWiUIgULrnUxYVTNfnyxhwI/iINpfUlONFAG99p1sLO3hf42VaT9Owuo2yTPXX0vwKRZ4uwc7oKzHlTDeL/qqjZ/zaslYmHxdnClHw9gWQnCuHKSdsg7NNJ5lBj8JDo5/bSMkqKvoHFDVassluPCwLzMWd0Ojn/6QT32Co2+qMBuftd0O6TOC73u8QzpM+D64/t/HK/G5+/KIHbqq7AuMdnyWbLaLh/exOHH49in0oTLty+gN0CJEhhbi/8/vkKTzzMwlMXbrCYiwKM2XeCKv/eAvvTY/lP137UtZ0ECjeiecf7+bRvIIVdnS6R8zxJeGddy2nrrWGrfi1vfRiPf9Rs6WqrISj8CuK5H5yxU3E0aeirgtnUaHyf4w831Nfi1J7VkLbYGLceqKTcSDWwHNYCL/ONcF+rFNwe3EBVd06AeZ4ojpefRfp3BnCR6QS++i4KjmtKQNjG3eS6zQLOnMsDH7REddMmPjDhF1vfX4ibFL/D1qQ2Nlm7BLY9DcZJ4RYwq0qAqz7XwVOXbJTu9YOAt1vI/cgZaHrURCEDOZg7Qxz22gjCQ+nROHu3Py7YmQypOY+oZN8e6rP/ijNe9YHY4YlsbVhD11LHgP6SfHY7Z4arQA4jj4VzfyfD3rvrYdoSD5Iz1aFUGxvWcpeD7eN8WUZtAXoP7KQ0z/UkkuTGSZtHsJ1NHrYueAi2C3y5tNkSYsr80L3RmeUL1OhfYjI0vJLDx5dHYYPgWHK0+8DjDQ3JX3QY2EzbRt+W34K5lkr4+dZFFNqSQlGPi0FKfTm8DZMFE/UPpHdKDRIu9lP6hUKyfd5EQsF1tEbZisr6XGD9rkhe+XcLvVfr4WU7FOD261FwI/cV5+h/xbCzWvSuYTE3rbpA9gKhaJh1k1cc68P0g5Og2vbgUJ55UPbXkXjc4i8L9r2AAd2Z/MTXGH942aKs0h7G4lHwa70gXot7jO/ENGi88l54cDGclO7psNpOB6CXemRbqQwv1MaC1esB0Kltp9jTH7Dysza4nlLAEMGf/MKXWf/2IbritQQPvTcAleZlWHApHPVuH6DHBY3Y7/YcO2ff46ddxfDw4yvMsL/FE98rQkFMK1asOQSPFeXx3Kw0Ev9xg8qac8jk/mSe/WEA88ZO4HOgAhXRr6ihWYbHFKXi+oU7MbsrhA7qSrLxNV+2ef0HSxxvU8xnaRjTKw9ewll85NgsEn1Si7sVm0DUdiIdz1iIy/pGwCnRYzy4TxlefrOjTZPm4F1XH0z/Tx2vLNbmn4UV8HNUOGiWHcbtkcGUED8Wsu5fgLigFzDaZjePWGYKN1JCaXuaARtPPkQus4S487YvXY/XBM8ZsbhBSAYC13qCSPUtCrsYRBMOLaHVD2fRIuU0WL7Fj3ZaScCTLqSLCybSgem+PF9lFpztMaa+8BiON9WGFr//uOSiLqkmaUOa3ni42lPOcdJfwSBhLiUlhuO/hX/hfp4cLG9fhP+sruJTbT1Y+igWvqemoPKGFfAHSvGBuz3/PrWWx8tXQ3qENzXbvBjaPSEY2/6Jp3VGgJ6MDQpsU2Pf3EocnjINxKom8UHJsVATnDPkKAhO9X5UfigF1Oc8hFtWj/BUgzatzJmOPhqiZP28kjfNrcCmzUJQpd5AS29d52QHU3yS4IZhA91wXtYIw/Nu4vRj/TRMBOl56zCoVFqNjzRaaYx/PFYl+WDH643w9flW2FNajs3v6zh8zE4+UWEFiTsmoI6/GYS3zgDvyU38cY0E+sYPnU+kiGULfTDuiwLOlxoP+C6av0iLUUSfK4UL+eExFXl6NdUeA7Y8h6ZVHej0rByOxplCVWYytXrvp7FOGrTIphceHlfHkbM2U7pvL86X28i1tQPgMlwAFuudouaMXDy+OZorNFW4cPIevH8hAh0mSmPDuGGUt1OHZEerwyLRAgq7sQwCXhziBRGX6XymC35pdWD/m5foc7osrCpYDvopgnBPMZnmjIzn9d8NcHTpeTi17TBO/dBCu/+m4+vICpzx6CLWek+CzD8FIHYzku7ureTH2ms5RLiDRkdlg2WzF99ZQ+hb9pqFvA0hvD2dJoZpQU2sI3rt3M2Lxpby9pd/+PmJQVD8fI7y7Uzp221pSN/wCqTkH/Or09dZ74w8/tqZB42vNDlvTio9EPOi1ObfPMJpyAMmVYO16gw+4XOIYhfWQeq1YzzK0goCDPeR0bXvQDW3yK3NAJrk+sBILYisJMr4aIkSvH+qTTl3rKAmRRRe2atDo2cY5a2VhOxvE7BeyJ02tLhwfFEh7xOOwz3lrrR0URZrfRnNi04W8FJLRVBRVMDkeZd42DlDKrvwj0VbujA/bi6L20wjgYhxpCm2A+6JMBxb+AW2O4zBkoULIOrTTfh0Uwu7Ow1ph48inJl8FB51tuP0OFHIXekGcZHvuL22jjuFbVBLwoj0lVNgedwd8j+CfMzpF+fONgXF5UdxvNwGspBZAl+Sj0HDnW4e1z0JN+yYAiVXY+jzHWnsSx0Jg5caoM9wMa20OU12yebUFFINad7e1FG6goy++2OMlSCvHa8BJblVVBXZA3EaYnSz140Tq5UxYa8H7315GMcVh6KUajke0RWCnOBf9DpuCUvNE0EB7Xrw/aXKopeSKVS4DmcbxePdscc5xEUI+mS0ONXSkLVO2INapDYfey4C0b8M+PIqW5jU6knaLS9hiq0mHAhJ4LrJoSzULQ+aSkmcEvERZNdFIa4xIeECPRKsz8c58iOHsiuX9rkowRj3HljvJIo1W7pIy/I2TXjoxke6rdHoghsG5g8Hoz9JmPZ4IWid/EPatd5ckC4Gm8MtyXvbHFq87RGHRsXT+9/iELP6NbQuHuCrgbKwMPE2N9h5cFPFAVhZqAmOPSE8IiUJLY7KwR1dDep5eh7/EzfnoqUWXBH3iiZv/4UGFdn4t+oVRYjb8JkPw4Ejp4Ge9W0+3RpDbjJX+cGAE328vx1eCU3DrMfh2LEwmzJEp8LioXuU/iZKFmMKuevxCHQK98N/gkIcWvWdn7dIoOqFS+h5QAe8b5dB04QZ3PTzDdeM/AnKtevQ2F6Vn+uq0or50RjW2AAFmeMhcr4oH/nyAasz3rDT5HK+xS/43TA9XJJyDj++noo3ztXB3KNGcF9aF/qSKkA51RCf7jfj0dmP2exhJ3nt24Tqq//BJYHnJHN2HFBRH2CtFfTdMMIp717D2WsaWLxIFvQEVlBnzzD8+/gG+r2Sholbn8NMtQxYml8CSl/ucMq7hVAwegSZH7Di1dJBZP4wGa/MJnB2yoEnDnGUMEMRXVIC6c6/f/xy+R481zDUwalKpKlzhzt6dSFlnRf8XNND2VEFHPT1KKdK53GudQfOyGrmkMFj1NyzG3bT0H+7tvD9qHxSzV6HdeezoeHgTpJQ/o3e72zJc2sF18bNp+Lr+pA0MY+HZ49mwU8feMXGYsz+t5f0FAX4of8lVPPwxmez59A/A2O4v/MFa37NZtMfY2iGykrs22CCubWRdF5YmkQHXGjRoeW0oF8OSiAK9ugzBitsopyReRypYwOzfM/gn6RaVl5hCQ23JFHRwQLMD0XBsfIWWtTWCvP+nSCb2gLeE7SDlcct5uh/EvD85wiAfHUw4fVgi3Lw1PsSef06SkmmlWCQqEIpd8ThYWs7v926l3LKZGCpsitO3ryaDPKmg88eE4zWe8ESuTc55eM8njdiAhxM2gqzevVgj00o6bq+Q0M5HXytcwMuvHmGdscf89GDwqwYKciL3J/gf46akPNtAK2knDlpvRHN33gTqz1eQfSUJ1jqdRn6xrvC4nu38PsQn/qcEYR+x4VwdlgXV4ueoJEzBDFq3F0K6B6JDt0iPEwuDvQdEeYrp6Fvujl4XIqmQFtJXrvAllWrjkL04gy++l87RuRfJR9UAtUuK36+aTL+lqnlaesM2eVWEk183o1yP9diUEomhuzfDVM8TEB+jg33Z4jT1aOx5HR/MZtfW8cd5texdO9X1thrAi4XxLDL1QQG1Gew4s9b6HA0HY2fnIaymJWQWPGC5sw4R/XO5ST3YIAuO1uDyNN+ej2QAyuPdfLmc6WYWvwAYrtsaWGIAE6oSue0FZ9460uxoc7yY2fXy1Dukwv5T+aTyKwm9M6NgdOOsZBTfxBnjrwCdQv1IEG/mBtdtfibQBF+qhvEPz9X8AuvcVzVb8bJuJqTZ+4h3YsENV0BqNqRzR9vCRH2PMcrY/xg8d8E3Hp8JbfnJ5Na5CtWviAIC2KC4UOdBmi55JCoyFaSFXWhMasiKNBVkbyLx6LBxuMY+lIborxd4LCqMxyyHXKvd5G8cVo+pKYuobaDiK7JBjSx3YuLTk+CwI9f6LSaFL2FfD6ExrBavBAMMnVhyvKH9PrIYdq6ahdLCk2GlWLrKd5ZgFE0CN4Kd3FMw3m4+iYbb92UhArTZOxdWw27HfSgqfgm1xdsISnRU7jGcAWtv/keufExVo19gDLLd8CCglG4I9McZph/xP2bzFn64SGet/AJfbP+C0lB6Xi5IRa8/Q6T6zh7/n6MwWPCZZaqSUJ36XYcVZjLVyVu0uPtQfx6qxO1e6dC/zd54PWT4KT8D96c5cuPr+nwvvWVaFL9AZ57ZPDcqP/4YFsRmOw8QLv9dKFr12c+d3IfnBX7SDd3uVBiiSYV7xjOqssP4OLWNGzbNpPHzLOAx/8k0cB0N1rtagPhhcjl8xejVsdokNZPhvAnV1F/Sib4/zGGvl3bYMUfCRgjdh393/vRRuMy7ByVyzaTR7JX5nHQ+TuD434Kw0D3HfJeoU3V9jtZnL/hk/EvaUxZH8Y/duVpmUa81PkJVmWOAbT9jhO/PoXiJgsYHSmPMTm3+FloGQe8/Q8mbVtLYUftYYWCFphrPADJR5V4p9eRwhzbyXTOJoBYYTgVvhOeOh4B0RPJENs5FhYam+EMfzOekKOCEy1uoFbJUsg9WsohLxog9ZcrutgxpwaaQr+mM0pI/wATh2swu+I+eT49CJwgxRUBBdCqFIfvG3JgWagc6H8vgzfZM3BtazbBhKf8c+Io9gzfxt80X7By8Cw4daOdu4ynwqNDT3hVwhaUnWRJFQsvkuvre2Bn/B/M0Y5gs72VOPq4EZgpDvGa8ir0HG4B7SkPUMnOnIvnLiMQSuC8sE+Qr1rPmYvt2TfSHBIvvqUmqXFYJSaHL76IgkiNOk/JKIb2jdkc0/IFX7stgJi90iAsWIQrRP6jwdOjcLpHNz8Z9oIX/CghO539YL/IkKRn/aaZEy3h060AThsbiKZba2FPTTxOM9sA+4R+8JLa4VDrlMHHxNZx1GxJ6By2lfaN6eYIuUUQ1nUfU3THoeaeYuhLzoeB65vgx0AQyC8QBDmfKnr28y2aH/8JT26W8v0xHdxdvAuVPqfhC/s22j1hIdZnWYLWj1N80SadrLa506Mdk5BbI8An0QoXRUVg/INPmCsbRYtqBKDvmQJKjDej+EsKZLJqOpT5l/CG5DaMnObLbZvnwMfJkbDZSw08V0qy05azeO/bU/7zehaMvfWC0+u20JUT8XzOXR1PylWhkJ86lPT64aCaEZrc2kXFHoHY0vcFDlyVRYcj1hyhEI+XBJZg8Q5Z8JBy52MxvSzyeiHKPUvCB2PysVZxNj1aFADZHas5YYUszXU2hMvHH8JtkZV4QdYOE5Yuw9179kKI00m89b2WuuykQCl0FB0vVYEwk6W49HwBNJzPJBvlanCqykG5PDv+I2xIK8QGUbviKEK3MvRH+HCZgy2ZjNsFvdJCdKDhIDcXLOQzxeshRAngkHgDHTzPUMyf+MdcU/wdV4n3GhZh386rIG7gT98jtvG0tZ9wy/FCFJhrCkmZffTPawAk34nDgPI7uq5uAl6DoWQSfAdXd8nDTdXXaDVcHOKOOXCr41V23xPO9btMIK5tPGc83TzEtY2w8e0Nthf7S1fea4D8u7n8wvUTabxs4Zk1K1hXfQfF7MghuY4MjB6mxsMkhOCmvjbEjYjib607uLBEEveIX4aeVzVDPiuLwlP0afY3DYLG3aDYqwCrLpYSX1LB8EXS8PD+Kxpd1UR2tf9/yyYbE0/k0ZKZYnxl6QhYl5hE128Gw6d5Mhh6oJk/RPixa8sf2msvAtLjcljaW56lEtVhbVkWtHaGQGlnHBlf8sW4Ga+oclMSV4mFo2F9H7m3+kP1MjFQNHnPKd2GkKKujj8vClNazix23vUFBFv+sbWaB63vtKcpvuZQl1hGa8OK4cs2K7j5ZASe9Kwhu7t+KN/L+FvdmQt72nFG00hYXdlGJm0ynKa0D6PlVVl1qwFdmf4CpqSl07LPm/B+7120dpaF3/8Fs37Tb+6x3kK/pePho8VwOj1sBbbwQUgb4wq/puvQk39DeZp1H2RTI+FtsQZGXB3GH16WUbky4bPUavSKDOAStzqY1o1QuKAJvFq6IOLBW7p4LIVV1LTIOmM5dqsc4bvHytmraxm1rh3qX7ViPNQymVOChfDzlbloNPw/vPXoDSZO96df377AveQe+F0nCpXepnxhy34utZ1AiXbBNO4/RF+NGzhrtwPe6L3LwftcOERUDb5Gp5DClLsUHmcFbyvfgsnk0eA89zukZaTikT5BPv5kKvfKaMHondLU1jKXR9/fxd4qx7E8PxsN8mbxfAiijh3LMSHxE08SITg64MgBbhrgrytDEbMf8Y6HN9BRR4Jcag7w/gVHCBe2Y+9lIahQFAC2XgsZEQ7gLBGGX5aexMDjW/DRqWMsE9SAZ2UW4WCMAuj0JOIPr1X4J1iRA5QOkvaxfpw7rge1Uz7gTEFB2lNXAjWCFiD5aTFWj1mN/aZv8MrDvZB+T5GGGa3gMzUnqfdiMIzzsKNyVWVIft2EM/cGcqVPIl3RM6TNzdvo2YazeDCtC/ePmAy+gqvBfbgCfO1dR3s8rWC98RLM7hHHMc9zIChVEc32jgPcUoVnJM1ZdkAHirESRYf1oFFlEBFqgqXuV1ipPpWP5mqSmWc+hkvawvJPYvDd4QCaHZwBig+0MC2sEVacu0v+NB1SI4CW3i5k8a8OVBdtDdE1Zbi1PIZmVQvCgOU5nO2dD44Hr2LmSB3wCDTmqS9votkeA9hR+R3Wyk8GN50iTLpdQmNbA1BmjgGcKl0Fu0TyWMs9AVUspSB4ryxvHv6KcuAgrBD9y1nSDqA2cAZU/k3GGc4xMLGskkOPIeR+eoenzy+jwc3vSPrONBgKNrogPAJPeMWxU5cPG98ywDJZBLcFLtyTpYnfVH3oTXEyq2wD/NZrz8OqvrC9Xyz3nZ6PeruNwbzqC5mYelC76SksCl1Oe8d7gk/MHDrnL0WZgaXYIHeLBddaQOV4dVq68x/2KH4CTfNfKOSrAh2BBtjm+QTas7xQXTAeF8npw8ZX2pCrqEGXX0+i4ODjXCO9Hab8Oolnr50AmdzRqDD/Lm3qVQEYJoP3MpPBfPtFVrGYRW59D2nF7DRIkduAblukEI/k09eT5lA6+jL2Lh8Lho9ewcWcTHq3zhPeT7AltTMbSayqDwXVxpHMKwKpIXYYv2k9BKw24vIlXuCl8hDEF6jCjmeeFFOcxGrKm6AoWAAW/Z0KQQ/e4NieUtBfdxei12eRUM8nWhetjG807PCgxiBs2CoHozqf0a8MMzgyfDYplxRSlpgH7ZbdgalGdyhX1wtPZ99h0QOm4K3wHqepdmBPdQiculBAjfmLIFV+BWrLTaNOEzW4Kb+djxyTgODZi7hJOpAq5NbT5bvnwPvOV/oTaMAbdnRRVLUZ5Z3cgZ8mWcB0CsGIj1fh+9FNHPC+Dw9N/I7mn2T44IhSaP9vOZy4ZQdHqkRhx0V9vHJMBAw3LAEtBzeyHmyElPjDpK+Vj1OmPgfLqZZQPUIJdForoUTzAAtLb4KxxvqQsbMbhYL+YGXMB36rDSSbKAaO96fCsRw5DEx2wcN/MkAn24X2m8bC55Xx7K4ZhF1/xrGDiBvfqbKEo5HNVKk9hXUXZXGG89CemP6GOUmLUSYiH64crmT3D/X08L4SWCSHUv7Dddjpr0tRtgtIeVor7W/aRNGds2ixtxZUXpvE0R814JVmIUJ6ByV/cOL57SKQ71ZAG688g7duJpiuvZcljlpBUJcYiEYgfDXIgeZDi3CWXBZoiRiSxvll8MA9iKKi1uCUmh3wPsgC4ixccJnUPnANjITGiEG2LvHheau+wz3rU7BxUz1uun+A+wfk4OidCFriV03BOto45rAFjrwjDxe/rEadwXIMua5MGxsa0WOJKrSUbYXbt3VYY4QoL35nyoI6u9hKwgie2AzH+SfnYscuAzL3sYSdjqmwwa6PZhvvwfnbxVHdMxy8T9wBmaar8IEukPm06VD/bSz4JhBamXiR1tZ52OF/BTJ3dFL3gkRYlzkbM1erc4PbdNzgMgn+OxwIofwVTHW2Y86hCVyyPA3DLu+ErIxvjALL8HLMMGodxxAWEUy4aR9kHpHi3PhSfPLsDeet8cbL0ydwjU4hxJRKYoKNMuzaCKC6q4a0wsL48Gc/njK3AR9O+Qe/7i7nuROFcVPaDzL4OwIkr2WSz8NkcGl7CvG55ThOaBT0e1wBw8FMdnVNhzV/91PTVxMINOuAJWH9oFl7GNqUY6hcwYkvhIlw1IrftDpnO9UFxnL/zckgf6cPBPIEMKtlElavWAre07/D+5Tl1H2eIC3/BDRt+4Hl+0bAzgIBvBe7HJ+qBqJ7ZCM5CurQOPN39DPXFms1p9EK7R+838Mc9scfIQHjV7z2fTyJ5P2AHBF3ssj1IfA5CKnZjOaFEby8yQhcpiwGidghhi2xwZGikyHA9T7/CQiCB2FWeEE1BW6/SGXDRiM46xVIq4ZLQsidBDqhuBauHCKqkLdjoyUpnGfQj32ls7AhSQPm32hj+3tVtCXbnbz+yeBfSROqulrIIzemA97zpHZ//SHnUYdru5YS2efxo3uDaPVyOLcUroarBRkoNuCPKnnvMWF4N2y5Mhl+WR3hQtd5bJ7VgrKT32H1eSm4lO7PH17P4B1TwlE9VA+8t+tCZFk+vv7tis+le1i8u4jMbhjiudwxZLr2LL98bEp1Nh78daQalIm+4tcG7nQ3qhobokJAZuHxIaZ9hnV1krzxcCzcWJfLgvumwoags/D2ylzIj5tO8FgFvbU/cd5AF+iLN/P+FDHyP/OAhH8aQ+4DG4i97IX7HrSA+bdGPLj4KLaMXc7xU/pR5fVZuG83F7NMZGBZZh4o/F6KiZajKPOpK70f+5KD5hzm190nKe2FK4d82UJ1m/TAq90Gan9bk5/aVDzhsAFqzp7FswaP6Vx8PXSOVoNsfRF4cVkK7r77Q/ekOmFN1nfyensGSpKrQPrCejp7NQJvSx8Et2NSvNNEGVIrjOncszJu3ryRXUNGQlBdP/zO7oOH1snY7fieX24ZzuE3pWBRnBidG3eGTnkvptP3AtAnXxjjGs6QoI01GozzxOLkQTD0UIAnuukYq1nH8fNWQ+1MP5q97QPZH1TEsPIiFJr2k58q7sGdy4yg//BXGLb9Op5y/sBif8fy39YdeE5PEI1e76eRL+ayhttyFh9FcPpNNUN+EBQ5jmMR1U04LuUMf3laiezTAMvnufL0xBG4VVYaJmpZY2t5J8kovIeddibQfr0DJ5y5zP+KnoKCrzMbX51KLKQKU5wF2bf4JQsUvOCFz+0hNdqVqpGg05NI+48DdZgXs48xgP2vK9w9sgZ+px2hZt39+K1cD45+6KaAogTUqbfg02dDcJasJURe/4yr9iuArsU8HuixZ68Rd0jR9wHv2L4bg+/ehi33msl4UAzc9unRSc+tSE06eDRGnEvNr6CjwDy+ec2aNtV2kPM6Dc69NxVC8wTgV4MTPhl8BXLXV1KLkQU5xX7G2iIdzNjcSZH5djQkU7BBpo/vJvRBtd5XTPCUpPyxOXDz3nXwbliBB0ZehiVfM9CmSxaeGJjhcZN6vGDiDGo5CMc61OhLlCkNNPSz62tEzRZRxOnaEDbtFxcZCOCem/PoeEozGDox1G5QIKmIxZx2ug5m+ARSdJou/DlyljasV4G/WYfom4AE7VfdwftrmqGxTgm90Zj/tuuyma0alKcVsPgHVRSPTeO7L9UxdsJ+ihBaCecz+vmb2D6e6lhKsQ8nwM8LI0jO/Tkr/o+483wL8X/f+DUqSaWpkLZKQwlFNAhJQ5QkhDIKUZERWUUZnwqRhi0lFUkkQgOF0KIpI0WatFTy6/tX/B7ez973/b7O13mex3Efx/XEG4prw8mQbGh2528+nloC/WJxIOp/AOXrACIbXQADX9EB2ft45GMZRv3upXLz67D7nDOfvjmXw+QGQDFJHkKHZ6LtwutguHMYLpF4TB3y2+GjcRyG3xLG2w+28TR7ZRp5dCro/63iV55daFCoSo2ZGqxgZo3uyYu4MFWONq2UhkFRYwpfPxGWvFgEqyZ1YzlocfXp93A46TyM2FCGvvvC6NafQ9yyqQ4bE83A0eINLM6fTdNtZ8GXgFyelPMWJj32x/TXzqjsWAi3PUqhu08dOsdOBA//cK5YdASrw8VZuW4lJj7QZoUNHvDJdgAjFzTB/NLh0DuoQhX5wyAqNodd3vbBnvBLHDf8Eh3dtwMUAgtJlLMh8ON0mHDrA267X0Rlnk/xgLsC3ouI5Y5bbnxkmyNOyyqG0VZ7aIS7Bly0E6adneF47L42RT8wxMVtZeDTsRYyNtzkE46+VHzKBTc6TQOJzVl0tfQDJu77w3elztHPl8vg0tKT2FBUyu8Hp9CM6W40+AFg3kgvjo+bAiJvrtAqnW30x74Tar4ps3fMNvjT8RtCD8eiWaEefO56htlddlRcbQqps+Lx7I/JeGSxLUm8zkSh5U2s+8qIT1/Rh3+HRVm7wpIrbb5R6WMN1CqL4OPn0zhhxy38kBsPcfX3YN9+M8jYNgdMFuZDxPNivpSnx0peAyj+ShpnBtqz7swJ2FAhAqm5MrAAhlHepV20JHkS1Qa3gtjpNlhy6gi8ExAB0XGHaHcCwbv4mXA2az74BWngBf0pZHjWFxZZbeN+sSDq/FTO0ZFDd/CoGRdWKEHNLF8Wi5YGb/MgZndBjixZS87FK+Dyy0HwGHeeBUSWwyNPQWgQdsaJGiNhUYgExyW7cveZLLj4ZwI3tRfw+YK55CSViP/OT4QfRxpZPXQ+H5XJYJcjKSx8UBGF55WQtMJ0+jLqHFYe8WW168qQsFoMEk1twSNHjeSKlHF7Yw2teHuTk550oeN7UVBZK8j7EuWgSvgO5MVc4FXpl3hGhTy6PkyDc+0a6GcfR/AyCC93p9PVAFFQnVNLZiEzODY0c+jMWqA/VQmTOyLJTc0MLXoqSe2kNv4zGMqnz5rg+4U0OKxvgqa34/Ecb6J4LQ8+uuchXR+/Ey7NOEu6jZNBBo3pkF8dxoTn46s1h7j+tCLVDzfmN+ZrcJZeDL+sKAb5FDHYb+VOOj1tFHMjmd4IRGDylb+8zEKOVm4fRbPf6uGJhARMJzNYs3oyyS44jBd2F1L9kHYnGztQgWwGqYT/pCdfa8Fu9RhUqReBh2XxfN2tGybVnmQfA8ZA9Sj+/E0D28xPAr3tpEwwx/mzxWFTRDWJ7xRAEP8y5H2KvMfnNG45nEH7JHbhlEvDQK3oF4euHgVs0c3ntS3wg8p9jGiPgdSoqWT23yxYclUD59z7Ra8WBpL1+LGwb0QeybVPRL2QRpw3cRTJZEZz9D4jLki34ciUW7jF6ADe+KsA3RaRqJigCwkVoWTjMooe5lWBto0bzfs7hSITU6DQIAutFGVASCUb4oeZw71v4vjkhT4Ub0vBPJ0GMGtpZL9PD9jhgyf1tk6G7iPn4crLaCgavY+eHQ+AQR8HPvQ0jfPsdPlhw0+Wzj5Kf8yMoC79AZdcDkS941pQeLSLr9hshWevUzkl9z6qnBOhb9k7QdVCFj4dMIcNQ96ZofGTGnMtuVUon/Z0nmbZ+a58wuob+Qlto8BdkjBD0p7fcSRuk58L1kuc4EpcCZHNXIw88p11DzkgjdsN3g4K8GYgCtZPuoBOqma0BK/BQppGYXt3wq5x96lj63tcZHiDJ78Wg2nRYzhQPB0DwoPZTc8a1q1UpKpsQ455F873j13mvWN7ME1lGOweJclrrhnDv5ROtNy4GLQqF2OPZC8XDEjxessTuN9sHW1qMoJJC77D4Jh0XFehgIunH+RQ0UGaucoTszIzYdnDGzQ7mnj/7JHgvrgS7Wet5493AiDhSxmFl8yGSfFusFMY8NXCx0M5p5mNLMRh+N05GD43k19HK9DKg5GQPO8rZLzbD6EfdkMmx/Oril68Z6oCqyK3ss6OoTNLWfPjV0Rqe7azeK4pOu9N5WNnZ8GdoH9DLBaDVsED9M3ehILa+2Fs5gmYOuMKD1aMYNvx+9DO+C41mrZD8SpBWF2wkn+GP6e65xGcrzaLbDXsqd83jA6fX8Be6w7wiPKlPN5BGMrmnYUQuan08HMCZNUwnrglTpUBa+ms+gvUPDYeA09pY22HIfz4tAMs9wvC0uQUjJhkgRtnjKCsk6vQP/8ffXeNpAlHC1DuqzyIBbnw8tMz4MBCQMESS0xT7ISVgWq8tbyeji9aB4ej//DOYSNBPEId6rUfwL0MxvkhPnhuyQpO7leiw/aW9GrZDWwvvA1uurIQV1DA25Wl8fB2hDnN3bTffiMctU3iT6UtrPJMC15zOHy4NwZeJnZCVvQivG6oBX2PDuPdaYexd1c6b4s2wa5FTTTy1R9Ok5QHz58f6HT4HXLv3wTPktLIY10AO6Wn0tYFzrhZ6zm8OjKHSuPUIXGXG/Ktv6w5V40ftXTAR/eNHGRaw6oyz1GlbhIrhYyEkSwD8W03uPCjLhrWHIIYTyEYXZwCfpJLcbzwf+An/pv23dwCv8zGgPNuWb787jhnv9uD9h71LHDvEBn01HCY/k+S3d2Kku7J4GZjADOurISfExZAW81PjGqTp40uizHjjSrN8zkIlV/MqX+wmVbPGA+HgjuG+lYpm8tX89NNIrDfKZXj6gHF79rzskN3yVMkilRbxsAEt3iWXAac3vMOoiqW0KemPBq+twOXNuiifPMFTqoUAM/bGvCsyJBFZesg1/AsOeV4QUrjAVxTlQn6GnroazSZkoVnoIfmdJii8gQ/zrmGZ/8dhfkFjnxOqR2Y9qPCL1+y8vRl5RkGnPdJCY6dk4GEj648v6KEfKqbeVy1Iz6QuM6eJ7rBtSEOdPcHQZyzGsSZ27FD9GdWziumxUIH+Onift7wYg6IzbBlDWmCccH6kKYtDO9iUjlKsB3n57bC6FWpcLE6Ce3erUA5i5tk9OMRJT4PJnIfC/huN2uqq6KIpQO21o6A+vCLYPT8NR3fm0ha34vIs7KFhSJlQUuzGzP/yrCH7HDcWXqQTmgKw1l9T9B8IQ4PUny52mc+3PouBvrLy+HRQQP62r2D994LQyHzh3xY2ZAMvoujVmwM+NgW8u01InBgShGl1SyB4N3y4Cv8lMyzTVm2LA2/DNTg0c9aNHfvJe7yEYTlsoLsZL0S0//qo8cVU7R2Sueprp/A8MuQ/lz+wt9agNrd4jDf8weNVsiBGosHFKYnDwM9AVwd4I/qa7fQ3t/O8MesAaeYjAO4W4FWj3Tp96QFoGN1i5UdBfGlTzIUfZ2B1nfe0aiz5rhFUxDOSezkT3/WDWl+K34Pe8kfz79gjZCzZHMwAdfH5dKqys/QpikNWwuEWK4xnbXWBvF3pceg8lgAF+8FSD5SRHYHOsAn4B9YDkqB+tkNuGxHNgZlNbPowxzkkEpeEvuUHP4qcV1mLCx2f4yyMdNBaGEzvt8QiQfcvLGmup9OrLeHr28jUWv2enZrygWBRjF646sHU7o6ec2VevgufIkTk05yzLgKkB82Hs9EZOKZsKUcZtSNZZayUBB0Ah9c2ws7R0wG0S+B6Ne8jmaWToVdYy/hihIv3FahiA0PzKEvaRzqPBtNLquSQK/9GWmN8oWrPIfHm9jATH031rUUY+XlelBROo+qco4ynpqAjolfqSIlhW3nOPCu1hXwoG8rkVUEmMJkWNEvQuntg/DNcyZ2ztThhKXzQfdaIdw0doX+AzKUljdiqFMPh2/rs3Cr3liwzR6D5wv7IDTBmqw+92L943n45YM9qJ3NRkkHPXh4eigfJ11D9+1V0CqGXH3zLiW+3cUBB1yZZW5x/pcjODbLBHK7y6lgsRb+rTHDynviZOd7m526h9FYiUpcY3qQBj3Ok+dmTZj73IU+jh6Ar/dMqHH2OPB52g2aitaA7rV8P6IM6jXcyHJQETS2jsAgiR9kQDqkLloCE00+07pcE4ipGIvT5G14Q/g+nOthDmfvTQL/wGqWkmuGZydLSGRGPs26EIaaK/0gTnQXvj18FDJNzUH5vATPLZLmPepXQVNOkZq2LuM8dSsuDZpDV9tL+HCqNJ7oM4eMRQvxw0NH+BLcgqs6WnHwyWcWrDOHUD8X/OrcRGvv1A0xesi3JnnAH/V41i9vxeozKbRvKL9X2d6lP7VHwfSpKC58Ng2O3h0FV+utaFfzfDyQ7cF+U8yocbs8mu9OpIdZB2FglQZmHwtBDpoIRQs+0UW7VGgJVYB9sm44qHCYrd3GsczNHFLx0EBL4VweryYA1v6zQOb1OsrYYMLD8vfxuRJgF29flo0WYxEdRT4f2Qy9iVOgcUUrtvxYz3biOSCbqgtHNxTBrIAskCp9QyohduRjSxjtKQo9+3TpWu1zmqOnxtoSD+GwZxsOW2TJv6dkUHlgJGTUvQB/L31QN0/kvKon0KEpR09di/mG5X+8vtSQlvmPRas+Ubq9RnloJk1AInI9v501Ab7fXMiWS9UoPqWYBWKtYEqIMrnDVRij9RAExRjWBVymvNNC4P3yMr1bbwPZK7tI6n4TX1jlze7+g3TVSR/uXRAFLveii01O+NZvKuU8q8Pw11oUe/47P3qxlTvzlWCTtB8J1pmAZ1EaRq0R4E90C/psKrFvmDhGxJ3DizdvQYroQlpwfB2eb1OGS1EbYclaPdJKSOV06yT84YkYmPYbDA4vhtm+02jggwkKnBOBmY7K1P3DCvfoToKuAkto9LRmq70f+WnjV96SfpvI0JJCTRVAQ24uywysx52uVWR8UJSu+DTQ6cE/ZDjqCDctU8JzC/pI4JY2RPSu5j6xfqhZoYHG6MwRyWNAIFmSA+eNQ6XrlnzZP5kE4lRBPPo4HtXMwsHNWdDaG0DrJK/xDM80LHviwZOlPmD9jk9YZqgDt5878Mxv+6iqbxZZZb3Bj48q4IZaFPS0u/JUpz6wmBGIT51U4Mk+M0YFMZrj6AwBHfnsL30JbuQ/5B3x+jTz3xrcv38JH5tgCPPj5DB/wyXI0ckkodIKfjUxFgzz20DbMgTfzdsA70Rd4ZSmNuD4o7xxSKcXNFthm8AYgEN3eOS6U1ietxStc3s471ko3LqrBDJFb+hi2AL6MXE57xOMw3zFB7zsjtNQbrzG/+wSecoEVYj5iDCx5gw5Di/EpMOH6I+MNEueD0KTjCmcvuEJlNwQwl/Xg2G1sBrM3WQCA+ntOCZIhj/qRpOTSQy+vubNn9uH84SfSPpRqkA54jBDxoX8FV+h6dHt8HpyNubn3YW09ipQuJ7Hy8wkMX6ODj/eKgIimqXQeuwWi28Won8Gj3jdUz8aHLeafR32sWNSHPXmH6XcEjEwnyUAf9aeBLfpEaihF8yLV/0Dv4BG/nQlBHRkE+DzwVP4d5cKHM2ZOKSvxag34zBfX2XBimsZg/b78VuTWBpPNTizzpY2N2uDb6IevJSVo4/3S6jLU4ir47eQ9ZRQzogx4BnHy3HNGXt4PqACNgOaLPdLDR39knCWVyLoHjxJB650gIrVWhaWNqafhuWk16YKqn35kBAyhh2vCMI9Aw+edTuFd7XlUeoJfzw89yJvz7DHenVhWCYVCA3eKRCWE4pVYSXsaCpLEZ46+EbLFS6dmIgRr63ggOwYkGpFtG88xOsXZLJZWTT3XygA6y+PofNrPbjiWPx2xZYPJqhCxZO1rNdUiEH/HtCu/cNo+Ik9nPA1g/OVGrntoAltaAgB78sy8N7xDfouVqevG8Jg+1pRuvusnOdPzIGIHU+49lIEZMTegF5lIzDcogD3fC7wqSl3YGZYLN3qrsHUtzlUPpRRF9m/p8Uh2dQrYQieX55hiIYUOKzOoYlnj2J9jS77tfRBYPcprPctIv2eY7RlpzIcONKOS/puce2SLNAqzKYk0UmwKHs5nUqP4CyvItwvUwI+dQDnqhfyjXRlmDizEN0OR8GVR3doXtJVSEtYC3o3EqnSaCt7gh6M01xME/UvQ21EA23wDsK9/ns5fK4EdTydy6r/ybLkOWkqXCQPRZO0OKN3Pq+x2IeL4/TwjOwIsPO+gH2316DHQwEYW3QWWnUkwWf1UlgmdpSPmbjC4eqDGHkKsVM4Gj91aIOGSw5zgQldHspXgsfnQUdxO76sdcXo1rW07sdl3vOhhWblaZFurCjfKD2HFq0TQbbTkqf8M6UIRXG4ev0JtNSL4eMpb+BWpDuejUYMFltDa3fJgq7mQjxRu5hdB+w5u+8oBvRvhf9MnvOXYg2+XCOAQl63aH3CKFBS/IDNRRt4vlkkTi/ZD0v8/eBe1D/UOuIPxzZtp7e/vUleQwIqx7tw1egjLFa+bWjeBGhjuTil5ouz3r1rsLu5mH0VFXGaCsFUn6vcZKzKluOugLz6f9zd9xDctGtg3nVxSvi7HPvHlfJhO4SpDRdx3YFa/Ny3DloK9lBNRibdL/eCFx3vaWDifJbWbeHhpmogO8afj8QqUu7rPSRZdoE+K8WjqvEzDqgo4NUp0li8To9WVaiCs58ctUqcB7XjQSAYfJmlqYdtakbRLRNnqAsYCQURv3mClCx8/m0OPq/OAOs8g0lW0XCpcieVFReS4/V2+o5n+X3FAZwvNRzCK7uwUciZtWteQPfbv+Qr8R7vJFXR65SX2P+7DKw+BICRtx4E2YVhsN0PCJryiaSqfHDxw3LoufgP1SaOoNGCy6hAyA96jVShbNtzvHGxES+s9eFRTcux2Xo/nxE6iVOXBHNDZi9mPh9ENQMDOD2iHI8JDVDfsgrKPXqVJNIy+a7kCawq0mDj22lwTP4sRI6fAoOJUWh4SJu2Hc7lnO316JSrB2kdMhjaFEWb7jDvTK8k9/eqEPvaBe5oPMVQgzRUmtnP9guvwzQrOdr7dDN8VnnND/6TJV9xFbjWwGzyOg51lsoDJ6zFjWcn4JyKriHN6nCseAsLm8xkiUSEIiMxjDw+hZMid0Nj8i56mBNK7Wr2OCfcFwOtWlHt+HiKMJkJ3ceD8Vp2K8+8yHS09RS5FxciBB2CSY1SXD0rmCa5yGOAgAFYvRWD1zPrcJGdPe26XAAfFXKBIvfTxBkeEN2uxYceaVJz+BjQ77GFRaaIXyRNeMGeRDLLWwWmvhvYRfwCjkqIIXUFQb4rMA1y5K7hON3VZLJlEc2+oU+Hfh6kVw57sbAvhMP7X8KV3oNYP1oXNEWe8zwTSQhdVAtv9RNRWfU+mqzTQhsvaX60+hOH1Q7HO6vM4UryeNzl+Z1tfhvTkoB8zor3wnAjJXwYP509ApPIJDOezH4owYPkWMpyFSTxY8qcFnYUl9y8gzN9f+Fahzl85eor8EgsxCv/mcDP7T7w7tp3uPiP+IqMLVc9PoRWi5XQ3JSpTDMMeixiMLxdDhY/aYPWiQ4w/6s/bS//QMNNNdBhohBImrWymOZaON8txQpzFaC32pQ+7BHlNy2HeEJNNd+9cpQ3FP6BclUHNogKgb13amDCViEoOrqFVUyGQUf3C/QdVcz9dxfRKK+JcPHCB9g40wDrCw+jwj5V8DpXAKbBr3hL+E/y6qvijVfzSP1lCdT9iiCP2woA8lvwyXoA34Y6+lx/Fpuve+MM9sZTWi6U//kWFp8ypZ0bxpKQtB2mZo6ElebSqG+wkuef6uAXH1Lpkaw7BjRep1Nd2Zg6cBh1hIbz+l8mIPxcF0LuPkZhg0A6XTIGri/PwlHB8bzn5CCl1GzhvHmpWJWkC/7xn9G+ZhE6m43DbWpxKDxrOcaZt/BJL0M+p74EUyVVwGmlCYz5do2tNg9Q23AbcE7K5CnrJtDZf+lw+OsiHK2ymd4brqHQz1JwcfJ0vLIsHe+7vqDG4jowNJ4B5QKjOHVOD9X9VuOUNW1gkG4EP71eUsV+aRp9KRo1p8nwplolEDKU4OgN/li+ci4kT87mFVkioJVdRO9cJvGtEA1as9IWnl8xhAfjF/KZjR3wM3Uthg7lFuczErDQ7C4v3DSTJietoayLs8E+JB/L57xDl5rtKPjfAF25acFpFxTAQ9sBh5l/R6W6TKpzj4fM+N9ouLsRjsccoGEjFcDZfCW4bZMB18QVWB2WzkGqSfg1djUEOKui6oMKTIk+AIlxb8F25E5sS50J7tNHoOs6XYqxU4Kod848skKU8s6PIv0x7vxhRhRnPpoFCcUTQCU5AL2PzYEL116DXe4knm76jz71NNEZlxqomzUZo+Pvw2DfcNi/6y8IyIVR1yDj8jIZPBjjjYpicVzw7RxV388k6YRrXFekC3Iiu1E45SGHL3Ag0bRN7DOpAl7fXsiTDzxDy59i0Gyozi4wCZbZL+C5miok3FtAvh6bKPxnEd7ZupiNTG3gTddHdviWgX4rRUFl0IhvaN/hqaYp2Brexp+j36LYu4PcO/MPNFz5h02ZJ1DbVxrWySbDknxNsvE5hmdueuNkJrpZ5Ya/q6vxc7MtW9f+hmcGajDW0R6vPDmJMjYveErnd/r0agMovd5G5lt/oum/FHR5ew1FJghC1s+RuDRpHq9RvERqryJZXrWKK8mRmhoXQMWHJew0/RhsNhgJLxp76eu26+gerABG03qpt3cilz+p5rV3T0LUwwrMGEiCSTtHQJvqRbqtkUsHFrzCpzsdsfHPDpgfaUEO57tgcv0dfJrhBWPPGEC7wVNMW6nOp8P9SDZ8Kwx41JDaW3PYeWMhyHcOwiSnSfiwWxd8st7jl4R13DnvJi3xTqIMNx+U+eqMzVZufKU3C5XuvsW9k5Vh9oeH6PBeisKqn1FeoBNt+mCKKzbIkrOILo9KuQrP/Dzx9pWRMEEjlDfJ3caBadaoIV3DGZbHYdHgYiz42olXhwVgVtcC7mkXBKEzi9nrkQvMdHYgrzcisPtbKrrGzIQvKadYsv4qNlhE4lqb6aB0TQ/2HvZlfd9fNC+2ArWuNrKKqjPM3e0FytpHaYpaPKyJV4DmKW/x7wYhqLsjRufVvtG0hgJoSCXaufgWSArlQe6Mn3jriTY8v1kI63dZk3djOh+4aQGthVvpU/ED+DpWlnrG9/GTMe3g1aEC3qMe4OR34XhpbCgferaSNP4q0/L6HbjrsDTZhTwGuhYLwba6sM2uiF7rL+TlXxtw3q0kSI/cSwrrF5LmyMOwrPETXXnZDEFXlSH/1jLUnGlCGT/sYeD6Aq7+MZoCt+6COrVvXF76BcX+1MA6t2HQ3GONtvd1wOlrGxn8PMKW6tlQMNeTfPfeJcFpD1mnsoKaNukMvWc/3IpeBBGVV3DN44P4fHI9eBl3wqXHl6j1Zzmczt6FYw7KDn2DmVgtf4p9l8vQFlxFq3IWwjXrR5TaoY6thT+4snYGLfEaB08+faeFl27z8QuJIHPaB8x72ikvK5xtlO5R5s8d5LOml9QOKUGkkDWeneNA+7+/gxASwz5lTRquEQaHot6RQJcbrB2RSPdHAAhN7oO2HFOyXXsaR5p9oC9PVKDOVRftrl+BnU4O/HlxDAbUy4L+nqX86tVWNpeogNWDqtjlNJ4aRoxn56KJUP/Lj094hUKSPkHl8QCcbaKMawR7KHWLA5ppi2J2vCqukNKlCzZSfDmsnVafGwM5l+1olbY3OPz+jx2uDvX2pef5tJ4Pyu/O52XbpzEY1uHdZmmY/SuaRl4V5xQtLapy0Eado0spv/ACfc32I9PDdtRUa0QqL3Whd1se2v6ai7vklkDynRr6ktPF8jeHgs1oL7Y4so2P61vicTlZ2L3TF3caaEHbxk+4et0gD066hJPn52DQmm8wdmQoxUm6c+0JPXhfmYmCZ9dSelEHi7keBFvFRxTxYYDXNezhEWvusMQmMQ4+KwnlNQ84OnU06KfMxKOpbtgUEMLVlhL4eeNd9hCq4nPv7MFqmiws85RChYm/CE/Lc6nCLhI1t+Xvc5ZDyENPmvysk1f4BFKRqz78awiHsU9L2XnAl6erN8CCkQux+rgcT3i7knbFAJUpCtG5AQCLqMc8fE026Ng7oFfLV+q06EPfMkMSmOAEKp6y1CzvD9dBBIyfqcGHvCYeN8IHuuIi+VrdNnDuSma77nh8GnUFPrq+xKP6ohAi64+zCqVB76cNB0yt4DgjafyhrQWCLRFY+NmZ0+5ehq/NAjDwnzuNvWyCj1Vv81V9G9AJSeaE2MW4fGcFmmlk05i/zWxYowWfvKxx87uh+7h/ip/M9qOLr3Poh3kRXb8tAmN32NPbv4fI8JwKLLusTe7PGtEjTx6n33iOfcUb6MvcOKy/3Qn1wkI07Ko2vzyhCHtuDHHXoQpWR02H63ey+MKBB9TW9BEHHZ15nuMl+s91Mr1UkgODZ0Chey2oa7cplHhJ8fcwKdr9ZA8UbD5OU602kHxZLoTlKoLQspPQWKiOqrbG8GVRLV3LuMmYt4Mr9krx/pBhtKAW8MR/ijBcsR9RQRUDVJ7QGL1y+gGLcM3NJ/jKewsEy75gI90rsPWGBOzb5MRi408DV7yA11WVmPrVFl6UzmGXjCReyy8oK8WfG/4Ywd8iQQ5zSODuP9+pJewe6OR/p5T2HfBuri6v1P/OtWerQVfdDD5N8Mdn8kJ0SyiP/5YEU/EpCVS12EKJuA3ad19A3Q2H8Y70FIiZOIJdTzti0y8NKPs4hhtrNlPzzxyS/lyH0cau+CRlJJzIFYOGwouc4R9FpQo9NLbDgn1iBiFsYAqZzFKC69VlNHg2m1MTTOHEvjSK/WHPeYbDsOLpbAz99BAq5URpfvdCnHbmLrxSe4J/uwncHK5wdNx/OG3jFbrZF0SVs47g0+3NcHV/GJ0qD8N9xY8hJE4EHoeIY7DxFQ6sbMJJZk54Y4wBzHZRYOdHfdDoJMd7xOZhjr4C0I8qWuRTRmLLjOFX3lvMF26DuJf9WPCsh/tPz6YPh5Wh8JgmPAhNJEGfCBocvh63mdjx0hk2UOU5i16ED3E86yQdFvmPbzSIwTuxR+CmsZ7eyFmQqfQefiR8Fn2el+HPSYy78+Lx5KQqzMwRg5wHKVz57QieEttGj6J0qWrUJHg3ZwGXh8nQg3u6NH1vLc49IQ2/495QW/cV7nUez/oKirxP5gforL+JYr8rOGhsHuz1C4cM0YlQfHs8JGrrwoj8PH76wR7Gv/jAN2//gZJJsRggxCBouxpya6fAQ3MjKJ57hMcWNpG6YBq/z0jkM+9/g3fMd6o89xRbvYajk6UeNH0txWdSLjjwJ4XVfC7zNO2RLHncHOI7hOnW9GTsnncC/BXV4JZbEqfJ/qXDV/2g/HQTy19aiz/1z6JnpwSrxwnT99fTeIaDEgiKi1KKQh5v+xcHhUs92eLbEOt359Hi9Q0srzEMFqiq4JKXY2Fywm9eG7eBpIWjyKNYjRwcWtg0xB2ffwkAwfNVdPGkK7q8MIS1y6fBLClVyBpniRudn6Kq5ioYWPkAZ9fY4weDVBaeMBEnKs4AL00T/PFxNl30WMDB6d5gZBxFfuo5sDOiB3p3h7FxcS3mlOjB2xUHOe7USBY6X0iXr70nwUAvErNbjd0BmSzfUYeBrqvwao4G8LkKdiv6TGmT94P5u+Po6POEjH99gdWrq/HYWlmOFnalwH+aEDpySCtrJUlL/jtfPrqRD1UhGbRbY6n9Ir61zAqXWiyHHh9xWC4zgXdPGERzk7Pk3JsFjbYHKWrFLjp8+yGKjHtLke238Ye/HrgvaeQ7QY/oS0MeuMvm8JFoVxj2xAZWhHrSopZONIozhjJjgOjgaaSbmw9P5uRSrYAP9reVwFrR5VSiFQBxUnN56UZ1FlCQgm0oxM9FJenfHSuKeCAPm0KnsYV8B0XeqyOpDWpwO1eAjxerw9Sw/+jmqDJWPnUHHCZ3wIDhTdySMgBdB1xAWEIF2lOT6UDmWLh8aSEWRbXSGK9Q/Nx9mv3nipPXlwyc3viFUvv+cfttd7b1VoIdW79i2o8BPN7/BW+ol3DPbSt+XjmfZm1qAYE/0iiyv5q1hjS3ZrgDauND0HicyS/tEmnPsTryvzcVNl1S4EdrzpCihTnqLNYAtfsvaddtGVh9fSM4iL6igo8vuP3hfZ5cPo2752VhkDfzZLmxsGneS9CJ/kBbbc1gUcNKDHFfQLWGXTR543n2qPuCYDkX44MnwsF7xnzmgAb3BC2C18/CWOe1PVe1FvOz4iRctEoYv8/NgcqI0XDsggivq/0PynRm44wsfcg4akszMs+SUKcop11+A+kRu8B5uCyMKjhNe9tN6c/gSZB7JwfBr6/SsTFRbJzUT48vP+Ewq934JmUMTJAzAO83dbAjQQpTAgagSquSK0uGwd03gXBbwgE+G3Th16MT4FNHI/vbfmZc2cB1XaPY6/lf9mtZAalfE+GM8FIqsuhCtYBhUPLPnQ9/uoAafrmwN7ERFs1/T7ZbOtm3PgyW7e7g5cvM8d9eEVjjt4AmW9zHmlUHAaWrOMn+EPW4/uNZ40N4r6oZrXqAdNdXGBrUFfC1732Y8q4AAj79woAH7vjlqi1+3E/80jsbT1pVk0CmEFREmcKqkwUg4GWE+xIawOh3E/6MnUW3O6VJN6KcRWbko3WwOTTWH8GP+2JpXudIuPWmm8sX7mabtBNUZGhMTeNl4dQ/ZdruKwCDFTWsIyfMQqJfYK4hg+Wce3x/niQERmykqoHZ9L3Wlvfg/9v6X/hl30J9mkfxbbQlsZ87jQ9Ih2s7nNj66EK8JKeCg3+/YluPNhi+e8IpOVpcUmYP11pFMae/gkQVb+BOBVd2eX8J/nUvQDVTKdg1dzYcVJrJbfMuwSN7KfjoL8sH/CJ5+sqZoH1zO/98sgs3akuD27w3zItegig5gLrGCrh7WRI3mY/igL9F1HI5DLLn7CBLq6mgfeI9ZqrvhDULxHFCpiCk+Qnx7BkHSXJWG26hHRhXNp3uixD4d23BI3v+8vP6vVx66DQ3ymlw1fALXHW5n1TfpsOxY79wxQEVsIk4CgfuitJM1TnQXLgVP6kW8/3Gu3A8NZJv6EzGbcsNaM8oZSioS+N6szbwnb6WY98GgeyeFfQ+MRuOG2wgh8XrqenjdmhsNIZozGdXveswGB+D11wGyPnpWXz0cxvlLXHhqA4NmDL5M3r3S0G0RgRZuoXQyD2VAJM7cIt4Ke/648g2jSqg0X6ZIwJK4MuBCVA534OksZOCU2z58bscWHk1BCX/FXDgk9OQM+hHvsoaJOJgDI+9X7H6xhW478RmunHtGKsUuLLZyFzYkhsIck/CodH3IFg4qkJTiyYL71hF9zfdIfVL7iAYbE4nJE6A2ZtjqKgyGUTdvuG9Id+NPsCQhLnke3wv+xgtQjen17xsVTpOunUQxxbFwI3qUfRF1AB2jhiGRyWuwD2n27BKshMaRx4Y4vtFvHHTmx9dmoFb1E6DRZUSbO56CN5+I+hjxkt++HQWxAjP5YBlz/nNhLt86pEyD3s1iLVr9UEVR1D1tAOs0v8XquTmU7OTIO14rwFZD8ZA0aSF8PeCF+05ZwSXz0jzFVEzWrw1lrrST0KZHpHM8veQ+rOa2zzzafjRlfirYTpYNHew74vFNExDgfSNpdDE1oRyT+ny6dTnPKw6FiLWyFKmjRqkzY7G4HOeYO/9CUhnBKw7rg95XiYUKTIVngUakHJ9GxxSFIf+Y+qkWVaLNXs/4qpNipS2JIXrPNag+J4j9HN9KLzaPAXLpwyH9HG5PG7ab/7kNx+e9mRznksVdqmvoe5P7hhl8ZpWWtRgv6QxFLrf4YstTzgt6g9qvXsDTyM0SN/6O32M2k4CquvQ+ZEmfhYwhws3l+Iy/X3oshx4zrRvMCptJ8VYXYbV5nZkWHuaLbKbIUFGF2KcYsDP9iTFKv7k0PMruXiyHYf662HwZWG4KdbLGvLC7OQyHKrz7fCTpDgt6WjjNe/y6WloAu0My4K9T2+jjpUNWfe+Ql+50aCYl0L6Ib+GngXQumcde+w05fwD2yDiugw3/H4LucXZkLrBGHRVpWG06C/sO1uFI/vt6eGyNrywq44+L78IydTFnurioFioBJd8j6DV8VX88UYFPHkyhXeknabnlZ5ksbQSTCPtuHn7lv/tzAEv71qqSDfl9Bofil8qS8lYA5dWXsPeX1H82z8UVswOxOVKJiAbPB9UzYq5bWAzvTgbAIa/ASyD3tCRmapctW8ujs1fzoMmArDv5VeYfJ1w0+hF3PtrOFqFNOL9vEL8XZnKdycMR7s9+nTYfSb8PVsMHb++4PjSV3R6dAx9F1NBR/+3PHbgLz3bKEBWXR0okioNUubzOXaiBdWsdqRJsauG9LUQ9cok0f1zP+wqFcS2pvmoZjADAk1s6PuANpW5R3Cu9ggWen8E6sddpYqqpeCzdhK7zfVDqXHjoPC2Ks1KDSbLbAFKu7Yc/76dDBIpllTYXcXm/nrUevMR36iUh4y1O0E/egK8/9BDnjIXOBC/8KuOEK4/9Y/SShN45ZfvtExSAzolKrF5XT/0nTuPz0/8w+UHJvK7Ei0IV9TBv3eaMEpCF51i9OB36A/oqSrGp3UL+Xr6CBxhlAc/X02i/qurUNQiE5P3dfKW8cZQN1yGJ9lZse/iLpgksBSlR/4h4zut0FWYy1WZ5ThfbRMZhBrD9pcZqBYpj9Hb7wNPmYZzlJbiyhNH4PHsJJy3+SM2mNyEey9UQGnmBczLuEAzO5fy2ohnDIpnIMFmB0/1PMBWxS28IuMVjiFl2C80ApefkcXmOwpQWibEjS13acJmOdh9eRmtT1Em04RSyFYaC9OtJfBAXTDd8ZlO/u36OM3qJfsWL4a9kzT5gKwrPVlYQ/F7VeDghbeYVehPm0r6sDPZFH12faLmKDX62a/DdSsvcJlHD6nXmkP5isuw9n4G7WhxoDn5x0BZ5zVcnjCV47IKsJcEefwLI0ownwiRf+ZCSMlpDPiInPtBkBKGJ6PuREesvboS/1thCRXH+jl4jiy8UXOG3Ped3FJzibo3/MGjDsmcPjid83STSazpKGsulYLujwag2l7Pr3qt6Wl1LT98sJgDBz7TlfcWPNxcklvM/uH5hXIkc0gLBP6zZrnzN0F3RzHf899NAY8PcdWCj7jCv5+t54aAlvdWftonBI4fXNlnSi8Xnh5G68dKY+rhRyT7xgIbL66GMP1EdJ91jRdomcNp3TDOWDABjvdsx6YHVSh414VPxAhg6m4tnGOphbHLM3iH0wg4skcGSu16IM7MFIusvTkWVGmF9H1a/28Nw1ukrsVFsNB+HLzZqgYmf3rZ5VQUeceuRPOqdai9WIk/D54Co7hUrpK9BTuX6sH524HcqPGW8xR7hpikTf0aU8kveA54rlWDMIcDtOPtAsjuFYLMUb5QrClIjtdFwEOyBF7sXQBGn8fQ9yJT3MPH8VXHCrI5Ox3G7imG1Yd1eLBzK88b8vr/DgKvd7AYmotroDfPC2St19A0VwFIN7Qj6SOJQ93hHcdKzmLDq/N4pcQ23K8/CfqiD4Fo9Gy0kjcBz6BVFLSvG3auWsfjapfC2AADHL3LE1/eeYjBC3/j1u5GXO+tD8b9YpBVr86SlbtBY7IObU5Sp58X3TD8pitW+3zizV+tIPftCBCYHQvq58byZe3bXL8wFZ99SMHe9e5sWV4K9aczIOTZPN5VIAJweSr8nV0P5l1GvKWileulxMg40AcTNeLAqswLHyxbTQ6tMrDXuAFVjvxHTk5J6Otxlh8ExEPlkWIqDBeHP5X3YE0JYFEdgZ21EioUl0FfkTT3PtkL9XeX8tmsX5h1YiyN+DSRIvY7ktxyOajNDyKROm8uzZcEYdGl/OOpNR4aUQK6Q1453/chng+Xoqz9BtB/WpULHmyGkH130doiGI+LF5Fl2xlqzvhIYy5lUNPWa6jhaAb5UbdYecUdDL7aCZvrL/I7kZf8u+8ESr45w6OejSO+cwnGz5SAUf/8WHR8/pBHaJF6uQCcGXBFmUUVfK80GBdPN+S2jd0QpT0NHr8czmcDo/HR/QngMO4BfPqZzsM6V/GGO42ksyMVP+fb0jOP0aCU3UTqLkc4+cUH3vRDDmYPC8WDzzrhwH0liHbQx6S/opwoaAD399VSf9xsNr7pTiybQJ92xnL+1O9UbPmVNh2p5Ng5faQbZAQ503rBZOoDunrBnz+XVVNQihWMqyXMDI9kc+kX9M/JgDqGD4fhJ8rwntU6Pm8wCgYi9/Fv5V7yTVcf8ugVOF/Xhm7+RVz+cjToTXdD0t8I609q4pPsKt7cNYMu7jlFsnfy6O+LEfxHcia6e0yAzNFaJFU7juO3JuFs7yO49M8m2m7ewyPCAeSebqHtjv1c9U0Dgrb5srvXDFq+/TuNTuxFOhWKmSemYMZFLWi//R7/lm4DjxIR+FK7BF3a/6PUF4403lICnaVVYczn4zgu9AEeW6gL49zWsOYPEbCtYTxj145GBxdxteYCKtueQ7s2f4TvQ/x1XF9Ai8M72ersKEjefIM0g87jtUcuJLovmG9G9xA3HYOETGOYP28+58fY88dHw+BU6FLeP9TloToVpgnUU+eqX5gwzYMEz93hqUdcMNLiHI921AIzt2RIyIqiprxwDhaL54Y5rtB6rofTVoaAyihheuW7EdXLdCB3QRDmHrvO0wdmwtP9M7Bqwxa869KJ05atxobadq7/8Jy+nR8OF23SmOIJZ8RKYmTfcPrr6AiBI94D6uzHCcZWmBpjj4evm8HEQ4yFtXfwkMhpUIQbkKq3lC7rp0Hy+6n839Ji1ngjwe2/5cHo62iKuTwOxspU8fFMNxjGH3DOWAmWafnG/quy+cL7YD792wCeba2l0sESdsu25JUPfXix+AdoqbAlra48Lp3yiER3mnPQHxUo1RXAgYjjNPrzMdozNgtXrr1J175dhtmDzjA9R48PbrejksdaMPLsUo6vP4fXOqQoZMEMclwXAFcuMir+W8/eH5tpzGstii8AmNMlSzhOF/JjorAlPBgth29AiSIN3tb5h6R9siD87iQq/i4Hge7PqfVCL+RNnQer54bjp1mW0OVbj5c/nMKtaZ04ZeM2CDeShSdB+0gt/g0/WwRssMmJtl68CM2yC8jhRwilHS8gA4NWnP9GFDTUX/DNw850fkk8C3Y8wt+3p8OvZDl4ci+JFyxcCvc/TiHJqmHw6Okv6qqopwmzR5Jfxwhe9nw0dNm/Z4v972BF0zsuV/mPfzyShebF9uiuoEevwiU4fYcyVAS3ESwswoSlBG4DB2HunlqYfncK1AzYcoigLUitCgFBJTWOTciEhGITlkiXBbfo01Ts0AqH5qmDU4EnjglPpH9a1fjooB8GXBTG1+NWw8qTkcD2czHp4z0WGmK4g8kK3p9SzelFu0j1mDku6GTs8t4EdXNu4OXYJFTbtpM0BZRB8X0t/VjrSGuv/4E7J9N47+cs3utaydbbJnCP9yX+c38hp6gqQmhvEC13OsHSIifxy/nfNHarD95yuQftwkt4bd9Y9pn6k6s+ToeJcX9Qoec2Cd6MoiTPSChaOhlNlr3i59JSkC63n2bUD8Mnu5Th5ItyujFqJCvGV5C2iSPIfp/DYefdqHf3VQ71WAWlXReocokpND38Sbk6z1hB1ptb97Sxa7g3fFYRoBSpKjy22g9ubEyGG74iYDx3FeffDYEO5/14r2sQRh0c6hQCl2hR7RUMEB5Hmdv0wTt/JsRd0sPySY/hqbMNlMUp0pq8g7g7w45c/plx9ZzJ5FmhzCNW64C7yzmyWTOXVk3JJK86R3hXp0U7JgazzjppmDvvDOj2aUH2//5xsx9HXrMHcX9UP9t6Z/LykzagmHAMru/YTStnDecnn//RzJ+TwGgn4z2hGKx0VqQA60gKqgjGOhJCicxNsKl1iGnYBLdjtGBbsTGbzlLB+xdvg6v8XXjjeYiOLuym2l9r4HrxIjxRHkIyXyaBQrc0yLbs5/M9YVRc8heaB+U5ca0h7cyOQmHrNHjqdIuWJCFkKJZS4Y0t8FzTiHUNz8Ci7938PN8T/O9tZjuBE7z3gR37eI+HC74ZkBSQjBPsVCBL1p1tWtzRymkeT0iWxVyBJeD7dBit1deHOlkJaBk1G6zVHpC4WS3tcLShh8PtyCfElccPa8JRESvowFIhsLrTTAYnM8FsZhtp++5Ax5rlKKV+DR976UGP2x2I8biI59zNoHn1RIiJ8YPTiiNJIuYFlKy/hL3u21Drpifdsh+GS0xn0KIjRjBNQ5x+BJTRX47CU70fYdmhfXj1iyz/0EyBi9Mm8ZeKn3zQbgpYv2yCiLmJEKywCt6X9qHnoybw2LyVXmxeQZ3BL2HJEh+OHOKeDVzDz4G1KD3CgOcuOQbGgpMhdXEqt2TvgjOT92GHxWE2KpSHFQMDNGP0KV42/QonLZ9PW4b6Da5LoMxpapQVW47fdI/xb0sRmHTjO6kpTaNhxmI84vdevv/ZmJJ2R0JEZSSnLZqLui/9UG2sFnRvfwm3zG+hmJAM1xsdhHH306A7NZz9r+3mCa+cOWKbMqzTFoCvzzKxNUUNXBRXYfzOWLrcaAdbE+1YrOwjN4yfDZ6VgZjbYgCb4kqppW0q6omHY0XeJbpGd+morDUn34nikpcNMEajFD0MRsA786/oP3wCWwuIc/eKLSD7oQ6EVyRTcs5H/DNyPFQVZSD1jYFLYSqcOvsmtp0xYPnxerjIx5yXV2ajnsM6FhwQZZnTY6jpkSioDGX3V5LJ3PRrJ2iLKIDtxhg+tmc6Fg0/TUXv7aAw6wnOvDEZNCcsQ7OaGxibkY1wfR0oWpZR6j457NqkgJ3nLdDfpAFWa4hB8JJp3KZ0AB7duw071Ya6+rFbUJ5SAFfybCD8TyE57X/Bi8MIdufvhZHhy6Gmrp6mzyyA+SGtXOxwlV0HFFDGyIYPfm9DuTPC8HVfMzV9+cN66/9A9IA3aDhrUrLPeW6c8o0vZLzgKWnzMTpUH961rcOUnBasPPeLLaeehIUD9rzyWA0YF7wCH41YkHlWBvtyzeBwiRFEPZ2Aj0cF0sUWI3Y0COADPZIo/htYbOZ87Av6AG9Xj4FNWnowrn4ipSwspRUl7dS+dweOyw9mxTYxKDB+zuHOuyj8xnAYmDmeCsuuw5hPb3nl1Wa+GOpHrXdzMGv9axC/eJ4frF6OLqFKMM34PezcrcGhGU/I9D8hetxQz64KB3H97YPQsbIYXXvdIGb5OJAoj4RiB0VSElnIJ21P8PHXw+ilsTyWWVTzmNF7sEVgKtp/lYSlbnNRMr4XbKqeg47ufYzq6YKLVYfIQ+cj57xqYek0wpKy0dCStYTsy7Wg6aYA6gT1cugCK3C6eItsb/RT6qJW9PIypQ8e5tDxWAc61thirocjRA5p+7tyMpc+HwMT378kp8dyuCaphsO/6MOWgRVsUPgSbD6t4WvHzvG9/UM9QuovTK57Dq3NW/jVPyu+8G04THl1EXIFLsDbQ68papMolhoewQYXQC9DFaxd7cMn0kVIc95I+Fn8A8t3+9CMe73YcncUby24Dyc+huAf11ToFtgC3z938MuPorB/8CUtnZNBNzW8aLTBRMje9YZHfo/kq0Lf4KrzVNA9tJcOyilCw4vb+KBBCr+us4UwJ1n2nEYsfOwNXbi4i232nULlaz/ptLU5iC9cROPiJ+B5/QuU1DakH9d0XmYVgldrD2N923qOj91PDkuNoE38G2iV7eVu137OjduP5YH5HHr9EKyufk4rNE9RXvRa+D1ZFv79us9Ri3TBy/kN6AwLY8mL42GflAH8C9fmBNdqehT3imp+yILFaU8IGXiIWcmO9OhCGYnE5rD4ihBsq/JHrYPD6I+kMEfulQCWroclt/bSvYvK1CUihoHjNEGs/QV7jktA2vAPhAUa8bnGaGgrCObubzNwDnVDSkkiq9RkcNCcmXArtQb2zerAmtjjcPCzNjg0HkfNtLOoWSYCg5vsWZcqcNXfbXCiazq/PuOJwadGg9j/cXTe/0C+bxs/h6Qo2bJCRBQyK1mpJEVpkVKUFZFEi9IuRZIiGj5KSZTSskKUVCLJLBGioSUJxdP3+ROu63Wc5/F+3z/c1+SxMDdbiYLzLoOmxUrazYux/FczCH6XwOS4IFo23g2StBVwjaA8aITlU1CoA6wf+45jHraAaiBxzebndGa7Fh0dtxpWeA+gk6o+pAzEQ1VaJb4yY5qyt4jqPqyD4ATmuiejoNrfjqR/JuL+WYowaKnBBcHF6NsjT+5rgCOSDuN/AYfoj/pM9s2w4pSH6/jVq2kw9DYVzEwOUd3SAzRBcRsZrMjH7uxtZPI3lIMzzXnbY3Ua66sKv06F8O1QSUwb2gkbPjbg/pgGTD5SzS76uzDbO4mHxS0i8y4A+03XOKzsDrwZqUe5Mm74y6WYI6KfcYDdKjjDq2hAdgj2jzeAs9+SWPPicyoRXgRLgxHinOex/IN2IsVvFKPdR1rLF+GEbk14s+YaOI+ZSreOu5K8+nTMljpFe14s41sjl8OpdBkWF03llnl6sNY8H8XHT8Q/AifJvzOG70pdYgOT6fxnD9KazlzILXOGjPzxsFXnBC16+gEXnxgGvpONSTPTAlYcyMI5U0JxjkQd5k/5hgrzzGERLqf4rSIY/dQOdretB8tlh+lpfj4EZ4Xi4nODpG1SSFp9aqBXuIH+m7QJ75j/gOEX3HjHinIs9LOHesslcDQhlZ6zPcb5K8NQrhkEB10EgeXjMcyoncJXNPPNY0/w4wNXljf8Qq3XTdkoSxUwcwxoCdrDnkDLf53oyz1D77D5pQWvnefCT24pUO9fP4z/NAMu351HYzu/Ua/0OXp8Kx26vs7AsSqeuPGwHBTkaOKSyJV4YIcQjJv2iw6ZRHHCSFNeOM6VAs4AGV6bTWVvNqKrwEhonaLJz14JwtwSbeq4mYYd10u4+mohXh5hix15EWh3V5GWfnZjvWXX+FyXLph/PoLKdTp080sgNMkUcXW6BLsaNLPrVyF4vmM/TRAJZddyIZBwf0Z3EoPJ6E4wfjlUBY7j/OGV7VWInKxJYvu18bjBC9S2MoHD7ul4fWAynu25wHMc2lD9/mt444E4JiENhY4M8tfuNlJt0Ae/2X2UXH0WKu+34d74JSSnc5PPB7ri5kYbUlj5Fb1PLqbyxdPAWvgplaxRQyfLHHxl60RTH08nkagtKJy9mXau72DRmsNs904AypaJUeOQCFyzPsb8RAkPKV2Eg081uDf4IxWFHefTW/PY5JkZnDFupanve3jZWT+0PumCXSHzwG2LJp4/QyAUbUGjP8jjIiUN6PMQgw9zW8DshyVXjJyPW+YYUoaTIIUnW2GUWAZsje/CJ8nq0P93Hxx6NYkSnllwUXUk7NQvxBVXpWlGmxBV/ZwPy40Xwy1/QRgbK4yCw+OwPXQkjG4IR59T71B6nBTnFkZyx2AFjtNL54YaPXhTtYPHRTnj3vGDeKByN8ZGOnCufjEVfboFD7OnwZhp6/jM+Cmwpn0LLLr3iZJa38Mk5+9wJ/QI/xxWTKMO5UN21HIyfT+fbPX0YMatSfhS7SweuvcaNOWEuWK4Cp0YaQ3hiV/p6sdR/Hz3REo6RtBQOJdkTuXyfd1ObtsjRVnqy+lmwmmKuHmV1uwRw3PpX/i0kQVEek/jiPSD1PBEB3ddqKMSkuemNwUMTV3gZAYw0+AWuuwZA4kT0/mT9RW+AjVQnruIj5mowcaXyrxsmTUY/v6B6V/l8eVwAoWmd7BE8iZkjF7Pi81zYfWufJbV2INPNS/gk3em9PPcHcrUF4WEfl2Y+ewyR488D4G3wijeq5nW3paiGc9aOXLMGVLMrYWVR6dDRmMc5P0pxGY3Y2p36QPztGdkvHUfLNihjFME5mCtsBknvB0GVtk3oVremHP+mlOPQx7tlcgkg9QeNhnvAp2OH8lYdT4pS2uBZ1QySeUt5tDN6+lh1F7es1oWpq2xpOb+27x/0iH6VRBCLzJVoFx+Eo95eZPDigRI038QJlwVo6NWNvDR6jDUvNoHPNeMdrpOhf3TP+Ght0E867MLtR7tZvOz0fRiTh1oVClB4WpnHndGnYYPTgIL0bE87epPaNL4Qp++2nLF6Fd8y+QwTZuvwpy5EjR7r3PYflGYKt9PU/d30heDpRCWmQCj+sJY+9AnWuB5BBO+tIHkzxZqq58IuiIdoPTBBp6kd/G4tsmc8WcedfQM4xX/6WC31SWommHLm+/owlj8QKLVp+mb9khCzbO8vsIQhCTsqcViLKsr56KadyYFL7OA5MoC+iO9GONjLOBXzFV+6BXKdOYjexz8g7Z3BumF5wd8pzwKglyF8MfTN3Dtjzh/do3CoHebOUClHy89EWGXhi2s4lBLChuV4Jp4EY56NYCLvv6mHarhIFE3jNSVX+GP1OXkf8OFRaZ48AIPYdhb6YPmR45QcVAhLz3xH1eRKeesfgWBNc40PjcHPCZPZOHD6jBh4zmMuC/ESveH05GySRgy9Q5p3bnGOzyF8aeqEl412ovt0wQhYrQN8mwLPnVqNhscfQRJi7z4+PRcNPpzAES1MjBH+z251gnCTv9FJKDpBeLh9+jemiC+DAeob5oaR9Qexpz9aWwZco/fnxOC65tuQcPVIrzxpw38XgZylt59sJr5mxy85UlLwx1Ph9Sjer8RZK31hYwbdtDl3Uzr/Ixp8kpDrHmuDSp8BQODvOGMTQplzNIDrZWz8LmNNWaWT+LN5vt5XbswCvis4D2dmqyWfAnFM52pwE0MhmWs4Kwno8jDxZByJk3B3MaDND9OHrfX58DVSevJr82CV0kZg29oPU3ivWj6wYl0NwTA2O1psE/sKH/L8IDVwT8JR6dzyDQBeDLKCRfe/wXPhY9Sfr4rbLO7i5cEzGhZwgR8mqdLZVJxHGYwESQKPHkE1pNxVQaKRT/ielFTrpnbhhQlzOWbu6BK9ji2ntKHkPoUjHDeQRMXZOGC65eo6qoe/wg6wTE+vmBkHAqNWl8p9KEmJD29wHKXhoPWLKQdgw9ItucIWNW9ZEF5Dzr4qIj2tNfC7L1joV43kXUC6nH+zjA6+uIE7et3YXCZxlbnvKlg63BScu+BwcumkNw7i/aWrkIb30CcYHcf5bJroeHLTFSvnMW5R8TA+r0DfzEUBq9rB+hb0hDZf9mB/SrS/MJPhjJe17KtmAtWlXSApIwPzDszES5HNHFX3xnyOCrGn18dZOeqdpIdLEffhffhZcYwVP1PBXeHKoCHoiCYtYrTWbMalB7pgwfmh8ERSVHIDfKkdpMc+LzQEz3CROD6Qx/0/juVlwm1Q2PTFlAUfk/hTemobdwA0cKx8FbmOn2VFQefnnqQbQxHvTVbwelLHpiOMcZ4lQQYXr0eesuysF74NB7T0gMDjZv82fs9ezZN4XfH7HjhBiH68MCPuwL6+HsFw+vVpnRrtyLMWHyDh4ISuS76Ajyr7YOzheWc8DEMf006Qe07ykg8YRnPK1WFnNwe/JxTRKqZBVw3t50//JUlj4OPuWx7Nmd/1aQ1knOIF46Eu18qqWS3GPb//sie223g+ZIe3PHDBjdNysMgW306enAmhn+Y8c8/huGtv2KgM7II+kKfgJjnXBJ1q8OSZEU62f2EWzxkIDdcCsQKdUDh7SveaB3Mn58dRwjbiqVuV2Fx/CEucVbgK6tt4Om54TCzrIx/NuZj4F91zFhVghsDV/OhtXIQLLmOVu3Yy2onAqhoQAwuVzmQ5cNYClk6jEY8HwNlQY5U/SSOTI+KYOzWx7i5T5F+tYqCYdJ62PE9kz0VWmnam04Il9KhxBm5sMJWHTe134Bxe1dzjioC7WHklItQkmXKdMqFlMo1IPLzA9b9Jg6CRshfBWagipYITJ2uhKs+inKlaB40ukRCZstzUv4uj71QyE9b6tjX9ADM3KwL949vw2sTVblovSGdU/Dn+4K7SHH3V/C2/87V8y15fUwgX7LVhtFjj6CeyUzU9k2B1qseKPc8Hpdor4U0vWY8taSB5VRSeLgJgdV7VSxoOIw/H65Ayz5ZCPI4xJKzZnNR/yesbfkF5/eOopVWIqBvNY8PTdfmUvdetFsUibWLQ1FLxBC9xtdT3Sk7tqmYgKKpwiDQqPDPZ2bA6Jsd+KlxPevZeEC4rR+tTaqCi1v96OXpUA4UGw27l1sDSlrx6B124DxDHlPklEg2+wZotslxm186us4eQzcWysDjEcPh/JhiyN+VTM+Ux3BZQDmpLNnELrMO4sFqYZIIc8DaCAt4NlAI9rbFHDojG2/X1dIut6+kb/SAXl6zhpTqxzSjdyUcVzEAe7U3oLk9nBdP/cFGTsn4+a8PGZ9wAHMTC2oVf0uJs4W4PHw0ZJz6gXYPV7O0qyq/KFjP0a93kERjBf3Mmo0Sy7NQc3A33FzKsFT6PN1YeY8UPA1hYrA59wfU4vf2+WQ8/xFO5l2UOEIXPe2NYOF0YbL1fkoGr6VQbt1+pg05vOf9JBQzCsduV0eGWQUc5zMc7v4IhxdOx+mIqClND0uFR7EysOVkJXgYBlGl3b8+PnuHVH4agNYILdgZMg3OZAeDfW0Je16/gqtTi9lh4iNMXR4P5wWM2Pf6GJi4zpiXJO6EefOEcFHULpTr+I3Pb5aCZ9d+3P+PTz/MOsqjf5vAcplsSP8zDTQenIahQ68hLnQfhVa8gt0eGbCtRJaHS48jxxhR8HqEVHPnJ+ChN3A+ZRP/1yyJnvmb4URMN1SGWJFLkATbLzcHyednWV6hFz++VYSxXzvp2JMf7LAhlfsX1IMEy6HG/Jdo06QA8ybvB7CJxWb6Cp6igdDasI1Ojye+ljyXlaefheeOznywezIo9Xqw2zhnVE5RoWPiR9GzWxS+JalD8IR4TpPMoKCsMDTQEYQz6uX8R8QHfe4Mx0Wivrxevg00sk+DmMII0Blq5I95UdQ9UxnOGDizu3kgj9kzFkIUz/LyF4fRps0SdD48hMwfxTjIj/i73kjYGqYBX4yP42dZW3j3/Cp4XpWFTocOPHmih7Zfy8DlM/xwwRlRMJ06lcKL6tjI9gvfHlpPx7X7cYq1H344FQl51Zsp1vAoRMZOB0w5zLm/4zniUyta8CdOnmXFhY+3g/FUPcwtL4Bu8zf0q2oM2Mm8YqffQ3D7rhbvtBtkHcsAfK1dSYopzbzBbzHE1dtgTJMaTBWT5QDfZjKtZX7mcxZUiq9w85YMSn6QBtYmM8gtp4RGzxwDW7q82d/wP3Af/RqdM3w5MG8jSnzSwWqBrXxx3Bh6M7COetqFYL1jPx90ygTzzh98vTMH7lV/4VL921RonYD2V52gtz0LnJQVYXb9IZgh2Im9vvX49pgcGhf58MVPSXR6/UWY8LYYnwQP0NIYc5j+5ShYGm/mLS5d7LmsBqO3DUBNsih9931Cop8e086cPZBeoQnrn4XT05lucKLNGY47p8J5vb0Q/eYHxmTXs9xKfWoeH4yGj6VgdmE3Gm1wgriZYgx5IRSf7w+fu+Zjwr3HvD1CF9SrPem8pg7YPFtDyTkaqFYZy3WC2+HHPsYP7X685mQRfTOawB9m36ftsUrweORqCsktpvMxtUAjL/NNnaVwLvUcTh70ZV3bSnIpCuELJjoQu8wLPW6v4p0+DXzHWJCal/Rzk9x8vh1YyooyORAydA7GpmrD7q+bcUDLEY+fCOTnxl85IvESzModoI22jlBSNBmrq1eAQLEW7Lo5Gz71HKcFdn4U0ttLzeTFhzZVorJgGsXeyQBp2fVw48Y4yNsTjbVmE7nx8QD47zsB7W65JFYgyoWb+/lY2m8sG2ONgoOiED77Ai6sbuRvM4bBzJQR7Ff9krYdk+MR++zQdtQ5GnjXQ2N0lABfjefLrYKoN2MRFyp9Q+ufz1hDtZ19ttVw6CV9Xu6xlapVGdBuOmZ8tSVpk1v4+nA8v1LbirEjltC1I8IgXqFFc3JXsf27iVDidBcPOC7gJNdt/N/bQb70oBIOxzayq3QqOPZWwpQntVB9bAbkyJTyKp6JTQNirJLTxJFHPhGvW8eX3JpQTrwSpg8vI5ucSVD+z2czhZfibrOlOKshjDjNEDYad/Nja1GeqXCUUpquoLilFOxIFMEvpMNyy5bjFLcE6pceoo4PRhy7qpTWL17+v+881DwgC96fRaG9ZyWlvzqEOlezqNBGF4/KtvKPLS/AvWQJ58SaY7LJFBhTd4Oul/9gj3naWF52kURm10NT+AHwqDjFqWMc0HJBBBuESIOwrRmOqjrPpcLp2BYoyoYvvDBgxQRY2rKbj+WsINNbfiR6cwI43UtFmc+JJHdYCVdoDMABo/v8fn4hCexfTaeyz5C92jVaaGoOpbl9+LbvEs7eZPdvN99Ho7ZfNGX6BFRJDcVNGgU09I5QdkgJ2s3EcO/qGPI7lAelQu9w+91IGj0kRlH2NSwzPBVd/xpTZLQRbHv6BTcLFlD3x0D+1VuKmuOFsKNFDcYt/YmbNSIgufocRXzUhapp0vjgVwHMaFPlZ63B2D40hw/MH2BthXXg8KKd34o5M/zjr0xxTQz/LvCP36xZQOw5ZV+w+Gfq9SB92ZzscQH+3T0XN+gIQHbZLvC4U8MLxr6klzY+EOH0FWYFr8SdmwgsnmWxp8kjejxeH37dM6fh0WL06+1lntLvAK64G3btrqaBhankv9yMDfaO4+4Ohm1eIdC4YiM2NPSBxVVh+Pj1NwtK+1BQ5wv+PTiRTITm8/zOKRA16QXNCXfib3JDZDrGBbZJ28H49Y2YdccD133KxcXXxNDBSxqWGY2GcasekGNNIL/PmopFVxZQnFk3hKSUQ87LEDB1GGKvGClIV3TApphXkHapkY69r8AktWJ47ZfK005WserbSNKefZ0aMszB3zsPj6zKoWtqTTRs/Qoe1VwAZ+sDeN7yRtQ8bk4FRcLQ6DkMYpOCofFcPvm8OsAbvS6jrJY9x6bvxWSz2Xj/6ghOfF+MSafHQHPNTvIx3YNfl5bDurlxaNmzHFu2zae0CZ3kMK0Fdux5TQmd48FTdhUnep8C+7RNPDZCHW/5fue8kh847kYkZFQGcsEZFxipIwU97hvggtMI9DI3w8GdN3D5xzH8d4sG3dIbDdtcrOBmjjDoS0mCVUASepM0ii325oQPrjTeJh6UAyNA9Z0q2ZSa8sr0aXB3lBA0ZtiCsEURb31/kf5zfkyarQXoF/iWl74QwWLfDiy//ov6rivAyROFdKJKALbK68C6lRtZ7mgYWX1wwRGPy7EpczE+FU7CYzOmQvvxPDg05RGvtlvAjyAYTZdfw9ioZajx4CS3oD8ePXwbriVLg2FEK11oNkIzZVE6+8EIdgjeZ6X8yyDo6gYXlkvTqIWN6OdqBLJVvei5QJ4fTBDBuEZtfp6XS6tub0bzlDvUN2QFWSMPY9NjfUgua4HIlX95r2UmP8opguBJV7liyl++dVUGWnx24uqpytD12vSfK/3rp8U7qDnoKJySysfSiy/5zfapWPX2PCjseASHl+3HBsERsDx5NPZFfMCH/A3aZi2kmn0neHbVcTp3dDVVy3mg1FAYOriOhKtSZbDvv2Q2Kv4MYoNKvG1mDtoNX0rTfF7g8vVNIDVPm07/77yLndAy/Cg9tDCh2Au5LFF3C7Uf9dJOVWfOyXeAvmABrncdD1fjguBGRxPlH3Qji+Dt9PzbaFro2AFHG5Ng/r1CUFn4ip4IAvwcIQqTfh0BYEP4plXHIfqJEH3WCqukOnFt931+4PoHnF0kIF70EkT8d41u7jbBhpY8EmqvIPWaLbS92AbiYoQQtKPZVU4LfhXsY12/ZigZ6Qs/bi5HQ8GF/ya4Gxz3CFN67xG8GFmGdQUK0GYZSus9Yrnq7Hl+627G78pOgHphC06K6ifn78/wtfozMj5lCFvme9Orwxb8If3fTnRZSzqKY0C8PouvJwWiv6MmPs/aibqhhpAY9Y0bHE1JojeItP7Lo7LrirBiqRYp7u2nloADuM9wiNQdtMHg8SI2UOrja5fUYZ7QPszRrIZ76b9p5MxJbLH+C4QJN9CIzknwzGUFB4aexvyXwTDzjheLV3fhn5X3+NpGZ4q2XwEhOon8UkcLXj3YCPfVAvB4uDEJjrnEkkkLocnTCH2PWpPkmhAq1X+Nu8JF4XdOJu+/Fs6GAk9p3KJLNGVXBb5ddQd2PPjJqRujKW6uPJfnikD2pw7K0DUnQbtcdBd6CC2f0lg6SB6Wpeyh4pfbGSpNOMpNGC7K3kbBjMk8eqIILYvtx7rULMrN2A46R8/yvcgjVO03hjc+0wfhDTthYFsXOyurwe6GDIp91cY7opfBH3dxqs2/CNe3joP4pwKgFJGHdm2ufC1BCOpaY0FsWjvHi/my/oT9/P75MP5qIoGPgmXBvNEILzt/4V+5wvTgjwqeqTMnNakPXBywAMXebeMzd9XgW4M8nEm1JoEjHTjndDN/sjxGz28vBS3TH/R3ThC071oApyTH41NbM3huF8Ytz3w5ZqcHTNB5htMn6OFOxTweey8SZj7cj+WP/FAoZzhMznjCzZ2lPKibA8Nf7IXFy5ayTe5VmuGmjOtJlb0e/sMFLQSuGMD+oVus+P4H/26vo4+BIylw/Rn+e6+Hn7uJkbelGOgoTYDqpRn/fKOfvY/84uCqEuq83k0T01TpgsoqVEtRwCORBpQSy3AyOYovcRRXhjbATiMX1Bz7lgu9XXFK2E00u/gfrf0zn7xuMljZW9IsJ1GQ1emAxwvmgeDDDJp5IopM1qRzxvdg/ispjPbiarBF5QGYlVrSCTNT8o16CzmxT8H4sTD1ernj3h4RCvPrJflZsiCqNBWjq1vpYY0QrHz+k1p8p7IqDcdrix7BrxHtcKjOCV3SpOFHxDl0+J5G62QmoFz5I9bb2EPu/5w0P6ILR4k6Um+HNqvKEjw68x1KWxpw5JKN/DSwgO63rse4yWW84Io/7+kWgvMrArnlDsPiwBN44oQD77oxF165JYKkxHvo9B0i4f0fefP7fpzjK4F6WmIw10eGDyw/wzO+W8NxC0P88W0pXB02m76LboTLPJETZf/Q1qLhUK1WwuPXuOOstgnss/ExheI8mjQjj3sCToL0dDWW9cyAp3snwOVnKRwerUpHHP/SvHwXrmv7CnIJdyF+XTSE6P0h6Zp96D3WDNTdo7H6jDFOWdEPHSM+8CYvD5q18zs61Ydw3oEl8L78LQVWInx74Q9X05NALaaUPzy2BOUQIRK+p42Pt0njmnGrOPagCX9aqgopWdo8Q+QPNSvspDEKnjhrMJsij96gv53bwbHJENd+loRdm7Xh1d9erCoY4N1xDuDZcA03f7jKievd+ci1b3BQxQA/bDjFu0sQaIIPihVc4eG6sXQ46RNOEvPgm0LS7B56CThmM30emEgf7orCW9E+Vsqzpnh1L9avK2SrsuVwzy4OfUeOJPfQZTCtIAsnTp4GnY9HgddoOfK5nc+bORQ/bJTnyRYOOGK+O8htrgSRH5uo8xbD1OrbOL6nnc+ki8OBrD3gOms073gdzAeqJ5BU3XBKztAAF3dxEN0ixREJ++D1UDqOiHTACrPrYJF1DxYqK+MWzx88ua+bypIFYHCxJiS5zaXQsC58NNuTrA8PgOf8MrY5GgtXZm2DOV7vqfKnGBgPtOO9chXIe20N+lcduP5OLOVOVya5e9/R3XEYZx8+SkLu2jDhyixob58MhvvDWK5eBXd4+ePm7f+UKssfJLW8cObXDXRq0AzC3npjl89CTn/pDanZp3CHtCvr2d9kLd8IPBZ8gouyzfB19ySYbl7Fizb3glDcPTYy/gsP+xmaz6+kc6vS6MPuIj7Xp0O9+YJwTSGfEw8Uc+OhJhJInc6KuzNQ/HQw+Q/roK3f5XCTSyd4TteDNakyaFk6GeQlV/PjMB/It4rgpKobUPc6HmyXb4WGrWP5j7A53H34hS7snQ6DIft5hsUCXB1+gw9PdEcfk0yQMHuI61cEorSdIChKB9O9FiOoLupkq6bpNPpeMeT/WgDLNVpJ6nEipZ/ezV9l1UDj4WxKWjmEngqxMP7Wf5AxQYsPZidj4vPfdDH1Kn1esZz31Y2G2mG/wbCulsQdilh2ySAvsNHBmX2tLHY5n82S1tHlpnDe/tgU6h0zYeZ/5+C2QAOmubrSglkWyKSL3bOO0gvVG5xtsYTHC4qCXOIE+nrBin9u7aDjN9fD7BBXWvtWkW6L6LKOtCQqWThQaKoebIy3RUVvU6i5uwYu6J6gPsPJmGgijJN1b8O+G9N4Y5czK2sqwRmZPnbbOZFHvDUjDc89NCvJCiyjA7l4YdU/9v5DfQ1T4YkMQ73dFdZZEo034ifiBalLKJ9ch31rn/Oe3EckkS2KW5uHYHrrdMg/8QKSUyZRgOos8EiXhK/bYmFu0zTYW6lNbukSKLypgpI0RGDTLks4ceUGLEuYhu3vUjB/by8oPgXID7qCtwtssG5FEj5LFgL+dAOmXb+Cr2gEB300wt3LByFuRDw79xeBf7A1rlQ9SEUzjMDYcAlH9U3i+dbnwFb8Derf+EZrDWRx3zEVTPshS3Hz/9CuFwKwsKmZFh3bwdYda2DNvH3ktiESDesKMU6iGYJXqPDjs2vp1UQdWHZDE0QiyulvYzOl8w20DT+CyQqGlJ4bze8mJcJS3z50Godg4t7NkoqtHLWdeb/KY0jKmIkuI+3QRMQPNN/owateb7w8UxReXR/FqXdSWc/sGg/+2UE2s+7SQumXvLNTEUeun0nfm3dAyyMTuGgdhrlK6hz76Rx4L54IaxUiOf5qDemfq2crp2zwjT7Ovi3jYXhgODg8ABg65oP6jYl4eJU+HhayJIV9l5An7uLBSRrwt0kb1G0MsVc3Guu+eWFx+yu8MuE8j+nOo3cS3/C93WrQ63vHg3WyIBxzgkOVH5Os3hKebVfCzcIv0UanGEnhAg+P2UGd2X/JSng67D+hwU8ue4HlhatsvfYA/zXuoKPhX0Cz1QjFW77Cyp/FbLtuGKwNMcdznfZ8TyKHfvZIcujxYdjdkQMzLURphmUBFG97QwFqE+Hlsr/ofHEYjxawJMeESSyfPo7MixZjm8JN6FnyBRcZLf3Xi9qQNGcOrYzfApkbXsPhtBm8KXoVG8+JQL+dw+nMF23q90mhHbWC4LG4h6T9hVH6/kceZnqCug2UcOTzazxCTZH7Xy3juCUXKXmLKHyv1Gah9Vtow4P7UBcuRusytrPAdRVOehgHXSOK+NEfDX4gNQUK4RHZ9O6iB5V+nN2cCm9umuHslh/YtWUeyDVqw5vsdHR5awF5/Vu5tG0EuN/exsNVtpPuy0h2CLlDLcse0MOIb3Tp8SHKvzsK+goDKMEhEUJqivHFJxvePW4eNig9gJbxfrByXhQfW/KG1EJN4b7MYrg8eSELp4nw+X5tSJmVyPonP9MRiwO0WvoPXjdxwE8uBhD6jdigMJ7PqzhyeWgKKjRVsNURpE9Fc3FC1ms482sdpQYwnGY3lPKfS2NcDuCzs7dINtyHvx6YxLNCvdCq4wSNuFKLIt6j4LpHJiU6huHFLlu0/dxPxw7E88KARJztEQFFGa7gamqBlicEQba4nhIEFnGB2mfctqsQwz9/ALcdA4CrXsLPKUX4KuYOjf40Bto3DaNYpVa0838O+7Ykwu3psnC0fIinLK3jS9kV+KJyHPf8m993WRcBKx0x5bwnlWkL4hd/R8gx6ofALT58RDcS1qa8obM7CIY+74Tjbn9J76sL7XMVYO/tV9CzZRcotsZgy7t6zhcfSz/vSMFBBwE+8Gs1mk15ged2XqHZ5lPogxXyOZcwOlwzH95pKGPDylFQ/2+X/X6pilXnhqB09RWwSTyN6SwBncnC8MrDGByk5kBQhxgcajbm2r393JLZAS8n3QeV53pcvncUiKoW4wXP0/SMPMDf0wKKs115lFI/3dYfxjm7T2DoG3UKWikAsdPfg4vWKDC364V3xROh+3sTWVbv4uUhjmCjIENLVy5D08xUjqxfgTWb9TlzxSsI0tGBlBh9XLPpGAR7epKXqxHOu4h46O9EetExHLefMYINP214hIw0JAQEwiP3GD4TYEsVHq38/vw/bjvuSZuvb+bUCkGoUm6Bh1pT4ajuYb59W4U79ymRyBFR1OiWh+8jovDDs36SG7cPk/YtwqgCKfDdOsir/NtYU8OAVdM/Y931EKiV9uCWqaW0puQeyiiZYVy9APwuyKLYn8jNM++B+pFOiAnL4rw5IpiVloC146bBhiUSmNEmB7ouZSBSrMFt68aSZFA2PXYRIDv/LyQfU0F78oO5V7CZzz1SgtdPxtCEU3tJihR51+5CjNTJQWF3O/z9ZQNuuejL6m0R9O7TKFi58AXIdEWyvdc5Gn1BEs8/rcaoQGPomfKQX3qfwPFZPXi7VAm0Mh3gp3I7KTsnYipF83uHTvL5KwS9qj/JQjaRN8t5Y0GJCQR/kCfBl870VH8GbS7JhlfRqWiXuo/36S2C5IIPvC/r307fZgzb3qlR3q10uNB+jAq+B+A5EVV+WGxKo4SdSbK5jB8vV+UQ0oBWWwdeMT4E5zyZSR0v9VDGRpdvF0izzvXrfHC1JhygOygarg0mx/r4xcUH3O30iPvMyiE8tJG/v8zEPcuC8PDvsxBQvAqqa8aC78F63lNzhao2JZOPRiDc171PTs1x9GxoCI0+LwO/sAHKuiYL/x1r4ajlH2G24T9mSj2D3s1beJd2Kd7rMoTu2oswS7YQYqxGg26NJaY7FoHTGim2/V1FPS+KcNvU27Qo3wtCzTvAveogqcwcByrt83iNRTacEPnDpzctRn5nRsP/u4ALzJr5oMc8ql1cgU2WCEVHbuLJu0pspafEA70NfG5PHZ27lg7b/GU4u9iA37cmQIevEYidvM6Decsp/YUXN66Ng+2i1/B71Q6uN46k+T+2k7VBHndPGgWXWoq57V+G7s7ThuqHrTjW6zAYfL6HY4yPwdynMXCrRRkVWgXhWc542rS/lsybm2D3nDAy1/rLAbMWkHb7BF7VcZrLW2zZrXsUnL6TwJaxotD9cQF3XAmDY/cOcdM9Q1qSOQomRAlQc7wD7bCUgvaWpfgtJZDrFMQgYY0wapYtISUzY1R4NB/fqJ8jEcVnfKZBEWpff/mXrcuUvyCBA4RMwO+IGZmobeZrftPgo4g3K8t+p48Bo0Bz2i54tFwPQfsENDtK039pYpDy7B3XPQrnAdsNJCfuwe9s5OC43Xhu/RIJs8yToLlsJmcb17Nz6WtOqL2MnGvGNDgTKxIYLrlVwcN161h8Yg5rWpwnjTVLOe6aOG+dMRvXzk/kmrBFcLlRFtaL38Pa3w/4qfUR8P6X2T7LQGhep4NPW0dh1bokuJL1AOmRBjjqbef5owLxwk43nKOlTiNao2jh9BaaOvU6qnvO4qsm4eCVpgb1VmNY7O5Nfh4bACdrF6NwmAn5D4ih89opPKUokDaeuosBI8fDs19GWLn+AMQlN8PICfvQa149nBp2i6UiF3N29kieeX8IRkpbQPmpOHILX4Kq1tq09psMNo+XIbuhRjj+NYKrTTNhyt55NHqOGFwxdsKZb5x5mlkDZY97iO0mC+CK3XCYdqAZrZe84ADT3WA/TwskZTuou6gLpOwnw/wRfrB92zzao5fGaqm6LCyiQ+eujMZ6RWM4aj2FYpzk0ebPQeofiySp4YEy9mbYpxDFymqb0KLPjMKnW8AvX0mevOcVhSx0pQ0rBLn/mBOVagaxY9R5VC7MgTHeWzhpqSYo3LQHz882OCu8i+a+u0yrDknzyCgjFAyq58sjDuEx572Q4iwBbRsGoMn/I3U9vYSF0+v/OeZBsn76Dpt+i5OOz0cyv5eOPduU4eKmw/w7RQhepB5F7ch7xLvyIeD2Qpz8tpNNd6fy+ideWKijD2K50hxa8RvrvLbQrklTaU7bV7rbVkClc+bSF7/HeN99N1jPlYU39vFg6hnI7/M3g5G6GglI6NDSo++gN2wWcth4bvxbB9GLZOCTigksUQ/FiLifPLf/AQadUkT7+U/40Os9WC64k6vqkilJ1Rg2zHrIdds1eddVYT62OQh2bOlgyzn+HNM+gBHxF/nPSScYlz8FNmgaQdP0PrZZMQJMnK+Akl8j/DI7TfmRRqhisIb1jYFMS1Sh/nQRzBm+h5Z42fMaeWey+XkSbD9pUoi6JXuIr8RTB77ipu1aYBSrT/a2CyhuQhTbThGDEDHE/yznwmuXxTBZy5m01Hvoyg8d8Bztjt1+obRiWC1MLT7KToLb8cLrlXTafxR+GuYAwV1q2O77j9c0R/FZQxda1noZ2u8iP/lrDiOG7abX6S/x9bAlcHbQDyOELAA2vKTNJp9x5tUL8P34Q0hJWgF6cBDLfI1w/AQ7FB5MgdgUQZhh/pQNCuJAdasdThuwIZFYCz7z7jPsvFlGxsOAVgTqsJWcLDTFVNPWdwkwQj+SX3f84YTIz/RNdwGLyl6iYS3reGDMXJzUYwiFWy+gk1wxHM91x+SsiRAXtAvtd3rgsg8dqDlTlSdlr6W5VtJwcoMtrDtQi07QBpqnV6CN92PSkJgFBpse8ISg0XB8IJeCvlrAobxOFi2JwewhPwhfX8BNRVHcfesJug0m8LtfG/C520TKzlGCk9vOcYP8ehap+MfrY15DwsaxXL0rgMqMxrH58Vwmd0+O0teDsakysCTIDuT/ueLS4adBxPM+TQnp4hlHIkh1ywhW7Y5Bnwo9uF6mi81uG0li9wFK3ZsOdR3BMNZxLuRuPoCVfaVo8HsB9DYBXGB5UBKyovgIRyyukwHDEg+Kf2qJgxevQ9emMGg2tePeRTNAdrEyNL6KgMO2Y/lJxVKOnNtDR+fnsu7DGhxxRZJLV53itT7DYPH+QHgem40Dgduwd00cpLkL8szyU2zg8Ryz1iwBN40AmKKgAFJ3JyEIDsCxh6MgwaOdzbsbUFzQiTdhJc6VSIOZpou5erQhTLxegV23PmBhVRsYeTvA3N31ePHIRtgl6gtLXgSBV1gltfxzxpMZjbBAdw9Pa1nPC9sMkMS7efq0GhIPSaNxQk7IVsew4c4MKP+4Bd4uFSDLux3QOHUC30peCZa1D0il7x6F5vuz/XWmkx4K0LmtGNdM8CRRmYf8VcIIFaf/ohDcwCrh+wB8O7ncbD9se64BHcpJOG/cXuC5X8jmjd//v7lY/ewx6x9I4tFrqsg2/j3I3FQBV28RbuAq/jRYR+vaFPjGawU8XrsN57p2of/hs/DpwFZeFSoFP4UPkqfjJniM08FooJIvu6/GHuFweJz+kLBrDKmdseeoNhnYfeMHLBe9hfYf43jLjHjueh0Fsr9qsHZ7KOHPIVggsBe+WY6E0udLKUP4LrvZfKODJyTplkUJib61Ytuqwzz/SCsYfY7nXikJqOl3oEaZNdxb8gGsmv9CkfUt9M0JZ42A/6BQpBj6ZH7gOxMjmClznufFi6Pvu1/gPPsHrrH34zDpU5TZeoLdG5fQ0/f/+PKyNmjLtcPpcZvJf0MY3pTJ4Xfm79BR7hmEnphHH96JQOaLFWC33wheS+yiXSOO0VvOAVuRPCpVi8Qxdutw7MFx9Fn7P1KrnMyP/MTg7/dELEd/uiEoiPWlBWCwSoMiOrNhvsdT7hWajipeDpi42gJa91+m6E0bSPGKNOT376Lqu//8QLKfCn/VsMgSYVQo8KcfutJQtOEWppfqkeWdiTxJdi0cWNrICQaJqFblxRskxNiq4CcP6slBoUo3p63+AT0VAzgyP4ZkNu/DY9mLOE45g57+eAROfct4yw45ONN2AUeqXOJ5BiG4McoVyrPW0cDBXfwuYhHmNB2Ea0kHwPKuKEikDfIGm07cYxhIxQsvoWNIBdfv38PfPK6R6sLhPP6yBsgNDYfRMgvBTVUaf4n+xLWHpCml8QzoK75FoUVvYeykSAoP/YveHpowjhwp+XUl1VsowD1jB0qtLYWui+fQy9OJyxOtWL2mlxJDFCD4bhHl3RiFh+w7KXFKN57u88X9+rnc7EIotnEBV1wOxJ/aupD9wJq3TnBF4VxFaKjTo/bCr3BX0hvmHJhL334tRbJeDI0loyAi6DBdU3tPXzTvg6HMSaguvgz6bXdYgLWhJt4HXe/sogXvJsFOZQF8lKBNKa/86bHYfszWaQV5p1xwkKgGifvLMN/9LAbki4H/zXq6dHwupQ3v5c/f97KTxTVMyZXlmGprEhURhfrMqTTVUQNyd5+GY1N8yLbED/vkBnj+8wFMPWILX01NobRLhZ3dNDF2rgH81frDm0yvgGncbHDaz5zZasbtQfvYa6sHGq2pQN/PQ3j3pRB4a+eBxfkitubblO/+gBdSCI39FotnT73gZV2KcGp7EH7qHw9X9ibwcjczvHPyCn2sOka3T6dw7Plo8LpfizOPT6FVSaEAK5XA/dlVHFEZifHSFSSd9obsOj9x0q5B2Jp0ChSya+CAgj1YFQyHFQZ3eWLxYxzInYltBTXknDsPhR1+05miMdCxU5JTOxbyWxtNCE13psCP/uQm9pv0h5vwS6sy/NzSzsUlljjz0mL4JavB4b4ykDVyP61MqKZOGQ1KTazEUQZqIOuUgG3yV1gwexONvD2Xt9YKgNyuUs55MIP/d+7GMVv/sdRjdshKwY3af9i0kCnd+wJmTSeoPwSk6zSSHm3XwuKz1jx3SxpXH7Dn2MJXMN4xGOaEXoWJbdKwYtll+nZHHx/OFqem/xTZODefn216SF3R+nTjaCaeiZpMs9KHQeLtJn58L548nxzi/dXG+P6JDGt7CqBTTRjtG9EEm2v8YU6ZDvz9FgV3JiqTsMkGUPscxbnPpvGcn8o0tamb3QqUaKbtOVp5QwyiLn1mg5BiPPA+FDVj9EksTBUT3v7k4fEToePVVO68rkyu1gjiuWmgVa2Kd/+agG5MJPb5C8CH+fOpPWA37DZvA8esqSSoLQyrSkR5pGE0zvG9hsOiVoHNlDuUtMYPoi6oo+3+//0j8i9L7BwBBrYzcWrTX5z8cCJa+UnhmGfxUFs4ioRjrHm4qBS2blcn69Em0DHnEcv2WfNO8x9cU3gdfsxtxa6K/zgIdEnyHFLjxtvQ1D4cnilogcCjPJr16gP16yTy89GtGJM1Dsujn7LaK3uyn1SK9TVaYKiZBYtkcqji7k2aP0uHxkmU4IsJufCjcDaojNbgOTqJcLt3BgwtTcaLax+hmLU5LI7Phl//SfDDsXI4tjuQxRf/ZPEZ1uS1XBk2Rg9S3LTzlCl5nitELcn6rDmXh0egJSjgmi+OdHrWYtrfKADpHw3IT+YJbJifxkvfpmCh6FzYt7wPp1vl86BMMx5fn4FNgxPgRVkPBl9x5j0f5kDKj9ts+3Yyqstvxdla3+H2pnyMCFsD8iPEIC9ZHqbtSYFir8lQftcNuq6LY0hlODVtVCG7wP9AvPYYxOwdDSWRd3DCkVEg9PQNDCSbkNilXbjzgyhVjh7E4Ht/0fbxPgqVGgfPywJhyEGfbG5qQnFHNBVHRFJOwyn+3XiLG/4egn1vD5HTRF3onf/vrm4IUkGAGiv9owyVjincHb2dTjac5NdtCpSktx4sNwqCUXobRLxQJRVrHTKOdcI/YaYsuEmShsm9oz7ZLMhjITgqqwYphwtBvf4Fmtp/woZcd1CpS+PDf9WhujUJd7a/hZ5tT3CvkTqkDYtkRckSunxcGQ8V5ZL2ZXn+eGEyHxQ9g2t2HaAjtxxJp8sC5quX8eola2Ge3i9QvfSNYdQvVHs0HEwVx//LkjpOTJoKUaO1oe2PGkQfl4BFavv4/tejtKNHghT6e9BnsSdJvTPHCwErqTNOEtwO7qIT/W/JY+ozFhJYzlVHpSHePowDddpZyNUBik3SIEhqPCQt60SpGR346dYA1SWV0/av+8H223iyF0qGhNpSynwdjL7VonA37C2J16wgt/ylmPFci6plvOFl8S7emp2GYl4/KaciGL5FjINEZRlY7NzCuu97yCl1B+V1xcHuf9l+e2oRBaQdQPuftqg/TwmmPNCmpCXLOMsmgNdr+ILYQAJMrvgJ59IO8a2iZAws/gHTuiUhLGk3bZv7mLIeanACN3P/Z3cYstsO9kvE8WzRKG6RnEMZr4xgfkAUC0dth/eutnjncyhq/LoNPgu3Qt7bQdysdQJK1dpxa+kEiPV5SB6TW3FtpAY2KIbBveWT6MOFJ9BvIkMy/QepzscSzv67Y6pSYFGjTWA9XYfLj5Vz09lyeJP/C8xsPuFBFVM+f9+HCidMghhVJ75nXELP2txg8TN/6Ik+gZKK1+DI94/cU7GKHLe9hObMkXDt+Q/cvmMyX92QBp6m7fh7ZSiaNJeC3jdHLunqxMuVXyi2aBg0jlxKT9quk0JfAEsOb6CrLfmop1mDQp/CcfSpQTjBrvjccwz0eiuT7/RD9F47A8dPbMHS2gDMthiClPpJfKhYniMTn8CPMcNAZcEQxp4rgX0Z8rTx90KMG34Y+lrM4aWHJ/X4fIef46TxQbs+dP/YgQuex4Cx3Tzq/7QBKxPFcOy0bRxv94Il2g/i795jJKLDsDVHk+1+O6DqngbYEbaDRi7cyEccvMm12wTO/7hOCy8YgcpwLXAXus9/kjai9yU31jkYClPzG2ibw378lrGKSnTHU0vTRbzbIQJvtWz5KAwDMakxlFlyDeUWX4fjZmogv9uYy9YY8M6ynaCwfTI4iW2Bs1W6tM72A/3ZvxOm1cZj2+UerLPZC+/fKbLyUmPYdkQYvoxdAJ/ei+JVy7+YlO0M6glPwfqfXxwSfgPuX7M5YrAPVw2OgxP3pUDW5S8pK4+mhYYAQ6+AA7b6wFr7MzD0tZM7zfayebQxBG4LZNNhjRyf0Elua6/xgMgZ1g9bxXabNoDemUegWbaUnetHgWXXQhrzegnV7T+FX04cxJeXQyFFsYdyS9tAp0QCYkRE+YiGKZg/XUdry5bAhG4tbhUtgzoHT86sHIGFhu2o23Cbn59diUEu4uA6SQWaTbZAZfphPGSYAfaiG/nBij2s9GuAQza7on7yGe61UQK8sh5PxjXBjoir3FYdhn9cRP5xdRYnxAWDRK8JPLO9zDKzp4Hr9wp8l1UCZUsmoultCfR0XIubo8/RfxIddMymkmIebeVKT104VbkfpsXrgZy7L98fCxx7Uxa2KZ+kxLYosBNXxwCja+B9cRJUq8jDk2PqMDWaKFBvDY1wOYm1Th2gd7SUWxJ3oZP7aFxfJwKLc6bgragElrlyGn/+3kaTN1RBVbEgVo/6iUNSDzFD8S4ofpeF5r1irGK4hB67fME+t2x0/88PeovXQmLNN4jeexZrVgmQ0ORRMDJEnj6uuc/bNCKo4GkrS5z0hxla72GcxFZuSlfkg6udaNMHMdA56gmXH9zlnaXXqNZiNAe5qMAL8aUwpWI9uN0ZCycOJEN3AMHaTx7cN90BU/+ewuPRk2H412hqr/kOswpCMW9LDhs5OqAhMjRZHqLZkqUU9eYLZQcF05a12qhd8R59fBWpaX8nHSN3XjWoAVYLzoC/mRU+jdzGeZXyGP8kgA4nTcTMG6K0fZgjzcoUxt3EcKTMH3M9p+OOmEqS0TjCYXly5CInAbPWK5NDyS0Q+vEAX1ppwMX/JGlfrQudtpxK169v4R1jS7AzsAD35nlCb1w7G8QY8Nw5wuCceR+yAwxoZYkFtEzShsOxmfipdzmled3jL7MDKF0iCt8YjoZ8CXfa3hdM7k5nscsmk462XGSz4/Hwc7Uibp92nZKOzeXof7O8QGczPnGUo0eZV/FZoxK1FO3D5zvHkvfNazCYMA5GVizmxTeHgWmYCvr/3AVu+6rJTn4yN/QL0Ns5I1hgpgIPyHfRzSpBPFMgB2knvnHsVzMeOS2BpldcpeBicQx4fw6ivx5BqWGPeY6UBM6rnACRwpeZ3FbjFUlPEN9xkCXuWGLXGXdw02d4lpuApeqjyDFrBAgLeVOg72oQnWzH+cuc4PQKccrcKozJ9ytw7pG9JCtwEvstx0He3CksqlqLKx+UgOrvLbipjGmvhh36Gc7ltaNX4g+DJzy/ywhq8Rc7/B9xZ/ZP5ff//fdA5qlCZR6TKGQWKg0kKqGBopGkFCkVKVRSSCiKioYPoVEoDUoaUKFI0UQoKhqQJLfvf3Cf/c72yfVYe6+93q/X8/m4Dpa8Ms53X0SGp/xJUk+erGElSrQs5Uo5AsG/cdDTqQ2yASrgMiWJnb4YcoyeFvuuiIelJZKU/VcYb84xgcrvx7hWfyL4nDLG6vUxNFNmCsm+uj7knqdodZkGWT/QgKm72/mZph+sGdpH3QQ7Kgu6Qnu6HsO1AiEob9UHtSJvlD4SOOSUOfSkOIC09ihCfqsNWL2w4SanRlbVqKTPX2/jCVyMJdMCqF1JjiK/W0LKsYkQHPaSTpSIQtfeqXD8RBAbS9WStqcU1Ww4BHvu56Kj2HkcdUkMpnxfTyue/ACRS5p8NkOUl7ycQn1SofRggg6tSQvlQeUDVPFGBKYVN8Aag3c0OWQ8/+i8T2/bplJl6B/qf3aKKtqDeWqGI9vvHQWq59Shw96BE1ocKP1HOb56+wJKLZTJ3Oo87FZ7hUdiNvBDXx1wLJxLD6ZG0dsWH5o77CLveBSIUYYH6PyzK1RdEI5L1fRoOo+CxYnr8I/70Hd8XU8HF2xhv9M1tPXrIfrTlwBfynxYYHUsLwqVBiFWwdhcU1T+7UgDxd/QR3g/twzqgGjMKtbMXY626Aj/9mtB044eOPJ5PN6vKyJhXUfqWaSM6WnPUPaoJEeL1sOrC2vB65I8BFVeY+FoZ7Dbuo/g2m38/tUXsorH8uiM7WRgeJabxOrJMk0LJhqEDe3JPuwe6rxEwXFwoXoleC4NAkV1aZbt3E4+3TtBTtgGMqfPBHHZAi7f+Q68NilRQm88CsvvgZdlkvBw+ygo9qlhcZSG3TcmkPrmel55oJcMI9vR4bIC3hjci1WvV8OlRYIkzdFcojgSxu5zg+vmtvjmngo5HS3idxdF+f7THRQgM5NyZ2nT1N+ulN2uC8+aHqJQUi9s7L8B04J30bjOo+B0yYe+TvKgxzUSMPnqd4yI1IAJG3/x2dD5pHNUFjPv/QbdHWc59FUN+Vv7YVN1Hpd8c+HT44fB5dJhLOYlScHCpyFU/C8cfqfJ982nw8gt9rw6UAjen6vDe4maMHeCBSyaMQrN77/nQLsitBMPJNUlT3HA4QUJv1s35MuJZOjNMPf2cTh1pQz3lWjwt6goFn6nDsILBLH+uCLNnBWLiTddeLW5BuxZdpNaX+rBq+75dHR7MKf6dbKSbzu7tkpA1kR/mGR4gxrWmUDsyjd0RWUOpsZtw665z/ha7Dj07fqFxr+86cGuMNRvEUR/DSl4VyHLL6emsrDKMbY7tR5V2uxxycSxeKiohnTWfASR0hy6cmM4DJ7vhCO7p/Pgw9u84Ps80FvyBMq3D+L+GyVUYWGHkWl93JiqAhcDnrLnkSB+98GRYyx/csfr3RhZvhlEO5Lp/Olo2Ha0BPaCBbhr34cbkXLoMzuZ6gRk4HISkVvSD+6QbWRPqRB8OHUevS4SgwNzrvNvieM8afh7UC+KAwtvQez3TqTbBvf40LaJtFzjPTmNlIM/T6spd7oZ96o9wcvXZuD9dD+8UdWIL4bbc+zUAkr+HMOaUSPg+bgyks+Lwbac9WCXa8vTrVqh3seFdfgK7R3vicudROhHkjKoFi/iRQGDUBraQjOfOUB6jDIvWcFkrejML16n8+Xp/0h6xWiYtXwMn1klhYZvj5NyrgzsVpeF57liGPkllw/fmc92vlOoukEJpj/QBTlXAXo1+xNkrNnLf3qf8tkHbfSh34Bla9zRX76Hf+QA/HR4xEs3aPDdp0849pYoD8jPZ4+52TRrrjX9jH0Fi3xe4qCALfQbfUYDj1mce24ZT25dCG1210DpURjNdl1D2RL+qPxhIyz9KwVv+npw9TUZcii4hSr/tUGyoDR8bN0G6SdkacKWSJ4t/w8tvupDr8t41hKI5ddL/4M7JypQsOssLZb8xkHXjpLMjUgUeRYEW+o1obahdGjvOkl0zCS+U6xNerMDODfRl06G7eMMu2YsybXA1nwzsJ+eSEffN3D7Z0+qlFLGth9HaVj+PB5x3J2vZKXwcDdl2m8oBy0Pf6BdcgM9bJ0DH3I20VFHQxC/JsXO54qpc8VuUJiqBM5mwpA3sQH0j4uTTfYx9HPu5oDTU3hzexbH3VKn+pvBqHK6GWx+moLxpt1oHLyAG97uxmC5ZRyVIY2x5tagODKGFq38gO3DAFdflYEwfUmYgnswqyge89vUqf/yARivuoIStjdhzbcpGKrpQgrvFIc61oNeGI9mrapIUnUt5jcjN0OYbiUqcBar3l1PquWO1HfaGA5O+II5o4WhxyuMxIetB80bn2mr/BS+u7EeatWk8f4zO1o4QXGIDx7BWEEH+HiujKZkBYFJVTDL1s+iXLNB9LIczW9H6YN5kxBM/NFE1YZvyMTsApVe6KHVtyeR1c418HbCa9ok+5iX7nqOo5uM4OG26ST5bANMKDTh61Nvg/ThEfxZxB08E6/R1cmG/CD8CCwvVQB/9VM0Q1cND6zUQsvaiZyskQKdEcPJUF2Hm7aGsmjj0JkUHgavbH/TU9lFJBD8jBwOtqJd1TV2fvWQXAukWbJfFZuiptKhDilIKB8Aa39ljrYvJYXGLIrot8JzNsaY8lwLVyW1sPy0F+BRKgVteuY011qUdi2zojCnRDq88C51bXoAjbbrWCQii8zXGYBR3WhwPP8GLHdGU7hqHaWblEGEwgYyEzzIer6n6VfUQejbcxIC9omC1J5e+uEQTDelG3D78y5+f+ExfX51kWstArnm+QvyP3cPOsVF4eK4IC5Inwc3nZ6SXqgqhpa2UcHt83yhLgwebv5OBn890CIBQDFkPdrHCdAWu49wdvhW2vfff/hybyWsbjgIYtce4vDTI2G951joWPgNr9gu4eeTZaA/SxfMcvV4Xekx1PwngrmbX1KwWjJfO2EJZ3PewaG30ZhdqUJ3PFbAiON14LUuhHY8eYXH+qXwrW0EVQYJwoRtK+HGEJeuyVbjbXYz6InBbX41RYPfjs+HcgEtOm1QhKr3LGHtHVWcmLgdnp5UAMO2GiiXFceVVk14tUwZBQ4cxst+q6Dljg1EnOhijgiiqkB5SDR/AsI7/VnRKYWr1TbyhDsl/FMylLpypODrvAHIQSeyOlvPjvNncXpgDlZlLMWA5v00XCqB0n3dYY/jOBD3HuDMe5/Aqaedq60j0VTKmpTcq+CV+27e3u/NG386sUiaLbwarUxaG45BkWYNdew6RqWhq8jh0RWu3qZA/sMyefzVB/xYVgICmpwp4pAnB1p6DeXtINyZo0i2eV/wXn8V+wk4w7LHV2DNEOccdP/A8UqmsGHDYyLfCOg3OUcz59riystT+FZRAd8TkKKrdwTg7v04Slc4ToGxY2jihlq+OWU5JA6Px+XBe1mv1hObKmrgiK8e2Kka0d7753jnqGDsMZMG3TNDXLBvAWnoiFPy334QcC6F5906EPWxEGaI/oW2vdnYE9UHaUudOOqlPlSBLZ030uZRMiOhpdMSSmbu5APLlDnItZtj91SxzgYjmHDlBiv9iaXd2+TQIcIYqi3k4cWaQpxgsg4uza6gbNNWUvPuI89iI5D2FOKRdxbguM7JVH1zONiffQnur3/BZ19HmHc+CFY9u0xyUT952YMgPjEshcyKvKgveSQsmCJOr/648y2Lr2h74CQJn+9jWxaE65cbUVcsm/QrXHjyEkUYV3OLr83Yj9s9d9Cmm2WY2P0KD29rh7GvnuEy+0C4kN0EAhcQBLs2o8y1dppzPpI8EzO4/JMn+x8rwqvRwpgnI8MX577AZ9ONwMpqE2rJMjZlH6BhW5eiysKDFCF0lp3nW+CRjzd5s/UnKF+kAwt+jsBT15bxJJ1b2DMpAvYVrePsMWUQmHQT9yzdz18d90Gikgn4WYqT8/XvGF2/DcOvqVCh+jCo/ynCs7XdcesWYZzZOAgNxxBCTNxZu0gbzyWmsxP+QFG9TMhbiuQvdYbiywNQTOIT9osIQXKcGVctKKHaunVkn30Tagsb4NLei7x40gt4d3wD+cu8o/r9EyF/7Du0+SaIUJlDnf0a1Pk1iTXqvMnY6CSw6wzStNyJr78Mh161jyRn8ozc37/BhyckIO9uOc7R0mGLuVfAo0OQcgQWsI2SBczVn0UWQ2vkZw/SKc3fvP3zKJo5xGY3o1/hGfnzYDfDhtTqDYG8EZMSJ1Li2FK4dvQIhM6aSPu6FoC4sxwudjPjIOcRNPOyBMQJbKXnwsWgoHeMVt63wTPO70E4bBhar+4mDasa5oMfcbGDBZRkpVCo7ycYbjgKDruHgniEG/39u38o/7fTj/3bEaMfUfwxBfBuMcY3SYH4ZXQBv/3wF8SWtvCipBI4FSiPB+/n0NwrxnTKZDyQXCyofT8M2Vv1uObZDpoxqQCWBFbS2rhzfM7nB3zW280LpspBwMh6qu+q45VfKikl6CyH77Dn7mkBML2qFZeLFcOe2AvU8GwyNKRn4l9vJxq1+holzbpD2vVXYWWiOdyevYp7nU+Crpkg5lZZgv77pZj9NwIGVu5DgUtvcU7cBRghup3XHJrP69sng0zzCa7ZpgU9Yy7DPiF3NnPPAZuuRFQ5toQkNa5zWfBGupc4xDIrAnHiLBHYf3g6jRf9BuGZkZy6Lp4btQcoKLUc/gzTwylKs2HblhR+p60DJVor8OP0v+jdKAiwXoNrD07Bd0+Rn6YiRgzNvu6gIcUflgG/0+v5csggNjRlUOy9FPTXewCFpqc4ZPw4Cr1mAyovBMi5RBK8q7ei6rZ1WNK1idz2viF5yQAIt71OxfO60V7tOkePTOB7bZNBa18tHbtqR6AYiXnDG/Hw/GN0p62I2+w7IPV9KVnWlFFzkSTMLlqFNZZt4PLVBYUyRfCUgSzobBDmqiFPK/Kvw1ejM2iuMcAJDTW227Ydbc4J0diuXTywPhqMsyZxQ2czFrut4onjfnBPgBRsVeqhTeatBKOd2UYrHgM7NyKPn8itV8VoZqY6qVq3kvsYGVj6LRvT87pxMP0A3dv0Gsa9cMOr9/7yg/lJ+Ez7IAqYPcLoHhMoG56PV/NTuCN3K7+vGYF2zVG8RO87vF3zjP5sjEAX38kgJz4CtqW+oe6aeRhefpFOOQjAhAnfyXT2HniYL0VxeSK0Mv0xfAuyhrK493zOpR5PBLmyUvZKDslpAY1SIy5r02Tr5nAsr1rF6cly4LfvD32Z6MonTV9TyZaT+PC2E4zY+JZ/QQsc1H4A9qaBtMt4FIy2WgxfRv7g7ghEH+shtoMC2JvyCcvTdvJoj194b5ct3t0rCD+f9vOJiiTsHbWQprTcpD9ranhNTSV8eiPLF1M+0AMX4C0PdGBCXx4c7hOD4sM7QO9cLnJcB9WYn+DRAZOpamwKevqfwc+n1UD80jo4t0sH7H0i6at1PA8L6YDWgnTquVsCB3RzyLjuGxtMMoQA62vwKWMaF1X0kWaZJR7dm4R6OJG73j7jnrEZaHOqnmMeI3ilJ6KIcQ5dq1CmTvFNXHhRhJZ4zKLanLO4aeoPXBb0ErV2WsOECAGeqBIHwyfMwIPpO9nF/Aq8XTWIs2k/js2KhKCKUPqZogtfrPTwWXQ4f43NgpQgWXgToM4W6jo4esg9xjtMZjOLbowZLgL68ZEwNXs6/BERweDbe9FtuAo8nGAP15fr0fz94iBmPwa9j1nD1vmu6JFpx4K6ojTr3wKarf2AfXZ7o25UG09TPoEX384k2Uvj/pf5+F3+KoX4ZmN4wSrQfe5OXtmPacIFN6woduQ7jeGcWqkD12at4EadsyyYNpyGB5dghfEi0g1cDxuUbuAxb1uSI1HICFaDX6IfuN/qCQrtL6Zfd2/D5HWMU7Lj4aiZOD7Vy+LKqVJo826oUy4kUsZNIRA4bAhzBB+DxG9vOnhGHGN3l1NSoRj4/ZpAgmAJGzcEwezjLSD7Jgga7n+Bqwt8iXqL+e10H5yyspWqnu/mI1G2cPaKDDa2Z0L+kwV076UIPDs0l+0ihrH26FDYlXuNXt2XIcMkcRj/uIdWTo3Bczlp/GjeX1r95Sj95z4Gi1e60Ktvh+EuBrHHVwuQTCkkJVBhtfS1/PRtFHU13+ZFBUx5h2y4oGs9qbw9jVN8lWBVAlD8o9fwMr8CqkzVoFFgKZYv8cfRa5tgdXMShnYqwJZ18pA/xPvGboewMV5xKKvqIeTMV9rwuhVWJG/BTQuuAh7dx+1HtEAibTjKqR/Ho97X0eq0L1bV2UP6Wgns0B4GmoXJIK58BksaFaF9wyXYl7ac20NEQNj1NUbOnExJM7WBAsuwbQuSm8VMKr5uABldsqTwVpjMTUJAVzkE9/f/w+hWS7LVOYljnjhi8rxdFOciDwOLS2HPJjN0GXuOe8Ne0XrbrySRk09C3/zh7DVfOrrgJCcLqEDrWgeMFXZka6MTVO/US9tbV6Oj+G/8W9fInwqiYYauMyYGjAb7bf/g7+XhbOovRqF6cvCuxRS/za6iAttnHPVZEQ6eiCUBc0XwGrmTpp+PxYQHzZxfXUnVmX8gruI26R+NhsSIL+Ta38LHpkvDzfdReOdENMSIpeMrlbf02PkwLz6nx6cKVpKJaBk/vWaEYnNEgJS+cahtFk1T8sRb+v6oGm4LWisEIOBoADht9oamAFOqFUMwvquEwxRuga9EOBz5eIEOjDakLzGVuGfyGtS5HcZthRV8XtUA9pz4Ce4xV6nIUZ0DvwVTZeNTmvC0FXX+awS9f7Ys/UOemhIU4fWloUyYI4EunRm4lqo4efk4GJHbiDPmLwFXTQkc2RSO957owOUnhlzZP5JU4ubj3bLZZPckGR6HVYGfAkNuVBYn6xpTWQjB9BAliF+Xxt8fqUFocg4W5/VyRa4YLL+iDbVOlrxpfT32iWnCO0cPrnh5HFXtsklC9QiIRV6hd+fvksuVH7TRKg4byzdxda0e5H0f4NQWffhibUHhD3dC13srCpirRZv3P6a22iguvRBPo1MYamPi+JvGIBvvieKPbhew5qol1UQ7otbcZ2g4+y69eVrARuHyUNYhCCstt2LauEoQXqVCYv3dIOp2HE4Ur8NJD/7xtQVCnBshAv7jNVjJei3crnUlpyOlbLHZjna86GbN5emcun0qSK2IJUPLId8arYQnC3fzR1AjF0NX+tiSBduv3+ZZt7Xosv8pOu1VSOa3lSB2xEcQPWjEG38LwIV6W/6RvxFfbGuha+4xKGdVh5KH/amyUAueqM6D1eqTuOZRIGTVpeDDvZ5kIqXNvZfVyKPDGVTTVfFTqQQc1ngKUcm7IDN1CSb0DsBtq6u4TqYOlzzswoQsOfz38zdWzxeGurBUTv5jxT8eeJCPigBoD+wAzXeHedbaqeybeBlWLQwF9SxR+NFXhnM8ZPBwtTLoS1Sx77lNjBl69Kn5KLiMbWex9GXU5qQP/6abcubDQ/DLPYsGl01mGvEdIpb5Q0TaKwg5YIkfXmdzZpkRBLc+pgGPdJ62UQW3Jk2mvSv2wOQMGXb8pYFP/rtO6dJNOP6YDLxRnkFajX6wb5k6/jg+l76qnKcfG63YfL8YfPxlCFMeTeNzOwgufimEkZ+i8ObNcLgusw+8npnDD0cp3Pswh6OK6tFy9//e46tChsU7zv2vDy+VJJG6ZBTK33aAnU5XSSyrgHUSKmhv10YcmGQL9tE38NPXNyh/9jUprnvO/Wu28k1Hf1T8dY/3/WuAN3ckoLhTCML2SsEgf4H1tVdhuFwaeRyZiHVDnTDzdg3vjb4HAXsAwruMoFR9MSr1KOCCoHIWWYtQ/UYSi5raMTdBGNZ86eT/6iU5M2wkXLq+CNb4udKNhS2Uf+4SJS8bR/1PrfnLq0KuXXgRjHwOwdkeFZB8koR1VmuprPsvzfb5SosVLsPBWXlgKjiOdx6dgnWv3+PZKGX4vPoeNsE8aNqeRo3f/1JofjDcsfkNu41V4fLN61x9cyRljRGFX3qVPLLIlmePKKRN6wbo1swIPloeDQmj9/LrtyF0W3QUybXYwulL72He7tMsVPOFNs0aTefX2PPdIWd2lAmhR16vqVPdkUr0bYA7GBseKOG8GhOYdnUGNV+IZvnro9g/oZLSH0lR0INUBgcr2OziywvTR5D8wBo6o5HHL4LuoY1XOmje9KDx8h280DsXIp8YQPycHngj4wPf0j6TY0Yac3EKHTzax31PYuijnw8dXvyGP1eMAAWdInIKr4W5CXow/McHstHdA0tm+JFTTj/kv9gOmm4f2G9gMuhJDfLlqHqQk4zhzH1Z4PI6Hx66OcFjlXj4HLEPUvXPwcP5ehAV7cnjSZvOyBqQWtUYvvpXjD+fFMDPfnm8+9BwtLhuTrLX5UBipSpfnidIyRK6+Myrh4+9aePhIWnUOfCCs9tOwXlne5pSogEjUkTxw5t8MgzvIQ3xegi/KgyB14htltbRfM3t5CE9mUT/M4RDpZNxxbvN6HRoPbxtt0W3d2YsK7Ae31UkcZGxPs20OQ0vA7XghN1IehM81HEZVZz6txNqrsqRo+omemisDC6jNvDT/jwsVlWGL72+FBcgSOExjVx7ZhFtO+NIq3xO8D2hw+AolYjzQj+ytbwhRO8V5Zzm/byrOZn26jmCscMYnHa2H/YqzWOJUjmWvu/KH+4IgZtJCLca+UJ8hQndWvyFDj+/BleH3GF0xjNQiH4FBvLHYVBcHZSTBiB620oMVgzGc1ti4ObuTlp/NBfFUgfx1MsNsGfPYejwkYDgD2K45LQwf591iLNG7sDvepYct/Egucom44uxWhyonohwXBA27pzDDxYLUunuKhCJuYE7Dthhq9ZXlnx5AjQyxsBwc0kM3moMX0Sm0grNATpk5wZTxrzFK+0HUeJoLIU7PgcHn2joe9PAxe+NwWHOCZ4oPZMs9Ew5pG0rFJvVY0nJfvouEM6Fksa0RLeC5zXrg72wIZ37Ohb2LLnMJfuH5t7xFgrtqiad0A0cWY3w/MMfDrCSAHzRDPsMvmJqUjxM212Ga+cXg/TWLZD0xoOm9i9FY+mzOHyLNMhaLmVQUaYx/m2UfWSQpP5K4SnRP7TGIwziJUZRU/5csjCXgKppztwaVoS8MAFmh07CLByPN32XQ76JCzXOc6CfZhp8304Scqbb0amcp/TwqC1n9VfQ+0eOJGRzgUtjJ6L0hTFUFLsAzz7Wht+liAIT1kNnsSFGCu6HvVVf6a2JGfa8luTmUdlYpObAL14OZZKZHs8PXUeq0YO881ssbEyphVt/x+OX3M946sUp3FlrAl/uC4Nj9gNM3XCHveRncEBJKQuIxpCUxGKaeSmdumrGYckyewj9qQLPoh+ykOR9ODHRCdvXecBnP3M6nGuOd8/JgvzncC7dMgOnFMpCecMi/jx7NNzpq4WZ51MoNvkBfNkVT5+NGgBsmmDOwX9sliYMnY4vKdhoC9PgAF5xc8NF/9To439rMUzRk6o7TkKd/Gi6/kkdXg35/51CIzTSX4PzHl6BSP9+/pZym8cGhJE+SGL1/Zv4On00rHoSiJLieTh/3y62t7SDz9FddOxCK+WXxcCMP3M4+asvFTRZgWn6HHCwDWF1eReUdB0FVl2eHPx6JTbHtKC2SAYvWZZOb/KMYFzhZ3jRfwJCdI9hwfY0GLNxDcx4akKPfvlyf/Ak9qh/wj9+mUFdoC+apbuTwuimIedVI+maXJj4SJFctxhD6umZEL4siD7nasAm9Sv08WgS7UiQ4qrRHlS2kXFX5ivqSt4PDbvaaSDmKt+fYQxqFQFUeG44rf42nTW6JehtkQf9a9PB698uU/NVSRod1oChqsZwtcUe3zTcQy3PkyyzMwBMVuXz69jdnJiUTbPDEFPGvgOrKAnwfviXd93JosTy6yigOp1ye25B8z4ZeqT4mvO65tGony54ePe4/7P7f1Pkf1OZ+yk4mRxL5oX+/Pc48d17Gew5bhi5X/5GjX07KTVAGYpeSPM/jV94P3Uqyh5Tx3z5AdCdFsUld+bSlmQZPq29lQokh8P/71XG9y6uZj0ZRKVterTwdT9Hxxdg7ZZ2rrYbhXs37uMsZQFwnKECDRV5PHGxJv3bYwvO/r9h5R07qjGtZ8edA3jrjQbrdTuA+xlZ2JitRgOzPnH0pEjSNZ5BvhP/oGuUMO8OPwlfdTVoltM3WK+kCarL1SHeZDvelojGaLnF/MGshyYLN+P8M3ZYN7+Dr91tZclscXh96BvlXhiL6qvvwry6fxDqYYsL5XL5getfFrlxHhvFLvHfa8NAq9gU3UyaSYzGYe9wJw4X3c8tbeu5bqoTDiopoY28OYapicCwtnPUabQJP/rkwTsHGQ4Jc6RkvVos91hJW7OP8/JcDzzQoQ3Lhpw5XOYcXUn6iBG9s0htRyfkVchw3Yt2jOlkrv42C9/bSIDL1NUUFpOJduVfeSIIsNF0I+zekAubP86HL48rYN3KGvz62ADsWYi0SorYas93sqh8x8cjAmBA4RE/2ZOHF3sn0nv/RnIzUIfQuRVg/HjoV4yywozdO3l9syfsGvWPyrd8orUGs0gvxRSWJAGoCS+FiJAHvDRRCn4vYLC2DeIbqEHfk5y5W1GCUtszOKRSA/zF1aA76jiEi3tjX+NK/lr3gk7Mvwz2JR44qj8HUtbZwOc7NjDaaxabCJzH+qUBYDGphwaKVUFdvBZ2dVtAmdQcxGe/IM1NC6xr77Kv43WsvyCFkxsS0Mg/lf3fPELNtOs08+ZZXl6zjEfkyMJzmxt8cmodbd+4FM+c3wNT9Ruwe/ZO9p5bzCE6unSzKhWNugXhgGsJvfApoObiBTxNWw9lbByoqnk/9Zpb8nf5efB0nDy8UBWD/x69wTvtnmwxVh/+DM3/6iItTHt3mwe2V1HbrYdoN9aHXYR1oO/8UQj9+Jvrg9Owc38YLbUNoLXOE+D12iBM/RSNUR6tGN4jBAJbGR/9YLLdPIyU/VLx5/iLeO9PIBhd+sd9FcG0acQ9CH2uD61VTH8+7KOFy+ezlck57mp7SU9xArcuL8O4jghKPxNH+afEoM+daIpNKp6zVIJTWdso+Jw0rbLTx5sdq3iRzFTeIRlK7ZGScDqsGaSPhoJb6k8uDfgN3zQjKHzHfv7qNZUOh5wj/xuaZJIvD50DXvRroxWlR5ygXZrGoHsiBh1fJNNVmxj49lQRxkhf5yZrMZCI/0UutRdgBUsQa2yH4rQMyrh7hJOKC2hfmie7zK3h7MYRoGZfhKrrq1DTYCeOsQ6Afd2yNP96JEnvfsRjVdK47J48BJwdCQ2r59HJFTd5Xk4sVnb0cJnVOcgPBVqiagdNSofA3u0fvtk4CTa+6Mc/fsJs3RKKj59vxzXpd2DGvx1wi2PQ+8VBFI38CRdmC8CUqWtxxGdnqKMjkBenS79cg+FIaA9o691BL6FZbKz/j8wkx4LwjQlgP9cIjpst4cUuH9lw/TtoLtRCnzmX0d1rBxS/vcWP1kiCXpoPBZ6+T/m6/bggfAy6aKVQ+Ugv/GHpzjUmDhjWpwABT/TA6c58lE5YD00ep7DolgNeCtOi0Emx4NPYyX+cnSA4ZA0e/qsMBgdi8bTbEyxac5ml2obB/cAoDFYew78VPsPzsfV49OFNQHtJcDuoSRuf1OPj85ewxvIg3Rrmhr1vFOFqzX50ChbHWtlILvebCAF3CqHbrJfcm+zQUi+VjK37UfbK0L/zcg4qJ6nCj19X4fi0cfDRO4zHlp/nt25z8cPaVxg+8yuYjvgA1e9XU7afF3SEPmWPSBu4tOkrCiWJ8NmxlyE9IhNFDYLZYqk9O033oKp/3Vj7PA4FP6tCrGMCNnuu4VHR3bzjiCLeuWZN+uUHyKNyGAveC6HV3+PoRIcC3Pv3Ah+d3EFeHWGUu76R/n3fgVPeL4Y803+YI/QB4kdcIitZgr4rBVx62IRjlpSjuP4sPNkrwdedqnDXJDWSnb0Qvs4eQ8HXxEDMUhP1Pr4jsSkqKPnuJFZ3zYDM225gt34V2uZ/4fsaC1HWzgQMO/7BsjVPMKCuHyrvdtGc48O58KwVqD/bSaW3CQ6f9oZ9m5VBafFtSNE7hP8C/uK1UcNATEQHB44Y8aeG2aDaIEp7NmqzeZo25HxwBNtjgeSx6QOo57hDzZ1JZLvpGyywfQ3vdP/QlwoXWLdYBApHiEJvpRvneiyGxQNJ7DFVGCUDTFh4yRgQTX7Oy5KWQ6b1eEhcuYdq223IRl2bR+uVUdypVCrLLOOXHy5Rr807thJ6z8dkjGGgq4YPeN4gY4UESBsvRJ6+PvCu3Au+56uiglsx/UyzBMtaaVi+SoYkVS+xc+d2En+eQ/9EblOylzl/UPwDmzrDwCh7OwwLVACp7kCeX+UJMxW0cUXEQ+h+LQoPVKQ50kAXJswF1p+ti282D4OsLRfpn9wLrLzQS0GVK9Dyz2fe2HiIPKeuoYRdl3Bi3xQMzlWGXnwHN6YdQ5t6AWqoTKWU7Hvs+d4GReUng8igFIquL8BdEuPh49gCHnH3E8Wr1nCaaRSNMsjk4fpL4La3NchubIb5qyahnchw6DhsDpeP+NPxmnooKXmMO5wYrwjtoZrmQOqRec67BkOxKVsUHJed5TQnf9JZ4IH75PfBhqheTFm3GLyyb0PM3A3op/cUOkcqw5gkO2o/0c+RwftpsdwZeKrkAe6FigCGuyE0cjlMWhBKVSMng3LNCjKemQkiPZU4RncKpG1vwy9RkrC1ciz8WNTCZ5Y9A+sKY9hy+i59d53D9yftoPAcCSr1n4JxKwRZCryh908zegv5YFeoKhimfaXCtbGQIORMOiWGeMZnBe14Es4C46tpWvwPNkl9hPkiCjA2+yM9UTPE0jZrKI3aA9PLSznVrBXXxV/lYpOzjNLCfDtCFepEZ+E0sRwsXzEGZw8fgSWbDcj9UiBVT9CAdS0fWFn6EtYbCkBTuQNtPrwC931eiJkBzPWqJzioj/jgi0JuMJCFMQPacHenJqwafp42bZrJ3ceE0XJjBB9XHo2P6pahavImblHvZ42cEahx0gDud0qCZ3gydpVdxIsWS1h+Vw/rvFqLh7+sJumRBTj9bN4Qf6jAssRalJilgS1LZHCz1jo2eD2ff79wJYEWATy0qQTHdk2n6hANOL/sG1QI94HUrBm4TOgXu9Ym8gU5SWo6o8BvC17A3xgjXDVLDWQUz/CNEEl2nmrFK+M2YM/lpSyaawRK0y/h+PR0OPnnAwmmDIPErzNhTlcrVqS9RtMDXiSWf50mSP1HBW27kPaG84yuSIjSkAED6WaQ6lvJFh0CoKn5FPXrE8jfSpgGMuT5dL46PbVezTo6AqC2+C0bZATQzApB3q1lgr/c/fDRvSa2aTvDHbl1EDLWks4MGsCgtBf45GWiq/Z0CjsYx6lPb3Hg2ckUM2kz/Sm9zAaVP1hKXh1W+e3hXQ7lPH93F/+QaYKMnwfx6eT3PMmiHf288sE47wnvCZoIwsMfDnXPVBC/dACc2hx4zaV3nN/cTWEOw2jUxoUcVuBAMMQbCjsOo2ueDV08sAQdDy/l7JiPfMf5HwYELWEppcPMbY+5s3QEFMwZhZ4y6TBX9z9W32pE01Z9At96V86FFhhTVkDKJsP4Z/xk0Nu5FsuOKLHcjuNw3nM+WN/azxYlfaB0cx9cvXgAz8/Qgz0tylD7+hWcMq+GS0tEwfyPKLeN3UO/1U2xsucA/TqTBO+kttP4G7LwIfsWns1bBHr5P8n0czPmRj5Bm4I6TLk+mwJUXBCl3CleRAqKt6mAi9xRnHemC46l3ue7BgL03+5r/MArCtIma1HwrGHcqDYMnqw+QDorXtCImIf8bZwFLM2Kp5f+rnhgbiPKHEjhC4+fkVjkUB4cmo0dp2Zi/vb1rKzqwIG5Izlziisrdyby6g+bsdh/HTk9koG91sPpiHk0rQ5ZTmk+zni14ix8F29lk7BJsERdlQ/6BFLCPgOQivvC4gVytHuwh6Wji/nptuVsETsCPexluM3mK23OnMC7F5jA2pHbeO7XvfjC7x+925qM8UHD4GyGOEw4kAaGnuF8xXg0y8+3AKuStVR76xDnLsjmGS90sFJAkLYPBuLWxi/c+Pgsmb46A6dDrODxEmWKbh4PGwyFQEXoBuv572cRXEu+wmNRdaQ6n/wrgS5JyjA/V4RE30+EVqkWShqaFzO37SC0aRkUNV9lv81+rLxmJdcOmICX8yCPdlyL8sdb+OfgQpxnKkrxQ55y6LAmbpL7CwP7X+NCeVW4c7KeHZxO8T3Zdr49UETjpXLxYqUK7Xu8HB4VhNDijWkg0K0DcXMWgnJ0MvZ41ULrzI0MDdXc/WghZD/ZjmtjDWFlwRM0PisBtl/1eNa7NsrK7MCGkdaYNXAQwned46s7//Gooc+j97fjurWW8PnZdB4/8xIKFauBi74lTXK8Sa3jOuiT224OEd4Mw3X2UUzgcBj58gcn76/FZS9d0CFoDapcvASL8kVh1NZJsD+ecL5fFI75BKDz1R0sYntw38Mht5yYwa0yMjzZuAjzQmXhe3AzVyYmAP6bBJdL73JpbhRkrDqHq2JjeJVeN95q/QyHz2lj7xh33JQxHlN6jSD1hyD9Xp5JRYcCqbzzBO0dV4v2pu30PsSF7nyyxsKC1fxuizi8NXJCP4k1rFQoD3v75tFWhf8wQKqLHEe3c9aWDXB8fjPRCj1IFQWmDBXqWS4ATjEa8LEwjE0er6aI2DXYXF7FxfFJsE3TAIRE8sF88WZUmHGSZ/ZGc9C9QzD10RHaEHEHryiMoS2aIfTfYwbDSRd5nNIKWJhhQveniqFjYDfLF2iz39oS0jEwROm3wdBtpwXbThzktvgE9hz2i4LuZ/CW/XkoMd8Q1X26eMe8/awx+IfnmEuC1VgzfIx5+GRlAL5/W8vNP2Lhk0MTyO58id6DN2CHUC35eArC15cXoKMpHpYHKHLQumf4I04Fv5k8wNma1ay++CCczX9FOGMCpCSLw7P+63T4rAurXqrGKX5NNNc5jS80pKLMmCN4Kt+bK+6rQOhDwMgeeZyqso/LJorRSL8tbDvmFy/RKIbtVSPhy6oOErmqD0f3Z3N9/w7cdyuKi5SO4SZTOYzKNCX9zVWo5eKP0xPa4HWdPEw3+4S3nO7wXTMXTm0x5IvluvhtrBEt6f9Nhk0HacuSX+gOCFpKWeh2tJfHZ63H/7rGc1fud9o7bD2MKqmHj+ObwaXxDdZkToYXIYvxVMN5yOjRohqNJRxutIhmcB6uvNaN90urceGwcNrgrgqiJ+ei+fFq1voXOMSrLvjDNJf+3EVoPjsK3P5MoV9K9WQtoAvVRQ/xd9wiNnjqg+YaFiw2aIUG5i5419IV5529hQ2LJrOzjQxIJ24i7Y5fEHl+EW2JbMRmhYdkm7oB96qE0HVRexRIaoHEPSIwPuskSpbb8ubHIkOemEwp4Ukc+ohI/FY2yV0Kp2nvZ7F8pSLodi/E9A357Pm9jqJ/m0HJxTN4ouUaTf9VykdiE6D5XAH2N+jDxZUqNPEQ86vTi3DqZU9yaoumvwH2UOE9inwd2qljsATPvxUHqw1bINnzHTlWIJXrG/HA+G4UX50CuiNaOXbOCnxXfBRWHRkFJgfGo0PrFn5/vQW3VFnDZ9kL5PzfMJhiGkOlPsWc6veVYs5bgcGP7VzzqQcOSQ+Hx3Ex0OG7iVripeCKQRa7xvljicAyWp06AWa8SaLuu2fIddpCMlObQVGyrpz86SqPUhDi/a5W0DktBuWajWCuTQdqNG+mU0KKWNglTao5hqB76Syq3ZQacgF/jjhRSa9+S8L2wDYWb/IlPZ9P9OSaNwZeF8SbW8phsKIQTqcLQp/5GV4oKw0LqxbAMWkDCruQDP2PiPPqZ4Kv+j2+2BeKlx9Npfdh6dh63Gwou6fwoych1Cc0k0f7fgLHIFtctfkpb3k6jbJtJWnPQ3UaPn84ZGe58NvyBH6mE4IfVqVjfFon/Xf+CCd2WfGS5HRoENhETztF4EifNmQ8b+I4g+90sPolbDcR5t6aaaQ8aEWHJ22Bh85OONWF4HuZM6tbyMCdUTns0loKE2+Xg0jreTh2awQ/iiI+kq8AC/IFQdtEDf5N1UZlm2NQL9vHZQbBOPZ4IY5jZbCM90aZeXe4xm40XG7IxMcJAlic6YepM/QpxNmP7S5kUGbVPNjiN4+a7j/B3DsysO+3Gs2NF+VP7X5wusGez34fS6P1t9Nk65FcumIJ/qeWRH9VrKGz9zQ3j/KmDq0t4BEkRZUlY9BWRAgUZUai7BwPaMvzwl+7hsEytXXwu1cBG7+MIFUtWWw2+8TWCbrQcO8imJ68yNFug9i0eTTof3LFhqQAEppvi1vrZXHk0mI+PEuZCme0QcKSGDZcM8AGMsPAsL2LBzsyOb3+Ini/VmbTtGJQr1NE/7qZ7DJOmzbMes4PLYdD0ObpOH1vEVXrzeS4xEN4fF0fV6zPBnMrX/Sdq8b/5s5k2a26sPTceKr0kgPBv1O4+qYP+fueBtveXHzy9w7+bRPE8Tvd+csCeYi/ugFe2mhT5YJufKqxkNWOLucDxzPY/c9Wcu5yoWbNU7Qt3wYiQgWpLO86xi34h3EzR3OYtgdnPoyhfQcv89WnV/FA4hbUXSwIdTt+kLjAGDAWH0RVQUv8q6JDwT/rcEWPChv1buaZHyLJwt0GTHKOsKB1Kx7+5Im7L/TCzZf15Ku8AFctP0LvZ4XAmD/W7PpdHoQbmBPoJIhG5MCEF9OoOv0npTUVQkjVIB+fFIFrDiygrgO6cCNFCBdoRZMKB+OU2nD+3X4XFNv9aYqnClRvHMB+1xJqWy0H4oNq9MBsDP/YpYnLRijAofR2ShTvIbMjY2inRg2iWB3ulBSC/aNng6blc7QUG8Mr/VQhc18VcHgg5ETVc17TAM34+4hXxBlC2pm3XNM7h0dGdMH7nTkgE7MLp1MqyCnq4+S+OfzFvpuVbwrC/TwfLqttYH1+RKqb26m09i5tTbrDaquv4i5zBZy6rQvUEkQBhezJpmg3+PUPYO8dXXI2/IyDX8S4U/Ei/vrnz7sbL3L1aBtotJ5FBTuKIDd9G70zeIDFpke41nI71Yy6g93r98LfqjLQMJCAkikzMGv9FOjt/U4XLsXh/Ye/+O7FNEpfIsx5X7RgVlI57ZhsBvt8M/HnzfdoqCsDIvNkMUi3aOjZIjit2IJxOzeCaPlIcD2iB4cWI/y8p0jHhj/ClJGx8KpzDJakGYC8yxswzdHn3cdbYGKfGLi5mrOCWSDOUZiHKt1NqCjdQ38a1tB/sc0gFDQa5TqTYMqAJCx7pQz5YfGwZvMfPP9GDb8vfQSKdUd57I6xPCuMQEPAnBJrCeRfD6fs9ePwlowtLb0UDvqKv2DSwaGztEIbP31UhFSpexhwHIEO2FHeNXlYs0sb/Uef4SStHFK/Ngi3eTjcWLEXMtamQcH5SdAV+57sd21hRYX7MOgkxFnmgTygc5mdzpwna82/PPOaC/TmmkDsIYCq3eFsN2c5dZiZ4e60O1i22RQF56bSzyGvvLhIHm5HmUJ8egP4f9fBkWPcIKLUD1/Od4DLhRtY0vsvfdIWQOGMTbxSZRTkv1nC072raN7ABwTh5fBg8yE+56BJVbUrMRh7KDs6AV5FCkHx/RTwOXKRntvYc46RN0VtkAb3bS4UcjMFNse+pXlXXCgvUAkmPzXGitJwdFggRTfktqBX5Upqy1jMBXO3wuz2Vei0NwLTNVXBNrKBkp1GYPXtU/jG5QDO1M2mGd4ItcWf6Lx8E7qP+slyv21h+WAF3QvzhUP/zuBbtTyY+OA5SBxeTJk2jdidc5cya6eS9S4dSMkRZJtPEhjSYYszVmTyfwfvw9yP76Eq8czQOhcwTkaIv4kYQcrpeWxcVgGHXA/Qfs0XtMh/Jo0uqYD/glNIJ0aU8wMr4ZS3Pvgdi0Qpmz1ksCaZw2sFoanclNZdEkOHc4boJeVPgg830rG9amDP6vTqbCh8fegItxd7UOnpGPhz9w30JRXwxC/TKGXvbWrzmwwXiwLp3ZgxdNloOeycpk2Bi+dQ9KtestpsiDnXn8Mc79mY+RUgOTEP3WP06Z1fB/V0/uZWm8/Yte4x1q5AbF+Vz5tFPoLLTlMwOniQ0t8m0LegUnKwVocga23sCv2OwfMDUTNKG1paJCny9igw+vUArasVcOVmQSpcFEGR4Qe519wKxvlO48TotTRDtpp0DXTBSLiQvvqcIb9jq6jHXID53tBzztdRbacqpmr8Y+ETBljdYgb/db/B5bum8JmBX7z6VQ4prfzENRYqEKxxHtcfCOU3tnHgoWgMjWOlOMi7C9cPPwan94yA7RZSXJhQDXrVacz/XGC6G3PhTTFI8+3BD3ERuPTaBIoe40fnhnxwHd/mcpdSUjlnQON6S0l7lgyMrT5BxykFj0WagoD/SVY48oyE3n+GrJKrNL3mCpQ4O2Jepw7oLNyJ+34LQecyIW48+Y8eDbHMUQ83dkir47ths/HVgiAQ0B0O+v3ZHOJngNvDd+LuiSX4/dxmmuNfR/sbT/LquD7e86QdviwwBy+zBlr68josOeXLJ1QiaVfPIMzRrKDnJzvI7tUeXBujyjTdCCIl5sBr03p89OIrPaw5gaIPxOF00Ta+UDad7p+Q4Ys3p/GOywyxc/+B8MEveL95D4gp68Lc2X9BRuMnTDacRY1Tl+I6BSVuT7aBCc5CqLR6IbvtlYdTOXXQlJ/PSr0B3DZnPwje7uZKXQfweywB8uvz8LFpJv+94gvtic4c/ecQrXizlRP8BUBLq51HZlynzC5RaI2qRvMd13Hph2AaMejAm3YdgevTz/I0wRVIo0JB75I3WGhqw5cPd6m64QxNtT/Jn3PV4MS1T3RqkTgv9VpEhxI0aUR3HnxhAAuPSAqQk+HTO3bBigtP4fvH+ey5fj2t8rIC1W1z+U2pHfd0mkKGQApf0dOCgD1n0PnvLygT9qMeVU+MLD3Lb51aIexmKFTaG0D47SnoMk4NNI6sohYbDZj3xAQtdmjBgFsN+Zhrgqf5JKyWswWJnyLUP+02aUr2sGakCerbX4dnMw5wyMaTaK+0EZ7oiEFTnxHkbMniDnsJaJr+iJVCHvAE20RoHOrP+IRAXvIrCRdtLOFxiw3BNqGXL3e8Bel4L/QtKafPhx3RqDsLi3esgaMjd8HUbevhwX4rSK8+Qj889NEo8wqZe9jy3PNOcGNmMO6w0GTnS+qodfEri8iOhbBvtZx0oAK7yo9xv/ll7C2t4dzdG6H1bD97N7+m/14e462yI2Gc0C2WumEJ7uEvWfpEF3RGTcWt8uk0vXE5SZscJQs+xTMuyED7US8YfckD2kfcg7Z9KjB7rQoV6gXAtJMJ6Cy/hhLLLvDASTlIWdlJtmsXsufFRjT1mQCfD00m75lzwa3PksdvvUYnH61F7/RR4M0LMdGzEl7nPOPUSVoYH7qbEkYlw975ptD3cybK33iP+tJKgIeKeHeuK+/OkqENLdPxS2oIrRl2Hvq6r5LnEQuK+v4afVr14e6PAPBddhMTNhTAsnmveKBuHbWN+wE7/p2gQa9PlLj5At3ssoJPMfNxwvtyGrG9D1fbXoQFdZ0YmTV3aE5OskbYRrAudyMhMxvwL3Ajy4ByvhpkRgqRu6huIBeHlUnRrZenaPJZL6g4OY/erFKHC14S+Nqqhv5edMZrvj4wuVAbjkfocFHwctA5NgemPFsKnTKGsHmcHl2W6afZuetB50oqJZRdxpxFT/DgoauQg3ug+mMP3ds2HhR/n8GkTRfofJs8vjf8Ts3/HUSf3660zn0nxEpuIK1xM+mKlggMjvIjVy9BdH07Dre+ziSDcZ9Q+NwfKow6hk5pdSBwa8gxf00EufG7+ChM5otXkb5NdOKGtddIx2oX6Zgfo4UNS3lz+0uoUx4LheP0YIXVMaz36kat4mosn3oL3uWmUt5ZF7p4NxQeyauArqsSnHdzARsZK76Q8g7HKfXjfytFePenFF4dFA0+su2wQMaVupeYAc7YxNq5jaQ/uYf6PxqgdpwQwr85NBi7ki3n5QGbhuL3Y5NBNHMaj1kojOP2PeaizXk88r8sahWI4gsTJdBkURRbzYoCQZH/R8F5xgP1tnH8GspeJZJEFNkrsoq2aJKWFJkNkVBUGippiDRRCOWfohBFJSstCSUZpYyGqIwmeTzvzudz3tznPtf9+32/58UxBU+ZhxS36xE2rR2NDpeKyNtSCYKmDODmY6XY1F0AYQJZLL7EAiIc3XmukwCnPevBsmAV9jU6BZsnraFFeeW07f/f2BwDSXXecIi1lqD+Bffx8m47khn/kKZOSqHdQ8/0+d84VkU9kM8Swy2jAXJFQvCT3gbalfoZsn5sws9Fc+DtFgN+9rkJM0wbQTNtiEElpeFB7RU46plCwXOfg+ktb8iYKEUt0d4kYGkGA1MUoCp0gDfOGg1mokFgm1oGxjMGeaDyP3J9sBlcbSVhbkkiWO29Qs2tf0GpVBo66oDe7IhgysmkbbeDIXOkBVJKFcTv+Aoys2yg7Z4NFI3WAgubddD1xwTd/Sqoak4mPMp3g/2PT6DgDKLzfcdg2Rc/UhCZBk8Gm+CcgR2KrfxKU9zW0qdHCPu8stH4uzA8yynjx1vK0K1UBvbb6+Dcb+PghZgUve7/BBcseunqcxc8mLN7yAnX0J+Pa2Dfai34BhoQmuVLBz494LXXM2BmkAX4rDUl/Ye6IBfnxs+v/0d+vcNBy7YZpy29z/+KJ4FkeRKFmH0B9znT4MHVGho0qkbzke/Q3WcKtPkFwwY9Q846oMuZQp2cImoIaRAPYUu66UV4EnXu9aKAB7JwQ3MGjfJZgR5LnaAnLI/O5Nnh1YQkVLwnxmMfFWLE0zeQb6cEG82kac+RPzQYM4nF7OeQRaozq1yMwLSvg/zhnT8FlQuRsIglTOms4F/q62lndBDqOshD7rZKqlz+Ejcm/uYCiQfwxneQPS1NYP1AE+RZOoD0PzV8U1jNKUOsdMtdkzIOt6PrFE2K/PQSry0f2r8+P+5UfM/D/Y7ysaSvdNX5LFqeFuHGjf0k8HAzObMLRQ2TgIC9rylbcBDmLTmBYyQjqcTXnRft0aZ5BxTxh9c5cDrnCz6zpSHngRT+aWmnCZ/24C7jxZz7PoFfbJ5HX3r8QfCKNn55kU+vkydAsXsECWZ341aTqewv40uGb0twkd9jaJv9AJzjT0OqtBtB0AgY/NLENqbrOPHhbcjbvxhDd46GhUNu+8jtL694WsGJ0elwUHMUdB46wB+n5UGntT2NjFnFF2ptuMg/nHZp23CQ8SMef+sbTG2XgdEz/iPPA6fhe0IGbH77BFz8EtHcfS+Jp06DtKHuCDd8gpe9J8LDT394lt83So8dxbdV/VC6vY8S85fTwfZUrIqZwYc2P0ePi5YwWxlBa0AOdGXPsKnsfbQOK6VMyURUG60HXPgTRL+8wDPxmjB9fT72COwG02grLvcToFNeGZBTvpWlNdfQs76z9N3DCP45GINOdiaPPNiBgpV3oLVDgoKkTWkw+THOkRMgo/UzyDB6iHvtlGGvx0++dbkJT7yX4qdls3D750w877OclRwFuOxJL1RoxWKohyb0vV8POkK/Se1YLWza4UYXZpphxamX+FXPCHzyt4D3nme09juBUEkrTgpdh7oZCNf2XQTtS5IY9WwGeYhkoa28GL0cvR2i8s1A90kPm3VGgoyDNV6rP8yFj+VYO8ecLqyT5bJmXaq3kAfpcml4fqoXor+1k/6qMBTbGcl6d4fcML+N40Z/QcuIxyymMRHmDBsJh+Yv4ZeZEmDcf5cXX0mhlR9XYvzPcTS5fjdVOY3F7v2veO7PobN7vBIDF2eSlck/+tCfAcHrXNFH+i/k7hjEmD5DUBeXBkM9hqUXJ+HKwN2Eil4kE3wOlc/40qvXwyjB5jCe79SjlgoVqPNQh55fbiQnfZ7GSjyBgWXnuK6lkIrXZeDMB/+x3q0CVj/2HCN2jYUy2wq2vexKy1omsucjIdy7diYLKs3n6FeCFNGTQe7S5fh7oxi8j5GGTfKvwKFOkd8tFYDTUXEY+N6Z1sY64r2TVpD825HuXBMA5y8O1HDZm2WXJ/Ljxqcsv3Ela9ZegPzFSVDclc2hL5S4vFYZ9p1VxSOjZGjc4jewb85myBhrCFY+9yi6TRWsQuPp/av9/G+vFlxN3A/SNR2wX8EA6r89gO2DNVQZ8ZlcBrroyHxjkHIKwa4l0nDF/RueGfEbbVMWcfTTP6h18yroXD3BP+8rYceas2BTkklJXaMgOW06XTpmygMcRScDf9PbnNlk+eIBqgaag8ridzjuXA8XGpnC9WZ9Dm72p+C6bLi1+QYPe32Ktq9KgyUJn1FR4wsIn9rLocMF4ObUR9R2Lp4aHM/i4zuifOFNCE3eeYfmwFcejLfkKeqbsD5GFR6lzqSVm/zoYLM6eji+ZIddbVzdL0JRMrr8ruETKp3YzR9nTQa5JZ5gpNVI4x9HkDxtpb6b6rhwpjTPb2nC5e/f8mUTPUi/KQw79b3QsV+SDruuhacrPLiqPQ6G9f7hmhcNUGv8EZ62G2Fv3AQ41NkAAwM2KLFIj8VnLeEvAkvQxT2GjPzPs0VhE3l7DAOpPjm4Cw0w985T2qZfAItsDFB58Dzvk7mLKXs6cbJvKwlaePHWy+Iw/44lLFCVwbUNMTC4uY3v9z3muipf6vhojv5rn2KU9hOOq9CCkFV3sPIZcO3JZ/xffiu2DhPG+iuGsPrIfpzq94t1Dp3E/p+yMGaEPGy/M8RqVfI4Lk6Rlw3bSpXK02jk7X80/Pxy2OmjBuLDCN6P/8wzmjTY74grPeg6glGZGqD13YwzdJxoidVivGF6nIKGerovaQUMd7pIGzetQ1edPXBy40MSn7EVAudG0quH8fhsUTaUz5WD+XIneYaNElnJjIadY5UottaaBMw0mV91UFHwMNoW0w479pjAqjBvWNoyQL5TN2DlnLcYGbkCF5V9R+MltRiwzp5sUxMoqdMYan8XwxQbO2if+xNXL9Lgt1bdpFSiBN29jbB39nNoslgOXcrjQXhWJ+cU/Uflg2rs2rcGa5WKodYuEZVMmnjWnHLUvtjEnk6WcKl4A9xz0yHIs2YZV31u3vwGZcPS6GVyASbNM2PrZUrc1T4C9B5XwdKSJTj4/TfkxIWQp6c6y0xwonslsRAe4Q+vVl3kxVkjYK7HXcp9VYjOVR64Vz0U3du1MeruNry1vpc1bxygvgOp2JQuBgYfX6KLWzi6NATA/Zf/YYHIQ0g6kA17Juvxr2MTwfa+JL88ogrfDmTxBPUk/nDtGwlPDCbpmHfkptBNw1+a0Ji3D8h+rg5dPGQIP8ZkwqyTR6FFJwG/tY/mcw4yvO5FCEbLlfK5uYow7Jg7+LQZwJrODjziEI12dtNg99k+nBzwE1UOf6UltmmsvyMTNF06IKZSFfY4qKLsKEFYtW0GDPTIwQ7ro9A2XgtdQ5Jpwm09fH70F9cUCMOYVSYo2GLFBtJ7aaLoKjwmJQABv8PYyVWFv7p44B+wxZFoBqKjpkPayFU0+/R2XqF9ml5q1HJpaC269wO+aD1B2ZfPsoSrOmwRvUOVpb9hcvdxNi6dhEnCVdygKQ7SC+/g5lJXuNt4ln+OMYBBrWI+dHaIS3VPwPmHH+D6MX3yb5VgMScvvhTpAhe6PCgOpEByehI018rSOVdZCE5r4u1zdLitLJlmjrkOsd+auUyjk7xsTeDTnPuU278EjVWOc9wUWWzULWONK+LwrzsAVLobaIXnJLpWIwM//bNp3rBCav/Pkn8MjEZxxYdkeDKUoq5d5YxcPS5KdsCQlWZwwMaWY+ML6UeyEU3Y3IS9S+LZ0OsW9+7JJWfDdl79KIEEXorCg/QzkCwlx+E+Knz9swydmFtEuOskJ67cBHfHJ8GJHW/A+6MFlASUgYhbCvTp3iK+oMt/hjrBtawFdnSvoZzJt9j0ohNNfKwKp04dg1FpaSCpdYdHFLWjdGMuaCv8JGvb2eCuHEQ2x3r4fbwalNaYkVL3Qzh+bBXvuXQYsnrtQedJKLkEdqFD7i1IHd9LXRn6kKK4CIJPuWOBwScsFt1Jkn157BhVh3fvXSJDh1ZMdzmHu1gdJNX/wJT0Jfx6py82pyaj6FxrfJ1hh+E5ITCsYw+knh1HKGABe+bsQO/88eQRswXX99iR1qIgvDrlF2g/24YXv8yH0T1mtKJoGMg9O0zyKdvoU3c2jR5cgEv0BNlwfxW2SG7FdV99YJykD6+OnQwuAreoLOg1PntTyGf9F6DhxVpurkgEo4l76cENZZ62djtG50+G94K18ON2Dn8/+AZbel/hdKNUUBqjCr88icqDveB3tiLUFo4GleLNbClaz2IHErA06D5HXz9Hj9YW4tZZGvyrwJolvnqg1VwR2LHiCZ5ZpEBPFf7AqF3yFHteERrVtVm92QFmGX9Gt251EjtsAV7Vu6j8wxz2Pr4OIlZdYqdzweRduBMl+tMoafwvMr6zFPC+MGTmbMMLqoReD75w7Jl2UMjt464t9fDJu5ld6hdylZ4fSM0dDkFH99H5J2lg/hQ5e/3eoT2y4q65Evjq23u+PdiDifFlvM7AEjLOP4fzz2LI0tuAclTD0TtvGVVkHYItRy7gj4/P+YldOdk+UgC0+8S+r66Aaawehr0Np/QTygzJ9RizMQJVXE5TcMd1ju9SANc5drTx5FpQunKXRHc20L2Pw9k7qoROWxah/ZRGeriyGcUmSIJh1wI41eAMqxQPcMnJH6xnfZQ+hlzD4cN0sDvTiFRe2OGNeQBLIhL52joVOnr7Gwi8lMKT8oEkUqxOta0aGNHIlPi9i/WkpeGEoxa7CBG9qlVlQ9EXnNj8iur0npP02z/QOWkEZP09y+UHZCGlqgOSVMZDX+MxzgzfSGXVzbD65RZKfTmZdUSEqf3ISPw6RhoEPwVRWPdSErFrQo+BUBbwP0BPc1RprshN+ravApXfu9MbT4DRoh3knVPOjkEacE52MQyrbQfr77Nglg1S76tQDgjp4+sVI+FOYCg+3TkZAxTL6fPZb/hX4yBL7lEn4agOmpRcQN+eb4IWOwHIOauEM4+XsdJ4P3gi2EPd+e/5oespqhsnwyUGR7k1zBivxoyD+vJkvrvOi8ZOiaM5Lx7BF9MQ2njrKpvsbgRbHVsYt7Wf8oa8TDz+B6l9yqSTawPINUiMvRL82OVOJjhJ50NISR+OiG/GV6mGsEb8EJev2QlzcvJYudOPFSvmkqjxIzRJEGNtz2DQ9ekA3zAj+C8rhgYTX/C0mi244MY1bji2kLrjPaneNwgP66ylRXEhQwxiAtZfTuM+g25KlLIhV9lysmjzRTVFUdzwYgMGG3gCiuTBe1AEo3817P1Bibc5plD9wvtw76M66soHccD1BEp4GY3CYlVUK2IB/6VvA4ECDZI13o8bzZS4wgD5VeBJtlH15i6PvRBYupOU003gXfZJ2v/ICt0b5Hhbxh1arm5Og0PumawgDO1ffuJFgVXU9UgfxnhG0xO188jiyN9KTaAxbyWNPOwPm/9mcf6MIhr5PAWu/zaCdhEperNQiXefLOa/Et0Q9UAcXoe6ocu9t7AlX58j3tqRBI+BZQnXYctuVyoXzkDBV3voal0FNF9bAbm/64EeBVKd60/o9FAD/a5UOhluhRn7v8AzzZ+4tbGHDCzd8PjR3zy/vYllBlXpXtg0+PK2hAOS3dn01E56JjsfYNCPX4jEk0S/Je7YfZRfGN2DKUUi8C9YCPUvXuCbe1PZzjEUxlongva9XsicaMiXKzaQ7fb/cJ7uVAj9Fsnen05CWtwc4H8x7JCsyD9GeeKp85a0/2I5zvz5hrSq5MDDLQ2nD7pDxLFtlKmwg2+M8CJvS3toeyWEdPIGvDG9SQmyGlB8aRRmaY8cyo96mm1SCaruuiCe9xXKht7Xt5qXnHbvI3kaisHw/hjUL/AFofn1GFy1A7bP+QmDycJYsf0Qdye74ca0MSzhKQ9Bt/so2vktHZz9hm19NxGrLQfjUbPBuqMIGyJa0Ur/ARs/Gg+F/tvh5L2F4Gy+jBu2v6RvWo7cmvAO664b0hTjN1icVAaHrgnB1ehOWOiwgWQcjsLu//ZCxYIMVJbbx27JkrxGIYECdm6kzBFW0L5YDVXWG/Drab0UWqgNDqYt7JcXjLsyD0NS8WPSPPUJ/t7WAs1JwzlbMo5eSZ6Gbwteo93pLXB43B74ezcDI1Uf4Lv4kTzqqjwkLbHG+nNLcEbjAq7oOIg0xMItsReGMiSW1z+LAO0WfxSxQhCziaeBxmY68lgO1qffgVkOpzkiLA4PXD/ID46kgOPGV6SvZAY6ma6wYVEObLy2En7NlaV3foHoFKOINZ1R5FNXBtXL/6B4lw683JcHinyE2jdbIr/JYf/ZBTD9qxRKpCuQjtEz3h0uzMaS46HouzqNaT/PtcPqKEbxB2i+3M/hD8WwR+Isjv74Ai88nQWOw4TA8OJuvihjBy9qZtPN87foQdhnMJI+geO7fGjNni5aEJFJU0kAfm86CU4SQ3OZtQ9j5vmQ7ocTaFY9F4arzKeTkTNh1LbNOHmRPFzuu8ChodUksvsRGmwjYPk2/vlAlbecnwzPk1tIXqoG7MVVoGBJA5/KnQof24VprY8ECmj08/y1f3h3sguq3l2ItguTIUyVYGeLPm413sI2e//RjeCLtNk5l8YX2YD6qkdQ2fWImqbqYGqwCXRkxfCclW9x21EpPBcvS6YjIvlgyFcaNAiAuLFulPPIH0vfKkGY71iacw/JIuUVXR3fTM8ULdnV24B9XK/xH8tfuKJwLMjOnAQ3lMQpxkiSjCauwyu+hzlJ6A0NPF+BHc//8L/wLKrYqQl/MpSh8s+QExoWU+J1KboUU0yNqz/hf1nFPL3jJWX7yqB220fSNJoIC+3C+fWRJfBhlw99/h1J2283s946ebhia8RpKyeSTeUfdFtNMHD3E68u3gpfBwcgSOcC77l7i97MmQA6puXs+9GPI/NVMS1HD3qixfB8Ugn63XiBGVErWZAdSOCGCcipl/Gq1N+U7JyFsYZ6kHtLnN5GPSTl1Qfg3KFernTeDteFPPn8lMmsVDwCDu/fyd3jCJKiL9DqkP14bbouLTCfihfKnPHhpC9Efs8oInYJP22dD82LJoJOSinNpEn4tD+DxEce4RWGJtjz6CTvb7Hmv48m482nmUCuQ8z/pIluzuwDn2lv8ewmC6qpdIBzPg58RDGGSGADrd4qByq9o0Bg13v0fnEdzR42cPsCR2zscKX17tH859pNEKsVYL33+djrNQlWln+FDquLeLL4G+83f0n1/3yh+ZICfozMhkvlZfDp5wLQTDABza/i+N+YVnRsl8afh9tYrtqQneI/odb5fXDzwilKf76B0kdLw+qYTTTOOQuEL7TQLbtYOiv6nGtGWlHLmfH4ROwE0ysN+jDSGH7URdDniR/wYFs7pRgGY8aDUlhmF4FNJxaRfspPpuMHsOWrIWzreE29ndFseUED8HA+5GWGwP4XaZDpZYaJlr58rTsDNt23guFG1VT2sZlT1kTAAdUAsJ45ERt9inC9nzK9y7VGc8FiDugzgrAwQ/B3bse9X1/wvxfTmRbPwIiValiUupCKq56iz6ZY0PloAquFvuOEidZ8Y3QkNh5dCDGr/blxtSvnBbwgpeo/tOCqHbj6DYd98pZwJeI83PoPeN0Tc5T3HYnRRltxlW4Bq9v406OQIq4z0YN9Is7YdvwX/7sgigXpkTh8cxYfDp9LpxcNcq/bNprR3E1XR6rBAdN0OCvrCaW/z/C7oWz80JBKsyt8Wf27G1UvOwVORVmc2zwWDOTn8K2yZ1w5YyxbHDeDHfFLMT17LPYnnETTYZ9hYfpv/PDXDKTap8JiJyOiM4thcnQBKdiH8f1zeiQbkQIRTyfwWSa4YiwMBt896dTsHWymkkrVD27DjMPhuP2cNu28HMvnvm/F+ppMKNsyEZ4Pq+LFs/N5pGM5Ov4Uo31SeyAvZhRYpV7gimv2sPpNFLR9GQ6nZ5uDYKQSW7+Yx68D+lgurJx1HAqhO1qaMv5ex5j2J7iyWQiKHt1BNS9bPLRnHcbpNJP2Hk12ud0O8XnylB35FXLGJaJDylT4c9gRz+1MxxfvV9Px7xex0UQUL2Ueg6rqZdzP1XhDpwZ+TdeCc31zYWRgCnDRY7px5RRMvXSbSiybyPj8P1gWr0hpJUHoGKQAQSsb6U/6F5pYIoKnfh2C7lf5/D7QgfIWzqPL3ZVoXfMVdtiJQo28HxfcUYEVlQI4kDYDxrTtBtTJwMQvR2iSz3wwTKkCk5X6kCpyD26Pc+H0UXHoP7Sebq+vYOn0HzXGfeCIS4/x8rLFfLB0MohIl/HTJTW06b0mheWuwQeTkiE/RpU8pAxxxKQo8j94hS+p6MEdnQ343fwXfxNexwFXKlH6y1pMeFYJagbraXjxdQzadp4tQ8xgSdhbLs20gj1LMyj+wH22/yKIQ1SI35xmw4Zbx0D9cwD7XBWGFwdmcdNseShVDoMrA95wV245Hgq9yDvD32PzzRXk07KTVMarwYylnuh5bzJcWHyYCqc44qKeS2A4T5GGpzwgWJyL1vZbKWXWJJixcxveaC7H945S+O54BxT/zGfrwBlwRWEth3A8/lG2hlUFavDpkDm41KhhYasHOM5fww9makLf3yFHXHwN/7O+Cor3ViGuFYeq75P4vtYUUrmsjyPPToSScR1YXWBM2u+X0vKDhhg6YQHVfbWCnRVzoSHmCoXKJYB30Ftc4pbBhuuTOcREDrZs7UNf7dmgJqMFAzvyaNe3j/i+ypD+Nenwf+E2NGa9DBXET8ai/a9AO9gURSI04cLnhaC2wpjfGv/m3aSFF7tcYFV6JRWHdGNFvA2hsBFad8vA8ksfKPp6CyVvGM28vARPtl2l0cF7yEG2Fm8niKBQbQw1rlCA5hGHkD9YclLySdK6sQaFvCu5O/oB3aPRvG8nwGeLfwD3xCDitTlNS5oDB2cP46kFF+B1bDg9PyJC5rY76JZxKZp6dkBIhTLEzC6iiIQINPi1AiXyVnJQYiC0b26HdZedqCI3Ej2EbeDpWFMwqT4IezYEk/2VtczRE2B1wxeoLvnLI4cYKkF9FX3uMMSZEuawtDYXgs3Xw53Zl2GEigdfMJ1ISm5GEN2yia7lpIClxgEO1p8CAd9LYKb2MPJyusKHt/3gT2Yn2TnQnmMmScMu/W3QoBhBEnICcFryClJiGI3bvQZOagvSnK0OLNrRz6brTGGLjT98WHwPPt0XhcdPNoCzWBV2THcCeDaOk9ffBq0r63mIAvD5uEO0tssdRJN1oP5ADnKWDJ0WTAL3P/lo+qqHA/E9r93mik6zY9H04U2WvWoEJ7aVwsCuCaT05C02rlhEPzbWc0hOLHt7mIOlTwK9Ks+DBLvJcKN+kIZkGj+nraPLJtV8M0OJMt51g5ygEieOrMaPZZ8J5a1gvXwZHzUQRT8pf3TzK4fGh0zav/bjrtD39MdaAkNt7cnzvDhM3tvOAv+ZUEjHCchNSeWBW/3435NVNKP8Fbj5F6PMyHHYS0Jgc3EGJj0i2tSaS54j60jcdjNbKjyGVN9+OB55lQbztmPIbWWYUjKNs9TGQ02tH982zODmf1XY+LyEkvxV8YzVOtjwbz0UKA6HUdLb+FzYM6ixGstK2a7sULKUU1dHMy2fh46t02mSZjGm/VOFS2+r+b9Fg1SUuYxGVfykx76qbHFSEMRPhMOP2Z1k7TxkjT+GmPFQM3YdTWPxrwtR2vsrHowrw3CZTfjpmyMJrb8JkSP98fwtVSgV3so6U3tIxfkHiEjso36LM3j2bimbf3Rix95PrPtlB/qnK8OH06Hw+KEaZxQ+hoLT2+mIgjrmVyXx/N5jbLH8NYdoNnG3rzb8/exNiQdfglXIIch1mQUBtg743HcYjaibgVY3PlNC1Hb+umciFHzeQ5enXcKNucmwYsoptjaPQ+fW7RjpcwBVzXNwqqshTQB9mHnSEuolXsHAz2TM+y8Kxuq740vZJ7yqyZfjdcpxUOoaXVltCEHKb1jovjtWnusljYuOsPSwOCfI/ePFubl01d6Qg1rdYNSYqaB1KoLVB53o7tjFcLvyBYocDOaN5dr04uEM+qW5kDTTZHnY63FgNqcNFm4KxUmudjT4N4j3zh4P4z/cJx29eyw3TByUxujAwfmqIOkwDfL6HGDPhEa4Wbyeb6opQpyKIGz9GogeT7OgclsPa2VLwPSGR2zkqI3P1zfTlw136IeoJN58mYKvBPx4dtRYGP9ACtYKaIGcYgiJbDoEi9WVKURiELXVPcEtNoTD5zjBlpA8muaXD5HrNeG/a2l0RnA8Ln+fwB5vtmDG/AConveWN9Uq8r4NocxpOfytbiKMuHubbnmLQd15Hfz7pwAELili+nRDfDZnBA4kAV9sk2fzCebw9l4wLX29gDVmL0DTc6+o/1otTOk+AfvWauPtifMg9+FyypitDaeO/EDvJBs4llZHB0eNAqmeevg9rg1lypu5ZP13Ns/7AT8ujYWKuQI0QkqTl7MX7bldwAe2mHLm/MM4C17CW+H1GJqUgPMdx4K342HeuboQi5Z14pV30jC5Qgc8RswE/ap1cKxzOvV86KcKeR2weNdFi8+U8NvvjTz7hCHk6qWgwEZ5zjycDFda0ljK9TZf0VeE9mmJMHvqFTxRao8PPKbQAf0kkOB4wH11sPSkF0upFmJO+Zih66t8RqsDWxteU4OgAl4yH0EuQ/tyIqqHQ5RXgUS/G0km6sHT9uWsE1oGsbPS8JRIBi5fkQRxq/aR0oA2Dxq+xux9xvxzsgq8cbyKb+VG8YOaTSwi1w5+VqoQWqtIXpOOUZTDB6i2NqcFq0xhjcBmipU4hyfvRPBI+9kww/4EVrdXYIWyN33XUOLKlKXQbqsPRU7CMCibQ+sHzsKh2mh4bbsJjO5LQfJ2TTa20iPJznF47dEIGL3Ljqr3BUCb22hSCD/EawXzYGlrLExw+c1pK4iLctvA5qMhuK85jgYWN9nrXhQ9jXCCjIkmcEWrCX08pejMp6GY6ZkL56yE4fkRFbqabQOB2gO4wrGXBV40s+vRdTQehOmO9BjqcftC9Q/0QDJyHaYrF4L4qqXYut0atko+477ZJ/jAEmUKiF/Bj3TuUJPdeGipVcEVs25CiU4niFSHgefyZ7hTJwZjTbbh+LM/aUfwd/6xSgCmHZwFr7fa0cDdlxD7u5PSLv3Ht31MMLt7FkY73mGpJ03gvEUDOmYaofjERpBSL+AHxUJsO7qUH6ttoFnHEqh4ghRusrdGh2miMNg1DFzOvWHFj9P4suArzGsRBt+aXXD9+WTwn1WMUY6ZrNluAZfER5BCRhB0iy6idbY9vGueMTxXdOfoixt5ZHAb2vnHw8WMqTDv0xocJ/+E+0VDYIuCO504tZcUYpIJ3SZi8Z9+2DqU8YevSkL85HAc+Ahss0oCGgJXs1PJJDywMQOH75/Jh8/dws3X3fGy7ARYEW5NZfwPUj8+xn8jjnHgmE10ypVBd1c1yHszmwSIcESAEsjPSEanRfLc9UedZE7t4uDvo8BfeALu1dhPNhdquWv/d1pTrQ6lYe6YVX2LTdo12FZDlycqhbGXmQj56y3B1WeSYU4Zwo8ycZDeUInr/pjQ146ZcGOlJ6sPf0QfTkSyqdVC+JB6Go6nr4eLKRNB7+E+mPKgjXPhKP/5cpP2f3bGFVamdGn+Kwr5FoRr9T/RxRxpeDPeHpKcRrLpD18eN0UVnpdnYqRHHzk97kGN4dIUYbGdpTYPg9eXNrDvbANef+YAzKuNhGXX9kP2y0wUXPEeNXPyadnig1ghbwCStJG+a+ZDWMgYnpWtyPYfNND+oDu8U6qgeZc34rg1DSA2SwOeee2FhW2aaF47kVIuvONZnpboNPk2pzh/xqb4Seib7cEq00eC98Bn+L7Phq4ouXGRcxafl9tNt4dmcaOGLX9rmc4p7ndgo48InA7IwM4/+9EwPZK1lXdSvp4zCIxZycuUO4fO30XQNtaFgRYB6C4yh/uZCqjwq4rSI55yu24sf90cB+stQniVahb1FtTTnG+mcLNagytPOMMOkwZYly3EZwJfY97GPzBieQs03mykTQNW7GRqCv9sK6BS5REnN0xnrYZaUKr+i1XiLznzdTw57izHq1Mn8t5VI6Hr6lze9sYKzT8P4vm8Plhmepmsvv3GJINyPl2zA57/U4Str8xALfct3FF35teT3fjmxjLONkzmxjHvyLe/C44c2Q2ftp/glQnysPWWDwhen05sOItf7Z4FkR/c+YH8RFhZHs7ztOJozpQJcG2ZOtxb/ox26I+F9AbAnrSDQzN0HtesL6C7ncfws7cQP4vbjnM8LWHBQAQ41u1kf3QmyR1ZKJfnySHvsrjKQ4DEjJVZTfs5zhWShMn3gZ7N6kWnKw3gXDka1yQr8sbwIg5MvEZP5U+Q39mrpHdIE5ZpOOIjzZUsvfkYatp6guzRXFToe0TdsXq82+szPZf6DTOuyIBpQyc1diTyfHMxbvIaDqujSmDHa3csCY1n/y571tsQAE83jYMVJAvvdh/F9VMCsQGkeT8MOeCau7D4eA8+jh7kzE/HsaRtMiR+dEfTI3HwtOQO3XvVStufyeDx4VMhIXUsatf0UX2+Ju66KA/TYtVoVvcuENHrg5cuZ/hifCCmpX+m+3Ol2Gl1KJZmBdHuLcPBK7IeB4rz8Nj8IBJ8O44kS93wWUwWHLgoDqk3DtO/R0fJ00QLShynsNjRIQ6Um4Daih1ornQXdwfG4ybf+Xhqiy68zxeEGkMZuN+lgo2uldRz9QqCxUF89kQZXEgUkl7vR4exEmwt1A2fzHTBvbgYrNdp4oHDGnT2dA9sXLSXa8Y0QJ1CDk6pn4Pe4t78LM8Sxhw/xj1338DqiM1seC8RJIx6uHXJV9p8LQrcf27niHpZXDygCoZvrPFPlyY3RcjwpxzZ///PEBxv3IbIrBeY9/QDvIn9iosey4Jh6mZwP5wNie8suKoUQH33EvAzO0GWe1JILvUJKCjG4lI7aWjqe4k3suaxTL8JqSc9pCmCf1GWeuFgljaNk5KjlT53yPmvLMz7nsOFoS50S08NBXLtSVV3iC2j/DnoRSLJh5VwgnkoHzIjOHI0mwK9LsEX70647n8Bk7Pk2eGUJGVqqfDYf47gILKEf1fKwpFh5RBrtAw1RI3oi24/eVb1kGplEu4qrWVzIVNYFFiEeZ2asKb7DfycfgoznzbT6v2tqDruIeSpbaWW+afZK0qJP8wswnobKyjonMpG0Qlo+l6Ot/tkwTv/WBq5+wGKL3Sne7ExoFhQzpJ6U+H90XRoiniOU5d8wKYhj1N47YnJS11B3LML7vnJg99YX7ZrHw8WC73Q5fU8vJQoRPOeHIGKDCmYcmUShE7O5A+/WsnDSR6Dpo2G9WNMWKHwBbpp9lGg6yCIdzdDmPQN3L+9d8izfMhHsYLUHluCoOp73KTux0/6bMEqNpKv/FkJqTu98e2yWFzvK8Jlk4ywdooKVCz7S63JttS8yIZ3xcrwLJNNvPSTK6ksP8kvd3vQlaJOUmwSBAvhp/RxmQO9HudEE8X7OP1MBnt4hsH6uVt4k9FftBh7gqU9JsPUL/9wSeUPmDozi+zri2GpTAEt+rEZXIJ80Xh4N2fI7wG9BbKg6lqHU8NlUWPmYhCe/pDuNXXD6eZC2tURTLGbm2DJE3vSaRkL35oUseLzc1y6Wg6UKqfC5zuKVHXbFqaFRGFizRIo/PyD5n+ZAF7vS8HmcCAZCqxEN7EyfvckiT/mC/Db4/PJMPIrHUjfBVu6h8OcqZfYuSYGrTO2UOu8IBw84YpeY//S1WUL0e7dezRalYz7tynDo0UBYLoxgu+c8qT3wj4UHpzB/Tvj8dytCXxdSQFiJkXwkmRL2DJ+KrdcF8EZGfas6CrKW5MXwVuFR1y4bRzlPPbjphInLr+uAA//q6Mj0YUQOiqExpbX0ZYJZ1nlLvHYzXMh63gv3i7SoM9WYpC79hraF04Eta376KjJMA6eVk3xQorsrFxBb/LysWNlJMltMQb/cZPhnfkbcIgYBn/sY+i4dQXIn42kda099Hu4IgrL7OYYOS2w0LaDxOdTMMfchSMjge8Pz+VNxnZ0WHoT/Fx/i/yfR1OKgjBsK0hGw7rL/KywH5L9lfj7l+OcMTUE/6Vdps3ZKVimYkeyI9WABLog6WQ6vE16zkHRetQ2M4z9lY1BtNGak7f4YLzqfU7/oQwvAnvRZbIwBhuG0Yrf5rBIIhsiXHVJuaeSK0smwkvtbeAymcDM4ShLnkikp8IqfNp7Gms8vcvdxb4sr5oKGeXV1Bc/CDhGBIRCttODwPOw/0kW5qiORzv7w+ScXkzWQ/398NwrTBx7hszGqUCsUBItXbCQVEUdaJ6WIbTYB3P+5SSQK8+G4cUy+LbjHqlHjwbvjebkutkM185/A3tlN3FU/RhUWjgPjkWmYoRBKb8snMjm3hPgUOoIXLbqDutOXMOzf0vB0rJ6vCq3iVY8vAb4rJ0LYv6xeJ8SqFVpoIO+OS2rGoe/N3mwRsBuDknswBmz+yFvhTrVyUSCbJw2aN2NgE26JdRasIMd9zVD9459IDNLnNyW/GLTilYqaJhGXrbjoSvoJivsvI559R/56Ica3L8qiE5v/wjT72rh4L87NKr4Icj6m4LgVgP6ltnOY28codHohYtsy8Fu2Ty0qW8m4aPv+ZT5foqJ1QKz+hHYpKFPfnFLIHT+OrI4nsQjJYXR/nwynDXLxcllAbRoYCT4hh+Gg7SaW7Wn48QZhWh5pQgUH4RwiOUGlPVOorfdG0jHXxP6Dy7FoL4Etpj5l2LuZ9P05CI+3WdGna6pkB0ngpovUujmT33QejOOBuVv8Ye5XvQtTp4MoqpYMNWYJ5RJwdfaesqt00dwZ1ggtgXOVIagps4YelwTC9GnFTikNJrSd82Hk8/Xcq2bMgceGQv9UVbwU307HpIZxbOKQ+HxL1GepODOITI/aUOdLVg6xUJ+vjykTNsDixZfg7nTDTjHYC5aRXRxeqYY/Mq1h24PFfIoFuHs20JwpqkVJ9fU0L7Muajz7xloL3sBsVbXeYehFigLStDer8lQ2mMIF/fU4pnoIhS20eSr2pepbsokAgE7FN+nw+X3tsEs4TWsf8QQ7Gw20p/c96BwxIr/vTgO+jlmGDdvI9TlBIJHyExIOvyXJu8SguuPH8DajXV8rziMBnsfYmlAEDQ9saGRzz7SxLXpLN9mwpN+y8CkFitKtXWGasFo3tzQhF76BbT+3grsGv2Hc5aHo+kWc3IWtQK5uv9YzsAN7hNwXboHPxc3hGBhTWo7uxm3VR3DX9EDaHNQDZadmQQdpR0wEez5mfJ01MrWYpusIjYzHIQXYgtQ9gDx8PCREBB/i4pCBfmcxT3cKXUBEydUglNBEly9shdlBHQo6roNv1075FtPb8OUTik2Ci5Gsd6fmFyRzI/99oCQtin+W5uI6+3l4KGEDsxyScGjOQOwQKWUVWx/cLBcPG17N5/lH8+F6lXX2Pk/JZ50TwKGNYaTV9lrni+5hWZHW9BUi5WsrbaSBZQdcOreSri5QosNlsmA9809MNOxE98m+HBb4ExY/mkEnlwbgNtzIsBXYvHQ2g3prpwB2CuspF/GV8FHfAO0WYznzjRFfJNWjokjfVhc8Tv+fD4KLBZMAJOoJ6hrbIGK3wLg594FaCaUgIkGOly/rhW/B3zEY5uDKUpcFuzb4+iZdhwJWK7DGY5a4HnGhXYe/gUhAzJ8NXwlTEsYC88eCsGAUxYvG1cDu/2W8e3fGzkz/CVY9y3mhWAD7TbPQOhCHd7XF4X//p6Eh9M/0fFgKa6JTSePWBdSMVjMHddmwO11U3C1eiuK5qvBVdEC+DgvgB0/jED+cRkne17jmsY7/HnJNv4lJU7XdbKwvl8HWrpK4cLOh1S06wA4TejFatcK0mvRpdsXNeHdvqmYcWMp/H7EkP6xl8ouV4Cr6G1You4M5XtP0xEtDZQLk+LSrGnQ+Oo62H1RgwVOhTSl3puld7Rx7/pmmKS2AH2D5tIffTXKGXIeT6eReGSMJKS9qKQ9wRdxiuQGEH/6ELNvabK+hSAb5q2iRTJTQVtqI5hLI7SyIpskB8G8dh9Mj06C+f6f0GycD6XLLMNpF4swumgTFjoIQnl1My1cJ4SS30L44Axt2n98FNSJRsOJ5lfoUtSN67ZehB/VOqCU4IGd87t4eL8CNreF8ZbxqmSr/g6a56TjX4kT9G5gPYSlGsD8dbYsbHqO9KutyGHtX+roL6BC2zKSWLaGjarluNF2NfysHA3ND+1QOagP+o6KYf08Jbqg5oKmmf38W0edSoT2A0ZnQEOmMUxYMxGEvj/GDOUqEpA5gG4ji8mxIQGf5fez8cNbLF06GkTWjQR3cU1uXVHCD7wekVDLRtJRmMEBH45SytXlxN/rQO3KAAdZy0HOFh2KXxoGd9f0oOv7QJq34xIaHdAGlcU/UbUqny6RKr5+qAcLJ9zHdQujaP5Gf87anc37c31gRt1n3HdJEfR6nHhl2l5wt5wIi4SHQWZgPvbExuBhrb3wQPQUOi40Y6GhbA27Z8H/Vgx10Lkx8EfqDNoIxLFXzQDMaFLBhVGxLKH7iAUk1Bh4MhrLb6Y76vKw4q0QRDdsgHt7tsCBy1LwRP0qVS8Lp7akQpbymYFi8XuxqkoNwocN3fNrxMHyOXB4/EYMNViDSZ/z8d24E6SWPwt1438gmQ6H3spUEpm4nMbHrqP9202wRFSMnBPdqDaikhuHx2NE9DDu2Tkajgq6wbmbFpBichYO7biO6oKbUHtFN96blECvvo7Gv2umofyHMXBUy4Acbndwiaswu+oKQ9x3XfbTeQ9z4vv5mHo3jvfppi9H5cC58Qhu2TKGYzqaUeaaOOYvvg/5R1rghOlRlp78AJeNEyKFKl34qvsKnFKiuFthNcj8JwV6/w2nu2fCcYF+MCkO+OHYE2pQaKUPGxXecEmjNs86PQ6fhDyBZw1xbLxXHdMNG3HEiAKsiR0Pm8t04XVNEkYtkCWuiuWRI85j45atMPDrOC4WWg6hBSmg/qaRH0dMAA//cjBu/Yjvz5zFDcccee5KC/wi54s/DqnTIYe56HlrAfDAWIAvU1lM/Dx+vXoMf8h14Yicr3Qz6D/yjz9CIyscWUe0FLtJHYRudeOuWW9Avs0aby0RhN3Hb9DK1Lk45u1c3DNuNx4rlUT9amHwjn/Nnye4wSQdXZofEcFRS9/RBUUf7Du+GwMvVeL0GG1MZmEYW76fNeNdqBMSyNpGCOOnmvKUXbXUcPUc1H9qgW2r8/mCsBjIX9sMe6OIm7suMkZ208VhnnjJyxSq5y7jxUIyaLbGhj/sAwj9MuQX0SP4yj0/Fln9jQzObeGZsx04v7+WilR/UWHlBBj/chLsq8nnYVkNdMfzIR0sy4XzK1/SN4uHsFJ4D03utIRxAWLYXiIPZZnBGF+SCFccVGjUriSM9dlBUq0S5JkyH7okb2NZ3DU4nTEZfufr0N0n68DK6SReHxiJv9r04ZRMPG431IMJTs6cH62On2W0QTJxAlXVf4K1Fh/wdPZcXPFnBB+ZLgh7xyyHF3yebM0TIeHiJBjR2EPV+JGDS135nNJdcNWx4uGPvXCvbAQZjiqm2y/n4gtDA/CRNaXc1OswsMaJHyxohpTMV/TzvjLkzimD1sRm3L7DgYcJqUHEbwX61JWFC2Y9xZ2jNtPsKW6UI6hAt54YUtA9HSzYUomGTUYw/9RPeJ3rT0/nfGH7g2OoJW86jh30JE+pGqzPV4Uthuk8PVQRnKfn8zuVZMoKXwCW/X9QUuQTVXX1Mu0/gAEvbkBfaQ4/FRSCozVr0M6lDcZcvoMSYZJolvmerizdSrvLfpCJ6z564dUCu30JfP0Q1j27SyElmXwh7SS/nv0HGmYY0N6l4jT80XOWKL7M5ROHgZvYIlKZaolpHxrpulEYlfS/xMjlQMcCjejgvCts/60VV7jpwpzliqx5Ro07hTaxdos+fIrrhNPr74Hd0WSaOSsCldU/s1CvPkxe2s5+5rp8suMCtB23pd7ipzTVcQfJTphCnltjeZfDLKjNMoBWtf0osmQD7Ui4yVchjsJ3aoOLwydwaPWDPQZhmCr0ju0VVSHSfDWm3bOiEHUBmOFVyHNmFIOrbynMm5mDEdvGg6t+C2SbiUKGqiwPv25Ckt+O8J4F43mrUA47aE6gseJfOOhSAXkkFvDnnzKw6s8gXFZbxNfP3cJjGtEwrW4hffxQhpKuTaRVVc0jPM7wzEVqYF04i+PCu7jB9S3l4lbYq6VJCacD4F54ABnP08JTeTOp7ZY4vI0y4rRvPxHj3SluBFKRaTPE/I4h3a4YXHG+hndq3cdDPVrgZfQb1TsvQ2mbHsRNGI9n9s3BuIdlHLVwIgV72/K68zlwrM8Mpl4UYUFtRWhdVUehAdOHnNuElo7OhX+67dD9OADfVbVhVgbDkZ052NZ4gecKHYNk8TAYkBJCUzlPeGf6D1Yu+sNwQhTmhYnD1rl1UFVVA6grQCJvh2O/QBy52JnByY4f8OhrApbn7OP74VagrLubNrfm8y4xXwrq3gLvQoTI6mU8Btgfge+X8uHxBX/oFBgBd48dBhzuD5KqDvhm+9Ihx3WGv+uVsXdqD2YsdOUGnSXQ66sNO39/4LvDv/OSpYxv2sN4pu01WqV9AvabpPIFvW4Uch3klzWTwPC5PZbddGHhJ9t4ZncsFWjVkuEbTX7mvAEDJ33DnAOmeEJSHx5GXgY7Zw34p2HMuapBdFlgPm2OO4rNu+fgzJtjYV1vCoTdlYQDngtAPPAf6EhU0tkkD1z8Xp+dN/6j6wKyOCcoB61/SEPdTzEYdkKUO2qiePVCYVQ+Ho+X87O5p3k7yz7ZhBsvFmKfxnE69UsDzm/4TfKRaWw6+gjvW6mAnQGNcEZpHpy4JUMmo8TIKKEEBnZLgnegMVP4GqiaUI0ZprcoLNobzK3EUXP5PvA4gtT8IQu/gwrQ70f05OlKjBo+gp7uOUYNYu9odHo3XLl8iAck8iD3vSDdO6IEA/duYGbICVArmUIa/oVsX+vGba6uPGj7BLwnEUbozqNl4eNARfklroIx4Hywm/3XdXNJeAruHB3NstlvKbGC2WTLBy5fPQaavNrQfqwLfQiLYGV+CZ47xuCDrRnctWsfbszzxL2PLtL3j0bwdI0j910Lx5lyCvhuTDXLL3gKcfv66ZFVACt/dOKowU84dokSnE3/B9+bQ+FWyF3ovKXAial52Pp7NggqzsbjYIkPp3SgkbQWCC3sI8PAG2TSn0azRRthjs51WlI2loZHLoQ05Qf4NTAaV58Wh+yog2Q25KZL6n/TF4PzINu9DPflX4FLwg9pfe87+ObYjavcJ8Cfgk6eMuUvFs+uwZBVM+j5K0e+FikPEcr1OHcWs7KmAopFC0HVUyV4qf6bPvRX09jQ1/xbcCTZKWxAodfn+LnVO45crA97uiVhVF0MvS3fyrrx00H41Ufgwy58a6krKQnH0I/PLzip+iDOHy0KIaKxEKPtBK9L5tLGM6Yw/Jg9x99cD95LO7iy7ia55ydS/Gpt2Ox/HJovpiIdKkavjEco2t0L1ww0adPrGfyl4gC+GfYBtd1k4HtmA/lduYKjmlrpVXYefvlegwdmvGGZxffZbHwa5fWspGMto0H7rADn/iaeY2BAJ6cVoorNK/TuWQdX4yxo6ZpSUL6uCgnzRkLNemu8obwCJybup+y0Hthcf5jE12di14TbFCLpTZJFpeDuog/Vxp8pGLvoq84IFppZCPoZBTQ9LAaNLD149w9z5sBRdP2OCJj5tqCX2wUs7DjI2cXLMVNRiCd9/cprN2Zz3YzToLzYgk62Evi1LOBT7cdRcIEHa4xLIwlfUzg4cx72/11Ez4sQD7fHg+M8I1g2UZyrg5fAjc+1cDtwBJqb2PKj9iQuGjjHr0yuctChFTh6rTHkPZ6IWqu/oeVvNwqxNx/quQxaIz2cNI63QgjeZ6UZ+nDnrB7s2NwNYpYWsKrXHNO3akK2aSl7uTUiqcuBZpo8nPC8iWMeiEGt4kGsr/1Mq3pzaXm/PxbO/k4qQ9y9fOn/KDrvhx7Ytw1fI9LU0CTtrSFJoWREKEkoSRoy2hokldH4qAjpoZDdoyUhReiLjFJE6gkpGpRUykj26/0b7vM+zvP46dqDZba7ochuPPiiFtS9V+Azj3fj2pw2PntuE9watMXdTWXwb08RWxlV0PAnX1jgYwRWQ4XwvrWWkvo3Qc2/u0DumgbPk5X8mzNnvDwsxqvuTebsLePBdM8qDNARoisHddhNYRtl5qiC3yZ3niM7yEXJRbhU+jdId6uC7spiOmJohDdPibC1jCNn2RbjJ499kCE6hDkt/iC0PIbrbCaDYUgvSdp8p+N/TkHX1lRqiQVMt29F0dQ6mOAwFzWsfkKLqAE0O8TCnTw/vHZMnYJiVNFCXQLVk8Io0D6blwWnQt7kQxAdOgJ0F2fDJ7FwWlZ0ga1Gt6C1jSEaOrVSgWoBRoxfRPuM83h/MEKT0g8qdxWl7M3utKXlEyc2pVCR0nU6XHGet0lnU1/4atQY1IBWw9P4ShBPOjrWMHdNMuYlObD2flmUimxB/RIVqIj34bO+EvA8+w99+TqdQj2cOCkrDC619NG1lF/cPi6Ng7vOUztLQGgMwaSsuzTRbilaCGuBTkgq/Y76AEdgNnWuUSAnGymSqJLDh+b6cOrRNFh34xaprG5h9dDDUBk1B3Zc/MrT4h+hVuE+sD62loLyAAK690FK73VOGCOKbTcHqUItGnTcO0BbMRqNBUYcMe4qmCtMACn/7yDqMkzh+Awm6ZrDg5AdoNF5GHtnPYbK6X+wSLQe/GP1wMsToDJeFSZdHY+j6u9Ap7ERJy26xYuF40H8ZwRZmXnjkQXCYBXnT5kzDcjymh5LTiomqbdTILDKDx52T8EslViccns8nRgYB3WmaVhubgkF0lJ46GsNqMTFwoZr9ynN7jaVpR2GUTN9MXiOEWSfNoFpxQ/5VaoUyZks5HO7o1H50zrsO74e+nsWoIL4RVg+UwKaEtZyzb4h3l6/jlflmcLc255ovXEpiq52Bo3Ya1T1IwivuirBhSNAim4dWBvHqP95DbpPe4FZQolYWi0Ke6vt0S79Dp97KQofRI9Dw/4EvDveiM+o17DGAmXco23MTv/z4uIEfXpSFEAyNBI0hTVpY/sKvCMuQ1ufGJNmz07a3ruTXIoG8eP4MF4XrgBD7oYw3O0Jey3mcK7UG36ZfRJ6pYzZNNMMrhnaUkZ9ItteSeBgBSuIOTgXPPdKsNvefF5Zg6x8dxz4l/tQbfRq1hhVSSatm9G8RBwsdadx2qt+9A6dip0WiuCgoQbHt3xkHZ1GDu06zUJ98zksVgamKFShQtttVLPSp/8qTuPOGn+6J9xIX1pHot+aZeASeR9Lt0yAQMlZ8EFWi1yfPMLzsQl4YVk31d4oh0RfTzRP/ILDQovgxX59qNyTDXYBinyyZwwa1/vwgZ5TbDfTE0UUSkHo9ULwLdFFk9dicG2pB/lnrOCnyaXY353G51KFSdL7JalUfeLmeum/ribP2sVmUG8mC75hJ3m9zk/ceCgL/UzS0Nklne3Sn0DawXdc7jVMZ0pEoG2aAIKWL8HsbU70KukYqibrYUb/aE6fKsfl1pfw1sTncPOVNWyyT+XZ8b2wQMWNvC0UeUxOKsiNjYLy+TJgGv8OQl4JkdN3SRjfXkHj6kVR6OFBWJY8H7IOy/G6cdswp8oeTK034JCeCM1sHQdL73XTSs/psER4Ckq27aLwoEZY+taKPfdF0hiT3zTpyVK4UD0SpExdoWChH5qsMKDyjRdIru4Q3zVs5A61t5zzshjfR+XTDdsR8GfXeTLRRhTrFafBAxMxq2QpNL5OxR+vnCmpfBUvXjcPfmmaw6Ptz8HReiotfazNVjpbWH6PHw87ZPOUcdmkVKIDrqECiHulDwZ+aagu9Blf/c1NnbAcS4lL8z/+Opwd8g3O7Z/Lf5x/4r0UhjnjLuKbLa2s3PeB3bZ/xzQbEzqmOAkdr4VCQ4Yvq9UI0L1CDCJLxLDX7D7pO0RSt38D62nacpbkALckJLDCHQlYqH2V3D20oeu1P2gaB4Kh6BJadGEz9oREsesjYbifqQaP96hx3/4ivNBnApmvb/Li6VKc4toAefMzcWBdJtdL+UFH1y9cmJ2Ih/EtLAy2BrqciuExtpjpYIujzstCv4cHytt845JoQ/IV+evKTUYodtoQijas5KHqYAqVPIhez0+A9YV5XKMhRrkz7rGahhNOWlILN+8ZgqJ7N4h5JeG1v2ylUUpc3CxFefK51NHjQ0ckb9L+ok6ydhMBu7YGCJpxDPbs20wVA/IkxKLs2mrNsyQDqSNci2NF8lhJSwyu6z3A++6n8Oq0Z9BUqAcj4qPwhNBukq5MpYJfHni2qIHnf1QGs9wZdGqVAly2ceWBupW860YOri9SwGZnQ47ZuoarDm9m4VqE/WFi4Gkn4OPvBkisrAckQ5kUvyH2+eXR9SudWHxwKt3rMwBvGRG8dTMCj3rNZKMxOXAm5TdOCazDO7P7oXXHWPzV549vT8uDxQoBJ7cos7WKBVqYicDYl0LcaNGOUwXzuCsujKp9xtLgI1No+phBYZ5jqfBDHjY49HOi7wOIy38ONVmXYTjvEsV1HADxMHFQVxrmiZcq0eGfH/DOewGOWG6Kn7QNqMZzNNyyN8EIq1IMaDWCV1L+ILreiZUOVOOvA1lsJP8BQ36m4fuMyTBBJp0uoT9YPRaCCj1njHL2pVjFRL41sB/0Jq3AI5kxsKbEjCat3kAT6rNQbLEQhMyahbS3myR7TpFj4Uecpv2NGzbNx5fubiDX5ghj1Z042s4Ucqptca5zMz3r7oT2aW8o8OlZeH8jEuuOZsLMrUPss8QML43Vh+iEc/xpWJTSCpQ4RmUtfnwvDwoli8Fvzyru3aRLBWr6aPtFFfoVmqG7sQKDvEbxjDfvKafCEUH2ML6cOhNEx0Vh2SIxMI8aA4ZOxeT1o4UFU9+gbM4avmf2nY79nkArfXIxeWCQDzTMYCkPcdDPEofH6ftop282q7ccpZGix+hYgC/OCrcAc+9iUOl6A3t9pv7dis446e9fuWwUzBX1a/FtlDG0D6riybE3uDV4kCM+2+OKgwYQ33gFvm7ajW1hjiAbKc11p3xoUnMcVQ4J06Srd2nJtYekvWc0zI98gEaFZdA/Kwh/OPWx2QtzdEk7h4KtFXygawCSpvnyuFpZ8C7VhPQTT3FtTB1NzxQGn9BI9I7uR0WrK3Sg4yVU7BtJOYdEYU3PA44/OJriJUL5aKMXTB4WcOmKMVC2M54PXSbMeNPAzjNUIXj+ZNS0FME/cqa8UD8brJ96kXGHEFu/U6bqi11w374QR34XA7NEZXh8yR1NdqSQ1OdzOOWHErftOYl2NiU05ZQkDxqsgAKPibBIWI+vvPlCx3kea43NwfvBZaR49ij/rrpIIb/O4vAsVz4gMRVSl6fTdAl5DIkvB3cRWV7rYch+c5og1PgoxywT4Ll5CTBOVg5cTkWA5jZXCsx6DuFPS0lUMwDsXgizwjZ7zDOYwWpnPEl9uyl0Xn4IAfbzub1CAje6i2HRUD8//Mte882pfH7Lamhvvw8R0mbwbKUkqRhkYvuGI2zouJCSex/yC/deMunczyGFQzDv83qqfjUR/G8+RBEqpjjV/2jI0Qu+Vgphcv4FsnK9RLCtn0aIh1LKCVlIUP3K050XY5BVPnjHitL19cd4gZYQZoe+hFz/tZi08Bl3SABYBBhDZOIquC4fSWvf5dNmF0MQvG6G7/d+gqS/I6QIyrFUbQw89zBBL2ldDHPYj5OHfFCs+jWsbNyOTjInOFX7Ki5/MxnPe1vCXQkP6p4oBVfFJmDTyD5alCSDb/0eUunjbzi+cCkU5P7Bh23G0G9oxy9W6oJnQip3v/nBdoOdoDiDaYnVASiNvka9O86RU4MojK+LJp3xApIt+UL/3L2CkjL+NOrWV7jjNged7J9Rfsl0Et4zGRSaVtBy/ECNdyfAcKwb1ISo4QMDbT7QcQdMFr1G2fwPrGKrA3u3jKWHgkE0DQwG/0dNPGmnGkw36wVV9Sm89MRMkIuug0gLAktZaWh3+vsOvr4UHBaH8U1LyUp6Mzp/WAhBwxakqJTHNzMUIOP5Mb51PgbjHMVZ8+QCuPVNlHXvnoX2yi78VFZGgRXe0CwmBQ1DCdj4zhj/qzoDulUX4Vh6HSsPLmGbn7/xlLkLqo+s5h4ZS9Csnsw/D9/HVsURSB/qYEmvJqlIttGFY4OwNlsepp1aQ6rTEW7NqmA9r0fYY4L8O+IAOX11BPmUXkqGQc7arg1zDNLRe9JIEHs9laClGQqdVqBicCw3zF9JEHmc7UoL8V+nuagX5Ymq76yh9rMdO1ZqUVOZGupLvwG5lfZ84UUMTtX/RJrNl3BsoBXxXVNofPWNlryYTjYd/VS3UBLu9cSQzgMZXnFGkn2/59DZR+/QBsbAFJta0FtcD6+nXMaTjzupweoE2ji8AUedLh5o8iL9/HmUHz4SElc9g6uzlvCuICsK0bqCrXuTUZnGEB/OQfvZynDGYy5KhunCjK5m+C/EmDK6HuFl7wba+3fzXHzQx5r933iBTCnVbHoMRntNQbsihfd8cQd54eewUdaBf0jMhX8dd5FK/gWsWDME0cEivGhAFVK3r2GPRFXQlvPm5LCZ6C3opdIXD+DCaF+86CRMxmq2VDNxNPxb8QOdTd0wtHsDK0+ei63/3QcdJ2syCL0KXov+o4qIQ1RVoAXmngvod+pftzHJpiKPw/BVJpefGqfgUKUMFeW/p85hMywUHg0PwhrRP7wccwTL4IhqEJd8uso3fvdyq9h8tF9TioGiM1jZ0RieHbnOS84cY6MzWdDwcgx+0VHjEzt+QM/b2XDo2VKYsk+ZyVwEFj21oBv1/mBh/A6VHrfyiCcmoCIbyIKNnZQ/3x3X9r6AqdOnw03tBzCd7fG7+iLesXEOjN+dQobqaaizLQ0udV3mHztegMDSCBRuD0Ln6GjqnaxCe3dXw/O3d9l0bBp2BG5ApZkxNNugBzaXEeS62PHmDS5QUHAeVdpnkrN7At9f85qd8v+DW8ZfcHJYKRooKcPWc6PpjP8Mnm+7jZVjzsLG+jjMDU2Czkh7nKZVjM4ft6GlgTycfCZHT/ObeIdKK520PouNl9/StusXaelBAuerlnD50iGS8dKHarNTLPbRjyxletDf5Cgv3KoCbjMSWfTdMjK+0wmhqrW48TJCwLM1cCNrOrRoyqNM722M6r5ImzQH0CW8gz/8T56eOMeBGcwA9POBc6Oi2bPCFR54I76P3MnbfyVS6RUzMOmL4d4Nbbwr3whCn+0HlYP2dOCKPbktyaPDc8/x/27/Qsl7dvwz2ZeWpZ1E17vikDvBHjL/TOfWBQf4iPUR2JhwHZsu6WH0K0t0M7Dh4aHDqPcOwb9wE5wL2YUDUwR4y1CE9u85C3laEfRV9gXVa55il/AKmms4CgqCLKB1YB1PiB+DIn6nab5xEsYvn00GYp/YXF4EFvyMxOwaefgmU8EB750oI8YFFBQFsKR1A2wL7CbZkQOoONmQRY5/poWF42GHVDfv8nfl3dpufxnlBEqJSjDF6jmFpW+hs2dlwLe7G3eWy8IyA13Oj23G2iABe7vOAoct38j+xmsy6/oBqU90UVC0ixbOGQXfA3ezQKBBJct2Q8vixZC/VY4T1+yDs2V5WPveDlpqT/IVaUNYlNlPVRerccLOFt6S8YcdH4RjwOb35Ll3A72bmsS2yf+A7pMRYD+zjCpd99E/tkL40sAGT2u48L+zjlJZSBYpHf0fnfhai4b75KG/1oUa2n34y2+A7X9bPW74My1zsOHj6p9pzpZAPNpRRAkyWtCo+QtXPIlEqy5xCuj2h8O6llzwIZb14jbgNS8BNhhsQ60hYwhUG0FuDQaY2+hAibMioTxLkuOW6POZKZ7cW/UMrc58oZKcqfD2qht39nmiaHgeCq3SB9V/fDHXwBYr4hrp9c0UNKvcToXOI+D/j7iM2NWANz83svWRbnwfnol9Q+mYELGSky49hoy/TI4WGEJIpSXK7N5M0s2jQDJrIYzedwx/mZ8Gr3EzwCuigwpk6lkwqA5VoYngdkuR1YPO8M9nBdgcrQfL/gnC4HFt+NwlhsylhkE2QAlWpD5F15XJYGesTnJFkWiHUmids5LfPn3BW2Z2c+7u+aBQYwZjT09EW8uLaF9yi23cduBFNV26ESAFJwMecvVbNXzp0UpptQbA/t24q+c3vpy/AlW+VbG73AherSMEU4OF8UNuBF2a9Q7JejysHWiD58vvYKpfNyYFDOLXhijqiBjCrQeSaO2FWhA3q+e7nwHu7piJ359msCClDMQLg+mO4mqKulfFjXXpvPdTDr/eMQffSmvB2mVZHPK31wS2Y7jyWj8UOEiyxrrNrBmhxIO/ZVDv0Vcy79eA9UpXcXZXPcyxlMIl1fpQo9mKp9Knce8HK44yWo4Ng3Lc3zcVpCU+Y/mxVuzM2QR7vunRbJWnrKCZiLRuPaTXTaRcJUPet00JNGLLodj8CW6UmEv5HWNxVI0cm04cQ7dPfGSX0wQuEilkqTICSNsTf4kBFwvr4+KTlbj1cw4XqjrAXedATFLaBs3jXsEXDSNYapFORWavMSp/OTpYvAOdpzIgt2Ie4xsX/DG2mFJvb4WHrZrQ9vAyPOl7jEM9tpCh1I+3M32gQG40Fdffo8nXGIU3P6Ffs8wh+1ssq5c+wfWb3/IfZSu6LX0HOs++Z5/ry/F+HnHGaQGvJy2Ir9pLkke/4v/C2xH/nUOyjyai5k9LuhTTCeIP7rCS7xlKjJoEpnEj4bqTETobNvD/nkVygPgvUNn/CUclh8HOoGQarJYlldyJ0DH2Ir88vwPNtzuz2GAt//B1xBRsY933s8G19wjZiq2C33PGwf8FAAD//++T2kE="
diff --git a/vendor/github.com/btcsuite/btcd/btcec/signature.go b/vendor/github.com/btcsuite/btcd/btcec/signature.go
new file mode 100644
index 0000000000..9b27652079
--- /dev/null
+++ b/vendor/github.com/btcsuite/btcd/btcec/signature.go
@@ -0,0 +1,539 @@
+// Copyright (c) 2013-2017 The btcsuite developers
+// Use of this source code is governed by an ISC
+// license that can be found in the LICENSE file.
+
+package btcec
+
+import (
+ "bytes"
+ "crypto/ecdsa"
+ "crypto/elliptic"
+ "crypto/hmac"
+ "crypto/sha256"
+ "errors"
+ "fmt"
+ "hash"
+ "math/big"
+)
+
+// Errors returned by canonicalPadding.
+var (
+ errNegativeValue = errors.New("value may be interpreted as negative")
+ errExcessivelyPaddedValue = errors.New("value is excessively padded")
+)
+
+// Signature is a type representing an ecdsa signature.
+type Signature struct {
+ R *big.Int
+ S *big.Int
+}
+
+var (
+ // Curve order and halforder, used to tame ECDSA malleability (see BIP-0062)
+ order = new(big.Int).Set(S256().N)
+ halforder = new(big.Int).Rsh(order, 1)
+
+ // Used in RFC6979 implementation when testing the nonce for correctness
+ one = big.NewInt(1)
+
+ // oneInitializer is used to fill a byte slice with byte 0x01. It is provided
+ // here to avoid the need to create it multiple times.
+ oneInitializer = []byte{0x01}
+)
+
+// Serialize returns the ECDSA signature in the more strict DER format. Note
+// that the serialized bytes returned do not include the appended hash type
+// used in Bitcoin signature scripts.
+//
+// encoding/asn1 is broken so we hand roll this output:
+//
+// 0x30 0x02 r 0x02 s
+func (sig *Signature) Serialize() []byte {
+ // low 'S' malleability breaker
+ sigS := sig.S
+ if sigS.Cmp(halforder) == 1 {
+ sigS = new(big.Int).Sub(order, sigS)
+ }
+ // Ensure the encoded bytes for the r and s values are canonical and
+ // thus suitable for DER encoding.
+ rb := canonicalizeInt(sig.R)
+ sb := canonicalizeInt(sigS)
+
+ // total length of returned signature is 1 byte for each magic and
+ // length (6 total), plus lengths of r and s
+ length := 6 + len(rb) + len(sb)
+ b := make([]byte, length, length)
+
+ b[0] = 0x30
+ b[1] = byte(length - 2)
+ b[2] = 0x02
+ b[3] = byte(len(rb))
+ offset := copy(b[4:], rb) + 4
+ b[offset] = 0x02
+ b[offset+1] = byte(len(sb))
+ copy(b[offset+2:], sb)
+ return b
+}
+
+// Verify calls ecdsa.Verify to verify the signature of hash using the public
+// key. It returns true if the signature is valid, false otherwise.
+func (sig *Signature) Verify(hash []byte, pubKey *PublicKey) bool {
+ return ecdsa.Verify(pubKey.ToECDSA(), hash, sig.R, sig.S)
+}
+
+// IsEqual compares this Signature instance to the one passed, returning true
+// if both Signatures are equivalent. A signature is equivalent to another, if
+// they both have the same scalar value for R and S.
+func (sig *Signature) IsEqual(otherSig *Signature) bool {
+ return sig.R.Cmp(otherSig.R) == 0 &&
+ sig.S.Cmp(otherSig.S) == 0
+}
+
+func parseSig(sigStr []byte, curve elliptic.Curve, der bool) (*Signature, error) {
+ // Originally this code used encoding/asn1 in order to parse the
+ // signature, but a number of problems were found with this approach.
+ // Despite the fact that signatures are stored as DER, the difference
+ // between go's idea of a bignum (and that they have sign) doesn't agree
+ // with the openssl one (where they do not). The above is true as of
+ // Go 1.1. In the end it was simpler to rewrite the code to explicitly
+ // understand the format which is this:
+ // 0x30 <0x02> 0x2
+ // .
+
+ signature := &Signature{}
+
+ // minimal message is when both numbers are 1 bytes. adding up to:
+ // 0x30 + len + 0x02 + 0x01 + + 0x2 + 0x01 +
+ if len(sigStr) < 8 {
+ return nil, errors.New("malformed signature: too short")
+ }
+ // 0x30
+ index := 0
+ if sigStr[index] != 0x30 {
+ return nil, errors.New("malformed signature: no header magic")
+ }
+ index++
+ // length of remaining message
+ siglen := sigStr[index]
+ index++
+ if int(siglen+2) > len(sigStr) {
+ return nil, errors.New("malformed signature: bad length")
+ }
+ // trim the slice we're working on so we only look at what matters.
+ sigStr = sigStr[:siglen+2]
+
+ // 0x02
+ if sigStr[index] != 0x02 {
+ return nil,
+ errors.New("malformed signature: no 1st int marker")
+ }
+ index++
+
+ // Length of signature R.
+ rLen := int(sigStr[index])
+ // must be positive, must be able to fit in another 0x2,
+ // hence the -3. We assume that the length must be at least one byte.
+ index++
+ if rLen <= 0 || rLen > len(sigStr)-index-3 {
+ return nil, errors.New("malformed signature: bogus R length")
+ }
+
+ // Then R itself.
+ rBytes := sigStr[index : index+rLen]
+ if der {
+ switch err := canonicalPadding(rBytes); err {
+ case errNegativeValue:
+ return nil, errors.New("signature R is negative")
+ case errExcessivelyPaddedValue:
+ return nil, errors.New("signature R is excessively padded")
+ }
+ }
+ signature.R = new(big.Int).SetBytes(rBytes)
+ index += rLen
+ // 0x02. length already checked in previous if.
+ if sigStr[index] != 0x02 {
+ return nil, errors.New("malformed signature: no 2nd int marker")
+ }
+ index++
+
+ // Length of signature S.
+ sLen := int(sigStr[index])
+ index++
+ // S should be the rest of the string.
+ if sLen <= 0 || sLen > len(sigStr)-index {
+ return nil, errors.New("malformed signature: bogus S length")
+ }
+
+ // Then S itself.
+ sBytes := sigStr[index : index+sLen]
+ if der {
+ switch err := canonicalPadding(sBytes); err {
+ case errNegativeValue:
+ return nil, errors.New("signature S is negative")
+ case errExcessivelyPaddedValue:
+ return nil, errors.New("signature S is excessively padded")
+ }
+ }
+ signature.S = new(big.Int).SetBytes(sBytes)
+ index += sLen
+
+ // sanity check length parsing
+ if index != len(sigStr) {
+ return nil, fmt.Errorf("malformed signature: bad final length %v != %v",
+ index, len(sigStr))
+ }
+
+ // Verify also checks this, but we can be more sure that we parsed
+ // correctly if we verify here too.
+ // FWIW the ecdsa spec states that R and S must be | 1, N - 1 |
+ // but crypto/ecdsa only checks for Sign != 0. Mirror that.
+ if signature.R.Sign() != 1 {
+ return nil, errors.New("signature R isn't 1 or more")
+ }
+ if signature.S.Sign() != 1 {
+ return nil, errors.New("signature S isn't 1 or more")
+ }
+ if signature.R.Cmp(curve.Params().N) >= 0 {
+ return nil, errors.New("signature R is >= curve.N")
+ }
+ if signature.S.Cmp(curve.Params().N) >= 0 {
+ return nil, errors.New("signature S is >= curve.N")
+ }
+
+ return signature, nil
+}
+
+// ParseSignature parses a signature in BER format for the curve type `curve'
+// into a Signature type, perfoming some basic sanity checks. If parsing
+// according to the more strict DER format is needed, use ParseDERSignature.
+func ParseSignature(sigStr []byte, curve elliptic.Curve) (*Signature, error) {
+ return parseSig(sigStr, curve, false)
+}
+
+// ParseDERSignature parses a signature in DER format for the curve type
+// `curve` into a Signature type. If parsing according to the less strict
+// BER format is needed, use ParseSignature.
+func ParseDERSignature(sigStr []byte, curve elliptic.Curve) (*Signature, error) {
+ return parseSig(sigStr, curve, true)
+}
+
+// canonicalizeInt returns the bytes for the passed big integer adjusted as
+// necessary to ensure that a big-endian encoded integer can't possibly be
+// misinterpreted as a negative number. This can happen when the most
+// significant bit is set, so it is padded by a leading zero byte in this case.
+// Also, the returned bytes will have at least a single byte when the passed
+// value is 0. This is required for DER encoding.
+func canonicalizeInt(val *big.Int) []byte {
+ b := val.Bytes()
+ if len(b) == 0 {
+ b = []byte{0x00}
+ }
+ if b[0]&0x80 != 0 {
+ paddedBytes := make([]byte, len(b)+1)
+ copy(paddedBytes[1:], b)
+ b = paddedBytes
+ }
+ return b
+}
+
+// canonicalPadding checks whether a big-endian encoded integer could
+// possibly be misinterpreted as a negative number (even though OpenSSL
+// treats all numbers as unsigned), or if there is any unnecessary
+// leading zero padding.
+func canonicalPadding(b []byte) error {
+ switch {
+ case b[0]&0x80 == 0x80:
+ return errNegativeValue
+ case len(b) > 1 && b[0] == 0x00 && b[1]&0x80 != 0x80:
+ return errExcessivelyPaddedValue
+ default:
+ return nil
+ }
+}
+
+// hashToInt converts a hash value to an integer. There is some disagreement
+// about how this is done. [NSA] suggests that this is done in the obvious
+// manner, but [SECG] truncates the hash to the bit-length of the curve order
+// first. We follow [SECG] because that's what OpenSSL does. Additionally,
+// OpenSSL right shifts excess bits from the number if the hash is too large
+// and we mirror that too.
+// This is borrowed from crypto/ecdsa.
+func hashToInt(hash []byte, c elliptic.Curve) *big.Int {
+ orderBits := c.Params().N.BitLen()
+ orderBytes := (orderBits + 7) / 8
+ if len(hash) > orderBytes {
+ hash = hash[:orderBytes]
+ }
+
+ ret := new(big.Int).SetBytes(hash)
+ excess := len(hash)*8 - orderBits
+ if excess > 0 {
+ ret.Rsh(ret, uint(excess))
+ }
+ return ret
+}
+
+// recoverKeyFromSignature recoves a public key from the signature "sig" on the
+// given message hash "msg". Based on the algorithm found in section 5.1.5 of
+// SEC 1 Ver 2.0, page 47-48 (53 and 54 in the pdf). This performs the details
+// in the inner loop in Step 1. The counter provided is actually the j parameter
+// of the loop * 2 - on the first iteration of j we do the R case, else the -R
+// case in step 1.6. This counter is used in the bitcoin compressed signature
+// format and thus we match bitcoind's behaviour here.
+func recoverKeyFromSignature(curve *KoblitzCurve, sig *Signature, msg []byte,
+ iter int, doChecks bool) (*PublicKey, error) {
+ // 1.1 x = (n * i) + r
+ Rx := new(big.Int).Mul(curve.Params().N,
+ new(big.Int).SetInt64(int64(iter/2)))
+ Rx.Add(Rx, sig.R)
+ if Rx.Cmp(curve.Params().P) != -1 {
+ return nil, errors.New("calculated Rx is larger than curve P")
+ }
+
+ // convert 02 to point R. (step 1.2 and 1.3). If we are on an odd
+ // iteration then 1.6 will be done with -R, so we calculate the other
+ // term when uncompressing the point.
+ Ry, err := decompressPoint(curve, Rx, iter%2 == 1)
+ if err != nil {
+ return nil, err
+ }
+
+ // 1.4 Check n*R is point at infinity
+ if doChecks {
+ nRx, nRy := curve.ScalarMult(Rx, Ry, curve.Params().N.Bytes())
+ if nRx.Sign() != 0 || nRy.Sign() != 0 {
+ return nil, errors.New("n*R does not equal the point at infinity")
+ }
+ }
+
+ // 1.5 calculate e from message using the same algorithm as ecdsa
+ // signature calculation.
+ e := hashToInt(msg, curve)
+
+ // Step 1.6.1:
+ // We calculate the two terms sR and eG separately multiplied by the
+ // inverse of r (from the signature). We then add them to calculate
+ // Q = r^-1(sR-eG)
+ invr := new(big.Int).ModInverse(sig.R, curve.Params().N)
+
+ // first term.
+ invrS := new(big.Int).Mul(invr, sig.S)
+ invrS.Mod(invrS, curve.Params().N)
+ sRx, sRy := curve.ScalarMult(Rx, Ry, invrS.Bytes())
+
+ // second term.
+ e.Neg(e)
+ e.Mod(e, curve.Params().N)
+ e.Mul(e, invr)
+ e.Mod(e, curve.Params().N)
+ minuseGx, minuseGy := curve.ScalarBaseMult(e.Bytes())
+
+ // TODO: this would be faster if we did a mult and add in one
+ // step to prevent the jacobian conversion back and forth.
+ Qx, Qy := curve.Add(sRx, sRy, minuseGx, minuseGy)
+
+ return &PublicKey{
+ Curve: curve,
+ X: Qx,
+ Y: Qy,
+ }, nil
+}
+
+// SignCompact produces a compact signature of the data in hash with the given
+// private key on the given koblitz curve. The isCompressed parameter should
+// be used to detail if the given signature should reference a compressed
+// public key or not. If successful the bytes of the compact signature will be
+// returned in the format:
+// <(byte of 27+public key solution)+4 if compressed >< padded bytes for signature R>
+// where the R and S parameters are padde up to the bitlengh of the curve.
+func SignCompact(curve *KoblitzCurve, key *PrivateKey,
+ hash []byte, isCompressedKey bool) ([]byte, error) {
+ sig, err := key.Sign(hash)
+ if err != nil {
+ return nil, err
+ }
+
+ // bitcoind checks the bit length of R and S here. The ecdsa signature
+ // algorithm returns R and S mod N therefore they will be the bitsize of
+ // the curve, and thus correctly sized.
+ for i := 0; i < (curve.H+1)*2; i++ {
+ pk, err := recoverKeyFromSignature(curve, sig, hash, i, true)
+ if err == nil && pk.X.Cmp(key.X) == 0 && pk.Y.Cmp(key.Y) == 0 {
+ result := make([]byte, 1, 2*curve.byteSize+1)
+ result[0] = 27 + byte(i)
+ if isCompressedKey {
+ result[0] += 4
+ }
+ // Not sure this needs rounding but safer to do so.
+ curvelen := (curve.BitSize + 7) / 8
+
+ // Pad R and S to curvelen if needed.
+ bytelen := (sig.R.BitLen() + 7) / 8
+ if bytelen < curvelen {
+ result = append(result,
+ make([]byte, curvelen-bytelen)...)
+ }
+ result = append(result, sig.R.Bytes()...)
+
+ bytelen = (sig.S.BitLen() + 7) / 8
+ if bytelen < curvelen {
+ result = append(result,
+ make([]byte, curvelen-bytelen)...)
+ }
+ result = append(result, sig.S.Bytes()...)
+
+ return result, nil
+ }
+ }
+
+ return nil, errors.New("no valid solution for pubkey found")
+}
+
+// RecoverCompact verifies the compact signature "signature" of "hash" for the
+// Koblitz curve in "curve". If the signature matches then the recovered public
+// key will be returned as well as a boolen if the original key was compressed
+// or not, else an error will be returned.
+func RecoverCompact(curve *KoblitzCurve, signature,
+ hash []byte) (*PublicKey, bool, error) {
+ bitlen := (curve.BitSize + 7) / 8
+ if len(signature) != 1+bitlen*2 {
+ return nil, false, errors.New("invalid compact signature size")
+ }
+
+ iteration := int((signature[0] - 27) & ^byte(4))
+
+ // format is
+ sig := &Signature{
+ R: new(big.Int).SetBytes(signature[1 : bitlen+1]),
+ S: new(big.Int).SetBytes(signature[bitlen+1:]),
+ }
+ // The iteration used here was encoded
+ key, err := recoverKeyFromSignature(curve, sig, hash, iteration, false)
+ if err != nil {
+ return nil, false, err
+ }
+
+ return key, ((signature[0] - 27) & 4) == 4, nil
+}
+
+// signRFC6979 generates a deterministic ECDSA signature according to RFC 6979 and BIP 62.
+func signRFC6979(privateKey *PrivateKey, hash []byte) (*Signature, error) {
+
+ privkey := privateKey.ToECDSA()
+ N := order
+ k := nonceRFC6979(privkey.D, hash)
+ inv := new(big.Int).ModInverse(k, N)
+ r, _ := privkey.Curve.ScalarBaseMult(k.Bytes())
+ if r.Cmp(N) == 1 {
+ r.Sub(r, N)
+ }
+
+ if r.Sign() == 0 {
+ return nil, errors.New("calculated R is zero")
+ }
+
+ e := hashToInt(hash, privkey.Curve)
+ s := new(big.Int).Mul(privkey.D, r)
+ s.Add(s, e)
+ s.Mul(s, inv)
+ s.Mod(s, N)
+
+ if s.Cmp(halforder) == 1 {
+ s.Sub(N, s)
+ }
+ if s.Sign() == 0 {
+ return nil, errors.New("calculated S is zero")
+ }
+ return &Signature{R: r, S: s}, nil
+}
+
+// nonceRFC6979 generates an ECDSA nonce (`k`) deterministically according to RFC 6979.
+// It takes a 32-byte hash as an input and returns 32-byte nonce to be used in ECDSA algorithm.
+func nonceRFC6979(privkey *big.Int, hash []byte) *big.Int {
+
+ curve := S256()
+ q := curve.Params().N
+ x := privkey
+ alg := sha256.New
+
+ qlen := q.BitLen()
+ holen := alg().Size()
+ rolen := (qlen + 7) >> 3
+ bx := append(int2octets(x, rolen), bits2octets(hash, curve, rolen)...)
+
+ // Step B
+ v := bytes.Repeat(oneInitializer, holen)
+
+ // Step C (Go zeroes the all allocated memory)
+ k := make([]byte, holen)
+
+ // Step D
+ k = mac(alg, k, append(append(v, 0x00), bx...))
+
+ // Step E
+ v = mac(alg, k, v)
+
+ // Step F
+ k = mac(alg, k, append(append(v, 0x01), bx...))
+
+ // Step G
+ v = mac(alg, k, v)
+
+ // Step H
+ for {
+ // Step H1
+ var t []byte
+
+ // Step H2
+ for len(t)*8 < qlen {
+ v = mac(alg, k, v)
+ t = append(t, v...)
+ }
+
+ // Step H3
+ secret := hashToInt(t, curve)
+ if secret.Cmp(one) >= 0 && secret.Cmp(q) < 0 {
+ return secret
+ }
+ k = mac(alg, k, append(v, 0x00))
+ v = mac(alg, k, v)
+ }
+}
+
+// mac returns an HMAC of the given key and message.
+func mac(alg func() hash.Hash, k, m []byte) []byte {
+ h := hmac.New(alg, k)
+ h.Write(m)
+ return h.Sum(nil)
+}
+
+// https://tools.ietf.org/html/rfc6979#section-2.3.3
+func int2octets(v *big.Int, rolen int) []byte {
+ out := v.Bytes()
+
+ // left pad with zeros if it's too short
+ if len(out) < rolen {
+ out2 := make([]byte, rolen)
+ copy(out2[rolen-len(out):], out)
+ return out2
+ }
+
+ // drop most significant bytes if it's too long
+ if len(out) > rolen {
+ out2 := make([]byte, rolen)
+ copy(out2, out[len(out)-rolen:])
+ return out2
+ }
+
+ return out
+}
+
+// https://tools.ietf.org/html/rfc6979#section-2.3.4
+func bits2octets(in []byte, curve elliptic.Curve, rolen int) []byte {
+ z1 := hashToInt(in, curve)
+ z2 := new(big.Int).Sub(z1, curve.Params().N)
+ if z2.Sign() < 0 {
+ return int2octets(z1, rolen)
+ }
+ return int2octets(z2, rolen)
+}
diff --git a/vendor/github.com/edsrzf/mmap-go/LICENSE b/vendor/github.com/edsrzf/mmap-go/LICENSE
new file mode 100644
index 0000000000..8f05f338ac
--- /dev/null
+++ b/vendor/github.com/edsrzf/mmap-go/LICENSE
@@ -0,0 +1,25 @@
+Copyright (c) 2011, Evan Shaw
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of the copyright holder nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
diff --git a/vendor/github.com/edsrzf/mmap-go/README.md b/vendor/github.com/edsrzf/mmap-go/README.md
new file mode 100644
index 0000000000..4cc2bfe1c8
--- /dev/null
+++ b/vendor/github.com/edsrzf/mmap-go/README.md
@@ -0,0 +1,12 @@
+mmap-go
+=======
+
+mmap-go is a portable mmap package for the [Go programming language](http://golang.org).
+It has been tested on Linux (386, amd64), OS X, and Windows (386). It should also
+work on other Unix-like platforms, but hasn't been tested with them. I'm interested
+to hear about the results.
+
+I haven't been able to add more features without adding significant complexity,
+so mmap-go doesn't support mprotect, mincore, and maybe a few other things.
+If you're running on a Unix-like platform and need some of these features,
+I suggest Gustavo Niemeyer's [gommap](http://labix.org/gommap).
diff --git a/vendor/github.com/edsrzf/mmap-go/mmap.go b/vendor/github.com/edsrzf/mmap-go/mmap.go
new file mode 100644
index 0000000000..7bb4965ed5
--- /dev/null
+++ b/vendor/github.com/edsrzf/mmap-go/mmap.go
@@ -0,0 +1,112 @@
+// Copyright 2011 Evan Shaw. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file defines the common package interface and contains a little bit of
+// factored out logic.
+
+// Package mmap allows mapping files into memory. It tries to provide a simple, reasonably portable interface,
+// but doesn't go out of its way to abstract away every little platform detail.
+// This specifically means:
+// * forked processes may or may not inherit mappings
+// * a file's timestamp may or may not be updated by writes through mappings
+// * specifying a size larger than the file's actual size can increase the file's size
+// * If the mapped file is being modified by another process while your program's running, don't expect consistent results between platforms
+package mmap
+
+import (
+ "errors"
+ "os"
+ "reflect"
+ "unsafe"
+)
+
+const (
+ // RDONLY maps the memory read-only.
+ // Attempts to write to the MMap object will result in undefined behavior.
+ RDONLY = 0
+ // RDWR maps the memory as read-write. Writes to the MMap object will update the
+ // underlying file.
+ RDWR = 1 << iota
+ // COPY maps the memory as copy-on-write. Writes to the MMap object will affect
+ // memory, but the underlying file will remain unchanged.
+ COPY
+ // If EXEC is set, the mapped memory is marked as executable.
+ EXEC
+)
+
+const (
+ // If the ANON flag is set, the mapped memory will not be backed by a file.
+ ANON = 1 << iota
+)
+
+// MMap represents a file mapped into memory.
+type MMap []byte
+
+// Map maps an entire file into memory.
+// If ANON is set in flags, f is ignored.
+func Map(f *os.File, prot, flags int) (MMap, error) {
+ return MapRegion(f, -1, prot, flags, 0)
+}
+
+// MapRegion maps part of a file into memory.
+// The offset parameter must be a multiple of the system's page size.
+// If length < 0, the entire file will be mapped.
+// If ANON is set in flags, f is ignored.
+func MapRegion(f *os.File, length int, prot, flags int, offset int64) (MMap, error) {
+ var fd uintptr
+ if flags&ANON == 0 {
+ fd = uintptr(f.Fd())
+ if length < 0 {
+ fi, err := f.Stat()
+ if err != nil {
+ return nil, err
+ }
+ length = int(fi.Size())
+ }
+ } else {
+ if length <= 0 {
+ return nil, errors.New("anonymous mapping requires non-zero length")
+ }
+ fd = ^uintptr(0)
+ }
+ return mmap(length, uintptr(prot), uintptr(flags), fd, offset)
+}
+
+func (m *MMap) header() *reflect.SliceHeader {
+ return (*reflect.SliceHeader)(unsafe.Pointer(m))
+}
+
+// Lock keeps the mapped region in physical memory, ensuring that it will not be
+// swapped out.
+func (m MMap) Lock() error {
+ dh := m.header()
+ return lock(dh.Data, uintptr(dh.Len))
+}
+
+// Unlock reverses the effect of Lock, allowing the mapped region to potentially
+// be swapped out.
+// If m is already unlocked, aan error will result.
+func (m MMap) Unlock() error {
+ dh := m.header()
+ return unlock(dh.Data, uintptr(dh.Len))
+}
+
+// Flush synchronizes the mapping's contents to the file's contents on disk.
+func (m MMap) Flush() error {
+ dh := m.header()
+ return flush(dh.Data, uintptr(dh.Len))
+}
+
+// Unmap deletes the memory mapped region, flushes any remaining changes, and sets
+// m to nil.
+// Trying to read or write any remaining references to m after Unmap is called will
+// result in undefined behavior.
+// Unmap should only be called on the slice value that was originally returned from
+// a call to Map. Calling Unmap on a derived slice may cause errors.
+func (m *MMap) Unmap() error {
+ dh := m.header()
+ err := unmap(dh.Data, uintptr(dh.Len))
+ *m = nil
+ return err
+}
diff --git a/vendor/github.com/edsrzf/mmap-go/mmap_unix.go b/vendor/github.com/edsrzf/mmap-go/mmap_unix.go
new file mode 100644
index 0000000000..4af98420d5
--- /dev/null
+++ b/vendor/github.com/edsrzf/mmap-go/mmap_unix.go
@@ -0,0 +1,67 @@
+// Copyright 2011 Evan Shaw. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build darwin dragonfly freebsd linux openbsd solaris netbsd
+
+package mmap
+
+import (
+ "syscall"
+)
+
+func mmap(len int, inprot, inflags, fd uintptr, off int64) ([]byte, error) {
+ flags := syscall.MAP_SHARED
+ prot := syscall.PROT_READ
+ switch {
+ case inprot© != 0:
+ prot |= syscall.PROT_WRITE
+ flags = syscall.MAP_PRIVATE
+ case inprot&RDWR != 0:
+ prot |= syscall.PROT_WRITE
+ }
+ if inprot&EXEC != 0 {
+ prot |= syscall.PROT_EXEC
+ }
+ if inflags&ANON != 0 {
+ flags |= syscall.MAP_ANON
+ }
+
+ b, err := syscall.Mmap(int(fd), off, len, prot, flags)
+ if err != nil {
+ return nil, err
+ }
+ return b, nil
+}
+
+func flush(addr, len uintptr) error {
+ _, _, errno := syscall.Syscall(_SYS_MSYNC, addr, len, _MS_SYNC)
+ if errno != 0 {
+ return syscall.Errno(errno)
+ }
+ return nil
+}
+
+func lock(addr, len uintptr) error {
+ _, _, errno := syscall.Syscall(syscall.SYS_MLOCK, addr, len, 0)
+ if errno != 0 {
+ return syscall.Errno(errno)
+ }
+ return nil
+}
+
+func unlock(addr, len uintptr) error {
+ _, _, errno := syscall.Syscall(syscall.SYS_MUNLOCK, addr, len, 0)
+ if errno != 0 {
+ return syscall.Errno(errno)
+ }
+ return nil
+}
+
+func unmap(addr, len uintptr) error {
+ _, _, errno := syscall.Syscall(syscall.SYS_MUNMAP, addr, len, 0)
+ if errno != 0 {
+ return syscall.Errno(errno)
+ }
+ return nil
+}
diff --git a/vendor/github.com/edsrzf/mmap-go/mmap_windows.go b/vendor/github.com/edsrzf/mmap-go/mmap_windows.go
new file mode 100644
index 0000000000..c3d2d02d3f
--- /dev/null
+++ b/vendor/github.com/edsrzf/mmap-go/mmap_windows.go
@@ -0,0 +1,125 @@
+// Copyright 2011 Evan Shaw. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package mmap
+
+import (
+ "errors"
+ "os"
+ "sync"
+ "syscall"
+)
+
+// mmap on Windows is a two-step process.
+// First, we call CreateFileMapping to get a handle.
+// Then, we call MapviewToFile to get an actual pointer into memory.
+// Because we want to emulate a POSIX-style mmap, we don't want to expose
+// the handle -- only the pointer. We also want to return only a byte slice,
+// not a struct, so it's convenient to manipulate.
+
+// We keep this map so that we can get back the original handle from the memory address.
+var handleLock sync.Mutex
+var handleMap = map[uintptr]syscall.Handle{}
+
+func mmap(len int, prot, flags, hfile uintptr, off int64) ([]byte, error) {
+ flProtect := uint32(syscall.PAGE_READONLY)
+ dwDesiredAccess := uint32(syscall.FILE_MAP_READ)
+ switch {
+ case prot© != 0:
+ flProtect = syscall.PAGE_WRITECOPY
+ dwDesiredAccess = syscall.FILE_MAP_COPY
+ case prot&RDWR != 0:
+ flProtect = syscall.PAGE_READWRITE
+ dwDesiredAccess = syscall.FILE_MAP_WRITE
+ }
+ if prot&EXEC != 0 {
+ flProtect <<= 4
+ dwDesiredAccess |= syscall.FILE_MAP_EXECUTE
+ }
+
+ // The maximum size is the area of the file, starting from 0,
+ // that we wish to allow to be mappable. It is the sum of
+ // the length the user requested, plus the offset where that length
+ // is starting from. This does not map the data into memory.
+ maxSizeHigh := uint32((off + int64(len)) >> 32)
+ maxSizeLow := uint32((off + int64(len)) & 0xFFFFFFFF)
+ // TODO: Do we need to set some security attributes? It might help portability.
+ h, errno := syscall.CreateFileMapping(syscall.Handle(hfile), nil, flProtect, maxSizeHigh, maxSizeLow, nil)
+ if h == 0 {
+ return nil, os.NewSyscallError("CreateFileMapping", errno)
+ }
+
+ // Actually map a view of the data into memory. The view's size
+ // is the length the user requested.
+ fileOffsetHigh := uint32(off >> 32)
+ fileOffsetLow := uint32(off & 0xFFFFFFFF)
+ addr, errno := syscall.MapViewOfFile(h, dwDesiredAccess, fileOffsetHigh, fileOffsetLow, uintptr(len))
+ if addr == 0 {
+ return nil, os.NewSyscallError("MapViewOfFile", errno)
+ }
+ handleLock.Lock()
+ handleMap[addr] = h
+ handleLock.Unlock()
+
+ m := MMap{}
+ dh := m.header()
+ dh.Data = addr
+ dh.Len = len
+ dh.Cap = dh.Len
+
+ return m, nil
+}
+
+func flush(addr, len uintptr) error {
+ errno := syscall.FlushViewOfFile(addr, len)
+ if errno != nil {
+ return os.NewSyscallError("FlushViewOfFile", errno)
+ }
+
+ handleLock.Lock()
+ defer handleLock.Unlock()
+ handle, ok := handleMap[addr]
+ if !ok {
+ // should be impossible; we would've errored above
+ return errors.New("unknown base address")
+ }
+
+ errno = syscall.FlushFileBuffers(handle)
+ return os.NewSyscallError("FlushFileBuffers", errno)
+}
+
+func lock(addr, len uintptr) error {
+ errno := syscall.VirtualLock(addr, len)
+ return os.NewSyscallError("VirtualLock", errno)
+}
+
+func unlock(addr, len uintptr) error {
+ errno := syscall.VirtualUnlock(addr, len)
+ return os.NewSyscallError("VirtualUnlock", errno)
+}
+
+func unmap(addr, len uintptr) error {
+ flush(addr, len)
+ // Lock the UnmapViewOfFile along with the handleMap deletion.
+ // As soon as we unmap the view, the OS is free to give the
+ // same addr to another new map. We don't want another goroutine
+ // to insert and remove the same addr into handleMap while
+ // we're trying to remove our old addr/handle pair.
+ handleLock.Lock()
+ defer handleLock.Unlock()
+ err := syscall.UnmapViewOfFile(addr)
+ if err != nil {
+ return err
+ }
+
+ handle, ok := handleMap[addr]
+ if !ok {
+ // should be impossible; we would've errored above
+ return errors.New("unknown base address")
+ }
+ delete(handleMap, addr)
+
+ e := syscall.CloseHandle(syscall.Handle(handle))
+ return os.NewSyscallError("CloseHandle", e)
+}
diff --git a/vendor/github.com/edsrzf/mmap-go/msync_netbsd.go b/vendor/github.com/edsrzf/mmap-go/msync_netbsd.go
new file mode 100644
index 0000000000..a64b003e2d
--- /dev/null
+++ b/vendor/github.com/edsrzf/mmap-go/msync_netbsd.go
@@ -0,0 +1,8 @@
+// Copyright 2011 Evan Shaw. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package mmap
+
+const _SYS_MSYNC = 277
+const _MS_SYNC = 0x04
diff --git a/vendor/github.com/edsrzf/mmap-go/msync_unix.go b/vendor/github.com/edsrzf/mmap-go/msync_unix.go
new file mode 100644
index 0000000000..91ee5f40f1
--- /dev/null
+++ b/vendor/github.com/edsrzf/mmap-go/msync_unix.go
@@ -0,0 +1,14 @@
+// Copyright 2011 Evan Shaw. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build darwin dragonfly freebsd linux openbsd solaris
+
+package mmap
+
+import (
+ "syscall"
+)
+
+const _SYS_MSYNC = syscall.SYS_MSYNC
+const _MS_SYNC = syscall.MS_SYNC
diff --git a/vendor/github.com/ethereum/ethash/.gitignore b/vendor/github.com/ethereum/ethash/.gitignore
deleted file mode 100644
index da074e6b3a..0000000000
--- a/vendor/github.com/ethereum/ethash/.gitignore
+++ /dev/null
@@ -1,12 +0,0 @@
-.idea/
-.DS_Store
-*/**/*un~
-.vagrant/
-*.pyc
-build/
-pyethash.egg-info/
-*.so
-*~
-*.swp
-MANIFEST
-dist/
diff --git a/vendor/github.com/ethereum/ethash/.travis.yml b/vendor/github.com/ethereum/ethash/.travis.yml
deleted file mode 100644
index b83b02bf3c..0000000000
--- a/vendor/github.com/ethereum/ethash/.travis.yml
+++ /dev/null
@@ -1,23 +0,0 @@
-language: go
-go:
- - 1.4.2
-
-before_install:
- # for g++4.8 and C++11
- - sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
-
- # Set up go-ethereum
- - sudo apt-get update -y -qq
- - sudo apt-get install -yqq libgmp3-dev
- - git clone --depth=10 https://github.com/ethereum/go-ethereum ${GOPATH}/src/github.com/ethereum/go-ethereum
- # use canned dependencies from the go-ethereum repository
- - export GOPATH=$GOPATH:$GOPATH/src/github.com/ethereum/go-ethereum/Godeps/_workspace/
- - echo $GOPATH
-
-install:
- # need to explicitly request version 1.48 since by default we get 1.46 which does not work with C++11
- - sudo apt-get install -qq --yes --force-yes g++-4.8
- - sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.8 50
- - sudo apt-get install -qq wget cmake bash libboost-test1.48-dev libboost-system1.48-dev libboost-filesystem1.48-dev nodejs python-pip python-dev valgrind
- - sudo pip install virtualenv -q
-script: "./test/test.sh"
diff --git a/vendor/github.com/ethereum/ethash/CMakeLists.txt b/vendor/github.com/ethereum/ethash/CMakeLists.txt
deleted file mode 100644
index 807c43e963..0000000000
--- a/vendor/github.com/ethereum/ethash/CMakeLists.txt
+++ /dev/null
@@ -1,14 +0,0 @@
-cmake_minimum_required(VERSION 2.8.7)
-project(ethash)
-
-set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/modules/")
-set(ETHHASH_LIBS ethash)
-
-if (WIN32 AND WANT_CRYPTOPP)
- add_subdirectory(cryptopp)
-endif()
-
-add_subdirectory(src/libethash)
-
-add_subdirectory(src/benchmark EXCLUDE_FROM_ALL)
-add_subdirectory(test/c)
diff --git a/vendor/github.com/ethereum/ethash/MANIFEST.in b/vendor/github.com/ethereum/ethash/MANIFEST.in
deleted file mode 100644
index 74e73c8be4..0000000000
--- a/vendor/github.com/ethereum/ethash/MANIFEST.in
+++ /dev/null
@@ -1,17 +0,0 @@
-include setup.py
-
-# C sources
-include src/libethash/internal.c
-include src/libethash/sha3.c
-include src/libethash/util.c
-include src/python/core.c
-
-# Headers
-include src/libethash/compiler.h
-include src/libethash/data_sizes.h
-include src/libethash/endian.h
-include src/libethash/ethash.h
-include src/libethash/fnv.h
-include src/libethash/internal.h
-include src/libethash/sha3.h
-include src/libethash/util.h
diff --git a/vendor/github.com/ethereum/ethash/Makefile b/vendor/github.com/ethereum/ethash/Makefile
deleted file mode 100644
index 741d3b56dc..0000000000
--- a/vendor/github.com/ethereum/ethash/Makefile
+++ /dev/null
@@ -1,6 +0,0 @@
-.PHONY: clean test
-test:
- ./test/test.sh
-
-clean:
- rm -rf *.so pyethash.egg-info/ build/ test/python/python-virtual-env/ test/c/build/ pyethash.so test/python/*.pyc dist/ MANIFEST
diff --git a/vendor/github.com/ethereum/ethash/README.md b/vendor/github.com/ethereum/ethash/README.md
deleted file mode 100644
index 2b2c3b544c..0000000000
--- a/vendor/github.com/ethereum/ethash/README.md
+++ /dev/null
@@ -1,22 +0,0 @@
-[](https://travis-ci.org/ethereum/ethash)
-[](https://ci.appveyor.com/project/debris/ethash-nr37r/branch/master)
-
-# Ethash
-
-For details on this project, please see the Ethereum wiki:
-https://github.com/ethereum/wiki/wiki/Ethash
-
-### Coding Style for C++ code:
-
-Follow the same exact style as in [cpp-ethereum](https://github.com/ethereum/cpp-ethereum/blob/develop/CodingStandards.txt)
-
-### Coding Style for C code:
-
-The main thing above all is code consistency.
-
-- Tabs for indentation. A tab is 4 spaces
-- Try to stick to the [K&R](http://en.wikipedia.org/wiki/Indent_style#K.26R_style),
- especially for the C code.
-- Keep the line lengths reasonable. No hard limit on 80 characters but don't go further
- than 110. Some people work with multiple buffers next to each other.
- Make them like you :)
diff --git a/vendor/github.com/ethereum/ethash/Vagrantfile b/vendor/github.com/ethereum/ethash/Vagrantfile
deleted file mode 100644
index 03891653f0..0000000000
--- a/vendor/github.com/ethereum/ethash/Vagrantfile
+++ /dev/null
@@ -1,7 +0,0 @@
-# -*- mode: ruby -*-
-# vi: set ft=ruby :
-
-Vagrant.configure(2) do |config|
- config.vm.box = "Ubuntu 12.04"
- config.vm.box_url = "https://cloud-images.ubuntu.com/vagrant/precise/current/precise-server-cloudimg-amd64-vagrant-disk1.box"
-end
diff --git a/vendor/github.com/ethereum/ethash/appveyor.yml b/vendor/github.com/ethereum/ethash/appveyor.yml
deleted file mode 100644
index ac36a06261..0000000000
--- a/vendor/github.com/ethereum/ethash/appveyor.yml
+++ /dev/null
@@ -1,43 +0,0 @@
-version: 1.0.0.{build}
-
-environment:
- BOOST_ROOT: "c:/projects/ethash/deps/boost"
-
-branches:
- only:
- - master
- - develop
-
-os: Windows Server 2012 R2
-
-clone_folder: c:\projects\ethash
-
-#platform: Any CPU
-#configuration: Debug
-
-install:
- # by default, all script lines are interpreted as batch
-
-# scripts to run before build
-before_build:
- - echo "Downloading boost..."
- - mkdir c:\projects\ethash\deps
- - cd c:\projects\ethash\deps
- - curl -O https://build.ethdev.com/builds/windows-precompiled/boost.tar.gz
- - echo "Unzipping boost..."
- - 7z x boost.tar.gz > nul
- - 7z x boost.tar > nul
- - ls
- - echo "Running cmake..."
- - cd c:\projects\ethash
- - cmake .
-
-build:
- project: ALL_BUILD.vcxproj # path to Visual Studio solution or project
-
-after_build:
- - echo "Running tests..."
- - cd c:\projects\ethash\test\c\Debug
- - Test.exe
- - echo "Finished!"
-
diff --git a/vendor/github.com/ethereum/ethash/ethash.go b/vendor/github.com/ethereum/ethash/ethash.go
deleted file mode 100644
index 2a31aaf2d3..0000000000
--- a/vendor/github.com/ethereum/ethash/ethash.go
+++ /dev/null
@@ -1,441 +0,0 @@
-// Copyright 2015 The go-ethereum Authors
-// Copyright 2015 Lefteris Karapetsas
-// Copyright 2015 Matthew Wampler-Doty
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see .
-
-package ethash
-
-/*
-#include "src/libethash/internal.h"
-
-int ethashGoCallback_cgo(unsigned);
-*/
-import "C"
-
-import (
- "errors"
- "fmt"
- "io/ioutil"
- "math/big"
- "math/rand"
- "os"
- "os/user"
- "path/filepath"
- "runtime"
- "sync"
- "sync/atomic"
- "time"
- "unsafe"
-
- "github.com/ethereum/go-ethereum/common"
- "github.com/ethereum/go-ethereum/crypto"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/logger/glog"
- "github.com/ethereum/go-ethereum/pow"
-)
-
-var (
- maxUint256 = new(big.Int).Exp(big.NewInt(2), big.NewInt(256), big.NewInt(0))
- sharedLight = new(Light)
-)
-
-const (
- epochLength uint64 = 30000
- cacheSizeForTesting C.uint64_t = 1024
- dagSizeForTesting C.uint64_t = 1024 * 32
-)
-
-var DefaultDir = defaultDir()
-
-func defaultDir() string {
- home := os.Getenv("HOME")
- if user, err := user.Current(); err == nil {
- home = user.HomeDir
- }
- if runtime.GOOS == "windows" {
- return filepath.Join(home, "AppData", "Ethash")
- }
- return filepath.Join(home, ".ethash")
-}
-
-// cache wraps an ethash_light_t with some metadata
-// and automatic memory management.
-type cache struct {
- epoch uint64
- used time.Time
- test bool
-
- gen sync.Once // ensures cache is only generated once.
- ptr *C.struct_ethash_light
-}
-
-// generate creates the actual cache. it can be called from multiple
-// goroutines. the first call will generate the cache, subsequent
-// calls wait until it is generated.
-func (cache *cache) generate() {
- cache.gen.Do(func() {
- started := time.Now()
- seedHash := makeSeedHash(cache.epoch)
- glog.V(logger.Debug).Infof("Generating cache for epoch %d (%x)", cache.epoch, seedHash)
- size := C.ethash_get_cachesize(C.uint64_t(cache.epoch * epochLength))
- if cache.test {
- size = cacheSizeForTesting
- }
- cache.ptr = C.ethash_light_new_internal(size, (*C.ethash_h256_t)(unsafe.Pointer(&seedHash[0])))
- runtime.SetFinalizer(cache, freeCache)
- glog.V(logger.Debug).Infof("Done generating cache for epoch %d, it took %v", cache.epoch, time.Since(started))
- })
-}
-
-func freeCache(cache *cache) {
- C.ethash_light_delete(cache.ptr)
- cache.ptr = nil
-}
-
-func (cache *cache) compute(dagSize uint64, hash common.Hash, nonce uint64) (ok bool, mixDigest, result common.Hash) {
- ret := C.ethash_light_compute_internal(cache.ptr, C.uint64_t(dagSize), hashToH256(hash), C.uint64_t(nonce))
- // Make sure cache is live until after the C call.
- // This is important because a GC might happen and execute
- // the finalizer before the call completes.
- _ = cache
- return bool(ret.success), h256ToHash(ret.mix_hash), h256ToHash(ret.result)
-}
-
-// Light implements the Verify half of the proof of work. It uses a few small
-// in-memory caches to verify the nonces found by Full.
-type Light struct {
- test bool // If set, use a smaller cache size
-
- mu sync.Mutex // Protects the per-epoch map of verification caches
- caches map[uint64]*cache // Currently maintained verification caches
- future *cache // Pre-generated cache for the estimated future DAG
-
- NumCaches int // Maximum number of caches to keep before eviction (only init, don't modify)
-}
-
-// Verify checks whether the block's nonce is valid.
-func (l *Light) Verify(block pow.Block) bool {
- // TODO: do ethash_quick_verify before getCache in order
- // to prevent DOS attacks.
- blockNum := block.NumberU64()
- if blockNum >= epochLength*2048 {
- glog.V(logger.Debug).Infof("block number %d too high, limit is %d", epochLength*2048)
- return false
- }
-
- difficulty := block.Difficulty()
- /* Cannot happen if block header diff is validated prior to PoW, but can
- happen if PoW is checked first due to parallel PoW checking.
- We could check the minimum valid difficulty but for SoC we avoid (duplicating)
- Ethereum protocol consensus rules here which are not in scope of Ethash
- */
- if difficulty.Cmp(common.Big0) == 0 {
- glog.V(logger.Debug).Infof("invalid block difficulty")
- return false
- }
-
- cache := l.getCache(blockNum)
- dagSize := C.ethash_get_datasize(C.uint64_t(blockNum))
- if l.test {
- dagSize = dagSizeForTesting
- }
- // Recompute the hash using the cache.
- ok, mixDigest, result := cache.compute(uint64(dagSize), block.HashNoNonce(), block.Nonce())
- if !ok {
- return false
- }
-
- // avoid mixdigest malleability as it's not included in a block's "hashNononce"
- if block.MixDigest() != mixDigest {
- return false
- }
-
- // The actual check.
- target := new(big.Int).Div(maxUint256, difficulty)
- return result.Big().Cmp(target) <= 0
-}
-
-func h256ToHash(in C.ethash_h256_t) common.Hash {
- return *(*common.Hash)(unsafe.Pointer(&in.b))
-}
-
-func hashToH256(in common.Hash) C.ethash_h256_t {
- return C.ethash_h256_t{b: *(*[32]C.uint8_t)(unsafe.Pointer(&in[0]))}
-}
-
-func (l *Light) getCache(blockNum uint64) *cache {
- var c *cache
- epoch := blockNum / epochLength
-
- // If we have a PoW for that epoch, use that
- l.mu.Lock()
- if l.caches == nil {
- l.caches = make(map[uint64]*cache)
- }
- if l.NumCaches == 0 {
- l.NumCaches = 3
- }
- c = l.caches[epoch]
- if c == nil {
- // No cached DAG, evict the oldest if the cache limit was reached
- if len(l.caches) >= l.NumCaches {
- var evict *cache
- for _, cache := range l.caches {
- if evict == nil || evict.used.After(cache.used) {
- evict = cache
- }
- }
- glog.V(logger.Debug).Infof("Evicting DAG for epoch %d in favour of epoch %d", evict.epoch, epoch)
- delete(l.caches, evict.epoch)
- }
- // If we have the new DAG pre-generated, use that, otherwise create a new one
- if l.future != nil && l.future.epoch == epoch {
- glog.V(logger.Debug).Infof("Using pre-generated DAG for epoch %d", epoch)
- c, l.future = l.future, nil
- } else {
- glog.V(logger.Debug).Infof("No pre-generated DAG available, creating new for epoch %d", epoch)
- c = &cache{epoch: epoch, test: l.test}
- }
- l.caches[epoch] = c
-
- // If we just used up the future cache, or need a refresh, regenerate
- if l.future == nil || l.future.epoch <= epoch {
- glog.V(logger.Debug).Infof("Pre-generating DAG for epoch %d", epoch+1)
- l.future = &cache{epoch: epoch + 1, test: l.test}
- go l.future.generate()
- }
- }
- c.used = time.Now()
- l.mu.Unlock()
-
- // Wait for generation finish and return the cache
- c.generate()
- return c
-}
-
-// dag wraps an ethash_full_t with some metadata
-// and automatic memory management.
-type dag struct {
- epoch uint64
- test bool
- dir string
-
- gen sync.Once // ensures DAG is only generated once.
- ptr *C.struct_ethash_full
-}
-
-// generate creates the actual DAG. it can be called from multiple
-// goroutines. the first call will generate the DAG, subsequent
-// calls wait until it is generated.
-func (d *dag) generate() {
- d.gen.Do(func() {
- var (
- started = time.Now()
- seedHash = makeSeedHash(d.epoch)
- blockNum = C.uint64_t(d.epoch * epochLength)
- cacheSize = C.ethash_get_cachesize(blockNum)
- dagSize = C.ethash_get_datasize(blockNum)
- )
- if d.test {
- cacheSize = cacheSizeForTesting
- dagSize = dagSizeForTesting
- }
- if d.dir == "" {
- d.dir = DefaultDir
- }
- glog.V(logger.Info).Infof("Generating DAG for epoch %d (size %d) (%x)", d.epoch, dagSize, seedHash)
- // Generate a temporary cache.
- // TODO: this could share the cache with Light
- cache := C.ethash_light_new_internal(cacheSize, (*C.ethash_h256_t)(unsafe.Pointer(&seedHash[0])))
- defer C.ethash_light_delete(cache)
- // Generate the actual DAG.
- d.ptr = C.ethash_full_new_internal(
- C.CString(d.dir),
- hashToH256(seedHash),
- dagSize,
- cache,
- (C.ethash_callback_t)(unsafe.Pointer(C.ethashGoCallback_cgo)),
- )
- if d.ptr == nil {
- panic("ethash_full_new IO or memory error")
- }
- runtime.SetFinalizer(d, freeDAG)
- glog.V(logger.Info).Infof("Done generating DAG for epoch %d, it took %v", d.epoch, time.Since(started))
- })
-}
-
-func freeDAG(d *dag) {
- C.ethash_full_delete(d.ptr)
- d.ptr = nil
-}
-
-func (d *dag) Ptr() unsafe.Pointer {
- return unsafe.Pointer(d.ptr.data)
-}
-
-//export ethashGoCallback
-func ethashGoCallback(percent C.unsigned) C.int {
- glog.V(logger.Info).Infof("Generating DAG: %d%%", percent)
- return 0
-}
-
-// MakeDAG pre-generates a DAG file for the given block number in the
-// given directory. If dir is the empty string, the default directory
-// is used.
-func MakeDAG(blockNum uint64, dir string) error {
- d := &dag{epoch: blockNum / epochLength, dir: dir}
- if blockNum >= epochLength*2048 {
- return fmt.Errorf("block number too high, limit is %d", epochLength*2048)
- }
- d.generate()
- if d.ptr == nil {
- return errors.New("failed")
- }
- return nil
-}
-
-// Full implements the Search half of the proof of work.
-type Full struct {
- Dir string // use this to specify a non-default DAG directory
-
- test bool // if set use a smaller DAG size
- turbo bool
- hashRate int32
-
- mu sync.Mutex // protects dag
- current *dag // current full DAG
-}
-
-func (pow *Full) getDAG(blockNum uint64) (d *dag) {
- epoch := blockNum / epochLength
- pow.mu.Lock()
- if pow.current != nil && pow.current.epoch == epoch {
- d = pow.current
- } else {
- d = &dag{epoch: epoch, test: pow.test, dir: pow.Dir}
- pow.current = d
- }
- pow.mu.Unlock()
- // wait for it to finish generating.
- d.generate()
- return d
-}
-
-func (pow *Full) Search(block pow.Block, stop <-chan struct{}, index int) (nonce uint64, mixDigest []byte) {
- dag := pow.getDAG(block.NumberU64())
-
- r := rand.New(rand.NewSource(time.Now().UnixNano()))
- diff := block.Difficulty()
-
- i := int64(0)
- starti := i
- start := time.Now().UnixNano()
- previousHashrate := int32(0)
-
- nonce = uint64(r.Int63())
- hash := hashToH256(block.HashNoNonce())
- target := new(big.Int).Div(maxUint256, diff)
- for {
- select {
- case <-stop:
- atomic.AddInt32(&pow.hashRate, -previousHashrate)
- return 0, nil
- default:
- i++
-
- // we don't have to update hash rate on every nonce, so update after
- // first nonce check and then after 2^X nonces
- if i == 2 || ((i % (1 << 16)) == 0) {
- elapsed := time.Now().UnixNano() - start
- hashes := (float64(1e9) / float64(elapsed)) * float64(i-starti)
- hashrateDiff := int32(hashes) - previousHashrate
- previousHashrate = int32(hashes)
- atomic.AddInt32(&pow.hashRate, hashrateDiff)
- }
-
- ret := C.ethash_full_compute(dag.ptr, hash, C.uint64_t(nonce))
- result := h256ToHash(ret.result).Big()
-
- // TODO: disagrees with the spec https://github.com/ethereum/wiki/wiki/Ethash#mining
- if ret.success && result.Cmp(target) <= 0 {
- mixDigest = C.GoBytes(unsafe.Pointer(&ret.mix_hash), C.int(32))
- atomic.AddInt32(&pow.hashRate, -previousHashrate)
- return nonce, mixDigest
- }
- nonce += 1
- }
-
- if !pow.turbo {
- time.Sleep(20 * time.Microsecond)
- }
- }
-}
-
-func (pow *Full) GetHashrate() int64 {
- return int64(atomic.LoadInt32(&pow.hashRate))
-}
-
-func (pow *Full) Turbo(on bool) {
- // TODO: this needs to use an atomic operation.
- pow.turbo = on
-}
-
-// Ethash combines block verification with Light and
-// nonce searching with Full into a single proof of work.
-type Ethash struct {
- *Light
- *Full
-}
-
-// New creates an instance of the proof of work.
-func New() *Ethash {
- return &Ethash{new(Light), &Full{turbo: true}}
-}
-
-// NewShared creates an instance of the proof of work., where a single instance
-// of the Light cache is shared across all instances created with NewShared.
-func NewShared() *Ethash {
- return &Ethash{sharedLight, &Full{turbo: true}}
-}
-
-// NewForTesting creates a proof of work for use in unit tests.
-// It uses a smaller DAG and cache size to keep test times low.
-// DAG files are stored in a temporary directory.
-//
-// Nonces found by a testing instance are not verifiable with a
-// regular-size cache.
-func NewForTesting() (*Ethash, error) {
- dir, err := ioutil.TempDir("", "ethash-test")
- if err != nil {
- return nil, err
- }
- return &Ethash{&Light{test: true}, &Full{Dir: dir, test: true}}, nil
-}
-
-func GetSeedHash(blockNum uint64) ([]byte, error) {
- if blockNum >= epochLength*2048 {
- return nil, fmt.Errorf("block number too high, limit is %d", epochLength*2048)
- }
- sh := makeSeedHash(blockNum / epochLength)
- return sh[:], nil
-}
-
-func makeSeedHash(epoch uint64) (sh common.Hash) {
- for ; epoch > 0; epoch-- {
- sh = crypto.Sha3Hash(sh[:])
- }
- return sh
-}
diff --git a/vendor/github.com/ethereum/ethash/ethashc.go b/vendor/github.com/ethereum/ethash/ethashc.go
deleted file mode 100644
index 1d2ba16132..0000000000
--- a/vendor/github.com/ethereum/ethash/ethashc.go
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright 2015 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see .
-
-package ethash
-
-/*
- -mno-stack-arg-probe disables stack probing which avoids the function
- __chkstk_ms being linked. this avoids a clash of this symbol as we also
- separately link the secp256k1 lib which ends up defining this symbol
-
- 1. https://gcc.gnu.org/onlinedocs/gccint/Stack-Checking.html
- 2. https://groups.google.com/forum/#!msg/golang-dev/v1bziURSQ4k/88fXuJ24e-gJ
- 3. https://groups.google.com/forum/#!topic/golang-nuts/VNP6Mwz_B6o
-
-*/
-
-/*
-#cgo CFLAGS: -std=gnu99 -Wall
-#cgo windows CFLAGS: -mno-stack-arg-probe
-#cgo LDFLAGS: -lm
-
-#include "src/libethash/internal.c"
-#include "src/libethash/sha3.c"
-#include "src/libethash/io.c"
-
-#ifdef _WIN32
-# include "src/libethash/io_win32.c"
-# include "src/libethash/mmap_win32.c"
-#else
-# include "src/libethash/io_posix.c"
-#endif
-
-// 'gateway function' for calling back into go.
-extern int ethashGoCallback(unsigned);
-int ethashGoCallback_cgo(unsigned percent) { return ethashGoCallback(percent); }
-
-*/
-import "C"
diff --git a/vendor/github.com/ethereum/ethash/setup.py b/vendor/github.com/ethereum/ethash/setup.py
deleted file mode 100755
index 18aa20f6db..0000000000
--- a/vendor/github.com/ethereum/ethash/setup.py
+++ /dev/null
@@ -1,47 +0,0 @@
-#!/usr/bin/env python
-import os
-from distutils.core import setup, Extension
-sources = [
- 'src/python/core.c',
- 'src/libethash/io.c',
- 'src/libethash/internal.c',
- 'src/libethash/sha3.c']
-if os.name == 'nt':
- sources += [
- 'src/libethash/util_win32.c',
- 'src/libethash/io_win32.c',
- 'src/libethash/mmap_win32.c',
- ]
-else:
- sources += [
- 'src/libethash/io_posix.c'
- ]
-depends = [
- 'src/libethash/ethash.h',
- 'src/libethash/compiler.h',
- 'src/libethash/data_sizes.h',
- 'src/libethash/endian.h',
- 'src/libethash/ethash.h',
- 'src/libethash/io.h',
- 'src/libethash/fnv.h',
- 'src/libethash/internal.h',
- 'src/libethash/sha3.h',
- 'src/libethash/util.h',
-]
-pyethash = Extension('pyethash',
- sources=sources,
- depends=depends,
- extra_compile_args=["-Isrc/", "-std=gnu99", "-Wall"])
-
-setup(
- name='pyethash',
- author="Matthew Wampler-Doty",
- author_email="matthew.wampler.doty@gmail.com",
- license='GPL',
- version='0.1.23',
- url='https://github.com/ethereum/ethash',
- download_url='https://github.com/ethereum/ethash/tarball/v23',
- description=('Python wrappers for ethash, the ethereum proof of work'
- 'hashing function'),
- ext_modules=[pyethash],
-)
diff --git a/vendor/github.com/fatih/color/.travis.yml b/vendor/github.com/fatih/color/.travis.yml
deleted file mode 100644
index 57b4b57c82..0000000000
--- a/vendor/github.com/fatih/color/.travis.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-language: go
-go:
- - 1.6
- - tip
-
diff --git a/vendor/github.com/fatih/color/README.md b/vendor/github.com/fatih/color/README.md
index 7c8eea20e3..25abbca3f8 100644
--- a/vendor/github.com/fatih/color/README.md
+++ b/vendor/github.com/fatih/color/README.md
@@ -87,7 +87,7 @@ blue(myWriter, "important notice: %s", stars)
// Mix up with multiple attributes
success := color.New(color.Bold, color.FgGreen).FprintlnFunc()
-success(myWriter, don't forget this...")
+success(myWriter, "Don't forget this...")
```
### Insert into noncolor strings (SprintFunc)
diff --git a/vendor/github.com/fatih/color/color.go b/vendor/github.com/fatih/color/color.go
index dba8f211e4..34cd8e4c8a 100644
--- a/vendor/github.com/fatih/color/color.go
+++ b/vendor/github.com/fatih/color/color.go
@@ -247,6 +247,21 @@ func (c *Color) Println(a ...interface{}) (n int, err error) {
return fmt.Fprintln(Output, a...)
}
+// Sprint is just like Print, but returns a string instead of printing it.
+func (c *Color) Sprint(a ...interface{}) string {
+ return c.wrap(fmt.Sprint(a...))
+}
+
+// Sprintln is just like Println, but returns a string instead of printing it.
+func (c *Color) Sprintln(a ...interface{}) string {
+ return c.wrap(fmt.Sprintln(a...))
+}
+
+// Sprintf is just like Printf, but returns a string instead of printing it.
+func (c *Color) Sprintf(format string, a ...interface{}) string {
+ return c.wrap(fmt.Sprintf(format, a...))
+}
+
// FprintFunc returns a new function that prints the passed arguments as
// colorized with color.Fprint().
func (c *Color) FprintFunc() func(w io.Writer, a ...interface{}) {
diff --git a/vendor/github.com/gizak/termui/.gitignore b/vendor/github.com/gizak/termui/.gitignore
deleted file mode 100644
index 8b156b0202..0000000000
--- a/vendor/github.com/gizak/termui/.gitignore
+++ /dev/null
@@ -1,26 +0,0 @@
-# Compiled Object files, Static and Dynamic libs (Shared Objects)
-*.o
-*.a
-*.so
-
-# Folders
-_obj
-_test
-
-# Architecture specific extensions/prefixes
-*.[568vq]
-[568vq].out
-
-*.cgo1.go
-*.cgo2.c
-_cgo_defun.c
-_cgo_gotypes.go
-_cgo_export.*
-
-_testmain.go
-
-*.exe
-*.test
-*.prof
-.DS_Store
-/vendor
diff --git a/vendor/github.com/gizak/termui/.travis.yml b/vendor/github.com/gizak/termui/.travis.yml
deleted file mode 100644
index 206e887409..0000000000
--- a/vendor/github.com/gizak/termui/.travis.yml
+++ /dev/null
@@ -1,6 +0,0 @@
-language: go
-
-go:
- - tip
-
-script: go test -v ./
\ No newline at end of file
diff --git a/vendor/github.com/gizak/termui/README.md b/vendor/github.com/gizak/termui/README.md
index 4f3d4a4192..d5f3d9a8f1 100644
--- a/vendor/github.com/gizak/termui/README.md
+++ b/vendor/github.com/gizak/termui/README.md
@@ -131,6 +131,7 @@ Click image to see the corresponding demo codes.
[
](https://github.com/gizak/termui/blob/master/_example/barchart.go)
[
](https://github.com/gizak/termui/blob/master/_example/mbarchart.go)
[
](https://github.com/gizak/termui/blob/master/_example/sparklines.go)
+[
](https://github.com/gizak/termui/blob/master/_example/table.go)
## GoDoc
diff --git a/vendor/github.com/gizak/termui/barchart.go b/vendor/github.com/gizak/termui/barchart.go
index 1102f3416e..6560c8b14e 100644
--- a/vendor/github.com/gizak/termui/barchart.go
+++ b/vendor/github.com/gizak/termui/barchart.go
@@ -1,4 +1,4 @@
-// Copyright 2016 Zack Guo . All rights reserved.
+// Copyright 2017 Zack Guo . All rights reserved.
// Use of this source code is governed by a MIT license that can
// be found in the LICENSE file.
diff --git a/vendor/github.com/gizak/termui/block.go b/vendor/github.com/gizak/termui/block.go
index 43a4c4039b..3e8571bc23 100644
--- a/vendor/github.com/gizak/termui/block.go
+++ b/vendor/github.com/gizak/termui/block.go
@@ -1,4 +1,4 @@
-// Copyright 2016 Zack Guo . All rights reserved.
+// Copyright 2017 Zack Guo . All rights reserved.
// Use of this source code is governed by a MIT license that can
// be found in the LICENSE file.
diff --git a/vendor/github.com/gizak/termui/block_common.go b/vendor/github.com/gizak/termui/block_common.go
index aa4a92a7dd..6438bf217d 100644
--- a/vendor/github.com/gizak/termui/block_common.go
+++ b/vendor/github.com/gizak/termui/block_common.go
@@ -1,4 +1,4 @@
-// Copyright 2016 Zack Guo . All rights reserved.
+// Copyright 2017 Zack Guo . All rights reserved.
// Use of this source code is governed by a MIT license that can
// be found in the LICENSE file.
diff --git a/vendor/github.com/gizak/termui/block_windows.go b/vendor/github.com/gizak/termui/block_windows.go
index 50480e55b3..a4fba77d7c 100644
--- a/vendor/github.com/gizak/termui/block_windows.go
+++ b/vendor/github.com/gizak/termui/block_windows.go
@@ -1,4 +1,4 @@
-// Copyright 2016 Zack Guo . All rights reserved.
+// Copyright 2017 Zack Guo . All rights reserved.
// Use of this source code is governed by a MIT license that can
// be found in the LICENSE file.
diff --git a/vendor/github.com/gizak/termui/buffer.go b/vendor/github.com/gizak/termui/buffer.go
index cbbab6f501..9e3a97345d 100644
--- a/vendor/github.com/gizak/termui/buffer.go
+++ b/vendor/github.com/gizak/termui/buffer.go
@@ -1,4 +1,4 @@
-// Copyright 2016 Zack Guo . All rights reserved.
+// Copyright 2017 Zack Guo . All rights reserved.
// Use of this source code is governed by a MIT license that can
// be found in the LICENSE file.
diff --git a/vendor/github.com/gizak/termui/canvas.go b/vendor/github.com/gizak/termui/canvas.go
index 911a6787f2..6d2513ebd4 100644
--- a/vendor/github.com/gizak/termui/canvas.go
+++ b/vendor/github.com/gizak/termui/canvas.go
@@ -1,4 +1,4 @@
-// Copyright 2016 Zack Guo . All rights reserved.
+// Copyright 2017 Zack Guo . All rights reserved.
// Use of this source code is governed by a MIT license that can
// be found in the LICENSE file.
diff --git a/vendor/github.com/gizak/termui/config.py b/vendor/github.com/gizak/termui/config.py
index 9152bf517c..30fadcf868 100644
--- a/vendor/github.com/gizak/termui/config.py
+++ b/vendor/github.com/gizak/termui/config.py
@@ -1,35 +1,10 @@
#!/usr/bin/env python3
-# use v6;
-#
-# my $copyright = '// Copyright 2016 Zack Guo . All rights reserved.
-# // Use of this source code is governed by a MIT license that can
-# // be found in the LICENSE file.
-#
-# ';
-#
-# sub MAIN('update-docstr', Str $srcp) {
-# if $srcp.IO.f {
-# $_ = $srcp.IO.slurp;
-# if m/^ \/\/\s Copyright .+? \n\n/ {
-# unless ~$/ eq $copyright {
-# s/^ \/\/\s Copyright .+? \n\n /$copyright/;
-# spurt $srcp, $_;
-# say "[updated] doc string for:"~$srcp;
-# }
-# } else {
-# say "[added] doc string for "~$srcp~" (no match found)";
-# $_ = $copyright ~ $_;
-# spurt $srcp, $_;
-# }
-# }
-# }
-
import re
import os
import io
-copyright = """// Copyright 2016 Zack Guo . All rights reserved.
+copyright = """// Copyright 2017 Zack Guo . All rights reserved.
// Use of this source code is governed by a MIT license that can
// be found in the LICENSE file.
diff --git a/vendor/github.com/gizak/termui/doc.go b/vendor/github.com/gizak/termui/doc.go
index fdf7dd079a..13924eb1f7 100644
--- a/vendor/github.com/gizak/termui/doc.go
+++ b/vendor/github.com/gizak/termui/doc.go
@@ -1,4 +1,4 @@
-// Copyright 2016 Zack Guo . All rights reserved.
+// Copyright 2017 Zack Guo . All rights reserved.
// Use of this source code is governed by a MIT license that can
// be found in the LICENSE file.
diff --git a/vendor/github.com/gizak/termui/events.go b/vendor/github.com/gizak/termui/events.go
index 5ba5263c02..16d9bd9cc3 100644
--- a/vendor/github.com/gizak/termui/events.go
+++ b/vendor/github.com/gizak/termui/events.go
@@ -1,4 +1,4 @@
-// Copyright 2016 Zack Guo . All rights reserved.
+// Copyright 2017 Zack Guo . All rights reserved.
// Use of this source code is governed by a MIT license that can
// be found in the LICENSE file.
@@ -221,6 +221,7 @@ func findMatch(mux map[string]func(Event), path string) string {
return pattern
}
+
// Remove all existing defined Handlers from the map
func (es *EvtStream) ResetHandlers() {
for Path, _ := range es.Handlers {
@@ -309,7 +310,7 @@ func NewTimerCh(du time.Duration) chan Event {
return t
}
-var DefualtHandler = func(e Event) {
+var DefaultHandler = func(e Event) {
}
var usrEvtCh = make(chan Event)
diff --git a/vendor/github.com/gizak/termui/gauge.go b/vendor/github.com/gizak/termui/gauge.go
index a143111ea5..9f6ce3a706 100644
--- a/vendor/github.com/gizak/termui/gauge.go
+++ b/vendor/github.com/gizak/termui/gauge.go
@@ -1,4 +1,4 @@
-// Copyright 2016 Zack Guo . All rights reserved.
+// Copyright 2017 Zack Guo . All rights reserved.
// Use of this source code is governed by a MIT license that can
// be found in the LICENSE file.
diff --git a/vendor/github.com/gizak/termui/grid.go b/vendor/github.com/gizak/termui/grid.go
index 679b825b70..a950232253 100644
--- a/vendor/github.com/gizak/termui/grid.go
+++ b/vendor/github.com/gizak/termui/grid.go
@@ -1,4 +1,4 @@
-// Copyright 2016 Zack Guo . All rights reserved.
+// Copyright 2017 Zack Guo . All rights reserved.
// Use of this source code is governed by a MIT license that can
// be found in the LICENSE file.
diff --git a/vendor/github.com/gizak/termui/helper.go b/vendor/github.com/gizak/termui/helper.go
index 5870bac947..18a6770435 100644
--- a/vendor/github.com/gizak/termui/helper.go
+++ b/vendor/github.com/gizak/termui/helper.go
@@ -1,4 +1,4 @@
-// Copyright 2016 Zack Guo . All rights reserved.
+// Copyright 2017 Zack Guo . All rights reserved.
// Use of this source code is governed by a MIT license that can
// be found in the LICENSE file.
diff --git a/vendor/github.com/gizak/termui/linechart.go b/vendor/github.com/gizak/termui/linechart.go
index 1886114961..f7eea28bbe 100644
--- a/vendor/github.com/gizak/termui/linechart.go
+++ b/vendor/github.com/gizak/termui/linechart.go
@@ -1,4 +1,4 @@
-// Copyright 2016 Zack Guo . All rights reserved.
+// Copyright 2017 Zack Guo . All rights reserved.
// Use of this source code is governed by a MIT license that can
// be found in the LICENSE file.
diff --git a/vendor/github.com/gizak/termui/linechart_others.go b/vendor/github.com/gizak/termui/linechart_others.go
index fad7a80b17..14897ea0f8 100644
--- a/vendor/github.com/gizak/termui/linechart_others.go
+++ b/vendor/github.com/gizak/termui/linechart_others.go
@@ -1,4 +1,4 @@
-// Copyright 2016 Zack Guo . All rights reserved.
+// Copyright 2017 Zack Guo . All rights reserved.
// Use of this source code is governed by a MIT license that can
// be found in the LICENSE file.
diff --git a/vendor/github.com/gizak/termui/linechart_windows.go b/vendor/github.com/gizak/termui/linechart_windows.go
index 9c9917ba87..994d3e5900 100644
--- a/vendor/github.com/gizak/termui/linechart_windows.go
+++ b/vendor/github.com/gizak/termui/linechart_windows.go
@@ -1,4 +1,4 @@
-// Copyright 2016 Zack Guo . All rights reserved.
+// Copyright 2017 Zack Guo . All rights reserved.
// Use of this source code is governed by a MIT license that can
// be found in the LICENSE file.
diff --git a/vendor/github.com/gizak/termui/list.go b/vendor/github.com/gizak/termui/list.go
index 492b62d543..ea6635eccc 100644
--- a/vendor/github.com/gizak/termui/list.go
+++ b/vendor/github.com/gizak/termui/list.go
@@ -1,4 +1,4 @@
-// Copyright 2016 Zack Guo . All rights reserved.
+// Copyright 2017 Zack Guo . All rights reserved.
// Use of this source code is governed by a MIT license that can
// be found in the LICENSE file.
diff --git a/vendor/github.com/gizak/termui/mbarchart.go b/vendor/github.com/gizak/termui/mbarchart.go
index fa6d54ca1d..0f91e9713f 100644
--- a/vendor/github.com/gizak/termui/mbarchart.go
+++ b/vendor/github.com/gizak/termui/mbarchart.go
@@ -1,4 +1,4 @@
-// Copyright 2016 Zack Guo . All rights reserved.
+// Copyright 2017 Zack Guo . All rights reserved.
// Use of this source code is governed by a MIT license that can
// be found in the LICENSE file.
diff --git a/vendor/github.com/gizak/termui/par.go b/vendor/github.com/gizak/termui/par.go
index 14d6b4d346..29b6d462f9 100644
--- a/vendor/github.com/gizak/termui/par.go
+++ b/vendor/github.com/gizak/termui/par.go
@@ -1,4 +1,4 @@
-// Copyright 2016 Zack Guo . All rights reserved.
+// Copyright 2017 Zack Guo . All rights reserved.
// Use of this source code is governed by a MIT license that can
// be found in the LICENSE file.
diff --git a/vendor/github.com/gizak/termui/pos.go b/vendor/github.com/gizak/termui/pos.go
index a0359af7c2..c7d647f31b 100644
--- a/vendor/github.com/gizak/termui/pos.go
+++ b/vendor/github.com/gizak/termui/pos.go
@@ -1,4 +1,4 @@
-// Copyright 2016 Zack Guo . All rights reserved.
+// Copyright 2017 Zack Guo . All rights reserved.
// Use of this source code is governed by a MIT license that can
// be found in the LICENSE file.
diff --git a/vendor/github.com/gizak/termui/render.go b/vendor/github.com/gizak/termui/render.go
index be3bf464e6..b9d37d9386 100644
--- a/vendor/github.com/gizak/termui/render.go
+++ b/vendor/github.com/gizak/termui/render.go
@@ -1,4 +1,4 @@
-// Copyright 2016 Zack Guo . All rights reserved.
+// Copyright 2017 Zack Guo . All rights reserved.
// Use of this source code is governed by a MIT license that can
// be found in the LICENSE file.
@@ -51,7 +51,7 @@ func Init() error {
DefaultEvtStream.Merge("timer", NewTimerCh(time.Second))
DefaultEvtStream.Merge("custom", usrEvtCh)
- DefaultEvtStream.Handle("/", DefualtHandler)
+ DefaultEvtStream.Handle("/", DefaultHandler)
DefaultEvtStream.Handle("/sys/wnd/resize", func(e Event) {
w := e.Data.(EvtWnd)
Body.Width = w.Width
diff --git a/vendor/github.com/gizak/termui/sparkline.go b/vendor/github.com/gizak/termui/sparkline.go
index e127b52e13..d906e49dfc 100644
--- a/vendor/github.com/gizak/termui/sparkline.go
+++ b/vendor/github.com/gizak/termui/sparkline.go
@@ -1,4 +1,4 @@
-// Copyright 2016 Zack Guo . All rights reserved.
+// Copyright 2017 Zack Guo . All rights reserved.
// Use of this source code is governed by a MIT license that can
// be found in the LICENSE file.
diff --git a/vendor/github.com/gizak/termui/table.go b/vendor/github.com/gizak/termui/table.go
index 319b897014..e3d1bbf309 100644
--- a/vendor/github.com/gizak/termui/table.go
+++ b/vendor/github.com/gizak/termui/table.go
@@ -1,10 +1,32 @@
+// Copyright 2017 Zack Guo . All rights reserved.
+// Use of this source code is governed by a MIT license that can
+// be found in the LICENSE file.
+
package termui
import "strings"
-/*
+/* Table is like:
+
+┌Awesome Table ────────────────────────────────────────────────┐
+│ Col0 | Col1 | Col2 | Col3 | Col4 | Col5 | Col6 |
+│──────────────────────────────────────────────────────────────│
+│ Some Item #1 | AAA | 123 | CCCCC | EEEEE | GGGGG | IIIII |
+│──────────────────────────────────────────────────────────────│
+│ Some Item #2 | BBB | 456 | DDDDD | FFFFF | HHHHH | JJJJJ |
+└──────────────────────────────────────────────────────────────┘
+
+Datapoints are a two dimensional array of strings: [][]string
+
+Example:
+ data := [][]string{
+ {"Col0", "Col1", "Col3", "Col4", "Col5", "Col6"},
+ {"Some Item #1", "AAA", "123", "CCCCC", "EEEEE", "GGGGG", "IIIII"},
+ {"Some Item #2", "BBB", "456", "DDDDD", "FFFFF", "HHHHH", "JJJJJ"},
+ }
+
table := termui.NewTable()
- table.Rows = rows
+ table.Rows = data // type [][]string
table.FgColor = termui.ColorWhite
table.BgColor = termui.ColorDefault
table.Height = 7
@@ -14,6 +36,7 @@ import "strings"
table.Border = true
*/
+// Table tracks all the attributes of a Table instance
type Table struct {
Block
Rows [][]string
@@ -22,22 +45,34 @@ type Table struct {
BgColor Attribute
FgColors []Attribute
BgColors []Attribute
- Seperator bool
+ Separator bool
TextAlign Align
}
+// NewTable returns a new Table instance
func NewTable() *Table {
table := &Table{Block: *NewBlock()}
table.FgColor = ColorWhite
table.BgColor = ColorDefault
- table.Seperator = true
+ table.Separator = true
return table
}
-func (table *Table) Analysis() {
+// CellsWidth calculates the width of a cell array and returns an int
+func cellsWidth(cells []Cell) int {
+ width := 0
+ for _, c := range cells {
+ width += c.Width()
+ }
+ return width
+}
+
+// Analysis generates and returns an array of []Cell that represent all columns in the Table
+func (table *Table) Analysis() [][]Cell {
+ var rowCells [][]Cell
length := len(table.Rows)
if length < 1 {
- return
+ return rowCells
}
if len(table.FgColors) == 0 {
@@ -47,121 +82,101 @@ func (table *Table) Analysis() {
table.BgColors = make([]Attribute, len(table.Rows))
}
- row_width := len(table.Rows[0])
- cellWidthes := make([]int, row_width)
+ cellWidths := make([]int, len(table.Rows[0]))
- for index, row := range table.Rows {
- for i, str := range row {
- if cellWidthes[i] < len(str) {
- cellWidthes[i] = len(str)
+ for y, row := range table.Rows {
+ if table.FgColors[y] == 0 {
+ table.FgColors[y] = table.FgColor
+ }
+ if table.BgColors[y] == 0 {
+ table.BgColors[y] = table.BgColor
+ }
+ for x, str := range row {
+ cells := DefaultTxBuilder.Build(str, table.FgColors[y], table.BgColors[y])
+ cw := cellsWidth(cells)
+ if cellWidths[x] < cw {
+ cellWidths[x] = cw
}
- }
-
- if table.FgColors[index] == 0 {
- table.FgColors[index] = table.FgColor
- }
-
- if table.BgColors[index] == 0 {
- table.BgColors[index] = table.BgColor
+ rowCells = append(rowCells, cells)
}
}
-
- table.CellWidth = cellWidthes
-
- //width_sum := 2
- //for i, width := range cellWidthes {
- // width_sum += (width + 2)
- // for u, row := range table.Rows {
- // switch table.TextAlign {
- // case "right":
- // row[i] = fmt.Sprintf(" %*s ", width, table.Rows[u][i])
- // case "center":
- // word_width := len(table.Rows[u][i])
- // offset := (width - word_width) / 2
- // row[i] = fmt.Sprintf(" %*s ", width, fmt.Sprintf("%-*s", offset+word_width, table.Rows[u][i]))
- // default: // left
- // row[i] = fmt.Sprintf(" %-*s ", width, table.Rows[u][i])
- // }
- // }
- //}
-
- //if table.Width == 0 {
- // table.Width = width_sum
- //}
+ table.CellWidth = cellWidths
+ return rowCells
}
+// SetSize calculates the table size and sets the internal value
func (table *Table) SetSize() {
length := len(table.Rows)
- if table.Seperator {
+ if table.Separator {
table.Height = length*2 + 1
} else {
table.Height = length + 2
}
table.Width = 2
if length != 0 {
- for _, cell_width := range table.CellWidth {
- table.Width += cell_width + 3
+ for _, cellWidth := range table.CellWidth {
+ table.Width += cellWidth + 3
}
}
}
-func (table *Table) CalculatePosition(x int, y int, x_coordinate *int, y_coordibate *int, cell_beginning *int) {
- if table.Seperator {
- *y_coordibate = table.innerArea.Min.Y + y*2
+// CalculatePosition ...
+func (table *Table) CalculatePosition(x int, y int, coordinateX *int, coordinateY *int, cellStart *int) {
+ if table.Separator {
+ *coordinateY = table.innerArea.Min.Y + y*2
} else {
- *y_coordibate = table.innerArea.Min.Y + y
+ *coordinateY = table.innerArea.Min.Y + y
}
if x == 0 {
- *cell_beginning = table.innerArea.Min.X
+ *cellStart = table.innerArea.Min.X
} else {
- *cell_beginning += table.CellWidth[x-1] + 3
+ *cellStart += table.CellWidth[x-1] + 3
}
switch table.TextAlign {
case AlignRight:
- *x_coordinate = *cell_beginning + (table.CellWidth[x] - len(table.Rows[y][x])) + 2
+ *coordinateX = *cellStart + (table.CellWidth[x] - len(table.Rows[y][x])) + 2
case AlignCenter:
- *x_coordinate = *cell_beginning + (table.CellWidth[x]-len(table.Rows[y][x]))/2 + 2
+ *coordinateX = *cellStart + (table.CellWidth[x]-len(table.Rows[y][x]))/2 + 2
default:
- *x_coordinate = *cell_beginning + 2
+ *coordinateX = *cellStart + 2
}
}
+// Buffer ...
func (table *Table) Buffer() Buffer {
buffer := table.Block.Buffer()
- table.Analysis()
-
- pointer_x := table.innerArea.Min.X + 2
- pointer_y := table.innerArea.Min.Y
- border_pointer_x := table.innerArea.Min.X
+ rowCells := table.Analysis()
+ pointerX := table.innerArea.Min.X + 2
+ pointerY := table.innerArea.Min.Y
+ borderPointerX := table.innerArea.Min.X
for y, row := range table.Rows {
- for x, cell := range row {
- table.CalculatePosition(x, y, &pointer_x, &pointer_y, &border_pointer_x)
- backgraound := DefaultTxBuilder.Build(strings.Repeat(" ", table.CellWidth[x]+3), table.BgColors[y], table.BgColors[y])
- cells := DefaultTxBuilder.Build(cell, table.FgColors[y], table.BgColors[y])
-
- for i, back := range backgraound {
- buffer.Set(border_pointer_x+i, pointer_y, back)
+ for x := range row {
+ table.CalculatePosition(x, y, &pointerX, &pointerY, &borderPointerX)
+ background := DefaultTxBuilder.Build(strings.Repeat(" ", table.CellWidth[x]+3), table.BgColors[y], table.BgColors[y])
+ cells := rowCells[y*len(row)+x]
+ for i, back := range background {
+ buffer.Set(borderPointerX+i, pointerY, back)
}
- coordinate_x := pointer_x
+ coordinateX := pointerX
for _, printer := range cells {
- buffer.Set(coordinate_x, pointer_y, printer)
- coordinate_x += printer.Width()
+ buffer.Set(coordinateX, pointerY, printer)
+ coordinateX += printer.Width()
}
if x != 0 {
- devidors := DefaultTxBuilder.Build("|", table.FgColors[y], table.BgColors[y])
- for _, devidor := range devidors {
- buffer.Set(border_pointer_x, pointer_y, devidor)
+ dividors := DefaultTxBuilder.Build("|", table.FgColors[y], table.BgColors[y])
+ for _, dividor := range dividors {
+ buffer.Set(borderPointerX, pointerY, dividor)
}
}
}
- if table.Seperator {
+ if table.Separator {
border := DefaultTxBuilder.Build(strings.Repeat("─", table.Width-2), table.FgColor, table.BgColor)
for i, cell := range border {
- buffer.Set(i+1, pointer_y+1, cell)
+ buffer.Set(i+1, pointerY+1, cell)
}
}
}
diff --git a/vendor/github.com/gizak/termui/textbuilder.go b/vendor/github.com/gizak/termui/textbuilder.go
index 818a40022f..12e2055b50 100644
--- a/vendor/github.com/gizak/termui/textbuilder.go
+++ b/vendor/github.com/gizak/termui/textbuilder.go
@@ -1,4 +1,4 @@
-// Copyright 2016 Zack Guo . All rights reserved.
+// Copyright 2017 Zack Guo . All rights reserved.
// Use of this source code is governed by a MIT license that can
// be found in the LICENSE file.
diff --git a/vendor/github.com/gizak/termui/theme.go b/vendor/github.com/gizak/termui/theme.go
index 9632ae791c..21fb3bfb75 100644
--- a/vendor/github.com/gizak/termui/theme.go
+++ b/vendor/github.com/gizak/termui/theme.go
@@ -1,4 +1,4 @@
-// Copyright 2016 Zack Guo . All rights reserved.
+// Copyright 2017 Zack Guo . All rights reserved.
// Use of this source code is governed by a MIT license that can
// be found in the LICENSE file.
diff --git a/vendor/github.com/gizak/termui/widget.go b/vendor/github.com/gizak/termui/widget.go
index f14aa8602c..80276bf1f1 100644
--- a/vendor/github.com/gizak/termui/widget.go
+++ b/vendor/github.com/gizak/termui/widget.go
@@ -1,4 +1,4 @@
-// Copyright 2016 Zack Guo . All rights reserved.
+// Copyright 2017 Zack Guo . All rights reserved.
// Use of this source code is governed by a MIT license that can
// be found in the LICENSE file.
diff --git a/vendor/github.com/go-stack/stack/LICENSE.md b/vendor/github.com/go-stack/stack/LICENSE.md
new file mode 100644
index 0000000000..c8ca66c5ed
--- /dev/null
+++ b/vendor/github.com/go-stack/stack/LICENSE.md
@@ -0,0 +1,13 @@
+Copyright 2014 Chris Hines
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/vendor/github.com/go-stack/stack/README.md b/vendor/github.com/go-stack/stack/README.md
new file mode 100644
index 0000000000..f11ccccaa4
--- /dev/null
+++ b/vendor/github.com/go-stack/stack/README.md
@@ -0,0 +1,38 @@
+[](https://godoc.org/github.com/go-stack/stack)
+[](https://goreportcard.com/report/go-stack/stack)
+[](https://travis-ci.org/go-stack/stack)
+[](https://coveralls.io/github/go-stack/stack?branch=master)
+
+# stack
+
+Package stack implements utilities to capture, manipulate, and format call
+stacks. It provides a simpler API than package runtime.
+
+The implementation takes care of the minutia and special cases of interpreting
+the program counter (pc) values returned by runtime.Callers.
+
+## Versioning
+
+Package stack publishes releases via [semver](http://semver.org/) compatible Git
+tags prefixed with a single 'v'. The master branch always contains the latest
+release. The develop branch contains unreleased commits.
+
+## Formatting
+
+Package stack's types implement fmt.Formatter, which provides a simple and
+flexible way to declaratively configure formatting when used with logging or
+error tracking packages.
+
+```go
+func DoTheThing() {
+ c := stack.Caller(0)
+ log.Print(c) // "source.go:10"
+ log.Printf("%+v", c) // "pkg/path/source.go:10"
+ log.Printf("%n", c) // "DoTheThing"
+
+ s := stack.Trace().TrimRuntime()
+ log.Print(s) // "[source.go:15 caller.go:42 main.go:14]"
+}
+```
+
+See the docs for all of the supported formatting options.
diff --git a/vendor/github.com/go-stack/stack/stack.go b/vendor/github.com/go-stack/stack/stack.go
new file mode 100644
index 0000000000..a614eeebf1
--- /dev/null
+++ b/vendor/github.com/go-stack/stack/stack.go
@@ -0,0 +1,349 @@
+// Package stack implements utilities to capture, manipulate, and format call
+// stacks. It provides a simpler API than package runtime.
+//
+// The implementation takes care of the minutia and special cases of
+// interpreting the program counter (pc) values returned by runtime.Callers.
+//
+// Package stack's types implement fmt.Formatter, which provides a simple and
+// flexible way to declaratively configure formatting when used with logging
+// or error tracking packages.
+package stack
+
+import (
+ "bytes"
+ "errors"
+ "fmt"
+ "io"
+ "runtime"
+ "strconv"
+ "strings"
+)
+
+// Call records a single function invocation from a goroutine stack.
+type Call struct {
+ fn *runtime.Func
+ pc uintptr
+}
+
+// Caller returns a Call from the stack of the current goroutine. The argument
+// skip is the number of stack frames to ascend, with 0 identifying the
+// calling function.
+func Caller(skip int) Call {
+ var pcs [2]uintptr
+ n := runtime.Callers(skip+1, pcs[:])
+
+ var c Call
+
+ if n < 2 {
+ return c
+ }
+
+ c.pc = pcs[1]
+ if runtime.FuncForPC(pcs[0]) != sigpanic {
+ c.pc--
+ }
+ c.fn = runtime.FuncForPC(c.pc)
+ return c
+}
+
+// String implements fmt.Stinger. It is equivalent to fmt.Sprintf("%v", c).
+func (c Call) String() string {
+ return fmt.Sprint(c)
+}
+
+// MarshalText implements encoding.TextMarshaler. It formats the Call the same
+// as fmt.Sprintf("%v", c).
+func (c Call) MarshalText() ([]byte, error) {
+ if c.fn == nil {
+ return nil, ErrNoFunc
+ }
+ buf := bytes.Buffer{}
+ fmt.Fprint(&buf, c)
+ return buf.Bytes(), nil
+}
+
+// ErrNoFunc means that the Call has a nil *runtime.Func. The most likely
+// cause is a Call with the zero value.
+var ErrNoFunc = errors.New("no call stack information")
+
+// Format implements fmt.Formatter with support for the following verbs.
+//
+// %s source file
+// %d line number
+// %n function name
+// %v equivalent to %s:%d
+//
+// It accepts the '+' and '#' flags for most of the verbs as follows.
+//
+// %+s path of source file relative to the compile time GOPATH
+// %#s full path of source file
+// %+n import path qualified function name
+// %+v equivalent to %+s:%d
+// %#v equivalent to %#s:%d
+func (c Call) Format(s fmt.State, verb rune) {
+ if c.fn == nil {
+ fmt.Fprintf(s, "%%!%c(NOFUNC)", verb)
+ return
+ }
+
+ switch verb {
+ case 's', 'v':
+ file, line := c.fn.FileLine(c.pc)
+ switch {
+ case s.Flag('#'):
+ // done
+ case s.Flag('+'):
+ file = file[pkgIndex(file, c.fn.Name()):]
+ default:
+ const sep = "/"
+ if i := strings.LastIndex(file, sep); i != -1 {
+ file = file[i+len(sep):]
+ }
+ }
+ io.WriteString(s, file)
+ if verb == 'v' {
+ buf := [7]byte{':'}
+ s.Write(strconv.AppendInt(buf[:1], int64(line), 10))
+ }
+
+ case 'd':
+ _, line := c.fn.FileLine(c.pc)
+ buf := [6]byte{}
+ s.Write(strconv.AppendInt(buf[:0], int64(line), 10))
+
+ case 'n':
+ name := c.fn.Name()
+ if !s.Flag('+') {
+ const pathSep = "/"
+ if i := strings.LastIndex(name, pathSep); i != -1 {
+ name = name[i+len(pathSep):]
+ }
+ const pkgSep = "."
+ if i := strings.Index(name, pkgSep); i != -1 {
+ name = name[i+len(pkgSep):]
+ }
+ }
+ io.WriteString(s, name)
+ }
+}
+
+// PC returns the program counter for this call frame; multiple frames may
+// have the same PC value.
+func (c Call) PC() uintptr {
+ return c.pc
+}
+
+// name returns the import path qualified name of the function containing the
+// call.
+func (c Call) name() string {
+ if c.fn == nil {
+ return "???"
+ }
+ return c.fn.Name()
+}
+
+func (c Call) file() string {
+ if c.fn == nil {
+ return "???"
+ }
+ file, _ := c.fn.FileLine(c.pc)
+ return file
+}
+
+func (c Call) line() int {
+ if c.fn == nil {
+ return 0
+ }
+ _, line := c.fn.FileLine(c.pc)
+ return line
+}
+
+// CallStack records a sequence of function invocations from a goroutine
+// stack.
+type CallStack []Call
+
+// String implements fmt.Stinger. It is equivalent to fmt.Sprintf("%v", cs).
+func (cs CallStack) String() string {
+ return fmt.Sprint(cs)
+}
+
+var (
+ openBracketBytes = []byte("[")
+ closeBracketBytes = []byte("]")
+ spaceBytes = []byte(" ")
+)
+
+// MarshalText implements encoding.TextMarshaler. It formats the CallStack the
+// same as fmt.Sprintf("%v", cs).
+func (cs CallStack) MarshalText() ([]byte, error) {
+ buf := bytes.Buffer{}
+ buf.Write(openBracketBytes)
+ for i, pc := range cs {
+ if pc.fn == nil {
+ return nil, ErrNoFunc
+ }
+ if i > 0 {
+ buf.Write(spaceBytes)
+ }
+ fmt.Fprint(&buf, pc)
+ }
+ buf.Write(closeBracketBytes)
+ return buf.Bytes(), nil
+}
+
+// Format implements fmt.Formatter by printing the CallStack as square brackets
+// ([, ]) surrounding a space separated list of Calls each formatted with the
+// supplied verb and options.
+func (cs CallStack) Format(s fmt.State, verb rune) {
+ s.Write(openBracketBytes)
+ for i, pc := range cs {
+ if i > 0 {
+ s.Write(spaceBytes)
+ }
+ pc.Format(s, verb)
+ }
+ s.Write(closeBracketBytes)
+}
+
+// findSigpanic intentionally executes faulting code to generate a stack trace
+// containing an entry for runtime.sigpanic.
+func findSigpanic() *runtime.Func {
+ var fn *runtime.Func
+ var p *int
+ func() int {
+ defer func() {
+ if p := recover(); p != nil {
+ var pcs [512]uintptr
+ n := runtime.Callers(2, pcs[:])
+ for _, pc := range pcs[:n] {
+ f := runtime.FuncForPC(pc)
+ if f.Name() == "runtime.sigpanic" {
+ fn = f
+ break
+ }
+ }
+ }
+ }()
+ // intentional nil pointer dereference to trigger sigpanic
+ return *p
+ }()
+ return fn
+}
+
+var sigpanic = findSigpanic()
+
+// Trace returns a CallStack for the current goroutine with element 0
+// identifying the calling function.
+func Trace() CallStack {
+ var pcs [512]uintptr
+ n := runtime.Callers(2, pcs[:])
+ cs := make([]Call, n)
+
+ for i, pc := range pcs[:n] {
+ pcFix := pc
+ if i > 0 && cs[i-1].fn != sigpanic {
+ pcFix--
+ }
+ cs[i] = Call{
+ fn: runtime.FuncForPC(pcFix),
+ pc: pcFix,
+ }
+ }
+
+ return cs
+}
+
+// TrimBelow returns a slice of the CallStack with all entries below c
+// removed.
+func (cs CallStack) TrimBelow(c Call) CallStack {
+ for len(cs) > 0 && cs[0].pc != c.pc {
+ cs = cs[1:]
+ }
+ return cs
+}
+
+// TrimAbove returns a slice of the CallStack with all entries above c
+// removed.
+func (cs CallStack) TrimAbove(c Call) CallStack {
+ for len(cs) > 0 && cs[len(cs)-1].pc != c.pc {
+ cs = cs[:len(cs)-1]
+ }
+ return cs
+}
+
+// pkgIndex returns the index that results in file[index:] being the path of
+// file relative to the compile time GOPATH, and file[:index] being the
+// $GOPATH/src/ portion of file. funcName must be the name of a function in
+// file as returned by runtime.Func.Name.
+func pkgIndex(file, funcName string) int {
+ // As of Go 1.6.2 there is no direct way to know the compile time GOPATH
+ // at runtime, but we can infer the number of path segments in the GOPATH.
+ // We note that runtime.Func.Name() returns the function name qualified by
+ // the import path, which does not include the GOPATH. Thus we can trim
+ // segments from the beginning of the file path until the number of path
+ // separators remaining is one more than the number of path separators in
+ // the function name. For example, given:
+ //
+ // GOPATH /home/user
+ // file /home/user/src/pkg/sub/file.go
+ // fn.Name() pkg/sub.Type.Method
+ //
+ // We want to produce:
+ //
+ // file[:idx] == /home/user/src/
+ // file[idx:] == pkg/sub/file.go
+ //
+ // From this we can easily see that fn.Name() has one less path separator
+ // than our desired result for file[idx:]. We count separators from the
+ // end of the file path until it finds two more than in the function name
+ // and then move one character forward to preserve the initial path
+ // segment without a leading separator.
+ const sep = "/"
+ i := len(file)
+ for n := strings.Count(funcName, sep) + 2; n > 0; n-- {
+ i = strings.LastIndex(file[:i], sep)
+ if i == -1 {
+ i = -len(sep)
+ break
+ }
+ }
+ // get back to 0 or trim the leading separator
+ return i + len(sep)
+}
+
+var runtimePath string
+
+func init() {
+ var pcs [1]uintptr
+ runtime.Callers(0, pcs[:])
+ fn := runtime.FuncForPC(pcs[0])
+ file, _ := fn.FileLine(pcs[0])
+
+ idx := pkgIndex(file, fn.Name())
+
+ runtimePath = file[:idx]
+ if runtime.GOOS == "windows" {
+ runtimePath = strings.ToLower(runtimePath)
+ }
+}
+
+func inGoroot(c Call) bool {
+ file := c.file()
+ if len(file) == 0 || file[0] == '?' {
+ return true
+ }
+ if runtime.GOOS == "windows" {
+ file = strings.ToLower(file)
+ }
+ return strings.HasPrefix(file, runtimePath) || strings.HasSuffix(file, "/_testmain.go")
+}
+
+// TrimRuntime returns a slice of the CallStack with the topmost entries from
+// the go runtime removed. It considers any calls originating from unknown
+// files, files under GOROOT, or _testmain.go as part of the runtime.
+func (cs CallStack) TrimRuntime() CallStack {
+ for len(cs) > 0 && inGoroot(cs[len(cs)-1]) {
+ cs = cs[:len(cs)-1]
+ }
+ return cs
+}
diff --git a/vendor/github.com/golang/snappy/.gitignore b/vendor/github.com/golang/snappy/.gitignore
deleted file mode 100644
index 042091d9b3..0000000000
--- a/vendor/github.com/golang/snappy/.gitignore
+++ /dev/null
@@ -1,16 +0,0 @@
-cmd/snappytool/snappytool
-testdata/bench
-
-# These explicitly listed benchmark data files are for an obsolete version of
-# snappy_test.go.
-testdata/alice29.txt
-testdata/asyoulik.txt
-testdata/fireworks.jpeg
-testdata/geo.protodata
-testdata/html
-testdata/html_x_4
-testdata/kppkn.gtb
-testdata/lcet10.txt
-testdata/paper-100k.pdf
-testdata/plrabn12.txt
-testdata/urls.10K
diff --git a/vendor/github.com/golang/snappy/encode.go b/vendor/github.com/golang/snappy/encode.go
index 8749689060..8d393e904b 100644
--- a/vendor/github.com/golang/snappy/encode.go
+++ b/vendor/github.com/golang/snappy/encode.go
@@ -138,7 +138,7 @@ func NewBufferedWriter(w io.Writer) *Writer {
}
}
-// Writer is an io.Writer than can write Snappy-compressed bytes.
+// Writer is an io.Writer that can write Snappy-compressed bytes.
type Writer struct {
w io.Writer
err error
diff --git a/vendor/github.com/golang/snappy/encode_amd64.go b/vendor/github.com/golang/snappy/encode_amd64.go
index 2a56fb504c..150d91bc8b 100644
--- a/vendor/github.com/golang/snappy/encode_amd64.go
+++ b/vendor/github.com/golang/snappy/encode_amd64.go
@@ -26,4 +26,4 @@ func extendMatch(src []byte, i, j int) int
// encodeBlock has the same semantics as in encode_other.go.
//
//go:noescape
-func encodeBlock(dst, src []byte) (d int)
\ No newline at end of file
+func encodeBlock(dst, src []byte) (d int)
diff --git a/vendor/github.com/hashicorp/golang-lru/.gitignore b/vendor/github.com/hashicorp/golang-lru/.gitignore
deleted file mode 100644
index 836562412f..0000000000
--- a/vendor/github.com/hashicorp/golang-lru/.gitignore
+++ /dev/null
@@ -1,23 +0,0 @@
-# Compiled Object files, Static and Dynamic libs (Shared Objects)
-*.o
-*.a
-*.so
-
-# Folders
-_obj
-_test
-
-# Architecture specific extensions/prefixes
-*.[568vq]
-[568vq].out
-
-*.cgo1.go
-*.cgo2.c
-_cgo_defun.c
-_cgo_gotypes.go
-_cgo_export.*
-
-_testmain.go
-
-*.exe
-*.test
diff --git a/vendor/github.com/huin/goupnp/.gitignore b/vendor/github.com/huin/goupnp/.gitignore
deleted file mode 100644
index 09ef375e89..0000000000
--- a/vendor/github.com/huin/goupnp/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-/gotasks/specs
diff --git a/vendor/github.com/jackpal/go-nat-pmp/.travis.yml b/vendor/github.com/jackpal/go-nat-pmp/.travis.yml
deleted file mode 100644
index 9c3f6547da..0000000000
--- a/vendor/github.com/jackpal/go-nat-pmp/.travis.yml
+++ /dev/null
@@ -1,13 +0,0 @@
-language: go
-
-go:
- - 1.6.2
- - tip
-
-allowed_failures:
- - go: tip
-
-install:
- - go get -d -v ./... && go install -race -v ./...
-
-script: go test -race -v ./...
diff --git a/vendor/github.com/karalabe/gousb/.gitignore b/vendor/github.com/karalabe/gousb/.gitignore
deleted file mode 100644
index dbec55fb6f..0000000000
--- a/vendor/github.com/karalabe/gousb/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-*.sw[op]
diff --git a/vendor/github.com/karalabe/gousb/.travis.yml b/vendor/github.com/karalabe/gousb/.travis.yml
deleted file mode 100644
index 2029cc478e..0000000000
--- a/vendor/github.com/karalabe/gousb/.travis.yml
+++ /dev/null
@@ -1,12 +0,0 @@
-language: go
-
-matrix:
- include:
- - os: linux
- dist: trusty
- go: 1.7.4
- - os: osx
- go: 1.7.4
-
-script:
- - go test -v -test.run='BCD|Parse' ./...
diff --git a/vendor/github.com/karalabe/gousb/LICENSE b/vendor/github.com/karalabe/gousb/LICENSE
deleted file mode 100644
index d645695673..0000000000
--- a/vendor/github.com/karalabe/gousb/LICENSE
+++ /dev/null
@@ -1,202 +0,0 @@
-
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
- APPENDIX: How to apply the Apache License to your work.
-
- To apply the Apache License to your work, attach the following
- boilerplate notice, with the fields enclosed by brackets "[]"
- replaced with your own identifying information. (Don't include
- the brackets!) The text should be enclosed in the appropriate
- comment syntax for the file format. We also recommend that a
- file or class name and description of purpose be included on the
- same "printed page" as the copyright notice for easier
- identification within third-party archives.
-
- Copyright [yyyy] [name of copyright owner]
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
diff --git a/vendor/github.com/karalabe/gousb/README.md b/vendor/github.com/karalabe/gousb/README.md
deleted file mode 100644
index 05f3330031..0000000000
--- a/vendor/github.com/karalabe/gousb/README.md
+++ /dev/null
@@ -1,47 +0,0 @@
-Introduction
-============
-
-[![Travis Build Status][travisimg]][travis]
-[![AppVeyor Build Status][appveyorimg]][appveyor]
-[![GoDoc][docimg]][doc]
-
-The gousb package is an attempt at wrapping the `libusb` library into a Go-like binding in a fully self-contained, go-gettable package. Supported platforms include Linux, macOS and Windows as well as the mobile platforms Android and iOS.
-
-This package is a fork of [`github.com/kylelemons/gousb`](https://github.com/kylelemons/gousb), which at the moment seems to be unmaintained. The current fork is different from the upstream package as it contains code to embed `libusb` directly into the Go package (thus becoming fully self-cotnained and go-gettable), as well as it features a few contributions and bugfixes that never really got addressed in the upstream package, but which address important issues nonetheless.
-
-*Note, if @kylelemons decides to pick development of the upstream project up again, consider all commits made by me to this repo as ready contributions. I cannot vouch for other commits as the upstream repo needs a signed CLA for Google.*
-
-[travisimg]: https://travis-ci.org/karalabe/gousb.svg?branch=master
-[travis]: https://travis-ci.org/karalabe/gousb
-[appveyorimg]: https://ci.appveyor.com/api/projects/status/84k9xse10rl72gn2/branch/master?svg=true
-[appveyor]: https://ci.appveyor.com/project/karalabe/gousb
-[docimg]: https://godoc.org/github.com/karalabe/gousb?status.svg
-[doc]: https://godoc.org/github.com/karalabe/gousb
-
-Installation
-============
-
-Example: lsusb
---------------
-The gousb project provides a simple but useful example: lsusb. This binary will list the USB devices connected to your system and various interesting tidbits about them, their configurations, endpoints, etc. To install it, run the following command:
-
- go get -v github.com/karalabe/gousb/lsusb
-
-gousb
------
-If you installed the lsusb example, both libraries below are already installed.
-
-Installing the primary gousb package is really easy:
-
- go get -v github.com/karalabe/gousb/usb
-
-There is also a `usbid` package that will not be installed by default by this command, but which provides useful information including the human-readable vendor and product codes for detected hardware. It's not installed by default and not linked into the `usb` package by default because it adds ~400kb to the resulting binary. If you want both, they can be installed thus:
-
- go get -v github.com/karalabe/gousb/usb{,id}
-
-Documentation
-=============
-The documentation can be viewed via local godoc or via the excellent [godoc.org](http://godoc.org/):
-
-- [usb](http://godoc.org/github.com/karalabe/gousb/usb)
-- [usbid](http://godoc.org/pkg/github.com/karalabe/gousb/usbid)
diff --git a/vendor/github.com/karalabe/gousb/usb/config.go b/vendor/github.com/karalabe/gousb/usb/config.go
deleted file mode 100644
index 840bce63c6..0000000000
--- a/vendor/github.com/karalabe/gousb/usb/config.go
+++ /dev/null
@@ -1,153 +0,0 @@
-// Copyright 2013 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package usb
-
-/*
-#ifndef OS_WINDOWS
- #include "os/threads_posix.h"
-#endif
-#include "libusbi.h"
-#include "libusb.h"
-*/
-import "C"
-
-import (
- "fmt"
- "reflect"
- "unsafe"
-)
-
-type EndpointInfo struct {
- Address uint8
- Attributes uint8
- MaxPacketSize uint16
- MaxIsoPacket uint32
- PollInterval uint8
- RefreshRate uint8
- SynchAddress uint8
-}
-
-func (e EndpointInfo) Number() int {
- return int(e.Address) & ENDPOINT_NUM_MASK
-}
-
-func (e EndpointInfo) Direction() EndpointDirection {
- return EndpointDirection(e.Address) & ENDPOINT_DIR_MASK
-}
-
-func (e EndpointInfo) String() string {
- return fmt.Sprintf("Endpoint %d %-3s %s - %s %s [%d %d]",
- e.Number(), e.Direction(),
- TransferType(e.Attributes)&TRANSFER_TYPE_MASK,
- IsoSyncType(e.Attributes)&ISO_SYNC_TYPE_MASK,
- IsoUsageType(e.Attributes)&ISO_USAGE_TYPE_MASK,
- e.MaxPacketSize, e.MaxIsoPacket,
- )
-}
-
-type InterfaceInfo struct {
- Number uint8
- Setups []InterfaceSetup
-}
-
-func (i InterfaceInfo) String() string {
- return fmt.Sprintf("Interface %02x (%d setups)", i.Number, len(i.Setups))
-}
-
-type InterfaceSetup struct {
- Number uint8
- Alternate uint8
- IfClass uint8
- IfSubClass uint8
- IfProtocol uint8
- Endpoints []EndpointInfo
-}
-
-func (a InterfaceSetup) String() string {
- return fmt.Sprintf("Interface %02x Setup %02x", a.Number, a.Alternate)
-}
-
-type ConfigInfo struct {
- Config uint8
- Attributes uint8
- MaxPower uint8
- Interfaces []InterfaceInfo
-}
-
-func (c ConfigInfo) String() string {
- return fmt.Sprintf("Config %02x", c.Config)
-}
-
-func newConfig(dev *C.libusb_device, cfg *C.struct_libusb_config_descriptor) ConfigInfo {
- c := ConfigInfo{
- Config: uint8(cfg.bConfigurationValue),
- Attributes: uint8(cfg.bmAttributes),
- MaxPower: uint8(cfg.MaxPower),
- }
-
- var ifaces []C.struct_libusb_interface
- *(*reflect.SliceHeader)(unsafe.Pointer(&ifaces)) = reflect.SliceHeader{
- Data: uintptr(unsafe.Pointer(cfg._interface)),
- Len: int(cfg.bNumInterfaces),
- Cap: int(cfg.bNumInterfaces),
- }
- c.Interfaces = make([]InterfaceInfo, 0, len(ifaces))
- for _, iface := range ifaces {
- if iface.num_altsetting == 0 {
- continue
- }
-
- var alts []C.struct_libusb_interface_descriptor
- *(*reflect.SliceHeader)(unsafe.Pointer(&alts)) = reflect.SliceHeader{
- Data: uintptr(unsafe.Pointer(iface.altsetting)),
- Len: int(iface.num_altsetting),
- Cap: int(iface.num_altsetting),
- }
- descs := make([]InterfaceSetup, 0, len(alts))
- for _, alt := range alts {
- i := InterfaceSetup{
- Number: uint8(alt.bInterfaceNumber),
- Alternate: uint8(alt.bAlternateSetting),
- IfClass: uint8(alt.bInterfaceClass),
- IfSubClass: uint8(alt.bInterfaceSubClass),
- IfProtocol: uint8(alt.bInterfaceProtocol),
- }
- var ends []C.struct_libusb_endpoint_descriptor
- *(*reflect.SliceHeader)(unsafe.Pointer(&ends)) = reflect.SliceHeader{
- Data: uintptr(unsafe.Pointer(alt.endpoint)),
- Len: int(alt.bNumEndpoints),
- Cap: int(alt.bNumEndpoints),
- }
- i.Endpoints = make([]EndpointInfo, 0, len(ends))
- for _, end := range ends {
- i.Endpoints = append(i.Endpoints, EndpointInfo{
- Address: uint8(end.bEndpointAddress),
- Attributes: uint8(end.bmAttributes),
- MaxPacketSize: uint16(end.wMaxPacketSize),
- //MaxIsoPacket: uint32(C.libusb_get_max_iso_packet_size(dev, C.uchar(end.bEndpointAddress))),
- PollInterval: uint8(end.bInterval),
- RefreshRate: uint8(end.bRefresh),
- SynchAddress: uint8(end.bSynchAddress),
- })
- }
- descs = append(descs, i)
- }
- c.Interfaces = append(c.Interfaces, InterfaceInfo{
- Number: descs[0].Number,
- Setups: descs,
- })
- }
- return c
-}
diff --git a/vendor/github.com/karalabe/gousb/usb/constants.go b/vendor/github.com/karalabe/gousb/usb/constants.go
deleted file mode 100644
index 7f0287d5c9..0000000000
--- a/vendor/github.com/karalabe/gousb/usb/constants.go
+++ /dev/null
@@ -1,183 +0,0 @@
-// Copyright 2013 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package usb
-
-// #include "libusb.h"
-import "C"
-
-type Class uint8
-
-const (
- CLASS_PER_INTERFACE Class = C.LIBUSB_CLASS_PER_INTERFACE
- CLASS_AUDIO Class = C.LIBUSB_CLASS_AUDIO
- CLASS_COMM Class = C.LIBUSB_CLASS_COMM
- CLASS_HID Class = C.LIBUSB_CLASS_HID
- CLASS_PRINTER Class = C.LIBUSB_CLASS_PRINTER
- CLASS_PTP Class = C.LIBUSB_CLASS_PTP
- CLASS_MASS_STORAGE Class = C.LIBUSB_CLASS_MASS_STORAGE
- CLASS_HUB Class = C.LIBUSB_CLASS_HUB
- CLASS_DATA Class = C.LIBUSB_CLASS_DATA
- CLASS_WIRELESS Class = C.LIBUSB_CLASS_WIRELESS
- CLASS_APPLICATION Class = C.LIBUSB_CLASS_APPLICATION
- CLASS_VENDOR_SPEC Class = C.LIBUSB_CLASS_VENDOR_SPEC
-)
-
-var classDescription = map[Class]string{
- CLASS_PER_INTERFACE: "per-interface",
- CLASS_AUDIO: "audio",
- CLASS_COMM: "communications",
- CLASS_HID: "human interface device",
- CLASS_PRINTER: "printer dclass",
- CLASS_PTP: "picture transfer protocol",
- CLASS_MASS_STORAGE: "mass storage",
- CLASS_HUB: "hub",
- CLASS_DATA: "data",
- CLASS_WIRELESS: "wireless",
- CLASS_APPLICATION: "application",
- CLASS_VENDOR_SPEC: "vendor-specific",
-}
-
-func (c Class) String() string {
- return classDescription[c]
-}
-
-type DescriptorType uint8
-
-const (
- DT_DEVICE DescriptorType = C.LIBUSB_DT_DEVICE
- DT_CONFIG DescriptorType = C.LIBUSB_DT_CONFIG
- DT_STRING DescriptorType = C.LIBUSB_DT_STRING
- DT_INTERFACE DescriptorType = C.LIBUSB_DT_INTERFACE
- DT_ENDPOINT DescriptorType = C.LIBUSB_DT_ENDPOINT
- DT_HID DescriptorType = C.LIBUSB_DT_HID
- DT_REPORT DescriptorType = C.LIBUSB_DT_REPORT
- DT_PHYSICAL DescriptorType = C.LIBUSB_DT_PHYSICAL
- DT_HUB DescriptorType = C.LIBUSB_DT_HUB
-)
-
-var descriptorTypeDescription = map[DescriptorType]string{
- DT_DEVICE: "device",
- DT_CONFIG: "configuration",
- DT_STRING: "string",
- DT_INTERFACE: "interface",
- DT_ENDPOINT: "endpoint",
- DT_HID: "HID",
- DT_REPORT: "HID report",
- DT_PHYSICAL: "physical",
- DT_HUB: "hub",
-}
-
-func (dt DescriptorType) String() string {
- return descriptorTypeDescription[dt]
-}
-
-type EndpointDirection uint8
-
-const (
- ENDPOINT_NUM_MASK = 0x03
- ENDPOINT_DIR_IN EndpointDirection = C.LIBUSB_ENDPOINT_IN
- ENDPOINT_DIR_OUT EndpointDirection = C.LIBUSB_ENDPOINT_OUT
- ENDPOINT_DIR_MASK EndpointDirection = 0x80
-)
-
-var endpointDirectionDescription = map[EndpointDirection]string{
- ENDPOINT_DIR_IN: "IN",
- ENDPOINT_DIR_OUT: "OUT",
-}
-
-func (ed EndpointDirection) String() string {
- return endpointDirectionDescription[ed]
-}
-
-type TransferType uint8
-
-const (
- TRANSFER_TYPE_CONTROL TransferType = C.LIBUSB_TRANSFER_TYPE_CONTROL
- TRANSFER_TYPE_ISOCHRONOUS TransferType = C.LIBUSB_TRANSFER_TYPE_ISOCHRONOUS
- TRANSFER_TYPE_BULK TransferType = C.LIBUSB_TRANSFER_TYPE_BULK
- TRANSFER_TYPE_INTERRUPT TransferType = C.LIBUSB_TRANSFER_TYPE_INTERRUPT
- TRANSFER_TYPE_MASK TransferType = 0x03
-)
-
-var transferTypeDescription = map[TransferType]string{
- TRANSFER_TYPE_CONTROL: "control",
- TRANSFER_TYPE_ISOCHRONOUS: "isochronous",
- TRANSFER_TYPE_BULK: "bulk",
- TRANSFER_TYPE_INTERRUPT: "interrupt",
-}
-
-func (tt TransferType) String() string {
- return transferTypeDescription[tt]
-}
-
-type IsoSyncType uint8
-
-const (
- ISO_SYNC_TYPE_NONE IsoSyncType = C.LIBUSB_ISO_SYNC_TYPE_NONE << 2
- ISO_SYNC_TYPE_ASYNC IsoSyncType = C.LIBUSB_ISO_SYNC_TYPE_ASYNC << 2
- ISO_SYNC_TYPE_ADAPTIVE IsoSyncType = C.LIBUSB_ISO_SYNC_TYPE_ADAPTIVE << 2
- ISO_SYNC_TYPE_SYNC IsoSyncType = C.LIBUSB_ISO_SYNC_TYPE_SYNC << 2
- ISO_SYNC_TYPE_MASK IsoSyncType = 0x0C
-)
-
-var isoSyncTypeDescription = map[IsoSyncType]string{
- ISO_SYNC_TYPE_NONE: "unsynchronized",
- ISO_SYNC_TYPE_ASYNC: "asynchronous",
- ISO_SYNC_TYPE_ADAPTIVE: "adaptive",
- ISO_SYNC_TYPE_SYNC: "synchronous",
-}
-
-func (ist IsoSyncType) String() string {
- return isoSyncTypeDescription[ist]
-}
-
-type IsoUsageType uint8
-
-const (
- ISO_USAGE_TYPE_DATA IsoUsageType = C.LIBUSB_ISO_USAGE_TYPE_DATA << 4
- ISO_USAGE_TYPE_FEEDBACK IsoUsageType = C.LIBUSB_ISO_USAGE_TYPE_FEEDBACK << 4
- ISO_USAGE_TYPE_IMPLICIT IsoUsageType = C.LIBUSB_ISO_USAGE_TYPE_IMPLICIT << 4
- ISO_USAGE_TYPE_MASK IsoUsageType = 0x30
-)
-
-var isoUsageTypeDescription = map[IsoUsageType]string{
- ISO_USAGE_TYPE_DATA: "data",
- ISO_USAGE_TYPE_FEEDBACK: "feedback",
- ISO_USAGE_TYPE_IMPLICIT: "implicit data",
-}
-
-func (iut IsoUsageType) String() string {
- return isoUsageTypeDescription[iut]
-}
-
-type RequestType uint8
-
-const (
- REQUEST_TYPE_STANDARD = C.LIBUSB_REQUEST_TYPE_STANDARD
- REQUEST_TYPE_CLASS = C.LIBUSB_REQUEST_TYPE_CLASS
- REQUEST_TYPE_VENDOR = C.LIBUSB_REQUEST_TYPE_VENDOR
- REQUEST_TYPE_RESERVED = C.LIBUSB_REQUEST_TYPE_RESERVED
-)
-
-var requestTypeDescription = map[RequestType]string{
- REQUEST_TYPE_STANDARD: "standard",
- REQUEST_TYPE_CLASS: "class",
- REQUEST_TYPE_VENDOR: "vendor",
- REQUEST_TYPE_RESERVED: "reserved",
-}
-
-func (rt RequestType) String() string {
- return requestTypeDescription[rt]
-}
diff --git a/vendor/github.com/karalabe/gousb/usb/debug.go b/vendor/github.com/karalabe/gousb/usb/debug.go
deleted file mode 100644
index e7de8e522c..0000000000
--- a/vendor/github.com/karalabe/gousb/usb/debug.go
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright 2013 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package usb
-
-// To enable internal debugging:
-// -ldflags "-X github.com/karalabe/gousb/usb.debugInternal true"
-
-import (
- "io"
- "io/ioutil"
- "log" // TODO(kevlar): make a logger
- "os"
-)
-
-var debug *log.Logger
-var debugInternal string
-
-func init() {
- var out io.Writer = ioutil.Discard
- if debugInternal != "" {
- out = os.Stderr
- }
- debug = log.New(out, "usb", log.LstdFlags|log.Lshortfile)
-}
diff --git a/vendor/github.com/karalabe/gousb/usb/descriptor.go b/vendor/github.com/karalabe/gousb/usb/descriptor.go
deleted file mode 100644
index 2551dfc234..0000000000
--- a/vendor/github.com/karalabe/gousb/usb/descriptor.go
+++ /dev/null
@@ -1,77 +0,0 @@
-// Copyright 2013 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package usb
-
-/*
-#ifndef OS_WINDOWS
- #include "os/threads_posix.h"
-#endif
-#include "libusbi.h"
-#include "libusb.h"
-*/
-import "C"
-
-type Descriptor struct {
- // Bus information
- Bus uint8 // The bus on which the device was detected
- Address uint8 // The address of the device on the bus
-
- // Version information
- Spec BCD // USB Specification Release Number
- Device BCD // The device version
-
- // Product information
- Vendor ID // The Vendor identifer
- Product ID // The Product identifier
-
- // Protocol information
- Class uint8 // The class of this device
- SubClass uint8 // The sub-class (within the class) of this device
- Protocol uint8 // The protocol (within the sub-class) of this device
-
- // Configuration information
- Configs []ConfigInfo
-}
-
-func newDescriptor(dev *C.libusb_device) (*Descriptor, error) {
- var desc C.struct_libusb_device_descriptor
- if errno := C.libusb_get_device_descriptor(dev, &desc); errno < 0 {
- return nil, usbError(errno)
- }
-
- // Enumerate configurations
- var cfgs []ConfigInfo
- for i := 0; i < int(desc.bNumConfigurations); i++ {
- var cfg *C.struct_libusb_config_descriptor
- if errno := C.libusb_get_config_descriptor(dev, C.uint8_t(i), &cfg); errno < 0 {
- return nil, usbError(errno)
- }
- cfgs = append(cfgs, newConfig(dev, cfg))
- C.libusb_free_config_descriptor(cfg)
- }
-
- return &Descriptor{
- Bus: uint8(C.libusb_get_bus_number(dev)),
- Address: uint8(C.libusb_get_device_address(dev)),
- Spec: BCD(desc.bcdUSB),
- Device: BCD(desc.bcdDevice),
- Vendor: ID(desc.idVendor),
- Product: ID(desc.idProduct),
- Class: uint8(desc.bDeviceClass),
- SubClass: uint8(desc.bDeviceSubClass),
- Protocol: uint8(desc.bDeviceProtocol),
- Configs: cfgs,
- }, nil
-}
diff --git a/vendor/github.com/karalabe/gousb/usb/device.go b/vendor/github.com/karalabe/gousb/usb/device.go
deleted file mode 100644
index b4c4131fa6..0000000000
--- a/vendor/github.com/karalabe/gousb/usb/device.go
+++ /dev/null
@@ -1,295 +0,0 @@
-// Copyright 2013 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package usb
-
-/*
-#ifndef OS_WINDOWS
- #include "os/threads_posix.h"
-#endif
-#include "libusbi.h"
-#include "libusb.h"
-*/
-import "C"
-
-import (
- "fmt"
- "reflect"
- "sync"
- "time"
- "unsafe"
-)
-
-var DefaultReadTimeout = 1 * time.Second
-var DefaultWriteTimeout = 1 * time.Second
-var DefaultControlTimeout = 250 * time.Millisecond //5 * time.Second
-
-type Device struct {
- handle *C.libusb_device_handle
-
- // Embed the device information for easy access
- *Descriptor
-
- // Timeouts
- ReadTimeout time.Duration
- WriteTimeout time.Duration
- ControlTimeout time.Duration
-
- // Claimed interfaces
- lock *sync.Mutex
- claimed map[uint8]int
-
- // Detached kernel interfaces
- detached map[uint8]int
-}
-
-func newDevice(handle *C.libusb_device_handle, desc *Descriptor) (*Device, error) {
- ifaces := 0
- d := &Device{
- handle: handle,
- Descriptor: desc,
- ReadTimeout: DefaultReadTimeout,
- WriteTimeout: DefaultWriteTimeout,
- ControlTimeout: DefaultControlTimeout,
- lock: new(sync.Mutex),
- claimed: make(map[uint8]int, ifaces),
- detached: make(map[uint8]int),
- }
-
- if err := d.detachKernelDriver(); err != nil {
- d.Close()
- return nil, err
- }
-
- return d, nil
-}
-
-// detachKernelDriver detaches any active kernel drivers, if supported by the platform.
-// If there are any errors, like Context.ListDevices, only the final one will be returned.
-func (d *Device) detachKernelDriver() (err error) {
- for _, cfg := range d.Configs {
- for _, iface := range cfg.Interfaces {
- switch activeErr := C.libusb_kernel_driver_active(d.handle, C.int(iface.Number)); activeErr {
- case C.LIBUSB_ERROR_NOT_SUPPORTED:
- // no need to do any futher checking, no platform support
- return
- case 0:
- continue
- case 1:
- switch detachErr := C.libusb_detach_kernel_driver(d.handle, C.int(iface.Number)); detachErr {
- case C.LIBUSB_ERROR_NOT_SUPPORTED:
- // shouldn't ever get here, should be caught by the outer switch
- return
- case 0:
- d.detached[iface.Number]++
- case C.LIBUSB_ERROR_NOT_FOUND:
- // this status is returned if libusb's driver is already attached to the device
- d.detached[iface.Number]++
- default:
- err = fmt.Errorf("usb: detach kernel driver: %s", usbError(detachErr))
- }
- default:
- err = fmt.Errorf("usb: active kernel driver check: %s", usbError(activeErr))
- }
- }
- }
-
- return
-}
-
-// attachKernelDriver re-attaches kernel drivers to any previously detached interfaces, if supported by the platform.
-// If there are any errors, like Context.ListDevices, only the final one will be returned.
-func (d *Device) attachKernelDriver() (err error) {
- for iface := range d.detached {
- switch attachErr := C.libusb_attach_kernel_driver(d.handle, C.int(iface)); attachErr {
- case C.LIBUSB_ERROR_NOT_SUPPORTED:
- // no need to do any futher checking, no platform support
- return
- case 0:
- continue
- default:
- err = fmt.Errorf("usb: attach kernel driver: %s", usbError(attachErr))
- }
- }
-
- return
-}
-
-func (d *Device) Reset() error {
- if errno := C.libusb_reset_device(d.handle); errno != 0 {
- return usbError(errno)
- }
- return nil
-}
-
-func (d *Device) Control(rType, request uint8, val, idx uint16, data []byte) (int, error) {
- //log.Printf("control xfer: %d:%d/%d:%d %x", idx, rType, request, val, string(data))
- dataSlice := (*reflect.SliceHeader)(unsafe.Pointer(&data))
- n := C.libusb_control_transfer(
- d.handle,
- C.uint8_t(rType),
- C.uint8_t(request),
- C.uint16_t(val),
- C.uint16_t(idx),
- (*C.uchar)(unsafe.Pointer(dataSlice.Data)),
- C.uint16_t(len(data)),
- C.uint(d.ControlTimeout/time.Millisecond))
- if n < 0 {
- return int(n), usbError(n)
- }
- return int(n), nil
-}
-
-// ActiveConfig returns the config id (not the index) of the active configuration.
-// This corresponds to the ConfigInfo.Config field.
-func (d *Device) ActiveConfig() (uint8, error) {
- var cfg C.int
- if errno := C.libusb_get_configuration(d.handle, &cfg); errno < 0 {
- return 0, usbError(errno)
- }
- return uint8(cfg), nil
-}
-
-// SetConfig attempts to change the active configuration.
-// The cfg provided is the config id (not the index) of the configuration to set,
-// which corresponds to the ConfigInfo.Config field.
-func (d *Device) SetConfig(cfg uint8) error {
- if errno := C.libusb_set_configuration(d.handle, C.int(cfg)); errno < 0 {
- return usbError(errno)
- }
- return nil
-}
-
-// Close the device.
-func (d *Device) Close() error {
- if d.handle == nil {
- return fmt.Errorf("usb: double close on device")
- }
- d.lock.Lock()
- defer d.lock.Unlock()
- for iface := range d.claimed {
- C.libusb_release_interface(d.handle, C.int(iface))
- }
- d.attachKernelDriver()
- C.libusb_close(d.handle)
- d.handle = nil
- return nil
-}
-
-func (d *Device) OpenEndpoint(conf, iface, setup, epoint uint8) (Endpoint, error) {
- end := &endpoint{
- Device: d,
- }
-
- var setAlternate bool
- for _, c := range d.Configs {
- if c.Config != conf {
- continue
- }
- debug.Printf("found conf: %#v\n", c)
- for _, i := range c.Interfaces {
- if i.Number != iface {
- continue
- }
- debug.Printf("found iface: %#v\n", i)
- for i, s := range i.Setups {
- if s.Alternate != setup {
- continue
- }
- setAlternate = i != 0
-
- debug.Printf("found setup: %#v [default: %v]\n", s, !setAlternate)
- for _, e := range s.Endpoints {
- debug.Printf("ep %02x search: %#v\n", epoint, s)
- if e.Address != epoint {
- continue
- }
- end.InterfaceSetup = s
- end.EndpointInfo = e
- switch tt := TransferType(e.Attributes) & TRANSFER_TYPE_MASK; tt {
- case TRANSFER_TYPE_BULK:
- end.xfer = bulk_xfer
- case TRANSFER_TYPE_INTERRUPT:
- end.xfer = interrupt_xfer
- case TRANSFER_TYPE_ISOCHRONOUS:
- end.xfer = isochronous_xfer
- default:
- return nil, fmt.Errorf("usb: %s transfer is unsupported", tt)
- }
- goto found
- }
- return nil, fmt.Errorf("usb: unknown endpoint %02x", epoint)
- }
- return nil, fmt.Errorf("usb: unknown setup %02x", setup)
- }
- return nil, fmt.Errorf("usb: unknown interface %02x", iface)
- }
- return nil, fmt.Errorf("usb: unknown configuration %02x", conf)
-
-found:
-
- // Set the configuration
- var activeConf C.int
- if errno := C.libusb_get_configuration(d.handle, &activeConf); errno < 0 {
- return nil, fmt.Errorf("usb: getcfg: %s", usbError(errno))
- }
- if int(activeConf) != int(conf) {
- if errno := C.libusb_set_configuration(d.handle, C.int(conf)); errno < 0 {
- return nil, fmt.Errorf("usb: setcfg: %s", usbError(errno))
- }
- }
-
- // Claim the interface
- if errno := C.libusb_claim_interface(d.handle, C.int(iface)); errno < 0 {
- return nil, fmt.Errorf("usb: claim: %s", usbError(errno))
- }
-
- // Increment the claim count
- d.lock.Lock()
- d.claimed[iface]++
- d.lock.Unlock() // unlock immediately because the next calls may block
-
- // Choose the alternate
- if setAlternate {
- if errno := C.libusb_set_interface_alt_setting(d.handle, C.int(iface), C.int(setup)); errno < 0 {
- debug.Printf("altsetting error: %s", usbError(errno))
- return nil, fmt.Errorf("usb: setalt: %s", usbError(errno))
- }
- }
-
- return end, nil
-}
-
-func (d *Device) GetStringDescriptor(desc_index int) (string, error) {
-
- // allocate 200-byte array limited the length of string descriptor
- goBuffer := make([]byte, 200)
-
- // get string descriptor from libusb. if errno < 0 then there are any errors.
- // if errno >= 0; it is a length of result string descriptor
- errno := C.libusb_get_string_descriptor_ascii(
- d.handle,
- C.uint8_t(desc_index),
- (*C.uchar)(unsafe.Pointer(&goBuffer[0])),
- 200)
-
- // if any errors occur
- if errno < 0 {
- return "", fmt.Errorf("usb: getstr: %s", usbError(errno))
- }
- // convert slice of byte to string with limited length from errno
- stringDescriptor := string(goBuffer[:errno])
-
- return stringDescriptor, nil
-}
diff --git a/vendor/github.com/karalabe/gousb/usb/endpoint.go b/vendor/github.com/karalabe/gousb/usb/endpoint.go
deleted file mode 100644
index 12b4ccf950..0000000000
--- a/vendor/github.com/karalabe/gousb/usb/endpoint.go
+++ /dev/null
@@ -1,100 +0,0 @@
-// Copyright 2013 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package usb
-
-// #include "libusb.h"
-import "C"
-
-import (
- "fmt"
- "reflect"
- "time"
- "unsafe"
-)
-
-type Endpoint interface {
- Read(b []byte) (int, error)
- Write(b []byte) (int, error)
- Interface() InterfaceSetup
- Info() EndpointInfo
-}
-
-type endpoint struct {
- *Device
- InterfaceSetup
- EndpointInfo
- xfer func(*endpoint, []byte, time.Duration) (int, error)
-}
-
-func (e *endpoint) Read(buf []byte) (int, error) {
- if EndpointDirection(e.Address)&ENDPOINT_DIR_MASK != ENDPOINT_DIR_IN {
- return 0, fmt.Errorf("usb: read: not an IN endpoint")
- }
-
- return e.xfer(e, buf, e.ReadTimeout)
-}
-
-func (e *endpoint) Write(buf []byte) (int, error) {
- if EndpointDirection(e.Address)&ENDPOINT_DIR_MASK != ENDPOINT_DIR_OUT {
- return 0, fmt.Errorf("usb: write: not an OUT endpoint")
- }
-
- return e.xfer(e, buf, e.WriteTimeout)
-}
-
-func (e *endpoint) Interface() InterfaceSetup { return e.InterfaceSetup }
-func (e *endpoint) Info() EndpointInfo { return e.EndpointInfo }
-
-// TODO(kevlar): (*Endpoint).Close
-
-func bulk_xfer(e *endpoint, buf []byte, timeout time.Duration) (int, error) {
- if len(buf) == 0 {
- return 0, nil
- }
-
- data := (*reflect.SliceHeader)(unsafe.Pointer(&buf)).Data
-
- var cnt C.int
- if errno := C.libusb_bulk_transfer(
- e.handle,
- C.uchar(e.Address),
- (*C.uchar)(unsafe.Pointer(data)),
- C.int(len(buf)),
- &cnt,
- C.uint(timeout/time.Millisecond)); errno < 0 {
- return 0, usbError(errno)
- }
- return int(cnt), nil
-}
-
-func interrupt_xfer(e *endpoint, buf []byte, timeout time.Duration) (int, error) {
- if len(buf) == 0 {
- return 0, nil
- }
-
- data := (*reflect.SliceHeader)(unsafe.Pointer(&buf)).Data
-
- var cnt C.int
- if errno := C.libusb_interrupt_transfer(
- e.handle,
- C.uchar(e.Address),
- (*C.uchar)(unsafe.Pointer(data)),
- C.int(len(buf)),
- &cnt,
- C.uint(timeout/time.Millisecond)); errno < 0 {
- return 0, usbError(errno)
- }
- return int(cnt), nil
-}
diff --git a/vendor/github.com/karalabe/gousb/usb/error.go b/vendor/github.com/karalabe/gousb/usb/error.go
deleted file mode 100644
index 30d47bce37..0000000000
--- a/vendor/github.com/karalabe/gousb/usb/error.go
+++ /dev/null
@@ -1,92 +0,0 @@
-// Copyright 2013 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package usb
-
-import (
- "fmt"
-)
-
-// #include "libusb.h"
-import "C"
-
-type usbError C.int
-
-func (e usbError) Error() string {
- return fmt.Sprintf("libusb: %s [code %d]", usbErrorString[e], int(e))
-}
-
-const (
- SUCCESS usbError = C.LIBUSB_SUCCESS
- ERROR_IO usbError = C.LIBUSB_ERROR_IO
- ERROR_INVALID_PARAM usbError = C.LIBUSB_ERROR_INVALID_PARAM
- ERROR_ACCESS usbError = C.LIBUSB_ERROR_ACCESS
- ERROR_NO_DEVICE usbError = C.LIBUSB_ERROR_NO_DEVICE
- ERROR_NOT_FOUND usbError = C.LIBUSB_ERROR_NOT_FOUND
- ERROR_BUSY usbError = C.LIBUSB_ERROR_BUSY
- ERROR_TIMEOUT usbError = C.LIBUSB_ERROR_TIMEOUT
- ERROR_OVERFLOW usbError = C.LIBUSB_ERROR_OVERFLOW
- ERROR_PIPE usbError = C.LIBUSB_ERROR_PIPE
- ERROR_INTERRUPTED usbError = C.LIBUSB_ERROR_INTERRUPTED
- ERROR_NO_MEM usbError = C.LIBUSB_ERROR_NO_MEM
- ERROR_NOT_SUPPORTED usbError = C.LIBUSB_ERROR_NOT_SUPPORTED
- ERROR_OTHER usbError = C.LIBUSB_ERROR_OTHER
-)
-
-var usbErrorString = map[usbError]string{
- C.LIBUSB_SUCCESS: "success",
- C.LIBUSB_ERROR_IO: "i/o error",
- C.LIBUSB_ERROR_INVALID_PARAM: "invalid param",
- C.LIBUSB_ERROR_ACCESS: "bad access",
- C.LIBUSB_ERROR_NO_DEVICE: "no device",
- C.LIBUSB_ERROR_NOT_FOUND: "not found",
- C.LIBUSB_ERROR_BUSY: "device or resource busy",
- C.LIBUSB_ERROR_TIMEOUT: "timeout",
- C.LIBUSB_ERROR_OVERFLOW: "overflow",
- C.LIBUSB_ERROR_PIPE: "pipe error",
- C.LIBUSB_ERROR_INTERRUPTED: "interrupted",
- C.LIBUSB_ERROR_NO_MEM: "out of memory",
- C.LIBUSB_ERROR_NOT_SUPPORTED: "not supported",
- C.LIBUSB_ERROR_OTHER: "unknown error",
-}
-
-type TransferStatus uint8
-
-const (
- LIBUSB_TRANSFER_COMPLETED TransferStatus = C.LIBUSB_TRANSFER_COMPLETED
- LIBUSB_TRANSFER_ERROR TransferStatus = C.LIBUSB_TRANSFER_ERROR
- LIBUSB_TRANSFER_TIMED_OUT TransferStatus = C.LIBUSB_TRANSFER_TIMED_OUT
- LIBUSB_TRANSFER_CANCELLED TransferStatus = C.LIBUSB_TRANSFER_CANCELLED
- LIBUSB_TRANSFER_STALL TransferStatus = C.LIBUSB_TRANSFER_STALL
- LIBUSB_TRANSFER_NO_DEVICE TransferStatus = C.LIBUSB_TRANSFER_NO_DEVICE
- LIBUSB_TRANSFER_OVERFLOW TransferStatus = C.LIBUSB_TRANSFER_OVERFLOW
-)
-
-var transferStatusDescription = map[TransferStatus]string{
- LIBUSB_TRANSFER_COMPLETED: "transfer completed without error",
- LIBUSB_TRANSFER_ERROR: "transfer failed",
- LIBUSB_TRANSFER_TIMED_OUT: "transfer timed out",
- LIBUSB_TRANSFER_CANCELLED: "transfer was cancelled",
- LIBUSB_TRANSFER_STALL: "halt condition detected (endpoint stalled) or control request not supported",
- LIBUSB_TRANSFER_NO_DEVICE: "device was disconnected",
- LIBUSB_TRANSFER_OVERFLOW: "device sent more data than requested",
-}
-
-func (ts TransferStatus) String() string {
- return transferStatusDescription[ts]
-}
-
-func (ts TransferStatus) Error() string {
- return "libusb: " + ts.String()
-}
diff --git a/vendor/github.com/karalabe/gousb/usb/iso.c b/vendor/github.com/karalabe/gousb/usb/iso.c
deleted file mode 100644
index 0544863184..0000000000
--- a/vendor/github.com/karalabe/gousb/usb/iso.c
+++ /dev/null
@@ -1,79 +0,0 @@
-#include "libusb.h"
-#include
-#include
-
-void print_xfer(struct libusb_transfer *xfer);
-void iso_callback(void *);
-
-void callback(struct libusb_transfer *xfer) {
- //printf("Callback!\n");
- //print_xfer(xfer);
- iso_callback(xfer->user_data);
-}
-
-int submit(struct libusb_transfer *xfer) {
- xfer->callback = &callback;
- xfer->status = -1;
- //print_xfer(xfer);
- //printf("Transfer submitted\n");
-
- /* fake
- strcpy(xfer->buffer, "hello");
- xfer->actual_length = 5;
- callback(xfer);
- return 0; */
- return libusb_submit_transfer(xfer);
-}
-
-void print_xfer(struct libusb_transfer *xfer) {
- int i;
-
- printf("Transfer:\n");
- printf(" dev_handle: %p\n", xfer->dev_handle);
- printf(" flags: %08x\n", xfer->flags);
- printf(" endpoint: %x\n", xfer->endpoint);
- printf(" type: %x\n", xfer->type);
- printf(" timeout: %dms\n", xfer->timeout);
- printf(" status: %x\n", xfer->status);
- printf(" length: %d (act: %d)\n", xfer->length, xfer->actual_length);
- printf(" callback: %p\n", xfer->callback);
- printf(" user_data: %p\n", xfer->user_data);
- printf(" buffer: %p\n", xfer->buffer);
- printf(" num_iso_pkts: %d\n", xfer->num_iso_packets);
- printf(" packets:\n");
- for (i = 0; i < xfer->num_iso_packets; i++) {
- printf(" [%04d] %d (act: %d) %x\n", i,
- xfer->iso_packet_desc[i].length,
- xfer->iso_packet_desc[i].actual_length,
- xfer->iso_packet_desc[i].status);
- }
-}
-
-int extract_data(struct libusb_transfer *xfer, void *raw, int max, unsigned char *status) {
- int i;
- int copied = 0;
- unsigned char *in = xfer->buffer;
- unsigned char *out = raw;
- for (i = 0; i < xfer->num_iso_packets; i++) {
- struct libusb_iso_packet_descriptor pkt = xfer->iso_packet_desc[i];
-
- // Copy the data
- int len = pkt.actual_length;
- if (len > max) {
- len = max;
- }
- memcpy(out, in, len);
- copied += len;
-
- // Increment offsets
- in += pkt.length;
- out += len;
-
- // Extract first error
- if (pkt.status == 0 || *status != 0) {
- continue;
- }
- *status = pkt.status;
- }
- return copied;
-}
diff --git a/vendor/github.com/karalabe/gousb/usb/iso.go b/vendor/github.com/karalabe/gousb/usb/iso.go
deleted file mode 100644
index 1ba694e0e7..0000000000
--- a/vendor/github.com/karalabe/gousb/usb/iso.go
+++ /dev/null
@@ -1,148 +0,0 @@
-// Copyright 2013 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package usb
-
-/*
-#include "libusb.h"
-
-int submit(struct libusb_transfer *xfer);
-void print_xfer(struct libusb_transfer *xfer);
-int extract_data(struct libusb_transfer *xfer, void *data, int max, unsigned char *status);
-*/
-import "C"
-
-import (
- "fmt"
- "log"
- "time"
- "unsafe"
-)
-
-//export iso_callback
-func iso_callback(cptr unsafe.Pointer) {
- ch := *(*chan struct{})(cptr)
- close(ch)
-}
-
-func (end *endpoint) allocTransfer() *Transfer {
- // Use libusb_get_max_iso_packet_size ?
- const (
- iso_packets = 8 // 128 // 242
- packet_size = 2 * 960 // 1760
- )
-
- xfer := C.libusb_alloc_transfer(C.int(iso_packets))
- if xfer == nil {
- log.Printf("usb: transfer allocation failed?!")
- return nil
- }
-
- buf := make([]byte, iso_packets*packet_size)
- done := make(chan struct{}, 1)
-
- xfer.dev_handle = end.Device.handle
- xfer.endpoint = C.uchar(end.Address)
- xfer._type = C.LIBUSB_TRANSFER_TYPE_ISOCHRONOUS
-
- xfer.buffer = (*C.uchar)((unsafe.Pointer)(&buf[0]))
- xfer.length = C.int(len(buf))
- xfer.num_iso_packets = iso_packets
-
- C.libusb_set_iso_packet_lengths(xfer, packet_size)
- /*
- pkts := *(*[]C.struct_libusb_packet_descriptor)(unsafe.Pointer(&reflect.SliceHeader{
- Data: uintptr(unsafe.Pointer(&xfer.iso_packet_desc)),
- Len: iso_packets,
- Cap: iso_packets,
- }))
- */
-
- t := &Transfer{
- xfer: xfer,
- done: done,
- buf: buf,
- }
- xfer.user_data = (unsafe.Pointer)(&t.done)
-
- return t
-}
-
-type Transfer struct {
- xfer *C.struct_libusb_transfer
- pkts []*C.struct_libusb_packet_descriptor
- done chan struct{}
- buf []byte
-}
-
-func (t *Transfer) Submit(timeout time.Duration) error {
- //log.Printf("iso: submitting %#v", t.xfer)
- t.xfer.timeout = C.uint(timeout / time.Millisecond)
- if errno := C.submit(t.xfer); errno < 0 {
- return usbError(errno)
- }
- return nil
-}
-
-func (t *Transfer) Wait(b []byte) (n int, err error) {
- select {
- case <-time.After(10 * time.Second):
- return 0, fmt.Errorf("wait timed out after 10s")
- case <-t.done:
- }
- // Non-iso transfers:
- //n = int(t.xfer.actual_length)
- //copy(b, ((*[1 << 16]byte)(unsafe.Pointer(t.xfer.buffer)))[:n])
-
- //C.print_xfer(t.xfer)
- /*
- buf, offset := ((*[1 << 16]byte)(unsafe.Pointer(t.xfer.buffer))), 0
- for i, pkt := range *t.pkts {
- log.Printf("Type is %T", t.pkts)
- n += copy(b[n:], buf[offset:][:pkt.actual_length])
- offset += pkt.Length
- if pkt.status != 0 && err == nil {
- err = error(TransferStatus(pkt.status))
- }
- }
- */
- var status uint8
- n = int(C.extract_data(t.xfer, unsafe.Pointer(&b[0]), C.int(len(b)), (*C.uchar)(unsafe.Pointer(&status))))
- if status != 0 {
- err = TransferStatus(status)
- }
- return n, err
-}
-
-func (t *Transfer) Close() error {
- C.libusb_free_transfer(t.xfer)
- return nil
-}
-
-func isochronous_xfer(e *endpoint, buf []byte, timeout time.Duration) (int, error) {
- t := e.allocTransfer()
- defer t.Close()
-
- if err := t.Submit(timeout); err != nil {
- log.Printf("iso: xfer failed to submit: %s", err)
- return 0, err
- }
-
- n, err := t.Wait(buf)
- if err != nil {
- log.Printf("iso: xfer failed: %s", err)
- return 0, err
- }
- return n, err
-}
diff --git a/vendor/github.com/karalabe/gousb/usb/misc.go b/vendor/github.com/karalabe/gousb/usb/misc.go
deleted file mode 100644
index 6e25431bf3..0000000000
--- a/vendor/github.com/karalabe/gousb/usb/misc.go
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright 2013 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package usb
-
-import (
- "fmt"
-)
-
-type BCD uint16
-
-const (
- USB_2_0 BCD = 0x0200
- USB_1_1 BCD = 0x0110
- USB_1_0 BCD = 0x0100
-)
-
-func (d BCD) Int() (i int) {
- ten := 1
- for o := uint(0); o < 4; o++ {
- n := ((0xF << (o * 4)) & d) >> (o * 4)
- i += int(n) * ten
- ten *= 10
- }
- return
-}
-
-func (d BCD) String() string {
- return fmt.Sprintf("%02x.%02x", int(d>>8), int(d&0xFF))
-}
-
-type ID uint16
-
-func (id ID) String() string {
- return fmt.Sprintf("%04x", int(id))
-}
diff --git a/vendor/github.com/karalabe/gousb/usb/usb.go b/vendor/github.com/karalabe/gousb/usb/usb.go
deleted file mode 100644
index 366827e69a..0000000000
--- a/vendor/github.com/karalabe/gousb/usb/usb.go
+++ /dev/null
@@ -1,178 +0,0 @@
-// Copyright 2013 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// Package usb provides a wrapper around libusb-1.0.
-package usb
-
-/*
-#cgo CFLAGS: -I../internal/libusb/libusb
-#cgo CFLAGS: -DDEFAULT_VISIBILITY=""
-#cgo linux CFLAGS: -DOS_LINUX -D_GNU_SOURCE -DPOLL_NFDS_TYPE=int
-#cgo darwin CFLAGS: -DOS_DARWIN -DPOLL_NFDS_TYPE=int
-#cgo darwin LDFLAGS: -framework CoreFoundation -framework IOKit -lobjc
-#cgo openbsd CFLAGS: -DOS_OPENBSD -DPOLL_NFDS_TYPE=int
-#cgo windows CFLAGS: -DOS_WINDOWS -DUSE_USBDK -DPOLL_NFDS_TYPE=int
-
-#if defined(OS_LINUX) || defined(OS_DARWIN) || defined(OS_OPENBSD)
- #include
- #include "os/threads_posix.c"
- #include "os/poll_posix.c"
-#elif defined(OS_WINDOWS)
- #include "os/threads_windows.c"
- #include "os/poll_windows.c"
-#endif
-
-#ifdef OS_LINUX
- #include "os/linux_usbfs.c"
- #include "os/linux_netlink.c"
-#elif OS_DARWIN
- #include "os/darwin_usb.c"
-#elif OS_OPENBSD
- #include "os/openbsd_usb.c"
-#elif OS_WINDOWS
- #include "os/windows_nt_common.c"
- #include "os/windows_usbdk.c"
-#endif
-
-#include "core.c"
-#include "descriptor.c"
-#include "hotplug.c"
-#include "io.c"
-#include "strerror.c"
-#include "sync.c"
-*/
-import "C"
-
-import (
- "log"
- "reflect"
- "unsafe"
-)
-
-type Context struct {
- ctx *C.libusb_context
- done chan struct{}
-}
-
-func (c *Context) Debug(level int) {
- C.libusb_set_debug(c.ctx, C.int(level))
-}
-
-func NewContext() (*Context, error) {
- c := &Context{
- done: make(chan struct{}),
- }
-
- if errno := C.libusb_init(&c.ctx); errno != 0 {
- return nil, usbError(errno)
- }
-
- go func() {
- tv := C.struct_timeval{
- tv_sec: 0,
- tv_usec: 100000,
- }
- for {
- select {
- case <-c.done:
- return
- default:
- }
- if errno := C.libusb_handle_events_timeout_completed(c.ctx, &tv, nil); errno < 0 {
- log.Printf("handle_events: error: %s", usbError(errno))
- continue
- }
- //log.Printf("handle_events returned")
- }
- }()
-
- return c, nil
-}
-
-// ListDevices calls each with each enumerated device.
-// If the function returns true, the device is opened and a Device is returned if the operation succeeds.
-// Every Device returned (whether an error is also returned or not) must be closed.
-// If there are any errors enumerating the devices,
-// the final one is returned along with any successfully opened devices.
-func (c *Context) ListDevices(each func(desc *Descriptor) bool) ([]*Device, error) {
- var list **C.libusb_device
- cnt := C.libusb_get_device_list(c.ctx, &list)
- if cnt < 0 {
- return nil, usbError(cnt)
- }
- defer C.libusb_free_device_list(list, 1)
-
- var slice []*C.libusb_device
- *(*reflect.SliceHeader)(unsafe.Pointer(&slice)) = reflect.SliceHeader{
- Data: uintptr(unsafe.Pointer(list)),
- Len: int(cnt),
- Cap: int(cnt),
- }
-
- var reterr error
- var ret []*Device
- for _, dev := range slice {
- desc, err := newDescriptor(dev)
- if err != nil {
- reterr = err
- continue
- }
-
- if each(desc) {
- var handle *C.libusb_device_handle
- if errno := C.libusb_open(dev, &handle); errno != 0 {
- reterr = usbError(errno)
- continue
- }
- if dev, err := newDevice(handle, desc); err != nil {
- reterr = err
- } else {
- ret = append(ret, dev)
- }
- }
- }
- return ret, reterr
-}
-
-// OpenDeviceWithVidPid opens Device from specific VendorId and ProductId.
-// If there are any errors, it'll returns at second value.
-func (c *Context) OpenDeviceWithVidPid(vid, pid int) (*Device, error) {
-
- handle := C.libusb_open_device_with_vid_pid(c.ctx, (C.uint16_t)(vid), (C.uint16_t)(pid))
- if handle == nil {
- return nil, ERROR_NOT_FOUND
- }
-
- dev := C.libusb_get_device(handle)
- if dev == nil {
- return nil, ERROR_NO_DEVICE
- }
-
- desc, err := newDescriptor(dev)
-
- // return an error from nil-handle and nil-device
- if err != nil {
- return nil, err
- }
- return newDevice(handle, desc)
-}
-
-func (c *Context) Close() error {
- close(c.done)
- if c.ctx != nil {
- C.libusb_exit(c.ctx)
- }
- c.ctx = nil
- return nil
-}
diff --git a/vendor/github.com/karalabe/hid/LICENSE.md b/vendor/github.com/karalabe/hid/LICENSE.md
new file mode 100644
index 0000000000..230d1daeb6
--- /dev/null
+++ b/vendor/github.com/karalabe/hid/LICENSE.md
@@ -0,0 +1,8 @@
+The components of `hid` are licensed as such:
+
+ * `hidapi` is released under the [3-clause BSD](https://github.com/signal11/hidapi/blob/master/LICENSE-bsd.txt) license.
+ * `libusb` is released under the [GNU LGPL 2.1](https://github.com/libusb/libusb/blob/master/COPYING)license.
+ * `go.hid` is released under the [2-clause BSD](https://github.com/GeertJohan/go.hid/blob/master/LICENSE) license.
+ * `gowchar` is released under the [3-clause BSD](https://github.com/orofarne/gowchar/blob/master/LICENSE) license.
+
+Given the above, `hid` is licensed under GNU LGPL 2.1 or later on Linux and 3-clause BSD on other platforms.
diff --git a/vendor/github.com/karalabe/hid/README.md b/vendor/github.com/karalabe/hid/README.md
new file mode 100644
index 0000000000..5c0213f3b2
--- /dev/null
+++ b/vendor/github.com/karalabe/hid/README.md
@@ -0,0 +1,47 @@
+[![Travis][travisimg]][travisurl]
+[![AppVeyor][appveyorimg]][appveyorurl]
+[![GoDoc][docimg]][docurl]
+
+[travisimg]: https://travis-ci.org/karalabe/hid.svg?branch=master
+[travisurl]: https://travis-ci.org/karalabe/hid
+[appveyorimg]: https://ci.appveyor.com/api/projects/status/plroy54odykb0ch3/branch/master?svg=true
+[appveyorurl]: https://ci.appveyor.com/project/karalabe/hid
+[docimg]: https://godoc.org/github.com/karalabe/hid?status.svg
+[docurl]: https://godoc.org/github.com/karalabe/hid
+
+# Gopher Interface Devices (USB HID)
+
+The `hid` package is a cross platform library for accessing and communicating with USB Human Interface
+Devices (HID). It is an alternative package to [`gousb`](https://github.com/karalabe/gousb) for use
+cases where devices support this ligher mode of operation (e.g. input devices, hardware crypto wallets).
+
+The package wraps [`hidapi`](https://github.com/signal11/hidapi) for accessing OS specific USB HID APIs
+directly instead of using low level USB constructs, which might have permission issues on some platforms.
+On Linux the package also wraps [`libusb`](https://github.com/libusb/libusb). Both of these dependencies
+are vendored directly into the repository and wrapped using CGO, making the `hid` package self-contained
+and go-gettable.
+
+Supported platforms at the moment are Linux, macOS and Windows (exclude constraints are also specified
+for Android and iOS to allow smoother vendoring into cross platform projects).
+
+## Acknowledgements
+
+Although the `hid` package is an implementation from scratch, it was heavily inspired by the existing
+[`go.hid`](https://github.com/GeertJohan/go.hid) library, which seems abandoned since 2015; is incompatible
+with Go 1.6+; and has various external dependencies. Given its inspirational roots, I thought it important
+to give credit to the author of said package too.
+
+Wide character support in the `hid` package is done via the [`gowchar`](https://github.com/orofarne/gowchar)
+library, unmaintained since 2013; non buildable with a modern Go release and failing `go vet` checks. As
+such, `gowchar` was also vendored in inline (copyright headers and origins preserved).
+
+## License
+
+The components of `hid` are licensed as such:
+
+ * `hidapi` is released under the [3-clause BSD](https://github.com/signal11/hidapi/blob/master/LICENSE-bsd.txt) license.
+ * `libusb` is released under the [GNU LGPL 2.1](https://github.com/libusb/libusb/blob/master/COPYING)license.
+ * `go.hid` is released under the [2-clause BSD](https://github.com/GeertJohan/go.hid/blob/master/LICENSE) license.
+ * `gowchar` is released under the [3-clause BSD](https://github.com/orofarne/gowchar/blob/master/LICENSE) license.
+
+Given the above, `hid` is licensed under GNU LGPL 2.1 or later on Linux and 3-clause BSD on other platforms.
diff --git a/vendor/github.com/karalabe/gousb/appveyor.yml b/vendor/github.com/karalabe/hid/appveyor.yml
similarity index 73%
rename from vendor/github.com/karalabe/gousb/appveyor.yml
rename to vendor/github.com/karalabe/hid/appveyor.yml
index b249862022..34623ddb01 100644
--- a/vendor/github.com/karalabe/gousb/appveyor.yml
+++ b/vendor/github.com/karalabe/hid/appveyor.yml
@@ -1,8 +1,8 @@
os: Visual Studio 2015
# Clone directly into GOPATH.
-clone_folder: C:\gopath\src\github.com\karalabe\gousb
-clone_depth: 5
+clone_folder: C:\gopath\src\github.com\karalabe\hid
+clone_depth: 1
version: "{branch}.{build}"
environment:
global:
@@ -22,13 +22,10 @@ environment:
install:
- rmdir C:\go /s /q
- - appveyor DownloadFile https://storage.googleapis.com/golang/go1.7.4.windows-%GOARCH%.zip
- - 7z x go1.7.4.windows-%GOARCH%.zip -y -oC:\ > NUL
+ - appveyor DownloadFile https://storage.googleapis.com/golang/go1.8.windows-%GOARCH%.zip
+ - 7z x go1.8.windows-%GOARCH%.zip -y -oC:\ > NUL
- go version
- gcc --version
build_script:
- go install ./...
-
-test_script:
- - go test -v -test.run="BCD|Parse" ./...
diff --git a/vendor/github.com/karalabe/hid/hid.go b/vendor/github.com/karalabe/hid/hid.go
new file mode 100644
index 0000000000..be75f949d8
--- /dev/null
+++ b/vendor/github.com/karalabe/hid/hid.go
@@ -0,0 +1,37 @@
+// hid - Gopher Interface Devices (USB HID)
+// Copyright (c) 2017 Péter Szilágyi. All rights reserved.
+//
+// This file is released under the 3-clause BSD license. Note however that Linux
+// support depends on libusb, released under GNU GPL 2.1 or later.
+
+// Package hid provides an interface for USB HID devices.
+package hid
+
+import "errors"
+
+// ErrDeviceClosed is returned for operations where the device closed before or
+// during the execution.
+var ErrDeviceClosed = errors.New("hid: device closed")
+
+// ErrUnsupportedPlatform is returned for all operations where the underlying
+// operating system is not supported by the library.
+var ErrUnsupportedPlatform = errors.New("hid: unsupported platform")
+
+// DeviceInfo is a hidapi info structure.
+type DeviceInfo struct {
+ Path string // Platform-specific device path
+ VendorID uint16 // Device Vendor ID
+ ProductID uint16 // Device Product ID
+ Release uint16 // Device Release Number in binary-coded decimal, also known as Device Version Number
+ Serial string // Serial Number
+ Manufacturer string // Manufacturer String
+ Product string // Product string
+ UsagePage uint16 // Usage Page for this Device/Interface (Windows/Mac only)
+ Usage uint16 // Usage for this Device/Interface (Windows/Mac only)
+
+ // The USB interface which this logical device
+ // represents. Valid on both Linux implementations
+ // in all cases, and valid on the Windows implementation
+ // only if the device contains more than one interface.
+ Interface int
+}
diff --git a/vendor/github.com/karalabe/hid/hid_disabled.go b/vendor/github.com/karalabe/hid/hid_disabled.go
new file mode 100644
index 0000000000..d8ecc9d5a2
--- /dev/null
+++ b/vendor/github.com/karalabe/hid/hid_disabled.go
@@ -0,0 +1,51 @@
+// hid - Gopher Interface Devices (USB HID)
+// Copyright (c) 2017 Péter Szilágyi. All rights reserved.
+//
+// This file is released under the 3-clause BSD license. Note however that Linux
+// support depends on libusb, released under GNU GPL 2.1 or later.
+
+// +build !linux,!darwin,!windows ios !cgo
+
+package hid
+
+// Supported returns whether this platform is supported by the HID library or not.
+// The goal of this method is to allow programatically handling platforms that do
+// not support USB HID and not having to fall back to build constraints.
+func Supported() bool {
+ return false
+}
+
+// Enumerate returns a list of all the HID devices attached to the system which
+// match the vendor and product id. On platforms that this file implements the
+// function is a noop and returns an empty list always.
+func Enumerate(vendorID uint16, productID uint16) []DeviceInfo {
+ return nil
+}
+
+// Device is a live HID USB connected device handle. On platforms that this file
+// implements the type lacks the actual HID device and all methods are noop.
+type Device struct {
+ DeviceInfo // Embed the infos for easier access
+}
+
+// Open connects to an HID device by its path name. On platforms that this file
+// implements the method just returns an error.
+func (info DeviceInfo) Open() (*Device, error) {
+ return nil, ErrUnsupportedPlatform
+}
+
+// Close releases the HID USB device handle. On platforms that this file implements
+// the method is just a noop.
+func (dev *Device) Close() {}
+
+// Write sends an output report to a HID device. On platforms that this file
+// implements the method just returns an error.
+func (dev *Device) Write(b []byte) (int, error) {
+ return 0, ErrUnsupportedPlatform
+}
+
+// Read retrieves an input report from a HID device. On platforms that this file
+// implements the method just returns an error.
+func (dev *Device) Read(b []byte) (int, error) {
+ return 0, ErrUnsupportedPlatform
+}
diff --git a/vendor/github.com/karalabe/hid/hid_enabled.go b/vendor/github.com/karalabe/hid/hid_enabled.go
new file mode 100644
index 0000000000..3ceecce0d3
--- /dev/null
+++ b/vendor/github.com/karalabe/hid/hid_enabled.go
@@ -0,0 +1,216 @@
+// hid - Gopher Interface Devices (USB HID)
+// Copyright (c) 2017 Péter Szilágyi. All rights reserved.
+//
+// This file is released under the 3-clause BSD license. Note however that Linux
+// support depends on libusb, released under GNU GPL 2.1 or later.
+
+// +build linux,cgo darwin,!ios,cgo windows,cgo
+
+package hid
+
+/*
+#cgo CFLAGS: -I./hidapi/hidapi
+
+#cgo linux CFLAGS: -I./libusb/libusb -DDEFAULT_VISIBILITY="" -DOS_LINUX -D_GNU_SOURCE -DPOLL_NFDS_TYPE=int
+#cgo linux,!android LDFLAGS: -lrt
+#cgo darwin CFLAGS: -DOS_DARWIN
+#cgo darwin LDFLAGS: -framework CoreFoundation -framework IOKit
+#cgo windows CFLAGS: -DOS_WINDOWS
+#cgo windows LDFLAGS: -lsetupapi
+
+#ifdef OS_LINUX
+ #include
+ #include "os/threads_posix.c"
+ #include "os/poll_posix.c"
+
+ #include "os/linux_usbfs.c"
+ #include "os/linux_netlink.c"
+
+ #include "core.c"
+ #include "descriptor.c"
+ #include "hotplug.c"
+ #include "io.c"
+ #include "strerror.c"
+ #include "sync.c"
+
+ #include "hidapi/libusb/hid.c"
+#elif OS_DARWIN
+ #include "hidapi/mac/hid.c"
+#elif OS_WINDOWS
+ #include "hidapi/windows/hid.c"
+#endif
+*/
+import "C"
+import (
+ "errors"
+ "runtime"
+ "sync"
+ "unsafe"
+)
+
+func init() {
+ // Initialize the HIDAPI library
+ C.hid_init()
+}
+
+// Supported returns whether this platform is supported by the HID library or not.
+// The goal of this method is to allow programatically handling platforms that do
+// not support USB HID and not having to fall back to build constraints.
+func Supported() bool {
+ return true
+}
+
+// Enumerate returns a list of all the HID devices attached to the system which
+// match the vendor and product id:
+// - If the vendor id is set to 0 then any vendor matches.
+// - If the product id is set to 0 then any product matches.
+// - If the vendor and product id are both 0, all HID devices are returned.
+func Enumerate(vendorID uint16, productID uint16) []DeviceInfo {
+ // Gather all device infos and ensure they are freed before returning
+ head := C.hid_enumerate(C.ushort(vendorID), C.ushort(productID))
+ if head == nil {
+ return nil
+ }
+ defer C.hid_free_enumeration(head)
+
+ // Iterate the list and retrieve the device details
+ var infos []DeviceInfo
+ for ; head != nil; head = head.next {
+ info := DeviceInfo{
+ Path: C.GoString(head.path),
+ VendorID: uint16(head.vendor_id),
+ ProductID: uint16(head.product_id),
+ Release: uint16(head.release_number),
+ UsagePage: uint16(head.usage_page),
+ Usage: uint16(head.usage),
+ Interface: int(head.interface_number),
+ }
+ if head.serial_number != nil {
+ info.Serial, _ = wcharTToString(head.serial_number)
+ }
+ if head.product_string != nil {
+ info.Product, _ = wcharTToString(head.product_string)
+ }
+ if head.manufacturer_string != nil {
+ info.Manufacturer, _ = wcharTToString(head.manufacturer_string)
+ }
+ infos = append(infos, info)
+ }
+ return infos
+}
+
+// Open connects to an HID device by its path name.
+func (info DeviceInfo) Open() (*Device, error) {
+ path := C.CString(info.Path)
+ defer C.free(unsafe.Pointer(path))
+
+ device := C.hid_open_path(path)
+ if device == nil {
+ return nil, errors.New("hidapi: failed to open device")
+ }
+ return &Device{
+ DeviceInfo: info,
+ device: device,
+ }, nil
+}
+
+// Device is a live HID USB connected device handle.
+type Device struct {
+ DeviceInfo // Embed the infos for easier access
+
+ device *C.hid_device // Low level HID device to communicate through
+ lock sync.Mutex
+}
+
+// Close releases the HID USB device handle.
+func (dev *Device) Close() {
+ dev.lock.Lock()
+ defer dev.lock.Unlock()
+
+ if dev.device != nil {
+ C.hid_close(dev.device)
+ dev.device = nil
+ }
+}
+
+// Write sends an output report to a HID device.
+//
+// Write will send the data on the first OUT endpoint, if one exists. If it does
+// not, it will send the data through the Control Endpoint (Endpoint 0).
+func (dev *Device) Write(b []byte) (int, error) {
+ // Abort if nothing to write
+ if len(b) == 0 {
+ return 0, nil
+ }
+ // Abort if device closed in between
+ dev.lock.Lock()
+ device := dev.device
+ dev.lock.Unlock()
+
+ if device == nil {
+ return 0, ErrDeviceClosed
+ }
+ // Prepend a HID report ID on Windows, other OSes don't need it
+ var report []byte
+ if runtime.GOOS == "windows" {
+ report = append([]byte{0x00}, b...)
+ } else {
+ report = b
+ }
+ // Execute the write operation
+ written := int(C.hid_write(device, (*C.uchar)(&report[0]), C.size_t(len(report))))
+ if written == -1 {
+ // If the write failed, verify if closed or other error
+ dev.lock.Lock()
+ device = dev.device
+ dev.lock.Unlock()
+
+ if device == nil {
+ return 0, ErrDeviceClosed
+ }
+ // Device not closed, some other error occurred
+ message := C.hid_error(device)
+ if message == nil {
+ return 0, errors.New("hidapi: unknown failure")
+ }
+ failure, _ := wcharTToString(message)
+ return 0, errors.New("hidapi: " + failure)
+ }
+ return written, nil
+}
+
+// Read retrieves an input report from a HID device.
+func (dev *Device) Read(b []byte) (int, error) {
+ // Aborth if nothing to read
+ if len(b) == 0 {
+ return 0, nil
+ }
+ // Abort if device closed in between
+ dev.lock.Lock()
+ device := dev.device
+ dev.lock.Unlock()
+
+ if device == nil {
+ return 0, ErrDeviceClosed
+ }
+ // Execute the read operation
+ read := int(C.hid_read(device, (*C.uchar)(&b[0]), C.size_t(len(b))))
+ if read == -1 {
+ // If the read failed, verify if closed or other error
+ dev.lock.Lock()
+ device = dev.device
+ dev.lock.Unlock()
+
+ if device == nil {
+ return 0, ErrDeviceClosed
+ }
+ // Device not closed, some other error occurred
+ message := C.hid_error(device)
+ if message == nil {
+ return 0, errors.New("hidapi: unknown failure")
+ }
+ failure, _ := wcharTToString(message)
+ return 0, errors.New("hidapi: " + failure)
+ }
+ return read, nil
+}
diff --git a/vendor/github.com/karalabe/hid/hidapi/AUTHORS.txt b/vendor/github.com/karalabe/hid/hidapi/AUTHORS.txt
new file mode 100644
index 0000000000..7acafd78c3
--- /dev/null
+++ b/vendor/github.com/karalabe/hid/hidapi/AUTHORS.txt
@@ -0,0 +1,16 @@
+
+HIDAPI Authors:
+
+Alan Ott :
+ Original Author and Maintainer
+ Linux, Windows, and Mac implementations
+
+Ludovic Rousseau :
+ Formatting for Doxygen documentation
+ Bug fixes
+ Correctness fixes
+
+
+For a comprehensive list of contributions, see the commit list at github:
+ http://github.com/signal11/hidapi/commits/master
+
diff --git a/vendor/github.com/karalabe/hid/hidapi/LICENSE-bsd.txt b/vendor/github.com/karalabe/hid/hidapi/LICENSE-bsd.txt
new file mode 100644
index 0000000000..538cdf95cf
--- /dev/null
+++ b/vendor/github.com/karalabe/hid/hidapi/LICENSE-bsd.txt
@@ -0,0 +1,26 @@
+Copyright (c) 2010, Alan Ott, Signal 11 Software
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of Signal 11 Software nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
diff --git a/vendor/github.com/karalabe/hid/hidapi/LICENSE-gpl3.txt b/vendor/github.com/karalabe/hid/hidapi/LICENSE-gpl3.txt
new file mode 100644
index 0000000000..94a9ed024d
--- /dev/null
+++ b/vendor/github.com/karalabe/hid/hidapi/LICENSE-gpl3.txt
@@ -0,0 +1,674 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+
+ Copyright (C)
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ Copyright (C)
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+.
diff --git a/vendor/github.com/karalabe/hid/hidapi/LICENSE-orig.txt b/vendor/github.com/karalabe/hid/hidapi/LICENSE-orig.txt
new file mode 100644
index 0000000000..e3f3380829
--- /dev/null
+++ b/vendor/github.com/karalabe/hid/hidapi/LICENSE-orig.txt
@@ -0,0 +1,9 @@
+ HIDAPI - Multi-Platform library for
+ communication with HID devices.
+
+ Copyright 2009, Alan Ott, Signal 11 Software.
+ All Rights Reserved.
+
+ This software may be used by anyone for any reason so
+ long as the copyright notice in the source files
+ remains intact.
diff --git a/vendor/github.com/karalabe/hid/hidapi/LICENSE.txt b/vendor/github.com/karalabe/hid/hidapi/LICENSE.txt
new file mode 100644
index 0000000000..e1676d4c42
--- /dev/null
+++ b/vendor/github.com/karalabe/hid/hidapi/LICENSE.txt
@@ -0,0 +1,13 @@
+HIDAPI can be used under one of three licenses.
+
+1. The GNU General Public License, version 3.0, in LICENSE-gpl3.txt
+2. A BSD-Style License, in LICENSE-bsd.txt.
+3. The more liberal original HIDAPI license. LICENSE-orig.txt
+
+The license chosen is at the discretion of the user of HIDAPI. For example:
+1. An author of GPL software would likely use HIDAPI under the terms of the
+GPL.
+
+2. An author of commercial closed-source software would likely use HIDAPI
+under the terms of the BSD-style license or the original HIDAPI license.
+
diff --git a/vendor/github.com/karalabe/hid/hidapi/README.txt b/vendor/github.com/karalabe/hid/hidapi/README.txt
new file mode 100644
index 0000000000..f19dae4ab7
--- /dev/null
+++ b/vendor/github.com/karalabe/hid/hidapi/README.txt
@@ -0,0 +1,339 @@
+ HIDAPI library for Windows, Linux, FreeBSD and Mac OS X
+ =========================================================
+
+About
+======
+
+HIDAPI is a multi-platform library which allows an application to interface
+with USB and Bluetooth HID-Class devices on Windows, Linux, FreeBSD, and Mac
+OS X. HIDAPI can be either built as a shared library (.so or .dll) or
+can be embedded directly into a target application by adding a single source
+file (per platform) and a single header.
+
+HIDAPI has four back-ends:
+ * Windows (using hid.dll)
+ * Linux/hidraw (using the Kernel's hidraw driver)
+ * Linux/libusb (using libusb-1.0)
+ * FreeBSD (using libusb-1.0)
+ * Mac (using IOHidManager)
+
+On Linux, either the hidraw or the libusb back-end can be used. There are
+tradeoffs, and the functionality supported is slightly different.
+
+Linux/hidraw (linux/hid.c):
+This back-end uses the hidraw interface in the Linux kernel. While this
+back-end will support both USB and Bluetooth, it has some limitations on
+kernels prior to 2.6.39, including the inability to send or receive feature
+reports. In addition, it will only communicate with devices which have
+hidraw nodes associated with them. Keyboards, mice, and some other devices
+which are blacklisted from having hidraw nodes will not work. Fortunately,
+for nearly all the uses of hidraw, this is not a problem.
+
+Linux/FreeBSD/libusb (libusb/hid.c):
+This back-end uses libusb-1.0 to communicate directly to a USB device. This
+back-end will of course not work with Bluetooth devices.
+
+HIDAPI also comes with a Test GUI. The Test GUI is cross-platform and uses
+Fox Toolkit (http://www.fox-toolkit.org). It will build on every platform
+which HIDAPI supports. Since it relies on a 3rd party library, building it
+is optional but recommended because it is so useful when debugging hardware.
+
+What Does the API Look Like?
+=============================
+The API provides the the most commonly used HID functions including sending
+and receiving of input, output, and feature reports. The sample program,
+which communicates with a heavily hacked up version of the Microchip USB
+Generic HID sample looks like this (with error checking removed for
+simplicity):
+
+#ifdef WIN32
+#include
+#endif
+#include
+#include
+#include "hidapi.h"
+
+#define MAX_STR 255
+
+int main(int argc, char* argv[])
+{
+ int res;
+ unsigned char buf[65];
+ wchar_t wstr[MAX_STR];
+ hid_device *handle;
+ int i;
+
+ // Initialize the hidapi library
+ res = hid_init();
+
+ // Open the device using the VID, PID,
+ // and optionally the Serial number.
+ handle = hid_open(0x4d8, 0x3f, NULL);
+
+ // Read the Manufacturer String
+ res = hid_get_manufacturer_string(handle, wstr, MAX_STR);
+ wprintf(L"Manufacturer String: %s\n", wstr);
+
+ // Read the Product String
+ res = hid_get_product_string(handle, wstr, MAX_STR);
+ wprintf(L"Product String: %s\n", wstr);
+
+ // Read the Serial Number String
+ res = hid_get_serial_number_string(handle, wstr, MAX_STR);
+ wprintf(L"Serial Number String: (%d) %s\n", wstr[0], wstr);
+
+ // Read Indexed String 1
+ res = hid_get_indexed_string(handle, 1, wstr, MAX_STR);
+ wprintf(L"Indexed String 1: %s\n", wstr);
+
+ // Toggle LED (cmd 0x80). The first byte is the report number (0x0).
+ buf[0] = 0x0;
+ buf[1] = 0x80;
+ res = hid_write(handle, buf, 65);
+
+ // Request state (cmd 0x81). The first byte is the report number (0x0).
+ buf[0] = 0x0;
+ buf[1] = 0x81;
+ res = hid_write(handle, buf, 65);
+
+ // Read requested state
+ res = hid_read(handle, buf, 65);
+
+ // Print out the returned buffer.
+ for (i = 0; i < 4; i++)
+ printf("buf[%d]: %d\n", i, buf[i]);
+
+ // Finalize the hidapi library
+ res = hid_exit();
+
+ return 0;
+}
+
+If you have your own simple test programs which communicate with standard
+hardware development boards (such as those from Microchip, TI, Atmel,
+FreeScale and others), please consider sending me something like the above
+for inclusion into the HIDAPI source. This will help others who have the
+same hardware as you do.
+
+License
+========
+HIDAPI may be used by one of three licenses as outlined in LICENSE.txt.
+
+Download
+=========
+HIDAPI can be downloaded from github
+ git clone git://github.com/signal11/hidapi.git
+
+Build Instructions
+===================
+
+This section is long. Don't be put off by this. It's not long because it's
+complicated to build HIDAPI; it's quite the opposite. This section is long
+because of the flexibility of HIDAPI and the large number of ways in which
+it can be built and used. You will likely pick a single build method.
+
+HIDAPI can be built in several different ways. If you elect to build a
+shared library, you will need to build it from the HIDAPI source
+distribution. If you choose instead to embed HIDAPI directly into your
+application, you can skip the building and look at the provided platform
+Makefiles for guidance. These platform Makefiles are located in linux/
+libusb/ mac/ and windows/ and are called Makefile-manual. In addition,
+Visual Studio projects are provided. Even if you're going to embed HIDAPI
+into your project, it is still beneficial to build the example programs.
+
+
+Prerequisites:
+---------------
+
+ Linux:
+ -------
+ On Linux, you will need to install development packages for libudev,
+ libusb and optionally Fox-toolkit (for the test GUI). On
+ Debian/Ubuntu systems these can be installed by running:
+ sudo apt-get install libudev-dev libusb-1.0-0-dev libfox-1.6-dev
+
+ If you downloaded the source directly from the git repository (using
+ git clone), you'll need Autotools:
+ sudo apt-get install autotools-dev autoconf automake libtool
+
+ FreeBSD:
+ ---------
+ On FreeBSD you will need to install GNU make, libiconv, and
+ optionally Fox-Toolkit (for the test GUI). This is done by running
+ the following:
+ pkg_add -r gmake libiconv fox16
+
+ If you downloaded the source directly from the git repository (using
+ git clone), you'll need Autotools:
+ pkg_add -r autotools
+
+ Mac:
+ -----
+ On Mac, you will need to install Fox-Toolkit if you wish to build
+ the Test GUI. There are two ways to do this, and each has a slight
+ complication. Which method you use depends on your use case.
+
+ If you wish to build the Test GUI just for your own testing on your
+ own computer, then the easiest method is to install Fox-Toolkit
+ using ports:
+ sudo port install fox
+
+ If you wish to build the TestGUI app bundle to redistribute to
+ others, you will need to install Fox-toolkit from source. This is
+ because the version of fox that gets installed using ports uses the
+ ports X11 libraries which are not compatible with the Apple X11
+ libraries. If you install Fox with ports and then try to distribute
+ your built app bundle, it will simply fail to run on other systems.
+ To install Fox-Toolkit manually, download the source package from
+ http://www.fox-toolkit.org, extract it, and run the following from
+ within the extracted source:
+ ./configure && make && make install
+
+ Windows:
+ ---------
+ On Windows, if you want to build the test GUI, you will need to get
+ the hidapi-externals.zip package from the download site. This
+ contains pre-built binaries for Fox-toolkit. Extract
+ hidapi-externals.zip just outside of hidapi, so that
+ hidapi-externals and hidapi are on the same level, as shown:
+
+ Parent_Folder
+ |
+ +hidapi
+ +hidapi-externals
+
+ Again, this step is not required if you do not wish to build the
+ test GUI.
+
+
+Building HIDAPI into a shared library on Unix Platforms:
+---------------------------------------------------------
+
+On Unix-like systems such as Linux, FreeBSD, Mac, and even Windows, using
+Mingw or Cygwin, the easiest way to build a standard system-installed shared
+library is to use the GNU Autotools build system. If you checked out the
+source from the git repository, run the following:
+
+ ./bootstrap
+ ./configure
+ make
+ make install <----- as root, or using sudo
+
+If you downloaded a source package (ie: if you did not run git clone), you
+can skip the ./bootstrap step.
+
+./configure can take several arguments which control the build. The two most
+likely to be used are:
+ --enable-testgui
+ Enable build of the Test GUI. This requires Fox toolkit to
+ be installed. Instructions for installing Fox-Toolkit on
+ each platform are in the Prerequisites section above.
+
+ --prefix=/usr
+ Specify where you want the output headers and libraries to
+ be installed. The example above will put the headers in
+ /usr/include and the binaries in /usr/lib. The default is to
+ install into /usr/local which is fine on most systems.
+
+Building the manual way on Unix platforms:
+-------------------------------------------
+
+Manual Makefiles are provided mostly to give the user and idea what it takes
+to build a program which embeds HIDAPI directly inside of it. These should
+really be used as examples only. If you want to build a system-wide shared
+library, use the Autotools method described above.
+
+ To build HIDAPI using the manual makefiles, change to the directory
+ of your platform and run make. For example, on Linux run:
+ cd linux/
+ make -f Makefile-manual
+
+ To build the Test GUI using the manual makefiles:
+ cd testgui/
+ make -f Makefile-manual
+
+Building on Windows:
+---------------------
+
+To build the HIDAPI DLL on Windows using Visual Studio, build the .sln file
+in the windows/ directory.
+
+To build the Test GUI on windows using Visual Studio, build the .sln file in
+the testgui/ directory.
+
+To build HIDAPI using MinGW or Cygwin using Autotools, use the instructions
+in the section titled "Building HIDAPI into a shared library on Unix
+Platforms" above. Note that building the Test GUI with MinGW or Cygwin will
+require the Windows procedure in the Prerequisites section above (ie:
+hidapi-externals.zip).
+
+To build HIDAPI using MinGW using the Manual Makefiles, see the section
+"Building the manual way on Unix platforms" above.
+
+HIDAPI can also be built using the Windows DDK (now also called the Windows
+Driver Kit or WDK). This method was originally required for the HIDAPI build
+but not anymore. However, some users still prefer this method. It is not as
+well supported anymore but should still work. Patches are welcome if it does
+not. To build using the DDK:
+
+ 1. Install the Windows Driver Kit (WDK) from Microsoft.
+ 2. From the Start menu, in the Windows Driver Kits folder, select Build
+ Environments, then your operating system, then the x86 Free Build
+ Environment (or one that is appropriate for your system).
+ 3. From the console, change directory to the windows/ddk_build/ directory,
+ which is part of the HIDAPI distribution.
+ 4. Type build.
+ 5. You can find the output files (DLL and LIB) in a subdirectory created
+ by the build system which is appropriate for your environment. On
+ Windows XP, this directory is objfre_wxp_x86/i386.
+
+Cross Compiling
+================
+
+This section talks about cross compiling HIDAPI for Linux using autotools.
+This is useful for using HIDAPI on embedded Linux targets. These
+instructions assume the most raw kind of embedded Linux build, where all
+prerequisites will need to be built first. This process will of course vary
+based on your embedded Linux build system if you are using one, such as
+OpenEmbedded or Buildroot.
+
+For the purpose of this section, it will be assumed that the following
+environment variables are exported.
+
+ $ export STAGING=$HOME/out
+ $ export HOST=arm-linux
+
+STAGING and HOST can be modified to suit your setup.
+
+Prerequisites
+--------------
+
+Note that the build of libudev is the very basic configuration.
+
+Build Libusb. From the libusb source directory, run:
+ ./configure --host=$HOST --prefix=$STAGING
+ make
+ make install
+
+Build libudev. From the libudev source directory, run:
+ ./configure --disable-gudev --disable-introspection --disable-hwdb \
+ --host=$HOST --prefix=$STAGING
+ make
+ make install
+
+Building HIDAPI
+----------------
+
+Build HIDAPI:
+
+ PKG_CONFIG_DIR= \
+ PKG_CONFIG_LIBDIR=$STAGING/lib/pkgconfig:$STAGING/share/pkgconfig \
+ PKG_CONFIG_SYSROOT_DIR=$STAGING \
+ ./configure --host=$HOST --prefix=$STAGING
+
+
+Signal 11 Software - 2010-04-11
+ 2010-07-28
+ 2011-09-10
+ 2012-05-01
+ 2012-07-03
diff --git a/vendor/github.com/karalabe/hid/hidapi/hidapi/hidapi.h b/vendor/github.com/karalabe/hid/hidapi/hidapi/hidapi.h
new file mode 100644
index 0000000000..e5bc2dc40a
--- /dev/null
+++ b/vendor/github.com/karalabe/hid/hidapi/hidapi/hidapi.h
@@ -0,0 +1,391 @@
+/*******************************************************
+ HIDAPI - Multi-Platform library for
+ communication with HID devices.
+
+ Alan Ott
+ Signal 11 Software
+
+ 8/22/2009
+
+ Copyright 2009, All Rights Reserved.
+
+ At the discretion of the user of this library,
+ this software may be licensed under the terms of the
+ GNU General Public License v3, a BSD-Style license, or the
+ original HIDAPI license as outlined in the LICENSE.txt,
+ LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt
+ files located at the root of the source distribution.
+ These files may also be found in the public source
+ code repository located at:
+ http://github.com/signal11/hidapi .
+********************************************************/
+
+/** @file
+ * @defgroup API hidapi API
+ */
+
+#ifndef HIDAPI_H__
+#define HIDAPI_H__
+
+#include
+
+#ifdef _WIN32
+ #define HID_API_EXPORT __declspec(dllexport)
+ #define HID_API_CALL
+#else
+ #define HID_API_EXPORT /**< API export macro */
+ #define HID_API_CALL /**< API call macro */
+#endif
+
+#define HID_API_EXPORT_CALL HID_API_EXPORT HID_API_CALL /**< API export and call macro*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ struct hid_device_;
+ typedef struct hid_device_ hid_device; /**< opaque hidapi structure */
+
+ /** hidapi info structure */
+ struct hid_device_info {
+ /** Platform-specific device path */
+ char *path;
+ /** Device Vendor ID */
+ unsigned short vendor_id;
+ /** Device Product ID */
+ unsigned short product_id;
+ /** Serial Number */
+ wchar_t *serial_number;
+ /** Device Release Number in binary-coded decimal,
+ also known as Device Version Number */
+ unsigned short release_number;
+ /** Manufacturer String */
+ wchar_t *manufacturer_string;
+ /** Product string */
+ wchar_t *product_string;
+ /** Usage Page for this Device/Interface
+ (Windows/Mac only). */
+ unsigned short usage_page;
+ /** Usage for this Device/Interface
+ (Windows/Mac only).*/
+ unsigned short usage;
+ /** The USB interface which this logical device
+ represents. Valid on both Linux implementations
+ in all cases, and valid on the Windows implementation
+ only if the device contains more than one interface. */
+ int interface_number;
+
+ /** Pointer to the next device */
+ struct hid_device_info *next;
+ };
+
+
+ /** @brief Initialize the HIDAPI library.
+
+ This function initializes the HIDAPI library. Calling it is not
+ strictly necessary, as it will be called automatically by
+ hid_enumerate() and any of the hid_open_*() functions if it is
+ needed. This function should be called at the beginning of
+ execution however, if there is a chance of HIDAPI handles
+ being opened by different threads simultaneously.
+
+ @ingroup API
+
+ @returns
+ This function returns 0 on success and -1 on error.
+ */
+ int HID_API_EXPORT HID_API_CALL hid_init(void);
+
+ /** @brief Finalize the HIDAPI library.
+
+ This function frees all of the static data associated with
+ HIDAPI. It should be called at the end of execution to avoid
+ memory leaks.
+
+ @ingroup API
+
+ @returns
+ This function returns 0 on success and -1 on error.
+ */
+ int HID_API_EXPORT HID_API_CALL hid_exit(void);
+
+ /** @brief Enumerate the HID Devices.
+
+ This function returns a linked list of all the HID devices
+ attached to the system which match vendor_id and product_id.
+ If @p vendor_id is set to 0 then any vendor matches.
+ If @p product_id is set to 0 then any product matches.
+ If @p vendor_id and @p product_id are both set to 0, then
+ all HID devices will be returned.
+
+ @ingroup API
+ @param vendor_id The Vendor ID (VID) of the types of device
+ to open.
+ @param product_id The Product ID (PID) of the types of
+ device to open.
+
+ @returns
+ This function returns a pointer to a linked list of type
+ struct #hid_device, containing information about the HID devices
+ attached to the system, or NULL in the case of failure. Free
+ this linked list by calling hid_free_enumeration().
+ */
+ struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned short vendor_id, unsigned short product_id);
+
+ /** @brief Free an enumeration Linked List
+
+ This function frees a linked list created by hid_enumerate().
+
+ @ingroup API
+ @param devs Pointer to a list of struct_device returned from
+ hid_enumerate().
+ */
+ void HID_API_EXPORT HID_API_CALL hid_free_enumeration(struct hid_device_info *devs);
+
+ /** @brief Open a HID device using a Vendor ID (VID), Product ID
+ (PID) and optionally a serial number.
+
+ If @p serial_number is NULL, the first device with the
+ specified VID and PID is opened.
+
+ @ingroup API
+ @param vendor_id The Vendor ID (VID) of the device to open.
+ @param product_id The Product ID (PID) of the device to open.
+ @param serial_number The Serial Number of the device to open
+ (Optionally NULL).
+
+ @returns
+ This function returns a pointer to a #hid_device object on
+ success or NULL on failure.
+ */
+ HID_API_EXPORT hid_device * HID_API_CALL hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number);
+
+ /** @brief Open a HID device by its path name.
+
+ The path name be determined by calling hid_enumerate(), or a
+ platform-specific path name can be used (eg: /dev/hidraw0 on
+ Linux).
+
+ @ingroup API
+ @param path The path name of the device to open
+
+ @returns
+ This function returns a pointer to a #hid_device object on
+ success or NULL on failure.
+ */
+ HID_API_EXPORT hid_device * HID_API_CALL hid_open_path(const char *path);
+
+ /** @brief Write an Output report to a HID device.
+
+ The first byte of @p data[] must contain the Report ID. For
+ devices which only support a single report, this must be set
+ to 0x0. The remaining bytes contain the report data. Since
+ the Report ID is mandatory, calls to hid_write() will always
+ contain one more byte than the report contains. For example,
+ if a hid report is 16 bytes long, 17 bytes must be passed to
+ hid_write(), the Report ID (or 0x0, for devices with a
+ single report), followed by the report data (16 bytes). In
+ this example, the length passed in would be 17.
+
+ hid_write() will send the data on the first OUT endpoint, if
+ one exists. If it does not, it will send the data through
+ the Control Endpoint (Endpoint 0).
+
+ @ingroup API
+ @param device A device handle returned from hid_open().
+ @param data The data to send, including the report number as
+ the first byte.
+ @param length The length in bytes of the data to send.
+
+ @returns
+ This function returns the actual number of bytes written and
+ -1 on error.
+ */
+ int HID_API_EXPORT HID_API_CALL hid_write(hid_device *device, const unsigned char *data, size_t length);
+
+ /** @brief Read an Input report from a HID device with timeout.
+
+ Input reports are returned
+ to the host through the INTERRUPT IN endpoint. The first byte will
+ contain the Report number if the device uses numbered reports.
+
+ @ingroup API
+ @param device A device handle returned from hid_open().
+ @param data A buffer to put the read data into.
+ @param length The number of bytes to read. For devices with
+ multiple reports, make sure to read an extra byte for
+ the report number.
+ @param milliseconds timeout in milliseconds or -1 for blocking wait.
+
+ @returns
+ This function returns the actual number of bytes read and
+ -1 on error. If no packet was available to be read within
+ the timeout period, this function returns 0.
+ */
+ int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds);
+
+ /** @brief Read an Input report from a HID device.
+
+ Input reports are returned
+ to the host through the INTERRUPT IN endpoint. The first byte will
+ contain the Report number if the device uses numbered reports.
+
+ @ingroup API
+ @param device A device handle returned from hid_open().
+ @param data A buffer to put the read data into.
+ @param length The number of bytes to read. For devices with
+ multiple reports, make sure to read an extra byte for
+ the report number.
+
+ @returns
+ This function returns the actual number of bytes read and
+ -1 on error. If no packet was available to be read and
+ the handle is in non-blocking mode, this function returns 0.
+ */
+ int HID_API_EXPORT HID_API_CALL hid_read(hid_device *device, unsigned char *data, size_t length);
+
+ /** @brief Set the device handle to be non-blocking.
+
+ In non-blocking mode calls to hid_read() will return
+ immediately with a value of 0 if there is no data to be
+ read. In blocking mode, hid_read() will wait (block) until
+ there is data to read before returning.
+
+ Nonblocking can be turned on and off at any time.
+
+ @ingroup API
+ @param device A device handle returned from hid_open().
+ @param nonblock enable or not the nonblocking reads
+ - 1 to enable nonblocking
+ - 0 to disable nonblocking.
+
+ @returns
+ This function returns 0 on success and -1 on error.
+ */
+ int HID_API_EXPORT HID_API_CALL hid_set_nonblocking(hid_device *device, int nonblock);
+
+ /** @brief Send a Feature report to the device.
+
+ Feature reports are sent over the Control endpoint as a
+ Set_Report transfer. The first byte of @p data[] must
+ contain the Report ID. For devices which only support a
+ single report, this must be set to 0x0. The remaining bytes
+ contain the report data. Since the Report ID is mandatory,
+ calls to hid_send_feature_report() will always contain one
+ more byte than the report contains. For example, if a hid
+ report is 16 bytes long, 17 bytes must be passed to
+ hid_send_feature_report(): the Report ID (or 0x0, for
+ devices which do not use numbered reports), followed by the
+ report data (16 bytes). In this example, the length passed
+ in would be 17.
+
+ @ingroup API
+ @param device A device handle returned from hid_open().
+ @param data The data to send, including the report number as
+ the first byte.
+ @param length The length in bytes of the data to send, including
+ the report number.
+
+ @returns
+ This function returns the actual number of bytes written and
+ -1 on error.
+ */
+ int HID_API_EXPORT HID_API_CALL hid_send_feature_report(hid_device *device, const unsigned char *data, size_t length);
+
+ /** @brief Get a feature report from a HID device.
+
+ Set the first byte of @p data[] to the Report ID of the
+ report to be read. Make sure to allow space for this
+ extra byte in @p data[]. Upon return, the first byte will
+ still contain the Report ID, and the report data will
+ start in data[1].
+
+ @ingroup API
+ @param device A device handle returned from hid_open().
+ @param data A buffer to put the read data into, including
+ the Report ID. Set the first byte of @p data[] to the
+ Report ID of the report to be read, or set it to zero
+ if your device does not use numbered reports.
+ @param length The number of bytes to read, including an
+ extra byte for the report ID. The buffer can be longer
+ than the actual report.
+
+ @returns
+ This function returns the number of bytes read plus
+ one for the report ID (which is still in the first
+ byte), or -1 on error.
+ */
+ int HID_API_EXPORT HID_API_CALL hid_get_feature_report(hid_device *device, unsigned char *data, size_t length);
+
+ /** @brief Close a HID device.
+
+ @ingroup API
+ @param device A device handle returned from hid_open().
+ */
+ void HID_API_EXPORT HID_API_CALL hid_close(hid_device *device);
+
+ /** @brief Get The Manufacturer String from a HID device.
+
+ @ingroup API
+ @param device A device handle returned from hid_open().
+ @param string A wide string buffer to put the data into.
+ @param maxlen The length of the buffer in multiples of wchar_t.
+
+ @returns
+ This function returns 0 on success and -1 on error.
+ */
+ int HID_API_EXPORT_CALL hid_get_manufacturer_string(hid_device *device, wchar_t *string, size_t maxlen);
+
+ /** @brief Get The Product String from a HID device.
+
+ @ingroup API
+ @param device A device handle returned from hid_open().
+ @param string A wide string buffer to put the data into.
+ @param maxlen The length of the buffer in multiples of wchar_t.
+
+ @returns
+ This function returns 0 on success and -1 on error.
+ */
+ int HID_API_EXPORT_CALL hid_get_product_string(hid_device *device, wchar_t *string, size_t maxlen);
+
+ /** @brief Get The Serial Number String from a HID device.
+
+ @ingroup API
+ @param device A device handle returned from hid_open().
+ @param string A wide string buffer to put the data into.
+ @param maxlen The length of the buffer in multiples of wchar_t.
+
+ @returns
+ This function returns 0 on success and -1 on error.
+ */
+ int HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *device, wchar_t *string, size_t maxlen);
+
+ /** @brief Get a string from a HID device, based on its string index.
+
+ @ingroup API
+ @param device A device handle returned from hid_open().
+ @param string_index The index of the string to get.
+ @param string A wide string buffer to put the data into.
+ @param maxlen The length of the buffer in multiples of wchar_t.
+
+ @returns
+ This function returns 0 on success and -1 on error.
+ */
+ int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *device, int string_index, wchar_t *string, size_t maxlen);
+
+ /** @brief Get a string describing the last error which occurred.
+
+ @ingroup API
+ @param device A device handle returned from hid_open().
+
+ @returns
+ This function returns a string containing the last error
+ which occurred or NULL if none has occurred.
+ */
+ HID_API_EXPORT const wchar_t* HID_API_CALL hid_error(hid_device *device);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/vendor/github.com/karalabe/hid/hidapi/libusb/hid.c b/vendor/github.com/karalabe/hid/hidapi/libusb/hid.c
new file mode 100644
index 0000000000..474dff41c1
--- /dev/null
+++ b/vendor/github.com/karalabe/hid/hidapi/libusb/hid.c
@@ -0,0 +1,1512 @@
+/*******************************************************
+ HIDAPI - Multi-Platform library for
+ communication with HID devices.
+
+ Alan Ott
+ Signal 11 Software
+
+ 8/22/2009
+ Linux Version - 6/2/2010
+ Libusb Version - 8/13/2010
+ FreeBSD Version - 11/1/2011
+
+ Copyright 2009, All Rights Reserved.
+
+ At the discretion of the user of this library,
+ this software may be licensed under the terms of the
+ GNU General Public License v3, a BSD-Style license, or the
+ original HIDAPI license as outlined in the LICENSE.txt,
+ LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt
+ files located at the root of the source distribution.
+ These files may also be found in the public source
+ code repository located at:
+ http://github.com/signal11/hidapi .
+********************************************************/
+
+/* C */
+#include
+#include
+#include
+#include
+#include
+#include
+
+/* Unix */
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+/* GNU / LibUSB */
+#include
+#ifndef __ANDROID__
+#include
+#endif
+
+#include "hidapi.h"
+
+#ifdef __ANDROID__
+
+/* Barrier implementation because Android/Bionic don't have pthread_barrier.
+ This implementation came from Brent Priddy and was posted on
+ StackOverflow. It is used with his permission. */
+typedef int pthread_barrierattr_t;
+typedef struct pthread_barrier {
+ pthread_mutex_t mutex;
+ pthread_cond_t cond;
+ int count;
+ int trip_count;
+} pthread_barrier_t;
+
+static int pthread_barrier_init(pthread_barrier_t *barrier, const pthread_barrierattr_t *attr, unsigned int count)
+{
+ if(count == 0) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if(pthread_mutex_init(&barrier->mutex, 0) < 0) {
+ return -1;
+ }
+ if(pthread_cond_init(&barrier->cond, 0) < 0) {
+ pthread_mutex_destroy(&barrier->mutex);
+ return -1;
+ }
+ barrier->trip_count = count;
+ barrier->count = 0;
+
+ return 0;
+}
+
+static int pthread_barrier_destroy(pthread_barrier_t *barrier)
+{
+ pthread_cond_destroy(&barrier->cond);
+ pthread_mutex_destroy(&barrier->mutex);
+ return 0;
+}
+
+static int pthread_barrier_wait(pthread_barrier_t *barrier)
+{
+ pthread_mutex_lock(&barrier->mutex);
+ ++(barrier->count);
+ if(barrier->count >= barrier->trip_count)
+ {
+ barrier->count = 0;
+ pthread_cond_broadcast(&barrier->cond);
+ pthread_mutex_unlock(&barrier->mutex);
+ return 1;
+ }
+ else
+ {
+ pthread_cond_wait(&barrier->cond, &(barrier->mutex));
+ pthread_mutex_unlock(&barrier->mutex);
+ return 0;
+ }
+}
+
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef DEBUG_PRINTF
+#define LOG(...) fprintf(stderr, __VA_ARGS__)
+#else
+#define LOG(...) do {} while (0)
+#endif
+
+#ifndef __FreeBSD__
+#define DETACH_KERNEL_DRIVER
+#endif
+
+/* Uncomment to enable the retrieval of Usage and Usage Page in
+hid_enumerate(). Warning, on platforms different from FreeBSD
+this is very invasive as it requires the detach
+and re-attach of the kernel driver. See comments inside hid_enumerate().
+libusb HIDAPI programs are encouraged to use the interface number
+instead to differentiate between interfaces on a composite HID device. */
+/*#define INVASIVE_GET_USAGE*/
+
+/* Linked List of input reports received from the device. */
+struct input_report {
+ uint8_t *data;
+ size_t len;
+ struct input_report *next;
+};
+
+
+struct hid_device_ {
+ /* Handle to the actual device. */
+ libusb_device_handle *device_handle;
+
+ /* Endpoint information */
+ int input_endpoint;
+ int output_endpoint;
+ int input_ep_max_packet_size;
+
+ /* The interface number of the HID */
+ int interface;
+
+ /* Indexes of Strings */
+ int manufacturer_index;
+ int product_index;
+ int serial_index;
+
+ /* Whether blocking reads are used */
+ int blocking; /* boolean */
+
+ /* Read thread objects */
+ pthread_t thread;
+ pthread_mutex_t mutex; /* Protects input_reports */
+ pthread_cond_t condition;
+ pthread_barrier_t barrier; /* Ensures correct startup sequence */
+ int shutdown_thread;
+ int cancelled;
+ struct libusb_transfer *transfer;
+
+ /* List of received input reports. */
+ struct input_report *input_reports;
+};
+
+static libusb_context *usb_context = NULL;
+
+uint16_t get_usb_code_for_current_locale(void);
+static int return_data(hid_device *dev, unsigned char *data, size_t length);
+
+static hid_device *new_hid_device(void)
+{
+ hid_device *dev = calloc(1, sizeof(hid_device));
+ dev->blocking = 1;
+
+ pthread_mutex_init(&dev->mutex, NULL);
+ pthread_cond_init(&dev->condition, NULL);
+ pthread_barrier_init(&dev->barrier, NULL, 2);
+
+ return dev;
+}
+
+static void free_hid_device(hid_device *dev)
+{
+ /* Clean up the thread objects */
+ pthread_barrier_destroy(&dev->barrier);
+ pthread_cond_destroy(&dev->condition);
+ pthread_mutex_destroy(&dev->mutex);
+
+ /* Free the device itself */
+ free(dev);
+}
+
+#if 0
+/*TODO: Implement this funciton on hidapi/libusb.. */
+static void register_error(hid_device *device, const char *op)
+{
+
+}
+#endif
+
+#ifdef INVASIVE_GET_USAGE
+/* Get bytes from a HID Report Descriptor.
+ Only call with a num_bytes of 0, 1, 2, or 4. */
+static uint32_t get_bytes(uint8_t *rpt, size_t len, size_t num_bytes, size_t cur)
+{
+ /* Return if there aren't enough bytes. */
+ if (cur + num_bytes >= len)
+ return 0;
+
+ if (num_bytes == 0)
+ return 0;
+ else if (num_bytes == 1) {
+ return rpt[cur+1];
+ }
+ else if (num_bytes == 2) {
+ return (rpt[cur+2] * 256 + rpt[cur+1]);
+ }
+ else if (num_bytes == 4) {
+ return (rpt[cur+4] * 0x01000000 +
+ rpt[cur+3] * 0x00010000 +
+ rpt[cur+2] * 0x00000100 +
+ rpt[cur+1] * 0x00000001);
+ }
+ else
+ return 0;
+}
+
+/* Retrieves the device's Usage Page and Usage from the report
+ descriptor. The algorithm is simple, as it just returns the first
+ Usage and Usage Page that it finds in the descriptor.
+ The return value is 0 on success and -1 on failure. */
+static int get_usage(uint8_t *report_descriptor, size_t size,
+ unsigned short *usage_page, unsigned short *usage)
+{
+ unsigned int i = 0;
+ int size_code;
+ int data_len, key_size;
+ int usage_found = 0, usage_page_found = 0;
+
+ while (i < size) {
+ int key = report_descriptor[i];
+ int key_cmd = key & 0xfc;
+
+ //printf("key: %02hhx\n", key);
+
+ if ((key & 0xf0) == 0xf0) {
+ /* This is a Long Item. The next byte contains the
+ length of the data section (value) for this key.
+ See the HID specification, version 1.11, section
+ 6.2.2.3, titled "Long Items." */
+ if (i+1 < size)
+ data_len = report_descriptor[i+1];
+ else
+ data_len = 0; /* malformed report */
+ key_size = 3;
+ }
+ else {
+ /* This is a Short Item. The bottom two bits of the
+ key contain the size code for the data section
+ (value) for this key. Refer to the HID
+ specification, version 1.11, section 6.2.2.2,
+ titled "Short Items." */
+ size_code = key & 0x3;
+ switch (size_code) {
+ case 0:
+ case 1:
+ case 2:
+ data_len = size_code;
+ break;
+ case 3:
+ data_len = 4;
+ break;
+ default:
+ /* Can't ever happen since size_code is & 0x3 */
+ data_len = 0;
+ break;
+ };
+ key_size = 1;
+ }
+
+ if (key_cmd == 0x4) {
+ *usage_page = get_bytes(report_descriptor, size, data_len, i);
+ usage_page_found = 1;
+ //printf("Usage Page: %x\n", (uint32_t)*usage_page);
+ }
+ if (key_cmd == 0x8) {
+ *usage = get_bytes(report_descriptor, size, data_len, i);
+ usage_found = 1;
+ //printf("Usage: %x\n", (uint32_t)*usage);
+ }
+
+ if (usage_page_found && usage_found)
+ return 0; /* success */
+
+ /* Skip over this key and it's associated data */
+ i += data_len + key_size;
+ }
+
+ return -1; /* failure */
+}
+#endif /* INVASIVE_GET_USAGE */
+
+#if defined(__FreeBSD__) && __FreeBSD__ < 10
+/* The libusb version included in FreeBSD < 10 doesn't have this function. In
+ mainline libusb, it's inlined in libusb.h. This function will bear a striking
+ resemblance to that one, because there's about one way to code it.
+
+ Note that the data parameter is Unicode in UTF-16LE encoding.
+ Return value is the number of bytes in data, or LIBUSB_ERROR_*.
+ */
+static inline int libusb_get_string_descriptor(libusb_device_handle *dev,
+ uint8_t descriptor_index, uint16_t lang_id,
+ unsigned char *data, int length)
+{
+ return libusb_control_transfer(dev,
+ LIBUSB_ENDPOINT_IN | 0x0, /* Endpoint 0 IN */
+ LIBUSB_REQUEST_GET_DESCRIPTOR,
+ (LIBUSB_DT_STRING << 8) | descriptor_index,
+ lang_id, data, (uint16_t) length, 1000);
+}
+
+#endif
+
+
+/* Get the first language the device says it reports. This comes from
+ USB string #0. */
+static uint16_t get_first_language(libusb_device_handle *dev)
+{
+ uint16_t buf[32];
+ int len;
+
+ /* Get the string from libusb. */
+ len = libusb_get_string_descriptor(dev,
+ 0x0, /* String ID */
+ 0x0, /* Language */
+ (unsigned char*)buf,
+ sizeof(buf));
+ if (len < 4)
+ return 0x0;
+
+ return buf[1]; /* First two bytes are len and descriptor type. */
+}
+
+static int is_language_supported(libusb_device_handle *dev, uint16_t lang)
+{
+ uint16_t buf[32];
+ int len;
+ int i;
+
+ /* Get the string from libusb. */
+ len = libusb_get_string_descriptor(dev,
+ 0x0, /* String ID */
+ 0x0, /* Language */
+ (unsigned char*)buf,
+ sizeof(buf));
+ if (len < 4)
+ return 0x0;
+
+
+ len /= 2; /* language IDs are two-bytes each. */
+ /* Start at index 1 because there are two bytes of protocol data. */
+ for (i = 1; i < len; i++) {
+ if (buf[i] == lang)
+ return 1;
+ }
+
+ return 0;
+}
+
+
+/* This function returns a newly allocated wide string containing the USB
+ device string numbered by the index. The returned string must be freed
+ by using free(). */
+static wchar_t *get_usb_string(libusb_device_handle *dev, uint8_t idx)
+{
+ char buf[512];
+ int len;
+ wchar_t *str = NULL;
+
+#ifndef __ANDROID__ /* we don't use iconv on Android */
+ wchar_t wbuf[256];
+ /* iconv variables */
+ iconv_t ic;
+ size_t inbytes;
+ size_t outbytes;
+ size_t res;
+#ifdef __FreeBSD__
+ const char *inptr;
+#else
+ char *inptr;
+#endif
+ char *outptr;
+#endif
+
+ /* Determine which language to use. */
+ uint16_t lang;
+ lang = get_usb_code_for_current_locale();
+ if (!is_language_supported(dev, lang))
+ lang = get_first_language(dev);
+
+ /* Get the string from libusb. */
+ len = libusb_get_string_descriptor(dev,
+ idx,
+ lang,
+ (unsigned char*)buf,
+ sizeof(buf));
+ if (len < 0)
+ return NULL;
+
+#ifdef __ANDROID__
+
+ /* Bionic does not have iconv support nor wcsdup() function, so it
+ has to be done manually. The following code will only work for
+ code points that can be represented as a single UTF-16 character,
+ and will incorrectly convert any code points which require more
+ than one UTF-16 character.
+
+ Skip over the first character (2-bytes). */
+ len -= 2;
+ str = malloc((len / 2 + 1) * sizeof(wchar_t));
+ int i;
+ for (i = 0; i < len / 2; i++) {
+ str[i] = buf[i * 2 + 2] | (buf[i * 2 + 3] << 8);
+ }
+ str[len / 2] = 0x00000000;
+
+#else
+
+ /* buf does not need to be explicitly NULL-terminated because
+ it is only passed into iconv() which does not need it. */
+
+ /* Initialize iconv. */
+ ic = iconv_open("WCHAR_T", "UTF-16LE");
+ if (ic == (iconv_t)-1) {
+ LOG("iconv_open() failed\n");
+ return NULL;
+ }
+
+ /* Convert to native wchar_t (UTF-32 on glibc/BSD systems).
+ Skip the first character (2-bytes). */
+ inptr = buf+2;
+ inbytes = len-2;
+ outptr = (char*) wbuf;
+ outbytes = sizeof(wbuf);
+ res = iconv(ic, &inptr, &inbytes, &outptr, &outbytes);
+ if (res == (size_t)-1) {
+ LOG("iconv() failed\n");
+ goto err;
+ }
+
+ /* Write the terminating NULL. */
+ wbuf[sizeof(wbuf)/sizeof(wbuf[0])-1] = 0x00000000;
+ if (outbytes >= sizeof(wbuf[0]))
+ *((wchar_t*)outptr) = 0x00000000;
+
+ /* Allocate and copy the string. */
+ str = wcsdup(wbuf);
+
+err:
+ iconv_close(ic);
+
+#endif
+
+ return str;
+}
+
+static char *make_path(libusb_device *dev, int interface_number)
+{
+ char str[64];
+ snprintf(str, sizeof(str), "%04x:%04x:%02x",
+ libusb_get_bus_number(dev),
+ libusb_get_device_address(dev),
+ interface_number);
+ str[sizeof(str)-1] = '\0';
+
+ return strdup(str);
+}
+
+
+int HID_API_EXPORT hid_init(void)
+{
+ if (!usb_context) {
+ const char *locale;
+
+ /* Init Libusb */
+ if (libusb_init(&usb_context))
+ return -1;
+
+ /* Set the locale if it's not set. */
+ locale = setlocale(LC_CTYPE, NULL);
+ if (!locale)
+ setlocale(LC_CTYPE, "");
+ }
+
+ return 0;
+}
+
+int HID_API_EXPORT hid_exit(void)
+{
+ if (usb_context) {
+ libusb_exit(usb_context);
+ usb_context = NULL;
+ }
+
+ return 0;
+}
+
+struct hid_device_info HID_API_EXPORT *hid_enumerate(unsigned short vendor_id, unsigned short product_id)
+{
+ libusb_device **devs;
+ libusb_device *dev;
+ libusb_device_handle *handle;
+ ssize_t num_devs;
+ int i = 0;
+
+ struct hid_device_info *root = NULL; /* return object */
+ struct hid_device_info *cur_dev = NULL;
+
+ if(hid_init() < 0)
+ return NULL;
+
+ num_devs = libusb_get_device_list(usb_context, &devs);
+ if (num_devs < 0)
+ return NULL;
+ while ((dev = devs[i++]) != NULL) {
+ struct libusb_device_descriptor desc;
+ struct libusb_config_descriptor *conf_desc = NULL;
+ int j, k;
+ int interface_num = 0;
+
+ int res = libusb_get_device_descriptor(dev, &desc);
+ unsigned short dev_vid = desc.idVendor;
+ unsigned short dev_pid = desc.idProduct;
+
+ res = libusb_get_active_config_descriptor(dev, &conf_desc);
+ if (res < 0)
+ libusb_get_config_descriptor(dev, 0, &conf_desc);
+ if (conf_desc) {
+ for (j = 0; j < conf_desc->bNumInterfaces; j++) {
+ const struct libusb_interface *intf = &conf_desc->interface[j];
+ for (k = 0; k < intf->num_altsetting; k++) {
+ const struct libusb_interface_descriptor *intf_desc;
+ intf_desc = &intf->altsetting[k];
+ if (intf_desc->bInterfaceClass == LIBUSB_CLASS_HID) {
+ interface_num = intf_desc->bInterfaceNumber;
+
+ /* Check the VID/PID against the arguments */
+ if ((vendor_id == 0x0 || vendor_id == dev_vid) &&
+ (product_id == 0x0 || product_id == dev_pid)) {
+ struct hid_device_info *tmp;
+
+ /* VID/PID match. Create the record. */
+ tmp = calloc(1, sizeof(struct hid_device_info));
+ if (cur_dev) {
+ cur_dev->next = tmp;
+ }
+ else {
+ root = tmp;
+ }
+ cur_dev = tmp;
+
+ /* Fill out the record */
+ cur_dev->next = NULL;
+ cur_dev->path = make_path(dev, interface_num);
+
+ res = libusb_open(dev, &handle);
+
+ if (res >= 0) {
+ /* Serial Number */
+ if (desc.iSerialNumber > 0)
+ cur_dev->serial_number =
+ get_usb_string(handle, desc.iSerialNumber);
+
+ /* Manufacturer and Product strings */
+ if (desc.iManufacturer > 0)
+ cur_dev->manufacturer_string =
+ get_usb_string(handle, desc.iManufacturer);
+ if (desc.iProduct > 0)
+ cur_dev->product_string =
+ get_usb_string(handle, desc.iProduct);
+
+#ifdef INVASIVE_GET_USAGE
+{
+ /*
+ This section is removed because it is too
+ invasive on the system. Getting a Usage Page
+ and Usage requires parsing the HID Report
+ descriptor. Getting a HID Report descriptor
+ involves claiming the interface. Claiming the
+ interface involves detaching the kernel driver.
+ Detaching the kernel driver is hard on the system
+ because it will unclaim interfaces (if another
+ app has them claimed) and the re-attachment of
+ the driver will sometimes change /dev entry names.
+ It is for these reasons that this section is
+ #if 0. For composite devices, use the interface
+ field in the hid_device_info struct to distinguish
+ between interfaces. */
+ unsigned char data[256];
+#ifdef DETACH_KERNEL_DRIVER
+ int detached = 0;
+ /* Usage Page and Usage */
+ res = libusb_kernel_driver_active(handle, interface_num);
+ if (res == 1) {
+ res = libusb_detach_kernel_driver(handle, interface_num);
+ if (res < 0)
+ LOG("Couldn't detach kernel driver, even though a kernel driver was attached.");
+ else
+ detached = 1;
+ }
+#endif
+ res = libusb_claim_interface(handle, interface_num);
+ if (res >= 0) {
+ /* Get the HID Report Descriptor. */
+ res = libusb_control_transfer(handle, LIBUSB_ENDPOINT_IN|LIBUSB_RECIPIENT_INTERFACE, LIBUSB_REQUEST_GET_DESCRIPTOR, (LIBUSB_DT_REPORT << 8)|interface_num, 0, data, sizeof(data), 5000);
+ if (res >= 0) {
+ unsigned short page=0, usage=0;
+ /* Parse the usage and usage page
+ out of the report descriptor. */
+ get_usage(data, res, &page, &usage);
+ cur_dev->usage_page = page;
+ cur_dev->usage = usage;
+ }
+ else
+ LOG("libusb_control_transfer() for getting the HID report failed with %d\n", res);
+
+ /* Release the interface */
+ res = libusb_release_interface(handle, interface_num);
+ if (res < 0)
+ LOG("Can't release the interface.\n");
+ }
+ else
+ LOG("Can't claim interface %d\n", res);
+#ifdef DETACH_KERNEL_DRIVER
+ /* Re-attach kernel driver if necessary. */
+ if (detached) {
+ res = libusb_attach_kernel_driver(handle, interface_num);
+ if (res < 0)
+ LOG("Couldn't re-attach kernel driver.\n");
+ }
+#endif
+}
+#endif /* INVASIVE_GET_USAGE */
+
+ libusb_close(handle);
+ }
+ /* VID/PID */
+ cur_dev->vendor_id = dev_vid;
+ cur_dev->product_id = dev_pid;
+
+ /* Release Number */
+ cur_dev->release_number = desc.bcdDevice;
+
+ /* Interface Number */
+ cur_dev->interface_number = interface_num;
+ }
+ }
+ } /* altsettings */
+ } /* interfaces */
+ libusb_free_config_descriptor(conf_desc);
+ }
+ }
+
+ libusb_free_device_list(devs, 1);
+
+ return root;
+}
+
+void HID_API_EXPORT hid_free_enumeration(struct hid_device_info *devs)
+{
+ struct hid_device_info *d = devs;
+ while (d) {
+ struct hid_device_info *next = d->next;
+ free(d->path);
+ free(d->serial_number);
+ free(d->manufacturer_string);
+ free(d->product_string);
+ free(d);
+ d = next;
+ }
+}
+
+hid_device * hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number)
+{
+ struct hid_device_info *devs, *cur_dev;
+ const char *path_to_open = NULL;
+ hid_device *handle = NULL;
+
+ devs = hid_enumerate(vendor_id, product_id);
+ cur_dev = devs;
+ while (cur_dev) {
+ if (cur_dev->vendor_id == vendor_id &&
+ cur_dev->product_id == product_id) {
+ if (serial_number) {
+ if (cur_dev->serial_number &&
+ wcscmp(serial_number, cur_dev->serial_number) == 0) {
+ path_to_open = cur_dev->path;
+ break;
+ }
+ }
+ else {
+ path_to_open = cur_dev->path;
+ break;
+ }
+ }
+ cur_dev = cur_dev->next;
+ }
+
+ if (path_to_open) {
+ /* Open the device */
+ handle = hid_open_path(path_to_open);
+ }
+
+ hid_free_enumeration(devs);
+
+ return handle;
+}
+
+static void read_callback(struct libusb_transfer *transfer)
+{
+ hid_device *dev = transfer->user_data;
+ int res;
+
+ if (transfer->status == LIBUSB_TRANSFER_COMPLETED) {
+
+ struct input_report *rpt = malloc(sizeof(*rpt));
+ rpt->data = malloc(transfer->actual_length);
+ memcpy(rpt->data, transfer->buffer, transfer->actual_length);
+ rpt->len = transfer->actual_length;
+ rpt->next = NULL;
+
+ pthread_mutex_lock(&dev->mutex);
+
+ /* Attach the new report object to the end of the list. */
+ if (dev->input_reports == NULL) {
+ /* The list is empty. Put it at the root. */
+ dev->input_reports = rpt;
+ pthread_cond_signal(&dev->condition);
+ }
+ else {
+ /* Find the end of the list and attach. */
+ struct input_report *cur = dev->input_reports;
+ int num_queued = 0;
+ while (cur->next != NULL) {
+ cur = cur->next;
+ num_queued++;
+ }
+ cur->next = rpt;
+
+ /* Pop one off if we've reached 30 in the queue. This
+ way we don't grow forever if the user never reads
+ anything from the device. */
+ if (num_queued > 30) {
+ return_data(dev, NULL, 0);
+ }
+ }
+ pthread_mutex_unlock(&dev->mutex);
+ }
+ else if (transfer->status == LIBUSB_TRANSFER_CANCELLED) {
+ dev->shutdown_thread = 1;
+ dev->cancelled = 1;
+ return;
+ }
+ else if (transfer->status == LIBUSB_TRANSFER_NO_DEVICE) {
+ dev->shutdown_thread = 1;
+ dev->cancelled = 1;
+ return;
+ }
+ else if (transfer->status == LIBUSB_TRANSFER_TIMED_OUT) {
+ //LOG("Timeout (normal)\n");
+ }
+ else {
+ LOG("Unknown transfer code: %d\n", transfer->status);
+ }
+
+ /* Re-submit the transfer object. */
+ res = libusb_submit_transfer(transfer);
+ if (res != 0) {
+ LOG("Unable to submit URB. libusb error code: %d\n", res);
+ dev->shutdown_thread = 1;
+ dev->cancelled = 1;
+ }
+}
+
+
+static void *read_thread(void *param)
+{
+ hid_device *dev = param;
+ unsigned char *buf;
+ const size_t length = dev->input_ep_max_packet_size;
+
+ /* Set up the transfer object. */
+ buf = malloc(length);
+ dev->transfer = libusb_alloc_transfer(0);
+ libusb_fill_interrupt_transfer(dev->transfer,
+ dev->device_handle,
+ dev->input_endpoint,
+ buf,
+ length,
+ read_callback,
+ dev,
+ 5000/*timeout*/);
+
+ /* Make the first submission. Further submissions are made
+ from inside read_callback() */
+ libusb_submit_transfer(dev->transfer);
+
+ /* Notify the main thread that the read thread is up and running. */
+ pthread_barrier_wait(&dev->barrier);
+
+ /* Handle all the events. */
+ while (!dev->shutdown_thread) {
+ int res;
+ res = libusb_handle_events(usb_context);
+ if (res < 0) {
+ /* There was an error. */
+ LOG("read_thread(): libusb reports error # %d\n", res);
+
+ /* Break out of this loop only on fatal error.*/
+ if (res != LIBUSB_ERROR_BUSY &&
+ res != LIBUSB_ERROR_TIMEOUT &&
+ res != LIBUSB_ERROR_OVERFLOW &&
+ res != LIBUSB_ERROR_INTERRUPTED) {
+ break;
+ }
+ }
+ }
+
+ /* Cancel any transfer that may be pending. This call will fail
+ if no transfers are pending, but that's OK. */
+ libusb_cancel_transfer(dev->transfer);
+
+ while (!dev->cancelled)
+ libusb_handle_events_completed(usb_context, &dev->cancelled);
+
+ /* Now that the read thread is stopping, Wake any threads which are
+ waiting on data (in hid_read_timeout()). Do this under a mutex to
+ make sure that a thread which is about to go to sleep waiting on
+ the condition actually will go to sleep before the condition is
+ signaled. */
+ pthread_mutex_lock(&dev->mutex);
+ pthread_cond_broadcast(&dev->condition);
+ pthread_mutex_unlock(&dev->mutex);
+
+ /* The dev->transfer->buffer and dev->transfer objects are cleaned up
+ in hid_close(). They are not cleaned up here because this thread
+ could end either due to a disconnect or due to a user
+ call to hid_close(). In both cases the objects can be safely
+ cleaned up after the call to pthread_join() (in hid_close()), but
+ since hid_close() calls libusb_cancel_transfer(), on these objects,
+ they can not be cleaned up here. */
+
+ return NULL;
+}
+
+
+hid_device * HID_API_EXPORT hid_open_path(const char *path)
+{
+ hid_device *dev = NULL;
+
+ libusb_device **devs;
+ libusb_device *usb_dev;
+ int res;
+ int d = 0;
+ int good_open = 0;
+
+ if(hid_init() < 0)
+ return NULL;
+
+ dev = new_hid_device();
+
+ libusb_get_device_list(usb_context, &devs);
+ while ((usb_dev = devs[d++]) != NULL) {
+ struct libusb_device_descriptor desc;
+ struct libusb_config_descriptor *conf_desc = NULL;
+ int i,j,k;
+ libusb_get_device_descriptor(usb_dev, &desc);
+
+ if (libusb_get_active_config_descriptor(usb_dev, &conf_desc) < 0)
+ continue;
+ for (j = 0; j < conf_desc->bNumInterfaces; j++) {
+ const struct libusb_interface *intf = &conf_desc->interface[j];
+ for (k = 0; k < intf->num_altsetting; k++) {
+ const struct libusb_interface_descriptor *intf_desc;
+ intf_desc = &intf->altsetting[k];
+ if (intf_desc->bInterfaceClass == LIBUSB_CLASS_HID) {
+ char *dev_path = make_path(usb_dev, intf_desc->bInterfaceNumber);
+ if (!strcmp(dev_path, path)) {
+ /* Matched Paths. Open this device */
+
+ /* OPEN HERE */
+ res = libusb_open(usb_dev, &dev->device_handle);
+ if (res < 0) {
+ LOG("can't open device\n");
+ free(dev_path);
+ break;
+ }
+ good_open = 1;
+#ifdef DETACH_KERNEL_DRIVER
+ /* Detach the kernel driver, but only if the
+ device is managed by the kernel */
+ if (libusb_kernel_driver_active(dev->device_handle, intf_desc->bInterfaceNumber) == 1) {
+ res = libusb_detach_kernel_driver(dev->device_handle, intf_desc->bInterfaceNumber);
+ if (res < 0) {
+ libusb_close(dev->device_handle);
+ LOG("Unable to detach Kernel Driver\n");
+ free(dev_path);
+ good_open = 0;
+ break;
+ }
+ }
+#endif
+ res = libusb_claim_interface(dev->device_handle, intf_desc->bInterfaceNumber);
+ if (res < 0) {
+ LOG("can't claim interface %d: %d\n", intf_desc->bInterfaceNumber, res);
+ free(dev_path);
+ libusb_close(dev->device_handle);
+ good_open = 0;
+ break;
+ }
+
+ /* Store off the string descriptor indexes */
+ dev->manufacturer_index = desc.iManufacturer;
+ dev->product_index = desc.iProduct;
+ dev->serial_index = desc.iSerialNumber;
+
+ /* Store off the interface number */
+ dev->interface = intf_desc->bInterfaceNumber;
+
+ /* Find the INPUT and OUTPUT endpoints. An
+ OUTPUT endpoint is not required. */
+ for (i = 0; i < intf_desc->bNumEndpoints; i++) {
+ const struct libusb_endpoint_descriptor *ep
+ = &intf_desc->endpoint[i];
+
+ /* Determine the type and direction of this
+ endpoint. */
+ int is_interrupt =
+ (ep->bmAttributes & LIBUSB_TRANSFER_TYPE_MASK)
+ == LIBUSB_TRANSFER_TYPE_INTERRUPT;
+ int is_output =
+ (ep->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK)
+ == LIBUSB_ENDPOINT_OUT;
+ int is_input =
+ (ep->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK)
+ == LIBUSB_ENDPOINT_IN;
+
+ /* Decide whether to use it for input or output. */
+ if (dev->input_endpoint == 0 &&
+ is_interrupt && is_input) {
+ /* Use this endpoint for INPUT */
+ dev->input_endpoint = ep->bEndpointAddress;
+ dev->input_ep_max_packet_size = ep->wMaxPacketSize;
+ }
+ if (dev->output_endpoint == 0 &&
+ is_interrupt && is_output) {
+ /* Use this endpoint for OUTPUT */
+ dev->output_endpoint = ep->bEndpointAddress;
+ }
+ }
+
+ pthread_create(&dev->thread, NULL, read_thread, dev);
+
+ /* Wait here for the read thread to be initialized. */
+ pthread_barrier_wait(&dev->barrier);
+
+ }
+ free(dev_path);
+ }
+ }
+ }
+ libusb_free_config_descriptor(conf_desc);
+
+ }
+
+ libusb_free_device_list(devs, 1);
+
+ /* If we have a good handle, return it. */
+ if (good_open) {
+ return dev;
+ }
+ else {
+ /* Unable to open any devices. */
+ free_hid_device(dev);
+ return NULL;
+ }
+}
+
+
+int HID_API_EXPORT hid_write(hid_device *dev, const unsigned char *data, size_t length)
+{
+ int res;
+ int report_number = data[0];
+ int skipped_report_id = 0;
+
+ if (report_number == 0x0) {
+ data++;
+ length--;
+ skipped_report_id = 1;
+ }
+
+
+ if (dev->output_endpoint <= 0) {
+ /* No interrupt out endpoint. Use the Control Endpoint */
+ res = libusb_control_transfer(dev->device_handle,
+ LIBUSB_REQUEST_TYPE_CLASS|LIBUSB_RECIPIENT_INTERFACE|LIBUSB_ENDPOINT_OUT,
+ 0x09/*HID Set_Report*/,
+ (2/*HID output*/ << 8) | report_number,
+ dev->interface,
+ (unsigned char *)data, length,
+ 1000/*timeout millis*/);
+
+ if (res < 0)
+ return -1;
+
+ if (skipped_report_id)
+ length++;
+
+ return length;
+ }
+ else {
+ /* Use the interrupt out endpoint */
+ int actual_length;
+ res = libusb_interrupt_transfer(dev->device_handle,
+ dev->output_endpoint,
+ (unsigned char*)data,
+ length,
+ &actual_length, 1000);
+
+ if (res < 0)
+ return -1;
+
+ if (skipped_report_id)
+ actual_length++;
+
+ return actual_length;
+ }
+}
+
+/* Helper function, to simplify hid_read().
+ This should be called with dev->mutex locked. */
+static int return_data(hid_device *dev, unsigned char *data, size_t length)
+{
+ /* Copy the data out of the linked list item (rpt) into the
+ return buffer (data), and delete the liked list item. */
+ struct input_report *rpt = dev->input_reports;
+ size_t len = (length < rpt->len)? length: rpt->len;
+ if (len > 0)
+ memcpy(data, rpt->data, len);
+ dev->input_reports = rpt->next;
+ free(rpt->data);
+ free(rpt);
+ return len;
+}
+
+static void cleanup_mutex(void *param)
+{
+ hid_device *dev = param;
+ pthread_mutex_unlock(&dev->mutex);
+}
+
+
+int HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds)
+{
+ int bytes_read = -1;
+
+#if 0
+ int transferred;
+ int res = libusb_interrupt_transfer(dev->device_handle, dev->input_endpoint, data, length, &transferred, 5000);
+ LOG("transferred: %d\n", transferred);
+ return transferred;
+#endif
+
+ pthread_mutex_lock(&dev->mutex);
+ pthread_cleanup_push(&cleanup_mutex, dev);
+
+ /* There's an input report queued up. Return it. */
+ if (dev->input_reports) {
+ /* Return the first one */
+ bytes_read = return_data(dev, data, length);
+ goto ret;
+ }
+
+ if (dev->shutdown_thread) {
+ /* This means the device has been disconnected.
+ An error code of -1 should be returned. */
+ bytes_read = -1;
+ goto ret;
+ }
+
+ if (milliseconds == -1) {
+ /* Blocking */
+ while (!dev->input_reports && !dev->shutdown_thread) {
+ pthread_cond_wait(&dev->condition, &dev->mutex);
+ }
+ if (dev->input_reports) {
+ bytes_read = return_data(dev, data, length);
+ }
+ }
+ else if (milliseconds > 0) {
+ /* Non-blocking, but called with timeout. */
+ int res;
+ struct timespec ts;
+ clock_gettime(CLOCK_REALTIME, &ts);
+ ts.tv_sec += milliseconds / 1000;
+ ts.tv_nsec += (milliseconds % 1000) * 1000000;
+ if (ts.tv_nsec >= 1000000000L) {
+ ts.tv_sec++;
+ ts.tv_nsec -= 1000000000L;
+ }
+
+ while (!dev->input_reports && !dev->shutdown_thread) {
+ res = pthread_cond_timedwait(&dev->condition, &dev->mutex, &ts);
+ if (res == 0) {
+ if (dev->input_reports) {
+ bytes_read = return_data(dev, data, length);
+ break;
+ }
+
+ /* If we're here, there was a spurious wake up
+ or the read thread was shutdown. Run the
+ loop again (ie: don't break). */
+ }
+ else if (res == ETIMEDOUT) {
+ /* Timed out. */
+ bytes_read = 0;
+ break;
+ }
+ else {
+ /* Error. */
+ bytes_read = -1;
+ break;
+ }
+ }
+ }
+ else {
+ /* Purely non-blocking */
+ bytes_read = 0;
+ }
+
+ret:
+ pthread_mutex_unlock(&dev->mutex);
+ pthread_cleanup_pop(0);
+
+ return bytes_read;
+}
+
+int HID_API_EXPORT hid_read(hid_device *dev, unsigned char *data, size_t length)
+{
+ return hid_read_timeout(dev, data, length, dev->blocking ? -1 : 0);
+}
+
+int HID_API_EXPORT hid_set_nonblocking(hid_device *dev, int nonblock)
+{
+ dev->blocking = !nonblock;
+
+ return 0;
+}
+
+
+int HID_API_EXPORT hid_send_feature_report(hid_device *dev, const unsigned char *data, size_t length)
+{
+ int res = -1;
+ int skipped_report_id = 0;
+ int report_number = data[0];
+
+ if (report_number == 0x0) {
+ data++;
+ length--;
+ skipped_report_id = 1;
+ }
+
+ res = libusb_control_transfer(dev->device_handle,
+ LIBUSB_REQUEST_TYPE_CLASS|LIBUSB_RECIPIENT_INTERFACE|LIBUSB_ENDPOINT_OUT,
+ 0x09/*HID set_report*/,
+ (3/*HID feature*/ << 8) | report_number,
+ dev->interface,
+ (unsigned char *)data, length,
+ 1000/*timeout millis*/);
+
+ if (res < 0)
+ return -1;
+
+ /* Account for the report ID */
+ if (skipped_report_id)
+ length++;
+
+ return length;
+}
+
+int HID_API_EXPORT hid_get_feature_report(hid_device *dev, unsigned char *data, size_t length)
+{
+ int res = -1;
+ int skipped_report_id = 0;
+ int report_number = data[0];
+
+ if (report_number == 0x0) {
+ /* Offset the return buffer by 1, so that the report ID
+ will remain in byte 0. */
+ data++;
+ length--;
+ skipped_report_id = 1;
+ }
+ res = libusb_control_transfer(dev->device_handle,
+ LIBUSB_REQUEST_TYPE_CLASS|LIBUSB_RECIPIENT_INTERFACE|LIBUSB_ENDPOINT_IN,
+ 0x01/*HID get_report*/,
+ (3/*HID feature*/ << 8) | report_number,
+ dev->interface,
+ (unsigned char *)data, length,
+ 1000/*timeout millis*/);
+
+ if (res < 0)
+ return -1;
+
+ if (skipped_report_id)
+ res++;
+
+ return res;
+}
+
+
+void HID_API_EXPORT hid_close(hid_device *dev)
+{
+ if (!dev)
+ return;
+
+ /* Cause read_thread() to stop. */
+ dev->shutdown_thread = 1;
+ libusb_cancel_transfer(dev->transfer);
+
+ /* Wait for read_thread() to end. */
+ pthread_join(dev->thread, NULL);
+
+ /* Clean up the Transfer objects allocated in read_thread(). */
+ free(dev->transfer->buffer);
+ libusb_free_transfer(dev->transfer);
+
+ /* release the interface */
+ libusb_release_interface(dev->device_handle, dev->interface);
+
+ /* Close the handle */
+ libusb_close(dev->device_handle);
+
+ /* Clear out the queue of received reports. */
+ pthread_mutex_lock(&dev->mutex);
+ while (dev->input_reports) {
+ return_data(dev, NULL, 0);
+ }
+ pthread_mutex_unlock(&dev->mutex);
+
+ free_hid_device(dev);
+}
+
+
+int HID_API_EXPORT_CALL hid_get_manufacturer_string(hid_device *dev, wchar_t *string, size_t maxlen)
+{
+ return hid_get_indexed_string(dev, dev->manufacturer_index, string, maxlen);
+}
+
+int HID_API_EXPORT_CALL hid_get_product_string(hid_device *dev, wchar_t *string, size_t maxlen)
+{
+ return hid_get_indexed_string(dev, dev->product_index, string, maxlen);
+}
+
+int HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *dev, wchar_t *string, size_t maxlen)
+{
+ return hid_get_indexed_string(dev, dev->serial_index, string, maxlen);
+}
+
+int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *dev, int string_index, wchar_t *string, size_t maxlen)
+{
+ wchar_t *str;
+
+ str = get_usb_string(dev->device_handle, string_index);
+ if (str) {
+ wcsncpy(string, str, maxlen);
+ string[maxlen-1] = L'\0';
+ free(str);
+ return 0;
+ }
+ else
+ return -1;
+}
+
+
+HID_API_EXPORT const wchar_t * HID_API_CALL hid_error(hid_device *dev)
+{
+ return NULL;
+}
+
+
+struct lang_map_entry {
+ const char *name;
+ const char *string_code;
+ uint16_t usb_code;
+};
+
+#define LANG(name,code,usb_code) { name, code, usb_code }
+static struct lang_map_entry lang_map[] = {
+ LANG("Afrikaans", "af", 0x0436),
+ LANG("Albanian", "sq", 0x041C),
+ LANG("Arabic - United Arab Emirates", "ar_ae", 0x3801),
+ LANG("Arabic - Bahrain", "ar_bh", 0x3C01),
+ LANG("Arabic - Algeria", "ar_dz", 0x1401),
+ LANG("Arabic - Egypt", "ar_eg", 0x0C01),
+ LANG("Arabic - Iraq", "ar_iq", 0x0801),
+ LANG("Arabic - Jordan", "ar_jo", 0x2C01),
+ LANG("Arabic - Kuwait", "ar_kw", 0x3401),
+ LANG("Arabic - Lebanon", "ar_lb", 0x3001),
+ LANG("Arabic - Libya", "ar_ly", 0x1001),
+ LANG("Arabic - Morocco", "ar_ma", 0x1801),
+ LANG("Arabic - Oman", "ar_om", 0x2001),
+ LANG("Arabic - Qatar", "ar_qa", 0x4001),
+ LANG("Arabic - Saudi Arabia", "ar_sa", 0x0401),
+ LANG("Arabic - Syria", "ar_sy", 0x2801),
+ LANG("Arabic - Tunisia", "ar_tn", 0x1C01),
+ LANG("Arabic - Yemen", "ar_ye", 0x2401),
+ LANG("Armenian", "hy", 0x042B),
+ LANG("Azeri - Latin", "az_az", 0x042C),
+ LANG("Azeri - Cyrillic", "az_az", 0x082C),
+ LANG("Basque", "eu", 0x042D),
+ LANG("Belarusian", "be", 0x0423),
+ LANG("Bulgarian", "bg", 0x0402),
+ LANG("Catalan", "ca", 0x0403),
+ LANG("Chinese - China", "zh_cn", 0x0804),
+ LANG("Chinese - Hong Kong SAR", "zh_hk", 0x0C04),
+ LANG("Chinese - Macau SAR", "zh_mo", 0x1404),
+ LANG("Chinese - Singapore", "zh_sg", 0x1004),
+ LANG("Chinese - Taiwan", "zh_tw", 0x0404),
+ LANG("Croatian", "hr", 0x041A),
+ LANG("Czech", "cs", 0x0405),
+ LANG("Danish", "da", 0x0406),
+ LANG("Dutch - Netherlands", "nl_nl", 0x0413),
+ LANG("Dutch - Belgium", "nl_be", 0x0813),
+ LANG("English - Australia", "en_au", 0x0C09),
+ LANG("English - Belize", "en_bz", 0x2809),
+ LANG("English - Canada", "en_ca", 0x1009),
+ LANG("English - Caribbean", "en_cb", 0x2409),
+ LANG("English - Ireland", "en_ie", 0x1809),
+ LANG("English - Jamaica", "en_jm", 0x2009),
+ LANG("English - New Zealand", "en_nz", 0x1409),
+ LANG("English - Phillippines", "en_ph", 0x3409),
+ LANG("English - Southern Africa", "en_za", 0x1C09),
+ LANG("English - Trinidad", "en_tt", 0x2C09),
+ LANG("English - Great Britain", "en_gb", 0x0809),
+ LANG("English - United States", "en_us", 0x0409),
+ LANG("Estonian", "et", 0x0425),
+ LANG("Farsi", "fa", 0x0429),
+ LANG("Finnish", "fi", 0x040B),
+ LANG("Faroese", "fo", 0x0438),
+ LANG("French - France", "fr_fr", 0x040C),
+ LANG("French - Belgium", "fr_be", 0x080C),
+ LANG("French - Canada", "fr_ca", 0x0C0C),
+ LANG("French - Luxembourg", "fr_lu", 0x140C),
+ LANG("French - Switzerland", "fr_ch", 0x100C),
+ LANG("Gaelic - Ireland", "gd_ie", 0x083C),
+ LANG("Gaelic - Scotland", "gd", 0x043C),
+ LANG("German - Germany", "de_de", 0x0407),
+ LANG("German - Austria", "de_at", 0x0C07),
+ LANG("German - Liechtenstein", "de_li", 0x1407),
+ LANG("German - Luxembourg", "de_lu", 0x1007),
+ LANG("German - Switzerland", "de_ch", 0x0807),
+ LANG("Greek", "el", 0x0408),
+ LANG("Hebrew", "he", 0x040D),
+ LANG("Hindi", "hi", 0x0439),
+ LANG("Hungarian", "hu", 0x040E),
+ LANG("Icelandic", "is", 0x040F),
+ LANG("Indonesian", "id", 0x0421),
+ LANG("Italian - Italy", "it_it", 0x0410),
+ LANG("Italian - Switzerland", "it_ch", 0x0810),
+ LANG("Japanese", "ja", 0x0411),
+ LANG("Korean", "ko", 0x0412),
+ LANG("Latvian", "lv", 0x0426),
+ LANG("Lithuanian", "lt", 0x0427),
+ LANG("F.Y.R.O. Macedonia", "mk", 0x042F),
+ LANG("Malay - Malaysia", "ms_my", 0x043E),
+ LANG("Malay – Brunei", "ms_bn", 0x083E),
+ LANG("Maltese", "mt", 0x043A),
+ LANG("Marathi", "mr", 0x044E),
+ LANG("Norwegian - Bokml", "no_no", 0x0414),
+ LANG("Norwegian - Nynorsk", "no_no", 0x0814),
+ LANG("Polish", "pl", 0x0415),
+ LANG("Portuguese - Portugal", "pt_pt", 0x0816),
+ LANG("Portuguese - Brazil", "pt_br", 0x0416),
+ LANG("Raeto-Romance", "rm", 0x0417),
+ LANG("Romanian - Romania", "ro", 0x0418),
+ LANG("Romanian - Republic of Moldova", "ro_mo", 0x0818),
+ LANG("Russian", "ru", 0x0419),
+ LANG("Russian - Republic of Moldova", "ru_mo", 0x0819),
+ LANG("Sanskrit", "sa", 0x044F),
+ LANG("Serbian - Cyrillic", "sr_sp", 0x0C1A),
+ LANG("Serbian - Latin", "sr_sp", 0x081A),
+ LANG("Setsuana", "tn", 0x0432),
+ LANG("Slovenian", "sl", 0x0424),
+ LANG("Slovak", "sk", 0x041B),
+ LANG("Sorbian", "sb", 0x042E),
+ LANG("Spanish - Spain (Traditional)", "es_es", 0x040A),
+ LANG("Spanish - Argentina", "es_ar", 0x2C0A),
+ LANG("Spanish - Bolivia", "es_bo", 0x400A),
+ LANG("Spanish - Chile", "es_cl", 0x340A),
+ LANG("Spanish - Colombia", "es_co", 0x240A),
+ LANG("Spanish - Costa Rica", "es_cr", 0x140A),
+ LANG("Spanish - Dominican Republic", "es_do", 0x1C0A),
+ LANG("Spanish - Ecuador", "es_ec", 0x300A),
+ LANG("Spanish - Guatemala", "es_gt", 0x100A),
+ LANG("Spanish - Honduras", "es_hn", 0x480A),
+ LANG("Spanish - Mexico", "es_mx", 0x080A),
+ LANG("Spanish - Nicaragua", "es_ni", 0x4C0A),
+ LANG("Spanish - Panama", "es_pa", 0x180A),
+ LANG("Spanish - Peru", "es_pe", 0x280A),
+ LANG("Spanish - Puerto Rico", "es_pr", 0x500A),
+ LANG("Spanish - Paraguay", "es_py", 0x3C0A),
+ LANG("Spanish - El Salvador", "es_sv", 0x440A),
+ LANG("Spanish - Uruguay", "es_uy", 0x380A),
+ LANG("Spanish - Venezuela", "es_ve", 0x200A),
+ LANG("Southern Sotho", "st", 0x0430),
+ LANG("Swahili", "sw", 0x0441),
+ LANG("Swedish - Sweden", "sv_se", 0x041D),
+ LANG("Swedish - Finland", "sv_fi", 0x081D),
+ LANG("Tamil", "ta", 0x0449),
+ LANG("Tatar", "tt", 0X0444),
+ LANG("Thai", "th", 0x041E),
+ LANG("Turkish", "tr", 0x041F),
+ LANG("Tsonga", "ts", 0x0431),
+ LANG("Ukrainian", "uk", 0x0422),
+ LANG("Urdu", "ur", 0x0420),
+ LANG("Uzbek - Cyrillic", "uz_uz", 0x0843),
+ LANG("Uzbek – Latin", "uz_uz", 0x0443),
+ LANG("Vietnamese", "vi", 0x042A),
+ LANG("Xhosa", "xh", 0x0434),
+ LANG("Yiddish", "yi", 0x043D),
+ LANG("Zulu", "zu", 0x0435),
+ LANG(NULL, NULL, 0x0),
+};
+
+uint16_t get_usb_code_for_current_locale(void)
+{
+ char *locale;
+ char search_string[64];
+ char *ptr;
+ struct lang_map_entry *lang;
+
+ /* Get the current locale. */
+ locale = setlocale(0, NULL);
+ if (!locale)
+ return 0x0;
+
+ /* Make a copy of the current locale string. */
+ strncpy(search_string, locale, sizeof(search_string));
+ search_string[sizeof(search_string)-1] = '\0';
+
+ /* Chop off the encoding part, and make it lower case. */
+ ptr = search_string;
+ while (*ptr) {
+ *ptr = tolower(*ptr);
+ if (*ptr == '.') {
+ *ptr = '\0';
+ break;
+ }
+ ptr++;
+ }
+
+ /* Find the entry which matches the string code of our locale. */
+ lang = lang_map;
+ while (lang->string_code) {
+ if (!strcmp(lang->string_code, search_string)) {
+ return lang->usb_code;
+ }
+ lang++;
+ }
+
+ /* There was no match. Find with just the language only. */
+ /* Chop off the variant. Chop it off at the '_'. */
+ ptr = search_string;
+ while (*ptr) {
+ *ptr = tolower(*ptr);
+ if (*ptr == '_') {
+ *ptr = '\0';
+ break;
+ }
+ ptr++;
+ }
+
+#if 0 /* TODO: Do we need this? */
+ /* Find the entry which matches the string code of our language. */
+ lang = lang_map;
+ while (lang->string_code) {
+ if (!strcmp(lang->string_code, search_string)) {
+ return lang->usb_code;
+ }
+ lang++;
+ }
+#endif
+
+ /* Found nothing. */
+ return 0x0;
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/vendor/github.com/karalabe/hid/hidapi/mac/hid.c b/vendor/github.com/karalabe/hid/hidapi/mac/hid.c
new file mode 100644
index 0000000000..e0756a1588
--- /dev/null
+++ b/vendor/github.com/karalabe/hid/hidapi/mac/hid.c
@@ -0,0 +1,1110 @@
+/*******************************************************
+ HIDAPI - Multi-Platform library for
+ communication with HID devices.
+
+ Alan Ott
+ Signal 11 Software
+
+ 2010-07-03
+
+ Copyright 2010, All Rights Reserved.
+
+ At the discretion of the user of this library,
+ this software may be licensed under the terms of the
+ GNU General Public License v3, a BSD-Style license, or the
+ original HIDAPI license as outlined in the LICENSE.txt,
+ LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt
+ files located at the root of the source distribution.
+ These files may also be found in the public source
+ code repository located at:
+ http://github.com/signal11/hidapi .
+********************************************************/
+
+/* See Apple Technical Note TN2187 for details on IOHidManager. */
+
+#include
+#include
+#include
+#include