Transaction Hash:
Block:
15931301 at Nov-09-2022 08:32:11 AM +UTC
Transaction Fee:
0.031899232678062879 ETH
$65.11
Gas Used:
1,840,473 Gas / 17.332084023 Gwei
Emitted Events:
| 362 |
TransparentUpgradeableProxy.0x5e3c1311ea442664e8b1611bfabef659120ea7a0a2cfc0667700bebc69cbffe1( 0x5e3c1311ea442664e8b1611bfabef659120ea7a0a2cfc0667700bebc69cbffe1, 0x000000000000000000000000000000000000000000000000000000000002f2fd, 0xfa9f88ab7d3ccf28e79aae45560dfef18e14255b1da405dbfc704fc2c4e0fe7b, 0000000000000000000000001c479675ad559dc151f6ec7ed3fbf8cee79582b6, 000000000000000000000000000000000000000000000000000000000000000d, 000000000000000000000000a4b1e63cb4901e327597bc35d36fe8a23e4c253f, dc9d42597f0245fe85dbf96c376dabd55d02b6c047d3d8dcf5f39333c4dd0c99, 00000000000000000000000000000000000000000000000000000003fe8a1316, 00000000000000000000000000000000000000000000000000000000636b658b )
|
| 363 |
TransparentUpgradeableProxy.0xff64905f73a67fb594e0f940a8075a860db489ad991e032f48c81123eb52d60b( 0xff64905f73a67fb594e0f940a8075a860db489ad991e032f48c81123eb52d60b, 0x000000000000000000000000000000000000000000000000000000000002f2fd, 0000000000000000000000000000000000000000000000000000000000000020, 0000000000000000000000000000000000000000000000000000000000000094, 00000000000000000000000000000000000000000000000000000000636b658b, a4b1e63cb4901e327597bc35d36fe8a23e4c253f7caca4b1ea450c94e993452f, ab5b8213d6c47f8445f3fcaf72edf8a2c25285b1000000000000000000000000, 0000000000000000000000000000000000005d27000000000000000000000000, 00000000000000000000000000000003fe8a1316000000000000000000000000 )
|
| 364 |
TransparentUpgradeableProxy.0x7394f4a19a13c7b92b5bb71033245305946ef78452f7b4986ac1390b5df4ebd7( 0x7394f4a19a13c7b92b5bb71033245305946ef78452f7b4986ac1390b5df4ebd7, 0x0000000000000000000000000000000000000000000000000000000000005d27, 0xc98483adc14ab2ee9e6ed6f5e895b11baa50b401c21b3f2e04bf2d8cb70b4f39, 0xe219b7da97e5cfb385f1365c982909eff4ca3245f30986458c4e8f90371bef30, 7a3090e82bfe79fdcb87fbbd7118441f5ebdc6dc436afb023001473c49f667f1, 000000000000000000000000000000000000000000000000000000000002f2cc, 00000000000000000000000000000000000000000000000000000000636a140b, 00000000000000000000000000000000000000000000000000000000636b739b, 0000000000000000000000000000000000000000000000000000000000f30125, 0000000000000000000000000000000000000000000000000000000000f317b1, 0000000000000000000000000000000000000000000000000000000000000000 )
|
| 365 |
GasRefunder.RefundedGasCosts( refundee=[Sender] 0xa4b1e63cb4901e327597bc35d36fe8a23e4c253f, contractAddress=[Receiver] TransparentUpgradeableProxy, success=True, gas=1877695, gasPrice=17332084023, amountPaid=32544367509566985 )
|
Account State Difference:
| Address | Before | After | State Difference | ||
|---|---|---|---|---|---|
| 0x8315177a...4DBd7ed3a | (Arbitrum: Bridge) | ||||
| 0xa4b1E63C...23e4C253f | (Arbitrum: Sequencer 3) |
3.845305904759777968 Eth
Nonce: 23858
|
3.845951039591282074 Eth
Nonce: 23859
| 0.000645134831504106 | |
|
0xDAFEA492...692c98Bc5
Miner
| (Flashbots: Builder) | 1.23704744221365764 Eth | 1.237372691369694881 Eth | 0.000325249156037241 | |
| 0xe64a54E2...80E2E4eb5 | 300.76303108587613911 Eth | 300.730486718366572125 Eth | 0.032544367509566985 |
Execution Trace
TransparentUpgradeableProxy.8f111f3c( )
SequencerInbox.addSequencerL2BatchFromOrigin( sequenceNumber=23847, data=0x005B5C2EC588447D08D0081D3EE73D40D7FCFF4068195BD29517E085A5550B2B2FAE16FDFF7FA65ABF5DA0BAD970A0E5E1244D949D790E171BD22F5A66A1A8118AFDA1D6E1C19E86E4406A0ECF01C80D900D74555733811A43C9819A0487CCB3A626929EADEA57F7551344A31900826B34809100980EA0229A74A2E949995458C74C54B56CA28353A243865145386132D70225EC42E0A6500DCA7B0ADD5A1D809A404D943999F323794348BF3F9237FF89DAFCF1173F7EF62FF17BBFF6ACC5704555754EF49F333643106D246B32664F3F03BF15AEF9761515113184C04185CCFEB35ADC39449CF0FBBB9005CA23CE4E0C549495930D733474E42D5E4137CC3C080AF4CBF7FA1668C853434479335458143CD2E5502474B775C66736A205A0445C22CF5D2E6672A025DABF613C19D6258D605AD50A82B6A06B13C1ADD5D3CA6D3AAF04F62B43E999D4FFB5F844540C8181F27DD564755FD280289CB984EFCE83DFFB9CE0995AA140788E1652F130C2A5DF0006337225D3263F3DD27FF76EAA22997B8F1B58FFDFC9ACEF73EE90AE27C48F075CF1A05FA1214FC911E5CD78AEFF5007435E91411636E55C41B14A1D189E80D0D46CCCBF7F98401F565E99F126089208220F29DF55291902036AC55D50A1D2CD53B350FF2BD298E2C402FE3D9C9233C2383E4B8F8BF62D1D9D01CCFBE7A0978F5A5292C7E73C334BF35A4CCB72BC2B1FE9F6EA8226DB64DD2EA54FF93E06ED09FD0CED1A5E180573BF078A149F72CE889BBEE39223445EA34661C4E491B2CC4994493F0CEB8686D6EE99C57259BBBCC33B4DCC1ACB93CC14449F1DF8970C75144F77DB41868D809B6518181898DAAFCED23D43038BD1AABECFB05208C1F066341B5A04F113C4E60B77D6168038BEC0E4A026583939CCDEE13621D55F209ADAA08987D03A1B0AF7379B7200A9342169F704766314443FCCAF0381C3240DA776912FDAF5CB55B2D53F7D8936668FF0395D43F8A208647CD1316980A0AB130C32CA79740B53758D81E2E4FE72A2740E4B4CDB92FA3D326E9CC130C059F527DD57EB28B5344A853E1FE3BFC74E24582106189163DEE8C232136A03DD65D32CFFABE66C55D43E7664E8479F88C8E78539480668A2B1718F275DDF69CD494E29DDBE031C530FD044C554E2F922DFABE9325597BBC1C2B9FA0FAEC19CD0CF60D608087A14D2D9082892DA632CC386856EE891CE63CED8F75D1C75CBA20DB6CE253BAC6B4C45E1E4C1CA0F4A1E8F55289BBCCDD6D82F206322ACBC8B8B40E5847C46889243CAC7C3408C9F48B04234D0C0BADE82FD5DC4340F8ECF6FF23135B9FB2D5F9F31D57C2129A7F1517AAB261F608D845D30F19B7FFE73CAB3FD582493F80A062E392B7B1C9D6F6EF4F3745D35BA21055EF875E440439EC1E911E5CD449938F3375D472442CE634691EBE3A3E15AB2EA86722ECD94926F81118A65785837989A556520D5A58B915A5DEA2AD776912F7B043BFBE75000119F225FFAFAF7991EC89870A8171C369097CF40D11FC0CEEF0790E0485EFAC6701FF87AE822D48B8D1B18B0843219CADAD931314D34097EF2EBFBCE861A80B35CD1F5C9BEDC192F0EE3AF248AD2FD9DFF50A109EFE98E4AF6D9C58E48A20334140630D457194039CC786B202ECF406D12CD204E45ED7BB79AE3282D30F23773B521032AB9FE043A7F983699379F21F5A8836A384121BB2E737E5F58DBA60A1B8D42B4B1657303FD741909DE6F8A82A343054512BFEF6600335C5B6EF204BFBD282DF502183FA85047C743C3BAA2649F84D49DD6F5B8E199593A0B9AE505E2F0E4F3BCFFA52CAF71FE34219EDFB536EC774285B00BE2DFE329C716AD72A7707F2E4DA78ED494FF28F38A1F8AE5B4661D42761CA5B24ABBF0DB1A4DE17F2C57BB7CE7F76BEC6EC7E25690DE15F4EAC5972DED4055B87C96E889A06374062E64809E84DBDD35D75834B0897DB07E507BE3F7443597F706FC9FA16AC2834A941BA108287037040F040D798660449437478005C2A2E0912E8722910D5F32EC5B65F5B95E3DAB5067EFA2770F26FA636CDE64C2BAC1E58607E04D1056C2CAC9560E64F8236E870C980CF96D1C401F1836823272755F55D3D459D6CB507EDC4295F9D4C42107B1E8C9836431F09DA8FACDC104D547E8E3C532D2FBF70FA364A4CED59EC15B540EAEE439D62ED85BC76C72AB0128D0D5571E0A0350F26A6F4E4156D389BCFFD616EB27FC54F83128B0D49CE7437566A0402D140D806EA31E4A3211748FD4E640F82BC0886CDA9D516AF77F45C3E3CA3E8EF2DE87AB1BD252A11F1884501CF2759308EA0B8E2865A5EF288FD833E1936A4D59FAE2BE5853516523AE40361EC084F1FB807CD9B48CBBAACC66F4AB1A71ED583B94CE1A33B793A0AE67D44B612AFD0107CC0DFD0C668FE85C8D16E4619006458139584019182BF470EB2798C0B51EA6942CD2B314CD9D506758D7989EEAF000ADB87D6FAC4498202CBD3B308E5A03E89A702B271B1650154E8CEDD0C8DB03258EA3E8D08BAEB0B731879C6E21161E4B29930D33CBCF065B8899846ECBA03DF73B73E71DFF317507301EC245C124320719B698FCE48047F109F4FB7A339F7F78EA1714971B57C66A0717F216D28E764F913163538D39C7CFD88D50422AA532E8D3AA46FCA3109AFA524F412EE8AF1B57D07166ADD811A3EAA9851E88B878DFC76D717A5A6F3BE5DD87CBD71CAB2F2D88BE703FC4FCFA12D7F7965DFCAA0F04066836929FBEFEA7CA37C49BE7F29A2F99472CA2A97E3466E81062B82F97D8E986C28FB84437D1FE5C8E84F66D8C32B0670345D9685D832261D63A32F43EBF6534A9DB7425B5FEC74EBCD869475DE7A00BEB92C68B3421A6153BE5F1E0E0804090131008B7136FAC4418202CBD70308ECA2BC870C5823ED15018A073246C4C636A6836C7E24630C477363581318572DABDE82CE8FC8F5154E5F41A808BA89D9B999C606494F4E288ECCA2E8B9CF51CFABC2FC6563F3F2640FE97F81A0666D80E07932B91F11CAAF2A8815795446888D21BAEF84CADAF55DC0664060EA5F2708BE992F33999584E0BFA76D9372B534DF5CCB8540C565211E3DFC7C259B2A300268527D8C262F23883002E2499EA9E978B0DE4C04FD35448324E3014272E8ED1F5EDBF40439E1E22CA9B236873A3C18C3037A0BFEB3A2273B2C2326A4D73E16687E77FCD38E56F3F341B7896CB7489857545099A0CC1830C50D60F492195C79FB4122391B1BB436180C3577B4BC6B45F1B8F01D1B59EDEED7FBF239819F3F51C9E3585C3BFE0E0F6310198FAFAB7DE9A8449B711A833A2AC78252F86438A37AC9D8BE1C499BCB7618CED42AE23C142B8AE9843194D3F07FFB15B332E1D6FCF4E48C4A9248985F4B9C33956C2609551CB7EEC4B4E32ABFEED2432909B14D1A0CAF939D35BFD3D2C3179D0ED87F6E6A26B052D6DA5C18F86072AC00AE1FCC6D6267538B294DD577E89C5FBFC9D22BD2E0A101EE8C26C4B5C9A68E806BF80A04020100804020B40439EC1DC11E5CD5A6151F04897439148612B194490F5A4A65FD967C97A253E5D49C18972B93EB031600327CEF8E0AEB15B98550210080402814020AA9B33336C0092A8A830FF1EEB5FB6F0C8D640AC0B1D90D168047C55CFFA627311906BF898ED4C02ACD78CD6EDAECA622695F1D9DB2D0526C9EC949AD980AD4D6BAB0C63C5CAC9197B080CD47EA896FFEB55AB7F8D6773CAB72277FFAA447851297F944749FB570C33BDA01910AEB23154E57F75BFA1BFAED83578A7D69ED4A022C7AD39B247EE18F0D7522EF93F9CD108FD54071785B157068AC48EABCE482078E8E3276EA49EC0A4CCAAD180F680F926EE1DD625FDB7B7591F64CC43822FB1CF138CEB52DB7BD17B6DE7785405F70E50D3CE650C55EECCAE55D10FC61F0F7DD2966D24A731A65401A89D3EA37C090DB3CAA727A31D1642D7593BA7A22B7A8BB892E65A1DB810CF4A1CD7359C3B129D44EB9B34E4283F9E0C50347435DE24A85C47266308F7FD180A8B271E1669A426B84C5691EAC7BE7D62E8FBCCE5FE7F019633DFA956E58F35CCF20058D691DB023659E86DA3E243FAA855816E738017BEBFB20758137B3D21C494EB6A0541439E1A22CA9B39B3C54EE651C669F2C75E7C4208A2C1A366289C05ECEA8132856F0030B291E5EEBA0F85017EEB37340BF3983E76E2A6FDBE44130730E505DF09FEFECEDDB37B8CF3F901AD03B8C1940EA1A12666C0335D9CC58D12341BA5131F7D97FCE7427776D501F7FD35A01B0A19040502A1040A52DD26DE7D91DA810DA2444865F40D5C8D8A81F4045FB283BA2171FD510BBB30046C97CAA85998000D6D8CD89B38064552625AD91A166A80DCA88AED3F377ECA79CB1A4CC5A2353AB5FEF7089F4B2607EB15E264ADE348D83C2D7ADC0619D2724C964DD92687F328A1B84444A382747002DC7E7F663F8AEEADA684A6584FF3AF7D942610F0DA390B0B1A27BB4BCD58030FCFBDCC41E2E135B2DBFF4B5FF5642C54E516C8A060BB9F90FF1523BD7B7C2CFD75CAF51B0203294972E22BD9D0A1048E6A52923E0C1E3D86C3745F46412712B72D3A690C9DC380122436DA3F872D478F371AE7EFCC36EAEF860EFCFF106D658E5AA6A5B10EECB16E289324711D481BD1582C91A41B81E29891D1F6A40B91A6529D0C04720F3A6073BC6D5364C8035805A42E3BA0E7CCE6EDD01529F3A40B69563AC838D9A415C495BEB841953F8A90768638E99DAFEFEA4816FEFE5E7983A29344540C8501A1D4DE73B37D5D6BB8348E0E0876C77F5BB942776ADB848C313725EF7952153E005C4441FB18949FDC1FAA59F1E3C3FC33D7BE0BC13C479A166390D311D571C804BE381B1AF2D4A3B77C0404213FFF1081E48095C12189D394D4872DE084B19D0F9105F3F94D7D670A2B67172920641B0363B0FF035898AF55D086C040A7A0C4B6EC1ADDA612469BBCB28B420D6CB181CC7D1EF5422BCF25A49B7DB91240FBF0A1D4A3439FD30F1E1DE4FDC0B5145BD76A92CFCE000C14DB38A4DBA898FB758ED4ABEDA56911AA66D31FF4C2A5FCCFB022C49442CB200FFE17F6A7A34ABAA10D41646E38ACEB2068EF196CE5EC69EBE36ACD62E169E9E0EDE9E302322E881FB0C1F64B0866C0ABABCB94B264DA3FE833B6EC4E15CA3624D6549DD3D94EDFAAEABA1C88FC1FF90C4E11A9980E3B66133225CFAA0F89155BDEDF5740C4CDB8D2B44CE73096FF1CC8524B89BD301CE76CA110D8397A23D291F42CE93C724C9C97321EE606FF98E04C3DFF837583ADA3280908C0A70DA65EC813EF216BF9320406103F0FE935AAC65D26C2A336B47D7DF55F50CF161BC77EA688EE4BBC60125F4C036683B7FFF9B315ED2F3646B2369C2DB6EB6158E1CCFE974DABDD573D65B8B5468240201008D469487D7397F5FD2655371B156FAE8F4EE1ED88F24F1A0FDD60350C075986BC72DCECED7FCA223CC93A28E65B1AA3B7996CCF5A566BBF1DA9DE37C56C814FE344611BD77A98F41635FCD16234106374209AFF95FC3B34A537B71AA6EBAAFA5736103A1AD522BF7BC09F87DFBF2F00C4C44736F401DDAFDD096177B51343D1B6FD6371AA31335F86F10FEEFAF4EBA7BAA11E4150201008040241B4A121CF10B588F2664858143CD2E55024DAEFC50CFB56D98E43B20703580B21005377E9E38BD903DD6741504D4A55B85DB491AA632EF57A2F932A2BAAE64C896BF1EBBEF6B16D135548EBF8951A19644C8404132C2BA8C34B2EEA26CC2C202AE79C7C91FEF70DCA1C8A70AD781A44875E9654097C57046194A8180A0318A52FD28A9B4F19505C6B18CD1D7460A68D1D128761CAA9B7792AF32F0A208480E9EAC88348DB422E13499CE97EFF0AA2304BC27F1BE531FECA297FCC44A9FC11791D56A1214F4B11E5CDE105E3251FE223823242D33099AEDCD18A42C8EC53FFD166A0C609DC6A857559232987A85C2B021C0380AE58029BA91D215EBBE70F81017F381DDC9C5B3E5D02D31D7A41663185DB7BD8D9F1B38D2EB1E717AF104E5F3CC093F48A606F8CB7BF0C7E976B18D620EB618697B2FB61E8223CBEDEC97B45A87CF2DAB9D3201C215CC6586411737C8729E87D2F5033CC9826CC7D4A38643D894D58F0A79840B0E3D5F822B2841C51798972AA672C81F043FF30B0AF5F81F51811108579BA67A7E6968975FAC556B2CA6A0DC878F4EE7355E9D39CDC1B71BF3E55ACDA0F74EACA92F4B1E6457B984C31C886464083BB31E541502010885B58B0B7D0CFB09711E4335178AB51A0484FF7BF194259B222759DCE017C1D62989AB42E1CAE371E8B61DDB051D35934290B5FF0742EA6518D5E3C7BDB161CDB6B90CDCD89A552A1DBEA41121A049A5DD7FFD94C37F00B5CF52331E40FE4FF642064A06840EDD2803627033D663018FCF04020A87651E1A1F73A2871D01C0F2CE97F38B96D96DA740E46BB308FD7616B2B20BE447289D54E4AC9BCAC6AD01B4113D24CDE96ADBFE18DD146DD08E8EBA668097B10962170A0E114A98DED3A37D840839A35E8528C4F9D359B607E04B2134830219F41870E9D0C913FA4A2EB3802BA24F563D0C5EAC328FF9D269ABAD2A4DBF3AC96AC582D6F7971E1D7E344AFC7FD4086A41083E627E16F007F30A7792932D435633901661E1B86AF0CFC9CEA217F1C30CE71F8BDF7994A57BEBE6AE8A78A086ABF28A1BC9F831AEB64AB15CDC2B66918746CA47F481435048D55F05707E51275D0D900BF3D9FDB52885F81416010A245221804FF4FA6941988CF13AF50A52052301120D6CD11D81DB6C4B65ACD7A02F30FFC05413D3A52937E2E17BAA18A58E89AE40830F9BB52BF18EB2A2A2974826A4FD4C86CE5930494C8BC0307E1873497EB128C201008040281BAA09FDA23E8CBA3DCBC4E02583C0BA2A8CBBA04A40D6345F0B6531928D4B41833D55FF99DFDD1B8C282DD84DFBE2001F0AE04BE77534B609D1F1472B7AFC6B8B4CEDC33440331B06A328DF0BD147B3E27A6005E85E90CE10AA1BAECEC972D2450EDE79B292C780330ECF97284BAF35F7B62C9AD79A7259FCC1B21602238434931DA4E866C1432C500FE509E4DD3B8185921F0321F9B32E968BA116CF2CBAA64958EC6198A540457E407381FAA9B31A6250F6C793A1493FEDCDB84F1AF029CDF4654690B2DE3A333FB7CD4FD1DACA0FCAB7EF64FC5EE884E1CE47FE8F0F9617E3036F433183D0266B626BBCE8198A00C5EABA7422F2C9705E208B67F2355F8D1C5FEB89378C35662706B8E426183C074E874E84525327B737F09324CD0B9E9190483686FE8D00B5264E6FA6DC1F2A803A4C62078F04BB0F8DD704413884950CA4FB38B8A29162512A02BFE603A8D2A09990E4DE0CA67CE40AC9A745BB1BCDA560684EC901A60AD347CF686C8741CDF6A4B3BAC86FDBF8ECDF620C27BB17430102F816D471FFDEFEAF7F566191FCAC8422DDB9F78E5F0E2FC93162BC2A38ABF6AAD93C653D048A21B1E64941BC2E068A6447B9FE681CD4E8809BF5C937B7AF9CF067DCB720A6BBFA399285BAAC5CEDEF8B07FC08FA07ECAE8F319307E3B709C001C8BFD62B5E3A7082C4C89AF2D42F21C9AC53069105B9CD8179A5A760C05915170EA50C4D09067283C25E92D16B4FF7919A360890EBD3B0A4BCD4D8346D62F1B85B1DFF69AE2E00FB026E176BD7E7643CACB957A716843AE0DA28D7BAAFBE735FA1FF8032A6B3DF9EE8AEE682520435C861A2AF8BEF3FA2542FBC1063200A8298FEF020D56A068C73090C83098141D2D21F738129CDEDC480608088A9D4F85AF6730AECA023E6D6C90712C2286C200F757BDBED7203711587A4F8095F7517DE6D114C55838922949DBEBB6B5121309C0F9AC8BA6B7224B20F97E9B4468C3F33698F703E661E834917868995328B2321A25506BE98458F2B5ED0AE872D087CD32B632C0A9DA87361B6FE9C55FA44B5C71C56A5A39C2BAA1ACAF03656485C450B9C17E3CA16076DCDB82DB00B37EED8CD40477943605A5945F194F716D8F972683EFEB3776BD082444D1C14B1E80B393E736C0ECD8823D989F41DA34267C46908236CA10DE4313AA431138858710327DA0B058F243AA37BCA2E893F1E5C0F0701028101A98DA00614D62850BFBDAD665B4B7F7CEEE4D190C794112FE9F774FF4449A4FB572B291FF630DE028A348963E183B0B576B0B675B6F7B1B4B4F373F573B7F177F570710F63BB14C1FB33508942C697A30E0754671C796A85FC434AD531F9A46D41627D1F602E19BEE18E47FC3EDD668A58948538AA7A297C57A1EE77ABED54EAD453CA5423D416B37C058FF46FC090281402010E842C60B6C7EBD510C81018B6022BD2C7E03D7F954E5AD69BF49D5E3789FF4B8BA44AA36376F280B3AD17CC0E6830B4AB0F0C6F4A24F4115EAA6F2C7F8D2ED173DD8423B578B112F7AAAB1CC818AA510A2AB47DB10DBEDDB289516643828B5E8F1F2C87D35F84DFCFB62E0314F647622942C92B9E3705C2BD8D6585F4262291BEF0A4DA757B6C6A1D834EA4FAAA98DD3BB9C0E9684C44D88ECC2A96BD90CA4472B1DF28F436B4BB1F25A88C6235C54EC186095FD8155864464BC9213C6B890E930331400F6BFAE08D87E55D84D91AC2E4AE9C27D67E7D1F2896D4E721D5BBF20D07410A502D7E3B78FDB6543A4E52B70F7F888E39F3987F3E6A408B1E705063FD411711BD2F23D6AAD8D89DBF3F9F13FA582A7D7E3758A2E920426B368199010FE25121A103E4AA6D0E1060E376CD7716042B072F07B7DF9576D2C5D732043408023211AE89C39FED1096FF4D63C31DBEA9F7252400AD3E02B7C54208E4F7FDAFDF377183CA073AF8D092E408C1D703AFFABB0D76CA2767570427EFF9B888F6AA471D9AA780D5CF177499999E8FE2B357F863E6C077932BD17AB90EFC36C78055775388D23865518981150053BFD002147A752EECEDF5ED721F34B4A11AC34A5AFBF68E78CCCC327AFADA7BB1554A23142C4EA122EE321BF9DFDD183237E90C2A707630E634F2110DB14CC1DFC679B8AB666785D45AF8309F09788E1A89C1AB0B27418466E3511BB8AA4627E883E25F7274961D7C151B973841582751F085A04A6E9D0F413018EA48154644C46CF9BE12F017964B1FA896F8584BA1E133245CC177039D9C6ED398930F14F774A42B4910E4086D0FB51336CFC91B56323A729299E8386324FA0BD085EA69D349757ACE5E5691327DA404B9ABCB1671FCCD8BDFC2718E1F37ADB122C79E8795D9888CEF199CDA6F35B7F4FC4A5CB7279AC57F68200EF49E19BF01699F91CA8CD40E3E229BB41B78BFFBA13B4F5CA7C0F612A741B3B48071BA683758E09BFFF310824AE84F9B3ECCCD796EB3A08BD756C0719F92102FFA8182D0D12C62335C7A9E1DBFA23A8565167E8F597D62D46ACCE7863B196DC5839390E089330281C90F37F6365080C8492F01256DF5947F8CE9BB40F253A2D3D0CFD46C1D6212DFB1A843DE7EC8C560B608CE3CDD0EBCCF07C4E633CD9B52A4A9708EEA1016112D61284EE5C505AD557DDB0BE11F6EB81C6867E86468F84B0210F08AD3301866846060B08946C93DC2BEE6D343099973EA2F5DC15817C802A9F0AF3110025437F2035A8150605028335FD8435C82EE687D003FA19D8ECFBDD4B0B747B0CE51108AC1D020D078F0003828061A1D6CD1223FE98B39C88570B832B61B88976ED384D38C420EEB410F737F3E035279CEF11BC1D92031DB7EFA8763A384C8BD1E90236E81F4E4F241663D6EA56A0251FDE2B18DA0CD6382357A68C692AAA3EEE304874E73BBEF7FE55E777B2F90B28DC5D81E17B82515C8134336AF6A293BE82E6982F26C6C13AD4FBAA480CAADFE15A2E7809D92BC3C59A457236A24BF7289A57B1D8CFB1C9B4C049DEB354926CC456BE616F99584B7692C44F0B2E6F57F607330ACE858691859FBED295A59CA358917AE44A31201008FFC400EDCE65F20B9CACB04A387EF348A7F6102EB94677066A5AC9FD8658177B5B8D696A5549FC8CFCBE39E12AC717051D3F7D6706BD2B03127E17C8F963BBC7AB428749E42A1AC74D6F347796B287725B3BCCB82D8FF2FA2DD151BFAF11F3A2BE26859DFF6CC79A7D294FAB3FA047E67F3CB4CC4F690F03FE9895BAA08BC04E067105BD48B0423410E2CFAC3B2C5E3BFEB3E34DA27E7D315935E42C918691385C836ED179ECDB54022006AB9D9D59CD965FFE73EDFEA408A5FEC756577036C1A879A16BCCD439234C3A0825609F1FD2DC2DBF0E5A19353461DD6068FE73BC2C4274056CA5D8FE1576C834506C0055DEE008A4BEDE2B583937B7B19DC35A83FE7FEFCF82DC5839395308736850292A86CA4FEE4CC464FFDF98EA5CF94B3FD363315D474798D284C45B8811F2F5BEC8F69F0DE0ED6B454105F0E5C4E79622415A3587B9BD0696FE4D5DE149997525C53CDA075DF75982863CCDFBBF39FD8F82899CA6331459D2A254BB27712ED137A03C3CDD90CFE8E59BC2BAACBB1C7B1D5936136F5E4BF40638055FDAB0D50FFD11FF9B96BF60CDDC6467E47F878522E9655BEA752AEEF8975B549C25689E4337222216F03FBAE4A7B3FBE4CD6F4E1DEF15100884B964ACBE4648DF0D75C7C5C180EFF321B984D9C42E6DA091F87BC55C446D38EF80BEFAABDCD3E5F6B7645B40F8BA7E0EC6A68FFC4EF952D623903D3B1BC14174F3240E425AAA77B01478B1D00D8DA08F90F697D85A3E0222F7F30FDE5105AA33BA02A59CD23FFFAD1A1BBF04D57D3E5BB337E5D8C7E1F7B383CF58AB35BBC1D6467127E320C3CBD295B89B320879570CB3C23C5AC4054C5C629EB1B4B283F8462DFA1D2EFD3776B6D8D8451B88971FC35BF440053E24856E44FA51440C8101B16C272395FB6D0E42D859166F6983D95DA32CBADDACE25937EFF5AA433A4F3D00DD1DC4D31051FE5FA39C80247DD0BB0D83E4165146268001FDD3056773D9320925109C19E804FAF1116083F8BCA2909DFE65AC7D965249434BBE1E797852A5F316A925CF11B18AFEAA6B1794AA8E88CD6F573FAAAC823A4B531ED948C0C55AC967FB59850FA8B5B652AA8F1BAA8FBB3EE63215E0139D06566902BA133880D8FEB9189FFB37A7FD5B23743A39D274A7F26E407A4EF757AC1585C303858FD36EA87B90EA217179346C5806D0E560D81A658C5A4BB6956BB2C662E5CE7A04F6AFC9D5627CC485754345D565A9AFB90C1474A07A1FA81109F176905A211D08D084726485994644A52143AA918D9CC83753ABA5B5345538BD9500D74F3A0D1E7B0D3A85AC9C6C554146F3A3DEDCFC6DEE007846B41CD0A75782ECE012C0D20993A20A67AF1CAC29EB1C4D911897AEDDF97A8615AD443A31A846659BB96B83F830D63B8CEDBD17D6B9C539C063AF1F58DDB8510C85015C82C379C1BADB2BD053329455EFC4EBDC46A29E686B39D5CCF7FABF005BC9704063EFEB351996FC5D31ED9F4858D30B1CDC0CC552FCCCEBA1953E2B52B9ADF93DB5C412B060F26716C75A3E020A6FC2896B72C23A3DB78A6AEC96F833E761DDAC8A3EF80FCAAD68696162C66C5B08F48569B85D2860DA95C5519233F73423A28782D25240516F5200F99FA6B8333732F5EDAA969197FED40FC8E48FEF38F2A322ACF51A2F4361C022F19FFFB1163DB96323FCB7DF6C96A65887E32203696E4D8EDD4FEFF5F41137010DEA80B856E715CC4F51B8A9E83BC7AB8B08A1719DF994AA13EAABC8B0A8BCBD6ED8A4DE267666C70E712272758442CA2FF9FACFE1E0927D5374C49093AC3B5A659DA07C5A490A6B528686E3AE3DA2671E08981B0AFEF2DA5FDCFD176B3CF9C896D1EE5154363A4A9D9676BA8A3C351A4E195CD7C558AC9F7B24E6F13A12C4AF5144E6CEFF00DFAE77B888F7FFAC63708040F8163BE41E40E22255BFD520A9ADDC76E8B2D8D71C16746505078186828501A3902BCE08CB1564C7716C974BC789FD59C71FAD33B4E30C30FA8780233432FB3761B5123BE992BD82C36CF6B6EDE11A2964EAC4B0E650E1B59BF6E1AE26292E0D8789E6974C4FCC6C7F05FD8F6339838836C444B8CBD87FB6365DFC28AF13C636EC069F12B78B7F76FF41369B0A09751BBBA605A9AE17E7B198EFB6C5A6BB06F54169BFC69EF9E019EA5CC5E3ACA448E727E6A57498EBB4FBEFE78B574AB35BE0526A97A05258D22C814020105EE60DBD3E881DE66A774CA33A7C4DE00CE686E620374BC174A76DA4BF4E7DE61ADC90EF1D7A4E2BCA2853B594388EC8F0ED3EA0AC034AC6B6118212E932DA140387553CAA6E9B7B501A225F32D65975E4D009D0540570519B0D50D595DAD7CDF54CC47844AFA95E47CE30EE7B69A7EED12802A377DC0F16C3E4B7A6AE33BE4F90A922126200E10FDF882825C9EABF0CDFF93A0AD09BCA63FE199A2180B2CA671D636955FC7E01380C852AFF23F42783D8A1E6702371FF943CF512332695DEECFF62DE44AB41C88267E58762BA9AE57AA3F93566E4D13FD6E69DA961BF29EB23F03FDD9F14FC0B8B627036CAEF958295241A76B1535DAA233AA087C280CB8B6D31DB6117B6C60C0939F61EBA646180E74CC0F50474EB4E6DC06C3497090879FBB2596A3538B4C1E4DC32F47D64E31C5AA30BE4FA05A2E79B9F8BFF3FCA23E7FA233156DEA3EA638CC1FB096B0DE1C455EF2946229B7352D79948EAFCEC70970AEEFAEE4924F326B5BD50A8E68F30D817C02E6EA82364608A2CE443F286905329B6428022B18DD94103F6EA7DB3FBF800AB1BFC0082028140201068C9C345C30F59276892E244CE382A2FC8881A94F6E8B02130F09C8E4BF2843A4504F682225AFE3FA4C9C220AD9936FB7EBF9C26081B1BB5E702207E42AF612350331ACD47B1EFF31299CEE4C5C67219F0152EB81627F575229B7ECA3C2DD04F8D110697D1E3418D8A248D0A73BBD7F542D47CC6070B15373781F1B3624460C2E64700EE970194C2A6F885C57AE5D39D68FABE48C6A189CD5813784B09F2E2509066FB44C8B67D2D3EE5255BE91104FC766AFEF5918BBEB6AD57DFC87DBDA8B7FBF1D39A39A8C3E2BD7ABFB984E4DE1D27F4827E728F28CCF0F4A71A3E5F37C36F77F0BBF5CB158D464D3FE95C40D6A20513915B2CED0255C1AF5DD0C79FF70A9D1E1C7E06468E39463E324CE8E98673CB05CC5DBE5AD7D4A28FEB09CA270E0016395844F195B7C52808933D6C37D3CF386F0FE7BC6F7B75CEDF140E788D5171D789F4C4587B09AE8206375D15A80D8F0A33038FC3212BBB857E314CC83F4FA557392B50B3AFB8E74EF25E9E0D65C50E70D27AA31666C84A0383934455EC879495AA5416DE4F14191D3AE6631AA92DFE4B740EEFE3929C197ABD11D623325ED7148E40A1F9A3332CAECD0643325D9BB6107B3865F3C6EFD5F228BB1DAD55D620E32E0E4887937AFAC4FEC6584136AF4799FC491E390BF93132AD897C22E396A7C9CDC1F4A3D8270A738070389FA250DAB4CE916BFBC832162A2A8EF4711D03C1A1F127672459B465BE4D3764E9110602DCD2C5D110067877BAE1F1FF395259006A2A417A0444CCDF834D7AD3F1BDD8DC60B1BBF85F8500EFBFC221717FA61D2ED22AE80687D77E57158FC08D205EB4E217B29CA63D292EE384CDD04F0D11108C4D2E3A1C7A1B778681B79EF7B9E9679AA885992165C4CF5DEEA81C43A76B928F8E034E66CEAD3BD356F0A7255719DEB0EED21698182FBF42F07365D8079BE2F1E1585C90D008EC76D5982974E04667BC8352E926DC401D40AB43F28FAA996DDBDA0BBC52C2906F8F98B5C47055DC3C6A743225311F52DD292700EB423F8335F7966844A40802684872E2100907F3BEC00D213561B9146EF1358B9D17439A4EA63EA90B0359C14B0083264902C8052F993187986855F58B03EAC2FFA35B34E4F63AC66065086CB1D29B666BE3E93033B9FCFCC40064697F55D70DC6652C9D1CD52DFCBE619CA261988EF86C5398BC9BA9E6CB9CC6EC86928CD95628FED37A86E28A286F462D482AF30A3D1F75D042C65040601E0EA4A635F98EBFAC067312441EAC90C1822991FA0DE23684D404C69DF0449E351665F353B45FF5B75DFE5D124CDFF0AB82DCC11018103218F45D8020C8201014341804030641C0F5C38E1C387D2A94D0397B5791397E1E7EBCF4D79CFF7705E1FB4D0C95BF8D6F8E5CDA5C1BFF96960953392A0CC8760C0256DB65F75324D442722835940EA4CAC36018102B4360C04CB120C36D983D8C7684DEC82754F1C2C84B165244C94B73664BA2D6D9157A0FC8516846ACA1E8D15E95A8E8D972A23C8C1515ABDF2FFF7ED435D012B5DF1B60EF86CA4B484742D60DB498D90DC736A5D084BA0AFE7DBFFD9683F59DF97BF33E96B5C605D589943DC8A81CD5683EB3A64A05A1B53AA208EF77059D38970EBE63278F0E9DD008B1512EF1FABDAA9B7BC2D5F7DB2A650EA30BC2BDDA19C07EC10DBD36D7851ADF4192C0A5B9303DE9FACFE783E947F9478918D71B201327A165A7C83A8E9A3B131B480F4D4D9479F26744EC8EC5B94BE68072533DD5BDDB877D3BF0ADFA09745485C9701ADD046D2106909AF714568536D2F9FAF535E093206F8E415552C0DC424523F2B02D268DED5B0A40DD5EB1236F63AD6EC0939E17F9645478E5525B236B2B7A9D4E4147B4569AFCD8F369D2B8DB3358D9B958EB2A383C14326428BE3A7856B918BDD8BC6A153C022306E4EA75615D0791ABFE674E2B3FBDB244B34AF91A4D3F8D33BEED5245A014D6F9C5578921DA77CD7F2EA97125FEA2823803ECB54FB4E1E2FCEFFB9E9A920AF76FB4317ED242243BAF03353A9C312DEC6F5DDD5B5501780EF46019C4D7FBFC89C2F0A50433D3DE3BFE6515807DCA20080DC91C21A3E5F7E906FBF526A7791C83D495E1AD3762254FC6CFC309287DE86B810C6A7990B53AC650888A65014E0CAD8248E7BF9AE01D80DEA942AB01D8588DE2D3F39F1E60A249FA910E7CA3CD10E6CFA0833C0CCA6C6046BC0C8501343E26C6F9A1FA73EC897CBEAF52B6F3C57B302B53C9A2CA1848A825D002A43400FDFCC4C604971E5E2D46AAA244FE0162F7CF2859A20E87639C9F66D75563EA17DDF0F7C3F969FC0457B16120D48C54C2503D5E3DA32913BA19A8BB36BA6836E8E47705BA047F5C53BC1CDB6D509A4604A46B0A1FBAE6F630F1E9394330547C6D617751F4928BA14406E55018F047A3FABBCA4EB88FFB14EB8AD2D3F0C06FAC3882F9E1C62D7B2734AEB85EF34900154879369ABE3480A6358BBDFEC9265DC459D74DFA8BC143C47EB41299686E1E5C87F65884CF7B34068997A77D8A5328A612A4EC3A6CEE44CC43E2A2610C30BE599D7EBE8A0224DECCAFB264186E7999C31895510D06160E017C198301C1A309A048B43B3B34309B68701DD010D3A0A19141C3E5D89E7EFA10375429705FF60A6EFCC08AD1C233E3BCB3782B7884AF6F1D06D62B1C389E5BF4C5B66BF9647A5FB63FCFA1914738ED8F5B43F312555026FBD7F0E876B7CD746D3263C81E4F2BBC1182CCC8470B6FB37CB408B9F92519F1FA925505F61019D8023FAE5046447E312D7FF1AA2D5B1152800D4D8426E257DC0808C9F3664BC2D67D20196FA32DC51407814020BCC26B4CC31534813FBAC673FA4726785189A93C98C6850A28F5C77C0CAE027EAF19BAC7827C89C45D5EF03F3C67DC4876E35D87D8658799EFA11D6DA7BF6DF079737A27D5174E967F7908C98AA4E34675678965B7236478DE2C29CF3D0C77BCBA1FE0BB2A7D57ACEF41789B5503FBBF5ED09964561B773705849232D95353088A2643FE488ACA1628ABBC2DB8EFC41E986E479BEB3D25B54F121FFD269D1148570B7DBC002341B751063A24188B9544A4734A96B4E1C4EA02DFFFCB94BA7C66FD878FA518AC601E5795EB04E5CD114136619D26EB8C80D29241532BFAAE7924071B3E07F5655976D3DCD3417E09DFC0D8DC37392930485382A2203A1E83AF6495BEDFE766E5148841C500861A071B8F1637A78FFEF539F95FA56FE82953B73D2DF045F95B39D4468B614738AF44A636E39DB5C378CF0445883B752806E1FF046C94D51F5DF3AE6BA593EEF6EBB36E2010080402990B108926512834421FE49E0BFC952E79E080A1DB43E4E94DB7130B4360C05C614D451029D58D9CACC5E0A50CBB34A3F02E9BE44E135E25D1E4EABF61500D80A4453025391B5AAD41F23941CAAE1B8BE7C8493B59ECA0A3646A5F5617D7B2292FD74B66A6DA17164A7A7D58D449BDFB49A5E08FEC9CF96B55A2F80B836E91634831015D537523CAD2FCCFE7242ACD88D6BC849E7F320D0811417E4329278AEE1CF92BDF67C4E8C93B5F2667D79030E3C6B2AA719388DE615E815AC0C6B27E8837A5EC77443816BEB726D63796CBB7ABC925540FB8BAD1FB2FE362BFC05BADC786DB5EF1285E46B035053E4C196B91A49C848DC48ABB0B8D53E2A7E7622749088246C881ECF1BA20F1FEAC4259A95A1EBCC3EC74D15B17BC9FD539E4087331DF9C4CD0D33D15B75BDC45A8769F14D29CFBBFDB24A091BF063F755D75858DE75C153ECC3854DA8C8DC26AFFF7EF4A590F6B57B4CF08DF2EBF6B2DCF1D9684B9359909276B36F4C289DF00D1975AE413CDD4925C9FE40E9C2F1D343AF2E96D74C49A27A219E26C946B6EE4DD10B25A673A846001F65EAAA59F32E82ECE8C51E9CB8F6E70F94D031F9B970992583517EB1ACECB407570D342DE818772177940C2E962428B43BFA6D9884F8717E9C71BC5501830022D99CBBC9183A2B961A7E16BEF923A0B8F7089F0AB8C88076C3DFB922F4F00189007C550CA06287BAA4D0D4754C7E8196A77D5478A13FEB5425C58774627486EEE59A12CBE08F20C6524BE5011A566F4B7BF5D995799E320E30957BDD8205037E46079BD6683D0D054276497817A32CC416CE4BCB2DF10DCFB3F08A909BA0B51BD0AA498DC61BC175E652CA169E48FACBAB865501A0402038271F5674E07A78BF705180207024341E3A540BE7A49049115240EBBCC8D3F64F771F2C9A69BE3C0FA5D9EC8AE4C649241766F829FB957180A039EDB5812DC328AD6170C4EE747C1E10DD47D5D3D12E427FE7BCDE56FA65E01970013DE0FA5AA760BE5B1B185CDD181552E3FB9846811865FFE055D2952934E69186390E6B03A819D5B18B555E5CDD550A6624996ED85E2AFA11C0C29BE63315886F822FA66D344F60ACA423182CAEB0E05ED9570267478EAAAF87CB6C2D1E646468769DE43EBD276BE8066D345AD59C99488686E4A26D7CC8D4DE372DAA41424287FF1FB93EBAD8EFE5C570F68A5659BE665353BBE61AAF9C88468D595A0C3AD4170C7671A99EBE77A9AC1614BA6A1883A958510CDE98FB3F7E5916A16BB22651F13D55A80DED4C7D63F03A572B0C2DAC19E643E47385FB93DF1964466342575D3EA59FA6B37840404050281402010D8001AF20CD68E28DFB6360824D2C801B15B8A83C240A98D74EE55684302C37EF1426A0273F8B8324528DAB7F0EDE2B81CFA71CE938C3D560C1A6716889901A27CB380B8E4E59D3E6ADDE256FA3FCF304311417D1966BC84F522A757C5CE3BF36B806B7BFB07EA4F9DB7B44E8AAB6017414ECFAAD850B4D1E28332DA7428E3BB6D3370B55733B84EA0BBB03529549997EDFBAFBE8A85626F9176387E6EE3BF6DA853C5F822D8CF5168B6FE3FEB18BCBF1AEA347CFFF3B711D432035CD1EBB2BC92A72B15F98FBD02C5DF2F0025A27316CAA13918B1967B427090DB4FCB41D19406D7D5C40FBAB095E29F4606DD9C33F0BBE4D230AD84A5AE7A09A34DF1DEBBA3E4F42CE37F5A61AC538F2B1E5EFE94E4DDC8100149EC2ACFF2346594547BA2DAA1FB6D60069B57F81E7D618CAC5C0AE28A9416F9C5D81633B7791D61101DB0D018FC25D076C0774361007A06CE2DEDF393D4848B5AE7974BC5C3A7C7B00FEF8CB683541B5272F8259E5F80A3A1D5E46FDF752E264CBCAD741D666443610FCA1177C23497CFBC0D8437A7B26E28B16A01219019E6E051B979AF9863C077996F5F40639C8F4510D516774B11C9959D9308B79E4F4E3CFD66A5C015822EAFEC3704B4B127889AF2D1EF3FF8558B5E4430D65BE4AE2AE83FC3883F274CF6C3A0F685038141DB602EE453B0EC8C298AF132040638942664D27EAB0BA038588D850D228CA6A17B18D7A044718DCCE56E139311B200DAF7CFF49454151EA86AF4DD3F27CC4B448F96A2F131B49729A404D42C844B42BAC1A265907B1C8A2202A2C5046DD5C2A443114186C7E8A678498806C8F7F3FE1D5ACFDE3749CF95822A7797479ABDEBBEEFFC7D3897AF41A2E33BFE07C87345A241E521F9C7EA1B15E4ECBC07C37D05199121F4D64EB0FAA4C535C4B3435807C9DA162229339609CAAA054587C433667886C080F3AA7411FE7CB359C6AA6E027F41A35FC34B1F3BD5AD3A413A8D4ED490F80819404E70642236929CA10867FCBD43CA0FA63C215D4B141EAE729CD9FAB427220FBA1B3A1AE9D041E9D0BE66910FDBA16E8D64F46052525252262796CB6426F800EE2ABA4E3793B1108A16CBAD305037347486D1DC14C8001D88C5166AF36A369120A1550FEF5AB5BE4A8E6EC02B76A6CCDF034449EF8160F9A1F2B2DC58397D299474EF56491700025D2213933B2A40045621788F1AEA47BD7164241BEC30FE9F2991DA4E4351D82B13F13B9E0418B4C00DC8B02300C2B7800DA8B1D7A9B1E6E6C9A8CDD7FD97163B5879C365D2A2CC4286470C615819D0A7116FF769D6EF02C7AE924360E0CAA71DD4B8BAD06223F89F65682283D2A176B43AD6B340F75F1CB71A2EFE3C09C086713E6A1A29967FAEF7E292865A4AA0847C2FF43255C97C0B1BDAC6D7FA7DA51B9AAA2C226EEF7E190125589FFB1ECB526E466AFA6983B66AAA69935FC96E018E366C701173755837380AC28C520C92D344BC96CDCA6A8D419A42AB9BF1EC9930DDDF12425AF83F862B621901F700202FF4679736E6C8069F08AE29B06AF0D9862452A1C01E76C218006A83B5CBEFDF6C482E97CABBFCBCBC7EA88F5E0228D1E384D75912B595FF5185888318D77764A6F87B19F60367B1B128951F6E5EBD650966BEC8A72A7FFA3EFDEC679E76DE201AB37A753FFDDFAC748FDFE300BC2A9B7A070E52F9FF1F78F84F3EDAD26A138ADFA8F229ABC7E28D632FD627133EE35808694FB08DF350DE6F4115FC78C6F8D07C170E35F3A1EFF3D68CE15B5A4ADDAA8C7F0AA02D69CCEAAB40DF6B8C2A2E78CCEC6F781B5FB6969CA53C6A1C7B225DFB24279ED728FDFEC919EBE4F6F328B303E097A590AB666793FA5FA584E15BA3F2DDC1E73B68151D96C21DC3A685C1369A48DB7C60C09F322336727D7DD2CE20E29BDAA2F3E376E0EFEF4638161EDA52CF95BD50659B771FD07F81004EF2E75F3EFA147F3E7820439A1654BB4DDE09F1DC324DE39222463C3FF4D1BAC1DAA07DADCDE8EB8D3C5E97D1FF5F115A5BF63E725357199132F45DCE8833FF0A2B217182570B3240250C68701F54C29100D381EA15798F38A3A0FBFAED70676D280CB8DD094D4E8A67D77A3F44613304B82184DCDF5443F8270FD47B5D356551FA11002AB413A0D303E19B755C7E37D346D54323B27600577346BEC50F3A1D36DA2B8A6E70BE67F0775DB369A53BDBE39B5C1F27EA4D20ABA61A1DD49969BC0CFBF53853D5B65F589FCFE7E2D6ABE3B2546F687DCF31D863A0E8A07D8458E6840E90BA5AE6D635D032690936A4EDC0F8CBA58DF3539ED9C299421A7E5F36CF2E3D197F895FD04FB3E1359A2B95E194D4699B08EB60D60FB86CD3F680BACD4B99F2E269F2F736A1CBE4D455F2D5BD63E02B5EEC0FF1913CF342FD7FF83DF2D9264F0AA3B4D15ECE80CF54CB46272D04CC18C4F116462B376141FDA819541C0CDF2F73EBF803DF97AA1B6AA8A7C6B7676AC56CE4039C6CB56B72E6D79CBE14853FD9A1FFEA707E181E0B0E7EDB9E13077543C9BFA289B6F3A43B4B9778E334C1DEEEB408F8D766191A1577CEA1EB43424323AE2A7693A16EDA0F362460DDCAA55620A8B6B9FBD2A979D7C2CA51F4B0528724AD98E6768278915D077EB5F0827473A75514F9A724084205FA5A750EA602793E821C412AE6D5BF8F490CF2C3A169D0AC83EC8836207E005BDB56AA0CF0E1212475FDA0FFF78FBFD409347CB50362070980E8B0518B972A02F9FD01208951B04856663DA4AD28B0DD9C51DFC7B114D9329FB855198320DBD968637F73926592FF0F8BBC624DEF45FC59210C4F7D357973A76D7C5BAE1CEE3FEF0A0C501A3198306A134361003F1AAAC898F01FEABBA00AA15E27D2801CA5C4DA3ABEEC65CA7A59791E163C31C0E26736C2AA4EF8988A5394919FD09F701C4F9DCAEE68F48160B228D90389C9C9AEE8239F6AE9CCAC1D32C4BB0104A5587F7E18460EC86A0643E5534419A912FA45FE94C59626ADC3CD48B93B097FFC7A6C0AFC723C79C8373FBB03680DDEAB1ED604E9C53FFE13FBBA9C4E554740562F03E3617FC6BA359E02EAA8FA9013A6413F2547403075931AC416C9C898A50539C3DDDC500EF3798D15B79A5371E1890FF8097E1C93C7732C8F72A9267DA5C1BAB7D71DC402A298B6CDE41F67B20192A0CD8BF04DBCBE4DEDF37C1178A4BB65DEF1CA388EF4D5E328D9AF4070E166379C7D11CB1D0F27908C67CC1B055D4CD306EBECDCCF7E5CBC0FAF86264B0811C5C7DE2EE83BFDDD44C7809D184F89DC9700BECFBD0110F4F7C18DCBA91EFD84ED0DC6D474AEB896653CE425BD61073444DBFC81EA498EBBFF534A8482DC797D5C4324EA21F356DD4441C78BA4E992A9BF02D76F7A3309751C56DE494C7E98A5AF02D141D8CBC890163F4399E2D47068B8A82E98B3D8B32CA8DF2ADF331C9CDAD736B1917C4C7154E250346568005C5B2666C581AF4E82DAD266EDA8A6DE527E5024F69D07FB40CDEB91302A99072C02C61BC021E733609390DFDA7F69DDA59777A3010C1012150D2D53FEBEECF9507718335C7F01CEDD5ABE9973705FE122D885A6322B00320594EE66B810F209559BC4662E5233C5185E61C50BC5B4CA3DE39B3F0E0CD5F79B570BFA19AC160946C43DD20DB360097A5E4DD95D6B4481122B6645012FA24A4C456C29299F0337729ED28217582316503915F7687952AA7B4AD4F72C85A926954DE89D9149B461470183D0BE8490BDCBC609FD503D7F2DB37DDB4A54785E783978512CF54DE50F05204941296B5346FFE56F8B60CEC0D38260AE416A865F41969C1F09CE63D2D8FBF77A0695E789E05F89D2F25405D589770991CA4AE2DEAC4A62386CCEBC49E16FEF34B678C170A48BC2DD657B080193D0A0D814C3C85C934EF77708190D436040FF340CB7A092B8FD668614752141248167F1FB6B4B4F1AB6E2A116BF62D9C94F40AD0EEBF5D26F63B9685B70ABCCDD73E6D5406013D3B34D539719BD2BAD42A7615602D6FB83D0F4D5EFB20806590CEEA850137C20DE6DF5E21A7601B0AEC0CC20439567DA16F9D8BF98CF73D1E276E323962DCA88347DDCA156AED2237D5A6438A3033C14060848E7870B505721067134301C9ABC61C8A73E331DEF4DAF409D90809DEF10A200E3762C77C4E4A87081A6EC53FA89473EE1103AC2998A49212EFCBD5FACB4E9BD70EFB14CF9B5343DC12D8FD051F4F8D73CF62AE5A4378F91B828954654F7911F331233EE5A1C2B498F82521D81A0C7A31AD595725D5F11511603FE546C41DFA68A1AC8049EE11905B7B6CCCCD148F0EDE7DA1A0DA9167471F5C5BB21E135ADE942318CE09DC5370D67E97BE3D5ADC7240EAC4A0E29AC99FB3911440B1C5A66E95B60DABE2496D3ED616CC9BB15C812353CA46A58FC16C08A9395AE9056324D415793FF965FD3B664F5D9E9FAE8F707F09989E2178239ECB189548224FEA7C3516B19C935D4DFBF26E84DA84EFB29BF2134950EA8866B3103BE75C67FBC2B88E70CCC36F6A982873B2506708C0350B37BC8216EC3449875B9A07B5893424213AC5543960E049D0CBFF1CDB0E1BFA8B20AE0ABB11A2196DD060BD8878C8DDC30F5A7ABCE355795A8EB70ED2B020023A33A25C37918757C61B8389C39814850234C6875025D88999470683BEB2B8DD209AFCAE7AA5951253FBAF681B7CD2F07F31888017A81BC868050B8C1F7DFF2A8D1CD4D7662DA1CFF9453E8D07E749176FFBBADFB09C01D9F3785437FFF79983A5E8DFCBB831A0BE365EE91F162F5ED1FDD487C807D1134D587339E26A91D833BFD9B2B8FF8C30671C1A0C00BDDCC4AEC1B6D05C660C5707410294439061A04C252431902034F217BB290B6FE94D1357E84238B99A05017DB2F95BFB03202A1D1829428485F01B62F038F73B56D9107C4CF58C3702AE11BC51ED113EFFF9C78AF56427F9B2EE9454081BB612740503E34F68CB5AADBB0634C591AC77EA56D1CBED2A5C413588EC28541865F244CCCFAE4DD8F6DC1DADD5DE16B6B18051400B10545BA63940D11FFC96E41F61B314685BADF01147459E49D342FCA22851C2CCF0BE095FD4D818570ED3C0E850EFA31B3EEE311C7559B8242D06518FA4D1E780E743F0A253484D7240FB76FD6EAC6E779B8088C3993CCC7E3B72340AF54BC74566A1880CAB1D3DF3B969FE0C27E03F7D76CEBDB52B01A1E5E5CBBFF4E203D4C524FEB28AB6DC6C6D7469BA8F1D538DF8D8468A037A9C26DD89CA743E144B7A5EFEE271A0197F1B1921A612C53045D4F26881C1A60F6E601499CA1102145AFD5248B8808CCC6F8657EEC2D2F7CF3E481E6411869046F7E808DD7908DC887A1CDD1E33D35D3BB7E0E524171103BC8A4542D5AEDA7E57C4EECB55E599BBCED87C6FD10D2A58B896C24F5C83246BB90E5D16C51CD01DFEFFEE4738B75799D49B845DD7B45D8D1F7998F76F0CCF396FBA6D4420404D2A1CAB221BD5FA5C243383A4BB966E0A501F98DD53B786214096702E3C50BAF679DC3439FCAF61EAEFC72ED9F0528FD7DC75DE577ED567C9B9A852F0EA7C1D1E441073F86E0573C15EED5A14C6173731597929BDAFB90E6087390712188815ED8C601E6E3CA8707906B1F5A12FCAF53DE12088BFAE3235E93C6FD21C46A80814EFC0789DC58FE76B2E445321BB9215B7901439BA0C7674071D7406370953E8DFE75783777E703AAD560390B983FB3CE66AAF07D754955AB1EFE3669E69FDAADB6EEDF84790135F93F9036FF5F399E4A30AAEF7EC61123A2010CC07E0E2C2E24E1BA3F61D2C1DE8DA7F05A65D41423AD11BFBF05881BB06716920304F0DF4BEFC94A1E6D14EA61B8F886CED0CA281AFD727BC308CCFF9F7F1C65CE6375BF867EBA888823AE6F4AB8FA46D0227073DC8F01E70F779F221AD0B9B533AE966D5E8B735BAD3EE60FFCA972E38E1BF3886D4A6A7D714D5DBE3F077064F2594CF087F78978E35C2C995B906699A4EB6C6236D267040670DBA8622B7783AD4050201008D45C4CF2ABC86BEEE9C8D54139E9890393769464C74918203EC59E0FCF17C14607CAB296FAFE436E8BB729597A2D42C938F278BDCE1D310320591045083FA5CD24C52109E482A32BA06A0DB2371C5FD16B73B37AC862D1F7EA86F8D41998659A6E095F234A2E2669BD918E76337E89117E3F77DCFE0C2166182D04B7D297FF44D84073F6F21F453F8D10AC986C1C22FC767BE92E32F79084FD9768E29DA4189FBAEA9CB69E6497A782B0CCBD7BC9488CB232F4348E6ACC5521A0973E96E7C12BBECA9DB58FC7FBF526FEA3935F940DFD1956DEF0706CE522ADF3F43EE9D090A7D418722C985C7F7A996F1DF6FD4512AC8E6925A16DE65018E0683861FBB76DA29B8F6365F46FADC639B4407251D3928FE3BE45C66DAE0B0126E0539995FD741FF6BAFA36552EB2FFB23BF52ED51B46186E8D804CE5C5959E980141171B393D0327A340BAFA5FDFE209A6C2F2B9882788ED8B798C84010BBE9C3AD6D7AA0E25BB2D02C2756235C63766F347FF95EFCCCD0877A44E7C660161D57ECA76EDBE53FA03D75EC9A77B6B9E367DC480A60DFBA3A4F119367403976E64C7B8F7BAC05942439EE14C22CA9BB1E74E7DDFD004656C5F0F6DFF1998B82EB1832788E414BFA26B31FD8C0173E433A0A377C39E48E8D8345DA04361A8F0C5C5999E35B9F88024BE99C20FB6907CFEA74363B01F258E4DA28AB9715BB801580A4939440ECACDFD82760319E80A13B7030A032F02F1639659868AA05F50CF804F511D548C608C630C41CF1040901DB1BB636288C31001B901AFA2FF2608D1F2F1B277D0F2B37087E46914DFA15030A9C079088A83150611CC714CCAEA1ED000A561901F800674406914F41964009C61802D8F638D13C76446CDFE3B35010941ABB9AF0FD54E224E667AC174F0C1A79F4B7465122B5FBE5839D9B00E81018163030A6DA92FF6E27D46948C38DBA19E5080C328E76B14F9489579A1FAFF0CC061C9F09042BFED25FCF54FB2F8D7541AA5A680D9886F5CAB0EEB235E55F84BC560FB3828B3CD30C873781101EAFEEDFA57C311AEB5298EEA15D831BBF6386DA4D452F4E4DF7B72FF4D83FE3D67BC0348031A1BF16112C8015A9FC80AE98FDA737F17B489C6598CDBB7163589D9BAC51D47995D6973616F8AC63B43E579ADC3239F394B289DBF21CAA3B181777495D20536BC0407D69D08AFDE92E1D001A3ECB7B3B34E506D4BCF655DE19C5560082D962263CC391BF44F497281BB571830F562FB117AE6F9BC4B58222FE54DC030F22920C5C1A82D0808D78F9EC825FEB32CDE1789F8A6E8E53DD77F22DDD7FF2646971A380330C7B9FDE31DA26C0E89B06C9BE5D2F6011E461C357E14B2574351725E532E8EFF3C702E1FFC3338E3AC774336A6B6556F6823F43CC3D49E3F5AAB31A08F637C4FF3267F68BEA3B99CCA961A8E5EF744E8B925AE3FAB9A4FF3BAA167BE1AF3639D596FC64ED3B2B9A0629E469779329C60CD7D9F882586F2E38E59D67BFE8F77F55DFCC7579B9DD030E01DF223497A5AF722F7847095D27D408B7AD4CEA014B1E352A5CCA964B7F08B88CD8F746252D25EE8478FA973CA4C0D989A66D78717054D9D60A483A632ABAA966D42D68053E80A03CCF57753DC46DAF675E4FFB82FB4F0920755AA50DE8DE14797827CE339F6C8B1CD44DC66E6EF3A22DF98ACEC12DB7B72B000E7722E20D4B7B27EA18178316D5BDD609341B67C96B0A29409A514C89DB608039967EE03A7DB9A59A243B131D248753A4AD86A1707D6B2FA0C5C35BC19A101B9D70F8C6D210C685C644362D08D3BF98EEF27AAB2D9DE02E0CA5056055A3C3A3D84C7D86098C90398DDDD1602EE28163AF54332984CF25EE04AF43FAAB6939F6C18BB9038CC358D251ACA421939A04C71B4627538F14B2012A281E33CF82777A3DFAD5CB23450E867ABE571E824886FCBF1D984781E465F64BF530026B42D8F3E7D70ABEAD309B83F03B75D7B04C9E3BB2CFE47CCB3C83702E795F9B08275EEFA0C56DF25A5F8BB0FAF33BCCD48C6DB223853DC53DB9405B31B2E7AF71FE6F997916E84E0604F7ECE1164886A43840CC2449C8449377DA42A70D6ECF94A0C2A81EC2ED130C31CE8D293AD8CD298A354489E90BE8F48C34387C2F8AB8DDC8BF7275C257A9E76F4EF137B48289896DF3461E7E77476AEF47943444AF234B77AD1940F60C2B56BCE9BCD436BDFE832FA8D64826D77E5BD5E7A5BF63FB262CF5B12510EA092851138E7D52D125380AE6DAD2C1B0EF4AC9F4BA03B1367D8A8C0E763B9D705A3BB546D33F6C5CC9C9293E48F99F122C5A3DD578269325E2FA8B1895E627328C4C2BBCBAD82BF0DD85FBDFAF719C0BA5615AB7E0ABAB6A65A763058B5A4DBB262A675750DF7457EB85B53DB39300EF1A45CBCDFC8CC0C5369634AAD4361402580F59936654D15B0F7759E84B0771A4F1CC651D7088CD0011DD9BD2CC8E40510EAFDECBB5399DB7FDF6A675C2B641466CE5983BE7B3761B22A80A727554A25E9EA0141439EDA23BAADB3B6DD9C6C3E3441E78B321518FB7232660486C280B5EC301A22D635B7F650C31E211FF5972A5EE1BE9CAF0638C4062B175B51B83D80BED141849A73BBEA5D9F04295B4EF5ECED670D6F30ED978F0A89B7E5C54F34BF6ED8F7F4CC9B96612336983A1C80CCE444B3AE212F5793883745F94E508DF9FC84162CBFE51720E4E3A650119AD8FA4EE3DB4766B5A840FA71D1A538C931C26835D951B356B8EE4F64CCE057D3F070A7A8D8A9BA9D835D2B65B7883B20B0F9D97DBE57ED4B5AB9C8DA285827526C9E2E8FEDFF57C30839B9A3F159BAF4CFEF89A347904D7D8A68833918B418990C4AE7612AED77C37E9AE3976A25C6658EDB0F4A3BCC94E1855703311F7FE9378C5D56A7BB1850D00654E3445634D602D80711FC1125B4BBAE4E5006FB60802FED144734B6E609C5FBE0B03570720ECE588ACF8E8D5633CC89CB34140931802E05BCF9177217E684B82246146A129412AB8207BFE89EEB6A8C57318807BE3C105039354B9D9F37D7D287BE70A1DAA471984FE7C9A3A3FF7DB6E4F88C1DD5601525902F29DCD7EF2CAC078F52CBBEC9C68151B160046CEDDCBA21D0EB5B53A9ABEF030DE750A76ADBD1F510862A3FC22EA93DC98AFA5D56D9A67BE1AB38CD5E2388D129985E417A2E38F4CA66436352A026588A852130102BBB8E2A5B904CE2F4FB7153F8BF1C915967D9ACB59CB6D0703576B17BEE2E2F4077F69311B47AF4039BC952DA4AFA2280A5B537662BE2EA09B28982B54AA978D044B6C6484E496C02F95283033669DABBEC1B44B74B599F46471E3216ED3B0BC1DE37CE1432517BE4DD271BD278E6B41B61D603F8ACE1A4F5486D19615B0CC4F53E6015D84B3787DA25113A82DF4FFF05D42769BBA1E9415BC20DDD7F378A68CC3A5C95C7FACCB966A3AA475CF2FB8F8A0ECFAA58845AFC72F489D365336423674F61B86975BA5E83659B75FC2B0BF8783C8F5AFAE32DEACAB2498E73091266B86199BBE0A74A75E6930FD939D2A640302E48C19ACE8E4321115D74EAE27D39698D313D67BDBD026F20C600181888BDF2FC877950F90F03FD6F313CBA5F668D16F7A395B2448E05CCC082603815F08517EEB7CC3EDE06395C0A327E84DE3D990465E017D46998009635F211EB8FE7604B06CA1C33B4E42CCB8D8877FF168A7593450D7E0E447F27DA0BAF9C6BCCC0C58414FAC3E6FAC2B6C63EA77D52808853928C2DAD8642E3B3568B512E94D53825CDA8D58BB5A53F41A05B89DAEFD8719439DDA2C71DCE72A3FBE3827EE19814ACF49AF115ABD985E288A0122F170F7EC28F20D67556CC1D969403F0E6A74B8BF94ED9BFCF74301853FC25B742BC7A4B9707CE1D52DD351E5F2BCB409973861FD904EE24BBADBFFD4582EA82C595C2A968E13E1ABCBFA6160CEEC8DC8CCB5DFCDE2303F7EAF50F308C1432645C97EB890C569DC5215C3A379315A34550E5B71858FCB4E6757F793AB574590E5A610173716486056436F8E5B0EEDFE1BE6E707FEA6C1DCED0D241EC9EA33FD494E2A397B43103AB08432C3767E4069011AC2C5549DFE683F55F6C5910829AA3D3BBF0C1169221A988BD0B1698AFAF0C9872469B61579DBD658C3CECE3221C08391AE649DF7A3F83D8CCEE99F78EFE2D06A935179B0EA37D2AD3FF470160EB136F7D185DF422E3278A67E952E501216D4196BC96F883A9A53CCF65D62ADE7CDED04F1E9190CAA0C6C5530D1DC297A163AFD9EC88AC8560932B74A7AA4CEE021B5025129BC9D2D0436A4EBCD796F277B8EBB1A0DA3C1B68F200124E3F4145D347B7F89FBBA4057FE58F9472715206016E470B74BC66AEF70702855F22911C9C9E656CEF5A9F2F6BA7E0CEB6538DE705B263F2E4474431040CA5D4840FCCFCF403E85AB2B8A01A4028685E0B0AD97F2F352E85FD56801B53605CB662BCBE4EFAE7477CFF8F5B8044C679981BF79F1ED6CCDEE66B1124F88B9F8C71A1869E124A2E89A55342064E37B8506F232D9D4829C6DF97EF328B90B3DCFF686861F43C4B097A6BC92CB1A2C9033EF9FA9F6DA0FD0EDFD489425F9C7DD9ECBD14CD66AA79FAC0D827EB3E44B8DF8A60B198A5EAF2C72C3316FEA00641571AAC491BBC7C10A12F242C242A0913E9490603D221A90A1CB1244138B17ED5CE26A84D43C5D2B8DB262ECE855038E770C7DD2A806E89969FA9B28B621016BFCAC87DD899A5A407FB407743E06A0FD53F11B5996C975560529B1DDC586A4223E0BE743A64C33FF37FB460476C0D7DCCE10CA1C83AEF3B9E62C757898AD4B5F492D3B9172ED6FDD9D9B63B089299C80087CB4127A2E867ED0F841DB34FADB782BF80D5C3DD607BEEFE62C7F6432F4DE3DA4EFEEFF0682D213AB63CA0E519E575DA5C8F551A76E4793A2BE98CF16056EF280CABA8E7E5FEFF6194A7D6CA4D14339335084BF83DE3C53A0AE95C47BB194D344140459869E675436180A95FCA3F2519E9CE4C216257D99E9671CB63727A39BA20B371FA3F3E1007635280A2655733C22B23E67B9BF23ECC8356F408A5565D9A454EDDE895B285159416194C8EC57609E6EC43F62933E404CCDD6935924DD53C1696A71060598C913BFBC2B299B898F56FD074BD2E454B6C7BA050A800D06C472A7F126BF86FCC05C0C9855960CD026EBB1DC31DA22F7655F8D786EFD8AE2C269473C7343BA0837B59D2A24EEF3BF36EA46E1D8CB7773BF4335C33659499EAEC502486FAAEEAC5498675C3C92B5D80EA50AABE9D264A87499F4052CD20B9B5C34CAE996953C78EA0C0FC61FC4B30297AFC8EF6F6CE1AC840FB036327B1951A8486BEC23061C50F501CEAE70849031F6BF2C178E0A6B36B5267714CDFA4128D4A40487C7E3429DAA0AFC36DEA819A92DBEAB6F1236201AB91B794B40776F0B4B37B0013DB0F4A1DA038283971F9F3BD0D89FF7C5070066329AE7CBFC7A569F369E6573A981F6BBC3D5224767772FCFB30BB39B12D99CFAFA94B7700FC32421D0B1CB6DBC39835DA993A8462F28FAC35B1EA2F079EE2934F64BF7FC6E2795F061378DF4CC8F3BEC045EF3A23FE91CD6025F7C0878D9873A60E227D16E167512F3673C443A3BF58B81DF12E8E6713CAC5F2C30714028370A0F149EF6560EDCB8F9ADBA44F7E47D832ABAA118DFF7426A52B80C707BC37C3097F35E6DAF82FBFD36A7D6629F7A7B792BDCA927AE95F555FC7C2B90804F725A82CF276D3B54EA94CA0254089ECB8557AC404DD67A04F5B3E4BC13F6ADCAD390087015991FA83C4F012760D66F860D30981DC1F1FA13C8FEDCB7E42FA1EB97573E9776CC99E5FF9D8644C01D7693386039AFB3E7FCAB848E8C43ACD809ECB197BC6AE95F810C92466A9805369F0A7CE546CC719B4CB4AA509DAAAC94C87E5609A10E54FC5E3AE49DA393BF1562FFCB9A470F1AB27C3A2205C23E199198A2F4732B9621EF0A8EB6F167AF7C01A50EB4D4EF3B47C96FAA664DE9B92B3BC6DFAD9B2ED11C9077717C1F55ACECE39E4633E43199325F07D66AB01C165883B90DC7D3977EC5D2876C17317DB4234207F159BFB7BB4501503A7D99D39C9BDBBC8A1F597AAACD7208983BFD95D1BD4368066983C17C7AF32707911AA0B8B348A1266002BFACB2186B8A72CD8BE378558B86367789BC9F5682779473C85583F72320C09ABF57809AD76A607674FC3C96C7523D87883C3A2642568827F51BCABA4C75E2E3E003B95AF8FCD671B6BF0464C999B22FFB78D5C8990910A53D2318039554525AA7EBD25FC6D4DD1CB1025DC5BDE5F6901A2BE03B28AEA1530FE9D03F2A6001F1F012E4CDC41205521ADB7C28E394AB90F5C4B426C90E97AC8FFB2052D5EBDB5B1CEF8B0862195745DFF56537683EDCCCAB6B0C850175AB47187610FE430EA891819CC4360E0F5E477C9B3CBB3D6DC94B0D71BE249F3B58D0C2CCCEF94240DF961BCE7671631C02F25CC20EBD24977B8AE9DCDF6049DAD55E0B85FE4E60A759AF9FA1F1E78620BEE793D862739A3F718831BCDA48E9AC44F0709BC99C704F6ACF64A36836B4554904520318E28A48A14868EA49EFA37E20F536838607C10906C6DB4AA89AC85C383FE517682F1D01EA599BF3C71AF5CFCF5FFB53314967851376400BC9794F1858CDE378869299AB1A07DA8C2BA21E21556900323D9ECB64B3F668DA43279485A873564F8AA6154EFA4797B1578374EAED2E7681B70CC105B1CDAFEA6E80B57506E115839597DA6C304BA9882EBF8BF997317F4D6765206B89DD4FA1ED1FB9AADC1BEBEFE771193AC0383FCA05D428D7D95FBB09F6DF3E322BF942820FFC41BC58503C88F51462011F9F640F5F6B470F5B2B5F1F47663F50F08B4F46AF10BE5E37CBB7EE0329EF38CAAE74FFF86F11336ED63444085B0B390C710188029D4D37F7DC859E89CE8FA37FD07958503B1BF3EE9D6E1D55CE5C2FF776A2C0C00CEAD92A8DEC4E9A39704778BB1CFD758F5B64BDDB5CA23545697D8E5A2B97576438A419D9CBC41A84561A30AB07AC254D3D8E8D52E20B80238260D9883EADCC1BF8AAC85287F61D722B0EC5D09570D417E91E49AA1EE614C7864C1AB0209F85BD31015F720559D464D2A7B124F180BE86140DC535F074E56EDFFDB8F9C36DB4602AF6D4DC63F0734DF4F16579ACA5924D57BC1BD635C00D796483041AC6A4374C88CC9081BDF1CDB04CBAB50476B976C452B7F45437E1ACDF9FE49E7CCEDCA6DAA7BD6286253F59D1506FC64517B5D4B938EF7AB613FECECFE34BB59DBB0C7A85A5494F90F3BFEAD4C7AE986229C3A398BBD94CE86EAFA1518184AA07E5976DB164D1911B0574A49A8AE4E4019C33E55ADFA2CD98339866150B05EE802C2E4D9C6D77E651AEC1E7D18680196B376EB223FA9483ED5F7B2A74CB8AFEF9994BCD41FE22F92C31FD331B7A7648F1A0ABAF52680F60D4A0A216C4D83A9A7F2AB5803CB891BE504D94F803783B94B2293962D219B82197EE4DC076EEA025A2747CB875DA428C3DEA72CB59DEF3C969D55E7888824AFD7E7EEEB42D59EC1ABAE7CF0984E0F29BD012C13EBE862F5CA50D619066E7FF00A94BAAC58A8BDA163E60E42E74B6DB84D367118B5CB6A535051B6FD52C394E539D4E2DCE05C8EBAD6E39FE3F38BAD09C4BE398D5DE3D3DF997F21E741BDCD194F5B2EC11E14232FF9FA2922AF70E131CB1CCF80171C16BB447EB041BD6275D9A648346629D69E47A06B954061AFFD49A059A4966E7DB3ADC06318D60D29EF36AEA37F4B3F7EA41486CF665950F85FD1C11E838A5FFE51C77C6A375FBF0D7E26DB4119810C23895D69DF2140983C3B87D028A49B990EBF7B5A163463370DD5D0EF1D75BB4057B920B2564289CB5CA9DD77F57E863F4324031699C44263BC67813CF0EF37A57DC688180203E4933718777525AEB78F6B86E860062C8949EA6C521237840E4A7183147E8908C040E1028CE16DA40F9779A08BCC26EDA4FADA7559CEDB1E9480FFF32551A8591D9E83226642B9566D79690B0845FACB30BC0BCE909F1708BE8986ECFDC445FFA9ECFE4BB64771EBC844E7658BD03D2D2F3F08946A0E0D868680E010E0A16060E1344C74624F136062E0D9EDD0A87AB0E37458F67FE53A1E9BF2CBF1442A5EC75370F76B555251C6BD82A3A10A8D28C61CACB3EEFA8B724F3AE8678C98CCAEF987DF6EC9551A28BCDF0AA247B1CD90067A30E63524E25B9716DA53779B0C871B5EF58B13349C1D23C68419300646F0139DC31C6C7A05C1E6850BBCA33F0EBFB6741CA3A66B1B93C0CF1EB9780A48FDEF6D6731B2322D8FFC75E500372D1794C84E6A57F18F1AFB37E75020080402E1155E407B268C765279F591A79A7A2B89DDD78FEB409C6A8DD754DEDDF1D34B7B2E940C144A6ACA270B8DDA2F84C6FC0F422FAEC1AB34A0980BA7B70642DB6CF6C1B69BBE78FC476407FE9A7DAB399D61477AD3B88072BE21E0A5ED41468291DF426123DE7EB6FA67E0ABF265E13A670FAD0FDC84916B35AA733487BE94874C38D50094A74A488A41F897748AB83868F027393D993E4F4B33E7E584CE434D998E699CE41160B1A518F9C387A65BDFEAA9A1DF3A76F5C33A97DB579FBC1BD33F72735A51A81BC4223137CBB36AB9AE2B5219ED1714FE2EF43F7A2C6C71D463337CB29DDCDD73791BD661EA28E4AA12A068C1936C2F63A096B149D2C448C364248F5D8FD3058E4A7FAD54DDAB2C6293C0ADE64EDAB6FC051BD569A739C454E9E8924D4360003E3EABD9F7C71D3E36A802EBCCA25F4189EEF798B8B4817FDCD435E7B58E940600D1E56DE17CCFA151F26733E7677D1DD5C730769EE3CC970E63D670C18993E600BF5D3736587E3CA19EF8D12290146DA71142F9EF04DC447464D31545B17EAEA6C9816AB0F2432D176859A7D1DE859639F86176599F3734614D1AD78076B4D0651ADB4FEE2640676981CEE1812FACE8D0F2CFD47694A317423333AD8C41DD0BBACA182C639A07789E7C2028283BFDFD693F688ECB7A5E9929B6FE3B655FCF35A7C329ED0DFFC42D77BC16E508321E78E42A2968C22E730BFC68870338979A0D607034B72A09E6F3002E4EB4DCD73E18F61D5B0E14C2A7C00602570B1C088262A7636FFBC133267C2C8E0430C055609CCE83BD2B68E582FC5700D4F1DA12A64A88EEBE3477E701AD97B9D0AD061067F56540297DB88F0A96F26075D76743358C26FC5435771894F1D26E917239075739FAE1C1C4B76823D100F2E3AFC191D58469FD46EF8E851F4BE7CDAF61E913913EB79AF7C9EE889D2FDD803EEDC54ADB75DEA40FCB6A4ED818A5B19DBDCCB7A0EFEF6B4623B8628C2E4C665DDF40EAD501739D627A7F00EFF0AC947DA46820386DFD0417F5588FAAADE2B49692F989889A23E2AFE5583159DC1165EB7EBA27E0EF3DC682107AD6205CD44BA153304F6C864629B71A1440A372F9106BA6BC8AD28D8030ED9932D539D95E566DE12E0C3B2D4B2C16D32CB67CCC005F0C51110BF9CE48ABF051B547732E27E10374795E1D10DC57A82062BC3F10D4A2DEB90ACC09BFCB11EAE9D74A5408C6FDE53AEE0859AE9CD5730E60E0BA63791EBCACFF7B2EECD37764363A9587E7323ECA0AABE7F201F023FE9AB6248C484283225F3584BB069D0CF8EA998C014CF3F59E8E3CD7EAB95FCFB75963A581979681C5CE0873B14162EED10C719F96607CB5DA66DCC27CB42C8A995E0D5014C400775F3D5C2179AECA4C67BD6BDF4A556487C48792D13EE88C0A55F9D79105E46B0089C599411C22067AA2D5B03651EFF47A866F19BEEFE4FD0CFB4FDCF31C02A115A11248E0D89AAFCFE65335A3443EEB5CAC0A318497E599C698B3E6520A1D68C29B21A16B936FE9443DEC39E5144A88072A4F3D22BCBC02A8AA2D5F554BA1364A36499D929FC28A889C5B863B51A145A14E3CDAC587840D8E44BEE45F836315515DCD33AE9A1C5D5F7669898351B4A5E0A9E7AA54477D7BD63C7F7405A0DDF5858FE6A6D9F9A61DA0088BF9039DEF77250CBBF1C0E0374235AF500F3D1C07F63DA2CFF5A184CEB4CBB15786E8F9ADFCD7422C04ED6F856A0F2C966EB4F583A5C8E12D9046A12A6CDA8EBFCFFF08653AC7E70E882B6F366E8BC637A0E0A0ACAF8C949A2F4FD61ADB5CDAC77A4A65DD19EDA2B19062E656A9A5D4F25AF38CB672CB6545F78E2B483B45543C94658EE5AF1E33555ED6FAB005DE4696D604FC41DC12FC704B52E01B9349AF1510BA5885114AF038FE531A71D0F8C2B0AC99817112E5FE552FACCF76829D04B19ECEEBD8B6F00E0ED7746C9691DBF9C0FB4DFE83E177BC24B7E9CE6236CD5842B9B69BF9974D9074E907E20482654C290ADF66259F2A20589EB1AF381406E8972A1F230E8DEFE78710F27B89937E2DBD599D264FFC510113F4D07A8965A70FB06C51994AB34FEE023428751A3F69F07EDC0D5AE8CEFD00EB8FFDEAA08FBC46EC86DA9A363B706F1102848E23C594F1085ECA89EFCD43E53359CDD9FD125170201CBEE58EB8B5ADEEDB94855D4D3FC7D6F4A20A9BB0343800D1F26A6362C15C7BAEABA17061B5C3CCFFED0440A4F1867DBA5D484A898EC136D97A0B65EE73120C1CB8BE2C7ED3FD2C7483B6DBCDF80C1444964B2FBE2CB5088E720E90AE4B1B12BA8741C99B76EA02BE83EF873A51BF47F0FFCBA06AAE732E245AE20DE414DA1A18AA070744D891AD3BAEDA14D4AAA8A30599F27E83065D18C400C5ABF199A87A9DCC9EFB5DC5D963832E5F1E37F9DA08AC9770D5DF45CAAB3C4501E5458346E402F848A200C8CFD49440B3D086B6EC9F1FD32F49F385584C0D7D2FACB6190F5FCB107EE0C53E4CDEFD6FB72F8CB0B1314F44DE2EB1744713DBB03BCD19A9A28FA402DE1F0227C24907011B266BEF48345A13A9901F45478EFC4C9F1BD2D8BDBA500D237A2F8DDFD5D91E4999E7CDBC155F39A30B796ECBC2FDE73BD8D0BF6B14F13FDD7E9781F4A7332CDDF16C69BE178A43669FD7D3018587A3E5FA9C4DEED65FF1F4AB673497E7E6DFF2E8DAADD25BC49882ECEF52186F491B32B3C354234CDE7C080C246C35CEE84F3818B6FE16EA17F056B99073A7A468F6AC0D76DE37BE11DC1DEF05C0BF53B19ACEAA5B766B893129D8D35B1FF3D5B2B1B662A88503F4684A075D2E22A0C0DD301320280AE68727F93F6B46E7350BDBF752A0B16D6241F76C4D15DDFFD4168C108196DB109CC22FC579ECC82AB5DE5C35FA60EE6620655E9D8EBFE302C8506C9B662053AAC5A2AA1106B6D18675D55F53E82757A30590635E5709DD6F30605E51708E3D0FB36A666ED2FDEF04BF27C2BA25DE24D74DFC2473C4D57C21AC22F3D947AA0A3883E96DE522AF02983F18B1757EFFC76913D2F4AC963B38111157C73B2C25C7E79D1150AEFD9BE72601F376DC1C53E1DE573EE97EF10B5FBE5DA9C028C7B8CA95420CC699A0918C0F1E480C647FB7A97FD5FD71A40F10C16C1834FF550C72314F70648B5BC047637B6A0C4C87DE7CF6B4FAB5F5D1F40BD5A6A09ECDDD4207CC5D8BA8FC40815C3A9956CEF0D1AF38D84D78FDCC8051EF2C61842B5EFC5CF3AED57F954400FB00511E2FCD894E7435696C1994E151B5FF423D973392939F6A0941C191991ED856B8B15357FE2EDD99C5F90C6EF983A4FE390C987E3CD137DB67D34B473014A465EF586569E8EFD1C4B90C1C68FD00C076FD62D21948CD2592776ABC366C9130ED4B35F1D16D4937394FF3EA7526F4E02BE0D0234234701A0A6460EFFF75DE6FCCCBC60BAE7DFD75E85C0FA3010C70B6B979B67E69267CF8EDFFC3F65EE70E3F96FE408210FCC3C66D9B5A28F66E050846233690AD47B6ACE8849F951D96971355791767DEC86E8BA7C222C50F7DC9055FBF3E709DDB52985AAC849FF9A2900AC6BE7F9E26C2F35E64A4D6778B95BFBACF6B82DA742505060EE0217FED8E9694B703F12B342E3A2420D8FA0C4E3472D2359DD4BF0093EAA25D39182FC2A12062D810EA8EED5F660370D41B3364BDA1C34C335EF68B86B2D97FA261D3325AB9B07CD111E0E1D3448E52E6361B2D0A9A6C6EAF2DDF11FAF75CC6D2A08E89BD89AA7692C46960F62EDB4FE3F4B417FDB32492E32BABA47F6C0CDAC92A8BAC36CB8B990A858F0CBFBC0382B9F3483C290CCD7BD8076D6BAC3EBD1C4D790C333C821EA24917C290F599BB086870372233080A0402816658531EDDF5D8F0691A7493B041FFD1F3BCFCDA214F796DDDAAEC91D51A1156997EC1D091A3F81B4F3A9A3E16DE49EFDE7AAFF1FC1CDE2DA2AFEB4FAFC2CE91FD354CF2045912DEFE614A444234008FA6A9E63EBF2D39D78152AD6B688B947949D32EBD2ED5CCF316C09003E7F71BB0FE32B9AB6E2BB14C6D6B51E96F4FD7DBC74C25A902DF14EBB7FC451B5BA9BF0E5B58505CD0CF506C112C995108F1F6A0C83B6A50864757D52656C7EDF4F58EE570A7E98CDC7FF8B45F61DD9031AAA2918582C6883C5470EC4744F71B610D445003900C14A881E40F162B0CF64236D4DF23AFA62EC8241F8B3D20B43E68C4AE1D5E9C3ACE02A1033600B911E40764386DE83B87C3C73BC7A23839FB5F51EF26A28CECBFD7BA2947820C49C30862C74BBD4C8B0EBF490622FEFFC7B27F7E4186BF8BF305260667114CB638969F2C9A0A99E7E1938A0EA1135ABBB5A9F8D610BFE9E11C9155FFB4A9C860F9BC0230FAF2867F0D5536926F2B8F581825DB128AF8AB730C88ACC779ED787CB7CAF3C2FC305CD0CF306C119809FB8DBECFB19C0532FC2BBFCF8E170D1870C6521AF65D3FF95713E4E98775438FCD12FC9C40FB8074A474506CC285C9AA2C2529BFF402A5090C7E1E6C17C816BB5D2F4D805589ABAE20FBFDF2E40FEA396182A64362ABF2360F261967CF7785308F212E7870DC0322A0BE1F3A905D7C73053585577549F2314F0A06EB78EA7412DD4B43C13BA29EA0ECE9360E12AA4B8AB5E891BF870069F59BF433D54952157A96BB1164EC90E622B3C810E92F98E2598609C81FF0E963E33E1997E80B5F18750AF1246955CB67DED16896D07B1390BFB59C7D216F428B83A92F4D6A056DD5CFDF4411B234CC2E75B6E419C62CD62B999A47D8D1631492F30CF98DCF9E60D02ED0BABF3154635F7B94C30E4E2A047FBB616E1404D457D9DDAC3CC8BB5BE8D5EB8C693BD36B7856466516ADA9CE7909FE9BB2334EF8E456A62E765A43A5C3C1D8E566ACA3830AFA4DE0B690FF8F5B58BCA5AF4E81504A889C1401E34B02188042D1ED17EBBACB21CE0C94DEDDD9FC4F443C89C74011C085A1A46060699A6D0004FF106A925769F8E7B601158989B3F50DAF7BC1CC719F054A20F88106FB92161BB3BB6E412FBB9F145BEA8A2F0E3140674A2B77C10D05D416EA7927A22BE574C2EEC63F9694343EFAE84A6430BF691AA0B9C934985DF429918B3DE5A76FF54FFCC989FFDF4CD5727DF95154E2F0594A3F2DE69EA09BC553D9AF5471F91BBB7B154D1D656D758B73B34AFD5CE3DD911EA68653FEE08982E2E95F7F3D04C7AFA7D907FCCAC18530F5671936B1A9A5C25F33FB46BCB1C97AB20124E851D96CE6D5E62D83C902653E1349C864CEBAEBBBD0BAF9DB3432B261DED397AD9082BB3C43B2D7D82F0E77FF16128A8C4686D660A4A089B3CA7A5CAAC30873DCD4AD6E392E762CCF7FE8185DFFB66E0875F120FA327EFED8D8C932B02AC33CC46A7076A367BBEED9E011F9AF6699A20D1A5F8D47C65BEF6755E0CD0F16013A3311EC85CF0203324284605BFB533FE10EA0C1E40AC5F6376F97A4F7605EBCA5177018226A38B520FC574DEB0090EA61ED0AFAFB77148826F97C535C5DAF56F90608A05496143AEC90CE84DE687AE5DB6DF56BD1C9CAC42EA218CB69F4B09AFE83E98619F260661ADF52ED6B14D5A8EC7A53E19B6718EAB37E9E5DEEEC863BF2550D99D2F2AAA839E02237AA313DC2E2E2DFCAE072EB45AFADCF11BCBF9265F8975A39D9A85F8A1F59D70F5276E868ABF4F36A0EFFF80EF1E9BF1EE5923F89348BF71A1EB5ADDD00F8857078E3EE10225FABBD11DB11CBEAECD0AAED3FE8423CBE137FC8F5A631F081A1D7A121CFD0CB7D4473237744C16AB886FDCD164024EFE366C6A05A60768A5249750C023CAA5FB6894FC7B701B5B06E686BF24673069001894320A53D581AD6CF5B5D79657DE2810F56490214EBFD8AA1A7B5BB8B1858F0697C015C10BC4A582255AB91E2B5316683083EEB76C20AF21CDF123AC94B1C401E9C11C458190203DBCF4A595A1DCFE5AEF2ADB107FF439850D8A85C3831139ADCA588E2F8BAC2418038D2BFB68184534D3F5EBCC45ADBDBBC7A15BC8EA8947AF6B1095DA39A8ED2996E78993CBE3FCEEAB20C0B6B543B34B1C4B386CA8D48E95F2849AFC41E15B1516F59A990A030D63BBD1A3B4A7A10744DEC8C85A13060EB9F5E3FBCBA1948AC1146645138AF2B8C30B4B62FE7F367AB3DDABAE982D22500E387F18A87472DE213ED82EFDD96DEA2149DDB84D0C7EEC345E94DB23B801DCEFCD1AC8AEDFA86E370240E8932D39355E60F9DDF188498E24FAA3C297417ED5D07A6EC913746C59878FDE14A75754618C85D44B69FF07FE90034524A91F00AE840BD67649BC21FB4119E9C1F3F471D6B53FFD0C2460ABDDFD48AA74336584F83642659678203F98CCA4E52DA1FBB5166DE9398E8CC55184A8EF18E2D9804841A37EEAA5B0B448DADAC55ED7914608CF24F6C44FEBA22292FBD848BF84C3C1FC051469196A3210147758886A1D8F307644879BE392F8ABF9DD9BB542616462D5571EAD8D68B2FF8A382FFD10E5FE150CA4BF88CED8256BF55BF5CB86F4E1BC787BC9C98152F14A93587CE5C300CB541021A883A11DA73178D92446D1EB9FAE53C378AA130E04F3C822FD10649411D5167E62178515B80F496A81DAB024950E489E92F58FC1C00236FD95DDB37CBD89AE24CC84A574E5817480F8DBE2CED811DF11CD1A1F989546746C099A643095E078A67B1489EF96367B6FC332331EAE7FEFF948CF0995E8967E6FE2E49A69E1DB571BC1CD8155F23DB85216D2D244244F867A43D27DC66CBB22DCAD9AD2FF4D4AA99108121488F5A41231677EFC207871D66E4B072B291DB9C6B5C4357AC58466A43DC0A1B6C7C6EBC1822767723B6E2AA80997086231F85AAEB9D3E452E32CD8595938D8AA4AFD8FAFB814012378F9AFFE1D023DC5DA41E50734E5F6D9109DC1FB5C807570CC1743DCDEECAD70ECB325C3E745307A9EABF79BBE74209D52B667C948EB4A216EEFD08E55E904737568448CF5782B46491DBE6B3B56BC46896615F6474033B0215DA3F314A2FF3878B0E4ADDDA18759BF7459668FD28D40A9F0F765996C1967447A03FD33AC0400C1C5C1875DD6EEC28FF48D3EC9F53EBACD3EE85351797DB3F84D86F39CCF19BA873C8505450C34E999100FCB6C25F72C60162D6BE48E96A088464AC3523FD519D45B2F449F820276D760ABC85CD6649760C569BC2D8775EE6E20C73FC52ED43286071827737E0A6FC83282B1CEFE1B256F584868FF15A1B0866DD9ABAE5672AD61B18220289D7734300F5F9F6149285425D08B8415AD845C551B8B5CE8043D8F9BAFC59383AB3BEE503ECD1B94891EC023423F30F6018352037D866D8FD9627AA2D52B9239CB37AB816815CCBA9D9F68F520DE426864E75B306FF9FF2B6804543E8D4ECA24A8A60AB5ED857F97472E1AC3CC8B767F54505CE307A7969DBD0210FDEF76F2959E4618CA7F67309B11197DF398B87ADDF36BEA5C6F7358639070EF7813873E1ABD3D37FD7735BE107EDA55C808CE7DCEA9203F5C4614A0FE658B50E75EE8C65247A00272D149A9558C4143C00DE9B8A9811C61B6656544A610A35FBD1EDA1BF12C53905F901CD6AC5A3FA3FFA3DEE1EA037115A439015E13CEFA5292C419E1B4D149731F86EF69C78C60818306471AFE2E4EB7DF4744258CE8B21B02BDDBDBC7915FAE3488650FF6CB7D590042894B23A3EFDFBE1B999323AC0CA9205D98B145A8E35C58B39DE4BBE0C9F3A3FEA46B64E665F0FB221F433B26E24F850695475CB68BD3A2D032F9877E32F1DA1CA06E31ABB4A84654A37C56A5A8C9A37CE5818A81BE900063EE31B3962E3A6EA3C2C113E35FBBB23E22AC5F60F73BB51ED03AD5BF8FD219856F0F5ABBA19C9BB3CEDB779588F20FF23330DAFEEA1C2B0BC2A94B041B6A9B8FBC07E82917E8F4C4158B5716D63E7FFFCC19ECBFD1FE4C42225278B9E842DD05C4CB0D9D5042ABDC70587A785E0ADD4BE8D7AC1BB1B04C3B83B541CE2494011865F882BB3FB03275226C43387B0F08C3017411ED68D30F98CF0031C09976BD60D1E4C395A1C3E177027B205C46F688BEE8B6F89B378A4F878CCC2E19DC1DAF00127E15969B7593E0D1E6C8B6FCC6494E961779D01F90A1F885D5F72DF605CF860D021A077A6B0115F1E1D3D4C456E26FAD733B64AC4416EE8E13DC3F73C830533B667901146DB1FFEB1DEE14BD02C5B27D8EE6BE6EC01DCB668938DECD2D69AC5F255FEBB2250074B4AB366F96EC8AFB7B35449D66CA1DDED7B32AEC29BE08C97A71C3892B30810C721CF5D8EB316E69C418433F4A7FC8C5570BF1F78B202B66E34EB89FE4EE63B8C34D9BFF125D76432555D5B8D95E0D2DF1BAADC53B59E311BF9F8424BC84012ED01CD0447BA52801CF8DDC624A3BDC3B3FFC1460B6A1E92C1A451B75B50D8438F2D0CA446E4889313A3DD3450C9A665C83FFE7333959BA3F00F5789E29B2C8E1526E0D36899D7C2732EA3A7EE98B705E220F02C2A46318F6579868763E40DF1DBD68D5DFF572D189D56BC4AF2DD40FAB82B0CF87EF02AC1428AC5FDF68226F8D846EF5FD0937E46F8F1B7C3EF20E1E1C9411D07008DBBC3C4A7096F0FD8A118C3E94C59D4619ECAC654D8678411EC3B820F44DC7DBD7D4C6EC753E44EBFFB1309F9AFE962E9C5FBF49CA1E255DFC934BAC51B6F7BFEEBAA053B0A5CE2FF175D57D338E7BD19299110B348C41DE9818753DB101A9A49D46CE3B0843E51974FA05AD77086A4D51C7F745B510E42914FB24529208D2FFDE98F62D396D01EA02A7181B52BBCBC2B6D1DDB4EFD3E96F05077E30CA752B7B1D3D1EEDDC61C2EDB95114817275C3DC402AAA93B61A67B2024AD2E31ADD5A328E5B0059D175E85F9B1B35BC124E90E7A86AC07ED8721FFF59F9B5197E3A6A809DDA9821892728528F91CEB93F427B6BE7B24684F9F467443F68BB91E44BBE1CA35909BF32BD6B5B622AD4EB564CB116148A4622F60C9012A19404611C55F8092A5C5C191D63C57A04B5A0DA90AC6AE018A941A9F023222D78723F78064D1DD1D47A59088AA1B445F31627BDA233C2BAA239D46EB5B2AFC88600ACCDF5DD9925F955BBD791358CC645AF331D174D09FDF79F31B2B6B35D28F5A9E643FF8D6F9DD6B2B3833C8E8C11FDE81C30CE0F9DCA17885A5F1A22BCDF2C09E8B55EFB59C8DF0CD65DCCFAE6A9D6B85E90DEA865905A7AE6F4EFC114E5C4150FE9F8D6E2B5BD9C284CD8156CD1167D29F955F8949DCFB6DE72CF52C372F78668C00145618E2E3C50FC494261B74A2FF0F92EEFAEDF825479ABF6B29C56D2770C919417C23528E098FFAF143146ADC52C677D85BFE698A70E33EA5C9C0B922FBC990A7B5EBB072EB07693B77B529E8D292DB9DCD79952130C052D961C7BF1BF3FC8EA29553D0432B1DE130D32BA0D371C7D8FD38E25860B4092875B103D19D41EF1C074BB45E33D716A295C5B61F13ED9BDCBF7D9E5E9F484187C8E5BF5AD8F5C1F0C1216DE5BF00B973F8D38D877947B577288534D437B9C1C85D6EAE7D4E69CAB64C1A9C6559B3C0483C1A2B0B774F457D3C7306B28C1DB4231332E215C979CF8540D6F7972994FB992550D05F725AC7F9A6D4F6E14860FCFDED876DAEFD4D16E088F85C96CA6B7AF98E562298A96E073039E7AA8E32039D2D0563CD5E3AFA3A537E2DE8CBA6C6E2583112CC04D826F2C8EA96F56D1F8F8EC44ECD11557C5641114240856B7C10567FFA15AC99AFF706184D947C06CF696A747CE56E0C9DF34DCFE11D0EEE661210CBD646A6D3FCA002BA518696BD2033374C2D4A643986C200832C33FBD681E64162B79F4FD3D89414190EFA0F0DE2AF79359E894DD2D6C3B500D99B39DB766B628E06C71D31A4D949C730AC967C35304024218A6A72A5BCA39DEE156D92DC1D466279D4C99F647B950D070D8750DB9154EAA10476C343D0DD411B511A8AE5F2CAF34E815904C0739C0CD0733416B8AFB317F1BEA12C2489635DAA1E729EEC9327C1E3B97879980EA3B1300C661920652A3FA634633ADE5560807CABC32EE221C69760C3C602864BCA349AA9EF13AF02FDE7BB0DE7B072B25140A62589C4A57B56352E018AFB36FE9C849240991CAF91691F119A9D596DFE48E7D78A7DD12AC414A3169D8416B9E15C7CD3AFDB1EE471E9AC350F6AD10190DDD0F39570266BACC3FBDE1755645E46A0DDA8F305C393CEE24B173DAB7AEE7F0258156866FD1F192D9697F97984F25121B172A1BB75F76A8B3561C22DEB887E736FD508480FAB02A0BC5E244A6C031AA38B732E8FA8508325AC6B587DFBCEAF1F0BCD9A680F118D9D8200270E81928DEC05CA49ED474367A0E48B29DCA7A2FD9E506002E0D014CCC61AF571ECF56307B9DFAA06C0D6FF5BF4BCDBCFE2FD2D2BF99DDBBE5A91D3E6D3B5AB9D476EE785D5E787EF1D6273802F94B26BC718432E9995109C603119FFBB0C9FAAE44845D45F4F5E134EA7AE600E11C4075039A4CFF4A3E561AF8C0C965A406C0A4D7396320D2C033B5149EDF084A4D0E3427D7299DC7DB9D848C929B115DA6C605B2E337F434DCD87B4E73D4EFC359C45C171423E9EA47ED9A8227428F4FC8AF5F2290AAD0B0953722EBFF0219BE3B2A70520302E387F2231B7F3E96A2D45F1D280B20DCF0D8D7B23FCA15BFB37F9D0F9379FC750FFAA0F7E286C9F6F07770051C461C12413F98852FACFFB0038CF1AC06569E1FB6FB1E9F6C2AB7A8A3F35C29C3ACC92A77E49D3FC6AED0D421FFA671C1AEFA662A18254E1F6C4415DF2BFF6519AF4E2BBD164FDB1EA1E2174A1828960C71FC1B4C8279600799BAF8D1E40ECDB41340E8FD3883E13443146C15A0054912E0F03FE86DE4A0713FF63E3BDAF30C1775DADA2736553467C1C8B9FB708E986DF01418140201008F49A41C5763746CDD17C60BAB32A98D0394F2724E4172FBA15A02CEEC1F1AE1B7DF4438BF9D075A3E070F52F5466953C1BC6E5AB9302B8B28F8BE5B0A52CA64BB54D18E47FF169612DDD2DD7E2C07413ACE2BB9348A4211DCE301D4EA7F611B05417353BC31ED8137AD706463705932180FE78C1EBA4E6C94544D5D2010A74449D11F4F04052077A7881E06940AC618FF5287D42ED67900CE41549B863F5C9ED97071038E2B9DFA2D8E0A2CE4C4F3484019C046B358415E8B12FBF9F11420882AA71977DB6E9D9780A5D1FEABF2B4C5BCD033EDFE4CD7F982FA9E8F0E9E3BB3EB27CB1FE73897C0523A753734B6AFE9F9BF11865B614545F53112E90817C34697CC7A3B58DFEA63BF713F1D2ED6A4B5AC556AF6D210CF8FB52C5B33000CE996C8D7CD2537322179E978D1E48290FA5F9BBBAFE64CDBD0004C11139617EE81E74CFCE18284ED731AF194AFC2252AA091833B76B27BF97C67CB4E1E92085156C7AEACF608388F266CC7CDB138BFA7A9DE17D13C7F9538A6F701C4A1B74DA85F86E317B6B140B46FFE382908087391876DE4E208673E1F5C86C96B3AACCD78AED140F0C46117B170C555EDE45D5B030A44E8AC2A48ACB4D55D8A62ED0BC8426C6E7BF382E1486C2806F23738987FC4A9C45D19C68F7FE6EE1C8D8ED23AEB10D7FCFA56F4D8D634F8A009F12FAA491BA1BA643CCCBE100EECBB48E116F4CC203D14F53C9BEC8B75A8D821EF49829F56215CA6BA41BA596C64B7899CBC47A4B8371330BCF64D43C1BF0224F2686E76B71086F3847EC1FC9EC11AD6EE5327770102495CBC2F7ACEBC7CA65FF729C6ED3593F5B82BEB6CB037D5D9FDAFD1BCE912DEC1983D722C2D5646D6F18CAD3B3FA98D98C73CD5A9C606755343CF3D749F8BE8388C9244455232082786C23804A887AEF73A1ADEE06515867C6E1E0024B6F999CDBF0B59981ECCBB559C21652F34AD5A6A0213E3903F73369D87F2026D2168A3E7C6942EE7E10BD43D460E06E030392DFCD37F1DCCD9CE6D7DCFB2EF701D75FC64A934496BC28F3A6154326DA47D913B04F687B1CC5A118B6A114188892DD600A0ADA01275766E0AF289012D22CDF271CD9AC26119E527DD52287E5C60006E2A6F84EA3676B1335DBBCAB8EEB3B294A115FC6EDD9EE7F86E47C6D86F65EC406A81421EBBFE329FF23FF508137DD286DDB7DFC21D1B87CF683239BDB5C69546E33011A01D56D05B5953C35BD067DF748700C70CB28A1B573CB0D0AEE048E01A878F13774C2F583879F793B5234F513D75F477E2F2F3C4C3DCF4A87F26473FE6A4F02FC9CB277A6032B03347BD2882EAD2783D086D61507F69AFD6474108DD1232DB2469E8E80246F3C143041FA111BD0B4499FDB845263BF688806C60A11D42704E5E0FCF2DBE9BB777CDE6FD4C7B0BE53EDBA4F2C2CD9E77CBD100404DDC121625AB012688CF3CB28DF44455C5CBABB682C76D8F24473DEFE860B7F8347F7789BB0A11A9783418DED871E9F0B2979F867E8EA92AECF0331114E238DEDCF6E4D02A77BE81BECB1BF29AB243FE8641A4B23C47D90E079C012567F0D5691A4FD8C1D1A91A045AF10765D87AB0FB171840142A6E3D73788C33BBE927694B51DF2EE7DDE1A26D576F8BB7AB77B9E4A518FA9001CC368EF6BA4AF53C5E2D4F1849A1BBD9CC268AE289360D687DE31CA7933E96057E793F9B25A4A79EA044D525CB422B29793306E238601832B437CCF840A3914E596040CB22C61F6A882363F969B50B5B131D7C02412218032D742692011337334F7C8AD9980AEC65A22BFC7F2DF1C2B8F5FD928030E5DBDDD90F6A29DACED39A064D3B9553A81CEB4372119F6BF022F2CC2FAEDC32E4E0E457F9FE3089B5AEF24A5AD8637AB7E86107606D8A9020A331A3A47DEA36B51F4A2C7975333A3F2FE0903F2A475B32371A7393402A357EF1FCCA7423F25856744C1DC1F2E45C224596594142FD73A27CFBF303298F957F42AFE90AAB9DF0F2BD7146DE703054719A65CFCC23E4E224703EF83C6AFF943B8241C3B0822780E5299318A3038AC044D2240E11001B6476201AACC66FE53C59FD8442A94A44BC9FAC8A0075BBDFFC89CEF381ACB1DD3BC4F2E34E429B31A4FF1495EC7952C9E33CB1F35117E07F9A2F5529B7632A25324E311D650B1BA58DF46797DA152599C670162C8F40985BFF9A9BE5E6F2B5EC818C873B00D8101B6ECC91752714D9F1AEE7DC1708E0D36AC8C01188C4C0759ED75763386384C6E4087F25B4E12773F72CCE0C80C920EF37625F59703FE641DA93DE54DDC57B76E29100804028132ECC5F4D58C3A1CECD07B46FBB6186CA3E59A6442E2639B386A39E3E26E9F1691A6C31015BD7355C6A539AD359D747D62E06AF647577DFBED1764822231176476CC537B42073FBC70D077098C778181082044AC4A7AE2E7253D46E0107C5EA2475E18BDB661C209A2DACF8E3D459B48D3F26EB0AF684C5F463D7B9155747421D1B42F140604D61B3442D965A05B2E4D9F111EC66D5173386865146E526510B1B8FBCE633B0304A1265498848603FB2E090F0709FC99FF1D8B0EAA1B031B58087BCBFE17D75EAEBD856999706A5FE79122D0616E630003FE3668BBD77A16B646228347135B73E125BF9DE5F9870155E2132698AAC5180B0071237E66973C7956DC6425719CD85ACE06667DE42BFED713A5E4C949D9760E0F59AC84CF437944422ABFE8FAF7B4301ABE40331460B5AEE9E67DB11E3025C2A6A8428D65FF5B514D0C52E62726E498E6A335A562C3EE06BCE9516FB1487E6ED6C617B132DEDFA6A5091871A07A01A49D98BF5F611B656EE3E1AF6E6826BC6C6E79DD88633AFDD12618A73DCD4433BAA18C76BB4059268BB4DD8813928A2D24350937886AACF123B5CA43DD04E5B2F97B12C9DF51828CDA37341F22BD879EB24CFDE1A67C652480812F491843DD9B69F0C9B1E8FA0CC4BBDD6E5EE17A628323BEED9E9AB8186B5D08804A2C7481A40C21060BA65416920D79C8D9A279822BE726487466AB27D0F2101D5630D75D9EC1AC5968F7F1D12042097B46C658523371E70FCD2918BF8D538B9A46C65589F1896D65080CD498CD22D98A3D9F4CC741667A8A9C4CD8DC72D9F4B6EDD00F90D132567F7F1A01EE3F370279C13770418BA458DA97DDD3FA2DFE4BE3CCE4F3D29A35DB786C048CDD60EC7B7202D54C140CBC1443D4AD86E55F1D74624001E4ACA131AA5EE91147D766ACBC8BBB87C280DF717E7C42BE455F6B6B5F9A298A08790ADDA971C58392DE9F29EABB75A4A32E0162E6C1995BC5628C017A4874BD882A4447E2D8CABA794D7E50AC4902CA6D374683A8E924B1930EC13323D78C829699E0F0FAAA0D4F78928A294077619A802C1B7E3444A511F05F444D6D6C4704FBFD8F391EBC68D8A54A32C42C0B0588B15F750593CE4DB6322E7F9887FB03D95F6D1ED73E707EB4AA8E8B72AEBA798DE365080C3CF47A806868B50E570B703AE167247F5FA978E21F1EE779BC52762C169505F6025F52613C176CCA3015C8ED172B9537797CC5CF2DB53626F5BEA2AA79B077E6CE7623405E7621969A341F41EE6EADB41D168C35EE20C132923D98657C436400080309A924045201B12A5080072C22D6DA6918E2D04B24B40BB5BBE2A782B509A78DA1EF8E8B7808644176FD8D9A40C5FD1B739D218F42DEC9560473F41BBE1187600D24152A070BFAF5EFB0819234F5C3FDCC4BD26D0C249427410AB3061A8881047B49E38835A385FC7182624C0452652F62DB3C908536D5F33AFAC6669DE49EBB58E14AD873CD021700ED7DD6C14A60D58BD737CFE2DC7AD44EF89407718C5431EDF380E768C8402380FC660C2CB3D96077981C60553285A5092C0CE30655E6F12C5C59230622CAD667EB548180DBF394BE35380D4336D6B36B8221E0F98E29154CF2011FA2348435DEBC52CACF7051F9A782C25DB3CF8DC0C5C2891FA605B65E34670F63776815CD1E4C7AF6CB434D6C00BAEC1A5A9A72B7C1570DFD499593DFB7E477FFDD91074E95FAF68E28887FF590F8AF1A000D79F289286FC6CAC43F91CD7719C52592D182CF22C8A38D39CE74F6C9DA73163F53E3C0C47CE921F0B84FD4BF7311F6265AE2C1E7969ABAA87E8DBA47F510922BB2B0DED20E56CF9648B58F0A15BA8EAFF506A4DD36E7B549221A09BE248FCFB67233D76B18E5BF30B9773EDB39DD9A58D73475C3D3A549273C807EDA8B80992B20106969D634BF62882D58919740B10E794544A6D2DF392C8378C0BF12103C58DA0FAB9222981D542AAF7C6494B89CC3246BD619B90F7D47E78FE02BCEEEA57F1BCF957B7E642CDB7413D400B5628C000AF688DA1E01AE5A61E8AEB988AAE8572E26EDB10FF39BEDCFA93A1C3C121EE867304704CED70D5E27C0B285C9D588D9E38F42AFDBBAE06BF3FF962E154C9F707EC15CE8797C8322D683F491BFBFB8D0FF4787F5E894E18D0FACC28CDA34232A14470755064E3BDE8060595F97D41A132410D7879703921B99078D370E8426290E1D81CA9B16EE5592E4385B36E87EE7F526391218836790F2553EA8CF7C3336D5CD6ED6057456023CA60FD260E93A8BE39AA610E435F9D0F03BD97B5AF6621DF8289CC513C936411B301F259B3350368849E288CB3FFE55B7B3545299807C5CE72112561D910E6D7E9E34D3EDBFADDB6D983A19570520EFF3914E4D1253713C893091E2B53238DEC37DF99E29AEFDC94C97B915E5B90181CA8696E76C545E4C913C4F236697400B829D6624FE818266831D5E728AEA784C82A7B5EEBF04A02929977E39F88DDFB59A6C5865A4A2A8CE76E3EF0D1D41AB78D0BAE053E37F57FCE1DF4432B6343A34BF25F1DAAC97088BD774F626B8928DFE00BA071BC92FA3CF1D01F1292AC36937BAEDBF9B859BA779CB923F3B4D3993A47696FBE4185C0412B88A5527D8FD5B7DAC57254206538A4835EF9E3B176E24C400D1E2DAD215D173FA3FA214B2271FD73703B70E9BE7E21A57F2ECE8D584B8A23000CF2FF436E79B69B758BD531D33730CB9D593F62FCB91BB9D5CB90013AE35C6354A2084F90D0267F90875435D45CF3482645F46207C4B5EE0EF923CD39FC811F75711B1D4710B3CC59C39949968FE6C964D244C556FE81E1E5F7144ABF1C66E5AC632B1B32F832040C46913E05CFFBB7367560E07053D1E72C9DA2E15331C52D4BA2FCF2895FBD799D1EB0E99BEA1155EBD1574F712E91A425E7ECA2DBF0E9A5666B8806C356E18A527D78E3F3581C371E2102E3651F5A3352443DC7C681D2D692917036140ED235BA15E2F30BFE22C4E9E6DDEA56534F6478AF23D02301017B0514FB54502641678CEEBFF411C7B1729FF213BA75416E39DA678FFA9FC44F0C8BC1DD7EEDB0FFCE77536BDE3BAF3C8F460953FA4F36F6BDB507A080CAC101BF57DF5A8FE142D87E0FF5A7EDB1C6A2232FC6BCE05654C7F64F45393090E40110AB25A9F9022FC66E295DB9FF8CAE88031B41C48299976125E9E73B5A120F2F4C6CCA1738BEE9FFB9744CB77F4A339ECC5284B5B46F56A8BADF93685A43758C466ABB73F32D29047002E458C61AD14DFCB31FCECF4CA8D263EE57E93854FE46C340CDF374C972C4573DEEFA93142B849E142E6F225E25FFCA817725A354DF75605553A976D3364D297989013A2367E7A632E23570ABB3E5BC2D621988820A5FD1E2F52D530E8C852B77908B0DE1D8B6FFE0AE50A2969A1CF38ED7DD6DC9AA4C4AC893A157DC0DFF35412D0EB86F1FB2FA79AD158724D7B2492A4E01FA7575F23B264A28517E2D45182AB2D10611030FE5319DE3F95D983B7CB39B155580A7325703408ACAD0B86828685C0C3C18010C070DA59855FDC69E75FB9E84E3B2F765B3BEDE2C68715BC4BB8CF3A3AED32B931E4B4CBBE1C5AF02EC7E6DB18BC2B5CF731D224573A1356BF5770C1865FA768FDEACC9FDC95E5E8F2DBAA85079D62ED91E1AB2AE3D1805C2C644421C259B2A2117B87C441930E919206D95F8347B52924501EF9B29EF96C46F8A70C8293E5B24187CA55885AE1B9735D05741B5E7AC31792C477ACBD3BB541ED8B570C40EA3DEBEE97EB60F156808877A9CA0F262E268081D871DDB3BC21FBE500040281F00A1F5C75AFD04573CDAE440B43AE54CFF7A1298FA34977C3F7939BB5F8F44F0C5486097898A96FFCEE1F6FE5CF27D5D51F1AC6B7A809827CC5EA516B0F014744A3D3C65ED4BB776BFC974D61D3F70E55957890C4720158E11FEF54228A39CD2C534D7AA31E442387A1036EDF9B4B2A6338A4C9561924FA12629D426930AFA60B2C5D20BF3789A0B278CC8F1FA9F32A878F09B17E5337D037FAD79D95F54DF89C037129A9007FAE63C9FB8D435548B102AD31548BA1978A95235304C8F7CF81E322EDB7201ACE07D6807E06AB84A7A40EF5C4D12DAA0D17E0A51910C5F50CA5907F714ECE8E8309DCD4C465065B8AB4E131A61F25824A4F66E03C415F086ED2F1DAB14E5988AC0B6207371E6773C8925A01ECE7F6B4706BA02EBAFFEF4BF3F628D2717C78D57C8BF1962A5B9CE08EC94FC4E7E665BD363348F99BF8A05115E5FCFE0C01A9BFC96A52B4B8E3220ED3DBF0B15D1A1ED0924421AE788F95E59D0AD90B7B366D3F9CC3E766B77D3CD851A9F100CDF27DF86F0B49FDFEEF16C8D98AA6DC2A3F32C58DECFFB477DF8098BC4F02022B0D2C0F7972EF367883908FF90C2382C75CACB4B74DF6E18D62D81018787175003F66195A0FC24D30E62AC75AF2BD8635A356DB116A994C8FFF53F1660370C9D2F71079A69DA5DCC142BA62F68B96FED52434C7FEFD13CEB8254C6C942EDD105CE7D164DEECDC2092844E868675850C3A8520FE2510AB08C234089527D48E1283BDD3C3A4F89D6F6BDB2C506D11253977DB7B3EDC117F86E17747FD157094D1C61E25461DD8B4D12D918B4977F89B66343456D70D5F49F9F77125D76A19FCCC5C60FA2A5E990F4D77563980CEAEF534592A1F859471C8C5F0376DBD1F3F1D71FC60A2AF16F28B1C89C5871C43AD899BA08C1560F4435993B628EB5F31C953F05A535E920D4F26AB2280E6EC56C538D606D12293CBC7595097499176C3B46A5EA6BF8254BCF6DB50ABE7B41F7A9C620AA2C7265CEA8BC08FCEBFB9E111F71C6F5F8C367CED83CFB7AA1BE2809EB4C497CA809B9F940E9CE508F7BD4F006EAFD610723CD0302CB368F3CB895360CF67DBA5F239F3DEC65883F1BBF8C5EB3979822610F4531D5D42D7E1B046FC3252909212BB3714CA6DB36F2B7A13D853BCE52916575B5B4824FD45434E7FEEB1F6719890B0A00A5BB203F69F019390C443391B9754D6338EFBE4CE88EB4737BEDC29BE8B0DBE829C25E2B1B78067C0C610809671BB5F7CD1769584C862DFA9C47D9DDB97DF3CFCF728AAED4EA71296F554B52BE4802EF63EA3CC184F3474997206ED5F7714B4C03614E301B2F86CA90B3B6B98C9B958FC6DDF7097301036A630C09F0C0EEB2EB1EA7DF91F494C1F35495B1121185C4778E082382731B5CA9EA906C8C788362D719AE7CFA90CFBE6B41EBB7FF0E26A4C76B01AAFB9BB2AB273FDB5EE06FB80A0402010184D388ED66CA9E4DBE190040833B4F2B75182FBB99C02B013AA24E338727A1FA024BB64A54A2F9A4178760892CFD9FE3EFDA413F0AD3707600B70FD7160B8F5EB3D96C044EE45CF82CE7798BA7560C85C2225DFB15EC50E4229E7910242D3D500974FDFCBAE106FEB8E641F1FFEA973AB3C2FBEB5D778D9AD9130F6D78E69F92398A93A1C74B849866D0637DA10F98FA36E1BBB2891D21D70CB1C690790B6EF82F2456FAF6286FCE80F23ABC6F60507962CBFC1577D2957A55F1298C9AFCAD11B4F2C003C733F5850D4FCF0416ADFA0D52D1C1F93DF829AC50B3889FEA03649008D052CE0D5309D0B390AFE6A21EC57D63F1283343A83A85FF70412D509AB24DD72D7A7A0489B62A1C2CB1CD5C34D7D6AE45E32709C0998F957E1EBC84C1C7D178148B3B5B41B7710D2927F8B2C49A1BD4360E07CFD8BAA78EDB6037A711D3319184D4386CD5E305D477931F783D9AB63D7CB1708B0EBFC978BC857E27C406AC159BA976B86CEB4F95F95112F01ED8D01562E3BB21B6C4E2293F8EA2B5E49B66B81313DCF40780C49C0DACEE3A9A242A7C70F295EDE48609C0E2B2FF26892001A1720ECA130E0AD984DBEE7708FD079E95BC9BFFB370C1F629C052A49F1BF17A77F35FD70467E033A72592BA7B325CD2D7ADB8F1DF6E8AA284DEF841F1E7311E5AD54B2BA9D6F2CF253E28AEFEFE2932FEC2DF5B46B6742A3F31B97905B2755DD07CA5B1319B7E420BC8AB617A1324A312B773E9FF16FA5BD50CF2D7259EE01A811644C0FF8D2EF0ADE0FF17822F814134231A2A88F9196691CCE3476D0CE6EDDF02CE05B05D3326C2728A9DB33304AC9D57FB7E34C4D30533274D40EC887CBCA251FC8C92E5B8C479DF1C4A0B17501B2759268180A03E85E2E62B025EC45F48617A4ED8C5317FDAC8FB4566F7F2D496D2C55EF3B29BD01810DB28B91FEBCBB0E56766E8806FC0256A09FF8B5A076D8C07A0626EBE7BE96A34AA0C59A1025047D058FE49AF17E6758A9E42A6E2CE4EEA7F9E909A81BEAAF0584861EDD9EB55FE9FE97CDA8FFEEA1285999BDE18ECA7E83C89AFDD8A809C0336CA5A9BE9B99562A7E4B3DB1BDF812D7B772BC21C1CE701078101A18028192C7225E860A13898B1F7FF22874C815EE6E564E366632632A19E76D12EA12C05B26CC8B57C0767FF544AB5B657DB34CE8CB0FEF1747C4C3E6D9413695A7386528A87EF2658E0766A9D0EFD09E75D81D23685FE08EDD64B500EBEAD75F25710994F29D7C89C41028100C080C0522054181F17541C3804921C820302C1C68F53AD6F0C1218A990F68F9AB66D6FC6D70BB885A5147082840161276C8FE95F1D25125BA9290B6AEA8C64E4A3F1992065723586C96B01FF42B1A411E05EDADEE72475E4BF520A6114166A78E862130B02C907AB5E06C92E3BBF924B363AC4521FEF31AFF98B1DB360E3B6AAFA8F4FC0B6028F6C7AAFEAE2116F52B266C07EE3D97F319351D16D14742FD21F600CB555C276E789AE759A0B351563719A0747AB6C0B0A6142EC069F92AEFF55654114998FF87BF6A6333F40327E1BCCBF34DF0D10A05407D3D63778741410158F3BCDEE0FF963FF75E3A7745581873A2214D6A99595E035125981537CFF9ACFB15C69F08702DFA5E81C087B8C298DC9D12EEF0A9C28EE1AF952D5A988C83F3B05746D6A4D00DAB587C1A368136CBA81EBDDD5839938A338CFCD9E104ACA6D112DF46DFEA8958D723D81BEEE8E53F481AC4C50A419791B958D4A514571FD2A5D1EF97A85130077553D2DD0FDB7701BA52CB187B7A4F686F1D2D58BFDA43AD15B9E39C928C6BFEC64F89E02E5B2F5043F09685C5D86EA6DD49C51EBA3E4234A1C1D20BDEFE849935C14F6F86CB0ECFAB345C990A90EE488C4F0E75FAB09358238E2F3884D1B021660C3C1D127D4BBCDD52D862C869E59325962176165F0718FB0EFE772C3389F3957C6AFEA9B32320DF705F3C5778DF97FE291635E0569F7A782E62F34488CA46C122EFEBFCCA931089189C9BC1F77DDBBDC34BE5AD422A730D962403E3CF573881303625C06E296425F5ACC0E0380303A00B14D68E0E422EB2CE92981AECAE14B86259AD8E22BFA30511CF7C324CD1B91AC16C9535FD71A67F201BE132CB6C14436040A392648B842517CFADBC754930BBCF2DEBBD01C7991C257BFD7FFD4F8411462C20D8B86BF1EFDE57BE2050B6602331D38B40242FE68C4242061ADC375717DF309C3291B436A2F1B8F0DAC29C0EC693814CFC1027FA42A4E0047ED0FE2BD7DD4610CBAE0D646FA7A1DC26D4056D1FF8AFDEFDA79C4F579AFB4FC64F243AD6453DC2C0983DBF4673C3BB7203C83E5B70D27C9B125FF87049BFF8C616A2306F5EB0F24D5F680BB613DCF719B3DE0D552C0A819CAF81BFA140F49B3E797BB734070F0FCC220EB212E5554754EBE63E0D2C85C74A0397442C6E50207C15CBD884E6C1367C4132BC2D73003C610F45D6F0ADB4CB0BF41F9EB25FE715DF00C1C04915DD1E4DF3912B6743BACFE3D7C1B2D40CE2FCA42E73384DDEAFE870A8B998B3D16BCA0647E0CFAE92B4948A7A4671BA2187D5D44CDA3DB8C4DC294FE6C9A7C8B9CB9E3FFE8C73ECE2E882B6CB2D0DCB304CEA147669F277795C301308C12BCA7C75029F17EA82B66F865DD8E08EDCFFCCFF2F5471A91FF8C03C778C759EF7E0CC183B1DA2140847088A8FA27F62511233756362072A885B265E86C200392A7D3889CF0058084E3FD53C469E3969C7EA3EE97FDCE4CE3D2B5ED73B8C4F80B0428660EF7BD350FF4211BBBD41BBAD5DC71D58B2E49395972F42706F4A4EAC1BEC7896A699A7192D0AAE2EEFA919C9A3BBD4524A21406FA55473F1989CF056CB2DCD3609142E1240C8D7262A66F87249E1517DC1BF4402DCAB4CB258FC3E645B1C468D07C970ECEA6CEB30F12D470EE367001114BFDB2F4B21809BC29542EE72A9768CDAB62965462B57885BF9571BE52F6412E3E62C220A06D4DD508B20281008040281DABA357B8D3754DB8101ED84CB0D4217962C544515CE2FCECAEBAD0885391D9BE4A5065C1A32E282909496982068E467979A4475E1FA9D681BFB25C8287E286FE1013A8CF3AA1C2AAF699377AEC9C318F3F3398E0AA3E9DB8AE592CFB76E5000B87C78E79A37A1AA464454AA3AF7CB9EF9B9531E05623EC56DABE995456DD82831AB35BB60A9D3F70012296FB8A6BFEF1331CF2F504EDEEFC68F6DFBA153B86F63259B5C737F3A2F4C386409A8137D25E1A6E0436028B30BD5B5E1752EC840A1AAD0722739916829647653D8F70FD30C0D79AA171130880543841B6CF862B87551DED2F6218C21709973A09671C016E53D4F6C0293AE01BE103D61143EC060187677A5F5416ED995E8DCACF0FE0D56795750B7D3067D03F5FBBD37EDB7FE0C5A5A3BD174D98800DB4865888B8BBE8C8E6E6E46969EC1F2E37D74B325BE05D97C76A2F1F89EAFA41A04D07B2A8002EDF4ECA386B67CB169D3D9AA22D0F46305F1BF56EDBA709CC6B0C07B45784037D4D7C755EE964292DC3D46C2AA9A2B3F6A30175C6687D3D34AB6FAD55A646D46F34CFA122AA557EF5DA0D51642789B0AC09E9C9C16EDAF613A966A313C85114A539FB8E172C467E59774251020F69B239279B87BB496DEF5AE4EE0B8F3FADAACAA5C089533379BFBBB0B3F5BE00DD551AA5B3CFE71E1BE20F8AE9AB495575E6CD3E0F78D6194124194E45C403567587CB236A206A231C1EB26BAFA6E1EFF19E044060EAC82910C482714207F5252113616D0B5205EACCDD0E7783ED323404F05AB3426659A19B04B211AE05DF9A12AEDCF208F649CD995D78595B82DAFCCD1CE2819AE306ECC98597EA60A555300A64A8972A43E5BEE358ED55DA5DD22624D57F7013AE63438AAE76D1691C9A414BCECEC2CFEBCD8F68FF13762466A080C40CCE98BB74DAE2939C7578F89B6A561486EE87C6A3F5184D2040E9B0C99F4B701E181418A562891FDC773059AC4FEE828EEE406122584919BB46FA6F79A6B359DDD48BBE7E5DC482BD09067A405B1CDC51FB1D975F0A0BE6478853462C3921DA5427F2A57931BCE6B45EBBC4D86752359635C085F8302D04518D41637A84402F48A320973500FF968C002FEC0AD230D8430327E0105B5EFA3EB654868FA85964993741B257D4517E4C9944A5A01D21F1F4ABA8F48440F65916D481A04D29BA063804C762021249133943961A0E73402E640AE1A79410188243C0773242D8C0C0195C6204F42994E6457425F2340DEC8D23E90320EB48D244C8632EA1EA9041B59114656C636A3E6101820582B3ADDB81945DF6A33F14BB06FD41F3F9E023591C3675028D1BE319B2A110228AEE88962F57887F78F7AB1232BCD278C08D717C5533E45479A1F974ABDCBD8DD982D0F46C8E91B381D0540F013163E44032F7172D0BA72CC98951E529EA33128D30C4B5FBEFEF49751D646B82FA6CD5F47E32DB55076751289A7810355806842B9EAF98CFEDFF254CB51EB9CFB0839E2E416DAFF8C6C8CFFEFF59C7D3455E4D753ADF881B7053812B9A6FF56C97B3A5D6D8482FC418F93E2660FA47F475E480B7C51F4E426196EBC826D04472A3EB3156051A9AD0129FD9CF419FFCCF4287851F39D1AABC7394C83E48F7B1E8D0D56426A3F8A277C5A91A81FDC331299D50F6B26BAE61E77AE8FABC4A15243A596C5AC9C772356FF1D546B0C4455A2E0CB0B80D3EC87A16946EE3A4439B679380AEB041715E505051FC54AC7DB92EE73847F5105F83E107C0A08DE1B042F0B827B03017087438B3F6F855B2B7FF5E8742D5C7E0C05913FE1755C0525952A8E6407D7200F852D7C640A14E8FB17E62AF8721F70A89274D3FD694DB1B631C11AE34390A4B700C2AA7702090047CF24C07A884CD6CE120B26DD1FE7503291E62AA93D7BE3AC460E48DFACB215E41A8D27EF7BF205138127B7AD11066A590576274F821CA4DC0619A8AAC0882F03CA0A491A345AFAAE1427056E349E64389C83EE07F19C5069065BBE413DAFC34A810FB2488CD422F247DCE3AB9C844C81B02D83D3051AB40D8DA7B6326056CDE814B272721505050F477ADE6D7C9F78D31A49DB0397C4ABB2F79915CED7D0D169E5AB714074EBAF311106ED4EEE52EA740D9FFB0345C5C75DAC84F115DF251D69A8168D8A708BA422E6AF2F38BB10420BB0C46A458BF541F4DA1C47B35FA8F7958D8082C1208B2EB3EB8F96B5A06A0C676B8A3BDDCA2F20E0E6C5C976106D4EAC5C47ABE566E7C4850E2B1BF2D3D07CC4E42BFD83FE0FB1C48D8CA444B9336664DAA2200CB0D1989EA06652BEC2D152BD5E882D1CD7304CFB23084D47A696949C754D91B209286CAFF04BEA2757F122FC7474A34F3CFE413D4696F29E814F2C69350AF430E79304BA8A1E50E7BF5310750C3122A1A40F1804A2278D567A4703239D3822956C930918E203EC9452C97CBF404606352EC84BDF2CB2F2DA497F26109185A872820F49429F2B07B960155E6FBE8FC77E6DB5DA405BEFA5059849AC3B4970353EEFC779DC6AE3603668646079F2ED2A3D820D4B1E9710A00941F4101DC78667D4CDD92232E6CC18DA65AC3041DF8FD3D913B2AEDEE30F84B62704C5C22252E3938A83BAA40FAD2DDA00B5413C33A87F7807DEBFFCACD5F10A92C1948601E332E455B36C7D36E357C756A3190FA1BDC7AE61FC3F6C3B3E18505BAAFEF7A0F5C6CBCB16F8EF809D951B49189981C309434CFF134A6E0051209D355219EF28C507C818D1E309D77A549652561D4032A4BB01E846ACB33A18C610C8B662182A8E46A2748B4A3B0B4F3AFCC1C344400905D754FF0E25AE2A492E79730A0DB38B04B0FD2621D92890FAB637F7A97D6AF67417F77F961AA485DEC73B287B49F3EFE73BAD02050452E2471C92BACD5F06D6819D2C95777881CAF8EFBE8D1C40456A6A54E92EFB78BBB7C46C03A58D37BDD60718B70210DB2B92E52B662B66F60BA259BAEE78BE6F88F7E449970D78D309CCC13F7E19B6218723A8BDEC60E308035639C2E7674EE74DC4958E4834AF8F8813E5D52A4A483BB548B34E83B958BC1700A81B27AF43ECA9AC4720F0F75A432D26CE3C708EB429FA03E350986E8F465CBFCBB33A26E1328BE23AFB4AC57C9051B866AF6D456FB8FC5D851933715DD834C1C26B322C4A04BF1B73080C8C556BC067B6D195DAC3325C8AC80C8F04F1FD7024B58E26CDE8A92DA3F1F3B601CC45F81D98C7EEF0B8CD8A3B7E540E50AFB529C7AB9793C06845F37C69C73088EBF205413F7946422A83A31A887AAAA371335E8F2B7432F38BFF630900AAB98CDB79DD2939FFE2A07C9EF6703CD851FF1A134C0505FE3DB24927AB72CFD215DD85DC61F9F94B71D7B8A214795DB2C3F615CF80D79742C40D3802B4C5542764450FB80D1DD4FEF627F8F90F9323186BB7F0D4FFDDD01B4807B72D0A6EECD857838883AE19FAEF14322460E9DF6AEE6DFB03F46ED9B2028116C23D9A54D204ABADEC5EC18549F4473DF9E05F1D3D4D16CB4012A6FA7F662AC48668E46B908A672E4188CA3B56499D2F1372FB4DE13E4C5D2CD18D306B49F6E5FBFFF1F82733A935F59FD35C5DFCF3314C732E3B37600BB729D61110B9EF6EB01E133C2790D875A019E917C93625FA563EFE7EC0FE86282B179A32DFD168EA898CCAC963201AF8B178B72C5CF2A999805C2A20191C3293CD846BE9F26FB97A573F9E03A897DD079C73956069579DB86DEBE63C9B0F22747AEA0D764FEC0F630765DEDA5BF8CF76202745CC23AF74D99F4C19CC6F14AAC1BF4C02C9DDDFAF93EFDA99545EF51D93394C2DF565C96F6B916D34FDE80A8DF93B54D782652920A5138FA8F043D6D863BFF36E2EC5DB973F9C658A30D19130833768CA6E81251201D3B208C71CC127CE49B3EAAF61DF9437406F0A345D3356BF99E57331FF3243DD9E49660753A21EBA38E2584D430CD8AD5F5618AC6AF99855591E9FC2AECF3776919A89099009A173DA0AE112A65CC1D9FE12191BB0CAC6A7EFA7FA9985DD3020880D6DC60964531657E58D741818B290531BD4C1DF89BBCD7E118F258B09305A611D35177EF3641C196DB8DF3630B14B8F5F725DAAB2966C54642D9564AD55C71E8794F96560DF9CB5241F6A7DC9543B42A78612F1CC66DDEEA593C83F2946ACB2C1F45CA716FFB6AC780C4BAB01A282A832697984A63E64A6F387097707493C6F26E9D4CD269077D5DC8446F479FBE4656FC8CECD624CA4C92A608C84300025D5F0B166B3A34AE864C431A97EB92AFF9148EB4C59EC72D36B1CB0C5A7680288561AD9897F249B63A5A34AFD921446C7973637AF4B962F64D9F53E2FD9611B86C0BE34E472066E0626039E910C8569F3B8B899649D2980F94888EF7D3B99AA74FEBF2B881DCBE938B5CB9D8EBA5A386B0F02CC54640CE7C67A93DD7129A55C381B1B2740FA03A2DC0165324D5726FB5FB12DBB21DB7BD8F3D68AE5FB32290BF837F2C5297F404191573E9A30F881AA7DED7FE7E4DBF0CD9F77BF78122CEA8E930B1C7FF46F745D0D3FFF000C654E904117590AED61298F4F9598F31E4DAA62A6E726DCDD96A19840E4736AF0EB29503368DE371D5BE5F3E88CF54586D25018901E23BA932F8CA2E6AFD4B169AF761C34F08E1D65FCCF0CFC3B82FC8F2D1B3600880EE53BB3C33DBE965DFE4FAADC2A2F62CF3E710D99FF75387FE572EBC6D9538D74B07E3A586B01945109AD1764A31C53005E7691CE4630DE5DD48BE2813174A1C2DBE0C717FBE07C03D0269E7EEAC6BF9286023D81886393A428FF775E806BB91D41EC767AF45E5655D2C75D611192B33BF005DB5B8CA66793376C09E66F37D2500858614C97F80CA35E41CD442DF2060DD8B4622856D6BDF2BF76431F6862A1A86906CAAD75596146CAD4EFDEFC8E07D81546DB4CF87F344923F6C21CB0BC44DE116C144F125DC6E56C5981400B816ECDDA051A36B97252F0ED0515AB07A7D2C1D692CBC4C8079A923F1CD73A0DDF41CF312D063723C6EC272F13200B122F74A04E6066031010D9FE118464DCA5AC9708DAC6CA43EDF310C074ADC11A3C82353884D5FEC45E08BBB5045568B019C27E0C5E64700E2183A8180203331F427F50B0AFE404E849D50BD21B78BA0FE752BC434C2B1A3B9BE67E0FC02B021AF714A914DBEFCAE61B08DFE0621E4DF6D7FDF9375A387B4E56953784D8A024E87E9371803F8C6A9F83F5C9B2F7937EFFAECD667109E55D33F7F628BD8E37E37F395C2026178466BC06B954E312B3992AB5E7B7F69485013C2CDEEBF4A7C5FD130F3B74A73FD4363AFE37748F1FD8C72E3375C2FDB74FD507CFA25B36F94336FC2F0C1D8A1E9F581457CD6454028A0671DB363E1E3F6A3CB726424DCD7FD2AD995563CEDAE75F64961A1F538C6F52E40639328BBE7CA5DC9C0FB3E70FC4BE99DAB9FB29A7A9CC888630E05FD03CA7CEE9DE814DB8223199490BFEEC075ED7B5C81C47F9FBF786533D9E4400D321F630B01543C56E167A16297DD1E363071B5E5EB16573DA83F86D946DE403ECDDA1C19530B232BEF8DC363B78D160C89E9DD4706A87AE474B68992989DBF88788300EBB4D3FBD55466F0DF0FBFAF9E61A8D2C4063B4F1C4D1BBD85FB93763C3D7315B10E62E9B6569570566579EBABC3C67FF16EA3DB57D133042369026FF6B15B5A3886FC0B9F779BA5621E66F03663D0D5FA83CF3D10CACEC4ABCC3F67240303DE3E88324050D0B739307BE214F304C57F4C737B7A7808F948D1A93897624944002A42C10DE668D834771895905A223F7430F90850EA61496403ED0C2465563B65D20A6D5ECB6025F14D458D80AF9042395CE02687837667724B28B89B5BB4B67A1A48C2BEEB6E5E007819333CF0956866B998117C6F979EC867B197AC03639C091B0EFF5F4ECF8E753EF030D32F853C7D55E3B0429919CF3CF7FF349E46E1832A4437F4987F63B26BCE2500C02356AC634C9BFF478149DAA4AB05986723DBDAA4440586B078C5DDF8E4087B4687C4840D2CFC0CDD4A409EE43E1A23962D887A2F8AB7FBC4CC07274AF7CE1521E79EE96C34D0AC39FA98AC26C7F608D22BC62A4ECA1D3335B814C8C6F15655E182021BBDB12A886C44904771D3E178E6708622336D9EC23BE320FBD25F4E01AC8912DE00D987FBF476FC6B54BB8BB5DC80DEFEB4D75A937F9F793FBBA1CD3191DF7AEE51BBFA5D215FE07F720B94961E13829C01D36F57B776D974C8CB024F669473A20D46C8F35F6A7CD4BE9D55BB558CD59376E0097C8AE24650137A35B0EA2AD8F821880B7A5F95CA22F895D7E99033E21F75451DF709DCE279228B2F0A4AF2AE7DD290D808D1F51148073EB80F1D1736851185AFA1FA31CE2B9C1178F6FD0CC210237D6E942415F6193FD3AF27C8C413275F24B6E9F68B67FC8FF43AD28F44EBA102110D31B1AF36685374ECBE59287901322B465CAA17B8CCD06A8ED3AFFCCBA3B95576A27D2B5DD7B30779C980E6359BFEAF0F9DFF6C0A1AF9C0E8FF63CC91B1F054C59E4578B50EC2E91FBDE62DD16E5037BE306120F4FBBB905EFF8742F111611F9CC2A4AF3F829D82B54BFEC24774201BEC3B081E64A8F2A736A22750C8C025D1ED7FDCE5DFAF8B30747A245FDA00B18C73E280B98B68C982F859F6A53EF0AAC9CF2D084726178D72DC17EECC76681378DB5A87C6098A1A177167E6ECAA800FBF12580E035F6672F1135C1F75E2B2F522D9387C53E5684AD70C7245FA668F920860014B0E3AA92F90AC718CC6A8135C88946041A31403829FFB23031EF876828DC6DEC5D918DD15DD8CFBE6856931DCE3C884D2E47B31EED1FA2EB636E98FBF0E164B7A2490BAF94F400901EE992949FD535ED2F787052D9B40CE51AFCB6D247EC9BB1F68A1C6C1CDFE2884DAB280BCC40928250DD0C747F351A07908C08AC44412569750B67338E6E1FBB0FF662E70334E3E6E978714B35A03F8601FEC7C0DAF3B3E889ECE8C9E75F2DD3D0C1D9610EE4DAF69B42ABF796C4CA51163407E5B74112F1FEEEFEE0BA8E6FF524ACDF281BD20EC09928D2DD8BB1B78E1E111827011BC4E924335400770AC11CA8C3B4D3D7D8A4C17A7403F2C48DE06EB4FA721D16700A087C09ED26555F326A7D74F09F4788777FB3D0D90A716639FF2EBE7148AF5B701BF2E08223AF0622CAC8FF75C95D4BC12EC0454131EA28BFF0923A2B56A78821D6C5CC1DA799659B921FF62FF132EB4F782B50167C8B1B282B221FE5A34BAA2A89FBA77BB6E23A64639E7B8A8CF61DFF5FF491E057DAC2CE1FF20B0C00D6E6A8F7DFDD81B7E1B4F39F55C5FD80317A5281BDE1BA7563A3471D59D2222D780A0393991FA61E67A27B4360C02C88BF9278EF112961AC19C38363F503997F81A69711E6E32D416884922D0907D0AA28857FABCB9C8119B1457E1A0ABB51E3A5087EBF19A426A719397D60FAC5DE950F82028140A0B4832A9D2FA3B5E1151F79FD803D563C9F743B1FF54C127868FABA8A97DD2B0BAFF1D7CADA3D74EF4E916BEAE5833C01056CD3D4256FEECDAB77B52A360502BC55B8EE8388737764B96AA071DB43EC6F0434B81B92B992820B7392DF40DE33636B4F62B3E7E5EEA2F50D397AC040E54AB2E5C34E353A3642D787C11A41676D8921F0BB6D11E76F5C8AD787F6051940E1F5C3CBAA33D1AC67A1676BC986FD3B935A269B08FF9A6417BDBC87BD0F0B0A0804028140470165BA73AAB13997195294EECF298D92B7F25C2C00B8E1078A06E6FCF111C9D80A3E5D50AC1045689D9D42400330676A73944F18B6DE90B347E9612A0B0E8E02EEC4B8A8EA08F9D7CDAEAB97E3913944D5176A7B4F9B93B28F7E360086583388329EC90C5328FD5779D8727FCDB04F34C99A23D487284FA60DB2910C162AD8FAB37359BCF3FDFEFF59B375B223C62E3240AB6ED0A06C68F45BAFA4C35BA97459D1FFFBBE3193D5FFA77F06054E1D4ECEC4DDF04F39D98085AEE19CF55FCC19975788EEAF5CE30031F9B7E9FAC21138B14A81D28DDDAD6D0997F26E9AB2F6CF245CD7500ED00B8741641F87706EC170431B780717E5CFDE2F1D2AAB43120B07FF43255F772060612B3767CE9E1F8DE0AC963F4A04E3AF0547BF02E218ACA67D09B6D2D5A14B89F8DCBAF9B442837FB874DC00C06DD3A0202ED97C9B8AFA2B453C504D9DEAF37645C0F3288670AF48E4265C349B8F0CEC05FD0C768B48592DB3C73E98602180D7021639841F063DC4E8136890A80916BECB45346D4735839A8AE267305E85F4007401C699CD0FECA91073D42A2F951E0B25506BF9539E7983FBEF7B176A9876DDCD795846C47ECED674FECB4639807239E9DD295EA7F06D8AD47ADC7FD366E66BD7B3BD97C33E2328BDB7BC9D4389EC794E99DE9C2C81FB0E056504C26D62016D48A223DAFF43FB3607888E4F31FEFE100075BFC6F0B7CC05F55733EA3740D099AC4E55531C800DE74FA822341226E8839969EDF2A6B73ECB328983EDC88EBB8BC883982D172E5E9EE954FABCA967A14E1277511842D03A6EDF77719939AF956FC9E54C694B60AF19DBE04B907240F25BAAB0D206CA616FB83BE39009ED924700B5F6885CFBE2267BDA409D05CCA8DEE8B809D0CB4E45E67C4B0B559DC4A24115D8C73506D7ECADF95DFD8BC3A8BC523ABF7790A3ABD8748D963FE07B2D66289F41CAB5DCF7EDFBA1A53ADFCD520A80AB6A759817B0F0D987D3F74C939D45405AE11EF3459049D8514A34ED09B1719A9E1ACC168C1DC3F82470B77C215570CA7292293D0BBB978B88A149DCAFF12FE1EF7989FFCC38E63BE47844C4E9674AFFECA03DB3A77691FF1F0A0316F2CF11C4FB5022869B85ACEA8E7489695C61F80BFA4C3AA188C56FB71898AB00B294A7DFD5914A948A1611A63628743C859CFDFB3C716AB658DE19A20DEA70EFE578233054E785E1867E86618FC04C2ACCF9F94DA2C0FF317B3D11093100FE4A8385728BED2BD8A332A35C1DDEDBAFAC87C93DDFAA41F3971C8179B6D319A0477FFD1198AAB8219031F35188D493F73522B09308155A47D0888226BBE0B1019C7E1263D1AB27EEA00B0E5A101857C76010406078685838080C149CD68B0A25773C55D7D0E9E236C730A7BB9D50879C1E5A3355707A8C2537DDE9B9E33FBBC1AF48ABAD4365F74FBFA2884DBA74B51DF27B05E73ED6902FD56FEAA5DE9CEECCBD0C2E6B75760AAF25CEF193F809CDBEEA985DB3350EE29967D97FEF45A08FAB9AB05ADB2DD79E83E3892E17AE79F7685F3AFDAA08E8E91F61F55D322E2F9EEADA23B3B95CFE0DAC5112CC24532130933FF75148D841A9184AC416B7E063D20B762365D6817EBD95695CB2BCA851180FA2C2B307814020BCC2DB7E4A2C8550781CD60348DA5BEC797E9EE40687CC4BBB7EAE41BF0834C4D358C8EDEFC4BFD668A232090DFD478B38F623C849E1A130074D8FE95DAF065B3C482B72BE09577D4D2D0C21D4ABEA2613752E88FB5D1B35CF91FCFF7632396BF0861E368AB9CCEF3BAFBC611EB9DDC6035553C6626986E1BF0697BFDFBFA1A42CC62E22ECDF906D262FB1C7EA324ED8FF160F479F80ED6FA82EBF0C2329C0D4E39F4CCB4A022C2979FF77995663C50F48BE491C3A0515FE490AF11931178F62C5EAFE849D17B2C464EC0737A19791594BA10BCC76575EF9B45A508F55610D3824EB966ECE2E0F8EB7379E2AE338E1CECFA91F136DDA8102805DD034A6712529B115F9AD6C184CA00A5274FF771313931803ABA1F3FAE3AFA39FB6E1D2212BB370EB60D5A80C9F91DD7B4C62314603F876C340DD2A61EB2677570CFA2AC95C0E905912CABF91ADCC3E1FEDB454DA1B84829B1637C0A8F0F588EB1538E2397119114360A0E6247CF38372D1ED22395EBF68AF289C603D1A3BAE86EE4F540B975AEF8A4206C0F9C4624FAD409FB862399BB59DB0E8FE876282C83D8710D3B598257E6CF2C38D2590ADC3DC77CD865A35635A460E58DF9BEF78F02CED8B5C0AFB986A37C47AE4FA24ADE1046ACCE136ACE338AC7575F7D4A4DC9F412DDE769A96A9CC1EBEF3447700401EFF67A8B2BD474849F23E61842D0DA1DEF7E8E1B1E533424440DBAF16ED80551963200CA076981E820D9B87D0E4097216393C4D30F61937668B7872659FBDEDA0BA9B15025638AE3C1792C5D14AC073BAF9E22DB54D1191843B45C872EBCB20C5E2C3D0BB9E6CC91275A3793E194CC361E97E37304333759198F2F663DDD6FFF43FB1D789A9B316F4128CD266F8FEEB150B7E5FCC2D3BD958CDCB008CA6846CB5C67C32ADD6D0F61307D0337ED307D6D770EA72513DFDF9CACBE1870DEEB5513362833076EB19FD53D4C9202B9CFF243E307E4B284BD142EAA3D3CA06D37A57CC8246465D2C05D678175FB5E7220E01FEEE8617D0A686FFEC475FDFB8C02E66BF39E87577E86C7F8CD0EF1FC30DDE9EC5A5A97BCCF39E02D7E05EE49B80BDF64F40CA6B09D0D8D81A17B23CAD46D1F491F66F3D150515A303F1A9F8AF59158697AA240038D56AEBE16FF5A723F2D47F9F5FDCC2EA43C15877CAC9AE47276F2B5857231660357E31EE7BA7E2F3DCDDFE1527A7666220E646F9E8C3CC95D7C3C61A308FF9EA3862604D3076D5546FBA468F88D38C80D41ED9E4CC10C0D00C101CB9B86A11D75599D164E25C6D556EF9E9A8BCF52ECE8F62B2082B6AF6040539FEEBA0153BD41765AF6A5598CEAD423FE824CC112AFF33285A44F1FACAFD7C7335A0B413BBD50E93E4CD13005B83000C0E00138F7387BD80F446065377F81E7E71AAB44BC7DDFAE5ACFBEE64579A23538B924ABA6666676F37780404050281402010A800FA293782282D0AE192A2261279413C63713775B4E21F4AD83A72A5D8998C5056186DCC605813088A10A401920239827E83A041D0CEF5408F1FCCADADEC6BE564937098C97F9A97EFD6BD8A8CFA031E7E1285C440FDDBAE3318EDD0F36445C14ECB06612110B066CC2CEEE4FCBF9BD84B912221997F3B63A45E8AE8F1056F1C8AB36ED881F003DCD09E67C1FCE7E18039959E1D9242A1E27EF567D6594EE985AB1152498581202122F6C1470A2F430A513BA3D86010F88E0EFD556DB4DF5F80EDFF7ADD6F048DC7FCBD13CB4D3C262ACAB35967B381831E63F2EC405243591BCC74596A0596D18F8EB87E46799C5500EFB77EE0B14BA150EEA4DEAB3806CD9FCCCE5A1F8A938F33893512E5ED8A5CE66EE8D11DC9539DDA866BA8A6776050E344A1C7AB6C0FBA1FB7809C69CB954FC584CBC87D1DFE2E9638C916C3D4C03E56C54B5DE2CBF53522A74F19DB057D7E9927F41DC75B4982C05CFD49523ED4AE8A7278B6BA2FC061EFE2FAB17E9623EAC548C0177DBA75DCF9AD0FCE1CE1E3DA77A7A733F46CF1BB1380B776FEFD6A78A8AABF49402FEEEC9A035C39F43EFEDDDB56227CB1CD2FF2ED6BD8C7F2E4C245CA5CF815B46A906850CA0BA9BCD3DE7755406785B9C132762AB2614DC6E89C3653F180531F35FD7F2D4AE2B423E0E91BD3D2C2215779DB63E3303B22A44127675D3DCD0EA7BDFDFB6B5FB8A6838A9FA714FAA93802D7332A057000E3B160AE0E10F41388F0EF259AA0BF1F0705FAFBE9E08A11AF1AC6787A76BC3A3903A3211AE8394B343FCB15197BC9AEFEDAD023E4E3DB328D203C88DACEE83645DEFE4FB918A04831AE3E27EC282624CBF64F8BF4271EC5D087EF738CA1E3595EF35D08E306835F152805D8B4F16A70076B9ECB849A514A0707B3E33F950F562581A199959C51112F34BFBCB909654F5C4A9F4128D0A077169520A5F06E07E0A1F5A04B091A066D0E4823BAE722CE4CC059752164E960C5216865706C900DB8DA68C52C79A8574B2828EB8CB0716F4E1B17036CE5CB67CB9397A76F36B97D4F71509A8C38B043564C614361C0CB757C174BDED7E2B58CAE9D30AFD5C9DCC9F7F4E94B83B61E5F3182F748830D007B7C2173EAA8397A43FB6B2BB2D499E756F3BE349581838D7A009E3DCF3D725E0414B89B7002040502814020D06B9D03F9B171CA2614D61C657664B694E39A08C59DDBC524AA642A047544FFF57869B093E0706C4A46E35C9E39E6F0BEE4E25F83890080C9E10E954E56A4C37F5CB8241430D6D50EF8D62F177B522D1CCAC076AF6046153699A02C22430FE507EF99B8F211253E03F32B5F87EFF5435FF54C19080956DA4BE8E4945703EBE8EDD9FC05BD0005DC60E41127548964908F42C4DCB7103D357A348B3F8B6323FFDDF2DB766C6A615AB8DB5C0467411ECFB55744F073C5FAF0BC69153CD886B3B398E6EBC5285E82C7C5DDA4A6A62B497D41B0866CB78EDBCFA9BCB7A4BCBB5A1FBC6765D9ED0568FDF10AF23784D2E5B29BF91657D540EFCFCE6A6395ABCEB3B9D2D132F135F6C415B4C842CE63C0664A6BC977ADAF36BB10AB42CA4F28BA47B9FD1D83B59B840040185EF1B76C7FC8E70B57690F565624A9FB7E250A105AF6360C777FF40B5F43AFE9DE75B5876BCE7A2BCFB1A4F616AF1537A2C8DE6213C0F90DFD8CF32B127CA8DC7BDE508575E358D3B00595F348DB6F5ED054FF004DE50F88839484FB855DD005D9417E6197D581BA3581AF2C11C1F6C4B27EC6B288200FEBC6327AC6D20747220AE4F78B7718791A6418FC70E87DE009F161E2AEAF3B465C9CDC52958307730CA08723F842B6F101D0ACA030E872C719902FB54A428E82402FE9FA1A33866B0D83114787ED17AF6B03A785F173A28714236C35C38631559E7247837F4B680FA07F4F30596768833280D9B509CDA6564445BACCCE24A54EF975331E9B6C9336D2754A829E78899726F2DD51F84CAE90A7FC8C8C26F81A905E01165CD325B342DE9F84A4C314FD5EE7B6EB1760F9786D8B4565CE539DE93F066F8801898A3554B9FF1EB5413765EE512EEBDC9C12F8AD7522458D0EC80AE2A3CEE80AF440D8F73382F9DF5DF9A205B65E5B735D7C6797A0DD5CC88D3D7CBB16B6827B243E85372B37D268F18E1A24B8A66576244623289BA933EFA6E4DD30EE545E5FE772D3C656AD26CEE0BE1D1797DA9A3EB9EF7167C848AB056CCFC1B600E91A7C061367FCF0EF0E7CB202C6C8039E15ADD4578FA8CC18F014A89FE9671827F1CFAC3FD640AA18667D3FEDD610197DE5EEEA2572E33F1F9DDCD41E726D02EA0FBDF18141B0BCB5CAE61CF46FD2043FDC1A805EA8A1218AF6070546001F5CB0630779B591CAF55FA725BE1584458E26EB7FE37D20CA2620B84BC3BEB3E28EDAE171597C7592EFDA84F2891C7B7A71B0EF47F7291BE4FA87AE8C2337512C3FF740F0E962725501A14BD6A902BC921B0CFC420EB677B15237E785CE0E3D86FD9007043AE51D4834BC062E06EED31F2303F0877229F1BC9803D455F194E00F0084117A65A83EF46D3A0EE217825C392ED7F019FAEE441605F4B3ACA63FA000769832E5FA6157346B8D417783A37349638D7F730CB09DD19950230BFEC96360BC8F61F0EBFB03C0C34D17EFF9A4FFE737372CB4843819558DC22943E38E7D1DC21D9EBCEE344AC4327239AA47EDAB82CF4491E9C32AAC4CA7067598AAF22271D01A1FFF894294906CA3E8FC01C2EF5BCB74B17D2D499A8D16EDF64F48F2801368D4B20F8C1D3E49A0CC558988E7CDD9812B40F01B5B24C29825E0B54C4E944C95857144464E888F29CCF5E5C5FAC8D180BA837374CBA3C0742EE3A0B12BD7A1A4A307F6D67A26BF5C3CB671E2E35E4B1F60A34BFAB3BB2B41AC95BE8D693C6BBA22E7D851FE7FF7558476256534955ED3D76E580229F6C50CDD0EAA731482D061C8E5BA150461748087C000B44DCA61BBFD3649DB437A374CC8B505F9F74E9F6B3B117A69143464112C2D028081ECA42EC9D4A6EA2BBA0EB6BEDDFC7B265F998FBA667277C481FE908EFB6A36E6F3827E728F847C8F1AD6A1D283BDA18C3F7436911CFE73B129748E2D36839F8585CE63C0F816E0A1B0064E14FF1895757A97198AA027AF09539DCF6D1A2E9319F12AC04B407966F824E79DF80310047027060105491848E3450D1D0F119BA034F600318455F33C558A0616231194FD71C39017E91AB026998191D8417FEFBADF15FD9C6FD62B1849E7435FB811B1C4DCF91963019BF75D71B365D01E01814D11602217CE8DEF03E32095A277E135E07A379998C1495537E266E27F0CFE954E871F31D1345E82C387B40774830FA14883B5230454A7CB151BBEDE4ADD38AC3B434C2DE5EEEF1540627CF79AD917D6775E4FA1BFF09BE9D41BEDE70CC5BAE317968A2D65621F80AEDD28F2B4F6CC008F87CF32CBBFC54D75EAAE7BCA72752EAE3ED257E952D007813B1453BC3288BC33043D97D652BE36E754A77CEA8B2239A68DA622E2B597CC65980CBDF8371BC973693332756B5978E148460820127F859185E5F6B5AF3EE8CA074927FD1FC71C793797C597A47075F4994B2F02B02B4F5D5A3EA08AE0A45925EFA752A5A713093180B306E67492EDA1FA50F5E47ED0F84F5E3DE5585A75E7477B25B62FF05268FA540047DF80C4403D2B2C9B8949B42A94600ED77F776D8B188AE973D146D858E7C203082ECD9720D1D55EB3FC93A9EC3570E915964FE3D75FA0400C9C5BDCDF40E996A3295BA24F6AFF54EC158020AF7CFFC24E85B250B2C64029FF62F2879EFC433B8728ABEF82596207A5530110D4304D01B650C9FDB45A2AA164048D20DF129D324EC200E0375B8CD98FE21FE4D9CCA76297D2E75B15F6A3F761C345DFDD7EFDB3444BBE06E498628374DB3F2F0DBB0FA2507C2519DA2FB527307E2A83399536F224DAC81DBA1134F33E9EF9D0332098F59E745A81932DE550CB2C510AD294D85A621D3FAA2B4314AB5BD936C8DBEB77677E0A4C53A3F2D9CD19251E8CDC6C2B3959DC0541F3FCF9F28E38407ACDA07ADAB4AD42304605C0A83A220071BCB0FEC7167FEC2930108591595CB4B0EC879D284EEC26D372FD416C036F7939831BDD558126F8AF7E3BC512A42857FD13C0AE4A1712DDF9A1388BC1EDF48848080384C3D9CB35972D4E71DAF04DDBCAADB0306676E0E520588B4D199E7DC847AC5780A97D63BFDCBA9C8D90A4B5B6CA085D593AD1CE97926B0A6EABFBE4464A06BB7470B6BC3027FF082717DC509E9A225D41D2F4CE41F1B8360DB0D802E5305AFFD047BF0959A123FE6CDFF6B9032C1631FBD3CBD738D7A734E8A86DCA9CB57C508A09E4AEF69ED5A099733E8BBBC1DEE15257920F18AC92EEAB97A5262D0F792BFF44D75415F42EFEC057FFDA1F243054C9EE7AAC1588212ADE8027860993BBECE4E5CDA7F56E77C8CE148603D65A8109A24A214C81AA97D3F71323D30034DA58BF618F44EFDD265826A1931D5B454EC801519EB3D04F916FFD13D4A4478CDA77E12D4D558F07DC8D51B9D4C8E38EB0F8163CDD8FE8C21A5E588034D14FC79F92EBB2E6A794EE03CBF7809AFF2F1B9657E33F37ED0D7ACFD8BF4BD838F356DC1C699B351803EF7CC1B6DD24F8BF35D981E29C733ACD3541660F06060E2A81CF6BBFEDB78317FB6104FF600C06BB330DE4B76AA8E4BFB9BFF766033A227CD570904E4880B39352CC3B3568CA264B59CE18401CDEA1717CFFFD3600F4BF67A744FEBBB3FFCB4EDC6EF66F00269608C1615117BCC107E199AEFEE051949756851894AA6FA67F5F9952584113702907ED8E0EBD83C263DC76BB34FCBF0B87C6ECC34B1B53AAFCA75AAC77D423D987D844A844B5F186BBDB5BC197C182D024B793DD1D89ECBA5F1D9166073449822FBAED5622939CC698F817FB64C3F10AADD604A5082D72B02680723CACD5AE5071F7A4C014FD96C23A3F338668F8A2A6FB1ECE98CF6618294D86EA9A896CB73BA3D608F2CA170373E5E9FF167757AF8F22636A65E8FD458D2A6C12CEE51EAA5F3BD635FBEDF9CD38470A50DB3F8ED8B9680939E15EB375008B476ED4B1DB93126E4613EB717F4A9F98953B36F137787EB37123C1AEBBCA5FC72F0CB722046429DC8DFC164B89738356AED6B122E00D7FA3ABC4349A2C1504CC9D8EC39A2C982C87E3352F0E11E353C3F18664757F1C5D3BC81DB5A1DAEE9E905D79832B37D477579A99C1587FE65687723268691670ACBED8A38D6628E0FD307A9E96FB3641FE2229BC0E97CBE108983C7EC16ECAAE1A1C78FE3A8FF7AEDEA2FB7F5EF66A038506CFF93031E59083C36EF80119E4018B3A26BED434C900551239C3AE69C6A0568706811BD816AE635DDF143F4FADBD03F1BEFC71C9F0CD4804D5E501786C43A7E2B17942484972DB893F248C1683A73161FB17EB5159A9F58FA4D1578E2F1B2170C3CD64BB683AB34AD8D0C9249DA646F9E31DE127FF8F2C6F38E147CA25D853586C9AE146C6A08C15CF0447D04ADF3CBB005FD24798956BD2DBE7C74FFD04FE456238315AECBEBA8DFE10802B48EE8BA86103DF800697F6109F0057CAE427EC4A4E8B09DECF20FE8C95468AF30A38E2F92354D8470203A85F8566B114D867EBAC6EBD46CB4A6F8471BBC3F355F6B0252515908902A7790107E22ECB00088B50A699D1AD445D394D4025FE5B42B03EF26D2E15B351025C5437F42FA95706D7CA828D94DF160B3BA6CC4FC7CAC32F8EAEB8C67F2A98F79B9A6AE3107373651CD4984F8276E9CA0900A78D994CA7D99BEAC559A71B995EA187D52D3B0EA81E6E7203273842D58935CF36A811287D9D4446D7DACEE45DED04454334A0DF90F9B8F277AFB5C27573E1233C0562871E149566E42EDBEE132FD15615BB09302B575C453924CABD055EAF62074B4B66C254BBC2D3BBC8787FF6B154B7933EF01BF186863C43B9459437A33540BBF47F99AF383F64C3BAA1A027B98E96109377FFA91DD5D3B5CAEE5D9FCA20E4470DCD45B911FD2E03FCE8FC9BB85597919415864E9DADA32D58D5A71125FC762B217243F5F803B14FE79F2E4B9048040DB3FF6F1127C19709592D0C8E32CA6C8010EB67E08EA3B8010F85013F9163539F1168A2C53462E7543E90E50E6BC72564214FD2DF3AAADEA4A8FF18012ECBE1E8BBEDC7D331142FABAF6438438CED563E9748570F22A70D585EA293B9DD50818571CFA674E867706AC4DD4414D2FD755024320F28A3AF9FC67E5951FA9B8E2447BCE7D29D6DD641DDBE102EA7602C0C7D42449AD4D305E0696300D8C34DA9083E1124E8A290D8C5D7CC9DA9F2164959DA74D81F6EFE5B1CA1D4B9A4D52E195392F1EF2D86B2C2D4DDD6DA978EC01734DB352B809E6EF2178E5F15EC8CE87FAE8273BF325FD83674F9C1177BF942B847EF265348BB50931EC51403E198D48C29845606D3E4CFD115AABD7A2FA4FC17FAD788FE0243EF2BB5594D404ADA8835F4B2D48B17E07439F0754EFAF9601860EB103A790A4C866149D5ADEB401411ED1F4FD1E92798607F039791C1C70E4401F1E8F63284780E054D596675F3ED51F199BEE8E61641F87FAF9A7EFE880CA3DF60C3831B61ECAF76DB0F2A12D4EF67532342A47B874E06ECCA015A839F99E781790980755BCCB6630D171F029F9976DF3BDFE0733329E16FDE069CBECFAFF51879126485E123A043D2A1BD178576AB64100C6AEA9CC1AB13ACE9F5CDB2438C305C0556F62D821BBBC2BF700953299FDF1421E967E0666AD20986B04E40C31C368369F7EB94F43280DB918082ED4351BECFF9F9F91C624DC829A53D140610B98C5A882783BE2DD51D216286FC9B271C5A6481EBE892F09F4397F457F2FA01B825F1446B6633DB09D73767F4DF8076B0CC52EFAFE9F26BBA4E346A439750ECBA61F065D80DF027B5441C2DCECCBE4902F63E4451FEDF6B0B03FF1AB05E7ECB6D8DFF7BB50ED535B474FE7D1C1EBABD6029C3A0F2A904B0A37D7C0432ED6B0724113AAC64BC6930A4904C2145864B3ED148BF6D8F31E1C03348089950137614FBA5FB0B9057D360A161E04150100438B06F022862456E193A6BF8242C686C385761FF97AB46BE19FA63FE1D34DCDDAB14FFE4F60AFE5171CAC803C5FC30EDD72A572BF8CF98FEE05F53B4566098BA8C0F9EA5BF84A2DA6DDAC399B1C558B5345DC6A3221C52145F320EC780A377534C5F6DDB3405D97F6D62C2A2CDD353D18792F862B816ACD6E1CCBF9C601158E40E3EAC20EAB86E1A3F245A6724913BD1C0D17D82C7B65CC84F9B4DE61A90DD4AB8DCCDB0E5F115080402E1651ECD57FBB38876400B53A96B987F449FF501231C3DB8780D6A564862232C5E0C0EB393A626E05FA34DB250D5329C99DFD56DED8DCF3268750103A8A3ED7ED5C8616EB42AEF698E50DE6814529AA9EEB2A283DFEC8B97FF51DFE4DAABA419916D22C73D7F3859E36FBFD2468D138860C62B5C8A6B688F8F4A83B2D837774CC9BB8F5E351A4035495FF8B3AC25B5B242F463EA418416DE68A9C040F10F33ECA75FFCC02CF2256076291567A0524C9EDB01F29668243B4A23FFAA4655CDC04F6D5F47C76A76CEDE8DBE0E82028140A0AA160381AFA72285543CE71945E1A4C64B8E42F222DB533EA0C748687D7C75FBBFACF403D55CCE643122E073BB379508877FC5EEF205C1016D8D43930EEECFF67F1EF3361EBA61873DAE2B5C09D8240B4FE81F1F0121D88020908CF1FB39111A08F60977921A4817CADB339433157DF01B2A8626B80E89EE39CD8208BD9A2339BAB5B5A9EC1F8B6480D1E65B5264E3C3EE1BF4B37C6AF7BA0631F2E7A94EDD489F65716ACA3723672987F12F8E84BCCEE6C01719BEF5E505D570BA01289BF2099559B8CE54989D1F9606FEAEE877355FC1151D39A3901C1F01A68EE73A81C105F7B553D3A6381E8870B8CF28D68689A86FEF6BA93D7ED7AA1F24850C7B34D2C3DF904D65CFBF69E12CD9A292576B74F622B2C1A26647DFEE15FD71D4270055F97C2AAB0BBC281D736C527B5392EFD6379DF4995ADFED1150739BD706FEDD42F09F7A56FC88554205CA8B9B6EACD23C746A2E0975F975699D6058A2D8CD3A61B59B8DD1E1A23408D872A54656164435E07FFDFD9F610848B06C2C57E8042BE25299967ED3D8A0E3EEEDCA3679AC2172B2FDFFA5EED026199B100A37F4330A7B24F85045DEE7A0471E03682E7A80E69A8784CE8E48BB7490000323E0C68893CF883FF6471C7C46ECBB212C574E11171787DC96B1BF3593FC3B67A1DBA2907975CA6B166241F21F66E57DF2D7F4C830DE4A5071CEF25E6D8E703498F9DFAC67FE3D5DEADB78AE18FD2B985F17E798A088070862972B621177D26784665203BA171CE1BB4232BBF1536046474152DF1F4481B5A5A599ABB27FF61AC4FCBAC09324B0F7F936F64D04BADDE06E312FF1CD791DFACC084558164E63449CD9D8780ABD80DAD656A06A0FF6DEE798460CBDADD56F9CF24A364B04BE7F0CF2714A5E821123DD2BE812F8758DFC2295D5BE2F731557A6C3ED9268FD5F30DDF273126C50909B288E2B034770B8FF72AA02183CCA93DC3B584EAF6F9A74359635EDFCD7DEC5E76044EE24182BF3D4FD177DCBD4A202E5AF7522224E3AD7B69D89ED8C81B28E40A22C23093D27A13802135F50E20A720CC5129038AF141CE15C57F1AD99C4EE5AB1F346D2BC43E9707138023F10334940B23B7FBC0A41C53AACE49D79C0D71BA0C14EF311D739EDAED4D9123EB3394E9D13B3EFB4971DB16FE7FF81BE65DC1A044C0527E2C2552A5F2F979E61E548E60F3C78B2272EFE7111E58CB9697BE2C17777832D2BFD8D7842439E5C23CA9BC37F9770FC8FF1F39932D06F6EDBD5FF24BA6AC81246D68BFDF5A0124067088BD2FED1B037140674FFCEAB65FBD4E2C8F1F20DB79C33EABE325DFEB83559FE65BF4F73278D24B80D50F3B6FD15DDA6238AEF0B93BE777F55F4A9ECDCB2B1A02548FF0B07DFFDC73A120402815E0BD514F1DAC35F96182C62FB2992F49A81FB4BF9193DFD30FA156222FC3D34275CFEC09DD9705CCE401A26CB0147EE4680BC756683D09C61BA9D371ED056DC234EF50C3979656F724FBB1C26379696248DCE91B0F2316D79AF486E388E80028FE50655D119B52EDE47E94776E5AF8C865C6CBA7EB92193E6EE9120BF4D5C8546FCEDBD3357354BE82F76F729150BC0A6FD0857CB48AB3A8C5DC46D04DB422F27E19DF7034A93E29F2BDAC595145C3A081F1D1E5ED6FE1CD195EBCC50FA96F0FEA5CA67E2EEFF0E33A8F3083E8BB17733665DCE7010048A924A776F3EE45FF8F1CDA7164C18BF51C9B50DDB1CBA065CAF1DF9BE5E1B85AA912BF73CB2FA705800D0EA57A92CC1B6C5E8CD279F7E7437A46BDEADB85D599149544A21EF341CE6D0180ECD335E6BB2C807D99F31B1B4F4A4DE0D19DD1F7F09CE4933B07A21503B72C44611B76129A052AF260B9F03DC99F3FB774967495464C7AB8C89A608BCF5DBF985FBE3258BA87F452ADEA3E67483A9A3C20A265CFE198CF3C8B96678E976652638DBF7547357B94A130105DD90BE6280B3BFF3185419CF64168FF3905FB9E35DAC2C633EAA4A6257D9A30E5DBC9AB4B70D8501F2D61C8FBFABF53E3E8875933ED238300AA6327B75983BE46F7403648FBAB65C01A8EC2BC71C5BD98895B0CC41A90B7234BF4B03811A931184ACF2311F114B2D1FB5BFCA4E2D00B64877341BC30CC144FF50FF559F86F98B123DD8DF9444E2B732B550230A2725A5EFB7C7049EF6314B8A78DE5174896F638031378C248D20A6F3C17B76F2C76EA30569F3C5AC3A593D04221B91DD69064A4BE5FD77AFF8B2C67C659FFFA60D6015B1D4BD47E09309BD64E215DF8D8EA090C9A95117AC3451DC30275DBA0711106D8C9D4BCF26F35D85ED94FDEBB9A99B77F3EE6EF7D15719C5C5F37421A6E0C68AD4F37FA3A0F2BCB07A5F4DF01B69773CD7FF62D56890BAE07907FA8EEA51620B039A1323C450000F177CFDF634251331A5A5871AE6F75CA42BEE97A1ECA935788159846F30246CDEFDE4732CC2973D12BC7007B6398BF8AD153F0F946EC3E58C114D99AB20DD5FBCF07B140F7F04DCD3630C75F3842242072044AA204838081602070F030B46983E43D2B1D124360DED7F995012FB0622FF092571B075B0995012F7D635820925F1E27CEE779AC42F4DBFF12441AA4C9FE174504AC390D3B1EA9BFC4D4A66BEADFEF75EC16C937918AB512D57146DC45FF824C71504A71C94AAD2FE9066B3C51620EF1C2D99052042E4F19E407274225873411884EB2F8256C70BD47F584E6DE64DD3BDD5C17E44E73AAEB246BC2AC81C9EF5A15E85893957D5F18AAC82C8EEC75E2AF744F15294F47BE4498D27B5FF51730A66933850E96515B11A7F99A4EE4291467429824020105EE1A97E297F556F3441D575DAE10A161B017BEC6B4B33D5CCED2DB01A8399C2D05F4811FE49C2E3D32210B98325E46C9B3D2DFEC20A4147A83AFF55E840BC81B884F9D67406EE98F46184C11F0B524E42C551791ABB41F7C11BEB2DFD8DA3BA436A0C593F1200D3D7B5CBF7FA7C503B674F4B236318E4FA5B36569EB2850750F8FF42D843EC0BB6EBAE16348618891BEEC94D73DFCE8AFF26E2A15E5D6B0F8D1BE15AB001EE38C235F419F078C8FE09A515A42EB2AFE3226E34A960F4829E2C2A38C1F37974C1E9D46DA60F063190D02A0739972FD6ECCD900726223C58F97BA9EE8A5CAFA235B446233E1CA1DA22B382BC4FC36737FEC0F3D5D084CCE320F2756483A6EF0EB0241CC8EA466D7F5EEA88C00C55FF56186F97283AC1033D46DAE3C1FB1094ACD10D3D0682028140201068B444331B1F125495A0DC041D2F4808CF74E95FF67827811D74E11A56268DDB7C5114F8F20B5ED2C10EE10E29B9B15B8E013B9EFD2113649D1F0CAE6B8BC79B3B51B2DA8CD4D40B4051EB27E1A3294A2558F819C8388E88A13000E7C067FEEFEDAB13A698C7FE3FD6A3DD161C2AF5F13F9ACEEBC530A1EE5C846E80EE9840E49E43E1FD5E72F977EA61E290B1C42FF5EF68C3C7CB680296E51FB957E075B4D6CCB9D3210072384240D29772F32D7A10EA266B0552256711151F978F6741488C3EC717CA7CFE2245DB4E488BD7C3B9DDE798139251DB66549B06380FC349E318429830874431C1F37F7D9B48B566FB5A2DF7EDB313C7DB8BB95B2C4AF49B734D99550D6892BB8C42772BD1116044FEF2D34FA2B50446BFC0F9DFCFEAD7CA69F6C027449EDADA11EAD3A11E8C763FF74C08BB6A454E12815AE23680861F50FF93E8FF5AB033C298919B5AB6DC896F38BB4EB793D216A550D6314EE9CC2A3053D735C27ADA1C9EC95FB04997E517ACB5180903E05E333180B514D426463B8ED923D3D4756D36DE03EBC4D93C1B2C858D51DF0480DB812D87952570D4980955814F344C7D0B3C3A70E145F6B3D13F87738794F0B91B46025628FC537F86C28A286FB64B8883426B669BED30C62E9F796B8EC3FED3FC31237C7818385FFCF03EB3D8FAF5E9C181D9FFF6206330041A84C20641100894ECF90E79D0B233C9E0B7C5321792CC176FE898AA3EDDF61AD7A2D63F1A86C04000EAED91FB6753A729FCBEFFB4B74DDE0CD1D0CE467C8575112929CACFF4C76740EB66F69713B44EA3F47E23C229D2AF4418EB807E4646C1B8BA97261C0B7F82FD7C42081EF433048B5218BDEB8D9A049E5C0B872E2C8C9FFA260C4A930428DADCA98C915EE24471539576FAB0DDB5670DEF7A0EC355702B7B0B07573B1B5B1B1B804E4024995C76EB9324D97EC2A63910693D8A937CB8F014E639A8293DA61D0A151D692331989DB0031C5AA709442906E2DEEC9809551FA9B2131D31457C3BEF97F184F72B7AA5D8870685B3145A219BCB3F43564DED5D33D67AB372267F791C072D67FBED067E34FB2F2005C530E7B82126F5761CEAB0AF0A5057979CCA91461DB8DCEE10EF1D2231024E0734798ADF62F1DCDA546551CA2F7C514D77A183864D2FD4995B440F547B0E3885AC9C6CED4001583713E5B7C043AC140C7B11A2A33F04F48CCC8FEDCE32D4793009B6A9A4FF11CD8A6990033E74378E7FEBDC8670107507E8276E8BEAD615247E3FD7594591D3DECC81A3DB606A3CBA8E3E93D0A026E3EF0C537DB4605897B4AB8ED8C93F29B0F6781455F88FB3D4FD0DA1087D95D999BD58C8670A3389653C2A83F491C1B6116157E78697C7DF41921CD5DDCDAE52F44CBC258E3B4363ED209374293DCCE21B408C90EBE337BCE85C31F290BB27D4BB63B20A35AA938515A895F25892791373A01B3206920A53B1A3F6BC594852E70EADA2FD743C25A669B9704F1DF86A5DD12D2728E5741FE68AD2ECCB23E97D74D57119D96B089CFF81369A02C48D6A06702692DEA328A0B1DB53B1904642A4E1D31E99E6D56AD5E2B2F32DE9363FF819FA197C1F01A1BE1AD11141C8D228557E098D0F6BBA3E5224B70C201E6D8AC5F1BC7EBCC2A14C92FFC369B5E2B01B59CCFE36B76742A580E2E3B51C18B528EB564F4E6E39CF405DAB498B218EB0AC1473285FF0692FA74343057D7D0E0B4A4AB53E85FAC9F7B6DFC991E756FBFEF105B2B9AFBC0B38DA521652CC475FD1B0217374B4B8147FDE8604FD7F922F0D096A731B954B6B1A7AF624BF8D10305E56598D9ED44768DA4968DE215F1CC0000D0F7FF5376CC763AE390C747C8DE029CD9540975AF1FE1ED2E32CF196BD9A24405096A677AD3093DFD0DB53EE42B38C5D6239F4EFE42168A69575452C0029B61E0B198E69E8BDF3E50C332F311F9A406CCDCDA790633B3E1D62ED9E86107E34CC69B587C1EE2C02C50D4EB3101CD89FFCE4D99D6CBD527004425EFEE2415B2AAAF8AD9A008F1C45EF80D355F4B3D7E7E89C17E040CBD2E725454EE7D7CF7FAE394677C9C91A7A115542CEF6E88A0CD96E009104ABD21C86B1C659D2F1D161882BAB8681EE6D68E6C0F57E7B17AF5742EBBF3D58E53ACEEC6DDAE784BEFFDCFA1D909B2E207B98BAE487609347047559AD0D98FE727B0BB7839F7539475D312129496A6B95C5BD3FBF913CB3FE7197F84C23D98B15AF7314C44E9D7F6616A986631599A46357E98F36C99857DF5F5070473A0C9A62DA00B52E56D3AE068A1CF16565363BBAC3A4A6B84BA0058B1B1942B064E5B6CB0A401050B8A1FEE7BB01F5687F88F058607A482CE2ECC33FB6B47BDCA1DC2DB20FF86EF0CC69719B26C0E076F8D738F056D4D590DE42891D66ADCE7517DE04FCE1AC97C870088D7C1E424C6CD0F7D12FDB7D30ED2E39510CE23E0D4EA1367EDC5F7A924ED79A7690B4C4D501DC384A6FC3FC4D5410632E1EA30E5F292DBCF708CEFF3612B8F6DA5DEAAB7765DD30EAE0F5DF3C75124074E80E85013CAAB7FE1EB09DE7649F8ABB1FDA0B2F168B1723FF19395C57B2099280AF98B980375B1DA27D636FDD85A0496E890439052C0F15A71E75D4F7D52FADB69984E81864050205CC40BBD60CEDAF3E1A53E661579CB9CAFCA20F3FE35F568CEECEC35A79633D17616D289837DC300C1DB6BF0A07A03C4F97FD486851A82BA5085394BDF4C3CE43CD0EB581FFB7115217DD2AF37E53C5158F9A116A86496CB2C8AA4EE60792F263CB818445979B08C6C8A4B3D251186EBE1250B8AC790EDC4D17E1BC78E1B558008EDF85CB093E2353DAF76F7375622BEC2634B8D02BB809A6D1DBAFE55FA77338C0BF65A8F8310BAC0AFA59633AB38A7CD2B10D2574943F4D8A01ADDA5E1625B839798189B4FF1FCAFFD3B444E15DC9C27C63012F24E4001846CE0A925F867A58A98B2E78793CBFF4D97E084C2C6E1B850B63B8D3A5A08C20CD8B702DC68EFFAE02F38A3603C857149B62B0398CFD2E237091C8F3FF8EC5103EAC1B0CED907E24E6566CC05A3AACD2BD642E3730CFE704E2EB21D7CACAC9418CAEB462E9A261085CACF4ECF5F6C59532459EF1E35786BDD94C10002D50BC8D11E8B061560F75630C204FB136B3FF52103EA87073D9A191141B6778DA12C3851829B7A16F8B650C1783B31E8F99EFC9867CCC6708D527F67D4B69A916E9448E08555EEF2B790FA48E459FF4E78FFC8C425CE8F47C1A30C678F4E0F8667719AF8CC7F856E05841B342E7C37F8F3DB03F6FE405C865D949DAF3B0FCF0A0423455F6885E546DC3CEBA75BB58689BC8707F4858967443F2C18EE4E710278D9A9D03D947A81E09E162971F4A26B339EA257BEA8B11A9E21BB5AE9BE211DBFEAA537BF4FF6FBCB8893FA37A0166A7BB35A29B04EA4CC8CE484652BCE9151A29F918EAF1198A67F74F057B324A5F0EF0EC021CB2059B7A48193A0D3DBE5853C91D49894A67E3F8769DDFC1846DCC46CDBCDE445A0DA43E82A3BC43F7A3C2ADE935E5A9AC6BBF3AD5B31F4A2E8D7F67B107880F066EF74739A8B71CD294B290AD1F18D2D5729C257B7A9A9A3EB3A2041B852AA47484AE5F65A08CBBB4AB7310290C68F35E7559A0EA1F3E422D474A7F1BDBC741960DBFA36AE11ABE9A46C10FEDE5A88E375CC5D301277351503049DE454A7AB05F82F21A953A2B84337CF8E57E34E24818C9EE9A1EAD89BCFA9ECAEAA153421BBD2F9D80C66C672B1E7D5CAB39E741E0CF7C5AAF664A06FE03ED62DC20458EEED248D412472CF8CE3EF10B9A887C6C4E8C5DE0627449505C51DF74E93BEF1B345EB832FC17D74E04550FEFFE14CA2B935D94634D81C381BBBDBC02CE62470C4AFA112DF8328BFBA5DA0A8A4A9547FD160FF654041E69FECA838189387269746D597BBC70F82A12899C169B7F3F635ED1254FAF12D0633E69B1358A195D4838CB134E9FBF36F8CAC5DD80792FD326E9D42ECCAEE698F5FDB4154519F066E0A10DD290FC3982C683C8ED2C2F2CBB6A726C972BFEB201446E87DF886B64073B26CEB000CBC9EB8D2FBE4F1602145A62022A704562190DBFEF184B52B78F4D360BEBAFD35EFF9F5DBBFF3C0E50F05ED0CEAB44C072432A0462A93291021E035F7FAEAFB0E26C36AED9FC72FC63F7076A53B0ADA1A8A4F87F065DEAA896AF6655F9B631FA9DC078D21522210C60E8CFFFB5DAC2F1E50FBA8BD62C917DA3CC2007BDD131D4938050F93DCA36F74F4080916F941981FCE88D4627AB14DBC07F195576B99AC9B2A5FB416C0B9FAB45CB71050214AD13D9A623AB30351DE53E323A545A90010F430FBBB60F8FAE0C1F6294796E665314F7F95DC27633D38EBF6FFF7EAF18B54D28A92040D3587CE7854A64E2480B969CFC160324C460F0793335F8A938B5FF7E6CD98E09DE8C4EB0E08FF3937E77D974115F79A353F8BFE86489E73BC13321BAC6EEF22B2FCA8F82BBBBFA83D603E519669409012A099B61A9D51796BC63EDAE8A3BDBD989D16ED5602C128529679E739D6D7B946E682C10140804028140A04068C8936F447973585426E41914055CF48222A1CC7E66B41049A07D2F39D4C7C0F0F1651287FEA67BC3F5BB230CD116F5076FBB7D280CE812116FFDA7837CB39872804B1C8B9B703FD9268EFCB554399258FF09517F57010093A6E3342C127E66FA0F35D47C9D6AE90E1C6F36AF272EB7273F73DE348A090181402010486F54EABCF3FC9C07600E21BB2FC87A44A761F7763F81E5D8EC0775A5887438430FC570469DD529CC80095467949CDFFE87D6FF369600C4D89DE6B3E448E68F8ED52E9C92172FCB3E0172EF1AC4B630A23026F9F661C8CADB0F7F2C1FFED10B7525B6EF17188CA91109D1C024B454BF4815C7E6E2F59C2AB2FA9FF0C49F36CD6F5FAB5F5E70CE0909C4C454001ECF89E18A81090565B1E893C44DBDBB9029BB8FCE3ADECFD43C570D5EC79FC9E0CD6934CF880FD51BB2D697F702522A27A8FA4053D7DEEF488B8F3D97CE8767FAAA8187E5003E38842A4378078702E2F4F822A1E3D4470A03D63F5851E93FA15756617A2B10DEFB1803393235C53B124224047FB09239EDCF03CE59D6E75C3384F04C6C9EBED463E98B5833F5319F8BBD4F8F050DB0BC296DC5DDE0C7163A0216A3887FE9DFF7E99007B60CD74D901B559967F709772E91BEA48A7425E6DFD1DF5F717C1E8EFA84CF60C966DFFE04EC5094DF94AF57D6B9685FB60F959C5FAB8DA3B77D9C2448A48CB075828D5379385DFB568D503B263C5A3B852070099B6DEEDEB4AE03F6CE7A0E491DBC8CEB9AD007FCC6814E37E7B92769A406EE521BCFD71D9F829C3E0FE0CFD8FAB46C2D9C080374F3C199504D62D322741542347FD2846BB5340E8E9C69D9E60284293935DF5CBADEA4000EE8672DF672C121BC9E70C3F3AADABE400C10F2FAF2B4EDB0E570BF0B18681BCE746174D48933481E87470896F9A79CFAC401EA06C4EC4956759A07A7B56D39D1B4D93C6535362127BB8A249B352B01A9E509E6BDF574F425891320AF4554FFF55DA1F9E4B65BEB6F4D24C4006672DEEE7E2D328589ABD24D2C2872B51FD73E30B288A9ABBA303B2D1455F4AB00F735EE9B1D7D1E14FA01ADCB0611D125B2C5F791378D60E126EDCDC8F68A5E14B8654C3F1EE6BC283406B5BD48C66E9EA9DB7C90C6A9530DB70B0C37CC11BE16166159313C9D8ABADBC698D2D8D3D25C6C46997FD180610FA79DA0B3DD8F83CA5B47FBC469F2FF49FD711E7CCF60D7ACB3BA6CA8D771DE645C98E8A2B94AEA210030B21223B2BDACCD96B4E8DDA2DECE78D249722A05FFB3477C68FD599F31D6B3077EC175C5FE90034624164371666A6EDF2AF84E47067B9A2EA32A2CBA017AE0DC0D31B33DC1F2E7395E7632EDC2E5CBAAF820FF1ADA713D01472FA0FAFF537CEC9B7AD387B458030D7D44E0C38BFC35F54EBD9768BBF69B4183857937981B040502814020D0A58BB2D8D1FEFC9BEFF313BF308C0644A4A6F26C8B349B743FC5E0BDE3313FF3313E45A541B7B32470BE245F573C7C01CE5C2F4A125E3353F6CCB8698810F3CD10E247E4CD85460163C9D5EEC2F542D8CA51169761FA7588E088BC4FC4E2CA786487E23470C2B5C77851BE1C5287735DA229332A28F65FFA80378BA81C3056FDFCA7FABE00F7F7DB792B8B07AC6E91E95779FBAC63D23519B8E3D92C5EDD6E28BCE62C0C1ED41D83EBD0B716527EBE9339C61D3FE889EC4F4FBC9F978F5E6B66913FD936A23DA9A38B87750585EA01361AF9E28C66DB014BAE16BF7A6CCF94BD5843DBB0F3A7B03FA1636E28F2FD83E0D926C78C34DE3064F807742012760C4EF2106C25E36F927004C14E3DEB4AB01FD1A047D5440C978ED435622712715B280CD88E72DF36F620794092AD3AE96739432EFC3DF194D22E1977BEE16BF82C25A607D853C31D982EF5591FBEBE5CBD37FD58EEA590428C137B77ACF85EAE2FEBA26B310572170DEF2ADCC445B4311A2041916BFDF706F1A74B6D6F37241A7FCC23BFBFDFDD07A80588CD356CF6BEFF5659B77488059042FE9EDAF831F83215CB7EB0E741BCF78F5283AF88B7ADC5DCC94341157CAB9D20B7C44C876D03340DD6176B5382415B601B1FF7710A0B8FB50CB0F170C1DF7C97A94FAF4E3E27650567BFA0EA34483AFEED03861C98CB68256D011DB68CF87D083A4680818E5A682FE2AA80A615E06AE1EEF56E82D4C77885852DD3A94469FD10F243CE04BA0B49576E2C03B8649D51D6AC800B3A87FC817292BE2A0AE2F6F5F8AEE3324EFC8D4426E595E4E34B63280C50DE2A5157C761CCA5AD9E2C3D0890407B9EC26FF45A0863E894D3F3D3F8D9100A78C6222F7F1BF64331174EF506BF7D069E7000A139654BD7C16A52DB25FF7AD9BAF241502010089413A62CFEAB8D9151554E4A94EE77EF603BC79C691BE08206615627B7DE9AD62AAED8F9559B640953F40BBCE674047074FEA84558B299740DF98D3D61E5D2D72539179F1C5F56EBCB8EFC9684616032138CD9EA0F039E0CE21729A57F0F59A0E23648196FC4894BABE8EF6C746C86DDBC1C337910DEAFB6A32833FE04DA7518938091742F41C62FDEA8F776AEA506FDFB654563C30249FCA22F5716A6E47A0D5A401609DB4D1726A5B283AAEB04E351DCC0BBB5841F11ED0A76D0A58D836C9620BAB7B2AB27544ADEFDA60E0FCF7BFCCF31F8F6794DF4BC515DAE95F441B9F46FF625CABC6D9851E2950FF56CBF240032740DA8AF125D9CE1A3A2728C291DE32EB3BE19549BA7FD045B3CEDB131EDA8F36A829B1863E28C803019C0688B3C320CD9F0AFD7970F883689F7D4F3CAE145C8D35BB5289DA8CB3E5EF44BCF61E8BDC95EBEE919E274C8941F89692E14CE46BD53D6C30B9BE6F5E4D33E000DDFFB7A4B88E5B2ABD6214BAF889EF136559E7E4996A44A0590295D352D608B07EDFA0A827E4A8E68BFCBB8B7AEC475464AC0A47920FD07E9A866C0D7C9629222DE859E3F61E5173ED4E5B9B5BFE2FF4A95C57087B8A006A3C0EC111995A5DA7AB93543F1DBC4440451B79E721BBE1A5F55E1AA12F3DD103AED5294E07507AA3A72E6AE0AB0F78BF2774252771101249D18CC523A1A542F06F5BFC47250CE889F449D5D9A75A43D521F683B43D12FE4CC8F47E101092C4F02AA000D7602683013B62BDDC55493B81284474F4E2DDB05F7FDFD0FDD2BD80F730A834753F72461761A6D032BDEE9277B4E945D11F7BA0429B843EF230899FA6D0098F88212579063289680C4F90A1B1E5DBFDD7284D78ACD289917A5A2098A372DCCD94AB1A97228AC82258251377061180D9061861F7A7DF684F5F89A59B359BEED1714FD717F9AF1FD4BF03FEB9E59A8C81CC09703B9A2782DB533DA44A5D0576284B77285F6CBEAAEB61877D138C08C7232F7FA5307B67E882D3927AF0321C9A130A0B8FB0F3C65C9B6C842BE147AAAECCEE1C840A8EA2E9BC4DDB71FBFD14BB9880F0074548C5978CB9CF5049473C1917BA5DDF26A664C662D37D13F5CA6BF2D4AEC37BBA198D690A72798C5341B55845364F9F5FF43858ABC83D6FBF5296D859F97D09A123B325A229328279DEE40ABD7147C8E5CDA74B881E383A00ECF1022FBDC2098044B1072CAB722A737A1C6B11C66FA238671F1FE1B1D26DFA0964A0385955FC2C6F20B25AF0114EF90E705BC25AA90C5DCDDE088DFC38544CA57FAD9AAC4F04229CFAC69399A48DB2D6B631A8C1C3CAA68E95F2AE3A09C756E724EFD24E7D5E4BB7010AD24EF719BE9B2764A135995383E8E67EF47BBAABA7C6F1293866DE130C051333439D940D6F809E1FBEEF51F7C130146365B03010526CD983F56F8ED67A700BF20A246A5843B62B5BACEAAD8F4EFFE28812F72578A917C93EB5668A4A74D8733B1CCCCE500E2BFAC7C51E3A7EBE29A74B1CE9495C4A9296AE2F5FFA5E845330887ACB78F69CBB45AC655FEC330D2406A1DD4271A0A0338DF763D9BBE237F83735095BF530B052FC90DF29F46737ED1A98ACC9FA0288F05F0A9CF7F21F9F330DE3108B5959716D4289305EB4C53BFD0BA621669751CB0A213F7FC5A478E931E942FFAE5707474997A6B1EC9FDCA44AD274C08575F83EE5DB3433BA57B3901B28E8519801927DCAE4FA848AA5FE0F8E02DD79CB78424312B836639BA089B289107E10EF54BEAEAAD9E62F0AF184939237EDE27A51CCB31BF79AD54764962B5E0FF42A3192BE42FC67E366B61D046C57FE2FE0FF8C2E6D0825F2C6079F8CDBCEEE1F70B538D2D925EFB3CB5B15A39A57688907FF59C42744F86F362F09CDBA89911C0372D7F91CB41DFD9C4DB2EF4562B6986D6577A8127EE41B28129785BA4AAF4C09780353185686A50EC35E86E6F06F43CB4161B30511876F9CFC0BDF330ABB331AEB44E16C7D0606B1A33A36279A59A4CA5EFF2B35F7F8D001CE8B94C158C435FFAD0E833B84D9BBA5B166D9777944E0513766B927593BF7776C2BBD47D7D1B862F1EE2BFA42F88AA1A0EFB89AC40393279E31E2F9EE23BC09F64A6A23C6F74D3A53001B8463D93823AD117A099D3394D647829DC6558E43B6E27F4DC78B6F44712D6EB6EB8439753C6CE9CF2239AB854221262009AF0E68E6FE6B24CFCD1156E96B74BDAF5CAA8861FAB18DAD319B1D7BFD11D6500518C48689BD02BFA8EA9167D31FB28E5A94B73626944FC7A23A548D4B8FFC637980E968899063E36022C83E2FB089280610651DD08B916A69694CFE4421831DD62A4BB8DF3678C832FBD6D8B4337D8DAF73B421E90B1D4657457BBFCF22C0857366A5D4ACA0D748167CBAD7CBE2C968D267850316C450C3C819787B69D437C292C5C77170A05F84294D0F93C8C74CE1FE7EEA00054E9CC2FCBF208A04A0912C6824BDC84E20FC6CB16509213F0B6718B4E9D3289C826CB5DA2860E135AE518BE386B46DA0085D178EEE3BA358C10439E6666907329AE382C5F0A79C4FB8AACC9F7223B8B437A06CEAAB87E2F4B347141EE82A1EB730BDAFDF5F15277FA3467384CCFC88BA771CE539F0B0B049209CFFFBC9A34B6696C31ED001AD6B7B806EAB9EBF1AD9A1328B7BA6B6A897EBA5EC2EDB127A90ED1665DD95ED348266BC7B96AF0C40191613AB0F21FD1E134258C5A5F74557043D092D8B0A74C83817E83C517B16BE81D03ED35E4AA8D48E9CF98DA0CA0BCEEE079A6CE1E6421865551ED4A4D22B8747DCF79F0348CFD73F3B3D5515EA0CAA705F04C6A010B9DDD2E4FFDF90C045CAF00E1CD8C27BD99E9B8BF9F36F2131ED69D2EEB5D90DF5B5CF902379CE4284789098777D70D5FF2159E7D432B8277F07BA845BC48131580613D42BD9464533A1DF63C88CB5F34FA6FDB43D921789ED6DF7CFAA9585B2506E990E774C8DDA2E1792504EF6F44DDDD8CAA0BC5079BE07DA2C91054BF0050F5FF070357C3B06E4894A32FE6A9835C3670A0C0D8E05BF30426A89474122069147D362C2D1A4B7E73DA8C31D732012FA711BC631D0AE625341C25CDEB62455C20E27768614EDE2AF72E4D532CAE4618079BABEC1D619078FEA8C7A33B43F9C8E0D810D5C050D938A6C6AEFBD4B4FA8F01DC15327F9DFEE740422597575988E1B2B854C65C40FE0346C3CC0A5A647F029120E5ED1D6DE83A11712EB4CC372286C0405CC64F4D83B671221FB5806CF4B60444B231628B473B87D883C00B74D6C3E618E00BCBA5AD0C5230A221FFCA8BDAF55E901286364DB9367AB2AC59E42668FD1B1F4B20BD2701D1C1E9725833825BC3C376AED9B63AED86486BCBD4A9518D89ED6F1E01454223A9FE975FC4C1B3477BE080F4B3CB68D080CD09BA4BC24DE9DACB864ED610A14FB86DD856180A03247F9DF44B201BC4127443F5AFDF5954A7A227CE626A595BEDD1A7C545FA75ED00411798C4B2FC3BDA4FD5BA2F755445138BAE3B4699F72E02B6D3F182FF69881CBB11C55FAEC87C5E2730140B8325A6A9ABD75B260AE4560A3F4FDAA3DF9AE644B2AE1DDCA038E5DDC7AD21BFCAEA1FF13D5AD26F74471B27642A5AADE37CAD55222A153064ED808DA04B9C1D5C14299923A939612445022956922AC3ECDE1FE90C5AAAE135BAB8E2CDF3241BC2ECC852FC22E7E222E0D702F35517551010C7177153F273F423567823D123B555464253FE67ADD1FFC5EFA7BBA696CBD7C92F075CB9894E570502C44A1B3CE98CB9E74B8F008D74C2F6F6A1B122B0F8F51C5018936E517530259BFDF18121BD0423ACD7178112B0778990AF9B8946EB01E9F1701CEBFC013D205CD5506E6A9414FCB7A9290D3A0423F84A65D8BB2EF62C340B1E2E2FB1F95DC83221EC657D51311406D052C5B3492B705292094BE44EA3DBBF5B7A7EC32E6FC1C1A4B05277CF5EFF550DD0F5279BF295BA9299ADD54FB3FF7DC1D77AAFF4583371320CB29FF6E6FF75AE01563E706643551FB0311EC8F96544646B1F481A897BE136ECF3568AD18A6B7C717B406D211A404BA34A60EAED9FA74AD2D0785E66BEFFC690D26243C5C7ED1ACBDA86FABF5F0AC01B5B250E094DD0B5E871D35F91FE9410BB08B2DD9629901B2F8B904D5DE6E21E9A768B20679505A3AF61678E537986D17F23126280AAEDFCB3D91F652D9312C2B21C4E6BC52D12A50BBABDEE7F20138FE8EA7B3C92805041D84C6CF0ADEE5DCB2FC56EFE5A2E493DF531F7E9C8822077F2D4F7474611F044A6DA200CD9AF6293B1DAD005E8790E3008C7A249E86EAA19D05F0B52EDD05767B73610B294128B441B43E56FFD673139925F0B479C57C7C6601AEEEBC4D5750C1375C7234BFF23402405A33357114D4CF9C95A32B3F763CA0269C618A1E3A631CFF9A685FD25CC1CB51D84A894DA08C1730095E2845BB407545CE862B7F2F0CB35B14F74C6659A7E65B0F0739DF8578B07279640F589E5243A6D78966E666CCFC7222615F93F931190566B1710B48EAACCDAEC4B38F9F990AE48E0446A0F68CE1A232A3A202892591BFEA558D3FF5F83B40882C536B2014EDB1FAC090253977BDD8E8F2E9A3ACA69550DF68317C67DCE04F45C227161357C18664D0CAAA63CE9F0F04AE62CE7287F35F73E9C28DC691FEC9D8760D88A7EE11BC21BF42A9DE7496FF8B4EA2910B9E3011C460E88657C68111181279ED1A91B63A540D051C1E7A3A9A5CADC04BBF5FC70C59F0921F2D370FE3997803E66DC7606541E4D312F27586E1FAEE78C3CA8DD05BBF338BF078B13A6CB5CF8266CC45647B009087AB01DBF7C264F3AA21E0236CE67A939034E43F3FEF9DECF24B5690EAEF7F6729A11D3C1BAC786B765800E9AEA6E8DC4C2A893C66927FDAD2385FB364353B48DF3CDAE2253A3CFF1BDF6A357BCAD49DECD9F6918058899A98A5BBF9D7ECD0526EFFFB49569386A195385785B49F250588BB33F26215ADB074F2465009C8A42B4BE979A0D3E02B5DF19B5693D3E81406895B3725B62F0E9C45837370E2C5C1D2D5C20A3E30B58AD0A7494155EE915EBDAD5F352E6F4E901E43CFD87B9280803E0FE46E7837DD31E2DEF10778DDB4A8DF01621868B9E6477F11958FDB8D1C7470031CF2FD8504CD2D0EBF21F20EA99229B5FB544E5E3DDC1B4A8DFE5B6F1AA6B1B62E7665C1A4544AE4755A61D2BEF0D1DEE1C7F8C49C692FABF31A113CEF0CCCF695D5E5FD44F3FC3A8C1D7D833DDC41BF07475684888AFE9A3EC0CD8E43B623837FE4813F3B3B84FBB89E2FFF2B102DF8213F3E266703C14CFBF60D90DC90627906C8AC98F4296D6F05D49B4E574A969BB2C8BE6CF00403A65B5D8EA10E4E2CE12572FC31E0F73BDED39775D49DF6AB1EB7049BB2AA31231DFE268AA004AC8265313828747D85742E93475F7DBEFBBEBDB42A3D91D4211C288355F8246F36FC8FF7BB1F1B0F8A094E38450EAE86C7D21029FC32267621CA184A2D74985DEC8AE86592B663BF0E5E5DF225179BD2B12403E851956C9E3917239B688765BD6F1DD24AF090039F13ECAA42366F28C0AAB0B22B4FC288122CFC21144EE09CAC7FC4A23225176098C597F1F549E9774C2073E862D674BC952F3C3A8E9BE2FF297CF2019F76A823EC06888EEA8DC6EA016C57D985AACF01735B4D67D509FBEE453923BEC3E103C461E3CDF1AD390960CFEF49B651C2F3ABB42F5E9134F8DEF8BFF2D5C07B7A9CDC1D58EA262080C7CA4ABBE66E2B0EBFB870BCE55AF288916194ED1FCF759FB474D09D692A7758103F0A46DFC872C8EBF7AD0479E71CB888B0ED17D1185E039E6E3507CCC0102DC95E449D8B6E48FF34A8451C1D237DEF722BF2F54B4D453545578E9E0222116A3D27FBE87BA831C000339966B1F8C25435F13CA18404BE49933A7A92FC30CB3A419FA0ED94A65DDC5BF3FDC42C70A2D3464B556A9BC1BB20E82028140201048B4A2CDC4B2D8AF6C0FC845F35FD3B6959F800E2F0161ACBC0B3E1A1D4E977D9493C9EFF7A82AAA7A9EE7AC600660734BE459FAC7DB6D393E20F17CBB333BDDCA9615ED649C360E0F536496FC65CDD4E561563C02CAF2EC6580FC197061AED11C04E9A10CAA306D8567A296451895FCD2B8F7C9AB7CD3BA80B216D04CBD7A5C43C7C089E6E34819E7A12690584AA37DB56F27729CCD8257FA4555FEEA753D8371E6F0D22E32CBA6F557E7DA99AD0EBBE28D7078A72FFB9D1C40DE4D44C5101848721AB043138F7880FD1E1B37993E376A3E81CBA5C4CC3EAE0BD5573E3D78EF0B6015471B6F0C8407DAFFB0EBBF9D9564403EB0F121A14D2032D26869580C96FAEED85238CA8C466BFE891CDB14161F31C00361D3CF22AE0985A67623E30392C5FBEC928386E2CD504673D41BE5D4CFF03D40D0C0BBB12612351F8283890FCAF91B99C4D79828E1235346AD2752F19D3A55B71BA2430E6F24548AC9180472D96AC712D8112DC0204026A9040394BC619E12935E6AEBA922CE919000B7E739B4AF34329F62724A5317F58023217F922C842882B2E203CAA2CE86F8205E86C28042242BC6131213191E1FB4A89B4F6FAA304771BBA7581F5B5D8A9A12A6ED7B76C06F6B6FB2EC3E882071007DD1716A5F4389F4023125AD965F023F29DD58A6F0B51B929E0EBAD517CE14DA2E9EE4742D39AB82ED7150B8DF449CA2FA70633157110DD14022E3D868BB8D4732EFBC82A37D72B92A2C5C5705EC549DE410B93D8D7C88F10660449876D925FE6AA380F0B35CD1F08DAFF62D7FEDD2048D28B84E2252E65BBB25980643C990EF0610EE4336856118172013A822C6400CF063A58ACD3B1DD398C483B7C903951EC6EDB02EED47076DA560B24BC0B4D53D2E6065F64ABCDDD69EBD73DFF4B653967A8CFE3BDEA2DA6B8B78099EFCABCD257FF7435C0D7BEF43140C4E08FC58844CB0F481FAC31DE8166436786AF4C0D8F06A91D548431B9A3FE57645A79947070DBE670C93B0F5AEDD53EB3B5B797D011C00ED629E73AA24DD0BFAACDF51DB27558A8A581C656989D59A30E157E1C6FA3FFE64B4472045B2B345691FAACB28FAA5221C021588FF55D7A8FF4D228DE14FE020F618EAFF28FA1CF8B3A73FFD32AAA17EB7F3CFAEC222C4507AF9DF801BFDE3BAF553614D4F2AFF5BD0E70C610A6863FD6799F5F0C7DFE6A879E4325214F8EA72D1D49A4763A47B8004FBC71A66C9B6CAA5C9095E38325EF1502561D1EF3E8A28F17EA7B3BFD370EAE03D84B6411FB2854D6D761A3A1F3DDE155F97CBA2AB0044A6EF51047581127FC4E0A2CC968DBED9C16285B24D8B134141C0453F98B33727E828D61C51E122C105EE6517321ECF50082F6FC422AE8E7394BF80566C380C577DAC3D3127BF47BB9A3B2F2CE2565455C7F943B8D51A16E7CB2CE0BA1E55E7C3F40F1D91982634C7EF0BCC97C67CF8CCD7860036B0A7DE6CE6AC288E85100FCB9919CA01640FCBDB0358BF8F1E698C97AEA4EA0B495B7E5125A7A965372E58F4D4E57B1B77562283A93F2FD03EE0A2533457241574EB928F8C58BDF788E431CF70146F93D4A1F7C32568C126A5F5FA2FF4581E8B356F82BF64008A87211CE7603C6984A338CF437DF259F6785A22BCD92AF796E6881085074D846EB037A8FE8ED1FF60678E09A482F157101701CCF7847A7886B5AE298433D35D1723E5497584C564956A7A4ED87A6F7B63B600AE09E56AE2BAB852E5191197DBB3C50231EBAECF23D25411798B776623BBCE6B37147176EFBE77D090A7ABD253334D83B069BC19DA289F565857D479FFFD5FB627CC4178F3578676F37F1407B1F52DE1C7481BE5FD8152658FE52E15CA8E1DED17E7F1519A4FDE49A7621E67E40689C6F82A32E287C20072C67C0C2128CC471624C22B995752F8E6B2C970FF9210852274F12113FBA90400ECFFD9E375D9B6E0F1A08B99F0EDFD09AF27B7CC6B52D922978F3410E182AD0D02C5F82CB276D3914DA942D12953E12660B3885B550D60EF415D0B4865243ADF68C66149451A44B92D185FBC3719A3F74FD06835E96C6F2B75BADEC283427AEC4BFC0D02862D93DA6D24409F0B1172F6058959BE212E289D499E328A16B17D716AA6F25EF14030914249EC1A2DBBAFD8C976FCCB0AA269C72A8040479E8D306D7D731787EF4C9033551BAC88EB893E9DBE79DFE99C5BA3C171DA9BA57CF9B804348024999C7196913C214CDA49AFCF6B0A0F97FAF54E7B1DB1CB67E419BBB24E767050EC86E13262BD2D8576936F18D0DEF0DA9D2F5D530D2351F52EFC0FC79F886270198776B01C330E05B773A5E8B03DB063EF43AB93F1D0F589C92F60824EF18DBF53F57940C920C16C74102276CCFCB30BD8FC039A656BAC8101343EC65E5E337C0F39F3E8FD7010F7D95EAD175569A5EC9DB87C6A67C823BA8DBBA11544A999F9EB1C96B0E32DEC51153560307204F914EFBB279752E8B834DB33BE7BD923B2E7681551FD903283C3B59351050FC29C0403B89E2237DD96E3D9442B71266BE17F0533D8F65A043454B2757AC76B9759CE3277BC769DCCF4E30D2DDF32A5F0841650D868E3CB4C9D51AF5EE4710CDB91A1C27430F43B4FEC084DAC21ACE94E70E3FE06B9439F7162B88CE9D09F8A88670C80813A360D1B2F69461F82039E5D019C8D34D5C4BAC4306E976A02549D9377BB5544004570FA8F935BE7316B7E8FFAED66B6EB667A113E226B41B7AD10B6EBCDFAE92D3A2B51CAE0A518096D161A76E47FFD9167BDA12EDF6EC6998677B5AF7BCFB99C15ACEDB5AC924A70B8DD97D401F3807247CDB0A55EE1EFFF0F0573A5FFA7E56ACC3B9E005219C9784B4A8D05AF5BB00F032933CEF0B59F54107BB74F08158E6A613E3FF5ED1782BFC0CC2BF7341B8445FCF590F458D2160FD568540502F05BCC1DD38775EEF8AC4AA0247E6233FDFF77B5D36692FB8C843D2C2E5E4B70D30DDD519DCA54307E70F4565712713D46666F58D3C573572FD8224384488806D8E183014D61449EB379C219A5895912CDA07D10173794CF1A8729950A6DEA1910E45CD9C09E14F0499F7F13B43E9EA36045842DC5804415FB41FD491FA5EEE08A1270565109F1F5F80870599A1A144A70DDFD967FD4D3E05C74A7F5563DCC21D46C5C43736A897814D59711B7A83CD810F68129D6CBF4422F7F90D1CD322829AAA0CACFA7FE7B8B3369281E3DA574115D71652DF69A24D2DD1329D87F6D02EC44F31B0EB0E3811B367A8C4312E8BB21BA7B5A4B4B31BB50C7ABB81D73F81F6C546AD37F05EE2516A3AF63678E2AD380F157111786CD57A7C8421F636A6EDDA34A482CB2B9A7BFEE7C2F7412C6299324E3BF845E034198D1A83F3BCEAE9A3A6A3B71F82629833FF4B713899562FBC9524585BEBF5A7743826A31DCDF03FA19E2D2967450C8A990590C4139749793D8AC7C33420DA111A745F5F571F39C34F6C82C802DDDA6FC57D8CE3A31F48103AAADA90427337108B7B173C5866280DF8882694572FB2E4387388A232C7F9B080A98A4B9F5B773D47882C391176D85E8F5BDB123C73AFBDD0F4DB0F997AC30FCBE895C665702FA1CCABDDBAC78E02C433FFA7F62F4905DA26B5B221B9FA77CC8EBE16C25D74E5DCFB2C4445C1ABB00B3B7AFD6262AA3FC7E90EB15B885E20539CBB29FA8CAF44BCF25326F07C56CB17F29CFD361A4AA4300B18A97247E4856D7FF2C48125D93BB1B51D0D1C195CC5C19275F4F7BCD559B0F78DDCAE48A781D4029D1791C00234D2ED325CFFC634AE104CCB9042F7AEDE19DCF768E55B9B2BB77472273EB3FA32B6F518919AB0D3A84CF79399936A6FC5FFB0356FFC36723AD5BE5A151A11E90FC3F3A17A7B445FC8E7890EE58B92504368170A21F8C5E3F63F8B3F365250CB5595FFDFB6D03BFDD657116F41145509C96C32C62743487A6945027BD5B28BBFC729EE723A1D74B5332C493BCEB6790F90ABD9C3D3BA68ED58CBE199A95E64FF3DBA17F7AB5961A40ED5AFFC04B543420D0ABB048F52B269487E4F28B7195F5D8CB36362C910E9025ED36AE7512FBE10020A0DDCCC8DF6CD9C1642A3E74748BB7866B15BF9354F43ECEC74C746C6B3E237623A083A040201088337DECF99C29ECC9CBAC8F34FFA0E92B6EF75A40927C7423BA9575688C43D9659543AD2B134634C40060B6342A3C3794A02FEB04326B198E8C55A6998FEB5B4CD9DE3D0B257D0597F7006D6237090B78042BBE25A92610DE219D5FBCA922F18597B77C0AADE4B74BB028B917682CA235DE736418A813C70899960714F07B1FABF81BE288CFBAF2DA6089B387B91A0E1D7F03AB5C0EDFEE06AEE062D1CE462F4331A05CCCCE2DF4DBAD2057C768A79C29EDCBE3FCB45CF1902702CE700806A7FE62E37425908C148C4835D304414D13AA8E4D88BA21D4B1B6632D198052163243FF4FE460C214E909CA29E3A566361D6E6DF66165D1A7E5EFBFB0B912FED43DA6F8B33769A292FD9280786DEA2311E9B59461FAF1A93A6F0C1C3BC20F86BBE2B18C059CCD6BB2B834ABFDA7B84F6721A06442915236685C473D3AEAA19E2D80C8377C53ABE29ED268FC99AAADFB5AE71E4BB2799399984AE57D0CCF248C3342B4A6E7534206EE771093AEB86150F3CD5D56B7A28B6B738162A6712BA13F51CCF68F7A426F40293BAE844D93AEBD89890A81D6636DCB8721CD491E850531CFB522CBA21933104F43ADA3931EFFD5828A188ACB26D182B7A127844C1959B054257E399FA38C60C2984DFDF13FA973952D6143BD4E302C66EB07B59FA0AC98F515B968D06CFC1FB676282AFE3B4C847D8EE1DE93AB4155946E565B59EDACE9E03DA5DF18ACE99C4C818A64D7760A5A38813B5366DAD1BED25564A626E1370BBF6C7891DE965C36B8EAA67DB83714F3D4B489AEFCBF26A31424C104EBC95BFD5F59AB6538C7FC05030281B8C121D670E723C66FBDA312759F131EBB249CA87FEA807AD23FA9B39914E136ADF708615F7BE67FD9E31B8E4EC6D37337629E4DC9A39FFF4B6F0CECEB45777873DC9242283B8BB034054D9C07BD50C0DC457C7ED06952E8AC4493EDCD1AB2D65805DC3F4F80CCE9AA7989D3D44842FDE5F6F0F7B31170A911092F468FFA1F2CE30A7B6048E938F1C196D44B3471451F311A78DE1F550A789DED41ECB5693779880B9BD4F7E8D7C2F984A520604266B390C5056CB203A03607B8E0FF4E17DD276B05DBEF60C377CCDEFF9A8FFAB7CCB8574BC6D38D612618C4E81BD8992366C560FC35C8EF215D8218136FDBB6A65B61FDA35E870DA7BC8B515E573F866ACB4E0AE48AFB0FC00F47A9211E632833AC65876AF742970B751347DF9C66E4228AD025B0CFA2B6C23780B60EFD8CB612093E546BDEB4F23F36672C055D346B0A6DAA14A63D9564405345069BD384B05CEA2014BAAF6FF9D77B25234BE97D4F9BB026B023AA391D945D32B0920AF523330458E4FFD20B04E67E067300AED5BBD23C95DD30DF1B97389BFC120A13489AF225B7434FDE336D0C0229F58401DC6FF693BCB91C6E592DF822790F2B0C4CBC18A62D17678AF80C737F39180C7701DA5FF18C748CC4A55407DB14C666E9CD182DB79A71CC6F499AB39E91D22A49B0801659014AC25ECA19A6726DE3E60FD587359782D2C1020FD6F63E83D6A6E9E578E0629D82ADF7179B56C8BFE3F3734729DB76D660A522B9E6E48678A90FCD6FBFDE812C493D761BA6BA79D48EED14D7734AA9E026BA351E2B94D9FC62BA6248432C32F047873AEE43578020476F80762DBEFBD4AF3663150E2EB80CC6DF55113702A710D84310C6F096B83B2650563D21D2F3435DB20E9D9A75BF4611116BE282BDB20901327187027AF32C6E68BEBB0DC5C28B7AFF67520133CB388DFD343320D692FDE319161616161616F696E9FFC70608F633040398266218729061849FD0B1607A0B75DB2D2AECA8B4E90153470465B3756096BB0099D3B10148DA1038FB0C78DEACE61C7D77263E197C8FD647893F743131BE297500872449AF568F28C524BBC9ECA182505572BF508E6A50FB64DEBDFA4F85F40C5A802FA02F8DCAF5F3D09DDDBEF55620F1CBC94264EFAD02FBFFC15D49A4CE213808F0737A5431B864B219D52A74874FEFC969DC3633AD6955336C4ADA9815FAD683057083E11890C06E89C5A1554D03802126AF25B743A585A0EAD67121FF374FF22060206C6BDC911431D1DFE68C3F0353A915954139D9D51FD69BFA7BAFA4268FD63CF07571808AA120B509294197B4E4E64638560A7106E350C2B1FFFBA0F3194C0E1A208704250D1EFC9E6789C61C749CF85198E0DF699BE45516874C87513C6FFAA0018486706A9415C6CD0DD29B6DB6F79AFD028F33526ADFC1BBF404C41556BD64F70013C4ECA5F9C7774F29A99F598CCC69754ADB73F0B02239F512243E9648EB9AD9807EF9418C33B67C7B6A3ED1FE2F6760F97F27DE16724F136A1E2828E2B2928F0CD85CE910471F25FE3F988968A7448D9CCC31CD99CAB3888562740F865DFB62EB05F042BB0F72BBAAD59C6E4152F2D8F1EFC6A5D91E05E74292EFCF61F10213BF950127C809C8E85C4EFB314799D4F1DBBAF28AA2F09339EFFC96D3FE7E36AF46592E000796CCE81F90D4D1F79FB1CA79BF5F771F5050917AC484C4B91BEA6804F60990C2402010E897DF3102E733021B793702D333023D38D235F1AC8963C62F111E4257B03C3A3438F374ABF0DDCE047FB43CE8977CE713E6DCF419FAC162F4C35FE83F3F0C14369C899EB689971307512E5B06F94FC0E6230677E95F087821D74FDEE5199EC4EFD1DA8173DF89A9865212FDB82AE9158ECB8FE4FCD405D6ABCE8AFB864DFF4AC7E1448B6B83EB5DC069206E96025D0E5FC729127987170A15598B9AE67861CFE481DC7C21913B49345B06F48D6393F7A97BE7F65BB6F219055566B86B95B15397C686E0616405F51B8F9DCF86AD8A2FC42807BE081F539B50A8274E864FF90B5AA2D880D3A8887BD40DB53F34B94F30645DB46CA32C23398533A5D05B6083A68A0C6E3A4FAFF407395DFABFFAD661FFE8B44C8B65E3977CBB4747C9131AA69202D9ACFEF6842D7DD893543461893328F195348024DEAEF411F02D1237A78BF9164A3C910797CE39EEA8A440F760A0E26BD88C1461EEF25BDFD57CB2A42AC905B15CCEBDE4F81568FFCBD241DBED6EE111F733ECA1745D8006A0D53DB886381B5674A5BD123779789F3C82E9DF4967832D1C68CF13F10F43B0CCB6307C5D8C15C7876C1C030C5DF2303DDE8931BF2E25CD5F2E94E3D248B35A8DC7F85B3AD58528379A36F44FE57BEA77B8348541AF954460BCF7EE097A6F870A1F2769FFA5DCCFDD1D3FB3BD38C35ABF28940743374D2E77842E62C9AFBE4CFBFC5DC1A24622F2BFFF7794C92E9363EA7DAB05C89C3CDE064D96241C2BE29FE49AB9BF09FCA2B77BAAF92BB1B050088B7F8B7809F788AFD9B8EEA1D360524A669BB4A448CADFBD73C299C685706C5F2125901433684EAE87A580383D9BFF52F4BCF3520F4B007801FF7285E3FBC8EF981B91BD28FB6A70AE826E94C88E13A46228D37911BCA7C5DD38B4F861B20D6D554686D7674072A24D487FD509BCB24A2B934536E920563050101D86C0801D325EB68AC644397FA1F6CAB3378B11CBE4AFF14D3124B8BB4E0FAFA45F71B600340E6CD3F47FD273C948F8926ABD5AD6741417620F9849F71449CB6E1559E4679BD6482CF4535424E47B74E5023D2510FC7010109681C35546972AF65562F989BC24EA54091C3A4715B139865D47CEF69E488FD067A520EF47FEAB74DC60B9FA9F1857EA9A8112BAFAEFAE69C7002B041410206B48C2659C23FE8CFFC55EB700078941D4E6D590C162C37D3937A8A53BA2B481FB4A08A0197E39E017799596E258DC3929EC5FBE3D54A5B7D5D08FEA1BE9267C2F491EB4BD2F51C67A7A4C808D64FE8311180DE8F3CF317C92F4FD2627F182C6C9A3481A9FD18525F154FB61E891B1B223175F26692E9776499C90BC461F878AB587B0E6BE8BAC5B6C5BD8E7A597C29CDFF0704E292DCA15DBC6CC4E79D4A674C2E8D854F13789B8B9731710D42478F29A8BD4E0C0EC1C120C852FA5F505EAAF78E25E6AA43391E2ACA9824D374C038E5B302F3DDB38961B4A13644AB7ABFA79BF09FE11F2C5D452ACC7A20AC37540CF99C22994FCF77FE0840FC7FA9CEC716A20724AA88E64784CF486BDA4D5AD7352A87CC78C6D0062255D65EADC5A306643F26A5B09979367471D3F630EDE24812CB6E66D86E6215CB507FFE95179C4480CC02185B57979E18477B44FAB47246A6AB6EF4EEE86E303457AB21EC14790051907680123DB1A0BA94C09D713D77784D19EA79CBFCE16FAD177E1BEF50167A760BD6E78F2AF23A891A04B8CE836E6A32808034E5CDA8C87D6B6551EF2BEDD343B27D2E9D9260DB5074605DD48A036B37CC5D5049406E1651A0B737776BF3AE7CE11475E1D6A5BAD896C07B5C1BDA33C827254CF92EE08C9778B42B25A1437083469A3C6F89E1CA08A337F9E3D9690B1AD30C8345AE0C6501214C769655B2130C8466235F544AC1694C4432DD09901ED98F0FE0F2B07C9226EB7D9CBC28477BE7993943FA350D1000676D638EEC6F785B647F762DD6309B91593EDEEC4B6367ACCB62DE5FF34A69E8F033A071D3F0FCC43DDC26E2834A9C33D98D2E144F36E11A3C3BB0B621502E51A30E1BC48CC9A0DC21CBC64141EA950B5784E3C0D9E739780809750AABDC2FF25069165F808E11FB645B25F1842D2830B95EBE7E2E8BABED47AA06993950314EFF37E237B263E1570BB2C66C3CC8C6D2BB5540844EB384A204B3C045BE88E6E382350E58DA4C4CFFCC46E36462C3F7999DF87963E7218C080CE2E2474B360222BD1DB36ABE4E8B76A55C31439D492051D33A25BA0263F0E28FA78AFF3EA37CB433D39068DB8602236F765CC246E8E06A8DAD6741D595DDD4640812B8E3E6026312A6470272F1F741EDA26C41763E0FBA01798BD62633BA2C3BCE47F1B531D28BF0FFF933192F545E1573B0120BCF2D18FFC27FE974E357BA2ADC5920636354A5B7FFDB701B11AB9CA588CB6976E847C4F824B90E8328329F9D524BA2955C56D8B60BD2886D2D699F5E85D123CF378C9EE31D87E37275723F803A68D508E44A1C37F17C20BF590AB1ABB9151C1FBF276F2660D412F3DACC3424970C1348CBEC9CE1CF6508FF1D7517E3DA7AFB1ECBF3E2120C03CA6CFDB725818205CD1F687EA8E6D4C66C99EAE2416101BC95C7C37706A7BFF8564CDD26599FB107A3BC91D38827740FEBB04A9D6C2DA798A5062AEA91368AFB77BF05A42CED95DFDEFF1D8CEFEE7370F9088A8D49E8553B10B983547FEED6D318508482F3B53E450A1F834C585773C4BE475542A9F2AE7EA450635BD0BE0AAAAACB0EB4E988F3A96FDA6B7149E52E3AEBAE25A8A54CC1E6CBAE252F38C0BAF99442C30D9A8343E1CE02B83B208538A6036CB26D40E26703450479EC649DC97B25BC9A5EE0D075035FB8E1B832DDB164A7F4E8C3F0187EC4917B5C8B8E431F44837DAE710B338125931B192268C13C6DF3BC4B1424A5A832AB092F44021C3B94B9A39FE3FE9947CCC0319E05206C489E1B9971F584F8F557E2AA8931B2387EC0DFDE27F93A791F0CCF4B9EE86B346609E262931353FB18B9EFFC24F669E095665C30710601ABB4B92414BBFFBAC9744C7926CAF92BDD4CCCC58EBF4788F1BA36BC10302221D385E8729C9D09CEEADCBC784E4A18BBDA71C5AF5C887A839B6C5BE210BB1B3F1DA2E792EB928D295F27FFFA650970E3C3BD059414845ABF1E0F207AB5AAE5B4124B2325A27BA2D88F0203DC6DAE6AEC0D123B360F9DCD918C20087940957D1619D161177C137D33149BBBA31C781C764F721871175D46FBE8328808E7106D45F27AC44EAB76F6723DCEC90C1C2D511CD39DE40B7002B514F412D0BD2BAD25A6716C6FCFD58B134008545C20E0C752936EF97491DF2FF17084CE51DEDC834AEDD6A647BDB3B5BAC3637BF2EC11F8F838F28F0B1785CE8A7E5965228EE8122822B835ED0B4B9D65C8FF3158E948DC6AE7A23ED1C4C3600018158B343E678D6BE1061A813FE4E98F27B2C028874EA05E99AEF405350CA6E37E4E4F97C4FD2F1B30433D678D02F6A6B360EACBF2D21351E60FC47E0E14728DC25DB338CB99025FB2B92FC0DC5AE4A274452731622C27D037D654BCABE5FE3A9947E4152980D8619FEA7FD0670FE504163A635C091DBB60E1286E2DB6FB6AFED1C7E75B0BBF9345F3F255C3CA1041C349B09DF7923C144D1512467FFC2FE0DE39D8CDD3B03DC094F1E624A50CC2DD294A95B360C54FBC7510F7A94AE12D9F3337A3E500586F6A0571C0203D2221D292160C75A59E23C96AA2F435912A2F6FA587C1AB5CBB4952CB124490600B63E5A86F2B1931B9A7B57DCD2ADE857436DD810E20541F559534CD90FFF9DD1768B6793782443B11B4014D217BFC3305E9C250D8EC460D046E08C38ED6492806687A57F47652831B1B41832EAF5D0DE0A7615C24492437DEED2DC199AD53286D7BD0EFA8BA27B2D0C70E691E8735ED4153E78ADECF80CC4E2F9BB7F91A571CDE7A8F27AA084BA45ACEA862695C7483033DD25AC351A4818520FA6AB6B10582878101C340C048C80C3EF05EC4EBBB0440D38EFC249DAE487585A7A8D77913016971FC60533834D03B28603C78391FD6B955C1536EC156C86E41ADC0DA327FCBF660A9571E7CAF93DA526E675F27D11E533BB25FBB4E6FED0E427A323D16FCF2FB31F762726EA229C9E2F6DDE85DA71416823346ACAF1E20D054A99C666A461371F1A1CEDDBA93BF3579EDB9B88B0CE11E85163E245925DC141C787AD137854059E4ED97E7E135C98DC4C21DA5EDDB7243DB7E2F6EC238F201008C4CBBCFFB658FA0A5FA704AE92E05F495ECBBE62D6F5D341ADA0C7C4B80E15A1418255A7A94C9B8EAE6E834B66D5E13352EC9A9FFC093CE42E3D987A279917667F084B3CEE5A7AAC32EDD7C1AADA1395BFF3DA6AB2879005DA239FC4A22BE53BBF7D1A5B31D73D614EA482D2D8B86D35505424D977607C64B1EE4AA0CC9E1ED6405A78B48518A0359592986AACB9EFAB43A710C2F586ABF5A23D0ABF17F7E4A5FF954929825005C057B68C5E40E4804F35AFB88343FAF35514C76CF85306FB0B8375654814231767DD350D0F4DF321DC678537FF6FA58804BABC8A9DA1A101BB8AC693CC53714F5346C44503EE015F3CF228814EBA85BF06D64BF51C24734F83BACEC600C68B9693802AD3CC9805FD7A01F6B408A26FFE123ACD8564633FFC72F825A06C982333CCDD97BC8340214240905EBB6285867ABC6028681001041902828105F3060743102170F00860103404A1A4781DF24FEA4F0BF31FB4C624E53DEE85F64ED17769A524EB4A87CCC3FB13DAFEE8266D2EE92E9D3011AC53273E6CBCCC906D6F8FCC7E02329821F2A216345FFBC4436040289C4D9C13664BDB55C217C5DDB1918D2D24391F6C71481DC83DF697CF41A41F50B2096D3C06A1B0C1F72D6BF3F2B6C0EE9D66499A679C7A5461A482C61D71BD6202DE414EC4D027FCD51491B852061F25DAE925B4F9E13ADC6A2C3A4D2AFFA838591421F35790171D902160E618D97C5CBCFAF52AEFAB944F0C3EFF2F9638E7B01F3F3052DAD9BD37DD0D798EF6CEE85BECCCA1E422187F13F9F192CA0C32E6AF8A00ABF8282E2ECECFE6683AA1DCE34A4DFC33E9E3B1335F6E4024ABB2FAE8AB889E6BAC1BFE162AC9DEC3CF7FD50396CDAA8788533222F0AA64F0F2A865C6D9F9304162E565758D1A050B4EB7D7970113105DF1433748AD141A678E08D83D730BD59B00F793A7C3C64C8773BA32A6DF5733FD4BE9A14E758227F6AA26363E2D51E8BD8B0004BF39BB3C2CE34C6FFFE63F42DF9758270BF7A9AEB47333AE909905777668DEBB217E20281008040A0ABD437B8B6A0FEC4FE7D8BD48543EF3BB2B9FF228B102D624FC8CA9C68BC360C28FBF8CDFAA7DD018F563DA0F7DCB004B76A1D7BFFC2FC524E2EE6E3B4637BF9B2AD0827BFEBF5D01C718721AB43573F0D3A9CBDAA9038A306D59B9BBE8B00611D66127F7E0F21B5CA8AA1863D3ECE580BC08815F5BFD93E0EFDDE90CED4B0DADF46E8150BA2613983AC27B5161012215176D3D51C5DC743D76DBB3685BE2330C62E2331CEF16F652A922D22E98538FD284A2CD1377E7786D71BDE8AF6BFA96652C311FE93B9299E317D2CE42C5546B08EEB2E36748750B7D518B2C017CCB835DD5BF949DB714D6C917D5503E3C68D09582E79CDBE87C57B789AD66131CD78DD0831E1E1881001AF28C807DF2EB7B11154683A474BA1999542CD44AC197472E885EC4DA0CE132EA9435D1AB6747F22C2AD780ED40614D68C0997B69BB6ABC6D0E535D089A3EDA8C93F40470108B8346F83C293A638AF842212B4145D8AD7786832DF3D2E79423459DECC8BBDA651481EAE189E2A7DEC61FC9C2AE0D0F7F121B2724B4649C6130E68AF55A3495CCCCA7FEA41A57273637AA16D0575C107A1981D6113D751AD132418739CC46D132B0A09A3418349F40DF03E490FBA372834622B753F77EA62AC83ED27576C8CABF3745F9CA6405879AAE4C2B75F24B83FC8266A540D2027272859DC177771EDB688D80B9A3AC70372C0FD4926010B993D26E77430D2F1599FC7F45DA4DC863EA780087D10562191FFA27AE8DD2B3C2E0BDAD093C50D4A3C66FC4FA0E1129FD1E237263E5141E02FA0C3D5F091CB2FA05D75BB53F1152F0DDF7468F399AED8BE3CB521F7E4C87DA85ABA9D82B7C2D2BF7C1B992DE4A281BD357A68EE0EB36415E3D7A9B400989E2223DE1D2A0A8A862A26682FCFF79BEBF4102590EDDF55CEE5E215990269A24E2F89FF0E2138C93BA48402F8E00CEC0A3BFC8292A024A2A0593969D39A709C757E29D3D15F3044B56C7B56B0DD43B136D2AB5827428C3601046E60D38AC97DF1329757899654D8A732A274460B8055CB9CD2E5B2052BF3A18569C15B49D1AB3DB1BAC322F7C3331AC9FFABD5CD9A46D470BB3CB9E2927F0FC8D8851E58824AF8BEA08C0591E5E1B488D5A0DCF53ABAD551C4641CD335804BDC6755D81D404DE861482BA215153707633610863220369080C7C7F58E96B3F8C3BCD350A1E918AC713FF17507C509C745771EE1E606759E79307F07D2E8D6FFEEBFE35478E728E1FF7D9A5050ED23518594B2971FAE52CF7CB5881AF036C00FD0CD68980BB89EAB145A26E4FAE81D873B0CB6AB6A6FF7D601C497208A509A4951809EA8F09D2907E91662C35A327D8BD3D58068DED5790E93732FE2F3181D7A794AF24EEBA5BDB8DD1DD8444DA7B344B9796FAC7BF28906B4645FA7D1A0B90D71EB2FF2258981668B981A781233E6CB56C36E2ED23304A42369859C565CDD60DD3450934B7FFB72F5B4760AD19374DB7F1604E32AC1B6AEC493D500EAF70794FAE6DC46CA436E7780617A82E07699D888CA62C81681D3AB3FE14D5A7678A13351DE2FA126A6E21E943D1C2D548535212FAEF3719CCF58EBFC1199CC531B08B69F9E13BD01EB439636AF3FF17C4CE47609EB00D63EE40EB8164D2947DB27F17F0F4373AFF3902DA8CFA7F3CC0B9EAA00CA079D8F8037A54BAA3580ED2D7686ED07700ADE7C8A0F901048DA48BD9292A86C0C08F343910F6EDFFD238E1A7AF05CFB7DF7B189F1A1AFCAF199A038E7E8E399CE802F8E9336615ACBFF02BA2EBB6AFDD3263F923E03EA95FD66FB48B625E23825A82B96F2F34E4A9337F5DC5C2A9B8D54CD0A253A0DD4D2F363B36DF2F8E12D425AD555D93631B318A2E280B091ED6CB5AC8C7501860F98B00B4C04A0CDACA09B822E2E523EB48300E9DC1D1C6DEA15AC88A253936049C61DCABFE97DE0F0777FD121CDD7EB2E8A5AFE24DEDE85BF58BB4539CB4DE73E47E8DD04F75549F5FE796DAD116A201F9A30B2E172A7261016C1ED52E93D12B5E19BE27505F6158EBEFC58934FBC77CC042D0A6335E8337A67CDD3787DC8AF52238AC2393F290F7AB51427692710F66E3DDCB32C97CCF8DBECDCE1CAC7086D1B788866880C5E03935AEA4D8C5BDFAFB6921C2707E33967DCBA5BA2E2BE11C6D280346C71360880EE74DCA6E13E592F9A7FD4A3842719732E12D39B77AFB98C081E17B98D2249E3EFD9059775F5436DEF5E933CBB52AC8779AD6D756D981BEAC0C6313B7A6292C4A955512BF109C036B4BBA9EA6A8EC68F0DA9BB4284BA6819246EF831CF6F7937C5186423C4FC3EF088925F720573CAFF497D4665DEFC4165491AD39F52EF5F312371699D8E2F710DAB6BC44C5FC6BC0F516477933FBBE97E377A5BC1A9F0E6A2E07BCCF52246AEC80FE93D20B97FA3986C04C172CA3D9D0F1711B1C8784CA3B90882A54EB41695E82843F134D84E611DD7B545394185272C2026AD97AD473D0DF3D5822D80D49D544F0C60383FC765EDFB2391016A17A50A79B42E6FFE3434C787D3A28306536F297BCC507C04D1E89FA112C6C5BC7263AFCD83D0EE7E1AAD658DB9884B87BFB255CDEA04CB51B624988BC2C295828EC361E985278A0CA67E29BB7B6517599BEBFB443FFA29D679DE6D06FE0AD16E3F9DA84C04895E4D8D7A60C46FEA0CF1B12A43322C5C5D63D36474A391A644278F12865EDB9B0FDE27BDF80BB9AA246D674B2511EC91F80C2F4ADAD78DFE46DB6473A29050B22C2C3A26B645D37CF46F41842433C9397D60DCFBE9279D2239DA5A8CAFCFED18FC0863A84BAE65F200EDC0FC0B2D7ED933788AF88B1B438D86FA6E021C6241C2EA2FA4AA051910C1C8097EF788DEC4872DDFFAAE22E9BEF5F59B26F8CB186F550D70FD4171802039E3F6DE7745F039517AB65AFB8CA6988DA657688B4BBA714CF2B67433DC7CCFF0186536436C8AC596784DD42524962C7B875D00DF3088BAF512801D14724D438A6DE1A30D3C8326E51F48F97C9587EA94BCDAFBDBAEE1BFE670CCFE4734E14761B5AD58928E7AA19384C73A4AD1EC7805F81D388AA40BCB97017176C24BE9D41C1BFBF17FD980DB4A1BE29ABA47D54E52A81D6BFF22E53CB00B03E1057411949E91A76DC795BA3954FE4F856AE96CCA718F06D61DD50076581C0D816B3BF9CF3157A5D2417A8D4BAF0C8A0938A0BA05361644D7F019C9724DC91EBA44801D6B5BF2476A2D78C777148F26013A149745A8BD72C680A5406BAD3F1FF6B282636F74C5BE97982B7A5E403F1A54405C1E4C65A2A37A9E66828CBC1E8F28A4B29168D0F1F87D85D06D48C48141034BF5BF2DC816455979F855721D2A50CCEF05FD11331CC9DEAB1CB5A719E2B74300E8D4763BEA1557C50E053E8695F19C2497A94C389B48E0A218BA0FCFE03105377DDFD82BD9C305D174243C13F9C65A395AE97AC5537A324CAB3C5FFDBD55A6ED93802032893439A383359487E37FA501A0A030C4F9B58D21F9096CFA6F46F4C401E6506DDD2D33B227E63BF0B1E2A6757BB9B014FA63613FB91DC6FBF4075EBDF5EE7358BBCE296D9904BA67D6368AB7D51C21CBA21BB57AE9EA27359282AFF595719E580F00F931BC49C484842295953EAA582716EA1ECD3E5147FF10BF695BD39BBD2E139C39823A69E61948FD527207565B03B20207646B8C16F4DD98C716CDCC0DD49FE4D54557F51B08E0F98F5E8486989CD06B8A3725AAA5AEC08ABA355707B7A246AB4B21D3C316EEA16C3EB3B709612A9B21E2FBEB779AC6A7C3FAB3B3C736EA429E9344842BF50FBC9CC4DCEC8AA71591F4D25CA3D31B6166D010C5011BCC24CD1C88664D93B14D9BAAD1B55D80D524BF47343B2BF50063F8B9EE20312F57E2BA4FA6A671DBB5F1852A17912BC2738291B67778E10EF124FA97F7D62E78F62A1614911580CECA6919452C5A009A5DB70E18E40DFC358683EB738E635DE5BF95827909C5A8D4F74D587B0CFB6424DED590D60E20BC22F081DE0728EDCF8C1086730E3355FE90D7297A89002C637D3AEF1A252F11A150AB581C4EF394AD3BE7FED4B6AC0758A03FA21A7959993F53406F1A2E1F5A78141E1EE9BFB211D66E654FF6C8304E5644D739AC424FDEB9147BA463BAA80604B338E378AC3510A05E35E3224796EDF9F38090358631CFE82B6C854227E98A86A1EE5FEEDEBF6D616041D62347DFD489AC7BCDA0582CDBB08394BA518256E8885F6B2CD4C53FCC1BF8EF3A8B0F2A6929AA02BDA27BAA1116F7011A074A8575FB4F91C04CE84693F401A05CA9FA5EEDF9F410B1515CEA380A0327C144DA4E87DFF32132A51895E8FA7B11F6C236E56278CC37B23CADB06B34766A727613998D9F2810CD1BCE5077CDF7673C4938EC31DB05E28FCDDB2CB0455A83B4230866F130C818601834148601014040481405FC323E72BB2369534F933EB37CBE45F77C49EE6EB27D67987821A4272DDEFD4571C0A03C6E4E037BA6EA4E443335F22388F7863581CA4A5E82CD6310386886CBA98DF7701F613EEEC690F900A8675168D156610CDCB0E0B0928162E21EC5DDAE6002B31BE1BBA3334E8581631D7AABDEC734BCA816DB27D412951E0CE501F303FDCE3AD26D7336BA8CD4DC20F3CBEB60D476F33F528EB8040A91AB05070014199DA724D2CE73484A9C5A809106651AF6968E8ECDAF1CB158DEEC6EC8FE51D02166499ECDF55D78A5BD84C7B058FF599F6EE41DDFA6BDD87501FD85935DCB75AA73C4F2F2FEDB02B187AE39612BD097A564E9ED482A8B0FEEFD86BCE8B09C97A507CA919AFC7FCA3917095C7A098D501EE58CA266E98FD911F6A20CEC1A1289A5C08275105AB7FFAE7F068A4221B6B5DA9EB2789FBCF7AD2BECABF3F2E4B257F553AE5621E55F269AFFED73AAE27078140205EE111204F626BFCB1800AC3BF3193F679530DA989CC9205A30D5524FC43F8AB2C5B54B0D8A32E9380102B6D722F17514FFBAD221B5A031763D59CBD717F3F9F39265D815C1CC52F0656C2D2BB9ED5AAFEBA80DF5625EEDF49A72FBF0D1AD05A7CEDD27D0C5A6F86E9591EACD6DB7462383BCA1565CD4DA6368F2A42C6BBE2336B4F20ECE370161BAAA5471F4C5A07C46927715EC5F0239BEFB02839420704EB9BE14F874010C85BF588662636C44F6CCC9147AAAA4CBB791D33EEC7D6CE05AB1F3C337A0A94AC6721656673C2586592054BF71E1363FB388B4BDFD8F9FF08EE890227E6273695C0AC58C08771A0C38D87AEEC4B3DE0C8F533526D56A922B8171137056F7BBA93DD5B06B189356C73B7B9331561B6B01B668053872182863CC3E01ACFD6960AEA277A466ECAB56B39067AC699E931DBC8F8DDD189B5AF6D2CD9973F1FE557A06EE8F2D632656524F5F483FC0C5BE876F9EC84F6936B59FED12240F2B99195E7FF2DFD22134DB0E06F83D19061F289AACF7A220FF4BE82ACB17D97A43D020F7016E4B49593D5FFC3D3EAA0FE3FFBBB47B8BE972A61227A5D488835769CD1E73468043A8BC3F7280FD2A883CB0D1AFC82A9E21D491320932CD5104987464F457B315E7123A6D933F91F47AF3258216C4A7E568EDD878113FA6E31EC1DE45639D256EDC4404781B65194FB9F47F13F0DD92B2C62B309B017EC53198568B830C6DFDD84776F69BA24099DD278F4030B4B630CCC88C963CC0BB953BF2F1D3C588AE32FA1A7585084E18E7DBFC078A3180A039EAC92F6EFEE865A064AB1F82A0E6D1E3084BECCD0463D1DD27B8AFEE30C63F20324BFA9AE1DCD652C5A1AF749DCB652DDD477191B8F52D8765AB8260B927C7C5F058140204F4F33773030F61E3D91587C9AB1A3CA483B52E51DC5B63E6CDEFCD7FB8E6F9B5E0F55D2FEE85A890C5318C3697FF7E08A0478E65E0426600058D1B75BD13BDECDF9D29629347A9FB2BCED35BBE7F2BAE9BE769D71EB61AEDE4AA93ACE1054715D8B42955C87D60BB27264A38F8BBF96C720E1C6A7EAB4B78980375B4CCCEA7C55E5D1501BD3979E0615EA3782DA5E7101066ADC7E04CD14A211690B3FD4D39B330AB888EFF321961D40598CB4F0CC3A77FC02E045153803FE1285399518D5FB353EB7AD7CAD295D7EEA81C89A48E48D1716BA769538C1F32C9A2FD55CAE99E887F6DF57BBE8A225CBEAA33F14E9BE0963B4ABEAF1B36E0BC12BE4B16E8D6978CCE491680B55F14991A033C69E90CE6FE6F520F7BF89B2023AB9A5D3CC9C50053FBEA9C623927B549CB5687850753DC1DE5ECD4953E6311177C374A74C6DF3326463283174373D3EA4F5D48146D554BC29865F2475F498440CB6813B273E94C1A1B14978BC0CA6BB5F14ADA0BE44536E5914636C72676E2F25193243757F8BCDC09EACB651CA0F1B2512C0C0CDF8D34AF90F2C1DDA8DC39754E43B5B2F0D392666841365B78220B106E4DA5420289401EB89632A119754BEB0CF5AA77B22A2649C76609AB1EEDB1F2B6B9841364AC0EB0BC977391AE79A111AE16C7CE89D24865B790A8D2FA11B6CCD8A4395F421413716C5CD4570D45BD011C83767B30CFB765865D45ACE80222646FC552F077F104E4FAA7A2640F95C700CAC0C1F0A8917E7464FC4B04F11154360E01BDAE0F4D4C8B0CD37A3F70116C4AEB65D8DC4EEBA0F39CD87389AEB3350AF17602C7DC1A97F5D8586693161FB1746CF8EBC92EEF2066FF18743426EB95E8EE31FD88B01CACC6F6182B4AB422D7F85A7BCEBBC9F04CBDFF6CC1D7FE4F3CB3F6B0A7E00C2E440EAD7B9142BEACF6AC0FB0BE30724CCFB51A3868596D1637B2B550C57BE518CBEBDE364B9E24D654F78E0F22939C5144621BD93234E7970100FB4ECE4B85D3DCD5E1E13F11103708B64FEAA1F0C56B727A36A4EE98BF38F11400F04B71FDCC8C38BE422BD846B0394A7E766C2D0A553A4DAB84279E307FECE9C0BAEF9176AD47B3D1F0B8B050E3DDDE0EC18BA73C367701546AE69892B5F6CE410526B9B04F6C4355DF31B3A9B46ACBD31DAAC981DD28E9A88D5DCA66907AC5CD21455D9292D3780767C3265C6A78ABC52F71D93A1022354CFD5D992C23E4DEDD2514F6D77AA7C310E3C52761C3D7F3E47457AF2B05DD4F1C02FF4A4929DD09973D9370315F2CD7570D4B5A80A50933C5631BD3DD94451644CD15DB313E4C36DFAD684D822A07D4F46AE4D1FF051F1DCF8175BF58693AC25A008278C536D330915749141E790044824EF7E76BE41BA6512FE1DD48B5D8E62F3EA3CC131E757030D97CE0FCE0C878643B355809915D454C773642694192A1EEB793CBB951939E4E77015F214B65F6D43D81FFA0F576D0A16BB95D1447DCBA6DD81733F06A0BAFEAFDFDC2F886AF2FCEA1DF8F3FB9726F750C830E829F026266C22CC32EC0250A332309BD4139240ECFA26BE32DF8FC342777D09BF9C7E8D999A81308969BC2A8CABB699C4B9F6A5142DB4550487A4FC4AE6EDEB48F2B6B52A8260BFA6F5DF7B713C1BB199D60A5EB4A24D070D9DA46F804466B03557D6D5578CDCFC9762E63EBC3182E2A61F12DFFE7473319913B55F9CC26B996332BF8669A4735085BDACFDF46F1261675B862AD831C6D0D2FB2DE7ACF7597688D386DF2A444E5E6F181011AA5AC6CDAA34481FF8A242DB4F544DB63B7885DADA0D19C58ADE55C2FD72E2EA8E9423C9BD337253244EFE97836B1C99522642297F10C6E170684AC28782D1E429E7BBE7699A5EBFD4633BC081535AA4D6FE7A9129C5EFF1CD4BD68959E4796DD8BB630CCE585CFB5B4CFA23DC61668A298A4291DF1E9AF2C82433264EEF9177FDD5A7EE43284FEBBACCA104C3BEE77050E95C59540981829F2792EA993F548A474742CFC45A00B07148605D1BCAAC135AE1CBC8F65164957A400484BF9CFD7544D5F6A85441953FD11DD6C3E83BECCC4161B4187D974888012E77DEEBE8B8C72A60FF62D65EF8FE1CD3FD4904360C5AC4FCB32C319FF3453A0508106C86A088D9E763F78EB3EBFF0023078C6A465F30C29D9BF5F7D626D6E2B3910EBB9E0EBB5C6C1ACEE97719FFCB648645F0056E970D77C5EAB7F2D54AB6B6AFEDD218A47510F8B0B0D6B5F36FF3518BDC22CA860B879E56653A194BADD65A03C9AEE3EF309309034CE22DD10D50E6F834614D5461DA2574FDA2B1E1498C6CF900E3EA2D457F8025086C23AE8A15BFE225F30167EB0C6A3CABC755EF052EFD276DC41717FF0E11B184B1EC569A41205A47A572C53C82D98004C8E97219A3E731C665E8DACE6938A257051226491F5792F46748FA38957019B70BBB94DECC8390644B1B3C35E1097732358F56603DA0FD1C6819EA651BD3C3E8050E560FA2D472F3F1B4B2A114A4740AB0B4F1F4F2B370A764A6947071F371F55670D5D192A614A46467E5E0E417E0E767E748CEE9BE40CDC7FBF76F9183878F838B9F9D4780838B9D97875F8067AFA68DAD8DA7A78533A520252533A5ACB3859D17A5200733A582ABB78D9DA783778082ABAD1BA56010A5924D80C28FFA5A39289929B51CEC5C2DBC7D3C3FD9FF763394E2E567E371E55551E354D6545170F562D2E0B2F475547155D69262E2B3B673B094E5D1F63130D05273F456553390503150E490F6E7F590B117F0D4709175F175525797B567D775E1F7F7E7F6B3900FB456F4670B60E31450F062776673F3600B9092320CE0D06192659231E451617390F5E550B67634D4769193B7F7907070D191F4D074D4E19276B455D17171F69094D29171E690D7F6E550D2D5957770D3F1B4F673940B90D375E517A10C0E062D9CBED250185006934C036DFF54F639E4A7AAF005B94ED6E7896E4B4A59D2B5064F937B4FAD1C087567D5A32420EB21C9E2571F5C2585A79D3582660FC3718E5DCAE0905345A9EB4672BD84A22C29837813B5DEA278F79BE8FE07CB234C86D3CBB45EC566B66E11E5C5D0D7AFA9E86BD323A3EE7148D105F0D412DCDF8E692F1B0BE9ABF42F2614FAE2990876B4B4B1B3FF9B4FEFFB13BC42B5CD247FB8527EEE259BE89719D7FDC975C257905E6703BFEC2ECB2FE23578D59490FDEEEB28D7B0FB95B77F23536001E80C9ADC399F770E6064F6C78A76EB6C1B73C72194FEAACEA308E8D336F339E185B2940C6C242596DCE4DD2FB760F59B9FCB09CA3DC2D2F0C7EBF7FF8C6FC77C7F5B83385AE17ED7D2EF4B8100CC53AD65F53BF4EFBEAC3844FA7FDC42F6F975679D36854C363FD217A5CADA865DB529585E74CE21DB1A37AFF5C7523E87CFF10DFEE023973B39510EF14B01F5DE8F1F8AF3D3E9A4D8A5CE0B8D1E7E2280BCF4BFA06051270FD38FE082D63BAEEAD7C85F22C025CE491E439BEC048CAA8F4C9EF3B945700847A11EB544EAF14A40695F4B181B5FDC059580AD895A8E7EDB70130517164F0602B1FF065DBE221203E03A0B831CBCADFEB8B546326919F56B29E5B4D7CCD810EA7947152EDDC0AD39008B066BCC0BCDA8663D55D782E2C757E15FD1C1ECE69A77AC5FB9E44C9FF834DEF87AC06DD0CFE0A648B0FAFFD3B80659C6473372347284847583A58794920D4007101B4095B7B7FE13A14152ED397C4DBF6156A61AA4F5201CD1282B279B0AB520823CAA3D8E65BBF282A6716BE192079DA523755D0A89099A287EC4AC39F2DF8C7EC574716E8FFD3C7DB03AEA413F5B46E336BBA81639C0B5F3FC1E6B59B40404F327CF932ACAFD30D2B9ACB69E0A481B9FDFE4C8FB7FA2ED6B453EA1C9BBD94809F8C3E39D785EC032BCD4603A2BAC084CACDF147F5FEF7A170DBA3F0EB14414BB59667936E0677757C7450EE54E76ECF4356F031805532C0C81817D25DEAF7D74A4E7E1177AEB990107AF56052209FBC6ABDEF7A4E4B38DAE030280888EA64E4E8A7403E65DE488904ACF09AC60686F948D0EB23042171F4CB151CEBF593F56EAB4F3BC62DAD85DECE126E0BFA53183E7765E710C8C59651243CC4D6994B8CA7790419BC2C42E5780D1F937D2EBDD194A7880E7C923239E6076BD44FECA6C8FF9AF4A7BD06527BE19824872B9470733633F1C670F1594A58E465BB241C36F1E09D140E09E6C9FB1BBB9EF5F7821D6B194C2BFFCC964531B9642A6B2B67F4DE9F21C00C06F55B370AA16D1BFA8E8EAE21CDF74DCF2365AA4231A972E8EC1B6E293220F039E850C5B30EC66729054DDC15E89AA00C1D26203A8928198BAF2C4F5FF6D223E7820D467D01482A5A7A57F10C5AA0FF79FDCDC8F8C1D7D0A245A52BEA2AAC4BCF6A1E79B17748219DDB900484299B5A0694C2A5FA6152B4751B8BB1FC0901E61C4C5CF917A83F2D0EF9B308CA448239047B3F8BFA05E6E11DB704450A3E20E9B052B0BEAB6058E4ACB97423151AA3CCE98D2E39B202FF64F9B7FC78A3FFD25BACF8B4418AEF1FB8CC2029B3E3D00EB52543B764B5E6F914EBA8EA53B7F97A75DE4D37BF167BEC0A49C38DCBC23B81B3565709BF3DF0E5CC49A9031990A5E3BE15FD16F9F0AC33CF4A276C11B56611657C1F587343BCBA008E73EA532ABA9803B8DC58B0EA4B734424132301420CB4F96F2D8071C05123C807E067B112EFF6EC0D612BCC6E65CF34CA52F93C38DC551D66843EE16CE98C6101E1B7B313C09C0D0EDE1B6D7E9E6ECFBC66B98019A32127969B35322970EF982F6FC09A7B8E2007733CD543C7E3CB5A8A63C0AB0E88794D2D3AEBF45620E0BE58B38A84E339DE7CD970E63C5C8CD465BADF8FC4837FF7115E8637E9C2B3E0C4E021CA1F979CDFA4225AEEB2DBCAE124161015F9C82B179757898293DBAB060884A6152DD2343B91B20923FD3DBC53001202B6CA54851100D1C25D00AAD5326804B4842705D841331E09E1C58657D06B72385CAC3F50CD517004AD3BF38C395067C3589E0813B8E03A678499E18557D79E9B2B905C4F13DD3AC0C7ABC5A2CE7C97798B504174D418039F917689AC451D875407A7249DF3F231C31EC9B6EB972A29E14F869B8913BFDD36C14C506E0BE5E01BEAE4272127498C43C05A708E95F962690A7C7E974CBFE56C0072A4BFEFAE1F83C173F498E8AFD598B76A6A863B03F44449BD6AD9C36749865097BF9C559DB4F40032A0B96ED5259865AD3F2DBDFFD1676F20DE2E6B1D2261E9B4B5D01E3D7521B54A4F314451AC2EFFF8DAB9C409823E1351521422BB6EFDAB30E08AA70E60E7FF15F16D27E07295B58AEDF7371120DBCD500491DA6C526406D46646FC96F660AFE2293C5084D7E8F1385CBA0EEFFF7000B6706FC115EC253B588402C6CDE939BDD9C2C2FFECE9BEE7BCCECF20F058EB86EE8F2AFCB9A566116FCDA1F1B0446EA425E8EA085B3E99EF7A777A08B0FFF8D70A598140BF27840F2AB2C1F6F566058B6F02593AE55E87F2C2C3520813DEFA7FE37FF250D14D51F9505D8E796C3673AAA7ED356BAB8E40B7587107BD23AD47F5EFCB99F13F7A8869A2591DB47D1D83FDAFABC14EA67869994FF80893989BAE7D1E1B8441676E2778E09D7C292BA08223070FD813A325E3A540B88297687E4557F5669D8B574605371A0AEE49C5CE21EF0C45E3D99E48664B5FC549A10C17B529160A298D49B45B4B64CBE80C7347B07186C76B1A6BEEC7524E9CFF0AA462B81A19775B9B172B2F16FCD18DD9CE8E2784CDFBFA189A2010CF88E91681E0E79F65564BC6E8E3F26CEE5361AF8352F246F64491139A35F8F5B00664364D95BE14FF3E37D6829A7ED787DC4D26EF3B7FA8359A26FBC74440CBDB8E292AEB2B0EAD980B23606301057BF2AC4866E9786D01018407128545410EA78BE8C082D57E6ACC0598297110A107D67E8518EF89153F2BD83F0A31F36B91EEBA58B5AB486A7FF2B8B880E8AA389464057CE07AA877EAA89C0EB6C894C07507A81BB768987FD4E101E10D75737B3BFAFFE6FCEAA293AC8F14696AF39B295D6D98B3527C042914CB2D5C974EB0DFB22B21577F445F91A09C565152842D17032C480B9C1347ED035BD54CA1E9D980D70961773C639B0440BAB5EA73B2896299E2CFF4B9F7E56FA15C6B2BE578BE3EF99287B2F80B2B40C0447F4EF4161CAB7F57EAE92AEFBB6D72C855CACBA38DE55123336F4712B7C63936D16843210390304F6F20E5B789EF9B0D147B6D1EB1F1D6611AA4FD67939DC89F1B54E6DA344AC419476311B6E117F45143A2627FA1BE66B1BAAA4CAB2C3FB1690091DC8251FCF7923A6BB9345D00E373B45EBB0C30F0DDA888630A0C6A8F4AF7AF6F520ABC316F6316E75379D3ACDCD3527C5EC934338D3CB93E92660B9E965CC853050293753E6F67ADE52D2A60EEDEDB47022786A49E5565B70AD3DB02B30655FE7A05A06A87D3EEFD0FD457AF068F185A670C5F2BF0D20B82E6FAAF8466EFF2BB5E7D2FCEFF0006A3F8B0214D558ECA0C03204DBCC4E123F82DEE267064DC57EC4AD4861900DFA15A48FDC4195D597D1FC88BD70FB7842A44F84F565A0BE03507EFC6FD2A17030797EC939EEC3329B4F0D512D6B7EC96E4F8D0788831A8C446E02AD0F35947BD2F315EA9609A875C659EE97989A15680270FFF07683B5038618FC8991E92A62CAE7F553FB7AF5BF23F27970ECEEE8055F754D73CD9A19B753229E89E21D6C214301167BFDCFA54BB8AAD2BE849227D9C953733704AD3C6EEFE360A1919E60294C3BD8654ED9B70CD0D8A7C6D0E63141B43649588DC20973BA9E189C76EBC526560DDB4008C68437922441FA58FB540598AF64764C63A6E45DD1483A7909EC462CE3185E5997E5ABA9104BD81AA58AB2BBE16C67AD2097619720D1D32892F2231F2A197C07DB375A25D0E5F1855D8FA5C45DFF673751C9E429D65A9FAB35FA0BF02EA451FE1E52EA132D2E0CC75947FDDE721CB306A47C0A9CDF803F7BCB3A19E1D9401C5785CC41A0C432174F7D1580FECC876DCDCD30564A110AE60AB894ACEB5880AAB39B5D1C89EBE2230CC89C06A08424173ACC866CD5B2B519C2A78889BEE311A3CC67AE6FC8513B03B4001B4A6332CA14FF9BB1D760873E9162409F5D6FD677F5BE3AC42F73DDACD1B199DD488D3A25CC2BCA408865A756BC20C6E801281F32FF5FE205B61047024A1E51EF558053EC7A4433EAC0F86F7F015D379F47252A40ADC25B86D428A7AC44FAC6D40DBB2E8E3A41CF5411A1130366DD3634F8E7DB207793D0928AB93BBD3998BDEDB4E4675DC60F343C6E70E7743ED4F8ED13FC55C8D3E13AD16EA0628D36791E7814C10638C23B570D7AF4FF74FC0C7FCFBDC5C93F481578D463F1703020A5175281D627852BCD9339ED4738B16547FE7F839A941258AC802BFAA7D0972B86782B3D9CF39DB4ACD47D3C279CE05CE67E80BA60EB079F32223BDCB75CAB2FCC8E25322E67CD16A52358467337DA5E1257C8430984FC1C8E20FA9D2220F24FAEEF702C421A7942AADEB5DCA136E2292DF9FD024B5863D64C1851C6361E375E8AF4717C180CC2C330AE495FEA0BA2010CEC55DE56434C3283FA4E595F44957FC4B4EA71AB8A1FFD8349BF10AC9C649CA1038830151E95E57DB6345D821AC81AB63F0B0C292FC2074D1C5EFF9AD3B2F169A3E02909BA4DE8904D7BC1D00DF4780F3936C47DD33246220BB9E4CE1749FDD0852FE10F55D6A4F9B06FFFE2DDD3D2132817CBFAF49D411BF806F4F07A85E267EB3EFC65E8C29FB8E0CFE31AE5B2FF6974B7CABB2E4ADBC76D5F168722235BCB6F8E176070C4FFBB2A79FA5675A5F1E519BE901550B05C79DE9C90CF428D435D28BE9E5271879A68EC73090EB554ACDE2897FA67EFDC67606462EF01C9B10035C8F186EF7E71FA8DBB898D8BEB78BC8E5F957AF751386ADA66E4B5933E5E5B077F817D0568D2912232C7617B4C4C882165DE1085DCF71110758E1F7726B854F25837C6FDBBE17103347FB6D9950D4241BA1B1251190D3140ABD2514D7DE89E21EE7AA7FD10F1F56186EEB40AD160C123F8593A485F817616C028F89E5CD941D31B899B63FAAC8AED7544057625AE467137DBDEE4B925D2C171FCE7476CA7C9D6CC0CED6EF68C8804D31F2B730A1DEC916786E31018C045D495993F111A2485F0085717E1234FB59614C8205718B10820B21CFDFECA536D9ABECDC88F05A87F23BD7406DF72A10EF1334A2BEF99CB62D621AAB2C254D0E1299643F226A280290CE79651021DA973DFFA3130253F985CA54E882BBE7776D783F917DEEA50F5BCCFB64B16230A75FD93C30FF21F4280F6197154923F0649E6C45717384A22F5F24A02B2A293DBF1189946442A83497827480AC3A26C37C386942A914E59A6AEADAACB6D84EB45B91B9EC4A36640E7651415871DC5DA5474248401D14876BDFFE88256053C7F6BDC57DA6833F70E6B36FB46810346636A9F0AA8CE00B08A4EBC41ACD03E16B11271911BFE157921C4EEA7E907CE43E197A18D9AE1300459D2BC04591AC20E4B267097CE0D54872264245B223BEC8A6C912D756866C24DEE75FC4A287CC1001895A014FAAF1BA983D84869EBDA58DA18237B8216AA5B8A16A8DDF831AF8C321A703F77E82717818BCBA711DA4F2FE32FCAD1C4169473847FCAA0F9FF82D33A1C8DCB92189C4C4C7E6F1F64F9A983633E27BBCA61F68192BFFE6E25071CBFA9AE45A54F1030500571D7A1D5A500D834FC2AF8FDBB2A2332E3C2B108D470E8EEE151B912FFDF5AF7310F0B91DF4F2881749CFBA5355F1F725E6F283F520219F7AFB7B074B6754AE4E0D974BC4CEAB69D0AF91955BD4D2EE54374E54CB616BFAB535E12CAF956C97654BD031840D562A5553E78342EF8EA040D0BE8F1D05B7F2B5BEA84EB1898F11855F9B4F202548BAAD73F7FAC52D072F161B1B5EB0A0B9B0DE7025FB756E864CF24DB726B05BA119A3886F0253C170D2FCA516783C4B7BA1959E58C9EB0A86D334BFB213040117D9AA606B92F9B50956025C22CD56FB15B76255F32C0F6A16E1FD5E8C66E053CA42F82DA8510B24CC92F437D85E80397B8ABC3E879FC6A504B216CF02991F781F9A7C73F822CE24B911A9477AE20898093BF644E0D08771C224FEFE76F67398BD4FADE54995B57932654F717908AEEC69723223D120071DD7C3D4CB6B64B2B64664F14725F12F86AD4E6F80D56F7C982863C7D3BC6CF28F5FA65FE8DF64722D23D64887EC80A9CC1B35292175F30D4F45C2B6E1B3D3119777354C40C85017CC1BE9722CCB5A7D5F8CA4BE375C59CFE7C5F34B21B2817F699059CCA9A95848020469BD8EBACFCFAE4599B8B111A4236255C6EB976D5CDBCE2C4F6AF383C403636B8960BA068834830AD5B59C6E81068937132BE15712216AD4D7B82B0E6B7F44B14E07D13E92E8EE45BF6A6BDC40F30F094EC21E168004C9F960C936D86D4EFA67B72525DACA00355547E2353F42264876B33723D97DB474043BA215D15360D920639363CF93AE4A08373578518FCEF9A119FF30FD3A5147160EE49065E76669D226133246D4F111F6496891268523FC9D9AEB8B838C72E8E44564C7407DB7BF27822EFC78B1647E5FC17FBFC172EED40FB68E1EE65E3D88B274FFB0F40CE165584A6E96DB9680928A80B81C1B3F7AF92A7EACB251EDD5B37529438B5EB864987BB97482AEEEE003934FCB5B8FC615C7A4D5F9F677DC6A0C214E98D67674C410A21F657D3F0C7FC1A5F18DD5C2200B4A06F3515479E16B04ED5848B5AB50994702D2C9156711E1005CAD83874BE42B838ED93DC07375C6D3B8A84680046A659F59FC0A845B9DA0B6384AC77034A0129572B05BD88B57B58038D136F22C0DF310C35F5CD05662CF962AA9786B94A8BB76B2887A7C31D9CEC50392B95E78E27D1D74CB1096BEC31123E9C00D3D52C58300234080E0A02033BB430B8C298796D761AA7FD597E993BFD2D8C042EE8DC8A62D7EC8A767CA55D35BA1BDF1D574E135AE70F394D2F53ACE8B470F79D46D524D49F0DDE3B189A95E439F7539BA2D0423547151F513AF74B6C8C871C33CBA7DF09DCBC925EB3412CEB40E0B8CBFB7FA631839FD9FF2E5A4745BD21A64DB4458FB9DE03CCCE12D9C4B56BB58453B849F760988E856B8A6AD1DFB7BD9A9407860937E85A3711B115003E78E81B661A5C6655F1325B8ED038DA3B1C699107FCC2D25431BD8A90E46F100804D2CBBCFF5F367381D71EC99D011B63660E8146C7B04E6391C70B77AE2DE9137566525A1CA31A95CE9F3959963020E5FD5731DB2CB98E605546E9E582D1721DAB52217B8D0F2526BD72901C8656E177B7578ED4D79A003C25D8FE6CB4C0614290C9D705BDE5CDC5F33A05ECDBF135B5DB508B306FA9486EAC9CBB95D3C2AA51D683660CDA400C10CB53313DE0D92A8B837EFBF9F39C94E1D5CBA9F79E7F67081E4D1695AAC4DD16204DA110A753575E3FB4885386CFE1430EA5EC28DBD419CB42C67E030AE1675AC76D04249257300B8B68362A480E0703B5EBE5DA9422104D58BA5EB7FCF91A1234AE45763DF77087CD4006B5849767ED554DDB1C8F5CBE03F37B9B9DE80F74A8452923C60A148035FDC62C8E4476DB0483FF7EDE9DF00FF48D6BD070FFFDB54EF337573E486FCBFD277C6273EAC85A9D2200375870887B8FDD863C2EB12F211382A9435D86D1A86FA6F2C323E2714B8BF4B81BBE684DB410D9D77F39A58CE25AE57B381D6B50F7A81636E4BC5CE1EEF971FB4D7A5D28BFE3F2E7E7F660DADF211D9D200B30A8E251C53CCCE3E49488BDE7775D26EF332F607FEF20D5CC79F7DBE98B3C746147DD67CB24050A627F0C3B182E99D8E500576FF014ADC53252E3986A461538A28C054AD58826F7922506B4FE8EE2FE3D4B17111187624BB5C63D6B5DE932CA4E2FF1756AEFD29A3485C6488B183016566AB0EB184134B20848A2F3DA5DB30164391E19262D068FBE134195F531FCEA812E0A4B68904C49127D50BC127D2121211D463F1D46CBD7FE31CAA0A8324CF270ADEB3EBEDC68303B9290DB6D805963503385D383CE7B43856D67BD3E1BCE22240E150A09ACEF4166030F0643C01030FCA8E71C72061936CBC1884DDD892860680818FCE0B72689060641601AF92447B37268D36736AB52890F8B722C0A37E1134858137E5FB71FAEDB3CADE76221E12FEFB3443B232277E74475752CDE99BDD483A15EDBAE45FCFAD0309C277E3B039A2F9ADBBF74E9D8770989C9AB78BCED6D38CAC7EDD33C8940681010043613434FC2738879218B4885B117448678CC7D860C028140E37BC06EE81BB807014BF3E44A635BCB7E857D02B3896FFDA9ECD694577FD8AA88E23A297FF455ED216960E626427466100C5367CDC2D2BD65A9FDBE3D1F26AA8867BE12F54FBAD7211143D24155C3E57AADDC16F9F6CA72D53758E62686719F181A06040621414070F0606864300801110C81C07C82402010A87089E15E02DBF6CFEE58DCA7A746C1F78FAB69F1CF6C440B4089B8645BD82C1944ACBAB8EF56DB235141F41C286488A3C6D9EF6DA431E480A5FAE1B0E4695BD46288972130D0C0786ADE5A50E3A51C58A22148E2DC6666C7E3B2112374152356A855595FC70F704695EB177C53621BDE2718449CB50FD005FDAEFA49659B3461D3D39EDAB5F7DE0DE3EE87E1BD0561F5DD2F08943F6469EC6B31A29BD394604F923493511C37CF7DC0FBA45882440572607487BE0002D854A69DF62E6C0309AC36A29679CBC92170B3717A2118FB1142183A1F62B48E8DCD805CBAD816A3CE00CBB2F5557D577E6317BE5F2249307049DBE74AE9CA32D412EB9902772274A9DEE2D1765B3E88CD80BE3A8EBAE16A70002BE9FC2CA3415FF296F770FC4EE9C0E9C592DB12658E4C338F141A0BFA191A2D42B56C027B24D864AABEA8539F69BB16854A9BD13AA3887A1CE13238C060BEC5245F712724875F5435463DA68665E8705C2D7385814100C14243C1832170AC38EACD8AF6691CDFC654727C0757DCF15D4102C7F79AA11CBEE489749E0614AB39DE6031095CDA1B7C561DEB32AFBF251D2D147357D27E911A3AC9FA95C83DA02ECAB6B44CA76A084F12FCD68919F133692B34E10178A8B75B0337B06783EF8132DFF446BDFAA2245D8CAA00C5BD8C6E4570336AD4BA649706D91FAA9511D852542F3306E641E9CC6412AE51E4B7405DAB88EAB7FE5F5BFE0B2E254A7DB44C5CAD732A6BAE1ADA37201088977E1532E402D6E4F03EFCF588CBC49FE7D3E8C5CAC7ACCD6536E3388B5D1ABBD48E3CB1835F2577CFDD1BB4FCE3181F694F4DE7C1F4AF6CED1497DA8B3B53120E2F9CC7B02AF6561C448DE60AB63E6DA768494955E42D16A5D4DEAE6BFC13DAD9E362C69F53549DD3E99F51C3094A44D3A4F4BB9F6BC944847BD25E1D464B4B972C915CA844039C5EC2BB799D06E1A19D8EB7179DFBE9CD94B0C8884EDCDFDF3C707A4D9BCBE70007836F6768678789850E011EF146635297C9190E565BED5F51F3E578CB5FB3B4BBC13620281008042A0A0939A12B7F5BDA777AF6650A8CEE4CEB2B383B6249EA765772663B22E1BF822A7F3D1205AD2750C383C4FC634C6ED3DC012C8E04C1433A39A1894231BF1ACA5C5F1EEC61A43F82AC4CA34833689382FA53718A595A78151FBE7C04147E1096D486A53FEC7FB98C53C29FD5A6BA6D520A2EC1207E38AA89A0AE69FFF730507156C1559D71A501B863DAAC24CB9CE714CBF375EF2396AF65E4CEC6D5D0DEDAF785F990E85CA988C2742FB6E790554214CCBBEF52249E6E41067634EEC6C537953A97BB576808F719C95E3E0D4958B977C9E2A941B914E97780AD698413747EFA39DC83F3550814FE447E78A16A999C81B8338E72CF64F4B6C365EDCA1CB3DB7E6ACFD3308F24270C4B78C046ED1F0DDF7A5B12EACE8FA48FBECD667A95C91F8FECDDAEC2E2BF7FE39FE92EB33682B9A09FC16C111DC4150D69DAB472F9D311DD26E34CC6AAFAF64123774B7085BBF33E6D91303AFC46C2663E31E43D1ADA6BD1AA7FCFBDE0BC23FA27E317A8F2A7E2E810B17F0D190837CF47719001D2043AFABB628F178D9A3ED0DD73EDA94877394DCB20526739D7314F352C7EAD7A2158C7BF5AC5AEECAF5105A3A429DAA556307A0FDF6F3FDC5EB9FEFEF8D175346B294396A9814EB7A5504C70EEAEE567F12D70A4799325E8F91D67F1B8E9CEF660053A4BFFCC44A90BBD6303B80EBFDFBB50A6CA6470106D899854129A9CFE6D6450224DA302A148062CADD07643E77CD82F86E28686C479FCF9E5CDFEC788CA4C6AB538FA38858C75CAF06928FA04EA46005F4E2D4B7A4B77455AD12F0A1C961828880E8601C0FD50124836E6F87E8DBC86C0C01E07D076D4CACAC97A9F5F61F043BF3B0FA262080C5CBF4756DB9C50E2E4B67D97353EB1A2C7667E648B3AB609EF3B7B06F43C4CE400CEBA5519EB71ACA4EEBEABFCCD8FF3B3D3385BB4279EB12AB3827B14DEF0C82BF861562B76A66A1B171211DFB9EB10414B5CB848CA1BD4085A74136E54804FA29928AA18EC7F677110B3FDBE184491384DE321DD9803DCBC4413929A74DA9DF8B423FF0C02EA447C13F540D4FCC7B6C053F3C8F819B5D8A80FC9598BBDB2CD40223B23DB68FEC426D37E72FF4DF2B3BC300B4C07967D13ED99BEAE7AF9DD9A3657FC1C26E19BD0F3C3AAE28FA423A7239B127B1188E192CEE11B9632C29145D088B3B2381265844068377C211D183E1DFA193E35020C8A829564168F245C494B33FB518475C35357DD0F43BB044B2DDB8B0D6C227BA99D40D7C8709E05407E63293D27D0775B2DBA1C07347E2BC51C5465A544027BB3ADB98753644B9FAB626BC7B5421E9982318767F5FA66CF47C674C4C065FF5A0CFAE72E4E94C4C8B127741844B0029489FF356A63E5E4B80E541C7488E4CEC8C905B8C1C060890A07F66DFB66F9F6C420B6AC6F2783D6116E082058D2A666AEEB5B8D928608177E47D03202ED4340278F9D296FFCFB524B52AC2113D2D755D2294A38B88CEE1EDD021FE9671E81BE03681E80F6B1B8F6918930AA3A5821B5F3B703270F070F2BB7001FA700271F3F4F42E7EF589CDC3C9CAC1CBC1CDC5C5CBCBCEC02FCBC7FC82AAEFF13E7206FEDA46D6DC1AFCBA7EA60A8A768CD6DCB24A3AEAB25A1672325E3AC2869A867C8E7E9A124EB6D27E362ED6A2FE76DE0C164C8E1C8CEC9C76B1128CF2EC5A32EE522A1A1A7E9A7EF6BA02BE9EFCBC1AF2425E1A3E7E5C7E7ACCBEBAB68EFEE23EDC9A6202DA52EAF63C723A1C9E7A72FCDABA0EC6027A5CBEBE6C126A7E0E020E1ECC8A5AC67E827C5A565ABA268CBE6EBE7A5E0EFE4A3E66AE06C61C5C3A1E8AF69ED29C5E4C5A6ED2642191C0C028140037365BB51C84852B954C0DCF9BAE86D478CBB1849886FD29D7AB79083236D919BFB3C55CE019CF1DA4DAC92CD8E4C26FCC37F653995A9A779FCC8097DBBA3DBBF04F240176C5D85A0C854760EA2AF51E6B6946EEE4A7C6F53D1C0F07A644DBC507E8A8F4DB3A543DCDFF9CAEB7C162E4481254FF2BCA1144C7835C05779D4D3914D895291DB478D2AE5681297D0D43FFFE7F0E27BCB5AEF49B69E7A0414B82B140405020D6CD5385DAFE5FFD30B05659DA1E936AAA0C5919AAB04EADD6D7A15FCADF9CCA212074E3EB6C75DAB77CCB8C064E4B532AE0EFC8B01AA174D9A871183C3BCF04FF929F19575C0302993BC5F1C20B49616EAECE29B79ED583C22681B8EB7FA8F63C72450B498DD4723DCFAD331BC1BFCF1293C959C6D90A35436CB0B1ADD0585F8D253EA89554DEDEF2A7830ABD525E41312FDA3DDA6A9FF9792F43A9D76A60A63A3B3169BA7596AC7E1FC333ADB51677496A9220DD6E3A785ADB2F34DA7234DF70D77F486D1366CC43906A124DDECE78C9A79AD3CF99EB198F3ED1A5C426BCC8BDFB893DF5A586D01D2A49A9FCD1F16D57AD8DF5100644356DA67DF1F6E356EB4A0E2D91F36E1FDD2F8C74D3B862E08F66318E69796D8F378CA6CE6886EC1B9B0C4AB1E13DD7B580A0ABDC2D0C66984A40F29A40EB9C51D1FD269B9A24769C193DDA10F0980C35B0667F4562E566186181CF5B0D1C5BB9F45D2286885EA4E5C94346B4479A11BBB46BCF6DCB788ED18428CE96F7BF7B7A1D7788FC4CE29CA3590129E0C1549159F5B6FABA7CE69ADFCE4C109E6D1142B8772B0130102758CF2ED0681CC600F74AA84BB92EA440E1896A138FD6A1FEFD7B213260E11F2B7D2BDA01DA155A3556FE364A14AB028C42F14571C94404851225F0A8D2BD0E500306F8CF5AD7F67E1CE97DB85F4F3F3C23826C27C644620EEFFEDAFEFB725E62C12F30271B934E5184CA7ECAB3C8D2BA14E0F96A0F5C58E539E14092FC2B4193FFB31F309BA200AC28013F1DA9B5663B59726315B648CAFD38EDF0A44C32D67E233AAFB267B3BE3301E0128C1D9DF6A448B7A55353B38500E56E83E5F16BDE7433F60F4B6A1F756032E8F4873239242439E11092250F3CDDD1E0E1E7B86FBC7D6B06E84573A0EE833AAF230B76E9914CC3F5AD3B450F74727A2CABF30C689040F16773B5E7E148345A4D0DC41C11DBC31C05582E0FC4170A6203876238045CFEBFE4D80393E0930ED6274AB20688D013E6CF7A7D81A7E8F27EEBA6B956BD64A04E84DFFBFC41F0F11E9D88480045901253244969A9DAFB1CBB2F364D02303ECD44EA2D63B564FBC488F6331D21BF3D5F689301DE33941348A2F221EC6745FD15E59E24C005657E721EED7CC8CFC14265A86167803AF3F4F1CE5C774E0BAD0FA73B9DC149929A982557FD67D133404F474CEE255E017313069732657DD4386E3CCEAE15F3BCE9698236726B1C8569524681DD71460C784629CBAFA0EBECE4FE630B5D7699FB542299EFC3D7739B193E7CF47F1D6C3EF5F9483B3FC16BE8CA4AC7F1230AEF29BC4398B013E7C7F21DBC106317E5A8524D4E3CBC8084AC70BBE3F4A563E33A69E84F52E0F0E71993AC873200A19B9A24EB471514C7908D603D9A85CEABB7ECE191E1EE202FAC9C04A8ADC159D71711C5D672FBDEE609BDF799010013E7FF183ADD6892E19F03A1AC076B2104F71B18E4DF9176DE8433CE77BD35C1DA78C5B68EFD6F71025DB0D597E88D3639CE85C5BBA0581F4A5ADC4582DCECAE66A8A1DE6DE841132C816100DC5C4EA93A009C5BB97CC43580F1DFEF6995B2AE3BDEA661A93890C1A6743A236CCCB1C8DB1C7C5AC3C6B3FC21549B6F3D4ED6FCF101820FD84569AA15799D7FBCCB8C60F771D60E817C8B5D55689BF8429FB737F96CC0E38FA038CB5342034433801B9FE97CA44DC7BCA2F6A64AAA97A64487F19FE8CA6392E108899B9DE606AA5CD0614A6180803D00DC8462659795157F59E97A88BA577F835B39DAF52B66E6352392A6447CC7B01E72FFF826728FC7BD445A00B20EB3D4916AA64C6B576AB433217DA3AAEBD4C9F636AA38EAEA3BE74AE7BC505EFD6FB9D14E8F72BB7918EC359D2D798F9EFF8DE3BB679DBC28494BE8920454DDC47ABF3BCD1B6A4EF48A87DBF4C8B3B5029E32EA875C7D717D388E4483131473C6D86079CA8BDC2EB7816AF58C550BEC7DAFEB456C90F265D6824BC67C53DA037CFC8342078F67ED52021A3BA87710343CB78306FF1F4A7313322E5FA9897685BFCA7BCBBF5C3AD08E1A79712E27E5C1A62321DA04E9D9C5F049FB2FA12E217A1AAB2DF27C0C33CF009C5744EFC197E5EFF4E50DE0DDDF7BCF9CD119F2C0A18E3E9FD4011BEEEF2D332A1F8D8FAD28DEBE13FFC4532392F52878E2FB07FF409221D98FF2FE0599A0C40FE9519003FCBE29FDE46881A7D58BA9AD4DA158AC21BCAB0BDCAF5BA09308E1D2F2B451617BB454E24D578FA8D984E5D0A12AA74EA7B5E79D62E76B6057EE110EA33684A50A18F999C3466F5A4224E97801EF63E3F0BBC8694DFAF923894D90E67E56093765D7E212DD78CE98A5EAF81CA6D3B117FC9531D630710833CBFCD5B9945A795216813FD606391D8FF1E2721A07861DCFA39A4F82FAF01FEB390153E5B0C538F5C32ED5BF902E8387411AEBD4123BB90F6A7C67E6CA6DC859EC9D7039475C752A10667539D550523BA42BAA65C0065F5632533119DBCB36533D6D525B0514E8850FC8C761005895F72EFBDF9C77D37C4E8F1D1D61F6F27C77B02557E7FAFD41EF55FAC9A51A2A8E9A5125FEE8F03DCF70B3D0BF664F71EAA7B1D52E8014ED19B64FF6A7EB87C26E075D8D2A9054530460E755BC8B3485FD8F8E7F6CB11BC32385918EDF6473CA5084195271F9D6E544F4C93463EE8F63C0D27724251E7457122F9C52D6C1382F82F69A57063B7300681DE6D2584DA0818B8DE974780119AFD8B4EDD24502E4D3D6541CB4223B7C4940C67A8DD681414B00C8889FB0DC0587222F9CB6A2CC781123A7FD2B7880444DFD3AA48D6889C46F56475B5824C3BB282AF5F97131AD01CB22886187AD0C81AB4DBB6A4C060449592D7EFD97083E56A7551A3C9959BD08DCC60596C0A11965E1F8C6A14CCFB92A40871D3C1B20B1562174029F18FC3D954D0B3475711A7592AB8380CC9E46BCDB5FEF377E9CFEB6C8491BEBF3C02A9BC04C63CEE06C228334B25B025DA5E6C565C030FD66937F44178064D118976A2EAFA6EDEB2B1E4773D91A9F8D11852A18BB80D05D4CE84181CAC81FE2A0C5AA05B9198B54381D8DF4E95F4461272BD1225F0723EE5E01C5A3E4023495D2541BDCEDFE0DBA97E85E59A03293CFE6C6246C2D95B1F5E22E28DD9DF5F8777C93FB5D9036E09C1B4480803C8BB4B792F5C249EAF055AAD1B46D0407867D1C8478BC49798B9A1C3697DE66040365FD0A9C978079E1835AD5AB30CFD2BFD1FEC28A225D59042762B6C978A07610469705938ECA6929352C5A3EA5FE3BFAEFFCD5E661FD367D8486B9233EDEAB25344EC8B3867AD045BFD25104844B390FC7C9A0049AACD99C5E1C55998DADC8BD6C88F31CB181FEEA8B85D9A84AEF7E02480251A8125DACDE23447F56EE69C265241F8F5F6B22AA2872DA729619EC0E2C7169E2A32C874BF47E4F2072C5160C225C763FC758F915084AE9D1A93078600F19FCAF6D2A58D777BF6D2B46C6324CBA609FC4010446518786828101816010E064213282D277DA6C9FE34E0B84DEFBEE38ECE438EBB749738EEAA08ED7800DB93E329074D8EA76E8ED76A80B55C7B055F8AF495C87B89A42C4D2E12D37C3B0EBC5D0D60E3EFCD7696045B1388DE1E8A6FD7F165FC4E31DE2CC54AFBE4689137E1AE099D22823171ADBCD1E86ACEC689C89135FBB694B79C87215275C16C5ABCF3DF596DDE18C97C0B73958C72545C657EB594F9BD2BD4A1B133904370A49027A4DE0F7A68ECCAE76F07AC5DE003994627080402F1324FE189DC63C0F1B2B235BA9B19BF3C5196CF6F3AD3B686B32A45CA34FAD790CD94683A607F50A3E127145DD7F79172C8A7CE0F8E2AAB7C9AB3B5950D3BCFA0DFA2E665696602F35FA3E8E2CF6E51A8B5A71325FA161CA21FE2948353046AC33E0D9C0EF9335BF8D45843766AEC7776227A7CD844DF63F87FA01393844C4FFCC373E542351A18F718F1DA10CCB6F2968F7861283B70A11AFF7697C3CA619C2BBA507EC953E80F18D44257160E44855CE2553E91328418371423BDA1F19B451A9069CC4EB9F87A7643184150201008949AF181E091763882B8BC69045DFB77311772A13AC52024DF6798B1432DA04B127A0B12546EFFE51AA5C61B8A6FB15723D655F072636E633344452FF5150C030279A02C52DBE44E3CE49C4A3DEC90980D9C4E978D14E6ECBDFEEA49660B4DAC17E65C32F6E00AC83FFBDBF22C6190213C5C4686E8C29ECDA6B2F9FE6A5B918E921AC4FD2D5A75D10D450082863C43614594374347C1DCEF81A2609ED91C7AA1D66DE95F4010C58378F27AA7BABFAC86C8C0E291FCB44760B7014276107D07F748284DD99A577445806CD65F69E398E881C1297371257B302DBD3013E9AD81311DE66796F5E9B0B4038838B5853000782284FD61D26996231903BD26F5296275338DE1835CF36DF497D4AFC359B5140016EA4C0289A0CE81A4CF251B3F1196E2C42E89955051D9B9F5E517B743B7F2D772800C3320B4160D8FDB8BFEF80DB701BBED6F23050C8CDECC9915DDA48B344C8EF36AD1362235FF1AC1A37D7EBD62B9074D4185C4B201462EA9A13DAD578E6352C1CF9A1A2C2BDFF52B8898335D69C51E7615D6CD7F677543E380CE61C7526E4F582B70181C60B0413FA2940E065F998111A0606041D038AD927038E4B45AF244A7D3EA49C7D5415B68FF1A9A4D62B1DEF94B4E5B139153386D43F2532A78FBB1BE5FC3E9889F44394DFAA1644FAFBD8267DA953482E26BB64DEB75E47B4F8F68D4CD1FE3C363F4D5053CC6121BBF07C701137FFAE9F9C89603E648F3CE1BA4D3187FC3D467A1AF4AA5E8F70EE47C2E179ABC85D58BDC99AA94DD7AB06D5D1314C27FE332B62E697C2D198D5921C3A3983CF621F0DA607FA553FEB229237980C444E424C0BC8BF81280105766FEA6C4C004028140BCCCABE0217B8B0992F37FFD7C1EE83369C3DA2F4265921FEF5D9D2D97B0269161266580FBC62CB10F9688E66B5D805BAA6A37380D75C49EA81EE0C00A3127B0B1D030BDDCF6E81F9A1CD1E63F425BC28CB73DA4922F8BF8ABD99CFE8F857C2C3ECB564E702CDDB0BDF0E26A6E278C7D9B6F3C696FEA3C11A413EBDDDEA0C3F4E0F497B88A0188AABF4C8D2574078A6EF1677EC6FCA3DD368E7D558CFD7750D9E9E69B5675200078FF71CED15EC2ADA8777952CDEF04FE18B53F2E4AC666AC3F58DEE35FA4A50C74B982A0214F0E11E56F278860A0B55B3B71732F311406D4D09D07CD30176A9D2B13D7BD847F350D2A39525DCE6A57661A424D1EB9102400A464BEC036AEACA53BEF755F85F3F95B6B2E257BE12FB0F3B02192BCAB5090A276839B6684C0988D12BEB14B0A02DD85DFEE1C4EBEAEF2729CBE7CA00B5D8830F57F6986279F22E3BBCE3D4B565167B202444968254B18C965BBC0C876F829E31585F275EF427E17C21FD9CE1999D2A5958F7BBF673DABD1F5965AF9A0A8692B0482FE01E05BFBF55DC8BBEED7DDF29DBF820827506250FF2C9197DEA99F1DC99D6BE8FAE56E4A874CE14F16E99494CE43AA0BD332A540223FEECCD5B5EFCF9A588C1EF37F2EBBE2F40631004BC17B179869ED6D6E8376DE7DA7BE80415465936E51F8BBB1296A164A85CC04A069BFD8189AB3C90C61FABD3A76D5849BAC7B064B61C8BF17652FA9D39C24FFD39034AA4DC1364FDCA309A8B651478AFFC17631C021630BDB1A7459CEEFA7B0B1328CBFB51DAB6E5CB41311FA3CC402BEB561CC7280C4E042E7D49AE55820F3543EE9E3E15C52B9FDC234223F069B777397A4C3BC5B37980704FD0C668FE820898E9ECCB466E5C0A5C30150E941F5419C4403E49DE2ACA79962A57BCE0B0BCBB4811BAA48564CA5F520F7CFAC77A0326AED0FA0D729440633E7E1C69AD477992D3F6F5D78372C828DBF94D73F319D85EB0166EF86F47B1471A53E32B349D296825144ADC45A9614330406867B31D82AC16A69C88E0813E70274C255CF4794E4F414DB474D3DF9CBDB3AEC80DA0CD457D8750C6357E54A7AF15F4C9B75FB392B9BC7B03418E14E66E758A13D8E7F633D6BE70E28D215C190E92BC04ED98AD4AB7A0C8101554ED524C084A9A35F491F2E876A0869215261593E1E27F7722D9E9A6187D6173044440D42C3CF265A0F2639571A326D11FC1C8F36F7E816A33B21CC84E05C428140201008047EA434C9EF1A5B405E73A80BAE36587E4C2C18512A61262E90E457FDC849B3C6B384AB8AE22D82D6123D675BC4826136EE1F72B6C53C12B600F795055A82C4F60BC1372505DF21BDCB160F9D2F116255EF7973A37C4507A0D76EF0004C7E497F8D0804B1680475B6B48131842674FE6BDCF44195FA68E0EB819B12310A1E80C0B2911DBB9F2181719A3065B12AF1419326B93A52854E85AC50E8B509BB45F0332E2E32BCC2AE8FBD967DD14C8673D179AA37E97252C459832FA08748B455621795DC00987845F73F1C1A0AE30DF3C878AAE30441EB75E3689D4D2874B4937457C2C808DD50650BD16D9906864C066B06A71ED2248C9A699A82DCB504C453273FB6D4CDAE77E98C55467179252FB6C24B17514C578F88F819ED370EB756892976865287E24C871504FD1D800B2D2445572E985FC9A2123BA1468BB0A6DD3E4BAE1696BF8A92AEB7F0E4E84A514C332E0C5925E9764432F41E3D3E467585860A9AB633824B7D6909702A73A7E47F86D26F25063024D93F2F1430BE0B076CEFF30F6B0E64FC0DE48891298D89D00C4CB2085F22BCABCD8573250FF5A52D840146BF9AEA3F69EC6EDA38B534A86F5639634731A928CB56E229DA7E619CFBD42602962151FE3F6E1F9E6BDE259A4EB153079731EF28E60455DF5E4B0BDA37310846DA14CE4265852538EA19B6A63B7CCBD2FA7480641FB41676C394D7B658958346A2BD029A8F629AFDC77F9A2AE514771814C8C21A52D0938F71481A7A1324E4F212EB60F3393746CCEEA506861EB20145F6C60DD903415A41905C101083C8591041F67B767888BB0639991F5B591F2D87F929422FEE1CA153EAD04BABE34269D2C115054232F136E4D813301148D2452B71A0607C2369374F27AD9C6C525CA99F38269E09A99D7E2673865161B1E1FE3E708957B16DBDDDE2349D26F6F6111FB31CA59C3629843658D8CC391BA42ADF82F6333498EFB856BCE9F6D5FBB97D492BE26423856F4CC348C304682E4A9D5093EF70C42C734CEE6074382B43845D16C1CD5F7C79DC274E86C0C08A6F69A0D7C2996E662977C87E2F8F15722C91CAE4028FF46069BC10BF59D41F807531ECEC1F8ACBD72A1E9B5F4C74C87DAC4E41DE39F4A7EEFFC65D379D49FFE974C3D4BD34F734C458CA1DD7CACD4FDE7C02550DCE9ED5BBD868A81C7E352F9D9AE9B62ADFD2DEB67DF083C5BB58C8190AF38A99BAAE963141200830F0D07060102C144ED33F43E73781FECD32629AEC3BA01D828FE1DFD9FE18729E0163CCC471CCDFBB7EE0140FA3F10CF8D8B2AA9553FBEDB057F0DDA204D27A57F74BCF5DE8B712CD097DBF1D5151EE1010DB4127361DA324D56AFFF7735701F20CC2D174CA71D6B30AACA0F08FE52DD9F0BC84AA2C9B6E5E039653C60BBC16C774958B9521991F0454E0E51A9193E34F2B99BEF4E3F309C3AFA75B92BE820302829685B1879FCE5470993A67E3D1A097BC6500EFD36256EFF42F080402F1324FA6A502D6846DA328540BA00E5613177C1B1ED2CBDECE79109B330D42865656754C4948EDC4FBE567826B748011A8B6C0AC1AFDB1F954A691A6A620FCCD6DB74A7471000626F45F8B4D9E689547FD8D5D6FAB4756306B25D983746484ADB16F322AA6565E5A88FA966E295B2A51FE7960CA60639EF18F5F8B36A3D7EA8EC91DD944410CD07FDAF065FD66B9DF92092FE5C84B73270635D3DB6246595C59B910371FF00E05A4AA25D5FDEE7DF05137313F935AD5DFA9733C6EFFBA59409169C495DEAC621D2D798944701E4E9540F20E63B87AC6C4DCCCB97DE5AD8E045022D9CD868ABB094ECEABD92462643163902B340576293BBE333A81EEFD6F2A02FCA4F392165762858B19AF2130506999D21A45A7A4DA3E1835FC1BBB33BC53A74F3B9EFC7811E242B47AC333ED0CB8F7133426C9FB51A53733DD487C93EA67DE93DEE27E18972DB2A38BA27A4218ED863A44E03946DD3C116D9AB3B2E3D1A181737D13F907FB75A2B07B13FAFEA80D72B9FB05D5ABD6AB5717230D0B7D75F8734A79138A06E08AF38F6ACAB92C40B5B9B7F70E4A2A3BB54EECC1147FB8E5CC050A0E4472BB2B1D8AF03A50388B814F62A71A92615B5603D27C10E465C2679A1F336E6907842B21B3D30569DF6FC46D4E4ABE5F779A726F0C69A278C6D3D42446EE9482D235A3E999698679DAA112C8E0F66C2A0FA84295702618B74D007E496540DED5E120D6FDFE402C9B4CA1AEF5F81116567644EA64C8D6EFCCC809F85837A6922B9165A71626C0B8BEA0819320B07EB5AD2C9FF0352D2B2AAFE924DD60EB10D9F34740CAA3C1724B7AA07FF70371248FDD6EC6B6C9D7B571D38D399C61A70E05B3A7E7C8020CD2B0AE7D78B4CFCF4F7250E5473DA610F4B0FBF2AE794B047FC247880F5241EAFA1F712EADC7021804F12D4707A9840402FDC073F6F91E6F75B9F0E6A86E1DA7609249A26995934CF3BB6566A297B5368797EC4F5ED81018F07F4D40358DC17B61EA792A070B8EEAAED4455487EA9980C7610DC32B959D3200639B3BF64BF6FB0CC1CCD61944AC6EFF529CA526A66F74F0583101C3B390BED208287037F423080A0402814006A2590CDFE7BD8390FC71D02BA542D065CD61F2D3D565CB301394791C6E1AC6C9AFA2B92DCBE43633B3F0096D5A04C56AECAC19596CCC5AD2A084BC3A63708F390C90AB68A9317621407DBF39961DADFF2ABA017916BDEA38FB4B5021349FEADB2C0C77423E161B28915FCA250605712F75300C1448BFD4207008B060391EC18BED7804DF95E311FC828E4708F2381E2125EA7884ED2FC7237CDD6944041E8288BA3A5AEEEE7B05734A702F614992DD7FE122D750BAC1D3791922CD511F09CF06844B12F0AE4611BBA5650CB265BD863065A6FA93B53E7AF906065D5DFEE5D450D4051DEAFEFD2487F3764BE5754A1F572E2E76FE2F03C83BFDBB7737C68DBBFFF8F67A7A4B22A643EBD422F438E030EA85E8F5391523A53E8D3C110915356544C2F9499DFD55A0020402817899FFA2D5CC3AA082E4C270A35B24926E2D4023B4102EDBAE9BD8325760B6B79F9620EFA84198332DE955B618E6E35B43D2612A4E9091487126BA1EFC58B83BA013877E710F9D284555EAF7F9EEDE3B06DDA11933C0CBD2ECA9261C925E957986DCA2DC42DD60F70713F2670701395E55B7A74376C7EAA3F53B3D3A669F36BA005C207DE16800B92CBF2DDE03B2EBEE29FA4E44C51134F26238A9176655DF7AEDB06517BFB209089466BA461106903004D40C8E17D76D94D5EE87B2917881B2E7911D94F49BA56A4F8D0CD56E00F39BED5A358689E22CC1A3399E73BEC9A92C7B78C06C549CEAD1A6CA9ECDE698685980FBFAC632941230999A3CCB91BF1213957B45ECF59BFD29B7BAF580EEE82720531AE9ECEEEC6C36E37DDBF02AD51DECC8B54E9AF3237FFFA15260028D5CD6A21B330F8F652A25017540559B05AABAACED4A77F1D42457827086571C94F7787EFD7E47DC07EC7F3585C119CC3DBD9F4D28AA2F781D7F42FFA69040F9EF86D8B96199D5F1AC7AFDACFEDC27924A7A289C156DA43C9B701BA1280177BEA09D2BC8B11229C0CEF98A1BCE70F09D78B249D78A8D60BE023B175C916724EF1B867CD86C61C70FB362DC4DC2EE6A3A5D38C349FF82DE276D2982499355443EC386A9E07BCC821FE2BF982D8B0790199949261AB61FD8A7842D7F383E8AAB5700D8831A1F19706FE36C3B2F2D7B062ECAC4814159CE12F965334319ABFA38713EB1623BB72A9C415E1CDE1AD61CDA704A3F64E83AC0BB5400821DAAEC6A66F7349A678D335D62969AD278AFDCEB88925DC5662DAD8B9ED59BBE14741EF4337496892305436D49595D1AB7442F8AE46A3B34A8A1A9EF72388D818534B8CB403FD6D906DB889B95DB0D4E13048AF09D8FB8FF0AC387643190B225A2D3383B4F71CBE0DFD0B0982098FDA1D079B6889EC35084EAE137481010180286228AAEE6408282868680A052DD994C90A1413010100403060486C04283C0F020C8DB84685DA1E0C0A420282804300204448A88040D428405C142C1F03E814702934223C3809051C0106418102A1A181E05061D024284607CD29127E9091E198BFCFE0E8D56E67364C9A54AB30BDF0A402671D821391011DA71C06BE93951E0D72A63B94D83EB36C63AD045568F0632C9C30E597939E252A3D4D23D684205F4913332D58FB417253DD92147D48253342A5586A9E2C2FA41BD5924DAD3670C495022EBE31659C207647647900FF368D2079E231329991D0D0A0354D7A299EED07ADF4ACB7AC378509DFF85B455ED7CA740D7EFED1990B9C1E1554EF83975E8816CE168DCEF62DBE51B410D9095FB40D109E41BDB8CB57FEA6B4C1D156905231F99BD6C5C68521900C559160D694E25F328D4741CEFFCAB5BDF8F86D09DEABDECAF445F340916DE676CB128982419A9D1D2C6EA5CF757D17A82001E3431596CD96587012B6A72B834DD26DC6F217EFFE6D42E6092FB93C20974506A6998FD8C66DA2010F3909A4FFB61CA219EB7655AAF3C6642DFE6AC6241AA8181DF1BE712040FE819C13CD1F7A94B8FD430D599B5AA5DF6AB0F4FCEF92351424C7A182CB9049786A8B39734BCAF4E0642585D7F3D330776BFE1D612D9AAE473ABFFD9C90FB9594C8360731F7F0D761440D24CE599E6AD6C5D741871C9F804D25A181413CCAB2F9DC3DCADDF9B4FFF856E2657BE12D21F74E888DBAC0DF72C5EDB6264E5011C3547242757F0F7C8B31C101CF12DEECA863E92867632414F941402EA7611BC6E3099AC609CBB3C83D16F6E1E1364FB3A8871046E4571FFF201FC93F2CF40A3EA0DFBEC9551BB1FA684DF9F0E81D84272E4CFDE840A5D3FC11DA7DAFB1BA89AC30AC3DCC252E9014BBCB2C7C3D761D2380E9C6453DACC9E392E21825966B7A1DAB3641F0FDD56895403658F182ED2A9201008040281E8BB8AC8A296DB7650EDF522187871F02C258453C62C0E8181AFCB690CEBF8FF4A7F1D8E051C56796D1563DCC1A2A1285ABFB7F1E67C2177A4004853EE4A099AD64A6C9D742D7E3D75CAE99E53799B3AE00DD96CFF97B92FB8B98E78BFA659A425ECD3392955369DB2403498665DEA9B71E8D07AAFF0EF4287891248431C76E4FD1C1331020652B728838536F0603FDB4F9C05C9B3ABA654DB113B44FE542F4856B18FB611A40028088E2A8C582BC8FFF2A397D988B6EF94E8B5C09B7131586C58653D23C1D26BDDD020F10A366281C98691ED6400338E1D1FAB985224B059469F5FE24ECC069F74F5F2D4EAAE29CB45DC552D00BE9E090413BB381259F22F5484CC6153B8C5D06B0D5D66B43AF1E9C37B85A48D49FAA804BD9BBCF89CA1039E19F2C99B9EA418F8B8BCBF3E4A85E3263FDA5572FDDFB59F4DE0A4AFF74B0CC4ABF1440BEEE02BD6A3E5C184912368BA7FD352A91ACC55F545805C9611600F98F962311406A09C117218500BF459E422C7D3E912CB7E5CBD22D39FE0B79E502234576CF10C0014E83CEF3B60373957822F9EA4CBC3FF3DD559DAECF857E79D482BA2EC38B5F1741436E84DC3540CBEB2AC37DAE0DD63434A95C71ED9DD4C757D6BB499E251A673453F3331D12F21417014B95E351A4059326C1AFE297782C3164484421A7FF42FD693A6D42ECF319EEA8F546DD9F31EC03048D6E2FB82D649AE489F0B11072FDE5B5DDEE3295409A89418FCBA34E817EE86404050201008E46552C152294CE06C10C12F86EBCD3A3EB8C9FF1E5971F6587D7CFA7B8F8B37D91FB11F95FBFD4DEF295B9CC645F07E9DF3C8149097069455E2372A47EA12775AAA99B777418097D59FD16F71A4D87F895DE328550216DDAB10020BE83D14BAF4DAD79AFC7927891551F4B117BB06758DD51EA5D438F1C7961381154A552569858FE1DF3F14EA852F8F7910E374AF17E39AE0FC4279E25A3487C38D6757BB3A3E7A72D0E56F8D230F681F6C45ECE28F27C89437D3EE5B60494FD9953A5256F3E162EE4DACA2BB9CA268C981A05C1866A3CCEC703069A42F934C2953504116F45EADF27BF2020E1AFD82A41B89D374E51B7250318B2391B5F583449710BF002D26F968D2FF17E904F2ADDBD86950561687F45D189D9275FF9C008E94DDC9B1995FD1AD1F1A45B80675C71E11AC9BF47104DEB0D78C5F70A6F7E53B148E3916D79B6C46950BB7EA85DC043F2F1D73C1D57AF3508526A6AA5BEC47321BDDF8C2475F74BD52D4213E5C2B8820E173221432DF94527040EFA1E7666E1A8A99B01C042CA599D68AEE9837E8C51C55CB40795529AF3A9F3A57B82141ADC97929EABFDB64B1E0597F753156667D6AC63656AF83B1BF6218CBD0FC797E1B0D318CE9EC2375397EE3AB1CDC3B86B2DCB35BB40B12BCDB97544D4B330444C9148B782A077827AE5F53E069FD80531DDBD6A30EC3E79D0E32BC9A20AF658C9B41348001AB5F2B503785D81D0D6B76F908638D17B4147A66A373BFD5F0B11CFE21AC5DD5018271E88996B5D7D16D7AD716D3BB0BF7F166BA5A04966FC90D17B47CECF653B9B8A30FCA14F15EB15A67DBEFB8CB8DDBE078F345FE4472A06E2672D88000FBC433DD56030A9B64A8026101701C25AE41F5AE5B7F8E3C509E171E05EE1E3E763D01935FFF627D45549F8B080697C606642C6065333A872B234A465E70955DA6ACE1BAC1C1E728668E7A83A5A6A9786E7F3E47452EECDF6C5AA416793D38B5E125E94AF9CA9186526ED93DA81FC9A4F8887AFC7F947E07A42793C2E60F073AF49A63155808661715AC56A6DF211DE2D9AA8919F07AA98F56F1C3DD54ECAF868177C9F735421AD32F2BC7231D411CC2B737C0F282691FA5A68F911DC365091446684A2E0290C5EBEF86A4657FDBF88E909800217CBFEA73A5462FE52C7403E5F7EA90C6465C234D02AC3B689DDBB4794E9950BBA1DABA6CBAF17ECE57CFF7E0E0D10E891F17E210D25FDEE6BF9C6B27A8925224A24A2BF50525DB4A2B13A0BD3149E074228C9ADB7E006E769517346A1257B5F4BA43EF9CC59574574761B68B06F9BDFE3FCB5864DF2ED6D89ED3127C09EB3034D8DD60C5533BDEC42ED9170A1C2402E44DFB687AC378BFE21735FD334BCA0745D92317F3FE849D0BC39F0F785FE02F1B4AC02867F3047C5D44402A42AE8C79D66F2392A01354917CEF9A095D446F170265C6597460935F4D7899C971CEF39AB3F5C71BA4C5BA396A0499B2D80D32B8CF6E63EC777E7AF17A37F6F0DA1B223E60F200C8F5115798F5F66FE8429110496CD7EAD8178F98AA1B98A860776CDDFFBFA01E6022F74D83CE8CEC086959BBB1A182BC394D6EEFCCB3CB26C7F1311167CB39DB050EB771ECCCAF0E058D02D6CFCBF58CE0F75B0197FD4C9F408680A02060100AE45EF017973ED8346D621FEAA04030B060581018840405828305419021207804302C0A041109040D41AE673A2C910363C9FF25967C5D6E966017F11ED3D1EEF69D1A1BFC46B9191333BF2F6509BED721DB18615432511AD73CC31285238B7B035F63F694F360095E66DB4843618049714D6971BC3451C521E61185A5D17A26D4E71FF8CD9898E57C2DB2907B5F6D0061077E915E59DC4645F36B2E56D695EB3D7BC9AA0FD2394F4D79BF6543299F4A37544FAFB2205E7AA05BF2E3035D7D202B81072481D4304D4E9F89D847DCE2A8A96537E238815CE4CBE55313EE0EDC296A58BB98A41B8CF925B7BC40A388180A037850E35B76624E067AA464907B5F4AE2945CC19F8F7AB381FADF245272102CD200DA8F9D7BD427D26C4945ECD3C426BC2D51116C1AF11BA31FCBE807139CFF54C8540E70A7721CA2F11FECD44FE933F478F7E24861BEC15E6BF0D94A4E8FCEA3D646D439E9FE93EBF8763FD5B4D398C093EC3537E87753EC2EF60FEA8F6F1FA910D2F2F6C6AA7405514DD86198CB6541890331D1CA5BB537F83B084F382995CCCB04CA9A849F0ACE5B6E82828B65978893BE8E1820AEC4636E8709F23E5655C5CD62C696EBC53A339E948F7EE4484A1A263993FED50D85BA11BB9EB02914F1B980893F6625BA3BFBCE0DD7BDF3FA9B4C97489A5298AAFD8C9024A24D85BD99FFCE25EAC9C59B511494DA8D7B5688D6AE1CE632B17AD08574F0B2E043CD7866E80DC14045600CFCC5A6E90B4659D30D2E45CAE6CA178CB7127F929AC2F68D40E773D546408A32AB7546D38B8FFB61F7C58173799C4F57B1D72B663C65A03CDF4F65D0312C034CBCEC779213BEF2F7E67BF48BE628C6E83E747FE96A05BBE6FC63275F147616B19083D3D87CD78351FD06316075AB3BA2AAC40D5078CF4E7FBB536A209505115B94C75806E5B0693AAE1C9F7E081E530E990B8B286076F13267E0DA24965A356F7DEB49507ADD96FA062227DE5B994D38D9EE0E7AA1BE559611A9B04B64D1687A0EC03AEDEE5AD72B2690E4CACC8E8C5411CCF1C3670A664C69F2EF44DF375C5BC3ADF41A8E54580FD2C4CA14DC312EBD19E6E6CE5A1D87343D174A8403FA3D879807C10D062B4AD39362240C18F2B8D65BBBF33B446831E065D1F3406E11D0838DA8DD9B27E1EC6EFC6B726207B0FC4C835BFCE2FC1DBAEB2AD91EDB4FEC3EE27384ED57BA84698A8DB227FDB7D66E7891F9391D7A9B5A145AD72226CE39AE5E588683F3D7D9D1E33C6F7F63E62DB899E141A489CEB8D8FC6286A81BEAA0128BF8600B0ABA8F2F254E4DF1D3DB75F058BCE5F7336155EAE9C1A1694761A545B84DABEA8DB94EBCE26903D502EFF64B990E20512E12FCFE7F5F9928A3282E64079804D85DA40309FEABF8DF9A60E56437EEC4866441650B14B4AE6AD110638D400BD5473222AAB11ADDE91F78611F67FBF8808C60664CB31AC15A5879BA799D4E8B5C46799D755160957C2B9D1B2B276BA1DFFB28D14BC91D9B7C9D6F8C9B54BBA0D6B4B0E2BC8DE2CF95EB83AA4B69C3F9D98D1DAF49AE82C4999B7110A0F3BA5C6CBC693F35936C647495FA1D03A742F85F86F04D3F61917814154360A0116B4B0E7C9CBD1454A918C92DB2DFE002AFCF399440AFFC6A5CD5C0A8E1F504882CEC560668C2F4F3C8D3AC57505E3EF6775536AD7491A0B6B8E7240B1D8EA8CA938975734483308996190F5FE8C406D5E5772645861BB02B1EAB6F8CCDBB7716883724FB09E33EAE9E3DF5EF7AF2FA1ABB010852D5AAC9BD9AE37F2CF4F7359F2C5968AE63F96F4B30994D4235A93CA9BD5F2F2E3270B2E21FCD3749D03950B6F0D13EF598D74624C4004B5A4205DFBD23345B335DFD7727DD5532FF8DBFF5D055FC95E22DD9C6CAE6830798FE95B1DCD7E54151E9B9D11B59265C2E8ED726960407AB1B0A649045D053600B9BC57CFD2283CD6D6EEF45531AD1B37ADD614E47CDFAD9FB3CE1BF2C7EA6081060746BCEFF77DB55F4F33156075DFCB37F74CDF4C1BE3CCD436BBE2B2934C1C5A7DECCDF2D039C6A98234FBB64C65ED526CC43FCDA923C5A747B87FE657E6F17DE85F4653847BE4C1659BBF5CF26954C74FD1499AA678521BFBF20DEA5D4318B3D948066012A1DBC172089D81E96DC60FCAAAD2F6DCD5C70C09F7CE53F1BB918C647D5F88BDC16E330605DAC5B9AA8BDB3432471C03BE49EEDEF52432B3A6715F03CB27CFFB9E927EFF6D9266B787CCCCECC4872E16C08066EF2BBFAC8D097F43CEDBC0D1F5842953147664B236A4B5D855C67B4C8C48D0AA83C1F866CB1426F06A9865F8AF93732865717577D639D697FED8FF045FB1FBC1C88A625DF7EED3FD921260E824DACA179CD307D61EFD97EE87BF7BA3E5B6599B3C7FCF7FFE96762F6D68F01067CE3D636553D7A0CEDFDDE8787539643E029B1A7199A14F5195A0E3D7F3E4CAE74E50996DFD2E99697715E71FD4020B11A1A4AF37387D6AF09D4CD1A70BFB763FA2A60C54AD08F61271CEA5E4CCBFF3588DB3822DF7D7F1450377AE1B8A4540EAEBCBA6F3F35B6DAC11C4FDFFB4A94C1EBFD4161AE2665FDFB924F902287BB631458F82F854D6272850FC6008DF31FF042FF7A21D4A69022639B1B633285D95501B749126E6FF3EA8080E73FD35A826500B8C77E71D17ED636B429C50BD3BE98D664101D5FE947BA29C942770ABB88919A9085BE048A347E4E82C017765F50332ABAD8EDCA2BE81830D2B09E739BD33F1641506DCCFD5DBE59D37CCC5CD3EC702CC9AD99A059D96F089409579070BFDF873C629280FC4D4140A49FC8109CF85C5B0803AA202D3F592DB5A846B219DB2FD2FFC74D5C9217473091913F8BAAF0691D9D35025FB8F0B7C37076F3FE20E232F5ABED18B5F83842BBE70EAD616A65E6884312367BF684D857C89148B328FD45069B36E1D788A63C7D6D9C8AD4BEF995C99CB0E93458F85FD15E8C5EBA3F77DDFAB91D96FEB223124DFD5384182F12E8F866E61AFDFD5B4607FC83D811D472DB5617E0C2872DE0A6B527527DCF09F77F21FDB506AA74AA7E732E29AD3770F4AD5C055B160C7DF7A299B87859A1C2A0CA27372FFBEF60C7F25AC8F3C4816F4DB3F6CD260129D7594A82260FF06587562E9B537F689EA6FBF1B3177DF9B12A61A46C1EFA3D9347B508C9096CDA0DD5B98E78CEAC6C08876C4C1386BEA3C71B0C13C2AEACF5494B5784F3C9A2118F7223B457991A5BDA216D968FFA84F6F3502D8046BBF406AE4A5ED6AB8DBC325E51157E9D276E3349AA58D2FD7EC8475EDCA2C014B785B5A674E03376A5D6486A24EAF87578CBFE168BD53DFE8D1E6E0A9ADE3E77128013C6CF081AFB5F67546FD6641C4657D0A4D241355718BBC1BC29D77DB036BBC3F5945938791353C094D8E30FFF97E3C7ABD8058E3D8691F23F1D181344C256DACC20CE3FF45A92777D65DF52A6348E69306F332F7BC95BBF0008C1B2AB2B9067568C199154CD4684BD8E508546CD1C4A6678523FD668DA7D1B798DBE43D7DD38B0501B5E8A69C2223B1E19A704C5BDECF29ED0FD2BFC34FBF47C1EAEE7FBB1B0CA18B315209DFD895CF152546CB0C6A8F855AA76F645D12D602348526EDEB25A0D3115ED509EEED863E6090226C4AF160C2F3CA3FEBDAC5D0C8501E51CD06D7F8E8C7E542D7127D5814BC4DCA41DAFABEC2F94BA617CE9509E604B010C15B94FB4242E5F76CCEC47913C15549E66BBC9855691379F49C12F1AA45856662712B885274C89E8993F6375A78353342DD0F506AB7BBE7C6CD695AE5CC7F60B853F15A059F3E10A3FD10444F13EBB6DF32DA5A50193C2C3DDB02F4B9A6C256A1D81C26BEA997CDE97B885B827AB38223E874DFC7EDDB0598EE0CC88CB069C0DE28FCF462A17F2965F9F0B69B792FFEBEA69A6C25097577F2D809AACD6C1FD6013527E9972566B0E00AAEFD8325550645C538E845502017AAC8D724DEFB23D0AF9FEF0EA1F98F35DD578A23CCE8476AD5ABF6E8C8D3DB9732319ED5C7FF3155E465DCDB7AF0502F94F6592ECA2599021862E7FEBFABC07C9B850102855130A020F0387008202C342B3E264658987A6197F3AF3618EEBC3E9386EB0D0E2B8B15190E326A3EE7EA4E74ABC49B29D66016EAF6065E6D57F0C0A26C41C99E207B8CEED4A1DFA195A118F6368FA6BA938BE54FF15342998FD39F07E5355F0DA237C4B4C971EC621F1A6C86FEF524A0CF3FCE9CEC87B51EFE14D09972A4D49AABDAEB643DA9256D14C18ED53DC457E516C58204D56F66CCCD807F312C127656092BB3F45C887339117F4117885323E58EA54A40D2880402010AFF06E65FD782B0CA4BFD1FE5EBD85F87BFB86E56AF0E5632E316BB40769891A5427C0C0B44177F5376E769CDCF975B791D8A1202361A63DFE1116E2DE0F1675ED3D21FAC68C439216C5D411253A3468CB56B93E6891C557FE861DBA39212C8E169E635A6DD0FD7E9E0F8CE832E3D4F8B3ECDC1CF1BE3BB8C8328CF5DE11764DFEFE447E63C5729B8ABE2C98D554FC40561C608DFD6B2019DD2F3257828B018AEF459A0B80E09FF4B1C5CE2EB3C0B299D49F5E3998E48A474FF7B8FD7BD7F6FF72EAF21703C5AB2C58A837B30E4FD735E580393DF0F600E5A1385350926D0FA6556BE16806839B73DE2F561E9C87FC2A276AB39BB01EBE35986FA4AC2D475D33D241DC57C0F98A01E5006078E1D46A734FF4A6292377EF0744E652551AF35C37E21DD75B946B19B9C20AFF45CC39EF90CD9AC5D037F43C3D2A1333D3B5CD612826FDD7398ACE1ED5E79FC2EF3B99975B584CA5B15F393615E288EFFE66C6FF2B39A764B01D3984391519B47C4A6B6E7FE435EB9D9D3C0825467EF30ECA5E2F31634634886B57882D4A57702DA1CFAFA6C8F961BB83A7C34B5123801313A116C7339D792CD4B7D9766C99A59BADA23BD8F979CAB7548473F87D8404DE5D000BA6DDF86D07F437B0161718B32D2D78912A751CE30895FE985B9DC61D6EB734A06EFC1D6A740DBC94A8F5065726A236311406A0CD2CD6CA93850A306D4ABB25AD0EB85E316371F1247A7E46245D41D97F3F16051881FF2E03853E899703DFD7FE25A36EA42721597967745EFC352C2CA851C81AF5C61D4E351F01F433182702CEB8E409E71CF64537636089816FAD62411253E29E1E212D95106FD56823B6BA19FE15B1AB5C60FCC044465B9E45474B1A3402AC2A55A0A5D94C8F565632EB9B17FE36959AF2BBBB138FA156DAA77344BE19872BEB8AA7CF0F3F2F820410B37EA514A06B565272E6D8C5C5EFE49C38FBCC28C3F3B5D1C2C9E4E7431BF7B87EE212492C167E8F95C665063F51C61814C16B7F0898191A98C80894565939ADD7BC6231DCFFB0C6E50F110D60A0D7FA6DDF1FB7F38AEDA15D7F28FE3C9E21EF3706FD6CB9FE02C6A49DB8CF962280E3CC9BCB6CF5CBE2574D6149509B7CE6D16F173E6B32D1AC7C76D91054E4732E793519455D07A52BD4F93F72B9B771BC770D533DF720FFA36425E55F0DD5A03299997DCE5F507F8DF689330191981FAA3F14099FFC7E07B63534C3D23D93F550652B6C0725386BCC9F4BCF5FA76DE3B1DF3771C6DE9C4FA8F2D15FB0FA0F3FB350BED6347C2D7BCECAE8BE9CF7CD1D796A51BD28E42182085C65F53D3F9E874F328F2F00422ABD47B6258D323E4056462643F124F241FCEF8BE81C4E7851A769448A8B242876E7E91BD160F425F02289E125B866A1D2B1A962E7A9F5FD7A9E85E3E176283504E1C15DC3CCAE78DE94BF1AF79063FCABCE9030B320DC66599D640A096FCA16C97C74BAD79214AA7FF704046B1E8D8C28F5B30798077B1FA2ED15FC5A862D65F8F3863E0370D791F8AE9DC56DE699F5CF99D53509B9F982DCB131D36BE4C6D99E4EDB2F27DB58E3DA295424840117A4665DF015D958251A9A1C43CFBF1A714CFE260C728A71284C863B2EA1AB2F004CEB3ED3086DE304A5736C2CA1819A145F61782373430D6A631BECD94489EA6FE09D4CD9900E59E76F18FA3F3DBE3E1211E0ED2F4BFBB10C486A5BF78B15B172D3997AD222238B48D9C1D13FBB2F56E3D0B4D46404D37916872971745E8286D9AF5E724F081F5DBD4A91B4CDF2554442180065C2A57BCD106CE13874BDD33FC79D47A56EEC691B3343755C46F6CBAB5D8B0020F0762A44C4765CF8229455E1223B03A0086F588F85EE6994414D913DB5B1F6930E95950EF5F5F80848EA2A120CD674EEDFE9425153192B69640264007D85B355650FC6F0F6D8DA9F95AAD59F6C10F00D5FFE35F9F1E0F21B13E38EA8B0B973BE191A94CE2C31016AC5645A10F4FA80D3CF08EF032D983FA197288DB02E03B1D611F2668AE10383F015E36A8D0B34DA2886C280B367D4EDBD5DFDC2C5D03D3C41688D8E363884B6714F1F4AA8B2FCF79B7C537D40AE5983906A1DCA5A117569E2CC9C4BFA3F6DD7688394821E85660CD57CFD753A, afterDelayedMessagesRead=193228, gasRefunder=0xe64a54E2533Fd126C2E452c5fAb544d80E2E4eb5, prevMessageCount=14351141, newMessageCount=14351455 )TransparentUpgradeableProxy.STATICCALL( )-
Bridge.DELEGATECALL( )
-
TransparentUpgradeableProxy.86598a56( )-
Bridge.enqueueSequencerMessage( dataHash=7CACA4B1EA450C94E993452FAB5B8213D6C47F8445F3FCAF72EDF8A2C25285B1, afterDelayedMessagesRead=193228, prevMessageCount=14351141, newMessageCount=14351455 ) => ( seqMessageIndex=23847, beforeAcc=C98483ADC14AB2EE9E6ED6F5E895B11BAA50B401C21B3F2E04BF2D8CB70B4F39, delayedAcc=7A3090E82BFE79FDCB87FBBD7118441F5EBDC6DC436AFB023001473C49F667F1, acc=E219B7DA97E5CFB385F1365C982909EFF4CA3245F30986458C4E8F90371BEF30 )
-
TransparentUpgradeableProxy.7a88b107( )-
Bridge.submitBatchSpendingReport( sender=0xa4b1E63Cb4901E327597bc35d36FE8a23e4C253f, messageDataHash=DC9D42597F0245FE85DBF96C376DABD55D02B6C047D3D8DCF5F39333C4DD0C99 ) => ( 193277 )
-
GasRefunder.onGasSpent( refundee=0xa4b1E63Cb4901E327597bc35d36FE8a23e4C253f, gasUsed=208225, calldataSize=99204 ) => ( success=True )- ETH 0.032544367509566985
Arbitrum: Sequencer 3.CALL( )
- ETH 0.032544367509566985
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);
}