Transaction Hash:
Block:
19032428 at Jan-18-2024 08:01:59 AM +UTC
Transaction Fee:
0.052970604053177862 ETH
$109.18
Gas Used:
1,826,906 Gas / 28.994706927 Gwei
Emitted Events:
| 291 |
TransparentUpgradeableProxy.0x5e3c1311ea442664e8b1611bfabef659120ea7a0a2cfc0667700bebc69cbffe1( 0x5e3c1311ea442664e8b1611bfabef659120ea7a0a2cfc0667700bebc69cbffe1, 0x00000000000000000000000000000000000000000000000000000000001453a4, 0x20737a6eea6c8c0741d09df8be690c79212fd61a75aa5b2e35e5b44904a9025d, 0000000000000000000000001c479675ad559dc151f6ec7ed3fbf8cee79582b6, 000000000000000000000000000000000000000000000000000000000000000d, 000000000000000000000000c1b634853cb333d3ad8663715b08f41a3aec47cc, 7d846ace6d6cddfcd05c9b3cb99e31d63998e13e78cbe6422a80676fc55617d7, 00000000000000000000000000000000000000000000000000000006bd3d2d6f, 0000000000000000000000000000000000000000000000000000000065a8daf7 )
|
| 292 |
TransparentUpgradeableProxy.0xff64905f73a67fb594e0f940a8075a860db489ad991e032f48c81123eb52d60b( 0xff64905f73a67fb594e0f940a8075a860db489ad991e032f48c81123eb52d60b, 0x00000000000000000000000000000000000000000000000000000000001453a4, 0000000000000000000000000000000000000000000000000000000000000020, 0000000000000000000000000000000000000000000000000000000000000094, 0000000000000000000000000000000000000000000000000000000065a8daf7, c1b634853cb333d3ad8663715b08f41a3aec47cca3215d2c48d9465bd14e64f2, 8af02c997f51c74e03a164a7d6e638c177ca0f1a000000000000000000000000, 000000000000000000000000000000000007ae46000000000000000000000000, 00000000000000000000000000000006bd3d2d6f000000000000000000000000 )
|
| 293 |
TransparentUpgradeableProxy.0x7394f4a19a13c7b92b5bb71033245305946ef78452f7b4986ac1390b5df4ebd7( 0x7394f4a19a13c7b92b5bb71033245305946ef78452f7b4986ac1390b5df4ebd7, 0x000000000000000000000000000000000000000000000000000000000007ae46, 0x0d2b5f1485949191e4ac6a96c2f01934472de0ffbf50ad343afe6838156d254c, 0x1e7bca5a13e78372d34eca2762b0d9d4628883018f4e9662b02270d34ff616e2, 67781e9539bb0ad1081eecf10460eaab1bd8ab0a42081006c694f90b577475fa, 0000000000000000000000000000000000000000000000000000000000145393, 0000000000000000000000000000000000000000000000000000000065a78977, 0000000000000000000000000000000000000000000000000000000065a8e907, 00000000000000000000000000000000000000000000000000000000012252ec, 0000000000000000000000000000000000000000000000000000000001226978, 0000000000000000000000000000000000000000000000000000000000000000 )
|
| 294 |
GasRefunder.RefundedGasCosts( refundee=[Sender] 0xc1b634853cb333d3ad8663715b08f41a3aec47cc, contractAddress=[Receiver] TransparentUpgradeableProxy, success=True, gas=1869690, gasPrice=28994706927, amountPaid=52903041078063892 )
|
Account State Difference:
| Address | Before | After | State Difference | ||
|---|---|---|---|---|---|
|
0x388C818C...7ccB19297
Miner
| (Lido: Execution Layer Rewards Vault) | 187.508697494449069466 Eth | 187.508788839749069466 Eth | 0.0000913453 | |
| 0x8315177a...4DBd7ed3a | (Arbitrum: Bridge) | ||||
| 0xC1b63485...A3Aec47cc | (Arbitrum: Batch Submitter) |
10.001753489204091312 Eth
Nonce: 452152
|
10.001685926228977342 Eth
Nonce: 452153
| 0.00006756297511397 | |
| 0xe64a54E2...80E2E4eb5 | 879.975066293517356653 Eth | 879.922163252439292761 Eth | 0.052903041078063892 |
Execution Trace
TransparentUpgradeableProxy.8f111f3c( )
SequencerInbox.addSequencerL2BatchFromOrigin( sequenceNumber=503366, data=0x005BAB53343210380F9073F049CF115528DB3E3582EC467F2F99C8F6E98B0ED6B07118F0B09B63C65F0FF044A4C17EE382845A2258F78E0E8E97F77DB34E4DB07955CF0DB34C11602138205050E995440069ABD08893E87784B6AA2086CAD4CC12F5C07A226C1918BB0C4AB4116B9D7807E09CDB5A10FE60BFFCC00763F1594B0FF0939FFDEA3DF974A91EF3DE110F0BE0E9148FF8BE76DB88CD4E747EC050E755AAAA3594D2255980C6A15B7FA591A9EDE599C30D41CC9876B28B945684DB3B1CE9BE072ABD9457FA37FDE56400CEB9043CC85C121FFCE0076008D6F94FBF78192F72988CB7316693FDB22666F2F542C78989FCF563B317556358E919E6D9F83F9D9F7F65CBC4029E1106801462055D2870E7ED068047B2ECDDF0C8EF6DBF652AEC52D1A7D313E1CFF373FB73EEBDAF578C118311660242BB2126764C3F4C7B664C36237A766FE630AA401B23D13F93499DFF76A365D207362872E2C0C780310845395612F9D9B2638CFDEE6DBDCE8833ED7F2BDF8E33D0D6EBFFE9B4DA912C2752965087D45DD12D41D968FE589135B2126B8C92E1458E43242F3A0786257016A13DE605720EA1C2A2D9F68AE6AAF29AF2B8DAEBF0FF96A6547F566566B533324D3A4C08DBAADB9D995DE114D800DD9BB9C95C75918BD21AEC4DA755B1BBCE963B4C79DCC834A502E817188A8282E04127C82F2856BF7C93DE3900C8A5EEE937D2FE24E5D29E4388D4D5B3EF428AC54D4804C4A624436C000D0F50E8FFBF3755B7F8030D88910DBA54B816492E4C5BE3F3E061041143443AA07DE803B8C28511601D9E03E410F3318439E080120440ADD1CE3934E5465215CE21FDE6E182043FBEDA602463089A014B0A11F238A490428AA905804C4704A4944A0133743C2893BE726B63FC8FEFC271A730F3A9B10820A5E1648672F9025200CA05E92E7DC5B4B2CBD2CB94BA5B24CBEC265D4B656765E52C96A5F4E52E14B5134C69AD03C59FA809548387E7725C14E889DCCFE2CD096CCFAEA8682D0BB417AE413D1FC01D69D34AD722BE12DB6259815B87BAC659A462D77C9B9A6EAC30AC6C0CFDB67ADD83DD66BDCD0657A91AC4216A2C4A11B4EF5EE45FFE3EE87F4376F7FC365D0842441414B07C7A745AEF7D992D55D7AAB67317C751B224C809B1B571C30570A35523BA0A460DBA63DF9CFFFCCFE9B9D0356EC75F06DD643F0DB524AE57038A6B21A8B0B386FFDFDA6FEE206ABBDF4C13DA6824D2930306B8692FB5F7A96E3183082435A8EB32BC6D27B58F1511B9E3DEF9FA2A02EC60FE49E947CDD70012D0F861FBC9A02F4FBEFD11BBFD169BEA82D35287FA919BF5436DDB0547ED5DB5E48EFC649783D76FF81D26EE92EFA81B7CDA2AFB8B489059F1FA9C9701F96520F0E051E157F006FCCED7CC491236BC1E2BF2EF549A5737FC940FAB9B769AFD0103D3DE37EB7FA7149FFDD1EFFB25996B6F7EE59D33EFE89FF78F73B83FF5707F20541CFE0FCC98A1DAD7CBCD333CED9B9D996F7F24E76EAB75BBBC1E069A1142593EB3C737C600D31B11721BFF1F4163468252F96526243B35382E80516923E4CDBA0AD31B76609DB55754D63EA8DDDB00A685E81D60B275019EA393976C9FC0DEC8283966C8B5EDC263BB38E6FFD53A4CF107C4711A65D0E97814B791F12BFF85D1961D959F27FA012DFBFF5E5578B5ED3C6342984F0D85E4CC25A63766054801AC36F80F00DB27DBC29405B06E5380E0EEE4FB5929B8CD0311845CBE8A6A9B4C48B6953A412E4663CA536C06B3DE1A90A0B74A28A4A1D0452C3452A0A09418892980BDA2CA78BA039C2660270969626025654B3AEA3807C754324E6FE468506899FC711BF3C8FF19B1077BDCF7F0932773B7960D35EA86E80C3BC650DAC54801DC7D79A1EE0EC09B465720EC901AC30AC801E3B1A2C627688B02FA820B16B0D6C420696FEC184B64F9DE85F72EC6B2DF4B68480261A502618AA0C03DCA749B3EE81E479DE1F0647B6A99648AFDCA2DC57B993D6DFC8D38AEB9A41C0A1FD38E358EB67EE5F78DC05FD5D34971FA5DCF640E15FE54B5B2C95D421F4848549DF6E2E106EE27E754D015E9A942249B75114C9EB00647335C33E1B283ABA0963AA96D98B47F9DF495B2F0797FB408FEB6FBD5BB6EEABDEFCFF227FE99B277C1F27D5E5CBE5A6608729BCA6ECD11EE8BB418890B90D2CB1D906CCCF730F3242112FD249182D806C2366E93474A4C2E4927E76698902920D833AD75238A67A0BE3E4F91065B48858CB013D84D74E119DCA3C990B6281B13F204A953557CFE00A55B6227B8CDDBEAC3F40661406BAF83983D2F02754B1E79F714E5E58A3B492CDB4C766208EBB5E148804883C33049835F6D3805D2167F7E41C7689F1915990408B66D19D4747D46C383C94E5EA2F6E93325768B76A1054A409AB64B3B6AD723CE4B8990E09D10E76DC99C097C469499A01C5B8707063382D6787FDB44269FBDE6ED151FEFF4DF8EFFA32F59408737753BAD9BBBEF2EB79EFA5389CFF5B3BD57E56A04816E3511D1464C9D10D5CC54F39713CDB420010CD07BD927087EBFBF0FD1AF48C5DC6086D7F4B7656148130D2A5B230C6E916C28ACDDF8E43F397386DB6F1E7ACBF367787EB97C55518AF4E547EB739F4A3257BDD08063C75F34045EB1D7F5DB6092D15AAE4ACAA280E5E1B5567F1AC35C5280954AFB85CAB7E1C02EE9CC6FFFD8AB84B8790D6BE057D445EE7BFE6F7E2293ECA02591FAC3F61B0B4476DF355EF1A7D30A1079B63F682973845DC92029AD2A2A7E863C150C73F52CC829A9D563C60F9CF1C785028C6E2D560AF0D805D874F57759643C45AF5B542AFE1E6EBBE5B1174FB6FEF02DFE3DD5941F184A3EE2C77C7E5FD9B4E6F1FFF157BF3973299C1AE139E52BB651D161645862A61FA9C490DADC11B893382591C3AC4BA4ED9F623F91C9C8AEC174C2D9B46964547D7FE9D9F6FE31DE7828FAEF642A4FFF626058A46ED3B902816EEF66192F0BB044624E499FE1095794B101390BA4C4306BC74A0A1219D48E06F70B4B10B83755C7B498DB7ECBB83C2BDA28851870D917ED86FD38C13C5706E024ABDA15EBD2830CECD69690310D8AE0142E6ADD27646DE629CAB25D72E6A63903356BFABC57988514C4D02DCDE83D273E2DFBAFCC36858672E2E8AAB346EDB05CE1F71450C072C0282834C2B919F6AE497FAE236016DD573D3B575F004499E4D8F20835DB779CF8521124248D491C6615822035014B74E678B98C5EB4649F312CC2A736A458669C4229898715E4BC68DF7557BCF018FE80B80DCF8528AB631433C0A00E88075FF5F4C58851E69189D8B305BC8099665A47F446814422093D1A214C5E963C788A0713FA718477188F3ECFD30974B90C5BC4A807277AF6BD58F968EC302427000EADEFD511F2B3B6AAEC37431A0E07614CA92575209486CA9642211F3993F110D4060904C68C99FE809E76F51AB5CA18BD28A77C07DC9AD918EB2466BCA09042B045EC0166F5AAA52CCC010791EECAEB0B6106D1E9DA3C2AFCA37E14E7D910212104412603AC05E88C6A711824CDFC1048A3822519079A9B081CA34B0BB5CADEC00BD89F0872C0212E97018372CEAD6027AC07B8EFED491082D2BE299597D59E559BB7A2B91527404A4F9D0DA4642244512E69586795C5AB0098D66B704240B44F97EC3672856AD02D4E8C9BA2A10EB4C9703D43FB97E5F6D678323870DD99C24959C0449BE32B651294A4F68889E231724B128D4148C1294460CF8B82FFD709998B241CB04562006984B4AB4D5ECB8C771F013DA5F2C29C6432F3D251A213A41781BD9A22B563788575E71702F689436BB1607ABA6B38AA5EE554396A7A8391404651723129A0D04EA5FEADA65A5B487384A57133421A33E3E711E1D298A8B282CB8CC30BFF05843E09DD92C97A41383FE8212DB33D0753280103030C0DA130B2E6C7E71A2C0F5484068AB2F11F983E6A3279F07ED834C4CC7C8D8652D93A4EA1F3CC2068050CB86EB0D5AB9473056882BAC60D839864C042BA66C05452A76A9486D09E98961E8E8C742C8120B4EA764AA50EB467E5294B947760011FE11AA43350E32B6836AB03BDD28B60EFB77FC699C71A6CC118C600DDF86704380F8631884A74B938E37DFC2053A7E1DD551463C0516D27D752FA34FA475C87630CC63E2D5D7583939297636F9E3873F92982C09EF392BFF2E2F8B920F9B7A8C63D9FAC0DE8D08A8C6E0C5AE2BAB2A604033724A79D2D88712B72F19A0932F7572EB9DB09E0DFED57CF5230609BBB1FC7AF496314131014D841E8DCA12C49C9C1C23FDA0ECBF6C021C92ADEBE021CA9AB77F2090B9C946C6ED3936B5853866C0E13A726A3BF0369B91017C3333BFD0F41E452E71A0B3319925436F76883E78E96A4EEB9A7816FBFE9D2D210DAC23DC28149E66204B0B5890F1D0909ECB478FF83FCA94B920A93125A289B388053CE9AE5A7DB6E532B60521DC98A541FC424EF5AC8317E00194E65D28AF16787ABA9956DDE915C5E688FBF915CCBA87C7677420396CB9AD4E2F111F0EB7CE4F198BF028D4848477AB1A103BB1D328CFF3F48893896FB6548F2BE35678D8C71A56F6A9C518981FF9064D2F4B927E5258F32E60DA3B34216C963BAADD1468D46C9131DD3DA7ED6D413A3F58F6093DA20E108EEFABFF34F4DE4C3C8633045ED4F99B3AC89FD39CD6CA649048D56A28344544B0420D114658C758801ECD2664D755E6A3BA2BC4EA44E89A6EBDBD1EE8F3AEB56D0ADD2E91DCD6C94D4A9ED82BE4B745D98636A4EA2D17DF523D2EEE3DBF89F5007E5FCA99A276442E7B5B2CB674E32B3B3B69C8CB50E7065169BF14B767B22CC1024E88CF5C86B742E99E0F4C424CB2C75A872D4E78AFD83184FD5C1068ACF0A2530BE4BE219C6B922E141281A71EF308D9238472779754220D8F0636B952603302505DF83A3D0203B0CF72B0020DFBB574DFA394C418AA55BA14C410B45AE45F71A6B7130CB5DF9E128DDD81EA5BF4F283BF211AEC6FA27785465DC91FD6B4DEEB7D8C22940C303DAEDE03D01EB86FC764441F21EFDA60A2E046DEAC5DBE272B1B6B260382A687BCAB793CBEA6A3482271BD51F73B3CDA76A1FB7501A9BEBA49093985A6BD81E01B6AC74E43BB29BE26BD452DE8E51E442FBB558242C2E7574979A665EB227674AD64E67707B78DA8ECD8BBC5239CE4B1DAFA55079A5CE809188435DAD81F91EBB785F196377EA73752820B6ECB7410A3220D4F93D1229608F3A4E676EBEC5799950787CCB6AE55F928DB2F38211CA38526485B15AC50CE205C284B3F079A10DC41F9E303880BA187229D3769ED5754F415DCADC161B9A547672EEDC18D5A52E4F0E842575721A29929C8E2AA9AB2C28C81B47DAAC93CC64A2EF8E0A3005DD10C96EDE5BBABF0C4D0EB8926AD454BCD3E1B26F5FB2D34B530FA542F1244DF3796B37E4E9E736EC5D5DACB8BA494F8CC65CD05A6C7886FA7498561BEE19677AC6FBB6F97AC9BFA058AFCAA06C0C6F82D88B2B103185B1F7AE4C7AD812646A79FF29C7F93E6E85E190B574612AC6D4701562B2B2809DDE51C5813739F5298C71494FF2FAACB5160920D47D742DE526509CD6659CE716A8FFF4299F4C551392DD704A4A1D267B458B3F0A5F1A7C1F083B0EF777B727F7CD6E36DCCF1F2EE6BAE25596637C49B83746497FA28158E693B9EC3FDEC1E4BD04EBEFC29BAE6F3DD09FFBAF52938D2DB8F7AEAD88DA80F792EB6E3095B86926DF61EF6B71E46C808BE301427680703DB6E0E9E49C06E49A38D2FF6B1339077274E8A0688135584F5E70EA27D6F86A105FF83E4E8406D5C2A46A778705863A45A61BFEDFDA24C3F509F5FA250AEF599F43EDD87DFD3D9B8ECA7EDCE75F9DF08D3913E3A37FD7146FF0D478B2C4736C883AEA9AFCF80FFFF67599B2EA680F4F763EE7DDBBBEDDEAE9FED496FB397417FC4369C2CC7D1FF8AFA9A623446A6841060A1646A386A672AF96D057CD8875D95923DF69B4B6D9DA61C9ACF36CAA83A9E9F01E0F4F39C353570D4D0D3FFBC389DB8B8FA8CCAC303246BAAD596BF048B2D4A1E8BC0AA04EDD910EBC8E34B411C7AAF8CB414212141B45038D478FAB61956E090A230A03ADDADD5B7E329046D55363D0FC8816A8509B1E33B5D612582CCBA030E34817701C1E50F1B8B4D499EE90F199DBC3BE2893B4295A5DC7136EFE84BB33F936FBE2ACADA72645781CD5510B617C5BAB25DD33582FA3F828EB18A75FC29B9A1E8E31E0529AFF254D9597AF480CFEF359B8AA5E6C3E816C7A84A5585707836B2476DB67E0F3513A4FF6C43413CEE7ABCC10352FFF60C8D38C3EAFF898623AACFA44A72E348968E6BD643397B52503DDB76DB6603E2C92212331CDCA720C9A492116B8370E66CDE2C2729FB1777381371F1FF4A6A8CC5CEBE22511E225C7CB98E63479C62B9A56CDC3C91270AB86F18733C931977D1294843F2466E8AA2673D19CCDF97A0D870C05389E932D183B399BCB6F98CC5865ED05628E52A8F6D22A6369BCCEC1049E5D41D9D38D2D14E9BE9FEA8C16CEA3A7EA446EAC9548F30E59FB15ECBD36A41EF57A10DE56FE1143E4EDAE2EB027A11E2054D8E45142980227D90240105959D8239399833316AA497CC7F847104439C9E487A60A958843095843B0D514A49C2DB270255EFC287544D0F8667D63788DFDB2AA437FF1B484A7C9437DAB7EF6C43C2943417A21D6E0663F4409F73B2922D81D8003B9D58150C996788F442A2EF6FC32254A2812DF85F7FCCDED31A940E288A42C637869630E8F919443CC21C50683D1CBB6698FBFF235F57627FDCFFCCE39E79DD4F1069876C1B2775D9E7CC935F3DECB8F6F7AE8B6B7D5B8176AE593892653020A137BD11039087952B52B87A9A92A46DDEE23D62A0AD1DCB99A5D41EA764743F2346DBEC6944BD396D504A8DA7731C7E6F3E5BA08755887F53BAC4D14AD4D64BB8F4C37C73A49A9BBA99ED21D3329AA554F78CE192F59A5535CD2F3F22C0B4202E5202F6A09902AD22B1D52602A7A9197DCD7E9F88913F553E2D1CED981F4336D941C0603B52A85A569907B177D3B299122BF5BF33D9452558E4BAA1E0245C032B16C04137FB047CAD16E0736F76915072BDF99F3D890CC7F839AF970C970C64B308AE85354D7C999E15353B426193DDD64E14B0EC4C9586F053DE6B664645524E12592EC348FC2251396E5563C54D7E8ECF7FB647177F2DDAB557DA592342ED4970F51253119CF9664EC274454559F66F28423AE558F98AA11407E7D6FDC041D04B65685213AD0907E03262CA818D34349F28E427644BA02A309D162742199960B45142375F2755B88E61299BE6824DEEF16AA30E38EED686BC4011EBA4DC925333B5702C512E7EE690BC57BCB4218D7E3EB7111060B0BB6FD78AE963ABBD32E458120F819AD64F9BABD9192CCFFC7F27FA745A4835262640C1D125082596DAF510AB7F1EA2FF094E288B602B15402C6E5F3E596294B944C2CB9C28CEBD40A9544F5EA9A78865EB52E2C6C7786E566834219E75ACC3DC50A50B0372250CCE91B4FE1A42B66A57D58A0F3963536CDD333EF44680166FAA162FE9D3684CFB576E66D522A72333FDF12A6D888CBD878136D7224F23623BBC7D750AFAD259B9FE4CD966CE979541A0DA8B0D420A78C7DB5EE0DBF2751F088DDABEA2BD56E5DCD9E904A6695B76AAE1B48937C88E1D6832D923018237B7401AFB66856249505611BBCD50E6A653DD822AE009E129E076AB51535C31FCC22AD7B6972F0EA5E72C82BB2F3997698C35C6821B7D856555DCA5B8D3B72AFBB1A07B87F805A563974F5D455EA905B41ACDEABCBB4E4C26111C210C72024A3E2FCFC54A7305F85DB7A7AEBA00E0E024AC0E4F86FDA30AF5CE4D6E6B88169A16F1B863161C9C380DC54EF4CE8A1405F4257D8395C505E1848570C55DF88F33710E461801EB37AB9D3CCA534E213155027C331481A69D7528F4D20EAAD4E437491AAB868877F38E486CA2D1D24F903B1833887DCC9F74057551E4957ECC55C1F62861B6A512DBA894258AD502099F46DA17A6B163CEEFEFE687E263CD41B2129AE1453421FD03F52F99386ABF85362A7AE80864DF2B0EFF0C83DF7EEBD77955CA976A7540590640624379CB025C699E8A9E145A3B6B609605001FC03E879AE8671C99BD0D66337E14A26B457B927FEA93AA14C8B845022842544E5134EC82F148049F31BC313316444A74298D515BD396765742987062BC1DB0A978603AFF489C45FD5C9E9E4D6B204A589E419660D4B37098135D3637FDD59CB26911E223A2511CA35C279FD9AB73E1E237F9E1EC778073D0B7B220C037E3E2FB8B6F696A14913094CC96A776B7B117012C59E4C491C461956A1A836BB274CE133914A1B8E67E4E3548B5ABBC5869B5D5C24DFB6ACB7A89095A35EE334AF52BEC18E6ED6CCB0B4C000CBAE7AB01C22D2A1B7B980B0EF23E89AD1C6CAA6FE55A8B615D452C59976A2E96C6FAFBAD297069F23A19958DC208B86DA51F3D899A6AE6CA22127F9780444B2AB07B94F846978684DF4B904BF2C1D62253FDCA2650E63AD886ED98AC666FCF64AD8E3CEBCF28E09054481C2426F2C34998E99F402449C6868857AC92FCF0D55300A8483A2BE76223A2B765159A7F60D0B3D083D03D272BBE65273EB0DFA30E8AEAA9161FF8B25F9E7A8CE4AFD4C9BF441505F1F74AF019D1D6CE46CCF42867C9E6C2575E19C01ABAF1922C3D0059BE811BA5604658C82A1E0692C94CDA09C261E980E47989FE2F41089787A5FE418CBDD15461E95D7C035CCD42D342E0575B92A9C88ECAC9A218073F1C66E149D3FE5F1300E826235216ADFA24D8524CC785F525ADE6867BD4E7A00584743A29C538045BADE56E161E7823DF170E560D538BC39074520FB32A44AC415E841CDA89BE0B214466387B130C3CDFB2AA4108FC7C3EA40CE7E9451388334B29F2A11C73FBB45DA3D818C70CCC446E148E9DF125E521481A0798132E5716CC629C2A266E8BE8D40341ED1BCC7387AC38D187A93C288963497AC213B02459AD87150E48169A2AC308A238CB4166B20537155CF41AEAAE7843E66FD0D61EA2C2A2B6110A48E42B90635A1DC267575CEB734A661126193B8910CE50E6750163C8A9558D923A8F3074070084C48C8DD32511A996BED7E1BC5C638F6E060BC642374D71B4561AC191412618CDE6A3814D3C694743765EDC80F646F1DD41D55BC2BB9F9005D4DA74E268A5D6B8756873BEE5E5DF29ECC77F82FCC3B8F7E9BAAA39D8786B1BB9D9BA4BBB18B99A1B88A280B9B70F38EFAB3D8BF6E8ACDAD9D2C5CB548B1880F57A3A65E0EDDAD9164FE218F20EDC4ADBBB26B76160CB160B8F24AA7E2F3059AB93ADA998A02445A404CEB28A6D7E4528C1D4CAD2A5FC42433F3AD0B03D8296BF8662ED1E9906F7D36C4E81C88F2A377033C8DDF0952578BC1841AC68A00EA22944FCA24BA70EE5ACD25772909A1202D5A50FE8AB6A3737A5204537949E7C75E45FDED15935DBAD89889469C52DC27BF529A3885ABE39DEFFA41B9E79DCC7E86058E5D70948F97962D55B1935FFD0A63B856F7111731B63F0838039D203464700D2A7D7B429063EA59141D6073FC5386765C6D2E5329F265AD81BCA36C4682B42A6C53275208624A8312805C7DDB130FA0708944B492A0362562280CD0F398D3F5957100F893A3601864B21C32042E6A3A6D6BD347B1182D723465A49A2B2C49243EA7E98B74A4783F07B38064503004281F0EAD6957FC23483D52A82851846D3BDE612384832742BB9D8DC0262DC43A5A139A019AF25BB33F5E8CCF53ADF42FC38A6345066F8C26E3D5F0CFB87A98EFDF01E38200FC290D0607F99D434B1A5082C310903FF5A791D5AA01BF36AFACE87C4090D1ECD90FFF3A9836CB952552527DDE08ED7F101CA29A48D305E131F163FF389563B880975CF532357137F1B868D0B14CF4FE83600E1864DCD3142A6090323252060BEB81EDAA1CA01271809198DFB7B94BA86EF911DC01842985F73D041CE477092D69C03B98AF1CDC6469E6F67A0688A2F6E3C7444132B00A4A7D58A527AC51A0233F8FBB7000E0E80F02D4D3B9F5E5C718918BD9262F5F0E959E576425B58B6A737C5DE67FDD614560006EBD1B064AE36A21187E13E2EF25313765C3BAE96832978792607A1302C57F8BCE3FEE01A33BE5FD790EC1652D0F83BDDF034C402E1174033851185CD2828C572A9668A084D7B1587C39A662D930D1694F2361056685BBFB60621E892E33FE5FBAD326C79426734EE6B4DE68D77F51336AD7DE8EE0D61045108E5412031A1CF1AC860D48512ACA696BE725C4CB37F69CC3889A361915F7DDFEA3D959A0E902790530829FC0679594CFAB1C2FE6A9888ADB1174DC0ADDD367C7BA988B0ACF3E7B6E94115A9EF8CD468B5DD030B5242D0E000BC3AD7AD5143CD99F69C248646CB309C33ED304E3A91068E001C43C1FCC239C0821A7114004804BC3FED9146F8E4CA154CD89A3F81CE0E1BA6B7C942C9D5E4886F1BEFCA5AE0CD2F7923B79C08DD8AEA49B7623ADFC09FC7A46E1E8DD22486D08126D5DFE51A28834EFBD083C4E7317FBF383A794C54EBA0BC6CF1AA8E194FBE727848D69082409B8B9AC047066A607A73ED5F9EEBD714727D8657A1ED08AFA9429FBFC1A46122A42DDA90CBDB6FD2D5189643EAC21168F9D9ABF1569FBD7F0AE753EE5A3B21073CFCDEE47FB8701942EA73BDA28FDE71A9D46D05E53548C25C57797C2458A3E1FF820546C83979A23507BA9BADC90853AF90CA7CE654F8BA60D7F14DA3DA461AA7F55BD09DF8B630147490BEE9482F951D604605E5FE4AE1ECE05E67473C8C18A21618DA7DC019BDA70AA9BCA30A6D560103882B09D85751ABA3CEB4E7CFBAC6B3EEE5E0F40D8473BC258A7620AA592E75A002A871D7B3629DBA54412081729750BE3DE3BE5F9AA576651C04E7CCBCF3AD25B809EA4A22A400784C27416E4B92FCEDCC934CFFCC41C75263E58B269E3BB8600EC7E8B066E9BA00EE0D0A56D9E08405D1069E73EA826A3489A1121C4A1AF219B53DFD39173E9361485B0C28AB08B7E10A0E0EEF18BD8E635F773474E2AB9B6F82FC667B599A9FDA2C39528B457A53AA70F1A983C76DC63B687A26ACF6349CFF79DCCBF17AAC909B32FCFF9773123F1AD40A1237E80160023F0D7D7A3BD90C22CA095A5A7B285CC926924FC12233520B732E7EF404C56AD86825796243F1863FB780F4D07C662E62D9A1A6B2B7084A0D1693FFB779C685601E6F583001F9134F1C2F29F339034DCA51F78217C81D26EDFE119E74F2D8D546CC017FD03A060A1DA64B0F8CAFD5A9BD2A4AC13F1DB3E5EAA8F7C6BBEA1A24B65A995B6C97B17D0AF03C9742FC447E61306B75B281406BF1C2A94EA8235A446D7F21CB57974E1949D0798458D5CEAE61982B2931870C22516774A138EC947ADAB9532B0D0F09DAE90447879021669322BB4EEF20B61D8B7DEDA2A644106D60C165A76CD31BD849C12F01C17285262B5D57A02B8F177D4E853CCE0BC12765BB408C904AA805F28C55622A87FAC2AD0F34F6F723008F8E3CA47512A0DA356A4D044D866F01A987464EFD8C86AA2BF6A3C37CD0A55D541A512F1ED8C603ABE6ECCADC92BDE3771251FE284EA3304639A608538F5DAC43C40E14DB9ED291E347AF86AE5C46A7A4CADD4F9EFC2F5FFB8CC8D4D20BA22E7DBCEBAD89A74C47DA20CE62EC085253D168B0301B4C74D4FBACCA19A42379FBDAFCCB95E3B3AD5FE04C680AD910731B5252C466881D2196E29B0DE2C5F12CD950480543111808E8B831934C188F761B71412F04BBFBB883ABA8FFCF806FC0C6C0845413E9CF537B9EA775ABEE3EBABDE6ABCC13FB96CEA29598F3C7D04D390E00EA0D4959D7606804FC9D8A23B425EBD6B52A25D40F90C39C6E504CF1AE95C9D9FB20AA085A62D2498DE97A8ECD1B19471281EF6B3F038B72E27D6D52F977822A6F5FB5A104B7A31C97FEE7FDAF0A6B1BED2D45B99DE68430F1F70FECE47BBFCCB016806295562C79E5732F74281FCDFB50EF879BBEBC0C179F710BC1F23C46D66E824B52E33BCE7CCF0DBFA2589C45F25A1FC9AA6CB6834498DD2CBFDB637627E14384543C307D6B8E2BD4C40B53A481035961317013EA693B7364E1E0A8749F2064A3E3267A1453EC2E06A3036F8C929F81D7407C16EBF0C23A54503387B919353971C146A2867824FD9ADDE9FD431CF4123B3476783DA41610D92E00A6327F8B1179E68FD445923D7BA36C6911D8E688BEB85BB669C309042EFC3AE2301D955CC4A9A20AA222E6751CC236DD763E7EE96BF8CF69745E561095BF91030FBDDD7B52449A95F84B498ECBECC9BD2ADD0856600E2BF0C9AE3E5775B7D14ACA9E3620A9C6E021E6B761E81FEFC54458CF9E35EAD42A435B53EECFB55D5D7C0BC9CD8EAB94AE0FDDA9681F1537DA9658924EC63479E2AC14BFCD7732068FD7FE9BF21DCAF07CF1547D4FD953C5DF2B7F96371AA5DCD8D7BBF70011C536C756F1CF713E48AF4B26EBF250B098BFB9609C798EB9C50CE0547570F3C2BA87F601727C58765AF4F6FAACA8E3D5E9023E0EC06AAB7EEB4223B7BB7F10AC7A85CA801A7D3D08AF4B675514AA22A0609A3629E86774B5AAAF727F2952295F1F551811D2DFC3406FC827D7285608EC98709E64C035C407666C0FC9BFC15498635E27130CA79968C98DB66D56655E991B01AC28F7F0601D35FF72FBAA590554BD737CDA89CEAEB62868ACF41AFDEE9182278700D001AEF622D38034545A986B6C4C0E2D24A927473733715BB26913DD5885BD41DE7EB1E345192C1CCBAC7C338D0338DC2E09CE6832F4C8986F8B9B17D35DCCE7EBEC9605A7E9C9BC2738D111D830FA01691389137F6B6B460768295E74F6B403AC069185A9DDE37232811D66D1700284D0924AD7CE7B04DAC59DC63C5D10CEB2FC9413CB1396850B21604A69433D81276C575200AFF0BF9F945301E6E3914B97130CF70BE1ED4B4DDFBC1DDCDFEC1FB222B6842088BD01D55B3C16F50079CB5B8BA79A3DAB68716BD0F36B149C4346E3065621773FF92B8878B07DC262BC7F871B2D7D8E5BB7DF56A6EEA1BC58C0A5108829915B3551C06ED4B138A4689961F545406B1424340353983482583C985C0B7551F875ED3C1DAD5D3D84983957C59EA280E5A7E40F9E5DC3B3EB01767F447D73744D8FB187E1011B8666ED3A2D3E5D77656B0A175F262FE31F0073D793DA85AB72AE22A829D4D003CAD8D4042E199439DA5C726E4CBC1EC08C91D45511F5514C0824C4C0B9BFEFB6619A07C8A8B7B36A69D544A920DC2A44B606CFB1B7A3BDB1393EBCF387CAC69F4389DEF106FFF0079333F87B5494CC07DD174650BDCBC78A1F6DBAB4EDB07D84570EBAD84261379BCF8AC6DD6AF430F12E278898BB9F761D70A9FDF0CFC0C5282441E83F675AB1C5B09978AEFCFB17148852BFF8F6683493EC434A1E3CB7A12C9023CA466F405A17904A92697201A040150134FF3E4A51FF3DACD9C995AD7A3E7B28E150FED275E0B5B85A3F0040FCB8DF911E9DB0469EE62261B37C9ED2B2CCB323421C7293315D26A256C3BA3AAF888F9802CFB8897916D9FFFDE475543E922C453D422FB6D01E85CCCC93E5937BF1B7EAD4EFDB4845F1E087B058078B32A8350D886A9F6253B49E4422A553A4C4920328BF76B91EAD28F546EC79995F95B9EA90CFC924A5A7E3F40051E18AE0A567EC65D3A584719FFB00E011FE0FF303893FC9099EE4E3C57A7912E421F009D487DDBC8155C974D25264AA5079C8210F3649725A53B84AA96100EFEEBA5A136FCA5E5E844FD0902912E30FA4BA04248D279F51C931B46FD5755BE038770E43D7150D46AD91254ED04890B20551C65CA8F6F85122D6487D30B3235C7016785E58DFF1871CF877BB16E1F41FE701324010849C2ED0572D93FE749EC83BB0489EBBB9EA296A9698C26F658E5358DC90EE0C8B417CA534F7346DF43C72E6A3F130EFBC59A1FC7C87AC708DDAF0FE5591691C0F6FF7461DA6297405414F1D46FFCAD090DAC8FD8F885A85367D3C96940C43625CB400D1DAC8A46DD545303A4E5F6A03999FD184959E5A711CE532CE696F736C7AE995FFEBC1D04FEE41C5219867CFE1BE04457A9490D1E7163B1B0D74657BC7D3739FD784BB6C8EE7E8A423D946251A429969CC5D84304D4B51583CD954656A825DAF9D9432BE336349F8E120AF185FA2047A86AE2BF9204A84C911F60EC0CE34A5C80E269866EE50F2E06B7763C3B59CE1A33B47B98168194719CBEC9FD45D506F17C44E191068C85522FC1E42EB6E13CA60C3FD92CA231A50CFEA45F7EAD725360C238FC459ACD83165DAD3E5CD13C9EFE75CAE8F2EABEC4AC72627BB5B56684426382F71D9A8515A8315C49DF85A37E119336443F0A7895D6F0F1A0ADE31C323AC2BA4807AE3621D405BA07B41ABDBF6BC85D19AECBEE393ADD60B4A5822465B3F74932F038266B2CDE24A75F9CBCE420BDAE25894E05225D60F497C086D23FCAC82954F436741C5980ACB58604251A8BD6B5B11FD66EFF46EB828D255A9214E67251D4C34F47083BB9BA1C81D4A1B5677CE87CAB2972018D24901B91C087B935278525844FDF24990BE992E3EE6F276D9D44F48FC0C6D70A597BB604C753274B638AA0D0A93FB09DB78EB1F09C4C13B499838FB7E153239E037C3BDD1A88D18C22A08A5F0BC417820CA58B826E1686B46F11B428562A4986FF371DAA794235E7EBBE02630C18F2042FF10E28933F7A50085F16FD95873C7AE29A1A6AF8C527936BE7EAB1B100761185E6E9582FFDF99FB69EE29EBA98B469A2F449FEA2BC761D18324514185462DCB4DCD7B6B77312F9889FA3560030412524FC6BB4375B64A969D99DFFF1BA067BF07E8FF6DFBA95FF6A88A6518DA65F00D21B59ED6CA97466B62B8F2796DBE7493D5AE30A9D2F1DE18F42187F31708023EF00CF59BA5081D30D703E97732854A4B4D2B6EF9D3FA46641181B36E09E6E2634E96239DD6846C0472EBB3B01BC602A8DA347BC86453E88E6C5D1314441DF73F0A5536B97ABAEE757AD252F0CDA947E44C651D2D533C7340825614B8E7AC39C976346912C7092A20910144AA74E59DA3458B7DB0931371E9089ABE4F4E012A5C6E083DFE384E9D17B2CA55292E0C2D561FBC59E8DA67A49807B32853E4A88F1868AB2ECCAADBC42D11309C74C65A4A6E5926638AC68D449A8A0841FDAF90825D9E3AC114035D5DADC6AA5D22452A0422FE654335ACB09422E78B1D8E9B98F2CBB8AAC467D8EB381C4C0224E28E9055B8E1E0B93ACDF86E2A644113066F5C208403333F118CD223F19E1B6588EFEED9DB0492295B40D9B8B78EDC827AC32A1D09B847AC4241F198AFFCA72679B8A7B06095F85063410EC449A226F651A7FF71BD4C0E785C18D38747A02429132091D67BA0D5D43B416BC342F59FCC17AE429C18753FC75CFDD4F742546D9D0E0B03FAF943A7194EF773EAF3421F7D3997115A0AF3466EE9D4D3AA81569778A37555C85E8643C5140428670420344B6DF2FEEC97F7BFB97151A7ACA6F9C66C506826F7CF77E792DD44360805E60E042DC240F18E46F5ED97DBE86DB09B3B66204B82C54EF014EF4D2925416FD711FD4E9BF41740A088C503C9F42F0367820182B8505D1C727212076FB00682406C0679680D26D9DA0F838214B6C26AB4F832020033F367680A5D619A3B008F49636A84517A29D6E8E74FC57E9A653102FC92E0C6A2C4E85129E355F661FE80F2FD2CBC75C37D0FA964D60F0AEA0A4466F01CF8F81AC7D6BEA83812E25B2703552E4F36F9FA535DFBE4B310626BC88DF1DDAA51CB5FF2F0B1F227C7D6977ED474EF70F40EF0CEC8B6D2EF1EEDF4D04F885370DE87F1710B604FEBDE772F0AC873A20BFF82F05F743B97AE5575BFAB8C1E921D60665785F504AD3C9A37AB78A59A2685CE33ACC30681D4180D364B4375711C311793941CCCCEAE68ED97D6A956383FC936C2C092941C954B579A3D491CFCF4B09394B59FB7FEE534B7672BA308A2229630FB6493EFA86A7B45959FEBDAC948B8DB9C28A234E03E73B0E303430B600F6E7D6691F26E259562F40C2FA0562797D459725A24D868767B94D196F5C0B518F6B35BF85916B1486A595969A5DCFF975A7A0333B35C284E668EB489DE5A8B1A861BEBE314ED0C4C104F947A3A7FEF2BC2CB248BDBC2B67329CE527993A6714E1FB6C0E1DF24EE45DD779E3C73F76476810E3B9E3FF5A7ABFFB474F4CABC79F22815EFB7CDC352448EA48D1EA0B32D81B42B15A8350611689664B5A6C339878F38A28FFD2C5C2F3D9B6DD7DDBB67037594541735AF048F3FA249CBA80BA3B13D236708F4438E37CD6A973FF1752CA764707A17DC9C7DFEE41E9A7D0066B571A6A5F63281CF8349E26A51B8EB7D3908699816855D8A02645949E4D91C3AF4395A4A14A456D052713F9BB497C9DBD5F5749AA47977F2D7AD075C81A438DF9737FC42DC252D9A1B171F13ECE8F6055B50C31FAC8FC791285B95058DF386DC747E5C93332F55F0F69023515066AE9428AA2246F44219E277E47A8BB78D9A705243549E02F1F82A79DA8140D82B19119D455766C80B20EEECFC9427A91E526A03CCDE7B8E2C209501E9B3DAB8AAE45DAB704EA48D83FC289A9A85C0C62AEF22C9F2817A44A02F42DE0CD8CED8EEC46D5FBD214339FD55B50D60C4FF63342F79B0DB003375356E8AA3864572B214696068DECCBEA88A634968BDF10AB1EC36800DA6354D36BF0EA1FC399BCB07F0DEDBAF3C9FBDDF4E724D5FB987DA47AF56D444CCA0CA8710805D5E878B9E71FC95CFF87596B71BB573C2CE40C0339B25420C2D1DBE5B48320A58BF730BAF3C8761273CCA5206432BBBA20BD7ED757C2B129A43B103A4FFC05D4BB32C83A40B8B17B2ED9C44136E87630F38F97AC736E1190916D55662D494DEB80ED07D0E04BE6CE053BC209650240EB6442DBECAD250A4200F7F7B4BFE2A6BFCFDB18CD240A8CD044C9D93D0CD6D72CFB508F72FFEB82A39E145C6C5FC32D4A659CBFCEB03C9A41231B304619470D748DB5ED6944833536C0D9AB20301F41E8797604F91D6ADFEAAC3AF5FA796FE1E162B69C34F8199621243E0CDE4D5728945B8223F52A161EF4C1F35F3FF0A33195FEC852B79D1BEC30B81D3CC49DAA2117389590ECCAB5F74AC460C053026BC0201C3A06041A50842614D0504EA9C24021DA612B6CA156E85BC3E2DEFFBFF64D1F1D45155164E12E95BD60BE04C04A82A022CDB9B3E58F7827C0963A400B9FD19C8B4DFC5F0FCC939A310184E35F254CEE91959654909687242F0728CB6F9BBF547CE8EE5754D0CAF6B80BB21BC6F88FE0E6A3D7C8E779B9F67529246B39912771CAA43DF90959F1FC3B1E86DFAE082C2CBA827C4A144F07DEE4964EB4034189BDD8DA84A1BCCE79CAF762892E00531904FEE24E5C6AFD51ACB022981EA8E12F5B13544EACDBBCED5DDA43E99088A8EE25674A0CE3066AB4F9688D13FD664D8038325739CC7B5451B619C267BA03A007B1375FB8444AE00F3A927716FEF16C42FF35F33906917A34F02E0896AB554D91E6E95B4941EDC0A8AC1C73B3F0BC1957ACC418260AAADA4DB399677B42FB8FCD3FAF3C1910A155297EF481C65A8522395ABD32CD5C6960D3A13428CBFE2A6BE613C7970479D4727044C05BAF5B86117B4EBAA119D416F359789C4568E7311BABC005A29323BDEE93253F0802AA82693191CF3DE5185AA36BB865E3613202AE65513590C543180B7131E0472B8166B0C27831BCA5A6ABA0562E7CE486E2005A635E9D453BA88F6BA14E00050FBA03D6B3339FCA0EFE641FF2BB2F524724B815A9CF06B76F0CFC624D4B627C9338C6E87BC725723B4189048277E1F5D0F6BA0276152708C7DEC61EA90CD8DFE79BD48886CDAD03DFC80E3FD2EFA3FDD94028ABA7E38A2EA6498983E0A61F11A2C17F0B6C810DDF7D1AA556939F6B13F8A7E9521F777DCF86791F7384C1857DA2C24388B9CDEC0691C2BDEF4EEFB073F1C791ACF263293E99D2464E6D5E98B0F837463AB792A874DDFFFEDB1DAAE0B1A373FCC991F7950CA6DEA39DD047A6FA8AD2E850C307FCDBA178A0B1C76494AE14BB1BA078D30AB1C855A47F09B698BCB39FA3711F86B511D2AD85809A99A882F4E0C5DAD328B849AB2BE4A154EBBBF9DA3F7E11074D82EE5A935D2553E80DAB1158A11098515E5201A1D3781E75F59524217DE67045AA2B0942570691BA6DA48F5ADA5A1BE385666ACD755CA440170735263C49912585EDCED4F96F92D4EFFA2E90F3CF61B0F86339D7143DBB9E49466350F4F751A57BA2BC971F4071C6FC440995C4B188F84F53E9E1257DE71E517D7ED5DA26A9FA28052175365F340710B0A0CF4E9E2D2B66E95FB965E1DC3F2E13013B475097907B37F676D55BEF133D02E471D868B4CE2CEADC824C253B09789B48560D636355941522F14490AAA1B6EDC7E103C19F9CA87C71675A422C2DC79C98CFEB41A17EFA592FD6A9622E16CC7A9E441174F0BCEA668A0F0411B60834D811784FF31C14574742CFC121E56439469301F365AAAFE9D197E28D95457640824EEDEB7E221B90AB99A77F3C69D5D30FC3CA9E2F2021416970A46F0DCF679F5D206FB44AD80B7EAA87C0303684C1C57B058501C7078372637B46856E97AA82CDEDE2F572FCE59F0AB13B1AF038201BF991B5474984B4C8B373BF25252543A46762A00F7EAC7AD01235E90A64372DE9C389544203E72AB4E1293CE99BA7B1803750E383CD883B3DB061F08590747A39D38AB94C82D1A3A6CB4C50A9ED077A8FBA70E0BA1223B6BA24A271B009C244DDD24833EB2E698C7223A99FC0ACF56E9F9C00941821FCBE4469AE30591750A5FE0C74DD112CBA3390ED57866123AF77A432D4C94A1C0BEE48CCF72910D5970CAC6A981723202D627E45F003259FB0E2D450C148E041FD47D17A628CD1C1E99E9FC746F6FF824941C697F809AE7118316C0A23A04A17F865283608F16B6729FA80EF81BA0A0F5B9A4DF31102E0044AE4FB939C4340C1AAEA09E563E34AD88709EB660190C0D09CF14FD451DDBB49157B4C83F6BFE36BA9BDBF1BC85D0DAECB96F9930AA20DD1201387B8AF3D553E3BA18BDB4834289268DCD3AF27E09B3BF81A44BAC0A8FBBB391CBB13F9921961404C79AB41FADB78DC89F109AF4054B4DA5174DD5BEC4AD8142A5533893EA9435DF71F49CC93D11E9CD4127FAABD6D8EE9968B65C710E9197E34448EB49B3B14079B979BA26790537B6A4C84C8FB5FD85C45842FD5B0D6077E0EBE041C941077AC54AAB8BBE5547748A7BEB43C5115828A31F03AEA5A237B0841EB0D5F2BE1F82119A9C7D927EBEA569F20A78305A93F1C3EDF1135AEE9A3F42ACF3D01DE0A0227D677857DFD549BCFEC00C4D67B335D139287251230F79A8E2F2F90044F7BB2B6DF66A3F9EC47AF34020D430A2F973F81302D156CEB1CD47EA8804CD77D46D0C029C685B785CC60481DABF36F1467933F276CC1633AC0E6B51125AC9175EDCD010182F549FE2D323AE00D43AC92E6471F0DAE884C5E5BD3B3C544670101AC87FB0250ED28B5F47568297EBFF8F6CC1EE165DCDDAA12B8991072F8E3F3F0850792FFB2410DA3DC4280A59E96E70EB63FCA084402651720C035778480592D82914B9E0E6C6E6E402400DDF32276763EA8C5A5E74D44CBFDE971A55E62673D07D4EF540DE8F3238AD7A1AF98DE13A6528C1FB3EA0DF9A73F6FC6E7400C432F5DDF01943AD9A170600F7F63DD8367ECF77F3EE82BFE4AC08C6E4C055CBCEACBCF1BA620D619D5EDEEBBE3FEF574A41EE9F2E4567CD1150C3DC061F7FCA5556022B61A5D812070F236726C562BD365E0CEA618D7A75569DB1D805551D987BFA66378BA16A520045443DD0ED592EA12C09ABE7392FA92343FF1C8C60A0B6F2D3AB9599EC9DAC6FA4E661F6A45AD16794B71B889B778A8631AB8008FF677997E12DC4412C605968E04078E909ACC4BD58F42F7D02FCE4270BBEE9588380FF2E5B7A1BE3A10095FB1A264747F070D81411B2D62624CB96622D809D548EABC438AC3AD5A8F5E75028BDDBA778A2AEF349D8D0076518DE24F299D54089045891B99F0422FD37C5B8B08F918A4DB334BD39A2FBA1755663B7820DEF21CF45C452DA98D73080E55EAE967A8E98FC101120C3C07C7189AE2DBF220493E66D056667959FB35122064745A7ED34C5098A0A2831727F5182A851FA12BB50CF9F0FD7958E8A5540442070C7A35A0F650B55970EB57C3256C4748C2AB87895551BF8BBA4F2E0671502D85069ADB4D18F628EEA3F50B7DAB9CD369C700A3889340FD50B9E1D3CDEA4A56FEBFCD452B0D709FE77818016D269BA6743E7888D1B09CDEA08DD948CFEEAFDEA23C5611F2750BE5F0AA8B55291B4D9D13A5700FD06DCDE02498C44289C6D1D2AC5A64B4585F5DCAD0A6EFC2778F27FA922DBEC45968E03B7A0DE3594198C37492AC8543820A7E2CADFD13F21D7858E02645D1F0941763908655D83AB0326EE991D3B54AD322E7185A7BF52C93B2DAB6D570FC94BA00E7FF798B3684B6491F239A91CFBC474451510CC5EFAAF5F76301AE956B4E880B8A6D658B2072596C13340027310D5F87B6785F7CFFA67161369FD5D8145A50E69A80D271113F2EC1F1FCD2181182F12177C788243BCB298A39905CA3903EF8D3B2E36B6140D9D9D12534497F3F288E1B44C55CA55ED4F250B6C1D936E17CA0CD2DAAD2A6D02890DE502270037274CE9F1F7E7FB7C48731A22271B6EFEAB0474444D85AA5944073F5FA3E94D6311EAC0C6F2EC72107DFE322496C9F29D90080FAFFDAEAF825DDC19F1646D317B1374DD9C5B66DFEF92F0084F487AF02FA42923F24143567DE7E5557116B37E6CDB9CE01758AC6E84D983C3962BCE092EF4ECE427055D7371896F858F085BDFD0B214A986D541D82CDCC9966BC35C71DB1A2F1139BC29862A4B1934D809C57550B2FCCEF277D8582972EAF3288CA1B91A25ABEEE4DB5DB53EC2C986AE4450A71B325269CF749A5D3840FD85B2A4CB60ED68F772E36D95880FD862C400558FA1882F80FD9A1BD452C93617676E134D8099913688BBAD9440EE36E6D061DF984BD5F8E106769EFCD990830791D025AE7A9CAF55136630959A2D00AF3F6089638B2007C45C9025342156E3BC29DD91793D61160328654AC1243DCE017DB73C2F97206F2624710D4FA7EDEE3EDD810BF0314C1B8DE9F0B1C3E3F2552E9FF4EFB152E3EF85CEE93FD1F864AE1D22E13E44B087D0506BF1C494D99A53F3046297001BB0E07CAE8F10B38C3C745F04043F0527AF994A117EEAFCE5777EF3455F0F7D6E1EE4C4FA4C850F2FD1A65A1A0FA9F98D1ED64A495A83B700C45A6CBC7A854268153B00E0D3AB6AE4E4DE2A658B8625FC5DF7AFB2344C7DC502D02B3E7D377CC383B23ED514EB846453E84C9B92ED32443552609741834CB1DEE08E4D887971C944C947AF0124A15576C44FCB1E24676C83488C99D91C799B29BFBBE03EDB5A9CCCF82C0CF60FB5046268F469513BB17D26A6DFE03E75A763EA4EA98CF6C57E69C297B15D0685030C85576BB050E058CC50E208823EE56036496E89C0FFFD9A2FC10AC8206555613B31F0D410206C0C07E6E1A303D192D9E02004844C641DDAF0CC03F436323546E100DEA1C7093AB085447215D1EFA570483D37B2573F451A391A30200F099385B918E612D091DE5FDC6E79D1A66F14C5A0A426F29B74C347FD922004026E2BE1FA00170E44D6B9BD0060A3FF1B6C727B4E97B264804570C0080EC98109820008328448004C814004A84BC42785E40088041E84E1F787C091303CFF8ADFDDA14640D47740AEE2A7E5D5912246F3376C1223FEF636D51D467860183739F5C49826A06F9719D80BF93C46A3416758885CB3E2EE4EB6FB516961B6274F4DB877B769A93DF645A022C519BEEDD5716D665FF9BAF68EA237672679BC2FF6ACF61CF8E17B626FBA2A11428FD674CC9FC17A7C90B86DC94C8EC23A07E317466FCA54BD6C928A12F26C79384376E57775056147FEC34603D6705EADE8F4F22F36BD0CA014E03078D428D933E00A0485891DD4F7FD74DDE191744F8FB26564A7F9E4012AC65D1CB39F1191C749CD126D4F2F3AF11DD083B304DAB53D1750DD30C6ABD6C60591B4422591AE661B58D1DB9AE881F15F7367B5D55255C71BB7275416EC2A7858F800B03407219183D18001C05F08C2020AAD4280683801AADEEB3F36E8DEB55882C8CC555DED8E66F3970E351819DEB1B7DC556C91474F5C5880ECD9ADD6F8E3F97A9D0E1A5D12E26E5179AFF75F39A8CE732E9CDFDD2772CCC61250248D8903D65156EBB65E45D98B641710C2D494F4B8BBEF7D51C5B59AD1224B1C5CBE04DB7B19C3D669C9E463C0CDA7AE63B947FA13993D850669740C11FC7993920199FD04E56C262F3255AF994ED525B692E25722382737AE969EE462593066DBACEAFA98F48A14DFC572737A3C0476A1636D6C3FC05A820E37025B475C6F9257B34EE9DBAD517D0103567FEDF2FEE37592AD5D8754B0D07658216B36BC2FA6D3DEAB93A5205119A27D1D6A4A6D58D4674EF390DDC4EB4F6F311708E3D7421E0D73E4FFC5387DF7CE65FFC95A1FDC74FBE8FA41A7EFA114255A05189F55B3C839A8D45837F2A6DCF901427A49B578D1173EB9D41C522DF9F108B82302611F0EF0BB22BF95A408B74C4826782BB28D3BA59AE09DA6475C92FFCDC9B16AE747AF9D13293DD78B82061749670AC3901F31EFCE738541A14152DD7E9F79E361DFAEBE6725B99BE7F76F83308EB4B908F2E54B6A25253FDB7D0C68E1F588EFBDC92D35B656F093D789B51FC63C21668574920C675277753DEE391803F835423162DBF0D1F198E7360E6C2139C916B878F85CE81F1300B909463B045534B767BBC3320872B8C39AFC73187B8571FEC0F0BC9175ABFCCEF87BDEB6DDAC2861093E6DB6EEA9C8C8581DEE1B9F161F87DD81A556CB63B9AA0DFEED1ABCB265FC52F686B0292E624E4B2EC7F7A95EA34FAF51DAEC8D7069AAFA78E2F5E82CA2953B3C01A0FD9F7E048AD92147DD990DC1C93DBE026A29429EEA5C189E9336BDEB0C20135E2AC511F81A67D0D2DF9E90DE06558B99C43E20C20B412F6865F4E0160ECC08A109F1AE23A4C9457F4F4FF9DF3143B04E31B9CF56866D213AF86585FBD2F4E3DBF0B4DEF1A750AA37452D1FA690FCE2EBBC58D6FF17BF22E6C23650DE8A7449A95F3173451ACF33EFFC16AA28A47600C155EEFA6F8C2FCF35973CAEA5DC96657D344EAC5801701D35E297FA199E61A81CEF9ABF5CDE2A3360C9CB5899FFCF2DA5B10892E4528939D08F082C370D87652A3F09482005C60C805AADF6CED03CC7F2454167A6D99F1822E17F7AEE649FC597D411376CB3A226094B55339FFFB50F44D2076ED1A2C7B08BDE1F8ACFFD6A58762BD12E0F962757B5F61F56F59BD2BECC2B275458A8F86D5E3508B84AFB509A13F39A82DE32BA84452B5B84724EF3DFFFFC95BEAB10F272B623591CFBB54B103775348B3C6EC309858D6EBC03DA3C446BFEDCE0B25F66D7C4B202091037D26A64289A4D231698A3AE5EBC35996A544EDEF19FE6EFC45D4F8FD51EC2FCDD700CFE476D0FDDB5806C5AB2AEF7AD76B33B67C711E6246E0788D74501179438A8C951B68DEB6ADC6C5174ABBE402490C60BDEA69A55788A3A88BB7939B23CB44B809E98F9EC82ACCE7AD2EB3AC23ED9B1C64C63B232A56D961719222645EC3AEC8E74069F3E1E7E542F5A422446A8639120660CEB3B6B669A98FB24DEB29EC7B6AF5BA3A80AE008607DA23CFF9D798073898461C82C48784F4D346BE541CA4B0BD91B888D872E172838BD44FF25F63FE00202A2A8363B13AA0E10947CA5413EDF7F39F1A19429AA55D02C11FFCF0A47B294D193C906C8F4C3F6FE94BC65DF3F25E039C90FA7B03C5EA5583B04B9358DAF9086C032E1B8B8863576D0CE07E7E6CEE2DE8551B8D2DF820185451AC6A04AE2B4CAF0651C6547D222AD733C9EA40D8381223B1D4BBFA8A12633947C2F0D6ACBC94EEAFC9107C0C04D1CEC61D69AE171BBC1704F805FABA8E346E695BF83A976B817C968CAD52FE2FF06DEF0DA102B891F9C71A4642B5AE61E9D9BF4F912F0EFF4A9EDDF952C55B96FC8D765A98A53825E1B3CE15B2EE2D946C1D68CE9449D6816DC521D8EC935592508D59E9CDCA0559DFF7CBD8229EDE234224F712996198CAE5D2B8A6A45EF135CDF0C39E573A20DCC9164856C9E90E0601E9715A59D78D39CCBC306C8A94184E0E5551F8359253A980A29A7FF16E4C3ECF401390511DB4524BC3DE590B7D16E6443CBA1242DEE99521942CF85F5D302DF9AC5D20FC009A9B1452546A277AEA581647ADF2C2164C19AB175E72B75903ADA44FA96DE7C3F7937A3BE45D32F45A0717AC09609AEBFC264AE68FDBEA409E95AE7D77BDD58AF8628EDF43B44728B8CB71B533C18F0C1F88C6D4430DDEB2972B00160CBFFD9C743FA893911F8B37757E26C3BD864D914A93068183FC4E46E4C174AD08AC59A4585A24F3143B16397B60088AE910D8DE995719B0323F38ECDA1F9F7BD43F056308E430131E4A2134EC05AF16FE5AC0E9AB15AF697F42BEE7A219B2F9A871416591D9D3B7BC26886240A8234EC5259365C52DA7C1EA3B13549C36ACD7BD0B6230183EFB63A16FC1CF308D90C863F0594D9CE66FAF50A5687641395F5A44FDA09E720C65770BD07A9C7F68FA9ABA2ED4902C3B9C4813522D06AB0893F2A3E900F6A216D96F8B05C0BCEF77B61053F6E10DA0094E5935A2FE7EB04987C644AA11F716CC4DF2C2C1040951B47B79E483447E0572F93CE6486CA2A9D8B5653BDF035D31E42B68FDB85387D816DF6B086A0C52C0FD48D690EA847176E66B29CDC36BC392F8DBD9E50925837200B1E5C587F74FE42967DA8C672DD257871A91A6C4D6DA63D278BACAF4746D641CCA1609EB15778120EFBFA55C33200E94EA90AF34AE55563B99F6B3BBFB20AC32AB612F23DE5E29C76C35F5AC01820D3C12EA8750AB9DE80A9A449AA00AB9155FB6DC89CAEF0875C24D73F2014DAC8E496C7229883F6AA6E18086508AA0E8D6DAFD020B6C4A0D3689A8E8C61E15105AC1BC0CFAEE681EB9F8E0F3357440E4748012F7ED037D77D2D69B97C52069CF0E86A8738225FF0966D13B695CE22878A9215341D7E0198826148109E556BD1FFFA190D9046F1F39134C4788B6F535A49EF4B4C222C0A605CE124AA7C386858180D0626254ABD6362611C54936EFE7CBD445168ABDF9C9523566B6F335805DD486C25F0E0A5B1D1E6C7AAAFB6CBFE9AB2F8219D3EE4CF26C99F6805D02A24FDF06BB52C5E69399D16C8BA8FB42710817526712665C3F30134C12DC1A37191DBB0913922AF0E707A5C1EA0BC8F82D8ADF038B44D69A34173081B2477EF2C73BAD67BBF7B778A2109E861197B43703AE31A05C1C80F041DF016506D985DE1BE5AC9A84FD7D1B759ACAD66404E9E94FA3AF214091DF29955E2DFFC4BB002AA7FC10D1E0FFDFA299C60AA6B2F73C00BF6679553A9C4E394DE342DAA5EA00A70B7A23E14985B07AF25098DCD4FC2A877DD6A5026C398A77E84AEDCA310CC4E74DFFDAC88C6FC1928D60FEA036902180281C97EEB92304A0018760C3EB1A056A51CA06489D2BF8579494F2D0C48C68B0D51DC20B57F8B1118903C75009CD1B10AD37EF8F71E750AF74FCCB62067A582963D7552D7B5C9E1CC854EEE5A1532BFED3CE6AE66C0784E5EA8319852573756C647B9098592216EAE071AB3D804183B8CF73031BA0D58DEEBF62BE15E8AB5F1888A3227E73D3E818B4159DED76752081187823E0C64775DF30190433066C82BCC42A9ED3C691D70940A6AF632B732957C6CAC9DB04AF88E7D8A8C7357122F8BB9219FC6B7181E094F8CF30E2F6A2D3D192F04F13F32F11B1B91C02D21984089AEE0A66BEAF8F10787E9C1C284F04E0155CF239363B53F498226601B58185F874D713CAE2C2C6DF05FFBBA1964F6D25A610A08A82371BFF65D18BD84182EC53807F34776518DBA064D884719E55FB71CB468C1D1ED61B3E68CC7DDF1A94B4224F21AB063F3F6BF94DDA70BB8EF3BA09857A5EA61F81DE78E8EAC278F3B337449480B4DE015A8A67BB8400351E9D267D5A6A11B3B44C832EF9AC4FF18815801207E307C5C6C989C9D6A6AFB1D7385B81BED6FB46FA9593FAA9580D414DAC67401DF31BABA78E13BCE434DFDD721EAE95116C06D045EE8068CE081FCFB1390568FC68415A9BC8EC524165887D9469162336ED5FD22DE3BBC9C8885C4AAB10902EE304BCFA88A54DCC9DEB79F550C8B1711F85EA884B3EAB1FE222C19EFA7C9F56F8A7BDD89F2F3FDB2A65C98E3A625BB1939CDE0E6684087CC9E9685D8A72A0B68D8C35F18E0A5D07EB8D8509095332B152C34795E1239518CFF645860D1B69D83415BE2F240A933371D73F2D8B2CF44BF791EF16D92F82E62559317AE1D2B7557BB951DB28300DD973332EFDADE24D0F858E15460C72131C8FF84938CF8D65C4B99430819F42576297BB70DD3944AF9ABCE421D8AB7E408A0F86B5282E58C1B5BE590B646CA8F862C5FE4AD7A1B2B1CC46AD67EA102F045AC9C3B9686F0F8EE27300D3E32365BA2ED01F4DD4CEC0BF2AA40339DC4064291A4CDFFF60857C659341D64059373FAC38CE2797E2E966928FDA05D8698E5115AF1E4D048B12AB62225BB0F10EE25F390E8A4BEA398BEA26645BB6955B5CB88362E80A20C0474BFAFACC59CF7E9A7CFF9A82A2C2FEE9F9FDF09BA9B48F76ACA3960D213B0CEA7ED4E506F18972CA173C0CEA31D1C1C462DD954EC529994AF3FA74737D1529CA22186A65ADB0864C16CB29D412FEA158198991A07F76CB3AAF44A61D719EA90961C0E62569A45A0798FF00057D7363F2B96BE1B587D132A74D4F0A38394C6BC6EB748C80B0D6F44FFBBEFF5AB263DCBDE629DAD713799D3EE29F53E847466A9940C41DDE6453A6146F054A1888F0393601BEF534735175048B1021A20A131152FF1E68D14F7A4FE7A00E5009DC8936E9D505B0313A46D322A361047336631EEA47F49B02329716A6CA374518084BBBAC3A41BBB3F845660186A4C489CA10094AE5D2A96F248A05E49E1894E4C6733FE2FAF8DF0AF15FE9D708980BF402FAA03713039503A41036598DB5FEA9124899FEFF751225E719CF24E1A5AE2CD25EC228F045D5BA7656D455AE6AAE828ABE13E6A912EBFC2315317310DBAF0F71968ABD58BD7BC134F1A269337CADA25C9151B4518DF340BEFA385E23105B385CC28D20DD3B5D7CBA45D7091168BA9E3D10D553A5A743F1DC0A69AFC0DB15088E7672314E67F9FF23A78254FF65B0548DF3E2B11C17ECA9BFCFF735D5D10B485DA8758B3FDEDFC2751462B8B26C6714462726CA904547FA3F7157465FE889BD0B94CB2F13066A2A97498A35F5F22DB8C208425E4DB67FE9627CA71EB68F915CECDA9AB9F1FF756C7533517C1C0C028AD10995B845C6195D53E2BA62DABCDA24DF74F2821D6BEDC12F97E1F4601092A0E0BFDDFA53D591630DDA0B837FABA6EC25F5A4D7B84D54FD19D480FFE3E8855102FDEEC5974BC396561BDF3327B538F00ED97C9F2556A9525DE340BBABF212C70182F9580DB36CAE51EFB587FF265A87FE233F4C91B7086C60CC8676A7C23C510451E959616E36CFF45D9B07B087EE54CD32D5F86B9E5957E66D19A370D8E717D8C19E10CADD50722F3602702D182548B3544117036DC54C77E28E3B0B889FFBBBBD7D149015B55B2450BFB3C9FBC1207F8384684E059138CECB0D2E2DE4A694764C4F7ADC8D9E8207641CDCEABA602F2399C282FA412AF4F42989D082A2F21DF7061EA3992D890A41CCF45B816B1DC62206575A8CFF01B9D552F54667F69B6668351E1CAF1DB6CF0B2E903AC3C39005D431943593A2CBEA7FC685190B1364FA9F1922630CB111E4E7E8F07B02CE8934D12EF59567952830FD9C35763EDCEFE4AFE3B5DDCA95A1183D9F419222558E3E4A057773E874EF2A8328F23B32270150A6BB093DF1F84F0CD4C0E8CF82CF1FD91BF4F1130207B1E61FA778D964CF77FF049814929C01B45D38A4920484A69C76F377D50299BF366AD60E1BDDC3B176AA5EC4CA3F103A183C3916A0E1793F86DF01E4B512AB5955161061428F24E427C8FA4F888911760EC935358E3A92FBA251982A041CE8057603FA6554BB92B65CAED59FB464B373DA2281139AF06CB5F85D205213643D723F9F99BA9762C6B35394C39A34C72B68A14F0121F2B13A5F30B9CC1EAA095AB6A118E2B02B93C7A0F3EBF388D320BC826B89A92498B7C83080357003587573CB9EF43218CA5C118EE74A23A37FDD281A58180AEA5E46F2B30947554DA62F4E3108DB8B2B26FAA4F42BF3FB3ADE3510A0DC87B58F14867BBA46E8257FBF394E1195D19053992B7A3C4C7B0DF3ECC88D8EBBA05E65A977767661B07935E61B164B23065D8FC5CC65EEC55B167974C606C4CA667B40064CC4AB01F59ACC322C77C6FCBB54FFE234D6F46579495D25D6FA3488CAD37BDC37753139A79AC64F8D5E57DB614908FFAB5364684490BAF33BD0439B9ABD24143169FC6E272A677C9F05330FD352FF56109C17582CFF1D5F3741C3C7FC178507077118B12E9BBFC39A5D8BEE9C8FD70227C4FFD4A08C5B77D11C8F3EF0B0357372276EBBD31A6D8BA8F6E22FD29612065A0E4507D5AC84D940A0EEBE4CC3EDD394E9231F44991FF09A55EE71F9805B1301267EC183C1DC0578A44ECC8CEB00BCE32980C6FCA2756F96E0FEE50EF71FFF49C0B6A4BEADB8AD725C10101B95D5B885AC8533DCB445509D98979DF18C180D89B172E72434725DCD14E003D25494A90A2D7AA773148D7A038A3FD1B2639ABD10EC136B209253D3056D20C57400F524A4509BFCD53F04E6F49288169087EFA4979C3BE83C0EFDC4FB0E180040AB8EC9609875D9EDDEF1DB8CF862D79BD14CE25344921711E59750DF72456028DD2E4EC115D900A01A9B4A45D136072F48AC333FDF3A4B895E0CE921AFFFF3EFCD8A3CD8E8000048848403050A48008402909041115A65D64AB824A448D78FFBEA69B2FB04FC10AB5F745E8C45ABD4B85CE371B74D5BD8CDDBC591CA684E46367F05A917B8FFA84384CCC66DEE6A36DC12845D2F5ED58AA798E2BB9923B65984B2401A198B6C95A8033170398286ED4EA130035B4A0FFC00D7736AE8D38C5913B3355046A58BDA11B5036A60C2AB58A15695F0A523C88D6CEDFD4694B0EE58D1B7582173CF2AC4EC91A6CB589F6DBD499F5E2CBD513DFB688AF4DC4EB84B71AC744848A47B85CC3BF65EB383688118E230072E835B8A52F7D30E2B5B7D712604835CBBD80061F9FA9C304380A5D1247C082EF28EEA5CEC91EE39C4F6189821D64A9054B73173ACDA909B3A95B1C19210AC5094E2A59F222F5CBF3AD7E0774F1AC525FFCB66666BD54D378521626883C30C2B7C0CDC3C180FBB08493986F47F2F8E0B583B8FFB1C19567DB6398A4ED9B8EB099126A012052CF0A71D9805D82CD2B890FA29C64EBBDC2CC3848BF7405ECF10B6833BA2CB6C9ADAF99DC5C7AD9160596E3D2746334EC7825000CA273DD7FA71401B275B2D7FB7892E860A98FDC93571CBAE6DC77F341CA75DEC26ABCA402BC59F13C867218E55D71B90C6D35255883E191BAFC686FF6894188DEAF29B03C79C2F97A878E45111B4719D4C670B4F5DFB9D4F6FE2F786077772923A34C856A1B5E61C08E1D2DD3525A7E6AE2517000DF78C6363D6EE124644F3BE8716252AC3EF60CDB61A8BD696C01462690E2680FD1C51E26BE241935BC438BE167548BBC4533535D80355F9A805D0EABE9DD4E5BFE08B50F7128491DF1AD08D610C9256B2F51C9D1EF9B40E834CC3CDE215485B11902D3F08DB2ABA18BADD190530737D97A8A3BAAB94DF2F4849A9290BC95F35EA93F27F5336A0173791EB463D29CBC6D9431008CE360BD43252C254B75801DA7D306BE1AB288D4F72C733662691A0FA1D3B9802FDDB3986E270A41140F314F29F8454FAF3CD1238771A598FA3936CBD774E5A61C3C830B0D0F4961284249DF840698E0C8EBC7C25F825D54305B61EDB73DE37EABE3356EE6DCD0287C0E2F460A54F9089150E1059C524FC206BEC8E52DAA1C7883410345D9F5E12F30307AB9CC31018107F402B81E7E26F2FA572DA1CF2EFF54B274D62DECC61B47890506ABA85BFA5EFB4DEDF2DE4AE0BD765BF2782EDECA4029B52D553C8B1F835917DBC6E0B2608CA2CD4E0E2670992DDFE06515460ECFEF6403B4A29092D878E5CAC33197E739A055D0BC3E9965B494723E2C9BD1B978299861FB7789A83CFE6CE348B4B5A385169449B6E92F5C4CB7E5438FB43D6A04993C4B6D04D02FE1EBBE11C1CD4FCA5417DCDC009726ACCCD137FE5A8CCB0D1E589F2FCF3A62083FD5D503E991E12ADEB4EA504D81254B42596D212704F1305C5FB06E9CB81744B79B8D71A654611B3927A772E61E94770EB4EEDB259F0DAAB2A3593EB0149B0C6E92040DAA8DB716570366210B4963564A932AA42097987ADF470EA325676F27FE4A172D66122E9DDC1E1E0AB7C336A8D4C73928679BCAEFE1216A31BAEFA1AA7CF839BD7298454120967814F9715043E9EB81FA59C754DDF9CD6BA993447CBB0EAC249C76F998FF2BAD1AA97AA71698FF8B12340BDD50A952A9206284BEB61A2C31E273C0C454D6A2CD7A4019C4FFB7EE85497DDDBD4FD42618E0CAB307FB45020987FEB0BE478D9F25D94D2B958CE35A7945AB1E53A6511C66D5C8CAB46D37F0FD807709D7E052A9F42FB4BCABEFA6920BFD3F15C8B72EA70CA238C82DBBA39861D4D803284EDA591E3D3820150219FA101ADCB7B7338A58AF527B84BE468A6AB28EB7DED705DD2B6706D7B6E1E1684A61BC07C8E4D9B1029D5E89E73A5F1FFB4F47609A5FF7D80760CC881363AA8034E8ABC262DF65C1990C9F5BA55A12FB1249C92320E1EE883533D3D1CCA1D6B04290CCE895018BCAB768128971277D91FDB4CC483B7AC17F05871D2112DE22EF8369B401BA28A7395465FED5B06A6980000B6A9E29050727250FE730F2C02809CA33BB71984F6F5918F03CA27B7F67999AAC85DC7B789BCC7BBEF4471A1E1735DE73FE84B115E49A0C6278A7966FE8F9BE693A9F21F8FBD31E32B242ACF94E7E8C428A68CF882D724512C7C994B206B79CAC54F538F4288057494C27F465D5850FC8910CABF20C637B68E00916B56F1036CC516FCB4040344BFA69B9B154D24E0D115A81BBE30007847DD1AE4EF7E8DD027E4BDCF8E3D630FAE6A69306AC417BB661C81A05B8CD4B971B7A0B92697FD2CF3FA3BFCD90029DB9AEB104A84DFC40681CB722BA1EBF62EC509198BD35FB0B7A9E3914A5F296B74F54456BE317DC7127859812D02D725AD756DED3AFBEA536E16912B1B263B6C0EE9E96C402F05EFD7738FC90D171057880D319D16B32DF9F3CF4BDE251EB6520FF1F9BE7A936E2248BC4536D22D862EB0484C033BC14FD58AF5A74B04F36F5B305EEBCADCF2B15750F3BC66763128942005DD6AC6D9927B7F781139EE0B5D9DEF757F6C7DE3F0ACBD5A8392F221F6E5C8C047B84786157FE70FC8F0F8E5EA106CB4023FB44C83AD47046FD65C5399E3994E777CA41FAA182E296FCAF6CD5C9F3F10E6ABFFA9C0CF40F9908297F1DD0293DE5CAFA3A282CF3F0E4ADFC3D55472E5110E21CAED943D09BBEA44F00145FB62D1C36D2389B421BDF45574BED59E46B7AF9D31C8E89208E035E792E052269B4230549123141A1B49F142F90C3B66B31BAC65411CBC516F196C21665AE4EAEE72D451C8FC479E105759318D3F86E0067514C47B043BE40011D39AF4208283DA8DD07828C0B71ABD70E2171746304DDF7562BF53B429D7854B2A1BCD037D259EFEB9DC23C970DEFEE26849A6884411F8F4A47D8AEFDC0F1231445CBCAF74031EC58DBCDCBD49453D56FCFBAD61185AC81145C23D44A5AE0057674C2379F55FDC8D5E7A668751D398AA288CD85CC5A73B556000AFEC2B053617D4684F7F2D008486AD02E44E47379302FE79AD7B900613FCB722530C3F9F96306758EBF9BA8F7E453D180DAA570C2A28900DE46CAFF48A994BBB34FC59C74E97D1CA30CAAE8BB6B694F80A99CD2052F4E17FFA1900BCC861FF30A268F7F6628B1CEE91D7B6ACE451AC548D1E5BA513B8ECDF768F6815EAA7E1D446781A4D768220DB0AC8D4F0735572373539B03D9198F2F28B6F1B4B52094140E652935744DEC2D86871994E975BB790D60929E2590464EC20F54B2FFCBD55DBCDDDA30CA76BDBD699EB4D08C814ACC56A071831BFB86A531C859B25110CC6249F222033A190E2233D782D7B504C2458B7521A251EEA9109011993FADC11A239A9F007CB6581D3E727113746593402320FCFA824498221A4C73D22EF309407070598A2D22020732CFB387269C6A26D4863AA8207F7589BE9F3841D019957BD5D724CBF384F7DFE2055B7A9AE08341A3E5E2220D3F57FFA23E9D813C5C18D4A290CEC474E20FB7B1A0232CDAD99D82473CC195EB7E65AE4C1A76CDC2BCA2F1090E98916821EABD147C524B49E1B85C168BDFAD1828B808CFD57AD03BB279F7F04A6CC323EC28F383057A215019901385BFFF868869EADAC45FA024E9370BA7A772608C8B0A38AD47C56AFA515C0CB7815B61629EE8BE6640464467864C4EDDD37A06CA42A1A34D7DC1CA80F73C7222033F3EDB0D836255F8654EAD26BC03D8D103B0A21190199C2F9F430321D4E12E7F6DFD73A4765DC758BF46408C88CB46B62E718EFE91A3BDA5769470B08F11E1FA1444066006C11646AA056AE98FB12948385B04846BFAC0F0199EDFB1B8A5D9FB1D3738A12C47528C82419511B5208C8AC36F633D0582479CCFA958CAD64C66BBE804E928A80CCD6AEA722A64AAB8A185345FED0ABD64DF47AB15E04640C7350EF1A03302D34BF3A850B644ABC54DEC6321090295F8D2858B718AD904D0F5B6C1D5EAC918EF7A18B804C6AF5ECF430CB80F0277AA4572B121FA0EF594C320232EB3EC1F0680667780D482A76F32BECFFE1F4F27D2220F364FF7B8FFFB60F87720E3001C14E464755FA0AC310A4FB93ED9016B748C8BDD6FFABE9DAF6597B22C84842DBD3B9CDA7EF974DE4673F254E47C6FE592BAFEA45592D508C0938A2BD967B1405C09F413DD0A683FB9DFE3F919D50A29B051B4FCA108171B9A30267983AFF0F985A0A84FCF47C39E067506228B086DBB55C651613EBB4413391D612758648B4EC39679FBE55C91ACC9F28B24154C9B5FEEC3644412CFE3A14F9A9FE9771D129850F89723FE585E47F38CE7C93EF4AD995EBC8800F36D79B93B7B9A1CE08CC118CE65A1AF3646A5D53C3FAE9ACBDF06F12F8AB81136992AD1BB5080BF066D7AB8B5AF4BFBC704C74457855BF02B5CAEEB8B7C67550FE2E6289B26120B54ECC695024A31175769889B30624E9FBAEDAE7395DAE8EDD29E80CE1FAC6451773D57455C58565C2467586C169ED6730EC33986CB37D78B5B184358E9443880F095F9743613AA81D167C7EAA95E0260BA2EEEE28E43845BBDB6ACADA34B80AAE338AFED952FF88AC39C0E7519A314EDD85F3E8268D130E060F4A64F6AAB8EC842514FE889CC0B93AC77CE7C79C3AFDDBF4C598201362237239F07E4C6D8363C10B6340877437DC77CC14F3660BF53FF96A8B3E38CF80522C412E80C3B8F61B143FDBB4900B3563A8BE5706D2A95E8E2E428BE680020724664048AF4EA822FF89CAABA391C1413F4CF66CCFFAF6F12E98258797D9A43218203FA3AA0436AE05BB711EAC6ABE0645109F8FF5CE57F5B46284164BAD386848BFA26BF621D66EF2C641BE2F6C4918A3A4D4E986642E07E7350D7F528510B6402AB61DBE43606642A4CF909C633C1E3047FF81420D6DBD37A64327415E068D89FEB5B560430E48FC80CA8D47C6612EC9892BE880A7793B6C25C607755A7FE91502D799F0A7D2713EDE96B897244AF45FC40A62A8FEDED5A99CE1C494130454B292384F14AEB0BF95F33EB81A8E0B4B3C8C3CC69934D7E81F82D0CADD3D04017A5D72AA02438954EE0361ACD4489AA72011165CABD4A6635D346161B67823596178652E6A3D758704E664C0C78A8088C6A105293C39F7ECD4A6FBB071CCCE905EC48F127515EE88FCDABF4A565180CC95BB22F1FE53EC2D9520E404CF4022E14D89829BE14E53E4952D28EFEA988A8CAE48F7167CAFB4589D49B2721452C1002759C175E415F55AAA453D037895119CBCEDD455C54475ED568C9CECBC2D1D1D3EE7CAB379999A33F34870F0B372B2B3B330199B30B1B372729A9A734A70F159B04B087349B2F14970497118D50093E44D4703E9E850786E7C52277FE41A3372A82B289955425E2BDA871D0112141B4CD9056508A2A27C58C5EEFD1FAF0B4B915E127DF204A16B7080BAFCB427098C7EDF8FD88588B82187843840DAD0CA47DB0E331E15C09C9A4D4DA4496AA4FFF6440BED881B4A94399C5226A9B7F0665BC2F83AAA1A25ABAC422AA75CDC0DBCDA6439AF1C9750490BCAA707DCF07831820C55B020B42269C405FAD90AC29606D6F8FE2B1514565C6066FFB7546159ADDC4ED67172E73A6F2DAB45F9E716EAFAA9FBD727CB154024D2874DA90141574AAC09EB2213E9ADB943B98C88F68E1897BED90A570E29304221AD8142FFE4CDB9A533C14F10528557B5893B564F66395EFF4CB06FE96A25AF4EA04A78C7E6E64F8CB3DFB53B643AFEC91DD305523219FB4C17CA14429596D78A6CEE0E4C700549AE1C52D79573A2120F074753201BB9139729DC20FFF40B90EC57869EB658C3FF9F7652DDFDFD33E1061EEF90A28801514033692FFD180078B2CB74DF319E17A9E677FC73C41211918E7E662102FC4EBD371946973069D1D0962B1EE674AEC45FFFFF200850DF2861A2CDFDBEFB1DA1F1803FAC7213B6317CC413B10D3513AA70BEFCE32B026502BD8BC8CE1D284CB92C78DD9478198B1C6F6BE7AAF4E11923011926CFF3F6EA82F1B708519F6B03369598231FF4B545AC58618E3CA98B2A75889B286837D33A93EF17863545B0E065F8CBF6A9E5012886978BDDB96C3CFB63CC878B434889DFBC139050C6C1B4D6A7497720DAB095155CCAD7B7AE4770F2332AC655CB8E858D800E97862E0CDCE1D3F6D918FE65B63AEFFE7765D9044F9C92BADEE10ED9DD23C557E589647A5C519D6A51A3CA86EB1BFC45B9064545DA96DC71E266859FB9A501692E32EFC08B3618DBDC77468D3639B77FBA1DF3051E37F21CABC20AAECD7F62B7BC80DEEB595F2F9AEF75823505ECA4AB50049799E4DFADBCE349ED1845DD9D2D1B707C3F1DE56A77F227D283F0350EAF0D788CF3D1FC2953A00B05EC046B2FDE551428439563FEF3AFE3792373F3A21950DF4A022310153E16F3BC29006FE4AAFA02A96078E402FCDE0F22A7CC042716361ADAFD640B852332152D07DAC1AE97E918AF8A7EC17A863F2AA1AF37244A6971D89B4B40B5976A9C88317A8136392172D944D10DCBAB962D4EC1CF04AAB43485CDA23154E91ED8C6A3D2EF9482758BBE976C437D07F57A724BE9B90D078F5D3A8FE41B79267427A4BB90D9B0160B8DFD49C542D46ECBC2758A2076934FF17B0DBB9A8275679B6C3934C533F063416E0BFA8F344B5E087D2E0A5335846F3E847F0CC2299DD22B02FEBABFBB0494D07D9391A2890F0601CBCD9FAA33910B1B1E47EE28F50278FCAE8EEFDE06EF7357FCE7D1D56D5AA4485003DBF13B449369941E42CB4D4C49A1BDD122CC2A6B2AA7C659A4BE13B2C2990527DD6104FE3FFD8C4F3F6CDFFA869E903DADCBB0ADC16ADDC01EFCABFFEF87315C8ADC92F37350BB794DCBD1E1D68A8B5AD61CF8ACD50F3BBA511CD5B42F05903797B446A102422A741D58E482880558DCBE22A66F92ECBADDB7B99D1265F531BBE7A838E54921BF9BD9039F43C35AD123F89279238981BA52CC0520E3738B2D99BCB3FD1C33D4A354A126F3EEFE413635FD13343B979160D5E85B6BFBA609E09E3722F17C9766F68E1226AED695767A26827BA969BE63B86E2AAB0ADFF628334E367C1D9A4741648976C515E284A2F7CCFFA2BF19CCD94D0BC087A2E9FD8D6F69E78D80D20F72A6267A253FB949D869278877984AC764E6804C2B528CE9EF9748253C6ACE1DCCCC6D7A7F26F60984695B7AA640CAA4D444382B28AAA7BD82D5C752A10622570491D0E4FFE6847B0126354ADF4B7C4A3741EA5736E7BCE6F1DEDB9F225B1D52148ABE816813B6CB985DA8C371203357E9EE4FDECB26B6BA1998CF065F94ACA582C84B7674DACC895D3107B096A236F238E0BA7BE92B0986E009EE0AEAF3CE59125F17D31996706E62A177A5F109FE8634707FA456B64CA3D6327E9D617CDF3423B184C84B29B4E726438CA0DD559FB5758558A803FB74B7F348A2394AA5FAA597E24E7BD5F146E4A985E46E0BA4C20A634DE69AA1A4EC36A0FD54F710B6B65815696F5878D0A70FFB34FEB2D0FB4EE39A4E5FB35E7F224100B3E8B34865D03CD627D88A088B33660E7DAFA263F0E7E9DF6A9F69EAE2310E67AE7295AEAAA28AA130892CF8984ACD801BD38BA8EF824A6FDBC2EEB8E1E934EAF61258E3124EAC583AC09600A31AA81F4AAD36223B2B8814810579270F3DC01CC805149398C556E6B0D82760804C304CDF7D928738EB7EA6BF460FD0BDF084A8330DFF3905C37B7E5B955FF4A7B0933ACBCAD7AB51AA7F889ED3EAE760C0CEB35D95CE2999B9C3AA9140929E50047747C849809A7DE331F07608E5FFE25B41CD7809540598548393FCC292C1F02DDA1BCFE742867E687F1D4FCAFB82360119B9C26B3DF43CBFDC2A144E1B673663AF7DF464A55E5A28E19A323C3EF50E0A8F0406D2AD484FCF7611980B9015C8D12987CE84A0CDDDADD1B634BE12A2FF183B54AF112AA14D91A0637837CCE960D93836722F3D01B57532B8B4AF487E60DC52E6D21BA5793583B36A5DC3839121F8A5575475FC5333839CB4D63F9D40E39549EA2D6C634CFAC4A5C198DE3A233A3E9EA401DE5819837A3FAE732B753FD2C61A274BF9ECF537E1610E5D5D9C1AC9517C0DA18D56CB2E270E4C3C14533F9105EDECE5A8D4976FAD63D53B047AC842DB0160308F941509C8D6DCE1B23DA473C5C371BBD8EC99CBAC7AA2916579BC3EE5B5D1726A9FB7FC5B93CEBD236A045246DB81D0EF3F72EAE4901AD4942302BA8C73CD7A64BBD688F5FB305A13FC3FEB8C397B523EF34250934E3BD9ADB5686F5ABB771D6EEEDE058D8E8EC091C40B5B7D02B3D3531448F427B9783EC018B1FD8F6289842F100A3C8613504BB4172C3D74A46641E2A7A5DB57E4C16107A0EFC881BAFCDD3042AB722DC63A6B2C30878142ADF8C2DD1D030CB7C8F9E9C46606D9990387E4C09636B86B75684EBCA9420AE2BCB2321B5F3873EF9CBCC51F29049104814D8778A586E70A4CB6F176DC4BC289E706CC5577A0BB1D3FF2BDB60DD0CCB66B071D23EC6243DD9AC604DFE253C0B04C631E892EC6B0E487A4CBD802E52A1B22CE0F09152CA8C15D18E20E9B7F7CC7FB99E376BEAF3EA75A3A8DBAFD6CEC84A04B10C37E3A4317B4EE672A04D5C28CE638942EC3646B37E8189305FEB0C2C0EB9616CD2BF6612B849FAB67CC24C96278CAD30537F170CD7A58D15B5DC9465155357A2FB6E22D5422958D24346EE00B4A6E0BAF701E231AB8A595940A94E52A3F3896FD19CA1865B2A72602F8AD5125568E0BCC90269E90FCF73F37CA1527454D03B352444D02BF19B78C20B72DFBDFC66F1D845EF7A469BF841D2038E35C3ED9D00F4AC8D9619C8523CEE452F298526E3099231FE175A5A02ECC02D9A8571BA2C8848D1944479841E855A12A66289C8FE3DA68F54B2E749D26FCB672942B214BC88B95D3BC02D0575BEB2F4C1A670136D4991F69EBED32BB19DBABC8B2C9B3CFE8B45DF810C07AACF444A022D492C3D56F13064B8813707DBA9DD2801BA6F3B1F3178D347800158EB596777469ADE5D92DC8B3FB02D39AE9C3F5BFF2A9B775442A8FC3D88405AE3FF642CE77C5807A62701FE6F462931656CDA9F3D344F23DE69AC8F7AB5559BE5561251EE477395170FFF575979B21E08503B79178B63CE1E89E11F2845449392D5B5A9BBBFD06B0BF3173325465171212391D03A2EDD1F07BF0EC9B514800AF7411D3EFF10E97986A139B882ADE4B18DE884CC813ED976595A755118D5627148FF4C19A3672D5BAAE399A4389B06418279DBD438B0C8B63D2FD37AA07C62B6B6F52BE1EA4A5DD82263040CCB7F3EEE01912C33B5F346BB182E9987D4D08A592E44A9D824493EF9E5883744DCA94719C402EB2DA98C5172D958A70578BA71C8F6F9F84E40691BDDA2164B544365656A446EF1864CDAA3F1468399B3346E4A63541E8AC8ED114AC205661DE4C919B71491CCD39F3B86631A8A6454259A2D3780E597AB9FC6EB784F3768FDFC9317700D8ADD320C4A19A91C82ECF5106DC9072706F11E9B9A6717A7A6DD7EF85F3DAF8FBB2AD8984BEAD881E64EC7C30DBD7355D237EDD4E38BA555636C10C46A15DE0181CFC792B50E24C60F0FFB754ED00F59A1428B70EAF11573D65B3A42C2DC674426C366DED7E98BFF3B55224FE0DA14859430AD6D1FAB7B37F6AEAECC1647DE0DB68F0E11CFD98B244CE83803A71438659C67A801A449492985487BAB19B221019B9A92571EE55DE13853C2BF5031B123D2FAB8DC4AE5EE7B95D78C15591DE19299BE53B3541251F100A742B71B6889318D11A5A9953419375BC200AB6654EA047290E379FC92444F5960369EDAC9CF7A0D6FF973C0CD3289F362602F41744771CE5E6F3D7E1C366E5855B528B920D0AEA367ACA99E2A346E56C99BF64CB192717608E0B8EEC3CF59B59B90F52716E11FC38C99AD5C383AE471F63A5ADB578F7C8C826FE9BC0EA0F28E14FA13A4D38CA200898EFBCE502952FDB76D829BBD2C61ECCCB8901AE52099E9DFC7705C64E6368F80AC4F05E6627706E128FFD7D563C7B59CD08BEB31298EEB4D2D4B6C999F4588004F0820AEB7928D8280C03DAD1AA9D8A9A362E4D650BA2A8EDA7FC52B4A54FFC0DD84CB7A65F3E2422CA3EABCD18E005967C19CF61CD3762AC5E2632044DA408B94FDCC1B923E8EB72416E4D385CB8065581F240727BE7C2A69D4BACFA96171BBCA85CD150842C6E03A48B35B953B2F37B611D2B9BCF2E7D04F47014444AC688A5EB202E08427AEFFDFA3339DF7CCC3E1D7C943C2C961D59A110246A759FEEFE97194BE1596255DA9FACC5757A1B4098F1E53FD22DB710FA89B36961C221839C4A8F5FBDB284001B17BDBE31C50626562672B2253C79BC731FF68826D4770C733ED51166254317095AC44A39DCC05DBE4FDE1067517715E769A082B021321906075FA59AB082695250EABFFFA339120DDDC548F8050F131E956765589161DD55D69D8FBCF36F4ED964B7BCB4D728127502DF3FBE50D9EFC73F4B4D86AFBC2AA668660AB64DA45EF4190AA54A3B5363E49F792629D64E213D975DDF628E7FCFFEB5FE4716C9950B1350068CEB6C9562106B96A7B182BC650747803BCB1C349CE18BD32AE9262F69558A5D5A988B06C9F948475CA4E0BE986C02251A9A516C5B01690D31F1B81CDB27A9B13C130436396468C908392EB381840486A3AF5946F287E044E5911D918FB143884D98C281F6301D20BFBD0DB8EE79DD153F610667297096D0176D4713536AB2831503FDF3CE30C0189DACE1DC0E66D189DB5BF85E885D738C4B3852DE77E9E19F0E568B944438DC098160F3277C1B3025C1E6709D84E1B7A0FECF0D0EB66B9D2D53FC1EE40E4CA0AAB00359A0CAC32ACACC0C7974DF05899DC75FD2207D26A90564B42898BC210F7BE4D7C5FA463AB16C80B9537A53BF1AAD84AF2614C7EDD99BEC63DFFAAD5BBC0A460DBEC2411A57A9D6953B61CBC333FC5FE87888F42C2FC191A80F9C005668A199B167D429AB6EDA5AC4DE9B52787BB42ACED21FFFA34E76BCC4467E4555C2367D893E14007CCDCD1B4470D1AC076215324D3CABF5171B58C90289FF82C043D22639216A3A043229F582052CB7D9488F780659A0D57F48CC9D81B5C3EB74AE19A0ECD4BA333E6A102B51511E559F6C3756CB986F24610D563EDB707A96C86A436E50F70FAB356B09778F7E1EEFB307C3C31D1ACC3B16964117835D936BB68319E551C7FE37DF5B56F50DA8DA7E36D156916EB36FF5E2DB59F1F5CB32CE1D588DF4D5532FE01FE922B4FA2054CBD9D550029348173CEB657D2EA5BA80B61105542032A97A6DEDA6AEA33858AA991EC0123DA8D250CD4AEBAE8DA7718D81FA4465FA1CB055C4AB9A15D0221708052D141756E6763F26A3DF4D50C3C9CD9A059AA16F53DEFAC65B3778FC356E505A4892A037BE97266402295A47EF8B6895D05066BEC58F13697EE426285324E6E820AB025468C0398057336BFB4EBCAE1CDEE9881EEA66DD9864009C2DD81CB127DD68ED512994FB6C771F5E8557E40475690978C9150721F5D94B7399CA7FEBBD6A279E597100FA4B290A3D86E46A37563F226C642855EE6F7FB407DE276BCA07A95B2EB07424D9BE103BCB8F36D7D4512539C38590CEE39670D551FB875F0D297C7F538E9B4F6C7D819249CAE8B926C4CDFB093F5CFC9D2DB18FEEF61D5873B8A4FAD1A615C36410624590BDBFC6553769E009A432F08103412B52136553FC444E4F9817D75EB6FF544D9BD88F054669BBD4310209ED65DCACB2A239A1EDB071FCC0B3723238ECDAE5B73AA08FD38570C4E7AFD1625492E4F8BC4EF93D72E5385E3FBBC48C29893C41644696B1002220B02989DF01E48E24A543A500902BC60629230040CE84434DF73D00395263E641EF00C89E659A9ECC08005BBE5DEC1C2695F7AA668E2493D49DACB77EBA22A051DF77E9549084A583EEC31C3CC79804AADF1EE96962ABA2FE9AE7837D1CB91367C402EBC62D09D2A2E4DFCFC52F061DC0329F5317A0E0280D47942BC13FD01F63B22493D78FEF24E0E8DC4B7F8ACF39D748CDFE7AEB1051BF67F1A59DD0791FBAE7062820AE00831E6B9A42B13101508B7E737AF703A4FCC9F1AAE6CC5714E0040D2BA546B317B9CB1AFF59D69329BE0E5390AD419A962370E548FAEF5F9DA5C7C0A3111D368EB33EC834BE6738D867C8C000D328854DBACC29CC2EF8F213D15EF581A0056459E1F70090B3144D06CEF62E20C334E8BD6D7978DF512BCB37ED8B06A58A5C71AA8F1250848EDAF8F778E54AB83909369E2AE6B58DAB999F0580FF76EB97125601BCD2E1A98D7000103F07B3782E03E0851C9D8C941D80E7FDC97BB429009EF14B74520B027AF632FDD3285330D6779E7508ADA01ECCD52EE6FEEAA36FE4A8AAD3FE2AB23ADC2C9443B6F66CB9644CE45517205EA1F061CDB36972EF331AB92ECAC1502AB9A0E83B5E9010F6731D25F8C9A28B0E200E327208D17EDDC4B5746D687C68530001EDD2C909565B04D37E02523AF048ABD3C1759A9191AAB5B34D22B3F304856D4950D6210947C19AAC99EF0D259796D24A44EDE137A4BAACAC888DFD549E4B68B6323C10CC003FFD0C8531731F26268BD6F1B05EFF7DDDB172C596A277E7A6770008878E59A1FF5E71ADAE37294E389F365EE922D0B2079C1C87A55D3E79CEDE4707220AC50FA77AEFC18B4DB69C514B096D6F1AB0F00F658974957C4CCB070FFB7C19A1670C690DFDF69010B29687D7F75D4EE515EA3DD19778733F75E4A9B2BB777D7CA38843A867676A09B334C3B0AB28CAFC2357899F9BDBC342A987D549BC2CE09C20F0BFAC5ECDDC272BCF8A79071A8303F4F8247F8CE7C89DFF556BB0B31DA0F1A84D3F394F18AD558D78B9D627BCBCBF874ADD2647A82895589239B21CFD4880B619712C150AB45A8FE6F88D1353BD192A1B72CEBACFA45A038C55B26582D671DEBBB6208932172C26DBA3581B89499706849DAFD608E816AB609B457F1050675130173701E00F77F591ECC65910BD8DED459539D2F63BE80CBF02EAAF7C28B87C9DAA309A972B9FF62E966E6B3558A7DC5D09A573BDFC79F7E0B797EDB59CB4FB15B826BF42228FA1CB854F8277F9B8C59E92A5802AC93ED376015E60182CC27C32F37904A9C1D97CEFB81355285C397BD4DE3ADFF4429530A42500440301410E1444CB17A44C9E63EE2087614B4740E68B43296D35A3BD2D533161010CD6F46CA84A00D8D7BB919A4F3C7EF2326C66B234ECCAE5C88F09A8807EDA2150099781740832E0DFCBDEBFFF4F2B3BF07293494057C743B964B209417BDCB930BC3C573930817A4916AB98DCDB40FABD36C715B9A1FF9D5F52789440CACC04A5CDE634AE2D5EBB60E52C9FD2ABD823407114A63FEEB4173275E7A56231EFB69FB9E73FCC588B167B142DFC977254A88F7424D57C8209027841FDE41B2094B7F0ED900472E5A5473F15B84458F2135E150C53DBA49A83EF263CF196D32579B5E2B2D03568C3544A34BCCC6BEB70317AF4FB7BB6F417C5BF536CF78187A7466A922ECE48441F9E02C078DE97566A01E8B521A3CA33775994A928022C87FB1848F8E56F394B5F5DFE6AA6CC88267F4D7D7DB95BD775152D7D49D6BDD9B7AAF7864EF91AE2532664C7EB3218046A6141797D6735715329E42215925549A4469D098F75FFC714F82F83C6A53C3AA058284EF1467FB5220A4E0B5E96AF427FB9BDF124D4701DE9E8310DFFEA1A198BC9BD306C34EC306071B9DCDC2B69569591B8259B720031905A4D013190BBB7FF7C8756E09F3708413532E9BFCFCE98653F2CF6BE3B60294A0D45576284AA190C0AAC880F6B3D68B31804019EBEFB850BC7389AB4F5035E9569222E3CC48D7288C7CBB3478D3D2CBBD9A58B40113F118E6EBE71F0EAB950DFEFF9CA9927AA3947E18BE72B1E61FEE71389FC4E668DA979BE8BB8AC55B51BC46A4BDE59211B8F7E87089EB58B9B54948C92158572374A9DFBCF081B0E51E7BC5FB956E2AB4C74D0155365C6C9A69232D374F762DB80FC5FD3331FEB1642A0BBD32833C5C9F72AB6D51196CFC453497576057B7E6F7B568075C698215E964017D8E7C0CB8A622A5D19744679E2EA5257750DB06C992E1793ED2DA95F2E9734ACDB516322DE0B4FED4EA2A908D591968685A0315E1F5A9B1AA2A08F855939CF1E5EE08FBF5AF761A19296F23457FF72917622D900769743B30AEA40B970D49701C14536FEC6CA68C4FBB54B4998CBAF8DBD44E82470705F30A09AE6B7F7E411203A460825B7F0FF51EA18296C11BDB63852413328A4EE37E187821BC9CA1D34D94059D61D1583BB40F6018799A270FF3412479E33E397F2C2A58C5B466F7BD5A6D1104AF32E1C4FCAA9CF9EC367DB76515E98CCFB217A52EA869886175A94428CCBFE3F34BA26A9AB84FD9EAAABC42CD96BFC66A332023968D999446FBCC1DBD294FE9DF0AECE2406865F0597079C0E44B320DF0DE0506FBD354D125898A641F1300710FD9B639F43E8A1FA7507A725630247ABE568CDA8244B45DA3FC71C162F20E4D21A565A577F5D48459F265487F7B99DCF734DCFCDC5DC5157364398E59D4DF276D5E03AE0B2BE9B731032D7EDA6E74AFB402DEB02EBE682E558FA44FF031E0ACEE1D7BFE89D632AFD0383786BA5991DD65786B457D1BE8AD8DE5D4C0CA6CC00113084FEAAA227309CAF617E7804A69C3506F4D8304233F9833A6B4FBF5437586E8E867E1CC68B16A10F272832698A4886166411BA01666242D5ED3D4BBBBE6329C1191062FF7C1E4A09F32F6B42C240646424C9FFB7E4BC92164B8D0E3E9F5DFBE7D96FF7D86415C8618C798569A55A51E8BF66516C78B12802B36A620162AA15781653271122BF1ABD8EBE271A3E30C06CAA1E197B6EA8109D3245486D08BC47737C1EA49BAFF4ED6FED25CFA9AEBD267DA4E610F433C6F28722D7EFC59B365C1744FDBB219043FA824CA14E452771B671F23C56C24844EE97542200D67DFECCADB19F629684A5344FE575617763527F93FF09DCCF59CFE505B77420C24028C297D7D4C084A55FEC59EDD17CB845DC83E3D19DF1BF20C158843757E9BA2781C1A827839F8172709AAC32C5C8669ACC5FC30B559B7D0F2B21CDEB97D38064A5612A4816EB30F0D1A685C98673F7720F3A34079FC53E132E9204F04AC9A4909A239CABA09E2B94154BA50A0F4FD60E0F8AC02AB89E914F57DBFBE868EE280F61722F074CD8FEDC56933B10C984EE1CC9A8F67D1DA122344E29DA57D821A5999D909BECB4C526017923CA1C10B4A7650562681A0938F303874AB58899E23377B505E1745E1F452938E763474653E1EC0A9DEF006A5B61965E0E4B2D8185A9E12A0486DDFD95C3C3AEDADFB04B663EFD310FD1116D543D8FEE80AD8D4FC1C74E789ADE68B80F553DE0F7C4C048925BCC5E2BC393C6CB69C7DAB844870A28FC5E5E6FED5B137E7E116A1E8B2F4A8AEEEE97C8EC97F264F9D045FE053086867D8C365297C97FE017DEDF3456CE7B1C0FC87530971968B6F1235146BC39778354E912E62022FC18240B0A6EEC73B7761AD1D29F25A80C6F52D8AA3B3B8C5E4A7F01D503C285B10D7F7FE7751E2A2C6D2324DC9DF3637D1745791D69C9F7EDDFBD8C2204768084438536B43A75D96F46254AC37D4158C7A8E5048C49C72942FDC48FD451D5B50142217D2CB55D7A928C9D9F362178A417EB1A0AE9465510B9452F66A6CAAEF05D4EF85868606B7268800F40DFF881A8E2A1B894763EFA1295C520A542F9A6D32A8DE1CD6DE37A44845AF54CE747347A27D599F2A85E76DC197039CB6BC188845CBC98562D87AA61FD077843DE2D5C28756959C9252851CA0C278F13E7CE0A62BF7535E19E6F186D3150433BFB672C185F8B7A6DF122CA776BD1F690BA7FC93A1180F10658D59331E4CFC846D9338882D1F0EBEB67364BF2751A05150847A1C5B29C635136F446EACFFE21DE721EBA7D08C924B2BEB9281F3BABD97D1B2197070A0759DBFFD9CC56165FEEC09CE87F275FBFB583012E4F41DC8DC20D11A3ECB41DE4B9735A80F579CAF6BC02098A856C41F85D7C1F20C7E6537DBEDE1DCC359EC689DBBE1CAF5ABEE527877D167C15E774574CEEE1F38DE5C59A2F02882B61CF23A7DAA523B0F441409558955CC2B8D24A094AA03A2F8E0667FC928F9DAC08729F7CE11C0A143B469D01746ED45425FB06D557BB82D0313468A844B4DB9358EE0C7724C667DE7645B9B043D43E06EA909D855697D37046F4CB90FA7CDEA67F9EC8CF5FA89B5FE6BF92BF8602B6EC87E956E0DAAA221E729B9D4F1A66AF32343FD9BA3F0CE1026629F4AE069DBA80629795BBCB832B8705BE52279426E2B94F75936C93577C7C0AB3B16A5E4EBAA6AE97FC4E9108310E45DD468067A878473CB591EF375986F1751B6C3BAA7C5EA43D1C7EFAC68BD1C7B2804F1668197DFB69B8E8A0CFABAEE0C4AEC2937E54DF7404C02CE131C29BCB15E2B730FD3D23EB4C9979626BDB34CCFDAEEB34A332992D1C325DA9AD0E5315FA087C89B18977D5D1292778A30A116F40D4591DC739168CF840BAB6554DC277BA194025A0542E87E7B711E60A81CCC0A3AEEA96E253833DA64EBD041EC3C436FE99C93DB9D9EE0D4401EDA26E5F89C66A64BA5E889B9A647CB5A9E3A2FF9B7EAA09D48CE49F111AE2CC15A2F61003E92659CBC0EBC52AE5C2931F6C85325A9844D853AAAD095CDA8F0C8B7750983F7BED3EA044602ABE906F5D592BB195CB063D1CE45B742B0A0F61FFF942B778CA1866B56C2C51428B30A89E666D7F99C1345251909D941C91ACF18049A95FFDFB1F551DD4B61C9B281EE81B3AA86ABBC8B9169A79BB8D5B2598DB4B854A3464EB3AC620852E6E92365F876D053869930732A8E9562644A3D5C5EABC50A6EF131D26375CE9BDD4973B2DB641FE47A45013C70CF316A6EC2AE764192CFCED108FF04CCA63ACF4FB78A854F9A309C6BEA19DA12E6ED1CE963AC22E347389D75C40C707DC0B3025C136C584E6977921560DB53B4654F180E7F1CB21807C469846D005A2551F20082E7432B84C30030C8624C476B742D04A6BCF5C72C9F68462BE997F436DB4D53E4653D9E8E865A00BB32ADE3C292FD1DA33964A9E40F540494F7464112846CFBB37E9665D13327E6ECF460DA201E17D54F20675AA6CE4AD78E80230C85F07BA30F0E07011D81EE9A92DB87C7A3C4A8195E16CE7D26E4AEE96AE5B994C41A5ABACE7D06C24C69C4110E042A647C398245E6206DD04FEC203429CE3AAA81B2C87F92C89B1C4E7772DC907550DF8329A57027D1781B6DAA84325AE3A3F05165ABDA9C9631107BE8C4B979A64ADCF9A2CE51251BF0E4F7FCB8EEF65F9BE91858A214B2EDB79B121CF0947CC6C28A23641FAA16A443982340B26C5BB454D43261DC6DBF7AA59AE7EBEE2D3C4301A98D695E44029E690EEFD9B7092992592A551E38C150BE9CE6AAD53226FC6962CA79A1107DB1B2D5A4BBFB5E081ACD5E0F5FE8979401C653808D9B11D7BEBD1298DADF604C14297F8ED544A515452FE17545C43465CAF38B38A70529CE4D89156F257DE757E13FED09B8766CF717B7263B5119DC42F92E182D673A9C1021D9C0C931E5C170502EC6686C63F78DDF9FDB89BCAEA5D5042B0B9CFD2F43C7738DDEBEAB0304B91A131279F7F7DB2136234D3A487993F015E600480E6FBEC226AD259ED0805BA503C24E10BA29CAC4D514E79C971FF9CE1472191A4ED3318ECEBA1099445AE84BC4A8CEA23C1F9865561B39F3B823FD696F2A8F3A9A9824AC763F2B303A5EB57C3E83A3C4DC393AE6190F6214E7A21DD881E44C3BF9EE592F9A854E26F01E427F6FFECED2E24330CF6FE683994811098B67A0A9642FEEE3AF11104F0846585A8165E4388ABC88B96BCD9877046E8A42EA28273A4B7A60274E000B1FF8FDAC0F3ACFBB5FFF1D63D74184730566E8F4D1D283E92F8CE56FE84B2471813FA9890239D89032C3871B5C912C07AA8AE03872BDB984477B09F900FBE48C7E5EB8FE35B452F931B7E59C13D619D7857D0D1102704F5F03FA837A7A8A8540D7F0F0E3B855CC84D29B112BA726A11E1D17E62E701B7D6E95F7711180513098D0352ADDCDA190B974A17F78A9613D3A0A844AD21F238D1E771A413EB25D88C3AAB3E5E05C705EC76B7D9EA528D1D06972E84414E7FB8D39AFA6DAD3964AD0BAFF7CB8B83D86ADFA40B6FAAF8BDD7F8CD98FDD7BB14AB346CFF069203DD5C8EC811B2DEC694976A7EC097A2631FA602BFDE4139D15A948C5F28BF156F073F455F09ACCFBA19F44EEEF3F0196F8003C137CD0DCB958F8C8DF62D3690BC537B853484E71C68496060E2BD7C5D36ADCB7AD51AABD39750A02490837713BDE92690A710CE10C6A92916FC0CD34AF10EB557721C91A759A4FC564860FB49B7AB9B9B809A44B2CD3A96F68A048AF64DBEDAB577C0482D72817D6FAA03E9C6D7D783048B1F57D20C394A5DDA6FC98CFA4A8A8CFFD012C3D51F3842C36A924716FF53682568E219FE20ADE00E05444C212DF77E0805FD6A302F58685583A1C30D7BEA1F2C9CC81E0D252833604BC57B171F039F3DBD767E8C6583197408F39A22458E4A17E78042D6683DC76FB814393E364E064F73135616A696327315B7C28D31C8C66CCC4214ED937821D57A999F7EE727CD327D099E6A4FE3758DE914551E0CA849F1CF13D2C79EBD117645241BA6F7B454CE3D787E7CA20A1FD1915C5B89B4BEE6DAF043FD1048746D7BE93C396EA3BD97921195D992ED12FBAD33FD0731B380AB875BEA96896C639EC2446D1456CBDE8E7ACACF5D9AABC2698659599FEAE18376B4B327D774DAFE4ADEDA998B0CEAF127C0D0DB8CD222EC1B0EC4573A9564953D742BCD9BD37800A2042D5E3C552AFF61A429C662BC6CC9470EEE6B7A6D0B3D59776A53D156F52E386867BDDA4E2126A634BB2A3B6ACDC2E9DC29692B549175FF4B6563A30D667D611BBA2771A7BDD0A66896786D68B085F919A490ED5B8D87FC673EA28D58919CE1B6958EC22893BEC85338F3C74DCECA70C7E9E3BA514ACA6267D9C155599ADFF3E9A03A11A4E4D24619BA3835528C82340D2C72853C51A69B638DA91F4A82649C9609CD4E0837B5FE42BF2853EEA88FC693D517D0ACFF433EED16599CB498C09302DD19A95055D4C13D96DDFC819DB9D8952122AE6257A078236D95FC746CA29841AE462E7DA565EC0D0C53A2FCBF35AF0CC26CF9A8D1BB5BA61386139B0C7AEFEF0E72B780EBB2BB281889B8309549F356F6F07D013B8CB02FB408F5DAF06A6A11F308BCE1B80240141518BBBF07509649C8F58E559220367E66E260AC4ACC6C094F7A6679A73B5BFAC12841F244F92C1EC7D91FEA931031D75B5B3153741C967D82ACF67E455DE9C6CE1177B9F0B365710388D63D3EEE019F077901F5787FD3AB120087B7502DA1663E11FA210DD2631F52DAAC42F5217CE4E50B06281C6EB1193928FFF4F5076FDB933684C917617DD743BE26CE85B9845B42A839AC670B9A2C193BEEAEE350CE162B439AE171484D508FF75D67A9412985A526666D2133B342BFF1BDEEB60D8B3939F24CCF9DFF9A06C846C514BD8235B3E383907E303CB308DE5D52DF3551C2514B789EEC954C4B74B0D0719523B99682B0435316603BC45A294764524181B5B3E4E53649F6F73E14BDD05E3B558C7760324B1027786DFF9145CB19A0523A9DCB984D47CC0A5548D6D24110007CD1FF282614A2FF88AEEF50DAD26D1F3E739630F8D7419A5B175E1108DFFF0854F45D063940A3F6C934583B4DF4B6D4B6CC644C22FC5D287A66BE6BBEF6FAFAE8006908F596AD390217F634F270887315EB948140703F8830E2E151E9204DA7231A9C267ADDC9D8E2369BC3B6251C948A413B57BE52858213336BAFEBCEEF4220C2065FA4F8DB189BC0356AF472605E077C50AE0A75846A9F095C30F86C0201986F5E21B4C29FC8B91AF41ABB33FE43BDE5B36EA120D963E62B90B43F8713FB9D4632FD6736894110F0DB0AAA4C0764C6C7BF382F215EE91A7C3AC55DC8D9DA66A166D654A9EA5D5913E8DBBC3E8712D6BBEB046D2D1BD8FDC568EEB4674BED04E61F599000604B46BDC85753F3AFC0CF70754AB128D78BA532CD8A11AD933E09D9275A38A745F35AC0D66A9ECC049F982BAF3859B943D98CE6CB991A7C7FC81FB2DCA0CBFD43305539D0D3E5AE8709216134E3417EE1B1DFFE7BEF7631BECDB7BBFB55085385819E36DFDE4576BF80C2E4E0F3252504B61095DB1181D281FFB65A53FBB907512F97CF6B709236604CF893778971BA600BEE5F60D982128B5A49E3B8F73B08C17C1CE32AF039272E2B61B13FF0CD124861589036166D74B50B97A5D3D53AA3EC956652F90899FCFD11053471349A287CD07DDDDE800C61C334EC4E433A41C42570179406C1BE8110061B5287455CE3F415532A5123802604C1251E4A6C30A6FE2C0FCBA38B7EF7259DABEDF3342E87D8B2F2CBDCE559E6E931D87CDAF9F2192A421D55A1542AA372A90C4B50AEFCFBEC308923C95AA53687956A920C61B76A5223BEACB743ECFEC46FE09FF9603482A8CA1784B5771FD2389F03A2EEC6F9E52E117EA25EBA484FE97E8EB58BDFBF6DD8B8DCEFCD072BE350C99AEB603ADDE7CE193169BEF20F6B7978D0955638CA464758F4CE06C81DDF394615BF058725565FC2C265B16D6FB033D6CDCE69A5D7D6BD70B4DE577BD39ED9192234DB68AA9CD64B3212E97A2B59611B8F94F10206BD0079F67C3F392175AC1583C17C325335F14E70A73EDD1C659C47A89C4AF57AE6B6F520BE33940DB5731CFBCA48AC9A7A558F466383E5CD0942B543A0887D072DB733D31A4ECAD9E45039395852C6838AA5859927CAB548B2DDE9FC3443639D85A68719750683F528B9A347776AA6681F1575A61175DAB2B2C2DEBA3D039FC99AB5CAC3A4E9673D5D5546693C8E6D2D2A11C9C7ABB43DEB67AEB654B3A55DDE2B93D55931D686D0C882955E6C214AB2D57A3E6D36EFDFBF7C717139DB25189369841B41CB1AFCE8783396CB72756E157F2A687B5B951FBEEAA5F46486AF4DEFE380962828B606D34E28D82CA9D935461D71C81317F5CF65F86A34A5747C1747D223BA608807731904233F2DA4D26BA7B1BDC6A440FCFFF7F76AF135A33EDB2E94963F116329BF24649D50A57163DF05EA9D984B26FC07C28AAE392D8DC2EAA891DBF7AD75AF530C6268DE8DD6102D173FA7ABAE7B38DC59F6939169FDA472D0613EF6116CE366FCEBFCD98EBBBF2B301E29DF2DC36BE94CE6DD227D4ED7FEEF5712B12EB4A923F3D0CB7147DA6FE725EE0F64D9CE7980AA9316ACA74FFA9905221954C76D30CBE59710640DDDEEDD75E92F23465FE5D439E69651C571DFF9CA0AEE680463DAA3902573A067EB671D9C30888F2D159F093D4BB394182F0B3771C9594490582A8E4A554C1B56A56EEEE0216167FEE9B910553D18B3B896E113611AA730EDC154F9F5A6ACD5B4A6A3A90BB4F6E51F831299BDF5CF5AA5C8E1E36B095845677BE00BB0700404B4B72C093334F823F3607284F29757A8C7216F02167D7DE9CE1438876803FBFA69DE11774BB13F37C0A1752B336F82F496232976F5FD5B31F2F77AAAE11E7E44DCBB45917BC2C9B4292B9C7CC68BFF0A85FA2FE2F9EBF2B128BB0BD6DF9F32D290D7FC71954B8148D6F3ADD887BF81F7FD9AE6A12D6FA74665C5E997A64BD0C2557967E2E43C1445F03DDE5531DD9376EA31B7C0F2FCDD0305D3A949AE70184823132A47049D38B08025DFB10B440E7BFD46E651F562D538CC8F9321C2F0B5A8B31910929F56C696163E78AEE680B7AC578FD19E27DF39C8DC9C8F5F025EE98D8EF03DA4E87A49EC79BF2D3031EF6077F2070653F7B14DD58FED111B0F55BD572AC02549723D485A781A19101C185B22FA7148CB1F3164C1D49243966880431DDA18DBB636E32508A95391E6EB24C7B193FE7FB9BDC7EFB28DB33F683C3F2714D29C184C7791136DA5DF461B43D692F03EEBE9AF04A70F0B6E57BF8680814D58B30C14A7A959870579C887F9788028D7EEC26C966A4AD1D96958B8038FD9EB26AD24923F52FB4D3F547B6A56D9B5A7FD5DF1617B3892C9CBF77B7F7EEE5FB1E7D0DAF157C53315A83D34854B38B960797C59BA6720BE92A7C42A9BB3C52972F93A56169F0D93B046772B0C05532BEFF4B6A158D1D0EE52D814566F98770E19D74C786EDFD7BBFBB0EEC90BCAF8C7C892827BCAF82501A1C82EF908B702DBC2F64314F4399A6670A2A66682574F900E9D63190152D1B2D65A77BB14F7DC9BBDB89E9E0E6F959F53B183F3C2413543D6B230A8C748EEAF340219315019313E887A239AF08B904C56920D5AAC79CF38D879847439AE490AFD731A287D68CD237DD18EB1CD64AA9623FD8808400D2683AA8E01B16982D1B8D6973160DF5CB6B65CA63498BDF0CCD3575BFB27E7A669F71F5CDC7C5A3A5AF2DA82895DC00E498729CA32BEC476EB6CF128E26A396CBF26FBE66CF952924334180A489CC0BBB65AD713A50BB91CD2D179E97BE3763E36F05DB0B78A3411840291A8D8AD5DE87E55E5C487A42F0802A799A0AB4888A0903BAA86C24684621E41B5C368DC225373A83803F67B653D4355A89A86BC4C79860143D04C4143F004D58543013BA3381E54F32BF54D404CB9A6D010462D67B7F9A9ED35A40E7790D6DDCEFAB384B0BC94B11A9C76B569A7D03CA3DC49367BCD830B82A1DF261F8742873F6C2CC83AB683DF3227D767A163CD7DD2AD12EF3652FF1A55F73EA3EB5F856D603C5D2F24A7F7F060304DE480597724E9890179EAAED2F3776F9608F44F2644CEEE7A874BEB950F88851529B844E647F2699328A3F2D9B1F61BE6205F640F9759354374C30B410B928C2AB14030AB1E23DB77783FF623DC5A9E69AED1EDC3722C5A01B1690630295FF77BE6900F3F2E2E8274D52B0ECD101AA0B5B8CF614832B0EB64F447718C464A00DC06627BC5FD0C5292DF6AB01C7B80E4A9A828AD5F558D6016CC227896D7F173336BBEC7239D152F8B79505226D86BC475FF04A51B172FF75AFCD49B188670E75EA34DC0EE6ACFF71E74B45CFB7BA8CA6C001972FD32E2397B3809A7388CD3E991EB48EC9EA3A5F55BE322DD0A30A40DE72EE041173EEF9DD332230E65EB172BDEEAA37849EDA788A76DF838693DD3B200181EF887A8BAE249A028EA19A042ED431E61FF4C21F03EC23D6FAF048F628A47E98448E232C4826669D6369BCA2E863711DE38DA9206C70FEBB406DD1E5F7BBA4C8B12ABA24F1098A4EC507AA855B57037E0798A6C5C55961F9631F0D44B19F55FDAA35C066E4AB50CB70CED42171FCA31603BC7A73CD4A4440479D6B850E81F23DB738909011BD6F819327861DB0A825A29A5E763A543D9721FA52D851F052CAA43BDFD0AA43799969385411F1921D594191A163882B6D36F3DA7216B15787DC17C20DC2FF183088A3B7BA0FF071C6D5E800691FF54FE07F2C92DF6EE8D2C2F0ADAD5F3995AC30176B167F1FEA6CAABA57952F68C5AEB52D24B55FD2CAA0E73C0D7043A00092A15153C41AD7210D2CDBCADE583ADE57618456E0B1C0EADD355FC1ECD771654B1D4C268C89C13AA37BBDCC3A95F56B3211CFA934AC028B6774394415F9CC8B5DC3C32F8BBCA455FC2EF31CF29098F4BE4206399BF2C08EB71999F8EBCDD1ACA8CD1A6B818EB55F9B1AACB15B5EFB69D69C1B47B9BE2A1A748CE70D755C05494795CE4B9056758355F238A5BE74D45A95DCA4CC246CD4B2F683D7C6DE14306865FDFB70C5D9C1AC751C1CBFA39DD01D6E19635EBEDDE94C74054EE87F3B7BC29E0D2C4CD1C311DDB18C2F5BF6CBFD5F96F66489C423B793EDB7146375032457CAE6FE73FEA9384F514C80F5424F95B5A860B4EF3947C5090361B4CF8B1C78D329AE1E485345CD30E1B58F88011BFD8FDAA2CF974FFFC570AEAC1D1A9EB0DDD7ED5303A66D885647375EE616F12EBF5ED29CAEB942E28C3179E4AE5FFC3974FAED52E244BCDF29BD47218CA8DFE7F8CF9717DB16D938DDBECE3D9D26E6719E9C931D5674003472266B5B95D7875FDAEF042CDF490CD3B0A6CC74A72E707186DD32EAACC9EDCCB90918E0527FF918E3FB46BC3DDA6C02BF9D7F95F8A6A4353989B940DF8A705D972608C1D4E057038F058365DB8839C1F8A9DECF2678163FE300EB570DF05CB2AA633E53E87BDFBF9545B5156282D212D70F9DD7AA5FDDBDA5EF0775CC327435DF94547920C79F4E1B5272B373DFDE35C9F2A27208D009F72A339F411DC9BE94E556F78F46EF23FED207D465FBBA94DC09A54F54188AEA5359AAD6B57317971B2992C652D2B1F3D97AAEF409AD7E108D964AB5DA6D092AAF448FB3CD4FE757E72F88407584694F2018D7497E6BA21ECAB6BD491FA3FE032BF2785D153BAFD9D268173CFA10492D601978BB0A9B5C65FF5475DF842DF70C0C4E08770DF11A257CEF3CC9A630ACBD549980BD2E7A88318EE72EA607BFDAB512DA915BE96388C93558EC442A144BE551ADE21F40CC4F869A3231F77917600966D5B0C28956FF95D953CD8FD7D3D98A0161A23412F5045A3F7770FB95BC175D9EA6C5992CB7A47E44846544EC50E54EA4592F55B6B890FC4840DBD7F0C4E71E241141518BBBF3DB607F0C18412378CD5EA0D7E297FFAEA7F105613AD57D1175655E6D1B31AE26027756B207E1FD688C144C315B988B9D7EE487686F7EACD0C5731345EAEEBC9447C2DCF1915AFF20EA69C62F53662EA4462DB57E416AF1467F8191C66A13B8E1BAF2CE80C3A3BAFCB196A192C4082772AF434CC1932F7A0595B38D771275A113012D2A7D1AEA5527B77E48FAFF5DD11B8E23789B128846A54989C363A5EB569FD2CC308A568371B857CB447B55DE549470E9F32A32AD1B08F52D5BBF4AF8D01FEAED439D29D703D6F37AABABB2DAB8D7E6091F62E0EC60CD6C437E424BEE04F573AD150B544C9CCE2477425F002E4B827AE03EC8466F58380FDA52FB6927728FCA456BC9716450CC3A38616A193AD9E1687DE1CE8BA300F1FD02134BE44927195A927AA9BB2A2E9C77966D360BB89784813E15000C9481D6F71B3BF5C0FC019A330C69D9A67480F1C735E62F23CB5247E696E6E1A6AB54140693792A1F268E6D78C8BA0203B10D7FC03467CE22FA2EA68A7E02682D0C85A4A7EFAF567CF8EBA461BB84F7D033428921D08B6CF9811D33BD8B5B298235A65E641D4B6CBCBABDA12D9AF6341FC174A74B7A1EECE1703DA4E68B35CEB60B4CE5DAAF28D2F6F276938F5A126779553A53F1EF1EE98F8294838C615891AAD4C996A63E9F1A84FAC4CA4BABC50EA65CFCDE798ACFB52292F45830990F025EA589164E9EB655006476D4D227054A3E7CFDF20B475DF64B2CC6C4AE8FF2E025E80FFD072814B430E960DD35D1BB13F423049A95EFDA040429284D0EEBF1D621420152D8ADBC34330D9E634BE5D89F42178695E485BCC1F4C6F148797D2601C88BC6E41C7437D52369EB412AF56B43DB898C95FAD956EE609EA69B2EC248B87BA881E9AC4E94AB0CA441806405EDF4F081136E119EE6DD68603C9E517D21D4EFE18812B58AF545FFCACEA47F97D908B0F0B0EC730C60C0F8D54C8BBBECE6553981BD439CF23EBC6F700B46073B156D2E1E97DB35CC5B1A175B40BEB3FA17E1175094B5D69C5325C9024DF02ED2AA7AF4D52D7484EF1BAE5FE6CA8F94D5DA0E6427C25D888873E2A338A36C512317E364533FACE5990BB02D34BC84F36F5F1628AE4BCAD7E3AAC7E7391277432EB7772F653581ADE972F4EF39C028EE7AF8958E5339F4173F56F275B2748E8E2D458DEC19A2C5D55BD91262E86559C1FEACA7C9D6FE9C6BAAEDBF84CC2D21852A1D797B06B7366B6B93FE2CCE87EFC2881BF7A324061EB09CD91847E1E30EF3E197D2756D520C6A543BE77E71862A4516641FD63664A2D65325121142E32526DE6917F698C596A073211CCEF47059CA8B109464EADC533B998C6D4B19B7B745464843DECE74D53471A057303BAD0275CA1547650F4D59E2574167C763CD6481B642C4C0305BB221908BE5E46EFFA5CB32F0C627F6FA5AEE56696C0524D258A54127BB9E5B67B9DB629D793878270530CB53ABC6E7E7C4C309983F12CFA2F7F5772550139721A296810739B42F9E7DB862F40EB2BB75285B6F9CCE958EA7F57C4FC6C9DEB0C3E8D15709584B854767128826A26A7804F9B4E74F904AA6D83C816441CDE24B7C83EC3E9F39A6299EDF16CA6BA6C9985ECED5D0ECA6C00572CC6AC53EC7192A8EF0E5277E89A4304949AB9338178F6E3D659AA7E873BD0A871B28C60FE8FFB7E7615AAD6BB16F10A195078AE12FF44E31E997FE28880F93D7DA182B85EF7D1B39E9E73E02A8FA534E30B1F912EF05348684F4E18DCFAEFC1506A1EA5343FE891DFA499830D2B7217FCBB2888843CCED51A41998046D870AF3C4F36943D83E8A0AFFBEBF54DB7FDE9D60EB1B9EE3EBE4024C6B8B9AAF3DF374982E6D519785BD4C83FAA1D5FA24EAB857FD340B56C3C940456A7CD02935A2CE7219A58F7E534813EFBA844DA82D50996DA48AF2E6CAC73D978416B14CA04B388C1AE795EFE3D68E717765A99AB994B8C25827FC780131BFF1587A54814F7C7C2FA7F91140A510B05FCEC7CD7C84E67B31397A5DD7622F3B9204A6C4BCA0EEEA304800A0D360E645CDCB50245D3F84E806F1A9F3F6C6A7E385A494A6E8571F3532450924AAF958DA5AC9361C88B2E1FE53799961C2BDED38AF16E881E21D319F05CB3AC4484DD1AD481794C73301E908A817707D2EF2C312B1911E74B17BCCC55873ACAE4FDF3791F264E30BB45470C09868451667DF95995A03279F93BD606F565901A6A3C85867649FC289D7ECC4EECD40C7426AC14872E8676DC05E535B5705A663051B13E9AA65A640AC15223D206515576386DCDCD4552E2120A55A355D65C30D5D48A024D48487288503413D9D42572216B04000F0573063A53AD3E5FF4270DC17EE7FFC15283175CBAC9211EAAD192987E57A0EDC0DFA85611D80110561E0D5AC98667E4935F27C162234F0AE1F97439CDD2A3CBC7539673F635B1DDB0C7C05E344B2C154FBE0692DBC326A222E112B1988EF9657A7D80CC2F0F7480E53D86505B28FB23C6C65FA92B5300752500ABE4D461E8D8064BB9E64B111404EF3B5CF09F516A28FA0AD989D9A0A4E4DB1B2B292B39838FEB5DA17655C52D9D2147ADE4C8DA916C88182F7293F9002A84EE5F7498BD4D6AD363675954408DA713AC1F88B44144386D7DAFC1C26964C227A4FF935C97FC9F303161B84587478311FAF76D2159BCD098F801AC5EFA1D9F644BC57CA7D7CD080396339AAA6F270D20D49EE91460FB51EBA67D519F8478C2675A402D57CAEACFA8D2F8009B095AC5958620395801EA9D69EAA1DDB5741B3C332A15C84364450CF496AFCCAAF7BE7BB9283B76CA057681ED0B1BF7543529D365EA1C17847F5378C1BFC22F2F42452BB7EF7BE517080C4FD226836A311C5147ACF1807E8358C0677DFC91F65FF807D501552692B2F7410CCA8E63FB0EB5E743F544F9F876D5E4FEC3C0FB0AFC6F26F7D9975217768B52EFBFBBDB3D5C13E23F3E77C8B9A6250F080786221BC5AB6F2A9962CBDAD9FB3195F7AA7DA3753DE78EE6EEA14ABCB7762BF04711F1BA023A75233578EAA468EC99A9FC8B163CE760FF685BB7D0189A53E2CFA4DC574E5E709293A5BAE95E53154724F4538BFF2B7630972D5A48DC220CF0A08BE56153B9A25AAD865CDD85390BD4B89C569CD35B1654A374975214F37122B940AF4D5BB38847310D48875B5B76DDA1456DBD240A29B061F00DF1B9582BEF81AA7D55F9C0CF202788AEAD7CB9DE739DC5FA29A9D029D61D47299C455752534D6F9A0F32C4C191C0A00E10B88F740E5DFD1114078AADBA91AEE78E26D6B027A9ABABFAE88EBD82EB46FA15E1BD26071F1B0FF9AD4C3139D22584075C705191B3FB3BB4C04E9E3426E212E90056E2B8C559AB4542324AE32F42647027D6E21CD9FB8A0E8B70C049150FB3468217A737C845495BBCA1B193029A7924F721DE4732B88EA4A2C9A476453E7D74B6C32CBEF044B0C5F9E73F25055B114B10E928B9312087173F2E57E0185F999C378A51FD1624DDB2FF90C6FE59C5F215F79AD2DBEAEB112954730EF191958A8D290CB95CEB69883E75DE25B80498A97023FEEBAAACD0BE67CCDC7D0494FF9B269F34FA1430E85729F69E05B496581B71708A31238D4473E1FCDB3A1FD40EEA38F104CD9D9C00418EB6A9DCA80774B5C454372585DA06C0D936C612C6F18390C3EE6A331CC44165526080AAC360B72E5C2D00306AB09C5BCE1F1208D73E4EFC717E30587DC80CE009E17B51975C0F5A70131A87AD55EAD9A7A1D2FFCF0CEF2A09DF7615DC9B02925ECC5E8A19E0BDA75AE5BF4C9B3731B39AFD968894991A9B53DC69D20C6F49A455729DDAD6F0C37A1860BBAC2D97D8EF27AD2FA7FB8FC08FE909B1334C42B0ACA987E43CB65A41DBCCC050016D91983A394EA326D22E2894216D2713B234D915F30148971516ABFA14768629F5747F66A9DEB72C63885D5703ABA6A8146B4059FF0C0CB30E9077C89F5CD559E37F40205CAF8C7F5FDFF9E9EEF3F71DDD3273928EA6DBDBAE8A5787854A7CB8BB3F9C312C80FB8712090EC176A671247A53FF9C5D3A02D73B6A60F3824FB26F971D8D4D7E1846D6237A9A17EC02D8F0CD536C063B6D0FFB306C95F37F2C4CAEA2613B4194277AE3CD2DEDC076D8B2B3038D5176A72DCD962602DDD4990B08BAF5D847809C9FD44DC15339A714CBFB14A0A573D902003DA1D80C9A2532039CB501AFA7EE2F8F63C9F5402B35C8F9E650D5B6F8437A6349125F3C98563FDB9305F99E437D381E37B76484EDF2ADA505005CAA90B14F8639E88442B9F7AF433EFADEE2FC45AFCF6D4EF801C6C0637226D49793E8204FE201EB13FECA22E817654C4AE7E55FAF5A5E40D432D1EB02D68382655B359DAC0A1A1706662CB2B6B904A3790FA510C930039E6766DE0DE3C3DDC7C9C25C5D6AEF98E184A88A8E0C900A1F0E5AB860769ED9F456E7F4DF96ACE68711A1F14DA5B8F60A0E1C6594E4DA69D567814BA98D9BF8FF17527F29259D5D222779362B0AD384D780856EAA6ED7427C9B6B5446D3542FEDD27D6D8B1DF6723E20DAF00579AD7B38FBAB0D92A5EC81E738964381FD56BB9F81E285FA60E7200649176C4E2B075A737F3DA4429F262886F7D9DF22C080ACA424DB35247A26FF229AE0A62DC88203FAD1609079F21290E12FF00D1DE7461D15A6C3A768BA31C67A7186B7B3CD4FDB32BE48B07988D885BAF9060FB63FF4EF15B180195F8F5FB10E07891F806AC98F4FBE1CD1C11457AFFE5006144D00E50587A47D3C8215B31B517B9B839C8EE8006B44E6EDD1ADDF444AF9B84E0E1DA1B8A49E0D3E27F0720599E4D22665F72414E1E335F8F05CDF010A7BD7FD06CDD1A89FF7FA319A094509E2AAA78C5060F71D09F1E56868BD8542FE2BD7489BCF3BC915F15C3455650B82C9301AF415A41381F4100B24C9329123C6F8186E31E7E0EFE21368BC2A8B0CF10F1B409E9BA8186C139E12E19FCDE7A09B41482F35C4365DF38EFAEA7688F50AA559992B34518AEF0465755CFAE2CAD6260A980954973020371E506A7E2CBBB0F1DCE948CCD0CBD30326E0CA33F99C2CBE9D6384E72EFEE2889AD4AB96B6FF7976A257813AB249CE44F79EABB184E84F5C1C0E1A66C92669355B81F23EFE0BB4557268BD9ED878796F390643AD6E5D2BD69B7DAA34303708F923E5A049AC94ED367D6952A9C8CC3AC9400D7B9EE3341009BAA72CBB41278AC8FA3E02FA838DB1AB13FC1C0E7D36AC4324066F9D21925B7CC87039C2E89D6184ED41DEFE78148904B008673C1B9DFA40E01F8AE7F26889C47F732A9986F560B05B81B690ECEC035C840F32155DCFACA1C7EAD6663A0439516E73AEDC3FBED880E87F9E59BF78B2A496EE098141EBDE777C95B93484D3A42765DD873C6B58BF41320F6CA72A74DC8321E954429039CF6B43CD65CC3F039320A8DCEDE72DE3516117F93B7AFA9C499011C1D58EEA8D2EA4CE2C1A3A0CE517C9D1BF677C41D9783D8E1CB5C0AA36885B113FFDD6A4845FD2220B1F7CD5C6F8250CCD2A18896850DBEC80765702C31493C2848547A7CAECD76D931B8ED295EE51419C702A50AB72546BA6F24386878E71E89483352E4E65CA4D9E570856EA17A0200A1D369B737F3DD7323053108139B7883146DA7121AA64647CEB9BB0D35562C4C932EE97519677CB81D3F92A4C583A4C8197EC9A8F1C4CF71FD3A06A5439E61C137A485ACA22080ED481CFB3A0F67AFC9B65A5B4795E17AAF7C70385A0849E17AAB73721E932EB71E5379C1416E9AD3F7F08E492B72DBD68044D5726CF529F6D774437FB427F7F2F085782A051EA882B0FC9EF91EB0F37DE8F17F5ABE2A9A909CED4694C5A0C1807663CCE3EE0099A321FBCD0F43AEE01C975BFE68582D41F3C41DF25F53F9A64FBFD93C5C2BAC2A7D4DA144FD0CF995C3B54B695A7772727413303AF44153FB1793895026D1F2348DE36AB2CA4B8D3901C885A43046E0F9D303E67E98B2E39A66A1C63E12A5BE2C513A16EAF5DC34F23FCC9D466590A95E4D132E61EB894CE5F55593287CDC275CA441E1B95D79C4FD334AEF536AAFFE5E4A8022E7D009FB3A28BE54FA0DBB70F55D5DC88A0A2E67C7AF959571709343EFE619C86F4AD6E67F9ECDA23AEBAFB68C6A6B7FA0F1F851977E174A4EFAFCDD6EBE06B1F1400111072D63DC9CAFF49E39D40CE6D0CA57DC394C80622E290C1BACC1769B951E1285C98D810B253B126063CA5709C5B25A9D0C39439D8FBBCCC14D28234E67EE82684C85149684C3C4845D0FE6ACD3A3AEE6578F802F3CFBEF5511901851E4E6080952B47003A7A43A3F3D2DE30A2FAFD6F4A6E2FBC5E5F69A86355A2C3A94D5E8B8288A0D5FA4F1E73CBEF8C08FB414E7C2A49ED4A6D4010D1CB72182D1B7EB269CFD1D58516FC7F00C4A3F023B9EEC0B8CFFB453D039F4E0F32899465111CB8DDB72112DEE247923F15B739747AA91A693ADFF358F2A59E230D1BA9C9CF84DC12CDDA2B9854D7D10D8347987259940FDB3241DBDD6FF3CD4BAB59FF29F14F2B9EC91774D43143160B5B4158EF8A0EB5E460AF0746D2E29F411080DC42D20224BBB75E98AEADF384B27E7317513B31DD05AFBDFEADAE29556C9C0DF509B89DF835C8690CCFC62604435FC2CBB636220D8F4B5DD5FB4853BB4BD10457B59DB93A117D6DC480F98A5D65B5F27197336DBBE70F9A3CB5FE22717996C80FA67F3679059C7246B99FD6CF6380B9A510F3929C52B4FF4AFC5E2461A9D82BA883F3D791CE90F3F391A9B91EAAC73A694C210EBE45C7909D8A25AAF8A4509FEC2E2891C327EB6FAE247DA43236F26021B49B296CFA128E8C3C11BBDE5AD922242B71D2241F4D2212D32DC4AFD3B76D98C73ADEC021B4EDEE688A3E13E89D7901EA35C5E7AD679D4AFDDD8A6839F282AEB74C7F52588AFED852DD5D38AD67E3DBD881D800159B5381FF760220403DB5A0702003EC0DC0E917279256F549C57588B58D9F77F47A79B7769711C6B4C118D405368601927636B73B477FF510B2A36AD58EFD5D90D3AB5CC100660CE9AADC9FE49A52F114D898001B5F959208D68C6831D72C4F138A83B4A589A246FF5BB365B498A1350F37D4CA43ECEBAE0DDD90F6BEC6F33289BEE7294428CC5F7F59E789B6BD1B50BA76B5BA1CE4B7416DABC15307FC973947CB8F353BA856006709F6B5CE38401665992327DCD5650D3F431FA6A3D672307B68E3AC9E9AD4696AE6927FC0486039D8153966A64DC798FF5FCB42080F9D6B0A008015CA1D0479AB1EA9830B44EC9891180727D11395DFD4E8CC590D0DB10BECD43A7A6C465F6BE3EAB6CB9F05607FC3980ABFB6A8A0656F798A411BC6E462EC9C215CEAFDB7F40431AE686B540DE27D99F5169B7FEE40BFD466F54E49142D0E2DBEB4AB3214E30D26AC66B13906F992CB77132C01255924DDACEA825B7B4BA6E37F74A834E340CF8D020D1BD176C59FCA369E036CE21709A281D9036B8A21BD16C38994BE353DD5B1C7EE564854FFA4EFDB366D0EAB278723ED1D9DA94C3387813C9F6C2FD3F9E4FE3DD6FF24714396B5E378D0E0AC4647B8863E7E4E52AFA2766EC322A63F5C1C656CF277B579C6C74E7F1695966BFEC8CC4ECD0DA8AAA5F5D72EB6BC4EB14D65A0EDA7095AFE3E310EE73859F137A9FE99AF5A0C155904D782C2533F46DDBB16E7E72980AE15A7DDA38BE1889347AAEEBD152A1281ABFF2A122114061ECFEF18788C7229B91ED20CA475A282C2ACA8B4EAFA838079AA7821B97A0E0FA5CCAC06FCF3EF51A2E777E2FF23E6A3B1C412D4BE5772324065AE26AF8201E0DE3FCD082E4E8FA90C16CB7023B2182FB9B29388FEBF8ED44AE117E9016040D4ED3A91A23F889E5E151904610A8209C5C7D46C73672B0A89B84AFD94481C33CC07D36DBDC184098ADB310851855725F953DD4756383FE746A7734CF8B6AEE0198C96100EE549F6F688CBE2EEE48E372AF06F903E70580F6B3F6394F45B71E8C1A2CC612E0022D6D3118DF98D830F0ADFDB7AE4259E118E8FB731EA17365F8487745767E20B1844520AC59AB5B3D763EF13E4F3055C37BA99B6CE1F5CB51AAEBDC91E2578C4617999143EBE93F20CB739867FF12C8070E1D63DA600FC7E7F6DE57861B17F54BE63B377714E6E03FB804818A416E4FFAA3089B29CA07EA430C283CADC169F0431DF4D172546C2BDCFA60C84466B789423291DFCD12802D4EAA3ED0362A59FF68F5BAC4C6A3B2B5DEC6ED6CDC0062AAB53B3B3A5DF5B82DBF191DFA8484FA7CB1B8CC3DC5A9959DEF22EE1CD86F654936509411C435E6EBD3ADC2846F393BE999DA80DD29F984AB18562622805D6BD3307F72A6A89CA96028155850C4F6C73D585E34975E1B913F80EB156770750A4AFBDA1FEAD0AAC6F5B2CF4AB559EAD34E74BE21087399BDD3F8E01C26660CD7F6A0473A7B1FB7F87D6D9BAFB62A0B714616BA19E180FC2622AD21467D79F121880A5B65CCE8C01B948720726DAD61BE40D3C409EEB6079BFA3C7CD2047E7456A5FFDFD3DDC6421B8329335E8F5BC3E1C5F7A565AFB2291770A367F179398F92B4657089A2419F95804692E2BABC94E86285231A5EAA08E95FFB8E5C920A573FD492AE79593DA6541F89DDFF8222A58665B080782FDE10C026564040A1FDD94E3F361B78B4AFDC5B8C64C52FA37C7591C3EA97EDAE05F726E0529C2C760A656CB502E947D975324582E615FA281BA8644888913BA1AF3A9AB70563A6B6B71BB18E1B90B21D0FF8137EFF9C77154FD5EEF140EA456CC56E4E6B9180A473217B791115C87423C36436A91A0F8A7B72B3D4022768AB3C6618CBE4C837C982754035F7176CDF1A4E6EB32B594843350C2C61250B26A80A2111F0CF0EF782CB8F4FC0115A8FDDFB3DF4E1BE6C8375CA6A74D8820F18711BB0B74D498A2016C1E4BB9A8E9C5A956AF8CC982B5B6185138BED21180004B3DEFB0E61751A46B148C286C2395A96E188F770CB974557D7C304CD5931332945CF0A270A01D73A02F0584DB1AC83B45EC2515E838381AAEA03622D34B3B2C6C91A8A97BF410DC7690ADD389B2809BB9E0DD3FF80B6C0A11D06C48EC94BD4116FABD59E836D3946BE54B972D499A6200B533972BE28198130ED401D7DE3C44FE1CEF603ABC80D928D62EC183AD4B511126B3D7B68F8025F00881D95858604EA5CE4453A6D85F75F0D0A789E2E07DEEAC24B3BB5E2DAD24EFCCEB38477EF74173AEFE171E650BABBA36EACC989E3E6914C24996B0BBE96BEE9823C3EA4C608DA776EFF791A534F9D9AD06FF5E3938C08186DFB74863823231D8243E3DB7132DFE7F8E0EA9A2F9EF105FBD317410495BC82D174AAC9FC0171E5FE715ADD588B2849BE4572D6D092FC91E0133E6229445FBA38E63D837C44B45185420248370C70716D12CF68502E9CE29E954CA4D42F14546492ECE08F6FF08BAD4708B8D15A286CD23F7DA7DF59DB0F4051250AF38B2D3DD3EF593FF7698DF706BAA210B5B469E3B32B01AAF61F4D99EB6CA2DE0AFB0F47F7753FFE1107188A35317A819EB6BB8B5615ED8009ACB29FB90BB9713930CFA6E58B1EABBD8DD761BE13DF4160F515B4170149B2C304860582E889D7F728484FB1CB0AB83693C399AB3FF3C81E9D1FA95FE4C153FC8D8BFE337C51E77B5409D3D81242F2F77BE9E99E17CEB8E22E41FFEEC292D907169F27C8355CC5E65AA23B02CE77B46E515A21395FC2058D162E6C11A527598C359E7FC47779751544C845586DF9684BE21601004ACF1FD782D372E0A085F625B22306B454D7D8CD534CEDD814F3495CA6C7FBA63428DF491BDA0C9B3C18C373DF97D275679BBDFE4900454BD0FCB57D16F8611C8BA4D58761BE87755F6BB5A2011B0FAC2DA98928B0E918D80C3AE9E3C0270A041926942D7B17588269A93BC3271D47D77ECE176FD1DE0B697D1AAA293D15992480267FB65FCBBF43C3496229A90378E30107291703860EF02F39CAC80822A3D5CE167EA4750767825014D36C9F522ACA6999B6ECB814958240E6A19E9273124ADBFD6816D57C64B2359B22D58E6942219CEA6B69803E9D3287E14733DE39B7DB782AA309725D77C34BE305190767A4993FEA32BFA5786CF08799C4D302B4B5C36D5417EF207FC0EBA0D252D4E608B68288063F65377180A55A3D5CC08C6BC671299324109C5C465480BC9FA8D0A6BF6E501A743C5D8A30D0C026129B27BF96C2C948A27C88947B867CE202F91AC3D9AB61E5F02AE62EAD1F9E1FED5D6215599836093B05C9C1F43068BF155C4E0D62D8DACB0F2481CE1C7C5F5486665937014B2A0A21410D54BE41B2FDC53750A5314C65F2C881DDFFE8991FB15EF0224C17CA1D7885DDE4E7F40584C865A5D2B2750AD04FD469373B39B5E6B40904DA614AEE059246198A586EA3E341C02ED527B0C1794B86E175C9F5C6B9245ED967C5FEBE08074EA57277699EDC964061811C59048F334B9FF95425C9079117BF29475AEBDB3A4441D24D8762C68C2D5D405C3FEA1B8CF34F053147A188FA3F6AD7389A443517CF3669C00100EFDFF1DD3630CF233A0F29D6F6C11774A9629082B5244E730C2BEC70D9D83C2DB1028AE06F81BE44B74B81E2C5C40A7F3B0E121B1B54D07DBD3A273D213B44494F1DB6F87F2EB806359AE406AC169D3370CD6BE34EE7F7A4D5B3DD3BEFDD373F6C4BE9877329B3665145497D445B215BF25916A2CE01D9ABABA5B843C96735702E80B8BC542B0CC93EDAD5E92BB87C0095C2BDBF0C9A25F9E97F23EC97A730BCF030CDB95C32DAD425877B8AFE012D88E31DA6A759BBB8EFA63DEE6E0F22DAD7AD2EF8B17B185062ADAA4607DB9689DC1B956F8C36F113B06C784AE4CB577408141FD1AE4C04E1F3A2268B63A15AEE0B2A20CDD1D2B4F3973A57F6EA0EAD46F36C0D95C7EEDC2AA5AED859B6F176195D6F8AF91C61AD7E93AA1B08A4129ED8A983A917C5CE9DE60663A1FA50D27FDCAE6F145D58B1FEE75B956DABE2ABE2F3BEDA971C1696C18421E15E79A0BE684325121ABE2961AE6EDDB2D93373BA335ADDB3643E0BDE3314EE774F37CAA41BAA860F35AEFD753FD489CE0FF4955AB8DCD95B6CE4C6DD37DA165CEBC1D9F586A547E68428D90E037F44279CF8F6AA2DFDBB940E384614A8665FE9B19193DB6AEDFE0E4E57E6E9EE53B0D1E0CAC4447B43BC16B2C4C2275389073119D1AACCDC561D42F69B4D775474D89BCD3E6904ECCA3DE5341E7412FB25FAFB34B2BB0B0AFCE55B34486B920655966610F20805819A8679F36DF1B4197831432A04580E66B1039D866C2E961CAFF5240877704643A44E6EBCFA3BC3E1A4C3BDF3F8D6398E8E0A2A3676080002517C1F7EAA16CE43CE8533FC099093DD4281B7F96A0658B4F6B8ACC4F2B693FB8D184A764C459250E215243940B2E51F3FCE66D0A1D44573A217DF8DBAF776B1257915724119BAD194CCE5178476B6251C44B3E0802F022696804A66D5758EE5D737933E663AAE83C6DE890C278C73AD7A4CEE48C07A0ACDE2E7FFE5B183951BB2BCD8B8338454E1DE497702AE2252270F565A39CE91D7611A4025CDECC81031FD035A6139F491BAFA85D99B127996482CA189CAEEC38919B3E5BE4A2818A72A3390BC5289AB0E0253442086445CE3B010E2F47116477974966EF13EAB392F42347FAA3DCA6EB2C91F31A2F8375C19DD1168711F9078B51F1144B425F2995B25B1D9BC84280FFFF58F8D8A657900B7EE15C2744FE4B13BEA211D1A09D5F0830489C07D3E3257688C9FF06CA60D4EE75516FD2CC526BA177150357F4C71672BE19D8418995E6630197603BF09EEB0BACDFD144F7E3FF4267FDEAE0BF39061B7AD99ED70DA2E8893A1E82419BF0C8BEAC4778032E727521C288B6FF492A838A4E19F0C3CEFBC4F7A8C469DE7242FB4031B15872B7789460360921413F8CB1DF424F4ED1FB810F2E30082227562B9153D7E24012E72F2592460C0050E43BDFB50809DD44F1973B3350A627948BF9B61F3A8CF6414A95EBE19512C647DD25C80718A837450AAC6053F002FC2655607FF361374DA1004E8A45CCD750F24EB592FA8C8E0EA0AA941FEF819F8122A1F0FF74D51246E899F07304AF16894167E21B004802F43177BD5649760B5044197EB66ACD17105CED5F9DCD38E7144A797AA20625B3BF87213704E1057F9A1B01406DCAB6647AFACA9CA4D456E2D2B9FCC29B3AEB7D288B96261820A140A10048805920B8161D6FB0BF18BBC3C6E7167709AE69BBB5DAA9CEFD83A4A837BB5F893FB9D049B81326FDAAEE9B46224C642776437928F80844993768916A4C0C9FFC828EECAD958BD6553703DCB3D62C887446A6BA88EB82C520F7515C4EEB15FF88770A013454CDA0B6253B30BE99C78C55F391C9B78198217B7C4B377F200C5DAF06F290A58F489458DF6C4D86674C7874B11023C7BF25858AA1B85906D010C572C7CE874FB54F7510CC31852C485EE628478FFB8348544C423E757AB55D9300B9A6F8C4D5D58536D4D2F7F095BF3E2B77AD3B2FC3CBFA4401F6AA84D5EAD91D7F1E86B07CB03139CD5525F86E49F2F521C5866B0BB2089EA20A21FB5F4315B72CDB15B4C6CBFCABF9EA6444AFC921C831D61072793E0975E845CA863362BBD7FFEC927B1CE48FFB535DF74E3667D3C9DEE242D61CD1148060F24F97795E47BCA16D4DEB5FF26252A8CD5F09B430F4F8334C7CBC02EAB3C3B340E23F6A2D1D4C10B376BAEB82169C5DAC3D7FDD5BF5624D4ABE47BD1227D4408FA1A7E69305C384C13F571909A290CA03DFD502BEB3A71CF47BA76E514121A630674CA252C080EBFDFF8355E762B434A92913141E46212865A729377465C6D54BA32B45290A83E978172B8946174189F77E4C3BFD2926B93325519B31A7731126555EDDFD59135B5411D0A948158847A941955F3C977797E2694907B7E73A496DBE417299C5B74E75F97F0E3A181973ACBA82E2D705E8122A76CEB5257D9133542E49A17CB473C4A8835716D59821C1D9718B5385F6128A63DBB388C7F3DDD991DC5E857F38F3553FB2E0D82D63F4CFE9DCCCD5D6D0782D82FE42B96F90CD9BD1E07313DC761BFE0917BBB41DFFA075E47612F68E63D0F0EE0E1D6CED189EA5B18E55256E518D1A983F9C39801AD506779FE9BF67F615C8F29BEE2D707185503033B8EBE3AFDC128ED91027272B2B4A5BAEDE9C2F7C19AA804B990EA66B9329A1B4612CADC239F67A9A1B3F3CB6BEE580E9E73445E5937B41425468FAC96DDD17491A58F737822F5BEB98D5D9E7A1A64F5153909A0F590A1073623DFDCC2895E9F27E98FF4CF2D97C5A10541CAECECFC9D44164561F116887E6A245DA0DEF2FD3AB745B6E677169541E420C40FBD7374FB2F3877E9942BF22CF8604098A357459FF6E376A6F847CC4E7D179185A49263F570AE59F0F5F36614CA12D098F54D90DB516881DDFED908E76DB1668696AC958A718EBAE5DCEDF7E122CE02B6B9623EECEA86D4FD6F24B22D7C4214D5F83FD689488F8F139FB5288D3517DE5A96374D1B9911A7856EBA1ED6A258F926EA23EACBE57DE93E9BFDF1CAAB3A3D0A04D0B7B949E63FB441F187C0FB0184319AA6B7EFFF771829EDE363AAB1EEBB8C90AC16F6D0694A4471FBE52FE6F2098B4167F1F6539C51FD4FF3A7CEE78E52181295ACAA47ABF1E6D25444AA07C05E5EC6211B5809D8005B753B13F1804E21A4713227495CC4F2C3E766984B0E7F9BCC6216E904558012A869C1FB2A3364073BE55AF0464D70D0E7B62624EAB8B3C02D6B31252567E3FFF238FCD8C0AD9209F6666DCC9946E0F3925CEE443F75BB506C8DA0CDE2767AD4BA8C7367F056598DB3B0F59AB9150D7BC5FB4B075805996D3DA96708383230CFD67ADC5820BAF5D4832DAD85FBB8BEA46C74B435A53E75995B0F0A7810A76D87E57EE59E8AC35DE70967DAAD57DAF5B7458A4B2EC45CFADC8AA448370A9E8E90610897DC239BFF7535F37BEFE476ACA89A783201317DAD69CE0C19D3706D398ADC211E1F78C39A67856543EE6201950799C7287ED6BF613B16D47200E1F91309A571024DBE07945D49E413599B7F6D30D75B9595F620839F38690C6C6E08C11D9DD7C158A6B82A1D4510716950A6800F138EE8D4E3F9DCF3901998BD7C9F1C8DF8C8B48553996CFD49DCC7957174C23BD69EAC2FED952031AEA9D6DAE4EFB697F9D4778B1CCAAC6EE3E9255C5306260C2F5021B82F389D44CA7A0C9512889BFB72013153C75F79D378E98B53C08502022BC463C2FA3A7CDE656E87696098C85DB39ADC19AB45FF3774C53BDFEC3606EFD552BE81618D53C660B17308C47F3641F0ECFE573E68343C951551D4D4763E93543928629D54AFD51E10B41182465D960A8444BED0DCF185F24248121F8996A7C613228176BA19859C13CB856D01FE38C301435C13C75B82AE5545D7DA52B4D41BF39B9C2D8B1FE23AEFCB55B15FE27666D669DEBBAA3E0BFD0B271FF7A009B52E68F8BB4F812CE81E2FA512D2720F865E3733ABE20AB69081B7B70B445920AA04EC7C4C88D349344376B410B535DCC86426DAD0765A83296D2551AFE53F59F182EABCDEDCB880372C0C4CB581F450B5F436CFE77DB12BA66DB89FAE48AD4D2F364B76C5ED04C739870620D803676665BBA4780601ABA9D32B9FF5F08D13FC6B8640E85A19CA1828979D4000ACD003C0A699B892CFF0390F77FB35CABB5AC3D683204A0CA4413E13080F3ED0D6342D86DEBEBB5CE46D0A26D10B8C5DE7BFC002287D63F1093592FAD085957AD3F8EA9C9459DDAB42219F3C1512B9AB71627A577F0F8BF4267A2E2F1CCD2915F7939526FC6E1C54374A9D8CF9D8CFDEC0762B3A15969806DFB04ABA79A3DD4950E2D7933DB48C25B792600E45CD3069449BAC3D0B0A4CB0E8D6B1B9CB17F6A2C660D871D19281EE2C3C39C62605BEEADD792A76C068639FC7B230C219F196924249F90FC40589AF412F29E29DFC3833BE45BED34CD3680AC183A2BA043205B889CBAE5FCA402A56F0434251F7D234FF3EA743D67372E5B6E39210990E8425855316CF441BB4651286A02FCE5E0CE3FEE70B199C3298DF03D3E7A0A5FC9CD644F0626B905D82E7B1B41B6911786B029A67C0F5064D9B988EFBAF95026C09CE6CB089748B8C4250BA3DC2CD0F8687AC927213EE00B0D73946F366A43F85CA67C775CDA7CBBC736129E76959432BCC7F02E3B97E4BBC2BC9A5E8E55285B5DC3799C15229DC7AE90CD84522A4412A13123A7CA0A9DAEB09A15BEF81E8B848D25A242FAA09F904E3F8E621A3155500FA32A54352698D843C4714F38F3C47529E14C285EF969400878DA627202D3083D9F6EB427936289F40C097B52014F38134ACD59A967202DC4601208A52B240C4C7CE12C094102C3A60F61E7798533AE5C995BEE91E4DB65E4DF2D3A49F93F920779870E19209DB69CCA938798921CDF2F169D58F9D051F28B54169680344AAD1BDC983AB0A38A036E8275969F3A50939934505F731818DE943E7650FB96AEE0DE09C3089F1CF8692BA83CAD6D56F39F343024287DFB5B7F65541A6B1454FA487D6CA7571B77513CE4EFDE4699D6DAB584B345911A118241E5099AC06418C6D6EAD0964BA6B6D588DAE61E6390F78DA7FB90E331A7F2261B4F888090D35208E30DC6EBC8F83456A8A84C64D7FD4A97A8B936B16F38C9F3900050A2D1CDA3782834A8D093FBC56EC3313C979B40CE91A74CA6C6C0A400631EF2221C1EC9EE00CC289C3BA1912CC26868FE037E99DE924AC426096777622A6220000F9603CFFD883178AD09784568580F7CFAB099414EA20312966B312B1DA1D55ED985985B0542DBC0F2095633430001918628E88786667685D3A8A998A7DF05F10A31817880849B9041A2F386271253A9D3B60A51B2276D1609CD9232AA332AE9646ADC2A401B0F091F5ED16B087BFDCF6DB419467F2A385102DCC383EB4AFE19833F942A0803860F3034214B04274AF60B0548915DE4816AE740F560A8390C3547910D5598E0000E2A80A15E293916888EB31AC51C2DEF924AD4D42590D3A3BC4F3EB50B60D085E74251731E351EE7A89A3B6500318B9204881D94A468E10C39A39F1A0C755518075D290FC188C282F163C7839D3D6AA4941CCB11735E6FF23B53432428BB56335FAD96C28E60D88E524DD20D4B481755680E762EF20BC1E674FD2F8B19C3BE4981DB08AB99D79EA48A8C6B0CC7A0FE1031A4A8FACD8CF992AE70FC8E7EC7184E76A06B9413592872BE35AFF164A081A36CD5497CF91236B0445C43E5EF5A695593785BBA8266DCED7DFA469306119614363A7A076A3584CB97478B713FD82F97637A109046C308C596988D9021BA8FE9DE8B89A4F8E7CA9391E20CD1E9E92384AEC286388C0DD18999230955D24D5DC839144C8D8CF1509F0CF567270B920C0B5C25FFE28C14545BEAA8C179E37C0887468051E5EEC2DC48A7A55D7828023C0AF594CA62E45AF47A5069566579F22BC5A4E1EF81878D87ED6D2063E482A291C158686F30AE041E6B945AE157C366F6B6D64223ACF8EB5B3B29ADD0BD5705830B38E11B04F044874C74660777928B307A389583D3E39FD6841C93F7D9606EAA89431341E0A94D4719174EE374D4CC8875A7AA6BFF53674033DC8BD159109EB97266AEAE6A9A9A459F73A6A1DAB2C8D9AA272F17242FE79CB365E7245698637BAE8CEEF0C2AC90050B77414DE69949FFAB97D09086B7C0E4CF8F732D3065E77774EED3F3093E5DF4E14558A9BA7C4CD306EF8842B6E21E965BCBB37FCB770929741575B185250FD4BB96138326A831C5C2DCD874050B7F9D4D872C432BC81B1E85383627A6B32ADD56DF6410F15867958FF2CAFF3CCABB4015222A7BC1B1CD684A9958E3A1EA30567F963AED3291559A994685D5CD127613521ACBC2AA3DA5CC9D9A4E2FFC3469B6204AB3BE7141F46FE0EAE217486BEE263ADAAEA733F375502E9D5956C7A05ADA451912610261A1586F247A55DB3263A69584BE973EC2B5A7A6556F0D636CF878866BDB2A20A6053120AE6D9BD3942CDA14E619B7C238AF0813CB330568FC5FC6B49238E25FB5A44A4717A5661277A79C25EE1C0B15C61EEE98095F229CEBA5D074802DB2C7C722A32492CACBFAEC946866167204985943E08CADE94C9247AC5D37E9F2ACCB10E78EADEBDA6892763AB6953C9B87E990B4ADD436AD0AB6EE82883B9C13B697C4AE48275DC4EE6A275DC41E254917B6E74DECA9BDBD0CD83E61C9CCC07E706C30E7208039381D872CE53012876B230F03476CDF023B1A6A4F013BC6063E5BBF170AD6204EAC820676B26DF8F6FD72E9AB6FF4588B9D69F34C636572D410B7AF73BBEA629746CE159675753CD7E393AE496EB021E713EA35FFF2082556ABBDA46E55DB6D2BD2C591F4C05C77C7EAAE147A94D4E36F7BD23C17C7CA44A49ED9AB4DEA21C675F8D666F0769F8E9FCE0E330431EB0D8ABCAA947758AC57EE1172B13775840864D0B344A413A8BF505983515D7393B3963CAEC8BFF488C79A3D42C1D57B94E4B449998C8B5347BC20DE54751851092E2439E07C8929EF23A7BC443EED9360812CAAB13C0D11105109B307155051857BE9840962985007392A9CA5673CDF98EB23A57C927B7D06A2C31C9A98DB1795A4E7033FB85264FC98E511CAA9667DC9F35BA93FCAFCE59ED0B674C0ED06945C6FEAD608E0CD9120323FC7413628E506DCC26094055BEF088E4C10B89D46EB06FFD51E2D7BA210CC0989EF0D19890E4B50077E28F799D069593529340E7A784F102A794119422C82B649853DA270A56857074754A5FEAF287C83614719088E8A1BEE7C3B518D17B5AFEEF135A5C8009A831E68916855216603D16AB2E4C56099218EA584D989B907B1642BB11D34D64911F28C57CE8DFDD68D935692966C4962AADD463CD3462893806CE33A4742A82A9326CCFD847BDF429048D344B79D5870632A2BF812CBCBA5EACA566D2D3D4C597919720F4F5609E67F2B81D3AB21B5CB85DA6D538E78A07F14E634B3C4ECCAC1ECFB7BB2D1410814A576FBE92094792ABEF453C6486542CFF0CF88ADB8AFBF0DB0444A7DA8EFF9C242F6BBEAA9FF3DAFD2C76FBBE20DAA33CACDF939CA9834ECCA9434F68B99A17A22F3287DA94DF74E29FAA64399331804665EFFAAE60684C977F0F721FB18F1491C4AF6847E672DC23D121048D1BB8721833A5A16EB40E039A797FC9A99C1B48616D95449FAA9FCC1BB41A249F877AE5DA4AF8B2AE4875A9518038E65B9C5A49689C9C0AB1BA28A1CF89F5E9A395DFDB80B71CDA237C2207A8D11FA41DAA2B8530B9E430C31A25B45685207F98B34AAB07EDF49C7104FC01399F22643E8BE4B86DDA6CE14FCCDD02C46D9C6945B9F1F31F287DAE9464D7B837B143D570DFD0E7D7BCBEA4A728F56422FE9FF2F7B2F36C204B0BE7A64A5D3C349C9E2B9D2131DD9A94174ECD5F478EBDB73D32BE51D09B3BAC32E8F9F369D682304F732744B46B107933CFB213D02F15DD2AECEA658A6CD9070C2638271DFC6BD4E0AC9C81A93AF06C937D5E2A3715D573BBAA63DBCEDCE754DB6C556B35E3FFD2C721670767768507D82797046E90C5C0406C229412B37111CA5F93B272EACA0C8415B3C42FEC7132F3FD0FBE2C076ED8E9C835212BC856635C2C66DC838097CBFFE248B0C12E47B87DD0E939677EA5FC2E997A804EC0B6738814D1B8BAE8DB81C6EDA0E352A1F26B5E993750C69D72CCCFF3BB27D9284464D3702256F2AC8B17D5DA549469DD65943E2574EFCBB390B91A2985EF9BAEA9FACA4A439958C95FFD3F0AFA6D94C5E4BF3D42A1DDE1AAFCAB5EC7318C62D63E53AF576AE04F4EA74097CD0C2E643C11CB6D2E9AAF7E5EF1CF5AE9CC2929A443F081026A7E9FAE1C0A7C569FF9DFF885E31FB0BE2CCE83B4F3D82E30F0CB72FDFCB4EE8536EE014DBB71E9E7BF8A5A3E733B9472431CF3DA69578EFF2E344F7D2CF9574912908E5D9DE1F4FB2FEEB14CC373FDB0D11EB833707AF12F7CA0CCA6CD1BF4A7EB5636FF24A3BE9E72891A0289EEA8818BCC5CCBFFEFDEC5423A3F10889CA11AD93F535A0BED438E05F11B8DDA8AAE993C3052D0A05A00E4D4004E17DB8FB849C21831B42936377C864180097DFD56164CB0FD01C5E936428E2C309196C04E532F802B0D30B6038989A0F36AAA4A942DF81C6880FC48CCD1BE69E02D60D73B2054C5A01379B44DF920C20DE91E41A9CD350AD1CF0A0321F65C40288C9C3CA9EB15B28B736AD6F9507227C12DF1BFB80688D9B52F09C9BD4102A1ADAF177FBB820F876418C0E2119C35E9D781E915341F6A63117287048206296918B02D726A94C80E10F0A9449C36BB9FC8AC7A289522012103619A9309A5C324E3BDBFEEFF34D2F0EA2414ED9DE60FC2EC157A9E51EE5806109C1373478384B42D8CE419424A70E67CFC007F03BD8CB41E38E44200D039A7EA6A84B7860E209E17C45F733E56A4DBFB19EEFC9A159E31BA10862C2DE8EAE09941A20317316910EE90E49A1CB3998B488898D6894DC2CB00C9A2A577026982B91CC25A40E8A1B88C174A3E0EAABC14DBC1AE15291021C0EFC30AA7F0EE7A004EAA0D907BC5AC1B14B72540AE1602DDCE8A37E57AD62239E596B070CB051F9CA19C9411CEA52B24A3A2D12759778D9268E06EA2C404B93F90E502FEC10AE9C62C933E4A025E8DA23202B45CDCD843C57B5440DAE02CC9AD42082B1C4411274944F4AB021C11A21FE976F35C0748B5D6A5C2844E538B1E875BB64F3C2A6E8D4980C5909CD4F76D21940016DEA1A00F067678F85A9C46B43E9DAD0665C03D54A514C899E3AA16194786147102FCC401C182460B908823BE60EBC9486C28A7B506EB02037B6E5B16EB2DDB641A214CC908D3A22301AFAA897B0ED614ED3A3F40E6A403823C8F1F2A5049B378237B8B0846B59196A03D042793C60EA907B18467F59627AEB212915A30A915E1F26D77A24809E1B43BC9F128DF7ACB2E803ED2181C061C11BA0B346CBBA18A42E757C94489516CB9DEFB2E1A9702A622E4002407A869BFC829EEB3AE17090BE0E96ACB783566F30543EFA01AE267B24FE24370EDA227B0DB3D3F633A9C6345691BCA1D4DFE569E56554D309FC187EC46366F35E670C9D09A7CC71B675DB2E62E440B09AB7629F277D346A7476AC462609E3E8F54B41AA398F50CD831B91891403400DF9123540536B19039CF6C957F7BE4D1C3EBC430B6287A2935EE0E510C2B6951EF87DD9DF9A8C2262272C29ED10AB304212AAB7243A490A41A5E730A5AA1BE41E333B90CC0E11F2C9FAE6D164A405B58745DC000167CDA7290087111A7E8B8517013B88D3B98D20BCE0A1D17E22A2B836DDE939EB7F72CC1ECC91B0AD0A54D96CC5D80364894717B33E97CD86651866243B7E81C522D99220E515C4C43D0250BB8DBD3C85041695702A847356DC12AF6BE531891DF016F000CB5F8A118C1D7227B1884FE3EE8470D501DA1A8055341043B9BEDC15ED6D7DAC115AFA570D80A947EC432D619570A91AB29161642972CF7578231A0CCC8253652B2A2D7B4729896C17CB63E8D45C654B57079F71D1F052127AF772AFB3E24E6615EFBDF484C43EC6C033B1B54377477E3A3C661E763CF2AB3978DBCEC177C6DBAFB7962F730B2D3CFA5341FC684E9C67EB89606F4C5E2C0D7A71C618A8C141931104CEAA7166D45D090EF82C88A579D595E7EBE44E12751408BB57BBC4A37C81DFE4E3FC57CAA90C60EFD4384F85325C161557EC44C013E8047A8BBCC099F13429CE62C7645C93A74E9A4D9C3C90A1C36240EF729B4E43F494A74C05E3858CDC5B1A720E4F94B279A488629AE52463F44111597E76C70565A7E2E482BC148C4DCDA37D419E50E54EB62663428F21D45028AD28945F26F7E1C7289457A8D2A932A5F1CF48CA356CF146BC62EA38F9D105B03C5554C6BC22AB53ED4FB04B58DC600B46E4D3DD050B3B87B378D4EA72779CACBCA4E7B3989A73705F27B53D59086F138219D9D5BA199F7E0093D2A34D2F052FA6A27C43AF22A86D8B584F0525E15900185D4110234248BCA06694701916F3A41193673383113F0C9D8EE39E898224B41A625A812A010D06843B8E8A225314E15FCF0B82A7D71B20F71CC2919515E1D95D6123F22E0F92C018064484CC28E71CDFB26B30D29423FB0C9EC629EE445FFB33A8C44324E5827C76930A44401B153E317E6FC4813D8D0F89C501126F6FAD7418C9DA49AC5C73FFD24F26C1AF2D8DB63E6B3C6F68F126E5BDAA4CA6D3F6907B4CB2B5C116C53B13CD59214736104A1D931F5232FDE9F620C429800F2483EFEB60EFF28339E04743051BD7C3395EE57F534EC7DC4F446CF099D0F9C77A98DEB716693F1B44556F3CBEFC604ECF3970293F4F1D63F0210C70EC50F6D6EBCC45921ADF119390355CDAF06BFE3F4715CA35842AD55A1DA17A19C14AB92C5E7EB0522FF5B8545A2FCB5B3E676A7AB9FFF0C2AD3C2F66B31F8C7B5349881432E600568F4DB137E345707C4574A987F959677C773B332BB1EA9EF94AB402FCCAD84F5C3F89888B9338245B81D8891090509DFA5C5E403A67B6371D8EF49D77DB4346CECF36674A23359CF1EA9C08422216EE30098A261F1EFB9198AE17641FCFF29DE6156455FD7052587ED68F49EE92182CA77FECB5C2ABA33F4C0B1281ABA5328402843B405D873E668AB50B6F92EB7AE78EC1123A0F44D7A3EC20AA4CBA72403C033E0840A666642F7439B5D3415367B2E525D05489CCD7DB970F3830CBA89BC734F05F8D62EC287BC5315B755D7D8625C7814E49E160348403C9C1C94A1EB90F57D987A80FAC8A44C44A1353CB5002B7D4745729E9E81D9DD63A9C6D1D6B68E516778293366F08C98CF358ECFAA7C24C4443A62867FD53A0FE71952305B0CB85662A0021BE9355B094F00C052054BA5781F32A199C4437123DE1A93C25D52279816ACA2F6DA0C8EF4A3B500D76F55B014DFD93D4F00CE2A0709A2365DA99B293C2C9DC70D74E5498688CD00FE203A1116DDFCD6DC7B02F8FDAE3D04076A17498289B6A2CFAA8E230C46B516DB1D39AA7D92CB2026E48E77C2F1C48496054B09039EFC31EBBF76D475E4E61D812ACE74497E4D23213688E17EEECE18D7806279B275E4200B449D578C750518616198A2CF8ABC304B06300AD383EAF049D815298562374DE166533E5C419D3945A6631D3C7960A8CDCE072094F3A1DF1489EA584E5495E9E0DE92CBB7E78A5687E4B0B8D3A64F8173E03D5CA078C2711195337CACE4076BA2789ED0C8F632DD31043A5DB60794317572BAF9304BA5F6A87B81107F80F194096959FE999084CF38124BB57566CA7E829703BCBDD824CFE21C504D75470894CAC53D0EE77897E982C0A2D9F3351E07B062453D1E91B1135FB54FD30D4DFC318ACD7C892AC6F2920E7BE005FB7FD44233146B8CE03B625B839B57F23B55DDBFC97ED2FDA3EAE142042FBC9AAE4D9C12F91084C48EC83913675BDA2A2C5DEBEF34B36A17743BD6F02A848EE619F0E62E0DA93BAE03EF670FEDF172EEDF0792C5D48DEB2E32CEAA225E68E1B74FE980C6AA5F6B20EE63D7364FC779470C47CC3EC76F3D78FE19403EB6FC66594FDECEEFC2AD7BB48F7007490594D3B0C6E9A6C97317B6BC4E76EBC81F56A47783C2F98155D5243BC6051415CDEACBBE2EBA1E733199EB7B271AB00E685C1F27EF726F0C961446B3037DA22D5A6FE25C9176EBECF84DD15692FCEF5AF122B96EF4FDDC548CABA7B082E11BC1662E775CE685E5D5931D8973E52B27E6D3B55F025FFCE33DCB9F9BF8A16EB5680A33DD113D0AAE8A0F502D61450F2872B167203A6A6A9961C57824C16BC497FDEBBBDF3F4CA6F4D1B30F1ABBFECC328172631A5E4695A44EB12F96A8303D32E495CEA9DC589B60D32AB8AE61004B4B2869D2FEEF3A0F427F70228A0D384FF0FC30D89FD3559C310962EACFE6565431540F9C48B35F11A2AEC656942A9099499869E1890E21C1E735D263D31431D6478F867F67619BC30C517559261BAA6319000C33A9BF798AD3B165F9FC16E95E9E3327341D830821BECFD7E3D578A6ADB0823411D372BAACC52BBC0FA14515BB53A312BA53CCB2FD0A91385EE6A41363F5BFE09CD87AA1BB9CF4948C480703F0C45D770C63DE43AD7757441DF5FB8E7FF85B6D6417C7762FEE1696F4DF943CF855E2E1876FA0189FF283877C3605A94D54484B7D90789D16BC2DF0352ACDFBE48F2CA4898539736B14180175CD20FA626908F82BE830C7FEECA7B5EAB7615FA92EDFBA025FDAC089D52CCB9D1F3516C15BA788192172CEB74CD66C606205465A81D4E0248544252F38D5B4038B15508FC50AEEC1299EABFA3BAFC84843775D9DF179938B0B2D77B17B91833CB80AC8CF27A8F4711C7765F55182089CAFE9BEA918BB062751A7D19723A2DFF86E00ECD383C3DC5A5EF626F17A1A2265E9AA620123101B686ADB8271C4B352E89620E8FA646A691A47BD9B7FE0325EC9247B1E9A7E5BECACCEA705DF585C2CB5C353A0BEB54539429F0DC5F3A0DBAE042319DA389321083B733B4AC3224C802E6DC099A8D37A7AAE64D19F1A096F976134E9C9AA7685F7AB462C4224FC2B61863DE98C1F26D4492702B0B95DA70AA2544A0983B8D685E8F45240C530B224D1E04B22017549B84393E14D944A6746D544A2E26C6BF31F06EF98F8329813B359AED45D85EF68F454E417BA0DE4C66AF72E70B6B0989746F2679E6335BC11A68D18333642E53789399F8CF1BB269FC905F0AFF29CD25C308D5BE84FE88196D6D9F0E2CD25DC3F8D812E9F49F1E4067790DDB87C928E2E8AA47AD70A9E1BF12325F7F7E8A431CE4914EDA566F828672BAEEF288EC6EB07210601EAD298985D80084288C45199CBEF250F1BAC5206BFBAFFE1E03DEFE9CA00904EC36B36ED8360D789A70EC996CF35CD3AD910AA7C2321D9B6F63636A091FC3FA22FD9494DDE2CA4B37DA1D8007D44C63DF4FAAB136EB816C6BEC3E4F9A9C499FAEF3D37FF069EC1835A4C86A09AFB2C21DD9361B2EC666A39889B9965DB4F83AA829F8334E7E676D840B84297EF1BA16C3327CF8FD2D36258AE4D0E160C6B957FFB4F319822D74308E3747565FF654C4227DFFAD33B5999AEF909667787985A75CB43B6851EFF6DE181A360D5792ADA6CEF5812AED5B9E34818CF150E25585FA2ABF0D9325B298DBB533F83A44E8105708E1BD7B8FA4F93E9B805FA76A0D53B0B132A6F982EC64CA500613D07B3EF76E47C827AF35E000C07EA7914CFF994DC2E70090C15BD6227EFC1B2AA51ED6EF64AA596398734D757E02067B76BBE87E71CE74A00842FB6F05769BD0B606183CF0F74C71E63B14DE801722F6472497AA87402B54E6C15093F04D8249B3B2ED26A9BBC046F84738EC21089469C6ECEF92D6F6CF14CF888498676788AB85ADFAECB61CD8620AA7221891EB03C145EF683B80BFFD139864FC57ACB2C9A62CFF05DDDAEFC83D0BCBBBD12F9997E560B44C3D17CAA660D8DC636853CEAA2CC66A90D6880EE4BEE946A897F46A2573BCB6DC8A63386C932CB0542A66D338B3144CFB2230E5CBA7BC20F5503297677023A879620FD21CB1C683F20ECEFBE40CA58BD0DA77FD07D2675CB726D1331B62DD3263D6D5BE722940A59CA9E9D29E4B0664A3BD449FC15D371C81C989673441564388A41C18F1C8B94DA7E2F1E5E2BEAF0F96BF10A097DC616A7CC989154DF7DCA419E7BC2BDFE5CD7B8CDD6A3831823DE6C2BD70F3C1E81C3CA9418D76B188CD1F99E3F4DEA191D719903F6D88F68FE4C404B0AB66B2292DAE549BA08E2D589A6EBF7AC0A3864E7ADE385584EDCFEF4A838B0BF78E623BF974C3DDAC41781A3CC3B850748039829E616C80907D408D0E9078213E99647C5F118E9F50582A64A1F8E2D5BD5BC1E289E940C93A4D9C49948A349F011484BD686ADF87F827317C06D1D7E7E78BB730687BD5BB01A7A59F9B50E91BA66A3D7FB114EBC6B16240536EAFC1EA839688BC10908254B26BD074F711F68CE86A5CBBCB3796DAA4B96E3AC96623FEF39164A8A75F549EBFD62153574D1E8EC93D2D5955B45A3EA449BB91FFA51EEBA8D4DBE7FFF363E15AAB84B4159A06FD88EBDAA431FBCF7AFB78739F5EFBED3B359E36C4DEC2A0BB62F4CA5A5D410F1006083B29C47C69C440D87EFBD07276E65B7E445C57C8D84F41E33A085819FF2A448A44714574CEB5FE7EC482EEAC49E2B5823E3EB07BBCEBDD9FE2BAA102DE9D15670F56D055E0A102904760A25E43491CBD8FAA0DCD1E50AF4193CEB3F10D44A4D02719B66A36E5E48F6C3EC48BF494A381E57C7191696C204DAAC0E346B7E2E541FC2BCEF921E8D379B97D84E55A74071C78C0BF74DCB492907BCBA4E032336D8A5BF9854B65AB20CFB41C429C8B710605572DAFF514C9B7254829958706A7980F93077C6E5BD0F4620CB582D2B64E36C064F69661889768944BD87D806F953DC958A3F66F5C59604314FF1354A06DA6FED3E03FACCB06D969F2E284B463BE7B1A567729B055F03AF4D00B3C67B18FEFCD13FCE377A2593D0C44AA3A8786068EB1E3F22A6DAE131C6F2CCAD03FB8AAD1ACD3CA646A31865188E4E5A609AD1947E45CB3D1D8776576C74683B772240231B6BA43DEAED0510609AD5B909385EB6256E2DE4F45FF42AC4EF87F712F7CEE14F4DBE387BDA9D1B522F128DA353131E237EF40A3CC06295766FB2DADFD6B294CC27C80C8BE8344EBF10C6FC5FE4676DF1F0F48467752324F64ED8397016FB55749BE8EA167D927CBF5F1A656961EC46004B5CF2333DAF05A43C657ED9D3855953E06A24E4BB3F2AB9D08C60092E3A7D16A57E483653D2BC98E8A75B42763781D51253E0A9320FF1BA4F717F678F85E37359DFC8E761AAA732E3F168A96CDE197FB8BCCA160DDA27984A2442A0D867E90C4268DCF8082E26F22419A8AD84C708A978F634F129B1C2A905CF3BB43F217A49AA97D8A4DAA7B47C3F37029668C06532B868A68A77062EAFA3D87099FDEB5B05E58BAAA946A68B7AE3C8B3D7C21F5523239EF6387DEE3F9C788C1B9D2188D9DC7E78DDEDA19271EAAAED44607A0A09E2AB43DC48ABBAF2D039F92CBF1DA363C3C2B91AE052A9C1C3D7DA3E57163BDFA2911FAD953395067AA3A5CDBF490366F13F33667124964C81BE1262F8572A72EFCB797EE0BAAD88C537F89E12A39267B0507F385433CDAFE9422F6533248DFB01D85DA0A2E022E4645607315D018B94CD6A6BC71D4B57BD916BB658A5AC99C7C59671A811AC7B6679121E454C9F1F9FEE38E67014F2485717304940B8E29BA72FF8168D9475E033E6287376B24D649369B808056708D3E1857990D2B7B10F820955D17CE095E2AFFBBEE7A37D4A1E7797A92E0923005C21DBB179CE8ED2C143FA3815EF5C8AD9346945F1663C222DD44B098A702FFC36BB94979CFC9E7AEEAD27AB64C7A6CE90F31CC6B644E70563FA9AF7F0C52C2CB4F07B7F79988A692B93B210C6062FC792F688FC71A61A7E6F1ABE58CA87ACAD5841D69ADEE85DD89F2310F7CD3FCED9A2D5E5108D732861CDD674C9699D577C516BB959F0B9A587EEBE54C5EFEBB87CB9683B12F4F40981F656BF5CBA095239E8C2213875DB93E3AEC34A6D21CD1E055FAD56A42F6EE4398DFC83EFECF64C8F8266A9F2B38420F0BA94DC6267F9E2FC3A7AC6B586F12DE4E2589DD34E7036A57543B8C618AD4647A0992C35741430B12CEF61D5A08886DE80E1E3409BE82A699614D94091CA8E89CF8AA7C6C6F9BA243EC0701AF67D2F6B8032B0976D1B0CE515D75D3F836B965CD2730E1B0307B3623E2630681C26C95ADCBA9D7A7A945D488DED71F67FC7B5A832BFC224C7AA9ECC968C8C5C1A63D5F31F218B6F47CB0A545665A92927607BBC9038CE71CF16CC166331329028A1240866948AFB2340CB8D34F5D9204F1B86A07422F3E262E7FE7AB0583650C6CEC7D79ECF7810943F75606A93456FB6A85717A0B3570432F37B57D39FBF8FD265ABEC1CE20ACFD58B316DB8A7DCCC96DAB26D46E23B46405F4FF96E9B4D7474D67D7B2841FEE5EC0EFFE9A90A419A7C21EAE41252ECED71764660A0128EA7B1B47D56183A066BCA2E42E03A6A3A3278003D118BF8814FD41F412E7D19FD7938160BB50931F8FD1288B5E4C1D4151D6A2E650894FA42EEE993EBF6BCAE8F5EB00B5807AB80E7E48F71351F8A726314CB8F48ECD960E9F9F1D6104F4A66E8866334B12D3CC013FEF939AD6CD89CCE66004C3DA5C5FE7AD68DAE75A04C89DFB374882BF66B4E48C6513F7FF400F9B0CA637AD44AA85AA0D08656FEC10C70CB84F709851B86AF2A43DBBFB19A88B3A2D5137A2D0234785631ADA0BBD30523153ABB9A04A85760A14FA7C1A41E225482C07A83F5896CCBFC7E6E77ECC058C340B9DBA1B51F090B0883EC28D1A2911CB52188E00964367BA0D4AB531A0787D3E92DD823BBA2FB9379E2FE92A8779BACF963ADC227AD96752DA941E9CEF4B50822DA2A1179D81AFDB9918AE8853B865E7FCA24BF010BE8D4E52A599F714A71F826098E1E0B7A88C236AC8652B812AF92B27B29408E40B54910AD0832A1B86F797D3B9AEC5AADAFD96526BD6ACE3BE9414B8B9ABC8748168C3C9738A50D092A968FD36670BB25E85D70B6A83FC199EEA1A224CA3F0B6A5B1555A678E6E4FC67DE342E906D65CA8C9F6640624B05F1FB81ADEBB498C9A516242C76AF235CE6D812176F5144BF9488623F45985F46AFC596675CCF93B0423F64C1C07DF5DB7A1D6A5414FFC3156905160B53B9FA401647EB9E83BCB822723F0D9F29099A63B5BC8780C37DC2A714E218998F1B73816D2EABA5DA28EEAA952296A9563016C06EEADC47D921F25F89EE3967D90EB3AC6A6E84AD9090880C78632C8156A93745A874D6528F725AB09E00DE3B0588363B21C21321D637F03E129A72B0A0B430958D71E721042C1BBE297B74BAC71A2A7B91C7EF1E8A7715B5D84C3789021101A6A4DED729D6FF7978D7012638F68C5B6F7CAE1B9CC61605120423B514F3A6368D81EEC665294C3945E0C8E79D2421CED7D1D99F9AFEF10C67CE8AFC4FD0A65A2C32110390A2F6048F2F38588B6A5A70FB307CC2831A98ABD9280B52C91E6980CFFA3EA18A95D8B12C1306140D77245B4ECD2A6387C8C490E1A3241A9A15864A6327680BC21522A34A02540A4F3B1485D2A8FFB24FFFFAC1C21C5A476E672C79F0BA940CE06F6F55B2DBEE30DCA4066E029AD6FA81D58987036D99AFF4CC66CEB5762E0CFE7D756078D840BB165E22B6369153223E0C375EFBEF2678587F4FC2465786F8ED774D9D48C2C667FA8E3719EE876B7EFF9EA6240276932AFC9C9FDB5DE08B33B92F10F9FDBFE8D3A657EF3479BAA7137E6869EC3E1A597FD63BF72104C6D5643E3B94D86321D8D99AA7282326C53AE221523ED3EA0859428D3BDD17CCD0181C7B0229BEAE522B46A90DA56DA124DEE9654111CEC0CB31CBF88EEC241AD3B0B2863096A23C163F30AB743F71EEE64AB1C2559C469631854133EC398BD9AF032A30DC7CC21A484F97240F5752ECD11E44F9847BAE816FFE061485A6DD53A1CC9E5DBA030A1BF6B70B860C0BAAC5340E2D7F56315A9E2F9116EFB784343A63A4CB7177F01C2BBA363AD90114870E6319114A004AE8809D67B7C091CD72CC60367BD11A02178A103F4DDB1CC65281C081316C3108A7E8B3883DE3C09E47C09B53E5EF2D0C77667E9DF4872C97A18196D44FABCEC5D9F359E371179E4F69FDB957779B652548D231EC0F655B63BD2626DADA9047EAA78FA61D162F977E2E8BE22CFFE49217C242D26A6BCFE52BEFBE1B346EAD9E571FE67D069224DE99D15A444C65E25AA697E19B1A3DC203A929D1364547E3FA8B4F190FCA3C24F560C2423E621C49B85A26D4A41EE93320992CC4669FBFD0ADEAB5B92AEA6DF8C7CF9ECB2B90127993AC3F4A025A9B55A588142DA7FC60DF465C1FBC70244E25A256923C1ED10A91484391D4944114A5094B85AA96F00CB10D17B38FCF9B5DD5B401E2A6FC2FD6A97699CC3430EA6B0D0ED9071D4F990AFC0DCCC76E4C5CBF48B4E9B9D05395B5DCF8F7B023C842A19960741008AFB8A2667A3AEF1D035A2BC28330E6EDEF7560775EA97C3221D3053B98EF228A8F07CA3E24AE2887FDB4E4D7D39435C0D038FF98982A5CB2DC88A0CB9935CC9B72EB06020C014A194536EC8A9C6079C181F8C554EA30316CF9C6868CA152C283FE6F09C7A33731D5CEF81C34A6232B2F0A537FD05528CD7C5126A9CEAC27ECB74FCD3AD3C1CF17E862A8F3A41611C7B276A5BCA937BB83089B045B7CDAEA2B680C32E9A2135077398C444052A2AEB9C37AB20FBDD27833A00FF27E0C35471AA61FA0FBECD5D296E82FF856276D106797CDDFD62FBBBE4053F0698F7B22A1253A1DC703EC61B1B8BC230B4F8F49F450B5ED3EEB98872FBF66FBE5FE06C7E22FB9EF325BD7707FDE361BEB539F133E807FB775927D64EB237363965C3CC4F0AB0AE89FCF638114EF531DCA08B2CFABE90E1A7DCF9AC9937D8D0D0D45789833C8124F5CF8BB019526BED1D645A7B81B037198DB4CC319B02C48740A3382ACEBDD93C0B09EE1ABB4BAB0AC0E154CA881B568B25C5999B15711FECEF121F4D792BE112E72F5D42A89CBA0C4E01B16F09356E75BD898981C7243A60ADDCEB60E252A53C0E2997F59ECE76EFB9EDED036EDAE650BB5B84A22D0D140DEF7CF8C319BED5957BEB25C323580969412B89138D9EF701295A3A4F27479DC5FF74BA6EDABFD68099F3DD0203A5600AE8AA72269BC3107A81EAE5B0250136F6548A3DFEA7C1846C0A4F600527FDB6C8E9D4E1E5C9247472D8B5928E468247BCEAE77BFB4CE4C7C217D2955E2EE0B570C98DD35B078187918FFCAFA17EAAEB556F7EF6BCC79A008CAFBAC451CC88D85A83302630CDE7870ADFACFFEA4EB0A30A6D99A5297B33EB954489374F6AFEA0B506B12E9342972EB7C52CE65B3EE17CAE61723035C63F6652A828A75F3406449F22ED08BA3C0B9B396E64B1DA496DD9C33734B5E91C26545BDD6CB8516BCED1FD51C4C3B4F5971FEFD26A72C29A8DEE09677989ED0701F325B0E6BF5E4F74B37FC158FCA28256C0742A6D0A22F4172D2747BA13861861A1AAB21AFA31DD658F5AB320BDD7669C4D1A9FD72E92544BD8831D4C93A7FAF2900B0596A596DFD2DA72A9D3A2BA0D8324710C594D29191CD9CB8F318F313F32216843DB65CCC0F76B1D16FDA3650A1ABC1566D9FE11A1230002AC5DB647A8EEA0AB8D90378E7EBDE683A11950CB81B7C8A5B37DC808D4E90626A0A513A6316F490B6C6EB33C3DC1DF9366DFD6247991B877CB054B16A672256DD3353CD253D2E0C29E461A76A17F2BDE225A7D0418AAFA87BE2FDC4F5AE1FE5848C1DF7E81951A8E53AD2E5E0328C5A559FD19FD23A6F36FA220E1A467DCBFA2BF1A8FBADCA51FF5FB3D181690EA0E64923D41858CA9C42B5DBD0B302DE98FEE91B00CA20CDBA2835DB0922DA2943220B991C34DA1FB958C8B2A49337C0BE157839783502928CCB0534993636835320D182E9A0004E944A217BD13C1FDE5B5199AFC501A95DBC3653F8D2209511C5082D9FC26CA1F94BF17E47F0BA28E4238A4BA624EE0828ACF4690504414094546515054286A140D8A1645B7450E06C829D4BBD2157ED19F08F02367EF363DC6A97C132189AEFF148924DD542B7E9C75F367E6E29D670D9A00377D80D4287C087ABDB1A480946FD52F9C8F2C8BB80C30C73BCD7464F038877B279C2CFBA2A3C74018D704F7EF281F3A6B8C8BD0425DED26BC81F731FBCBCAAF789B0D01D5A1C991BD85C1AFC1CF63578F85E57C4C36EB4680A8E9ACEFF2D6AEA6FE04B3BDAD4D838A71FE9DD03C0AAA9DEB34EC910E8A7D5ED0004582F74F145DB1B6211A05F2B21FB31889AE221FC55868266A3C3B49C7E8FFCA9F70F1FF42945184ACDB0E807E43C5788F62F4C871228EE7111C9B35D8CEF70B5CD40373BB5DD9EC11E86E992EA0C19E406964517806F0C45594FCCD716A8F426350350FE18888925A0F1DC92507AD3E4C2BF7CD0CD295BFB5BC35CD91841AA1A1ACE4E3E4D330FEA213881522508FA1E78FF7E7CE3E4E6872F41171D729BF902BC35E3B44360B6A99E499AA7F1CFD8386BACDFF58B34E75F16BE65EF9E7FC4F1C72665A64A93D04A4E5761AFE642DC53C299ABC7D44985A09971D33766F227FE219AAE7A98A0DB97BD94EAE47523BD8DD080A01F08DCC91548A15940C97F552E44078FF9F1576590202859FF7627A9C7E18BB2FD3CB134013981FAB75F00D33CE8E3BAC8F36BC447252FF3E24BF979A4B8E00ECF3060FBCF66400BB880B656D0E83832D211A8A587190F6A7D65DA2134AAD548751F9A78E8ADEB16363A7065DC23D85C29AB6BEDAD8CA4BA1A525C948FC3F174AA989E910F60D55300E09745BEA20F9D77C6736539E81470873A93E9BDBE8D82AEAD34B45C0DABC99D940327C9ED2BD1948D5F757A4F4E63A190299A9C888FBEF07861924D605977E8D9039FBB9AA49E04692FE6CFA6B4D2102EAAF3EC1CB86F92D4C12E61A294C7F13B64B6FD4129694A85F12E12CB566F79C0925FC8E4B9F7B7B84F086FB1C329C6A438B5DCE9061771725F588248AC0A11748319B3B6DBE48DDDE0B025403B9FE129764CD15156C70954E92A94D547A75BDF54EA173F03D232F8E12958A1201E55D914D53DC9F6AFBB2D8CA6A6C5E81B961A9452CB24D566C5B9146CF9D28B5D516E6A3210B7692738627A4D8D73DAD51685706994C3D85A8F8569576841AE2169F2508F56A5457803CC7C6294DE1FEEAA289106F9B769C46D3B780C9C9CB86754254A5698F870C32F22EA95F3E7177C879C94E12FFB9118C260935B5078A3D142C3E26698A036C2A348CD720E8E4CF49CA6090A437FA3A9B175EB076ECA47D6B51A24AE8EDB64AF41970BF3A50E4311B9097389A5DE2C899B639E7430AEF0F9CBBBEF0C498E22AC9D6FB50DE85469A7FDF474DC419BC25FAEB461E3ABDC3051A72F91DBFCD27740C29168841485229A100EBB88DEA65AEE744F3ED887DC106C1DD46580F21C7CD46FA64E4574911A698ABCDF6DFFFF1ED9CE1AE1CC06FD5EBA46B998C8C905DA371100798CFCFA0D2570EAC562059F1D30AADA3BFDE9EEE9C94418DB8DEA0BC6BDB7DA7009224FE7CC493F1A0B12C6B9FB8DAFF19DC45573FB0FAC9EBD43A7013DA8DAA4CEE402DACDEB8BB02B8725881F7DEFEFCC9E1CD93FAC8E1816FC5ABDB4CFEB257D952A2E435447F0B930293BFAB097106F00C2138A295E7F2DAE2964F57CB45DF75034929E8E62486EFD11A9B50E87EA6F1F2DC2D656B159E2F920C67BA17E7AC1E88C228F725BC4043218DF57B6D27CEA7C303EE25D40E2E42D3CDF0D46DB20AE0FA29D1C0D866714E699FC15E2E5E274E16D80CB835C1A95F167FD5F5ABC761845E995C9B02F92120C0E39485997D27C02E20D5107F1A3BA3954CD7998F294921DF1D8F31B39D1541C152503B32552A8FA38C585DED369548C9ED9E4BDC8AC1EF595FC3ED739C871AD7D703D6B60365909155F7E8CC8A38FF189128A2205090282814340A40C181BA08C506C16FCB41676D90058591E8EADF97830CCF0EE782D6FA9A57D08C3986C0BA107F7A8C91413B8BFA5C367450F898AF65125FF855F6B661AE06EFE57664C6657E52B0A8704008AAB3018208F7DA5F7C240301758405294A94A4547EFDE3F6C83435E69401E67ACAADDFADD12FE78C564C7C32E860E86F9C5D28DBE30BA365F17FC30464E55CFB164CD7297AAA2491EE7656A7F5F6238AAF14FA6ACD02732DD73858CF9919DDE1A838328B2923777FB1369FD30951EBD2ED88E7D813DFF17F57ED37715F9569E3E15F9373C730ACA6474BCC0B4ABC099C612DD1629D92869071C4BA62302C56562583F27C7F6923CC1DD786AE70C343905F9411F04750775B563E41BB40399A8C9EE77F65DD6DE0513E6DE9B1CF3FC08369F710C69C724A18D3FB20217C990B6DFEFE02E7C90F86FF97A16AB7A78C0B1B4EBD94EDDEECA1D4B67A98AF5F6ABADD931E65C03B9613B7399C93052651BEBEDFFE5FDBFCF39664C3EBF9272C69CB3B1FED5EAA96855FD44AB4BB08B30CB30999BAE31E2F4D5A8FB1899991BAED1185F1D588F6D01DBD61B9EFF150BFA0234742C46D52793F2D4DFE595B13C6550D93FD7669ACFF52C2DE06D759F2F5A1B89E973FA544E0A1A79D195E82584B16DBA549ADA2678773319B046B56D94847A17F4F0D83D982A2CB492327C29067FB9E29DE947BD8FD13435270BEB90169B01943599E724BB6778E081698EE8D987088A3A8C15CA6298F39C2F5B8763BC0D62E61368B825B4A9A9F3E3839A185E0FFCF2876D4E1AA6E4EAAB45FB5018A351246B7979A21751116CBC217E08A543713FBF9D8E0AF4F9068D8F90361B13AC565DB57D6B8ABA8DA1A276BD66EA2BC9BC9EEE228D8FBA38216733ED264D5E7DB1AAB2EEBF7458BAA274750F90DA185AFDFB8AD543B13F32D8C7EED3DC56DB6DDC7BCBC72554AFDD223A28F8903FEA46D7126CD038599E8598CF936CF51DAA2DBF4D0AC3FBEDC8BDC19E2FD5456706796FEFCCB21B3D8D0EAC363690D78DC2024CC0579CFDB8E12BB0C8B23F00D812F9FAB213DF12450E8B0A96D6DFEF23B152DA759F2976ED79F406B8B4B313AFE9D338DE22C91F47CFB3944A40226F953514E2080F09BFECFA42B5ABC5C5A499CFE56BCEB121E194846BC8E2A30549E132FF95C53BE3ED06BF29647F2B755E45383F9B636B77AF39BC11570C49153458BF10C2228DE419A5F532387408775D4A1E66F805195B8E7E88E0B4C638E50670F644B1ADDEFFDAC48A07F037E75BA26E0FA49304ADC040DCE7E83A6E6FC9FF1B2E9B0CFFAC58CF54E7E1A038D210850E70F650BB288924AD05983AF5DEEFFE3195CAE36545E45516C21B31F1111B6020A7BACB108AA1F630BCF4072785222DF720A8D879A3DA1BDB92DCE1764ABAA13975ACC52C70E7066DE5A89DD8A58E3D63F12D07B64391E6CD10946E3B2AB265B427B2D8B0949053478083CDC61C691482F18AF8C47406C43DD769E4B3A9AEFFD1C0531AE81EC0ABB364FC49B841F249918C8618BF3C655F9B9EB4AF855C47CE044C4FA954EF9364CDE49D269755C7AE4A664AC0121552592E93923B08252E97A8C10A67636AFB9AD3B73124BC43D1053F8B5075DEDF5B043B8CB92449C9DD2A06F0ED2683403F40FC3DC3C1BF3BC9361C2E9414F72AD5AF850CB22051392AA5C858F1A4E3CE39D48E85F0C2C71ACDC5F03F699E6BE2866E7CF2E246F930514E1946B612AFFB59D5EDADF84D4218549FF8A1E2690CE85FD6FE83B283C385777ECD5A7DC84BAF6659B6C92847E0DA3EFAC767A1E28FC167600C6C126C3B0D1C9C577B351EC20B27558B86856017DBC4B19E1462E732E2CD262E555FAE87E8867A4265254E275255392CF0132FCD412E233C24E291858F54338C50F4443892B1E39DCFD08FC4AF81BE270CFF7E4B8F2B3525E5A0EF4A9C0821DBC2288747C80F07E2D3AE18CDE7F2BCB5D79B527F0FAE159ECB3CB3311A79BDFC836E61099D2CCFE8563FAB126F4945917157F4B89862784F1849611EFAC792EA31813C2D9A71B0C8BE9FF28EB3BBD4199A000277883DA72D7F46DB2D3BFF51BC9F38D78B9AE894E12E30FBD8C01A3C19F965F108860826E07116410E9060306A6A15987C9B870FCDF4EA9E6F423A01218760C8FF48C973DCACB358A370F7CC93D353CBC838808EAD1A433E5A61B0B6A872BF9A5F4E10EA0900DB83DE3DCBBADE95AAEA0D16025C1C59AE23FC94780BC89E67473F38D40DE0411E5E77309F14F05D917908BE7C406A988824241A300250E5E169457794FDCFD0A81D0D214F6960FF2426E8882A4B1AA206C72CA4FBC894B2E2A14F950833A34D88DF0F5C72F5B78975B84E2C42B2C392A245F96B302594ED5092337B576928413B938C44E252EB35D8CC2627FC0053D4496279E53FBE209D99F7D18B23044994E90BDCA42DF00F8FEA1A4DDF81236BF54D9605C40C1FACE1444E0DB1A28D98EAE69B719D901FD67D1786AB5D1CD0884061CCDBDDF7D0275C518A4A76BDDA95EFC6470AA0DE6D7B8BB519CC526FB6703EA0635A304964BFFF73B2D6C99D306B59B27186AC56D4A461011E9A87D23A6CDD3009DE2DC0D34D46DC3A3E119096E7E3791E98B204D28BA6E9BEEA41F7DCA3C8503B73A502B6FE464B7604A3543D46BB300BDD5A73FDB212841F7A24018DA97158B206A942E908E40451BA86D652917AD3E29754D39607D71C527C67B07E06BE67A36221E7CF2EC37150643CA821812A73C1D38234844B6A5CFFA4C6FA077DBBA555DE672C674562F02F2EF2F520F5E80F7B67B3605F542BD3290A85494FD8AAAB0B4E00EF32F154370C54CB189532AAD5D93601832D49CC65CCDE0301149578BFF502F7CA1A8443C0A053A363C8AB8FED6DE3C3B2FC2E994BEF699C6A175BA74FEC5C9D2C2BA1B611D563AEFABE9FADF6EA1CBBE7278FC245E40A9471949D7E56466D95293BA3880C0EEBE44984B817C9AF4AE30DFB07D93472088B5E96558CC1F31F7165C2BEAE9C185A24A7D71A2FCFC61A6AFEF27FF24B2E4C8AF4CB2A4C54341AA3884A5E1DC5CB8024CA935B7898A80DD14D9F443341A996FAFE3F439F563F64C6C1554BE6D00459D2B130217EDA6F37C9E8BD26D1C998383C86B30E1B6D07FEC7FA365EDC0F76234EACF3D6F43E10D3E3CAFEE055D1AB360559A15927EE15FCC3A96687606C9DA97C86A2A12C6E25B7ED5889A46C8CBA307A7E51CD1F520164513B5EADF937F77F2CFEE6351E2C62B20F97DFB4790807E4624719CD0D43CEB67B5FFF6B26FEA872978545D2548999F185BCB6AA19C455D7D369B709F5EFEC239C19BBEB37B2DE201FAF0CC3246FFC7015E85F8166C65EE6149466943D40C3B75A704AE174AFD6DC6DA48D04C805A600A8D4E0488F73C4FA8795C31F92DA32EB87289EF3C7457020781F6EB3ACBF334F9419791DE09DEE99A2A4459E4099CC50130D2B751DBC793DD2930B1CABDE9E5267A9959CFA8777A42309D4FCD7DA1C2D5CFFE41601FF4BC28375534ACC58ED72DDF2B1E3248767CDD55C7D745C4A0AF354EE14A3F7CDD967A1518237BB0F664667FB86D2D2E02743F915B04A3CE64D7EE005F03061BA680A0ACE409730F266751D9206570BAF56E0620229442BD728D26155C065F1DE6076D29019915EAAAFBE2ED268AF80D3778616C106A73D0E53EBCAB6FFB77308D9C9AB2E9AB299C4AD64553B3D67D7BC44251342872C90E643A9E87BD20BE4F0B2B9B4B07CB769140D68D7818C950C311780FC9F2A00CC7251E17116741C50D14521FC88E2B0DA5B856DFFBE3E86774EBFEF12C75EB64D09C3067B609988480415EA0CEFD5F06A932BA5FEED78286D4E0C73C1E9190024E12913631ED87B54C13331055E52359A015884973459D5204F78C197475F3055F4A3C186FCA18CF9D497B18A25480BFDD21856613662320A02FAF16E7368A9D1135FCC0BCD18DA23A6F28ABC4CEA09E8F38B8D2E08CAA3C3482D9F003DCC341F49D9552A8F8F93F54993250E84C5FADA830FD278B2B3BCCFC09D3ACD956FE45BE526F2EBF821F836467236022234AC218D766ADB7C1ED9B162F5DA8DA9F1FE1CB93811CEFEBFBFE4042EE24B178241983016D5F281CE66DC632A9BE7D8C38047889FABE55175055BB82ACD0FB4CBD8F56EEDBD0600992F67ED33D6349035DB7C667FF11B532CDE61F0A245777636363482EB5F44C95796019CAFA2004BC7781B801D91814631659C8903408FE06935F711319466D42A459FF70D3EF2E0AD96E5D31B2A2B5048627AEFF9D988AADC88C47093D6E74AFCFC9B680DEFB499095961F31452946C817A6E0657DB9941B20528E83E953DFD1ED4D9E3A2733FD526D4D6A6E62289E5590A7172612401DA47EB8CE9D6FBC7228D8907EECC02E7C7B248F0F6A37375E29A8371D8279D6A9F8EA336C66B487D2A93C31EE8ED97D7C7DEB473868283E2E9928987DD0CD4484F400FF3C7AB2D8A7C9D6F2D300C90D466AE9BF8E7D0948C74B5BEF71DCD0EC0FA3FE2010C68C5195D4485AA44165B13CE8A846C7D2C69991802A796628B17C4B61560882928C52B8BD67B9A0FEF19299D6FE5BCB0FFAB297EFA0B8F70BBB8FFB5B21A39CD1EE0A60178E98D328348DF14C5E56226039A46C0A02E1EF04E9A64AB9A50DF3EC76CC0360EA25D03FE162196398FF35744EFD610632809387415C3D72499EAC2AA93314951F5EF2E67696B9CC0986051079EC6956B4A702DCB3893AB9C789874140E6066BC036BE94924076AE7FB023F507FFFB6917C594BC9857E3DF904B9F04AE73282E89D1BFCF1A0DB37D9F55F3A048FD185F33E5B8E84654BC393004D84D532BED8B5C925A2DFA07DD4900CAA17D17A81DC0F0A016F4BAA71B4C62A10C860669DF072002FA76F25B511936C37451538F1A2578E811B7C6BA7CFD925D20A9823E8C2F23A03EB3E83EBCBC2067AD9BEACB504AB408DBFD9F5A59ADC782155DCC7734DA41121310D5BD78DB47116130125ED6C00AE0D2D06B150B83F68105738E6B78939FD6B879291455C7B577AB114977269A3DF996100D7576B61D1E789875B42E4044B446E0AB343FB06A84AC535207E14A909094E0693182EAD7D4B8822120D9A70C64D6FCE1229BC9C9CB47B5711E7B77172839629463B5582C5E4FA04F0FDC8C84DD724CD862BBE0DC173CCC47416BB5CF9811EFF496E74E83784DD24E4A5A4DDA9401C2D771859D3F3E409FABA67E59815566491613DB53DF004D3A034DC854308BE61C83CFFCEF6C824205479930A396BACFCE2B334268FF11121E580B31BBB82903B77F2A969A0086E44F8CDB936FD95AC5DCFF34FB71E6D0F5A7F89C4F929D8892C9CA476BDA7DEAC673C3BBF4233EB9685A21949E2BB67B608F1E9290E6D5C0C43B523E3711568797A09E75581152DE98046E7885ACF4FE1E20771FB81E0F3BC3D29C738FDF3439BA8A386D3B67B55877FF91D6DFB2794C0193BBBC7D8A1F70214745CEEE6F78FC5DB89AA69955718E0EF14B6FBE84799DB4CF787A50D85652BC59689091F4F441337A4B5CBAE34D06B23397BCBF542F6552675ABD68393F293BB993F8F40CF1AB52601B4EDC3E3B8DB38D518785765AC71610EEAD807467580F5061E1C98DD8212F2F565C61FDFAD44B23F48EE9A0F5A899F4E018AE66009B070F03AF1B58361F76ACFDBC7F8103DC97E8AE7937410FC022D0DFDF15ABBCFF6762FC478C6B2078E252CE409684108331820712AFB33177605F7F4FCCC5E1ECD69D71AA3B8A424388192F322187FB221778CEBA72E0BA3EB1848A7FC895BCE07ADE54200E78CA8807A70100481CDB691B021AC7002019068B6BF099DA2CF7FE74ED4F11555AA94A2AD284BA588F295173114FAFF0246051310C1F3B9D8252147A9BD026F40B0BE3ED1D8F5C2B4BD743C3C79BF47F0A794EBE8FDA67F809E99B3993F2CFC8374679874B6507F946D109D40CA18A020589D8CEEAB0EFF03EA760CA11FEB33D59BFB64C6F23E53B1264BE2348E839D9BD764A8FEB9103108FB6D801419D2CDEC81CC5FE134CA5987030080C300D91BF58C5CF97EDF74DF535856413102E8DFFBC5D4B6B4DD3331C2B869C03A16D59716D1537DA4E78727691CFAFB9983F75A12EF5D1D6EF13AB1E343E0D6B67A9E2F29E9F7387B89F441EF71AFB87CB6A3140AB8E2C3B426B65366EB646128DE40AD78BFA246D00244D4383A72222C6881B13F2C9084982134537CBDF92496BFE1E2325A9FE909ED8C1927B9E9C6A17F8A926E4EC1D2C13CC5586D2775E67ED6809305FD9716CC66D7EF6C1F988154B6B54B85F4359A1F7A1F5FF55DA151DDB0E67E8985C1CB39434EC11686231AB6790C54698D0748D52642B023D16FE89026E3987585A962DA17855E3DA727258947555700C8BE6216307AF9FA1AAB4A6625E695F0C856E04258134900F014E67C785B4449D36E4ED02973B7AFA4DBD257418E493699509A16A641DF466D98204A86929367CE593266A142DC6296DFE6EE6BCC7060D438779F040FDD1D225985B108636D99729C9B6C96539D29C4DDCE10E54E2978FA558B98A4E594447905F25A794434B10B648D47BC7EB8B068B0B41FA7F84C481F37BD02C8774B22D6894E89FA68D7BBA6D11C50454F8B8A6E035019F1082A6174E17E8EA6B41654B1BBCE94D16BAE3E6192F8D0A5E90AB8297FC3CA6E409E9FBBAEE9456429C180BF7D857C681603F3DCED5BD9CF768AD2148B5B5FE97494A4CB53FA732346CD05668FE03F1A819C012B922F9B644E9116E8D59C66FCB9642A1D7C980FCFD1C925940A2AABE9D14C0EB1ABCC01F0A7E92D4E065A21003D85F09B8417945900B50B360336814582FEBC40DAB0B2A8AACB48932A804480A726080D482AAA01064BF021B20FDA5EC3F55D6223D69A5B4804C81A5922D5496CB0AA92529B02C10CD024B245956C19A804A01D2040BAC85C5410E28287552EDCE528839C9DF8A893010A22A208A289248228B2C8A28A21295A8452D1AD18856B4A2139D044880E8452F811228063148900449B0044B888448A8848A518C122661122EE1621293444884444AA4444D8341DD8F9D6021932FA933A900A9AD96452CCC2C4CA474A48E7F0D1643E157D828B8F8B0C9E558CA36B6770B2C0D5D2CB330E53EB29136BEFEBD4395BF71589813E24F1DF8370E0B33AEE530EBE25FB9980FC5DF77C5351C6EFE8383853929BE96CB5210F4874E5DD870F1BE8D8DC2E700A1385DA00BB9BA69F9FBAA13D79ED712021204D9CB661B99F1A90911F86187A240298C30B3D06FCD69B8FFCE5FF5F8B6A98F2D08D245A57AC463A8991ACA52679747B20FD9C94FDE809F410DA1B61AED94ABBC38199C2B0E26E3BD36CEBA5165E77E8016C3014BD789B1C8DF9280A4EA086333BF05C4F709C5F85B9E429FCE2B6107C6FC0D8CB39A91B27512281AF563F3819643D1A6D03B96FABE713A803857A87C6952DC47DE4E74D0273DF118410EFBC27275A1FF5C81DCD59297E1F4FEE572AF30FA074BF08F7AC74CC3919BAF5F622AD7A3A8ABD17B39E1AAEA21C3A071F50BA7F36067CC82B6935DEF8DFAE1CD6A78CA698AC2CB3D25A2284A3451F56D455B9AF43DC6E0B5EAD4946EDFF98E2F53109C07FAAEBF3A937510912969CBD36FD848607C61E2A48FDE3062C614217D7726359F6898DDE66C3921C4D35FB26BF07DB12962A348D8C3D4C99F288D64A0FD5526863F959D8ABC85444BEF7E05C27C1130D61F429A8C5AF649189E814E15623C67D676C743461E5C9C03D1105EC30892464570D5A02844E515E47282C3C299F65989952CCCF5ADDB8D3FFEE2D27E5C98A96242A65B07AFA4C842E0A5544F599512BB10B88DC3EF33D3E3D9EAF579667D5AF4E49FECA0D8C73D013C56021AEDDF9B43E3C67950AFDA490588C36C6A819630C7657EA434CDBC61DCCCCAC8C6E43F8A0E8E9CCC270B39B36AAEDF47AFB429D1F0576C109848A37CC0F58C19E988F80380B3E484CA3667D866CB4CDBDE754F1D9EADDD5050324419E49924D6C6DFACA4545101B86D2C32594ED1AF76454E02E2387229B0942CA7497AB7A1F7976CF42EEAAF4A3ADC4D72ECBC123134B2B744AD0E49AD1D060A8CE36E1E2DB99B50F6B42AD5742DA8702B7C3EDFD18BCD2FD4EB0ECFD79F5A93043025BA87C50E3ED8AECE297B643F9A8AEFBBCBFC9F3BBE56CE555ABF259F6882179B61DD507616AD388DC6FD109E11D63CEE2D9D81ABEB11CFD63765E6CBBCE7400DB4C4574A641A7112220201C9EED685EF7D7D675809728A201D5883EB567EF71DB4E204A5EE7F125418A20F5EDEF16EFB52111436E8DED124F05D7BFD6BF4DBC705F1B459DE17C0CFCDC8D703B4FCAD838F5C4B76E70367C655E6379AB77DEE27F32DED5B985E2594D0FAF131C6E9A4F2E5157BE5FC62180FE5DFB83366424CFA7BD02FDA0FDE44D86A0441450026FE49B896F5521C833E1D07B2110FFAA4753A2B8C864CE8EECFEB53514929B95D68CEBA1051F7B55A60881BCC84D9066F14D610078FFA2949A2C0B34C06FC3E3FACD09D2E0940D60663BF73988FEB8DA8E3BE62B8D2571817AE7A55C92197E583B5CCD8881B2B13519DEB0064A69C26345D2A8EBA3A78D69E64F638A2D85367C4747E9C8E935640940B2183EE403507D09031F50C8C61C5EFD3C404F07A4373234FA6977588A764E84858E9F905AABB9D408B4455BF5EDD048EABCD1118A57105F235B05D5366BFED4C54097B3765C41C7B3D8CCFC886218865E39F2D6D5A9FC5B0C4772C6F075227AEF04BFEA06D5CF4A8BC2C3E1B64A52AA8003E161B3328943D52D46CD7FEC95DF8BBA1DDD25A7ECE696D202A05D544ED482031A031CF051A554A870AB9EDE4A1E0A0B7ABCA265CC169553659D2F99E0117CDFD31001AE3D7968516444CA543968AF1879739A1CF1D9DC1FE81561998E6D3A4A7F721CF188F4544796D2C3A8E8D84380F2E9F1CE34B4F65EC84E5EBA6C1BAF0CCB2C02E254A1246DE7C00484F7DDC4A309403895D4C0089F15846107E5F503E44BF9F2D95E0878AD0404082FAD0375679009A508034278F52843C5C29005105DE8AC1A10183F1513031C545A355440A540F5F2DAC33E4315D595C6A7D8AE04E6BC4C898C80A2E788C58D3730908182E7FFF37C516508E4537404EE450CD2CF1312358A12E328EE61A2C46CC9FA580A6F1F52EC6A1ACF4B124962AF1E3811B7B51C8E95A100A60A55CF8829597B2462404A48460F4F35996269737E33E9085D715BF59A6974FB2371607D83AABBF5E8D884D83114647DD08FBF8617815F2B3EF76891A6DE7955724F1D0DAD2184EBC5F06CCC3E2B4D3FA40EC2A1056081B54083A8C6125FABF6DC948EF6C30BBC1F1B6AF13C5D353728A6D4653D50534045C6B519AB92133BD6D3CFC42A798693C64EFA20438D07F87C8516C5E3B7CE05327335F466567847A0E9713267AFE5D5DC8F7803C14689779212C055ACA04FB6F2D5EB47DF159F15DFFAA28E3274803E874443D05DDAEDA39FC3CD975653C3455FB837CCC5695B2DD1B97BD0E8ED07341EFFA4100B72B775B3F2C3DFEF42B9C245DD62ED791BFC3A40A268E38C73670DFDCF0B00A38FE38323DD7C2C334B2433B2DFCAEC7E2436EDDD9F84F238C3AF83FE376555A6307E868764B0D08DFAE290706471A69667D0F1F676491F10E42858B52B09C47AAC45144D8A03E4A389FE14C7B7079602B4686CBBE517119A1C8A54F151440B0127A2873D85389E4AF4047EB137DB97C32911B50BAAC6AADDF5EE7789E69423CD6E6EF3F203BA93D47C324F403A3557A1DD8391726A3AF745FEE138B5138AEADBEB6A899ECEF933E95CA25C4BE2314BC39FE16E7DA22F696095A2AE6640678B56C6D2687994E7F58A969A7FA3FD4FB763192EE7A3419D688667A35180448D5DEB9723EE52B8C41FB8706E8BDD07870C2D2D6324A89D65938AF4D7658F5809E1FC15747EADB330F5FE1F3B186AF670E6B63ABE65B20E6F188C56F5929F6E1159AB0518838E196114CA5759CF17638D7DBA1C5DDBDD3B237CD418BE98E7CCD20C4843D1924DED6F6F88CEB07393B464B371847FB370B16CAC7E7BBBBEF0E71A2CEB9ADAFFA1A96EE4B0042C3889E9858CFF513186120FD20207BCA7391281AE257244FE97B32DCBAA5C2B89BA819F10235435370572053CC14D0719D6B01D5B74289007B0E7E62DFBC801D0165675B06D09D2B76F1617556817C51D58656B72E732F7854798DEAC8F6333E7A45E0E664C597E0C24890B7A7FD07B2916EE995CBC12AF407979326873353DF3B5BCB9620926AA10369335D067936687C7E2B04D4DAE00A287E112D9974201BF2DAD0B748DC3D564A3F6C6AA5C78AD70BC2B816F778A1F2B1CA143C8369DA07FA842A29373F939C14FFB8D4656F5225A0C712AEECBC49DF291E448DD524EED843256BF4E0D9B4845D67E57B9ECB5CE93430F34D42FCE0E2BD00B206F0A798B2A76485400643D6C3EFAFBF5BFE814DCFFD75DE082DAFE3D200FA74C10E4FC350EFEF11B2F783CB9A10CA13F2C6C7CA9C291A67B5E9DD9EC68C6B35462FB2DDDB34BB82CFFC6CF80BA2A8C0D8FD3962DD9064B44B00E94B6990EA4D6B1F05F9579A2E7E7753E866019E97822A2B05D1C6427CD642887729B99A13A0CA6380FE8E2D2917F0E3CD7332774E0FFA8B00FF26B826A6106191871265457B90F6FA970EA29185AD6E51B7747F3D728B9BBFB12806DBD6263A4B8BC80AF74D30A6D268FA673254CCEEDF36EC45152D3FC8FC437388804642EA4BBD3E23811CA593C445E4AE357C142C02D282510D41CD66A403EB209C50FD03FC347437A31229670FA370F4B5A361188A5F8F6B8B565D8EFF36D0F0D7E9A0B86696236118D0B4DD4C80FA3E8DB288DBD55CBF486A8CCDE5E1CA7FDCD8A6AB0A290A41E00E54649EEAB80B1A967066DE72591BAFECCA5DA6B1CF688C5835AB0AD95D970C0D52F697A0CC4841BDBDFEFE5B04D11F89DCA1C4B4FE3C33401348FEE6CB6EF0F933267FBE5D165FFD413FAE39200BC141DB4FB5FB77F26577CAF04110A0A249F1034FE82BCA7794DF99F1332F155067A0AB9F856816470A3639009250094837E5591CDB52FBCE8A9DE23662912616C87871429A1E726A32011177B9383476DAA6F50D97955D5E5DDADDABA3E316257E721EEED8DEA2FFB3E9613F8D4D29149B35391E04011CC23563F4075A9E25EB600AB0972893310994DDC1F563F96A5EAAD73E75D33840EF637F7FC9C8A0CA980BE356CE0D12EB19EA35FA28D6B6CD7D1F5719F9ED63CECE0003B0873FB98452EC2EF2DC5955A94925E4981D7BA94E3D6D9CDE43F16EE318538FB4708F02C194EC5273088AB408CFAA1AECA11D19F9E726CDEEE9552D544C06F5995044CBB911B28E4B1759503594619B2516DDFA1C216393B29C105B4A981AD2711DEA6AF4CA9BB3E6641C338CD505498850363719BC104A59540ECC6C6C136CBF75AB645007D89C1C0B8BA8D04E36B80B8E200D9C35E6E9D8849E94ED26DB22518C6FA99BB99F57349AF1E327E7242A270F8FA948F91F7CDBEBFD305C18F723B151DCF85DFCCB06F5226448BDF98ADE711D4BD1FEA0805849E9C90291F2778746DA55600A16FB8B288C32F15360EBE63DCC61F89A27462E45BC5F27BCAF70FD233965C7333B404F6EC0E851CAE05FD60CBCF3B8163E0D40DEAF2D572EDF65C8B0E9795A310A2ED1077F2926A5583A1950845034BA4E3541921F1208C6FC8D6D795D945BCDA99CB0BA013D8BA15E493CAEAFAADCD8434ABABB0AB75732984E6709CC7855151A84D2F74B2E723DDDF23C687F6ABE541C73BA3486AD5BC37F832F100E80D75596D1817E231C5ADE6741E710F2E10AC6A0EC4A64962508EE49E789B1C2788A13D799999820A2766B6AE47DE9D3020C68816B126E9A1E5CFAA1A233B116ED130501612D3444804403E6944F25CCFEE9B7DF7FCF867663623957291F7B70BEC1290F7A60EEA8D3891620B5CA7B7FB27B01EECC5ECC8553DA1E347EE74BD2D70EE1509C4B26D3A1A1EC446380A094E648034BC5EEB2A738C4E23174CF7E6A0AC6050791A2AC11CCD14EFAC44FE8D1570F407CF761463746FF220A0D7E0D08ABDC0A4378688D49E77533FF0035ECAB7CB9B3AAE474B294113595E79B39211006B985F9007C47F9C4627A8C9B3DC31A9178C062DC0DF9AE5F3B0491E449CA22FC5ED1BEEEA6AF0187533CAA74B2B8CA1AF8378B051D49DA32B7D68BC048484F16633166557574EC3BC159DD4F6F0C1A4E8B5B3304F4FEA1A1691D02B0888083F7FAFF31A3A07630125AC1DF2559FF069D67E3219EFAC8C63AA361EA69EF2A18ACCCCD52E24552DD0C722DE195690950117412356766E5C505B47BC8306FA1B89DF88DDE32C089734E8C0C14C60293615F9E08E8A80E000D23B62C046391F9CC24A0C7B640E9F5C22438174DD1C9B9D9D2866F96EFB08541806BA9B91B042082CF06DF5E1D37635080A707EAD078A353DC5E33766403BE668767C28D0E95230311E4C53D0BE2B9207D05F2EE071898D1149B4DD3D289F3546C19960B90D33CF3DE0C28C0FD0A79C3C2400E2F6E6282191FA606611149C22AB475C0E70970A849BA9C98D3D2770895517257C585E156398E05482553F7577173A0CE805B2680F4A28D2AC0D0C7A00FC6EC05EE30712608F23447CFDBFBADBF6898DAE056C718CD0043F1A9264540FFB77109059DC02909BC87EA7D6AAF1AD526C56A4ECA0D861A91AF9FCE3E01022FBE8506663E15B1F33C9BD018FA3B9BCCC00EA2ABE9027DAD67A247B931E7F3104BAC483BEFE2FA5F1BC0FBB1C47C84AE7A0B17260FFBB61C215694AB96EFD5F9C0AD9918329DD6A5F2694B89B268F306B770278D96E4F5EA149016F7F30FFD0591720D3FD9355908BA24F86BBCF47569904DC465AF47C91CCCDAC6C80C9497A8EE0E6EB29E023AF9BBFF490C80FF5EEC8B57258CFA9EB117B596AC108CB0B20A66225BEF4ECE245DF7A3810FF3DC946966701C78AD338819AC09986E27F9D7F1025F8918BBDC684095981889D08677FCA69A793D3187630055FE17E1D60E10161B6435B57CC01C9C4848ECD5CE565FCF6339CD76425CD0BEF6C01DA33FB1D105E504D0256970D530A42F1F6582A1FAF736869727F87573673945E17D9B0F83BE447CAE3738436547384CD110F23C8551B3E194411D28E2A1BD5A0AD294E81BAAEA400442E9694E0DC7D83E58C463509FAEF140A12C74792E0641AC159FB855BABFDDF38E3FDD09B7910A30925C350DEB90729BF02A93BC5BA5AA150655883496DB1E1FBC46C86AA61889DDDEA271F5BF85FC580D1ED7FBC5F1838F4AE0E02F32F87912B7397588CABFC4BF97904861F3E66E551E4720B830172C22AEF235E4BF2EE2C10B461C80DCA14CFA38B6633A68613BB68AB7C033831102A682ABEC620AC2FD90AA126B14A63205849813C1BCC007464138D04860234041B82407D67C63F71B0360A6EE007962C8C8724C3687F571C025ED39CB82106E2E107949979FF544BA5E7F1EB1B2CA3EBCAFC5DFE239E90406DD373C0566648B9D3E2BA591A20C3D9D30CC7924210DB210BE243DBD787D0F50F15B9782DB29CC77E12D5D81A9643E5CEF3F0AD8FCBA466BD89301CEBC4C71869D439C4B819DB1E97B41D8458957681ABBE3A97CC26C03BACAB3F18B89B5463410CF13F506BEDF46CA4EE080AF02AAC4D88EDB6F8EC6F8475DCD57681AFEF7BA35E5B92A0887A0E93ED5FC1F106EB95D7AC250B3252A979AD27419892D6A1F495CB8A434215D74EC9EB81AEE4E02F2C7703CD3E1B219A3EB0C9CBD845EEC5792C1E8C034BD007A9FE921A1C9265B75E244C9C9DEEE6911F045806625802E30377442E3C5D8031AB2D81E014D26C24BCC84B0E89D3CB6E4029BBC01698B391C1006FB338014C96541634A0D13134EC56B53EF04C3D61FAA3785E4587B26AD3358B2A1F7593A969DB97C41799CE408EA3B6D8230F22F378EF35B398709350326BD0CEAE4A17B1FA1C23D6F704D2B522842B796C0E564EB714C1E03FE7585381B6FA0F1A932443DAF020987014B8474D53EF3E5779BE24A1F3B1363C17FDC0A34F1CC7450C6D40517FD71FB9226C01A21F918B1619A3CF6E5E9900443F7ED557409987689362F71A1C74CE725766EED30E158DCDBF8DC890B025D147DE7BE2BE80280708344FA84E94E16BD020153EED2E3B84B9B3F8697894E8454190C318A4E44F75D4851EB374C097E76E344B54A0300AB30BB4540551D16AEC7EE7DE858877C258DC0F03136407886A04C020B30F662A214C446892F8B4E41A698607B40417D63E756C9994655E009B87D78DA3EE4936DC7E765BB4A9835A2E28282C15999A15BCC444073E6E2C38CAAD109991CA86441B576B6EE328FDAD4A0EA7D1507516CE346D64F652F8C6050EF9A1A14E820DF04F053280428C633E9C238C2E14287807BB9FD958432197C0BB88CE5D8E6419EB72D766A4722F7A6E27AD93B3E7E80E24E58EFCEC9737924F0D639ACC74EF5A60E25A2C2D0E9B44D3E9B2017C9DBD3E99F7BAA21F6927E1D304888ACC5239EECA1F24F9F01B480ADD5C6DFFECDCD559EB01A0E47B4411BFFF5C1E87141ABF8D51A70493DFEDC160386C4D596B8302FC3FA95A5FE66867B37A23E3E7816BA32034876F490D3BCACA68C3A9899BCC4686A6DA02B0F840ACB44757C4C6B36F9591BD8B4D952D19D882AFEB6A3B05EA764F3F8107AC179F760F85CC4AC7E5E4B5792DE30D36A8C490637D44EC98A38AA8A8E221FB8D040EC6D1554CD43461346F0D100E51B0FD60DF137649F4A13CD7842773899135135DB59614C7DB956809C4969128A9BE3FC8420D735727E941902FFB10F42E6603E3E3EA63EBD45FF95731D9E886A103AC05C06C30C1FB0E9EB597B906B3C472973E9A7B1FBC944BE2E40A6D65080352414941DBFFD1C4F75913C26E40CE8BF1B1FEEE6D97A934318AD1A1E7DB68897245AA31B958ED85608BE4C4EAD35D3015B4E304501EE0F7B57B93F6D63F697FC18DEF6D66833C6D0166761B95F8A76C54C6F88D8DE3E0D6A581E89F5486281C8803204275B007B65E5EDA7617329B51110FE3EB956E6B6370C6AEFEF09720F80EBB189A2713967B92285B01DA66CB5B429BDFCD41B29B8265EE5DCE3100415F2ECCD031786A8C8D9FD4DDD508A96A963D530A8343D237D83F399600CF3C402BB876BFF059934B97E7E8E9A3877F2510B5897A987A5222289ED39D2BD4346D77547F7E728B18483CF019F583F423A13E34F35614235DFBE746500EE481593966FABEE38E8BF906F50CA51F71E1FBBC1F401D092DCFFFF4078FC789A9F6F6D6D6675828FEE4F882488AC14052E0F50F77B421A417736143E12798BBFD545561D62E483C9C4603E0CD51A1642A1DB467906EA40A3AF22920AE87BBC447A1B220329B243233BA9E3417488B5F67CE7A96BB338B99262265CE9B6D821C28D66B882DF0EACFF0E9940CAE65E9343CB92F7C44AEBC71E7B0E17237597FF28B9062F17CD99182E40973A779405BC95D01A3DBAEFF07997E4827F2C64C683E84F128DA950EFC3EDE6F3B143515275995F45BE2239B4AF8FF94D2E9DAF317EADD58C7103059EEAB02A64169A93FA10C26E5EF1E00F612D8FA2B9827E4EEABFC8C2728BA98BDD5897E6A71D70E9CB4305EBFF24B118BABBD9C744740F657C283D0101C89962519D635BCA09ABEC2071EACCD943BB1EE01A63E89039C1F1E84972E1049293B8AC0E5C000058621C2A7312502EEE5499A9897807C15ED6DE44F24A12C32E2F74AB82C201AA80FF7CC632870158E2343A9247E5FFC4E786F903F19A82E6667199DD906B037B7A221244C90954725B010CF9BC34A4FFEA0A02235AA6374CE65AFA7E4AD7C0033693E4C53EAF99184B174FBD98B68CDE17F91E0A255ADE1FB0F9B903F94FCABF156A0112D013B62B589279B05AD167690494F26750CAB67ECBDCAEA40AA88B01EC495AB0D2A37D936D5E84F4726971A41B4F49A1B2B88DA38F4134EC55345D36C1A14B33E6FA6566E205537A40B5E8AA3CC25FE2A96CE2C5A07A876FC21C05EEC9F518B49FA1860DAA5865C3B6157061305E65C2A42CECCC01AF68BBC67BAA4F03DFE6B825A2A9759011AF45A79631A4960ECE0A7F240B02EBBC21E051DD95FDCD50E036BBAF59DAE73F94B505C9D5A4867E702A5D4BD1C9310350966F1127E9BE9648E0AA71387C4B4E5BAF065081FDA24D2132A6E6DC9D6A3A6F5D51426528792CE020625AB483BB07EC1C8F27C3595A59F7C56F0B48CE12655F4A864E0FB32AA366AE5EBC2AC7929660059FA8FFBD4CE505809D617E4BA4977E2F0350973FF342C36F51FB08F886F835209C50ABA1B0BF004E2D35B349A60364A01DAD231903F4955D757F18E93373B7EF60C1FEE4514D76A066DDBAC08A5A7487248BD0AAE86133B1AFF448DC879AE9C2A7F65B348F28791287A412C628C7716583E75BFC3F284B405AC90C4907415517D72442C9074189F4991E1B04EA3174FF544299E79FFC05DEF0019616500CDCBAB6AD322DA7F3F8D515EB23EFE2718D3D609099C063BBE051CC87582938FE11CDC0732603C0A960B704E52388C8419488A1905367826AF331CB24AC4A30032D53ED48DAAF505C9492DB2A54401F5D6B4E76605DC7583878EA1041F363DCB4F64B6A66894C83E09619C70D314BBB3462D01E71BC92D6325DD9EA40F1F0687EFE30A36DE38F7803E3D8BDEA671F1E97989B200E0A726DD95806CEEF5D6040E9D6544B603C7005F5DB1795989F2253BFB57ED95569C1A407956204A3DEDC743D6B70698B9486497BB9D6EFEE009A0FE95F5161349CEA47F9F58AC3BA207568758679C67AB5E84FA4E3073518F64E87278B2E778639BFDE62BA525AF306253F4E4A0879A6DB596C7655796D9C9E875C2FCEBB454E14C4BF481E7E027F04130A491D57F6E94AF82321A3BCC8F3CB7FCAFAEF0161727E66E0130D522C55E4777FF6A837076749920821794B95F3A188A0A5336EAA99B15CFAE30854F3EB0ADD9B77B37A1388B929501EAA5DFFDAE5639BC1818947EA7586CBC99EA6F5D5AFBEAFF0AF97F37543D8EB4AC18B82BA5A8A0305EE8DC513B68216DA8955EF5018D44B81F4292E5B5F95CF59B16BBA5E2E3F52AFD467DE704A47E983CB981AC550A1FDB640AD3CD0E89C390EFB9B68E547C1D811E889D986C847680745C94C2B668077204A854E891FF5671B4108ABE6F30E928EBADBB236BC05271F75C6C0A226BC23508F39D63786E6E05195E7C838C934665084C91B8B8D422C101A69EC71D5647F78B9752752C48156B423DA48B583AA76718CAEE539E69445809D39A86ACF72FAC3B7F56B33B1075D04EB8D2C1874DCA70D639055A66A5C4F2BF85E15528995B8F1F258B6B6F39FC3C54D5DC78C2402497D93DE70805FDEA873228FAE28466E9559A209E61CFCD701CA923CB566E1E22807F4036459B3C45D49BC9CFADCC06F967A4F80C9EDBF0AE65970099915CCF3E5480ADF36F156BFB9AABAAA1840F67E2DD3205DE3B9DBD9750D72C15F0FB19BE396278FD1F132248B05DCD3A24B1F0C4A39342B9A79F1D6648DABD4C59E5AB6F655DABA4574C42E2DB497DE69A26B6585BDD65BFF98B22BB8FDAC223532F98D0F9D5770692189C630E99D2E4B40B7B96491604703A0298BD52EE3B12C8A7924EE8908A5D86948722E5FC14F61841D7470191CF25EBC7CB6E9F2C57B7FCF907B205C97DD73CE3ABD54F50A31EA85E305276BF38F54CDE4A378A57B3B4F50FB0F02393516104505C6EECFC5169FBF01769A729BFAD9E19EB7C49AACCC0CF40BC5430D67BB54F2A76A2EF714DE2D0989482851BFC58BAAB42694740B45E2A4A8E001F92DC4336FE9DC3EE1F1BD13415D869FA1339A2F12BEC0A2744106D4BF9F04627AD87BE14D0F1FB9848EB4E0CC22E158B8D950097816CE0DBE1F68F50B0E764FBD28C6D8BF9964917F9BD14822A0E9BEB7CEAF5F94B219B85D3CED5B826378C59AF149FF68686DA6EEDD8F6C4EEF80E8EF25F293FC7DD439DF7FDB9A65ED8A234E3C14A3657A97590D292CB55F9B06BA087E1FC515BDB9510CE3B12E570E1C6EFED9FB01A360B1D3FEB8ACAD9C0119C8D50824AF52414E5EDAE24299DD2BDCA58FBAAB7D7490FAA38EC4F2550BBA5FC928FED46CF6D7D3DEA2710EEE72447243E427B752391240D25CA689D224729DFB77E859F4990CF5C418FAF756E4FBA0361020035DF26D42A6914C4F0E0655B08C0E844EF14A3FECABF8133B42DFF975EF9948E6B35FA96A146AD0553C944051DE647D8D7EE80F5E3703961C86486BB3618927D313AABBEE975740205B51FADA7D00B3344F1BAD4BA62241F3DDB5EA54CE497910D482274E5926474D24A209C6313B00F56F90B55599C61736707F22D81049CE55379DE1066D1693C86B8E8EB5C169A8310D64BBDABA0BA8483B91EB310BBA2047C07B89A715AF51473493EB4E69B96EF50C70124CE13BDE6347686375AAF464243C197018F99209418B3CA25E7C64DFDE88829AFE0DD747EA8F7412D5F065CB42ED0A6D12F33F7C05B0787059222A78BD89EC1E89FF612C93AA98DB01513E63924ED0A941E50B71CDC54A1ECDF3E2738C66D60FB9AFE090DB8D0539F65DA07E009DB794FCA1C3E6E12C49D70B803F590327B93A646ABBAFA86DEAE7F9BA9EDE876FF5E7BB195B7D967590E6BD429D5F354EDD0D8F01E73F6D27019FA206147EBD1B065D29C64A275EE735933947D524A5AEF75EFD27048792E27E478462A6AAC1206014EE8F7B10F2C3E51F5E612FA66F4D8E7BC6F70AEED925F23A54A48DEF1CD07D204BD909D7BE929742DA06CB87E4BA1676D07F4668BE13B0BC50A630F0E87F3858CC8F74E0672062CE25EBADFA737B3833CB693F9DCFFB28A774754C1C0D30B58731E7C5FD2E4483DA4BBCB3768713288E8B6D8A18C78B5148972A5ACA2BA830A61BF145B38D2210B4E4F76E10277A23CFF9CFC70C062B228E215A9A2E838C1DBC9CF286792909905649B2629D5C3C59379C10D7B68F74300C3EFACDAAD3EB9FEDC78A7602DE40547B3C60D33AA8DDBCB998A085A3FF3E4688EF060F669BFF7F99976104CCA3C3E07ED7765BF628E7803E048640D9C595D4457B37D5A68AE6D5FB033F706F56F503870533CE1C80E20B7F8F6B4E3A409A80D54FDE03C083C8E92922457F1017140917ACCFA8FF1EAC1B7F3345BAC7122D905B74C6B2AD4D0A8A48B9EA602F433E50AD2D646C3654C226A7E978CCFB6FD6B32552578F215404CE2F296FCFF337A9AFF9E31391ED50AE3854D8DE0760BB19CEF6F189234654DC7F4C91C00594873027735DF4E01BA30AA407C3CA88DE16717A35D6642528A2A010403411226AB0AF9F4496C2EF2B58E705AC51E35C3E93D74583F065E45C121BE4B7A840CA28B119425F217E6336C1E9F36BA9566D0320B3472D9D0FAC0380D7D4E69B9BFF8D75A58197AB06F2DEFEA82B7871FE75635EE12FB42FDB822350A8D1A181D7FD2BCD480C037BB17EA911FA58610D69B167A7E0B84DB811F17DFB57A39C81B7D2EA27AC2FD0384ABE69EF0D7061B1EFCD66B70B50D9CF71B88FD8C8B6E400FC0CCAA7E70C47E1A07CFDE7F28B0EF181BFDB9766AA0BAABE38783944999DCD9589A2AC90E12C5EFE935B7E5A04C769A7F320DEFB905A53163050DA89FDAFADE87D25B6DF5C1A2A0BFD5807252A4F7E563D3E534662A5C27B826584A269B4A0464DBD9D05BEA4B3EF2CABCD0519F074FFD98A6E6B6EE6A60C7ACD3880FEC9A3494EF3B679FE75D0AC036243E21719EE2400EDDD5E2C5E090BAEBF7CDA7E4ABA3CE2609476F017E8FEB89AF515AB3B2565A3D16EE1DC2EB955566EDC791B2B06AB0B06923CCE14A3FD404580DEDE8FB29BF92CE99F5A0859CB7FE8BEAC9DE9305A187FC99E097AE8A598F51DA57E04B5DA890CA5431952F7997913EAF9D5B0DB911B99433F27BD92B644083B89C29DC75B683D95D4BA9F482417F2BA6BA43379D6A729EA7CBECB1A6E794D324FF160B9C96ADD3D341A93CBE07E2569B92D24A1CD3546B160E6BBF57D5CB0F234D5A7336F7674EEA0559A10F674A0A3ED3A1EF55E9DC47130DC9B6FEA2510B099B1A7E4DAC61AD41D33BF4C33947C09F132BD6B28B3CB04CD1138D371BCB02E85A6667DA266FF83B0B15B7ADEA14C9A83B30D8D0F9552765834E6631E680C8200D4F5A12FBEDC385860CD65A836F72345EFC51B7D1902883BACC23281A0BF381B14DA574A99A042D6A85402FB9EEE18DECF2DDA34B760500E5EFAF444B501A675A88B0877A5DA5348417AE9CB83BDA6156269415CCB2498BD7721FD1F15FD033FE77685FEBCB58C469D000433BD7424A4FD724AFD70ADF05ADE3DC75696B0BE01ED7DEFFB69710908C2CCE6185B3D8FA23F33EA3675D0D1F880C93EDD6887D6627C9C1B6FE4E9440CCF06A6D942C8E4C11DF9C75F44E83A3D0357389F9212CB8A6251C2A2EA2DF4CC561736EBDDB735C519F15F7781A05A3AF9BBCF80C848424405CAA545911E1609F346A2099EADB1D2BFED27FA4E33A07E1A6C18A4F8DA9C71C9C61D2D03DC98C8065EFB404E9A36BB51CC5105C6826FDAC616EE5CF21E8179223B06212BF7D9A20DCB551736A018FEF7FEA6705A3B98A524F2F15C0BD9E5DDBAB5B932EE03B758150AE8ACB89FBBD5CBBCDD9977C74C0D3AE009379CC8309195529C440F6A833778654970CD9378AEB8AE9852C4D613F923C386BADE7E042AF02AE6E28C386878AB6E7719EFA88994E5FC4F56E83EC36745120D2536386B3A29E6A1E4D1798636EF372D9F4E7322F7BD833EFD115DBA037E160D5F0EA7442CB7E1E9F06D15C18540E50212C39EC454A6769220AEFC7A7B07EB50B3D61E5770CF73DFB9514FECAAA38867E59517E33FEA8D13B7B344B1A23C509A4146A3763F3D9D7FA5C4F7D2CCA58F7F901EF2C505B95E62F66F464889385541CAF635AAE0A0D8D8175AB09594380E5211F76DA0EFB370ED87877849D73E50259DAEFF86D589265BC9CA71FA6B1F90CAF47927B45A94EEFFDADF9004CCD69BB6EDE0D8FB8BFEEAE6A46694C06B943B9E1FDD52349CCFA6040409294AF2A8740E803A1FC36CB5CF6F377A581224511684291D424C7747B2251C53F3600DDB859588275D37E2BC52FDAB79146F08C737BC9F986A764154359A41B517870CE1BE59D20818C17C6EF88EB57E0DDAAEC3BD3AFFB15B9656916485D83EBCDE1B138F85F7F5462F77D777A08E3F94729D5538AC71663815BFA8517F7AC4F7C2228A28F5E79B98CEAF153191D56367CD605FB852D8623837EA42E6E851E3719D971AA4FFB95B727891749462F80796A73C99D6565FFD74AFEB35A650A64BA2AE0A4431692A4D5DA7CD608417D7B9A23D72334180AD25DC8A9C15ADA8B37C329710E3C9FDC09FEC382ACEEB8831F699861E7886B879ABB46C1C62DB40B7F5730E2764FD19142637269B9FBE95BEE2513486FCCC1BE5B567C192542FBC489CDDC3DB008B3ADBBC0D53B97BF7D56A606FD0925160248A76241AE934F2A4DB8873D23E4F8506665ED1B1CB6A8BC7F669403D22F9D3148761BDA2DAECDBC67B8E5CED20C75897DF4BB1750338740420408FE9C10D2FB2699378C9BD21798BD5F854A304896A634277196E43A19909A714882114555ADBFD8EF077E8FDF1C6F121D0ACF2885DC54C779D43DDE0B919EB1772A3327C6190043DAC3953406A3B5A6C33936B3E01BA396A95984009874863D2EC61DF1F253377405A41F0708F2868E7460CA0D45AC8698B7643A19A5706124B174F6A64FFA07E7EBE0D479B8718C890B0907A9DD47D8AB579A485DAF654EE82D9AF93B63B23B8F64709297AF74AFFCA1C58AD9445F08627239BB19FCA3A1D90CE78638FCA0868FC7D641E863CBFE790BEB23D9F77FFDCC791C27C4542FA4CBCAFAAA53BD1F25EBFDB7C08797A89CC03A042055038BF5B11C160E12F26B7FB3B817EB7C26BBFFB45AE296B8579BE17157FCCDFAE8BAABEB3D12DD5FE901010DC1E93B26B4C54479D065E7AF097A4111A79E0CBDCB4A9A874994DC862668B89D7606E5CD6FF234B981341651B9B5881E262B34A70B85FD598B7318A3B2A478D80617D2DF626058E00BAFAC6DC337D048221FB7BCCFE6BC34F588BEE9887D733C5CE5EAAB7F5B017C1D301CE0F785ED948573AA583F4DF4403FA3096B6ECB9E152F21A6A1272770C0FE85BD54F479CDD92D2918AF3B3201CC04A99BD35C7333BDB5429F1CA9527254E73FFEB37EB9120D61DBFCCF249BB40A5D6822002EE54865AB903C5090D62B0C768E373BCE3FED583286EEA67C7BA7825904EAA5579547786F130EA995834B3345EEF7F031928A33022C797FA4DF6FB4B9E352F5FF8E3A6E3D655B9B55A11A619A1EED401A7E7CDF0DDEA07A7899497D2F886E4FA80ADD74F929079325E7F4A3F99A6BDAFEED4005CE4049CB31C916B17C626888AF2F90E9DD46BEC315BB5F2DD955E1C7FA541AD674574AEE40C3BAF049736C3CE991469BF2E6B1DF5A6B7815FDF8AAAAA60853A55CC12D5B70F7FCFF0D3D1FD67CF27990AF6910008071EF07DB429DE87CC579A1195100329B9B8EB78ABC0596C68E6F6D254387E6682C6ABAF0029114BE7A0B81C79F627804828E0C092BAF153449DBD50B8DE1D07077180DEEA663CC2D538D631AB7D2CDDFFF54259098D570DFEE62B8C4875C5E9840E5C5058FBC58A4F4046E7AD91561D6997D4898F14A297AAE1CF160BA71AC7246212D92E389394983EB23D40618FCE10CE305758502A5241A82244998AA68FAA4D0C8A153BA4D275EF29124EBC63A336018BC48177B0BDDC240DB74466553107481DE2C6B16F487A4A51415B2A68796D4102D3919AB944174D0CFB67D1597AEA5002140165553E902433D2F7CF634FDFAB91C89FE2E424576774A02F76D4B687F4E1D2B55F7BA9BFD055B5046AF84F2448AE4113B5AF4EBE9F5CD98CC026F85294923BD0D7932C35A9AA51216E6EF832FC0067891ADCCAEA07331D6CFE8824F8EA3AB99DFFE4F24D79C5B8EBA7700CE4B21B718182A66D0684B78FF21DA3F51BDD934347F7E8B8EEF0F9468DB443138678CABDDC22D1DBA8342F95DB029FF699D5197B0EA8D5CD552991BF5F365EF7328CE6C6EAB5F1DA98F366EC527D24A78EFEB282B9202F515180437E2D90E7A5B9BFC4D90DAD6F3A319D7C0064208CD4235CFE997EEF1FE2CA6F0D4D65615C746230949486F68878C61F9028038C607FCFB931EA50C9CE18640C9DA778BF87E859F06F0C858CA1F1640DDA0C038CCB2787263EBB9550FA048CB70F7A5E79F6E9CAB1393E416F7DB1D17B93FDBF536709EB77212A4E01930A3558D738F5BBC156F86C53C59CB30872B731D7E13CE3874BEFB4D17B8E31C5ADEBFFBAF7F702D987C365199FEA552C7C7441B502F8A61C52D80F2EFF559F0956CD51AD872F9AF6559EB480282A30FE25508E019D86959787AC341710EDB10CCC0D641CB78BB95CFAEDC102F96B152C5A4D065376698C14992C369D90E3C78D8EA01135F10BA67B79BF6D6256C0A4EDD849FC2F5B2B40F7583E65DEEFCFA0785939E478EBA3E21C8B30C5FEDF2EB95D4D24913066F14102BD22B86F39BB040E337F49E9BA1BE36D3D0F8D4E3BA50379C68CDA8851EF36EEF2D2728732A4AF93A0DB9C0D3A452E9643CD7755A6B04FA8C11E7F483B0E0275F33902C33B430F265F0F3601CB76A10B1E4ACE52C6D51CF132CE50AAC76A57A2EFF4E5F63D0022889AF21329FA8390AD3AE0092F272DEDA4E9FB3B0A483C91649D020C5C66008009CDA655EDD3E10792A80BD05CA27D2B622FE07BCBDCABE69304A263DEDAC1FD241A8C7369E3B06115E88578F0188523F6FBDD48EC1AF53356E4F39FAACCA37E42D11ABAC6926CAFE02283EF32F30EAD29517C697D9544890BB12279C28016B601B91B4170E91D340D5BC61B7751E6E522F59B10E69DDF97C4CA0403B402C35CC3322949EEDBC245E1A6A9650CC8147F379DC6B50F13374EB245086BB034D90FB912E81D27CCB30E5A57522F80C24B6327D8827888DB5DEAB1FE382255D2EFE6F5282F81A600AE0872B559DF6DBB801B800D9D7B8AD0D69ED161AB7D579B8A11804D87317660B66F08CF74E7557DA8B8625519EC48A4112BB282183F65291E02CED14E7739FC5D4AAA594B357FE9CE3284BF70930B51D9F6CEF68B9D70B516FDC8398FBAF2B5289814516FF684F76B8148E09456DA7C8D72F7E7E08996AEF9244BF192B88B617877D5AD1042CF6FB7435909FDDC31B1610D2887A3F7F642745A041B56D840DB8A0460EDB3D02534D4D165ED222719F66FA6AC8A085FF8CF899DD4DBDED01AAF79AF707D4BB5ED3AD4873F461450DEF0443A2D791728C7A947EF8F7AFABEE26751579F0FE77D7274B031F4A035D12E30FE5BBD2D182517D87E436C99240CD72A9CF775AFEC20886C4657E93CF64087E3882C58A0A911637517EF3C4F183D94D65A2C79E64A7086944C182AA98E4858CEAEDBEB687026F340C3C6CF800B46D3D28DBA511B6886F74F4B0CA70E6C5171647F800DA60D79CEF83796A40570FF7CFE31E6637F6B204747688AD9A8A03FECB346A1D1E597D9D12E9947FE3F9051B0F65E076717FF23951464D1048600CE7FA03DA9C9B374F21B1485AA51583317056D94FE5A8E33401F446956A4B202CDED51184BC40CE35CA01F0203CC0103BDB00FC1F6A2EE9548316B09907D18884657205284145191DB4BFC83FE9C7704848C2D98C9206295908D46C4A3B860465D7C8A12D801EBB14F4C4E5ADF66BA230C2B68FA5D5A188A1FAC43B278C84AA900403C6742FD536CCC099B4B1A71CA4C7ACDE87109B548F86F164DB5B9BBEC282EDCA292A88FE52AA6AEEE9A5B4F43B068284B9B35F7A6BEF507E36B53407711D546A05C701D429C277877907978A2612277DB2F65C55F166910D48FD40465D544CF56F7362F601293D8F5ED363620CF9C39004B1373D9F8D046746CA5CFED82310B515141E51C0E17067AF95FDDB8742ED5AF95C6741A8804970C39EB605B46D428C430CF8159DBBDB209A1A04C50660A73996558333D54A23C85EEA1ED3153B956242205F3FC65ED2276684E69BFF3B77F4C138144E97EF63E9127FF7D440C0970E806EB2A0880C20171D6F52DF49B74EECFF3CEA286D02DAA760A28839A58301713118F19DACB9FF8854B237FC49D6C0FD587CD761C6E248EA2F4EE993FEB3DECFE86B3AEEE41D94BBF224A746067F47AE965E12AE7199C2A1DE50AB396F7E04320CB0C57324013D6B18E6DE69AF776E580848473CC7214B13CD3E3B8D3802525F1B4BFC9822ADFF777154E66CAF46158F892100E25AFA791E399B58D38FD821666DA11E4DBC1323874DBF747B2B6BA5323F6EDF002AAE574B8E492AB9FFFF358BEDAE09EBB68903ACA960EB85F91B5EA9CFBF1C27D87690CAF004D809DF349D94E223262F290C060D234BBB45B196E710BD2C361753CCCAAA6921D2E4EFFF59CB3126FC54ED0F1F6A0A0C07E70793F9FB93F834C06EF985649C3F6A96DAF79EEE7AEC2614EF287430F8C77C2E07EBB070FFA374A21A77D83EBE57DA141DE6FB09714F82A333B0A774F5CFBE0D660E25E8D0C0F2624ECED8668F6767D53F39B6946BA1C124D64BEF2A3486B0CC3038F959E808E29DD7569D3A2F1EC4AD174A82A509BA5CE87BF5C5A4F091C65F4BC2D6573CEAD98070DD378440112F2FB5E2F8643D63662471F56F170BD225DB3D32F831A913D5FB217E526865D17BF86DD736FCEC427D3FF2DD59092FE20608B8C18DB79D2E1B5F7AF54A3573B2F9941EDE39D62CB01E9244B3B79A9DBFA1D88CB8333A659E6B49570125A84865F58689083696D9076E9925E929C8A3B83F8F0E664870382FC1A961E17539197ED6C675CF5870D1E89C40C4603A37F6FB58B0350E2C64EA6DA5527771DB3818DCEDC8CD07952B30F87A0E5A81613A1810159D01F24A16BF46D8491FFAD2197443D526976D25F75AC9DAD85FFA918C14C36554DEAC0F64736B6A71954CA738B8C67ACBBC6BA2BE36031DAEABDCD74D08C6079C2EF299798FDEA5AEC9AD5C4500EA68A2884456A0B34F502A3CF047C653E7556A08C7E9BE014B017DA9771410DACEB34F0FEF64A33B70980BD58BFD4087DAAB086F4AE1587884E6BB85F2398B25F98EF417576DD2AD257AEC42EB66D1165B706DC8729EAD90225B571625F228A9AA747E96B06F51976EE28037811ACEC8E8BEDDD4BFBED41423BC08E81B3536C505B8515EA6459C065D2BE72D6AECB2D635B5178311918731926E84606F1CA5D5B3F8450604BC79CB5D88CA4C3E8E4B9412C1F0C8B8E887A27BF12C6E0F2BCAC7DDF7B1551B05989AE02B4686F4F0EEDCAE838C122209A4424359DA1AC4A020CC0C4E6D86AA5822ED460F6295F16BA605E01A9C3E813A7C4220212BFDA02A7B39A08CF8D4F636318A23467DF8C4FD08E6B0D42F928A6B227CBE226620E55ED0B8DC597762814AE52D0F3F128962A60F12B92962C3DA978698D6EE591B2968133AB1A15E643CFA2480FF5BC4A125167E0BB99015D130A1790E6EF1C63B2B7616DDC6469D1E2D47D10C7A6020470E061927161CDF485DE09A28E9C020E56F3CD41491B5D63B90116539C1C7BAC0235C92CE1CECCEEF0366D28AC381BD62FD87296FF4CCD439D6EEB1255474A4EE5B703F30043150DC5E2773B26954FF338667004E9BC5E06BDF5374294DA53A6F0E73778749020A02A245E9C97EDCDF47C2AB5E5B43B714EF0791DCA6D37E6D09D8EB74BC5C4B71E2A29BFC573B9C8CEB1B8D8983F6F8157D79646B0AE059AAA3E8611999B03D7F0D601E29FB66236F0C121B819ACCC2449A854DB8B5EB1A9AA4BB8BD37D288BBAB6C1449D11190889FE7AB1796C6E0C647573228015178E617C7A43326CD4BA730A37C0A4BB2597E26E75F676214AD4BD8D9877C085EB676F3EF0503F340EACB30BD547D98541FF1A5790752D1386BEAD8B648057EB47A9426D2B74C147D2264ACC73F8418297B230A27CAAA93CEB4F186ECB54ACAA31E320FA693FF208D823A9ACD4FC8CAA1C737AB92B4BCFAFF869F32032033ED14F54EAB0FAFDE5D107A2B6CF0CACBFBD0845A711BB2FFB5904D59071F5C1C77680D5CFB72A600F5F5AC6AE0E18AE3DEEE9E03341FE96E86D8FC1426B6AE8F3B52C2C84E899F6DCB18A932C7298600D3012EF8390783507CE6E034B276ADC9097B7663C47C2C3B2E839080AD51405470275F73D74C9038542CAD45C53B2BCE64D363780A8B44124A8A694000323F401EDB09E548780B3F46FC88B7E6761504010340AA8DD22926511B4EEA0E3EB462C880F7EDB78AF88B3DFCA39B8EA208F2D9D7562A9B6A3F005AFE9F6390584EA699E030B25E26B8775D3F8EF1C81F54045250EF47BCE35624EBC036B483B8F7F70AB947C1F5F4AADEDCE2123AF9AEB8AABC0ECEAF4652A9C04C4EC5AC1351524F73ED415CD86C0317AAA8C8D9FD999F8CB357D0C08A5A6D670DF7F051A625C58ED80D0BBB8602BCEBB99E20F98B0960184CB92B4BB489D83CA2A6974333870F652CC50E13213B7BC2735C1680B78867678A22BDCD600385CFFB200B2FEA7ADBDD19A4F0CA8CE4BBFACFCED32080A59489084F47CE42070AE6F6444B9DD8444E2D28BB2F888491B59CC52A818721A70F4D211C5AAE481AFCBB80CE9E61CF0156937D64B0B26DCEAB4E4821F9DAF820D4EFA5A9008A6B621B979034E3F5E157CB9621F7CAEA0C7ADDCC5934535ACFB217F504905D4165D850E1ACE5868C6D5960F900BD497F47675DDE572164D585634656251DCF58F48AD740446B20E2349020D12454D0B9A79EAEEF5E167AC58EF2BC9E6D086A2FC187104061606B0881FCE92000B643CFCFB3DA88DAC643E923BC2057D3BFB3B2C9131B7FF904284C724C4FA8970954D5017B29F3322EF84A538E19C05EAC5F6A84585DF565DABEF99D0A09BBB4D8A6E47FFD0EBB6215244CD2CDB00F81D7D7135BD3FFAFE35F512027D9513E2BF897D73DE8FD6883761724B4D0E81B292AA4DF1A35120E9820D54A7EA843C19FDC2098634A8B507D96D41B67CE8D86F355D7D844490842C1CFA2DE61334681B4476B2F5002225D02D93FF18C22874360EBE24727F9796FB49EFB12AD3C3D5566C4AAE253418CAACA403409A5FDD9CBDC19355AEDFA080ACF2A5C61505C2A1F590AB81B6D1CDD7B2C980E10B905F4338B8640FA827A853E4D4200EFD31A2AFBE25F64A1FE3D8BADDD853BF11563FF5F992783B23DE937559E1C8D210BFE35F36405D63014F20EA701A743F1EF046B90E65C611B1125CBE0016C9EFFF3F8903E22A2B4D8249AB0C42B4A0CD00985D123F220E427E35F7B47A01C949D639819C740CE7F44B3539CA4A5275ED767CA6BA8D762865379AD88590FF54BD33B237FB75A067C8848E154AB7FF12B0DB082E6A42D30977D89D2E42BA917EBC5DA70BF12700E62C868851914A4C0ABB28B9DF4AF600ADCECBAFDDFD28EBB22F621C80EA82814F322A6EA80FA9A74C489256ED44F6F4491653B2BC5CF4619C9B14F8EFBCAB024487ED37B45A5C10B2A792152B81687C81AE1D8518694CDF9422CA2F20E9D3675E132CF17AA3E5A02FDE495C575DE7B206377701FB850E12F472BBAA60598AF85430E70A688CD21CB82E0C10335000F9D4F2C0E7090672D9293179F8C9F0F525C1207679339B9ED5B4D8C2B713F0B42FA021F103C93A9FA1D8632D73E61D1FAFBEE473BFDC9A34D4044363FCFB85EAFC7209A44039A83FFE2AFBCFC0C90BC9C33945E858AC4A24A34EB1F02D7DD303DB7B9D9F2FC1EA3E0F08DF741983321147AE2F96C0A94B17AE4E600514AED5720755345190AD2B91EED35F64439AF04E9A4866A191DC4F7E70CC2E64C1AAFF83DDADD9FB70591F649F759E9D3B7540767FD8570D1FADDE49B61A098F725F6DC4E816492410B32AC55BA52EF088868CEED1B9FD1739E9214B7ACAAD4DCB3A7AD68C78BAE7A83DED6B6634AD901FAF609512855F72E6D93E58F5DCE865AE1F9B1F20157BC36608A987185E2B2F6DC839ADA3DA58C69DBB7A8AC4CEEF44DA4C8400DD049A50451E7F1F195A43B7BCFFD4DAE8158B8D02FC9210B9BC5BAD44B27E04F4144713B3FCD0EBC5CE4E415E6D0C32B3D8D99ED922AAE5C3450B7D18223C1213AA1C120B0F8859B8CA8DE97E8515747DDEF25B1B3E62DCF88602F65640E1277E83114C80AB5E8476782FD45756560428414B2CFECF835FB0A8273CFE887F4F0FB16B34C53BF0BDDDFFE4E458522E72321B20D854135874D546CCD5067B77650C5F682DA409F37E143055C12A60633287EDED8E6880F31ABB455EA2E282A24CD1576DB63018BF958F11FD13A550AF0D73C522ABC4726402055D25FBCD3FE7D91FF0E62832BAC323BFAC517AD3CC81BD5ED1C75D9B7982B620DA3139F0330725EEC4432DA4A524776626F31DF71B47C756DEE581804B488C3089EAE42A48D9FBE052B10227406551EF524AE33B18365E2914FD5E10346C1A7319741D77F71EB017729528B9C23C1A056F4638286625A2F800A6E83851704A67A72BA7428BA87E322A8A86C43518E202FF9ACA9B9BCE10277A25ABAD94AACAB1958CE77142F3F188111ABCD42D31C3E68AEFBF7F1B7D46889E287E3665AF47410F011C499F6C248AF83B81BAB7EB9CAA1BC0FB47BCBDD51443F0558F6D68F41BF920A70764B596DF6FB1AE7AF4C33793203ABD9E547E0DBCD4C99435F31969576F401DC4EE7E7A3AA6857CADA9E0A9017F3B5756D047199C7B6584342AD0AC370E61F1205233F5B88BF8F1F9B42E0D7758E846A497C7C544F06E53490E2BEC11B18698A007EE48BF83729FCF448B6E0386321DBC7AB97246B9C5EA92732CB04791A6AC52701DAB0DD0D8D3F164B2EADB3DB85DBC80D01E1D75AD9B7928210BA3272F9282B0880E4B1B534BC32122A3F41F38F202838C39F1A73ACA4B991785A0E19F880F440B6416453FAB21AC51661BAA3D815AFE8C9259431AB0D030AAA5172C259E87DC10207945B215AA5DF10A0466724A81E78CE3D07E6105D20DB837E4462C79D91748EB34D28236B33489B6BBA899734ABA08EBBE2DB79F07945FF9199A430C287E668A08901946BFC5996CB2E56A80344F20AECBC2A5F86D246EB3FAC209A46D32001FC8F02EE3487951741318F5E76B7BC2491BE5CD20B41CB354FEEA6B50163F6C30BD1ED0148BDC9A9E57405FDE773C2FF6971F2A0572BABE0828291ECC6C6AB5E96420E82D382C303B9BEFC90DA79256BC1C045B6783E3B7F05154EC330109759B6EEF78F8D0908FA11CB395C19C53ACEC747B361DA8D9F16A9468F4F1EFB6F92C522565D0D918AF13FD8CDF44C5D82DF53BEB20BF3ADABAD0DA138862CA720A481AEDB5C7B0A73B82018E1938907EC1F97BEDAC7C8959392069A98787767D85286DB8B41AF396CF7406E226D4F1F98A67BDE78CBD772C02EA9BA9160D36F46F8A6C52734CE30D6C677B5023187B77D2EC791E5F84115A9044C0E9908FAE5F92D310732CBA9027E8F8411EC7A84AF8A0F8E88DD0811E6A1DC08DB3BC51B7E91689D1915D70DDDA95BD5C3962780ECCAC570D0221F267AD905F7024BA18D2E3C9CF0EFCDEC0D354C9000F398644080122F3BB9A3BF96AFDB37131FFAB12CBEE2A9F541E9D110BEA36B61631CEF36345A9D0BECF18B4C915DD7C05B19CF9DC92343E242A97C47FCD3A8A68E05E9E4036FE24AA8D33BBF03C82A3F181D73A70487D69BB98F1E57C5C86AF10EA60D19973A449BC229464E048CB5D9486392F806B5B3287B880889FD1871BACAC0C80912E9F8690644046FE75FF4C28CDC22F2813CB1C8B58F4F4CC23D875CFECB60393DE45A876DAD653FE49B857CD85CDD6A0AD3B1F3EF3EB81DE2E1355787B6EF5B08EB611A4368ABBAB5093977EA6840824296F93255A7B1A65A9274F96A361FB289A992EDF589731859DD2956EF9138F77ED8F1BDE5A8C51C991E828A2C8D09CA4FE80EC8720AEAEDD4872878BCEE94C0DF1CA7262233BF80C7EFF7513DC65115FEC34BED481F9F4C75E501D967651109B4EDE473C843AC033F31E5DD2E1F3342C526B24D4D1C547EE6E9C3AC65BA33A2E5244B277680FB07778AB7FBC2707329F4C5A5CCF91EEE355E440CFC2316770C606DFA6FD0414ADEDACED2F79E9F4C4B1C396CB8A21CF5736249DE13957FC082FA13215D4D842FB5DEC7F0162801A26F0EB3282213D6B2FC4F84D9659818FE76D34CA8A03765622848758B5FA68A61EFEF0DB28FE96ADE65C5FDF9C72CD491868D7167321C2EF02CBDF5297A694C287CA14FFB985CB7CA4409A2A8C0F89740ED3FCEE1979DD1A0E9FF346D764938FA9F8C5331E9439AD00425E44A1021A892F207CEC8F84CFDC7710226EDC56059B076893192574FCC10B365A2492291E03ADE482DBAE0D3A44013566DE4627485DA06236A3388AFC2CDD616C91DD63E1D35DDE70ED0F1BC25E0F07A3A0002AF1470A670322B985B8ABE9DDE9CF32C5EDE0F6082F436EC2D72A541D63EF0C2871468F79D73A47957FCBE6A5CDC27D8FC48B0B963140442CC554BB19EFB1BB137D35AA3C606FE4F5976A8EB4E8F13F668E9459F60BCF95E581293805FB239A660569086E8A45C3B18D2B7B33252F63B8D40B0E247056B76D56B52CB9136B23DFFB7E4A61226BE1AAC7F0ED4489CDD503D6973E7CEBC3E6C5BE879B9FCD461B497671DE13E289C361D2AA374F37EF400C820EAC38048D11F44EF4F03491BDE9076C68063F9969AE0A9969185786A9676CF6DB5C35B91606B0643D4C9F38E6C4622EFDDC6CF1120DE06C702FE3F9AC79D4736BC7A3AC21B86451E2C781A667746917C009E2BEF26EF8574CF7419CA60D24FEF0D68BD5A803F9A66A53AC5A521FE3372857ACC60F819C4A0786DD4F763416B2A0833FA6461DE616832B214682E05D1473D2FB82A555345642EBF629379C578A9C2926A021BA1F828B80741142CBE0CFB0040FAA52D9A119A906E1947E4D9D830004391A49AC2D2507E89734E5907F8AE84C89B01ED2F46548A0AC88364A393925751D135246ACB50296E0CE52796145B13932A210FB44E08C770F124E1A5D5054B35BEF1B31F347F0CBDCABABE8D8956DF1FF0683B50147D486C152794DE7CE9628FBD6C27F57B1561A8072DCCBD1AB99BF7E48CE8B3B6AAF96900310B1894AFC0EAD0957F7D39CA30303BEB8D99729EBA8759BE815AA7C9D1AD0599394FCCCF63CA75D1489DEB96461C6D95BA3369DBEEFFEC69F52726C96D69A85B6C40EB21419A247D4B73E102748A271DD5EE87753787D6F4AF32FE8BEE2BB8D23BC856E510407DD9C4BD5C220E9F07BA140615C8CAC778CD7C282C2F7179FF600D1B0C0A382058D4A7B44AD062BB637640839B7E7C1BC9FB259ACB624A4854A4723DC2BEC47003D8DAC47634960756A83895576E9A72E3B39DD05B41141518D77AB02A02D38C7768A1E9AF0FD7F4A061CE7178A95405ACD0421FA9CB2C7D93B2BD71C723568956DF41C803DE265A81909F8B91837CBB2DE448D9BF935D9226FED2CDEB65E768FBB8DAF4CE40446AF043B7E0DE361496C5C2D3A97344586CFD483FF0174CDBA4086B785C15764F1C7A7DD1CAA9F01024E02E3F9B80EFFC3D095DEF65080FD2FB45E11ED582D5590DD20388951B548E232B96C0C265B131F41F7E6D5F255B261DAAB85AF9209A5698F7D3109B89CB8BFD57ED13DABF5D31C7157A3CC21BA13BC3DECD70702B02D56436731832AC0D89D2A3B25E0100DED6A01B437ABB40CC0450C42F078300C330CF1FE1FD261F4584793F59CA0975AFE2DEB5529BED67DE4DB00D1A97BA50283282F82F4129485348BC643DDCD50FDF39357ABFD814F352268BC2EC004E7CF700A5147259BFD80EDC3EF96B9A5698C47E5585F9DF41225560078674B70B3BDDB71561FCAA2EC193DE051CBA2639966E4D01D5087CB9B86F25BBACBFD30E2CDC5F6799B5A72C2399B370E23FB37BB0306387949B4F8B66E4F397C3126E46CB55C4AB6A6D6BD7A216BB8E50AA7D20B6F6DBDBFA5FCA1D61AC309FEED03D3C988801581B006C2D3DB251905879B655E7BDC4402AC212B18ACFA5885967B3D7C2728BB4DCF40255EEE47411BEA6C574FBBD5CFA7EF20C78B96861C2FB6020D7C65BED9C6F7EB8E4B8CC4AAB84D29375F0460CC501EB0C82EA8DB80B57B1DC4A5B97EB7E81AA97FA83E096701D9AF0B97B989314331C100A6C9A0457598B848758C87234C8BB4113B7190489FB9BB4F0B5C40893E22313E3FAF3BEBDE5A7EA7632564343AE4D9604B1679EC10FA0F0C17754709467640C78C3CB62D06DFB788836E5DF1A3BB06BE3A9265E202D7FAC9DB59C90612F141A774374137CD238B76747CC6BE4FE16C6A85266CFF3DED162EDA489BE507BF5BB521D5254FE4B3C639E12FB6CB4FD4049717FA7AB40C68E949F168779F15507D60F9E0F12FCC7B6C340BF36117692B69DC824DD629694D059D2D6EFC924CFCC81F9E39EEBECE4C3F68B1F47B93A0A25C085577E0B10913E6D41A8D5CB079A1E02BFEAD15FD1FA30992B5123ED409B8166C1968DFCF38C6F4053307E1378FB95E2A8197B998D82743DA1CB892FCD7A46D783AB410A64B659E8F599290B10A82CCF9FDAB45C6EE8E09B63A905CC754B1121B164136316F2FC178742AB7A70655FB8076A3949F05408C2C6B65B6B355C9E44347E3F00F1F8E503B5E2CCB2E362704DC55D0915D5AEBC7C266EF8E31DB0B2BB63C4EF145185B3701F86F33FC2312C12567ACC152C1380F3E69FD5FCDED88C28FACB54779573A9627CFC0C734F73020D5B7A40BEAA43516118F52FFD737CB8C045AD877FD9F1EEF026B725D2449EBA1755F72B9F4A1375E62761691770F5F3D5F76639B4BFC5CC3CE6708210998CF5CECB9B271676B46228076D319E823B2D41DFDEC542630001BBD3B3E904E7A748BFA12DFE16CB098696D7D181377BBC9F0E7A3BF0E6B8F772506B28C456BFF9B7D14633FF2BF9841DF8D74E7EF1B008DEDB7BA164D739495A774F182D3364236353BE3921BBC79A768430200EC26B6ADEBAC3E326CE54EFD3F0250D98AC627370F6D3D3282AF5ECB33323007811E0BA68ABFF396311CA639F11B2EB6E7DE06CDE314F95FF0112E6E6FF674114987D74AC1082D815547C4C13273B481D24BAEA34E4D0E78D81EC3BB26F78F08144AC0C59115014BEDD47B965DAD5AE14AF518ED827BDE5F05B0447C851703B899AB81CA2327F5C4A4ACD89C5C0FBFDA95ACC12B8C062BE2D85730F2C7146B1C913835CD580A22CACF1D99723F2E288BFE81276F296DDA19ACA9698A7B546A311DBF724A021F942147D6A51DA838637358562E9544A22BB5C472BD9A762AAAFEFF7FF4541E036E71E51424026477A6636708F0390C96372AA245A05111AA4DA1E1A7289DAF46D93BB21AF8DEE80E8657DD43F51B921C8E5016FF39DA0798B9E122271DDC04ED409461D5698A440563F9D9DCA4F1918FEE4E71F56A16917C4C73EE8065026594F1043C2D687ADCD781331A301BB80A471F6B15586576DBB24A8FF80A1C87A048B58099C8AADC8AC1C38BE0B2AC61FA246A797599B2BEA1B57100DA35DA48580C647C1B911ED864DFCFC53D04820AC8B68632E2AF2AB161F662773C8B6FA2417E90F22CC83E2D2D1CF9860CC889CFBE22A68FB6107810F94B7B43D1EB563EECF2014181A2B29F0CC9914A297AF51B32D7E29F12A214E8600D202A253CC38E77A2BEA33CF4C44D52EBC5C74F5FD89DAA788A20579EF1EAF215165EBD087454F76694BFA461D3EA952C05CCF33F24266D21C76B91C94B28D1F03A0E7EDDA3F2F92D6584EB54C126AF7DF79762AE70103E01FB074CF8C7AE79EE578909F110C6D164AC529F19A9B4777DF73B41B6856538D5F20A424FF0F9689E1D4818047082F65B372E627305DF4F1A2F705A1335E3DA541CAB4125F08B86651D6E3CC54ECB647BC3B6105752766FFF2623A9A949BECE19DCF4A1F20FD7D7DA140B8FE0DE044280C91C759236C1A79FDCCB7A384FC92A5C9F567A74BDFEA317450D7468D1D62892B1A4B822822867AFC899A664FC9E7C379641D63F84EE9C2B3F70C0EA23C0221595ACBA791AFFB725887AAF59C5CF55A3B9AE71018EDEC5D40BAB82653EB01921A40539E8F1F92D0242048A17AC36520D0FC4FCCA2F06DBBB036455C5753CC2E02224E5410422097E0E2EB124C77402DEDEB9ED885768C53507BA8E831790ACA6B7462EC8F7BAB9CE1F05BDBEF36C49B14CC845D4BFF5572E95A59E9E136C66F261C0B446A966F9B3F02FC9728411AC2F46FDC275CD307D468808F94A4A30DEBE1A8E36E395E4A9AFE2EB1E3E726A68A3ABA8488C9B719F0DB40E4F28DC56EA229286352281079C7E649FB08942E590C639BB264239B865781903F64F427B1341E81CC505B24A36C8FECC8ECD5C32738A99B4253220D5EF4B084D62ACC97274CA5AE6989265E1604AD0BD122C9B6676F91B5E69141A4E0426FDDC68B06C3D7F4B4E23C46456BC6BD09EE0B0F8E75575CE89A8C7DD21A730725EB4B4A9FCB7F960CAF8E0801EFD36D73801601D27C9D8AF9B4FB3F2EAD5F8CD04BAF76F9BCBB9BAB84E1AF7D8A42A62FFB3359FB72B22A64FAEAE1442435F58E6F4DB7E1255E5E332C93EB610DF944ABDA1740A709FF78A1F8BFAED630489189C0F829475400C76F464E4C2A6A9AAE8D13DDEED5C94782CAE97C43F498FDA46D16C49BCD3C6615507DDB448C8A65C6469C018C0FC42C5B42F8F7161209A78DB7271E0AE79FBC5123C62C18A17CD2E75726A53DE24B086A465B67700D3FE9D6624CF44153323A7F2161DC697D585C098395F9CE5A328BA88B54A3DC6D3AD041CE7581BEC2CE14D6E680CC818FB8EA4CFE99CE527AE0FAD9D8B74521C0D58B1EFD0ABAC48467F7671197C64A65302EA3D32BEFFFA30CC3C2BFA0B0B37C8560CFFF057DEB0AFB4DC7181B7A3139EC6DE590B7FF0DFF45C96E4B0FDD880B07F4795939C0557DB4530922D6F4F29F336EE157846EF4657CC10B85A93DFA9C7F52700AFD66611160B0EBBF437CEF91CD6758CDDD1271EE0D5D6E76AA1E52C47A72179778432D77080DCB4442A3F8680C37F1ADFCBD2555D8DAAECC6CB981B1559B0B7EF6C33BF783725746C860040AEC939551616EA2BB90154028634616849F87437FADD0C9EF0A19A89679F74877013DB26C284703E527A53359B08D975FCBD7E6DE471C843580641CD067B6264CF99183E082017EDD32B456AE56AE8E05236E1BF57469AA889E21F3354E32C1236B0F319293239089B6904E1937B9E16F7CA76E740C93A86380CDEA073DF596928CB934651AEBFF9CCCD30970E39CD65F229B8683A1F3B24E45FB03B6ECA1E2494D5511AA324AE665AE2F12F6C4BBC115F7078110038F7F0170AC4F5CC9CF78DF8C84F23FB646EEEA3E950DF3FD95D1D0CBC01960109722352C30FB993CE4B078D806A65A9E13D142DBAF36CDA911D5B14B88DEAB0B748FE3826E9D76B144E0377EB0ECBE0E0A03925CFF85A8808202512523ECBBC6716B6D7482C1EF69201BAC19FFD168EBE70A765E5C749AE82A0D068170BD3DDB1FFA148FC51A55DC8BA1057C4316713DD50FAFEBFF87ED372D7FE4C3A11268761E4DD2BE7DB9F60D0F47217D6B9322E78CDB7C6BA58D9A93B008CF0FC12ED083558DBB53386175F98B8F41C6DE7388A4F70B55939724C43CB1C0EB3512640798227807EB7319CAF47197F3384E74A3C76DB788BD5403AD7E54466739E4CD6554868978C0A0DC49EEB7F33F776814DFEA673AB21A65E1D0CD8F43B805DDE96C396934612DA7D093E548170C0A83FD51AEC8157C6EED05ADE5EF84AB5BBC1FAF2BA352227FBB16B6E8E982E6E095B2DAC82D831D7936640AA7A001B714E7437E2DE14869A5F8D18651D438D63721466486BFC5963E45347D084F8DD669A746C5E337706FC03C530C677F042BFBD7B7DC4354E2169F26259A88B255516F1FD4C1506F06C11A81B93EFFDCF0E970DFDEF7DE5D8A4BD226D74460701C854CB4E1C6F7A2331503CAD26671B984A9DDCE1FCFBB9C3E70683DC29F3386905181551AB4A2E4950187F02218129574FFCBD2CAE44446C6A0B08271B6524F18F0BEFA35CEED9A34A67F10E4B74D09607F4365A4352FA508FC67280FE67B45E09A826AC6BCDEB33C27144A1BBF1CA2039DC8D7D0CD2EA2265DD48A8080F96B5C82E64BDC0B9AF9DBBE4965601331309260D723D821A8069E2797023B01C3981DA7770BE8BC8947734298F8377A16E76F82764296C7B34E753254597E9F9A1162FE17CFFA8F357C64DD87EF2A27F89D11937F3AF7F078A0CA3CC9C6DC9E0401D23D853D605BCC1FAD41A8746C7FDA4F26C15C7F1FFE03C3B81C290871921F03758A74C159845E89F38B7BFF2B8C09D1A3DC65CC4D83FB273FF753B1799F40A471464EC21C2B5417C86EAEEC6CC605362C9CA7319EBEAB40DD2D55F2787ED38F86E1E2FDF12677A9C94DFAD61E72A6F087035BD332BEA690D9E3D203A080A8BE1591A23F88DE9F6695E5A435FD167E5F8C036FA949B5D2FF8C104F9FF8E4D5ADB669E48CA35E08A2EEB2F761A9E477E552B29E8EEAAED99E4695C19632EBBF257B7141B7EF794D9A4F56D1F9FE743CA1946327E5380FE46C3BAB99D7DB9D0B6519D6BFDB9A84D7EB32ED82F92AB4BBCF5E59263FF03597E513A2D2E7216D338583C18B196D91227E71AA137655C6B0A9848E754146688D0DF9FEC55F6511D7E0A5EF67EAB67653F415D51D021B6795F4C1775C161ECE82B89B0CD4D009F94A755C1B94FDFECFEFFA379B1983EEA15E4A207B08CFCDFE694B42A01C898118EBFA45607C8B881E001544ED6C8814FD41F402B58E36496CA59F8816F3EF351570BF1015F1B54F5708621E9840DFA6A85B58F0AC4F2935A19E60CEF73CED82D40BFEA12C2EB97FF4BC5DCBC85D019C27D4BD9FE9E4EA0C7675AC22DF0E976C8AEFC36BA681FF1D482441A4E48DB84572D971C43D659055E9CAA2456F8914C4B30CF7E48AADDDD1AE9F0E94E069A04564A0B9361BF8B9DF206F7CB1919E6467D9EAC14679828F24EB8E4CF23A879800D17FE64C3BFDC73120599CCBDAD4D0102193E7C3EA390CE547314E95768285909FFFAE574D3419541CAE6894B0AD8E4998339585C35C8CEF2A488F571D128313BC47CEE54244359F8D977D77244A3C17D3A50CAF02E1DB7E34B267D415A721BCC6919690FB23000362275198C4E8FF45CEBF515223329B6E6665959C4B8201EB0753049C8C00D9BF4B0ADC2B452C07A5783CF359AFF0D248D2D79E74B54374EBEB55E4F2A465325CEA47536B2FA2210C88147D5FFCEE15DA9C7E40AF7C624CEB095E30E10FC95A3D10F3AAF41D8A2E31ABA7929833161EC4304F80697109D87713DA116726573EB04D6BC214756493B5C9F115E2EFB704FA3B7590765DD1C43AB9E81260B1A1A1F15560C2210D89164D559F2E66E6054CD3D7F0E460F5218B732837FA0F744C8727C2E7EC42ABAF6E4FADE41D518861080CEAFB77EE77B4F1F7BFDD68FB4417B47BB93F5F95C44725687F0B687788C1B1D69A4F19094248A6F83B286D7CF6869350EA7B76A3A69B213CB2F054D61229EA35BEF3F246B1FF742E17A1317340C637EC6B07555A9803D8348E98F153EEADAC7FE96A221E03F69C1C1B9DE8749D55E14C1B774AD422C3E611D3BAE3DC28E2DF5B2A7CAFD60DF4DDE506BDF131BF9BD261968F34FCFB02614D1DBC392B4B026DDC8F6317AE82FC0C8B276B10028A955445B21E1D50AE2BF7322F2B6FFB4E7EFE5ADAC016A7A7FCD2BBE2DE954A5AB2DD8CBDD3D526F6144A53327D37133A70A910959830995E8B9ED771BF8B7301B8290F5ABF886968D2A167BA50CB158E9DFDB4611D762DC15456694B7A72B8920E5373B6913FB4ABB922C2523D9141065D5440D419BCBC9DF105E27F8EA2D1D0D8A9624E655D39A8BA5641AAF0C0E22FD311CECCE8B2156DA22E36EA5F45FF262DCA316D1E22D96338B3586CDD90220389D0D722701AB43D3C03843C944D535AA76CF110BC9EC3D76A0611C4738FE53385B03FB0EF0A3B018D8511492CDD348B13AAE4F838F9497EB0A6BBACDEF20E8F9B651BD3B3CBE2202F227DFFA1A962ADD69E812DA371877FE6B388F820EDA12ADD5C17F6D3F09ED72ADE865CD84608C71C9DB5E3136AADC9D31FAF073F44F3576C1CE5A2A1F52233420C8BEB8E333DB07639AFD1FAA20B9A05300A48C38CAD9890D864BE6035B32D507ABD3F46939B96492DA7232447899ABB19359771034D825F96FA17D7D89283F05D5104A25A4AF5747B3C259BFBE501BA0837257CE2BDDF7A94C57156C0B4C376E9D0E17EB4DFA1A32349BFEE377DEC360690C19E426859D721A811555A7C1F599E122B2DA040557D3046BC77CCA4B473F8BCE9BEC1A69AA1213A5B8A528C12AA200FFC572B5FA5E74839BB67A5DD284F9F8547698A44C3DA79CD2B1F07FA30C85D1FF8C71BDD48784AA6111D9F785B7F74F01C0FC7ACCDB7A6CD669B7871977CD93E4AE52DF22342A58311444852300648B8AA97C5A746CD7FE4A755B901C81B3E8B74A7D06BFE324260B8977F01E2E1931FBEC7073C8D770F338E4644EAE630CD17E71758D9238BB55720AE17756AC9E6EB63FE6808129EB713FB136D88DD10E6E749EB3B82AD3FA5BA4EAA864EF5EC13E0C55B356568C14950CE9E15F1A4FA5F2B19D951CAC749C1622ABD3E58BA9356DED24422C604B361FAE5D606BC54E58025962E7814F02245934D3485FE61E653ABE0B22211D9149B89B3016765E0A3DFBB59C6EAE9ACDAD7CE7114165E97FB36CF3680B438441ADDB5BD64E99C0509E28DD4EBA756E25394AB9322D639ECEBD81BA4C4BCB865A01A81811D772713556D490B3644E92ADA6B74D85EFF58C9A7A28651FDF77245C52E448BEE41150A14CB71435A6D41B68810F6219CD0AF318307F6A3100547BBF15E6ACB05BA785C165A3E17EF24A58FEF300DE9F9282C2E7F10E1791ACB74FC4467A98C8772503F4845730D94FFD55280806EB4A62D6A43B94ECA71D039F4666978C031F14612E51FD47EAC5D586B054E06D179D07D5CD599118A5865A238856AEE727C065581BA9BF2C578BEC50862EE7774B5484075E0C9C68FB9A49A50FD56DEA40FE46D245357373C7334B7FDB2198AD87CE485A2506283D74409CED9473153CEA263195B7A36DBE01F3CA20F887E104C49B7ED06ED3647D3CF0873F353440045C3B68F9ADEBE22A3CD308EB47EBF2C04EA6546B0FF9E8293061F7EB95A41C73E5BC7342CF6294A774B2FC4987C261FB6F0F5E5C3DC0631D30C1A7F43058D081A9358237B5B4214067D139DCADFE1545379237CC708F1FF4E516E87BF1020CC0EF8983B7F87D57E89C47D0C72EE1A30D1AB9924CFE45059874492DFF28A34418BD63CDCE46FF60A0EEEBFC3A0285ABB3A97392A5887DF8BB5E2508FFBD69D4098259291497C5DB81BEEF6DF87A5A80DB512FC73536AB28139D4CBF5C878AE037FA153477E3B676A02426DF8AA8CA2A3C2E89B58F67D2B090E1515DF9333336B3F10F092397108E9A78E66626E3B22F7A23F6248057B7F6CE0316937F27FAD93B77E9239FF3C44BF0F0C52F08ECDE7B8B95A2C50BC411692265B06C74ADB92AE33FA190238319EBDB6EC369EEF1AD2F27A19E5C5CA5DE7AEB060B9722F1FCA27D2A1D98263850076BE253406EEE182698A62CF09431B491F9819C68501102AF67F16BAA71DC283D2055706B77110EA16F43F490DD5B7C28EA7877F35D800232D2BB37A0536DBF98047AF0F6A122FB28579C0048112DF1C0FD497EC83CC8D0EBCFB5374C5151444728CC1ED45A0604740EA80E58709037C60825B88C9A2F7457A03CA16A79A8716A64C5584EDEE4D1694C84F3DBE023614C96D55CC858DF6852EFB550E497F25E306C8BB0A5E74B672FCA8BBCD6512673A1280CAA0DA3DBAAC0CDB2EF8A9B4972442636293EB2CD0A68FBC9B43226FC115DAC324516D85A417884644170AE5D5221AE60065BCC13B1419A9BF32FE42EE161B516BC5F74EAAF0649F55C6E26808ACEA99628F3BA79ABAE5CBB2C25BDC55999A03650DFDF3B3F63FF35B6B1ACBAB8DA55DF40810B4C863E51190D25F757F2050CD000DC595C27A10528FA0123B4C2E778269190E7BAA36662657704FEEDED811F48FFF9BB00761942873F7D2D291E71985F15E59E940D0C5B91920B29592FED2C6BB4A8FF94C05A575E240582BAE822490C91AA681232AABA9AF64C39CB3C83F81D8923F3C9965300D1AAFCD5FB29630AF3ED4F2787FD301BA2CFFECE152294A78D645F0ED81A4757AA659A9AB106B8C13376C2D0D7CA9D83DB7AB3BCC4755DC6BC3B3BC9CCD143166A39839C866DB7B88B6E08207C65C670E002F6E36A1AED2F987F60761D61D2E2A8ECE97A65F2B3CFC7622E02375663A7CFC0E548630E082FE12784D9C32FF5BA3EDAE6EA86CF81B2F4E8F5F84C506E6A18CCB0C35CADEA69D85DF3D7B924B04642AD462E39E3AD315A79B54ACEFA1F7135676FF0B440F7B097C62C2F32F8185F2940EAC8C1C2D5C41D95C4B18D1187F1F86EA232024458FE8DD0E25099842B18B93BA2E63CCDBB32FAEF0EDCD57FA2209FD6ADF0E979473CD11FE8E32334E2786E9C59431444E0B371DB5A3E9E401AD7E8D337AECE3B23D590442D4D8690A7618A72F08A3F3E04AA761A93470E8630738227378CB54C9FBDC11D6F1E61D64FDF153F60DDF29B949F227C0D4BEE8DACE75643A37111E933865DB35FB980BB9E01625E0C20E2841BE5AC4F2936B5DC9829C2063FF992C214CF91CD96078D60E0F34AC0CA344341C93D95A9B806ACC0DD928BCB4445089A6768FA62029242DFF6D0087EB830CDB450B60D333B3487DB14D41F2E577016E4011B055BDCD5FDBFB6B4ACCFADA2A305504E5EA87101116C273B38DA7EC8DCE4B39BA8971A9493D6E7883FA209CAC9CA4BE7DB39E2451FC4E3940865156679C87D9EF44E1BCC9447E389009CCACBA64BAC242B238214FCFD9718E604CC0D933BA412BF34FBF841E64CE1F1736C6D4646408C4E580536C3596E5E14CB3FED56545D74EA67FAF94E8DA22D14DB0666523F862518E078572DF29C70A7515370E77D4023E3BF2A2BEEABCAD45234209F7E335739C16CD6F4B007831130A649C488027A742F7DD8364AC987B753EB5146F8D75D16634C0A4EAC3789ED0802C3D864EAC0CBBBF9895633153B542625A2B56904CC95527ABABD1EDF9081432996ABD58C39767C9B5F8503258DBEDB22BD645D9064C0FBDAFE9EFD43AFFA65F4B4CDA017EC3F5B35FA2CC6AE36595AA5E1E77CCF0F5E7D298AADD3C4D7E69E305C392FF566F651BEA88AA45E987AC58C77E83AEF48E4035237B82924266D4A916DEDB674B2FF31CACAA5FE199619A997132FBD38DE399A2AD466D49E577EF72B896FB1D83477783E28388D7D06F6F40FE32CC1E9FF28C409E7019A5D3ACA75C86693250DA2318F387A23983E1659CA5F148BC38EA8D0D83B3307B7B6D58140F65A715BDF418E77DEBE8CE8533A8FAB18703C3164E94316B7F46F7F81793BF13F1000A79B2714A0985908488AA34CE3E92A52677D841D62C4B0C5FFE38D46C47AD7584703A158D955A434396E78F807E4034849A61685CE93A7308EC520F823C75749EC60B232C30D526F748D26194B3815DA03BC0460E7BFD0F42DFFED18D95DC53E0BA6C4B157BC3BF0FF0F256A4D183F1BD31F262D50B95D35474FAA45A8272634AA5AA41141518BB3F71585DE310CBCF99C942E65F19AA7AACC4E18D4F157D0437E5C8D9BF627702A203AF1C2AF1BC1D0530D9D92E613753E929E57E23364ED2638C0DEDDDC7BA2D4A49AAEB2103334C20294A5FB6A6333012E2E5FA5AF209B8BB7ECDEEBD5FF3E2F21CF9702EE2157CE6AD3069912982377E7241E13625636372C4130D992C7F41A394611711D015B132F4D58AA76817D9FFEFDF40CB0DCB6193CA57F7D1E5C8DF63541AFCDC950B25805306EE2218CB3BAE46953B9A989363F1AABE73149F21D6304FC29166EE9D8B12359B1312B23C9F9871715489674D37E482EC0D7C39BD5590433EEC75D965F585256ACED1970EBD8F03D23AC267FF240E23A96F3AE3FC4D568D2B41D711B970E7C74056103F73C8B74F937A26C524504ACA073D3A70E950B25ECD2214692FBF059FE6192F8D24C93C7BDC309137938D7DBDE08E0B7E4EAB416540E9FC883D777F1C2552CA166C18CF5DE652EE52AD405094961447811CFB9C532E705D80F6C46B42803C11E97DDD3BEA8BAD58182E1061DA585105522001360BD9271FDF5CEC760169DECB0655A076F76B146142EB6F3F822F8E6F14AA64AD08950883678C7A69B33F7BD06C6FFB81BFC87A0DE2AE4359797312C30520B059789B0F3F47A7BF1A3AD89CE3822E3931B6F629DF2B57B2502D528D1BB8DB4574E7E0B1E2264F6A6C1ECCE212021251809D7AE63148DE277D5FE232EDFEF3B1270CDEE61AB70DDE15E676600F635913625B8160A976705453F8F9AB5A5584FD88AFBD01684ED7C63C3E0C4C074E3E57F39E11FBBA1F6A5EB9C63C0F668397CC1EFD3B4C2FF2FF51864FAF44E50F03CEE4A7FF935C93784DC93561DDFBA1DE989DF13921DBC2CFD885F761F6574BF6B618397CC7E6F4EA247DE563D60B5C4D80F6D239A995AF62100A6E7396D4CE2DD98C48E6AC60624FC2C5A2117AB257E470AA77B057D112846A2B8C923C13FCBAF8DB24EE7C6C3A22518DDCDD1B0DBD5ADCB9886FDEA61C5A8386B33DC1E94B5DB958AB031D375516F61A3B2A66E97593ECA7C628366D9209F4121E578F484EFFB1AC5C5E75518CCE566C033DF9428041DB6102445E10107624BD542B9EAFE6AE8895441F5901A2773712C731F6A2D0614802B9E771501820987C0E08150689CEA3B1FBD72BF59C0B0C095715FF2E58A150D65D4F79279CA2577D4D0A6D5BE32BDB2DB404E47A15CEB63D8D346DB77F7F23A8BA02A56C539B35481A8B73C0F0769DABFE6963ECF1F30F02FCA111C6DA000D70623328A52D3178C7FBEE3D19DF0839A01D55B087726148FB0785C390616FD3C1F312176098BB299FD0AEC43BA36F4272AF98FE5536A99B021AF3602CB77C8117B604C215CD8E215447A06E947D63229FA2CA5067C43FC5580FE1C26BDE68EA87A401CECFDCB66C2A416231CF591F24697B9FD5F26EF5ADAE282D52DB979EF996D0C0FE7BBE21A9CB9CCD923D264C47E9DC5BBB25F48EB8D83F63DF74F98F506B47E86097D46A6CEA2AF46401AD623295E16BEAEEB25B25B87D5A8D04CB99803707114B09E3793EA92328825BDFFDD9FDAC4B383780D376B196EC9C809FE3F34B7151B24F6771A0AA26C66FC311D968C32C247CEDEDCDADAF1A5F8694426E77E1BB60631FB07C28F26007A6AC0EF1DF8CFED2595A8D4546F6FFE487A76CCFB7F593C232B449BD1C5C0B52579AD4BEB9DF0DA6934DEA32CEFC401CFCA50FEF0875AB9E43F8DA384A2A605935F83DCEA5BFC437C0BAC2503BCD5B8FB4161E166A3CEEF09CE5994245ED42C5572B21CAA00604ED80839852483116FAFF3D9F79CDCC4835AFFB9ED807C6142283B88256C494D2192558C33BBAB372D209CF19416C1B65D38EA7E305371FACC799AF1C3398DFAE1ED7EA88B3074916A513E3732E35383CD9357BDB3F46602B00314D5C557699F2A2E4658B27179FB850CBAE9B5FA1D1017A010C314DD42D0B882B9EEE5149331C061B56BD154276AD3510E6C250226BDEBB82847FE462792529A7CFF7515130F7B2AFD22B313E828E5905D20ECBA3D48D6B8A709BD37FB5E0CD6B2AA92E116DCF80DB3DF22250D765001E3798B159836B0EF23E2748DA2848D27F6F099722C401C211E2F865C41E0650E400F62D93BEDC375F2EFD3AEFA78651712524969A61D273522103F5FFFF365708BA866295C9B044D2623370BFCB589FEAB7AD825D58B638247AFC2705A950D8B8A56F7D1A1BEA8D9E1F6E86B45B3A1669BE2021D65C233E55781E4489E3D77AD3CDFC8C549344F1BEDFCB9C02A6E0BF86B0A3D56FE04964E8F908503B0C63E23FB8716BC357F1F1F7BCB132BF418FA6CA91733FBED68D700B2971ED50DCE53C50E4D67D3E308F0FA6ED569D6B3142DD13AA3AB95C0915AD39CCAF26AAD15140A41CB8625F1DA49391E7C90FD942995B19465A15CC37C8F4EFBBC1FE8700E19FB09B2F00D932CA581C88A01E5F7AA37B7D5901F9FE434A1C1423D3B275F0A1D2B692926043A37FC9BEB1E2D4D8D16D4BB5964686A2B2485867B150839A541BA849008338B5A170B64D5B6E0EE1D0DD987895C1C78B97024E80F1B33FD398AE03E8FED810F53490298D0FB4C4DD03AAD58BA2A44DABF6D934D9C2EF78C20DE00B123336D97C9426AD002AF9B31B0A23C8F1241000418EB60D432E6E370B458DFEB6F6393FD9540970801548896A8F030F846B453A6054F2FCC65F4409A57DC4CECC4EEBE8E3E0565BD96F8BD63EABF3E0F0C967F03E75597E00B1F2B9F6914E0B1DAAF4D3DCD412256208E14588BB5F8449F4D67E6F727E38FA9F90956D316FE21DA4BE5A8DB4C4A9A51BB14EA8243EAF160DD0E39590A55D2538FE4F87FEC2FA8622589AEBF9E384F770E01BECA9F9BF7CE4A81C10E962680E3EB06726A85112B7E37F887882A4C898D57F58A99683B481E53C832A2A3A83C462EECF1A4CDE45E494D3BE8DB018E02697B25C6C078769056347180E15EB345E2686F890C394965890A4EC036D844B4063E77A4CDA72DCA4AE78F66A821AA2819A9C3D622EE99D18BD0833AB1AEB37E6279772028604F4044673A333EB509CFDE7B0EBA18C1649E2DD9AA19A721E9E22B6F14F1DE4FF25630746CD40FB5094C158B042969E525BDBA4052461DD3C27ABBB08811C6A2E330644DB3D0B0324FF834CE9341D7E0133C400B3280A19AF1CBE2CB063CEADE49ADB6EDCD15854FB0DCF7B40AA0BFB370D93C08E3002FA8BF4B02F08A2412A1119852A654F6D45B109AF9712EFD8C2A573B4C66DBC6F0379E64A9076716EBDB852D74531D0F6673A7E66530E6FD3FDB8228A4C030F984414676B2AE87A584DA0A7B434DF617FE86B6168DA3ECEEB83E5D649B4FEA83E7620E8AEA940148ADA2A5574C64D4C82C09D0BB3E50A484BD3A605FABBEEDE7CF9FA6DC843A55E335DC5EC49FF7A826C9FB6D8AA2AAE194C9A0B06F9E393DF3DB144863B9FE89218DA701FEE69E486409371D28F12B64E4267EBE5C5D8728226D30F2AC83AA8590F99385E4095072B724D2DA8C35D100A21242D91AF937FC905CE7E9960B8ED0307F08C67DE54BA65F2DD4DFDB6F3F62CDFA902958B84F180CCCB68CDE8C54378B60F275E57A5F67FD4F2F9B386EE77417A2D09ADC80D82F3FA20284BD8E8CB17F9491E6C2D6D01B40C5468E0D010FE2F04024261E3105A8FF926978BA1F7B8E0FC1363B87675001B53FA7BE532F32FBBB5898AD007A0A1DE6BAEC96C68CCE25817F057130DAED4D834EEA6F9F84ACC34D6398DC9C22C2D5D28A7D532770F01D7BD9D20C09F6AD9B24C9574ECBA51D53688BD9A45E131DA2F1EBE5C4169243DFDC1CAE431AB557F5224DC2FAE079E82329F599ABDBA3441A288EFCBA8464E135882D376D8F945A8599BF437066F656A31D9C885B7FFDED65A3FA652CC1F93510F88921C72ADF82DB4947404240E471494E2DF04BE5B7E825D1AAFAFFAC3DD35C28D549C7160914CD5D6569DB207479568CD8BF97CF8F5B37FAB0136A6745D35D55624F783408512B3D1463DC3581D0DB2A009FAAD8253D69E27A5968D162FA4A6D55BACE87E3310988B7A9AF919EA0F614CA16548BAE7B00747E25D786CA14BFC1C3BF3DA530445690D285C82F8817D31185C57FA381131EF911A55521AE3D534B43273FEFFA36345FF2503764C2F090BE3A10849565FE8F01415270C44146B781FB867A87937D408A019DF744C8FB03CFAD68F04D74DAAEDC8827F74DD66C8485A5FB7FE578EAA50F7345849408E04A895E7C9118375CD7E8A3EF41DE96D4DF7063CF09682DD843556A3E1F68CD907FF316FA080BCF635045581F99AEC085A6C8ADD856F96A236F819281C5A361B466275331DCAB5BC9746EA7639281ACB729F38CCDE4C003BEA833A088D0BC6AE500A890778614C64402E9369D9EC56DA2E9ED5838C6B4CC5E5DD7EB80651E888617AC24FCD24D371A464D010E4D76A9C6BE0BEF52F9D18E7B2BC8405369299399E45E59A0908E2098BB7CCFD0709636B4CE9DD7506F60D1CDC3A3136118BF6CE093D3F90C83AF18C320D318AFF51F5E76233B741ACDA6D61AFB898D7D6F612D3D223E1D30EE8F94C156168E94B02A8F344A1B4C95E9470A8CFDBB6ED1AF2A1DF374F83A0393BB65B1FBBA63D2E5CB688EA04079B35E47A69A9D377BD08ED25A04CEFAD08814DC0EF6169019CFAF1C17DFEC3A7CAC9C98B8397AEA503B17E11FFD75AF6F6C90C3537C6817F449200F299101EADFC091F0853BA849FA77F75769D07BD731BEDBCD4128DFA228380F7023E6B6A239E6BB3951BCF8A89AA908C464F81063E0B7E01A1134BCC5130B9B003930F5D0C987F0DD9EDED4EE891CF70F12E76E8E029E0A78833E85B43C67B1D87EA16F5A761483EF5CD043D310B6DE68C5F700DC6BD5992D882F26111098E48F056A9B3500D658A7D82022821B404B4009CC453E0D3F3935ED727AD27CF86BCA1AC4EDD69946CA2B146A24035946F03825DBB87B85262A1CE402FD4F9A776E69D0778712362CF83B3D08C67EE4FD7C3944556BE951E857751EFF55D382850B6BD884C70F258919C8B7F96B3DDCA08BB9D20ADF4750EFA31756511277CBFD3E792D6734E4F39856FF5DB38A50A0ECC418E0E4C95606E8375988A0AF6509643D2A8ED72F9270668DA716808F2B23B57B5FCF94488BFCD9E14F58FD65CD55BBEC0FEB26BE035BD272FDB8D29381711A6218E59588FCABB5E8120D3CD1AA68F0192CA5A14A3166E0BF47AA2A9BCF36E5329411C7AA02461ED9D123FD7E507ABC2F8892EB55A12F8284E21172D20082C92F3C5859D696972B62015F4FE3317B2BD6EFB98A02E6B3919F1821EAC8AF80DA83AD1C3F9C2A1F93EAC40E77CF13AB5F69259F9BD51757FB8D559B3A41393EB4AF849A688BDBD85965F8721B12FDD84B2701426AF0D9FAC4238E645CC459A59BEE291232B697E6FC5494C3F8679B747D9D7B3D446843BC3C34AFD4DF74F952769569BB18EF75834D8C99BABA9D0AD98177610B1FEFA5C061F2428C296F59A0BE20789C49A470FCF7D5901F0EF8EFACF88817FA3E6245EEAFFB1075644B1DE94D09A57531FB6A7FF4364D15B603A982810361C7B12956BE0779DA2475A6A64EE70525D18D13A0AE45BF44EA80F2FF4D2E553286763D610DE661AC308BC40F015D4D29679BBAB31C0EE73C0756C082C4874217D4F9B4B75D46A3AFFA55FD53236025681B776C723559751B1B46A50496A07C12E84DCBA540889BF82B2F7FBD86D1ACC9A78D38E269D9FA7F408CF2D8A9A995319E610C846537450D0CAB10FD1FA157E476B7E9F64D1A0EEF2065A99DA72EB88BC32E5BF2D47CF264BD52252EFF6D04ACF48C3B664895A43D56C015D1AC438C313C1746C3B89AACB9D52E6541B373E4039F4AF1B8BF53DE14B9AA82E055894FA532309DACE0693127F56230277E2A68054563DAFEB62256743F2B3CD77A81D8D150DFCC8E913BB54B8E0F512CB73658637D05C1499AF01383919BCAF88C0DDA420AE76F203060089B3192088E7D05AE3F965D7A7925F5B8EEEC48C9B12938B5594218F0BDF48B6040302FE88B4EEC506C240C6844C9DB82AF812480DA6BBE365E068973414F8D7281807893762575B35A3C96D9972B1442BFE2D10E8528432ECC7CB30B47D75B3EDC0A5938CA22FCEFA1B96D2AB0533187CD6E5FB60E40F5AA50B68F8BC05D0999CA1F24920ADA553446556281A3FB9E78F5005D931EC20CB1F7615C1E2324250D31551B913FC0135A9B97E7C7C6A08F6140581D63796E5AEF9BA231E4A1B8F21365BD02817D7C0AB03EE8F7607673018A02981E022AE5F121A45407F10A8C23991CF48057CCED91EAAA94BD20B39243C2B0C558086EDB7C21C93923F8B55F82187620BE41469D64949DBA0044DC2708963A184587A523C56652D1837ECB3FCA3A8A527A935A8377D6CAD7DD2DA7D4AD10F89FAB62314DBC3C67B37F0A37A5524A1E798402E070F49753B719273A9CDFF5B4AF5AB3346D5007212CA2A91AE34DBD25C8E50F036FC2915E7693141A467AD4E9170E0F5DFC3EB023543115D1263FF35BC8DC8475BD9E18F2420E8FB0A1675761C28BDED5973206516AC6F0CF898CC677EAEEB23A73ACB51F6F229069D418759D3123CB3A130C511066146E629FF78DEB5FFD6C89F43EC14133D28F9E696D3F6A3994B3D628B4923C1417ECFE7980B63F5FAAE3E2AC7D7B4433805558AECBB05AC094ABA73B4A10A41D0BE6F914FA9ECA12E61ECAE9D69199C06D4CEC345816E45BD025794594E16571F42E673DB664C064C9E85B042CF6840C700C4EAD718B26999F01649FCCBD16CDFE4A6783608C1505D96A7E4EC478A972E201FA045E144088CD7D3576BE00206780BA58D0C3E7CD1AFF8E56870368FD22F7D768FA14A309E23114B2CB88B8A8594909C5E75C4546A72190673AE22AF170151A3A5D2AB067D60FC77A5646AD2281845F8C60C2DBA4D59FE5DC825F4E28112B31C44B1943F4951B5E12008203D45E0DED5E9486ED9CEE11F332769AE065D7054F9C71BBBB4B698D733DF0900394CEE301D4CAE4F4D8C0ECFE7B93F5E2478737BC55B669F1F3BFB4AB5C305213B607801737D3EDE6F74A7F22103B4325B0B35A81D3432AC53413DD9C2AB6E9C913EBC90DED32F13B31DCCFF17A319FE1AEC25859B31C1CB20315D65C8C2CEAE0458BE88945C7C2AFE76657515B833B930B1ADACEBDF9CA24773C61811C1B37D9EAF63FABACA88DB0C746D2CC4D4112A2757A96AA467E2715CF7E5F92AD0F5081926FC6C8318997F175A644B70A27CA15A47E077E05EB00F680C594043250D3EFA94D794F51B6CC89F38A00C317205B56FE0B31E7C7A975C0C1296F2689F64CD59C1DF0720F65A189019AE0A37161F02FB55F6F473A67F643A52E72E45D2D47FE0A4521C289D5E4CD73D9D3D14B177B880B8184693F3965686F53DD67CD42C96CBF624B63365ABBC2BF7FE34DF31F61DF73A830115C59A61DF5F9D74705BD1FD909E3A5104339C4671E8307991B91CC36C2A221199FFD5BFA56DD25D47CF0D4783CA1A35315982A1E53F0CD0945B3D926C3862AA566D398881F7C0DF71E1C423F05AFC8314BC5DDE457883A9121DF7B759623831A4787941D3C28AFB1AD07DDAB6742078429AEB09D1B8499BD5BEB405D23F5F888D69662CACFDD7451157F234A3FFAE87083BD64E36D88F3488A4482A35A43DBDBF4FC83D1DAEC793E90A63C974BB069180B234D9447E05AB7B8613DF48ECD70CDEE21E7CD9E35A022B392A30767FDBCE0AEBC3F3DA3BD5ECC438FFD7AA6EA353AEA020D29E5D3CE408447E27F9A3062163DCE93B645C2979CF38E56697DDB4B9F3F7B0E2F1092F281F564EB46800130916C7916BF9BEBC4B8A1401BFE1DBA556532543BDF27E7F2F1AEDD016997B67ACAAC50D58388BFD9C69D1371B1F752D959687A95E8CCA1BE53C2A28F506F49AAB83AB8FF89DF6AA1262658063401B37800013F57CC0F05E9C996AB23377A7F3C8703FFE0DD4F6C494C9E94CFCFFBB77684AD39DBE4CC393A8DD087CADCD8D46C2A7BC486AF8A6E51C9BD1EDDB63BB2B4BDA11D0F618EDD9C0D8534C6B5EFFDF8D6E6C4766C97935EB984AB779CA4682308E674043F15C4BBBBDEBCE41C84CCC6D143E8F34FBFA51D359BD3825941C7742E76CAB107097D1194F5E4981058D4B907E362E6D08038612EF070EDC737792E04112053999C794A643E817C9A3E410D3BC253756EBF64E32D67BD59161DD3BD3BC1847594B863D04A54119EE8DC6B59979856DECD1A501B99A1F703B840F0F63CEE52C7B6A1BB80A7D991DA0B10A158A210719F85999138230DDFB75524EFE8368F87B607FB71AE65B50F25B259B0DA83AA9F54D0FB39B3D5F63E254B81926EDE7023C3F84D5B68E342BE80E55AFBB3EB84030C02500055F1528E7C7DEE801C5DDFF5B15B6D8EA1249467E8255F2F874AF2177E4E2DA331F2F524789ADD139E80A906D2A8F770C8FC9A127157A64D535AFE383E72E41FA1EED2451C86C8F72761143A97D4D0D446F9C55C2B08B0D69BF5A05714B7D88CF1127FE0EB6EBB25AEE0DDA7B474AC8BC518C0A6854CEED871B23A166EEB4DFAD2980A7CEE75DAA9E37F065A9A4272E986C80F4D4211E48146BF240A6FEB7D8C315DBEC3E19E22CC30BF51C47D3771652D42A5656E554C522810F1D1067B44A94BBD0644DDD145B2E8A469EF57D856A145C5D0FFE365B0FBA5B835DA98C1BBA9B3B0596D2DEB99F2F3736E3D8B8EDD2C7C3C9434F9F8B6CF7F2CB1ED2E50E7C2F2BD3C0B03B6A575A564DCBAA0EB647176AE1956E650978EF3D3B897C504C6D5A182E7317E497E9071E2CE756AC738DBA963289F4C294348CD287BA7DC64022D742D02B907FAF2CBD20806433AC419374E1516F36ECEB733B590260C131A1314FA83588966D8C4945E6445F7D3DB62FB3034C826B89F67215801359FB3D3B01E283C8852258F9AE4AD1FFEEF08E1104A592D25F0BB7FE596087F4C87C97C7C9C15F64E7F24BB2293A4EE4FE7841F3FF0AA7A9060ACC4A34C62D7DD7AB1CF0C508CEF4A7DEDAFB9EC115108D431F7AEDCD85A41E238A2419E993D98487B50E68249A4F97E7C9420028B2DE3683537A0EC1612B3CFFBF35873B846FF022D454F185875D72CCCFAF04A6391B7C6FB75C425D0979A09D0548969844B25605D8EFE9F4F27DC2EA8B88CEB41292CA96E5026B1EB67025427F4546C570231511A52763128E852B62ED66167854538EA30D97E47584E1F57B76F04AA695F22A70FAA9E7EB089B4987A032D462476E2BAB8998FF770A6B158607B4122DB8AC89370A845AEAFDDF1D7D32EDFD99E2767D02B3DD2415DD74F66F1C569E276DB238B327BA3999F784338726218FD0E3FD90D2E2591FFBF87F4A8E8A9BC329D0C086217F1683BFA299653EEF50BA7FDCFDA69920B75B43E60FF93740B35FAC9EA494289FEB11EF0A79AED0BB65EB63A43EF62D953E1B48A5393F0DC6CBC0D18A53CE1095425A83ABA50931D81FD28AA04E56AF83A100F71F810CCA1FB7042EF9F18DE16F91164E5B83848CA9183B3F98F84421BE1A1103821348A720549EA1B85CD9B991F4C4B890302A4861460CBA2A9C305F3590115FCE24F1D5E5BDB8C20A78BC40361A03916A46C69DE2F3C8E649024B8A4FDB4D6CC27B02255648EA113AF8D399C045DDEB6007ED5C16A59C3466B6B8C12FC7EAEC0E853527A53C4B36EAFF0C64FBD9513CE17747C191C6E2F88A4D04192D099BD5AF6D6436349E8312530A28C6234EDBADA8A7CEA9D27541872F8C7EC26EF2A500BB81A8B143F903A72A140F, afterDelayedMessagesRead=1332115, gasRefunder=0xe64a54E2533Fd126C2E452c5fAb544d80E2E4eb5, prevMessageCount=149405339, newMessageCount=149405613 )TransparentUpgradeableProxy.STATICCALL( )-
Bridge.DELEGATECALL( )
-
TransparentUpgradeableProxy.86598a56( )-
Bridge.enqueueSequencerMessage( dataHash=A3215D2C48D9465BD14E64F28AF02C997F51C74E03A164A7D6E638C177CA0F1A, afterDelayedMessagesRead=1332115, prevMessageCount=149405339, newMessageCount=149405613 ) => ( seqMessageIndex=503366, beforeAcc=0D2B5F1485949191E4AC6A96C2F01934472DE0FFBF50AD343AFE6838156D254C, delayedAcc=67781E9539BB0AD1081EECF10460EAAB1BD8AB0A42081006C694F90B577475FA, acc=1E7BCA5A13E78372D34ECA2762B0D9D4628883018F4E9662B02270D34FF616E2 )
-
TransparentUpgradeableProxy.7a88b107( )-
Bridge.submitBatchSpendingReport( sender=0xC1b634853Cb333D3aD8663715b08f41A3Aec47cc, messageDataHash=7D846ACE6D6CDDFCD05C9B3CB99E31D63998E13E78CBE6422A80676FC55617D7 ) => ( 1332132 )
-
GasRefunder.onGasSpent( refundee=0xC1b634853Cb333D3aD8663715b08f41A3Aec47cc, gasUsed=172532, calldataSize=98372 ) => ( success=True )- ETH 0.052903041078063892
Arbitrum: Batch Submitter.CALL( )
- ETH 0.052903041078063892
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);
}