diff --git a/CHANGELOG.md b/CHANGELOG.md index 26b70a801d..206de34099 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Include patch to release stuck collator bonds ([polkadot-fellows/runtimes#289](https://github.com/polkadot-fellows/runtimes/pull/289)) - Safeguard pallet-balances against consumer ref underflow ([polkadot-fellows/runtimes#309](https://github.com/polkadot-fellows/runtimes/pull/309)) +- Polkadot Bridge Hub: Unstuck Snowbridge ([polkadot-fellows/runtimes#313](https://github.com/polkadot-fellows/runtimes/pull/313)) ## [1.2.3] 29.04.2024 diff --git a/Cargo.lock b/Cargo.lock index 2b5dec6ee9..98cd39b3c7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13052,9 +13052,9 @@ dependencies = [ [[package]] name = "snowbridge-pallet-ethereum-client" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb89a9f375672031669fef4b2f4037cdf84dc1624ebd204c5cea839a0844bcdd" +checksum = "e41b74c0509a263bec0b86a5892d3a5fbac0084fc7f7b2e5cc523119ed91c7e3" dependencies = [ "bp-runtime", "byte-slice-cast", diff --git a/Cargo.toml b/Cargo.toml index f9c0c920ce..37d5374525 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -189,7 +189,7 @@ smallvec = { version = "1.13.1" } snowbridge-beacon-primitives = { version = "0.1.0", default-features = false } snowbridge-core = { version = "0.1.1", default-features = false } snowbridge-outbound-queue-runtime-api = { version = "0.1.1", default-features = false } -snowbridge-pallet-ethereum-client = { version = "0.1.1", default-features = false } +snowbridge-pallet-ethereum-client = { version = "0.1.2", default-features = false } snowbridge-pallet-inbound-queue = { version = "0.1.1", default-features = false } snowbridge-pallet-inbound-queue-fixtures = { version = "0.9.0" } snowbridge-pallet-outbound-queue = { version = "0.1.1", default-features = false } diff --git a/system-parachains/bridge-hubs/bridge-hub-polkadot/src/bridge_to_ethereum_unstuck.rs b/system-parachains/bridge-hubs/bridge-hub-polkadot/src/bridge_to_ethereum_unstuck.rs new file mode 100644 index 0000000000..1b00e18b26 --- /dev/null +++ b/system-parachains/bridge-hubs/bridge-hub-polkadot/src/bridge_to_ethereum_unstuck.rs @@ -0,0 +1,122 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Cumulus. + +// Cumulus is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Cumulus is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Cumulus. If not, see . + +use crate::{weights, weights::RocksDbWeight, Runtime}; +use codec::Decode; +use frame_support::{traits::OnRuntimeUpgrade, weights::Weight}; +use hex_literal::hex; +use snowbridge_core::RingBufferMap; +use snowbridge_pallet_ethereum_client::{ + types::{CheckpointUpdate, FinalizedBeaconStateBuffer, SyncCommitteePrepared}, + CurrentSyncCommittee, InitialCheckpointRoot, LatestExecutionState, LatestFinalizedBlockRoot, + NextSyncCommittee, WeightInfo, +}; +use sp_std::boxed::Box; + +#[cfg(feature = "try-runtime")] +use sp_runtime::TryRuntimeError; +#[cfg(feature = "try-runtime")] +use sp_std::prelude::*; + +const LOG_TARGET: &str = "runtime::snowbridge::migration"; + +/// Last successful imported beacon header +const LAST_IMPORTED_BEACON_HEADER: [u8; 32] = + hex!("8ea383d85a87a2e27b088571aaf219231c1f6b3510d7be3c160eb1bd93dacc25"); + +const NEW_CHECKPOINT: [u8; 25122] = hex![ + "80c58a00000000009cde110000000000f118ba039276d46ba87cd50790e2547060aa6cd260476bdb499dc38ef834d618910884d25c9608dfe669a39ae64814db99553d82cd7a5bf5808240d2dbef04e6035075425a8cfe9d2bc194fa1ce245681e84909e4159e0c5cc1be7f876ff57d0af821d9b65aecbfd133c02eeecf2d8f64a164474274529f0a0fa9f8ab033cddc183b5dc028ccbc6c27887cbd65da8d4b8d6983ebcf4a910e6e2403b68f52628fb555e3486e21fd446483ed9df35377b07851e0e07803b7af34cc02494fe7a71fb32ec66a1c279dfa9e12b96b4a1e44fd1d3ca5db007ab2b953f6708514bc65ea545ad562b10a900bf3d9b25b5153d552ac07a256fe4f7761a5f9fe130c8e65b8f35ec53499db3a67c630148b7baf1ae8b79c00ed0c5f8f808bcb9e01cdeb963d8a6319e82af0f8a64b1819e2b21ddd3b07b74c8ef2bf01450a4bcb4180795b745f2f11c449223cb5590c155b284ef45ca108dd0c6e2ebeeb1e93bf710e1573e1cf7d2e3ce4c45cd5e5cc6aabfb110fc1c748b6a22677b333aa36d283f3d99eb09577cbd44b3fe69dea5d5651887877aac4f7f7eb0856e272144e187aeb92df3bc4b789b16ccc3b9f014b60b56159692db7f9ec5f2bbf753c0e19a5a22400b614c45da5ee07ff2a4558c2038f3772f2da1772070d65ecf063b908ad751a192cf1aafe980d1b628aff8bb34f7cead01aa4baf5d8be084e112f2cad65561c40a0932cbda6d5d37d6650500f14b7269575e1ac157dae537eab19abb957f40043c71954cde60e164200f453233a8b77fcf8ffe5d95463b486da0e6e873a1a00d3b04aa4f0672ad6b6d03180cc0a089adcf50b7e3688c68b47d1d5812972cfd5952b4197c414bfad6025d8c8f060f16edcf8ba8bb9075672310a1e10745e4e90fbbbc61f2fcecf5399045b103317086f544bef7b5414e373401b13893a7520fe0201de90c58991af476a86d9eec14cfd0baaad4278204b6d822cd32414da207ec86da840cefe31c5cbfa6ceff0546294c296e6aa5683093bf0a69ba502c89e50a6084b899a36f3d60db2dc9ba128210c4e75d76e83799132cbd4fdd9fd17eb704703cea9df391c83d66a2d7ab894cb5a15a575d1e71389b8c57d63ea48017254c02c106c64b3e8aa0c2f33b9af3ebc44e541aca5e69cfae22549ee562eb8e825d81830317e565d04563ed05fb8682f1ff79e0c855990e03a9d18ad8ce8983fc55deb5398b333a26db57d0e690ef6ad56d85512859d9bea389877d01d3fd8ce1a0517c87ca515b12ac524c47439b2c4c00b553f8a9a6831fccd0641f8eb33c0eeba8cb5ed88e035f5bfa079644258f5077483b45589d5cf4b53915bdab34d4030dfa8ad85af76e194db58d453df3411431cbbd8dd19e619ff613cc3cc9e88745bd1b3d24422d3dd4ebd82467bd232600401a39fa3134a2cc099b690158e52694b2141ce2979ee84416d8c89f55c23cfab2804e26fa2f58e96fa9d8e7f7fa8c33022247ca0cd1808fbccfa4f3dc4e70ed62e031598f4776745fee59bf0fd5369246ad97c2f2798e808fccf295ce5f8ad8e7e70268d6667508104ed10beb70a794196a3b7c7e7188e766d9a68d32ba7297f9f916e7e20f5afe0a758dcd16953dd81ed2ef48f4d8bc8190f601dd3da1df6f78ded9ced42b00a310957f65ae029e7e170d106e9593dc2df9b54d9d6692ab68e9d42688304fe8257fdade19bca9d162c83b3bac4b6626979a8fc77f49105f49103d55374bdf18e1638be1d8db2945dce2a9b7ca3c772605f9059f0754a06cd170268ed71a19419ec3c88bacb63bed8086c29322bf2d5ede197f3dc626dc83fcf7d3ad2aa959d28c9f659824abd2e7392a2658f1cda46be4fccca644292573c21ba76cd183817fe7d59641bb39a369f4b43237eb752ee6e0647a94c0cd1ee669010a851f133e7d674bf23e6ba23028bfcf6ead7d960833ddf004e335b83ee062938bf9183c99d97a411ee79b18725de81a5131e8c8f0e5dcac8837d036ed9c85cc02314994d865c8476e63100deeb615722ad6f8110b209ba9eff76fbcbff25b1d83f31e7439c00ba009d8ec4f87d32ed566e7f516e7dd48d085808641df325942b46d98b616d8bf622147f24e180a6be27fb74e042439e19ab3c73f833439a86dbbcd4e0ac43db4b891b67155ddb007d2475fbb070e847fa254273b63d0bad326ba60dd8c0849725be0496d270c2cb30804da546d94b3071e6de53a2ccd167acaa2439920e9c77e475fc120a12d91be2176a87f6c7f57061fba362e5c38ebd01f01c659c3631bccfd6973d68beecc3b363ba5ea9fe3918cc7629672fda8922852fdae18a99ca7536861c73a6f241440fb9116ffb3c9144d649d00255a4f15b1f6afa5c88e59885eae06fa271e0e1ab7b5a1b4ce2827d3e2cb309ae2d58e98a926d2ed525a8e8e1d4bb55f621eb6f688ba7184688819bc8aa9e95b114b78584247ab2f7e8c217ca0de8e219646f9c0184d03f292bb3138feebdd38de30ba4951cb1665a81994db24b5105ddd683075f6cf5f884ce7ee6525dcb09e04903424d7b8610a4be604a89d099d71d038091eca1a6317291e4fdbd84837621ae37182bb9eedc4182c1b3e3af35491cfa701ae2f55522c2042e7d8a93a54c2f505b62a748e1377789780f6fd9c54981e93f76b65a7c0010ce6f84bf03154c2d75b1da316b9dc62a2f62736944cb935f2f985da9f6fac23ea4d578136a1b3cd1ad29818cd02e9a72da1779f07c7a9f88b4e9fef6ae1db26de2946ba6edaa1b43fcb1c7e10ad49b9d84d060c6ffe0ee4f2fdcc34d27601a6bb3fc326b7dd600aed38ebdb605282d7346c990194aa7bc8775a1dd5f64c61abe8b375d61223917fc8427e659d431a27391ea0df523a25e96210e17ca85cf5a4f5f6fb6b5c4473b4b92c62609bf31e8bf8402e391e3a7ae63d4aff55a17ac1d97620b97983e3ca421a81ab97f811921df29e09948dddb325945e3a7c53fd68c9c9633321afd3873ce4ebb4a6856b4a4caf2e57a2e2532a20bd768404e84d2b2044b22f9b2e8f76946029db8b84290f6ed94df22c8596dd9c6bce3cdaadb43bc90d1f263e64bc00863fa218495994cd4b42025b22d257d3ab275ca382ee10231e8850ada2b50d0fd507b34c0b74b13d1794ea68c1d594d221ef84f9557bb43495f9652e3fdee490cd327116aba0bde4812a95c47955ea446dd6548aac044e14798beccee03b10a59ea6d9a5a2bf6e6bba2f2130128a29ead57203869d1fff9467d835cf8e7ad3f3d2fc077dfe11769982b2fa5e94379c3a2087edf3bc587d27987811204505bd74d8ef13acbec609ae24793f5a2b101eca199dcfaa4531a987b6524018fbe4c9ffc95985096a67bb041c37056498dc3733b5be3d6d03a001b418ab4c0ef72c609ff263136e14c16e9ffcc8a2c6ab4b3b1bb730feec0a1ae7c15fed5509ddef0e00b8de4dcfdb93be4e6ac902462ae732c20a79209499b9b87870e0476d016889a60ed361c5353020a3ec98e34e63b9f3182ac02fe66da7efbb1a3895c727cdca56fd43edd20bff709ce5f86fe5f9c880c11ec739b9485c0132efeca6f6014be637028ec04a36b57345d5680ca76837e1aa7f14999c928578daf668cea7358c4110d88abfbe25380352feba160638608ae27c8336fc4fccccf4eb0abe8942f11a77c6a39786aa8287ecff1af4732e63c834f325d0719e5870914a7ee8cd22592c42b6bbe86ece668f7b75ab921fb30979ea979d9a67dc6cd4b3ae2cb3751b35f51c7c8fcd75505d656d10fd54bb1afa2d24afe1502740275589f07b5371914d703690da14b54285e8943f0e6c532a977f5fc3c1564048b19d731cba84f69c076a823353ce020094fb46c5784c2098313f99c96c539258b59630de96d217795318faa7bbdc52aa37525c7091c8574c4a9a03b5cbf80963facc40ea68ec48cc24f71f3337c8f7871aea9a18aed2b1664c9c5f5af76dec55f74bb441abc21da357de621473325018aecc06917aff025087275ca4f964b8cd945c7c41964fea49386cb3ed22036e0474cc2def65a6a380f9a120e5560722b942f5b88369817d0a965d6482ab324b7af23bbf854a41fc2510c2898712f6177f9990a2587a2fc9d2cc0b7ff3c07b5ed0ea20c24bbaf58d5a29ab1c64f42e8d94ba4400c65a90a6ea0a7d2623dca1b2e4f74a4374faef87e0a77b09a1b45558a9b81b9402b933317fce57824dca4b911f066892672e667f37ad0a750e09802784f2a0f6ca3a675b5f6a6e76e96ed60a36cb09046b39975f8575adf33e2b0ec9eea1cc61ec6364a0ebae32e9902129aa3b174c0332bd338a33dd91cd8159b47b10883b32a4ba60759c14f12b8741582bce5cfa0f7d86743e0da364170d9677cf448d7fa3590256ea01dcf11905726b88b15056236d8b65ea63039efd66b7fb4f168e6ff46fc5f7d7dc734d2d406153340788216a5df6ec9fa169ac78540cedd4fd9a00382798ed054223ebbac19c32a0e02b9a27c5db531e507c1855fcb354bea4e484bb30bef99bcd63be47e4d3d4a4e0249f41588a18519584d6086e0b2039b5d14130a4b6aa53a088e98ac24da38b83b8f1801b612370c71613612bae8e5f1ec6e07260fa081bacbefc947bd612ab85eafe775db1aac43fd4abefc58d49aacb57307b29ac2ba517af4e7b26d6a836338d6c8941db0bbb9ea279d33bdb9632be5ffd687acd2b9003040d346aa947425b475d04333b54958b6f4600f7d7456050f160e2a078302e7011c634abff5e0dc08880d5cf6ec705f94951273125ee1886396fd14df2ebb8f39e6171876ad7eb0797e97facf88217ecb60eda8fb336efd13715928f1311606187e38e0d7a4cc94d9a1a0c36aca43f3a98440724e8704b935fb52a0d9aeb1b8861c6a7c4535af798f2d46a769f897bceceaf1f5fb55986a40567a8d13731b4274787ac1995b77d08d780fe788b45ac80dc136504f7e1f8a96f55add4bc347ebcadac13dc5f43436192b7ef765a23dd8a82083dafd346a8ed35890a855a0856abe09f943f27d2ae609efb77499ed7fbac5f5d6ebb58bc1aa061fe70397143434f1b318e3d9aa8f5daa5543f7af91f534d2193d7a09097c373ebbcd9982c24bb1ef2c3b6125466ed13ecf5776c032a3bdd2a77107d6a1323fed662ee74a8650bcf27ba22e9c5172c069b0db13a03a0aa7e689a0c6cccd03b894348e2b88a577921a1934a3888a13c4219057df4393158c7202ed74ba8ccce6491af1b143758cc25e4261cac346a38761c0a6a24f275e1fbb117e9fe566a555e86ec79072ab3e3c17471bd6fd429af98b00b8abe4cbb397660351dcdd941bd3c8b6f77ba9a6f7bfce57d1820273a8000b9a9cc23fb8536bdac8a3f780f0ad86964828ea9be5595640b4a7a6c14427d7cde445d1fa4985a032beaaa5ad2d47bf2a536f25fd855247c5e229f5084f4d3edce308fc0e3e92c00ce3ea6b6c81381cab6d769c81410b76120343202a0fe78b083c4b3da0a5a16d4169cbe2f18fd611cff69d75673dbb01dc2e288335644825e3297a6b94ef4407036fc2c15109ac307d8c83ab4d8029afd1213fc4c2df73da3eb545c6c55cdc003bbf6bd302c8a792263c2ffb1acff931957e761bd98ada159b91c5db7db9cc5708843bb0ff18b82d85d51f9227de4a5292d4cad152bee03e97007f40dff61b9f326121e4d533322a8a04cc5421aa4fbc8256bd21c37943bc25be49e8ada61e5f240c754dae5fb242b5f4e101317143d0f7da29a42dc81dac6987517ff085cc9b2eaf258fc97aba502d83e38247f5ed56a7eaacc68f850b3541a435304344f3b466925cdc531d54ea55988271c18f993ff6ac2f02a4c1f1aeedda7c20082dd5a7c2291e1ee60a449a6b8f66f2938af7b48a2ba01b453cc2d98baa4bb2449139c3cd4436daae2c1f637c8f7fee6e3897534250f313ddd3417bc92b0129c347c648d7773c79655b4aec68623b2924aee7da53e8ba56772cd6520a5c6d78b553627f3de75b056bc618ecb17a94b4d6b60a7164b024a693e526bb32e97f612b92e6a798b10b774f3cc7886a3bf419c0562801baa67fb28b3c02909bca1d542cd6da0f359d6a89aa73760b8d3642e3e688294ccf604369978ae4c9b220a9661205ba7a1fec3e96e2e10d73af9af284d7218dc9c249c6fd5f339ceb3380cea7f5b9ca305c04d9f0322c827bfd5ff8704d9a0b95c10ef7a4e3a332ac2e227beab26f367fd5a61ecdc228c73455890e935d949dfaa52ca8e65dfd5be9d73c4be0f8d2c0666c688de7e98de4f567627d3aedee8eb7fc75c4ab573e3fbdc7adf0d934a25d5312c8ff2cebb7959177aa440fb3a7cc8f4b85dbda4c65524df016c7e77ef90b11038e6da568d6c04bec1d53740d8d0e669d7a7f9ac3e979e816194cbdc54ae7fdee3d793a0006d415e048fe4e0f3f69c04bde7bf192686e53f7783fe7caaeee6019ceec793e54f3d0ec024e9feae6f643b8826dee65647b9f53a51509d36464685f44e1964eafb98b825d53ee3a8e9f85894ad6097a5cefe8daf6931ea7033400c7808d6be6cbbd244a6a694ec9bb3602a1bffaeeb3ac266ee3dafb4a0b8af48486c8c682e70597d5952e78a5fb01137dde04b8dc0af662de6b8a33a890f40e3c68c1c49dba60fa5e7e9d8d1414a36b0394acb7549bdd405732d118ce9e18899f897ada4be16a73a5d2f8e83b36d1370e0d71a3f0b1ab6e956ae959fd878374a31d52c8f6a5a30442652760c9de032cd6e1f621cd557b802777f290fa716771bd240f23217c2993a56aff4205f5b233e4403d73c719b6c483c0ee81c51056125793efd502e3b7be54138357335f7ed5370be3baf470ed7287a0da23815690ccd6d59c55ae1b272d46d2d57d7186e8b2550350b023b09cf34947fa86f24ca0b8b71a3ae3933cf8aa43afc46d87de82b57b3fa83e09e87ac43e362625ffddc02d4bf35f1514f755ebae9aea374dc7720319d4f80d4c9609d0970f16ab5b6ab96d10040777e2ba8dcac635a9358e636fe84a4c9794ee9f7c9e6b4682a4c9ec5b2a594071eb34a5c581d1288678dac0b525b459f96f377ba56a1eb1ae9275d70d33c3d4741e66144ea92f880fb154ce6d5dd8fc74fba41d12e9d66c859a8cb892df9a8d9398a80fd1a746ed19cda457c58fac722259a67573b7add86ce157cb3fd1e01c077e93a1560b2ff3c79c4cca88100a4cbd6e0a40fa3631d1de6e035bc197ab7573f10eddcca678433f231dd23ec2fe50652473af6133bc8c1033953baea90012e2878afa07e842f8b47a328ca9df0d21b58ace0fa8e7e501a5b03313764c81e2786e9489fdfe741521bd4fe299548e89bab19e8847ab274d0273f70f52e71e9003d42a7276521750e5c0792ee01cea2be884920f52075dcd02e9e25c8307dd499764fc029717c2ae5178607d17a730978a8896b6bb3b97b47cac98aba15ab24e1bfbefc5a2f8e2ac0c4eef44b26917de5e7d8b7330fca531689569fbe31003b760c6f4bf17460eb51d21c11b4cb8ac3bb28ba7e0c16d35104d92b1738e84b31cd27408d095984d8d0b20e0386e4e4670f34d0e8a0314500df98a568303486dac06ee4c6b14e1747062c34af8ae21b715a30e4654806717a334660155b8ef0d713e7cd2d0ab0386016b90eaaf8468e75bdedb81aa9f3467a86e012916afc5ed65ee4542016b22a6926c58962decf0319b73397e000a8ac83245564e5ba5adae8e0c76eb64bc4a82e05f9b376185aa44aa9ae831f3b2338badaff0436c57c38e9f3242aa9c9f7c00807a9ac8a97ed812c5ca69767766f87ab3711cfd478f6f60f9218c32a1c5d9d7b5bac1c1093b399c46f3270e26f035fee1e5b2c9680298b570a2db6fc8f2ed1c5b9eb65c8b915378db43893c9f4ad7026c4867f04e286d26c70e52fbfbd0420c4fddc0179675d2b2a5b7a7a3bc325967566662192b93e1fbec87f90e4861809e84e5a691bb1aed7b03797036c668fd07aea5d5586d1ed72df9fce56a6c599bff50a70086e689fe0d102e078358e4ebcf70746e7b86ba97ef46eda5927fcc5bd63564794ba207b1d85a2b38ec7a93e84768962ac23cadd9e4d66daf8f9772ffdf311a1d28fcd2187b8a5f83b03c64dc49660f630303ca5d8e37e4169dfdbddf490dd8f226b29774d95082314ff6112ae77869e72886c7a93bee730897b7d38ceb673d4030283a248b66c62c9554e3236655486c214baed7631a301fe780d283adb6fede12e43e848f81f16b36f97149263fa6bf54484c201f51665e2532f6b29d4037a19bb798d5d73aba460e78794afd7f3dc2efe998eacc597a27ae8c7d0378a6aa42dbbd2606b9a9f0045adc22ca004ac27a7e0b87d282c2102797566e215a456cd34e754c67258a067db1a6af16ee8dd50a863da3939ea8f26e89c5e87c3a35dfbe08a98c0f2a45b297609ae574173d9cd07955814ba24fd0810b686a6a6487a34bdadb76cbe8d7a100e29eb66a4d2ab72df6738d15092f519d8cd1ff5724e359d2cebc2ace815c4c11012aefe433e176b394315c6ff6b31d745b65de56fd842c78de07a1b22652fcd11a340caaf56626a999625d32d762c81e097f4d548d94eb075849beeed2d57c40ff9a545371ce9bd9f42caea334101a01afb0a73bfce8fa0c6ba88e9c159f8009701773f2b9d79f48bb793c04fedf8278efc1a54c1f77a1f8ac4e83e784054e76160e05af8b06e565a5eef9b06e5623f5c0dca6f2c741de8e71241d94055e0115056200cc5a5de25c4cc3a7507e3b153bddcd89bbd9faa0e13c30c6aa4f3b8b28e7436b0564625c15e7425ca2e1dfcdab8a721d5a01314e23358e991ae4eaee313c8efe723b19a22ea8f857667afd92267cca94bc82d6bd73f4a935c2f32d79dbff17f9e54b463911d81d80b3c9d98d45e7a93c3b6198ea8b8223f2223950196950dcd4f5f4d81423d61c682c040b2748e57dd3e51b207b4bb1658fa013f1f6ffcffb5a3df119753e65619a5dca4e507f510360721e37654b76771814fba673e1c8ef24ebcf91f2f7d08db30da1a1b0bf3300a66d992072f15daddfb5d08a08942f14e854dc29c3029f6c27968118aa2d23b528148a6e70f2438faacb3c4ce494dbeef03508206826ca8b0bada57796f4a4cace53a1339b41331dae0c6cd3f620ec58d04dfdb03d0710da8cbc876ba222b16ede82ec4f8839d42d8d92f4e67f804baf44790c00918f7e231d6b79016cccdb2efeb7858e1e9e4a1eaa67ce4bb608790b09894b06bd0803684ef706c0ccdea713ea7ee376d9d6c9f676efecc91ea317cccfebfe465edf03278410fb011e5fbf8d50192e98bc0f65aa4a8615e44660d3e047e2703d60f7a6d08d468611fc0b1a0f16d3293842c80a3fa7de450ef0ae47a084763780da1d7e9755b80fbb07ec7304d1c19a7f6dd3c2878ecbeb46706d9939922b92b3390dd918a11eedccee7188a65503c983b8804acec6bced9dfccde579891a1a884a4000adb864d8f9be54657d653713184a81225a83f314b07e32fad554ae49697d5cd9927761fb78eae1e8571efffc50072b44a3d229e07cd8cc57751a33537e66ddd2e4950793b39d471821a8bb26943e0307d924e82d3adb7fb04dfbbc1b1b832643d84362f465a8ba7bb8543ab793caea761c9986b845aa2ae3d99604185bc12c25019d5a981812348c662cae1795aacd0eea8609ea2dfaa0e772e9aea92d2d654305ab6a0068ad1475fe14f733483b03e768562e563739a412f4d3eff2ae6c19883681e3b22432943b32d9ebc6941674deb3920c52624605ad196bf1f8146689872672ddba241100425d7b73d8ce99f141de338f94e3e6e1a9bd8d6ccc8dc87e585ea8120121308ab58517549e87e8d9e358f7c653af923c2b56a0ab756afa52c2fc5b1133407ff0d088914f04adde7d8b9a840156135b5991dff05165e34974d92702d93d7027d56a6fe2a9004c05446ccb7283f2994cc064cbe6850dc82c9865738e9ee7bd205a50ae83128f007bb1b6e5f330fdb634e823fbb09c279609e9819df52bfd3214635c80c4fcfd47672cd7dcb05a7ffe0bb71867e7061764cb68fed668b00335d6d011be76c3545c4ffb3d54810fae5c498a29ead7fbf6d0c4e707308ad95103f9b9bcfd3e3a66c8cc66e506a650a9a2f55de7724254943e076a0aae77969219f0df9f7781278b9a7cf9960fb6ec69d05e819b3b448910a59f1eb3307135b469dce550594709cd9bd7e2ae8defb1526dba97db70b04c2d361f468a3193fd57d0fd328117d05bbbfed2a6d3ae4a555c332dc38fd74daaa6a8b3b55624836e41d8aad26be0982de48a98f93153b27ccb597b8f68f798789a9d46d84cb72ef3cebc064e428613757eb75c86f535b3dfb13f7abb8bd9216e70f04c67da84b6d684ba7bccc57b5d4b67aec5a1ccfa2c858017c579cbed366c29b6cd1ce009d5879ffba0c650dc18e683b9610e651584b9a04a9fd73cde3a56904b09f6ae9f6a4bdcb0bab6c1e5b8e7e0eb5c8bc1d130cea0f4a6be6e364a28021fa476893e87e779022b6cf983dcb394fa936a2245cedf379642716df1a932d899e56a9d42ac668e783a910fa39284ec7ab00f08918acf9119f9e964cfea71404064417aa574c0416acfdbadca8ba43895bfff699cedc1603f781b4b7c353724019562a947afc7e7c30ffe6d9857346aaee04143e19d8429e486003243387444b718ddf52bf372f542a95e1280c4a54299d13e3879b8e479925aaa84368b47a69f9c1fe7598f0d0f5fa405ef3829299e970a8822e1885aa33e7eb400d538d335ab97b746bca8da82350e3d52a9833f010d9b998af92b54a67f6d906d12fdf22d64db5902452071bfc8fa65fa010d2a8ec2a1b8f3f38fe4c37fc95cdc46a8ccb9743534278d225a5ce233a15d503158e1db6e9d016db93b240aba04afdd7ed2f8f909f32d478b149569b768c13c4f9f7bc14fd5da12bec4692dd6119bb35693bc0ba09cca16c496164bf598d24e5fa641ca59d4b283a60b2a3d30f365014f6c8d79f0b3d878a5cff8f0ef98e48b5864c9e0a450fcc3467e19a3761ff916ff1e2a89f61bb73080cab649a91ad197fa3c3b17c6859b57f49a845fadf994fd36f575724226e32866725d8f641bbf052bcb41c96c6b7dfbb13324b10a801ae1314373b77b6cfc61580c46bfaef27b0b0446801d054be7f1e33266bbc267c09c6aba0c3b81ad54da83c0b627503d9462b75249569c8b97b6da662c18e2269b37ae6eb3e07e995d92466a990b3f8856bbe83a478a7f8725b49285b479e1cb89335af647463a4892216851668daeaadaffb0bb37d8dd651c509c3743274eaf7a2a51a0e1777fd21ef8a1555f625d5f21823aaf317e36369bd5c4976ff3c848256df750c421c9145f64a59a62218ae70d4684935b63ac3ff6f4a96aeb2910993aa02dffa434ee1ce52cc899089eac0c142a6d2ff99cec8107649c42b61a32e9e4b0541635191007ba47803c1c351ff2302104f39c4d5dd1614175cef07ca15cbd0a774dfbb79e897bcce54c4f49124d0abb171159eed866101f8bc4782c167ad4332e04d659c071fc7cfa8530854f8e6e93f21bc8152e672ee134b93e64eebe550f35e53691d1ea6993ad2158006191f1e2973efc194ca0ab66fc174758f0226dc531fb265a560e5e38a4225c01b2bc362af73af9cf446491578ecfd176663c471c60a613ad7a119659ee68c43a5a08cc7c737c58447668644f2444fdd978bda86c60bbfabd0098e7d29746440da19e9ec5c8cba161f299fb9a5a83ffe05ef8433746c7eb6e174b4f245bdd63973c76c73befd9b7230fc8f115813e6651f1cc7445c5622af346dacd00bd0d6d47f204caa07f54d4c8c3a6a1ffccf161038bb7e2184821427e2bc8fe3c8cfddd731c8d98b4e6386d70a6d9040a8a4993061e72773d1a82dadc8c9e0d0927d990916ecc59118eacb586294277fc8f63de585929d522e13f8e27331a96499ff0f1daa43e30176853767fa3362209f69dd13004e6e6f7e898182dcbd2c1cea23b682caf8d9139d4f0baa12592284c3569031f77d4cb3df039991d2d032f5fc61b035a0eb2f70f7cf1177be908cb8eaea47baccaa254a1533cf91f52c586e5648d1271cefe9633f39cdfce209e09530056123ddafaae6c8cf7cdc4a5ee592ba291292adaff17a97ed3de2ee575af0ed4b4705c90b30f42902f7f5591aebc1e5e9a25b103c16aadbae2682df90eddca8610025bcd0254fc55833850ce6b1121defec4a9e502ec46af0293dd87f90fabe7e8eb0d758cf4a6c2c6b4ea6bd2183ba734471c82f41105179d222f34b40dc1df7d4370be2d0b1c985ced4311a85479e7d5b520fad7ad6a30fdf272f3c6140487ce28a9b490c65e3976f35e51d1e5d3147a1fc418c8fb9b98dbb032af3193f1196689423632d92fa81302e998faa9b9964d0a92a7159bfb362749ae88dfcdbb7e3b87ea009a4fa76880b817aa55df06b1d2327b01c387a0b926d8ba31a32a3696402c64e0a02efbfc32af918129a4e2184833c3a763c9681092db63fa29ff811de4fb7f34211d7a05c5d46a890e5e058b18522565e89649c9e397b3c4a2a35065fc996469416425e3e59cf69fb886b9f89785c9c4bdd8c4c224bb826c0c2fe2928a66d78432d240c1aadee7acc061727d3ca44db2ba819cd401cb9404751d1f48f23184f3aca22245791be2ffe23c25a811adae614effe498d6f0c5cb0d2cdc6714b3f23a1c7858ffd43dc1d1be0f760cf28d2d3e64d6310854d6d54471d71e8a8d7f77f3098378ba1e5122eabbe0cb9d224ed4904429b2b275f5bdc45bd8eb71f9d243e5b7e55161ff23e35434e83cb38c3873c037f255995350869d8c06ddb813aef18bdafd7a280d92f25b5719a242000ebf0a89ca4589894f6aaf04e0288534f83560c53c82e472ae8ce54c5dd9812a6964174192b857f8144a77af9c6a86d4d301212ea8137352c14a002fbfcfa6c56d4df69fc9c235ae58b7fb11df3bfc2f087a051095beb722f58d1d1c6b644f989ebaf4bdf648b8addcc90ce1d8d080acd5ca2e6499bdac856177d8b121b77e7998ed394b47a5e6badbedb0e63207d84190b721b7a40037df1bcf45bfee6c953aa2dd319498200365a5518ef7815c71bdc88c1d8c317d9c1174c401cec7eef84e49fd2e13b60210d58cece2b3ef17b0fc0253c68c125cc18e028311623ba3f0ed6126e71e0af814fb5137bd5653b6fd923ce03df31addb6728df0932d710f876b87e4ec88b05fc406b2cb5ebf3a7097068a0a3edf583d44f7a52e042fecb083bc6bf8927b503fe23134d1fca2d7238e894606860ac772a3d371643acac90dd864107a046dcace6e1089135612040ed33ca50ccd15358813ea65077abf2da58b84891ecebd6856ec6da84e1aa05007db848d95b27246565d7fa46b2f4515fa38c33b0c190b343ac27e18779082eed3a54eb129c4e889f52779cfebf26b915227724e16bad10f4a2037128bc44c341f90418332f8037c34cf4e781a01bb9421922b747ac89ab2a8a3378709ed1c401e8445c2272d26ebd9b585127fb57d5d183e52b2e17861336cf9e10e34073a97a4880794a507bdc3c9dc553735787357eb8f726cd7ac0b56559fdbb1e3758ac97fda1c37419da24450c62eb6dad5e479608bbd4ed4296c6ebf812b6a57c379c796a5a6baa3045f715c0a7894427d314ef37f454c83cc888b165aca2a3eae11a768834b6b358bd399fed1dd302fd79ebf951527a448669c516cc2d0f63f7f968d138c3af179d42f02d3c0f627eb7dae2f4489baec3626c85116dc23072b4d9c59f35564137816b4ff91fa4988cca72f0583ccf80a5ce91edb8642758f49118ddd7cb598f92cde96e8cc7873c34c1d50988346307c7ad359a5fb1e2a8f21b54fc1f800d83a5db56f7d3c459500429346de68a1a049a610c86dcc5a7dd737a0b1525791d8712d4de313bf3e68fca59a38a43145074bd0235a4e599da5f58197d353bfa8c9432c709eb3a6a8b533930531b16388e0d9df67c46dd2199188be257c065c55091a1006ee6f8f93677f3f9ba7a7e0989b993fdd53a97b92b7a33d4ab0cda47ed4a26bb9e6f0ce3ce05f9cc563231e020fb655e76ac7276febba742c99f5928f17c2f5788f0f9bb4c3021dfcbe7b86cd1396aac2828455064d7cd2c56cab823e2e1b56e6f41db25ace49d092eddbb0913c13f9c8783bf986e7de6fc5f2db09ca04c6837730c7ecaed255c6147b6974a29fdd2e3b7140e3397fee402c9d478d879aeabb03f0f3362f5b5a2ee4d8b92aa97a0dc8c8465d0375d8e0eb3db05589a86dea8ee32ba2b040048f0ec7ed391691a1cf93c439737fee4445fc2750378f3c3dcef47310dee2ec95558e2fdcd69fbe4eed7fb4f804970c4afb7ea2f54486a6122bb870abac18656546f92efc00660503ed2ed25be1b43275cb454bf1cefe62865830ae736357dee7eb125ac93a308a7144662371d634c3ec003aca83647443cac5f8e8a324d2a8ff69722da02fdaf0f1ddcfbf836411cd5994f0c8f816fc8e5a738d6778d4afadbefd3eb830ca2168a1cd941d037f8f0889dcdbc7321b131c7bd6d6dedbef81e9162b8a6028696391a5f4d40d52e8bde21fc8f4df1396b58d6c9d125cf676a93029994d13255f14b6f7ef90fd6aab2e8d0e8297cb53d7faad0e361be240b127d5d275fb84759ab13a7ad8be346518eb425d471b2600b78fbe5218878aa6997cdee9baa4eb483c7d979162ab1418ba5d4de7c2609837607bfd9e24ba0aedecd13d0253aa10c91fa13cce0ea826bd9c4964e416f9d0ce064e8abe60dfdee2845d2c393196cc17f7f5cafcd2fe059b217ff9b97ee17b779401e701c971a99a378635cb6fa1389d6aa5ae5027d924743a3a4c68919efb780e4bae0b725df4e1b1d4f9a5c3efee2beecb428d4ea0b1232e073350c30d86ca6197b5d079bf1c9d0fcb1e705d2b54951027000245ba068b7c6d9af593e8ef64834d47489a673df93960b90c54ba259150e989c941fef9de78403bd7e8e6961811c5e824f43cf71e6a48ecb0c65f14d168fcab6eca03d7ce316f8b3a40c0cf4a5baab0ca4d339aef0b5d027c75daa258941cd6f6ad7260c1bc5c1ffc463b0be9a40ac7f96f90d269b60c8c583e624e0c11aa951a4542df0684fa5c699a5416067d5e2e26d9e28b90bc50b6f9ad2365f31cab40ec0e58d824e047914b97cab112ac35b49ec606d981c0c3083e013be7fdcaa80a2686bda1c58386aee9507801aec128641ac6c2fb6346aeef8ac2e86e122621b7e95131dbb576d6975ff0c12bd7990c3c94a19eb85efe8b682bb526e5ab6645767b9fc86cfe92101773fa7348076ec58c1991cb182a949b52178a353299114d4c20e389d4dee383d6750cad56fe52591635a8dc94af1208782bda71108f03d9a14a41310c4dae567c7dcb22f1f42c6475319cea9701834164fbe9418a9eb575b516e5c64b3ec3952fa51ba06685f0d79378e8e5e8c0b61c662f0dd48b1a9ad44ca7f94bca32ab8affc2d7f1f48301a491d0d61fb47a59e14cb84688f5d6b6a68052d4850d1490da9a0e764565c4c57f06ca7e23341dddf122499ac666eb2c9fb4cc9190ef9c7cfd595f49a12b383706b7b1424d77102738eaf01ed34326776776f3d69ca39b73ee4706e7bef37ab288554bb51e9050fd7d86540db0b550f463a17485483d5932a3962ba3be881298d314d25ff8716e670d2938f6cdb250fc4a05ee338c0977900498d1fe2b194b1e47b6b674ec87f43ca2d4dc70103395ed85b20574c5fe4c62c4fe092262cb3b06ec0fa3fb7eede7f0c9e7461835c73160998b03c3249eb465667b1363875db308e837ec4843a20773df183663ca92b1af0dbf790cf3d3ba94c95668fe939eaf2cba82006755730e94e86f3ef600bba835371552ec4258cd64920bc19e6618bbdfde8c600bfb842c054040fc9792403147d48ada0fad576b0535312225418dcb0c82334a3f14dcfbbc9fde1200e3ab2d7f3e3a993182af99213c0e00b4e4dd3581bdaced70e7116a7916e62bcf0a78668112d43d23291aa30b3acb4bab4d4bda8d2824192bffc4f7eaa5b8aa056f178b6ddeaedb7e38af6197ec370691a6e6819e6b4080aa8f51e412d504656ee70b782995848b1e7e5df415e86a646ce2c86fc126a21fc4b00d3f4927700c53615b79a72da6124854014aa16f6f8e05e316003bf4542bda9a03705c456d22c668f9d5f8cda0231785bac0986001de9d41aeb2b8b21f4996483d7bf61dac2618a42c329fd514eec5c80de4604269cd1f1f74cffba98acd54dbbacf938dd42c9564b145c5dcf21f8aaed19d238f2ee3519489898ad2bb00f235bfb6b34ed913871fc1ee5af2a832b01ad5be44ada3b1d53df21ea0145611688e1ecfc4579f5cd951a04aa8a5a1865b93fddff38aa6bd6f67b43680efa558192feb644672003e95ff12e9d7616108f4bebdccd422e0a46d4275ffbff3a7bba3b9ca3cf10a4202f71e0a24fb98874ea983b7e98de2dc70d3802fe2f9ac074335b1c002f429ed56645d532d8436cd9d068100d536416fd2b48796dd5bfea7048362d70ad1217f17090d388bcad7f7758079e1d0ec27442731e9ca09c5a9033860039617da07628933dd0dd5c8c98956ff072840ff2128749d747c70db6ece43f1a54d239eebac6b380b71437307bb78741da5f310bb10431164010b0729b55c1686427dfd6ce56e5a24c38d4c64f81f3b2ef7dda5a0e524e6302f2577af7bdc9f898ba5930528bb3380b8b57e60ab77ac5e6df651a89a7ce535fc5f615aa057624745d1be6611c591fa3c4ab2f6c235904063f7df82c374fede0ab2cfb983f4a63455889234e41716baebd9fa6d797ee58fa56bdb5b02e50594e1cf0c43744a26e0ccd230545d79656e6ee161f4a27b3acc65e472f89281f4c12bfe8f3c412fd5abc2c6593b6b8ac71c17dbaf42e639dd4b869792418fded79484e56b758531293cab094cf0895c922f57780ac7a27c7e92d6a8c1b859833ab9753b745bfb17c3e84430db225ad04abb9fd5fe5ab337773c3226c2934809fef9b2d9a6e981042508330551f0e7a248e1e546c42d79449ed43fbef745aae18f3d9745cb1d95669c521c1e1375a161209918ea32cb8cabee764637e7071f3b0d0fffab98672ea5bc3ff0e2418db5a76bb7aa28bc5095c487d12c42be09c7ec7c8030b54826af316d3782353d709c62b16d65e65af2d1f17a2655e46674a0bf82f38f2f53bfb8add3b43bd66041a346c9cb65e8d73d53d077c0fee758215942aea0af363b33f562b0614a186afa1cc5479fb797bff0957b49d1b5ca904307568d147e598869d72d9e9516cbebf153b427511c0b10c9792c62be54c51af4bf6a6fd90403aedbb67669e5f47ee010c2369d716774be289391ea80e07d756ba2669a6825ab425430cb9ca3ac1921997db50c424d7a6b9b829dbb3a4a13de16227ad16d62f820bcedd88aba5368bf9fc4f6206f186572898c0fe88509d87ec32f18108490f7404d856448393ae8440668b090146419e3b93008568800432213455cad46c504d51906674c602f1ef66d5a4caf76ec1ca319a80eddc66f438cc7aee775120210515b19107a01777e10cf23a7915bf2ec11f9e3d3defa70b77291670c5cb99d46bd5d89ba4a7019297cecb1014e78882ce25822dad5fa6b9671431bbf83539e7bf1537ce0b152a3e618c0b1285ce2955531e28c508b561b2e11757ad4c71e86e4f56b2f24d65acc5acacc3601f3d69d5622867eeb72d39c6b9860df450096f5fab66693662ca3e6e36d9e0ce8c486856243a9249c155dc6be52f09415d848af3444603e3e3e94e39b188641df7f548265c9f2b0741f275eb2210cbfa22d522b9cf1bd89424a644b97d1471a175cc7dc1a26a0f180dbf97316b8344a48d2063bafda91af0826a37b8e97c64317fefe2ad1c8bf7e80b78981ac14589c11daba097540122105e6e9a99554343f50ca6b9e6ab4a3ad3f005b5ec04c421e84e69feff6003c1e8492024595e31483ae9117cdaafc8b7db08d732618594c92ddcd2a0c84104291dc5e997ed9b4a149d99522ab2245bf225d848d790824e4630899e3e1dfe6f12e4afec92a1952fcc0d3a5ac8b02ef1c98b4735e4e478d34e0837779dbc3c32c7806e3922561605117e632eee86e250f64033a51b27d2e6fb36f9bea0dfa9931a0f76e4c98f142bedd160653a9b1072b258dcd9d5f86cf1c76f14afd79eef7e17709cbf259f94b7fd0cbd136d0ed5c5482fedbfecd845c0dc52b2fa674d51f26826b538ea62dfa20b4d8a41bd26c0b056b34eb1753281910cdc1c149c14da6cfa5d062fde59dde7f29c1a6a72ff8670e4ff6a7260f836ed9527fb64e8b0e925b0c83269fe58b07b5950bdf8cd209f5939713c5e24ef439b2020131c1fa10af61c4afcc81d49909d0a37441b9861bcf4babf7f490bf3c397298c4a475d1614be8a3897595f83cf1b96d56390dfda29304b1eef5acdcad0a15ab4a13c61ac03a9e08ca433aaf9329710c683a7faf2a613fa721c7ca98552a28b357277c30843222db2d54e033fc99a94c6c59111fdf18f54c287cf4259a00ced3653bf01a9f1941abed36a6bcb6f806662e0c82b94ccd760835ae922a81d0b01d7ae7987233e61320228d5393431362d430c8860c020bf2a43444fc05ec36b02d428a02669370ec6bb036dcfecbd3bba4acbb7d65e59a4fbd5580964e60e74476f6662cc58c5dfe8aabaa001e6ea5eee885c69523eba01118381dc608f4c2671e36f1abfcccea32fe08755bf203b6408fa4d982f729d571984902adae18fa71a15b363792a9e013b06a30def5db262d0ec542d933a02c6ed1d9f09d5240f7fbc23d4bcc1f4745f6ad256d37665a57888e9746d81d39edbf4cbecd2a5f4c219657b85885ee35b806685fb0e50e544ad151952ce1d5eb0fcaa05e1dffbb1bb82e407bd99cb5cb4b793f39ff10aa5f1c9e5c158606ec3eec64d60e4a7bcd228a8a2fe5807d68a4952cb29906c0fd627df3019a234f82ce9974c95cfcacbe6b9d6de25b5b1d425b985027967128fc1395e009acb2becb9f339a96345749ad459ff4a8fa749aa47b33ab7aa1b6a79e6d9cb73e46675235eb0a8b1b82ca8c5ec91b694f09c826243310558e062554423cb1d837bb4c06779fa47d7c88e1a5e71feb2c707dee677a5e07baca4001ed4ee9e2c165be2824291dd3f397edb022b03c5b49246a22eb669e3525c92a6faffd400dd53b66973343aed34c5b99480ee0980a8f611b5f5389869ec6b0f7020cc3f73bfed687c06ab5f23c3757c730309240d7840bbc20c4d09b9993a0706890b76d543d37e1c4741f44751ca3549de3f1d721c0a196424d1d2c62edec2172c155d522995c75776424d3ba9b4310ffc50a51863f5895829ec2909a0997d91d18cf8044b0722fa6487a27ab6cc0eb88b35102338c65a62427cc3cb212c045d2c659cfcb111becf2b71b9a2a6e93714b15132e7261dd821966e8dfcc09d86a65218801844f374afea830dc4107d38effe63ab01cc1d6505c8771fa0387a2726fe96094c24d048638e2ba9def73f70e0f0fea802cb733151c652e8c3f512cd5ec8d7c369c092075fbaae060f2ba8a1f0b7f1c6f505d908e5a302592446cb26737b57e038242b8daf06d6feeb2c9a4031654e7d9a8b07fcb529fd3c77bcea6c4fa97027fc292d32b5b834606412e1ab5a4cd25ab3af24db414cc35b6aaf4e2800dc1c3c655b0bbdc2a1501070f96a7839e5ca3653b4596d8210f725fc3f24fbf8e506953d9c2077dfdab76046dda37945acafa2326e00524321283b7d8de962c6babb6a4826ea24b8f6abbe18cf8cfc322f75f08b11eb612bdbbd6dbaad2314e3523ce196a4c7b7ed01a290526ca828b3886b36e316478aec8199cdd4c40dccd17e14c5b8a3743166a41bebf0099f2d38aa1817dfc0c54b04164992416718eed4563357bdea26e952ceacf2a4ce6cebccc3c188873e0b4628e90d2474632753bbe7373db04a528f06f04240f362cb9ca48e67a236309f82602cc62765aaba724d07f542fa0f42c537e8a772203e400f92f27f36f8cba341dfdb613d9bd81857f8fe530fac2c593d92b5138d92c36570d25f70b19dc4c1ea3f2cb60bd9d2cea7a80a3d2e624ef3c1aa8ac466a7ab494b123e4dc026cb1b4528df1593f58971b3f9f6f1b31083eb8b6c40365957e0b3c89b8efd120c6fd16e93915f989368492a44b759a47847e4190409e62b82ece30d1aa63f8a553a70829c7c60a3d627e7154a390b83b1ebe01156b00ba2b1153b924bc9fbde0e01c35b09fac0ab9fbf4e86c5a0cd7fe094a15da00d28532ed2eba4243893aaa7708d6e70519d25bcb2985bf2596086c4cdd020bf330f45bc5251b20723e71a1ff9ea6ba65b0548023690f7f3553bd483a338f45902d4a53dd319234012016748fb642eaf36265ba94010b3d544ebf355322a32836c4e7ffb140faf971018bda3e5352012db80b80fa10a8d287a4c6772f6dc258d933e8404d22387ad40d8a92ba731812f4d7c9f0cc7f02a70b496ef969a56f843312d0d57f71a2f36753ab37dee4059404eb8755e3831a6c3900bce4b25a6cc86a722c574fbf118ab60f5d93cd8dccb884cb06e5501eb332a69b5d90ca50cb328a4d3cd0a62fbf943a8ac87cedaa1b062dee70dc185f58e41e6f6930f77528485f715f5dcb2bac5d49f4d06e1501aedf675066a688af26c84448c114d1e8120ea68584d728067ec03ad23c75bd6caa3abe9c54d92c53924aaed4e2ed70b414e9b5c57f1ae35fb099856e24e7a9414c1d4c26f4b486d238c6304510ee3c4dd18bbbb8ba195dc9b63d0f357a33dc87373822fec9443a814606f44fa13324dce0e099921077b83edc9f19849dd0917e943dc721ae520bf2a1b15d29b8f12775ebc14b5be224c65f369e3d305f03fff87fb5e91b45ecbaea7571905ad14407d079898e7883b3e334880ab16a5bbed13d38e271357f03184d31fd55f66e6e1f1a9d49ce029841ba7672e103de0b0a48c3b71a8d626c578da391c429db8766bd825f3b8ff98c76cee1a76105e2ff7685f4705499108d920dfe2389c2c65222f4ad435c78fa86ad94bc84e8db3ab29823469574c9b596e2e070b258640b33d402da3213cf53c7550243e3f5faca65791ccb4f456ad51adc0e1589df67d0ab448d486155b8b26be4dcbc2bddaf70383a6338fd234a532516647f6b6967a51d3b7f65fcc60af45f2d46028cded491058ead42e78f898a70468e9112d7085fb21792fc74ebaa7afe80267b33fb1e62fd1561b94ab2c94148f94e2a898d31c37ad5fdabbd3754dfba6e48db7979d808acdfa2b85ad4e4637d1bbbfb5add0f67aa31f709da8856ae5ec34235b5f9a170558b9ea06b9ab63b0014a800aa41c716a851bc9e4460348db50bd4c18293719c2f60a2442fb5eea3d33efee7b1134f3328161e67ca307316d44160e8e1257a4499f57d0e098429a13048a105d7d34bde433e8610ad4aaa237bff7271914e526b96564e7a3c210c88192a59f3bcdbf558a7a8e6a732472aaf6020d30821cd3a04a5f49ff7ed41549faf9ac8ce82a32650e1cab5a4bea50f749d51855f76d7a2ba7ecfa0026ef50d9002c1f455fb814ba024122311757feb22ab7c2723a1cd5efe2a55848b347f7b62aac34ff7369b0cb479714e97fc943a136b20fc1149e900e56a9e667b1ea9d2691ae9ec72a20e722d5a4c87ca9d51526d1a37b4dc0638abd12d1f58cb6e02d096514d8f4de73c8b989052e3eec5f7a7fc72a11cf6ac2cf20022b862b312fe4e4dce760ea7d75ec8f01e595966154033f30783402e9eeccee22712a78a8646ad493777177692910aa01e5f402b47d76c27f43b4824b03beb9996c39dec280b3e0ec0ab390c7e4cc00df6314984cec4b76750627afe99eeb998d02dafd64b9505dd39d889d2f0217095963e5f7e38aac3ac3f5531e285808609db23be1d1ff8d4a5999666b984b6bd0a865ef8e195343c8dc6a2fc3b34385ee72f83ec049991f6999fdcb8e1efebe92a71f2f9c788c6bc6b2ddd84658b1ca4a87c3fec78396311eb498d46d3a459ccc9dc5b8362597f9d67abc3ba900afd8bda4bd20d55d22d371f87bd32898b58eccb42dbc524c8294f00fbacc62fffa1e6e7c6b6707427f2121f9437811e72a7ac0da7563d81b0275429e4e15e5d80b67392bb1cf4a75ba0e4ff27c7eaf72681f41c5b94076ae263c0fa311547a1610fd4240ed106c5c5529ba611dc1155a4541562e4c4fff585ccfa3a425516ff917cab5ebd4d5b219795887362628789e9e996de906eeba05ed747c4a7c532b092be5e7c14750f6ef6dac5983ffab22709d942ecf807869653657e89a98eb298e2e24d3ae263fe4f25ac168a715d476c85d532eba1a43448019ab43754a5c0f72c620dc0856dd7bfdfea72ac7fa7d2ce9705c4ff0c6e91106f47dde089cd6796a8c6c5e585cea5d0744a53c28efa2b678e98817411e583191d64ad5c3896a9881cd6e642b104ceaba79a47ffada4851caa7abdfd8803597a4b4c8f38e278d6affd8934ef17c495cfd3382cd36504f10f3eed146539caea34aca98987dd6f6a2ab44f20346477238e09335fe9ecac88f385625b2573710a88a48fa5da761d39a340974ba8bbfb6f1d5acdab9d8b2c7ceb86cd60ca7da608ea7e79c1659346cf59375847d48504b920364c08bf17d465c7eebc57aeefaa0f3312880108b954892aa76b5b70886e1ead98751950a4af8d5446481c7141c3351cedc596a3b132d471244df56c2a3c28a7a3e7d65762cb431a8e4c093401ad9f50f8366e6b24e9d0e6adaf1ccd219adb4e628eef8d033872c41ddb2a5436b91a8112df55813b5ad6bf96fe9a3b5b1860ee2e41f35873fc8141da0a6753120d91ebf1c4fc8b3b58d4bdbbf12449b1c48331d6e36ec303cdaeb58303eba7e478a2249bd6cf81c5e11018463ab8f5a4fca2813ce0eabef7d9dfb310060fc7b0267611463c81ec58753450ab7e7f58c7b3c7c286befcd33fc317c55c4401c1a1dc3617ffb7cd049998449927387e70d519b7d07ac617f193409e6a965ff20953978269c3e73dfeac852d3dd7a09a058d6a79fda1133992caa3c71ab2a85f857a05308b027b017d085d73fa9971e87e527e23299766a1079164e70d1ed7750ef7e25a976e69aee6e35e1e46802b958157043aab9f5b8132a250fa918cdbc69a8e1b191c06c2c433c10342e6f6e7422635058914c099ed0a435a8611e141b46053886315b8908a4ab6a0823aa1dae7329656270d54b9c9636205297171cf4e63c4db4e810078d93d765f78f224562a163a5d5770393bb54b666737a0a13fcd5e8024cf8e25973f36925e92823d81b4d6260365454dc01dab3a02b4190448549996fd8ce52a0cdac9ba702bc485d4a62d48a26650fc11c0eeb60232787508ecae3395529c41e86c024c40cd153474d8698f035e8fd450e41bfa57fedf841bcdf891e077c1c5893d7c5c8dcf0ae417f8d141f101a94ca97a859fca42e92f9db94cf11b70204cdefe9ca4e51934a1225d0820b59ab2209c7f1dab9df65e1bc80a3e9a862ec63f73cd38bc4b7794eec4c67691bdf18d1cf601da22bf100ea9883f7c079be1b45647b2685cabbc5f5ac0f43fc96ebbad1e3ce6c7ffe25e72387d0ec9f3efc81de04e8c6c1b3a900aa7aa9703394def15d532d649064b40ddd3fc1d71287bd5985667356034f8a39576b3492e9d6c4e1f685e159b40085473acf9bd1c9108d8b4471a62ef613d67fcf44b73f22ef17a03c9d10c310449479f710f7ffc66784d065beeea0977b451c98422f629da448a54bdc442b1e19a55e8bac544f6122b1b7d185ac3bd4340f93c3063dd337940b530c39c443d17f15f1bb7052402ea380961ee19a83271eb9c53341996a55ef77ba58a696e3cfd7c37b1b992047985be1a7bd26b053571d0dc84b1265a97d03614c2d45c0df3b61d09c790336d24226ba600c821d29f8d694bcdde887fe9f0c0fae0ee60ccbe55a520eba4ecfc7c9b734612dc9ca777571e63ea32b1738677fab634dd3f0e07d625b045142142d3e204ff5f937883c0fc6c9855a971421e7bdc38bca00cc9ad32f6a556ab243612d3964e30574bde4ed1abf7352fa1dd7ac0bdf387bcec1782ed6d1012886e81fd3e919a53c785cf0c28aae1248766ae9653ac43632c4f6d3123c240c6014ef90111248952452c5a8f19c98e1a97e9d856d7470df70046359900e01b3ac906fe305277d802781a7a02e5782bfea2fd290cbda2d367110ba39c1e3260a1b41d88126b921e1c34f8578a5715303d80d227de9aedf5337b602165972dc9676e40b9b118f8e797606271d736e42b518f74ae72a3333a847a79299b4de1db49f426260bdd5454fdf18b56daef690264e7e675b856fdade54fef5aac36c52657927c1afd0868c13b7ec29be409913cff2b9f357c7857b83321b3380396de09abe5517926ab23b40c68f8c971e6c357ac81e6694b5d23d2674711acc817b1dc6a1e9cab51bedb61eddd5b0d6502fc766505315e2993bf6cb0136f8fdeb9b9cb3ba5bae4d1a95275c1a78b159ee15bf47fc7ca1af3be779ef0c7a3f45e8b66b7c0f03cc8870272ddacef8efc3e9e1867e2ad2958a3d48800a8352a4a3de143f93254389db5330346705d7566c2a24e2a5c4eb5cc432d3e55e8aac37fe77903cf17a13e9e5da6e52febfb491528370980624db7427366cc841aba23a6680aaa39ee760f9c857541e6a6bcbf2a66e8197078b70361f465038bf9a1e44be41a48facc4c62972d2a2303dcf07f82b7ee979a31e292ad84009b529ff0512f13c9cf14ba87f5da317d0e3b468e9ab258fcc87c87c6cf0aaf7db05345edd6309e451704e85a52a2942736e69d0ff9a4ab7b35450ea9162286711d4906a5ce3ea7d3f79c95c93d772d10a39aaca284d118f31857213d9dfce4e0f2d80830c0816fa8c6850bb1f0a2a117879185361d7ca996ec4f94e21bfcf117e396de524f3e3778540bc06673decfc447b8536574bf8166febc99b876ffe55e6777e8ed486cebbcd594a307ba3d5da6e666dcb1ff95880614675aa92bc3f1dd7630ae7b84c07abdd42254b9f6961246f2f284b12e0e32265603d0df6d9b99184d8acd3b064a4bd22eb031e244d269308d4241b05d49a5ddd2d3ebad6701dc8eef502cf633d9892cf84e6c1bc2a53ef2121e8f791bf2fe36d631b5f3064c5ff47861c969c505b5d2041cc68d922bf12cfc6387d124b2ef3b22511481e07f601765930beb55e8781aa71cddc70856729453aa7350719d9cacc1e23f87b64c70b0ef52b421faf36b393f2a57889e42f59fbb16ec710fee23d770b5645160fd5194ce609b91291de4eeb49588ac272219fc701f29a2c3fc50dcdc0d2d01954a910b963313b61dc88260c7c598ab3bc79bddd57ca1d42cbf8f1f0d4b8186729ffbbeaa668550fc36e510fb3c5970804272f57c7622f51e63303ac3bf5b0ae45cb28b7c985889c39ccbe15b30c3909d093093aaeba34cd089bf87d16e07257cf21444863ec1d131a5e8a5724d02959e748919cc18bb8311d5c7452f390883f7b693d2a0b54519a6ca41f9f35443a85ca48e8481cb350851bea417ba42be4b3bffc76a7e71f1fbe9c9a8319f61a7abecbbf218c377c0ec1c5512ec379ab333cfef78a0f88bfa516e5b0dc37b2b9387107cd09c0a68454762f69d4601a500a0fbf1a5746c22efc2bda7fe595cc53263fb759eb0adf651ce221836c34c8e018a9d5cf7f11f0b49adbd2f8b844d6bc889a8a12d52f96543da3ac3d20f4f17509e76999212923d584a50626b54f4d50d0a389db3648d29371df62dc49ff938c4ad51d8e49805f266555bcf22bb261dc8a8efc0ca6f6d29aca55e110d92eaaae583d4cd784529f7998fbdff084dfc260eb1af5e1ed3a43993971a923b803bacb3cf3a493175152e8ea3af1e1862a467bd1d29add3a47f6911d651e4a526da163b8da718ff5ab6f95d7468cbd7d07b0323a75cdcbf7cd1170d185ab74e47fe508ffaa30fd847e38fa2b42bcb83cf67516db1b773c6c3d5a5cb22f425cb57d62734d1534e816c2fef0a7d30821beae76e216c251e9e55fc1db5096cd28dde7943de9858bae95b7e7032f2076cbcc2b7d934219ed0d3b29cd049ee94ec5ece7ea9f0c6fa2faf6615cfac2caa63424c72817baa90807bae132b06b21567393c8ab71827e00103f0b9cb2a6aa8e50f5260a301d36d6e2e29fe51d46f50b1a7fd7e89a790b98fe62bdae71b24981e1285ae27a8e2e4eeba9e629f477db6378aef7d68492553bf89a955b4ae84f96927035e374aafd9c7f49bc05de73089991669eab370d7a69bfa6f322134b78e67959ee7a2600efae6f37bddbe6c6aa49a068bcdcb92847dad27b4cff7b37bfaad5b7e441124e19eae304059ffe9fbe1fef5b0f153566c05ba49cbc75a057ef7f5f336a06ba58a4cce365cf207eac2ecae5abb2d9077bf252737abecc3cf30b9cbb68d66a69624eddf58e9c8d8e20f40cffc0905bbcfafb57c09571e635f3452e6a459dfa0d548658a9fb0b1837d10478c8b17c1300b42e8eb462eedfbdf85c5b7291c59a05e8bae729ca8fb7e9c32a00d8bf943f6412413f660c9807fc931294e5788ba2f184f2bf69e67703a868be8f0b7029284768f88634a6a185a37d1b4ae0d7b858837b2e23b07d9fd045d73849e5a8cfb279940ac515ca97131e703455ff844d211b281761c751ffbeb44059b32d6a8a8da2062e0a493db7cb050e3443d7f76e37ab19ddc5996828ae143c40e753f64a433b381424363dbd9ce965f84d001c686de80a04dd270d4d3e2c3a9ce3a5fd5e8c50e04280a3d3512f90759f2c4afe03dbbeb8cf183391ce2edae7bc81b62699ef006874cb0c95b8ba5ce0c5361c4e8ef358f106aff304c30acf17015144895b812b4a61b9ac841d8f4402f6484b275e18350278471fbd47981fca3a0be0e5740ec259867f4e88c716379f4fcc43dcd432904918a0e2a4e2615ec7cfc2584c202722413c8a843bc3625ed9fe76da0159d85ce5ba462c23d390f163e7b08c4c1f160e8b4989cad558d913696b06817912b730edef40ae3a1d727783ddfb5fbd0a8271d6d624253957b6209a3e2101afc2d2df082304be41b2141a6e5c38eb13df0874cf402c9cf57f6735dfcf0422e86efd775fc578d64f78bce8a0b1f367a0c7cb009935f30c13a7713b029f6ec3748334b3205c5d2ceca3abd81f032003cc90b6fb23cc284dd690d1be1c2bd3602b60891d3a52982858e275eb6a1ae5280145c34c207c556acd3eb36d771f10e13b1f3a1101c047328e40d4cf45bf7970f14d91c61811d24a852257d9bba4821db57af1b326100fe262b492fbd7f697fd86cf44b5a59c3e86d2c22608bffbd534846b9bedd97553d7a047e834249650679a7d018e9efa60eef00637439841e761b481cab5fc88fdf3c8d1d61e22005790c9b1b52da8160366b372087f3f7cb1eccc303a85a8879a10fd6cce12319c9f64b95a3367d885268d647a2ab5f43166b2d5f94516b919a55c6a03516207dec1c0e73ef454c3a52487552109cf635c1028883040af0969352b04f142c5ce8a2ac5a37531dd7b6a3557533c0ee7a25fb25eea77de284898a0e5b57066c1edcaa2292cefe1bf43960d7723c27f56b3d5054d037cf14508571a36ae42ba5f9eeda34bf5915907869bacc66ad83d2fda0ed5ca9e3b073ae8ec047d4add458669015850c248cac2f8b39f2da267264e7bef215c6ff4651b36cddef2f57453e5ab6de7ba7a7999fdc66fba3c60cf8c070dc2e0bd28c9f4cbfa049f4af736f80bfbc80d585831d544f961684a35b14a41dd40111c4274d356e9f2fffbb4eb77b0edd58a4490a34f5a6b834ae596f349ba131263b7e7318a4646c936475864fe6a14b0fcad82eabf7a355ef04ab0718a8a3cffa114c551f44a6a71b864420036885b89c998b7f47308426700b800176268b6b9cee4af3be48c003e6126cf4cab9ff061606686a373a21a7a4a61ffd7df5eb769063ff6bcc3682c5ec432757df673f9aff6c1a5e8f675790f8a6b8751d7c79f8db32b302c1d3a9b5108e24ff30c1f2e68b4801ad433b141a46e9c827c538600278e65a51f8ebeb8194c77fc99ab4c91a6fdf75c292554196b8eb006e652c7c97018db8ce3f7a21a73296bd269e6fc1c42d3d02bfb145a5e4202d6056f40562bddcab9e81e69add85439c933ccb2dee1b333181b2e174802c8cda0ce8bd936e20a418794fae6ed58c0e9b5ea91e61cedc091665bd7038d7af7cc9175e6457fd626c351aa03a5d76b86e8f090624dd7a6575c3f17994423f9d70677e3a84d2965ee6d4f70614d7c8998b741a9e9a81362a1b3f7746013f35ea2919966e3030799dfb7e263e63ed9a9a936a3775c17ddc139a2aa369d78777b53587088739a8ee9bcfe03f561541468090308e6d21db9bde1d40095d34a9e0a1513a7fabdade1309fa77f80d4f51bf8f92cd49cf74e48b80d0413fc9fe861e91c431838091e61bffe94a9a8f9b6448660dc7c3fb8ab8c6a9467c4b580fc6c588b702945a125368261312a9c40e781066b77dfd95afb2278b4a737a0ddec847b48045366688b9424a694390a111165ab4b28f2da525cffdd81f0e3624e10a52ba2f3891fffaa0ba1c650ffe4509794a404126470d811a81ddaf0464d5a8cf31b7238e75ddfa9999f975136353ac68eeb39d1a4f66a71170590e6ba91aba97ac7d039428c85fa425d6d707acf1411618a144f08549f74ac6938fdabc25e7b7a44edd8b3213fe6dfc62046da4aea5f4b85d48c09c01a994ddc9eb0c5a190416868476134b991eb66f16b224bc770cb2df36f42a33b413d36e3f02965f9a2c3bbfbca15be770786376e7b35e7c5a1c390ca07f98f358b981fa18a0a0bb6802d3a67c4d2545252e71ebfa6df775982ae70f9eb737ced39f1921263c16d261f5cb1b84dbf1a3a578fd9460cdc6122265527d34a19480ec6851cd28b0740a5535a9b45d15fe0f9fe60cfff4e8bc840a14ad0388df257375ef8c0729eeef028cd6aa863ea0cce6951d4a6adbd0052ea14349f4726ba763d366319da7e48191ae3faf38a03351e4a5af31c70e3e4f69cf995d783853ef70a9570ec0c7fa1893ddc28104bc29b905e66d618434d4a4c80e5e1503a771751e3f84836e63c020f7d264cd62cb39acac61b53609c3a399e2ed4436cbb5b83f185dcccea986e5371f030bb0e3a25316026166aa81c8a8a3154b2591c52552f1c30da447a2f8377058202dcd2dabc90976bc9b3a0fd1d782c2d9b3fcd68ee62dd5bcd2813c4d80025337a5dde84223aabeb91a12a52fe38fe7f2e5d689ae07233260783eb1720f652d20789dbdb794dba5c941da246396a4de7cf19fdf481ef78ff59be601f0a220b7e5991b25dcacf8edb5a637105fb139c8d7d04d9e88fe3559cf133aa38725b8a4cb00a491652676ca731513d7e03bca1fa57b648a25f1f7ec079b7a1aeec7598e1c0cd228930df20e2aaf0fb97c8cb8e4567d119d3ac25fee1c0e031575eb1e1e6cbdf7a6dafc444055ab1646ed0e0c63774b222b99e08096a0d6a09689dcf8b80271f0082babf29a6260a9ab5021edec8e6a3c7f915e0b742437e420443def7aa3f9aedbb3089fd0473200c31d7ca20e403d3bdcd40b6e73dd772610cd582a1d07d07500f8c043a1098fb3a120d93ddf836c3775a5997b9842bdfdc78615dc83d7bbe97ec7c1c3d4ec504158ab297b755facbc9ef00caaf5c6a4ac45e9dba22cc5b73350a107e123276b84d96601fed3f2e1af18ffa29517dc9cd046d273428627889fd18ddf6a8ac8901509d53bcb3026c62570a0370505ee1d6baeb689955c4b39bbff2fe875e5b9d3eef2a5f61b570ef043bf8d7b7d8090b37364cf01f7b5fcefb538998eff4fee8699e97fd0c91a62c4960b64e12454eb31fc19b3978baaff0c43bba5132c12c27a8817a3e2ac0bb37a74dbaf602504d61538ebcb03aeb277acc64760bf3e0ca2df55da1bcbd00187953c3cd968a90b74beddfe008f90be48bf959091b68f2ce78c0427705411b23fc2e764957cee78869647b67b61da29c33403df1c075730af2246ad2bbf059c962b84dcaaf2de43237578b2efb92b1f66cd6c29e5f5adc2304a87bc416bd71c53350541d444b768f9ebb50ffe3255001f0fc4fa804731710025f253bc005adf1aba619ef6168a5722b185d5075211abb9b09ed00db760dee50167d39777151d14bf12ae9826ddae793eaf601c8aac2f1603dd3b62fdb91ac326063c999e668d7171c98a91705a6fbd617041517afb93d322a823b06ea31a0d6129b0ff9d060305d6dffdd764d02efc129a666ecaa0f109c4a30209c4bbf2cc2156e984c9663ac4bbd655a4a9678e735cdd555c9b73e34480e7ff2878c5f0c29e6d2524ebdc6b67fbd291c3f8509500460649f3dce066879ef2c2884902790fb1309d3e3ecb6dd42179983bd11dc7c6180f27edf97a1563c385127d43166cedb710db3eb326355d00ac08aee1ae4b2b399f357695a41b25ee6dbca79d973e294a25eb06f5159c44f129e2a4068d1dc1eb8f1512dda907a11b911c85a54800f65d91e5dedb9cf1fe7aa027e3fef4c6de92c73e56f96e368acfb62fb156609c72dcf3fc882f9fb889b15b57840114d3709482805b02614c494e95cbc5e382c61857a1726ffa7a88cd135fb8e7ef8e8f24169aba8a356c0a1cb0bf90b26f0d6ea59bf882f653d7630503054c2e9785b21c83f9c93a33dc13c1cb3e7f3d8fd5f40e0e92af02cc4dc37bd1d49bb87dba6d410523b4031974279d9275920fcf8dd50b72e781161bd8a6f5a5b70b096d94c671a0bad05b3ece99921cc250884eaf550e685e12a6e00f59c8a8259c492973ed998444f5b9797b6c342a49aa808c54ef3dc1a65ae297db972936f7cb88fe731d572f423599630d979142643e263e5a773d30915fc2ed0d785197c6bf6bb86156607b328a58a4bbdbd8bb7eb4a2cca4b9ce799b20c8532751c2e088f3d0846326a69d42db34360f8e0a3c5ac1cc5dfb5ec065d68f2b4e5755f890491ca7e56b65a9e70817e50683241b2079fa9fe7f537f67e4434bd5dbe9b194d6913613143ec838a1ab8b219511124290a1d927944e270325cf7bbb21c3a01fe787364101d87777bfef36cc977e47f787d0c39e604f840834d9f086609a28b6b49ab83155ef32cb6193a9abddcb06a6993cb40a396c1e085f600347c2b7ea619eee2c5bb3eb816d2822c46b47d59f1b639dea69ad6a6fc19b2d5418eb624d5a92f26e550e71da463a9f0eba29510dec09e59977dbb9522c9eacda7a6ce1f07908bba9999b86087987c2c38f2c45f85a8de97716957581746b992239e0c96f6d275e9d07e36713de9a5a3becb94ec5621360f8d248a310075ff378af138703e50329bade76649dea85a90e5f07729a94cc8e4f48296f0a05c36c82e3500e6f46b9b1db46b420c39de4b7d1fb13e89bbe469876ee4b244f3778eec28e65f3a2c2e7b2b311e6f8d365d8988d5822feff28cab30b95fa085e2410d5eb82f5480793a9e8fa27063706b5f011d5b7339c03975413b49ad48103dcd770ae60d693b954a07fa8b9e0f2b3a223d82087ffe594d6d7829600273de919a96d0f2452c8716b0e2971dc02a61525f8694b8eba3679238b73ba37383d4718993a0646bfa1c85b7e36df79ae1261ff4ca2ce7b777e45a1a3517acff247e2222ba73f65befb42d94faa88a8c145af5154477f14b5a3cad90858143f159c5008cc5ae69a762298adf36ede7314fe0084538acb9229198e301e0ebb5ef62ece69eca57cd1fc0b905a662c98fa62a30bedbd22ff797add0a167e1e953918b132dd4cfcc8bf7b3ce1cf3002f8917dc4552848c9bc21771fdceb0fbd77dd7618123234b6743fd29dbb18c23b4eff50e38e0409f2a2cfe4bbe734ac85d85b5fc05191402986dc2d4a278956e4fadcc1d641158c05428f7128138c785bccc8c06c59ba5b8988c1c3e5fc92bf40a959662879fc2f4b00a462335ce971e7f7b7553261c798912ed9872328842a1394c84a2af5f1da00fd5dfaa87b37964b7ace8bd7e110aa7c7c65fce19a17c8049488e80d95cea228134b5f05d3f17cdbcba1887fb38279bb6864ec4ec191f1d8181784b135b363978b89358ab9bd8bf0848c1bfcc1934e2de2eaf3f5d2dc23d53bb0f415ee675bac37e5d1e48585a105c9478cd94ace5d1059fc3258f7cf8a197c9bd0ec4658f223053c53101240ca478c11bc6dd8b94462c1243807156080b7f827d94ec85674b703f5fcfecc7f90af2f65f9ba70bab70e474b37b2544a425df406dd0775a5d8719e2316963d53f13708b31a67d7a996ec0b1c4e320dfb25938a4d081e1009672e318779468ba2d5d507d924327919f0b7f76bd45a306cd4fbba5b2a0e945eab386caba321d452a62ce40d1398a7ca5e447329e657987178f006617ca5191dee1676d7a3a566f841c8b82cd9e89bf947c3fbee75125093190d512cb70bc167c29f62ce2c4d82c7279b27c011c3a1e5adb5dd8b5cf64a250c590a0f13be4f38ba4c688f6af4496c396c1ce97cd371499471e890f1a421b94d404192af783fcc4b7996a5753725731782f8b9cda9f82fb9a089c4bff3bda28a2baf48fd97443bfe8f95ed711efe9ccc4d2e1b65f5d67bc49503d8fcfeef5df2300b2f2df07382924451c22579bb55fca85f02e8fcdabf2a2ece3f429204423b39372379dc6d48b350b5c16e18ac78cf212b2655bd8795b21b689039e49820f4e6a0299d74ef23968ffce5c98393395d2833c092039a02861040a9253a0611f40ac89a828c9caa407cf9dc57d8b048d5a07341b8f9061fad1d678bcbe4988db97e9dbdb353e7a8ea5655554b9d7b5992d4983a6db77c5ec95a462354d0db9ca680e13ffd6ac07f75f52462151f914331f89b2dad85cd88d44bf800d4c6aea0fa9c48b7fe25b3ea46ecff43c89e285cbad27ad0ae245c46be7d0b9eb188bdabc3b9b501c4fd13998ff2498aa10cdb52f8e9aa2180b52dd722214560934856cdd413a0844682b450c072341c396fdb1e7232c83311f95461b43d907a6cf2052570cdcae75aec4ebc2d21e111223d0fc4d75df4d53d3bc893baa3fb91ee99b8009d76f49cdaa476894237758fd795f987ec95f88ebafc6e509a9c56c704d1e07772191bb0a9ea2974451471ff1131e8fb0880efec56f6bf6dedcabdc784ca30190db8aaccb5d972ee5227958df1586556fe6c9bb7fbfcc2dba5c2b9c78961327635d147f663cd76a5442dc54e0e1d3930f627c8fb36bd813d59c49a62f5c157c5b9250e58aa02851eea9f6a2fe14857750a558260552d504bb9039d777572fa71f52e88a1841ab10a54b7aebe94046a9a2c7621c4df3b6142fa3a1e2cda6332b927a484fb9578186e5e9f47438f4a2a123e3b7b34c88f5c51739649e5b87c5e0fe8ecd68a6278ce0afce79a7b82010fe7f41d71e73d804601364a3dee89b9b919d51e1b8f3fb696fb9787df427d46e75db528a051fddd1e4c314c3da0ca15e03c16be82a0816fc0840189b0ba45523e7fb1ae5a1c98b384689d8775ac7f675f7f1f4a28368032b30795986ed95033607aa72689c44551243416db292007da123b7700dac53ea18973b24c63e9f8e0331450d672b99d1a9bb7116444c01f46040997d6c720d836e0daa109368db89927d2d6280b22684f581cb129268295b281103746348c288f0e904989ff638892ddca22952fde2cc8cee6dcc4b3601f22e7c27f1f78427c324d57dd56437cb31462909da1a0e1485691a47858c36034ae13a2997b7569d8a81a62494bc56203c57a3c9a6bfa3684aea392df1a537ddaed992814dc81719e95e443a21a85d03f633438d152b2df343acd7c2c570f3b2bfdb0a057c86b3d800c827fc1d4d39a4f6b22f89c3774296da68ba5f37542753eccaf92a8d0742951dc2f4cf4a0d19de7456ad4f7cfeb1a0f6fcf9af6dabaf462b4ecced3d195fe1b2e82bae23af088ed48f9dcbe3704ff614adf382373dc8dd9432c39cdbd48f2730e08be81dcce2179494f98da010b7e6164ddd88f7604b1e813505b6803d9611fb22b86801b986ee8d72a5e6d25dadf9f13e4d7c558e045d6c9ec1f7a607414ed6726d08ac780a2dd5bf5cb03c8bbd896fb0d94aae4925eb2f24ca2783b7a061d9bed376b3724ad6393ed08c817aa5dd9ffbee22f3656d0948d312264976dae5c6b2dd5fe93dec513c13680c5371a6f742957e248ecedd5220472c28c930d2f2d863e52d15af9e1570a88b01c9632dcc7f038c4e264d83997f3694751f808788a7a652b5b00361b7588a0855f6fd123434766ef36128b2aed370199f1b98d62a7e8f75e6471e248cd7ad615d1cf5a0e037d894a007dd467211ed07f0564777b676f88de294c659b5b7ec9dc46f68529f518d85d5c9be6b82ecc73137a7c3a9192258d189ff7efb598d202c501c7606b48c899b5c9aba85aadabc1d67c055d998d2321016823e4dd6c2be473bcde5ad5c7f4264ecad21d7252bc5418e74c99d7db7675aa9b5383dddf1082eb6bbe1efbbd05487ef3a61315eef3933d32ddda3360712724cde070e4ed36349abb3f756881d3dfb7fc71e646277abc197662d1d81b24b70663b347c0e06a2c48fb23fb4ed42716a72c09033b386563a08968c5b55dc9a77c7789896ba14266d3023d388b1811b87d21454a90d8d5853183d3ba3d3d3f8af59167d120ea504acb005d73a8169f59c8c6cae07dd77458f9b28a11a6f08d65acd478c814d0eccd98ca43ba251804df69c446611a42977b6ef9c09cf906329317c0930a6e15832957e8e51f34ddb288408d57a55ccd6e9443cc17a81ad57bbc52928e855214afbf1fbe48138fbb25a71df3a1cb2abe803df77e7f7086ba591ecb7f098b0d96178c161a9ac146fa4666731ceb355c7c48baf392f2f02e3545d448c0237c4b552a6e6cf0cfcf28e130ae50e41a9c491bb05d6baba768677bbc68b682e136c6829fc30c93a93276ca96ab5170e3c41d47031a0c1de7fd5dd6da9730e79ecf095dda3ab815e3a7f451948a098bf915ca849de967d2a11ad8ff0376172e67b065364d3bb28f9ce095fd7f31df4c3e499d6129ac17d3e1a243937503878833ebc0280f781c3ac14164b363db94e286120d76eb905340fdd4e54bfe9f06bf33ff6cf5ad27f511bfe950fc8893ce690c41c30bb1a9846adcef56fe53eeb84398327326ce74b71f9069214cebea7c0677ad4c1c530bb2516bab0ca560779be256a7260acf5d576b9b3118d409387e386ddf67b1f02a03542b092edfb32be734144f947a53916972e39d515f7bf0f4839e721dfbf7814e4a990deaf77cbc2517c38d54e651caf8a34dfe0d59daf186fbe30b578aa59f9add67080011d2b490316ec124cdf0f936282d5d0b3ee9c1c79fe5f6cb5d7a3359f607b62472ea5bdc75008d17e4e608e514be761c2" +]; + +pub struct UnstuckSnowbridge; + +impl OnRuntimeUpgrade for UnstuckSnowbridge { + fn on_runtime_upgrade() -> Weight { + if !is_bridge_stuck() { + return RocksDbWeight::get().reads(1); + } + + log::info!(target: LOG_TARGET, "Updating beacon checkpoint to unstuck beacon client"); + + let checkpoint_update = checkpoint_update(); + let sync_committee: SyncCommitteePrepared = (&checkpoint_update.current_sync_committee) + .try_into() + .expect("checked by tests; qed"); + let header_root = checkpoint_update.header.hash_tree_root().expect("checked by tests; qed"); + + CurrentSyncCommittee::::put(sync_committee); + NextSyncCommittee::::kill(); + InitialCheckpointRoot::::put(header_root); + FinalizedBeaconStateBuffer::::insert( + header_root, + snowbridge_beacon_primitives::CompactBeaconState { + slot: checkpoint_update.header.slot, + block_roots_root: checkpoint_update.block_roots_root, + }, + ); + LatestFinalizedBlockRoot::::put(header_root); + LatestExecutionState::::kill(); + + weights::snowbridge_pallet_ethereum_client::WeightInfo::::force_checkpoint() + } + + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, TryRuntimeError> { + if is_bridge_stuck() { + log::info!(target: LOG_TARGET, "Going to unstuck Snowbridge."); + } else { + log::info!(target: LOG_TARGET, "Snowbridge is not stuck."); + } + Ok(vec![]) + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(_: Vec) -> Result<(), TryRuntimeError> { + frame_support::ensure!(!is_bridge_stuck(), "Snowbridge is still stuck."); + Ok(()) + } +} + +fn is_bridge_stuck() -> bool { + LatestFinalizedBlockRoot::::get() == LAST_IMPORTED_BEACON_HEADER.into() +} + +fn checkpoint_update() -> Box { + Box::new(CheckpointUpdate::decode(&mut &NEW_CHECKPOINT[..]).expect("checked by tests; qed")) +} + +#[cfg(test)] +mod tests { + use super::*; + + use snowbridge_beacon_primitives::BlsError; + use sp_core::H256; + + #[test] + fn validate_checkpoint() { + let checkpoint_update = CheckpointUpdate::decode(&mut &NEW_CHECKPOINT[..]).unwrap(); + let sync_committee: Result = + (&checkpoint_update.current_sync_committee).try_into(); + assert!(sync_committee.is_ok()); + + let header_root = checkpoint_update.header.hash_tree_root().unwrap(); + + // Header should match https://beaconscan.com/slot/9094528 + let expected_header_root: H256 = + hex!("84a581291c4a4fe66879c4647a1084ee584ea5c8ac82009aee323a66bf865e82").into(); + assert_eq!(expected_header_root, header_root); + } +} diff --git a/system-parachains/bridge-hubs/bridge-hub-polkadot/src/lib.rs b/system-parachains/bridge-hubs/bridge-hub-polkadot/src/lib.rs index 37d537ba48..046e66e3d3 100644 --- a/system-parachains/bridge-hubs/bridge-hub-polkadot/src/lib.rs +++ b/system-parachains/bridge-hubs/bridge-hub-polkadot/src/lib.rs @@ -23,6 +23,7 @@ include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); pub mod bridge_to_ethereum_config; +mod bridge_to_ethereum_unstuck; pub mod bridge_to_kusama_config; mod bridge_to_kusama_unstuck; mod weights; @@ -149,6 +150,7 @@ pub type Migrations = ( ConstU32, >, bridge_to_kusama_unstuck::BridgeToKusamaUnstuck, + bridge_to_ethereum_unstuck::UnstuckSnowbridge, pallet_collator_selection::migration::v2::MigrationToV2, // permanent pallet_xcm::migration::MigrateToLatestXcmVersion,