Transaction Hash:
Block:
18421588 at Oct-24-2023 05:24:59 PM +UTC
Transaction Fee:
0.041836786679872404 ETH
$85.79
Gas Used:
1,839,732 Gas / 22.740696297 Gwei
Emitted Events:
| 226 |
TransparentUpgradeableProxy.0x5e3c1311ea442664e8b1611bfabef659120ea7a0a2cfc0667700bebc69cbffe1( 0x5e3c1311ea442664e8b1611bfabef659120ea7a0a2cfc0667700bebc69cbffe1, 0x0000000000000000000000000000000000000000000000000000000000116d15, 0x5cf709717424af408e6a993037e45a3222ba4ed545f25274d3954bcfe57b4370, 0000000000000000000000001c479675ad559dc151f6ec7ed3fbf8cee79582b6, 000000000000000000000000000000000000000000000000000000000000000d, 000000000000000000000000c1b634853cb333d3ad8663715b08f41a3aec47cc, 3367145364b5d40f9ebe2ebfffc95c146d149905d5d64d99a3f37cbcfe47e986, 0000000000000000000000000000000000000000000000000000000548788c69, 000000000000000000000000000000000000000000000000000000006537fdeb )
|
| 227 |
TransparentUpgradeableProxy.0xff64905f73a67fb594e0f940a8075a860db489ad991e032f48c81123eb52d60b( 0xff64905f73a67fb594e0f940a8075a860db489ad991e032f48c81123eb52d60b, 0x0000000000000000000000000000000000000000000000000000000000116d15, 0000000000000000000000000000000000000000000000000000000000000020, 0000000000000000000000000000000000000000000000000000000000000094, 000000000000000000000000000000000000000000000000000000006537fdeb, c1b634853cb333d3ad8663715b08f41a3aec47cc28f38ab85e5993af06c03368, 1795d0b58e575f69da51d8f7776163031b5b743e000000000000000000000000, 000000000000000000000000000000000005ce9c000000000000000000000000, 0000000000000000000000000000000548788c69000000000000000000000000 )
|
| 228 |
TransparentUpgradeableProxy.0x7394f4a19a13c7b92b5bb71033245305946ef78452f7b4986ac1390b5df4ebd7( 0x7394f4a19a13c7b92b5bb71033245305946ef78452f7b4986ac1390b5df4ebd7, 0x000000000000000000000000000000000000000000000000000000000005ce9c, 0x2842f7aa3725801c0f7a75bcf58656ab39120d212ffc42a5ed2648ae4e3d166c, 0xcb3746d729b044f323854b5517d1270f191d2c3868effeb73bd45ce07226515e, 9fbe0da8d96d0ea9252395d3690b92a54808c1ccc964d3f0f56fd3766487a8af, 0000000000000000000000000000000000000000000000000000000000116d07, 000000000000000000000000000000000000000000000000000000006536ac6b, 0000000000000000000000000000000000000000000000000000000065380bfb, 00000000000000000000000000000000000000000000000000000000011900d4, 0000000000000000000000000000000000000000000000000000000001191760, 0000000000000000000000000000000000000000000000000000000000000000 )
|
| 229 |
GasRefunder.RefundedGasCosts( refundee=[Sender] 0xc1b634853cb333d3ad8663715b08f41a3aec47cc, contractAddress=[Receiver] TransparentUpgradeableProxy, success=True, gas=1876592, gasPrice=22740696297, amountPaid=41528804323971681 )
|
Account State Difference:
| Address | Before | After | State Difference | ||
|---|---|---|---|---|---|
|
0x1f9090aa...8e676c326
Miner
| 0.58701335786498669 Eth | 0.58710534446498669 Eth | 0.0000919866 | ||
| 0x8315177a...4DBd7ed3a | (Arbitrum: Bridge) | ||||
| 0xC1b63485...A3Aec47cc | (Arbitrum: Batch Submitter) |
10.001411269977445975 Eth
Nonce: 329358
|
10.001103287621545252 Eth
Nonce: 329359
| 0.000307982355900723 | |
| 0xe64a54E2...80E2E4eb5 | 603.810570942928639644 Eth | 603.769042138604667963 Eth | 0.041528804323971681 |
Execution Trace
TransparentUpgradeableProxy.8f111f3c( )
SequencerInbox.addSequencerL2BatchFromOrigin( sequenceNumber=380572, data=0x005B14F81445B07100069CF9DBC12311E9CD044194F925A390AC121ADAF8791883DBB442B6AD4D73685451216C1371EEF2DF6ADE9E01EEB022E6F3E7F96DFE39F7DE57440946828DBA0CF7C165B872897E7111C55716D1E83AC4FC2CAA59372E07689D77EF4CE5987E313559E319A636913D3979E245E4EB253631FA99CE31DE588BDCB03000E75C069F8D45EAF5A047CCBF9BD969BE95BE03FFD00DB36009043611EFF49F6AFA8B05051C79A5BBC84C2B742BF3CF75B08474C61ECF36781A4DA06834C36B63F2CA0C38272EB4870B29F212AA8D64C94D4A93DC2557C905F7F0F0A893C0954E82281F41D2314933451ABA08621A5D2B495DA7DC1ACA15B020ADD091DD85E1AEE02246D79400EB810A522A6640BA2DC914D09572D539ADE95CA5D4F6F1E3C9DFDFF92F9F52EA5DFAA7DBFCA735B7AF9406512D532C0C532B3713140EC51320A224AD06AD56F9A000110C918068C46C0494A0013436BD3FC70C285719B9049003A03672F9BFF15423111223961EFACD44425F939B981CE5FE1C5D698C797784EA5A1386E72E73EA0FC6610C4E9F43D8F0856DC529E8AF788933C92BFCF317F13BF7CD8EF037FE8A886A536410EAAC9955B8E4FADE7DE9E81B71A82231B1880516E0529B6CB9A8B850EE3A3CCF7F9BD5B9AFC68459FD9AAE75C689D7A64937330D512506C4304D090594B7C0934E7EEFDDA4982C0181A898584845C5898A1315135F10121409876B0A5E9839D7E76A047818080E16651728038002F2A4BC0B7A7B051D2615110788D3F9239CF60D6D3B3AA7274D309B177E75E25534D85E38D315D4295E0591D70300BB76DD0E2771183A8E37D39A74CAA6B53E4E007B3D02A02E8DD159D90805914900FE83DC9578B6C443CEB5D01545402E62DA83DE2FD9BE5721A47360AE2588B32403B2AA13A63CB261E00BC4D989A8F133E9AA13483E74C27AD969BAD6DDE7BC0B7503702AB5177A6B0A854FBA0DE3CB9906E4EC1D0DA625D3FF4B16C7C147053F55D3FE8955059E14984BBF0F5629309348C64EE6C29810670B7F5BE9F057EF562FC445B36BE93B7A381B005C010DA4AA78B455685FC9E671763F0DEDE0442F9B9D9F832C09DEA53BED8EDA9A944D042A6A564D3B4A853A2A3D29EFF085AB61714B2129362F30457CEF63275AEC1313E22104EA6B0C296D220D0A83867B8F0D854FD0496B885A343FF38B1B264BA51ABB692965A54CD06279E90DC6A0A1855BC61907211C0A4965BF36C2D2679B6AAA994108D9FC8A1334360858669B72A0A70EE3C62FAAA8761473141CF094ACD4BD20A9D190CB249AFC66390BD451B64519350A1AC1BB9F94725269BE8A70BB95E6C5BA8E6A5637EA1E8048260E01037177002084EF6D4869137398B61513C0E9AC7A0F54D535FD340AF17211BAB1FA61EF4BA47890C0D6AA764B8169BDA54BA0097043AC15BA6E45113C91B93DD29389E17142C9254735800D06B12090301EDEB3E44820C8695062E8AC0A05EEBBA5D5530586DA38E52E54E109EC4200AA8396E4C0FBBD2912A3871FCA9AD36698D52F2DA70C18A1F3CC47893D1984BFE8841036FB7BCBA221D032C827B6B4093B0CE27907F047CB0F39623161697E56131136661FEC46AF199747A458BF0391449591FCD336C3872D235DE0E0DB339436012242180141006101840718B341244FF53D402C3B553A0A2D63FE3E6A49B8280A4A2D61DBECE9155E0380FED0CC00580EC990160FAF88BE2E0562CEFC35B4DB8E22E884CD737E8C4905B0D121FDF18EAD5822F60C9882A8B26EA6B2FA0BA4DC008631019063A86C5C71EFAE1BD09F6CF273B0161957CC8C2A04E0D4A100E896C6581632079C45F256A698532F44F13A572C28307A14D94D32E2FE3150C7BDE97D081A6706222A42DD4DD105AC0B561FBCAE1EB90A4BDFA0D19729ADD3723B0477EBC8F94EAB4210E821CA41427F423FB00D09F2CE958418B1A1DA0D3A6C47FC6351E0B71B62EA1307109D2F80ED6EB716AFC344734F89B311E7BA397EFD91532AFB33F602BDFBC9A828F3FD209030D8EEF4BC196D465202105999DB6DD0FA5EC8A71653C2A99560CDBCE46AC7334174D82FC6B10621586CB163AB1B32F2AB26E58DF91E50B5DE2889CDAE356B3E59773B1B9EDECE0FB47E898BAE06F165C9E1A495C1C59994B5860D81CE72A5779DD8DB8D1BC8C1E7EC8236484CA3C8AF28C4FDA8109091D4ECE9465A7593D6CA621029D0FBEEF84D3C97512A64951F47FCC91CD4051A163CFCFD79002C68C07C82B9A106E4EDE1ADBE72B9AA4664883BA447C4B233B0987AFB995BEFA1B1C25B958A867A75E092962EFAC42E03FA0AA1697E264DA6AA124923924E2423A73283E21EA4A45C80794BC08CB9C72718D1E480ECB1B685C0A25B088D04F3D5F238B7FF6D5FF9583424DC64E0F426E116926348C241E1B52AC9AFBE2177D637159CB81A5DBAE537AF912EA72E36280166CEDCA272BB30DA1D0A39EAEDF7B280D6ACBE36E62DA6D3CA934D975E12AC19CE4110A098A4C4F60B431C34EEDAF36FE54BBEE08E6A16E0F64FB33A96999950C3853C1B20ED5BEE2B50D8416E815F72CEB21726B011FB32C8C6FAB92D1E7E84DB0E76340A634740A03EFF3B612B08A62F16489E6A69997CCF26C29E166781517AF84B959088A978136A411119A7A5C02C9C411020E88FE7C02F532533C3966D804D54D9EB6CA3C7B9CA64A598F1CF70E82D9C87315084C74FD96A09B45879A89857CF32C8C610938C6D036E454DE8E283EF49948B123C8C92E0EF204B28C4625A3863D2CD22C009A25606A5A1AC53436D7F4305DE6BA28A49C2BD3FA078E2EB08EA1CD55418EA07C827718D1F00E288012112EBA09075824C5879E9CF55E5653B5D85C877D7A64D83E228F3E00E3F0F3650658EF9FA97B19393C132BF379C39FA3B0EDEF73C30E745CE046291EA0B64DD9611DCD7245A7F3BABCC9293E5CFF48A28F214D3A4057F5772F236C8D644242D1B5E8697B9C7848282C4E4679717EC1205004E908501B068D5A008E1328B03E76FC5B46D91D5F65DBB7A5C65501718790A7FCE04401AE3FAD218BBCC9F009204C149297C5CB34456819F42ACC346C442ADD0A786D1BDFFAEFE4B1729FB0556B674084CD750A60553CBE921B174CE0E91D8736E8E94FFEBF84EE66B1103557BD9C50701EA70987B2E45C9254196C96295A300F9687A606094EBD6DA5828CFCE3448CCEC4052A9CFBF867ED76E0744C429A3CBA2F8939D44401104E3D108D51A303B4A178C557D30C55D4057B849D87D0A67238FFFB7824B31040CA4008213C01065F8CC21A54DC1D931EDE383411A98761D8B14F85FEE4C3FF0A3398DE6D852B79D03EC04EE021F954CD5900350D8800C979ECCD7F31E62C4C0930205030A3A2A0E8222178F266397FA7729AC31E60F7E91347BA990FE89AA60DF8EDEA4EA5C4A578191B2DB464D00E63489947C1859C8F12A4F815A57D6A8C1F33C222D0E1B815A23162090CA064A9030DDF551E4FABBF076928C750CEF23B549131BA4A6E5E72F6A5D2C30A5DD576A3E05BFD91A26FF101F1A9668E155DCC26E863526131126C923EC9F0C868F3D30E93ADB29279ACF2CC5F34A1E7C54877A078FB2EAFEF6160CFC25F153FE174B245EB0EA40F08FC0720833165DD186A837834140F47F25B4E7AC06B1FFBB596D3F6FAB37C5B307629FBA72127F1FD2D4BF4D29B60379BBE7989DD0CD2BAB93E4B2CFDDA0A3241CB1AE5995E2426F5BF4A09E6E7751757E00286E743804EAF30B296DC24B48BF6D041DA5990676386667E81E003956AB927888E89F7B3975691A495159BA5C100480B141C088494763F86ECD6170311FBD32F986EF0094B24093A202D9AB0BA8B039B57977A0B74D3BE9A8365AB9E6F76135357C446973F02AC7E67F99574A0E9BBCF612E74E2D62431C93D6234FE92F410A4DA9993CDB07B8418F3476D93D12849E147F1CC84540804732167F05B373B05CC11C2AF0D6B852CD73316EEE727A654744DB3306D76E2181F60E5E4278C34FB3C597646AC32AA0721629172412632264B8FDB31D576C09804E92D152EA242DE0EF888610D8F8DAE1B38D1380C8690060D97A0D870A3012F760913A5FD3C08613008E4E50F189B261A1BABD9E10E951AE593D691A78E7A99312283B2BC69E705ED248D3B80DFBC9E4EC74D9734BE695FDED703729C34CE5078722D8DF209A2E475DB27AEADCC976CB11C51EC5F527F9B43160C475E9E41194AE518BDFAA04950B00FE6E437CE09E086251D375AAC438DB550550E9FB592E9A5A16FBCF10311D2F9D8F79E6F65580447A80CD8A186826C3772D617524867968752C2B032114C5C2A16E6F85C01EF35F13394599CE26040B6FCABBB1660A7BF4ADE551FDE5A46800BD830AB1D1A691D81759C382D2066D219CBF5142BCC8A04090AF055E417220236F05759EC85F1BFA8E10AA4D545A777DF5CFA273F23F232F8D12958A05591FA9D6B7381A3329E4CC803224467FED708B27268125798628520CC2F332A0E365FE644364FDFC82B08B05A53955DB0A91C49B872414AE7B59746BFFA580EBB104628EE04EC23CD88129ED7246E1219A27277AD57B59B1C36928AEE76E0864BDCCF3613A047AF309210E0883BB1A04E4503986A5B5C36599AA8CF3CD81DE2B90632AA044E6AFB10383C201B64E34F0E1EB7B6EDA4BE87E31E735FBCB02418D2DC6F41C251DA4FE85637F82A3305B814AF81D406D86BDB07F146B7BE9035FD09ABAC6F22B8736510BBFE69476D767C9A191FFD5CF624BA1E72A53363EA4499F1F60B725AE3C223B4BA2802A5AF2288396751A1DB6AC07F9FEED3F16B966F852D92DFF5E98BF1265644D4FD4C419CE7F0B7D10100676A8C0D7B905541F2194102B53717CD943E333DFF5AC826938139AC8BDF7C06633C27A389A6CC0696C14037F071943EA90C2A0DFE278430933B7D382E8CCDBB6402CD84F8DC0EA179B2C3060845863833A47811099C0C4AA38F0919853A37FC5212F433C074DEBE4FDAB8186925C74BC8018FCC9A03F054C9B2179C9D0963B01E6BC1A93FE147EBE87C0DFA24F7A6DF3BD795F92D34C516DD131E311F978504CBECA81FBFF4F852C1B50FC9F7CF7716992FCBB3A26FE91401931CF1942150800F9D91E4CC640C0BF35612B1DBDAA36E3A755A690668F517E8A3D702E16CB08D52E56D2145E897683A297BC1F099B0A39E3B9F4D56CFD838F91C9308681F4A39A46327899CCBAA76D5CEE790388EDB1D89CB9459266E5C86800EF551C567E666C93E56AE730A607A5F05C7202EC2CC68482A2961DD4D0BDEB3AED5708BB4364960F425EB7DCBD331E6C4471686D131456FE50CFFBFE1DAFFCC95954462998C661C0E16D8A56E08C821204FCC71C2DFE6A80D7A51D2E570424C5BE5D9A0E9995DB7F7FCE1E1330AAC414E2B023918C92C19BAE12876DE5C4C5D87110A82FA4716412E841CB304F8E344087704D097DACD3D88DC93284AFF736D6B489B177AD752C74094F1D2271F2DDEE96800508DFFB1CF96C19C9182581DCCFB667F9E480D4233B210F18C680B33E2C64909B0E22002AB9D8D8E152A177FBFED6D41B414D01E99236B3F003B15DDA929DFD2D5160B17AD805C8EBD062AD3EA66EABEE471097849B592D475650E2F787FE80E35B04063FDD5A663163D8222049EC6B8DC647358FCF2B275775AE6EEAF55673358002DA2851D52157C2A8B55E68086D38F53369539DA4B7C1A9A91B7BA76CE61600D8D201BD458642B1C987410B3D7487C27926A6B92A29D43601464D8D258DE34720A702D566388983524501D089F4D4E81A670204B0E13595412D61E48DE0F86EFFA55F4207AF3F7FD0A44DBCFFD3311A8BE7507A824A9779D759225BB15ABB0365CB453F0FF87623037B8921BC39F8B53168AC636E7092F6F01BA6C93B8DD8ED31FA2B38A8AF617D84740BC8153919808481F8870AA7E5EA03D714E1FB4DE6722D795F2AFC1E64787A87833AC3FE2ADFCB109832E8DF369C8FBFD76FAA337503AFD42BAAF5EB11FD3950781004386B490838A665AD452732AD6A96B58503262DCB21D72A481414EB889AFFAE3B06A425772D065F7A89136D1FC48C44AAC65E83E8D54F102E5043135B03FDD5D742816F87FE656F7F63C537C3201DFFAB84A2230DE541B91E0C8AC532DE278E713413C04E3C451D811E843B53302D9ECAAFCC14A65E8AAEC00786760B38A762CFE959665BAFAE04C0C29EDCD1C87DE3C03B201DFE5748FED83C95ACC566D03B8C71D014DBA40D128DE2900DE3E29B737D81810A676284D3A2CF14967CB51D2AD31A210480C3166887227AA4BE197395353B5C9C98E7D1D56F604AC61C7CCF01613257DBB84B360F6900FABFB0F25E695C2B0543C91014730C8AEA1D436D0450AADF8F3258CCF3C589B9E5FBF62165BE2A352653F7A54E34F3B5BCE9BA3F643C441A536268182E46C97628DAB208EC9E9E89E98DBB1B62A5B0194C6E747E9219B5717C30C591A91ADE789DEBBB8564AEFE0C4C6ABADC9D367FFC2A23E8DAC2980DFE4FE73FE2B07C83FCFEC2D1629F1F8A94B6C605D7CA7DA6B094CDFC2A14B151872D90193E6033C779BBB36B3C6B294BE9A791DBBF89FC87B341E80BEE25E21660D99A8A10F4820C8FA4AC445D121B74E2943358D4FDFF197BE804FAC1CF5E89AD42FB7F102E1A85A8F8F34202560F106C593B896F32FD90D197CFD905FD58A08F44A62711102B44A22B0C72833935146BB4F5CAD482BA8D9D528C965B445D87D5E907F3444AA437CCC9AE393C0BC63B73A6E3E20292A3598C7363EB22DC8DD3943C58C911C15812EE13E879FF9E213125E6BA69D31B141E8A961D5049378F6250F579CA300D2FB8BA2682346DF2F49A6F0EF029E018A3BB977BF67F97D900700460AAA68938BEEFA168559150C6EA91DC69E4910B1F61EBDD5A6BE4C4DA0C2850C56B8DA442AB07E2CBF6554895C8030290DAB11363CDEFC8A0B500DB473D7E0DF10B8908317A29C9670F7F7B8F127F2C7FDAA9C6BCABF804C51F6345219AF848B039D407341018A10591793518CAD04A92FA7F3EBDC2DD55F83545190D2CCC27F3AE0DD19401485D1C931159227F2A62ABA44C1A6E99280A7626554D12D5821ED581F9D4EFBB08D1E09BF30E394BD460B18A0D0DF4530BF3A1CE9ECCFE0C452278D307793C26DBBE773679670F2BE1D893D6647384C54C8685B3C68DE5C335EC63970CD73E65165709A4A52D145CC84D9E8BCBEC6AB41818546F7F80734E69AA3D87C669DDE80ADED6640F9B588B3598A1938C797DEFE91FADC59CC27C7AAD2CED0161D01D8F381FE3852127882D3B329F806995E5F53D59ABF4E8D91D3368AFC406B8E0D505844B29EFAA15B69DBFF68D59B5B4550EECBA4CF02295DEC5F0179F6B79285E7F314BCC709C621C286D674AD96CC559C607A559B5486AB17DBA5420CE9D871F9E4CF445987FA905759E809F5834D49C216CE9EE09CF597916969E2CB863CC007B77E1323910D2B3CE1287E5FF2ADE8B496282725D72F5CDFE7B13E8C5D284B2EFC36E7CF06ED893F4909229DF8D3F692695DFCC3D0B2EE6E8A8DDCE25A17B61B003D2B9E8C2CFDCC13003A9EF0A62C4F62C3707703395BBBD2CA34D6724CF7688CD959F59D179F6057C81133D59B93110241C230BF800B319A66CF8302FA857136A069518A37D525334FA1B7B568B7138527D48008EB1803FE21C9DE4BCD2F889053FFB424300212D95A742AB55F68B8ADC328AC140842D9B32538FEF456FEC489252A130E0FD9E91F6EA9F5EBBAF2B76C68A68ED4A60E2D7CF140AD1BE1A064585B82B7DBF3B2B2D2F3E8654426248897C46696290FEF132A7688053598EB21877BC3489104159D65882F31C356030450EA8247DDFF005315D138A8E47B070571F250CA18D21D419CF8621B833BBFCA3A1AF90086AC371C1BAD0AFF18E31377270E90A74A85861AEB49C79FE4C6E61369A8C78BCA4355667C3202A278705463D3162B6E45B3CE4C266CAF0C24AB187C6148F77158983A26CF15122A9503C1EA244E9A7B4EEF3AF273093640220E755EACB43A1FC51B70157157377FCE36EA3D5669AB19A1471E8FBF23510030364F4CC16A5568F2F4C4416054549FE20BAC41713AEAEA4783A9D4C00DD786D66EA6F2E816510B6816A6D821020795B181F0562FFEBC71ADB261F9F1FC78BBB0688A6037CE71F7AB272B2747C537905173E66951A09E2DAAC2E9FE43B095432D9A21DA9F0A471E1DD21AE4582A81B20E4A772B251993CAD22138BAA9E78058B97FEBB39625AE8B1488F8AA7F67A3D1E034A7BC81412C71DF05E0A20D3C6A4BC0D9CEBE2E8ECD2FF9FFF35C5240D5FEB57EB821B0668197E1F861C063BB4EBA88AB9732CFA869B2D5BEF6BD32326651654AAE27869A1CAF61E51BE184A89B6D01D35FE045EE8843FB7CAF8994190EB7D10FAA00C46BEAEFB84DD8B57F7F3481A1FF11F03E263C9CC947432836C47F2DA5E9AB7211F30DD9F72FC89857D8CA7E9A2CAACD95567902A5CC8C4360BCDBA1541C4D55E6352EA320C907BE4FF9F47EE00F52104E30F4D5CCEEA888C6076278C727EA448ED33DA8B1241A558C9FD5537683C86E71B28D3CB8D7507BF45ADD2F85E3D7FD8469B2457B8B89EB8848E1F90EA541AA542F7CDB58541A065A07B15757C1ABC30488828E13F6ABE42719567D29427A8A5C763320C2D3EC2A2C20D0B3DC394680383BA40C047B128099D2DAA1834511898D44F5A41155F24BB799A260124CADE8446E9E3B67AE18181FCFECC114C84AA19C611030CABD1BC153AE8C94A0E9F2A9BE72FB141264A30D440067E6EAC45C68709DF23150554B6E5392CEDBE6A62A3D47CE39E3C9F718A8EF10F3E811EF40ECA39167F8B442656A70D03B75450E7C9C2855D580487B89F4F83590B83C50936624B4F20FE7F174F85641ED9FB87ACF5E6531D7012278EC484C94F42DFA6555E411D8ADB2020A943113E1FEA786255BC0B5501B09190120340235410930BFB9033B5E8207A0C1CE4AF582B9E39A06A954BA3027639986B088C52F912736DF00FCF5BCE0A4822D0A4D3091CA1860DEFE27CE82D234428341C8416E261F2C3D2D46DCB188E44C9BD726F7632F3E1ECEB49A372AD23A8946453DF1A2047FB4DCADB9FA5FD7B660E9B818A569BD7C8894918179335CB98D5772D2ED81A8B26C7FB3A891F1440925EC98B40DA2085FE97C44336F52ED1BB23C8ED749F833AD6206F7CD721570D6461D1C387A56617EDA95E65261AEAB40287D7DF169BF10A3B72D914537F3CF274114C62CEC49333CAF7275E1AED7B63D51FC7058399CCD348E894B4A6F60C7EEA3C1C5C2A982B50BA4F899C0A65247002EBA88F8989740EF95F21EF0B418978C27EA7CC56BFAAC416F5C1D5BF4DBBF226785E9F47B57E06179EAE9846C1C19E09F9D6F4A62F82E2ABA84B08415A41F73DAD7884E8C36BFF7E2903B5F414E23B089F55E3758A2F65F0E9CCF30E355895FB18A6C9F4B756EA40F75EE598B6D49A092319E79998D4949DF00E92FBA6070EEE42C004055CEF3416DC07460BFE0E218704D18683AA919C4C3E59A694DCB7B8C7136BCBAD1DF17F6F79F15B9C1D222909EA022B9D0A72E719E641C40EEA0132581FD7AFB14BEF3C40A11F44FD3B2BBD080264ECF700C06C39305009183E4581174192B0018ACA8012701A56C1AA2452FAC2385D0324AA0848747F90D96E207607C1E0175BBD792649EF842E9B77CC9A8CC9FA8EFCE1420CFC1D0FDD599A6A3E5A05F9A866AC3B034AA4F6E71651E57EE3161A98261BF52D9DB83DED9A2502FA082F65B9FF26C3D97FDB404E239A3081938A3057952CA6143621D4091C0FCA43D16F2664596A46BCB28A33C0DB575EAFE65C4AE45D3B7C36BA0AB70A173C4A347C27551A9D9A7E91B76B6751AB92993441F2565C1739C58AE1B3BE86EFB3645F0862E5EC6E796CCEE5494B1BDCE1D3F5F522CE0AA533589237F8DD466A7ABAAEF7C688F1DF11B24CB619AC12494606EB3809F04B420E38B1549E189DFB813BB1C247823998BA6B5AA706212C361FDC0C66C6AD60E746F9FA9EC61C3778070C424B3FF14CE277D354C8D15B7F79E391BD0D4FC4831BF401FB53AC7241B2E36A0F5B0EFAC3255E95B24A8B2C0344C32B4372B385878B70CC2CF3974084E817BA3CC10864FDAF5075676EE7EA313A4E4A9C923D7D18841970A65B63D3F6B4540FA74A0FF0ABC90E83F113D5C5988F2583877883812DE99D02E7B4C12020AEE64DCB8104BDAEC55D52CD1FBCEE98F7030EC0257B87BFCE94A275E575EAA04025592BA04CB86B70B96B0267AA735504FC04D92907A2FD32C2B1A3ED5AE5F96517482B00BA021B424432C3A0EFE683423BF0008BCAF0967279AD887F6C15612F5F9C9D45ACCAF287047581883BF8AFD900183FB724B403C16F6CF378B3280C1C4ADA24B1BE0089EA0ED7C2DBE75C5F7FFE8D7BA7EEF539E64880019FCA4203F4C20691532C4CC539377A58051216141B491834792880BADBDD316BFEF4262F6CB0466FC7A07BF79B42DED48F0B3CBFD47F35498D8243CFEC3F165A971FE17ACC21EE979B307E5ADF02DF3E3560070B6C61E5C0FCE565058C6F636DD904D9B46D353079A7677FE4097D1F80FA0C95B7C31B731140B9CC1F5613E6290B17226A5A4F4590AB8990A1184C67F80BB51BE30EAA576397117703C18A03DBD26F8415C94D014CBB14D0741156CF90E1E2598F5F7C134716E83C68D409D85FEB3955B61BF096D0FA7F166887233C26F47ECF50DE730394711A1242362AC5A5968F641B3A705799378016F5B3AC9DBA6B6B2F7F718334EFABBA9E1E9E72A612D48D7D94BB879C3ECAD9F6E6DC1C2C7F73BC4C49F5F20A1D503C8D95D43C8A2B84F31BDE0FA59A5D18558BA8F7CA33127BDF23D83E08D08947AE7302B23B2493C88B902D7D77A0864C962A57A71676FF229C83D5C27DAA95F6FEF9BCBBE5A252094E688F45FEAF5BC6DC0460C826862E363FFB838339E5B4AAEF4C80E7E59F296736219880E765112452A71A0F5F4D37F005E58E34648864404595AE9A43E5A59863C83CAD53D84C95647DD00F62EF7572E0643F788CB0F56DE5FD4C20CCBF67BCC46663ECA602DA4F43113DECC163F1FD6C61FB8BCC3C5C4644C5C000778F69B4365F719D137DBAE0DEA26A14C9C3F09021F43D584BBEC4D13C2D7AE8DE90F85F1AE687720022C29F0E2CE68F2E896450175C9804A95661045F66AC085F846D21E451CCEDFAA70881F09F6C69102E070860793EF9D3832556A12A758198886C3A198E9C32A24BE7EDE87B619AF5E86F5490BD1A953FD17EF6975023628CD85435E557CF04760B17553F3F39CEEB961DB86496F127A1BFF4F4DD3DEE199CA3FC5FD884E486F13FC9BE6D07EBD60A4C6A2934439C16EEBB5E70003237A703E3E1101ABBA7F56F3CC277E5D754A8B3A7CA6E6DC6185820036A5D79E493950A0B09B5A6C767CB268BB0D46A0A0FA8E2509CD2FADADC2ADCC72E44F4A47C7F5924587D4530E42C38105F289DE163A26AFA1313C77E00EC81566EE1C88312382B780959EFF578BFB44695EC435E3405B71CA2A068AE70A1160351537BE39167A584A2F08600488499E9F450B91195CD44F7DB9FDD0A5EE6ADC58ADD8B56CEA41D15EA917406A69F5FBF43946431B0730BCF714FF79C4FF1083DFCD53CCD643FF1B088DD74A92EB7A0F9DDED862755E42658749D6368EA9CA4A5424155BB6D56F36C4FEC34D8A279E5CD800851E0325A24B27CEA2F7878FE8A214FCA3006F37BFD10EAAAF91B96C81E4779E72B795A31018BC5571D34645E6935FB60823BA5778AC14EE5D194BBDEEEA4340BEDDFFACEA1A1FF679E51BCC415AFAFE4D17F30EF73E4B821C072115193167309205BBDAD3300A8AB4CA27F0B4142B8FEF2808832F5ECE64BEBB2D419739951A7DD78A46F30E149766D2C7DF76F511FE8B17EC96ABD7CFAA80A552BEA773D64FA88A9EBD59DD2261CFFD5B320233FFA4BA5C540D051970C5B432FB46C2746998827DA79DC3979FE516ECBF08F134BB01F8927699C796BBBD88533FB7A6100509AACF4811B7C34594107358FC38B87DB8C49E33528AA9D8AA1CE2A572579B42628386B30551D7F69AE4859FB2BE88E6B7BB8F2698707C58F1EB7EB3D458E11BB8FD60581320836DF5622EF9D526DED9E95FAD28AF6F76991F1BE044CAE72BC7B6DE85EE6CF7410892AA0C859BF7AF106D7B41CB8F473CF9C92B625CFB5CD38F02F59E9221CAFE201A8E87FB6537981ED453369CB4FD66F0C3A7356F3045923E4AE1CB9F60C86693D4D09DA2BF1C5D98523EFECD2303568F29FA8FC2728616C540C0209D09B3FAAF53C47E9C79B68E914B165573F6B4E9E6BEE352CF9C0F810B5521D512B49ECFC6A2A49409C0CEE4B20902653506837B3C823D62A28A26D54B7A472D3E9896D4D9BB7EA2FB1EA3DDBEB4117A4C79BCD6F39498A2A2DD5689B66CCD2F6715450FABE657639289C200EDD6ECAD566BE83047FC4B67891FA78841FD7F2D826F8C55DF944C82A1DCAE6355FBEA9012454F5DB08582143B1DB7940902833C29D3FD3B5EE7C0462F7111CEB7FDC8742CE399ECA0AB7CF8475C2FA0F41605FAB9B8A8EAECAF416AA569AAFCD2469390AAB609489DD4B9EDEF01A4BC68132EA9602CBD6A43BEA09CF5E0198A2180570CA6801070DF7A5B73A119EDC402D11B6F9E726DA358FE418AE7106427F00529F8EFEAAB929A2D200611CE90785322A3083410D7D39064FC24977D6791F7849D369EF245FD6339E7EFEFEB806F629EAF0F184AF6E9C61E85F9A013443EDBF9ECDDAB7836B41500C60F49D66D9D1E14BDCDDA47EA096D23C705D07E2A3BB7F9FB1E5526FB7B76E9FFCEFFF8F9EBFA78EF4B1E82F23BDBADC0DE77F6FF0EF47BED42C3D3B0D3F11648E9EC6C6703759EDD86AECAA6DBC40D82228D50EE9C54BB694581A1B60C65BC3B7BAE8499A6D51C2658EA95F371AE3E27207233C88695B716EDB118DEA57661695E8B4F5C8F8ED32FC05A7CB9C63220BC79409A9ECDCA8365D54C1BDA32123CC9FFA3DF719E29E5FC278A58F3ED7CD64B3D049C715C905B010CE7CF4D856EBEF53EE3146B37A2F745162522F6CBCC54FAA17CAFECB2821412BE65295434554495249151E82D43CB307BE3E46F1B093CA6206783870C6B25053C6FA20E77B48B20D716F82B36CE95A7C7A10AFB3DFA44F49607518775FA6AC07D2B0E8C40BCDFCAB9ACED7A021CE648A234CBDBBB2FBE8EB4B9933DD12867E4F638C0202A4FEFEA9508390563D0451C5D9B84133C9ABDF69701C1CDFA994C8BEF9B6984B5F692E94B8AB020D860B3547AEDAB03C5F3FB73CA47E61E8BDEA5B423BB3E3567CE367E5BC1FA477E1AB0E761ADF8F191CB48C06CB1AC730A280F9E4525BE945B3939FC6C16425DB75E1634A52C47FC76BCC626B4550B81CD4855A9AC6EB289B8F7EB505AE3021502289E33706109EBEE515366E2BEA37A7F1B47F88FA678259D31B9FDE6A1A1AEB455A03C941A9123B02134C49ACB592508B05DF71B0807C6D585FEC5BA971968CE9572A99B088A809AACE6B5197B981D69CB59A1A5BD4204C08B09003C68BE8D29A973AA744E0A4A19B195E86D8CDA1DFA74DADA2E18073769C04AB55DC4C376219F284092000C9A437292A342C8017B31C82C87472220C7976D54C91A6BC93EE730C29A1A5E62AD891D646B2F29447C2830B4445E6F51270179BDBAA8ABF2754FA179EE1728998C995F3908CCBC00052677BE0D29E407DEBDAF2EDEF94D4AB49D2664AF182A57FD9601D10634941A56ED6A017F891300EB38AD0B82B9244C39AA1DCEF6ECB33A06C7A8E95A7AB216A42BAFD23C603226465715CFDDE5A8B01718755A5D57A289186B5B726B5BC5EC183D9E46ADE1BA666AA69D0E1667AE33BBF4702D3B06D097666EB55E98B534CA65A3490404CB0E24A4354D7BB7C516C0EAEA745915D086A7C544B8EF6E7C2ED3E21877545D3A0E753F8F532CDF8B7EC1AF6A956A399525E0FDCD162AFD7E8618DD191357AC74B409AA3149DB181DE89C7438A0EF6FC277982DC9446AD024B772195DBC18C96F3922594F2D02C8AB7B792A096C589140A0E478FB51AD4C27F720E7F459D544F215C251C14F43063926456D28CB8B96E6A818117CB2FCE74C83B9225A36E2CB159EDA8D84C48ABC79C42743A13FFBA8F91413B29795F357413FB98AF67425C8757F677A0535F608008941B363B6EB5E5DC24030175380529F29404547EFD53F6C89435E694FEE67ACAADAAD6E890756DCECD914E8265AACACBF637E527BD3F9BCD4F96D5BFBEF3116A35E0F5DE59951104C460FDEE0EBAE7E5E6BB6CA7AC9065EBF23110C924B416F4BAE932B40C5D8ED4F448F26417919375FFE765B58C71516E98824233EA24DDA375C6ED8644E4DEAE654C246C5BFF1C68C965C33930BDD9C91AFA7253CC0DF5FD2907186F1247D01E7FB8A4B471E1DD5D775CE16290E1C1328314E62A24B5706C2BDCDBE5598BB7D06BBED4810732DFB0B132B595547B3AFC604740A4029D8DF40F414F0535FD0F262BF66C931EFBC4335C32118971BA41320104FD2F15BE8E381705A4341042AF1ADD89E148D4EFF77F343704118BDB541C3C271D348B5C3F983E74FFE1D1C1EFB6E5C9C934FB015623DBE6F56FD14FFDB84859B0F86E9FB6F485541AFCD9A1FA05F088ED129174B18AAC58C68ACE349CB12F9178EFD478BC26C8805C341389789F023F85C3256B2F9085573A2FAE61ED65D6065B3A20CBCA46C4778DE8E41BE1203F58664292A955E5359B78E6FB7EFE66EF8D49BCC5FB7D0DB8B0136D2ECDE38BA430868F794CE97CC818C4A9B2FD9296F0DA1C3C3A714FB96605BDB4DFE70BB5D7400F5F563C31D6106550AEEF235E660BFC35AFBCB24CC320EDB848CFDF4FBB23B5EAD892CBDD69D3BEF095F3FD2FDC87C70BBDE0677D1683C76DA90AC40939EB5B24EEAB40FEB5137579312ED168C57E8A5EF7514F7AFC4CC76DB7D152C628D5FE967B0CD8E1F5FB32F6E050F38624F2A2D3CA33C45E63AF2638C5DF7B9D36E9C75F702E3E4B63C01E68DF873D81AF7FDDFF337576818C0CE614A4085BA63835B34B3F110C5EE1F7147F408A383F4C44967E982DB0FACB419CD9B3485AA7A16B4AC95C2C4CE65DF1DCC74F2623F52F5D56F093C4E8A09E1121E68B9179D6C267466833FD19618888390B2E1506B300912D08CA3B19EA4F5703C541F0E0F85027064180DE399E0C9A581A57E7B7C33CC1249B213111C0F9643885427E41644EEFFAFFD440DFCBC626EE73A0A37489716CBB90B5F316F4823734509AA0854822CF9540CF0B93121AF077045236E2C434107318723A6D6C5B18A4749844BBBD141EFA36B851DCA5066B8FE094AF1B3D766D896EF633D07E64227CFDCD32AE50647D4889A019834A8E8504B440FB98FB63025E0E5C7066A091DB7B69AD340DCAE7FA9BFB1EEC5FBA9797EFEBF3990E5F0D307B1D423CCC12D7CD9E4EB1230A705481A55B7C400CB63FED53B78923E98DF191F610956B467473B7BB4179A9BD4458E05585AAFA6351C684827DDF1EDABDC9827F052A2D8D0100B39DE37B84DD74FB2773528755DF3B4248574F90F3ECAA63F22FC8572086CF9F3EDE82B745909E02E86E3D388428A0043C1E2398C7F436D75F5559559543750D8555EEC4B3085279A5463E4FE5ED5970405F3B9B0066F5AD5BCA0BE2B9A2839FA10B62D0EBCB9B2640B3D39ECFF41834564E61352A822C0B3772EE9B74B7B2FFFEF080B0D5C0FE9B894DAE3C02EB6FD713B95316DCE60008290ED77AB7E4A6D304FFE0DE210E735ADF3B2A411DB1F0FEF16DE8E6B74C08A6A7687F686C09262B68BDD4B1D7539E682253797EEC3FD74C37AD152CBBE31BE90CC3F793FC88D73ED38DC0BE177C91472CF269FEF460B569DAC77541499738ADDF72F9AC9B4BCE383C9FC05416CA6EC6EAABFFB67DE177FB4AFC8A55AED86555669BDD09D3584EF8D41A8E7E8E85ED21552C4EEE5F44A8DEA293B19CCF167D97D67B5A74B272A89107070B63052193015526936387574C84E2FFFBC090A7BD893838CC40F90AEBDBAA9DF83BAA4F9902FBCF3617961DD5C55B16B94ADA9F47ACBC10C62B5B87BE1CE4919F4036498BC43A02915691DEB95BB2EA7077427C99A7692D82A614D2B7D29E937D5143DE7C72A5B1CAA4980BFE0E2686781FDA12ACB65A8B4A1ABACEAE0282D2A081CF4BE208068544C2D3BD23E2E4C1D2544247587E889036CDCB93188FA7BAE6380A444020F38AC9C78240464D593B52A214E56F0F467C5C64C34F6236363E1F1590A9682675F01F5792154A7E5CBD95FBBE34ED921CBBE3CF1EFCAD3CDD58AF849EB5B12E3D762BD0B642816DC25E0D9CF3BC3780AE2D33EE280CACEB0F203D9387D409CF76AEAD7A3E99F6BD0B2ABDBF584E4FD13AD03E9D0AF5CCA33324009B63DD365091ACAF358BDE9998E8DCF982903C9F0FA00685DA8196CC4A7BB9700375AF5514B7E1B86ACFA5DA9D76B50B085D741E29520F8A1E1CA31C1A86D3A4F8469EDC02981580CEE0D1767F9154CD7526DCD7B3885346F6A232822EEA4EF33CE2AFEF2F48A6FBB1C2609A40B9D5462AD988BE7CC3877DEF0DF1D8F231E4EC719E5F2C06A2B42825A4AE15F9BF5AFFFD7ADBE177FB25BB59DC268898BB4E5B95834C3EBBB148496C75B4A81825EE59F83E7D050967635B7284008F68C9B2D718BC71A6A12FE70AEF67574F9C2AEB05DB195012F95FB5F6045B9B93488FBF3B748988645ED90501179CD1A90C5DE70502423510ECDC61810185FF9E6300EA539574B3E99E86A7FDAD4FD65E212C5B371B387C3BB051C045B16D18A091B82010AD2515FB7418542D017A7A0D1CCBDF017AD4C3D00FED7F9D2D8E67B2CD92F6DD112A294D35D7A5B879F07204316909877FAC158B4F354586B9D71957712CCD7AC4936DC56A807E171C691DA0E0F7F4EC25806440E1998621A3D714C722F29E3F432B702E3183917B92B99DA7B1753AB1F8E03356C64D39FF1C7E39EC5993BE023EF18AD9987C8A378350A6FAEDD82D45372C9C9CBDD9887E62CC9BF10814A91A57298D084CF4C97A775FFBA17764F5325C990F058BBE97A45DE78D6ADFCFA1122B82E4608AC758881983A3B525F81E75F038168E6D384C421C088A43EE76222B81FA04D3FDF2A968B459B189E0011DD01ADE866D670F7562325CA58F5D725A72775FB99C9032F9D6861E3748E5026ED606E17973C88641AD7E979549DEEA276A89656E832585E4AE3F60A604312FD34F670C518DA09E3C7839372EDCA13A57FB744B1CA61AB5377AC92BB5F7B134F48F309ED6B572BC71FCDA12125AC81544104A9CABE852667DE39B3A4C1F06026860732F4A8BBA6904299CB18FB8DF5FC06FF1D37E8D1ED353255B0384CF907344798C3B689F6D812955B87CF51C026117AF8D41F24ED21FF0C75F0735F04F169E3911F648E366D8FE3BD5A9B93F6B1E02D51E497BA64BF13BA9672D8B7E7EBC83470C6A093C307C8F40C96F5F2FE70FDD1116F8C9D7E3D4476CD3F4B82A4E9E1485E869DAECB8BFCC15C842BAD91F3094AB86821A69065DC8B296E0F87C9A0BD6B32DA0233D3C63637634AD9DC69DEAA1BF695067A9CC881D941D9E3921462C142D5955D1442A0CC525005A753E60E14E4C68012E0DC27FFF98B2E24FBF1ABB24219D48C09AEFE23ACDC5DC76DB96E4F0D4FF07A93691FC0BA443B58233053F05A7E1991321812E1522F0906DA494DEBB24ADFABF27040F75AC9AB5F935C82DBF4FB7C91D6CD4073430EA2B9536C7687F2D74B05D90C7A8235E33EF70AEFA234A3A318F41B261644907A8C0B81F01E777F39B3C49EEAC8DFAB84E337B6A09B7CC430E04F4AF3419F6D50C330E8E296E03D83801F15F9F280E06014DFF30306B47F9FD31785FCD8357946A5B9F676716573D6FFCF57024FADD20DA03FA9D0B448FC14BC9923E118F11801B55D9549D47CE4316B7A44BB50C36BE812AC482DB1C24370A4CBF991010D959513AADF617044D01FFF3A82A7A21961E78BDDEA42E1FF43FA0011F25FBF360AB2F7A95D8B056E93E7F9C1F3B74E04FD6930A4EF6C4C9F0BE2956B500A45EB1DA4D525D10F637D053461BFF3E7509695B7D71355FB641C04269E46F71DC05A181DFF7C4174FC671B389FB27AA4DB9409FBF7FC2A71953FF6D0540B24E411A2C6CA7C81562A3A1DAE6FCFC5DF1286174EA8252595755BC88CD7F42C8E274D0CC3ACFEC1E29B06955BF3CAC7FB176F1F38E5FAFEED6EF32C2E8379982BAC08DF04048ECB51396DBE7EECBCF7E9C279E8399033073AF0070080B91F9DC1F80443AE00CE9803799EC2CA8C4B5B7549851564789FA449545A513E736E7FADCF980FDC07786A7105F69A4FE6126BBECAEE3741B1E85E593E0F3594B74C9D8296D24604C5710AF55D5041328F0728130B16CC565EFFFF1549735C584BCCC45EDE6341EA18DB379EA1252579347FF0120518DA4B2086C74D4A6A7AB9F3E1F2780041C0DABD6EAC71DD8796B1EA9238B441C98911847FFA2E72B59ADE3A31A1AE297D8A97534D84CBED6C6D51D373F8B04DE6114D96C87BC656F65AA5E1BF2E452ECAA215CDAB36CC655A7E6FACE153E40FA3F96B27D96C9572CFD94D407DA537A4FAA4427EFB0FB3A19311EC8A75504A339A31D53C1CCAD68E6CC8F3CE528EE7C05E5DF9F9F8DE186281EE6A0A7F78DFF8C8C33882926187F8A203A983AB0E9F28EC7872F9EF43D041C0715DF111E92F6881205BE5E738DCA0F5A2F55AE8C35E2D400AD2FADEB782FF609DA48B0C9476E8804CDA598DAA72A444C8B9ECB7FF6C909CAF9692F43A0BE99E5BA2B4D7C7498F6D4246DBF210FE564A75222C0B23158FD0DA9BD63AECCAC59E3AF97CB83A20E57DB8FA82B07311A4CEA23F17B3771DEA2F6B093427C074180CC739CA5157EB10AFFBCB95BAE6E6464B66F235DCD839222BC6EA83A362A0A398132E9946EA2F996802DA3F7A7DFF0B4F144AB0D0F93E88A0F2CC52578824105E9F586C79A16370C32C13328D40715B0C845603D2F188646FEBFC7F7D720D9510C8856BE31F4552F4AE35E989A8F9CD822FA550CE1EB25BFCAF994E8793DD47BF228DE9637DCAD4E9F9643F211527CA69E7E4A660D023A83E09310CFD696301151CAB2EE6DC21EE6534E9CB7A411714D7E55FB7BB605E87D5D65A1D5755EDAE7A9C6FE773EE27E72AD6C102D9AA7E59F1949A29DE61C6B17E2594672D7542CE0A065E4D821A54DC491306F3D3DB0EEC08B8806F9D7F191F8B7D6320564A5095F74F4A22D1A5B0EE90BD69F7326EA9C7E150C28C9158A8574A3824AA2B57099D5B297910415A47DFE0587ED23616EA5E81FC6B8E5A8879E7F8FC1A7BC4C5D57FB88853D555356BD236139E1C951CE812087E4881C9313724ACEC839B920BFC86F7249AEC835F943FE927FE4FF6B7DD3C693C29274CC400E47C21381884422B21F32C201B95D5B0425820F9947E88FF7D3DC6860110B36681F01F8A8FE86130E8A0C81421897F9D3F25DEF180583265903947AE18181F0CDC35CD9222828251D1999C34D4CBD3FD0D44F4E0B5390457D7BF32D8D078B40BA2160CB53632481E080D17D9E948AC7FB76F6A41DFB2DCC86713904815C669918EB86407DADB5B08391E09BCA6F47C8ACE5844391B4606F6858651B4F20ECDECBBA4A1B54D2258A4D285576BBEA25DC10755BCDBA8B8F0406C5FA90275BAF07D52AFA5C121733DFFBCB109F18FAB7BB8C24CB61CB3FF615CDF9A74097B0B4F90553DF97DB7E34689D27B4164FB919D09B86ED0E7616D22C4C5C74FCBD38B606D11B0F4642A0BE274DFED9231610AED45EBC736789194DBBE872377AE724F779707AB6BE0FFDD6A74103381EBA966C6A3253A0EE2563E629B4E065746C653F1423920347FFB073333730CB0248F59F1EFFB0AC01ECBA289DC403522814FA747FC2AE2D7424BCDF5A9177B1D987E3AE42A0BE39AF1E2493CB2AA491CA6959FF596F9615E853540CB41B46A5F450454B40C2823ACDC4808B16F9B90AED0D8FCF6C562F203B3ED320627CEDDCC45ADC616E7864F5F9E7A295338894BB2D76AA9961B3840426F94A7A816A311FDF0DE2A2E933667C7E961CD00FB3DE57178B93DBF85B6119F7243683635D2002D0B6085D32108F903964964C23A15C98548FDCD25CA00B3145A91A08D7A23F3F26CB764A6A013C20705B4AD92BD33C8E50C3C6B1EFBDFCE0C11572E8340BFBDDF68E86A16DC29A03085468F36BA38F089DD4B9AEE59F12333D4A90455DA32918904CF1AF70B2DB8CD374BB62BCB727A1F049FF87B70D70D9A166EEB6AC76FC7977FBE8D09EF7D6889525BA9C109413718D7E13DD91018EAEB43A84400E4E9D534C88605DE02EFDB0EB115D0909A61819ABA1AF26349E9193AAF407E827D8C6D5E46B7C46628A587DEAB0622CA7CDE830623C9144D48B50E9A1F3A3D7990C802ED34340E2BB9F96B272B1CC69BFC880956028B5956DA95032BD08A92342B129B1A0D21D40DF20A38E7BF82796D4A7A1C8FAA9A1A7494A2130911B31A57C644306D6AF2F1718D6CA874C1783362A5E2AE28B811818674EC24AD4D7B8FEFBF5C961BAC31B8C1EE0879FE2F5E33FDB1C56F03A31669B16FB6121B728143B9B296C6B82D71EDC038A7478D17FBD74C2739D00224467462A12FC6F0669D2DDB29DCE3065E0C53A03666BD0931785CC3BF113661B7DA49AEC27A151C27F62F9CFD3AC0B28FB804DD41C5267D6C8AF69DAFFBA35E90E8EB0B61C3A569C601D68C50EF7D0EEF43E1771E0A4E4266A20E120BB2B4A6F1622D0CE55CAE1C104B3EA8198285ADEFAFE6724FD7A2422C7472AEE43EB1C9FF04154DCA22E9860BD7CF1AD43A3C14DABDF8BA3F5B6878ECA149A60019B0640C755FAF9A731E5831B6A0EECE45B4DBDF8F9C99D75BCC157E0515312884B3A4817783FA0C349DC39041CEA9BBCA928CA5D4438B39E880ACDE420E1BEDF052EEE280211E3B2E2489063074C72D69290DAA08051C293222D34D3611ABA8E12E46B7AD29726284908C02D6A6125EF207CEB1D275C9D21C28B101ECA0A352A77C9CF719DD4810F2A41EE56EDD104D9F52EDCE946C28E1AC030B5FAE13CBFF67F287131F1E7859FEF7BE1A77608F126552797C665C4E1FE09EB72293E10276F0595908537AE31794C1937B0BEDA74209BA4798D37EA830C4782B77247A50B841D30A0A5CDAF439601EA0598C0448633F04ABADB0D5960F2DAD6AF3301A5D894D9314DB038B3D7C6BE76AC35C57E21DFA8F3C762DB201F8DE445016A3CCD55C8B555C532FB2E52E193CBAFD1874EE59022D60C2413084215BAA13DE71AB786489F948A81BFE33186204EA6D066B144033C0FFA9168B466820AB75DE4F614826C9FA02F0D1CE74BE0060DB450019FC5C04DF04239018C10165255A85E09E897BE723839A8A1963CB39BB14090FE5FEA1D7CF332AECD12E10BE8EA7151986D7FABC887C20FAA2209232AA7F3DC657E2457EE5393A290E2059683B05A4D0BEDDCFD965F8EDD0F81FA9A7352916BC72345926A16BF7A7A341E733A285D3FE85D8ABC3FB58C40CE0A39F0530EEA14DF3758CC04ABA496EE23F8F7B2D97AA3C7548846B164F5BC8089D6754F10EA1A4A7939D5266F7F4A543FE21E2F25BE5E4A8DFB33DD994675117272A83521C69FD99FEBEDA9483C206E5179E82184BE965C684DD3E911890F9CFF21A6167874931BA48D24D330C70D22317F441998347FA564BFD2448CFFD3E065A67C265C24BB8D487799CE67614467DE844A5808843CC83AD7FB5BC3AF16D09867F5CCC238EA45CDBC0B458ADEECDE03C29ED558DB4C5CCCFB0C9F4A5052080AC753B106E1F52B804CEC677BA15F40099EAB120775176601A679DF5117C08B471689B1DDC9E2C464D1FEFC4432A27C32D93D32EADB54D60E06E3CD090029A9F68285725BEA91BC6DDC00477414D8B7068ADD48DE93EFAA7A3C7AC8014B3A4159A05399DE0AA4778D60C0DCE837516FBF048499E8E5D2605C105E18EC4B9D514E14B1E40C06016D5B3EBA232AFEFE2E012E5D61ED6811AA26410671BF91F74757DF0DCB770ACC00890B6C7C081CCB529377E323A1E3DA9F81960E261882755C05A8B69E1FD1DB5F62EC5C08D4975AFDC91718EDD24394ADF0010F5CEB65B7BB012C1C18ED24271DFD009044F8D557C33E1804DCC5F01400746B83959745DB619A6EE21CED41D29AE100178E5FEBD96A93FA0F70C9CE5496185FE3CB687591FC023BA73F4426208A86961B1BF9FC63B9CE68159BEEEE21A001A19F377CFCDC104F902779AC5C9BF35D0C1B1DFA72881CC5E6F59D377CDA4C6619030BD5EE25D1200890BC7D3DD774F6EA8D4BE7FDB474CCB9AE6DFAA63C7164B661E93EDFD9582A7C0728FB82BE63A69AE193FB8B85C7EABB0C4B6CEC488BD877AC68FCF3DA8860806EBB0B221880373A2AFEC503A06E2E839155872FDCC8046295139F69AD78FB64869819E340BD2231D071E0C82AE53B7FAAD985B8E22B1BF5BD5DE1D52EEF2D27AF71239780FABBFC7FEC967CAE4C366B730C1095AA42F926BA404AC89CAA088133A20C1603AEDDCA71D26A84849B6821C0997C197C48C7D367CC6370B61C29AD3415D279DE69E22D552D8BA446CFD850DD8A7A6CF229A32C8FAB8271934C67AE5DC43BBF49D92E7AE35B964E2EEE2CC9519683CF9976FF3E435B3C9CA151BF06FA9F81DA19541DF554B7D4AB03F8CE7F42A4CB0B6FF30C93C4C478EA89BCBC8EB1FCA517A78F9B3EDF9B6E5BC5FB00FB64975A95638D272C075A508C61CB493A6D7B8C0BA66DF0A08F01B5885445CB760133FDC0EA20B574C0B0DCA80FBDEA304C5E02D361A67AA7FD5DCE621760578F16AB3D2BCA3A33FBDD99960E31299DDF2FE9FF8D7179F8FE99730B051E537DB8185B25C6FF73D18F09988B5837692868FBC03A23FC77242B90A7F120E2BE13590C9986EF543DB973767D67720E476ED268BC713A9A386DD078FA590FCC9F4D2A344AAF0614D805196A4221CE54E4BF7031F39A098FE25C1D1F9185B184CA9BC4FC7F4EDC785460E7F626D4F0687F14AC0B066CF0630BA867442B6921416E1D6022E2D4F763E2E114DEE19EC5E3099F30EAA4F93EA3B35BF52911B223C62E6F358282589881828C2237DF860346014AF8410C1C1AD4039501D67DB73EB30B918F7F9AC02D947C3988C9E1160615825FABD0549FD54383D16399BD2634A23E90904511055F3568E61D59A59FB10BD5CB7407D26991019C0CEB678E6BDF3168FA18DBBCA5DC93D176EA590EC6186AD615FEB3117F93705BC3800AD7965A4798E4CDB443DD304E8B2A6D3B52C63CE8D05A0FFAC3548672CEA59153E610A18E70B81A5FA68545D08C060544C67EC7EEBD3B85F977DF1AF51CAE5F7651BE5DA454E9D7626CF6EDBD12C9B2AA06FA25A8B2E15E93EDAFC25C0964944B0D1497A0DA4859838AA6390B283E5E1C1A386907F00A47467956BE887408D1F031FE21692D5543CA8C6AF8A3010B5BF41BA232223BAB4D2047312571E268151405821E42EFB34F88A8454024971FCCDBABC0DFF994B26094E96E2F86911D2344E46B12B19A4F5D724C97A602E422C95F5662E446A876154209F82E09480D8C827D155B56B15E903809B44FB1E8828CF7B7A131B10F86412136690AC5F61A84FD652024F05EE3AD54B76C89A9C6BBF028C353C8C44B9438192F14F9A50BBE7657DDF0CC0E1A29D558D0524DB267C08D042AA0BFD75363F07386CF7F7AA28E377CF08DA5C44ADFFB5DB950A79D3AC202DD1A32F26CD63C2488A7520DAC8A617D2921B66E0AFE1FB93B71AE56586D34634FADAA49AB25DE35F0A81DA1694994ADD29FF99033CA038A70CEA751802AA1C04E52701266BFEB0D6660F3910C2ACFBAD2E51BC388303E0B02A4A742BB71ABEF956566B100406FD00991453799040742928405F807418014A4F4FA65A96C4FB2626196016C4DBC8C5C4B19E4B3DA49E8B70AE5D655473240926C11A99E5C5A54CCE80885F23750A334D401C9AE3C165772477B98DE201E2EDF66A4D6B289EFA04A3DCE3F7EB41275433F88873C7D51B6AE3D0FA8A015237623C3D66F85618582932C393440FF73F795913F4DF8F916ED4BEB7ADB403237B0C1DF31662EE42C0508598DFE9ED3A5888F50E4DFA7646CDABD1ECBA4DAD2962A637518F697EC3B32D41C9A675C343ADF42D61E272054D8DFA3C11B843F47447A869A28CCDD23F81A9FEF4A7F6F21AFE47A4E27F5E45F975D0B9CEBFCDC0B7C53F2F7C58FED7B2D513BD18A7FD8CAF4769B796AB7F9A6E51E2FC283FE76F76F0472A374158659B64ED798A2BA0235DB8ED2F07B8A71F9908D1DE35CC8FAB40E7988304DD2687D0B0A554D1D0CEE166FDF87A18441CDEDADABE2CAB828B06156FF0CCC4B9A3748AF40FAC76DE57B7D11F5F5B6789F626CF333CAA6E1C18948BF4F7D56CB90D338CBCD4354CE5E3C806E02D58BB083714F2B7AEDFF3D068D3BE43EE79183C594C01FFC73088AD1BC314720C614DF0A4397AB0F50E824CCEE11513604818AB36C7AEE349888A4DCB1D2FE1D37DC280C6E090C13414807A79CCE7FE800E33B94F23D61A63D469B2420495D15ADBECCF1687EFA41FCB780173E5945D1F2FD250FBE7EA840DDDBA8940687019783D48488EF49F9212AD55FCB5068294BB5D3EBBE432BB6789BF081F014D88681EB8AC2C31DA03961CEFAE8EF699F618917A3C4EEE8719F1EF2B227A6F65F47501AE3FC98226F342689EE3048DEFDBC502C3C7838FCA1EB783F5221384CE68981C63983E11D6C88237EC7B3274D9338B3B241DF5F04468912F7EC1CF907D13F043C6C7A868480F5EF850C78E9BC75329BCDD7AF69E2C438EFE743565485FC81F8803A6C8198E374935FD8A0C42A7794AB3EE4BF0A0B18D71B1F74DBE7A4508CE97DCB89316E2FC51CB70DA3690EF296FA2BEA0AB88018E3074FD520030DEA4B0A1BA9AAFDB40802B5CF7C1A137410B335704BAFA1BD2A4839704473B01AFBA4CE74C83422B430A88D4704A168B50EB0BFB4A3194CBBC4A37AC06B2E114C4E4C0014836B2E8122AC3E42860E1418416C84F9775E98A965A1AA79984F4A92701CF1BB269F487E3CE9380A8193E68811DB030F797EF6604D9FFAA7CC8FF81875987EDEB0F0CF481F383FF950039A2362472047FFF3E3D9EC264BB938DF0BC6D2AFCA79A034115094A5A7F52765EF35DE98321A7540CBD584856F7883A6D9D1D8E360DD180E7B2C9D16092715AF897A28D614AEED91A79C383A7C2609AD39A40A742C9F9F76981398A025F99C8D2AECCC0A5AD10BF88AED63CCD118B5A9779EAC25CF745FBB05024F8CA8152F3385B1E7BBD7A84BF0500C993BA6C115965D797000933A823E0C04128091C91C58501EDE06E622673DC56956ABA6585205589672782A9B5DE308A377328156738A92C2032EAF876A7E6AC9FE1F0484DBE2CFA781BBB0EE51C66E6B966C73964F3AB04790A14ADA88ABF77E358251C0FE772DD9B38AAC0FF9A66D77F68FD3797FA40504208A53F482104E7A808107792BD7270F8433654EAAA2ABFD5FE0EC7D84CBFB58461824A9EFA04F52C2ABEC5F7C280892CC09AB9ABF58290B9A7E56AC29A50EDFB260FC470A3A9F7592057D772BAD0B7B1F82036097FE61C779F870A7C68BEFABCAAABDEB75ACFFCB3F74F53B6E50C3C628F57EBEB4D0CCBA8CE922182B3F120C7FF3F9A1873AE937108096DF417BF26ADAEB1136141924986EDA8A04532BD6ECE1438007431C3EFE388567194BDEA4E7F2CB7CABD6B111500BBDB53B5EC9BB8C8A2554711E3AD5EF74F1F5B4652A1C339494D37D7F659C325C382A4056BC5EA90AEEDA6FB175213294C6B7D59B3EDDE8DE96041119886FFCD1B534D9B39CFC2146F3FB39EFB0804B1E3E3DD936D6380E9697D1ABF4D7BD9AB849AA131314FF2961868BFD39D08C7BDCDA1718F95567D03ECD8413664C1350FFFB7DE6030DFE1A25354CBFF8D582C5817608A65F647720BF508238A4C6110145FD0F67353A53007A315E71CDF02C3BC8C85F4F0C0688035130DBF951BB06E17EA9DEC383609312379EB724CE17A76B3758184F5F1367DC4DC3DBF16918B60B14B1C442E1029954915BAE6F74170A7BC1EB39B3AE9BB85963FEF337F8435C4EAF0B323F4BC8E224FC41C49832B95F75566F23BC28E31B00212F43AEDB6FF3ABF919D2C64F18D6FE28B75E4F7A6DCCC079B6BD1FDDEC06DF727BD13D9AC515C5D2A53F5EC58220DF699C4934FAB8681B3DD82ADA50AC6AE046C478CD453EE10FE596CF3CBEFE8CDF6F3F52908A29D086A8138320C0945FA22706B86B47D232FA0C2C243B77531B2EC7ADCAAF9991E966CF981DE12DA0C0928A79D04EC7AB366C6DF9F63A2D30DEDFAE0BE130BBB8A9F8C37AF49EDB155968DA7A86A964E79E43A16BDE6EA3F622E4B4E0CA9A4188AADB24DC392BCB5A1A56D0C028B7F3F534AFCD54B22548983011F45A0F411CEC03B59B6CC28020F81E1D4EC11E875549CCD0F0136FF2FA04F7B0A64D69B84D993DA9EBA3B8D74B8256EB6A06E8C8794102EA768087FFBDFBE0B742C02BCBAD1A0009FA41D2097A93E60A8C5BB40B0CAF4FDAE67818D3D29B7BC2DD6CB165CFA765AA560557A3266EBE3C366CED9D71BAB8A9EB9805758196CACA6C3A0C5641D7A99E1FDA90AC2AA35F39C354938636891943A935F0FB66F1FAE571F18F92F051D9D9587B15C330F3A09F4293B99D6BA2825DAA020EADE2FF5A87664E125AED1315B48AAAA7B03A8F7D893CAD94C35148D890A81887259B3BFC24953D16E6335C78181525DC543AD336C6DC3EEC561D3DBEF9072F80CD4D3624F6416C6F9C4F18D15171F55B6F4E29BE1E86BA28DDFC4FC6AC58E26916568000FF67AC03F867B1A3D05745D621275903051BB43F1A8DB700C2DA6B6627F5BF659685D7F9640F6F3197B6D670207822B4F0C4594F69F0DC171F4671F7E1199BFE78F647236695ACF3439130EF22A97B8CAD41AD10BC7B38F8BABC6C7597ADB97ADAD0AEB27CD5CAD8FCD3F5CA8B73114B14CB2F430E348719ECC3C9B79E39A60FEF8312CC3A550C4A5E53C1F9046367D0AC2B0ED5AC68278D04513B3794ABB97053B3A94803296D105754FB79072FC880554B1C4CB3919A29DFF39915B63846300ACD97113245D19119D194449F3B147BE1629902DB50AABB5910202018A3F4C39843E3006C36D4311B5179339F9EE6843EA0A0AD2DA38229551A8C3102CAC40CDE1BAA73DDA82F81DE06881A8F19F98A2B2C0B5ACB7F0EE31C75DBD0427781C0348634A6CCA030E8FBB39A5074B4233CE6617EF1DF40545A0F1237D515404A318D02FEA2F9FE9721AD91D39811868DC99C4D9410E8E0A36F62C11E5FBE781D159CB9EF585B5C2074FD399EDE1E5F3E520A3E11AC191F6844EB872EEBC7A42C2694FA9D7E8ED1D50AD9EB50F86EF0CB6ADF836A249DC44A95EF515265BED25F14884F5649A2F84724D00B0C5D92FBDFAD7AA2D4FF227315E46A364289B107D49572426E56D00B3754892E70E19EBF186F76DCF4CC0C4153585FDD17D120E58DB095B38002BC5110A1446C04BCB314615FDE598DE75DB5D54737C4E6DD71B83F1D0F581A75C257071D2A88B81790F965DD66D2A398C4560CDEE304ADBA689DB68DF3C6DC5E872DA1A7E9FEAAE20DDE4EF38805703EC3A1D7646345C6F6489F9EF10B3862C44F15E76FC15076BEE40B8CDEC309285DA15C5F551658DD64A0EAFBE51921766449C238B2BDC82898123A01992D3588DEF0D1670F17B49501A61FBDAB3A2CF22CC9C0C4382B1D764CE741439CF3F11F2041EDC8D46C23D4BB9F6111825B9E2CE61FC3A2301C2C2825B8000D9D67275AA70B52E84D16ED29BCA5750C249384E74DAED45328BE5B9164110F8E430028C0132F1C432D090F26FD964B5DD6D6215C7797FE2D1974063338608D233034DCF0F612CB12A56EDC7AB658BBC23D104B6A10906A31E21601AA022C5B0F21E16E5A487DC15730E03505861F843160DE4BE991372207C8F84440B122E0B69C0040304A24352EC1E23142E3188DCF2D92BEB2B9351DFA17DC96057C7BCD02FB4FEE9F5EE2DD83FDCBE10A1EEFB7C488FC43B9B8BF46B7E61D17B1BF81E2818E035C2133F6FAF1095EFF862C490C6355CE48A001DF75B15BB3CB701E9042A68C7A32BB8752ECB4D5D9CCDD3B91443A92702CF5EB06FA4E5D770EDE358813127FE81D614F5B2030871BF9B95630CC41C1119E5FDFE681DE990066F0546AF7174F99BD60CA19EFD286A4CF5A2360AF1083B917A3C9911E6DC635D5A5C80E4183DFCEE5AD2795B956077BBA99761725AFC72AFEBA75785E6735B5C63C1CDCB8564BAFEB95B327FE2D413A8BC8B51F665BD5BD6529B49CEFE3ECA0945A6611FBAD0F88F5A605932A9C2AC1B9171F03745CAF2779F1851BF064F718F48746C4536858FFA239E2ED651D769C1FB267D299DC35B23B9598CC7EFAE46E6359CD057677FA7DB8D0380B8D1FC95AB9AD70E158204A32D820E7EF13B9E4C7301754A67436D383BEF0E2F88221D7483204E12AAE26338DC9F0F0B5357D7C51380DA348F6064F8BC938C3242099F6DDC810A1CB48B83AF8D44F6281EF02FB6B0A62F201326AFE17CAF810D7BF5776D273E81D7117074986D847ACDA35369D696B0E0A356433C14F2C56EFE7062857A0BE2513B3BB6B28A4263170CB97E8639E9E60A047D732A0AE836E648F33DAE266F1AE193D0CA4C8EB6FCC5B98324AFC6E6B94C8E92786B98662F393C5DF102535CABDFB4F277CEB2CD4CA3CBC0EED6F9B61585524E69EA36BDC699B7F40C4F488E4BB826617E5800A8EB8F831E911BC1841537D931A30FC78BD8E7DDE7DF21BC20FD2E97CA3A99FC6764441F225683F91A0E67AB5A5116924277F282604B9DE479D34B9DFC3E7FD434C2AC631732DCF8B2A2C5E8296FC7C97A6A6F68757C7D2680FCDAE1017DF58E7518E2E5C0DF25E3B2F96DA34D8F0B4D2E56F8F8E7D7BBE25AB1FC685E431DE10E60009BAE892F7C75479534B1A06A17364761A1CCC2FEA29A7778EB0C555255C029975A054209A9B60946BA391DD47D428E4C1D37DC7A670B77C02B7FC7D6B92770AF6B72E701C009DF9B9CD6F405EF6DD22DE3DD8EA8910EDDF67B971CFD5FDE57ADEE6C641D0080ADB2C071A8770DCEF39DA4D136A7A577417E81862BCBFA02F0BF8D31F8D5A98F73F8CF19FA8B009F0E974C236AFECA28DB508596429C5C21632284A3D6735B3320EA5010080B75F3697B1C6915271F021A11A8BFD990EEA02351B9F6DB5B168029ED7BA98F28B4B355CF701B25878AC5BCC8AE9BF742752D0519D07204CF7A3EC8B0951D6F23006EE01F481BDB171F91B4121C4894A3B5239C29E14EF068B512B9EDE0D4E82CBD80BDAE2AB0B4226443505EA12B852E36F896DFDF555A7F634CEDDC0DB87E4224CD326346F115C4026142D97411669FD1A90B6BA5C685B85BACFBFE003E45DF437BF3D05E712DDAD6B43D84745A3056D4077EDEB8C01023731BCB15BB8D46A95657631BFA1A51B0232402833E0580FBCFC385AAA6B0B63CC8033F1A5053A7B701AFE64FB7FB23F01681A32A2BA6F4A1E4763FE8BE9419DA3D2D9F32442CDB28260D3BB3A5F61F88295FF6BC5427949BCD82E8E3B3AD4BBE08BAB6DCE3E70BE7F2671DDFF79151946F0EFE6F0ACB163699A98D08C3DA172EE87F0F7160F0E614EBA32AAC9146455F03DA6A2F65BD0FB44E1960502B738B4B1312073A8E3DE8719A65EDB105CCEDAECFD975E49FE282201A1730AF24FAF6377B3AC9D62A06A7F3B586F59F65B3BDFBD6455C92F326F453DDC49630062C7469CD63BA40205FAFF78E5EF48B17CB7224C80EA15F33A9C0106A6C1BB046F66E72ECC502BC39CDE54524444197613CBF892FA323F5AD8C79251035568EBF7572501E58E30E5E9D9CCCDA65D42C91D7229D240E7AC028290C9829F79D376E007A307E5BB8F297D9C529AECF97CEF9C1355085C254BD4C106FFF4621535640467CE4B47494473816A4D3D0A20D23E61445C4B487A82FD898448DAC882E2A65FD297031716B75E7C628034A663A19F0425339F55919D0F759B3991A1BE20E4DB59ABD19CCE2158F4E5D1FCB3596174AA38131D0386A6EA8474FF2C1044015873974230039F624B2906CBF0DC198CF551CBF34DE1A57BA213EF6F7D5BE70A805DCE8690A25E277A769665498B9AE1F84C79AAF200554B92AEA9A9B145F10B8CA04EB351C1E5C9F4DA286376A5C98F3843BB1CFAD13F3AF880A43F6F114A2B6FC69C0D824CA6204D180BABE0496E2311EF405D5CFE98ADF55589B95156EE75D452668E83A588C164708B563242FF262465D7CED607076B1A1ABC32B58E442201DA9D593987C3BBB642AD42B4E14C0D14551DDA1A3A2BE5D33F031D5BD81DFBFEEF9584667C20C38E82336830B562290FE5C811E0C1AFC17F73E7BD584A73815CE6D488DFF38A5D200068398AC9E11E060932A059217FAEC7FCCA05B22E7A71D87284EC42E67C698D54BE916D13783D5A5E3360216023889F4894B83DBDF09D213018991B854908F6E7B24B8F194C65BBADBE0A3D5D47ADE40CCF3C4000E57F38990D9D552664AA913A6C81E06A27AA9C039C2E11CA6AA1B492FB225727513269FD7F1E76966E5AE63B8102ACDCFB812D68CD5E79E3450A36A5CADFF22A8777CF7C40C7039FC3D369B4069CA44375C692060332520776E8D47B8FE05870A7D9E27AD9846318F876955D5C8A6564207FA2CB0D840D3169AA03A1BCFA76F2DB5189D6C3F451538F1AA598E89120800F089182D75DA0E48503C85F0049A22F906344955D3B45A9AD6518D8C28054C2D0FBC8C59A00B1A24A04B0D895D95C4B589A95B6FF18ADB6DA86B17B9322033626F5B56E46E9F50F9BAFB1FF8906C7A06A1B44EA75B40E4575EB572BEC5F3DCA2F81F512DDD7D54F81676F522055E4BB05A84FAC94265DFE26E7B72AE6FD8699C24543BBD6B497E0E3A09FD62727C500E81D748C8D501BF6596D961993B4030339AC1BA468B6E721AE38A63FE1CB5481ECD14ED596665AF73D4542CA146FB1A0E54B4D9CC17FA62E1CB8FF23594245EA00AA5FA23171AABF42208D199A90D355F1B2C181CC6440F4D4B08EC3F8F71F793E61DE6BE77F43CF19791B9D7FE1B90BE99B9B20B449D9B6DF96C35493A781C989DEEC5E6B1E32A841703A38AC3EA1E0C6711AFC0C6EA16E05D01E4A3D6A1EDEA6B2EDCCC4DA5A3A3601FF741643E44351BEB8B53A64E01AA5373BF8B1025AF04B0ADC16DFC4B8B57A7A76C11B234DBE8B218C8472A30617F84ECF446B3A4F2B60854EE4C7356889675DBAB605F60EC8E44FD50675C19163EBEC05E2B2E24845A4AA14D0B22BEC4DCCC8A90B5F8DB22C3D438A9D455BE36C07D70BE13B7360E08847531628FFAA8F551187AB83D0132CFBCEA5A55AD83AC50F7D570146A1DCB86826A0362025F88932234E5B9CAE5D1E4E6EBA61CE4500DEA6C0E8998DDD3F2D74F22454C41B42B363768BD9A5B8E7B2D8E291AD2EAE37C96005AEA9407AF7546A39077A33E7667C06190FE639401D34ACB4AAF231963DF949AA5D67F3D3E37C80826F3D82B498E6D2F5E8D925713D4D066B2916B8D074CD0BEF2D46068602223D84F6835EDCF93EEF1928B96AE29627A6C877CE3B50AC56DA106CCB3D308EDD6ECF56A46A33E02F62C50B1EAFC299DD3FECC75D0FBEC3D6C337D3989AC5ADDE754AFF493B75CAEE498182511F32F6569C332735CEA9FAFC466CDA3DE5F99F9D0383B7B19F3DF078F5ECB00BDEF8B10D1F86EEC935D7CE6DE1EF48EEC43D165CCCFB6DA36BF82B8F492B55C0F9ED3B96060CC8926057E50D89698B2789DEE8390CC77E60297CBB2804E6986AB1880966FDFB639F532B2C55AF1C5EB435356536F0E51F2AD64C8E4D24F18C95D03538E9E6D87CF664322B81CD6FD6D53BA0BE2463F06D6FF28E272B507BDEAC1111B95B69624055F8F180BF6187130B5B46B40F66A68F1D1C4FC97C7123084B6C95899E040E48CC03C90C8A10B15FF6ECD3C4079F6B3278F38744FF82B33E71F2FD64D6C820E79F5E8305EDFDFF3426C8232A123A087AD14D5425598BA66719F1AF6B8186205BD01814396841A645BF7AE34DE5C839C1999BAD069F6157D4274A88A67C6315061FA8E7DD659C19FE992046E946105FFC60665D2F38DD27BC5E2BA53EAFADF275990681CFA8730B393E311DEED6D16FA06F40EE7A9EEDD55CC0435275058F430D44EA33BBA3C6E578B2EFEE93D696E446C5177ABCBF2D7EF1EC223D25874A75BAEACA34013EB5B34696F8415D18407D6AC62D4A8217AF748981EF041AC50A45E5ACA7738C618B67E97FCAD52C305ADDE338BEEDEAFB70BC95E4E8034D36B99062E4DA5639E06DCD68CF0548012EF48A9E57898416F4AF4E6D38996D43184931F51C4362D11EAB77DA1FB29640387654BA26FAEED5C31C3E1B87BCF0F11E631E26F19C7B462D512FECE79448D7B8AB66EA5D07464D8607E4A1BEB63BF76984553E3C2C648EA3144E56D385AB4AD733A307A6E7E3EAE4C720735F8392644601D467504F64768E61F9DE3D414BB22FF6BDABD9119F3E17DDD19701C8E1CD6AAD7AF41768CA5B8C6DCD9774B20CD5B41F79184D3AB54F40EF0A1DDAE7926EFB22672A028D1D5CC093FBB020BBDADDF055202D06C4318DCCC721216B471FBDF5CBB077B71A9A0DF03F1C87D7691D7120E842F8BDF4846BE4708BA28AC69C2839F7F182085EEFDFBCA3B9EF1AC968E35F0FC9D04571A26166BE384062B2D6E751C84C385C6726E1B2478778BA54732BF50D75FE7FEC63EFFD9B9EA283537643D23AC9BCDCAA4D2B9B2E1DBE1B297EB57B8FAE4614748B7EDE403BD69C6FBBB5C63B694C0F67EF633208DF28068B2A618FD227AF3CAD05A6F3112BA26D7E13B2ADB004DF77FB0943642D4C8D57A7332400D332B17FFADC43857A11A9E360B3B22D1C5513622BA14ACD03D7663E3A99BAAB81F40F0C4A81CF348557068726158085C3B73A7AFAF7AB280261FFF5037182280B6C0DDA9586EDA46230836E7240A5A9AFD7D3C047B2990F08DE1E390BBACB242B530AA357EC099B472066CDD71DC34AF90C588CAAF204454E3FF1C845A3292FB71713A5A38E6CCFED58C33ADA3956ACF32F2BDE420D444B78F843C3E6D0A3FE127F9FEA02E4A23C1002F8A63566FFF2E67FC4C4F9A921C59E6C0A1488F60AB6F7AD4205472AEE47F31249AEC5208FBAB1F447C74DDD129E485D2D2A447E47ED41FC64864D48F4E892C98628FBBDF50B89134201E29546000F0CBCF2D2E28B10326D89F3329939AB7FAD998A6E132AB3F9FAB77070A9997A585109843C26EDA014EDACB8F0B78350690A9F9B51C7BE7EE499D15F7D51A2B1749A31C7D82B10A86F36FE9534171A3911B11D42BD22FA5ECB3FA0B6B25C031AF2B15575B788DD47A884112D3AB168A822C7D7F39F8320C0334E9CDC3F2B10E6F79367579AEC42B183684EE39BB1900C621141161136437301A54ACD8D7CAF1F5BE34FBD8AB0C6467B998A6CF099DC19CCAB2DB01DE82FAC923ABB00EB3C4CEBDBDC955765B29DCF69EFEB69974B365052C197E783C642D3A14F67B9C1CCC40AD54F9A2C1522B10D0AD921A848913A75439DF222D957F1CFA1630281515958B4FDE60D62FD7EE45D83CC0615262F357D0950443649C244B7CEA6871BA6C89DE0CDFB4DBE3BE038699630A91F14B7E4104EB113240D304B4307F62F642897BEC465D5ABAE085C25152CEF135F5FD37E1D98456F811077D569822D9D73247D9728A5C313207CB6CEDDBFCF0595C1411AB60B35DE51FA5B5DCE8FEB79F10C73DA83E557155A5D087B00BB22DB8CD5945E5621EFA9F7413E807EB51A0539957208264E43DF8560E60BE846E10FC152487ABEBD0BD2B30ABA217B296630BB1F2D4142429290237353B44B3D05E3190CCFCA0D1D291E6A9D2CC9E4370841FAFBC1E840D5713C2C1DBBACBCF1DA73E86B92C298A1A65691400C19822B2B8BA3B08F8C2E72CC6BEA4B6473C9ED79ED6E3DDE12EC3FEFA62F0D817D87A36DF6A862A5E9CAECC53A86B5F8F494F79B9F77FA2825336991582FF04C5353793128A24959CBD7E512D99A142D6C843ECE827EA6C1F35D4BA2F750BD7F35BA027A74AF0FD7D789DCF3B0F9D2F88FF44ADF92A796FBC1B9809EED43E902C538FF8A4AC8B8E39459E6CCD7356428FB5FDF6EC0A6EA911FFF1D24E393FE57F22A4DE679CF130673779DC7660FAD60F9D3013B06302DBA412E0188EAB033E0A2B7DC4E8BF5276768F4A702A6923115E0A2424FD4ADAF56B9B605209D568AD2975F46B04595030A947AB3342BD9636F8515866BADE5B4F8D7D75ECD36F987345FE6FBCE3F78877BB7A50176258062F8D57F17416200884FA629E697FA742C42038478D602C8BDEE7D3345209957A375DF66D2A1D4AB8B82D74C2DDB9B4EC98C0826777F2CE4C400A37561D14596D4A3416C1C1AB41F96FA0D517072A209016FD6F8B6E66F645DBED5FB7B11BD19BC6D47D8CBE26300234A66984A8986A22C3A35B57CE020ABFA19B395F3741CBD2390EC26F77D3733220909874A6F197FCD03102BA30E52349CA339D031E6D6A56A9362AEBC33B2D3BD7750D5276ABD4A5E652AF1DC758BEC2DBE42056E3E8EDD7DA781CC3222AF6E79053D8C512B748976FAAE8C1856C0A12C93EBBAC365124CF876FB0F7546F985DDFC496588500C937B918B2FC5DD4469B2A70D683C3A3394A9EC7122CB22A56F42818B4B87DF30DEA301F6984FB38E80E8CF03EFF0DC81A6AA677D0B68CFFDEDD4DFC3184AB9CD0892DDF7848CF88AD05D3E559F741EC8DD56C240F6112004A185140D43E10CC5276D3CF6D3B6356659D5DEA35B327539E346D2C3C274E5527122F7092EFD43618DAB5D3C5868F8D9B83435269DFFFB2B28D429DC0B4C8EED55DA4407B804910CFB7E4E4D77AC737004445F75EA166DFE3C8E3C0F4CDE7261E91AB1F5AE81FF7EC18B29AA5441139FB0F880014C4818E64122057BFF470E74381FBF957D9131FFB6AA27253B2EFE1810616776BA03767F7AAC11C2ABD20A56DAE52FD33E9AD54ED6899ADF90356543E5ED2289CA0E68F5F025502B28E6FF0A3BF764C07476DAFC2FA61CD704AFBBFACBE9E1F1824645774D2DC4B3048A828D7549451960DEBEE676D1C8A2163CF55290CDF430E2E91302A2D58DC956BAC07A2DF360ED991AF5403341F96F94F71E8C93A6576C42BFE55257F036D31E30C7186632A636B514926F5C93BC38CC4C41425A1FF05E08F85093C91FB5F7FE014000686340C897430EB71B89BE0B87BA4F6042199EFCD38A93006CBB13118E6AA7135665E6293D797C10CE62EF05AC1B40741E4F6040016DC5DE39FE7AC0723A2AE197072968D2CCB3A57174B5124BC73C3F85A871A4DA2C6D7958F887A67BD0AC09210571DFACC644CCD038EC853FA4C646DFCBDA5424B66853F6E528BC9F3776B59AB9A3DF522EAE51B7DAEABE08F8B1923DFD3C178468862D0A2D9EF9057210D5B3FF17654373BC67006273F9A3921B3A0D71FA709E55A8F6BBFD1632EA9FCB65826E82720BE280EBB0BE2B2A84F30D9826C8705091B204ECD802A7F77BDF04E27629FAB843A4B215635AD2F70BFE47B9ED066316EBD9FF1715DD80C00074A160ABF5B6256B22ECC3C976E9C959751B87C65E75DD0DFC2FB60FB5F8AFB9B883A7CD6F41A61B6AE537B1B31B81109DBB3D84601E00979852F8CCCCDE7726BFA02E249519C8E44FD29861F1381E86C39B0B6EE74BE7E60332A6C8BC5A2453E2F6EC4833AA289DB7B6D498EA4A8C048284ED8730046D080D75C1A4CD162AE6C3C8AF10B235E0838E5201F18DA774ED60A054D5449425478934B64002DA98CFA78BE116A35511CD406696C5F026F23DFAD0E516058D326221EC1160A1E2E575C2457EE90005781CDDCD5AA84178EE40FAE8FBDF6B43DE01F26581EBD0E8513C510779C3318510E08FC85107EBDACEFE6CE6449775301344506FA03D3B07865B6AD8C13911E0BD1E8FDE14412F786389ED05BB9500C53400C3C16093213DD29FA59B5DD110711126A722EB47B7273E92CDEBEB02992E295DB57421727B590CCE5CC25BBDEFC2404C4776AF571503F55AE081967B5B3B01EA5EAAB08FEFABC9247F485235569FF3D9C3E47A2F9442F4ABF08104A2191C07A4248110A8544AD8DC2472757FC0F127657F34BFDC5A68E483BF32D8FA6C5D3419D0FF28C6DBD9CD32E99E5AB888900139659CE67FC407E29027FA59D5D5B6ABC467A058484AB93F1FD797A53C7277668115631DD9A5077B9C3C688DC9D322B7AD994D1C0F27766287D423AF114588B8FEED468818B46CEC03DCAAD6124D64E05477C834CF726646D3C3F60C0B832C457DEDA433CBE2E6F697BB7E90151C711DF899BFD2B9C2565B2A21D74D1A452E32781E61F375ED9D0A00220899F295BA828BA1C476F895E9D950981FA19AEFEC06207FBE1A1494CE1BD0308BAC4EF5C1963F21145450D76DB26A0B4C11A529936881D52A5915DE486200477CDF7897CE9881639E4B51EAB3A12E31FD7720122401DFF63AFA05315772665B7DB9D57DA3AFE8BC804041A54F05CF9BC5C77E2E03C3644E6DD3391D0120EB3AA0EABBB89BA162952BE2332F5818150CDCFFBCE985B8BC6B054992EF945682F8E0A9F1FF4A1BA690F67B46AD4F69D0FE2A864CFF39AAF4086F216021B54AAE3E748B356F5149762607BA58B56C34FB5A23F89FE837E8EB1768F20F8C6419D480BE5F14DAC735AC6768D3A434C404D597EC9D1F9686D4697541F954EDB7C41A8106BCA78797063A5A881BA4E0F35F08A6310CF1FD1B7832C333FE65622777E677F797437F9D63B33D0577CB5DF763B58677B756CB8B595A098D98EA31F66BEA45F3E1748D42A6FF3B5139E75978B434048CA70CAF699A91E2209C12A66FD1C24B2A2B0FC91F90EB0F37CAC40BF95571D6D40465693526AF068C03135F171EF0048DB52E29C2D262E9C2152C6CBF21B0D4C013B4F989FD2135849687762CEAE70BC4208827E861740295A317E0D4CDCDCC1CFEB1D80F9EDC66F92BC3F594F4CE29F93FB8BD493D2275F8AF2E702B4CAFE4A7C4F0166539E786E3ABDDBE576C82CC93F9EBE6D07B0FD52008282B9EBCBD612BC433B0D53F69A4291ECD105F59C878F0ED2608EE2B12616283B66A3F032CD37739F519732B2726DA30D46B317BD49F175B2B49BFAA43B8C4747B86EC3BB5A8CC2152B944A1AD4A509DE425033CDFF9CE5FAA7F5DECBB77554018B00EB20D063BA7763660ECE652BDE690C8CD16BB626CCDAC311A86B59C7A045D90C04137E2156C69540888C634DE6AF36971A6C1F4D1B28D7A4AFEE275DACE2B44E9834D6825C47D5D7ADC9252B1F5A185A3267157ED6F1D9E1A3EF4925ED2A3749C41BB7CCDDC5B7EA607F1333349215B7B55F0E98F30C3C1884B6CBA20BF374092F5D7B2590AD62865D8038F9646822ABF336E09E06303FB43567290DF1B84E675C20302ED0BDCC8BE302A7FC9EEA60D6E8E139EDEFC9A752C5707B411A9FEB32D92F5E702051E4A079F5885C38585B1DC1D03CC07E7FEEA070BDB67B24A298886CB531434318DBAAD27C61B15229AF88A5AC40C589EA7EC20F7864C7198CEEA1392BE79CD26373194CFB9B263997599797CFF2FA2909E2AFEB955E629A656DF3D031B582C4B11056140D6A02EC3AD74EF16659245B7DCD8BFA3942AFE65AFEA3B8F550AA22B6C52CE67B0207D5E848CF852C5864C0F8C69BC05F79FB114F5CDE1ACB1554F07FDF8DE811145B0B92CC21F92E818BBCFF37044EA5438B98DC43A2D751C9F65940BEE044C7C7534AC6AA8139DF7FD91AA3DFED5DC3AF01BFC8EFC81F4F800E9FF5ADB24A442DC4FE29268CE58780D9DB8026584D072D660546921F63E7710F4E2CDB183AD3E71A3F5F36B75BD229015F10F80FAFCA643688BBD40D5A9C773455DD2B7C916FB971FB16FD88FC758F92A67BCAB1F913EB6AD79D0FAAE5A29A89515089D838E4A019DA85AE08101C6061D940191BAA8B9D9959DF35F77E2F8D469D184485713DBFFC43458E2BE1EEE35DE8C41E5F94E244DAEEF7EEF07366D2D82D37EEC6B28A8A1BAFEA38B74DAF828F390B3C0C8D8D112AB88461C660D8E5A2C0718E6FF794D3E9D1007648881356F63E8D07853B928359A464262B6316CCF4FDABD4F4B74773C1AF951E11196BCC88F92625FF6743E5B7C7E1285AB3C3600D4B5A9F902F912A24F21B2180C008B8A7C795ED19DA2DE767ED9F788461FA5AC9D322E3DA45D2ADE05B8F3D22611CB1DB409BBB380C4DBF73680BDBDC9353A45662D040138BBEA0B87AC28A7E622ED045E5C510DD2B91600F6864002183EE50582A284752ADC4A9FFF88504DF46D496F7C80F2E6FC262A3BC66A5BAADCF16FA1A16F4D4CD395CED51DC5C5A05506BD0AC253A029A8283E1A9563D8E519B3D627DC686AD3A7F544374E9984D3AEF8924945FCA1512E85140953E47EA89DA2ECDD4FFAC61C763114FFDF99E7C5EC7C5DE1AA540A91E7F0FE6716EA959961C1233BF0979D7B14DC418D691C8BCD883741A1CD07472C45F97999F1C24BEA16FE4F414660D096CBB5D08D5CC1A5E2D98FFF175FE405FD3C7F840D811FABF834146B9CFFE63BCF9FB77FF882CAE2DEAC8941E6597B6937789AFF3E04AD7D24F7A1B3A6C03DF78D2CD78A8CFCAC7CF7B97049FFF632A935EFD19DBFCD65488B8A319A7E79A13AAD527E59C762E4604AACFE5BFAA3ECCF42FBBFA099EC5706813386986FCAC326CB2BFE0B9235F86B62C5B49BE223D2BD3BCDFEF77E9486E7969E6781606C27C8D6756A23F60CB16C0FCEAD0258716E1E626BE6404D5E7C6714BF6A8F5F4AED81A85AC3E26A3ADFF9709D9ACDFED76DAF2E5BC4038E078510A8AFDDE91049C529034AB66CDA684DDD719192D9FBAEB6B5D87836189574139B4A44DB29F15310A043555C36F9909179D45F28B11BE4E7F81337AF38B34AD3BE100076904E1460EBBF0C161FCAFBCCEE00F884DE2AB87FF92BBDBC8AD1F287278320C0C10828D82239BB567D2F94034AA3D00CB6C92DB6B051F54AC19F07F1C1DBC90AA0DC75D5D3EE97728A9C83DD08DE412A451106E427330A099AD2BF0AB0AA8037AFCEA01A6E71F82810859C1533A9174A4029DF3A52D533725AE0CCDA6D6115E73687EB755022BCB9F4E73118E6EDFB862100A9C80783806EF445D3201E6BECEB291AA1CB07FFA3BFB342B006FD000710DCD25FCAD0A8D54027D6710ACE629A644DE7D9296F1802D215706AC4F2526BD7C40692D00236E6E0A74523076C4E6DC3B664016C43A7D96123C34E70B2BAFCAE5AAD8473481D3E94E7B7F730EF239F56DFDEB2119D75950464F7C8D8AA53620C2FAC8CCA035DA2F9804BB7AA87C55C39C1B15E276552CBFBC86A98B8D43BE17A534348119B5DA0A24053431AFF8DB015086C91D43699698BA76B77B17826139C0400F4A1D9EF37833EE893EA9013DACE96A39206F9E2E502AE1849EEFA6E3C332EAA909B70AE5038B7277B82EE2BB5810F0E980929793494638EFA4D609B59715D0584C10B85ABC5DFC5239DD9EFCCE458D30D5D033453B1268FEC734B0B28F00BF651E4A79AFF2B81823EA89050975C8CA33816554B7A4E0F4A561A6010D7D8CF46BCF76E0BA2C1577781F0AC879189DD32BF90B1692BAED6B360B14D174347B44BA5D258EF1A522DA29108E4B05AC27D64E0BFB1EEEDE62B58F233988D45E4EAB8B3E020FDD24CA96647FC755799D01F6BE349A07A3A4E02D905EA62CFD75290CFE9035172E61B1D034D2B91673D2412F4AF386C526803A83EA076A7098B04F5427997229C4E9978DA47837EC563ECCA3E213C57501D842E8E58DA8EB3E00B2E1448AEDF5557BD9CF89EFD4BEDF196226E3542218CD7CF8774A26C09F7558D1661DDD90298AD43A2D5E450F1DED3B087889623C6AE5146DA43A72BD13A02954D8B482F8155CA99F45C48B51C7B230FFE1225B7FE528639D58FE2068945718869D5C54C7275EBBD00AAE221CD54D6D7169ECDAFED79636AD3EEE1EBC10034917686AECB161F37D03BCF92B111C2CACCA38DC8B787BCE88A5D591F71A966DA41E1DE3913DF57BEA10B6C0D6057788B715E35E59D7ACD4E5FC0621A963FE7CE5F2A5CF91DDA4D66F91093842E928DA4A02E30B3BB4CBE2007B82C56AF2618E25E7D7C382C2C5F68F5327318D6D6DFB2877C31316EEBA450AA08130CD349A085D8E64095C502C8724963471A448E9D76995B8609141F8034CF13B6037C821F7A1EE4852702721EE3DC4F0EA43CAAFE7B28FE55793CF32CB5F8073A00AA6A255000D6E63FF4B3B0D6A43C3BFD8B5248B30F2B2266BF3B6D74613114C51CFA4D86F6836C0F1A17C554D8755F5B815E2BF8D6B936AF9164EBF237F1677982A8B32C39D66B1F68ADC32E906BAAA39484309AB8B2F9D8CB95AFC12DCC34F9AA7409C59244021B389970C833609BB9E38704A18BA3F91A2055AB534A93C08BC9AE240A4901BB875F680DF33434063D90C20744C63F91538A74CB6CC31F10E4E125C97A4276BD7DAF5AA5D7DCC27833F489F6E1B0EB93E767A60785F05D40ADDA910869AE6C696745AF2ABAF2FB154DEBAAB5D6831A0C7A23C7F60637C6D0548ABBD33D470F46DFC9520E6FF7D4EBAC12F9054DCF4817FB94F12C92F78B39F03211A47ED349A5A8D49E513799762A32866CB7B653F987A8FC71A59197D39A0C0F109EB44410288168C219274B48D234801DCDD81C9FEC5AF1F2205038C22119C7F71FC6F7C27C4A548DA1CCBB73435FD895037F2D20DC16572E2D0830A75DD4A6C767D11E801038F1EC016641102AE3F78AED8A4A3125F94DDD8A7F57755A26FE545AFF50E11767342FDA691058A423619AD5F70D225825EB67BB7987433A8DFF3289F089C11DB2E6953B1D172C572AC52C6048E0BFB0E96BADB5AB9A16BE994EFBA5278A74ACEC006EA9229CECC78DCD0BA9B0B34C20CA507109BBD87425AA4F9945070950A7A2C4E473A453366F7414E2963F187AE865ED6404B2C6D099CC69E8B1A1E09DA8B2FC2627C930529CE195B9A59F4C51605E82B5175B807E3E278A67F62A5CF21D0331C65510D905899AE723960D082148AFA5CEFC47B6A3EB4A6420FFB053C530BF00D8A5E1C9F4AFD4E284E9FA86784ADA07B17213FE0A02D1BA4A17A88A910879BAAB670EBB9AB6C342490C7252D28E616BA67A2C31C2CF6FE4D354FF6E35D0DCDD9C9265113BF13F612600E1E1008BFBB44492FD36B67F3E6321DFCD9ECAA4377614B2BA88C028F1125E932DD58AB7E3F49287A75CC234F0B6ACA715E499060B0C222D1E7D798C9FF9D71F5AB8470C9A702F74C0D16C225523DD05D841172417F3823891FCBAE9821BB4360F2E726917A87B391573CCB0F86C8D252C995913A543B2088AC5E73EEADFA8AE79CBE1DC8BE74E19E662D5AB646B7BA1C1399F56EFBDCBF916B03134F19AE88255D470474FE500B3604F70FD1D1F1AD03013F523D656A14BB2ECFF09EBD14D9DA291DC642FC7BFC1555BE86C57155F38CBCC87350DD0F83536C8B1734474E4C178138219C71F7D92DEFDC41CB0B80E1D05C2E92321EAF16204FB87549F2FB9EC1C2594E6FED390CE0FEAD9B0282CC1014F6B6FEDA017A3275EEA078271EBC08C591E6191A50235619CACA5468CFB1DE7410AF088DA530DF6E64DD399850F5A5AC482230244401BF04F054342E5D48FD26094A3BDDA6BD56DDE0BEE0438DF754D2CCB5BFA823A97010079787A6B9271F96408122B0BB73CE556481D3301F1679709CEA17E3B8224B289248A0201ED773B1C4958E7CF268A0C9A8158723CF1C9E2CABA951429C0A180BD61A69EA451FF30A7191163243F875C19473AD38D8B74D94110207CB43FAB96621EE2144E4B39FD121F09A227AFA6AAB94774D778FB66ADC23119D0B21F66E6C511BABD74D18A60BDFA229A343183C3D21F6255221FBD253ACF62A51030103FCB3707F38DC273CF400FD7BC498A93E396F57D0206A2A2CA75671758F242E44D754A828A505EE7918847A0B8BD6A0F081318A24C5E73CBC5AB097AAFE880770D0286A657704E11AB7A7CD487C54425CC7D5E6557BCC7858B68250232E5E69E7B378CF21EC12D0F840BC28366782384847B74F1C510709712A680969A7DB0E37338F79F2D1DE282BC0B7427B738723DE6F4E02FC5F3D170A48D9889B696AA3046A265CF39FBF46D4AD5A0FC444581F2F325928BE53376819A2D2885D0CCE733744A6231D37021CCC0D7D804798797C28A0F752AF37F74545D9A071AB851344C5F0807848B3E5497D22A0094CF3F2D54613F08C2E0D16E5FDBC029C7C6F13A58D49E361C1DE8E4312439F6B1A49F241D522000AB3FE78E519320C6D4A1D48AAE1FF3B691906D358D4EB378C2BFE6A6F88D63F90AAF04989A9BD260395CBC13403969E9392D51E284861D98A19AC63D285CAE4A21B70A325B26CDD1D7CDCB21ED2EB0DC6C46D327A2C738A24A7B063BA5353DCA969E16BD13A5C33395107879B5AE8570F3289760E461B03256EBA5E3306ED938353C0E630D0CD3E5BF5D58A2A0E75BBA205D856716604A3097C9647E3BEE8C9198445F70EA2CC9D80790F9E817E354AE220373CF64E890A4B25485527EE05A52A0B23201D72C7B99E0EFC8DC08583F55C584309EACFFFDAF0480959D9049FFD71AB90018319A453A5C9D17A74DAAB78F043ECBF06D2CFF30DC0532AB3C16756FC15243A42F88CBDD809F71B7821FD6BB1E2A2F83201C9B354214509C3F775BEC3A64C915E825D7CF9CDA678084E7DE4315C63A71B6CB428B628F860925D8E0A97376C50540F73FD0DE674991D9D34912E2654411AEA1CFB79EAA29B1662881FD425F1D87FFBBA0D6C89D90F787DE6FD9B30EE7ABB6667346DAFEBDF38FC6020846D3265CD46E428D3696E3ADE67E80FBA8FDEE231E649919BE95142C546343AD80A45B53CBD521EBD9523ED7FAC9A5B1E0BF7A35C8A0DD981B12CC0E523287051C5318AE81F7A9076F93E8F98C4E9D2864DD17522C69BEBF5E111BDE14DCF2FE94EFCF110C9E2AB101C763C35C9E73C800B309802609F351A50B3443C29C0ECADC4A3572102CA4EE074A4085B9C174B2D1ED5A2755BA9126946A08256F4D60CC17EA9B32E0CE4E48DECF66CE73910112AA03C1284243C399624B548059A85B466499DD31AC307E3351C17D702C4D569BB943FF814766F2FCF3A7EAF10CC7C52A624516CB2D8C2AF6ABDEC1F63EB1CBDF49D83EE49BB1282CCD374E51A9BA7D7AF86D6F39B12208E226D60CC3075374D2BA7121AF8047514D1B72D94EBC12E8761C47106AD5849D497C7CCD5FD23D1A2DFBB932F96222FF6DB3E76535634AE9A08CD51D394153BF80D40C97B24D4EC65922E1F73ED6618301C926C101EF06863344484DF5868DDA036AF2DBC4D37524A3AAAC2C24EB8CD5E0A7244D1BFCF76057A4F99AE7D4B97AB51800CF39FA16BF90AA2AA13D2BE06CC7075CE164A00133EABB79A381538666E6F1EB2C9775FFA79844584793AD72790BB986A8B07F885DD65D94FB7B201143AB1FA6E2A1DADDB58FF09D91DE9E1754B7130FAE0BDC7F99797107D632107EC893A6D7C7D31D6F1B98768B624CDD555DD7BBF43A14013D46A5A82DF7BC12D405261E4043FA78761E4DC264D06AA157FB7F65074B71C9A7AAF354480740A22FECC99308192BA44CA2824A428041FFF9B1BC95F2A39D08705F8A2709487589704BBC44BC392BEA6251CD1DE470BD186FA8DC249D41AE10100E8240BFEEA72D1006A9EB6C48B69B6A1A3029F0DECF30EFDA006C36E06889D655D10548BBAD7D04FBEBCC2617CC042E9411FAABFD719A67CCF46427D8405820898B1A6AB75B129A37BC1BD90B5004AD0D04B436AB37BBB30D5E18EB431A4DF7B399A641B76CFE20E0C343D0034AA8A469A6D903778F5538165415008C8215872BEEFA9BB4E8908C317BF5ECAE9897A0EA83A61926ED7BEDDEF99999E0504B51E3C8CB5710094F81203AC53C42444E1AA365CC116F25A1AD98B64BD0484B41A72B8D5E074DEBAC4B94E64336217CF0092216DA07B788EF5A17120A46EB88A605F8EDCAD8DBC65FB002D94E0CCFABA093C12A77BCC1798A184BD158C46266900A1FF51EB86CD4FE7E9676411F4EE0171BA7297D02928E2AF392A4A78D30B63846399A26FEAE711E880F9143C9FD970C3BCBF26449D1A9D55A2511648F3CC137C8E4FA0A8BB9A081C2FAFB91214ABAFE66A29921B917FA10CA6166C7FF495B4B4B4BCA4B077BEE513223A3EC4D2C276224F520F4E1CDACE2D0AED09B4D2F1CE720BE73C2BA5D5F437D551045AFB0421C3CFCD46F6B450571F78E730762AC5B34C50127E56DF09C0597DD1E5E96536CCF3BC2F8D11FBC5E6AD26C39961DBD71BCC059C595C3A25E8B1DA9CA21D7FEF785810BB1E1ECA4F6787E74610E06139CD4BA9CD383736D19C2313E0A6CE88ECB770FED979438CBA67EA3110BBA7B0A995A078CE562036C96003E89B75DA4B57ED4F1FF07F2DDAA2D3949F18EF392769582149F330C6ABA698F95CF773794CB1C69DD125C86D60CCCDD1CF0B26FDE3A6D3E85A6217A28CEE55B7649C3BB316448B9BE66F07D94906F88BC07F432C5A4520DD9CD2326E05C04713A357A0F042FD288201335E12522014F46B9A80C65CA480D552F06838099EA2BEF3C216657B745929BCC0918B87E213D912984C3D6CEFEA9A29E5FF8B318949BB428E1E8EACB1A2977C3BCFFC1B87C2EFA4EDE71D7037260179F610D9BFFE74FC54FD3DD3C8495049AC1A0813890FDA92452AF9BAAEDF55D1718E08811B8743B0A93AE02201141C8F1054C2240E29CAFAD3F74E950D5A147D0F9F08E5276F3C722DBF1AC4BADDE5A4D1D24587C4C157A39574F82696371BCBD45A9A971E774812A5651CD2EFD6135AF858044D67FED42E2CBC245B29F83FDBAFEFF1E9AAAFD813E666B4AD96E8DEB5E47C7E8B9A04FD82060152A9CDC8F6F52D1C6E3AAC369BCD3C25C894745348DD105E860805C3B84EB4720B5BAE03F460FC76D5525215248ABF8F760F5C2BF31A7639C4AD6CAF74A39D17FBAA0FC0B3BE2C501DBE392F62A13AD3F2B86A8D473A3303CCF493734BDDA126E0B8FF308893C0663B1A9621AAE87467266470B0432C167ECC23804E5C9728F0175A5A5B219790B90FBEAC7B832637E7007005EF5D485FD3B27DDF3D4EF60B649EA09633CDF8F326B0BBD5D986ECDD22DE21E10C8EF06377351A8DDE8B74A606572F86D0A4EAA673A1E32C1C4B7AC7EF5C4D321E7F5679298E6966874A9D5D5C7A3C09BF84E882964B1D1081F1DC3E910FC5C3BD0D5B12548569EF6597E23E780852C4F3C897BD5693A8F08206DBED56F8D844505BA620769E98B720E9745C6A9CCC2A44ECE863AC465ED931C199B50C0C7974745EFE73E4C88482A9F49A3BF0695C043AE7695DEFADB424EFACF951BFAD7913ABF49E39F81F3DB5C5CA74ED38196FFFDC33667120F1B78C0AB393A55A0FC569370DF0733D108DF7011EB1A79CA920DCBBEB028BC7065A43DA5401006F2759B7EFD9F6DD8C8D13CC1E47F2CBBCEF625A1F897204383C8B7B61A9AE7AF0A846868263A12C3232E0FD6AB1ADA5F7557A10D424CEA73D0D28254C0503D6F33BEA4A3D8546B2CE38F1E043D00BFB7C9A6796BE7D01AEF65411C6B1BC36F7DCE5C95245186F748AD9016C464C6658D4B8D633DD6EAFF466811EB7100A96E14E5442E32B46E33C9A49698E5B4A5C0009C8343F97ADC8D7EE5F5BED492C633FB29B308FACBC6BCCF479A7F722175D5CF60186864BC47BED2F24A2D57F16053B480F24298411968C3FFF2E737749703D37C29AA0B441D30529A623D8364B56B62B4E1FBBF775AF0C9CE20D49E0155F1D1CDE0F886ACA2B777D703FD8CA441B2501C477C6DC3695C683723D6E9EA9D5700280FEB6B5D8B557E7508A8F7E24B1E2ED5BA129757FF21CA11A62E32AB8A3CEE6CB7AA07CAF1ECD92CC3862E1E5D842B943DA0BD8D6BB32A17B18C05A7E2803EB7C4DAFAF707DD06FE119B8FA54BCC9E4EAC0B65695793FAE2F39FA8A94EBE28AF507DFCD7ECAD6B1F41A59EAC851CACB399C829CA7FB62AA250E1F53F8D3ADBD6478D672B83414056E5EFE9AD830C0571FA20877676B2B7AB7CA774FC59631F861DCA20182A9FBF400750032D1F87F29A04EFB78547BA0323F4B806BA1CE7FBEC4DB349E8A744975E4C2A2C42EF040BB1B359F76791361F0FD262D35286EC8232CB1FBD601690D82BBD64394AB8D4115067CFC5CA4B4D0A8077F514C18AFEC06CEF96764702431347BAE5C020DFDCEC46D34F2AB76AE4876A3EAA10B9E0243869D0EDDB14ADDAFD010EFB8E1A23DF667520BCE3761C04A3A025541C8B46D532860B9C91C989F195F68CB873C9F203EAAA9184AF1EA0E1710E889EE5171F921EAE4EF17BCE3ADF04D2BA551BC75C891849AF75BA972043997ED8DB4B41A31F17A1CA599A63F6987D98ABB58E857AC7251D0F53A8A0648F57551CE55BCF9B57BE4B30FB3C8D0149AB2C8CEFC203EFE9F9BF4E0C0CCA4F3A283B9F92527C90BBCE0DDBDCC4BF53C8DD12DB26CA06025943C0149F7193A8856FEDAE8150FA76B1ADFB458E16878BA30EA977E6E63FE6EC1469DAE0E70928C7EEE4A6D9F3846032A7D1A3E84EE6A9E67F05A0E75B1418CBD48EC1C50A37ECBF187F4D16794555371CDCB802D1A9363E1A904F27ECF0F2965A2894F8D9E3B81A6857D30ACF95EB4925D9165B1A4A282939BD90C84B7FC61889707EB1286E903D842852128548CFA0FE226FFC4D10F742CA43C4AAB1121DA2C72B741DC69CD4F88B4F6EF19A7FBBA3892214325A41FED5862A849F12FAABBE5C9B08C1AC40E81F96F50104CA77232CAE90864002AD283A3C8FA4CE5F45321D2416C4B9A2FFD80D8FFFEFCD053ABD4F39379CFEBB4F35FAA6B5D9113FC026488084EC8EBA7037F3D36406AABA806A5F1583A34240420ECE6A26C7FD4CCB4E793142F3F61E9A0E8C45C95B3235D656E00C0EEA3C5140A6EE1EB38E231EC9E6645F099541F7F3B0BECEB30EF02BCA1D9A018458DBE2EA05FAE791872BED14ECA2CB760C79B9B41F198B230BEC0B8471A6F957929385C97BBB0C16AB251408406A5AD1E27FB7A6C8CBEE3F01D2858741EA6B3846D50E725BFFE5AD736A0D3460BBC0DA4B979BE335664CCF6A6A06D75D3DE96546D039F5705A70B93B1AF8F4AD24E30ACAFC8D9E9D4D94A0CEF7C5124D45ACAC2FFAAC6993073BD5DC42BE562A73860601D800D657CB246D0CFD999065B555426680F083D3987FD712D961294EAE4926D068464F49AA4542C93A37D5E71D72A0B8F0085D1B20915C4DE865466A030CB4965193A37D92D9563892CE0F4D1069CE808489B484A7B89E0B8641E6C420AE05CA5DFBB8363FC5A8B51890C40D64808525143F885AE09850F70613877E6D07974F5F4DD7A9194A578B2127D39997F36C52A4BF7955908F323324C17ABD7F267DE60BAC2603DED6EE833A4F983B0088E9CDE8A5B168F9B94118E0B66472AE9EA56E3C1570E3E01E2E1EBFA0D3E15EFCA7138ED5B20F8EEC4B051220E1822FDDB191E4A2B815A472EC093F7EA6FB1BD7C3544707787F9CD9A47BDBB90A587E3BA33E8134875C9CA747D2C1BFA851B79C3087A6C7F9F71F64D720960086F114E06A78F2012B773F4964A9E5953DD58DC02FEC57F61C9683F0FA8D2BD73C62052CEF5BFFD2C8AC704C9DC063222B194B0A68D7E32EE8A7F2C83BFF4B0274FCB4190101DAE3E20F3999756E9F05FCB0313D31266B10E4326ADB33AD06D7FF5D22446469B3602707044EDD88E013411FBACE4E52D010508A5D30BA39FE870ADB67E78777E2298B609262A7DA5BFBF47D435C8C23DA26E84AAF9DF9897EB969500169B13BF21DB06E48FF92F8759545C7FD758A8B2192C6551F62E0712B1ED132528FF8113DD9DBBC252B126B4B306DA6A56B8E98F8295F554A5965292E844116976795C9555ECDD5E4B82FF40049C20B2C21E9275366CD7B543B4211C9C375E03156D7A0467797003026F2FEC91FEA10D6B7BA441903DC493C4C13D305660731ACF88FB94D1ABCD406D6AAE683A6D4AFC152F309A05A1A75A9F00DC317F37ED21FAFFDBA54F540B05FE9CCF29B70DA164C3BC07AFE2ED0CA375801D626313AD258E08179DE786631257D2419E258D6F0A67AC24FA41781656EABEEB95B3527401309C0A95D8ED74302E055F7BC739B29CD75088E544A29CAE208FB2B24473B1414ABD2838B735EE25A24DAEE5DC0BB588ABB3EA64AA54D0E271D4D005DE27351DAAE12FF984829ED0D88ABE76139D36F7DED50E0DBF20A290482A72C300B3F9A24B6392A048CEF75DE249D50BBCEBBBE4810E2FB80B5C2C8473F66EE062FFD9C52DE2825DFD6D6814F4CC3EF2F33A4D4944819700146650584D22926865C9AC293495BA44D180941D50A368C3AD90716CD7AFDA29BD9553A8ED18AF839752AFCF678E8D065BBAD018556A062B618EFE86493E5A8AD7B0D3325963F510B136A7C6C1D32A04B7179F6D4A54E17086FAC83B18F0841E859549E5E40CBDFA12971485B0BB197671E426DEE06F1C2F01DCEADBCF42AE607758E6EEE878341F07ED6A7D6789407FEEE16BAF2EFEAA6DC12126A8FF244EB990996901B9C5C0D8CBF3560D2FED7FA230FA5CFBBA9B1B0F30F0AF8E223D7FC290CA55C236DB4540353B659EA77BF4A1C2B61E3F6F67E2657DF94C2259E007E9EBBE3BB95A69A11169364D623FBD6EB3E9C297AC5E0E9BF079B3D6FA2818E8323737B66B6AB19728253574CBFC1265453D32C3F541B2ECD90FADCB58063F89974C9A2A2FE53DF49F0CE7804DA601070FC0ED5B9EB4190EC8839B485506E06A146877E2C7A45A51A3454A9882547BB19C89A26A9071BF996362AADEFE9EC0827F04FC19FF3258E3FE5EC9C6AE43E8B5ABA1F2FD6423DB9F0CDEE0CF2C2C55979CC5D4795A4741748A57703F59D129A9BAE9CE6C618CDFDBC75C8BAC1C1DF77CD58F9376FE49A96A2542F580FC8441FE86D4614D93C65BB75E32A780EC42036CEBC81717E61199ACEEC32CA6C23820C645A0BFBDB76AE88623716782ED305A2063C5983C1EE4B197F95C525008B46061FBEF856FD72D4B85A4719963FBB27512599EA8D5872D1DDA358C209C9E6598747A52697A137E72AFAFA23206A623C83FAB9EF8E478BA77B82D209D1E906E1885B3EF7F89AAB24F414D30271FBC82DFF2DE8581685638134FE229D95F5EEBFAE35E86A4A7BAAAB24E997D2F4BEF15F6A54F39DB6846FE0FA9C17A1E0C522A2F67704E8FF27A5780C0B4CE95F938160EF028F09714B62842CF3074FA163122DB0E55CC6243D95F79CC8656CC625BEB98FC9A0D6E69925D077FDD159F949F435BE4B3842840FA6FAE85812C3994B5C3104BA07F3E70EBA8434BD9687B481275BFB03A6B6AF0E4F6E7BA26C6C21C3E6E4CEC70C305A87450A68BCFFA3DBCB76EA8B7ACA08CEBFB1715DC11CF1DA26F3C21CC8F7F6F867538FB30B5429EB9A700FF4D618821B1E8C02B90F03B8B559B9CED365E62B77EFA2ACA289CDFABF7484602645EB8856B204DDF03FD56A54DFC94DA1A0A68400EB1B051FDCF30989513BB5010C328EF535514179219031D9DB5DD71A934F1DAC9D62AF1498916D91274CE8F28FD04289198ACB90AF7A2755D2E45C93E17812E77AB33BE4BF1875BC2DFD14069E5737F2C0DC00F52166263C2DBF1F5A91349E6A975D96D0CE08B433C60A1BFC7C70E64364DA2F7BE9393AB9403313F92F6980B013023987B4E3A5AEAA32E125E86D260404771CEFD39B39D42BCD9A5B5230B9EA99C76FC226893CC33557352B0D31A8D34C348C1171B09F3BDE126EAA71454FE4DE046FEAA25DB29CD506E9828BEA1855AAFE955A5B62DEF708837449A6D2FCB7EC2B717A5CB4A813FBD1390597160BDBF05895EA6239BAF1E64A696DDCCEA0E5FF1F08F64742925E81FC6853F0989F468E4B21DDAC04CABF3FCEFE77AF4E18AC5ABE0D3A3BAF1472CB777A00B67C19FBFE019931A07B8D90BFA2958DE0EE9C251B6C01F3F9021589F305A7BA4B0CDBAF82DFAA1B6DD5BF9B7C0943C6B36BECD7E359F041A13B2D3C49B37391E0B79703851223689E9335A6F9310938C13430EA27710F1FFF42AF4ACDA9AC8CE5B83BBCE77B9C5CE769B8D3E59B22492D3069C918E8D6E0F4FB2783FB5BFD13F74596D038A1ACC2773CCD06BF132C8E73D05B0F34BC5C02E3D6CA08E80D817D2621CE5D53ACC8117A47B45A4CDBFF6BC5402CFF5EC6DBF5B5C73B89426D0A9EA12CFF896A9DF3F210A5F689A299BAFCED971E91569C396369D307673C3E46B9F1C8F39D48945CDFFDDF5D4DDB82B960D3BF334FB728C1A16B96674B049B5E5E22A04E47BB6A86543EB1660F664A90C412B9115CBFB33069412AD2E29822B1D2FEBBA6CC1910B71AC139F813EF1BC2A334F90DCD60EBE23FB896928C4C73B984A8F3343387627F7E8BE4AFA2B85920842732CE695832DB2C458DF6817D72FE17E9E86943DC12C2EC900967F79A807417740886D2B0D997A4780A84BD9F01E0D434EAF8B8A383FA83016112C234E9889E262D8F2F30C073F05F74FC08010543F591904413ED0175C07B260C32CB5F831DDB0CC4361D1AC4892D2004172E1761E594015F0C074968C1EF13F1B1D48A91AC4AA1F5DE125CF8DD8F695E1677FC90217439343FEE3EF7FF9DB55EAD0401755321ACD9704BA9525DD8D478BE615095EE36CCC3DED9604216103C835F991995FEDA1464D900852AA0B905EEA1D91D42E6A96102BF2A6A23CEFAB6BFB22C42E830A631ACE2C643E181423DD175314FFD4C2010B6B738407B4ED648741FAF1867E567234253EDF9A3BE1B73395461847F6B6ABE68E305D5CACFBD60964E15F95798529A3E1029906D708F12FB302607B73DBD0C4449914CF648B199B8CF165471C1F1E4988CAC8BD72FD621438620D40BFEFB5FC3A597BAEA133FA8BEECF21BEDBDB94068C537CAF47C433553DCB2C6046045A3C9C8199A8706B183FA8A989D0BDCF759105F63CFB387409435755699BDAE368DB182F8D2567E9396C5C3BEB8351480AD21FA93F0E827CC54CC5B63A3728D294B8910F05CCD74E7BFBF9B49A55BA9EA2F5D71C1113702207F57B5422A9D4117E12E162F1DDB439D291CFC2DE59DD23CFDFE04B487C8B4DEA8D5BAEB36E1C32A0D1A687C0BAFB3228F80898C1AEE3078621D8153AE7DA30909B4D013657568B0DA6633EAD36E6562528C72E448FCBEB2A5D09C77290C1375A88F4116586A065BF5DF50FAE4F3D0B8AAE1FDBE1EF55A03C80FC712F5FEBED6AD28C54DEAC5033556AB883C908494A895494F299AAB56341010686E5F2DCEF087C3CDDAF849186672B01E62776211E103D0F6C7EAB3F30A37AE02699621293070980EDED1CB892BFF2E46CBD1BAE59CBF112F5816AED97C1B6D5777818802832C5FF02DB12508D4B7A16E890A0887C2A8BAA441F0F2FA1581308BB14B7E796C11615A6F233DCD44161E88BEEC0501602C0870160AC6FBB924CF42FA4099AFE5FCAA41382A654297697685C1292E1F74E8A21F68207BE7AA5546058BD7D423886C540BF5E7BABB319AC5F73948E1C509F5EBCB64998A31A1B83F14BB09361C59B951DF8F0C3C4B0AABBE0939F22B5E046EF5E9500FBAC3F6E60D9798BDEC35A57C106D4BE054AC0EE6693387487171CD4B318FD72A5043092E365B0142B68CFE69199C5A101146A3C5F582DAA2691CC42B393D464AB7D6833D66D178EC84C3BAA2D9466F8918A75E139913641A2F5CC5DEC4DF33742C580294F40519FB480807C7CD163938FEBC4684618CCFC866B9E37C0ECA2159172680304C11CA394B704A15E67EEDD41F6869C98CDB1BCA10E0C5D48674E6D2B6BE09A6F6727E30C453680F874F85A1D53A4BC35A473786D0B6AD62760CC240D08217D344C02443D7C7D936ABF4DC8FD0623861A9BB31967ADF8878134E6CE6F03479AEEF55C34954D1243C4185BBEBC3167637B4B22D65693B3253EE24E204D585533761FA9C51C9071F0536485F0B135AFB9A9779EC9F3F0A7965ED94691B5E42DB0F21B42C4325B724695CA6C6B4BA699BD53EE5D5E36B5B20E5ABFFFFD5FE8FD150694562A457B3B6942F5BB93CAC8B85FF738FF502C54755533A6CD03961E7ED49BF6D032E64C04DA36645F2F5117E217E590699FDC8E67EDF9140993ADEFE0542FAF9FE0D2CEC33133E0229A78CA59E89DFAD8F5DD1C494FE89068A22B92BD9AA17C39EA8D23C0618E6579A9B9094BB113B9044A8C19C1A2C21FD0D7C08BC4BCE5AF2E9877E14801DE1186B6879E487901AEC9D603396450E78E22707FEE7B7AF645CFB7BA1D24EE9C6489D00BF114C928A26D61D9DFFC3B9748B4B23099499BFC2E1E620E4878DE470AA4E28A13AEF8B4411F7ACADB4E6B726F6A974996B5DF8E0E8CEC44B1E964CE54229ED3433F181AE572F30DEAE1CCC7CD41D06573C75D097657BBEF626451BC7C43990D08B9BFC2FF473877F16949EEDC4FA0F41754307A3F692A8F7E4C3C8457A94D2265B7AAEADB301D38EE01973C7A9EFC759177B779C26B0DB4153D9777CC323A69CF34A3C9CD3439AE69FDFD7155442FA4EE884536A5EBEB40D44AF0B2B20D746A548E53B19D419E97F78AD2CD95F980376C82DDF0101A226A9FBA8BD6737D386BBABB10B3032E0C22931856A599EB6172FB3B3438F4E83D48E993D5244865AA430551551066D55D2EE3C9E855FA708A13B4841A83BF3273D82B8A851EC72F7E9FF6DFFF925E37BDE000592A05736DE9C8162846EA4F8EB4EB152AC8D0B87D3F8D86DCAFB93FBF7ABD7B80EC1187A2750B6695FA48C1F4C5A29BE82E02EC8736575F3C6E64C14D6CDD4C7198F2858FDC1EE39B48C9656D0D58C7380027655C0186593031934E41248513B28421912A59BE34CA2DC3345F2E8EFB5A68450088A9664AEA23376B07E41784334D844284705220E9C87939EE688FAC05E7F6738BEB925C23EC4F08388C0308B2A482DB983CDCFD438CA48D7F27B9510618C5A1E05394AFB0F42D62C800CB7BF71A44BD6A1EC2EEB07A6E487CD35899AC25F7FA95D54DE458E267753A9B7C706A8E98AB66A7F6F5A751296E1E611E9C9D616E1AD09A9BCEFCB8828F62ACFB99C216E48B932EBC83F93C08FBC92EDCE2EEA175A210D00AC580642D4E79F9A670D430DED4E267DA0E8465024E67E6C0CD7AAC46428A42CA1FA302CFE2807684EB373DF6A1448974AB7909CAFAB0D52BD3D5639CCA39EC0C0E88607C3EE4C46F39B0DE285BFBD7161952AE45CD0AF1F90D01859FB3BCB7ACC80C2C95CB9EE1796C8B81CA9A4A33D6631076985851E7CA001C6C3E4916E9F26B09D1E80E50DA60DDE7A0A01C72A68DC8DD5DC5E1B5DEEFFBBC9F9C75B8E7976EF5B24DA3FBA9C7E3246F01F7D8AF46D6715427AC4858E7538A9E81C3D5A85DDFF853691080872F1AEE3135F200D4AF9CCEFFE030C89A3C1AFF6C1FB76183FF4A441314272A23BAF20D4A69392BFEB520C05FA94931D3B203BE5A828AC613936A90CD0EF22AAE21F3606382A1FB962D6FD0EAEBD10211FCA4CE8F35925786060DE68BE08A4E7CD4C879B4875E2BF5BF9CB3DC5B1D7180D7AF1E6696FFEA9F56120B611AC622C9D9C8D3064F38F79B3E56F97A6EB6753B2B6DA6357DF1A820F227B51C24CBED6A13C5D93D2623510871752933E9F04E3634B25D263DC814EF21AB60F63F9A6D17AAF9B1597E0146B1E09A4F38578D47B3448C1ACC90E2BBB33F31759F049E2749A5E0472B5E1F2405D21E26C22E72C7EAD8E0049731F17E760B0CB356D0693C46157127EADFFED635DB05C912B8A9865540884E7CDFD5088AEA54E2B2F924A73ACAD2D80CB0E91766A318AF250CC280CEA8219FDD47834AB29F1FB2C34545C8C9363425C58A80BA74B7DD2A725958149922EE0BC6E89E8DE0A12725BE59D5F6C822D9C563CC56F96B800D0F3416855B098EF12CA09AD30CDB7EACF09C98FDECC1D34954A5F49263DE4B5F46723C81661F0024E84BC31244161121C361C0816E89F0F2CAB57B9673EEEC745E022E52364185FC959329D1DF7C504C800169221766D193B1DCACAC294B1B03A7607E7F1487F256AB3AB103C05E14738DFA81D090ABA55F3141A0A4A818AAE104FC76456FE93D525CE50AAA82EBE1BD416FD3C2EA1A202B2E470AD46D51C658132296408831AFA22F6AF037E1EEF879DC0508EAFEE1486FE120820300AC57020750144EAFD221D476940622889009C7214EECD14496CA8B12BB3020092027FA45D931973B0C7C4FB866B4E679FE28077E5504935546C920756C2E501BDA6AD0C99CD7C3BD1CE7F7C46F36BE4D80F837195FA73336D533E272C2EB8852A81BDA812081A793BB5136977A5D8FCF0755B6CA7BE34C24F21441D0AA5EC099BA46DE009464BD2D4257D8B2C7CC3308086B34EA88DD61DA2056F9F814C38D11B97EA72E9AB7603CE379AA61DC77BAFCFC878699FF9A8685919A118F9D0945F6158BE775D46DDA996ABC1FBE36E4EB3E4111C80D701DA2598583452432E7372797E20FDA9D136A12F45B5FD446DDD0FEBDDC6382269BCF8946D5B69274DA68F58462482167A8063C47930223C82D91C69D70DBF2A568005F709F86D0A38C52507A0209A04BDD990D30F7EFA2E03A95CB82BCDFC91D89051A006304A3BA87C3B8004710C459F13E0A6221AC32E52CF9F9EE758525BA82BD2490CE1031EA22FFF38748107E6233787BCB702E1FF4B338C983669D502852535A9B0A7928D208BA4C6FC654DF2EE8851D020AFFC4D2D82009D10F8DA8D1DFB25F059E9222BFD6D68A8F86A08BC754B3D86E72A43854BB5A02F08695EA6DDE7F5AC2D64F5793AAEDBEC3641C5D04D71E46FE2CAC49D3FC4498C714D5853DD27EA946B9379D4DEA820D9F5873AFD64522EA725701A5C08A7FB8C82418CF2BC466212302E1438459432460E9EA4A3827D09331A7369651EF2301C1B3BB91EEDA1B1A5CC35B8882B90AD80933416B6B4DC2694AF9D290715C6B4CA220549F4E788E6DECD2B466DFA741754477CB439415326A59739957E5CEE98D68C04C27D368F5029E9D748667D6D791441B6DF650928715DB3691C803CC400B78F0CE9E6118358E7771BF2E5EF903940D7950ED655A5871BD8FB2DF74B7D605183741EE853DDEB60106C0EB66CC00A0923BD67334BF6677F81AB5F44D7AE6B907C04006FAD5F948B9076D4D0B73050D5323F705A06C66C00D7ACCB1193B3A564571F3582F04FA7B7A620E03571EEEF5265DE265BE3B3774687B20E3520C7DE184DA9EDC9BD790C1E6A1B0250773C35E3DBE1C3A81A7AC3303316E1611E9FFBA82A033BB0F1A6DEE083CAA5107800299ACF5D99EEFEC016A13028A23EF334C0545075C2B01DC3792D1147CE5F023C38477978B2B975E18CEE0D73433AB6F509566AAA4D4D54CFF20AD9E0E385CE00EA3B21014D3C498FF76C0CB805B56BBC443CE957AEABC4643A3B38A1CE068F60837024DE21EC905D105688777C3330145A23AD0BA4A80ABAEA911AC20C635E3DB6259D3DF5D06E08A9581C071140AC4DBE6496C9C57F9DCDF1EFD335874D896F12CE147DE29DB60DE1E9695531A1FF8D994640E3A1EF40CB3B4F86DFFA5819B8F66559DACF7256D90E231AA93B55D6954BAE2154698806CA5B1870EF41A50EEFEF64AEF570A3D597747C753A5DC5BDE9681126F5B38EFC3367CB7F20DCD3E345115B0147D02522997E9B9D646FCFC1EA8F1D109C729E5CE111C32018FFDF9D112D750A224501687BE24CF4B64EB984DF417EEED793E35B18B0B3E65B8FCDC2CF4DB8F40B45B59EA7589A6DE74431A029AF5F6FED414B5046F89DB869EEB3C91DAC0FADCB2930E8185E669BD2CDAD620660F205F3CFFB8995EF0231F2285FD622641DDF4CD96738349BEF47745A9F40B835D6FA77FB3CC3583963CD5B4040993176E31F09A50A6508E0273C1D88BF6D4FD40FFDE9AE9DF1FD3BD543BCC5BFBFF681D681EBA95861A74FC56A504861273EB30DE82BA53F22CFA072EA2722D13EBAC68A53895E3DA95FDB03FF0C30D35C061180416BEAF7130507C8D3D79366C4E5B13751A0009BE59BD3BD406A99B20A61AC1939D509FCF3584F1F05BDD476A432557DC1C06B933A8D6E06A86B7D6AC880DF15A0DE6566DD57B6913BBF9CF27E629E3CD6819603E9F018165021C0ABF3ED33EF01581E7A53011E11D0175B71DFEBCC884800CC0DE13D028E49B981268C0379122AF2371E4F54977269729D40E0AD026564A82B0175AF43AA52E9B8EDD31142BBD658884C10CA9CA2F87CA1D359D95BCE569C98AD8FDD60D44F4315E8817A7A34B8FED9B758287D4C6DDF97C4828DB2887B8AB88CD43D2B94FF45FAAE509EFEF6617A02D435734957DE48E79A7ED4A4D65BA8F0B3A647C6EFDD4CB47BF56A5174BAE02F4CAA5FA624BAC8E6AE4690EBE35981F82FC086C5E48F71E9B79058BBF55D20FFF79EFE85DB6490A4EF3DB576A85BC6241310BA80F4A5FAE3BF89AC1A8CFC88DF9B3F8ADE49CF36AC092BE34A46106C1F09C9566224B055262AB04E9B4986C2C4CED982D86F9990A1EF63E4FADF98D6A4B76F9D287F6E1A49C26DDD51E091796FB75DFB3B58FD4BE92BC803A843AD0F3090F7B4861EDAF18E3E71BD23ED446FCAEA40B3ADED9DF9CA78715A771DF8D7B93CD097CB0D3C3EE55F542899BFB90A8261BF934E6050F422B1BA2E33865BCA862D35C68D82407D01237425A96E87FF3B967605E2B0318636FD8F90756B73BF06EE361CF30DC72F82E3BE082DEE3FD5EBDD7FC1206F0CE31D4A4CC598C0B11B8FAA0D45BC06172E74531F20DFEC8B8D7C64B03F622C652D454E5E1B81ED67B42F58B7611408D81BBC8C5AF197D2AFB1CBA0993E1ABBB7CAF490196979C7E2BE5A6B0911A01DCCA69865BF205ECA52747D70C2F763D093B99E936A8D48C6863F7D014D883BB7BA83651E7951D40B750D65936499EFAB785AAAA9E4EA8A6FCFFB795D8A8B160AB1BEAF25C4201EC72AB4CE851A9A83A86BAE48EA4110A07825C7D17F1B75F0401CC2AC94D8997136166AA13A463695C0F05965A76FD21C108C8B5100D1B4DBE612E48B84B3F3CF0E4D3E0AAF34849E3A99FA9670EFDA7D74671300BA7C1D1CD9BFBD4028ACA51D75609535F393154E7EABAA688F281EBFFC7FEF85382C7071C1783B4112066DB16E1CEC144F93241635DCBDBDF234D0AA3A86386540920D523DA29D328F2F580FB8C7800A42E1BA6CB4A9593B60E4E5B7BEAE8367F580B97FA916EE9B88E5869F57ECE802C7003862D5C3FCE8268905ACF618E17B3281F99B2D60CAFD011BFEF1D636E803E4ACDCC1872F80E57EC5AA2268620BBB25B22480EEC68038430329E17801730EC9D6C60FAACA3B44B0F53AA7F8A035D7D5A71309F0E48E32495C9841AF74027AEF2F646168FBE8D586530A8F40B25FC8C5D0E4371DB2D0185497EE675DF02969CC76A31D4AC5CB1C3D6759EF4B89CF7C6A1DB2FF0B7EDF1BAAF11F040DCBC9571967159793A5D26053BB8C0F6491F826BC4E69280150F31FD2908B419655DB36EA7F07094A2D42F75E3138D1B310E0F336FC7F23AB33F75141110EBE50E08BBC4A1148AB4DD8372C565F89F8A39F6F2DEA0DA13FC4A1BABD0412DC2B83910278A473EF6F9AF69EE8ED63EC6C0D08D23947BC10F93524C9A32C021B7F42E0D2227C3882C2DD9D3841C71E60C597473A2166791BCE86C0846313C96435DC8B3FEF32C0336ED624BAC6F51DA281CF59BC84DFAFD7CB1C2EE6D2D1C3D2DE2079A7EA0C296910346E01953AF6896E4A288694598E2D979CCDDFAE9B04712011DA438D34CF0E49406940A31D99734350EDD66876DA320F8FE5AA8F1961F6E19FDF1FDC7C562658AF0E5F404FF5A1A0774E053F44F875D3F6759D17414638C70E97C84EF27F3164DEE33B549120C85B2C0E8300E7B401BF7EB6DF222EF9F06D424AD3884060A5480D39B67C175A18431D5A1D25BEF34E5549A305C269A7CBEEFEAB6F30F2A470831C70818CF385EFB368F753FFD0CC41338C425ACCD1A40BDAFEC2B81F649AA03058929FA0D0E2AE93B4FC6D87C7759CA9DEA8F0350D98EC12337096F3532FA02C8618B7D554A789AD9048FA84286B80AEE2E7EB60FED386BD9A0687A4B9F9CF893E74DCAD46E4E1D45CD40F01FFDBB190DC6B357609F7A246EB61003AC0A37CD50ABFE7D0D5291FAF560E3320B1EDF05B058983B2DCBC2703CA185C02D5B90A360FA854AA9149FE091CE01F2C08F0F0F369CC2300780F5BD4A648FB8C271A625857F1CFEAAC396734BCAD35F40012E89EA6F66C184A7B309257D7657D41522D79F9C5A85C5DFFDD8779601593B710D105F1D746400C8CC03094A39222A907A9D296F5030DA201FA44A0B73206BE90031E5185DDF9AAA0D2AFEC5A377CAD76391A2A22337CF1E1B6BFFF6EE55981A7343AD6C800A1A80B0419059A9F44050FBB42A4CEDFBF040589B4AF75C1B80E2EEF0126E813591CDB2A2E186E76C849D5F9108D98DBF2EB0B78A87413DAE8B7048B96503974349A52DF1452B5D91F8621A9FD21979D39B4CA2AE97B44B38FF8E295160F6251C4342AA791D332155DF0AE61C8964FC1A0B249A5958994A9F487DB0DAF95C371B07030DCDFA7228F049B3A3A428E2CAC5D509E0F79078FFF678FCFEBA32EC41010108FD0C9F3910BF6B1BAE47DEA0A3A2A00DDD3A3E34414E969BA289587578152F61B888F56974254D54770D104DA6FEF65BB903D00EC8AD239D4ABA6A2043A274EC4B9F7B9EB636491C1710380B3D741CDD606E5391494675008433F17D5C8049C840A13CE20ECB583801D198AF925F3CAE512909EA46F8069E6BC90B561EFBFB315087CDCD964BB8F8019848F834D7016452500C31CB51A85E8DCB4FB440BC309C943898F4E0A97FBC7414275C11B6FC422F2EE1A78AA0247D7CFBD466E44EBC66D065E23C3D12FE4FD3006F753827BD9D97F5B1D01547778E7E5D146180C46EFF50205066EADCD84702937228533616D05895F364402EF942A54068EBC77C3EA219125638E08606B5F54C7C4EBF9B9E1A5BC36A1DB645AD21E68E5687287BC278E9A68D18AEB4AF30BBA20A4B0687ABF50621FD4748458172423182C7EFB3FE9A27D0745011EC9A1268E4770DCAB5FA2F880A30B82F7D50FE5B38A685F892972D1F540A0AE01556B99FC6C4B4F25AAB463B522A1280303F933AF3FF953D92A20E842BFB9BC1C810AD57690DB0D95E174C8E45F03841FB4CF01EC51A1EA6FB5EBAA5E87AEF7F50BC0BFEEFD36EE7264CBEEB4080CBB6E8EAE3D51DF5A358EFBF8F47817A2FF12CCD4805824FA66B53EBC29EF368092B64EA2DE2F6A44C0411C2B3DED924564E207B524B05C67F03EE91DE1B028063DEC0732197DF492A26223E2DFC6F39D9FDA864C813890D0384971858CD8725B3C1F14765E2E3CB76DDA8A3214606BC065644C368E81099082CDAE22CFECFD424768D246F7889E6B6BCF7EE18DA66FAABA5271BA062F280D588BDCB7C6A8BBCE93CA901E9EDBEF676BC05A395E7C7BCB4C3DCC15978ED0CD063CBA4E173A358FC4F38E15B2AF18E750B801BB8B33FDB18AD31B281FBE9FE92A078247986EA6827735F17F3E2F04FBE436C365E63C4C6DF9D8CF2C95421D9E212E61AEE95DEFFE9E1DFFA88996C1F20139B5E95A4D93A179CCE492E0401B14E2396E06EA6C9CBD2DFD37A150BBBEE205232A860A22602E92AF0B6B6BB00D583D3ED5A6008E55A8EBE97CBC0A49C1C9D2686988C4179EBED82D0E2164F648A9E1102DFB79C3A0732DD3F8ABD40F9EA01ADD223E8CF85230C6DA96653AF83882766D2F9890EC01FB98D8F11DE7AAC8D0EAD75803BFA772BA5FA1867C34E5B937E14BA2C912CA0A6FA62621B3B822D64476C1AA22DE8915C1D08540DE2E9076A82D44D4054894C20007E1280619BB284171D66696E944B045333BD8660A6A571065CF8C1EF83A5BFC7FBFA203499CB24B586C32C60203283B406743C01118F5E78361F036D14CC7510ED991971205DE766530E257A0405A1BF0F201E55B18F0542640F09F740917096703D30C64C60ECB97DD03C2C8CF43023276E527F37114C843D150B692BAF391DCD03DCCFE332CFE51BE9B0ADF0B733D566EB05B055FA8B9598EA8B43F4F43B4138A0FDACF3EEE499D079F47218B0B70400F5868517EE63DC78FBFA71ECF7755D0F065F910A5E6DE494DF2F495A65D86696FA61DC8901F159AFE57636337B269F90CDD22DE004343979C5A97C33A189BB3C15A26C050DA267C83C55275C104F0AAE82558B4085D8243CA28A0959A90148B00321FDE5B86015DD913876F0823F385496EC4558463696F5A69EEBB09864A93A4B821D3362F5A6F54D355A1ED8647C00392518C8E846575FAA94C5499635A08DEDE53681FE2C33F8FBFD3DBB064D9533FFBAAD4F653ADDC9C2F5CBC6DA585CE5F4A3D02368EB33E1B12E2F1D10B843C119E38DBB60E2221758F9F6B1812D1C2EB74F751EC04DA55416FF778C63EADB9934E831D01234F6C618D8B7B5D2559B15DAC8BC0064DD16F61B73F372732BBF0A8BB2872FD7F9F8D45465BC1D51CCF4BF40EC2FB11D6F8A2EFC690BC14334191EF4901604ECBE623E5B2A98BD39AD8AB728E519BB90CC936D1D5C174DB5FE4FB728077CC6112C0A772020E3798A4108653D4C7C1B20066ECDB8AF597C38E80160A94DE7EFB28927B5F5D652B4FFBC658857928CDD6E1D93D30A7094FA25874B71F918182B67D607D13BCB39CE47F987A16A0FC37054168082F19F49C865B495B31B63424BAEA16D6BD66084C8B03AC58D22B26D518B2B5DEF7B02DA15EE2F78F969184186A8220C200B5305A1B35CC07AE86A47CB4FC1A5183FC84F25B0F9FE782017C9ECDFB7A2F06F222841A50F91F7879C27A0FD1CCD647841AC3331D9B6A6B836F4FEEC92CA4CE3E8F8F433261CCFB31239E119DE7CAEBF9B32B92818307650150CEA8444BE4FC746457835642BF18DA27F337F5100FF8D6D4262ABBC60AC340D7C53ED23142622BF4C4FA9C78634A2BCD6700BF9EDB8761E235D27EE42182D00E696A5ACD1E641B957E90D1AFE657C8307E75AC23C48E220265A290EDC27FCAB81B149B32C1821A547F250D6323FFB434F4CEB9AA7A2733FC2972873CA532D0DC74049B9AFBF20415493404B7D9A6134946C4B9C3BE5BC5068B60F4B82AFB8EC88092821279AAE7E7CA023FDA49218C08315C609610C604668BB07211912A946F44B9EF425D298451E1EFBB1E9241E24FA2C953924B0A48224923E9249864937C1242424918092259698CF431AC206ACEAE0A39D4287EC1A3048FCD110222021189482422111991113991130551102551121551113551130DD1102DD112DD7FA00DD47D7B3236B3BAFABA6C193ADB9C7F535C9E91CD35D040693CDB099A385BA630CEEE351EC7945819B3C73A94AD66EC43D8623FB88AFDA7349D31D020DF15D96174C3906B82DD62F8538B31D52A5B8056CE6C3ABF777640452C501C454EE55B7247937FAEEFFD03510096EA645720B587A58E22869E41326B648C9A34CB4C59963657EBB37A54CE13F0FFEC1A55368917C4E0BF432609011CEC561F8201799886C26321933EDC1BA6DB8CA0915C7150EDC2AD16D88C5760D79A49FB9B4E817292B54DDC2357C7C5A38BD64F8A9ADF10AF32010094994D5D97321C265518EE4AA49E3F76830F4A836592CE7D54C1AD7640D07964EF70FEF06379F7B06A9AEDFBE756FD5440F1A7AA7F57CEDC9A26753585063554B5B50D15AF49BC98BBAB30D4D049A70AD545A8A90636658BB85C2139898AB4226C5BE08030BD132616A10F1471D522FE8E612AC0C528670093E06784AE4C240608E997904E45B0A250B58BE033A18D12E59B454899E05284D24708E7C2FFEB97CCECBBAA084C807739B82BAB24D0D5F526C35D61EFB240571901089C360CF097F3068234F6253AEDBEF38AC9A9E3EB8EDD0766D31C019D146DB84187BABFD3E5BEA9F6FE1912AAEA7DB2395DB0DA790E5570C5339A1F2BD9F6786A154C42FF9BA44D3D96D40ECA5B8DEAF2B9968832A5E6EF2A69EAA854FF809E6725A5CFEC5959BC268DDE55FD8EB69115D4DF108D1E955BB528D7FAB40EB5393F9B5799BB845468598CC859C562CC473F9E3864BDAF0CD6EC5E164C5A1FEA9BAA001DC989D6D3816727206EA3F0ECA38B0B19601AAE3A11595ECFC7A9EBC9092F4F0BEF8950C65C81F00EEB54D44BE7AD944AD498F377D812567F55EE0BD261BC9D42D83B9B7E4A7D79F963DDE2EAB04E1E2789E51C5ACA97652C689CE784BCD200AB26309A1EE3EC52A9E205936EA0AD1D7DA30C2AC7A134B5C1DA8CEEDCD33639032477E47428BA083DC2407FD21A26BE4145EDC0882E7C362D919D95F5169DC9585AA07016B52318D2E0FFC46073D2D9F75690F16A5753E3B2EC51A5B6416CFC80BF555D60DE007593A1E38702A12BA3F9CA0F4BD30E94690A272BC17A1C15BB7113EE28E190AC5ACC23E796907585120DF0065440C818FC14D6089BF6C99D8A65FE002104A6ADCF659EFEE0363D82D1B84008DEFF6514A93713D58557BE0C1B2DDE46982D8485374AA82EBEC1DB4837F3AC82E133A38C49E0C3837D4ED3A6B109BE8EAB9E5419B1653556656683A1444A8F1D8EAA7AC5731F27F4529CA695136DD37A7727C7A65A6E45A485E613338B489BEE5BBDC11091AA470348002AD67055CE7D4573872D6FD2673327D773DB73C47D4E4AF57B53B1BBFEF29B8103E9B9383B9BC5AE86B4B0F879613B8C4078B547A87855B9E6C5BBDF0574D38F4E37E130E8CD2F04C76E71F285469E3C4C535C1C1B7365CF5C57FAB62007CDBD1849FA3F9F1739DF1D086BF00D8080F066E16169A1633AE5CAE4940083F64B0247A78E6359E470375D08219AE9463A1E688B8C6B2000329038BC8B701310732854A02AC2A1EC69441CDA1ADCC6187796D6059EB92DD96D525B5AF28F16345C41C495C16138F13CDD0185782A3E6D58889AFC71AA241EFC21A1E147C21F8D442E301E5B8C4CBAA062D0EBC7E7601D9F4C66D1E44FEB8FE3109CB566B7DC82D944A488FAAA5B26E3E7D4DDB2E095C3D77FC735795B322F7746E76404ABA3FB988870BA77AFD374C068C8FFEE57BEB0EFFC57B1042DD3C6FF2373918109EC786B9903BDA10E73D7B18D91AA933E15D96842F8AB5FE183BC43A2642DF21EAE0805923E1097FFD7E44D4E636F195FE48501BD5FC97A15962E86EC8E40634E186A08FEBF2E080417476719D5EBD94FAA901D2E94067E30F79BA954C2C9E0FE8F26494FE7B0E8DD0806C6DD136C59EE4F20A2AD921B059CCD1B178C94E060BD17A2A84A14C3DFA319EB22F4018929303D42A4BD8FD9F6340D225983D53A98A710B3E523987190E5735FBDEA624AA53DCAF03DB4AC3F9CB6F4597FE4E405FB9C2E6729B37D4272F3FF11491C4AE54F4CDE991F0019739C9AAE59556BE36DC35EF8474E9ED2C1406EEDD186448928FC845EB926CCEE2594F6D7E2016C07E401E8043C5C273450B200786276F8CB378AE40E719150B8DF32F180786AB570E2CCC042E971C1D8C2D79CB165688502A5775C64144679C09D9F6612EB865B09D447EB49B29D3480B8768FEBD7BC5A87CCB39EB3BA2E3A48ACE967F9CC951A420E010379323CED03A1CBCB613D8D08BF17FD97A19F525250AAB73545883274F91F0D056CC59C7090B92EAECBF0643F3C54CB4A47CAB814A29BC9D88B4999768F589482832BCDCE4C8C6AF3DFAFF8315CC9A81BDDD8058D47D3208B9E2342EC414B5C4D9CCB89E54502F7D2587FA871666952F181480F2DA31D7FBBA881C6DF4C080C8A38B0CBF23AB401363EAE8FAEF3E68277665DA06D005730A4BDE16BEC827FF688E75410A9B06B1A9056A9C7904072CF5B53B67F81D7B5ACE59091CB29C45797998B7365203DB8BA2F923CA7FFDFDE49D3EDD6853B4799247126F48376339D8C6D1EBF7FFFAD97BA3A9B9D938C1B342DCDFED7D2FDA2A57305A2CA2B423B15DA6BC2B5AC95D32315AF31312917E7C44A485B3710245AA9BD3DD8FB5FE739C2CF01737B36AB44C993FBB563843A5CA45F0121FC7A99C6E067F49F905089D10ACA3BDE2523591DB03FCC72AF77FF8067DCBC2B1C2A60A77BBC5FB9F1210663151EB141AEE26E189768B46841C28009AAC8B90AC3F52E6700FD577A0E0C140E6EEDBB46AC344DAC0953951488BAC4C6327117E36E9A9350D4E77F5FB28B268AE32180C2926FDCAF0C0C54C43A81575CE35FE5D44E8A117B52A74C295BF38D6E70ACA6CF444286F3D344659811411ABFFD8A3B1860C510EC37D6C36BBFC74D48B258D2155DA04FF11A28D2FEDE09B8923669D90BBB322573A806196E08C1B40070DE6D0DEB1296BF7ECCFD9D3D275E0C45B3E6A9BDC45C0D2E3B9C6819FEADDBFCEF133F590810A6AB9A362D6250D05F07BA64FC1FAF58AF342C2F6D17E9061A26F5797650AA5A17042E805DE1630447262BAFF013F9E49F5DF7358C6EBD9208674E77A06E15188897C01237D4C801F2758DBCA57420D837233DD27BFB21C17D4D24D324497E69AA66C9CF63F5599A80FAAD4D68B1D4C4944E61F5E362357AF8775D92FDDF9C1D6B1A7EB4A7FA97D3D7D557BFC6DF4AD290F53BA07869B6BA6089F8DA57F0392E7168E50674420C64D38F5E940F68641A95027D4217927EEE6B3085E6533EC30599835448FCF311DC1CF1E44F9D894D9291D7166879AEEB3A932F4698954C4CC78E6A477DAE83DBB6E33E682D9984EFCCC1801045FAF30F0C614BD0A6501C09D8217D4A61F80ACF6EFD7C03093C92C0AD92E8012701142F877043DD11C2EEACF05F3184AC91D0ECA1C71C02745FC1EA56E1B0D5C7C35F56A8227507916F428F41AF03ADD4425BA22AE40CD0D3C1BB20940BD85A367D9D16773E0B0A1438DA8AE685B92BB5DBD505C335D655C5A383A7993E7CFECEACC23DE158AF96293798A3FE57F87147975D0EE604870645877E54F214D86D5C572C79E5EADCFC817CF1ABA8CE9BAD2843730F0FA35606F9C93798F07B8FAA8DE0563CEE675BE50F3F74ACFF95087A005BF2E47802ABD2237313D01B1E41407B843BE7BCDBF9C6024FD6204C4C3D5BA198BB7EADCCD1F3F60D3462C357D7645D2274B3526FECE0131738921E7294C6643F5482AF256F20185C2942DDA1DA462B75B564C83E98867D599284FF0F05534AE7F65AD41B024AABC79F5EDF722E886FF0E29AF7F2724B34F1BE622C7D70E403E9CF57AFB36F438D8A2D96323FAA5C1E3FE4AB72C1E818FC5ADC825D0C64BC724304BD12068ACCBB5A55B9875207EDAE8C730950CC2495FFD9643D475E2C3800AEBCDDB8CC84D5A7C926A9235C72E3BF919BA69BC3B011ECD8127FF9F567547841E527EC3AD039459CDED272D16A81A5EF3715A64E20C520D4E46C52A381A3BCC5E175617A48DE675584134361245973C7FA3C66FEBD9101CEA75A567B5ACAE8B2FAA2057FEF75069082CC596D62A031412E502C4E870F673A18266CB764DBE2E408AC68B84E54A7675F3173B91409A4176B597D56855880CA87B1DC8DEEC7D8C5C7E027E630EB4C8B54B41646D26DF5A248FEDFB9F73C3CBD60E31477E8547AD8436836DFAD14135AD120FE73576509F7226195CAFB7B0D7FAF0392E4127259541BC74D9A709A82D4F82FFEA1E0FC76637148807981CBACB8D350A9A2AE8536335A1EA94056D2155A8610E83B80C8871F73FA15D3EF79CC5BCB5BCC40C80A6F2D17C8E8DD81E560D004D5D1BD319999C3A49D960B13828682FF398C0E9765459C308C8C53BD5D66ECD4268239AF44E6CC135E8F87928F0524E095B8CC1E27307BBC9CE0C200B202BA95D3EF5A3A04460A7F51602D2FC12A97E5E3A14144B8FBD2F8792A3E4CFA9DCB1E62B8506EC5D5CB069DA26722C0CE2F13A47E3B03BA56265C7590BD802E916805BA68DA5E6FC8CB73BD9884765127F5A604C191FCED82FC41144A4781ACD9F5AED9C220B767D2726E78A3322A0D2F2AA7C7E873851960E84C7298833A47F76F89DEB778305507AB5CE7A55972FE70D252215EAE9B9DC656242FCA2524A5791A6DE52A5DD58078300848B9D5C1EBA166279E12CC6BFEE7A1EF9673DD93152486D2BBE50827ACC864080F4865DBAF301900C545EAEC8C8FFD01D189F7D3425C493EB1F3DAD80C2B24B3AAE7162CEEB1D3C26B40D0DDF07B671FA2573F7C5CFF96D45FED4BEF7716873CD1EDEBF65FBF250662BDA9E324F3D983DBFF8086BAE81ACD950C4B472C4E07D6E1B781CA4694B51A34B5F8370E09D88AE7FB0F5E490C537B728405393409A7723D9E79600206358DEA6576CDDF25031B9793402A6F0D23C7A385871B2033662E4E2EE52EEF1709FC0C171D7D0D15EF856EA36FCF8F3515820BEF07F9074FF48C0901C23149209D4B04CC319D640E379BAACAE61556D92A5B6FE10394B77BC856D9AB93C148E5203710259543BA8907950FF39F5239A62365B444250182850C7AAD95276EE900526725886FCBDCF543E9CC20CDD7927DB547FFBE4845D4FED03B97F6B9DE7F5272A4643A1DCA7E08C9C8346509291F419BBAF35AEDB6A4B120AABD8B3745D4137D163E810E39B0413279AC7EF71CF8292AEB3B226A648D4C43DD9635C15BFC2F578ECEC8AB0506BE134FB26999F8195EC37C5E120DD51A06EF410FBEC8DF178BE58DC2ACEF1D36FBDE43C6A4304BBBD772F9EE7D2E3F1B6D716F23E512278A92BE78EAB1D57C3F246540D0B73814A67A44A724B0332E593A51F1762BA3C428B82D4C64418A1DF8C53823A33D84A0083947DCF094A8826F945A04DA24EB529C123BBB4E939CD66D05FB4C07801C76FFC946B7B9116A2370C9586E1EB0EA82F70DFF4F152848103FB15BCCA09814C8211DC08AAA97F01365306248C03ED052F101CAE6BC1D8ECC63FCDCCD63B4303C4D83592A4F7C76C4DF9C16FF2F63478D047BF6A44D0E909C1A732A8CDB655F01EB9E575F227EAC6D6E6647D70ADB4BD0B6FEEE63D85BF43DBCD6A12782BC85EC0C44990FF7DBB14038D84294B19403E9D1C918C297B48B15BAB98CC874B0C5052A5F4024E3D5C8499BD3C0ECCA06CEB6963E02D4EDF64130DF5121A87A4E9C7CA160FC214FEBFC932F1AD882B8E284FB317CE81B2785D7387E1B14F6FB6BFA62300888D3F4496B6399A356C2D27922869C185F086E912E6B3AD5CC78DD1187C41F2207A4FA7B33B4C1DEB1B1A9CE104C41D0BC8913A5F1FC2A4008A638038E5F336AF2ABB3F31CD25AB2BDD84705422AFDDFA56B4E6D2923B58D962FCA7BA19153E020BFD621AC94FAB19A629D911345C1F857AC0446B320F56E16DAAFC64A1C343CB32E004BEAF7C0940EFE9300D47E5A9C7C4C7554D854480F60C36A524179D91E49FB409C5AB3D58C145AC64AEB6C0740976FD5352F50AA5886A70C72EF724F0140CC88AC79112C2730098A59C3578EB53897A9AFCFBEB31F4238B2003EC39C8A274D19D773DE4051425B6B9090F75D0929822B154C3A349DF0BAE70B8C70F48155BD04B8D050760D070C72EBEFF202B58B7D0E82F052C1FEFD8B09C242F2E94A22DD37ED3EC7219BACBF97372FF0638BB07260E5B49A8303BCF6EE51BB40859AFD292112F650EB86609C184060055FDD9D39BE22AD837D97A33CDBF27EF177F4F80128550FD4649D59FB813624D05ACEE77B3FBD77174F77EECE71F76E76E767DD89C178F4E7342F835E2EED558BEE0B12219E2B7AE9DE64242E8C51AC1AD1C34B362818E1BE586768504DADB90DF37F22CE498529FD264E02E2F69A7D56806AC57C6106557FEC081CD251E88E0759FBF195A066BE120B8A0B236744DD2CCA76C1E5039EE5272E386FE41FDA163F8A14FFCC266FDAFE8036B443CD5FCC54F53354B07CD1F51EA8ED0AEB2C06E99D248B822AC413C1CF15B045127D8B5DDB86E09A0A00248197709E09799CE6036937D83362907D2FCD572382224D69C3B6F6A076521223D65B6883D6E9E461251332DC08849E835E1BF4D82CBA099FE587F044A77F60435A0217C77429F0FDA028401EEE0EBC9EC6D94C02C1218603111485E2F50F06B21C1EF3FBE2ABC119EB2CB5CC96F0047EAC7E9AFF87656267CE195EC1A51473E02E8DCF47FB0B089BDF1EEDF448C5898258CAC30A1ED6AEF6188BE847CBB1FEC1309D4F0B8D992C3AC151568CC081FA2F5F13E490D7A924365C6658C9A6F4B51BD436EFCB488CCEF3355A07C9A59BD867D98D9DE1991D2B6A98905A692F778FFE63F4A52915D80136BE45FDFFD4829A79E13A0C82DCD7F7B653A5A20B4C38ECE0501E67085A96F5CBE69928C0674D27955729050CFB05B5071325C5FD9F10679CB17C690561AC644B644CA6079E25EFC3E1517938C4E390FBC2DC151A647E297E2CB0A35157793D78A9AE3CE8D69817E58A18F492F71C63ECD7BA26DEA1F52F86C72282F5B2A4919D5CC0B3CF4E852112AB1CB044E95F968115C8C220B8EB36FEF4EDE1901BE18966EAF100ACE406ACE2E7D52B8E5A9EF9D3D01C2C88BCAEE3B106917471AF16513A12C0D2C39958259FC5ADE90D38ED511F0E5625A966138F448219741FF7219760796F89A27C552B16C8A4ABCA177A662FF73E2170B8835AE8C705D061979702FF76CFA049D337CD2782611D45CA877D94D4B07155284531491CB642A3F04710E7E6D2BAF0185C8CA10B7E4C33F4461526E2FA9D10492A9FFE6D008B2B77A4F8BB40325AEE51F6E5F5FD8B907B5B055DE6C2C6B9AD42FF37F2B7FE40596483F1F6986BC2FFD92F6ABE6FA13231647FB5E651202C2FD2FAD4B4A9CB679011F0EA17A1672DCF0023104EB91D85C9E6B8DCCC140044EEC882566E479E0B0A720DC1B5C318686F527B8D1C60705EF09328C614D620EF0211EDEC7536BC3D768D85D06A220B639F03E17EE2F5B4BF776EE7E79F45C182A71429B0C4C1861504FF1EF26704B282CE70D2651C081AFB316214D5CE7E6EFB3396FC5DBB79D0F9295C01E272436949563F66628398B48FF13FE21F7AB47F5C357441F53EACD5792935304EF1D574206827B9B384197494189C3278B2D3F9FC11697286CCA8A000B1D2D79694494B28CD2596F67E9F559DDEC53A02ACB4520A5B28FF4D87E6E3825EF8A772DF7E27EFB2CD02A51F52C555DAD3CEF61F7CC4D7831290742A4C1A418A4AD76FD2F9AF57D727D2BAC08F9E7D402CA999D12992FB4A13142BA4E9B4A13B2C7F6421CC5AA6F9AE39EE72998327594816D051BB78A32BA4C3006792F52F9708254288F0F26442769935CA70CDAE72CAAB631CBCE9FC552C62FAFF74D81DCA3A03F74719C28025AD0AE4DED54AA8EEFB1C9E5B46F0B3D44858710EA7BA9B8503CAB02547FB9F6C60C86010F04FFEB0FB02EFFD566F20FB8737189BFA401F4FC4BBF56FBB72819C6ABFC15A1BD0CD3FDC674E4B34BBC8AF22C1029D2A3A317950FD8A21DB2B5DBE878E9C5DACCFAC50DA5EE22AD0E194EC18772C0AAA1D2FCCC00C5B48274CDEA2677D2D1133A218436B2B4A37C6AE5F85CB28D355E67A99A2EB9890E91F835E877E44A0A88415F4909C3F1D2D693CA6F6365BACE63ACE0FEB0599BB5FF10387803517B29A0D0C0BE010ADB84E62E5C3E6D9D93DFE666347DDC105531D0EF29AF41EDFACADE82305E047B5AAF683002D2B5D874EA25F5BCF61345812FA8A4E9118A3997EE5A324A94FBE6EC33EF04C381522F517E62C0EF9BCBFD0932ADE9C9B35F1EBBF2E9323B9726B8D4B633AED429C63F8BDCEEE1B62A285431FE5047835CBD8080AB30F727E9AB38CB92E9EDE79F1895B34BAFEAACFFE63E95D37D68FAF76945BA1E1E92E456292532FE360B8276E05047A7C2FF82E57FA6F3C275719628A0537CF7040D7DF9BAF10ED1A7D6772EBA1DCF6351D209648555ECB8DBBE824D360731D96FBA9077EA257AA3D326F9E244ACC4AF14691A504000EF85782ECD07F0FC6B77DE666A7FFC7A5267425E165547650F4B4ECCE50559DFD4A942281DB3BB3928761DB089CC8C86397D7B1EB688E820012D0D901917A39E4A63D87EADB70436B0B622543CAAA1006F68112C115CE21666A882A472DA469932470DAC4F264F874A239C489926C3BB5032126396225756CB29E04D17152200C6B93ACF166ABF1F7A8E9222DB5CF1A0C8287C733D0F309314D8E54C3358DE6EE4BA1B8C4267725B41DE123CE62233521F7BF34E510C4765AE362E655BC66917B679C7FAC54B6FB9EF08D1B75E70D0429408D291FAA728A3D5FBA1A748F34122430ADEFFF19D0220D3422A591ACBD7F7E6E8F754AAA0F03400586FFC403FC9DDE533F2CB7A9DC371C93663798D527E27F414AAE7D3A335D8ABA40529FFA93915011E6F49AC35B91F4F87A584FEEE17FB7F96831FF3B17AD864F84759A6E87A8CB9908F2A9FC19BA2A6FCAC771446D96322CDBBDFBA203FD51E9B23886D328853F7688C49F56938D83A2D09F59857F68C5AF75C8E66BA759CFA2ECADF0A315B58906D0F1B5B1D046E8A38E337910B599F4BF53837D40BDA3A3276B329B3A72C7D655C4D216CF367F5B76EA8DD9223D176D08A9BD180F32123FA51D6D1B2461E6908277D96CB6CCC2CE6FAA0E5CF14599DE404738756D35A45F697C7D4FE4C8270F2C5F3A7F23C343DBA9B1F7EB0AB15D79EF7475A8CE61E9F37384A0D0BB54D4B0F5245BECC3746A32C1F1AA0329DE1EB5CB212E365134CE3D86977CA040EC4F9CF36DFA10EF2D828DB3EF5D9AEC0425FF4AB9BAA106D702A51B326A816A6E39A32AFA88FB80AC3F952823DCBDF895415526922C6CDC7337A9F5EB3A5C93AF0FD4DECF9E5CBE045592A566C18052D08A7A6286B2E2DE0186DC5DF5911EC645AEF75CCBCBF564ADBC28D8EB354C406ADEF5AB6B0C6A1A0464745DBD0AEB84E60580F2E82E9AE13D85A2F4C53772D81A7A77345976E9C4B1A80DA395E3D0632B5A97D533F0736B9BDCB82DCFC808C542B87F48FE7A56AEF03CA7039139A41178ABFF85A06F8A67CB293AA405F2A6261CFAC19C9BEC79998F62558B74813821530C4A70BEA11437A12F0DAF769858155555CC7D7229089F6A39D4C9DCEE371194848BDEBC47AE0B447C82AC474E2E376C0F2C5680780ED39B530FB9B54E357AF814714F4E228C9D18E7495E63E8EBDE5F2C9521734B573359F06C3DB2E1CE17B503E1A44A44E180E148400AA12A096400A4FD0BD9290B695941D0F2A037D001F23AB0D204D3080889897164F452639CF9C3803E8AA1506FADCF9954B6F5E3480D04C7CCA97C2F8A6B20DD564A146E98CFE22DDE3C69ECE3330001ACD28C5B23CCEE028502EA07313BD5045D936CE48BF7E4605D73E8F878EFFC64DF2A010442DB4858F9A4BD2D61F80FD737CA762196A8B9743F2141F4B9063D4626C91F310B68C5D8B851EE55824A0CD4AEC0ABFAB4652AAA90A90F9D11223424124C7F6BC07899B81F471D82507A94E33D394605796ECE782808A998D700E15FD880CEB834B1607A72C41517D990837FF8C38A9BFF05DD6A33DD525C2B08FF1A00F540BE4B92F08F3BFE147195ED898A78CEFC539B6C2EDF06E92D5094C0AF18095F119709FFD06C2100529D5CE314560C8A3CAD2D308959C91301A38F91DED0D5061CF0BFDC0037D8CF62ED2A0B35D69E060572811616B558AF724659C6D32FE1BACBCD179025036B4A3D1B90DEA164F50F70A05EE99DB2A6E464832721E2A113BD1A8DBE6A75ECD4A0955B7818907CBF5A78A27C1AFFE9FBD3BE0A7CC95CFB6F934B67A86A350146F57B62CFE11DBF20F113A5B810682670570EDBE0C246019A7A6C0581F62B68E82CF05A8BAAF121DC38A25C46619F0E9A1ABA5E765EF5FB5F9B099E7C9D1F0728D84526BC9DF945BF4BCF24C0F951583523DC1E9DE6461CAB9EA552B8FA4A24227330E715365E6798434CFCD57DFA9FE82F09283732682A0A5448B3FECCC244F6E9526548A1ED1C65EA0FD70DF3794D12D16F00CFFF8471BBCAF65507209BCCD52D0CD1C298AB040A6CA09C6D445D8DAA6BDF3006ABA4FAF2647D1FBEDB59AD6124B4BF179FB4137A7B3910B638C9E374C82A91BBA3556A5788A125BE68FAEA2034FE0F86DDA58A36363264892C8DF4C2D0C928496A5311CE571220E4D03B559263F745285D8574E9FC6F611C9FF3F5873E42658C038F10F53D8234EE02BBD6C799FED2359D6AD28816F077B686102386B930A74470AD6720F14C249E5F851468595F6800A2137A785DA06D79EAB9B1EE1C22402BE446022E0A494AA8BE089C154992427623944255F2F92DE78038A16412882FB80D813BA2E29E30977FC1A0753B62951433C4A11C8C469004439004439004439004439000F345CB9035D3BFCC3E23EFCDB53DBB5AE05321212E0A541212A350E60A295B40A8A07882228A6AA75118A8843869A478B053C84F04F681EAC51A10792AFD520C0080DE3F3D8FD194A4F27EE1E12C32E5EC9E101C0714860C52D1AA50EC4D89672E30341D21EE9A269E390E20F2986A2CF7627D08EA07CAD179A67A1FD71602E373F6C5377197A8F44DD9827D2563DAC785BA2CF57AEDA4DB6894F7F9EF54FEF02FEA5DB6F55CBEC1959ECB3327F418B1A816F9FEA8EDF71638850081B8B5FD2CDD2655FEE76EB85789BA39885483D63E41255F7B2E6BCF245CFD4B2875E1C80187538FE2B695213C16DFDFBC81AE4B2A3CAB8F85DCB7D41BC503EAFF30F801700674F55EF7F3AB9F3063A9B34473455DE8E9E2B559597A1040A4DCC493E145E0DE8388588CBA239DDC9D100159BF1DED7EE548AFA57BECB366A733805D7A0795E9AE6971461AFD7DD5C7B660FE58E732B6A2D0D5AF755A30034A44C86BDE16001C46738952E3A45518605A8E74776E5DBBD3E3FC425BD59159D1FF790597D2236D044223A085E138F73FC66CDB9920244BAB8972A89F4F02EAD7217D38679B2DA47D3F65F45D10DC8D1DA6B50D330C6B1C12DCF991593C0419E6DF92B338190AE338BFA82A6233F22EC69736A319B93352806D2F332F1E0751758191F30E28CC57FB68BEE656E5A29ACE82FD2949DF61F152552295BC9A6A1E2ABDE46744A8447BB4FD09D90698576BBF84658A25F78118BFD095224B4677F3A5044D700979AC6622A8C12E0FFE6247F5F730B6C31B52D8F22A43217C266F6F260A89E30B11FD7E1057BF350D25ABCA899AD84FC96057F5FE37FE14FDDED76E05915B5300A8F20A7AF369416525353D1E5E5F9361682E9F6D13317F562D6F05ED59EBA45E389310F75BD247B1F4D7DED401A8A3B6A93E9A28855431C06195E093C4784F142B572E3B26CFA4897B4C8E5B62D61C63363097E63D209A79C99FF5228A5FE2C5F0025618D2A8FCC1827F224155DF443ABE8ADD61EE5309F9E8BEA797207083C4A99DCE7288352D34F99BBC59A1B0BDB6E05C4F30F03565510EAF307E3F7AFC47D06506F35D1996E679EFC28FB7258CE111C9B7D98AA57913C005E86D0A73235E245D756D9A33CFAE27A8D32CADCD634C56F622C4991BE611514B46D1230501F0297DCE23A25DCCDE876733E9BF3B5D00253B8DFE2460388F80280A11B0FE29D44934E541424C0EEF9939E40B7F37E6FFDE2FA7041DB8B7C6B573CD55430078D982DABFED622E59E2B23DAD09D4B6F4739ECBE2EA2C3C1C5A8A8894250584EFCEB5AE1EA8AEEB70D4D7725EDF15C86C04B16C7819C2D4262095F1E6AD18BD8974F0D0C45786D26E3BCE4BD11450BAD40C9614B1D0FFE352135FD461BDC66C2A7687784DCD7E34E948AF6CF7FDDB4F45F35384D32CD3FBFB24AF73D7C8250C0286A3C90E187979244FE3825E9B1B4A0EB392E11F136C10566C7F5598EA2A86CC89394EFE43D1F14F92D8D8C19D341CE61D56A4219E98E70275B9700C0F2AA163BAB940D201C1CB25F9DB656D5CF9EC7F21B9341E9F1D140C76B6012C29B11548A8C784DA6F9E66470FE94D2228C8CF7DC4F8972938B4C507ED56FD6B4A2E1A654BD444535701E0FDD8E8E2C46395800A7705AF5C88CA7BE0371354F449A043CF7658EAF08DFC0B2310DF17BE7F1006F22F7F9050C6F5BBDDB7DF562934A732E1DE2FD5C8F6EECD54ED9D59F2AF926B3E547BEE50BAA1AF7EEF07148A06BC53BB7FAE232FC4CDA922A4176AC9EF1D282F4FC9877A6416C53A64769E5943EA031CDC8F808FB903EC938086DC6E5603CCA93CEDE1FB8E24AEBA669510F9BA1BDF734BCEF85989475581E3107749F1CDEAE53E835453E627C6FB874180BA8006F6D1134ACDDBA77C9E497E189F78F814D0E8D59042B376A58B3D4BF5F7410FB500E533A4F48E95250D2623D3868CE083491D9B1AD6041707BAC7CD6DE8FDAA05776DA33790FCCD3D6B3C16AC2BC2CAAEBF951F09793615AE10EFDA87873CD08BB53400A2695853ABEF3D9A7C7E4F372216291C6F840D379A7DB4A5CC249676D7AA11A45C68581F2C78065A6057B12599E9C761A2606A160CDD7A8A75E7E59AF827BE4BF74D3C37DAC6265A8564B30783D84380954D866BBE60349FAB81B7672940A344883445945DC6CC5890DE9DB0B5473B48AA9FD2E73EF26078C85FAE28A966C446923410E9FAC8CF9D3DBDDA38C111204D55D0F91991323F9A7E54851A8BEE0BA65E59ABD2D298ECE5EED3F2AFD4BCC5885D06DB871ABDC83BB3F269053B3589511FFD18C629A9C64647E85E5A2EBB5898CFC699DFAEF496EEB687171C7671CA138A24BA5EF36A8C22B3B04C612C32231F1784623B5818AE864EE07DF0F076A0B57D20E2171C233836D9B9ABCBBE97337E034F1C0F70741657ACBF5E7EB1564579063AD8BAB1EB70391236C33B46B1367BAD365113A35DF8E580307ED053AA704B5AD73D13D1216E1A0A9AB2FF1CA67FAB9C12745A30FFC528C43AF9E6C18E94C33F8D055466A68083F0E5ACDB42FD29A16DEAC1430CC7D4495E472FE50D01A0095476E82F2FBB0FF617D06B0F2C45402E4D64F2983F4340E6A59F404A8B03D58BFB3972A29254920332D467D0AAD5C8C33FED75E702FD4AC3B0AB07C3E47FD9D3AD708AE05E2C928BFE4DDC738C327A7334BD917990BBA951851F24E7822C0243A872CFF0AFA4D4E37D899FDB7BA1E2B3F1052C8EB458973737E23AF69B14F64AF60B5CEB276BCC550140042EC1C874102EBB367D012B9B76BC4454DB11566B9D66F1D76D9EC893AADCB83990928467DC8FAD54B653ABA04E0856CD3425611E7B74CDCC844F12BD4B9E3292794F684A26B05EA99DB955DD27874038BE7D01E6003D3AE5C0BFD8DAA847E333F7F95A044F14877AFE9B3D462817F19DCDA51ED314FE3B2830C4D0F85829D9042ABA9FE18AC97E15C66D4C536B68278E1B28138EF7C071D7143C14EFA3FB6AE732DE48A71921581E135BFF7BEED30EB56556FF2BD5AF88CB670AD51E06946AA3F4D8F66EFD4B44310BAE485F4F3C1F18F32FAB99461FC9E6B19320D38FFC52CFA071534F81208CDEDD9F6165255B62CE09DD944D39955F182FC557281E78BD0AAB4C695D636B300898A4693F17F027FC269E8187904AE12DE24A5076F30B35E9E5F377F630BC783D3D5048A935A6082BDAEBC96D756DB4AD456F7F9AF068EFA84E8D850C6AAC72C42ACD46CE1D3F5484AE4FF335E8351C4D4DA51F1B02B1E70C6B2D94C79F718E0470CCD0596BDCD9A6F8CA356BC8FD78A8B490A9770135006A8354513327ACC33680239B11834A5F6CBB3FE1ADA6D42BD9D0E1A3F68C06F809E46C755CF8C89ACF0F90F169C19F1CBF4508B20BF255919E1536D26470E3E35AB465211A6A43E63E231E64344F06BB148E2BF3D7D0B8EB4C3BCF4855DC3FF3AB97663F75639F79DB41D53D06D571A1FBE0C3D3E328D9ADAD7C35F48DB467E361FBB1290275FA55F4FEEF717D04B1680F96907DE82890FDEAF1F025C81FC04B08E6B297806F5F3A587EBC04655E6D3920AD5CF751EB239CE01210370C7D2B2BC1356B542E020FC3C844B414FAC9E36A286D6B439686D96FFC2BF689FC5614EBBE2CF2737237526631453AB085BEB394C6850305A0B90150D664B71C68C20354D3465424F429682EFDCB8F55AD8C8BB254EB2B51E93C1ED429C76F34642BF070B94BC46A86E73FB83128EBCEBA37AA1F524D9616AAB169AA8DDD90B954C9F03BD2C301ED6BC0FAEA3D8DB5ED6A852A6465880B0CFD30786A06B77FE4B4F8D629045B133A3D017E1D103BD22D8D6E1659FF54292CBA36C4F817F143AC0F4C2E30F1BEA810CE12D885630D98C0E6AA4FDA79789928ACFED454A365DB5525A3A2A5342EA0A0336F10CBFDBF937FE18EEEFED67DDEA998C84F16C9AC72D5363BE499B58876038CEC21B57593449C18F4EBE4C66748864438FF52941282FF336358D2F163F4724F03BECBCF9D7CFD9F17DA802431FA0312EE4AA6A060A433304E04818897E21F1C3128D2557EA67550F9D92A6FE5E7B2897BDD0793AF5EF7F115A0F44F01A712E50752C249D04BC0A3E1449D7A548B6B075F9B6BE5635A0E76EA0DD3B5044AE474FEF8A2A8684131AEB06BBF7D472F0E9B6BC6B7B962CCE50B4B91B13355AC454762210ED5FCC18779A505E12274CEB6D0601F00B8E3ED4D0A420366D153D0D0C8323AF7D77A3C04616C3C7D14220F11F1D92CA1267CFF0656F73D2EEFC01D8C7D47DE3C72402E5FDCDD0C083ED95C0EF970882B5C704C793E0D86FFBE486E6E6D8E106FE87449CE452969872B85FE1C5F2C186E07E6B320E2FFE09E2EB84E4429CD8853FB9FADB87AFD413A62211C165E78991302BBDDF187FDFB09FCF5364AEE4407B7FCA408E953AA20DA8774851943B8512BE927BFE69F025EEE4C4636AD6BD4D31B5B202C41D358435BBFE9DCFB75C53D31893DB221E2422E13E01F04913688DABB6B370D47A165B09F040CF0BFF5C312697101B99D747ADDB5BB7B78BCC3DE712DE361EE5B7B65BE7FF81FED46E2C5859D97B13F84801D50290634A9CEEB57CADFE9F527BD381547C583C8500DE51F8243610E5220C16EFCE9044F204CF13A18FCF0CF4C70FB4A91942F38264720B228B1CDFDF126D7C9CC168263DF0DAC85F3943D2773003E31E0DB8C0FFD2D0DB6E88301BD930402D2AC54B59F1B20CED18C4546BD45E67B113BBDD8B6E66B805413A72C146057138B3BFB1B29B5EB7C0954A9831EA64C93AC6B95B9EFB2556F5CC950795EE6A06DFA87A89CBD59E373E7DB05A20CCCEE34E13BB1D405717C8B72AD0D14F80B142C9B1964FF569ADBAE6B321ECF7D73B30F92D7F5F4E587BE74170018473DF11C569F19FDB9B673E4A93A7C6AAEE33BC774B132DD9AC4B29B35D6BDA17BD6063ABA8D4732F47D0E80952E826F6DD2BBAF1E846B825CF9BCC75E32672667BF1E77813D0354AEFA1E7ADB877C79CDC1B0E2AC38517661C6BE40AEA2D2E9ADE1FDBCE5F40CEF2E5B93959403076577EFA8A2E673BC0E8B7423F0DF8390154FE5B72BC42A01FC4B65908F6AE41D62C4EA403DB9C8F7775755521058179D923115CE2DCAC56C0A6492C3A509B1ED39520E580C0371476F776502FF376477DE3A7E6808DEF0D4BCD9A2C9598B567A53841DD27F17BD18E54549DA66C452F74F698F57B32C95EB651C072A2D64F22EA02DB2750F5CCA19CA5BE254327966758F5168528E70A9A95B295F61CB14075F7FD10F0F3D9BD699072CC297EDDDC2B4F31A56917256A7E52223CD5C6C7FE0465CBC79567E90C7E0092928A5CCB25BC5E1C12CA69722DE818AD3483CC19C03AE6A10A205A86B3A0761392D0B43C560DD3902F3ED86BE5A5F62E4C463DFB6432BDF017CACEFD4D1A818D7A1A5120915C8806A574340CD01AD90D6872DF51D6AEF30DBD8F40984DA0577BBB83C25F81C9FFD7374C69132B3BEDD531549DA1B77B1EA1EA9A709397448CF2EED7D27097A7E68B6FED8ACDB940B796535837E71C515991A7476E1561CF6112286D6D6B5F68954B202A52193E0B72A48938213C73E6192203DF1D0467C687D56FE9AF7DC01615E3B02232FC6470FDB155747A46FF5AE33D369EC0AC69C35663DF257FE7EDB509BBE38667F51D0043EFAAFF87CD2FB2A27650745C79EA917F6FF88B77FD6BED8818C2663016706B91FBAF59BC12E2EB497A650294514A9C49733811FA8531802C1ACDB3D89FA0FBC288E2E1A1454061EB95D4C6741C3B2DA7AAF7F2FE95264A59D232D53CB0E1425AAB285D6005424E8EBAE85340A30CDE69AC98BACD29BC11010FED1335D98CC5BEF4801D7B24897C502B1B6D94362A7DB0F3247C996DAF9D6A441C50D56B260A3EE9BC14350CD02D8BB130C1769BCC8DC30292AF81F49C03F9ED4646021E5685F0743A6E09148E06E35D7C6BE6A3FC2FF9C941DE663C1B7C0F59E4B8323A8CE17B7D76274D0F17E70C151397E08E5B60D67F4BD2E4A6C4F6AFEA838F8F16DBDBF3CC8989124CBAFFFE508AFB8045C0CD1C7C7FB8D8B1955BFA43BE6990415DF5E1971A817855D760894DFEB62514B28A32345DE00897690B444935784F6B11F1CCE767ACD947AA0DE8872243EE3301337A85B3EAA1F0C1134D42D1D1F2A68944E7339855165B42CB592A07D7258720AC08BF6BB7D8AA5496864D713CFAC6396A573F204C8BAE08F88F486B0CA37C7AFD9A6E46DB2AD0D5FEDDBA6149F7F462DDA26667ABF0B5AF3BC7014A1F2154250C71F72A8AC07461A5D59B04D9158F5F0D7B4924E384B295A11E464AE64813A51953CA964D233A3309904AA3B6310D5F9EDB006D6397B94D535106024B81912E5D024848130F6B7680F8C040224106EDBA4F3D8CFA666A4E5DFEFDF8919906ACB6DDAD383B48B6D0B56FFFE49C1DC60F0062CC551A99D60619436CC27B4D78FAEE72F966EE4C88A9184496B33DD103208A7C4748592ABE7434ACB486C8910F4E0AC4ABA3D1B7FE635EF1487D2885F7AB0FA58ACDF160363149672FBFA3FC674478E87BEC9C1DE278F8D3AB0B803DAC8C9D4BFC8593649BF47069ECA658F10A8F032F95F039D12AD1001D9BF34F8F4F91AC27085D75F47BF9F9775CD07AD38A6787CD778E52CBDCFFC2560E0970F0B86B212992BDF1A3169440ADF1F72D3EAF469FF4295CE50152EAE248C8B41BDEB29D7272D39D6C8CDC80F9AF6B05DFEF9E178DD61F7823A91D6ADD1D84EB8C3C8094246DD5503C1824059C5F6F3C086A9500106633EFBE06DD7AA88625090C3C660F73F4A9C9D4D4648816E298143C2AA6ABA3F4391AFF12AA78C73F28FB76C72FAB85710F3AEC4040219C6572B3BCCCDD49ABCF95EFC19CDC2FD9B7EDF74A35C23B1EBBB49E714995F12587EEE552FFACACF7682C2E65A6146D27F202A453F0DF3562B1BF03CEA4433D8CF3A950D3FB190F940B8BC90CBA5D7341DCC2B8EF2EFBE96AC373F2C21C64CD09950FF57EDD289893E6FB60B58DAF96113C8C48E3AA8254E67B28053D7B6B9764F0E820077DCDAEE77A7FC29E54EE282D74B498D1BF39BB850EC435DC23F1A97927F738F81FA5B2A11A59917A01F2A63878F90AB96A83C060A7FDC9F945C2D9AB24D528ACD1BDE8BEB64563EA292984B9455E450F9ADBF4C8E4BDF6DDB3258C4DA0A8F840789D44AEBD0C6B2F2D3A8F32678AEB52E03062EF99F0D2BC70B66856323B7A33FBACC9C919352E6E5A75CA9067FCA42FB56B4CCE9DB42CC6413D6B0DA9F7B4393479DE31BD9796324F010FCDE6F461BC5D2257CEF48C05219FC72814287BB857FEA0D2AD812AD72E4E0C6CA98D2D1CAF8A854E7EF4F7F163A6B9E0E6C0F280474038F8BD85F9A2EAD64D899EE38FE6D3587B97C479CED03982D38DEA79AE35BADF50D4186B2F4DFCD840270E3F3628076381C29951B185E4DD90C924C38E8ACEB5EBAF45D0C0EB499DBDC6156CCEB5A5739D77C504E312815B212131C8432C2496D8D90D2CB27431DD5559E52D3A1EB52950BD3751968B2C997BA4BA804BD08FC8CA141924AA9D371F057F0EBE5D9FE5EA85B97B14E67AEFCDA1E1803FC27AE1E9FC51D23B1277CB71736B0EDCF4226C51B1D0264F05E55441F1EA69FB1DE4E403F0C84173A82512D7B0C2F4112F9A82D74F83CCFB323011744E1FBACD1E51EF9E9487D66B08CE8EB790CF5C836A4FB38EF8FA7084C74DF65CA8C9D22603BF9622F390ADDE09E89103EC904494FFE9BE3A95E3DB28CDB719135DC018D45B8BC7A62EE3A6FFFC316E0D713729C55190A4AB7090BD994B94A0DF5CE32B5E87C700A4B733F5ACDB84CE14808C56F53C00653A6114A883A079D55F640644D875E24D115A2D295B94CE42C8AABF8CE859A1E8BC5489E8448BF67BDE3E7E33D16DF1C975CDF225D0175D50833D458E307DBFAA33E8BDC20659A8D9AA76AE47EA9397EF7F06DEB1D88B05C0F35BCB785F21CBFF81F7DE2535BCC5F0858178FDF6AB39AF1837CB5AFD4051ED420A7B84B5344381D489EC9D2771ED583DF17C60DF9B5023F04A86E25A1D3CB2E0B58A38E815461ECBC089F99E77B8BF10C7589871D5D0C803A50426988384E5984279964D2CC7A8693F5132BA4921AFF5F412E7EF81D57F2CDB2E8700DA5B2D76BEE7A5A52CDB09240B95E79BB269C7107FA906F9A571D5D0DFC53FA8ECADEEF546CD1BED574BE82FC0897C4876E87CB099FD8FC9C8D7D94003CAD50FACB7645C712FC73B3733C6B7CC9C74B89BABE265EB3B02FDCB4ADD924152D3B9AA12B52EFC22B0F345A03F3AE13C42BF90421E58CE56F4555BA632962F3AEA38F749780FD9E19DCDC838FEB1456BFECD45178FB2B45AA3FBFDD9A7DE61AB8DCAFA94D572D6D6FE347B5BA09002095959F31887ECC2AB9934325CEB431529F4FC01D8C2798EF895EAF42C9C446CA1B259ABDFE0DACE43476F3FFB58D059BDA2E7A5E14A4027C07316794170F0B8272B63FC5C7EF93C8EA48126974DD069D3991BEC8C195F9B9FA1587A1F9094D0515717796700C0AAC7F087FAC63C36C59FF552E867E7C3AD3F9344C388469225FC2490F52D9AD406D00810E2B4E24C69081F8918CD6C8E3B1C2E0B71FB833835A6943A830E530027C173B801A96AB1A74B53823138921D294142F610FB69E0E6A87CCB756A4A8D339B54440FB334668EB3A167A329ECE9B75568E57C27A9A0BFF5313EE7F760071318637B94A264AC945433F6FAA50D7BB62BB17F49F3E04D0140FE1A851A23E30D8ADA63F9C81889CBC84087A83875B67F718909B9491AFC15E52F8F8BE4997F90943CB57581980D8795144292D335596DCAD3EDAEB20EFA5BF5297E410E82A9BD139C8868A012938850C73F512CDD8F9E368920917DC50D46925878B02C15B6F35ABA848CA4BB6B496CF52A7375007141DAB943189216C9AF822483A6A4DA4A7D5686DE194AF729DA4EDB801B329EADAB04B143148E2EA2C5F33745FCDA8AF1958ECE287E0378E216586EBD766AD3319C8D2028D45E1925A7B3728C5A7D3BAB5143A9638D2F45B4E4834DCFF356974DDD0F2427741F4D9245C2C25661964C6ECF1819AF5B13E5F2413F8A8BB87CCD43283E8900B68444DC57C96D99559642E2658A7CA612962B620C92706712D5D2B8112081AF3E1947D174A42A96BFFC31AAD538B3275F349BA4CA299848087CC17B85151B5ACA09CC97CFD70D5A9C774B92553A51164ECD57C5C074E449D79336558086E8A0F9C943A2103E2C167A589AE7B8C5B081CB0BE7B7C81F7DB20DA6695DB7C44D96A2FC018085349CAAA4F89250048EDB8D692DD0E14B287B22B5FAD8EC1662E9EC66E4BAC15C4656B3180088678EDB4E4067BED8C45BCD7301BDF1C666F176BF1BF56EB9B77BA7BFE539A21D91B39349B399DAE25C1DBC1E80B048CDB6BBFF71023BEF40CA2DF6E274194F4165F0D33FE871EFE7D25B8C664B2AC0D6C38C91E4D1677A047B2FF1A3B67AC97B8F7B1F34769CEF043FC89DEC13FF4A59C2A9D02FED33A2878906CE2BA97E9A49B3EE27777779A2A84B0232F27D4E3C325650A10EC031A46F38BC7BCC19DE98AF78349276E8F0019126618A80214C7195DA9FED878F94D7B4B76E1ADF43124A7724F73F83951B04ACFBB644DB5284C49DBA49C1D41D60A0A5B4EBB4BCDF72624E83AF45EDC4AEB8C8253D4F08C7EAD69A74F3EC41B6647CAE578A429BE8D81AE9B53EE248CC8C54FF173D1972242A3E7168F4643221D521D7BDA2DECCF0D39F5EC4884AA8CAC3D94B66900169EBA01CC329622B9BC50BF2626EDEAC2533C077521F3815AEF552FC9BFA4ABD7AB2AED2CDE9F0810ABCAE686205A87C6F315EE6733CBAE5EB8B4CC5BBE4FE758B25E3892230393464216A9325B08E0F24A87885C963B683481742CBF625F93BD0750122C0DA1344377EC3EC59937C54D17E632C2D6C6F091569DDD002BC64A288E25BC9B72DAE0216D993EF27194FA119F59E511B70FB81523602A24E634D6C32DED9F9971DDD473ACB6BD45AE7101FB287543CE2371F55F655E2B1B594C8320C015C4296BA7B22C5081743E1AF94261F595C999105EE5933043E33E543AC8095F201CC4A1D7658F48501BE9AE494051FE7E5C45CE16023EE0620B1FD67C26E1F6BE3EAE9D696C86D94B2D12965AE96E42954E585FB69680C02B796D9293EC4F7C4EDA47E7F5FE25401F29B4F6B63A4E6A16ADD3F4F2D090592018FD0687A17EE353856E7E5D207AFFF0892772EAE3F6D569B2E652C02198014B1718C6E9168694C1BF004592503FA7D9A28D3ADE5A6C5D7AB5D4AC0726BBBC37F4EBA422A910F4A7E6BBD8985A22EBAF9E682F276D7627DA71CE2865F8CDEB2FC5B6BE18DC902305EAA2DCCC0AC4A121EE5839D079B5A1DCED2FA6A01635F800184672B67C3D3D69A0C81CFC4A2760516B8B07069AF30648BADC5E1C393D6086F2E2B4A8DF57FD0AA53DF1B6C219A965820CEECC8058F9719DDCB0459F45E58C622F4EBF26A3DC4938276BE6D87C4212E131D7173B5D20820FEBA67317A892B0BC715F2D9F5CF3F8442151BBAFE07A2694758E3E426C3000ACDB0CEAA9657AE926950CCA81EE2647D07E83FA36E2DAEE1F277F2E099D94BD45F9278AB5FB07B4A38F82495F148168BC585C867E1004688675647D7752C940CAD36A72A3474DF348D5EFAF4DBFF217189FA1D0FA4F800A48B62BB5B6546E12C2C6DE1CF390D39D2AA90373F0CF4695D39B5394D4423625BB0B1CEA5455DC85B5652214929D7546DCC1C0EBF030AEE6835A1536291D5686C7F32336A79820AB19FEF27FE705D5AD2BC6F18D1A9CF8E69E36F42707B22DE8ECA29A530B7E82391FAA9DEC132BDFC6FC8C4D4032F261B0AF6F87048487447042BD68BAA58D27448C8BD4B06478B0435320CBEFDE9CD7290FFE8EE00AC118058F193CE8F8634FF3963AE9D3AAE62D14D2812E905108A02C0047D90BF5B19E1AA778B8B2625FC80F5829FAA7A5DC07140BCBA05849D63E6013F36D268584E6D8CED89EC0A2736E55B53B5C0AF1E21FACC3DF938083804BDD4D8838A0F4AEB03631410590A259BF355C284B7EC93255909F282C3974A672C7250B47DDCC23FC9FDF41DC67672F6FDAD68372C0E5D497D5D91725D99AAD4E93EA7B10D8F3CFA4DD538AF8DE0267ED921CCFDF517A728B52415504A0B211D99339D9B59C2F1B87307958E138D04C885BFE8668383E9E51E7C4191CE7F83D278600D0517E4E0118BB80B2FDF9B6672D496972F081D469138A271318CA88C397E3044E2B992DC462CF16FD67D259A1D87EC3AECFEB4FCBCDF9A4FA63E495A49EAE58157744A4CCB0A2A74DBE9652E50C90C75DF28ED2EED270B37C47BB8EA5B54E194A11935D03B0B9D226244AC2087940FF0949A424899D4736562BFA161012B4BAC787570542ED203E8FFFC97424221574A6497AE60248D2975268C4F069D545B7F14311B227C9E12356E7E3F21B4165481D41A5D0AD7DA67FB0D53CB42F043AB885C6ABCB07838063AE6367EDB9ACDB64B0DEB8F6DE989E8E62275D44E63B37463C31C3760D5772A07BE503890BF4B5F7B06FC0F585C96FC086DBDA3D7B48B0D3FEA89CAB4784376F579906805DD529878292383C87C8C941AB2086F27A6EA15ACE5151A91A168EFE7652B9909B50A226D881D2132A8C23BDA6A5AB74AC3C6E7F8353868A5FA5023354C482B89E0108032627485B4FA89D2EC089303B61C48A68A488834502CE24DA019C49B20338531105B0A22A52D480456D9CA9870258F10F4AA46044234034B5132DB0A6250A60452B94686D27DAC02215673AA1005674458A1EB048C7193B0A604D1F648A227DC500580C04C4103B311C2B4623C538584CC4896C14992CA60362969D988B150B9162099CB1DC1006561397C8450E1DACD09000F43BD521FC2293A24CA87EAFD08C744531F5F0C5AE9D141A07ACD0E65376C863C27A96197B40C43619D0BE286853461A963DAE9DD652318D83922A043BF77CD338464198A9F5137EAD47DB464977EBFE44E6A369CBF87474E97E5C03DB69C7A6C36E2BD26FAF78E2721D85DB65D02D9CEB8F408B59745DAA46643EE63A16F5E2705D3855D25728B222DA24199A571BFF278663EC1F0E62F6954DD4E06DB7F37735F4637CDACD8D559193B7CF1B36FAF6F74E435F72AB0EA252FA5FBC5BB6E7EA6EC2C22CDD90F39B315B5B6C2441C46B9736CF707B4F06DF8CEA523B31007E3BE60D31352F09D7B9C0A4AC60F6521244E0B37E71D9B63A8FF39DFAEB827EB8730F4904E9D9124C1EFE934ED48EBFED5FC322CC2C747DCD2FF746B377414620801DD4965FF4437C8B945E8A6FDD07BE20ECF963155BAF9F479CBCA459B77F93F252E875D14637D49DCAD9CB81F32082F18E6272DB26EA7F676ABA64B323BCC96C53FD5A336E45F2FD32ED4DC20F8EC36EF6B45F021FE6E3577A448E116C75CA0F0684569B9AF075F53FAF3BB2D80320E82F759C749082C4BB16DC8B96DA315F86A84DE3C28133EF431696380EF961E6971F52117F94036C4A308F02C27C860F92F5A182E071907A6E2C0986EE11D42EAD11AEBF4AFD915A67A4955F66CAD94F41BE091D3F266029446129887ED6081AB2D6FA36AE69DF87D5D48DA39A977ECC81FCDBCA00EACF08AAC3A512D8B4FF984078DF15AE7B7AA6B10C921CED75DE3B096482C0428BDF33F1C984D2602CA675CE67225C228706B4FC4A5F8BEA71F41AF82BFC351C1168F0D0D40E6AF06FB31D8F85DCB5751D8B954B5E9749B4D72841645095D769DC45CB7977461D00986A526B1C4BDD451106DC9BFB509FBAE0C092CEFBF37F4793D332FAE78A822F53B1C6285CB901FD60EAB5E4615F6F5AEB121FB712D26A67BEF41449CE9E022F0B93EF495750F5ADA752585BE3066F08557A40539B298A30D4ECE65DCDD2F8C60B0FB4532740A0EF92575D98FDC75A6D259EA11B06950917DA9447B668436619520CB09ECE0482CC3BF0CB849930E3911B94E33451349BF5BC7070A66C693349D1F69174008C33546469CEC113F059D2DC321B43A0CE9E2D9BDD2131793AFAC7E38E24BEDF35616B86531A9F04B80A2EEF5B570E4CAD3826687F7FA57F0C8EA3B3DDD3B267F46A6FB2531ED70FA68D1613B87DEFEAB6209678359C7B9C5DF50E53764832013CBE526530E481C5FEE3C0ADA695A3BB4E95C2A22039D4E12A6290ECA9CBD844B3ABB32BA541551643F105631D9542DA1283AF0E4BF5DF849C7B727C9A61E954C689347A5E1AFD0FD77D00869C453C9B2586656637EB20CC26C1A2499856562D2B8C33DE64DB934AFF16EC946CDFA73FC1E9AF439DB346052A38BDABB1C311B303EC15579CBA8EA0F743E3E012C550B0080A1CCEF33293C43725BFE4D07215BAB48A463143663A8FBFDE1999649E9530374A544F7508EBCDB6986E452BAF77D3AD5300F21F8D20E436267CB137FC6E75CBBF3A920404882BD1566A0323B6C572D52A1951D9480E3FB3EFE4A0D81111931EC9D550694BEF56573D17743455FE9CE38B3845453FB1A973F1C4508AC1E53426AFFC90AC9E004AA4B2E86DA9A8EE5373516392E60038C789022E82BB8F36B7A88041B17F7FD03BCDE1BFC86FBFA689EB49CCD8ED8127FEE730B8AABF7F80282C74E62BF00477464652EE7AD045ABA9E3BD8B6081DED51CF2DD9442F1973A82FB42F57DFD85909D8900F1B18F78F7686A99140B3B14818FFB9350123F2714569DDD9CDD452C7E940D5AEE3E9B882A37C6FD21044B8F002B12BAA6302BE850BC44C5117F6CA9BDD2ACE0B7ACA6346D027700367519EE5C0509FEBA43AB9338C3E784EF300DEACCC5FA66B7CFB3AC36E6CF0FF5AAE5C0FB0F3D081E1F52FC4EC8CAED14810E2AEF99F55AA7179E3B3097F1C78F2FC536369320675662F296A13DD4E9993BC09C89EB8761AE58E9F0EC4B6CFA63FD2D9FC57C119535F0015F62165275C18A926B180BE32BFB7F036DFFC1B79098791F6EFBE623B8B328EEA8E6F9CE4D052CADD00EC5856A4B4F85263B46F5DF8956B7C70F7FF923DDEBA04ED60A1343F9C7BCF679DE71F23178E9717CA2762911317CBE6EF6A3EAC415266A523CA8A93EB3001F7A38F22A0F5AF8DAAC5DC64F1E086C3F5449F530A5F815F8826EA44724221EF37A8A22AACB13C456A76A58E846AFECFC5C434FE6AE9F331C3B8A209D0245F7E41909EEAF5BE0C8E13C0E4EF1FE2CF07D9B59D0297389C2BAE628B3B41C0E1BA01E85CE309597FDA006FF577BFF5F5E2D44BE0D8A86C048DECC68F42EE8E774B677E2BC8B27C1041556C619DEA572EEE31B5871C0B59D2CC3F92531451B976A3A17FB19055EF345E0CB82F20E6A79B69AE4A37E53507E2065433C26472B4FDFCA6FE58B8ABDEA77AFD9FC2972DBFA4C822CA01E8521BF6011A4B0C59FCF7C1266934A7F8A5237F2914451D1F35210F97218277B3A0F7F958C2C64CD2D17782E75F85D381AABDE909493712E1362E9CA36386F863D5FC36CE0CCC508D896477E5BEC0B03DA03F92DA6BB3B33E8A58578A30AF50B509C8CB77DF12FF15AD5CBB34DF6BFA1A6531A17678304C6179945918E2C7532253E148192AAA53685379BDE084942B75D295F343B9B7A10BC0836E43F07460A8BD699CC0111039A3EC6362BEA2A987E33517EF2F9E05C0F2EF36AB71B3E33822127763855F5D03627D6987AE1CB4905ABE9D8985157BA41A192B634F778B4E2F31E9B65CB641DF7405A0477E5D85B58DA6C917C0C0AF756A47B62FE84292C1F99292C90B8C523FAF5439DA62406DC8DAF43F9EBED3A27BCDA6CC87CD04515CF4D730C065F09539EE425ABEBF96FAA0CD1948B39B85A3DCF2E323419C415EC0CBDE2E01C79788B3F76BEE088752AF11A85F05C844B5795024A4C543B8CD02909946A7305B5A29F08D45960E8D0D817E767455C903EF9CE6BDA2F8049296DEDD7159CE3082F47914CFE3A5A409E206A8549372DBAC0E93DB45E408D24F7FE924BB82D690AFB6D1155C7B55FBD2393DBC47AD73A3759329CCD97FD6F66650DF8F7941A010174A3C73A3E43F95D29A0C351F37BD5823C8940F1B3A341CE4D391316B4FE827312B9FD139165BED20E82162641F8167754FC27D8FD043A3D7BD9369A378F60EF8A5BBA199F758DD828A1D5DE233C70B39971EAAE3635D1E36EA8968E0FBC156BA477ED6F32806D283F98D1368E9C57084CF642236FA5E8C7E3521342FE6A4B8ACBDBBA278C93D3BD042AFDFA5F983FB9E4D1924A3A3A7F9A51FB4DFC8519663CD104A71593EC27C6D7A1C1EA40FFB1AB888126B177758590C08C702F08DCD5C8901E50FD5F3ECA458D8EF6FEDDD8756D7C8B79605DD5C938B657CEB14EF3B10FE839FCBAE3F78A591D523BDAA2FF1AFE842785B40984FA90994F3B5EA418C8BB3408EB07B45EF2B6FEC0655535BABBDFB2CF9A5DDBA87B805F68D55DC0E84CA0D9261A0DDC9AB1B40D62B7EF763D101E8A7740D4ED451F2F7F2AC1A390CB1A401B494A42D83FA228EDEEB5C8A0FF083A92FE92199F8DAC6757B22AEB307695E1E370192F261E7DC40B9CA7C2CE4C1A463670E8454733F0B3D5E6747BBDC952E1A8623BA4A56C61887E835367021A01F9D1B3E970A09274C3535700CC4E1B3EE13AF5E7F0592CEE935771E8A67522AB329F279C0DBC3C61D0B2D841156125C31A0BE7893CEF1B5187FF425FC15ADEB3DC679B8248606F565670FC9ED993BBC49F82E88611E0C7FBF0B1E193AE7C69EC97D0B96A19A324506ADBCEBBEA78C0230E50B42B9C7A94B408D2E15D0A9542F78281CE1DB9D2639D5181168C9457086E5C91381B41012A5CDEDFA6D0343AE9B5BA63CBEBC7B15F688A829DBDBCE52950C13F6EC92B68857199023CCF542D653A8742EFA53F2F5CECE9880271C6F8AD41A29FE4D4458F4650FCE8DB85CEB05CA0AA55679CB52921D79B34B2CFC3F8DA076973BF587FDF4B1568BC8BBAF735473B06B871B1E9CD8F1B97931FF498F29BC8354F48F1E6DEECA28F7D198B70EAD1879103702A782AA950B48F9E7AD4070453F2AE6FE74714037F9BD5D5E60C1C49B4DC074CE45AFFB293DF73A69F5649D36E4E214A986D9C4105F15095F332238197FEFC40EF61C2B93B93A672950258828395CDB4B29986774E700F0AA58A28FD2753972CAAA774E54085F1FF68A121E7D5099DE70DB04C82CC9B4C184910A82975141210203BF678299E65282F37649749F31967B2F8ED98EF6648A955BD8432A7FEA66C0ACA27B28306191E4D84C755BAB93E76C71A713467B16B8955E2EDF5FEF97225155525AA4D4A8F5C94AA210C2A156EBB14CD0AA31E840101AAC1DDE3ADCD01DFA5018F1A185617C6C6E31D55BF08DDDDA07D7E7D7B9C5975C91A7B482BAC07019A413DA865A9D403D76CAE7A951646030AC09A9D75F9072344C221A5E6D696C420E4E28279A9DCFDCB37CA26E25D0CF4933A259904481F7996B464896D942629D6183B677598A885449765F6725CE85D3B8A11818BC675E8E846B1FF7491B642F701712B9A87516C5BB4C3640CA442F5FEBE2D9DFD21761BCDBA465A75057CE13976C5D783EE9A575A282BFF6E8B6FE0C2D051C9DB2B8C100329EC8CDC716F61C110A5A62E590A83C3068FDA35CB0BB1DB0F349509246318DE84A75BA4F548CDCAD3A67158C63597F305F484CE72836AF95C574AEADF5934516A81B8A28658467E1685050C6EB6EE712170144D9634A5C30ABC428711D16F68EA6CF220604EF47C36CCF6C7AAFD7E7C64F4797E0CA6738D413095012938F6F071182BCF9027638E2D0C2ABDB0E2EBEE611DAA12AFBA81FF141FCB9A9B1A704E7CC6BA46A3FDC2696BF078917E9F5F259A139AFF41B4D487EACD0A211E1369627471CB53907813C0E7709C13238D972F928F08CAA6B465CF470D9B10C1A0704F3A382B7C28AF7137136D695A06B792BA880A90294E3D4607E734EA6F305D84B6F08190B35119F45557549E76F2A6D972C511DA4A8DFA3FC391CA1C1D61D710174903C200B02FFAB64AAE6CF734333AF50704D2736E4EDCA9D7D49ED994F74356A45B72D1BF29D4130A641095E012282FC9B4451CC51244EA35DE5BBB5036E7F0C888DA30D02140FAA7C13FE39B5CDB127738486F466F1A0E64FDC6477E5ED39B789C686B4D32765B3F8C53A2F23E0A13A6DE3F68E39C49EDA7B209E35B197482BAD27E08021F3D1BC2F99E2CDB34BCF158E44DA31D78D2F12719C26FBF3CC45C632CE3172B336BD1AF9A8A21DF4700727E8A322C8B75281AAC92ED445779530CDCB0E9190662862F2188FFF082B64B655EE348370CA41CFBA58E31B02527855D2E0033426929031A6A3000CA4A5DAB8270531F39468E90E686ACB1E90F6AA0A92663FE20332FEEE85FFA6557B4C9F701F0522F52503378B07821433B3EDBAA0058BA78B3465F3948E9EF2E0ED8CF724FF7995B9A2BFA4D465D8107802CFAA66913AE5119466F50041615FE55D6B22DF2F1B87C2E079DB79B1354F0BC3B25A7A251A47D4AF78106C9B432AAFD0493B63020CCFF8A6B665BA4DD71CA7F66BF61112EE1EA148297F8AF871B15AE7E6F801044A10244D9A9EB94909D15E1615D21E17A577B5D97D87FED853C4796051CCDE1451B977E2DA321782171C14A46715FB8A7CDD06F876EC84A3A9AC4B8C69C0A4BE7FA8C5FB6BA04790FC10EFF59FCA54FAD102E651BD8D07E4ABC3F7F3D6F01A8247513880CCE1D9D2F4A24963E9BF26722B512A3085BCCCF181AEC08868F0AA4B465DECA52DD52FDA393F5B2CF71B268375B31B21BFF5598DC05BDAC4860CD2DA46781794E050531C5526D89485A871A4F3DA308023DF62E9E826D1671340D18279C127301A853B031C5431FB2A61A7C7353CF54792A3271802B9AB82DED968F39A8B5DEA453CC3E53B3643647DD8B5DE46343F8FA6834916D7C25B73A473B7C3E0930949516DD6EA5919509B5AF69922DE571DA9481F6D161513AC1AE47393571E2FA5C8FB058AE0988C420F193E39455E8D071643ECDCD91AA12E58D005CF74C7701962499E87BF2D2256054CB1806126CCBC9F9A8555B2F692B73A45349426477A3AE55188A16CC4D6DF5D8F566D308A63CA5DB8780F4E8391BC989CD3F422B094A8A7A80B9C341F90CB6FDDA106BB01E1DC4390C797BA95D5B1070CA590422037EE8DF8248AEA6778DFF53BD01830C264CC23703C9375BEF144464C319105AD79069723DF0E89C526D4F1977375748A5E5F40A81F25157E795A08C82B3C017FFE55DA0814105D47DABB254FE6B8A729B8B30AD1E7148DECB32BB98D2A085371D9005D71B26C5F92E53E27FAB2169FD91121B31B1F4327C00DE58FD0709D5A7B43B720F3F0E950A284A435D0D1D04CC8C9EA39591F856AC54BAAD7C57DC25C52E23C6FDB185F9F8F237EBEACCBB391251F07C0769BAA1C624ED4C51297890DC0DE881F583616740783C5840DA19B5E33F81AE23B437DB928205416E1972454F41B861092834DDEBADF9784D2F8DD594AC65BED2306DD060D23AB50AEA95782368E737770DD34B262FA2FC0D62CD6F8DF3C51C654BBC4BF1251E8822704512D00D91A1274250FB04B83DFFFC02A491E119CB553BBEFBDE58701A4B309C6546F2FF935714BD74708F2E75C9B7E4466DBD23EB871E10A221FC924FE606A3E7FBD7496DE2A61E28387791510D4C395A7BAEE43AC7B7875ACFECC86F52BEC4969EE67F4ABDBCC59AEE9C715F9292316A7FB69349E12EC503ED98E23B3BD095864A062876C869321336CD869F8DED7A3EC5358D668B27F3831575CBA7DE882383ED058F541E75A193B08FBBFEFF097DFF0AA0B6CD6F54F05168107E6B583FBEF452A926636347712257A7C6F1DDE39FFA300EE268DB549CAE831D23FC88E16ADB0CEE27A678446357B454F2FF1824EFD2E3477D8999BF163F18520617CA52E9B092A1C47D70FE29F1905DA8B4288E0CC4CBFF8FEEDD1B622D0B82D17F4B7218B99FA533FE4C08439E83F5094A6910B9762C6B77CDCAD4519857DD58D773D7B875728BB5D1F3474FD4AD40611240F4BD05D112127CC1D559CF64BC0D7E59883EBAA8D4351D1BBA9650798034A12B9DE19F24FF5A0049661DA7641272F4E3EC34916121A1316920D8F7234AD6137AF6110B7A2BD2A6BEEFCA07ADA0015DAB8CA99B934E80BEF990F2344A193F70F4F6F9D1FB8C49EBAA60A9F70C77A042C1E3202750E43D41138A7F7DF1272BB36220DF3FEAB275964BC970F7AF90D3C0AF0B4A9D52B28ECD41013A1CDCDD6A728F3CBC94022FE8993C22AB82C2008F78AED3D256A5B0407AD3A03F716AB3942EE51A405482BA630680EEBB4D767A2A5D1C3385C6D28B9C8F9921AA0AE263E8F42CBEB79DA5F048FD9C1E6E3111251AA4C96ADA8A1FDDC8D3BD5EE9A6660AEC5BD4384F9EF9A720DB411997E1B9082FA1FA0AFFF1B072230F4335A9FB4DA11A5BC1E388977B2D1D0FCBFD26D8757FD68DAC0E387B93BA3C68A9E8B8DE1B7D01571E86619EC519A1F7163EF9E1571B255A0BBA03AD24BB0B0805BF8FE429D8D7F372538A26ED8A5A538FA898214BC6DFF6464E4A7210A6B37104DC7F99096F707E51F4346EFCB4A0C516C6A2C0814511E4B419F8ACE4C0BECB1556A583CE54DE2C157EEDE6B72A5F75A027690128E5FCC0274F2D9A626C6E6EEC91459B75A9F784C8A050E121EB61091281639A541BAC7C92AD63CDECF219EB7F4D1C6DEB3D9565446706775F6FF9B9D8BF94BE57E125E8F9B2A109A5BF86CFFA7BF53F48C4382EDA48343A6E781443D1AEA8BAE42B22A791672EFF3ECE7B649425C5FDAE849F3B53D8C8AD4D52D389FF47196070A6AA387DE108526306AF2302032A7217D23DCBF47DEB06705CFE1958093D76A5FA4C0A2D1EBBAE63B1F3D2D64779DB1E1BF83E82CCEC264E1933FA1A2709D5927C35A1141CFA489EB77DF23448C717A8B3AFB966D0EB957C95277A89C361DEA2F5617BDFDA704BA0E5803BFCE6C85D20CA2688BFF39C6B226AAE593E036CB2143EECA1B10BDCEA1B0230F9B216371E6485FA41BCE5D11AA500D48EFA177490106CE4D9C036DCB793EE5DA9111CFA6A928F7696ABB808BD67CB128ACCFAD100316A879C72EDAB3F6A762C00715A8329656FAF5EFAA92D2C7F51B2D30FDA9EEE322524726CF4783A871ABEF0E476766A70D6C44F0DEF2F4E06405123EAE10988A06FF87791A77B8B8A1819092B0BA55303B2F3CCD14B179F610AE58B7D96B7873C2FF7E4D26449B41F158C488D12CE3FAD4E4247648AC2D46F20EF3D17C64886CE941DF0C89BAC25FAB3573108F025E06EACAD16475B1618A82175FFE60EB47EEA3494C7848D315C84B3A26C10E98CAABE95AB74AF0AC608D07FFA5CFCBC4713CD69342C7F39FDBE3C5DD336EFF7FF21326883AF81C04D7B5BD1E9A9E6364328DBE0AECD1C65CCEC4A99045C8EE400873A538F39EFA04A479EFD79EA6055399D96D228C84E0A35D9C2314E5020F6DDCA02D99E1626F1F6479D9F5E5439BB1F26990351A2B1D19C373B44118601619AB472EDC9C84B18D2B080FBD803B64097304D531B7F0CC64E44F74EA88F5B00B00777CF995171934B5077940F11E43C75C8197E3C6527E2A4EE54BFCB066227A627A1A035C1CFF66625147AE04C9AE47D336F305E018AF95FAD18BF2A3CF8628A3470E62AACA226B9809876E6241BEFC24E28EA493D193984B488BE7FE57DC31CE6F91B08D0EB6CEB2444B7A8767E4F02C7CF687B0CF73A957218DEE4CBC04A957E1E5B48956B385C68D3E0FC98E12DA8F3CDAC75EE9EAF4EFEC77762112ED58A97584B9ADA29918C9C561E6A4F3DBCBD03FD081E43A4986033E6BB6266C6239089C40437CF25E590FEF9143212ABA42E8465D682684927DE6E42AD1B5A54293BDD377D73154679A43B81F81FC06851EFFAF761179424459376454D24DFE2DF8DBD85E239384EA4DC4E9649B3B2CF885C24DFBAE89A2CAC7B8871EC4A00D9E93C2B80E8FBED090297BD90CDC16B7DF588160944BE4EA7F9C6D09682602BC6DFB5D7EC9AFD94A8F405C92AD7E7FA85E87D81AD7549EB716BA9AFE54A004B7099710AB4C5AB3D06C3BB63CF1BB794D65EB21F501DA67223D80D50904731E3A750C893E2CB1F0985B3AC050BAAAEA9E80F306920886BDD702ED09C9D1E1CCD6953DB12AEF144566CD445F2FDA7DED8753D38A2BEB97C0BA39D9242AA44B8CBFC86F5100541673A9B82CCFF0B513BDC56A9B2F351FE664FD342DE8856EACB797E6B0E71AA2018A3AD2E68D76AFE755781DAAAC56C5EE18DAA995297A18B640A70A553B529E3631A039328A48FB7BC704A41DCBB9F1ED8A29CA3D47723624017EFFA231EC11D9B8ACDDE3ED485F773A45B473F4DC473E78044E357EA70B66871E6CDF188772A6FC4BF1AD4477665F7F85EDE80D5B5E9DC5F4B13D34FFA36C41FE8869D14DBC81865C477D9C16F1D100D71967CFF8E1C7BABC09C0A8B0A9681BB02365C430D4E7031DDB0D164B9F3CCAB32DE5C7464575990C548D688F4E7D6260C4F08FEE4988BD9B7A84F5A6FC1C130094A5CC2B49EB50FFB43B1B145ABC198AB095B06D4877A82254CC835F14C875F124FDEC73ABE48D5BA815857F03194B5ABF80C819E2FC8E505423799A533752FD89522EE645263FB123A8427D0FA31CDF8498DDF6917E22A909202D8C9BD650B3E3AA70EA5D982E8C2FCF0175203F6A3AD9AB45EAA90FAE104A0ABE163CBDF2187A58949E2FAE8C9EFEEB1C52CCB9D0D45E8E1553633554FDD190CF03716A80E5B11FBEF8A9FC0067D63327E4C6BFB56713E3F106B4F5F67AC0DB38D5B7CB42DCD85879A5B8C4650CFB99DA0BABD6F2DEC1E687F937EAA6C7ABED969338F5B04467A0589F54F77A6FA338AA72CE04DD14F57F38EFB221B557E03EF2E80D78FCB8DC04E7CCE2037EBC10ED371792A9025682955AB90618C6404644A76A6D1FF1EFABF2B1A42BD60411AE1091E51FA82F05B1CC453BC6D91E22CDD3C5CC79EF6F3B53674B9F0652654E68EECAF32B7B98C80FD9C3E9248547A59040A9094CEB2890792B1398B16D69F3D8F0C342562D16449539BC9D2D8CDCC43DDA867904AC0FE914F02B7C985BC39F531642E5E709B86A0CA58B85D9267F0878BD85C22AA893DC25A2594877197E6C8D07FDB57847C6018309CF91F9064051FBAD01C0D9CC362417E2BF3EB2CF681B4651A249BF99F5A44C395A93F7283A0DFC1D9947D71170C2F1FEAAC988FF0CC7156A9EFCA2748FAF448FEE61A493A05CCB624DEC0C806F7863954B79A8D8028EC4405EBBF5725917144693E5C21FDACF75DCFA5A0BAEE60659B4BFCCC5FD112EA7FE33B68E38767A5E745E2830CF4CF60ACD020A7255CBA58A0E54653FDF448563BB4EC5987ED1F2890B8CA56DE6314E5338E6EC952BC1427441EAA503823BD5E7E52CEA8DB606A7A350E60800FEBAE0AD29B709EFAA4BD45305A6BA1D1A8AA04821F225D4C99B6FA31FAF80936E2C380F448FBF696A42EC240ACFC386C6BD0A83A40D127888E23075AA7EE253688AC981030101B6F6FD62D5C66FED9D34D6941858CF704E43E7BD37440904734145ECB929115733F3C278DA824D5250E6D8758C0A9BD6C40A4E707D4D68C08C9D82DEC3863B632519C110F3DE6099BC4087011BBFB21E4EA6EAF9860CE8C83CB9248D9756037F47A9F31F80ED3491BF98658848739796FADB56CFA722F6956C36825CCE4CC5E63D7E9025F8DB2C223E3C5D90E60FA67BA1B96A44E4500B1A236C85012A917B63E4A0AD33938A8F65F8077C9B9ED8CA56ED27054E06AA10326B6C44459740A2E6928B10E4F5E6E64F3385B64BD49BD953614B3FC572CE2512900F1F9833D435AF66D46133864621BB1CCB156C8724549589BCD608BE46D7BB26CF9004951121CCA1CA4397065F34F0182F77D163873A9E1BA5D0B8C461884498EFEC87D3CA6662B5623A6F338A10C6B0A615D5FBB1BFD965EA843967BB7A1D68FFDA641282C8C657A2D9EFDEB9BF0DDBA7F2F56063E982B682B51B0D7DB037C6F2AE1BCB00624E710900AFD313EAF256860182FEBF57D06C27FBCAEB1E1B7F99C749A6705F9253FF9AA63DC490BEC8E891F206AB7D6F972E8A41D9599AEBFC9FF16BE19DF951BD8E65F162C20C943126F68A90B84A0D7BD62ACAD40C18E3486FB535E53B42ABD16EEA762BF7583FDC81CA7473AC5AAA40B27D799EE5A3107C8A431864C420078E7494DFF4AB0F696B27E837A89E48C608C22D137DFA70D12518F9D4EC3CA4088ABE36F598E1C4F6BAB1D100AE6DFE11A0CC8E8657FFAC018A9AB0C8E5423FBEB4D19394CC655B7D1D60A184681A8017100D1BE77A352BE173E7A8A573DF2EE01138AEDAA135AA3EE46A0BD0D3BD04336B291E8D3C74BD02A8F61363B3C3A9AC83520543FC10365B493CFDD0CF34D77BC84990F5C0836D1FD0EBD86E5C9E84E8DAD8EA796392DBA40EC3FD30645B5544D269B68475A5509DF474FB72D43109E4E924EAC160F24E4C931BF0A9FBFFB2C116F8A5A5CC701FBC70E245196396EACA88A5C4CC7A3B467E5627049B5CCF1AB6B755067A88B38B707EAFD12C424465B4BA02C88ED239D3186FE1044BFC1053C745E64DA76D2D71D619165A89BC0996F983911FE070534B1C881467C72C9D49A4E3E18C3C6E3F7A6CEB85513B41E3BAC46D289D66ED78236E0B6E3A67FB5B8F76E1D92E305BD2658A5FDF2953AF99956B4E814A3391DE1BF071466DDFE2A0890BB0F01A2E0FB13B6F28093BDFEEAB9AF2973553512A895DE9B4059780AF8D4D60529E333076D0404FB1BF67AD07EBF1C87F3A3A330866217083F97CC098923DB59E0D1F1F3B30EE1F30255B4D0801F3A7145DDAE727E83091BB924D5DA7A02D6D0CA62F78DA62B5DAB40B413B92A31CF1BDE0D1C721A52F76E536A3B45F21AFF45F882318F057F8CBEC4B6DD1A614F780DF659C1888A080AA4E3F309A9C4A1AD03C513C7B0AF8CB24C4DFF65F562D92A251D75E5F986DFAE6B7796C853F2CB8128CD8704AE40F03FB6C6A19553F46156695E73CB7FD454A8705C8E12FE43FC97CC0563F6F73514C660382D0FB9FFA3B30708702B5D5362218919FB0BB2C96C0EB57ABDB00D54A06A8BE50E41125BBE1D3893A7B23E5E12A7D3A67F973D80376B64EE3A8ECA631A5AE2174AB1B35E4E71F90A2501597F43C9C022B77761B4B3B5804FD17EA38450F99F14C1318ADD1A5E53D8C8EC5EE76AB7F7D45674D3748929ACA8EADDD84BCDC6727FD850EF955DD63BDE5327382B3AC46E300A34D157695F6BCC42C1C332A9BC6FF0A90334456ABC8BFDB87DE1305FBB13E561F35297FDDA225EA3E8CC4147DFFFD110D881F2AB78E66BF730C8AD4DCED69A5FFD2EBDD88F091E891D5E256487F106E6F0980035762804EAF331D587A4226F58916FE630BBB6A0B09354A6308F20AF0BBF0D99A3E867602F55FA6214B72825C8D7505114A5D4F8BEC0381840FD8D03201E498EF2AAFBE12736E2F77464033EDDE84CFC23D2C821C6EF3EB9F79A08566B177818DAA43B93882A74C138C69D36837437EE704F03718D97813BDC94C09B8AE4A2526E04D0CD2E8B6A02E3FC9EBBD2CF757F811AEDE12B3D283D7A151F4576639C6FCA42E521C82C621E81BB72670CBD3D814188E64D9C1E527B1E060FDB08B60AEC112AFCCCC034C0FADC665C104C9AB4435D63A3033F9F09D3E214A96134FBB10E9C48A636ABB4B71FE1BFCDB23DCEF9D0C11C9BE5434790E4A117E45020D5F24B26BE03C74DF41AA34B4863BC0310364A430C731F19248484CE59E26569A6B627EA41753A225991AE74EC5304D704AD875B773C8F914AC850216DC255F8FED1A88C87D8BB445B65D52209E130FE94E5B1A0BAB153A3324AF69FBBAA53FEFF4092BF6E494D959BDEE8A5546BB6B67E018BECA199D27D581E091E55985F6B8E15BE1B1E2BB74A9F35463741BA35F8A57E55A0F89ED220BDB1FD5F62C0E6D0FBD7E85399B0BD2386453726CBF8D36A16D44FB7FD1ADEB14DFADAA07FFFCB672E0D831E0B933190D453A61D25D92DEFA3DAE39F72D582824981307663410DBD80DE94A6B5F12507DA24B868DF2F50496E8ECB2945CD0C8C1C88BD116B2E8206AEEE435B24216D3134C02899EAA4CE95B63DC07148EC8F8C37CE868A1254D8B20285951DFF1EDD72B374300B09F2823C2E6B9B532177E71D9F644936F35A06B598744132F778FE3E0441EFA0731CE8D8AD3014D2D3C34094A81653F0BAD76FE720251F79959794097CF632DA15BA9D137AB36A3F2643982A10B16FA273C2B49CC407F322F1FA87B1BFD46B9C5B279EE5715F4AE11F23F38265F75F54E19BC685670BF40D524774FCC729D41CF77CBF8043A3C657AE59338269B441EAF236D1BD47E926ACDFE03FC30E94370569CFA611FAEED995934D1D2392BEDA460EF857D04163D4EE91DB8F8ADAF27F11C704E0D77AAB25AA04FC820E4AF9C054B2CB4A698EDC5AFB872BCECF48F4717CF93A05E9B89766E1FC0B55D34EEA3F904CAE8571D4A9288C002A8633E2311C582BC85A7606B98060F6BEC36590330CBFCDD0BD11F8E50D5949706D301D02F5A1F7D64D72DEF5B0F10FCB392C6BF53E77D4764DF744ACC9F47945A6927D047CABC47DB1A5AFCF8986F405207FD2F05A36E262AB888B275EF460E9B57A58F731011E107E443D0F746A8CC4AA4DAEC7CC5CA8FB1BC57B63A0A8979C72E7D907E4CCC51100E0AFDBC495621689913688B82706654A84DF5AB963F67273BC6257F5E86679C78551B160391F34527E6540FD9F42964BB33C519C0A9EDC9F50A007A7E0C213787D6384AA3016EE26C60462181C955E01C6D53DD213D09F9AB106EC8178633AF07917297CED18B0204DADD38D1C875E3CF665B8C75730A1CF420A5B143D12CCB2E44A921AE0760A9AD82AD825728342C4832D0A813881C1FDF4FC25C3312401FD861690728ED1D82060DCD05EA67BA98706B817ADD6AF4C2914218D6099C50D71FBEDE7F06EBB40A32E105A071DD6733432872E1AA35EE84F71DB90F361F55C38B581A8FAA02CE7F2585C69BD10BC31896F87419ABEDA0AC5DCBBE7319FF238B676B56DC70B6AA2E30FAE207AA0F55C238D264FC325009BABD79E91240F6DEA1EF6C3510F77FBE07096D0496A87203EADAFEAF0A7AE25C4ACF2DA59E506DFE5CC010A79FE4C5555B24D5681EA8E4A1086673B5C4144FB0B5C7B8BC73AC8CDC22C288100FE8BC325031819A5683CD57EB8825348352961DD5BE1C43E8DC536DF863BA5810F51BED08312A518E2480CF2145C2B4AC7103BC53CDA267E00CD0432443C514F65FD61C4725CDB044D954BCA0C1372DCBC4BEE193E1FE55E2573969D1937D2A02C666BE51A4C273BCEDA910FA183E5492EE8E8E2F98771A726B511C5F8318FAFEF1617450C5BFD1D24EF68238EC9B486422F4266081368F5C75EB636C0401529B2B457ED6948A166857A6FD8CD2EE7FE3F92205E4811D58BF5FC20104549A0FD1CFC1661230DA305A9E43F56D6DBC46E44FF8F237386E82B418C3DD820362C8A0E60866E88354FFAA51EB5FD245E2F299A3703BEBEB4EEE402881F528B3627B56682342F3CD7A1DCDB8808BF470C96E7D35B3F31E7C0B8B65DF8EF9195C12760CF95652EEC4DC0819AAEED970D5B4C0A32FD0587E53584A9E67F34D056B571117943E0019ECE732E893D714AC822A83E55582722BD69FD83A14B94E5265B26F815C2A6A66E9DB68D0C58D5AB0FB5477A3D626CFC95BB31055056A1D19E9422975CC190B4F6FB172FADBC13B125AC569AB1C9DDFF4CECF61B040116267CF773C5285C2CEBB10F7D02DE66C5DCFCFE0B080CEE96637A95217270D10542B0A4D647EC38A029A621DD3EE3FC57F568306C82CD83DE82C20B2DF61EB11877842B42E7B4D5C8F0650541AD26E2B1C5B0134A34FBF78ECD35C64ECA10FB21A6AA3B11AA340307CDA012B7C132819A5E1ED5E66A307F0A038F95B590DEEF3E14B23493DE954BDD8A881A18DCCF5674814E02D4F7D57B40A15FACB78343AA12268D00623E97BE788FB459C6199E4BF8D73F1575D160DAEC6759716ADA1E5351DE82D85AB5DA1A0AAB98A552EF1E156605742E3C5EFFBA19D2DB8D58195B1368D41BF8D6F9E50F80B7127F3A72C0C0E5BE3EF7B1B3B9236F7768157FDE6F947CC23CD926EB030CFCF7BFDDFA04BCDE63C75AB157A8DBC37CB169A8CFBC175DD46674727BCAC25A1C48FEBEEDE960554AC5A7CA22EE2F594F2759462F65777A5E9ABE8A40D96BE52888E84FE3F9139B191C062D7D32118A56EB7FE46DFD149752B93C65B5A16A706A936521B9123DCFD3CE3F0CDD1DCC65ABAD921270E498F2DD2C6A91367C373C103B639ED85E75ADD5C2473C2895BA50A6F79260BF839DB8AD3941A117B3007DB958158ADC6554EA45FA45E18AD72BE24393F03710583081949190BBE4EBB72AA699C518DDD0C74757AA9B7BC8451542F468E6C5FD523707BB7F5895839AC9B047BCFC93E13B9B4F6D2F8F36D0942F5D20EC2073DE446B71F846F54243AF9AA583ED261FA35BA1AEDC381357BE26D5B6BF009A2BD193222FB76211E0722C7E0E2B1DC94AEB2314D3FEEB1E05A5F060DD5C1CE8D1852BF01F2C411EF9B40B72EB75AD4DDE42019B910C2CA6EC0941B36BFEABC36C6CBF6B49D403BAB7D50557B762D7BB54308BB83AFB31445E0561620E9D2ED59DE60064FB89F236E076C427B61D766538EE3812BF8BE5BBF3B915DA101DD587DCDF5941C7B2F9B8AA4E8B6B34213182F6C6FF4C1456581FEBE1C6DEE0725941CC1DA074139EEA7F68F7C9C71E8DB58F27BC6B70C5272200E1E8A429851C11F9C07D68027F2C2F756633E3A6D0BF1DB6422CEFC1C7FEC0E2ED0F30622F4EF82AC732BEC360FECDEC267B56A427EF46BA2BCB46C6BC2C20C2EE40B37BC05A921B777525B154373D96562C9BE374FF227D05ED893172FA920CA14BB635927FB55C0741993B054A17A982377183E7106BA90318E4879BEEE4039A541B9BD4E25C90F0AF1999133A54906A086526A7F18B05D8A2526C7D608515530E628C1BBED1406AE62BF865545935366FF4B635F2E8BE38F6C61EE5AEB7C3066EBAF122E388191C0215B17D9DD822B02C5F8A351713A314BF86FBEF9D46E0729A057A20F8276BCC079C3B1350E1620BB594E0A2B9414A3ED86B3EA5FE5E8A7D6D4D75A6D193FD3C7F5B47D8A7F2AA18EDF48B982D8592543949D5F8C1C127DD5B6D4AB822FB56D46B6FFF6E6DF1851E20E4187C5AEC615396B62FD404E7D81F0B924A68DBB2AFFA2421326311F47997B201F12E52C8275189B6F1D0387CDD90FBA91D32112405FBEF52ADF36B64CF05502ABA204C017AC9CA785510D58B49A426D1A21A2FF3845A7502BA94B502B1BD5961D7075D66C1B871F337BB192B607D8B4F3C2AF59E6168AB03DE174E46082690193A118AAB811765465DC5F00A3FB4E1CE002229B8147957540843F253F2D5106DA8DEC445456D40037505941C9F73FD23650ABE79754D8C9FC7F6115D15F878D389A6FDC630392D908154D76B7699CC8B52EFC5416C868D44417C18423B086D3F97948931902DB00B036803E27F1F851A06CD631F9818D8B31E59BE21B6360317DB1CCC5CAC648B2F6ADBD765280F2C667F160462A676D2E53308DD37A41B879911B986C9B06EB743E1E30005D83AC72DD49A3769D9344BD1F67AB0993DDE178317CD87D70A1B0A7922FDB2D08DB63D3C41DB6C442571CDFCFF67F4F1ACA3826FA156F00F316E74D85D13536CF2D4027CFC4427E4ABB1D27A59F199BB7E174652EDD7922910EA9E8C14F5CF4E48CEADF24F02E1BF84839C126C71433763B3EBB058C5995088B2D5C4B1D4EBC0F6A32BB35831C4E3B7EDDA900A334E04F922E0890D2E11634467E70796557A1F2440A8CF92FECFCC905CC3F2BFEDD4E288C746D9428A4304728FF90075CAE9142258B49184D0663F50D3A5BB3F3C789D046F153F6BC745AADD4AC410BECE0D884B9E6765D765F488D0F0559196DE79B62075D664CE8B84F7095A0AFD0F82DA3D005A4D79A55F9D84ECD84B67BD981AFF992FB78AD933503F6A19BDD6FA53E83011D005CE1A2F0CED7B20AACCDFEDE7AFF8C5D65C72214837D1743B7AFE190328FCC59EF503082464B2C688D34781CD45A95AB5A3D21DB775D1790A724840F658BD9E71D459D6E19B789F1A7B73EA996CA21E637807CA41C4F18AB9F705E20DF73E0A2D0CAA5AA32431E8D894D1BFE1775489EF4B50F3DB76837FF024627D45212D8760CC88073C5942D52D2F33B46F675C1093BD151E5F498355014DFF6A968059CBD06013CAE70DCBC7F0A441B9DF1FCEC249E2F243D5057CCB25BC5DB3E379825458867A694BACA6D5660270FE87BF7C7C4FE031642DAA9C289A5023BD442BA132AC94A40273426FBF7D4C1888835332DBBBC7FCF44821F380BBA1FAFB55FCB19273AA39E3DC1C3D52775135B10B520EA0B7F912BF10A34A8DA3A9C5E3A489040006F34549B7FEA2D67798E14344ED55FAE4C2129BE6BFF220E41521D0B51985D2C946C2DE2836467CC6401CDCB57E5148AADD7CA06819F21E1F86650F8E2EB38B5AFB1763EB691D611723DA0017BF3D03B1DB0A43ECDCAADD5F2A56870CF68B827B3DE39BAE83B882CA8F11604234C08BFD773E4BF86EF5393383FCD282A6C04E9CBB866ACC0E93E4D959D024F93C17759A801A307DB960712E52533DE950EF2C62BCD859A98B74C87EB433D00CE0D69F1E756101C886DEA243A1D814C2A0C2E31F43E1C651F13A7947D3C1C121D13E140074621DDFE3CF4381421635E9C7B6175141F07D8E7AFBA7C583BE4A8877EDDDD88C6CF7F099E8675E02AA2B4A93091928A90CA9572F661C25C53B1BE6CA253E8DB97849904794AF6A18511E4016011385361216E266F4B8C724EAE9F27DAA836E029F234F5EBFD841FE74BEF85CE42D8A4D55452F7A0B07012295D7291AF1E30A7B0FD0FE05AF9EC4FEBFEAAD71697E663D0D013D6E5C978BB98409B5C728461F7FBB3B8C60CE1CF017D47108706497D4519AF9F032538EC9540994AF0AD6A712D48CA8354A3C0490A254600C370802DDDEB6D173827DD88AD32A332D228976A98631E6649767D02BE48DD41FB13663404C9BE88E04818DD3F66746237378BF18DF93EBC694B9D86D6B8626A5B46A29F9A5151E12B4C854B8DEC61A876FA77F1F9A040230B0ABF409C529EE7F10D798622E6B52182C694599469FDE4CF5BA670CECAC3A8B2B90FC4E658549C33F2C9F7E177737453DC47CD11024A8C3BDEFC0657C2DD7900DE3E495B83A168B6EEC0F8C0FCED82A41E2F4BFCEF9876232FAEF4B7427BFC5489EDBAAD9677F7F00914067EE96629C53AF3A3B566C2990AEB1DC34E47D7F7CA8536C931798FE5DFFCB10A754041EF95C9D66E8135376F24B12D7E039CE23D8A93B5DFCE8C5207DEF9D139D69EB375055B262F88D7A7637813B260DC353EE8F0931793D6967707930C26885278403E5AD778FE086DCF057D81E4C2FA2353D5F855E2481A746F32C78DEFBBD94F3AD17430E155A2D3917F761E861501B8317AA78AA258D6D987D9DC2E6D275AC0FC50F9B2268ECAF5077A2B1152D18C0845DEC538EAB1172D63DEF4C6036218961E5397F7CD22C08B44FBADF302E42FAA8F18601BBDDF8CAFF37856ED44C9F2650A0609D7FA1CC758AF1C0070EEA3B2FC088F7EC6E615F8E5EE6D54AA3B0C1200DC51F42B3E76864F6C4420663ACEFA3F7CD1528DD80100B02BCE597D99E445D6C13CE3CCF1985FC6622F4BEECE896F336EC36E9CD6BC3349702FA54EC7513762BEC263FE954BD5D32CD759334FD695B88EAF61265DEFE45F26735447848D0812BF4A86DDF6F93D4F146F9C71DCD8688C1993488435F82707C7738A1264EA36ABB04CA5404E737188B97795556AFF9F397A8EC1F02B9C3553920E64414F1F5CDF5B3DB5230D2EF5E95DFE827D7F05DD23E2DCFF0296094E95F2EB083D8DBF4200B243C9385C18769058522341AA6ED0687754B27A46561AC567F72B48CD92CF289785FEE63852784128CE9D75D831D6CA0D329D79D7B2667F7D74C44BE3F7B2BFFFB017FADC3F158FBCB2228E2B89ED6CC0203D0418C5A4ECA06AD0EA81D186B62F7ABB765345340B83EAE517115EC3108C33C3A1ED8CD1E421EE779EF0C5B51A32FA728F273390C356E0E04EA4B29279F63DB5140B1DDD8F1F5F99A20614AD47F6A458ADE384310D0A0D42A1FED2704471AD16E6FBD6E92F3ACEED4380394F9968DBE2D604ED35C05886E21115B7DBA92BF98FDBE1FAFE3C122D18D3F8D7CED51C243AFDC5E46E1D489AE8DE525C35D9E9CFDCA8E824B5DDAEA228FB5EDCB88853B99C084059BE79074AF7A0302D9096DC8082482FEA2E7C73A2E98001040C7E41F6D9D988600020D7E541A1CE99BBB6E984C38E18CBE3C58CB684D6E9A83F9107F85C4FE2799EA051AD956591B6DE6B53FE28DEE667DB5B19FF8BA7A5D9F043CAF6DB8A73FBB0CE63B2AFEE5EF10EF7F4509D256C996E64B5770E0FCC7F679664B727E4596DE49D1417D92C27DB9526362D6188BCAD01299BE5698B8DC0F39A469DB2361705BE3604D1E1EB7196018324C175C857911ACE054D8053EB8E79766714A81A94F1C0A7AD71046707511F417D4798556A10A17563D75C6848268F5FBBD3335426791E4CD153517600389623C9CF34A169F314A061E7D1E440801A1A5EF80CF066565D88C8D27B7224EC3A2AEB97DD2F2F349CB626D6D8FFB17392930405D0A4177A6BC50A9F1BFBA003467A6E2575884C97232A880E3CB891A9299030020F49DE2588B95EE3476DC1D1C03ABBFBDE3E6677449CFA05FD1F4CC0B6E691B16F795476FDED9184814A8B806A5735E36CE88B0BF3AE09795FD21C998E1A4FE7D5FBACEA8EA9010CD65591051AAF1E72E20EEB889F509BCF08C011A9FBA6F9738B45725434298A82AF4A68FE7004D2BE0742E738F6D7293ADD2AA88225283102C95FC2414661069A2BC0E513FB7354AF304845E0824B2CA56DE548AA586D16A70D0FF9A10B64E60C38D9633409F742994E83303F90D961489A6937478A233F895647D6535AE04419210C6532472D978FEC68C33B3C84BF03B2E8988677B07FA465328A0363EF78ADB07536B522F2AD0425071DA83DD4EF8C49ED9F647F63D31171225AAC6292A8F610A07C97BC29B30A9392D78AD32086AF2F24D514C16635F3851A0C42CF5A856FC39CA9DC89041D7B5EF0871F7C28775BA365F43183016EB7BA6BB873A4A3CFEA25464FDCC222126D8B8D36AEE12F317158132217369AC8C009ABEEEC46CD6EE93C369BF661BADCB82BA7D28D2798EC9AF719994218B7ABF9CCC3008922D85F843FADAD12DE1DEEC5D1E3219A2BE0233F5E792BFBF37A0617F8A28B58FA6222F879400F8E37BB096F5051F5465BCCF19E367524D3830F96FD2D59BBFF831B69272806F586F898607E75F332F88340693F3F36FA836F3F4D41560C2316145D7EB4CB3BEC3F29F68B38C88FDE5106AD9D5FD42A0043D7B282C7AB26E0C557C012BF69F6B07C2EE70882C6422739ECACD7E548C0877A4090A76C882886BFC9503364703C14A447416944DBE6DA3121BFEE5C753F7B25F4485BC3E45C09EDE6CA650D043A30DCBAF76BD8744113E648CCF146F22900A0FD42BECE11F4449BF705C7C7E9221D26725A89EB419BE11B07C051C0584F45A46841253F43E208C7CB6C499FC7214D2F188A560CCE3E1D4CEB8A33FA9F89EA3F97EEAF6A64ABCED47E23A95957FDDA20216A1150776B3E663823A217CB7BAA82B585B911774871FD59AC705013C59E96AF4D9486C205ADD191A2BA81371E9AFAA0CAC0431B49D76CC243FEEB7D2B6B732D5D9B7093EC21E90B225FB83683C852A99BA4A41E69827DC269036001EF00614BFF7CDCF6BB220F3D3C2C877D5213AF2FAB87D559E2AA324F6D8E89F12BF0C5C1E0FF7CF4BF8A99B116A806F3865132E362F74AB26A93AFCDDCB83B0B060D982A1ABCAAD000152307F4BC69977BCF0CC0748B5F0E5CDF1750447A2E9406ECA84A07523F5420D48492822EA3E1DC6128495C4E7F01C3E8779E038BF01547246B00CC48B6FCABEEF821E05E8D5E021EECB139C3533CF411ED525D451F69FE497B91E34D8B1223F1C1EAE23D912DAC06FEEC0B58DFE15D0CB6FACE043ED2D7550FA7CF2EC4EAE836E99DD73757DDE255400D80125C9894D3D58F881C30D54894302DA5F5F47B014095D1F0DCB7E881B2547679BFD146E8D711866FE397F40C32B6BBE6DAAF34A41954D4DAAE412048CD93FEC291312F92AD327E56B1E1081C93FB3EB45493ECD632A30D5CE9638CB550850F90D68AA8F2F58506732719690FE790345372082463D86831534DF436573F1C3ADFE86179639AC11C74FA4815F010F2A2BB1111FA05E1EDF9F48EE473C0D8F68EE226DC08BFC71FFDC34AD16E7155D562D6D24B815F8736B0764CD4671C020E20D3B9AA8A1C40FCD30B67DA5FD5822192B45EEAEEA64DD9B1B885E90B849B67E7D18D746C632BCE2257EAED424E9561C41C8B1BDDEB2F61991EA011B9E04BE3230602D4AD95E8EA5CA3FE479AA422D05022483EC6CBC7511BCFEFFC36BC456C69CE8584F05A7D96971B910741C7EEFDB819ECD04AF3C7852D940A7773C90BAE650081FAC138A5E854635B4C90F51D5204047BA3095DF4B3E0153026DE29A92EB0A9E658ECD01DDBB2B69EF1082D15F6C53C47F570831639F5BC15431F7222DE35B6FD3367948C6BDB274D29CA851B9498E291FC03F36404C3DAB3891A786526B746289629FD551A6D88DB488DABA8B4D2C74DEAB3B44DA811AA02CEE06A5DB121401DDD6DFD9AAEA1A573BBACF09037C7951A32025A1B2FD7E919364C214FB6895B4A59099A8DDDD9E5090A4B59E1664C20DACABEC09C5A32AE378D82DA92C0287811E1B83E00DB3DB55C95EB84802509DD5785F287CB4F205A5176F8EC8BEE330C74FFAAA8A4046342A6394888F3B1E0865A6136CEB520F89D0C69A9A3FCEA846104730F6438309C1A188B75A7C1F6CB81367E576BB710B20505F865BAD46B48F8555BB4E7B3BA2B5D45DDFF25E9DC6F9B0CCAA26EF3E7294C4316261C275021B82F271D54CA7C0A18999CF9516C2847F0527FABC0040042020E7EFA52D9A421FBB1B933FD16E2F6285D00AA6C6083C32A8E1BCFE82495768EC31CE11A0AA4BE301DDCFE1022F763F203E4B590FCD70FA3CCEF104C8946D9D171C07747BD3980260D086805AFBEE844AA2734DC4291AF70D4ED24313881208A28170F243B0FAA3D14693958AC5118CA2ECFC39DB75C7C0D8CEA75FDA750CE66B53203B9E347FC8322D44FA62100E6B5D6CEDEE9CF1C42A52807AEEBD6C8374BACC9F9BE2A4DD5923B07AF8DA6C750D003509FEDD33FDE0190401C324C96BF8DF6BC564E8D518952214F050BA2970D64E82A68AFF2AD35E45853C089678D8F519C3434E26F1D305374DE2AF56E23BCA187429AFF3A3D0921FE1121621352CA134FC1045CFCA966D7510C5AC0BCEE099932558F217E13F1157965119DF3F176DA0A3C25E88DFD3D78607640425693DC656FAD66834FA0940B637DE489FE98D3B3986D9A27DF7A6647FFC1C632BB7E2B3480F3583628DE2D8F2FAED7B10AAE484D90DA6FC9434D3A5EB8E1AF97EFE71537123D9FC28CA8AA4F8CAF80711C0B30B3C1145EB2CDCFB0799645D5AFD0D0EE44ACAE4C5128D447826D20C4625A26DE6045C93D7E42F44D1EB7A44EC71E1F259B791E75733C4BA0BFD4A6625F2D5AB48FDBF33C241BCEDE6240EAD3F63F2D6026A095F2B962D25D1DB4DF98F4FE8AAF8FF3211E5F6579A26DCFF31228EB5B1FF59D88D508882C8EDD650F62FDB32DF11E47318EEE7041AAB7C0874792DD32F7C7DCE8555C8C644F1AE127D3BCD55AC5D42E5D06651E333ADDA6AE2357121CAA3F837FC994D7A2D457D88BA1E8D5FDA23A0B87FE1CBDD59D268EB0AFECDA4FFBE9F5DAE939E0438B19A5025695B6B857AE227DBF86E419242AF14FD829D637AF4A5EE6D5D95618AC5A64B4270FD1224CD8F6E7848B1F7FCB265AE3259BEB5DE238704F3C1B4D4A15819F19B859FEFEFD224120414487DC106BD0225435A8C7234D1B05182105E1E129D2FC060981B09E1FE3A97791F9D0456EC34364D1D63A9A04D9C77736A258D8AFDF6678CD9B09AEDF21C66848D44E07026D59228E473F38915C73646FF3F7BA4C2BDC8F8D3DC301493045FDAC3E2C00CFD3AA8413F34B3DBDE98ED11C88A55F0C3A006656C6287A493565CB93F2B5B75C94ED0437AD8DD422F61A92727182C8CDE37891F49A9610DAA83BB4AD26E9B02DF141B9B2FBA9B97C5D7DEF662CC9FE247D7DC185FE24172AE70F6A0EB7F7608040576174E5F36E19284D546A7F9C31BA8FB533C16758C7690C1083A935003EDBE31562E797D5B8D5F4711B750F00E19A5EEB7AEF2AC182F73DAA7F134614F03E5AFFB282075AB5A27AF0C42274500125FB024F68D151FD64CC8C5CDC559D77AC8872D15786B099C598347E244158251CC31DF632774D73A990B73932134D7107931E875ABD044B04C673CCA3C6DF413D4BFF3BF7F352913DB436D95F46146220D4B6AE3833A5F424D8EB249A18889F799C2FF30FF01C10CE59FEED13717CD352C561134CE565126E443FD15F22CE7ABD79419D55DF85BA0868992741B1ED06F18CB14D08398A564159BD78EF9E2244544BBECE451A16A9614010DEFED3FE36632E661267FEF75F24DE24B3AB748EE9BAAC499A99F6153859CD37C752C92983B2C75F30012C470145B2C2E5C9C57DCE247779D951C15699592BF3D1FF1F715F2FB66797D3182DBA4FDC47D060A98EEAF4486474582741E8B140BC8E0A77DB2BA22C96C9A55C959B8699B636FF3A9131358F7B347F28C28ADD73F9A19AB3AFA1AD858121320C40E7685A9C33FFBE1F66A6F62F40639FC9771646A4882A5D8B4040C1C3439ABBA3E6237462289400DE70BC397B64519D3AA193FCBC6381BCFFC8A0C309C377A3CE9C4BC911C02F57BE8F6611861D09867BCAA7877C7BA6D98C34B02F9AF2949F8A089A075FC8A22C99B43A335712DA3FBAC668A72B4CB13A54F531ED852436BB949ADDF4430D0CA3A0E97BAAEBCEC2671B49C3787C6D04FEC44B74C62F96D57763FB34353C40A6C2196393A146C42BD6994923B558636CFBE7E10E96F6F5DD997AE0BE18525F00B18DFEFD9C356A971737F985184DEBED393D63DE3D8477581A17AE4A1CDE047C32CB30C646EF248AC279D51CD34D92A1EA3E549A4A6DA5EFC2DD18EC3F9B97A5BE517DC6D0D8970E98EC1AC588E9FF6FD230DA1B03ACA5C44BF1DAFA5F049ADB5EE20DED0BC7487E426FF128CE88EB158F54E95DB4ECD89E710CCB12E1E715EC5593B42508FD4DF4E1B206DE5B6DA00D317C9B7EF97A824FD46FC94A2F16D0752134FFD354E90005421FF06A751B8E3A55E9D83EC6F5200A9F1BE5590417E38D1D41935F6F655ED2E8C959E36472FA3EB86BB153D2D7BA61637C82E8A2A8A2161BD784BE171FBAB5DD2F550604DAA51180C827375BDD22492C2691F250997B2288E499CFA7F1CB8B6DBEFBDF03C212AC18CFCB3C221D32076E4B5C0FE555D84E6B3444A1BB8143CA89759440DD31BE1C299E69428B1BE3B38C38FAF934068F98AA935BEBC98AE8A81C4BB7DB9C6A78BDE2884F87E2C4951D86A4586E702C01E485CA5C7D7FF1203250F627EECF5DAA963B73E78BCBBAA3E58E16B4A21B63E8000558E5EDD2F5D517EB9D2102AC21393C6BE607A58FA44FB721A9D44E0ADC2E14631083466F4D68586C35DF5064E1C2FA5F1D29DD84E2582B46D737ABAC8AD47AE2372D57ED09B1BF6CA09FC088A88D3DEF51E2FF905C49BD6C4F967708CD18F4E4A38F682C2B085EEC2F18106F20AE73067E22B6ECA27CAA698A0C97C838767041FE2B9E6A9D7783E1AD7FF817A7FD94CBCC3B4DE23B1573754E469DBC3EE7642E9C29978FEF167624B93FE2B6E1B29366193482179F188230A72F7268056F3AE7BD906F687C083A0B262288BCCE654495BBD5485D3DDA62D630A83FA8BC4B67FD4096D64BC124FA441A917AE83270BB191F2A9778BAAC4DA64AC6543A9B3EB00E26CD264731DD0F15B4488C8FE2D97B5FC3D0742F59065473441FFAC42556EA2A33B6BEA70752FB01BC939EBFA2F6BCF569BF99D72A2AE1DBCEDC1D1B5458382B361D4864E2967AB8AE311923988DFFB110172F215D900FA155D838EF37354FFB8A09AD1214A01C976F627DAE8FD8205970BB5DE1464FD379EC5DBB6EAC6B9D1114C69B1507F44E1C55110F9879C8474A53DFEB30747FD7516EF746CF28BE873AC795E1E9C74D8D47ED379FCFEDEDCCBBDEADC0254D916FCD9662C83D8A7D4C4C561A8303758AE1A17B0FAA328D22A8A75F84A7CF546140251CB64CFFE08FFC90FBCEA9E33C02F813F78F157721B95760F559A2B2EB7DFEFEE60DE013DB67840AB2499DF39FCCC8CB96B9B3DFF06D0DEE5194DFA6906076C2337FB848BF176BD9244ED402D508E8A85D26D09AA03A847128A03436732F65F472346853EFC85F0A89461CFA52AEA106B177059DD4E982C6833041E530890D140F06A1BABD280214AC825E0E89B4DFDBF4C838F2EC4D56E09B56B2D436B6BC9594030AD7D02DA7350C4C01C9E208A82DFE6F5F17EF1E5BC3C678BAE690E564910CA2E1096D9445A802126BD5F9C835F435BD413C9D21A3072DF31A40E8200758EF298747CC9B9AABC10992EC9C3EC0DE62C430DB447D070E6C7C17575C84381F62A51EAE8706C9123071EF3FA87D6C0361A2D3971AE15ADFBAD925912FB1CEDD22EA4A32632B8A575A7AD599F01A0E5FA5C687FC027AEFA2152FC8F8B80004B80FFE922E9E4C63252CD37BA569BD47434090F8B6B8C3B4A8F09ADD288699D819A1C5EBD3F5C7D07C70FF3B9A0D8CB0BFA3E5DC7AEA4E043B1EA0D23DA581B045DA0F9C6D34E0DE2F82B8C6190F95D837FE1BE50CC63A334DAFF78C3F72CD880D597165C10AF52AF011FFFAC92C221265A5C01201E45AEF68AB13E128009B9913281A6CE7BACA789FFAE0346516DF83D0B020631974B35584EFE5828070AC7152ED717891E5E61E3CC009DD8DB0B4D5D5A5C512A7EBBF907E2BE0A5EB59D290C4C92697D130CF0C8087F1EBE69DF7B51C9C1C24036C55B57EF5F2D109311F05F8EB049DA97FEC3139DFF1857F5D415823DD44E2A7F582633467353DF15AB783281AA26216C05BB92B97A8D0B7A30A90FE55FD84E0CD389C5315D23FF8C4F9EF09327AD3153D971A3DF96EE5C4C837F71AEFAB5374E04DC3F10510A774D4406EF0F890419EF5731150638EF6377A10E82009591209ED4B2054F88E1D59A349F0C6EDD72EBB95B249DE77D4CD4E8CBF45508034D41F7C060CC77BB299F49EDBC8BA079C742905EAFBAFC3088AEAED5CBDA3EA82E2860B8C131C0662B304E1A462EAAF9C46B70C6A733D935B5808261F83CB3496ACFF2544430C3E7E46A5107AA1F727F4739B5A07E7D45B50A4D913BC7735BC2DF0BED811011B98B9BA2D9398037C9DA1D927664510D279378B8D14A9EC788270978947E12886B508C83AF44FD612C98FBCF2D5A8C0104CE8F02512ABF9799F8DF7C20B8E4D6EDC74133E2C5159D5C8588ADF005502DD47CC0363FEFE81002F592DAB0DE91E1A74A37BF270ACF240F9998DB2FBF96321A3828232C540582FD6718FCCC7883C1691FCA2B5DB93E479DC4A0683F1713D0C3B28B54FFD77483C600D1C1B351D2C90A5E323A527F535C7855D4CB94FFC6CF7B8F7D8BAC73B51157BA28DDF8B0FFCEC058124DAFBC4652A57A523E104979EDBCD604FCC2678DC72DD2CEFA05AB4B897CBF020110F8906CB49ED320074BF8388A2C75CB13F068BB0C528B2B5404734746D7C582870F840C21DF62E6D9CEEF4D25261E1530D97888A74F6263BFE480C1D039CE290954BDB6B00FC30C83646E295445E9E77FF1863941F156345938FA549E08BAE33F32877E3B07D457AE2E16A9654ACD499629F68C88B8C19324DB02CBB9CFD7A40CE84485574AD43842994ED082E1DE49A80D1EC08E2E2406E6D328AF2354B8B50BE337C2743BA2665064FF76DC04500D1B2BA530B2C9C746A41E8A5C784A2A4D7B339A62E5F5AED113D9FAE155D20A0976CEC12AC14B592DD5B7099564A3E8B5D474336655B3DC4DF09BF1366CD89094C311D1F80A633CFAAD930E42C0223D8B96979F0D03C4886A0EF316C415A20D84778DD8A78CEEEC00788B218ED2104D44B17AC5052FD54C1DFEDA7EB82D5AC0453E6DCDDD7C0BC9CA67CAB1AE10547C8628CAC8EC19A3E1D9FBFE7F14768012E1BB378A6F40991ABE482E19410A239526C82F2C78C3D03F8AAFF4F755AC84586C93221FA644D6F251707166ACD6AC0B4C6EBA19235C44BC0934CAF39D48A65CDFFD4F65F393AFEA932F8B01616E3B5F914E89E84EE159BA13E14847D9BC37E713012A7ECC8E56EBC369F63CF423CC462103D2126547F81CEF2911F6A64FAFA568210D3CACAFE5821EDF8CB68AB859D9D087908265326ED9999D66B39F76BE042E88DF49780554D1963FBFB09A432FBB65805E52B634868B2FA0BD11EB95713F2DFAAD2CB1D744C70B8C45DB9A6C2A10D1B97BE78AB27A1F7508A771A1FC7F7F6F7A99550690510DE18B19D8EE644E8FEDDDE966586DC5FFED6B819061122264018E919ADA6684C0C942E5206D0A55F768812EF05D578B0214EE7ED9DE0E0DF96B1BDF0529E6BF02B4A1992C70FD23D4730C42FBD9D56050B3052810EAEDFC3CC2CA0752CCD5DD292AEAA93C9DC3B1489EF48D15165919C9C2DE5ADDFCD13FEFD864FBB2A3A81D7F48D88508F26CFA2B037AEA6E0CEBF5344B6E6A5C672727107F36F4C734C334FBC0C2F2AE770BE95EF00B7ECD3AC3F8A3FF4F7238C7D6E3CDEB14FB822811A7B1300CE342D3E5CE2AA82615E8E7D0FF719C098110A389D9699F153C4996EEB579F9740BF6E60E9DDDEC0CE1DB42046BB7E8864CC209E97AAE71ADB8882D392A50DA6420F8C2AD83EF34C8B07D633043120766BFC941EC1F81F9BF8BD77D3D842CD1F545C59CA62A6858B994C5F53C4262D0CDC03D014D5B73862DDE364781EEAACFF70E1DFF28498948A67085D68DBF26542C13A5DAC63C957233D4315F7B91276AF4E82003548E3B5A70C376D10C19C2CB6D7FC4DD3E734256DC4CCB172609B8B9173AE96EFB9FC72E85407DB9C72D3168B5C3981AA0A9BF7866CD392DEF4D436039E968CA19595C10B874DE4C6E07D74C6827082A05B775B22B128BF1CA8559BA20A8D688F521318341C0E5520EEA4D33ECAE70917245A6DD37D66ECDE1CBE8056F588CF74FF195416D1120EC6A1E3955A83A14DF6B23203818D7F0A37DAF3392B43B0AEF325637B7A3EA195D3FF0CF883B35EDA2343CAED26B8A8E25F62AD0377FB5E9AA6AA364212167578EC3B2D6DA53687D27FDDD3354A062CC9221887122BEADCBCEAF03C3F2BC72AE8F114FF825200C74C629B1FDF476FAD695B855C5C11306A861D9EDAA5AF313D4C4235724F8A927033D9C511F404CD0C3A32F88A70BA34A3E1B8DD1AA7B6B7410F4463368DE2471291251D4A2BF9D154BC70F44720C53427372C1C1474E23CDACEFE3E68A2C32DA432874560A96F648153D8E845668ED9F4F21EE0229A53F804B878B264777A9979519375099DA87ABEBE47801362DD508C55CDFB40A0DDBFB74A9A5892023E89DD30B3F3DA60ACD655988F12D5A6317CCC3D7173C30B0E30EABDCCAB4C5F28B9E97B824BEF14CE7613097AEADD0993E2502FCEB5FC81E508188F7A6EC12033EE171FC93A9FA7238341EDC3B67D1B46BCC85D3E9EEE092BD0B64EACCE57433F3612CC275CB016998CF07452FB6024958F11DEA6614823FED0E0283584472120034543004DB3F918D8DE61641314B7FF07F8934EBFD46E5955C3FAA10C121C98E54534E647302FD33195011B2F4A1485B9B2CBA4D893831405A4E398DE96862C95DA35A5BDDB8A023B12A92837F3B5AAE0699BEAD2E4E70F743EA61CD6EC5B0144A203033D05C3DC9150BE28AC649D717FCB97B37ABE26E5C3CC25D4B2C846BF735B7202510B1F92AAAEE0DAE69AF2003EEDBE8258C885F89A74F8B94F99F784FBD483F594D62D63404C3CAD9660B238692DEC623653841D270DA6C59EAF0C993A643C467AC01752FBD410B633C270CC733D3F93B5C2A504A65EC7768CE27647E19FDF95DA6DBBB208400D4288DA8380C520ACF3E0E8B4D1587C30FD51B8C3EB02D2BD143B6B9C8C4B9D91AC56B9ACBBA316E2DE01810480BABB16FA27FAB1A842227398CDE16482322146D5A2019B404E3FFF7C2C5DA4046E84789A31FC02FEB5C7090888D52FA24295A209800F4E33D33809D59F1E0222BD5719125873A10FAF2547BB16142F1226748B615A704A22606C3EDB9A9B5354D840F7C5F57CC3AFE903298274E803145F5824ECA5D11D43E81976DB38A330058D087F8BD0FA0F0CC2E66F942764F22A987D818456B265D1318ADFD3F68A625DCAD59EC0BD0AB21F697EC8FC111578F50AB8CA3ADCF7C5932DF44B6539129606C77A2C161C27FCC5035DAC8863FD172761849643B8D8B0BDAAD6EEEFB9EF60373960D13BBE205C0C0946E98B98FBA6A6327B177F7ECC27F6B33F026149B48F67D1BD96626EB0383DAF33E48B6616CB93DC01E3B5A3FAE38A0FB021A9F45F525B34A6CC93AE20E67D07D0726FDEF53A1B04CB035AC0406765C629469AEC3698DF8DD1FE92E2078DEBEFA45506B32C469DED93FCA645E44D3495095CD90E472DE85362044E1A47D14F164273A813D30193A315114D2F2461CDDEDBCCDA3F2410B2A34CF0ED298E116B4494A0E970C4CD015EBA1234CCC17CC7CB21D45B7EA4ED1B32EBBCC304F93E199B877703C7F3A4E6F0D0B6A8AF1AA0142F0C4960337043D57123AF1A883B2D9E651B1E38BED85B50051FB8432A5F87E7953BEC19B5F259E649AB72268E1ADED32208D84C01F6BA41C0B6277DAF19B246EEF2510B869678E6A9406977CE6A7F70C4530D8C398C31068AD4F2B8DDC124CCB1CC96CE6E6BCAA26D2008D96AB964CE73A3724D14F58E4F1033E2B5DCB97630E2B9ADD8093C7A09C7A1A759EC5DC865D99DA0F8B6239D0421B915656CDF8B73DBCDAA2B33F916714324D9D76D9883BB873F57ADCBF721F04CD8273D518669CF8FEC823E2FB7B7E0E7DA3399E724F2F71889B5636D86BF43ABDAB1E730EC42C32DC368E485B3D5D9B04DE0EE56CE148306B8EEA2EBA84F8717B1E7E82DC768260016AF915B036152613EE417420690DAAC5172CC98EDED3E2130DAA0B30D05C195210BB6BCA7F37FBF6D7EBAAB806A0C9FB81C94D35D8438BFC3BAAF7AD01240413E443D7C6D9F493B682F07CBE6733EEBBAB375284D4E08EC3D548163330754E4EE0586FFB093B880E09DB3ECDE83A316977048AA3B4BF67AF983369E27EAAE5B431696E767258F360B5510EE8157EC37CCE243CFCFD48326EDD6A7A8285E046619CBAED699ECA4DE519EE8FD2202CA64AB5722E607392811BED4B2B7B74CDC7D21861FBC7108F58F152B7330298E51B0DFCABAEE099F3658A118833D9A1681BA9700923A06238D6B7560F9572EA7C5C0FD0981A449C840A4B72B220D217012D7F77E5A9602963F85492EB8BD0B635610053081BC1EADFEFCF870D7E1E49B3467940674DDF0D05CC7B28CD5A2D0EF9E8C29A75DEA5519BE9DA41C7E2682DB00DCA0F18C64C22CDE08C536CEC2313CA6943FEAB6083BF71390A02F89CAFF7A60B2AFA918FD19B7E67257BD6383D1D6F18B4FEC217963123A8EA69010385FBE0933AD4F72FD04E218770BA2EBFFE83FA4E255F864BE00C3B799138836E55BD9F269309CAAE9726923D0774A7882E695E2F16952F20A83E9573EA8316A86E807A3066548089284483A0AE5066E448943079CE4F449475454F22551911D2F97A36183BCD2EB2EF556936E6A734DF9BC2C09622AFF014DBF709CAA0D2B099C845E9FA0963A1CA17D828E3947F94E662BD7501D702F79630FEDDE350D3B35F9A5D653792455B2959594EB6F057ED64D5D34EE88CE7431C04817F3EAD968A0CE30C632165F016983C0EA029D60C6A1455B3D2176BC674A78B2B80A0AFB2BA2C178CAD627B4DA6D2D3E57805DE310AA093C978228A0FBBACECDD36E356D1F657828283FA2A64E52D350850E00919270948C9871605B96E180B1F128FE2D76424D409D893507A33492D53825E6142CC3AE4E6085CEA1296A22EB2A4DDBF05521228DEE1798A24A7F02F3E4A1D2EF1911B035FA63C90AC41E11CD97B4BD9CC3B0F9E31D73D314FA4AA8F8CDFA7B395EFF219C7CA150E843C57F638C620BCA6975481DEDABAA2F0A437F118BD210744F051D2F196BAB79E77C65D35B81B7E90F01983EEFBB0A44EBB0FFBCE93D27C911732187E93F94FD7F70758CA6E875CE174E4AE93233AA86CA3F8C9463BDB79898902D7CCDA8B6C75AFDB8E80FBFDA7BA3E922FFE7F4114FADBD9E110B4EE07E110BED7498A42EF04CF0D644D31D3BB6217BE4962180A684E50C4E966BD12E791FD0A5D4CEA4AEFC5F9D75650C5F2FA6D890FECABA74BF04092FD7ACB3D6E1AF2E2C2D1FEC11EF29C46CBAC10B5BAE5AB5F7F7CE55307DC77F4CDE8BC20B362C1729EA49B80F221F79F216D1F9BFB2184754FCE95BFA8E2CF6744A3D8F48308E86B06FDFFE57D0949D02CD1D91DE318567996715E446F4CB428F689BF6E8321BD8B16FAD0C52520F1D34E9435A5DD80186D47C985CAF27B3B62030B0C4B8D6BEB94A66B3E50DBBA117960E15F0482DB03A0820E82D4EACE26957192F8E6FF542B7464A88D1985339CE9BBF64CDE303025FF2E28C7315AE8F8612074279A8F011EF812076C623760F2B4D99155289827C4D2167BBAA423E5CD90DCEEF90CD7757C1D1801161D188FD141CDF6FD8D34D3C861328D2789A5439C2B31AD6E25DC8A2691E03027F84DD23F5F208D48EE79F01FBE7D1F1B62DFC0C95FF8DC813781BA7A8FB52AF75A5821A12CA4FAA8CB4E6B563A09C1809D6D1392DF2327A48F576D1CD0D12A9350002FCD4CFD184C2D6A178AC3E5508CC3797817F7FB53C7F4876612F04B548CDEAB07A961FB1F9B181B9E1F158B30CDC556D8FBD7836EC8BA998CC647BCE09B7B1B5EF88FA853E7523CC20D82C87498A595518FDA57C15C2124FB2ABEBE476D4A8BC43C1148D9663265EB0D31A8434C7598149A7974409FABBEDD2BCC7BC2F7F7C67C3B8EAB8842E8B8E3C033BC5057A9E3DF3C5313D1C3E9B5F3922145F22A2AE02C36EE4C3439D910C12670FCDB8AFDFA124811F99F710F9F70B4A0190997BE84D96AD37F803E43C0B30B91942E3B215C7FF046E9786FCDA12030716F370ED4E9DC540C7E013E974B091624A289545830E5A4B80C44EDE423EF69268838FEB034A82199DC307D762C6885E6DB4FD820D3A9257F19EE54647E004A572C9E165EFCB946D95387C2F7FB7F009749027D7B5D2EC00E66B6029FA0CF55F87CE70826CD8F3B377CF592801F78EE0306B8F6580B0C768733710293C22F6D90EBEA00F17C466A5A8464C824F8AD252CC6BA05D2DE7EC7C2D8EAEA3CBC2F934C6BA94628AD63476EF4B8581E4E6D93DB52FF04EF164720AEA20224B586BB384CD1522E25F82751EBECF90B66CFE0FD61268F47AB3FBA290B6B72E1F49494AAF39A91A040DA46CAE6F1DAD45B739EA0945EE000AD194B8371E3A2F1651760A9112E18E9A81CF3C9F9E87708AF62FD831AC5FAE0B324FAF8CBEE613C72ADD541BE4D19BDB745FDED16D43B2B993EFF7370CF2C818E3682A6E0CD4FA1643546B88AE17F84FE2546568404FF0526820F9BDB6ACCCF5D7CD25A903F36C8D19AD711210A226CEF63E5A1ECCDA5904E4B4EDBCB8D04F5585CA9C71CE40C20C00D7D6C3EF584410A63D0F6C7FE0CA7FA6AE5A33FAF311613D8026462713E7D45400CEB2B7F1D26D6FF8CCFD285907FD654902485557FBFD5AEA1E1B34A855D81F123721979E903B9B7F28052D990A4092C2DE9F27BADD77EBB17AB9D6BCEFCEBFA257E4854BB6B1E9AD5729999FDAFC18C35DBAD9F7F65AE82EDD3846F7077DE80D2E12635419079B63DD8D74FF800719128D5820413F23C1C584CBC90C40351EEC7E4A58653FFF39B1FB47DF6E16AFD7C22201704A2CACFB66ABE3A3CE1AADA21669217E8B8A7BACE87C519E48B065C11D068055F6F5F2F772BE83F6238504A8B6909349EC10AD920C054A87D5845B02D3D155704F2126596F1B7E040E7635F86607E918912EA99C73F3E0087783F9E614209CF281E43D0EECE39A8A91DD0229FD9ACF8DAA4391F05A8176EDAF104B41CFFCDC04E0FB543FF7DE700459102DF56D39D741FB5370A95FE1CF0B5CB61A9FA3B1BC4C4A41D25886E34B840B38F41922F4951B8EBD9A27CD8969F04DC1C90E0F65EC79AF29EEBAB787CE2DCB259EDEADB651E5BFC2A299701644242E90105EBDE029428CBA571FC300E888056B57482DBA9DE91472005CF74783011215A1BE1B3CBB49373A6CB36AD8952B1A4FD43AA6A1973FCBC9DD7F8554EA497EF8E184C0DAB1C3824F1B2A71EEB36B6C0508A4C73CFB47572CA46EB7182A9D9BE6B9EB83C4B6EB3CDBEA5876C683F76BC915C9938DCD81AF4D5237A692A3CBE01A8D63B4B62997318DE3E333AC2E6A931368E2332D0854BF0ACF11C1C3B9A3B61D0673FA997056028F4E60BBEEA6E2409CC0B0FE8A065FEA9FDE966F278AB0292A2132737C5E95618375ACCA6415A97424F0D3E9D6D05EAFEB30309C4B47FD222AB2E7C05ACFE973F75584EA40501B4FAEE6B16F5E55B55F1472EB80BF273E89DE42E0E94C4F1E8DE1CD5D307F3E992850B237489D4550A086B3223C25ED00AD8C107A0379F067D5304B65F640F3AEECC63735DD022EA4D5E10B29077B1340D31F104B4842881C423813501D6FF7108F3E9A351338461E11C26A5AB1F87C90AB4926F4225EE2097A0ED7A76BD921862B4B8DA7B386E3A7C2D96BE316EC28679909A2B48ACBD6BFCB5673E267444F22B5E62F42CA3C0DA6598AFCA41920A4F3AE6152044017BC98190C4B5F28740149654F0F7BF8208FF1660ACD11B8A1C632E65240C02E1614B0610AB75F966F8E0A73983B660F0DF48A88936A3B8C9A6787223528BF7E003EC0FDE43D314F9CE532B1DC1415D4DE940011A44E09CEBA885DF4F0AB93F8F40DE8108F92E166AB78E0834F28FC1CF05B939C8512E3DC9B7851ED9BF503CC0C188E694A1927899F515420FAA32B2E3418C9F643C51CA25560647EFCC890A3270485FD006EA831B101C32BEBEF7D96EB66AC9146A31D90684940833C8187B4CDB7B5D2349CE548C0A30AD021508E4DA4E0DEEB9832E110B4FA09EA3DB1678D924C330BAFB1A3ECC5E573A3B8DAF2DC2E6D752CB9F86AD6C21129552D1155A545E105A26F9A7EC303C5C62DA18C89BC600B150A3F588513F525ECD15026D1AD367A5CB45F00B5AA96C104BAE92C5A83EFE6E2AD45F084484B94E913F20E845BE4ECBC1410C04AA75FCC5435FFEA277689CF36BF0FE14D3816A646AE075897131DC60267B7F0D456C737B9297E564AD22E53AFE7FC091BE17DFB39E5246487CF2AD638978D28F2DCDDE99F01794BDB7E302B6A1C567B6A491F7C87F9AEC05D183EFABC4D055D7055415675FF49DA6A30DACEF1F63B98F3D28C301A768264530A62FA72CA040FE8663B38ADD968B31E79E5B766C5AF32A7C842A8E7FCBD3A2DDA00CA3F754083888A742E0CE9A9A5A475A025C5C6CD78E4CA945E663594F0C73829B34C9326C58E6E7E444FE1F61E5AB0F34B9BA8E643BE940DB470157790BB53F4C67F2834140932612DB525AB27DEC2BC6E87E31824C9682B7758E49F18ADA83564FF31D7D6BA025C65F84BDDF1CA9D0C5F87FFDFE98467DE29107FF63E781DB9B3F68F7F235A9ED02E504D0A24C2968AE2512C4CE176C7494D93E1401C5B6D9ED32A923F02750108CD447CDA8D1F7D82374B256A6B0C083811E1148482962F50F71FA1B0198401E9964BB0733079ECBE2A6337DE17CA8628C3E93B5D219430349789343C50F4D83C77F8912FCC093B1057931FA2BD5D58A13C9AC062B7DD960A31CE2551CFBF68114A53FA20ABAE8331921A04A3697FE33762DAF300802743D75FCE4EE6E65ECC7ACA82E303BA45435FE16C76DA64846C705EF5560D1F703E2CC05A49C6C2991DA77FF95A24236800EB6A9F7E75C49E8D3A3D6D29EA3AD887F586132987BAB779699744EDB3A8D7B9FBA08AA592C99BD0057F6F726B562FC1A178181FF52EC3FDFDEBBA8AACAE3116A1C0B1313A0FF9CC2EEC50E5772F45789F2A467010D3165FCC23345F725538EA8BE335FB0A4074CB0C23C2C51E3EB031B7ECEAD16BBA0BDE38C20CD24E4E835E324B315C454A5557D1AD3A889F13118C6DA73223ED4BEFEB1F7960EFE7FEC66218893475DBB99D574A36BCBC09CD0F920B9FD8CFD395F481B8D7F33799C49603D01CC4F844350EFF189E0FB1FA1636F96B356F542DA3F8418384DFE01B84A1BAD8EE971195219D67C924E4261BC6C7F841EB4E424E75BD1169859F7A6F2FE627A9D5D2451C35DAB9FC8C21153B7A89C61B37F1641340FCC67744892D51A795FE67775D5D7C19F961635496186F408DC53FB8B8BBEF5AD9F9B94087D358B208EFED97945BF77A22AFAC0466AD53F1FF33F371C0DB20446202A019426CA189A1B9740959C778CC8608AF91583BB0D9CA90DA7C1EBE606F1B91E641D6525134789B4A907C17A6D47D4277665CEA41C4C69D0DEC06D21A07C289C7F49F4FF1746305F1E51ED521B1A4ADA13DC631E3B2DBD3F5F946BF38674BEE6B500C96469F1244CFA802858A2C61FF8C8FAAEDD573B98B08FAFB97622B31A1C6F617AEB90C1B09B39DA7838DC6903A477F7F1BD339794F18F91A585CF64F1CB82C291C8302F5E1F40762542419FA3BDA2A5231E4D65E5A11318CF7D0CE550B9A2E93EC9937637E785575212AA136002CDB29247FD84BF7B3F1E60943E73D4ECDDF43961B49716251E4AABE35BA47B3B5D318CBD5F15F1837A7536389AF25DFF78352074DE141148FDCC86A35458AEBD7F9C05CC7F1EFAB2BFEABE2BFA1F7BB50FF5B47DF334ACBF52B3AA2FDF372F42512B7740B5920402D983B4C5A05A980F45E79D3BE6E33FAB50CA85EBDBC936BC0144EDA020ECDF2B5824B34B01D9E8345BF870DDAFA830502EDCDB73C1F81A857078039670D8ED4579EA2DFD8D7746A32EAB70A17566D4F2BEF76736B030A881D2A050D452C5B48DCA9487F89B09055B5FB677BEC3988191B4122358E5545759F94380482E84795A255C1EBEA3C340F32293548F0D55C2EC4371AFEA3420A6264A46FB2215CB2E8DFDF7821FC0A132288C74BBD93F6CC2F7318FDCE7113C0FF404C3C11C45495508C2F9DE6186C831AE61C2377A464FB3FE298CFB0DB33127EE8208DEEFCEE1A0FB1958DD3C9731873DB8ED0E30DB423354B0616E808305B31D25B3D83F2D32C548FC9432E9EBE7C4BF61DAACB93994D2364D9A3DB52A5A683E5CA4FA10C848548EC7068DE795C592EAF71F42634C66BA49E398CD1DE9E00BA068B1145F9F61AC37466B87809C3C56DD3F19E6D7FDF070ED6C783B6E79D1C43713F44B1ABA52B05D9B2B3312F2F28210CFE9BC51BC74F5AEE941B80453314D8FB31FD1631A543008D62E9F62D863F436FC15A3135A08082389B5D10C908FCABB5DBD7E42C96D3B3F0D7A6947BCBB045C451078070B589B5C82331BF6D505D65B6A312DFC6E67CC63F610019FF6E1A819450A1ED9129570217D708AC78AA6A7804656FD48A68E72ECC824AF19AE4E1227F2C384A73F4B08D2C981A24A5A357FD0A982A1A4FBF18FD058AFE0884E624F875327EB663D96B2E83CCF5ABFD26C06D118B4BF46B42B4866DAFD1C0F69608A1670A41184DA0E50220A78640A00B8CC0420F70163BD016874732806106A7F67D07E6FF67E0F687F3F0D788BA212502703D8FE00E059035C4906A017004F737FBFC302DEEC00D28E01F8FB33FB377F07A0F00114F74168F2018F7A007A96801BBF81109D3FD1AF22FAEF45984625936A69BC02FC73ED3FCD40A555941CCCD7625EFB7D748EE41FEE09C93FB8B5012D82E9CDF4EFAB3321733087829F0425E9033E5FB7B82FC2E58092380E6B7EB9CC2EA144E38FAF0D78A88DB24A6FA6FF30A982159CDD114613C792DE37F663A5BED7AD49EE48214E18F2E66F7CC4D89E1E1C0A72FA7008B262F541ABEBFC57D830CC319E47CBAB3EF291BBD8DB4A2419C05821A6125EEBB47258803EC768FD1756B46BDF03BBA8F581B69A9D0CECF8338D8A9FA35D9D5CD3E6D77DC5D0C4A536EC4F0A166AEEE6FD0085959FBAF625AD7C3933B0BB1C9E0C2E196915CF59FF120D59DCD347BB38E263CB82F5292C30B7217260C1ECF5EDFD59905586EE126CDCE5BC4373C5A9636FBB21904AAF4EC533806F1126C419F0AEFEA0B3C56AF643FC7FA3769F4E4EB7B3FF82ABB893B1E31027E2D45C437984D61E1F3017E67233B4D43AB0557F916E6CCFC6B0F04ECA7049DC26CA8F7E96199E5F341042D16808AF5F66D44D41929F7502843EC22E5E495134BCA3844A2E568F1C8742F81EF94D77FFC52F29BD5FA6D6E49DA83CF13375CB48372765E858740983CBED16B56782B4AF9821D6A3B76000C61C00F005DEA43187E92D158D21A69D05A115927F7E80F0AF26BF6B94D4F49C40A0200FC9D3A67A5429E0843801A6BF19905871B4913F4D4FF4079939316B41ECC3837A02DD2478408A2DF4DAD4FDFA437E96B37A82C6A7039FEB862C2399113959D5D3F23623B49BFA8C76081E103DEF9785C46D5F2EE10EDCF24D6831FC8794CB548FF4CE2A33871BE396EF142675D1633B081345C914880F1824E6566A0BC9C782F8CCB919AF761DBF5434BCE7BCBAE503099F6D501CF35785E781B0D765EB866A03EED71A8613C352DD71AAC0E1F62728E437C79A10B79F69B67B6DC3A63038153120C5284F24DEE8F77D645FC77163E33EE9BD4CC7E81FF738A73F2B5B8433374D515DE0AEEC104312087368403CA25B25CCC14A21F3CD1D5F8418F51849186EBF10D89F79AD66F8781D0DE36874E2150CFFAD8F9D73C8BA4BA1D46F8F6F62AB912DDF31472B836ACC573E5E3DA7EF683791ED742BCD109A490A48FC033B382D00EE49EF1F6F90B2026B0DAEC92103274A4393B5F0310A3B8AAFFF7FD5A5DBD2882A60EED1E7FDDE41AFE25EEF8373EF2FA2ACF6F2428CD812590032770CDE86FB0AAD97439AE6485B0460FBB7037573FD188B8B2AE6DACF76D2B5C6D2873C4B26940E514057C8206BB50A6EF9221DDC0D041D15E3A912D9882420872C2A3A6DBB1A4B06A35F67D8CCC9482992C1959F299A3923125AC48FE3CF97705A1A9AE4EC8E17454E27BAD99292F09430904AB486860003319EDD4AED83A8CC2CD6FF4EB780A029A3AD96407726DBD08F691DE9160B57DA03954EB06CC4B9BFC38AC3CFBCEC6471C5895AB395B394798C5DE6CD163081C817F1391899799154DA1DFAA1689B7D56176319D64F47B3745E295084A0E4A886406D34D3D0FF5AB1858A2B9FF56F8F0D55201A0A69EC8492C80A044B6C7339BCD55D61963092F1A2FC1C409C78F10853CA6D2D0E88FC17A5533CD164E5E63255942691EBDCBFE32EA29F2529A6C7D06199EE19A2A7B844244CBD48A3D99E876CB63A789605D2B7263CDADB3C3C9868E5728EBB10DA5FCE5E87298EF5ED0A880451E47C22154F7DDE192950A163134089FAC33C402106F2DF95D9AECDEB79BAEEB008AF74977A21B6E216AC369715469ADA668442947A45BBC3095D2263351223649F19EE4975A9BEA73B97786B158192A7DB31B9D42876000BEE52D74417B8D7D5B4482347442380E1C2377BA9DB9943A30A769F1F30E29E2089CAF978A7045DFA51A9BC93B9A60548F5C229690046F7A5756A75D9F4D61002FA980832C9271848861F727898B62569F0FC7B9BAA36032169692363DC2E85BDD8EC748E1546D6B5993D28064855886FC394A62E4ADF5CBB3411684A44CFA3AABDC7820040760E11F02F0D960B74C2C692DB78CBE6737253EC2429B4F110E2958892C7BF483D2698738C9A6F56DDA9F49F2B6E52FE6BDF432A1F1B9C657A3648690536CD7BADEBE382DCC22420AE4188BF635E6E602577F93670470A064B0AD644663A741C5EEB37354C327735037A512574CCD1AF9747E0DBE581F647FD8D2C9A3A071C2798BA29FF7DFF4A49EDD505BA7C813D83ACAA9D2A238A09A65DC6FF1C45C704C06AFF36088432BEB5B12747E251F4DF9E262D54A9D4F8E738763245F01B0CBCB651066263E659255CCCE0ED5631F46A32FDEE43015F282A90F2648BFFF1A6357ADFA2E462CABFA7AA253DB45AC0BA18998CA4EBB8ED2DF6BCCBC11DCF53A412323449DB71DDC7FDEF7833ED8D514FEEB31CF49F44F142D440946D5DC5050499CFB24FD4DA5839A8409BC295BD61F85E06757B34535E31489D7BFA2F2A76F6DB6662A4D201F58746D84FD13FC0F36D8682DE37C05059668FB40406CF3427B5319026CC85ECF259E1352E292A835CA90266F4FF200870301795636AC7D49EC34AE5FE39466ECD1A0983A9E0466EDB2F02E1D4D5A5A03E90A6ACB254D890D777966FF44C4F9B4861B8F2E27C0A11B6A6ACE3E444F9121C531708E81A8E8DC742D30337AF030AD96F3B91998BA4218B78B203B40E976805B1E0F2FF79773A9B63162341FFB61845B9019C1BB62A928341C02151DCEC96A592FFCEA2012FAFB5539F6C4514E251999CF3C590B14CDA559AB38116CF59E2F97225DF991509A47D6C65BBCD031FBC03BBD0E8F8E4722E83DAE10FFE2B2171A0666EC4B1D2052F41D906873E6772521812EA69FCAA427BB11F19AA8EDFF3FC5A8FE38DD83FA1C074AB675513F9DDEC3FEE65EA7FBCD6C0158D1A9FF66156A22356B3810C8159491062113D378DEFA2289B8B4677DB23DB28F9261D482C8AFE34AB597AC9193D8B6A2F077027758AE6D2DEA3269217B418BDEDD3F1CB635EA36330B56BF93B35FBD2BB94B83140DE706B31EA2FE4FF720DB565650A259E00A00276D9E9908F547EDBF6D69E719C5CD805B20762D8587C6725B462F916C9D2979B4A7CB98EF7D9EFAEB46DB24509106B6BBB6B2A828670019A75D1FE73CEDFD648D488F8FAF6AA1B1F760965AF513C20741E93E552072A45592874BE8704DE3B1495D948F533D0BFCD736EA92C0667B10BC40FA02503B706559A715D6E8D0A20612587B68A83EE934416CE0F43BBAACC628896D3DB2117E5A725515C370380673D17FA54037A9B27804BE3FD26239F3F779BC449F8DF92A9C5E82D5B4EEBBDF8D28182EE377EA93ACB3C08821A3AE7CE885C80CE8DBDF1DF219E738A6842D570E0FAA717E3A80DF14408569AF420A1339844E796AF79772C7512F2A3B20414452E8AB1F4129F1B07017CDF76BD7F3B225CA3DDC48A24023FCB0F0C87A541E306227DF0AFD167DD5B89021CD0153CA130C0C27968AE8A55983C3216BA6EEDBA06138EA7269B068691C9EDAEAB46771C8D21EAC16265B71D3DB811B17BFC59445DBD933951354A72072B542760A8E963F1BAD428AF3C5C4ED2C08DF53CF05CB8EEE1ECBC9FE1F3719C1072C4A56AE0313590106438ED07150FDD3B7686BE67554C0D2B2E30F8DB58C62CD88E32D33CF01CF5D147896D81A03ECBCF012B0FDB221F4FD21E2413626AFC6D5EE5ABE557E035A73BE431531FFF70A8FE99D8AEB308BABCF5FFAD7CCD2C593263623F59770E747EACE2D3AAD58280963F5A0776B98746D585613309343A91BB985097EC2F3A53F6B124513C9A7F8A2B42D057E38B24F33B4C8BC519906215E3353669A5BF820FFF02F19B83B3C36308E3C23D178F6D94BE78D8F3000888F5EE4C79EF4CF934F86D77D2185647716EFDF757A223443B229248FBB9DF05F180FE56B042CC97FB5C3A393CA8E672E364142E2E57288186100BC1C49F12EB17EE5DE02FE430BC9FFD72EA5392CC0ECD30B5145DF321A543188E1A6A0B67446C3FF5109E978469568F974F52D27F1B71B7B6870CF3C2813CD6EC8468D3C03C790AB4A562D44FF46EEC3C4E416FA37275A125A81A46C62CA2B9108186DA1DD2D06E884E1C2C4B228A4406B5CD2B4F9C5A69C4F7F5DB078380B6D431257ABB8B874AE63CBB7367EABEA73E3788A05997151CB716961E2D5E1456256AB56BFEAA00AB65A081526E105B409A2F32B4EF6B707B9A50B2719F13B8344C82AC974AFF4E2CD8EF6D9546CBF446E06D05925A24DB3B56DA14C9F4AF68D093D745972675A74A064A17E596F2B73FF871ABB3245262C68EDDEC82A36B09AC32B358CB16AC4AD1D611831DD88E99108D258229C3598DD6DED3A5A7198D3AAEFFF9EBB1FB49E680728DD27B591A6D377E02108A1261E1B6B7DBE7E3FE9B2E8C7BA55941244BDE1C57CE3C2318E931188913ACA88A543388878D8E7E249E7AC7ED99B1B1B42B8CFF868EC7180C4323C30A51B85EC19307A65D3C15C2D27D2935E28AA1E5C56A6F2A1254CCB4B63ABB872A4E80F111BA3B29D101F262E7A4E06EA563D471108EAA05CD53F138925D4DCE98508805D6951234D457F9A389BE6CDB7F55BDD7036D8C428BD07B867436CD32A0D0B030446AB6AD34F1B09EA63B3717F5C0602BE8F6B676B6B4B33ADF6599DC12F889EFD9FFAEDD35702461F74493FF4C296CDDA8C5BEFE316AF6FFE2F307D998E22D28AFE29216D7BBAB21969DAF83B979D3CBF6EDF0FCA28F4A5B446F1E941E615438C6D63E7FB3242A8D8BA7673C56DDFC24906DBBD7A8D49514ABB657ECBB1B3146E98F4A57CC12472F89DFDABD42A698329CE61BC3A6DAB8B77FC73D8143B3253D5E1B5D1A22630EDD5C0C9C9A7EBBE05431B826A9AD6839C2B12CE5EF3104A172281FC330C3D36FD2D57C2A53B0CEC8A72588C5996FBD40942525685C2953AEA20F15FCBD2195887C1EC827B54EF81FB6CA8817421E4CFCFDFDE0D3337DCA144362CEC0AC56A71F3447DD3F5B158E7B8F27A525747548B81F147BDF1C2DD50CEECC6B8C43EF2779DD80E9229D71B584974EAA437F6DB53FBE2D5B2CCC2210BE40EDF0C1DE5972B883DBCD1A381743647B6005415C293AA8859C19AD6A7440DFBB242980B611AE2E64A3BB0D58E7A8584873219E16EC125659428504D1B5A31EDE9717EAE4C1859DDF7BBEAA2647312FE893DA837C6C260E932AC08220772EBC8202440A8D1FA75E93EA4FB8484C44EBDBFCCC46A8ACC926A713E70938C52D72A2DAAEB641AA746C29CAD2CAE7EDEDF3E5DC7BCE75C642F908A173127EDA0C23213E1A4A71D4E70EA44F0CFC83DEE129DBF33416BA6FF43275C6D1DABD609BC519C61ED841DFFE133A95C140319DCBE077149E2BA196DACA1FAFB6E34BB4CAC41769EB4FDD65000F655C3CEB7473737E217E855F3C2056AD6402432E0EBE0686EE372999C48F711E811291302D0EB0EBF05DF1B687AA6E6CE544C709F1AB3C7AB8248E3129CB5F5941013FC84D4877FE7946D92C00D4F6B8FB64E498B02ECECCFFCB76DC4D06B2AEFEF8ACC51B97A36C9C974DAF5D7A7FF9103C22CBA860E1939E6E3564E79535189B95CBD5521D16E335A8A5048E3BD74682808F2FCF7E39383FFC475EBDF67B7A24AB26B47AE2A49CD271E75F379D274BD8406B672BCD93C46A440604F371518ABD35504B701C85DB1677D8A85DC69BB28CC5C08CC4F1532BAB2FC2D859B505BA776E9BDA01026CC55D36ED05BABC7E1142C2475FFD8358263DD674DD99BDBACC1D7C63F111920354D6E0562B980B9F1A3485F82BBA665D49694F7D33C794D6C70A3C0F059F65F9E9028F20221C640EA58088BBA0CA2538F822DDF9A923851C4376A68653BCC109A161883077D163DC6C552BAD4BC6E15F9F0A6D5A082BC387355A4442921CC53F64176C9DE1D02590AB768263C8680440CA9277007E2158DE63396A04CB484BD82D96E2177610FC35021BBC8CD1F1D1A56FB2D8B04713BF425833B3C92541B0282118F5366E6164E1BBE9D6ABDDCD4B2A91BB3A8AC8CF361A9D709281C8C9C3CE625AADF06E4652FE3C8465AF9F842F2308B352DFFB69AF6D63A6732ACE646BE77B4C9FD043673DBDA75777C4B8F9F1072C4DF78AB45010158053CB0E841D81A012187654C2389D39167F112E75A86AFAF7EDA70796863B96A65B01F5A77B9A4176239E37D54ED08EE249D0ADF89F926D2F14AC0CC13775E9376A94A63AFF58975D58D009DD5665A55067C50E43A63935A083EFD98FC7605D66D427AFDBB324D1113D7E4EA67463DF879DE601E9D9F1C5F643C1449616AD79CA6EF404521714B3802DA9411D7B264B3F0C242F82A8E1C12C400FA71B198AB774AE8EA7FF271F38D0D457F785F4A98FC3B4F8F9E2FDD79C374E976A445DFD8F21AD18AD601DDDA99634224FA6925E4A16A34B981ECC795CDBC4C18F169B48D0D5E0CEC99BC172543C5430DC32645ECCFFAABD4F872B0C71EAFB3E159C9869922AC08EBAE908A7BE780729666905BA5C5E93F0A8C2F79162427353AA0B9F326C60B9D02B048D46A97C195E1C0E9F427FA7FE9EAB316FF3D3E6DD95AADD0E158C3D58A67593EAD0FFBF1652907502D3FF979AE8287C8DB613A58022AC5B7A0DCDB92FB6B6EA4902EE405A2E1A83EB45AAA1B040518627CAA2F9F7DB39063DC2FB3F5A2C2A3A8BA88C345EF735EA4DF78F1170D976E8303A57A02985F71C9F0595CAC14096B25501205658CA050059A3E426318EE29A6623024D6BBE818BFA492524E3CB6009B5C132BD3A0E82A15DD0F900E88A30AB75C3BCC5A26F464679E712417E6A94C6D6C9BBA0A9874809D364149A72D1F44FD45F12A2EA5C10B0AB0E27328824800B6B0EE739EE5059059515AD9F67CA237F7F05000B0182561743245901AF31096BC650255CECAD4581A9C5FE186AC9EA4821823CAD1D71A74C14928EBA408A9EC4FFC06C40EA08D53FBB75E1F6FDD9743D6BFBD4A1E63E4D9D312B747732554AA3344269C8959FA137F99422912EFC98CD854EB3A44704641BAD31D8598A18F23CBF246E115068F3D4BEA5F74AD9EF080DE635F1914963386E87062797E063F36601077B882BD1BD3949C8EA5095118851C02B1A37B2517907384CA6958016006119D4A091AC7F4E3EF9F5CFF3E50979433F1468D07DF07684D81033EFEDED23FB70EB142D2F63C69C10BCECF4BE4B1CAB06647ABF97ED2C786AC7F2CFA38689C355BC4A00AB442387093A44F179B125AF1E108277F1CB856ECC909F957B32951F4BE98C34387E69A1D906346AABFAE5F15CBC0BE413E85B00AEF685777D30FCCF62BD8539554898C72AFA95D091100D5038A0142088E6B5181A9CEA544AC27A69C13CEB3D7961AE67499BF8D5425F6C564C1BE3CAFBFDC3E54A0F936EBF48C66C3CBCAF0BA34B43B3EACFBB425D47A7BD5DEFF4606EA7524014AAE0E8B51CA48D80D63830702475CC00A2042A34CD1EFF8193F47C1D76F9C7606D2BF2A667360227C5D5C8155006F07AC5C049CFEFE139090C716C0BA687FCA185575A53A464C82735EF77A0CD103F8E3BD50534630B03910A0C4EBF3731554777F3BFB59AD0D4135F140122F9850AB755B0441BA027DC7B6100295AA487C9109616B4F57831725CBF2BD482A440FE75727543D50F8DAAFEE89099B53A1D3D31D4075C6A4EE8AAC0C7EBBA1372E9A4E820604822B8FD506700B02E072E1DE3C8831A8F2E1A6D4D982203B3E742C24CE668B1B497C3588244F3FD22872EB8BE2865B9BA27C77292718240BDBA6FC2A15C909884F748FFB5AB620520B1C7153D66C42CFD55A39AEA456C59BA62F963FD8D06162DE638CD1D0B19F25445A50EFC39B861DF9B10520F004F871B8DF8A884494FC810ED6D8F9A0ACD9EA1CE0D7478D60A63E9078A4C030E5343608540640F1C5FD2980BA6CD350537F06A106A704227116B39C21797B613F4DDDA16F4067E2F3059AF7612247693D6385EBBB9B90FF0AF4F8909A6B14676E380C85994187F85C65DDAE8AC232309AB18EFF123300F2F81A9F234F6AFF68A6FF1C33FB57D54139CE248828970BBF8174EA07EE83BE46C87062E26BBDCCE9C96A639D431E35E31E603E1B6B70220F31224D82EBCED3F3C1691D798BDA9462F3672C3B79EF1ACE4F9D0BA9035663C34A62CA957E6EF1A75D8239D00D5BE0B54FB2D28953C81B60C430465245CCAFE170760C71BDEF086F41995D24F98A2D5D54F2D0C2D70C3599094C79212138ACEFB06178849C44C6E048E63F104121CCF972E863091FBB961695DF39DA53E1720C26E5E03E6F8B97E8CF631053F190051DA49E2BC04064FDCEBAABF07C86B89C017AD82F7801455212456503BEFCE590AE9E8967BBCC23CBB67A94824B462ACEA3DEFDD5133829ECB3E4075268F69FDE910396A0E01C40D6FBD9E2331AAE1CF300F749BB91A7979F8DCAE190DFDFFCD547F711ED910B8A126C78F598457A9DF72FC95DEC4A1092A1999968DBD478D86070C5C01BE666D6CEAC822E506A293E98B04ACDE0FBEB1585D55A9AC46F9B5FCD9004245C3D77C71DF653F9CA1A29F99967F614241A87B94D99BA01F804BD70AA5FB0369181C11D35B68A62416C1294E584FC4B1ADCECE8BF6C9A5C479C620AB76339C803E5A06EF9C50A3C938B78884C456CFC99F13F61B2813A01D41A19194A6142C68C03F0C81D4A1286CAB15926EAD2EEF98533BED38EB7553E9F62B267022A2D59202E0BE76F01BE6C34B6A26BB44C3F771153CD2F74478636D023E0934C9EB38136364600B568EAD210936592DD1938F927B4F81EB1D83FEF76E8FDAE39ECC945AEFBB085015527D4EB13096C97D868BB1E37F55D1C321788E6423B962C5107DB56646342B90E358BFB67DE32068B89AE4CE0355325BE4FB59B8041965F0C12AE3551210DC160381CD545E432D6B3C74A59450C734C73261D4DD54DE329CCF4812CB6CC4E1B803243F54C52853425C41E4AFB6FFEF9AB1C1CF986E2DD3B0B7490F860B33D30D7504863596DC45B3169BB71CAE7E9E6C2125ACFDFDC0868B9D21ED622C6E213136B6026279A8AB2D6CC0E584B3D2A799190B41231DF3BC80CF00F8144A8F508D9140EE60227C9B5C159595B0115DF245B2C2F2BC7F22ACE989B26272B12FF6E807BDD905817274BF097FD580D48C31D31341A491FDF2DAE27C9E6564DA439619FB4198B9659CEB73550BE419ED3A1237405CCD23AE8943C047295E52D89121A1DB8C918DAAD3EE7CB5D7E17FFDD3AB33428A62656B40292B42607F9236135E498FCCE1BE0148BE6ECF8BCDA1B307BCAC508836C94D9E432FFB93B5B5CD03D1F2DBCD9FD17C5E5571798CFF7688B02BD06E0A2105B80E6EF504FD02A397503A1C60555D70F8FA9E4528B47E6D3B50E4FFFCBD15A15E9E24552022F7E9B446580D5D98CD529FA5183C1A99749CBDB28C9FB17D7E9256D241C697802D96B3FC5FAD76C60EA5918BBCC92A020D2CD443D24BD6B8D6F22B2BCA8CACAF03E7D25D7025F17AAA2F12670FDE2FB13C04E2F32FC1B1AE23C35B137427E10067BB30087EC6AD4B8D6E7CB7B546E00394A542C040E28FC12888C8D6B921E8027E8EB6B01229713C85573B484F77E76EACF3A44001C1F7C8318854840D5C62C29D99850E90D8051D280DC5A4FED6DBBC32F93206B3696840F020A7B368663AEF14C9275A75E8937A32FB30468206E9BA83B940509F098595AF306952023EF40B73C3E4A63AEAFEE312A6523620BAB69BD9ACEF096840448D90C68B45FDF97603C709CE1ED3AD189BA448C17A0423436F66F7F70582B45E416F5CD2E55C0AB4E6F60C580CBEFF1E84AD76FC4BA324AC20A59215844CD6CB9D1AB4764B31BD518A813664EE3B96B3EFDC9D6AA6408E762DBE5F09918863A434C99267207E5741A726443211CF4B3DEED099054128149E21C505D4B47347CE2AC9BAFDD54F76C4AD8769E29D90F23747FF9B5963B657C1F3F514DC91AA02208B47BF270CE2E12AA0500BA8319CF57BB8F1B49A87175624991F0AFFEF0542FCE9DD03D94DB2AE74B79AA70B59BD85015A53D8BC4C49A551364975602B11FBC21878B2D98307ED8117E7F35D28E1BD25E7346D4BFAB1457FD704EB71491AD4B0F775353596F78DD29744F00281CA5A35740CDEF7A9EB085B0A98642A3A1A841D8B02171A0E5B8A8B6698FA1BBFC9219CD9DDA80AF4253E6942CF5A9DBD132F8E3C9F92130DC133DEF6C9E34593AB631E1E4DCF06DCC5277C93E97CC588535C383790C0677A60C125C07B4A371FEE0026561CF0F3230421365AC3CC86EE6E02597A0E6A04B65AF0390A467D2CC6DEC10786D15B40CFBB69091C53ACF512F39EBB407D8942B8CF1E82ABEDAE6965704A9C7612149C532AE1304E750D9B6C13854474C4F48B729E5BFEAF224F42C423640465341E15A85012182C298B643E3BAF88A068D824B52A16186C294CA3BBA1BD9FB45C1E74671E97F4AB2E53DE61FFEBE228AE91C76288E76DCB4509707107F61AA3F1F75E72259AE96A5CC667A7C9ADB85F197D2B7DB62482E576DB7DA08117901E02CBD2F25912841BB4ED9CBAADC730DB342FD776464B4DFE00FC7F7D1093B0D93D2EB6DF74B57661D67870249D1CA70BAA8BB2FB2452A47AA0C44E538EF21DF18049C20432A111AE46719E83083C46456B7F546F840CACAF2725CEFC3508AE8515FE0AD8569A59944BC76850FB048641E3DBAFD8BF2FEA1AE57BB5BF4A6B6280303EBCF00FBF417902443DEF1367CA143E695265F6452C4720C479314797D5F3AAE34D401590A52132D6A6FD83152A019DD6F523D02840ECAA998EB628D012A0DCD890FFEA191A595CA7B1BA59D315778509FCDFBB66F8DD5472D579AB531E26D5553F51ABC98F6A3D630601A358E91A316B94A88C812C6019DA9C16FD53E702664D75E9D987021E929EBBE7864A822113E44ABC8B1E70A5F9FF98162869383E653034C39D3BB9B0699E7C31B095BE86DF271694763CA7E06FE4E1FE184DE76FE5822CC2D180BB7D73F8210AED12F27F9C23707065FA7772EC3C493AFC8A39C0AE77B7AD0D9138FA1B267AEC457DFC54E99C552108EC3D7076099E77A6ABD81C1ECD1776C7E5A84EABD6CF887B9DD69513474C894B03121D7029A39B59974729DEF39D795FE928B5DF98ECCA9007371C7A2E4883A3D6245E46EC8B9A30E67E72CA551215DFA85A4B7F3FC77AAC31A6278F9C476C527B07F6EBBDEF3D3BCB68279E3DB076117179C214464EAC79156841AAF77871C7E654DE4ACE1B883EFADA5C64B94A3FA476B522547A81F3AE9B7F24CD1493BF1F8A5580C0251B5441EB0ED98741414F0F0A83FFF1086222D3ED1341F48C342B7DE4FCF3875B0C410BB86DAF5751BD4154FF6596758D1A75E283F8473CB963E3EB904E281B01C3B51569B90388A191F646B78C71EE5373D5C346404F0312A15E5E0A1E4FE389C49FA2E38723FAB4E0837AFB1828CEC312B7C00B3ADDE630FE75B8BF4AD03DF8BD93B04E14A2AC4A9F85341C1280072F7FBA2711C1A7D54CAE89E2480A648763AAE1F77B685738061040965B21FA7015E4C2D3D0C3AA4061FCAFA0F4D0E91E268C04447684D2C6B843AE4E148FB0D1897D6C1464898135482551C2A0BE17D7120C66E840437E3D365B8D3703C2B9637BD72F3F72E7D10E6A355EF751CC848BC4C8DDB50F00409464C6753AABF73834E8FC6BDBE7EBEF1F0AB4508433FA08C28B4C975DDB34B6F117AD776879567E4EC9C318A7588A791BE3B8474C60BA9FF3FB8CD4446827D56D1E2F3EA51056DAD86B22FDC27FB27DF7F3786DBD8E6338A77DA2D7C50312F16AAC1366F2D522F5F0F03F17ED1349AF149C15F7555167AE1461E80AEACC2C701E1C81BDF24E1232B340462E3D4071A4C546FBAEF9C2D0CCB12B618D10664649E10ECF1AB5F06C730FF72B1EDE37ECFFDB736F7E4357804EC2D32B556B5DBEDE2B308246E8F02C48BB4CA5878F0B54EBAC1A984DCAA257E8A8B41BE20BAC34BA1EACB820790C9D3BDC02DACA957BD8B94DDA1EBE7175FCB3A77931954D93B59E4B6B8D34B4DB2D68B8D7B200C2553B5391EC9496FAF44F056AE4B61E955AF59A2D7A7116C3E33DD1CA80670486A4DB076036ADDE4148D3897A85B868B7697829DAC45E42A7F6139C860706F8679574FFAF189FF3AD61591FD07B2075299FDB1B846BD9149C27CA98A4A3962F73B9E1F22F603274BA434E6007DE3BAF2E7ACE1F29653945D9312F4E75C86B82D41832F772D48F1EECA20346F12E39939A4950A72FE08CA0DE9861A51949DAD34BA597D2A0629461675B1E85EA323E24A55BF917AE99CF53533E4EE181B09FEAB7076865710B3EDC3FF26EED7198B436C49319EB95FAEA8281CF834FBD9DC1D4C9F34C708CF8607061123207433A9D5FE172EDC49E050EBE82842DBF3AE9DFE9BB1705B16DB3C7B738C1FB8D50C914D5E272704D340F448D68DE21949CA4FAFD330A0627AC7F16FFA150E0EB7ED7395C13A2A71C266DDD7014D71DD6C6A04B29A0231F23E40A8833FEB9EF4BC735F02D901E5B4F91BF9A159B2A7132F38B50F06B27FE234D7E82D64305C47A362F7453A54175879E9E55E8D9EF5569CD37C29AA1FB77289A2133E62C70BB471FD719ACBEC27A1A694C15B67E431D2935840E7CD707DB378EAE5AB8B2C28F6ABDED8401FFB2F213D267522165A96BBB6BF02F733978BF2105CCDAA387109F48A792FCEBB640562891CBFC367ACCD6B6235294096E71CF074245AD3C8166D1C56CE710BED3FD141B0FBFD7245615E1B748248DDD926BC92B0E91B4C84EFF568D7966989235032DCCACE0CC180B19EE685C9642C99F086600B4FB2412E6A31231846AEF69C12E75B0687F80AF0F900EC7784BC91EFEBE7B1FA038362ADF6AB33411FF53CC937A36C3E477585D6406C2A3FDDE72119E7594B41B88720839B5AA1D00C29BF76A0B925916573BE3FC5CBAA0DA30930ACFD89DFDE92E86B0A40C6C73C1F6FF6442355B84CFB07EF3E494DE4EB1BE607390867126C62AE7A3AA7394F4DD5106BA819679F7E3BE22196BA0950A2A57613E226AC9A9259BC104647F3C6457603892C66B11B786802A7F59A4CA4C7C5AD57F4FC922C12FB59806DE08BA20C56DB516570E6F3D421AEE10AFDCFE37053F7C316B92ACE19843A4CFE67989483038E7F83B5339E9E7104D9855812186896D1D589D1126D2452A337F93A9504F424468080CD06D8EE012DFB7E5DACFA4C0746DB7FFD2A31360290CA4840F523E01E140C01387E3C43F7879864E08672A4204C3A831A7A0CBAA02D07D1BC8C968760733FC0F9C432A724F4F4507BC7A8884CB441B9442F3EA401A77B1A4EE59B101AD0EFF365A75B5B58860DC7E773BE4DD9E096A188203FE67390D32373059196730274CB2F290EB457FB7C88D0AF52B92819FA61FC184CA8ADCF9BC76E7E6BA980470B558982A6E2AF284C1E01C52BD6F3D35F1DE217C54DA98E0A1785B04F3135CEA9C5FC56003BCCEBB06A25EC3F55048917E6FD39F4969B997D18188AA745EE0330EB93BB67E21175A50C362FCC23594DDAC34D8A62C50B59832F4C1637E9E8B217530A2980368EF8D15D1F73DE11C20A3EAC78C62A1F05070C43A6FB5290B671C24D31032285244344344FB30262A10AA638D7A62596553C8107D472843675B1AC6877825DF270663240731A37A2F7BC543553437ACED0F918C14A16030A79908CDC71AE19ED2637B50E54249161587D2D31C0966AE738F215403A59E4696E1D372332252412C82B87AE4B38CB290DDAF57539E0078A910A1A2686B145EC341F4FE6D23CC7B4E13A2F28F14289C6438213C70A6040737DC61AE3B7D329E2B411CE5C6889A9744DC54D515495E47AF33B21C043482CA0E882DFD0BECC70EAAEFA262B331D4D24426AE0002B7725EAFDA4EB379D0D4A2237B696CF8F837DF042C7BF6B0BF797F5B55D2BBAE808AE686849562F2B41626EAA78AE78BB17778C6E871B959DC54457A8DA59C1682CF77400F3D5DE078501D1D5BEA42B61C18423B96AD5DDAE5E39CEFFF20D1F9AC20D83617952A2BBA5A270A6087BF8923F52785CE29FBB3325D26E8FFB48C8AEA971BCD443C911250610099D9435E92AEA7FF2B21E4DD0185A6AA91B791D757D73F5C77EFF532E162FAD893EFB8BFFA948D79B3E441E7DF489AF8C1271141987DA7ABDAC01E68F79FDB109ABCC91FD1419E22349B9B5A5008927E7AC516D6D7E379DC2F2852AA9FB0A904E4561533A15E065C11AB7137457BB1FA40FA46AB401824EBB48DBD9917AF94CF20EC42D0D7A1C470F70DB7A678A469C632AC264CA1B9F4B9332DA376FC2559831DF3B7BE40C5122154471C90E604A43905E105289339AE7854845A5C2841B238546E536D841C49EFB58D603CCB55CE080F05DCACB460F1A04056CC8F0A62F964E4A0D3DEBD8AD237DB1501E784564DA8DC4609D2919040FDBCE7442AA8934FEFCF1DD273B5AFBE1E6C6A18A8AE82F5D5DC6C8597469A92425549F9AF426521D403914054FAAA0491527F455A025B8CCBEF0079A56F243FAD6EF799920CF612D0CF45F191D01A03AAB9C913752AEDF18BFEF310B92942A5B76068AA91CB3E78B7337BE442391F463BCF698EA3976B9F59E5E1A7426D6946627F969D7A3D1AA8413F6BB7B7288F333FA5E779B552B291A457D4C92D5AFC82A83220FD55774EFB389C2D596C1F9D7812AA3DB24E000D5EB57DF44847385CFE80BF7F9FF00682F700824AB65560DF1EAE33120BAB8309565873853F3FF85D40D40BAC0FFABA7161292A69CF687FBCDAC783FFF799D220522F1E9180AAAC30AB2A5B875B816F6ECBC69003700D8431958196791B51E94B5A728126C59D9FA47DECF2F196200955963CC84AEBD26F6BB2DC30B00727F5FBBD36864C955E767E562848BC65B76BA94BEB0F645C6F9B9B4AA7529FCAAFD5FD440E97598CADE75E5CA6E08E6E27E3FC1A76708512DCB5D71576E706C5883CB63DE04B7E5A87C3FCED669F2D923916D00BC38A0AFD32D3786B05AA36C565D33245314AAAE444573DFE1E6191C14CF1905E26158826155533D923DA3754BB340E5AE8B67A8971A5617B27D36A890AEB46F807BDF35E8F21080D6DA9A7A22D6E15FF2C36896D733A5CA2C529EF4FAD9F0D5CED27E83C5FE2B741660B92715E8724372BF1C00FDFD318642045E2036278161CFC256478C14EED169B290403ED270F69C35117838491EABC7DAC5CD67886A41B4A8150F3F5BC1D2070D2BD9D1022525F28D3EB44054C9C7AA7F4ABF2772934E20C0429FCE15AC7DF6544AA07338C150B159AC8AC7954E5CC7FEF8DBFD3563758D78058B8562C4A39E23A9E509C211DB0CDC4ADFC8518B82657B03B7D337D4E1F9A695D38CD828B19BA392BE362344518479E774C8A67CD99820F0E60A7F23E17E598275810D1E5AA01DBEC325724D82C09DFFE9906C1D9655AFC1D39DDEA7F96D95F79F93F7812391F33BA55FCC2015E4A052811F4FA1C8B18CCE474B38F63C3F0582D6103B988A674D01CC46053C1672736A4BED2212D07689C424031015374EE7B9B3C6D6FB0A6D397ED7FA20A766F723DB4D8DCD61836A599CE53E1FB3C6B37510699592CE52F2D50F0C6C225588C8EE05712D1DC41061E94190C9686507A1992858E505FA5924063BDEBC9B3A62AB3103A1956EC4D0BF36649AADD8369C7FABD492E53D46CB7EBEEA9218DA7964460395FD0D6A6ED812B8C5C5CFD23432F1A288043329D54DA746187B1AC9DD7EC384A9B1BC689D2500B369C623AC0EFBBA94B98FE755C29A783CB45594CD873F85F1E714A458D1BCAB7D6E752B1363377BA7DA528398032E1B3D53A645B65422C15D381672081442DDEE01EE4C85A7FB5893D2D7BC4725E2106DE74DB7D1C9DC72DA45A628899B8FE154D9CEC79AB948ED1C355A6A17936EDAF47752282264968834158C1303CD334DD66D3CA3F04D2E8F0110537274F27C54C233FE4E2D86E4CCEAA20F13A58CD192CC8D594041EAD7486023E491AA715786BDDEC75A8287511BC62EA12D6CDBFDADEE66D41D94950E42A076D903C7DEEC5300A07760FF790660AF3E8C40D3ACAFA2A6E056E911DE38B935D5D74073A8988882AE72B1D23DF9C5FAA84F3D92336257EEF0E60A2A83E2EF61D16FFE75E5C64F498FC598834D6424EE0238471344DBB91FB969A26AB2D7840956DAF03C762885DC4BC3CE13D0235B21635294A0FF2A403A13608492E92CB7CB1EDA172A033B11F85CFBA26740C79C1BB56E64E56C66F27C64FE7CAD233E05A9BD428478746AF7E76A74EF055502E60A7B67430CC404072E8283E1C474ACEF728CFBD64DDAA7C4E1A06FE00B85246CC009544F893D17E16E91B8AB9ACAF6092C8E6AC1227A621071F81DE6F4B91A5F34D98D6B0FCA530F2A5A90225AE4E28B84653852AF805F3A1E9A05965ECBADB5E7A1336F901052D5374B4AFD6064C4130F24083D0A3B28E5FF6B41ACBF1624A2A8853A33219F03195591D264A81E9617AA4D5DB13EDD5C2BEB796E004C750BB323B9BE25D712E437A5825C4E06F11227DE40926E63B20688B6450B4C5E090FDA4C8FECDBBE6A38F7E54CB50CB58ACEB4FD998EB982CBEBD59E2A318FB158A9F11C6D96BDCFF4C12F84E7C8B8C8A547BBBBC59ED6BB515B29DC7CBA1B599CD6E195D37A4D5A2447482FAC6E804932561A53B4B276213D4CAB363311EBE8A6DD29264FB084A616BB90089C9A0E88E5172C81E5B8313084F45C8CE97532CF37B3D430FFEF0AA06A85871C40DFC66766E9D3F3C8E00B7FF5EB98A35D460AA542577F21EAA0219364C95BC43F789433AF57EA9E01F702D19A00D35335949DBE3620877DC28A35E32850CBED72467D6867EE6FF4B38EE7DCE80197771D37E74D523D87E4DD46AFD82CDB36861BA207D0C5B93977AC58CBDE023612B7D6F558338FE25C4D44ADE5B03B488B94CCF753CFC29F4E5935C3C47B5D2D24C876D2237E29C80DEB655C4A06A62FC56EF49633BF48EB7F710C343FF9565FD17E39E75B1E62763FD38840A06CCD8E605421AB752AA9815629CF19ED29CF3EC60CB5217B02DBB454EED8F8EB908241831F6C195DA9A3AB63F1B40E600F453443F2C76BB5266D9ADCB03EDE37F2208CB4C795D55171FFDCC033AA91E78B50D11DAFB8CECB0E97F4F3F4749669F5E1C223486370A525FD26210D60A13813560083A475F9F1E240CC39D162C14B77A32EDD8204BF4EBC77486269C2B2AF4A92C21D1CF9076ED0548A97867BF955B620BA9EEA2EE1D702F551674329BE644B64BEE18F048F606946F38DD60324BAA8D54373FBA5919FD26A295C8B8BD905D8B2992A80701746965C2FA37A298093F29D133AB3685F4C9025D923758BC4557D94C3A09BF0E88D41FE528F373D6021807A22219532CF9CA2A230EB7360BFE1BEC25029C8BF5EA01C2E19783BF8F8587A05F19567BF863C53ED4EEF2EB968F14D983E22306E187E3FBAB2964653A5DA0CFAF12EC7F86C01F973924B279DD8D0A77D0300809745E408120EDFA77A8C674AE9F8BD45E00B00FD335792104DF8AE44346A2A5473E9CD610A939832B4F5272B3D5E852CD7B6A1EF931A08B6D41AA704B1F5DF030928E26FAE7660F9030855C3BB23BB5C34E4E48D201F631313572F14917A4FEFF119FE50FDB66C94A17CC33E58888CE014AE232339148150AC84297CAE90DBD052D18C04A6B7FC84B88B59C8625830FF200A64C67AADB84691D79FB635838DAC49F25D372C66853A801A362D2109B0E20AF776A546BF88A56DDCE9786ACEE06B50AABD53130210F670525C4A7D4D9814636055448A2B3035624B45510FF86F9544FA9BE9A9A047EF756DFE17B3CBA7B74157B10F5A17D86BEA4E56316C578FAA84F4FEC4533AD58058A21D6355F35B7E10DCFA801908AF7596C9DD53DBD82184147DF63D4F83C3CB0A19D0E6889E760046C442BB529DA6343BAECF8D5656E8FE711CAB73ADC03B8EEEED22C038DE6C733A804C849CD180F28E0DB92F4D2872D792F4B494AD1163CAAA589FE51442152DCFDF9A5AFFE4E90F091A0521BE85EA940C07455B8446B48A422F3745FDD768220B5F91D9AD3108AD8E854579E895614C31AC6168E187B23F48D8FB3FCBCF7233CEE7127FAA93861C2838CB691488559F7A18F90F45A034139773DF9E066CE6E63A13D4179CA6DFB1B0263ED3AB5C0F8806FB23932627C94E1B14867876B9EB0FDC78C9675C5010BA0BE47F1DE72A3D81CDACA84A2548D999A9468BC589A71054C31047E27507672B1142B7590340444FE80EA289245083BAD9A3713823AE37B28A901E0717345635F7D945ABF1A1B5EE052B9F5328BFCC1CE26A6AB414EE8087896BFB72F7F6DB33D5792F57D823C7511ED729C1C3C2ACCA5240A616BC35FD6D74A9711EE70BD6A8ADFDB28400AA9015AC6910A90AEFFFD57670381AE62844F878EDF21262FB6C37591156F4F, afterDelayedMessagesRead=1142023, gasRefunder=0xe64a54E2533Fd126C2E452c5fAb544d80E2E4eb5, prevMessageCount=121395789, newMessageCount=121396085 )TransparentUpgradeableProxy.STATICCALL( )-
Bridge.DELEGATECALL( )
-
TransparentUpgradeableProxy.86598a56( )-
Bridge.enqueueSequencerMessage( dataHash=28F38AB85E5993AF06C033681795D0B58E575F69DA51D8F7776163031B5B743E, afterDelayedMessagesRead=1142023, prevMessageCount=121395789, newMessageCount=121396085 ) => ( seqMessageIndex=380572, beforeAcc=2842F7AA3725801C0F7A75BCF58656AB39120D212FFC42A5ED2648AE4E3D166C, delayedAcc=9FBE0DA8D96D0EA9252395D3690B92A54808C1CCC964D3F0F56FD3766487A8AF, acc=CB3746D729B044F323854B5517D1270F191D2C3868EFFEB73BD45CE07226515E )
-
TransparentUpgradeableProxy.7a88b107( )-
Bridge.submitBatchSpendingReport( sender=0xC1b634853Cb333D3aD8663715b08f41A3Aec47cc, messageDataHash=3367145364B5D40F9EBE2EBFFFC95C146D149905D5D64D99A3F37CBCFE47E986 ) => ( 1142037 )
-
GasRefunder.onGasSpent( refundee=0xC1b634853Cb333D3aD8663715b08f41A3Aec47cc, gasUsed=208146, calldataSize=99140 ) => ( success=True )- ETH 0.041528804323971681
Arbitrum: Batch Submitter.CALL( )
- ETH 0.041528804323971681
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);
}