Transaction Hash:
Block:
16940476 at Mar-30-2023 01:52:23 PM +UTC
Transaction Fee:
0.067944327962708951 ETH
$140.65
Gas Used:
1,765,387 Gas / 38.486931173 Gwei
Emitted Events:
| 294 |
TransparentUpgradeableProxy.0x5e3c1311ea442664e8b1611bfabef659120ea7a0a2cfc0667700bebc69cbffe1( 0x5e3c1311ea442664e8b1611bfabef659120ea7a0a2cfc0667700bebc69cbffe1, 0x00000000000000000000000000000000000000000000000000000000000aeb07, 0x6bd81d83fc3de223ae15196e088072be1b0ac7e4e956af154b6b5f83e8b7c3b2, 0000000000000000000000001c479675ad559dc151f6ec7ed3fbf8cee79582b6, 000000000000000000000000000000000000000000000000000000000000000d, 000000000000000000000000c1b634853cb333d3ad8663715b08f41a3aec47cc, d9cc8bb3790b4adbcad8afc5d5765185402b800de710b397ee95e982d4df3d16, 00000000000000000000000000000000000000000000000000000008f24f6fae, 0000000000000000000000000000000000000000000000000000000064259417 )
|
| 295 |
TransparentUpgradeableProxy.0xff64905f73a67fb594e0f940a8075a860db489ad991e032f48c81123eb52d60b( 0xff64905f73a67fb594e0f940a8075a860db489ad991e032f48c81123eb52d60b, 0x00000000000000000000000000000000000000000000000000000000000aeb07, 0000000000000000000000000000000000000000000000000000000000000020, 0000000000000000000000000000000000000000000000000000000000000094, 0000000000000000000000000000000000000000000000000000000064259417, c1b634853cb333d3ad8663715b08f41a3aec47cc9a0ec44367721076fe72c9e6, 1a43b4b673b21eb9cf4e41c71eb1a43d3e2aa179000000000000000000000000, 000000000000000000000000000000000001ea51000000000000000000000000, 00000000000000000000000000000008f24f6fae000000000000000000000000 )
|
| 296 |
TransparentUpgradeableProxy.0x7394f4a19a13c7b92b5bb71033245305946ef78452f7b4986ac1390b5df4ebd7( 0x7394f4a19a13c7b92b5bb71033245305946ef78452f7b4986ac1390b5df4ebd7, 0x000000000000000000000000000000000000000000000000000000000001ea51, 0x233abdc51fa34b9747833eee7ece439e308c8c584b9f8bc1d874894f1cb4ffb5, 0x97d0f8ac5eae9f4347f399ad745b6f28a8c46177ffe9a9a2b447380dbc182527, 900f028fb9208f4222a078f8f4962a647b7c91b02e0f2a4e705d0fc09b40621c, 00000000000000000000000000000000000000000000000000000000000aeaca, 0000000000000000000000000000000000000000000000000000000064244297, 000000000000000000000000000000000000000000000000000000006425a227, 000000000000000000000000000000000000000000000000000000000102673c, 0000000000000000000000000000000000000000000000000000000001027dc8, 0000000000000000000000000000000000000000000000000000000000000000 )
|
| 297 |
GasRefunder.RefundedGasCosts( refundee=[Sender] 0xc1b634853cb333d3ad8663715b08f41a3aec47cc, contractAddress=[Receiver] TransparentUpgradeableProxy, success=True, gas=1802379, gasPrice=38486931173, amountPaid=67981199506234793 )
|
Account State Difference:
| Address | Before | After | State Difference | ||
|---|---|---|---|---|---|
| 0x8315177a...4DBd7ed3a | (Arbitrum: Bridge) | ||||
| 0xC1b63485...A3Aec47cc | (Arbitrum: Batch Submitter) |
5.001828397575773603 Eth
Nonce: 74252
|
5.001865269119299445 Eth
Nonce: 74253
| 0.000036871543525842 | |
|
0xDAFEA492...692c98Bc5
Miner
| (Flashbots: Builder) | 1.283495371654588512 Eth | 1.283604650167355325 Eth | 0.000109278512766813 | |
| 0xe64a54E2...80E2E4eb5 | 133.990698078090877132 Eth | 133.922716878584642339 Eth | 0.067981199506234793 |
Execution Trace
TransparentUpgradeableProxy.8f111f3c( )
SequencerInbox.addSequencerL2BatchFromOrigin( sequenceNumber=125521, data=0x005B7D1224A2B00F1B919CD57A00344287CF790FD035FFBF0FB016C425AD7C815BE0C23297B4B46AD592B6FEFFDE66B6E5975D98764C38E11057EDC54A65D7830EA076A0D50E45B75340722ABBE1BF5F1F1909B55D0A0E51464E1139D33EF5C37D5F6DF8A8BB4509DB14A50E203980A370442DA7380372C221AF46E73F9CEA1793F22AD6F09E70500D4E344E9AEFCC4CFEA59E4549DEA08961D7B30B49B39C59AFE85969197633AB592CC78BBD6639F35FAADA15038909520B4DBD9452AF668CC1500E41A6C05645E85600284AC088C09F19F8519D629A4A7A13D35D66E6CFFFA342904A81E4E780525CE8CE54804EA9B252BA28DBE9753E943243DD37DAD2C91043A5714B07B7B781B26FDF184CE1A3B628DA96742927DADAED976BBFDD78D4CB49B9FA725B1B43B13B6C7F4CBACC52631049A0624CA2AAF13E642EF9AB8212140614FA47A652F3C46EBFC2953836C6142154BF9437291626DA8636F335161A0D86847476213E8160403FC63C5AA090E786C88A66FAF06804E4BF0351A8DA0159EF5A7E110D5FC42338B7E976B698B6105048C80DC33B650E7A9A0D40B0D51B5A68C5C5A770D0403840DBA37B06D611801FABBA0A6976C616A2F22BE1AFD16F39EDA7F6BF4A1E7EA006D8523001C128E3D440555CDB3C3380DF2D98BBED182FF2CBEE58502AEAF05F8CBDF8746A823ED7476C44235C2F8647A1FCACCFFA87E0343E6BA2403A5318F3E7C8BF74A0A364BA2BBC5306D1ACBA75BFF9B23845AEDA63A38FF1B0529B1E581B5DE143739FFF213689022BC600C54B2EECDF7BC5E20682D236FF5F50139BC06E7BF4ACACD3A478A65C1AEE2571012A3DA1715F65177F0ABCE164C7B3AAF9519311939116ACF7A5970D5F9810A91BCAE8E616FAFC370A81AF341A9E1E0D14C5F9D49905CC70EFB829102E7B5159E90730FDA7461B1E0B0BEF8C967B16D628F1F4E36665BBA14416634382EFAC6591F293624624CE30E126696E2D11457532FF0B9ACD3A9070F0D10FF81C5A188630C8BCF76B2E0D22E7CA672B2D2C518FE46DD43407AD283CAFFBE81DC040055F636C964AB0AD78789E2800D9067A8B2A27D25745D4E0BF266599F00587F786429EDD232B9A61DBDB9E6FF0B230591A77A057BCA4F81A9B4E348D1AE5AFE9AFF8663A71D0CC74617952207C000CC047AB99509A552A5008F47F9F6554FD3AF58BDB3534EAACDCC52E9245D5D35B18F0A9E44B980C92DE5CB8938AC24EDFE1AFBA322F5EC0F92D93AE69DDC59F4F31080281402010CC32F40566210A21B12A1A9E1E0D14B5CA1F9F851FC2B775404FA4BAC5B4CEA11A6995D245B99616DE056343CB1E040681402010481FC1ED8B4CE7658DF4A93BDC1F92502D71789CDB8F6EEF6BDD59C36808CB1AA15A93D8DC4F088FA8D80C4516D611B9A95FD91C758B04B7BD7474A14A2C0A68CE6302A44C0C705F10EF374AD5ABFE3BF3F00EDF67BBCB85EB169C6870A9FF017E290BB34706727327CA760F84A47D4B4C6BF5284E396EC1E0438802B91E775B4020308B12D590D47311025B2ABD20916FF2EB58CDB8353923940A9B3899321554D981A493308CC986199C2EB85FCF2F29254C81DB8519900C33704E582E8F41C702C6E3B6DD4445BFD527F8EACF9240489028B0622C6053B5F8D92E29BCC4A4AB4CBCECF716822364243044E9B395582F579414F62109C0B2683D84F9DB1866B9C300B5375B0CD72092E5612FDF606E12DBCDAB74CB8D487A015E85425EC08B9115CD9149D1E1D1C87F86907648AFAEB2D090B02427E7EC14577E82794AB3BAC568B06160C3BBC03692D4DE6F6286220FA83D43D651ECC87F81DAD0663E7703E351ED79384881D2374124A5995EE3D6F08C6E3E48EE568AD49C023CA6594A5F86763FEDA9595FF4D5BC0B8AA57DF7E2459E57FAE2C26093B059D58F740C4F143B3211B76CD791342E683040926C310006AE55A3CB431EDEFE74D903889AE9C8973075855B704EBFCD8412854A8B548E6301A4F0C0E027169E4FC4B36C0A647D9F2492909AC61EC54B578811277F3C56A91FE1F0E950C87372644533FE95632385FCD92B8BB3BFFBF1BF6F130CEAA40A56673906BC92D667ACF08AAAAC77A19DB2154A65F86FBF2AE3E80130B03D33F5BCF8DA7421A3F893A1B542505815774FE0F626950816D1531467417802C0DCFA544AADC8545633168EC52F30C3E0C8333A382861D75E7A87DEC0D7731F2FB2F9E4858D0B52239221C2D6A07F1E19BF5DB211B8C683DAB0EA4E25A145C90520B510D654295C3EA21A7C8BAA8F07244CC4168ABC82E4730EFA27EED307F2EC0F83FBBEA08536A5B603E6E92B7A718668BD173668CFEAE55F9DF698D50F0F13DE6AACBC4F71FED17B5647C280BBB0D340302010883F831AA1CFDFC2A3317F9583A25494250EE0AA6A610B7B986C25C02FB89ABCF02C8321DAB9D76414BABBD27382DADDC4BB6FE73C7D29F42547F06E2CA9581D8F2C31A389C0CAF9EAC5CCEF639A7C96EC090AC4F4038033F3CA51EDE4FA4B23DAA54A195EB5FE7791FA3A7DB512EB7056770C9D30AA4E78BC05B71ACED2DF6812F2E164F11D3B8FB206223DC02DDADADB6AA26C707CE066877781A1521B26E3FBF72CC0715CDBB8354CC917EF4F531B5973597C21EE660595C43CE3DEFE167952C24E8F99224ACDD5F87DD11607E5A6072BB4EA8B297814D9A8281392007FD89BDD8BAA77A725A925DE7DC53603CB66833F542CFF0F4596B5178A8365893F3EEE9CEE0018681585FE1D01B954F9255F69262A20296AFFD53B4671F0D0A6FE198C4FD58AE50FF87D7DB1E5CCC076EBD5EE1B1A1597A4F57BAC0B419B61D3DDEEE85A8C1C0CAB4EF78B84429E43BBDBBC22CE33FBF166BD2BA288A02C1811D0BF0CA67B64BBA8FFDA1E02089C959DA4FAE199D0AEF27408BFEE0835F6ED1BE8EF15977A5D1D734F8408A5A00F60C59308FFE93310A469478F4A7C3A1CBDEE9602D44A71B5A860FB71219599E24C547FDA49AD4513F727700BF67A1C11DFDAC6D421D9D2BF4B6AB382BEE3D9E7A47796C8DFFB514709F56BE46D02D9030197C8A2EE62067A44C56C077100153B054E8B05DE8C5CA6B6D13A06461ADAFF9650B97A73C866CBFD39F13E5A323E70AED06727F868E1FC295014BA94441677405E8ABCC26C6C961F7CD686141AEBFC67B784F0E8E06D9C7F67DE80FF5F58CB40D86AE9E5C7AAB9ABCF24ECCF2F7E08AED1D3453240B39498981B9D07E4B9ED23BAEE90E421BCBB168C2420EE3FA7EF6628CB49EC16E464A5F104B3C68FD8617CB2C144C37B194A442103AF594F40275CC445A6A9CBC65D632EDD4962DEE71097DE8EEBCF7C3EDF6C4AA536A8781C8803DF9C00F4F2E48F2197F5B6B155E98C7F0DA8C5523DFEFD29B2BC81BD4DECE6E96971D97CE1CC932BF87C0A2829B405D5AFCFF67B89EE37F674D618A95F7FF9DA1D8ADDF5E7F0FDA76F1D59066E0BFB2E7BC13ED52188869B0E0F7FE7E317C52DFF9185898989A573D5A2E3D791DA69B6C1F82494031B19DE051B8F5527D2C894D8F82608D168DF9CEE164B9FB1DABEF31D4DC6B1E649493ACB71BA0C210916F444D6F07FA43670546CAB00CD9E95D83698528554981D429773437CE147607E58575E7A36E3957ADC6C97E29A483617A43A90F849682E571420E80F33607BD30CE4F7BE40FBA063D4AC2B502BD22D65B0A13B76FC26008804EE36E48741FE573555BD7CCAC1BF9F8FEAAF5DD34316AA5963A4B1E3467F2B476A7B9DE4EEFEADE373B7C7D4AFB08EA258AFAA124F968A596EEE6D6B9515ED9BDF44336030BEF63309720B828C8020812000FE786009A45E09440F0481070193BF4DDA5A73302146E9C616BC01023B81C024D2588D27E7D18B9FD033B36ADE6752CA6FD3DCB1AB3840F263807BF91306A2A169254211507B252DBACDE9AE804110DF0A410054CC71EDF3F542C0DBF759B85F082D87C86C49612E2B17AA4F14C6D9B3ADFCBBB103A365C22C2EFE59F4E30B9225A04C52AAC053216E7AA42DD6BB6532A140358C504372976B5C37832493B3C19F692D08C303FFB34DDA038607A02C20CD0A683C642DE2E93E74AFAC078F4159E44A0321B474B4A99340A0733EB587A1431BE101741308B87D75B2EBB554D5B193967EB4C88B9A5B111E0E38AB4DD1AF4DF39C5695643970CAF31B0003B5282A7DF19E523C685F7638353A9396490B849AFC07FACDFD7DCC6AADEF947F0368FB21C91946E395897640EC6636B3518EBF242BF267282B7D1CFB1C397AF039225BEBA7615BE6FFAC5AD12253203B1CF63DB401D6A5AE7A421C0F2B13A3347322A80BEB346EC66A8D3100B29E7BF7753314A5F47E4F9FFF4E290E1B81B4272F5EBADA4654BFCEE09AF9BB171F00838931DD5A4D7AB19DE6591AA80D57F8E8A5108B2DFE76A968557BEA46C51684D1071407FA02C5888221C78B867DF8058AE2B91ECF92DBB5BB81916E2FF8361CF2D2FA18BC303348591EDE05533119EE23085290A16114108B3C266106BFFA45E98678B588DF7D21087BA1C7BF2BCEC24129173DF8391C99080A824584814011C0F0702065C6828D46CAB00A115002637E9620BEA8F8EB540702ADA0ACF86F6CA54787DE1E084CE190E2FBFA74006B360D94FE0F0094FF0EE9AFE7F97EB4CF5BA3D2177815AD1093C09F1B5284E9C6CAF1F7CA55AC3F5116384C5ACFC814DFC8C428DCA58EAF24F424C0857023D42CDA2FA0787483E1F7BF9A79525A35810300823B4E68AFE3E05A82E6FA8D3A998E0E02CDEC88E5AF3C8BBB5CE387B2CC97404781EDB37F078DD357E11916C30761128F63A25383A920FC07004535D664597DACC9437FCB35CE584F3D23ED2AF78C0BFB4F982051145DA9E392EDF3502FEB3A068593241A77E7E04F4A5A2F3F52967ACFCFFF7655406A7EF8CF49386884DF0BB745B572AD5DB2A347F8D764F17BEB5C550326706C5A294D118D8487A9B3F85D0C0A6939D6B3956CBF4DDC698842924B6CB1BB0FD419D0522AE88B32CAA9E739F70C87841E510792DDC8A64D085647ECFB0CD4C75BA4D0555C30347DE64802647EAFE0D9F56813E11AA55A47E6F590D27FCA26AB470F65B6F9ED761836475D53AF10A20B85BC4034222B9A23F2FAB6E3A56CCFCE722FF4707817F8C805FD3EBB80DA0FDF5F555880CD879B5907D0F3AC623A3219111D916DCABBF95BC8C25299D195B3D0A9A04E37BA60435B2005526660F2A08051D051907CA0A00BA9F6253892205F826DA9BE34F40AF0C7955AECA09678684428F8664A1D0E800198EB6496D1E8C98E46344C8048B4C079049BD012D688333F72546CE3F1EBE038A0D82368EAD5FFDF314C263046E84F3FB48FD61FF51327D17E1B8CE8CCBAA5710A3E3B35439F1B22D14DA3E1A45824A27273C2B32CD89A36F2CDC47C1735613C4796206858E7E7090E22A6BAC36D77F8BEF960E04C5685DDB531598EA9C1C1A300AFF6F643251162807744298ED7B06BB10F0CC56B851E589BADE87693F13BA1FC592F712FFA825FCD0099CC552823AA68F04E3D3E9F1406CE7DEB603EAF48939ECD8CFD6996C63AEE21AAAEF7B921ADC62A6595B716D9A8DD1F2564EAACBA199FEA38C4123F79A75781870352F70553C597CEF19BFC5FAC58B85D1936D2EDC8745391A17634F48E07150F9466281663BBD3329602FA0063F23B9A6E952EE2F5A5FDAF6CF7AA72596DA425CA9ACB54E46DE2AC022AC4812EA82D080604028140205003F4F92B56343C3D1A284A455922EB1F825B8EC9E72AD4ECBBD86F49689FE932D7E43BD3532E746A916FAB7D03A22EBCD8C8A51CC620B7FB1E96EB43838343CB67D34D97F1438F8DAA8B98B6E629AEA4630146738B64E939503A3732C7B6CFBCA519DEF9195AF7DC29715E11BC5847B9E0BD987141F9C9616431A9D0960A33946DF1BFF196670FDACAE16DEFEFAD7DD691B54E8F94B9A7F5134F653F55FF5BE73796B69C82843396C9CD4CAA7D98F36F041BB868FA24E4CB000BADEE72BC7FEAAC1FC417E3044BC43D75AD87EC87832BBC67BDF2F9A7E9B2C50883FDFD8982D72CA87B03BFF334A3F0F930B29C17A24F311013CCB5EC1E671BFC5724EDFBFD7C88D905D8A7F1CF20A5B4EB996CD4A6E0B17A3CC43D5CBBBC045B6240DE789CA92DB1DBD0E6BA9355A77B347D398A3C9AADD01603E100D70EC315BD4B6B25F6D7398B20CCD3EDEADC1DF3F2E87244C61A17AC3FC2AC788092B31B81D859E73F43A4BD33CDB501A4AED6BB5C4C3FB2535289BE60F1D833874D281CE9E26C7E5C90E22F7CD14CE621E512B3C449158F08451BD0FB2F9CB657439384856EA87FBA85FE8CF1626FA481C1A4FCEFC202F7BDD9DA3832862232AF0C7B770186930E6AE80940CFF75AA7C0E0AD124DF85D836C117BA0F8CEA3DF81050E129CFE0D08A8BD475C25EE25B7093087572C496201E1CFC326A79CF10FF375D1CC39AD7F9A1795315D67E8BE9A48633BDEB89B7B82008A1C3A3917AA97CFD87D9F29DC51236DC95FF6390D51C093A573964B3B046F775DF0EE7D8D3CB8D80749C32E897E9295699F9214CAC90469FB0EDB7B518BD0F818FC750083C160F456B797BFB210992F3B5D8E1CD32D3F7B1004E1C6874010B02AE0A0F0B08318E3D80190A7544E9E0352560C6506E1B424F2B028DC08DB6694F7312A470CD923586CF72AB35CB74A9075C7925DCF745E72B768912F4E8BC5AD6C2F3B14AD2E31C8EF77A480DF4C849D8DF01127BF3C57DDD799B9DC81EE79D584CD4D4A178CD4B8C87E2AABC96AC1954564FE7F0DC19A20F521A51D05BA917CBA44FD8EA3FC6398C85FD765F6AB81BB4FF854AF5FF25754100A8A8F12D6334C077E5170FD41E671068140207C9F67A7D51362E5758D567885F3768967B35718BDEFEE5508DB181BFC5CE80F1267D01A179621C378DC5EBAE0F3B72BE9CD8C48AAE88C0F46CA31D001816586C25005E5EF782EFE64F2F4A30DF19B78A744B8CD758C398A49FE3771243133283AB126E614FBA21EBB8030F67C463B7B58F13256B4141BE584AAAEB36966AF49E18C87448801781A608AFDA7FD667B982A1B2AEE5C73C225B0D87684C64F6830F8A3D39092120064A3B89D53D4F59ED967D2E0174B1BCC6BDDB06C78230E2CB43FA8578A98C3C5C803E5BEAEE7ACC88AE628305B5EB4A1033B28DA66D8B823C6C665FDFDE9CFAE3F0980E0837BF0F088EC1953EB3251C32B28EA887B01DBC045CCCB0C84034216177DE7AF2E4F765E99FFFD9FB3CA5392A5B8193911AF361B4D17968BE8A7009CF6BB7F616CB9A55222447D83C1C414D16650B7FD944946319D1482E8D1F40364C0D4656D6A7D2651D1D247471A287F2E4BD66722539021E20EE2891F0CC2B464A5F927E31A89FA06431D016847FD1CA6EEFF99FAA041BB85A29C5156114744CA4042F5812825B718D6478100C14B709B131E02F5760A926485B152B36E0B854C1C12782CCF18A452632DA4E6C51ADD61044A80267DAD0FC6E388699F5F6F4CE2D214EDA371B694D830E61E415F9696A663EC099FE7D101CCBC081635D5ECC8FF6ADEC4B43783334C48F2667ECC5ADEE1A20CD6E829F3D7A4084BC70776EAC33F057908A154AB0C071C76B0C181FBFDB852ABE28B3535D1975E13E7B32227F33342CA156517D9FD194902062E7C77C763E6D3EBB6C67260B776FC61883EEB54D85512046EA73ABB98D3555E0201023F393C7944FBFCB66A0960A6D89B427CFD11965CCDF4CDCF9B4F34C227A9BB907F5E76F320588B2068115FBEC544F4F1365CF7BBA293332DB11BC783DDB51332904785C10AFD98A40F0557D638083EF92547923F4EA5F520BFAA7F59DE9DFB0B143414080A0E0AA1B29440B374A0E1F61BC5113943AD975225416542636F2BDA8596A15107F40EF4FFD6AC6D5DB8D775CA3431228BA01C7F7C3348E3860BCD5A0B613F8D6866249B04183FB0AD8689956C64E02729F7927C58045B1911F67E813C4795F87E8B4EE2B84236846BE01817E421C46812E216A52D06C000B85BA41FB6912A3146DFC2361502B2EBEF8631BAFD32C0CFDBC0E0EFB9E7800CC83B3D74ECE3FC1ABF266BAAAF806D929CD0437670EE94263213382914A3D0EE1462D3D1891003109CE262421414246D04367F33088C4E87A23192D1D55D5746058DFFC076BFA904C42F1D991C90520368110D8B82029593C3259C883FEE60893E6262EC7AA7429B1006077769825F8D6BC857EBB8BF1A8340E6C48F1AC1C12057741CD59912562DFBEFFE565F37D0BCD2AB71BFB58B7B0A841CC1D096459C801CC522A4AA1A3C27413880E87A75FFD81EB5E389F76DFBB52EBCCBE6FF235EC8E380DA7A4D3EA7A83AE21A80FAC1D0531560A72CAE6DF5476BB82EE36E56A2887B4E7618B02F8EC86CEF1145BB75F3E06DA1FBE43440FAFF18F4847A6DDF2EC687E9DC699886B0C68565F4DF9AD2FA95234A0AE311E7B800827FE8BD582C22A489CB5D72A59B9F6C43CFC12AD901D38FD3DCDF5BAB6456F720EFFD1C4287C5506BB9CE2AB0288BF241B0BAE773FBF41074AD5F3BAAAD860426124336939A16BEFC49D62FF5E94C0A4994CFF381E3A5F039F24E4F34D2CF63A775D913A33BB78E60B0AD2AD8CFEA38E83672DEFFC9EF64B379E8F82EDD0330E17553E1468FB85A761344E0F99357DAA9829DAA5EFDA3134A4CD1369603F1211A3FB351635E62C228047959548549F50393769C4078D7163C90FA3BB95FB342C0A60575824F9C350EA263342B687DBF2B6BCA76CA0FD96300AC76F3F7D6AD1425C1A3E0F3E84FEE8FD60A955C2800305311AECD2BB9DDF20A797C57AC2E77AA3A1795684A600F69F91C0223D7DC688B51167401FA029D89446F8E867DB207A21803D6B28A0BE9C10B53AD62EED78733C3B4B2FFBE06DE2D8777416DFA9B0BC31741C331BF06820E378715F983826F5DEDEA949222A2625FDB80A5BDDCD58C29D749FB88D0EEDE5470E54DCE2408858C5B4BB2839DDCB1125221051A3C8791E1A30407B1C34227E16AC40412BF8BFAA2288B9DA623124B22CC245643CAF8B9124E7AC12E1DA43AC96684A13A1B7DB2D658BA30C2C1FD4000F1D9602CA3217A6421A80E5565A18D2AC5339FAEE0444184857DE924CCC150B4606CEC5A63E9F0C15B54FE09949E5AC23835F4F3609E681B0CC886368B0F740C721D6DFA94D50AE5DB99533B87C853B9C30B67BA7EE399DD9AAF48A6EEAFFC74C80AD624905724FCE44E9FD3EF45B8319D8C62EC9ACA4AD759F932C48FC4F699824531A185B8156FFA58F3C9E2AB3377039283307CED55213BF51AFCAF090207AC38E5AB7D013651F5D8C54614ABAD28962FC6B94684DA2666E1E160A6DE1F51CAE38786FBBD557B4A24DBF84820068E137E56CA79ED25EE7C68719FD77E827EBD967137CDE33E8F1842B143FBFFB702105494977D4C136894031FAC53AA4B186F3792FC69EF65C0381A6AD4C10DF3C90EA53D230C6918AC6D922CA9E602EF35D69D73962ADEE59A2D7B86649E118589F311861248533317DD70F49954CC01A4741DC31A82F91990FF1A52D867DF837AC96F02485E5991831FBB9BBFDF8ABDD4ADC2A0EE6886B777A4B705BB3DB2AEC89FA6E98F73D12BC59EFCC1A6E7B86A94EE7DEB8D83FB81FFB6E6F995ACEB96D73E52EE0B2931454B837ED29550E01DC435B6B180EF8BF207D37DE0D5CFEF0B693A0487BC654A4569EF77005FAAFB9F6855BE3593F7FCB43F4D02CBBA146A44A2EF16336F10F3795D11CF4E64C0703FBF36D8749F3EB97733F68616FAB6354C3C86DA7D0CDBAC2D547B082395C6AD31790E0949140E10C8F00ADE33CE455217B5FD2953F5E34850C1BA6337EF50F5CC120B38A10DBAC7033CA0CFAEE8833DF146A7778CFEA134FF7336332BBDF56B908F9E7811FDF044741C89D3031D0F0814BE71FA66F41371ED44B58C8FD153D593DD703B263FB384F5318FC64F4D6F8B7F53EA600361E520EDED5CC56AD50B515A29D3AC40ABB7F7794D3A4FDD2F1D977EF1DFE0D771BF7828E439DA7DD3264843588CEE61B97ED7D3C1099D196A589B4C703C02036060CB301B34A610B34AE712D98DA116CC9E7EC698C1F9149C0FC7DC72F350CEC807E0AD2E1EADB96CA4B5CC7FCC492C22B8720C12C6606904DB547D6309761CD430EF4273010DC41E77090A799E8BAC6816BDCFB0D508C6ACF9B60A5E3736712D64EF80E1E315A5DD44AC93913009DC844DD8797AFA131AB3D1AFE1FA2A87D7FB132C9F84DFFA3BF70F2DC41F9BD6AEE3D1BBD813A1C527DDE2FFAA4118299A886905801E9876DB7DB768150ED1DD1E43C9BC60960B30A3791C91B850FC97DD2E1B45897A604FE80BD835E2D1A7523A0267B5273E3DE4DF55D00C31C867A19AC4E6A647F53493D01268BDC228AD540281BD12DFBF594CD0117AD107AF0E35B6FA956F28E916131593271AC7C3F6C2A2EBCC1CD181586B439B5B399161BD56A64AA2A35B3D93FABE50ABC91A3378A9B3EB557F4A61D095B02713296ACE1F08BBA1FFF85216A023B802D228F458A95814EF4335D842E79325BBDA739CA9B0DA4E357C0084077EF4A01E1E8D44F93F3CAA6C1B9455B4E97AB74138F9233E66450F31AFDC06CA797A12DE05776CAEAFCB084A4AD307343FAFCA8E4047DA40C9CC409E0D236C37575B45576B073D5E395B5B9900574B17476B10554622448F0124ED8376C302EC8E3C9B98227DCB92D598009BB65784D460312C3B6F43D9B1EAEA544DD6A942EC97DD74FD288523940A2E57E8446837A81C1BBA52C484C9480C3A6FBD05628F6EF8CB9ED1BF9FF3BA343239C4E07A30545A106CC165C2507FE1672E2C08F21704690541F240402C12D70548E17218F210774D0A723FF6F21F749C16E7883D7873444EA903AFAD9F2AAD4347D79488A7BFB279F22872F0EF4321AB6679697EFDDBA743CFE685F6699B4B298656BDA1A1414495FEA655DE85311B3B52A34D01DAD066118C4EC0715C5308F7107B4B571B4B673B6F075B2B4F373F577B7F177F574710FEB235C5BD921A88A6C081D29B1E929EB97AF0F883E74A2B0DDBB167442111521C8BBB38E26C9C64E769F3CC27DF088DE4705A9B74888BC53F2FD0C27EC175B42F2EFC0EE2EAAE7F1B8945FFFD5716E986C617118B0744B1DADBEF5FFACB9604D7C9750565230A518D7AC0321A5AC9F67D554CFFFFF5841808072A5673542D0F6C3DEFDAA7BF2EFE3EDD467B6C45803581FBC9494E6B108E528302E814A174FD17F18D72B3747B394DABFEF1D793138C1E1B995ED30D4349164C25BDBA30642FBA50D89C071B6EC8B64EC2CA71CFCC4FA77198C301FCFBE1A02E88431F0BEA4337C8ECB278D00728464FBA6CEDA345CBF6C02D73641D64DA0A9D24DE607879000AEAFE47C537F52129474C0D840E4517D7BEE64898C4E56F2BF920E56A3607B4FCB59C8E9CF8568924241BECD05F38446D52A0F0C6FADAD448EC2346628CBE61C8F7CD587EE0B0D143EF5B400249B70768D63188A15B03ACD7FABE93DC746D1841781A2D40A100D38C96F32A35A635F37C829C5C251684710330A0FD55F1438713F5489FFA5E24DB6CC6CBFE8FAC723914CBD48F35BB4CED3F193EFB8079A12F60CE28C889780C5BDAE502281ACCC90ACAC25C6580DF3CC5026EF4B1A4E5905FA469EF85BF87778EE8AB0DF6491EBEF04F56926C10B1170DB8D5A4078436D8D066DE785E7A78649C5507354905A9B9F49846F880937CD6FEBBB766E6C5431741D9CEE5BE720F6F21CF60EA5CE73CE96C79223F7E056811D0C5D409271BEEC84CBC2A3D4135F437513609D6101E9D883E93FD8EAF31241E90027D4E241EFC6C64502B4059594B2BB23DD39183C905CE15FF42E163452E9E5BC22B3ADACD69F7BBBEE7A2F49088A4DE6996BB79102C2FCB52E4ED2C3345EF209BAD3BA78937A3CBC47CDF9DB8BB2C661C6C637B003CCBF004B47C0F83FF14C4E56D9853A07832A437984438A0DF6D583C35D4B90A7621C55186C1593E1921D58B9836885730B27EB3457678AEFD3C80E30A86B73A0B37EF9F9ECA08EF02D3F45E28D1C3D54F048806849C0745C2C722254EC9713579C3797B725130A5232A15B3062C6786608371DE2255E3976E3053197F2F58DFD3BFBFEE830CA4EC45768D916A3342962A380006BE877EE193662F741EFB8923B4235F0DA225E1026B304BF330764F449171411B01E68D4B2DB3A368B6F154A5CEF675C2CCAF0D5E1B6D9451F19FBA258570A3D4C7B69209B79D9F25AB4ED10E3100CAFC2B282C35DF8F342EC604659844343A55D568ADCD92C824C672FBA19E8B0EC0FA897BC6C4EE72DAFD9FB987E39C9141BD96C63AF9F3290E37FC8F02FD6E6362A837AB3F1B1194CE2025EA8DE77A39EDAD52048DD4099D8CF51E16D9D679600A1D946A207D3329FE2FE5C32226539B50AD7CDC2CF64E2C81897A4DF9BF10C9FAB1D3DEBD83AC4EC2E5B325FB4229ADF64EEB1D3521A85FFCA226DDEDF0BECC28A0CBD4A6AF669B184017DABD257E69D5A6D1C1B2507299E9C1C7636AE4B1EE838B30D8AC7E04C3591C060B7EE77395283C52ACAC056CC2FB0EE3002C59C55D8922BE5B3368EBB166DCB2FF3F56F21AA3CEA3B0BB4FED7BFA53002A8CE1BC142AEBE30C524AAB81C92E15DE92EB677F4D91F4CABE32BB1FF550D514AAAFA12336B4B96E3C028420EB5F7346F09B010360409897D039075A12027DDD4AFDEEF5A5E8573F2CFAAD1F5DAAEA814CED78724A0DA08DF6877B19197886D6978E92D08932D530BC5D6FB0993EE611AFE2D6B6B8044B1B1146B446063FA6177F67BB5FB1D0167669ABC3E77C21B83B97D1BE65DDC6947AB8EF7959E947059D67B4690D0FE7C8082294F9100767FAEBF0E74116F76FF4DDB82D596FC3E1E5726A80BEC1BAB8E6122FA168BBA49CE097FAE5D39876E871E405FC0FA77E7D5897AC0732DDBE721665C5C164DF53A9F2B9E951FED0A5BD951D67692553B35E8FC3F5D1BF214C6271826B0738A3CC61F825DC51F590128D181FDDECFFDE41047C7A0072E1F8EC6DE4BCA44A811917289FA85F8F2043A479CE5E2D532FED7A045E363810FA02F68DA88846893608EFF8B5A3356678D4FD8ED66A9B94642DF9C79B25B1F9C0E021C01908F62B7F135C4B41A63DB60305D42856CA4581ED35FA051DD9B672A27C83B1177F797BBA0B24361754F80B1C5E953A0FCC68F5577BC5002EBDF81513A4CA9D3A3395EE9FEB56CEBE99FE9A3639DE24CA5FB4E771A9997341305287BE6236D2CF43F4870D9CB745FFDDECCF3F356049CE841B2E53AB174585584DF82900C7DADD98F5B97EA2C4B5EC3140F8909C3FD8301283A221AC9D718C402B7A004B662E33FCBCF0B890F960AF0BE7C71A3D1E3F2BE5BB5DC0D32513DB008E51DC7FDED5B0C75FF955E19D36D1BA03A48969A08DA82911B5808671A73DB56EE31C961CF3309FE7FB60890AD62E9078D08007C00063D2F70891077CA9A8ABCD7ADA9732BB1BD2FDB12F9BD12D49063A6E2DBDC5C8009B161B1E1E031EF9AC60DCC413CF5F53EF671CA5DFC2C6EA3B7F155393F5C00F5D3058B6E6621ED017B00BF49A137F422D89DE30C8E68B23CB1F165549071B9C2B8615575416A3FBE6ED706479552B398D266B38449FF1FD90D515C0AD8B7E440FDA1824AEB6FB3CC94F2CE5BBB32C31FE5A4ADC928F749751552B3566B90060944B2BE5B3D614953EA05C1B7E59F68989A0C8B49898533F2BF9C048E51C5C0CA15D68FE3A350A3CCE0D1783889335068A52165CC852E59DB4169ADC081A3A8A47BB220BF89D8B5FA212DE291D8DEDC826EE6C49614C5C3C0BEAAF5B1ABA971CF9C3605BDD3E669E326A717AD5FB6188BB049B5627989FD7F9768E20C930000688A2B2DAFFD4B91BE61D5B2926A369D9A421D0F89F75DB17118F96BC572BAC24014C0D48C420A45292FBAC25BACBA99E978EF31E2383B01141FE28FA4A704E44B724CF8879D1FA8CAB529945C1D55573F6F4DBDE612AC303242A26FDCBD2891C57E5C8957CA1E92034F3A114EC53C195D74DA97F7E1C5724C36398C0C490D3FEF7EDB4FE91E62ECE79AA3E4B34883C4FC898AA1F2015F058F4EAB3FBB288D5839C8391CC0137264789E211948420185C43698F8FBF1E4DEEF4174E4E1370D407F152A28F1D73E267848B0E3D2DC6D5767EFE6C669A047D745273A336DBCF1878B25458231244076BD97077FFCE6F1A8E99846085C28039C0600F37845645E94774C1D740C5482AE39E96FDAE9F2DC5BD49D29429A72BF28149AE9C1AB7C0C221878AD999A5FEE565C8F267988D9EE35ED6B126B9C22A87CD418F058A17D450D1F5E4881DC281912DF495D39431BB80607EA9F7F1AF8AF26F2E6A9D62832F4C7C48B5F3F861D580BEBAD951D7564629793CDDF5CABFED6AB99FFEE80F265D7572B0BBF35E01F0FE72780F28E4D925B2A299BAD9C58A5850702148880130C0C7B02CF98DC5F7681303E3D93DC6B4E91FB05D523E4F4F4B56F0EB73B6524D2D40C97518FFEA5E10935876968C32D83B8A728EF4EAFD87F03059E6BAFABC3A39980F0B130885BCC0F8FC3A038CEA9D993877DC89297A7396E91EE85B8A51F37D8193460C09EF824108866891F82347CC5890DC5C5F4A36314085BDA6F03B2817639696EF996B9320D45280F691C9F3399C1751537C4A232D58BEB409FB3FB5D06C3610131C2CF5E0ECA7006CA0A5713A0BA391294881E679962288CD061B91396012698E9526A13C196284E4DB0CF1623AE734478F46D6CB455E145817540C44CCBEBA9687CD68B6926C01A99D321FFF3E5BFF5D7CFFA46113AF689A4DAA659D9B4C2B446761236A3F59E6AF821106C0C0F2C7A06E2BDF79F347FF626A2D8F722E1C8F2E1693E5B498D85D19E39D6C9E29A00292FC73D5368B448751345B6AC4F55911BECAC5ADA05274AC64E804566BB8C4083E2F8C3E2A9C079CCC7D2127EBBC3BEBFCF40FEEAF9BC4E49ADC0DB85FF004A7CD74FDFB009BBA10DE0CDF4CA31AEA80056569186DE2A691C7EBE4C91C5EB382572B3FB517DCDF1F0A79F6BEE524E216223118A63FABC365E72F2CACCC8D7EF35C074C7C240DF999F671F83ED9652E36F8481A0003744888968E5F27A70CACCE9295E799E3BE5C716F697506BED74BE11DF630446900C853C19ABE55366F6BCD696067AD028C4FC9231D6153AAB1893E1AE18409257A5D889420181048AA1EFBBB15A8EE21D2569370AEC791D5FD8ABBF68F9A3FB65605C22DE602906AC46B96A30F7DD8641CEB753241DFF6911344A48CAC190C3001FBDF9938334953F77594173891CD0B83A17A3B8D94C5338EBECD1BCEB08A8487A642C28314105C73EA354D9D14244673FB4E12C4004DCDEA11B5C104AFA6A933189E8F1927ECF3F17296BFB1A5B1FE0A0E285A7DE402825D887C5CCFF44908307421E4D83618BB26E469727FBDE22B4499A60C4CE76E25ABF69A890BFAAC465993C9D5790E6BA0B9E119ABAC9A431EB14B748C19F54916BA1E2530C87A5DA466B437410D610D9BB875B7BDE8B2D0530ACF0169DEBE76AB2D87BAADC05BC0C3AEE1B6C71AD36147727286D6F5EB80DAB691F0EAC422421B11B380837BAE05F5C086D017B06EC44DCDF178153B0DB2FA15CC896F90ABFF5625F6561A0EB5F49BB8F06BD09C3C99290F4B3C5057C176EEA9C50C6E35970993FF8C9E0AA21D6201232D2EBB14D8C2F25FC07E6D3B972A06F2297F80DD8245B1E8DD889B48159D3240C3F3228347F9159E3BDAC8243B230C46F7A49CB91E61E77FDA0EEDB3A2E75730469D1E4C7ED68F03895AD4624927541EEB6E4011DE90535B398F9B04460C7D9CA64BCA92F73FCF1B2A8B2B9D70F2AB7BFF840E91CB926524103948BBB13E38018C97794B0F874E0DAA9B0BCCCF5CA4067757AF48AB96C4F61F5FE3BF78E9085F3B6C55601E1C5E0D242EB40F22FDC0B8306C23D556A1C516879D37EB11D8BB2EFF15F37FBC4257247D355437E3729D03BC535B3F3338BE5F313341633184ED79F1491FE1974DB238D580373A5D074C4B11AC0C0FAFDCE4A042A8B7D26F13E6B463CA245A6CF84F7D99BD84863528FAB2B425ED0A2D51F697F12B91F46CCEA0913BEEE865FE5E43E8CE62D81CB9CA91FB4D06D0CFC0271CFDA307B9600ED8142778D36F952B9A79F7590DE737389C7DA1899D9F881E6BEF4D018DDE180F9239A5DD44B2E5DF7CA4D5F912657C54F1D956B792345496F419F03008AD42E3828885EAD572A11F3039C3D4B50391F405D4460AFCDE2E37FD8E42BDEDC8617C0A40A0DC9CF0C464F41C0E6E67DB2B371C88C3A939E1F75DB8B3998669A69734189862FDD713520DB82BF87B696A4008CC0D3C43DAAE7F299A509DDE029A348C62085F28A083209F2E1223100C0804028140B838D0175C8C48A487A7271FBFB08F8F8FACA4B8FEF556D31833BEF273546F66F5E57429A6C3F02E9C8AE5BBD07297CA61C265D43F23BE4B76CD107C38A91F843C22B88981AB5A330506DBB0677EC36AC7B732383B3898ECF39560F7B0E9937B06AC2A94DC45C4C957D9248C0A1D05C356847F06A4A1631B402026950056A224B000C2BE19B86DA0C099805FA52D20780B87306006210CA3410817641B2888288828882848D1205908120728C828C828C828282828282828A828A86650CF7133683283B60D1434147433E832831EC7281828182818289866301D0A260A160A160A5634D820AF9A5A233C4B44C6C08B2E8F053960383E9647143669833D713D7236DD7DCADE78EDF026183EC63404E5CA2AFC92B7437CC2D0D0B884C1884247C2FC2587A639B43FAE78130631EB447A7F304672D9CB2225002BB9104A85DE42378F8FFDB0A0E44DC4BAB4403717FC550FA722EFD7C0BE86B671A2FCD558E4520D770562C26FDB61C1A0E69FFDCE3DE41295528D1A5185F5E0A66D7CF91B32023C0C632176E8AE337C37187A3818951841F379423F62F6EE2CE6F5EAB515A8023F274E75A31D4C07B4877244A961B9BCA65C149364DFEFD649987393130EDB6726D15E0543938954720BB39ACA8D0CE160C0E5D9AFF54F76191F520645106C519A0DCD5836B51AD896A102FEBF54D36AC4454F163A4D1480187AF8EC3DF3DD6A0C536A0ADE82854515F294C55B9FB17FB9043EC7476A78D8391035B11BADBF291764CCBCEC8CF513D731AA57ACA3FA4BBEA2FD7D203CC4BCFE086F0760D1145ACF1B729ECDF12CD05B2971823872411EDEC7119E560496BC7F43314C07B8DA237767C308DD8F82DC914FD93ACD36BB16E12290ABE9350623001EC15C0153053FD417D4FC5D7AC184A746873B24FA4E2940F78F420D096E685F4B5218F07DF4BEE89AD2749C540E8BE66F858905596280FA7C3B1EC631097BB0CB86CEA9800C62F6371D1A63E9B0C1A4B0F879C5E46F269B7B2AD279927D5C5E390921E1A1484754E4CADDA40BD4572140B9DCDC026A69B4F0BD27E8AF7B59467EE08F968E91EFEB2F07337FC18EEA7086F1C8EBA2090A5697EAE736E0737CC4E589D3343EC765D014419ACB64D98140815E05D5883F17BC14A8334E11412BD88D65290D18490AB21B16DC2009AFCBBC83E5203F65341F8B522A54C733B5485D8291D2B031100A074F3AE6794D262AF03AFCC669B6395D7EDFA9AEE64BFD69E2712EB7CD6142F523E2393A1603D6836B20C3E97487C3161D205D514AE7489C9C4B2ADB8AACE318D3238C719E14DC803F12816E0C08CC4F73FFA5069AC2C49E686940644302AAA13AEDF0F04AE6AAE0AC78B3F03E1E2F7202793A83F940EDD576D661A5DE6163A2EFFD950A28E2FF9BE54D3027D6EDDB77F11C1979C178D2110F54178F9763D26F7FB2969DB96F5E96C4FF3C8B29498EE3F45FF4975A0202D50811063710099D1B46F4DEEA46DE0AC1F047EAFA388FE0B749B4C3EFE0E1DC04C4301E8B84F10253E6A6A3904CFB2234532D239150AA4B7A5A42887617067245CB55466978CAC1F00F53DF2B3AB755CA75A2EA9CB625FCEB47917CBDFD6F9EB0E42FAE9A5E63307AD0F5BEFF74D244B24A7AB60FAB3E7F7CFF80EE34DC0B35799CA30DA3A772DE41DC3B59CDA0B1107D9FFFDF67D9C190CF4A2F3DB85CC3199F6606C31B89F5F732FABA19E4F3985263D0FF6C440A03FE61ACF986B3F6E1CE6FFC15FA5B9FCB878710F1107959A6E98BF7A3AB49C56B0C0616787642B9DC03CBEC83FAE3C0023F675B8B700AC1B1280412EEC280B820701523024526CE8B17D63B1FDFCF5A29A574AA297E84740E8EF03491C23797EA9835A31387FD51F517E1BE2DC9D3CF20737C0989D8561D03E3A119A959C14DC09C7BB6BA73FE2E0C45B2C0EEBCD14254248390094A7974FDBC3276D84A35B5466A78307290ED0BDB7046762DBD5C52E92A6283B1A49F9F4FB28837F1E26325411E3E47C760A210A8E84A8F5BB0FCE59133441C708BC872CA0B84D78D10164EB526F7F590E9526691CE21FE11177B3522597C2A45DD80419FCF7087FD04C0A368480A859F23EDE3C807DEDDE80DF16F55DB6FA4F45AA5EE12FC29FBC50949A7AE66AE15081721197D9B191EA613E963C178A9A8A77161B754DC6C21D447AEE1F4E61E588769E87B22D95C6B8A3B8A31016801DCA065167118F01D8CBA257E4DD2A0D3551CA8D0EC671A7A28D6F62367BF711A370663034D6E234B530E2ABFB21BA546D95110C8083F5F1C7D18BD6157F4BB73384DB906215D631B1A08652916FA9C02F6E61E3113466341FF0AC43B777D52C1A42728374181E807BECB99DA51CBDE04A3DF0EEB5C6832FF67A34FA91AD36D4F3BF09D6DFAC388AB2E463B29B5B3258AF4A8B62C43E551584BAB57CF02A26E01C5A9D9827F00FF05E13CAA57382561C4C31091E0A8581017BB5F6050A966429EE05A50EEF93EF2E0835EAD5E23CEB96669FFE2AC557DA18F03C21FC94F827F9DDB499CABA0B7CBDF632221F15949FE6C333233BF453D51144EC1590074EBC0335CFE23B41753FE724096943CD3A1C90F6CEE282303B0E7A5141EEAD0924C63EC21858DA4BDBC18F974902B671F8F704F3FEF1F566E20B6B1CA6A3005108F0D41443BC402D9E07FC1CABCD01516BAB13B2C9C099D9432DF775ED18CF42FA6919A2D6C6F1200761AB61FE5B96BE64AABB5A8B43EB59FBC6E5BB559329F85FD59B78B1C435500429BD0749748F8EA50FD78613D1F64C53692E99220900DD19558B9273112DD5885555C8677CA34B1A64802B2B816E9BEB2A30C8FC520EF7120BA0E84031DC55922BF6C81E48F4DCC1EBC3F5F3E4CB25B1DFF229CB77D0E1C3EEC10763101F4C59B0A65ACB29F9E9605AE463217115904FFB7D61326640A07F6160F9C7D62068140201008D401853CB74456342335805F61C8FAE1769F751CC063E1B242C67F293D865B52A15F8D9B3421451216FE75F8EDFD2C688FECBA47A2E64DEAECAB1866A893A3F9A613602D4634EA2394816FF20B6962640013339B6B960BE90B7C1769839509901C464F68B8BCAD22DB339A0A59BFCDE452F55B0A72F3D32F7589AADCE0B7F9B76A92839AA45F89750ADF9D6A9F9901D9E0F70FE6B9AA2E42B2C7F320F7048178DE34D1883EB53BB53695758305780F6E036953F805F2971AF7867DE245938EA49C7C88BACD15D395DF964B8F8CAE108B7CFCB8C3BB2032DF72342C84818A0AA0C7EAA06EA0A0A7FAD70405E804C432CD12A15E4F6C9FDF8CC478774A14EC28B91B81B513F05100724F37194509E5E03D20DABAD31603E180D50F04270F45A7EA2D6E015FD62DDE451C54ACB937105AE2A8B9BD0F191C890BC068361FFFA7A01A62C65699FC3B74D7291F8DDF478F3E238BA86221B9953A185B5569E619C08471416A627A2E8CBD9FC954CB5E30E8982EBB678F6D42E389E54A2630E312F1001880D68FB95ED2C1022C042C57ABB181FDEEF012BF3E3352648AFB554D53F403A38087694DAB94AF3F8A819BD195C10B5B9296E7A442BED1DC0BD786DC9D72D1B24117B1CE0346014FC0437B2C5C5CD0A94DAE0D5E3750F5DB73A1BFD9295F91370D154B363B81C282120E7A80884201D9060A5C34F01242015040456901514B225A684B06812201110ACAB68C62A1ADD90010A1A0B72406855080AD39088850B051B04DE1487A40B97D44D859E2EC25A39431E4268A2DAEB3FFB8668789F868EA1E9DC50B36604659BD6DC3C3841D2B08DAAAEC95F5BB2F12231B4658B0B2641B933787AF6FB0A84638085D5F1ED1A6F93BADBB5A276523110FCD640A1FED1392DC5EE06D1924E56F0A9D0C83FE90A30C92F3E5E4E88A73C1A74B51466C3FA37EBF5F5FABC24CED92D787FA0F9DF3E7532FFA571C76C05CB9E2D16C68107321785BCDA1DA5CCF2D89488FC23D4CA3A25870C485C452699A5190DC7F1ECAF4823805AEFDD22C0652F2FF722AB66A6A99A936AC3FFBC3EAF1DCF00074925897CD5356FC399834D594BFAE4688ED124CDE8C3D4A4751959930B98A84AFC14CDABEF389CF9DC311470EB645D1312922158BBA86C95F760307F87821508FD8C096109C41B1DE221FD42E76B3B8494EF6B2FC4B13FC62593BDAB5345CC64290E407AC079930BEC124908C830E1ED1A9827EF791BF4B11D0B97ACC74F5B9A4BCFB60FF749909C88AC241E7A74138593B1A0DA0269283AE920FF57249BEE05F09E46B7FC7197D21663331E14FAA41842D45CBFDD7F5889D209DEDED4F63FDD1C32D2E614CFE58FA4CB031E9231C46F873BCDA73891CABDDC1416681A43BE9D1F59B5E27ECFCE98BE4143483877187C4B78296C79207B3D38E8CE172573628E21777E83F71EA3FFEAC99945F6674557028C1B8019963507EB6A79F033A40CF4BF96BE8FA7B3C43610EAAA1C2AA41E6B992FF5C23724C76A82BE806F02AAC6B4576A808B59947E64517C44F4CD3C89C9C14E57AFDD24D6CEE882341E5B66950CD83F9E80AC77C02D3FF59536B9019217C911ED30D10448DFB2D14A93D29E5DF21CD85E57A50697DEB43E42E4FB7EC446B5D2C11CE6775C4F8241FA7E564656B320E5DD6D2D82711C06CA437678445D2DAB6CDC4D3684555341847654EC9EC46ACA7AA08212742230B796CD47D88DBED12C9620581926D937B24BC8DFB26F23387B45F3A2399082010AF7654F811E30FD8BCF6FEB505DA1E4B75C2292B536538101406111E0E010C0BE1790C924BFFE472B4CE21A6FE7C0F0A582BAD7D3F607BD01D28E0CFE64C03018F66A2F8077A7D1016DEA53CE8823989F6083E9786B334359310261D05D74DC228FFC3ACAA8834B52FA030A23B27D65316BFBC98C0A164EFF1935388918FD4EC90EF46F163B105AD2D5B8C5B15DA44C82D5F9DE64DC6C0B0A994F974F7B5E6B43E462D809F2757F89D3299E3D44D9F3AED51FD1C69B0E8C2355DF316BE8E93A5C9DACDA2BE3A40B49EF6DE7A44483393AC3F814020103FE031D64B2EB6E728483366231BB54A73AD4D0D1385CC3A338B9E6C951BBADAEBEF83537C49D70CA93FF3375D5CDD52B476B59BF68A9AD19CA4148C8FA5DC3B375E713FDB87EDEF97AA807B263DAE9A17CFD0A174E13606CE812E6BF72ECAA40011BA48C76492B58C2675FA6BE34E9CE66A4478421C393A4289DCF6FFEFA619FC6AD047554C7E9901974B570838FB7D4FCA6AF752765C3939D19BD2F6272BB6C2FEFF0DF0E10CDDAD82055924D350E8B4F882F1EC4D1F1FC4221E739214AF43BF6646AF21040ABE4F2A126A69DBE02D8A19E2DC36D33FBB3C4974F7A2920A9575B96E3FB08F2C6AFDCF3D740B28B9F70A26990EC9773BFF55D2AFEDD65176E0C9D52719C325FE791B0548D8C6F72C1C39DFA2D42F48F21EAF309A843426325EE79D4D6D849FEE5D26725AD939237473717000F405ECE33D407F0C4466D156D56EC998B275C1F2631EEF57B46DFCBC5B19DC4C3792221D7278D0C9E587BC80040DEAAF4827FC629083029F0E5F7CDBE6B7CCBEEC49344022A8A224E9D82C722CCDC96C0957D4064A875A3509DBCD01AAE7C4F4DF41523CC56D7013A51F31FFC06E6332AA26A5DF023D89DF4C993AB899EB913CD2CAA268F9D824BD2DFF3FD19ED57E2C9D5B309BC17EF68C773A781AD88D23A4D3A03075C70EE14059FEC9B9FDFB93312091BC5AB89BCA8EB3A872686AEF11EBC75DCF0BC90023022822441EC84E8FEF20C61452938065B740EBC15A5624E1D4BFD1FE35F65BDCD37BE17E63AA1781A436ACEED0D7D2DB5C3C896F4155D2FB114D39C0A9F295773925FDDB59179AC145377C0B431BE0622AAFDF32B856F0145F746317B2BA83AA6E90AAC9D10F3DDBD99EEC168AAE5655E0ED979B87F640397514EE2ED3EB41A21F5948994BF15D6557FE5EB79FE4EF983134F51CC5D75140C1689C9C44F027C17F209039652721FEB3ADCB593785E73254954C94A8AD919F5F425B8176E2E35BFF04B7FEB908F30B226E86A4E92B6D6BD6FD1A37DDA090FAE8BF403829FC5FF4E167BD56C39425B9B7CFC51F929B0561A1987D2AE0B399EB53D0E7A93AA5C2AFC995F2D402C4BDD2BA9F275262A13F48B95032CFD610B3CEE2E92018DCDE165EC0791E7539D9E82F44C22BE5C8F61508DCACC4098A24B1B3F60282BF66D2D7C90ADC1EB9C8598329978C171D529E7EE97E5D50C873BB6DB42744FD4913C271414A7F192F9009B468E3FDD7CB4BBBADAF98F23DAB91FA41D171783C26C6F550FCF6977B2292660F83423F05D592DB223379C727947BC0D5ECB604CB5550CD4A4D0A75DCBBC31C62970C589CCE7C99846FADFFE24E2282EB49CA4A18F0D51F8125DD208C65A7134A0852EF22E83221260EA0746A58D16CCDBB9284D3778A2AEEBD111355BF21A4214917431AF52F8EFCC56BEA355CCE0BCBA073FDDB58F978BB85117946DC02F7C9CCEA674C68795AD2C2A7A63F448927406048705F3A3A2F5FE5DE4C291347C2FED4A89A7DC668C4DCD0CD10C6C8E3B7E48D3B2F0EFB6E158D8FDFF6071F53C84C7F67A5B3E1F1B6A00DE1BD5F73B0745458E74D01567FD238A7CB8F428A8A9E63D8D0D7F4E06C9575915AAA8569D12F47EAD19C55711E5C3BF01D07B79D4C2EB41133DED0B4890FE53EC3C36D582C47365378E793184F0078A905C248CCA29284C9E60927282104849225BA45FADE8AB4986AF7C32271248C078905AA8ED13823EC9CF1124813EA7A1BF93FCE5F7DB15619874D7F9C89E0F0A4842602C2A88D388CFCD6BE354BCC0933D4C43936E9A72C89D7A9E844EBD19E6C843A62D0A70A262C3BBE6211FCF8865A8431CFBF37F5FCCF80E5E143765CB6B4008382621CC0B4A17F085320B6C552D8350A790920CE7E45B6E00F4648197C204BA7201FF483A0394CE7E59FD94C0474CDE427D3DEF8102CB7FBD08FD3B6F1FB908402DC220AA29DDE50338001C941827B466CD9EC47D7433FCABDE39D44815E6F3366F3DA6A01FF71161D5624D3A722288AC6E590B764963215AB5E5875BABBEDFB9C9C8F6E79F2DFA682CB699A1F5002159F3BC1671D63CF16BF58C880E2CD0A84C8041748464B22F54948F24510796C1F28E4D923B2A21962E05EDA8B362016235980A3BF20BDCD7277BB3829F79180B5F92AF5B0F5AD29BF7CCC1BD5F847333F50A3F50888280C9A6153D2265D0CB4B767C621D82C5D14258A86633D592745D1B544DCFF73114640737B964BC3B6593D2E2C7F7DED404F953AF64CF9B022A5C04453EF1AE6A5A4DFDBAD47A2E4733370DCA2A749DE8B22568F5E5BB2217CB9C067A6768E6B74271495AE07C24E25F8C3A6C32EE5641DB27F3CBFC57E57BA5DB2D73A1BB06A597C938A2CDDA31A6A14DC03F5C2F49A2672384BC502163BBA975504DC3F213B6FAE2CF3A3AFE898E902A5E1CDD45341B1F01B288B0D6D366D743048AD34F40B34BF16C8314401DE1768132AE363805A7835F4E1E9D6D3CB4695E20924CDB8D6BF8D03439BFF61667FD9E493A4771CA55A9AEC35F97DE3E0DE38B2FC4DCD46A3F755E33FE2E40730788A71EDCC2FF04B3F82BCD0364637E6E6E71F8333B676A7CA6C61C37AEACA6CD46F483FAA9300C16E45341AA2C060444817A68713CC7CBCD2214FD381664BA5E535CC7CDE4C08F0FD984AB02938EAFBB3A130B0C5001830337AE98D54FF118A1FB84FB73B27B26B79F2C95BB7F5464497CC909CB01CF11B20D01EB5338F80C675D4AB87E77C3A52832741FC35C2EA651080E69087275ED44136C7715EC27842F8C7671572D6A062AFC6BF42E01A8A802F459ADF159721BACF59E726C200A2FCD59006D64FEAE32826EB1F13DCDDC3D17E3F940D7BBA67101FECC2DF3E9C366EFD539371F5A83BF834BD266D7DA2E96B4AFF33110B5637F65EAA3B9AF403DA3D06405B4E45C5E90BA133136A792C3BF0E2880A77D4B2A878F81AAD9B527388D9124E18F2D6D47BC9C7F9187E8ECE38F89E254E715AD69187828FE511667A9EA4CDA8D5E79C1687B4C9F6C99E27A40B12ED4C9365D052F5C2642B35633E71BDDEF2C09D015845DFA3268E6B1E8D12E47D5A807FC518B8172D0D18DC138F934AF397A412C5DD5D1C3D59C01C5488AF60321584A3437DDDF0EE3D0207E5A7F77F6A93A85CA0411F83EC5B40032F48B0418540170EE8D94D2D02372FD7AFCC82FEAA1986E9CAE86B106C2FEFBFFB61D26E783F05911326ED3ECB5204756C21F9487385A4B9D6E27E6394C586369B0E36BAD826C7EC3B2D623A1FCCCF4A17E046FFDE1999B56F22937A202DD9DE1BEDF6D404612B48372C70A6248DFF5E82708E433D94882CE50A5EAC8B930ECA606834BA18030B6E314E9F78E0539E40ACBC71623DD546738B0AB9835613ACE527373AC146BFEB18D354654069E7AF91E934F06459E5D7A3162DBB5D94DDDF44E8F20C0ED47AFEEF599F5B0CD9EBCF797087AB525DC8491B1630AF5960EBA0429D08676AD2E2B21296F766FC97F3037A0D28B21BEF30C5DA584FA2F724026964BBBF01157947D3A9C1FF8D161E1A724FA21B4F8458A087CD4DB6BE92CF6200C1AB13225696B9C466CE5E32424B467AD39EB83A60A40168597999A6BC5C0C8B069C691BEB154AAF2B55D8F94BE06023300FAC55BFB755F3D5068C0D7D01A34741D152A3E152FCC2A370B35DB26C911E4C0DFC6E3F4705737429BDE00A546B28FB867756807D9A47846DF35BB235414516C17AD82F34116C78EE75E72CD7432787648BB867923024519312D28DB35F5277CFAA698D44252C1DF8E3FBD114158E652D5EF01357A34E5CAC0BFF1CDF1D0772E54F89C72E5CBDE059B8D66FDAC25338C56E9640F0D09F0D9EB4CDBB1CDC8DDBAFA98B295B508833E571FE9550221A0F83D1665DC4EC0810F0EA1082F124F607D18258D3EA04F4D476C4FAD809DE8B7295E0FC25046D7744365E9C07847AB2B67D9F5445C3D3C96D0ABB2C5BCE91CF51E31B0D5FA777EE7EA279A21302242801EBB09C976F316574EA4D127F5771E72300610C2F1102C33641EB708E808D8F0789016CB3740C43B125D4FEFFD6D3DD73464CADF62C72296A65811F39DB85FD21468F03D0E0D9CB59B918EAF3656671E71B2741E6B4D15316A3B5CE0B04A9F01362B3958EDA79715BD8CC99DBE65C5FFEE4B5DBEC46596AC4DB0A4740F0EDB757BC9FC22F1A2322404992C82812A4CC10F15BBCFFC4B3A2036977FE33BA936FB3FB0A4BC5E5B8558C9C1798372E279549296419758421DC0E4BEF14DF6F21A3AB0971BF7E05575E7ACC4100AC9256C12844DAC646F15F29182527D25123F0A17E35E33712021A79D8B3BFE0705E1CE195BF2948CE21F135F7DBC5E34F18BF859256A9474F3B8B1E7DB3FDFE75720A20330AB31FECF148A7236D1DE61F7BFCC2326F59DE40CBE2A2E0BDD2A6FBE03516CFCECB51ECC66E89E66B54A8D230ABC8259D32CBE0D44F355792B3BC96BF6CE352BAB0007DFDD80F0DF916818EBD8F022D1AE31C9D9F420C3D7F22228C5FF94BB975D8C5705E90B1922E7A3443731F59F4D80538F9AC31E0C3B2D35C514F3D97BEC57C1A258C048CA1D2FAAC7ECED3BF8D8A013608BCEA6C5448BD3B96E9CCAE501AC073D13E81F3D2D4DC6E9FC923B2D0967550E0E93399E01D9FA3313C125BC24EDF54D6F6D08D0BA080B247B5FB0274EFAF2F317DBEF3056A525FB4793F79B7015B540E8566B5BF82DB7971A1ABB9B6032A45FDCD7E3ECF73A58EE71359B6D9ED7850BFF9FFDBA661D4A204FCBE97D8E96F36A6D45DB6687F85A9D9AE750C1F5DAD87D241E62A117ACC8C5F715E207FFA7BCA48BD217123913E3BCE653F44E50BDE8B0ADEE108787A989136511300726B78D41AD8DD9DBB252DEB18B50606DB9EB5D04D08B96DCC3B43F95DF535D5E2BC3C0B548ED0BD0EFCE878D8EB678B797BB4F883A64E2744B42CE8BB227F28B5300F840D7EDBFA8E55605407D5C8FEFE99F3B94C84D59964D9D57627728E375BCA6B12E725452CB954081A8D7949950874E56D1910FA181E699AA388D630FDD7EC2BAD5603E445775DA3D0F2CE46BD35A6C738FEB77E9DE3FCEDFACF1B22D3CC8E7529AE7027E7C5C054DE43C1852AC7DAFA773CAF7A0D9AE16FBD060CD4CFA82B9F9393C008EC9200E5CF75E46F1696C6E76F8C76889CD84746ACFE0D3F89DEDA0E6029C44007973B382F9D5FCAFDD75093F3BEF4CE3BA6A3158694D70692509BEE9C59EA53960A07CBA002C65870BE56DB6C218F1AE2A1DFA323129F6CFEA6A2FCFE70D2E06ED270ACE070C07941613F9A846570E923232590C787D997579A0FA1DAD6AC1A7E4F1F777BEC0BB501308B257F5CDC45D0FF5D48E1D73C8C384D1BE529A9E567304C79DE94431CEB4895F3D2927D09B7ABA429849EFE3361E34E0D21C919334E6123E8710F7BA87A3CD53A1E90AEB1B5E85CD8B109781FF2409238494D5203CF362D7D5D90DC405D80C1ED97C479E9E359B82E33DCC3E1DDF540FFA1308709A82097CFDC61459584F67694F8AD02C0A76F0DD3CA4B169BB41FB51A27C8F7C1F39A8D7EA855AC51C4F65DE2FC0AC18C725EB29D256B44D8D8C9B5344D1684393EA980BFDE8ADA1BE281A42870BEB73C347003BAFC640E4D535A7B43CB698F2174CCCC7B173BBDC7EF8D12F301E5391A4E8837725E841CC871B6E0AA94E4E39DC133FA158B704F9364C618140BE29BDFDBF668224401C4EC5F655D17CB30DCBC70E8C9698A0D9FFACB87398D71F4F3619C11481B8C3FC5F377C6F19DB7465E4185E828F617AD8EF0920C3E170DBA2804FF8FD7667897EB822F68057C57BF5004BF785E64C52964F511FDDEA77DAF3A20C06CE9BCB34E95ACAAE856E942FA0D9A55EFFDA1112FACD3FB3FE058BCBC99FF543E408FC1C353FFEB404715FD32D4CB0FBBFABD1A6D87B0AC3FF4016C0E82CF83DBD6368FEF8F90F5648837DB0DBED78679836B46696CD513B3579B7FB231463F80CDA340A4A9A67CE78954B922E9CF338235FDDCB3C5262FFFEF56A18A1989092084B6C863F91CDB802D708595E3AE31505865672FAF0EBA829CA62BA2E5D4A58B6CB0D91B1417A4293A13BA9A03FE9BF9F02A9DF360AE5A40B1AEEA7099D32C5D3B5169325AB6BC8CF323B61032E195F44448C4C0050865F8B6DB76F2A5E1C084FF37CBEBFBA27240858E345CC268388F2017637CF839D8122106F04A28E414B9D95ADC2473797A5F423F4F30EE8CB1BA82C73BEA3D5FB9FFA0A705F09534BFFCF1A24E8CBEC5F47213388CE5128DB6A69771559396811BC6B3ABD9E48E905668AFF67910F6EDFFCEC6BF9BB56DDD79385884722C62B749BE237FFF8D84AE4E97C5C8AA0D48731F989C8DB1E841274DDEC83145903E8C78F3606F1A4506BEE2E91F0D6D6EAF843F900860CDC267E2773FD5DC4F3FFFDCABE8F72545FCD49EB32800B894C962EAD7A7CDCD8688563CED361847A0D903BAB621DFA88306C9BB158107C85E37CE8360CD948AD327ACABC525F11BAFF774228E352FB1304E957FC892257F306D5A7200938EC0B9F88223BFE42735134271F695BEFD43C6151FF667C9BE68E1CB8D3BAD8DDB2116C83A5256FC9DA919ADEB7F16E069BDA28D72547E4F7A54EA5D1C87C86D69956908B8110755FEBA19F004B048DE46B4E73F41FE97D9F5B3E9A8F38695078DDE1D5591337FFA19BA3443ADFD91254B99EEE859ED62FC6AFBA65DF8040C1952687C0BEFB40961FB6F5FB9F15911051A61A616761C427268D6EBCB480B4EC08100164745540A9F4F69328372B1A8BD3C771D26DF941BF04C9100DD031B0E3FB975C6B68785A8A03F25EA1015AA07CF9A1ED89FACFF760B61067808C33C8EEDE4B9390332EEF1523DE66519A3AFD4D28E4E8C50A028E108166620FB501208D0F90A14C5993E95069EDE70BBE3CF276A71F8E50318E548D5AD2A1BDA6C7CD7F9E877377F5BE93C467DDEE5FA5015681D520E60FCE386C12B395A8DE1A80E8F1214C776AB6C24F36F6C0FAB65E1C5F5B004322D413AB6CD1E537BB98F9451A31708A2C7D5653B09A7EAAB46741FC78B0C80012322AA7402D28D409FC3E68DE96ABF21977B197F95403CD62325DB84B1FA2E3040818C538B6D24C82E5C9A9CFEF5762C2756B45585840BF526035EE96FEB40B0731762444B9DF120B1C06C15A393A1BB82934932DA79B3C5FA21DE80EB4B6E1B4EF896593D060A613E0B40836D48BA9173877EF9FB1AD2344E2CD8E8286F4F5B5F8823091C4BBC0613876DDC7A84842FC4E123DB74DA7516E23600C13DD557BB03E16A7FDA059FC250A6F7760D80631669B72AC8B6FC98E4636D485F87A2CEF6515AD74F8CF75FD2D485F6920A219153CD9F8FF251CE8F8570E67FC27743C036F19C367AC4C77006A8F8E0FBB68009D1D6F14B69EDD0A27FC8F7AA204E077927302DDA2D767BDC03B29FC064EFD6C9FC6F7B92763BDFC459A3ADC731E99CDAF448181BDA2CDF8170E0CFB3D36BABF569B77FEE3F52686B6505F95C4D9E0A2A8458BB6DDCC414C1A00A7086FB5A764ED83C37DE531B8F1407F2C2EC706AD6D569D8940F6B17C51162CB5F160773405FC02C48D3E6491B0CF8F959CD3714FA093E9FFF65F2719AA83EAD546E80BD6AC23B47E87C8A0E418B0929771488C31FD920E31AB100DC85CDA402FF661D2BF12F06C8716186AE13E97A8CDF6B69FC91A083B84BB43C8B287C650CB837455BFF2D5CA663F2EAB590075AA5A645F1E617F5DE66FCE2FFCD212A4AFC9A80391F0E133B369FB84297C4F9B661CEB7A8616B0CB333FD740B5488A2196343C9926CB9CE79D91B706D46D79C4330CE123F448D1E1D923718B7F0B4A7BA93A9BEB8E6C9865702CCA8BEBC7A95A3AE40E4CBC583831556D80EACEDCF54B2F0FFAAE1284E473B78435F2384AA888178C3CA79506E732ACA2D18A64B25885678C9B0508F3AAF34ED331B10D0EB44BB767615161E844EA1C2705D4325AAE82C887855DE8C8C4ACEEAA958CFFDDCA19067E77655B26DC028F6FCDA54392E85B22062F6BC54AF21A51F7933C103FC75EDA7D9F2B6B9C6244726F368557B5C25C921B2DA779BA5424708BECFEC210B1F58098021F57BCF0AC7366DFC44ADEB413B2F61B0D0B258EE659A8D844DA2E11A85892FFC9098FDEF91DB74F0FD04436145C30063F5AC2F42E10E532A419DC861124B4605E8D80E95AE027EE1ABB5F0C87D044634D3B7B72A367B5C810958FE39974A5BBBDBB488FE89C6268E3DE16880497425E09F2BA07D97193040ABB7CCD5DAB5CB372CA2FD314F4E2854A96326A3841CA28C519580784745D67299B512CB853456A5CC08431346FD52023733F4F71B983113935A58911C42392F19B5119CA33DDE53C1AB28D52F53F74A8DC49CDF976F355253948F62AC3CD23B00F98617A10D767155369D9CAC585EA952556769FAB0456149A9182C251044FA1AFACECECFE01FE15A5F6F860AC38C3A42A26DEF4DD7DA8F7F88160FBF21C759BDDD01244F652D3FAD8E3A2D5D9760BF71239365BFFED8DAFA7E90B91A10A34D2234A202C1011F9D875FEA2A4944966BED36A256272AE1C809D41759BC20A42ED7626AC4CF17FFAE7A002DF3A2E2763C88E31551BDC4E89AA2A99F890ED3B6C05553A885FD59658DC5F8218F07890198C4C6A0FD974F029F9D25ED48509666DB1128684E58490688D7433C0FE49E2E01243B9FF79DDC3A11DB349DF7D08A778F82A8199BB4EADC3CB9E1F95B3196B1EA8DD337FBD7779E1BD761D21E4CF577C464859E0ED4B3D1FFA3B0EBFF4E75F8EB4F673680EBE64649EB451F8B47F193FC2327AA668CBD0B6C2A09745D6A68DF908114B68A07044121CF7E6DAD1F1F6D4BF6B7E546620E072FB2B288353593F1094C40C8F757283B0E23862E9407E023010CACDD09E6E2B4C3A97761C17E7EE591DF93BC9C7D7A95E6B1038D1F9C63C977D203221645418F2332DF2CEF65F2002C2FC917AE958F061809A1484459650D049FFBDE202D8466DF60DA79201DFD6E16DF93F55F4AD4F8600365F87A57FEFB74BDACE729BFA9BDCDEEF79B0880D0C50E91CDD8B153CBD83EC976115D8696242A4CD3AC81B7E1900BC35768E296F120B180F029BD8FC2B481A31EA118192DB5C6C2A10886C45F8AB457092DA96119749C52003F910FC59438351EFDD8009FF6F864DC93E61C3BEB4B0496C757E5E55DDC6C2BE8BBB0C34396630414CD6D79B53726A5468668A4D9F84E60CC35D92DF1381820FC805FB8C16386E2952E54FCD0B34865CA617D3AB8D8DE94709607677CDDC68AAF1EF7DFDFBD0862369E6DA3F3306B50D3AC87B07BF1F098F1D07557FCB2D6C05D5A162F72148C577A222EEBFC0EB0699753B5E3A97735E79769BAA85232A799D2463A33213E19BEA8FF33FD2E1FCC788018C048CEBDE65983DDE9DA8DFF04AB89C959C5233ADE3CBAED94336BED5CB0AF4008E0B73AF0F5E19EF0379B37BF1C82027F204A6DEBD923D78D27506DDF491B67BE8D8F078905E01F65D1FE66BEFD8C9431D03CD065FCCF9D7EA938C91E57FA9379C01B5539341B10CBFC6598B220826ECECC7E4A7D82BF73D4C697DBBBE15EBF1D98F7E95AE7BE04FA018B02CD3A1C729F223FB1E2C512B345FE5EC4A086BC06D85AA0883D44405322001E6CBE996A6C5915C274AA477AC184BADD83C0C29022C30121B8D96F619FC53890EF687B11E38209DEEA7CC184FF383346880FCB6E350FDEFD4BEED85825DB67765C360881F22BAA0C4E2EC879519997240E5E4F80E50F689D2B10B82778E25075CA3F88F6D9CAA212BC4CA1C005B8E87F56D8CF05D005CF8D61D331F3FEA9ABA7A9E94DE1DF929C874B747953C792F3F27D1E3E3DFC6BEAE0F0B4FD62F0C7FFAECEBEECA5D39E0E46B0A2975E66D0E92F404349A3B1F4504F3E43BA6CC8ACE7969654178CFA8DBEDD6A90C43E0AE2B2CDB6382FB49616E9D403D0715B09C7EA3E7BBE1C8F2F4AAE434ABEF70E146A060E9BF393806EC22F3BACE87A938A0498221EB64C7A73171D014952A2A7EC2F90E033035A729C0704249AB9922558AABFD263B4BF53FFA49C5093DBC2739F0956104530431A7D9A016A81FBBFEF36F71295F0AD67B2356F79A1D74DB2B578E2D939ACB6B5DF7E1450300E2616D05B8AF3300F48EFAC973596B71DEC6F4450D2E0CFFA1B67FAA7437CE47E75471308F2C0FACF193735BA0DDD437F810F754D03BFAA8B942986D2ADA2297816FDBA349C978410F0D0615ED55A7547D923511727662BEA53F0078B5580CA0A2B05AF56792780D2C7514E236A90C3A4AC2A3681D74D36672BB9EF2C42D9AB44A28CB3479E7A27E7656CEDE702C2071573899EB3819B0FB34BA5FC92A4B7905531828DABA594EA2C00E8063F68C6220E4BEDB66571AFC009FAAD2D7AEABCFDA25ACDECEAB05C1AF89189F3B2E5774E7440F2736CD0D97932831E43D42C12749D24FBC9B5AED211DB873E7B1CE09C0A0D99912F5EEA474040DE3C7FF512370EADE9FE9D68358279FC0F9B7B441DEB95BBBB2D8E58FF763ECED2C7DE6E32DFA53594079D8582CE42AF48F34AE58BEB015556DCECB3FF81E4F3EAC14AB3F23B375AB46F5DC8AA7C3A1AA5BF4446FD896289BC4F31076C683B36FC8F8FD7E109DCAAEF63E6C0E4E684A3B4F98099A84D4D7952B65EA9F21CCA138314A22BE74436F8852E41726D29979EA0A0709901AF02B74FA2573D066FEDE662E964EB2A3B0C800192D90BF1776C67589DC529FCB24658C11B20C7DFE46DB557A38FDE1093423B0AA079715508A5E9FE7184C3FB705B4AD768ECA11E33CA00B92634CD5507E5C4B4BE0A837362F854E95EB43E33636E664D78FD9FFEA9F350E90AFA8DD185764F41DA2293CC754CA355A742159038DAFAC42D055E76463155F063DC7760584540C9689D5A59FB8DE62727A8938D38F9D24C17E475C48636B75E3E9094300E9E9BAD356A232A1305FCB5588293CC0D8E0D45F32E5C420C8081FCB802A19B5EEBB05395F86FD342A77C626B067CCAA83692FF6739074B248F0600C3C1C59D15FF1E7C6ADA3786EB9D47C27293EFAB7B336471262CCAA53EE9357B44CC92664AF4D2E13DBFC52E70896F44A279A4B377DD4F688B24CB5381E59E792C8E2B6949D503905AE0F45325B87F555B6621AABA5790422B253EB1C14A59CF6EBD14AB90AA0F26A9DD7E3300165F582D4E7DB252F2827773879E349AFB5000760A33E798781A7285F1E9A0D357FF19162C529BC4CEDB969EEF158BF09F97E1A90FD682BE80D522318DEFE3F5DA38393CCBA155CE80FBCDB31A6DF63E66FF68BC37D6F65D966B3A821E193582EEBE129E529FCADD59A6782F5D2A86E15751FC36F81910F825D2C69210FE899EFDD76DF4C5B965056CA22E81FD130AFD8473964181780DCF4D40B8782D307EFAB738C072DCE33EB722C29798835FF8AFCACADC970AC0E38FEF7419919F030ED2935DFDE1604FAB38FA1E4987A7E8827F79706E05DB761706516DB3EAED7FA64E7EDC19603D72FCBE95341CA0711E456369965D6DAEEBF1D1989272DF55D2B7093B36A273F76861E8488FB2075498A78F82FA3CDA3090EEE1956B8E8ECE5869E07C2EC13FE63ECAF5DF8FAE164120100804027914DFE873A552A6614E6E9017E2A9BE60FDFA392E7F32FFB73D09A6CC8C0285A628D94E1F5084A3ACECF4EBB182189B325147A5BD5D2D21DB5DF06991E0A737040E1316AD93B3B8682E1281DFF6425CD0CDDAFA337225738305F34B70583C3B8B9E6491F0C5D45F787C0C90EAF1C1D17FF7296372721C8547AC4AE0B39FF01AAF8A296B4E38A2125AE6868D1F6CE27F079870D7C629E3E5D31C1A2DD2E838327B94425F3EE2E3AD57D3C53EC88AE37922C0A38F9F5E26B0CF44EA49597AE2059ABBCE957F8E0D8D21F806F11A500DFC623A6B70B464F2E1B57FA2D90CD0D9FA0A1CE967C3FD5FC8D2B8D5BDEE1EF7111DAB9B3CDE6D6B564EC1A2CAE97A139EC8F36102B87914B0C7E563703747CC1169D7EC1555218295B614199E6D4AE473A8C432C2E4B82F7289147BDAF977D054A826CB850B739583E7FAB78111051573F007CADFAD31D5F068590F90F7B6E947DBB91FAA21D5A6B68724C5C5044E53DB3B334E19E1528740F1A29142B5451A814F78461BC57A22903832F7ACD19784D7C1978B64EA3CA7329F71B2E9FA92370BEE9704853CC75F1079ED2577964CFB7A5B601DC5FE8A26FC5056D1A59C5131901289FF259E34A3195E14631FE9C037FFC7B9AF1A420320B21D455CFF6ED84E303C9826544363201C782B627DE4C04216233D0F15DFC2E76DF035323C4C8D5EF262988C5339685C5B05445C7BCA9017B4FD7BE08334B81D323F9127AE14C8CA25DF605410FF593FECA70081FCFA602FE80BD82D12713840862C81C26D9698026382F9698AAA55AEE987EDEE613E6DBAA2CF8C34DDD2F0265876A17E82ED395FF14B82823D249BA65B9F2F141CDB37D97F5243DF119D6F1608BBE6F565D3ACFA335760ED56283D606CE576BFAC7DD9243BD4883F276093509D043180DE8C3978C3DBF46A2352E797E1A7CD1F4EB944AA5DC603A0871245BDFA2DC174C0B45D9BF7730140753C5736D27C6D211DF5D74C4CFB4C954C44FD047702933D29176F0FCDE64E95E282D488374E039313717255F77796F6C3D7ED4BFE1C3C4C2A7F317A66211C2CB584B3432CA0D352778D79A6997EB370977A79D98B6E297738CC7DD41492EBC0C5889E96D50F28842C5AC96584C7F01DCA746E7EDBC19E2A61E837BFB5ED00FDF7CE7EEBAD2C43BA82909EF33F78E5D6E88FFB54FB6C913E3F20D560DEB28899ACFE671614FB98ECDAAFDD401DB3F4937002782A6EF0D5DCE45ABA88893B24B146F6728412B0686E2B42CE8C34EA759FC49391EF9578E1E3825E4F7A4B8DA9BF0F59E39263C4F96D17CF50EFBC8854F43F1434B10FC8F57DD97F000C94EE311A9EEF067BEA67D2E24BDE1A97A9642C2EDCB063648956C9C2F9C197CB0264EBF007E34F768F63C06A2A7EF8D6614F6C4827B5552192ADAD428A57951791AABAB59F111173B9C458CC6B890B5655510ABF9472D21986BFDAF86CC2E75990392112ADF599AC27C7FFD30D67FAFFE6D154D16E26C829969867A275659F861341DFF44D052541157031E3F0B8D9725CF2580811F4B7E783AE19A4C82BC81B4607364711DF1D4ACE13CA088AD637E03656658B7C30AC66007DC10E1D863E218CC14FD4D5BA14CFEDD3C689BC0BC2466EA5CD8320FEFEFFDA0900E4D856AD537877EDF326B3BF355E61140CC8FE50F137453E054D58A28C405E0B99F3765A7688050CCA83AFC93675382A7EB71F41D5FE97B6CC7D835938FE743715FC45794DEB9723201AB09DC0F0F5A92C68C6196E3AFEAD06EA6A9DF5F11BC42EA069995E4339FCC785A610157AEB8CC287F4F829B9F77FD63AEB744D33BDFC34AEEC3DE9AD70C7D7D7FC03D16E863005458EC5BB8A92FDB5D0F72F35C345A9CA3A4159B4497EF4BE5ABCF732E33B9B09722940AC2E5A9FD3B10134217F28CC54825CED9CE142D7C3ED9668D4BEAFC25A5C7DBB58FB6CA6A3E88A8B7887E6CE919C6A0FCBDE55D6B181ACFDE7B9C06809B78A9351BB71DADE715FAEDA98CBF01870732E2AB4A8F58576AAAC421FE4C729E220304F95E9903AF03651BFC2E6090EC8F92C3BDA2B08080AC76721B504D20155824CCF7609D46A0F96CCEE10A2C8106DD551B3D479034E0F91DA60602DCDCA5AFAF1CF29FAB7FFD2AE7147A9FD45CF5F535821B8B7ED040D49320BE4ACBF8DB22862FE053F761797DB5A25CAD4B626F132643C4B84645E7C9600CB8E6B07F0AC7E94A694ADA7EDC699E2148F2C6A3652F081771FC5BD24D10927970F4934912D23EEC316D825C1077F6497BB44D05A3975A47C17216F8264C652CDC40081DE18E3BFBA1E3704DD33638DF4F28523C3FA20C46A2098CFC3B060780808010A870803CB338CF1A0C542629DC00FFD7BC34B7D4A4911F091CA77D743EC589FC83DE093B825CB807F87AF4775E8AC3A5A457B04177F539DCD16C7610CBD609A58D93CE7BECDCECEC05856FA3BA8F56B480FC9090EF912CB188BA9B126FA5917635F3789DB51FC53C56850077A85474FD043C33DAB0159CFF8B2619A5E5F711B7C4931AC10412944567B73DB49BE252AD6FE586522690A5C2CF083CF40498EB356493EA1D898DCAAF680DF46ACBCFED1CBB094AF19040281F8016F47F3616965A836ACF1193653C6D711418277F5B305CE9F91EE5A8D7B1D71674A955213B48B7FEFE2460C1FC0CBE1F77045B14F9BB116263F676E8CA3B1FD13A3C254C77EC996D2F9626584AFA93C2C696DF1F8E941397B6B06E807A951FE412CC8F4646B50730BED2ACCC52F87CA4CF2532EE76E76B50DF64BF6DCAA0EE77634F8DA10F732FED13E2E90ADB9FDCF7AE4E3F9E6408099B66DF6110C0D56CB0F9C977946C09ABA3B9ACBB29C1A31C0D0DA187DB46EF0FB6E4F52A072022C66A078B973766C171901689ACF4D2C5232E2C2781B9552D38384378275895FA33F8E5358E89A0B25B535A38F946FC0EACEB90F37752B87FD845D2D602752EC4A5E84BA4E1326F01F370FD701A03DAA66AAD443C38E8C652DF201D5147C9409E0A88FC0BC63DC14DF360E9B9190D3F280C62808F67CEAF7F14216D2CF72A293ECC99DCA528F87B3A5A37BD2149F1D14C00BEF94299589C8723CF844B7886A79BBF5A53A8336A362EF71FEBBEACDCC20EF44513D58C6F882EB9E1DA09931F24C9C2E161AE3DFE8A1FC867D1D5C7DBD8E677C5C218DEDF0F61FB07ACEA8CA33CD1D2EFDF4A3A1000F5994657D4FE3F33F9DE8CDA4DCA23901A619E36737742A66773C08B35322C402F705E936FAEBFCBBEB4111E7D48A2265BFCB54C2F38985E75EB25B219E6885A58008BADC64555F96954E8712482837CADD79E79B1117E85FFE503CDA1A5A038F177960AE0780D9226185035DCCA275DC69B9A6914A95376A1E257FA5F4939378FCECEC11AEA4F753FDFD4A8CB911A3A1B36E857491294127E2DC4E84D0A3DF0C19E5731A0D6E7933024038745C897F5F94DEEB2FCEADE65754CE1F6C846100D4C38C159C41187F2BDF2ED3BE590C0A38EA9D1E52EDDF623041E1BDD4CFCB978A183430F72BA10A29C9D7D22C40A86440ACA2AEFA666D2664ABA55D1F42B9A6EBBDD47309C995C871185637383E5AB14B0EFF0D106F7E6D8955E885A830906ADD79307CB12E99A3147A74BB2BB9F75C40232D6E50F9B088AF50C80BE2C301CC47589F78EEC79B27A9386BF7666077A36FFCA6D41E81308A4BE29ABEC5EC23BC0B315E52D7766AC2296167A295FEFE49D24EA724F02B9B4FDF75C3BB313A446FE3B617F233E658D70D0C1581CE7F50AF0123BB5781C6CC830D4A65E484609A0EF4F0CC5571049C516F0BC259AC03181311728E403DD03E186B75AD3081358FA5EBEAE8E567E9AE67443F663EE94A5706112EBD6DD87BCA2A8F812BC7195281481767AC879757E404FBB8C1B0B1B8360BE81A6998F9BC6C11F0FD04CA098661A937D0320EC9EB1239996C1EC01F29ED1BC606056D958B1391BCEA2B68B71B3CC2DDB44A471EE4BA711D288C7DF653F9F587799E756181D3B4818EEA1EF46F5538BB0429A122CC57ACCD1BD6FC1B406FC1F246103A3C75F419962914EFFBE529DB199CBFC6987044FA9CAF230677D00879A07DF481B82C0D86A55119BD98C158C8BDA8A896502840DB20574600C5216846DD9ADEB162B3A3671D536241C25075F7CD81AF134813D95EB01DFC089997D8EAC28FB882C48636F37E201CA0FD91AF25D98D1E7BD1A5BA13BF593CF076E16831C0A8708B68B52DE87DEE9407B05D6C2BB8B813FCF0729441FC4C2FDB71EE2A3AE0DED78E20BF3C9E28884D76613F1FB425E80BDA5CC466D15FF36DCDD74478179A8DBED4833DC853C60FA86982AA56247872F84554BA845AF189D971B817D0396464AF55D098BAB09B683EB0A07064B276C12E6A482FB753004E42B5543C676ECF238C14A0707E62F084751832E54356FB85B515465207D944B2FD8E65F75AD5E407A30730ABAC6BDD0645E780F7E2C2AF0DB5FB68FEB0E093DED847519476E4995665632C027B99D4B473A31B60D7F02FBF494ABF272EF5F5C9DB9E5784A98BDDFC5601E18C83F4DFE64C2D4EBD17E05ECD5A2D1B1EBA622E3AFE6DFDC02FEAA07BFE226145CFF309BCE5AEA22C62C42E6557679555B32E446C1D2D0F728E1D2D12423DCB5DE7815A3C2BFEF45AC96286A6BB8568A9BF18598E06753C3705BF0F46D6C3260C8C04A038246C5E03E44051005AA7D89001BDE7108905568C216A24955C3DC0E063C8F07A94F679E512CBCA460E7B0AF3361FD72828E088A6B1AE77663EBCCD895E0144DBC7CBC151DBCFD21D238E41CEA3B246CF117CC12CB8C8CD9B82F039E66E578418B05D34B41E8732A03C890DCD830DAFE769056A633055A0E898F49D57FF8B05EBF520E77FD3559C7FA4EA00B236DE14AE4A5053EAE1BD45F4045DCBEC9C869EA185B36F910FD53BE329239BB1431804E0A7A4036E21F7952A629020E9331A7B63BCF984C994D1C103C7330BD53765A9E824E3103140A66EEC4BC0C83A7E591BEFFCE4F4195B5F29B63F79078A9CA6F98B8A6283CE51C85370CE85010CC2D2FF7060430AEF93018D42C01F7768910BE5E69E7DD1D53A65CFFC56822F1EF1FF6334BDCBEEF822567CD814331AB335F0716484DFEC3DF9A8760B6AB6CF70FA621FD8662965C0547C3F14C2813D6F397FEB1518B158DE35A4BBA22463F52C5B28A66105F1473D55281E1B2A0540E96DF5E39CF8F81E7A1B4C1B00CBE0C4B51ABF972CA548F1F5DD7F483DD0689D5CC7AA102804C2240003F01337BD758C978A08ED319C7714E396979D1FD5B3C85DD1B8786F8B9B88F27D00973B87DEFF9F46F1AD83E34DE3784BF583BE8CB74AFBD5FE151DC9E150D1952B3FE29158AEE072993CB730881DA139B414808F1651CDE8C7CCC1753F239530525BB1FBFC56AF7588C5446F2DF2A7B4D7F2A265767CE1CF04F43D93DEBE0FCA15187F43E38E1B40E083A308BAAC659D8DE463E4C423CFB5A072F7C886429E3BFB2CC9117BE90229A33B4B71292880562131773B064B143213A9DDB65FFB23BC62C7D14000E4D9036E000C7498C80D75731E132E1D363E2BDC16F4FE108D73DBC9A53544AEFF6A3886EC2D0B180970A0D32752771BE5FBD58B84FC1B5845DAF675FEB9E77F7D012EE83651347191438DF9D04D95956626156173729233982123569A78ADED5920CECFBC28EB612505070959F440B29EFE739360FAF73886A4C650F7AD8FB814F9C2CFF354147368B3CFB6A6F547A84380B661F71BA719CD98AED8B31D2506B35D49B1DF414A3E7C63E94FB18A340D95C79F1A06FBF6D6113CEE128991D4ABFB780DEB83B20AC96223BCAB9254BEFBECEA3E235C6093F8114CF59251F762571328ED97F757E42B9E968A91E5D71D60F4367FCDE7B2ACAC63E04C793DF3630931100E7C77A254CEEBCD7615D935ABB929A588CCA35B682014D8FC2BE37CC52E03FF7718502B0D5ED938491819BDD4F02338BE5E023C1F7165CA2F12EDC91373FFE52B7B1006B7C580D058A374697EDC8852DEB30CF50DD82130E0B227AE7AFCAAFC96F5166F2CC9F02EB08C26FF5A357CA83A50FCE82479BC4D68A21CEEFD6205891AE73607798616545A1000A901A87E8A1A74186F33D5392071C46DE0F2BDF644287F1F05D540BA325D4EFBD888DB469B91DF910DF70A810931100EFCAEF20FFE6C3A8805A8615897EB3BF02C625FD1DFF37BFEFC754C7D10655F3109288A5594B478122277955DE86AB3B06ED2BC316135F57BBE66AB911386AEACD413069BC79F607404997E6EFBAF7BD1DDF160F1BE98CBC9990C1F6C88FEF4E95C20122119CB96FE57311D69EAB23E07F9313C6F0F30A173CB49868170A0E03BC36F99CB4CDE774DFA9533E4412C8155658E2887D885B4E0B79560A19F3500E6DDE9D447443CFD6EE54F5851BA938EB5F9F301639F7D27DAC8B4FEDD46EFEDC88DE4BD641B1C483DD459CBCBECC82E7F55F605F8F8FCD09EBC045163C6884CE3EAD1DEC10B787EEF6B699E7DD617EAA38197BFCC5C46BCF307FDA18FD72C24B9AC272950B42A9DA839FF6C13A9083087690747A82659AAD7C2CF5606D5299E63EB226DB326266F252DC2BFAE522420356CF6524D6DF8F3EE819011EE4F76B714BF579A62F9B71EEDD28F5D449F6D1EBDCF5373AADEF2900C2A0A20BB9E66FDFFB3ADAC4A61369A02BF9E54611C2B415213532F3EB22D2B150A9326792FA3FB002D75E601B748696BA38E1A9ED772F4D643F4A2C2FEA023CB53DE0E760C6835BC51986D08D9D70A357E679E4AD92116B0BDA34D8B50EAF882F86084C5F879ED0E9CB0769228C49D45FA405678127F2002E81E73EF540D802C1BD3AE89767F5797C27B1E80C0F3BE9A451852C9CC40B222EA932976EB7CA7EE48A7C8FDF06AC0C335223C4A20E57B9E3CDB5D739AF4D2F31D7BC7330D12BF08A350CFA99F22260148CF94CC9170B61E6737525337F16B51EACC7867E664C2CA4CF46C9043BC8551C2FB574121CF656FA470677124D8DE919F1DE96881AC7470F464F02AC2F1E34111BE5ADE33198BFC4FCFF00EF5EF2F660C037C10106862120A1FDD20304BF3F0EAB7408114A181D26B646F9670C46CFFD6CE013080E0F9703D36F6E545414B76CF2AAF7C7902EF3A3E77D70BED5F2E51ABF382B603204FC13B01A3EFCB48EAB31931A05D922FB6DFA5CB338E9CE6ED719E9A037B630402F991EFCF90CB239E2CFAF43DFFCFEDC3C152C7EDC561AB0086BE7071AEC063B2CB85B89BB649CC4CB285713D9DB6909298E2A4F824338E5BE75ED4ECA154FC4A72F9053E173AFCFB7FB46786E824D6B7DE5B8CAEA4F389C7CD37FE09F904D74F20788550BBA56F5046746E5582793A08D88CC6D22345E8469A4611D3DEE7A762AA5778FF94BBB273B4DD71454EC4C2FE8694C2CCE6EA83B9A208799F3EFCC5BE2480DDCAC679902230075E43DE1839E2E349B8F2DFA79C46F187EBE12931BD0C70B6157A010F381CB1B1EA7FDDEC6CB05C7FA4757D5137F7CB0E5C6E2D9DD0CF969A1B6FFDD346002168E673F5E88432A35213EAD183EB2145C4775894D830AAD8C29EFE307D2CCBFA39378BAE2283B8271127F6FDED5D60DD4781B38A34E257728C549E8D1EED8DF1F7AF681AB250F8520A10FC87AF1D6492531AFE1F2CCFD65C1D371802C90A34AF70CDC064720E5AF9E1F81BA717D7465A9C28AF1AC19A8D6E5A033A7CF0F4D5540EC6D1B66B91DD7EB7BBF64B0CF60FA0A26E07140BE88911793518BD6CDF0196E6FC3E19F11E7E4CA61FFA3086E4B5AC605B9FDAA64DF98A3BAF0C11D5F939727ED4EF8A24968C0133C1DE3E9A5E575F786201D2DAC6AAF0950017661CD669E67B231948A79AFB09448080B18745E3E1D2508E65488E7F281C579F942A8FAC6D970E1FB546516291225FF0B5646410F071D027EE930D18BE0C466CF658FCF9FC9BD5688C91D20FB44E11129EBBC7DC71BD8C02B8947852E81A7D60FBFDB8ED609F928FE5ED0B8814895DAABC087455FCC5BAE38B5CA2F0A2C705E5BF625598A9844E7755221A3F4AFF3E54861778EE8DA6A2B010819FEDDA62201CE0539730385FA175157C5AE39941337399E7C1A22BFC9E7A975BF768284B325F06C825A9ECE59D7213536CC8D95DC67EEC27901C26B6BE72FA2A10577F1E4BC323453202882FF9B820CD8C8BC9DC3DF8DA779164AE4DB194D5CFB63F630D2D3B7AC97743EE63B15E4C08F46A3401F374F65B296ED0390E97F9CD6839BF85DADD557D8843F3574237201B6F284BD6B1C6702198569C04FD7C7D7EAF0005CED27E3F1EEF9BD697E22C10F18EBA358CA1FE76E34EBD6671CFB504092EF584B0593EE9A98ADE66CA40A0F8F110252E80FB3A5C5DB802D65A409EB236C324F8828641558F69E075EF7B5A6B5768D69060F90CF2A6F4A9BCB0170D7AFEABB6AE7E08D79AD7E2897CB3B567A40DDB9C1BC8B3C50018A88BA4555B93F5D93D292871CBB3A2F63963DEDD39C41626DCA4635B1C6B44FB0450F396987B7D896AC357084F4D41E7274E9251D0ED4C71BE3DFF62CB7691666126DC5F3F8A58A3546B269C946A411024B9D2BCCCE554C97A021F6471B4CADA0B5930A72C8F68519C89124A133D6116DEA9E282FAC6E23727406372E1172225E6A748E0C6F27904DB7822A8E0DDBD3A30115B053522FBD4A08C9703C685BE8031A3E00DA30F2F2F10EB4BE5EEA29AF0AC89553EBE68997095C2FE8A6BA0684E786715268FD6300C0804A67BA2C76819B6EA7746339BAE8CF362D7D4CD25B3D8D88C398A8D012C080C82A1C7C829F1CD7BEB1A2F4AB4E4D4E398BDDA30F49BEF1C45F56982E86EE9319232CD70FBAEE1EC9585ECDC410860ECF714A22B5F0DD0ED56FAE06D1434CDD59BE1519950679A5B3C2E4D124F05D29A5F9091BCAF6D1D372DC880BA99F8C84200446833172AEBDC96DD5AF69C48F0EAFA777EEC70290D5A5C2F01412B984951B6DAB4AA42C461B6BA23E223EAC6AA1D5851AA6319BB3CFB6DEA4B300F7E091E405696CC3E1ACDBEB5E94EDBDD387151F69B2E18A67D28BEA726E467678ECD185B17D654E13B0CD91E875458F372B74E73DF6C20FA147B3CBC4D6CF570F4E67217C466980E947DB2C6ACB9F06E44E4DAE45B365E0F774935891AEA81C65B8F4414C89D3213640CBB58C14D7270EB52907AF7A1A5E8F367F9418295BA72E2BD3C8FB81909D5681CC65B3BDB4CDE36C0EA6EC172D1CB0C84B5ACC2321430BDC1ADA34D36B4D98D4D747BED876251A24DCFC80E03E140E3659C333C291DF86AD13809BEEE11B95EBF64F91B56ADC3C491A3ECFFA0886DC0F171875B484295E9ADDD295A6E16CA14E07A711E6B1966E83A054E4125342A1145646E8779BC7C755153FD6E9E69002ABDF5AD096D0E8DE0906FC7140E83574543FB6B6A5C975D57610E90B93CA44F69BA058036932E42EB05A6940F51B7089F53037A956365CCA7F89110FBE9371EF96DFA4FBC1CB037F405EC1E0591D84CEAD659B6552BEB782EE77FD885C0BD2E03551C77C9C61A1C93017155A84D16E32FB66432A7A52AE9D8F107D21DE8DEC26C865F2A0FA1D6892AFF3AB11FF08FB38431CBDC211E29E18493865D90E9D93A5B521B6A0C4F698FB5E36661892B203EC93094D0BE06D765BAE570CE183870C9CFADD165D9B41E7EF6C4149098F61C34E2B152AEE850CBA0CE5A885CDD6F747C5267104E1B9EAD1DD6C3FD71688F66876FBDAAD08712383673201C283152BC21D0158CC90E8B51136FA14FF1A80E6063069295A4E46D9BFF2B091F00440E415D56F2575397228DD08829044504F35A029F3409DCFEE95C8794245742100804523DB85BE80BDC55446A1BDB58C4F8285E41FE86C045FF689ED4273C3881AEB6353FC9C0C8FFD0DA86EF9F1A85981EB0C36E293C0133A0BBFAFB821960B263D3A02CA7E74D8F55F526BEF5FFBC14BF7331273A62435B40BBF88FDB96B09BCB7550AE50FEA25CA3DCA0DCA2DCA1DCA33CA03CA23CA13CA3BCA0BCA2BCA1BCA3FC43F98FF051925B10E822D1790E7716EC85F51BB3B2085BDACD2BE4249832C7FE64F977AC9A4E767DF68A1F70E587441C219B123A575E28C92B8C8BCC914143115629DDC62810292F693362A5C2CDC92021497F0DF3826FC10E1282928D2F7E982B5B90E0046BAA322F4D618304A1D3B0E2834B610E1A88E8F45C2A95F5A03C09BB12FCEB998FCA8D198EC9E556B1FC7068E29617BE7F2E3F42F576EE523FBAF223910EF63E7F36293FBC1F0D9819FD0675D1FDA3D226D0E52B86F4F5AB74597C761CE35E9B6EEF78FBD2D8CAD02DD816014FB5A54294EB58C7C053C0E53FE235EB49FD58A2D9C7F276EAC5741E62EC17D433D87656FC5B712DAC370AEEF102853C772F5E140549FCF5E8F2CCD8E6C46F27A62C4E16ED57B17F5A27F270117330C12B72DB169E8E0A3FC33BA347D7A6329A7CD6B18189732F335931FF3FE4E85212201BDA9A47181A30352398DAC164AB3D8CC4055EB8559E527A27A1F428C93D84E273FD17FF9272BE3404DFF5C695A2E4BAA8245F2A2E98D7EFB3CCDEC73BC573EA086EF60DE74E2C4F0783201008040281902597F8C525232B30673FA530B96981D0346629412010083C100EF0BCD235138F568958B30929DCBF67E0DE6275EFA750A7E6D10FC4CF19915D5F00C4536D8940B7C9EB84B888466CB880E4694385D328132FB1BCEC8CF83984FC1D0402814020703B14F2026E8AAC688ED80C8F4640FE3B1045C2D89765A86FF0D87DE7F09DF20D810921EA578699EB1EE425564E2AAFA54490A7D40631967D153E23C41DB3D611DB0FEA4807C26BB28BE0A77B103AA0E4784112CF643547CF80D92ED85A63F31F55F3AF5720CC44498EA124432C8422FAA71B2CB53F14E2C844042EAA783D3E93151AB7A0AD63DCAE64E8B0DDC149CFA6020640B8FE554D51F2CBBEAE8F9984173AFFEB4FE512A8334A2943E68744F0BF11CDEC54F8B9ADDC39176276D707FF06BFA2B0983E65F5CE13112A1A26239731AC26112864FE10FE32586D41687A819F29523E13CB25C3403860BE26DC03E97F4DF7D072F907F52BB15FEFD24BC4B6032B0B6555AAAACB53ED016E1F03A4427D974438272A59C90C44B9CE86D3A605E494BD785846E6AF15C5A57FFCF8E0928653A2A987E57A4F4D6091F5CD12655B8D1A85D6BC9881FB94DCB5189B4B75289C8EA8C5768BEC99AEACAD1BEE6E91935F1DDF18B2FD604765BA2E1FB536B45928490FFD3F2C8FB0497050566D8539FFFBBCF94F044512A4775A42164BE360B13BFBAD0C80B9F5B9D9D1C49EAC1DCD9BAA5F2F85AFEDE23DCC8FFEB073D5EAC3CBEA460117E9692C361019175CF083585E604321E07FABD634FB6092E456BD9008CCFBF536C7457A71D70785575ADC0E262329E6DB3993A29484503D8DB6AC7794ADAFF5271F7DA65A540C63C046C183ED9B1384B702FED33A8340577BBA91CC2F3551FE93342E81129725D2CD2E44B727C939DE0FF08802FFF43E847715EFD0220B0D081A47522A0E1D60924399D7E0CEFB62B2841D47BD3ECB3901D8311F707B02A11199B79E3D7BC184AEAC5FF3DF8FE527697FE095905C7FE9C7053BE957012C7CCB1D428338813F5A2B3C6ABDD41E46D9115879910B1078C65217323B2793EC0C784DD4FCF575C973EB17400521FFD7559D680473714075A6525C5D44365E9FBFC8B1D2C39FB08BCA7E00D04EE4413F4F95D9E030C8FF1C8F49E4D413ECAD8175D3EF7996EBAF459DDE5B18F692964C1EF9DCF891313982DD738D1A6CB51068F9276BD1863BBAC7988D27433F0B3647A733718600F36BF659ACCB71064B21014FF1DF6C3E3DB2D6B0FFEEA15A40586687F6B3A6D1CEFD6F634917F77C49744BCAE573C27A5366DE3F833F2AD6969C18E8B32D3E8E525C909AEC9EBC13FF364778A1AFC8B29B76B76EA9D561CDE7FD4E2E35DBA6BA8375E98F21B1524C6E7BC7582C018814FCF6BADBBDB2CFBA578EDBA1D56A491352FE76FC7D226E802BF094139AA68BFC49C9A6A47DBBA43E65316495F3947BDAC6B6C74C1649D52243ADE3D03F46DCCE8069AC578A970F74C8618ECAE944FE23F183266342B6DAEA2A8A2E3F978FB7E83B7A420DA05359099F262533D5E0E4D69D82C116A21712E65A394F13D827E2CB3252AD8DC6C3424BA09017687E8CE33A35FE8DFE46D1787DCAD295D645B58D1021AFB692A20AEE01CA1218FD3CE29ACB7EB08DEA59764169E07EEB9B6507B5EB2657FF0E6D0AE2E92A603F3B3079435956944EE5771E798DFB91FBA29AD54DA0CC25C3DF7577B95911998537F49EB40F301CE553FB29F5942F0D8BFD7BF27C02C34B53D13BF2AED6351D25D4949670E149A09B10792D43E685FA34A91A23C7DD1832522CBDEDDB09C403A88EE6D2F96EAB795CC197A253AB98F9874EFB13A3270125A3E54F3045D3FF0D1487EDA7F96BFAF5753DCB026BD28E47CEFE8296472E8C416148FA1E18641F0083777E251808072E6FF95714FEC9AF5E55594DCA5D3BD176E7FC21FD6080EF39F4D9C0ABC42B4106C079199635B15BB3AFD70BD0B7857EE6BA85215C271A1FBEA923B84979AAA8B1FDA5F6F7B944A0977F1CF0243F943FE47DF5A84A21285FD9F8A657FFB5FCF314E83A9D1C5D3B51F33862500634701A64D3A0F1D672211B2752F5586C0536D20ED2498E43197A9AB3149BC395678253EDA20F4F7838707C7B8B46463B969D4A6BD1E6C39B9BE135422A1616569A4B108DE20884B4C347D43604E89B8864506478D606D81496BFF02EF2DC4B22E70B51C4FFDE42CCCCB610E5CF943528CEB63FFDB9FA5D02AFD4FD17B0A114A6AC1D4D3650F7B519E53A98FA859246F307B0F8EF554C2EB9673E59D6D7734196D86FCF293EF869DD0161FD6A6B0EF5AE81AA0BFA31ADBF0CFB1839D3EC3E09852BB01BCAD503E0CC70D306181FCC07F819AA363747B2BD1CFA22B70D7FEF8203F5F48E8D7F87EE674D8DF6077C4C1FA52EA2701E0FF56665AA005A30A80D7FFF7A842FE9C3D08F05EABC66087C61E721BDBA6D11C993F6423B7F22B263832F7DA1F432056A1C318D8F3A57ECAC9E28A285FD50D4D858DDC7A5D22B0AE79B3FE4D8010CF0B9FF18D114DF8CDCFA7DA62AC87C16B870729AA575294E38C16C54FAD9A9AE1AA044E4FE1F8562AEF44B0776AC925C2113170E42A5F1C48E2AD533DF3E406CABC69AC281BE8031A2E00D63DA069CAAF24E5008E861BF56032B4D177243F2F1E870A60116E7B51EFE94D7A05F635FDB412D8D908664749FECDFD474F29413419470634D193DB2E106E3B87E1D70413F69AB7E80E0FFC77EFFB5EE5019C0D50AEBCB1D6C0E4128EF78948AC74959F658CCFAF07CEA48AB7C38F26C0791844332A7006633AD82DFBD7AB77C7C6B1C71F339590BE14DB8C9816BE25552518ED80B933A6170EE0526642E0957646B9D70EBE635A12B5D63698667E91688C03FA9D1F9A7B62B0D6210512EAEA044A24EDB57FD4DFA562EDC76EC3FB2843CA6C40B4A890F0CE86D4641F9A0F605F8910006F2B0FFD3F43D2258EFB2994E1332280B7D1BD39D3244D2271CD9B567C4DF5D9500C2326EDEFF490CC5083B0A497FAD6831B81D3B2209293B58FBF276D858A8B4FEAB01F33644D4C94540E59796DDD6B36F7A207118A8A01A15DA07A97EF1F8CE114E02D06B31792F24C8672FC05EB702B02E9ED5D1EC2A4FE13CD4AF5D72913F390F16DEC890F26D8A891F3061202B15BC1C080FF405C2110556ED3EB9FA4C467D96B5A95FF7826559708396626096C946B12149F7851B75C3953B957970560152750A7B5FB0075A23ECBB3BDF9A981EFE23B505F2D36F1D145F141F142F140F1477141704DE922C35CEAA3F7F06FC85CBB3588FD3BEBA6A487AFFE4C0886A8546FAB525CB0B6564AE53A3D874011FD01D8B9F49F12E6CD630D3EF0329282B8537843242BA5082CC71505EC8CC7EE47F916DB2D179FFFD707315C709A46D99C7207F3FC288CBAF8D2471E42CEB0F36F6F50ECE583D2FEF2BCCD837E499B6A40DD6FB504C8FCDCDBC09B0CFAA5E8E6A5A207E30C6521949FE39100E2436FF887C95EA2C2F5FA02581FBFB302137D2132ABB5AA37DFFB950333286BB1620FF3A0FA6863E6AA3854E54D4FCA0339912FEE3480C13B391D43CD4B9675C610C028140BAFF0F28E4B9F300A212476EFE1EEE54FECB4681BE8411063C4CA6335EE3D8F5DE3783C327F280B138425E210D02B34C4AFD07DFC49F29C91A61DB18C297F9923FD65367B7959814D403E1C04D65CEC1FF8C1F7807E28FCC56EFC96F1DD9E50A96BF43C3AE703BFEF946E65E03640D5B9BD21243BE70E0B9E16AFF680E568C18DA25E62D8589E69D6FFE3713EA20100804028105A19017304F6445732416241AF6E117E842BEFB776250967EF1A4A181E051C3D3F0D2404B4D691D6128181AE19D2356212B9FCA2FC70BD6AA1D494635935E1DC96D83040110A6BBEDA2DDA0888138225BD4E51262000CB0A1C356AC00FAE207E6D943F24F0FB1631B3B79F4B84F7DF35B353ABED22F9A80345B5440DB4CC8D04D2A43FDDC5554FAFFA541CF68DE998965D3B2966DC4BA41EAC379415FE0DC2285BC5B05A50D3BC397ACF89452C1154426C71C07BD3AA7A557974A235A97F02E38E82C6199DF52786037CD62DE2C68278CEB50581648EAC4EA040E0779A03B34AEB63CEA4361E83B186B3895211D5D768E805A2B121469CB8F4A0F144644ADDFA98621E97D848D4D01712808464DE806CB4702748C20CB9DA03026DD195C19075C4108ECFE5AB8AE415BD39AEEA83056F2CB6B82FF9CA589E2409EB1565F70018A7ED047BE98FF015D737E2173E82C213B6501038C4C230674CD0B564BDAE831EF1E08E03EFBAD9A592A2A32EB35DE15F776F14F89EB2E18344D77201FC1AE7251F68935740A7D3E8E82378CADF67A022F09820302836C86F4B5542CBE349FD6E4B60B466605D35E3FC75289F7D524493321D18CDCB7000182E6B69968D6034284C8106E61204C491CB31D62800AEAAD7375F0025EA59F4A4EE3194882BE2BAB19CBEB82FF7BF41DE483DC4D0DE03C6CA270C1F6DA8DA8EEDE914B39D63FEFF3A58103AA31614911239B1C923EC01D1B4A10AC26C0DE016621CDB50A81402AB944CA0F9A81A58CCC4488013A10359C94B8C2E51FB3AC1E2807E0708DF361751062F67F94B9DB6F19704E6702C43AEB669C54098DE49B251A73F40B8893A2A87667ABCD4DD1A007B7F1179E78EAC2BC43212F304FA5C9FFA1106D17EDA4B8048A013B8F4F7E449126396575C6A6C9916E7D7583EED5873C3AF9D166B1FF299C5A8EA10F2C408636AF49E673A9F64C2A73E24E0790B091FDED1EC4ADFD2A84141B3F77273B29B1B8414A952F53E8CBEBC6013168657CDBA4FF910AB166B4AB31B374A49CA3C081D6913C5315CD748D4A16BAE0BAB8ADF692ACAF1AB0843468D188830DB2FD6460C3F3BB6CC4855FF964FC5188AB5E7F4FC83A2417DC75D028671614C64B0969E94240A10ADBC16A31C34CA7282106C0C0C27C253B6627028D192985AB352D4AB1BCFB300B9AE66FF9DFE3974A14F38E56404810B4D21DA35109DA4BC2AA207BADDEE0FBDB66ED30C09E7BACEB5BF4277BAC250C26BC5127E07C7A45425CA3B3212FA068E0AA071485EFF19C1588D0921FB85C9A6F368512F9701D194713BFC81BDE5971B755720C8FBC70EE13A9F2109BE21FC7B9B52BBF92F680040C84F86D51163857678BF64375B5654E525B0C84035963660CC58401F7853043450711433B446CBCEDA1866322EA75BFDEA0AE45F1003CDD27390CD7B7A1BF1364A5DC92D9D4566F36194B62D4843C88B224FFCE05DAC1394074C452FD513DD62F2A3C8CC6B79D712B3ECC5443B34798665EF7A673BEEAEE0BD7678E3F37FE5BBAB074EDDFA5B10093919181C139407F1F60501FFDAFF47A593A4478FD2AE16EBD1F7F9AD2D37E1F73A1E616723EBEE1DDE5F142AC83AB4EA294A5570C5325F03291B9FDD8431F192DCFEBC64EDCD41F4B7F7033A1280217B2B69948C21A5622C2448517631CD5B63222C2F85F2D4E0F25E8FFCDEC58769A622F34CD410FBEB359E12ADDC22AD3A2A949FC2B97AF06B1405B0C26FDE71154093FD0B90345DB68A55DBEF2C5698F18EAFE70C5720C11EC358045086DE46EAF0795FCDAA487DFFA97BAA54F2F23D531B0D0C505A9CDF54EF28AD5F990EF830A131A37890BE8CDD7CC46F0FD8E3650E4A0F66E43AD7558C10CA2B519931D6281B47D6D67596EF6C1972AACF1A641B3EB8ECD0218A77BA49D3E42F1B061053A7E8075C045E1E3ED6F6E718DDDD7F76D47CE418B4B27529773795B453D93680F7843E47766F34136F0CB563512E4DD176C3AB0DEEFACFF8FFE4B0FF63CFDF883256C0F4FE3C3A480A6F7ADE553B4688D32DECFFC995F5500724FEDE98581DE33B6651FCAA22BC14F41BB71D29CAB0038E778D3CFB4535EDE44A64673512C1BF4E0DFE87B14B5047996DB8071C87F1D93E5F8B3E510BDF96F35A98E65BFDC557D16A5611D5E341A244EA5FBCCA8BAE612EDCAB123DDC3704EB381BCCE4219171C095A25C8FD8C74B96402E7E23DBA1879C60E800189C6ABE07FF94ECE6BD7684DE3E8AB27E8F8AB5928E53FCDC387BEA0E0E8049100663AB879F1B4BB08234797FC0F19AC17379C8F26914BFFE0B915438E082FF3862425D8D572C03F551CA058DC56A2184F7AAC5E97AA392B5468D0762134D1253635B710618D92027A36AF80DDC4543C56B2ACBD589460C3BE82F6BDB1B3A9FF68A21393C25C643A2EB7B29A833279F3A1D64B914540534982E1FA4EFFD3C8FB6FBB4BC183EA16D5F249C5174BCEF6D75FC5152F1B36E703122932081DD6FCED1F5EA5E85793E6FFC462D6337AE87DEAD969B86D5BE69A89ED58C48A98DB8447D3D974E60410CD74FA5E9F8697B2EB743A33964A2138DB5FFC90B76F6E0CAED0B92DC4103F13F9954ABD317F6A914C5880F25FEF25F93C0AC9E5B4E51CD0BA313C45CB29F42D277D73687376107189CD8258A1B6B5131B35C6B5BFB71851C8C2614CA5A2D4BD96FCF12F81A44FBE9242CBDA3E95356AFDD483935EC0DE1FA823565250EE2DDA5710A348D637FD68E6F3FDF40F1E3307230F8BD3C7EF27122C0E1BEC2A00FB12BA1DD099B2B466E474AB85251ACEF4DB2EF4E3EF7C844ABBADC3015862B40BD1FAA659D547959BA27197C63C7E4782C40DAAE8DCE5069071B3C74D72B8B1C95203794ABDDA0EF947908468F5B23A24B595C71E438E5366A64CB06058081404038F8008C7AAB33FC0BD5EA7F47FD8D14AFF5732AEF437340B7F6CEF744004EE80236BD1263E2C7EED114CFC542642B6E70A5BFB424CF148F0F6B3DC0FA5DB019D8BE1CBDF2F125E5F16345D4C3157A8CB3F62171B8EFE21DB3321CE25CF14F3B57F6BC5933DE7C5BC2BFF1C44BAA525D671CDD0ABD595771826C8022CD1656698B88BF0D4515A09AE74A7DD1C39C17976E633A0D5A09098633574221DEAD0B3071D3F2094C833D65812B2814020103FE0453BF7D411796CC230A2AA3E27FEBB440EAC6FBB6F8C8DE7B33C0E880582147B594942C8B47AE99020F6DF5488555978C795D593D0F73943BAE18A065FFB9A857D7A09893DB0C9D0554C4774C9192C52CA7F716D823D250BBFD89E55FDA6BDAC551221B7F839FA98CAF08C2E3E5FBE94BC5B1DC83A992D7E7531AABBF6A3871716EBCFFBEDF4CB662A0A06426AC6F2CF362231DB423A4864C87DC97E5093BFD25BA6004CF98653C99D2F9D447E38DFBFC4AD72D0BD198AE550EAC4A5670F6BAE9378A0129905CC074FE45FF1A15CC9983D9ACB6C4E361FB933FB6BC3DBD2C43ACD59C55882AD8CD9BA798B4DD4FB2910471B94EFC1969D9F80570F37ECE9BA2ACB14DC2F5CF85B5D873A8C81BF6FF8DD8B447E4451109A66C48B4DB2C907C0C0D81179FDABB3F282352542F59C5EB78F2866A90CAC9ACB80574C996C68DFDD1F205879C86E762CD3C9420883480F078F22EF77BB394C66CA1AAD1D52A5ECAD499E931BDA3509AA89DF0F76F880AFAED47ED8A0C0C79734F3FB9B4F155AA2F9C1D9965D72BE436937BB56B30079D02A4E7A42FCA3DD002C0C7C263BE7B4BF947DB5CE2F972C68BA28ED50173C69EC739CE5FC7146692C921D6200F2627B6E31A55ACD5E8DBAF9C003C23EA84ED5A780D693D8566A9E6DFF5F179D803059C78AEDCF629604A5FE9CC020C3F453C39ECD3FE9880BD1028C056B38834454B576CB06CFB9923412F603489DD01808240942E6DB491BC495D5579B1DC488AF0B4F4F430DD91C18E823D5F262647735760807445304DB65ADA68D79F111F48FE8F982F3A43AA350485103D34CF0E659E732980073339500A059B836285FC44DD5CE525876B6CD1C8903F1170BBF00FA2D354BB0A4B1610DAF96C14F9D41D1D5DD5FED18BA2F788065FE4543E1F02717AA4FD35F12D11FB76E5A8C7C5A3FFE00523DE9472F9C147A67BBE67CA5D36C265F84E5FF0707EF07CE93EAB055176482BAE0525A4A4AF39C3812ACC848513A26409A61930B253A026D0036B459C841849594403432CC91E886877D53827E8D0F3B380774BF82BEEB6F71F0F4FDFF754E4CC7E433DDB163C4B516A2A9C81A32E4C883C37977FA4F002B7FAE8FF9DDE8DFC451F27AFBB2DFA6E5350186CDCDE16FA393134F65A1F885C8495DA17CFAFCAF342BB873FD8BC3DF178F25F67DD42E5DE5EFC7628CF04CEE9CEAEF1EAC4B935A402AC7227838751DC753E6B37E442DDD10E692BDCEDC09A3137655A3C759615403D90DDB302C3F700DFC95BEE0130613D60F05B4F51E926539F8B847FC93ECE3DD2F8E409D933B8AC7EF70714042CF57AC2515DAE81A7B3B80B2B233126EEB612F42082169279B87D7C49D1A94A767C98E2AEB3708F1DEF3B288BF0D516863694BFB4C2C8693D02F45B9DB3A7FC43157B26CB5009FBBC03253D43D2A95F4BF009826ACB77C0182FFC9D90DC8CEC87A81426AD145430E74BFDEF2AA2732F95418B638ECCEEB5EC3C3CF9D85C20219C4353B9D36F3DC9C6E5316E612CD200F6414C494D57395E2D363AC18F45F4028E0456C9A6879AC59D71F414DA2EC6B676B0679899B283336FA79650D6A41FCAA0292AA9F92800D7F0374B6423D1D1B713267F732F082287E94A31EF6DF602B8F97565CB15AA70B43F0CC3A09980B226126971F7F2283F46FF7D7B3201BE21F5CBF2D8641DE5F1B1828A5ACB8D2B0E43F4C5D2ABE143D5A018E1CACC3D9108DABA0285950D00B0D4CDC10B3429A65E3FF2D7F201CD8EDE73D6BFBF606765030D71CADEEA84F4A7FA4BB885B49B72F56903B904DFF06406DD982688DEB21597522EA022127638FDCDCC6FDB31A5A017585ECB3E6E29C9D4DA0EE9DF8CE7085EC140B88BEBABE7BC59F7A4A233BAFA79F460FEC2238C833C8DBCAFF2486DA2CAA0E6202B6D8853BBBBA1D379874FB1455BAE95A96BF6F771CD923163E244EEB0A1363FF46C280BB2075201889A96A56C35300657D2A13B7430C50C7F8AC5200BA5C7D7CF75AC4A2F9B740C3781F2991A326DE9080465467C53D03C0FCE2FF63BB5722A740B9E4F2B3DDBF27246FFE36DA80761A65DF58A263BE7C447838FE3B837FFA04FE34C11BBE65B29B5DD8F680E5FC53168BBAF1A27ABC365E48903AB5448B1B6C7B4FFF0F1E73EAA102DEBC25E9BF2B1175559D29C3C7B066850C73FFB2666F2B257D1440F5D7E0510794DB2273EDB2BDFB88E31709E466B5F506D3FF684EF593E70F01260C198CE30B2EE267383EEF6398CEB42DD6F644A9DC44E22B0A1696B582FBD7A9237F1839E15B406B42415EDC0F8D0835B93AF5145D9B2DC246CA96EAEC0B3169772E4EE715D9641ADD7DCEDE1F6A70D21EA6AF88E8D4055D9B695546BF8564453EC5C69F85B157FFDF3B84AD9E1766CE902176D100A41B116FF620D1B986333DA5E31459EFFF8FCD588DECC98F93B01777F0CC3BDD23A1900F961906FB65A75B8C67FF9869F6D75C902B89CADFDDE8B78BF8E1082DB12B2C3A917DF98DABC9EE526C0006A40555E60770DEEB00B327F963F9D6D5929BE8EF4C8C8566E8C8EE960D4130FB25267AFBEE4355C1407D608E1DD2FFA40736E5602FF302E80FC60E12DE8D6607576585E0C8B09067B37141839BB624CB5415A6DB3DA650BD204DDDB82F1496C580B371B32905606DA26011FA4FBE4D89FC2B7F5C1E3537113122255B4FFD99B0D78E3A4A950B07A37EF1205C004E10548424D6970015098D90AA395DD7DBB64A31A5B34FB80E686DCD7D66BD7D107C6241DF39C7653663756422712843B7746B1D4E78A01B6CF6CF678D8FA9A8C423F82D1F70C174136792DE5D31B4D903C777DD939D5E2D540CD510FD3586E5F3265CE9B0E6019ED067378DBACA5B0DAFF127AB47208D1FC5F7BB0CF9A21142E9EB0AFF907721D12009D254A5AC6F9CEBD170A7D425F6B15253F327A2EDB93264196C4A10C00C75486A07C92B9C012AEBE287BF87DFBD6A96EE102545C4C496CD43B8798A3E242C8E47E5267A91CF09433E8A2EC26B1DC268D2595BD06FE0C45EFBAD38666CC49DE254B9A4792E85A794F8C5232D4F1A2A9D3CE9E6EA7D210E13C9E2BF9D8330A665D3451AFFDB2D10E7B5693EC9EA8447686CA239B585E985E723C3D9C1B3C6E13839B905783941DE264928CBCA4C4E175B13B3EA4377099282E67455EC29BBBE8419AB5A03A6043B6CBB2E53252EFEC2B6B2196C3C0E1D13AC1E871191B8501E8A946993D753FC6EEF693E2BD159BC4F708BF3F26847A9BE11A50D7C1039543F440EB94DF479F79ADBF9CF20C0A7D4F628EAAAE98561B3FC8D6914B33A5EA9754DD6D77E0AFA1BA12F0F11E451777A3BE0ED1382624A197ACFE9C232EC7F2CBD898E7DCC98D30009DC1C3E092A3B763A478807E2BFFB6AEC10B2F33951D5A50A72F70C473B234132E75E4712C4029EF61FFF5FC7E5575E75CFD0E6FB61397E28B87B5FED7C772C0B3210A4943DF400DC663B14E35560312A9E7ACE8432CAF1CB9A1A9D30CB4C0C6561B370E0D41F9A1A3D450014F2ECF3A9385B2DA5C82A0D7F3F89877A903E934A5980A2170E519B06C28149C9C62C3A063D6F2AB1DD249871DB098F6A31769CDFB3BC6B8DC0DD885ED91620556B6D0D366D5F1BF6D9F4581DDCB0B9319150D3529817C4959BC9EE3DD56FEA42818260402010080482E784BEC0B35A46C326619F9092377B5928963C5F0712C81A870FB6F38D16A87B10366387C3BBE0463EDBCF4E99E4D506AAB5ADC815C3B23A46B3D9CFD0095EA39F18DA990DB48F4C80F3E818377781BDFD070FDFCC31646FC17A4C2AC44F46B052DE5DE3EEE942730DC8FB5B0CFEB4A935B998824DB720EBF8820D8D0335070E23538897A04284E25052196C6873F3A28186CBD07CC3CDED500D1D2853E51CD0340EAE90CBBA25C0C248CF41FC14012BE511C331FE53513C15B9FB123C224A03A47D88F864E431D15F4CA6601B7C58635E6D18120728F03083174A0FF46E976EEAB6D005B013E2E4C9A212C65CA9BC738DA495F8BB483EEB772167E594EE44192CE6BE81A21844E5E5E6E3696D4B254465636BE7E8EC6CE96249C542E5696B472544C5E1CF2160C96DCD2529C02928CB6D63CB2F296DC92DC063CD2F28C0C52728C52D6DCB292DC361CBC3CD4F15022E800F7851016C043208FA530B372B3052D1BBF9B5045D716D1992C068764831488B870B6008CCCCF876DD3379D4B7E1E90E263677CE6A7CAF02D2F2C22195A2A316DE859B0C7837BFF3B060C1A6D9211678707DB53516AC1A55AE318C8EBEFB32841B2D53C4B5BDAD18D725DA2625EE81051888146738EC44A0BC5903619F72D929090FF98CF7287A1E8EAB2449A737C65F8898D41EBAE91B61CD51B4A1CE85E74D01C2460DB2C10439A4E1A9A47F877CF6A83AA8AC73B6568FC3A246A586DDB851229097E0211299AA508E3BD8097CBA54882F819F171EAC8D68640AFF1E29179A8880AB55442DEEB60E3C4AE9F32F729B2F2F724C18AABDB54ED53065AA2B94D34ECD655509A5A35682FF3599F4EC538530F601C120FF7C1C00037D4331B2271514BEB98E1CBD22A2470877D0BB5FDBA79A0BB825811D6C5575F800DAAFDD7FC77D2E815A9D8BFBF7912852CE86ADFFCE85D839E8A8333A53972E2D259E08B3650B5071C16065AF2AF3C05AABD2B96E5B9D8C76D6D9E70B7AB5433987DA20EDF3D0A5BE82157DF9196A7B05A580551B099B006249DFFE0C945C3C83199692CA90DC484682485C80D88D33EFA417DDE0BE1971AB6A273F363850357457A20DB3FCC913E6DB94AE35F2639E26809FDD7685E8FB1CCBBA85D26B41EC197A16C63B3DAF2D3548440CF237CCE307DDE337EF9278000F50BD342D8A8E18AA56D54DD92CCF0381B9BBE42DD9BC33EA2F13C489206C16E4D83E0CCD7E5AA13C339546BD0371DC37C38F826A0D41A850D17CC5FAB19B02309E1BB121FD25F7468223574AB3BED0F37F454D309A3A2A2EA9D3193F58E353861A8E5FBD8600C1B97F76A68A7E0DD83F0B1B9B1EC13BC36F5BD43AB6CDF502AF8EFAFD87674DC8939FCAC59A2A8CE35CC0F7F80D2163601250B5EA5E929352491C066EE228A92251528455D84E2F067EE57E2F63A52DB770098452257FAE1FE910DC8E719ADAEC5B5C01E0053850AA1CF3167FFDDBA6E7AE4F6B99E94408A38381B8ED2B2ECA2E6AF32F7521F8E47BD5B046FF3DB0355A9FDAF1CA87ABD4FC741AA72BBDE759080275C1C27E7147725E685319EC9A0E3AB63FB96C157A8CAB0E123647B11C94B0C35A08E0090539FD2284A070748F03C7C39F62315ED74B33C13A7FBAF17C62AD34171DB7E877E2C8833DEEC5414C037964AFC325774F90874344C777DC22F68913816A3CF8CFBBE983A1831E41EAFE228B89813B0006541CC867F1CDFBE01F293576BEEC3139D215858AFE3276BDAAC768507417B3380634AAADC511DE13C101DE0AB3366AE246851827224BADB04C1AA1576E71AAEE25EC050EDC0BECF38491608C9BBAADCBD4517C3F28C83310AC98D108C44EE1A75B630C4C72ACE3C2770372771388B0647E0B5BC375B613D5A7FF16994CB56C16501260DBE0EAF3A920ABC1A11A8C4F266959040ED9B826F803E140AF33DAE2A8094DF81185844896AE5BE2AF920876F18D3FAC240812DFFA339C7200ADCBB1386F3E858E51FF9FD017808FE7296AC1B2641F6E560CFBE78CAEEB35320FF80B7DBE602CD2F51A3B9230EBEB4C360A0B42423C6154832E93FAE97DFD5547352B2F5A6545EBD3FBF161BB3215796E2764FA77BC335A7DA5DCC96D39FE26C803555767E9D50BE8CBB7A3E0FEB04A1E9361E25F71830552E9CE74AE884D6FC3870A2FD34ED3D2CA00941DFB4497730B8C3153298F6157CE4D33A99DDD5773468BD1BE4AFA9AAEAA19081AF25BFF941F476FC85D0BA671A7FC25A8E8FBB685218E31929BB6F8F2BC64FA3D755FBE00E6E026CF7FED712831B8C2002B53A9DDA924678D6DAF7313E50BEC27062F0F8507D56744EC7F4C4816F40592162967529F1A0581A36108AE2BB382488BD21EC25C495D684B96769DB30CDCFF7C450FEF82D03CA172873EE81D51FC01D652F071E76BEAC1379007BA91E143A0D9AE4D21AE70A1647F3FF64C6E1013ABCFF3CE1A605C74752C07643BC10707341F38AE843190535DB6728507C2A47955DF2929511A9F163B1404728D3F88B7E7C357077DCEF6A4EDB0EBC26FC1DFF7616F6BA24A6E54B57B6CE555B7F275BF4F966EDB5C0188B5791A21B4C948BF6F87AA87285B589CBCF99D563D27F1541D90E5045E52BFE3FE8AFE45E0BA4C9983AC5FD7DF1CC723BBFD94A1ABFAC7C27F732DCB7FD2B3A9B851615BD1E57AF4E48F22A0158B536FB064E52A980F8539A5835F689F3089BF3F6BA221186B36C6D3252A210F26E8E15F607C232B9AC56A2CAD9369C5BFB8E8643D0EF2F5752B972FBB0B06FAFEA248E4DB2C321858C32BD04D3A72333551F9B35254341EE4C11E12E85B49FEE080FA1C7C1F8C9D2441C3CCD774C6BF9F67C8B3C54038F0712245BF55B9FB0C6694B3AC66D4BD992AF8A9EBA07C770EA63422C54F6B39074C849227AEE43E54E4F84199DEE7C14DCB9B0A3CB3F77B5B8F840D232F1D6A67C2D3409D474354A0187274670C59A318EC67BC251B65A97181F6874EE8B0A811E533F787F87264004E586610497B0BD3B1385091C07B268EF0F9F0B0E8EFCCC6CF779D238974393E10F3AAEEDF62DAA1E0F970E27289F8D93CDFEE372601106751C527C14E14B749E9A546FE012156BBDCCB8D8D2B73483946F0520B2810B10156BD4878CB18880EF251EBEB3E0D5DADDABBC7F497658FE4F8F5BFE6DCBE0B86A1283645BC89211761275DC8C30B7D524EC1C9B48E7EBD6857B5244B6254192E85B7150E1647B9416C0DBDB1503E2740744D3D4C1F4B24F71A787ACA5D6BD3338B624F3D3738CC784962845E27AFE1A3B8C1244D8CB1E19587AA5A629AA0F5C7E4DEBDF450AD3A6533E332E36732AE0B021E5AF4F504ED66276AA1BF1BDC1BD157A4B36289FF1DE3D5A557689A87F50E3BF53A9460A912C17CD2C01680FBCDF6099230B49B5B7228BD2F7967607BC5AE3135529CFFAFDEE76DCC8ABA181CEE072026C674E78FDC9C2B4A1B24B1C0E6B79F71F556DD093DB0C4DD421E749563DDA85E81536746DE2F175AA5A67CE2803D2FFBC3991EF654F8AB6616FCA0C3DF92F388F7BE3B99862DAFE0C2BCDEF0C22E44C4529C90999F1A99A8FB372E8AC73BEC175817E9930252AEA339F97585B8D0E285F0F2826AE16DDDC37D4EFCA78D847ECEA863D9F6C1F758DFA5C0ED51FE1BA981BE5F9AF34499E5D52760624EA28F107942CA42D32B89831840FB58E3D452D12CD63BEF0938349659B73AF491FA42B1FB8E4950A8262785CAC4E2E006E80BB84E2E258E0F513CE178485C69525BFD387EAC2E2D905FA94E951ECB4A239329206BC090F634F5D33CEAB8FA77FEA6AAD53F91FC4483C489F730302D142A33257829103FBC0EA07E68D56FE0CA4D0412A0485787A33298E403A0C8A3B194C9A27B56FC95DF5CDAABFB331F3DDEC742F9011035571886F9947735F6F5D3DDCE786880F1A648586EB4157E602BA71702B28B0361486FE336A1737EC46C7ADE3AD5BC612FA039F186133603AF42073315D5267E03A537E413052DA7725B6162E98AE7B6FB7A497DE78009196B083C0AC564452CAB091CC7B56D8021481E146B087F197DF98ACD232264BE41931D7B26580DC25E413506E20514BF07542107D2B34E432563B5DC5D320C8081C6D6A570214BCC134E333CC2A52FB2432609A97831C7BAF63F7FB46C4313633A01173A95475A6F4858BB39693F3956577EB03786DBC517F2F0CCC49E8F1DD79AB2C3A4949B7FFD11B8702D0A2A1870C418CEA08EC10DC4317DA794C767A3EF29A1B10C39FC516D036789F9BFB39E4900E27B46A0999E265766397DDB17EF9EAC988A24C84E1CFDF32B62D5082926D7926876E04CBFE4326609D8B3DF0D3DB5084AB37FA78411CE633EC5511D7FB294CA4EC30EE180939DCBDF792D600FC7A00B7AB9333E582E44038D1062BBFDE2DE26D4AF336402A8ABF237B4D9922CCA8E9F2D949D5F1125FC1BDA4A79EEC7E1556673CEB9479099E41C651479F4C605835DF0DE2A536F6D715714D858D897F8710A1EABB437E5B35A17B82F847D674EC27D4781904EDB4929FA3129DE618E3CF4CF42455A861E142A14D8C50A346F6BC45CD59D80F0DA6C225693C09CD4A11BBF40CCD612E1BB281767B7A3B8F45E96C94C1B497017F80C04030281402050857C2F02EEE47B18A15F1048911FE16EFA61966AE39B7E5DAAF0D5A8F273A289137E13076F0DFA03E20A8023856092AFD5CF1D60CF8AC6CB901B9BE70E1362C36CB6E3F731A26294E94B2492AD4AA2BEC8815E951D21713ABB3E3B7FF86E61489312B38E2EE8B97D2DADCCF2B89C0838FC82E7C572BC8ACC851D58BB4EF1319E1AABBDA7078AB009EC2A06E1A77A9E51EDB38961274AC366168A5CC4C900B566C085A8BAFAC89E28CEBF0D0B7C2B7D0FB68689916D23C1B1A081700011714A836CA78808AD0A232050B5ED9F4C6834EA98CC46FDAF6E3BD30E42544D00DE2F3677BAF6B4EFD3547643CEE249B84A6977C671058575141EC1DEF9DB26A40B17F9F39663711E39A2689B7D47917E4767050E9E2A9869ECBCEA8561342073C3BF2372A091C451C7DEBA0D821A88443D17A53683A66297F6AECC575078E6570FD12E2D16CF01BEE4B3A9626316FD683C6079C54593E76B030DC05B97ABD4EF44CACA9A7A0B94E7EF1FC74A1599FF0353AB9990E7FBF472A67F6E21728E197A7A12485F74610D431F20C45CDB1FA15EBEEACE9B19155FE6A95B0EE3C79E78D9FF8EEF792901702EB98184B33A8027DA22AF6244CDB58C819FAE96A423BABBC080D55A7371BC9E1AD83805C78B943E94156FD0158DFE4C847020A45751F14845226928D13A646AE0F2778BE5F742357A5CB478163E0F97FE0E7820B4BAB3E6BF85CE7AB723D59EAA3EE61D88FBD31A341C0DECFB2F5C89D1E0648930D8E7569CC77D3EC4FED86460DFC3EC4B6061B732A1CB75BF3FDFD98121DB5ED88A5743616B163752FC61DD7B866BFBE9F7CA912E15CB8734B6E1A44BBFBF2C06DDBD123B182A1F69220B277EDC11FC2CF36340EB56DA2B21C73CE9AD1668149D6DA1FE25B3EF1503F2764DA4482C1A96FD99EBA6431F263D46CC2FDEC351EC04D38DE92BDB07B13E2CD58CA686FFC53BEF66822B1B88EE0D9FE2B02BC6EC5D7D74972C2A39BFDF1E516825A0B89B9A9B40A5A37FB5F71B16ED29095DCF6A571EEF4FC8E20F1D7FE91CB45DB2BB9F595AD644E3A380EB4F22FB221893AA8BC6F23931AE2C2D828F01670DE15F3DBE5A04E17A11DB8B4EF6854D89354D90774DB5336884CC9260000C90E6852054130F10D8F460E0FFAE5BEB3871DE5BF91EA5C55E2FDA568755FF7304901CC4A81595477123DE1A083F8C1CFFE7B2F8C5818C4EFFDF08B536D65C6671859177D18F02B9D9865AC6E36BBE23A26F4E8F6ED542181E096A7F7F65DBE68A1B7C9973D0FD250DA2A00CC8D9CF4B14CE50CF8EECAE2511C0006766E4EFE81D9F02AE2C01DEF5E3F779EC07AEDCA90EB726CDA516002D617F0AF0A9E29C453F7114F951254362714F720B26A2C10B7DDD37A971AC808763868B230CBB1D974C58F3EA9422AE33FC52D8D85DCD70C2B3D796D04B65B2C8BD07A6CDFCFC4C82A3F57D1A4D8ECB4F39D3765BED409D82D5C63AFEF2EB47850E45F3D87DC62D743FEB8FC3DE3B587F2B7799E5B627148C8203AD47F788C0E7B035FB263FCAF2C0D1FE7F5AA62645E3A434BFA3F320E83781CC1E20D13D23B12E95FBB3ABE2A775C486853948E4CA75D5DE56B129B2C91D09F04C775CB5A4F01A0807A4FC77BE6363D1D0244517A69612A339CA749C10178DB7E0E763CF6087540A18030A9C6921E424579238B1430940AEB62776C45D525E5759885474986E28F6E98144CEE8A08E5AF4B7017C8EFF82F5761D5DB6F81D914EE437F9965E2BDE97FFAD06FD388DEBBC5756071FF2415FA2B113D66BF215ABA4E9887F5E61CFE05B3D42243B324AE3449383FEA3EAA132802D866AE92E03A76E36B09882298E7AC86CAE124AF0AFD04416211D8E8B22040D31BC42F2A3F43E8A2C3A3C4B4BEB339A29AE808D1D877B34CFAFC9BCF8759270E547100ED85A1FE0055F457B2ABF7ED589797337C2994216994FF11DE2BC7DA97283B542E0D7014846CC0D959E39C8E75E6F3397E90B32AC8F0A79BC06452F2D409499A45ACFA950C4D0CB063001E2F7EF68CC60C6E6F8D72C0CBB642E85E95B0E3EE3DF0CE9C4ECB1A67565BDE0B8C6D0A741D62BF2BAAD2BED9F45CAF8A616681EC1E49DCC58FF3E8B32E3FF29468684C6B51A034789672194FCC0D23DD6979C54B80521189105503C946424EC9E8199B3617675331350B07C1D4313BE3CD6D7979B09EB6B4F91270CD9BA33B0E46AF0640CC477836571173095FEED529BAA101B72F1B8432F6584C3EEAAC072F4FDC3C998DD2FC237771830FBC8072AC5EF53D968A146F1B455EE296C5ECBDA26B09E3357B6180807DE22DC70BC85B94BF7054B5A82A79841CF35FA1E060CFCAFB58A88D6A2D1702780F85B0AFD078E780EEA4D5CBA180FEF422D098AE8B73350F265B2FFA25F99081319D09C8BFC0D97EEECF58FBCA536B69738188F7AA88283A048F61D5312EE846DA797E28387B4A62478250E503BB9BB619AD78EDABE18DF932631BB6C413236CBFECDB09054D012F5994CA8383AE7D1A37FAA066A1348A42DAA10FDD9753A1E14EA63D40826BDA04EF0D25E4643522847A758C5DDFCC0E2EFA6E32820E04ACFD935C7758EAFB1F458D768C86FAA7880594CF66D33EEC7AFE3F878FE0BA43CF69FCBEAA2611F8E7F36DA8B0B2D68C73C09F94068DD5DF49F2A58A1DF012EB4BD94BC27DE7A4478C73F874252331371CA66FF6DFB910377D34E914B89A8FBCF1C3553D196D780405CA6CF12E7E913D1375C1CFD0979CE546DAD77085AB6F8B069C73E784CB277449820C4ABDC3A9DF9E571AFA1F08A07B8254FD9E71D48FB61235E73BCF0742C987F1750ED54A6FEC2A4FFD18E43408C6ED28F94B7F3152DF3771D3EFB9954303E91F59839026D27A4D372431C246FC0C819570EC9CFAE10186E752F3803DA8C7B471FE15D7551BF0D76C26A37031A7DE8838E0545805F90A169A949DBE0286BC18F49880130F059E56038E991057EA90007260B3976EFBB4C73A0DDCD7C54A6B4F0CE46B8A91D1080E04C86F18E173EA0A4EEA091CDDBEC9FE4162FDC145B10A2AADFAA2899E1343D0CC27728E40521C070412438BFD0D61984B8437C566A7817826C500FA98221D74E580EAA8724BD465E63C51F85C33F8C272415DBA8BA25170DF87B5C45B081D58D53A55624CAF07741B6CEA38563A86E7E66ADA7151987682623CF42A6608EE09B8FEAAABB2927982D15549D7C22C789CD925CB18D67B6746C574D6CB33965A03BE9D0E410D03E6EB898827979F9E751F82F5AD9D28247EF73AA878ED8D81B0536F6EFFDEA8D9A933D5606C080161CC6E183CCA32FDA7967F7A4CBCDA9CCB1C1D9138721D6B7E4919D848843584098979823336A179629BC1A5218DCB2365713F2474E717479EE950965FAC8E49DAADAE87AF3871C06CE6E96B878AC613CE2C22BA71B8AC14C0F3E76F191B1DC553713E8191F1D06705EF9F5F7C1550ABEA6B6E79781CB44D474B8D2FD7A814AC8E1DB24DADBE2D8FB65392FC3569E4FC702226574F09BF6363F7D42950802205F8405CA7CD6D502C45D0CA89C272D2B46218855FCA207A2D9921CB403C06B17A20208060402814020702814F2020E88AC688E044B84472320FF1D88223283CBE23B76AEA9E1091A369C04CEFDE846D34C50BB955D47FD79382B3AE8C4F97A54AC38B6218BAF1065835FACF2AA48860130708E2202936B4AFBFFD3B5CB322C1DE0341B70C91A2AEA063B3A9470F50EC5DC0684B979F4C2F4247C2B7FCDDEED5E87A96273AB591AB598FC2C1AAAFD6DC202D77EB60C08B5C9777F3884A70FF8FB6A22CF4BA1E2CC418872C66CF082EE02E944A5040D0DF6C42DD949507D01EF938C8331F7E7A8E4BECCB972996D2A36A0DCCF87F9F4C44CC3DD712B82F751724CCF2903FB153EE6CD65EB6288A3F2F7C5EAF4F539C336EFC7739CFB183E3931B60036000336CF940BBB480EEB1C7AA26417426D2E02767F96C79AEAE453B8F6603923D36101CAE44F740A26FC04AFFA8232267AD7AE6EE8DD0ABA608F7C5A98EFC8DF57C9379D2A9B5D6F056A0075EB9C91DD46E70AF76D1F05AB19063173052638A0E6EF50D89796681AD0AC9D1EF1E2737721BB0D060959EF613E3341D07601D170038433E9CEC951924A25549376D2CA1AB0FEA65B7F39059AE1304BFA1D65BE65BE75FD659694E21661349FB0CC709F6E84423CF2266F88A94FDAB6F00115B4AA5082937C4420A66BE225BBFF42D74ADE1DD9A5C7796E207D213708D3C145E6C71A17940AB543229319E5431DBF065A8CB9D1A02D4BA7786EC316BECD92EFF0D745BBDF23CBDBF50DBE97FAFF28D2AE71BD470CF5D4EB7F8131E108617F38451D85725AF2AE062611E8280F2AB9E55457545B10F8A62E8D303C7C7C5B895732F28A34FEE30C0E435EBE60B5325AB97084BB14ABCF5C7D9D0E6161E317176375A4ED13227A5B78593FD33505F78603EABB3B51A69D79C2535366FC1509E3008956A8F71F9618442B00FCF0E582A52F4ECA6B780BF0DA7092D1143C5BBE7E65D53EA42074C3283815E521B294D32383D3F2A5FF13871F6AAB4309D8FC50BD91A8974356A5061544A9BABFEACAD50BD7FAE8E8DB5B46AD6080B2927B97E244F56F3BE53042D833C09DF087EAD69B74FC9A290B1176DEED8FD925F990CE8A4FD954E65863F0D890B62E4838080604028140A008AB72E31D4819A280C93AACEC25F1D9F2A3745873492DF2B6CD1B9B6CB1889B6FE534E00A1B416CFBFF3BC744E2C8513CBCAF8C487EFCCDC8BD8E3959B9B90173C159190242CAEC7998DB6FDE05A2525198780807AE309606CD5476CED160B6D280B2ACFC14E5387B4B327FC071414AFF559D21A6F8C0C3A2085676F83C847B6A467C08E88DAAD94D71A994BF8A510ABED2D8211CD8A1311AD9C620FEFB778B48A46EF34410ED9978A4A6DDD0EF9B31C13BF8E41C169059114E355FF0986DF3AA6899C9BE91F7BEDE8DA11018373A31520156FC5A3BA49DDEE4ED1928EF06443A5DEFB639B6ABCACE2AA542A1F1713C3FF8686B0C07A0DFD32AF57B6BC0716CE455720ACC1E4E80E6D2AC147378D16D66618B3CA428EB09849922288A0C506061F3C8FC03ADD7FACDF77B593F6A59F414A544D52BD713B851D5D4E5127ED990578474F25C08E96504BB7135F942B745F5125F3969A6203BBCA970E2AFDA8B30F32F50AD2429A69D89D8E828004E795C31E124C5B52C9DD98A51D2565381DC9CE803E9EB7CFA02C7143A6CEF43175C0D080604028140206BAAD3CF2A107C926BBF7990E47D2518C34ED5D3ADAA0881DFE3297EA2E5A8FFCE74FC0B80E7D37730BC57F9DC43EC8FEDAE656E42E6FA22BF6E70DADE1994E958FF8218E508E603439FBE98E78462CA6F144E0235E7D9D45FAC76D563D3E96B61283B1B44A0506FED2B409EB0EC2C0A67B9D3CADE2E86364DA3AD377D323FD1FF75672C90F34401866150195017A07CF7B55C52FA090A4663E3F519C7577D9C20F660A72A73575C7E0CA7260D564B38ACBB59AF5A206C3BD05E8D14AFC12B05C2A1F75912734978D643523B4A8EEFD0AACFBE43B08FEA9DD808C2FA5D22A1259BEF3B88F74B29ABE08932EAC499C8EA26E85355CA779B04688372731C6C23277CC53FDBD4811A1E086E68B57F327906CBA6589F9EA1783CFA31EBA9605DAE2D19BC0C418397D55160D5D59611CBFFB6DCB03D91A86F0A3BEE1F9170F60B2EA3FA8C87148B35EAB655A062FB8439132AA0F1825F96F2072E564ED128EFB6FB45094505DFC867410A9BD9F646DAA35EF01FA162F8E6433A6B627F40F151EDCBBE69B7B2275DF3954F6D5C849BCF3FD726DE3BD67ECBCB60E307EBCB80212A1B156B83FC08EDA5DFFF288EDAA8BF1A237B7AC9C225E63D3C18D6CDFA612AAE4AC523FED8DF4F112BD7BB1A75A668566470C6B7E033D4C53E0963F2FFE5FBE27C93CBCF17C51B4838DA29B25572BD04BDC662E0CDDAC030925D0D1FFDDB6ECE98DAA5895F33AE962740205C877ACB7551361069349FB24EDAEBFFE7AD96BE956C3DE7677821865B955FEC1B51D7AD264C8E8B5B3FDC6CFF5A8F7D0682E2D52945BC7BDB407265C24F9892BB4A58B9D0234FD29A9E464C1716988BFDC81E6784955E1C9C017D01A790A713C03D2A928EF24CF502C4D5E01305708DFF7CB017C8F26C37FE0BEF02D3E495FDCA96C2B89C8588DE12774D3DEFBA64BB98D46D52CB3D35F746213C177A3380822B37CFE3623DEBEC83D77E96659E55E9772BB46937BD1BFD9DF07D5E627E15FB821920827AFBCB4ABBAF91B6549FBC0507D02861FE55B3B93C43FA070FD6357FD596E36A06A5565734D875FCE56AC077FE07B277D6CB1017642FB55E9A634A8D3D0DC976B2300AFC84C9801B2D302BACE3BDCE652297A702FEC166F4DD320AF29C063C08FCD8DD1E87DD57C407A59506832E7A7F701FCE7DA60BFB620758FE26D66CBF3CEDC997CBE33A8E14D0C0CE1D8CB1349A1D988DACA799FF83692379E9BD3431A197A5279C56F5143061AD21274AD3742C1D4155BB87EA12B141DD6D00C2E2483911D6D7954141B2D69F3D3C9B7FAB546DCE42800DFEB5F5BE50FA794E868282C6687DB155685AA13C04B004584AEA39B072F12A699259035B262C7F0E69D25DFE2C2C6F59C8EAAAA6B99CA4162BD490A637699989E8F44A8181FD08866734F63F8E53D0D304AE704CE3FF6BD00D2A3AE60CC1A9ACF64E6E0E179720ABBF821DFD2CBAAF071C0556C7BC0310FEA8FDEEB1E70303602E90C8D92CD359283FA9EB017091A5889FA2720B81E0D381EF50BF4E1DB9DF8DA2CCE662E8E22CB27935B9C0226F36B92684DA18CEE403CD18E609ADB69659BC4BB0B3259203AA3BC13CE7214FBB5AB395B96AC1EB59D9D4A41BB6237F78FF7BF624611886DC95D4FF03559C487B6CC441004A113CB3AD6702F2597563ABDD90F09AC15DE078982CC668613ADC2972D02DEE82FB0F82018140201028970057FB80F33D0BFB9FFB3B49EB314EC191858176177E0695D47C2D706740BD3DC557E46850E89F027C7877899AAA6C82E9E249074BF77695FA1F4CDE7EDEDF7DB5FA6DDB04E6C1D324A42FF434C36A3138CD1EBDFCB9F2138F3D833F1E5F907982954549BE89D708A7FE07D95D4422808184734309C352653C3DB5180A8B398684AEE6EC85B414C31FF2EAF949B5C9EC0480BEA2478DD078CDD90FE4F5605D76AD106820AE7D85018CA1DAF507E60DB7D4197990FB877F81FC8DAC6826D9F463215198314BDC4487448342B91421BF181BEF0FF21E61FE7A5DCB10BC14631A39C42212704AF7A8556E5CF985473A1400B4900D32D78FE34F38881E236BBDD03A1804036080779937E3A2C9BCE569A7936E16C3336770E61098139816C156456CED91CB1700E80ABFA2924DF5AFE3D8F72C044898D71285EC9DAA96591F8AD5E442A83C1A1770CF79E8F34CD3815B4741A92FEC6EB58777DACC3528F5C104B86E1DEFF4EAE449A37E82B40E7DD777FB431559F38C5B6E195A59169FB7D2AE641FC35CA4FC70FBEBFC48B211437D9F416896571A7B99FB92171FCE53FB13CB108B1B242062B2C5BB7A9C8FABC4789A76694255FA7BCC938B129328585DFC7FA7AF4087B3F0B641B93403C3B493D45C3A9EE5221AEE21F3E7BF1C34A3BBC6F997652CBDDA516DA34B7C922F6159463027FDD3AF5A3B8A168D07C0C73FA23BC5AE8E990B295BFFE19F39FCD6575C267F9267AC032CEA223E7C74139A0692FDC7A040FBC348B2377131827DDE99C700B64489E0188DA461E969DD6F13D059A195BB0670D39F6B71FF79E5AD16F82C9D2A9ED592ECFCC9A249812B441CD4C1A55898E8EC8217BA94A8EAD5972551CF26571E8FB6BB5BE2E4518FF6221B9A74AB867610DA43D4993E49CF15BDEF28F46D3FEE3223E20CD238E2D8839871846CC89A5AF4D405807E054F9F527FAFBEBEFB27BDEA56BF6403A7A52F929A7EFD864EAFCF1C0EC6E5AE807F3C3FFDF22696FD993A8F9C9B703A6D1CB3E4B9A741CCF3A5B4CCE1779FC08E29A2255CF3A147DBD83A7F27066531F9BC18FB18A9C7205C8C87EDE3786A9893537809D77CCF0B7D51B1983A4AED4C60C228628B68BE37CDE311912AFA7C63080184536B792D2F5A11AB62B694027A1F1512FA0AEB4C8C00C2A9DB33AD23E28C507B0C8E7DB62D8EEE693DEB5B4304E1D2A93182FE35DF1E2406F2F27C9AB14516A5D6A2AB4C1FA16AFA49C93AACBF4E6644415FFC36FA192B9EDCF6BB2442822A5BFB31990C43F980C6C8FC14221240714C3945DF8D305E3454A2324CEBF6A435D986EF57872F7C54E27A308419624818B279C61656BCD8ADD3EC79D60AE31F4762B51F64D17DF61B8CC1A51DC72DDAC7558AEAEE9F1011532E5F525E51D1331AFD318BE2D6D76F534AD4CF6DD2EAD6259C8369A3AD8D24DB39EDFE1F3F964E333703756D89B46461D895C93E9B4F7F36160C7C391DDE6A92115DF9613A1BEBF50CB2A1CD6606CDC00DC6A03FA8CFDA99E769716F59CE0D1D7FFE67F3E16E7CF0937EE2DB4096395769D48F03C07A6918E6AA4698625BC6E5AFAC5EA238D4516BAA7562EAEBDBFE907A8D37C227377353D5CF49F3BCB89F2E340EFA593D2615C8EC8177CD1FA63FF6CF66FC9FFB6BF0E7E261507357F27340A04E1B799507515272DFACE0B2A60AEF6EA1552ECAB93650F70FCEF0173C2A91C5CC55768E3E40FD6BF7B8445B2CF4A66C1E9C2E064FD03FAE715D781FDDC7835131F7598C8E12E82C4B9AAADAC5137723B3EE1E9039A30368EDCE36ACE0991996F44F5B5C7EDDDCA68B20728E253F450BD2A62FFE49283721B2C7C50A29FC0C088742D6479588D6403870253BC6D44EE7B13338CECBC28CC9A646484B32D4123EFA56B8A9D6AC5343C60FB8D5AB1F75FECA0F18C1DB6FF4340F543AB1CE151C1DADFE36234370F8B4A175D1452D028201511F5F07FA82AF1189F41412A7D7F2D2BFD7C73BEAD6051476432D2B8D628132800282BC86BBBB6D01651F456269026E2B26C14446DE17648A0655426680090584628132007128E813197D401019DB2D0B660099D9178A44110230CB4A17216006C7A1E0A0E09AC20DE8F090A7312CC44824A2913F78D4C5F1365431CC46CCC4B11B187F3CED849502923CA4FC04F3091A7E60F3C4F9CFB05C5AAABB79D51CC57FC36464A7054F21CB526F17B7B406B4031665E4B889A2758DF44355DD618248C3EAD1345643DFA47E299FCC277E65C7033C667691B1D23C8B30ECB6EDC6EDF0E51A0FE588921AC29B013178DA30184059E1FFFEEC8AEC822EBEBC9EE48663C54274FB3F64B9EAC99B9FB4D773B1170E71CE917C411A7FA75DD3FABD1426E1A19B1C314002FF8247129D94B613D48D7E9734192404D7E0B631306D0EB588B05DDC84E8B1FE1057FF4A515A6C2F2303A1605525980103266DC3644C60CA5FAAD249046AB514E9D8C3B7B05C8ED87A151F11B31F905D5A84ED390151FB20528EDD76AB03A31B03C0EF623444F23F76484BF5E8473DFCD87C184518D8047E82EF99A661121429AA69DDC24EF9E3432E58D9DD516878CE37F7DE8CE7627BC15620B9AB0381284310EB491434E3DC80A7A5A9929F090EDF8E36BC150F3BD30FAE031F4695AAEDFD2DF8933E8CE53AAE2A45DD2A1578994A3A3730E4A79C23FA0565EAC7694CB3D0ED16881DDF6793DF4EBF8513052E4AD58EF1D7B23002376549FD9353FF8A88CEB557C42DF98F8B498AEA3C3CF53EFA23CA4ECF79FF6620976AD5F28948C65C8303FF58177BEDB1235EEAE7F855E464E8CFD870033711EAC7DA01BE53CD28ECB41F753E08DE7C8AE4FF7B629381EB96832AAE8DF28496F8268F011FD3F179B8CADC9C127271350FC32C9EC96540976387BE24B6558380345E9F377D3BA6AA3FC2CC8C07ACAAFACD5DBAF4C0858BB59ABF9BEFAC7F2A2F6D30583A0EE0773CF6E365E5BCE8211620B0C1B176B7D26C327C8FB677EDBB40E7105D5C721726D10F185A993AA89103036EFB0A43A86BDEC655637D3BB6C50D094A61054668F185E6DC78B2C64E62018A846367591C8EF3194749A85F9E43F2B9AB3F11F9249EB18E79D050F695DE8F2CF41A8F1661FB930644621E1FA029B61CA4B7A8662801A62D2524A91359531B1C6497470280819FE277EA0F9544E2C4D531342D93A1DA6BD2F55DD87374B0F2E1C222893E3D1E9AFFB3E0B57DFD65937FB4CC3853771E23BBEFFD59FF6FE6F3E5F796FFB4790DD6E5FDAD26BCC966C632D57902DD1C2F61562AA986EB33A6016F33E77F261FCE479B2F502A469D603B5A982D4BA3E345D16B1064D5550D1EB2E856F7D7C07D726B2890B245A7A32190A14B70106A368A87770E7AAB5487EA6292FE1CDC2A85FC9C42AE3B2AFB9E7EFDC24BCB60A4A91D5295D47C5C007C178EF842F0A585D022808978AF9CEF5CEA69C2142C4AF60B13A234093A738DA5EEF194A0EBBAE1F91CA788B180CE09D9C464FF5E4308B1620D3B6D20A692950F5A58747AAE8CE26EC2C3DD2E5EF29B4C0D98659312D47E35F2DB04E6FEF7E94255DD562AC8A87F4B88D07E42CBDB01EEE4077BBC6D256132D79818DB9F99E2E1D48BFCEB857C27B239734B1D4138A38AB484EF9C50B2961641B2EEC0C29E15E348D13E1FDA9CEBB799A1E68DD8E68C50C6D2668BB5FBEBC1F26B010C9C5E2F705A115447B3F4C09F7A6AC0F6D814658FD7872AE0873B7A3D06AC297803F063EFB0BF2AF4EFCE352A1D07FC0B3852264882AA49EBC13A68BEB400FA77724459B6328FE6438F43B9CBCE9A000381E04E7EA31A02D130D9BFA2B760619C3F074C0D01EE2C5961DF5E28B102046896AC22C1ABCEA60530B0F7F3BBC6409B99A6919D5AFBAC30322369150C25A94B0677FFA84B6A2C832B2CC0EF73F18444FC53AC70835A9459C7A6779E2FDC01C08E9E359A3FF0A4D354E7D359A0B8678162DC3222A33AB4CB2DC0979F45AF56F804FF1FED2920C0BBA5046E42799C79AE149FC354E4CFABC836246C3AF83174D2904ABB8F06494EED270EF6FF68F3771AFFA95CC0ABB891C9A5FF166A8F2BCF89F49B3DE769B4F65C724BC47375781CCF1DCDC63C8FEAF0F7BC188DD1F34EDB2DCF47D3DBD6DFA5DE64909601E93D20AD03A47588F419207D8648DB00D236A41522FDE6817060CA3D85F8FB3C7A06D5A58C5B9548FEC467CBB5E2188574C372BB87B33E4A7F4EC02DC67E66227223AC8F3105ED559566D11670B3CD6FE1690B426AE523FBA25F86A08DE985D08BC1B5EF07B86B63C39F2DDF8381ADE564B2D5A71812663094633683849B3596CDEA9AFE9EC1716BFEEE46F46C2C53879CE87FE4CDB689D9EA430AE837FE3E2293CD1C1C854BF737EBA7FF4EB578275C66E240850078CD855C6FE6E17EAAE74AACD9C5450861664314B6C307F0B8D759A16BF29F987876A1415FC04851F0867195E7B7975C0E0C0E1804BEEF90B395C2E47696B25ACF3C737FF98892B180CECDF513C6741C10F85B3A6483694F9EB6476A27ACAB87B1C7E2E24557C8687FB223AE6AFE6FFFAD1F99F054D97CAC021D4233CBF21B03AD9FF0FC9B9AB31B5EF934AAD2527167BF85643C57061023C3C0709841E1FF40040562DCBEFF1FEF6BFF685F34B854B3AF0D2B9CCCD75324F5FDFCB3A4B4CD8FD6D8F92F0D410A80D097A044DFDC705B9080825403835C7EF295A984703388ACA4B542CB0EF27253B21D12C92228168DD59E314F3ED39F01F45DC69F07E7CA2E0689C49341B37F157F4946A1DF46C978318661F1E59DDB7DBB1C2B470C7B37BDFE6B671DAA5A277ECD96D6F7AF989D1C8D08A3B4CF7FED4ED15DD858DB2086C47B0CD83A285F3B02704898E9C8E964D9586FF6FAEFB218080678838743DCF2F23E3DA7622BEF07A93F62587113B06D7D2BD2FE33C11BC5BF9E31FC179F507EC12CC7E2C08C39BDB321A8E768ABEAC31698AB10BDEF5531622E2FF39DD704229BEC677BCA4D032EA76AC11899ACC4827FD8583D31E9650F18B80599BAFEB3DE6712F253143BA0A21F95318F8586A933A0EB31B1B471832357480E0D97624B2A29EB6F1D0E2AD8253B8EE997A2E63A0342223D3E6D1871ECDBCF29FF2819667EE525033AE0C557817AA2960FDC46978B0DFE4B349F10DAC0E5E4E7C106CE95F742CE7186A14BDADCB9A7A5F0363E4B1DAB0444F247E825E0363ABF504DF84CBE58CB692D6096F74BB6AF99E6807F4D039B24EF43D1BE2A54B37EE2259D30E063F6CA8B80F9A6908A5CE2AEC330FBECCB3EA0CB35F717F16AB93F439A0AE2E5DB31959173BEF302A404AA9E12A16E08010CF0EA0391DA1BCB2FC3F347611018473044D3EED07DDBA7D42F31828BDF8AA1A77A867331095691E379D744E1FE2BEB2E75DBC45DC8CAA6B00AC85D6E7A9AFDBA284F0AD6B269A4FEE73FB61BCE4734933BF279A6DB4373BB928CFD43B8A12F10F6C888CBBB3B5D556E4E7816DBEA0F038E7A4DA0E6E3B2C267DBE67058975326BC0B3CC2976511BE80728CA9067BBB1F44B8171718C7D75409300806066471868706CD632AE5EC1120833B7F691FBB2434057CAFF986B49453F6C77504C48A5823EFE43E28B8859DC57484271C12DA9E4E19CB39DF9087CB598604938C0EB971D7DEC66C06A98B17017D16D75B9202B768C87FF0BB4EE58BBA477260D8FC6317F1407564B8533B9B323F6B4434A625BE473C05DC42240D58885CED8457EDF96EA74A78AF54F3D5CA180CF6B99AFF82660EE0105D327E429F1722A36F5A8AB4B4485850A70D7C0AF1643F541D150281C417C945FD55FD8DA97386E17DF5DF0457FB4303F73387DE7693DB1621F0F6D477CAFF3B0CCFC3A3ED7CCACF1845AB74C4C3F82A02DA4340559EE0AA6B60BED2006893D18058DE3F31DC22C73B80270126D58BAEFAE08292FF64FC68255A89B32411BB4EB8207E2DD27ED37B784AA31451AB069C998F55C07DB7760091AFAAEEC8A814E2488BCB525C62A3874303577D04626C4697BB09625A3FD4747D008234535EA5FC014CAA8C1B37C233FD80AE0BF55A05CC5E451DF8F477E36BD009AC193E5C227D73C2C0D23C6156FE8D826E0FD0F73A938C0CE4C8876C6E0BEE0CF96D6BA94554D8EA541612EAC9093AF9D9AFA9298522685DFF4A04ACD6516DB6298BED5D6E8630E43705974CD3478EFD4808F0ADA3558CF027F2BFC367E69387F486C25D5F6775DEC1F5FCDF151F1B2DB3AFCDAEFD217872DDA3158794DFBFAF379C8DF3AF8B89A31AAB3593F23475571E38E0E9938AEFE8667A86F6C693A2F9174FF6A3B07300FF7E1AC2714F3C6F30CF4F37FCC59AD602B1C6BDFA6EC45A7866D6C56A2BACDA2EE864BE72D686A5C0A3EDE496FC02F29576286EDD69BC876F819E8418EC302B8AD55172F4E2A1EEFEEA77A1566DC03FD9893A15F2D307B5817DB0C3E47F1071808BC20E1483718700EEC3F67F6B3D3583A02F60BF4848EFFED62EAA0371CB15BA1E65E240C0803682DEEAF77824A368AF35BB7A9F5F156052FFD455564E9FD298CC5DB60F7EC88CDFAE56B6F2803CDC844B05B797E56EA72F009023CCF4F2F7AFFEF99159731A94118C9BC0079DBD4B6BAD1CB144E657A3FC190C675AD18990C6A6B4D8D04E21AB8E976A0547A19C2FD291F9DB7CDF3B461125B9ADE2AED1CDAD29E63110FD5C790ED4293B1FA0D74ADA1B87FFA6E623BD8AFD00B0E55A613D26EB6621D70A62801FE211826C7C5546B9322AC842A970C37C667BE17C3863B6DF7632865A2EF9CC01F8D42B1386982E1BAA0D74A1CC734354A9BA9EFBCE828EAA403FB4AE30E6E6E2B4A46D838454E5DAEE4F89DDC100FD154F146FF88AA62CAD6582F86F531333A38DD84F6FD5DD20817D6940C9A0FFAB83539B1916D94BFAC7BEA30EA0DC62567BAAB4DE03EB7BA14F8F9CC944F3175F2C488D4319C2829994BD65A2F950685AA5320C1668793CF7AEB7BE96B437FA36664989A128F536C9082D0C4D4A8637F1E303B0681B8143FBD07D2E7F603957CA3A4F157F2926BC86B4BAF5EA54A4559BB4B30B991F04030281402050010773E136304CC1EA34C9D1D5C37717D0A1FC9BEF5155BFF0B302D777FC371924AA4D877FE1AEA7E93A1545F3441ABF7191824CDD6B6D9E00F1A180931B551BE1945B22CE407A6C6CDC8AF14091F0DB4D8FD7649E37F3C4AFD811EC08733866EBCF6698DCA56C46884C822427B389C60DB9B4BA8D94BEA3E0F481BBE02B98F8AC75A023A1643DB6DDE1C4A103468AA851D9FA24FF071B061574D42F8369167AB78C1C6C6370259B1D1DA38A873B0373AA3425B048A19E355365DC75F2846388F501C2232B9EF8BE1FF97ACADFD1100DC7CECB97FE0A1E3D5A0141E0F8D4C6146342F836F54379BE0508A662348DA39E6B2D1F2F3259457B8A6E6250CD3B6BC09B4BFFE02CDEE7403E52E4E5D99C33E3DF4A223BBE2EDC7A9E8E1607C318B044241AEBD010F7AAD4D6518D5B1B912E1C207216E22F168B22591A1044DC38C9F85107097D0460ABB1B9959CB9F113D5703A59181C7FCBA9A21D779C13EC02410D023445834CF72FA63E2CAEB5249A6A1C7BFA7EBBDE131BC6B386ADC0420A598C37779A2BCFF5C5E0F23D1445CED0466C8EE95A5F73C9702986D3640BFFEC0120C498BE940927CC0902A9607D83F2B7446E441043926EF4FE3F9AAB3202D21FBE314EECEFB33AD2B72EEEC85BBC7E68016760C48F3E51021F3921390349D7AF6C1D2024EFBA14696B1A044E9358BCD474034C1E6644994B86471C4CCD9A5F1884D5B9D2A1B04C4906DA482F0A8E173DC6EAE92249072F9C29E1C5601BDDD9EAFBD8367830B2C9E73B7385632E4E0893DEF3D2D4269D6572E074A2E2E75778FDF18CFD7E3536CCA4FB16D4380115552E5C80436F9F3E656CB019F5F266E6C7A0ADD6BFEAFF66201404FEA00AA3FC4EADF49037B6C001EBCA01A7F96EBB167502F11D9719287BEB09D3AE06FF7586BC8A179DF5552763303E21D9DED7059730E7C41B422192CD895F203402B3C4881ACAC6E18B798F6F6B9CC7522D4CE8DBBA6EEE17A6DCE6B05374A81704C46DB93B01EB069E6A32E25EEF8237B6F15BC92F4E3DC33D76D54EB43ED37360741D72AAE92FEBCA2A329BABD67DD8DEFF5A7932F3CE453483BE6F80D5669907FDEDA65B4EB95E02FA5145D3B4D7675436F95E059F115BB9F50413CE07F08BFE5983302A1D3E08F3FD1610DCCB1648D857FC33A30649F2730AD3C819CD595AC9BA99C964CBD0123BA254A10730AC1179F4DCD1262817BA28F705B8D819EA76EB43CF6320CCDFBFBEF68ED05BA12E91D816F62E4F48DFC85BF0E55F5A1DAAB27D6919A3FAD9A336F8CD28A9793F0153427BB04687390D428231FF8B8CBF80487585919E99B51884059AE64B18B0DB14BDFE0173A06445824954E1632D717667F9F78B86589F142FBFD41F5243ECA6D55A3FE685A13ECEBC7612D97125BE86156858A96DD194517D1DD88636F3050402814044CFB3D4435FD3A9FD38FC90FB80644B90C90E902BAD70F77835AD9B2330D003804020108E12AA2A58834B5F0104030283C010102CA8080A49ED5614E20D9D3D5158C1F6A9909D23E972202D3DC73CB66AE7A5AAFC1917964B9EE612FC3FF391205C9DF4B4189C77FE13EE7280EA2735B25814EC5D7A1308046274F1D60B0781402026546C8B8F8F8F67CD648CB16E29DB0C8628D780A249F035069D68B3D8C2FF0EBEE9F62EDE7A4FC47FEDFD7E32403158AA6DF73DA066C27DDF16C2A73F9114D9C96A50FB3FC621A70246198A7BB1B3E4A2F8ABE66637D3F7CF9F0141BCCB532F99602CDDA595CFC41973FAF84F996F00EF54F50820282EF1E6C7C7C7EBCD64F246A9BCD29DA0424F0C0B3809EA859323F113F17A9F8F0548F449ECCF84BD967E6B4A397C6D45D42DFDB24936F4E52BB6A8AAF4BAEBC987A522512626D6CE4D6F84FC2CB10DB6CF5389012D968B9D4E789C1CCF3FA43966321EDE1621767B6871CADADBE6A9B54A611B18FDDF9E1486D344FC747B180149BDCF9383113DB05212E46D7EEBEF6E71D188ADE5E9E3C3350A397CFDE4235F5C49F311FDE9576F07077244F095F9EE41D52621BD0F0C6ABBA5715685ED83F03282463B17277EE40E2BBE34042F538DEC12C43B745303332A2B7663D14C826B20ACA43B4CEBB299AF4FC47FADDBD511F6A818CAF056159F8F506299AD7A1A406710950D8BAAF31A212BFADB00A30CD06AF27C1157DF634FF547E095F22E6FFE3376259D789ABB207BDAEE54FA1F7BE226694D042FA4E45AC3346B0D03E1807104DC8DC0D466F7E1B8FDF93F5FFFFAFBDC1C74A13F538D7779483BC44157F80044F9F39DDF328F4114F5174AC15A07F9F008F1F75F7DC8BF43827D79FF2ABC96D22BE83A93BCB21D05E5BAC0104054A944D178B73A410D48AEAB00FC18464DD757DCEBC96C056080A8B7C249655DE2BBFA64C51B5E91D22A72735B2E8EFEC60DBF3991AD0DE56B1AE0013B422F956530171CC5EF2C4227B89ED9002B8E8489A7DBB266DBD328D575E5B85F8FAA9EBFBFBF7360CEFD7CA5692C41D6E7F49161792934793792EB4298AF6534D5AE8C5FE2ECDB2D644FA9AA3A65D275286240B3700A28E242239D11562C735DB231CFED86849E531F9909997F1122797FC276C272BD6E02CE156E23C1342F8C6912DB85FD08A592E3F5AA0A9DCF4C5A4E830D278E863F76095F4DD72DBA5D7AD2F8AC6DD7A64C3349275EE3591E7B7FDCAEA7A0D9ADEE0D6E3F96D774BF2EAE5CF09C335122249AF57582A71750BBE4B2FF4B9C0EE79FC4E65DE148E0537C01BCFA76519C1D633F606376D20C044761BBEB439379A2E439B2D926989E17533F77E1A88604581B937CCFF8B92D3DC4002758BAC5F1742355CE3D4FB625687EBE4E384E55E185AA9DCEAEA60443D9C868004510B32279DA97104540895B17911C9E359302932935382E5A01926C33C0940C7B19DABBF04FADFB8BF9025E426901F2DBB954F7AF07EA5EB4D3FA042153085BFAC63CAB11C45E4AA5BFF67F9A833DE5EE4BC77158A1A53C4CDE97F6F568B2BC65B4BDC9C127C7B4848FEE8074CDE95951FC45D13E92BE1BEE1A084C28D19966F9F9F9CFED2BEA2EC90CD69F88404EC5F7823ED65CEE2B178D95FD89B5026DDDBCD85097FC17839AA060D3D4C725FDC6293AC35D13B5D916C51DF7D566E3EF4E873979FADE80675119D5040A71D2D77FAFBF732DF09999395868E02BEABD1EA6878754C92A1EC096C1B40E6280E1FBB90DCBCC2B52A1CDF1C428DC688CE1535681BF93EF66858B05C87C98402EE01CBFF74A18FA38C81D18B8158DC4D3C982FB40E3CD197CFB272724450E2E379A79A494D91C500B526F082AD9DB82A6703D3E4A120D92109C7E8ECA755FAAA186CA913A9E8816407E95FA6D09E9BA5BC701ADD18169013E8088F33FE5FA409D0643D281FE20111BE46358262ACAD7E6FC0AE3115D459C3530C3061C850D67ABE15C6613A64676D2008003DCE1056932EC9EAD09C0BEBFCA714ECB409E9FAE3D5DB09FEC110850B50C625E2D23F206573AF7B4ACEF9E825B3E27648C1CA190CE92BC1C9BEBB7D7C37477FBDDB23BBABDB02FCFB15102311B1DBD15B18F0A0288047F0747C3936B935576023B1C5A758F018F6B24FB75F38CC45BE131B04AC1A1D47CD835BB2D82F27FA35F99E42E1E5683998671F6AEC3456F5DF3AD1AFE573749B012FDD4C1CCA0D100A6E83A31607BF635DD92E387B9346F0308E802AD1EF7EA61004674B3E501C6EBF1D37B37B1C29B908CAEEDE002E9B48753267A88055CD81802716E130698F35AF21C89F4260B7FB2D5A59D04F2DCBE798680F6502A01D9D692122175083DC524DE32CE2F0DCC6A1FB825D107FD335A5E456E083C1327918647B8FFA6771280F6BA0F14852CB37010D92E765665533006B6232D80816A20E5E42081CF34192EEF7D2322B7892AB7FEEB2F0F875FADDE1994E12DAE48000EEB88287CD45FDD518DB8AF9A4A0A017F285B3CE3D6B76B0765509038CC3B57616D813F0139C03B7CA3B145183AC4F0EBF574F2DBCEAB81BD2A30FAA6F50796CE1B55C5D310E50A6EF4C686B6070F658745AA53CB347A8CE9173EAA70FB46F4DF6BCFE98D9F5FC7A6716BB55635DBCA4272DFD939CD989D5EE176000AD883875231FE06D97E7E14F2BCCEC4F78A2C2B2BE9071C6E490BEBE1375C4F1A16C9A96E58DDB3D54E682116980D365183C3727BFD4F1D8660D8E8EE54A4BBE727DB30725FD748A906D7B6560D7CF2F1FEA7AC34C840A0D77939AAB8379A7348C979B66080C2366E5B501CB9A1CDFE61B8A12F30EC91F52289F9979B272C3B4BD37A56D6D8C9D52623A6211677B218799A02279A450C19A9F0A45CC34B7255B994A9DDC51A102F4A110DCC94D5158E144F4881E9385BF21B35E824249A65DB321482225D4160AF771FD26B80DD477D425DAE2F45A66A8772923C76CF4B06F4C33C09018F4C7058A7CBA75F2B382CBA018BBBC1287D4845FA35219ABD497B2743F138AC063E3877052DDB865CB8F31F1F14D806AE09931B03F74EFDED90D722F68EB20739A474AE3F5293FEE22EC92E6288A3DC94C19E41AD5B10215CF39C8E7301FEE5E2286F75B1FD8213AF6C4DC143D2430C80F4C8169F99BA775479C0664F6A81DF61E27A64D44CC45D42A6B51B93D19EBB01D0A2FFE00812EBC11AAD7EE9729CFFA4512003D56027EAACB4A31AAAF6BF45280354CFBA5AAD78F41000C9F86BB7C8E0479992D8921D1E636E68114DCB825B7AF29F8350BD304BE4F503AD3EB2674D4283A6DCA5A9F153F301AFF379041B44F35B002B89E5FB27EBF7F3D5CA655AD79F5FF691D0CACBDC8AD8A38F3E30DEE5AD26B8614DBD9C97502AB2AB0D58CDAA4B1E372325E1658BCD7C944FA84E32926BED84712C5F6B96B1DB10B4EB886834CDD5C38CABCF95E1A6F701B49CEE54728726F62DDA1FEA29082138EC245F73090AABEEA468970A7917660B179E59A7D11FB1E5039D6F96C232F3FB990FF5C90915420323536308A6575D7C2B275BEF506E4B038ED7C7BACA2BE30144D4BFBBFC75ADF4610C1D263D5264F01424297D71CEBC947ADB86B36CD10ECF309BBB033A03BCCFF3C810AC831880DE597472C1449B63FBE939F37B68CA1192EC7CFC436AD98DACF341EE16F7B0152027FD659998CA7E1E875C2A5535F5A5FFA70E3848F6D689FA1F8CA1D48037EBE67240080EF4058211093EAF84781CBCF6FB812F09EF0257181D81EB3C89EAA751A84C31D6219D60B3CBF6E3698555FEBC843CAAA7B60B4DD1AAF1E29BC7733F6F3349E1E39DAC1FDD4D6EB9E4D467524C9800B68FF73F7E150CC14E6D029C63E2ABD2957EB206E920410A3155EFEA5C3C9B891823AA3B60C95B15498C2003E7EC42D8CBF02907D3D0504E14D3516CEE270E678CB024D3528609E764C773C079CC847371F13377550C2B42596B373BA68A14D68A53A7ED31EF4D73A239378E6EE15D70D0A845B10FB1D000D60FA011449B83510EE902381AE86324BA681A57A9C149C29259880C336A9F08A20744A11A6FB2AE174B8066F8A2796F5D5122100E5D0D2AC669BD37EA6F9997B9A41A2AD601A93DE5EABB5D7C56A6AE225EA176A7C9D5972FB6C4B519378431C6FED86BB61BB15472739FFAD31A3CDDB8BCD425407A8B120564216D2348D528C25DCDA24200EE035876193B117ABC4050310AA078F6B3AC9D99771FF4C686B6890469197E1B40B22DF19B121240391331EFE28951E2E55E6E186874512C5E5DA178E63BF745772EE4E196F63FA8BC6B5902FF863982C98CE6070B2AB2181ACA785714B1093B7F1A315C7E9CC42BE561309A7006D0B93ADBBD495543B66122778AECFA3C710E6277BDC6E1AD009F35B541941399A354030621BF14B7608DE2ADA3722BF5DB58B5E93BC666371E04ADD6A20FB4449CC93F678F30A1170442212F734AB321A6807256DD24F5BB359488A625AF2AE674454078DBC78E2BA529DE58F62F0E9EC7AE8B77D9C7C880B08AD3EC7879FE78B23EDF7DA0F1D0936E718A2096638414AAD16C38B74B5F17BC19EA73B509AB3118AD409FFAD5AF4321056FD3219FFF6B2106403ACFFFE91EBB7D52E848D4A3C735AD9DF2E2CFF39E59F567B88A0A55321EFC0E187F421269B8AF5EF69697456847EACB2D6672B3FE5FE16CCF58713B9E6EDD5E37ED1FDC0A7D013746C25C7B36969B29D9340B56DC8EA89F6E21965056E2169D930D35AD0A1BC2DE806512397F01482125ED32F614AE18987D20F7274BF1E1C80F116F7B55F01366B98F98D0C17854A78BF6721C9303F33DD11D01AD7E674508A9393C6870D48B4B304DD87F85DC62F36E4B4EC48D979872D9B9AB5F06BE10705EA2EC7CC1E22D66C616938C8E55C681B32396ED002446AA9B96753FFD58A6C71A8F96FA3207B9AFF5B8336B20CFB140F9384BDE830F69B06C1D41044DB2F8FBCA47162689B61827DD3DAA274EE50857C1C940E4ABC49423420A3BC2456715C2D5E87999E6B026A2451AA0F29B1B6868B8CE09798002F4262325A2518DE3A77815A604A529F5CF5A99F9EEEA4B93E82272D6F6E929C02DDA22FCCC6DEA43FB877F94696AEBABB3730B86E75F950AB2D141326FEE86687ED4E16F185B41E9C91746F6B25F7CBFB698EE7C221E26C6E85C175BFF03BC76065634B1AD25DF73275CCF42474F74DB18E8CA757D47F8F1821DF1DBEE2B5FBB08E5639BC6245469268736A06D95232E614F9CC9F21B6D60A03E2906B3700BFBF57EB903FD40E79FD7B198A3BAC8E20C7ABD26DD498FD56E1D63C0B269DAAF15D1339EBB614F6C831D4C87B2C21C6C4A39EC6F12C501EF13D666CF9386ED81425E603BEEE4FC2C890E49352B72BF73761DE9211345466B2CFA37492CA6C245421CAEC6D3763508D4052B2372281CB2A790E7997B2914D119F89114D5CBCDDAC9D65BD2C6D2DDDBD613349B1BBAE177CA86C1921DFAF794565ADB868D6CC15B457119BF9A1E03935256A4407149C1A51490981578A0ECFADFED9CBDBF6063C210F4A6EC4DF8B867F07A1D140FDA38974F77CDA8FB79C2C1402B947BD2131A01BF0BCEF453A53BDEE08BD76237C85BEF90AED8B235B2D723FA7A402AF1DD3A600F24EE3ABC297A01EA320C932D636130D41E8732BF3D618243596179875322B10E96E6EFD7C2269F81E3B8B6CDFB703F07EE75E434962E06C28163A6029B78E317977F7321BE334FB52BD8088BEB912712BDA796175FE8208D7E004DD5FAB8C2F4168DDFE433959D551ACC90346E11916CEE27ED2EF2C5F8DDE926D8584575F36A57FED71667A69D98F8709701D338DC2138AE3BA68BC67123A1A06C5F7F72F9F5E9DD824F98E481B3D1D318F3EBF7E7EE488C5BBEFF02C1687B21FDAAC977D484936CE3C59CAF1D13E5D3692B22F5EB378A5AD9B25B045A5F7F75336D4DDD8D528F2376BC16BA3A672E4B3F1D788600CC3E4B6DFD1A037BFCFBB629DBD1AAABB9D2F929280205DEA5956F04950844B6FC2B066E81BE801B2262FCA6D01C57B109D3654372C0184115D2811F4799A392C1ACD7CBD5E255CD013B70DFD875325B5A8801C6D1AE17F0CEDEFAB198CF78623E7D4737A77A628037BC434DAC95B72A25E15D0158E9FF2ECB840D3F3354B42468B35506323A87CC0A596496B7D70B99E16C0FFD83DD6A8A60C7BF4645DABE399F1B0C697968E08A60D838FBB54C60CC3D3A5A8805EC58978E19904F57CBEF037721969E43203D12508E9EFE03C6751446AC40D12D204ED76B6BBD3BA47FD25763E3C9279158775C8864E8EBE36E2DE30EBFA46CB5CA14983BFD2C0AE66FE46D7F3452773628EA9E0694153848A6A0546FBA65B2FF633076DDE27FC7C0DFDFE15D30D1D4C5437E62F97EDA06D1B7181DBAE948D08122DDB48E465674C0E2CD0A77B81892945C468CD5D880F6C9423D826648131D587CD64784263AAF47D08434216D63E6FE0CC0EEAF7E294325C2EC7088B5E025792EC174F4F134E6471C3DE3CA70D79ED1134ED18B0640693D9CC9FF914329F0DF23E02804FA96DD7129F175685A357642019344AE620907B8793D03D71B9C2F3A6519FF708452810935B033BDAD4DE217EEA63ACD62708563F876922721CD1EDBDD1FDB5A28E3F255FB083194E4B8E645A3FF4CB91941E4329FE401A46DD20DDC067676B81A94B1211E751328890654923CD9FEDBA894702004B43C7E44F72A9F106BED6F1887FC5369636AE7093A9AFCF8D171F4CA1E123370205A9F391F4685C8FF442EFA76C7A2E0352755F42155CB128AB192DF9986E5077AA4D9918A277FB505F84CD89092CB1328F533F189D3E62A107FFD1D3E567571682DFDCD39B634013336817C2FDC8AC5B3914E8792451FEF170B0402C9AA1DBA6140C7AF95D46A55FF8F6A5B1DA9E746B3BF3AF38FA155897FB3C84F829575CE7ADFE0784E3CFC29BE018AF0035349C799A34CFE413E3C630DBFB36B6EA1A63D03A0ED73267906236C7AF8503D8B95B035B2862BF13EA39BD8AFDE3AA2F5492F248B19841CE09A940981C3D22AE91AB93782B4529BC6E1DF2342AEB960A7DD5871C8E08A3CA3B8CF4C4FB724CF182A748762F337B6E52B8A7D72DDF0D0E145BE0FED4FC55040F44F700CC04FF4A7891C6DE107A9017778D2309A6347ABDFDFAC9273A0BF9863623FBE5E069E67AB60C44832279F9993969B53F7B6497EE33A15B68235E50036F6C78B91A4DFF782DBDD231CC12A4872152061D4F21972BEE45975DCAA97113AD76259EE62799C6E8B3145BE1A48FB61A3653D4E24D1D72786014E0F3414ADD39B63A4251029B74CA85EC151B1A960A6F2F9725E9957E19EB93A5C80AC856B698482E0618319EB9A3D084C55EC7DA08583DCF9490365BEB0EEDE75CD2782A8F0690FC26709E3CE73315BF9C42E050F3DC6F6BF458A94B800695D84694D49928A28067FA22A9B5C14D43D76C0EE7D91F02B9A863B1F9CD20AB458225799E4550F4DB357FA74CDBF5DD971A7BF24A7FE931FAA72264E436365CA98C9AEFCBE0D1064F8F322765D697F4730BAECFFBB24D7E0FB5BA9CD57AFFDADDF9C4D8CE9FB1DEC1E777688EC8696F625E4F64710C1CF090F44AB5A164942FCF6F3195F289E10FECBCCE64513A74EF9D94FCC753F3B2D8C6766B8627FC1F857C27F4786BEF175813CA6DF1C686AE1B4457DFEF42A02CAFA08211CB11B336BE930E8B29B2A259D71E1BFD038D1255908B1A9E1AA5DBA39B557EF714B22F7AA48D8A4875820D5E48B5FD590502B3CA9286995CFEB79537FDFD4A9276610E2FF008A563D69754010C6F18F47FBC60F95E11B10C60C8A5AE758D480BB47BC66D401AD26AD81CE5F8436592BC45022E99769012B445D1CB91F83472D4E5D5F31C285FA91E510966B8233935F7FF27E614CF9185702AA1AC58BDEB4D001B502D3F098AC332D79C38A437773931A23CD98863560CA17C2FA5D151B110DE9B70D15AB8CAFB7DA2D55D449F5D0CD67BE1AEB82F2AD50708F9ABED9FEFCBFFFB164C2669D3D2B3DBF96E92930041E821DBE2B20F29F93A2BEC4EF2AB1307570BF9FFCAD718DC187512F667C20662BDAF3618BDB5104EC9C7FFED8D8488744EFFB3F262ED52BC2B7A5D8B731E4BB285AF078A519177EC01D4E2C2648B6845835E9A73674D3D65C885F8AB2142A276A26BEBFDAB1187526F58BBCB8F0FAFC23F49AFA791D0AD71F383D14DC40BF883EB94A9E97865B97DE92013E963899868C2FF74C559A7284AC427CBF0A5E0FF563614844C2F9D0AA1AC5E67950C80314F202B92E3A2F2FD3131221D0DE40A2E12FA903141DF13848477B24419755BEF38C9377EE8409A7AA96CD1FA6E0E850382D74E48149A4395A4ACC2FB7E92556968E760F3D0C840306BA998A2DC152D73131E2C43F89BCD711BEC6D0BAAE2DED71D0957224D8B420036C78F92C2A034C49A60BEAA86BB949B7EC4AFFBD88452C74BB9E11A6988AE60AC0E12F3A2CB6C5C740C698289A3B49DD89FBA4A469FA88F7632C634C40B3849EF8B6B736F49BD559673F5756F8644B15E39A0F4DC8161F6D2993F41003849DC13640883142EDC228BCA71FB4C80D28221A97D41AF6C28A8D04D57BDB1E00EE7116F268EEF2D38245D6F899C05A8ED6BEF79897F10D4191D4FAE30E0F876104BDA57BBD525E97F86F6F920E25FAEB4C02900C1493B1A9B66B7784B87185DEF67603B400061E23F378E85D4EE5CF17CB23E43BB67235C890E12594EF495078A793D37B6C3E03B64D180167EFD499F5FE2EE5FEFA79BF04D71F39B9EFBE2AAADBF8E82D992507C06F40160BA253F6E54705D505DA510C3925C6B9B708C942A9026F29B81AD290F089845B6C3E07BB9557E84B8DB419CE790AA9396087396888563D4A0FB1C0A76672B6F5E58809B4F4CEC39D28CDA1029185EC7CE4C4A5E1AF0B563FEA6DBF03D6CD6807DC0D0C5DB24E04DFF6BE084AF1904AC8B12B20DC49D9527C33FF719A099B674524FF471C9EBFB464C17B837DC45E1D3CAA700997CB6F0031F8C9E3EAF80A5B02FD86389D1FED147EFBF02F4CC94B2EDAB7EDCD90D762BB640AD4A52AE19587C8F9B238C0DF1A7C45B67173B9DAD203ABC57028DDAE4957116E31E794A6DB973AD89679D045865081E03CB9C582942E6AB12430C360D4687D1DCA3D2FDAC81529F40D80812409995F42051843CDB52A6342522D3842387E04490F470C5832A2B559C20E8D80A035DEFCC6FFA040FC732A98B92FBE07F66CB57FD6A043E5E82B7415FDDCDE74F0ED9A9FA854ABBAC5828AF92D0B1A4390CEAD556344DE17CB3D952C88EDD5289F0155F2136BF7A8235FFBF23216B2B839227D0BF1B04165FFD3ADF1B2D81AC16667F123259D23D9CB15087812CAC8C8FA595812F1290E0912B2927490D6B1342C4E3D95EF4E19CDC6FA4FDC60E560BEBCCBBAA44D6CA2BB69BF62FD572BFA79EF4228A6AB302CD5E3508FE18B5FA3AEC36F4C909E03883C2E51527389BD823D0BDFA79BC5C9ADF02DDC769FB20539410306EDFA69E287BF0071FD573C1D2B4AB6072EE21CD478F456DB8B0C1F4C72C5051271B60EFB246F73F84C6827C27CAEE18370BB082A37A5BCA57223D8B073A6B6C1E08D5FB07610F55C72AA39066BF0B5AF66BE72413283D5A3A5BC2E905AA7757E5C27F9D412582CCE90AB016A5C3408D70DEF72E57B45A46879F0340426E8329F3E4DE3B9F8972B7953B48ED4FC57C241847C9BE0E7986EB0B8850F3B16212A4362105888C89D9100C9278988E9F9E7937174A47CA3D72921D6DDB5ABEFD78F386A8B29753BF30CADB90664AABEC2B0B7DFD9D2DFBEBCC975099720D6F8D21FC04BD6A4E17DD589DE644A220B2A435CE089042953FFEA4208840B13B45B13BFF258A3C8661F48F18DBA2C52C6A321440AEB18492B02E0EF93C55FFE835D651DA5AFE87C5F3EEA38B507952FC0B136A5FDDB42ABDEAA04574FDC6A98AA8B95F8E86801FBAADFC4B6C4287315CDB5C7505415A75EB9397C670C1A7E9732F4C99A4033511655AB50250CDDB598B84F24F6515234AC34D704344FDB93405B8DFAC6FD81ABD888B09B393F258A2069ECC864A8BE9505F45C5469A4B48B943AB53B800B1F134AD2CA12E9D65E57C85AC877CB74E87864EE9778D081CEA6B382C690335560E35294E7D4AB09E6E3C60B15317522360B9DEF68A966DF0D25AEE4C7587CAC2FC1593B91CEE2D2A1029807F10ECBD422AB14FBD7D2B32189E8E91FCBA042FC7EE0F9D9103FAD6DB41589EBF51AB31C76D4E6166FB4A03B70460DEEE7B93E7241F9AC7F644DCFDDC8C488FD48B6F9C6D98DCA28BC057FF72A67D7C4470F22220CF917C7ECD1F024B188E675FC422E395B8940D93DCA3A67CF2227E533D9F9F13ED01D72E144C79BBDE746CD794DC3B815B0642838B656EDA7AA7A1310742492A989A7EEEE5014E592FD83D5FD0DBBB816D75ACDB586E61B0A1DB94A191CC0DA64B108F9982BB042879B04975111ACC50E83B84160E807261A2671E98123C938FD911B5EBA644BB3F655F5FD4B31DB6A1352B48D630597B7FE50FD0278F3E40F8677FA540BD12DA0EE511E253F59DBA0EEDC55AB2F825F783C0E4EB3277130009F56ADF35975FEACBC51E5ED7C553898994DDAD39FDB118655070666FF86A87F619BAF9E1168792CAE9178630842527D82B7FA1115B9B57E96DF6B72D083C9E55B70CB7A021CF1C8C7DA652CA31EE36AA35EFF34E28B283D923C33D1EA8935F8A0564DF8D3A85CFA0C18586B26CDBAE3DAE797A91053B74C246052C1803A7CC2286D7E7A31CC963B5B617FA6EEAA22D2321363D3DE84CF965DD1B4AD75ACCB0FB73A23695A238FDD65D35664E99DF02E7074A93646BF2A21A5C0404A4620DEAFA0CB2267424B075C2E48E6EB4D3FA7C5C24DDDA4727C6D4582BE70C8A9EF9703E8D80A27C5A1CC2C8B94AF3324F0F086A47EFB95415AFF6B7085BE145518B0FA794C1A5240DF63F6DD20DA9C23D295A0AD8586C4D83E7403A0F97EC6E7A1C723C378435F60DC23D1CA776A3627EDD0643CCB9EC9972283FE1F9551BA27ED41996407E15D30D04B63D43B99BA0695E2D7C05DED68141D136443DDE9B9857D4C950F1F55E826E690BF078FF833629A7D8EF796A1457A7DC951B32B2B3545D42CB047089EE7E71DD23A3C064D8088108F9022059A3A691DEA3AE61DF67528D49889ED4BE2EAD5780F4E2BEA671471FF3E3187CF455749640CE6F773CCE22876B7960A2D3B71AAE0CAF37CB707E4D8F24490071EE458E65BBD9478629C87CFFB888DC328EE2A49224CFF7C8BE6A50ADC77FCA5BA66454255FC9B0D228A078DF09FDD2E3324262C20553374A459D63959C2D2C679B85607960A59DC08106FBED44FB3C7E8AB878E9F74F9371252B6F2001810FB41A234659C8F21629A58C07A64CF086F4ACB9EF2294A137AD9314FD6B0C700907EE35FB0B6769D5919299483A943AB18EFF8FC8F3DFBBFE2EABADF2C5CEBB7BBED5CB2D56A6238E37BB49894303ECB4E85EBD1BBE366658E55D0AE91ECBC78157D745B2318930A53644BBC436E262BA6D46A047696679FEDF8C64458E66E2ED9FD87984C2494B165D21863D865A9FC0F1EDB665F91FA1091290611098CD44FD5FC5AB4F79EA65C650A045295C15CA66055964727EA53C01FD64A4CCEF9852CEF13FD034BD5735C99830923494874900C919EC0EDB78509AA204677ED28DD834776E78D3FC1E5F68CC7C9C2F6DC36B88FD2516F7FFD0127FD14DE38E01618C4F1071F2175C359DC0FB5DC335BF4EFFF0815F02A702AC22A10153815907EACDE0F9F83554EF3E8F0E44D6FF308A8592458C22C126C111A098FA8170FF70704D70B82F3E2508844041BC6C2C98220262016C3028800084C22CD41ED4BC1C025154718D07D0EFF8189CAF50C1B3063100FAE0AD1D054E59CA655810B53C5318F00CC2328548473A4B9C63F148EAB4F4A6DA0FE2026D1287D09EB0FBF6B04D898FEF74F5D700488C53006661404E3CB21178D8D8606A35D0AA300826C82C07D20B086265CBBAD7F5A148E0541EFF1EDD683A3E17E79CB9A47002A7026D1362CCC71E61160156115188B1C05484D74AA84391FF4490697238DE5E8DE3EEAA7318AFDAB27D6FAFA80FFE1AB7DA2AB493405096CEC323E16C23963F98F7BBA4FF79110C024DAB39A339726024406C30831890E6F64BA578DCEADF10B678240BB2E45170360A0E00F62BD4FC3D7FBEA0BBF5789E3EEFAB4B6842A4EF2CA1A06BAE7B9038EF17800396B0EC4BEC197D425C666BCD2DFB71778FA15263B9FCE546C961E254DEFB73AB325409FE3228DEE8C7D006DA2B87F496495BF1512C3E83E7CE7EBC3CEE43A9F387A8481D10B2F46828540252CAD85A51976F641702AE6ACDB3030A061903148077C0FBEDFEED5975E0A086E824862A81E7C4795BF7AD17DFE1A2E83F2ADACEF8DFC74FF077AE000806D6D9123F64DC6AF462A8D676AFD414C5C6C084B848924F2615EB651BE64AA11FEF238672345730E22D8DFB54F65646B609C8417F0ADC717E4046DE75BC0183A9E1F489C6B210628974A9EA9B3FF35386D01BBE481FDF574EC0FDAF22CA5FC52B89E4F53D8F8B02C60B8E62D2BB1EE2EAABCC200508F919894A42365CAF7FE29CFDA6B95BD3A8549828D9FDEE3818B915B9A1A924EBDED01D7AE5A14F9BF1EC6001C6FA5FDCB267C025B5C8DABA5DB92D1A4302D16456EF6B3F5AA171D33A98CEA80DB394582A429602D5859453E9B4B2C68468DC876CC51DC54E787B5D386AAFE8D3E1B468672000DD0ECB86DCC6194258917C995536F7B4832655AE23CF9544626DD27CA8B6BEC1B05522DF77E5696DEA46B89A80DDBEF49164CDF596A25004A75D16C58C2DD4A9306C84CF2125FC91A5B06FB2CE52F39ADD3EEBF9C0AB772546E7AA3ED2B0BC23C19783A5C346A8B92CF3F25D4CA83568B3307C744B6CA79020BCF98D9998DDED3FBA8A1DC26CE7E51CD989FD63B8FF85463CE8C0E563D4C97AC6086A4081F4CCDA2B81A756FFD31B0CFAE3C7BA7ACBB8690C3631F55A3332270CB57D509D129DC9AE73130D180B801C16E3D30900130702EEEB91C3B40F7226363D55F4BEDC88E22AF7F38B3E734072AA6558DE1950603EC8F3762BD9BA03ADFE2E5ACB826DBF434C2298E86054668ABC123293A2BB7641785DFED603EA4E273231A903814668BC6E0C0404CD84E4D3DC40015766F1BCF974B222D6067AE6E72718ACFF5D30C16351752111DDF2F17C23B5A00476BB6E19E54A39385959DD710FD1E5F6B5EB63069AA6A6BC1AE4D192DEB0E11F8E2755DF0F962B8203088011ABF0F2A9CB563DA0F570ED02BF4CA0AEA5E199C25F66611360801497D44295C67C5692116E8C8C923E1601FB631C2B6AF7B64A3D0CC87E7253D26E819BE9BBD269FE7D7250794D7BE5188DC5EE06FBCFDF512783009777F47253767A94FCCD3E46F9F68FA230E7F70FA2C47179BEB9CB5DFFA92E37090F05EE312F67528D2189E58CBA6AD2AB4B2D5E29C43EB1AEFDEA4D6AAF10D5114B0366DBD4750D278FF862D7ADB72D6180B013A87E996ED65DF4219A2131712F4CF61321D5B14BA68B28D7CF323F81ADEC74A88A0000417E88F75AADC58BA409501E48890D743384033914AD08A6A356833121E818D67374F6BD039E5EB9535E6DF473CEA96EB380648A9381C14EAA27C894B54B3A2DDF867596903FABB52E2DF91E8F043E523D4F71561E7B8F4009271222CE810C458BD10E4EE81DD0B03AD2D96541F8347E5462FB38C1907E456B59CD762BA24B846D5BC14A03279F8C71DF4AFB21B70F34851C07B3C4B573B7CD99DF4FEA537A597188364CBD64CDE2033FA371BE2087F44FE2CC757369FF3A95A2A8DE04C817D1D9A50EAFBD929C6883D6DDD4EFEF4169E3054F5CD599CB1F39670210F2A4A223B1ADA550770BB10F8D098A90F97131D1779F0E6B5E7B8259A169C4F9A10DE96C4BEF27A3F200CB01F2AF2F7D6AA17AFAC8618277E6F1427A05F7E713E57EC7329C6DFCFD9E409FD281F1717EBCFE5FA2DCD2C6A624BC082B142B2C8C6ACFFAD543B2734FAD8A718C21721464184140FE27C66A191C133CD11D885E405C9DF2889367A9BD07642060B85040DFB9F5348176D25C56BC99F849F1271BBD258FDFA3BB6B3AFA4C7F57249F915F8AC25C9CA2126BE6AE827F9E505D1347D5A112900CA934ACB2EBCF6C98EB2AEEA642C7E46E4312791DAD3AD64904EC03D07ED7204FC11FEB31C4D6C8E10B0FE363231A803E646572B1310807D1D8AB5272B6558AD37E82116703B125015E9C5920C0E6FFBC29F78EA89F4C211A2F143497C5DE90B3976EA8827C003BB28231AEFB84C2FE0735DB81271DF3115842E8F387F23096914130C955B868D937CDA0C0F8D46AF471F40E2A33114C0CDA70EE4B33790AEDB969D1DD2ED5BB7825524A7C212C3FB5170E0831CAEE70830E10CD73E5E12A09473CDFC21FDC5A0C41C92C59313411E3583C9B29CBDCD212ED5602897D83C890B03887076817B2610E6B464D35CFFB7D4355670DCD471056092AD75E9E061452396B3325B2CF4392A523F21CFF1B08932C5A1B84FE9C8477CC0B58EA42039D440D5048B07673B2122FFC56E0CE4DB67FF506088D3B1612D67966527A326737ADDC5F59876F8A2A3B36DFE30FF870F6851FB23BB1621D741CF1992C788F55A31FF56ACE225D4FEB7FF6B6C73D7D2F80FC145CE395141BDC3128AA231D471F783B51C174458C203CE122746AB727B8DCA3EF9787FD6D502180855CDE7291DAF5651D4D5D75E3662E97DF07A2FD09B5E9406E5E3ECB8B7BBEA01425A9548FE215FD97CFD692D72C59B89B198465C2CD3BC9CBB6B232C669D1DD4A982747BB4ECED4533493C494B7A286D888CEDB028D2D1F75B2F0E0CE5B5AC89CC348B01477853D0C48B70201A5D1DA20808110D8430E240805C1C21070413F423480C8C3E080681433E8A140B46AFD807741383E6C43C8F82389682C6592AE0C72950F166D63CD9112016BD78E813083A0982B473C847D12041F58A2171207FE2F261285E774F7173DE96AB6E3613A094350680F10F04B81961988E39ED8C87C2E1A195DF0506F1F07F1226D41E8B23BFE537809110C0209E24C23C1E966CEC9A26022422C4211F45820EAF17033E0181BF484505A15080313E7F3A82C7CC05D1D1021826D14CF372D5E048692C029368E31FABE87E4FF0EE2EFC55889175C5C0A4E0581050134874CA05C308318E0147C2927FF6C7D96D9D960B5FA6A75C42CD4952B2A0EDFF1F3619BCD8B78A6FBBB23E962B3EABD5C4A70E76F49DF70080ED85DEB3287C61E93FCFECB86041B723D813A3F4E7816F7790614105B076C8C3A9663CF43926D210F188E601FD378993538808857092905899FE336600294C23EBE3C0FE3213E694AE8E2C29077F170A323946468528E55694BA598C3366F604E6744A4020F3F282B234A070C04FBAE79B1F62B1E1C6FAF5CE7F2F9DF225DB72918A38CF099A88D4A74D13D6A8F935E3A0CFD19172D9CBE481E88C0655F092C4AFC7690D8B96344066832EC83844D8B5D9AACEACECF512018A9B9EFDEB08F6A0ACD2DE689F3DFE94C1CFCDE1985DDCB444F27F7738008CE2F0D387246A4931F3766542C417363843B3FF940250A1C85145243C953E3A015996B91D543EFE7EB52A29A8CF5F2C2DC4006B4DC8C68375FE4D2CCA6CEA9AEC7D677651FA6C42B3EB66DC9B5FE70C73696E003D82200D1AB4FDECC55A76A46F5DD447F2FE98A2F05E163AB0B3813956925DDB082F121F0C193F1ABEBF2223861526C0CFCECA7BDD51AAFA0BF1414EC44A19EC37134AA953AF9137A69170B874008487C86BC75832C0E828D7363B8647C7A3149CAE38732961E6C720954989D1402E8A9EC1E1498BF4100ED4A27F1B9484295FE8FB37B0FC2706EDB26A690EC7DCF85C4C21C0D8A6B43D321FD0FB8C20193EDE16A84143162467B4051EDB443BE60ED1E4EFEC6EF88250369825D6329BAC8173164A217582E7B4B407C71B2096BEFCFC5BCAA5B77821DA83C04D2A996B42E274296EA7640F4FF9D78B9D9A137DCA2CAB659F6446E6D0E9A8CBF75ABB77426B5ECF2BA9BBCD39462004E5938960EC746069E637DD9FD4301AEFF188339B7C0A8A2F2981CC0994F45710F7FA0E853CB7A6C298F3DF695DC9BE6490EDC21E375D0C8403A63063A99F8984C00FED3F60AB7FA415F75D6935EF11FAFEC2BB29B633684DB40268AF5EEBD107FB62B20E25361A76F17903CFD38D14B8303B163319CB0C337E2BF3AFFF2214F23C1B59D1EC39F2CBE8E6AF0A31D30303016EC739AFF154DF8428FB78ED76832A031CB712B0CFAEE27B1A27634B68D696B708F2D6081C48049569A9A652B4CFB077E91DE7AEDB9A7DAC77B6FE74E1AE6CFB6CF183CCFA8D7695E207450198C7B120F315CCA2A6F598883948FC5E9D8B044C70B1C06BAB5E6BB03CB68F06E2C220F5598008215EEAE2E1EC572893F04DF891C7AAAB16133F93B7EAD1461B99259F0D97E2C25B3CA8DCC4F33D8C22669C5D25959EBFB8C79981F3AD657069850BD3B29D585007F701F5C703CC2188ED1180D6622661925AB69CCB63D58F7CCE5232B10A8EB2C14F4974D6A95244E353EAF98B09CA89AD160B6E5E8AD26A48FDA9098FD91AEFF21EFD511681FD3E792C930DDB406BF027B4100BE08399F4296983F8ACC714509BC5FC8E9734AB5213E63C619DA74AD0343B1DA90009F9F58BA3C76D021E7A958247F163B77BC4D9CF2E29B6FEF057F1026F77E5ECD383A21443212F2879A7B80599A8F6E578542B3106CB6B89A2304087D2A4699416601D9830AA3FF4D12C3F4663A0ECFC1C4F74237A041F822F24E03E79FA95C19BA3F5B618066115B5CFC9F5434A7C95482E20247110E20308710B04E4362C2E672D117D141F4DC47A108C3F08E8EDC8A2FCA430AD5DD61D61BCC36F9E8A09066598BB36E2140452EF77FF4F6DBC66F4ED2BEBC16370273D667C4ED0AF55A73A2C6627522BD8950544B7CD0D6D88097E25C7FBD32B07D2A78524DCA69D902FB05A653FA6216738B78E064F31193B4B5DF2FB2F7BE684D47035DFA1F6DC025D50D60FBCC2B3BE85A3CD2B6316395D0371AC0B1624889B9403B68C3F6EDBDC56BEF2FEB07BB6FDCEE06A99DE52938263F5F501CC1916E1DDF7467BF643B8AAD8B0934F07B612049B0802D70C2FD951212040200E70E0A7263308B40D02B92A404AD1F822E4C0FB3574079AF21E2AC841B8390A1AEF48F1310FBB955201E26065F57F1EEBED66DC5ACB91983A5973C42975E515651E85AE09292B60EE0586BE332DC838BD7827AA01323B3E45059998E3D0F4BD5446C068936D53AE3DAB6DA14B96552AC94C589613DB6D023C0349E6DBFBEDF0CB13E167152708847D84AF82690FFEA90D560745C99B7D9581C4E73E3A0C6865AC4DD9A787A0115ABC5E2B8602E6F0A7C5AB7641D049D4DAC6703553B2248EFFB566C77A6BEE9CC55619C5C46941FFE842DEB456F7F7807FC44F93CE563C285AA3016C8AAC56B9F26678A3D19C067B31993C4A5DCAFD975F5379FAA33586C84EAAFA4D86957DA8F5F6BE54EC1C97734069927E2F6488BE0873D0CACB78D2A681370D06A39A28843FB29CCE437FCCD04DC7C84396F4DD798C1860F61BF8DA97F955FCE3B87624C7D88602A558DE0F6660D416AEFC70608A6DEA3C96EE428B90CFD333C4C26C1D54FC23CFF86DBBA9A947F0C234FD920E4099AFA977F60D81EF8C65FF3BE11B9E48A34A9AE821DDFE976960E1873AFDC897CB86B6A19FEFE777B88C37E938148FD01855953DA54A66468CE125343E218F37C11A9AFC9877932BB68507E418DF2C702FA740D17889A8CFCBE2586BFDEC2276553F7AB4366C7FD80FFF0D393EBB1269B8247D193A5948B01008FC6BD4276785BD26100C7894A21B0631AC762A72A7F410031C835E8A43DDD30916CC8F7CBF527F0D3BC0404A6F2D5857C1C20E95BB39613E014872A7CEDC2789A69F4828E0245FF1CD57D00D8FE6330A8F27FF0AF497C9240E012EB0CF0E918E8B4D35A92F92CB468648CC7D76F8AFB609378B5F5626F98310331F81D9951162EFCAABEA01FBA722126F1A3984680D677FAE9052E40075C04C75C8B9CDF3953C7AFE9F02B7AC6D71F0B55D30D14A7022C3F39F0E287C4204B6A5FDCF47A25CC4E02BF89E0632E308AE3104F923818FE712F9712F842F495F4B42CA177E7D24E05677097877EA6B9E06A8B3044D4902C730C310997C76B49CB5FE5B3626BC9315301B6C49023DA08B17D3706284F71620F6F4070BF9BAC072762F91A7677ADFD75C63D561D8C0800990911D71F616E615661D1BC8C2E8483D433CF6BE8C103ADE9A668EB5ECF9E7918437EEF1C672742CF015D60E9B295A1B032493A8C9FA6242E190CD33C51D6A451F7430035779A7D0FE35CAA5B93736B4D9DCF746F4F2F172B0D047DD83666310D4CBD6D919A46C2E2CE08842FEBCAF80036ADFE6935BB3FFF04FA7900B8B539433EBFC6DFC4CEDAEECAF838926205A5B13328BD5ADE54358F7441368A3EF59E3E86F7D0E7DD8401DFF05204967C376F28F5553490604F2FFED766DE8A36D14E4258F558370C8D3F5541EF004D0F7DAC89FAF860CAEE762FCFF6ABC6C1B84C342EC21F238FEB31908FE4CF26D1001A82F59F36457BB603A68F9848C4EABE4D585D1EA9AC9F4A2DB0DC68A4CAD2A3CFFDD05CDF6146F4CDD2CAED2A9975CF8FBF177E7150BCD5BF95EBB63FC6E7F03F6B9111E7B47B45DFA79ACAAB9491A5D68049C14B189E0195606DF8390B0ECED481870176679437985D119F2C0EB62C671F83792EE262A9B184FFD9899014965C64E1FCF82DE6214EB7AFC6561EBD6F056FB0F4F990EEFF09E5B72C0B738F77AFB3ACEB83097C97C8548ED878D3FEB134D95AA0B84A69DBDC10AF20C05AA7EEEE8FD0E7A2876450F5833A8E60FCE3FFF431CCC52353ABEF8F955ADBD31B15CCD7A7B47C8DA545A7C000CB02F8AD3CD4E7B1C0CEB5A8A5CDDF1A8A01A1E1EB8CBDBF8B2207E10F2E88561035E7AC923FCAEF2CB41CF26C2F1193FD81A57D042D4CE9E5A4D61B305D3EF3EB7804020103553A1CF49910D4955E7791B5A90DA64C9CC3EE4A60851FADBA55DA31EF6A268935918BB8497538014483A541284F1B0FDFB699A0F0978E11864E0186F3C4A465EC90AB9F57BADE4BD29D06B72F23F5FA0E8A57798A83A5CE279FEA5A23271825393A4A1537C1BA20174AE4BFBDE37224699A3EA0464E1FF94AABE4A1AC5ED704D7434AA6F3CF109A2AA6634F43922D244CEBFE48170A4C5C9C9458442D2E7DEB3FC3B6029406B9BCDCB788877D9C18959FD20239A23340B6EAA1FC39AD0698EC7D21C1BE5E8C29D44261A160486D676795620F467B21D2DE56F64DE0984EA7C5511E434A5C10D5DE617AC334909AB67FAFEBF70A535FEC5DF7D0234B8868239FD8EF2E0EFBDDF62B8B987E968F7E3D1C60EB55FDD54A2C8EACF60AD273DC40051E0BC8D2491390A5CF7437F6BADC0AFBFEFE37373DE7BA9D5180E751D47F97101CB68D12A6E8D097B0AD11079DEF4227F277B65D4954C33820A8F963A9CC91132F8A4A32E48E09A3D033DC42BED6C2007DD0DF4A400D7C52C920D2165D785E5ABF5154C790252FFF13F2F8F1D7967AAB6F15515CD68CB15E5CC765FE1BFB6122F03D39E6659B91F00EB7A62D5163545F422DA74CF405C0F332BFC2F6AA10FBBC75BC3BF2510F87B050423ABEBB3235E14A725F73F5E3E29CE856AB6B62D4AD00AC0C037116AF3D13FA050737AF3E684B33493B173B6D48F862274395CF26F3D74EF9B805FBFEDA4B35CB8E3006A84CBB3DD9D48A527E66F3B85F692B4A78737E1F1A5E244F8E60F592F111BAE037EA1436ABEDC30AA97AE56BE5A36CB2BB0B930BB4401BD5078362EE8104D86866F1D1406068115AA552D13EF52AEBEACD946C65B43E7C2EB4FE0CECF9AA7C2964DAC5F87417F0857B2BEC4EB240408FA5A14F377FE387198FC8DD94911C699DACEDC9EF4A8A330DFA8F26FEEDEA6B032EAE75DE6235BD88220E2223A9931EC44536CAADE5B25257F971EC186B607BF536649EFF4D5CF537CA65B0374684C480D1B1F36B3ED70074D2B79B645B42E44AD3F66F1BD5F3A7DF37D971F541E8D3E5EF56FE7FADD168E7CA8440835EE0E4968386FFD0EE652CD894F60422694D62FBFFD027065AD4B717C72DE36DBE0BE94FB04EB38A5111B1489FFA15B11EC9B95237DAF878B9749B76A026CCF9198F7EF90F4100B48B8B68A0B66DD98F12027C0AE75C589411B93CE76FE73B90E9818B3FF6F955C0578531DD8B45C650BE83AD021C8BFE752D39734B9EB57AE4E2B090A23489DBE8EFD65CFB1A7DF12EC9D0B655C647620BB179CDA69C8E6D037B4FC8B65BD46B0E11AFEC63C588412787883F8BB800FDF6D59D8546752F91B63EF78EC5565000CD0D93E795F5CB5FDB1FA55A049182F30D48C34DBF815C4BB194C2F8428A632DF03F81FFCD1761040AD469C9B38C82154208079DFE560C30AC0422701A5F2945C447611E9FA88D92A31D4C55B253BB5100B943C90E6B13E6AEA35B238F8D6584CC9807E8BE9131F2A91326CE7F7C79D100D0244E4E618839CA5D8E3F0C83DDB21F19E51BE05DA015F83760AB086382F4A3EC2A9448BB23C08ED963A3D1EB5783C55D5FAD47C7B514F4D92222D196029CAD75003EBCAE73D31C1EB7779354EC95142120D546E200D4483FC1ACA1AF1C93216982DB70624D523C5638A01D947DFC690DDA9900253BC0734597900731F9E51D48BC1A09992FB70AF81A3C06471F99084D41637B4C7C4027CCC149C7A13EC3ECB2294B274B674B5B6F5D4E342A9F7103EC7D563B59B1BE63146D48D45454545959C58219B9DE003B8ABEA39DDEE4128E790A820EB50494BEA227D046D0C068C1B3CBF9BD435DF5A2C110F308C71E0C0C1AF9E4E688DE5429929798C6863F03EBC5FD630D2FF993DA3A5AF03062949571E5FBE134D4C6AE1ABFE26C4B51158E2B34A64382CDDBE20997B2162546543B94762988B5B9430EA0E691B409A95220012FBF1908E8108DB538510D697E94CDCA6EC2C1A4C87748E16EFA338DFE3CEC03BDD5F098DA8D1E0F33A32BA1383C685D973DD82957EFC55D736F299437F4E2BEA87CE265D6C782B069FE4FFD3C8821F0003995D4E047C15B1D7A0B4B87F9BE673F381475E0985865E9E5681B1749EF317A700CEAE01D625DA863DE7496CA027AFD6D9F2880AED870FA19590FF6C0713377A2408040281BAEAAF9A15D34E43E435C9E736A288A57A3AE8D58995A415776EAFC61D4C928DF33E4BEDB857A604D503429D2FCB0564CDA4166469B9994A865E43260F9BFF3A51B919DC0B0A7CA6DB630562ACDC0A8BB51430C6EEA109EA6F8F02732AE82DA15AC068D7400E177FB1F51003B8C631752BB3516AB1E4F37421A96E54C2D87DE55F9DBA3B0F400891A04D8A6C020CF3868F8FE8E5C20C2DD8E37735B6E2E67BFA2371699689FB1D8234C6BFE135231C1B93C00A978B05BDACDC96366945B7108B49D6FC06B865A4562878A300C44DCB08DCD5B359E85E707E6E385D258FF9D19A3394E5ED8966540E6C16FF1A554F40D4C1C81A19A6D8A9DF5E4F5EFD0DA092CD3BBD9214A666F3FBD4C6A9AD067148FB3A2A080FAA0D2ED80CD9A165FA03C251160AA746F5827510038CB1E24122BE94FB76B9F6A5B44FB29F60D248BFF7814643FF0CDAC02B2A515B962CA8691CDAFF39D88B4CFD426D67C793E1A725EC3F982AA40C5B66B59FCCA33AB1717CD82666C490E0291DC4028AA81475D70836FB0299F39811EA572AF755340E353608639A912F653D680B65006A9F46E032CAD4D17A61D0FA8ED9E29C6878C04ECC437654B681DA2FB1BA96B4402F1356000A7981E58EAC68F68F465D4602FD972E2BEA0A6B3BAB5ED24B358781E10969DDF44830B9F83E7F69E238BC0B3AE2CB173BA8C991FC7F7406E8800B21201DFFB0E62815177D74E632069BA896DE7A4A3D9A9570041BDA2C5AE8BAAC1FD02C1CD93C2651CE67A8DD4764F4EDD5E554349D1864360CC1FBA0DF052859488BD581FEEB2CF6CDF604E4E80D914D3F8A2E26347EAAC6AE5C7874D560EF9098ADEA524581E5C3C9CACBF186E7136C1517F92AC0EAE9AD3E79645768499848BC0C73A13993855F293A6D28614E4140F39E51F01D28BB8D8513F5A77C080966467008F336185D708DCAC4E73D6019279998F7BF284FAAF4E5FC8C772360D27DA0BBA093CBC3B77FC6F7F79BA4A958DA7DAA8B1D96CB0F0B9DCFEB398DB1A9F7DBD0F417C872E8F7826C4BA999E3093D322B7AA99421360E08782864E8C4B8ECD49F02B3E8EBC53CB77C862EE6A29D88A86EA3BCEB1A08A1374747B711529F23600828B310BBC5E08B5F1A35FE01F3C6D9E1D01B4B8E84009640C3415569F8CE1C2F4B23A3B2FB53E38CB0F3C29C96C66A12BDC14093488707C3FE7C2782E60CA70252815181047FE9A598446FE0C4589944DBD066091AC51F9FFFF844EC0C624F1DBB6CAD77AAA466110906CCFB256514B7C729A7007FF7B80279A7A4792D37A1FEE1D4ADDE95140DA25FFB0413FE6EB4117FA63A31BFCD6B5A7ABAD3D17A9DA623A56335381885D0FF8E786F8A642236658030424CA26F04593655A3732B7E853341A0DAAC2203E180C1BA5D269B36A717E62ACB477688B092FE2FB8484C51D2B26E68CABF696C056889355CEAF2577116ED55D28581DE25F1A6C6A2A96A8C62FF3F1137BC4A0FFF08BBF03AAE4440B292B3EBF779C2DFBCF08A11A1102D2BE8881A1F02081488EE778C53F8D339604EC90714BC09A8721BC31F476F520B924F12106C9BF2FF568DC4127AC9F82BE212F60178206C743522E0360D93224A66DF158494A1EAAE5252D9D059256FF25A40B71DA8248A914CE11E56143899B1EB313E0DDA4780454201CFDFC94FC1F25D7395D4359FAB90C23B2BFAF141DD75E73B38AB0E5A3CE23F4D82B376700675033B42BCB386D9D0663529401703E1C0B40D8F7AB27B3FC5A61D856D289D61D99A2D4CE0A0625133A107E9450321481F40B0E94A3D2A9D45E7AAF9368455D077412F7ADD10886D40AC551618FF42C9118BA04E302E281DEB92C22A5C70A1EDC059437BBB7F3103734CF3E68F4A16F0DAAA8B1D9ED997999C1EC2F87713759A5192B9C84F6040C2175E28DBFF3AB983A36D35697B2C68152DF632F6901D9828AD2A4BB9444E592EFAE6ACAA2942FC7C4BA3E1644E864021187F88340A364BB51327C7E81B65608D11851326AB6B7A2A623D6A221F91E00F9A5D335283DF3F0112D938D87171C14CD230D22F686CA573CE6F5F8AE249116DE32986F65FD64A8A96DC1F1EF4058C15599B75E88E83310D25138AE3D55973A408697EC011576022F1323BFA090F752359511692D4435CF302A5128496093D73FE2A789C47A47CEC36EA62D7A6FD49907A5F3CE2BDBB71179CB996C9497DADA56C631A7018F203F0A38B99ED74DA1D9CC3A83AD1861EDEB8083303995471DBFB9EF54EAD65462575B14536CE0E571F0DFB88801EEDBC450C20FA1DD01548E3E7CBA2C3DFD536501A28434E2358F17C1042AF476B039A255C63C9E3EB7D7A7F7E340AE28EC91E1708E9CA41D9B4BB60ED924708CFDD58BA0A3D8951FEAFED2090AA6EFCB2FF50F37B0053CCBCF57515378C0950310DBF4DFF808F6B9C515188C3ACC075725CB70735FEA1F95345B8F0E7B63DD245F607F7DF0C4EAA5CDA0EC06873481A0E428DA78DE23BB77486C283690C7B41417D8568BDB3403C601B7FF317EF1A7E5237A8DFA404D7C6E8E8D50C05B6E371A80E30AEB794836567E2CE5D6F9F6FB4CD0AA114B1C71DFC3798C25F47ED8D7DB3470C6F45EFC17A5F7CDCA11884DC9734D5458B89B2BA7EFB6B0F33C82B7A210D7D0EE0C8F7287DCB75925FC8DC87C199D8895C85C56D4B0EF11EB44856F8AFC8EC6893C30B7C7AF32ECCACDD0DB13D0FCFF9E927ED354C9C8379F9D00353CDC897EABBA3D1C9BD6EA190E7AB5D667FF6D5E131C815C2DE45977DDAA721573D871D7949A5E16D2C2ED5F4EE1CAA28F30BEF8C004120D0E0A80F08FCA1E88542C6D3B3E503ABF63E3E3EC0BBE6D3C6A05296BA9FB643707FE403C5074C323D49B8906A01FE705BE37E3084BD5481FBFB5D0E8550420DF1DE001880B24C7E991870A38E29F943D0543437D49EEAF39C0512451D090177F1DD0F0F03CAE1AB24E69CAE7C84B46D298897E91181E5D2E41209D893D4C7B7FC995A79DE1D60DA2D6E0CAAACA784E48F43BF767D365E1EC3FA4DA8EF436CEBAE2A7F9D0E2AEDFCC05677FDDEE33E4DAC99311FBC9EB5FA29D5B1B70B08A1BB32E45097FA0C7703F56A2B2A255A8DE12242CC3196F7F69CF8C532EED40C373A345EE701AEE891416989286B36208BDDBE66C98D1F398399B3396F3CCB596C4504638C8675FE59A9BB82485B77990A3730AFFAC4B090894CEA3AE622EBD315D77240B31860D6340D04597BDDCF564D5D0F2B6DA5ED4D46B7F11EB283A523285FFCEAE9E4C860E92012A6C4951C70FC88FF4849274F9AEABC42F4D10C2BFD3C1017FDB3D9C8233C7D3AF8AB31FB2AB99E1B77C04183C0DD4F46E586E048E6C5DD2CD3E12453ADD8F0BEAEAD0DF21F4D376882D8E9545EED32605EA366F3F6D8362AAD0CA7F80DEECCAE8388FBB7ECABB5F8AB18A92E5DD07742723D0FEEC07EA1607E23100BF0CC783A2D3F6205F4B21A122DAC4773A63906236FE37F52DA33B97B21EB793B0038D5EF3AA4E742C174860572E2997FE1F8BD558227799A520C18DD707E30E5DF90EB797117EAA9871840011B521AE4879416A622F85442B9F83A5F69CDC2787AEFA3BAF4DF65CA7B7E0EC03198402547E83DE39572731422E5FFED15DD527AB478B3327AB86BE660CAA9045B679AD3E7ACD63160DBC6FF7FBB0309667759F2DF39CF7CB9753E4DABF812A3245001AC156799EE22C9CC39CA475E1BA72A88FE002B1198948EA4E253269AB6C8E6DB9F0907667B7ABB8DC49F9BAB8F0C114DAA3470E5E15AEC06A46B28EC19C8CA521296CAEC36D438FCEC8D28FB620923A4EA99D422DA3D0740C65DC554B30524A4851840A8FA49467CED90B239E9C48BAF845E92A2B5CA408EA9DC27A9263C3E24E4430AD05ACAB10D43FDBD9261539E184EFCE1E181BE567A4FE170325A5FB31F0F2F47055F19813CF86291928E604B50D79A25D58FE3256BEDAEA660F9DF893F2AB65E86DDDC6E001F77CD359D087640D96A5CC1F2FD6287D497868BF04DAD4246F60A2C398D1545FEBB550B83B136A230559B27C47EB816AB0DC0E31997881D1A0F187F5BC3099A6B90F7DAFAA46E99EEAA0183100BA316133C08E88DA046458125E56EA20E81923581C9571C6CA419DFE3B3EAED591BA9B6819F1EFEB205F22017FEACC3F594C6CB59CC02F4114C0D83DC4072C977F619479B9EFDD313B763FA37CEAC9114D722D098D3D949D09CB53C9C38508F300C6E5FA111325C3957717D364F17B60B6B49EA0F6DDA177EA3FF9485093ACA1159442EB6F2DD20822D7543CD1D1C0807D827CAC46947F89144B6C8FE65DF6CC0C6D0D5E6BD5835A4957EB965635889E505700B82FD85F0ADD1262B5E566BDC6C048261E5AC9D49601774945343BFA7C0BE8140201008041AC830981A9D949653EA83D39F70F0005E7F04667C4B98171F0ADA6CF2DD185F7E912F9AA10CA7BD90975EEF31149D31A99A9EB6D381FB033EFBF635F3D5DB5779421F60A5ADBA919730B61A6B675DECD934D6DA6A42F575F6774E55736A8F1D417EC800DC535F00332B5DC26BC4AE4F12726D230CCC5ED692C4350DF32FDF78A4F2E11003B447FF1C4E63F8EE9C9F83C066A676F33921659AC754A91FC27D4DE088B6224A0284CA585CAAA48F8966A324EC1F0ECBDC3F93D5E27F8223EABA5669C192EF3263CBBDE2D1300AA58B283253DBA675870CED757DA832BCC8D36B55186A1A222108AFCBA0BE101242095ECA16A3E7498BA0CDD546042CC8D6DF7A5FDCA2D2E8D371B7B20A02803F847A1EF270F16FFC7577238FA0A3D282E255B52E49EB7688FEFE2B66A23CA3EE04E681824FAE21CDAEFC351A31B74E229467ED7C7A45EC702B4D0C84039F9DC09B4A99163DE76C04DDCF266BF907E40F3603F6F2EDB198352AD0DB9251004E377FCF626C335BF334779A9E8FD5617004A981C733C1EE8B8D8A49507A3A1EC2F5D7E787A94097487DEF45B1D0D6B645FBC8E08336EEC2321D66D1E7928433C20DDC980A390429FA3180219EA22F7EA47A023AFC90B7C09F4C444EF26B201025418FEE3836E9152D07969705F186BE40DCA320264CD1F009CB3407E12E85BF76D7BDC34BF5BD523A7B1D8E340B73231D5E30BC0B020DB0FF19BA744871FD91CC348614D78E0E5008922DBD7E1EFEF211FEB2C2BEA14631AE3D4D7B5E64BE860FA15A58352DFE4D822964DB9AB4ECB85CA176F9E3AC6CC84B0A50E28D2CEA8AE467880C24A2C57F9BFD1F844E3B3E3B2B30D2FF633B73F1C9654600F8898253DB735515B942ADB4024F89BEAA3E2DBA32282593B12D235361EDA45E22D5EA3F68FEA2CA69FFB82CF51D1737D0CF148B9EF27B9DFF2DFC827AA479C4B78527228C6112537FFA3C9A7242C8841A076DA5882800D698057CA55515540AEC2299ADE4B2ACD915A223CE774B509E01DF66B76FFF1A52CAFA9A8626ECE0BA326C86C071E1A36E60B07BCABABB2A3F8016C0006AFE15DB0F12BC3F2E463BA73F4A15FE3523A5BC13CA59A0F1626C5A712AA08B01547F514A727CD441DFBD7ED0B84FF2BA6818E3686EDEB1D8F8FB0C12EAFE0CCE4478B0ECF31D92A18BAF3E07C16E484DBF8500A16C44B52A3F9142759EED743D6BA1B7753082EFF202723A406FF9942436DF38EB285EF609F7C95681C28D7DB032C32E3E457ABF03A07E1147B8FEFA7C6E7FE8985390D75AF9672BA96E199103A5F25F93421DE3C4ABAB223CEA0044ACB27E8D8C100CA75C3ED91F0DD2A3AB55CE56AEBF481C26FF1C16A2FC5A891EF467B0BAAA90086183708C3EDF72173A69E16DAFFBBF64F9A94FD1D8247E05AFD9F15A7C7DB6EBF2236C38BE3D7FC325EBCEF9B05F10A05EE4F97264FC41C455BF73207D76F2C431ED1F81F2446D7D49843531AB15E0465FAF9D45AC30A6EAFEA5BE6D3F57FCD8BE50B895F52E72EBA29DB9FF10C6350EBEBBC200617BA8AC4901AE6BAC7D8306024238DF99F6F20A935EEE2B036E05DE0CB2A407FA978E30D7E4E9EB39E97107F61305439E188390F16A4747EBBE839C9867E060AC23DC04267B43495C153453EC96275B08A8D4FE347D5AF921339C45627E16BBA079308C34A17DCE26AA18E613F3C788D1133698B4DA6C369EF1DA7BDDB903391E0F76E417AEF00488EBC02FD7BA53A7047FEA3075CAA0CB32A02ACD8AB7967FD1371419009B715C9692517D15C195283F45102F9A2A32823D373AE876DD33BA4AD4E435102AEB6AD3A2C0EBDAD1D8545871192787677ED8049A01E56443A1251F2904A4C5B10DAF56E266DEA9EEA87958EF019EA035EB8B518E1F64804160DD5B8A6ADCD64641F053BF592EB05E99D3D982C07FF2314FCAA3D602DF925FBF38DF5B55B93849DF227F5AFE9B5559D01AD9CF8FED580A5844CAE7FCC619C8FDEDF5F52375ECFD21D2FFF90DE66A4790963D32EB0E07C712C151A1AF6FD9C71D98077D4006C04020A210E2A7E7FD470DD3E6AFACDF8FFCAC9F3782FFF98396E11A8FAA57EBBE18028C8A9C138FF059EEFB759EBBD48F7F2EBCFB1DA4323C07E77EFD73ECD74A2B7445B0FEFAFAFA3BDC033DFD46381C28612CDF3B081BCFB3A5FD5A23D945BFBCCA3065268763E6B9A2D383A0CF30A20B486F8A89E2337BF674D86F574DF9500D698004CE62928FBE8AC2220C344A661DD0D7D3A2E00E4C863EC0036080DE8AF97F7B8019D0AE14844F9680940CC4A741568B4E14FDE36BC25D907F1101369A2EF8B77F9AB97AAF5103BFC0F6BA0D5A32E258E1E0BA43C9B5583F28584460CF467DBD1D26EEC37C25EF50F8734BCFB758F7F788AE4ED915E665D456A06D5DCD6860499B79D6E88F454140B6D9E3AC9ED72FAD3E234B198391F8684BC5A88095B0F1AF7F0DA984A1553CB9130C0B826DD375A8AABF0D2819996D573CA887185469C8D5F2E7B5AC40B33A8CE6631672EA13758E92B92B0D38F0D04184C9AEA3D88767AA05FE636BA7874F298D3ECAF87E01EC0277AEE9B5CA942D192ECFAB2C091B5691FA9FF5FEFF66C7E683C719C0A9EA808F5068AF701906362B692441AC6F7BFCAF7309725FEE47620EB54E0F3100EE469B912CE182F8A78D85A2DF7192A9EB9363BF98D4E79BF5638B43930CF0DB007D7A512728A435B0342BACDFEF58B170D9E1B25901F6F192EBE2B438F460980CC1807972517C9EA79D813C4942D9070A425F899DA2C87A6571760FD9C5F627BEC1AB80724B84EF16DDBC1780AF188098CE48A8F9EDBB9A9F175E7E4FF474E2AFA3C75A2B9316EB1DCFD5ED3824C7A5568743ED4BC9B2617F6DF161BDFB71E61EE55EC28780DEACC0126EAE2743250329FA8B83124031846220902868560724E20179E388DAE2146A7AC3BB91DD78FC2ABBE3BB8B5FC956534CDADC170A9865048546003BE511C994D610E7046147A3D124C277AE0879C6EF733135D3F62A0A73CD8424B285DC2530521E219ABB0728BCA093900E0305F7DE5DFD1C14B623041982B4E99E3E4CF58B22EF69194CFE7CDA9B5516B2409D0FEA287A4E60758B98B132A291F89C03AC03C41E15894C126D7BA9C6ED61DF74E6A4033CBD8269D1186C62AD985CE824F8E07819602CE80B182D92D0371A81A54CF183FC0446C59B7C85005D705156B432ECA521F367D34F5FC23B2B5E3ACE529A618B738BA4847875C42E4DF23E6075868C7BEFF0885F5AFC74F27477B6A1CDC2F2EA913730DE0DA2A03C165CCFDB9752DCBD15CD777C2887D7BB79213F8AE63E88255205C4A29C31E92F9B617A15635388024C795CC73975274597466BBB7EC9CE983824233023F1A3D33788F46F6830D739C1CE5776F40B2AB73FD56EA30F598D712EE8972DD7658F2959A08BA67E2AF16C94B0B9DE69D8DADD28D3194BAE956A4AF223C54B7C418F7AB2A993401C009755C394E8FEB53E0A7EDCD4605618EC81F593BB39B2AA7C7127A809C681F482C8754A4F478761A1004786273702B06B93AF4CD5A51D8896707A12B0C598FB5A36F1B978E64B9B0FFA40D1CBC3845BFFD33C60F1269E11A137924A1638C25554687972B34FF82DB9D8974C9B10EA5F796135013F901A7A705BF8C5CDE586EDD0E47CA8B612E4F778990C51954D9E7DF261C9E71D0434F9425FF80528E8973AD5C3F4EAADD10300F5F5605215DB6B08BCC1B73C1B47C6BA70E3DCFAC4D9C1E0C44C2F2A4AA15F35B0C5BB5ADD9969C3790B4F9ED5F25CC57E21A63948ACA1B34ABC7DFF6254F0F2278CAEA44DA4DED5907C012720C3ED9F0167A7E79CC7B1E7CCAF2FD1C23DFEFAE05A2F8DAB4AEC600C650FF000639A70F5E343D68A68D31EEDE404E55DAD024EA69F9A120C99B02C08EB180D9D761C5AFB011329BDE2E6942527F4C1C9879ADF3BDEE1827F499702A1C2E46D2D04FAF6BD9608225B9788BB86231AD426F883AA2C12AA78FE906667595491BCE754167555FC3461FAB33779EA2A2774DACBE0EAF7E1156C93D6CA0F07A4D5A425730303FE2FEEB63963E4DFDFD697E3C4E4EE248EDACF9374B10991D4004EB110168F48852675C0A55D04E341D82921099848D453FA6101D32BD06B1523DED60B855C4D37F07205D56FD5C500187025A960246D37A94DA426D1911D62CBE85BB0EBABA6F6C5818DB43682D35257005CA71B631EE45E8C9EC89A21E51729283A6483BFED945703D38821A98188C7BB02311D8A0854BD468D6F59179B70AF125257744BF77B7C4BB57D1224E8211670BD9E0C70D54DFCE5757222A17FA7B74FFA28E78BF214BC340FCE0D0FC2397803D410F8E5507FC802F28D965AD4DA9E2EDA76F681C585F67BEE75491BD3D8896602BB583566509EAF2D3EFA359055B0CC4D2C5168DAEB64B410CE537C6C4BC81838AB384C79650ADD4816643CB8C929A2BF787A60918DF071997C5C08ECC7BAF68F202905BA4E65CAEBB248BC5F14EA5379162CEE8F3ED684ED9E80F4E3980202DEA7A4B6884194CCA7D0A0EDF4981F59F74C2B56705F869F6E6D951C58F8EAD0B09566B824A20659B9C9F21365A6D3DF9FD4FE3EF649A1EE4A3064A81D1B46FFE356C6E27C8F2CECE45162612298673A65D6895F51AF9E0AD5473179B800EC93EDF2214FDF1846CF0C20F8F5731017FD8DB400926EBCC069C492F8E18E73F7F70805EA0A6ED478D97F6004C9215C52E35E34D84F01628F6D9AE401EA4E3D41950722EFD3943C43C2677AA748AE29485837CED6A73184BD9E84473CE613F2A561535A0ED065EB0693D89A117E167485799427E9C7570A66C4A9106D83EEDB7FA9B43C89840D3AA8D69EB9C90C2AF7BD5676EE42FE6B211630D8EACA3BBF9E6FA9F8A165AF186E80F96D30DF2DA82CC2F80A0D07895113E10E9082ADFD781C99CCADD0D27FD29B1BC2FF6FF94F7CE7CA5F517BF1CFABBFE02F261CE0BDD95FC09B9115CDFAD155C17FF9995A1457A94396521BE5AE562B262B4486198AFA73DBEBB4D1BA3D0E4627EED082C5A20B6C33627A1122FC74904F1DBDDF35848DFFFFF6CCF42FF099D76446DA92BED7B65722ABD412A628F91A2933227C11249B0209AEF4D2CF4F2426AC8F12010A7D425AC6B4D615FAF2378E679C10BA0E624F741A73D91849702569FFE086A89B9ABA295C1303E100EBDDD6FFDCD92F6BF2089DEEEC7F1189A25DCF721CFBB2EE13E2DA8ABE105C75014AB6E51D34E9D9B328FBA74C4203F49AEB33FB9A93ED28CC8C3E81B564466C65702D44CBE1B151927D7FE70426D73702CAB2672D57DE1970806807F09528509077CFECD80E1A6197C14D849FFACA19A47AD82052B51F31506076169145C3F4A712F04DDD9323D525C653FD1C76E6F36FDA54C8336696121C4E2E88FB2BE35E59424AF74A84429EE30EECCBE4278F460F530445E3DD964994F5D54E730C55D94C671403CEBEA67FD726E68EFC296722C1E116A37950C8B8A9536DA4FB82878FB8BF11D870CEF19876693378DEC8B4D87BDD98024DBD70EA72A87561EA258F342FC902584CF90AAC27D2C7CCAF3712A117EDF10E822D93D826029D1F1C5341554514DA5DA89E112863C2CC8EC01969894EE6E17BD894DDA0214BF55A17D617EFA006DD0F8B54614630D1D858F14C597C8828005433B926CA0DF771790B8A9FFA884DA829B53F450FF9C862BD9B6762BB04AF53BC761156DD364599A1A9ACCAC4EACE6D77D81C3796185EEB5F448FB8491E3319D7CFE3DDC3E838B7F4926049F875F5CEDCAFB70285B6EFDDBBF691EDD10DC06A87854515662E3F906D7A6C3D41B0471521BA6435013E19F74EFFE63074DB111B81B98889E2726136D8FF335B62D204EFB03C196649D9D2139BBE7317103A40792F8BFC695B5D423728D3D5CA49DB7AF663D6BF62E59CE5A865A6864B3F93799AC1C51E08EB4EB2FF128C78DB63F0AA66FDF36F1BC2248B764498BDF649020E433947C5A1D8CCF373846185462AA4FED697CDA7925FDCB2136F6DA908EA79EB00C17DA230FF42BDD04F61D58ED2543740497DDB6EECAA1257D376F20A7BB5458985F8F7F7D034581FD605F251B878BD7604BE9612E3C7931FF45BA1BDB1BE673EB8FAB8E9B052DA3F2B638A9FD72F6DB4218D8BE01AC82F3893C29BD229C0CBC9E752EDACED0D41BD1725813B096178B477F61FEE48537615E0A44A6C7633A0A9CBAFC2D0D887E58135005B43FEA7D657508F3AAD73ED6AA1C37E9BF4EC1AF9B1121DFE9230C6AA6004F569EDEDBD5652AC8C5008551A7B1C5D446EEB09B5C0125BE2E9F0021ABE14BF8901E22C329928F66A2F4395700CD01B2AC298AF246F4F18C7A527DCA9090FB346146C155BD7650CA39BB03A06FA272A1E6FEE5FDF684840851BA35E5B91A81F893EFA16898846FACA49BB7768BA7C113658545133B48186FA91D360BDF7920650E98D1BDAD011A64C07F92D220029271539B5B8A1D0710156BB551295934E7820C625C094775E5AC2F959FAC1F71FA308D702B601AEC761B324877697AB331F40ED8DCA4779549F62AE4D31A28887ABF896E02F0A7EA1D2D12F41D6E680A5250C356C619713AC170043CD9528BBE9E3248D6FDFAFA0C84C15B16F0E77F2396BD404B7DA237D06A117AEE653D3248DCF61F2255940A4697C105019CAC9A050BA24D7E9F73AAAFCA6779EF7EBDE8F7F64D42A5C097746DC9758FF1433BAA930521896A9D2432CF033BBCE0A02BB6204AE49AB0E93826DC5A6302C7538E6FD9C3B00B3FE5F24F4018074757C9B95A5AEBA272BF92FEB6253394CB1C5A39F413F39D61087835C12E3417222A1CF61914AC8A53E9F2507BA14AD1705488E98470122CC2D8C69209DCC795A410C101A074E6AB177B8184741C2B6A92C6DB12F0A10AC5635EDB27F41FE927428950E90F369BBD7151F46D49772841ABF4AF07F1BEAB2BF2F34D41F8417D60B83FC0B2E67AFAC19C679EC7F05ADE73B43A85136179E3CD0DEF35F8D91FBF62AA47A571C0F09C5FF3B854982123D138CB0FCEAF9A48E216093BFCFDC0DDBF3271861B5EADFE7C26E3CCC092FA6ED87AF57E83F12BFA8D94A023C1D45CE065EA30FB6812D729B22304DFD52F7D6588405EDBEE327F4100BD00907153B14872F0C7B7A8D42736F381B112B0F906EFE56F18BC4F008CA7EF50160A9A5623E3BF5155519461C6E69F72D91D3EE25566FDAD4F0C622CFF52AD858C19964214772B413E4B5367D2426711AF4A971BC4D8ABE387DD475EFCB3D991F31C18FCF45EB26E74B66D11B1B6DBBB2C429319532890B238B3997CBD67BBCFB6C09B9E318F23858276E8A85BB25BC7073125AB06CB2729A24949644F9939BABAAF949F06A7528D156E68D85E55E9015D44F8FDFD77F07F37F6B3A8CA048D28532BF2E61A592F0EB3D8ACD911C4711974BFA9456DC0B94DF7EEC16053EEECE90F00DB047AE1EBB36A0AC088E331B95323F329059C7A2E109F6F8F1CF6FD4A1328E548A5E06916B7B55D65C0BFA3E3F36B938F82ABE2CFD78D23B9D8134135E548D12DC01AD12BB3F22C57179C8EF3B90CADE5F057B996166AA7BFF354845464F9C1FBF8F4BA0009011CBC9DB6D8AD6F934D28711CD0293EBD33EBDCC3FD714B9CAE644FA6F94FA5D64CDE52D739FA1C584901F546F26F91EB3CE0E87BC7DCE0BD4924566A46A36CB52A04C80B983F29024525E4EF83FFCF91BB3F1F4E5E7D213A2CA0FDA3C3EB23FDDB39F5266E32545252590800029E3BE333216B520651FCCC6C6B532D379BAFBBBB88EBE6FF62CF265DFB8DB410D4E2531F1B3B6DC2E22F247BC7F03AA8F83F8243EC3E7C86196091DE9407483732722950B6CB858A08A9600BCE777150F36D73DDA34D08913F5E195C50EB5AB99B4180EE16586698C4812326090DB568BC28F4FCF7050FCA7E1E52911836FC87C589B8ADBEB15D67386B1369CB2E115D48C4749AE00F90D2AA13E51BC4BCEE98CB39F33F52F8F56423CB45DA7C249B1A03C178A0343E2E9A32D3600F78388753300B4189BE85C3977667BA18F50DC6A686E1A84560767F986F7AE0557DA5F6CE085AB919DD91C14CD6F2175AF976936575F33C3A1A4F1DA3DEE66B0F23431C10836B459486921CDF47DC526037F842EFA56D0402F455BC483A8DCAD46607781E831D8E3DF4D274A3C7C8FB37CDFE5ADE4ED0EC21938D364FE89F3DAFAA9ECBFDBA8612E99744389C2E71D853F6C0F7C785BEB907FF4D5FD64808C20BF77211B1B666BCF26B47A75B39D916E956E295058AF6E3207564D485B885E06035C6866CD91CAF75EC597923982325F8A869C6E553C61082C1F3F078B7C06C2ED2C7B265D755B4BABE3B3248376D02C832672159433F71EBE5D147B750540E358DBC75472277D8FAE9D5B97FE8D7ED67047F135C1BE5B016932EAB3A4E55FF8DB9DD686356BD1D583A4C525D53CBEBD1C90B7DFBFCBAE9761A3CC82E34EF94A2FD69A9D02F26002272E98086402C25A8AC280673C5CC200C557C55F76A33A196B21AC9BE8B50F38E936B553BB58A7FF07BE60085CF1B8ABA0FAFCA0892468B0E82C0A0930889CCF18A4AD875880DB66B78FC7BA0E47B997460BADBB726B3E7816322359ACB498C40F64B1F5B0001CAA508B5FBF51E87CAE0EC02FF19B45D3702BC1FD823E212BC4F50AEA55A662801F0C29AB76A77914D4921A88BCC49AA0269589CF283BD9651CB7A1DD28DD5DB9D3FB17B405D7966F2A0CE245E300AEC2E93D717002DFDFE4180CD826CA5C548E26065088B7A86C977587BEF7F428180D2E9EF29E57C60C7F0E4EEA364D9F110CBB77EB4083C93770B55E76A6B603D1BF8D535680FD7BC23B6867ABF5D4414C4257776573E569431B057E8931AF61E56FD67C5CBABE483B0B0F0E19D5ED63847647BE77C86229DDD347998252CEAA2F0744E397B53A7B9DCA5AB4C241D9E0201A390B4C2DC54EA5ED9E1C70CBE95BAB401C0807366A7248E961E63A7C00A22D7965F687A5D9E8E5697A9DAA4A2C5AC848F01D132060C27588F5AF48ECB07E364778FE0FF1BAEADEBAF6004C87989ABF4D6199FB0E20EAE65FB3F7A71CF950E495BA2AD7C18AFA839F7FE4B69BA3BD7F37FE7DB4FD9A2DAA985916FEFA1D0B5016345A33EEA9B4DA9DF3CE5B55EBBE79374BF0FD5DA93B0D7AE9E2E33EA7CE844AA0621B14D95E96DD2455B07F08089C29F8D38BA9B91DD81F69284CF1F9706008E2C84038A0CDB9E812F6255052FBD724EA4C225BAAF36CC27817BBF392E977FB0E5B454A6EC0A1FF41B08A582763A409A3EDD7D87161FCADCF191AEEC1245BFBB169905FA02F0844CD60E8734064437234BE38D824D02B84F0B2D3305148C49ABA57882113AC4106E098AA35435E305396347EE526473E3A7A17E157227BA5A81CBB873073089E16D7EA8E46650B2093A6554CD0A66180A1F201C222AC21CB56E9DE8253593DAA7DDB21711C6EE82472D725A6760B51854B8105890E57B44CB0270AB08A82B757354060088B7FA0C84038101DFAC1FCF932B5B17B536BE7ABE613676CB368FC5CE7A7B2E39BDF3CEF4571B680B187C37C78E73DCA346340D1168E997107D1B63751D41F1B93C5AA3DDCC0B4531008040281401F5609BC195E13C212AFE90F761C954BCB1090EB40D447A03278919AA1DEEDB7C96AFD3C9FFC577DC4BC9F72417519D39CF4DEF117EB06E06DC6A592BE1C6CE72ABAB0F84D65E316FDAC933659966958EA75BBCC9BDC94994A70D99E76F02347813FF34593FE390BFF2FA0D7A3CC70C5AE68005F5A9ABC63C74473781AF66040ED2C95BBFCC3C00FAA04FA834D22E5761794FDD365736B180807DA3FEB972AD4B8CAB7AA8821E529F0504FCB238DA47EDDB562D4E85A2F90927D053448610A6B08F7D63B127D970CE12BEEEE1B0C7E1BACEF7CD5E628BF9911B56B2D11F0BC3B605867C0524BACDAE5229F5472593F59376DFA824532EB88DD1BB715A5A413CBEA22D80551826C68732CB80EFBC5CEE5617BAAF07C2EEC5BCB171B0368504680DF1BCCCDE2FC5CC15EB6BCEBB3F8B1010025DFB882FC8874350F371DD0BBEF9E3B3247AD28AD0CC2BB62704AB989605EDB71EEA62B7356F72DFC9DF947915D247666FC9B9237189103B9F7048BF6B8554869C8A9EF3E1C985BA734B45A2800FA19F9BE4580C8764DAE6D88B84E2C0B8B0EE5CDEA05781C3B3689941C68321FCA39BEE37C9B5C243B3265A51863C9F1D8FB8B6A11A3081768548D13EAE96C315D417C56EDFD69A03ADF343C09CB9E3A66449B83D3CCDC7F3546F5C23C28B4425E1CFF44D3155449555283667E00330E4BB682F055B102BA9B20EC1A5CC82DF9E20C7AFEACCFDC183E978A211C429281EB4A26F25E940953D7E8B6657B0C763600FB02150387E5711515A1843785A0DFC397DB2B19F1F4FC72E8A4AE3257F5EA3282887FAED1A407F193A26E7453A379004AF07F5327B2D0021878C058440C708A0991A36943C00A0F8615B213353A82C571D647F963D770001305588E45AB1C1093545E9C3C72FF8B42737A7ED36AF89E5717787088B6DC75F771810311E7E02F88E85D6A7FB87215BE594378E0C987772154245C737B398C80541F32B6F687E3882929AB732BB4EC5446897F38CEA06D1B48C5E3CC0DF71C70ABEBE37210A159AA5FB19C9DE7092ABE239DA8D6BB10A17F1EED67EE648A6F85D7AA9797095886E4C08927DA7D3BABEE46356FC8A1D8ED28370CEB0E52342AEE99F8D86344C9966BFF2342DF1DCBF04A50CD05DBC85626B2620C4503D6A2E3074D750793B60926A4E740BA612BFF35BCB0A1CD6DAD3B98FA28C18D778F5F18B651D4CF10651DA3157F63AAA2A525A7138C84B04EDA2FD04CE23346FA0C143DC6E13E462B3943299E292670EC3E528F5CBA1FF82D884ABB079BDFC30E6ECE365EDE96DE8E6EAE542C54922E6E3EAEDE8AAEBADA32544254BC1C9C6C9CFCDC82FC023CBC3CFC3CDC7CDC0F9BA5EEE3FDEB52B9B8D9780478F978B9F8040467A1BFDEBE5AB676B69E9E96CE544254542C5472CE96F65E5442DC2C548AAEDEB6F69E8EDE018AAE766E54424154CAB6018A4FB4544E2A162A6D477B574B6F1FCF05FB4F0C3527594B66272E67796DBD4FDA4682F22A9E9A06DE763E018186963C1E8A82BCDA1E9F1CDDADECFD1C1D3ED9794831FBAAF069CA6878F84A7AF1BADA39F02AF01AC9CB7178C8291A7819592BE869D8CBD9F8F1DA70F248FBEB787B4A1BA9707B06B26BB173F3F8382B6BB91AF170E9CAB8EA6A791AF21ACAC8D8A8E968B9D939CAE87BF072F8734BFB2A68486B5B732A29C919281819F207FA0572D8E828A97A68FB6B735BFB7C0AB0B5B3E3F455091434125453B356F2570EF4E35016E0E333E2D694E1920EF0B1B55692E43454E26797B277E67076FFC4EFAFE7E8A1A9C2E1E8A22325A06CC3A5A7AD14C0FD2980CB55DE48C147CD5689D3C95FC5954F5AD29ECBC087DD535ED14FC1413FC05596DDCD9DC350E693BCA3B2B3BD979B1E87AC9EA1979E3C778092BCAB930A87868F9A1DAF8032178FB7A4BF02B3B6078F3ABBB29D94ACBB95A7B7BD9B9EAAA5B78323BBA5B3AD54A0BDA8285588918874310006C448ED05A4FE331B78A4B3CF2D7A090A1BAE312E59AF07B9E406ACC91B6D5F4100987FE201C66D6B313B33BC155A464FE3E565237CB21F8EFC8C7DE21379B5701B2C3B03FA9C1A05D3791803138AB9DAD36DE963F16BCF7973D29793A906C0087B0649D633997132BCE23B0945910D07828CFB1C3728FD92087E5ED98B26D8B6AC959A020DD3F969478D78C70BB2E5DCE097EB7FDC93F8DE630A42B8008F87A1F7A77AFD9B3ACADA8EDA00C2CF1398E3D510D734E57224322B3CD4E1390B96EE06C19DE569BDCFD6A42F77C198D8CE21902C0AEFCA6DD0E7BD8C2BD12351BFE4DFD7432C70FCB8904F23912BC9F77CC33EB413E6991BD9D586E89215C52A2FF1C583D6EE0F205CCCC0F6A1D9F732DA3F6D6BDDAB1A9D0C50B656E18FCECC150E263EC2AAC8C3DE03AA0BB6967B5788FC8E9673AA295DC41E14EE594195BE8A9F120AD714E4DF4BF11727A48883BB710BE0886E2DD9534930144DC31CC3209EB302A5FE162E6442F137321F1C1E3B1B6692A85024C699FA65CB8A4583FA3AE8A169010C288AAA77534EEE9C9DF90840DE2D2EE32BF6071157BDA4B0911D8E4A3A43747F03E625A7E2518726193A075A9E67A167AF78F17A7FD794EBE0C19648BD93CEC2C8705790BD2BD12ACA81A2811869256980853AE2FBA819C1F6FC797A189C5FA53D2127C105936D98376BE212D83515A152D69341BF418C05F0F0C4954243A6D41947C8A8F422E19F130ED39DEFDAD9D2D9766D072F5DF45801C95C9E0BF27F9FDF34027ECE4448D6C0D6FE259437537F8C4DB5FDA20A73DB00D3C5E07BDF7AEDDDDEEB720035CAF42A1F94139421E14598831C85B4077C07A9B33CEA2106A836D92AFEFC9303176D38F4F3FF73663C9A9F13193184891264C7FAD5BD48F054003DE29D2C1870740F5CBF3F4AF4D4CE73CF758A0A130D93BEF4404849409D5D1577AC67ECE84AEC9BFA640A2D5A412CB06D7C2C9FC976D94CE9D0ED9182647BC84A43ECC455EE03B55674FD8621A6DC08B007E15CBCD9ABF299C5D8B899EDFFD2CFDB8ABBF425DB874DFEADA429F6ED691F63D36F5A3D91697D9EABB5DB593E381D519F12EBE9CF903358D9C492175BD07A0D28926D26B1184DE3E1A24E03983E312FAD8FB18522E3C77D44873BA058E6DFCBD0E75F554293DF8758FC0447B9A3D58317FE6CBD54992FB8A59CEE197181570570B1CEAEEC9A49BB1649CB90FB3DA230C6766D4271E900AA77A2541205A6693DA3117A33A97FDD17DF2060ACA7D8F0E62CF2A48D324A39AC9EC759060DF5100B842F35FABEFCA9DC3AF511763391B68C6CFDC4B0CC5F71C6745BBCAF59088EC402489EAF101FF6666647C4505F114F9534DD734E0C14D21926EBE86F3C5BA2E6F8E1BC058C555C56D9BF6A174BFD54C53E3457814E7582BCAF8F5BB5551CDC288C9884AA967C09DA92F424AE09E980AC66F12F5E99A87AA73951C2CBD3B011E960E6E6B12D7832059FC2F8AC952223442D5DE901A4E04C44B0232FF02B4F50FF91A178F7FD2FEAB01EC0C074D3B835028D5477D3C3677B9FF29F456CED3F742A058F1C330EB545A62A11A1002D9E4A671C97F888FA28C52852866634E76F5A91C37B78435AFED2B6F5B1331FC71DE0183BBE122B0BA76A390A2DC400EF389655930787F416D6735F11F068B02F657566D7FF0EAC4E35BC4DF4FF12E50490AB28F13E19767C1D5CFDF565AE8A0C01955B69720F39712C6964656B87E611972AF0AF6D83DA5E30622861DE4F1A5A4568D694F3A6060A61E23C9D87AD8C5027E7A7E8B72B8F7870A219B96C8A235217D8C6CA2E450CDCC379CDE981989097ED833437D8A565DA9E7ED0ADE149F546650A59ECA71C9209EF075850CD88DD49C2F5F2B37497F5B7B4F696D5519073F3D47173B275F59A0A4194A86DB9FABBFFDA4ACF9504F64435EFDF9F2255C846FC14EA43CAE355105413C39B242FE8019C798AFD1AAE9EDCE87CDB5C2D06A7E974159E51EB65D5D9B9F7DE6B75FE9E0678EF510E378A92E9FBFD477E2CDDA4DCB2ACF771947706264010DD70C675F6D557B443B53CF40313329BF6DD1E7A0DAEDB1BE87B526C8FAF45A1915EC13D0D45039A571B6C77797A469F476508117B098F5517EF0C7DB345F9E6367D6A2526D3DAC4B7A424D756803BF38EACD5E951901B6C7B913005A6BE3CC425ECEB50A07118328EF119D3DECA420F31C0D8D32B5D1EDFF77F091CF9D5824966EB24A26458DB4670BB8B939F0A772F0ED5000EDFBF0543C7FA060D7FCB17A4AAB3F56C625197E9BE352210565A45A33D3EFF87CB32CEB5B548510845F2B593095F2F13ABCAA60F2362A49984FAE61ED39080BF3B0F8FB986AE3C0BB42CE832068621F74F71B6FF0CD4C699497F038A5F84C069042B39B54249234E2FC56E8EA7D7EDBA5D5E56E6DFCF21F34CB4D1701173FB30985B9AC02F2BF88FB0FB29374A701DC56BAA7C2B337CE739F9EDC02F7FD3E0F97E0ED085EA21163822C4F0472330A8E535BD6A40C7BCC6673153AF21FB92BAB13B422EE59AC36003F0C59DFECA3FDDF4CC8CC797B37AC754CBF1C8170A6DB4404125F678DC449CE7A732DF6349652F864898CB661E5A95067F905EB70E4F218879C1C2BEBD84B18395D6488E14956C0B32D23F54434F65BE6100A5C3A1E67CB0D2090CEA00183873D3C84E3C47CEAB26BEDE7E0AC24DBF296BDC2FC75E6E91628A97FAF123440BE09A4D618397E4E03ECD0BC8362BA08216E16369719D78AEDDFCBC23620A57B07F39EED056B755C56A63CB0933F1EE0ADD7252B5EBEECBDF8A22EEC291A7DC41BC0B589EAB705C4578CE72D6BD034BB094ACE7A28F697131C337A59C0E0321AACD9C61FD0D1FD0F769F37C4DE77B942D4EBE13DB8F710611CAFD886D201CC10F13D6D0F61D061994453B25927546157A4BB5CA32DB45BDD4122C62BB8E6E409EF8080360A090689274734629169EF14A5D0150A8D57A329AB28EB665B0B8C12554FB3E030B08341B9C1FC1C0AEB0226DC49D1EA9C249A8F41F6619974BC0D9E7C6450A85A6C166D344AB3A929F027978251E3E5F5864AB665E65872E9EFAFFA6F3B276B1FF04783613D0654DA2707F03C85A5569157583CB019B9FFCFA353FFFAEA0E9B4842BF19DC42A7851258F3A9F41B06E86E68C31C8B82CCD6F83101413112747F32EC72F3E08FF996DEE70C887B768DE260FB5E0B661151BAADC38BD520EA3FB5E8B144DB39E4AD1AD2B8725A6FF874EBD1A40FF6BA71671F26E8E65F954F939B076BFE19C67EAE27B5D98B1415A790710CBC4BDBE4021CF9987AD4757AABA88867849EB95DEF8DF58E071BEDF12D8109E7B3C6949201FAE80B2897C5C8C5CEF9B354B616EF60E22EFB7A48A7F9ACB9CEAFE02053F7C5D4B36A89EDE01B1B431366345CD31EB61495C5F73CACB18E4956E7FAF8ADCA15F43A9330F1AAB8060B1451CB299ACD5E325418902189E4CC1CCB798ED43BFD2D10B8DC33840A5C041DA332C0C7A1B8D5090DCB8E312BFFB49910438F0C799C95A4DB7AA5F7CEBDF7C4CBBBC8C68B5C2F6D53E2C6E4E7A32FEB9EEB7F0563FCAE5EA6C587FC8B3246EF860BA118675ADFEB82F41FD426FAA99DA47E9FFB96B7ADF5AD4CEDC591930E1F823BA2EE0B2CE801059FBEEC96636A43E823770C731DCBF68C79141286B8F60A31D1A66C9A032B3469ADC508AA8828FA406DE61EDB5061BA97ED175732FC8977491E5C888E44FDA78CD6ACF0BDDE54F995F51FEF4E0DE146196128997C2BDC789CF6EE175FC0008FEE39D92AAAC30FD3C601CC9C0291B31FA5F348FB20E2F65E464424C85CEF75D60E52E324CA37CCF1AA756FEA431E23E39E9211670DA352ACA4F41C96C12763A250B2FF9365983E404265E88CE5170D0267AD75D01FC0EAF2360AC2EFC958DFC811104068186AA3D0BB38C6F4E9F8976FA7A0B3A6311641FE69A5A7A307ED25CDD6A2F340F50851F6C52A403E40F06F74E6F3691791EAB72926E6F764938A971BAFEA57EAD1D31F6E59D50CB800782B90FE3FF544F2EC8F1A2DAD4DC106CE3841DB4A04D11BFF89464EFBB48CCB05019E037A2BC178C781C662DCA75959567BE631381C641FAB77F164FD65068004BFBD5024B861FF177665DD9D0CC5DB307432C5D8D2606C000BF49CBE03F9465633CD3D666423C93207F5A957ED75F8D7DEAA3D0A3DA90D86500E50BEDA28552B0D3BFDA53BE9DAD5B1AD7D55FFC8FDB2F2694000D05AD60F4CAC4E56E7C5A4970198DF4540CC2679634FFCF327F948F64DE547115FBC2E1ED206CF29867A9570A72EE4FA543F982C8C9DC3AE1C039BC4B9A5FE8B5F85024E5B99D2B1056F6E083C39BF9893C31AA0981EB9A39EF45FD8184C21D236CBEEFF6E945FC8BE3EE5E30567925E228A2F42FE1BF1EC4003B663D33996390944D35F9CCBEECEB2CF8B17D152F7FC43E174D68C9886CA33720ECFEC4C440FE4CC742DD95B6D6A415D6988D5E63C427490211EECC8A70C3E45EBA2506D379127E7E15C672F17EE212E415FA3ED3EB983A37A56999DC3353D6A2FC1D87FBDC3630F47FFD53ED02AFF41416803B56F20F8FC7A2BF56398A853BFD3B825FDEAAF557D202B46F3D5C8B0764E29B02C9C062310A6A1C932307E6913F4D29F8FEE2F5C381FDC70C1D1043B3985A410CE0605F8CF91D1977E8D098635EF0BFC38F451C196D7EC6CF6BDBAB6409B5D15CDA008E7123EADA9D01F74AFAC1B00397DF7C107587975339CDC95D26D788591DF9D280DAB1C46A925BE1FA97053E0FDFB62C8B680581202B8602A44C36CE84837C675F10F49DB7E045C0AB4D7EEC1846EAA732C1D96C27C1CFBFB6DFA47AD94D3580A054FB453C1AB59FFB3D5919768F54086095B751B635A19803073207E8D2E80A110FD5F6C55F19E24AA65C2EAC8CC3893EF138B66AB21C04EA6884CEE5D88F264B0C8477BB4F8A3F0179BECF31B4FA65CAC83320475BE14EA56C9060D8949F3349463C29605B36A2C0BF125CEFA4A925477DDEFE276D428495778CD50D41F49BA2900EC2F8220EFD3FC5E032B3986C547EA01BA18A6B65FC1CFBBAE7863769A6128C7618D7F1D40706C0400AE2DB17190E71CE1B03D8676888D730AC5EC1CE720B23CAEFB4B7C272EDDFD68030381A9EBB7AEDE69A5459FDD46FE2C3ACD651C5EE498A9817296CE4876AAA23918CB4739E2EA5B7A7302CC4A8E1B015F65321F5939BF1BC5DFD483F538923B34F33877F481329A90C18C4A9906B0A172F4D0AA700C2A5E6C4CCA99BD6C1B3E80EA2F469B51613DFD8A8ED29EEBDDD9779569A5709E1C3E33FC7A9BB69C363B03F4698176CA11E628126C1B1544AF93ACA32230C8EA605CF2C0FD22FAE22606447BF40F6F3DC3FE9A580DD258DA99BC1BB4076BC0067BA2FFC2CF9FFE0C5EC1D69F96ADEFF8390CA5969F863634F478FA850C7469D190A18200FF6B3A7053504CFCC62D2977E711A9F722A87FFD54D2BACBEA6574065C2F6950540B1E30FB907C887E39FCEE47E6CF8D44512AF4B16727B1C894F4D574B506A7E922087C53AC3BFB043D13EE0C3C8F39310DFEBE3B4AF9F1274060290E5511EFA7BE0C3211C9067CC323847BE39B864B9C3A6FB0996BD283AE674C2DF1263F270750E0D2A5805BCD124A7E2CD32E74F4AD38507312051E9F206979A8AB30D81A4317FE0E291734A793F27E574A4D4EBCD4ECCD1881BD65FC05D7B48D93AE239F9011E3A6A601FD52C74BC91AB85A7B553496CBC87E6B59C800AE8779209C87B954AC410BBE3D314C06EC0A7E17FFCF20E71FF42FB7FA35B53F996BE1D4E400CD075D45B832D8689FC96705CF0B5EDB497B850FC973FABE9C396FD10B5D09D64056C7276BA29F912D9AD46E747AF27D7432C90661037DA58AED9CD0541C19759677BB4BD6B8CB2F8891C46B845A274638BBC0438E5893263C27F95D56B420BEFD13DCFDA76B2EA74FE449E6457889E730EE390035BCB015A7591C065F2D8FAC60953EEA6B1014AB7A7D5246D5F2C42F1AC536230A5DEC577A138CE23F880144ACD1F73C566358B93D1EA8E8FF25615559BA9AA22EF8DEF9108569CD56F530886A8ACF5B1A077AC0730A05E149D2AD0D621FE3FE7238D615118D6EC081E3E4AB89E7FE3A4436F253B910B3054B591A1D740C9F56980B5F7FEF65B8868CAA8803CFDEE6FE2694EF26C2106352033E01D0423FF7D0818D31D4B7D7AA86197FA4E4EA716E3809EAA2B2274988B2C5FBA4D83B6360D2455847FA30BA8913D5671F6F729CCA6A9B53015D039115EBE2B1664326B3664567C14E3FD2F84F7EB7E96A399CD119D626EAFE70E04644BEB5DB1AF43B1DBD32560A2138CC84722044557BAA5539CF8D7A1458CFAB0EAF2B1867A3C9E5D6A4B3AFD4AE33F4B016065CED2A9FFDF93BDE1C2E0E63073667F304C1C5B9C251CF43E1BEE0D077E124558D218E386FDB2C58582347937F4D05B01184873F2D92D766CFC1A18DFBAF2104AE316F10DD6258DBF9C976F97BAB020457906E05F34723FF09BADB87DA6BF8B148A7E9FB27E4CA626B69730AF2342A34BB8F470F2C6BD9913D24D74AFD71C9A6AC18D4D9C3625F2CCCD92B97C3A7EFDC5501CD56F32AD078101A51C567EADE478E32E1AAF2AB9ECC8AA9529F9633607B3FD38F270777DD3AE35B7167082766108D8DC7757B08969CE1D8AE8DA97F23FC29F2D9D7D2D6754D2D21ADE053893EA305FD16555EBE34394FF0546143141D9BEC5D6739A700D1A47C8701FCA5C569A3A3DBC5583F41C402B9FC8F63F6B866AEA56F3B846148EE5C68E9BFD4556B595BB8524F80FB5BB112B1BE064E7EA70DF769862C012274A14EF235AD5D401F6C259BC62B42E230105EA48F3249E3DA2E08D93739B7A53E6A30C08AD7CB3CEAD981C1EF98C08424D72059CE360B7EB527F518C91B5CC430AEA6DBAC9E1EBC425FCB2B62354F96A726400E37180E46A74E993F49508F80A88AB9A89E25E5E9A50D1EF318B5C679C9FDA370B14F9F3F3CBF86A49519DA6E7BA59519070EB99B5585F87240B2BFE736D279BAE3798D20FD688971355639828443F23526A5A4CBB711EEFE1AE94E41815EAED4741268EB091090DEE1CCBB87639AD34B37392129C9E0E080312AEE7763523A39ABB194F9F5D1F3ECF58FDCA25984EF88FE3D707A5B47E4CF7F2CA9B1D311BDA6C9E07CC0E86AC8406D1864FE48FFB9F9BD95FFEE3D87EEBA04BFB9E42D98DC9F43EE72D9A209BBD3FB0DE764C087073778DC7918A844B29A140A23A53983F2828FE7C0B0BFDFE8943C931F9D1FD0541D61AAED1A207F513D378D0CD5FF100A4AC83AFFF06D2423810378067DEF3BA6B1E3DE8C99D947A52891D019DB5B9049DCE055E61CCF43A3400C8C7766FFC39BB4F27C2038848BEA7BBD7370EE19188AB201A11E29C701FD66EF868CF39DB3A45589220FEFFA516517F52768E4AD3CCD60F39031B203ECEA6ED3EDDE42B6437AD7EC2AF8964BD3D8DF420C2A1C6C7F8F05F3F51D1C8A047426EEDB4C3014DE4EF444E8839BFE6AA6A460BF1304550C31E5CA2740DB6F390617061C1DF9900AD288E45BEF2A686231FE1A50D6244C0C8E63E8360176B21AB308879EC71FFD0422C80349A5A2FC3D33D511BE58D34794335DDC710F2915BBA823F04CEB93EDE13BF057CDCCFE4BBDD50FB978EAD108A2AEF56CE116F3C5A080A59693AD27A79AFE33F236C0BEB82D0C52A76AEB7C12981960DB1A51445A4F981D18B8730DCB8C5E2FA5B98C6C07009E748FD694BBD18BC07085E7AE24B437EA7C04DAB92595320F03A914E0E85480624C3027042E3E8E43445FC7185AC515A06446EF534811EBFCC84BAB831BEB6E0C16A3B90110E66ACB028F210DEC78136E784C78A44F03745314DCB6290F035C8BC2DAF6A3F6BF74E107ECF13E37E1E249F3A0293E8889B5BFB16F73E35C63110F8EE91CE5FEF0FC3835BB4DA6CF2EDD0D4C30018D0D76FB72B8E3BF84A5A109B5FC8B3254B138364C3BC82FB4320A0435B97F76A0EF8946359C4965A850C63FBD3FF3EBFE6EB95E0E665051AC209836524742C47699B17B43065A2B2BD92FEB682500A241079C199CE7F6FAE5F837C7589AC1D9E85D51051BA1808070643E7E7502375E9856A0FCF0535C7A2269E2558063F3350CE52C305B35381DC00B9976F2F145E2A24CC5D14C94F5AD849C5B329DAE2888DFF14548F6D2D2D558AC4972DDB83DBC60F76EC2B1D7C77059FFE9937A91F5D80736F992388E53D0667B1C21858BA4021BA752F1CAC08FF57F99F6AA28837E0A1715B8162B9D404BA9CEE6ED97F67B3B8A9A1525E26370E7639C9FCF367EF337CE7A4F63B30D1D8DD3503459E285A8681A15036E6900377E39FD5343C627B0C2C924DEE7962E45CC4EE808C4AA7EC782B695294A0851840A72479B17B6B0B2F46666FFEA70468E60D7B54C899A94228F82A62E27824670080335367B5EA734BA09158B31F7727EA228FD275699BA542114FDF4B3ECC2D31872DE028671B1144187D4797CB16DCFDA46138A5340506640986DD7FD9BC6822E3E138530E9CFACB4C08B42F473C5AC21CE31F2D98D18B95B2569D356A441B9633B532C80D3F2600F2BBB9C3E3BAE863CF77FB1F9422F31BB68DB04ABF6E707164BEFFB656C0507B65199076E80BA4390A6C4092F7F48A8361EC24B2C2DE87F0DB96D30C3110E747143A24D15FEF8FDE4EB7A3C57745ACDEFC7CBE51177DC681EB924F88D0ECB286F21C6819C615826917E25B76C5948202870D4DAE3C2E46623F144E9C3B3A650D9B190484F365AAEA83AAAB2EAE1CA682D0CE31C1245E06A40DD46C759D163BA41D0CA14C3A05E202820D58FDA5C93A8417BEF6FB868AA909D54B7DD711AD6195BCDB59E15F4DB7B6770349148049023458EC8B8CC74DBB019D5481AD42B197A1573064CEDE225ECF820E44E00A775DBBA10607471B9C2688A0EBDFA5D375FA0EE320B484435389212C1CAEE6436310C14817112B3DC4027AC4E519DFC5ABFDFF8B7F38D958AC562214A5D1C4690BA1C6098B7D179A9F0806F812CCF277BDA2301B040C64350F32C10E0CDFA44FCE61179D538BE0DCF3767161D3DDDC0AB930F7D835CCE2AC0127588F533AD847014C589A95B03F70BC18181BF85C55CC3E32F3E7A60ED18ED7BBA742E46DBE5BB772D19CD3A9241898C3A6355506A929A1F2FE93F6084269FB91DD4E5203F085299B6D7B277A0AFADB739B3F70DBADE41C1FC26C9136552CDF40D828BF53008C135D3AF1B914BB2DD12F8EB0E016068B4188E4AD1FF6F4C1FF869E987BAF63C8D1DB5D27D2A6A73F254715244E364D7050024D80EFF8567D66C0BC28E48A5BD4E03EAEBA615B494A7541073B9F16E3E3373AC628923D1516175246511EFE92B9BA1B12DB35A40EA9C397F8D379B275D16C1DC55A816F12BA180003B875EA4A29EBA173BAC575DB5F222315D40EE1F88D72FC0386E6DAE26F6AE70A0131E253FF44FC0AB290E9D898F18996A4E1DED987253CEA420F36F7932C296B52C71B4DCDC53806F415B954BDB1321BB976A72F77669463CA36EE9236B6EE4BAD226000F722D0BF9A7A624ECD67D58723245A33409B28DBB78B614A7569BCC9EDF3EA5FC0C46CE2ED27C585D6C86F6EE52CEFAD80D3446F7E9A99E5F6378F95B76B9BA73F5DD4BD678C7BF94121CF5EA13EB1F356E73E3D3D3212314C80FC75D5F08A0819508728BBB37AF1F17705CCF534B93F9C01E534FFD14807624804889CA4F599BA4AA66F6EF2F94F2333CF72262DFFF1081237B49802D54EFC4171709688B6C01F7AF6840CDB967EE194FFE55066E913B2915F9D6F2CB21560B0916A8769A3592C45EA80939870FC642607700B3A62BA8C7FAF8C4F4D923E42CB39214A301F51C82BEAE726EDE29D0A7A29639B3D97F4D998A646170E36BD4AE0841E49177791B76D1F87581522FFC68209B2C9244D599F2DF7B185CBE23B84BB0AAC075C1A11F3BDBC6BC0A4CF4018F2AFDB62325692A2FDF2968EAB380F81330CA150D296E0D6CFBA39849DFEF1B056EFA4951029F3597DFBBABD5E958D660BA9B3419C786B6C0272B4DDB58247A426CE87A6FD9D09B252802769547075208E685FB7ECBB9751549C298F0CDFC1EF84474BC2E124A4DC9FAD7057F2A7D198A3D1FCC99C05974ADCA85923E16543479627036250DB0DAF2155FD532C77A71BCE0F365AE95C2F2ADEC321DEB291D7D38E3044FF6CAABBFC655C29155FF6DA12B29B48B69C30505F5FE69226AD2B0038659DD95930B20898A031E5B17F1ED7257E57A9A11851966BE502C9D8B668F23AD6E0A0749166C0824FF71873B7168D7C8D4B98C892A66C368642729D9B9C074BB70C7FEF67C49F8515533C12932BCA7E00BFD108AFC38B5A04C11EF7417C43CC96BCC4978BEE399353F6F4BC5EB0AFDF8CB8C4338CFD7E08B917A36F85C0D265DECC63C7DC77445DDC0B137A4E5184BCD1A90201DC86BC83EFEBC157056AFAFB28002D9515E2524967B9B6360A0CF6D8622DD438C4762ACF704F9A22C5E5516B3C992506EEAC4A70747FA6C11C0D34A5FCD46C370FB2D6D6206F7955C2474096C019F06F946EC953ECC15EC62E7BF99324C074C8E2CFCBDE2BB545ACA0D632572542E09C600BDD26AFA3276B85F61B2C4533A68C2AF532A698846CC839F88F2BD7E5931D8D706CF97E1A9D37E12DC92416A7C67DC7142CC0512C43C89AFEEC7652ED5ABDC4566EEAB5253FC2901D3441AFC98A003A306981C89309B1610A3E9C85AE53B78ECF3ED8817D0489BEE4D41742F1BF6E448AC4803E00DB34E1DCF34D1D2B0FBE97B80CE45F628B0B86438F9E8AF54CA9B83652E27C63F0F137B6CDFC86A0BB1DE4A1A5B64816FEEAAC1E8F4D1BEC2D22318903636C70BA0E0C0B28F2696C55EB41C1AD17753F32E0C46E77A9DFAF31238D23F20F8BFE1DAEC76A6DF703B48225BF11F2B419B8CD5E45B0B19AB1267EF061AE66F312D548477FF6178D750667A953C4ED77D773AD9E62FBD9A6BC26EC97C314357D89490D91C5EFF7CF4C2F51E2E500C3728FEF78C523AB2E251C9E01DD8BD3CF0C919A13076F6FBCE15D769BDF6AFE2228FDC805E5D784619F7EE488753C72F5A169D82460300C7227F93FAA4549BDCFD3BCBD07297E1FB89DBB79584B7C14BC4BBDD0DFF97D6996417F00A7B6F28E99A3D7FDD46F936D47D26424CC70118C9DFB78D16E2177A321F9FD68B06D823993ADD32F72ACFE3609D4BDABD063DA9CF04E4E9B6024BD954F0D582BE0FDD5C3F1EA15B8949FF8C3B22D7ECFA9B8188A38D311CDF8C5853A53DFCF71141792E73C3FFFEC650304DB0FB7261904E9817D2CCC83E0C8FDA23F0D842DAB7F7196E8ABCFF85EE47AB265EBEFF13A23A246A39DB48447317585673599BC7D2A9AAC62BBB6F68BCFFF7F2D68C55970CC085CC0BB58BBB8E15E65187CDBEDE775F9FED522A845174071DBC3D421EA2235817A0EA403D84CF2DE601CE6B0C7B547FECF8F023E86096ED340513E4C5162915869E7DE4EC14E9D3D74A382AAC16EE543C081AE4A49EA0B71EFF360C359BEED5E7EAA8C8F6EB1B7B7554666E36793AFA685082B9BC6386A21C877D4AB65C39AE30827A22DEC412D6A1644F27FA91377212FFE154F0C4E76AB430D66716CD0044F47A83197BEE36A65E4508A9776FDEE040508543F099B7E65DB2DA780FFD24AAEB3CA3635605E993ADCF1231AE594B8C472022EC315EB7E6DC380EFE510D1A647C3DEBFFC49A461DF21CF7910C5D8621CF021F8F2F32D44F3EFEA89CA2F69E20D8A4F4EEE560971BDDEE300D5785310ECAE53E956E62ECC2C2B061CEBC572BC39CEA4EAA48BB2C2C429393F6C3E088C2504089BF8D7A11F16DD6FD7E68647DBD5F155758A6C21733755370CF5E454A2BE0BDA9FC81A6DCBB7047880E53BAC3E33E4C3DD65B24901636EDE4FC65AA072403599A67DFAE2C9FB938C0925C34F101D6C9299BD257BBD44C9DBBBA9D2F20FE434B21A160188BB7F225A425121F2B4AB1832CC20808612DE36C5B6C14EEA22496CF00A9BBD2190C8BC01E761A80BF0DD43B3F991526AB8351453C9B45538CEB4B13A3C15CC47C1457C8424A5199D0F179BAF48A8EE298AEF82064688155DB7A0FDDD36A9137E31A65ADBE00C57614E8A491AFA71C8E6237F93F91AE882616B5648690A3885F8B7BFC4462F9E2133A445C022BFFBE5D325E1FE1A8B7075E7D85CEA3371FFA2FD356D475A90809F6833EABAE2E10604D027CCDFDFDAAB063947F87375B927C00A48C9C531CD8A35B5539D0EFB861723B1D0ECEB361C94CC33FCC43921F24DAC648F64A87F96E26805E140C1A8D7D13533148E31FB43F3D9062DE5BA551AA4AFC27672F18E1235F4E0F7012007215036AE63BCA86F1E5B87146CA24D93E4BC3049073DCF1CD7139C318E78A0D934EE312A45B7FEE405ABC96015CCDA4D8683BC2E7F6162D3060D8AAF1079543E29FBAD5F4C99A76A0E093969B9A25AE211CC9A9F1EF48B6B67E2AE18152C00B58A485482E8D2BEE5DE71CD251DA7E7668118F61601FDE64782A4FEF787B632ECC214DF0123299462C0A5C2B1A0CB990DB559FEC08991CE0A05513F1F32F7F2F5CFA48AD68E86A4ED76299AA103F8856A536A6426F95DD2516B3C0880B42FF7EAB1CC78F8C4D79997E9043C8116694A7520846E7DF6003A422D89160E48DBD1214D9128976D9BFFB38C384FCE742512B739AF92EB9358DB18FE8D84D2B30B38FEA0BA117419B036701F1C02C87BB2B593FB1006665B9DB875FCFF481199584853D45D293E16795FF8272597700ED0892EFD3B37DA11950FF154B9551457FBB6BDF3BB22B44332BAD3365A023DE104CEC097D62DC5972610F579FA4F06B7F0EE23BC0E6CD7461258FB11417D14E1E6ABDD16A427362D97A0397535C128DA3123850B04B0EA595E5249D0040A40A4EAA02EA5E70D878BBE00533CFADBF1628A2FE64E679180F16970E9FC3B020FA2A3670F4119F7A0157A080786CFCE8931941FE47CAB747177CEB2D21974186DAFE99D263206D5B98FF8F6E80035B1B31F8D42AA7FEA86879CAA4D4591829D8770482FC44D904553C24B44AB6B5DCD50E87350A4CCE109B138D227AF34030A0B0607C40E812B281A5E90418696E521EFEA30C3D8DB95BE36A264BABFFA421E3FC0DEA2FC7342AB8FC023BC6315DDA512082276EB5ABD368251669BB72DDDEB25B2FEC3B5F8A892BCB5C8CD47BB58EF790E9B9D523517C42BD762E2A2F0ACD29295AFCEC9F3AF4C8CE6FE953D4AA3D2750F87EA82FEBB7D1B79DDFD3C1D5EFD509BFC7764880B49D0006CE58D06825E6F44E41414C1FE80CF463838ABC59CB5138CC780CD7C658B6B4787ABF06EC8D73C0DD08BB5CC6F0010EFB7213CF910071D2D2BEB5A456140E6A105FC7E2C11E1D85E0471ACD95308B5BC77B412F2836ACAC3F374BC0F3252D0A2F7B3CB1678402294B6227948B06008D2F71149E4DDD17D100C2C28FF938F65A28E6F85F8750E120007E84873CDF34EB3687651FF8C489C4D560DA4474EAAA1ABB36C892C41DC86E9FB40C207369DCA3C9A0F408F77D83AF9550775AEE17966DAFF16EEA69A9FA1CFB1910A5F97C703C1B7015BD12B86C0ECA9BE18CF4DD18340B05D5F5E3B602C667356E44E1DC40038B2C51155D96AB070D407CF675D31A6D702D8A24D91F64A1FA83AB1B67992E380968261CAF3077C004FE316CD34CB58EB99ED40B979876E04F2A04341EA286803E62F018A24669DA2BFD1C1AAFE992386A9D47202737DB46D93E75CAD9CE10A9956A01DC30A61F40BFC8F2F89BEA1AF32CD0BC1652176056D70D9198B7F2328B8CB17E24FC5DB16F95FB75146F8ADBF5940A4E42CF31D4E41B4748E9D48DBDBEEEBB0CC4C613C32380042D0CB387F2F95D9051EA3382A89B5F01E04F78B80CF3495D07BC65041AA920C92F105CC5C02BC2606C281449A14C887E62286321769176B6CD92B99C895A2FEF960C2C4C9A9EA825A5D0E80F0E048FB2EF8A04DF583409BA057D6828534CF9F7C64EC45ED705EB4F437EDBEF88A3AF4D5A5D116BB0B3A026DA2B9D67671F81313CCA36AE5A6DAC029008232F0530350F51003F4B51424991DBE56B6148690614DBE4DE2077EA8C2B9BF5EFFABDAF7D4B93ECC0370AF6E2E3EE15D97C2E15D7C7E53364F35227AFBBE8BE24C33554D88F5A90C322AEA9EBA9E1509E6DAF4E2C1BC1168D1C2CEA2CD73F8F1700C5E6394D1D52396F360BDC0693F0E808119FF1FBA987056F24F8E09AE5DFB72DECA16A5002F676E50C6304722C6371C3220F8CF65DF584CB1AED9BF75FEEEDC959A83AABF8CBF5BD5B1C5FD12DB924638DB61AB00464B2F92AB81FA5FAA4FC35D4396437FA77C734EA1D3DF0857BF9FFBEDF279C49323979D8FE9ED37E0C437C697BCB212C2D4F03FA72C91BEDA155772CEF0DDC16BFA7466823833890B0798FFC15EC05C9115CD230B00A4B9ECA2A8AD0AB3C448A77BB6FD49E3043812D124F802F400470D9CF0CE9143CACDF6E6158231A2D5A7499594C8F1835FD42AD62E1A4569B6CDC31E55A468C048D758D148BB56031E080766CAFE171F85FA2C6359146C8283E244730817F5763F6EC7C7F7A2E21FD70A830028941043B6C0A6B6D62DC0581122CF3B5F26FCFDE62F0B2426A83969FDA851B74BE8F39BAD0207AD47CAF7B0A2C09FF9EB0D604878BF89B1FF5B04B47152583F9D92FB2EDAD673D58F8198A6100FBAD8ABDD3E3FD25679587C85ADE200AC4A2C8B50895267D47FE60CFB48F9DF8AD3A452D166320C23E4C069C42EF40724E406DFABC42594390CE0BEB568D89571C6F6CA7AFF920DE21C24E19D9DD455357C3EE8F96EA4CDCC4FC914D096A63DAF7D0AD5C9FAD1F3D8FFF6098B2234CAC8F23962730377DFAC4298CF639918FC944A129450C23B6D303764946444966F1DF109B5F27015B8AC70FF848E922998D60F83E2DB487A5FA6734B8D7C92D061BC22D02DD6F91CB09C6E7137100E184C1F48C07BF690895D1B813B6AC1DDECE1A17F14DD2457F32222E3123B4C9C00157F3580B1F007DC2AA2DF3FB6169C27EDA601D29BE97FF246A3A7EFDC573B9320100804028153995A4C982C39B93D1B4016349A444E0EFB3A2AD178280B244B011008FD3D3962A48758007226308FEDECFFD68E90DB532B3C6E4AC851FA8ECBB8D9755F201BD75DBB1E0F90D6559F1551A396399998E2255D2DD55FFCC2E54DF080144B6488364FCBBAC7C1669B3338D543F6A7800B0BFB69CE0C19BF1743D5420CC01FA797A44A80C5F87794648396E5774FC3CD83957AFE1CF7817C499CB3C0783640BD6FDC0B8CAA3F094C7C455C82D0514F9AC5D9AA74D511676A913DD15E8773233E505D2F015963995FB6A03F12AA52FA560F9654939142FD47E479C5942949491A565E9A14FEBFFE3FF245366456B6AA44155590D31CA7C801039C4643AFE550A2A4C35F818EA8D7DDF1A79505759BDEF131AAC57F8F7C1C6711D72FC38282287AFF179BD0F3976BA8B191BFC81363A84911F9241E0FBBCF45261F07576BA7227092A7F8166BEED3507E27C2C1062441F98D99E6A899B127404EDF33B739038ED4754C551FDBC26BD40BB9CDCB067CB7B81F4264B4EB99A044E0750D455CD2AFE4C6E5A033C887330683C4B8873441FE11F17ED222565CD9D5DDED53FBF7724472C59622BC168EAA2391979B0D511F45DFF25907F01CDA7828BE0869A8EF7044F6B8AC3FA4874B6D869903AE09742BF953BFF03E2714554034AC5482DF1944C55E3ED8BEC7ED57D98C1A604A90CB826BB4E9C1F90903D2765DDC1FA070C7B9969B00F9636DC1A765F2A6FC7F05A4D3A0832B834B433458625D662AFFD12E4BCE19A815A010356BE5D09D99CE2FB7E5344C8185EFCD9D020B5439E29A7B10F3108C7BDC42DD0DF91BA9D7D0E2402C5016F574DA330E9745ED48A618C97C9E6DD5B59C3A1D098E8E6340C304CDE4F64B6D507D38F8602C55E41E1A0513D7586DE6693AE02806548FE0FB0C48FD6EBB43C2A6E3E4BFC6E8C6F25AB7DF1BCCD1BECA720E5DC9133A0ADD594E04A87D5F34EB9E05B9635F3CF224508F186A1F86C8B18FD51A7F0330BBE374C25D0A5F9110A97E9EC02C20A132EA4646199BE07A5610FA61FE58760B8791E7BA018CEAA50A3DA10AA59C1F79F9CB666D74AA7327261EAA43B75484EF0B31F64D1C4B5E669EABF1B1191500833A016522A9C94C5318D17FD3AEF38A54A38AB3A4DCFA358E3A6DF4B8F1B29F7359EA6C2BA55D2226D21377344F8A76733342F24A72E42C5D60FFA28518E09ACF8C5122FC2B0381F2BDDE5E15C97B07D6A66DD41A494B15F4AB989CE5F122E00037F478FD5F12EEADC66944F9B2E4B1F7332C2872E6D98BC054E7D470E6B30E7CF450C64E1F4FD2F1D0A060FD9437599D6BA854250F215459E9399276CF491FD2FD15566CE7A007C9F48E888D9003AA5459B52553A2FB265FD186056AA78D95ED73AD82736E7DDB12850657376B0A49E7063CE08477BF59D8C9EAA660A411EBF3D85AB3C557696EE0E189A5D0C70CA5F5FB895E941E92DD2DE7A1EA4F7B24FEC33DD85DABEC68CCA5D248BE7668370683D54FBE6DEDCA6A0923F0C054D9CB3A96427DFFBC22E5DB0F832FEE723D282AF23B531F80D971386978CB324BA1375D7286101BF7DF1B6FD1D5383C47F4C39E8A7E853A57B85EC7CAD5673CEB60F629DCA58141EBAAADE3D9DA279C127B2D01FF457A880150E67C794560D816F6161325BE91A31D7CFC466C84BF906A005F2463A484870600D614A36D4B581E67550964A6D06A37E424933AB96A49CACCDBA643F8A6ED2D616C7F17B8C0B417CC1A1DBAC9CFD23BA6F634D98D9949E773650FAA7F5C4660A857500CAC7CDB64C80DC2233F16DEA63BA350A8607807BA7CBA77E72DCF89E97B4BEEDD2971C3040D2E090D013E8DCE8CAFA7EC1C8E75DAE292D34DF843304D630453C7DF42B19D2A94266B1109BF75C6B19C82F139F91FD1057BBBDD0F7A386D37217F14C1DA5965B6B577AA7B2CDA05F1AAA3F8E7237018E874D1EE714AF10990D503B071DDC50552447B8EB3AD243005A60471A4C584578CE4CB96D0DD28FC8F439EB07DDCE53DD26237E8F00F50B8F16B591FB842755DA87F92E3877F9FED7B05C1549E7689847766B0443E3316CAE25020790FE70A7CDCA7C9DCA7B21DF97BCF0D6265B3A47FAD1BB6C5E79526CB731A8AFD33861AF040CC63D3F08BB162E7809816EF7D346FFFFA96C486368B01447BCCC619D9A82813B29375DCE8B2CBFFBC9AC0EE496AF9CFBC5EFB0B7D83CF4D48083BD0EC4B92E91260D0978127813CBB691F2F6871EE3BCC795B54F6421F165C84527B25D8AA2D5748970D0B29C61230D1A4291629965B0865B4EE5BE84BE0B7C04D68CB0DC3F4088EE98CFB1729FB055185201867EE972D8604F3B29EA087AE857060ADA99F31DD738D0735542162EAC8F3178AAE2FFB26065EB8850F134BA2429601E0AAF3A518ADE82BF6EB9A575FB88CC671C20083BCF0EC87734FF07F633E936F7FE07AD7FA54013F3011C99B54EF0039C224B330775A6FB2CBD4D52D427DB1BA07D74B0A57C7D68E3CF4F9008BABC56FD75BB60E4E29D37B1D25B6A4650B6830D1B5E803EE0F97F45CAA9F7C52648876A88F4AF7D8E90123B57B65DB6740DCB1FDBFE7DCF1707EA14361ABAA38EB769DDD0D10F5A29FD21FCDCC96B2FDF486A2B07CE6E8135D01E53975D85AC2E6238A7BD8806F2E20F336D91C790087522E8E2CA3590A8094B9026E24ECF3CC0BAAEC5D4957E726B556B83AB2710B851500B6EE9687D39905467574DEC41ACFE4B69E3FD62D5A49B5031EC10B7BD5529FCB30E5FC7E8C9D5D5664A35C6733F3EA7AA63E19F5961347A73D45AD0E1BFAE97BF4B37D15FA143EDA6BF24F84802F052045EC6AB6C383D92A78D08A64FA26E9920833528BA7256F33D5AA5BC478FCE565E99618B8B33A59D055108E6E4C1384933F2301A97C0B384894DC1E0C4A9E26513D73CDFF7496170D97B02F5EC399EA9A0A2833A9CCCA1F34A8BB916C4A53CA71C30E2607456F9FDE19E81BA1A9FE66CAF6836BD723E37C591DC90F432B3CBB1F3836A3803F9AAE18B3DAB416D538A4CB9C17A39D398E064E47CC0A9DB147B95C809FBFA5BD757E96E3F8D99AB96EDE9DA7F7CB97957F9FD793FF845A9E2FFFA3C520D7F3AF3D1CEA7EB0F87A77ADC677FE0F8FC8152FB24EC6805C2528C230C809DFAD0F49E8B00B2C001E5B7BDCF308F824EBBC9C38784A5DB074BD51C915D3F52A83ED47EDAC7AA034B95E40E8AA50F7F31199710DB9135B3986617EF244BED32D3B4470636168500875B1E953E8CE8102423446ED417FAAE64E500EFD5DCBC531F22E7685ABAAD83B241496DB0D4FD283C8F582E010790A3B1D12F3AF03D8B8C94CAFF230B5E9CE0C7C485EB1C0E40DF7490AF121A617E09F82A54DA51CBB5DE0B03E5B196A91B4B7BD02FED3B71F1268D06247980F46844BA9625DA0B4735FD36F226034DF7CDAF4C1DC36130790F7CC11E00EDAC6905456A278E77CA5F5C8DDCAAF4A234161A6767AF55E655F5D04846C78F54D606FE07BF9B7790491D63C57ED14AC2616703FB2E571A9ABCBBFCB49D0EA6CFA96D7EC7FB066A972E3F57D406F2D0B6620083C043BA45A60201C1809744845AADF969D97ACAC5884121D5564B18DB7C7EDF6633C61F14B104DE50126A7BA44F407F0F625DD04722A1D25374AA7D7A7CB2C7F29083CC84C7DEBC1B7709FB875CB0A81F6B5DEEDC9105238CFA60F298EA7E613F9197244FCBB0F749150EE39196E470F823B7D124720938EA023729AD5407FD202E07809C327F7700E859A26647F4F8A5A3EEF57B798B46D191EB8CD59701A9EC0E4B92C1DFA9C1205D379EECFBA323E10E3753540BC44D4F063E1B4BF1639C5D28A2A58F2EFB7F66C5BC960170C874D1B531676464B40E0DDD72761C379E07F75315320B67360EF98241837E85C699F084B47B866A7F0822AB0E14519A573F04844AB9C6CE3103FE1B446637D77FEE500254F86FC05EF3375A9CC6D47E4EC9B2DE8D86029BD48308D54C4A354E437108B5144BCD41723896C69D95F24F271BD3BF7B346B7D914B7CB4C0F03604072903F3E773B5F8C4A5AF2D695A6D864EB43C5D5D53AF6BF222F4A97C1475F1A2060B9C9DCFE31F4094BD845D57865945F1ADF67810543D2312A420BDEB705F67E5515A43823572A6F66244C48B038080658F1C5A7F82C15C106CDEB2D8152D231F3F9AB820E21271CABA1E8D08743EC82D0D87BE04EEC3AD2AE53D2298817D4B7D94F34F82A4B027B0C1D8968062471B6FC81798BCC3B1DBC3F8F168D4BFC511519F57E31742B3B7393122E8E2899F786137FED2EC90722492B6B1D7F448C0DE93BF6B9607E6C54DDDF267F34B2BED03721CB90612712D232B64B9B3F9BCAA2D65F6251B5B03D9CB5282B25D5544C70BF07F13A6A976B8ADF92ABAA487D4EEA89F455DAEBBC23152853ACD0C324F73CB459132A86BF7A14BA3878BBED927E98088FF8792EFBC2A7A8C65A1D016FF4BDB54F6DAA48F4400320D8B239C147FB7DEA12E082DCEDCBAC0DDE0D7F988B58417FF540FA0C43A6DD1FFB03C80354695EC6F511B60A34D77F4BCD8B2EF2CCF7B0261049E5C8DAB87BB5CEC6DCCC8E3269FAAB009B2A7C963DD0FE996800A01CF83BEB8EC8594B766FF4829F3CF4B1BCB7A288FB1F0527F4B2D3F4BDAF600F2E06739104B953F46BF635E7FBBF27E8F39D5DC78519E6AB374F6E2667B85A42EF8223C0C4C24CF2041352889D6B61D4AD75924FD3C3D61C57E08F50186D71F13ABF84CBB056100B5097C77CC7C888E1DC25E0B3DAC210B166C46EFB2F956AF09FE1D9D34ED925D807209A3CC0B560F47AE610BD5529439B127E8CDA7F80B252948A60C0217D573DF19C0B36BD3E3F4C15BA44E473FEBF52A499B8DF502DFFDBF64664EAE2A53F1F497C837766AA2E7CD02194860061F97A2C0F3A57BEE40DCA2A1E5A33BB8E38915168C49DB73A36791A42E6F295131740C258CD95206B65F2B80EE82106384F5F288FB9D6B60F7E21B1C28C159441D5F0439F53DE585213D6C0AA7D5E5D0358130AC0EB96B548721607D2D6E679C4CF5D779F441FC2CACB9AD8C584A8E773E0A3F40F863FC56CF0DFB36E0F8EE82947BCAB3BF8F6E42D8590E4927EAD637286ABAA9A8B4312F6D28BC6E83E27E01A4BC6635B927DB15287CD8BEE229D3BD8C686BB54E44578146B429EF5CF4B56199EF809D33ACC1F7DBD4A93D36312ACF20592BFBCC86B473D87757800CEB7F224C4CFC52DB64D4CEBA1D55969BAED3F23D9BB0B3ECCCD0C07A6A670BAC485C731F6E7FEF49FD9465333C2212FE6B9056A1613E107CE2396275467D62199093C50F0B52C6F3F03F15795522300B70AA64D8BC9CF47AF040E0FD4BB4882C87995372B18B6DA61E6DB85394901852B293D67FDA67C7827CEBC367C89B37B590B98651E5EEE4FEF3D06A281502A7C0854DE605E99BF4257FFF907AE57A4E365AA43F537C084E2DFC5958A311472E6FFCDFD4FAE5790A75ECFE9F788B8E9B9A644DF0AB3632D3198CE8BCFEDBE647F3C2F7EAA42E4E5022FDD1F24C9DCFC7489BD1F05B26ABF627CE462997C848E221993625544F000CA1C38A930598243A9DFAA7987ED0B49DF9F78EB83F7D5392F94C15E74A59829548A78F029FEAF16A2C0732CC992E9ED6A211C40A767AEC7E53E8CC6DDD4207CD1C1D7A93F21604B69F413BF8DFEA4CA268F960D0883E3B2B1C958DCD3034A2FBBA4BEA9F0BADEA0375A522B59F0FD8CFB12678186307DE2BA0239327451C89FE66CCC23E6C1B14A4EEE2DD9D4CE64099738D7F7EF969A231F5473BFFCC3B60260DEFF0214BDE9382DA4852D70D4F6D28BC01F96A4AB0AAD9724BF6973D45A4A0415087681D13541E0C47761B211D72F1FBD8437020E0CA30730F045D69BC9BCDCE0DFDB4333069D19B238422C3B9991B4AF9C614CF3314BB5020470B15730DB96A4723A721CF47AFF964DD8454CDC172742DCB8C829FA5B6C02C6C5F179955ADFDBDE99D1E629E5CC510FD0A6A60C1671BEEFD7F43F193FA1B17BE014BA69C7FED43CC26129FF510DA0E44BB6737BCCD9CC95247868942DCBDD80E4109ABC9F517862F757F005A6EBE60732468859CEBCE0FFAB4937605049FA9D80B1B79A4C886B8830299706C6F371F9CC0EC4942DEF731FE32E9C620BC305EC333073488BE9B5D4226F018E7698C2A830981251BB94F57A81FB9F2EF7BCB75AF4CF034A3B24E30B25676B9BF3A930567B1560772ABA5D09F2CE76B681B2B0AD719A7E2B44A910A4F7C7A975340F99A40BB6E5FBE88DF81F3200C547461641DCA5F04F035DB8BBDE5DFB08FA949C172D8D7BD94B594DD86EBE3D043BF73A02D10DEEC25CBFB6A9AE06636D23A0939D7C72E0D7EF7DC9069EC364FD6B566F8C625A2C23F237DE68F66EAEB7336F316D9B7F8EC2342F08CD79A37D090FFB11C703D60B9C9FEA755011ADC61EC22DD1C1C63E0989BCB99D458164CD582D68CBFDF14A638C349C4937A32767F7EBA16848EBEC4F18228041A043C3CEA94D06B64C7A2786754A2C9CF76FB83BE3DD0E5371180B7D9C2B1441ACC97503B81DE88A919F9EFBDE0356632AC091EF19F5BF6786C93097F431D9DFCDC8D86938853DAD3703AC77177D44FC3E4B3A1E47897DCD10183B3435AB0EDF6711E1B88251D21C59D383CD0926C6BC6863C4BE3CDD3C5C91C56B12095068376112218E0AE89E400CE469A812CEB45645B1B5B7FD3B8BDAC753DA262F556106853C560AA7BF557F6B1A0282F064059C61BA7497D2F41D0CAF3F30BD70DBAA8590ABD22AD12208962797FEC297499FF3F429B5138D2F7DBC931244D4BF79758309FDACE0D75BCF366946D9BDD767F64AC3D98A11B7EB277F2E48143A0F48D31561BFA7B2BFFF4EC62DBC6505655478BE055A6461B0F2401D71C0EB3AB288FDC43D0456DC8146FEE60066000C28A5BB6C11C4CF8165BF70CA49675A397CD8A92EFEE3AD79889F3FABB8758EB10238EBCA99E860781AFC1C31BF7AD24BFDDB5421E38562B6783116FE1D398F924EA1A78002BDB70F07308064FC3E5BE896F9ABEE1A8DC0396A5FE32C3CA863BBDF9114F90A3FDC8FE8FB7F001DB1538E48EE8121BDF2CBE1F0960DCCDA2360DB427B8AC69B6C18DEA2A6A505, afterDelayedMessagesRead=715466, gasRefunder=0xe64a54E2533Fd126C2E452c5fAb544d80E2E4eb5, prevMessageCount=53061248, newMessageCount=53061311 )TransparentUpgradeableProxy.STATICCALL( )-
Bridge.DELEGATECALL( )
-
TransparentUpgradeableProxy.86598a56( )-
Bridge.enqueueSequencerMessage( dataHash=9A0EC44367721076FE72C9E61A43B4B673B21EB9CF4E41C71EB1A43D3E2AA179, afterDelayedMessagesRead=715466, prevMessageCount=53061248, newMessageCount=53061311 ) => ( seqMessageIndex=125521, beforeAcc=233ABDC51FA34B9747833EEE7ECE439E308C8C584B9F8BC1D874894F1CB4FFB5, delayedAcc=900F028FB9208F4222A078F8F4962A647B7C91B02E0F2A4E705D0FC09B40621C, acc=97D0F8AC5EAE9F4347F399AD745B6F28A8C46177FFE9A9A2B447380DBC182527 )
-
TransparentUpgradeableProxy.7a88b107( )-
Bridge.submitBatchSpendingReport( sender=0xC1b634853Cb333D3aD8663715b08f41A3Aec47cc, messageDataHash=D9CC8BB3790B4ADBCAD8AFC5D5765185402B800DE710B397EE95E982D4DF3D16 ) => ( 715527 )
-
GasRefunder.onGasSpent( refundee=0xC1b634853Cb333D3aD8663715b08f41A3Aec47cc, gasUsed=202541, calldataSize=94852 ) => ( success=True )- ETH 0.067981199506234793
Arbitrum: Batch Submitter.CALL( )
- ETH 0.067981199506234793
addSequencerL2BatchFromOrigin[SequencerInbox (ln:154)]
NotOrigin[SequencerInbox (ln:161)]NotBatchPoster[SequencerInbox (ln:162)]formDataHash[SequencerInbox (ln:163)]packHeader[SequencerInbox (ln:318)]getTimeBounds[SequencerInbox (ln:300)]
concat[SequencerInbox (ln:319)]
addSequencerL2BatchImpl[SequencerInbox (ln:172)]DelayedBackwards[SequencerInbox (ln:345)]delayedMessageCount[SequencerInbox (ln:346)]DelayedTooFar[SequencerInbox (ln:346)]enqueueSequencerMessage[SequencerInbox (ln:347)]submitBatchSpendingReport[SequencerInbox (ln:365)]InboxMessageDelivered[SequencerInbox (ln:370)]
BadSequencerNumber[SequencerInbox (ln:174)]SequencerBatchDelivered[SequencerInbox (ln:175)]
File 1 of 5: TransparentUpgradeableProxy
File 2 of 5: TransparentUpgradeableProxy
File 3 of 5: GasRefunder
File 4 of 5: SequencerInbox
File 5 of 5: Bridge
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (proxy/transparent/TransparentUpgradeableProxy.sol)
pragma solidity ^0.8.0;
import "../ERC1967/ERC1967Proxy.sol";
/**
* @dev This contract implements a proxy that is upgradeable by an admin.
*
* To avoid https://medium.com/nomic-labs-blog/malicious-backdoors-in-ethereum-proxies-62629adf3357[proxy selector
* clashing], which can potentially be used in an attack, this contract uses the
* https://blog.openzeppelin.com/the-transparent-proxy-pattern/[transparent proxy pattern]. This pattern implies two
* things that go hand in hand:
*
* 1. If any account other than the admin calls the proxy, the call will be forwarded to the implementation, even if
* that call matches one of the admin functions exposed by the proxy itself.
* 2. If the admin calls the proxy, it can access the admin functions, but its calls will never be forwarded to the
* implementation. If the admin tries to call a function on the implementation it will fail with an error that says
* "admin cannot fallback to proxy target".
*
* These properties mean that the admin account can only be used for admin actions like upgrading the proxy or changing
* the admin, so it's best if it's a dedicated account that is not used for anything else. This will avoid headaches due
* to sudden errors when trying to call a function from the proxy implementation.
*
* Our recommendation is for the dedicated account to be an instance of the {ProxyAdmin} contract. If set up this way,
* you should think of the `ProxyAdmin` instance as the real administrative interface of your proxy.
*/
contract TransparentUpgradeableProxy is ERC1967Proxy {
/**
* @dev Initializes an upgradeable proxy managed by `_admin`, backed by the implementation at `_logic`, and
* optionally initialized with `_data` as explained in {ERC1967Proxy-constructor}.
*/
constructor(
address _logic,
address admin_,
bytes memory _data
) payable ERC1967Proxy(_logic, _data) {
assert(_ADMIN_SLOT == bytes32(uint256(keccak256("eip1967.proxy.admin")) - 1));
_changeAdmin(admin_);
}
/**
* @dev Modifier used internally that will delegate the call to the implementation unless the sender is the admin.
*/
modifier ifAdmin() {
if (msg.sender == _getAdmin()) {
_;
} else {
_fallback();
}
}
/**
* @dev Returns the current admin.
*
* NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyAdmin}.
*
* TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the
* https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
* `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103`
*/
function admin() external ifAdmin returns (address admin_) {
admin_ = _getAdmin();
}
/**
* @dev Returns the current implementation.
*
* NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyImplementation}.
*
* TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the
* https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
* `0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc`
*/
function implementation() external ifAdmin returns (address implementation_) {
implementation_ = _implementation();
}
/**
* @dev Changes the admin of the proxy.
*
* Emits an {AdminChanged} event.
*
* NOTE: Only the admin can call this function. See {ProxyAdmin-changeProxyAdmin}.
*/
function changeAdmin(address newAdmin) external virtual ifAdmin {
_changeAdmin(newAdmin);
}
/**
* @dev Upgrade the implementation of the proxy.
*
* NOTE: Only the admin can call this function. See {ProxyAdmin-upgrade}.
*/
function upgradeTo(address newImplementation) external ifAdmin {
_upgradeToAndCall(newImplementation, bytes(""), false);
}
/**
* @dev Upgrade the implementation of the proxy, and then call a function from the new implementation as specified
* by `data`, which should be an encoded function call. This is useful to initialize new storage variables in the
* proxied contract.
*
* NOTE: Only the admin can call this function. See {ProxyAdmin-upgradeAndCall}.
*/
function upgradeToAndCall(address newImplementation, bytes calldata data) external payable ifAdmin {
_upgradeToAndCall(newImplementation, data, true);
}
/**
* @dev Returns the current admin.
*/
function _admin() internal view virtual returns (address) {
return _getAdmin();
}
/**
* @dev Makes sure the admin cannot access the fallback function. See {Proxy-_beforeFallback}.
*/
function _beforeFallback() internal virtual override {
require(msg.sender != _getAdmin(), "TransparentUpgradeableProxy: admin cannot fallback to proxy target");
super._beforeFallback();
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (proxy/ERC1967/ERC1967Proxy.sol)
pragma solidity ^0.8.0;
import "../Proxy.sol";
import "./ERC1967Upgrade.sol";
/**
* @dev This contract implements an upgradeable proxy. It is upgradeable because calls are delegated to an
* implementation address that can be changed. This address is stored in storage in the location specified by
* https://eips.ethereum.org/EIPS/eip-1967[EIP1967], so that it doesn't conflict with the storage layout of the
* implementation behind the proxy.
*/
contract ERC1967Proxy is Proxy, ERC1967Upgrade {
/**
* @dev Initializes the upgradeable proxy with an initial implementation specified by `_logic`.
*
* If `_data` is nonempty, it's used as data in a delegate call to `_logic`. This will typically be an encoded
* function call, and allows initializating the storage of the proxy like a Solidity constructor.
*/
constructor(address _logic, bytes memory _data) payable {
assert(_IMPLEMENTATION_SLOT == bytes32(uint256(keccak256("eip1967.proxy.implementation")) - 1));
_upgradeToAndCall(_logic, _data, false);
}
/**
* @dev Returns the current implementation address.
*/
function _implementation() internal view virtual override returns (address impl) {
return ERC1967Upgrade._getImplementation();
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (proxy/Proxy.sol)
pragma solidity ^0.8.0;
/**
* @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM
* instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to
* be specified by overriding the virtual {_implementation} function.
*
* Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a
* different contract through the {_delegate} function.
*
* The success and return data of the delegated call will be returned back to the caller of the proxy.
*/
abstract contract Proxy {
/**
* @dev Delegates the current call to `implementation`.
*
* This function does not return to its internal call site, it will return directly to the external caller.
*/
function _delegate(address implementation) internal virtual {
assembly {
// Copy msg.data. We take full control of memory in this inline assembly
// block because it will not return to Solidity code. We overwrite the
// Solidity scratch pad at memory position 0.
calldatacopy(0, 0, calldatasize())
// Call the implementation.
// out and outsize are 0 because we don't know the size yet.
let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
// Copy the returned data.
returndatacopy(0, 0, returndatasize())
switch result
// delegatecall returns 0 on error.
case 0 {
revert(0, returndatasize())
}
default {
return(0, returndatasize())
}
}
}
/**
* @dev This is a virtual function that should be overriden so it returns the address to which the fallback function
* and {_fallback} should delegate.
*/
function _implementation() internal view virtual returns (address);
/**
* @dev Delegates the current call to the address returned by `_implementation()`.
*
* This function does not return to its internall call site, it will return directly to the external caller.
*/
function _fallback() internal virtual {
_beforeFallback();
_delegate(_implementation());
}
/**
* @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other
* function in the contract matches the call data.
*/
fallback() external payable virtual {
_fallback();
}
/**
* @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data
* is empty.
*/
receive() external payable virtual {
_fallback();
}
/**
* @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback`
* call, or as part of the Solidity `fallback` or `receive` functions.
*
* If overriden should call `super._beforeFallback()`.
*/
function _beforeFallback() internal virtual {}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (proxy/ERC1967/ERC1967Upgrade.sol)
pragma solidity ^0.8.2;
import "../beacon/IBeacon.sol";
import "../../interfaces/draft-IERC1822.sol";
import "../../utils/Address.sol";
import "../../utils/StorageSlot.sol";
/**
* @dev This abstract contract provides getters and event emitting update functions for
* https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
*
* _Available since v4.1._
*
* @custom:oz-upgrades-unsafe-allow delegatecall
*/
abstract contract ERC1967Upgrade {
// This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1
bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;
/**
* @dev Storage slot with the address of the current implementation.
* This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
* validated in the constructor.
*/
bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
/**
* @dev Emitted when the implementation is upgraded.
*/
event Upgraded(address indexed implementation);
/**
* @dev Returns the current implementation address.
*/
function _getImplementation() internal view returns (address) {
return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
}
/**
* @dev Stores a new address in the EIP1967 implementation slot.
*/
function _setImplementation(address newImplementation) private {
require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
}
/**
* @dev Perform implementation upgrade
*
* Emits an {Upgraded} event.
*/
function _upgradeTo(address newImplementation) internal {
_setImplementation(newImplementation);
emit Upgraded(newImplementation);
}
/**
* @dev Perform implementation upgrade with additional setup call.
*
* Emits an {Upgraded} event.
*/
function _upgradeToAndCall(
address newImplementation,
bytes memory data,
bool forceCall
) internal {
_upgradeTo(newImplementation);
if (data.length > 0 || forceCall) {
Address.functionDelegateCall(newImplementation, data);
}
}
/**
* @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.
*
* Emits an {Upgraded} event.
*/
function _upgradeToAndCallUUPS(
address newImplementation,
bytes memory data,
bool forceCall
) internal {
// Upgrades from old implementations will perform a rollback test. This test requires the new
// implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing
// this special case will break upgrade paths from old UUPS implementation to new ones.
if (StorageSlot.getBooleanSlot(_ROLLBACK_SLOT).value) {
_setImplementation(newImplementation);
} else {
try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {
require(slot == _IMPLEMENTATION_SLOT, "ERC1967Upgrade: unsupported proxiableUUID");
} catch {
revert("ERC1967Upgrade: new implementation is not UUPS");
}
_upgradeToAndCall(newImplementation, data, forceCall);
}
}
/**
* @dev Storage slot with the admin of the contract.
* This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is
* validated in the constructor.
*/
bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
/**
* @dev Emitted when the admin account has changed.
*/
event AdminChanged(address previousAdmin, address newAdmin);
/**
* @dev Returns the current admin.
*/
function _getAdmin() internal view returns (address) {
return StorageSlot.getAddressSlot(_ADMIN_SLOT).value;
}
/**
* @dev Stores a new address in the EIP1967 admin slot.
*/
function _setAdmin(address newAdmin) private {
require(newAdmin != address(0), "ERC1967: new admin is the zero address");
StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin;
}
/**
* @dev Changes the admin of the proxy.
*
* Emits an {AdminChanged} event.
*/
function _changeAdmin(address newAdmin) internal {
emit AdminChanged(_getAdmin(), newAdmin);
_setAdmin(newAdmin);
}
/**
* @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
* This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.
*/
bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
/**
* @dev Emitted when the beacon is upgraded.
*/
event BeaconUpgraded(address indexed beacon);
/**
* @dev Returns the current beacon.
*/
function _getBeacon() internal view returns (address) {
return StorageSlot.getAddressSlot(_BEACON_SLOT).value;
}
/**
* @dev Stores a new beacon in the EIP1967 beacon slot.
*/
function _setBeacon(address newBeacon) private {
require(Address.isContract(newBeacon), "ERC1967: new beacon is not a contract");
require(
Address.isContract(IBeacon(newBeacon).implementation()),
"ERC1967: beacon implementation is not a contract"
);
StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon;
}
/**
* @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does
* not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).
*
* Emits a {BeaconUpgraded} event.
*/
function _upgradeBeaconToAndCall(
address newBeacon,
bytes memory data,
bool forceCall
) internal {
_setBeacon(newBeacon);
emit BeaconUpgraded(newBeacon);
if (data.length > 0 || forceCall) {
Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);
}
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol)
pragma solidity ^0.8.0;
/**
* @dev This is the interface that {BeaconProxy} expects of its beacon.
*/
interface IBeacon {
/**
* @dev Must return an address that can be used as a delegate call target.
*
* {BeaconProxy} will check that this address is a contract.
*/
function implementation() external view returns (address);
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol)
pragma solidity ^0.8.0;
/**
* @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified
* proxy whose upgrades are fully controlled by the current implementation.
*/
interface IERC1822Proxiable {
/**
* @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation
* address.
*
* IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
* bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
* function revert if invoked through a proxy.
*/
function proxiableUUID() external view returns (bytes32);
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
require(isContract(target), "Address: delegate call to non-contract");
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/StorageSlot.sol)
pragma solidity ^0.8.0;
/**
* @dev Library for reading and writing primitive types to specific storage slots.
*
* Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
* This library helps with reading and writing to such slots without the need for inline assembly.
*
* The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
*
* Example usage to set ERC1967 implementation slot:
* ```
* contract ERC1967 {
* bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
*
* function _getImplementation() internal view returns (address) {
* return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
* }
*
* function _setImplementation(address newImplementation) internal {
* require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
* StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
* }
* }
* ```
*
* _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._
*/
library StorageSlot {
struct AddressSlot {
address value;
}
struct BooleanSlot {
bool value;
}
struct Bytes32Slot {
bytes32 value;
}
struct Uint256Slot {
uint256 value;
}
/**
* @dev Returns an `AddressSlot` with member `value` located at `slot`.
*/
function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BooleanSlot` with member `value` located at `slot`.
*/
function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
*/
function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Uint256Slot` with member `value` located at `slot`.
*/
function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
assembly {
r.slot := slot
}
}
}
File 2 of 5: TransparentUpgradeableProxy
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (proxy/transparent/TransparentUpgradeableProxy.sol)
pragma solidity ^0.8.0;
import "../ERC1967/ERC1967Proxy.sol";
/**
* @dev This contract implements a proxy that is upgradeable by an admin.
*
* To avoid https://medium.com/nomic-labs-blog/malicious-backdoors-in-ethereum-proxies-62629adf3357[proxy selector
* clashing], which can potentially be used in an attack, this contract uses the
* https://blog.openzeppelin.com/the-transparent-proxy-pattern/[transparent proxy pattern]. This pattern implies two
* things that go hand in hand:
*
* 1. If any account other than the admin calls the proxy, the call will be forwarded to the implementation, even if
* that call matches one of the admin functions exposed by the proxy itself.
* 2. If the admin calls the proxy, it can access the admin functions, but its calls will never be forwarded to the
* implementation. If the admin tries to call a function on the implementation it will fail with an error that says
* "admin cannot fallback to proxy target".
*
* These properties mean that the admin account can only be used for admin actions like upgrading the proxy or changing
* the admin, so it's best if it's a dedicated account that is not used for anything else. This will avoid headaches due
* to sudden errors when trying to call a function from the proxy implementation.
*
* Our recommendation is for the dedicated account to be an instance of the {ProxyAdmin} contract. If set up this way,
* you should think of the `ProxyAdmin` instance as the real administrative interface of your proxy.
*/
contract TransparentUpgradeableProxy is ERC1967Proxy {
/**
* @dev Initializes an upgradeable proxy managed by `_admin`, backed by the implementation at `_logic`, and
* optionally initialized with `_data` as explained in {ERC1967Proxy-constructor}.
*/
constructor(
address _logic,
address admin_,
bytes memory _data
) payable ERC1967Proxy(_logic, _data) {
assert(_ADMIN_SLOT == bytes32(uint256(keccak256("eip1967.proxy.admin")) - 1));
_changeAdmin(admin_);
}
/**
* @dev Modifier used internally that will delegate the call to the implementation unless the sender is the admin.
*/
modifier ifAdmin() {
if (msg.sender == _getAdmin()) {
_;
} else {
_fallback();
}
}
/**
* @dev Returns the current admin.
*
* NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyAdmin}.
*
* TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the
* https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
* `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103`
*/
function admin() external ifAdmin returns (address admin_) {
admin_ = _getAdmin();
}
/**
* @dev Returns the current implementation.
*
* NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyImplementation}.
*
* TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the
* https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
* `0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc`
*/
function implementation() external ifAdmin returns (address implementation_) {
implementation_ = _implementation();
}
/**
* @dev Changes the admin of the proxy.
*
* Emits an {AdminChanged} event.
*
* NOTE: Only the admin can call this function. See {ProxyAdmin-changeProxyAdmin}.
*/
function changeAdmin(address newAdmin) external virtual ifAdmin {
_changeAdmin(newAdmin);
}
/**
* @dev Upgrade the implementation of the proxy.
*
* NOTE: Only the admin can call this function. See {ProxyAdmin-upgrade}.
*/
function upgradeTo(address newImplementation) external ifAdmin {
_upgradeToAndCall(newImplementation, bytes(""), false);
}
/**
* @dev Upgrade the implementation of the proxy, and then call a function from the new implementation as specified
* by `data`, which should be an encoded function call. This is useful to initialize new storage variables in the
* proxied contract.
*
* NOTE: Only the admin can call this function. See {ProxyAdmin-upgradeAndCall}.
*/
function upgradeToAndCall(address newImplementation, bytes calldata data) external payable ifAdmin {
_upgradeToAndCall(newImplementation, data, true);
}
/**
* @dev Returns the current admin.
*/
function _admin() internal view virtual returns (address) {
return _getAdmin();
}
/**
* @dev Makes sure the admin cannot access the fallback function. See {Proxy-_beforeFallback}.
*/
function _beforeFallback() internal virtual override {
require(msg.sender != _getAdmin(), "TransparentUpgradeableProxy: admin cannot fallback to proxy target");
super._beforeFallback();
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (proxy/ERC1967/ERC1967Proxy.sol)
pragma solidity ^0.8.0;
import "../Proxy.sol";
import "./ERC1967Upgrade.sol";
/**
* @dev This contract implements an upgradeable proxy. It is upgradeable because calls are delegated to an
* implementation address that can be changed. This address is stored in storage in the location specified by
* https://eips.ethereum.org/EIPS/eip-1967[EIP1967], so that it doesn't conflict with the storage layout of the
* implementation behind the proxy.
*/
contract ERC1967Proxy is Proxy, ERC1967Upgrade {
/**
* @dev Initializes the upgradeable proxy with an initial implementation specified by `_logic`.
*
* If `_data` is nonempty, it's used as data in a delegate call to `_logic`. This will typically be an encoded
* function call, and allows initializating the storage of the proxy like a Solidity constructor.
*/
constructor(address _logic, bytes memory _data) payable {
assert(_IMPLEMENTATION_SLOT == bytes32(uint256(keccak256("eip1967.proxy.implementation")) - 1));
_upgradeToAndCall(_logic, _data, false);
}
/**
* @dev Returns the current implementation address.
*/
function _implementation() internal view virtual override returns (address impl) {
return ERC1967Upgrade._getImplementation();
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (proxy/Proxy.sol)
pragma solidity ^0.8.0;
/**
* @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM
* instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to
* be specified by overriding the virtual {_implementation} function.
*
* Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a
* different contract through the {_delegate} function.
*
* The success and return data of the delegated call will be returned back to the caller of the proxy.
*/
abstract contract Proxy {
/**
* @dev Delegates the current call to `implementation`.
*
* This function does not return to its internal call site, it will return directly to the external caller.
*/
function _delegate(address implementation) internal virtual {
assembly {
// Copy msg.data. We take full control of memory in this inline assembly
// block because it will not return to Solidity code. We overwrite the
// Solidity scratch pad at memory position 0.
calldatacopy(0, 0, calldatasize())
// Call the implementation.
// out and outsize are 0 because we don't know the size yet.
let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
// Copy the returned data.
returndatacopy(0, 0, returndatasize())
switch result
// delegatecall returns 0 on error.
case 0 {
revert(0, returndatasize())
}
default {
return(0, returndatasize())
}
}
}
/**
* @dev This is a virtual function that should be overriden so it returns the address to which the fallback function
* and {_fallback} should delegate.
*/
function _implementation() internal view virtual returns (address);
/**
* @dev Delegates the current call to the address returned by `_implementation()`.
*
* This function does not return to its internall call site, it will return directly to the external caller.
*/
function _fallback() internal virtual {
_beforeFallback();
_delegate(_implementation());
}
/**
* @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other
* function in the contract matches the call data.
*/
fallback() external payable virtual {
_fallback();
}
/**
* @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data
* is empty.
*/
receive() external payable virtual {
_fallback();
}
/**
* @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback`
* call, or as part of the Solidity `fallback` or `receive` functions.
*
* If overriden should call `super._beforeFallback()`.
*/
function _beforeFallback() internal virtual {}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (proxy/ERC1967/ERC1967Upgrade.sol)
pragma solidity ^0.8.2;
import "../beacon/IBeacon.sol";
import "../../interfaces/draft-IERC1822.sol";
import "../../utils/Address.sol";
import "../../utils/StorageSlot.sol";
/**
* @dev This abstract contract provides getters and event emitting update functions for
* https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
*
* _Available since v4.1._
*
* @custom:oz-upgrades-unsafe-allow delegatecall
*/
abstract contract ERC1967Upgrade {
// This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1
bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;
/**
* @dev Storage slot with the address of the current implementation.
* This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
* validated in the constructor.
*/
bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
/**
* @dev Emitted when the implementation is upgraded.
*/
event Upgraded(address indexed implementation);
/**
* @dev Returns the current implementation address.
*/
function _getImplementation() internal view returns (address) {
return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
}
/**
* @dev Stores a new address in the EIP1967 implementation slot.
*/
function _setImplementation(address newImplementation) private {
require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
}
/**
* @dev Perform implementation upgrade
*
* Emits an {Upgraded} event.
*/
function _upgradeTo(address newImplementation) internal {
_setImplementation(newImplementation);
emit Upgraded(newImplementation);
}
/**
* @dev Perform implementation upgrade with additional setup call.
*
* Emits an {Upgraded} event.
*/
function _upgradeToAndCall(
address newImplementation,
bytes memory data,
bool forceCall
) internal {
_upgradeTo(newImplementation);
if (data.length > 0 || forceCall) {
Address.functionDelegateCall(newImplementation, data);
}
}
/**
* @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.
*
* Emits an {Upgraded} event.
*/
function _upgradeToAndCallUUPS(
address newImplementation,
bytes memory data,
bool forceCall
) internal {
// Upgrades from old implementations will perform a rollback test. This test requires the new
// implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing
// this special case will break upgrade paths from old UUPS implementation to new ones.
if (StorageSlot.getBooleanSlot(_ROLLBACK_SLOT).value) {
_setImplementation(newImplementation);
} else {
try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {
require(slot == _IMPLEMENTATION_SLOT, "ERC1967Upgrade: unsupported proxiableUUID");
} catch {
revert("ERC1967Upgrade: new implementation is not UUPS");
}
_upgradeToAndCall(newImplementation, data, forceCall);
}
}
/**
* @dev Storage slot with the admin of the contract.
* This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is
* validated in the constructor.
*/
bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
/**
* @dev Emitted when the admin account has changed.
*/
event AdminChanged(address previousAdmin, address newAdmin);
/**
* @dev Returns the current admin.
*/
function _getAdmin() internal view returns (address) {
return StorageSlot.getAddressSlot(_ADMIN_SLOT).value;
}
/**
* @dev Stores a new address in the EIP1967 admin slot.
*/
function _setAdmin(address newAdmin) private {
require(newAdmin != address(0), "ERC1967: new admin is the zero address");
StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin;
}
/**
* @dev Changes the admin of the proxy.
*
* Emits an {AdminChanged} event.
*/
function _changeAdmin(address newAdmin) internal {
emit AdminChanged(_getAdmin(), newAdmin);
_setAdmin(newAdmin);
}
/**
* @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
* This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.
*/
bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
/**
* @dev Emitted when the beacon is upgraded.
*/
event BeaconUpgraded(address indexed beacon);
/**
* @dev Returns the current beacon.
*/
function _getBeacon() internal view returns (address) {
return StorageSlot.getAddressSlot(_BEACON_SLOT).value;
}
/**
* @dev Stores a new beacon in the EIP1967 beacon slot.
*/
function _setBeacon(address newBeacon) private {
require(Address.isContract(newBeacon), "ERC1967: new beacon is not a contract");
require(
Address.isContract(IBeacon(newBeacon).implementation()),
"ERC1967: beacon implementation is not a contract"
);
StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon;
}
/**
* @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does
* not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).
*
* Emits a {BeaconUpgraded} event.
*/
function _upgradeBeaconToAndCall(
address newBeacon,
bytes memory data,
bool forceCall
) internal {
_setBeacon(newBeacon);
emit BeaconUpgraded(newBeacon);
if (data.length > 0 || forceCall) {
Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);
}
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol)
pragma solidity ^0.8.0;
/**
* @dev This is the interface that {BeaconProxy} expects of its beacon.
*/
interface IBeacon {
/**
* @dev Must return an address that can be used as a delegate call target.
*
* {BeaconProxy} will check that this address is a contract.
*/
function implementation() external view returns (address);
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol)
pragma solidity ^0.8.0;
/**
* @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified
* proxy whose upgrades are fully controlled by the current implementation.
*/
interface IERC1822Proxiable {
/**
* @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation
* address.
*
* IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
* bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
* function revert if invoked through a proxy.
*/
function proxiableUUID() external view returns (bytes32);
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
require(isContract(target), "Address: delegate call to non-contract");
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/StorageSlot.sol)
pragma solidity ^0.8.0;
/**
* @dev Library for reading and writing primitive types to specific storage slots.
*
* Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
* This library helps with reading and writing to such slots without the need for inline assembly.
*
* The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
*
* Example usage to set ERC1967 implementation slot:
* ```
* contract ERC1967 {
* bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
*
* function _getImplementation() internal view returns (address) {
* return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
* }
*
* function _setImplementation(address newImplementation) internal {
* require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
* StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
* }
* }
* ```
*
* _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._
*/
library StorageSlot {
struct AddressSlot {
address value;
}
struct BooleanSlot {
bool value;
}
struct Bytes32Slot {
bytes32 value;
}
struct Uint256Slot {
uint256 value;
}
/**
* @dev Returns an `AddressSlot` with member `value` located at `slot`.
*/
function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BooleanSlot` with member `value` located at `slot`.
*/
function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
*/
function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Uint256Slot` with member `value` located at `slot`.
*/
function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
assembly {
r.slot := slot
}
}
}
File 3 of 5: GasRefunder
// SPDX-License-Identifier: Apache-2.0
/*
* Copyright 2021, Offchain Labs, Inc.
*
* 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.
*/
pragma solidity ^0.8.7;
import "./IGasRefunder.sol";
import "@openzeppelin/contracts-0.8/access/Ownable.sol";
contract GasRefunder is IGasRefunder, Ownable {
mapping(address => bool) public allowedContracts;
mapping(address => bool) public allowedRefundees;
address public disallower;
struct CommonParameters {
uint128 maxRefundeeBalance;
uint32 extraGasMargin;
uint8 calldataCost;
uint64 maxGasTip;
uint64 maxGasCost;
uint32 maxSingleGasUsage;
}
CommonParameters public commonParams;
enum CommonParameterKey {
MAX_REFUNDEE_BALANCE,
EXTRA_GAS_MARGIN,
CALLDATA_COST,
MAX_GAS_TIP,
MAX_GAS_COST,
MAX_SINGLE_GAS_USAGE
}
enum RefundDenyReason {
CONTRACT_NOT_ALLOWED,
REFUNDEE_NOT_ALLOWED,
REFUNDEE_ABOVE_MAX_BALANCE,
OUT_OF_FUNDS
}
event RefundedGasCosts(
address indexed refundee,
address indexed contractAddress,
bool indexed success,
uint256 gas,
uint256 gasPrice,
uint256 amountPaid
);
event RefundGasCostsDenied(
address indexed refundee,
address indexed contractAddress,
RefundDenyReason indexed reason,
uint256 gas
);
event Deposited(address sender, uint256 amount);
event Withdrawn(address initiator, address destination, uint256 amount);
event ContractAllowedSet(address indexed addr, bool indexed allowed);
event RefundeeAllowedSet(address indexed addr, bool indexed allowed);
event DisallowerSet(address indexed addr);
event CommonParameterSet(CommonParameterKey indexed parameter, uint256 value);
constructor() Ownable() {
commonParams = CommonParameters({
maxRefundeeBalance: 0, // no limit
extraGasMargin: 4000, // 4k gas
calldataCost: 12, // Between 4 for zero bytes and 16 for non-zero bytes
maxGasTip: 2 gwei,
maxGasCost: 120 gwei,
maxSingleGasUsage: 2e6 // 2 million gas
});
}
function setDisallower(address addr) external onlyOwner {
disallower = addr;
emit DisallowerSet(addr);
}
function allowContracts(address[] calldata addresses) external onlyOwner {
setContractsAllowedImpl(addresses, true);
}
function disallowContracts(address[] calldata addresses) external {
require(msg.sender == owner() || msg.sender == disallower, "NOT_AUTHORIZED");
setContractsAllowedImpl(addresses, false);
}
function setContractsAllowedImpl(address[] calldata addresses, bool allow) internal {
for (uint256 i = 0; i < addresses.length; i++) {
address addr = addresses[i];
allowedContracts[addr] = allow;
emit ContractAllowedSet(addr, allow);
}
}
function allowRefundees(address[] calldata addresses) external onlyOwner {
setRefundeesAllowedImpl(addresses, true);
}
function disallowRefundees(address[] calldata addresses) external {
require(msg.sender == owner() || msg.sender == disallower, "NOT_AUTHORIZED");
setRefundeesAllowedImpl(addresses, false);
}
function setRefundeesAllowedImpl(address[] calldata addresses, bool allow) internal {
for (uint256 i = 0; i < addresses.length; i++) {
address addr = addresses[i];
allowedRefundees[addr] = allow;
emit RefundeeAllowedSet(addr, allow);
}
}
function setMaxRefundeeBalance(uint128 newValue) external onlyOwner {
commonParams.maxRefundeeBalance = newValue;
emit CommonParameterSet(CommonParameterKey.MAX_REFUNDEE_BALANCE, newValue);
}
function setExtraGasMargin(uint32 newValue) external onlyOwner {
commonParams.extraGasMargin = newValue;
emit CommonParameterSet(CommonParameterKey.EXTRA_GAS_MARGIN, newValue);
}
function setCalldataCost(uint8 newValue) external onlyOwner {
commonParams.calldataCost = newValue;
emit CommonParameterSet(CommonParameterKey.CALLDATA_COST, newValue);
}
function setMaxGasTip(uint64 newValue) external onlyOwner {
commonParams.maxGasTip = newValue;
emit CommonParameterSet(CommonParameterKey.MAX_GAS_TIP, newValue);
}
function setMaxGasCost(uint64 newValue) external onlyOwner {
commonParams.maxGasCost = newValue;
emit CommonParameterSet(CommonParameterKey.MAX_GAS_COST, newValue);
}
function setMaxSingleGasUsage(uint32 newValue) external onlyOwner {
commonParams.maxSingleGasUsage = newValue;
emit CommonParameterSet(CommonParameterKey.MAX_SINGLE_GAS_USAGE, newValue);
}
receive() external payable {
emit Deposited(msg.sender, msg.value);
}
function withdraw(address payable destination, uint256 amount) external onlyOwner {
// It's expected that destination is an EOA
(bool success, ) = destination.call{ value: amount }("");
require(success, "WITHDRAW_FAILED");
emit Withdrawn(msg.sender, destination, amount);
}
function onGasSpent(
address payable refundee,
uint256 gasUsed,
uint256 calldataSize
) external override returns (bool success) {
uint256 startGasLeft = gasleft();
uint256 ownBalance = address(this).balance;
if (ownBalance == 0) {
emit RefundGasCostsDenied(refundee, msg.sender, RefundDenyReason.OUT_OF_FUNDS, gasUsed);
return false;
}
if (!allowedContracts[msg.sender]) {
emit RefundGasCostsDenied(
refundee,
msg.sender,
RefundDenyReason.CONTRACT_NOT_ALLOWED,
gasUsed
);
return false;
}
if (!allowedRefundees[refundee]) {
emit RefundGasCostsDenied(
refundee,
msg.sender,
RefundDenyReason.REFUNDEE_NOT_ALLOWED,
gasUsed
);
return false;
}
uint256 estGasPrice = block.basefee + commonParams.maxGasTip;
if (tx.gasprice < estGasPrice) {
estGasPrice = tx.gasprice;
}
if (commonParams.maxGasCost != 0 && estGasPrice > commonParams.maxGasCost) {
estGasPrice = commonParams.maxGasCost;
}
// Retrieve these variables before measuring gasleft()
uint256 refundeeBalance = refundee.balance;
uint256 maxRefundeeBalance = commonParams.maxRefundeeBalance;
uint256 maxSingleGasUsage = commonParams.maxSingleGasUsage;
// Add in a bit of a buffer for the tx costs not measured with gasleft
gasUsed +=
startGasLeft +
commonParams.extraGasMargin +
(calldataSize * commonParams.calldataCost);
// Split this up into two statements so that gasleft() comes after the storage loads
gasUsed -= gasleft();
if (maxSingleGasUsage != 0 && gasUsed > maxSingleGasUsage) {
gasUsed = maxSingleGasUsage;
}
uint256 refundAmount = estGasPrice * gasUsed;
if (maxRefundeeBalance != 0 && refundeeBalance + refundAmount > maxRefundeeBalance) {
if (refundeeBalance > maxRefundeeBalance) {
// The refundee is already above their max balance
emit RefundGasCostsDenied(
refundee,
msg.sender,
RefundDenyReason.REFUNDEE_ABOVE_MAX_BALANCE,
gasUsed
);
return false;
} else {
refundAmount = maxRefundeeBalance - refundeeBalance;
}
}
if (refundAmount > ownBalance) {
refundAmount = ownBalance;
}
// It's expected that refundee is an EOA
(success, ) = refundee.call{ value: refundAmount }("");
emit RefundedGasCosts(refundee, msg.sender, success, gasUsed, estGasPrice, refundAmount);
}
}
// SPDX-License-Identifier: Apache-2.0
/*
* Copyright 2021, Offchain Labs, Inc.
*
* 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.
*/
pragma solidity >=0.6.11 <0.7.0 || >=0.8.7 <0.9.0;
interface IGasRefunder {
function onGasSpent(
address payable spender,
uint256 gasUsed,
uint256 calldataSize
) external returns (bool success);
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)
pragma solidity ^0.8.0;
import "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor() {
_transferOwnership(_msgSender());
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
_;
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions anymore. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby removing any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
pragma solidity ^0.8.0;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}
File 4 of 5: SequencerInbox
// Copyright 2021-2022, Offchain Labs, Inc.
// For license information, see https://github.com/nitro/blob/master/LICENSE
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;
import {
AlreadyInit,
HadZeroInit,
NotOrigin,
DataTooLarge,
NotRollup,
DelayedBackwards,
DelayedTooFar,
ForceIncludeBlockTooSoon,
ForceIncludeTimeTooSoon,
IncorrectMessagePreimage,
NotBatchPoster,
BadSequencerNumber,
DataNotAuthenticated,
AlreadyValidDASKeyset,
NoSuchKeyset,
NotForked
} from "../libraries/Error.sol";
import "./IBridge.sol";
import "./IInbox.sol";
import "./ISequencerInbox.sol";
import "../rollup/IRollupLogic.sol";
import "./Messages.sol";
import {L1MessageType_batchPostingReport} from "../libraries/MessageTypes.sol";
import {GasRefundEnabled, IGasRefunder} from "../libraries/IGasRefunder.sol";
import "../libraries/DelegateCallAware.sol";
import {MAX_DATA_SIZE} from "../libraries/Constants.sol";
/**
* @title Accepts batches from the sequencer and adds them to the rollup inbox.
* @notice Contains the inbox accumulator which is the ordering of all data and transactions to be processed by the rollup.
* As part of submitting a batch the sequencer is also expected to include items enqueued
* in the delayed inbox (Bridge.sol). If items in the delayed inbox are not included by a
* sequencer within a time limit they can be force included into the rollup inbox by anyone.
*/
contract SequencerInbox is DelegateCallAware, GasRefundEnabled, ISequencerInbox {
uint256 public totalDelayedMessagesRead;
IBridge public bridge;
/// @inheritdoc ISequencerInbox
uint256 public constant HEADER_LENGTH = 40;
/// @inheritdoc ISequencerInbox
bytes1 public constant DATA_AUTHENTICATED_FLAG = 0x40;
IOwnable public rollup;
mapping(address => bool) public isBatchPoster;
ISequencerInbox.MaxTimeVariation public maxTimeVariation;
mapping(bytes32 => DasKeySetInfo) public dasKeySetInfo;
modifier onlyRollupOwner() {
if (msg.sender != rollup.owner()) revert NotOwner(msg.sender, address(rollup));
_;
}
uint256 internal immutable deployTimeChainId = block.chainid;
function _chainIdChanged() internal view returns (bool) {
return deployTimeChainId != block.chainid;
}
function initialize(
IBridge bridge_,
ISequencerInbox.MaxTimeVariation calldata maxTimeVariation_
) external onlyDelegated {
if (bridge != IBridge(address(0))) revert AlreadyInit();
if (bridge_ == IBridge(address(0))) revert HadZeroInit();
bridge = bridge_;
rollup = bridge_.rollup();
maxTimeVariation = maxTimeVariation_;
}
function getTimeBounds() internal view virtual returns (TimeBounds memory) {
TimeBounds memory bounds;
if (block.timestamp > maxTimeVariation.delaySeconds) {
bounds.minTimestamp = uint64(block.timestamp - maxTimeVariation.delaySeconds);
}
bounds.maxTimestamp = uint64(block.timestamp + maxTimeVariation.futureSeconds);
if (block.number > maxTimeVariation.delayBlocks) {
bounds.minBlockNumber = uint64(block.number - maxTimeVariation.delayBlocks);
}
bounds.maxBlockNumber = uint64(block.number + maxTimeVariation.futureBlocks);
return bounds;
}
/// @inheritdoc ISequencerInbox
function removeDelayAfterFork() external {
if (!_chainIdChanged()) revert NotForked();
maxTimeVariation = ISequencerInbox.MaxTimeVariation({
delayBlocks: 1,
futureBlocks: 1,
delaySeconds: 1,
futureSeconds: 1
});
}
/// @inheritdoc ISequencerInbox
function forceInclusion(
uint256 _totalDelayedMessagesRead,
uint8 kind,
uint64[2] calldata l1BlockAndTime,
uint256 baseFeeL1,
address sender,
bytes32 messageDataHash
) external {
if (_totalDelayedMessagesRead <= totalDelayedMessagesRead) revert DelayedBackwards();
bytes32 messageHash = Messages.messageHash(
kind,
sender,
l1BlockAndTime[0],
l1BlockAndTime[1],
_totalDelayedMessagesRead - 1,
baseFeeL1,
messageDataHash
);
// Can only force-include after the Sequencer-only window has expired.
if (l1BlockAndTime[0] + maxTimeVariation.delayBlocks >= block.number)
revert ForceIncludeBlockTooSoon();
if (l1BlockAndTime[1] + maxTimeVariation.delaySeconds >= block.timestamp)
revert ForceIncludeTimeTooSoon();
// Verify that message hash represents the last message sequence of delayed message to be included
bytes32 prevDelayedAcc = 0;
if (_totalDelayedMessagesRead > 1) {
prevDelayedAcc = bridge.delayedInboxAccs(_totalDelayedMessagesRead - 2);
}
if (
bridge.delayedInboxAccs(_totalDelayedMessagesRead - 1) !=
Messages.accumulateInboxMessage(prevDelayedAcc, messageHash)
) revert IncorrectMessagePreimage();
(bytes32 dataHash, TimeBounds memory timeBounds) = formEmptyDataHash(
_totalDelayedMessagesRead
);
uint256 __totalDelayedMessagesRead = _totalDelayedMessagesRead;
uint256 prevSeqMsgCount = bridge.sequencerReportedSubMessageCount();
uint256 newSeqMsgCount = prevSeqMsgCount +
_totalDelayedMessagesRead -
totalDelayedMessagesRead;
(
uint256 seqMessageIndex,
bytes32 beforeAcc,
bytes32 delayedAcc,
bytes32 afterAcc
) = addSequencerL2BatchImpl(
dataHash,
__totalDelayedMessagesRead,
0,
prevSeqMsgCount,
newSeqMsgCount
);
emit SequencerBatchDelivered(
seqMessageIndex,
beforeAcc,
afterAcc,
delayedAcc,
totalDelayedMessagesRead,
timeBounds,
BatchDataLocation.NoData
);
}
/// @dev Deprecated in favor of the variant specifying message counts for consistency
function addSequencerL2BatchFromOrigin(
uint256 sequenceNumber,
bytes calldata data,
uint256 afterDelayedMessagesRead,
IGasRefunder gasRefunder
) external refundsGas(gasRefunder) {
// solhint-disable-next-line avoid-tx-origin
if (msg.sender != tx.origin) revert NotOrigin();
if (!isBatchPoster[msg.sender]) revert NotBatchPoster();
(bytes32 dataHash, TimeBounds memory timeBounds) = formDataHash(
data,
afterDelayedMessagesRead
);
(
uint256 seqMessageIndex,
bytes32 beforeAcc,
bytes32 delayedAcc,
bytes32 afterAcc
) = addSequencerL2BatchImpl(dataHash, afterDelayedMessagesRead, data.length, 0, 0);
if (seqMessageIndex != sequenceNumber)
revert BadSequencerNumber(seqMessageIndex, sequenceNumber);
emit SequencerBatchDelivered(
sequenceNumber,
beforeAcc,
afterAcc,
delayedAcc,
totalDelayedMessagesRead,
timeBounds,
BatchDataLocation.TxInput
);
}
function addSequencerL2BatchFromOrigin(
uint256 sequenceNumber,
bytes calldata data,
uint256 afterDelayedMessagesRead,
IGasRefunder gasRefunder,
uint256 prevMessageCount,
uint256 newMessageCount
) external refundsGas(gasRefunder) {
// solhint-disable-next-line avoid-tx-origin
if (msg.sender != tx.origin) revert NotOrigin();
if (!isBatchPoster[msg.sender]) revert NotBatchPoster();
(bytes32 dataHash, TimeBounds memory timeBounds) = formDataHash(
data,
afterDelayedMessagesRead
);
// Reformat the stack to prevent "Stack too deep"
uint256 sequenceNumber_ = sequenceNumber;
TimeBounds memory timeBounds_ = timeBounds;
bytes32 dataHash_ = dataHash;
uint256 dataLength = data.length;
uint256 afterDelayedMessagesRead_ = afterDelayedMessagesRead;
uint256 prevMessageCount_ = prevMessageCount;
uint256 newMessageCount_ = newMessageCount;
(
uint256 seqMessageIndex,
bytes32 beforeAcc,
bytes32 delayedAcc,
bytes32 afterAcc
) = addSequencerL2BatchImpl(
dataHash_,
afterDelayedMessagesRead_,
dataLength,
prevMessageCount_,
newMessageCount_
);
if (seqMessageIndex != sequenceNumber_ && sequenceNumber_ != ~uint256(0))
revert BadSequencerNumber(seqMessageIndex, sequenceNumber_);
emit SequencerBatchDelivered(
seqMessageIndex,
beforeAcc,
afterAcc,
delayedAcc,
totalDelayedMessagesRead,
timeBounds_,
BatchDataLocation.TxInput
);
}
function addSequencerL2Batch(
uint256 sequenceNumber,
bytes calldata data,
uint256 afterDelayedMessagesRead,
IGasRefunder gasRefunder,
uint256 prevMessageCount,
uint256 newMessageCount
) external override refundsGas(gasRefunder) {
if (!isBatchPoster[msg.sender] && msg.sender != address(rollup)) revert NotBatchPoster();
(bytes32 dataHash, TimeBounds memory timeBounds) = formDataHash(
data,
afterDelayedMessagesRead
);
uint256 seqMessageIndex;
{
// Reformat the stack to prevent "Stack too deep"
uint256 sequenceNumber_ = sequenceNumber;
TimeBounds memory timeBounds_ = timeBounds;
bytes32 dataHash_ = dataHash;
uint256 afterDelayedMessagesRead_ = afterDelayedMessagesRead;
uint256 prevMessageCount_ = prevMessageCount;
uint256 newMessageCount_ = newMessageCount;
// we set the calldata length posted to 0 here since the caller isn't the origin
// of the tx, so they might have not paid tx input cost for the calldata
bytes32 beforeAcc;
bytes32 delayedAcc;
bytes32 afterAcc;
(seqMessageIndex, beforeAcc, delayedAcc, afterAcc) = addSequencerL2BatchImpl(
dataHash_,
afterDelayedMessagesRead_,
0,
prevMessageCount_,
newMessageCount_
);
if (seqMessageIndex != sequenceNumber_ && sequenceNumber_ != ~uint256(0))
revert BadSequencerNumber(seqMessageIndex, sequenceNumber_);
emit SequencerBatchDelivered(
seqMessageIndex,
beforeAcc,
afterAcc,
delayedAcc,
totalDelayedMessagesRead,
timeBounds_,
BatchDataLocation.SeparateBatchEvent
);
}
emit SequencerBatchData(seqMessageIndex, data);
}
modifier validateBatchData(bytes calldata data) {
uint256 fullDataLen = HEADER_LENGTH + data.length;
if (fullDataLen > MAX_DATA_SIZE) revert DataTooLarge(fullDataLen, MAX_DATA_SIZE);
if (data.length > 0 && (data[0] & DATA_AUTHENTICATED_FLAG) == DATA_AUTHENTICATED_FLAG) {
revert DataNotAuthenticated();
}
// the first byte is used to identify the type of batch data
// das batches expect to have the type byte set, followed by the keyset (so they should have at least 33 bytes)
if (data.length >= 33 && data[0] & 0x80 != 0) {
// we skip the first byte, then read the next 32 bytes for the keyset
bytes32 dasKeysetHash = bytes32(data[1:33]);
if (!dasKeySetInfo[dasKeysetHash].isValidKeyset) revert NoSuchKeyset(dasKeysetHash);
}
_;
}
function packHeader(uint256 afterDelayedMessagesRead)
internal
view
returns (bytes memory, TimeBounds memory)
{
TimeBounds memory timeBounds = getTimeBounds();
bytes memory header = abi.encodePacked(
timeBounds.minTimestamp,
timeBounds.maxTimestamp,
timeBounds.minBlockNumber,
timeBounds.maxBlockNumber,
uint64(afterDelayedMessagesRead)
);
// This must always be true from the packed encoding
assert(header.length == HEADER_LENGTH);
return (header, timeBounds);
}
function formDataHash(bytes calldata data, uint256 afterDelayedMessagesRead)
internal
view
validateBatchData(data)
returns (bytes32, TimeBounds memory)
{
(bytes memory header, TimeBounds memory timeBounds) = packHeader(afterDelayedMessagesRead);
bytes32 dataHash = keccak256(bytes.concat(header, data));
return (dataHash, timeBounds);
}
function formEmptyDataHash(uint256 afterDelayedMessagesRead)
internal
view
returns (bytes32, TimeBounds memory)
{
(bytes memory header, TimeBounds memory timeBounds) = packHeader(afterDelayedMessagesRead);
return (keccak256(header), timeBounds);
}
function addSequencerL2BatchImpl(
bytes32 dataHash,
uint256 afterDelayedMessagesRead,
uint256 calldataLengthPosted,
uint256 prevMessageCount,
uint256 newMessageCount
)
internal
returns (
uint256 seqMessageIndex,
bytes32 beforeAcc,
bytes32 delayedAcc,
bytes32 acc
)
{
if (afterDelayedMessagesRead < totalDelayedMessagesRead) revert DelayedBackwards();
if (afterDelayedMessagesRead > bridge.delayedMessageCount()) revert DelayedTooFar();
(seqMessageIndex, beforeAcc, delayedAcc, acc) = bridge.enqueueSequencerMessage(
dataHash,
afterDelayedMessagesRead,
prevMessageCount,
newMessageCount
);
totalDelayedMessagesRead = afterDelayedMessagesRead;
if (calldataLengthPosted > 0) {
// this msg isn't included in the current sequencer batch, but instead added to
// the delayed messages queue that is yet to be included
address batchPoster = msg.sender;
bytes memory spendingReportMsg = abi.encodePacked(
block.timestamp,
batchPoster,
dataHash,
seqMessageIndex,
block.basefee
);
uint256 msgNum = bridge.submitBatchSpendingReport(
batchPoster,
keccak256(spendingReportMsg)
);
// this is the same event used by Inbox.sol after including a message to the delayed message accumulator
emit InboxMessageDelivered(msgNum, spendingReportMsg);
}
}
function inboxAccs(uint256 index) external view returns (bytes32) {
return bridge.sequencerInboxAccs(index);
}
function batchCount() external view returns (uint256) {
return bridge.sequencerMessageCount();
}
/// @inheritdoc ISequencerInbox
function setMaxTimeVariation(ISequencerInbox.MaxTimeVariation memory maxTimeVariation_)
external
onlyRollupOwner
{
maxTimeVariation = maxTimeVariation_;
emit OwnerFunctionCalled(0);
}
/// @inheritdoc ISequencerInbox
function setIsBatchPoster(address addr, bool isBatchPoster_) external onlyRollupOwner {
isBatchPoster[addr] = isBatchPoster_;
emit OwnerFunctionCalled(1);
}
/// @inheritdoc ISequencerInbox
function setValidKeyset(bytes calldata keysetBytes) external onlyRollupOwner {
uint256 ksWord = uint256(keccak256(bytes.concat(hex"fe", keccak256(keysetBytes))));
bytes32 ksHash = bytes32(ksWord ^ (1 << 255));
require(keysetBytes.length < 64 * 1024, "keyset is too large");
if (dasKeySetInfo[ksHash].isValidKeyset) revert AlreadyValidDASKeyset(ksHash);
dasKeySetInfo[ksHash] = DasKeySetInfo({
isValidKeyset: true,
creationBlock: uint64(block.number)
});
emit SetValidKeyset(ksHash, keysetBytes);
emit OwnerFunctionCalled(2);
}
/// @inheritdoc ISequencerInbox
function invalidateKeysetHash(bytes32 ksHash) external onlyRollupOwner {
if (!dasKeySetInfo[ksHash].isValidKeyset) revert NoSuchKeyset(ksHash);
// we don't delete the block creation value since its used to fetch the SetValidKeyset
// event efficiently. The event provides the hash preimage of the key.
// this is still needed when syncing the chain after a keyset is invalidated.
dasKeySetInfo[ksHash].isValidKeyset = false;
emit InvalidateKeyset(ksHash);
emit OwnerFunctionCalled(3);
}
function isValidKeysetHash(bytes32 ksHash) external view returns (bool) {
return dasKeySetInfo[ksHash].isValidKeyset;
}
/// @inheritdoc ISequencerInbox
function getKeysetCreationBlock(bytes32 ksHash) external view returns (uint256) {
DasKeySetInfo memory ksInfo = dasKeySetInfo[ksHash];
if (ksInfo.creationBlock == 0) revert NoSuchKeyset(ksHash);
return uint256(ksInfo.creationBlock);
}
}
// Copyright 2021-2022, Offchain Labs, Inc.
// For license information, see https://github.com/nitro/blob/master/LICENSE
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.4;
/// @dev Init was already called
error AlreadyInit();
/// Init was called with param set to zero that must be nonzero
error HadZeroInit();
/// @dev Thrown when non owner tries to access an only-owner function
/// @param sender The msg.sender who is not the owner
/// @param owner The owner address
error NotOwner(address sender, address owner);
/// @dev Thrown when an address that is not the rollup tries to call an only-rollup function
/// @param sender The sender who is not the rollup
/// @param rollup The rollup address authorized to call this function
error NotRollup(address sender, address rollup);
/// @dev Thrown when the contract was not called directly from the origin ie msg.sender != tx.origin
error NotOrigin();
/// @dev Provided data was too large
/// @param dataLength The length of the data that is too large
/// @param maxDataLength The max length the data can be
error DataTooLarge(uint256 dataLength, uint256 maxDataLength);
/// @dev The provided is not a contract and was expected to be
/// @param addr The adddress in question
error NotContract(address addr);
/// @dev The merkle proof provided was too long
/// @param actualLength The length of the merkle proof provided
/// @param maxProofLength The max length a merkle proof can have
error MerkleProofTooLong(uint256 actualLength, uint256 maxProofLength);
/// @dev Thrown when an un-authorized address tries to access an admin function
/// @param sender The un-authorized sender
/// @param rollup The rollup, which would be authorized
/// @param owner The rollup's owner, which would be authorized
error NotRollupOrOwner(address sender, address rollup, address owner);
// Bridge Errors
/// @dev Thrown when an un-authorized address tries to access an only-inbox function
/// @param sender The un-authorized sender
error NotDelayedInbox(address sender);
/// @dev Thrown when an un-authorized address tries to access an only-sequencer-inbox function
/// @param sender The un-authorized sender
error NotSequencerInbox(address sender);
/// @dev Thrown when an un-authorized address tries to access an only-outbox function
/// @param sender The un-authorized sender
error NotOutbox(address sender);
/// @dev the provided outbox address isn't valid
/// @param outbox address of outbox being set
error InvalidOutboxSet(address outbox);
// Inbox Errors
/// @dev The contract is paused, so cannot be paused
error AlreadyPaused();
/// @dev The contract is unpaused, so cannot be unpaused
error AlreadyUnpaused();
/// @dev The contract is paused
error Paused();
/// @dev msg.value sent to the inbox isn't high enough
error InsufficientValue(uint256 expected, uint256 actual);
/// @dev submission cost provided isn't enough to create retryable ticket
error InsufficientSubmissionCost(uint256 expected, uint256 actual);
/// @dev address not allowed to interact with the given contract
error NotAllowedOrigin(address origin);
/// @dev used to convey retryable tx data in eth calls without requiring a tx trace
/// this follows a pattern similar to EIP-3668 where reverts surface call information
error RetryableData(
address from,
address to,
uint256 l2CallValue,
uint256 deposit,
uint256 maxSubmissionCost,
address excessFeeRefundAddress,
address callValueRefundAddress,
uint256 gasLimit,
uint256 maxFeePerGas,
bytes data
);
/// @dev Thrown when a L1 chainId fork is detected
error L1Forked();
/// @dev Thrown when a L1 chainId fork is not detected
error NotForked();
// Outbox Errors
/// @dev The provided proof was too long
/// @param proofLength The length of the too-long proof
error ProofTooLong(uint256 proofLength);
/// @dev The output index was greater than the maximum
/// @param index The output index
/// @param maxIndex The max the index could be
error PathNotMinimal(uint256 index, uint256 maxIndex);
/// @dev The calculated root does not exist
/// @param root The calculated root
error UnknownRoot(bytes32 root);
/// @dev The record has already been spent
/// @param index The index of the spent record
error AlreadySpent(uint256 index);
/// @dev A call to the bridge failed with no return data
error BridgeCallFailed();
// Sequencer Inbox Errors
/// @dev Thrown when someone attempts to read fewer messages than have already been read
error DelayedBackwards();
/// @dev Thrown when someone attempts to read more messages than exist
error DelayedTooFar();
/// @dev Force include can only read messages more blocks old than the delay period
error ForceIncludeBlockTooSoon();
/// @dev Force include can only read messages more seconds old than the delay period
error ForceIncludeTimeTooSoon();
/// @dev The message provided did not match the hash in the delayed inbox
error IncorrectMessagePreimage();
/// @dev This can only be called by the batch poster
error NotBatchPoster();
/// @dev The sequence number provided to this message was inconsistent with the number of batches already included
error BadSequencerNumber(uint256 stored, uint256 received);
/// @dev The sequence message number provided to this message was inconsistent with the previous one
error BadSequencerMessageNumber(uint256 stored, uint256 received);
/// @dev The batch data has the inbox authenticated bit set, but the batch data was not authenticated by the inbox
error DataNotAuthenticated();
/// @dev Tried to create an already valid Data Availability Service keyset
error AlreadyValidDASKeyset(bytes32);
/// @dev Tried to use or invalidate an already invalid Data Availability Service keyset
error NoSuchKeyset(bytes32);
// Copyright 2021-2022, Offchain Labs, Inc.
// For license information, see https://github.com/nitro/blob/master/LICENSE
// SPDX-License-Identifier: BUSL-1.1
// solhint-disable-next-line compiler-version
pragma solidity >=0.6.9 <0.9.0;
import "./IOwnable.sol";
interface IBridge {
event MessageDelivered(
uint256 indexed messageIndex,
bytes32 indexed beforeInboxAcc,
address inbox,
uint8 kind,
address sender,
bytes32 messageDataHash,
uint256 baseFeeL1,
uint64 timestamp
);
event BridgeCallTriggered(
address indexed outbox,
address indexed to,
uint256 value,
bytes data
);
event InboxToggle(address indexed inbox, bool enabled);
event OutboxToggle(address indexed outbox, bool enabled);
event SequencerInboxUpdated(address newSequencerInbox);
function allowedDelayedInboxList(uint256) external returns (address);
function allowedOutboxList(uint256) external returns (address);
/// @dev Accumulator for delayed inbox messages; tail represents hash of the current state; each element represents the inclusion of a new message.
function delayedInboxAccs(uint256) external view returns (bytes32);
/// @dev Accumulator for sequencer inbox messages; tail represents hash of the current state; each element represents the inclusion of a new message.
function sequencerInboxAccs(uint256) external view returns (bytes32);
function rollup() external view returns (IOwnable);
function sequencerInbox() external view returns (address);
function activeOutbox() external view returns (address);
function allowedDelayedInboxes(address inbox) external view returns (bool);
function allowedOutboxes(address outbox) external view returns (bool);
function sequencerReportedSubMessageCount() external view returns (uint256);
/**
* @dev Enqueue a message in the delayed inbox accumulator.
* These messages are later sequenced in the SequencerInbox, either
* by the sequencer as part of a normal batch, or by force inclusion.
*/
function enqueueDelayedMessage(
uint8 kind,
address sender,
bytes32 messageDataHash
) external payable returns (uint256);
function executeCall(
address to,
uint256 value,
bytes calldata data
) external returns (bool success, bytes memory returnData);
function delayedMessageCount() external view returns (uint256);
function sequencerMessageCount() external view returns (uint256);
// ---------- onlySequencerInbox functions ----------
function enqueueSequencerMessage(
bytes32 dataHash,
uint256 afterDelayedMessagesRead,
uint256 prevMessageCount,
uint256 newMessageCount
)
external
returns (
uint256 seqMessageIndex,
bytes32 beforeAcc,
bytes32 delayedAcc,
bytes32 acc
);
/**
* @dev Allows the sequencer inbox to submit a delayed message of the batchPostingReport type
* This is done through a separate function entrypoint instead of allowing the sequencer inbox
* to call `enqueueDelayedMessage` to avoid the gas overhead of an extra SLOAD in either
* every delayed inbox or every sequencer inbox call.
*/
function submitBatchSpendingReport(address batchPoster, bytes32 dataHash)
external
returns (uint256 msgNum);
// ---------- onlyRollupOrOwner functions ----------
function setSequencerInbox(address _sequencerInbox) external;
function setDelayedInbox(address inbox, bool enabled) external;
function setOutbox(address inbox, bool enabled) external;
// ---------- initializer ----------
function initialize(IOwnable rollup_) external;
}
// Copyright 2021-2022, Offchain Labs, Inc.
// For license information, see https://github.com/nitro/blob/master/LICENSE
// SPDX-License-Identifier: BUSL-1.1
// solhint-disable-next-line compiler-version
pragma solidity >=0.6.9 <0.9.0;
import "./IBridge.sol";
import "./IDelayedMessageProvider.sol";
import "./ISequencerInbox.sol";
interface IInbox is IDelayedMessageProvider {
function bridge() external view returns (IBridge);
function sequencerInbox() external view returns (ISequencerInbox);
/**
* @notice Send a generic L2 message to the chain
* @dev This method is an optimization to avoid having to emit the entirety of the messageData in a log. Instead validators are expected to be able to parse the data from the transaction's input
* This method will be disabled upon L1 fork to prevent replay attacks on L2
* @param messageData Data of the message being sent
*/
function sendL2MessageFromOrigin(bytes calldata messageData) external returns (uint256);
/**
* @notice Send a generic L2 message to the chain
* @dev This method can be used to send any type of message that doesn't require L1 validation
* This method will be disabled upon L1 fork to prevent replay attacks on L2
* @param messageData Data of the message being sent
*/
function sendL2Message(bytes calldata messageData) external returns (uint256);
function sendL1FundedUnsignedTransaction(
uint256 gasLimit,
uint256 maxFeePerGas,
uint256 nonce,
address to,
bytes calldata data
) external payable returns (uint256);
function sendL1FundedContractTransaction(
uint256 gasLimit,
uint256 maxFeePerGas,
address to,
bytes calldata data
) external payable returns (uint256);
function sendUnsignedTransaction(
uint256 gasLimit,
uint256 maxFeePerGas,
uint256 nonce,
address to,
uint256 value,
bytes calldata data
) external returns (uint256);
function sendContractTransaction(
uint256 gasLimit,
uint256 maxFeePerGas,
address to,
uint256 value,
bytes calldata data
) external returns (uint256);
/**
* @dev This method can only be called upon L1 fork and will not alias the caller
* This method will revert if not called from origin
*/
function sendL1FundedUnsignedTransactionToFork(
uint256 gasLimit,
uint256 maxFeePerGas,
uint256 nonce,
address to,
bytes calldata data
) external payable returns (uint256);
/**
* @dev This method can only be called upon L1 fork and will not alias the caller
* This method will revert if not called from origin
*/
function sendUnsignedTransactionToFork(
uint256 gasLimit,
uint256 maxFeePerGas,
uint256 nonce,
address to,
uint256 value,
bytes calldata data
) external returns (uint256);
/**
* @notice Send a message to initiate L2 withdrawal
* @dev This method can only be called upon L1 fork and will not alias the caller
* This method will revert if not called from origin
*/
function sendWithdrawEthToFork(
uint256 gasLimit,
uint256 maxFeePerGas,
uint256 nonce,
uint256 value,
address withdrawTo
) external returns (uint256);
/**
* @notice Get the L1 fee for submitting a retryable
* @dev This fee can be paid by funds already in the L2 aliased address or by the current message value
* @dev This formula may change in the future, to future proof your code query this method instead of inlining!!
* @param dataLength The length of the retryable's calldata, in bytes
* @param baseFee The block basefee when the retryable is included in the chain, if 0 current block.basefee will be used
*/
function calculateRetryableSubmissionFee(uint256 dataLength, uint256 baseFee)
external
view
returns (uint256);
/**
* @notice Deposit eth from L1 to L2 to address of the sender if sender is an EOA, and to its aliased address if the sender is a contract
* @dev This does not trigger the fallback function when receiving in the L2 side.
* Look into retryable tickets if you are interested in this functionality.
* @dev This function should not be called inside contract constructors
*/
function depositEth() external payable returns (uint256);
/**
* @notice Put a message in the L2 inbox that can be reexecuted for some fixed amount of time if it reverts
* @dev all msg.value will deposited to callValueRefundAddress on L2
* @dev Gas limit and maxFeePerGas should not be set to 1 as that is used to trigger the RetryableData error
* @param to destination L2 contract address
* @param l2CallValue call value for retryable L2 message
* @param maxSubmissionCost Max gas deducted from user's L2 balance to cover base submission fee
* @param excessFeeRefundAddress gasLimit x maxFeePerGas - execution cost gets credited here on L2 balance
* @param callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled
* @param gasLimit Max gas deducted from user's L2 balance to cover L2 execution. Should not be set to 1 (magic value used to trigger the RetryableData error)
* @param maxFeePerGas price bid for L2 execution. Should not be set to 1 (magic value used to trigger the RetryableData error)
* @param data ABI encoded data of L2 message
* @return unique message number of the retryable transaction
*/
function createRetryableTicket(
address to,
uint256 l2CallValue,
uint256 maxSubmissionCost,
address excessFeeRefundAddress,
address callValueRefundAddress,
uint256 gasLimit,
uint256 maxFeePerGas,
bytes calldata data
) external payable returns (uint256);
/**
* @notice Put a message in the L2 inbox that can be reexecuted for some fixed amount of time if it reverts
* @dev Same as createRetryableTicket, but does not guarantee that submission will succeed by requiring the needed funds
* come from the deposit alone, rather than falling back on the user's L2 balance
* @dev Advanced usage only (does not rewrite aliases for excessFeeRefundAddress and callValueRefundAddress).
* createRetryableTicket method is the recommended standard.
* @dev Gas limit and maxFeePerGas should not be set to 1 as that is used to trigger the RetryableData error
* @param to destination L2 contract address
* @param l2CallValue call value for retryable L2 message
* @param maxSubmissionCost Max gas deducted from user's L2 balance to cover base submission fee
* @param excessFeeRefundAddress gasLimit x maxFeePerGas - execution cost gets credited here on L2 balance
* @param callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled
* @param gasLimit Max gas deducted from user's L2 balance to cover L2 execution. Should not be set to 1 (magic value used to trigger the RetryableData error)
* @param maxFeePerGas price bid for L2 execution. Should not be set to 1 (magic value used to trigger the RetryableData error)
* @param data ABI encoded data of L2 message
* @return unique message number of the retryable transaction
*/
function unsafeCreateRetryableTicket(
address to,
uint256 l2CallValue,
uint256 maxSubmissionCost,
address excessFeeRefundAddress,
address callValueRefundAddress,
uint256 gasLimit,
uint256 maxFeePerGas,
bytes calldata data
) external payable returns (uint256);
// ---------- onlyRollupOrOwner functions ----------
/// @notice pauses all inbox functionality
function pause() external;
/// @notice unpauses all inbox functionality
function unpause() external;
// ---------- initializer ----------
/**
* @dev function to be called one time during the inbox upgrade process
* this is used to fix the storage slots
*/
function postUpgradeInit(IBridge _bridge) external;
function initialize(IBridge _bridge, ISequencerInbox _sequencerInbox) external;
}
// Copyright 2021-2022, Offchain Labs, Inc.
// For license information, see https://github.com/nitro/blob/master/LICENSE
// SPDX-License-Identifier: BUSL-1.1
// solhint-disable-next-line compiler-version
pragma solidity >=0.6.9 <0.9.0;
pragma experimental ABIEncoderV2;
import "../libraries/IGasRefunder.sol";
import "./IDelayedMessageProvider.sol";
import "./IBridge.sol";
interface ISequencerInbox is IDelayedMessageProvider {
struct MaxTimeVariation {
uint256 delayBlocks;
uint256 futureBlocks;
uint256 delaySeconds;
uint256 futureSeconds;
}
struct TimeBounds {
uint64 minTimestamp;
uint64 maxTimestamp;
uint64 minBlockNumber;
uint64 maxBlockNumber;
}
enum BatchDataLocation {
TxInput,
SeparateBatchEvent,
NoData
}
event SequencerBatchDelivered(
uint256 indexed batchSequenceNumber,
bytes32 indexed beforeAcc,
bytes32 indexed afterAcc,
bytes32 delayedAcc,
uint256 afterDelayedMessagesRead,
TimeBounds timeBounds,
BatchDataLocation dataLocation
);
event OwnerFunctionCalled(uint256 indexed id);
/// @dev a separate event that emits batch data when this isn't easily accessible in the tx.input
event SequencerBatchData(uint256 indexed batchSequenceNumber, bytes data);
/// @dev a valid keyset was added
event SetValidKeyset(bytes32 indexed keysetHash, bytes keysetBytes);
/// @dev a keyset was invalidated
event InvalidateKeyset(bytes32 indexed keysetHash);
function totalDelayedMessagesRead() external view returns (uint256);
function bridge() external view returns (IBridge);
/// @dev The size of the batch header
// solhint-disable-next-line func-name-mixedcase
function HEADER_LENGTH() external view returns (uint256);
/// @dev If the first batch data byte after the header has this bit set,
/// the sequencer inbox has authenticated the data. Currently not used.
// solhint-disable-next-line func-name-mixedcase
function DATA_AUTHENTICATED_FLAG() external view returns (bytes1);
function rollup() external view returns (IOwnable);
function isBatchPoster(address) external view returns (bool);
struct DasKeySetInfo {
bool isValidKeyset;
uint64 creationBlock;
}
// https://github.com/ethereum/solidity/issues/11826
// function maxTimeVariation() external view returns (MaxTimeVariation calldata);
// function dasKeySetInfo(bytes32) external view returns (DasKeySetInfo calldata);
/// @notice Remove force inclusion delay after a L1 chainId fork
function removeDelayAfterFork() external;
/// @notice Force messages from the delayed inbox to be included in the chain
/// Callable by any address, but message can only be force-included after maxTimeVariation.delayBlocks and
/// maxTimeVariation.delaySeconds has elapsed. As part of normal behaviour the sequencer will include these
/// messages so it's only necessary to call this if the sequencer is down, or not including any delayed messages.
/// @param _totalDelayedMessagesRead The total number of messages to read up to
/// @param kind The kind of the last message to be included
/// @param l1BlockAndTime The l1 block and the l1 timestamp of the last message to be included
/// @param baseFeeL1 The l1 gas price of the last message to be included
/// @param sender The sender of the last message to be included
/// @param messageDataHash The messageDataHash of the last message to be included
function forceInclusion(
uint256 _totalDelayedMessagesRead,
uint8 kind,
uint64[2] calldata l1BlockAndTime,
uint256 baseFeeL1,
address sender,
bytes32 messageDataHash
) external;
function inboxAccs(uint256 index) external view returns (bytes32);
function batchCount() external view returns (uint256);
function isValidKeysetHash(bytes32 ksHash) external view returns (bool);
/// @notice the creation block is intended to still be available after a keyset is deleted
function getKeysetCreationBlock(bytes32 ksHash) external view returns (uint256);
// ---------- BatchPoster functions ----------
function addSequencerL2BatchFromOrigin(
uint256 sequenceNumber,
bytes calldata data,
uint256 afterDelayedMessagesRead,
IGasRefunder gasRefunder
) external;
function addSequencerL2Batch(
uint256 sequenceNumber,
bytes calldata data,
uint256 afterDelayedMessagesRead,
IGasRefunder gasRefunder,
uint256 prevMessageCount,
uint256 newMessageCount
) external;
// ---------- onlyRollupOrOwner functions ----------
/**
* @notice Set max delay for sequencer inbox
* @param maxTimeVariation_ the maximum time variation parameters
*/
function setMaxTimeVariation(MaxTimeVariation memory maxTimeVariation_) external;
/**
* @notice Updates whether an address is authorized to be a batch poster at the sequencer inbox
* @param addr the address
* @param isBatchPoster_ if the specified address should be authorized as a batch poster
*/
function setIsBatchPoster(address addr, bool isBatchPoster_) external;
/**
* @notice Makes Data Availability Service keyset valid
* @param keysetBytes bytes of the serialized keyset
*/
function setValidKeyset(bytes calldata keysetBytes) external;
/**
* @notice Invalidates a Data Availability Service keyset
* @param ksHash hash of the keyset
*/
function invalidateKeysetHash(bytes32 ksHash) external;
// ---------- initializer ----------
function initialize(IBridge bridge_, MaxTimeVariation calldata maxTimeVariation_) external;
}
// Copyright 2021-2022, Offchain Labs, Inc.
// For license information, see https://github.com/nitro/blob/master/LICENSE
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;
import "./RollupLib.sol";
import "./IRollupCore.sol";
import "../bridge/ISequencerInbox.sol";
import "../bridge/IOutbox.sol";
import "../bridge/IOwnable.sol";
interface IRollupUserAbs is IRollupCore, IOwnable {
/// @dev the user logic just validated configuration and shouldn't write to state during init
/// this allows the admin logic to ensure consistency on parameters.
function initialize(address stakeToken) external view;
function removeWhitelistAfterFork() external;
function removeWhitelistAfterValidatorAfk() external;
function isERC20Enabled() external view returns (bool);
function rejectNextNode(address stakerAddress) external;
function confirmNextNode(bytes32 blockHash, bytes32 sendRoot) external;
function stakeOnExistingNode(uint64 nodeNum, bytes32 nodeHash) external;
function stakeOnNewNode(
RollupLib.Assertion memory assertion,
bytes32 expectedNodeHash,
uint256 prevNodeInboxMaxCount
) external;
function returnOldDeposit(address stakerAddress) external;
function reduceDeposit(uint256 target) external;
function removeZombie(uint256 zombieNum, uint256 maxNodes) external;
function removeOldZombies(uint256 startIndex) external;
function requiredStake(
uint256 blockNumber,
uint64 firstUnresolvedNodeNum,
uint64 latestCreatedNode
) external view returns (uint256);
function currentRequiredStake() external view returns (uint256);
function countStakedZombies(uint64 nodeNum) external view returns (uint256);
function countZombiesStakedOnChildren(uint64 nodeNum) external view returns (uint256);
function requireUnresolvedExists() external view;
function requireUnresolved(uint256 nodeNum) external view;
function withdrawStakerFunds() external returns (uint256);
function createChallenge(
address[2] calldata stakers,
uint64[2] calldata nodeNums,
MachineStatus[2] calldata machineStatuses,
GlobalState[2] calldata globalStates,
uint64 numBlocks,
bytes32 secondExecutionHash,
uint256[2] calldata proposedTimes,
bytes32[2] calldata wasmModuleRoots
) external;
}
interface IRollupUser is IRollupUserAbs {
function newStakeOnExistingNode(uint64 nodeNum, bytes32 nodeHash) external payable;
function newStakeOnNewNode(
RollupLib.Assertion calldata assertion,
bytes32 expectedNodeHash,
uint256 prevNodeInboxMaxCount
) external payable;
function addToDeposit(address stakerAddress) external payable;
}
interface IRollupUserERC20 is IRollupUserAbs {
function newStakeOnExistingNode(
uint256 tokenAmount,
uint64 nodeNum,
bytes32 nodeHash
) external;
function newStakeOnNewNode(
uint256 tokenAmount,
RollupLib.Assertion calldata assertion,
bytes32 expectedNodeHash,
uint256 prevNodeInboxMaxCount
) external;
function addToDeposit(address stakerAddress, uint256 tokenAmount) external;
}
interface IRollupAdmin {
event OwnerFunctionCalled(uint256 indexed id);
function initialize(Config calldata config, ContractDependencies calldata connectedContracts)
external;
/**
* @notice Add a contract authorized to put messages into this rollup's inbox
* @param _outbox Outbox contract to add
*/
function setOutbox(IOutbox _outbox) external;
/**
* @notice Disable an old outbox from interacting with the bridge
* @param _outbox Outbox contract to remove
*/
function removeOldOutbox(address _outbox) external;
/**
* @notice Enable or disable an inbox contract
* @param _inbox Inbox contract to add or remove
* @param _enabled New status of inbox
*/
function setDelayedInbox(address _inbox, bool _enabled) external;
/**
* @notice Pause interaction with the rollup contract
*/
function pause() external;
/**
* @notice Resume interaction with the rollup contract
*/
function resume() external;
/**
* @notice Set the addresses of the validator whitelist
* @dev It is expected that both arrays are same length, and validator at
* position i corresponds to the value at position i
* @param _validator addresses to set in the whitelist
* @param _val value to set in the whitelist for corresponding address
*/
function setValidator(address[] memory _validator, bool[] memory _val) external;
/**
* @notice Set a new owner address for the rollup proxy
* @param newOwner address of new rollup owner
*/
function setOwner(address newOwner) external;
/**
* @notice Set minimum assertion period for the rollup
* @param newPeriod new minimum period for assertions
*/
function setMinimumAssertionPeriod(uint256 newPeriod) external;
/**
* @notice Set number of blocks until a node is considered confirmed
* @param newConfirmPeriod new number of blocks until a node is confirmed
*/
function setConfirmPeriodBlocks(uint64 newConfirmPeriod) external;
/**
* @notice Set number of extra blocks after a challenge
* @param newExtraTimeBlocks new number of blocks
*/
function setExtraChallengeTimeBlocks(uint64 newExtraTimeBlocks) external;
/**
* @notice Set base stake required for an assertion
* @param newBaseStake maximum avmgas to be used per block
*/
function setBaseStake(uint256 newBaseStake) external;
/**
* @notice Set the token used for stake, where address(0) == eth
* @dev Before changing the base stake token, you might need to change the
* implementation of the Rollup User logic!
* @param newStakeToken address of token used for staking
*/
function setStakeToken(address newStakeToken) external;
/**
* @notice Upgrades the implementation of a beacon controlled by the rollup
* @param beacon address of beacon to be upgraded
* @param newImplementation new address of implementation
*/
function upgradeBeacon(address beacon, address newImplementation) external;
function forceResolveChallenge(address[] memory stackerA, address[] memory stackerB) external;
function forceRefundStaker(address[] memory stacker) external;
function forceCreateNode(
uint64 prevNode,
uint256 prevNodeInboxMaxCount,
RollupLib.Assertion memory assertion,
bytes32 expectedNodeHash
) external;
function forceConfirmNode(
uint64 nodeNum,
bytes32 blockHash,
bytes32 sendRoot
) external;
function setLoserStakeEscrow(address newLoserStakerEscrow) external;
/**
* @notice Set the proving WASM module root
* @param newWasmModuleRoot new module root
*/
function setWasmModuleRoot(bytes32 newWasmModuleRoot) external;
/**
* @notice set a new sequencer inbox contract
* @param _sequencerInbox new address of sequencer inbox
*/
function setSequencerInbox(address _sequencerInbox) external;
/**
* @notice set the validatorWhitelistDisabled flag
* @param _validatorWhitelistDisabled new value of validatorWhitelistDisabled, i.e. true = disabled
*/
function setValidatorWhitelistDisabled(bool _validatorWhitelistDisabled) external;
}
// Copyright 2021-2022, Offchain Labs, Inc.
// For license information, see https://github.com/nitro/blob/master/LICENSE
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;
library Messages {
function messageHash(
uint8 kind,
address sender,
uint64 blockNumber,
uint64 timestamp,
uint256 inboxSeqNum,
uint256 baseFeeL1,
bytes32 messageDataHash
) internal pure returns (bytes32) {
return
keccak256(
abi.encodePacked(
kind,
sender,
blockNumber,
timestamp,
inboxSeqNum,
baseFeeL1,
messageDataHash
)
);
}
function accumulateInboxMessage(bytes32 prevAcc, bytes32 message)
internal
pure
returns (bytes32)
{
return keccak256(abi.encodePacked(prevAcc, message));
}
}
// Copyright 2021-2022, Offchain Labs, Inc.
// For license information, see https://github.com/nitro/blob/master/LICENSE
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.4;
uint8 constant L2_MSG = 3;
uint8 constant L1MessageType_L2FundedByL1 = 7;
uint8 constant L1MessageType_submitRetryableTx = 9;
uint8 constant L1MessageType_ethDeposit = 12;
uint8 constant L1MessageType_batchPostingReport = 13;
uint8 constant L2MessageType_unsignedEOATx = 0;
uint8 constant L2MessageType_unsignedContractTx = 1;
uint8 constant ROLLUP_PROTOCOL_EVENT_TYPE = 8;
uint8 constant INITIALIZATION_MSG_TYPE = 11;
// Copyright 2021-2022, Offchain Labs, Inc.
// For license information, see https://github.com/nitro/blob/master/LICENSE
// SPDX-License-Identifier: BUSL-1.1
// solhint-disable-next-line compiler-version
pragma solidity >=0.6.9 <0.9.0;
interface IGasRefunder {
function onGasSpent(
address payable spender,
uint256 gasUsed,
uint256 calldataSize
) external returns (bool success);
}
abstract contract GasRefundEnabled {
/// @dev this refunds the sender for execution costs of the tx
/// calldata costs are only refunded if `msg.sender == tx.origin` to guarantee the value refunded relates to charging
/// for the `tx.input`. this avoids a possible attack where you generate large calldata from a contract and get over-refunded
modifier refundsGas(IGasRefunder gasRefunder) {
uint256 startGasLeft = gasleft();
_;
if (address(gasRefunder) != address(0)) {
uint256 calldataSize;
assembly {
calldataSize := calldatasize()
}
uint256 calldataWords = (calldataSize + 31) / 32;
// account for the CALLDATACOPY cost of the proxy contract, including the memory expansion cost
startGasLeft += calldataWords * 6 + (calldataWords**2) / 512;
// if triggered in a contract call, the spender may be overrefunded by appending dummy data to the call
// so we check if it is a top level call, which would mean the sender paid calldata as part of tx.input
// solhint-disable-next-line avoid-tx-origin
if (msg.sender != tx.origin) {
// We can't be sure if this calldata came from the top level tx,
// so to be safe we tell the gas refunder there was no calldata.
calldataSize = 0;
}
gasRefunder.onGasSpent(payable(msg.sender), startGasLeft - gasleft(), calldataSize);
}
}
}
// Copyright 2021-2022, Offchain Labs, Inc.
// For license information, see https://github.com/nitro/blob/master/LICENSE
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;
import {NotOwner} from "./Error.sol";
/// @dev A stateless contract that allows you to infer if the current call has been delegated or not
/// Pattern used here is from UUPS implementation by the OpenZeppelin team
abstract contract DelegateCallAware {
address private immutable __self = address(this);
/**
* @dev Check that the execution is being performed through a delegate call. This allows a function to be
* callable on the proxy contract but not on the logic contract.
*/
modifier onlyDelegated() {
require(address(this) != __self, "Function must be called through delegatecall");
_;
}
/**
* @dev Check that the execution is not being performed through a delegate call. This allows a function to be
* callable on the implementing contract but not through proxies.
*/
modifier notDelegated() {
require(address(this) == __self, "Function must not be called through delegatecall");
_;
}
/// @dev Check that msg.sender is the current EIP 1967 proxy admin
modifier onlyProxyOwner() {
// Storage slot with the admin of the proxy contract
// This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1
bytes32 slot = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
address admin;
assembly {
admin := sload(slot)
}
if (msg.sender != admin) revert NotOwner(msg.sender, admin);
_;
}
}
// Copyright 2021-2022, Offchain Labs, Inc.
// For license information, see https://github.com/nitro/blob/master/LICENSE
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.4;
// 90% of Geth's 128KB tx size limit, leaving ~13KB for proving
uint256 constant MAX_DATA_SIZE = 117964;
uint64 constant NO_CHAL_INDEX = 0;
// Expected seconds per block in Ethereum PoS
uint256 constant ETH_POS_BLOCK_TIME = 12;
// Copyright 2021-2022, Offchain Labs, Inc.
// For license information, see https://github.com/nitro/blob/master/LICENSE
// SPDX-License-Identifier: BUSL-1.1
// solhint-disable-next-line compiler-version
pragma solidity >=0.4.21 <0.9.0;
interface IOwnable {
function owner() external view returns (address);
}
// Copyright 2021-2022, Offchain Labs, Inc.
// For license information, see https://github.com/nitro/blob/master/LICENSE
// SPDX-License-Identifier: BUSL-1.1
// solhint-disable-next-line compiler-version
pragma solidity >=0.6.9 <0.9.0;
interface IDelayedMessageProvider {
/// @dev event emitted when a inbox message is added to the Bridge's delayed accumulator
event InboxMessageDelivered(uint256 indexed messageNum, bytes data);
/// @dev event emitted when a inbox message is added to the Bridge's delayed accumulator
/// same as InboxMessageDelivered but the batch data is available in tx.input
event InboxMessageDeliveredFromOrigin(uint256 indexed messageNum);
}
// Copyright 2021-2022, Offchain Labs, Inc.
// For license information, see https://github.com/nitro/blob/master/LICENSE
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;
import "../challenge/IChallengeManager.sol";
import "../challenge/ChallengeLib.sol";
import "../state/GlobalState.sol";
import "../bridge/ISequencerInbox.sol";
import "../bridge/IBridge.sol";
import "../bridge/IOutbox.sol";
import "../bridge/IInbox.sol";
import "./IRollupEventInbox.sol";
import "./IRollupLogic.sol";
struct Config {
uint64 confirmPeriodBlocks;
uint64 extraChallengeTimeBlocks;
address stakeToken;
uint256 baseStake;
bytes32 wasmModuleRoot;
address owner;
address loserStakeEscrow;
uint256 chainId;
uint64 genesisBlockNum;
ISequencerInbox.MaxTimeVariation sequencerInboxMaxTimeVariation;
}
struct ContractDependencies {
IBridge bridge;
ISequencerInbox sequencerInbox;
IInbox inbox;
IOutbox outbox;
IRollupEventInbox rollupEventInbox;
IChallengeManager challengeManager;
IRollupAdmin rollupAdminLogic;
IRollupUser rollupUserLogic;
// misc contracts that are useful when interacting with the rollup
address validatorUtils;
address validatorWalletCreator;
}
library RollupLib {
using GlobalStateLib for GlobalState;
struct ExecutionState {
GlobalState globalState;
MachineStatus machineStatus;
}
function stateHash(ExecutionState calldata execState, uint256 inboxMaxCount)
internal
pure
returns (bytes32)
{
return
keccak256(
abi.encodePacked(
execState.globalState.hash(),
inboxMaxCount,
execState.machineStatus
)
);
}
/// @dev same as stateHash but expects execState in memory instead of calldata
function stateHashMem(ExecutionState memory execState, uint256 inboxMaxCount)
internal
pure
returns (bytes32)
{
return
keccak256(
abi.encodePacked(
execState.globalState.hash(),
inboxMaxCount,
execState.machineStatus
)
);
}
struct Assertion {
ExecutionState beforeState;
ExecutionState afterState;
uint64 numBlocks;
}
function executionHash(Assertion memory assertion) internal pure returns (bytes32) {
MachineStatus[2] memory statuses;
statuses[0] = assertion.beforeState.machineStatus;
statuses[1] = assertion.afterState.machineStatus;
GlobalState[2] memory globalStates;
globalStates[0] = assertion.beforeState.globalState;
globalStates[1] = assertion.afterState.globalState;
// TODO: benchmark how much this abstraction adds of gas overhead
return executionHash(statuses, globalStates, assertion.numBlocks);
}
function executionHash(
MachineStatus[2] memory statuses,
GlobalState[2] memory globalStates,
uint64 numBlocks
) internal pure returns (bytes32) {
bytes32[] memory segments = new bytes32[](2);
segments[0] = ChallengeLib.blockStateHash(statuses[0], globalStates[0].hash());
segments[1] = ChallengeLib.blockStateHash(statuses[1], globalStates[1].hash());
return ChallengeLib.hashChallengeState(0, numBlocks, segments);
}
function challengeRootHash(
bytes32 execution,
uint256 proposedTime,
bytes32 wasmModuleRoot
) internal pure returns (bytes32) {
return keccak256(abi.encodePacked(execution, proposedTime, wasmModuleRoot));
}
function confirmHash(Assertion memory assertion) internal pure returns (bytes32) {
return
confirmHash(
assertion.afterState.globalState.getBlockHash(),
assertion.afterState.globalState.getSendRoot()
);
}
function confirmHash(bytes32 blockHash, bytes32 sendRoot) internal pure returns (bytes32) {
return keccak256(abi.encodePacked(blockHash, sendRoot));
}
function nodeHash(
bool hasSibling,
bytes32 lastHash,
bytes32 assertionExecHash,
bytes32 inboxAcc,
bytes32 wasmModuleRoot
) internal pure returns (bytes32) {
uint8 hasSiblingInt = hasSibling ? 1 : 0;
return
keccak256(
abi.encodePacked(
hasSiblingInt,
lastHash,
assertionExecHash,
inboxAcc,
wasmModuleRoot
)
);
}
}
// Copyright 2021-2022, Offchain Labs, Inc.
// For license information, see https://github.com/nitro/blob/master/LICENSE
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;
import "./Node.sol";
import "./RollupLib.sol";
interface IRollupCore {
struct Staker {
uint256 amountStaked;
uint64 index;
uint64 latestStakedNode;
// currentChallenge is 0 if staker is not in a challenge
uint64 currentChallenge;
bool isStaked;
}
event RollupInitialized(bytes32 machineHash, uint256 chainId);
event NodeCreated(
uint64 indexed nodeNum,
bytes32 indexed parentNodeHash,
bytes32 indexed nodeHash,
bytes32 executionHash,
RollupLib.Assertion assertion,
bytes32 afterInboxBatchAcc,
bytes32 wasmModuleRoot,
uint256 inboxMaxCount
);
event NodeConfirmed(uint64 indexed nodeNum, bytes32 blockHash, bytes32 sendRoot);
event NodeRejected(uint64 indexed nodeNum);
event RollupChallengeStarted(
uint64 indexed challengeIndex,
address asserter,
address challenger,
uint64 challengedNode
);
event UserStakeUpdated(address indexed user, uint256 initialBalance, uint256 finalBalance);
event UserWithdrawableFundsUpdated(
address indexed user,
uint256 initialBalance,
uint256 finalBalance
);
function confirmPeriodBlocks() external view returns (uint64);
function extraChallengeTimeBlocks() external view returns (uint64);
function chainId() external view returns (uint256);
function baseStake() external view returns (uint256);
function wasmModuleRoot() external view returns (bytes32);
function bridge() external view returns (IBridge);
function sequencerInbox() external view returns (ISequencerInbox);
function outbox() external view returns (IOutbox);
function rollupEventInbox() external view returns (IRollupEventInbox);
function challengeManager() external view returns (IChallengeManager);
function loserStakeEscrow() external view returns (address);
function stakeToken() external view returns (address);
function minimumAssertionPeriod() external view returns (uint256);
function isValidator(address) external view returns (bool);
function validatorWhitelistDisabled() external view returns (bool);
/**
* @notice Get the Node for the given index.
*/
function getNode(uint64 nodeNum) external view returns (Node memory);
/**
* @notice Check if the specified node has been staked on by the provided staker.
* Only accurate at the latest confirmed node and afterwards.
*/
function nodeHasStaker(uint64 nodeNum, address staker) external view returns (bool);
/**
* @notice Get the address of the staker at the given index
* @param stakerNum Index of the staker
* @return Address of the staker
*/
function getStakerAddress(uint64 stakerNum) external view returns (address);
/**
* @notice Check whether the given staker is staked
* @param staker Staker address to check
* @return True or False for whether the staker was staked
*/
function isStaked(address staker) external view returns (bool);
/**
* @notice Get the latest staked node of the given staker
* @param staker Staker address to lookup
* @return Latest node staked of the staker
*/
function latestStakedNode(address staker) external view returns (uint64);
/**
* @notice Get the current challenge of the given staker
* @param staker Staker address to lookup
* @return Current challenge of the staker
*/
function currentChallenge(address staker) external view returns (uint64);
/**
* @notice Get the amount staked of the given staker
* @param staker Staker address to lookup
* @return Amount staked of the staker
*/
function amountStaked(address staker) external view returns (uint256);
/**
* @notice Retrieves stored information about a requested staker
* @param staker Staker address to retrieve
* @return A structure with information about the requested staker
*/
function getStaker(address staker) external view returns (Staker memory);
/**
* @notice Get the original staker address of the zombie at the given index
* @param zombieNum Index of the zombie to lookup
* @return Original staker address of the zombie
*/
function zombieAddress(uint256 zombieNum) external view returns (address);
/**
* @notice Get Latest node that the given zombie at the given index is staked on
* @param zombieNum Index of the zombie to lookup
* @return Latest node that the given zombie is staked on
*/
function zombieLatestStakedNode(uint256 zombieNum) external view returns (uint64);
/// @return Current number of un-removed zombies
function zombieCount() external view returns (uint256);
function isZombie(address staker) external view returns (bool);
/**
* @notice Get the amount of funds withdrawable by the given address
* @param owner Address to check the funds of
* @return Amount of funds withdrawable by owner
*/
function withdrawableFunds(address owner) external view returns (uint256);
/**
* @return Index of the first unresolved node
* @dev If all nodes have been resolved, this will be latestNodeCreated + 1
*/
function firstUnresolvedNode() external view returns (uint64);
/// @return Index of the latest confirmed node
function latestConfirmed() external view returns (uint64);
/// @return Index of the latest rollup node created
function latestNodeCreated() external view returns (uint64);
/// @return Ethereum block that the most recent stake was created
function lastStakeBlock() external view returns (uint64);
/// @return Number of active stakers currently staked
function stakerCount() external view returns (uint64);
}
// Copyright 2021-2022, Offchain Labs, Inc.
// For license information, see https://github.com/nitro/blob/master/LICENSE
// SPDX-License-Identifier: BUSL-1.1
// solhint-disable-next-line compiler-version
pragma solidity >=0.6.9 <0.9.0;
import "./IBridge.sol";
interface IOutbox {
event SendRootUpdated(bytes32 indexed outputRoot, bytes32 indexed l2BlockHash);
event OutBoxTransactionExecuted(
address indexed to,
address indexed l2Sender,
uint256 indexed zero,
uint256 transactionIndex
);
function rollup() external view returns (address); // the rollup contract
function bridge() external view returns (IBridge); // the bridge contract
function spent(uint256) external view returns (bytes32); // packed spent bitmap
function roots(bytes32) external view returns (bytes32); // maps root hashes => L2 block hash
// solhint-disable-next-line func-name-mixedcase
function OUTBOX_VERSION() external view returns (uint128); // the outbox version
function updateSendRoot(bytes32 sendRoot, bytes32 l2BlockHash) external;
/// @notice When l2ToL1Sender returns a nonzero address, the message was originated by an L2 account
/// When the return value is zero, that means this is a system message
/// @dev the l2ToL1Sender behaves as the tx.origin, the msg.sender should be validated to protect against reentrancies
function l2ToL1Sender() external view returns (address);
/// @return l2Block return L2 block when the L2 tx was initiated or 0 if no L2 to L1 transaction is active
function l2ToL1Block() external view returns (uint256);
/// @return l1Block return L1 block when the L2 tx was initiated or 0 if no L2 to L1 transaction is active
function l2ToL1EthBlock() external view returns (uint256);
/// @return timestamp return L2 timestamp when the L2 tx was initiated or 0 if no L2 to L1 transaction is active
function l2ToL1Timestamp() external view returns (uint256);
/// @return outputId returns the unique output identifier of the L2 to L1 tx or 0 if no L2 to L1 transaction is active
function l2ToL1OutputId() external view returns (bytes32);
/**
* @notice Executes a messages in an Outbox entry.
* @dev Reverts if dispute period hasn't expired, since the outbox entry
* is only created once the rollup confirms the respective assertion.
* @dev it is not possible to execute any L2-to-L1 transaction which contains data
* to a contract address without any code (as enforced by the Bridge contract).
* @param proof Merkle proof of message inclusion in send root
* @param index Merkle path to message
* @param l2Sender sender if original message (i.e., caller of ArbSys.sendTxToL1)
* @param to destination address for L1 contract call
* @param l2Block l2 block number at which sendTxToL1 call was made
* @param l1Block l1 block number at which sendTxToL1 call was made
* @param l2Timestamp l2 Timestamp at which sendTxToL1 call was made
* @param value wei in L1 message
* @param data abi-encoded L1 message data
*/
function executeTransaction(
bytes32[] calldata proof,
uint256 index,
address l2Sender,
address to,
uint256 l2Block,
uint256 l1Block,
uint256 l2Timestamp,
uint256 value,
bytes calldata data
) external;
/**
* @dev function used to simulate the result of a particular function call from the outbox
* it is useful for things such as gas estimates. This function includes all costs except for
* proof validation (which can be considered offchain as a somewhat of a fixed cost - it's
* not really a fixed cost, but can be treated as so with a fixed overhead for gas estimation).
* We can't include the cost of proof validation since this is intended to be used to simulate txs
* that are included in yet-to-be confirmed merkle roots. The simulation entrypoint could instead pretend
* to confirm a pending merkle root, but that would be less practical for integrating with tooling.
* It is only possible to trigger it when the msg sender is address zero, which should be impossible
* unless under simulation in an eth_call or eth_estimateGas
*/
function executeTransactionSimulation(
uint256 index,
address l2Sender,
address to,
uint256 l2Block,
uint256 l1Block,
uint256 l2Timestamp,
uint256 value,
bytes calldata data
) external;
/**
* @param index Merkle path to message
* @return true if the message has been spent
*/
function isSpent(uint256 index) external view returns (bool);
function calculateItemHash(
address l2Sender,
address to,
uint256 l2Block,
uint256 l1Block,
uint256 l2Timestamp,
uint256 value,
bytes calldata data
) external pure returns (bytes32);
function calculateMerkleRoot(
bytes32[] memory proof,
uint256 path,
bytes32 item
) external pure returns (bytes32);
}
// Copyright 2021-2022, Offchain Labs, Inc.
// For license information, see https://github.com/nitro/blob/master/LICENSE
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;
import "../state/Machine.sol";
import "../bridge/IBridge.sol";
import "../bridge/ISequencerInbox.sol";
import "../osp/IOneStepProofEntry.sol";
import "./IChallengeResultReceiver.sol";
import "./ChallengeLib.sol";
interface IChallengeManager {
enum ChallengeTerminationType {
TIMEOUT,
BLOCK_PROOF,
EXECUTION_PROOF,
CLEARED
}
event InitiatedChallenge(
uint64 indexed challengeIndex,
GlobalState startState,
GlobalState endState
);
event Bisected(
uint64 indexed challengeIndex,
bytes32 indexed challengeRoot,
uint256 challengedSegmentStart,
uint256 challengedSegmentLength,
bytes32[] chainHashes
);
event ExecutionChallengeBegun(uint64 indexed challengeIndex, uint256 blockSteps);
event OneStepProofCompleted(uint64 indexed challengeIndex);
event ChallengeEnded(uint64 indexed challengeIndex, ChallengeTerminationType kind);
function initialize(
IChallengeResultReceiver resultReceiver_,
ISequencerInbox sequencerInbox_,
IBridge bridge_,
IOneStepProofEntry osp_
) external;
function createChallenge(
bytes32 wasmModuleRoot_,
MachineStatus[2] calldata startAndEndMachineStatuses_,
GlobalState[2] calldata startAndEndGlobalStates_,
uint64 numBlocks,
address asserter_,
address challenger_,
uint256 asserterTimeLeft_,
uint256 challengerTimeLeft_
) external returns (uint64);
function challengeInfo(uint64 challengeIndex_)
external
view
returns (ChallengeLib.Challenge memory);
function currentResponder(uint64 challengeIndex) external view returns (address);
function isTimedOut(uint64 challengeIndex) external view returns (bool);
function clearChallenge(uint64 challengeIndex_) external;
function timeout(uint64 challengeIndex_) external;
}
// Copyright 2021-2022, Offchain Labs, Inc.
// For license information, see https://github.com/nitro/blob/master/LICENSE
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;
import "../state/Machine.sol";
import "../state/GlobalState.sol";
library ChallengeLib {
using MachineLib for Machine;
using ChallengeLib for Challenge;
/// @dev It's assumed that that uninitialzed challenges have mode NONE
enum ChallengeMode {
NONE,
BLOCK,
EXECUTION
}
struct Participant {
address addr;
uint256 timeLeft;
}
struct Challenge {
Participant current;
Participant next;
uint256 lastMoveTimestamp;
bytes32 wasmModuleRoot;
bytes32 challengeStateHash;
uint64 maxInboxMessages;
ChallengeMode mode;
}
struct SegmentSelection {
uint256 oldSegmentsStart;
uint256 oldSegmentsLength;
bytes32[] oldSegments;
uint256 challengePosition;
}
function timeUsedSinceLastMove(Challenge storage challenge) internal view returns (uint256) {
return block.timestamp - challenge.lastMoveTimestamp;
}
function isTimedOut(Challenge storage challenge) internal view returns (bool) {
return challenge.timeUsedSinceLastMove() > challenge.current.timeLeft;
}
function getStartMachineHash(bytes32 globalStateHash, bytes32 wasmModuleRoot)
internal
pure
returns (bytes32)
{
// Start the value stack with the function call ABI for the entrypoint
Value[] memory startingValues = new Value[](3);
startingValues[0] = ValueLib.newRefNull();
startingValues[1] = ValueLib.newI32(0);
startingValues[2] = ValueLib.newI32(0);
ValueArray memory valuesArray = ValueArray({inner: startingValues});
ValueStack memory values = ValueStack({proved: valuesArray, remainingHash: 0});
ValueStack memory internalStack;
StackFrameWindow memory frameStack;
Machine memory mach = Machine({
status: MachineStatus.RUNNING,
valueStack: values,
internalStack: internalStack,
frameStack: frameStack,
globalStateHash: globalStateHash,
moduleIdx: 0,
functionIdx: 0,
functionPc: 0,
modulesRoot: wasmModuleRoot
});
return mach.hash();
}
function getEndMachineHash(MachineStatus status, bytes32 globalStateHash)
internal
pure
returns (bytes32)
{
if (status == MachineStatus.FINISHED) {
return keccak256(abi.encodePacked("Machine finished:", globalStateHash));
} else if (status == MachineStatus.ERRORED) {
return keccak256(abi.encodePacked("Machine errored:"));
} else if (status == MachineStatus.TOO_FAR) {
return keccak256(abi.encodePacked("Machine too far:"));
} else {
revert("BAD_BLOCK_STATUS");
}
}
function extractChallengeSegment(SegmentSelection calldata selection)
internal
pure
returns (uint256 segmentStart, uint256 segmentLength)
{
uint256 oldChallengeDegree = selection.oldSegments.length - 1;
segmentLength = selection.oldSegmentsLength / oldChallengeDegree;
// Intentionally done before challengeLength is potentially added to for the final segment
segmentStart = selection.oldSegmentsStart + segmentLength * selection.challengePosition;
if (selection.challengePosition == selection.oldSegments.length - 2) {
segmentLength += selection.oldSegmentsLength % oldChallengeDegree;
}
}
function hashChallengeState(
uint256 segmentsStart,
uint256 segmentsLength,
bytes32[] memory segments
) internal pure returns (bytes32) {
return keccak256(abi.encodePacked(segmentsStart, segmentsLength, segments));
}
function blockStateHash(MachineStatus status, bytes32 globalStateHash)
internal
pure
returns (bytes32)
{
if (status == MachineStatus.FINISHED) {
return keccak256(abi.encodePacked("Block state:", globalStateHash));
} else if (status == MachineStatus.ERRORED) {
return keccak256(abi.encodePacked("Block state, errored:", globalStateHash));
} else if (status == MachineStatus.TOO_FAR) {
return keccak256(abi.encodePacked("Block state, too far:"));
} else {
revert("BAD_BLOCK_STATUS");
}
}
}
// Copyright 2021-2022, Offchain Labs, Inc.
// For license information, see https://github.com/nitro/blob/master/LICENSE
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;
struct GlobalState {
bytes32[2] bytes32Vals;
uint64[2] u64Vals;
}
library GlobalStateLib {
uint16 internal constant BYTES32_VALS_NUM = 2;
uint16 internal constant U64_VALS_NUM = 2;
function hash(GlobalState memory state) internal pure returns (bytes32) {
return
keccak256(
abi.encodePacked(
"Global state:",
state.bytes32Vals[0],
state.bytes32Vals[1],
state.u64Vals[0],
state.u64Vals[1]
)
);
}
function getBlockHash(GlobalState memory state) internal pure returns (bytes32) {
return state.bytes32Vals[0];
}
function getSendRoot(GlobalState memory state) internal pure returns (bytes32) {
return state.bytes32Vals[1];
}
function getInboxPosition(GlobalState memory state) internal pure returns (uint64) {
return state.u64Vals[0];
}
function getPositionInMessage(GlobalState memory state) internal pure returns (uint64) {
return state.u64Vals[1];
}
function isEmpty(GlobalState calldata state) internal pure returns (bool) {
return (state.bytes32Vals[0] == bytes32(0) &&
state.bytes32Vals[1] == bytes32(0) &&
state.u64Vals[0] == 0 &&
state.u64Vals[1] == 0);
}
}
// Copyright 2021-2022, Offchain Labs, Inc.
// For license information, see https://github.com/nitro/blob/master/LICENSE
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;
import "../bridge/IBridge.sol";
interface IRollupEventInbox {
function bridge() external view returns (IBridge);
function initialize(IBridge _bridge) external;
function rollup() external view returns (address);
function rollupInitialized(uint256 chainId) external;
}
// Copyright 2021-2022, Offchain Labs, Inc.
// For license information, see https://github.com/nitro/blob/master/LICENSE
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;
import "./ValueStack.sol";
import "./Instructions.sol";
import "./StackFrame.sol";
enum MachineStatus {
RUNNING,
FINISHED,
ERRORED,
TOO_FAR
}
struct Machine {
MachineStatus status;
ValueStack valueStack;
ValueStack internalStack;
StackFrameWindow frameStack;
bytes32 globalStateHash;
uint32 moduleIdx;
uint32 functionIdx;
uint32 functionPc;
bytes32 modulesRoot;
}
library MachineLib {
using StackFrameLib for StackFrameWindow;
using ValueStackLib for ValueStack;
function hash(Machine memory mach) internal pure returns (bytes32) {
// Warning: the non-running hashes are replicated in Challenge
if (mach.status == MachineStatus.RUNNING) {
return
keccak256(
abi.encodePacked(
"Machine running:",
mach.valueStack.hash(),
mach.internalStack.hash(),
mach.frameStack.hash(),
mach.globalStateHash,
mach.moduleIdx,
mach.functionIdx,
mach.functionPc,
mach.modulesRoot
)
);
} else if (mach.status == MachineStatus.FINISHED) {
return keccak256(abi.encodePacked("Machine finished:", mach.globalStateHash));
} else if (mach.status == MachineStatus.ERRORED) {
return keccak256(abi.encodePacked("Machine errored:"));
} else if (mach.status == MachineStatus.TOO_FAR) {
return keccak256(abi.encodePacked("Machine too far:"));
} else {
revert("BAD_MACH_STATUS");
}
}
}
// Copyright 2021-2022, Offchain Labs, Inc.
// For license information, see https://github.com/nitro/blob/master/LICENSE
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;
import "./IOneStepProver.sol";
library OneStepProofEntryLib {
uint256 internal constant MAX_STEPS = 1 << 43;
}
interface IOneStepProofEntry {
function proveOneStep(
ExecutionContext calldata execCtx,
uint256 machineStep,
bytes32 beforeHash,
bytes calldata proof
) external view returns (bytes32 afterHash);
}
// Copyright 2021-2022, Offchain Labs, Inc.
// For license information, see https://github.com/nitro/blob/master/LICENSE
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;
interface IChallengeResultReceiver {
function completeChallenge(
uint256 challengeIndex,
address winner,
address loser
) external;
}
// Copyright 2021-2022, Offchain Labs, Inc.
// For license information, see https://github.com/nitro/blob/master/LICENSE
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;
import "./Value.sol";
import "./ValueArray.sol";
struct ValueStack {
ValueArray proved;
bytes32 remainingHash;
}
library ValueStackLib {
using ValueLib for Value;
using ValueArrayLib for ValueArray;
function hash(ValueStack memory stack) internal pure returns (bytes32 h) {
h = stack.remainingHash;
uint256 len = stack.proved.length();
for (uint256 i = 0; i < len; i++) {
h = keccak256(abi.encodePacked("Value stack:", stack.proved.get(i).hash(), h));
}
}
function peek(ValueStack memory stack) internal pure returns (Value memory) {
uint256 len = stack.proved.length();
return stack.proved.get(len - 1);
}
function pop(ValueStack memory stack) internal pure returns (Value memory) {
return stack.proved.pop();
}
function push(ValueStack memory stack, Value memory val) internal pure {
return stack.proved.push(val);
}
}
// Copyright 2021-2022, Offchain Labs, Inc.
// For license information, see https://github.com/nitro/blob/master/LICENSE
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;
struct Instruction {
uint16 opcode;
uint256 argumentData;
}
library Instructions {
uint16 internal constant UNREACHABLE = 0x00;
uint16 internal constant NOP = 0x01;
uint16 internal constant RETURN = 0x0F;
uint16 internal constant CALL = 0x10;
uint16 internal constant CALL_INDIRECT = 0x11;
uint16 internal constant LOCAL_GET = 0x20;
uint16 internal constant LOCAL_SET = 0x21;
uint16 internal constant GLOBAL_GET = 0x23;
uint16 internal constant GLOBAL_SET = 0x24;
uint16 internal constant I32_LOAD = 0x28;
uint16 internal constant I64_LOAD = 0x29;
uint16 internal constant F32_LOAD = 0x2A;
uint16 internal constant F64_LOAD = 0x2B;
uint16 internal constant I32_LOAD8_S = 0x2C;
uint16 internal constant I32_LOAD8_U = 0x2D;
uint16 internal constant I32_LOAD16_S = 0x2E;
uint16 internal constant I32_LOAD16_U = 0x2F;
uint16 internal constant I64_LOAD8_S = 0x30;
uint16 internal constant I64_LOAD8_U = 0x31;
uint16 internal constant I64_LOAD16_S = 0x32;
uint16 internal constant I64_LOAD16_U = 0x33;
uint16 internal constant I64_LOAD32_S = 0x34;
uint16 internal constant I64_LOAD32_U = 0x35;
uint16 internal constant I32_STORE = 0x36;
uint16 internal constant I64_STORE = 0x37;
uint16 internal constant F32_STORE = 0x38;
uint16 internal constant F64_STORE = 0x39;
uint16 internal constant I32_STORE8 = 0x3A;
uint16 internal constant I32_STORE16 = 0x3B;
uint16 internal constant I64_STORE8 = 0x3C;
uint16 internal constant I64_STORE16 = 0x3D;
uint16 internal constant I64_STORE32 = 0x3E;
uint16 internal constant MEMORY_SIZE = 0x3F;
uint16 internal constant MEMORY_GROW = 0x40;
uint16 internal constant DROP = 0x1A;
uint16 internal constant SELECT = 0x1B;
uint16 internal constant I32_CONST = 0x41;
uint16 internal constant I64_CONST = 0x42;
uint16 internal constant F32_CONST = 0x43;
uint16 internal constant F64_CONST = 0x44;
uint16 internal constant I32_EQZ = 0x45;
uint16 internal constant I32_RELOP_BASE = 0x46;
uint16 internal constant IRELOP_EQ = 0;
uint16 internal constant IRELOP_NE = 1;
uint16 internal constant IRELOP_LT_S = 2;
uint16 internal constant IRELOP_LT_U = 3;
uint16 internal constant IRELOP_GT_S = 4;
uint16 internal constant IRELOP_GT_U = 5;
uint16 internal constant IRELOP_LE_S = 6;
uint16 internal constant IRELOP_LE_U = 7;
uint16 internal constant IRELOP_GE_S = 8;
uint16 internal constant IRELOP_GE_U = 9;
uint16 internal constant IRELOP_LAST = IRELOP_GE_U;
uint16 internal constant I64_EQZ = 0x50;
uint16 internal constant I64_RELOP_BASE = 0x51;
uint16 internal constant I32_UNOP_BASE = 0x67;
uint16 internal constant IUNOP_CLZ = 0;
uint16 internal constant IUNOP_CTZ = 1;
uint16 internal constant IUNOP_POPCNT = 2;
uint16 internal constant IUNOP_LAST = IUNOP_POPCNT;
uint16 internal constant I32_ADD = 0x6A;
uint16 internal constant I32_SUB = 0x6B;
uint16 internal constant I32_MUL = 0x6C;
uint16 internal constant I32_DIV_S = 0x6D;
uint16 internal constant I32_DIV_U = 0x6E;
uint16 internal constant I32_REM_S = 0x6F;
uint16 internal constant I32_REM_U = 0x70;
uint16 internal constant I32_AND = 0x71;
uint16 internal constant I32_OR = 0x72;
uint16 internal constant I32_XOR = 0x73;
uint16 internal constant I32_SHL = 0x74;
uint16 internal constant I32_SHR_S = 0x75;
uint16 internal constant I32_SHR_U = 0x76;
uint16 internal constant I32_ROTL = 0x77;
uint16 internal constant I32_ROTR = 0x78;
uint16 internal constant I64_UNOP_BASE = 0x79;
uint16 internal constant I64_ADD = 0x7C;
uint16 internal constant I64_SUB = 0x7D;
uint16 internal constant I64_MUL = 0x7E;
uint16 internal constant I64_DIV_S = 0x7F;
uint16 internal constant I64_DIV_U = 0x80;
uint16 internal constant I64_REM_S = 0x81;
uint16 internal constant I64_REM_U = 0x82;
uint16 internal constant I64_AND = 0x83;
uint16 internal constant I64_OR = 0x84;
uint16 internal constant I64_XOR = 0x85;
uint16 internal constant I64_SHL = 0x86;
uint16 internal constant I64_SHR_S = 0x87;
uint16 internal constant I64_SHR_U = 0x88;
uint16 internal constant I64_ROTL = 0x89;
uint16 internal constant I64_ROTR = 0x8A;
uint16 internal constant I32_WRAP_I64 = 0xA7;
uint16 internal constant I64_EXTEND_I32_S = 0xAC;
uint16 internal constant I64_EXTEND_I32_U = 0xAD;
uint16 internal constant I32_REINTERPRET_F32 = 0xBC;
uint16 internal constant I64_REINTERPRET_F64 = 0xBD;
uint16 internal constant F32_REINTERPRET_I32 = 0xBE;
uint16 internal constant F64_REINTERPRET_I64 = 0xBF;
uint16 internal constant I32_EXTEND_8S = 0xC0;
uint16 internal constant I32_EXTEND_16S = 0xC1;
uint16 internal constant I64_EXTEND_8S = 0xC2;
uint16 internal constant I64_EXTEND_16S = 0xC3;
uint16 internal constant I64_EXTEND_32S = 0xC4;
uint16 internal constant INIT_FRAME = 0x8002;
uint16 internal constant ARBITRARY_JUMP = 0x8003;
uint16 internal constant ARBITRARY_JUMP_IF = 0x8004;
uint16 internal constant MOVE_FROM_STACK_TO_INTERNAL = 0x8005;
uint16 internal constant MOVE_FROM_INTERNAL_TO_STACK = 0x8006;
uint16 internal constant DUP = 0x8008;
uint16 internal constant CROSS_MODULE_CALL = 0x8009;
uint16 internal constant CALLER_MODULE_INTERNAL_CALL = 0x800A;
uint16 internal constant GET_GLOBAL_STATE_BYTES32 = 0x8010;
uint16 internal constant SET_GLOBAL_STATE_BYTES32 = 0x8011;
uint16 internal constant GET_GLOBAL_STATE_U64 = 0x8012;
uint16 internal constant SET_GLOBAL_STATE_U64 = 0x8013;
uint16 internal constant READ_PRE_IMAGE = 0x8020;
uint16 internal constant READ_INBOX_MESSAGE = 0x8021;
uint16 internal constant HALT_AND_SET_FINISHED = 0x8022;
uint256 internal constant INBOX_INDEX_SEQUENCER = 0;
uint256 internal constant INBOX_INDEX_DELAYED = 1;
function hash(Instruction memory inst) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("Instruction:", inst.opcode, inst.argumentData));
}
}
// Copyright 2021-2022, Offchain Labs, Inc.
// For license information, see https://github.com/nitro/blob/master/LICENSE
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;
import "./Value.sol";
struct StackFrame {
Value returnPc;
bytes32 localsMerkleRoot;
uint32 callerModule;
uint32 callerModuleInternals;
}
struct StackFrameWindow {
StackFrame[] proved;
bytes32 remainingHash;
}
library StackFrameLib {
using ValueLib for Value;
function hash(StackFrame memory frame) internal pure returns (bytes32) {
return
keccak256(
abi.encodePacked(
"Stack frame:",
frame.returnPc.hash(),
frame.localsMerkleRoot,
frame.callerModule,
frame.callerModuleInternals
)
);
}
function hash(StackFrameWindow memory window) internal pure returns (bytes32 h) {
h = window.remainingHash;
for (uint256 i = 0; i < window.proved.length; i++) {
h = keccak256(abi.encodePacked("Stack frame stack:", hash(window.proved[i]), h));
}
}
function peek(StackFrameWindow memory window) internal pure returns (StackFrame memory) {
require(window.proved.length == 1, "BAD_WINDOW_LENGTH");
return window.proved[0];
}
function pop(StackFrameWindow memory window) internal pure returns (StackFrame memory frame) {
require(window.proved.length == 1, "BAD_WINDOW_LENGTH");
frame = window.proved[0];
window.proved = new StackFrame[](0);
}
function push(StackFrameWindow memory window, StackFrame memory frame) internal pure {
StackFrame[] memory newProved = new StackFrame[](window.proved.length + 1);
for (uint256 i = 0; i < window.proved.length; i++) {
newProved[i] = window.proved[i];
}
newProved[window.proved.length] = frame;
window.proved = newProved;
}
}
// Copyright 2021-2022, Offchain Labs, Inc.
// For license information, see https://github.com/nitro/blob/master/LICENSE
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;
enum ValueType {
I32,
I64,
F32,
F64,
REF_NULL,
FUNC_REF,
INTERNAL_REF
}
struct Value {
ValueType valueType;
uint256 contents;
}
library ValueLib {
function hash(Value memory val) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("Value:", val.valueType, val.contents));
}
function maxValueType() internal pure returns (ValueType) {
return ValueType.INTERNAL_REF;
}
function assumeI32(Value memory val) internal pure returns (uint32) {
uint256 uintval = uint256(val.contents);
require(val.valueType == ValueType.I32, "NOT_I32");
require(uintval < (1 << 32), "BAD_I32");
return uint32(uintval);
}
function assumeI64(Value memory val) internal pure returns (uint64) {
uint256 uintval = uint256(val.contents);
require(val.valueType == ValueType.I64, "NOT_I64");
require(uintval < (1 << 64), "BAD_I64");
return uint64(uintval);
}
function newRefNull() internal pure returns (Value memory) {
return Value({valueType: ValueType.REF_NULL, contents: 0});
}
function newI32(uint32 x) internal pure returns (Value memory) {
return Value({valueType: ValueType.I32, contents: uint256(x)});
}
function newI64(uint64 x) internal pure returns (Value memory) {
return Value({valueType: ValueType.I64, contents: uint256(x)});
}
function newBoolean(bool x) internal pure returns (Value memory) {
if (x) {
return newI32(uint32(1));
} else {
return newI32(uint32(0));
}
}
}
// Copyright 2021-2022, Offchain Labs, Inc.
// For license information, see https://github.com/nitro/blob/master/LICENSE
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;
import "./Value.sol";
struct ValueArray {
Value[] inner;
}
library ValueArrayLib {
function get(ValueArray memory arr, uint256 index) internal pure returns (Value memory) {
return arr.inner[index];
}
function set(
ValueArray memory arr,
uint256 index,
Value memory val
) internal pure {
arr.inner[index] = val;
}
function length(ValueArray memory arr) internal pure returns (uint256) {
return arr.inner.length;
}
function push(ValueArray memory arr, Value memory val) internal pure {
Value[] memory newInner = new Value[](arr.inner.length + 1);
for (uint256 i = 0; i < arr.inner.length; i++) {
newInner[i] = arr.inner[i];
}
newInner[arr.inner.length] = val;
arr.inner = newInner;
}
function pop(ValueArray memory arr) internal pure returns (Value memory popped) {
popped = arr.inner[arr.inner.length - 1];
Value[] memory newInner = new Value[](arr.inner.length - 1);
for (uint256 i = 0; i < newInner.length; i++) {
newInner[i] = arr.inner[i];
}
arr.inner = newInner;
}
}
// Copyright 2021-2022, Offchain Labs, Inc.
// For license information, see https://github.com/nitro/blob/master/LICENSE
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;
import "../state/Machine.sol";
import "../state/Module.sol";
import "../state/Instructions.sol";
import "../bridge/ISequencerInbox.sol";
import "../bridge/IBridge.sol";
struct ExecutionContext {
uint256 maxInboxMessagesRead;
IBridge bridge;
}
abstract contract IOneStepProver {
function executeOneStep(
ExecutionContext memory execCtx,
Machine calldata mach,
Module calldata mod,
Instruction calldata instruction,
bytes calldata proof
) external view virtual returns (Machine memory result, Module memory resultMod);
}
// Copyright 2021-2022, Offchain Labs, Inc.
// For license information, see https://github.com/nitro/blob/master/LICENSE
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;
import "./ModuleMemory.sol";
struct Module {
bytes32 globalsMerkleRoot;
ModuleMemory moduleMemory;
bytes32 tablesMerkleRoot;
bytes32 functionsMerkleRoot;
uint32 internalsOffset;
}
library ModuleLib {
using ModuleMemoryLib for ModuleMemory;
function hash(Module memory mod) internal pure returns (bytes32) {
return
keccak256(
abi.encodePacked(
"Module:",
mod.globalsMerkleRoot,
mod.moduleMemory.hash(),
mod.tablesMerkleRoot,
mod.functionsMerkleRoot,
mod.internalsOffset
)
);
}
}
// Copyright 2021-2022, Offchain Labs, Inc.
// For license information, see https://github.com/nitro/blob/master/LICENSE
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;
import "./MerkleProof.sol";
import "./Deserialize.sol";
struct ModuleMemory {
uint64 size;
uint64 maxSize;
bytes32 merkleRoot;
}
library ModuleMemoryLib {
using MerkleProofLib for MerkleProof;
function hash(ModuleMemory memory mem) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("Memory:", mem.size, mem.maxSize, mem.merkleRoot));
}
function proveLeaf(
ModuleMemory memory mem,
uint256 leafIdx,
bytes calldata proof,
uint256 startOffset
)
internal
pure
returns (
bytes32 contents,
uint256 offset,
MerkleProof memory merkle
)
{
offset = startOffset;
(contents, offset) = Deserialize.b32(proof, offset);
(merkle, offset) = Deserialize.merkleProof(proof, offset);
bytes32 recomputedRoot = merkle.computeRootFromMemory(leafIdx, contents);
require(recomputedRoot == mem.merkleRoot, "WRONG_MEM_ROOT");
}
}
// Copyright 2021-2022, Offchain Labs, Inc.
// For license information, see https://github.com/nitro/blob/master/LICENSE
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;
import "./Value.sol";
import "./Instructions.sol";
import "./Module.sol";
struct MerkleProof {
bytes32[] counterparts;
}
library MerkleProofLib {
using ModuleLib for Module;
using ValueLib for Value;
function computeRootFromValue(
MerkleProof memory proof,
uint256 index,
Value memory leaf
) internal pure returns (bytes32) {
return computeRootUnsafe(proof, index, leaf.hash(), "Value merkle tree:");
}
function computeRootFromInstruction(
MerkleProof memory proof,
uint256 index,
Instruction memory inst
) internal pure returns (bytes32) {
return computeRootUnsafe(proof, index, Instructions.hash(inst), "Instruction merkle tree:");
}
function computeRootFromFunction(
MerkleProof memory proof,
uint256 index,
bytes32 codeRoot
) internal pure returns (bytes32) {
bytes32 h = keccak256(abi.encodePacked("Function:", codeRoot));
return computeRootUnsafe(proof, index, h, "Function merkle tree:");
}
function computeRootFromMemory(
MerkleProof memory proof,
uint256 index,
bytes32 contents
) internal pure returns (bytes32) {
bytes32 h = keccak256(abi.encodePacked("Memory leaf:", contents));
return computeRootUnsafe(proof, index, h, "Memory merkle tree:");
}
function computeRootFromElement(
MerkleProof memory proof,
uint256 index,
bytes32 funcTypeHash,
Value memory val
) internal pure returns (bytes32) {
bytes32 h = keccak256(abi.encodePacked("Table element:", funcTypeHash, val.hash()));
return computeRootUnsafe(proof, index, h, "Table element merkle tree:");
}
function computeRootFromTable(
MerkleProof memory proof,
uint256 index,
uint8 tableType,
uint64 tableSize,
bytes32 elementsRoot
) internal pure returns (bytes32) {
bytes32 h = keccak256(abi.encodePacked("Table:", tableType, tableSize, elementsRoot));
return computeRootUnsafe(proof, index, h, "Table merkle tree:");
}
function computeRootFromModule(
MerkleProof memory proof,
uint256 index,
Module memory mod
) internal pure returns (bytes32) {
return computeRootUnsafe(proof, index, mod.hash(), "Module merkle tree:");
}
// WARNING: leafHash must be computed in such a way that it cannot be a non-leaf hash.
function computeRootUnsafe(
MerkleProof memory proof,
uint256 index,
bytes32 leafHash,
string memory prefix
) internal pure returns (bytes32 h) {
h = leafHash;
for (uint256 layer = 0; layer < proof.counterparts.length; layer++) {
if (index & 1 == 0) {
h = keccak256(abi.encodePacked(prefix, h, proof.counterparts[layer]));
} else {
h = keccak256(abi.encodePacked(prefix, proof.counterparts[layer], h));
}
index >>= 1;
}
}
}
// Copyright 2021-2022, Offchain Labs, Inc.
// For license information, see https://github.com/nitro/blob/master/LICENSE
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;
import "./Value.sol";
import "./ValueStack.sol";
import "./Machine.sol";
import "./Instructions.sol";
import "./StackFrame.sol";
import "./MerkleProof.sol";
import "./ModuleMemory.sol";
import "./Module.sol";
import "./GlobalState.sol";
library Deserialize {
function u8(bytes calldata proof, uint256 startOffset)
internal
pure
returns (uint8 ret, uint256 offset)
{
offset = startOffset;
ret = uint8(proof[offset]);
offset++;
}
function u16(bytes calldata proof, uint256 startOffset)
internal
pure
returns (uint16 ret, uint256 offset)
{
offset = startOffset;
for (uint256 i = 0; i < 16 / 8; i++) {
ret <<= 8;
ret |= uint8(proof[offset]);
offset++;
}
}
function u32(bytes calldata proof, uint256 startOffset)
internal
pure
returns (uint32 ret, uint256 offset)
{
offset = startOffset;
for (uint256 i = 0; i < 32 / 8; i++) {
ret <<= 8;
ret |= uint8(proof[offset]);
offset++;
}
}
function u64(bytes calldata proof, uint256 startOffset)
internal
pure
returns (uint64 ret, uint256 offset)
{
offset = startOffset;
for (uint256 i = 0; i < 64 / 8; i++) {
ret <<= 8;
ret |= uint8(proof[offset]);
offset++;
}
}
function u256(bytes calldata proof, uint256 startOffset)
internal
pure
returns (uint256 ret, uint256 offset)
{
offset = startOffset;
for (uint256 i = 0; i < 256 / 8; i++) {
ret <<= 8;
ret |= uint8(proof[offset]);
offset++;
}
}
function b32(bytes calldata proof, uint256 startOffset)
internal
pure
returns (bytes32 ret, uint256 offset)
{
offset = startOffset;
uint256 retInt;
(retInt, offset) = u256(proof, offset);
ret = bytes32(retInt);
}
function value(bytes calldata proof, uint256 startOffset)
internal
pure
returns (Value memory val, uint256 offset)
{
offset = startOffset;
uint8 typeInt = uint8(proof[offset]);
offset++;
require(typeInt <= uint8(ValueLib.maxValueType()), "BAD_VALUE_TYPE");
uint256 contents;
(contents, offset) = u256(proof, offset);
val = Value({valueType: ValueType(typeInt), contents: contents});
}
function valueStack(bytes calldata proof, uint256 startOffset)
internal
pure
returns (ValueStack memory stack, uint256 offset)
{
offset = startOffset;
bytes32 remainingHash;
(remainingHash, offset) = b32(proof, offset);
uint256 provedLength;
(provedLength, offset) = u256(proof, offset);
Value[] memory proved = new Value[](provedLength);
for (uint256 i = 0; i < proved.length; i++) {
(proved[i], offset) = value(proof, offset);
}
stack = ValueStack({proved: ValueArray(proved), remainingHash: remainingHash});
}
function instruction(bytes calldata proof, uint256 startOffset)
internal
pure
returns (Instruction memory inst, uint256 offset)
{
offset = startOffset;
uint16 opcode;
uint256 data;
(opcode, offset) = u16(proof, offset);
(data, offset) = u256(proof, offset);
inst = Instruction({opcode: opcode, argumentData: data});
}
function stackFrame(bytes calldata proof, uint256 startOffset)
internal
pure
returns (StackFrame memory window, uint256 offset)
{
offset = startOffset;
Value memory returnPc;
bytes32 localsMerkleRoot;
uint32 callerModule;
uint32 callerModuleInternals;
(returnPc, offset) = value(proof, offset);
(localsMerkleRoot, offset) = b32(proof, offset);
(callerModule, offset) = u32(proof, offset);
(callerModuleInternals, offset) = u32(proof, offset);
window = StackFrame({
returnPc: returnPc,
localsMerkleRoot: localsMerkleRoot,
callerModule: callerModule,
callerModuleInternals: callerModuleInternals
});
}
function stackFrameWindow(bytes calldata proof, uint256 startOffset)
internal
pure
returns (StackFrameWindow memory window, uint256 offset)
{
offset = startOffset;
bytes32 remainingHash;
(remainingHash, offset) = b32(proof, offset);
StackFrame[] memory proved;
if (proof[offset] != 0) {
offset++;
proved = new StackFrame[](1);
(proved[0], offset) = stackFrame(proof, offset);
} else {
offset++;
proved = new StackFrame[](0);
}
window = StackFrameWindow({proved: proved, remainingHash: remainingHash});
}
function moduleMemory(bytes calldata proof, uint256 startOffset)
internal
pure
returns (ModuleMemory memory mem, uint256 offset)
{
offset = startOffset;
uint64 size;
uint64 maxSize;
bytes32 root;
(size, offset) = u64(proof, offset);
(maxSize, offset) = u64(proof, offset);
(root, offset) = b32(proof, offset);
mem = ModuleMemory({size: size, maxSize: maxSize, merkleRoot: root});
}
function module(bytes calldata proof, uint256 startOffset)
internal
pure
returns (Module memory mod, uint256 offset)
{
offset = startOffset;
bytes32 globalsMerkleRoot;
ModuleMemory memory mem;
bytes32 tablesMerkleRoot;
bytes32 functionsMerkleRoot;
uint32 internalsOffset;
(globalsMerkleRoot, offset) = b32(proof, offset);
(mem, offset) = moduleMemory(proof, offset);
(tablesMerkleRoot, offset) = b32(proof, offset);
(functionsMerkleRoot, offset) = b32(proof, offset);
(internalsOffset, offset) = u32(proof, offset);
mod = Module({
globalsMerkleRoot: globalsMerkleRoot,
moduleMemory: mem,
tablesMerkleRoot: tablesMerkleRoot,
functionsMerkleRoot: functionsMerkleRoot,
internalsOffset: internalsOffset
});
}
function globalState(bytes calldata proof, uint256 startOffset)
internal
pure
returns (GlobalState memory state, uint256 offset)
{
offset = startOffset;
// using constant ints for array size requires newer solidity
bytes32[2] memory bytes32Vals;
uint64[2] memory u64Vals;
for (uint8 i = 0; i < GlobalStateLib.BYTES32_VALS_NUM; i++) {
(bytes32Vals[i], offset) = b32(proof, offset);
}
for (uint8 i = 0; i < GlobalStateLib.U64_VALS_NUM; i++) {
(u64Vals[i], offset) = u64(proof, offset);
}
state = GlobalState({bytes32Vals: bytes32Vals, u64Vals: u64Vals});
}
function machine(bytes calldata proof, uint256 startOffset)
internal
pure
returns (Machine memory mach, uint256 offset)
{
offset = startOffset;
MachineStatus status;
{
uint8 statusU8;
(statusU8, offset) = u8(proof, offset);
if (statusU8 == 0) {
status = MachineStatus.RUNNING;
} else if (statusU8 == 1) {
status = MachineStatus.FINISHED;
} else if (statusU8 == 2) {
status = MachineStatus.ERRORED;
} else if (statusU8 == 3) {
status = MachineStatus.TOO_FAR;
} else {
revert("UNKNOWN_MACH_STATUS");
}
}
ValueStack memory values;
ValueStack memory internalStack;
bytes32 globalStateHash;
uint32 moduleIdx;
uint32 functionIdx;
uint32 functionPc;
StackFrameWindow memory frameStack;
bytes32 modulesRoot;
(values, offset) = valueStack(proof, offset);
(internalStack, offset) = valueStack(proof, offset);
(frameStack, offset) = stackFrameWindow(proof, offset);
(globalStateHash, offset) = b32(proof, offset);
(moduleIdx, offset) = u32(proof, offset);
(functionIdx, offset) = u32(proof, offset);
(functionPc, offset) = u32(proof, offset);
(modulesRoot, offset) = b32(proof, offset);
mach = Machine({
status: status,
valueStack: values,
internalStack: internalStack,
frameStack: frameStack,
globalStateHash: globalStateHash,
moduleIdx: moduleIdx,
functionIdx: functionIdx,
functionPc: functionPc,
modulesRoot: modulesRoot
});
}
function merkleProof(bytes calldata proof, uint256 startOffset)
internal
pure
returns (MerkleProof memory merkle, uint256 offset)
{
offset = startOffset;
uint8 length;
(length, offset) = u8(proof, offset);
bytes32[] memory counterparts = new bytes32[](length);
for (uint8 i = 0; i < length; i++) {
(counterparts[i], offset) = b32(proof, offset);
}
merkle = MerkleProof(counterparts);
}
}
// Copyright 2021-2022, Offchain Labs, Inc.
// For license information, see https://github.com/nitro/blob/master/LICENSE
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;
struct Node {
// Hash of the state of the chain as of this node
bytes32 stateHash;
// Hash of the data that can be challenged
bytes32 challengeHash;
// Hash of the data that will be committed if this node is confirmed
bytes32 confirmData;
// Index of the node previous to this one
uint64 prevNum;
// Deadline at which this node can be confirmed
uint64 deadlineBlock;
// Deadline at which a child of this node can be confirmed
uint64 noChildConfirmedBeforeBlock;
// Number of stakers staked on this node. This includes real stakers and zombies
uint64 stakerCount;
// Number of stakers staked on a child node. This includes real stakers and zombies
uint64 childStakerCount;
// This value starts at zero and is set to a value when the first child is created. After that it is constant until the node is destroyed or the owner destroys pending nodes
uint64 firstChildBlock;
// The number of the latest child of this node to be created
uint64 latestChildNumber;
// The block number when this node was created
uint64 createdAtBlock;
// A hash of all the data needed to determine this node's validity, to protect against reorgs
bytes32 nodeHash;
}
/**
* @notice Utility functions for Node
*/
library NodeLib {
/**
* @notice Initialize a Node
* @param _stateHash Initial value of stateHash
* @param _challengeHash Initial value of challengeHash
* @param _confirmData Initial value of confirmData
* @param _prevNum Initial value of prevNum
* @param _deadlineBlock Initial value of deadlineBlock
* @param _nodeHash Initial value of nodeHash
*/
function createNode(
bytes32 _stateHash,
bytes32 _challengeHash,
bytes32 _confirmData,
uint64 _prevNum,
uint64 _deadlineBlock,
bytes32 _nodeHash
) internal view returns (Node memory) {
Node memory node;
node.stateHash = _stateHash;
node.challengeHash = _challengeHash;
node.confirmData = _confirmData;
node.prevNum = _prevNum;
node.deadlineBlock = _deadlineBlock;
node.noChildConfirmedBeforeBlock = _deadlineBlock;
node.createdAtBlock = uint64(block.number);
node.nodeHash = _nodeHash;
return node;
}
/**
* @notice Update child properties
* @param number The child number to set
*/
function childCreated(Node storage self, uint64 number) internal {
if (self.firstChildBlock == 0) {
self.firstChildBlock = uint64(block.number);
}
self.latestChildNumber = number;
}
/**
* @notice Update the child confirmed deadline
* @param deadline The new deadline to set
*/
function newChildConfirmDeadline(Node storage self, uint64 deadline) internal {
self.noChildConfirmedBeforeBlock = deadline;
}
/**
* @notice Check whether the current block number has met or passed the node's deadline
*/
function requirePastDeadline(Node memory self) internal view {
require(block.number >= self.deadlineBlock, "BEFORE_DEADLINE");
}
/**
* @notice Check whether the current block number has met or passed deadline for children of this node to be confirmed
*/
function requirePastChildConfirmDeadline(Node memory self) internal view {
require(block.number >= self.noChildConfirmedBeforeBlock, "CHILD_TOO_RECENT");
}
}
File 5 of 5: Bridge
// Copyright 2021-2022, Offchain Labs, Inc.
// For license information, see https://github.com/nitro/blob/master/LICENSE
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.4;
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol";
import {
NotContract,
NotRollupOrOwner,
NotDelayedInbox,
NotSequencerInbox,
NotOutbox,
InvalidOutboxSet,
BadSequencerMessageNumber
} from "../libraries/Error.sol";
import "./IBridge.sol";
import "./Messages.sol";
import "../libraries/DelegateCallAware.sol";
import {L1MessageType_batchPostingReport} from "../libraries/MessageTypes.sol";
/**
* @title Staging ground for incoming and outgoing messages
* @notice Holds the inbox accumulator for sequenced and delayed messages.
* It is also the ETH escrow for value sent with these messages.
* Since the escrow is held here, this contract also contains a list of allowed
* outboxes that can make calls from here and withdraw this escrow.
*/
contract Bridge is Initializable, DelegateCallAware, IBridge {
using AddressUpgradeable for address;
struct InOutInfo {
uint256 index;
bool allowed;
}
mapping(address => InOutInfo) private allowedDelayedInboxesMap;
mapping(address => InOutInfo) private allowedOutboxesMap;
address[] public allowedDelayedInboxList;
address[] public allowedOutboxList;
address private _activeOutbox;
/// @inheritdoc IBridge
bytes32[] public delayedInboxAccs;
/// @inheritdoc IBridge
bytes32[] public sequencerInboxAccs;
IOwnable public rollup;
address public sequencerInbox;
uint256 public override sequencerReportedSubMessageCount;
address private constant EMPTY_ACTIVEOUTBOX = address(type(uint160).max);
function initialize(IOwnable rollup_) external initializer onlyDelegated {
_activeOutbox = EMPTY_ACTIVEOUTBOX;
rollup = rollup_;
}
modifier onlyRollupOrOwner() {
if (msg.sender != address(rollup)) {
address rollupOwner = rollup.owner();
if (msg.sender != rollupOwner) {
revert NotRollupOrOwner(msg.sender, address(rollup), rollupOwner);
}
}
_;
}
/// @dev returns the address of current active Outbox, or zero if no outbox is active
function activeOutbox() public view returns (address) {
address outbox = _activeOutbox;
// address zero is returned if no outbox is set, but the value used in storage
// is non-zero to save users some gas (as storage refunds are usually maxed out)
// EIP-1153 would help here.
// we don't return `EMPTY_ACTIVEOUTBOX` to avoid a breaking change on the current api
if (outbox == EMPTY_ACTIVEOUTBOX) return address(0);
return outbox;
}
function allowedDelayedInboxes(address inbox) external view returns (bool) {
return allowedDelayedInboxesMap[inbox].allowed;
}
function allowedOutboxes(address outbox) external view returns (bool) {
return allowedOutboxesMap[outbox].allowed;
}
modifier onlySequencerInbox() {
if (msg.sender != sequencerInbox) revert NotSequencerInbox(msg.sender);
_;
}
function enqueueSequencerMessage(
bytes32 dataHash,
uint256 afterDelayedMessagesRead,
uint256 prevMessageCount,
uint256 newMessageCount
)
external
onlySequencerInbox
returns (
uint256 seqMessageIndex,
bytes32 beforeAcc,
bytes32 delayedAcc,
bytes32 acc
)
{
if (
sequencerReportedSubMessageCount != prevMessageCount &&
prevMessageCount != 0 &&
sequencerReportedSubMessageCount != 0
) {
revert BadSequencerMessageNumber(sequencerReportedSubMessageCount, prevMessageCount);
}
sequencerReportedSubMessageCount = newMessageCount;
seqMessageIndex = sequencerInboxAccs.length;
if (sequencerInboxAccs.length > 0) {
beforeAcc = sequencerInboxAccs[sequencerInboxAccs.length - 1];
}
if (afterDelayedMessagesRead > 0) {
delayedAcc = delayedInboxAccs[afterDelayedMessagesRead - 1];
}
acc = keccak256(abi.encodePacked(beforeAcc, dataHash, delayedAcc));
sequencerInboxAccs.push(acc);
}
/// @inheritdoc IBridge
function submitBatchSpendingReport(address sender, bytes32 messageDataHash)
external
onlySequencerInbox
returns (uint256)
{
return
addMessageToDelayedAccumulator(
L1MessageType_batchPostingReport,
sender,
uint64(block.number),
uint64(block.timestamp), // solhint-disable-line not-rely-on-time,
block.basefee,
messageDataHash
);
}
/// @inheritdoc IBridge
function enqueueDelayedMessage(
uint8 kind,
address sender,
bytes32 messageDataHash
) external payable returns (uint256) {
if (!allowedDelayedInboxesMap[msg.sender].allowed) revert NotDelayedInbox(msg.sender);
return
addMessageToDelayedAccumulator(
kind,
sender,
uint64(block.number),
uint64(block.timestamp), // solhint-disable-line not-rely-on-time
block.basefee,
messageDataHash
);
}
function addMessageToDelayedAccumulator(
uint8 kind,
address sender,
uint64 blockNumber,
uint64 blockTimestamp,
uint256 baseFeeL1,
bytes32 messageDataHash
) internal returns (uint256) {
uint256 count = delayedInboxAccs.length;
bytes32 messageHash = Messages.messageHash(
kind,
sender,
blockNumber,
blockTimestamp,
count,
baseFeeL1,
messageDataHash
);
bytes32 prevAcc = 0;
if (count > 0) {
prevAcc = delayedInboxAccs[count - 1];
}
delayedInboxAccs.push(Messages.accumulateInboxMessage(prevAcc, messageHash));
emit MessageDelivered(
count,
prevAcc,
msg.sender,
kind,
sender,
messageDataHash,
baseFeeL1,
blockTimestamp
);
return count;
}
function executeCall(
address to,
uint256 value,
bytes calldata data
) external returns (bool success, bytes memory returnData) {
if (!allowedOutboxesMap[msg.sender].allowed) revert NotOutbox(msg.sender);
if (data.length > 0 && !to.isContract()) revert NotContract(to);
address prevOutbox = _activeOutbox;
_activeOutbox = msg.sender;
// We set and reset active outbox around external call so activeOutbox remains valid during call
// We use a low level call here since we want to bubble up whether it succeeded or failed to the caller
// rather than reverting on failure as well as allow contract and non-contract calls
// solhint-disable-next-line avoid-low-level-calls
(success, returnData) = to.call{value: value}(data);
_activeOutbox = prevOutbox;
emit BridgeCallTriggered(msg.sender, to, value, data);
}
function setSequencerInbox(address _sequencerInbox) external onlyRollupOrOwner {
sequencerInbox = _sequencerInbox;
emit SequencerInboxUpdated(_sequencerInbox);
}
function setDelayedInbox(address inbox, bool enabled) external onlyRollupOrOwner {
InOutInfo storage info = allowedDelayedInboxesMap[inbox];
bool alreadyEnabled = info.allowed;
emit InboxToggle(inbox, enabled);
if ((alreadyEnabled && enabled) || (!alreadyEnabled && !enabled)) {
return;
}
if (enabled) {
allowedDelayedInboxesMap[inbox] = InOutInfo(allowedDelayedInboxList.length, true);
allowedDelayedInboxList.push(inbox);
} else {
allowedDelayedInboxList[info.index] = allowedDelayedInboxList[
allowedDelayedInboxList.length - 1
];
allowedDelayedInboxesMap[allowedDelayedInboxList[info.index]].index = info.index;
allowedDelayedInboxList.pop();
delete allowedDelayedInboxesMap[inbox];
}
}
function setOutbox(address outbox, bool enabled) external onlyRollupOrOwner {
if (outbox == EMPTY_ACTIVEOUTBOX) revert InvalidOutboxSet(outbox);
InOutInfo storage info = allowedOutboxesMap[outbox];
bool alreadyEnabled = info.allowed;
emit OutboxToggle(outbox, enabled);
if ((alreadyEnabled && enabled) || (!alreadyEnabled && !enabled)) {
return;
}
if (enabled) {
allowedOutboxesMap[outbox] = InOutInfo(allowedOutboxList.length, true);
allowedOutboxList.push(outbox);
} else {
allowedOutboxList[info.index] = allowedOutboxList[allowedOutboxList.length - 1];
allowedOutboxesMap[allowedOutboxList[info.index]].index = info.index;
allowedOutboxList.pop();
delete allowedOutboxesMap[outbox];
}
}
function setSequencerReportedSubMessageCount(uint256 newMsgCount) external onlyRollupOrOwner {
sequencerReportedSubMessageCount = newMsgCount;
}
function delayedMessageCount() external view override returns (uint256) {
return delayedInboxAccs.length;
}
function sequencerMessageCount() external view returns (uint256) {
return sequencerInboxAccs.length;
}
/// @dev For the classic -> nitro migration. TODO: remove post-migration.
function acceptFundsFromOldBridge() external payable {}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.0;
import "../../utils/AddressUpgradeable.sol";
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To initialize the implementation contract, you can either invoke the
* initializer manually, or you can include a constructor to automatically mark it as initialized when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() initializer {}
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Indicates that the contract has been initialized.
*/
bool private _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool private _initializing;
/**
* @dev Modifier to protect an initializer function from being invoked twice.
*/
modifier initializer() {
// If the contract is initializing we ignore whether _initialized is set in order to support multiple
// inheritance patterns, but we only do this in the context of a constructor, because in other contexts the
// contract may have been reentered.
require(_initializing ? _isConstructor() : !_initialized, "Initializable: contract is already initialized");
bool isTopLevelCall = !_initializing;
if (isTopLevelCall) {
_initializing = true;
_initialized = true;
}
_;
if (isTopLevelCall) {
_initializing = false;
}
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} modifier, directly or indirectly.
*/
modifier onlyInitializing() {
require(_initializing, "Initializable: contract is not initializing");
_;
}
function _isConstructor() private view returns (bool) {
return !AddressUpgradeable.isContract(address(this));
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library AddressUpgradeable {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
// Copyright 2021-2022, Offchain Labs, Inc.
// For license information, see https://github.com/nitro/blob/master/LICENSE
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.4;
/// @dev Init was already called
error AlreadyInit();
/// Init was called with param set to zero that must be nonzero
error HadZeroInit();
/// @dev Thrown when non owner tries to access an only-owner function
/// @param sender The msg.sender who is not the owner
/// @param owner The owner address
error NotOwner(address sender, address owner);
/// @dev Thrown when an address that is not the rollup tries to call an only-rollup function
/// @param sender The sender who is not the rollup
/// @param rollup The rollup address authorized to call this function
error NotRollup(address sender, address rollup);
/// @dev Thrown when the contract was not called directly from the origin ie msg.sender != tx.origin
error NotOrigin();
/// @dev Provided data was too large
/// @param dataLength The length of the data that is too large
/// @param maxDataLength The max length the data can be
error DataTooLarge(uint256 dataLength, uint256 maxDataLength);
/// @dev The provided is not a contract and was expected to be
/// @param addr The adddress in question
error NotContract(address addr);
/// @dev The merkle proof provided was too long
/// @param actualLength The length of the merkle proof provided
/// @param maxProofLength The max length a merkle proof can have
error MerkleProofTooLong(uint256 actualLength, uint256 maxProofLength);
/// @dev Thrown when an un-authorized address tries to access an admin function
/// @param sender The un-authorized sender
/// @param rollup The rollup, which would be authorized
/// @param owner The rollup's owner, which would be authorized
error NotRollupOrOwner(address sender, address rollup, address owner);
// Bridge Errors
/// @dev Thrown when an un-authorized address tries to access an only-inbox function
/// @param sender The un-authorized sender
error NotDelayedInbox(address sender);
/// @dev Thrown when an un-authorized address tries to access an only-sequencer-inbox function
/// @param sender The un-authorized sender
error NotSequencerInbox(address sender);
/// @dev Thrown when an un-authorized address tries to access an only-outbox function
/// @param sender The un-authorized sender
error NotOutbox(address sender);
/// @dev the provided outbox address isn't valid
/// @param outbox address of outbox being set
error InvalidOutboxSet(address outbox);
// Inbox Errors
/// @dev The contract is paused, so cannot be paused
error AlreadyPaused();
/// @dev The contract is unpaused, so cannot be unpaused
error AlreadyUnpaused();
/// @dev The contract is paused
error Paused();
/// @dev msg.value sent to the inbox isn't high enough
error InsufficientValue(uint256 expected, uint256 actual);
/// @dev submission cost provided isn't enough to create retryable ticket
error InsufficientSubmissionCost(uint256 expected, uint256 actual);
/// @dev address not allowed to interact with the given contract
error NotAllowedOrigin(address origin);
/// @dev used to convey retryable tx data in eth calls without requiring a tx trace
/// this follows a pattern similar to EIP-3668 where reverts surface call information
error RetryableData(
address from,
address to,
uint256 l2CallValue,
uint256 deposit,
uint256 maxSubmissionCost,
address excessFeeRefundAddress,
address callValueRefundAddress,
uint256 gasLimit,
uint256 maxFeePerGas,
bytes data
);
// Outbox Errors
/// @dev The provided proof was too long
/// @param proofLength The length of the too-long proof
error ProofTooLong(uint256 proofLength);
/// @dev The output index was greater than the maximum
/// @param index The output index
/// @param maxIndex The max the index could be
error PathNotMinimal(uint256 index, uint256 maxIndex);
/// @dev The calculated root does not exist
/// @param root The calculated root
error UnknownRoot(bytes32 root);
/// @dev The record has already been spent
/// @param index The index of the spent record
error AlreadySpent(uint256 index);
/// @dev A call to the bridge failed with no return data
error BridgeCallFailed();
// Sequencer Inbox Errors
/// @dev Thrown when someone attempts to read fewer messages than have already been read
error DelayedBackwards();
/// @dev Thrown when someone attempts to read more messages than exist
error DelayedTooFar();
/// @dev Force include can only read messages more blocks old than the delay period
error ForceIncludeBlockTooSoon();
/// @dev Force include can only read messages more seconds old than the delay period
error ForceIncludeTimeTooSoon();
/// @dev The message provided did not match the hash in the delayed inbox
error IncorrectMessagePreimage();
/// @dev This can only be called by the batch poster
error NotBatchPoster();
/// @dev The sequence number provided to this message was inconsistent with the number of batches already included
error BadSequencerNumber(uint256 stored, uint256 received);
/// @dev The sequence message number provided to this message was inconsistent with the previous one
error BadSequencerMessageNumber(uint256 stored, uint256 received);
/// @dev The batch data has the inbox authenticated bit set, but the batch data was not authenticated by the inbox
error DataNotAuthenticated();
/// @dev Tried to create an already valid Data Availability Service keyset
error AlreadyValidDASKeyset(bytes32);
/// @dev Tried to use or invalidate an already invalid Data Availability Service keyset
error NoSuchKeyset(bytes32);
// Copyright 2021-2022, Offchain Labs, Inc.
// For license information, see https://github.com/nitro/blob/master/LICENSE
// SPDX-License-Identifier: BUSL-1.1
// solhint-disable-next-line compiler-version
pragma solidity >=0.6.9 <0.9.0;
import "./IOwnable.sol";
interface IBridge {
event MessageDelivered(
uint256 indexed messageIndex,
bytes32 indexed beforeInboxAcc,
address inbox,
uint8 kind,
address sender,
bytes32 messageDataHash,
uint256 baseFeeL1,
uint64 timestamp
);
event BridgeCallTriggered(
address indexed outbox,
address indexed to,
uint256 value,
bytes data
);
event InboxToggle(address indexed inbox, bool enabled);
event OutboxToggle(address indexed outbox, bool enabled);
event SequencerInboxUpdated(address newSequencerInbox);
function allowedDelayedInboxList(uint256) external returns (address);
function allowedOutboxList(uint256) external returns (address);
/// @dev Accumulator for delayed inbox messages; tail represents hash of the current state; each element represents the inclusion of a new message.
function delayedInboxAccs(uint256) external view returns (bytes32);
/// @dev Accumulator for sequencer inbox messages; tail represents hash of the current state; each element represents the inclusion of a new message.
function sequencerInboxAccs(uint256) external view returns (bytes32);
function rollup() external view returns (IOwnable);
function sequencerInbox() external view returns (address);
function activeOutbox() external view returns (address);
function allowedDelayedInboxes(address inbox) external view returns (bool);
function allowedOutboxes(address outbox) external view returns (bool);
function sequencerReportedSubMessageCount() external view returns (uint256);
/**
* @dev Enqueue a message in the delayed inbox accumulator.
* These messages are later sequenced in the SequencerInbox, either
* by the sequencer as part of a normal batch, or by force inclusion.
*/
function enqueueDelayedMessage(
uint8 kind,
address sender,
bytes32 messageDataHash
) external payable returns (uint256);
function executeCall(
address to,
uint256 value,
bytes calldata data
) external returns (bool success, bytes memory returnData);
function delayedMessageCount() external view returns (uint256);
function sequencerMessageCount() external view returns (uint256);
// ---------- onlySequencerInbox functions ----------
function enqueueSequencerMessage(
bytes32 dataHash,
uint256 afterDelayedMessagesRead,
uint256 prevMessageCount,
uint256 newMessageCount
)
external
returns (
uint256 seqMessageIndex,
bytes32 beforeAcc,
bytes32 delayedAcc,
bytes32 acc
);
/**
* @dev Allows the sequencer inbox to submit a delayed message of the batchPostingReport type
* This is done through a separate function entrypoint instead of allowing the sequencer inbox
* to call `enqueueDelayedMessage` to avoid the gas overhead of an extra SLOAD in either
* every delayed inbox or every sequencer inbox call.
*/
function submitBatchSpendingReport(address batchPoster, bytes32 dataHash)
external
returns (uint256 msgNum);
// ---------- onlyRollupOrOwner functions ----------
function setSequencerInbox(address _sequencerInbox) external;
function setDelayedInbox(address inbox, bool enabled) external;
function setOutbox(address inbox, bool enabled) external;
// ---------- initializer ----------
function initialize(IOwnable rollup_) external;
}
// Copyright 2021-2022, Offchain Labs, Inc.
// For license information, see https://github.com/nitro/blob/master/LICENSE
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;
library Messages {
function messageHash(
uint8 kind,
address sender,
uint64 blockNumber,
uint64 timestamp,
uint256 inboxSeqNum,
uint256 baseFeeL1,
bytes32 messageDataHash
) internal pure returns (bytes32) {
return
keccak256(
abi.encodePacked(
kind,
sender,
blockNumber,
timestamp,
inboxSeqNum,
baseFeeL1,
messageDataHash
)
);
}
function accumulateInboxMessage(bytes32 prevAcc, bytes32 message)
internal
pure
returns (bytes32)
{
return keccak256(abi.encodePacked(prevAcc, message));
}
}
// Copyright 2021-2022, Offchain Labs, Inc.
// For license information, see https://github.com/nitro/blob/master/LICENSE
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;
import {NotOwner} from "./Error.sol";
/// @dev A stateless contract that allows you to infer if the current call has been delegated or not
/// Pattern used here is from UUPS implementation by the OpenZeppelin team
abstract contract DelegateCallAware {
address private immutable __self = address(this);
/**
* @dev Check that the execution is being performed through a delegate call. This allows a function to be
* callable on the proxy contract but not on the logic contract.
*/
modifier onlyDelegated() {
require(address(this) != __self, "Function must be called through delegatecall");
_;
}
/**
* @dev Check that the execution is not being performed through a delegate call. This allows a function to be
* callable on the implementing contract but not through proxies.
*/
modifier notDelegated() {
require(address(this) == __self, "Function must not be called through delegatecall");
_;
}
/// @dev Check that msg.sender is the current EIP 1967 proxy admin
modifier onlyProxyOwner() {
// Storage slot with the admin of the proxy contract
// This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1
bytes32 slot = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
address admin;
assembly {
admin := sload(slot)
}
if (msg.sender != admin) revert NotOwner(msg.sender, admin);
_;
}
}
// Copyright 2021-2022, Offchain Labs, Inc.
// For license information, see https://github.com/nitro/blob/master/LICENSE
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.4;
uint8 constant L2_MSG = 3;
uint8 constant L1MessageType_L2FundedByL1 = 7;
uint8 constant L1MessageType_submitRetryableTx = 9;
uint8 constant L1MessageType_ethDeposit = 12;
uint8 constant L1MessageType_batchPostingReport = 13;
uint8 constant L2MessageType_unsignedEOATx = 0;
uint8 constant L2MessageType_unsignedContractTx = 1;
uint8 constant ROLLUP_PROTOCOL_EVENT_TYPE = 8;
uint8 constant INITIALIZATION_MSG_TYPE = 11;
// Copyright 2021-2022, Offchain Labs, Inc.
// For license information, see https://github.com/nitro/blob/master/LICENSE
// SPDX-License-Identifier: BUSL-1.1
// solhint-disable-next-line compiler-version
pragma solidity >=0.4.21 <0.9.0;
interface IOwnable {
function owner() external view returns (address);
}