Transaction Hash:
Block:
19430388 at Mar-14-2024 02:48:35 AM +UTC
Transaction Fee:
0.086210115577245348 ETH
$183.68
Gas Used:
1,840,917 Gas / 46.829985044 Gwei
Emitted Events:
| 558 |
TransparentUpgradeableProxy.0x5e3c1311ea442664e8b1611bfabef659120ea7a0a2cfc0667700bebc69cbffe1( 0x5e3c1311ea442664e8b1611bfabef659120ea7a0a2cfc0667700bebc69cbffe1, 0x00000000000000000000000000000000000000000000000000000000001610ed, 0x07d7957da98ee9e2a761b3104e2095f565233ac898f1027dc7f8491ebc4f2acc, 0000000000000000000000001c479675ad559dc151f6ec7ed3fbf8cee79582b6, 000000000000000000000000000000000000000000000000000000000000000d, 000000000000000000000000c1b634853cb333d3ad8663715b08f41a3aec47cc, 8f6103355c87c15dc14a5775b981b064953ed81822bec090e0babd075600e197, 0000000000000000000000000000000000000000000000000000000ae44dec94, 0000000000000000000000000000000000000000000000000000000065f26583 )
|
| 559 |
TransparentUpgradeableProxy.0xff64905f73a67fb594e0f940a8075a860db489ad991e032f48c81123eb52d60b( 0xff64905f73a67fb594e0f940a8075a860db489ad991e032f48c81123eb52d60b, 0x00000000000000000000000000000000000000000000000000000000001610ed, 0000000000000000000000000000000000000000000000000000000000000020, 0000000000000000000000000000000000000000000000000000000000000094, 0000000000000000000000000000000000000000000000000000000065f26583, c1b634853cb333d3ad8663715b08f41a3aec47cc82466b96e508d4c258de1090, 0aca117a920522754c484b0daadb79fbcab72485000000000000000000000000, 000000000000000000000000000000000008d585000000000000000000000000, 0000000000000000000000000000000ae44dec94000000000000000000000000 )
|
| 560 |
TransparentUpgradeableProxy.0x7394f4a19a13c7b92b5bb71033245305946ef78452f7b4986ac1390b5df4ebd7( 0x7394f4a19a13c7b92b5bb71033245305946ef78452f7b4986ac1390b5df4ebd7, 0x000000000000000000000000000000000000000000000000000000000008d585, 0x3bbe8668c3bb0adfb20382ace51849536b3136b91fb0301bf3e6a2c39e63a8df, 0x231b0b5068643ac4f6385be51af65f4cbcc0447e9c1eab48663b7370cb287088, 39bc3880ab5bc857a1b58dc1a0cf0ade0f616f6f5bc8df68f9c05c471892bd25, 00000000000000000000000000000000000000000000000000000000001610e1, 0000000000000000000000000000000000000000000000000000000065f11403, 0000000000000000000000000000000000000000000000000000000065f27393, 0000000000000000000000000000000000000000000000000000000001286574, 0000000000000000000000000000000000000000000000000000000001287c00, 0000000000000000000000000000000000000000000000000000000000000000 )
|
| 561 |
GasRefunder.RefundedGasCosts( refundee=[Sender] 0xc1b634853cb333d3ad8663715b08f41a3aec47cc, contractAddress=[Receiver] TransparentUpgradeableProxy, success=True, gas=1891525, gasPrice=46829985044, amountPaid=86210677537065876 )
|
Account State Difference:
| Address | Before | After | State Difference | ||
|---|---|---|---|---|---|
| 0x8315177a...4DBd7ed3a | (Arbitrum: Bridge) | ||||
|
0x95222290...5CC4BAfe5
Miner
| (beaverbuild) | 6.085958364897976341 Eth | 6.086050410747976341 Eth | 0.00009204585 | |
| 0xC1b63485...A3Aec47cc | (Arbitrum: Batch Submitter) |
10.003062400041967336 Eth
Nonce: 527735
|
10.003062962001787864 Eth
Nonce: 527736
| 0.000000561959820528 | |
| 0xe64a54E2...80E2E4eb5 | 838.593112172161810154 Eth | 838.506901494624744278 Eth | 0.086210677537065876 |
Execution Trace
TransparentUpgradeableProxy.8f111f3c( )
SequencerInbox.addSequencerL2BatchFromOrigin( sequenceNumber=578949, data=0x005B9337353210342FE001F6ABAB6580A211B5DB516FD6662D1A45B9A605D23F13CA18C36BA351E44A6E699AE15C171B34451BC9C970B00FFEEF1DA1A58FE47F9EDFDC9F73EF7D013C72AC523F8BA887952C8D421D46247EE78C288CEA67566E80D6791F22FA45E454CD3039195335A65FC54CF4C48BC918AF631836D353B1899E1880732E53CFD292F8EA410FA48E0D636508B2567986ECDFFF9BAABFEF2DB820C0A65221A6514AA3944E4F3E3358040F45C623287B451A193074A146833160A64016F1164F1B135C72B20268354ECCE2462A8DA23B3523CCDBBB0716F8F0A0B25CCB5880D28010DC10BA108314A8A5D505288D212C95526960417B16653353AA4A1A6322B80FCF8574A7053C780560E1D238C1522E0B20059252C854BBD37FE9EDAFCC7FFAD7AF3F9D3F3295D2973F33F84DFF6C723E4BE3F9F40490BE943E4A93310E2FA5C399CD6CAAD399CDFF5AFB4FBB404246C689B301A431B7AB97E886ADFB7DEB9AF909BBADA895094F579B0FC207B4DBB72ECA0F847A2B2ABC9C7EEF057A6642EC55E0BFFFA301D06D7F27D54812DA867E43BFDD25CF3C8A7CD9A66D0196C42B3EF8A1C82C573DEB97F3C265282740181FFE755A7FCE554A7B6FB4FDFB556D67663C19EC905DE228136CCB196CB063B028CDA634D1854451819EB205FED3E5BFF7CC00F2084A01A8B449FF65D20D0C2C65C1024B315860B0C0495FAE3248A4DD856D48343412C416B88A84C60110405E1EFC0F05DF836EC24B1B2320381A9168ACB8C0F3F58008561699F417527A47CD2A033A072D3EDB6C62369E5283734738121469EBD39C0390861D88B8021C088401340840E32020DC99831F08318920123730467C87A1A6203EB40F8E209D1878234C5F7CE25B3A61F842E8545A28895F1E76E2D54E430D7BC8C13DC84648751B609F90F0788BFF76FEE162FAEE2C9BADD70297BA3781654755E825DBE50A4D990441C1F760BFF0D2C670283B3C121DEB5F5F8460D4587AB4B00598E0CBCA40D2CFD2C5CD0981A0726FBC97E87F9667D149524830F475D28B2D4071506F7F0EC12F7D65C2DB60DBC2C1AB443C5989F10F009F361A103CCBD8A38E81C4EACD0D31513B1A545A293469D7A22315F34B335D329ACABB09EF80C9A6DFE3F53F016EC6880020A4394C4B1C0280006683E2C8D2B114106295355E37FECB3823CDE23B037B0515838E5E3526757FF4E97FD07955498EF862045B449F15AF6F3A48E4115A9243C7D36242E2BFE5F9A787588115D3252CCE740909F90F40C1F7906BED5BCF90CB8B3472E00522ED74CF8188B31068BA3CD10287B1F37CD27D9145A3FFDCA5E58BAAAB381C0989ACC9D45A02048D2040400C5C1864077A65610210457DBD06E121BC486B944C4740D638DF0BF623D9AD92BC65F23C54A400C0D4C5BEF477342443057C27B8CF8953490F442C6192C4521C2D4BA4D03F3B949568ED94BECEB48D61DB93587C64ED518F93ABD5DA2BBEA768070FBFE5F14C621D97B926CB3B8D5660E072FEE3EC5E5D857356FD798BD00F411ABA16766028A0861A90CFE8B8B00D7E8FCC0902AE53141EF8037DD656FF1FE47C00208A2CED01902F4F1FDFC80A2BEFC2F30E0033311B0B0E0010BA669C610040A0907400C0E0BA113840BB51AB87000029B70B0700DC677EAB2703D008605C1500CC43300A5900A8F841FE0C00B8B3D55CF55638B7997F6069A74DE1FFCFAECA8AAA9B52FA4D38656913531E2D08EA9F5C510EC5F4CB5468A3D1262DF8BC13C903CBDC6B2569DABBA9F921FF8B9A184F44E18DB800919C4581238ED5309C2732105FDE85A9828CD779068ECAE24118DC74B7998DEAC19880DB2BC4475451C9D28FC169CF4C9364D2E3CF76F7D3B7659AAB6495F3E36543B5C2245648B06F52E4197371E83D48382C2612EB7800885070974E37C7A8B9C30667FAE00EFFBC51008C35EF96CBD26339D10F90DFB0EB10ED43F485666400D54948010EFB2EE903BCB818846A5A9BEFD83411AA008AC5D8CFF82EEDCF9DDE597156B49C367E5D897905CC9FADB5C60E11017A1D8520EF18791AEB4F59C32DF7724421A91C68C0C12D355FA49B64577E20D234488F43302A572064E64BDE7109CADB8F9E9A11519633B8257DF13AF8AC23925A0AD0FCC5F17B41C1771EE1A58D0257F1AF1CF88187E9E6F0DCA82A728E1CFAD3394C391B1F93E66DEBC898563E89F904382DBC0F8E20C9A3FF6BD558C5FAF13715FFB952F440583E16FDCB85B6E727D2231BB130D25944D0651493AD7DDD9D2C4372CE0B90C9A86A5853EBB435B2E1D7546968CAFD732FC1F3E403BDAB818A44B9FE0344305A3CA737C4CEDAED07250E30A6B10E9F36970AB02419F2C3DB152B51F23A81D7E8F3615A8CBA99BC9AB6AEEC4932F90FA1A452B780EC7475FD2DFA2240AFA3117B87A52A6F004D7C0A6BAD9FD5DFBA8BB8B67DB298B1DD98548B7065C90B669008D2F9E5E56F8D3337AFD7FF633D097CD8781F28DCEBD3F9FE54F9B5EB7AB101823E1C0242825E348FF44C76457FF098CFCE84A7EFA6CA07609E1C726F9FFEA523DF2409428926B185234150B937977100B166B750AE39E57CC5F212448D1BFD702A25F331833E0900DEFFAF7FAD181C8FB6DD9DD18DF3EE52474E47A6A311C0A89A76405466E563705F4E504212F44DF5D2F9BA4A56AFEB6441410C488672F2501B6312E99EE2F00DD0BC0335E061670312E6DCA0C11284227449BC9317232E4B7CE05334E7EFD002482AA9761B1007DA346D019638424043A7E65386F7BB506C82B9C6CF1FE33EE728E2B0574E0AC03983A0A0771FD31F472327839D3D9F5F5170A57C6E8008B489A33438E2FBBA92F39C192F195E4DF145FB3B99948ADD48B0300B0DD53D48CDAD45176FF53C48C2EA32BBF301B4DB7950DAE0C6A8D8AA6E762D47C17102C12BBBE4C0C0CBC63C00FD3775D08A2F741B76A722FFBBFA692771FFA2ABC8C8A89ADB84786733007A57170222FD2442F96351600C2A5AB0FCDB75F71773AF2A4D3D170F4B14FF891127369E1401E4E10C5E47C28148A285D00B8DC7B52B4E8A6815D28CFA7527C7732551EE0191D06E014D022C344090B746F8F035F41E92C1C4266C8C78EB560BB218AC6F99698D8AC4CC0F126F942EF0D12799E843C2A9A79E8F0B755A3AD093D1A7D30DCFB72FAB2F802186F79C900800746478C401057F1B5898250DBC8AD4B0FC2B5CFDCD9A93927A8CEEA2CAFDFAEF3FE8455D09D687965B2B50CCB2BD25E150F50D35BB43FD91FAE750160E7EF0636C4C09DA1B39C30829B11BA3D8E0E378B3816CE86A81D879AE40D87FC16CCFC7D49DC180B6FF10413BA31C5BEC3CB9B730805D72A73A67C0CEE5816F039A457714BC5BD82BFC6BD06467988AA091E0ADFCB9288C7214F70F98E4FCD60B21126297B86C5AA2E4C2BD5F3B12EC3E0967B9157800F134FE5671B464BDE09AA4BB66BDBCD4B8A7D16CE039D1B4BD2B95ADFCB01C648D00018F67BA6937704DEF7390C3FF1E09925D4D3A68FAA9179940858BC83F8C7D251302FD40F7AFFBEB1F5528430909344DAFF5B9E16C2B7551FF12A55F8409C35E84C400E4393BC141EF5A2E006FAF5321AC79C160C7FE5EE20687B5B49BF6A583EBD0E8513C510779CD308510E08CC851077B0DC64AF36C5B31C181FB7488A0C6406AE179C2B677292F1C379C0369FC0B8243C2AF4EF02CEC98A39C05C2940955743055083C7C7776D2C8ECE39F60A8C758D6E3C2EF229CDACD40CC8B038DD3E0764751BF1827C39464D19AA0A259B86C1CC2768FFA42BA4082F071C07670D0BBA690D226C858F8F12C1265BF041041DADE99F69B096B0C94C32F92662F15D23F5215ECDBD29BFC3BE0B5951817CF6AFCC29B38B240E76EA34EC0CE4ACF09409E11A0901C94FC7A2806F6AAF18FA9B6CFBA0560CB2939D007B8B6841C9136FA4F170420FF9F3503CA2D107A64DD640F37B32D133289F0A8C5468C452A4B39F1A86497A416EA1C40BF076F0F4F3A8C2F677A47A988B812E360C7A47D8B80A30469E2EB73E15D08A42B1F6BA85AA26479D0237A12B900427D7716807389CF7D20C0774BBBBDB6A2F6BAF50E8EB02FC324237481D7BED669D33076247FFF788CDBC1731730304B6BE7634BDEBFAC2E5AC1673A8DA2E9A7984A2BB363942F84BFBC888F5CE5C321A00E90A8B50E34C9282F90D4D3F1E88F55CD8B9D945EE6B88F5868DE7950ADE73E705E98F664E9D1248A0195CB209BD6C4DBB723BA45EF0100907F9CE633D2F94538C3ECC7CA3846B35B02BEC63ADA1FAAABE8F51DBEBC9F772A00F0675300F4C560B5D26BC52CD67E844F5F6DBAFBD9B0C92E0F0000F539626FECBC72E6EB6E6D31901317BF6A35FA547912A93CA120300A800A0281C90130080C0101E420100082022FE2A9E641DC1B39F730109C6BFB65468F3D630EAA26FBADF8BCBF9587CA8B315C5F4748206BD5A138B7672A29C67982719DAF093F9FD572A0FCD14160332524EF9253B4C6195F2B56BA2B74A6DD79363F04ADEBF90041AE854E29CD8C74559235DE39C46685BA788E44E0D2B63EE840E8FFFDF9AF07C62D0ADF421F40C2171190C65A27CA0B8736415CD33BFFA2351F1012B2D6CFFCD96A67F562B266214C8277808423F12FBD15A54B8F4365AE335FCBACEC5DB1BCAE6FBB60EFE3C2A441196F56B3425450EC5C62CC443C61888D53CC99B7EBBD9B6C0DDFFB1FCE65140A1DC0F5BCF5D23F8D82674AAE1BBC5DD41FB9AC3038D0231A2618033322F08455BC038B9F0448B054108B8449A4444A94C448BC244A8AA449A6648B2C95A4AA54975A5247EA4B9E144AB1349226D25CECD25A1CD24E3A4847E92CDDA487F496BE324006C9501926A55226A365B48C93093259A6CA0C9921B365AE2C1057E0DA0C9658CA325929AB659D6C90CDB25576C82ED92BFBE5A01C9663724C4ECA69392717E4B25C951B724BEECA3D79288FE599BC90D7F2563EC827F92ADFE597FC81F200410942055530044B70055F08844848855CA8844660C220CCC22A1CC225BCC23F2CB00A7913395409927A670EA183B222BB82F0484FCA6FDCDC1E5273CEA3E6DC36F8FAF2E55180B71527FF268893B8B2005BAEB0E409284A5D62CB2B5BE638702320882B518E8FFBFFC99394CEA50FED36B59DCF7AB30ABCB66BCDEC1160615337FDFC2ED42AEF089B8CDFAFDC710B595137AB8DB2EC249492E87CFD7D4977A38A24085E89B88057E94BB9F373EB9F166B9D47EAB86C95BF3A597A5B5902E2504512301C787F9435B7C5241A806AC186BEEE73D3F93E805951DA44352FDF2369BE4DD64E91BE1A479138FB84F4006445362F0F3A90F2DDDCED405A945E1EC2D9FBDCAC041F5245941651A593A751D21EC2ED840B1C2DD1DF574F4838B023C6091B0F83DA7E0C96EE4CF3BC06508B2E54DBBB8E300D0DEE7CA8835EEFA073B17A954E666C0E9EDB71CE993A9A102E2ED725935E39B841E8DBEFFA5E736C9D7CD8173647CCB39CCF00CCF28BB2CAF6C1EDC8099B49EB763D6963EC7B59ED2FCA0C51A90B47AB65A6366DECE49C6692D02D7BA7BE6F80B84C9EC2F401CB274FFF74E2399F2A38ABD6BFE2D5AF6BDE1FACF9F9AD3275614FEAB93126B44C6EEB447C2D6F6BFBA8A3C93E77EEDC04004599517E7C7514F253347D2E3C81BDF0D9BFFE34429211FEC9DE9BAC28EB50D9884BE699BC444254FF4AEA321E8191E4077C3055FD528DB820BE71A681877845B8F5944789BF7D4CF34C4B00AE282B51992A73B98C658F105BA6430BF96E61A4E8070397C2716ED8980308818BBECECE5A9508305B7EFADB2F23E93F146D7E11D60098D8F5012B14AAF6B7DCF95D67F50FE92C820787E47F6449B791991F633FEDD317A5AEFCA98CADF78C6EC67073795A759115D367A852A13EF46790E1632ADD7A9ED112ED83F0668750FA0B9A0FF5F62D176E9C13B49C818456D80B7DD41ED43F1E32BC5EA6F94F1819AE22245A427D84A8B81CD106026F84F84028F12DE8D5168B810B157A543FCC58D83178527F416A61CC8A5E3863963E187A9A1F5B55EC86F196629200B42F4FE21FF0144F0E7DBA508D416779079D12602232A5BA7DF8F8852DEAE9E3C941421E846455BB91F2EA2CA1E1B5EF1B6E5F2226E85A8A0C584FE6C11F75B592BC4E535AC47F73B3B66B7EAF6881BC384C397905674895286E4763A0451E934D7A379ED6FC7B8925A7FDD362F8205CEB9F0B6DD7F27682E3900390812E8ED16EDA0800C0DE4812C51A4DFD4DF8E7679C767C5268B7FB2294DE9B7554C7267DE294216EFC21E6B426027883E4520A21FC9554451F6CB80A9FAF138E914B7080F738CBCFA57E2F0F1F20F2002F3A73F1AB3ADADFC79D9A12998A793B45A590C03507BE9C6BD6C8025C12EE9F1786360AC4F75DD23BF2FCBA0060F99D16A3A605E28C3683897A7860DC69C7878BC7E88C7283DF3EC3D2826C0313CA28EA8B572503EAE1BDE0DA98BE5206F29B4797F0E1571B6594DE07522F8B550B97C9057CA8BBA6791D0C30549461E3472A4980EEBC341FF835E5AF0CB2BE263DD356F0739C9BF9B3C72261B905230CFD7E727729E9535C6192E7B70BD117BBCBFA55B3D622E57E6A9CFED003038378718209DD7BD150466893C69D50242FD6499ABD7050BC38CEC5429C7D75F41BFDC9B2FFF894E70273893F1948D05B5DCFF9B087F30FEF65D1CCF1D5CFF07171ACA0458B52DCE3038CC62F1C575F069D15D5E7AE18695C1DEE471D2D3832127FD689DEFEBE8F563CE0A8423D0F7100CA487E548AD6D28AF05E20439BEA17F0FAFDD4F5058E7EF9D91B89C09AD1D91843AF73B4C4C60730C471BAC09AB3B69CEFBBDBFCE4E3246F2F1CABDA5601C0B7297E920564C7CF21453232DB809E14CB9D41B507B9D540AA3187FF0C1B5748CDE62E28B59A640086DCC3A31BC228E9FA709BE7AC48D16709BE9B67F57800446AE8FC484588A548CF5708E859A97FAB1E44C10F10D529D4F71B0CC85139AEA552238E5A71619B216E6736BBBE06E0FDDB346F4200D6BA50D99BAA37E7B8D1346289B1F87AB9B857C3CA3B0266D01CB0FE518B5C5A0CA8F23A03F0EAD1AAA97E8D552AC4D3B0CFA0AB39DA70A0A83E1D5F567953ED9D14CD776982330A9BB9D107316A5ABE96A505F25328BF7D112A8EB34A1A92928E8193D055D94BB7FB44A91B0066E4C7EF00F99FAC8F66C4C063BF6067285284444BA88F541F8DA1BEF4285FEA6BEC833A3651F801A27AF9F939CA02447A28CED12C84ABEC7505D14957E2A3BBA99DDB275191377DD9922C655ABA4BA98F7CDF06276A98E7471C007CA2628B82C4AFD5D0FF83CE2AD11278A58978992FB9D883A7741E42715F9956A4E9CBF63F70D797106EAC68C5C0D368F1B6A6282ABD169D1F6CF4B513D5020053376F875E3FCDB37E0435EC739BF71CA874BA502B4E540D4DFB8D2A691AEFDE05C669419D941811EBA9CFBE8B9096F9BD5CE8289CEA5F6FE5AEDFCF59E6B07FD2D79122B80154507ED521EC5F68C34631FEF8F6A55014620FD0A771DA9A100E6041B4F34BE85C136E2E28BA46185FC712BDEF732B1C0420A2280BDB5F55506EB614707BF6F510E20852B8BD7301A8DF2425672171560D949BD03CA1F795BBCF3B4BF79264AE46E0C7B417B40001B5F2FC7110454E18867688ED431F7D2471AAA0CFBD6CADD00090A8D1E343C26C7399276F5363F0A3A10857057DC9D13A0A006CE32F765DD0B593BB070FA00899EF42B8A909C789DE5B35165ECC4479C3859A64694BB96B55D1BFB0BB5970FFB47A4CF2636DD4B4EE6B0057E7A780104FB7B40AB6787D3C675B80996E141FC091845208A1BE87C36647527EE29FAE2F67E72FF4E1385D50D0A0B3817800E252B93A84EFE6EB8CC8C909B720193D5BD936C830788D787C02E3AF87DC1153FEF7AB496A4B006AD667B66E53C340FF5C2E87DFCA56FFB8C2F830B4BAFD043AF387720AFFE4F8E0B2DA42B2B4F13C0334E7AFAD6DA1ABB51D6042CD07966DB97C56B3F4C70FBC9DBA72FFB6084D47BA51F342FD1D1A40D3C744B51D9CF070271F4BA631EAD323CA039287CC2E2AE21CA124E41F9AF949E087404D07B95DB265DF497E84F71182FB68E4F6DD3EC422DDCE03E9796D82ABED217334521864A815C3282DF7992EB00F3042E3EAF07192121B6418BAA63D4685FAE5F9755D608B697EBA50E1A31893B6EF25A2EC1DBC664A6D707EC99F08737C291B0E382AD457C76E7268E281085ADDBADA34F09F7589C7FDBAEFC2714EF823A7F671BB6FC91D65EC33AF84CFF2B2DB0F22EEBDC15F55D19CBE9E1756B4F2FA831797C4DE89C793BFBFDB75BD8BCE4B07509B2C03FA370171719C93F913A55C02AA6D2C0DB5ED739B6059084491D9CA579E5FC82F3B82A9D98D62BC974523B71F6E9F8E98BAF3DDB40CB98197B62DBF2BF908A1D8AE750D45C9DB96501610563B1F1F9CD7B943E9AA328EE1FC50BB1C03256681C1F3E71CA70BBA7222BB9778E8840344CFB7F9F3A1968AA0DB18ADF595B6274D573EC01B23C2B51EAF6DE08A5C8E41BE0E5B9EAFD0C587731A60BD8434BF34A3F001278C146D2AE989F635DFDBFB7CF3445F09D4871B6348D4E62D58721B52094C6B927DF51351B73BD198559FA74873897367F2FABECE17B6A46B46EAE95B234464ECD4B0B28BDC6D2FA4C7113C96A65AE8E1A73D6FCCF3412AF35E84A99CE48562B6DEA0E19C3999F5F6823AE6F89E4D8F66491CE7E8DE5E22CAEB3FAE1A8AD3E7761796009AA2348B6A57AC443558004E2960538FBE02C6363861C7240F37C1DFF637EC4EEEEF0E5170F61975D350A38165D9310BEE93FE7CADBF28B1E64A2C02E2F18E5EF9DDA99C42CE9713B509D33AD9944B4B422547688AE28DE222D9E4DA77428ABCD4228B9D82CD032E56F974CD358FF021A8F9691CCFB0E982FE3BB9FB64E32B4ACB7A13AA742AA7A6E24E38AD77C067D745ED6C693B4AF3AE0FA059CF6629155E6FAA9C2CEAD4E7B6D79BE07A4599DFFE6870C10A27457676B7115A8ACDF18E2659D429CB20825990AB6870C1E2D5FE4DC36E7BEA7CAC2E41CBD642DD8796BDD81970969F7EF9F1D571C2DC7F17DE6952AD1E28EE98654FCD07107923FB63DA286BFD69163459C24BB146544A406A298A6F0286DB07C7B9FA7DFDCAC8E00897326B89022088EBE747E82112F1BBAED4D4FD81C9BC7B2E1C764E5107002B8F67C38D2A479A57A80B9D2F409DFBFC7D8AF161842ED4E289784DFE20A8D8F1FA3355FE490F555E282E85E511BBAD2280C3E18F9AAB3CEBB11E73CE875D563B992C03E7CE003054075B5C28705DFA42BCB73EF86B2D61D8FEEE64751848A68BED9F2DCA7966922002A4E597A2AD25503B1FC1716ED877B962C9301D0B1F74760F1ED0C9FC24F66420AB96238F20B9F56D072EEF5D203C1E40C2F65E90C4BA75D65A26406DD3BFA8AF6B207C29E7293AC86760E714BF0565448AE3B4E6BB85141AE4CB0721E9A4F9D9F89CD71D53EC0B9CCE6A430B5343D7FBBDB88E0B377D4CCC999917DFD499C150972C837A3C2076DB0FC749D6092ADA9DCC250BBEE964E3C3422750975681D294DCA943C9102C916B187D6AC8BAB933CFD981F0A1F8B9D98F038096F69F8F227CBBADF3226E6F6CCF13D45BAB8A12E4657FB90928D72F43A853B9F6EF258054D445FCE0979496FB5CB3AE0FF8929FC6FE873F5DF53DDF96B7DD133E4E9B5AB67F919FF7F6F6587732C45107EC9ADE7F18C0E50FC5691D8F4ACB7DD6DE0700969FFEBA3D0675CB3198D00362B9FD729C2EB0EBACFDEC015674F9BA86009F0187412D4332A44D06BF01D673729CA37973DBCBB27F3937F4F244FE502DAB1B09E52082F39C8CE819BAE5BFCBA42F6DC91A0CE3F374C99356175C1F42E82C5D658BA1241ED569F9CFE756D742EFA450C34B88C23D3CD2BCB4FFFEA1506258DB3E1CA5CB3278AC019425DE7FA90213A47D020788D4CAEB7D7EF1C53848BA3A65D773E9FBC2716E98B32CD4181B2F4C468987F9FBD13E80D649C4A2D0A785E1BB0DEE90CDC509B49EA19E2375F04D1F9839BFFBB4F17FADBECFDFA0BA435FA23D0F50AF2C4398B58004719CEAFC0A7A71AAFEC14BD65E01510AC904F5799CD683E354297D9EDF711EA618A5FAA5139FD0A7A0DAFCE610A1EF8893DF8E7AE718A2A605B2EDDFAB149F50A4A36A9CDD9B9B6A5851B13DA8FFA8E990340BC0F273B1B5A2E24F9713213EAFA6401414A7EAF793DDCD52172AABE779B7175F63C8FD7DC80E1025CBD1016E0958F5EF1CA70BEA957788301CC4AD763EFE7E3126D919D61E2CE9D39F3D3A11258D3EA4F59BA49F25E80C8E737AE3FC2962EB99DEBD6F30D833ED1A183840AD3C5F1F684198030A0BF0FB05519F3C434AB44097B2349FE4CBA01450DACB66BADD64909114E7E954CF675F565B8A17DC611D863E1CA70BFA7063FBE99F75B2FECDD22E2477B9AB2CCA9869C84F4B109E0ACA0A54FCDC276DB76B3E1CCF7988D1AF7EE9E667D3FC8BE620A5040F2183A825C40619F53B3143A9CEF67F1CE766ABEEE54A881FBE730CCC9F7DB2B77A28C61CAF0A60F58AB3565C39ACC2CB37B69D4A853FE0F9A528900CA9B087E21C7CD9F8EA02AD3F4B3B0DE66C853ABAC180579DACFC08CBAD8E9B78A1846A8738D4EE840D4ED8FF6BA96209A9D75A31218E18DB3DDBBDFEAB883E0E3ABF715900C84F624F0A12AE869273E0440BB8BC974594F5EA97E6648DCD55A99BEC6E7BB9E2297586F82CC1FE49BE4580C74573B2A667BFE52F7C15020F7517DD4D37EDDFEED4762DE04F27DBBF10EEBA5B2E32759942964D3C1713384A95A3A3AB07407EFCC0718E46FAFC9BEE2CAD54DA6E5363E2032BD3FEBF1FB4B23221F6649BB3ABE36F6F7A81B1E6D2B4FCE08024EB9221DB222B1379233F326D4E734A03B6F97D860616EAC884007377B4FD5FA1E612999700CA9A69E83C0C8CA18224638548E0D2729F66FAC900EAF96A24EEBF331CD23E01D9E83787A9D8D2BD50EE1E342847381602B017C7E98206F7B963551FB859172A5D703F225EEF58E1DD07094B190FAF38B91508391BF403D2653D06DFC8FE2CB089780D3A53495EFE78F176F1637A8480E46A7360E84CF93EE44E987BE9E8BDF6E0984649F2763784A1C5E6D7C6EB9108F570181DCCA0166837BF3597DB367D7E92E3EABB9E6B4039CEC3685CA45FBFF2FCBC1528AA0A9F185AE910FB464F000C60318DF5AC8CD23A5836346474756E3FDAE7323EAFA806AFB3D0E484BEF6CA553BFF7F082F8E5C6AB71BA57FF935FDA446AD75A8F9118E73B210FD67C7A2EE11EBE38759CD361964919F1C0DFCED1C53B1D3E03780868C59F04618A88186AE3F08B478AAFBCD2AB0DEBB74A825D9250B048BE39C08B3C7C9C1CB003B6CFF778ADE00FEC9F7B823B1EEA64F2766034870BDAD91E2C1D227474BC5FE655ABBC902DAB4FEF81FE5FC3EC2D7FA20996C165580327391CCF773081F83DE0F723F1618001050D1C2E26CFBEAF8F0712768789661BA9680962C4578261B9AE85CD663E88DECBF3ADBCDCACFD2CE0ABD0FCF709437CFB03FB3908DF183A5C8E862227A0065EC33677938F04E88C73F33278B60DAFC1FD52CA5280BF73F154139B64BCBF76FC7AB5870344E1DC071DFA491F9739CE67AF5CB6ACBF67D764948067035AFD1FC637B8EE23FA62A778E03870DA6232906DEFFBD8BA39D4ACC18097A2A74AEF970ACDA1783F04FF3A8716AB8FAEEC85E83E2DDB69D5E24AEA7DDBBFE551AFCD62AB6F39F685238148C44E97673A33F4A5B3205FCDFE65B5FB263714A5F1FC3CDFEFCA65EA1C7B15F9440898F6880F0B9228AAFDAECF8CD1B388044512C5A576A5A19E67A0D44A1FCD7383612EFFCDCE18F4DCD2FCF8DA65452F50799C264EF067D8D7938A141FA4CA0B213C7349C7D8DF84FF149B1FE6A56C29F1C948CDEA6AFD2347030739AA8129F1885FC27FBE02FF7576A158810C568FF59E14311971AEA33BE8E385C438BDA6A96BB8B6DEA25A06EFC897A8C8A8D17017824A501FCF089A3811E86FEE0E9BD33C398DF6BDD37CC150EFC49A349DC7F75A8D1E31F3EE91E8D877BD37958AF90CDAB571B7E323DDE3C368099128A8F03582B185613A4F7A6BAE27E9FDA98854FBDE97376E89C5A63C5AA5FFA14F135E49789ED87B73E1BAF0937EBADFEB20885A35DF697A6876BE7D929FD5069F3DCD0EA97A002101946AF9E283DC5AB6C1E76FF4F92D7F05846649AFF01378C6DCC8B553FE32A4F67A8A6249ED8CF2CBFC4D4AD15B07F45A297C80175795DDF9A60C70B23CE4EDD40F865F5F147E8D2BD05198D7F3E5098A4C3B4DF53B5A412C6612B1CFDCFB851CA8E04091EEAED7A42EF3CFA02138E4495E7928DC04396A78F4DF0AB98E277BAD3D565E9EEF13AEFD6E37B3CC5C02A13B8BB59CBC2DDA558F54EEE44B24579899CC7E3941F1DF0F2D7BBBE9274090D603116331DD39F3326B822DC96C29524A0A2FAE1BA69F6827FA77449BEAE860FD47F72C138D46A8E51D71FC507AF87DE55333B2BB1A1A445A6A770EDA62852501342F7948C9EC355113B0576AA4894579B90056F081E81EBFAE14D0BEF6842C90B186EC82B1C1A5CD0AE5C5C872737FF26D2EED2E0CD950400E73EE3FF68A9A65F985983081D74B3AFEA98A36F0380AEA16563511C3F7B12712AF4692C034D9E2619B8467E380484048B03D07BB0103C12ADB7141E612EA6992E282660C70EA51F858E3414BEB908DAF5599587C4503B5FB30801C02ED010478D640D40F49F397425D61E101D60B4FECB0DACE633B2306DB32C23CFB53621FB2A9104608C6F1E548C510AC7F7B84FC6FA3B06EFAD849274D2CF80821A6FA6A2E2746ED7A3422B9F5A4BD5F18F24CD495FB3DE167CC531F77E5D90538ED653BE856746C1418CF5A06D8EDF67DAEEB10E3DFC8E50E53476D44B0573FE26CD48AF161B1D6788451210699789A48999BF0D7BE5758904FB0940EF217311E933FAAE495D67811CA018E964C1222B5BAC941A2B1C4B7C1AE1D64948FA5FC97024C4969937F0D0528F6688F564EEF00F55DB9B03B21A850E37DF37235B7B9AD7B03EC404C4BAADFCD216232C3114BF37B28B6AF311F624A7D139495C41F261EA23F518CDF24A405D211CF159AEBADEB56D9C836B2271F6A7B3674DE891A0A28F5B589B47F55300EE1E94191E01E0E49A84E466CF82A4DD267C11F408C02DCC00EFB6905A2958105B6C03283961871757278AA64E5AAC7A13662E632C8BFC1B546CA4614BA53242E9578FC62FBB611F97BAD0B06C783D5BE9F62FF87DB480483B3375AFEF8448B930E545A864DF27653A662BEAA6FB1491C33C4502B423C2F7F38F38A2972C306E7FBD3948DDE2C67E0C7BFF197EAF7C2D8687103BF950CEE4DA41B6EC6C6AA9BCDB9AFFE4667A363C9370B1E42388D6DE6ED4D8DE0E40C177CD4E53EC159AFF407720BCCA1D895AFD72E6934DD2FF28CF80C5EC18370A2C66AAF9C51ED9A97DC176C99F7C0AD57D007A490D91861C905E8CCF1F2FB56876D15CB59551FF6A0C1C26F5954197610E22FE516296918DF4287BC0E74BEB67E3A6E32CE656861A2EE91CA76579B9F8E32C29166A1C478862F95BB14C647AF76DF10AA69EF5D1A84C4A34105169EB5C5F9B7D5EBD10FC21F34CFA00FF6C7F0BA6E246C803DAFD7B3925ACE82CBA212771A18B03241409C4C76D3AA7FAD9AEF3D4EF2D9058C200F41E8B2F5C1D14899AE4078F0471761CA4FFE3C36B6192C0BB44C227CE14B1687C24E7582E85233187DC1B20CBF92A45AA13E184B008209F24299C9C0ED94C4529F9B88D880FD7BB82D053B8F67FBB767AA894E4DB718799A2EA63F01E14455ECEAB2B5C2C30DF289C4A56DA39FF25125356187C0CDD7FF899FA403464F120C30FC8A6A8E0E445D48F7C7B029FE6E616310891C972940292B28D7852022D989D286CF675DFB880B88605EF684DDE1EAF3E1520A55B904207A3C16C1443D1C0E005154DFE75C80E76D455D3704A00F5E7A19B06994660F9461E2CF370320684EE3604AD4893B8FAAE7BA5447EFEB259ED11FA6DB43DD624397C80AC064146213E2EA61F136D4E05E8EAE7E56AD308C8349CC0475849BC136D541C216AC9927458A39F3B07949AC7A56F0369A64CFC7E20A2B0C70978F5C411961646EB31A0DC3484C408EAAA5504BA068DD59C3D5E0EA42ED4D59014D0DCFAE2C207478842F4ACCEFFB1870A0FAC9E6EC74B3D3D439190E45AD3597AAE5F271C83F4342A0508096FC7F7793B91422659E08ED0C99A2A43FB84F082E8A963FB7C901BE82A0B32FF4A0FFD75DFC61F3A7739567850213C12B5251F166140A99ABE2F4CF7CBA3C42B1C494322BD97FC4DD8FFE75A281C09B51D34D40B89359F3E6631C30DC819CCA3BF0AC49BB4BB660B45B4A0BCB36AA85DF6E5E0179ECF5F2F5634DEBA272BB1C16291E996481F036AC6B708B92ED5914F3AF4D8832628729824F16BD82345BAB87ABABB242DC6DF629510A875206069A3494456BD2881414BA404046E3D68504B3A14BEEE0AFA51FCDC1C40F3AF24866B79B59A31801A4BE67B621B354E26DA1CC903B10FDF3BB1CE197908B8ECD9AA9590B2BB74AA1EF7E16FECDC19F871B3B91354068628F19A598197F9761989582F0888B8BCC8271053FCA0D4717580926A43D5B200F8F0A307EFF9724D534088AEF8A9D7329D4331C8F5AA48FCD2A85FF9E4C3D7C4B82A2689FE6D91C7C7D173089D4D1219B7744B8F6D14DA0B5915639D15E5260DE1583B87F6915752F7D9D83F91A016007A0FAA0FE7A12CC858EB0B88F6A617B8DDDE1A2F7DD25C51CF611E7FE39B6782631D06478214FFB91865E2004C610BCB935E25D164FCF9AB6FD3A019FE17EB728D651ADEF4BF4A3AD3BC566CAA0E2E45CF79A771FFB5E7F35DD8AA087519F77CC6F1181C6BDEB380ADA7F8D3D5BBAAAFE7618CF1ABD3E67DB8B91EE3E1E182A166CC8EE205D0161514AACD71A6384764520AD394CCA12C177F4C7497E2655C9C27D9ECD83E0C14E1F5F06F481D021E56A98021770DEB18F0AAAFAE91A84A5EBA0B6E727F67D95A1C26A1D89AB00D2072DDEE3CD21B8E9B0637F599BBF328723C26BA408528BB99D8D39863E8951942176886BF5E95E4B9B27C36A439A6F76B1671A511CF5C05D279548B393103514B358B21503D13CD2CA2F6E7F4321B87EE9602AC677B0D95F380EB8BFF0A1EC21DE34B5901EF6883149A59809D8080A1BC5A84C730767ECA0F75410101C5C9F5DBDF036EA70E4411554BB9B1890F028440D0A036F2C961BE43CF04DCE28096E58DC5FE90C197875CC15E19033030259676EA4940DBC942AD7FD21CBD973CFE6670D0BBBA90D22650F51ACBB1C55836B5C83E919D4B40A69C1774BE6B9B5056D28218A1D60802EEE38341C0E4096D8ACBEF44FB2D5F8E670CC5DF1D496866B43D29FA694023A73C2BFE9207D0517E4C9121327FE31FDABADAB2813EEF6A478B98B754DF21942ACD7B97A334B934BB3BF4CDAD9A89C609C8B61D5D377B1E114CE6347A14DDC93C95DC5600BACE22A9A63539FCC894834ECC5A619D6A9EEC6AD1F966DF27144ACC64EAA464D81C31EAF1C803EFADEA78533F6707340BC124DA22968EBD8D767CC3DE874A60F063141C7981B1C7B578503A942A94EB6C011C2F5F5682BB417D43DB4ECCE94913CCE6855F1E79150DB617CE7401CB2FAA3D2E574D4F0CCE27212252D1FE9DFB669A5BA1DA685F6CC2074180EE986A6D55F1B5BB53D9B83B628B0182FCE75F1B4866FBA022D520BF9AC07E2850AE540E950F263F541D7FB8F0771AC8620E994783BE8397943945369B3536172834157314209DC8913FD388297E2F0DAF769858155555CC7D7231089F6A29D4C9DCEE370A4A37A0E3A83A18AA0B447C9AAC471E7F0C8619AB32F3F3013E6AD49EC8F7BD88BCBDA2DB0B387F333C648EF12136E0FB2218DFB1903E030069F8AB3D5A86FDFCFE7B6D2BFF7A895F0330A04EF5059069B8003C5ADD8AA1D61C10028E012B39840207121D6E0EB4275E90CDC7B7E859F90505592D3A7ED182FA48E26E13793134CFFF006951B3F2E96F835769BC853EC6D7C1E5CC5CC325C304B3DD58E7F30B44685FC1B4EE3877F5A158BCB8E508674AC4D1FEE00B2CE74537E1CE5B03521726FE2DCF917954E92801F3700C597529D97404BDC8CA04408723BBB2392BAA86AA60D74C37CF4F1BE976328B17D234F0D2FF0AB4818DB016F6B55DE7F2902A4E804F2622B3BD6A46F0FE135B97C12A55DC784DDEE977BE907EC70B45B48709F3E4482B012937F1EB521A353EDEDEA542668B5C53ED717AAEAA37D327D4690CD92928A8FE24C06FBD4EE16D29E93FDCE60E93BA2DB6773D6F84173CC5398F638E58A85FCB9FE41867560F449CABDB9F27B2DB3E647711A5A578A540400B5D73576C6679029702532325BCED02FD4AA44EDA7437E3F10E0C230CCA555B3814FFCF48DAB0DEAD91F15FFDE34B0F3CE523377E22FD0035A81A05A2DC4B674C6BD930E62B2E74F3845E2846773FCFF905B500B8B56F1376E7D0620A271A7759DE1287897F49538178745713E8B94262DCA0FC0F48104EB730F8A8D0995C28BCE3395A9730E600350275617F0EC6597B9C3F761F16F3F780BEB987C8ADBAEC794529298069B5EA0826137EE3E972FD4EE669CC8526CC9E91A8118786552C40401D0CFBEFDD5E0AF26081981824190DBA8E4693E2B969B0687CFE335ED2AF42B896712504CA3F0702B325F42ADC9DD1ECA63ABF13BB9009A0E05923F8BB98476B4BCD9D05A1C7DED882EC56827C5EB0CA4CA4F192BD8B61A3435F0C91A3D8BC7678C3A7CD649645A22EFFB15612062041A43BA369B29C3A3AD4CBB48309F880F5E47E33D675F0DB8F0BF77F7CF5F8050E13E79B7D79967AFC198D5F3514041E52C541C1D37EEC8F4210110C8688B58C540DE23CDA5835F5725BF0602F434C3238FA88083C81F865D30B97C0B1C231CEF681005BCE5894422FC908D4A583F383EBC8A9EF25777D3D91D2CC5709B7E15062AE418198DCE94B612F33201F959129701EC4BDF3A6B6FF24BAABB985E37B6D42E9F2BD2EFAD388C83E00C7F5EC0307BD27EBCCDE2B81373E130C75758A04B7BF66FD65F5ECC21217CE884C8B7DD7B67AA7360AD4021482B48B54BD0AB56CE6292E023DFD821D67FC804833554EF242824219608852723FD1C41A69E46F0ABEA03DE7D1609654441A1A84097A599E7AD35E21C6E69AB3F0892D132877D43FFC444DE4FF08D7006E486CB7860D37AFBF69538DEE9A70AEBA2803A953D08930960A852A52CCC42F1F4B43D306A4C0BBD9EDEFC7E3F2F9C4145EBD0B68875D5569FFC6D320E1C30F1F3CBC303C7A6EB6799D35789934EED2DCE097DC41B4E07C3DFE39336CAEF911E0D822B108B1A11FBFE48E97AA06961A075C2C36D7B1675C6C8990C80E91825FA889518F9C00E06B42C661BBF560B7966698FAF95F5E3CD20D414A425D04CB0C8D130517F60F2DA83DC793E34734CA369101797DFA50FFB1AF468C8DBF52D7A6003845C0E2DB61C9A43BAE5556DB2CE08733E9FAF11AD5B730E02574C9F3C566BB3AA18F715A60455769305FA929A0C879E075D6E84FE95526D091252F3C502B057BC4BC405F8884FA95D1356DFE9F9FAF5977E6DF47C77A1594168242424970FA000A31E3F15A34F6C7901FE0C30F2FC18B176BADE5522B1410F037CE724840B23277531642DEE8526815D61B9C21B2A203E19F0CE310A4EDF73DC269AC11FFAFAFC574DB42F3E28DAB88466B9305C3DABFD6418397E61BCBBF5C3E9CB30B1CF4AEF57EDAA8F458CB39C254255F1A88E5360D56FAA229C2D04CA8110B6CF85B3D875CFF3A516320EE13791004D8B73813F604EF9DEA11198BB3683C9D73060EA8974010ACDB763CBACD5BD75101BA2E245E1116E2E123D6F35FED5304B65CD16CFADCF3A3F9A0C6DE95667123BD72413E0DFC1D3531043CA9CCFE98BCD59CBB0B6BBC4927E27386F37118F67B2987AF1530A80B927C9228CC0720AFD9C0D9C1CCADE84ADB2F295964EA771E2D1A5DA20E00F032F8F571DDE0455D1EA897A68707B731ABEA2DAA2100F1E507DBDDD5AFF1C40678103B2D88EF2A29E3C9AF4E5939BEC854FD1C049D2D25B8CE9DAEF35E9752E34B641FE1B6075C973E512A04B73D8121F75D7BDBF92309BD5809E9C1FF6EB89517203078C93DBCDCBB9C003C9A3DD97C307215D5D43A38172E2446127EC86B0768FB23C8B627BC00ED59671CFBB1F5EF04452A47FA42B721A446FC73B7D49B29899B82C766E2A60EAFD6FFA14393C8BC0B54C17A09B228576E90B34A7F65340E8FAC5E394385F34C822815A3102548B6FB2A509BA965EBF73A1AF28B09B2C73F484A10B70DC713870832C0C91120384749EA0134984E34E8ADEFD1BBBD6AFD7B112E16DD391BC624D8467AD4AD7D51FBC639AC979B02D3211EF2BFCC9FD31727B85F622937C7457FCB611F6756F91AFAA59221BD3164E661F01566648196A0C183E9005CF5AAED8465FF308E1F61179A63036AA85687310F10A9E6B639DB1F47A4E9FA40758020C26339FA1A64515F875613E5646CE99339315102D45CA312B037E0CD1A35B8E571984C5BC9A2C4643F7069C8229EEC0002930BB4825870851FEAADCEE69885A2489DDE9273DE700D7E36ABA848CF34C43522D16EF5E12FB926848DFC05410126E93F1627E65E49239588FCA31ADC5EC06E0110CC09C3FF249AE86F4E3A7654DB44987F132CA272B01DEA86EA0259548D48294FA73F604121985B81C02BE52761954C3346525833C7D97E2640B7798B648941CA9E92C38C02B1B9FF48120100748A573B82A17773A1048F9649AB494E51C0EB9558412FA68917F40FD8998872D163A05E130E9558E89F17866248CA41D628552AE364ED188789354B1FEFCA91BE8CAB2E50A194EB9CFE50D0BB0F8772F7DC9308205120DB3F951F3677E001D2E75E6B39B82F9902E80DA84FC14B4B8E3548C882A260376F149EB73B51F54DEFC08EFE72E6760E7569B101B681E6C1DE29AC921846A9D16F4EC546D3D052A07A1D63105DEA005B277C406EDBB237FCF74EE02741EA159FA6490654B0973DE7597EAF2DE0EFA0C650B0F3371D9568AA4695CA5131A15B812D3052B6CDCDAB767846B7761B67AA826F142C0EAF947AF9ED4720B30779B1F6CB183E711B0BAFF7940F1603AC84A39DA1FE45982D416A4EB0AB1560F8FB24E31185F8EA80FE460822DDDF61F4BEA4866CCEE7270100293AFF1FCDB308BAC5C6DE68D4AF8B765ED5CFDD64C14EB031DABD7C0A92BF401CFF73FEA5DCA9DD885243DDD2D06E39324BB5D91750B2E9D928D376752B1AC7A155BE1EB3AD000925A037BE1B5582581F6C749B373D61F1597B772D8890450507AE8154C5BB03D5C6FF3FA9E9A82AB9FBAD3F86FD24D55EBFEA8578E595ECAEF7E6903F03FF5E868081B4FB00CE1C15C40B055B01ED45ED339DA14D9E515A4E0D86E17CCF1D11051A488A3D8335A8C300022CD32983308A6824F264D6A1555FCA80EA1FC0F5E3EA1AEBEFFA6AC3CBFA5F860714EC2CF5DA18DA6572D9B43F80A590F846664D71224CB9A893B3C665B99F2996EE8211014012D5AAAB21E287D5797F0727B969D4556F684AD31C91A515B5987068302C1A7BE79FA1FDBD1894090B39196FFFA5B0FE6CF674C7B9DC8C919FC1A8E97A5D8F36A45A0F02811237A1A73C79E513CEA6F3947C678E219D5B8E09FBB9DEB2688E6972DA573BC29857F40507BD4777AED99302B95A576B9DE5263593B673EFFC23FD1704A3691D2E6A3BA1461BCBF14633A80B1ABC52D1EB366900563D3A5AFA234DAC62CB92DBCAC694B495523EC46CBB49DA37792126A3EEFEC4F6186207BEE29F3C88B541C15195BB211C5AE23D598001BDC7523A251932FC0FECA0ECB3D16C2F2448C28A06519409425FD2A5116ACDA8C6781A0966AB901AEFFD1B32B12267D6E123A0BD9AE6A4B24DD7A980D7D8939EA2D6F0EB5D078F751052C39BBADD127680D0BC73F94C855D40B953279D55044914E842C818F262E938AF08F4D1D6FA0B13CF56801D3EF8B493D73E481B2C45C7FFB053F003C8E986C539203DDE712E11C68BB5683FA7A6771A2D6E1315380259DA1FB9D332F8E60BA71C0E274D487841EB0096BA4EA094451369CDD022D757042FF1586169EFFBE9747C49E811D635C5AFBE2BB9B745744399729684183EAF79B320F7953CF0625153CAB57614CEEF745E30138106160DB3032A4FD78863622EDF6BE02E03F2700A7A6429C7ED4FD1B0B6C8A94F23B8D8A31AC06BD5D4CE1744671982B80B1041455826BDA236C7728D9F00D6B07588A2637CDAA1DDF4487F836B0E05B3CA56F50D248A7D0B318531A9AF942F334F9F5D7A2FC3D97964EFE411CBA7CB98D2C26BC64F3FA46563C0B3332EEC5D67D70210104F730072D81D802829F826C1EA058F157A935B2397B25BC4EF6577EA2FD340C57B85D238A48CB51D202F73886A840242FCBA91D7EE8D0A489DC2F38C5C288F43894CAF222A1860844A77630C84153FEE23CCE355269A14CFA2B8BA88BB7339B95985FFED78FA7FB64C743AF5D196B549E742AA1558E92E0BF08AEDC9FB9B0E0C974D882E67A496925CE18AB26B47B877C24629E40BF1D889E97973D4FE9CC2DA374CAFF89BF80BF191C20649E5B8778BCFB58BEEF907B9C9CCC342AC8CFDEAF08F90D3B8D65B65A61E167F74B928F867CDEE284A7CF3567938A5A8C09E7FA3E3C7F692B0B967DDF9F2946F07B696BD36F340F8FE1F7FEFF91D3D912F200285BD2F60D8A403180D3EACB2AD8F866617C514594E19AF5B924BA272205FCCDD710B86FC585D2AFFE7BC3BA89BFF73D1A7B735A869187B8AD39EE35639E6BE183FF840FF134520EEBCADE359154B890A151F9822CE4DF3191C712656C7BC76D2E12045137DFC88BFF5DDFD32A7E713B7E42F841641BBC56F9E32E72853637F92E6CC4946BFEB4406561D3756AE5E6F9856B15E465DD142D6A784E55E623745B20CBDE5CFA956AC851448EE03218E701B6BCEECD0AB4D0616C2F81A154406481438598D71A7975FE0A863CD234108D9EF2BF9E5BDA70F6EA3D4396744D93019AC28EC5835492A2679CA0241359D73243875A71624E9E923A07F34E32DB52E0BC8BB782926480ADDB4F1E0F51A04C47D0E37F4B6A82E778CBCD579A8BBD885A4F4E3BA06209724E15E401E210B319C58B5ED82E3E8D006F74C4C1E4AD0F6E5E3353A653A945CAD8E4205477C46FEF9D2A5BA45344D33F6D8D3737CD8A5B7098CC41669C7BF6ACFA76DF10A214A351571DC4E91B9AEF38C1F442B155C924C23B6AA520D76FDEC0D79E0FD10ECBC588C3F9084720056DFC0970342BD9CE46F947432000C89E53406C0E9C9C935700075D8E79B18005416F53EC62ECEBEF83ECB03BAE023E1DB5DAB67C15E392B6F61AF54FBCFE9B47FD35F87356457AA9AD914351B27587502EA56726C74361FA6FBE42B0DE6064B0BC7D7789DAA07D49D703BDAADAEA191CC5FF14ECAB126472B5F6FC978E342542834AB9E01B4F7BEFA44A394DE6241A5F9DAA1282EB81002E42702228BD14AB5A991CD40F62F04C37BF2508C7FEFB4FA916F6279F4C8810BCC141B7D016049A814597E202E9AF5C02A330FAB69DA0D8A317557755DEFE2EB5004F4188192B6FCF36A2408F2068BC320E0B81972571AD2C7ADCAD14BAFC61736758373FB347E634BCFE94BA5B7EA3914822A5D07815E1C207FFCC947FCCA9705BC126B66FF3FCCD99609002E7B344C49456E49E342E7D5512765E163DF67A305E65C5D19071904014A4A91E7CA338E78EE08481A0BAA2D8FE391C687CC8D1F5D214C4530531DD99402BD999CAEACD06BE709EEE4F130D06EE40D711978F5B5C435EDFF9660838C1DDF77A65C77D37E1A4A2357744CA6B48CE1320C2A65C4F55738DA3923BD7F4C85CF9B8A5F9181590432F663BE90570920C5212533223FAF78377F6DE504362B2D128DA48150935E2A27347F8AA756C3B539F3F1FEFBD325F393DD914A5146981D121D71F0372BD5236C7F330067F57076DB234BFCF5B5C7D077734169BFB84852E2675A0CF7F5302B567851BE36A8297AD05D0866B70506D41FABC34B835A8A22EA2087D3F6E77F9C11071CF4295EE5F426C750D878EC99CAAAB30A75D6B5BCAFEF54DD6A091EF8F41C1593A62452F9F97BFAD37958700EBC1531C4FBDD3C54FDCD7C17018B7050F786735F3F33002181775EB8059875D1CB5EFC4D1384233E5C5AA9653BE893FF22ACEB1085047BB24AF2CD08A90447F0E544085D2624241C071A391251A19CFB1EAF5A4C7991A683A04145DB42DDDEB4A55595B71D9348C9FE8EAFCCFFB69F5983E1DBF65F753A7325500DA914DB50E32F9921FA71AF435FDE1CA023FA682D77E27092817B927E6E1500B55CFCF02A9C483C8B20EAFA0F0C4D492F3AEAE4E28544F3CF256D4C9F3D3F9A08354644232966B9779782F8DFD98DF70B2770B9E14076F6AD64C80C5BDE2CC5288086B38161E876C9F8AE93CF01C940BE7B89D4263B4F31FDE151E7D5A1F133209530380B7F58489241EF346CC0F94C6FF7C4F3FF2AE96CAE7F5327B95BA6A878742108DD5D44BDB07B7F5F6EB42C8DD20B6B88C2A5A922322D53A772A605E3DDC15D273B6778BD34C96764524AE483ED66EF87F42B7A5EA69ED18CC08016E087A571C8000873A7DDC20C487A0ED19BAD206590DECA55452FE1899C986FFAB8880DE1838498D13D766E6590A7AD34C89BBFC9C1967A9D963AE5BB67799926B26F9E25C40EDC80B0E4B374D6546A69EC89B15B9D4ED65790389D3E337DAF06FF3C8E0FCCA34F8D67B8DA1884DD8A6A497FC2A3FAB3A83C3AA94A4D7386693607D261E5EF783C0CFE0E60572267627012497CACDF3A820744EB31BA9276BF187EEFE4F928FD3474C12E0C521A46EB421C4ADB4919AF667C77793573CD702BDF55A9477871EE3FC44CA8D90DC2C1AC64C4BDECD9491FC03944B69C14A03CDB71B41025361BC53F37D586087485E248EF16DF5A4D353AA4F40BC192B1A27BDF88CA630825498DEBC9FF7551E4A20270BF84CDBC365856085AADDDC244FF1542C684D74D41BAFBE77477792AFB81ECCE8291EBEC4B92E0E7546BC7373FCA952C97FF6189E2D6EF1105BD17581F4E2A629403E19BF647F33C514ED1D8F03836D6B1D170FAFA5E17FB5887F0FCE9621FA31AC8F7504A9377F45CF42CC099B0FFC45B1EBBFFCAF2C771E27E3A8C8162CEEB7EB2891C205C8DD821DCB7F4E1813C97638EBCE060C67EF61F19D93A343612A435E10B28810A348DE76E3E742584906D5EC4876815F4B80A7D7A215BE11535D2D2143257EF07E943E5F7F9037A38AD31D4DEE6FCC2D87A2F4799C859A35627BDB01618463357CE535AE5891149DDB521484EDFE0DD235C68BB9E048050FC513316545C55C9B34BD6B2B624E279F896C382253AA00FBC18BFA64C23205C3BEF0E5699A6B225FA705BA8C54CE86AAF078F51167AC2FC3E7B3763CCD5139C29C19B170762D2EA6889BF23238735DDB6CE90FDED1BE81E742931FF85F3241F0DEE5693CD0DEDED37905D6EB5D3871CD3C32C5CEB8D3F044BBF764715E6E8C8E9B41690F5DDFF6226A02B6DAD25389DA395AB12C15BE5FD7CDE44B97E92C8B76168D47C58BF18FD5351A39AE7DDE4CE86A51EE667AF03093CF70ED6B02E6A273C51A47C984682E37F4E91E530DD81EFBAD35FF3B37F0B3E0B7070E0F8AC3C611F3D6C86753DB86110081E59A6198FB14A11287AF8D83A17D5E41E9B3BD780D66DDCE980DDE9E17F777F73C557D2568C543CCFF4274587CE9C161FF1945B693BE91795A6017DE008011BA11EF2F7642352A6FEA31BA79659D687457F8AFDC89A3D775F793EAE060000DC355C5C3AC5EB0DEA49FC138302F4FFBDC98B2E98FCD7D8FF15AD295BAC2DD26B2286EA5EB61066A40616E01552B135472C44F5C5A392CE3962FECA27FFF37BA95231C7F7C5181791BD8B1C5353D57F5768E5454DD177B27E548A149FF48CE3985C90DD7149444E9AFAC083C9C6396C33DC8180484F9A617CEBE116287B3B711CE07AB34F49E71BF84411CC3F225D148AB587602A192F34CD1DBA34F1E0CCA4B57C2ADACC19DDB59DB85BC8EE94A38B6C2BC584C4D36357350FDEF81DC89889197570CC875D6FB29A22B68C7BD79B7C8E7FAB338F1F76A41B1EEDAE6D84C2EE4E8A5D1A8E51C363E5083394BBA4006EB812BA36ACF4A6C22B1C65FB49CD91A22FC008BF7A2561FB6F3666478F183942EDE49189199DDB7946FA80DD088C56F5EA037E4D246B16BD22CFC50729C191D57DD728CBCAD6906EF3125E508D255959F8AA5AA5EDB3C862A3CCF6B9B405B92CCB452D205B665B2060A5AB7B57D145FFC72A448F6CE91F487EE76D5C6131DC4FFC85C40CF9D62DF66BF2CF3B20941B9A463BB25F96EBEAD9CEAC8A328F2F35BA978DA78271EA1C70B22DEF85E3E43E8F119774215D139102D999BED80CC7971678AC58DF625260D88B35B1BD0B815EDCC26F1AEBDB723F366C79D81ED7415CB56FCBBF6483AB122147967B7657EDD1D68B6546CF154E3D73F6BC5EA44D479EB4FF1E24C6CABC989D1736EAAB3F3E05446344813C824777680E467E73845196CEAABF5CE194194F0DDCCE455A042047652F3FB79F01E353C57F5F24D95B3A738D6D3BB28ED829533ABF76213B5B42E21F8683B2EF12DB8B7EBEB112B7F143B0BDBDE4B9B534EB08CBC45046AE5C6B367E90A46516FCA1DE8550B5E742BBDE083F76660824866ABD263FFEE9E494407BA9C19F36F877FFDA2A1E1D741A66EF8E93E5D04AD149E9BAF8BB77C7221109E6378D55F948FE0D965671CA922B3928C3F04DA6F51FDA6A215B77C279BF418FE0ADC67C54C761B9805F15CECCB598A88FD8A750C402ED244B838A84830DDDC455DD514F0445F08421078CD3D5D3A0FBD305939CDA3D2003787874E919715C69F83A96A36BA2B0E543621C6C5A9A0D0AF33BA12CA03AF6E813A5D87D3920A5B097B10E1AA7BE6B9A2ACAEE1B963F7346AA9FEA8D8DBD56EF305329AFDF11D367A2E6D4709502112317B6CA9452504BBFDF1549C39DB04A949AE41734B1D25ED6C47813B2CBF1E5E16E77083554CA5C5BCD9A98989091768D289DF8C7DC4650610D177BB1C951258BE405C69FE9767EBB7C08405275986087A8DB0B052E9EA4AEE8EBE3F6D472981A1B3723E2355BC2F41E98340D7E91D531208A5D29C36F2249F94B30A11E4A072DFED0C80475BF42F6AF011844A8277FA30544CD358B19F8FBFAEBCEFA41B8643696905E7CDDCC868D27D993B746E471CEA297AD6286661BA9AF1DFEC121D7CA601B4146D56CC68FF37F4F51D41418B4310D726BD50EF5A9A270CB9A5B84929176D177C5FD271304945E588ACCCFA4FDB1F0CAFCB832BA69820BFB1F241730886A550746069E0E164FF2CA035002E0D7AF5298BAC50EBCE135EAFFD25AFDD315C2526D566FC5119F60E2F900C7D6B6F644A963793B468ABF723A64B1FEB9DE711898CB3BAA1D9BD1C78469442A7B39F14FB9DDC6BC9BCE33048E6F32CF279DE1DC184CA829680DE88B1864CF08028F6FE2F4A5A1DC5D99A805F84A918C342841BEAF0D7C2858539ECE111DE60C2977E02FB5DBD6183EC6F9B130132425067B14C052DF35C4351E754D91EBDC69681CB55CECD26FFE64B443C88E6EE32625B6FDB2267A21158A547C7DD50D91251681F7494F657226B5F0AE666CD32B3B1E57D4A21767FE3F2F1212A03DCBCAAE307CA436AC9D1C4DB9458EE0C04BE214FF98BC136BC67999861A8B721ACF0FECF9DCEE217711A0C90261D05A7C1F37BE9E849E29E7C9CF503FADB98ABAC62B83919443D74CF89380306EE65888FF85E90E7C0A79D7B14696093662BDC471013151CC6F3731F5202EF4C8FD42FB3C0AF9D8AB50CA1F93B74E0851DEDF8A389F18DD54C00B0B8B3CB8308706DABF2907E0418A20506BFCCBCB1300B0979767606C0B18E4007171031314C0711800C009380089018227005CA397DB7D00A3F8E5DA17C0080788CA001A1100808C68A00901FCBA06FAE580FF4CC0680E703AF972EE08C2A4067C7D00A0FCE3F2A5230EC02A06B0C440AFA7000D2A40CB08F88BF912E70C10DB0200980800E305A03915E0EE01B89881EA32C07D0828F80B649302E6390050FE190DB0DF7851AD7BF177011C3C0021658029E3E53F2E209F9107CCBB1E6BFF8B1EE099EA8F287B53FFF1540F527F8FCC00280DE1A45E2E5CEFB7679F1AF0CBD4A315398031936DF71907A6BF17E7DC57CF19174CAE8C92B79ECD32D271EE646953D6FB088E77FF88A3A88ADF787D4EB012A478D274AB9266BD40D1F33FEA40511EBAF7226847C2A7C53BCE402DAF3AC011F724B5FC2F47F0C2ACA6C0EBB4375F64D248BF098047CD6F1E7D137B6F88F54610EC1483D3F9143ADA14BD1C4EA9600362C8E2407F35883D543DA3E8968B2E1D22DD5D5CFAF0939C5382BA8ABDE15F311F3E4A65FF161DEFE77E33A33C54B73138FB853DFEDA62CC3B23DB0B5B6E3D9C829C360F5B6C7536CBFB03DA97300F008CC18A4AEBA55479A2C942CD269FB67D8536BA467F4D3F24507539C26A24B179E2E81123BF86C8C97861F695995961417FC4D6E6E75041A0FCEDEE3E108FD116F34ABF1653112D5FA9B227743F8A735F2F020A2F1627E6391D0CBBA8A233E0DD9FECBF466DAAE0E5BE784D1BB946AE6E2507B7D51738588B30E47C07D9776E898249A8FF5B7311C45823D7113EE56A90F91DCB768145B9F13C7AA8B84B91852F0AE7C7809F6EDD29DCDA07A5407085429203AF47212C18D436D63C6EE33FC26224240989B8C48FB7246778BD8A9D1EC1939E53A8BB742D773659DA0123AB8FC2FE99A07AB11DD5D90918ECDEB8074A14D8250334954CE8603D124758D3FC8C241A322399D2D4DA4F4AD7BBA02A01E1444837A9FC9B8A1884B147340D7471E3140FE1A88BE93BF85E9C71674A87CD910A687DFD5683C0238F16141125EBFCF78CFCAE84C895D0372CAD0FDC89BDAD595A9BC7CE43F0337F7049078D457F5DB1601D5D00A0984BF65D3D658929B6C75B17F673317FD9DAA5C6A2C0E8616EB83BF32B9C993BE61CE6B2409B511599E05FC95261E76B7A9637BDD028748FB2EB5D5D19C2E59A69657D20C4463D4242D554BCBF2298CD7DA62C6CA1196A571ECD13AB7B71B1381F75CF3389C05E508D592ACEF299FCF72CF306CD01938D74DAA14D6799860A35887F317EBAB6DDE77591EED3C3419E8FBF0CE09715A61F07424D35CB28FE11637C3F5DA990BCF4256B5980479E079109F7811031717C092D5DB0F83C02A3C216515C8E1206B9BCB3FEAE9E06E1C31B998A061F84E5FD3B87EB55423CC8F7FB73D2265AE6B165F7D678380B4F7A430ADB9B8807DF8104A61454CBB957960EBD8726874B4C150B3F133C12D59964351D15C2FFBC2CEC48AB17E39A11F8B6E055624B300C8E843235AEDA95022045A42F1A10BB34B55DD283E15DB419E121FE75C3340037A35859B69872E0E9E58127BE82D95C13A8D110D3A9E888E7AFA9983E67F6CE7E56CA04D5E5B3E45849EF16D3ABCBDB7891E6581F280B3A430730275AE68E934E8F250D19305E7974C3F893ACF2495BC4D0A4D45CE8D49C063F613E03FB01E065AD54C89537ABEC737A240BE0FA5F7C08C697D7C4C9441D9CDA3B81D97E8C2A780217D642BBC50BFB231980414542A8CBA610701C82B7BF755434AC6BACF1DA0EBFD23FC653A1CE48D9BFB63E3025945FB06B13288B1E136A4F5B7C5ADB9298527DFCA1AE6360498B98B58DF5C9AD89CDF126FCF33ADE79372B5102F290365AF49AAE37256846F0CD8502A9E887189A7C8565624A77954F6F9055BEF58DD515916F541B321F587B6C21AF37DEA6A1FC99E883C95152278CBF3298B9A164F234B99B54E94E3EBBDB49D88A44676E5F680FDF6FF8B6D7F4F8D7D0BA2EB0987AE83CC1C2BA95A605BB884B858F95324A4964F59FD40F47F27F5A06C95F9C8F4D3D025C81539F7332BCF2A87340C5AB3687240959226AAA51D7E40222C4F9F33B883B872DD114EE30304FA8FA9BC421B501E8922D8A664EDDE9F1E9D7629996F9DE2C23AF7BFFFC55BE9D0DDC7EA6BB030F6D0C693B4F762E6297236C1868FCBD8545A2F5FEE196A1EE2991821051C417821657EC3867593333D52A88F0F468511EFD4D5F9E0279D03EF4CAC23353D61775F5AAC77B0A93A6530E214D046229AC58A52EB90A71786A81D19CE5A9586318A189B3ED99A254C9DF450254F7FB9E1E2443C367A1F7597029B08A76B25D19BB3AD21E9BC8FB5B29D4A748D205A2DD27C09BA98580C8E4A098836167F292663DED6E0E14D549AEA30AC462C44958B4ACFBBF1CB06BA6E7C164F5C71A5409DC8BC5ECDA09BB1EFBB7FACC09C744ACB4A5B48FD24F48DBA705F3F4B57500C80DF13F1D9D261D4D355FE40A3B3C9D0512EE4E588B33FB757AE2F6D01316128484440540EF5111CC8FEDBACE024437AD77B09EFDAB16B9AF58FD5FA8C6DF4B4B6DE81BCBA02E885271C923B3A521538D48865728F4516119C7997D28697BC1491587BB12A9E70FDDE083D26099A4731FFF28E13A9631813993863FBA7982FC8287AF0063125AF26FBC76054C1AFB129D76DF79C9E4D4F17547EF03B36E84804E8A36DCA043DDDFE9726FF71A86634AAC82D9631DCA5633F6216CB1135CC5FE539ACE186890EF8AEC301A6A4660EF8AB928A51B1A8B7BBB7113F6F18743BAA95B9ED4F9C1AC254F88BB1B5D1390E1B5AF8B3ABB2F800F9FA0A8D45C151C42234F6AA2FD2D095BEC595F4AD4830C1E1E290D674B0391B45909EEA80D2561015414ADC8E81215EBCD2299D59754C447CE6B3DA276FB7FFB31DE51C6E1F64441DB059276C57DB3C490901AAB99B941D2B468355E5050FF0CA73D28356239FDE182C5646FDC318090DF9E75F3D5CBC7B85D62B06DB7427982A8C84E656EDBD7131E7CD4CB0EBCD2E5FCD5B8C53A13F15F74BEAA6628474117D44BD70045AF8BC15930344D57456D45B0653B1EA84CD4CBD28D5AD5789FD214D273EF8B4F945642C3C81E56D4CB3FCEC1D2F45977AF819E77248A1EC13BB2D8D8536C5D692539E60CB01ECCDA9282001A6048F87DE83F5F01E4E5EAD777F74B90CBF92C74E1C942D72AA9ECCA939DAD07553E6D8EE639C3B4D26C3EC1A8A6A8D79A5AD4239699DF77468A224960C5F693C02A90683EB3A00072EBDE9F0F5C22C2AE3C60513AD2DFFCDB3C41FE6495A1417FDDC4668113E133F7200564B7965179730ED3904DF50D924223C28EF7887868A8ED97FF2FD365456225B5777926D9B326840387399D217EF3525D27AEE51426006FDCB3CF42E33DC2C93062258925BDB6C7FE03C51A2D001E245628E162B5FB65007AECE61806BA883FE397488E5FA582F3883CD0E3B75C1BB2697A087C4D25BC52B34C46A7F5AA234BA78D486D5DAEB95BB4670A4A26F9C7C5B7E1CEC7AA6091E70F360DF1850E0214180D0F711A511F34ECE7741A6A7C9509AA6629B4611B4E1952ABB549B283E1C95C8744655262BBCC3369A3BF0FD0381A180C02A6281DB029788043BF11F44BE0F17EF42A8261A9BD0FAA91AF872CDCEB62BAD5028A930FB6C6E3F4FF7DAAEBD80F221F0A11D0E8158DE579717A0DC9A1C2B6B0FBE802FD3D7D88E575A0241494EF3E0C72736020946CAB358D80CD29CC64BB45D6D95A58325F766290D0BAB3E06378BB5813F23BFC7D797622ED36CC6A0044A85B31EB69613894C50950F2E5EFD8A2E564A8FFA054F668AF0128C6CF6B8D123800A566005035DEFE392DF5F3CC4F7CFD98F3BEF311FFEDA54382C71F6ACDA81E24637669B72E273410AC1486438552A98306231AC54D9CF7676AAA1377CB2983ECFF4CF3AA53BDC033428FA4271C4970FB0854AFB2A2A62F200EF18374E66AE9279D3D15D4B0EF90A045E5554B2F47D579787B693581C51208C098ADE25B62BBB46737EA0C0084221860771134C1C88E019EA02FBD14A9B645C38AEA739F2F2A8EC1CDCDC6678FDFB2A4FDA1C0B8E12C731B56F042AE68E4D4535CEED0D6E358B06D54A5A5AF8F95FC43466787706DDB05254418F592BB4872F82F0F6FC587AF7BA35A94436325C0620AEDD694C573B6996AED510E2ECB2AA145CA95BA26CDA13E38623074212AAB21245549D0AA4188B1ACEEA1862BD094FBF1E1DC2E14D0A7A4EC8FB600C2C9C3CCE51801E993D804B7C859113891D4CC7EB6AF0DBFE51852D1AFADA3D3864A4906813E177304BF80BB9A3F5E0B1083B987560575847FB0268737725A38D0CE9D009C6554E67692AADED669D87DCD81B8385F1F35349398BC02CE43AF95AE0EF47F15D473C8A44C3C1150FA6F8EA3B7788CE6FD74EA33741AC2A990C0ABDBA69ACF81891A19D2EEF3E77F10DD925DC197557145918DACD26A90939D3718F81890570AB1773E9EDF7A2C5FC6455443BFA67C05C55F4E71968960BAF169EB75C6E68151D46CC0234C21CEAC8673107876D460F82CE3F808B44131375D1CE382A7D47D7EE879271CCEE642761879132AEFDD0B54CCDD60C8ED0221FE00CC99090E7A971687658EF46F65902B26EE52DAF03B851454EA3DE180DB9548AD1804014A98622F9AC9C0860C9B7BC438717E0E2ADD43E7B6954C59210DAB258294798402ADF6BDFC3D75BD685F822C06691A55213BD0343FFD036F7F0B238B49ADBEE69FC59CBE50D03BEF537E3790DD8D72138605A5E586C7232680DF68C1ABE94FEB89FC3DAEA43681883C72478C914606CF5DADFC4225C2D14CF4A09E492155B258C472A0F1193C82F91F85B542C7E05CE2C95824A0132EE93B23A8A8CDBE355F829FE99BD792C12FC6A9D3862818E8FB85997419B23C4166587E029ADC8F554DD47A104D5DEFB41EF94E49446208BB850EAB303CAAE8E3D6A3CBFB8A20D8283ED7850AE950B890F66CA3F1CC4DE70C672AE2CC169B32D09888DDCAACA73D47F4FCC0B7F308D720AC78EB99C941B67703807239B71374136EBC7443FA8B9038352DE61E1AE691BBD061E9AAE1FEF1A30442FA27CCC5267BC071228FDE4A64D0CB7E5371EBBB8C24405AA2D465EE38710ECDFFABDFD5CAF289691C01748844D7A75BA4378321EAE0DCC14867020F2DE5FAD06EA4E0C66E0CBD2978C6823CD7D5D32AB1933BA3BB8AAAEE9DDA1A1F8A3BCE99E0873DC3B7E907566B45902E9A721B0F48C1B73E2E8D652765B74377EA4115699C8AF5ACF87A4E628BB8D6919B97F513068044A0AAAA7BCF594A6DA454EA3D7D1CB0A7EFF16DB19F119E93BCEC98F5D1CA5F9B65E18317D13E24A5E6F25AF1A59DCC210C520423397074481FCF5026ACA73ED387844C34D173EED93C560A762049922F510C3FD5ECBC227C323C07AD82DFCE7C328399D55F365DBDE8C4CA19F2E429D33A43C19139D5EDB26A49016267E3AD1F63404655CB7637204A53F60BD2CB3666CD03200966050D96B446D0B46B9460B985EAC1AC0CB6EE0BBFF1621548ED74B96E44E34146322A490DFB2EFE4F5F793D7E5ECE95AB5503EE368615F32C6DD0193D1B558D3BDF235EF20A95DD24DAB9CD157EB23EB5895EA270713AA86AF26CAEE0100A08184C774175B36CD46AA215B33929BB31964E741480F107B7D1BE5347B521CBC71F48F5E22B93476D3B13B8194C413C8DB3DFAF4A967DAF430DB70865FC67E0785372E5F107F93806F42C70B35B5FE1295C4AEBF411B34DFD3D5FD3D3FBF0ADFD7D37636ECCB28A42D80F10140477022041C274A3CE8E5F3884354E636929C43A6C442CD40A7D6A18DDFBEFEABF749100F2A5B7F6AED960F5D8F91B337CB092B826C7C55BC7582B7AF00B09367618B802F047E5C3F1194027007891BEDC91D4A7B97C547DE405E79C999EFA08C15A3D934794F9AB87734091E71BCAC50C057A0695E1A515103107DF79E34F555D3510A11581ADA78B5019A65AAFEB5C15438E12E4E1AFE3BC51B71450D771048D9414462C05DBCAC9553D9EE2B85845FC93C5720BA38AFDAAE708CF4C2AC8F4276B84DA84C15CA295F484CE69D2FDEDA460DAC82FA353AD83B691B643993FBDEED11B8A39405F46D80422456271ABD9F38486A4D86BC8E47F3AF06FEBF8FCE2C6C6C4F774879D5E80DBB4C09BB6C055D14C251CA0A0ECE2C1233AF68D3A66624F9D469E79BC066724A1E22D4D8ED0819869221B0ED1D59A98C71C2BA5CCFFB98594FFE2EC0E8A89D4CA8603794836AC96084C4895186ED942B0FC6BE54FD9C11F8BD47E5E611F3DB049974F2D7C898763EFFE86C0C4FCD827D4584F54D3D0EB4056AE32CE47C1B44C0A6DD22B46DA463B2C833AC3E457FEC07D044BC2068187D739CEFB23EACF383DBB8630DDC4D84DB331F0E1ACF324A913BCAD4D1A28DC82D9B6F3A2A0A269CA79C68784EE8A224C247B5693C37F686F4A81E40CBBD6C329CC813E516DCA6A1ABC4897CE9DB99ACE0CEAC61D67DAC9611EB39D5980DBF6B0903F56930AF0A7B9FE9DF96707D7A6A9646442956BE4317648527A203B4594AB21AB23BA90C120A0A13C8BE0D0D38E088A6A7602777703392E5FD7E36A490A672A1BFDDEB286AA3AD0F977A83D6E16362A65A4A9AB1254FD5E22C74556AE2BE8304436F942D4D240B147C2C9F2D624E5CA14819F1655B8CE5E51EF36D9E97CF68834F99DCCA8A000B1D2D79694496BC0CA3671314C66FBAC4FBCE0AAC45488E9B850464FE2D6D94369C3A88C9EC5B8AADFD702281256422ED5160427E8F38425D335FAC76D3CD9FCFBF438C45FAF4407F6E015471788E74A971EF3D60C1BF232B326F2A63DB27AE05BF2693713BDEC56D6254FA9C6C77EEE7F183172C8B2034359E0B5544056A1D580CC7E17CD07B0CCC83D92A53016F46D091132C1CDD8FDE54FCAAA80A45F24F3405B143A5DE9EF1EE5F583072392567F8B7ED46C7C69568CDC92D9D3AF915C6DF3324FB2D1DF669391D845BE55062D1223F94EE0B09E31942F123E1370547595A86379FD37B2B8A6D43005BCCBD5EA66C58B0FADE1467B6656D25E9B8F562B502CF53FDC8FF9CB5FC0B7AA344D7664B77110FC4A2E26EEE4276CFC63CC04818DEF81987AE2326B0B03FC7B67D90BBDBF55D8E2E45168D619F55C2220B78BF028B01ED68ED1425DC782D55758B61F5490FF2716777ED109A8CAAA13FCCD2DC230A2EBAD17B2EAD9771A02F3A6BE6C7176F07E713CFEDA30F69D363DB8EC9501EE5C41C08E5A1F1182A93A03B557E0C77B513682D0D8166396A96B383B4B157823EC3706E96D30AAF75D0BA6A311F2E7E9224035938D0B4B1EE188F1371D3F849C8D64F88FEDA60536D7D5C79A9DB70B0E15C7CDD8D2442FBC1195D4A9F74AE1D02F06199E5B2F4B49A5BFD3F46F3AE0D5B205F710A69C70CB92B2E19933BDB35CD53BEE9143097DED5305882265CFDD8E678158A78835A5EC54B47FA9AB55CF2FA15313DA98FF0DF44DC1AD710481B4B8CF38E7647692911BAE13B2E8AAEA6090752CB9536847E941924FF8BFF43251DB2D2F9A4A140F1E1DBE3ED796CA5F2EBCCD1B3FB40853617F47CEF51D9F58E3FE2C5BE2FBEB93940A1ACDD931CF299E8FDA74C60A84097D31EC60EAC517628B0970C5E65C89CDF1755406E1C1E5CDD6B80DB00A1613310717ACC4D820918A0563AFE9D0298B098A5F91578C8BCB8245627DB684E81933BE9958D296381DDCB8C3FD88D1711AD5ED6B0E53E8F2E7499637FD7D741DB51DC7F216C724AD994885848EAB294D5D3F14C7EC55EF63DE29701725A06B0B2851676BF6E4E62C0298747D3E54BD0DF3A19345203A12F42F537BC88BDC7E8DBFE042410AC2C3981AA0011104A66F691BF0D0CC949661ECDBCD99A83C5677B8ED5EDB6141E1A138CC567E701077A64B3789B3AE193913B3CE024401D934BB7C013CD87FBD3BCCFD51F46E3808402BBB0F6F98DA6236AA92989E6DBC96261116C745A7459E9AA77A1F19AAFB9AA4107090F6B6EBBDA2210574F8598E906DE4C78A583D963742824A51B0142E14F8F933699EB3ECFF3800A702F5AC26CA2008301F962D6AA0B33DC0133F1F54B66253D6A1C9012F734E8162CC991DD6B13DB006E866771DC512A24AA7A67EBA2755B7DD733129A6399CD83E601C09C125F4AECCDF051278F19933040A7A17F01A3283BC5E1AFD501F2F5822B1895800C22335B6A18AB805B9C19A2E771F5164BBEFB6331255662C763008B87B67FC43BDBF37303B85FECDDEDC5955877220B0881AA08927B76D9A1994A808D4C6B7D7D4AD3B0C8E116CB322C6E9AE5274F6F646E453ACB13A56268E05794EC9693D2604A4ED87DB888B5798E610FBD9822BB9F0AC4C4E0981581C8BF3766AFC1414A6E8BCC1F0EEB53C346E2D9869D8589E84D1233C5F4D33DF6DA3A336FE4B83C197C946E5FB440B08403D571F7A39D58F4C8631353800216537DBC1CB885AF2E20B3C1D9832D538C4582E66E03F172656D74406AFB8C04E637024B04ED0654875D79024F2DC5154220FC84940809A1274D1D9BBC94C1D0E6A39C7B3C913498203F65B9E78310879243591096F4240A3C05229601661373A573B01AE961A028DAD2CAA44E759455553BA3789C7AE58174A7347634F7584C1DF412CA1909D8CE18C49D70B804810D4CAA03494556AA8CD0354E0BD26AA9824DCBB0245E3AE5EB5C1DB870C34FB7BB89AA40901401E212085210035FDB399950FFE67F5258CE0C528C43226B40786E2DB3F9480859744FCEC35FF95729527B710DB5994EF2B8E945A83FFCE9224F12694C708E986BD37D102F1ADEE831E3E57EB718B3B7F4B88CEC9BADC60B55D382F0CF61FC482DA0EE83DCEB7703089A1EDF5A5D4BAA6F4167EF318A9AE7BF727CCE9A4521987FC44D87FBE98EF82740E671500248E62D22327577E0C5276132EBF453D003DFB2A0D66F4B43FD11E63FDECB3FE0101EF926B7F048BFF9EC53874FA8BDE420337697088702A4B5122816FF6AA8D42B51127AEEF64B547B1438FC62F9EA1583559568E1BFE2F72E552C8955CCB8DDCCA9DDCCB83FC9747791A7B3E3811D8897703840ADBC90D2F5F11241145256AD188245AD189FE97F30724EB971D73F6C88DBE029240F3274F3E1546DB101645064AF4FD455288C6FEA1252CB7C95F2407C3D3BEE98929AE635FE3593269FF9CB0A643DECE53948D6227030C3C9F78B9B83073C1A3D7284D3ED08802B1F12EA017D9E247AB036A1EB2797D197438C2D26A35CD04A6041BBD10FD9F4E1001661E6A57DE3C3044B9964C5CDB53B0E148E5C51B757C63372186C06F6C91A6B70E7E4951FEB03FC858763C29F3C6ABD8027D67662D5E237C40E94ADB0EE82D4787BBC556EBB720505DD7D5ABE8761663894146A354278DD89FB9708B925E30962A5E943702FFE108F78A84E0EF20C4F0359AD6849A617E6C71078113B37660968062ACECEFEE3F3BEA2C71B20BEA2C7D6F3FA7102CA5C5B14C62F0279DFE14306D9CE445435BEE0498B35980BC6C8AE7C0824158C475C9C2642667766DFE17D4536852F64FC5FEBD70C21DFE6F1E69569DFAF06211616C53DCA6A0CA29B539A7871743D18B6D7E404A14BF49B05845F529E851401701A5EF361A161B54ECAF8DC981B07259E770033D125568241175E0CF4BCC1B0291F6D4246DBFA600E564F4A74480656DB0FA1B527BFF33FF4A317AEB32C49B4C4058904D850EBBEAF71D0858C9FD9A4150F4335AF5679334CFF11E0401DEFA20FFBDE5A7D502458664DE45EF973CCA0FC1F6915012C96B4B3B611C5F36073A67BF91D0A60532B830EB765412C1FB422CBD27F984B2E459E745E29AD03F5BB9A749BA1CEB160A5A3995E36023DB615C5A30432719F3EAFFA7635A8B39C5F9F45A59DA5DC2A030096780CF4FA49698AF9A5FC446FC8B996F1CA3D024321FDAF3330BC1C95E6DA9228F48B665EEAD0506B02C1CC8ECD5DCE03B9F62F478E63EF1C9D9D8C52F1781102877DFE3EA093577811A03209CDB0F0A7AE7535C35D8AF84199EAB7C628A718332AC217291B1A27CD30209CFC684C1AD51A485DB9B5964B580E755CFE50C88688FB4226F8D8755F506C7B795D08AFD34E10078A2655036840DB5CA0339187AD6715B976AFFB2395DA8AF445EA37D14E0C5F24A28BDA7389213249DAD5AA5545983A077FEE112AB91A885CEA311D28A4CE914AF8B4A961F83127B9D0F4714E55E96222805CDE0C920944780127B0580B283F166EC2E6C8BECAABE868075209E438B9C5F055368353A93D5C67307343058023144CD4DB10C4353406812FFC564358C875F4683AA41573D93ECCB9B471DA0BD29BDF754B13A393C0D20A7929FA78793056B26F6E934BFA5F3CCF242CA4F986B7E741D0E720BE77EDEE4F14FE8C192956A095AF681101EFD06263B58699A1C0385BFC57E3DCBADA085DF51B990958C89FF16C43573C045787B3C8AFC67C4A7A23C1B7CED5BC32D4434E4AF42ED1150259CA3FEED28BF2B1A5377F674E01DE7A03A50F10B822F8579595E110BF8A2AF206A4431FB1F2738C66D2D84A44D8647AB56B7E710AFD8B608AD1435F8EB3E655A5AA0CC50D57771CBCDE51494B6D6FCFF43D992BE0F3F54CAD9F7A824A8B574CB2B2F0E4B070080D261BF927712BAD4C02873E8953A9F4E2C48ED3D6895DAC2EE83529A63FAE91D5293B7AE0C3767920A828A24886C41F5616F238A2424163576616852450761E947AAAC5780AEFEAE7CD4A2CBC8EAFD53E51D685C79D56E520C9C3B3E73B7B82B7293AF987E893C21A128AC1B96D5032FC1AB1FBD4FD3A697B86AF6702E829740EF295E30EE6393B5DA2F5E382698D55B5E2BB7ACDFCC728D30D0F57C4118827AEAFF429593AB60EC15940579E89D72DB88ADAA4ADAE1955466CC36AA2975D5C0EA00E1A83F84F5C2376551B7EB3C4BD64C238455C9733CD9FC6886AF5BFF593F91DF260C24EB742282751630F765F97F285DE7B5FA7E819DE2A3713C6843478816BA6200B1F3AE712C1FF9913928D87CBE18903FC0DEBBBD90469E292136E971827C0CEC3ABB01A330065E6B708C6B4E691669EC4883B0B1932E73CB3081E25D90E679C27660A10EACB1B808BB2D1955A85E6EF5185E33DD956911E721B83B48F5EEE8C60B03547E104C09EB7C99E477D97FBCE94CC1945CFFB93B8C9D920232DAF0BF75E9DE25DE40C19FA2251D2858D4DABBC813CBE2D8577B9CB6DFEF604D4C1DC0CA2F916F5FEBCAA6842EDB0F9112540DA662EFB867866AF1A9268B53E92A699A6E659DEFC58245922A99A08443F7FEA9C0EEF6432C468D14E3D305C559548CFA445C125288EA8402070A58EFAB84B87DFA8EB2EC8865855CEC20FDE48D26C0749D93BA0D421266C9B400C9B65A6D893B0213E2B52CCAD52E15E295800BFB45DEFBF0CD04EF0907B8982D95137D63B7F18BA4C1B36C7CBBB84B304248F4E4D12F571F6F4BEB7AE17028FA10CB8F7ADD1F4A3719286112B0F215E9853447CE733DE544C9E061A7B29CB60EF2E569A0A8023668F9C9B3BDF3994982908465FD3F4DEE25ECDBEAAF2D44ABCAF1D3A9B7615794A125C6D1894FF32A9C4A4A6DCC59C067DF76515998CC3B153B2EB53EACE18516C56C64A97B0C7E32B9E6ED19DC39B7335EE289422B9D301E243C1E25F3AB5330AA42D37311F1B9217B591D7A49211E0520A722EF9252EC26C6BDF9CE54AECD1CA86CD980A8C43B8B136C0B15EF886F67AF46C3D18972FF9898F2710B5633DFE818AD497A1FF5EC10D2BCA08C578999EC2AD3C4217AC9EB9C6E9357F0DF1D04F721D03E02BBB88FFC94083FE4ABB2EF20A080802344F61FD571FB20DB179F4F64B75B05C57E0135FF72EF5FE7B46105B941C9170A6585D1AB70A021F62E34F4570BBB36798702C30CB8FF87BAB6357A483AF8A177A64A8AA47F5926A40CBBB1A5064481D0423C00112E4E7B69AF4EE37C58665593771FA9CAE218B130E13A810D4105B86AA653E03060AB1F3971BB01C4B3F23E267900A002B088C40034E8108370E07DC694353FC4DF0DEBF07F5BE622A74F978713D53462563913BE691F48834B4C40B76C8C08787E52AEC4BF6A1B98E673DB6AF7D55CFFCDE2C0EA262FAC893AB198BAC02047594E0BB67CF83663CF54A6C1708FB3C004111E91F34AFB742AFC16F7946A1544815D52C7D103243393F28BE68763C6DF29AB7D8723FFBAD0C319889C16466A9E4C6AC5DBBA70BCAB75AE02C4BA69A082F89A08A7AF22A407837398BC547A16AD875A5B80879B0AAA4AA96BCFCC2E4858541F140E620EECDD43049C3620CE17095A3D978B2CE447E5DEAFDDE5312ECEFA4B0CD88D9E5DDB5B3F7EC83CF007116B36A238E76D190BE80C09F9698E316AF677C5A545409EA1EC708D06237818FA47021FB6A6549CA72E7866B06015245B2464404D2C955E25D58F210DFCD6B1CDB9C699C723D19824BCA78268FF9A9A3DF8D267816DAEA5151C8D72F9DA9065FB1E7DDE4766AEF1602F2FF33F384035EE8056D9B6C8C356342AEFC34D5E6FC54E57EEE5A848F1B2697659E248B305E831307E273D7450A9F9A715E5E584D3600B43E4212A94347D546D62E02D59422B5D769F2241ACFDC8A5CA92BB40C0EB985F6E2E24D1648499D73B0BDA1CE22D3878F26089703047D4C276FFF68AA67A144EBCF3C23B8A69FD085597FD5502CA7C1FC4294E619D978ED661EE086941FE6B37763D8B5785797D14B7827EF2308942844F68160DA463406B5B2DD63B25D7415FF7C4F7BFACE12E0169FCA7324A42BB85F6D0EDE4D70511D4AD1829319B33040CD39CBFF2AA7D4AA6F9594D44D8987D9018BD265CEC9362FD0E441255468227248F7DBFB42944EED3C9937B3241B3E0374A304FF53DD678B6655B7D74436CDE2D87FB87F180C551277C75B06F05146FA6646FD56692D37E4280D05D06A1095FA68C1071FF492B3E008F1C231B2B8AE0C6D5816DF78CAA36F92AE4AEE1EC1B3812C34BA7B87A809C4E3979A17A908AB62034A4B807962BEE757DA18364FDF9A5405DA7BD0D90C1B54778481B55FD158A8B479685376998476BC74A98572E89022C942F214A3473A3F133FDFBE401D07DD5025FDBD6A11573E3174F49C2F7354C976CD030BC81858273A7AC6537AE9A53B624AB941B59632D0CD502E5CA1E718E81D160CE10D991A256CB931EE669D3815EC455D0BA5B6597D71CFD3B70B65B342350BAF4C95FC8CBCBB80014A8742270C6CF67D12DCD56AAAC4B5C9201AD82B5C9E93096B74D87605693091A6F810AB24DB36CBC4D59DCA23C68BDEC6636519D10B964E11D51E0F25F569E4783A8F86C1E8F031BE30D4FB126FD66723C1AAC7863F5CD4E1A528B1D3634597163B728A03BE52408BE2957396145302ED9A96C6CD4B6B41E426527967400F98A1F99F0943EAAF06675009506CE01F0596A5EBEE92DC6833C0CF1D63147C37B4A8884C6D8236CB82E2076C6A408492EBE5EDF4A31012D93CCC4DD24EFEFA4C8E8713B3AA4DF4688D0328718E9AE1ED5C7D61A753F44B3B44AF01C211B1BEF9A00CB8DE1EA854CA3E56CC0D98172CF1792FB77D1831BCC10B25B126B17A8A9801008AE5DA7789A04F0339307A0705515354CB74A0307E8453C5F060CFA404D7F4B4AA5F2BBD77314DDBE5C5A6DEEFACBE5C8E7CD7C893C6D3565472397FF9D8D80A62421C28CF5A9DCD799E7B293E967CF2E8C848C924EB446A84148DE2F39472A1E62B84A0625FAA5F7B32BC92BE09D41F8A98FE3A5B1CCAF753AC3A20FBEC59B19A82F8308CA75EDFFB57BA8E1E816A92768D2843DB0048A88743A593A2C2B81FFE5C980B85BCD990CF7FE1A7284D8AAAB0D1D56EAA8BD6D8D915BE13017FB32E13EF74E42323A7660448398066E140D330090BF037CF15F54DDB2455866523278E27A8F7B75E2A976B5A54BE3977F0991C9593E409544182EC32009A48B36782F5A44FD346AD2298F3CE02106F4557589425252AA45B3BCA0CE71E01C9019C1B8F6C4C9DFFFB38DA3B5B0ABD32E30CF62442F90FD918D186352B870B7499C6F4E257091352094F3ACFD9FAA50A4CB83D1BA00014DD640C9C218F106CCF2575C385391F380CD93254444B15EE3C728E11C3D4C50404433560786908474F8A01576799769AC0E2A2EA0DE2AC0B5B6F1D00C5A0C6B37CBCD10F1711BBA14E279B4DDF1156CCC2B205B7E946E0AB250CFA8A9C17353E3AAA648CB293460DE893C9BA5D7DE9819D7AA0B6A475BF8A0652655AD926EC9C6C0DFB63A132454D8475689101517E44C224C6008820F9E7701356D55FF48A533E822DCC5E2A5637BA8338583BFA5BC0B111F7B109C4DD357B17CB8A42842090C0F76AAB884F53CBDAD86450B581CB4C15A2DF645CE0B92F4EA017B78A8BDA9BC805BBDC3B2A065B7510B2FEF90C0B2ABE8CD9EF9C9BA99653D69F4312423F66D4E6B8FA46286F84477CDD7B77BFD5730D08439FC5A64862E79A1E1079E2226D179C8B74F4A814D697009A9EA7B76C3387890F50B26A1A57A90D48F425E1039A04397BA3E727AE6712F2FD322835C3793E0C5E24C6F0E99BFFD412C2E6B5DCAB2D8C512CF6FDF9CF3AA14E3E48F5A0AF2BBD8509293BC6F968A97713C3D6E9686F1556DB95261A32EFEFA75D60C173DDF40CFBF2189D66E134990373BC1CA6F02A927589756460B7C93464BAFFA32B9047AFDED75E89A15D1C796522C66D67B54EA67C38F9D6BF3CA84E6853A7A430EDD0BAA7EC345B64282E7096B3D04A0EC7A59E713DAA7EEFCB7DAF534965EAD18EE327F2DF13B797675548D9FF272CAF1289E319D2E0B1C92CDACB45BAC125D2B10DEAE320DF1930D351FE293CD131D9ABCE2D47E46BD0674A3CB3062A35D45899E5FF66D0409559081378D4945C6725B735C577D3348B498BE083D81CED7CBB4F51F89A8597E3182427D7084D815CEB60C30861240399A7EF725D5C0FACD0079DDBFF8F0AE0D046A8ECEEA8BC701990EA0D1EDB69B9711E8E612BF53C3E416748BD56F04897E34C71ED2B3BF4685BAD0B10010CC6F72067F27B437B9F15B3D8EBF9A46FFD5F0489D2C7A9AECDAA94123604CDDDE0731AE48A282EB621A930D2C0B5987E0C54192CD4E7F1D11930E4991424724418B100C7BC45806DC4FBA2349C0748B6B09BDE7D83DB4E2409BBF313EDABBD2B0BD468EA684A4947C256549E5A137D57D2DF322EDCAB8D75EDEE1A9574059820281234A18C92645A4F72D4B74E84CA337012C3BE764E4EF59BF2CB826D82D863FB51853ADB20568E5CDA6F37B6707FE88058AA3C8FFF9E6D8824694FE64733A67B5F31CAAE08A67343F54B6EDF1D42A98843E9EA44D3D94D43E78EFB8413516517FE40E054A15A0B9E9083635F7C5112A92A867E08E8461F4120C514288A890C42558B09ED91F183F10982722FB677EB7861834C3E5EA968328004B75B22B90FA8FA58E22869E41326B648C9A34CB4C59963657EBB3BC5FCE13707B7A852A9BC40B62F06392494200075BE54330A000D350782864D217FC95D4F07B3EBB28EB0D019EFC83DA23DA7F48B96CC706F208F01E6B6449A11B06EC0C1C3EBDF563B34BAA62BA86423C190311FF95A9367452422D196CDDB9AAA7544E3820AF9F5ED577D6F3687B8E502EDE418FE975B2C844258A456C647BB37B3908E48C0AFD89E1648845A14CBB34D2D4BA4B02A3D248FA27307BB3DB36C71F26D9AE1C1C34EFDBE58DF9EB62FF5F242E92F765D2CCA27B325A9FCF9B7AEAEE3E60793FA355AA45E05DBF3B9E18CAF9C075CBA096499982FAB56EA21B33D1EBB8EEFE6F00A7CAF2227D275F95AFE9DC62485423153C554339CFD92F4F4B3F710C0676ACF87E6EE6DFEF6F19BF00D4D07D8E9326175487C435B1EBA34596778790237B0DA287B09E9C5F884FD1692B454ED2A80D4D2A4F0F817B78FCC4062DA77D5AD68002686233162DD07674646853D3305439F03DA8F368B352CEB98E55E1718EE43A4C587D85DEBC3454EBF29D5C962C770CBAC53366779520EA190B45E8CD0F07A148F6253AD7510F8025B11A557927B02FC2536924CF4694D07557BD513B91BFC582798B20EC1A34AC0FE4A13D8403E94301F234B548CB47DF89D6965CAF19CF677D1FFD41EFBA65E953A6BFD9963E4065F5F7E8584A41B898B4C920E32C59858D29085F2B2788BFD9D0ED4BB58DCE5A65AEE1C0C7AFB1BFEF63FB355C01FBB0A9CAFE4B8CC212ED8DBFAD51BE491A61CEE09DFB4BB050D8908DC66303FA1E7F970A3F0BC0FA119FCD4AE77E9074FD9D32CA2AC4CB362ABD219306A5B4CFFE8AA5564804E73D98C043429B51E0E08C8B26E4E6E2C4F06D0892D952FA7023C4F140090E297240E9FA6C2968E2424ABFE5142B4482123A57EE2C498D9A011D60244A1E7EEEFC2135BC909D9E4249348ADDC197E3BD3F964B6762519D61A889C8C80C5802965217F4CBF1B151574F9FE768A2AE8334E62C74F269C859BF1AF88BE609AF0A5BAC7D9DD651C8C48A309B4E4C8B64541EA2718619E1AF1AD5B951E0F6B12B9017409448CBD9F031580778044311EE6AAD8D07AEEF01A57C078643D993EF737ECFD508DE7F89AE74537E5F38970D8E24D5AB86AD01A67826D4F36F2F08EE9736E75CCC32E3D5D633A42B468B830F02C2B27C67D6797C708E7CCEB2DB1C00965606287FFA336C5AED8F15DF3EC868811D85E7FEC1716C220D462AC349ABA667C8F56036AE9F4F4DA580C7AC4F4D8FBEE09AE98F8F712BB295F382F324951009B41F0021228D65C1934F15D4937FD770D9778C851C185EC91446AB19CB374530A906A914CA11ACF6954A7958D33081A2CBB55894B32ECA853E882FED1DE0FDCB9B94CABCBC360A21D8237F1AD6343932E53F7D7C264575710E620B21609BA7AF274F8823FAAD52105AFB76B608894011E229D7D2275CE6E62D2A8AF45DFDC8456D27855D5CD62781258ADC6BE322FD6AA33A90447AD628D8D516D69E77242ED0DFB12D0C10B965FB47722A9EF6F58FE4E55585BFAB8360A5C2051AB6494177B39D42F2A6E1B04B7BD5439E0650D3EA4DC15FABAC9F2C0CC7675749DA7284C073ED5463701C9056796F401DF8FF7892A2B7C5CC35DE99D43C15B0C194D39105749951DA24A3B0C8DC4C0E2E4917E0463C6872D46CE06CCE196B4AF3C6BCE3EE0B132EEFA415E6AA744E6C713D361896C89AAECB7BC6CCDB52EAF563838975F997F0C60B394EC81372793BE7D9F7ABBAF65E7AFA4681A17DE7142B9FD99D9029D52286106A4234A268C9BBD093E3B6D48DC7FECE3C336025E58D98F64E133BE71BE0FF513CC61C09427ECF9E74E27CD8E975283C4AF7016DF2B371E5A5CEA5BE87501AEE782C47EB1433090F150D55D6AFB1971D61FB35DADDE0702D270837082F80E677A98EDFA9763DFB405D900AB6D2F4DB8B0A9E541DF43DCE4327AF705CD9FFF23611F53370C09BE459D9767A1D40F43FC3E2BD50408260AB6DD0DEED17C8A83BB5B0BE81C347D426FE850C2DCAACB7EDCEFDEC824381CA6354A0848616399074F5D6D2FF1D860EDA0DFD72107C187EE9C8649FD247C328C4994DE0652F97F98016A7D44C963546915C43F75229F68E3500E331C9B3A079237D2CC92381517AF9AFED871B75F5F43D9EB40E23CD1B2EA57EED4E0CF489BCD61F48FAABDB6D799ED000B448042EF557317DE2DAE96E967C09771E6FBC3604456E581D1F74B93F9D7CA488705160807951891E0D5AA2B7D5339B5D0723C7BDEBE0A694C1F32A966F3BFE776C84B4AB4AE1DF9FED6F156D252A54D7FEA62F585E9217C3EB3134393D6CD34D93BEE544661B1A061E3E9E0F3DFE43CFA407FB04772BF12B563DAADB51F882D73EA5A751F97ED3D810C966905DD5FC62B326498F3944F77A2309E16C90CB73F498378C4D7C61E73BF27BB280CFC3D289E9E00474A7E02FF97DF5B79873190ABE9B69B4A52CCD36A36089951EA4AF6AE19E58E6F41DFF2CF81148AA94968AD7906F95A52FBE3B3E4E1FC7A56363D3DCD721E2AFE5E532970EAB4DEA6B223CB456FB56A0C383071EC8EBFB4B812666FC08901F7CF1C98448F7C1115DFB9E7751EC0D3E5FD21939EA4BA57496425E85B77CCEE48ED5BC666235122F41BCAB52A06BD72813772423388EF6EFB1764035EF3824F180934A6BDD2A9946A298DCE21D17A0BAEA147CF6B96FD2728466559991DDF3317E51674A249A12E8562B6A4F8C7899DA7BCC08E1BA402CC5C9CF4863734DAF89BE6CD68147FB810DEB07605F15B2101BB3EF828422CB12266F9E995C7F2AEE0C0917B134DAF90FAB62FB60E3AFC5C502F11234A1C42C1D04EEA2AA4D4AB8E255F981FCFE977A94DE4EFB449E5DF26AEC8F645A39D33298F4513B28F0D15BD1912B58E40661561DB7BEE75FF6F6A2C4E465DC48C0675DC2CB40157598DE2899049B1EC9350E1DDE49556AAE4DB4F46DF36CF9C7A3894C032C6FD988ABAF099F832C38188520FA445094A2CC967F083B49E6FCB646BBD6BAAC9BDFD87EA2B60BD060465F438598530F5031B6F956059AA32DCE3C392EACF56E36609D79B3C2FE22FCA89EAF155DEA365544E57FDDC6B176C55400DE6603A3F119D63F7B9859E00847B750DBF06D8D476BE10591F9E93833F78157FEA6EF46BBE0812553BAFB9EF4D413A3C11F49BDCC611749FE5C85FEA7A5B52E9B580CA01D8A2F110FA266242020D4FBDBA4E7F7ED73BBF96FF65B894C947065A79D13B47A32A96C4CB4E17A2980A55552AA1EB8D2061FDE59F99E4FA34B0AF00CCF19DF5E0F5DBE7457EEBC06F38410727CCC8111B83BE2BD55B7AD4875CF847560DEC850DD6054D21AC47F8CCB84253F82F1A6954B2CE85320B5919901CB1E18E42D9D329A40436E558E49C634977035C218E6998D74EE144EC010051BB7DC286D99BDED7CD603543048505BC13E91DAF6D797A2A89C5E639F73C5F66BF829896EBF2908A67F2D2879DBC845B2DC374FF2B5E100094AAAE3FA0DD7BA9041F43D1E8036E3E6F82D1E567D34FDEF4F52146942DC0B4FE52D0AB5591116787DC8ABA418C5A1E507CDE3B3C6BA01EB469FF307FB2F412467D9CD74512F73D8F6627F043E28C1A3450E245D1FDB3B474A51D46F92FE7FE344DC15D261849533CEB95E77A732D7A2E6526FF8FF2C792CF67E721103B4A8E55E946D226561DD083010923C9CB9120A5B6E20B139F1B051574FDFE3EF7C345E5876AFF66C7B9A0A0B795749B2A7E03C11FCBE84F0335BE234357E59112DC928D3F913869A2A9559A46460BB5923EEC93A121A05B0361887D243A7C0F1188AF0576BB1A0707DBD353A2721B81028802373BDE7969FF5009E5EE2446C943F3CE19D360DDAF49BB08FF2EBE2477944EC1B0691ED72898231FEE2A93A2848BB54DDBF8F745D8C7778B840D6754F29E1C3FA8561F09A3E88FC4DECD3EFE2FFD06D0E03EBC22A9ECC54F33590EC122A4BB002B2B88227994B7294F972D783414042441B8572698C3B642846F72021A69FE6FEC51C82063C502F309243F1B43D15A0D1913C035CBF49517B138194D80BDB8D077653884B47EDBDF7D864BD88B9CB8D218BA99F5997A48F86E594717F5A200429CD42D376F79AA32AEB86568991DFEE1443D6C526126468CD0A07263F0811C834A288B814452A72B4445B3F72AC3029045BA4EDF49EF154132C8C0085F6FC71553E222270AD258EA808BD9CD417E72608A66939DF1DC53AED692FDF3A3D00D03BAF502C5EFC34E78A83B03000D2F78BCBA0FA009392A8C95417764C76B9BE0C358E91D233E7108AC2006B199C42BCF996D1B32532AAD5667F7109C769DDD4018F2B85706CE6428C5CA5477BCC15282F5CBBD404D330BBF7D2CCFB3ED5CD9832441F6EF06F40D3CC39C445F694FCA30BBA1F5337DFC732AE310F2C5FA25AAF35DC6B94220FA0C6AF519DF77EE4F8ACC20CEF93BAE2E41F74B2103DD1543C342A180BE479DF2456D9BC68767F69E776D8929D399A4DA30EE8930A5AF3B7D841AF999F925D04E7C84236EEF82936F83AE2AEC722B290029FA7244215FC1A7B7337B65FC3C836E65B68AB5F1951F183239CA466112C69156EFEF20646D8DF39EFD49E8C96A2EFF182785444B38CCE9E72623046F479438CB72B9E57684DA504991FD7FB9770784CF7ED54E6F1F490DABF1F563A134314C40D3F1356D07D0981B92521B03B010919F8A0048316399074B94EA1552F09CC0C1D68064D59A26C878987233027B657D237F5CC05F67DE68E8318675DA7B235A3749106D673FE985B7F14AFF2C54B4B122D310E883DA254B900B151574FDFE35C41FFAD8270CBCECB2923FF43D55454C0A110DCFD52799080FE931B01D6F91413D524B61E7C8F39DE35A9C5D36920FC22E47913023CEEAD88301C0B18D0DD2BF1D9A38141ABE76518A4B7DC4FEEB9C5031413BC04F9A565613C1609EF986F07EA57A9C82055826349A21755AF3B3BF98418D5A09F816C29B449EFA3F384B321396D91FA5DCD15BAF13EA057BF7188E3D8D7EB7A76AA7EFBD85AE8BF1AA1B53DE91285C5E145A8FAA776B7AAE607C34092A11445CEDF4512A474F72DE2AB560CAAAB732DCECD1DF3E829D6DD2574607F175C7EA1D1E15899F6C4EFC0559AA803B876E905ACD089FCB8062DF1AC8B57B6C0DE0199FCA9DAA02E38726C9DFF8120D2CF795C70C4DAB4316D6713F1F096D9961F5677CFDBE7A9131358A070F478E18793A141625FB35A4FA0D90D901D24B19C649F2362127E0AD9240083ED70E4520278DB394BA7800696809FB00DBFBE9980ADAD511D5CC4267ADA56241A34F9F8BA7A4A74B41CD2CDDE74F0A39F0529793F0B908FC1160998C29CF020FA9BAF0F24AD7B10D62A309A8EA654A2E96298AA9A8E3256FAD35FF7ECE04733656E314901A304E700F6089BA5A92F65DAE441CA78180C1CE1DBBAF5228DBECD4B5A96C5A4D0DE4B7C0E056686F251ACFD53667380003B602FBDEF4B3903D64C0928E1E3932A36FC3067A63E10B02F847779557EFA5126CD17DBAB0B25EB1EEA7ED8934AA244B0E016BD19011D3DC2A49C060A5268F1DCDBB410FF8FA2FC9AD77F32B2815E2CCD817A057CF7A385CFCB2EFCD9F0D51B42C20D8C54B3D8A745E5A87601B045F574031C389BCD970F652820F8F55C30C84E141BFC03B57F5ACCB99A36AC1577F7485B56B1E193BDCFF96ACF72DC53CAD7767E20731CEC0A76C1CC26A035368BBC15C245213CC8B191D0C11BCB89D839F82FF80BE945405FBC072620F8D9E900DF07A80948EE665569B3BC4187982CEC7EEB1194C56482103DE89C7640CD97BD99E621D9194FDD526CF0EDA2625CB4B69F44A71753D2F9A9012BC1A87DF50F5F7B2861FAF7C07D1BFDD611226794089C347433C34B10DBA9F43BB4A955341C70CEA69360B54AEBE946B86A43C023E104E3136DE9E444180AECAA99224D7947DD671852428BCD55B0232D8D64E5298F84BBE788C80377BD6DA7A4B1B275B5760CE006AF092D2ACABE421E321FF7D8787DBFAEF4EAC81866EA91439EB9E66D5EAFC16445D4ACC1152A9D2B3912CEA2ACA0221231911F51F14AFB09323F5644F816A1B6D41A230F27558F7684C95A12B7E93BE5F5F18AE6ADAA50BBEAE0CC5574D2B33C29B4A7536A024F33D33E3673CAC3B540BC1367628906535D28B8AC5CEB9850B513FC9600A4690E9A329A773B94828BAAC73854ADC7846002B5062C52F0E2716CBFE0ED42951192AE8CE09BAC14941E4EE01249C661F2AB364ED18DBEEA1E6AF29BB78E38176D198FEDB42E1DE8ECB85BE157DB520A95AE9691582CDEFC3501D0DBB15D10C818F1F168E382BED37AA080FB27E7B4A36944D37995C3BCEAE2A6AE942F5C0D06015BF0BF8F2DE725F80DE4A57E37BF5A23137F8319A531E95F0A7A79F302CF22F1814AFAB1B2DD19099A72EC4F7F8BA304F5AC9B732C8CFE1AC935DC2E2A4FF8C8A7B43BBCAF7E00C8E86EBD02F61D74DB89363FEFCFD5B46614622C0C536C2C2F807036B3D1077A45C23F28D89CE52846E0B214D0185B326C8292421C338D26C86F8CC5D33F34FF19B407BB802455AE739BF3B9A65ACD7D80B44E8E75C11879A458F6C52EDEB5317DE150A74D7022FB95C147D329E5C52C6E95CC4934BDB80C2BCD5B1CCFB07855717B357D6A94C3FAF96A98ADBFEB019A9E0E21B4696540FC7284C43F963FCC59D176AADB658E76C7041CDB1E7919E039CBD9322CB43FABB6FE05AA6DD4D083EFA1929BE46FE412108B3FB99D0BC705868BC1536CF5AB97BE414B5A3AD4E6AFB644066EE449482E669E72C7D8AADFDC60A3AE405451F4CC5C84B55C9A78B4AF3240890EE1754869FCFC49EA0528FC63DD4574EABD66922CD3F53670ACDD41734B4C5F8B0AE42BE8AAE30EBACECF1C60FDED243D77D8A9ADE2A8EE61B707674447C1D9443A4182BCBD2FC98FA04765A69FA049ABD63A75E1BE3B2A3367E78DAEC895FDBF26BE2A1381E54929E998D6F5EE8C2A491A9CD73031992DF2449FE47CF240D5ECB6F28307E16BB31B8160A7AE69F989D6F4DBC183F66226983948D44D07975D9E32A89D7CF32F4F71536A944DCB1BA14ECECF6F7D37171B677CDFD7E0FE3D8AF3DB1C39E343FECD42686F3DE3DDF30F8BD7A651682C0EEEA162100BCBD1F1B2CB10DC5D844FF47BC97AE02028CC0BF37D46C3DB28EBF41C36C1AC6A928B86343521FD15C35D0E1A368371041062E7D15F797BEA51A07A2A5322756FF5799190CE623E18589273A25E004FFA5D2118B566737286D6A51AC0C86E4F96B34C5CBADCD43A7965110BD3DABA7C16BCA34BF20E18038C5D3DFD40470BCDF83A965B27703945BFA15BA9D66953D688460DFFAEE0F51B43DDE72EE55B1EBA3CFF8FCCAB97A63EA1FABD411F6AE4F1B1EE7E3AA2BFE3ECEE96AA63DB285247A0D379CAFF4C7052D0D6D7AC5C3529A10999C73052E00A9D98E14C15BF6665C9BAE7A33AD563AFC5F66B545FC90F0CFA4682EB6F1534A38390341AE2D65167AF2C544AC7BEFCC535ED93FC88BEC77B2F8AC35FA807E79DB7BF53978B62FC49F992922215B4E9472862F9F0F1C038D6E3E4F2871AB964F3D6C8A6522FEFAFB9B64F0B9E9F6316665E99FC78F817E65A43054AA84891034AD7277D4A63111902F8E2CE3AD9C8DAE8F176957D2E7B1646019D32DD2A816A194349355A55B62A878CB1C9DB1A7412B08ED77E19ECBE430DD9DC657FA3215B1A394F858DBA7AFA3C176F42DFBACE6C7C8CB8E2CAE5CE5D5B54756D5B247931AD9C5F73A6BB94992CE6936DC6A793B6A62E78A5ABE0B1A7A05BE25A59F77EE85DD74408511D5D8A4B72181CF66820D1FAF886E869CC3C8BFD204CE11436DD082FDF963A807B3B5511652323C8DDDB10055B66809D642B167C770807818DEA29BDBC9E903CC4DFA1690BD20FB73CB68AD6060F3D926EECA7FE146E346860D5D3BB508731619A8D5FDE9080C5DB568678D6F5643048A282F9C716274368AB3A007192FA63A6F0F0849B1DBB26F46C59D8177300F5AB88B40D744CF662F85AEAF94C3368B2A541ADDBF4793A62A534F93013E4F96DE578A28D50DB6FB011057365D83D3C2E9C88AAFAB05A25A6705B98711AA833DD0B83F1F1F4784D85221ACFDBCEEB3081C53CBF4B202D12C0A89BD1266D3DFBED642B82742861ACDD60FFAF8CF5AC39E71E2B6EF9AB983A508FDBBFE02F5BDA85578A2AE3B95B51D95B3F26F63F893253EA4D2391A3A7AE8FD607DF7107CC370457C525FC7A1F4A5A78486ED927123876E5852B65BCB0E9DA978AC2733A80A80BF4D285F7B9852A30D0333AD3A2BEA62ED9D139FABC989D32945123AF261F9D3D43C24C8318DD4A72C15F43AF6BCFCD7DC8F3D7F50787F8428E501DB79315A9F80C754DCBD4C850C932072DF476D53B163116887297EB010A0B3B6EE6CEBFAB7F223708E1DDA3C1AF486E9094A98EFE89890EA282FBD771DD05D293FE99DD1E02823D26B5329BA592A759CC2B56A80495BB81F855822ED4734326B7E4224482C507948E0701BE6E461CE8817CB155768A70C77782CBF1C4092B4907EB8BE23DA4B569EF9C0DDE6BCDF100E0325547D273ED968D4234E1E351F1E1CBC6A24CE6DBC3C849DB63DF46CD4FAF4308775E8E6FC14764D254C4F7CEED93C06F47183646A61F2FF0EFCF968E05BF1E3CD04B2A6DAF55063FCF15812F25438F52F11A8FF05995301F37F6D8951B290A31A90B4E6DAAA6AA1B216286D5CAAE0645D4A8564F5E9266215A4F865318D49BF4D81B32F37F945B1CFD7E386E43AA8C1A3D2F3008E25711475A0453C1557B62824CC21D1CD4F024A074F89E9F58EF891918788886E7EEA50D0FEFC1C80C3A95801ABEA679B913966B337695A26BEC1548D87E0DDD1052631264B7F440B555B1157600C6C53F4F9EB370F647477612F72929042C117D8F5B47FFAACD445D56696408A41289D76674C26BBC111D5EEC260B2A7D326106877913DC56C76D1B3D40D4C5C5702CA76ACA8A2B925CCDFB384F71164D6A26586FE383123452E480D2F5D169DB15E3812C779054B49307978B55EA1E27B4A624E8712B21D7776D13E98AB64B1FEB2D72E73652902A0D4CF887B68EE74E5E5C424DBB38FB3912CFCA37AE8A878DBA7AFA1E9F7ADFEB81188E527F652D6A2FEF8224F63F484357A0E21DE643D2BEB9642DF542BE7F698C33CB83607CA708E295DC507F22CAE71C7DFB6412A692B91E399FAEC0678F061AAD8F3EEBD25D99EABDB19820338B1830CE4597CCDCDDE52EEF9AF3D968E1B2C4BC3BB83C6E6DB137BBDC21DF5B9671D2D89C5F3E3AB34A52344EAEC36F8AEE3D0F5978E891F462B8FAFF8A7C5D84EB001C08AD798DEA803B06E6CAA2C82876B5C5260B4A8F1C9ABC17BA8809294CC572310F24C4342B93CFC81D9BAE80AEC27A52841B2D2BD15F40D59DF214FDB6EC5CBBB2D4454141A2DF670892FE5D2975C83E780F42696B74F8119DC6B73C5F1A6CC2DA93DDFA57A99FD22506FA47359E8CF9971B25666837F7183461CB39D24FEC3DC7FB061A80707567ED51F30C40E9E0FB4FFC36BF460797D3EFD7258E22FD638708AE9A07BF607B25D67F1568506746AE80468D87243E39CC851895CCE660A75F4CE48E600470F11ED9FA9537A4D76EC442DC41B39B6D738B7774BD5F87D30222F709B0FD700B143E587BA46F762373BDBC4DAF5B6F113A71BAF51F8AF5EC5A8A99F4178A56E27ED521C22C0AD370CB73FE5DB4380B71F57D9E18D585B27F4B03305080B8F2C7BAE6A83A62DCE1D9E5B9D197A9815223B5FA55585BD5B9A7D7D71009F6153F40C727168EF8CB508FDEE888DC334611F53AE9B98899DB7C03E02E62BBD755236559A93E1B703A4E4DED579EED4237B232D5CD27E5E722A36CB95B771F1C54B89E689D4B280227C90FE156C4ADF0103BF76772F0AB4B51FF144761FE4CDA47FE3967DF58F5182DAF295B384B989FD453B85CC28C79F0CDE9B87D1CC52A41EF4AFC87D7CD6BF3E7DEF6756DA659DCEE73D2C5BA8EEEF9B3408C82D5E76887FDB369E99467DDA307947C5BB81D95BB348D99796856E44C01B116ACEFEB595DF79204C43CF5EDEA86E0BB0948071A9A6CBF863DDC8CAE93A8DD2593E54290A1E362842A03292AA0C3F976B5B15694B88D8E8D419FE7EF3152F20F1CBA6CB724981C6AE9117BC134A673B5E45684874DB0D6A50D360C7CDEDF319803720EBED2F3757BC5FC2E245D36A2E48D143FBDE1DD0F41A351C6480916297240E9F2DDA2DFC816901ABB08688A0407560B82FD11807568941187A23BDB9562BFD23AF1EC143DB7ECE99012A97509D5C4F0C1674EF4B0AFC49BFEE4F58BE844FED8FA8F8DB97AFA1EE752902AD4C0BF9E546A67F45A5FE7BA045ACF9B7B6824F99A0902E5C734E8B01CB727C7EBC803241D299B5887DC2619B1DAC91AA20B44E39D2AB4FE48AA5DA7E1B147038B56CF9643EEC76A7CC29C8D15396785156DF37D9B1D658781F39F61AAFFD23CCB04EAEA44DC3152AD7E57F97F6DFD70B9CE6C8A5F6519C6B7B17DD93CF7E722542E7CD123E9C77EEA5B8537B5F03BC24FB4FCC25886348476B22B7A33832E8BD068707122F666622C18A1E2633BB323D0D1259FB742D7F68FF26E9D222919BA261491AC91A2C88289A4CCC1023891185B17A8D3B208F020D47DABAFEFCAD2F67B8AD8A58CE6060D0C45812F33091E21002A57451254FC95E69FE2889AF573CDCF7A57EFAF4B24B090C6E228E7B65D21F42F8451BA874D062346E68FEDC8258DF6A8C8078100D08B3DAC1BA9FE75D23CE8060004E8261400D48EBDB3B5C5D31A7727E761FD676829E382A3B40681D0F51F6EC6FAADFA7FA6AC1542613838B4497D85C77A7BC8C311222619155C2BC49CF8A8EEEE14B78F74B5845173569BD6BB8A29CC21237560A8A498DBD5F9129E3684FD60FA00A3094CA238F61124681C681E3EDAFC7428AC382F7CA6A4378DF5F6807F8875B2B9D874453434EF7B08167E40ABD3DFCE90BF71AA4AB261C62585B379CE4EAB5AFD793BFC96368583D14B009045D484E0C98635B9B7E86147D2F83AAA043EBBA24A3CA752C40D732026075B99967214DB565042435C222ED7E609A7AB0F486DBFF1892FE592A4DB386DFB9232B9A02CB3123833CFB7D82FC634A77B5AE6D4AE819FF07E340362C8D1563195E342FF9665697273667901858D2C1E69B2140EE183836433C24752C594386C465F9A23FF1965EE49752664D073E3543163B16C0704E914BA8B28C09C5250F8C26CFA13B11E6DF8F5B97EE043F5206C774B1DFDB3D6E9069846C62028560BB0BB7676E5E3FC10DB5589FBC478ACFC07C789FD2AA397981E88D358EDCD8B830474A5F975037C770822DA0454BA762CA072C5A42476D1A40FF797A6929051F52C5D2FDD70FD5947216B93C0DACD38436B5AC6879D64D4093729CF95B2C62BADC3E389157014E94F64637B106E9E45FA5795B1ACBDA30039AC1B405A2D740F5F026C97934365F4BEDF3F601ED13DDB63027078A06E2AC3212A321407633E7308CB9FBF96275BEC0F7EB904E8F1A5B61965774A6868FDD7E08008711F5F29ADD27338770710F3CEAD67E8E28A23B32FDEB96EAF9B48F01DAA615DE09918004D4E01A7CABC662D9756BD252599595A418EA5047C742821E14DCD04EC73BA4521C0527899D97E290209B117A34AF1D4D664E60EBDEE503C6765452E7326B5829500E483C97161DE07580AA55F8E5EE6E133904195A32981F8A055792D2CE7A7DE98521268DB2C19E5A551F32A741975E61E27F010D00DB3B00AC41006B40A00EFAF6483B6AD87585A4EE446EEA65E0A07D2A05EF842252EF2F1C150829F55F3B466C06C8A7D3B4357A02AC02DFA7CE482055F7B141070B2D3EE62CE54822607574C13C6AAA9A254C54BF371936E4F9D62988589A67717687A11AFF8975DC17CBD6306E944A813CDAF3E4B06F3AE550E83AB52672102E3A50BAA08002933556429528E723B0C9A8E22DBDCD6AAF75505B57F8C077DF3D503E5F0F26209A4E2540B1E0214799D733C2D45E55DFE1515EAEC898A5B9B310616C8805A571EF9249FF5E19A28F8F716F90AFF5745F84AB7D276F99FF1A9B893C470ABB07635D864666569AFB46EC7E52C1D134B94C5A33B83C5707B69A84BB1E3730C4BCA94FA12EFEE8BB057F2C330153574A5A0C22A2F72F6905E239BFD4DB19619BC60EF7B67779183058A24AF687A78BA14CF52705161E1D8A6A4ABFFA06D15EE6317227A54BEB32412ACFE4F30E4749474B55BB99944BFA59789E3011C3E56F5C2E152247056F012B2DEEBF17E698D2ADB87BC6842121E2A8FF031000FACA68F65CE722D252835B7A01C107410A192803513CB4EFBB35BC1CBBCB558B17BD1BF536947C57AC49E659F1B99BD50200E2C2FD967A47A0720B8A89250E1A8E66926FB8987453455A2BAD880E677B71BBE899A04B27A6153FA90863C3BA75DD045D3D207FAA8257D9892E78D863AC14290AF24139046A471742E6DC65C6654404ECF56E54F769EF4488F6560B6FF6B36BB49FF9A5F55BDFBE514B5BE5AADCEF3E3D2472E7BC12458B90DB016A055F9082BE2C7A62117983173E4BDA7B2ED884506F2909209286356FF7CF83C7E13919CEF92A28EED01634AE4EAF3A1E4A779D2EA4934D969A24F4D1E77C3E2774C4B57F9A15333F83D983983C487368D382E05EF29E76E4EBDDDC31563DB1C153D5580C9146691A253404B49B198BCE449F493A7E415808A37E6ABC350FEDF40A7ED7E4810238DA60431FD5EA2FA27CEDB9AB734751E24EF17A846AEF4A2DF4FF68E6837C6874F21D322EC336E6EE4A19274569B66E6720FFD8813CC9F212C4E88D5E84F3E694F77B99BD15DADBB38EA945E25A0AED81A2B871CA253E9433C5FB3D8DBD73B5C8E7AEDFD4110A0180571F4C3FA573DDE562E811608244F3EA93AFDD5BC617AD2D5EA84112C411D90C14CD4A0CEE50D7EBAFFA1A2A800936AC3D1DF4F13D1DFBF2D415C16A3BC5F623604868D8FB45BC4408D1D47DFBCE25661672D4F108D2EDFE1BEE01AB2113518042CD1B0E61AA3ABA9BA1B08A48C9459FDA3A1EB7A8AB8742A079B7915A9C950FA0D64F35C4EA6752F84B18CEC0AA1CEBB11F87F18F36BD640424D45663C45AB803E28F4A4B58B6545A36E483559F350CD9A65CEE435459B565CA87EC9B1235858E41865335DB2459265B12AAEF87A67D9EC7B2A6D17EDC6E24C87052E8F17DCD3776B2A15EFD0D2832B55A824BDFA9E7DED3D337F43A95EC072E29C9A4CD1794EFEBA5A23068380521134BAF910BF8E86E05DFD0FC55E022686E246DED1AE9E1C3FC7E88A44C8234018D7C500BE6A451E09E91A296C0372F19A20768E2EA2FD468A66C19993C3E4734CC357933D9D1E025EFDB8ACD466F4697F4CB28D5FF1F129CCC6AA49B9E89BBA3E0ABA0523C439E5751B01E567F19144EA95E37956DF97C092F51591686C3A4744E03AC1980BF4C11858E673BFE1C94E85CA5A2942491046E4C4CEC8CD5F2E7E471B122A52F6D4FFE535735C157EFCC2BC4B8384C38A8E6C29488D693201DBB7CB3798194C047A889F3A1CE88EB4C2C7035CF5DE2F65EE003A0EDCA265C42C3187CE2093A17A55D45A00378838EB0482A00BB2630A2F1E4BD31A5E7409A16AA3A4361BB37A6F9AB4264F8C32E32F035098AB2A2D2FBFBBAA30D7169B2A9E2C2F62D2B9B2C388604F742B3599CD246EB50B313BA28FAF5D80BEE32C848374791EF65AE3182CC4345778C672C0A558D6FC17B53FB8EEE75859A3AD2C68178299217C66F0E8FF34248096648934FF18B4531C4570D5DA2E0EB84819B1995BFFF8BED8E5F5EDA3349B9D5FB51A7849AA4125B82467B074F26C7B8EFCBF7BD102DBDADA81EDB46D33888C4EBCAE2BD7805D12C9C41B727B4551DF54EEE9D6580CD2037B5F441CA1947992280F673715C31BE3B9B5AFEFCA82DCEC02BE442204005131634BDD7AD496D34C70DFA912800BFA5F40EEB8E0035B7FF3EFDCE79ABB0A52E15A41893CB41B52A8059D558072863692B2F8E81A4DCCFB2EFC86316AAF5F17045C56556CC4ACEBF53A9F0E383FE69E9B0258C388B96C4BF0DC02DA624D1AC879417A8E17C107AED2073C310790EBE62705F775A7377BB42547B49F2782160A15804012AB3F183EAB77EAB5E749B6D2D3CA071A355A69399B6717E40CA126D9403EF923B9DF8006A1EFF7CE2D4242EE1F13E12CD6365A728D2D4233A132F45209C93A02D0A4BAED576D414550E2F6544029C9CED7CE49115B398FD7EC08303BCCC326EA5C38369EFF2EB29A9ED431C04A97CCD4BBA8002E7495A2BEDE90FF97664E182E1240A0DB573C7C9BD72131A5F455299FA6F4203EE5EAA5AC64F7CA64E17260DBF2C20EC1216A337CE2472905C2453735BE239525874A91F2669D4039099AADED582DF941606B2F226387D7F0B11FC6C1D4A9BF1E6572FD073C7CE070409ECAF0CEF6BC400EF4EE7BD925E04EB5339F4BCF96FD24C266EAB9A57656EF379636175F1C1140F80058CE6437D8AE47670F010F9A6C9FA9C6AF63490A03C5ACA4F4163A896B81AB66F87279820B365C07082D2C5525B3558A34F62B8629137793C2FD2768550E643E7400EC9814B8DDBD7926C49F5F473B7075FF7E50C9F0A87D07F7F78E8D265CB5FD1B788566FD32E003792B70CFD6416860145DDAE0E23F7A35FDE9BE066FDE194189F8411072CF98F3EBB83D5CFC74CEB3E853A3D1CAD203DC39D46F0C8411E3651CDC278EE17A05B1D3480C7748E32B6395BE228ACAC5AB52DE618F05B8AE9F4662806C2B005C2BE990081F730EF0CBB2DEE850E7D7E1476562F13925FCB20EDEB973D5DC386EDFBDBCF296952BB25CE63D5218C03D940364F2EB289EFBA581DB26B8FC8E0310803F8FEAC7A0DD8F4C39A5ADF9CB3312F9E9168D310896DBC05637725472C4CA4E41C23F4D03AD31ACA6044DCCEA1EA003B43BF11AE5902D1F62E9E67355FA1E430610FAD3541E2FA1A827ABB8A6CE3DFE2F9A0D08C57A31B81D63394C7FA2682583ABF3697FC0A6A6143BDDA824F31CA7F7C1F9CE20B37B9AA2DFF9B8821345A184740508B92C551FC575C94C2432529534637C8B39700735DDDF34C36210944194798FFB65B2B5D270BFDCBF556188E1788B0DC967DCD665DB3CE6671749564457CCBEF8B20D05AAED9BFCA559B79D26EB77F3F0C5E13FFC40FE8762DECC76F4C2521CB5DE88F00082297748EDD3FB824BFCEED859834B68A914E95C4FAD9F43D56D0BFCF58C581149C1DA03A8895512100A0B7C57403A0E853A73EB9068A9FAFD9C97A733A0520D4CFBFA2130C91938FA549CC57EF30FFA1F9BC2A7FD306743FE1886CC141418FF9764205B8999FB2FE5B5240C0B452C8416F1F55F1D844FE11EBA4341F1C4DD98D8D9F86F6D79FF9E4EC3EBB6B15BD184A42FE2E04BA35E858398ECE369ECB47A5D9E1918A082C6D6717706A16C9409FD3CE09B632250F356AE690C7A4192619FA03E3077FCF87B174103684CAE32498DA94F2E66D9E89913F220B2E7B55BF1FEB86AD258C78A02A21174860FE9E2B2CA86A9EE140D96F09FBA03F989DF344B797D284BE272C30C0AAD20E09267814055EB850645CC4C76737F9221F7383E2F502ED5DEBAB55DE36D852C7A516E92A75877C34BAE0496093D9ADED8C21C9C0CEDE3556167EBF7A55B74001884BA2EA51F1265C61A703A2E3580B48E0B1A7226731A31813B84B787868828944C15100819EAA6979EF0F72C8FC4AA69DEE24B639C1B430AEB3A1979E686E468810180E604DE4AE8CBA79810E61E4E48C0EC6D1A2AF32088CA3685F983513A4A4869182AD87ACB3E4D66B49345AA50DE07598A770F4E8304BB07D9425E5B8F060BE40100F193844648467C8421468445844F360C4CB4A94D0CB7AFFA2075D83C7F16D81182A6CFA19A005C4147005B064E0329AC2BD39179D8B2B949E0D889D9A47CEF520E04B6B48DDD9E5FE5D2D6CFD43E7604455F3E6C01C8865EBAFB18979BF3FDEC35FECFE1711728519E222FC87E0145AF08AFA6F688CA64BDBB2D0517FE3B54D8B6DF0402F7FAE70B7F5313E8A5A340C02E31603A23EAF1C623DC39D5F516CDF6EA9464D2810EE93C29B04108D768F7B71F25781C295742DB48AF5EBF8D420ED036B544A10BC0E6233328853460AFDCF175521303115801E99B393427428B3AB774A7CB5D0DBC857D925528034B5A3DE41902E7335B340CDF568238295B4A5FFB73E2687209FE0E42F81CAA3DB0747177CFD14C4E3F87C5B7988481D5BD12CAB421C06CD32D25FCFAE9884CA398569CD9DE314687043E6840D0F4D53C8E04833B547430F9C362C68408829BA6CBDADE80FC1C2BDED6C746562D23D222480DBADF78D0D874E429C1F60D7427BD29506F6A104A2C1BF3503C388269B54E14DE5FBF32C7E433CBB952CD766104E06D07D4C7E807393F778A119AF5FA34F14F5B7A9F0B0A4E8E97A7176B137D9E095AC44309D5EABA8FC316CF5EEF30531FBD17F391517C7CFBBD14B2ED4A5068258020FFA7E1D268A8C6EB082D13C98B5F2A36B691C397A15AB2531D2EB09F872DDFFAA7CD1FD8783F3333B709A234A844599DA94B2CFDFA33B561A984101574ECFA2D00207453B3669A832DA0ACE8CD3C7287354FB3D9ABC86B8B8F714D8A14709F6D097D031FD8F2E89F32021ACB12E1DEBB82D207983ACEE0E1A0576BAAB41B7E0A14D121E4B2557D15378D0B445C0D073C7C9091E229275BDB0D421F2D753A72101F22EC4559C5C97B935AE99584A9D964B84B1DDCE07F28E0AEF40FACDA9F50DC95BE3E24F9D9DF2339DEC14B9CA09A6352F11090C5EDDD256E8A132E0D5A68D3AF32AF12FC1180472D1DAACC92975AC3BE8172E161E0C0D49D6AD9FFB62485CDBA8A988542B1B59C24C01A993F66C6AD730DF8C7601D5300DBD2F7C308449CBCBAC440284BD100C3ACDE27B99A4FA56744EE9CD8796DF12A62A72847902AAE0B12A6E678F69154FFB424471C484CFC27FD041D95A3A7F8480E746BAE7C3D1BC5C252547A68C7F4443161714D80BC6EA9F7F38774C3397D9BBD891A96FF833F6E03FE6A3E91F453F6B8218D8D1DB0D88F4E8044170747B1A2F6FA22BF6A53B3D3214EAE994B2DB6E88D581E35EA347BD59069DF5E5ADF6818567D07F04009EA94BC0AB8BDAF02B8CFAEF053287A1FE0EC5D7717799271FF4C0DA255A2FCC63AA94C2F31CE055FDAFB8917232B3A85DCFF77BE14B965EC6810FC1D065124EBD7144575C4E960760D4CF83F713186A6B837AB46B2D1AE9E9CC5D697A4C77E0B8B03B731B9AE3072BCC8B6810B43F9F5DBCE7C5B474A959884269D55A0DFE8AD3E937DE9FAD7CDE870B0642D673301DDC0239C03BB41C8A978E90EB59C2984584F9B39EAFC3317A1C7CD6366E1D61FBD42153678895D6E868D2A1E31189453D020285207B54B36F45D6DC698C8D7C7C23FFF11A81816894BC60809C481F38307EBB1FEDE9AF9DF09E7FFA3D19B986BFD2B8847D05EB3CB19490704AD8172F2D024F3AF3AB1A07D9ECA591C02CD00DD5E5EB2EBE3583D82E3A5B9FF2A31DD60ADDEE75B3000F6ED4C497E48961C16EE2A8A1BD40B149689217D2B8BD1D500C97136D486829876F9C9061D1A45F599B272E44911CD3B7AEE9F0228B5BE50B27F529FBD21D889DAFB4C1045D7133ABD02BB41227988A9248A7C37E29FFFC4D8AD406DD8928FB22DE5BCF651F98C877661E7B05BA856DEFEF34D32074719049D57312C4845C1DF216C211063A74FAE76B1136965431F695017E82461357F031B67F038C43B5FD9D38A09582CBEECA021F38AAED9075310CCA91EA31D5C94DE96F3179657C15F70CEAAD39CEFD38330A299EB3690375899A7A7096D97C42CA42D56425AC6B4C110F5430AE2756C2E0220A08EFB9688C18F91FA00E2B3630E12202F814636E95C33B55ED068A53EA02A059E385A86536499EF1EF7F08CF84054FAE09E1D35EF4ED278FE67980F88E78AD6B149549E69FDFCC3B93E7C385BBCF386BF7307E4B2B5FB98D6116F0C02DA294E537D27C3EF6DCE322CEE3ADC2C56FDC458FCBFDA2A7296D7EF0A64212915B2A229044F1E6B021057D4F395A2CAF528A099279426AD46825A047C7ECD02C79D3C4833852FD7C3F587FF232E4FB151A988794C4C8900B974FB5008C55BDB9D4B2CA2F190A6B61EA118A55ED1EE704497C8588DC408D96786BBB760B365D4B78E0A5D347033E230F4C058E9AA1F7B0ADBB3B67914E8615D849643344B45E1C320E79A89DE58489AC3BDCAAE15F3023E4561B2EB887B82242AE7E39D0C74E947A5CA56E68A16E874DBE50DE183122E7DA689B185AD8BB9B529979D8787B7B9A393A92DA78D05ABA515AB8F838F9BA98F8BBBBD85B1A7A79BBBBDABA78D8785B98B850F97B1ADBBB7A73DAB7549A6CBFBABB457A4D06F75D6C76B0A70F1F27C51632D212C06F7F5193719B937FF9F1D891CCEB3721B5BB96484C717D3356E04558F4AE38EBEF2C5D1DB6D3CBE55E4E5B8D52C55EF7EF5DCF32EC77513BFF8BF21D2F4CE0EFE08FF3ABDE8DFD0CE3392ABB1D75C1CD0A0401344750A37D0E3E0183FFCDE326A3F3537ECB8C8F1705E16E266F8F5E9879832D8C5013712DBF7B17CA801F1717CBD3B20594E2A15F997FFDB155FBDBDA24093087C250883A0D026588941FB59A11267A6F3B24B150CEE2DCF387E7006598BF0E3C8A4479DE984F503153DB2F4C98689AA9E7F53EE8B6F8B34074246A9F1CD965A91F87685ED13FD1C42C0414C78F00519291DE7E2D25AA7CCAE7A5B899062CECE3D13A9C2AA8459D1EC57667CBED2E4A2828FE6F2917AADC49AC02C5494E7437E07E01B85AA43991A5AB43B4C5FAD807FA6B7BE669942222A065A513C82BF1ADF894DFE33E0B4252AD445C72A520B5E1EB61274D324137AB6BDB6068A302F0C8200A7D22F5FAC576E8C23E35851BAAD52166891297E2CB872C42D744C0B49EB1A19818A0BB5E20C27A7EB0E8F16E115588644D16A620D25EEE8EFBC96C953C199A8D75DD06A00E83DBA520852982E60B5B146485A7F6312E041DBC47F90AE4D4DBA163BF5A20CA44C11843A9AB585826FD8C587296970B2BCF8697DAA1C4AD25A65E6E1452A6741D6B8D678C8278BC674D1FBDD1E964011DEDC57EF5640D9F0651C75898D24CA1BA5961E8FC930B4F8F0890A372CF40C53A60DC48FCA98C4F61D385C5F8517EA9A1E103C40B9183C0DE5CB279B9BF7675C54BD8B7157FF85677269BD169069C840DF43D6DA96D760A2BA31A50BCA360FF688BF5ACDDD3637836E0CBFD30315E198466311A6246155CE5B90CB07D3FF6DB2A3AACE642AD15EC87E16D8902615A90AB239151BF6C14BE8EA6BF50CB7E3B7EA80C1A3C5B2D6E10BD0B2895494703D0789F0465283CC5B08D654CBE2A9954199A306A5FB24A484938C38FBCF79B0B0F26B84E3B9511B86A608D9F80CAF75DAD5B614DB50DCFB01E4D657AB338267C1A766279B43919078196BCB9486E614D67236CB651AFFD22261BD8CB4249464CAB111CDB2789A06BF495345A00EEF28C53714513C8F8CF59FF3B1E82DED422F56AB15310663649043BE9AF2DAFE349E018763DE70486A25B3AC36E57BA45B8DBD108708D6C7835C7DE3B8333F92CB78BAE4D4ACE2A00343C203BBCBFF0C797496FF567143C0403CB17B0C043F63C222477C500189212C6FA6321FDD0AAEFF1AAFC675B009714050FB283EC12C9388A857A89DC22F4AE9E04E277EE45F20BDC818AB1DF664388D95CDD36F871D17ECBFD5A5E81C20C36017536FA5D5844514F36FC60B0118843147525AAF2728AF4BDEF47092707517D45E957A05358995C213544872794DC34C9A85C0903E3FEEB8D03DA3448DD54FC95D65E8B04A1488A6ED854FEB1C571764A942B05177C4149EEE8EEDCA8D02D72D0A446F812C05B3ACBA17C5A31156BF5EBACAB50C7EAAD31C61BE94635FE070108153FEBA4114DFBF6D965D4836C1A22052E787C878BB1E67BEB4E8E70A4EBEBF135D41F795E48C309008605520A89EEBD4F8C8D6181E07250EFAA74B854191CC5C5BB58D752B148D56781A54D6ACA6079F0D826A2858815C3E8EC47BFF70C7A64988882248F9391EDA971C7CFBF9277E83867183BBA784F541D5B68E9522EC7C6DA6D81EDF77572F25AB96AA9BF06799FC036FC4653F2B686231A7C6FB6D5841816DC1BFDEA92201641C89227B68208BB37E37D75190127EA89D20EAF3A356E50FD54C9DC8CF69944BA78B49404E27B0807BB4EE7939CCC5E418095A07E36A74DE5603C987D4D44B505C4BEAF03EAAA7EA7ABBCB1B8D30CCA2CFB8D35827B0A00B8EED185FC4024E1DEA9055AC0E2632B7265A076D5D3B42FAE6E03AFFFE03E23C549AEEE321D52BE750AE9531F50FE9C24C2AF8B81BE81CC45111F496ED927581E17EC4FB130A7F307AE6E0DE9E83AC566E914A13120125ED3484FB5FDC22B88478C97189BAB5E96F99809422FE3C278AD8BC31321EAAF91A1333FFCABD8500022829DB354B6AB17DBA5420CE5D85EF1D4DF445987F49DC580AF4448BAC7537130C98490D8757A2B48202B01C1F301B941377D71C9973F3D035950E646E2A3098F9D991782A41BBABDEEBA70FB6B34B5C8B36CDE7EA93B6CF19D914CB69DE1A4C3C5FB34F8A13C3FA451020C93F9662730487A358E7F786B29D24CDC691B53FAD5BF936943F7DD148329EC5B1EFA177276EA7C5638BE74033DDA427854CF3D97F4102C21AF4FA45C0CF72492403DE1E99C4D3812144E5745CBF614C273BB501DADB772D16556B7C735FCF21A83C672A8DFEDB2138D644B7F264B7B40044567B63099233268E095A1499E832494514030D5D35BD10D21201464C8606F8BD319F49AED5F3D1DEF5F00E582F7CB363A8C7FAA2EF7A4F890477ED046D1DD7F97DA155BAC9D2C3B6CBAEDE9344992814A6ED80A5979C4FADF2EE621879DDCC89E140E352AC44F4AD0A60ADEEBC53AC58BB7770AC150993AB6A81892D15F609D8576100CFA9C735FCBB78DDC9E892F6E2B2D73C98DA79A3CCAD7C7DC5D3B128F0901357328891A4C55DC5ABF95468B3ABAA5617D2D3E0EF125C86BE9A6878CE3C6B50F2E9032178DA8B844CA542A8460B2160DCB0B38291FCC10BBC9AE926C6C0F3F1E903A37584997D12CA93A5864FCAD88C0A472C043364505E7DA6E2BD1831761653CF92A979777D49B8F7B78CE6EE6E2C4F4EC4D30E52490D1C1BD5F83B10FBDDA2F053FFBBD7C22C5E6778E4EC5DF902A180D7B89995E8E8B2BFE3FBF81ACBB4F1AF01DFF28E5626AE730A930BCF5D40DCF54DD5A9C9ED14A7110EA78E112753FE5C67EB8562BF2F0F91D6B0598AA88D75C27B07BE418BA453655A4FA256D01BCAAB6FA7B01995683D4C1F35F5A8518A894E470101F6049995066DC784B13612104019DE941D4ABEEC053E072F22E7CEB19713B7C402351FDE584DD97067B6ED07FD3346619870469099D5EC1277CB7A978D3881162E5D20AFC0878DBC9F1E02D97F47D16A7E8AF9B4CD65C109C56CB3A52EB26C136A61C8CA1FD06E0E318084354C2666D44B08DC113F22A34CD2AD5018E2DD3466A22A83CC2CB0561CDC5D2D451A18804C0312F45B5EC52D4489498C0735BEF71A74EB147F1B93171CDB45A0EE17F8A016E40B92B31D3458B9F9F9A2E3842AC1C36F429D7C5AA06AA085B4A42C0B1BC2440546640D24E11351F489A57931126EB7047E158C6746ACD21B0B9FE83A39A3630EAF9BAC7C8500AEB43C2CD57E26C4EB53C30E78A739A62BA645D4BF9BF316DD1D18B68D2877182E08684F20BA4EE23B25E445496F9BE69083DFC30BFD624C3A5BEAE480E67B42F5540BDA64173A4A7A0ED1BDB0F746E2ECC72C50786A05427E4608AF0A5DA0F3006435378C5C9F07EB365A961B2C429A04AA9C8D2EF853B01B4863473076BE3B166E790AA59179F31B098E3EA17AA11B8567BC2F1BE8829D95EC3D9DECE5A2F741817A40EFC0E0405D628267B17C4F1FCA6F01C796436904C9DAAD1E98C91C5BB8FCA7C4C1AA460B59FF3B969B8F7E72CF763B54E7F901B8FA2A359F5A5970F030D48467C26E7F95972C44875063197985E519D6798CCBA2BDA4053E6AD3ABDAD37A7366CC9B3A20055A2ABB9C12A24E79CC214CE361F231B5431B94319DA8A374A028F7B31C9C2CFCE08AFE6EF6C1312A874133E4796C53D545A5C565627C97313DD5EF58053BB3FEE794ECF19B140AEA34D3DEC529B94134A6ABEA795860072C6C2227C4562FFB10E344311272DEEE5684F936F5C5D8265B5A1E33E539928666FD70E295FDF4CA31D5399BC6A37C8D9DF91E06D33E2AA5A37E7320F7DD0821FA4E0DA7711FB9919D61116D63FB7B811F29F5BC0C1CDED79E4F3FC40818417D5B45B1F427FF2807D2528FB66185D6B4819B950F5ED93E2BE6E4607995CFFDCCBB1E6694465B22E6975405C596570B76F226653F35905ACB809E8C873D0948ED33458554C8BBD84FEDCA93C6AD5D48E859D892AAD6B2B99B806A1E654E46E3C988245F833949EE8E9E081C60892A6284BF25E3081C5CEFF0110F29590B936FC0FA73DC70A5FA8B41FE9BC2EA6C40BA1E7EF8F47A393BEFB3E9FD1C3DA4BBFCF60D0BDD8E3A94A57D00DE5FB2C30735C737B56C84F336DD188D9BC2453E0780C06CB240E922561C179D3F777D80CBBB5885A34EA6F80F7FCD061EA253548E75791112BFB332A3BE1C91F63DFFF985ECB05BC4EBE2911CE8AF040DE20E03675440F0196464151290044CF6EA2395826B9D02026E28C68E34D77C1F2D0E89AB700CCFCDFF740D8A08BD8A0D63EEEDFD67150E3706C24E0E69ED6249BA87500AD785316C0F35A5BF001762607B82A54734359EC489BB405F00E83DF83E82E0EBB1ADA6F554E2A4692B0E8A356433C14F2C56EF4F3A2897A0BE3913B341FFBE0E87358981CBF9DBCD24E8B28A2328121FD7CF9D90BFF513F354EA2486593B6BDDD32117EBF5A696C37043542CF21D22B0DA289C4A3CD09C96B365DDB4BED676DE7A0DFCA4C040F2F541FFBFA223E19C2904833EF41DA6B9F2C069B1A7E70CB120BC449F4DAA451F1119F0855D88249CC5613F6E8771D0A90846223AB3D92A356C17EAF73B40369F5F3AFEC183FDFC1904E59EF2CAEB37097E532EDB87CE823E5D4318E40248FF5D7DD55550548B961A35E0E5A89C86900A6658287A68D82C52B25D0D4F0CDAA6A2FB5D20EBC62F73AB16D77360D47B4B4DD34EA06736121AB935042E763ACC7159215BEF74AC98CB42424059909643608FF5A8CC95F0765606D3B5E9549961D00DE4C138E22865F41720B90B44381541F24E0EBAEA2EA151A200C0B94FB724C8FC4839CF3796663F230D4BD5C588D51DE8101B07B068A8875ECCE3C77C9C5E56AA9D432DF9F3E356352374001CA7D0585D6F34DB411AA602B4AA7B0A2561910FEBA7C8E0021D33337EA6D14D3DEAA34E9B577F014EA5411A5844F05FF48B6B41ED2992CDFF5D207F0010CE9D000E7A17EFFE14BF935A7627802F77425A30DA140581D63796E58EF99A231E7C07A721367350C165C0AFC4D17D4336B48FBD18F4460050BB2FC40B11690C0001748341C0323F514A54CAAEE7DE0339777690765EBE625B99FCDF41590E45143D5C41DC39203D6A08BC6DF47FE021FDACB7983EC19A33466E19A13F835AD84886C7B869554B8EAB12D1589DE86379B16DF45862D8D664C4A4604E18591728CEE48633666C5E300054F18A4EFAE907AC412E9D05B5BDD21AEB52CC0878E58E10ACC231CE241A9128FB5F40AE423AD768317BCF263DE3BDA8F06806B1D6877593D3380780EEE0E7734A0EDE8B9383F8185FEA20F47FA556B3CB4B9B74FD99F9A7F65CE600D8C7EF427C8211348BC7238A2E8276982885913DB07476A0E2CB95B70FCEDF72B597F59549AD9989218C3FAF666F2BCA1276FFF398EAC8C0EF04BA53607D50DFB4BC23BA0EC4B24CA256FD77CA7027F9EC5E6D8131096D85A97C5FC4DE5E2F4931C33F0E2DEF307DF4FC75DBE28A03031050982E7B43AB8FBE2572D6DD08A2FF2322DF5A6ABA79861249AD38B4E9BE7A0E40F072EA0CE927511AE4B8CAD3E2AEA6A43AF045D9DE8151BFBA0D7BE38839DFAD42DE2E9CA9735B5A7A07E4405EE15CA1DA4E188D77143B1B9951D2F00EFCEF7F63FE8DAD8667763462C009F7562AF2155929386C1EA8C986C8CEA61F0883061395EFCBD1AC4F1AE7F14C6FE48751CC67CFF9FB42B20845A483406851F8DE4450E8C5F66A892621408E2D1F7A69DE5710CFDDECBFECE5840D90FF24AD3DA73557A1532CFE05AC2786853DFBA1103009674EF63F70ED78EA0B027AACDA72F668736D7B05497B0DF8439EEF77B36D35BB761B68F562641E1C8A6A018522D0033D95FA2AD26DF6080FB472137B4D240F0FDB18F3E7C745DC4A4643CF799793C0DF3E8580B45B43F0D8E1F34BE3BB44938D46DA0488381D49FF74F8D8ACA4FF7E049512860AE770B986BC26521D080A0C7560581D2DFD5C4CDD4F16FCBE78D48ADF100C123C61EF2E5B91E895706487FA048971FE49C8E2C0B40059F2CBB9937020A92A089B2017E7ACA1B98BAB7FEE0CBAF421665E85D3267C6A72906751DAAC55A73B6036D44A706699845680691CEB9CAD8C0A8DDCEF4093F9C55A9BB8A5FF2792DFDCEA9E71368ACDBF20FBE4C898251837FA378434B3898104EFFB1A9CB576528DC0B9F9E4C8F6C60D687F743F3C2D10B131A176E57C1939D1DE1DA67F352C0D89824E0D26AEE58F28E977D1209FCA159A56F06A6BBDE0F95D339D7819D0921AFF971D3B521238C44A1AC48E0EE1F2770D1DC00928BF835091338CBC62AE2208B5D05B34717FF37225DEC926580212E1BBA623AE24C64B9EED76F520D071621AEB812C0CF1594D093264112FA582774107F87E5705C5A680691CA3A8DD051DD9C9B2EC991DDA12CEB840FB28282E6BC1167600ECEFE962BD6F7F983C85A5315471752BA95C7FFD83E88B66100EFEC72B76E24E4608C813315FEB90AF72FE8A2168FD588F1A6B6767FC3280F34689CBCC3129156800063FE1F258B4DB7050B793C2928085AC7C1893A1C2DC5E0B61145AEB051243583C58BEF1272945EFEC4B1A012B3F521508A1BD50894E4929960C57E21CEEF84C73CB7B8758B7CCE32F1C718182EC36A4CE0D07FCD3ABD42A99FF55C19A5078CE8CA0E83661F853E529394C5BC908624CB05062B80602549AF491966850A19C5B8BDD93199A0A1599CADB4244C629195FE2D8DA3F57C631F45D24AC18C26B6E0CE1D6647F202E62EBA9A976AB08DB94BFFF2CD5C3EB7A0DE5D4ADC63A4166A4F2C1DFFE067CC793E8E1039BC465A5D7ADB6D0BD0C28B658799648DDC992D9E9BEA38029ABA9F0D68262D84F46380F0079D00479AC788FA6735FBCDD45D8E579AF727F44E68F1562AB976DC1245A8EA75B3C00F4D91F7CAB83BDB3586A814E9A34035683CD20B3568D272F64A741D7F8B0BC1051ADA2D0B1E148D59017D05E14699AF9F09B1F3C6CF8AB23A02404067F3152A99029D1C6A653AFE5E01C8A642B09C0D19B68EFB0215D5C1B9BEC3891BA0A7CD38142FF8BB77CA46CBCBF595A7F00ACC880AFC7C41DFEEA321804CCF91BF49C6E14D65453E717AA832007BF9E99E9CC4C6CC12E7493572533310E05F4371882D1E9D7247AB59C29977A34C1C7C77828BFC99ED8E4F9431C9E1B9F20DD05EAAEF5A4A38E3DA7A2C4D2FFF1D2E4311C905713E8CDAC6EEE58DCA75638D7C93FC95A1AE0AFC45255C275569137EDA3C7C0F7D985ECEE7F8ABA9CD6EF6984CA4ED1AA4131F323D57F79D2914594386919D9D5AC4D9A35CCD38777E0139361713AE0B97B11F825A27EE13009113B3F921534380D806F7CF260C2D5FF8BB323C9BBC98B12658A4A0661E35648B97DB384CCD3C25276217BA2851A53A15A8905AE2714234DAEB7B68C97392953C041EBC11CDED777E0211A9EC5AC6562523016AEA4DA34A8EB2F9397E162D0E4A8E4BCAAF197DED2A9914FA12F71D5FEC415CDA61D69C60CFBFFE649F8BF2F85EB1F18A47454768E1FA19E6066C396C03139E920279F715FF409CB7EC437BBD21870E94F900D6E97778A335D2E25492560B13A9B83220572163BED643981EAEF67CD9188C5EA10A333B59E37937DCF3D5229E8E4B3EE412EECB49C5CD52F352C29FD25159A2B59C11CDABD57DE8AB13C29533F0BD521C7EF0A9578936879E570596024ECC959DC2999B6D45DB2AF82D0B857EB82156E8DCCFD3708395C044C7BD6AF05AB0D51A66C760DBB6F287F0771CA5BEA927E974633622624DBF867CCA8147C81EDC091AA603F2777D161391D3053B6E6A483B7C15C3BA771881EE286F801BFCFA68BD372D9574CD967621B0C027A5444BD6B0A709570E1FA94DAE7DA63538F926E9215930BC84C4C05486136AB01B54F39BCBC9FCDAFE80919793F6DA045D4FB27905ED1E4F654D0492E32E197D47DB3A7034BEB32B4EA88C7F965B1537570FB4D23CFC3F108E43EEF45D0BE4BE9927724B3CEE4A7AAC03B66410C2109BBE846D8CF63E77D696A2FF8439263FD86DF28CE5A58F91F10D2EF2EA0631B88AC90E3A13DF2319BB4958B5998CB683DBF00A98090F657C6CE1789FD047FE056F0A08D7516F86C4691EAAF7E51DCC264B6B509D44763EF2DCF0151B5B4E0ED9637F6DC76080CA2731658C22B4D63CFC24FE12988688253958B8826C67D0D090F228CA85108078E25987D320339105741A71250424761ED8347A411BD042351418C12FF080A4521E141AC136D840DE140881249218473EFBF7FA9FD2F5AA1FD23CAE5D47F3CD583D4DF2333004A433869990BB7FCEDD9A7DCBF4C5DEAD7F483DD5227A5B098D3FF6654A55F0F0CF53A2609BBB3F25C1933FEF813FB68AE1A806085B471DE745FF79575BE8898FD04582B7C4618772358BEDDBA6EEA1C83C30D2D23EF15A6B3A067F3AD0920C48BD1FCCB9731AE24C59F7D3AE45629EE1AD6CE7681FF3727C7C8ED0D85921513112AEA10D0A07D6528FB970B42BF2F9214A02F7A26EF2E867DE738DAF6739CFB340D584D86BB5CE5086F9379ED522CEFE97564D64DFB91EA5EFBBCF8D69F5E5BA8DFBA16437BFA8E3B550B8514C5434E638C4D19D6F7B404CD8C5495E782179886B914BD7D9519C857FF5D101255685B7E7051198C77DF2903CAC29956ABDACBFE585FAA10DA44247670E4FF438216EFB092333AD367B90A56D9A6CF85B6F0E048902D8BB24A6D13A449E3C3E4D6C4E4C951892DD1202245E39A4C037C316A0648D35520C8B99992B1129C1DAD788ADDC0AFABE1825E5E40298B0A154586655D5C1EE4756470318AC914AD26E058A50BD23DF30E7A790187B6AE2870C4CF8FAAF67EEB6F9F46E25FE5B42D98AE106B3E0A0B8C4AE058C8CEB672AC92A7203CF11BDEBBE1E9C4FEC7A0D75766D753B0E900341D8BDA44ACFA23EF6453D2F5915814F932F3ABB5A1F7981A165925AB9D56D2D3B79DBA5AD93F3A0FBA27A02928593FB85BA2097DF26330C64E91E42BE5397CD1A088AB71BECFF57A911814F4DDF9CC199DDA5749DD3AEFB3991765866FA3163DBA33AAF46626BA3243A8524F262F464DBA417EAB0D2094F40354F5898D224E85F0BBFE6297AF53EFC4F95B0D6F23C1049E62C311D4A7C30B6C7244DB6B3F2C8623440A085D7FC8C2BF7C16E0ECB11B1C5F117BEB6730F684ED217284AC27C23428AC8FFD36B17D3EB18CB646DC91410B8E752BEB2C8A78F38F541E715EEDC134627614AF251B54FACD6A8B5BC0AC992D343912CF99D48A7A40C447425AC403419C1F2C55A3E95194F86E2E474D7989802D9F95FC42A917C43D777A34B168481B0E7109D460686D83237B97983E356B8C37D32F869B5FFCD1BAB68922C970F3A7FB9173FA36D210D6395D59828023652876581B3318040C113B5FA54B69E18DA99ADDF616EAA358200EA997D6D6BB573ADE59AA0ADE20013ACC515C49244C046780AB424ACCBA2678FB1C8C59EB9582A5285D2FFA3AE9357641344B7AD4CDB4918A84F67A112CC94F50289D58685AE4294A6FD7351193FD55E2ACDB1C2324DA325F4450E751A38FB9D3A98364D61394BC659B5CF417972ADAD7063810FE8FACB7F81E0FD1B57A3E21554E26B5A53061305B5FAF4E8B7A01C95272EB1B90EADCC8E09569BD4751426717619D4DA0D34E795482C22BE6DA8BA31ECC9EBEF735EB16D764D00B3410AA1D902A9223293BBF900E06C47E80533E1EA6F5041F98C08F54BD0E88594DC62E4597383A1FE1E5D8A54DD706F28780F117B6184B019BAC3E1C008B91A59A2FD3C2B6D18224E9604343A56834CCC70E8670F83E12326B67B215E7EE1E37BF86D3F8610DF9A6AF4FD70D1AB2366E295E021301DA0291715768FAC9CF119270205AED47F48E9FC35902F9282D5C9CB74435E1DF0B1752A338278EC1D711500C491F660D8689B7F6112C2DECBA4977E62538CA7BFCFBC1C9DA09410C19D64D80A408857FAD09073EB2C59B6AE9904366763FDDA4541B599467773B4E12D9AC5D810F7FE00C4F2C001A87707A8642402DE015DFB6A0E622374CB0F25F41E8E41A0196C4993840FC88BB40EE0108A76EBDEE286F4A8CDD7799365E77561E44B91252C3D5E9BD1835FD7A04F11F4394C79FCB122C55C484614267F372876BCEF5BECEC06D4A9FBD29639B3A8EE99D8EB4D68D7E100448A0F16B9731ABABB6185788FBA088286574D62AFEE1914553E98F1EF4B7AC5A1628913519CEA13FDBA569872A1AF9AD87A1465AC1EA2E3F8058CF1F9C913C32D2BCE25A813C3F1B41E36EACE6F6DAE8F2B7EF26671F6FA9E6D9BD6F912D88514EF5909FF2F973D576C491C6DD496209C3DA251CEC8FA26CE5AC6E47BB6604A3B4B9F33CA0914D69E7765E7ED1CBD9BB402BD148617CC76E15213459C48BD257D0403D01709239FD098C52A88AF365E412121A844F457B3F5EDCEE4789B44D1A2D638F1B8A342F32720CD39DBC3983C94A6C23E3CF8C94F442BD287B96A459C4E38C1AFC4281119F234420748217EB9ED5414A4CCC70BE9E6301234542388F5CF3150CB1D0A45ADB10474F17183FA06AB98233B3AF90ABB4B71F83B03000D26127CC8E089541608D686C78B0800887596F47D8415DA0A3AA6FF09830AB7B946F3161FCD685DE82FED4EB47526DF5A2C752E2AE0F0701729C21FE25AF2F00BDDE357A4F19DB06B3AC55BE5BD9DA3AC5197D8A28579006DAE40C4501025E3DAC1E56F93207F7848AA1CAB7453243B0F7DB2CBE1BD25A4CF16269A782485BB55736566640CB7708EFBF3C7D548B2C58EEADF3C8D5888174BE83D8D5816E33EE5371D0FA17157D7C5E35BD470C264B29B5AA6A741A3487877A70C87CE006AA06EE1ADF45500C34C5E37F8C0DE767431D5A0F63FFE14BEAF6A95B6F3390122F4324A74C1BD15D07297B824C63D3042B46F8EC1C9AE458121FD9170009C6F9AC53E9F83D049C6E34053EC6AD6D997D8B5680EBFE6C60177166AA17346FDB8247FB86B1EE5715C2FB7B88AF8F09628CD450BC62F424CB508817E8539A4FB7FA25456E82A2FBA419422AB3506CBE8D72114326BD9C1BBA873803DD97487F21C55B1E5320E80B6FFF2EC75B64CFBFFF760EAD95450A7DD9C3218DE15D0C82541FE3CAB499F19B4759EE3A3EF96F77C81F4ACC2AEB8C5EFAF5D032C16B1B73B65AE56D9822A24F29C6C5BB4227C23D4FA69C98B753417AC2B8638AD9ECA1BF02A72FED5DBA6A0CD70E0CB9906DBE255273B9666A081BC88429FBC10DB6F814917F5190856E90D986F2C43908C63CFDEB69FCB0B36269DDED850D57D8DAFE64A379834F8B6FD45A29596322A7AF7C2E2212663BB37EABF8469D8CF11FEED5C50084BB5D1B06EE9B8908BE51A716FB18450CE73F1964D6119486831A63B579CF5B3C8FFB8737BE27992CEF35C6185D2029DD48A10F04EC8DDA3884222A328BEF5432829AC7735F1D611E8AFA1B0F69A3F487A9FA7A300A48EAD83E3932EB137A1F7A2199A8E4E88029577259D9863C278ED835E842191FDE053E08409C283418A4DD6A3C5CA4B496444E50F62B076F4B870B1F0F63C01D31787B89286659449F3536C3DEA8575882EC21785357DF71A3BFB9457A666D3008687677A77077D9967F8B4763872CAD248062E17A3D14B6249776A45688728FA208F47D6C8723365D2A3FDAE3745A443AEE95D3AA3B9B053644E02171CE659BF4A22133A372B0FDB7BFBC05B1399D3FD5B8D03846374854AF704D4D680ECC31435E538A8DBA8A71159BBFEA676A0D7D796AFAE89B7F45E4AFFE171B7BF0F51B2C0483E8AD4546D193E47D4B7470C8A456E5C2BDD916C97E2E5944FC83CAD7DECF41B1F30C2D9FBF96E5B39CA06E00902C6BEC768B0F98F1F9FEF90EA0CCA3B9516FE2A8A22F0CD40100067763CB422CF5DD683601C02BD6451E00601EE19B0600707B0CEC01002215C8D10700B55B126401408DC1F709AD8FDB1AB22DF6298571298DD449A2EBA1BC6A46C625BC8CC36658CF862A29338FC1E8892473A5C91472AABB258DC7277BBFD436DD3DEEA9E29ACB947FF55ED33F0B52C18166395AC7526037D27CF54B69EBFEAF7F05AFF3A6A4FD5D488599F144D8CECB9F2174CE64EB898C6256D77CA35B059BE77EFCD6CAF94BAE6AFF6637ADC2D040D266B87D1E80DECD847B45C70BECB83D388D23165578A7ED70F7E5C42DAFCDECB6A717B8E15AD75C733120DB2695B79A2C93816A86E47921354440BD955B5A91A74EFF1C727A8312FD27B38CDE9179CDDEAC79BCCEEDC21DE8F9271C3673564F3D05105B57404CEA2FCD81993CC8F4EB120A116626791B38813D158744A414B4AD7630A240992ED04F0062F61BD66BCB92E1A913A09C5ACBED75114255C0ABB21D8561979F5B80FDCFFD27F3ED7C4AEB7321FF0447792CCEABDB8EA4626DFFB1051BFA1CD2E6143C03D4A7F15A0649C11CB80AD9DB6F0EC146969FD63BA5331DD08C3CCAD55ACCD764672622E155CBEEC81DA2743C3018E6303B49BDDA66B14521067C300BD3905AD999E9D57B703D77753E9B1406FD116903322BF0138663937829ED1A1660B1CBA31A8A111B6BBFDDBF90907919AAF3C8FCD525EC803BB576AC5B28E062CBA1949622959B5CB3B97868FEAD1106021E13E194652697945ABA8CF560EFA44AA7D0D4E9F15367EA78D73D7240571389BA4C6D680AF4A66350D404F5CBA8927B6ECF635521C1D178B6091E21D15EE874D89ADFE0B07242D248B9B82BA4B8051C0B43FCD3331415126226D4E629AAF52A59FC93DA8986E344E2C87D16A6A3797A1ACF51F5222BA74A7447937B30DBA1FC8C0F5619597F07D1FE1DF3826A508C7F0EB23D730109150F82D5D152CAB9960F6CA965B44D2260700878025714E721140E5D7107B9E7A09AE83CBEC05B9F324A82BEF200860DB9A4B3A7EE1C6E108AF8791E5120A6125EFA3100287C6A963EF4BE9319EA7B797490A17826F785388A09DD3BEB1C0691FC300BBCD887D01D50A61A10768F56C46C6F132E12A1C30359885A6402EF1B3C305519B1D0AF5E8BDA058E0180DE4391432105663CD7556A2775BFB466B8256E01461D9370B27FBE02D71AE9599766B98B8F30365341EE3C423A1DD5CC46451806EEDBDE97E4FF4920CD1F69F2FE6BE479C575C00A80F83342408231D0212800088AD6CA2E98EA65CC97C8B0898D29C799B96E8E72744F8D44C20EB652DCD3D1C171369140E11BDD57EC5ADB827CFD1A92F5E3862F16332BFC6BFEEDACF270648AB3C3E2128A0C7F3C7070935D449315C36BD5BD8A063A1839409FA9DD0C2F8DB831F59C378926EF379A9F5EECDF9E37C1B2AB93535B128D3D5B53142DEBD7115FDE3F1EDAECD074B9C5E5FE7C73D228B12F85A687494C0B4CC1A77DB5B82A3D6A08F8ADB5E5A8145D741F4D58E9E003E00BB0429638745FE6656E0C5987FF2BE59AC556BB20EC6CAC41541934C3830E18E782C132DD6575ACF9D3E2B4C325EEA17C1212B12A99DC9FA7B81ECE0168CF1413F60D8651EA93C15D369E8A7F24AC0E855A10B089C2626A8CC9D03AF9411D0E14FD8C95079566BB192522A846A021DE930E74BC228DEB47630AF3081AF125464C402EF9304DBC9825242AFE5447F2B58441CB173C58207149A199E5FB10F9AF964A063A8FC19BF32FD3621A10F4F933FE96071CCCC57CD78AE8E06F278A0797CD15256157D84FF9E173676268FE86366608A3BEB94D8113EAC83E6B09BBA56CFA48EE31584A0FD680BE02EC03785E5BF56D83C72935424723872F24B01F144F11804AC1020181064051D1C11010068A1834A3BA882356469B26E907A03EED30DD38A3CBAC6E1D67B0895CB768335B0DD2E489C57909851BBC124023ADFD88D2745F3FF1914C4C94ADC2310324443E7F8AD38FE0434B8750DD1E25D0DA47FCE2370F6863D7E3F583E4AC212DC1EEC9793613FE95849B3BCCB35DE5F1E6E2C78CDBDCA53232ED46F80D5C5B814B86AFDACACDEBAC4689D19362870AFD06519211FD9BD0FE30EFAE7CEF1975806B863F419FCDFB9D8084FFB53F882FF3C4E08E6F11C1EC7A1B8492761A48FDF4F536A77916D88DA52F86BECFCDA52DAC5ACFB6C55898AAA05FB6ACD1F1C146984EFE6E04BD7CB3BF838E1A26B957E7018E7CC1E1C564CF4FB60528FFA58E47A0EC47A61613F2F0EEE15E5E1FE59B0F6291BBFD8EFF8F507D4CBF922F9B4D942ABF816C56F946C67FCA8F550D143CB8BC8723688449B1D27957076463E7D29F7E4B34C645F91D16CEE278571F82D59AE7E6D103B116BF758617509ED5A1F1F066A5D71BF1780FD2F1D63D9BFA4D78FEA99AB23D777A265748AF6C8580EC7FCA558E7520557F8219A0B0E28F4BB2C225FD27ED924E4C964CE0F5714430542E61CA6B0E6D6E75ABCDB1BE84807664FA51954443EDD70A6368F385B7F3F53BCE2E4ED6984F3A4DCCD827D358D3B7775AA31669E95E9ABB73CD794102BAFA02B583D8F4322E89632DFFAC8A2A8C1B1CE28FB4198C0FE7EC4EC69E17808B8093EFDB78B6009912832DC65E43FCBC7832871C5E5D095E3E3F23916F29BDAEC3EFD93D01C1A7A524B0225EE6D7864E14FA1D615327197903DA4210201371B09ACEA1BB3934337F0C2ADB190364200205B693D6FE85103F5C5094D00FD092E1D8CAA2692B9BAD335C255C5C010C06B979D56BD26B5FE199B802944071AC0A320464B3B1E1D29026DF55512F13773DD37671FEA0C959EF2F1A976FB1F4C806F03C10D40562A23E2A09B7CB29D2865B99C1FC97BA26EA9A35E9FE2155D56738220A6B05E505B53D61881919C90035B1276F11518ED79CFF26ED1B6A7FDD8BCD634AFED9131DC792DEBC9F2C44BA43428341D142364C81AEC01F215E50A53840D731ACD373C01A009C31E8829D4A92926E1C9E74949A2A92F8D37EC514CDC37413E41D38C54AE0D7C5B051FDFBD0D1AB653CB6A27079B74E615789AA8F90F1EF11D4080504940BFB47BFBFDDEA441D5B0319DC272A29AD0E7159174C71495348F9890B49D10C74C4D45D7F613E8311396A428E7F0C05861EC94006A17C375B0116F0D76F3322C4025C07F83B4A7BF0E8499FB513CE452726AB4714083CF495EE64BF701784386916B10F4046EB0C0324F20E7B15482E09322C70D1C4ACDB2B2E2F92E951968A250A6930782F06E84C850E07BC61BB4E255D3880B32E89D9A46AEE505B5282BCDED492CC3778D5EBB76B90928FBCCA4BCA043E7B09ED12BD37D7CB5400545F3844687C8803CF32650DB05759B314BC6A29ABE57C0445BA9151C7A0E5BFE5945FD61E86E7FDACED362F2620FB87A7C246455D28AA7678A1D1D5E4F7C30E54D148BCA06CBB55CA141134C1EEB0BEE8B3DD29708443B9C7ACE88E5C0408C3B12EC1F559827F97D9DDDB18BFE5E6F57D21BE30166FDBE5FEAB118C76DEDA31F98DA2C7DAB4C5B268CC0A27C483E1B424078ED32B947D01BBD93352656DA8511E1BCD1FD50385ACBCD6F815E1E0A47E5A415741BE16909760A039993A93335EB7640206747909DF8B143B53FE1D7EBFCEE7C5492E2274009BE8900D598392872BF4842A9FE3495070B6D846B77764361198CB85B48572F5A42DFCD4545B4542D5863077005EBEF9219FD434420EDD4615BEC5EFF9D44AD874DF40173A124A1F7CD4CC4C67A9A28E019DC0E29697C2A307F945C7FE1BF133DA28E65D0ECAFFA5DFD126C3005DCCA7B2CCC68E02D2CFBC4D4572C7E21E4CAC2DB776C4FFBDE5C56F617688A404DE00C2B55DAA360F50E88D90E3D3D2F32040D2550F009C6B020E0A022068E82818A8501400A44CB841250D8DCD88FF1E8DC12C142F1ACC9D9118494CA387D4A4152F6EF0D2962D23E97B4787A4731090E6AC9F6A2E51CA7068465C71AEBBB6FD91F97FE15BD27D08E99F797BCFD653F9EDBE65A43268C71F7347B6F2587F65BAAE7AFDF7CCAA428319047C76B2DAFD4E742EC68C0DAA25B570EDE1D3B2BB8BF2C4B28EEC088544D57EACC85F53255A3663ED16A77DD2D3A3423D83CBDCB783D12FE2ADD7135FE63DEF4DEC775F2C6389C2ADB9C0E9952ABAF43E11A380FF5CB1DE4FCA1095E31FE07FB125D03F0E641C4A1D871C1F27A4993FA32B267059B79AF339FFC6187B0B7B9E4F5E9CEF4E5D8A03D045C53DDF5517D58520FFB14BD792E15C88655B5A7223200C5EF11DCB06770454D0DA70E6A45F2AACAAD2FB5C117AB2B443163F6EB3C11130D0507C17B81EBA7079E5D1D7F98FE1D87CAB6C79D7A95D70E894CA128E751981FCBE40FBD3CA6AAC377F0D57B88E179639871B435013BA669180EA8084B15EB32ED011D809F020B88FCD40555864F2CE9D699A6F85127829B06069F1E800356D69257945B79CEBFB10E81AB74A1444A80318B56D5BED9B000D21285311CB1B5FA68545D08C060544C67E87EFBD3B85F9B7DF98389BA566CFCD73FCE9443E46DE857B9E7756611F3BF075CD08DA5C03F7E066C7191ABB0FB400173C4CA97D4941146ABE0AB4C4A7ECDA8435DCDE12423D53CFE8F15DA930311165B4505200B17CB54D68906379D59B4C8C6C6F3D79BAB5F4B9A80643C97F4869B590BE9C5B26149D089EBB52828E58DA1F6A3E4B4D3AFEEFBB93FABF22885C62181F1858DCE5BD1E0DFE9BFEDD92031BC696760FA3FADE62E2A115D1B12DD349A58CD6059A578B2D6DC654C37375DB2A48B30BF2D161647798D7749B3000094A5E0F977CFC7E2D7C4C45CA374AC8D86035EE4225168AC0FC8F94DFE3C5DFCEBA01182383BBF67B4E01FDDF78BFF2BE52CCD7590ABC8CB5A01FB19D3C2665916C2B82A33F3A1B59BF287F85C9BE8D68132AEFC452B260F3B54C0A0DC024FD6730699AB9CBE71C99331FC229EC9CBA9A6D62514DF6F23D2F9D5511A0729597DAAA0D6F9139C343870A748A0D815EC7AAD55DD694308FACF67E2E0111EAC1A856DDF01B36C91D196336C320ABFA21602093C20D4C688B8D2EF4FAEC863AABD0F8205DC77E02F9F73B0769A414C2D14608008F0A1140F077634FDCD39A72FF3A5ECAAFFB9E68F10207D845569EDB75670AA545FF2A502085C7780F903635B47B94F06A2BC83466A960F70FC87B722DA20EBFDD765D75BA49E8563A5CBC90C2E12DC210F06F01115E8C7D3DB88668291616104BE20D8F4E05BD30E151E53BBB8A429597689C0587801C8FCADCC41FE8B068A79BD90BE773E664BE3BC1AE12A6C80029586E43EA82C5E32E91C33C55D42DB586B0140199A8C3B7E7005021DB94B7126C84B92234843C8FA2471FE04EE41BF019F74278973778E1BBF96BA4D4DD75FFE03B56D0E570BEC679BCA93D212AD2707897CE577F31841E88CD5148E3C14BF833559BAFE616B3E6201F492B319422F43AE0030295BBE57DD0E81C4AA5BB05C48BFEFBC67F790211B8320CFE388DFB372760B05409B53777CCBB1A712A231AC4E125FC1BA92BF6E9826D9A2BB6D22547B0FA13DB968B524BFEB68FFD82D2F70DB38B41E10471E87653AEB645F9628AC4642FBF550162F5BB312A4C66D15368A31660D550ABAC39F28FB8F300DFBB34E92010C2DD95C4CC68A9763532571F130DD4E78DD3DCB227547405AD2BE0992D20A8B4697C60905CB13171D25ABC2794273820E1781A158D352108F8D081C3E7354348D6AA0FB6EE0306D3284B7A3A96A72459EF99C19326B5A5FA0314B35A67FEE6F8B2DD06757B4ABB308714B611D189FF7FF4B38C94456371296F4C3D8A9428922CC786C2B273041D3DE3EB3BABB86446EFD841E979AE1A3EBAB129D49795E36A67BB995101D44A1DACB52AA357914199D7022DC02FEFEB57AC1B5A515CC3D36AD55EF8863E9208F3D7F25B53882800E38E588DDC8A03B463635F3F7AD1F45ED888B746817AB966D2B2448F8259BD29081B4D6259FCF6CC6A57A0C6382EDB3E07418045882AB51043BC3AA7FD224C2774AC2CDBAE26867FB54DA7063CA175441BA9C881DC3A31C5DE1FD989F7366EB85AB7C3EFE77F5AA42276ACFFF415F4B819B51AFC607EE11CFA8E76CDDE035CA9AB453AD3BEB29F63A2DD4A7B394F101964E03AD7A8B36F0A4725786F132039D069941D9CD939374050DA99EE129B74C0F4D8E0EC3B4CD59944A549CC9BF8BCB26B5464226EC4193D7DDF622C4A1942811627425F952E952961624885B525BAE4534E274809E91132C8EEC4C2216CABE6C4F4807FEFD66BEDC7ABBBC127B8864F86DA0A8B8B391537B79C7BDEA683004B8B2AA94903642B22BCCBF7623C9AF5BAC4A14677F0217997DADA350316901E00012824BA33D76CB44C700D87D740EE6C91395D5ABABCA362296C5F1483D4AB4025D0794F00AB175D7BD0D928DBF3D368604D3B067D2718C956733583ABA3903C04517AFDBE9BCDCDAEB51A43358D61079F26FE0B0023415A7816CAA881E123D74365619C21878FBFD84269F9A9AFB675BA8194210F1CD0FF85D5D78E9FEAA4785595CDD9F8151876F2528BEC012225391451899EB7CAA8FBA7D490D973B00A76E10DEA74026995022CA2D670A847BA571E36DAF96E76D3C66D6730836BA289CAA4DF6CC35F88AD999367F52049DAC65B6E7C315373E9C2CB74A9E062AD2DC8B7616382656D57AC6BC55448825515678C7DC11ABBC0F5F37387366888A6D022A594FB6C8414ADF1D3B4571BEF16CA46B170115F948846F832F5C4FD43F3EAB14FFD096B62020D6845C2672D10ED2AD09928C550F7637F474775000132A14ABB53E3E4D453F59335A6429A1D8B70FFF9730FBE820F01D25238E69FC405A454E6B80E9E722E1EC9570BA617F8F231AF0E406AF72700280522CD55CBC5AACF4062AADB37C4BB946347DB2AB6B5EDFBA55993D8EA151585576EEE033BBD291467401B3137B05C35426D6BECAFBC30B6D7768B476563B0FA04AEA9207B03AD2761D1DFB73A58226B579481DC9FF85D674926E8BD5656E7AD81F459489D85DBF66BC9BF9FA76E57C2E838B13B6B3BBE7F0208A1AA16DBE97AF1B9F49C063C43AC0B3AF12D402539E91C645E6DC47FA3A17F026B8DCA4F537D035EA6EE8A136B1D8ADB058F0645993FA23225C8C24AF35822F6B860410D10FAB8922E7991115D803CD669C33DD37AFC6CFF8D3B1DFAD0448A6AC6231D68F8B9DAEAA917E209FA1606DC8541D98EBEEEE62BF2C07A85BBEC92320700403F32D49E6F7C3AA4C6E8068DDB159FBAA8FB6A739D09667B6CB77803AB73B6D5DB33EE32B41F998C28B1FB92D1DDC516B62C851519839113267BF447A7C4A85323A5E0833041B62268897B6FEBCD683C74B91A0C0849F27B06DE2E0F2EF1B0B71296B02EF00AE0C3EC3AD9AB5B516B2FF91B90A4F0CE4A96EB039CC48E5C5F326A27E281C680B14E53C0687038846E7DDCC5C232C3B60E13CBD22ECFDF77CB945923D91EEC9A7ACDA9195684F0B7BC8C104C1BB20A30DFA1251F151B2075C681A45EDDD42D532764F1586F9D34179985C6639DA0591CF1C5CBD4090087A0A846345376D9F72CA8F19D2BD1E3BB81EB456872A703220D07A2F6F28E1CB2B132D3C3174BB85ACEB84B10E42AD94ADD4EEF47B3C01B7641BF30855C0F8DDEF37B426FEF82C5BAA76B4DF7207FA530821948974FF34267C96A28E0556E46031FC5E7820F4E9456050678990383F17AA092D24EACA54C720F3F6B294D58BB9E93BA9C7E5C32C5082F7F18336FE9E655528CFDFC2CFA6D14BB6D1DB0E040C56CF8BD205C0CC43F4EC0F1FAA0A21679EF0EF18EED8C484E9DF8E714F889FE05ED5EC74222C407D79385290336A6D5B24A5C074585A5592FC372862E5F19C4047447160EF170DC162BA45703C020B6D1B84484F1D0FCFF22179073248843215A1A7F5597B26FC2172F158CFEF5825CB0C1816051D16405FA81C8691541D30FB29AC3B4DFDB94D1E1621BBCF62F8ACB25890FD33AE55DF87766A64C58D32E14693673BBEF2961F9BAC6D11CFBAB2C93BD24336DDED915E46FE3BFDED76043134A6BADDD7921F13A15B933E0652E7D2CF5CBF2F51199591F1CC1FE06A9DA1F21ACEA550A5A71D6D73DB91E75FC1A8CED08A32EFDF5E4AD3F757EDE7D7BC935D6595D818CF2A7FB06D9FBECA9D7749AEA1D6D51CF6F187445B3B233F80D8384613D4092C0B8E173FD2B87FD38F05B819F5732DEBB305EBF723C530A1FED07E660B18BDF7D754A9881F9FB189B469133C5F5A049715E9C5108E4A80DDFB1E40FBFA22E037E5C8E3E15DB1E598DF05F3FBFC8DA30374594AF429FA0787D731425DA13BFB535C6D8C81C6C4DF0D39412A7D57D1FD5645BB1E6F14CDF69CEB61929A3DA50BC638D6CB5A4474D884670BCB222CDB750CB280C79749A524D4670D6505DBE1BFC24316267CD9727836F87E035012EA8F84B128BA7027B478511E84E4AF2373D7E69AD9F97FCD6380AC1A7B82DDEA4F6523017EF4D945A4A8D231D3C97CA2DE4A586714C22F88DD5BD6DC7CF984A94AF3036EE3202A727204AFF127107ED3ADEC3EB862BA37EC735B30EF87A14292149E13B1D614450D21D28B335262A9D142BD7F98D04FF6569CC97FEE01DFE9D182226C794C9FB58059C1CA3001D52849D41B5845FC89CD7544FB0E1879A1B54D2140DE43B3A61C6E687809F5A3489CD4CFD89FE0A12A55C83DAFEAFD354F454656B4E66B768BF79E9907EBC8B41E9B03C74DD24CCF4AC7C1302BAEE36919B5DFC91898A2FF5A3C4B832BB44E72047FCDA68270854DB341D21D5F6996F6EEB5F8FD801B77AC5B7270B8B718289889AA1C0A923A1F65EDF9A71F71D04403AF3087B0B2FB590E6727AD7CA1728662FC1A25513F6C7ED30BE8A9763305B8C131BF9814AF6561974DF41186F96483B850164DF00BE0FBC09420008C014600388719E0D012A00178E02401090E4DFA416921CD602146F3F801B20043065D1D224934C47300C013E0396B2650830E9D62EAF5FD6D2E271FBE13FA6024368B8A68265E8C73E59C5384F386B4A6BE591DE3E1EE2D98E94ACC87EE9F20D6C6768102A279825D33C407590B5A07C54BADB99C56191695CAC553FADCB4BB74F7B06E248414BF03C72CB0247B3B1860BA8BA36E6D03B4705BD5E073A18ADADC0BC3EDF09324F09E7B50D79D5667E61AEF8AD3C21E736393B87DE9B82DCA6689C0E664556AD3247E8E1A17D3884152DEB183DDBE2D1398BE1C57D7D7369048F95A838EE897372DB8C7E07EE1D7ED39B21A25F3F9551A634F78D67AD286DFF1B153633E293D514F6503717762C9EFF0A44E866A23180AFD1FE5F0656F21818DCDB53DE1F04E585ACBD2A66B3F9AE82D43116C36390D77E0A1C7284E391BE2E289667B668A0D913779CC5BD133568B7E52D2A21B61463E88B7FCB8E6D2250B5ED595F25B430B3D82EF7F19842BCB9D0D9D56C75C7F9BEFA202788ECCE1418B814CF2C498AC4BBD495238A0F41A922A2FD11D38236522E719A088ED8C41110020EEAD7E3A9DF7EFC6A604169E792FFFDC15EAE87845FE2C282E22AE329A50CC780B5A4F64A92A5073B5BBF2D90B9946815A7714D5904EECBD215008E20DB41284C6420C8E7AFE24B1F5F170CFCB4279BED2905F27429E5B52CB0E287BE81D100B5A62EA2A8A3B36CA0E6526B5CD2C7CE185A5B78781844231A0885CC2BC4E1F79120DE00C819E34B9E31A0765461F9FD9D1BCB48E356BE39D1087F6170EE94E439C920662654811E599A217B0C81FF18DFB4FEC1CD0D8F0950770B5ADDE6D8F265BD6A4815B7438A2B5E450165826C83439BB2781CB40737DB997957FBF4D5F77F807C2E06766873E466A6489862CF86967B9406B31F9574F66A6BF7E4DC32E7FE838B9B4F474F07AC9987A9497D6DCBA6A5DB73DDCF7894477BE84E0A387C2A887CDAB046C2CAF71E6AF2CB53E5B32D3D378162F74FC292545C86BA15F740E06CB10B194397E1033A94D4EEBB6FEE07D4B117C84D5A715AC1FEAE6BC29CCD30B339E27AA55AF9993D941A27B4E95B396C2C63FB58E6385ABED9A677F30B495DD428184ADE33C488DC111040FD10247F6EE321B7EBFF3D7A2E080B6292719500E1CF86BBA9508238D43A39EE1B9D38E340C2E93059AEB606D47DE4B4427466A7B698081C4A13893A04FD23BA472EF91DE763AF84CD1132D795D577C0F2F2A9163876B315F753922744BE9D0673AB75127304C4417DFF68794C18CD4C9C8D1EEBA6CD27A834F22AF51E7F27050D67A870348A3B4F2A99AECE80121EA2E69475FDDA74CBC1D3E9F9ED48BA14ACE7220D380CBFDCA75F95CD9663CE4F5669E4B46E3715AB5EBA4E6ADC85973C613565A5939E975E3552B6A6251D81308997E7BF59C4A5972D507A83E2ECC98486E96A1F38727958B9255BD7A9623DB9C7C9072A0B3A313AC2779D572C91FF9284F7B686E6D7A50FE5FB194D03F93EE2E09699A679F56AB6E09B9E26C0C1BB461C9B33601127FC90C354105B2C93FB7CC349B9220AC70F1821956B616449C5F638B9CCE941742C6AD28FAC58652EB4D9469EF03321E39645E5332E25EC775A1C760E82A49DCE0BFA093AD0934607913FA86BFD7DC2DD021B7E890FDDCB5413B4B66112621CFE19610EECF2EDCE2E8A5620F8F5F40EAEB8D8589EA6B94A32C2FE7F2F2E8E0DDE07090CCFEF22CE897ECAB9B59DD0413EF93C415E504F7B45A8F2429DC9A8DD0D8642ADD660E8DC2DD9BA8DC486B50F8272A50EC5C9FBADF22D36600763CFC94D6781734129F22C60713418D981DEE360836CB8F37A53FABA405293E34404BF0C8B485D528A6553FEE77DD709E730237EB15998841F997E9DA9E68B530FBE61161F44090A3CAB0EDBB9BBD783800A7AF6E281B8BCAFDA657F370A3ADB2F6182194D3546D45DFDF1B203DB3888FE2A52AA6618B19D3B8D95F4509E49CA6B3873D32F6EB49DACB21877654F3B7927CEE7B3744E30B1CFA9B5F955996E4710157606F41950BC9FD45102F83396086D393B65ADAD24FC3FE0151F81C872BB8EECE561FBF36FBAEEAB85A707EDB2EF3FF68C309C75C44DC509F81F08366B30DF8485B261C6EE61C363DAB051D30EF831B2A1D496B23FFECAA91F032CC254EC1BC355D89FE4E8732CBFBCF3457E6D255834B076FC0C37C99E4E52E7A19D921793A1E50505C8DF4D0858F15618A795DE24CCCF48B3FB9A597235E020C9DCBBBBAE19C2FC66841FF1990FEC14AABBF13B7A77A93F2D4CD280B36CFF1DA571965D494D34BD697FC810474602919F2E1239D439C5549C54E0435B76DDD1C90B23A26DD3B1EEDC409D829F5E367822CC53101A6B35CB9078881D60051BF18649080D0CC6EB81AA2FAFB1C8D18B282BBA1E04548B18F33473AED1C25F510C3D6C1544503A573F88787E6B32362FE10A603A8F88AEB66D6DA538737B0B7088E293FDD1CE6B7A97C527B0660BC6925C69CB4C793FB9E566B0A7F1AF58D31AE98108EDC0CDC9FB952F32C4F4903242703635C18F2BD812D53D7E583CF43FA7B5562376702FDC24195CC02FB2720A50B8615E65E6FA7F564700776D30540128D45C940819395EE80168D5F41C522320C4B6EC29EB2ABB71385D0D561F4701FC93B82525EDBF4B3F5206F4A7DE3587DE2E50A28B9C223371D287654E0609838A651E0DA5B97B490F5DD7B9FE074D4910E627D8B9866EA6D997C87DA6888290E77292599A4F003C5932F4869DE88125DDD1D655C4D9363B59D5D7ADD379FEB60D0ACDDBDFF857AF92881DE4B7DF8B51F034E5E52F9268B8A4B2D1297B5601F9924A9A733C7D11B2DA94ADE32E90E52FC29B64FBE88C9567D872A67955C17ED2B972F8C79E7F4FC626C5D0FDEAE33287EC0E6645B162FABD69905509050F4F8FE21CA8077AFF7B03798D8C8BAD22F552F46F59EC9B73842C93620A3ED25E2E9F1AFDBF0FAE2C858FCACA47DFE1B28AD1F3474363135FAA40B8F07EA6291BC11DAFF2BCF55B33AF266FC15CBE285DF8B0ED03223655B73DF7CEF45429997CFB509051F452FCB51CDADA5B5A0FEA16B5B3AE044EFEA420C1ABC6F783BF1AB95C50A94976F9EDDB352F33FE707002CEACBB962ABD46CE21A7F846F31B10CFF7185603118F1E1263ECF1C02D0E90B042D96CD70282252DF9EBE2FF3F4AE60C92D5051D122FCFD5A1C1DED65AD4ED23441F4FD8B8057364E4CDF410C8C2B4C3BF0D2607D5490B767421276FCDBBA7D29BB4AF0A43EAD331B63C8F003D9AF13FCDED0C6365D8B4E7923425FA09968DE6D17175C21AAAB3A52ED1D96003FA2484D89207C783106351A58E16C3500F7310645003A91AC93F3DFFCCD56880AF5797CE181E3E2CFF64ADD616F567D20C0958BA7260A29198E5CDD6DB6863A87952603A216539A631568BB6845895060F06016FD653BB3AE4713DDB99540D6ECAE5FE87A049ACC8E5819D0F7574DFD8E717CE00DD76904FFC1908F0382D896ED231F617689DAEFF8DC07FE31722436899647F9F77B603B2DABE948B046EBD70062B5E83AD4843E28D11E015CC4CFAE4372CE5D49F93783742B1B386120200B07FCAB8C020C84F454076A743EB61331EE217F42A63A7041FE5C87DD5063D5C2111E81A0E86ADF979B21357ECABC0B812C23045576FED8A88EFB841D7F1EF2CBDD16EF10592C02B406B0C5194856F9C5FEEA5CA5943FF65BA835883B07A978B883EB2679AA55F699C4634BDABE0CA746B6494ACE42C400FD3F4A73EFD2134138C297E0BA7F4671B88E3B014901CBA680366C0E16B1C1014AC2EDBEEF0DE9151CBE8088BAC412838E4AF81DADD35ED5443BF3F07231CAA072F9601692EA8834D4F5374E9D47FD08ECC2324A9BF35595634C422687FA11707EA92FFAA4DC10C3A15889B9282E354DF2D1025762E40D21FC395FAA6BFE3E6C1CB1531B9FCE636D6AC6D5B4160C2F2C105D461EA99EE0FE4CE53633CA382F0099D19D14481FA4396B28EA763160054BEC4D6A293A26151478225E08696F642FFE679FAAD8545EF28B350232CC2E5390928DB295875B323B9FA55FE1825EB67D8EC24AE6E140E65CE12141FBD8227A292D63782FD4949C1637923D053BF274BFC7C25B727E77D8A675052EAD7629AD41AEDE3BA3CCA2DEA1581B70FF15BB5DDDC3DE7B160BFB61A1EB82058DBBB0E178973FF6E7239FB3B76201573A77F72BE032255A2EFF8080AA2A95BD199AB6E4155245592FE081BCA6C48FC8704602417DA7E00D652480C529E49BB6D310D75FFA437766BE56C6A18D76463DD49FF497C10BE44ED897A8A5E5A1158ECD97AAF8E9DB2D24B5A9E1D2FFAFDAC8F387E03ACA50C1F39E84D0F1DE92CDCA87AAFD0B9203536AAE3C10895C5243D9F3FB7839B7CA3DE70C425328AB41C898F051F371B0F11E076989D2BC4EBCF1A227B585E634CAA007729E87A7D8776342F91ADA9ACD381838077CE6C80FC19CF96D82C7461D9A8EE49E09C89A7557AD5B4B6F7AD8D5D96A066A0C344779008D976176189CD855B3401BD0AAEAF66E658CB7BA01CAAD9D5DD645C4F16A688CA53B6CBCFC0C0D47BDC38CE930412F670F89AE90E4521982B4A86A7A23CF674D1F9EE9F732826E598703F34CEF9CE6FE7523CA76BDDE500593A8292F3D75BCFF0069D0FA45C108AF2EAD5622223BFB89030D79433AA4BA5B7AECBCF42809DE73BCB031F3FD3257F9C09D9448593F96509B6CF1FE73373D871C995EAD63C77E6A23B710643ED8DEC1126EE6FBFA5C3D617BEA28AD11D30E7E10E57EC7D61FEB095732DBB4491ED60FA0A5D7E0EC19913DF003A9DB745F7F36A79CF2CC3BA8E27E58F58A22C1525A8E2F3EAB652263FAD44CEAFB152413A72566E4E535D6AB463A23A045FB6C1C8628DC429AE56E31D8EE11B13FB1812F4178D4891B7FF50BE0BDE6361B1CBFF80705D4FBB035FFB2858FE489F3233D4D098CF57DF15D9447EFF21B4B756D034A80EEB9CB32E7215C40C5C45F0C19C909BFF3068252BAF65E2F0D6CF7C8F3E0763EB472F895A27C809777C798B2E3F0FC13630EFA8DEBC49F96358E29165A2719E349662C661636E9922F8251AB32B37EAB981924730A3F02483604240F884F4B23A31F7F028C1C275EB0F5B9E86AAECBB5E8DC14F559AB5BFD1D0E51760606173ECFA45F0707EC0CC2C384AFC718F632D91DB57DA31EDDC5127ADFA1120029A5D53573B5C00DB7F98685D27037FE4D12A44507EB1B751E9FB98D4B6BD1F3DC6A937A08FFDE74367F823CE4731298F9E4A0F4124A8008070D214AFF833F79B94C81C27267DB508BDC3171715E11B8C6AAFF200A116C62BC59039F77EBD4EF7D283AD879E296533D3DB6DDE33F6966C1BBA62C4479EFEB14F96B6AF870B9798953045F732BABAA0824869EC200D3673CBD6895A22BA5FE9C2F311014A518D00E5B245A226135444B0E4FC4E6735885C39EF65F5CF16819CB0E68D6CC480076A1D9E9201EDA1F69BCB0880160ED0F601346018400B026841001675F9B78C5649A29316042EE3464B9A83338195B722E18F3BEFE477466A5CAD99EBBF6CEFF06FC569E2D7BF98647A3B8570A697047E7A511180340CC0C2646A90299EFCA25D9F8CED608925E3414F252C0B488000F21FEE4E03DEF9401F08E1FCDD966F57AC8AAAABA954D6E9B729F52B72E1230EA70FBFDCBD6E184963A4E0081B89B267A3BB44AFE73D08F3C2AC5C489EAA875C1DFAF270B105CCCDA99D6700097AF70EE550389DF7BA05940A1D03844E6D66FD5BB20BC835CA7718ABEB0C967D9C903B00427C68E7FC900357AA605F34ECE8D63AE21CBEDB26975B49ED672A016B17CFF6262014978E4C1AF8D446D212A81885BAFB19A40D59607B359D7D3950CF4012AEABF484B176F582738497A38FA2C46D971B3EFDC86753D0A2A85112C83A12FD4665DD6F67426E3196A99B6450774491815A5B6E14159742AF7BFE565A44D585B0ABD5D72AAA4F50044CCF038D826A82427FEF80ED201021B43747C6DAABF04E5059BD8AF483BFFD5F248AD53C9E7CF8D8914E1A5A4E75BA6B7B43ECD0028D35A7E2741812E870C4E37EED022C0CB089740DA263259FD6FB74A7EBE3527C4065F583E74168B575B21E3EA51D7A58F5530D7952FF2D37A5B55A84EAC3DB5DF8FFA4327C7DE938837D96B47258A9CAC943BC2754B607E37345DBF6D404C4FE4F823644DEBF9F341C79466DE8A49C17FED2D415BAA643C6515074EEFE546D3A37008CB7FBD429EB63D233969B36A07BDF1E32B080D5475FDDE01F832C2AAF1E9AC05BA319F600E8C9382A0006C53CE852E82C627CD98189B49B32BA27164240F4CB49C94DA24D2B55821E6D3AC2DCE46873D00F5F47FBCD9D5760741BB0EB240A54C1D1E449C047A1BFD6A569CC5F65EBF3EDB98C1A4437616719ECF5701BEA1EFDB829813ACCEFF44364E13606869A94AE4D01C4204D1B022F318BEA40479C42C3273AEA5EBA893D4386E11EED7FF6F55A02B944543AD491750F3EC3C8C7089DD5ECE0D0FE4BFBD6EF82571C609F2CE7A6C05950BCF1ECFAC94D6B4832FAC5EECDA7E21841A18C097E99776E1560C8ED45CE3DF71DC15CACCD558873A0D93200E24886D5F220DA5DDF4A20AD69BC8D65B053C6FB07141B35E3D626857420A5930D53DD4713E5E355DB98C4B43840C92686066368F031A187E0099F022FB76B8466C638DC11D863B857FD3A86740E214745158158701CBC7FEFB18CFDD2AE19F8971382A46DD333B42CF47C7A21BF65219D511D3A79A77F10DC0BF9CB0AC5F323BF954A69A69AB2CFCFBC717C8F0C8004184A9CEF424A0205E1B1729AD0F56E99536C2BECA77B8BC6AD6BFA4698C895F320BA91C8C990E5BB1DAC0753412995B5748FB6EA1867AE3567126D88823000A9EE364A52CE7B7AC457CC7B3252A8611D1B575DAB7D58BC3082F50A96EC12D5BBB31DE068CB7898470121146CAA46F41267B45F2B3A2FA221D3D111E1BC7C295E918C0B2701FAA4D16752E76B663075A533AC2C234F8094B6D2A0F29CF3545F5C11BFFF0E9198C1BB2109D826909717564DCF2D2F002FB9FDF76F78ED8243200A468A5BFAADFD065D22FE85E292F6365FC50590852A2F6F8DA6DDD914ACA559491E759DDE58C19136F8EC01FC5C5F2A8A0C3B6970041DC86133059BB6082C2EEAF27BADD67EBB17AB9D69CE1C77FDC25EC440AFEC62A44314D5B50535D066146D33146A36889B97E77F4954C4AA830FD1A4FE2FF50FAF1CBBBAB39902195B5F1C6BF5B2BA2DE3641D8C33C7995E4F0DB838A6061682EFA74847AB9404BA201ABA90246F83129AF657D312A4FD6BAB04E88294AA74E2DC0E2886335B1E87466573484A40F10500ABD5EA04981B3CDB1152730E354E8CECCF4B372DB58440BB4C96FE3D1C054B2B26E1A925A39403B85CD05D1F70010350F134367065083B7A77179F93BC29AB8E43B9DFCD8078581F00B7F01B6FE23BE76B534072B11241568C8B4FE0A6531EEA541E5B5F022C3DAC05D21064D56F610A1AB6E697FF932A3FE4492E0CECD539D2240F5F90EE738B29EF4748567103F2678C2F70F7375328CF55F0F3D89EADC154751D0D65D28FAB78DF3F5ADFC48E9B90CED4122291741CE3432BB5E0E1561A44302C372CECBDA34CA908485167335E11B1E5C2E9919FDD0AB9C9C77F61381616EEB67F241ED4DAD19153F3EC0059949E62CEAB0C2E248E58890A64934D390051171D335EE27784F4D3E9CCCE0538208C70BAF7EB69F58C529CAEA0A21F946D6DF158B32AF60C3C3F3B31B866CE59EE734D18D6158EFBEBB47AC55E97BC7E3F5BD2EDC57A8A0D8A81EA13E630D371E3E251AD06026A1D32C4E65001D3D7B5CA3E7F4E8E4B173651BD480487AC7E70420997F320D982D19D87C96637EC2F7B14FB5924D0ACF459A696F2A079EB8673EE0F3D7ED7FE44D8CFA042BB6F053189281B2781CEE80E73C1E914699B9D7C19D409EEFA927DA8B4D0EEB8F835EC9D7B73253D99DCB5D486960E820029797CC01C5F946AB38340D99E0B9F5C99C82B7EE84490902E471B89A1F771D2814E2FD8533D22EA7DEF799C1F81B68F17FE70F9155A2F9284206E3805AFCE525042D7FB3E0301F2318644370F0AC53E6EDD322D771F055565C496D8F4485747000408DFD13F68564999B413A74065D64587B6144CCDAF2DC132CA125FA1118D36EF05D43A2A1D4817459518165FEE5B88C79ED47D949A541370C8F59C2D43A32F53B1CA6B56D28C163A5F23ACB630547E8A78B58245F563DE4C7AB872BBE380D843C7C12721A75279100428FAC33FD1255BE6E9565D2FA8AFC478B3B1F0D9DB4C5C5CED1A788FD918CB5801D448F6A885080BFA0A3634778B3258F323A9216D16A71EF63C1C10AED73EF1BEB5725405D5A61D3130DCCFC62BF2B6BF7B8D96D96ACD544B1D645160C969AC07A4C2708BE401476EA15ECA30F264C95D62772AFBC7519AFD068A45CB6B14D9DB930C933840FF51A5C82B1A047309DA5F2C7B172B33497DFDFB4265D0E1EB01B3A2A8CEEEB22EC8CCD5740D4BA9B3467ADA4C47378288BB061F67D987076F333C821C38B096E7345DDE709B4E56501668F1900B3DD14BEAC7173A138DCD474FD0E076FFC41B63DBA4403B08D6A15075B1571AD5DC066C119B0588317556245D3E4A09FC1A559802E69090500F15194C3B3A8385EF4BE23FB1572FD3E9CEBBD948D941FE7F930789F3F3D69BBBDE17019A1B6EEBFFE0D0113EE84EA27F90D9C51CA1636CA17DB8802E77CA0A9D4065B2822997ACE054FF9CC5953C0FC9A8D614CEE58F9F298A6F629A7DA2E0D53BC7F2D1E6147BC1A1024C318853934A0F3D945BF9545EE3246A06742BA9491625B2F0B772B939ED25AA5A489FE8A008AEEA6561BAE1625FF267BDFA6973C21A94027ECBF2EE5435345ADD0D9ED4292DFD6584B3DE3B8503C805471DA01B9E112CCC63FC2623D2C8101C3F2A7ACC769E724396C2B69BEAF12124F2E0B08CA6DA1C0A7EC3170D15F819AA7D9EED58C03DB5341132738F2C9A226B5BD940565A19E30E932DF03EEA7924C301F9034E67CF82282CC139BFC24C53BBED72E120523B9891A776A0D2C981CC644CF8F31F292FE708CD292AC3DAF579A99F8A1923DA050C71CBF01114655D66094682C2CEA4FA8B5D8077E5663CBE383FF9C689EAA2C7F807DAA247D4350027F85581A2433A4A8FEAD83295E63FF5EF06DCB07BA940675B2C08C51C4CE4AB70610CC83E4ED93387E19604887974844104BD1275CEDCEBCAD33FF02CBDC3FE8D83F1F4D30C2DB6C6AA4E0CD041CA3679D49ED963A224E1E3F94471A710050F400BE9140CB76CAD02F5CD0BC6DF542E445B7F6DA74FEF617FA486B80D686D3A4EF8C14FFDDD752EA1722457D2BE83B4CAE6AB41C4079B3419D8507B18B846FC234016463286C7565D479A4C78BB381804145EFF32FBAF4C93952E102BF85357A85E5663602981B56AA0F7F9D4E681D06D01944368DD7F8F869639E0C1B5964C5F86C900E012B62A2598B2F277B8F954321136C1ED977881F1A865D3ECC6FFCAC430AE6496C6AEA6BA5CA922FF47C946826624E716673B1876C8AE3B995CC72F77C218BEB252DE70BD67B546CC82860AF761EF871E68B691AC5E265B55E3E541132AEBE9447AE9EDD3337C474AB0489DB1FE472F8468514C54D0568011D35DC1FA222B140D1BFE5CE505929AE036DD29125621EAFFC6B5A9D2A985BAB013F9A10A95183EF963CF94147467BB9BE242D8D2711ED9A10CAE20C5811AD635DCB3765605B7D8FBB80F656367E924224CBB6F65D2C7BA79A22E5592B5074E0A3237147692C72DA7D176A60C965726461C5B194EFBE9DBEF1D6D8847EA023C45DB30EBDA6325506B9B9F4E0AE83CAD66554E50F876EC8A709A63F4065587A2E8CE2B18DF2B44BDF45A38D0097EE7BBF6B46A52E8CE3F21AD23607155D95A823A54FD6AAFD81DE931BC73C7AA8726F3C81CBA9FCDDF8BB2846031BF39AA3C9F989A9DFDF56304EE71C40E19193FB85A1F3DD8E5F52A374558B2BFC0EFFC0E02814894328F68387D4B424019243BF7AFDDECA444B9A305222FD4E2AE30D62EF53BA69CE4AB0A249A67AC6F4FF0B2D21298C346FE472F28C8D14D5EDBF5332F140C60526C5B528A0AFEE0B7BC45006AD261E984E7A4FC3D000B00735B6E378816B1BEEFB05A6BAB7BFBF391DA82C26813BCCF650B2341274690A1FBAA23E2B420E53244D4AF87AF139424866D4F32D2CDC36D873216DEBC6F3C147AF01ABAB30590639B2B0EEF69DA90CD092D9983BA90B9FB2B1ED2CACD8AF831CF1E4BB47CF49EACABA041E544E01F7AE6530AEEAA072AB33A61FFCA7DE3CBE4756422366173BCA3D87C97419B51C41EAE3C8E7EC691F3274B0468FF8D73BECB83338A9F01B465E1CA7EC12E17840261621F66BDF8639BA105FA880437410A667B33265C13C855D6271C5E6D0DD77372895CF078D27BF68C85D2533E248DAE5464A6ECDA845AE0FB4F7B2ADA431326BD88A3062DF700DDF793623F946F73F98104D31A0F70FC6C11E65FAA47108C2E3EAADCABAD50276E593F37D3885F8FC401345458AC3040831FFC5C56DECF626E6F6A0488E815D74ECF8EE6DD9B1B0F5D274234B72EA5239AE44CC761E98249DBBC4914063D694F9F922D69D923C76A61BACCB4FD21B94248FD8BA5B38243D590B73ED1BE4E1F7085042ACE9970DCAAC7ADB534073B55F46F287AE51E4E96BB60CA5CF03ADBAC499DCDC5616775219C6183C3F0B3F2DD3291BF47B2BF2186EB8C677630A71A3A8D59C392AC1A5FB5563B7256ABAF7FE8A293290131577DB3E455F66519152812F5684131740E3108020CFC85EA9C9FDA85688AEEB54D3E53B00427F9BFF0D7BC030A696DA97A1633BC1988E92F9953F2F8561792D1A3C951EB232DF166DA8FF74D4E8D51E62421482BE3D86073BEBB86509014F955BF5B920886F1C107B7481C2B541F9F642248FD2051E994AD2435DFE02ABF537293C1C8D3FEF5EE7B22F233AA78BBF59417AF2AD1F3B0B6B2F58EEB5E292490B5987272EF9E4EA3CAD0F5C5F7E0A7DB3B1A87460E682016282D17911F6A40E67E35829B23FBAFAD6568D37EA7775C51F7B052DF1CEACA8D04EC732A5D777F14B2174BD20609325A9E826B71E20F5C82FDC7493A0BD98CB409276FF9A4AA27FC512C7CF436E51E3E78A0CC34F6758ECE9554FA160D053E4AE584C0F39FB80794481AAA6E9E046F85772C1FAA053EF901FB261428B65F234088A61B313EFF47E61BC0A7861845260702A997C24795F34AA698E48F962A7AD1F7F8A0B639DA8D5EC44A8CD34B9C094EBFDD22F7542812D01247C097A0F8C129DB5AC824D82F0F5AC5CB2204BD269FFAC8FC4F4B0411BB0F4E39FA8AF6D6D4F2203F3E282120450E285DAE04A3A554B4102B736BE9E6D2E09F6BBABF56E5A6C2388469F4869A94527D84C4506AA6FBD8A3D35023FAA084E60C9475CB74CA32E6FF720EDC7DFBA6D5F7D179B151574F9FE76C7B78DB09145E1E2E43215BD003514F13BE8694DBD93408214EE09936A08941A678854EB69090AA94AB0B2B6FB900E6AC477AC6F74BA5C63358A87F5B2B4B0F0C4584ABB5A106B47A627AD3BFEC326418B05DC1D4E49BDDF1F3D37844EA577741E94AB9E283D3F69BF85D19BE57D6A9BF322DA5D7D6F3297AA0A94C42A065F94BAAE1111F440A627D2F1448B7390A2C1BD538D9EAE2F15ED5ACA51602330AF9F363E4FE6186DE6AB8A9A6BF91ACBC6D56BAFB2C6AD8E984CD0D1FCAAAF76AE20A71421A8D42C6EC254C6F03D4EAC7385243E3B76935A4E49637E2EF6415D81C2C78BEBEE8E9D3FC1CEC278ACC23D041CFB80B5796D5694319D6A51090FE5411BAC217E03A74D53DFD9ACF5E435B6D48A6ED47FF2C45B3880601DFC268CD7FE5C41C96953EC0F0DFEF6B226A3D563147AC27173CC7D35F510A6B50932DC47C6C4C34AA19E8513C280956F7E5332857F13C79133F2E0A4CCDF5C95CEB421F5F7D60E00B7E99D36E029042821092AD0DE1C0C7352C039193BA48A8A3776EC29CEBB4248D315F5668F22253B57B2E26CD6F2040372ECEDCBA5EDF0F2116911F3B315C32AE1FBFC4F81B3F41A4CBA68D567D1229A499D6282B3086A878076B1D8ED5B4CEA0A5B9C5FE9211C5627414B16378A713ABA3D25147F9D53A490D4649AE2E1830AC26FE6992358BE4AA8698C45F5E321C840D82817833097458B8215075DB319B50F30A63FDBF6ADD0725AEB13DD9386F5E7AB9C952F1F0E38FB34D0224DAC6425FBA0CD2F467B325971FCB5C1D0928C20EC6E7045DC95586968655E0FADB09FA698DB490C280F8EC5507F6A9D8657853FDB15D97BD355AE8D7DEDDA7A40E31657E3F01F475743B2EAC3BD00292314424A527886E1F17F14846F2D1CAE5A26A62694EF8E5E470211E3D548ED0A560CF0F7FD48C3C6B872BDA466C51798990FF609A3F4B7BA8FF110D7C4CC487A44B83467B83E88C58A8FBBE933D5C58703D156CA5803374F615BE9CD55A30C56253089A9DFBFC4123DDF479A5EB697628A614550F550707FA7EBBEBD1AAF1803663B8966D110EFCA50169C733EB3F9789CEF0FF45E0E8D9EF02756C861F5ECD07BA8B48FBAB1D6F5BD277767D8E8F5C90309C9F2D6EBA9E537D38E4824433EC4DB75ABD48ED225B241BD9F022921250D087D13B42818855BB3F2B8DAF9E8FE40AE164AF5F72B7C6E87EBBF238C3AC0252A27DC1A9C5811679FB8E2E87E894E3C72E123B739891E60213C38B81AB1340FE4308C9EA7527759EF62429A40F95B6E7B5F03A2BCA833ABB6783BEF9C0127DAC800ACE43B6C4F96CA9D092C83053FBEC7BED9906A26929B2EAB597617F6D358E162D26238D980AB056E3F90AA495BD24C6BAFF5BB11D53EEE696B92B8008422DA42DAF5C1950CF1D07563EDDFDDE7EEBB95259B730A7229485EF8ADACDCFBB5F7A6637F9F5A7DC00E6BA15D0EAD47742ADC778286571AEAC541E3D999C81FC91C88A6D91067757A7B7E2B3D69E391F3C05466630DBAF216F89F5504AD3E80342CC88C03ED002A34259D1486023400331B6DD4CE9A79C738FA8A0E786D48DDDDE53A40CDCF2DD7A96D72F435437480D940CB0C5B259E6AB8F88516E4FE50B6B10079FEFB1471937525D85EC5A2CCEF4665D2790584E3D99579EF0DDC9FD114B13C028B73C627362807B6BF1A30DC5A646490A40BD6313C361E414A3A6CBB14E24482DA5F21751784F1EBAFDCBF877C3C71562EB2E706124639A1F357DEB1AE9086911869771FB21A6FD959FE494A21CC1A0A9CE4C47A897DCFD8DDDC74E1EE20FB3F61E76B8DBC1DF95C736D44BC787ECDF29FF49E99F7C6EE1297757A626215036D4CBDCA741836AF6A4336BE0C14EB6B3FB89AA07DA3BEAE5E90911D4D506E31FC892060934CB2807B2EE436D6C55AF86098D99554718F8619E979193A96391BB8FC3839A100EEC97601466E743C71A3D69831905CC5D51932C58D27EA762B58C676783CB0FD080041B37A5279CBE5D1783857412D66830480DA7FF56984048BFEC09D6FF9E73CE701AF93294B3122457D6DED0B42936DE43248F240D633E074963533880FCE5358EB91861D51E43F6978C9D6F72F84177A41515C7D18262931DE34BD07A4C2E0F0A41612650F0525872035EA6610784340F8BC3CFAC72C43B6D6ED17F0D11D1FEE298314C1579CF87E4F0A2BCB21A1D0E0A33359C3467EF5609621FA00FA62B681F9B04B857FE7902BA8B05607B6FCE7E1FF294286B07C58050EAD0B30B9460F9A674B359EE534EBE6BB605E9A9C3115047BA92F55DCE5F7EE942E0D10DCAACC91120108DC4A05673EEB438C5351C0F57AC6E13B33B1AEC0A405A0926F7D2A0FEDC22139908B9A5A9ECFD9A782A3DF77E095A52940FAAE6E6BFBB394419A40613EAF3AD348B2EF366A79FA439F3706A7F9EAA010AB1281C8758201BED13A9128C588C39560B8401C4594C9542ADCF1E4A8818BA4936B0E4BC8EDECEE0993CC498EC78C391FB3B6E5F68718202105BA18412660EA1405AF126D1EFFEB52540A9301B6A72810A785641E9E774BB42A4B1F46F0F717E6B17A4100032604B5AB21D7455AE5E5D74B945D8A7FD665607C80C509FABF9BF5972912885856A92A1A57CE4C3BB55A7270C52606067295B9CBBAE91E4B0AF3B1628AAFFD923E56DC1F062120772232A2202C0B05A0CBDF430480E7FD297D496F924DB3D476304BA645B1CD1D6EA0FF3BD2585421F5BEB66253595BA4B63488CE5030FCB25DC6BB8A3E4235408F40EE2B02400E85FCBBB64CCF79AEB230CABA3AC79F2BB2D4966CE7A57ABBBEC5A56B9E7F859CA2D4308614E2ADBBDDCFDC2F2BDFD8F09E87D0F6C07B577236FC8D050DBB7C1B19B8D7B3564A8A4F99DC7613C4219CE56AB43A0027A55D54F41AFB6E586EBC92B2BA6687F9B6486520FFCE173286736871AC7035749BD6E48C770B53F7505D7338517C88642B57615FC4BF3A3E2EE384B47C9ACE3F8168BD5A368F26C837B8D87AA3F21096C15DE96B17BE7B7906335AE610BC764D881DCE9169894856E495CEC80063247B519734D22C54F7014B155922747F3E27F7CF792725DEFD419F4FC366D0F478E22834C4A094E3D6B17172BBEEC7F86936CC7BA983F2CF64639F586DA932EDCE9E357842F8DE0876CADB83C1F1C94AE2791390EE28FD2C3796D995B2E5CE15D5AB72B193344004F6B30441E67EE6849091239F7FD17B008794D5747C28A87720C7CAC891063380AF7EEB4EE482EFDA4C247F37FCAD2C7A134A93E3DDC96663110414F186AF3D3359B7A128F773F85644DE7C605AA954959D93E91E5FFED74EF5F86E8E8A6205BA82317F50B914E781766E76D68BEE64C8688140B2854961DC915FB9DE2D85FB31E8051E3F400CB55219C8CB727194CF3A0CB077319115CE15800CA3A9FB7F92BE210DBF0DD0798475272F8C6C2C7F9BDCF940E8EFF7537DC9FB09C11A5715805DAAA8AB094D63E05046DB6E2E20EC0A86AE447152647AF304FAA53A542F0973BC74661EEDB4B9519B2A46CEE0B153E248FB8E2C4C8FCEEDCC45F04FA065ECDFF5BB6FD4154E385466E9CDBED7C0E1AE8C17E805A6CCC3AB929AD82E3B3D44805249EC67A7AA621CAF77709242B8F363140B4FFBC2CC09D45DFF1EE56C2D408283BB4306B968D1A64D0F96FA60B7B8C32121018EAABDF2CB3ABD8E7A80E11400F518C49183CF2E116052A5A53B172FC1AF201745DB9683E305BF3481CA62524A0B898DA5791F1CF8CD4E82B8BB4F535BD1AD17085DC500DA8565049834C3831E6B4F7FABB4E128E8E24F3B410D435EAB39A46A02FCD35A0011D92E82411FC57BD8258E7AF6AB8FAD7A4A5395AF0F9ED59F119322D69DEB987FD08B8837060B05D558E7403FB6597B1B2D04C735F2EA98346CD886D8FCACCDA3F6DBDE85629A0FB16AB23564050ABB6B4650BEA09E4FC0A0EA77F7290747FE9D62303D45D06AB29C883B102449F42FB7F9AA8E8E7CD5F5B82465CE5CEC8C4F0114203D5B2F1AD361711B46C5F0C36FD24D6FC650BEA8341C0B3D9E70D32F86E12B98FEBFC75588994802253A307DA551B3B76FB1E7EDED44F205DFF6B9A00D3D7E1F54FC629EE6B6337D4B361670FF6E8DEBBD2939B529184CAA9390AB8FEDB72852B189186DA1A0DB927941B17B5BF48FE3B2BDDBB8653576FF9DAE9C8CE496DDD73DD4574F627DCDB425A6360DBB4C9C786B7A9E5644C912BD7815818A93945A432C4E1569638E5CA7DA5530A7CAAE2D2254DE0CFEC65ACE91AA23ECC50DE7D3F2D7C2A8C0325A78F3DD1687F76F3AF8869E64D078DE47B1191100138CB1425C2979073701B7B4A398F178DAB837C74B8E416C6DEDEEE566E562E1EDEAC36DE5EAE9C0EDEAC4EEC0EF63E36262E66560EAC2E161CD6CE8E96C6C69636AEE6C63EA61C366CF67079677DB312BAA603736C845863B5A3551DD783E683ABDFAF5F7BD10691101D150903429D8C6BA2A831167CC09ADB0E9F2CAA3FE1EEE375C8B6EC74EC655B8F32C5E12039B8F20BDF8B25F7BC67E842514F46CEB0B3ECB04F893059BA46C1F2C618AD3C40028E6F92AA597731A240EFAA711AE8D32BAAF1DB1153CEDEC88C55432F346BA62E105500D4DCF76430F12B6C8969E898D2AECB6F5A3C1707C36A47EF3ED7C25C9AA96E61435F51C6DCB2E4EAE512F0862350B1D36ABE41ABE5490EE7CC0B5FB005587AD746F13B7A24CD1A16FA1EE6C081496AA5AB4A91A029B2956582FD691F6CE183BA56802CCE276A6723286A6F2B2828602BC22F22C427282020682B2A2C646B6D2724262A24282A242E2EC82F66672F246C2F6E63F33F3F2E515B715B6B115B7B615BFB8B463BA96B27194FCCF7EB60A27C92E7BC6573D68CFA9E7EF48A9C575B3CEF37E336EC020145696BA170FB49FC87338E5DDBE5DA499294DD441D557B3DA3960C0345EC352E12240C40AEB6612AF64B5536FB81ADF45D25872C06A5468F7C45F636BF462DE8BEAB7107A3108A561A05F9BBBE0B03F57469FB12059AFF9E3130375557AA1DA388CC975CFF4622020BDEB164BD22F0A6190E86F424F5BC4E0B66D3482C28EC2C8A0B08C455BCF3E88145F9D5027A62F3B56F78A0A54914710574C75049BE83B044B40F0040D70742A890FF22F906330A019419739171A42A0706E4027ED82B6F82EDDAB79D96EAAF10FC03F7468EF8BF56A9679777CC3FBD28157D3CF55582458E3F6F3A93C32A7DDE22C1D36A0B735E58AA25DF4302ACF690D514A6513D7D46B2A3EA6CA705D037BE58F573F852C49E5414A59FAF594AA3A6C52E393EA2EBC5D07743E4D33BDDE5853CBF217C686A7FD25D7FD66F8AE1083D427D8F81D872E4E5143A5D28111130AFCDBDBE1C17009338219D4F1F017E35FDC9119E25ABDE9AFE07FEDB81BE0631FBAFF82C391587078BF1790DE0ED0F000096316B2ADE6EF98C9846DA07CF1FE4FB1DB91521000088095F1EC2C080C3733AB79297D1CF19F0A4A111DB049462EEEB929EE5734217D3921F5B0ED362072730BCEA6E19386E5F79F6785B675D073F5E86966014903EB4C88E086BB9BA582FE1FC1B729203D0C1D8202027A51EFB2EE2E3E06C6925AC1A04CAC60301877F8630FED40F6380C6F140C0CBE73CFC6E673FBC1AD49057723E76348A05CCE103A08ED59E2F334931F827494DDB9599F945E8A0644210F03DBB21BDE5AEA4087DB8FFEAE27F49323EE88200044CB40D631C2C8240A58400A8F066E92EF3BD0F2B26A61E1BF44400808E164179C3391BD5DDE7E87D70046B7DCC7D8919A9B53C0D43A94957D624B50F2281BC6497E40EBD205C6ADEC903619EF7C15F2E56E550EAE6B56772D77BBBA1DCAF325C559F44FAA82C1C66DF476DD96A9EB1747B950CCBBDCA28600D628DBFD46856A9CECB4E7439694AA83094C762E4AB157B9552A0212B6AEF73D8DA63FC49C1892F2F19FB4F3FE7836537C2898CACFE6804C65C9949460D13D6D857295ADC9184D5D70194973AD518CC32FFC1D26FCF0E7BC221A04517D7430D7406C6B9ADDE388C7D804679CEB68FA6CD0E42F443EA7B3BBF877DEA4F487FB51F7EF9196B19F295734B7DE0C7967D1B82721BE30FFADBF23220AA0B35761821FA1A95A8DF1E55F4B3D93545615B4E58637B00006981D42F798D5396BBA6E377D2D96383C9383CFD0454D4833EC9A2FFCC8C46D56337C859EF1981F19DC746E2EDEC35E54237F57CCC28F652C992758177757FAA107A8A519F89B0C4BB02C51314E427EF929BEEAC6CCF66721F182617E846C23B0ED4B5683599DAFD60F938CB45B2D4C7D52C2E0F18952D7E504FEF539E3366C1FE2E58883B843F3EA5FC47DBD0F221541004C18A8B02DEFEBE476F7A3A879061A337096D678211C46D8CE4989573AB3F0D35349EC33F7F8917E7AD58937C971D18C3CE363B96A946E2A24D5F5285D82AA5108B0BA9932F704742F42C416B90CB898B16B6FD1CCC446AF0C1CACC3A16D46B3C46557837676AE7CC6BD96FD653CB1EBB6064E88176A76D36F05EDB8AA293E3EE1EFB4890B6CD710F06CC45AB6B9954B13D26682BF60DB6B9E9BD9EC624ED27D25A81A3034FDE21EB1C6BA44D48977BC6425FA56D6985C001240E54990FB194889AEE4B697C3177235B4ABABE6419801EF7CD708DF6D88ECF799006A7D44070143915002B8FEEA888DE09682D292169C6AB18CCFE5435D2D28B73A61DFF45BA4380C68B54DBDCA2C66BB8075839DA98B490117C7227AFD5D9A8701E9744197EF42E54C1679488A758FAB2C6FB3F49892EB014A4E72DB7FBB9D5D026B448D77F9C87E0B6ED155F1C76167562DFB515925AB1D92CC4DB6407C8100AEAD4B07BA0A088CA2801C25ECE7285AD9FF7ADFFEE193D2FB244A78810903D636D327FC99D6F620585819536812C3E9430AEAFF885F3CE881F55FE0CBFA93E65D65F9BD68181402F285540B0EDEF98896F7F67E329A8D5998C962FEE4EB1E2BC6410E43967042D3BB700851210081AF8F64CD44684077F4F5F40FD2C08A801A68880928A2C9AD90780DA51A8FC819CBE5D8306C24723EE78D05CEAA3FD17C1CF5307B4F50A154645F666390E10D87D9714C1D74E47EF1A8853821979057E9638E6247DEA07081EA875C4C5C0A460E56AE7E2EEF34E909D2A7A52710AE8DAE5458B1CE45D2064342DF264B33F843484DF9B1FF80C465097CB2340CD15CB4B5946E4F41B76A2467EB3FA2F6C816E6FA57D51CB509B9C88A173189DDA112230FE2D64899285E02359985AF176DB36A397529A8DBA71E0A3ABB6AC799113674257FBD6F06D4DAC94A6F9BFFF116E7292E52F4B3F4A3B6883230DEB4F9F307129327908BB152A96FE26E0FCB40C2EC71A82BAEBCF9BF8A3BED351DE57CEDAD53B6ED76ADE5D24F9BA6F804627DD2594776821023099E7D5DC9C7FEFAF5464348A94926476C06D643B24E7D55099C7A14BCE7D0BBE7DE6E1B6C93C1BC5A586DA6FCC05C0B6C665E7DA969B54105460DD592BA8587A33C1C153E228F0E984D50E24425140D43CB386E21B9487F988616329ED3F6A247A0189AF293BBBF7363D67DB6DB67A26E36434549A8171868368E45A54983EB995C7313FCA6AE867BFDE3AE23DDD0F96107CB839D17DCFFC4FFA8F181D9E24E503F1012C266AF79772D97049E022650F8425DB6AB32300421425DDF66E12C94FF49B510668B530556DFC7F1B19FAFF0B8395DAA9B2CCE8901502E22644F63B11E4D59B7A214CCB320DD323F68A918D1DD38F99B37DCD707195D753930A4939946AA7630CA80CAF2C05F916F2C1022FF47E3A4C317E7A54156DA826200412CF7ABE189B5B7EDE7C0FE5A750FEA7C3A294F968EC61BFB5DFEB4D1DFDF11508AFFF618FB9BC05DE7D096A0AF192CDC9A13AAAFF76B709DF4BB28FDA11AC696F23C1E0B109291E3383EE2AB659C05DB9B473001E3670D6FC7FCA704B5FD08BCA3BC938646DC34D14FDD790B5AE12C098DD924217A1B76371B16170070F4FC020E13F81EA2BFFF9FAB62C99505A89F19BE7FDFCFD68A6B6DFE7417F6A05BAF017A1D12F777B70840361C8EC486205C57F8FE24856F8FA47283DC6820D5251B8D5A65A6405975B5A7AD9138A51B6E54A36479F3E5398892D89AC8CA28A748F38D9DE29F73A11EF5BAB3CEA414AECFE3D0141AAE79B961C55D9751B39BB23BC78FE6A775EC47E3662EE198196B1C9B287AF2C4246B4B96EA64A27EBB97A843E5F3C6D533C36B99ED370DFBD317939FB5FB8D14D194CA9DF2D15A567E57D85B14612F0AA88C94AF50CCF5E2237AB91E378199B20F1393E2165EF0190864986DFB1FC7F8338CB8700A8FBAF4486686F6DCB098FAB878B1489716566A5EBF7D4729976B682F248107E9A4BFA7E05C3A15BD8EE8367729FFC38FF1F5D399A90AD9C10A36B2403C01D12EEA995BA6184ED37FD3125108A4806845983E6A3C049A0A2A5EA25B5DC1CC13F700D1B6A7ACB412179A8549F42BEAFBDF7EBE3396E17B1CF111B020FB143A31854F11E8DCFEC397079ADD48A1CCABCA42A5CACCE3F5BEB27378D53B93ABE1E91DDFA5B7ADC7FFBC4F36EB1C46DD7B1791A634D259E4AAFA3D0C5E07616FCB5A15FA85396FE95DECB4E6E5018E95265BF29C3606390B09256F2FA8E3A925FCD93E52DABE840F07054BBCD2A17F3D16692B3EBC95085EC77A8B7F5DFB096B21CB987FD6C2AA72E567AFE688EEFEFDEE8761E6F1DD8E6CD6E08CF9100AF7A5470D69DC15969B8CBFBD2106FFA328D793A4CA8DCFF9C9DD7D96D0184B99D4FFF0C7E33EED71A5149FAF19037ECE9666E3E5E6E29182C43331973688C017967CDCC16876344DAC793253FC8BF37ECA499A57EAF0180A58DBE6BC4FAD4F4CFAD0C0C5C98E5BA7F4DFB83853C000CFEDA33C1A20E89B3FE59EB04060A2D451CC109FDDBF142568AFCF257EF965068D8EA32EFEC6B44B3AEE627EA10726A3A8A78DDAF2A359253161554D0DBFFD28A462FE3548B38B6F2BF77EA9DAB42A23F430F5B0C0D4D87CC84EC60CC06373E084FA7C9F602365EF9A83FE4A1DF125D0BAAB774699895AA6169274EF2E3C529EEDBE34D6E0E580A462F9DF546064620F258CD6171795AF2B39B468F0A580C3E59526E9592C2DE46A31CDC7C9FCB89BCC017E41EF855E79386B0ACFFDB591256F854179BF1D12D9D2027F80F87B524E718BE90FC335DE1951A7275C5FA0D8D29FEE48B48542E5D643E8707E71CB60576A325BAFAF2B97F7A096E592DEDA11AF0E4B5F7C4E92E2E0B4A72BEF5193C6CE6CD03FEA6B747A97F03B55485F7D16D98898E0DA64C1BF9D53346D5728176B960A6237B547DF1992463F4A3C0EF5AF73016B51F1003E2144919116778E104C93ED53AF9D02B047F8C8460814D29BB4EFD8BE215955C51F2A3FF94F7AB39EC933F74573C2C87C5670393FE558095600B7CD851C7A7BB9A58FE4611D30FF98A04ED24DCFCCBC175378214C14E9AE8C9A616AF4D15F2284E1B3EFF5093C4AE9F77FA8AB146606711AC9535BE5CAC45310DAE826AFE26ED6DAEAF654C6FA278391F79837D1B10D89B210D0F22EFE0EFE190A48767CBA7118856CDF0B25066733C035EEA1D538C27C01D7E211F7A3FACB2473A9F40F203C1EFCE7FB7CCD03DC1950D4C7BCF6044C556C3DE85678DE56DFE2437EC2661A69E2AD4B7BF688148100B13180CE09935EE2C0380DD3A276F030080EF77D01847A43AD05FE19A46FC37D394E6709691B6FE004604656C70A4967CF4D4BF89E33E8FDDF89331E9BCCE125A7822F92BD71EF392EA36BAD513DAF2C4E2D511631E7F81FF24C5E70195B6DECF50B1F36282969F0BCB9E5F52D22ADF4AE617B73BE24B9ED75362134075FC3D430B03003D93033A0060366D001C00723C79640140CD0FC105507EDC12D50138AA68CB650F53890A7873F99A2D5BD15ABA593AB6FAFD3035133782BFDFE95CF939BAC89ED138CEC09AC35BFEA09440582E6764631D7237322773BB3145ED47157616908B751C9971137D3CED69633B47B7E864C57346750001ED15ABACA2A4706ADD8688933D069733BBF5D78ADD1215513D3021A44FF670038036E4FD1F3D6F02B4D3691265BE5354EF14C822291E5D6B3387BE3AA3E6BC6978C684FBE3E87AEE5D9BB49E53D02813894A213381FCA736D37CBD23C6A289645A87407D246CA5EF8D6A10400720A8D08DD3390DFF671E09C783689E1F72CC78864447794ABC45ADF5FD2B5CC3DF08C8C5E16ADA0BF7BB759FCBE248BDCCC2460F4B2EC6A7287984948EBF0A772819DFDD8E2F26EEE7D0D3165EE007C2D12C71D26B07C01956F1FAD97C1B05F0AE7B8F6C6B24DCE4CA04394586B75FC7BAD9EAFD9E3D0ED8490BC49B491D03FE90738B02794A998EAB56122FD0764C1C8304B7C8427A7C2A15BC0A75946DD2E3CFE5127C29E0F40FE75AAB4A5017FCCF57E15D61A4504B01C37C7B2CE0DC12DF98896F40A3AC15F34D3C597581EE0DAA814B9796004ECAB63763644F7F7C008E67699DF587520C661AB0531F2B4930F130D66D53F007C95000914C3C59A5B5F776E67210317839968EF8FE5D5900144DE38837D75E102074BCCE861F66F5C1960515EA19A2857D21FB558B7677717E4E77EAFA6F3D3455FB037DCC5694B3DD1A57BDF60FD173419FFA4080F3ECA5ED50B15F7318EA80A3361A3C662C0602AF71A7176FADCBBEAA813E8C02A0CF3E82D273C32F661478F94AC349661EF398E81D24D787094F807CAFD8AAE995BF816F1F0A422A38884EA9B5E05CD2E6315F52DDFFC036A279CEFB463D77C749BFAD5A70BDE4A8CA6D1689D48AEBA20CC5E8A460C381DACF6A1FE56425B5E116DF828770CE34FC0D14145EACF8CC34C2FCE6D8F0F4608753C47FD3AA34FFD46800D5C7B3CAD49C85539293878D8B838395D9D88499858D8BEBC727CB25CACD6DC1212AC22DC6CE2DC92DCE7986346091719631C35665BEB31379263A46899B5CA75A145D76F1227866AE1E0E05CBAB32D95C177B2AAE50545441545E2B9B8A8E2ECBF416AA569AAFCC2469390AFFC1809018D88B613EEB3AA80F0EE2FC2C58D95B64F572D29B316C42BA7A502FD013E89171830A204DF3E655128780C5B179E0C98E5AE8B9DA418515B360E565A7AE2A2E9645907F7F8521D07B02E1B5ED5BBA1411B007DC2316A1209BB181D7342568889F55B016406C120B830A978773A1F59E3C2188E5B0147DA5FDB57DFDEB4BE447CBFAE21C48B7DFA640B915556DE2D40D0CFCD2486E730C2295007BA2242F75DEB632E98A1754EBC91E231E80109AA19F385F3C045CAB2FBA13ECD4313A9536B55B10B10ED9ADBFFD1134B83288FBC3AFE251818DAD5F7238174A29D477B53A324C01A996B86522713BE19507EE5A2C7DD78C7007D05103E0D7773CE0621FC550F04DC4B15127C29536353FCD4646530FB1E10C87BD6EB2998348BD78329D50057348E1231AAC1444C89D38A06064D3E7A59FB78DD620D2703E56843EEA1A3DFE30022F01E4E22460AB6674A399FE20C8D80647669A915634C2F8F66F7404BE2DA3BBD32C0065F3EEC334AD990BE74EDD339473F1FDDC96ADE41688CCEAE79DA3768E5CF6C14FC20A609458E9EEDAB0137571799A0CF63394D0B2818AA8B2011FFF4DE6B8156CCB6E78F6151C98D11B485CA87552D5275C0B683E34BB407A17EC6B102951D60230806186121A8B50572A4D5E41F5ECE1EA87CEF26FE94C10F2FF14013D516D94642A0FF0FEC68A4686F84960D1DFB5875E3DF61AFE5F724C83154854847B65D1BDCE9DFC17512604CE34C393BE7C539CDAAD4FD68AB7CD0D9009D7D96A6663927BB88B8630EC0E8128D1DCF1CFF901D03651ED5E6B443435C8D48DCB78B4998341C0BAA4E5D57970E947629C6AB75CD96E677C7E77462A745CA7F1620AD769C2DD13209E6F49290B8242442DBE72FB431EDE4C55EC314C8757C685F652ED314A3DF752E73B00E27732A5D39FD6F0974D7360D5E22B6E205EE316F98C94FC4549B0804C66B38DB6F917B4A7A927859FB5814C0EB12AC578F2A3242D4FE38676E7A0F56AA74B89B1220365B32C34B894E4F2FFB2772A710781464E806F40094D17FF670044F4AB40A052274C38D5C0DC37C182F7B4AE612FE6813D73319702084750142B65754E5A29565B63C73B2E70DBFCEC3D56C7016313A9639426D73BDB4F073AEB8FE03CDD508AC07A26418DDF61CAADB8DF78B038E955BD0705732755746E753E3CD04EF9787A4878CB660DB116F6293D55D518786A19181F6EF872C1EBCC5E6248391C626E90FF224F06AB7E908BB8F410B49CF4721F27D31797D421932A1E2D56B39BF168ADB3CFD398A20408593D14380A9BA115FFCC41A011CD8FF4BDD34ED4150D241253A8BDB85AC2BDC26DBA6E8573669037FFDA946EE18165CFB7C08C6883ABAD6669E5E224A95DF22EA890A55D94B5A71136A5ADADD3E049DC7A162E7AB1554E3703D9EC3B53E45672D8F4189F05BA81117894CE61FCE11E901EF3E6F0BE6E38B1B50E999E6101D31EC78F4B40E5ED02451CCDAA1F5883C31E7549C3175BD03D3D6E53507610D87204833828B35B500416CEC0070A9146EA641AE83CE1E53BB6550B410FD5713C6EFD8D5E159B20FD3D44F9254CF864CAA2F8F19E3347FF0F12B5EC836F48C49D2810829F747FF702419C640784C3A88DBBC30AD82038E0E36DFB3E643AFAB78899B4722DDD2C07D5B62A8C6F6F506230E45AD65859235F917E2E4D13A5FBE5F5693F3C9B624D9F567E6E19823BADAEC7D51BB58E59D64ED9B3DA5351D12BAF46DBAF2CF4E6DE90B924464D2A49AD0FC6AAE5602792CDD700DAB554F63258568787B6EF60B907A4D5B683BE183898E4CFF77B0FF61C7CBC24F789A503FB585FBB29905EA7EDB747899C9ACDB2F413361DE763D8282E92F8D10795B6B71976333BAF764355BFE202CFDB224EB1E45F9C08B173D6FB4E9AAC2D750A43BAE68A0F911C046E278E152B12313D47021487D30A72EA5816C97AFA8F5EE35F5DE7177619EB615E90C0413EED9486803BD685BAD1CB89E2917CD581F7265A6E8DF4A6B4861A55EBE744764D98C392144D9AF7E3FC2BB3F2289070875068B51BB7B18D4DC7A4A51B15AAC249B21BF2961ACB3E2D63B61394AF8C7BB7C133131518ED80C6A1E3B29D495014AEAF35907D65720A93C1D15AA62C614B7A26440C8703B3A121F309482ABFA97EE34547788C9066585B27E01D78ED3E5CF2D8A48685C72AD349B938A6DEDC54904D6DDDF394FC8EE9231009F06A9D97DFBD9794578118714835F52CD36C4C21718D7668F9177600D16EF94A3106CD036564FEBCB3BAF3CEC7B06C2BBFE378E24464774B9ADDA9328DB5E1F045E20992CC8E141D5ADF0502E7D346502E80CC0205BAFACA89D24E32C1CE32678F34A8F0ED2FB90F416DF3FFAA856540DF4D3B62E335FC111C040ACC1901A1BCECAF5797F48E5A293A26C6510BA0E22A4716A2A3B21BC97518A9FCA3A9597AB1C503A4725BC6C2B4A4C43546FEA96D354355C20D72334F54284748A3B76F16378A0DC424C9567F05F6F410F0FA73DF12DB9E8EED7714D970A3904BA6252408964454D488E0E23A74DB2BED7D50B1106E63701EF9BF37BFF7B1B4BD5735CDF6FD835A3FB5EF4072D41C8270122EC20D7804BA2B78630D460757CFFAAF63F420097C49C388E5356B739DA329746AE91A1C5DD9BE4A4F7C92142F4CA7E8E2C58C2FA2A7802A5CC58BBC67D0595EE5690C22C4288B0281AC08F50A2916C97A37BF3D943C53868F7FBD18E6DB5C3A081716B1246F5762A56B7222801AA1C0819F3277931943676B30D05C9389C49A8574275F3ABBE0AB4294C437B4C172481308925161AF95FE306EBB2CAAD7C47BED878593FB538E5175533D3ABF1A07EE507F26939B19F633792DCAADCD56A0E8C09D463DB01514230C4F36C361BB87977E96D6AC1F28B9F55E859173E2AB9B3500AB9DDAF0D78A411020ED772FD9AFC48FC574FE71C0C78CACEACEC5B0D02896B2F0FDD220FB1587442320E94A38BE420B6295EEAACB120ACC33BB739A4A7A28B69E24E7FD11A1FAD78B36667D0507BD3BF9A781CD6E971DAB496205D3F66C11E3E496D5310423D3EA022A7F7588DB15E56C316199D911286DFA382DB8F832D109A1A8389CF499E31269904274D407EBD0AF96B79DCBE5DF0E4B79FB0978F2180C02DAAAF8595A0AA1B2C85D9F992AD348BA674BE7991CBB6094F393F7F5312D853F026D67844C00FFF9AA24BDE9B95A2D8E84CC0C53B4DCD1F1BEA46B8D758D94B52A6BDCF5474CD36F76DC81B7CB14F52A813183660173F195FB151FD1BF6E856B252D0A148CA947CD210833386095334ECAACDBB2CD1765AEC21924D30DD41A676387FC5E8C05A4A3B2E2C113E001953A36D7E7687E75525FA44F63DDC1A4624F06D8D6BE35CBB3BC28B1A7FE7FB382289D1916928BB7819CBEC4074331CE6AD37CA1C7074833071B36E52F0476501071389DABD582B20035D868A9989305D30C0062F0A5C4E78B219CC1CAF04E912A2A90BA4536808EA56B67B9C75DFC48513F25BABAE201F331B4CA2DD2EEB503C4EDAED141EC7099772609046F2022745530FFA37FC035D13538510A7EF753C1A40BA4BDB8EF78A4E0EF20D410B8B9B1459F8ADC664732EB3AE7E487303882C17C99F6A8112DF1D3BFD64FC82D0FC2505F69271447156B7E038463A6C3F39FD9BF936D9AC20B692763A9CE99F95640C5B14F1CF2FF7A89940A244B43515CBFF6EFF9A14CEB5B9C18D019970EBFF9767C4847BDAE74CFE3450080E90C94E37C3B0F0278BD20973FF22BB2DAD4EB0301E6E62DD51DD36AE61A4D5A7FEBA96BE108220CCFD947A815A19942A4636C7DC101190454AAAA0C4A8A343DC063BDEFB8EC75F4E425001A4B804A72FA23D229C48ACE14401794610E1F96CBD489A2EAF9801B91AFDF4D71F9B71907FFF95601C12F4A3690DC1E0BB203E2B62A93302C80979A6995B550295D1D9F26C47C773920FF8D584523404B96013408FACA3003AD2AAC3932A496D8215774E34D4E6A1965764C9D7425325A0AF47CE410289EC67A7A695A1957E4868159DA65E4DEEC71C02FD393098AE37F4892A6C5C85E2C8FFB5F071E75853841EF365EA729FF30A1FAB85821E47908536108565B1C7A3240539E9CBABC550CF6D17FFF69D4A67722743A0497FDC68293414DBFC58099DC9F43477D4E85E2EAEE4C2D36EC499B6D7EE798FEA739D8AE157C00B6B195F0E74EE04EF96E1C623628152F4319C7F370DA90DFAEF2ACD7BB26C31A9A90047EC719F45CFE13D425BE5D4307F4207E99AE8C5B7E1F3AE792D7F836975C2C4F29587002781556EFAC838668BBC393705B4ACACD51409E0F3AB551EB37A8BBA717090A7D34B4701A3A591A464BB39A80C5A5F76825206990681A06051A9E693402BDBF276F2042A252954A4D2A79DE1C1FBA9E7C117A3435F1228DCD0F005BEAF322BCE079729BA700BD52057AE0ADC22BCE957970A7FF76FF7D5B6F1F469C58E9DA16E3A75FD308B9A7C16868A0230D187D554EA28DBFA8C0A9005D1ABE79073CB454DEF3C377DD354ABA14CDAE3CEFA68BA4AC925AFAA429643899BE95C14CB093BD0CEB54AF1515DF9C06577E376781FD978156F878F3779DB646F564B48DF7F1B13FEB5B2B530F730C93CB7488421A2810B0D897990FC69DCFC2DB7D9DFAD26BB4936C87D1EB73E4D8FEB0EE0D6ACA796FF8B39B2468E1670A1EE2BEA2D54A0F6AE9876F8ABEBE83080F96FCB832A18AC016E9C2A03E1427D0C8C6DA860850F73F83C4E0690C4CF44447B444221AA28E2C3AC62B32E7F8AB90649C0151B26DD95DE9BDB6899A41A174D80C1F9EA98941AC6FDBB74735BF6B179D0E18862EE69BBA49642D92A4C1CF9721CE90E68EBC264DEA981A437AF4674EF98F412C06DFAD2A7C1600E63E18D1B71F36F94DFFF183E1499206DF224A307F1BFA086EEF345736513524E697BB541B5DFA8B612FBC288DAE261AF60AFEBE5D0DBC796BF58ECCE24FF3FBE5D82CED88358B56B8377E55487D08E88323F2950DEF2E6A69EF79D01EA78C3A2A86AFF4A4223D6CB8474ABD72FFCB939C370345640251A8117446735CC5483B475E37505F29DD87E967AD930FF079850F31BD621276A9458098ED46A574B79C6BC0B5A16268EF6CA818BB7E675D59EFD650C3E84E4EAE9E74E89F69E78A27B3229458DB9CB2F88DD56A5CE5E82D1E7A2BC6FBAEC8BF1A5974EC5EA40E05714F8DC963140A3B351AEFEC2BA625A76362A64D71C8B98B7F4578A1882F79DFA1DEDC1597547E67C812576EEC06B02496EE2446E95FEB9A24BBA8E268D4F5F2379948345E4C25332B95207B117FA122B481823D944FF9FF07BFD63C834AD5F88C33570BC82461153FE28C11E217572B56B7B9DE6FF15E0ECD1DAF8C7AACBACA4917B2177CA7B29944E179B9F0E167FBBECAD2E53E7DECC50993273F6C53C20B189A89C613A7E56BBA702F1D0E3D360E6B73502A89D0F9CCDC31EE84611ACE80766B0EB51E18EC47701FE708852EFC5765C4CCE8A8FB5BFEB4673DFBA3EAD7F97A45F2DB3BEAA4707A7FEAF74E8BE731E31FA97B6D9C5B7C49A353B080CD3F5BFA617C68FD7DBDC685D4C5FDC00B9F470BB3A0C90AC0708A20E81906B9BC27C66DE89F24D47CBDD1D6E825B9F10B25ADE714B25A887D31658584BA761F7AE645806A4E2DD7FBAC098F3E5FCE5A5A01D0C51F42F906139CDAA87A66C2A082B0ABB3EF3CEEB64344DC835F87CC1694F570BA990E9FAAAE7449954910067C74EEC0178352956F1F3F7D622164BF92C46CF54A7DD3F9D74BE6E3BDA9E3E2874EA1AFD01A4C16BAAE7A656695FE652542D8EA4BE916D61111FDDD36AFD2939B1B03BC7DA7423FDB6BC8DC5492285D4CCCFC36ED91ED19873407370567EF857516014A4F9699E8263FBFFD128A703F6B2C742A8543DAB6650EB95A24CA3DF3B4ED9AA9509612ED7D7A761E10675AECD56483BA67740BC9AFB82307B573226ECDADF1E1C9ABA80BA16AA6E27E0B1E85ACA024394CAB365169DDF5D53F8BCEC9FF8CBC384A542A86D80A1D55E372329D8C4354DD4FA14F80CF98FCDE1EA01C6B0BD72D082BC8D31FA8A521C15BA11FBD6F94E0CAA540296AD5368002E5942E83266A9D21E1E151FE5A7E919B870FFB211A37ECB0A707E878B050F6E8BBBFEDB8D92E6190108CC2BF9E98B52E56698FF56E929D400AE53AE44A9A3A2A06C78EADFF35F6E49842619B4C129DFB39CED9A9EE6E7EFBA542A1B7822F0B042624BB8DB04201F0D48A22D8AECA8A61D402C494816335477A5B9F57C362E6E9A970D440CE3D18644C18F060F137B7A8A3121F694B8F3306722082340C4C415E21E89829DE532C9701A3B7FE99D8463A24BAC56679872DF8C198A6294DC8C5A4CBC7E81642ACA64AE65DBD9DBFA708585262B3400C631DD51EE4DF800800253757A1D3E156002F1B4F83BE72B3D83628FE94A9781714675F7DBC83763ECE7E4170C6E5ED06A2E4E7727DFFDFC8CE49DB56BD9BE5AD208304AA0DBF4C5299DAC686AFA3A88867831A508E1F34C9C4FFF0DAA723A8EC492DE73619F994F55AB6DB4972C853ADF9F60919E887F0E123BB11FF062FF0571B82804726298FDCB3460FFE99E37BAB7A18EB1D918EAE7E38C7B3FE3A44518AB6719940E486D9DF989E8B33F9D7011C766A87EF4432F5E18C6DA9763DF113EF2A388034EE6223F85B6DF0EC5E20DB5AE3F0276DC19F833301BC9267E790E3008D998EE416BD4716F647E999CC9D6007E725ECE62E54D3E8F964B980011278A38458129E08B7EC850310B2CA07F7F13F86841A57B7EFC125C53D70C568111B09589A671B260A6AB715E742CF79EF057FD2416774E259A297D654ABB4B7438083CAEEC1C5300154A8906CB0092A00E42A1213682C23289CA7078A13F943AC8E530B2007D3A0F2E05920D69D6988457BD47DF7B9AF49A6E1CBF9695FF1688649F754DC54C9A694BA10EB6D4D64ADA85B44E70D671BBA94FFDD2B99BB0EFF3ADC518878801CA0F4F2C60273F8ECB4AB4714AD34DBBAF29F95A9FC5964688C8571ADE0F42B69CC2982AED6D107C10322D016BC207D775149BADADC80819F133CE17FB144E205AB0E04FFF0A1A0FAE021D4AB8DBCEA301854F84123EE75DAE2227E7A74CCE9AA76315E5BF8346A2FBE24F2D9083663FC1A007462107690F4BCB924DBC53F219D807B6413F6F85E8C79FCE34636F31763F208C23E07DF8CBB64A9E0EFD0846047A759644E43E3A56CCAE4482E3E377E7F25C56C88A5A5A7064D4ABBB0C5D6B8A77BE4F6D9ECCFCA74C2F120A14A7F5FA2224B200065145201286C4AB02E848C2E6C9D8A06A9BFA5723F13AE23F6D71015DF233B1FE1243B9C0D02A8967AEB5BAD54CA440A14E8494A099DB506016808C03A4500C69012B9EE0EB65263268E8D22DDD9EEB21C3B7EC7229FC84540B314187AF593367D89BE9897BD51D8025267BB2CBA5835477AAF408E26A5C5A2DADC1E13BF68EFEAE54DDA3BA0500A4D3CC67BCBA9C3EFBD43615BBCCF8B8DAE7DDB4EE21F051F42DDC10DECD7643D65D0FD227BAF682E5F6D37FDEF14137A27EFC75F88E2C98A5B9E1921F196EBCDFE6DB05BE1898EAF1D9EFC4B6D04A1309350ADDA222477C3A97A37B42421FCAE800DB9EFBFFA7F343CF3440382AF6BD8268928516DE0F6317F47FC84BFEB54BDABC9B079A557D0E2A3108FAAF7AE0242BA02B58B8E44E90D8E5205E7899B8BA2962382B749C86265968B5C876F78CFF8E30D6A31D5C44DF2B65C55C8E147D1E7F398C370280809DAD57624483B61200BD894DDFF010279F7245AB7ABE500B073E8820193338152A2919A8AEDB15D3E816B1F1EAF76F5D1FED059A102DD4AC390587B1ECFAD1FAD8C157EECA11994A2BA5FE6CB21A9F93770230F0080103E901DB10010D706076A942D0FF5BAA0FA7D4FD3B4CCCD8292BC6CEEA2E081718E31E36D768753F3551F07FDCE8C143418B2BFF15CA4E7ABFB53267B2AE518CCB12DA1A8C52018AFCC7DA1FDF65B582F04CCB48CE94E1B211205F4A4F478D4862884DF379E8991206FBF204C8579E8DF1B55716700BDBC6C4DFFACE33389C2AC9B360A8DB084DCC1F44700C789BED2729731614ACDEBD243DD3484D5DA0870171326978DE7D64A82B5787BC1E96EB094F28298773C74F191FBEC6704C685744EDDAF35348B8D346D374DB76B83DF244163431DD290E93DF6B02C1D88BA839B6AF095CA795ECFE35B18F1BF552B64AD7DA6258C4EA1B6E289F2763EFD8C1ED214CDE52755F78FCDC48F12AADF60BB11ECA463D4410D88613E88559CF85C85C08F91D991A7FB16C3B4B4C8B1A04986862D1141F64FCCBA0B42B1F769C553D29BA7A495EC6A48AFDC0E074AD26CF23F28D4C33CC0BBF900F4A81687F09E8EBE2C38BF096F8CD0CF9BCA80CD8F3790CF9A57A654F860A45DBCC77A37F9400940D593A1A13B5F6135D4516E1F6FC4CE5A9B72750803809DB3E0E13B92B5E549C36EC3CB973BB3E9726675E0B6C186B7FD886F22B7E798244B76DD3B692687055A3DA2EE7200F9C2A835B1C41DB847FBFA66EEC247B4DE8AAC5E2FF742F05A923AC94F8B6596A6283824CD2AC1CD06AB7A0A5E1D3C16BDC996F50BC8E25D850F4DF30629965394F9ECD270FC22EB0CF1910681E0AC49D87933B0B67837FA48EFF473245BACDD3AB48B8AFD0F4438EEFCB7491C94758BACCDD21B8F172DF36B7B834DF964F61A21A395E492A442234D9499748D199B17AC8876F70674E68300A7FA6692011FDD14C220262050583B35FEE5737275461B8EBDF63084C8590D255A8341C031EE130FD833547C5A4D9350A6EE1CEE9953599D3F1C934A213673585DB408DF08677B5FC74541551B76A3058B6AA542158B81A7FF7CA17469D36DABFE2213425DDEFC67E6AA46610E669E16EE038E59EDE00E0601836E0818E75D783BA0A555D393C8DA1D7C8E375696F8C129FFF742F857FB43422050933019E53E72E87533E3C9C3A0140CF2CB5B2150CC6E6C96848597CCCF71E5F7E45F77E401513AF31FB851ECE75D4460E171107AF781A5774EC2A7ECCCF4EA17B89E3808E52F0BB131AB36890C973F857B989CA54C705F2D47B4C2E0985A695D19F842B62B71D845969092BE8EF96C042AF17FBC57544A47C34353971E4B8AB3D084F1E01486B57873A3281801DB6BB04C2AF8100E2AF84A31E72EA4F0082F40D4CC8D371A9071489004946E4D0A790C248A727458A561A2101C542F9943FF885D06C1995CA00B3CB750824C498E6779702A4C7173851976765299256864610354A817DB3B5A231065F28C90B9BEDE1C86508D6B7D64791D8FB53D8E124E17B24439093C847658366E0F9087A31DD640E04BD1BBF662768DB7FDB98C568154F4F20A87110B5200EF836944B298FD0F6FDDFA347F45888750002E466C5298E668B8DF04B90B87D265A0F8E6EF4DA9EBC6F75AF5C43CBA27086DF813C78EEA0C6695B8E73438E956117DE0A41A45974144AFE9CD666C9407EAB022220339444090CF9D79EABEC599E48F72B25D4AC7FCE014EE78E0F95A25CAF77D311EE6A84C17383F48DDB94AA16042BFCE547AA011BAF14169DDDE9F7C5067C7F3486F0AA72A8DB622195822FB2E45EAB7CE08BB91B6EB9338B4FE8CC91B7F110F11A161DF94D87857977094503376ED5B0B7B7ACAF7A9FA28EEEE4C358917B8F390592135BD5411A6545DCE8528490A19E9C483D25BEC2F2039697B9E85CED1D1FF297A66DDE80D0FF127279DDB03D0CF4F91972236CE9971289C11E06FE121F70F861ED668368824B6C9C5198FE3672580882E142AFB72786FC0CDAA17F38CC092DDD8AA96A63474D15BA4F505B4FE9D98C0015BB572E1ADDB2284700022D40FE03DFF97FB1BCC01B57979571E262B6C3F48F2BB638D635ADCE6024BFC4F9A3B0B1CF42E5D8F3DA92E5AB93D55A97DD75A22AC945B50BE01C22EB28F44D2BFE70EC381B99136C4DF3ED03A329C1FA58F434A7F2A2BAC5F79D6FF12842BCD8B766C73C90111DFE07A3AFA2DB4B6D4CF95C709A8CD78441BDE2B39F55D6011893F3FDE4B8B156D465EDDE6A74C03C4472A19AE012CBFFC2143E53CF4E5B0131AD0697FD80047029014DF17F41A36ED79B6EF3A8035E377978AD4D21880459EA3F5981EC814EF1DAADCB9139B9D9A484901EAF1DA5142F3E48E1FF01FE9DB0676B528C00751D0436F6FF11C0D62752A00D0D8436F63BA207CDA982B0BCAF5FA67490867A330332EFB37782C88228238716B8C54C8BF487D198BBC1AC34F49E5AE47B6A0B1FA25B9D581FA432946AB79DD3C34E39B022079AFB221DF16842C590055609896F49B3BF1ECC147A76593B42F65C0B21A919621D6105124B0D435898B386A4D9D3DC0D412F1EB626D2784B220101A67E4052A9E2E030E24BD9EF577684A1EF92E9AC0DFC59CE732FEBDBD72872E1B7F8138ED10A1A22F7B66A481F13124E50D9ABFFFB4F64673E7C0F57BD9AD012AC453C6C619F37D972110EE16109641EF8A43401D919CC203BF22A86FBAD30000122380CA0A0038E1500A44359ACD02B3F07631BB0BDB2330EB8CB3F285C316411020D05BD337720B9709C8D8523E4E7F7DBDE38741BAFA53DCE9EDB4BFF81A989366A152308A6E12373C342B8D9E5947CF65254393EC9A74705C33AE12E1FFD25C797404F50E6EF16AA6346E334EB5F43F7BB6B06CAC5F0ECCD2D4DB55C324B281A07DC02990C6229D1BCFC74C36B19305437373B0F8C4E1F2AA11F967DCDBE75CD1A264779F6B838FC7F0FCFDCFEBC5081AF060D152486EC365361C5DC145350F179B0DA9E103746E825B10C8A7406A83AC3021337FC72ED4D5626C72E640C7DE7B57B87D7018F6B6AE5A8C6B03128B75986A012CBBB2C43D48D2951C357BF72E3B25B458E18F015E83CFE8BFDA5D202BB68AA68004F94C796B0D6B569A275EE94C2F349362AD095B17AB2E6ADE3443B1540D17F901BB3B5E9153E584D763821E510FF3A5F61C724CEF5260A440BEE7DD042D98EC03B2D76190FDAFA13A7DDD5F51385267986D27C6CEA1D55D7F73F740D0FDF80ECFA913F76324201206AA656F5BBAC556FEB3F8FCD01C7B411187749F1A484EBA4911C01EC8732391715F7D50A67A6F85469A6D15CC7985B408C2ACB08761B54091DD5C2011D8A7A1CF227CD834258AA37FE8062E4513B678CDDE30611872173189D7D272170871374A83C1B56814EF2058CC65305F6668A4C9231EAEFDBCAB6516F9839D4D4C97839CD011F02C07372F700A348B101E3AF071E53D10089E4111DE01B1F3A03893E94A973FA13D231D59A9B5402AAA080370F9EFAF2CEC344239C479CFD819C4643EC8ACE28AE77B3ACE2194A8CE54C0B4FD42CEF9B32635CD3F39F2AD05A02031A387D1A1E0A56AD056BEBD78AC9ABC311CFEA2544F32AAF8C1C4107699D6DD35B908C4DF39BA98A0EC59203D27C7C2CF7BC6CD648FCC7A3022A78438023C8636B7FA0844C1F69A45082B887DCAE94C7FED064E130212B0013FAC7E8F4CC3C852DB978D60783F2C20408D4D30746A2D99CF0DCA44E68E26181B75658DE88303B5AD1F6F623B860A2ED783FE650FF82F6FC2972DFEC49FB276729DA21516559A0331FA604E9E38CC7748BA35A8914CEFE94BB9BC598AB102DEF5CEC062C2C7B0B0A8478B3798D4490BFE286B2EF5734B67CFFA2810E4AA8C58A203E2872A5D254968AFCE670CCAA2F3636BE14851D05A7C334C2C31E209B17B38A45CEE320F21C4B2E74AC9CB39430A11B365B53A023A66C7D6E9C19518E9429EF375B1D0E55F1B47F00E903C99FEBC849E6782D540B7E0BCBC30108143AACE9A8A38627CD0A0F34C20BD7249E87F3F69B7AF55CBEE2E70D4CD20D02BF41641D7F6A5EA13D45B70CEE9093436FF25B078BF2EE40A4AA589AD7FA46337142C9C43A1F75F0305685B78E1DD0B1511A9E6791AA5A4D3D6B121C269E397FECE1BD197086D11E561726FF74CA9105F84A5A86D528E726A030F6818426D55858589EDC84881D44592E4491BF4ED3F3205DE2FFBE1F98EFA614073306C626B9B42DA9D21837D242D48E265E589E606542C696AF9A9358334604A44866558C8F0648FE1E1DCA6A9E3BA420CD3CD3F02627EC4077F07C1831693C4229A4BC48DD2B9E72416BFF82783FE430330843F3B29775F720A20B2536688D19DBD43ACAC409ECDAE51BBCE82C209E6FC7FF865F4AD13F86E475CF0A8730915490624D95F644D687EE397467A5A407CBCCD7B0CAB0EC3737DBAAAC45958A9F9688B5DC93F5464293B8A9224B90623322D3EC60268A4FC86D06E58A54077516AAE71F223184914FA0B11096A187D8D642CC219A7C184D63C70685C80766B453DE69A1303D44795B3A75ACFFF1A53D63B5CAE68506F15884C1B1D70BCB3FF3F35055136A865F240BFA5CD9595AB783FC98C348F1849FA0E8255945EBE7D5592A2649622851D5614266903D7DB3AA408D068F3D9C07084023D6DD7AC6E525F4D53C0F383189238BFB2768AB9CE31950CB19FD0D36112F001ABFD1BE260A8E800A5E037D292D3D743496B81178F873A11ADA4C52635B02C00F728C93A67504F0E1D8F0CA9FCC5BF736E7FF7D6234C900314726A31C6D9D4EE67DBD13F44E430FEB4D5A5BF5B2A63E992D69AAC5A6F1940EF02F71529F4CAB1E8FD847EE0561D1C88EB9C777D11F05CF9FCD1114B610C63EF61762876CF514F27FA9FFAC99B31B3792FBD0F8A2FC457D0E14132049E205C8970A245C11B38C897D8C746F9C1379318F7A124404A355F44A29620F7E9209E084C45316146EC13DDC47BC2951024E24308F1DE2F7FA9FD2F5AA1FD23CAEBD47F3CD583D4DF2333004A4338E99AE95F7FFB544F397F99BA18B2E9F7F5891BEF883CA1F5548C477566574407223626F5A0146DFC5F706AA2F4A5DF008ACD317FAF0A291162EA76FA5C054CAB3CA249A6F078681DB6EFC5A74313BCCF5C5127B3A54B2CC030587633E23BC08497FBD660D75C7EEAC423A2BE61ADE9465CD56FD32FBAE82392DDF3E788562ED6BFF3D04DF217FB5D5E20B17A8B22233A01148051E8C60F4724D4BA2EF9FFB9CAB14D50793BB8FAA2A16617C80FA6A1442DB0E4E0C7871ED097E5B37C117836A14C763E09B364DE142939962619CDE468FBB1E789A213191841D1BBE59FC8C77F8C2E4ABE5BD8B287A0D68AF1A155E3FD115FE553E35809EDBA294BDDBE9B41B6BEB5A328E925522E8EBEA7B476150877AE1ECB6632266D494BAB6412A1F9C1B66D678B43829BBCA5A8DA5729A380DC49D1F2CCCE7FD71BFFF789F57A960900AA0BDB22C0625B3CCF50D66E8F271A35821751EAFB7A52FC00219474E7DCF569ACCC3C1AAC6BD95612269FDEA08D7B1E455597430F4BCF3084C2E20A624A8FBF57EC2624664D1BB50689300292089AB0A027012A3F69DF181A02C5940BD61B36EB516E40164F7252EAA121331EAFEEE01765EDFD3D50887DB32DD5C8FEBA501CBCDAD340E37ACE717A5C42F01FE8AA40088130EA197321611287CF7248269DD84F7EB63802306D20C24F253F7AA999ED1F971EB8FE37849BA13780A30C50074B35CAD6B2CE8FDBED7BD75DF23648C916E1C25AEDA34EC048FB21FFF518C2A3B98A07771B8F263E8F22CE7042DD7F3F08C4AE3BD78F8E45BED7B82631256A73182E7C83FF1EEE8110882FE3EBA988766ED4ECC6CC9D45C6B2ABD33A799C24967368315F96B1A0719E13F252557D6361938021646E17F5354CB13F4A17E36267B8F058D95C615650975F2AFBA9BEA6F73C7341542244803C613D15D04339FE9F3041E88E726EB9CFEF33D2E3D0A3C3E86AE83B3F89CFAB3076DFD0B9D7E774C4E6994A3DEBA9B47B4A6957311B28E723E183E620978FAFE19B3E107C1CD8B963B0C79F92B64FC8953F77BAB7E649FB457BDB2E120342622D4A6128AADF164741840C3FCBFFF78942040807D71D2558D3F7F404FFC14C2A842D1B56316EE03977B0020EEAA83E0117BEA553EC328FDD408C167384A94779BEAB585A14F5D0ABB2165C1B926329F3B7D8B43FF3F6A98DF3CADDE04AEB98A37CE44B83CD4D37E3969638F0A419946C4EA8F073EF408F76B632D1E40BAAD87C8EBE0319B791D881955D28540FB7E88BEF73281617DB20D71F532E2CD3713B1E7C46B94DB267BA324806550AB50552BE6D0514B7C6741AAB115B62257192C456A2F67E5D2D21A0FDBBFF1694D1D2496AE0F383788A544D71F71B03008750A4B42F38D7C41E0029441A0D697984AD62CB54B58623B60AD735657B5BFBB1F2DACB4D95D3FDC993FE47B95F1AC4002906EA7B25C5C8156C11F7934A7D43FE3CADCD504FB9B38C063ABAFF0B6AA4B7B3455505D3A6936ADB5770EE8F88FEE65A73484A2E39E766C2BB28069DE3A32631B5CAF01DA27FBFC33BD18197CF11F6343161B54AAB7F360E7DA189679804C5DB1C40BF14AA800C8DE50EAD3D6653B5D4A73FDDCD0FCDF7D8F0B2A87489B7A48F7FA00E595691BBC87AEC82D2A1D6EAB31A5D43222DC17BD2C887FA8770E48F77F264214101E762F78637CFE4C69DBC54C43BB2FF9F9EA16F2BEE5F4234E68D4BF42C3C0C72A85A6AF8CB7BDB71440261F3BFFE96D3169EC054F22E1F3A91F96FF08FFB926AEB98600FE11FD9041AC441EE25D0E25AFE4C40D93E490873C9C256038A9DCE4263954A33FA20F4C503DD655779008D20B79A30A7109C14FF394F234C296048BBEEC4E096BD34A52008FA06C8367B1122EE820730C58B4220B11238982419F25B7365E786023BE74FFCCE87D8940916D4A0FA4B69181BBEA7C5A177CE6598199ACA21D52435A496D4817A41C4CF099124E904860B2896C1B151305ADBCA9E92A1C6C0B065D6F664F1ABC0C9124EE0E182001384BE77265A1A3ABEE5890E1D092745918D20D5482D925FCC98C811889CA13EEF62AEADF671FF352572DF64911B38463F5270D353D6EAD4C0C0E0DE036496D9D3417296FAD755D772F0F1753534BEFEC12F2DC7DDC9D8CCEAEAABB225E86C73FE7571054636D74003E5F16C2768E26C99C23843E7BB7CAE77F19C695F1FEBA26C2D4C436F4841C8106098C04D0C500DE9CB4431548072C1DF58A8F03787AB23B0F8665564D61FAFBAB258E9BE72765AC19B8A6DB52FA8F5EF0B8971A0B759B7BF63FF0EB7B3E364F739352AC42C751017369D2B8C80DA4E4E19A46560EF423C0C1057C140A28FB4DDEB09E3A6F42F470FECE6C02732ADD119C47D0609322E5D4E36F424B77DAC227D1A88DC724365691C973637E1840A480D75CDE8BDF4CBE8C6ACD03B52AD9749FA5F2B662958A394610F3C5A1A09AAFCCEB825C0B203BDC47AECBF78C659E7114C7FA7A1D59BAB08A3889ED804DC9D3087B965F194D8EDF3818974EF0AE200B18C9878B12A006036475028D800EEF1C1D7CFCD87D5290BB5BD76D1FF869FB20848D70D3CA19B92345700C5EA4C789801305BB9BDAEFFD3BE02F0C839DB73100478C842F1DC50AA194D1238765D839A9C147577F3970C731D38D48E1077B305660A245EE19A18C2DCA9CE1E78FA0386B3CAA8006A153B2609E9716BA465801357BE130206E2DBFA10D961EA0E3985BB6F939A82180764EC7E401CA3C6954DE7BC6D34BF7B6D8DAFC5B709AED50C0C5029F19EA9E3D1AD2B7EA5A31642CE82CE89589CE063F1D25B4E3BEB4E65E2ABBB0B241B1FFC15FCED02679B9B3E5DEC7D218D72538B3AFAB9A0FA7C9308926F0F1D7E43DA462982F537A0EF79AA332CBA38B8BD5310514CC1310E95C33ADC23369A48B7FD3A38448F6EE537B197A01BDA7BFC5E88F52849BC9684EC2542FE93AA8F70B28FC2D85A5785D5CE0E635A59D836F6EC7A42AFC6AA2E853C865860083001D5A74793F87FD13B0BDD8683A3680AC3E741FF92DE3B7C60396F353DB8423748105252A588FB7938C0EACABA0972386836DD52F9CC05C780F0BE9647793690E5344D8B01B5DE5F42C0B8A4C2B8D1D72AC4F12812367B9926C1CE9D88E0113AC6CCD5555E9819DD5AB4B14E6B16FD277DBBA9702EAA619A1EB8D4E71DBB6522470BD96F462C7FEC42A6BA2D0E2BBCD389383E733E5461022C7C11100EEB3B708A3DEB56AA4F123B710E0BEFFB9BFEB19F88DD4A7C7028B74DCC49A87774320FDF4248EF65607FBFDF40A9A1C0ACB7B8B6DC23B37CD8D58C97B23C7DFD8C067C2AAD4512FA2F5810E93DDB3D1CFCEAB1D599B75569757139CB1A6193612D0CB18DF4BECFB05F478B1FC50926B4C82A3221F841E633D918E03A2D8FA34E511862F88B5EF787828AF7E3B922DF3AF32BF7C3E2EB2AB6E67B4F68804CAD396F3E1E021E25D2B4F628089EC8C43E41E0AB0655CC1E8E6AEA5C7531F1D25870763817AA02E76C7E008D10E90587D9E4182D8224A5573FDD8FE8E11382C16F111315446DA1DA36450C11D88545050D06EBCD1C6CB636A16A091A7990A402A302E3B5A93D90F42A18DEB9BE9BA3B79F95078CF617CD3E334D1691B8350AA4AC4F1CFCFACF2D4CE4D7040AF54CF3FCD9DC84A63E345DC260F48CC99F8EB78FEFB0ECCF041A57DB84A94A7069B3BC122D418186DEF3C35AE96E363BE8F11F3CBF55FE792AB2EC17475B1AB07EBAE1E8FC9408199F14C5A3BDEE902CFEC14862106AA5F1AF200C71FEA109ECFF95FF95D2FC42B02F05F4673027B768D19B7C157FA6D74B196E6ED9D4605C2C09045938F706479CCFE7D41CEED3EC4F61730BDB467A772FD17A2EF8358D658CCE84D0A378CB4C52E824E11ADD4558CD3C9E95BE18EEAAC1D74FD8D401FA8878B5393D7FD3A5946FFD6068693D0A0245956B9E21FA19A21854664AD34A9DA6E57D6C971678FEDB909298EB67B3031B7E1DF0A3FE56823D4636F7BD387A66003FEC8AAA741FBD927FDA58F4E3C586EDC09996792F534029C638266F3515C0F68DBA61F6E4F650EE90AF61D7F2D04FD952BDFF172A31ED17048D360AF2EE8F5A70DB4C58B69592AF1839DC7ADD43E3395D57DDB9D78A692D3D95AFBDD224F0F2C69FE477C96DFABBD56CF2C6B3EB8021E28BDCF884B727EC9E871B3A85543376139DF15268A6531EF7F1231FF9F1CA35F22AA9C834553A031154FCCA3DF86639FE7D8AB5F8CD6CABBC33595891993CC9CAE8A999973089752A16E49BA1F7A8F5E11829BABBD597559DE9D2974B1D62C77F3E350A7EEF47BF9A53DFC4F95DE747615445CFBF197D1DBB0B8A9F95069E645F6FA12BE137A793A4C8AADA32DF23BD18FB23E9B38C4E24CB5327F3DA19F1E50F19652E329EDF038A1A0DA571247AC8EFD81E7ED0EEFFF395EB874BDDAE2F07F2C5181F290DB7F28BCBEB8BF631FAAEBEB6040FB347A3A4F3CC1F54A32657A7CECCDBA3FA88DEA9114E27058660951A1C3065CCE2751D9B3BBE731BC8D935A0C9585BA7D5D5EF6CCF15499E8FC57622BD1A4D1107E965BECBFF5CD46FE6B47F4A9B30224660A252E1FAA382E4F5D3B8532BAE3C13555266A607792A6F366DAC1B191AB771A8A72C7B6A6E33ACF856D1C10E1366F95A6D466000BD6AF492706DD042FF0B439167A81BADD0CFD1621AA23260625EA59CC917EDE0519DBC5700E2596A76B33B40AD82A49A5A19BC31AC2583F320588520A5EE5EDB04C7CC20613794F94B5DCE45CEF1400FFDE5D514DA0F5332ACC25355D6A8FA4A8A6E2CA0FBF1171EB2D09137AD816DB8D46B49015FC7C8CDD337D3F37C130F5CBBB96A4C6AD4A4CD2F7C3ABEA6825012B9A5FCCF7B88EAC65B938C2775CCB325ABC529855700539AFF6142FFAC80592F086D61A2BEA3B08E99DE4BA9D45226F5F7E884B9F2B380C041AF0E40C6104CCFDDB3C48FFA5F235AC4AD8E5985E247E0C9E9DEBFC630CCCFFD64277B0186BE62D7B68846AA6CE1BB5B9BD950B9E72C6A290A19737D3510EB3CB99C50375093DD1BA09B1F9FBDAFBF6A08F29AD1DABD7BFF5066A3539D5043E2F5847A90A16D05556403919D023F62714366CF0E75DFFC9E35FF9FB98DEE72624FE31DB414609298B51FAC7FAA4DE5573906E658E931B5AD1CFECF53357E9987059EF0A775BEABE7DB51ABCBECB1C625CAC26304A589B430458D9057C08E3C6234E494F47D68C5AE750B9E765B237591649DC07DCBE70F718F48801BC4D00FB2CDB8C4C8FB540C4B9A8CD58650F8DB9ED2411F4DE9765D5C977DB8FFFFE7ADC3E2465C4FD172BA31AD7D16DB6CA7334674D7E7108F48E0F310FABDCCDAF75C8F18E55FA1F65031AF2A2E1C332DFD404DDFA58D4A07CD03A60A821A7FBC713C1C482CE4E510F16996DC45ACC740925A9AA30C523887CE516357138E8637826E188622CD73FEBCEBAFAF2FDFDA1BF1193091D4A9276D112F3B16E6B1A12C07C7B2DE527CBD64808A12A67A251CB4B2FC836E4027F31331D4DB2455CC3BC6B90E8D6C76A31FE9EF8E6CD81DF5F60F4DDE6630246EB84A6577231F64E366108C69EB0DD3969F68552610E72C0A8B17DE0DF877C41030D37BA45139F657FCFF486B5A1EF28B563862C9D6FB9465C1C90A48FE085FDB599469DE6C73EBDF7EB79CC9F51F3C2E49E816E55555B7EAE7A287A21CBDA3270D5B2277DCA4720B70B5B70DE5D76DAD281F3C53376A086D1FFE9E5B99D68674BC35B35A8BD7EDA3478122F4D78883D4203D0BB5749F0E24D2453FDED7693D2559A45682D0C7403CFF9988562D72CE10BE2258744A1378F977AD1ADA12A29B3723EF3E97DD16B077F778EDD0DCF82B3F8DDAE18A06D2EB45C6495F9E7435732708BCBAD0A29F4DDA81672861D27BB91368CD3E0C1FB9DFD5F7ADB878D159F98D43DBBC63448C1537FE431BDC94495D953326B2137F9C1E372FB60578D8371E43B15D14319EFCC6CB1A001D2E0931AA1D8F0C896908C108749D01F5BEF871E7DA11A2C239E66F4005955F6A75788E9DA493A226AB845B6E399EE0F9E53112512E6626DFC25F67392B6E535C78DB6136582C5BA634BCCB459DAD712526C20B3F4EF0B5D2265EEAC9BC01A2713C71FEE7BF3DF90CDC81A60714603391DBAFE40AED664DAC9EA4C120A0C4DBB698B650BD9899EDD5B6AA9E7D624B79DF09D59BE1BE960C62E1FED73737105130A4FF2B89EE63F61D21EBC5D1E4FA9525E4BF5B9C7F26B46270A101ED8761478E3AC7E16D16C946818327B1EC3917ECBB745CE9E5B879A0E9D53FF92B4381468059BDF27E0E45D3CBD250B40E2199FF13D02526A069667E3E96491367BE89C861149425FFC477060E14CB0FE058182E66EA8C8C7999538F251399723B687242F7E18B563678E82759DFB64CBEF58D7484B46D15D26C86CB8826F447EB07D169025ACAD10963D4CBCC916837A80416F4B5E90F7E2559D161DAC9397BD44BB0934D56E72F2287638FF5F108A1CCE7F8A2B5134429448AA4712A0DE440C8E78DD5AD477084FFD63C6C3AFD9E4FF981213D39C823C08150E0F93FAF7382D5ACCA3D69550615E78827BB2676E8CF7C08640EBA865BD97B8FA8C702151B32DCB07599323CFAF34B60F89B5787F74570C9BD56F69DF82B87310CB81DD4C6A65F406259A1CDD8AE67460576F7ADA29E451F5D52F52F6DEA0B682EC510B717761D10646C73A8D06CD3CAE98B4B2874B37794ED0B11AA4D5760370524387F9A355162D5EA7A458C09E8B94F384210105EFCD842DFF69B7A90B80EE79A2F0DDDE54B3665C5BB362A8CFD4FE14A878139D0C8140120299E718281139E1506E96328C8CD48CD1F421E4CD3E3C60CD63BD612FFED3F6851608872BD7C7D238791D9CFAB0AFFA97EDBF690B6CF304C8E84C2FD96890700B03FFC86E4C3F5A26364C514F8B565A0700226EBF6CD4060B8CF3D847A522C182901D0AFF6EA86D0935272485F905CF80C45E9A6DDC9D1CA3EF8E76AAAD03EE1E2B7067A4255E2AAC03C0A2E2D6C7FDC97371CE14DC54021947F3A3B6DD4BFF6B33AA82F3F18F5E90C322D64B884148DD3490ACF12509B8F36C650EA95A98147C45A914C163E5665F8F60AC2CDC95F6B9AFF6666C9307FCA2C9538E0411DB391B9CA66C0089101DD7CAF8E82EB4B106959D41C12EFF8A0442D84415EC130B2EB837B92D221C3A9EC7F6A1585E4D0E2B8276B9689A9EAB26CAD4F6A815E4E613781998A959DC82DCFC3BD5FCD1627B3B631F021E9F6B6D30BB9D859A89D61DC03C4A10BD57004B11EA26931261AC0ADBC8FEF3F273BA268AC0040D0B3DC70EDD1473153B4D7AF50B3C162C938C4B043A47FEDE51F982E4E959A1A329399642839C672C4C910C32C5B32F93E55CAFCFD824059F04DDAB8A51C2678B882E67B13853E7CF0041175C45DBF75DADC8C8542FC890485EFAD40673C2EE7C584D5ABE1E687DBC03CE32B5E8954E0964B28EC948655C3CA86BFBE9A0ADC7DDEF6588A1A10482073A0FD0292A8DB9429C17A9BC387583145F588B223E716BA4E7C42D2D22FC5BF38875253BB5BA67CCCF11799FF9F196347A9D296499B5A3ADE6F3CE7A240510E98DF7CA807A38FFD077F2E9B1F698A2B203C312FACD51A18D6F8485C25027BC43BB71735DD2F358380F2C94EA1C15611DA81AF9B72442F602FE314D987A66A6A890CA374A2F1B8B8744886EEFB9E3824A6DBC308E04D993D6C53D21DE1DFA10103555951898079EE73D1F284D95F612A4355D0892320584FE0E97D799A86FA43A3A297E8542F780B570826A88C2D58019CB0CCA95FD40F0EF396B846C58606FAA985F950678F667F862211BCB1823C1E512DCCD5E91083EAD6EE9342D2C91B85CB271C84033DCEF936EE72F6FD31FFF1CC8300ED08042C914D202FBF6BC7414D38510EEE2D529031BBA8657827065473D2B8B776BA00EC13F78D09D6DB5009E1DACC8AAF06516E6CEB4B969A0D28E696B623AB84F00D411DB129D71494DFECC413CEE500DA1493FB0A34779950B3AF89AD3E832C5E658D31536FF3F8022636FAAC6C9AD64ADDF5C980D5481DC4FA6CB5A96C581AC3EF6076524512C6E6FC5699B2F6EEFB8C384DB96C48CDB0B84FF268CB3F24568B6B86FBAFD457C5DE0FA26F16EF53511F742AD47F1FCD849EDACC849404D8B57F81603FB526822DE266B34ACAD4B7C35C774D5D37ADB07928F21F8845028186511A5D20FA034B929AD342401FE72A5C9B96E6D938AD37E4129F9F50E674735C67B6BB44C5D5287BDC595CFAB6F73CC2F80C139815A31005A5172B9D775AA707E051532A46258BB2E0B79761D5EA91A64DACBA0E8200858FD301F1FA2BD786EA94101674006B64033F64057F666D1C57617D09DD1C02502560294FC678B341C9A39A820CF0A0074E6CF9270331DE7B145F4F2499F32CB60B440F60D3870EF691254C58929DF5DE2A97FB45682412E6737E89E160187B25DC868F8100A0C816118DEDA2137FB1E21C420101A9D8B8D71C99CEBEE062D69BFF439A3D6BDE2E7BF98D729A251E0368B0538D4C803AF7F5D131FEE07C43796763A57279663E82B5603ACEC1BACBD404593F10CEB5E715E93ED43304C4848931B9FB655D300AC48200795F8F4CF361D3BF9CD83F51859A87AC60F069AE36224982A8BE12E347CF826807D6FDEEB214EBEF4E8478DF1F54B573BEA4881D27920FFBDFED15F0A13D79A5F4411D16F70AC16CFD506FCCFA9699D1AB698CF60833F04EB8B9C3676B3E9295A86A87461A26259CF0B35F5BDAF4732BC46B9D8F98E73A2D5359B808854BF88C5B8C2EA59FFB37F6EC8984E1645151D89A9952312F41D1DFBDB307587BA86B7F78E1BAF6EB9E50D16AF83228012CBA4512F9BD2D2A433C5F2506D4F6C57F1DFC8DD195F118FD33CDEE378221A5D17B8D8DC0158D37F7DB34BA94C5926A8A21F64F92FD9263A3C87E3B94F7F640BF369F991B8971ED9BAEAB8038C717BD60FB3D242EA310D55192F97BA536ADD2585615AD92D96D43546A75FAEEF6DA0CE6B6B8938F8BDFDE0228C6AA91D9695F79BE188CA359A46F4FF3CED7FBEA976F80941FBA3C94ED6AD0BD75622F45CF8E479BA7BC03763F42082D62224FF41E494A352FC4FCCEA25E9F70A11D598388DAC7AC6C36CC850ACA000994C9FEA65BBDBA0DF2F1686944F7DF4F417044CD30CF6C93CA75BF1FF731591E3CB49D2D93CC1DAC9A18B97DD978C6DEA3F2247EAFCF3263B0D4A9FDF06FF6F63FCFB4E3083CA13CFBA3307312EDC564EB0B72B6A1E8059D90F145A2F2346D34814D6207B328923C694B217E56256E7B1BCB24730C08DC2942091B18D46FE4DF336322E0377C36FF7E1A3CB83B3D16F2F1D9CF19BBA08CDE8F7F8DD5E8A1E9E9E547105B3B7E702AF3CE825AF4FB744F8D4B60E11661C71D3B727BB0126D18EEAFF7DEC923DE1CD5142B726BF1BAB969D3A73536FBFD6F7A6A9680DA9091E8CB5A54126EB42B7CFE24E449B3988CAD925288196D326A8F3CCF000880EF02E43C96016E4D43BC1C070FB442DF977E02FB7A58E139A46E16ACB56E07F16561411FD0F152B8498C6A113BC10D7074561FB0CF4D46310FCFA7A5A860FCB2765DDAD98135F5F61401F9F54F2A73AB395E9756151CEE68F4117E902798E9AD5FE2061C0ECA6356B2F66E013D21084D58946FE16BE454E8B7AB62983E21A12367863A1D08E8B3C04CBD594E7743FA6928B7FDBB5633C65CC5B1FC5B47C415617BE0AF07BB7B4AA03CBBB0B1E26F02DA4DEA95633F0802C4B4914D28B4285EB6B4FF681A7221AECEFBEC4AA1CA0BAFEFAD3413128110070342BC09AC1732A4DE1DA3CDE9BAD8C5C3312D1BFDA361E35C393E1DB92C7473AAF6E2DF2890BD75DB24FE62B5C708DF2308CC5F6F0053EE77D9F00F3736A1033D84E6A7B85DEA05202B55B1AC049AD8C26E892C89C8F8B90A0302464745418382B0CC014DF7153394EA5FDAEDA9FFD86F3CE65E21806ABF5F2E8C3B33C2E365F5499FD0B245B193CD0D5E19E697A778EF35C56F9C8B735D911CF0F78323330F9FF864AEAD45F3FB6D68A17EE03923A08B54E83DF04E9E8F986AE40589AAEA59EA54872DC4EDB99C31B88565B171D67FEE582905FD883B76EBDB87EE0ED10FB8E8192E72794A65D91D8269D8F422AC7EAE954BB058F95B4A6AFD7251780FD8831AC4E129F0A2B0662F8907F1E55D2DF9647CFD2EA36DD473A25D7AEEEF7D5C0A2AACCF629B5D73DADCC1D6C127B340BEEB581CBD74D1651FB6ECA687244ADD5E53C8ECB100AA4C40ADF571C1A58D3522FAD0D05D50B7BFE91448BF508A2BF96592CE705886B8D69CF3108E80269C37080EB64A6433C9EC83E816ED2DBF82380EEECC15EAA9D505B00768DE12BD9E1CF237C193E58CF9FFF261A4947677BF6133C78ACF6090F5FABF5207E827C88DB60004C887E7800E49DD0ADEB670CBD8C8EC985F18922B9A188291EEC8DFF2785E9EC6ACF799143C5746312FE94FF81A0C109E159F5855D1EAD5FEF5BEFE379C151B62390084438000F1BB41C93D5862E10427DB0BC8E76AF858CD869C26F7A1FEA9D9276E9BB80BA017C083C15339EA519CC964E72E261C028FAEA7653D1993454787980C65C11353E259FBB5EB0CF53325EA0B7F9A53BBC0A877E0057A9D94465931C4B4AF8C6EBC54BE7C72AAB5EC636B93F5C38892E294CF13F8DEE840892E5A1B0A8CFFBBC54AB97AE66717F5900AFD672B5AD3F5F56DE6C954C6723D259CB2F411166916C12CEDCD29AA102F6FB5016D28164B0D77EADE413824423D938334A9C06E13471A286250E99AEA1909B308AC7DB646BA77B6185D191ED98FF58BF5EE4B69A6D0A85ACACDA3D45B492513F26B0BCC40F9E4B7E286B570D1FFEDA4B7464203580F7873CDCAA9A092E39A168F00518611478C70B52496727FCB516818EEED421BEF5F8EF4702034D935AD385DC13DABA2E456833DA8F5569914EA6F6DCC5498A4E9467FD416EE334D0C5460924246F64541AA0E7441EC0506227CF3163BC655A0469F94531D394A8818563C7818E7DF466577B1B4B64B2AA401905189B31819230757332AA9195BF0DD4D25A08F8314CB3995F3E76FE24FF324D681B15BE82E8B6482015C0C519A718895FA2253FD33C376A7803028E8B82926F81FA7A0507E86C9D662A10E0DBA113940F7FFBCC17C59D6F1236B90166625893144D30C8CD9D61B087B7183A399D799B3DA37E0F58739E5C35A83D58120A0BB34232D5502E3111DB585293D264BB79D2285EFFF74FDFD09327F6C086BB27320F6DBA4E5E4286A6DCD2E96278279F12B6A0DF196D02D05E7CB5CDD45D512713287E9D3D307EA4717A3F9541E94DA1CD3344DB2EE4A24A49E4A8CAB85E0E32583F8932B8CEF6289EAA3E0AEFD56C7EAF52F5D46DB31C4569023A5D42D78D332A90AD86B62BCFC6FD6BFCCE3098952AE85736D58CF12247E76C4F419281E9A50C8DF3E37F9C0A5BCD99647D9FB441C4945483700A8FAE7F02A06B02E872302C065497A1549956EA409A5EA49C95B1318F385FAA602589931C9B78C248FA0576E18E282A189168DF91752E000A61B19A1C02B480C2F5C5F6B6BBE4110EBC9AA53907F99E3D636CF9214F3C5773D7BA0D3876114B60FFF938166811D5F1A9CB1A9F1A64E80EBCD549FF1852829735516CB3F5FC8E39EDD673F17857410B2B0F31792BDE8B2D270DCFB3A1874089398353C8D96E03923077CC2B79413BD81F23A3B5F94A3775F994B719FDD1ADE942692FA4784B244FDA1B35D6409DF155F5DE0DE0048BE4B480760F5C40E30DE319B77ED9BBC4D26040E91C8161EFC02C370D4D3FB47FE38E86BAE3D590DFF014D891F58671AE4482219352AFB9738C082DD6D3C18A451814A35670C1DF4E8CF31A5AB29EC35E709B5D49904EEED87ABCFABF2F7495DF3628EADEF01BEC0DB49B1EEEADC9A6CB46CE272908D7B48E1D4DFC5179110D886EC6FBE4BC80BC5897CDD83FB37018E14184C6CF8E65ED2C18E14B56F00A90FD428739CA38AA93FE9D6051544FE2B4F92B8C2A76D0193B19DD82B4D9B86D57DD7D981961326F8A1BC8D7948390569738824BBE17D86CFB8458EDF674DBFFC3D6EC092E2ADF9ED4E246E67E6B6F83A78BF483DA62A78A9DA90E2169A7D2B63234542CCE417D6686BD461752A98E09D385E280D108D597527BFFC263D5227C93262C5063C522F4574A7A26FC1373B41594DF6BDAB8A0FF5B8C138014D7849437FF6FE9FF616A7541B1F6510A51E60A53129E33AC0B6A332631AA249553F24881207032F312E785C1A90093F9385AF40592AC95D55338745B527469AA328C2434838E2967D3DBA3D42A5A74AEB150B314039365E966D160FD89E786D03B0D3B9A7E615675F657213F209F3D7FE5BC4DB71AE057AC83F5E28A4C0867F9569C0C0793C50CBB2A5CCFACC1876F1D49D3F42C90FA3E2B90B55A54E67E5BDE741D19D1D804B4E48076235189981386F9A81504FCB8CE93F1A7FB8BD17C00733C10D75E1A2592D6CBF2808A97DA4416ED8654EC186656EEA938BEC5D88C41CD3FB1B7EC44AACDE80C8F2A40705F539998E9FCB8C1C47E67FE0CBFDBD70754C63E588F928BCCFBF2CBAC078868322D9A6878008BB82A3C49E46B369F99B0E8F1B3853BD51E12B1A30D92566E02C6727BB40E3169AEA34C5BC70DBC5C3AC75DE4C7F79A69BA383F9BFFB861FACC121696EFE0FF6A5D112FCFC36430F265B561BA1C3A2C8B40A55FA20FEA748C2AD3E1195572DF0FFADBB3A15E2D5CA610624361D7E8B207108B88B2FE1C3684462AF122972D8822523811065559BA039DF01B4D27D5E8D4CF20F19CFB255BEC0DFF7B218F286EFF5C8EDDFE25895E731345FAA91EE2B8924558A96732ECB4DA0250CE63CBAF1E1539C6FC555310F56B96846002EB632A98E03FEA7BDB7DF1DFF606AE962E81C211D84F3EDABABC7DA8404317466A79CF448CDD76CFE3239174CF5CE8491BFF3F158D5A9B53A21AEF49C17166FFE3710951D87DB9FF03EC1A61430D12C69666080089FB398BB913C9798EF0C3E367C3F57696CC619345695CFD51F0216E3875F7BA6745431801F565E836ACE76C7830EE5DC37DF64E1673BC4D18DB3302DAF83C079A9405D55BFE67F8949BF1F72E72FB31D4B7837AFBDCCF5FEC69BDC9B19A966FD1D990EE8C5C9017A2726FC11552A9301B3A184742E91EEEB60534A3162A355006266A721A3BE9AFB2A2B1901A6DA57A96995A8D3B8EA068FBEC60D4A8BF013F4C677D3A84C20851AF8729D5DBC9FE44B6EC8AF865370F0D6CD00B7D73BF73D1604385FE25D9E1B3520E8EBE64564844BB5A5DFDABFE2D481261D2065DB7D3352AC028C68BDEF6620664B5DE9DF67D9578B5497636F3754878B1C90752932C5BCD530F29C3CC171F9CEA2C6C8B997BB7B47E8F61104574396CB94ADD3F76648FA7EDC2154D461E893D6D461F87CC356F7086C1964E2EDB71AAFF955FD34724C36471A1A8FC1E613C946CE4010D3588BB743F882C38089122027B1A8593C3DECAA773BB187738ADD6E54092611C8ED6D2A7001B4F950D4B2B9FA0DDFF67F680DBC343FC4F44FB79A119EA21BDACB6AD84A0A4EEA022B392F433A18CB2D59DA70C0FB8F5FE214079E3BB8046A5E4AC1767094A9C3678476FBF7B942B3E163D425D776E63A1FE571B97B48EEE3744E15D8F82EA6D182AB642600A129C649E1CE0623BC9C9529CF20630F6369F6E28B5AD20DB290FBCBDA6BBA60E04F56FCC1ABA70F05E510B477C86A3EF6C8B44CD5AAE06AD4C4F597C7F28DFFA79C2E6EEA3A66E204D44C5666DD01D094FFEC682C84943C84A7746DD60C959D7891AFC5AB17879E83C883A55253AB3081ECDDCD359F53B31EA3B6E6BD075866DDE56B2482775AC3C1ECC7FC4220C0964D95E2D038C38360B362EA7CA167BD0662CF38211AE3B7D7CB90AD4B064B1785CCD1DDDB1A9F0586D39431341FBBE4438734C14940407190155C7AAAE89D0BE65775476765F6D5E7209938872749589954C2BB7D547C204794EBC0958EB16B12AC3E16653282F12A2BCD00A3737F761186A4205A9E4E6717C6F15D3C451E9979BA503011F23D7650FA4850131D40FA9A4111C2453207CE41C5B46D91D5E65DBB7ADC972EA140E429FC3913976B0F9EB2085F3AA50FF8DD4004BFE25C9C31229014AB7C99A7FD1FE6BC3423494E5DAAB1081BE1449BBB9E93C92FEE26BD914C91239F51259531EF180590F5BD2D0FDB8C7E365240454FB8C07DDF1307D28DB53AC13188A3DA4319C497A561AA61594D46B8D8EC636D1D36B8192EB8FD218598ED0DC22E9FF10DF3EAC8D5A349ADC6979E76BF5CFF15E32D313796755F152A7FBE531D19C1BDAE63FD23679C355A908C19D44A48B896C7283722BCEFA125C24093F4A31C80ED5EB439E82B4ADA46529B53A1A6BBE2DD89A06BA849C062FEB5F1476BE88932D5CB814B4AE16E8FE4D5CFA07AEC039E56A690DD3B11D4B32D27E15D9870CD4672FADDFCCD47B44BB2D933F9881868C1EBB5D303C87F54C0EAD2DB08B2B93F51872AF2D4CBA94F2C4C1FAE587FDEA0A2ED5DC52D66CF20F4C71FD5D817A605B64546E02358BFF16F532013B0D9EC569151F7EF486DDFE4BF82FD73C55E910DAFF36A190AB54F9E6BE3A4E73B12352786DA6B31E06651353478E3A6B27EE3A023703869718FAB78465F6258972901AFCBDD65D75DA277CA2F50283377514D791C5391F4975BF51550CA9BF70CD392CE9D4AA25A8E28DAC1EB631C1F7C397F2AF41E9C143698B76289A5FC83D7E7620033E5E24F0948C2931A9A53CE11EC8FAAE45C71EF4E159D8E7783FFE8195ACFD28105E1850718EFF8FD96C49478143A5644F004420582EBB6A522DB349E16C61FDF9ED819219BC5607F8A6CA733C50DDABC7F5F896951F44BD9EFE49744BA01D6BA6E2F2C09FAA5502C8468B024547D7E505D638459D7BE4CB08CF6B1E67DEF45D4221193046B31868C58E8B53FFD1144CE29D92C99D6CBCD871AA938F69C19594378E8F5D1C3DBBE5750F6008EF6B073FBB7FDF13D3EE3A4D073C6C060E1CB3F8FE1F422694C26855B52C0AB8046F113EA091F01E894746A36BDFFDDB9D237EE640B5E91FB77395D5A697C11A8F63D26FB99E6E989974549F05EB7B41B97746A9CE0BD4729F59BF95A0295EEB7F00C8B9685DC9C5976A716F09FF04D63C67327A6634FC90C741549D2EE2C0F4D2D30A26BE746F4DD390D268D4342A30B7A1AE155F736134396B2D64D505E32EDC18455C3AD5A8038DA030464FC92D18AD12F28BEC7C283F353362AC94E6E1DA4A78F1F6BA23E6DD123E6200CAAE6D5588161A72677A49E222BF247FEC6F972007EF3E17E43AE4C7EC244B95584AE077A92681F6EF7810033E12F7E1FEC20D671B9C6ED0E5BA63A6D51EF408946B20E2ADECE0B2C1E08550331F1071DEB5C661DF8CCE94FC49943567677647864F2DE1588000E397112FB824BF4B8F94349BA60E2852A088804C4CF69105434008A828E01F5B3F6821663365BA9321293FC237EFB350673FC6168C448F3DBE7062F1A48ABF1FD29EA54029E3F7D89B874D9A663707844AA176EB63C8E8E9920CBA702941A7F4337C1CC8CAD7F779C526646FFB0D85ED78C57188C44C97B2E17109615F86484EC207D3AB35404C46C091D4E2D390C7669B0DAB85D98F153ED6511220485A83279E83859685B99CEB38FA0CA0BEF028FDA2EB62216DDE46520D6886DF0659E28773F666214A34BA634F7D13069D568947A35997A759E260811469F176C7ADE14AF237AFA0F30866EC2511C72051E1B7D2C0AB3563C8FEC9CC9188955C6E863184D0192658B14511396D3E9729916E1BC03A72FD0B48F07CF83C997F94D8AC5B0C297D020F5D4DC383E49846CA207E2F51202F877A009562422412E7E471892F3E316B39131A2D20EEDD07EE5CB2A61247F9D36762471AEB932FDC9DDD2F09158BE2901DA3C2719CFAB1707234D5F3B2ED9B699D25A5E61480F93C3104C65D49C323F4F748108D953EDE5108BF33283C326DCAFE5F1ABFCF7D313A70315183BEC7073D9DC6EDBFC2F77BDB6218FD407D1A902E7D01F88D1A45EEB72710B45E67084EF3EC99A43FF070E5DD8F3ABAFDE1F5ADA73399960F13583DAB6A5FBA79F983C27A3D2697684AA938F69FFD8D6A13D927C5EDF7337081DA2710FFC43B8E06B26C4F58953D829C80F06757ADE37CFD5AC0BDC6904F21DFA39D02984F937D1AF268F94543FB0693F19CB4C3BD8DC5085B9387F2B00519C66B5BA0B44D7CC34EF5802B562770004D889A93DC045EC312ED770232CF27286C24BBA81DD07F5AFCA231CF19761685F05A80DF29B0935680D6E2853818BBC04CACC64EA48869B5BD738F4555ECDE3A728EDFF3AAA67C1A92327F6212260A0E46EE1ED3799388FDDB3360B53586E2337774FD22FD8B4FA23B83E17B724CDB22C8101D04FA00275398415CFE16D17ECEBB5071972523A9C9A5EF729CC7BE3FFF77967EA2E90878A04A99DFB9C23D823F0651F584E4B87B8CB2ECEC996155C3871BBF35B56F97F448F00FFA14765F9B9F6C63B6CF70C5963F2F7A749B1B190AECF1D623153FA721DC08486C4B92D7304A2A1CC9F65C53B9BEF4750C2BAFFA544452B30A9E54D62E0536263F71861D7CBF5911D5504DF47D5BA031140D9220DF0950A6DF2849C34DBED12DD50553B26D0888BB7F5D3C3A3E93349617CA0E2EE4F64568A5B86891EDA44C2470531667CB662B48384C28BF07CE5627D4A9E2B26A9DAF0B73AB4CA77BC58F087EA3429C311D8FE8470AFD9302D3A52AA0BC781A3E6208247A66E080462A19000F9B90B34BD78C44D703FB5CE08D45B098642BBC8E41FFE16265D93C518A2EBAFAC6DE61A78FA826DF59983DA40FDED2DAA4E715354B04EC78C80F28F74720843F973AA2C7D73D8230B9213EED8E99CBEBF836FB93BBB81F94A27D8EAEAD3E2A57A03A58933E0B67BC23231D85D7D4D93752FF2A27D973584DFBE1D0FD25809945ADF7E785AB86EBCACA260774A27036DCC884977447A12FB9DB47094CCC3FE53DFC1507E1629CF19E53ACC6433FFB6821F9D1EE7C81654BE4F5FAC9ADF049FB9671C1AD201F18349766FBD883A96456F6B14FBA76FA8D44D09BE0B680F9D6AA7578F3590CB9DBF48D58ABF777494DF49D10E0245E2E90D81056B744235C78D55E9848393F69C36CD2F7F2E3F0DEB6920360E67375D2AF1C209B43B6323E5EB0A76058383136BFA3A6C1CC11D0538B8DC0AF428C3171BEACEA7EDD2487242EDC2CCC28D867A84734C136AEFC71E037EF66B5DB7434B797EA217ABBB2DBE705220D02E773EB9F572A984223AF343963BB94B368204F371769A34989FFDA06477C9A30B8CC2617DCC7461A9FEE75FACF1F263D634D5E3A21A4793EC6B73B23DC99CA0E229AC9626E9909482EF49B2E0894809143DFD0DD53DBE8E34EEE5FD9C6BABDA9641E32B7796D47C2662A02441975CF6BA4CF045FA2192BF379BFE2556762A2118C573D7AB127C7BBFF18169C45E7CA4F1B3AB629CFBB248593D3610739457BEDEA653D54733FD83DA6985A30FCA6063F270EFA2B46C62283BF072DB62F98C155B7977ACFEC8F7CD8B50D2CA1D50AD248140F6206D31A816C65C5681350960D583BBD703D1D6F870D0E7D074BC9775D4D98F9F9C9599192F9D332BC660E76DD18104B8304BE5CD7D5A659087875870236E334295608AF40268F4DB3C34291A67B79904BD00F8B6D04B060936F12E6BE5B2D12FA2CB71833A47110C11F9A4B549747C5C12D83BC0F5095C853A17A218BB42A2344FB8831AAA31C763313714362E1E067E2FA4D2972AA74A56F383632303C396EBD967A467D495531BFC8E0E390DD92A596AE17C8F63E714091BD145FD6787FF9B9BBAAF1D7F571EB98772A59F6DBE7308D324C64FAD9EA6D23D841E0DFD3856F569AF739384D1428FAE122E5379A594C49705CB05C7206FE93A362424D4423505194998647B42269E9659F31ACEFA9E50BB7BDA80AC74DF74A25AC858A20460887A473E281005923A5F320762C8A1D0CD55F5B3B0D25342BB04C92E1B7FEA9A2AA7F0505AF2A23B04DE80B4DC8A599B7E2503C26C8318C5BF6927FF77F46585CF19DE8F0AAAE89FBEFDB39B3799487DF128FCA850BC23B56786630E8326B0F0204122446166FB07393F777844C386400AB7B4B15ED6AD7BB0ED9F30BCF7DB5DFFBA28636B30403BFA138D2B7EAE79E0C5B4C268F4F783991F486A363F9A7819902549E323830F19855DCC065331715D54F7988CF9B929D3AB882763D7C4DEBC00C1CC39CED82E70569DEC19BE5A9F6AFBF015027F1E494C45786D1FA7F816A22FBA305C47C2F4EFE2530D237E2CF6802309BC58EDB3A5A80D98126F201FA1FF4A73708566ACF6C5DF36E5CF0B5B87EFB58CF31F1A94E47EA9028AAC998917244A9D613552EFCDB5C2C57AACB65DCC4B4FE258669089221ED8DBFB8FEE57944CFECDEBDD8B41909DB5745E20AF9CF2B76D58B0FCB56626F79B9B63F89B1F6CFB18456BDA7D2CBFD971B9241AFC8294D935B7558C0FDC6F7F6F472F93AF5DB7F5CFA8D871B266FD746C45F75B64AB1454607A002403B13B874158BBE1334071FD2FDEC873DC9C9C8CAD6C3D91A849B854F6DA3248B4506220E743A86CDA627FAB1DD8872831DB3C30D2A2422F4472EB5CF0ED079C5E9615901690F8CD68B7A221515F5082D35B8D3CEF9289DC383CC03987F8EFEFB6583679A9F13A7719906729BB73A7050AE500D277E6E3051F560D914F1056143E05B77BCA603550BE72D4C6065EBD19E26961D33DB35CCFA8D0822981BEE94F9919BB8749E6B60EC40AEE4BDF8AF491D5DD410CEB2BA4196B1FD1974557A342C5097A944DBD4F0EA15381D36E2C0F86EF377D5EFF15916BAC5A8820024B69D3F2CEE7420BD516FF109B35B53CCE8F46DBB73F0A5D18112F7883F513025BF077C218BA24A3014D9606A076864C43CFCE5488FE4E616FE897E1EB7F86828D90FCE7EA1BCD8CC9241E7D98670FC093E5F7EBE8A9C598C22D208D49E1F7BBBFA679F141E90AC81F74B70F13132C0BF60BA2E5CBA164314B8B70515A5C38DE77C573237FDE0DD67DD0952428910DA97734A74A37B23490EE87159224E90B1F8F242673D5A8D199DC8226AF2A5F61F0B91E55CF11ABD6C9A6C91390295D1815CA289AB7D604595DE54043B9DCF774CAABB65986EAB2C622D600E1DFA89CB246830BF1BB4F6E0615B368CCB079EAECF58B11B2B0FFBB5550B6AEEA743C643CF408CC7D50E102EE4D7E72079EE29CB5381EF32BF8F3A4FE37A2BBFBD106B663B576377013406DDAF99102A905B1FC6E84FFC4826289F663AE81FEEFCFCEB6AE90B01DD1EEE418CB57AD69743C28D577FE1AE9A28ABF66A18980E8542C72FFA32E192B0B2D875FBC57ED435DBA2427188553542A750BA442A93E04D1E51A4A003D1D2D63B1C0DB4EF615BF2D0FDCCA90B0A8F0B4BB754DB10E81A24C3CC48B0508EA4A18D65A1820225A4DB88ADFFD96DAA9CEE293F36B9E990472EC9A3F7DABD6E8B7BCC14836DFBA6A390AA76CD79F3174482B9EB69D395DA213817D0BA0F47270CBC97C9213E885599BD429FA5FA32FD52B8953ADC0693C59B06541A4D4439BE06952C308E6CC9B7F08D7BF8747E69C9C86A7BDB1F2D8F55BD757DCFEC258787BA68A54705B76633DA0AAEAA8BACE4145E861BD7E45E9615DF541E39BBA46ABC5AD50053E440361992E221F5B81794F9BFF8687707EB53FBCB800AA1CDBE7C99685CC0753AAB4DEE22CF4E920D184F4541C50AD5C1ECBD1407605449447FC904A2B379613EE062A95445CC55E5BC0C20935C4DE411C74CC9A3F04ADDC4FB22D8B77B6BEA439698256C2ECDD8A019FE1BB5FD1A88B01213BB31850735A2BD9C330ED70E237FAF73D12F31E8CAC396A4062DFBAE4632291B160191C83187822575EAEF993327D7D2B812CA59925F424C55E0E47A656CB2FEA919A1ABC28052E9073E9470231272738070027E7994AF05E2675487455C9DCFF87E01DC9CC9C82FA6223D2453084CB0C96CD7F02877BA061C26F2E1BFFC4633858391D1C112B0924413FDED8A71DE6565AA115480E504D4A8B3127FBEF6D7A52972996E8162DBB3E215E4DCB59C624FF9057448CDE41ADF05EDADFCC13DF68D795E35F4F6C58C2D5C7BB954D31132C8A10846714A070992096EC3F90E1A40F4636F3B0D25D851345B3C90CAE77CB0C99F0AF52AA983B64B340426B2192B163738A4EC6C9A266CBF870982FAF584EA1B060C8C94B82287D61D3595A327D959830F2844AB4CC4F3B3F9BBFA72B414D50ACD1B75F1A2931FE4B6B334D3A725D1A38DAD81CF04C50F439F710082A584DBA6FE0F66875ADE8E7B295667F80C1C1A6BB9C66C9AFA7D9A13CE8717666F506D9B497B8E0BBC3518879BA56F8CD874FC51813B6C4055F7E54BD13377257CF2697AE223CCBD89EAFFB8930EDFD902A4C1B7A96DB575A8859A2AFA0F34F6C9A925D3C3515AC13BD51698F3D2C7948297CDA31E7BA83756D9FD940C63F26F049732951E117867024384240CB0586FDB2127C75B35828B1E2A270CCDEF6E9101D39ECA63A119BEE3B1286F0DCF26F431A9B0D972CFA068E1D412569147BFB3F25BA4FB1A46146536D090DB47B03D03BF7B0CED3DDD01DA4B06F0A8DC601261B31B7391A6184FF55A1E0880CA677372C712CA67821A751B32A14F7A5200D5F74E0C1AA4706116C87617D2675CDF47621CBCE093D92274230962757B429387C698A001FFF2D3112E5270059D5D251C1926C0D0A17578ACB949DDE2A27DD87C9FFDD3F3DAEEABB3560592A9B58714A2CA5C88A45222C07D92CF6DBB39EC4D3E4D15519C8CF531BA7E798FFAD3E6BE7A6CD4449E049E1A3A69C15A411A184DE533DEDF1B8C1F20AD8F307CF863A7F8E7093BF11F6C111714E325CEA294821754760FC7DD17205AD9809ED2F61D12FC2A93320CA2C3659048EF02D9C7ECE917D6A29E78589D67EEC13E771E017DD94D4A2ABFEA9C6CCC38A45CF9B86BAE7D180C6FAE2447AE1B7D436A6DA8CEF019D5A406BE2995EEE56913C240517DBAD3F88D73366747E36A812125526C0E5C98D4329396199B4B07A0B50910CCE50DC91A4FC3012566ED7CBAF40D42BB71D64C1EAFA99DC2D8FBD4E89EA6FC1F9DFE7D6B12D5622FCCD0D502D9EB0B8A99C60CDDAA659AB59B5A691325D9762BED9DF2D37AAB31985646E1D7F8383690EBB9238AF49BE5E9803148AAA35C6176991AEA5C1A9CE170B5A30DB4E70DAB3192881ECF0EAA0869F78777AF44D487F3D0EB84C91CD507355DD80176993BC1B6BA6F849F0761BD946A0BAEA9652AA8CD5EC2414153BA969DECD631B1D8DF6406C59D916CAC6E0A90E42B39B50FF83872767909E45F9F98C9A4520F1997A7F38BA070BFBA8F5C1738BA08A6DEC33F7F01307B676A7AC03452102621641FEC135CE28EB562AA8894C928A1885A4FFA0B152B721F0BD9B37940F533DD7D57F38EE510500CE4198718D037C0F4DFA29639AB527C41624563E6B79DB656A07541DD86F3E0A7CA671C5951B60CDE956EE71C50047CCD023BA1308E3E0FDCAB10C2CD431EC421F001BFA3996F39ACA271BAEF5E8C4F1D47C28F44CC1A6DD1F3A790D853EB62DC95C68EBA39BF95F5C0C40F929AC516DC0E15287DA08A1C3259811B8A7EDC00C037E19A8A3A4AF14C0F39A78008570FC41B19599CF1AEAA99A879B6F6BBDD42ADB7B1D5839C1D0F2240ABE9333B3AB543FF86A1E37478800DEE1A09C04327BE1B68CB9842F8166D4249250C1DB7B2F6CA1B6FCD1F8FCF33600D4DA6DA7EEBB1ED2FD1B90D165373A79F66789D8974D77D74A520DC149466E4A9543C054E64762F0771032C9C5DC624E08D431FA23D94D6B1827D43D47CF731646D98111CBDD6E24FCFB4F9923B885AE0C810C9A7A39B91A62F81D6A458A8AE427581B8804DC433770C5095F7DB84B1D3F8C70C0D0D90E249442C519A2D711520522265907E7B744C8B85B4FE8C9698BF6D91C93AD359F827616DA1074C220F26594C851EDE0ED73527DF2406B3DBBD2D2A555AD4F3F96090EF54F7A4F6932D762E74093BF1150A7966AA3D181347623CEF43887011748E3C44A82329F04AF1E7EC175F11E56D3695CC75BFE7865C314AC390E2DA03DE92D6858464B026ED0DC58318659006517B9B20AD1B474F6D5EC399A7CE72EBEAEF50A2578727D90567CE1B8AD08886303E46088C1CA998F1BE1956ACD2D8B8F2AEF74E01C800343715BF4518F91F3FB99D51BE5A0E1419129FFDA624977048280B8882E2409235A184806F1E1984B31451EE1AFC2B944463A6798273FD51877D24044780652B85928C1A6E62064FB46D029B51154B5C44E947DF822494A6B4FDAC24ADDA934714E9D564BA695AE9BA8D316A41B24A559D6256E9F3122CF8151A422D4735765B746E63C6CA4935303C46E72B6DEF10A5243C616A0E23C7EAFC7E5E6EB48FA058BA31BF02B17E0A98808010741826A9432537DE45F12ED9B3F95E88779787836226A0761DAF66D0006615EDF95B9CA05951B97D7F3C3BD6BFF9C2324E96FAF4F24CAA9E26D8E3BBE1B2EFCDC285F773C25898E0E27B0341E3B85C5592D3F08FCA1D4DAFC5DE9B61FA77226FFC61A08E289561D1F602E3466FB29214A0CC7E646A3B4480C6FBF2805E785BD34D01A66502D27BE2C3FBC2971424A89E2B8D8EB93A22B4807FE597FC3BEE30CA348F7E03B0A6129C9F1034A70307E9AB207CC9F4CB5C934C5778D0119FB0419B045C02CC7851F5CB845F1996ABFFEB85A65E22863F67784C9EC9C60D34CDAE19B11530FAA588C2EBA4B23A8BC821B7264678369C28CA21C02B0DFE759885D646A57E3DDB072C6278AECFF4582A96A9931034C7A870DA84ED9BF4CAB67749A4908F528156B948AA540F83AEB1BA4D2DDFDF33CFAFE1B8F6EAD36C2E7C63A05AFB444F5470C403FF028C3F4A793059D0BE539919461297042A540800BA036F41EA411363DF53E4B4CF0EDCBE4953B5A81B34F4B72614D55F9BD4F4A0CF4F199FF1A52ACA30C1BC6738464EC63FDEBA86C7E265B376F88B0042E4AA50A4E1CF7A1A2A04F8DA47549548EA4F62B52C0347835A7873B88EF4A5F44E512991DC18EC6F03EB2AC2FBC75F1A0D25E20BE87622AD0983AF20382A376D1F9F0B5A34BEC3C836F509ED06F8CFB1468E7E1B35FD9325891313170FEF62FBE18A65AC4FFEAB2637751921FE2B119B2BFB753F55E6EF2F306D8CBD21379E103A8EF8B1FB8C6CB86981116769F9287FD9CFCE7CFDF8C57D743B2560875A2E97338C9E9A8A87EABE60B2E9BAF14C7097649122992CC8A64B179F9A869ACD266FAC505B5E01BF12C5164557F9276115486CD8323A4875DD3E73D78DABF53AC46F844A19910A496302201D91F4A7A3F4EDC79308B013BF29F6F5E229B0E4CC55354BA74B6939A23DFB7DEB242ED64863713600593CD83BFAB85B6FC75A00ED78874116EF0DC9FFF9B35BD1EAA82333C7EE834CA233CC8E771B8A1C807822E3E980718A41BE2F8827F1E7FFCBF5EE08EAB3F31C6CAE10F66DB3B564C7AAEA49BC160FBE94A94EAACE728CE248B881965ACBDC57FDABFD11854A7FA56D8210641800ED27DD3B173E4BFE42BC55E4A9BF7D026090359E7D0EC30D7B5598FDF057FDF8016F6D5329B54E245F82FC5607DFF5EC52BD063CCAEDA21FFF4B5312669119DD300, afterDelayedMessagesRead=1446113, gasRefunder=0xe64a54E2533Fd126C2E452c5fAb544d80E2E4eb5, prevMessageCount=167939427, newMessageCount=167939720 )TransparentUpgradeableProxy.STATICCALL( )-
Bridge.DELEGATECALL( )
-
TransparentUpgradeableProxy.86598a56( )-
Bridge.enqueueSequencerMessage( dataHash=82466B96E508D4C258DE10900ACA117A920522754C484B0DAADB79FBCAB72485, afterDelayedMessagesRead=1446113, prevMessageCount=167939427, newMessageCount=167939720 ) => ( seqMessageIndex=578949, beforeAcc=3BBE8668C3BB0ADFB20382ACE51849536B3136B91FB0301BF3E6A2C39E63A8DF, delayedAcc=39BC3880AB5BC857A1B58DC1A0CF0ADE0F616F6F5BC8DF68F9C05C471892BD25, acc=231B0B5068643AC4F6385BE51AF65F4CBCC0447E9C1EAB48663B7370CB287088 )
-
TransparentUpgradeableProxy.7a88b107( )-
Bridge.submitBatchSpendingReport( sender=0xC1b634853Cb333D3aD8663715b08f41A3Aec47cc, messageDataHash=8F6103355C87C15DC14A5775B981B064953ED81822BEC090E0BABD075600E197 ) => ( 1446125 )
-
GasRefunder.onGasSpent( refundee=0xC1b634853Cb333D3aD8663715b08f41A3Aec47cc, gasUsed=181567, calldataSize=99172 ) => ( success=True )- ETH 0.086210677537065876
Arbitrum: Batch Submitter.CALL( )
- ETH 0.086210677537065876
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);
}