Transaction Hash:
Block:
18648852 at Nov-25-2023 12:56:35 PM +UTC
Transaction Fee:
0.034784283886392546 ETH
$76.11
Gas Used:
1,845,202 Gas / 18.851206473 Gwei
Emitted Events:
| 113 |
TransparentUpgradeableProxy.0x5e3c1311ea442664e8b1611bfabef659120ea7a0a2cfc0667700bebc69cbffe1( 0x5e3c1311ea442664e8b1611bfabef659120ea7a0a2cfc0667700bebc69cbffe1, 0x00000000000000000000000000000000000000000000000000000000001260a6, 0xf6a8a78dbeb0e13dbb5849a2164c9ff8e80d02813c782bf2ef807e777ec0d835, 0000000000000000000000001c479675ad559dc151f6ec7ed3fbf8cee79582b6, 000000000000000000000000000000000000000000000000000000000000000d, 000000000000000000000000c1b634853cb333d3ad8663715b08f41a3aec47cc, 4a168165d783a7ce1ec3ff9564227a45ea240c43c36f93cb6caecb9ba3ea5caf, 0000000000000000000000000000000000000000000000000000000460a3a4c9, 000000000000000000000000000000000000000000000000000000006561ef03 )
|
| 114 |
TransparentUpgradeableProxy.0xff64905f73a67fb594e0f940a8075a860db489ad991e032f48c81123eb52d60b( 0xff64905f73a67fb594e0f940a8075a860db489ad991e032f48c81123eb52d60b, 0x00000000000000000000000000000000000000000000000000000000001260a6, 0000000000000000000000000000000000000000000000000000000000000020, 0000000000000000000000000000000000000000000000000000000000000094, 000000000000000000000000000000000000000000000000000000006561ef03, c1b634853cb333d3ad8663715b08f41a3aec47cc67d81c2b05e0a9e4648c6844, 357a2808853f8fa087ae9b93cec37f1acf71a72c000000000000000000000000, 00000000000000000000000000000000000665f1000000000000000000000000, 0000000000000000000000000000000460a3a4c9000000000000000000000000 )
|
| 115 |
TransparentUpgradeableProxy.0x7394f4a19a13c7b92b5bb71033245305946ef78452f7b4986ac1390b5df4ebd7( 0x7394f4a19a13c7b92b5bb71033245305946ef78452f7b4986ac1390b5df4ebd7, 0x00000000000000000000000000000000000000000000000000000000000665f1, 0x18757dec8c941207c7348ac525f3b577bde75b9810bd24270bef539284cb251a, 0xc2a6e7890dafac5b56e7609281f5848cd8870c28bd0d2b313e2a4a17303d419e, 30ba334ca38f125f23c64acbe2e94edecc9bab3d47a291945c7fe4968d3956d7, 0000000000000000000000000000000000000000000000000000000000126086, 0000000000000000000000000000000000000000000000000000000065609d83, 000000000000000000000000000000000000000000000000000000006561fd13, 00000000000000000000000000000000000000000000000000000000011c7894, 00000000000000000000000000000000000000000000000000000000011c8f20, 0000000000000000000000000000000000000000000000000000000000000000 )
|
| 116 |
GasRefunder.RefundedGasCosts( refundee=[Sender] 0xc1b634853cb333d3ad8663715b08f41a3aec47cc, contractAddress=[Receiver] TransparentUpgradeableProxy, success=True, gas=1883238, gasPrice=18851206473, amountPaid=34784340440011965 )
|
Account State Difference:
| Address | Before | After | State Difference | ||
|---|---|---|---|---|---|
| 0x8315177a...4DBd7ed3a | (Arbitrum: Bridge) | ||||
|
0xba1951dF...3A57E7ed1
Miner
| (Fee Recipient: 0xba1...ed1) | 384.664451646368490821 Eth | 384.664543906468490821 Eth | 0.0000922601 | |
| 0xC1b63485...A3Aec47cc | (Arbitrum: Batch Submitter) |
10.000914603984450541 Eth
Nonce: 368099
|
10.00091466053806996 Eth
Nonce: 368100
| 0.000000056553619419 | |
| 0xe64a54E2...80E2E4eb5 | 57.508634902687596727 Eth | 57.473850562247584762 Eth | 0.034784340440011965 |
Execution Trace
TransparentUpgradeableProxy.8f111f3c( )
SequencerInbox.addSequencerL2BatchFromOrigin( sequenceNumber=419313, data=0x005B55C31345BDE8CDD09108FBC0585DEB4844B0713018CBCF417C1CC68DDDAA7CA25CDA428499939DD122C09D1D45879CC3D3DCFEBD7BB76862441F2158D844E948A3C684E177C61D514AA481CADD760C3137C0A8FF6727B36707FF7F1BB3A918C0638A7ED0EB51CFE222F08C4719BD6F9AA5F3B13B28AC8C8DD644B2E77C8CA1F81720C429C8A1AE643D28E3316F79A01B1C6F68644019E7A9AAC50D3FDE27B9C3010D1675A25BEF7038E7228FA5E4C1E8CE83F3E5B98C149DB310FEF0C94DE11C44BE1E4D6DCD9F33D156FD65D43538F3B83CC74C2648F63299504190707941A22C61901E79BE76014AF8661ACF29848038E0F6044F3EC2FEFCBD3FBDF7CF65CFBE41094CF133DA73E2DE3E26B5C10A34D004320DC300319D6380DCD88A2C9560CB64A876B2D3FE587481892484C021DB6F944D1B99D710FE4D54F4414ED2B1D4A95319598304C10F1A2244D59A95E3EBCEE9BEE91D9AA25850B60179ABF4884DA3BE55EB7116BA2E6F3C21710008845FF50338D6BA47BBF59096DBA2BBA2AB60791F94161D57F9A776CB13CCB8F68F6A3BA71C9ABCD7033DEBFE737B548036873FA69857EC5FE695EF15EA55B2AFE83F6490577FAFBCF9E93959B9C596B083E9F16DF6442AA718896BFDDB3A165820507B243B4F0567BCDEC0F6432E831F980FA033C11D41A15C24A5AC445E86FA1F3DD8110C1075EE25FB2EDFC03294B418181BB8EDC4F0982F0B45EDC38C544E0410F23C5A39B7F6D6EC7C02E852808D49A99140749C36F6147AD17038CFD3784F5F1A253B3F4FE704C72AC9736C0D0180435367C9799B330C6F2B67DDB29612927453608C49A9E8BE758DE8A83265810F80B0DEECF04B3F141785D1C131075BEE51CDACD5CA626DBF80D3472838A2B6380D3B2477E2AFDB023F42209F5E81E8AC24AE53DACA923F57041A001C4473B39A2FB25D506A504D86037230A8542820D1D2164D941FD355245804431B54825BE0B4E5533F519E191F4A345243755B0B18364DD6FC93EBB906FBB5D47DAC5AB77DEA94C2973D27DFB538BF78C8F53C04A3E6DA2855EE794AC9FB1770359B41AC5956E32C698F3BC7EB0565B20AEFC52D0FEBC59210AF8745CF7FE7E2CF0075181FAB1B2B09BD55DD45D0731C55A10042D60BD304B561B5F167D09B3D406EB78268C5195E2773299CD6D6B05510D58BC8AE1DE0DB83F88C42A0C8CBFA83612949525284031688B5C8E30AE152C27EB2563D4F6A69BC5FF40B7DD80FB0392710FFC710520F980635430CD7C6490C9AD14A917160DABC600D017F64D9C0F3E0FE81F1908E93945F0804A76B48A07A3A2039FECF3FED9B5B7FC0E5793E248661283B9EF62FC53CC99763FF0F028BD7DAFD387F539A021196733DBC8F6E0F5963EBBE33F60CC322918B947F2EB444EF3C171E9E23770291B9BC7A2F00D023C876CB2C3AAA6635F201AB7E0FA6F8394A08BC7B5C97112A29650A497EE7B8C96E1CF475FB9819EA8E851266100C46530848C93918F95F6539AF15403A70D0922154C219B6C17680BFB580B3B26CAAD286782E34DEB4248735EA7FDFB7882B6037E954ED4DBDC44990AFF956F08B9CEB1247AF67F55275E9B32E323E308716203D4432BDF1B42CAFF1728732DEB8AF38408963FC402FDFB585201834070B8F303446D0EDA4C1187FEF0B7FEEF23EA6D187885ED268C5E13820DD5EE2FF37A8AE122240E74E3FD17E620DF0214FFBEB9FEA6FF080ADA09307C6727E87C5F179C62E72290CF8FB3B1F8189E9FA1030B75AFD53621315FD2C9B5C0ACA827182E4CCCAFB4FC14ADF40BFECBD4ADDB1CC2AC4C2F85973701621FE917249865FEA6728E1C865419F88C4CDA830C0BFBB131F69919A4CF758A44E651B7AA19568B5E50CF95A6E5FADBCCA9FF4CB0A16632DF8A4611C1002037FD31F0CF544A7149506AC34CE2E36AA04FE1138C5BB6F37F3E83D8FD82AFA0300EE0A3F095DB2C000F2B158D8CDEEA099C1045E358C762F85EE737247DE8D1704C04D3FF915FD6FC03628C3CC1F96BC4A25AEFE5ACB57D089A6E0EC72D2035E146D5EACFDD6EE55040E97B912D766CAE8FFDE5BF5C1FBFCF3BF7C8685C16370D54A83FA21E7EDD1B1EE2F9C3235582D9E8E5C160A11D7EF1D1F20260AAA9D61C9B507DD033E15D9D365672D528CBA0AE22F9915DA07E04D21ABB667412BC72B5865553319DEE03A60C6CACEC79149393D7CB54EE3C2935A485E97A908BFAEAA8F2A5907BEB1821DA2600D3EBC1EF7B78118993F31760ACF04A28BD01A883BF5ED08D5E42880F7092B6BC16E3BBBE719BC9B4BE5912E30BE19640A46E01282CDB69B4AB0A864A46EF4565889D1472117F55A0DD8743EFADA87449A42C9395197917B3D95AEB3D6861E65FB8950B9627ECD565A80E9DB22285BFF6E312AA8C6DAEF0B305B06D9BB7E3A3A3A6503A645CE4790EB29CD2DAF58ECF0685ADBBC6187C9D21B73B193FCC437AC059D41C4ADAA1E2FB0615993203ABBE27F290D0FD2C527056FC4A908CC45841E1ECD2B41DC3C011D60A22170523A2061EA15E036A105E4AFD67FD1729030B2D50E4C916CEB1F141DB3453E520208D4CC419D70269DD9F4FFA823667C0243DE89A338530F08EE52BBE27F20F7451AF5910B12470C88A301641AA4FAEF0BF983C44180640013D4C11739F48F01911D8A0D26316E6F7DBFDCBFE50D7E4390E526B3A88238580BDE062E137FFEFCD2FF7B16561C4999CEBF11D386848B35512276C9A683745B436BF88F6AA540173994000481C81200A0E70EF4F9582157C9C63989FC57F8EF77FD6730C25F3A2CB1BCCF5D5AAECE2F1EC053D92B3AE164A35A2E6C8B8154A60FE6CE8A52E254A7F54EF740E07D329135A8761176E12A9459262C98C21443A342F8B3D7116DBBD961B329A12D55D1BAE2D9BC2F258B56D6F71ED5BF02A3E6BF6AEBC94482A40D4551642A1595CC345556470E042412E40BFA2D865D91FFA137FC1B3284762852169EF9B549E5572100C1A4A4A183997B2E6BC782C086964199A1E134529CA216B93E413F6827D3EB16B9BF758EAD04B79D5C6F13BE963E0E7FA220457AD96EAF0CEC4A9FE302415F6738F19CF6FDEFCDE18F59A20484EA88DE9A91CD16B2926347D295A0AB36F432EC2258915B98F2145E2C8DE8663A1060578EACF69AE6056050BCFF0D45F03E4B19AEAA392C5034793BD4B41419CD04A7966C60530A3BD4AF600540CC2CDB6519024850B89B2520207D8667D484D2A4ED4587F92C72AE3B1155E18F9BFEA74C766F4A1DF959BA6606451A8080A807FA0380069C8265D81F571599B9249D5B561426B8ACE0E5FB64580710C47D7DE924C1FD801F956A4DFA7ACA5EFCA88603567DC77213B67DE73243DCAC650B05CFD9431448DFA9091471254E39A6C37B9473EC81B40D7D9E8F346A2B7D8CDB807EB984B96B877587890487FCB4D53FE83A548A341C8D7ACD8887ECC1E584F92B7A805551FBE782AFB51365BF93809DC15B87C34CD9510CC202DA4AC0206F8A6B3C4C53FACA30602150EE2924CD92926F93B970D2DFC9E09DCC73DC5205DA93774EBD82907E58FAB87A75F1EBF58AE874427D5262556EB8CDBEA74EBF56CF7AB33A5345EE850185EA8C4BA4558FDC797877DED499B9B44412FC55CFA6FE7E817BAF09908AB9833CCF8787EB512B331CCA454AF8F5F06FC2725A71EAEA8974CD465FE63EF11106DA1AC20017611B06F58FDCDE5901924ECF0D8EF86DEECA7011231C69D6EE6FFFE79CEA6D800DB5D793168365F9ECF69F36DBF9E4359305EB74D0E88852269EF4684034D4152225BFB685C1F0B211215071EE01C1509E2E29223A0AD531CC615074899DC6FF3F256CC35AF0F322A02E3721CD86E631031486D750B6F71369B32F3AA5BAAD08DD5F003084274B10353E36BFCDE1A8FDF6EACE007EB10DE164C1E91DDFD0DE9DDD59EE296F8C2ECC8669AAEE5A9C72FB6CDE05CCAD99F604F7E87A28F1C30B1799C545414710E9C6F9E63DE2C995399B38BC0FD33D26E682A4D69A8E959F5B1CBBCFFB12CF327D9E42C9C24F20F08628700D0590DE13034D30EEED5D9AEE10E270A9D3AF35DBD6A39BDEA61E3923D7CF21A39529B2FBD93B82C0385536D8BF9029529CB8D60BD68C061108ADD72566F577D06C685BDC60FCB3E14A19DFA7AF34EC4B4701449DB5EBB76FD0827A9B4E0C6272FA2D59636F0C50925F3B0818A895F03B1A925A4796DF6038730C4732E8EC58680449DB98EBC319499B77BA35356E8D151025463F0F09A6806B1E8DC3E234FCCA065F9C802F235533DE9579007F3FE66322508207ACD2F1D7DB18A4C9083D969B32B89110435B66D109200FF03C58AF2DAE8177FC5D5DF0181AC3B9E9CF6F64A406BF7D737FACD2DE20681A3DC160D856E2ED2216959C8C28C3443A38CE6FA4626347DE1E21E0FD954FA83DD63AE0A7C784350CA5E9558C2DC0CAE5013CA5CF285290A93F652B02345FCA8598AFB1A39F6343608410D04955F7EC855043F4EA6439F95EAB55EB6458006EDACC243CAC1277DDFF2275B7FFD4468CF595E80967B079E99049867E2D84D8857007783FEB19F6301FB91FFDE9FC5358AC985569CE06D829FC6820952651BF035099B57DCC986C6B3543A8EE4A6BCF7F47B727C69B771FB0D661CB962E980FDAD303A9E3F829F9EFD69ABFEA17E7897C733A3FABE4BD998410D4DC0ECB7B50FF42E51804260574E9B3B37D0C9EAC95DC23719D2B6599F84E7C2405B7CD25008FDB6FD3A932145199431574401434ADEEBABC5E33AFE9BDAFCE47CEEBFD121C330FBBB53F897A18346C3E5B4A22C371A2282E011AC48998E67790327094672A4917280AAB57D60412FC4570868E6DD85DFC07BCDD7A563E42177C4C3A2E06046545D2D0DA54660202620105FE9518443BEEF2EF778B1306ACB306F38121C684BBEE7CAA70A6967C617884990252971AC8EBA6C7BFE06EA297C81F8A05D275166357F1F6045F1C0529E3B2E68CB5DD0395A23153F2F2A0B483791BB4659E4DFA1CF061F9FFA92E0CDD847F51F6E68F993AC5B265C1D1F2F47814DFA33BC3AC0D51B231A5FC46D151B3750D005188A8D5419C37C436759046B842F28F29E3017BBBDEE9D63BE39ADE98B0BCAD1ABA6DDDB3126B5B4C39757AAEC569DEFEC491E1925C0A7082BC06FE34206E156D3CAD0E2A34BC8A7DA2286481D1D2B660CCD0CF4FCDE82A3B0E7510A0FB3787569C7D62F23085234D7FCA1D322858C2C61421E16CDF4D52B7255AB5CA767D02257E2046E9672F88E8512A685D1BC0C6FF7E999DEE04DED8D99774FD309A86CC862B1F3E0A6BE14AE16886C063166402B8AB9BE4543427C0BCB15AEDBD0886BA3B3503579A7073FD3B251A3FDDA7465CFB0EE22E7C6B8AA273D604DC8A12378D7D433674EEA98F50AB4A534486CD71A36E1A74ADF1C69719B8B3E6C35F61819CF93B7DBF39EAB11386C1D2C31F5337B72C33E597262AC065A6ADC03FB6719CFB9FB4E682747236227462D0DE7F2AEBBA5A6DFFF3BA134ADB8DE1F19598315626B693F43FA7519D70E4F942836C98BD61D45C11185088460EDBCE7A0DE4B55EAED02446BC4AE4C6FF1EE57B26B24E60251348F60544FED005DEDCE9BCCB16CB5BA6EB868F7D95073DD2E7F060E18AD5D894BAC5067540E90C94AC02E944E54A3CD828DA5A44950046F6AE7936A5CCA7A316CA6E02BCC931DD13D1A887572DFC0C34BE15CAC455AF04BCC8E7EADA6984028D9AF2B526002ACE1FF7DE70F709B5591FB960C1904F84EE008ECB6FE5362306BEC21AEE5BD353118FFD5B89E996B893EE446B71E5DFA7620614223482E496A76C1BEF082D64FA07D1365D709B5741646D7C1953B768171BB1D006B4FDDFFF21C9C20F00E754310B59C0F111940F67C8190EB75DD37A30F1FA98CEAC4E91D42C8CDE84FBFAA2BB896B257657C5CF6334D88DBFA6F4D2A4DDB1BCFBC84E3526FC6B951777A9FF7E2E43A828A4F1CB98783C77C82194B5FD9BC091BF360EA977BC026063A2D59FBB8371B06C487605F39C820F2346F66D93E9905DDA08D25DFD30322EA4BE8A1277615AFF287D392CF5467AE0E6564E5D11206E68B38DD795CD188659114F2130C27EF3A857510734B2C87E22D8D9B6413A23372F459710D0669CEFB38D6C10080B21BE7C75CE12DCF884E8ADE0955A0FDB2314527A8D32A62690CE9438B5A6A9A3077DF8C353248169E9EFD2FB78342F15F0D203583B9D07C394BCE96FEEC41ED35214FAB3903AD15D9819D0E7F0FC9FE2EC80EBC05284A22AB9F75BC3F7FA02F8BF25E44E9D9BA52E4B3A7172EF98B3D6FE0634060753625735E32D5294BB0F4FCC8AB799CA920121523659E0DFB39467F4BB895C709DB9C0CB84ACB6F3CFF0528080E316BB7DAAEB6EDC720107DC9750960F44FFD0AA2063BA8F062D0412C0FE23D7937862219A01693A0C5992D5F624AE94F8FCFF13FA7A0A5BFB99105D30F5F6F7052D8EFE1AF0B6CA7C9DC90AD692854736C5CEB665B9F17BD5CCA94BCAD341CC93B57A21FDB5038C7D9767D569625FCCD376F8DCF4FEB81F8B23F9C9C083ACAB579464BD8984CC474F88CF0EB5123B46238F837EE5AF4D4D9F752099C55FFAD0F38E026FC57593552BC6F06135CCD586054095CB171EA7DEC1B4698BC0DB967D45C4AD00B83E7FC250930F490A45688CCBE75C3E62981E2CF2069FA0BA442ED3E8C30B41A02758D0ACC421CCF45D9C13198876855691C80EF06281914A18088E1C663FD2B44354322AF90CFE0914CA6878D1BCD8AF29BFF04558DD571A0214070155DBE586B346C19B18C717B53FE024A6660D74221928EDCAE9A9DC95D922ED1A41E0A01DB00520C8F7B933D70594F8EE7402E4779D8B0B733F0EBAEF144232D0F0A582DC2BA00BD1042AC371A18AB81973CA7FEBEBAB8226CD3F5A5B42602E39B2417717030C4A2B7810C28B89708645D162988A2F3D5C9062EBE8EE3369F1B8E4A176288E78555800F1066DED0F1F7DF7908094E324612FB8AB73C6C3EBFFC4387B983E90619826011DA01042320F9120E1AFB60BC67A6C464792703A27F4F2C8A3A0BF357FAA0304FEFE0CFF8F718A3CF29D5BE70AFAB790EB2784D92C13086E536406C90B540C0A1FA2C0DC4923C36EA400BDB6D19984F3C089E0537D2F7C17E0F378767EBF4CEDA9E0602CB796B0060521712208DE3938F7D22C1EFD7FE05C8CF0956641C493651C59A4F7CB9AFCCD9E6AD6F9BF650184DBCEAA39FC68F93FB27A01BCD854CC603265891FB553C697D7755E15A598C6235C937852627915D1C976F677CB78D9D991398EF706A7D25579BCF749CAB1030D4482E0A09EAFB82857CC702D9EEA6211B58F388CCD12E252EB7BFB00CE5D115B8F4E1FA3864E509D5CAE2B92850EEED453A960ED4B187AE8D1817C90466E81264662A9EFC78E73EFCCC0F63D896EE9CD48C96B4AE9E0D652CC518C61A13D6FBD6E6BEADAC584BB008071C8DCE39930A6EE1241083C12BD67E9403183CB7C36715BC583D44DF6EAB8C65C2C581661ECA0DEE453568E43FD296CDCBF4C692148C72046EBF365EE7D8E5DB684C1C321DEC69CD405809C80C374D5BFAB41C2ADFADE6D49FC097162DA9FF4334D24F7CB48C3E4E218F83F422D40683AA7722631F506D294718C08E9A74703DA7A35F344C00AB2542AE525C3BF5E79D5CE140585298CB617F9862E350692132FCEEBAAF7665990165E883CFF1F178D8E483372F300CE46DEEC1DF4870CF38C3C6ED4A4580042EF30C402AB03EAF3198420662F69469BC376A06017A9DD3644165F65316C33AC83D6DE9F33088C2744D38219844D53BE1BB551E25B6FFAB1ADE4E8A22CB0C4F003B5E65417EF090E78FF2C422DAFCDAD20D63CDE551CAF94118DBBA0A11020C718337195C5CD0A62730E80B6D7F54CEFE49591E477254ED48D1770301E38B72F942F1EC55B32E6F0FEFE03EB9BF5A9330836CEC91C33283D582ACD945B5E55250FBA75BC65AAE0B87411A6B2AAF33FA7F47A5E2C1E9CEC9CAC5CD34FC166F8CB98CBE8D72F2E16AA63339CCBC919FED69C3C5CBF7E99B0FD623BEC97F1F79A257855134E1E4E532EF6A8EFE3620FBC39364EA3854574DB76910917FBEF67B0B1B2B1BC692B0A8626FD0180D82F703FA70041C2BA970AF8305FAD7CCB0AFCFAC82362C8459E1DDDF87F44DF0095A718E2387C8FD8E55AA249CEE38EE1F59AEB8C2E0D73E64E682139C83F0C51231C9D516D989C9B9401293786B582EE40B7589AA3291DF823F74750AF8A777B68453CBE95263E2CC03778AE5E8FF932FEA6AADE85E0126459A5B088BB9730A04A8FB187B8E950D4F62AD569ABB1B9F80795071460413190A6FE460F3A3E9A680B2671ABC4A7231D8716BE4D1EAEC6F1CCFF030219248F7DC6813F110D3EC2CB132ACCE9DBAD56CADCC10D917A1B673F9CFBC3261141A09E8C391E40A38FA27B0AF2DA55D573204E4753D8FD7EFEBE11E31D81F92030CBA22B11837B97F56994581DFB579E36B44AA18463A12BDB1A0336CB10010EDB0169F7B89B6629A674F04B147AD909C587880C1B2B3B31F101750CE1F4C497CCBE12E0B2A2F12C8D718C0499564988D3720AEF6B157229B34F3EC93B9257253C3DCFD701150B82D6A86939865F0579AFE51EB202FC70400F440720419C6EA1EBC767C23F32A369A32F7448836BD64E80ACE7BF876D59789D91022F89DDD758013176C2C053F0F44215EBB49275128E372CBE037FDDAA1702A3C1B7B2A4E47D041021D2E477CE5AFD23EEC048D2B9C05B5BC85818DE207046246D7356E3CF1551765F9D3724517CA5A391C67C50FDC097E754314751C0CC9284C577AB7DFC4D095128879A2B42F0E7666EE21472B68672953A476CD0D7381A43F728F18F4D5E5A91D2DA9B96DF92C18E68F608042BED1F2DE30DB6CDD3ADF27C727ABBFB9B8DC80C2870A918B093973E301A1938535905124A03D0F1AEC7DECE38B2B23C74327950BFAFE6573FE00CFD7C3184DCFF8438A595A4B1DD18A654890FC7EB6CA73628BA7985C662CFBB0E5EC171CBF10D1A9F87B07756431D793E8ECF29658BB5F96414DDAF675E2377966EB85D41462E7C0B40CEBC5F3553053E189BCD563F7FA5A097E6CDE6986586D241E4A019BD299A2DCD96DDF2AB1B4ABD63E6964D6D9EFC1B8F634A267A415EB79C5951D0D969DF5909AD9962F948D738E74B500AE7452F159ED0FB9018CD58498256AD1606621A37D61EDCB59272F9EC782DE44DCCF803168C96939C17782BFEFADD570AAF6731EEC0DB0B61CD7887884E64A0D77CA3038064469D7160D40DFB4E1C6DE367837B186454CAE135382010ED088F050A563821294BE1185AFC88B19F697AFDCCD609B35E6CCAFA361E860560827F12A4C47D90B9ACA1774C8F37EC167177EC5E91A9DFC21BF0DE3826928A4997C52A6EB8AFC70D5E55859FB3C684EA0CCAF69AA9E4E9E6D1E215F0502510A30E51F67E7D5665DA26098BC99BB19022FD897823C7269320A4CBC5C638E337C4EB8F6050DF971098DBFB01C14854E12998701AE7277D96D397849D5AE73E58B6E39E943C01ED210E2258C720611C904D0550E635BBA724F8BBB24F32A89913F97D604520B4D1E15B7E88F5976DAA9F8060E8E232D2D2B076D854BD3E7D1F612D334E1153CFCE7CA4C71B1195596A3B1E539AC605A67FAC4693008AA58321462EF5DC6246F691D33119DC7CB01B9DC8268749F5F95D13C02CCF6C9D1C4899875A284E0B9527EA98F0E5A7CCC81D7DEE76C3B39F15277E70CEE1A8B189CCFF5136C300A7901F42ADD2F7C0B462B9D1397BAD35C7B5A0F71BDA12A5BACF552CF341906D2670D1853E1625867DADEB2C1D39BBC4A6A749304ADF43494BFB050A6D7CF9A7F60EC41610749E416A13948330A02A79B2EC5B131C4CCB360E9A3BDBCD51E245DD864DFA5E5202450B9C96AB1B0A80BAA6046D22DABEBD3838440E3AC027DBDBF21BA107059DF1E67A11C98CFAC1E2B907B4ECA9064A4EAF1A8757AD542F3A117BC276B34FE71C0BB8565664EF633CBEFB656F5B4EA49C2086178AA97E48FB8D610AE7B2DDB37CDC56B31084D201883701ECD6C806A29C4C9599166C7FCB4E6525E76021474D60B9FAF6859AA211AC7DD6AE65E875B19458C82778391C71A1EE9582BBC06A76334AAC2D5E09B98F96C44ADD078A78A39F11C0A51F4538D9FE2C5B35F9CF07A6C2AD0DADB2B1BA01CCAF87ABC9FBC946C85DF603DDD93B60A5953AB67022464CD37A226D87A50523A8E36A9EF8C6554392ACABB2A3D0F5F7670A1192AAB53F2BC22FF8427ADD2B3868D58189509970B0D9000E7D03900ECE91ACB92CE399F4EE14C704821F730C6D3C4D38EC6975154526F4AFE38B0409F9C8312692C4A6D98A6136EEABD01F2E838A2284308B4C4C53166192787032C6A276D243552F3FF6A46222D2EEEE211331F4906DF8DE202113C8429F61C47C17A75185E877555A1533C29D0D44B0EBFD562BB30B0556E69E9A0A5919460E62DC710D4A0E52D8026205E4C8F2E55342CDEC40084A642EB38915710CE6EBED8779FDE92C93C8185474C6B68C3EAA3C1C5C4A582F871599592E8B57CAD06FD8E9C899229324524D3CA474BFB47E36EFFACC239B67820CDCEE820C020901F1C30001ED65B854FA29921724E40AD93D65D840A28EFB0C81164D1D61BDFDD11C60F9DFF3C0F92F2C18E70D5A2E026335BE54269172E289428B1C7BA2A1023447335517299B70327419F19BC3A61E888CB78E7ED3D13AF42DCCD7C80B3C429C3215A2E671C5CC75E376D0FCDD43ACEF2E0FB0BC99FF2CCAE482D6BD8C2EFAA96B40F0B44534AADDFBFD327E538C6E8216B3E1236A02D1EB1AE1EEF81E4BC4DBE525D3DE7F0CC6BCE923FB06503108C2A0C0745D74289A884059537DB1D49EFCEAF515932ED7B7F32347BA1A73E60C2B1129203F1D759C18D026E188DECDDE38F9FFB168016892085103ED3C9EC618C1D6448EBBA05F45FFC31386A8DF4516365F2D2A3BFE1BC53DAFFEBE8AC80F19B8A0A4E853385A18E700C5DCAE75C43F925E383D5FBCF8C13A9F3CBA12F5F546FEDD7D7B65C9A1883CA0A238C720FC50D91104DB53BAA7210BE2EBA99ECEA34FC6BC9A85A867F66599EB5DFA935FC37D8A412F18AEF97FD92538997A410AE7A51ABF49DADCFF89577656B586050C665525D5457684B7FBA0073AB523EBE615532E769F17AA3B69035E19CC69D05B22578919737C288401903CB3379B465899C6B80A7EAF9E6C9E25376797D02ED705D8205B2337D37B404C6E206987C1278B2A1E041D99F8D1A4A8E7C820C9715834ACA96155E1D854A6437865F80402EC0DAE78C766977CF91BC28E0C8B01D165CFF5A70C990837172B3185A367CE387AF5AC4B54A17E470474809A44B09AA8BD46447B404AD4370AFAB027B50751ED414948E94F6703FEDE930E6708C8101448B217FFD13D5216E8D9D4190759EF60D8D8B31E9D77689BACD1E3D6F2285DF6F24B2E038ACFF3161C596123A1F4252FC0CB93DEB5D331EEE934EC2DF9B1FA84E2CA30E1759BD47FE856762580A8EA828D3E8C8CD35B776AFE6FCDF2FFCC6AD1F36DAD6FB075E269C892A309805913A7205E7A6938F65750F2AA50E25B69EED6E00D2886E57C580C12A5F2F0EF4014EEEEED787236AB72D26CCAFA93E52071B040904B3A447D89AC9B1940115E42EE9DD0A93B94C288293C101B60CF451124DB18E914CD9CD0FCB4B8F7F5D6FE4B6E03EA2CE0FFA4E63CA0E37ED13F0AB396F8A2C4CF267245F58BEADB0253198329CDD4714A9FF8C6714412A1D43B2A89D27D5378C9DF447030602E862950AD5EDA3C1152A6D24BC2C10747087A49414E7040824631B406FE64110C981890780C1A07945431ECF06C58FA12C87BD53260378903295A11B0FB2CDF151E4880B8FB4B01487EA89F2EA768F6F81528BA5C919B3F458DEE29ED2400B29A5905E827C8FE8F870FEB59947397EB27B4CCAF7834A01CD9BCDD7C3CFF76BE950263FAB9251EE1BC76C89E5061EAF0412504DF7DDC055DA7BA88DBCCED2C4C2C87D1D0995F100264957689645475FA497B829DB234EA4AD6069A8FCCACFDDF87F4B73FE8DF43FCFEB653D37BE3A6AEDCEBEF65B2A298E952BFEAB17F88910DF66801053A2BEFFFDC328CBF95D1D95ED3E8DAF1BB29B4D07CBC8114DFC37EA8A0081EF0C96F231E87BCE4FC69B4859ACFA2C24C4EFD4E13E9AFC72C4736CD1BB4114ED6F427BB1542DF94B874B820A4381096B236A928CA8A122F4FF319430AFC0B1D1E357E389714B027B77E1595B47C31B68430B5FD85538105DB4E1D01E94880A57344336E956A0467A3D855A9BEB9C43ED4DAE8B214637868140FC6B32FCF56C407F503F8A3C839E3B8525E29636818BD89C831824E6B06CD05FB7BDBBD5528FE970D67DC03E6B672D57F3D464A112FD597E4B6E9861F1034CA595210B2C7658C2F589512118EB43BBE374789718E1BC970CC6EFA938A2B52F5EB04CF2E222222C007592203CE0CC6EC2995ED189EA72FB5E6E95A1889EF4D6C36BAEF07283CB67201E430667862A4D20C2AC77DA39EF97D09C86E44FDAA483F392FFFB319D074F3DE713B9F1B4A7C2DD25D197AAB244AC3D6A258EBC77C8B2C44E77FA0F1EDB67E8DDD9717B20A3112E8B8F74E0560BBD68879ABF5B36FFCD5C3E2256E9306B8657CFAA5773907B7E9A35077669A0D31420A67AAAEDE26DD19DCA7E37C11D7DDAA4F0982C4E881524D0DE7148E820F6D5A1C0A5F615FF4647CB681B91E2277F03151B34822F5E0E981DA7996F95D8F33C7B8C5499DE85C7D69329672C2AC3881F5980F69B10100B24C213CEAAA77E1ECEB0103379866399520448D04916651C4342E7331065ADAAF6EC623ADD4E9A67F409CEE3292029A6E29B388C552AA2885A2C3BFE179DAF8EAEF2AD694149B6611F2D7755EAE5464C1074E84B9C18254C0883565007AFEF79CDF8B7371A7CFBE18269ADAF8CA3C079F0A95B358CE633E0CDD830624DC9CFDD5DE4FA546913B20B9EC60942EAA3C1ECE1CD5C477F928CFADFB346B85D3CFF7263E005C2635EA84EBEEAD77B5C4E61AB42C7001A95FF1209EC60B466B4E568D413AB0CC3CC1D6B10EEC33639C20609CD2BF4757A28B7218A1BACF6752BECFED0561810752292CF7FEAF1C00628E393631AC01591B0B41D91AF174D3637C50FAE979FF85E274FB3F48EF0B71AA1F14A86FFED3221D6F4554757C837630B4298F17E7E7D19F1E771DDDFE4E8CD867AF04282189B8F4773201D148CFDB1691D7B2933F359DDF530434651A9EAF45BC352B1BDBF391AA0F79E2EEA1E4E550A69CA1B8A8F61DE91B1CB74A8CFFDF4A3026167CC2F5EAEC07D2084FD330223417076C21AD497B1A395E926E6AC779D44260205B01CC55FA767D9E615931D9FCD529FE0CC5C864E8106EF363DDFB690E5E3DCECE29A7C6FCC0C40667FB6D4F89C35AB8578E8EFE947B5B3729EE4E61A362A453769D2BC38FF22E5AAC88653AAB1B2A07CBF172BE9D78ED312BE78AFF7DD2F4934BE7388F01409317B4EFD0C2FD677606D32A84963FFF63B80D0E9193E81A18A6692997748314367B7D38546B8E559C24FBF2E103A9FE9912D08BACED8104CBF747B947F775610EB6B2CF12391C74B44FC9581024C4466A24BA1F14D0C69CF27C5A6244F74286453D64CC55C5771F93F2CAD198DFEFFAE04230DD1D05C4B06CC7894ABBAF97AE7A8F5A4A4C5525E334C324B6B6DE76555DDB4B1F75F18A60ED9ABDED91B183863EA4715E0F24E46C3709888E137B9C72004FD4B4AE7915ECAA5FA5FE3B2792FB7D8B1D3CA0F547BCFF0798363227667F6393B2FB4A653DACFD4FB6C048E7E195BB2FAFF0A5D3AA5B0764EB53435DA10673C788230393484365563EA86E5EF80C1F522E29A4D6229C3B9C584D80A72BF1AE941AAF01028F52AFAFB6609D72C9865C1C08002FEAAD42BA074B02863DC57AB02D3901D61E954613D3239FDA3FB895686B4A235A80B3B866B62B238363919D974BC1FCB1389FD8C9B4BBFD2EC999B713F2C2D6ACA0E44D808A28B139A8901DA6A05B228608F3451C12F7CCDC6FAC78F04BFA6C9B8CE873589DD4A31F80EDFC91E34478C1C2F08973A6EF78C5745CF25E81DF954BDBA81DD7F22610C6029073019802D98AD0ADFA5FB7AA61296D9F8CDFBE4C025C89FD50D128E8BE66F347CEC56CE17AA49709A4F089C193ED9211134BB2CEFC525AD4DDEAB641399169E37B42C269A5002E7B9575EFA00AB812AFDC5345D42DC1B9E78FA21EB4858DF5DCD7756FE8D6BD3AAA14DDD799343B28DAD8CD1721A2A4DD1B1ACD83707B13127D651924FDC41AB208A8BA04E0807C8EA9A724CEDFE5629142561F68657FDDF4A5B3B4C789DBF16C69E17D565A250125E57CE9B0FCA38AB355630873D0DACBEA55CA618649A565D0F1C680656FDAFBBA1BADDDC84361FA9781B9D06F31BA77407F2243396DB34D70E63631ECF223969C2339E1AEBA894B00FE509B03BA85C9CC519978A3CB73E87CBFDF1074C372B267C8B13695FFEB8734A885BC6F242D5E2BA4D214E37CF211F8A77F42EF93630D13D528924470FC0AFA196EDFA3AAFCBD01AF06FCA0C9ED19D540B85E90318F5BC521F76DD63908C758C310D4923DFF5E9B39AEDCE9875989F7D57FC56E3E348B1785B2727D406D0428CC08FD013F71C071730955FB8707AC8B795D21E8FDD8903BCC6582655DD07C08BB1D6CE23940103288F817E4814AF5AC2027A456BC78FB2A882C8FA28CD61FEDD0AC8B98D84DC3E290A02361C896489498AF0AF30BDDD2A27EE784F1CDA47107E16E06FF094527C85217199317F3C44D70C3AF288B5B68596D7B6292AB50A1B3902736AAE89728A0F8BF6F5B78B610C51F53F806D3A3D676CA8B9AB151D28F1379019908392D716038B3A7C8413900057230A3E232038FF207D7B24EFE6733FB4C058A1B617ADB4F8B0A3C6F0D66E1E703CCB1A1FF97A1B08B3131C18D31DB2119A8F3F5BD27134BF392DDFC5047401F4566389F89F65EEED3B1333299D085A62DF05F45D193F7B512830297F86D2F6151D206C50579718401C8FDFFAF6C258F1DB70CD8F7845CAA100ACF38DD946E990C37A205B3BF68949849415B77BB859484BCD10D1AD99C3BC553DA9023D6424C5321658BB09E8E925E5B12A3A6131717637657357DFDC0A279D3539F9841F264EA91EBA6E25F54711AACAEC8FF31E3460C3B7037C96AE1C9A6F84F3EE93CF7AF19274F01C8F55425C7B7133ECBACB173104395C6EB84012D061B6D5459C4285491C42DAD9DCE03AD078F1E80E348F3CE4154E715536D90224BE9661C92756347F42F7F5ECF7B212A3358955A338FF955165458408E37672E56EAD2A610DF2684456F086A41EDE25A3E1ADDC7B9A6E5192FE1ABF801ECC26842674D3BD632A317ED31956F6D0783D223B241520A3B253CD2A0521C473B105140D0D3A0BE92124B2A0AA94D9B49BD8178C4701441281EC59C1138945DFF1340FD8D67543DF49FCF6FFB8964EE54BA35EE2D41039CB8FF654B870BB6671E00DAC38B37BFF8F037C5A79CCC75F3B5D0EB2169B21BD46470AEF2717994C3725D9FD755648710FABB96E3C52377DE558DF6E44AE88F8FEBF366B3CD31587EA8E3A85B32DA526539038EE5EA406BA307D80268DA6C65869E28077757DCB8B1C4B2D1A3A6C1EB985D514C18B91CDEA3BB0A9D93908B110B99CD1CB6635ED6FAA3FC6C024EA5D2B2E8ED530F150DC90001739B367688B8463DD99DC91E6496FB5D83AD3A3E0ED7137C09EC6BD1DB3B0DAF7A1FE2F54E10286499072D87C94B093573812D23B750D83FF65DA8DA898D187C12C6E81C9974C2B829A9953D9C0B102AD28D1252372F458C2253D69A157692F404BA0CCB90CA6D7486886C22DE0CFDC9614FAB63CB5FFFE7FE2ED3C0C5740A4495C79035E716045796745EE17BDD9D01E49F895DEF5CA3401B2077F578178977E4A881DB551DF28510BD80FB29CBF46429D228A699E9D2E04D93A31BCF1A7922F4479B28B5E8DFDB4DC958A572675DBE6E6625C37972409B0104FDC48EAE357E689FF96CCF7F3808A2A97B8848F0DB3A6CD2C8CFB5F53AEA58863F4C62418903E76C4290D0CB3D9263FC3CFD9905B63738B379C04B0FD9201DE3A662F774D4190F672CC3544FD72AE62CC1A9246452ABE9564F4B0B586B3120176A39A744CC9AC934F77166EA1CBD98333F3A92B6A2DD13D475935D179C7E449C12BFB87ED07AD18C0B9F7CE6093A16C1D1953E31BD979D453B07E74037F4FF9CD343C0212D4EB5272977B166339CF10D1F8E5F68EA0B6DC025C0A226B133DD94774F560C9876597059141BAFFDCC39EE85855D679067428984C26A997331341348CAA60CDCC9A1723A309A22403351967B2EE37B8BE1AC079A6C15DCCE39153783FC04B9FE36104F45A3FF2398C6B0054A9C13DD49B61DB6D48DA65DDAF56E78581F424A07073E9FE503FC0898EFBB67AF3A7CBF0B499CE37B7948E7E31EA5338A7E4F8A9CF559017CE65C7799B405EB11D2BDBB83FF780F3F8EFAF2F0E30A8FCE4F27DE7A19B85BDC76DCEAAAAF78C3DD475733D95C49CEBA1AD1E213C37DE04C6AEE59C2F1D0E2C5B7DDF90C905B014BD0CE1DF01582A57D1A6B3E712288B95DD447427BA51CD73912E81E2B5289D803DD13F2E1A5C4DEF2679D4DC2EDAB2CB2091410215CE4F99F4F77E035F2EC8D283D97B361D2F461A59790142ECA1926E96AB1E15C38442D9A02857F353144F321D87F8008BF8F2B21AC25E86498BF29A3DA08E104581F7530A8BFAED4E809017E722831C7B9F500A1AC2207F1196BF100C33F0A786F6305F0BD24B93FE68A2CFC478A6A8B08B9D7E75831507942EB0159EF031B90F2B954340930163A26CEBA975878ED6359F95FF1AB47A7A5CDF0260A9CEFC9B4DE66BA6905C38DA1B68ABF81299A306CE865774EE2E542444EBF4B369E5FC9A1CBCACB44EE753E85943E12F0E1CB94379FBB5EA8267A86EBF65BF43CAD5DCF1FDB3053D52B7C03677B4FE61BD37EEC21104AFC61620F9026FD4225C0EA25D624D3193B77B7B63ECEDE4F28B5B2C7242730A6359FBB8773318F130E3255678BE60553193F595823477500828AF4A69981E3558A39EF0C1AC825AAE1DF3436391828CD3AB7CDC756D10A84CC38E459FB8340A51E83A34E50A99D32A09D5BFF5F1BDFBF3D00CE44549DC45F92890A5128CA971E8F65A312527381FEC1BB4779B6F0CA2F0BA597E28DE0B3E244EBC658AEC7A1FE18A0E9F27DB1B3A8C5EA7654B689B660138AC2C2DD5515F2F6E8B276CDF85BD600E8280EA92F2AFE575A3CCEB58B524F94927A6CAD4F189F0DAAB182FEE0C0C6429417B9A97830BED97E93ACD5C4691D7EE9862BE3E8FC8AEEB2EB0E72BDDCC5CAFD41ADDFDA7C68803117B98DA1F08A805076F3C30BC608D89218711F727FF138E4F46722DA45070BDC5C42A678AD7D16888DAB25F6E3D81D44CA5BA47FCF7706368D318CC2BD7E6F009384A05407A8E83140C88DD7F7A7845959DA061FFF7C5DAE851FA2B3813F0D54142167CCCACFEE491C2AB1B0C7B7E162FBE6ABED003159E0EE61FDAFA2E3DDEB30103F3237353AA4CC60FA6CCEC6B7833838DAC544DBA5FCDE8167D98B7C4F453D75039CB6AB9E39582F9C26F1FCF254C498CE6C2B3CC11FD1F9D2DE3418E532D35FAE0EE8F0918BDC9A6A7E785948EC035C9F5A6BA9B92FC3F088A628708DE2F928DED988E01094F7799A3D7800581B5ADCE1ED809CDAA346AFA9E6AAFC89DBB52B63A575C24628BDBDB8F8D5BEDB0771A36A6C6200319C0B4C8E021D42ADC4F9B07B6B43AA7C21B8B97070E6786B9A5224D93F530595804D477327033FCD01178A02828957F0666A8B42C8F2395879FA927D9668B8C0A32A66BDC841B57DE9957437A804277EDDDC7C9BCEF16D0C323075B3432E52F1AA2018066CD913C7814D0D813C369F604CCCDBEB36C4C24C718943753070B1315378E75A01E8F995CA678C6B325CD76D6E82852BE26C0B41024BF82C022B19735FDB4065C13119343A5943100405D01730B6C7EBB7331C257DD976A34B7E135CC88260438F99659ACAEC21EC49C0012C618589F42AE80F176C7B4904057E0A29B6654C5DC9DAC4817403842B5E8A8DC3E353A0913ADC22DAF198A22BF18197C3006FD2B2C3E0BACBE8B6C6AFECA063099EF71A7FF2DB7A8DC4D56E1837E1049FA0908EE59DDAF143D60375902E55BFD973BB150CA0CDD6595812044B1438095F98C295D52AC822CF1C50EE190F066A4BD740F43DEC63E086559AC44B5C368F0E3F08AAAA8AE3BB033503550D007603927FDE29345CB3045466250401148D7389FAEF9A214707FC013E4BE2507F2D10FF5AEEB7DB931C417A7E2555579F4E4F08AC1B982A4B85A574C70D513165D8141FB4FA67A04C8F38F75529A79D25F833F8FE10D6C944ABB50E72CD3AB4E36184C3CCE8388EE4D133A386C0E2B9BAEE00BA20531FE3DBF167915681D2F8B97C01C4972BF8ADE7E77FEF8E05F0AF6661F162AE99D7100B7E64FB8ED246636A27BCF58EFF287A5F07C5D68831EC1104A2DA8D6304047F2DE900D603BAAE8F15C28296DF1C8E2DB430CB7E081F8997DFB8B4A1F720620F52CD0E825F681F1123DCB51F6B59B57208D24FB7B84AA74961B62AF91BE9FB4CFF3761C5322746F4784103D06F39A177A78492839AB8AC1D1FB856DAB76991FC43357EFE0B6D5209CF21BF5F6B929C12FD27670734DDDE43DF945815AEEDE72BFD32EE3D2CF87A377E1AA863497AFE097601A2DA25C5CB8252E7F3E6EDF1E83B36FC0DD0E86B834969DF05EA186DF7B7760F32CFE4E004626898CDFF4DDC6E3909703324F10C2CDB154473F85FF6FF92BC1D6F693B67C64700CD9848F08382616EDAFAC484A49176020EDADC08E57D51918B11E90ABCE85D940E244225C1F98171F907DA630594F8FFE87FF76274593AA96D8F27B56035DC8BC410E545BF1729C367C170DC2BEEC9A860E6D812ADCE5FE9EEF510412E687F94B7051AB46801CC4FB644AB37C720CBC35F12683D176525D63B3CE9E54C24E93FB576618FFAA8B98BACBD79EF96AE4025CF246F9F4ACB4B64572E28ED7C97BFA2C68E2B3A32FC4BB269067E74D78DAD3D36EE4DA7D852E7D0E7880CA8FA086FD717198EDB677C0075B40B1BFCF43C092B1C985197544177692BB3D9CFEF5ED8DABE47FC04FD4117A5495A028479DF94DE97A9DA3423554BAB1EE2CEEFBFC93D75E35E3CBF6CEE74F21E88D98ABB0DD082D23A90687729E478B390618BF7FDB1C5EEA2FB93BEC7F393C7A49F5C31064EE4F08B0E0483D53A54214E16F6F6434AB4E3030B6817AD80CCE9F275DF8DD134894BB1DDB110CD8543BA2001474B95C548D0CEED21BFAF46EF5B2BE7CE9A1BFE6343A70DFA48B4A2221E6688E9C5DB87B09148B5A654F547BE03D256CA19102B574899154B3FF2877B990C0CA8829C5EBCFA505E9A9C3AD11BAE440ECCDF8B2C3371B2E2B5901481AF74CDA6FC927FB3DDF1EC01797C96DC202F0FA9DCDB9A8C59E3671586BF7C14A4E6368B7A8E8ACEE151DF9F143CE4B646FEEC995773458DE753F18A591D005B094ADFE621F8248E6CE8CA5FF108BFAFFC7F5303F976FB71930B58D3F9B55B3F5BFD1B2566C7C67FA1A1BB5912FB121208C905D9FEFAD6B400BCB11B98A81762C7A343C97644BE1596339ADD09E5F59A76FFEAB229D6BF08860E01F9B94998840989F3BFC6DE1F7DE5F3FA86E394BE3CFB9D6E466C925D8AD90F33D5A61EF06AF7105174255654E219957D04CBF38C689C17D27178D351E62B44FF784F4D6953BB1735265CC9734218BBF2328C76EA5169F029B0995DEB4125CA4BC02D0C85E2990C68998D5FC78E7641D3AB07D010710AA84097FE767DA304826CEDEE26EF1770C83D18AA654C32C25CC573868EDB22E71298F81B58EECA9D0A0A56A3BC7603CBE803E04F0018192207684B803E870E40436FC8B853A004E26DE6FC4B67923D65F595A20E4DE97C43AAA962EA97DD41AE8FF50D7C340546EED365048C66FBCA8A91B3A11F523C26BDDEE18A25B37C77BA3ED637E0A069027188A46FF86CD201E7C4D440DC3E90E876B1189421DCA66E6B9298945436A5677FC775F9B00DD3ED10BC4FAD366E757783FFDCCCF6B27FB38A2193364BBB39A805657D093B4AF1D9B8610E7D24B72A14BA1735B73E1F0253072A046F55758DB6F1D15FD51CD5DAD118849205B44D94753F4DF8B6518EFBB441706BCACEE0F27FAB5A004019B2D73F3D5AF35059BD7F648DBBB4F12786DDDAFA9DEC9F3BF3E75E388BD89F90015E53D10D61B9671311980FE6115BD5E77F57AF65059D09431E39CA6E3019BA963E58CD66E2C4022C11139DA44EFD04C85C438EA802072AD360B33B3DA089907EC9931CB1BC7D4FF273608DF81B76AB831F337D5E8C59A7C1B4A7ACD8C957914F053EB25ABC3D2AA15E8279678D4D07748085348840C8643C92B98B985C251B5F54D3463FB4CD1969763D7FDB8811025AE07130A6E5744C4B16BAD51BC818F466179EBC95126F2FCDC18C382498E838FFC983BA1B89AB4370594ABB7520FD04E634E258C94CFE92B41E00A295E3866CCCFF2453DC8AC5A792F766816AAE5CB94C3FD1B537B3213EE6A594E268CCB1B419D0EDCF83E501EF2F4ED93B6423C5D2DF0C0EBF236881F505983D7C7C10BE67A5EA4467DDB5A8B4B8E7C76738AB90C57C2BB673A60F27383CF021AB002E4B7A4BE4B934740845FF9C7DCABED5227574467CF93B3441C661E5CB13DC2DED94A8E5E9B7749C2EACDFCC7D7F79CCC1B9D8150D0DDA2257B564817DB1045BCE25CF749409683647A78F3F79ECAA069336B65765AB7C152B8D2D80C59F4B5AF568F0C68B125FAF3D50E89B2C4A0E3EC5A64875BD851DCAEFA473D21D6490AA104663F84CC0D71F34988B19FA3B3F891FEE09AC4D7C35916C7479CFBB66AC512F8B589B01175227294301701BCD4B4474C32467FC3A8FBE25DDB114BDB75962A32237A949AF2737B78B79F85F2B16D88FC0AF89C676D9ED8EF394F46679ED8CA87CB9C6AF982A42F4A90DE301E1AAB3B9E59072529208B9198FF1C359CD4AFEB2170873AF37EF9A610FE38BDDB0E6EBC038B7074550CBB3358401D73D50CFB235D2ECA125A97ADA970B39FF2D37FC373DE7618E56C514A235E225006CB06C1A470DE231B0DF3BD53A16A4C6F0746E96CFEA4BE39D24550F325E7DC60B8FE260AF07ABD291B11BC05F0E8E3AAE05490AFEE582D6E6A80233D1850F27C45A71032FCD784EFBC59781C1B576AC2873EBDEA29EA84E311FC92DC37D8B278DC03C4DB1A13FC619C97B7B38B32EB55CBC26E796AC2A5EE70AEC9F4104C2968D7C56F3C0BD4340B951AD6025572CD789AB52936A5492C7DF8FBE5D2FF8F8BA82B22EB46AD8FC2DF712393C78455CDB4A4D35699E420528E9C14C33BEBE7EFB93EA6C9E76A05955207CF4926F0370927D7A47901E62499B38A8D84FBBC199FCC8A1F3CF8F70766945D1E4C710DBCD6C085AF544FC6DF3DB349C61F71F9DC415723D589E553D3E5F6A6E4BB00BECD0A5C6B7DED1B980FFCC4D1D2DCFA2929628CDDF91B37D518FDFDD06A054AAD801D8B593D9CA45D8E6862BB6129B51AE155131DE17176D6C6B5CD9752EB84F2DF61ADECEFA5F9CC778184AE6D641D377FDA716B13E9BC163EB53F74D2FB635C315711B80F84533294DF9C42025ED5061173D1AC83E4F30C72AE9EC0E3D86F40A1F78D354AB0325181BC338FDBF0D86CEF24DD91038B4BC2DF4593C9D44417A37AE4EE3B64F57A1BF2DB368EAA0EA3F4E4B341D74F55188C1C3B4AD0F6482F42B08CF7D759088EE34404324993E137FCCC6AD2838C103255A8688E2768E7FF1B59A34F102CCE1F0EB3CCD143717413014C0936880AB6F878239AA8ADDD96E07F2264D63FB4157097DFBBC10BBD7FFEA16000C04C849F96A73D97A859703B95CADA50FD1129E175B093AB4E09A373F37A0BB2DDAA6E0D294F8E677C61913F401BC9333C938C8FC7D1C339FB541E0FF6C58D0101F2917767AAAF0CF59C2AD2BEED6CA53456933097871E1780FF29E01DC6B24C406F6DB0D5C73F6659D3DC9045C7015C62B9B11D11BC40D697EB0C961BC07CCE09908826000B0BCC8C4CEAACC62A415EF7EFF6551D714B0F6AA2AFD94924143322BC075D7040EB0F8B0E90EAB57A0E1EB3765CB07F8FE121997283B0858668E92114321A10F598F2E09773610BC4C6F159D05E06B8987E178F11B14E8486D8432DEEF6C7CB7CAB2B75C3A4CAF27800E237D5AAF0701E65B3DE1A2FE42CC9F48408FAE55AAA69B44DF32EF54E75BC2CC06534DAD81F769A59E46CBB1B7BF7BFBE376315646F321ABCF98C6C09DB34E1378EC38467E3119C1F6692325ED39BFFF6476D3F33E88DB6E2ED97370CFF0EBBCE2087F47E35DF75DD236673011769968F81177109D78E42868BC5C19200EFD3773C2DE1BA56111B5A339299E5A3FEA0DA0DB9283EDF9379C6E1B198569ADB05161097CF8EE1953ADCA85FA9F841EC239752091563C52706D3CB495D233B0EA622C18D28F432979762F2F5AEBB1F29BB2999413326E39DA884681011DA0144C72BDF1F20B7DC6F1D5CC3A55528F76F7FF85CC71F9A55FE4EA2388863A50EC2E3967876B4DDB56C6FCAE28314851AB2D11A866CBCD504F64C249B4FDCF22C18972FBA78ACBF8261C882181BC4734AE501D665C26A588F7E3CCAF410814902029ED12572DDB8123FAA0AFC07BE071209D2E9FBC9DDB593D392B2FC3718F03209021A04440C603FBD38E0CA1C572249E57E72F392E050C702E064508B504012268893861E1895762288B766681139B8520AFB099EDEE34CD7FD2231FA716FE6EFA3CF5EB045A32E2F42F3EDC4701F0905967760C1C56B887F38A9D99A48FD4002F37977FEB13E7DDD716E6149E85B7594B98E61A8FF6CA349C9C50876E9DFD471C393953E2F5200C0A44B2A30EE85590D1FDCF845C6C82BBBA21DBFC7FC1126FD41AA4C0209ED28E2807384DD6EF82ECBBA274E3F2201E82E5E8D75664FBD42795369DEBE159B973CBD0A642CCDD8BF757B79BAF49DD4ADBA30DAE952A89D9224A86959D21D0AD7123F1FABA25BBEA8D80372769771BABC5E641136908E96F8C518462AF41855F1B191936D7CAC7C6676E5865D6EC0581A37F6C068473740AAC6DEE310359F5D09D627EA2244C5B79B4E9447540ECAF419A959595C9D0C9A83F0058BA7C383DBA8571E2369E8E2FFE20113E751A81CF5480333B890FFD22E8BA9907A0157A9C4BCA8417F300F53708B24F24D8663AD60AB084E33F659EB3085ADDB6A2F1552E1EFDBB214FB5440C9ECD1333A1D33B1D2EDA7DFE65AB4427B365FDDC9A3A1B6A0CD4012AA0F52B08B9E51C015184ABCE8F555362ED213BB07683C46E99FE8227A26F929157E46612ACF8AE6AA1359D0959C184AD4749D456C65A628DE734E909BAB0DEE144C4382319B100F02E38B3976FB02F59783E2CE33ACE93FD8A6035542C999CDB5B234ECB66FB4232C4A8E4DAA1C44F7A9AD2595EB546454553F9DFA8E2DE1ADFAEF78FF685370D324873AEF8BCF07E859BDEA0838E141A74F3F4259C4508356B780BE96D69C24EBC20FBDF39006A049D0693B657EB7E9ECFCBD3175F0E1BFCD53A6D1F04BFC6B0B366F71E26FA7DF231DDBBC7C736FB842FF93F650EA49599CE18AF69983B10537670186C11CFC7B69DFC091E4533B80F3C16E2E16C03C9AE2601A5A7AF03A46DAB6009B987FD4FC4C849DA0D3EAACC3CFF8455D44E846687F48C6F9FD4E9B353420C909CDEB05D3EF383C9FE1AB6A3BED6EE7DB2E765C989E637FC42003EF8AF41EDE4F7702F25E686EED2D192E0779B1D1AC78B796DD9B398A1A56304710017C574E66F1EF161B722FAA8F53C6134182E13059EA842FE78A3C793993247EF4A06378FD70C3F92D3B6D4E8C93333E81EACFBECE1EC054760D46CFDAFC9FF8F376379DBE87FD200C88F437D64FCB937679B2DD932B7DF8974B49234B691EC3825F1FFCB67D49F69DB08B4C119BF8479EFFAF7D61D6631315B9C2013B342E0B2D0F6474C86D1E3BE4C2A4876DFB079550AF009027D0CD15947D4BD1B0B3CF69CBE2FE4272C2AAFE585D14117C4224327CD3DDF16EFC0DFE08BCEEF43EBD7B73D48B13A05DB9773F3801A4F6E936E9D452EC828AE83742D215C15AA7F4EC010489814A265A93ACB0B633ECE76CF385007C197B346ECAEFD9E9CAFA081D2101B074904C7465DFE063502ABAD3582026FE4D65AB9168DE8C3C207638F5C6F59ED1C4D8E9B74DB9D26AF5C38AE73CBE850B8F9C67E8967D368157EFB9059DF454CE65B15BCE388A6E025EA05BAEA295642B475FE2385F6974F40EC1348DDF536E5353EECED963387E41F888A431CB162DE5B10BBC3D26D4511CF61FC1E900FF7EBB486B2A6724D3AF556E8A711FEF05B30334037C4C531C9908123E203DED87FF1CD4D3EDB33DDF36EA038130385416935E4880B90DCB7F4FA52E9EECA22C4889FA8100200F37827800219BCAEEAA619DADA64F982F679BD64FF9EFEB37BCFDDC541166B15405436767C4F6D78C984D272A209CDA22F9E2A8DDE2651F198CFDADA1DCC8141EFC0784C836A328AC4840084E14F011292456904CE365F5BA364E660FF279441A87B1C59AC5DD4A00692437E2B00BEEF19D400C1A38FC06D95E296F205E48078A6DD405191F6E339DBE3E066B8AC50D3D9FA1E6AF157D13457E2D05DE60CBD0048BF3422B44A3B366CB5A931B7EBA2E3635906174576B59BFE45D648E582D4E85D2381680CB793B4EE4242CA74B8D5B40BE01E16B9F26472D6D204D083BCF6B4BCCB7863960E56AB8A184C904FE22C1923BE253333890E05C100E03DBA829E5AC7AB019B812B2D3EC1CFB688A7D9482E65EE0AA4F03B0364005211404AAB1D4A9AC18F0F4FB93BB60FA593AABAB3E027B0AB489972F41A7FE8D8B4698DC1C5955833A96C3B8F97D64BD0B57428CE373D83E2510519B87B72F144D9877F73C6BF007F199807CE39333EF911E7C66F8D20273B55DB0A568024D21DEE86620D8E0409A7DE0F4D88D71DA33D59BE389F6736C7A426506A2F3CDE8D9FF649893B4132378282EDD2A848593EDDDF3FEAAF8B413B81373D935D7B41D9C28B449A0713D4EEF9A97F160E649E661EED0FF9323EE5B7F224603C10671FC3A2820CE6D8BF5D42688699B88F504EDEB9E26542B6DB7D8E6665D3E5B210F4A722BFD668E79441E9E92CBF80AB0F30346CA769254D473D9ACF26CC8F7233983F6BA23720E76438BF5A09865E824088951B2A3BBF153D2E08A56ADCE54781AA18C478526DC0FE64D87BC6BF9B24C48943C57AE2CB27E775C8EE28DB4D3C48D3A989D0594681C5B88721DEB8B581E5E747C1F5CC544B59982496EB325147795AA948F4AA082976A578CC0AE8801255177E32EF04779E5532FD636F231ECFC952541C901CD68ADEF2B6A35EA62A7F5FE2A67C772B8C7318956CA2ADBF3697DAB478FDFBA7519744F3B8BCCD8DC561BE23746430C2978608A0ECC8FDABBD417234113681A78EC2FED523F9DA6179594FD1EB010794D157EB8AC648B11A2421159768A4847F3B2121199B816BC8BE80F0329F90BE0575BE1DFF042AF26C2942236D9752F5742ACD11778D444D3DC36E815E3C5E18354789B131EBA3ABA06272C9626B137EEABEC00D1FB68F33771A864F4F708D7CF0C6DE1C95BC543C81E5A5CC23E21A6C1F4E6548338FA17B47633D61A69F629B483CC5FA01BED53A02DD6A66C6F39849AC08661990D0A75D03E7CFA51643E7D5818CFF9238A69CE2C7B29E5CEF7EE955522323649EAAE9EDD172FA33AB7198D35FEEE5475D5EAB878D7ADDBDF743B9D8E4AF129BF7BDDA7AE81621E3126F7F6B0B9E9D34842EF9D0EE027294AA616A5A6DD7E0FC7975D053D9F658DCF046D8200A4E32CFDCAF8E0C1E384139192CF7EA3530E7B8740787E8261F79877A6AB6EC4409B91CE901ACD6847BBC5A665EB3D373D448E05927978C36A9F7D8DF61DC65668E130EFFE349C1757D2456EA0F0882D8F8BADB8EB0402D43E999505BF8BAA5026BAE09312B817922653FF786C9C6E5C8E368F8992107BFB057C26349FE4D50AA98F96C150CDB459DFA1FBEE61F221BB5D81CFEFE701106BE83203EF8F9CF87B499C732EDAA5527C952829C89B137950AB0CEE8748673875BCF9836D400F63352CD1349C2831BA9879F82A060B8D243045BBE151B27025E5022254FEEF6F142F4EBE8CF16E44D83E1474FADC12975D28319A82D82C183C7F33F5838EC2C32FEBEAAFD146071635665EA991266DB93BF8631C88716C48442022961ADA733E819E69EFC294321C9CDA493F4EF9920A440FEAE19337BF15613AED9C7C664780AA8BD3C5B158611221BE6B1CC0230B4E8C6A21AAEF1E09D1E5FC45443B3B638AAC6FD79062607596CB78698853CC2B9C907C04F8C40604B33DB43C2A19B1CD418EE661A538BBBA83081B1C3769145457B699B086864CBED986EE271CA68E5192B1558A36483E7FBF07012BE04FAF1334330179EA42BA96ADE04A100408EA66C653B6C0D3A816C2F2E1A3A4D12AF7FCF9FC585C937BEE60E1576A13D1FC0E0C5FE1058D1809C36540B2529400F7E4C7C5B2B2587F43ED722E4D1CA9E0F6DDA70BB2803E79EADC2637CB5E1CCFA2EC3972FED7EA6983CA50AB2C9D399BF570E54F78E35721210E6F4FB103F71DF86568A088634F907142253A29B4C057D690A563F2814BBC1F073A047106F683ED8EF43BBCC6B4F05E9778EFD040BE80037A164F606F58AF97A0063906BE5E1DEA0A05CBEC5F3EC5E484B6FD336E3217C08F7CDDF324E2EA0BE608FBF169EF9F8ED7CB140E876D779F3FADBABEF4294CCA26C13898EF1DE63C55EAF1BC0D3B7838ABDABD092FBC3CDA9F44727D8FCB7A7BF9C1C155F69BFDB322B6B59906C2277FDB1137D5F50FE2D6C7BD1F7DB39F70EF4753E789E9D6EB18F4DDA8B718A3F2E97A09C33A7304E6E39638B7EF20E83CDC6BF7D07B26911895313F93386799BE25BB460843CF916247E63FAE698538B09AF27DE14ADAD598C6483054972563C700E7DB62925C9906E0B30B1967A6BEA9790C42200F2A0DC6F7A648BDA87D8896ADAD77D040B927FCA4A936EE248CD112CDC5E86ECF1BC0AE8112946951ED78E3E765408D34E0D6CF22470ED171A4E240EE8D92616FA2CC1DBB84F26A5FB33381C3F35CBDBDE12AE28CD96B84410DE2671EB104C01E4EA044AD24FDA32E67891CA4A359A7B362CD7F85E521F1834C3A3487B2B38351D50F29ECF57CDC75F738278113D87431C4E3C9E026918FB361113132F233616481778952193AB4D191022E608E272D8F4637A759CF8A5346AAE692C7585C74684DAE8A96D4EBA8D95D5E03DFC6E45BF990D58C3266D1570277FD2D929D575924A4196DE7A75169CA05301B570AB7CA8DD8BE32EA93F278C580EC380D34006D21C99E01682970AF1818BCEEC472564989D0894B364CD408EAB3BFD768076D74FD2881C8D2BE034E73EA656C3EECE79C5388EB210B23990AA3B09D51B2676995C81DCCF6098F555EF17283E712199828A1DFC9F5F7A7E33A6D5AC24640E155D2A78C803A4F10F3BB63F512F7CC22D3F30C051A80A4BC79ABB416237C4A683B3E13D078192826B6AF556F25208DF76DBFA53A88D293DE5C919E5748B22A678CFED7F0A0A5FAA18FF8510803842508A0654B74E97E2D368C2B7A587A20C31F7EA95EB1F15340870B4ECABA2912E0A83C4D948AA62D02612808F9025FE047619851203872D9F53E67D9C048613416359655A3D33E0F7CCAF9F5E007B713D086EB0795CCD7EA4A97C642D01A9BC24CE076D33AD99E9D4C2695C533A5E210AB641606FEB87C5FABA5D81A654E0C42F94F678334A9F6C89D39E728D580BCAB228C17E50A09721F37F29B3E385F7F741535FCF9B1120398127AC097D73A849F04F8FC82C1640EE3755EDC78AD5C7BF89FD77D50146B51407B68394368F79615CDA8C4DFB8E348F99702B98C0FD1FF032DEDA9BF8B31221F6F6492384ED9DB03CBACA021AD582241C129A21C90D28179F0FE16CD728A37CFD60B1062105FDA590E5FB7375CB20A51DE5DCC9C7A4C9C3CD4BD1192E5965C80F26043728D98869DD484C17DEFE717C4ED7228814D0F282A8244B04F006D080E9095BBE9621E0E43F0A80EF68DD7B3A16EB7ABD426ECA2DF7A59816859670E646C2869FFE7784E15B5A8EBF7244A156E357A4E5EB2EE10307ED4B344C2D474030F2EF5A009B789496D46CA8E7D876A028CCE417318C00E9FFADBD9DE8D9AF1B68FD1F9DF1711ED7015BE9DA0B48FD0CFE424D51A16E9D7671145505790447EF170FC4046A165E78C6EB2383E40B2B9642403BA4665F89CB538636783129B7286DBB63A470DBB83132F598C457A26FCE5559CF9C5C54863D08070032E308F255FC77F72220595B6E3A8D41431A23DD53AFEFE1735D8AFBDA89456900A9E0A2025E5218E68BF143E8A2F081FE8BBFCB50A4F7F8D5030551E51EB28945D04300F7822B19C653B5CC9AC47BC899002B83096A96CACEE3806BD983E141E6080B220D005FE6644DDBB05BF82A1AB4BD22647FECC015EC11C7BF0F45B706CC133F79FBFFCC0ECC90DB0EC2CBB1347C16F0D383A92A5D93FAA8B6109B4D700B96F74F977CBBF638DF237F0FF3B3AE0FA5ABF7CA156302A64270770CD266E1E172B415DEFC5A8D6073CE04913A102CC4A6B835240CF1C2A71A94AEA01F8F129B098AC3E4B1C49BBD174B0BF728D7B5578474E51FDC4F03E4B76263D93E4A0DB579BDBADF90FBDDD1288C699F8FA7AC3DA4ECF765427FAB8C3B4BA80EBF1958CF40A60DAC0001D2649FBF109DCAFC9D6C29848D975A0BAAE25CF566612D80FF5A8BA0DCB8CD6E5E99FFE265FC56A9F6989B5FA324AD6B4D3CD1342A1C21383C853B46EF093F749E4860EB24FBF95CA3AB78589B791D91E00B8293723914FF4A6528385EF8084025CFF2695938AE67DD621FA15A40A6B094EA4B234BDDBCA55E2F122871F8BF2A1E98FE4D541A2F8DB28660E99B7C0F44B0BDFA77B2B4E2D5D7C3D7E583CD5699A35D977240F32D608CEB3E997737B8A2511184F5DF7380E57F694F96D4DE5F0B8E74AD731C94047C331B2C212794FEF67AA7F9FCFD3D4AEC1D4FC31CCEF4258A450F14FB5772EAC1CC2463C2CF9CEC00F47385235E1B099B41C76409042CC9824BFC8D5BD98AB53D0F8DEC767599F287966F14CBCCD42AF0EA83194B20292FCBCFB731D1166A180ED1272FC6532833E7BF5FA95BFB953161021AA80FACFB0B46C5146DB972980644BB5ACC2D70E246C5D5AB635A2C39F0F73FE01E55C56D13FCDE60E337EDEF7EF95E73B4CC71779826B4F12894976734A5522583AE87229BD100E1916EF74DCB6AF31902E3B69DF1FB9B49CCFB0587E518DBD95AAE4C1E1A92E8D9C16D9F75C2FB3B7E37F841824FDE362250BA72275C12FD6A70521741C3CBC390D488C21DAF4C4062C08C976E1577D3C8E6E1650D0C52002E291623496AA3258F3EABA4BEC8388888F1577D793098F1EF1038E5D4F9605919C11433DADE5FD8138A6DDE2581040F94F45EABA473BA01C5291D383B907F414CA99B8596C9370ABD54E7A2807B23B74AA59A53CDEEB0D6181E35BB935C194A069B49A1DEEF04B88B8E4A511027DF0E1DE91C0B3E8F84D2E44880CE3F076D02EBA062B41CB3D8B340B7CE2CD0C77B7A4104C75422BA3F82A4A1A26CF6F927A9DC6E2F84FC883B7DC31F1FA1BD2DFEC8D722D0294675CF7FD21F1836FC5770B514156FD0ABC151262816D0EE2E1666E5FA8BB14D96D027C354412FEBED2D1625A622DCE9C7AF33F40E1D10D5C26D36453FFDD76C0A5DD387E6051927FA8B49EA7FB838CFAA1931F01CC462079ADABDA46B11004E282250B82AD62FC82574C1E78D28EDE9FF0348E854684E2E51C79EF065CDF49D0ABCE608C35FE150A9D639A74916E32DEA51194ECC046E1BD8F8D4C258446D739D3719E3C906D8A3FF0D2745A285AFAEDC111567B64A36F22789EE512C5BA518A3D9A3C3B6B478A6B9430271941A1ABF40271FF7A835806DE2A7513ED84F8EFAD97B2EB1F0CF1138187E5D20FC2F6258A5CDE04E58B33D67781BF794E6587A2C51C3D29306E828BE9B604E2A8C0C9F487965097D3EDC54CDBABFF5A903A9601B60DC3967468BCDBD228A8DEF9FA88B6C019AE663E9A1A8C112353C688956DA0B2C97D7858240A7DEE400DA0980576C63F8EF692F625FCB81D859C3E72A3EE3B138F8274467AE850D67AD4DABB182C6CD97144E7FF3D8777AA67F9C7C7E455666BF1E205BBD7EE896A81ABBAA24AD78BA38C2E92400BD12EF4FB4E5CD062442CDFB856946C70A91CFE59F21493B9B40FB2F7BCBF8E43116E4E6D2B6F8BDB022357F2BED65F0C442301BAC2EFD610FD9AAFF83A1F9F725CF00615EDFA90230DAA9F1D426F5C38421B0923546E544A7CF4A604A9555BED8C4D62E04E799067B30D02A27A010A67FC5778ACA2DF727D604C95CB75CB1A5A2B7ABDCCE1F7EB1B8660D908151C3DB348050C44860C5C32DA51EA6865BC88934916EA7F2BDEC5CA3A4FE0A7BF585BE22EB38BFD240081401547E89953C10D7E339D4FF14D05660EAD795BB6132ECBA31B14064D41917694C09B762C7EDB08DA3278BD87B483EDBEFD4D5FFA5EDC6B423C92E04D8CEB4E4B27BAD707CA73EDA8373B44E1A30376A90C1628407C6A59A3DE7FBE676A09D4A25902B0227C5B0AC5B54D8CA207555F086BF254F04B5227F9CB0BF1EFCFF24832D5ADB013640458FD282048DBD0F0E97E6D88C2F5797F71E3DD571C14020327F8A88745CDA754A3E083E3EA75855628D9FA2A971A2F7E9CC14AEAD74990ED785D9BFB13DFD8A24997B3E80DC5EC48F4E97BD8552F01EF68A67D9EFC94D452FF01EC6FB99F54CAD8A4F138C549DCB32A899A9B0579B46F249D250B6BA8500C3FEE174D4D59134DE5F63180DF6D0A1E8666E348F0A6B3CE95990D74296ED73798D1FCF543242F440009CD5A1D43DB221B1AC0F056BB0EACB2167FDC2EDA37817144BEF139C3329F09858F3AD396F120C87EE13E2CE91A22CFB61824B4DA7B465EAD14AA9887CB94678B4991925C39E836EC14780FBBC6C32DFA080D09600C035BE97BCBB730F111B9FC00C1ACCA9DDB56DB58FA813293232FCF98A94CEB11F508E145A237D4D7A497897C2342D7BA0EB525A78ACD4BAEE311DE996668B5087A888CC3AE65BB6EA1704AE3FD24E16539A3B6536993FE9023A4045A9C425A273F46F34029E243DD11D018F1D56A5FCDD318F6404734544BD01B2E345A773378AA25AE5289FD54661DFAFED6ED09F1F3853D4D63B62DBA546A14C4E8CC16CBC548F1CD75488C41050EDAE8557B64703A46CDE8EDA0E743EAF09016E8507A9BCFA745E022B76DDC9058066FC3B5AF9AAE52C809290D724C8D090C431BAD5C49DD702397A1B61C8A81C7B3865E21CBA2DE2AF95218AC0A75883FB3789C07B941FE7E3347CB74008920E7A048783AD65042F827CC1AFA560F1AF4F3D83883759B864CD38ABD3DE23A76F69CE37A2621E27FE50365F1F500C2943D2E823B50229F877A865FADF56D347599181842473C305357BA24AD2C869DC14EDC59024398A7A103AC84FDD4FBEC272A816436F6F113123C00A7A4DAEFC00F099FF97D8F54554C3B24A76BFB376A31ACA0317C5C5D014614E4EBA38B7109AFA0630378E1F230B7BB5A2669FAA473B2882B0EB73C98D24F936BA843EE5A1221B91AB0BCC5AB2E195002890D9F7A531A567405CB0C8AC344249B8E1DE5D110632A325A570396A5D0DC9E13FC0BA84CE9FD297CFDC382D8313ED5A1C08458AEFA04F84540213F652DD71DEE23B48B07EC1DEE10696CB3EDDB893F48CF6B4CFA28F6BDA3130DC815A5EB3C62EB4C40D2CD70E30C1CBA21988AFC7427BB4BF8B3D93CBEB25AF970EEC874F99FF234F5E34B160BDC0DA9B3DB8FD8AF96463688225CC8EBA9801C99F5779D455A278EDCD02C44B4B495295D267A4CFF03921F4E65893DA9DD704F0A7A53BC4D334AA160C9EA92FD0F2CCB7F68F62700A6DDF5585372157508C96E602B8083B89BD916623AC19F6F76B43909E3837AFB8957D8B6D9A83FAC5F3687750CD9EFA972ABDB18AA09C64E75F8B578ACBB7CE0D1FA15A7932F7627C350F2690EA1E9438B058CBF62D2F93FB9F84F5431450E931DB5E57C650C54D8E80E14F735BBE951F9F598AB960FE76C3ACD7EE8347DA93839229BD66DADF05F0474B723C8C138556E2A0619D0A1BB1B784CD4EDB8231A98DD4BEB8005EF0D7AEADC42ED23B20ED410FEB5DDE85AA9E8878CFFE02B96469345241B6E1741A0078662F87A554E69B7341122B812D752EFE455B87643BF00E573F515FC45CF04C6D45D02AA6FB17C5C6CFDF1DDE8B56DEEC062AFD61E091573BF77F797A4865B9D161BEA4E1554A76611A2094CE93D46CEDE63012E158050FD8D79C4B14C5D107CD95F577E53587F48C61871B4E161F1F22742B6EBD6155068FB0D450341CAE4A1AF55F51A3F26F1E9AADBAB3B1E6A20900AC65E0EB1817F5C35B5AD9FCC7371E47BCBA84D8E6FC002DD85C82DF28152AE0E460C64CAAF3A1000A2495E8C0E288EBA822D61FED838CE17512B7816CB5D51FC08F98928CB58314B107D814E1EDA14EB8CA33DCF10326E4E88DBE2765C6D23AA9737DA1AFCA1B8AECBB580C1E867883B581338D884D5E931690F2493D83DEFC2B405F62020ECBC45690D2AC8755A456F9193C32F80FF7B63C0504DB656F4126FDAC2581C254F2D929A2382A6FC38FC7FB60BB2CF786A71137B9A87EDC143C5EE7BF68538582D1109442F02A34E1ECC5DAE6D1B169C6F51B0F2F979E81FEB1F0EA4851B988CFE71002853F79DE50BB33337E541B87BB52DA1E5726065DBBDAB8985C65AC0DF8F302C5AA0038F49788B4F774F3B1CCE8891A8BBE9C41BB60DCBFD27A394BB05C9AA16B85FCF624727BCD5A1B7F7150BB6A8750C066C837484EE2B708527FE65ADAD0AE70C774543C3B56C0560EC0261B4CEBC6267DB838C840A940E4BFC1F9D3ACCB231D21407B90A7985D55FA7B6A73CC6504E10080EF6AFE65B802B650D0E3D3A965ED07BA0B56E0DF5F6AD996EFABB49F293D077D003AAB0D5A6784FE47A76151EEFF3CDC2A27D6837560A1FE10FC4A1A361EA51643AA0B726CCA610040CE758841C3A17AD779108E00EF094159B35E9CBA92A0FF6BCFFFA64D507DF216705EBE8F4D2544C483AC8E24B43A6B5518D0E7E6D68A4B7321267C4A864A8E69CC67400E01FE7442D0C03D9D19D059CB2D7AFD98FA5EC32788C402735464F96F5F5C6828A173003FCE7AC9C5DB04B541EE5DEA73B328C1ED2649B7655ED8B55566A66400937620DC9EFE1FFA0B88A35B8035A928FEB92EFEB9231325615A02060D27E8D34770329C2DA83D7E0374E973CB876086CF94B0188939B0B4EB87A39D6613A867D74A5B6A69B2437E78892E78A9105611E5E32A0F923A6924071979A24F4F28F92E37FF21889AFAA342046FB342956DB70D5061668F45EA1CB1F00DA760D5CA5ADBB2334328D7C1EC1187FCA9F8DF3B9285DD010D172F42FD9251047FD64389B4CED253DC4EBC05E61A53FD53C6BC94CA7E75DA7B8A27042EEF127C2E007AD3FE53B6103A153BA190536A0912F6F990BAFF8462A791C82B2C8E0FA95DF796C70D31555FBC698CE77F78552CFF76B66D8AECDD2F2ACECCD678E3F6AAF6BEFBF16DE1B21E70038EDAA1D441CC5D96F6C959B8966F3CB609F353BC894E8478F4756543EB736237C100DC2DEA6DF8B90AA331C8E1F0DF91F638058C3E7E8ED71863E377C52D3C8A2E140A7D70CB230124E25D9ED24D9B0F2DFC0AA964D3C2E2F10CF5FF9F4712DF01D2F0448BBC1087E65E2FB61227A71D24B18FA6A2B263DB0FF55998CF37FEB50A463FF865B60733EDD78DC8519AB364A597DBB2AE1BA2DB1A5A27AA901B0B210F346300DD172BC437F0A74038506CE6B7D310B7EFD9BED4C3B866E3E40D4770C43CAB64AA8B45A09E0221B56BB7A1121FBD9C6EF175CB67209FCC7B19151116AB3F6A37C9B1443B5C058BFA22104F8A1E2E13E3DA9D3E3552FBFF3A53440EB1CC7CB26A749B25B0349C10C4D6E536427500D4A97B9413CFD4770F6B4CFA91EF7E90586F25732D85D6FB21B9B6E52662AB8C308B28064150403E9BA8E0480FAC42BECAF0F047CE147DF80D6DFA34CFB0909D49D1738C21021E3018F506CAEFC50C40B8FB7D56CC888B5AD4845CDA5A9EB5AE105ADA5449710D301BFC36CB05DEF4DCF67F701DF04386DCD6E9CC9D2428C2E060A9055E65A2B8155ACAEE14225900C33535D6D7EE86B19A5DD8A24852337B58226CE3172CC2FCE3E4BE02F7D494C36236989AF0237E6F96B7845041E5845F825EF41AA2F89B2C074E9A396419705A5FFF593DFA42E3010510CEA35650455150B5AC2D3ED9D9A3E0A05B73BC7878B0B779F24C4BB2EF277950DDAD7D984ADC04B27BD036DB7E6D484E6B7E21BFEDC61B9C65B7E1BB3F404EB7F75F4D473CF51AD6AAC90DD04CFD334119DAEFEEAAAB98B8BDA5D903E09DB30835C13CCBD6B45E9EDBBA402E32DAFEFA943A547198623C721FE06FA53EA1B97FF7076EF950E2D980036299E65F4F931F2C56AE22E70DA32195A29F0116236156D06F69B7806E52450BE80AA538EC62D5E15A9FAE5C16D7650D1D5EF78F6AA96E114D8927EA64996BD952E894AFCF6A9D2F1C50F7182F9048A2A4D09A9F76E556AAA356B331D485CB2CFBBD657393842B6B9809B432FA77808BFEDF2D9BB1A987842880BC0130D949DB45EB7B4314F2F9EBCFAF8C1558DA23E2C0FA1211CE4047BBB0C3B543DAC126CF74EEBCC3EEED07965F9C003D270A581FB5A4EFC5034562EE1F9B72A2FE3EBA56010FFE140C4B0FF31A80B35D55D7FFB73DA021BA01B71C7357A3C5FDDAAD9A31084B2E6D35570E82E867C1BB64679CB732F5E61D8E88113D75D3F0D9C0C70B793AB3405445F952A62B17C704E0B67BF385FF597CBC20C0B9BF2A3B2D3388D75754437A4F902FED3B057748FF970A8D3F69EA31F8B32A57EE86A3E24BDDCCE2B825A669B3897A8DA6BEA4A69E63FFA73836B08C9902B8841B19F35698EF9954F65AA28AF70E41406FEB7C89D4BF284ECCDBDCCA5CD0D462DC84E0F76BA7BF4CD5E730B6759BFCFDB1DE5DF248B5114A7DCA9AB0E55CF2A60FB6DC04201915CE25E5BAC2D4C1A53704413F2D4E6F6E42EF4BFFBD094FAC60116E2206221ACF4CC7D61000E4D334E9EAB0E514B920AB8092CB6AFBBDD4D07F220E3118033B76693C948158809E441458C471C3DBAFACF7DED6D9484E2481EF5CB4AF43AEC3C902658CA3352DACE3D6E139E05D3937B0DE2F5ABB2F25905D2C5D65D1979383B9785663E75F4551F8DB77EBB5FC7656BA4ED86A9CF83912FA0380D1BFBFB99033B15BD6BF8C0E088B473FAB11AA36B368ACC9D228E8D324FA21B9006CBE68E78F0C417CBA24CD75AD5F58428C5BB5876843BC74787F70952479DFC1960B32E0AFCB82D0E4C3D946649831EE2ECADF1B0AECF0BC187A8339B22149E912EBE11BA293B8287DECF86F1C12FE2BC7224202FFB23D89F73C3664AD5195FA9FCC841164B667A2B7C4AE79FD0073115FA52ED5A7886C8622C0125946BE8BE1CEFDC62DF5ABFBBFFCFC9801965F07A85FE2C9A408DE1DA3CE9716D62AC1A113102AB492C8F65BC4A9C2135E12C371066B664828D68277708C155AF37FBAE963F7258CCF4CC305DA03026E4864EBD9D4E209BF7B3A0A0C808513A7B767AB65CD124BC93C0B51465E31F41192F0EC7108BE3AE59C8E9600D129FBE670BD67CF89A1B0CE0C651204FA42642374E3399E5CE3F8D4F3A185839F39B608F61BBEBB58ABF43DDB065CE69C1E61D4EC4DFDF84CF9E462EA9BD79B3AF12280D6E53FE0D4433D865518C190829EE7E8FCEF20250E5AD3E5B4A76A218263E694E646B5E29CFC032E9848510C3414746B55115FAEBCD9C006AFF72CD6B2B7B0F28FEAE3DB22C8FE8BC3ADEADD40B609A9BAD20CB28A212770F6D2C2B2A341DF4FFF9C46B5AA464149D480FA43BF8876C0AE368A257768A89F538C4469A7FB333B9B62F09E67E17DA4B246B5FABC541CB403FE48E4BBA6D615DF192255DFBB217DEC8836A84FC9BB3329223DCF64EA29B84CE4A296799645C843A04FE988099E9F47448F1DFFC8FF2FEACE43E7F94E3BA14A9AC368B55EBB1D52D7CFB5775DF9B7D3799D8FC8AF5DF0A6B898B26EC19006B4F198A6AA0D9613625251AB3170178FB11C26BD21F885A403BFBB7F75F9E9F539710FE47CF128097EED65157D7ED1583A218D994583FDF5B90F82665E9CCD8430FD4D07FA66BD373DAD0641DBECAB180A89B309C54D2D4CB4BFEE5F5C021C5C3DDE00283A3BCFE83A4EAEEA9FC992BCC57F6A1E2ED3188591E376F63A6FB19AECAC2F4158E47FC97DE10C5C663F0231025EFD6BD177322467EA656AB76E91BA8EEF45EBD686BED13760DBD4F00FCB6342D034238886120AE716767A9CAAF021A0820A64CA39DC07B63C4A01A88678834A34215048C0643062A8544AA5C6A913F7ED5189293B6F6459B6F4F69AE8AA5418C60A6A95984FFBD15F95FE6690B51917803848B01E6A00566B9FCA7B091F47D2590D951120732A47E3F0281830FAD0BFBD543A9283A5D10AE78679EB9FA396C8BFA23D5EEF4F4A43BD36512865C0E2CF6D2DF48684343F6535013F9004C0CC57B5B5BEBB6821F841C161E55AFC1B1BFDBB82AED81241442393C0C4DC8013794C6EA165825FBDBD94BECA70CAC481283AE756F3DB19E4EE236D79043F3F9692BF204F558B00A01E351F72D558F8B1332323B29DEC1541A77FB10430B271F62B1C4490B795E4C4DE99FB2887A0C0F74AEF21FA61B7F52082FE04B87DA5E89539F1F445209270C8C14302B4E4DA3D80C996DE59EE84A1A96522184C660F35F3B7B779268DC38018FE867B8A4C85BC68B230579153A8E04FDBBD274BE71F68F42A85C4043D8AFA6390A965FA1621D1A8E96BC6BA127B6E052848651C8F5DD8604169314A66A39289C671C9F7083782BC886B71280D8EBEF44DAE11EE0F92A53F57D5A57FB16F440CCB4CA60996CA396FFEBA562382BE27183A7BAC1E0317CC9DC934E532C610859A662EAC720C940CEB39F4B0EF98EA9EE1C87D023513B0146988AD25B70860C6C7DB4A9CFBDC9AFF6F2905656E0CC40FC605D3E3A179B7C0CF0CC9017FCF1F391D20B58C75C1B0875F6AFFBBC133AABBBBA994B20F8E57792A7CD725A2336AB060E616A2E547FC8A7F74ED89ADF7829F718AC148C31F1DF614F3018F365A75112B879BBAD6C294C519A04A7FEB4A1AF3F3019DE52A9B878C50DB7F5451B11B5EF1EB232E9F387F9629CB3C50D51208C2A000433FB3D2840C3E8C2384982052AFB9AD99E8DAB5FB019F13628AC23DC1960D2B2047D1338115BA0C49F152CC4884B96200CFF0EF42C489EB9274F709D990BDE98FE79FF9F71CBDCA212840E3D72C7EF83F05BB52D3FCA844EA1E946D1D62F6AD9E3ECEBBB96CABFA24C50B50D88858DF3947783F66E709A9A9D436599E0DF38F40DD0DAD4B4B5F7639BF8526009A7C087CC8264C26A2A46A145BEBCB184FA560E50E31D5252505D14C7B9DF9CB9A2826CD809A966B6CE5ABF13F04DC985523F3A5C93F0B7A8EA9B4EB8E982C1D9A47F52130970337B3026F45B47D5AC9A0963B37B5CE9BD764B9275E0065EF228866E98F1631EFDBD7CD7E7D0450C4076641D0B6E8FF96FC954DFAEFAF45118D96722072DB8900C730753D2075DB0167D35F48FD3AB85C7F2CF4F95D7522F05201F765E1154667F7E63CB0FED63130DE2F9474D1A611DD1B401A6686FB2A66928DD0313AF8C3ECD9CAEC6DB23792EC8F75AF166BD62DC74B611E3E6A0482602870C0D4F2B01C670C83915137228F6489B221CE48BE24D37A21D6EE8284C56ADB0EB8AF6B31FD7FFBB19E3DB9A1217ECD3A6C290B51D49DA47EF032DFD0E9C188059FA86D12F60A5C3B96645F84F7CB87A1B1E41C0B828888F396F2E128E6803D75B1B49F606AC9F670618BFF920D91B4805F9432278AF2F3372E1737292028324F24604552222817A8F9899883407F7E30D03E9B2E62C112E13AC5E09C1AD0FA2D6C893B221CA5CBE543C85FA6DDC18A002D6F62D6C445A71E8FD9F1B9B4D69BF3C4DCF3C7B7A7D2EE0DE43D26B43E4263ABA6F3487809A0D52AFC524F458AF3770EAEA7BF851EFFC185D5F89542E91F119C6CFF91B07FD1E43FBAC57DF978D6BF03C1A7CDD4AE3F2AD67682791E95302AA01C0ECBEE00EFCF2918AC31E9B63813C7AE5796687D091D4F68277C63DE4DF7AC5BBEFD05EB9E015E3989F7F6A241E35FB6437FEBB7C923D51EB7CA6BD2995DB1FEF272166776BFEDF1ECE6E260AF251EB421C1728FB2C206101D51F04A7AB5CBFD1476156BE445808DEA879AAAD1784CE0C6B573C728B67169C1FC132C2ED18594833DF059461825A3D242A42B06C57464079028CA549AEDA47BBB8EFFA9E43C972B8BBE0A083E90E6CEFE91B9604B019FFF9882B4AEFA73C2F0C53549BA1655D777446ECD2CF238486E442F4A4CA13E9F7197D1B35E9D6CA80A024851AB7DD655E75C1E6C3C25823F9C52484A6BDFE1E2EB6581371587A94F9447C35DE8F5A7FAEE3DB4EADB74D0F6F23714D93285B6FA3491CB4CEB3649910932D9C263A37246283240D42F74B3AC430011E1E301665CC8FB6DBBC03E8FCD0D4F59690BC4B4B7362EDB8B7E40BC7EB57DA80EDA73F226E5B141D2764D0EDAC140A9889F75ADBFF20B4A73BFF32DE4ECBA627788C91DC1C18C20797D3D87CA0FB34DF8CF05ECFB0440B026076304344A4F4CBF96433ED8DCDF942BB86B5D1192DF4A6AB12EE78B0A1CCB85C6DC766FA877217F003AA25C1817BBB5EC831179AF27CFD32A3B8D6E8AF93439D855D33F71EBC6D8B241049DB0FDA40323848FB53BAE4C5F8EDC4271793D60E2DF8CA176B88A2A4CB1193731C13391741478E1976DC6D18CAD43559F66560EFAF7EC0D571B4ED4C5FA43F196D9DA9E5E7AC4340AB820CCC5A98FD6B582BFF7D21A2B7E4CEEB8F1BE8E8A1EE72D1E3C85467CB927173945BF41D1A993417A974ADE3F81EF5D8D4D8EE60EFAA6794082DC717ED9300247B818FCB205143C934AE2D9C13BB4CE3A464274486B465C95ED8C351FC934FD7DEA7BF83046BBD30A7D9A0561B9A76FB3F9C011169FD190FBBCEDFC2B69B7DDA4416BB2C8C1C13F3F93FC682B8407901F517DDE6A2CB7666FF3FE7CFCD807900C967933567FFD27B16FC67F0F959064161C10520393D0A5BE014A816AE121BBBD0BE99EBAA08A7D082FCE7F228F5D14100C07A3D405600617DA8F503166E82C264F89FE3F806BD972ACFE07B9B4C3EF9DEAE964022658E5B7BC44BDBEA406432D363957F301769ADCDD804E8A95702CFFF62BDE732566D19DA3FE7BDDC4AC738C4D39509015B2EC4BD1BBBB5EA13BDF82B9041C2826BA7510E3F10540C1067FB5BDB782EC99B96F52D0CC38F09FF48E328BD1B3284A1779D52AE703DE3B79B1836F6228A6FC6E99B58DAAE085BAF7CDB946FF30A5528BBF6290415900803931CD52D8A73729EE7610ECC6B711A6B074B998ED876AD2B67DB722E3F516E48DE0CE968DC12F805C0FE02E9FF51D9D7FD1B5E2BA18B231D37AB7553FCC6332FE585C3B8CB8030C9E4532C146DB8A9B7B7BD19D3676F332E992249C27C5E85C5AA10D5D7A243C8D3D0E2DFAD310D6F4E70C331F85998870E67DC4011D94641E6DFBAA4DFB67DA98DB2E7FB89A1BE1A803A075F1A1E42B7BD00F5EC65B37FDD59A0F8263E24BB666453FF2A189AEB2F644B26ACCCE0D5EE3353E2A7F9D73FD45C4BFB30B7F233F3FA60828571E2157564F6D610945A8CC012162120D21030239107ABB0D576DBED0732651C5DD54164BF018285CF4D8F3BD9A965AD9DDF6D444A720B51325EFF0AC6D435D4B6FFB212B4782C5CDE95490E3C75AD9FEE9DE848CB2523E764D7D62401E131167ECA7E85C699B2BC3D3DC9447F139F05C92B2EA86E85649ABCEE07461C21FCD1A8F77EAE6B8A650C8BA15903C6735A054234E9368756AE2047BC6215B5605E8D266D8BC7F55DC26CC2A76539EFAB26C8A067052A3A1736C716DDA73C3A26CE1FE5574A2C4596C0AFE6D37FCD6B2BAC172A767680C87FE58FAE2FDCC778DBD3EDD504921D11856897D4B40F60ABAB4A6636F0BB53CB23D9506F4082000D6E5953FFEAFFD7C20D2CF3D7BF330E0995B283A83C134A914EBA04E52EE1AEB88756061E0E4521F2F51F7561B7D79D2B9605E5D1BB98D8878CB4186888907B5622C0C0E779F8112C39B0D52903D73EF92E0B36C1413E1591C87229603BC4DE51E83A42F8C3E9FECDD05144118A6F0EA9CEE61D4BBACA94D12707C9D3171096E4C4DE2E05AC0D378CCD1DB79B8B76B9C9599A7CB90523C27CA0F1F0B53F1CDEB76EA8CC16FF41EF16E08FEF27A593C4F859B7F4F9D3B267D7953AA7795CD5DA51463A6E05BBF8474DFA52E813FBF9B480AA4D40DFDAAB4F42C3E433089D19E5CB13CA1B3B52A2B0664D7DB9F5D570BB7F635FCFF2AD2EF411BE34FC89AF651BECE2009BB407D42931818CEC0A60C8AA0BC1451008756FC42472608B723D78A03451AB394ADD180DE375442B6CF8A59C233C04B77074F7F1ED01D3E2D9605B93DAE739E4C6E294572D7BFE7DA6D54E2178A2B11153F35BFEC53DE2A00E8642F203C0B1FAB2148FF8BD283AE0BABCD358AA943B9A6CC4D82AB25C2E5E54A915BA01522FE0954134EF6E75A1E63EB090834B753F9CDF48BE03806FF30A49CC556BBBCFDFFC09FBC24F81C79118961CDBCE840EABCA652959EBBC2C75D7FC9CFCDE5D141DFA39361EE9018E3F0FB163CA1545DD8C0E9A4175C0573CDFE6C6BA32060F04448FE6A09FEA89E196D0478A609460F869F8FBA8017B6D18BF47CB9E9BFE027EC765A3FFCCE672D91082ADB07F975087A413800C08BFC8E33064DCEA753FD3073D2C6EB2D94DC1557310FB935615C896EE889A40794425C6D066C71FE9C7535CB206B551E2552AEE910CC2511ED97FD508D2A91727870485B8890E1E7C4B7C58169B548257CBC371A56D39749CA5515D5781D95BD7D6D7E94AF18C606A431D904875977970C2AD0EC786515FE391E5C2762DDF5C2BD95699B5F8288D21AA95E0761A2ABA73EDCEA08E7BCE1DA83A35AF339DD95F5333CA4DA28E48550604CFCBE2792F8BA990113C988E401F490755D873D6C1226E575339D9494349C404BED9F059763DFDC3452D90CAA469A22D03F8716873FD3D2E61E39E7C42B2F03EF3F31A4D8FA37A409B937B342EB2CD2C828E100671C4066FE1B6FC1D9886ADE36CDFFC80CC4F8AB7DBABB8F3CE34AB097F75488EF55B16942FA603F6FF1298716ABB32926AEBC6658CD29132DF5B7F24E33FD67A6A9DD0E075BC7F129390724950487FB884E323441FA4527CFFD9D64488AFF629DB5A9C62220E36B3D5BD46938AE555DFD1C7B6F089981A98A5B6A74E7C2E3A74A64B1F04B40343DA53728B3FD33521F5DA668FF43CF9BA399308D9152C0510E28CEC89317306E8FCFA90DAD92B43D22AD0585601329F64AE550AB19FA826C2EAA55A586447CD7CEC3CD3E3AD686B6990E0F027251A126E99B9CCED75AF0A4EEA2A55CAC792A0C704292512188FA4390B3B032E0A873764EB5E7C94F9408CB1230257DA2FEFFDAD561EC44B9EE6DD1717BBD6B9FA1322C0C1C99E337FF5F85B199F2FF9BB1EDF3858B37DECD41F783D0F01BC966A22C5B5E66BB96219B708615CCFC7691FBF8000F4FDDAFBE2B49D25D9406384E4DADFFA3AD77653CD7C87B569B761FE9C6A2955AAC081D3DF53EAA8476A8AE397A3125BAFA1BFD0FFD01190AAE7A4BEAD1310E9379D2EE5888FDD68FDC8F136C2AB7F71E050364E53490BDF6BFAEFB789358BE78D35590620FE79F1093657D9BB035DA5442999A76905B6A942B3E5DF65DEF3DF546D3542537D9E508D30611C2DC5201FD6258199310506D25596200E7B7DDE7791999A39F59C1A7DBFA0754598F474BFB487B356428A62DBFCA25AF129749AD0EC56CBDD2B037462B0FCCBF696441C9CF50BF26A7221CC1E2A4DF68EFD9F6BEE2FFB9A89DD957CB9B307E1233F32B29B9885125A3540F59A1A53F752C68922B60A9A741595E3DC47CAE080D4317F3F415B7F1F0D7F1EFD41E95EF5C7E5A7BC31C2F2EC05F73C176FC9BABF327A5C1480E39B17149B4C2ADA9A85D4EF62AF2B12C269CB4595A593FBA3A3C66FDFD595D9C89665D72E69CFCEBA7C2CE62F8090D5545371B6CF226239677AC61C6015221B623E231952AE33D030C70F5480F585F9DE2C94A77B12EE46B2B1A66B3F09A56F261BFA2F1598E5E259EEAAC4EEC25C1FBD98EC2BE14D28B88C7DB8970378BC295B3ACD3E3006CFE5AFBD0CEA1010B4927B55EC303CFA7060718202E1460A00EF357EF6766D6D23330B438458961184087A76A24A6679859ABE44756613889E021FE84AF12F943F127FCF85E95E689A421728B4F9513569083D2A6FD8D54A8B367F6DC2EBFB3E47FB0A06CCE115CA51CC1C24FC77AFCE4992DFAE9BA230B53F5032DE3B01BE5F419E00FEE1E6CF36D439E1215A5A0289275341D8BE0CD6FA46BE2F5345417F532DDB20134D3B3897F0602DAD4A484E344FC4A66A6B62DEF7BFE7DDC234494FCF971AFBB3D7BE57608CE173F5C408B794FC450CE61F6DB92D02D18E8698D436C68A7E4629CD5BF88D2850473C0FDF7128A9874C6DF8EDBFF32EC9CE5B2C57F108220DB8A4FFCFD0D3668797EC3C1ADA2504F7F57DD5435843CBE2CCF6A378302BC762406A71A95D94A7D4FC2EFB759AF10795580143AE963EA3E93E5A143A68DDF54CF08FEBEA4C1E378311D13A27D78950981C30D7CF21AF023A5C1CC305AD75F54C8E905F61B1FB30B49D40826F9C926BD43A226F650017E8000882843B0DF8BC6D58298020FAD737BC11B415CA3AD393E6883AEE206F22B7E3D731345405C7448068F12A29A0FAB865E79E3CF0F49520239839816A386D055115423F71A1284007E3985F6272B3F740CD61CE7E7D2381D872044D14BB4FE1F58F749B6794F3163C3DCDE2A15F0D1080B6F7844FAA96D181359A3CD5A32510417146A693CC47D99F33B371BBD1B01FC8F218BB1CB9BAED63E55108FC9E2F2BCA9D296AD2BBA07473C7C72EEA5117F855B533D7A45B04EF92C3ED37427BFFFA40DA07CBCDB7E87592EDB1B84A53F151245157A5A36000CDEA00DD6BFE8E9B79C2EAB0B1CFE394067992B557E33DE3042FE415CF46A4CE9C04C72A9BA27E46EB9994AFF7734192C4428431111B0CBB168FA6D2AF59518BE2C7E2F48A4CE60FAB29BABE987C8DDCBB5D687092DBED73F778B58A6BF1E9243C3C001728CA9363122FE84AF8C15CBEBD4E309F394A157948014CCB981475C7F55EE2085E3E4EF7C288002289FCD9608B8B4DBF1360F67C22A3B04CE392B840841E6C6BDA1D1C82F782917C04A0DD29BB0A5CC14AF835B6391153F2ACB90D58121BE94F0C4DAB72A519A9D9F3AACF1896FD8CD26BD57F6DAD12D5E43FF49B81976F7AC4E535CB783B24876FAEB1534B901769777DA7B986E50E93CC2B765F5DC9D3D44929CC398D182323E2BF0813CF8F4B62A3B54A3A4087DB195A573A6465F0E5A6A3C98CFF6EC84701039DF525FD2B574697F3C9D50F27EF8228AE279FDBFD3CFCA581F7FE954751996EFB8DA4E4488B386B1016B6CD1F45633F259D27D800B4FA4771118A3561ACB1A19029ABFFBE6B92946959564616E194949EE8A78477F027225F4E354614797B720FD0CDBB818DF93CA95B1841D8DC2B7BA0EDF8BEFB1CF024445016CF104D03C598350F735B0EFA7B0DE907AD7B047D4901DFCA7FF685FA4ADF48C96B911149A92E7D93A3C700C23A317071612CC23CFA7D6155695835F8C92772600F947BB2E65752319A4BBE69A730D585CD38254163258277348FA06384DDD8587E2D123BA55FE1C11EEE660BFEBA33BDAFE2E92E739DFEAF0F57033691C48FD067E5F9234BD8474E1565C2F48AA7BB0E429D8B624B15E39416BAA63F81F017E293C40F891421C05D4D3441AA2DA0EC3D413D663F7515C0A5E95E7A91BA5316BB154B1CE863B36071DB9670BCBDB2AE05D57B6052B8661323AF7228F512C726260CFBDD45EFDF2617394032C751A8AA490D184F17A903FF2E7C26684913D6D3197DD94179AB471C839D1CC99CB6BD7F9C67B529DE44E29FFFB5887EA10A5A0F8E1D0608EEC9BECE923303C7A541F292C5B9407744087BC6714D9B856CAA06973B120886CF554C7839FF584E27FC9AACF9D357532AD0BAE0F6E0211C976C0DF46515DC51299641A7D98AB48AC6474174DBA60E0978467F7F88F5DE10AA1742969C7E77C1016BDD7F0B850903881DFFDB8666E667841F1F756CA6B224A597F461BE46FA623FCCBAECE6283CDA047B399995923DA3F038CF428E3806AE96C1D3F6853695F4F6ED5B9A34F45BBE4D1EA8A6CE092264A4078EFA54BE07CAEBFFC4F188653DE816F4D857105E96E7CF13EEA78810A076379B80BC12ACC2696848A8CC855E4E829707473F41449AD692EB92E995C55EC96E3349E18C790540C3F7490573AAB782931AEABDEDBF9B050268B6A83647CDEDB8845468AC0DAF6D28AD027C14F58BABB82645FAA9D8D61F25DBF6597BE8AE0E46A2970CFE77F5F9BAD7CDF44E8D44DE7F226769E14432EE5BE8A5FAE4BFCCAB3C3598F88B3BDEE17FA25F6860D2DC2939D5081007E3C979E00BE93608C572946C85EE23237E1CC4C4F81B4FBC6740F0910E68650C74AAF48B95E8C8653887CD1BA97BF55F69A1A518064798AAD465F044BDD6E13738411AD51BC96E2CA9E80B369C84642583FE691E693F61D63DB419EE7B674C68A9FF5802DF6C42A7EAB2C6B1E93420775F34310D4BD907E37B04FBE892E3175AEBB0F9D1C9B5D0615A4AB6C82B718852F5323E63D9FFE105204052E05C5D1C52F39D92A751298A12F47537F00809D576700A9AA8A60A8B4C69D95F02543581B3FFBAB7E240C9EB227CB7F00621050FC5FF58774293FF39443E1BF67ED218BA7BF7850BFEEEC02D21F784117329FB51317EE55EB20789B863B28DD60A24ECA39A435BA051C82C593CA02B263D17B91C8DEA5DE0B2E2601F288D71A1549547B07B98019885926E63440EDCFAA414F6884E0E9A3310C4870E51FFD981926BC0D8BCF90E074B7B4CA964848B5F257DBDE91B05C6E65F48E6F47305C6A800225A06F5C354EEE9748B3BA06A9A20782FE370ECCE0C2018C3DC1A039CCD3CF2C0E448C8762F6324C7FEF0B2DDDF20E02785BD77497C7946771C8DF3FB19BA1C442E8828CBDD6AF4862809D3C0A1E11AEB1FDA79BE4796F53A562530382090678721FE5454EA5673E7662D740724B767EEBC6D95FE0788EFDDB824E315D9097B0F7B00B46F5458CF59FE53B2D9823842C80E98957FEFCD775984B4A65757C1963F58694C6A30FEC5A268FCB9AE53C2A8BDBC9DFA4E7125F5A6EF714115454C32DA64631E009BF2D1965E00C1194B6D91D1532349BE6257790D173FE802C06154E02202002E4B60AC86FC72389107CA74B40F3CB1745DEC83A0232BB3D315887DD4D25484AE300570D625CDA332B342059A05F4EEFEEE26370FBCD3F37C530B55BAC35AAE1FAEF8406957817037E85A8D08DFB4F8F46FCD5983D29571D09B72EB0CD4DB835E39E05351886D2610FDAFA0ED14C5212AFF8000C81CD364443E24146018168EF718B673C9C7DCD865722E3C55276C5FB7831C9DE8396D0F34421F8D93DA0834D2FB49F23DF910A73B60571C14B6F93CDC5A61EBCD1826E8673872201FF48018CC63F7D21AD209153D940D93D4424E43AB336E5AF80B5C6ED8421AFA21A787AC93C81E03F178972BD8D250035FA4D4F395435842CE15513DD69EBA73849D13B0E33CDD50428807C913FC2ADAF1DBB413DACA71133D24F9D019B198033ACACDCEC2083A0D2703F913F9D40EC0F63AA35CB8CC4698055B8B8A283C82E7CA0F34EA137441BEDD83B8A1465BB0550DB4D5476650E4577CDE6ECF76916024FC207D343D53CB66105E5BACB142C441D70E5A636B9B50D34E05F8BBA11CBEC2ACAF13DC39B1676CA68DD9FDB239EA0FD95BA3A038DD69550E90C18A88F7E69B83FE1EB9FFFE26031B2CA6B7AA0EA8A0630F4BE2716770DCA28762B1AEA67283169E59F7AEFA1C97D23446A4A009325A566038201FD4B513932D7616E8A7277A8879EC231FA89EB123FB9059FB2195EF2430C9F074D01A8C7B2B8D5E0F05F92271B9132CE0B37BE8E617685942BE47F1442B0A90BF43977D5D483B691CA611870745727F4BEDB9C78254EAE83D63C422A3883EE6E86BD9F73CC09DE6F7A4D8B0178874FE19108F9C52F360623597A58B1782931247C1DC955C615609CBE9627BC587F8C629B980E4F100A03C276951137545E3616A7F07E9BA1A7F662168E8FB0770B0A2804D8484A8865150258F6B24DE7150B7467D021852A0F1763AB31B4DD8C0DC59B648D089B5C1835589B3237961A76FC1BEDC93122FE045B012BF768B9E0F915B724F3F44CF8F7ABD3A983EDFFFEB4780368076B46D1A9818167BB7355441523B5E8931B434E8A63EB520159ED69932A1BC20CAFECBE120005649F2C961CBF67DEB9B2B6C7551F21EE75E7787B5981CB12E27CA88D0C8BBCFA00723D8C4F0E7B312CAC8CE4E8896C0321E84A96E3E8FFEC03C1C96BA28E565E81B62F31DE4341169C40439E18D212E4A7C93EEF5A504D21A1130887B975515576006F4830DE6AC6CE49E73F6C81AF0817832F45E5BFF08649C69E730279143EB2E4F0009FEB52ED31BE26FEDC606267A7CF3B7A521C9978E7EC825A8BC8C4B37F527316C6C36D86CE8A2F739187EED12FCD1E74425F73F596103657443EA8E32E0C1F7F1665E73CEF6402E07ADC5241DD71F85ECCB071F1F9591F0CBDDBB63966F99E807B6E1F60FB15D8E59346C3EB34689E237F861D3D44EACDB94FC9FFF783DF1228485E3E5EAA8317584275744293635EDC71230A274CB03CAAD83BF8DF6841EEADA5AD8B7507B17E11D7DF079C371A1E26F2EFAD94F732E1C606E4EA1BEBDEFB78121E204AA55A1F086E83B1462E946951186C7A5CDFB9626546100E05C0F3CF93A540743984AB2049677FF6C0D6F4C71AA3576368D00EF92265F72008017C786D071D7E6E3587C0D84F3A01592A7D4D172FADDE4EDECBE09051D9E6C223658EB44488EFFAA373DB4DF4A63B7ADF3FD73CFEADC46D4BA074CAF611CA9E008DC2D556B68B3902B0A6F879AA9345F0D6AF07C07F8C81E9EC886E1913A914DC5655AB28C2CD9D534301D4900484308071E8A1F00B814AEB25F4968C8E8F095951117AF9758D33CC529F62745F02131190148E64F979FA85EE7294BF7CD95FB7D0ADED5A1A9D1ADC3A3D0A6592EF6425DA019969AAD17054EAE012F0D0266883D4DC8389BC1475FE3D48708039B604829DEA2BF5E8AD6B91A71A199305AC09198F97F8FE3C893A2155E79B8795B6D539BAD339FFD3C2BC7030455AD24EED617CF492F9F28709DD1BEF714FCF52C55F73904B77D8EA965CA41C09CAA4B3782F2550AC79BC95824AEA2A855759C26187A956923EC5A4A9751C975E52B405860178E88F725D6D4E0496CF0271169B74469BDFBF5C5803F175A7FC43B41DF0A8E23AAF70B7A64F44FFFC7C20BBD808C6D40605E77CC8E2D0D71D0D73503D3DB1EDE47BF4D4BCF5A400E0A036785B274968FE5221A907E6BB582C7344ADEBF6D693A1CC8465F353C2DBDA97925BE90DC37B0F8AD42C36FA87D003D4EB9DFE588BB0907809F2E2243CBEB77DAFD05F85C70FC027D04C7B0C3FEAFEB065A98B2AB844EBB9C0C9B6F07C47BFF9CB76B9A54FD3191F9FA960EA1ACA85E80F489BD55949F551B27469CC74BE6B192AA70F9818870BCE8F7BB58FE7DEC6C034E42B55FD547A6DA6859F071BBD66E6688ADC0FDE53E23E5651AADF0A513FDDEC350B251F015FC0AEBAE49CA88A6CCBC879CBCBEFD15E1CB71053361365B8FED832E7BC5F5FB98026D51E5667249AA3403A7F5A85E423D01857082F31948E58BEEBA450DAD17301B7A6B7C2F8CA38351316EA2E9A3ADBC78DA54A91F415DDAEEA08A19275EC5CB0CFA1529490017A4E9097FCD1536006BA27F6A9E558AB8B9AA6DC94749266FF3D35BC18C6B3F0179A5BB033D3F07B0B7DE6C5B85323CB463680ABFA653BC76481A4BAC18A5F42DB934D5D336937012E8A319008D3CF938102D8D8FED77D50C69E4EA1D5667C357FE14968527B658C7AABAC1AAAA0302142F34C38D2EF806094957A640556F6A422A70D6B4F7EBB6FE1F719F5E6CF48DF20F8CFB1057A52E6A3C4C9838F98CDF5897BE7945C15D97C122CF4C616D353887F002606CB40CA2E795A5B85391F0B0BC7C6D1911DF8E57FB17B22C49C63698DBA7337EEBF26D28ACF615FE58B8C3B6FE02466FD366CEB4EEA62FCFE1D95316677AB8B91F180A0CB18F0873E24C3A82FA752E671F37BF25F751ABDBC0A61E68A4FE150198FCE1B22D3C845588CCF50B2D88BEBDFB4C3C71E1C58B11EC7420FA662D5BFC311E8AF2740089D2CF87B39891BD8307B43F0EA7970CD8CB0CF6410A82145FC8EFAFDE082E28EC7D25B00E645FC4BA85FBB4C37893CA452337F703E20A8FFA05C622E9471E83FFB516325EA81A6A5477CE0E70840C841F780CF50BCD582204BB47031BC09616D6BC25445F979DFFAB4250E0320DC5CB784B4584D679734F7C5BC35BE2F49BB4CC81D81D902A8467BD0EEEFE7262BACEF8837BC9A3AC765D04369CD524355117B9FD5E59FDD4A9C600373710E7CB2A557368867009986CD74F61C32CAF7155CB6955CE0B8C3EF01F91834BCDA4BA7AFF467FA54393116F2311E2E21DEF755EFA93EE52CD278F38B485B40898727BA1B305B4894E3F0A9976BFADDE69C03B24C7231DF78683AF7ED0F36FBDBB0691792FF37C4D1D2BFDB8AF159B8F3F8D2C52A76E7ABCA1086668780E4ACD1C0719E85B4D4FC41FC8A7D38BCD7A8128E3AE4C9B517F00DEFB5768A72554014C71BD41A4B1E2DBF9230E420B4E1A817CF691327BFD94BC7148038BD8315B7F0326BE0E1FF59D814FBCC5E79B59F6E8AE73C2F2818E8AD29415CF1C47C14569378A2F1920B79B8480E16D3C7DB7325DAA298E9E4D913A39E8ED20D89D706E3BA65B4FF071CBD4D84B3609F8FA49FE6C12D3F8D0D293E6DFC33E62AD5C2983569D0833142C46C704807C0F1BFF10A6761A0B8701D5966F2D983985C7969230381EFAA2B3BAE93F471976A91009B991FF44CA514ADB586D498DA88E221F3538D39D2C4ECD1414AC28541EFDE413F38A9A3E22D125211B07F58F51CD8F113AC1EDEDE43AD70EF5152FE4765B7FB2173D4FC5B2DCE14F901705ECC2D12F89798CCDA9FDB75EC7AA03C2CB91B97417D35D16694E28B23A0867720E0064EC31D8F50C9A79D065595CAD5110517299C64C8A7C41A382FBBAAD6AE94A3860D2052DB27A1063879F5B0A7ACA5BC9EA94F9375889FBE9248A63710EFD29093D491FB8763EF880BF957C6D7F08AA970547F09D1CDE8DC5C3EA40F9582BB16EA9C2E14246830F4D380CD22E6D001AA525A475F38BBF1EC9F2852BEF7EDF40D8A01542FC8920418A6364F7064FEAE980D7E6730085F2AE2CBE0CEED137CA34DE2FB0821C02D768643159CF6CD32A6508B0CB9AC89157036A74A82DA56B241D05AE0227DD9697021A98F9D7F9E066E5F6E92407F7EAC76221D9C1D8806FBAF2825734A2D9FFBB9E1BCF8194266368912FA641CE2A918C175337436FE76C7866E8636E22E360EFC5ECA459653E01D21B5912FEBA112CAFB15756A3885AEECE6BA895CB9A188AD36003871F86E873C4F5D99FD72293F743F090ADF1561A0B3A594F3EFB1174F2CF76EE5C3CCFD7C2804000E66B80EB537B6CF15A61F493CDC6A2F17E5B252ABD68C1BC9E59A15D112DE0F00D82F2AECE179CBD8A100C7B87E5A7A3B4E11ECF515C55A7833DDDFE32CD4B9D5A450A0E11D8B354976B258B034D865527237EC1EFEE14E744784AEA8C166169940B09E9D0474808DEAABABD236BA93A1D170E062FD0862D0A881C0C39F616B6F679A84E117AB71889B9A8E9E41B7B579CA46C397D07E97F3250EA4B891093BA22EB4EDF31FC866691A4F58A9527E6E46D836EA68978B552985ED13DBB0FB2980C22D9E1541AF4BFA3207E87BC30EBAB301A96FF2BD2B2F01525EA907E29729524F47EEB0585BAB3C56555289DF04A33EFD0140F90EFE938A4691022DB940B87437DA474C09AB3C4C40EF7AF911A56185299B1960A51DFFD331FF3F0865BE8CE279F46496C195A951B3C30D1A498803FEB72DC853FC28133F33D85F283C66A446377A12259DCEFDF6207E9D7F90857078DB9844D2DF5651AD1E83E29A894546C24F214DAEF83C6ACF7532502DE90BC9B6CF18970C8B58AF1EE8EED124B7D433D54D16B5B0A26095F76FFDEED9009FFDABD33B43D31ABE6EDAD05617238C15F138D99E5F84D39B806A78AB53A7969698A7EA82D4AC9F6DDAACE7D2EFDA1ADC76861864700E7695BEE60AFB4E152BCC7744E1D5E22243956248EB6D3269DEEADB2CA955C9234D3A3941381478BF6B1DA3576582283CDE39BACDF89A74893AEAF8BD8F256E498EA931E249A001C0844D9DDBAAB74C96DF39AAAEE9416C8A49721D4E0F23446758DA85761C09A6ABE9AE7289E0C3A5AE0139F1F8792B308127ACEDE39194A20A9EE45EC3B186D8128C1F2E2B450ED0C7FC8099E0AE3730F9CA198E2D4C9D647179167F6849D4105F60EC401B079F2F5AE1162A14D2BF30FCE24FEE3748E55180F8E9917C5323227BCB6A8E5A92A0420FC4F56DC6CB31203F4AA6CC4EB480FF3161978B2C3A3285341F77C09B389B68B67FB7E2BB092DDEE081DD2A9F24C1707868BCC8CB6E35E01C9145FFA7B1550E8BAA297C8771D930A4924EC145641C30F93B927C36F18E86116001DF79168BA46B4BC4225A2F11AE7B35E5AE9DBCA8DA016D04027E15497E97049B4A2000907D2FFDE7C4F1F0167B4C223AD63D3EC0D486A4587FF580978EDC818FBF6A730538F7EE98C49B19D904BFEDEDE0A7058AD1437AFF0B3A5CB348D00C89F574FAC55D2414E33B14BF840CC39AD4A2F3B30365CDE9CCE6E98BF1E5A1703A410709A3804A79FC0D605A81C4264E096B2968A2C9A11E2696834ECE653E7895A1B1B8B6EA76976D8018CE8E0D6ECFC3E8D7A00429469E357C9C5E5AE9A18955FF71B7642FCDCBC8A3B9DB70DB5380A3CF67A278136E230E072B67D0469EB4667125BCA7C7B1148B13886F993852AF0908BD82FAA2FF72C2717870EB5977C4F9CDFB597A74D40C9514FA74C997E33FE8410BF9684176EE110CDAF452ECFFC4938D7A04370686726C6198C3E09D3B49D99DF31AA4A30CAC034C7FD1D76DEBD7AE1CD27A38DA8E76914055A4845ABBF848FFCD5F449AD18BD892C23676E8B4329E120499F7EB5A79EA52F4B2FD790A0703335013E7B7EC00A3C8EF43F9ACDD0D8D4714BECCEEC6525D787838E2FAAABE7D53C7B6AEFBCCB0A417A8A6D3E27AA1E50F3D4349898A67F9F7154DDA5A3CBA6006F2D5EEDC1623FEA3B84010AD87550AF5E0AE0C7ABC1A62A987CB4D018A987141016C928DDEC431A04FB3447F217D0F57E059C52AF6BF89EA9DC5E5971B16E78CD334DBDF81B23B8BD639F45BE0FFF6FD23F51D64260EF59BF4FF35FF985A0E16EDE80AC67D0CED77B15CA776A9290073D150E674A7B597D9163C5050CA080E134AD30E8AD40136424AABED9AF15168EA9F1E27A445BCBF40D9060CFEA6378D343E2336BA672036FC5125892D308F9F604F3A269FDCEB00A82EE23BB1E15B508244C9A3F01E46E038348522EDF3EF73CFB03DC4EBF7BC08F7BCCC39BA632BA400E00ACAD2EFD080B36E1E35161D9791B49247EEB6BD4CB1E1B8825561F7FC8FA812C0979CC4E20EAA427B3DF509923BAF3A04ADE7D146E151AF61A33E327B36B476BD030AC3AE04F547693CDEDF549A5BFF57DC5EE80A10FAA5B1CF6D4BF6FD94DECA8F0AC9EA33764D838712015002B05FDBCDA15AB07FAA5DDC4779564EE3F3D2B01A32704567AB5482B3941E31162CD1793721F8827FD0AA7DE9EB8F62F4E5C4E129F1F1C5830BCE9E646E05C6FC6DFF70704247034EF597AD71BD7E2685152FBFD9D873FD979A7ED21DEA13E962FEC7178D7B30749D3672B3581DC14FF2CB1596C7864C2AC3AF04B40C669986F5EE76E036D6EC6F29B306805382320D28F89434A5D7D5B8565E33DB980AD554DABDFA3B1B4A51D00C7FC687F23CD56A6B80AE72BEE0DB8A7D21CE6D56E24047A07131FDBB43630363B5492840A3296AB3F63AB9A9220AE073C96B9697BEC6550C6B7ACC7C80973BB42740DCFEF133CE781446CEF050637BA6B885CFEEF1F50EB3C672A65E9CE2BCA4D086DFEF98F0BFC6AEF4FBBE2558EA23528A88167802528E08B7FEF20069D331541AB3681A9FB529844F65AD0183E9EDA6C47F33F25F0BCDED6692016F111DC257804C0B72BAA81D05F9F7B5D3BFCC93C77F37F2A9F2E4708A788A964D80C06D1C2C9A40CC0B2ABEB1C2FA83E7A960A0750AF338D23867496DB2783883987BA63194BBEDD41DD46194BC951937BFD0BB13E7D9F21CE19F1C47A28F24119E74089DAF79641B51F217D8F57CEE2934B142E4607347829EA22F80B25F367E3DCBA26FC0B5CC651C5FB9E9630077C3DFBD78162870403FD2F39627DA2A4C3D6D9EEC08C7C584C466FE2D7238F8F98C06F0AA9DCF4289FADBFD254F2D12F6E3D5711E70738E1A4998D573E6A22FCBB1596C41701D4CDB2ED9E6A925DFA32AF362BFCC81A381BF8402B0D5929501A241295BB578F6EE65F60B1B5A699AED7152ED85F11BE6A89A5070DE47EB589338F2E79A8561F24BF036FFE82CC3FCFB32F6E8961591B589EFFAE572EFF7BF68B6AA2FE33FFBC4052A1FD4975CB46D06F56494F4027F5D2A420C33DE6B92E44A8EF19F0DB7C4801B57B9A479AB23733AC6C7AD752B4EF4295E0D3133FCA3F8B84A3CD05ABE8256A0BC701E9D84BD4E7E51DF752757966070743421E91849F200644AD354F82F0E9AAEA0CBC8AD5E7FB2ADBA2F41611C60FC7FC27A1383BAE4CE8ACB62FC86127EECCF166DE6E29F9B79C2B5FC6CFCB31452E9184EB20D06897B8BFE893DA736C981F62B1DE22CB852AD7A703454289C8690F1199FD8691B4AA58321801A1112E8EDE7E367700209683B9B610137916B66B24F16EFAA603770CF024E420B75E488E47E998AE33499A25274D08211AAC58DE8EE90D983E2DEE92C2150EDEB79AEC8E61650A13C6774EB2B5D00D910F21FA53385CB8119251FCF62DAE137423F305BA788CD61C2D87942C1F61E6EA713A84F95B91A74A5ECDCF5EFFCEB1DBB2B3087C10DFE25784BDDA8F7132E126066E252067242302EA46A5A6FA8CE0F0FDC6AA338AC1D30F59FF82B2FA00C9C1205181DDCA7FF484B223F3905582594E3AF015FD883A71D3C8B74F9541C5CBA2F79F42266A47888A3A748C253D07ECFA2DD221AC301BA30D25A0994B109B6A741C6D1C991CC8764937C0AB2041641BEAEA06599E4F7918DAA9DA5B3BBA1831ADBD2B54E78BF0E35C744C0171ABECF13B62F6F13BAA46B5A69738E27B5D58093872CBFDF6679FC88CC5BA39C55DC4A5C0B1CBFC0F6973FC02759D963DC4136149AC10F45C2C96B68EFD9941D02684CAD43BA6DBD3E1CD16ADD3BD2A60985BCD29103627F71145E14F262DF4E2F989E29B663528B1D2B5285AE25F9AB3823EC1025E310DD7E3F917E65C88C7C44CEF30CC3544C33FED847FC35C23D9595905F7E36CDCF5B70EB44135CFA4A25D9FFF40DABC343DB362A7CB3BF5366B12762B5B5284A7469998FE20BDF6B29A3FED0F8A9F775C735C50880EF00F8B6F22998D9C458248443E1FFC5135E19F0F473CAFF6D35B6E0BE3CA7FD0664E8FF83DF37A699AF29BCF575B18C233D6998388FB4F9AC31C580D98D01C41283D4F2DF1D902A63F997EE22F20F6D042AFD6FE078B50979E7BB7E20D210355EEAD17FA8183B730BF4509E7FE3672A44CC71B89DE81CD7E18323D7330E86A0DBFE52BC78BCFA1A5720ADDAD65202987236643CA01153713250B70FBA4AFB6F98B94EA83D6EF2D441EF69350661BE25E717F7B35CFB7348DB6A168F35CC7193F48B0F8C7DCB48FE948B8597C87E85154531DC5F910071BBD830FAFB4E50436A29120BFA1A177247042E5BAF5298162FAEBB9865DB803A546A742A8150E0979EDF92C544E02953DDFF1B71036937E4CA0CA3DB5594FAD04475EA3BE40918C076F6F1FFB25C02751FC25C5756D14CE6103E0DB7AC4E153174975EA20A32BC747499E1CE134845A046A088C3936379B2BCC7C74C4A9D4CC9F30ED37BA6235C9FB08482F6D5E91C08C07221C117957F1E544691A638AD58BD688240CC1C61E3AA9BD3E4F3DE961EF9EA40546BF142BF94F70CBCE9370DC993F949118D3355B6087FFB684C2C17F63A11E2CC7F3DFA21584457809872F537C0CABFAEC5E7417113BC8FC81051E45597A1E692D47E1A28C1F07AA9E2AB3EA34789EF4A6CFF96115A57BF575C41CC066DB3A8099630531502DE0D9A6B26167C53DD35EE8B76DB2D228C1F9BD684757AE57D882A22C2BFD821AD8081D94B9A95AA977B8D9FFC2671016EC4E763CBB706CCB79E08B4A2CDA98B19AFDB017FB29342FA2FBC285B2F8245CDEC3E90F944DC3288CD37E7460FCBA730EE9F13A9F8FBFA4D01F6869BA5933D6C31E5F344E99EDE3558BA864835DDFE158E83A50A509A0BAA655D6AC9ADC197D8DB3FF657D291F166E965916317A749886061B074A7E5ED4122213B9B41A000801EF10105CC40966A3897F4911B517126C7B98AA638415548BFA9E5D9067536DFB8B195C0E07D1E79B806DE5B2E907660A7DB92F0A86D959FD4CA750BDC5D37BB43B2BCBFAE0061043CE453E4D2D96E460B90683BDFF3EB693D9C98786CB702E597CBE978AA2DCC068DD34B8CEF83A0A49D124BF5EA9C701DF1212A5C2137F6F3C14487EAEFB958A04FDCBF351700DBBB77B4A28B66384AB6DE469EC4157E84F810FDFCB0F4825F71C5BEEFEF78E08A7613BF049558E15F2DC9346CB47EACDB59B97BA4F08F0D8A47137069EE3531433CA467431639AF0257E2DC36E507AA0934FFABC08ECD4E829A9FC8037298E2FEA421D57A91D1EDF65A96C9793A67137676EABA32303604E744AC810613B8B5C0AF43DA9FFA0402FA698B272F06ACEE34721E14AB6422B2F9C579FE75965479961B906696E1B5115DA743B7A7E7D84E4561C9331EB5FA587A82456447493498E32A73263FDCA623F1C2CFA1D5F6AC521D633E6E2E5E4CE84DB4D71F6350107E0F800C9D35870EA4770264F3B7F019757A62962FBF726B996B8BC79A91C9109769AE43D619C7587CEFDAC46C701F4B1AF82FF7A823A40AC54ED74511A4B3BE2BA87FB5BA63F15706619F8C1AAF3CE4F09E01581E52CCC71DEFCDD104E9E6BBB6ACF3338C29E3AE8CC3D78E4258E678BA9E5D476F6E47533678C983E8359564E84AF3F38C0B10255EA7F08E2F2477BB3036458210E83A02327C00F48CB70E5804F320F88E1D78248A7BE1DF294751ADC82CF33B128418BB0CC2E3076EFAF1BC9FE81FE5FFCB4FF46A70E1A98FBE43DA6A3E479B1BDCBAF6FA2809AB64985CC05FC01AE0D6F0805B5711F70A3AED2629ACAD7AB7279C3948A6A3A39CEF055435AECD4F1A5D528F118443818440CFDE8E386EC640F0F3F2D297F2B0BDF36AD0F003627CA998BC99DB9EAE3580F916F43DF7BF42CC9F35A52B6C0BF9E8929E39E33CE8EF18A34F587DE4016D9DEFDC455623F53F84043F4FA9FD71B6505E596CA2B3F30EDCDC6047AC156B71079DBE13492D130030A4F9107BB7BD96BB5C9419089C3A38BF229AF8FFDA52D415D7FD8EE9859D0E6A784D6E0D7EF4F044344B79595AC09EC292EFD2686693D65354D693C0AD35DE7AEC3BC6871A60039440A9DC16F613BAE9692FB5E6FF91DF3239C8F1BDCC09DCC1627DEE46A27426E53788A8109F69D145F8C38FCB48A1AA0692CBF0F7AD0FFC6B335F88B8FB4189B7E4E936833BE04608AD86696820EFAF45F151DEAF33D0D891A878B9F27C532B48E2281C76820AB748C31DBCEF0116BCECD93779F0078799D415BA99BDAB1C361C3C10C31435F37CB12B5DB180FD0CF66FCAB8F02ED088D47FB772342991B9EB223144D58D3C0C1B7C3A7F6C7BC470D0352FE38B0E7B71D8C0723ECB6F865B05C4FE214896993E96288B2F00DC12BAB4EFD62B1910EFF7698CCD44B78B865C79B5D854A92EFAEB6527A4B77DC57A21C1973A3058A321CF49B8DF9225106B5DCE77E227CFA0EB51EB7977D2B458F8FEECD5D19798624DADF442921C3CDD0210977AB93DCA4945CBA0FAE3977275562DE5D5B2F8724304F4698D973A3A6A5D1D5024AA30B875946AE2F752E1BF1ABFF60A2F7219C1229FB76AD71402E6AE54CC926B731ED9B3B56E1D004D959720F48CAA08FD3A0F2BDFD604352EC3C234763A486107E9500E310ADA67B843CD11E31F33C1B0832B1195554E32B80655D3F8387D34D38C8DC238C08E2F17BA71125C06C01669BB08B37F90D69908C5261942E5CD1268254688358553FFA326109D35A0B425A5FE3443A2BFE45B3BE4B2C273180117999F0A1741955BAF96483966DCB5A4F98EF3851B352E408EC245046D1057381B2CAD8D64BEB33779B3281F20DD256B5411586A8E7796A756338A63669A20F89912A27BAD1920E07385A15ED6A1F938721E6E9D1C744BB6B9F5AF7750486EEE01223ABC64B37F386689E8D1FB8DBFD7911139D8A9BD8397AEC394A77D79B22C53360D6E62936EF88B2FCA36A5AEE213FBEDC241CD43EA59EFF98595A0063AD62403E71CA70CC6860181053E553999682F85FCC7A06B8AAE8BB6EC9C5F8787CEB81A771141435F48F32DD199B7117FE387D779D136C0B4C84801CD4FA54E13F026B886DFACEDC5BC7D2A3BE636BDAC4504E4B566A2E4A58B504B8E901BB11BED52BD643F54E6577812FA7A11F92D33ACA6D63637823E507CED9E294CC185C9D124BCFEA09316A8DFF802C68BF6649B174E7054CE671FDE4700C2C5EF653C08F0DF0A4CA989937D411C3C3D866BA41589B32D3167377EC40ED82A3FEA0BBE5B01A32EBF4C6D3531646FDE8CCEDE5F934C33BB5FC37FCDD6C1FC7FF8837E49F42351BC9A588A72174BD5C1A60AE2871FED05A3C8D1B97B6B6A8E8B131FF60099ED341BA33EEC89A5AC82D83A128D87EEE123EDBA366A2A374E71E7BACBE6428A65AE0BDE35DA7CC652F833A1DFB658D4C0FDED3578D9E04B9F4B810D5AC70F3DAD65642A1E4E719D2CC296A4B15D42A8A33FAB1A5E197BC3C2218A4DF0B20A04821B4A35503BAAB0FF3D115AEE667CCF12DAE8B191AE4D2BC1D83879C21223C5000A6F4163221E6F4BF65CBDFC9CC24349099EF5D8D7349D0B8D928C38CE4D8AA40EB840657686C34039EA8B3F7310A193975B5164FBA481C58F5A86D8855BAE829A4D2364813B0A9B45A1A80E808134309185689EF4E535897F2F6A2CC34BE395F7C5890A1EA89F92E18D8F8A0ABC8B7A1471EA03B73C97219C4B5A80F7847E0D0F44FB5CE6DE425C0B9E01E4A1D65BFFFFDCB50D80F7D67631FF033CE72593082A7C4070B12ABFB100FD972D3C7F4FCEDCAF39841CCC862776B4115F179ED7762ADDAE5D7B3AB46C808C9EBA6CE07DAE23017F58B998AFEB115B0C1D401342F761F8A7B09F73AF0BF1EFD79593554A79ED3DEF254D8BC9F950AFF862C11944F26F84E6095162959D4C87F1BB84CFBC34E91F1C9AE3DF3FC422C5E0852E7DF5BC10AD6E17F4539FEDE8FEC3A42AF70F0766CF50FECB9A6DD7B7CD2B1A20EF15C60F9F6BDB7FF0041E8BF989CA7A5E5112E5DEB085FA3A89A5C7476FB3301BA63C73A17865F8B4572ADCC442A32F850A1C841923B14ADC19EDB60D5D7F915FA00690C71E0384DFD6AC5D877F1C3F424ED54B2E5B3030D2580D8D3036FC2F02C91893CAF4F64A59B8DBBCF4C5BB91D01F8CB481AFBB50770D46C84E8B559727A96AA8FA36AB9EAA8B7B68182505D0803C5799A78AAA639FEB422FD695B408E33D34322A3B5A535E86C639B06DB5C76C300D8F66E126988C79AA56ECE8D3D7E26CAD05CC91FDC5B0594052EF85C83CFA07F6F919A501A0311A95DA93756497C41D703DF9F6C88F03D55135F22526531D5194771268D89EB9B554F0E14BE81F83A48CFB7ABEB5F8CDE77CBE0F169F537728C05C49DFD0D83AAC776A2D0710E71D6BAF54CA2D964631D3A1FBC1C1DA4350136957B927EBA9F54681DEB874E1462BE254624A81AF93C18A9BB58C2D060D9BEC96C474A49B0FC147E4675D327AFB5E27FF1713EB317F995A7E57D71DF4C88C8A848CDCF96B53B308D0BEA807788394E2E902DCBAB0707181A5856317BDFBB16D081B329002691491708B5E91E2F512F7C4FA6ECEFCBC36FC233D483ACD76D8862F293F4311DCDA26CDF05087EA0688D7255A930C58FD55F94F0B0562D314AEA981FBFEE1EB3F6C57FDF4B53990EB20F5D395DAA682F59F6088C9FC86651006301C7415339879F6FAD3BE99246B216D7E4442508056D5DEF8CD3BB2E2EFF9C03A3E9EDCF687F20DFC1CE0A906C3EB547847FF08226943002BC65C14C03C2FA00329C7E991EED367E05DA17E969CC6E56BFC462FA9B4955E67984D2BEB2CE1C892191FACE3B09AC951802BF276F7DA2F624D4024D39C50BE40AB2CAB94E8623DB4B048D789F0AF2D79FF18EA8E1005CB99C56276ECC831C1CF532459D7DA562E5312B57F2A06EA44812E9264C5AAFF75B74B5110C3FFEE1C0FA82C7413969594CE20B20965FD5686AD478A0C057BDBA747F00A47C65B21F5F05AF61DEEE415E3475633FD0EFA9FCEBCF8BA9153C2F924EBF9767929CA47C8521BC8AC3E80FD8E0B188218F33AE10F3A09180BB3B42F1398C7EE6F57EE220B8D3B2B634E75506E0D5422723330FC6667819ECA9944958CAE25A85D41F6AE7EC373D502FDBC2609D056EFE72238378081E8A94B1DA517749DD3F088EFC0FF1AA5E4AD045E35177C39F1424CA8D533D05E377590ED6914FD863ABE387C8F8A4725DEB5BB34FF3EF91FBB2B67FB5AD2C2023C937ED2670533BAEB09EF9F00EC0C807408C417347895FB68CA518ABF35EB1E2992D37AD901A9EE91329E9FC9A332377B8BE44BED3FDA9FE2913F91905C9F354FC0BEE5F4777E3CE754E4B8D8B848CD033D82B0AC6F93D3BA919FA229B7E027A64C0996BD0D95E40656705DA32D5211354DA2A5531B7C698BBD840757FF0968FD359BD3102D62B5D1AF9A540F20F4936A117C35FE553B01E4548F444DA56E7AAAE6E7B213D75DD2E07A13341107A9AEC3FFCEE35CAF971A7DB5886A6F102846AE0C82FB42ECF95564F2583EA4A9FB2D4C1CC6CFDFCE0319897C2BEC178A5F6E91D87B1C7C35C3E488E5BBBC6379EA7CF1CD8CC27804ABF4CB636A6F3597882EEDBD13ED8F806817D11F2D75DB48A40EB2CF7D125604F152FB30539536A99B42DE9F4AFB7197854F229C986E10E4CC4F7DD6BE5C7AEB03562F830AF59FF47D45C4F1AFD1E4F84F4F9E0E97B0ED0DFE5B1653B7BFF56E47262683A20A470EE776EBF9FAFF2FFBBE239FFD718460251601377B9A0C34585579B014549B23C23F0AA62FD36147D0A0AECF9A9233C031CC6BE51437940FE9FA5F0F38E5C089EF2F20CB5FC7F1A04E898726100C17E13D7F655FE5604E05C3F50144736480B05FD841A02A49D4D68AC436F81C8B8E4582AF1183A99E8D008F8E599509F938F83D26E14BA192CBD93B404E67158F0592E31535F943ABE905B29D7405CEF031D001E8A83B85A18BDED070D2578ADFDAAD8777F31F6B099A8293403559ACC408DAB8A72AFC1AE017760B349B7280FA4858B77E392588423382A42042E1B097B55BEC0CD7D398F600288A76A10F0F493CBEDF2CE3E0A1A393D5F69E1CB256DD5073A037F842AD57964EABB995940007029C2F5161077ED7B5D36C4F3F4E44CEB89DA7FBC058DA36239809EE7956D7176A807A0492E17375FD726451B2701BCCC9525702E23E229262D880F351DF19D94BA40391B810C170280CB3D1782BA063A2E902573A8BD99F70C67E112E2BAB41A1C8FBC917914547F3EBE9A96C03F078B2992B9533AAE8346020071FD8CE4A054999052E657C749D7E13CC6EE23289F14817BE05E9DF21DCB54BAC3136394FB4EF2F4FB73B7E4FEC001F918E35C1CE10EF976059990428B98AE8ABB8D23F475C15265511E0E2AED0F22675EB12CCE2986A201EC4E8B9358421B749E8ADFE2F7159994FF368FFF062962310025464551115D3D0CB377D60A42F70422B35E7013551A8FF38F2251215F50731E6DAD7E3BFB4F3A09BD69D1B95BEF46D86FDEAE852AC42CE007EF5FA1E6B24063E69BD4EE900346678F3075942753D4B453FF606BA4F876C4A3B000A311E49D4B19971A5D098DBBB12092694AA0B2A6767A513B9EC1BD65F26BFD5F822FD87930578C9F95A91FF5563EB671B8497ACFC47E1992CC0A40A653C62891C30257755A06100BC761EA0764BB451AE1B586E4B244438200FE057F974475360640BBD70D808097A96C75035DBBF9B86F4A18EF485B8E4EDF99D5470B95AFC6420773C6AC69B8DEE18E7340C87E20BED3A6EE712D55849EC78468E855597DC1CB5F0E5F253125FF1BC47E8215AF773608416269B7938140E7EBBF2031762EA192D3C5EBD8B5CF755DDB39912882C993F8B3E4DC58503916798001CA803F6DB20BF800BDB9F5868C7A068AEA2D7E20A70092EF474CE80F9E594BC2A22EA2FF02FB15166C47B24AE1E47E9F6FE74CB60072250F8953F1E20C92D0296A703D27D80E180084260EA82E64ECC897D21956FE8A3C6B88792E40E45F64EB6821BFE88FF8B819E657C29F0F345BD938515A2BAAF5D2656261D66D6DC3F3977FC7FA535A2AC477CE2E63BD20144E7BB23BB4FBB4A56D9ABA6EF220E89B320550FFC4F5BF5C995024C106E441FEA97B989729CA23FA02787CA0D5577A9C2A1AEBA119372CD208E71C776BD247C2BDE298446B50A05F085117AF21EAC6C64E024C259E018FABA1C6D16CD3163A5422F38D399DD236FC1CE93477FFC3D6B5F67FA3B55BE1528ECBE799B556FDC0EA7AD9203BA9369C5E8DC5C8DD37F0123CEFDF34CA14B0F7A1099C52CF319237E87C6D2A7AD1C72724E27888DCC59EF104A7DE6799DB00F017FD181F52444037668627110278A58962A9E40364F5698314DA7C6257533471E6010776CCF35930F11B44B20E9A6DAE6B8E12A9F418CBFC9AD1145F5815E56D157DA58D59208C201803EE76F2F2A06CAE9B35F8F492348929D86C6ACCBCCFD6AE2AC7069C3A1F967F90024F2F7D308E8EF93AEB78CD43057B318D4858352AFFEE4B087E807FA8106A226571DB4E6D1FE09C1A7E56483CE53441A41ACFD8E4BB6A154B581F16EE9A4CD8E9B3EB68353EC20C009201E5015F92F0BC49BBB92D419E874FFC21479D91E63E1FFA0A5AB770C7F10E72C48E41633728B9F8D0148935F25517EBA9ADC2116DCF29A8068222B0D34D6CFFEAC79BC26DF480644F3A4CA9C497BDC5A6F5695A6E942C7FAA4A6F5474DFC155E858832898409F12DAFC66498D7F344390C00600FD9DA67F76A78737E6D211AF96A0D95C44309C065900AE72FA75E6790B49300AE94B0BA2446828F25EC2FF784749748FE7343F566B21182AC87215D6E500B0F4DB5C86DC0673A60F59D7AA12BF16E3DD281B3E328FF2017448E201F41E17B264FC86766B30E80A655F481465ADAB8A58C7AED377B0564BB2CB3B6970021FD18CB31BF462EE3D35349CDAA4F2A10E4E7BE3A9DD45DFC74B3D168ED571782493FC98275D2BE509E12BDB0C4FC511D073C2D1CE2DCCE20A2C4E0817765846D1EEA81D22D312C47CA97B368CCFBE41FAE0EC8EA8BA4286862A995DC7F49D55D3818299EFB88405A82855A0A76EEEF3F814B52250AB25668F88937C96C353FFC90629E4D8DE9CE6513B7BAC8F227C9DCD71A30ED2499C7C441B41F39884D9878FBBFD145934FDCC69B41F92E638861C8306AAE88DB5DBB123E8C5A6B0CCFA20A6D170839E368B70AF5611718E8FB2F4AE0746DEF7A35BF0EFB0058B2307BE4505C9BDDB230D6D735E2463B17DDF75F046BAB287B6E0DDC583DECC5CCCC8691DD89E5C6F7DE7257BC17CF5CE322F7FDB3AA33E4556015B07AF0DBBA0796EA88B7E28F99158029DFC3EB230CC246083CE570FCE6702AE70AE4715ED99135BBFE79364BF79282DCC045D7AD2100A83BEF309AEFAB9662F9144757D64D54F10B1B39E6186CC84094911E9127EFB2056C0CF526FF7AB466A7C1841AB8BE9E7C5716648C2FBBB428A24460811CCDE0BD66A6D9ECA3B5AC6EDF7E2427CB65D849E93B98AE04D197DE769A0BD6C99A19532E67B3A21DB9063B725B6DC92BC5A62406893E9E90E37F318464D36B0BCBAE00C5E1F322D25E6E72329D4A492F2E30980AFB3E1F2E5B07E058703D344750BE21AE7B0976FBF8B7186240266D2E85B5EBAB8B5C5376A9F731EE4D2E45100605C01D3E68629E0C9E12F5D49199780D2642780340B396C9FC900D457FC62719CF00177B6B5A5D10B6673585781ACC4F7CBC378467521CC29589A7FBFB274D970EAD3D11FD0E3BBF128A4C775ECFB2104F26C2F0E63F788A2B02CD1EB07129BAAEF6D13A787F3D27004BBE97102FEF54F941CA405300C3A09200E46C5CC5C4B36D93E75DD098BAF26EB6C65D48A5164AAE21FF84C7F6940EE2C5DA1D8973B0882482638A4145103F0B96EE25BEFD2163A869BFDB5A81C5AA6FC4C032EFCBB11A60CBC319B6FF0830494F8245127F5C8BDDE6425436E4240F0A774B1B277E5A8E5D6BBAF9426E2A748007544770E73A438A3FCA574C25C611476457FC73816E524014E14FBAEE3DFFBA2BE54E1CF3A6C7B32640C321E9DF46E39BA69957AED046A1B69031DC4251BDC6E33CCD4E7A529DD9167CA6C77B6FE844E88684EBEFA9246E79A2B40EF5BD42561824CC0FAA86CBED7C60C14C63133D7E3B5510902C6CE4872C63E8FFCCE47FFD5B2F960D8A7BF809F775E8305B0A044D64CA876FB11B835628F53BFD01FA1DB92900BEFBDA4794A46D4EAE57DB6A7750FB8760996FBFB0CCF7297289D6405EA3A4A8507FE32BC22B36AEA80461C5EC3800F665A034CB7B80119A8FA68055357619D468FA8086F7B4BC01F12434EDC724F23BF904F86299C7370EEE1A6F0A5FA2DEF564C133D096A76EE08AA2AECEC46571C2E4B09401E195A9D93299904C6CAA4D18A35968940F568D6D17203F5C48D0A0260CF7E51B6EF1D3E977B6B7EEC8C7F2C2004A4B46698AC45E30888170BD2276A9338D510F69664A66B621133A5D488DBA5624EF8B3670AE8FD08C98E8F8FD744C3E3D82B66C25E9C8D2BA670D6A79B059AFE416CE36397E6C2F1B06737D3A696A65BDCBA8E6006B38669B6E6941A9668B85DF50C482E58D00DC91C09D7C100012B3C5963FECF0921FEF8A01918800D7FC6B280DD796BD8CC79136E64CC492E3250AB77A3E926ABB74D36BDEBB18080B9C409B8333EA20D1F15887E24C95C5430704DC68187A4C113F7FA63E0F70B1BBD773C228BF01C7F85736DCDDF720C9DE4A180F0AEDFD20FE7447438EFD8542725223FE7F3E525DC7E95829B348F41BE6822904D7E955DCF8001ADB9BA9397140FE7BFC6048652A136210BCC7FAB1266F306D8C095F979C9F83D04BE45015FF3E8F7AD6D6FB340CA7792E61AC45ED8BA6D93CDD6144B425CA30F76AE1B36A0BE0F987DF4DC7F8085B4DB84C02793A5392AE3FEFFF9966CF9AC17DB95205C83FBA1241EA6FD5C378FBAD4ADF0E77793B5E776E9FE739E5989E5ED0B35133A297DC29E82CE545BC33002C8AEE38D039E4242D9F75871F6D92D2E86B383FC4B1D805AE88E338F82A9760311C25C41FC9200C0ADC64B884348BBA548657B2AEEB4A99563DD5AD3EC75EDC3AA3D4EC1E8588337C017FD9C9DE4A9ABF5C92D458D82FC40EB3267743ECC1DBFE0B166F3A8FF795ADFE12F79F36114A4C62374761FBFAA395A571ADFE473AA723B7293902FCF45AB98AF1B0F505E163063209B425F72CD6A73399BB245C07C526EFDBBDF54F80219518F592697FBB8E5B0B3D2DB2FD8229B63666DF27A8E5AFB35165B77A2532FDC355CD8F200C0A08CF77F617BC2AC51E1F8E162175272FFB28ACE11FA63B76B338127DECE9FCFD00302F59F8D2DB1005DAA5FEC03673CAA5DE0AD6AFA2B9F02A400322BF2B1866FDCE60DC67D1462971E6F1CF5FAAD1A01494D8D737E6645260AD34571EFC5A899269D7EC8C7DBC97E58F1947068C27DFC9DD1927A0256DB71A3DFAFF5BE40056816D738A3682336719B03F2EB6F13ADD3CEB197F75A7F4F39B2F59A396E6F25C660E77E758BCB431674A4563D160A7614817454AF5D54CB31077EDCA7A9BDDCC57F9F5F022B6C0AF9E88471CDA554A55594CA97D86F6B2C919928737B966E53C6DA78198F66D2CCC866C0BEAAA2268BF681E6C98B5E238ED68A59383846D6C8640141EE8538B6A1D951F33062AFB0158C8037B5C0BB44F13BCB39CAB9344D50BFF65861C58FDE93DB2E1C587A09CAB0EDAF4D301B341D787C6093FDD9C503FF2C3F6B7F2957390DE3C185B598979EB16FFCCEB295711B5E2EBBEE00048CE6EAC06FC6BF7C5B45F08B4D61B86F9C32DE4CE889CD567B6D46AE99078F59B75042951BE2FF63F4AECE428F1EA368FC330927388806FCE259CAD708B005EB9A58937CD127EF6B05E0C12046F724DF95F3645C4D93346B87444F0FCD3072600D1DAD10169EBE13FE6D2F8AF88B9FF3CC358DB591DCBD5200FE71F0A541CD1979D3009771775FC124AD7B6C334601186DDB69B0CDB3D72438C848D8B0B2ED9B2E04A32F8362187807D1C747C3EA418BC974C2019DE1821D4BF20FD2BFFA8FCC615871C370310A8FDC2EDD4771A6FF151E0D0F817ECC7EF94CE271473F9193230D713637634F00327968D2A996B4A40A31C179C343CD28CC560B7854CD3E8FB0DF0942644CE4D1067C73FA3CD9D21807EC233217CA7BCB9B7DD466CC9640C1AAA02CAA32C6B722C30B26A25CE85DB6B72F07162A480BFD62576F7EED91F638B1AAE4F5ACE5DD75CFFB830264A95D27F3DA74E1FE95621DC2E0C1CEB66B3065E3A1979AA8D6B7FCF7D9495393DFAAADA0CAB1333B5C52D0CC71E47C32CC291C9915D8EEF47F977CC14800662A35C2485DB32B11A5DB6507995B10CB9C34CE164E19052F88A80767A27429DA7FA13DF3C95F6D9C16017D3A9391B733275BB292AEB61F211AA65AD7647F4F14C95C84C503D2678011D2447163D4C5E1E014EBEA225CCD9C58FB925E01F27F591848445FB1D5F43468E0B2D0695FA49E9B7B65F011AD3697770565D795E31160DB9C689A3713EDCFE81297E2FFFBB99BEA211E2987522EBDEA71E8E9FE22BC21BB1DDAB53E065D8D030D0E3EE180C9A4593D2BCC195F55F90FC0616B619D5C2A9F267C356F02D92CFBED008DC780504D0DA2462A0A1953A318D7CBCE179BF2DBFF0B0F16D2026275B8A2B6E490389F52328AE0719E0F88BBCB16F4A066E53D381EE9288CA335F1F9691881B64BF9BA4CFB49EF55ED3016A0CF606F58324BF83206B4622E2EFFC4AC881BF45C8EC1F0C06C191E2EAA7F5A630D1B40CAEC364D3F0C5A220D25F501CE17362A378100202CC6FFD1FAC5A3412FE41A6F047AB64C09B7BD3740D503B9857FE1A9F88C4346FF6B7E8C3F384B8B6A0EB843ACC6A7C3656188B5AB611B9396BD0B90606666B1C7AFC2875249859AABAA0C026A5675212B5B1119F7BE2406656DA87125531B17356157D605C000F90CB58578C2BC271D59F5E5ABA12C791450DA7F48FD92B8FD4C0641DA04149DAA3A3C275FAFBF4C6C427A8087E4174073F044F126E96B9C1E6DB58F2A8BD1DECF5D86ABE3658CE279AFE455CF99E31485053458A366E69C87A27614B445B45A1D48657F82EC34344AB4B5F586C76CB3A7296B1B1EE31BA40D62A35B652551EE2E5518A4ED696EE85361F302238A46E4F029373DE1B8F7941D593F7599FA74EC73E3F4D8F8AD9DD86FE2D6B00A62C083D318D00F1F43F1970A84099983D66CFE264918FF8BC291E4E8E3484930E506DB037A8BEF80BB86D37917796B24C3AC4883618540633A58D5EAEBFBFCF1B9B42EC1C7C9F3AC27153EBCFEBDDD3519EAEAC942F2C3C24C7F0AA54A347B22D5EC7CFB8115E70E25D47386C317DFF2BD1970E9CBA5B1209CA6DD8B24E6CDBE8ED5D1D57632792FEF2FAB6B7CD7FB96ADCB2F3C75E31C4C4D2B0D7FEF6A39E3C88A31094ECC28C19A8898F657AE24A5B850C5C01383ECAD7367340D55E2970C14FC5D9252B5EC8DD26FD6AD82520C01526D320335770532807A30D9136A52172CFE5931BE4ABA9100ECAA33C3CAF6779672ED7483D16D77B7AD9A5AE4E434C58584B1BB549622F34C117B64DBAA97B96A3481655C7DC4DAC0D488E9DC6DAE5C74DF04349FAD1E03E414DF8FB4403BC725F46A202EACBC8B3A12FABA5C9D2A4364DEB906F52519E14979E9BA523A0CE7EA975EAE91043CE423449C805F7B37E984C10BE6B7E6861EB883B9DFDD0D38187EF5ACED82B41CEBEF43E3E83458EF529EC9797722B24D9685AE644A0337187B673F5F4E7011DB8C5B24FF85C81FF0CF2BF24EECCD884A5F7F27E4C65A4D047CE8D1344E4A88CCD90293094F6CB91D838AC37628B0335764CD9E47A95E3E4878803A7E3E09271F0157D2924D4891EFC52C9E59334F6C6973BFAC4351E6622D5E11961DDBF528E39A9BC6D948C1E7C5629315D9D5FB703BA033295C9742D7832B810864C575D09493A2338CD44C1301303FC31173BE03EB276DB751A7F4C2AE3EDD069EFFFFA75BC89B90BC5CB9D9DD778E9C2C8DA34B0327783DBA8EA4BF61F045AE121735707162A20BF0458F036953B44D454662A06912F9CDCDA4E3F54309C1440A6E2BC2696E02BB4FA0C85E68221A0E8F9FFD2FB5CFF0BCA7085B5E3AB76AB40B9A14581AD3B9E62FCF9A936FDA7D63119BB081EC9FD741ED715D2629266B7BC1F2BCF8EF0E71FD6563E39F19E7DB034BF6B8CDA56B6E5757C12B8D463B59ED48FD1375CE6D0E22ADA9968CC82E94B6597136D195AF53FA3DC6C328A7D2DC532730B3E346B0504646ADF74E455C104BDC9DF50617C993243F009D46116FF79685C795FEEFD2C65D16B8610D4DB42C2B662DFB14A217B34C2F9576D039167ADFC42FFCA881A79805FB84A61E9F5DF90DB63A4E5E1CCAD045013F8D52669867F2044A3DCE9B5C6F6896F4FE717C0C37672FE7577AA7FB2AF8123C4B15AF350C9BDF770138D700B6B6A263996F568C69BBD7C8A0F7AA91E39C7F771D29720502D5D7F118B57D2F5D330608BE5216C8A6DE0E539130B52C381AD4EF2260598F008E5CB5D902489A0BFA92EDF1C3085FC43EB42A7B55CAF47F2D41EEA4AE727395627296A64923DB1435D2A589E1B33E73E88BA8D8F20D7B222B331A54CBF3FAA46A81A3C738533BE432F6F60A3B126E312B681C7399E38D3A60A92B8E29CAF468F34C5C596572247E80DCD61DCAB84E29F6BFD8783AD4C35F83E113A8B1E59CD347ABCAD0A5DEDD40228F9FCCE9CECDC41C2F6C65CBE773C7A5C6A20E0DBD255151E5AC0EB8FD5DDD097F59A98E295C117C028E6D5949DD8C00783CF4DBE1729C625DD5E15B26D184773202ED6F747E9488F7D701AB3B3C51A916DD53842A8BA663CE35A4370CD56FFF92E49A3A171997E068CCAE81872FFF93676403EA6742EA07DFBC42EF51F982B7C72FC270B28AA6E228E5E90F83FFB298B760542B00E9979FA2C8989E9645014AA82DCF48C84814A0CD7F888052176E791B56B1D459BA0ED6154D2118D2D071C7E74FA6BA45CC1739F4EF737B34E62479F07EC6AC6995577BDEDA56A547399810F87FFB914DC86887E65CFAAD2361CF4D2498698CC95678F640E5BE3DAF2DB6490B4682B0676E00F9E041B974B91A1C5968741FF0C3057159D8B882C312AF560C3250D32D4D032982AD22787B063A32978167009477A55BB5089D6439AE5B2BF96BF68F63733C6D8E0BDD33A1407BDE252E12870E2BC1A31F2B2C03F5E398D63BFA13674946B2CBA81CC19C37761E459B4996962FC62B77B583D88903C5E16E1D2AC0A7C4B5137501B9AF3A5A61C79A0728AF2CAF098D3C05A3F26A340FB376CE5C4E79F189351F4D95B43FBE6EB902A592B7C7375008E9B1745E04F5059F77BFDACB0399727EDA2E13B8405B5A0B23E134976D0B6D1B9291089CD96BE30BB9C18F1C59573632595DCCB34A9400F94A4C18918D786F3AF2121EB5DFA2E5E1DCC00FC476CCC96D41EAB0C34285040223142C48411907ACBA63C1A1D3121F0A258E143C35178E21525855258D65197FB1FF14F0A33771C61BD0282C12A171A14AFA08550891DBA456A7B6326931E63B8B0D1EBBF6D9294D5E7A6B9F25AD90F75632502C72C7F1D84340DA50F67C5DFDBA80EFAD56EE9FD8F13795BB77D848F10E74E8D673077A77EF54ED30F296AB177B118E671D04BBF44182FED5B1FC0550227A8393A6297123FE2B914C15EEA453FAEF54DAFF656038439092D64A9AF399A8A2D64CE60F569F8CDE41469138F9DDB704B8508ABFEE9B80725177E5BF2AD87962793642BC1EB94BFB5B02A23A908F7D2D3C659CDBD66FBB90D3F3E518693BC2DF5DDAFB816780D43EFD5A142A54E6D13D405A2E9CAC71EC4188576F9B996195899996FD16CE8985666542B408E912D868B319B3EE8DCF6667C0296C873744290FB54515C5BDAEE338ABFB60B1D6F1DC2E6E7906641BE0F0FD934A39B1C867193C2B9227C27580D5061B2F01C5D17DEB996DA123ACD64241C135D13CA721B61B26521403F3C6DE20DC638153F67DD72DC752416100E83BE0B1367A71C9F4F0B421C2CEE8BF5D3697D88C3534BC2FBD33B1AD5DC1199C5C72AE0522D5C9D86AAFE23322402595CEEC15F8369AFD1D59B051E0439B3A71C516A94A5592701DE581F4F35354C6B945B5003E7E69A4613062A86BA937D1AD535A2972B2EF279B495D7411F2E087EF2ADA0AA9237B5A3783315E7803C1BF6CB7AF278C84C1C7BC062DB8E8FA5CF9B71DFE899FD95D22464A27610D4EDE04884835EDA36AE20694927F32B441DF51C37EF160CF738E75FE12FE278152DACBA8BE39C4CD1EAEBB6E385C82A0358EDB3DBAA249E287589B4501882595D8A9EC15EB751DA35BC02528751A16057F52BD91E78FB70A43A6DC9D426E5BFFB89FD3D41EB2A54C60A8E254465997BBF2857152065EA70997DC256C1571FCECA9689847A3DBC1B3B3824A9ADF732BC0C3CA36DFA295C7CB3322BA9739F32913730D743ED9FC68EEDBAA499D40898B967D469555ED8F7887A4AE07EE8EA08EA93435F64B9168E3F40274A29701E399B8AC64AC070A5FB6EE8644FB7468B046CB8A77A0234ADF05282C5CEAE9F2B221A8BAB4FC0349F9597A4DB86822F3E851DA0995EB2536377D9A35D1FB07578062B6AA8B9492DAD104C2355CF21C124955BC1CAF771FE4A22571A2C529CD069A5B5512620FA8F749035C2CF50D84905FF7D0D3143B46B454B35791718E7ECBC8EC433EB23C2B0889C0B07532328AEEAADF38168C967A7E7716AD5D8C000B04A213DF6C4F44275F2308811367B52F422818411C1BB72992ABBBD06723FF6DF34661C0D7B75DDB7566D6EFA77A6830309196CF622020AFCE538D41CF44AE73E7858EA076966B625BC10510A31E1FBD2CE25D967AE30719BD54E1AA95A1BFB5FA85327C44085507E361222D5300AC4C39F6F05823DDAC7CEA0D1E6F73EB7C584DF42EE7375C9A1A4BD15D988A95203A51ACB7F8CCE85123CEB770A89C617530704E1FA5F8A0960D69DDB1A9820195179E2C672AE0A5564349BAE503EEB9A79AE54FC6F537D323B90F7395816CF10D606C4357529927E867850650E729B88BC732873121EB9FF977C8E9905FDEAEE8A12DCAE20459CB72F33883641563CDBBF76E1D854888889D4386A7110FC70F956C3358BC005D717E8DC23D3706E00D14AE516A0BF16AE0A8BF7513DCA64207B31A9357B3F7866C876FEF13AAD75FC632D7C2448D0A52820384B62C5B39E528344EA4757E2CF725A00735E0876334F9483BC1BCBE16AFC09F82B47920382E33617CD8BDF01BFB44DD6F9C623EFE39B2FC73246A50E85294D6D8918EA67E430199A6671E677DFBCBEE6E13BA1FF0DD7FBA70608D3D4C658FF507EFA3A7306EC0E2EFB7AF19976210B9A90A1AE2456222D5C6A285E32D50D69FE5B067E71F0D1C4232D8529AFABCE11E62D735C988A1D7206FD6AA3341E589249F19B9D223B85CC05974076E82C2A962013DEBB1D8105429260AE11B9BA37048B594DA627095179D3EFE09EDA689308C37659B47F59B5CB193BF6F268F00F0D5F57BC5F346C7B11D3889CBE71E4E944C9F2934CF5DD3F1B83D95C9663BD4E5E5E4D56613015927B4178318B57F3FEC33AADEC51FA12D2AFFC006BDED5923B5DED44437A87B7BFDA15BFAA293AD2D2E3A434A4F60D4602B096F4CF9F42F86786C81FFB2D48C4715AF01633DAB4F7F2E7B5530C4A4D433A06B30036375280B5BD42170DB572EA7AA6853A8AA79DEE1403767EAB787025005B6C60EA99F6A8E3685DDF4DFFD8712A857D7FA708109B7569396806B6EF3337B556843E868E497DB26C4B6D49E92149A7083643FC6B3970006C63ED513311A0DF329B1BC32DDB4AE25D59A231D7004656ED593CD15541F43D99B8CF680CB268EAD75AB695D09284354D4323DEF54A0F76498B265C3F01E74280CB270CB527861C419BB3B65BE39761DC3265755431ADEBA8785F7A445B7F9E4E8DDEFB609AEA826BDE140F8FE43599416245DFAFEFF663F0B34D2F736FBEA908B08DCC80C867BECAF525A484CAA7B026B6FBDB50E326393E61D16B57D60DB6C4937E81468FC0705BEA3F23D30508B9D6FCC38E4310C483ABDDE0FBCAC06999FEFD5727F130BAF35DDF03FEF03516AC66D07FA473ABF567FB0D05E63EE2B627BCBBFF208FED67FF4D66E56D0094AD164D477D805539AF223809C86983E2BCFBFF703F753910FEEAE74BB3CB32E29DE9DB0246C02382D54EA3719ADEA4705D92A2A7F3707EDB686E3C7B5423F3DFDC117B6DF05A33AB6C8946F9EF93215F643C313A62CD8D5B8A1C566F65BC2782627008DE5BC6C08F62D68344AF01B46F3F8DE9CC76AB24F0B5B66D7E0BDDEA9D6150C6A6C7438EAEF020DFD5E897C7FF115E4B7D9434B9A09EB37AC6A59CAD3D369E45C2CDD8750EB773BB0D3C394EF40D676DCB8078B4EF56B8A9808169FCFB0439EBD3BFFF1A04C21642587C23CC8BC687F3A8566B79B3D2DE76C32291CD96F006D99B1F82870C53E66BB6569090D45FD0FAB021FCEF17FCBC1E2121C1FE2AAC073CB8376C2B5E214CDAF09281F5B51980E081FA3D061DC4FFAF855DD2FC45CFBB3C5F968146BAA42BE3AB407AC8E7F6C87DAED80196B89FCB84C0EECDD31B2FDB445C8A3ADFD25F1C9598E96498D05F10BE0611EEC64F3F375A00737E67F05F461798FF5C7768356DD8CE69C33EA585085AC2B47E0AF7085227CC1DE40DBFFD1C72578837B963B0DF876E77C05382D1ACCBBA141B2F06444C765E0A22F01B5D07CF7F49E6A52B8C6BA7FED97F628676CADC5100C08E02FC95F8964DDBECF8C56103980C24F16F641344D4FF4152D4EA08B41E0AFE61CA08A6F0D246F01C25B56F3BFDA2756CC3D61B25F838CC634993C60526F33A93958654D86A7E9AAF5085839A41E27E75794375EEBBC3CF86940DACCA04DC7F03807B79A86BDD17AE9AB0FAD914B02EB5D231D36290536B69C027B1E6A55E944D2603B009D22EFF2F5B8D6DA0773420A36FDBF3FEACBBAD37A6E4611AFF41C932B82809F03EC814E2075D7E92ED2E01AB8ED1A1D1692A3C3DA21E48CACBEE26646E7FCB38A5A893AECD0ADE268BBE44805A572B994D70560DD4204D7E688B2CDAA0783D32CD58FCF1BAB3B6FCF1BFB53800654D85E75EC9ACF8731ABE042542408F1EEC1C1A071E4FD1FCA594515D93F82D00AA14DA7F3CEF135EE4609A47E9BBB735C70145B35539D6C9F0B46284181FFC0888825D23B58F545C4980A4FF69B1182AFD83220556F9FBFABD508DF63CBA34AC0CA8FD216A54CF47375CCD7954E8E4812CA7DAE1E2A0B6103BE5972CDD4E3A965B00AC6AF2B67A9C18D9410537AF1397DF5A901D92D5F8266B3224D3E388326B7F7C01552A9E5FB6DC9BCA1E48308A3B1AC595DAD3EF22951D09A8633725A34261D12D40C7D0D1AD1ADF43E0DE42705DC4721D3884B7107C9C28F7E762D140455D4D530F60E72AC7C5A88467F57F11030B7CF0F66A40D13CD349FAB6F3562CD844EAC65712988527F5609883BBB186FA9B18F3A930067814D46EE06B6ADFAFEBE382DFDD2707444CE7696FFEB3F97B223117DFABE7EF907468A270E1B2A890006B5487DC1CBF007C6BCB129D00C92FE0FB98C5151BB76CAAF92622A4669CDF440F2A4F8B7B5C06189ED815F98DBF087F199C2AF7C4AA9D48996B16C462FA9C2CCCFD004B3BCFE8B2DB46DE42E98537A43E920EA42EB037691B6830A22A7107280878EB266EEDF52805008537C7F8205628F3ADC0522C130E081CA95080C0888FE6E011B320095A89C6ABEEA1FCC368FE75692B377EA6C0998AC8753C69A6C7CC84FDBB82010C82E05660300B8042F6148D33B754EFD18988CD6C9C8B990A3CC50A2544BA449A1401F989A578A20240B8E6741B62F56B768A5D4829A95DE9C6B4E3FF386B386D67B2FFDDC8DBAFC6C0F6BD520DFEC178B6E560BDC527576C652A7DD99DF1700116CD9396DC1379D38D4F1B5117CA436B7FD0DD3B89658298CBCB2BA9FA0A97BDD99FF401FA60A8D99B8371ABC52B7B93BF7CCA9C917F00FA313CAC7C8E71C98001E16FCC1EA3BD7F7C79E5ABBDA0E028EC4B14F2B00D8ED1FFD2484BA44D02373E36D441092761ADAD5D298B8EC75E8581F4EE2DC2B5AAA09B641AD8E07B7E1EBCEF62E379B63FDB0BC5866EC91DD3DF17B92F6DF6E769B5B064346D049EBC58038920B295EB5C77E9DBFA252CF9813472454977D51DC42C43CCDFE79EBFB7E62ACA13D30D72F2C83F6DD4489961E2245B0E1EDB0AD5773ABE78DF5A71AFF668DE0776498731DBE216551926D2D1A40EE92079BB4F60BCE0F63E1E5E625BB0A5D9930FBF8BBBFE77D664048F79FD9772DFEABE2A791FA81FFDF5A44F84CFC7C01FF44874E468DDDC8F8CAC1B32533720A481DFEEEAA5D00E3C258B1BD10B043E9E87D5B76A3D2EF57FD2FA2A0CB49CEC1179BEA1996F61379FB0CAE9CA816BF233FCDFFB68566A53EC71B8D07A038626A5B1378E6DD305DAC5B0CB726E9729CC7B9124F42AEEB05668E1E95BB3FF05BC66A7684A7451EB28A108421206F11826E1E00BFDA22EB2E6B42C76255F8BF78D03711E7CE2E7273BF84F715C97F24E425D85DF4B3045CC43370A04B481E5FE1E33EF2719D4BD792721F8DE3BA024F05EE6C4D21F2FA1148E7A50CCFDC1E4B193C5C27A7480914C72478C06E45641E14C7190F027DD9BF4541F6F5502BFE60CC4A31FC97114D9912A0ECFC127E09430AD175CB19548E6A8D9FC8C9C4D1F2CFEBF13BC58CA04C7CA6EC3FD4EDF1EC00B41EDB731F0F48D5ABC5C153993B65B25586C2EE14E67048B6DFEFB8782BCABAD258BC72F762E3653B327AFFA64DB403F6BAD675CF42A0CACAF5D0D072052BE2BCF823BDDF10AD9662478F93DAC2FF5ACE53C7EBB2AE5980245D7BB13D08A1DD56F07161C62EBF8BC268DFA0F60F5ADFF5CF3386C1F9017FA8FBEF77B654FD424BC85E26B38EAB9FADE065AAE7A73B7B5C5A5992150BCD569C8DCEC884FCEB8E47A9C43E0F3DFE91BD48277DE73AD4F518C15A7C0F7280F421B93C947C6655513A331B65DE118A5327511043BC421D3CE1E86C18064F3BEFCDC08471D6A0BE419E3AA697AE6D576A7E4321E7B658175E289762556F66B436E876BB05C4387A936DED2D26E56FC2C13AAC88FDCA7AC8273D88772C4EA2EB883273F34230299F3B4170D09DE76C2778F6A02CEB68C8F3D5746F6E72E757BC35996CE68B6F24405B7AD7A220010E162CDE2B821E62A2D11511FB5E7CC5435FC3128C50393353104A57CF390A0CD1BEA0288E58F51C755664DE90A594BD45CEDDADFC1881DA7129C2C75DF33A4125FFC5DC3B64F971E7077C4181E455BB4E76A0033CE5DEFF48204FE17DAFE1A1CFDE1C42BAFC15D3EF465D46CB72AB2EB470A140C7606CD2FFC60A67F09D5637AA602B2A76B25DFABD31D32EEFF031AC904EF927A4571586D8BAD10170A7A7FF9CCECFBE0438E04FE78D4B56F76F10193C53FE5378F765163359256E25C1FD5C72DE45B3B222C88EB00690DECCD428096E6BC279B2E9680402539F826E2D4A08777599D09C947CF2952750B37A26540FDFB24CAED89ADA966E6AF0747AFE54CB6833B5195EF12AA38899EC5A79CBADE17014C50FDB34F53BE891A0B6A754CC48B6BD57F39CBA6ECF17587321841FF21D1102D5D76E0260E8E930ABCD8FE9F6BA196B2E36E194EA07F37ADA1E337DCB8FFF73AE9FB8B84D99A8108BD01E0E428BEFBE7BF20D04550E72D286F97B7BAEDCECF5127063B30F2522C16EC6A7C34E04FF00B199F91C628ADB903B57E4D90663BAAE629BFFF8716BB8A6961680255ACB4CAA5CB2F005B27C49B4287C3F2F766D143859ABE501589DEC14F4DEBFC73FD695E0CAD0F6F9D0B37CE505EE0951F5D88D9373F3EE7A999032567CFC3A77145E91FE37405E95CE95B79FF3A5B0EA86E09D14A25CA9F202EEDDE81156A9D82AFF9C366A142625A266EEE99F5600688D9E0BE76E2F1CE32DDEFC5B9758F5FA7DC2447DEA09A087C187AA090A510CCE223FE5F84F672005043BFC589B04595CBDF66C2DE5E83E618C5798EF674CC08DC7E87D59408724F6036E4932FDEF8AF56E50A0E9CBEABFE7FD0F6390C18F134D7C28D5D870AE6FF8306EBF6E1B8920454406C1B53A285C6B1676D0EAC2C619C79F0728791620551C56477C5FE8D7ABFDBB70BB75B9EB9A7B28BE2D874EC7F0905123EF38E41423E4E45C9910FCBC2116A74E35A0ABE700086FAF30D07EA944E7DE2BC2C90CCB7740620C379CA0C90170997D52290D02D9ECCC557E97CC313DF93A0CB3DE6C4DA474DB98A46F6FFE63DD5F57FAF4FA13D34D76EE5003F0AE880A0E0485693ED979A89E93CDE4EDF29474210B184B9E2C84E43F7F9D636226BA232322D2DFC7D29724127F7177FACBDAD6D39585ECF7DC9E5B6ABBC129D48DAA75A663E61ED34FC73B0C81812DEC0192D4694D2B46A2E4C6A5D5F950431AB0B505533CBF94CDD6D0652131A7C4706D3A6224A9956D8D1C15A3036F2EA37E9F070126C5C1C09B190DD4A477C905B56A08741AD8B5BAD8415C2C95E3D7BBC58658E8945FA8EB7FC7E9B4DAFFC509CD96917A9E58F8E5641C2E14ECF616C943CA6EBEAC9CAFD3D300DF9BFB1E60988D5B3227279F68A7020BF9BE600B14E77D8E008CB770491CD69B2619624F3C2D2BA8B7DF6F5AE4C5EC93487EA565EB5087FCD0F3218531CB3D990880829EC49DA9984B3F2592952081141453EFC43A3A3ACE10D35B441E9BF0322B1C5A7747A196001CD9A12EF686B5A299ED9C3873228BA6812A95599552D83DD7CBB092042766BC46EC56CE9FC977D8E3E0A3CACAE68ED9DDED122410E045D9FCAE7193C0475085B841DEC545ACA3B1984F3BF96FE17DAC3CA54330626E97E7DEAC8FA5480C4921F7ED0E6BA60EF7446E1D31C2D286946EA93CB114B74B360483C5F23F25832849D70C0CC7E1B5994EE8759F3B3697E9011624BDE11D7B3EAD013B65F15936E931E922A0BE431C9BBED3418D42194BC6918E34CF651E541024131764B35DA65A1B643128026CD2DFF01D818BC33D8081A0A788DC4ADC785BDB97362219E0E5F379884BA042CAB929F9D21F1D041F55204F3F8E526FA6E11B4BF4D9BB4EE14B7B0F9CE23BE5A4261EF42BD4F43109ED4A31CCC006CC26D7C35C798E81FF0AEF810F7F4A564983F8C6AD3BA8716866B49FB85891E7EAFD2E382FFE8DF14F6A78104313D09C5F6F5472B1E747D2BBCB7E89B164569EA0AAA2D791D00B6B6EBEBCDECA4B5D1488AD439849E8863B975382E77163BB5D22A7F9EDA81A491997C97B2090AE853E283233CCD9AECFDB6A70C1909EEEE3D35E58B40E4319D8D1285DBE0374B06E835D940FFA452B2FA5CC9213FFBBB8051DEB1A74F3A61DAB8799501A71339481DF09C20C89614B92DF810056F36C19505E12E4FD787A676F4EE31B4AD7502838F4B5DEA7620B29CF3BD01E2C8ABD59E1C057F728DB3642CCFA8F5E36569678389DF900D07FA0A70E521195718967CA7B3A6E09B4A2FBF2856993487CCEAABFF9BE9E1E01F7F4885710F08AF85C0253A3CABCDC58E4D790762D706EFD92B33BD37A7765FBE6D2DA5AC85E837A0FC5C26177E3EE7DDCE4BBB43F8E7B56F3AA8906861CF5F186393803737300BF666365898270B788F7F4DBD1235C0A224445C7BB43AE38CDBA8B43AF826756D1D7DF44E1EBF4FB303607D47BFBD2615A8923FFEB155E5FAC89BF285E21B71A2E6C96CF03C71C4E7FC3A5BE76E8FB5053F6F332630CF9933921CEE862AF580A9FB5BEA501A6E81087D79505DE323C26402C0FB386D54BB979020848ACC1A11E95CCD535DC1532911D95DCCAFE5D743B22C5FD3DC9AA6A8F523F6BFE87D9EA77B40F2A9CCE28DE386F958DBC3D3AF5139A2C9280ABB15CFE70B30124AD53E7DFB04DDFB809CB09C13B5E5936EE8903AB26EFA7DADE426789599C45040FD4D100E03E8B29895B3DA117406C6F1246E78EA820B635C0F84195B3AC383475C9ED0932B0033D0CC57C7198C2F5003E26AB102DB0B849788062764C6853FA2E69C3EC8376B7043C706812F3F8DB86B443C1AE3FE3F86176743ABFFB688C9E29393A3D96266C04ADE781433E0DDDFFEF75BE7E428209201A4DEB8C8FBA37D0D874DF4AEFE2F8542991C7E80FA8D5BDBDC37BE6AB10D173F72BC920DFB1912E6B3539130B65EF4ECFD528421F0F3CB74060A6A408CDD2CAACFF0DD76708FFD6F0CD59BF829E6415579DE23AD2A16DFE430E38EB55DD30E63196D4A4F294E7ECB37105D746957EE47B278899BF5F8067AC26599BEFCACF82C0664278DD47D59635CB55959E9AAAAFE763B1C60ED57F0D3D991EB9AAFD41B8F1CEAA01D8BBB64AEBBC11E8E53A66A85A3436CD16F3E3E01EAF238D7B5CAEDEEEF5789A5FF5D319929315C52776F935B279FF5C06C6A99018DC6DC3FB9DF467BB20352971133AE7840C3A0620C9D2E199BF4F7086506F6ECDF73C617A67E0DF0ABECAE021C2797B724FF60247B467BD89959FCE9D32901C5496A62DEFAAC3371FCDCBA9E91E0572098CF4F7EE2B9FE6980FB9F02AD548CEFEE56ABA20A3267CE36BEF6CB932F17A054228E95C7969848352B01A0AEDD830F4A91A5FF6EA6FC63932B0BEE6C14EAB4BA457FE3B39AFEAF8E4B552A6386BCD28A6AC1A9E43C646B5298B0576A53E7AE384884A399EB2C80A0B4B386FE0D494B112AA169592F3797FAE5F2DD106C4EB42446466AC76749B3B572725AF0CBA70C8FF1230DA6BA619D5B9B56E833C4CE96209D5182E4F54DC93F59CECA9A05F43143FEEC181FEF4896D67C9DB1C7E0958A97DB5587E7B1DEF1E7FD82F4AE4BB2A2CDCD087EDD6650C51C3FEF63087A45D361499F542EBEC7A0513AA71B224161700D47144480595EDAE5C6D2227FEE3A8955B81D97EA95A2F9477B05CCE8E933C3F0FBD72F8BE320B7F248DAE90F4F856FCFBB60DDF1E1724BB5957472E411CC340C93A04F959583CF851E83A808604CDFDCE1E2E06C5C8B3853FBDF0BA2A606F32351920493DB23F808819A89A23B9E410DCD07421890F35DF556CB2DBBD371638F962BEED0D9DF4ABA303F063A4A379241D7EAE90E0698FC0B87C20C1E433FDD4CA3AA9AD632DDD4331C8761B22CD88CBF8D7D759ACA334C706BA0A5CD86F81A43627CC4EBC2AFD84E7429CE1BF33D118C69D806F25AAB463E6CA02FD3F44A934C9E8900B5004395FDCF9F0BAF67278936FACAADE519B09A4E5430DC78097FF64B9A9DBB3D1EB7A46306F839C2EE9ECD10314A85AC2A35247A1B2E282535DA73C0F9DBB07DC23EB7B2EABC01C80AEE7E19A805F85597A8E62FCEC36AFEAAFDFA709C0A7466B26C9B9FD2B8C6AD9A9BC4E117FC7193EBC3747B8EFEA60BA0438E28A1042EB7A821C6D542B075C84077855CA70960AF83D5172023B9597779DEACD55782920440DD1729C3B48FDE658D50482A947891C41F1D8F8CFE6AA35923CECCD684F2A4462A14919B4C54DEAE37C4D5C0F48F09F9BD46002A1F60A5E58230B98927AD5FD323794F25EDC097FF8C926CE5BB6B61B2C32F7A9EA861D5847CD2C677D111F05E86C85E2B6142BD1B1E5E5C912A3B4F09D63EF4CE9874EE757AA084FB9701FC85178A623A32EF2C65905216A6E7ECF0AA4A7AA8E53A8CC55E24ED4D0C7C0C748D9B04EF339D5604FAECEA00B8893F314AB53AF431F00BF28C61422F68B213765DE60B1B003CE17128B1384CD3FF58F23D13CAE93E0F111CBAA00764A6817727BD1B6D9DA392A89A67B3D736908EF06A8535281CCDB0CDFD191647DE09109F49923CB058FFACF644A99EFD9A5655BA116693AAFCF5373479A384675314BCE6C8C0F9F20AD1DFE92DE1AF83A2FA524541D04FEC577C1BAAEFD6CAA6395A0B244244C4974C9312208198AA484E60B7FE27CA4442DA2A8A10756ADEC637DAE00B013AB6D2A39372B00325F950D239F1C940586C573A0643D9F4CA0B7B9FD9225DD8FF82804E1ABF58955A6BFE8AB39205943239522B0715E071EFB39959D830A247454C97ACC8A91FDF7FC18C170AE64AF8CD1321117FFD95E16DC929FCC8B3ED13080CE120C75706C97EBBFEB95AEF608F93A9420005E6D62C17221E3C4678A55574A263C726426B0D258AEAD68C152A3A6F0F17599000E1843B132BA73AAD60FAC09311E5FBFE5E6E4A9E5E0568AB364E1D39534E6DE40EA8A5E36963B05B25C6C1F8AF6E1A2A325E8F11A4B1593547374A559506FED4ED8E86541CDD1622BC6C0DEB1C354D2CA5693D07E4A346B4D069C2B64E4B31C0B34419446CEB62BB4216EE66CA0DF350B58C559B010C5A9E085AD4BA8851ECB93502EEF854D57AEF690F62E31BDBFD0A69DDE176FE1EBF1A92BB4B9B7DBF182A63979AAA97D53402D878837DFB3433AA9E30EA66B95DF48B911807731B83FF1B27D894398835F418DD01D538586849B027FB646D429F5246BF608D03DA639C11F775739B3195C75AA4AECC1D99FC5BEC64541F9F41C58398315244F0B98DF53286126096AA91EA480BFF73A637A0CAEC454AF1B971DC0AE0417AF7015A2ACBDD4B04864D8BC860A10D44FF962091916A4BF2F07B5F840D1B9367BA949C6CE32E067FD7481D9C25B59991B6611325789E6D991BB7FEEF5AB21E88725A8DB753C98654C0C23A4193E01B75AFA130746143B3F24599CF14AAB18B3C70916F1772263F0CEFD5C32D92C01AFDC3A2CC374C5B816C3FF95CC7584F5EAE93D5C35D74EB33C9C09297D873E89B03C0EAF527331E078D69E743FE21A0E5EEE5F6E3A5FB276AF61E8DDCB4A6914F986C1F496E172430FE334764380D5A8D557C70C43E96580C0E464614BFB65FC65635A3BCFF7010B65701B802C14DB9A7CEBF02945886B9F5614B2317407E8A6DDD05E5E411DCE1EF2749A3D1552E19F8E7D7A7A33C6F8F2ECBE2715664C31894E7FF6887CE493BC0C5920A656B7189110082A4DFAA181309817577CA1EFC3565495C2A8E46CFA33222554F09F8703C7359A9E29E1D33667C3CE170C4C7B0A6F552A47C1885AA9354FCA238C9FB6ED0C290795EBD9A09BAE800BECEE2A22E7E913588CC629E7DB5568AC2E0F04436618DA32BB8ADA96CDBDFB793F4A0BE89AFB0A1B27B13AEABCC2EC5AD6AEEDA720B6DCE951C504E41013F07B2BF9EC85AF88DC23F286E1886B9E937EF314C2FB1A0FAF8A1479106D50B005B1467FB7499C574526086EC892657E0A43E3462E0C2F19C544FC8BA779CB35B10046807E2000832EBCECE0B3E2A5F9CDF5ACAF5CBA828DE05B7D218FFA176DB99415C51FE09E7F69F6725BC1C03E4029FAF192943C303D9F4FD9B13595D8A7D3484705D78644E8DBF7DF25A5E9A2E13B97F05EA8097AF80F1E0918FE6288D3E0DB0629E711B971BED0ED3EA903811EAF2B5C379470168907AD1AE1485DF1C5F70969D5F7BC84AEF390DF89EFDCC14F4522E5890FEE689D9A0FC29A3C20BCA9CB9106B28C93217A1BD6D537AC2F3FBAE89FFBDFEA8D431DE9D0E56B7151140A76B4188119C155FEE96D236FB9D58F54B63643D542EFD4FE9A1AB627DCEE198F117FA655F57F1FDC79DF422728EC5491F5B89DC3224FCAE81519147FE8EFF934CED936686C25F0D30DD122E0DB46D684BBCD3BB0F43FDE36830E31A1D307B1D7B607A08508DA9B28BF469E2670EFD3B052BD031EB44657205BE4787981FD1C123247BF84428BE60E878F8CDD66BF17C4C06479F429A1C007A2AD1D248DA1E2C32F4CC91D4B07CCC4AFD9BE7625C052A27FCCEAD5FCED3DD040B013EFAE2EA9E75AE06735C0B8FFFA1D2CA720B4F325E4B1CFC5DA9B8173082EF42595AD89679A2839B49973A77C196EA4838F36884D567809A4E75907EF866202D7645783FB1F9F109626AB66F3368EE8F780EEFA666BE1836434C675F9B09C507AF5A7FAFDAD37126223F88535495B63EE3B0C0C7DD02F7C9BFDAE66966583AA76D00419A6CF3E43DA3E212B5360BF1D817472A8BBD2E3C651B552D63A9B96EEDA23849F6DFB39F3959C414B794B17778F930B924B7F67DDBB90BD12C6986C59DF4609B4121232B0F66A7554EEB9A35F1484317139B62133B676B4BFC9099A6B5A99308F60757A0FE9F11AD7F2112A39806D79A4D62E89C3D0CCEA79960FD77B036E8F40152339E66DBE55286EC1A3F1405A069268167EB6245C9AFDC6F7DE47B17376B11495019C7084ACA0940EA194E4C5741190D0D625113DF178B1FB8F541A3D88B9158626F8F2ADF69BED0D8482D56721189AD05E5D0703B80BE86E5F96A11BE4D3E7E140B1BF2B5C04E5A943CA3727C9C3CE356817307672ADC1E998CC75FA70403B94FF93D37C4AEEDF19B302B0ADAE22478D4EE838971F951F515648C1050C180F5971E3054D3AFA3A0456E6AC8376721F4970CA7481F500EB755E2E90C76AD8DBB02BC8A12C6AD776143781B120C5F9135E34B6D53B79BB1B736FF8E8C53E55ECB079A01270635051510128F22CFA32C7510C861B3BC8EA2FFCD7EBD86996108BC4B20EEE719283AD802D8790E29E98811F75912A54BDA116D0F588BB83253D518815D165DE42E82BD1C384483A3F4D27B30CBF99D1B04D8DC88164B063AF9F05E33314CABB16C40CA2E663ED24797589054B5420519A961389F9DCFC3F83D44A9944CCEA0B06EECFBB404A2AC3A15907F3980614AF8FB450A6B0D8DDA2A02C407EB866B059ECAA8E342AD9B3EC7B490E6A77704A70164A9C1B5A6DAA8505A2DA2E8F7C08FC1C5454F04A2EF89F68114F847F5F46F016269D6A3E9B4A7342982FAD9538C02C08FEC98FDE9920CF6694A968681F3641CC0F6606AAAF80F19371AFD693CB79E761AC95D69851C5F140ADB87D78B114FDEA1317B730492D51EA1597C45CDB782FFD938F659289E3B20AE89614EC0F07693950EF317F6165D5791353D5526204D7C64B9A390C1229DEC3FC8A51CE4D07E7394D5AE9A6A3243915539AB8F3E2F1FA5F18EF7F9B2F7412624D5F42F051420BC1A66777AADFC0B6E15BF5520613938EF549D92ACD85364192CB5ACF22B7DD047246A4CB69150603DAEBC8295A5338427ACF326219AE286CD639CA1C625C27F4A1FDB7E1198C10704DD557AB39E8A6AE273E09B3D111A483E688A78D79153618A0CD8362EA744CE3A207FB20B38F708C47B565D5045CE7165CD32D20603FFFC14ED9789D53C6F8D31E5957B4CA0B8FB537F025F58AB80A9720C5604DC02F74E02933D9158F54B72FB42834B28FD97AA291469467B21CF8ACC3E5178015FF30839D3AB972BCEE757CDD9EF749AE76DF88D7790D23CF78778E80CCD361D7DE0D2098B63523D1CC109D23B95820B30340601850775ADE56B4F268B0EC38D646DE85E62FCDB6E8244BECBF05FD2FE4CAC9E0AE563DC4939EEC6BB22E2FCB68C8FAF9A9A83B490DB90C61906AD72A7A7D3EA025701BBD5203AD103A8B9C247C36BF227C0225455CE6D79AB21C362B0F16C75747B8D9FE35EA69D0776FE624FF1CE3B088302CE59630BB93EC1D63C1D8DFF4B7EB9AB474D69644707FDA158EA470B502DAE62027CAAFC27E19540C8473BDC8C5388949B8F541DE5D36057322D483AB0B20EC5A4DAA6D05FBA5385D76EEAF0533C9AA7FC7053CEFB93EA61EBB4D52472B60543129C520E5530C0F31CD01A98DF7D0C6B5C4A15EC081C06FDE745C9EB42BD0C5F582C4F8C56469D898A5DCEC59D17B616FE636AA51F6B4A328CDBD1A1EE2C746C0F9D359BE17DDF13EE265C943717B2C22A806AB8FDF94AD6FB107CEC02CBD633F3BAF769AA8CB0CE826D5B02C7B072E2A47C65D39F3BDE8357C5840C9099C02F9670DB613997F728ED960DC4E4E992C0887C51F88B05A5DA0A805EC19C8E2723FC593E7D80A3B81619A5F7C2350CA5D974DD87E4EA753632842CF5A07F49C0D1960702BE254DED4E0452FE7606D1BFCB23B8AD579C357F8CDEB70758E4177F649B031A37396FDBD2E963C288449EB4732F220E01B7C9F4C918CD69634BF9CFF18EE9C3F16A4974F1622BCA68621B3B41380CB81BE0435DA0FBC7A4C71F7EF6B5D749B4A9349754DD29D2A7485B22F3360EB90FC0D375B5D4D5DB20DC6F831C14228A857BD92FF0FC9BA433768053D1A89CA4BECA01367E4DF0174F74D78E14872BF0EFEDF8473A080B917CF5BE3A49392656D88D7F5FB3CBC203266BC20962C2281D8A77DF3BDC44EA3AAC85479B35EDF5D91466F8A57158ACAE6FF430D10DE0C72A65B645A7A982D0AE7D0CBE6797259DA8BD8BDF4286F8FA4DE3EC4B2AF79A0528BB933D416CA9F1975F0A61779D5BD8A10EB040C1A3F95444E5A6E91B814924422F095E5B8A43220B03ABC79EB22AEFE7C66322942D2B0A236C2FD9BBBD1B8A4E73F058006B3F910751C3D393FFC0724D08894D2EDECEB7DF177432FA48790BD7C1C38DEB75497F1F6262EEC3AACDA0716E9AF68A1BE0AA3E15164C8D69E92DAB160C896274915F9F9749CC021AB09BAF9DE83F65DB58647A9B27F76BDECD9ADD0850D611AE3208B8A9FA8CAECC4249CAAB412B0575A7C3F90E21FC879B1BDC24A6619FEE1FB91143121A74500E54DB06C452FDF4D887A6555A42F80FDB296AC8750DCC9A0C0136506FF08487D850F781C86F112E393B46B0B17DE9E715F4E386B9E3EE4D74360ADEA4DD4BDF48281215951F9A7258929DB9FA21C015E6254C2AFEAE239E5F86995BBE4263846035D97476B6FADA7A9A50B86C3EC2AFE529BDB9625913EA4DEB85DF7AA96E203BE01DF873A8D309FFEFFE469F567AD21F315D2BFB5C2EAD0A7850B2E0F1C8CFD8FDAF4407B84ED3C1D716A94B014FBFDFB524CD0EAE5EAA60260A118F5B63115EEEA1B0B0F83F51E5FCF19EF6495462FBC3EF737C018ADD614CCDCDAFB37522D383F6DBFB1A64A8B51F872A6024A9708F689AF92B5E2A397E2F07E013F7912C652225A19FAD265F61C5898AE44D8AF1D7826078D9A80AC3CDB56B4C01F98E67FBAB9FDF4151BE50061447347BC4B2463F9C3FC715B2610F62941DF11D7473BF5C3B7A51A8619B2028E252E30561F662DE91B95A3B8BFC8F4401823A000D5B2FABEF37F1780ABC18BCDA0733DB46CC0F74E4521C5266F13E6057E096A23C815BBA75287EDD5FAF5144F05CB4D68DB1896A38194750605045C1ECBC17970BF54F5007DA4F008FFE9FEC1D09E30418C1E837DDBDAD90C0D28511306D988C7F5E730CA9072BF2012786D6F30A211511FD5EDB0D6AFEF9F1FDA74479CA907C8B34F1F1ED8C68887FCC9442B4DC1F273100E96EBC3D86E664FD2445E8EF6171F88D3E0BE82C8D8DC4B0C28C6035531A13B10E24E549C942FD892870F2FC3268884022433CF21082ED87ADA34243BD6F6B1A61AC387D9EA687C7885E04F85D0D96EFB7F17E19DE0AE61B4B40CA8DE62D3ADB43EB51FD06AD79B265616D8075DA32BB054E28EB78779F08C6DB4C5037EF1D96FFC46655B545E28528C3242FC25A4942A7A741CCC0A77DFC7103B98B4F94D8B1E067ED0DF6D5746E4A90FA6B64EE8CBB954364E36DB664904719BA460210B75DCA00705B720D2EE8869D2259102FB3203387F26A68878EBB7E76621C6BB1F2646AE34B04B8D54323C14FA26C48BBA2C753B98538D7BD44BF003AE01DC3B05FB75FC3FDD4556D0F8F2C0758EEE2FE9ED88A38EF74EFCD5872CA9F7ADDB5A0CAC3C7832F8CFDFAEBBA524353B1410DDAB1066F8E5BFD3EBD2626EA54E346B74F2523DA2FB0A6DF27DB30D0B670D7D7A9AA55CF00CBE6635343150B4E1A5B10EBCE0CB1964E86232BF6752D4A86CAED010CCAA5E37925FDA46713F8077718EE260C422EE37082056FDD58E33B4A71F1830E62838CC1D97D69CCA188004F3BA9BFB2F460CFFDC43BDAA47FA5B2F304F4AEC3276D5FD4709378357B6291A690951F06FC7C13F8B119E8488A64970BD1353CC55B9D4A57E091999AC383DABF3FAF57202C01370A8EC7DC03F013CAFACB52F5EFB865B976B6175D454708DB0EF341544473BB9E79DC7E3A6CF0CD09B9CEB68AB232EFAE8D8C18EBAED4EA1AEFEEFF2E294A7C798623615FFB610708D51786C09239D623675DDB422F982B8EF03B602016E461C807DCABE811F355851B373212BC6BC42DFBEC57A6DF9F4AF0F6550D8F9C41E8C3FE03AE2ADD785B9250DA10FD8880DC09D922F26FFD12A3F089381C1A900DC1E21395F6524742C237DD59FE3E2190980DE6EC61087EC9EA948163F8BFFEEE53A30F0A56B8FF9FA85F0E7ECB96A04965EDD77B257BFD03B457B083DCD5998591401DECF1A839F4224BA85EBEFC749764F9435F3ADB4970EA359273E55B891EF54A4CC9BE5848B5F9F0CFF578928DF1CA7E99D839B742BCF7AED2304938E6CA3BD2CB32CEC8DD798D31E4753E3050E5169E86D0E32593AA01CC3AFDF38B1B012AAF987EDA0F22271EDA0891BD97C38E0BE3342AF7437B2279ACA735FF2D04CBACAF7B7B4D3652D0458BACF0D53064F94699DCD5B97C69E277C02DDB239FD99C4A93F0D11A55693232B45DB44ED32634F3570E3C1B83F04FC5274D2F2D8EF981120722FDBB243787E2AB83C41FB1AA057A66D4D50A94C80B0637BE882D42846071FA390E0057659B4865298C173F831BD4B792148DAB791319BC9FB2C23FC305B9C8B842035D2DC8A7BCC7C207F7CC8B097FFE55D723BDD459FC3DA074469A17762BD5CFF9075B5D6BBFE10B14305B96D467F8EC36572764620781D31142F67E71F16976595EDCD588A578720EC3ABE30F8C70CA183ECAF4832B16F1C2E7A8670D85CD367667ACCF6AC89595CC66E0BFDF144A944A80D3E867C0498B20C68B1BA58D410E7E474F00772938931DB41E621A0714A7378A2786319926B6B1030FBE8ABCE017BEE5382D877B0025F30844A8BF99AB909AB47CC7F629D224961A26E012F8BBC5E9F06777EFB7283BA7728F282BF69E1015663F771E2B97EF9B414B2017EDCD4C9419FAA536C5FB3D62F18C3F116E6379B41B238F63374C2EF741F09733B87328CDCCB2112C96F50D6F1E3CAB6A475B2177F78ED05905C0DC36A395034C8A7B6E4E95C4A634440C3CDA355F874CA0A6BFF508211A19B62B8DF7AFD5AC4F68E959D394839F531FDE22C62BE4FA9DDF542A4716D471F5E3E80FF7A1C68E3671BADB5CEA7D1F802CD0F39633CA972790C0B9321CD5B12C4DFF391C9B55FCEB567073BC6701625ECB41B81592E9DF275E5C5DFA0CAF4538EB8B83CACC2072033657879B98BB871D164D0AFE9BCE0430A64699E259C6DBA3251EB084FEBDD07C48BF0DE7BEE5020BC20D6746371C7268374D6E0FFC560DC77693E7445288D6F99C787B03BC7035999B5B01D65C6522953EC357F669C07CF9A67CA1833DD48BDB6AC272F0641BF87F2BE59B10A029C09D7A205BF06BEB301E453A7936FAAF2219582BC33ADF9B2A039AD7CB5DCD1868D55D369266DB94144BE51F76670780C39F4E3572E9C85FEFD483992AA259980E17E1A568C5C78C5AB8167D776AA898AD2EC8EDA9881A256E95AF26E392D745AC0582B4432AED9CCFEBB603126B5B252C563EE87E9101BFAC2FBE08238AE4A53C4AFE00D749E18C9DB98DCB5C95E43F26A14FF0D349741DF0D9BE31D1FE437CE0F3EB562EA57568BC17F9B3E857CED6DDA749D3B38432D62A8B6CD699FE6155580680BD24F8AD6A39F5BAB82AA98CC93AE601A036C58DF570FF3A6B7E29FADEF6F1ECF0B8F53AE0EB7F25BC800ADD8E2DB7A9E6D61C1B18DFAB94D009A97B98E88E57A91EFED2D1BA0518AC88353DA532E507B762B761C5243A93B6B22B6A66D0F7488D7EC775CEAD366B128DE29999E20AFE838950765EB1BF58B635B56A0CC965AFD5913BD1CB07F9388ABF346385CF357D01956A091A2174D10186C568253FEEFF215A51C4B396182E7F86A93A9609D8A263CF5CB99192178F17026A5FA922FDBF09E3E7811C223F2ACA966BDDE666DE9FB99380BA4D34E3DE7B40D8E77E48D1FD3529E989E9389132B562286A34AF5A25FACF684E4D0AAC23AEFA1524FD71E624F091566D1E5419553A7927F0D8EFA150FE31C84B98FD4800AD7B7478F3D50FEA8D03D41EB3280920CADDC6217AC141F60931AFE71CD6BBA5651AA4D14F2D45D4AF0D9B474FFC2C60FFA070D515604789C08D1437BF0F5CCA76A2F3A6E19A4D57C30AA84C8DDE0293F887E3C938FA14D2E400D042A8140C103D6D2A506E63B54EF0F8EB256606022387A3003403CE52D35DFF2F9A3BEAF129C9FF6203D50F3829812EDE8A36A1290A13ECFA69EFC29EE0E09E057C82C68E78F00C195403EE699319413466F13D62B7A938FF546BB645876192DFD34E23BDD9F57414B4D8739376263CF45BECEB48E830929C9552F1C0278EA1DB1A01F8EC7A5CF92D0BF22E7936E45EEBEA6D7927D6ACBDB4AFBF7775A706E1533761550059059798175E3D855A167EC4E5AB9529741ADD4E7CC2F9A220FB94673CCE5A98CDFF5F482C29589504C9AB433E737E11F899E7C37C6818AD1EC45AE9659DDC5D1542B45470E1DC38BA49932B3E5763DF9030848F1B3B38FF9FA708C2B6782AA7DC30CB9617AEDA4F50F0204FA017C07F5F175A67E34E76395E3DA096A68D614247D22C7CB655B2C2FDBE48803820D0B9085FC4BAADA1613D8EB8ED17C4EB86A0ABD1ABDA80176442FD1B1F2AFDC1AB8C44263F129C6B38CDCDA38B3EC9B6AA237B010B93956DA6F2AEAA10787D3049100A03F68645BE19B139E6E2BA7F46629A0D94FD3EA52F1DACB6B8300773A78758FF200212AFB81948DF6682AD4C183A3486F766ACB51308D8AFA46CA75747E30BB30EC5F3186E99BA13FC1A303887F9C638380BCE54E582B123219CA5DC853DB5656F3853202730FDE67200B16055608390A51B9A15A9EBCF548D2636C3C9CC333FA84357E54E28A428A359E82CF463E0BF89688FD837EB489DAC7BA544A8EEFC3D44FD26018D995C1513497C2A6E92D300381C31308DC88E30ECDF4772B59F7B828FE579F43895C01EB542EB5C19EDEF38342EA6DF473F8712DBAC0D08EF6D5F8EE527E2296B0AD5DD852E7D92F0060D4AAE85244F3F005096943783B7E65D4A052FA09385AF7BCD9238FDAFC5F5DDD75D1298F8CECB1734F09DED8528E14EAF3BDEA1C548445EF4D69D58DB990EA2454DB5E2E25A5071BD49C4C04069BADA23093D4096848B75B18C0FD6501A0529EBF3D2B57B18EFCFAD136503CC7DF8543AC3782D6683A9F8A18FFFA96D5F496DF8FA97A011374A2F185DD7E93C4E89DD845805116D679B3D6C6213F0A7680B6270107AFC5EEA64314FD2E9E1EE0B2BC80A3B3E9EFF05A4E03428B49C4A106E52F043850AF446470BB3B975B6113173728F921AE1DF5336E9DA444F75574245B46B0152BD6346E7F5EFFE7828BFF3A47EC3DC7F123D6860309A39D1AD56801950BC775AD5DCA43A6EF0A5C4559A61097F8F454BA1BE5C2CE08EAC461BDEEF2B5F4C3DC990A4D5E7A30B035A9C59962BCBFF222B03BDAB6AF0206268B3A086C123733484B852317206D837B5D445C8A7473B34CA6E535E5BC58698CD907532FD1615EF4D26A591BC34CD1995C5B4C3704D011915650689ADAC66C13A57653C258B3BFD733CFA0E013D1554330BF7301C0B24E0007216C9233478854956BBA08D0AFF7B9793A25D7071AD9990941F2059777B0DFB3A0BF451CB92D10CE50CC7DC000B1151DC67FA9BD60C2E27DED2BF959B73C41CF0E361CEE575D1D2371C45A8C148325B536BF535A1C1979A66E1A19985F23E252402623FA3030561C28A0AB4FAE436306C8CEC13F04183E9CF9B47FF9D64AFAC7B55DB7BD2DFCEB016FD4572495E79431D4B227BCB7F5D274BE4A29A8083A96C2F3335601A4CCBDBE40401F26BA4F8BFDDC075DE09D4B5A908271FFFBF34B0EF533588561C537C57E7A54D9457911BCECB08FC8CBFFA048C9CDE6BEF3AE7B7383BACDB5E06A7B457C352C9A137EC23D054585200BABFB83AE8926ABA150CE8B8663924D6023557C963F904CFAD0D306C9F942BF71569DC0FAEF3E2F739FA1F32BC451C400B27658301464133FC516323A380239384F118EDDA123C0920B8EC0F8B0AC1E90F3BB08408E4606AE5C455D8A57EB976FD3ED850C191738C869B38A35E78C594D87E72E75820AA714D72C267FAD73AA6234D71E582A7254BFE137EE0FDE504B05D38C9D3BF1C36F3C29E781DFDD38FEAC3F1E5F031D6955C7B4448ACCB1131CA5EB99FA707047E9EF41F7AD237B2F971A02993C8FDF29B4DCA58FEA6BC688918D87CEDC98DFE06A8CC4327028E03F44BF1AE64DC53C3DA55CE0A5491F33B7184276A74DA081990B70E6E0BE7D9875F83029228001BEE6BBC5B6A6ACDB59CF668860D0A66A91DCA7D5F4A0C0AC43C2CE07387B6D4CA44B16FDBBB3BD688D0454A786EB58C981AFCEF29E669F7FF9AFC7ACBE526E0C90D87471E0456BC54B52E54F30DB5944EAC63D09228B060C2DF6F2764B73AE90C8F777AC9A85C630004F4B8A94B7544CEFF7252B060D9E11F0075D1233969E92B608515BE5809D64456858E5A11AFC4A48D4FA203F35E372230FD13CB32DA19FFFAFEAA085E697068F64412C6C5DD2D0B3E9490073E8CEE249C27C85B8FD5533D9205528D52805BA23AF6C733ACFB53FCD34E0E5429C6620F9EF1557AB8138796CA64FE50C46DD3E6EE509B8C77EE6DE0DF2A03A3B6C1BD36A76924764A854722CACF567A83CED3B51F4C39762320A93A48C9781441D6BB5B7E3CAA16BEBDDAA04E980B71AAE61DA6E38FDDB6D68CD9104C5A2EF163CDBA5C0ECDF397649B4907E40484672CA5655F494B762849605DCE4A62C3EF0296DC362C44464DF9C5F4C7FD3136860B4239A9B010E702516F4F6F30289F66C2706BA52809BF1C462502D6D5E3B8FFA3D38C0EA8537A58D1CEAB6B0DE6E454FF50D968C7280FE02E21CE528198A63E24D7114DEDF3BC5BF6B734F38C71F94A44E79748DCB554E12E841B26DE17FD8F5C294462593F42BD7314F2FC3A052D9F21267AF48EFA11BB41EB61929351960131648C07A8397A91F77F448AA2A9D5E5C5FFAF3151FA45BED9744AF3AF46FC9D357392C3A0FF727E6E9FE75A345DDF3FD3DB116EB06D283EEA1E5F4A44DDFB1CF15BD42FAA70808F2634E37DA5DC5AF8AB5DBC08B20975101CE7DEFB84F6BFD309DECA1483A46CBD3AF9B4FEC29D5F0B6F6A865A26FF4A550775EA51867F914B5695454E218D79A10DA490D8F7E002244CD2FD6BEEEBC45E6A2335A669492C64510FB3407B9DB5D9794332855A6F955D229FAD7F4617CAD9AB226EF8210D4542F7B326A4879D543E25D7EA70CA97DE12D3767663769FA57143E59AF4016286F4A0BF5AABEEBE1A6207CB9DB185D1DFAC9112BDD1775C21DE296A4E26A4938BA97137DDDEE13A8DCC8894248F9E47C0F39BFD38E467D3147CB7B93F8F0DA174F5AF20240A35351237C14F4370CF8EBE5787698FB4C4751AD94E59832EBD23D76EAD065F13BEEAA2EF178171D3B246C324B7B988F93E9BEC68CFDE2AB73308878704BF15C4A903EE662F736449C97B0D9D8F0C4CFD8288D8A8E56670D1B5D8C540112A45E9A076259225679F6B1E9CE6F48AD05F0583406075144A6A0A8BE1E10A60DBCADDBD9D77F9CC1C48FF83DEAA1C3F4A9B82DDE68AC576E49129042B5CA83CE40E4390C55D469D3384ADEE49D09009205C7ED6655F73D71A23D5B608F663904F3F5D0B1A846763539B9D24826D2C0468B43AF6014FA9338BC3722340A775B278218C53B05E9146E6B2909C07D63E94DD3CE3CC24916B359731930E1DD66052474679B0C70DBB788388E5C8671B20CC3572E405935F4E92B1F80AE5E844DA4624B43A3F63263B84B8829C18D3E7ED324D8E053EB99F28BE90F22F739A0D24BFF6E3EB17829813ED0897B904FF5DD0A98347496AC059C159C63D5D4847F27FED4F6ECC231DB25C08D5BA9AAA7F369A54AFACA85DF4776ED95EE981C8777A7413FE49B83E1DEBA0E305422892ADAF4448DDF33CC0700A5CDAB3287C0368DD9CE8CA1E5498A14758E96D56BA36D3228E67138B63A68BC9A31806AA6FCB1D50AA79FC22A703CE6F5C77AE612A40A96D57A5A5A7A7AAE797273B6A2B669B978392732DE992963A80D6900068078906F44E14E29786CC8E97FF4E28B29ACB2F9BF38D673DB7FA3D0C4EE40ECD14F0EFE15883583C5C9C70D5894A4691AA6B0998B32610C8A5A2AF25B3BB2EC5774603C003FDC4519FF01AE6B26A13F4ACEFB8305A49FAAEC2FC2EEE1C3D3A49B818E3D522F31B46D69AFBF261BA66FBC0737C507729027E9C1369791D25F95D182353046453FDFF592036002B2254740C4AAF913106F54E7080D665E6D20964CE349179D4FAB9E697AA6E2175D0A7F30D129FBF2DC56B39EA9DC6814E29B53C05969B8EDE25EB18CFAC97671CA97AE5D103DAEB827BB8DE401CEBE007AD307C3C01EC8BAEA1AE0854A2160496A3FB12C69274AA80C86CD1381FA4DDA07AFF530102006CA3BB50D8F1031A88F4DDA5E328521FC283DBB4FEA7DF75040A0601E2040A0A060E066ADF6EBB6C539EA088133A181C960F3992B8F94F3CBA09B2AB86DFC4682C686F4D81AE2B1940BB10EB8918CB9B261A9387E9BAA5C891F79ECC6A12FD379101205EBE0BF0EDDF49D4676FACBEAC43E6993A9DDD2318A11383592AAA936C1E0629F62177F01B087FB5C1B2D95B19148B03530ED20ED890514DFC630309DAE8B9BDF8BE7F7A8AA41D60C6FE7A25A9FA8B31B3344F1575891D03F2B65E2D5D5A3F5814D6C79F0C2A5458B163954B01AFF5F0907EC8DCC478711A87CABC5FEABF4F247659D8A28EF511A6156823AD7D14C0E86F812B0419FADE2ECE5218CE76F597403761C72A01C153AF776ED4AC71332FEEFED1D65562E15BAEDF62248CC77C6689179C08FBE01B3505DC82FFFA7C19FFFFDBC9F317E9CF686B744835E6EAECC976216B7E6A69CDC570570F26C0A0CC9A2BEEA453C1EE6BCC67698BE10F1691A01265DBAD803D9F335CB789F876DDC71D6E46699B28CD304ED4C1D8C39119FFB3E65C80EDBF85B53D6451BF3D4A8FDE69922EBBEB0050C8213A55F80B5854D9AAA44494D88ED88B69C0A91634C069E377251E07079477C0676410A4669D1858C7C6A08783F6966C4A4163DD697D72C97B9EB51429742D583A95B497AFEDAB64A028C4598075C2466FAF7FF60C32346109EFCDC108A711949B76FD4EB43DA02411F72FF265A7C35BE36B0E6B8C91B4477A7138F044D91FAE20732758B18D0C4C3FCDF945235CE1E61DB364134C6CA1A9D3240E5F9120F7BB455F160F166E907C5FA6D59FDC6DF4244AF1DE3243991737E9EAFC2273E6D12DECF13344636F7AF4C0811EB69AB66D86E1596C50C185A04CB4CADF759417DFF879E62ABA5B300385A2CB766A522F18EA3DB0623ABF467BE74791B63A495053BB996751E8A9AEB0014535911656079FD05C78DA23DB23D9A35DF99764DCF97B6A49E5A9C40EE414A503E991206C148D2D8AF307DFCB9DDCC94B7FF951B34625F97A38A56E2B505F8F6AA27E42C62A006F9DAE92EC9E2EC4504440215D136F496628DA0AC30C32FD95199D2DB1DAD3E711B97A21D045CE1D3E00CF57CE29B881761C0D7710A77440360BDA691BBE7DDBBAE8EBADB1DCD355B826BE85B2FB783D3863BB51B7977542CB9D41D8D60F003151FA37C85CEF5F8A321AB8FD3718ECC49766A99656B2E8C745B36289A46E6FB1E7D01B05CC831F56A8C5451FEA8A51DC4EEE935A9A315CA8DB8A8A9D816377E391F31017C7CF034007594A2518CF12E89CE537D6FC2DD68FB5AD79507DF66966EC1529057B178F3506613E407CE02F1577794F3D7B343257B210343FA15C67E8A44356E5FE0B65483C4C49EE803F06F81C48AA79F14AF9658F6B4641B6DF3DD7836EE061DF93F4CBAD25E776D986CED938A5C703DFC2FCB4F39D4AA53637187B58B7DA580D6DE8613F3FAEA841F0A5176B7A224B2600FBF89F83AE539248CB1B5E02F1763874C48BEEEB03AB15DBD8B74DE3769241F1653DB75C1B27BCFECB5616AA54D31B246CBD32E7A7CE081BABE70F6A3852E20B54F112085E537600E4F75E3A9B1DF9683469618AC348453F89EE6D1A49B37BBBCBCC80E06C38C77F67B9DCF96A9DF0BDF9E5B4EB1454F208E3DDC7A0ADA998BC913E0BFE9E8774A81CF44128B5553304A889DFD98E9809A103D44074576063B8A573078C625EFC08A1A8D66B0D4FFD076B55414E9609F367A0C36EB2A901D01EBAB7D4383A96170A7F114B03D40BD3709C69BCE03E6C29CB2F38B0EE23D71CD0492268A721FF75B1DEA33CA33063F1B7E2348D16AF7C934BDF1013A6A9323F45C9393B1F15910E73DF635347283B2D9C6E4453AA53B51AB7246035BD42DB307F581FC79C8304E80876D8D26C5959E40986AE09D6D317A098CED0948994AE39AA4BE47EA1B5BB74C0564F7A29FA0B3D5AFA4BFD4C1DAC84AB7DF65EE5867AC49AD6306114D93CEF8335D30E268857CCA8EB02ECA410A7A9E2607462EE5CC8FC3B695946ABF66A50C9AD0536A4CA6B2219933A8582D4D87C28840101A21FD7625397EDCEFD1494E6689390FAD990E47824B3DC96FFF86C9FBCE7CA00F970410A6F91D307AD2B2C062E2532326822DB277F645387EA08B9BD2E8D130616837F41BC41D5C0C3DFD6EEB8DF9AA7FC1FFF08489BBA344798C294F7983A2559B28AF2D8A140B0314005435EF47C397BD68C01924B909315770365FE4B6B73920BACC5B04984385A2C51B886AF3A6AAC1149E6208BE32D5A94D7E768DB9545100CEE48EBCD89D6F942E3471119B089B2B3E147D03E9B6F9D2DFBF6CFFF9A7077F81BD34B4F51BA53C04D676CB4BAF388EAAD330C385CECA905F7EAF0E431339D34C3EFBB3104912A37A5264F264CD6AFEE6C54C391C04713871E7C46B3575B320A1020EBA2ED4D785F76FB0D95CEFE4A0557F551308A14C408957003A6FCCCC1AFDC4D0190FF91370BFD4D3EC994B7E5DE77D96D1F4E71361776F6F78E2DDC9EE185E1DF87D36DC3E10E4F125DDBC4845DF70813746E2EA06BDD5CC7D672FD704696B2032CC07E3F7F25D3DAD6DD5259CF46DC45057A1AA6D6F1EDFA5C2BF9AC46C6467DEC3798AFD41C0AC93D83F6F12F3657E30BD6CC106A88ACBAC3ED07E3AB84B69459A1696F14A38E547FC0F03FD26B5FAAA99F20E9873221690BD61987B97B938DD0C4C8C05FFF865483F199859544D460270C0623CB7A5FBB97F5E41C44799C01024681B8B31DF252929F42E57513CD15BEFDA0CB2CA2B8320DF0676244BAD552B8A24F4065F06E3CD383FE45391B6180D233229E73D17DEBED072627E39559BFC51B1809C636D2519AA9954A86CABC852F92E385CDB5275B4A6B418A96EAA8CEA9F806D35FD65BEB49FE9FF5D89504E92FDEDF35765B1EFDF201EFB7C2E2BEC150BBD441263BE139DAB06FD56475F9EEAB0951CD06E9292B8754B0F236A82A341254E58B89F05FEC87E3D5D103FA77A3F8DE5BC36161445B925FE4196B6C7524299C6668346D5AE0765F1CFD85E2488298FC4A4A263B648CA053D4105DA2EF19615FAE5076879F98AE3893DE1EB4092F5C5EF6EB58C4017B7978EB52289E0F96738A6A719BFED56D5B3C0957AD66BB3F205DB323EEDFDDD04BC0A13FE9D898CD6D676E46A9D75509D4CFB965F68437BF929391E3A1A257FE08E7AC43FBD33FB4E6ABC5070FDC8CDDD4257BFF0FCE5E569B4A03BB64540E45EFB5D9C20117AFF362DADD4905E87151BAEC0B44E3A4C2AEDFA2F12981EA0E81BF0B392EB31B1D90CF80778E919761347E469DACFDCC822F923A0D1F4F8737F237FBC0B73338D201FD533440CE1C696D82F0272632408981ADBF3C62F3317AF68940596552B91913C633084AB7ECECB31661E25FC54D8907B39951975CCE9BDB02F2EDC068911C5EA7BF9057F59627A571BCB86A749DFB2478866B63CCB45188B1046B9DEC260F47AB0C0FE0681007E08CE5283AB577F46DE6FDF579FE92AAB0C0C688917DBC51BE2661379823A613B5665B5E4E2757DA2A2DDD42F0D097BC9B94F6B2C8A8FD860E4FC8220DA46541E39482EABBAF7A6BCB52101DAF03401F16B0DA71FFFE8A522F0B210C374DFE3E1D46BA2BAFD0CA6FB9B5D9F2CC76D41E5DFD726990A92FFABC4B6F4857EA2E79F0B7BECCD7D24A0BD2D7C5D5C3531E71AC7FABC46BE0ED5AFCB1DDAA00AB0343AA05080A0D246DFDE1DECF707521939434136EFFD58A557D595C3F5A3468A0D456A7D0E9490F1B0D17FE22F93241543EEF00B38098F812AC4F418E759ABF66437565A003865B07248396004C503536914721F07FAA88160C0723ADF86F0FFB7DAECA4AFA7E33EB0977180EF452E0BFCE9D1B9BBAD3FAFBD72D66092BBAC6774E27F876F4F8A387A6ACD5A6A3886F09306D085738118700F3F24E9CF6E947D9D09C1805473A89837D7EBCD49030E4E3E5F928F720F875F008B860F70FFF9A547FFF624E13D0DE20A0CCE2F079ECA2C08F0128BDB791004931BCBFE6D4D48F8B30EB6260819B10924C3E8A6F6FE6F874826109CA446D2E3553DC2EA324899F11BA6BF9DEFB263304B37A50B6472B5EAEFB345138BADE36FE2400F7747EC30040E49323E1BB679B0EC9456179A27684B453800DCA0FA9B766ECCEDA45B399BB3772C85D02FCDF3E81DC9A1562EA15023EE5DE113812B67CA87F8761EB07DA2238FA176E5795002A6F7CC788779865C5CD80C714E6E7D72EB347FA663575FD6B1D72B0E7B43093CAA683F14E34AB201400BC08A5FB8D991C42550D2EF6641EEBDF156E461D10EFB32B6CECB8F8BBE2868398381CEF74DF7F5E026CF52A2F146F5D5F8DEF2FC742402E3D988A232C456EF6405FE270B31953C36B644A4BAF77AE14792A10D3F552C8BD45CDAE549C3854FF3BE67A05961A9D4E17D03392E82664883370294742DB388EAEE4DAFCEC8A28328D90F9DB0DE109B6A2D0F99E7EC53019FE35D61B0BCED17D6BAE6C07499C8DA86B7FB590F52CB1D3BE54BE025897679C6F400F62E97B312E2FA11501F94F0252965716B86499CCFDC67A1376716001465877B875D45988D625F0036110B8CCBB84B1AFDF7D4E48F081175DB43F6887E84604378E78087CEE4100BF1B4BA0F91F4812E00C82D3A8F456D3A34D4947D32AB88AFCAB015C31A1EC2EDBA2D41AFA08F5CF4F8ACE846C0EE852EC4EB5B4963B4C47E336ABF00867D4C11ACCFAACC5AB9301D028A7E50ADA9FB6AFBF023FA78F2231B2234638109122AF1660A4573C94E0145B1EF13A226EF8A420EF4F46599AF9EAEFC50820DB3FE4CB2E0E7F9A114E6EB57CB786F834B23F034E1D6E585F74C59F70EA6F5884A8F802D11B362832AD9527B48A9057EDED70FC70EB2AAFC20F1795D521A5585A38F0C2D8758E0E37EC66F52BD266BC3F0F92139662F258A81590E9E91F73C3BCEF9BB402FBBD865CE46843651F5F692874B32D4210BC936D08DF5E9CDB7F7ABC94894AFFDCEA73E140D974A28038271EA6DFD62FAD1F58AEDE19964C0F3E1801590D00413B92ED408F914EB52F08FB7FE6617706CF26460F4114B2D050CE62A516069C0EA80D10E4D008F50F5B4328B0301EE27C796ACE2D0639039600F346847CA86E2C077F4107CB8F865C9EBA8800E8DC6F045AD68AF9DFD8D2EB1DF0FE399E3CC6F2297F63E2156634B2C16902BAB11A6B7E76800D98C57A60E3938F338AA421F93E31D02C0B907C9A7397012958CAD0941E7102D0FDDAD8C11E91CC8C1DBE1E470F410C5AB0EA680E53F72983B17ADBAD13B9EB6CD8F7FFAC35366B378B770103ECEB786C6647ABEE746F0EF7839E534C75D74817CC3877D8BAB6AB21F241F25706379E0646F806C1CF6A2B6945337BBF5656B6E0E1FD7649E64766748BBFEF50EC27F24DC22100913F946FCF65F7FE8D1AC465AF92718E5426A697DCF27FFAE7683C937DBEC77BD870E7EAFBC56B3F1C5A883DCE47563E5CC8FEE0EFD19D194CDAA11D64AEC993B37C15D8A7ED04D8D6479B693708AB75FEEE0FE368CC35A043141FB06031922B2E5C1D15CD0F4117B34113726983D7BAF988A0EA73F74E5E6F7C8F3C2B2AE316740337BF8E257E6A6AD7384BA5261EC01C535A58E671EB7221CA109A5EADB646BE262ECF7BFA97D1ECF48BF8E7C4ABF11C807E4A792B5ED3A5072074BA589368931BFBC6C09BEBE067C618EBADDA58C1723721E4C4960BF893EB2C4AECBCD084D919DC9F1A44EB5348BEA8F44B259F0A44700D24DD39EE4D8C47098D4B11FF6C2502A45D4C88AAB9426A2B409AF6BE81E3767E814CD2BCF36BC060AEA1F41130BD713BE0E345F8E31AE77063CD08CAF3269B07B1EB5F28C27694BB0997656BA0E6BCCA05A03F34248BF46017876C95B231B9898555C124049ADC7DDAE237E7264DA375565E0080C30C850FED5FCE85D8A90F6FB8B6C9974238C6555D1444F266400C7DE51CC6DC4E94DA910A2914006FD9F4C9DF6E38C50D990FE3EF96A1714A0B3ED9070D1FF55C9BE18281B7990748C1FCC63FF6BA8B63A3BAD2A22636A44CFD67ABE6CDC4BA454DB03DC0250E0B3A10418B9FC837D2D5022F633A25F2B559F80ABDEACC9EF3BCBB5DD6DF488CA7C838100E4FFCBC73A006606DC5D96E914417D9EA839696B9FE1D139FD44F69BD49FA83B42F8E44C3C1D193E2E386D76B50B3A394533A7A48F8C79C7AFF57B4DC14A4FD804AAFB6DD15C56A5FF5DDF4D1C5734039797206F7C9816D53272C8F3A5FA87F08C16DB4D38FAD9CDE126A5939FF997A2301CEE7ED3E93F1EBC7D8AFC641064FA3D207A5E35A531D8786219BDDD71EE40FA220C8EA0C280B437FB4165D3DC87A0A53CE2EA12FEFFDF87FB24B6E9F5DB6EDB40F2BE09EC806574AC01F6888A37AEF7BEF81EBBC3638622FB07B7511F628B3C3A4684505F9AF58D72F5584517C33535512F78237EFE7E9C763F14BF3F89756FB3CE6E903FBF4A91B945FD5BED9783A51334972160049B712C8ADF73ADA62A0FDFF24026491AA1372D3D98C9CB3C9262269610A7C3630EBD0C7388D2FC8F2E7DB1DC35B0D2B44268DF6FD5096630B9A1FFE5473059AA0E2A845D16C1350E19B22991F9ABC0535DB0F6B5C2D831D6D9789A30FF75A5D50EDC26E82449E3D53E6D69F5B2C45C77627C677FC9E2966B6466224B731027F4503D4668F0C14AC8663795D7456DE0FC08BFED4A81B0A9495001BA98C1F7D493783DC5492EA56D741934DB2739B1FD7F8C88D0CDEDAF738BCC1C4357310957724102C91A1A2671D87DAF4C4E4E4BAD48918E8E2E500B688C23D3BCF45FB63900B116DEB0721B682B6D412C7E8BB48CF4E839989B1A981DEDAF8B5FA6CA4B853972E0DE779C97126C96173ABDC5602E1236CBF418D82F8A76287B6D1BFD5D61EECD94A9261B3E3EE047BDCA7D95EA6BE6CA0D6C20DD9BC71BA78BAD01B20ABC216E979695F53DBF0789607E8BC78D53A3C7021FE9AC159C705E81D4D8D37C8E1C541087ED1BFEE1AFA2899BD090C968C36160BA0D34A609554BB5B32442D2F79A4ABA0EC8036A7427CB8F56E5E0EB63B5A9411525ED1FB540AD17041968CDFBC69C560C19B3D096A302BD9FA431D9005D5F0B6CE13F7671FB5A8A2055A0062A0BD9CCA7EA90CFAC083AABF2820F899EC8BB9AE4A3C45B10B23D396D211971D8377FFE1B96233B1AF7085673858D34A3E0B7E9BBB66E91A4F478994E9C31B5930D1139BD78DFFB0673F3E426495A5E3312EDB00B24D4E9634D5D24035654C40CB177CA0D9C25976A7A57C9AC5C42DBD97FD8C550355FA43F4CF1DD8756E73DD182EC8522A2342FD6C48B4680BAD31FE5BAFFD5705EB7A82CF0A60A9B06B6496294D0E662140485FBF3880BAB54D3D4CFE27B764E74807CE07A112DE03751D41380C182A07DD53899D83A274FE9BF00DD2753F709F37FE43EEF9FACB309581264B7A11A0C27DA81A615FDF0CFC14D27D017A5BA7A8C893FDBF0C3937341CC5D76A15374FCBDD331F4AECC027CE879991303C336EBFF8D337CEA4688A78017E1DC373CE044FFCD83F03AEF7E697A87DD8B72B74EB94CEF056B3BF9DBB8F83FE01AEA41D38B70A874804387B5B82B890576B592F91F5F7A0462F2411A3DC4CDB666D88E8EF1CF8AA883E57C4D2402FE3F3D0A8A3B634E33690207044F507778DA37AA3988862BBFA0700CA335C4C36DB92E10A319E1BD85F99C19205A1FC18CC398C10DB355D9BC838371DB0DA9741EEBFCD3494D8E9CBD7D35C772680BE2EA50FEA4EDD9600838826B9978609247CF6B6A27479EB28FBDB4ECC50F06AE17E91C0DC673EF8FF9FF1FF781E00CE30896D56BAA087DCBAEEB9FEAD5CCF7BD4A29AE2D4D00642C5EEB42B4BC08614D6D1F8C97A4EE22EF53B4DE86098D2CCAA17CEDFFD66FF05371357FCC7223786E483253C8BF6CE1C9F8EC07D1C42E25A43B6E138D3A48302CD0B7E3C94489D1EFA577748DD02A69AB6D744705819C4F3F8904DD2985F36494F5099652938B48398B187648827C2CD7971B0F381ABD8A4219CA6A2BF6F02A4F994A050D8207A249D2E849553A904DFE2F2F7D75EDA8A51A1F265AE572E33814BB7C11961F854AB6EFADC3FE5E654C034F3B423D542C45665484184D701FB17228AC3608642BDDAE8753051325730EF2BB73E88123749BB748397B8F9E031FC6B13B769404F58BDE605BF4ED7B26B1A7665319FBCD0F5A4318AECEE11A9C3893D49778DE36BF0EDB24132C07E3C9877D87B0765102C43393F02754D92119BF2DB48D41935D11B091FC9BB4C97233319413000A0C866BEBE7A037533FEB1D9B0102B12686B4FB7F769F20C7ED82179F9FD55BB0DB875D3CB380E8D893FA4D8D4054842D071A2935D2D66A560D424FC6672EF6A4EC66C70580709F1230E075A7F6C39CF38F48A01BD69134312814B18057C4F01FF71824F838CF617012409F8235BC340950EA821E4805DFF81D6CFBF25121A688E8CFD8498AE7FDC325C09667E2608830269F64D4B2B23638DFFC5EC9967CC33DE8B6FC779C3FA7E29FE8B7155964126C4031C5E4E15E2CB24DBB0B4CC3079FBFC50F296C42A898C60C1D660D1BD85C54136D248C38C45DBE11DE6651862CDB983CB671B2F3C73A88047512B931A3C3CE726E3EE920D151BAC00F491428F4AA7E58F78169F8521C6F21CDDA8DB4416EAF684A46AF128A53588C75ADFF1A79A75C73FBBC04F8D169013C606CE35AFCB62E0E5CC466E1CB04E527E8F2E9CA80A77550028FFC6CE325F69A178455D5A1D2390B82BE0BE7CFBBBDF224AA5B58E445173C1AA248C99992018004CAC1F5EB8FE3754D320254F20857C7FC49EED82FF737067F18996006D7F0A7207709CA3029378A54C18E00041CD7B1D5829B656A4A50E6843C156EB5E7FDA911EBC040D778FA5E1C7B74A0E0C9FD855EA53EC430F9715E4B310FAE04B7E90040800723E6473FB6040AE8D1B794246D7795564E447846BACF4C7AC9BEB31F64446F5FDDF8514665A651BC75B832A653698B67A33FC3A9516259450DD4E87BDFBCEDE7A2C606E5EBE9B6D2C9370E2D05C59FB473BBB00AF7FFD64F0BD6A322257231EEAC1BE7D214E0861153609EB5852EE4B9049AAA8E6BB709BD2C18B7A387806A1C60C1F41A7551876FD08D76E1700A7757FACE9085331174862C706688EC4BFCB2FFF6339707258DA2BE03AF94381AFB02D82E5D864F1C0D8CF09782C3577A7B2BE4FFFC098A3E3DFAE070620A8AB210FA8A1345ED6D2115C649A7CDCA724EBFCD266D1006C5848DCCBC356B2B38D8AFF33CA11C4A4A7C1A0728FDE07AFA3CF4173BEFE0593DE6D8F4A7D87FD3265D819532FBA70A363C7554E6F8AEA5F9F6C3F2EF60B9B723B46760377AC2A2460CD2323EC050622A677803872479B856EE04B70A74F9D994BC9686EF6E8969C91B589EFFAE572DF1310F58E76E46A1797D7D4E6FBB7C4740889EC7B664F8A12C6E88A1B6247DE36264C9A6972B83EA24671A13B20896D9926AC8582D9565BE621FF7EF1E8ED7745500E4101F5098F2927A3F19D7602313FED8B65AC90693AF21E87F7A6CCB2D67FE7A8B026804AD19A6FC6B5C8526AC988DEA0D18E6CFFCE7EF853CC29A9000EFA5B2BB4F59B8B13E44CE01DFABAE5542F475A368F7A35DE4EC8FF258E882CD5E7E8F921EA265332E3E38204B0C040179D61E1828CAE45C3C72B36F48CDF65A40B529ECB90E221A34549E5376BDD176EE76EF1D3253613A3F1F51E16F2F1CCB2CFC9042DF9C1FC6C4E680E38573F6AC5CD49FA007F1E23C51583470E84EB0CB6363DA844DEA842DC224508E55D2CC6683D852064B56836EEFABF77D80F82B14FD7C5A932D2DFFC17828FA7D7AE8F44E51C7C5987A8E30A2DB11F04B35351E512E6E767B381BA9257B3DDD38BA0303921A35349BAAB2FD4F2575E6580E6E48E177144F07D68A1DD89563FC7206F93C2D4C0D95F6942E6CEA0B6726340995FA66EBF14DD2F35CDE4EE86BF230D8AF177437887B08068D2A7CD9E1C8A19B1A90E1EBE03D999670F554D5734406C7EC6D453E2AD774CCCD055AABB9349B0A24B9F72F3407B79FA6F3532FC92ED22855B341917F80FFD4BEC22C913C14DBBEA4DF192C96B78969D36C52EC84114C9CA9F349B1EC980F378BD24EA06C5CB4C786BE0D6FD258D3DB240E40AF3898252E7F5E7A8B09DB8CF52B49588EFF81DA9E8DA71ABA8F1073F2E781D77FEAA65F077166D23D5C448C55E35B5FD78A80226515FCEE9F4EB8B023DD2739753C6AAD8B6F2776E35C2FA58F0F66B00FFF6F0AAE646C8349DFEBA36AB17697020F36DBD356E98657E815907331EEDCE24BDA13462F723835EA0000412E164EE8670D8BBAB7F9F21C2A19FBCD87E9DE932520B3DA167C310F0968D2B8DA686A51C840283F1848CA313A206326045507E4D260205FFD42EB951634325D888223EDEB9180016B63BAE8F9081C302C21445BAF3D7B8BFEAB76345E5622E1CAAD1E606C41EA218CEE7344977BCEFD3ABA146D5DAD808C2B3BCB43D7A64674FD13AB1E8C93AF9FBF7DC9284B40213602C3CE6631E7F13158A1B0CB457A1B9E67F74195AF9957DA7A85FCB8FFAE1F62391DC0533758ED1433BFC4ED9AE9D93012B3AD24EFB6474E69948DF73AA9F670F08B9FDB49EFC81F53731B60E2623AB904C7CAE77D6976285C367495AAA5A2D92379F584C1252EDF707C8E5836C72DA7AC1391DE8A32F350F48FFBE34A07A16606628421B986DC60F36557353E3522185015B6DB22E60B453F7DBFDC286203577B12C56FCA7F475D32CA357E31B4CA6CC79019D1D2DE4581BDB59F86C2196185C3B3254344E06E5751393414EB252F415B3F90E586E3F1BA8BF105556F0377793935C0264BE77DB4F03820A829A4C75E2C87857AB7B08A4924AEAF90D00F515A359E26645362CAA629ACC10564ED1FF05EC072DE9A4D2CAB15487F77DD7AF7D6EB2797F805708EBEF5106DEEF16C19F22D1E24C7D01F7B4E328C3441D830C985A695EEDDFE800C7CFFFD8609C738361F4077E569ECE79BA2CE3B165D67C453823FAE1DFB7DCE74D383A42744A8E368A9A1483CC424D734A9F500FD49D8A16D0CB0099F08DC8B410F8E28667CCF9E5D96B35BAF2638258151D484830D8A7B7AF85DF4A1D60ACC5CF3562CE1F166BB470B24260187A378E7A46540AB846E7D56F2A4AA5DF2E5B0503E42DB4431CBBE992425AC6163E7948CDD24F25973384D1E3048B5ED4D231E09D6B9C5BD56766FC06C65782DEEE9A25EDCB711215E02BE1B2EDCA644D6B0C57E6EC473FDF124B19805618CFDBA3F728B62AB120FCC4F8BDF798C60532F947E964C885D1E70B06CAC7C64DFF2B2747F8CC471A3A5F98FFD49506093F36D6A69CDF3682730931992D69A234A2F0F60E2903028D176CC3A562284857B9B764C7165C7D052EB7EBDA29943EA43879DB3886839A4AA2521B048AA12FD15CF9F8C547E7B002494419BC491C1A6BE3645AB0BB6C7F09FC7CB728D6E6D0A1FFA065238561E0C6B2B4BC1C8DAF6CB5A785FC7F69885EED0401E0D921044FF11B7A7368B1920AEA5F9C91B999F7EAAB02A2DA5740200BE041EF4B11BB16411814A8425B0CC4CBF9786B13D5BC658E18CBFC6D75A2E575F08E6E045FAE1E8C6C1404F81B43C3C4E77C80B07B35D6459A2BAA7690A50999C25AFD667FC8733BC04F44813FC61365EDA550D4CBEF051F6A75E3E05C06BA82ED5599F818290FE28AB16A9A43E8707604F339163726D76BFBE0E04B915F1CA43C9D89E805DD58453ADEED6A5D515B06D1BF91CF3948A0BFC66F88A8751A547AD6AC5AEF95E102B684F6AFB4BFC195FB7E1B76429A3273A5002EAF28DB21542CFEB5C346FB3CFE68B58F3B0FAEE628B2097ED386275F80F040A3767227CDC7F83A4703F0F43F86B555B318AC301F683963B6BD3FF9848EA974F44390103BCC9901A23C113E42EE22FCA2856539968EBB040986BC07E60A5FE4C6BD3F795AED7E6D17CFDC0A9524FA570783DC365635A29DA3C1FD6F22857E1CB7FA018595810EA1DA41754DF51DD203B85BDB2A8FD65F4A324B6CDDEBD9455AA0C07D062B88D0CD167CA5A1B7EDB7CDAA6827A777201DFFA70F49BBB0AE68A9857A74E74816B6DC44E2127B0A36A749D3A68F45B293E83200F587DCA7F9E3BF640C7CE32A63CF399DB7FCE34A2EB8108BE462719632F9C15CA7147A99ECF204E2A3B421E77D12011720E2FBEA607D0E05533AA13FFD35BD87546AF169AB030D0BF035C5A2BB5B40163BDB5F3B6CF6FB3A25FC0788DB88065AC8E9A216D519BCA075C0BF99ABE4F6D2CC84CFC23458A087508533BB0ECC4AE631ADD4B33E4B02FD47EE24717B1823D618A21A30EF8143E5136743A43DAA6AB92FC32C6EF549624EBFF893760A513B19D24A89BBD0DCEC7DADF1EAF0C9F295C8204E3CBB7BFC73C9F148A64211DEA1366925E2084CB01D6DB32102144D12041F31CAB8528DFD02D0DEE1CF1247514B7F97F3EC769C27BC4606977754437103B9E5D15F346F31862287EF843DD488CB8857B79A6F86A3A2D452DF9AB39DBB3FBBB5F705601E9B186B8785AC044466589C06ACAD3970FECDB57F5C6B7A2F5029D87CC54C1913234721F7ECAF46FFB6FA2000DD7C826669915FAFA692497765C59EFD19F6A07999567006001565009576BE2DBFCA14F3A776A4471EE0DA9DE69DB597A02A8E2C6A36AB1E4D0A8668EFB7D893E4AB79ED085F336650DCEFAF308E9A4A320F90F64B9D77C6793D2BE435CE6A816CD2E62805BDB5516A711868FDC6EC4FBE91F8CB863D7DAEF718977B49D5C3E25B3C65ADD8508BCC56774080778B6655C2BE977CCB21522D81CE11AD5B6168D803883F9705EA5FEDE2104AF484FEC65A46316970DBEA2107DCB71FCB54DDA204299CB545E1BB6BDE46F9F9BBF5ED5BCE509F11763A112CC6358B192FD61D397CDDF2EF63BC5223FE38506B297A5F5EE4347083DB765DAD63F6B8326950347651E4C345B6D7806B9DDA4FA7155BC1F241BD407AE4ECE508C323D352433E4BD77C6F66FEC26A2A46C36525624A08DE234A468365535C34EEFAA6ED7F42F660890207FFC207BB090B2BBF96F1E6361D004CADDCA3FD6CE3C2209E4EE7FFDE6C07034CEF91361315FF2A7FDE5A84462E3FF60CEEE49D9912B7ADD9504DFBEDCB1EC96AFFBCECECFAE236BBD8809FB36BFCE181729C20E5CA830BDD82D610FD33347A58E6EAEFF3AE6542330D0125E026E8E6C0C54AC5BB3279AC4DE28565EE19FBF08350528C279F15DD4A4E9458A2BB857708D14A04EEE77C1B9E58838BAF34D1A71E72417B4B7048DB647E1D2C44F803F1E93B5625E084E1E8A4B8AA5B6B9B0FB94B12E179D026152E8B2F7C144BB0A433A73FED2329668356FB7B895F168909BCE645E5897BC1BA0EF1319D4F5D87BED42C7BE729A6351583A7B0E50E500DDD2A789567C113C7A02EE162FFCCB312B1A1E2EDBFF8E04D7C872340100A305751E552C1BF7BBEFF802518B2FE27B220B341B83FE837645C60C90BA2BE26E16FDF8BE4AE4300B65162057E2F3D9621EA5BD9B238A3437D2B0929E70B7DCD25BA18F4ED3E5D676B7AFA23ABDFF8532BE1635EF4F87FBB8FD351587419F4E31E0E17A2E56E315B72AF959B8D64CA001CDF90F5D5305964C2F9528EDDF60E226228BA77F1C2B825DCAEA030E2C7298F1D2DA8C1C18F74FDF91E7030665E6460A33B6C1F3B78E9938E52B1BCCAC541F87A68FBCBC218807352F20D612A6C154A8D75CDF1DDA0BF5B35CEE34C74AD72D6DEED9AC1735B689B4E7FA911D77B040A59A98A35A72B3841E5B6F893FE7DD74F504E7E2FE52408BE9DBEF0060241C0A83F6902CA965D65EB8E724546D65EAE257666CE22785690ECC20D32294B0E86C88A454B03E3BEAD035FAC3AF754C7BD581DFB2B5B7F2DCCA83C239F7DE01F69550BB66253DBFBFEAB6C9F1900EA88CE8DCD307260F47A2BB8349FB866EF0360EA6D5D8CE219766C2E391C2487581BB6E54CEAF413145504C6324FD631E3CA3707E57EB4275C1160ED698B4CEF6E6138DA3B8A65D0A137810651B793203769AE5D16CA8587E4BA02DAC350DCD6703BA6D592C846028AF404EBFAB60EE80B3AD4A968235AA42529B31DE0F1A3D1C19F087ECEE2D392DF67F32EE74D9117F19B43D53A9BF69E1109C2633507FC2D18781494801E168EB5FDF2C07ECAFB5C6FF2A00881231ED7955A837DC08AE36BD3E1D4D5C8064C7FAD9A15FF14F5ED083EBAD7110E840E02776C17531A54D66C2987220DA19B6615AC34031C00C5324811E9AD5B505CB21D7D562565667C69B8F57DA7037B14C43F38A1D1197128E226C953DBCE3FB6B101DBE4BECEB5DE202318E6915E6BA9B3EB3E166DB37D45CCB9894F2CE604F8E380DB84EBE6BD5D375FBA4B2C468EE55D86CB47E5F28E4188C208B4CDD92A0F97D5A1B0975AA0B99E0292BE4EF61643B1553E8A8EE4BCE1B38DC8F006BC3BFA5B0A0FB65DD0C62C82B8AEE68D286EAC31969A52A5F10FB77479B28AC23756A86D86A8B445AD32D6CDF396C0880EE24259B02F736243A9BA1867BF9B0624D03641C5E06697D5B61B7EB709414197E231DEB02C232F9AC6CA2136E7C0F917F672474CA79E2D7FA280FF5101EA89AE70E8717688D805FE3EB3830EB7B44B56380FF2C09092E005800DE5A40B59112A40145441462D5DFFC5993A0055732FF9CCC52EA5FBCFC30432D89065075C93732BDAD583EFBA79A83995E37E8110D56C871F593A1EC1824BF4F3B8843ABAC4530FE7BE8E00A870D67B81F49CD44AE566FF68F1C1805F4EBE6B15C725FDCCF6B3ABC733F68E5F907A67744485E03DE7D5C6F6F8D96C0167EFEF4F3F48658021DE9A03459A1D65DAFC944AB55AFE0F58C2C82F56050F52E4C84D3A4FB20A0980C38EE657AA4A5F0BE3DF41E56653B60A779E9E19BCBFB0F48F253D3783FF08EC9ABF097A75563C4FDBBEBE6681D9FA7CE01049F9F00088AB8FE086E19A4926CF2B7994C7F74B4F52CD2B11A641079464240494EF8DFD623CA8B4C647FC5E78C43E5B454E2D815948AF759550893F97B06C86EF7C484CC4D8196E5FC9D700DAEF910EE71FBD294DA5F217A2BC7F02DAC82D86C771B2127F11EAA46250FAAE979C1E4EBFA6F7EFF6753098DF3E66EAF1BA8F3EF4F22CEB841BE0BCAF778CFE60BA0A96066D7E00DF81F6DB77202CBCDD539A33652BBC48F85AD41BDCA059325AD9E949CEF2E20C568195B3003160AB0EFEBF5F533ED6A54E40CAD70F4D33DA3568F68BB56F9981590484FC9E5B85EF0705163F9C1775FEA9F8C40C3F14477E5BDF142A519BA7E82BAD8C8DA7D696E6ED5901343031DF6D02A172A4B5965437E33A16BF63A1E280BD39C34B1F121807324FD73D1877F2880FE89FD6541899D48CBF155B963002B60974CC33E5CA25E52EB1EDA97672253BF081037F8E257A18B8A06EA3865A5C582CC5E7053D2E90610F35E6E186FF57DF153EB7D41D93E3F58FD6BF74E88055EC0F9C4A31E3A5106D4A04559D31A127FF75B4EB400334966F92FE01E07B09A5CD1944FD40212B52A1B55677DC8A79617912B380E6C0FDF16DD246495EF9403E0FFE0EC1DA0F9CF6DBABA47E1EC30495186D2F129649862E66F6CAD852250C9AEA7A8097AF9D26D83DF0ACC5E4AF362090901D698390465C1D7C07995C3A1784F35E7A0AC1BDA998467FBA5B2FAB9FCB8CCF0FC14EB9B868CD5D5E430DE20DCD3E9AED71D093009CFA49803A4388C372D4AAAC8C9D8E7B26BFBC4DF7BC0D2785FCC1768738505905EBB4BCC2847C78DCB92AA2BEFBE8A7B00A3AF4632F91AA2C437E9CDC86E9AED9ECC0B0F4E99A6424C86C53C058DEE7A1D079B87D5A02E47CCA7446F6B4744EEF772E67A8011E8480165B9779079458EF0C6E576DAF7821DD28659AA63A4D767874B85A2316423C741A26EB54791255FAEE2E7F726283001710EA3F6599C30555E15614F110518394853941D6332426283B867BF29FA4AAEABCC8A70982A0807FCC59B0A1B0811B5E3E6AD8EAF3A4FCD4D272A4BE4BEC48093717754B8B0A14C04A8916C6E3AD138022EE743DBEAF5DE8EBEA105BF67B7DB4B9CB61B3BCC0096F06369B0D0D41B1C92C0B27F8928065B0227081CB702F238CC79C8108ACB84F2ACD5E721DDFA1CE9FF77651B6ADE6C43B401F201784345DB4F192AC50200D183F540FD9E4B6ED9CD11493BA1CD41EEE24E5716E9DEEBE983959D39217FF0FFDF24B5F2B66CBC82C5030088102B4CD2434289D45EB2E2E7DE379DD8A5698897782A6EE23BC787F695B297D2BC7009896A8EE412A5CFA7A4E37551D621DA8CA3E24EC2F574841267BCC7070A2AE77B8F5545DE2675BB7726EEE36B33B014FEB7B2C13EBFEE36B34095F50D75BED5F08D59BEF2208F8843DDEA1E40A95369CA09C1F46BB7DB9881405A18FDBF39B0766D3F9803743E93FAB6A8194C30080AAEED9DB111A2321266057F2B532D7BEB62E76E22BDA0EF3165191C29305280048E5434CF1CC44FE52E1236F46A5BBDD11873BA5A1F40CCC3DD5797C0D3FEE32984B22FE8DF8F3BD6F6E19C461B6A93119191442C3FDF44C01E354CC27340CD508CEBD11D704FE5605E8A25AD5D67F2F2786AC528DBD557E3CB967C6CA202F481850B87FBC57F9B8F84D5E9157077B5D1654DCA05C0DF0C9069E6037C5A07D408C5C8BF52E252B1807DC2DFAC1D7ABAD32A0787A33D61AE4FE8AB5FEB68B9E02721BBDFEE8EDA0656C7660E38C0BFA6432A1D38E2964AEC9FBA1EF4702AFBAD424618D70005DF22FC3DD79550091B35D8A3C1A3E7B02A796F337A1D4880BEE9C7B49A529C7A184DC59955C25E07E79A82A792D1B8D96CFF53F283211318E77BA75F296E44A5D0482B0E8C2420160BCB5F7048DDA794F5DB4AB8C745B80DEA1A4849614A1FE3FEF3ADA06B853AB762057AF721B2815D27FD3B1287164F6DBEFA2D435B91822C27130E9D7F769034E0AF41FC15D6BD8E72580B61F572FCAA731624B93A9A0FFCCEDFD9DE6565E6609D28672A6D2BCD99F759F8692E4CE5A7FF1BDD6688849D5DED08022A49125E2D80CDF2A796F0774B6456710957426A8ADE201A41FF3B31F9AC246A05613D8085D7798451E1E54BB386B3B7EBCF70D9146A0E670E3AB37C53FB6E17B9ED0BDCA909ED5DD4A413CE1D5FC6072BEC06DEADEFBBDA329A142430BB0E9DB42A0910C576BB151A68A55AFDE2EB3531D393DE88CADEC2472EE464381D6604FEF45A9CA2DBA299BF4D31F1034CFDC0AA68ECBBB92A53C2DC90BDA82DF50CC46F2D0EF8EBBDD23EFF95AC1FB244924B26FAAF6D56A0011A6A9E13ABF1E70E0F0F4B8D9B54ECAD260A49A19B8E33596526ACA9C0FF736CA372714133BC9977077FCC43F5C3118D1B3409CD1EC4D8E60FC3E96E969CB497B7CFA1515E0E3F6CB15A73D18D024C8C73E0D6E7E8DADA3C921ED4E4663FE2FDACCD3838A882E5CD690F5438D542ACB1DA05A19BF5073F04B37164F3337F583B057AE283E93B234191850C7AE1662597190FCBA077068C82B26AE260B7FE024C2452C1423A45176B3C7C8FEB648809B0B1918FC9D74E2C98D126B333E9DDEDBAA2B85CBB7EC57084CD0543D382F680BC4C9A810D2FD2615BFCD129A1AC0E89C5E15BC97CB0BE7EFD355CDD6D88989E9A7E7841895287C2B2AF74B28A8B93768133F2BD87F285C3937B4F77F3FF6551AA7D552C5EFA88DD7EE28483B78F3A10A130A9D22091AA189F73374F429A4DDAEF8AEF860A1675B901D0DB655BD85F1CB4AD8D56F507CF39A44077AB7EFE356C5A4C438D4F357F77A3E0D5174AFC90F0982CB08756EB8D62BF862F9DA97D9E3B7140938CBD2137F21B6D4B87A2F8E812EB81B1B10CEAC04304859F416AD41A49089DD50A0B277439F3E9172BB57B84AF44D97ADDBEB54C9A234F1789993F490CFBEFE8B12057F0582E7D88B02A4875A81879875E7BB6371DD7D9EE0458195AFEFC830447B3907404AEB2459973F826E04FA307A7BA55CB45FBCE36DF14D029E93BDDE34503678B8C692FE18FCE332E38B68841516FA0FD8DCD14D6532085BF2C606E76F718F9E7A66316592F700DAFC3BE84910F52C469A87D11FF78FDFB31272D3EB2A8902AB1727BDE2C7A8E9930BA47197FDDEE1FAB1C03E5DFAAAD045A4BC3A4CE18481FBEBA9DBD36AF117122D71FD58B0533BC14BA719BCC71E0BC1C7EF2E136E95B392F7C5399DEDFF29775CF18016A5DEB37368225D21AEECBDDB24E919733B36793C5229BB4CEE9432F20F1CBD2FA9D0CF84A82E228C5670A930B6BB8DE1299D55BAB8AE73FA7D8E5E7FB14FA19DAC96445B9C13979AF6D5A9063B1A967ED266B885F9FCFB3D08A8149010A8548BD17C047C06DAA522F37638A332AF1CBE79B8F339B939967432476BDC83183B39BC9BC5891B01515C53B0AC4A69C8CED65A40B6D7D939190E6A3D2D740E025CFBC64F48606243500492CD231FE2119D37DC8E49DF289DE1837CDCDC1627FDB6A60D0A58CD9E59D564BFC097A6FC617A01691A11104CF921DA8A8695F8B10BD2254A1668779A1E1FFD03DD150248426FABCA15DB32158DABEFB7D5CF23D277447989D9D9CCC8EECD1901B87721378F055FBEC33163E165E27DEC4B9A4DC9BE3E0C71DDB8635562729CB48EDB288199E9DABE76E22F1E23AD6734300CA9E4315DEEA4BF90ADF8AE78530BF131E2C9EE1783EEFAFF1F2048FB1CB61D49B8605D936A5CFDB682C3A2A9DE848525F15A61ECD0FF73A6B409B7660E5AF08787FB472FC8447C8FA31F3787ABFB7A4F33D9A615F3228BA5CAEDE10996D2A6028C91EFC4897E9487752EA26A513326C6EEB8B4EB7F719C71A9CC7F77D0DF5824FA02483F0E5CA15FF8D38DBB252C65EC6E563744382483D4599BF203BED219D44976BF0FC4C80112F6042ACEAC0227C121529B16DC5CE4FFB76275EE0ECA05990C72C8B99F0FA663B9FF3661AF887005A6B48BE67AA28802B5D313D03F46B92F04CD99B0657C1A5048D9D49FD4A801D27D4A5EB555FE579AB6DF0574221489F71CA021EE2EAE0E6DBDCA9C370A0F711D90D9C5C8DC6A4EF5E1D7BC3FDFBCDFD875C13D793D16CAC0829E6ACDADFD254B3253B773D3519CA79F0A08CC2A2F39D6BA6EF9F8F3C141B41C54CBD327CB35D657F733635AAC33633250673730B4E94F16827F09CE239A97B5A9E7498D2510A4036F335C4A935517064DF99F8746793F71180420F358FDF1D6F6A25609E35A0C57601BA0C946CA2018ACD49170445D40D2CFF90BEE76F01F08E70546F4AB2172AE38F737FD2CA32287C5DEF54FCC278FAA90F0FD69E0CB04F8F9937CA636C025DBE036992FA2DA60AA2947DEB43B241206CD59EDEE82B643B70E6E9D0086F172E964E092525885CD10C6DD0CD50AFB4C1B58A85E3B0BB4F6F9EB545D0C9A84034E89DA10844F7E73BAB2D45D88C14A0D7697DB3E32DB3AE6D52B13B1BD7F9F7385BC2B4E643401062F6DC609F8A43821BF250E675AA6379FC77D445B5BEB40AAE60D1B968F0172BB9E454D5504CB397B06339D6CAAF25945361822B78ADA7657C69BE6A97E69BB245FD0268C3F9E1052A91A64F154AC6E56D27AD6B4FBA37C9C51B9445EA7032AFF7F2869EC9100D8B2F9877E44C09223D0DFDE8FB13D44B5F0EA6BAB26087303B26B131E977371B905379C5A41BCE8DC1426E5710B3F3330BBB995F001961C3E52C452EE684AE58ABC64A560FEEB804AB1F7F50E0BDAD0607261814C931A969B1BB0273F3C5074DB64BE166EBA87581B116ED51CEFECC0C71C4C6AA0B3DA77D6ADDA6E1A0AFE1A76268FA4A26D57580CD5D4782D8621539137B3BBA11E5FACCFC825B98213D5D8C1B35FAF374DBE77D8692BE0126CBFA41AF35660990DC1A2F00E3F12767AA17AD0E60198414E9F26A11E014AE42A2A954098887D4558194DB70A0EC08237E0F93F8938CC8941F2E2E16BE876A593755C3345B3AF0F3A73F8F29F30C52C0DE56440FC817FA51417669E065E8C88CC9A89FDA6E753877B29CCB1FC6572D3A433117386B8183091A2C81A9C6494566EA0458F1F8342AAAD63C123CCD7996937E61D7C656858D0EEC94D0E7E76886BC12C3AFD55F6478EAF3F85E67FBF74F7611A0942CC219EEBB1F7BC7E3900D89989B9ADA0C45DCED537165E5759754CE4CCD4FCC9E563B19419A82FF54A584D7AA921AB25F1275AB511759CAC8A83CEC9CAFFCC8436549599E8DD6E33D8F7D183A4C83EE650035C457982E9891EA4AACC291C4B0361E35E47298144A32F46CD377644AFC68117427FAF6B3AF79DD644812A9FEEBE3ED10DBF774EC0EEE327596D18AED5CD3A0020CE70C6AD17B0FD6138855A60B4160A27B7DC251B30F6BBBA7F11C018BC5713B6253346FB5F26B3A0969C43A1DBA6DFEA268B57D052128940B10EC4434B187A084731BD6EA3337104976C27DF51E28906C43532DE4EF2ED66BFF1FC9F6859F9D2316871FE7D65E1CDF22CA5B48E282A91C1E03BA4C75E176B3419F4C6DC4DD55B84C9449728AC7D3EC0C979C87D3A261032EFF105D1043DB0BF677E285C49B1962778153EBD432227ED98ACE9C22F2E739FB7BFF369140D7CBABE294C80F5C10E8EDBE23615936ADC1A77EA17362B86172F9ACE8FFC5830C7747D8B2C7BC303FAD5E93EA1FF847DCE5F5FB5CEDF942E261EF50AFA92A3C71BE1A304366BCD6D7AD5FB0D511A001A8267FF333C3C395B42EE6C21C8B69A687F52C4482214978567B859E726D61BFD25BC700881DB2D23071BEDD66A73D655001DD1A688AD64CC71C2D6CA50CBFB743F968E0DB102788DCB4F25E9E2C077E75D74176AAD5FEA5A9E7A359A9BCEB4A7D7D755FF229B037CDC4AE0D501393B114674A6605395D09E7A2E9CA06A04A9FB9ED08DAF41613D0E8BB7740470B891ADF721FC1903BA380C0890BEEF27876FEBD2C2840C98AFFD617EF63328DA36985F23401252119D5ECBC5BFEBA06DA5AD32E2DA63AE75433C118D2BAB735A12581DCB210A827700DCF4AA271B93295A29DAA094D08F8633BA363EE9AE2D350C24F3D93A0C0703580794AAF27BEEC4605FBD47094DD630F98D279992AE586C6BD7F8C5DB301262C18EB57AA8A426C202CE240F18CC439608EBC021567243B1089D2B6455419C4CDDE712A3F2A22AF82A4C3B6CBD59F3ACD285810D799A7CFB6DBA52F8A286EF98A9581F9E6CCC45F53C15953B233B25036210BF944350004240414733E9E0898490AE3339A1EA1D6661625D97D4E51045BE4982F0B9D30D602BD9740936E35068AC7BDFFCECD69D45DBD762813EB5E09AF0FE6519273879DB04901C5F770C7E1804E85C7FBA1F8944B2BBDC4056A404850F5B93E46128E899F3CF05E765C952003B622AE1126400B619EA6677384F05FA20010BC7BBE96B141E48C18FE57832CD679A763E620621F84B58BA7468798BBBEFADB4ED110EDCA05772DFC21D9B8C879C10227ED75D089F01085BD4CC69FB220DC98A8285895508D9076C23C035EBDFB0B37087ACF0E985F71E78DCC3E025BB53DF0C999083DFB60C380D885616B3C8C97E3EB3C01D206725C570FC93B800E06CA230CA966F80C30C474FBE2F29DCBCC53E172B37AE4EA45224E6A9F42820ED0CE81FC24ED29F162FB4631FB9DD28A1A6EAADE7F0C763058F30918936A483F5D53FB559A65B16A0FFC86BF216B88A989BDC1A610A85AFE515BC3CD9DC7A015B801AD91D0A7FC5687342EE82E7227D5B16C85D069F020F2EF65A16825F05CA8B4D3062B7E0872BD3C667D2BA6580A228BC3354B2FFC00547B62022AB9324FF5709A89E88469AE77625D659D9D8169D822B4FA7AC840581EFB2D722ED2525039B3A95D23374F1BDA2E3CC610821D84EF80FB6AD231106B83D2F7D52A77E96E691A8AFF59647C1A93DFFB7709A1F29C8C7C69B07D57D266CB92D4C6E1F8FE8EF8E089E1D377C2E13479E149C904B5ADEC434A8F9E6EBFE319B5372117BFD163CDD3399061768E9AA001DC63802246AC8A93C8AC2D1300D446EABBE532BBE090E640ADB2D2FA1338F740722E6A1A58EE3DCF9C6C174ABB2BEC11DD297BBAA99218AA7C0897DBA1BEB29E6203248C69ECFF00948D248DEA0FF6C38D5BDB5A42F77959DEA068C6D66EC92C9D0840D7E6F6CA31F6223319E5E5276A4EDC8DA908BC32FAB2FFCF757D1251829D1B02229AE196DBD593393B5A37B0407905D1DA1474B4C2456FDB979932EECDFECBD4F2161A234FE2484651EC1FD96580675A7A5B6D423FEEBEF489C4C0941E5CCAB4EC5C2505CF6111C2A040B488D8EF88E073D858D012E53E2F9AE2416F7834914C96BF3634D42E66FEF755B5B2E0B57361BE4BCADC37F573348C2833DC7B4F22A4CC40999979063A88A17E4E5DA276B629FE2F3BB0703E021BDA10BDF001595BB910CE4CAC7E6767F9F6A4BB75C2AC5DA78FE9C76297FF55882B71411DFB4767FCB6371B1144AB1DD8DB01658746573A39AEE2A48FF7D92FE7E477DC99E2500D493919429C98E88D8607285A4889330A9CB29706BDD11707DDF7011B78429EA301C95C19F4C7CB90F6F63E166F638E01A73E0C201A53F2D6E5537D989B195D66E2EB1B6D1AC0B001F1CE5CC6B85C9F8FACBE96B521833FD9513689F51DC95DCC7EF62E601B747C6CB49720E0D3ADACFCED939B14F89710D3A91154DE92CA744DD355E7C43BCF8C31AEC566E51C801C8210B7A22D08781DB28D12C54BF1622E440BCB6A4F7AF17B451EC88F721983AB44B257741FF2A4AC9B8FACF8F38E553F4B3204BEE0A851F82AF7B29D442370BD0A85F0F076D000EC2A9C44950EEBD17CA47C1411EAD65B739B647F94F4BFD642531CD996C346BE503F962EF22F8E446D8E4CC05ABCA24452995630F085A71B5BC9F7B816D48F7CF1AB81B0E8D8280BF38F43D10890AB111C6F9D7C36E1811CF7EDA5D26851F3C2B1153668298AA737D903B451909DE06013E888B3AE950E4EE3895FF7F30779A3E65796C9B582D20B75BF71287094D008D33868795271C4DD7B0ACBFFCDCE52BAF9A1A9E5152816199F5732E8FB9D75A4BCD5DE0F819FEBB005F7E095AA6CA9C7BE27D8108AA38B158BE32682F7E6F885706CF69BF3D06A08433CAF91D53F1E4566AE342F043C4F58858402AC0A8D6888D2C95C7B3FBCBA6CD18F909F80380933790239DEBC47338D0328D7747DE171AFE26BBA78B042DC5BB64592B73F62140834CA526361AC43D2A9982319D601673ADFF174930F93FEFFFD6BE517195B53CDCCA75F0F80D1824D8C87E395248ECCC77C707907250EF65CD7B9755CD520F7ADC3A3B3BE2031484FCB55F60EA3658FBC141DD895020AF3573168652658C2D712334DDB77A6815A854B934F07FC2C632D6C755F04957A88B746E9374F73B69B43D9703131B64F512F0426BC9003F3C8DF742C76CF37AA99F2FA1C1DFC1351F22811674D83FB637BDB9ECCDD34B451ADC359A6E02D11C5D1FE7EF7684E741917FFDAE08BA0746B57A2EF73729ABFE53716BB9D78B57031469CF411308BF44F7084B4249BD2D1A5340E7E9477D193F69CA259B1016BEAB3AE09A12254E0EE24E06FEAA0511B9D390AB7F5490E054A317825BC87849E44C9C4A8AB83CBA35BBEABBA900E74A8E9D60C2B00447679DB926823E3BF9DA5FBD8EC9F1E5BBC6A4F854E3318E95CD1C3AC9A782202810F3A5A9372AA803E1A887D8C284DAF2FCFD47D8A90F19FAA9D5C3AE83E2B4A905F06A75FEDF4C23EF70274AD87FBA0ECEA703E2B8C416EE01F97B96B0E566DE24633618B9B6617C9B2E12007EF055BA26CB750F6CF2E2758B8A0465F7ABE1BD5F3E18C1B381280A80A99EF542AAD7212488EDF20CFA1B32FBF9310FABB79D4F5FC6070275DCB8A3D0AB812AA08FA3F0BA1D3DE4CA70ABF666B48B1C69E55E5F0384E2AF9FA963CE604B731F7296C274FA5D6DFB82A71FE2F4A374892573C15417B84B3EBA1241D029EB47191EC7F2C05D75169B1DDD0F54FD17D28FD8852F7CCB3C375B34E11611E19E9E13DDA459EE03607B25545185B9F0FD399398022730AB3E2E444C54B950F40386E002F59957CF2B7869076B57E4951AFEA9A40771095CF57F4195CF790392ED9B115CAB95F9C0B3CF8E55264B36B83400A5E982A677893DC19DA1A466BCE155366ECA59A3C5164AE4B97471F6B0F6720B6A81B904FC2100A88F1AC5B453F3621EFE8D675DD7ECE7FA76AA798C50B75C8149DB8C4998472D01F4440A7F11D6611EA057D579F60D5BC87E5FCF72DDEF1D946D2041B041AA830493C23698A1B1D217064E8DDBE4558AF60579C9F3FD5F0F24AFFE1F3DB67DF260F07079A7903B91B97DB1C4F279AD7B49A6030E56BB73813B5BD119B56C9BCF862AF590F0D65D81BEF251C4C5995778BB2211F63EB1C24302B0DDA53EB3CD61E493C93FDA469208C6448CACE5E2A5A7C387080CDC625B0B0F3831B7775CECC36F564BA8CBF302FFBB06E6B918C6AEDDB6DA1DBBC3AF6C5D94DB49C0C6E5C36A02F0A2A4A7D324AE5A42F59446F9CE5B33E699B0049A4AE9912DDF4C1097F2B92565758834B388903ECC1719FD43F3A79C89AC9AD1D6E591BFB2BD731FA1FFC93549A37E6B6D5939FC95174D8D06B47BB1C2A718D875F18EC80DEC11D78874EB60A7197F0A1ABDC7CA84550410D2CD7F9133A3FFE05A7B194119C5E8FC5CEE88F9580CD8D99472A0D269384F7F0F394DD30D4D03009B1E957ED7D14D73F28C764739ECD4CF5438D1913926DA39D506C3ACEE4387A98E981C15FDDF132E93FEA8783096EABB4DE5D5644C81C514F5D78E7B558EF2F4EDCC0BE0B70204A7DC2743C4BF7E9D4D59C91AA363A52CF37487B55865E2D666133D36FE8609AF3F241F490A077E650DD9372F90E0DAEFC7D6565F8EE35E2F9AF31AC1965E52D76E5E101FDE8663E00F974F97C41C4B35CC1F539656BB6B1354C54F7E3CE9A4AD6B66D063BE3AAB0E97CDD98D08C20180728AFDD3BF4AEB45C93F47C766814F86ECE758BFE658ADC3B7549EEA103FA7D501B6E4A6D61424EE5F9855B3ACE33088D275BF8C373389E3A8F6331C152B7C9188DC01E3CF4EBD3A7C1E1E2AAEECD47A4966F8075350515D87D5B7344A54A98AF2769B220A2D520880D0FA91D8F99B6E97DE27FBEF951D9B4847A1479A7E725FCC22517A0E5F86E77923436A28F4932263B766E94C85FC8C32DAD49073441B4F63488143493225B8D88484C1B38F0684342D1FEC784BFA556B56F570C80213A3CEC1EE5F2B1C77C559BA9B4847291B55E427C47850782D5EF0BBA0D46C7C7C92650AD12E1135F728E154D48564287660300505494D8E0EA709F377AFD1A37B68E558CE1969EEEAD7AADE4B6136CF3910BD65FBD4A48C56B07F748FD1CB44EA8C7F2B204AFB030152EF4766CF500E8E7556CF5F3B9EF05E38298FFD52ED73D8E417605ECD5EB1E7DF13127BDEE8735F79EC28D4F39A4D46DCB19507013EED24E936DF169CFB69F882F10DA43673EEB29DCB316A636A0ED8261509479C7171A926DC871BB1836D4F87FB011AC621049C57D6D4F1A6D232B5B4B0DA8520DF25B479823A4E5A5B5D7F97DD31607CE049246F78CB841E82611130F4B1B66EC723661447D359AD24364D2C43A952625B7BA066A401E9C17635DA5633DA5F6B56C5578F7F5DC1B35B47E2484D98AFA95115CC99BFAEC46CD0AD1C93E345A95505FDC457DAAFD54C7770AC51D4BCE8D16FE55695DFFAD39A72F2926BF00159A5FE4BCF5E4E85E90D968E079B836CF39693F31628A9418420C9DF3CB28ACD980DA6D5FDCCFB9FC507AA02D982134F12C979B0AFFFE00409BB27D966D93FFBD4AD1391BA4AAF0098E368A198811BF6FE1FDCB286D41FB1D49EC9787BCBFF34A0231F23FAE67B1FBC4A29FE5A14F8716479BB2515A729351DAB3186FC8F959C7CC258446841A83EDEA929417EBE90FD74CDCF7284C3FFD0B38AA065D739E8E8DA79FB3AC26D4DF860F449639AFD91FA35E71EFDB7740F805DAE8CFD1BA9882E2EA4CF972192859FCE9EF349ED5CB014F2E1382F57290AEF2472B8B3B68E77970032F114FFB91295B9E6AF7C3D1779CDF89BE81149F6730499DCB6E2191402603139E05EDEB24267E96B044AA564C1A75C9B6EA377BC89B419D8BC1C3CD9258CD9E0813A2CE07E0F84C82CD9387908341C3FB3DD4948F652CA7A95B2061C7854FCAA23220D1A04A8BE7D6473F61CAF820DE92C784E1F7F7F848AD5ED7A1AF8B29ED6412B8C056660935BA5AE00DF3CB7CEF7C86B77347598B84FD2E3CF42B98938D83B8CBF4FDAE044A2075B6700FC3DA08F5BEF87E6442BEF3238A086283B7772ED2DEEFADED754796BE7D93DD5179A9B208569F8BA85E771A3A3BB5EE7E489BF2CCD893B9D575D30DE65869C8F8FD0EF2A27BBC400B08AB85023FB832AF1C4DA4206A6E5BCAEB2AFE2CCD5B5E1DC032135BA657C67E1D64FD67A4554833FC31616EDF94BF3F7FAD003DA2F850779CB88F463ADFFFC5B2D081EF8776A809653DE86FDE53E5E5FD0B9056BC116ACF059BA2CE9C6C730F9B956D28A20FD790762A08D3EEA6F44E5B3F6548142B3531B4D0731478D6F78CCCE3DEDF6437FC02750C94D963B2207B37A00303CF8EE47ADAD37C90E54E7255D831B37F86DE2C23EAEE2C301855B3DCEDB89A91C41AE0CFE08F788FAD9418E8E1B6A6E843643A894FEA392CF059761D27AD34D6F9A7FC7CB00D56432F36CFF99AA9DFCBFCA3722931C224AFDED8BA79150EE99D630EAF22FCA554DCF66310E3F63255F4E4E46A808EA488880AE2556A34E7483A5D44FCBB9F9CDCB332963D73CA0E4922F4C2DC286A65BE5AED0373C93656B91BE7541CFC6B4EC7D4124F2686F7754E3768BB817AF3C75CB94FD84E99F82CD36D9096178A1816309F93FD2AADE0CEFDA0CCA5360B180070C427A8C0BF79932D9E09D57656CBAC91F7544C8F3895A63BB06F3DE9F2F95731EFA199D8BF845922646D963FAAE28F3388C54F461758752851B1DC16DA34AAC34BF4DF2674101B078AC5F6D7D025804764502B1323DF9231DED8CA520BDD3FD6FD1F7C0976A7D148034EE26F89FEB8642C495F7678D464BDC5088ECD44DF062A51938FCC74221299325BC9B0394BC16679EB20021FAF35F199AEB37D4952B17A750CEDE425555225A603E88D0C2B1769BF5ECD0921B75223405B2C7D648CB31C7A35F3B613CE386E7D34214098FA4EDD8F017B476F759F9CB7CB1A319F995AD1BFD9CADC8C072F976544A78D9171FF65159009E499FF17BE7F427A978B89C41E83EACAAEE87CA7F15A7A6A6589D6072E415686D48F26B839F3216B666AC48B611447AABE07F163ADE27474DDA64BE9A259048E6D3DB0E2502E81096FA7E704FBCB03AEC1CBE3CAEEAF0C443758BBF6EE5403FF47854A0D3509E74725B863EA6FF387FACD5279B93F71D54530917B52B238EB2757EDD28D8551D7C353391D4912A80C5C180E97DFB32012725B32876A2322EC8A0EEABCF9D95F6385C1D90FDB366D87A807CA997B7FE011CFFAAA5BF72B659C2AEAAF42D41F1FF5F29CA4EE1718FC7A0C83CC6BD0A87025A643BC90D4D89557B9974B5B58B303EF7A67E1F78BE6292D22290FFE6E697630A07C95D0D48E27F689CC31717944B9FD6B059EE2D485DDA69891990724B28D69EB318D9ADDA35027845E0FF54C6D88011D5396944CD48E9D463D8322C464D8DE513157A5F4758821E9CB9C552CE83B7878F1AF58896ECA7DACD160AFC0F7BA79B7D284DD2DA2CC40CAC389DFF41CB2160CF594FFA57CE44307058F2107EDED2A2EF9705D3614622381A4470900BEBB3E3897D682742A610FCE545B9EF9736E84EAF5B2ACBD129122CBEF33EBC9E065A12D0E76DE2EA85AB04803C4998C94CEFC7F9BF813CA3F12E157CF1A29C5EE3B5CB875C8A025E35B89DB4CA047A591B92F89FB0D1404A69AE448F121B93636E15E0FD3BF2109D73FE2AFE5B0F8FB71A77065046010B7F25327ADE5DA4A427F9DC45753CE4CD47A3FBAA124DC345231F2DF051EC5BCD8248984F823FCB2755BA51A7C968CE43AE80B7752A4024DDF40BCD02A9356A68089311D803F0DC94F078E8F753AD61EC8BEBFD04E2C28DE67453559979D734AE786A86DD2F5F14DC9111CA0462AC03FAFEBE1E9C6AFC9CEADFAEECB6EFA936DF577EA88495E3B474CAF01698B6000424B55643F6C97D1105CFB264408974FF2BBBC3B453409BA50CB4A5EEF9D56507ECA2425A6E43F0AD735FEEDD4DFEDB0465A11BB937B09C53A3DDF2E2F96B9B2107BD6725E658380EB0A607F4B06C36FC4D970FDB5E1B4CB09C8ACE100D5AF9479FF835770C0146FDEEFF11BDF1B49DD3BF30E9FD35116E8DB91EDBC26EE7CF54EDD2B8CF13CCCB2799D3556835C394F34180B02A6D6188BDA246A16E3B8B013CDE9D5224E52A8DDB1A2EE6DC8BAA1BA6B24D9D552D2127BDBF86F89E435A3B50BEE39D7F311CAED0E3BB4AE256CD80A92B97BDAFFDDACC971168160290FE2535BC64E481CF6DEBFE84DC18513C2CF68FE149BB55BE56E511A3292E86C06C84F813FFD21039854621B3591DEF87B67EB75AF33ABC1F13CBD9CA7F831DD0FF7111C7A6800407EF75BBBC47E9C1B252A30DA70288EED0241B160C89116BCE99D542B68A40571FB8ABC07FBACC4083F11FDAB979072876D8054BC7AD5D4E92BBFBB0B5CB541FECC1489A01A046EB7F1D9C7622E15CABD7F286C15D8A70B61A1136E5805EF259AF09F62024C28DAAE315FF6922873DD62B4CC1BF1BFB9DD8A8F6B1F8A1FD94CBCC67C8E9CE5004EE5FE31100DE0B6829489C0A68ADFA9706B631EE80C4FF43D59513403E288CC3C0D897A1A6C3839B02FDB7591B3648C6BC1B6C1A49407398786A126A322B07B924B066D8F667F70AFFE002F24AC9B84EA1AB1FD887DC2EF1425A97DAA9581C6035EBFD84267DF3FE97AEA75D06C85DC1BBCDAF42199542B37A923688E8510B669E6FDA26C37DCD4D63428D474AA8FBBA0FA0222D58978E9570AD0969D39EDD9DAA10C75FA74BD2174BB2259120CAA3C080CDF0A0244AE1E9BA58D518CA437098E0D8B09CA51205AB2B6368F42DA54561E78B792D40289C836E97D28ABA06473F149069A40B2A26FE0671B25862CC0AE0FFB363CDD731A1F2DC4B444708110C611D9837B95DFB9EC9473E4F5AA1741803F8358C375807A6837D4F5C443417695AE89B6CEA7C9885A991AE0F0241169DBB6D7D4F7FAAAE159FFCBE00E857291C2A2CEBE97BC09A48A857C274ED171FFE2CB3A67F43A620F22CC09A861CD7CA12B59CA53654E0173F1CB41137C5C5D2DD4BA3C51A6D74F33DAA23DCAAE06727B121634FB6E84CEEFEE386B26C724A638A967A2A412B50A3860C523BF4CD0B303B0DFFD891CA0A1E9EF401EFB794E71AB045447096B2C1F0C2329D0DEE876E55C9C6FD92AE4AFCF86CE6C37FA313276283680B84987EB5FEAC952BBE591A3E78765FBBC5B43D0F02CA257325ECBFAD6AD59291EDB9860997D8C739BE7F5675915FBA46C9EB0D781015E8D05F19C40CC8D5670EAF1285AB9FDC1AE4AB7872B482B145653972E04876794743301EB63B4A004A7EA0E16CCDF1BE06454A01365C78EDE65969AEEF00A55DB063AB4E3D6FD75D07740D08CA64033F2CF8D7CBE6708306FFC42F2A912A87753EAAA7D7C4E6592C211B38FB8B317335B51902087D11FB8FAA58915AFD5D66F30890988C0D66042DB1ED36C5259E25521999A5669BF9B3E72C86F7B771C1A1F4976A6F9DFFA31AA2426A3B0B395AC88C6319E965A85034BF1BD2EA004361D5A584E02358966315601E93098EA4A66A88D8ECAE1FD374F7E6E011AF47AC3535B5C9C857E5B854C4E59BF26FF2BF7C3AB82EA2FD58E4919D7C5F15465BB26018D32F5A050C8DE29B1B9E82404BF05BA8BD909430E3C7F9BF88CBFD2B3D396B4312AB364274A84AAA0EF090CFDE39068CF03F24EC6B635BB0E177F38FC9119B69FFA68F2D3D55AFAA1BE58978CAEFE56FCEF4FFCD63E267FBB2AD8EB57756520EE72D325E81E7D60ADFEDCAFFDB4DAD9F274FB8FC5B37120035BB2A8F7BBEEDACED87BEB1C5B7A4C0BBE278CE7322B4EC203191AD3B7442D330186E2B03F87C86F70963B6F0B782EFEEA011A473F57B39063B3697CC1D9BC13FEF4C5B1F160084A27F87E46FA94E5A173B0F83C05FDADD6115378531CD1AC076AA909915C37E76CF6EDE023325664901F8DE7018A8ADDD9DAE8A3703C4B91C48F4053F9B6C9A53E6F824C1967D3DF814256DD7C49D7525844CCC7096379D073504891D2026D1D2226E4EF5BFBF856746534FF9179CF6E2F50B8525725EB7659B855A8899D23B6E56F4CFDEA1652EDA1EC99CD19A64E30ED4E1368363C765FEA6156AA2C83DC9BBE6ED01E45DD597B2385034E1B24E615E9B315C26B5A4A741EA9D1913B96E72E25982565C1525AF07EFA6DCF9ADC60EDA28E09757E213468EE7785D531E40572DF9113144C61708FF6282B5A6FC68DA42C6CF6D20A02C13423B20EF9AEC02D56BCE18E8BFB561D4964CC16CC8BD4926831F8B7CC16EF7C4ECF9BC5BABAEB82164DD6EF1661E02F9B4E85C8FDCCA9EC3FA11D00D7F6211C3467DE99D83603B5AFBD668CBF9FDCFB36F0A3B232B365561DC95E7DA845B5D5D2DDE0DED9480A8D91C4C0322DD8F0675770ACC5289C775EAFB637877E7E1F68BB81EC0C732143FA47E93FF84A4750799E81FDE1E78AB6B90E092B2FAB5EB9FFB71325DAD58E11EA6C22DCF8FBB5FDD4DD5E28CCD69F3B10C855A32FF2FEDAA8A7CFFB34A53ECDC5D414E00F0F52D2A482D2920062F9D35B9D7FB24FE64555CFBE6838AF84C3721B8899FFAAD7BD24AE952AF4CAE02DE36503DC188E4484F9B23A6AF91CC2813D028BBC9179698A17F9836D86E4430AC001F43EED3996D61CCBF153FB6EC8B93BE9BDD95051B66E8127B18D6AF71778EDA6607E156F389FFC292535687A3760ECECA1275C18A9C6B31BF535CAE9EB204D9B558876B45AB0CF02123FE2F798007CABCDC32FB6E87386144516AE56839F1B3CD06ABC0D7BF50BA4D73EBBA5788DF5BF4455B5142773E79131E79294ABE4B8C183AC3A4D6C2C5644FDFF33696F537F047D5F117A906D056E653BDDB865160BC5EABC8CD921A6C365F8EC08910A9E95905C30D1F3AAEFE9A8A98A5EA77E7AFCFCF814E52DF7D3752D3F6F9EC97F1BC73EEFF1A520CEAC600F28AC21D4945B675930AE8E7D128E9D52443FB81247BD48459830606C491935EC2BB8C107CF73DB6B97932B1CE6DD708CD0A50F998EBD64D59606B43752ABFDDBA41CBACC100F7570FB1D24B4BEC983C465D62AB7FB28F3A5C01C656A2E63BAA4C6664D0C6415B33B79A2E3D7CF95A578FCD417F9A32D8EB86FD83BE7FFF4ACAB27AD69A40115ABE5AA73E68F804A0C8E852CD5204F0EBA734D4211987D17BCB3A5B630FE7C6F6FF2BB2CBBF3A841AD999F05963BC300805EB54E87ED2A1DB623B9D2FA31D131F99D12A6A6688EFA1FEA79BC858CE99AFED336336518713AB6CE8DBAF3607E89E9CAE6C6B08E612F9BD59019784A2E78D272FF07C0E008DA363B7F71B2E020DA411BEBAB99BC5C9962E217850D460710A582239C5B9A80619BD320B39D38B4F4AAEA68858895B6E2B52659A20628CF830983A886CCC9C19DFF3F20F32E2817968C07DCD05F40FA15250D221ED6D315BA37941AE79EDBD6E0A233B463A6897A6B31A1C8F0761E02C65BA4B18B4A39B3B36BF47032DAF3C604E00DE84772AA409CB0BF8C36EB3087D8F7586DFD6167B8359F558C82C5E5F3F3B490F80FD9CEB7BDA1C35F8D6512F8E0A73B657632232A1DE987C77C403254DB208D5C48581FBAB324F8929AED326F8B20823052CF0085BC909105A780839057FE35A9B73223FC5C2A2F4F1FAAF4DF48B62301B8847D7A1C4ED64B49A99E7472FC0A2C736542B7D7A5C79EA05E2C21F8C87D22561652D9D416E469079E81633C9D865556A6C2A8400A0EDEB93B246007BCCE2CD4A2779A3EC743F8F71D99E37E2E0AAE9F7AE766A251D80AF6382DC0C7770BA493DD94ECB66AE2BCE876E2B914735FE7B93F14CC3055EAF03B27200ACC8BBA3DA46D3DCD53ADE8EC628BF34C4822C641AF1F751832CF76F62941E48B9E41F91973740B650D7F78FC2436779CF823EA186B16770E2122AD7EADE32CD8743E40A0D7C183BC9E155B9E253437C1B1C858FE8E06419983246BC955C2DF2BA8D91E80511CC0CDBD97B574400102B43B94DD4A883733AB0FCE8D14B86DAEE04C9B6E2B2D50374BAA2A31DF11B6EB644A1470D94B27E0A1C292D1E8EEC83D5523DB0F358E08336B56A85E11995B8FF99816F6F40EE599E125A0342F505F67E807CFD9D120A73BFEF5BFCAA1CBCEDBEA042F5647EFFEC750A1255497298F7E9E6DA076B07F85998E7C77D00312FC5395652EF55FE3443B26B2C3FEDF805A799922F517BEF8FAFBAFFA5AF09BD56A8A1C18F8D9CC7A56E758B66F93683CB724CA150E73DBE32702A94EA98C6D5CA238BF60CE845557FD668E5C049DB55FCCFE133018F42B3A418D0A36FBC8DBEDA9ECA91BFD497C93D82FE0CEB1FB8D84E41064FBF67A07B5FE078F3D8F4B9B74970927D6D41E23F87ADEE027278C7DF55D3A4663BF9C301A8D52D982687EFB9661E8B7A0D388AEAEA0FA4934D44C8DD344FE2CBA4E0EDE07D5F8579152198423839F9319EA07563ADCEABF7CC2499FA6988830350A5F118DA65F6170EF18FE8BF67FA9CF8161BB761CE89E3D851DF2987A4CD157FA20BD8C299FEF316C0B9D8AB2A8701C050A16616FB92C53C87D89ED5EC869C845B2DAADBD81B8CE4CB1ABBBD8A9137186075449274B66D477D8A11AD31D0FBC258114AEC5DF8A3B0CFA1A974B150D23E505FC4EB86908A48319981AA24450A4D2C6989C08DD422B55C4430F3EBC77F0A65C729410CD1B21020B4914239DDF91BD51AC11CCFB4BAE9B6ACE2CE72A2D8801BCC17CAE9822BA9D201DDA1A6989BD49D0CFCC7605EF6EC0FE501AACFEB05AFAEE4E787BAD1BC23E4181981B78871FFB462E4016CE616C5A475569118358F3665F2613B7337A64074EE2FC4DB5FBAAC55AE3AB9E6A9E809809BC98B48767EC74AD510A797A38B138504B1ECEB182D35E19C8A6063B57953F30D7844F8EA8AD4E02E88EC0F821A335BF98E847E5995FCA60A1108BD21D403759B3E90DC3E5D94F147B2D35B006E53BA78FEFE8C0977DC487F90C7824792348417ECAB20200C35250028E61DC4AFA98BF5C1EFFFF332A0A5736995CF6692AF19C30AAC7283A2A18470EBBBE8CF544DE957A0FE47F1B0667CFDD79450E3B15B91CA6B298581EA9B8CDFAFA206E9EA0C3F7C4076AC235D9EE74B988791581C2151A73527E5210507630C33F32F8B1F61ECE8735439D4FB53B33C08850159CBA2C3A50F629A757D521B44C54ACBD611A83AE05D961EB89158776B50EEBC804B6FD63A775AED1FF5A687BA0E3BCE0C489FFB34D5042B9F01561A88A2E825CB6D835BFD7212BFCB50A190A91015BEE7C60DD231CA87D31D038BC1A6D8627A661EC047B278800238FF65D0CF65D5BBEE9349F96F409A658914DF76AC4FF812FB5CA1B913F8E7D05BC5227719F88DB7C3F971E1C4359DB0E5479A026E64A421C81743BB244DDE94DE2DBE9C1BC10126155FB1335CF150CD2B1AAC2ADEB6F9F428AD5D39B9136BA15F6870E2395CFC25236ED436884ACC0C8ABCA7CDD1AEAF745076FB4F226645290D9E18BC23730A3CCCB55E6C60136ACBEBD11D6DC29E7CC5E10041B24C21ABFF4979AF1DA0407D5C1D4D64FC4D84F718DD961965D2E3E2387574265115D0EC37569E0F9258A53F27E0CF3693E1F9100D19BFF381D0A3042E17110EC2CA16CCF04F0126EE7576A864F51AB638FD491BD16F68D1BD6F2C8B38582C21783556D3B02487E98AC53AE9E2A43034A33953F6062487CCEF90AB6C8F445CB4DA01138880281FA153B0725084E6C564B5F518FC31ABD422D1D8A8560E7626FB37528C477A4895C46522EA4AA324E5891D94354A7E602656B0D948163601DA5093F59C4F408D0A2C3F181075696C68829B817CC6542268DFC023B7763CEBC23A9BA998CD3B01009DA7A30357EFF0FDC67802C41BAE18047F57745D7A8440A11284A7C4D16D90FD09C5183C39F980712F48C0697552FB09E8003F6AD8322D06811BBC9985C45B0F497C859FE4D318659E2F036416694E610BB6FFF653FD9B3C193B22F583C1512F877BC29666FD0C79F3461A3E613634129954423183303EF28EB5DBF69B9D552C3B9D6B82B3E03F65DCFB1612F3E557AA84519BCB8F5D2C9B99F299E38D09220F8DFD84DA3EE0FA400EFCE20E1B9D0D7130A13600192164A1ED67856CB84AA7CB9DFA763755522AF20367B4B3163B114802178F2F28A1FD35188FFB1588C4E14AF6F017C91CBAC66D5ABD409908BE4BD37EEFB2465CE55A5C72CE3D7AC4E690C47FE9D958FDF460A73B391921267DB24B2AD0D415DDDED29C13CD59070C0BDBFB4FBE745448A490C2809CC1980CACBA80DF93F8859AF5D15F54B76CCF4F43FF2B31152E0BC57D37E2EF7857CDDFF7CEC2352362D40D0F21B9EB2420E3C6692787339408B0C22CCE483AA926137C895FF19D63729D1478593EE58A7D85984F83D951534B24F8A3A5A233D19A7B8506AF11BDAF683FD027966382021AAF45CFC7CAFC7412B0061D1D3BF83F115B6E14B064E5240C551AD60636A666FF07465CF7779DA1E0C296F5E23E0284191072E3727E3E43BF402F48249B260913F2B8196FA74FB3FE078699DB1A10C2E56F05FD1DF5971813FE5AD0AF2ACE71E89AC4EB28FDFFC7C10F6CE87CDA89B27EB5EE8FF1AF3F7ADD0CF2C9CFBD5587E4D309C94B0333E9C1E8F15B4774E19315579272BFEDA64E4BF4AF2F5CBF61EF6B5D459C29915C4ADE3EA45BA5945943C2E4BE876051C1D3F734008815C277E54BC444FDC3A1E92EF6506239F7847042477EE6F0F1354DC6BF30F9AA97A8552987A1C0762E65D0096278B746EDF98330373FD1107269CD438D5B62D8688529137ABF2DA0115E286E2D1A52ACC8998D765ADAD5BC0317CBB7F28E56BE34D30F2100EDCFA541999CD1DDC3DCA3C9D0B3B285AE2D46F795B658A7A3136CD67BA34A4ECB53E5E11882300F29CB01085E609DAF536396B90E03AB3BA574C92713499619660DFB52F77360C1426ADC2C2E9B04F126530802155ECB858A15FD9BA290542B65505A2DF51ED1FDB6BADC3EF2C7C84A35A003E968D714ABEB5AE9634A0FCD9A36865A62F0132D71191CD19C728DC0455F4F26D7402D12175EC15CF19197D2B71663FE310BA55D0B9A2D1DB69B9BE049EE8FFD70553865A988ADF99921C6F523DA2D6F803A8517F992D295DD4F7C2B9F0933F2CE92E78CCAB3B197B13BE10E20312511AE5FAC9B8D6640C2A55011ECE2AED9AC4F36885F03918AA449856A186D4701AB2412D05D1A25251A42538020410809FE7427D9249BC403AD20B31E0B201B5CE994FCB1B3306B0A44277DA6C82998AE9C4BDDE92FF54A6BFC56C52BD62651205FADA153A2E83545720A6C4E2265FCCB918FE4AB9CDCB5E4C544CD9090C0C59B92808604149847C1FD6A8D411948023AA8A3E7B0531A238ED8E134B731EB933CE68F66CEEBD2008D00BAFD71A06EF9FD48457C514F686530DA332A928069CA692332FCC941F7ED410829D01948E2143F56ADA1B065994DA8FCD9F20ECC388F02FFABF3B4C2E1EF503EC22AADF699CBF71F1992FDDEE35EE87C9E51AC3E14E167BA9C9778A6FF2621EF7A4299B62EAA500C610A63F8909F0D9CCDFC5555AD51204DE0CE5F6AF836C90D3CD5A728BFB3BCA4FE32D9FCD7EB26BCCAB7171D5EF56EA7B4662CBDEB4CE18885BF3E8C2B7E48281765B81F9F6C555594FE5C7B69AAEDF1EE6BEF9310D669B4FAA37B95790BF5F8AA8ACCBEBED5C7B60DEDAB71066A0D2A12541B0DCACED5D91B5272AA65207D204968BCA60E31FA29ED7688C5920BD14C0F0F513E98911D417A38B9430BEDC9ECB2950C34A4B6D41B0D94A046ADA9B65883DA3E3E04AB2B9F3063ADCB0D96AF858F4C42F7B7D30B17B5658F591D5235B4DE698BE59F33180313924BED28E49D248C5FF817E79ADC04896B618A3BE9B3BAAF7CD4C4711347AA2295A342F7DFC76E3B275E692A00644CFAA854238AE9D2B4D624606992808678C64D285CD5406F26A6D5FAC25499A2AB9B48029A4235E6DDF7F7187B9DDC44FA400A9D341A2861A9ED86D01840286E605804CF50E38F682D2CF17059AC7D79FDEDFFDD7CAF6550C55378180FF26A0428F8E08A76A351A98CA049C0C829BCB468628DCA12378D8840CD89D0AA222A6A122C1C4EE165D5C1A4A76894C6178E6ECA35E2AB62856FDCC3B969693B0A7F9FA4AC9E1364383F4AB986E28C33188D5D9075F093F0EFBF874B0E0321704EA590736D5E5C09092D38385127A6E43A7DF52A6558A05AE365FA6133E3181AB3AD728A3BB9F2F06EBB477B9C5ED06E33D6531D0365FCB7250AF7D77943904B6B49D07009ED9AC32AA7FC7A213FB630DE7CE988420D6EEFC0E513469515FC8D26014464AA8AF471A8D8C8910EACEE17DA3330E3F3EB186BADD6CAC18EE2B5244DA0A18CFFC855190DCA6A1C94305A6B9D64E03B99F94E8B55921E4744B5979D417B42CB221B3B8A9FD4684D670218C02F9ADC665A487A3090B58D69CA8BE9008A5F6DD59769295E8F5A338B8337308CAA82247415102EABD911CAB80FFC50030691C0C86CEA43A3C1A8AAADA9257D9B4443C69E9153FC0F8D684F3E759DB751021E43F12FAB3535D5792163A64BC1EA2D026FA9D30C002556BA89174AEB2D413036C72BF4D0A8D4931E3A6813D6CE880D6054A015E457928456368B8026B1D26A95B42CDCA4F4E0D52AD8A68DA7F81C8D8EB1EAB56F26310C8CD7D9A6200C822361BA23934F4E6459A8D22885D292DAA6F0785932E32961CEA72B2A60BCA15A597016A18F9A157AAB30006B23A289CB4C5F69114ECEA184595AC571163DA40407D51A295B118C8A04DA789A11A18A59C9FC03A66B2A076E7DED8D06232415B0DA2869536D3C257CCCB0D9500AFADE43A55661D3007B7D6C406601EFFFD35D905A94372B251AF02540087506224CA5452BC5421A7BEE9E014398BA834B03B8316388B8BC39EF5E50CC98B89F3057A0D6899E93957F89F6ADDC6023AB66E6C32CB18EE3DCAFEF9B42E5F49FFE3F37AA8627445C426A1157D7707741BDCACFC7B5A9B728683B5F146DFE0A4AA398ED3845150AC3C0A4AC35D9A202EA173B6B76BABA69BBF4B7A165D77E051347DA379C779995B66A7AA903E968119C7273FEC414C11B5DEA19CCF2777116DB443D57BE0CB97D64A3CDE6654DE71D3FB4AB8B7EE56A1B70D6C8B50B358F4E940A3B7CC50CFFE25F3B79139FFB5DDADDA383965A243188216683A5E41CB3E8A4808A09B0D2BDE8542698A55A97572D8954082FC30B262A891D19F007CB69A501C61B7FA33AA2FB8C6BB858F140C30F48D4C9BFA61F852354BCF52AEF1F3D175216CD1F8BF71F2C73E92252CC72450B693DC495DE6F96DF1CC6B527C67C6E30165CD8C8EA63801BDCBF834A58A6A6FA328F234DD4B43BAB88F95C431BC37ACEC669CD53786E6B66967EAB7061608495DBCD547C4DB12D0C98E3E60D4E535E70C351552181A3425F538C8071A71E06BE26B22BFEA40CB583671A8154CFE8603EF47FB34F680BABEF41BE20C7E391DE94649E0F7F01472130E9EA8FBF98C3CA2CF0AC4AFC08D7F729FE836C17D9BA5D05676CCA17615665AA5C3A78DD6EB9F29EA6EF3B7F227312833DE20D4F6AC9D559D72330CF93DE0406A8FE5102286C16979E3C7D8C0936841E78B56A8AD7B2FE629AACFC96FF5680AC6978668C198D469D6A196ACBE7F3A8BC69FF64BF90BF14A967F29699995D71EDB29961C2BD7D67462349A7A20370494F38D498DB42619D48DEA1B4BD1921B7B6E913E9721AE813E4B997E4F426FDA88C4A74A938E47EF6CA147F34AF6A295CB4D3459DC19B36D3C65DA87CEE6B8FEC2ADFBB32EBFF604F2E930CC0FEE84C233CCD454FC7C810A132DFC0A86927EA7FFCFDBF1FE50328599891ADCF661DDCB5418FE3CD161486FDF993203034B64895E4B22CF3224560022627349A53C6AFF769036C0136F0F123CE4C583FEF2B06739F644E0165BCE9C24FD5054391634993390746D5A3501C43DF6C8F0D0DE94B5D9B68FDD25345333BE0C6312B6D3AEA864A1515419B26366DC173E3A6A291ECEE8B569F13C481AD179AD58C8094FCF7994ACFD1AA7519F92346754ECF6E79175393E2E6B90D1FFC448AD3B94463FC0E2FF7EFBBF614C248FF6504EEC474BAC30A92582E38032C1E81BFC941245F725769133F6558EBD6C6FD911F39A44C5AAB178B8B5CA54E46CA9B3A90996511829FA3D98BF9108E2190DCD7720671D04F4A519B2227C5894355D29BA6BFE5FCEF04602B7EF18319B932F1916DB7CABFD06F967570DB01DC633ACB4DF31623FA30232E393D426238F12746437CA8D539084A1988396B7FCD89179D3E85A8A9A0104F40787AF582180E00322E5C1BCFF0659AE2BCF6CBF9447E66AC4530AACDB9E45021D9D460C12007E933026EC4582EF046FA1546C99BC1D2E27EAAF477331F7053E41F4D84FCC05DFF833CAEAF407DBF05B02FC4DCA51E7EAD9CAB2ACD23D88D1CBB5074436A827A5C6F84ABEE124E6BC66B32A45F8B031BDF82BB99D4378BB6EA97337EB96B2C390472AE6DE50DD3A910F7D1C21F7C11237CC04B1E0A860EE48B64AAB182812255B650740A45EFB7864AFA716AA3E1CDE5F5EF8313B746F31BFC785A656872534D58E76F597914BB1469744E8B6BA675A6ED6016700391DD30B200D39C0A264C4B59A2AE9596E091E1AEE95FBE2AD06AF076488ADF8C54A4C054B21BE8E156435C11796974A83E4792C42CD6C1D8FEE681F2DA7B45B3E4D85870FBF7FB007220C4241FA08105EC96C2E5B6B63065F50ADC15B2A18707D16C415AC779053978BE2702271D30758D0DB993421BC69F21471794AA64EA31F0651D20AC4671156E121B3297CF6B719710FC5ED7FC3008388DDE3D8B2CAE761D8F8B5B4F4BFB2940A48144C0D35176BB30F9168C4F19FF3901E00ED29F8CBFA7D8C3ED97BCE9D8DBB500449FBCCE9EBBA8906FC3660D428E09D36866B6111520D0D4165AC64BA575D228845E0DF2FBC4682354F4D53D4670A8D4CDBD27B69DA5057EB83B41E3A71CC8F169CC41EB32A24B6335130DDD892009F58015C639690D2DA3952221F702D477FFA8B5F5219ECD7ABDCB9B4678330CD2C085DC5CFD5CF0B43150BD4210EBEDF1B8DD3DE5C41B2FBC44FE4BFB3F54D33A914768DB77C479B599D0B024E7F0E76B5A2D12B9FB20801248A9BC5601F79E106F53A2167AD564F737E3BBE80B3AD1B9E448A215963700EA5984521BED89719F886DFD4CF4F2DCB50437822D1ACCA57552A25CCD069D52B860DB1173009E88A84BF22B7E3287CF806F67FBADCBB21FA5B3D880AF9BC68C3589724977E2AE76E42BE0834638A596C2C430EB377F5085C4B29A1D8E84D38FCB0FBED3F0BAB3A9DB86C10754FC4F46DA83EA2ABCD5311CEED61061483A6DFFAD1C931E389E8DEF942B0CBCC26DA0A95A3F02D0D3AC955C154AFDBF8F02680AD2C987297F881E6D9E36A32C9CBE002AA65AC04A1E5DDF1137376E021ACA44FD458959EB5A5B2209EFE7D236A9DD43CB35427442075C973271B4C58BA5442567D0471E83B9CA53A05DE1242D7824D7A424E22B2FF9D368935C0F3E04D164A2FE2D3A547F4D1B4AB2789C6F72FA55E7FC4189BBCBDADF84B3800A16BE2A095EB5B579C21320CDBE2DBD527D4F2462CA202F8C1DBC008259FD1514A3E8B10AC24D3FDB5256928FFC697726182BBF3B4663827044FFABF71A207707FFEC7CB53C5BCC336EAABD11DB3818443E7F7D1E2A182542B58D6BDA987F4FB73B20EC47E9FE2D3F4616DCE400B124C65EF2976D647C34ABEBF6E59F213C65FD4FBCE2C0AA164C100E0094DC3DE8D956B34BFF2A41FE8DC0250C40F79488DA7F4B36C44F1C531F8BCFFB0028B5EED4B2FB0F5B12DA68FEEE2DEFE9B5E347D9F2DDDC626050F0C4B638D68EC0AD9D8E4EB86885734BD590B7F6747C51AFFD172296C691383A169F5ECA2320AB66B353632B031C038909ED114BB09D91EFDF86A35FE657155C85AA5862F0FF9A73CC41BDE607AD8BDB48676045A03F93668683B32C6502E2AEE10C8EC2D7F31BD8B8DFD8B7822EC1535B263C1A03B087DFF19C3C3570679CF1C27284649FDEBFA8029C78DFE0574AAECAA78A40333AE01AA7F88CD1D030E89F25CF3B279DC9D215ED9D8B73C9D5D35CB759D803B57C7056B8DA6D1035B6FB09C8E34A26C41C78BF153DAF6C9B0793190AB549B36F79C371EC2BAA9845906790FC1D2532332DC50536FD41D1127A6A48A9F92221BC021B5577259E90C79AEF578A8FABEBA1121389416F4D689367E7753DE4A27895096F3BD9D00F7708A6AA5075A85F63A77B3B6878D3FBAD7291A3815F578EB3656C97253CA4C0333DBD5DD9339E9616E08ED4C60D347FE3B56C228E03C0E72297D4F34F79960E82AFFFD445C9F2976031B65B2F116AA39030351B3F2BBC04B9D1D4EFE14F8B3F912C9A9281B2788F1696E0CDA6094EAD3139B4198E7235F793F076099C01DC2C74E2DFF4CF5530643998D983EAF457E69373095F58A4928BCCDB0E960DD5CFBEEB772AF195EB9EF41FB6966CE24BA95C3F352A9922A31001F0537E83FF2B59582199F41C43D73098EC637744932BB78D40F461F5E3E56BCE370534839EF82429B44AD9B9D63818156C3F3D064A4E9F174CFC27FE2CBDC1C974E92F36F7B69FCAFA376621C87095FF01B7AA7CC0F3640960E1B2F20A821C8813CEE72E9CC8CBF89F0028443A130D92AB5158F1F7BD472E2CB91FAC2184DE0D5921CCA39A5ADDCD301EDAC42367A1E8204F5434B06963680BC9393CD233C8CD637DA59BFFC2C33AE918F6FD7AEFD5FD0B20D56D8909BE3F6298A208F8E8DA5ADBD16F1DC9AFB1C0409DA4A918525A2026C586FE1CB88DC19EFE04874391FF206502F685A98FEE7AE39B9132051A55DA8D889B94B8C2009B2045655BDDC6C5CB5F93FE7552FD3285323394A7F36A0AB48A695F903D64665FB93515DA159F6268EC181F83B72A0D573D3BC7772724A950204B2E33D8B1B1EBF01F6285062EE0EAD4A8587CC59641187BFD5DDBC1EE3E1B464F96E357CF7C6F4DAAA235982DE36C7EE8E71A243E7DE61282C4BD8408865F55A3D44893208EF1E8109AE77B5D2E78B6A05BD29C84008F9F4BCF9A9AC50ED9704C474EE49D2CEFDED9E554141944815752F21F6AB3BF6A23267E36B08353B8D21D92A9131E8BCAFE4A4C9283BE1E23547572162B30D0D00D884A61609F1E5809E83EE3E85348BB5DF1BD3C49492D2D8A1B8D91AEFBDB143E40C65917ABB436EDEABA5C2455F647F1EA962E81D114FBB7650E47AD73038759C3F1AFF0C0F356706EEFC82CC5174AC57D6302E8E871C1435AF8B8F75FFED40FF4F45008BBFF197EB0B4E0F1FCF58E3028C1E85876435CB5B658E2E60DBC20B6AF3EC8711302EF84D362A6458D6AD51B1A0974C177B1D521557EEA77F2DE0EB1F03A14C757F4D12BC3D676856CEE89166D029E0A0B7043D0C4946F26C9E11926FF3C6213170D24994364CF05BF9A39E154B598B5A1EC67B8097D02AE88265F7E49B49AF0741A899B2EE76CE78199ACAA9504FC5011979533DCD1E957F600169E6B287C7616055582446F4B8BCC3BF2110B28EAFA5B8170CD94ACFF9E019D0E649C3A2B6E040540F819A9309E2FBE98F3487E1FD464DD467F9B7D607A75FF3DB92747DDA3233BE4FE0D588476D4CC67A0E97451E84FA29CD43736D2FDD7CE604BE24F6DF6E8F42E867418669798A2DDB53700A3DB9E2979971A881E75EFDA33D65D6AB6C30EC79665A4E1899035CCC1BAB0B5F343043C7BA9B268CE05A3DBE4508829D3678A989A2F328E47F2EE407D5EFF255A47843FE4045E8FF06154F5FE032F276DF3CBE82806A3496C6731D193C8F1A7C11CC15170497780F5E2981CBEE700C36B24799B0F45F162D15927BA23A5908ED25345609A1A560CE3916EF2748D7F210B05DE2D2F3AB02FABF42B3097A0729F736B2B6FA440AFC0ACD9D94122640BB0158ED0F678BAECB781F4ACCCCF222728FEE5F6571AB4872F5B3AE70DBBE37DFF749D5BCF4546BC18FB393B58C3D951BCD18862C3DA23FBFBCFBCF459E2DE1B91AFA4C715867A56C09FFB9E162538AC9E76F92F8CE90D424D37CFEB2E7007772F97394A759E01C762B87BC03BF39CF03122989B51CC792F118A7372E7E3D723C7B3DBE566CE02290FAF121B0220AC666B6870D4B49B18111639BE8D3727998AB034CECED6474347F4F37A85FB15D3855BB31BBE777363090E226166FECA33F3ACE5719FBD2D7C721531B3C9FF596346C22F7A8F80DD5FD20AEDC6CBBA51E80A9FCC9124EEAB027D85FF5F4AA085A75EE68D3CA8D8A736FF32624BE131D77F29525A70E15508DCAD46DBFE812D968364F8FBE890DBBCEA52058EE2B1E14546C24F214D0E007D220EDE52641ADC68B152742839ED0C3EC42BB36FCEF2FD5DF9FD006925B75E26721E65FCF31E4CF1D73D73DF408550D4776D2DEABA029DA830EE1D5FD4CEB504FF5A57EB5B78FC42BD45669CBD3A7FA9C1059B8DE2746CEEE5B8602074F5C890581E017FA3438D6515B6E7DC2C632FFFD6AD735276D686ABED1877FDB482ADED153FF798F8DB49C2C1CDD37FDDC2A40E9E7EDE6DC9C42029E2A4C53D9E5A5E86ACF9BD09CA0052E522F77801ECE49F28B60222FF85B4F7D57EE46FAA0EBEF932BB7F9E22D20EF4B7327F8F4148190405FEABCF4E46E636EC22DBEEE9A7FFBF33C8EEA4384B3A4CE85173EB6A7D98376501203DA5304117E099EAA549D610291831630B3189ABE08931467E0A3A47D00EC5703EF7B01BF116705B7B358A1EBA405B07DA6C0D906E70607330E80A9026A8260E320BB8AB3801E2BE5B4BB319CDD775DA2841096D2FBB5B17B07AB0103A1A7543B560EE9C6C076236A852DCF3F8F785A371E35E85ADD22510E6A3F0F90450589190DD805CEF9C0DB14CB8C00103807B418C217EDAE586BACB21B56E4F54AE6C862A44AED86809FF987BAAB9621E7BDBE0FE95DA41FC9BACB01630095C9B6B9FBE879D5DE7E9B7A818D9BDD0218F65162E6036ED0391000F55C578C7747CEE5DFFD0092F12F56A2553521D3A93330B64076E76E4604B05DC5166748A4F3B185A4BAD72474E0964DD1A915E6D4DF8396E7F278084077EB899C448E38A0FB0DD966EBF80F6DD2E9F17CF479AC4D4BC33E81D0DC21116CBE49230BA6815B766C5AF3EDFDEE18E0ECA88ACF077981C247C4A5539D22C21C5E98C2970D64E45E9AE700EAF5EFC2DDDF9ABED54C3FBAC5D5AC02C914C4BDCD1416DD435AB7DD71D7DF3C250F0D5D8E6A2FDCF4D8AA16358678A70BA789D470346C909DD9712F9FBF276309D82E5BD95BCCF8CE91626FEA7521AC816AAE221CFBDC56EF7CE1413F214D249DF299DE3A7F883AF55CE397BC04B811F2BAD5D791A5CDD4ED3DC23D5761C68F01CFDF17A840A437FFB6A417C0D07286DC28AF8BD84B688C65E1A76A3E8B3D337F6943B823507B92B00F74183AEEA36A38929DD2AE9DF24DD4C669F406416FC0EDAEEEEEA360FEB267D480ADCFC7C3084010D98D247739AE0ACDA57B1FD89307F1A0EA5ADA34E59412B227652A93A8FC94D010DFA06C97B09BCA1F29873A56390BE1B04A5681D74B5BC382DFEAEFCC3B95FBAF3A4B8F6FB55E12188375843758979A99DB8B4529421DC5634B828CA7322842E6DCBECBC1EFBEFFC3ABF4477FE71D3CD22C573211CB0AC1DF49A983AC5B507863254FE2388BFE49533739BEA15DCFD2F5422BEB1D40874079C3A069A4788DA929076DFF22EB29C0E5CF43987962378D3B71C5E7ECF2C4B5F1E7BF5372E7993EE044A46FA93E2C3D1F530FB8CCB129AB7F39E016666FF8B38DA45257176A7A536A22DA3D8BE8FA97803372A4DA3BCF6D1A21C700A522566543A7C83F5AAA1E1180B228F407515261000FEEED05BD92BEEFACC1ADD500C6802995161FBBB7845DF01450910E7EEACD06DCC06D3502EEEBD30CAA5E3EFD0D5B0158635280E2C3F01859279F81F9550E125F9E7C70ABCDB02C0F34A9AA2C4DAC2C63541BAE165E41E5DF0CB3D9F3B7257BF59496BABC46B7D7C5F5FB3DE4AEB20779B656A86C0FE57C30A9FEDB1AAC2973F322F0A77D2F435E027FA586217F139A69C629B731723E1AFFECF51882B5FCE43A9789322FE8591A3D516E24F21CA76F4BFCD86BCD7C3791675E1B8BF50FEBC4F6FC1A26BA01291CE9932AAB2490FEDAB00F43A565653FE1F46EF584CF06A96F52BFFC2C5691A7EEFC36121B2E2EF4317FE3409A25E25120A9F628EC9DEB052F9C2A5AF297DD97C9645570E862CF4C0F23B410702B3916015D090897F02DD1872B0A53F0A2CB2BFF928EDE23813D06E3794D477CA67900987B071491FEE2D0BDCD15BFDC5668D6302D9FAFEB7BE8278538923A7A3A405E04F6D64D48DC3C04B3980C68F0AB0776A339345A7E1AD2F0C5D7E7DD6CFD0BFB621FFA35BA7F584DA577ECFADD5D2141F139C5E572C42BA3FEA268EF27421280E9D1CA9BFD77966177B700DB2492B8F35209356D1E32F76CA8D6B8F648059A791EEA2AAB795E301A5514EDA86A0B6CF8A3CBC2F6EB03971F26E0929E67733FE2CF667FE067B93218BC6A3F59C6D86A3F7A377B146F64BEE1BF579167ECFF898385003B1F850A43DD0BC75583DC96B97F35CB4D57CF7A90B80B90134375499D2A5C969154C3DE59A9D75C847E1FCDF81DF487A03161F62D7AD9282AB8B849799D41F60B73D75803A8D926F709DAFE85E851B6C1966758168B5837120009D5F3CC7F7CAB632F1E587EBC16D77BF2BA624E6268FEC51CB2996FFB3FC1ECA7C273047021764EF715A74A370F1470004CD67D5C8EBB0E62D40D844DE18D5712FA9ACBFBA95D639743069B26467763B0905089F1E3B94F2C1A1E9F8C65AA994BF76E9824D764DB1861668CD82E9B3335DCDBE190FF513277145900E0DBFE9E33F9E48CEDC0532FD9D4CB47F6DD5E103DF4364A9513DD3EC571B3D0046213ABEEE114FA4CF37D478A09CEED3534F75F33E9A1351101AC31A9610D5D7815C3C39A36A89F7A8BCE1D82FB36259C8E440BB968FEE57A770802BB79E0DE1AA30FB853DB0372A7576408A59327031B35075D548E5D2AD268E9CE166A1EDFE127CCCF83FBFCDE5F0FFB247B7D88EAC4D7CD72F977BFB2CB5231F4F04395251B19144FCD4BE04B4A6D9EEFC09DF50B4B73C0BC584E9AB0DA9EA0B37B9ED2DFEADF25C451672D43834FBA5F16F36F8C37EE98AB21D4D1DFDEDA3C69C031F972413185DA23A357645EA056EDA4838E654DF6762A47A0809E8007B912E3B5CAC2CCF5AF0EA93B3E715754D3F3E6A38BE8D04BCDB530A697382E9D36A72504F04F1AB5E8391D48EA83AF0FA02680F6277D661458A8AA8081AF7F27F8BDB7DCCB3D0010FDC39B9A2A19AFCC1D7E8B48D7474179DE2D6BA153C911D212DD60F9A27B309EBBCDC94141D703AFAE40532B8ED5133588D59AF0C5C76899AF2FF358C6461BE1BCC8E5E15F400A9D28D64621AE8D8A8ECBDD2F7ECD29F445362900D4F779554BF4AA751E7704E43E8D953489E7B5AAF8A7566FBD248E56C9FB7FCF13550458A453544254C9A8183E875CDF5E447C09468BEAAFFFCFB876F41A71E83040AB4A6BB4A2A39B39CF811405E2E4744C763162A15A841CF0A06D3BA494CD70DC878FE8273C8A13E654DAF00F1228103F7A06CD2BAC062E3B65535A63CA0039C22E977D698109B8E70D9C486686F0AC0C94B03E92845DAAC84CC54F2BDAA985C7B6F6B3FB5917367E268209A1C89BC3C4CB57F09E9BFFCFB34577FE977C4291FA461F8B50AEF62EEB8ECB553CE696A987BC8466AFEEDF026E6F3752625373BC5D9043E45B6F3F7E0F89BBC6E60454311812D5A365B26B7CA053B3BB65113DD635CCFDB557F3BC6EC18407506EAC924CDE9D33CD7F08A71E05366BFC8F2EEB18BC59D63656843F617A8F1BC2346C7C49E27F031C2992713ABF404EF262E9066AEF432871725BA72F953F9FAB398C47814CD36009EEDC62944D29A576175D0C1470D62AE375037BE7D88FCF6817EB2CB44BAD808A50CDC5C7A4FF01BD734130134FC66D47C7F1A01CF8281B5417977484B30A4164963CA7685B21140FF3C1E019D108CC5C8F28E7B552F42018197F7FA6AD28982C7F12D03F52969D4FA3E6D3542F41F667D8C7BB581400B3D1CC2265DD1AF3C719700F9176F1283DA3E91B7DAB6300A8899048B48E6C160226E19B6B893AB96918C855F3B5D567A9785619EF0943E28F49322F7407F49ABD798BFA18AAB896A224E12EBA24FD47A251054A7AB7AF1E507C54AADCD1F0019BDD20C87CC5BC41DA28833922C12D8BBBD047B11D9118871D611D894A6D78E7523720402F283B13353482A0B6E386A45860E84F55B0B3AADD928ABE77E9C2E6C12E4A14F35800657BC169C8CEFF94EE4CDC99C9929790873B5D41CBC9590C69140B76F7E78D2812809026E6380BB1C7C13670BBC883820621942507F2EDBDDB1CB6F439AA6143123425CF44F70433D16801A6CA985BDE87B53D16101E7CB58ED4B5B63F2D9F695EE850BBAC5C9936905EA35C8ED1B03397E6DB1936CE273CC5914AE579C4127BE25BB377F87C3A91B0DF103BB7A51C22A6180686C2932EE012761BA21AE169E96A11409FACD89127A46BF4AF83B8125C07CB00700FD05F857A1F20AEAB5345B01EAEE9838C0547BCC2A1BE6B0EC840083CB38CBBF6E8812103289BB16ABB0F5A8F929BB7276D2A3A0DCC209F1EBA066DA9CCF37663109E831C9C43D0AFCA42BCC1B434A9DB4F02EDBE49B5B6EA2ABA480B9F2DF09F7F9AFACE2B98EAEC280B6BBD9EA2A2F7BBD616E7B6A0E242FF45912EAEC0898263EBDCC94948EF5D387F12872BE99141DA688CD0AFB94563CEF97542899F0E383CAA94ECECE647D9710861FD0A04F5934E02F56ECC54031FEA7D971BA44189970683878728C321174F4E3B172B527AC74B4B9DC75EEE0E67E4D5A9E3BB5AECA39A277F6F1B4670A8BFED998B57FBEFF2FED1F6571812D6D4B80C63E60A7FD650083751E5FC208B4E9C66FA4C52CC58B6E6364BF65F1D3043C50529C391EB25BCE6ED0BCC98C59DD5A365276EE1CBF25E740311BD6E123B6E2AA34B1EDFFAB07744042A81C3EE0FFC41A9137C5A9D63402F604B1D56E2DA004772AF40FB73E2170A6CDF81AA0011BE2410ACB24EF9E4518EC46260D31B5FDE5F65684704549332BAA108945D957137034BE84F9E8A8DBBF1067C4BAA0A7618CC803BCB15C3D3EC322BCF3EF6D6211BDE575486F236017D3F97594EC625E9F1EFF6E0A49FBDDA9AB79C1AAA512C1C08040241EA2B9863017D1D9796B4169F7AE9B9852084E95D29F0DC090F304F83B6F23C70B5A98E3304DCD20E74FEFA9494B3B80BA6D79972CA8CFDC21978B0C9098541FDD38F33CC66F189433F83AB562FA63AEB4480D73F7063EC5D70E84E0325A065B6CD3B61EF4442F5FE4B44FC6F81664BFDFBEEF30F30C0B6DFF38075DBBD1DF5C97917CDE4072C46D7636FCA2EE9F7492C1BA7E59992240E44B4480EB6C5317F4EE6CFD9761DFB9AECD7D94EA8D7D21E1AEAA9A948FFDBE720CFAB7319BC1BF35639712EE9AC03E45B8EB2EF07BB5CAEEDD21F3F987F18EB7F81A3AE5620706D042FC7DFA4C21A7BDD42A94EE89A40D75C6F6C0C58A04D284AE362D2294954AD0CB81FE31F819FCEA901293978993B5A0E40BB449A3E75199021768FE543F0C2C89ACEAFAA8150F80AD10846242A13B07DB0E8C716D9B62C455168CBC064E0FC7FCD5FCA7C22187A2705378E48C5F4F2F6386B1F0B0151997CC243CD160B0FD29B3DD22CB7D0DE4B64FCA97E81D17206D2D311CB30192A41A781596346059F6E6E1EA2A79443EED34E6C3BDA0C41E0E218C7C8220040A84AEBAEDD30FB1872486512CFCD31A7B2F8C892958B3503557A29C5B7E3B9B660068A7AB68B8759366456B51B1F09A4BC7097590A0227EF3F5A866087A1715ABE8C3ADCD36114348DBF001F65569A69EB5BA58B52DC7BB95CE566F6AE5008F22EDE8A2827906804B96BEFB6FEDCE65AA2D90A46670FD381AEA96AEC488DA9CDAE7A4B1B478C47740789376369E2871DD1FB51AF1962759EBC28350F0089181224C6E5CF0EAFDE66DC4C48131AB4C0FB39E3A81E9E4521F09B232F9B95A93DC517E37E17904E43196029D40C7C0382F0869B40D1483C4B95EE44746E0086462A6FED0ABD85EFFC5DD339B77F0A30B4E99B6B930FE33D9C50F346784F8CBE563BA54329435045E77D211A8117F0C08357B3CF23EA679230FCD6AD3E9926CBCA4288B3584FD539DF80C120DC76FC37644843D8720180058D3BA143DBA3E788C951A35C5A8D96F3EA4C936E6C4BF3D156D5CD621330A58007F345569D8CCE6E75EC8634266A83D1272262C610FA7E2E68379358F64766511D736779ACBF6F8AF05DAD8530C8DDBA50D37FE2893E58EC7F75680435732AAFA5251DA0BCFA4CE016C0846330A753A4882B7679C2E3D0FF0F8E07141E829D35BB73151E4E1A289673A54793390EF2E16FE3A5DE707F3EC4CBDDBDED8283D4C3B9548ACBEF80B53A296D46A4656973FF5C7807287C341048F3158E1C8EFCCE4B2425B52FDE2B07D43919C907884403523FA6D78C51D2813F35365D837E8338263B8F8C523AA67026A555DCDA6DCABA1DF37E3AE15280D24BC31A10054F8E9E07E94F35A47E3ECD416576322F2B035FF1A597554CBE5D39CAE95BBE001, afterDelayedMessagesRead=1204358, gasRefunder=0xe64a54E2533Fd126C2E452c5fAb544d80E2E4eb5, prevMessageCount=131723790, newMessageCount=131723877 )TransparentUpgradeableProxy.STATICCALL( )-
Bridge.DELEGATECALL( )
-
TransparentUpgradeableProxy.86598a56( )-
Bridge.enqueueSequencerMessage( dataHash=67D81C2B05E0A9E4648C6844357A2808853F8FA087AE9B93CEC37F1ACF71A72C, afterDelayedMessagesRead=1204358, prevMessageCount=131723790, newMessageCount=131723877 ) => ( seqMessageIndex=419313, beforeAcc=18757DEC8C941207C7348AC525F3B577BDE75B9810BD24270BEF539284CB251A, delayedAcc=30BA334CA38F125F23C64ACBE2E94EDECC9BAB3D47A291945C7FE4968D3956D7, acc=C2A6E7890DAFAC5B56E7609281F5848CD8870C28BD0D2B313E2A4A17303D419E )
-
TransparentUpgradeableProxy.7a88b107( )-
Bridge.submitBatchSpendingReport( sender=0xC1b634853Cb333D3aD8663715b08f41A3Aec47cc, messageDataHash=4A168165D783A7CE1EC3FF9564227A45EA240C43C36F93CB6CAECB9BA3EA5CAF ) => ( 1204390 )
-
GasRefunder.onGasSpent( refundee=0xC1b634853Cb333D3aD8663715b08f41A3Aec47cc, gasUsed=208648, calldataSize=99524 ) => ( success=True )- ETH 0.034784340440011965
Arbitrum: Batch Submitter.CALL( )
- ETH 0.034784340440011965
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);
}