fix(vote): uleb strict read#1589
Merged
Merged
Conversation
deserializeCompactVoteStateUpdate and deserializeTowerSync used std.leb.readUleb128, which accepts non-canonical encodings (trailing zero terminators and oversize terminator bits). Agave's solana_serde_varint and solana_short_vec both reject those, surfacing InvalidInstructionData via limited_deserialize. - Add readStrictCompactVarInt that rejects trailing-zero and overflow terminator bytes via NonCanonicalVarInt - Use it for the compact lockout length (ShortU16) and per-lockout offset (VarInt) in both compact decoders
Codecov Report✅ All modified and coverable lines are covered by tests. 🚀 New features to boost your workflow:
|
- Add readShortU16 mirroring solana_short_vec::ShortU16 deserializer - Add readVarInt mirroring solana_serde_varint deserializer for any unsigned int - Switch arrayListConfig to readShortU16 for strict length decoding - Replace local readStrictCompactVarInt in vote/state.zig with the shared helpers - Keep split between ShortU16 and VarInt to enable line-by-line audit against the two distinct agave wire-format specs
…arInt Switch all remaining call sites decoding agave wire format from std.leb.readUleb128 to the strict readShortU16 / readVarInt helpers, matching agave's rejection of non-canonical encodings. - sliceConfig.deserialize -> readShortU16 (transaction account_indexes, instruction data, address-lookup writable/readonly indexes) - Transaction/Message manual reads -> readShortU16 (signatures, account_keys, instructions, address_lookups counts) - VarIntConfig.deserialize -> readVarInt (gossip wallclock u64, SocketEntry offset u16) - ClientVersion bincode -> readVarInt (ClientId, major, packed_minor, packed_patch) - Add agave-derived test vectors covering aliases, overflow, trailing zeros, last-byte truncation, and shift overflow
ace2337 to
e5bd3ad
Compare
hamza-syndica
approved these changes
Jun 16, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Intent
sol_txn_sig_structured_diffoctane lineage fixturesImplementation
solana_short_vecandsolana_serde_varintbehaviorRamifications
N/A
Tests
Fuzzed
uleb_txnanduleb_votewith no crashes found.02fdd614d902d65b69e8bb154ab40275691c4f007e6a008e9a2a718baad67936070d9cad441f8447b3e3d492cff823b9621f166869b3d3d8f195015601f11905075362308a179e5b40e1243628d03eefda1870e2b0cb7ebaa5c8405bd1d11022075718aaea7e522a9b9f3c669f83cda64a959a978803e1c94081aed69d173dfa0794de64ae73b418ddcfb135c80845e28eaa5a747f486478ca1cc7aa2705593607bda3b5e3b42b6627112114e56511bea74200126f82494228147cded6da5f890aa7eb5085d9bc27af4b428f38a9c43cb07e7af973773288f29189fd01aaa30e0b911f32328e864e6c4a0ffc47bc01f11a8d9e195b43ba606e6371061399ea950c795b3ba831767f7a5fdec7f8c1035849a3d12d9c9e7ff87c68b214887975f10cb44ea500b1648df21f5ac52dbac744505d640eb4f3812c1cb081f3bf7cd67f0da1270aedbf3633d9e5442952d9ba8efebe41b5822f61945002d4203ba8f77a0daa83bb32abeec85fec05d1c588406d1f5ef48678cdfa4d8b54818e8d3dc5510db0662a0d175c7091f2823ffd056dca9388697769e36fee79aee262f8aacc6e0f474aac8dcbf68d2e723554a20aa188b0b1d7cac1f46b81125e2859a654d2dc11fc3594f184aaeb8879624d408ba91e4c50acda39abee54464125bd55cf6e0413844b2f1969f61d01743b0a248882bde08518ead3515cc63cfdb55e11c6a50a13a091d5e1c7d18667d30492b4e55277d8e9728dc674dde22a9870c0905aa42c14ebc8be4c853ae4f8a0dc738bb98776ee80d5213e86e68352ba1e422595af4a15c29d3f30206ce315cd47844dbd24dfb8b4bbc7a1ac978971ddb24ab384114f15e4ce1bce707b530746fd74348d7da44fa19c34cef08c9effd0633353cfb127190cc1150063bb670f5fb48ba0f43cfb09acb0cd2bfcb0fc1d91542e7904b226191d158924fd376d84ff24a21272649373bcaf7a4776e39aae7a07b5123101d61ae1af407826caf2e0835707dfe6b424361e644e2057c818a1996959d68913db1ae9e0e7fd98abe1c3ebc2fe54685f1e8100ee1d477aeb54897c1cbb2c7375661ba907c4743f659c98745710554ed42b658ee4da0b7fb5b1cf9b37d5bf5765441d8ed7588bc64305fe030de6640363f1b5a15d655bfbbb86aaa3a32db429c4c81d93e0e5bde938cef29eb14bb79c47eeff044727f7098170e7db0a81376c236d1dd9530fe7527b03bfc8eeab70ce08c858fc3e164564d54ac93126bef96fdb241eb30269bfb8df43140f5a635207c8140eb0022f431f02f184c6e66a8ec04759201ad1a394e6980f5fc993f16de80ae21c67528df5dec1c9364313bd75201eee20d15a1b85e76eef4fee0059428bd447f3261d249364ac0aa5e278dea2743b5a25353c9197efe2e89fa6829451e38a4d374fcb984f9c08afcb25c3b26fcce0e12826c48fabc0fae980ad01fc106763dc77c1a4889984867ea9909433dd55dfa4284ceeb2c8ba415221e1f7ffb63e295f46abb8f07a8d71ada16fafd5d5507a1d28e5fb5f439e7c7480f1d62427c1444ab5f17397176f97e072c5e4a3026724c32975e816aab00f0bf5ae72d50edad3dbcb51611fbd51c7188db3a7b627cb487729dd575c4d22f747185f0ff5a52a6a39c17aac9def04069c006a5d4a1e1067292bb6b5d8b2486ccedb29092162ee7bb12e7ffdfa604efa9845773190f191ff032c436a5cb43aa028d2ac1ec588b2496fb740503b4f02b071b02b00d6c3e75ba02cce836bee5c17fd75492d4d59c3a30430281956d6d534177946e4dbcf0f13d32f6a1debc8717bac92d2502e965a7c2a876a008aeb9017bc2a2fde0e4681d6922f7fba2abe3b1b15e6ece130a25a615b0cc8f15eeac7c3895109e35d49a7b754309dd9bf4d4ab0922028af2b32e037eef7fc6f5e8642bf2603750323b94de27430bf998ed12b225edfc1b5e444ec99339af3a285332d199820ebb14678df39b330e8ea9a2b40b88155d41daac9cdd83286550e879ebb417be1b9365b32525c6c31716778bfa3092354a8d663cc75beeb3d65984d683db16d7887e45d496afa87321efb7bff34a3f9134786b628103ce89ebc8dfdea365b7e1e189c345c1f062733747fd44533ea056a2a807e8b33ed0b876e637a39c47fc460344765a8fbb31033c4b2ddb479e0976a6dd9fdc0ac0c405975d82d5bf42962d9ec92b34742b578360d502e29b47dc96f33354a8362efe65b5bcb88cbc9687fd84dff2f2743925e361cd87d3ac8b5fe51aaff644a0f69e18fe7ef00dcd53d8571792e7ad6dabe7b36cb0e00f519b96168661834d75a300b4ef33b14e01255c6eede1a93b1b7a0c43782e81782f6da71b13f885d3e418e420d09a366d92538da2f44b3fa3d3f2191379f1c6400abc9df503087c686517b533bdcd362e02384ac20662941475fc75d381450b22c0c16126207fced7507c2174b6634da3dee808e4cc86e22048254963876a896e3d279e1bab275883b0a22f6d389a50d16633cdf7a78a5911f1489f43acf02bf579f44f8d5955d9846682e5a748ff2bfb0ff7ab6daef1999a7f479813b4b74796c488757489dd8f791f87c47530969f5c0df8297b53dad11aa0ed2b23bd391830946be47da5d84d44cd8773644206e210d3567207c91083caf3fc1913c25535c42c2be064eb6038379819b10e29372db3c993a288acd8698d072b5703c4393708e9388cea7806bf02857f8283053a2048b46ff41e9bf8b5b05f8c35d3c4cfbf79955869b873ffc997c7429263bf5827505bb9c3fa4835e2ef86ef97b3c9055c5ccef8039e7cfaa9d4ed0b9064aac175d8e51a81e6465d1a368ecd8133d4cdc440370844a06b3aa359bc7f8b5e6f2efae405740598880fcfe66fdff21405c3023a1df75d05aee06c5d4485627448eff8c7ba8be1ff33f5a5091ada02840a372da8b0229089af884204423b02c1789c3144c829e523bd7e9b49d6e14a240c293e3b622e6d1fab49cefb3fb274a96af5c35e74e0013fa3158393dc89d9241028f8dffd48e303bbbeba95fc537d533d869ae177f4910bd3bb67d418db05f42292e345fe4ffbbc14aee646447fcae3c1a4e2f7342faddcf58d7e14bd1079f425009d28cf038e4ad6a6eeca7d4d98f23a5cbc1b15761a5cbbbb4912d4ab4e1455c551812e517b05cf2e49897d8b0fc40c248765d48b297419904f0dc2452f24737fac1875d8cbcc43c67eb76484bc5a335bd49aa1b70765eaff9be0905dd94482b145ac7c92e874d33ccc0832bc0aef45281bf79414f144114ea787c95367c496e2b340bb04c353ac573245929b253338f4e914c857ca696ea48f9d9638a8e4a5635729b7454eca6909bae799e715a267c1a5a3c83eafd9a2b1959f92029764af007b1f7379014251c224c3beba8c7fd76fb0d3bef60328acc61c14adceaf94bb5dbbe3bd65e37e5f097157aaa70d6569f69f26fa36ae0f02ef1c2cb28ece24d88dfc8394408fb4ff6f77b86b109d5b068677357127184e6253c26cb2e42a04dec2ed67302799172942537445e312df0ed2954a0335075ab5fe0fba3b3ae364e1e3a5eb9ada6f3be35cbb0759958da2a290fa08d5941544b027e9f0d0f99434fdaf77ff339c13c3b632188980cb82394637d44027b7357ffee4eaf6d07a5c6503bd68c6b595f39e25352a8d1075c287e9b18e593e589dccf546e648ad45aac5163223749b1989ec082a23a92df53a666d01c79fea2657c561cab9c81a68d3d5230854dd80355c4c2ccf06780e41f5f8bf9d6a3f77ecc63583599f27528dce452f3e9880ea7e4f3ae4d146073a5efaec4efce2f1a732b5a634a1c321563a1c95456830755ba22b8fc37b76d4907f73fbbc3f6ed9574889e2d3645b6c65e3137553a00b01a6962def18321506e9a33b5e79790ee01f51de3c088526321913545560de0e3097a039aaaeb6b3fbe86355901bef984eed6f86a1b8a0b41a6327cad5658cc453e6f55f2d75bf855b7b3734f2d5b0ba8d2258fbc00aae203be5a16e55729ec7d87b90f3550afe6311ce5741fd4dbac39fb2665b3245ef6fcdae6989c589d0bad601a73de6bd973678a2cabaeda15d50ef34ad8bca158131cbbbf3ca958a12d5218afeb7231e00407d14cb1a22eada7127e4208d056ffe6d5b4dfa8be5955ad958c2349a6b8269d88ae4cf9df9996b381ade9608ce10f0c1d2300c62f5bd6bac734b632ac7b79479e17ff8030dff54a3ade61ad6255d84e31d8c081d65d12f951ed5c48bcb01c5c339c72ac2d6a9ebe5487db7f7c4503638f55943a1f5f755f9ce249e973acebe1fde7763a5babe9f79c0c0255c52a42ebf81905f6405fe7a75212317898fcb728985f6d0fe5ccce0d32f110ea04994958c5baffed4261a183a8182fcec373cdadf3e580d43a4992558b8ed3b3f2eb02fe826ebd7a52621619d70bad86d9f9bc663515cea84a6fadddf20a31297f683c592b343d1db962bdce52cd22c65a2d0f7fa4c150cac2b168263be8ed0b1170d9bcee6de3579f62efbb85743819accb8a5d5a905400c323b3ab6f82f36251293f303b15ea50d6632c8dfa1d87c5bc0ed8b441749d48f175422d3af16a14e2d21471b1d8376816651f0b436f507e18e4fca8528cd9f5a4889c67587adea7f88d2d4c24a1a3300a6626cee7df42e91bbfec46d95a28db020faa98999538d07a7c8ba63e6c0ae8f967e8833ac7e1acb4f3ba9d165ef739d237c58e297eaf474dd0785d4d8fcb82be68233769a3af50c2b091e39713f4cf70480f5bded3b19962205e4b9cc638fee36b44597437b22a846c1e09e44d413e2d4987ebfbdb6828c54b9ce505a721d2a86c212734d816636d75c008215978e94b20a80bca17c2fb257703a7a308ae6ff96c2cdfbf905cad616e6a656c7f7d2f6688de5905f8a0d6b49ff5be978efae8586ce433613cf95392259777df83d7c93abfb374c1d94b89348a511eb9ff48a6556e2102e88fa3312ece43fb6ddfbea6089116f7678abcf2dad30c59c5872f9fdc71445c50de0d68164742c7e27f0b6f47511fd682b2c58732cb1af7631702d6ed718b1159cd092aeb2e82a16a3a6b8682806fc5234f7178d9d38e11b9dcb5328272808703cb50396fa6040830830433959654feb7a76b9a69b9d683549f60a6d6741a09d793f3849bcbb3ee85c2991c0b4d672dcd97fa064eb56e27fb0034646f7595a27587827496f56d1933a79fd9c05f78c4e55ff9f9d1fa03fd29fe7eb442782d284290b18a9b6433a0eb9bce625f4f9e30c1d66d8e5fabcc087f893cec9979f639c85a1a0128a7fa5593cca310fca06a95994d3a17b5b08ddd1cbeb192ec7aea2fb2788df4df9d145c666ba997aa54c561a4ab4a8a76f250d3f9e1a56f607ba81f0c32d55c9fe904c6a72e982043523675aae214a2f7c536dde42e8b25857c58f537eba6bfae0cb1c096d41baab366bb8f8251b88be76cb8d711871f2d417caa47058169a6fec7fe973a27a5ef6853ae6d897546cbb888abe00c98a22c4c7d8ebe3d204c39d3b7e192a515fabc033023024353c6b9ed6147b109f6a316c87dc94af879a1d79539548f17df80824ecfd9541a0b5d8e294adeb591cbd645427f9039ff363aa69d5d9d1d12d9901d2de80f3e4af51648d63d367f5082ec414b81307264244bccf2821f835472178137bb7bf6fcc50a657da391e06c26a48e2581a0900225a3990025f7b8de1e32a06d67a3a4921ac0d1871a84234e12aee96781b8be2c4ff29aceb9b8cf005ff7c57d47a9fc0c678ad8970475127ddc5f10f9840c730b97ffe9bf00964576873771787dd5793cfe9f0cf592cd9cffc9f6aa478437ca5ccfae3a0f80510cfc69cbe88ebf71c10b8a44a9b9a0bce757ec0a053385f60d44513c4cbe13dfb7eb44b2f31a285b7174a8e0b68351e168993df9c2b387283bedefe23b60bf89dc77f327b78c395f84848ea32668b03a2adaa4a68bb7885e92aa795a39c8874174b7dd569927a5bf5c65eef2137e0a4ba32a5eb2c0c2894aacaea77c1eb29a7336ad0bb5942332f16a83da85a0e98e5c49c9983f95868ec96de6e48cc67e601380a61b3d84fb61d5b2f64c8143b016065fcaa72fda9e9142cd96f11b3b3233e4fb5204a2d413dbeb7ad8d71bab0975f71618d562a9b3919312b298a09f26e93a030b03216d8e0393787dd345e8a60829022dc73f391b93ef1c2a56cb39b8a026d4630e9baeecc0e085d96592de1fd18ca47337d9ebcc93f5d77ca9435112d52b013c836c193241d5277309ec204945054077ed260a61947f4592e925710dbcb82e4475bab6cfeb3ae6d37c1b02de8fa6ec474774d7db949399fc2de482eb2a07cdfe06b26ddae37ef971074aed0f4ad929e3c3da7830990e2fbacec41dd5dcb065e656abbe4d3bd7ec38e83b7f79547cac1a881e662f9b796caec3a7efaeeae0f9f5a6a372c6930be10123c593924a3b77fb81cfd0bb9baeded9d9b6141c247ff604536e304759fbe2cd414373a2d11f1148bebacc989c39f64ea3759abe385277ca9fcae7658917cb3b56f07743d0bc2f19d94d33ba9ca39cb44ad364b8ac6c5d39b5b25f85bdca064ed5ec27f6af9cd28df194ef939ca98b3443ed0d17309302fa4b7d9949bb0795da73ea7d139d879bc0cf6d42469cbeed62f3aaba23028126c3ee3d75bd6b4ae18ec78cd52ab15ab674475033049d9584dd5eb8d52aa9df9bb96ceb95e5bdb79f8c4346a473b9f97af42f8a4ef79da6de5f1d5fcee6f2716f69f5724227e10cf42bfbcc0d3c1a95719e441d07bb9ec673d7f8bf292b377b2f6cf7c1e6f7d25b100cd7af71fd3ce46fea61b989979f3c7a8db1e8d74d3c73d4e7225872ead02f49f1ad0ae794273063f40516cb489f97955fd60a53bfdd4b983bd8fb4fa588136f65db70e9ac02936e5ea4a1df839ff27623937a7f4ad3eb35565e647ecd155102d485606f6bc9169dd34f534e44a139fb0fe2a77b6f9c54054c85beb25ac12dd507c34e340ccc3600c64fcbcbf6a26d3f26ef150dc6deb5b757dac16739c97d58594a4de144ae8c78dcc24d70d3a7166b9eca0491d07ba414f93d044e3ede23dc7dd9fb6a0dd4c779931b2336d8a79fe6548be7dcf57f0fc51ea007854527715ad25967829ded0317f8a0ec6009a9086af582a8c773db24aab2a3ddaebe6c82ae444435a2b0a98b08f3c3e313b9a967fdd8f32dc90f32055dc34bea48a13dcc7f156725b401626f07c2e51b548ba9f22ecd3a4d32f8a3305c518c9914bef88d23a0ba1e370e5b208842bb4e2638aa7465d3c6ce7ab4808a69e7e805ded41ec9aba9a33bba1d8cefa1cce9261a71ab1cdf147bd525e71a14a2b91b57d248ca197da899a56c605a16ed699ad822e1abcfa5744c7cfa22a51f1aebb7f237da5a81229027d43fbf0367881cd5bdb753ac1b7b9e2f9a7b8b484e5cf9b82217fdeb9731b8cbd3a942bcb217f2bd374094acf1b5ef98583ec77e036f3401b1c90e4124b0e3049a06fbb7c1611f4d58cc61b13984774b632b1b06faca36519c4c104f4364e99adbb8970b94a72ebcd7b567b2047717c26a04c3097e2659816d031749c8d64d6f44186e7971b40907e475dcb252fd9630caacc0c1aeda76c301b0a50247cc05f938bad51efdc125310acaf9b29441e1f73080f36eeb4e3e33f4781faeb05866fb4b042fa834e5f10bc520acb353741d39e8de593f6949dedca7f065db395a50a8e1bc8e4abe1a528513f48bb38c67345967f1c11bdfa6edec31eedc5b7aa984cf09be62479b81a3888d0492b403c7f5d165b00b7046ed5f2eecc98ba89919510b16332de937f9098b81294db545ade456a7608389a8531e333077616dad3fe897615a5daef7a7e11a274b5eb72e8820239b1e53616a2eae6bd99a62ec7783a9036abd8042e28a7ede58f0caba9bf59dbaa86be10d8f684b1977cc04501241572068cb806ba26eeea5158bbcbade6c0497f59ac41c8661906c29426372bd01a6eacf2eb11dfa7abc8d9ed2b1bc46bd378236090680a3e22a0b49814e39f971eabe73f21eb0f7159dafee0c41bce0061e9e21da571e36800d6f93b5919e0e8f586ca4a96ebea31a1e56fd4292bcf86e2f67b46d59ee149a6fb107bf8136a5b2bde5e92ddae8940ce35d70721bbe581071830cce8fb69aa534142f02bed10c150ed7b848c62d0864ca40191e9fbe816b314cf014a1b865d4bc2824e172ee01b91cadca74d0651db0c5bfcbbae8bf7ad1bef27f99d76106bc4799dc50c200ab6ebff624e15e3c82a76182626ea9bfc220945997530dd22a4435e52d823bf15dcd7705cfd801b7e547676bab3ffdc0305fc3a46186bd8a2a12cb63cfe86bc9ee6c613a021bf40ebacb4cfba3cb3cc10c585657943feeccb9a9a0480bb7c3ef82af8a706b3f23f1b1c3da209a551cc1f0facc8419ca8586fe2084044f9d97f73c4a11def05578ef6de08e9d16eedec2078320875be8e50121675ca43dfe8cd6fb0cc3ddd21c555654c883177e5cb4c302c3d8acca47f5852a5f75d25196bb6d60b5043d4370337e00478817f4caa3c3129aaf4b3699c98d6a1e4507a87f758a35fb56af7d3f53b48ae17129db8b96c46010a11d732e8d5ebe6015d68b7c3dfc7df3a5659dd30179a1104e93bd49e2c75ad2d0a1cd548ff6fe108da242fd22b5c08081d401e7028693ff628c8ff97bc77a5b6561353480677d952df833169b3c40343966c6d7e93acc046b428290c4c87ea54e588e2cec472843d04c124034b3e12f5a64ba4ffe285afb4a75f43c7fc99d1272f257d9c181d0fcc2e77389dc10d258189180c432d53c6bd95bcca2bbc9e83f274833d63453b3155dc254e647068544a20b1c0675874952eb51470384cbc067a0a0f07ab26490303c8cd7a9e6482123e9276375e9504641881c18be95cbd7fafe6b81e4357de0a0b0e87423a85193f317ef465744b878f97a170bb3f9cc18612187ce9ae1fb27c0edef6d8ffbbfee2c540429ac77530776495b9ffa7ccd2f46211c9ffb0ef5497d2d89e9704929bc4f07dad17ca99f53173985cd341acdc57bd1555e067fbd3d96587c37afd94b66d732c759e5198316a6a5da7357adce6a288a4eee821b872f4ec3297da6bf682e52a5796087f40e80e7579d917710cec23d3c42fb904ef6d1576990ab9b451a436f35f17b34ab158f27224ba2cfeecf644764df0bb7701ebf5db5efa40753e706d449f8002fa77e5d76a1ee041edecf7f729886d2970b3aa116cacb5faa086d44cc0e03ec2a3ad170b2f3d5ec0f24d07dd615ecd5931f94d136b2ace5e01ef04a8aa9f195e725dc6898bc93f10e40d1a654ce07d5b213deb5321a7956f5ad9483e7f27818d800003cd272fdd54d17d39ccaaea1f8c972b5ffea422085f7c8279d9e3bc5ae1cf25a64bf801fdf649cd430c391a5c607a2268a3b14c8f765ab9030689c949fc848ce30e8e052334981d5ee3f3b6c798fcc174363dd2e6737efa0481cbc21a132399c5af0bbe77d7a6bd6a34d73628246a937037ffcec7cdb19ea2ac519a55c734d664e499f06acfc79d72003701c9bb81a0dbdd740758949c56b103a3264f4e7f1d04024a61784911bda71de78186a641ca4cd144131dcb1fc167dfff0caec388b5c7d608e99ff1d74da81a8b751b9a4a070e14f8e481ed8999422fe7bf14f77aa3f3f71de71f36744dccd6eb148780c9caf7651a7c5be50cf6a5674e2e674d1cc180ac2084038a6a0dd4ca35854a476139e19860d0e4f107899ad315397f6b554c53f29957c59c554dd74edb48b7af97ae5a0899c08c98ab73f9dc393ac90963ad202771620da9530ddb411f838a83c9af09ba45b8af1d242784576279c2aeeed6e808c9599c3f857df39299f661c6a5580fde9d776715288e7c18ec98d6a21ad22c561e64c85c6dcdfbecd5a5ea52d4f52130cd4e46ed3a9dc74d43a4e879f0e686e50ce6fb5c961e06e2af40a3ad536012303f1c7cccd74c8427d0ff4028a4a7ed35719b22780cee185e6a6737026f0a5763afd62faf949b7bb8ee780c2cfcd691cd549017f790ce21553ee2591932adf0b1f4e464aceb781cd359246beb44f615fad7448abacb4e2413e3ec0b282ee53f6fe81e2387595ca68c5f732f6014c5f56f2cb14ee027be38381d0eb7ad618003addc703e6c1eed7d44170b359f2a86cc621a3b37b6fa1e68432ac123bdd94ba731986fd6b6e1fcc4ab35551813fc33a8fc48b3526d167e6d55007a45d959e2e8639e2fcc70faa17208304b4fac320ca4b891d89da7cd5e7cd050a543a505c96a085d4242cb7fca1b74e2bbb5224d8f71235bdab5bc95be7f32f2ddea4e9d87085ee5d02ca8ca4859cf1ae79094a7b5d485bd9e4152e96e807addec030e76cc0f139c70824933ba10d6833a42093d368e761dbfda70617e8467b43974dbf61d1e8f5a8392a7587bfc079ca6e2ae34ec7435d9ebaf83270e858d5a6fd2497c8a0b26f7e72c0cda2b32de3bc0925996a5a4343906924f899e86b4c6bdd3242e1b60caf4ffce7aa3b061524de485cb7a4e36b28c4cf5c7575ea15010181f0b8178d33f79c28d69d241f5faff10b023f9435a9503c1e95265eec1565c61bae3348afb83d835749f62af239809ffc8edaba08bdedccc299a58cec545dbc64bc3f08b5c42c39c680a485060e82f7a2ac6c032df78f324b0f04d4ed0c4ddd190eff623a6cc7ee7e5e54b0795873d508a277f959f26c460705a72eedc220270dcb951ad970858f5f61982175c56d573b35d8e4f438e06f02ef7efdedd5f5b329fb87432919ca97e2d900ae3f03c3601d6699c22b971208ac38b45fedd91f827ca2f18f0eab3e3832e872be04279bd519674e10e405c2fb7efe76b1eea94d9e135a416b3a1c5654c11321a1560bf228d3e8556f91404196aeb68683ef2fbd83a524d7ba1c44dfafe2601963f45630c071734018ba4b5b96f910b0e9f2f07aa2c04f819be922bf202618ee714dfd3e74b92dc3ef6ad270a673078becf5a15a019a2163e93511657dd5dfb4c4d3c65e1c75157f5dbff2173b507c1c8df6f9ea79e78eb362041b9e1c4f7a02d8f741efabd90ad2db1256ac6ce7a0a90cf7c9d443c60ac13247d480d141c8e09d42c391ec6375cae4f195d76c295fc38ef886f442155114aaf9d94ffea792cc67c0eb76030a8f7f139304f2c4f57843d3fa26da3d0fd91127169743e7425a025c472ef2d99a761e1cf4744c5c2021bb43fa9b98cd7d5dcaf7e1948d077904081abb6199c41139c795cb82e1df4ca2b2bcfac4068e5af04af0d7900dfffc795c3c09c44787f991be3de3ef96059c30c1fffe49f25f57170c527a5c04d57f81ef32c1bb30f2e909f352ed23f3bd07e9a04b