From d521aeed58fa5bcc5d363c91ff273ebe7b59007b Mon Sep 17 00:00:00 2001 From: sanket1729 Date: Wed, 3 Aug 2022 12:13:07 -0700 Subject: [PATCH 1/9] Remove public has_issuance field from TxIn This required the user to explicitly maintain whether the current TxIn has issuance or not whereas it can directly be calculated from assetIssuance field --- src/pset/map/input.rs | 3 ++- src/pset/mod.rs | 1 - src/sighash.rs | 2 -- src/transaction.rs | 22 +++++++++++++--------- tests/taproot.rs | 1 - 5 files changed, 15 insertions(+), 14 deletions(-) diff --git a/src/pset/map/input.rs b/src/pset/map/input.rs index c7801ff0..dd1481d6 100644 --- a/src/pset/map/input.rs +++ b/src/pset/map/input.rs @@ -395,6 +395,7 @@ impl Input{ /// Create a pset input from TxIn pub fn from_txin(txin: TxIn) -> Self { let mut ret = Self::from_prevout(txin.previous_output); + let has_issuance = txin.has_issuance(); ret.sequence = Some(txin.sequence); ret.final_script_sig = Some(txin.script_sig); ret.final_script_witness = Some(txin.witness.script_witness); @@ -403,7 +404,7 @@ impl Input{ ret.previous_output_index |= 1 << 30; ret.pegin_witness = Some(txin.witness.pegin_witness); } - if txin.has_issuance { + if has_issuance { ret.previous_output_index |= 1 << 31; ret.issuance_blinding_nonce = Some(txin.asset_issuance.asset_blinding_nonce); ret.issuance_asset_entropy = Some(txin.asset_issuance.asset_entropy); diff --git a/src/pset/mod.rs b/src/pset/mod.rs index f3dafab2..e98b187b 100644 --- a/src/pset/mod.rs +++ b/src/pset/mod.rs @@ -245,7 +245,6 @@ impl PartiallySignedTransaction { let txin = TxIn { previous_output: OutPoint::new(psetin.previous_txid, psetin.previous_output_index), is_pegin: psetin.is_pegin(), - has_issuance: psetin.has_issuance(), script_sig: psetin.final_script_sig.clone().unwrap_or_default(), sequence: psetin.sequence.unwrap_or(0xffffffff), asset_issuance: psetin.asset_issuance(), diff --git a/src/sighash.rs b/src/sighash.rs index 10a33c22..63ff0026 100644 --- a/src/sighash.rs +++ b/src/sighash.rs @@ -623,7 +623,6 @@ impl> SigHashCache { tx.input = vec![TxIn { previous_output: self.tx.input[input_index].previous_output, is_pegin: self.tx.input[input_index].is_pegin, - has_issuance: self.tx.input[input_index].has_issuance, script_sig: script_pubkey.clone(), sequence: self.tx.input[input_index].sequence, asset_issuance: self.tx.input[input_index].asset_issuance, @@ -635,7 +634,6 @@ impl> SigHashCache { tx.input.push(TxIn { previous_output: input.previous_output, is_pegin: input.is_pegin, - has_issuance: input.has_issuance, script_sig: if n == input_index { script_pubkey.clone() } else { Script::new() }, sequence: if n != input_index && (sighash == EcdsaSigHashType::Single || sighash == EcdsaSigHashType::None) { 0 } else { input.sequence }, asset_issuance: input.asset_issuance, diff --git a/src/transaction.rs b/src/transaction.rs index 4595ba50..de509f33 100644 --- a/src/transaction.rs +++ b/src/transaction.rs @@ -43,6 +43,14 @@ pub struct AssetIssuance { /// Amount of inflation keys to issue pub inflation_keys: confidential::Value, } + +impl AssetIssuance { + + /// Checks whether the [`AssetIssuance`] is null + pub fn is_null(&self) -> bool { + self.amount.is_null() && self.inflation_keys.is_null() + } +} serde_struct_impl!(AssetIssuance, asset_blinding_nonce, asset_entropy, amount, inflation_keys); impl_consensus_encoding!(AssetIssuance, asset_blinding_nonce, asset_entropy, amount, inflation_keys); @@ -232,8 +240,6 @@ pub struct TxIn { pub previous_output: OutPoint, /// Flag indicating that `previous_outpoint` refers to something on the main chain pub is_pegin: bool, - /// Flag indicating that `previous_outpoint` has an asset issuance attached - pub has_issuance: bool, /// The script which pushes values on the stack which will cause /// the referenced output's script to accept pub script_sig: Script, @@ -255,7 +261,6 @@ impl Default for TxIn { Self { previous_output: Default::default(), // same as in rust-bitcoin is_pegin: false, - has_issuance: false, script_sig: Script::new(), sequence: u32::max_value(), // same as in rust-bitcoin asset_issuance: Default::default(), @@ -264,7 +269,7 @@ impl Default for TxIn { } } -serde_struct_impl!(TxIn, previous_output, is_pegin, has_issuance, script_sig, sequence, asset_issuance, witness); +serde_struct_impl!(TxIn, previous_output, is_pegin, script_sig, sequence, asset_issuance, witness); impl Encodable for TxIn { fn consensus_encode(&self, mut s: S) -> Result { @@ -273,7 +278,7 @@ impl Encodable for TxIn { if self.is_pegin { vout |= 1 << 30; } - if self.has_issuance { + if self.has_issuance() { vout |= 1 << 31; } ret += self.previous_output.txid.consensus_encode(&mut s)?; @@ -313,7 +318,6 @@ impl Decodable for TxIn { Ok(TxIn { previous_output: outp, is_pegin, - has_issuance, script_sig, sequence, asset_issuance: issuance, @@ -347,12 +351,12 @@ impl TxIn { /// Helper to determine whether an input has an asset issuance attached pub fn has_issuance(&self) -> bool { - self.has_issuance + !&self.asset_issuance.is_null() } /// Obtain the outpoint flag corresponding to this input pub fn outpoint_flag(&self) -> u8 { - ((self.is_pegin as u8) << 6 ) | ((self.has_issuance as u8) << 7) + ((self.is_pegin as u8) << 6 ) | ((self.has_issuance() as u8) << 7) } } @@ -1784,7 +1788,7 @@ mod tests { ); assert_eq!(tx.input.len(), 1); assert_eq!(tx.output.len(), 3); - assert_eq!(tx.input[0].has_issuance, true); + assert_eq!(tx.input[0].has_issuance(), true); let fee_asset = "b2e15d0d7a0c94e4e2ce0fe6e8691b9e451377f6e46e8045a86f7c4b5d4f0f23".parse().unwrap(); assert_eq!(tx.fee_in(fee_asset), 56400); assert_eq!(tx.all_fees()[&fee_asset], 56400); diff --git a/tests/taproot.rs b/tests/taproot.rs index 726ffdd5..21669fea 100644 --- a/tests/taproot.rs +++ b/tests/taproot.rs @@ -173,7 +173,6 @@ fn taproot_spend_test( let inp = TxIn { previous_output: test_data.prevout, is_pegin: false, - has_issuance: false, script_sig: Script::new(), sequence: u32::MAX - 1, asset_issuance: AssetIssuance::default(), From fa753b4ca2c9e84a58f9d155f35f2ce1ac3238c4 Mon Sep 17 00:00:00 2001 From: sanket1729 Date: Wed, 3 Aug 2022 15:18:38 -0700 Subject: [PATCH 2/9] Cleanup bunch of blinding APIs Now the blinding APIs are separated into smaller chunks. This allows 1) Blinding only the values or the assets but not both 2) Not relying on rng to set asset/value blinding factors 3) Bunch of API cleanups with better input parameters --- examples/pset_blind_coinjoin.rs | 14 +- examples/raw_blind.rs | 23 +- .../pset_coinjoined_blinded.hex | 2 +- .../raw_blind/blinded_one_inp_signed.hex | 2 +- .../test_vector/raw_blind/blinded_signed.hex | 2 +- .../raw_blind/blinded_unsigned.hex | 2 +- .../test_vector/raw_blind/extracted_tx.hex | 2 +- examples/test_vector/raw_blind/finalized.hex | 2 +- src/blind.rs | 469 +++++++++++------- src/confidential.rs | 16 +- src/lib.rs | 2 +- src/pset/map/input.rs | 28 +- src/pset/mod.rs | 167 +++---- 13 files changed, 437 insertions(+), 294 deletions(-) diff --git a/examples/pset_blind_coinjoin.rs b/examples/pset_blind_coinjoin.rs index 1cfacebe..6f900de2 100644 --- a/examples/pset_blind_coinjoin.rs +++ b/examples/pset_blind_coinjoin.rs @@ -266,20 +266,16 @@ fn main() { // ---------------------------------------------------------- // B Adds it's own outputs. Step 2 completed // ----- Step 3: B to blind it's own outputs - let inp_txout_sec = [ - None, - Some(&asset_txout_secrets.sec), - ]; + let mut inp_txout_sec = HashMap::new(); + inp_txout_sec.insert(1, asset_txout_secrets.sec); pset.blind_non_last(&mut rng, &secp, &inp_txout_sec).unwrap(); assert_eq!(pset, deser_pset(&tests["pset_coinjoined_B_blinded"])); // Step 4: A blinds it's own inputs - let inp_txout_sec = [ - Some(&btc_txout_secrets.sec), - None, - ]; - pset.blind_last(&mut rng, &secp, &inp_txout_sec).unwrap(); + let mut inp_txout_sec_a = HashMap::new(); + inp_txout_sec_a.insert(0, btc_txout_secrets.sec); + pset.blind_last(&mut rng, &secp, &inp_txout_sec_a).unwrap(); assert_eq!(pset, deser_pset(&tests["pset_coinjoined_blinded"])); // check whether the blinding was correct diff --git a/examples/raw_blind.rs b/examples/raw_blind.rs index 122bfa6b..74a60643 100644 --- a/examples/raw_blind.rs +++ b/examples/raw_blind.rs @@ -10,7 +10,7 @@ use elements::{ bitcoin::PublicKey, pset::PartiallySignedTransaction as Pset, Address, AddressParams, OutPoint, Script, TxOutSecrets, TxOutWitness, Txid, WScriptHash, }; -use elements::{pset, secp256k1_zkp}; +use elements::{pset, secp256k1_zkp, SurjectionInput}; use elements::encode::{deserialize, serialize_hex}; use elements::hashes::hex::FromHex; @@ -168,8 +168,8 @@ fn main() { // Add outputs // Send 5_000 worth of asset units to new address let inputs = [ - (btc_txout.asset, Some(&btc_txout_secrets.sec)), - (asset_txout.asset, Some(&asset_txout_secrets.sec)), + (SurjectionInput::from_txout_secrets(btc_txout_secrets.sec)), + (SurjectionInput::from_txout_secrets(asset_txout_secrets.sec)), ]; let dest_wsh = @@ -179,7 +179,7 @@ fn main() { let dest_blind_pk = PublicKey::from_str("0212bf0ea45b733dfde8ecb5e896306c4165c666c99fc5d1ab887f71393a975cea") .unwrap(); - let (dest_asset_txout, dest_abf, dest_vbf) = TxOut::new_not_last_confidential( + let (dest_asset_txout, dest_abf, dest_vbf, _) = TxOut::new_not_last_confidential( &mut rng, &secp, dest_amt, @@ -200,7 +200,7 @@ fn main() { let change_wsh = WScriptHash::from_str("f6b43d56e004e9d0b1ec2fc3c95511d81af08420992be8dec7f86cdf8970b3e2") .unwrap(); - let (change_asset_txout, asset_change_abf, asset_change_vbf) = + let (change_asset_txout, asset_change_abf, asset_change_vbf, _) = TxOut::new_not_last_confidential( &mut rng, &secp, @@ -254,19 +254,16 @@ fn main() { // For the last output we require all secrets. let inputs = [ - (btc_txout.asset, &btc_txout_secrets.sec), - (asset_txout.asset, &asset_txout_secrets.sec), + btc_txout_secrets.sec, + asset_txout_secrets.sec, ]; - let (btc_change_txout, _abf, _vbf) = TxOut::new_last_confidential( + let (btc_change_txout, _abf, _vbf, _) = TxOut::new_last_confidential( &mut rng, &secp, change_amt, - Address::p2wsh( - &Script::new_v0_wsh(&change_wsh), - Some(change_blind_pk.inner), - &PARAMS, - ), btc_txout_secrets.sec.asset, + Script::new_v0_wsh(&change_wsh), + change_blind_pk.inner, &inputs, &output_secrets, ) diff --git a/examples/test_vector/pset_blind_coinjoin/pset_coinjoined_blinded.hex b/examples/test_vector/pset_blind_coinjoin/pset_coinjoined_blinded.hex index a49a9e29..3fc78cf3 100644 --- a/examples/test_vector/pset_blind_coinjoin/pset_coinjoined_blinded.hex +++ b/examples/test_vector/pset_blind_coinjoin/pset_coinjoined_blinded.hex @@ -1 +1 @@ -70736574ff01020402000000010401020105010501fb04020000000001017a0bb9325c276764451bbc2eb82a4c8c4bb6f4007ba803e5a5ba72d0cd7c09848e1a091622d935953bf06e0b7393239c68c6f810a00fe19d11c6ae343cffd3037077da02535fe4ad0fcd675cd0f62bf73b60a554dc1569b80f1f76a2bbfc9f00d439bf4b160014d2cbec8783bd01c9f178348b08500a830a89a7f9010e20805131ba6b37165c026eed9325ac56059ba872fd569e3ed462734098688b4770010f04000000000001017a0ac55f449ddb6853f2508766d5afb9f3b45e41a8ef5368cad75fb88e5e249395d1097d88c92ca814a207f73441c56cee943f0bb2556da194c14a4b912b078c2238ae025341cb5e4e2d8cb69e694cb20e5ea4cc8ddf2801180096fd071addfcd8bc4445160014011d384302576b408aa3686db874e2b17cc2b01b010e207aff956e6c2a379543b1ec82b06958f062bd9f29aa1ac1c98d1f6398b65a8555010f04010000000001030820a107000000000007fc04707365740121091517eb0e8ff9154ed835c45bed0856ff6b385b12f7aa224a1d91a532dce77d3f07fc04707365740220230f4f5d4b7c6fa845806ee4f67713459e1b69e8e60fcee2e4940c7a0d5de1b207fc047073657403210aaeb20261582b6a470b523b53d6969fb878704689a6ad0b0a690ccfc39b2b03d70104220020e5793ad956ee91ebf3543b37d110701118ed4078ffa0d477eacb8885e486ad8507fc047073657404fd4e1060330000000000000001c49a6101a4a3a122e2316e466cd2d4eaf9ec9029024390d41ab38146cb008e124d94df5c0827b57353b88df660dd6483ce69f89db194b0d7d14ed04f67059e708fc7636fe37183ffec38c28168f7c0680ede63e23a53ba0312fd96cc47dd3e147809c8e4642ff5d4ec0e280aaa369b08f41694cc6abbf60716678f7a83d7e163b34e2fe06c203e702e52cb69a5bf1a37aad479d9bfe7feac1a16bf927b3b233e50a3f86a07d6cc69454b0051df0f2941fe86e98259b91945a7fcd0e5c64c4ed96a302f931c23effb8ef97b4e1e3d74b0c392f686e49cbf255961fa03fe32cf60bc9a030dc511564600412f8f57541306f83cc6e8d3bc84796e7439bc2afff98489754bbfb6f28b2c65bda4cc8d5514e482804391bfefe3116798c5f477d67c65c4f82f18d10c864a59fc7f9de325922415422d0c57fa70e94f878acc88d9389dafc99d584194ea5329e1fcc5a8967fb1e7c7a85384d1af35b0baef473a948d4f2c02403e0405160d22e793b079cba61377a2f25a78da9233bd6706192d32f80b6f51bc86452f47bd0e8e498033fcdf84fc16298b97d6e4dd4392f37869dd65af84394fbce984599da74907b70cf0bf3181dba69625aba09995afe37213f7a38bad1e4ee4d2d5741ca334d05f6fb5ed40847ad3cb40d75f3a407e669fa77acae9c7e33fb76a92ba445f6b955e30364957a448702ebf2193f9cc6bace952cb2b36294b34f024d209aae3ffbc8c3d3e3e3984d60ef7759c165d5e99b90b5843a706be29ae6c136117196495f8f575303b156b62e77ca6654975296092a630950283ea808bf266935c5f9e32ef637fba8104c2e766101cde30c48bb77dffed39b1aae769bd378860cfb4dafcc4951893e9549e84821ae78a614c99a368336d86333eb48234fe649eb911519628c65120b395c9cf14a9f2d9398ba6dd8c3ec2ba00bf9d18dabd8162e5df48ef3f1e26fc8e068d14391b192981cba1b9e665649952752c3038aab5b4e108b705c1b90cd83699a1ba2323cdc3eee1f2f1d909eb11da0c3940fce919d65c4920b22358995655410aeb1209a8c34e8621bbd154536a26d29a93c0c4a0b9cc0334e0c5ebe960b3c5e49c305c6d062eb918d5d1f3bcc95c900e06f737623a06a799c2a6bc182357d3f88a059459d02ebc492e7b9b43b1e99a4c8ec157483ecb70ed81e0e70855950f87ab444fdbbe20ee9a34959d63b9569221001942118479bcab4acf18dd56d7d768c066a3c6b2467e5dfba6b5ae5fe5ff1e00489e732b61899ad3b8c82c8ceebe76227ffa9d57003c1449a7d34c71625a1bb8420ed046d355af63c8b3ba4983035de467716bb34f7993970a019c9c87d8a6d66b52361a1b10352bb5eb7f05ae1aa6a487fa3452f8d25a5ab58394543ff0a4e78d75e47324572b42add9ce1768d78d84524fca712965346a542660648230c914a0ce93b460687287a4d420a4894dad96650aa4b473c3a01b1f561ff4ff4c06c5ac946952c9c009c2aaab33bfa7cec11f6a24d75d8112732af0fb6c8a0d1cc8d7d202f4cbcf5810f2d1c8c6bae7748deaebd2174a39828d11daf145e47a16aa86fab16264292ffee07bfa452dce579204d91038939ee866f3a0c46dfc7fd6d85409c96450042920a80a601d11a7a8ad231c6d996a79e6fd710969848bd357dec3b7d20bcd1aaef36657048000192f7e3f0910b954a943f2d9026d1e87e080f2b78299a00aa2c7d86cdf66b6d98bee293b46c44a3bdfa87cfb6f1659d213460596ab89e90c08151252e171d87a4406ef3f0185e21bbd5db0e298874faf77e743899e2af8eaa4b2165c8942c1bc488723d684ba8096d64b3c032e9d07ddc4b8a5bd1027a54ade8e56a73c15fcf1f204b194933c6dfd5a78e449987e682c81970cfe265aed282b7ddb9c7c952859205a42ea2c24abe55883acd0c593edec197b9cfe5fcd56d6b867720fc1fbae83909b65f5adaf21526cedeea64a4d495b409244fc734618590f0efb15d76740234b19cebb88f70d29679d2b0b34a739bbbf2d5e9ff15fcd97df5e1919eebc2d1f469f35f024cd79357963374745e92d8e8d1e29a286f6fbeae0fd3abef755b514503acf5106a2fbb2d2370621ac3c3ae34bb6f14f6e82c71d01ae33a1bb629e294022ef9cc50d295bce35cde0beb14bbeecbb6cb189ca692ed2040bbe0312e9f446f2f7394c6daa130628a03956831b7ba63f0eecb5caae6472dd44459d69b994917e08e05665c16b1e988189f468b170321876918c323e52646481532616d4361c8c2070217d40e052a6dc487c1ef9f030922458e829a3ea15d2670ac3acea32e9af81b2a455d0d63bfed89e911e19fff080c7e973be22061348266b26d3bee8c4c3bfad3ce0aec84b25e3cc41b46a902f9a119775d0a903a4657df112ece8e789aa7995fc90033d503ccde74901b1b40c440936fe0dba6444eba823b328c8c8187135be38a651526cd1e159ed806714547f09f45be5928efe384e91ff6be03ea8992b35eca865ab4cf5ba7788ba95642fa530f58547fe597cc3dd8bbe223bd008aea8c37e7433547d2ac5cb716c2403472d7a96a76d41e9f3b92a7db1f7694e28446bee478bbdb1c2c6fa787daf10ec2f539d87e3d5e43ebdcd43f2da2736d15cc9708b74c69a7419fac92a3c1c307867ea243ac4401835ecb459a888ad58cd2141808100afb3e3bb056fd9f42b2df7d6f426b4db8befab9582cea9954f58f2d899e1ccb4dfde1a9d7a8b2076403ffb8c7e14661038f952dac328d5b21e7f1e4258ca8aaaa43f426c8213383bf60d60640a9e67378097d5f07e05dda7159ef477439be71c28904ba4226708319cf854f92c62f51d7128338578eb259c0681e7bdd27426fffdee0081fc9430db6782e2b013dc7e76e4ed043dfd7a2078b41230ff437dfbd240d3f11f2063a808ae011147a4b6111b4fe3339deb4c0e5bed8ab5af0a991175ffd33941c586a1da510774e25eab6858f1128cb7f7e2a53645f909c96a4c9dfb9323bafbb9d75a7d979238b3da069ab16fb7e621a7a99195b78e11f85262d9d6413a7b88ca0f6fca17cf9f73a7332e7733a3e153d4372dd2e6d9af0b7883a99c0b5925f817422085808ef25a71bdea61755449dab91704b250ea29fe5e66e776217fd38054bce90e2ad5d8ceb32575834ea5e07542f2f1795c2c1df6579b7dda3b3ce9382bb9838e7324251a9f7848c56cf213ba968e632fa9f99e2a1f4f916231a70ccaa450fcf8b9a2c44f4097b65dc4fe63b218b6a3181ab5a06d69483442ad61277cae828c7b90e2caed91e8f9f02582a642fdcaf72b4f1d3c14102d2663726555288f48393a178ede1692d3a8209bda7e3a3e1608c4c1ee2fab5a4ce7960e4dbdd00579261cccffc49cc8a876f250833694809739ebe0a252951904b994ae9c190b0cc612e2c67d25be98720887dd8c9964ca698fc29151f833496ec3959c05a8785c72bf0f1c9c9ea41616c9aba960ac21c38f71c82ebf3757e86da00bdbfda319940c1bd8e468f9d83654d87d6c1a7d85cfcb233841ad0118e830e333d7bb1c19972f24f6efce9ed585a915a4bfd49518c485f9ce5c5df734f32ec825f8f259ba25cf4b9d0c1c1118d42d7110609b5b44c4b0d92c70101319793807f2f209e7b5460c9ce8993a11fc9613c96735cd7e2a3358756e0b4c5e24104c76fdd19bc5ca4123f6d07557bcc4c350b3c5b74eb45418afd2213bd52ab2d71658a59367441eb73c37cea82492073d2f38b3e446740b338cbd202f28dba9004044ad4b5b7085ff19a4dfab50603f4344bb2526fb144882695c2a31d86a4163f092e697065f55290b99167fab57c5f22e51fa1520ac48ce50cf54841ae22cc480ab4abbf078469e65a94969e510af6d58c50b140a38c03420d33f9faeb35b44cecfa0cd19cd27c20026bd19b2971c4f0d32456ba4dd4af61bfce234b471c54c013f7183559e4dd12e8fa1c297733da6d20c57b838a1db8fbfd4a367b5969328df2cb18688b7099a504e559af5edbb54c7b58441ae15c693385e0ec40f3043fbb0457292e82cbcf3afd3b3d9d510691ccd1441fcd45c9342522010f140ddd6ae4b79c326acf5f2873031911a4ef7b53363121c20ef450e5f64a63729969d038be74661ad9260ff39d738a476e306b15746e4c3a72aa2168a8c276de4b3da973cf8ea489320e4d1df7abd1f6dd38d9bfffd4ad26c3f9d874377a4718e13e77524c1cdf751fe433b72cbf89514103df8dae6aee905f24a1222633578607909f4473397f0ef7880069eb16772188793ae979cc9ba90adc6df93f059726f8ca4f94c1b986c8ac1b0ade97c23b139d303fb36037939c63bcf0b0a33cda54344edbc759a3157abddf7afc3e034ad2881a55854b6ac679316d99255a5d0a93a96b0b1efbdf8dffca1c4e9c6ebb11c7667bff42aecb0529b809eba6f7af3eb794614bf4dd266a19248af7b679b5f5a7c5896d3ad9fc23616d579e98d7959793f9a4d96f058544e38108ee04fbd9b91249633cc405c0f3593d4a337ae3e0115ec1af1f34f96d633044897193b6a132f29043922fd57866d9e004d3aefb8c36e8145226b1dbe7866f46790097f1052e6b18b50f6c83d4ad670dd0784cc73662481f415d03348427054a3eb50695ebb104fd45ce6a4a23da4386c3d384cc8bc7aba67ddaa49a0e49e98262a55c7947d1effabf398f919862fa38adbb723b1b9d1526dc11f970444a05389b3211cca97e62f94c66d785a96e8c507cafae02b6d0dd8fa0df684b3ed339374850a9e3d540eae25bff5803dac9c5d8be61b2bcf2055ffd946df6f5ceabffbe84dbea695e0b67f3b8bad1443eeb743ff7e4943140c036832b9b5344b8db3d85ba958f6935646b601b2fe497ef8ea1645fe41760c70610326c5253cd8c84831588827fe8ee0ecc661b87103e6e99f567308f580e2387d6dce7901883b8e428bbc9cbc19c1e850bf598f204258c9b6f09c4334a8f95021b94b05ae197dbdc972d6bed5e8452f39cfb98fb60b510085ed739dffd4241ed0eab4962d34762bfc8cbda6dd52b3a324612c32ed80b9d77c6c41443a9c2a40dbea51da644dc6becb9546843687bf9f4221b8bf436863833f258dbe98bd165488157301d74ff152483d6015459b11daf5f1af98293264d91b96f63885d7fc45d3ba117c22b420994b93b0aa207fd221370a55bb1cb130314ec9d21624a01136a5f51a5d1e028585896b7ae63cfc84c9f493430cce38d1fbfbfa7db9dfc0479ea027ddfc38c13c7bbe957b04a31e90ca14aa4e9f9c12e339d09811eb18f32151835f4d396da9decad13363c93de8d7499a941b168ea2367dfbfe3fef4bad204a12bd07ee0762de00cc193707d3889efbf13ad72c54b210b066b699e8f7c67b07648b743fae60b5f09f3455be11edad01c5b4a70141f969253a63754ebedc338e83755e8b762b023b60abc12be5c584a57308b10c8a335666d84171edfcadcdcd17a6fd30450985ffa2e690d00e5bd21169a0404777f51c37cbb89c745559bc7e81814d6010d331b16ffc4fe2e88f37256e29871a4f0f8c959b78927ae0ee449559e3f895327227e859fb6cecb20d4e6671f4d9d46a76163ef3c3490d1801ca8039b5934c1293deee598acc83a4b776d335912d0a2c602c653f8f3e9a2aa249958d94fca07a4de4366cc5349aa2f3f599f33bab74ddc01944be806a35b5141c95dc778e6ec102a609c7346211953510d7105d436112868d718b72b0b861aedebb4c77d6f2ee6b7101bc00ed406a89923e19fef2dae304f528ab56e9086fce342e4f19c509809fa399b2c150e6911ff5b96ee8627d226ec33c0b84c04ab0afcfc4d89793cfcf6111aa8fbd217cf5706aad49d4ce6480b7e57fc77c07fc047073657405630200030ac6a03fb2c4143a07d1599e22ea844e3594b77f4a960e172b3c04a7b9f7eb647887e94bdae208da814a7a0d2b216bc0a730da54cd34522ae1b71ea70a305a217014067b0ed40a77a3d1e92afd3c447018c8c60d4b8e0ded12f49671bcfa36a707fc047073657406210212bf0ea45b733dfde8ecb5e896306c4165c666c99fc5d1ab887f71393a975cea07fc047073657407210325b27bf6f8d1b06dbb69ed3944095d71b9a4558fdb574e2f032bbf1adae138d607fc047073657408040000000007fc0470736574094920000000000007a12018e6f3734441bfcadd5d94f97741e750dd28201a658d4785c5bede038f1a1179290dc688efae09c0a437af462dffc2fc5adf6bcbbae64cc40e099300c98e4cbd07fc0470736574104301000190d59bf3b61acfc27a23ea0f5994bf35cf81c62489a2f658673775457d0eadd732c4aaeb4275077bfb347f483378e6fa1570a1912e2a8a725a7a76eb0c2e23ca000103086ce2ad0d0000000007fc0470736574012108ef054b3ea0c1c3a6eaf67bdb0759cc44d7fa953fbe2df1df4d39a59dd6cc9d8f07fc04707365740220230f4f5d4b7c6fa845806ee4f67713459e1b69e8e60fcee2e4940c7a0d5de1b207fc047073657403210a93480fd89d465d14eb4e976496a7098fd22f5072f5740d60d12eec8c8de917710104220020f6b43d56e004e9d0b1ec2fc3c95511d81af08420992be8dec7f86cdf8970b3e207fc047073657404fd4e1060330000000000000001ff4a7f00d1d98a7d46cc2e7aeaf6bb9d3c9b1a8d573c77df6f0ffd7d7ce8fbb26a6497b001fee431414605268fb1d79614701840cfd7d806e3bdb0cbbf26cbaa4c88ff585a2fd69dceab1dd3d2df7fdf8d3f8d3b694fd42c087822232cf38f7862a1a4dce171818bda605bbed50deb0e960185e61e4cd439e7c0f91aab6d7de9cc3129152dcf66e77bb97ed6f2cc63b30761f6c55c2632390636f51861e0188a96f5b9d681037ed425a20495b11b588cb4f6963598ee3e690dd7349381301654120d0402974fbeff07ca7bac01849d8258726d4df8417e1fa83bebb53a6f92f4990772de7f5440fb56a78f7ca9bd9cfc3698599b5fb90105ca4a516f710e9d560199561a25df5c8304f8d37850748f4ec4e257c420db3a7ae87dee40b47251df09ca0e75b3a9b15aac33c29de742eeacccada72363058af435ac0c9bce5b19b8d3493273f592c2f9e63e15c39202c4bd0d2d88d60b16bff373e06552dca03094014311d85c93b4d5bfd3a77435754b31f776bb5ea24ce87934a38edf87470170e50816ac474f8ff97cfe89208395e26df1f710c65692f34441b298f9f73fd854a262cbe6f9e6fae868a2431c39e2da23c3295610c45c83c4f028265b5dc484cb0c7d9fce48e11e1e4f1da02f2690407a68251997518c13d1c81f3bc776c19da0b4f3a10aac96c7df96d8355619258920840e2a6f3383cdda4d98f41dd5e6ceb57727ce6dbe876ed0670f59c3e01b77df6cbd75bf527a9abe424f1225c14aca11ecca48e3b334620ba7072947bcb454330e2ca8c0becb2db1d020bd2201ab1642ce4338d0c0f669d6b51d056004ca2adddb7b0b76468ae8eed4bac80b7ff97af3a524640346d1b34d658439fe74186c824cb4702e289008c06a30e44653e222bb8d22813082db1193d9297821c21e5c5181a1253c509c72dd385977e6af54faec429d3a7343972da91d17f5d0598c9f28c9a435281db5063a03d70ff8a936f8da33f4c6a42a9944ba7f02821e153c941309aa998be3cd28273dba337396f5438ff364bcb759139e5e381563e0fbb9d7cc2eed215e96443b10585c528d14976703fa6cd8d9eab5fb59b9e0923d13e35bdcfec7d8af5c688a80f88d8e06267d14c8837c29440073f7e6aac21ccefb43dc1bca60249877f12c66e2e34769df0e38910d7086fefb37df8fffd32e71e27e1e262d8c7b7c42f8b7f34038cca6c1aab4eeefc3ccce5506a52d3a86630f62452bafd79ebb80ff22a4c59e9848b925bd64de0d3f472f59687735a051b2e5c59b1d88d7580dd65919286a56e88763e759f3d22ac706357a3570301782e54667107f7b2d3a47d3850b5f461ba9b2513177d93a95cd631391cbbf62c7e6d75297ab68860bcc41c4338a2715525dd96e6b0303a0bdcdb85ac29d0c01307e5ce54da090f5f4230695876667760c69ef7ca21c4ef54d5cce2594ec331c64d13d317c1b519af08db97412bc05731d62c68f9878786330d791704629ded3fbbe1e9ceaec9d751f31e20b22dc26fc940af3db67587d684654ee54d26d4107c4b07cecd6a80a8da479fc6934dacfeee3425af9ced800658f525c530255655186f7c1a1f71157727a59ed3e6b9ab220e628fba62f5b6620b67612dcd0dd387e7bcbb808429c82889f9d86931e1ee71628b75249c03a52c6d01a0f20720c6a710d11bd4e885a1af70977edad010c679498ffa935688a4068b38fb626e44de50408403ece279f817951c635455478e02f3b20e098c492c0ef5a76cf8e89c9dc842d5153fffb98090e04eb3c0250abc01e92bbc58ae5d2f70e5680bbdf3826e0f0f52f4f81a82bcd2d9463baa28e626301d996eb2c282a4454f68b08593a22f7bd53c0bb7fe85c224308bd058447b486d9c36a4be755e9df22d94f639fcda1062c673a7756bcccad2aaba46ec42665a776657cad78f6c8640e650bfa585638cf3548284baac1d6bcc6fc11dcc2f0ed7cb701ffe9bb1113fcd32779cf0f2b03d493987512f4a2ff71d51fdb4ffac05703867bc388ba7d6fc8afbef82f55200b2d352df0596324958656e572876511b0b7afff492e81967e233cfa80f12f6ba6dda7572de02a6a960d6be04edd2de1e8013f96014d55b50ce4f9cc5ac6234dcf5ad905c448556280aadda2fb89a0f9d945fffd2d5946bae4cb6a4f3fbbc56e329114fe4b5f5a6955f2c36fc82a29fa2bdef126492e8904f86cb2ef4ff00379c8d4e1f4af490509f783732b05fd4fa7d835cde39d23fa2b32ac05ba1f14fff3b76c540d8ae602906749a9349d610f59a057cb478bb896cee2bbabc8e99c746f26731cbdf024a6ef057255fef6e1a2a01d8630d80396a3de0b38a54a4c23612f4b566884ba93ad04093a1f521f50b3c7146b68eea99bc4964f81056a6f9499ea3545b250915227304576e8ddcf5b30953ab6cbee4b2cebaa7f62c17a0e69491b383fc7c02ca921cadcc914e0ecb68961824921c68ca716e303e3caf3d8f8c7370a4c91f8f952593fd737b471d4d1d3507c3bc03854ee9f72c91cb56ebd33180db187a28a929eb44b5cdb0a9cdd48ce2e7f452aba3910860a634f29902c476cc076c4b4338faa160f2a2ea8c26f6ed46ea8f1a0915baab3983830c8c8898cf89440cdedabb65215c1abfc5de657ea4b9880d669b49cbfc917278b6f901422d4ecc4ba9aa60f2a4ad78ced49c408c9e79a1c92c1559731f00dc87063e15f6e3058a575f623f0521d322315ae8f9f301b2bdecab23f80e89cfad56a6ceab333ffab9fd74881f60339c7f5a299b0620c3d27e30a6e19151c51254f844b83e88852f756fa9237c936539513eae1435aeac538af8c82a92f935b3efe55e23250001e4796f18fda3d1fcf0d295cf1986590f5ab52e0ab30a2fe145483baaba4c7d6a7bbba90046f5726a0b386f5e0b35a72952b7794da0907233a14e72f3e5dda7e531850e85cdc60d41e99e79ca2516ea3a1ef2cc38fbf71aae2918fd690b0a209b8e9d1a03d65bc200d074e178cd7422756d65385f7924f38d5280c0fe87bb2bd2b39f3c8c6c5f5118563d7d7fd89bf4c79bcccfc44c440b14355ff639ddb01bae514987cc8c621d5b1840852400ff524b667a7bdd057804b2d842ad932d3bf0227bb6288cd0ffd8b5afcc410e1cae1ca1769953bdc66f889f18e149da77c091c75e882022f1215d381b6d7fe13cf8a1037e1e488dcf0b084bf19b9ad5bca1c45b3b7710aaa55fd3f67ce8521c433ac0a5ad499009b40ac770024e9af6bb5cb02d4bd4fa0822942532b38e0e278cef8a180acdb71dfeb2bc474baf9fef0d4652eb447835ef0a0f7af7ea7b65de50999763a8fa17723b54088120bd46e697253e90522637d7037b1bda50a17fe44b5ed08540243039dc475539630f164a7b3ebdb80d3ab204b36aa8d04c47cdd1ad3bf6471bdddb6b6d7d35ad05f70161e5da5620f1fa1c79a235de999f5965eb52c2e6cf1055458a19288a91c272a8f40680c0e73fd4f758ceea9aef766c6c5b2ac6673874e3af1213e5f79531e5dcdebad605f0ff23aeb671c7acd0281a3c419abf3143612b5b53b0df1b484ab54ac8ad5d9e27dc3315fafb9839285db01e5d8898c904356b62edf9882df23e8b698cdc05f18c1d3badb2c66acc61dc0b750aa4f83c9ccebc0cf9e6906a699179b3df8be377ed997e023d7211d66a5113d388f9c021794bfe3beef37981eaf4a1d7909f475b9eb7ea82f48609aff9b4de694509678ac68b10573972c58bd1560624814ecae8844d87da516fee9b90be2206189530cf17b97d68a2bb7062f02fd6c49c2353356a29b98ccb386ba91b296cbeff60b9b876bf7e6de91b109886107affa43c2a8e844ae60c137c11ff3c44feabd90c2b009e04c85d5f55200a8b6b6e20da5492cd202bf4b5d83fb9cb7654acb4085159bfd7e11e2017d7aa5f96e4d343a008af5515fffedddc3a36888ea9933354a489d3300e9971b55fca763c98c3d9d22dc67ac25474434739ca81dbf1c394f73101740dfa9f2cfbbc5440ae58a4744f6e2b3b895ccda310a35521b5e8187b356a5da0a2daead5c54f3d3cd7f7e0318023c5d0176991a727d36ee26800b8c53f985bfa25df820b499dcb1a73fdfb6a636e3cd11d9ea63a8183fc504cc3cdbbc0cf6d2a54fcc1ae58b82c4b35953508934e371e959abfd44f252352d20f15de7ee83bc3995d5affc34eab1489b8bb44bb301a2d125bf62603286e3f6e68ac811c587cd125c5966ea35f09ea4fb91e72e1f43c1998866bd906e85ada83d4a3d9b23c2fcefb9f44e706a297f4713cd1f50690c54747de01e8d447f1511eea7300cae9d56f740ea2f8ae83940acb887cdf1271e7650573025325bfef481b0c2a40012def60362ef87f00136dcff2b8191a7fcf28996166be5d63fd9fd23ea15401a088e792d7cead57062202a34abaa5c078d6bb859bb2318e5b8b83b364de259d4d62e289505281d9b32343d865e6a859730ed1aa1f12fa38776f3d8d17c613c96c0ec214002a44dedec122bcfbab7d8cab07c8b72f90a38ab79abccfe849efd7a857e00bbe504d184bd3cdee76256a139fc8d5b4f22f1be8b3b0b1123d445be7066223b052f37444b531720662e00ea7452ea81b15ce9f266281086d5de16692beec5ddb8cdc79570d1f81d9fca65ac3eb7da1e518933f5d29eb3bc7292d419ee2ddf64e931cd881ffe125d9f7d4796482e2fae8ab83b137e2660f2c7b1936de394c48058772563271e557a4299ac1e659e1f76f9cf4cb9406feff09a7ee1a8ea49f36b5fb31a5ab7c8823501d86799794ade084603039a201a95392e604eda1dd7c67081957c0387c8d40b62cfaf80e63a7db01c17a04732bd743d7c6e91e436eb4ceb91ebca7903eda45f3ca657ae6ee36083ed280a2da0365d8a8c29a243cc3fce9afb8955c3ed92df67f8301c5e109b757fc46f764c527255fbf9bf02c3fc9ff449116e4f0de7e5635483d1ee4a49e48c64d4829b72e9b477f38c3617d0faac1961f443e23e087eaf301157885b94f2e032eb6db8539019f31a55fc6a5fb6d62131b4a7d195e62fb3a37c1258d1839dc240403ffbf876d6dd6087fe318bd68ae73ee28ba9bfe21cbcefb8ee9b798d5a016e3cc553fbd6c768fbdc1a28828e7466029327a7408677f9936c5bea9d9562c8fd3d2e29364e8f0a2a9378b77008494eb5ad3472637c603b017723202eae41a293501e1f48315216720ff07c5aacf78e6e34d738a50ed760cc5affadcd6a06784139b13ab110dc80b8d03bf0534d532e1dfa5400081b927310376ec63719f8479f1098b0605a0594b3404eb5d35f08d1715f81339ee1b11ad9d96c5f65ce6c07ef2253e128c4667b7248ef774f6c28b8be70ef7afbecf8b534836a08567f56a62a27129190120c656520c8b207ddd8ef2472d7976aeba99bbfc846370b141a99afe4c148ab7f01db0a62aeb9155178435406954f2b4441479b3d8a4a65a86409b8a69c3fe540e38c1f151dfa2466f9632671e9f289c3205a837b5db0fe1ab3ebdaf37aebcd48d66eb88cfd5d2ec4f4c8469cca69c53d92fc6f2b6f3d3e61a2d30b4c22e74a4a320f6d9d1fc6f51f498ba63adc7e0027c37c405b5802b669913b847931beba0cd645afb7bc663c7ca89ef3c47701baadb93a7212ad6352744306f53f1646e919801be44d5bd2e78bee69044aef8db04079ef3e5c7117449c7d7fcfacd9d433cba387121a011707dab8fdf2486d813dbb94e35bbb9f9f61092234a1dcbacfd99cc9723a35c58d16aac8827efe469d8a23533d317946ff7e10093aaafdf0c168d3f290847c3eb769f4cbced3f32e6c75b9f1e28ae8e7a27ad7b29ef98a32daa755c9bfcb8614e786fcaf4648ee68d02d8b40d2ab3955eb34f0cd182066f107fc04707365740563020003318739a04eeef538b5aa533a99325e69d6fc4e7c15d1d9c2a8e58e210a07b8bb5ea2d82a081398ab792b691933efdc867db671cc0d947d6f9e8f82c368a735fed64e50b23eeb6a49c228b09fa0030b4c88e8cf7b17b7fed5b313f90e0a90553307fc04707365740621027d07ae478c0aa607321643cb5e8ed59ee1f5ff4d9d55efedec066ccb1f5d537d07fc0470736574072103aa96c5110da9b0e6d04b6e73b047e601c46c1ef82a9efe180375736e41a33a9f07fc047073657408040000000007fc0470736574094920000000000dade26c633d2bbaabbcf43fb55d348142fb4298904909e18c4b73c952a5eecc464bb330404b01ec35a2fee7fbe4ecdb8869bfdc8c9552fe5229a61d6c0e98397e020b1007fc04707365741043010001455786dc62ff9326a2b449f428136e7aa130895ebea05497ed5eaccb73a61ff4c9799902b6a94c73b33ae2064e654d3986d8b931fe322b3c0fd401653242749900010308f40100000000000007fc04707365740220230f4f5d4b7c6fa845806ee4f67713459e1b69e8e60fcee2e4940c7a0d5de1b20104000001030840420f000000000007fc0470736574012109c5ba9abdcf24dcd65cd842bb47f78d6cf84f178efc80216d94ff8a2585826d6007fc047073657402207f8f32be9443b0547b4daedefd9b6b0b655bdad96759a57569bfd429291fa44f07fc047073657403210a29206a6e6974d903b467480e654c2180efbdbda5f69e8a87d0529501734cd158010422002037831b3ee29fc96f8e61ccb98fbe2dcb03e189dd29cfecc691b5a7442d8548e807fc047073657404fd4e1060330000000000000001736c1f018f94d3c1aeecfc5e79481642ae10aa575e15948ecb3a54b85b2274822d874cf225334a0603c3701fc52635fd65e8a946895af1092760785855a1c67b846e206246bb2eb1c7a660e6213aedab1ff06645630fe6b84c78ab6b74615866ba3cfe138e553d325b0ebdd542cf4a04a9276faf2e25594936cbc56aa6d70db453ad0868e47992d0ecd1227aba88a66b0d3844e26d586630c23fd6d8c162fceebab92e9d5500acf05a81fdf0b6d41db6f6513e8f25234380fb0561c2765480b6fe83d9e74d6913e1925916a3a90f9eef648a8f1caf476244191dc98cf2c39a172a0240b36034c31c9f8782aaccad02a0928d92970cf443f0331e5f580d52a6b9e6caad1c51a30e5fa0503c795fb40b0bcf047fcd873f922bd831c115b7627f77fed8fa76aad6d1250cd84184595f5163142bf77f385b47c49b529b7dda32fee16cf081631bfcb948c2426eb17b0c3bae41b16d5abc688afa285bc99579a30a05f57d0cd7bf777dd172ae03f3982ad912e0177f9cbebec46d6e57741b83289959bf6f68d816cf5ebabfc09676bcfb7766aaf6f5f04179a22d75273b82c94b7a9095eefa90574ba83aa85ea3ec3599fdd72a4fa267f7c2b944b92b690776b97b3cd4692fcd0079760d6a820ae51e1b0e6ef405d751414face0fdad0994cbf553c60017ea379d035e8ae184df1cf7fb28bfd746adef7df476213509924690e6d284ec2e3cc3d735b072f6582d913bbec5977d21f20bdd596b10eaf9bdada349dd63d99e0c28c2006f6945f09ca0d244d434f86841afa621649c4c1704252ac1a676d9131594297fde37194b901014a176abda3e2a5103b8b73b586382b3f469da738714e2d59b36cf4eee345a7faa4666c33a0d74469e39ca152ce7510f1abbf7cf24d37054b272691780309bd69916a964f2d535082d4403fca3210cbdb357ce06704f0f3aa6d8189badf11539d9e6f867cd4dbb2e3b4e13d6f9bedb459edcf1b520488c9334bec854794d3e5d943e7837e557c3131c085307ef712e122199d245bffbe6520f7af80cd73f6547057bc2b896e5430a27d5cc922ffbb5b4e012861061caf149d42b05b342f061fc5cab91be0645ba78f334c46f64615e60f37c84d641348800c5349f34cfda388fd58e48553722b7b53474475a6b6efc9753883a2b41e4678247a363998c59c37cd6c4706c56f5d5fe7596fb195c11748b66b2001accb18fd56fcb137f059973988f981c166b04c8e8ff2a52d705cbc61ee69c26f271e80995009608334dcef363a0f4eb5cc24fcb2160313836cb1707ec294c1ea357ebb70a478b84dd760a10284dd551ee7c8b086a201b900f7e3aa1e491926d74005fb2c989d32a3809ec1cca10bcad7b68c7be99d865361038b2b3023f421fff764a9ab759faf86c0a0042945969c6ca5f096cc1a592850622d6f60ba2b56287fdb6214d761dfd118ab8806a8557af5dd1d31f3d551e6b749bd37ad351184646d26360f150167a34685e24bd8127ec4970c73231e0ee4659bedbdf0b0fd64895cf13396f52417032f8bb221ea9216166d0a324c0d03603302e8234e9d98444153e91790567554056afa2f1d49d0277d757fd5211fe66a7f61624aed4e5dfea2cbbb8dabc4ea3037f4c6e236f1ee048b499cda952c7c9086f756adeb75022c1925ac0f64e4d7da8ec583e3326792bf13136d6e3eca27c56cb4be411d6b03ba8c29a4f17a860d1d27b93242e345cf7228bc6ce11aa876e7a30159a8dfead13520347ff5e949748ffc4ea51b75a7135456ca0a3b40a39bb082a9f02da862f19c651284ea28779ec034b05c07cbe85588f56b4a5432144ca7c1dd30b9783f231b1fc1ec05869de856a20a784c05f33055379658ec2a2ad24995e00c47ffc7bfea72e91df9d5e9a8bacd3ae3e12df323c0bc759857ff6e7891ef49b0176d0959f8fb2494e0fd85e68f0b8069bfbdea365850c15ca98d8e858936cce10a0d8a7d26877f260673ec3d1bb5f3ec4565726c935593e6b34c48f73e551b908f0a9c632166096efd4887e168831b0eb66c3e0e9e01a31f354e76d5f584273ad8f8ac2af7e4310b3273d106c171892ff3bd3c92f2727920d88b82b4cab6517eac2ac6a808c62da14c35536e47b33f028ead9d5486d872332fb61dc53c8281117f517b0b6d08626a4bf5d9ceef0eeb7828b56cf42aad8cc3cdaaf2c8f8970c6c20e1fa4c8dde0d822de374fad8fc898518129f7251fd9ced6b8f32364a1987cc0969892d1ab885dc9bbfa2a08a3d831a51755a6aadfe1bf78a2dd5372eacdb0e6a9668d2c7d1b720cb911005bae7f6d5d4e112aa4256171b6dd5652f95a4bd7f624b45432a99f14bddbfada9af1ee6dadae06f8392adf959979f46dc9a55439b5515ff57cb5f4934cb1259ed9ecd114014b99b3fa0f325eefa2ab8738e05c5ded5885d7430aa31b3878a10dd0a9ff95668e01477b0ebcc904e4b4f27840de17442661cf246f47d542f85a168187669820e6642cf58b23557c109b11133106fb043781a2da51fed9b2c5fdc426b4c1ee1ec47d2b9e992a2cb3485029d8c9d6dd44d104f0caa06a44b9f0470af5f905d155326e8156155903b9706cf6ff62c6c565ad9d1d25a0e82b1d8164268d83b8c8d4fce0ff202992738237d73dd242cca368fd3d3ca71d6acf49ae0d749a33eef07157adc94a049d2c6de65d2ce6a4c5957853fc89dca92da3f014739b24459f24de757abe4a127ec8f6b774beebfe44bf1eddd84a14f85c9d57ed3a9d8dbfe616db906c2d4b482b0d79f8165cd4c78af23c98cd715b406244bb5353edea403d54b8aa46206c5e8e551d1ee3a1310f7b7ce0e28392eac7e2546867d00b34fa47ae8f2c74ac9db78565bd7c685108de0ff3c0af495fcd31120e5497025416017ba47e6f32d3ad05f2290b471eb21aba1f60878f71e3102c59fe5ec96012f68e73c9bff4f35c25e65d66aa930286c31bd6a59e0d26b33cbedf4e5e43ec5ab3a5822ab352d61bfb45a2d9929dc72c5179acbb217e760683d079002b856bfe25e1951ee428475a5fa9447193778beaf49236a1a67905a55d541e69dc27eafcba25dc6ac6110f8e6528c5a3206cbeb36833544ca08db02c91ce03c1ec97b309014e52c546186d2bf62098b708054fce5cd5bc7e042f7da37780fd1ee3ccce6b8abe4c586f46b0488117d8cc2b42679ddb89dd5e4ff7f5e4a5c2e9c3101dc1d5c6d0415f255164eb38486f78bce5a0dbfc54aef8adfb647804a8358c4e5de06804539bb4ea7f7487f158527cd91081477a5a020152aaf49b4f8077296820d254d13e3c8fdd21906a801e665a4043b21de0edc08c9664be88f3834b0246b6264ffc081846cc200d629cf1ad0db881aded247a8174b4f43970d5680332dba5061f5055a2e69334cf4c8dda7302a9e37091e4f440608dea5399f1a8d748a59b009299a79f9da3c5f2b2648846c64a893bfbe0bd187b7b7767bf42e351a8392ecc744318a9871515d435ee05be0e5c800e0d1cfa6ea10335b48a2f00c17344afcc6d08ddb426031a35d6daf07f48c7980f56bb9fd2588f9a1f119610d70c8af3da487964a170b63ed3ba6c097e8ae750aeeaad733aa300d87a15e558fa6330680cfa4cfad9101ca85d012858b3ce6d944c9bd9ff072a151920018cd52314a595dddb0337a6af4e1aa7905ff54bec93f50fcf5625cb86d5ba0a39bd757139dbdd63b96c940ec14303b6473c48ec00bf1cb5db2ea7cdbcf4f0c4ee6a6336d7a321e57fa1f288b4b635addf70b724364084f05cbba5d52bdfe7b708cf25f7f1aae574c49758e7587eb15bde51dd3343269812c5030e9398a31487dfd86e2e8c9ab8e8ab0713e955f9981b7d8f1aff0424d01499555af7a1a17d041f3eead79e2a4f9528a6356081c550326b1bb4a6610302590430aead818e2195199742dd13fdd928a9ab23b15aa67c41758b2762078b2e3d3957ab202d0ffe80595cd51ff54ca213e21734d475b7b4b924a60580b5ae4c475a71949622806ef418273349811ac08a912880079ea2dacbd0e0a4092af04fe20ee0b2bbe1addcbf4289b5e3dba3125ef6cc09a8787e29930cb27e987eb599669349ac70e8fcc66f5c27aed363e28888b1b2a48e432ad2987606cc5496d76beabe66d1bb6fad2d16116a4d0d98509756e4d641f57d65cdd71ef99262d6047800dc6fd0b2a0d167b8d242cf53c41b8411b26d48b6a95e511d316178d34aa3d6852de377725d9a253717dda8238bbb2ece522f60ff4535f1bae8a71e52d904e5c849d13cb91765cfb20f5f74c9067e24de2d70006e384883e676b33549e708f3c90a0ae967fd54ba1364dd90f00f9660a27ed880dcb1067a4904a3c649d024cf9cb3a8184706c74d461b0efb02ecc4e93a709527eff8753dc3a515d7ccec22c9d08751a74a522f9fe99cc193a5fbe2b0a6cdff1d4e8e3654d4d74ae57fbd8e2582cced7c52051797b02e0637ae4d541cc206a754e960bb8983b341808b783032236a3ba305d2a5460a04da0da20f09a4d4f6c6312435e6c4c6b45a8d17998f969964284fa49cfa49c760dabcec76fb87768369f98153bc3ad86a3bca1acccc12ca8cf61b14d00a1de4623a372364bcc893983fca31b111b9458d809ff8ec7716190987297326bda2bcdef2faf880fcf8cd999d32ea77ec98958cf30e60cc0fcc3055d978fe7037e1328ca6c4c4134afde8d8ae5d71811ecd682a48230273bb9264eaf971717fb815eef06ac881f3d0f4d859b87043d7698ce28668bac8524b1d5763caf11c0dc6534c62c0dbc2291bd62b5d145fd10553b6eaadb1f6bed46b96458fba4bcec7785861955f68552335f36c687735425b9f9d17f2514a734e3fc385901219d20976df1045aa5023d76750a5cb10e70ea07f1c197526f5e71396177f66443999abc0a008d400da3d08c9740cf6662adf93dd1735f8c262f58241fc6cdedc9ef7cc4590b8aac248a831fc7476c0e26f0445f9ed723cfee1fbc2c8ac6315e14bb2f49c2fbbd593d870b8b98cee16f8adc6f841f236e4b499571094e07ad82e44e57f16f728a7187d6c1baf3cd1315b1f9ac4b7dae69e39efb6a03176430f69720e0ef879284f59ffee4e6720d31c51753d666681dd15e7ee5340a8629e8863d5e86b4088a32de13e13e0f92e15511e9bc4d57a25c71743e9b39af867dc17ad3ebe41b9c8f64d1c38573db395382b55a50ec279030ce8f59ba8a13525681efe3862f3c46eddcd3dca4eb3a191771723d3a2875fb2074ee9867632eda4ffadda4c64283202cbed717d3ebcb2030ead311b9c2ca56169f7ce6deb9fec78a76cb9f78ab8251b83bcda6dcdb0e916ba12daac78a151eb76d040507fa29eec866225f87c694233ed07362b097aec619f5df3dc5ad0a58f0cc94eacaf252f1f9dd59bce58904ff7460052a5bd0650111c105aeb34485c4730ed6e3e1c927e2cd956d1b9404fbaf0440afad135a3f320005d666abd4c69e98edcda3691b7e69b2c3c88ef5e1ab9062b0b3f08b8ca38e8f6f7b4d04f3daa358986a3f8bc5f6a13115c31e454c0dfff61613d0dde9dcf4516bad111328b9e88f262988e8c05e5ffe1fa6ba708f5fd51c34e4757814ad0ea5e6fd33cf51b45b84c85882406cd3eb107b96fe546364a9972d19022be3b5121ec64c6454f3a4f9809f49e11611b2131d5af0aa5e65c156f37a6062aa395e763522fe6b1451c0452c6c56443087202605ec9ddac8635e7fc086e330a7d22b15851671565726b2cce451d6288755a04862bc7f934b99de6809533c05b851ed07faf408f83fa9c18f3ed65a94e9788f830f5bb9ec744b71f59d6821899f8640441d47746497dbaf8e9ddbd252e04a5e4b313e2580a1a858e4550a1e5c09a04eae54307fc047073657405630200037f019cde9197e7270a1c7d726ced68dcabcbad740497313348e7ce6ad7d29f0bdf616a31c760921e4f9796161da146c841e86ee758cfe053b88447152770fa72c1d2b4d17de0698a19a7f1cd72c95a4b3851905c2a7a76d894a2885cc28addf607fc0470736574062103d559d2a5a4180f418a69c4bed5508971cda9313722fff71e053d3d82fee9d7bd07fc0470736574072103701e53a6d0b960398abf678382a4d17c5c153d1a2c8ffb76b302058ce915bb0d07fc047073657408040100000007fc047073657409492000000000000f424056773886ab9ae39b4056b656fb255a3af50694cda3ff4d8d4d450f15ffbbbd9043f90fa6f45a7e8563f8d305ab4b991a2c33e51b65f94230c9bdd457a3b31bc007fc047073657410430100017f113b550d4432ae02cc0d943900d25f6833c26bc1df867fa17b36d215044f889bcf7e3dc63814f6d7894608232902f7cf313b28194f104be657b44bf54471c300010308c0878b3b0000000007fc04707365740121080b9276ef17348a17b4d25e1d429594891f5bbb07fc8e33e4bd35bdf8296b7de607fc047073657402207f8f32be9443b0547b4daedefd9b6b0b655bdad96759a57569bfd429291fa44f07fc047073657403210bb668bf543a321a7cbad607ba5714cfbdff67e8d04c9a4dc539ff7672b84b19cb0104220020e7da55d19cc85b0420c539a90b667d4d85f59ee0ed417493a947c3a2256cc0aa07fc047073657404fd4e1060330000000000000001a000d4005894c852815a527aeb01259da98708628a2f2657826496e2711f7355a941f50a31be4e1df7d245f27e22dfcbb737e28008eee8322b6ee9755cf564411c5f360cd8ebd076db3f857f2a89a6dc3c84a200a3895a0a68b8dd14ca3c294eec37cd45d1cc69ba3e5a114c8a4d8e32eb79cdf984ca018052e503a5a6a71b49c78112909d2f1b1fe97ba13cb6804156d6202dfe1275a223c3b99f77964f3eefe61f87d483f5d8273edf67f4ba970c9abc27627bdac0fbfccdb6582e30429d2d82ee4658e2284927f66b3fcbd59b8282ea88e37198b3e6809a79e9be849ae2080195239e82395ea60e837e3e03459c4a635ae8626d29939026c1b69d6ac6a32a6a8c8a3686d29c636841fe4ad37402bd3c94a58b46a74898b614dd318211822e2927db89bc8d121373ee1aed057436ea6bc084e7a38d612fb9322265c7b04ba2a4187cd70856fd276971057ab4aec79d4e9f1ca9bad675c62c481a621f23ecb7b78b72a90448f40620152a603d4a150d1fb87c37cb281195045dd4730899f58f4813c1c99569828f377e6973bdaeff1bec942f98038d6599a73de84ce4c350ec161074fc30b151949f22687b9c50d05e8339c048beea2e944f77f601797f7fe64cde986746644b4c5f0baa42d6738add8f9773e7ff9199cbfa3bf03cda1e8be64163a3d8cff0875ea6b495e372107b5f6e9602fb6b0654e5fe1bc8a2626e4c9ca3a33bb0d2755055547dbbd2b1548de0b9fd7193ac0d3bf7d4ecc929c3ed0b1112aebe26188476f63dfb75b12187242436f8bcab54de04510dc31f3f3f14204e8b50bf3594432edebf93b26903f87c1dbea50dc9af089c4092654250e1505301daa5b0534645e52f2d3c36e7af6e9e04f7b54111282044afe94411854aa73be65f18fc868f39f79e312f62c4250e61a2511718808980fa0ce8089437569c149f4f9381db1e12e4d2d1ff682f47d63c8cae57eadf9cefd30e52128dceadcee043c84d90555b10095765a0d1f898399cb734477bc068fd2b37f47847332d38182cb23da3800c56dcb2a074aad8ef25d741d569c355fd4a0d806cfb698151873d1e48e24fe359b2182c8a26a1ca1c21ab609fe19dadbf5f8e3ffed3fa7679363ac7e303eb917554fda9d2bbaf6c053e658dfeeb88448f5fb017687f3eecaa3e7ffb6188c18e55678cbe2328a05263a987fc502280d070f181129902cc0f5e415e13f76b3f58dd257136ce579c4a999b127374e2bff94f694c456247c502239e301d21aa870ac1021b97b11a7d1ba0095696a50fe16e888616548d7eef96efa59cff978962a7c6f38aca24282091616f6acdb4bebedf236c043b36a6f12eb82c2c589c6a71080a46cf27e6e663060788c2871ff04d26ecdfe534ee254dce0328134af51228c908c5184eace62cebf5ff692097fc2d272a7275b965ef8b5953fb1ffe8d713cf92bf4b3f6a428bfc3aac0e67aa93e9571902dda5b1f66ce523109092aca555f007ee5529597ec185981f45602be0a8a0f9e9b75c477e0af5d27e546adda7c4a2776b97b9a301f0b6fc15495197cfa6f2975d19bbeb70db18dbad8d0ed06176d97c066ac19d4061d7f7cccedb352788ce5d15c26fd970bb68b879b5571ec5bf2917d7d58249fc8f9b2f5a5efd5e3596451a7be38dd75525fd1c2b0444ef9aab646869322c23e52b1e0b2b420d2220a4c150f0c6b8a4bb245282f546abb74f264b6c75286d05fc7bb2c266b5e9864bc6e9b45ffacfa2352ba898178856db19b41e7e6d90ba0e14226e698ebeb02b3fa349e8ee09d7bfee08a54763ac1db861aa0683b78f6bf07263e3cf0fff0b91225e5e009231155bea60b2e661e7b04d8803cf0c89192cb8f70cf16a6d256bf31a28d2203da20d7d33c7a6f841169a845ac35c8fca9253e807f72e96355c296323f6e0a1d48bff8c43f55a594fa251f69b907d9f97e7b2feb5296d12d331b34ce9107df9da5671effe1120e078956b85abd24c8cc1276d648a2c515791fd40ab74a5c46be36a6426b2c992c22cd3d96d61ddf089ca711c15ec60538057230a2e96a92ccfd605b09a4ead233440b7fed99abc47c50263728b18b2bbf79d814c30b5e96a72393d828446bc3ff14bcfa0c4530b59750c28d7c9639c961ba47320401566962b9fd69df8e87719e0bcfc5e9987d1cd9ff4407dec489ec6e1c0a82037f7f0f94d3a06d131876d541f3885906168181c21a395a51fcd3e2efd3d116948742f8911cb892fa7d4d4d5f83e86c9334732191c632a2a6a74d7f760ccb95e04ff59f8e207ca2491d0a6f48df78254a0019fad13c0251e107639d5669bbe90cd0188042c02eb726d3d33f69e5ca06ac96c733811098c5f9a09210b762e5fc94c493552e060058e811cd302abe0d60be900fb0158126a4d3c188a65ea6c2620aad9c73b0d452413bb26c5e6c3b2d885731bbac7abbd42895d5542bcacd1a93c405daa46bea191af513b0bfc3a1f992700daf4967cbe498bf1df5bbdecbdef4614af954060b7cb7de6833dc0d721eaa570659400f452664ea7c88e410ec5c35e300465ce779d76b0fcf8ecd375f727347bc46e069ac8ad816d35d08f4da02da77a75447a3da203d8ce3a0be9093dbe938dbb62936c7602f9bebd69261fa9fde170c9fb22a345183ae119af5b9a47c1cb0d740ff9771a27493c9bcb0ffeca14c376e0512014dfacbfbcc9d0956db6d642cc892dd7d8a5070b054f26e977ee6e3c121b16163d8ac151df29a5b8c5601d3cba799ceb10f04141c3f6081d7d1b6ea22202b3aed1f932f8cec9c65eea07befa558159499b1033e235078fa7e16be66be6f2ded84e8b47708a59c0c707fd79061945818132b2f2e58242238fb3c3410d2080cc8ff7b9a689d259b2bb63fb40f1af64f19e4dc53ebe3bce60977776328ebf6dcf24cac233e04c5df29d5ffed25609e3b8d96accff140f9f6acf21d9951ccff9f5c9bb27b7c8991b5bc8c2dbed6ff31b2b6e75f6f620ddf45cf6f67b900678567745e607b42d0bdb9d86d80eed1a1923c2386f371e0d2f11306ded8684325e46bfd979059ece5fdda6ee9b5ffd0697a54a64abd7599292509c3a82bb926b743a91affe05b7dfb350b605521dedda17617dec004a378b01682b2998941f02dbbc804c3553ace603226369bfca98ab4aeee767abc892e00f56d79438d075692a547da501c50289e91c3a891646daf82de39c7abdb48b3663bd870eaba0393b66dc7723ba77c588f5246fcf7b877e296fb784834e2cd679b54141860f4696b1b1ac330edcab74b59aff6fe2e36b7e3a459bac93e5068785f455d12c51b486f2063341113b6e196def028901f106b9993e4147ec924af8e6d86155d8dc2aff8b1f9268d9c75e94e253ad38ae65a8cd3cd19161dd5258588f8e74f3da7bc7df4bc6b7d23de75a02c87e8648a7bbd55210110239ed6e6214189825dee3bad6a028c70a2bf249b2294234798311c5695fabbfde68637ab9d066fca327472ca460468d34f74922aac4f1a64ddfdf7ccd4fe12d83ef033b901384ab8149ab50288fcdf087a50c0271046e7824c6c69c33ce1179c9e87dbbca60692027c1c54481a8d4909fcb1f2565c47d50218995fccd8cd64f51874180fd930256880aa1f696c321790cc5c32c49d146f6cd0128b18c52d00417adfc06aa6e279c03f5b21daea9a33390a91dd3c5281444d023362578aa83eb3a81d57ad360d337ab374c1bb3b251a51fef636418e1966cea1b2135bf444a03c39f4619c7acaf3c7a5cdfdf8a3893696e5fc076e915af6ef7817a32f5c815803e92810abc3ca09e421f8f039206e524a47ed746d3ece4c67e1dab74477abe25707b92598e71f6011ac9e3ea85417a6e4f43c55f158c2c73776c63c3af8fa472016ccae79a2b9e99d8c42fa1cd72ce8c9cb3c535719e075a0adf26fbb559ef129512833698d6892ca1a37f176cf6a363cbeaacf40813114285b032412f6d98854bdd758465604eb2ef4756064a16cbc02763323f29722e625ce895315bc6eb1ef3aba39543df3668991b3d7ce33c68ca975c18823cf37e8bf38b87ded0527d61ba10aa43db45b82e23b1582da992b9650f7d146eb420fdf679eddc26eaa3639a6aa41a2149d1b89057a05552b772504cc29132b7f6b3eeb5732a9830fca236fd41645f4da9b38b2207d931944a98ad45585eb659b7e1e43fed797c41705265bd155174f52e45a89ae79e5c1dd264a39758ab5ba42f6b721b926a06d45ceb114a0ad592ec71276bd7fe1cfc592324e58b37500b106355dc6ed962e1830ce33f8a18a0ca236c3301b0bd9029c6dcee2dc37057635fceb494a8352d74963fb2e3f75b91b19bbdaa49abbf11351f88b4d2d0550320a8df123289cb16e1a4de9e71974d920d2b28e59037e3a941e0f7c6b2265ee281d0f9da960d2b707fdbd0a58f0a19ff8003ccec3d1be962eb47f57923ee2a1df81cd2e77430eeb8e0825e8cc93ae0466a19c80dde5b8872491326f877b27db9543c495ce3c5965bbd48f216390115c7c31bacb20bd9f11267d2aedd4586ffaa27664991a100235bc197ea189840540fe0b29a07f24c400ffa2bd81eea1d15496bc14a65fea7e05604f987cd847b0814439e09ef47bdb3f273cf0a56e339e7105542a2ea1fdda77a2dcb792e474cd086341b510cd5b424caaa98497744303dc149759640302337f8d4038396f776dd79fc41fba310214a60ac5e047311bcdb5daeb1d8a601368fd3d84f981aa6fe7fc43d244beabf0a386414c569c8599918f8250487c546f1dd49a7793061a0107ae626beb6bda487f633b1abfa389e182f4f1aa99309ffc7c0b69344d0e9c5c2feb35cfe38f33c6f8b668af1df1bdcbdb5822c6c1931c7ca25258556881584dae524b35c0fc1dedf8604298014dcdfa39c3d38908364b01f55062bf7ad3ce8f85bb765afed8f365b1996a6600d39105203dd47023b5de1e2c2ff78a2e4b1fd6329afd0e86777471721fdf55e7189b18718b9c7d6f7d764b6bba82ea9eb9cd9dd9c09b9ff5ef25b3aa8ab309e6d85f43d6dca7681a49975372a9ee196f917e4e6b390103537d24a35a084c5eb5b378dd1654025fbee39935f599bd4a15741ce19479a93dc9489035158fa0812b6ac13c6f247432cf8ed3a92f86b372cf624e5b7b2a419184ab9b333a461d5fa9df9573f67212435ee96a59a020ab3c1dc0c61440905516a8b6f341e4d9cceac3129b6b7b6b3ba2ebbabef7857d8d7594f778163a5f95f9b443067a94f9e0fe9db323e25ccae107e960ce163d62fa0c6268d99cdf208705b57e3869a8e0687fb95d9244a3fcb447add7b7dfa850e9af704e2619821754988858693e27fce4b0b3be89e42def5bdc8213e02489179150764fc0a542e382f52e8d7cdb80e4aa78ac9b3d1d56ab23c8b885f0f173c4020d2330058dd37a34c0c1fde5142b3176254a6899d47514d9c2e68b040104b134f331dc4d9036505210d4944ab4b7762bbfa364fa3d96c7f87e53bf71d5a5c3c40cad698031e95ff17922952b5d1f9337c93bef79c09d075ac5d73b37a317f6c4d767a183283d1bbc97560d4930e47628d489a2c28267ed8bf0922b519eb3f72c62d710f81f07dffdf6d41b5ed95190ce20e2b94f8cf525be8352568b59a9a9db7840636d2b76494fb3f791bbdfacaf5541ddf8d7c104462dd1c6d3006bc386ac1f55fb8400589bcd895274de80092f69d1c759fdc3c31f2e1681ae75689e587d9b11a5673e069a98c1f77b538829c59e64bf65c1417abb2d8f52b8ac6c4bed00ddbb1a1d04d05d874315f55ed580c6fe3cfc967c15bdfda8be76eb1c77e3a720450dcbce40f772c28097a0925aa159858f38058ace779e4d8467de433e39518554630649613da5d20707fc04707365740563020003891394633c5f31c9ee5ca072b289c5be81c8d6237fb8290032940c0f535b9f72b4a4b8e967bc5c791a60b0567bd7c2fdc5ec71eb54c8f0770c92f5488c50d1416d636dad9c610e29d32d95c6ba93f6ce39a14fd1e6a11c2934090f494dd860d307fc04707365740621029e5980b4f9b9a9fd568c1c4b48631a800c310405ae8b2ac41ddaf87add3062f107fc0470736574072103504bd87c31711ff592af95f3c9c4f78e63f2f30805bfa95bc2d21e5a2db5c4da07fc047073657408040100000007fc0470736574094920000000003b8b87c003c8a469312a60ecdf33a36e22b37eb9c3e380ddab84491cd12ef7c80a6565124063d8d889bbc3a6f2e0d2fb66f78adb6d5a43d5fbb716a5f09a0db9788282a307fc047073657410430100018474c718fb7fef3e0585e56e19e551b357042f0195930751ce4d22721d93302dd78d263aa3c247113a0958851c182ad93f59216c95ad62b808bad00d4127fdf100 \ No newline at end of file +70736574ff01020402000000010401020105010501fb04020000000001017a0bb9325c276764451bbc2eb82a4c8c4bb6f4007ba803e5a5ba72d0cd7c09848e1a091622d935953bf06e0b7393239c68c6f810a00fe19d11c6ae343cffd3037077da02535fe4ad0fcd675cd0f62bf73b60a554dc1569b80f1f76a2bbfc9f00d439bf4b160014d2cbec8783bd01c9f178348b08500a830a89a7f9010e20805131ba6b37165c026eed9325ac56059ba872fd569e3ed462734098688b4770010f04000000000001017a0ac55f449ddb6853f2508766d5afb9f3b45e41a8ef5368cad75fb88e5e249395d1097d88c92ca814a207f73441c56cee943f0bb2556da194c14a4b912b078c2238ae025341cb5e4e2d8cb69e694cb20e5ea4cc8ddf2801180096fd071addfcd8bc4445160014011d384302576b408aa3686db874e2b17cc2b01b010e207aff956e6c2a379543b1ec82b06958f062bd9f29aa1ac1c98d1f6398b65a8555010f04010000000001030820a107000000000007fc04707365740121091517eb0e8ff9154ed835c45bed0856ff6b385b12f7aa224a1d91a532dce77d3f07fc04707365740220230f4f5d4b7c6fa845806ee4f67713459e1b69e8e60fcee2e4940c7a0d5de1b207fc047073657403210aaeb20261582b6a470b523b53d6969fb878704689a6ad0b0a690ccfc39b2b03d70104220020e5793ad956ee91ebf3543b37d110701118ed4078ffa0d477eacb8885e486ad8507fc047073657404fd4e1060330000000000000001c49a6101a4a3a122e2316e466cd2d4eaf9ec9029024390d41ab38146cb008e124d94df5c0827b57353b88df660dd6483ce69f89db194b0d7d14ed04f67059e708fc7636fe37183ffec38c28168f7c0680ede63e23a53ba0312fd96cc47dd3e147809c8e4642ff5d4ec0e280aaa369b08f41694cc6abbf60716678f7a83d7e163b34e2fe06c203e702e52cb69a5bf1a37aad479d9bfe7feac1a16bf927b3b233e50a3f86a07d6cc69454b0051df0f2941fe86e98259b91945a7fcd0e5c64c4ed96a302f931c23effb8ef97b4e1e3d74b0c392f686e49cbf255961fa03fe32cf60bc9a030dc511564600412f8f57541306f83cc6e8d3bc84796e7439bc2afff98489754bbfb6f28b2c65bda4cc8d5514e482804391bfefe3116798c5f477d67c65c4f82f18d10c864a59fc7f9de325922415422d0c57fa70e94f878acc88d9389dafc99d584194ea5329e1fcc5a8967fb1e7c7a85384d1af35b0baef473a948d4f2c02403e0405160d22e793b079cba61377a2f25a78da9233bd6706192d32f80b6f51bc86452f47bd0e8e498033fcdf84fc16298b97d6e4dd4392f37869dd65af84394fbce984599da74907b70cf0bf3181dba69625aba09995afe37213f7a38bad1e4ee4d2d5741ca334d05f6fb5ed40847ad3cb40d75f3a407e669fa77acae9c7e33fb76a92ba445f6b955e30364957a448702ebf2193f9cc6bace952cb2b36294b34f024d209aae3ffbc8c3d3e3e3984d60ef7759c165d5e99b90b5843a706be29ae6c136117196495f8f575303b156b62e77ca6654975296092a630950283ea808bf266935c5f9e32ef637fba8104c2e766101cde30c48bb77dffed39b1aae769bd378860cfb4dafcc4951893e9549e84821ae78a614c99a368336d86333eb48234fe649eb911519628c65120b395c9cf14a9f2d9398ba6dd8c3ec2ba00bf9d18dabd8162e5df48ef3f1e26fc8e068d14391b192981cba1b9e665649952752c3038aab5b4e108b705c1b90cd83699a1ba2323cdc3eee1f2f1d909eb11da0c3940fce919d65c4920b22358995655410aeb1209a8c34e8621bbd154536a26d29a93c0c4a0b9cc0334e0c5ebe960b3c5e49c305c6d062eb918d5d1f3bcc95c900e06f737623a06a799c2a6bc182357d3f88a059459d02ebc492e7b9b43b1e99a4c8ec157483ecb70ed81e0e70855950f87ab444fdbbe20ee9a34959d63b9569221001942118479bcab4acf18dd56d7d768c066a3c6b2467e5dfba6b5ae5fe5ff1e00489e732b61899ad3b8c82c8ceebe76227ffa9d57003c1449a7d34c71625a1bb8420ed046d355af63c8b3ba4983035de467716bb34f7993970a019c9c87d8a6d66b52361a1b10352bb5eb7f05ae1aa6a487fa3452f8d25a5ab58394543ff0a4e78d75e47324572b42add9ce1768d78d84524fca712965346a542660648230c914a0ce93b460687287a4d420a4894dad96650aa4b473c3a01b1f561ff4ff4c06c5ac946952c9c009c2aaab33bfa7cec11f6a24d75d8112732af0fb6c8a0d1cc8d7d202f4cbcf5810f2d1c8c6bae7748deaebd2174a39828d11daf145e47a16aa86fab16264292ffee07bfa452dce579204d91038939ee866f3a0c46dfc7fd6d85409c96450042920a80a601d11a7a8ad231c6d996a79e6fd710969848bd357dec3b7d20bcd1aaef36657048000192f7e3f0910b954a943f2d9026d1e87e080f2b78299a00aa2c7d86cdf66b6d98bee293b46c44a3bdfa87cfb6f1659d213460596ab89e90c08151252e171d87a4406ef3f0185e21bbd5db0e298874faf77e743899e2af8eaa4b2165c8942c1bc488723d684ba8096d64b3c032e9d07ddc4b8a5bd1027a54ade8e56a73c15fcf1f204b194933c6dfd5a78e449987e682c81970cfe265aed282b7ddb9c7c952859205a42ea2c24abe55883acd0c593edec197b9cfe5fcd56d6b867720fc1fbae83909b65f5adaf21526cedeea64a4d495b409244fc734618590f0efb15d76740234b19cebb88f70d29679d2b0b34a739bbbf2d5e9ff15fcd97df5e1919eebc2d1f469f35f024cd79357963374745e92d8e8d1e29a286f6fbeae0fd3abef755b514503acf5106a2fbb2d2370621ac3c3ae34bb6f14f6e82c71d01ae33a1bb629e294022ef9cc50d295bce35cde0beb14bbeecbb6cb189ca692ed2040bbe0312e9f446f2f7394c6daa130628a03956831b7ba63f0eecb5caae6472dd44459d69b994917e08e05665c16b1e988189f468b170321876918c323e52646481532616d4361c8c2070217d40e052a6dc487c1ef9f030922458e829a3ea15d2670ac3acea32e9af81b2a455d0d63bfed89e911e19fff080c7e973be22061348266b26d3bee8c4c3bfad3ce0aec84b25e3cc41b46a902f9a119775d0a903a4657df112ece8e789aa7995fc90033d503ccde74901b1b40c440936fe0dba6444eba823b328c8c8187135be38a651526cd1e159ed806714547f09f45be5928efe384e91ff6be03ea8992b35eca865ab4cf5ba7788ba95642fa530f58547fe597cc3dd8bbe223bd008aea8c37e7433547d2ac5cb716c2403472d7a96a76d41e9f3b92a7db1f7694e28446bee478bbdb1c2c6fa787daf10ec2f539d87e3d5e43ebdcd43f2da2736d15cc9708b74c69a7419fac92a3c1c307867ea243ac4401835ecb459a888ad58cd2141808100afb3e3bb056fd9f42b2df7d6f426b4db8befab9582cea9954f58f2d899e1ccb4dfde1a9d7a8b2076403ffb8c7e14661038f952dac328d5b21e7f1e4258ca8aaaa43f426c8213383bf60d60640a9e67378097d5f07e05dda7159ef477439be71c28904ba4226708319cf854f92c62f51d7128338578eb259c0681e7bdd27426fffdee0081fc9430db6782e2b013dc7e76e4ed043dfd7a2078b41230ff437dfbd240d3f11f2063a808ae011147a4b6111b4fe3339deb4c0e5bed8ab5af0a991175ffd33941c586a1da510774e25eab6858f1128cb7f7e2a53645f909c96a4c9dfb9323bafbb9d75a7d979238b3da069ab16fb7e621a7a99195b78e11f85262d9d6413a7b88ca0f6fca17cf9f73a7332e7733a3e153d4372dd2e6d9af0b7883a99c0b5925f817422085808ef25a71bdea61755449dab91704b250ea29fe5e66e776217fd38054bce90e2ad5d8ceb32575834ea5e07542f2f1795c2c1df6579b7dda3b3ce9382bb9838e7324251a9f7848c56cf213ba968e632fa9f99e2a1f4f916231a70ccaa450fcf8b9a2c44f4097b65dc4fe63b218b6a3181ab5a06d69483442ad61277cae828c7b90e2caed91e8f9f02582a642fdcaf72b4f1d3c14102d2663726555288f48393a178ede1692d3a8209bda7e3a3e1608c4c1ee2fab5a4ce7960e4dbdd00579261cccffc49cc8a876f250833694809739ebe0a252951904b994ae9c190b0cc612e2c67d25be98720887dd8c9964ca698fc29151f833496ec3959c05a8785c72bf0f1c9c9ea41616c9aba960ac21c38f71c82ebf3757e86da00bdbfda319940c1bd8e468f9d83654d87d6c1a7d85cfcb233841ad0118e830e333d7bb1c19972f24f6efce9ed585a915a4bfd49518c485f9ce5c5df734f32ec825f8f259ba25cf4b9d0c1c1118d42d7110609b5b44c4b0d92c70101319793807f2f209e7b5460c9ce8993a11fc9613c96735cd7e2a3358756e0b4c5e24104c76fdd19bc5ca4123f6d07557bcc4c350b3c5b74eb45418afd2213bd52ab2d71658a59367441eb73c37cea82492073d2f38b3e446740b338cbd202f28dba9004044ad4b5b7085ff19a4dfab50603f4344bb2526fb144882695c2a31d86a4163f092e697065f55290b99167fab57c5f22e51fa1520ac48ce50cf54841ae22cc480ab4abbf078469e65a94969e510af6d58c50b140a38c03420d33f9faeb35b44cecfa0cd19cd27c20026bd19b2971c4f0d32456ba4dd4af61bfce234b471c54c013f7183559e4dd12e8fa1c297733da6d20c57b838a1db8fbfd4a367b5969328df2cb18688b7099a504e559af5edbb54c7b58441ae15c693385e0ec40f3043fbb0457292e82cbcf3afd3b3d9d510691ccd1441fcd45c9342522010f140ddd6ae4b79c326acf5f2873031911a4ef7b53363121c20ef450e5f64a63729969d038be74661ad9260ff39d738a476e306b15746e4c3a72aa2168a8c276de4b3da973cf8ea489320e4d1df7abd1f6dd38d9bfffd4ad26c3f9d874377a4718e13e77524c1cdf751fe433b72cbf89514103df8dae6aee905f24a1222633578607909f4473397f0ef7880069eb16772188793ae979cc9ba90adc6df93f059726f8ca4f94c1b986c8ac1b0ade97c23b139d303fb36037939c63bcf0b0a33cda54344edbc759a3157abddf7afc3e034ad2881a55854b6ac679316d99255a5d0a93a96b0b1efbdf8dffca1c4e9c6ebb11c7667bff42aecb0529b809eba6f7af3eb794614bf4dd266a19248af7b679b5f5a7c5896d3ad9fc23616d579e98d7959793f9a4d96f058544e38108ee04fbd9b91249633cc405c0f3593d4a337ae3e0115ec1af1f34f96d633044897193b6a132f29043922fd57866d9e004d3aefb8c36e8145226b1dbe7866f46790097f1052e6b18b50f6c83d4ad670dd0784cc73662481f415d03348427054a3eb50695ebb104fd45ce6a4a23da4386c3d384cc8bc7aba67ddaa49a0e49e98262a55c7947d1effabf398f919862fa38adbb723b1b9d1526dc11f970444a05389b3211cca97e62f94c66d785a96e8c507cafae02b6d0dd8fa0df684b3ed339374850a9e3d540eae25bff5803dac9c5d8be61b2bcf2055ffd946df6f5ceabffbe84dbea695e0b67f3b8bad1443eeb743ff7e4943140c036832b9b5344b8db3d85ba958f6935646b601b2fe497ef8ea1645fe41760c70610326c5253cd8c84831588827fe8ee0ecc661b87103e6e99f567308f580e2387d6dce7901883b8e428bbc9cbc19c1e850bf598f204258c9b6f09c4334a8f95021b94b05ae197dbdc972d6bed5e8452f39cfb98fb60b510085ed739dffd4241ed0eab4962d34762bfc8cbda6dd52b3a324612c32ed80b9d77c6c41443a9c2a40dbea51da644dc6becb9546843687bf9f4221b8bf436863833f258dbe98bd165488157301d74ff152483d6015459b11daf5f1af98293264d91b96f63885d7fc45d3ba117c22b420994b93b0aa207fd221370a55bb1cb130314ec9d21624a01136a5f51a5d1e028585896b7ae63cfc84c9f493430cce38d1fbfbfa7db9dfc0479ea027ddfc38c13c7bbe957b04a31e90ca14aa4e9f9c12e339d09811eb18f32151835f4d396da9decad13363c93de8d7499a941b168ea2367dfbfe3fef4bad204a12bd07ee0762de00cc193707d3889efbf13ad72c54b210b066b699e8f7c67b07648b743fae60b5f09f3455be11edad01c5b4a70141f969253a63754ebedc338e83755e8b762b023b60abc12be5c584a57308b10c8a335666d84171edfcadcdcd17a6fd30450985ffa2e690d00e5bd21169a0404777f51c37cbb89c745559bc7e81814d6010d331b16ffc4fe2e88f37256e29871a4f0f8c959b78927ae0ee449559e3f895327227e859fb6cecb20d4e6671f4d9d46a76163ef3c3490d1801ca8039b5934c1293deee598acc83a4b776d335912d0a2c602c653f8f3e9a2aa249958d94fca07a4de4366cc5349aa2f3f599f33bab74ddc01944be806a35b5141c95dc778e6ec102a609c7346211953510d7105d436112868d718b72b0b861aedebb4c77d6f2ee6b7101bc00ed406a89923e19fef2dae304f528ab56e9086fce342e4f19c509809fa399b2c150e6911ff5b96ee8627d226ec33c0b84c04ab0afcfc4d89793cfcf6111aa8fbd217cf5706aad49d4ce6480b7e57fc77c07fc047073657405630200030ac6a03fb2c4143a07d1599e22ea844e3594b77f4a960e172b3c04a7b9f7eb647887e94bdae208da814a7a0d2b216bc0a730da54cd34522ae1b71ea70a305a217014067b0ed40a77a3d1e92afd3c447018c8c60d4b8e0ded12f49671bcfa36a707fc047073657406210212bf0ea45b733dfde8ecb5e896306c4165c666c99fc5d1ab887f71393a975cea07fc047073657407210325b27bf6f8d1b06dbb69ed3944095d71b9a4558fdb574e2f032bbf1adae138d607fc047073657408040000000007fc0470736574094920000000000007a12018e6f3734441bfcadd5d94f97741e750dd28201a658d4785c5bede038f1a1179290dc688efae09c0a437af462dffc2fc5adf6bcbbae64cc40e099300c98e4cbd07fc0470736574104301000190d59bf3b61acfc27a23ea0f5994bf35cf81c62489a2f658673775457d0eadd732c4aaeb4275077bfb347f483378e6fa1570a1912e2a8a725a7a76eb0c2e23ca000103086ce2ad0d0000000007fc0470736574012108ef054b3ea0c1c3a6eaf67bdb0759cc44d7fa953fbe2df1df4d39a59dd6cc9d8f07fc04707365740220230f4f5d4b7c6fa845806ee4f67713459e1b69e8e60fcee2e4940c7a0d5de1b207fc047073657403210a93480fd89d465d14eb4e976496a7098fd22f5072f5740d60d12eec8c8de917710104220020f6b43d56e004e9d0b1ec2fc3c95511d81af08420992be8dec7f86cdf8970b3e207fc047073657404fd4e1060330000000000000001ff1017007f0c699812e97d8507c899e760dbf4e630430cbcec3bbbaeebddc10f855c3ff8c3e5f54785fb6f527922b522c7d4cb56bd1e6e74afe3e2149b66d3c9a2d54e8255aef17ac0f30687ddc5425ffb31ca3b51b9848200eef211bd3e0f6a7883ce56d7ae74f382f67bc67f03482bdd1b39a6730b60043037cc4f53bb18159aed2ff23fdaed63283b6c97d14ea9674784fdd0e6e38553e96ae815338ec811fd3be74ab655791568137868d626a13beb59e019fa445c25d5b289cfb84517428c7ed913e73ce4a984ecd5ea6e307553665d6e0944e9698821d690b2b4cffad1e4b1e7c987229488e01c63c3244c435a35813695250f9a665e8603fdcdf2e65e5544354f886ca40a85b863d45221e536efde55f7ec8fa055e9f07bd988774ff59772eb96b5e0c79bab01cb3fe141a461dcfb03a5469f6f39f23413abd729ff9a450fbe564d8126eff14f00b9f8ccb05452ba471b79ecb9e9e8fadb67427bab207c24a0c2e6799da4a052ab408ddaa8cb56f1dc4bce5459a70aa35b87bdc85798e9f0e828a5c36d0254b98769a3c0fce7bf97188afd3d32aba2f5a1a52c057204b086c04220e2061bf68e76db32a0a0b6703e3584a652a72b32404b307209cad70fd4e451441d2aae539a168a72cc7ee2a51795b8325a7740e788a897b4c2ec053df02b77996503d50131f86936b4e0e9ac07ac77e2fb1171a36728b908e8e27e772750bf63710a7c137d87d41582da6d6b0f1c423e4a3834e7c45234f64974d2b544060bc82c80a74fc1078972ce74e87b71fcca7c63d6a1c7bb852cfe3b12751c9c02401490fbad794b90e2e7aa304c5447f4b37d92ea304f52580f38bb892fbfaa01e63fe6c2dd2b25a092bc6a5b0cc918a7e99f68baa286c19834e738cd400dd452b60106bfaf25d2da9767cae07bb82eae3100435d1c95bb9fe2053660a3991eec9b40af76e8d7564c6d07aca2da552c73624cd756dc72e714d8e784c9efe415f12d92cf56a02e886c329d8b7ea996c465c45da1f84f56226e816b3ada59c100177d9cb4bc0a593372105fea9e207730b57ac2cd97a4baea2b1b92cbae6977842bfc6279cc260970a41f9b8641a576d80266715cd0e56a2379b854d607a9cbe64b575cc70855b4d46bcb1c7df88dacf065d7a6fb52c911f60dd54100225163e738c8f34c820f285ca2d2677dc63e12cccf9f1c8e875af4c0eed38d15d8b685bd82843ab1e7d96202d411e839db71ef148c9ef7dcf1f088ff8f04c0d408ee9c8326b9dd73683aff18a7602064c4eb56c47b525e1918315a189e48651a944379fba7d5e1473ddb4bdbfcea6ca72d8ae5c06a37093602c8d2979c4c41f6633aac369ca839fc15b0b06aeebcb7eeb178a4ece0d221a3bfee4b87a019df15db5b27f27ca9954b073092dad3f3f5cd8b78e715ec42af635ad915693cd547668a5c6e9ee375c3789578288d07e655e1f1be71313cf51a4e2b6f66fd4c740d249a29a85459daeefaa618f42ac70089b86f07d2c80eb74062e617ef375008d94a8e06426a044622f3e46f39a47857c01b5c3fafcdcbec916d15e7dca650d09324af15274631e17a55b1c251cc72f9154f940e47055c0946465f4b4b6c9b3627b309e9ff0066e0079b590b21a135ef3287df488acc3d367b7d4488707f888432fd38cf1854cf1f57e0db57468217b6b482639c92c9bd3f3556b9b5b00963700fb9043bf85e1edc39b575c56cfaa75eba62077492d0a764cc6737014d94b99696f7a9e0401cd54b0415c6c05eee5967896f6c8d9d49d6015b787c1d563022841bd47cc7d5341cb7eff22b46a99c8920f8e3ee615ccc873c8b759ae18e12a8ec8d684f15f5a48e3c1935c94e379fc6956c1e0f3c6167775c107aa59db7a05c9b4ed00cee4d7af7cf3ab32a185444a3c7ecdc24dbf766fb097bcb0af185c4015af363dd0296eb4d87bae677800fed3f31339d85a3b6eb688e6e8bc08b1b5709f482463b8d968ce7c0aa4396c5fbcb7e8f98f64498810ecca8a428bd721f390a95da48e602b04dd20716be3384e1003ea605d8492b649d78b331025a6977d5269ffe676dda60b3096e7e1e849d3fab7f176de7d02ddf036380cd642aea57b9ee43f7b8f53288870c1f1db0c2de7d29d91e57a56c6de7b585c35c3e01d2b3600e244193adc74100ca404534b5cf6831268d30b37184273fb797428e990952dccdd01476ac837defc5339b4aaed1d0af010fcf52d07fdca34210e9b7fc6e6ada5e9158b7d0b556ad3b28ca925cc24fe26f71878278f8ded022c8c1fa742dd44a17cf52cf5e5b7fde2aec0833010d2a70882b4cc1b294fb5e0a6d59f711f0c6656822a12707b3921ce5d835c23b1c699cd9fcadb7b9f2f21660f9a303d41ff817f5d1581d2f3d6c653de4a70ed1a3cf9af81bc07672467b87f38ea179a8d7a7c64dbc26d466de0a2197df8807d493d9f809513dff4fcead72c1c5b3b5460a7a665bb275073dcf64c941ae7aa70d42ea0ac1fb04cb9d34debaa6593ebe71c549f941827149fd76f9f124c311b189868e4ab43e9a020fee48e4d7c92008ae04ea5bb10f55e400c2adec535c35c44bc9e75e5547e79bf18e8d3a726522f1ab886030f2a4522bcc4c91e0f9657e32adae30be072fa0d54d1789f471e258c2191783026cb14c6b796f997c352ac64f048dddfcc745075967e16d7bcf57cd67798b66d2446d9445d0d49ed922f91eaa57ab43afa1ca90ba1e7c6c4e20416577ff70f6ae365b36adec6c485d598717bec53d58e28301589338fb62ff2b325e6a04c44a68fcf91f90b018dca2b35e5230aea6f5681977db3eeae1673c4a10b07efcc3ebe7b0fabe67737d852f50dab5e0eab00e0a42360fdc8c33de0180b48c59302a50e59f1579cd8a5565ed4f78c9d91a4bb25ad99c917c579016199e7bbafae97dc1f943e63c022542d8a29def106afcd48996a221878a5ef787259187846283c641bce500834dd452ccb058607f4a5ce5ec2a9449e2a17ea699a5a3d23febe7ae2fb46f4be2fe472f813ceb932b20f131cf799f3d6413b7701bf7c17518ad79c53eb9ad2866535b5b492006ddeccb7e59e77525d5b064696d91436a6ee3d4d0452d49f753bb7d26da00af042739fee0308571c801d6c63358e03925b76a1dbfbb1b6a9663cdb1a2a58f643f84365eab5dcd9421e73007d4569c68a758f0aa6e3531170470812cba605017082b2efc45144f885e09919e522a1233001b798a9e09acdf6a55b52a7ccb189bc52879ba263e18485a285db5b4e178dd4d69d873cb92b1dd046aa9f2905b5161195e750a84f56bb08dac7971ed8bfe11bb5368068877bc4cc3227f04c6e94a374616fc2c8d3991660a53b9ce5c6751fb4331d2398a13946e36f916bb4f93323496e5d90f3a6da812979032eb4318b24657a8cf2610d10b147e4d6e5b6abd1ed9e5c10f4ac3606d374bd87071b1bc7464b8c3a2dfb58692804e9cb6cd9858375c6ce775ccc1d4cb9cdebc85181384143a33e03def2e117bf4f0b4e58efee8d6eddb8da2bbdeb0a618dfae4a5a6e05c7b3e3c73a9c73851d1ca1dc6c6f4fd12c7e6a26c47b3eb24c4e3077b2389dfb6dc0898e8a1e761df61700a7d245bdb78f8dbf3f54695ca36bfdbd20bce3b2cf53fa0d7f23c557c981138725233189c1ee2bf87b603c91627fe9623363f2a8c1790ce8737cfa4c557195b338a09e863526fe5acdba9f2da6f0c633cbe21aa4855c3e8636d6a1265f45bcadd46e7a0c2655363c04678999091cb669edfaa8268dafc27f2c33cbd65e587cb6b921f55d2e0fceb204ebb7088c2e58a5ad33d95e901c658d1966b5bb5c0b20648188f1a4a4a307265652faa07cf34cf5faae1963c18dc6b6394a3b9e3fa6de9d0f43ce15d58e10b7b1f6e4d1dcd3ef67a11c84c0a72194ca652bb193d379e564028652d9bf1850f2a89314f478320c925ce58c5ecf2a81b656e7608510dadbebb5f5b1672a8e5679d5883883eb29ce4d31c33a2b551e37850211829a70d36256ca8b335ab103ee256535f4763e274b6b400814ec35b8acade51cfe0b5a858e8016e89a4c2726e5eb5b2cafa0168d4850679dcf5ea30cb638d27d2700a82cfb73e9ec0b5f207e537418c4b5a740382bb7e335229831d67dce6209850e810eeda29cf346da502257c37ca1a3769693315692eff9014a919c850373a053b9cffff0270420bd1b074a83992a485564354b8d71da32063b7a3bcbefecdc54661d877804786fe0a344c0bb01cf640baf82d913c08dc8b014f94f5e01842e2cbe05be286db2e5907c9319c7c473948e4a1c918cfefcf61ebe86b6b1d83bd76131ab57032a5dfe9872698bbe679caf9137dc004fccb243474c992bc11872f9028fb353ab63d83738ca5034cb99e9df87b141511d04daa8326be73b20c699cd801fab724ae99fe3072866e09312971c89b5bfda0f70d8868e9b39aab187bd4dd6a2e5446e101d3e9dc44ccd4f0b7b8c61840005ca6db4c4d10453c74c7da686641c5f6dbde3d64523735bbcfefb78cb9fc83cbb43b28ac27480634b0eab13637eff98a54c86a16f9397fa38d21ba8e820d77db362ba1d765c965ec37f98f7552aa28c167a0aaa5e0e4571d45ca335965f4df679b48b1aa12837e120f4f1efb73941eddb63521752c4a2a8de312791d6645a0e590323f87a02b2117d71a5c1404dfecdaed7b527b6dbe5b67c9db65c2c12107f03c49523ab229c347f4f5c842047c4b0239f29da30b4f701ecfcda49b2aa96e51edc281ae87c94bc5ec5df8ac129e1bbf9a5b3f21a2dfd6cb0949b13daa3fbc05b68f5966e8c2d69839377fef7bf68c2123094e17bdadb684f9df502509dfb1c3760d10614bbdf603167466d9c71742738ba729d2c2f816d918ab4baffcea95991439a8e52d3010a4391dd875c41109d1130f53670d3376abd7f79a359150fee27538e76193217577092dca74225e4c93f3454657b6c119873de20d134be8909a8677cd612596f065c6a22ab29f738b51108d29435fbc44554c63ba7212b8e0dfc937efad6d7d98979e5348f41f48403b6c17d27d976629fd99a5587446dc75896e4d81341d6500937fc07d72681b3938f3cb4dbf30e9bcdce272574c9e8d4c9305b5b9866bbe3a4cd2d661d34cdcb90ab195a44b6a91d7ac1fd66845b398fcec93487ebbc65abbefb91f1b282b6c7fcdbaa07444838c577310d706847a8be8c6e2d503de53e5d472435038c70f60f835723b089b98a00e927b08c06b055b67d7b716b2f10b9e638575bdd6d181bc0b045b570bc91f574b0c250f663ce355ddbf450a1f3d303552888d976225047f3816fb7dd7c9798fef0323c8c76fe91e2553782f766acb1c1a999c7309d19d835e424d747183be0b3f4bae9bde806b991aefb5b53dd7ee1f8a8b4c3e34b033b2a55902ac3ce94e66b8487b998ef30845745a9de19ea882511189e20c19f4cca1f3710cfeb024df0e7ee597174f1b4c7816f09394da6c30c5a5e7d672699f2772e7536f6e5940087e87d00ba3e8efcc5442ca57990c290e56c036e3b22218507a762de22c28f0fb7293d3d32deefe2e5d92f64555fb02013d5e383f577483181c264ed8338bc22aa834b4668f7dcf111e9e80b4fe787bcf22718a773a7af904b5f32914efc41584b1277a99f8a9612b28e140fc26117bf97b4d01c183ac0bdade40c812dbf711c1d10879b3a02798d23eedf4c56bc9eeb40f74fddda67444885d68ffe215a604470561a67de0fef197ebc51368a95b0175a4d37e793b048f48100fa84e18a79b9ed8a2a9b8e8362e57d4e7bf0af3d7608c8e669db8064f038cad923ae0187d1a7ffdb732018136bec4793e17dfb78218581b1f40081356db8e817efb9d8cb4eb0cef3c5e8181007fc04707365740563020003318739a04eeef538b5aa533a99325e69d6fc4e7c15d1d9c2a8e58e210a07b8bb5ea2d82a081398ab792b691933efdc867db671cc0d947d6f9e8f82c368a735fed64e50b23eeb6a49c228b09fa0030b4c88e8cf7b17b7fed5b313f90e0a90553307fc04707365740621027d07ae478c0aa607321643cb5e8ed59ee1f5ff4d9d55efedec066ccb1f5d537d07fc0470736574072103c3581a2ce34495158ec797a1b3b0f3fe25cf28abadca7703eb0cd2348afa633f07fc047073657408040000000007fc0470736574094920000000000dade26c633d2bbaabbcf43fb55d348142fb4298904909e18c4b73c952a5eecc464bb330404b01ec35a2fee7fbe4ecdb8869bfdc8c9552fe5229a61d6c0e98397e020b1007fc04707365741043010001455786dc62ff9326a2b449f428136e7aa130895ebea05497ed5eaccb73a61ff4c9799902b6a94c73b33ae2064e654d3986d8b931fe322b3c0fd401653242749900010308f40100000000000007fc04707365740220230f4f5d4b7c6fa845806ee4f67713459e1b69e8e60fcee2e4940c7a0d5de1b20104000001030840420f000000000007fc0470736574012109c5ba9abdcf24dcd65cd842bb47f78d6cf84f178efc80216d94ff8a2585826d6007fc047073657402207f8f32be9443b0547b4daedefd9b6b0b655bdad96759a57569bfd429291fa44f07fc047073657403210a29206a6e6974d903b467480e654c2180efbdbda5f69e8a87d0529501734cd158010422002037831b3ee29fc96f8e61ccb98fbe2dcb03e189dd29cfecc691b5a7442d8548e807fc047073657404fd4e1060330000000000000001736c1f018f94d3c1aeecfc5e79481642ae10aa575e15948ecb3a54b85b2274822d874cf225334a0603c3701fc52635fd65e8a946895af1092760785855a1c67b846e206246bb2eb1c7a660e6213aedab1ff06645630fe6b84c78ab6b74615866ba3cfe138e553d325b0ebdd542cf4a04a9276faf2e25594936cbc56aa6d70db453ad0868e47992d0ecd1227aba88a66b0d3844e26d586630c23fd6d8c162fceebab92e9d5500acf05a81fdf0b6d41db6f6513e8f25234380fb0561c2765480b6fe83d9e74d6913e1925916a3a90f9eef648a8f1caf476244191dc98cf2c39a172a0240b36034c31c9f8782aaccad02a0928d92970cf443f0331e5f580d52a6b9e6caad1c51a30e5fa0503c795fb40b0bcf047fcd873f922bd831c115b7627f77fed8fa76aad6d1250cd84184595f5163142bf77f385b47c49b529b7dda32fee16cf081631bfcb948c2426eb17b0c3bae41b16d5abc688afa285bc99579a30a05f57d0cd7bf777dd172ae03f3982ad912e0177f9cbebec46d6e57741b83289959bf6f68d816cf5ebabfc09676bcfb7766aaf6f5f04179a22d75273b82c94b7a9095eefa90574ba83aa85ea3ec3599fdd72a4fa267f7c2b944b92b690776b97b3cd4692fcd0079760d6a820ae51e1b0e6ef405d751414face0fdad0994cbf553c60017ea379d035e8ae184df1cf7fb28bfd746adef7df476213509924690e6d284ec2e3cc3d735b072f6582d913bbec5977d21f20bdd596b10eaf9bdada349dd63d99e0c28c2006f6945f09ca0d244d434f86841afa621649c4c1704252ac1a676d9131594297fde37194b901014a176abda3e2a5103b8b73b586382b3f469da738714e2d59b36cf4eee345a7faa4666c33a0d74469e39ca152ce7510f1abbf7cf24d37054b272691780309bd69916a964f2d535082d4403fca3210cbdb357ce06704f0f3aa6d8189badf11539d9e6f867cd4dbb2e3b4e13d6f9bedb459edcf1b520488c9334bec854794d3e5d943e7837e557c3131c085307ef712e122199d245bffbe6520f7af80cd73f6547057bc2b896e5430a27d5cc922ffbb5b4e012861061caf149d42b05b342f061fc5cab91be0645ba78f334c46f64615e60f37c84d641348800c5349f34cfda388fd58e48553722b7b53474475a6b6efc9753883a2b41e4678247a363998c59c37cd6c4706c56f5d5fe7596fb195c11748b66b2001accb18fd56fcb137f059973988f981c166b04c8e8ff2a52d705cbc61ee69c26f271e80995009608334dcef363a0f4eb5cc24fcb2160313836cb1707ec294c1ea357ebb70a478b84dd760a10284dd551ee7c8b086a201b900f7e3aa1e491926d74005fb2c989d32a3809ec1cca10bcad7b68c7be99d865361038b2b3023f421fff764a9ab759faf86c0a0042945969c6ca5f096cc1a592850622d6f60ba2b56287fdb6214d761dfd118ab8806a8557af5dd1d31f3d551e6b749bd37ad351184646d26360f150167a34685e24bd8127ec4970c73231e0ee4659bedbdf0b0fd64895cf13396f52417032f8bb221ea9216166d0a324c0d03603302e8234e9d98444153e91790567554056afa2f1d49d0277d757fd5211fe66a7f61624aed4e5dfea2cbbb8dabc4ea3037f4c6e236f1ee048b499cda952c7c9086f756adeb75022c1925ac0f64e4d7da8ec583e3326792bf13136d6e3eca27c56cb4be411d6b03ba8c29a4f17a860d1d27b93242e345cf7228bc6ce11aa876e7a30159a8dfead13520347ff5e949748ffc4ea51b75a7135456ca0a3b40a39bb082a9f02da862f19c651284ea28779ec034b05c07cbe85588f56b4a5432144ca7c1dd30b9783f231b1fc1ec05869de856a20a784c05f33055379658ec2a2ad24995e00c47ffc7bfea72e91df9d5e9a8bacd3ae3e12df323c0bc759857ff6e7891ef49b0176d0959f8fb2494e0fd85e68f0b8069bfbdea365850c15ca98d8e858936cce10a0d8a7d26877f260673ec3d1bb5f3ec4565726c935593e6b34c48f73e551b908f0a9c632166096efd4887e168831b0eb66c3e0e9e01a31f354e76d5f584273ad8f8ac2af7e4310b3273d106c171892ff3bd3c92f2727920d88b82b4cab6517eac2ac6a808c62da14c35536e47b33f028ead9d5486d872332fb61dc53c8281117f517b0b6d08626a4bf5d9ceef0eeb7828b56cf42aad8cc3cdaaf2c8f8970c6c20e1fa4c8dde0d822de374fad8fc898518129f7251fd9ced6b8f32364a1987cc0969892d1ab885dc9bbfa2a08a3d831a51755a6aadfe1bf78a2dd5372eacdb0e6a9668d2c7d1b720cb911005bae7f6d5d4e112aa4256171b6dd5652f95a4bd7f624b45432a99f14bddbfada9af1ee6dadae06f8392adf959979f46dc9a55439b5515ff57cb5f4934cb1259ed9ecd114014b99b3fa0f325eefa2ab8738e05c5ded5885d7430aa31b3878a10dd0a9ff95668e01477b0ebcc904e4b4f27840de17442661cf246f47d542f85a168187669820e6642cf58b23557c109b11133106fb043781a2da51fed9b2c5fdc426b4c1ee1ec47d2b9e992a2cb3485029d8c9d6dd44d104f0caa06a44b9f0470af5f905d155326e8156155903b9706cf6ff62c6c565ad9d1d25a0e82b1d8164268d83b8c8d4fce0ff202992738237d73dd242cca368fd3d3ca71d6acf49ae0d749a33eef07157adc94a049d2c6de65d2ce6a4c5957853fc89dca92da3f014739b24459f24de757abe4a127ec8f6b774beebfe44bf1eddd84a14f85c9d57ed3a9d8dbfe616db906c2d4b482b0d79f8165cd4c78af23c98cd715b406244bb5353edea403d54b8aa46206c5e8e551d1ee3a1310f7b7ce0e28392eac7e2546867d00b34fa47ae8f2c74ac9db78565bd7c685108de0ff3c0af495fcd31120e5497025416017ba47e6f32d3ad05f2290b471eb21aba1f60878f71e3102c59fe5ec96012f68e73c9bff4f35c25e65d66aa930286c31bd6a59e0d26b33cbedf4e5e43ec5ab3a5822ab352d61bfb45a2d9929dc72c5179acbb217e760683d079002b856bfe25e1951ee428475a5fa9447193778beaf49236a1a67905a55d541e69dc27eafcba25dc6ac6110f8e6528c5a3206cbeb36833544ca08db02c91ce03c1ec97b309014e52c546186d2bf62098b708054fce5cd5bc7e042f7da37780fd1ee3ccce6b8abe4c586f46b0488117d8cc2b42679ddb89dd5e4ff7f5e4a5c2e9c3101dc1d5c6d0415f255164eb38486f78bce5a0dbfc54aef8adfb647804a8358c4e5de06804539bb4ea7f7487f158527cd91081477a5a020152aaf49b4f8077296820d254d13e3c8fdd21906a801e665a4043b21de0edc08c9664be88f3834b0246b6264ffc081846cc200d629cf1ad0db881aded247a8174b4f43970d5680332dba5061f5055a2e69334cf4c8dda7302a9e37091e4f440608dea5399f1a8d748a59b009299a79f9da3c5f2b2648846c64a893bfbe0bd187b7b7767bf42e351a8392ecc744318a9871515d435ee05be0e5c800e0d1cfa6ea10335b48a2f00c17344afcc6d08ddb426031a35d6daf07f48c7980f56bb9fd2588f9a1f119610d70c8af3da487964a170b63ed3ba6c097e8ae750aeeaad733aa300d87a15e558fa6330680cfa4cfad9101ca85d012858b3ce6d944c9bd9ff072a151920018cd52314a595dddb0337a6af4e1aa7905ff54bec93f50fcf5625cb86d5ba0a39bd757139dbdd63b96c940ec14303b6473c48ec00bf1cb5db2ea7cdbcf4f0c4ee6a6336d7a321e57fa1f288b4b635addf70b724364084f05cbba5d52bdfe7b708cf25f7f1aae574c49758e7587eb15bde51dd3343269812c5030e9398a31487dfd86e2e8c9ab8e8ab0713e955f9981b7d8f1aff0424d01499555af7a1a17d041f3eead79e2a4f9528a6356081c550326b1bb4a6610302590430aead818e2195199742dd13fdd928a9ab23b15aa67c41758b2762078b2e3d3957ab202d0ffe80595cd51ff54ca213e21734d475b7b4b924a60580b5ae4c475a71949622806ef418273349811ac08a912880079ea2dacbd0e0a4092af04fe20ee0b2bbe1addcbf4289b5e3dba3125ef6cc09a8787e29930cb27e987eb599669349ac70e8fcc66f5c27aed363e28888b1b2a48e432ad2987606cc5496d76beabe66d1bb6fad2d16116a4d0d98509756e4d641f57d65cdd71ef99262d6047800dc6fd0b2a0d167b8d242cf53c41b8411b26d48b6a95e511d316178d34aa3d6852de377725d9a253717dda8238bbb2ece522f60ff4535f1bae8a71e52d904e5c849d13cb91765cfb20f5f74c9067e24de2d70006e384883e676b33549e708f3c90a0ae967fd54ba1364dd90f00f9660a27ed880dcb1067a4904a3c649d024cf9cb3a8184706c74d461b0efb02ecc4e93a709527eff8753dc3a515d7ccec22c9d08751a74a522f9fe99cc193a5fbe2b0a6cdff1d4e8e3654d4d74ae57fbd8e2582cced7c52051797b02e0637ae4d541cc206a754e960bb8983b341808b783032236a3ba305d2a5460a04da0da20f09a4d4f6c6312435e6c4c6b45a8d17998f969964284fa49cfa49c760dabcec76fb87768369f98153bc3ad86a3bca1acccc12ca8cf61b14d00a1de4623a372364bcc893983fca31b111b9458d809ff8ec7716190987297326bda2bcdef2faf880fcf8cd999d32ea77ec98958cf30e60cc0fcc3055d978fe7037e1328ca6c4c4134afde8d8ae5d71811ecd682a48230273bb9264eaf971717fb815eef06ac881f3d0f4d859b87043d7698ce28668bac8524b1d5763caf11c0dc6534c62c0dbc2291bd62b5d145fd10553b6eaadb1f6bed46b96458fba4bcec7785861955f68552335f36c687735425b9f9d17f2514a734e3fc385901219d20976df1045aa5023d76750a5cb10e70ea07f1c197526f5e71396177f66443999abc0a008d400da3d08c9740cf6662adf93dd1735f8c262f58241fc6cdedc9ef7cc4590b8aac248a831fc7476c0e26f0445f9ed723cfee1fbc2c8ac6315e14bb2f49c2fbbd593d870b8b98cee16f8adc6f841f236e4b499571094e07ad82e44e57f16f728a7187d6c1baf3cd1315b1f9ac4b7dae69e39efb6a03176430f69720e0ef879284f59ffee4e6720d31c51753d666681dd15e7ee5340a8629e8863d5e86b4088a32de13e13e0f92e15511e9bc4d57a25c71743e9b39af867dc17ad3ebe41b9c8f64d1c38573db395382b55a50ec279030ce8f59ba8a13525681efe3862f3c46eddcd3dca4eb3a191771723d3a2875fb2074ee9867632eda4ffadda4c64283202cbed717d3ebcb2030ead311b9c2ca56169f7ce6deb9fec78a76cb9f78ab8251b83bcda6dcdb0e916ba12daac78a151eb76d040507fa29eec866225f87c694233ed07362b097aec619f5df3dc5ad0a58f0cc94eacaf252f1f9dd59bce58904ff7460052a5bd0650111c105aeb34485c4730ed6e3e1c927e2cd956d1b9404fbaf0440afad135a3f320005d666abd4c69e98edcda3691b7e69b2c3c88ef5e1ab9062b0b3f08b8ca38e8f6f7b4d04f3daa358986a3f8bc5f6a13115c31e454c0dfff61613d0dde9dcf4516bad111328b9e88f262988e8c05e5ffe1fa6ba708f5fd51c34e4757814ad0ea5e6fd33cf51b45b84c85882406cd3eb107b96fe546364a9972d19022be3b5121ec64c6454f3a4f9809f49e11611b2131d5af0aa5e65c156f37a6062aa395e763522fe6b1451c0452c6c56443087202605ec9ddac8635e7fc086e330a7d22b15851671565726b2cce451d6288755a04862bc7f934b99de6809533c05b851ed07faf408f83fa9c18f3ed65a94e9788f830f5bb9ec744b71f59d6821899f8640441d47746497dbaf8e9ddbd252e04a5e4b313e2580a1a858e4550a1e5c09a04eae54307fc047073657405630200037f019cde9197e7270a1c7d726ced68dcabcbad740497313348e7ce6ad7d29f0bdf616a31c760921e4f9796161da146c841e86ee758cfe053b88447152770fa72c1d2b4d17de0698a19a7f1cd72c95a4b3851905c2a7a76d894a2885cc28addf607fc0470736574062103d559d2a5a4180f418a69c4bed5508971cda9313722fff71e053d3d82fee9d7bd07fc0470736574072103701e53a6d0b960398abf678382a4d17c5c153d1a2c8ffb76b302058ce915bb0d07fc047073657408040100000007fc047073657409492000000000000f424056773886ab9ae39b4056b656fb255a3af50694cda3ff4d8d4d450f15ffbbbd9043f90fa6f45a7e8563f8d305ab4b991a2c33e51b65f94230c9bdd457a3b31bc007fc047073657410430100017f113b550d4432ae02cc0d943900d25f6833c26bc1df867fa17b36d215044f889bcf7e3dc63814f6d7894608232902f7cf313b28194f104be657b44bf54471c300010308c0878b3b0000000007fc04707365740121080b9276ef17348a17b4d25e1d429594891f5bbb07fc8e33e4bd35bdf8296b7de607fc047073657402207f8f32be9443b0547b4daedefd9b6b0b655bdad96759a57569bfd429291fa44f07fc047073657403210bb668bf543a321a7cbad607ba5714cfbdff67e8d04c9a4dc539ff7672b84b19cb0104220020e7da55d19cc85b0420c539a90b667d4d85f59ee0ed417493a947c3a2256cc0aa07fc047073657404fd4e1060330000000000000001a000d4005894c852815a527aeb01259da98708628a2f2657826496e2711f7355a941f50a31be4e1df7d245f27e22dfcbb737e28008eee8322b6ee9755cf564411c5f360cd8ebd076db3f857f2a89a6dc3c84a200a3895a0a68b8dd14ca3c294eec37cd45d1cc69ba3e5a114c8a4d8e32eb79cdf984ca018052e503a5a6a71b49c78112909d2f1b1fe97ba13cb6804156d6202dfe1275a223c3b99f77964f3eefe61f87d483f5d8273edf67f4ba970c9abc27627bdac0fbfccdb6582e30429d2d82ee4658e2284927f66b3fcbd59b8282ea88e37198b3e6809a79e9be849ae2080195239e82395ea60e837e3e03459c4a635ae8626d29939026c1b69d6ac6a32a6a8c8a3686d29c636841fe4ad37402bd3c94a58b46a74898b614dd318211822e2927db89bc8d121373ee1aed057436ea6bc084e7a38d612fb9322265c7b04ba2a4187cd70856fd276971057ab4aec79d4e9f1ca9bad675c62c481a621f23ecb7b78b72a90448f40620152a603d4a150d1fb87c37cb281195045dd4730899f58f4813c1c99569828f377e6973bdaeff1bec942f98038d6599a73de84ce4c350ec161074fc30b151949f22687b9c50d05e8339c048beea2e944f77f601797f7fe64cde986746644b4c5f0baa42d6738add8f9773e7ff9199cbfa3bf03cda1e8be64163a3d8cff0875ea6b495e372107b5f6e9602fb6b0654e5fe1bc8a2626e4c9ca3a33bb0d2755055547dbbd2b1548de0b9fd7193ac0d3bf7d4ecc929c3ed0b1112aebe26188476f63dfb75b12187242436f8bcab54de04510dc31f3f3f14204e8b50bf3594432edebf93b26903f87c1dbea50dc9af089c4092654250e1505301daa5b0534645e52f2d3c36e7af6e9e04f7b54111282044afe94411854aa73be65f18fc868f39f79e312f62c4250e61a2511718808980fa0ce8089437569c149f4f9381db1e12e4d2d1ff682f47d63c8cae57eadf9cefd30e52128dceadcee043c84d90555b10095765a0d1f898399cb734477bc068fd2b37f47847332d38182cb23da3800c56dcb2a074aad8ef25d741d569c355fd4a0d806cfb698151873d1e48e24fe359b2182c8a26a1ca1c21ab609fe19dadbf5f8e3ffed3fa7679363ac7e303eb917554fda9d2bbaf6c053e658dfeeb88448f5fb017687f3eecaa3e7ffb6188c18e55678cbe2328a05263a987fc502280d070f181129902cc0f5e415e13f76b3f58dd257136ce579c4a999b127374e2bff94f694c456247c502239e301d21aa870ac1021b97b11a7d1ba0095696a50fe16e888616548d7eef96efa59cff978962a7c6f38aca24282091616f6acdb4bebedf236c043b36a6f12eb82c2c589c6a71080a46cf27e6e663060788c2871ff04d26ecdfe534ee254dce0328134af51228c908c5184eace62cebf5ff692097fc2d272a7275b965ef8b5953fb1ffe8d713cf92bf4b3f6a428bfc3aac0e67aa93e9571902dda5b1f66ce523109092aca555f007ee5529597ec185981f45602be0a8a0f9e9b75c477e0af5d27e546adda7c4a2776b97b9a301f0b6fc15495197cfa6f2975d19bbeb70db18dbad8d0ed06176d97c066ac19d4061d7f7cccedb352788ce5d15c26fd970bb68b879b5571ec5bf2917d7d58249fc8f9b2f5a5efd5e3596451a7be38dd75525fd1c2b0444ef9aab646869322c23e52b1e0b2b420d2220a4c150f0c6b8a4bb245282f546abb74f264b6c75286d05fc7bb2c266b5e9864bc6e9b45ffacfa2352ba898178856db19b41e7e6d90ba0e14226e698ebeb02b3fa349e8ee09d7bfee08a54763ac1db861aa0683b78f6bf07263e3cf0fff0b91225e5e009231155bea60b2e661e7b04d8803cf0c89192cb8f70cf16a6d256bf31a28d2203da20d7d33c7a6f841169a845ac35c8fca9253e807f72e96355c296323f6e0a1d48bff8c43f55a594fa251f69b907d9f97e7b2feb5296d12d331b34ce9107df9da5671effe1120e078956b85abd24c8cc1276d648a2c515791fd40ab74a5c46be36a6426b2c992c22cd3d96d61ddf089ca711c15ec60538057230a2e96a92ccfd605b09a4ead233440b7fed99abc47c50263728b18b2bbf79d814c30b5e96a72393d828446bc3ff14bcfa0c4530b59750c28d7c9639c961ba47320401566962b9fd69df8e87719e0bcfc5e9987d1cd9ff4407dec489ec6e1c0a82037f7f0f94d3a06d131876d541f3885906168181c21a395a51fcd3e2efd3d116948742f8911cb892fa7d4d4d5f83e86c9334732191c632a2a6a74d7f760ccb95e04ff59f8e207ca2491d0a6f48df78254a0019fad13c0251e107639d5669bbe90cd0188042c02eb726d3d33f69e5ca06ac96c733811098c5f9a09210b762e5fc94c493552e060058e811cd302abe0d60be900fb0158126a4d3c188a65ea6c2620aad9c73b0d452413bb26c5e6c3b2d885731bbac7abbd42895d5542bcacd1a93c405daa46bea191af513b0bfc3a1f992700daf4967cbe498bf1df5bbdecbdef4614af954060b7cb7de6833dc0d721eaa570659400f452664ea7c88e410ec5c35e300465ce779d76b0fcf8ecd375f727347bc46e069ac8ad816d35d08f4da02da77a75447a3da203d8ce3a0be9093dbe938dbb62936c7602f9bebd69261fa9fde170c9fb22a345183ae119af5b9a47c1cb0d740ff9771a27493c9bcb0ffeca14c376e0512014dfacbfbcc9d0956db6d642cc892dd7d8a5070b054f26e977ee6e3c121b16163d8ac151df29a5b8c5601d3cba799ceb10f04141c3f6081d7d1b6ea22202b3aed1f932f8cec9c65eea07befa558159499b1033e235078fa7e16be66be6f2ded84e8b47708a59c0c707fd79061945818132b2f2e58242238fb3c3410d2080cc8ff7b9a689d259b2bb63fb40f1af64f19e4dc53ebe3bce60977776328ebf6dcf24cac233e04c5df29d5ffed25609e3b8d96accff140f9f6acf21d9951ccff9f5c9bb27b7c8991b5bc8c2dbed6ff31b2b6e75f6f620ddf45cf6f67b900678567745e607b42d0bdb9d86d80eed1a1923c2386f371e0d2f11306ded8684325e46bfd979059ece5fdda6ee9b5ffd0697a54a64abd7599292509c3a82bb926b743a91affe05b7dfb350b605521dedda17617dec004a378b01682b2998941f02dbbc804c3553ace603226369bfca98ab4aeee767abc892e00f56d79438d075692a547da501c50289e91c3a891646daf82de39c7abdb48b3663bd870eaba0393b66dc7723ba77c588f5246fcf7b877e296fb784834e2cd679b54141860f4696b1b1ac330edcab74b59aff6fe2e36b7e3a459bac93e5068785f455d12c51b486f2063341113b6e196def028901f106b9993e4147ec924af8e6d86155d8dc2aff8b1f9268d9c75e94e253ad38ae65a8cd3cd19161dd5258588f8e74f3da7bc7df4bc6b7d23de75a02c87e8648a7bbd55210110239ed6e6214189825dee3bad6a028c70a2bf249b2294234798311c5695fabbfde68637ab9d066fca327472ca460468d34f74922aac4f1a64ddfdf7ccd4fe12d83ef033b901384ab8149ab50288fcdf087a50c0271046e7824c6c69c33ce1179c9e87dbbca60692027c1c54481a8d4909fcb1f2565c47d50218995fccd8cd64f51874180fd930256880aa1f696c321790cc5c32c49d146f6cd0128b18c52d00417adfc06aa6e279c03f5b21daea9a33390a91dd3c5281444d023362578aa83eb3a81d57ad360d337ab374c1bb3b251a51fef636418e1966cea1b2135bf444a03c39f4619c7acaf3c7a5cdfdf8a3893696e5fc076e915af6ef7817a32f5c815803e92810abc3ca09e421f8f039206e524a47ed746d3ece4c67e1dab74477abe25707b92598e71f6011ac9e3ea85417a6e4f43c55f158c2c73776c63c3af8fa472016ccae79a2b9e99d8c42fa1cd72ce8c9cb3c535719e075a0adf26fbb559ef129512833698d6892ca1a37f176cf6a363cbeaacf40813114285b032412f6d98854bdd758465604eb2ef4756064a16cbc02763323f29722e625ce895315bc6eb1ef3aba39543df3668991b3d7ce33c68ca975c18823cf37e8bf38b87ded0527d61ba10aa43db45b82e23b1582da992b9650f7d146eb420fdf679eddc26eaa3639a6aa41a2149d1b89057a05552b772504cc29132b7f6b3eeb5732a9830fca236fd41645f4da9b38b2207d931944a98ad45585eb659b7e1e43fed797c41705265bd155174f52e45a89ae79e5c1dd264a39758ab5ba42f6b721b926a06d45ceb114a0ad592ec71276bd7fe1cfc592324e58b37500b106355dc6ed962e1830ce33f8a18a0ca236c3301b0bd9029c6dcee2dc37057635fceb494a8352d74963fb2e3f75b91b19bbdaa49abbf11351f88b4d2d0550320a8df123289cb16e1a4de9e71974d920d2b28e59037e3a941e0f7c6b2265ee281d0f9da960d2b707fdbd0a58f0a19ff8003ccec3d1be962eb47f57923ee2a1df81cd2e77430eeb8e0825e8cc93ae0466a19c80dde5b8872491326f877b27db9543c495ce3c5965bbd48f216390115c7c31bacb20bd9f11267d2aedd4586ffaa27664991a100235bc197ea189840540fe0b29a07f24c400ffa2bd81eea1d15496bc14a65fea7e05604f987cd847b0814439e09ef47bdb3f273cf0a56e339e7105542a2ea1fdda77a2dcb792e474cd086341b510cd5b424caaa98497744303dc149759640302337f8d4038396f776dd79fc41fba310214a60ac5e047311bcdb5daeb1d8a601368fd3d84f981aa6fe7fc43d244beabf0a386414c569c8599918f8250487c546f1dd49a7793061a0107ae626beb6bda487f633b1abfa389e182f4f1aa99309ffc7c0b69344d0e9c5c2feb35cfe38f33c6f8b668af1df1bdcbdb5822c6c1931c7ca25258556881584dae524b35c0fc1dedf8604298014dcdfa39c3d38908364b01f55062bf7ad3ce8f85bb765afed8f365b1996a6600d39105203dd47023b5de1e2c2ff78a2e4b1fd6329afd0e86777471721fdf55e7189b18718b9c7d6f7d764b6bba82ea9eb9cd9dd9c09b9ff5ef25b3aa8ab309e6d85f43d6dca7681a49975372a9ee196f917e4e6b390103537d24a35a084c5eb5b378dd1654025fbee39935f599bd4a15741ce19479a93dc9489035158fa0812b6ac13c6f247432cf8ed3a92f86b372cf624e5b7b2a419184ab9b333a461d5fa9df9573f67212435ee96a59a020ab3c1dc0c61440905516a8b6f341e4d9cceac3129b6b7b6b3ba2ebbabef7857d8d7594f778163a5f95f9b443067a94f9e0fe9db323e25ccae107e960ce163d62fa0c6268d99cdf208705b57e3869a8e0687fb95d9244a3fcb447add7b7dfa850e9af704e2619821754988858693e27fce4b0b3be89e42def5bdc8213e02489179150764fc0a542e382f52e8d7cdb80e4aa78ac9b3d1d56ab23c8b885f0f173c4020d2330058dd37a34c0c1fde5142b3176254a6899d47514d9c2e68b040104b134f331dc4d9036505210d4944ab4b7762bbfa364fa3d96c7f87e53bf71d5a5c3c40cad698031e95ff17922952b5d1f9337c93bef79c09d075ac5d73b37a317f6c4d767a183283d1bbc97560d4930e47628d489a2c28267ed8bf0922b519eb3f72c62d710f81f07dffdf6d41b5ed95190ce20e2b94f8cf525be8352568b59a9a9db7840636d2b76494fb3f791bbdfacaf5541ddf8d7c104462dd1c6d3006bc386ac1f55fb8400589bcd895274de80092f69d1c759fdc3c31f2e1681ae75689e587d9b11a5673e069a98c1f77b538829c59e64bf65c1417abb2d8f52b8ac6c4bed00ddbb1a1d04d05d874315f55ed580c6fe3cfc967c15bdfda8be76eb1c77e3a720450dcbce40f772c28097a0925aa159858f38058ace779e4d8467de433e39518554630649613da5d20707fc04707365740563020003891394633c5f31c9ee5ca072b289c5be81c8d6237fb8290032940c0f535b9f72b4a4b8e967bc5c791a60b0567bd7c2fdc5ec71eb54c8f0770c92f5488c50d1416d636dad9c610e29d32d95c6ba93f6ce39a14fd1e6a11c2934090f494dd860d307fc04707365740621029e5980b4f9b9a9fd568c1c4b48631a800c310405ae8b2ac41ddaf87add3062f107fc0470736574072103504bd87c31711ff592af95f3c9c4f78e63f2f30805bfa95bc2d21e5a2db5c4da07fc047073657408040100000007fc0470736574094920000000003b8b87c003c8a469312a60ecdf33a36e22b37eb9c3e380ddab84491cd12ef7c80a6565124063d8d889bbc3a6f2e0d2fb66f78adb6d5a43d5fbb716a5f09a0db9788282a307fc047073657410430100018474c718fb7fef3e0585e56e19e551b357042f0195930751ce4d22721d93302dd78d263aa3c247113a0958851c182ad93f59216c95ad62b808bad00d4127fdf100 \ No newline at end of file diff --git a/examples/test_vector/raw_blind/blinded_one_inp_signed.hex b/examples/test_vector/raw_blind/blinded_one_inp_signed.hex index a34e0447..8fbc95f4 100644 --- a/examples/test_vector/raw_blind/blinded_one_inp_signed.hex +++ b/examples/test_vector/raw_blind/blinded_one_inp_signed.hex @@ -1 +1 @@ -70736574ff01020402000000010401020105010401fb04020000000001017a0bab8c49f1fce77440be124c72ce22bb23b58c6f52baf4cdde1f656056cd6b96440980610bc88e4ab656c2e5ff6fe6c6a39967a1c0d386682240c5ff039148dc335d03b636cc4beba2967c418a9443e161cd0ac77bec5e44c4bf98e72fc28857abca331600142d2186719dc0c245e7b4a30f17834f371ca7377c22020334c307ad8142e7c8a6bf1ad3552b12fbb860885ea7f2d76c1f49f93a7c4bbbe7473044022040d1802d6e10da4c27f05eff807550e614b3d2fa20c663dbf1ebf162d3952689022001f477c953b7c543bce877e3297fccb00ef5dba21d427e79c8bfb8522713309801010e20cbbe4671915035276d8df41a7ef0b6a36dd101de48a4076046fdba3b0bec20ae010f04000000000001017a0b90df52169792d13db9b7d074d091aaa3e83aff261b1cc19d291441b62e7a03190899a91403ca5cd8bded09945bc99c2f980fd27601cada66833a5f4bc108baf63902e8bed2778bf381d17241be029f228664c7d1522ced55379e275b83fe805b370216001403bb7619d51d2af2c5538d3908ead081a7ef2b2b010e20cbbe4671915035276d8df41a7ef0b6a36dd101de48a4076046fdba3b0bec20ae010f04010000000007fc04707365740121089f9677efff5962164a434b0bffe53d90c271deda3eaf30c1d7a55105d24b874707fc047073657403210be6c538eee2e29d44c66a3e66fc8165afa4081557031826a070703cb69faf24380104220020c731ad44c00a2928d508ad82b05868cb42733a5b0d0b208f483307ce8c328d9307fc047073657404fd4e10603300000000000000015bee4d0045b0884354b05d0285abb287ee8e539e8146b92dceaaee6fc01af1a3730cece4c77caefdcfcea1073197ffb8b3ded97d0dda6f49752b31f23e196378a3da2128a8c45ecb7eb1c32f0c0dfa1ce7bc348e799f66d547476e976baece7445790064b34b1526c88cf54928acc906ec0925327d797d36d0db6a43633d7f963ec9b4123a5ea31b655882329afe2108d123f76857fd3ce344fcd651b3d3066aa506625c9309acead85fb6c8a7d977db5dd6cb6e2f99fb3535746258d42d95dd2103bbaf5d45c8a2dfaa2301eba08763bac8ab3b59bd0082a457bc0cb257c43ea6354348e73d8dee101864068f0e8e30e6711f1597d7b529a57e95fc0df813ea160f5f5152f341087868a680c1bbc4b2a427d18cf8f12cbc4304dd3b1ea4c916467ae48b3b53062ea046161170fbe6ca07462cf3e5534d638c91fe6919318c4b2e98ce0ebcb245680d6395ba746fbf510a9a36ad8d933b023eae39973a39162178148a897b5174940db46e4be54794cea11fafbed48b42eed27f9915cfc50c958e88bac551ab1c9bfa03653e558cf87a99ff13440f4808e27fb42ff3cbac9fe10d1de07dad4807c9f945784163214c739a9eed8bb2e7da6e1fdfa4aba5d5157787d0000b220145572d3d9253cde5c1132370c1849847633287660b429f20cf1f72e4ad6ae59154c3b8526fc5d30523ba962a25577427988d326e207c97c81b479540b1c63aed0a4b1dad9279879740b2f6a0bfc37aea8c81b3b35b630dba8d955afbba756b8ce9d2a9802939972c5f70efdee8778a98360eef15faf77e38627fcb4f98569d68ebad3bb667e5db46eb7f4214846e651224673dc998c55bdd9e0a1629497a75b76160865c7ac3af874bc45a42269508f183d2458835b1734791094122f75398da2bb7919c67221ee42242c298d744fcb920726b84bcb78d7eafc9e0f61a02de87ffc5c674390a33d722b50dc35bbc6788fe0fd24be7a9e358113a4e65b49655767b8f3c3bb86cd5a56c79f9148945af63492dffde82d682eca4787f203e49790650395c925e6eb68bbb3adda25bb784365c0b3e241177ca7de58252b8c79c5a865d1030f3bfd4d312bdf83bd28241389085433c34d747f9f45a0a636e700805e619a19739b15077d44d5e8969a37481896acebe7f350449c69b50376b7cf36e906d8a03aa7221de67c7fc4c5408b55e2562f7b783918004d93b284c0a1c3d596c7c18aef5cb77ad09172bfa888f5dceabf57f708f5ab61b1b4159742d3d35332e9942958ea7f39fd35cff66e84ea0ce3b38a85eb80dcc1201146fc3854cb40353a078f5435fe2becfa383b3a62564645250cf7feccff5414581e747166625477c70f5b0f579bd578e03e6b8ff8c3f0e8a82566199ff542b239f2999103cbb61602bc2f346702204e50c9ce7b85f3b8e144227ca8b9766cdbd498191c385e3a4f024c9396763eacdfe41b706fb23d4f065dbaa43d323edf1811950c71d4475a3e0913d3851be4e921cc933bb06b0aa20524267b0e9847b6de3883ab8c5be1eac17b06c946f19dc2244901890cc290f2e66147f7c47a4a29349555ca020e684ccba5f8a6f1be54e356654d3e8678c591633e11d9ee772940d92f07ab83228c0d8840cb9aae514c03358e973a2ef319a39a3ce819efc00e5a493fd582be164c1460f70fb2e103f09a2939f779377275be736ccd41f847133b3d400477582419fbd2d7ff328d88256cfadd750ed7a3c6657e332f635f0a90602b24135e705d1530531b7b738e686d83accd74874e160a5716191447f832d2f899476ec9c53204fc4ade5b75cacdc869b4088e009e12d85beaa3450889de0c86315755ec7744be592f058fafe62f9a89875bd2781d5d6928c8475f555e77eeb6e688bd8d3bee0a54fa1cb29c1b6b438d3f70ee4ac83fcb6f482575997e3a69240c6731b517d8241cd39dba6b02a9e3c94ff2470c61c693d32b1c7d22ba38f0da21d92150115d580249380500109215a05baa63474f773892b1870005e76a68853e6a8cd9f74ab3f41cf0730e702ce94c420dbf66a63f342d927923d7d25ca3c3823b6c352ae2ca127bf811c023205632ddb8f9191c2f3384a61038d1c4d32f808cbaea81d58f0aebc7c89bcb5b98f92849f4fec19cffc78173e601eb412aad24eacd74d17cce3a9ee76670367ed87c2da3db5e4ab01d4d9626d0ae00da7dbf6b8103d5994cf66ca56bb9aab9eabee2b14ef798d3fa5ed1dc16bb500a006c3320941c4c7f6f80c8b1bf79131a5e11ef38db7c42d4c4939711184ea414e2ec0cf5bdce3d7d0d72dc883b2595e5f0fe4c14cddaed61108c90c74b43cbf719bcf7a934bee760ab33f50cedfe3ce61dda3e4bee1ab4dc687f988cfceb207152f7a98c0fa3a114d2d6881034aeba877bbcc368ce591707da45becc48318f0558b3ff65d677578df9fd9e9a18d0cb08f2f5cd4f44925259225b1c4c5ed84ef30d136e7c66251329a223a1db0b485f1c634981f8860aec1f3dbda9442e5438f6fb09c7e1ab43e2b757911834df8502ce35e7be947771f7416f7ea97d26dbad7221614175e6b86f1a323e26c4f469236d1b1bf6ef28823234c73b275c5b0ff39e8c04d9dd8ff7f6a57214d803aa13dbf581295b92ce2b8a9c0e3fa8e4fe4e74c4bc2198fd010cf84681cf5f3fc9df1638c403006478b1cd4204ef3b7a6093116021118a839bd3ac270783e67096457a86d63654e268821ee742241ab5f7e91972da0a94f679b4c093d3f428d5876edf51459331df084f2fa245e3648e0cac904a82a7d323b965a39683ec0b2721105683e67d65fe10b8d41d0dfcd5c31756408c94cf425ae67f95ecac45391516875870386b675e24c462b1f7634f758723e6245da6a39da69cc2390374eb89c6c662d94eeb2f1835e233610072936be248e6a3ff87f9950c2eb2f88568c31dd30d1f0c0396a42f6be2505bf616c63f504dad5312fee2f083b406fa05cf3c998ba24237402681f0ec393de4650ddce3389d4c1541d4705d8f50c2c6d4864934394fba0c40df495fe3a5bf58a5498c1e63b5ee5f9a4b53dbd913252d4808f5bf5fc3c6dd74c86c974fc9e5afb1a7ee3d88738ab1fe9194881cb00197a31d648ae2448db872528d5f7c366188d9d98ea94497cb78ffacb5f6e8a2c8520d8d196fe0ed13e2b2a5a08dc45d8ff58a8c5d3bcbdc5d80c798acd0eabf146459e79db12c2a43c55d14b2dd608475c606fd4f943ae7cf62131691768f710fd718fda3967146daa8d4f34a3b8fe8084f4f3865e9e0cc1a0b0a799fceafd1b74f09f524822179ce38cf0f2c4c8623a3e3ab2cc20f5dccdadffacee62c120657e3d85fea93fab645b5fcdb812b130afbbd5b19e86aee66011b520b0affd84af4bf67a28b309cad66cec25a5de06390a4f2a5af47d59c006010a8ffd214149bbe47bf847fa94c2113723c9476c2e6dd84411bca16dc7bb096aaa3e9a9be27811b52838c78d16cbd89cad379bcc0cd966dadfa428f9d4d8bf133f7d21022ae3f966dbc1409c6d57cc46ff4434fd90d79b6c9e68ed3795ea6191a7e309783badaf8db9fbccbea905ff9d423370810f02add38ad3088cf3393e7c6d585b76fd78c67766fff03ff54c01228c6737da667147a8b5e722370a24db8c0165e34888920d70fb1356eb731d0024676444e2d37860eaaed9790f99069e622afe6ff12d516812022c46420006253248eb292908ab8658cd874ef05bd568547535fd54c1f0b5b816e4d90a1bd55670b96691e7633a2fa45be6a29cf7bbbcf9e5debb4b7a739b36b6b326b719a12cd0f5e3557a2fd94023d8c633fb697b85080a39734013b4ed9a7500aa8093edfc3810d4c890e608951e57af8447349cdf45a076449241a047085702dc3e44814390ceddc878791ab3a6503f48f48af25fe5cddf61e7870ce80e32e5f22d5725bfde4f319c2db7cf3ba3b9952202cd24210ab8d47fcdaa9ad5e2a9d2c7be1ed6b67cbc1a28ebe565ed0337c09c97d2d9608d97905c7201be7d4bac785d64caf783cb3ebff817bc5ff0448899537ce6911c9803744d06ae97e6d3aae037697986cb20061892ae72e05968e9bc54153bd745012af719fe7fd4b917689a6cbb94a9bc8cce51d234ffce7dca804e2b2759f473885855983b7b290806884fc66e724fa848af2de3164c611c630e5bea712cdd9a9943ca3ad55994e5587c5953f415171bdef3c42783b809bc5526a88aae66be626d73394a607ca32256198dbc026d9e09e9659ddb66736215dedee0cf69a24490a53b2c678e6caa2aaef10a4610f802fc5eccf558629554d6388465584514d3dd49fc00fb267c39bb746f76ad3cccabcc3cc882815bd9466d593270a5c9a04945dea7ad06ddb73e66b90270e859a109d52251d911e7177e07295ac9788ce970c1b718fb0c2f327f44fd0cef3cb90071ec85e958e6ae60bd134ae307720cdb10be5a0af8c051295df905447b46206b5e04d775b83e11c348458b1bb310ae25c54e8ed1488a95b2a576002198c80e0e69d14fb7bffcd89935faa6e3f9aed61e0492bb2bc334e389bd559806eff9e16643ddc4372ca83790a99bd4f5b042779ef7e3039858881c8ce0041d43ed6b1f42f18007d046fd6f65907cef73fd5e6cd514c4fa5ebb872b140d0b2ad43c58f2f2216522e78a19828baa34ba56d71414ae869a13cb708762565d754f0754561adbd9145d232034229d2840ef0c96f7af4b232c5e11ae9d018b87177a506b66571affdeb693e170dd12640e86fd430b64509d02694c52a54f23ea96e39be92b65c1abcb262a71d6e884183d4bc6cac8c79f6e94b51abe484794a42a8e1be721cd59383bdbf327a864b2cf27566f1270d82ab6e8b3b934e953b7d48ec4697172e0160b8435e8186a7ea685dd61402b0bef09137fc52e19ecb53674a1c0af17fbb0efc2b4d69572b32600fdfc3c85c79ccb2685c665aef16748b7f15862f435afaeef00f3f927cd3a60c22f137e9cb2c38a9652cee570a76351871ebc9b6fc720b9117b1306e8afb298e3a1d0d4b2c5ad5a21e9de4c0938a98daa35caa711bd6d3312a7e941b060c4a1ec211c31e53da263995d3be74a3ca5a970d3a663245a5d8eace336d9ee847619bb337e777b961805e808f7cfd8f09b93b6ce6c277396e6cf0a6153fb11625f421b02055dc53a0bb24786f4a74211bfdf44193e48b2c15c7c85acd3f4f0bd26644f9dc62653e366178645899dc06d191c785831b98de593519c0ac5849897a01b4f8c7fd559edce1c878bdb9dd091546c64225fa81b1c7dcd6fe72c8131bb160043976a5e891236d3552598c0c4fc734d1cc752c10306dfc8391f6d658ab8b7a1f350e1900edda29775ac8a531032bac968f6981889f13cab07f49c864c3ef3ff23555c170ee9730912465e6bb3b7508e11ba27001d9dc0da8b34954a7c46a2d0b0b75e73ad66278c8acbed3249936a6c76fe975954f7889bbaae5f73747e3ed02811b015beab9d1515e396d37b2a116b3cd8863517b88ee91a854e4740304f7be41123692181a8ae22090956ba619fb948d3f08108da17ac2484d3dd5795b1c716cb5ed3fc08b6449fec814018cd883b02256afadd1f35a04d9d43f661be624c0d59d0d397e8ad6917344203843495162217e79bade11ca32c0a6918350520e6c3f31f866b89e3497b518cdc056e760813ebea7fbf343db50ca2450d5b7a1c5f430859e2040ecfa70cb0c3e863a756ef6ae2e26c68b543d35beb44513f8295872df5b4062c9b80742ca7a9c2ec36a1d9bc936c7fa7328240a2db54463ca04a40dc0c9afe4d570012259c8c436d322483b17a705d60a283e0ea7545110e898ba43ac6130aebde014d237482307ff28f385fce8530814a3b3507fc047073657405630200039d46edc3d830d852edbdf28cbc023dd1666cc4a806ec9d4acb2c97865280698d61fb6b2a073be4ce75cf8193fa9b3d677146575a812873ae7eaa7b08110cb88904273dd65af35115dd116092a56ab45fb57178d8c5ed4cf99474ff760f6e987d07fc0470736574072103701e53a6d0b960398abf678382a4d17c5c153d1a2c8ffb76b302058ce915bb0d0007fc047073657401210821b4e7599b1b4faf29b521f1c442dfb0a893499d374c19db939c0c9a3b9798c707fc047073657403210b8529a893bd81e38743e8e3015095077f6e244a064d64708963c6af5024b6aeb3010422002058037c2d81d3122185c8704d4276e2629122c95b8ea68575c451628d37eea84507fc047073657404fd4e1060330000000000000001ddf2f500cf45e30e3911bb51a7ff633c1e329508e42d9aa49fa8248fa4d293b87005db08b17a472580ae2cdd53c40b2a16af885d6dfa3d5b3410d389b045e6c12405c635511ccf008390856f4c6d0ca472148d2969fd39e1307bfbb8f8268ce92398248f08df7268bbe23e13ac3801ad075376bbe9684db9b41d7b1148fa65a129e1d25193ad973ec7af631a0a30c5659409b0d00e6fe44c2c507d52afbee8059aee7650bee9d47936838e77f00cfec9de3b9efe72cdeefd80a19a9c8ddcd6cd9009ec96800f9fcd709f1432b5715466d601b5ed10b0dfbd09b954b109232fb5a24036b887d26bab43da7eaa303e7c8e9d02950610aba09f343a65a7cb4550d6f6e5c0eeb9410b68f85cc3b05b9340e2e9c94a473f2001f5aea7e875d29e8e0aa99c09afec4a5455258c803e55b89cf6e89796a6f3f9fe11ee05ec415c6ac08e0f1adf9dad681f8121f82e3a9402a2fe13a016dc10d4a605578317be0d9d3e02b0989903002bd35ec4970701da6eb6f9fd5e6cefad137dceffaad968d5ce522e77c76e665529f70c9eb805a240834f4c8c795912c37e7efeb73d4bab709aafb66bd645cf0addefdd83d185c1b4465ee16344575eb2aa3acb057c37d7c22cd03adc6701f03d4cfa20ca94458b3b87e3fb7de8fed28a755bcaccbd348dbc7f5aacbb25d19437d87cb48b88fc714f059b328c374fb2695a26537330fae42d3fcff40b07054be10508fa78a9173315506119973a9158828276edc6e8ac771476d7479d07ba73e9c5b58d61367d24435a1062dfa376546e843b34829103168db63b708a13894813a442f889a423054160b85a2584d36951136bafc490056f1c03c44580e2c7a12b170e5c7a3917720bbbb21e5da616649b554b7ff57dc84dc3935271a8aa6fb218becde208d83e76bb6197f5f4f729f3c57b4280c388bf4945206fa769b672ebd47ef2d0f777fc9dfb031cf7c333c6159a75a5b33ebc6c4683ef140a144a5ab15b2b6b72ba14ee7595679a0f7873a75b9a79e03676ae94eaf9ea8d3532460f3075f40c6b9848a183fe46651caeacd51551f308eab6ba8ac27b93865f5dea0fcfe1d7dbb745695dcf187a5955414763c88ec01d299f03cdaec48eba946c7ff6031f28a5e108651401b5447c0d21c449b387765a621c057eea7d494302222e3d1ff6ee9f8a0580671d9fe3ecc310e84b554e5c823d81b8027075f749b2dc8a6bc5a99fed4a0fc46fae59cc2aa9f1471ca2b0d9fafa56927fce0f1df92647ff5aaa083bfcb7078bd8ee142448d4e1f3dda670ad93feb21028a57ee9a8ae8880df5b3276e078555d868be0d8843b495e082d743328620f36f7e106733bcefac15076826cafce271caf1520cc8746948e71ea73eef5de770ecf5e0fe075f04d6c9cef1cc1f262e69fcfc89862877ffd520e25405d9d07efec82386640d97147e4a6df66bb1fa1f20dcc2ee1fd6364bc2024c0a4a2ec00b84616231c02aef16147df509cb830b9fb20111c60613d41169a24ea67c03cea48e1905b00eba8a61e967b9aa5b6e1264b0f3e2c051e47f54f45c6fb78b46b9993c7d223d51036cb77f5e31a4b30892e8fd7ae7028322d6402f60712f712f84443de083767c38ae88a38fd4e4bbec58015f4e49e36ecbde94f23d0061edfff0e9eb62b67327249d728c278f923748e4c1e225791c740abf9493198f073a6cefffba00d23715a14967a72cc7aebb81ecc6e8bc88ae63a47507296a573c415d0163219f3b20974ba3a32572d29a479b88b89c241e63e640bbb93e2da0b73024ff03516ee3ecfbd84348372cfb574817ca878172a779ff131492b86e64c1b7054cc5fdb999df4a9578bbdd6a6a2a798f053f4c7456173cb8cb9b61735e650d0394ea9effbef615629c1f393949095982345bfc02b9a3b3ec64d9173bb1285587048fca8c740b6d2265d3e727069fcb90282c78f1049ed7925113279474d0d873045851b397a8c26036c83906dccd0eabe98f7d6854d9abc2e6ff12d84c2840affa371cc2dc624fbce873f38570dc9eff33f5e200791bc052307f5c718d47fc2a205add3fd9de2a81cb452a0a7b4a08bc133e9816f6ba852735b813a1b906d4dbd1ac8a968a8adfb6aded0d3fb87d80132a4b45ad39274bb72df20d648a26aca4beaafb971e13094b6d6525bd418b91320964bd90d3a98fb32d69222aaef2ea95c6b84b6b6aaeca3f6789944fc7ef17d218abc7667ddff798b74a0d5fbcc33d22d028d207f82286fd777ea1e281d7eb88b665e29fcda067bf9ef82a190c920e260cbc44d394b78e0439bcaa6371f8717ad82e02015f21e5dc273de338102539bc924d5a3f897eb788e0f3cbb6e8a34590ff5370bcb0f671ce28d6ac0adea17f9fda49c784ae84464991fc71a31d320d62c4199e4f4e38f390ffbcc7f15922c3325451371bebfaed8f8a7d3eead71c65878a705a6163ef649bdc6ae7b81110a2cc9576da6b0188337160cd518fb30fd5b0c165ac3de81002490f36d29f3bfefa2b4796c070c6d7d971d18bb5a573cd48cb3c64dec5bbbd7f2f6f60bff3db4833bb64b426c6715021997350aab1751f0d5382087ec133c2c43342b31eca32a4c17db14148fb48f9b7a103b2c0bfc0dc95ffe097bd8f2213a3f7a43c994599b05dc35d469fdc025e23e483039f271d948972417153c849fa8dbf374693dabd59d398732020e90d8f443ba45a00b430168561de21db76b9b714ca8260fdc4ff1a5713e69ed7296f5a5a9d192474bc6e67788d6a44d46b69ac97d0b34b2b08aa79d5ee7e910d99221e1e7f6383628b5383cec4341e5c3f18ec3361b2f2ee5935ed40919a4f8892bf3467803b720d29388b7cd47067eed9be7648fbbafcc7bebfc31a30d02f38b7d6be1579c751aabf679fa6891adf66da2257432c10d399a8d496d1aba381b64a5e3ec9a65cc8419151b638adea994c3590f77bf390152894b2784f7832d986ac51b20ba9719d85509acdedc0282f27065c87bf483fc74b55579ecc233fd6c51822ae03e46ecdb15acf0204b67852d525168f409d2a4309c5d9a14b35905b836091964ff4fec0aa91bbd7f39919eeaebbaf75c63337a4dcd5ae37cb60fa14bd78157ecef35ddb1cfdc366eecd48aebb0f5b395e4161c158c46870fc89f8f5918aabf0577c914511cac7b189384eaddf7f03cc6706a9abf219ff1b293cc9fa2cac88b65af62f0493e30736b596c119149af07e840a43dba8d97455a7a95368395488304626d3b888069a0099c435cc11e5981412f79153577c9115a1812b1c4a9ea42bbf11b40fdf930bcc37e6a6c50a7e3d06bfe7043adb32244ae359993caad00eea5f1de90355326e921145add1020ef3c2cbcbd102e7b9a150ff9672697d31f86572843269978cbc4c3fe067417e84898587d4de009b33094c8e8102c07facbda62a2996e083d0618fd9651e17f0fc025a946e7c28d93e18675ba69d8811dd06a2cc1aae28de5a6af30f305cfd8a090832483e4ff7c974d47ac96d2f3f7baec94f965a116c2734f87f468ec33cee1a58dd2ccdbc8f6a0f2a50a739aadf4007c7a529844cd1ce5efdd42eb28a0f5f04fde00dea586e4b8cdb8469b36940de19feefd342285c29298afcd3ddc368f6365e9ee255f8c2b6f70c1bafafe10720402a668ac3a2cb8ee75cb7004455cb4221486c3dee64f8f25f1c8b1411437cf6ba70afac5182b21f0efc1b5c71dd59f71796d2719741b6d5c757d824cdfd2d9459569427951d6974d94bea1fbeb0e1a23ef88774b270a8bca65f01a00299258847ddce8af8a7626c802b29dd01d1dd9d2a7243b334c29c0943e11ddbfe82cdfbd506e81fab8775a1d3c4f6c0744e1086763ad84e8f51d601e24cd6fcba1409abbb1c6b5c9bb9eab8ca30282801448f86cd5d8ec187866f1ba738863f3995bf4084ebe8f41dc1ffe0cd47d5a95dc5fc0dde1559ba170316e085d0e385ecf8646bf787b5287960f07bff9d3d990b3be4b29f008de18ccb46dc2192d0fbbbb9e701d350aae205fcd2d7314112bdc393e2eeb0a96c5f2c767dea0b82e9549f46a270b2c69915711c144a7737e9003b1c1b8684e9f2abe66ad1678c32a0c6ce401ae2d7507ff32c8f6179433b94764a6e4ea0a363e9a03787502c67ec97724d78c1257499379ecc5cd006a13acbba05dc7f1310bc75b9ec6a09f4d95b2ec11952eb3dc3d2dfeb8678b10b5db162b44af56ada56f7e311d6c5ce46472d9ba2284126f8f579d59a9d3e81bb1b26a7ee59c3cca96252fd4ba8e009a213911619ab4184e83683969cc4c474e934f36e6ba4ea33d9e93e984f1603e259cb7f1a3824dd8764bbe30ae08166aca84e63615e59c31d2a968a0beccd40637db22b971d51a4c35ce83108d8975d758669bd83ff9602718a882b943f80745d95a2d5e07ad0acf8023e24589fd68988a350c0ad571470f8b9a906648895d312100cd18089465de942ae0c7c8bffb5d3705c729990721bb0497dddea6dabdd530c9ec90286cee5ba3e2b699eb2de55de8aa0012b38051862bf0a7a22d6cce4310dd8dc47c206d9eb7bf28f2a53afa8fd10836210c0c461e417be42d89ea659a76d5e3cba08daa885b7f0302c5df05c72f8257f60e2ad954891841e67d8b7184cfa47e51e9b36f6ed1400aa84c5058a1998d07709b8b46630d70c73552ada18713310dff4177e2143aada1038bae9a64e02870a7535598d766f447b4e25dbd009009cc0e3421067bd0cd10735469b308cfd7a094bbdaaef2e31c22dc6c1a6d4c7890020b5bd04ef649b56889b2031c1923a69002448dd5db1142384cf517b08096539cc537532f43afc33ca77beb2dfee921178ad51b04f10495365e60b4b7677880409716e0eaa3a1d649a871234f86787c2792bf1e04a635e3f22b8b3b1382be942605c3855a940cfa3825a2f8993312a512c81f92aea0fca95bd1bdb6b9774ef3f1fd15bfa1eae84ebb48bc9b55fb2141c55cd3188eeb5049b2e6f3360e60c5bb7d91c9028ebc9287b4b5541a4ca290288e08ca46f80eeabbf100f700c873d7e69dee7dc80b842004b2bb93f0bf533488028d1a1137371417d06785372ce942d4c6589cdb57514bde81960475c22393eb02a93b6560fc3e4fb6ba692dc362d38e33a41b7df222e9192fdc0e0499f110e681682e2b500c00947d62280482dde5e26010cf959fc717d0837c98634550376aaeb17c1c80e3c3245c36c68f56fc8be117ff84957a75e4aa4caddb38779f1c50086ad4863002127b6c8067f172aa78137908fff82b2297a53d6232c26a2e94bb25b7f9241013adeb36d1e437f2f6c0d983efdb78608e940390005d63c081eaef21d7f00ddf51a3fbbe6175be436a9b0b75f198c30efee2821ac5f088819eb96ba835999d0012e7a0c244268a658bc6b7845d10178283cb8add0b81405ccd64000c1835111511555eca14f7e3cc9274b45f817039ee62cfd95363cc66f5397f88822f790e0a86b6a69379dae77db24185394d9fc73880d39f6b3233dd8d3b912995b22905563ae8cb2b1f3491feffbbdf2c7d2e89dce1995d2429bb0a4c550860835aef589983d3170387971f8aec15c18450dbc9cd12f402589dfb17216e359072ceec8e9484f9b490a288dd4b268233c40ad23721961c390bae0a181c4cc8eb68eb4b2a5db6944042c6ef67550f9abf3b9084cfe8521b62d727416576a58591dc65f79f871958243ca4415d92d3e588c4205b4a3806d64224e94e8f04dbf7f75888246aae9f894bab1ea69d7e10b4f07e8cf2dcf70cc62571c737cb6b6c68b0e3fbe4b1931c8615a793fa3db0a45090458ff62ce8bf421907877e555cdb97d3709bbd8728c4432288861a56cbfeabbea5f225cd29e31d99eb788704a93696f5e81307fc047073657405630200035ed48216bc666598aac5498e9fe513a9e21eaf842d382767220cf98104bfd8866621efb63b2eed44028cdc9e2f64cc2447fe09f8d8a1eb3214272855b525d9ce24e6daee58effb4af28fcb0a4685d78d7995081b5cafd1cfe343aefc8e9cb23507fc0470736574072102b642f0e5b34746f2f6e3b511d037e16bc720292da4ea2fb31ec09f6fdbe777ce00010308f40100000000000007fc04707365740220230f4f5d4b7c6fa845806ee4f67713459e1b69e8e60fcee2e4940c7a0d5de1b20104000007fc0470736574012109a05049129b0d9e61c1bb87a9fa02c2435be35e3535082a772f65222f2e4a48cb07fc047073657403210baf4431fbb8f0227bfc0008368606a4b8f2bc1706e1a06cd4d83706217b74f5b90104220020cd4ed5f0db8c450e8b0be595b6410c1759c19f1f6926279095c83dade9862b6d07fc047073657404fd4e1060330000000000000001a4092701f9170991583ec8b5c9b5056ddaba7637f7d6733a57dc4990acba6d15e9eb5dca55528e179b98a9e09e05ba940b59558b768194ca046c22e12ea310ec05bcc795ea419277649d40b145e6f0accc31f2d7eb39b29b51d3ba3410536b9bb37bce9014d352b496b93161fc799b23939ee635f25c4cbd6605029722ac2bfed7d55fe4120c0cc880661ea3313d700e261ba973bea5df4dc4d8a05652d193c5edad01945862943a6756d4b0ddc93ad5a444ecb054bcfbbba3635aa752d9c4fe8f93fc56c8066b3fe344143d65328025f5184308f2016eae65df8b0f1818f59f5a9539eec9c9c94704ecac269b008ef25f67ab2b9ab4e903b1f2372d1d3988b86e5efa639f9f964599df8559622c8d11f6bc4f706c74e4a603a3798005e210f93d9e6b59f8ccac907dc9cff127c552c8c89981e1b91c817cd365422eb6bb0c7ef4ddddabd306b0c32a98464973dec30def4149f8e9f35de6840cbd0ce8a2f2b5dec15e3f3c27d0d2720159cabb3ff2f73b4571eb53ec735d7b0f27bf4d23cd8b0fba14d5921d464beb3fd4f2fcf844f76a7f7f129a3e7e1c4a6e4f07490f2cfbac4e6730148397c73720d35cc5a46fdb1e774e17f7b951887c1c72ae4cb25ae99bee652ebb2ffd9f4c9400ee0870b27a5dd8fdb8224aab6738399587b4513d3441e26b898b35f739d64047ce8de70347042fd18c3797b1de82cfe23521dc8e5c36e286c05d4f81508e282018cd8d263164512e6ab02a22b3d5d489e6074f9370e218a3adf8afd229659f5046749db9615541408739d4f0646a853b25f8e549e85708c368e45f3e1d20ab47a4ed647b820a360e4e351e4caf74810098f0df4bb74e0e69f2db3284c30d24a0d109d16c37509557ce15c81812bde78085f31cd7c93140fc43d6580abc7ca2adfe6354510fd8104c0f1ffe46d24f31bea808376ac27996fb992de15b30abf4df6f4d08860bec27a95bcee0df8f0a5bd7f72938ca9e917f39c5425bff826c4a84a1fd70cff87be2e8619e0d3b729f0aadc10d4b70d10c2c020a99d03424a595294dd34b84c83a2d434b98fb116e2ebc8b2bc444740ce090816218ea61da172e30db5e78a58ef495812c287e3cfab7bffada0d6f2fb3c153f1a225bfb46e7e9bae9b666e72c35597797927e1bf02d1488ba90948f07dc12f6d8b61bc04d82994708725e0ccf5d76dcac946f36895402e84856b3e25567156040510fb299b88c45713175c54fb3d54aa6d383c423807778a92b7d9bc8fa347923749d18c96b20cea608b6380b57c35b4408f724046f6f65fc0d71e237c39376e1e769cd0234473a261c76553c655de0e4aabb4fd44d0247e4ef08f48bbf13a8cd366491e834a47f8a5cfbd6ca91c832fe4f77b3b3140a6c1c70055d52f0aa67e7d3ba18e5bfb09f738141a611002ff9e34188d540ac42f48ee06f6925cbf3cca5ca033c4fe089650a2b86a8350367e9cfbd07fac9667c0171f54311cd5b37157678b3d6155f0bd12ce53f6599fbc5beabb1f2a5424eb3f52ca3c1e0779d9cbc5e106693ff12d6e66c51bb1d12dfaeb70bc56d5870fb5ce4b040f86d7725ae53b1844b07557feca4d0e4c55a9cb6b6164c4cd3fda89f2a7259a4cd7682de9d8541af2e18b4e49218ef48d97df114971b298a6c4af231a432d4ac295d0d1947e09ccf41ab104e5435e7dddc0a6815b636a31be9a0d9cee2f22c745f05f384bd703fbf4bbcfeadf177abf4ca4524f38a681e5436a06abf9ca70c7569a7bcb8337b0b0c280b5f790ebe1258bea9c1da58c65c13991efc1ef8f7c75ef28affa340d84b3db3f4f188b1c7f437b024dfa6207d5329a5a7a0a56018b1f96a1963961065e07e3b2759f7e27ed707f5807342bad0935ed42609849d7a9d11addf8a92df7933e353a9e86213db0a27285e432228cf2166d3fa2a7f6dcc4f1331303f8db6929a3c0fbd6e82ba4496f3eb2812c986f3e2e627240a9102089725057c1e5dcaa3bcc5efdd6ba7e8a496f609aca3dd82816552c669c255283f9372be7d8f12b044f8c41180aac612245945a4467fa806892d55ff425adbbe92bc892698a32d39d7c23be4ecf4b07d79970eb3db84ad3ce589bb8b134761a442f8ca4e2020a4a42912753603f72738d5ca88c5d8280c3d8af9e83c18be420bb87db4b82a98d3af42f9191d4023eb22f428def2ee99d04d1497cb8205b67c9ca893f7afba077bae5fc11cfeb53d882763f2eb6731bab373923a63dda3ee1c1b6207e0ad0884290333dfae3f80e85cc50a241c73d7d99998e9b14c3e52e660edfe594e1ddcef04402e8fbf9061a5e0b3441a1cea68cd7e067fb146f57f370cc94ef4f28f4f5dd36f45173e40ce91d021465610b85b5f1a98e6908a17c5e138f2dd7da2769bad8789eed99828e8f23952bab7e9ead5fa9bac781fecc93de7927544736fd5c57f1da32be31b85657c313cd02104e1b889426bf4c8e9daa741278ae3966ea673cd3fa164ea7cc947b34f86c92084043ae846aecfbb15535a9b21e27fcda9a21bd8210721355b4331d01e57227bf6572d9538e4998313c5b8bf6e2f3f7bdd7510283f20ebae59b7b0784c0759dbf1036645c5d673edb45245f5e78407978b63d5c25ada76b176dcff53e76801d7c2784d4687561f32e7a32175c0fc77227b3ab0a4054462d04446e9c77f30cc87a91dbcf27516c956dca6b93bb4315f2f0765981e7525a510410af05c462f08d328cefa4bf8530250f5a4d3fa7f58f5a48db45cd68d0dd53a2c66758a20184cf226565ce558e60f0af982b02672f8ab14333349a5e5a5dcea61a09f93addea3858fea4e49c84f5d8269a2fe52f072d66240e7d30b7345c841ac22c16ee979c0f980567f24bb4bc2997ded6fe345d1e95c1b5cdcf006eb17d492bf3119f1df2404ff9bfa39568a52fadf98ac6d5a4653862d91b995ab166fa9de73478f7e339941e036b621f7d773a5413471d6e41a68c02ed89a4882bfade2b10e399f4515470ef43930a911609911f8b66bc060ebb186cdc4c1aa3cb573d696b0f48a655f8877f68f678bbf467ec872724181d6f983682389fc8a61a7525bcd61ab37930e6eeaac82b7adaa145e2a0bf67e235a657949708f0640ec802a174b1bcd7ca384e09b6f0e811f553609e88c5e45252d0d9ecfa42ebb69b7c2d22bbbc6b33c79f3506806862d7600e62c51c4d909472add5eb08e2c5a8ca3d58901a49e77f3df8841de18a30a9bc321ae43c712dbb9f08b457dd3e3f13244ae03da16acd6d3e861efae625478a89020655f0de72ac174a50834db564d4e60bef51e28954a938c64a6ee290523337153aa4d6cfaa00826d2aae1b57e3ab857e10cf2b497597ef9395fe6afb3d74b21c5d44281f756e018539ce8b7f4bc663db1eac9b976da2f994b193a30bde0394b7648b55ad9bde958ec5bf89eab516d4418451d8cbca637c1d6dfdef61712e76aa7f12151d5717ba1af71c4754136563ff2667bb1603cda51baf8a575d4069262179828d54694382f6bb93b98ab9d53d29793a524ae9c42c12dd42067584c4a96f6c15fe590bd8616983abbf453ee038f385a1265f7856009646cdd6f409d9e1e7fd36e1cedda1137429964b71af9d438da0858e817ca746438e0949dcfe49fc67ae967d13d1d1aa37c2e410bb95609c7ba0586c8fccdcca933b1a85ec97d1aff670004f71232bedbd192ba5e5a681867470c4e146221bee322a5f458a2bea1316d3f4be26efbcdeb4b1062e58f2fa23b144cfdda55aad3ed7142653c7948b6d854abb8d1201e9a4de07b8985fc194e58ea08b4c8528adcd73ae6bcf5493b7b8ae1f663ace587a87d5a341828612bf82605ce6cc286ee0161631ba06d704d2f52e37e3dbe44fc40c4171446d0afe69cf8efac8657d9d5307f158d844bd3664865724aa9907d2ccaf4cae78e056ee78815cbcdccf4b11e181a1d2841b0146eda60d561762a7e3512dfd59fc133713e5c056cbde75d5b536d632338fe83a8d02a4b7fa9a6f1a5df9de85c88b944581294609c880ecb5eb45de087524d896486c200ad68f5c45e43894d6e84493bed02602ab075c8d1e5e5be012e4ce474423bdd21d8d6662e182a2ea7eb30f2604b468a25c417c15a2b55031563810b35f33503cdbeb46de12c0482c70b07b5ca3c4e2aa21be75c33a23e73c03379c434dc8bff54dc40b0a34f476d0fd1de0422ae6edacc8a729ed2443315336b208ceafa68a229592e42f49501cf03fcf04ed2ab60cf7c31bf4d498f10569eb3666501cb8ec6e22f1825b7e69f632c24180c3af0d658dccd1c5896ae71b5ce46dfafdc12f94a7f8f3d1bf1eb769f52f43238ed411a97e55625ddc208affbae8ade42829c82cf4f62423830db9ca4091fffe3d282c578552649a34cbfeef3d58e020978137a44fefdb9083186dfd712301431b78095a0997f0764f26e084ee5a6d1d7b24b3b0ae4100da91329f6e8a0a92f3fd94c8b53270b44b9d419e101e18bbf128c7a3492e8447533b7586a81e52366bdf2c376a57847b8a44f7b55eaeee6ab2f06596a87ccad4a60881bcf4b4b5d5f0de85593b643c0c4fe1771a0cb5bb0402fae0f1a2dd811d6495676ad718b73d4b86fc79ce074aa992487108dcb4d908f0da654a3e1b8dc28cc2fe35762afddf2c93fc7a0593ff7c7aabce02dffa8817e66205b179f37bdda376d25d6bbcc83a15ad757bb7843aa03d2f7193d8d707ccf4de1f5c8694aa212219752addd55cbb412c05118c30555ca7ea820bf3440d1dae3332947a1cfc22e366d1ad120b906274883d7769983eab6afe18a253fc6355f81f60eb54f6ef7a48ac185d7e61d6580852d4b98443ad304ab8e7725468034d2ecfeb68228060bad59a4deaa40843d0cfe0a1e58855113bb7c5965254b82cf3997924d0a8b1711b1e1e5b28343168f64fa9bdf8e5158f33c91112f61ba782a4f97c5456c9c8756adf53a7d919ad90654a1c035d8686f83475038580df22e4a72ea9f0cb73470f0b52544cd7916f6487afd32e0527a311f7bdb29e4e4dab266b7221a2c49e42d8ab06ab6d16efee2a0e0bab140aa34b53f70c808f3966f1a171bdc789e23ca0246328dcb1680c765fe262048b869c56f381bb7ded54e1486c0a3660d990f4bf0e5b4eec4cc0c3abf4edab6346cb531194c27de0d85fbd39f86d1839854a91291164823db1fd76397800c3b62b418bb3a894840ecc78579dd242314da99f01df55a45dadcc87e4b216aa0d817e60673c9807a75185e52a70f04ab8ea28cad805c37fae5417f89af44d4a5728c187c74ea736f21681fa7f93dd9bcab9b510febf2c4b5c64cbedb6b59b77a8816728dfbaeea423bba4663ce831af234352f8c68c47dfee91724c99eea5940f57b4f1d9660f0021892a2d39ce7ff235425942f2007b4e08f2002018f720e0339bfa2704a9d74798b13c6fda733d965666ec5592d1d6dae7af6efe5c87cf48d40858937b1ecde3445ab2c1ba1e87e1c2f3ce696baf3efb30ecbd9dbfab121a142ebfb4f09f343f37e851fcb7bf011f2117881098afc5a584e6aaa79f11d4d540874ab905787577e6407a3aaf293c886b58cfe9bed8a3dacda2a2ce41f95e72e46baf65ca666f61bb548afe8f92e1c4ada258f46178a4591015678fc542d412f7ed323d2629c127890ad9c2151261c4869f59db9648e09c25bd5ad8cfde27ea4ef22666ae0f30a4d25ca5cf42ddf3f75d2121c46e28f565d561c9c5ffbefc847ecb75a2595c3e410c1704d6fa62fa5fd54139d95217734ff4e596f2ac975bbfb8fda29f7e6f211eb165480e44fde387d4833f89c7162c1bda3265a5271946c5392921861ad5d9e5b672afe4778301d7a8a8d8a03ca1c99d73b2ee43281c0b88ca4292a5ea29a0e2377007fc04707365740563020003c54f16cef0fd4185f35dc6784047913c89883f72b68aa78c16f144624430909da01633eb2b4b13eccc2b7a7ac5ef3b13505cea54e1d390944b5680e6860184e35111675dce504784f4ae8121dbd1f76df3d55ef722f3f73b5b7723efe2fd34b107fc0470736574072103652ba5800d63722adef5232d31ccc12403055de720f0155fc47bba5750ccedd400 \ No newline at end of file +70736574ff01020402000000010401020105010401fb04020000000001017a0bab8c49f1fce77440be124c72ce22bb23b58c6f52baf4cdde1f656056cd6b96440980610bc88e4ab656c2e5ff6fe6c6a39967a1c0d386682240c5ff039148dc335d03b636cc4beba2967c418a9443e161cd0ac77bec5e44c4bf98e72fc28857abca331600142d2186719dc0c245e7b4a30f17834f371ca7377c22020334c307ad8142e7c8a6bf1ad3552b12fbb860885ea7f2d76c1f49f93a7c4bbbe7473044022040d1802d6e10da4c27f05eff807550e614b3d2fa20c663dbf1ebf162d3952689022001f477c953b7c543bce877e3297fccb00ef5dba21d427e79c8bfb8522713309801010e20cbbe4671915035276d8df41a7ef0b6a36dd101de48a4076046fdba3b0bec20ae010f04000000000001017a0b90df52169792d13db9b7d074d091aaa3e83aff261b1cc19d291441b62e7a03190899a91403ca5cd8bded09945bc99c2f980fd27601cada66833a5f4bc108baf63902e8bed2778bf381d17241be029f228664c7d1522ced55379e275b83fe805b370216001403bb7619d51d2af2c5538d3908ead081a7ef2b2b010e20cbbe4671915035276d8df41a7ef0b6a36dd101de48a4076046fdba3b0bec20ae010f04010000000007fc04707365740121089f9677efff5962164a434b0bffe53d90c271deda3eaf30c1d7a55105d24b874707fc047073657403210be6c538eee2e29d44c66a3e66fc8165afa4081557031826a070703cb69faf24380104220020c731ad44c00a2928d508ad82b05868cb42733a5b0d0b208f483307ce8c328d9307fc047073657404fd4e10603300000000000000015bee4d0045b0884354b05d0285abb287ee8e539e8146b92dceaaee6fc01af1a3730cece4c77caefdcfcea1073197ffb8b3ded97d0dda6f49752b31f23e196378a3da2128a8c45ecb7eb1c32f0c0dfa1ce7bc348e799f66d547476e976baece7445790064b34b1526c88cf54928acc906ec0925327d797d36d0db6a43633d7f963ec9b4123a5ea31b655882329afe2108d123f76857fd3ce344fcd651b3d3066aa506625c9309acead85fb6c8a7d977db5dd6cb6e2f99fb3535746258d42d95dd2103bbaf5d45c8a2dfaa2301eba08763bac8ab3b59bd0082a457bc0cb257c43ea6354348e73d8dee101864068f0e8e30e6711f1597d7b529a57e95fc0df813ea160f5f5152f341087868a680c1bbc4b2a427d18cf8f12cbc4304dd3b1ea4c916467ae48b3b53062ea046161170fbe6ca07462cf3e5534d638c91fe6919318c4b2e98ce0ebcb245680d6395ba746fbf510a9a36ad8d933b023eae39973a39162178148a897b5174940db46e4be54794cea11fafbed48b42eed27f9915cfc50c958e88bac551ab1c9bfa03653e558cf87a99ff13440f4808e27fb42ff3cbac9fe10d1de07dad4807c9f945784163214c739a9eed8bb2e7da6e1fdfa4aba5d5157787d0000b220145572d3d9253cde5c1132370c1849847633287660b429f20cf1f72e4ad6ae59154c3b8526fc5d30523ba962a25577427988d326e207c97c81b479540b1c63aed0a4b1dad9279879740b2f6a0bfc37aea8c81b3b35b630dba8d955afbba756b8ce9d2a9802939972c5f70efdee8778a98360eef15faf77e38627fcb4f98569d68ebad3bb667e5db46eb7f4214846e651224673dc998c55bdd9e0a1629497a75b76160865c7ac3af874bc45a42269508f183d2458835b1734791094122f75398da2bb7919c67221ee42242c298d744fcb920726b84bcb78d7eafc9e0f61a02de87ffc5c674390a33d722b50dc35bbc6788fe0fd24be7a9e358113a4e65b49655767b8f3c3bb86cd5a56c79f9148945af63492dffde82d682eca4787f203e49790650395c925e6eb68bbb3adda25bb784365c0b3e241177ca7de58252b8c79c5a865d1030f3bfd4d312bdf83bd28241389085433c34d747f9f45a0a636e700805e619a19739b15077d44d5e8969a37481896acebe7f350449c69b50376b7cf36e906d8a03aa7221de67c7fc4c5408b55e2562f7b783918004d93b284c0a1c3d596c7c18aef5cb77ad09172bfa888f5dceabf57f708f5ab61b1b4159742d3d35332e9942958ea7f39fd35cff66e84ea0ce3b38a85eb80dcc1201146fc3854cb40353a078f5435fe2becfa383b3a62564645250cf7feccff5414581e747166625477c70f5b0f579bd578e03e6b8ff8c3f0e8a82566199ff542b239f2999103cbb61602bc2f346702204e50c9ce7b85f3b8e144227ca8b9766cdbd498191c385e3a4f024c9396763eacdfe41b706fb23d4f065dbaa43d323edf1811950c71d4475a3e0913d3851be4e921cc933bb06b0aa20524267b0e9847b6de3883ab8c5be1eac17b06c946f19dc2244901890cc290f2e66147f7c47a4a29349555ca020e684ccba5f8a6f1be54e356654d3e8678c591633e11d9ee772940d92f07ab83228c0d8840cb9aae514c03358e973a2ef319a39a3ce819efc00e5a493fd582be164c1460f70fb2e103f09a2939f779377275be736ccd41f847133b3d400477582419fbd2d7ff328d88256cfadd750ed7a3c6657e332f635f0a90602b24135e705d1530531b7b738e686d83accd74874e160a5716191447f832d2f899476ec9c53204fc4ade5b75cacdc869b4088e009e12d85beaa3450889de0c86315755ec7744be592f058fafe62f9a89875bd2781d5d6928c8475f555e77eeb6e688bd8d3bee0a54fa1cb29c1b6b438d3f70ee4ac83fcb6f482575997e3a69240c6731b517d8241cd39dba6b02a9e3c94ff2470c61c693d32b1c7d22ba38f0da21d92150115d580249380500109215a05baa63474f773892b1870005e76a68853e6a8cd9f74ab3f41cf0730e702ce94c420dbf66a63f342d927923d7d25ca3c3823b6c352ae2ca127bf811c023205632ddb8f9191c2f3384a61038d1c4d32f808cbaea81d58f0aebc7c89bcb5b98f92849f4fec19cffc78173e601eb412aad24eacd74d17cce3a9ee76670367ed87c2da3db5e4ab01d4d9626d0ae00da7dbf6b8103d5994cf66ca56bb9aab9eabee2b14ef798d3fa5ed1dc16bb500a006c3320941c4c7f6f80c8b1bf79131a5e11ef38db7c42d4c4939711184ea414e2ec0cf5bdce3d7d0d72dc883b2595e5f0fe4c14cddaed61108c90c74b43cbf719bcf7a934bee760ab33f50cedfe3ce61dda3e4bee1ab4dc687f988cfceb207152f7a98c0fa3a114d2d6881034aeba877bbcc368ce591707da45becc48318f0558b3ff65d677578df9fd9e9a18d0cb08f2f5cd4f44925259225b1c4c5ed84ef30d136e7c66251329a223a1db0b485f1c634981f8860aec1f3dbda9442e5438f6fb09c7e1ab43e2b757911834df8502ce35e7be947771f7416f7ea97d26dbad7221614175e6b86f1a323e26c4f469236d1b1bf6ef28823234c73b275c5b0ff39e8c04d9dd8ff7f6a57214d803aa13dbf581295b92ce2b8a9c0e3fa8e4fe4e74c4bc2198fd010cf84681cf5f3fc9df1638c403006478b1cd4204ef3b7a6093116021118a839bd3ac270783e67096457a86d63654e268821ee742241ab5f7e91972da0a94f679b4c093d3f428d5876edf51459331df084f2fa245e3648e0cac904a82a7d323b965a39683ec0b2721105683e67d65fe10b8d41d0dfcd5c31756408c94cf425ae67f95ecac45391516875870386b675e24c462b1f7634f758723e6245da6a39da69cc2390374eb89c6c662d94eeb2f1835e233610072936be248e6a3ff87f9950c2eb2f88568c31dd30d1f0c0396a42f6be2505bf616c63f504dad5312fee2f083b406fa05cf3c998ba24237402681f0ec393de4650ddce3389d4c1541d4705d8f50c2c6d4864934394fba0c40df495fe3a5bf58a5498c1e63b5ee5f9a4b53dbd913252d4808f5bf5fc3c6dd74c86c974fc9e5afb1a7ee3d88738ab1fe9194881cb00197a31d648ae2448db872528d5f7c366188d9d98ea94497cb78ffacb5f6e8a2c8520d8d196fe0ed13e2b2a5a08dc45d8ff58a8c5d3bcbdc5d80c798acd0eabf146459e79db12c2a43c55d14b2dd608475c606fd4f943ae7cf62131691768f710fd718fda3967146daa8d4f34a3b8fe8084f4f3865e9e0cc1a0b0a799fceafd1b74f09f524822179ce38cf0f2c4c8623a3e3ab2cc20f5dccdadffacee62c120657e3d85fea93fab645b5fcdb812b130afbbd5b19e86aee66011b520b0affd84af4bf67a28b309cad66cec25a5de06390a4f2a5af47d59c006010a8ffd214149bbe47bf847fa94c2113723c9476c2e6dd84411bca16dc7bb096aaa3e9a9be27811b52838c78d16cbd89cad379bcc0cd966dadfa428f9d4d8bf133f7d21022ae3f966dbc1409c6d57cc46ff4434fd90d79b6c9e68ed3795ea6191a7e309783badaf8db9fbccbea905ff9d423370810f02add38ad3088cf3393e7c6d585b76fd78c67766fff03ff54c01228c6737da667147a8b5e722370a24db8c0165e34888920d70fb1356eb731d0024676444e2d37860eaaed9790f99069e622afe6ff12d516812022c46420006253248eb292908ab8658cd874ef05bd568547535fd54c1f0b5b816e4d90a1bd55670b96691e7633a2fa45be6a29cf7bbbcf9e5debb4b7a739b36b6b326b719a12cd0f5e3557a2fd94023d8c633fb697b85080a39734013b4ed9a7500aa8093edfc3810d4c890e608951e57af8447349cdf45a076449241a047085702dc3e44814390ceddc878791ab3a6503f48f48af25fe5cddf61e7870ce80e32e5f22d5725bfde4f319c2db7cf3ba3b9952202cd24210ab8d47fcdaa9ad5e2a9d2c7be1ed6b67cbc1a28ebe565ed0337c09c97d2d9608d97905c7201be7d4bac785d64caf783cb3ebff817bc5ff0448899537ce6911c9803744d06ae97e6d3aae037697986cb20061892ae72e05968e9bc54153bd745012af719fe7fd4b917689a6cbb94a9bc8cce51d234ffce7dca804e2b2759f473885855983b7b290806884fc66e724fa848af2de3164c611c630e5bea712cdd9a9943ca3ad55994e5587c5953f415171bdef3c42783b809bc5526a88aae66be626d73394a607ca32256198dbc026d9e09e9659ddb66736215dedee0cf69a24490a53b2c678e6caa2aaef10a4610f802fc5eccf558629554d6388465584514d3dd49fc00fb267c39bb746f76ad3cccabcc3cc882815bd9466d593270a5c9a04945dea7ad06ddb73e66b90270e859a109d52251d911e7177e07295ac9788ce970c1b718fb0c2f327f44fd0cef3cb90071ec85e958e6ae60bd134ae307720cdb10be5a0af8c051295df905447b46206b5e04d775b83e11c348458b1bb310ae25c54e8ed1488a95b2a576002198c80e0e69d14fb7bffcd89935faa6e3f9aed61e0492bb2bc334e389bd559806eff9e16643ddc4372ca83790a99bd4f5b042779ef7e3039858881c8ce0041d43ed6b1f42f18007d046fd6f65907cef73fd5e6cd514c4fa5ebb872b140d0b2ad43c58f2f2216522e78a19828baa34ba56d71414ae869a13cb708762565d754f0754561adbd9145d232034229d2840ef0c96f7af4b232c5e11ae9d018b87177a506b66571affdeb693e170dd12640e86fd430b64509d02694c52a54f23ea96e39be92b65c1abcb262a71d6e884183d4bc6cac8c79f6e94b51abe484794a42a8e1be721cd59383bdbf327a864b2cf27566f1270d82ab6e8b3b934e953b7d48ec4697172e0160b8435e8186a7ea685dd61402b0bef09137fc52e19ecb53674a1c0af17fbb0efc2b4d69572b32600fdfc3c85c79ccb2685c665aef16748b7f15862f435afaeef00f3f927cd3a60c22f137e9cb2c38a9652cee570a76351871ebc9b6fc720b9117b1306e8afb298e3a1d0d4b2c5ad5a21e9de4c0938a98daa35caa711bd6d3312a7e941b060c4a1ec211c31e53da263995d3be74a3ca5a970d3a663245a5d8eace336d9ee847619bb337e777b961805e808f7cfd8f09b93b6ce6c277396e6cf0a6153fb11625f421b02055dc53a0bb24786f4a74211bfdf44193e48b2c15c7c85acd3f4f0bd26644f9dc62653e366178645899dc06d191c785831b98de593519c0ac5849897a01b4f8c7fd559edce1c878bdb9dd091546c64225fa81b1c7dcd6fe72c8131bb160043976a5e891236d3552598c0c4fc734d1cc752c10306dfc8391f6d658ab8b7a1f350e1900edda29775ac8a531032bac968f6981889f13cab07f49c864c3ef3ff23555c170ee9730912465e6bb3b7508e11ba27001d9dc0da8b34954a7c46a2d0b0b75e73ad66278c8acbed3249936a6c76fe975954f7889bbaae5f73747e3ed02811b015beab9d1515e396d37b2a116b3cd8863517b88ee91a854e4740304f7be41123692181a8ae22090956ba619fb948d3f08108da17ac2484d3dd5795b1c716cb5ed3fc08b6449fec814018cd883b02256afadd1f35a04d9d43f661be624c0d59d0d397e8ad6917344203843495162217e79bade11ca32c0a6918350520e6c3f31f866b89e3497b518cdc056e760813ebea7fbf343db50ca2450d5b7a1c5f430859e2040ecfa70cb0c3e863a756ef6ae2e26c68b543d35beb44513f8295872df5b4062c9b80742ca7a9c2ec36a1d9bc936c7fa7328240a2db54463ca04a40dc0c9afe4d570012259c8c436d322483b17a705d60a283e0ea7545110e898ba43ac6130aebde014d237482307ff28f385fce8530814a3b3507fc047073657405630200039d46edc3d830d852edbdf28cbc023dd1666cc4a806ec9d4acb2c97865280698d61fb6b2a073be4ce75cf8193fa9b3d677146575a812873ae7eaa7b08110cb88904273dd65af35115dd116092a56ab45fb57178d8c5ed4cf99474ff760f6e987d07fc0470736574072103701e53a6d0b960398abf678382a4d17c5c153d1a2c8ffb76b302058ce915bb0d0007fc047073657401210821b4e7599b1b4faf29b521f1c442dfb0a893499d374c19db939c0c9a3b9798c707fc047073657403210b8529a893bd81e38743e8e3015095077f6e244a064d64708963c6af5024b6aeb3010422002058037c2d81d3122185c8704d4276e2629122c95b8ea68575c451628d37eea84507fc047073657404fd4e1060330000000000000001ddf2f500cf45e30e3911bb51a7ff633c1e329508e42d9aa49fa8248fa4d293b87005db08b17a472580ae2cdd53c40b2a16af885d6dfa3d5b3410d389b045e6c12405c635511ccf008390856f4c6d0ca472148d2969fd39e1307bfbb8f8268ce92398248f08df7268bbe23e13ac3801ad075376bbe9684db9b41d7b1148fa65a129e1d25193ad973ec7af631a0a30c5659409b0d00e6fe44c2c507d52afbee8059aee7650bee9d47936838e77f00cfec9de3b9efe72cdeefd80a19a9c8ddcd6cd9009ec96800f9fcd709f1432b5715466d601b5ed10b0dfbd09b954b109232fb5a24036b887d26bab43da7eaa303e7c8e9d02950610aba09f343a65a7cb4550d6f6e5c0eeb9410b68f85cc3b05b9340e2e9c94a473f2001f5aea7e875d29e8e0aa99c09afec4a5455258c803e55b89cf6e89796a6f3f9fe11ee05ec415c6ac08e0f1adf9dad681f8121f82e3a9402a2fe13a016dc10d4a605578317be0d9d3e02b0989903002bd35ec4970701da6eb6f9fd5e6cefad137dceffaad968d5ce522e77c76e665529f70c9eb805a240834f4c8c795912c37e7efeb73d4bab709aafb66bd645cf0addefdd83d185c1b4465ee16344575eb2aa3acb057c37d7c22cd03adc6701f03d4cfa20ca94458b3b87e3fb7de8fed28a755bcaccbd348dbc7f5aacbb25d19437d87cb48b88fc714f059b328c374fb2695a26537330fae42d3fcff40b07054be10508fa78a9173315506119973a9158828276edc6e8ac771476d7479d07ba73e9c5b58d61367d24435a1062dfa376546e843b34829103168db63b708a13894813a442f889a423054160b85a2584d36951136bafc490056f1c03c44580e2c7a12b170e5c7a3917720bbbb21e5da616649b554b7ff57dc84dc3935271a8aa6fb218becde208d83e76bb6197f5f4f729f3c57b4280c388bf4945206fa769b672ebd47ef2d0f777fc9dfb031cf7c333c6159a75a5b33ebc6c4683ef140a144a5ab15b2b6b72ba14ee7595679a0f7873a75b9a79e03676ae94eaf9ea8d3532460f3075f40c6b9848a183fe46651caeacd51551f308eab6ba8ac27b93865f5dea0fcfe1d7dbb745695dcf187a5955414763c88ec01d299f03cdaec48eba946c7ff6031f28a5e108651401b5447c0d21c449b387765a621c057eea7d494302222e3d1ff6ee9f8a0580671d9fe3ecc310e84b554e5c823d81b8027075f749b2dc8a6bc5a99fed4a0fc46fae59cc2aa9f1471ca2b0d9fafa56927fce0f1df92647ff5aaa083bfcb7078bd8ee142448d4e1f3dda670ad93feb21028a57ee9a8ae8880df5b3276e078555d868be0d8843b495e082d743328620f36f7e106733bcefac15076826cafce271caf1520cc8746948e71ea73eef5de770ecf5e0fe075f04d6c9cef1cc1f262e69fcfc89862877ffd520e25405d9d07efec82386640d97147e4a6df66bb1fa1f20dcc2ee1fd6364bc2024c0a4a2ec00b84616231c02aef16147df509cb830b9fb20111c60613d41169a24ea67c03cea48e1905b00eba8a61e967b9aa5b6e1264b0f3e2c051e47f54f45c6fb78b46b9993c7d223d51036cb77f5e31a4b30892e8fd7ae7028322d6402f60712f712f84443de083767c38ae88a38fd4e4bbec58015f4e49e36ecbde94f23d0061edfff0e9eb62b67327249d728c278f923748e4c1e225791c740abf9493198f073a6cefffba00d23715a14967a72cc7aebb81ecc6e8bc88ae63a47507296a573c415d0163219f3b20974ba3a32572d29a479b88b89c241e63e640bbb93e2da0b73024ff03516ee3ecfbd84348372cfb574817ca878172a779ff131492b86e64c1b7054cc5fdb999df4a9578bbdd6a6a2a798f053f4c7456173cb8cb9b61735e650d0394ea9effbef615629c1f393949095982345bfc02b9a3b3ec64d9173bb1285587048fca8c740b6d2265d3e727069fcb90282c78f1049ed7925113279474d0d873045851b397a8c26036c83906dccd0eabe98f7d6854d9abc2e6ff12d84c2840affa371cc2dc624fbce873f38570dc9eff33f5e200791bc052307f5c718d47fc2a205add3fd9de2a81cb452a0a7b4a08bc133e9816f6ba852735b813a1b906d4dbd1ac8a968a8adfb6aded0d3fb87d80132a4b45ad39274bb72df20d648a26aca4beaafb971e13094b6d6525bd418b91320964bd90d3a98fb32d69222aaef2ea95c6b84b6b6aaeca3f6789944fc7ef17d218abc7667ddff798b74a0d5fbcc33d22d028d207f82286fd777ea1e281d7eb88b665e29fcda067bf9ef82a190c920e260cbc44d394b78e0439bcaa6371f8717ad82e02015f21e5dc273de338102539bc924d5a3f897eb788e0f3cbb6e8a34590ff5370bcb0f671ce28d6ac0adea17f9fda49c784ae84464991fc71a31d320d62c4199e4f4e38f390ffbcc7f15922c3325451371bebfaed8f8a7d3eead71c65878a705a6163ef649bdc6ae7b81110a2cc9576da6b0188337160cd518fb30fd5b0c165ac3de81002490f36d29f3bfefa2b4796c070c6d7d971d18bb5a573cd48cb3c64dec5bbbd7f2f6f60bff3db4833bb64b426c6715021997350aab1751f0d5382087ec133c2c43342b31eca32a4c17db14148fb48f9b7a103b2c0bfc0dc95ffe097bd8f2213a3f7a43c994599b05dc35d469fdc025e23e483039f271d948972417153c849fa8dbf374693dabd59d398732020e90d8f443ba45a00b430168561de21db76b9b714ca8260fdc4ff1a5713e69ed7296f5a5a9d192474bc6e67788d6a44d46b69ac97d0b34b2b08aa79d5ee7e910d99221e1e7f6383628b5383cec4341e5c3f18ec3361b2f2ee5935ed40919a4f8892bf3467803b720d29388b7cd47067eed9be7648fbbafcc7bebfc31a30d02f38b7d6be1579c751aabf679fa6891adf66da2257432c10d399a8d496d1aba381b64a5e3ec9a65cc8419151b638adea994c3590f77bf390152894b2784f7832d986ac51b20ba9719d85509acdedc0282f27065c87bf483fc74b55579ecc233fd6c51822ae03e46ecdb15acf0204b67852d525168f409d2a4309c5d9a14b35905b836091964ff4fec0aa91bbd7f39919eeaebbaf75c63337a4dcd5ae37cb60fa14bd78157ecef35ddb1cfdc366eecd48aebb0f5b395e4161c158c46870fc89f8f5918aabf0577c914511cac7b189384eaddf7f03cc6706a9abf219ff1b293cc9fa2cac88b65af62f0493e30736b596c119149af07e840a43dba8d97455a7a95368395488304626d3b888069a0099c435cc11e5981412f79153577c9115a1812b1c4a9ea42bbf11b40fdf930bcc37e6a6c50a7e3d06bfe7043adb32244ae359993caad00eea5f1de90355326e921145add1020ef3c2cbcbd102e7b9a150ff9672697d31f86572843269978cbc4c3fe067417e84898587d4de009b33094c8e8102c07facbda62a2996e083d0618fd9651e17f0fc025a946e7c28d93e18675ba69d8811dd06a2cc1aae28de5a6af30f305cfd8a090832483e4ff7c974d47ac96d2f3f7baec94f965a116c2734f87f468ec33cee1a58dd2ccdbc8f6a0f2a50a739aadf4007c7a529844cd1ce5efdd42eb28a0f5f04fde00dea586e4b8cdb8469b36940de19feefd342285c29298afcd3ddc368f6365e9ee255f8c2b6f70c1bafafe10720402a668ac3a2cb8ee75cb7004455cb4221486c3dee64f8f25f1c8b1411437cf6ba70afac5182b21f0efc1b5c71dd59f71796d2719741b6d5c757d824cdfd2d9459569427951d6974d94bea1fbeb0e1a23ef88774b270a8bca65f01a00299258847ddce8af8a7626c802b29dd01d1dd9d2a7243b334c29c0943e11ddbfe82cdfbd506e81fab8775a1d3c4f6c0744e1086763ad84e8f51d601e24cd6fcba1409abbb1c6b5c9bb9eab8ca30282801448f86cd5d8ec187866f1ba738863f3995bf4084ebe8f41dc1ffe0cd47d5a95dc5fc0dde1559ba170316e085d0e385ecf8646bf787b5287960f07bff9d3d990b3be4b29f008de18ccb46dc2192d0fbbbb9e701d350aae205fcd2d7314112bdc393e2eeb0a96c5f2c767dea0b82e9549f46a270b2c69915711c144a7737e9003b1c1b8684e9f2abe66ad1678c32a0c6ce401ae2d7507ff32c8f6179433b94764a6e4ea0a363e9a03787502c67ec97724d78c1257499379ecc5cd006a13acbba05dc7f1310bc75b9ec6a09f4d95b2ec11952eb3dc3d2dfeb8678b10b5db162b44af56ada56f7e311d6c5ce46472d9ba2284126f8f579d59a9d3e81bb1b26a7ee59c3cca96252fd4ba8e009a213911619ab4184e83683969cc4c474e934f36e6ba4ea33d9e93e984f1603e259cb7f1a3824dd8764bbe30ae08166aca84e63615e59c31d2a968a0beccd40637db22b971d51a4c35ce83108d8975d758669bd83ff9602718a882b943f80745d95a2d5e07ad0acf8023e24589fd68988a350c0ad571470f8b9a906648895d312100cd18089465de942ae0c7c8bffb5d3705c729990721bb0497dddea6dabdd530c9ec90286cee5ba3e2b699eb2de55de8aa0012b38051862bf0a7a22d6cce4310dd8dc47c206d9eb7bf28f2a53afa8fd10836210c0c461e417be42d89ea659a76d5e3cba08daa885b7f0302c5df05c72f8257f60e2ad954891841e67d8b7184cfa47e51e9b36f6ed1400aa84c5058a1998d07709b8b46630d70c73552ada18713310dff4177e2143aada1038bae9a64e02870a7535598d766f447b4e25dbd009009cc0e3421067bd0cd10735469b308cfd7a094bbdaaef2e31c22dc6c1a6d4c7890020b5bd04ef649b56889b2031c1923a69002448dd5db1142384cf517b08096539cc537532f43afc33ca77beb2dfee921178ad51b04f10495365e60b4b7677880409716e0eaa3a1d649a871234f86787c2792bf1e04a635e3f22b8b3b1382be942605c3855a940cfa3825a2f8993312a512c81f92aea0fca95bd1bdb6b9774ef3f1fd15bfa1eae84ebb48bc9b55fb2141c55cd3188eeb5049b2e6f3360e60c5bb7d91c9028ebc9287b4b5541a4ca290288e08ca46f80eeabbf100f700c873d7e69dee7dc80b842004b2bb93f0bf533488028d1a1137371417d06785372ce942d4c6589cdb57514bde81960475c22393eb02a93b6560fc3e4fb6ba692dc362d38e33a41b7df222e9192fdc0e0499f110e681682e2b500c00947d62280482dde5e26010cf959fc717d0837c98634550376aaeb17c1c80e3c3245c36c68f56fc8be117ff84957a75e4aa4caddb38779f1c50086ad4863002127b6c8067f172aa78137908fff82b2297a53d6232c26a2e94bb25b7f9241013adeb36d1e437f2f6c0d983efdb78608e940390005d63c081eaef21d7f00ddf51a3fbbe6175be436a9b0b75f198c30efee2821ac5f088819eb96ba835999d0012e7a0c244268a658bc6b7845d10178283cb8add0b81405ccd64000c1835111511555eca14f7e3cc9274b45f817039ee62cfd95363cc66f5397f88822f790e0a86b6a69379dae77db24185394d9fc73880d39f6b3233dd8d3b912995b22905563ae8cb2b1f3491feffbbdf2c7d2e89dce1995d2429bb0a4c550860835aef589983d3170387971f8aec15c18450dbc9cd12f402589dfb17216e359072ceec8e9484f9b490a288dd4b268233c40ad23721961c390bae0a181c4cc8eb68eb4b2a5db6944042c6ef67550f9abf3b9084cfe8521b62d727416576a58591dc65f79f871958243ca4415d92d3e588c4205b4a3806d64224e94e8f04dbf7f75888246aae9f894bab1ea69d7e10b4f07e8cf2dcf70cc62571c737cb6b6c68b0e3fbe4b1931c8615a793fa3db0a45090458ff62ce8bf421907877e555cdb97d3709bbd8728c4432288861a56cbfeabbea5f225cd29e31d99eb788704a93696f5e81307fc047073657405630200035ed48216bc666598aac5498e9fe513a9e21eaf842d382767220cf98104bfd8866621efb63b2eed44028cdc9e2f64cc2447fe09f8d8a1eb3214272855b525d9ce24e6daee58effb4af28fcb0a4685d78d7995081b5cafd1cfe343aefc8e9cb23507fc0470736574072102b642f0e5b34746f2f6e3b511d037e16bc720292da4ea2fb31ec09f6fdbe777ce00010308f40100000000000007fc04707365740220230f4f5d4b7c6fa845806ee4f67713459e1b69e8e60fcee2e4940c7a0d5de1b20104000007fc0470736574012109a05049129b0d9e61c1bb87a9fa02c2435be35e3535082a772f65222f2e4a48cb07fc047073657403210baf4431fbb8f0227bfc0008368606a4b8f2bc1706e1a06cd4d83706217b74f5b90104220020c773786f3addae4c21acb094f39122c032daded1cb6225a64d923a0344087bfd07fc047073657404fd4e1060330000000000000001a4092701f9170991583ec8b5c9b5056ddaba7637f7d6733a57dc4990acba6d15e9eb5dca55528e179b98a9e09e05ba940b59558b768194ca046c22e12ea310ec05bcc795ea419277649d40b145e6f0accc31f2d7eb39b29b51d3ba3410536b9bb37bce9014d352b496b93161fc799b23939ee635f25c4cbd6605029722ac2bfed7d55fe4120c0cc880661ea3313d700e261ba973bea5df4dc4d8a05652d193c5edad01945862943a6756d4b0ddc93ad5a444ecb054bcfbbba3635aa752d9c4fe8f93fc56c8066b3fe344143d65328025f5184308f2016eae65df8b0f1818f59f5a9539eec9c9c94704ecac269b008ef25f67ab2b9ab4e903b1f2372d1d3988b86e5efa639f9f964599df8559622c8d11f6bc4f706c74e4a603a3798005e210f93d9e6b59f8ccac907dc9cff127c552c8c89981e1b91c817cd365422eb6bb0c7ef4ddddabd306b0c32a98464973dec30def4149f8e9f35de6840cbd0ce8a2f2b5dec15e3f3c27d0d2720159cabb3ff2f73b4571eb53ec735d7b0f27bf4d23cd8b0fba14d5921d464beb3fd4f2fcf844f76a7f7f129a3e7e1c4a6e4f07490f2cfbac4e6730148397c73720d35cc5a46fdb1e774e17f7b951887c1c72ae4cb25ae99bee652ebb2ffd9f4c9400ee0870b27a5dd8fdb8224aab6738399587b4513d3441e26b898b35f739d64047ce8de70347042fd18c3797b1de82cfe23521dc8e5c36e286c05d4f81508e282018cd8d263164512e6ab02a22b3d5d489e6074f9370e218a3adf8afd229659f5046749db9615541408739d4f0646a853b25f8e549e85708c368e45f3e1d20ab47a4ed647b820a360e4e351e4caf74810098f0df4bb74e0e69f2db3284c30d24a0d109d16c37509557ce15c81812bde78085f31cd7c93140fc43d6580abc7ca2adfe6354510fd8104c0f1ffe46d24f31bea808376ac27996fb992de15b30abf4df6f4d08860bec27a95bcee0df8f0a5bd7f72938ca9e917f39c5425bff826c4a84a1fd70cff87be2e8619e0d3b729f0aadc10d4b70d10c2c020a99d03424a595294dd34b84c83a2d434b98fb116e2ebc8b2bc444740ce090816218ea61da172e30db5e78a58ef495812c287e3cfab7bffada0d6f2fb3c153f1a21707923ae7ec862d44d357776803336566c3bebc9f53177a3a8825478eafb32a61bc04d82994708725e0ccf5d76dcac946f36895402e84856b3e25567156040510fb299b88c45713175c54fb3d54aa6d383c423807778a92b7d9bc8fa347923749d18c96b20cea608b6380b57c35b4408f724046f6f65fc0d71e237c39376e1ec6dfc6a2ae83ba70d25855c10e6a8f425951c52fac7758353e2068e5cb4b6ea066491e834a47f8a5cfbd6ca91c832fe4f77b3b3140a6c1c70055d52f0aa67e7d3ba18e5bfb09f738141a611002ff9e34188d540ac42f48ee06f6925cbf3cca5ca033c4fe089650a2b86a8350367e9cfbd07fac9667c0171f54311cd5b371576790e51a1fddbec64f8f559cc08b1c0ae5113bb0c532742d90c1a266bd7eaa4b1d06693ff12d6e66c51bb1d12dfaeb70bc56d5870fb5ce4b040f86d7725ae53b18c1b12a84f7e3a2e7d748e8a899fb917987518c6dbbb83e3b62b31b0facd3515cf2e18b4e49218ef48d97df114971b298a6c4af231a432d4ac295d0d1947e09ccf41ab104e5435e7dddc0a6815b636a31be9a0d9cee2f22c745f05f384bd703fbf4bbcfeadf177abf4ca4524f38a681e5436a06abf9ca70c7569a7bcb8337b0b0c280b5f790ebe1258bea9c1da58c65c13991efc1ef8f7c75ef28affa340d84b33398790a9a77d30b0ea35613b39b1b7d8667fd7299e2ff38de468f625df1485ee3b2759f7e27ed707f5807342bad0935ed42609849d7a9d11addf8a92df7933ec44e86ac7f24d55a55284fbc4e4824a2b4f8bcb146d08d7d6d3f551ce1b494d7c0fbd6e82ba4496f3eb2812c986f3e2e627240a9102089725057c1e5dcaa3bcc5efdd6ba7e8a496f609aca3dd82816552c669c255283f9372be7d8f12b044f8c41180aac612245945a4467fa806892d55ff425adbbe92bc892698a32d39d7c23303ef65c980c608b5ac07ee60ed2b4e028a5565f5aa3ecd1e15787c23716697d53603f72738d5ca88c5d8280c3d8af9e83c18be420bb87db4b82a98d3af42f9191d4023eb22f428def2ee99d04d1497cb8205b67c9ca893f7afba077bae5fc11cfeb53d882763f2eb6731bab373923a63dda3ee1c1b6207e0ad0884290333dfae3f80e85cc50a241c73d7d99998e9b14c3e52e660edfe594e1ddcef04402e8fb01efff9c00d9a6ffc955e219fe9c92cbe87865f7a25ac68fa2d360c584c33fa3e40ce91d021465610b85b5f1a98e6908a17c5e138f2dd7da2769bad8789eed99828e8f23952bab7e9ead5fa9bac781fecc93de7927544736fd5c57f1da32be31b85657c313cd02104e1b889426bf4c8e9daa741278ae3966ea673cd3fa164ea7cc947b34f86c92084043ae846aecfbb15535a9b21e27fcda9a21bd821072135554e3015d5a12d1c7f2fe74dcef63fe99c947b55a4253add3668bab2d356d58909b7b0784c0759dbf1036645c5d673edb45245f5e78407978b63d5c25ada76b176dcff53e76801d7c2784d4687561f32e7a32175c0fc77227b3ab0a4054462d042931897530502c85f0b976fe3e3fd5488853b20dbd27d0d736e9f44fe6224b9610af05c462f08d328cefa4bf8530250f5a4d3fa7f58f5a48db45cd68d0dd53a2c66758a20184cf226565ce558e60f0af982b02672f8ab14333349a5e5a5dcea61a09f93addea3858fea4e49c84f5d8269a2fe52f072d66240e7d30b7345c841a135271c07e6a142ad1ef1955e29469d3ad3d952ca9055696dd825253e4a0e4822bf3119f1df2404ff9bfa39568a52fadf98ac6d5a4653862d91b995ab166fa9de73478f7e339941e036b621f7d773a5413471d6e41a68c02ed89a4882bfade2b10e399f4515470ef43930a911609911f8b66bc060ebb186cdc4c1aa3cb573d696b0f48a655f8877f68f678bbf467ec872724181d6f983682389fc8a61a7525bcd61ab37930e6eeaac82b7adaa145e2a0bf67e235a657949708f0640ec802a1741590a505e4a109ba857824e00f8f675ae6bc8a0f32aaec0f38398c33c8f53bb3cd53bf697ece4372f8f252ab4b314769f1393aabb2675f44c05dbd279732824d49e77f3df8841de18a30a9bc321ae43c712dbb9f08b457dd3e3f13244ae03da16acd6d3e861efae625478a89020655f0de72ac174a50834db564d4e60bef51e28954a938c64a6ee290523337153aa4d6cfaa00826d2aae1b57e3ab857e10cf2b497597ef9395fe6afb3d74b21c5d44281f756e018539ce8b7f4bc663db1eac9b976da2f994b193a30bde0394b7648b55ad9bde958ec5bf89eab516d4418451d8cbca637c1d6dfdef61712e76aa7f12151d5717ba1af71c4754136563ff2667bb984a80a51ee9112587cb77ed6fac8f4263fce637adcab9f315d6beefe509f8d34ae9c42c12dd42067584c4a96f6c15fe590bd8616983abbf453ee038f385a126dcb71919dd7143a8c27186e1c6d29d36c1039a8f008088e03fe7b97fd7f285a0817ca746438e0949dcfe49fc67ae967d13d1d1aa37c2e410bb95609c7ba0586c8fccdcca933b1a85ec97d1aff670004f71232bedbd192ba5e5a681867470c4e146221bee322a5f458a2bea1316d3f4be26efbcdeb4b1062e58f2fa23b144cfdda55aad3ed7142653c7948b6d854abb8d1201e9a4de07b8985fc194e58ea08b4c8528adcd73ae6bcf5493b7b8ae1f663ace587a87d5a341828612bf82605ce6cca9253057a8096f396bdacefb56f9a452849f0ac652738b5b3135ae13af532dac7d9d5307f158d844bd3664865724aa9907d2ccaf4cae78e056ee78815cbcdccfc38b71e0c648b1fd9f710a15d799e237c344d53923d3941e73f924b75de975ead5b536d632338fe83a8d02a4b7fa9a6f1a5df9de85c88b944581294609c880ecb5eb45de087524d896486c200ad68f5c45e43894d6e84493bed02602ab075c8dca1e57e3932740c25a9401b5bbc1bf524f4885f77a501bc3c313666fdebe7497a2b55031563810b35f33503cdbeb46de12c0482c70b07b5ca3c4e2aa21be75c33a23e73c03379c434dc8bff54dc40b0a34f476d0fd1de0422ae6edacc8a729ed2443315336b208ceafa68a229592e42f49501cf03fcf04ed2ab60cf7c31bf4d4fb5a8d7b8969ddfa8a725eb9d32827446c141170bec2b0dfb5c0a6e00cf83b856ae71b5ce46dfafdc12f94a7f8f3d1bf1eb769f52f43238ed411a97e55625ddc208affbae8ade42829c82cf4f62423830db9ca4091fffe3d282c578552649a34cbfeef3d58e020978137a44fefdb9083186dfd712301431b78095a0997f0764f3ef29f138ffb322c8e187c260c90a3ef7da5638e8d961d6a6cb1867a86d3eb23419e101e18bbf128c7a3492e8447533b7586a81e52366bdf2c376a57847b8a44f7b55eaeee6ab2f06596a87ccad4a60881bcf4b4b5d5f0de85593b643c0c4fe1771a0cb5bb0402fae0f1a2dd811d6495676ad718b73d4b86fc79ce074aa9924829ceb4dfd4e3ab70fdbd94b5ad1d11ca9e582dc215577056373ed91ccd6472b3ce02dffa8817e66205b179f37bdda376d25d6bbcc83a15ad757bb7843aa03d2f7193d8d707ccf4de1f5c8694aa212219752addd55cbb412c05118c30555ca7ea820bf3440d1dae3332947a1cfc22e366d1ad120b906274883d7769983eab6afea2ec0672a2ed25b2b3390c017566e52a0ebc59e6cebb89918d54f75d4094b943e7725468034d2ecfeb68228060bad59a4deaa40843d0cfe0a1e58855113bb7c5965254b82cf3997924d0a8b1711b1e1e5b28343168f64fa9bdf8e5158f33c91112f61ba782a4f97c5456c9c8756adf53a7d919ad90654a1c035d8686f834750302added0fb7b29a3f4f43f4dec29bedcff3139cbdffe391ad64b48eb1691be659e4e4dab266b7221a2c49e42d8ab06ab6d16efee2a0e0bab140aa34b53f70c808f3966f1a171bdc789e23ca0246328dcb1680c765fe262048b869c56f381bb7ded54e1486c0a3660d990f4bf0e5b4eec4cc0c3abf4edab6346cb531194c27de0e316d9d0a823db00e20e2fb99c2b5383213518d0cf604ae8f69d2921b442b729cc78579dd242314da99f01df55a45dadcc87e4b216aa0d817e60673c9807a75185e52a70f04ab8ea28cad805c37fae5417f89af44d4a5728c187c74ea736f21681fa7f93dd9bcab9b510febf2c4b5c64cbedb6b59b77a8816728dfbaeea423bb7735ae1fba08964a343ef9b5d36dc7f8cba10c8ae69bbddc4e524df73c940f762a2d39ce7ff235425942f2007b4e08f2002018f720e0339bfa2704a9d74798b13c6fda733d965666ec5592d1d6dae7af6efe5c87cf48d40858937b1ecde3445ab2c1ba1e87e1c2f3ce696baf3efb30ecbd9dbfab121a142ebfb4f09f343f37e8c5c0f40408a339cc3e4f4d34742d695dfc037744ba1a794abb67954d3a6509157a3aaf293c886b58cfe9bed8a3dacda2a2ce41f95e72e46baf65ca666f61bb548afe8f92e1c4ada258f46178a4591015678fc542d412f7ed323d2629c127890ad9c2151261c4869f59db9648e09c25bd5ad8cfde27ea4ef22666ae0f30a4d25c3ea1780a6c3eb2d94d0f48c1a61701707e57405e7e9f448452d0a48af07013fe04d6fa62fa5fd54139d95217734ff4e596f2ac975bbfb8fda29f7e6f211eb165480e44fde387d4833f89c7162c1bda3265a5271946c5392921861ad5d9e5b672afe4778301d7a8a8d8a03ca1c99d73b2ee43281c0b88ca4292a5ea29a0e2377007fc04707365740563020003c54f16cef0fd4185f35dc6784047913c89883f72b68aa78c16f144624430909da01633eb2b4b13eccc2b7a7ac5ef3b13505cea54e1d390944b5680e6860184e35111675dce504784f4ae8121dbd1f76df3d55ef722f3f73b5b7723efe2fd34b107fc0470736574072103652ba5800d63722adef5232d31ccc12403055de720f0155fc47bba5750ccedd400 \ No newline at end of file diff --git a/examples/test_vector/raw_blind/blinded_signed.hex b/examples/test_vector/raw_blind/blinded_signed.hex index 3fd577c8..d05b88f8 100644 --- a/examples/test_vector/raw_blind/blinded_signed.hex +++ b/examples/test_vector/raw_blind/blinded_signed.hex @@ -1 +1 @@ -70736574ff01020402000000010401020105010401fb04020000000001017a0bab8c49f1fce77440be124c72ce22bb23b58c6f52baf4cdde1f656056cd6b96440980610bc88e4ab656c2e5ff6fe6c6a39967a1c0d386682240c5ff039148dc335d03b636cc4beba2967c418a9443e161cd0ac77bec5e44c4bf98e72fc28857abca331600142d2186719dc0c245e7b4a30f17834f371ca7377c22020334c307ad8142e7c8a6bf1ad3552b12fbb860885ea7f2d76c1f49f93a7c4bbbe7473044022040d1802d6e10da4c27f05eff807550e614b3d2fa20c663dbf1ebf162d3952689022001f477c953b7c543bce877e3297fccb00ef5dba21d427e79c8bfb8522713309801010e20cbbe4671915035276d8df41a7ef0b6a36dd101de48a4076046fdba3b0bec20ae010f04000000000001017a0b90df52169792d13db9b7d074d091aaa3e83aff261b1cc19d291441b62e7a03190899a91403ca5cd8bded09945bc99c2f980fd27601cada66833a5f4bc108baf63902e8bed2778bf381d17241be029f228664c7d1522ced55379e275b83fe805b370216001403bb7619d51d2af2c5538d3908ead081a7ef2b2b220203df8f51c053ba0dfb443cce9793b6dc3339ffb0ce97af4792dade3aae1eb890f6473044022017c696503f5e1539fe5cb8dd05f793bd3b6e39f193028a7299a80c94c817a02d022007889009088f46cd9d9f4d137815704170410f53d503b68c1e020292a85b93fa01010e20cbbe4671915035276d8df41a7ef0b6a36dd101de48a4076046fdba3b0bec20ae010f04010000000007fc04707365740121089f9677efff5962164a434b0bffe53d90c271deda3eaf30c1d7a55105d24b874707fc047073657403210be6c538eee2e29d44c66a3e66fc8165afa4081557031826a070703cb69faf24380104220020c731ad44c00a2928d508ad82b05868cb42733a5b0d0b208f483307ce8c328d9307fc047073657404fd4e10603300000000000000015bee4d0045b0884354b05d0285abb287ee8e539e8146b92dceaaee6fc01af1a3730cece4c77caefdcfcea1073197ffb8b3ded97d0dda6f49752b31f23e196378a3da2128a8c45ecb7eb1c32f0c0dfa1ce7bc348e799f66d547476e976baece7445790064b34b1526c88cf54928acc906ec0925327d797d36d0db6a43633d7f963ec9b4123a5ea31b655882329afe2108d123f76857fd3ce344fcd651b3d3066aa506625c9309acead85fb6c8a7d977db5dd6cb6e2f99fb3535746258d42d95dd2103bbaf5d45c8a2dfaa2301eba08763bac8ab3b59bd0082a457bc0cb257c43ea6354348e73d8dee101864068f0e8e30e6711f1597d7b529a57e95fc0df813ea160f5f5152f341087868a680c1bbc4b2a427d18cf8f12cbc4304dd3b1ea4c916467ae48b3b53062ea046161170fbe6ca07462cf3e5534d638c91fe6919318c4b2e98ce0ebcb245680d6395ba746fbf510a9a36ad8d933b023eae39973a39162178148a897b5174940db46e4be54794cea11fafbed48b42eed27f9915cfc50c958e88bac551ab1c9bfa03653e558cf87a99ff13440f4808e27fb42ff3cbac9fe10d1de07dad4807c9f945784163214c739a9eed8bb2e7da6e1fdfa4aba5d5157787d0000b220145572d3d9253cde5c1132370c1849847633287660b429f20cf1f72e4ad6ae59154c3b8526fc5d30523ba962a25577427988d326e207c97c81b479540b1c63aed0a4b1dad9279879740b2f6a0bfc37aea8c81b3b35b630dba8d955afbba756b8ce9d2a9802939972c5f70efdee8778a98360eef15faf77e38627fcb4f98569d68ebad3bb667e5db46eb7f4214846e651224673dc998c55bdd9e0a1629497a75b76160865c7ac3af874bc45a42269508f183d2458835b1734791094122f75398da2bb7919c67221ee42242c298d744fcb920726b84bcb78d7eafc9e0f61a02de87ffc5c674390a33d722b50dc35bbc6788fe0fd24be7a9e358113a4e65b49655767b8f3c3bb86cd5a56c79f9148945af63492dffde82d682eca4787f203e49790650395c925e6eb68bbb3adda25bb784365c0b3e241177ca7de58252b8c79c5a865d1030f3bfd4d312bdf83bd28241389085433c34d747f9f45a0a636e700805e619a19739b15077d44d5e8969a37481896acebe7f350449c69b50376b7cf36e906d8a03aa7221de67c7fc4c5408b55e2562f7b783918004d93b284c0a1c3d596c7c18aef5cb77ad09172bfa888f5dceabf57f708f5ab61b1b4159742d3d35332e9942958ea7f39fd35cff66e84ea0ce3b38a85eb80dcc1201146fc3854cb40353a078f5435fe2becfa383b3a62564645250cf7feccff5414581e747166625477c70f5b0f579bd578e03e6b8ff8c3f0e8a82566199ff542b239f2999103cbb61602bc2f346702204e50c9ce7b85f3b8e144227ca8b9766cdbd498191c385e3a4f024c9396763eacdfe41b706fb23d4f065dbaa43d323edf1811950c71d4475a3e0913d3851be4e921cc933bb06b0aa20524267b0e9847b6de3883ab8c5be1eac17b06c946f19dc2244901890cc290f2e66147f7c47a4a29349555ca020e684ccba5f8a6f1be54e356654d3e8678c591633e11d9ee772940d92f07ab83228c0d8840cb9aae514c03358e973a2ef319a39a3ce819efc00e5a493fd582be164c1460f70fb2e103f09a2939f779377275be736ccd41f847133b3d400477582419fbd2d7ff328d88256cfadd750ed7a3c6657e332f635f0a90602b24135e705d1530531b7b738e686d83accd74874e160a5716191447f832d2f899476ec9c53204fc4ade5b75cacdc869b4088e009e12d85beaa3450889de0c86315755ec7744be592f058fafe62f9a89875bd2781d5d6928c8475f555e77eeb6e688bd8d3bee0a54fa1cb29c1b6b438d3f70ee4ac83fcb6f482575997e3a69240c6731b517d8241cd39dba6b02a9e3c94ff2470c61c693d32b1c7d22ba38f0da21d92150115d580249380500109215a05baa63474f773892b1870005e76a68853e6a8cd9f74ab3f41cf0730e702ce94c420dbf66a63f342d927923d7d25ca3c3823b6c352ae2ca127bf811c023205632ddb8f9191c2f3384a61038d1c4d32f808cbaea81d58f0aebc7c89bcb5b98f92849f4fec19cffc78173e601eb412aad24eacd74d17cce3a9ee76670367ed87c2da3db5e4ab01d4d9626d0ae00da7dbf6b8103d5994cf66ca56bb9aab9eabee2b14ef798d3fa5ed1dc16bb500a006c3320941c4c7f6f80c8b1bf79131a5e11ef38db7c42d4c4939711184ea414e2ec0cf5bdce3d7d0d72dc883b2595e5f0fe4c14cddaed61108c90c74b43cbf719bcf7a934bee760ab33f50cedfe3ce61dda3e4bee1ab4dc687f988cfceb207152f7a98c0fa3a114d2d6881034aeba877bbcc368ce591707da45becc48318f0558b3ff65d677578df9fd9e9a18d0cb08f2f5cd4f44925259225b1c4c5ed84ef30d136e7c66251329a223a1db0b485f1c634981f8860aec1f3dbda9442e5438f6fb09c7e1ab43e2b757911834df8502ce35e7be947771f7416f7ea97d26dbad7221614175e6b86f1a323e26c4f469236d1b1bf6ef28823234c73b275c5b0ff39e8c04d9dd8ff7f6a57214d803aa13dbf581295b92ce2b8a9c0e3fa8e4fe4e74c4bc2198fd010cf84681cf5f3fc9df1638c403006478b1cd4204ef3b7a6093116021118a839bd3ac270783e67096457a86d63654e268821ee742241ab5f7e91972da0a94f679b4c093d3f428d5876edf51459331df084f2fa245e3648e0cac904a82a7d323b965a39683ec0b2721105683e67d65fe10b8d41d0dfcd5c31756408c94cf425ae67f95ecac45391516875870386b675e24c462b1f7634f758723e6245da6a39da69cc2390374eb89c6c662d94eeb2f1835e233610072936be248e6a3ff87f9950c2eb2f88568c31dd30d1f0c0396a42f6be2505bf616c63f504dad5312fee2f083b406fa05cf3c998ba24237402681f0ec393de4650ddce3389d4c1541d4705d8f50c2c6d4864934394fba0c40df495fe3a5bf58a5498c1e63b5ee5f9a4b53dbd913252d4808f5bf5fc3c6dd74c86c974fc9e5afb1a7ee3d88738ab1fe9194881cb00197a31d648ae2448db872528d5f7c366188d9d98ea94497cb78ffacb5f6e8a2c8520d8d196fe0ed13e2b2a5a08dc45d8ff58a8c5d3bcbdc5d80c798acd0eabf146459e79db12c2a43c55d14b2dd608475c606fd4f943ae7cf62131691768f710fd718fda3967146daa8d4f34a3b8fe8084f4f3865e9e0cc1a0b0a799fceafd1b74f09f524822179ce38cf0f2c4c8623a3e3ab2cc20f5dccdadffacee62c120657e3d85fea93fab645b5fcdb812b130afbbd5b19e86aee66011b520b0affd84af4bf67a28b309cad66cec25a5de06390a4f2a5af47d59c006010a8ffd214149bbe47bf847fa94c2113723c9476c2e6dd84411bca16dc7bb096aaa3e9a9be27811b52838c78d16cbd89cad379bcc0cd966dadfa428f9d4d8bf133f7d21022ae3f966dbc1409c6d57cc46ff4434fd90d79b6c9e68ed3795ea6191a7e309783badaf8db9fbccbea905ff9d423370810f02add38ad3088cf3393e7c6d585b76fd78c67766fff03ff54c01228c6737da667147a8b5e722370a24db8c0165e34888920d70fb1356eb731d0024676444e2d37860eaaed9790f99069e622afe6ff12d516812022c46420006253248eb292908ab8658cd874ef05bd568547535fd54c1f0b5b816e4d90a1bd55670b96691e7633a2fa45be6a29cf7bbbcf9e5debb4b7a739b36b6b326b719a12cd0f5e3557a2fd94023d8c633fb697b85080a39734013b4ed9a7500aa8093edfc3810d4c890e608951e57af8447349cdf45a076449241a047085702dc3e44814390ceddc878791ab3a6503f48f48af25fe5cddf61e7870ce80e32e5f22d5725bfde4f319c2db7cf3ba3b9952202cd24210ab8d47fcdaa9ad5e2a9d2c7be1ed6b67cbc1a28ebe565ed0337c09c97d2d9608d97905c7201be7d4bac785d64caf783cb3ebff817bc5ff0448899537ce6911c9803744d06ae97e6d3aae037697986cb20061892ae72e05968e9bc54153bd745012af719fe7fd4b917689a6cbb94a9bc8cce51d234ffce7dca804e2b2759f473885855983b7b290806884fc66e724fa848af2de3164c611c630e5bea712cdd9a9943ca3ad55994e5587c5953f415171bdef3c42783b809bc5526a88aae66be626d73394a607ca32256198dbc026d9e09e9659ddb66736215dedee0cf69a24490a53b2c678e6caa2aaef10a4610f802fc5eccf558629554d6388465584514d3dd49fc00fb267c39bb746f76ad3cccabcc3cc882815bd9466d593270a5c9a04945dea7ad06ddb73e66b90270e859a109d52251d911e7177e07295ac9788ce970c1b718fb0c2f327f44fd0cef3cb90071ec85e958e6ae60bd134ae307720cdb10be5a0af8c051295df905447b46206b5e04d775b83e11c348458b1bb310ae25c54e8ed1488a95b2a576002198c80e0e69d14fb7bffcd89935faa6e3f9aed61e0492bb2bc334e389bd559806eff9e16643ddc4372ca83790a99bd4f5b042779ef7e3039858881c8ce0041d43ed6b1f42f18007d046fd6f65907cef73fd5e6cd514c4fa5ebb872b140d0b2ad43c58f2f2216522e78a19828baa34ba56d71414ae869a13cb708762565d754f0754561adbd9145d232034229d2840ef0c96f7af4b232c5e11ae9d018b87177a506b66571affdeb693e170dd12640e86fd430b64509d02694c52a54f23ea96e39be92b65c1abcb262a71d6e884183d4bc6cac8c79f6e94b51abe484794a42a8e1be721cd59383bdbf327a864b2cf27566f1270d82ab6e8b3b934e953b7d48ec4697172e0160b8435e8186a7ea685dd61402b0bef09137fc52e19ecb53674a1c0af17fbb0efc2b4d69572b32600fdfc3c85c79ccb2685c665aef16748b7f15862f435afaeef00f3f927cd3a60c22f137e9cb2c38a9652cee570a76351871ebc9b6fc720b9117b1306e8afb298e3a1d0d4b2c5ad5a21e9de4c0938a98daa35caa711bd6d3312a7e941b060c4a1ec211c31e53da263995d3be74a3ca5a970d3a663245a5d8eace336d9ee847619bb337e777b961805e808f7cfd8f09b93b6ce6c277396e6cf0a6153fb11625f421b02055dc53a0bb24786f4a74211bfdf44193e48b2c15c7c85acd3f4f0bd26644f9dc62653e366178645899dc06d191c785831b98de593519c0ac5849897a01b4f8c7fd559edce1c878bdb9dd091546c64225fa81b1c7dcd6fe72c8131bb160043976a5e891236d3552598c0c4fc734d1cc752c10306dfc8391f6d658ab8b7a1f350e1900edda29775ac8a531032bac968f6981889f13cab07f49c864c3ef3ff23555c170ee9730912465e6bb3b7508e11ba27001d9dc0da8b34954a7c46a2d0b0b75e73ad66278c8acbed3249936a6c76fe975954f7889bbaae5f73747e3ed02811b015beab9d1515e396d37b2a116b3cd8863517b88ee91a854e4740304f7be41123692181a8ae22090956ba619fb948d3f08108da17ac2484d3dd5795b1c716cb5ed3fc08b6449fec814018cd883b02256afadd1f35a04d9d43f661be624c0d59d0d397e8ad6917344203843495162217e79bade11ca32c0a6918350520e6c3f31f866b89e3497b518cdc056e760813ebea7fbf343db50ca2450d5b7a1c5f430859e2040ecfa70cb0c3e863a756ef6ae2e26c68b543d35beb44513f8295872df5b4062c9b80742ca7a9c2ec36a1d9bc936c7fa7328240a2db54463ca04a40dc0c9afe4d570012259c8c436d322483b17a705d60a283e0ea7545110e898ba43ac6130aebde014d237482307ff28f385fce8530814a3b3507fc047073657405630200039d46edc3d830d852edbdf28cbc023dd1666cc4a806ec9d4acb2c97865280698d61fb6b2a073be4ce75cf8193fa9b3d677146575a812873ae7eaa7b08110cb88904273dd65af35115dd116092a56ab45fb57178d8c5ed4cf99474ff760f6e987d07fc0470736574072103701e53a6d0b960398abf678382a4d17c5c153d1a2c8ffb76b302058ce915bb0d0007fc047073657401210821b4e7599b1b4faf29b521f1c442dfb0a893499d374c19db939c0c9a3b9798c707fc047073657403210b8529a893bd81e38743e8e3015095077f6e244a064d64708963c6af5024b6aeb3010422002058037c2d81d3122185c8704d4276e2629122c95b8ea68575c451628d37eea84507fc047073657404fd4e1060330000000000000001ddf2f500cf45e30e3911bb51a7ff633c1e329508e42d9aa49fa8248fa4d293b87005db08b17a472580ae2cdd53c40b2a16af885d6dfa3d5b3410d389b045e6c12405c635511ccf008390856f4c6d0ca472148d2969fd39e1307bfbb8f8268ce92398248f08df7268bbe23e13ac3801ad075376bbe9684db9b41d7b1148fa65a129e1d25193ad973ec7af631a0a30c5659409b0d00e6fe44c2c507d52afbee8059aee7650bee9d47936838e77f00cfec9de3b9efe72cdeefd80a19a9c8ddcd6cd9009ec96800f9fcd709f1432b5715466d601b5ed10b0dfbd09b954b109232fb5a24036b887d26bab43da7eaa303e7c8e9d02950610aba09f343a65a7cb4550d6f6e5c0eeb9410b68f85cc3b05b9340e2e9c94a473f2001f5aea7e875d29e8e0aa99c09afec4a5455258c803e55b89cf6e89796a6f3f9fe11ee05ec415c6ac08e0f1adf9dad681f8121f82e3a9402a2fe13a016dc10d4a605578317be0d9d3e02b0989903002bd35ec4970701da6eb6f9fd5e6cefad137dceffaad968d5ce522e77c76e665529f70c9eb805a240834f4c8c795912c37e7efeb73d4bab709aafb66bd645cf0addefdd83d185c1b4465ee16344575eb2aa3acb057c37d7c22cd03adc6701f03d4cfa20ca94458b3b87e3fb7de8fed28a755bcaccbd348dbc7f5aacbb25d19437d87cb48b88fc714f059b328c374fb2695a26537330fae42d3fcff40b07054be10508fa78a9173315506119973a9158828276edc6e8ac771476d7479d07ba73e9c5b58d61367d24435a1062dfa376546e843b34829103168db63b708a13894813a442f889a423054160b85a2584d36951136bafc490056f1c03c44580e2c7a12b170e5c7a3917720bbbb21e5da616649b554b7ff57dc84dc3935271a8aa6fb218becde208d83e76bb6197f5f4f729f3c57b4280c388bf4945206fa769b672ebd47ef2d0f777fc9dfb031cf7c333c6159a75a5b33ebc6c4683ef140a144a5ab15b2b6b72ba14ee7595679a0f7873a75b9a79e03676ae94eaf9ea8d3532460f3075f40c6b9848a183fe46651caeacd51551f308eab6ba8ac27b93865f5dea0fcfe1d7dbb745695dcf187a5955414763c88ec01d299f03cdaec48eba946c7ff6031f28a5e108651401b5447c0d21c449b387765a621c057eea7d494302222e3d1ff6ee9f8a0580671d9fe3ecc310e84b554e5c823d81b8027075f749b2dc8a6bc5a99fed4a0fc46fae59cc2aa9f1471ca2b0d9fafa56927fce0f1df92647ff5aaa083bfcb7078bd8ee142448d4e1f3dda670ad93feb21028a57ee9a8ae8880df5b3276e078555d868be0d8843b495e082d743328620f36f7e106733bcefac15076826cafce271caf1520cc8746948e71ea73eef5de770ecf5e0fe075f04d6c9cef1cc1f262e69fcfc89862877ffd520e25405d9d07efec82386640d97147e4a6df66bb1fa1f20dcc2ee1fd6364bc2024c0a4a2ec00b84616231c02aef16147df509cb830b9fb20111c60613d41169a24ea67c03cea48e1905b00eba8a61e967b9aa5b6e1264b0f3e2c051e47f54f45c6fb78b46b9993c7d223d51036cb77f5e31a4b30892e8fd7ae7028322d6402f60712f712f84443de083767c38ae88a38fd4e4bbec58015f4e49e36ecbde94f23d0061edfff0e9eb62b67327249d728c278f923748e4c1e225791c740abf9493198f073a6cefffba00d23715a14967a72cc7aebb81ecc6e8bc88ae63a47507296a573c415d0163219f3b20974ba3a32572d29a479b88b89c241e63e640bbb93e2da0b73024ff03516ee3ecfbd84348372cfb574817ca878172a779ff131492b86e64c1b7054cc5fdb999df4a9578bbdd6a6a2a798f053f4c7456173cb8cb9b61735e650d0394ea9effbef615629c1f393949095982345bfc02b9a3b3ec64d9173bb1285587048fca8c740b6d2265d3e727069fcb90282c78f1049ed7925113279474d0d873045851b397a8c26036c83906dccd0eabe98f7d6854d9abc2e6ff12d84c2840affa371cc2dc624fbce873f38570dc9eff33f5e200791bc052307f5c718d47fc2a205add3fd9de2a81cb452a0a7b4a08bc133e9816f6ba852735b813a1b906d4dbd1ac8a968a8adfb6aded0d3fb87d80132a4b45ad39274bb72df20d648a26aca4beaafb971e13094b6d6525bd418b91320964bd90d3a98fb32d69222aaef2ea95c6b84b6b6aaeca3f6789944fc7ef17d218abc7667ddff798b74a0d5fbcc33d22d028d207f82286fd777ea1e281d7eb88b665e29fcda067bf9ef82a190c920e260cbc44d394b78e0439bcaa6371f8717ad82e02015f21e5dc273de338102539bc924d5a3f897eb788e0f3cbb6e8a34590ff5370bcb0f671ce28d6ac0adea17f9fda49c784ae84464991fc71a31d320d62c4199e4f4e38f390ffbcc7f15922c3325451371bebfaed8f8a7d3eead71c65878a705a6163ef649bdc6ae7b81110a2cc9576da6b0188337160cd518fb30fd5b0c165ac3de81002490f36d29f3bfefa2b4796c070c6d7d971d18bb5a573cd48cb3c64dec5bbbd7f2f6f60bff3db4833bb64b426c6715021997350aab1751f0d5382087ec133c2c43342b31eca32a4c17db14148fb48f9b7a103b2c0bfc0dc95ffe097bd8f2213a3f7a43c994599b05dc35d469fdc025e23e483039f271d948972417153c849fa8dbf374693dabd59d398732020e90d8f443ba45a00b430168561de21db76b9b714ca8260fdc4ff1a5713e69ed7296f5a5a9d192474bc6e67788d6a44d46b69ac97d0b34b2b08aa79d5ee7e910d99221e1e7f6383628b5383cec4341e5c3f18ec3361b2f2ee5935ed40919a4f8892bf3467803b720d29388b7cd47067eed9be7648fbbafcc7bebfc31a30d02f38b7d6be1579c751aabf679fa6891adf66da2257432c10d399a8d496d1aba381b64a5e3ec9a65cc8419151b638adea994c3590f77bf390152894b2784f7832d986ac51b20ba9719d85509acdedc0282f27065c87bf483fc74b55579ecc233fd6c51822ae03e46ecdb15acf0204b67852d525168f409d2a4309c5d9a14b35905b836091964ff4fec0aa91bbd7f39919eeaebbaf75c63337a4dcd5ae37cb60fa14bd78157ecef35ddb1cfdc366eecd48aebb0f5b395e4161c158c46870fc89f8f5918aabf0577c914511cac7b189384eaddf7f03cc6706a9abf219ff1b293cc9fa2cac88b65af62f0493e30736b596c119149af07e840a43dba8d97455a7a95368395488304626d3b888069a0099c435cc11e5981412f79153577c9115a1812b1c4a9ea42bbf11b40fdf930bcc37e6a6c50a7e3d06bfe7043adb32244ae359993caad00eea5f1de90355326e921145add1020ef3c2cbcbd102e7b9a150ff9672697d31f86572843269978cbc4c3fe067417e84898587d4de009b33094c8e8102c07facbda62a2996e083d0618fd9651e17f0fc025a946e7c28d93e18675ba69d8811dd06a2cc1aae28de5a6af30f305cfd8a090832483e4ff7c974d47ac96d2f3f7baec94f965a116c2734f87f468ec33cee1a58dd2ccdbc8f6a0f2a50a739aadf4007c7a529844cd1ce5efdd42eb28a0f5f04fde00dea586e4b8cdb8469b36940de19feefd342285c29298afcd3ddc368f6365e9ee255f8c2b6f70c1bafafe10720402a668ac3a2cb8ee75cb7004455cb4221486c3dee64f8f25f1c8b1411437cf6ba70afac5182b21f0efc1b5c71dd59f71796d2719741b6d5c757d824cdfd2d9459569427951d6974d94bea1fbeb0e1a23ef88774b270a8bca65f01a00299258847ddce8af8a7626c802b29dd01d1dd9d2a7243b334c29c0943e11ddbfe82cdfbd506e81fab8775a1d3c4f6c0744e1086763ad84e8f51d601e24cd6fcba1409abbb1c6b5c9bb9eab8ca30282801448f86cd5d8ec187866f1ba738863f3995bf4084ebe8f41dc1ffe0cd47d5a95dc5fc0dde1559ba170316e085d0e385ecf8646bf787b5287960f07bff9d3d990b3be4b29f008de18ccb46dc2192d0fbbbb9e701d350aae205fcd2d7314112bdc393e2eeb0a96c5f2c767dea0b82e9549f46a270b2c69915711c144a7737e9003b1c1b8684e9f2abe66ad1678c32a0c6ce401ae2d7507ff32c8f6179433b94764a6e4ea0a363e9a03787502c67ec97724d78c1257499379ecc5cd006a13acbba05dc7f1310bc75b9ec6a09f4d95b2ec11952eb3dc3d2dfeb8678b10b5db162b44af56ada56f7e311d6c5ce46472d9ba2284126f8f579d59a9d3e81bb1b26a7ee59c3cca96252fd4ba8e009a213911619ab4184e83683969cc4c474e934f36e6ba4ea33d9e93e984f1603e259cb7f1a3824dd8764bbe30ae08166aca84e63615e59c31d2a968a0beccd40637db22b971d51a4c35ce83108d8975d758669bd83ff9602718a882b943f80745d95a2d5e07ad0acf8023e24589fd68988a350c0ad571470f8b9a906648895d312100cd18089465de942ae0c7c8bffb5d3705c729990721bb0497dddea6dabdd530c9ec90286cee5ba3e2b699eb2de55de8aa0012b38051862bf0a7a22d6cce4310dd8dc47c206d9eb7bf28f2a53afa8fd10836210c0c461e417be42d89ea659a76d5e3cba08daa885b7f0302c5df05c72f8257f60e2ad954891841e67d8b7184cfa47e51e9b36f6ed1400aa84c5058a1998d07709b8b46630d70c73552ada18713310dff4177e2143aada1038bae9a64e02870a7535598d766f447b4e25dbd009009cc0e3421067bd0cd10735469b308cfd7a094bbdaaef2e31c22dc6c1a6d4c7890020b5bd04ef649b56889b2031c1923a69002448dd5db1142384cf517b08096539cc537532f43afc33ca77beb2dfee921178ad51b04f10495365e60b4b7677880409716e0eaa3a1d649a871234f86787c2792bf1e04a635e3f22b8b3b1382be942605c3855a940cfa3825a2f8993312a512c81f92aea0fca95bd1bdb6b9774ef3f1fd15bfa1eae84ebb48bc9b55fb2141c55cd3188eeb5049b2e6f3360e60c5bb7d91c9028ebc9287b4b5541a4ca290288e08ca46f80eeabbf100f700c873d7e69dee7dc80b842004b2bb93f0bf533488028d1a1137371417d06785372ce942d4c6589cdb57514bde81960475c22393eb02a93b6560fc3e4fb6ba692dc362d38e33a41b7df222e9192fdc0e0499f110e681682e2b500c00947d62280482dde5e26010cf959fc717d0837c98634550376aaeb17c1c80e3c3245c36c68f56fc8be117ff84957a75e4aa4caddb38779f1c50086ad4863002127b6c8067f172aa78137908fff82b2297a53d6232c26a2e94bb25b7f9241013adeb36d1e437f2f6c0d983efdb78608e940390005d63c081eaef21d7f00ddf51a3fbbe6175be436a9b0b75f198c30efee2821ac5f088819eb96ba835999d0012e7a0c244268a658bc6b7845d10178283cb8add0b81405ccd64000c1835111511555eca14f7e3cc9274b45f817039ee62cfd95363cc66f5397f88822f790e0a86b6a69379dae77db24185394d9fc73880d39f6b3233dd8d3b912995b22905563ae8cb2b1f3491feffbbdf2c7d2e89dce1995d2429bb0a4c550860835aef589983d3170387971f8aec15c18450dbc9cd12f402589dfb17216e359072ceec8e9484f9b490a288dd4b268233c40ad23721961c390bae0a181c4cc8eb68eb4b2a5db6944042c6ef67550f9abf3b9084cfe8521b62d727416576a58591dc65f79f871958243ca4415d92d3e588c4205b4a3806d64224e94e8f04dbf7f75888246aae9f894bab1ea69d7e10b4f07e8cf2dcf70cc62571c737cb6b6c68b0e3fbe4b1931c8615a793fa3db0a45090458ff62ce8bf421907877e555cdb97d3709bbd8728c4432288861a56cbfeabbea5f225cd29e31d99eb788704a93696f5e81307fc047073657405630200035ed48216bc666598aac5498e9fe513a9e21eaf842d382767220cf98104bfd8866621efb63b2eed44028cdc9e2f64cc2447fe09f8d8a1eb3214272855b525d9ce24e6daee58effb4af28fcb0a4685d78d7995081b5cafd1cfe343aefc8e9cb23507fc0470736574072102b642f0e5b34746f2f6e3b511d037e16bc720292da4ea2fb31ec09f6fdbe777ce00010308f40100000000000007fc04707365740220230f4f5d4b7c6fa845806ee4f67713459e1b69e8e60fcee2e4940c7a0d5de1b20104000007fc0470736574012109a05049129b0d9e61c1bb87a9fa02c2435be35e3535082a772f65222f2e4a48cb07fc047073657403210baf4431fbb8f0227bfc0008368606a4b8f2bc1706e1a06cd4d83706217b74f5b90104220020cd4ed5f0db8c450e8b0be595b6410c1759c19f1f6926279095c83dade9862b6d07fc047073657404fd4e1060330000000000000001a4092701f9170991583ec8b5c9b5056ddaba7637f7d6733a57dc4990acba6d15e9eb5dca55528e179b98a9e09e05ba940b59558b768194ca046c22e12ea310ec05bcc795ea419277649d40b145e6f0accc31f2d7eb39b29b51d3ba3410536b9bb37bce9014d352b496b93161fc799b23939ee635f25c4cbd6605029722ac2bfed7d55fe4120c0cc880661ea3313d700e261ba973bea5df4dc4d8a05652d193c5edad01945862943a6756d4b0ddc93ad5a444ecb054bcfbbba3635aa752d9c4fe8f93fc56c8066b3fe344143d65328025f5184308f2016eae65df8b0f1818f59f5a9539eec9c9c94704ecac269b008ef25f67ab2b9ab4e903b1f2372d1d3988b86e5efa639f9f964599df8559622c8d11f6bc4f706c74e4a603a3798005e210f93d9e6b59f8ccac907dc9cff127c552c8c89981e1b91c817cd365422eb6bb0c7ef4ddddabd306b0c32a98464973dec30def4149f8e9f35de6840cbd0ce8a2f2b5dec15e3f3c27d0d2720159cabb3ff2f73b4571eb53ec735d7b0f27bf4d23cd8b0fba14d5921d464beb3fd4f2fcf844f76a7f7f129a3e7e1c4a6e4f07490f2cfbac4e6730148397c73720d35cc5a46fdb1e774e17f7b951887c1c72ae4cb25ae99bee652ebb2ffd9f4c9400ee0870b27a5dd8fdb8224aab6738399587b4513d3441e26b898b35f739d64047ce8de70347042fd18c3797b1de82cfe23521dc8e5c36e286c05d4f81508e282018cd8d263164512e6ab02a22b3d5d489e6074f9370e218a3adf8afd229659f5046749db9615541408739d4f0646a853b25f8e549e85708c368e45f3e1d20ab47a4ed647b820a360e4e351e4caf74810098f0df4bb74e0e69f2db3284c30d24a0d109d16c37509557ce15c81812bde78085f31cd7c93140fc43d6580abc7ca2adfe6354510fd8104c0f1ffe46d24f31bea808376ac27996fb992de15b30abf4df6f4d08860bec27a95bcee0df8f0a5bd7f72938ca9e917f39c5425bff826c4a84a1fd70cff87be2e8619e0d3b729f0aadc10d4b70d10c2c020a99d03424a595294dd34b84c83a2d434b98fb116e2ebc8b2bc444740ce090816218ea61da172e30db5e78a58ef495812c287e3cfab7bffada0d6f2fb3c153f1a225bfb46e7e9bae9b666e72c35597797927e1bf02d1488ba90948f07dc12f6d8b61bc04d82994708725e0ccf5d76dcac946f36895402e84856b3e25567156040510fb299b88c45713175c54fb3d54aa6d383c423807778a92b7d9bc8fa347923749d18c96b20cea608b6380b57c35b4408f724046f6f65fc0d71e237c39376e1e769cd0234473a261c76553c655de0e4aabb4fd44d0247e4ef08f48bbf13a8cd366491e834a47f8a5cfbd6ca91c832fe4f77b3b3140a6c1c70055d52f0aa67e7d3ba18e5bfb09f738141a611002ff9e34188d540ac42f48ee06f6925cbf3cca5ca033c4fe089650a2b86a8350367e9cfbd07fac9667c0171f54311cd5b37157678b3d6155f0bd12ce53f6599fbc5beabb1f2a5424eb3f52ca3c1e0779d9cbc5e106693ff12d6e66c51bb1d12dfaeb70bc56d5870fb5ce4b040f86d7725ae53b1844b07557feca4d0e4c55a9cb6b6164c4cd3fda89f2a7259a4cd7682de9d8541af2e18b4e49218ef48d97df114971b298a6c4af231a432d4ac295d0d1947e09ccf41ab104e5435e7dddc0a6815b636a31be9a0d9cee2f22c745f05f384bd703fbf4bbcfeadf177abf4ca4524f38a681e5436a06abf9ca70c7569a7bcb8337b0b0c280b5f790ebe1258bea9c1da58c65c13991efc1ef8f7c75ef28affa340d84b3db3f4f188b1c7f437b024dfa6207d5329a5a7a0a56018b1f96a1963961065e07e3b2759f7e27ed707f5807342bad0935ed42609849d7a9d11addf8a92df7933e353a9e86213db0a27285e432228cf2166d3fa2a7f6dcc4f1331303f8db6929a3c0fbd6e82ba4496f3eb2812c986f3e2e627240a9102089725057c1e5dcaa3bcc5efdd6ba7e8a496f609aca3dd82816552c669c255283f9372be7d8f12b044f8c41180aac612245945a4467fa806892d55ff425adbbe92bc892698a32d39d7c23be4ecf4b07d79970eb3db84ad3ce589bb8b134761a442f8ca4e2020a4a42912753603f72738d5ca88c5d8280c3d8af9e83c18be420bb87db4b82a98d3af42f9191d4023eb22f428def2ee99d04d1497cb8205b67c9ca893f7afba077bae5fc11cfeb53d882763f2eb6731bab373923a63dda3ee1c1b6207e0ad0884290333dfae3f80e85cc50a241c73d7d99998e9b14c3e52e660edfe594e1ddcef04402e8fbf9061a5e0b3441a1cea68cd7e067fb146f57f370cc94ef4f28f4f5dd36f45173e40ce91d021465610b85b5f1a98e6908a17c5e138f2dd7da2769bad8789eed99828e8f23952bab7e9ead5fa9bac781fecc93de7927544736fd5c57f1da32be31b85657c313cd02104e1b889426bf4c8e9daa741278ae3966ea673cd3fa164ea7cc947b34f86c92084043ae846aecfbb15535a9b21e27fcda9a21bd8210721355b4331d01e57227bf6572d9538e4998313c5b8bf6e2f3f7bdd7510283f20ebae59b7b0784c0759dbf1036645c5d673edb45245f5e78407978b63d5c25ada76b176dcff53e76801d7c2784d4687561f32e7a32175c0fc77227b3ab0a4054462d04446e9c77f30cc87a91dbcf27516c956dca6b93bb4315f2f0765981e7525a510410af05c462f08d328cefa4bf8530250f5a4d3fa7f58f5a48db45cd68d0dd53a2c66758a20184cf226565ce558e60f0af982b02672f8ab14333349a5e5a5dcea61a09f93addea3858fea4e49c84f5d8269a2fe52f072d66240e7d30b7345c841ac22c16ee979c0f980567f24bb4bc2997ded6fe345d1e95c1b5cdcf006eb17d492bf3119f1df2404ff9bfa39568a52fadf98ac6d5a4653862d91b995ab166fa9de73478f7e339941e036b621f7d773a5413471d6e41a68c02ed89a4882bfade2b10e399f4515470ef43930a911609911f8b66bc060ebb186cdc4c1aa3cb573d696b0f48a655f8877f68f678bbf467ec872724181d6f983682389fc8a61a7525bcd61ab37930e6eeaac82b7adaa145e2a0bf67e235a657949708f0640ec802a174b1bcd7ca384e09b6f0e811f553609e88c5e45252d0d9ecfa42ebb69b7c2d22bbbc6b33c79f3506806862d7600e62c51c4d909472add5eb08e2c5a8ca3d58901a49e77f3df8841de18a30a9bc321ae43c712dbb9f08b457dd3e3f13244ae03da16acd6d3e861efae625478a89020655f0de72ac174a50834db564d4e60bef51e28954a938c64a6ee290523337153aa4d6cfaa00826d2aae1b57e3ab857e10cf2b497597ef9395fe6afb3d74b21c5d44281f756e018539ce8b7f4bc663db1eac9b976da2f994b193a30bde0394b7648b55ad9bde958ec5bf89eab516d4418451d8cbca637c1d6dfdef61712e76aa7f12151d5717ba1af71c4754136563ff2667bb1603cda51baf8a575d4069262179828d54694382f6bb93b98ab9d53d29793a524ae9c42c12dd42067584c4a96f6c15fe590bd8616983abbf453ee038f385a1265f7856009646cdd6f409d9e1e7fd36e1cedda1137429964b71af9d438da0858e817ca746438e0949dcfe49fc67ae967d13d1d1aa37c2e410bb95609c7ba0586c8fccdcca933b1a85ec97d1aff670004f71232bedbd192ba5e5a681867470c4e146221bee322a5f458a2bea1316d3f4be26efbcdeb4b1062e58f2fa23b144cfdda55aad3ed7142653c7948b6d854abb8d1201e9a4de07b8985fc194e58ea08b4c8528adcd73ae6bcf5493b7b8ae1f663ace587a87d5a341828612bf82605ce6cc286ee0161631ba06d704d2f52e37e3dbe44fc40c4171446d0afe69cf8efac8657d9d5307f158d844bd3664865724aa9907d2ccaf4cae78e056ee78815cbcdccf4b11e181a1d2841b0146eda60d561762a7e3512dfd59fc133713e5c056cbde75d5b536d632338fe83a8d02a4b7fa9a6f1a5df9de85c88b944581294609c880ecb5eb45de087524d896486c200ad68f5c45e43894d6e84493bed02602ab075c8d1e5e5be012e4ce474423bdd21d8d6662e182a2ea7eb30f2604b468a25c417c15a2b55031563810b35f33503cdbeb46de12c0482c70b07b5ca3c4e2aa21be75c33a23e73c03379c434dc8bff54dc40b0a34f476d0fd1de0422ae6edacc8a729ed2443315336b208ceafa68a229592e42f49501cf03fcf04ed2ab60cf7c31bf4d498f10569eb3666501cb8ec6e22f1825b7e69f632c24180c3af0d658dccd1c5896ae71b5ce46dfafdc12f94a7f8f3d1bf1eb769f52f43238ed411a97e55625ddc208affbae8ade42829c82cf4f62423830db9ca4091fffe3d282c578552649a34cbfeef3d58e020978137a44fefdb9083186dfd712301431b78095a0997f0764f26e084ee5a6d1d7b24b3b0ae4100da91329f6e8a0a92f3fd94c8b53270b44b9d419e101e18bbf128c7a3492e8447533b7586a81e52366bdf2c376a57847b8a44f7b55eaeee6ab2f06596a87ccad4a60881bcf4b4b5d5f0de85593b643c0c4fe1771a0cb5bb0402fae0f1a2dd811d6495676ad718b73d4b86fc79ce074aa992487108dcb4d908f0da654a3e1b8dc28cc2fe35762afddf2c93fc7a0593ff7c7aabce02dffa8817e66205b179f37bdda376d25d6bbcc83a15ad757bb7843aa03d2f7193d8d707ccf4de1f5c8694aa212219752addd55cbb412c05118c30555ca7ea820bf3440d1dae3332947a1cfc22e366d1ad120b906274883d7769983eab6afe18a253fc6355f81f60eb54f6ef7a48ac185d7e61d6580852d4b98443ad304ab8e7725468034d2ecfeb68228060bad59a4deaa40843d0cfe0a1e58855113bb7c5965254b82cf3997924d0a8b1711b1e1e5b28343168f64fa9bdf8e5158f33c91112f61ba782a4f97c5456c9c8756adf53a7d919ad90654a1c035d8686f83475038580df22e4a72ea9f0cb73470f0b52544cd7916f6487afd32e0527a311f7bdb29e4e4dab266b7221a2c49e42d8ab06ab6d16efee2a0e0bab140aa34b53f70c808f3966f1a171bdc789e23ca0246328dcb1680c765fe262048b869c56f381bb7ded54e1486c0a3660d990f4bf0e5b4eec4cc0c3abf4edab6346cb531194c27de0d85fbd39f86d1839854a91291164823db1fd76397800c3b62b418bb3a894840ecc78579dd242314da99f01df55a45dadcc87e4b216aa0d817e60673c9807a75185e52a70f04ab8ea28cad805c37fae5417f89af44d4a5728c187c74ea736f21681fa7f93dd9bcab9b510febf2c4b5c64cbedb6b59b77a8816728dfbaeea423bba4663ce831af234352f8c68c47dfee91724c99eea5940f57b4f1d9660f0021892a2d39ce7ff235425942f2007b4e08f2002018f720e0339bfa2704a9d74798b13c6fda733d965666ec5592d1d6dae7af6efe5c87cf48d40858937b1ecde3445ab2c1ba1e87e1c2f3ce696baf3efb30ecbd9dbfab121a142ebfb4f09f343f37e851fcb7bf011f2117881098afc5a584e6aaa79f11d4d540874ab905787577e6407a3aaf293c886b58cfe9bed8a3dacda2a2ce41f95e72e46baf65ca666f61bb548afe8f92e1c4ada258f46178a4591015678fc542d412f7ed323d2629c127890ad9c2151261c4869f59db9648e09c25bd5ad8cfde27ea4ef22666ae0f30a4d25ca5cf42ddf3f75d2121c46e28f565d561c9c5ffbefc847ecb75a2595c3e410c1704d6fa62fa5fd54139d95217734ff4e596f2ac975bbfb8fda29f7e6f211eb165480e44fde387d4833f89c7162c1bda3265a5271946c5392921861ad5d9e5b672afe4778301d7a8a8d8a03ca1c99d73b2ee43281c0b88ca4292a5ea29a0e2377007fc04707365740563020003c54f16cef0fd4185f35dc6784047913c89883f72b68aa78c16f144624430909da01633eb2b4b13eccc2b7a7ac5ef3b13505cea54e1d390944b5680e6860184e35111675dce504784f4ae8121dbd1f76df3d55ef722f3f73b5b7723efe2fd34b107fc0470736574072103652ba5800d63722adef5232d31ccc12403055de720f0155fc47bba5750ccedd400 \ No newline at end of file +70736574ff01020402000000010401020105010401fb04020000000001017a0bab8c49f1fce77440be124c72ce22bb23b58c6f52baf4cdde1f656056cd6b96440980610bc88e4ab656c2e5ff6fe6c6a39967a1c0d386682240c5ff039148dc335d03b636cc4beba2967c418a9443e161cd0ac77bec5e44c4bf98e72fc28857abca331600142d2186719dc0c245e7b4a30f17834f371ca7377c22020334c307ad8142e7c8a6bf1ad3552b12fbb860885ea7f2d76c1f49f93a7c4bbbe7473044022040d1802d6e10da4c27f05eff807550e614b3d2fa20c663dbf1ebf162d3952689022001f477c953b7c543bce877e3297fccb00ef5dba21d427e79c8bfb8522713309801010e20cbbe4671915035276d8df41a7ef0b6a36dd101de48a4076046fdba3b0bec20ae010f04000000000001017a0b90df52169792d13db9b7d074d091aaa3e83aff261b1cc19d291441b62e7a03190899a91403ca5cd8bded09945bc99c2f980fd27601cada66833a5f4bc108baf63902e8bed2778bf381d17241be029f228664c7d1522ced55379e275b83fe805b370216001403bb7619d51d2af2c5538d3908ead081a7ef2b2b220203df8f51c053ba0dfb443cce9793b6dc3339ffb0ce97af4792dade3aae1eb890f6473044022017c696503f5e1539fe5cb8dd05f793bd3b6e39f193028a7299a80c94c817a02d022007889009088f46cd9d9f4d137815704170410f53d503b68c1e020292a85b93fa01010e20cbbe4671915035276d8df41a7ef0b6a36dd101de48a4076046fdba3b0bec20ae010f04010000000007fc04707365740121089f9677efff5962164a434b0bffe53d90c271deda3eaf30c1d7a55105d24b874707fc047073657403210be6c538eee2e29d44c66a3e66fc8165afa4081557031826a070703cb69faf24380104220020c731ad44c00a2928d508ad82b05868cb42733a5b0d0b208f483307ce8c328d9307fc047073657404fd4e10603300000000000000015bee4d0045b0884354b05d0285abb287ee8e539e8146b92dceaaee6fc01af1a3730cece4c77caefdcfcea1073197ffb8b3ded97d0dda6f49752b31f23e196378a3da2128a8c45ecb7eb1c32f0c0dfa1ce7bc348e799f66d547476e976baece7445790064b34b1526c88cf54928acc906ec0925327d797d36d0db6a43633d7f963ec9b4123a5ea31b655882329afe2108d123f76857fd3ce344fcd651b3d3066aa506625c9309acead85fb6c8a7d977db5dd6cb6e2f99fb3535746258d42d95dd2103bbaf5d45c8a2dfaa2301eba08763bac8ab3b59bd0082a457bc0cb257c43ea6354348e73d8dee101864068f0e8e30e6711f1597d7b529a57e95fc0df813ea160f5f5152f341087868a680c1bbc4b2a427d18cf8f12cbc4304dd3b1ea4c916467ae48b3b53062ea046161170fbe6ca07462cf3e5534d638c91fe6919318c4b2e98ce0ebcb245680d6395ba746fbf510a9a36ad8d933b023eae39973a39162178148a897b5174940db46e4be54794cea11fafbed48b42eed27f9915cfc50c958e88bac551ab1c9bfa03653e558cf87a99ff13440f4808e27fb42ff3cbac9fe10d1de07dad4807c9f945784163214c739a9eed8bb2e7da6e1fdfa4aba5d5157787d0000b220145572d3d9253cde5c1132370c1849847633287660b429f20cf1f72e4ad6ae59154c3b8526fc5d30523ba962a25577427988d326e207c97c81b479540b1c63aed0a4b1dad9279879740b2f6a0bfc37aea8c81b3b35b630dba8d955afbba756b8ce9d2a9802939972c5f70efdee8778a98360eef15faf77e38627fcb4f98569d68ebad3bb667e5db46eb7f4214846e651224673dc998c55bdd9e0a1629497a75b76160865c7ac3af874bc45a42269508f183d2458835b1734791094122f75398da2bb7919c67221ee42242c298d744fcb920726b84bcb78d7eafc9e0f61a02de87ffc5c674390a33d722b50dc35bbc6788fe0fd24be7a9e358113a4e65b49655767b8f3c3bb86cd5a56c79f9148945af63492dffde82d682eca4787f203e49790650395c925e6eb68bbb3adda25bb784365c0b3e241177ca7de58252b8c79c5a865d1030f3bfd4d312bdf83bd28241389085433c34d747f9f45a0a636e700805e619a19739b15077d44d5e8969a37481896acebe7f350449c69b50376b7cf36e906d8a03aa7221de67c7fc4c5408b55e2562f7b783918004d93b284c0a1c3d596c7c18aef5cb77ad09172bfa888f5dceabf57f708f5ab61b1b4159742d3d35332e9942958ea7f39fd35cff66e84ea0ce3b38a85eb80dcc1201146fc3854cb40353a078f5435fe2becfa383b3a62564645250cf7feccff5414581e747166625477c70f5b0f579bd578e03e6b8ff8c3f0e8a82566199ff542b239f2999103cbb61602bc2f346702204e50c9ce7b85f3b8e144227ca8b9766cdbd498191c385e3a4f024c9396763eacdfe41b706fb23d4f065dbaa43d323edf1811950c71d4475a3e0913d3851be4e921cc933bb06b0aa20524267b0e9847b6de3883ab8c5be1eac17b06c946f19dc2244901890cc290f2e66147f7c47a4a29349555ca020e684ccba5f8a6f1be54e356654d3e8678c591633e11d9ee772940d92f07ab83228c0d8840cb9aae514c03358e973a2ef319a39a3ce819efc00e5a493fd582be164c1460f70fb2e103f09a2939f779377275be736ccd41f847133b3d400477582419fbd2d7ff328d88256cfadd750ed7a3c6657e332f635f0a90602b24135e705d1530531b7b738e686d83accd74874e160a5716191447f832d2f899476ec9c53204fc4ade5b75cacdc869b4088e009e12d85beaa3450889de0c86315755ec7744be592f058fafe62f9a89875bd2781d5d6928c8475f555e77eeb6e688bd8d3bee0a54fa1cb29c1b6b438d3f70ee4ac83fcb6f482575997e3a69240c6731b517d8241cd39dba6b02a9e3c94ff2470c61c693d32b1c7d22ba38f0da21d92150115d580249380500109215a05baa63474f773892b1870005e76a68853e6a8cd9f74ab3f41cf0730e702ce94c420dbf66a63f342d927923d7d25ca3c3823b6c352ae2ca127bf811c023205632ddb8f9191c2f3384a61038d1c4d32f808cbaea81d58f0aebc7c89bcb5b98f92849f4fec19cffc78173e601eb412aad24eacd74d17cce3a9ee76670367ed87c2da3db5e4ab01d4d9626d0ae00da7dbf6b8103d5994cf66ca56bb9aab9eabee2b14ef798d3fa5ed1dc16bb500a006c3320941c4c7f6f80c8b1bf79131a5e11ef38db7c42d4c4939711184ea414e2ec0cf5bdce3d7d0d72dc883b2595e5f0fe4c14cddaed61108c90c74b43cbf719bcf7a934bee760ab33f50cedfe3ce61dda3e4bee1ab4dc687f988cfceb207152f7a98c0fa3a114d2d6881034aeba877bbcc368ce591707da45becc48318f0558b3ff65d677578df9fd9e9a18d0cb08f2f5cd4f44925259225b1c4c5ed84ef30d136e7c66251329a223a1db0b485f1c634981f8860aec1f3dbda9442e5438f6fb09c7e1ab43e2b757911834df8502ce35e7be947771f7416f7ea97d26dbad7221614175e6b86f1a323e26c4f469236d1b1bf6ef28823234c73b275c5b0ff39e8c04d9dd8ff7f6a57214d803aa13dbf581295b92ce2b8a9c0e3fa8e4fe4e74c4bc2198fd010cf84681cf5f3fc9df1638c403006478b1cd4204ef3b7a6093116021118a839bd3ac270783e67096457a86d63654e268821ee742241ab5f7e91972da0a94f679b4c093d3f428d5876edf51459331df084f2fa245e3648e0cac904a82a7d323b965a39683ec0b2721105683e67d65fe10b8d41d0dfcd5c31756408c94cf425ae67f95ecac45391516875870386b675e24c462b1f7634f758723e6245da6a39da69cc2390374eb89c6c662d94eeb2f1835e233610072936be248e6a3ff87f9950c2eb2f88568c31dd30d1f0c0396a42f6be2505bf616c63f504dad5312fee2f083b406fa05cf3c998ba24237402681f0ec393de4650ddce3389d4c1541d4705d8f50c2c6d4864934394fba0c40df495fe3a5bf58a5498c1e63b5ee5f9a4b53dbd913252d4808f5bf5fc3c6dd74c86c974fc9e5afb1a7ee3d88738ab1fe9194881cb00197a31d648ae2448db872528d5f7c366188d9d98ea94497cb78ffacb5f6e8a2c8520d8d196fe0ed13e2b2a5a08dc45d8ff58a8c5d3bcbdc5d80c798acd0eabf146459e79db12c2a43c55d14b2dd608475c606fd4f943ae7cf62131691768f710fd718fda3967146daa8d4f34a3b8fe8084f4f3865e9e0cc1a0b0a799fceafd1b74f09f524822179ce38cf0f2c4c8623a3e3ab2cc20f5dccdadffacee62c120657e3d85fea93fab645b5fcdb812b130afbbd5b19e86aee66011b520b0affd84af4bf67a28b309cad66cec25a5de06390a4f2a5af47d59c006010a8ffd214149bbe47bf847fa94c2113723c9476c2e6dd84411bca16dc7bb096aaa3e9a9be27811b52838c78d16cbd89cad379bcc0cd966dadfa428f9d4d8bf133f7d21022ae3f966dbc1409c6d57cc46ff4434fd90d79b6c9e68ed3795ea6191a7e309783badaf8db9fbccbea905ff9d423370810f02add38ad3088cf3393e7c6d585b76fd78c67766fff03ff54c01228c6737da667147a8b5e722370a24db8c0165e34888920d70fb1356eb731d0024676444e2d37860eaaed9790f99069e622afe6ff12d516812022c46420006253248eb292908ab8658cd874ef05bd568547535fd54c1f0b5b816e4d90a1bd55670b96691e7633a2fa45be6a29cf7bbbcf9e5debb4b7a739b36b6b326b719a12cd0f5e3557a2fd94023d8c633fb697b85080a39734013b4ed9a7500aa8093edfc3810d4c890e608951e57af8447349cdf45a076449241a047085702dc3e44814390ceddc878791ab3a6503f48f48af25fe5cddf61e7870ce80e32e5f22d5725bfde4f319c2db7cf3ba3b9952202cd24210ab8d47fcdaa9ad5e2a9d2c7be1ed6b67cbc1a28ebe565ed0337c09c97d2d9608d97905c7201be7d4bac785d64caf783cb3ebff817bc5ff0448899537ce6911c9803744d06ae97e6d3aae037697986cb20061892ae72e05968e9bc54153bd745012af719fe7fd4b917689a6cbb94a9bc8cce51d234ffce7dca804e2b2759f473885855983b7b290806884fc66e724fa848af2de3164c611c630e5bea712cdd9a9943ca3ad55994e5587c5953f415171bdef3c42783b809bc5526a88aae66be626d73394a607ca32256198dbc026d9e09e9659ddb66736215dedee0cf69a24490a53b2c678e6caa2aaef10a4610f802fc5eccf558629554d6388465584514d3dd49fc00fb267c39bb746f76ad3cccabcc3cc882815bd9466d593270a5c9a04945dea7ad06ddb73e66b90270e859a109d52251d911e7177e07295ac9788ce970c1b718fb0c2f327f44fd0cef3cb90071ec85e958e6ae60bd134ae307720cdb10be5a0af8c051295df905447b46206b5e04d775b83e11c348458b1bb310ae25c54e8ed1488a95b2a576002198c80e0e69d14fb7bffcd89935faa6e3f9aed61e0492bb2bc334e389bd559806eff9e16643ddc4372ca83790a99bd4f5b042779ef7e3039858881c8ce0041d43ed6b1f42f18007d046fd6f65907cef73fd5e6cd514c4fa5ebb872b140d0b2ad43c58f2f2216522e78a19828baa34ba56d71414ae869a13cb708762565d754f0754561adbd9145d232034229d2840ef0c96f7af4b232c5e11ae9d018b87177a506b66571affdeb693e170dd12640e86fd430b64509d02694c52a54f23ea96e39be92b65c1abcb262a71d6e884183d4bc6cac8c79f6e94b51abe484794a42a8e1be721cd59383bdbf327a864b2cf27566f1270d82ab6e8b3b934e953b7d48ec4697172e0160b8435e8186a7ea685dd61402b0bef09137fc52e19ecb53674a1c0af17fbb0efc2b4d69572b32600fdfc3c85c79ccb2685c665aef16748b7f15862f435afaeef00f3f927cd3a60c22f137e9cb2c38a9652cee570a76351871ebc9b6fc720b9117b1306e8afb298e3a1d0d4b2c5ad5a21e9de4c0938a98daa35caa711bd6d3312a7e941b060c4a1ec211c31e53da263995d3be74a3ca5a970d3a663245a5d8eace336d9ee847619bb337e777b961805e808f7cfd8f09b93b6ce6c277396e6cf0a6153fb11625f421b02055dc53a0bb24786f4a74211bfdf44193e48b2c15c7c85acd3f4f0bd26644f9dc62653e366178645899dc06d191c785831b98de593519c0ac5849897a01b4f8c7fd559edce1c878bdb9dd091546c64225fa81b1c7dcd6fe72c8131bb160043976a5e891236d3552598c0c4fc734d1cc752c10306dfc8391f6d658ab8b7a1f350e1900edda29775ac8a531032bac968f6981889f13cab07f49c864c3ef3ff23555c170ee9730912465e6bb3b7508e11ba27001d9dc0da8b34954a7c46a2d0b0b75e73ad66278c8acbed3249936a6c76fe975954f7889bbaae5f73747e3ed02811b015beab9d1515e396d37b2a116b3cd8863517b88ee91a854e4740304f7be41123692181a8ae22090956ba619fb948d3f08108da17ac2484d3dd5795b1c716cb5ed3fc08b6449fec814018cd883b02256afadd1f35a04d9d43f661be624c0d59d0d397e8ad6917344203843495162217e79bade11ca32c0a6918350520e6c3f31f866b89e3497b518cdc056e760813ebea7fbf343db50ca2450d5b7a1c5f430859e2040ecfa70cb0c3e863a756ef6ae2e26c68b543d35beb44513f8295872df5b4062c9b80742ca7a9c2ec36a1d9bc936c7fa7328240a2db54463ca04a40dc0c9afe4d570012259c8c436d322483b17a705d60a283e0ea7545110e898ba43ac6130aebde014d237482307ff28f385fce8530814a3b3507fc047073657405630200039d46edc3d830d852edbdf28cbc023dd1666cc4a806ec9d4acb2c97865280698d61fb6b2a073be4ce75cf8193fa9b3d677146575a812873ae7eaa7b08110cb88904273dd65af35115dd116092a56ab45fb57178d8c5ed4cf99474ff760f6e987d07fc0470736574072103701e53a6d0b960398abf678382a4d17c5c153d1a2c8ffb76b302058ce915bb0d0007fc047073657401210821b4e7599b1b4faf29b521f1c442dfb0a893499d374c19db939c0c9a3b9798c707fc047073657403210b8529a893bd81e38743e8e3015095077f6e244a064d64708963c6af5024b6aeb3010422002058037c2d81d3122185c8704d4276e2629122c95b8ea68575c451628d37eea84507fc047073657404fd4e1060330000000000000001ddf2f500cf45e30e3911bb51a7ff633c1e329508e42d9aa49fa8248fa4d293b87005db08b17a472580ae2cdd53c40b2a16af885d6dfa3d5b3410d389b045e6c12405c635511ccf008390856f4c6d0ca472148d2969fd39e1307bfbb8f8268ce92398248f08df7268bbe23e13ac3801ad075376bbe9684db9b41d7b1148fa65a129e1d25193ad973ec7af631a0a30c5659409b0d00e6fe44c2c507d52afbee8059aee7650bee9d47936838e77f00cfec9de3b9efe72cdeefd80a19a9c8ddcd6cd9009ec96800f9fcd709f1432b5715466d601b5ed10b0dfbd09b954b109232fb5a24036b887d26bab43da7eaa303e7c8e9d02950610aba09f343a65a7cb4550d6f6e5c0eeb9410b68f85cc3b05b9340e2e9c94a473f2001f5aea7e875d29e8e0aa99c09afec4a5455258c803e55b89cf6e89796a6f3f9fe11ee05ec415c6ac08e0f1adf9dad681f8121f82e3a9402a2fe13a016dc10d4a605578317be0d9d3e02b0989903002bd35ec4970701da6eb6f9fd5e6cefad137dceffaad968d5ce522e77c76e665529f70c9eb805a240834f4c8c795912c37e7efeb73d4bab709aafb66bd645cf0addefdd83d185c1b4465ee16344575eb2aa3acb057c37d7c22cd03adc6701f03d4cfa20ca94458b3b87e3fb7de8fed28a755bcaccbd348dbc7f5aacbb25d19437d87cb48b88fc714f059b328c374fb2695a26537330fae42d3fcff40b07054be10508fa78a9173315506119973a9158828276edc6e8ac771476d7479d07ba73e9c5b58d61367d24435a1062dfa376546e843b34829103168db63b708a13894813a442f889a423054160b85a2584d36951136bafc490056f1c03c44580e2c7a12b170e5c7a3917720bbbb21e5da616649b554b7ff57dc84dc3935271a8aa6fb218becde208d83e76bb6197f5f4f729f3c57b4280c388bf4945206fa769b672ebd47ef2d0f777fc9dfb031cf7c333c6159a75a5b33ebc6c4683ef140a144a5ab15b2b6b72ba14ee7595679a0f7873a75b9a79e03676ae94eaf9ea8d3532460f3075f40c6b9848a183fe46651caeacd51551f308eab6ba8ac27b93865f5dea0fcfe1d7dbb745695dcf187a5955414763c88ec01d299f03cdaec48eba946c7ff6031f28a5e108651401b5447c0d21c449b387765a621c057eea7d494302222e3d1ff6ee9f8a0580671d9fe3ecc310e84b554e5c823d81b8027075f749b2dc8a6bc5a99fed4a0fc46fae59cc2aa9f1471ca2b0d9fafa56927fce0f1df92647ff5aaa083bfcb7078bd8ee142448d4e1f3dda670ad93feb21028a57ee9a8ae8880df5b3276e078555d868be0d8843b495e082d743328620f36f7e106733bcefac15076826cafce271caf1520cc8746948e71ea73eef5de770ecf5e0fe075f04d6c9cef1cc1f262e69fcfc89862877ffd520e25405d9d07efec82386640d97147e4a6df66bb1fa1f20dcc2ee1fd6364bc2024c0a4a2ec00b84616231c02aef16147df509cb830b9fb20111c60613d41169a24ea67c03cea48e1905b00eba8a61e967b9aa5b6e1264b0f3e2c051e47f54f45c6fb78b46b9993c7d223d51036cb77f5e31a4b30892e8fd7ae7028322d6402f60712f712f84443de083767c38ae88a38fd4e4bbec58015f4e49e36ecbde94f23d0061edfff0e9eb62b67327249d728c278f923748e4c1e225791c740abf9493198f073a6cefffba00d23715a14967a72cc7aebb81ecc6e8bc88ae63a47507296a573c415d0163219f3b20974ba3a32572d29a479b88b89c241e63e640bbb93e2da0b73024ff03516ee3ecfbd84348372cfb574817ca878172a779ff131492b86e64c1b7054cc5fdb999df4a9578bbdd6a6a2a798f053f4c7456173cb8cb9b61735e650d0394ea9effbef615629c1f393949095982345bfc02b9a3b3ec64d9173bb1285587048fca8c740b6d2265d3e727069fcb90282c78f1049ed7925113279474d0d873045851b397a8c26036c83906dccd0eabe98f7d6854d9abc2e6ff12d84c2840affa371cc2dc624fbce873f38570dc9eff33f5e200791bc052307f5c718d47fc2a205add3fd9de2a81cb452a0a7b4a08bc133e9816f6ba852735b813a1b906d4dbd1ac8a968a8adfb6aded0d3fb87d80132a4b45ad39274bb72df20d648a26aca4beaafb971e13094b6d6525bd418b91320964bd90d3a98fb32d69222aaef2ea95c6b84b6b6aaeca3f6789944fc7ef17d218abc7667ddff798b74a0d5fbcc33d22d028d207f82286fd777ea1e281d7eb88b665e29fcda067bf9ef82a190c920e260cbc44d394b78e0439bcaa6371f8717ad82e02015f21e5dc273de338102539bc924d5a3f897eb788e0f3cbb6e8a34590ff5370bcb0f671ce28d6ac0adea17f9fda49c784ae84464991fc71a31d320d62c4199e4f4e38f390ffbcc7f15922c3325451371bebfaed8f8a7d3eead71c65878a705a6163ef649bdc6ae7b81110a2cc9576da6b0188337160cd518fb30fd5b0c165ac3de81002490f36d29f3bfefa2b4796c070c6d7d971d18bb5a573cd48cb3c64dec5bbbd7f2f6f60bff3db4833bb64b426c6715021997350aab1751f0d5382087ec133c2c43342b31eca32a4c17db14148fb48f9b7a103b2c0bfc0dc95ffe097bd8f2213a3f7a43c994599b05dc35d469fdc025e23e483039f271d948972417153c849fa8dbf374693dabd59d398732020e90d8f443ba45a00b430168561de21db76b9b714ca8260fdc4ff1a5713e69ed7296f5a5a9d192474bc6e67788d6a44d46b69ac97d0b34b2b08aa79d5ee7e910d99221e1e7f6383628b5383cec4341e5c3f18ec3361b2f2ee5935ed40919a4f8892bf3467803b720d29388b7cd47067eed9be7648fbbafcc7bebfc31a30d02f38b7d6be1579c751aabf679fa6891adf66da2257432c10d399a8d496d1aba381b64a5e3ec9a65cc8419151b638adea994c3590f77bf390152894b2784f7832d986ac51b20ba9719d85509acdedc0282f27065c87bf483fc74b55579ecc233fd6c51822ae03e46ecdb15acf0204b67852d525168f409d2a4309c5d9a14b35905b836091964ff4fec0aa91bbd7f39919eeaebbaf75c63337a4dcd5ae37cb60fa14bd78157ecef35ddb1cfdc366eecd48aebb0f5b395e4161c158c46870fc89f8f5918aabf0577c914511cac7b189384eaddf7f03cc6706a9abf219ff1b293cc9fa2cac88b65af62f0493e30736b596c119149af07e840a43dba8d97455a7a95368395488304626d3b888069a0099c435cc11e5981412f79153577c9115a1812b1c4a9ea42bbf11b40fdf930bcc37e6a6c50a7e3d06bfe7043adb32244ae359993caad00eea5f1de90355326e921145add1020ef3c2cbcbd102e7b9a150ff9672697d31f86572843269978cbc4c3fe067417e84898587d4de009b33094c8e8102c07facbda62a2996e083d0618fd9651e17f0fc025a946e7c28d93e18675ba69d8811dd06a2cc1aae28de5a6af30f305cfd8a090832483e4ff7c974d47ac96d2f3f7baec94f965a116c2734f87f468ec33cee1a58dd2ccdbc8f6a0f2a50a739aadf4007c7a529844cd1ce5efdd42eb28a0f5f04fde00dea586e4b8cdb8469b36940de19feefd342285c29298afcd3ddc368f6365e9ee255f8c2b6f70c1bafafe10720402a668ac3a2cb8ee75cb7004455cb4221486c3dee64f8f25f1c8b1411437cf6ba70afac5182b21f0efc1b5c71dd59f71796d2719741b6d5c757d824cdfd2d9459569427951d6974d94bea1fbeb0e1a23ef88774b270a8bca65f01a00299258847ddce8af8a7626c802b29dd01d1dd9d2a7243b334c29c0943e11ddbfe82cdfbd506e81fab8775a1d3c4f6c0744e1086763ad84e8f51d601e24cd6fcba1409abbb1c6b5c9bb9eab8ca30282801448f86cd5d8ec187866f1ba738863f3995bf4084ebe8f41dc1ffe0cd47d5a95dc5fc0dde1559ba170316e085d0e385ecf8646bf787b5287960f07bff9d3d990b3be4b29f008de18ccb46dc2192d0fbbbb9e701d350aae205fcd2d7314112bdc393e2eeb0a96c5f2c767dea0b82e9549f46a270b2c69915711c144a7737e9003b1c1b8684e9f2abe66ad1678c32a0c6ce401ae2d7507ff32c8f6179433b94764a6e4ea0a363e9a03787502c67ec97724d78c1257499379ecc5cd006a13acbba05dc7f1310bc75b9ec6a09f4d95b2ec11952eb3dc3d2dfeb8678b10b5db162b44af56ada56f7e311d6c5ce46472d9ba2284126f8f579d59a9d3e81bb1b26a7ee59c3cca96252fd4ba8e009a213911619ab4184e83683969cc4c474e934f36e6ba4ea33d9e93e984f1603e259cb7f1a3824dd8764bbe30ae08166aca84e63615e59c31d2a968a0beccd40637db22b971d51a4c35ce83108d8975d758669bd83ff9602718a882b943f80745d95a2d5e07ad0acf8023e24589fd68988a350c0ad571470f8b9a906648895d312100cd18089465de942ae0c7c8bffb5d3705c729990721bb0497dddea6dabdd530c9ec90286cee5ba3e2b699eb2de55de8aa0012b38051862bf0a7a22d6cce4310dd8dc47c206d9eb7bf28f2a53afa8fd10836210c0c461e417be42d89ea659a76d5e3cba08daa885b7f0302c5df05c72f8257f60e2ad954891841e67d8b7184cfa47e51e9b36f6ed1400aa84c5058a1998d07709b8b46630d70c73552ada18713310dff4177e2143aada1038bae9a64e02870a7535598d766f447b4e25dbd009009cc0e3421067bd0cd10735469b308cfd7a094bbdaaef2e31c22dc6c1a6d4c7890020b5bd04ef649b56889b2031c1923a69002448dd5db1142384cf517b08096539cc537532f43afc33ca77beb2dfee921178ad51b04f10495365e60b4b7677880409716e0eaa3a1d649a871234f86787c2792bf1e04a635e3f22b8b3b1382be942605c3855a940cfa3825a2f8993312a512c81f92aea0fca95bd1bdb6b9774ef3f1fd15bfa1eae84ebb48bc9b55fb2141c55cd3188eeb5049b2e6f3360e60c5bb7d91c9028ebc9287b4b5541a4ca290288e08ca46f80eeabbf100f700c873d7e69dee7dc80b842004b2bb93f0bf533488028d1a1137371417d06785372ce942d4c6589cdb57514bde81960475c22393eb02a93b6560fc3e4fb6ba692dc362d38e33a41b7df222e9192fdc0e0499f110e681682e2b500c00947d62280482dde5e26010cf959fc717d0837c98634550376aaeb17c1c80e3c3245c36c68f56fc8be117ff84957a75e4aa4caddb38779f1c50086ad4863002127b6c8067f172aa78137908fff82b2297a53d6232c26a2e94bb25b7f9241013adeb36d1e437f2f6c0d983efdb78608e940390005d63c081eaef21d7f00ddf51a3fbbe6175be436a9b0b75f198c30efee2821ac5f088819eb96ba835999d0012e7a0c244268a658bc6b7845d10178283cb8add0b81405ccd64000c1835111511555eca14f7e3cc9274b45f817039ee62cfd95363cc66f5397f88822f790e0a86b6a69379dae77db24185394d9fc73880d39f6b3233dd8d3b912995b22905563ae8cb2b1f3491feffbbdf2c7d2e89dce1995d2429bb0a4c550860835aef589983d3170387971f8aec15c18450dbc9cd12f402589dfb17216e359072ceec8e9484f9b490a288dd4b268233c40ad23721961c390bae0a181c4cc8eb68eb4b2a5db6944042c6ef67550f9abf3b9084cfe8521b62d727416576a58591dc65f79f871958243ca4415d92d3e588c4205b4a3806d64224e94e8f04dbf7f75888246aae9f894bab1ea69d7e10b4f07e8cf2dcf70cc62571c737cb6b6c68b0e3fbe4b1931c8615a793fa3db0a45090458ff62ce8bf421907877e555cdb97d3709bbd8728c4432288861a56cbfeabbea5f225cd29e31d99eb788704a93696f5e81307fc047073657405630200035ed48216bc666598aac5498e9fe513a9e21eaf842d382767220cf98104bfd8866621efb63b2eed44028cdc9e2f64cc2447fe09f8d8a1eb3214272855b525d9ce24e6daee58effb4af28fcb0a4685d78d7995081b5cafd1cfe343aefc8e9cb23507fc0470736574072102b642f0e5b34746f2f6e3b511d037e16bc720292da4ea2fb31ec09f6fdbe777ce00010308f40100000000000007fc04707365740220230f4f5d4b7c6fa845806ee4f67713459e1b69e8e60fcee2e4940c7a0d5de1b20104000007fc0470736574012109a05049129b0d9e61c1bb87a9fa02c2435be35e3535082a772f65222f2e4a48cb07fc047073657403210baf4431fbb8f0227bfc0008368606a4b8f2bc1706e1a06cd4d83706217b74f5b90104220020c773786f3addae4c21acb094f39122c032daded1cb6225a64d923a0344087bfd07fc047073657404fd4e1060330000000000000001a4092701f9170991583ec8b5c9b5056ddaba7637f7d6733a57dc4990acba6d15e9eb5dca55528e179b98a9e09e05ba940b59558b768194ca046c22e12ea310ec05bcc795ea419277649d40b145e6f0accc31f2d7eb39b29b51d3ba3410536b9bb37bce9014d352b496b93161fc799b23939ee635f25c4cbd6605029722ac2bfed7d55fe4120c0cc880661ea3313d700e261ba973bea5df4dc4d8a05652d193c5edad01945862943a6756d4b0ddc93ad5a444ecb054bcfbbba3635aa752d9c4fe8f93fc56c8066b3fe344143d65328025f5184308f2016eae65df8b0f1818f59f5a9539eec9c9c94704ecac269b008ef25f67ab2b9ab4e903b1f2372d1d3988b86e5efa639f9f964599df8559622c8d11f6bc4f706c74e4a603a3798005e210f93d9e6b59f8ccac907dc9cff127c552c8c89981e1b91c817cd365422eb6bb0c7ef4ddddabd306b0c32a98464973dec30def4149f8e9f35de6840cbd0ce8a2f2b5dec15e3f3c27d0d2720159cabb3ff2f73b4571eb53ec735d7b0f27bf4d23cd8b0fba14d5921d464beb3fd4f2fcf844f76a7f7f129a3e7e1c4a6e4f07490f2cfbac4e6730148397c73720d35cc5a46fdb1e774e17f7b951887c1c72ae4cb25ae99bee652ebb2ffd9f4c9400ee0870b27a5dd8fdb8224aab6738399587b4513d3441e26b898b35f739d64047ce8de70347042fd18c3797b1de82cfe23521dc8e5c36e286c05d4f81508e282018cd8d263164512e6ab02a22b3d5d489e6074f9370e218a3adf8afd229659f5046749db9615541408739d4f0646a853b25f8e549e85708c368e45f3e1d20ab47a4ed647b820a360e4e351e4caf74810098f0df4bb74e0e69f2db3284c30d24a0d109d16c37509557ce15c81812bde78085f31cd7c93140fc43d6580abc7ca2adfe6354510fd8104c0f1ffe46d24f31bea808376ac27996fb992de15b30abf4df6f4d08860bec27a95bcee0df8f0a5bd7f72938ca9e917f39c5425bff826c4a84a1fd70cff87be2e8619e0d3b729f0aadc10d4b70d10c2c020a99d03424a595294dd34b84c83a2d434b98fb116e2ebc8b2bc444740ce090816218ea61da172e30db5e78a58ef495812c287e3cfab7bffada0d6f2fb3c153f1a21707923ae7ec862d44d357776803336566c3bebc9f53177a3a8825478eafb32a61bc04d82994708725e0ccf5d76dcac946f36895402e84856b3e25567156040510fb299b88c45713175c54fb3d54aa6d383c423807778a92b7d9bc8fa347923749d18c96b20cea608b6380b57c35b4408f724046f6f65fc0d71e237c39376e1ec6dfc6a2ae83ba70d25855c10e6a8f425951c52fac7758353e2068e5cb4b6ea066491e834a47f8a5cfbd6ca91c832fe4f77b3b3140a6c1c70055d52f0aa67e7d3ba18e5bfb09f738141a611002ff9e34188d540ac42f48ee06f6925cbf3cca5ca033c4fe089650a2b86a8350367e9cfbd07fac9667c0171f54311cd5b371576790e51a1fddbec64f8f559cc08b1c0ae5113bb0c532742d90c1a266bd7eaa4b1d06693ff12d6e66c51bb1d12dfaeb70bc56d5870fb5ce4b040f86d7725ae53b18c1b12a84f7e3a2e7d748e8a899fb917987518c6dbbb83e3b62b31b0facd3515cf2e18b4e49218ef48d97df114971b298a6c4af231a432d4ac295d0d1947e09ccf41ab104e5435e7dddc0a6815b636a31be9a0d9cee2f22c745f05f384bd703fbf4bbcfeadf177abf4ca4524f38a681e5436a06abf9ca70c7569a7bcb8337b0b0c280b5f790ebe1258bea9c1da58c65c13991efc1ef8f7c75ef28affa340d84b33398790a9a77d30b0ea35613b39b1b7d8667fd7299e2ff38de468f625df1485ee3b2759f7e27ed707f5807342bad0935ed42609849d7a9d11addf8a92df7933ec44e86ac7f24d55a55284fbc4e4824a2b4f8bcb146d08d7d6d3f551ce1b494d7c0fbd6e82ba4496f3eb2812c986f3e2e627240a9102089725057c1e5dcaa3bcc5efdd6ba7e8a496f609aca3dd82816552c669c255283f9372be7d8f12b044f8c41180aac612245945a4467fa806892d55ff425adbbe92bc892698a32d39d7c23303ef65c980c608b5ac07ee60ed2b4e028a5565f5aa3ecd1e15787c23716697d53603f72738d5ca88c5d8280c3d8af9e83c18be420bb87db4b82a98d3af42f9191d4023eb22f428def2ee99d04d1497cb8205b67c9ca893f7afba077bae5fc11cfeb53d882763f2eb6731bab373923a63dda3ee1c1b6207e0ad0884290333dfae3f80e85cc50a241c73d7d99998e9b14c3e52e660edfe594e1ddcef04402e8fb01efff9c00d9a6ffc955e219fe9c92cbe87865f7a25ac68fa2d360c584c33fa3e40ce91d021465610b85b5f1a98e6908a17c5e138f2dd7da2769bad8789eed99828e8f23952bab7e9ead5fa9bac781fecc93de7927544736fd5c57f1da32be31b85657c313cd02104e1b889426bf4c8e9daa741278ae3966ea673cd3fa164ea7cc947b34f86c92084043ae846aecfbb15535a9b21e27fcda9a21bd821072135554e3015d5a12d1c7f2fe74dcef63fe99c947b55a4253add3668bab2d356d58909b7b0784c0759dbf1036645c5d673edb45245f5e78407978b63d5c25ada76b176dcff53e76801d7c2784d4687561f32e7a32175c0fc77227b3ab0a4054462d042931897530502c85f0b976fe3e3fd5488853b20dbd27d0d736e9f44fe6224b9610af05c462f08d328cefa4bf8530250f5a4d3fa7f58f5a48db45cd68d0dd53a2c66758a20184cf226565ce558e60f0af982b02672f8ab14333349a5e5a5dcea61a09f93addea3858fea4e49c84f5d8269a2fe52f072d66240e7d30b7345c841a135271c07e6a142ad1ef1955e29469d3ad3d952ca9055696dd825253e4a0e4822bf3119f1df2404ff9bfa39568a52fadf98ac6d5a4653862d91b995ab166fa9de73478f7e339941e036b621f7d773a5413471d6e41a68c02ed89a4882bfade2b10e399f4515470ef43930a911609911f8b66bc060ebb186cdc4c1aa3cb573d696b0f48a655f8877f68f678bbf467ec872724181d6f983682389fc8a61a7525bcd61ab37930e6eeaac82b7adaa145e2a0bf67e235a657949708f0640ec802a1741590a505e4a109ba857824e00f8f675ae6bc8a0f32aaec0f38398c33c8f53bb3cd53bf697ece4372f8f252ab4b314769f1393aabb2675f44c05dbd279732824d49e77f3df8841de18a30a9bc321ae43c712dbb9f08b457dd3e3f13244ae03da16acd6d3e861efae625478a89020655f0de72ac174a50834db564d4e60bef51e28954a938c64a6ee290523337153aa4d6cfaa00826d2aae1b57e3ab857e10cf2b497597ef9395fe6afb3d74b21c5d44281f756e018539ce8b7f4bc663db1eac9b976da2f994b193a30bde0394b7648b55ad9bde958ec5bf89eab516d4418451d8cbca637c1d6dfdef61712e76aa7f12151d5717ba1af71c4754136563ff2667bb984a80a51ee9112587cb77ed6fac8f4263fce637adcab9f315d6beefe509f8d34ae9c42c12dd42067584c4a96f6c15fe590bd8616983abbf453ee038f385a126dcb71919dd7143a8c27186e1c6d29d36c1039a8f008088e03fe7b97fd7f285a0817ca746438e0949dcfe49fc67ae967d13d1d1aa37c2e410bb95609c7ba0586c8fccdcca933b1a85ec97d1aff670004f71232bedbd192ba5e5a681867470c4e146221bee322a5f458a2bea1316d3f4be26efbcdeb4b1062e58f2fa23b144cfdda55aad3ed7142653c7948b6d854abb8d1201e9a4de07b8985fc194e58ea08b4c8528adcd73ae6bcf5493b7b8ae1f663ace587a87d5a341828612bf82605ce6cca9253057a8096f396bdacefb56f9a452849f0ac652738b5b3135ae13af532dac7d9d5307f158d844bd3664865724aa9907d2ccaf4cae78e056ee78815cbcdccfc38b71e0c648b1fd9f710a15d799e237c344d53923d3941e73f924b75de975ead5b536d632338fe83a8d02a4b7fa9a6f1a5df9de85c88b944581294609c880ecb5eb45de087524d896486c200ad68f5c45e43894d6e84493bed02602ab075c8dca1e57e3932740c25a9401b5bbc1bf524f4885f77a501bc3c313666fdebe7497a2b55031563810b35f33503cdbeb46de12c0482c70b07b5ca3c4e2aa21be75c33a23e73c03379c434dc8bff54dc40b0a34f476d0fd1de0422ae6edacc8a729ed2443315336b208ceafa68a229592e42f49501cf03fcf04ed2ab60cf7c31bf4d4fb5a8d7b8969ddfa8a725eb9d32827446c141170bec2b0dfb5c0a6e00cf83b856ae71b5ce46dfafdc12f94a7f8f3d1bf1eb769f52f43238ed411a97e55625ddc208affbae8ade42829c82cf4f62423830db9ca4091fffe3d282c578552649a34cbfeef3d58e020978137a44fefdb9083186dfd712301431b78095a0997f0764f3ef29f138ffb322c8e187c260c90a3ef7da5638e8d961d6a6cb1867a86d3eb23419e101e18bbf128c7a3492e8447533b7586a81e52366bdf2c376a57847b8a44f7b55eaeee6ab2f06596a87ccad4a60881bcf4b4b5d5f0de85593b643c0c4fe1771a0cb5bb0402fae0f1a2dd811d6495676ad718b73d4b86fc79ce074aa9924829ceb4dfd4e3ab70fdbd94b5ad1d11ca9e582dc215577056373ed91ccd6472b3ce02dffa8817e66205b179f37bdda376d25d6bbcc83a15ad757bb7843aa03d2f7193d8d707ccf4de1f5c8694aa212219752addd55cbb412c05118c30555ca7ea820bf3440d1dae3332947a1cfc22e366d1ad120b906274883d7769983eab6afea2ec0672a2ed25b2b3390c017566e52a0ebc59e6cebb89918d54f75d4094b943e7725468034d2ecfeb68228060bad59a4deaa40843d0cfe0a1e58855113bb7c5965254b82cf3997924d0a8b1711b1e1e5b28343168f64fa9bdf8e5158f33c91112f61ba782a4f97c5456c9c8756adf53a7d919ad90654a1c035d8686f834750302added0fb7b29a3f4f43f4dec29bedcff3139cbdffe391ad64b48eb1691be659e4e4dab266b7221a2c49e42d8ab06ab6d16efee2a0e0bab140aa34b53f70c808f3966f1a171bdc789e23ca0246328dcb1680c765fe262048b869c56f381bb7ded54e1486c0a3660d990f4bf0e5b4eec4cc0c3abf4edab6346cb531194c27de0e316d9d0a823db00e20e2fb99c2b5383213518d0cf604ae8f69d2921b442b729cc78579dd242314da99f01df55a45dadcc87e4b216aa0d817e60673c9807a75185e52a70f04ab8ea28cad805c37fae5417f89af44d4a5728c187c74ea736f21681fa7f93dd9bcab9b510febf2c4b5c64cbedb6b59b77a8816728dfbaeea423bb7735ae1fba08964a343ef9b5d36dc7f8cba10c8ae69bbddc4e524df73c940f762a2d39ce7ff235425942f2007b4e08f2002018f720e0339bfa2704a9d74798b13c6fda733d965666ec5592d1d6dae7af6efe5c87cf48d40858937b1ecde3445ab2c1ba1e87e1c2f3ce696baf3efb30ecbd9dbfab121a142ebfb4f09f343f37e8c5c0f40408a339cc3e4f4d34742d695dfc037744ba1a794abb67954d3a6509157a3aaf293c886b58cfe9bed8a3dacda2a2ce41f95e72e46baf65ca666f61bb548afe8f92e1c4ada258f46178a4591015678fc542d412f7ed323d2629c127890ad9c2151261c4869f59db9648e09c25bd5ad8cfde27ea4ef22666ae0f30a4d25c3ea1780a6c3eb2d94d0f48c1a61701707e57405e7e9f448452d0a48af07013fe04d6fa62fa5fd54139d95217734ff4e596f2ac975bbfb8fda29f7e6f211eb165480e44fde387d4833f89c7162c1bda3265a5271946c5392921861ad5d9e5b672afe4778301d7a8a8d8a03ca1c99d73b2ee43281c0b88ca4292a5ea29a0e2377007fc04707365740563020003c54f16cef0fd4185f35dc6784047913c89883f72b68aa78c16f144624430909da01633eb2b4b13eccc2b7a7ac5ef3b13505cea54e1d390944b5680e6860184e35111675dce504784f4ae8121dbd1f76df3d55ef722f3f73b5b7723efe2fd34b107fc0470736574072103652ba5800d63722adef5232d31ccc12403055de720f0155fc47bba5750ccedd400 \ No newline at end of file diff --git a/examples/test_vector/raw_blind/blinded_unsigned.hex b/examples/test_vector/raw_blind/blinded_unsigned.hex index a8a1391d..04935958 100644 --- a/examples/test_vector/raw_blind/blinded_unsigned.hex +++ b/examples/test_vector/raw_blind/blinded_unsigned.hex @@ -1 +1 @@ -70736574ff01020402000000010401020105010401fb04020000000001017a0bab8c49f1fce77440be124c72ce22bb23b58c6f52baf4cdde1f656056cd6b96440980610bc88e4ab656c2e5ff6fe6c6a39967a1c0d386682240c5ff039148dc335d03b636cc4beba2967c418a9443e161cd0ac77bec5e44c4bf98e72fc28857abca331600142d2186719dc0c245e7b4a30f17834f371ca7377c010e20cbbe4671915035276d8df41a7ef0b6a36dd101de48a4076046fdba3b0bec20ae010f04000000000001017a0b90df52169792d13db9b7d074d091aaa3e83aff261b1cc19d291441b62e7a03190899a91403ca5cd8bded09945bc99c2f980fd27601cada66833a5f4bc108baf63902e8bed2778bf381d17241be029f228664c7d1522ced55379e275b83fe805b370216001403bb7619d51d2af2c5538d3908ead081a7ef2b2b010e20cbbe4671915035276d8df41a7ef0b6a36dd101de48a4076046fdba3b0bec20ae010f04010000000007fc04707365740121089f9677efff5962164a434b0bffe53d90c271deda3eaf30c1d7a55105d24b874707fc047073657403210be6c538eee2e29d44c66a3e66fc8165afa4081557031826a070703cb69faf24380104220020c731ad44c00a2928d508ad82b05868cb42733a5b0d0b208f483307ce8c328d9307fc047073657404fd4e10603300000000000000015bee4d0045b0884354b05d0285abb287ee8e539e8146b92dceaaee6fc01af1a3730cece4c77caefdcfcea1073197ffb8b3ded97d0dda6f49752b31f23e196378a3da2128a8c45ecb7eb1c32f0c0dfa1ce7bc348e799f66d547476e976baece7445790064b34b1526c88cf54928acc906ec0925327d797d36d0db6a43633d7f963ec9b4123a5ea31b655882329afe2108d123f76857fd3ce344fcd651b3d3066aa506625c9309acead85fb6c8a7d977db5dd6cb6e2f99fb3535746258d42d95dd2103bbaf5d45c8a2dfaa2301eba08763bac8ab3b59bd0082a457bc0cb257c43ea6354348e73d8dee101864068f0e8e30e6711f1597d7b529a57e95fc0df813ea160f5f5152f341087868a680c1bbc4b2a427d18cf8f12cbc4304dd3b1ea4c916467ae48b3b53062ea046161170fbe6ca07462cf3e5534d638c91fe6919318c4b2e98ce0ebcb245680d6395ba746fbf510a9a36ad8d933b023eae39973a39162178148a897b5174940db46e4be54794cea11fafbed48b42eed27f9915cfc50c958e88bac551ab1c9bfa03653e558cf87a99ff13440f4808e27fb42ff3cbac9fe10d1de07dad4807c9f945784163214c739a9eed8bb2e7da6e1fdfa4aba5d5157787d0000b220145572d3d9253cde5c1132370c1849847633287660b429f20cf1f72e4ad6ae59154c3b8526fc5d30523ba962a25577427988d326e207c97c81b479540b1c63aed0a4b1dad9279879740b2f6a0bfc37aea8c81b3b35b630dba8d955afbba756b8ce9d2a9802939972c5f70efdee8778a98360eef15faf77e38627fcb4f98569d68ebad3bb667e5db46eb7f4214846e651224673dc998c55bdd9e0a1629497a75b76160865c7ac3af874bc45a42269508f183d2458835b1734791094122f75398da2bb7919c67221ee42242c298d744fcb920726b84bcb78d7eafc9e0f61a02de87ffc5c674390a33d722b50dc35bbc6788fe0fd24be7a9e358113a4e65b49655767b8f3c3bb86cd5a56c79f9148945af63492dffde82d682eca4787f203e49790650395c925e6eb68bbb3adda25bb784365c0b3e241177ca7de58252b8c79c5a865d1030f3bfd4d312bdf83bd28241389085433c34d747f9f45a0a636e700805e619a19739b15077d44d5e8969a37481896acebe7f350449c69b50376b7cf36e906d8a03aa7221de67c7fc4c5408b55e2562f7b783918004d93b284c0a1c3d596c7c18aef5cb77ad09172bfa888f5dceabf57f708f5ab61b1b4159742d3d35332e9942958ea7f39fd35cff66e84ea0ce3b38a85eb80dcc1201146fc3854cb40353a078f5435fe2becfa383b3a62564645250cf7feccff5414581e747166625477c70f5b0f579bd578e03e6b8ff8c3f0e8a82566199ff542b239f2999103cbb61602bc2f346702204e50c9ce7b85f3b8e144227ca8b9766cdbd498191c385e3a4f024c9396763eacdfe41b706fb23d4f065dbaa43d323edf1811950c71d4475a3e0913d3851be4e921cc933bb06b0aa20524267b0e9847b6de3883ab8c5be1eac17b06c946f19dc2244901890cc290f2e66147f7c47a4a29349555ca020e684ccba5f8a6f1be54e356654d3e8678c591633e11d9ee772940d92f07ab83228c0d8840cb9aae514c03358e973a2ef319a39a3ce819efc00e5a493fd582be164c1460f70fb2e103f09a2939f779377275be736ccd41f847133b3d400477582419fbd2d7ff328d88256cfadd750ed7a3c6657e332f635f0a90602b24135e705d1530531b7b738e686d83accd74874e160a5716191447f832d2f899476ec9c53204fc4ade5b75cacdc869b4088e009e12d85beaa3450889de0c86315755ec7744be592f058fafe62f9a89875bd2781d5d6928c8475f555e77eeb6e688bd8d3bee0a54fa1cb29c1b6b438d3f70ee4ac83fcb6f482575997e3a69240c6731b517d8241cd39dba6b02a9e3c94ff2470c61c693d32b1c7d22ba38f0da21d92150115d580249380500109215a05baa63474f773892b1870005e76a68853e6a8cd9f74ab3f41cf0730e702ce94c420dbf66a63f342d927923d7d25ca3c3823b6c352ae2ca127bf811c023205632ddb8f9191c2f3384a61038d1c4d32f808cbaea81d58f0aebc7c89bcb5b98f92849f4fec19cffc78173e601eb412aad24eacd74d17cce3a9ee76670367ed87c2da3db5e4ab01d4d9626d0ae00da7dbf6b8103d5994cf66ca56bb9aab9eabee2b14ef798d3fa5ed1dc16bb500a006c3320941c4c7f6f80c8b1bf79131a5e11ef38db7c42d4c4939711184ea414e2ec0cf5bdce3d7d0d72dc883b2595e5f0fe4c14cddaed61108c90c74b43cbf719bcf7a934bee760ab33f50cedfe3ce61dda3e4bee1ab4dc687f988cfceb207152f7a98c0fa3a114d2d6881034aeba877bbcc368ce591707da45becc48318f0558b3ff65d677578df9fd9e9a18d0cb08f2f5cd4f44925259225b1c4c5ed84ef30d136e7c66251329a223a1db0b485f1c634981f8860aec1f3dbda9442e5438f6fb09c7e1ab43e2b757911834df8502ce35e7be947771f7416f7ea97d26dbad7221614175e6b86f1a323e26c4f469236d1b1bf6ef28823234c73b275c5b0ff39e8c04d9dd8ff7f6a57214d803aa13dbf581295b92ce2b8a9c0e3fa8e4fe4e74c4bc2198fd010cf84681cf5f3fc9df1638c403006478b1cd4204ef3b7a6093116021118a839bd3ac270783e67096457a86d63654e268821ee742241ab5f7e91972da0a94f679b4c093d3f428d5876edf51459331df084f2fa245e3648e0cac904a82a7d323b965a39683ec0b2721105683e67d65fe10b8d41d0dfcd5c31756408c94cf425ae67f95ecac45391516875870386b675e24c462b1f7634f758723e6245da6a39da69cc2390374eb89c6c662d94eeb2f1835e233610072936be248e6a3ff87f9950c2eb2f88568c31dd30d1f0c0396a42f6be2505bf616c63f504dad5312fee2f083b406fa05cf3c998ba24237402681f0ec393de4650ddce3389d4c1541d4705d8f50c2c6d4864934394fba0c40df495fe3a5bf58a5498c1e63b5ee5f9a4b53dbd913252d4808f5bf5fc3c6dd74c86c974fc9e5afb1a7ee3d88738ab1fe9194881cb00197a31d648ae2448db872528d5f7c366188d9d98ea94497cb78ffacb5f6e8a2c8520d8d196fe0ed13e2b2a5a08dc45d8ff58a8c5d3bcbdc5d80c798acd0eabf146459e79db12c2a43c55d14b2dd608475c606fd4f943ae7cf62131691768f710fd718fda3967146daa8d4f34a3b8fe8084f4f3865e9e0cc1a0b0a799fceafd1b74f09f524822179ce38cf0f2c4c8623a3e3ab2cc20f5dccdadffacee62c120657e3d85fea93fab645b5fcdb812b130afbbd5b19e86aee66011b520b0affd84af4bf67a28b309cad66cec25a5de06390a4f2a5af47d59c006010a8ffd214149bbe47bf847fa94c2113723c9476c2e6dd84411bca16dc7bb096aaa3e9a9be27811b52838c78d16cbd89cad379bcc0cd966dadfa428f9d4d8bf133f7d21022ae3f966dbc1409c6d57cc46ff4434fd90d79b6c9e68ed3795ea6191a7e309783badaf8db9fbccbea905ff9d423370810f02add38ad3088cf3393e7c6d585b76fd78c67766fff03ff54c01228c6737da667147a8b5e722370a24db8c0165e34888920d70fb1356eb731d0024676444e2d37860eaaed9790f99069e622afe6ff12d516812022c46420006253248eb292908ab8658cd874ef05bd568547535fd54c1f0b5b816e4d90a1bd55670b96691e7633a2fa45be6a29cf7bbbcf9e5debb4b7a739b36b6b326b719a12cd0f5e3557a2fd94023d8c633fb697b85080a39734013b4ed9a7500aa8093edfc3810d4c890e608951e57af8447349cdf45a076449241a047085702dc3e44814390ceddc878791ab3a6503f48f48af25fe5cddf61e7870ce80e32e5f22d5725bfde4f319c2db7cf3ba3b9952202cd24210ab8d47fcdaa9ad5e2a9d2c7be1ed6b67cbc1a28ebe565ed0337c09c97d2d9608d97905c7201be7d4bac785d64caf783cb3ebff817bc5ff0448899537ce6911c9803744d06ae97e6d3aae037697986cb20061892ae72e05968e9bc54153bd745012af719fe7fd4b917689a6cbb94a9bc8cce51d234ffce7dca804e2b2759f473885855983b7b290806884fc66e724fa848af2de3164c611c630e5bea712cdd9a9943ca3ad55994e5587c5953f415171bdef3c42783b809bc5526a88aae66be626d73394a607ca32256198dbc026d9e09e9659ddb66736215dedee0cf69a24490a53b2c678e6caa2aaef10a4610f802fc5eccf558629554d6388465584514d3dd49fc00fb267c39bb746f76ad3cccabcc3cc882815bd9466d593270a5c9a04945dea7ad06ddb73e66b90270e859a109d52251d911e7177e07295ac9788ce970c1b718fb0c2f327f44fd0cef3cb90071ec85e958e6ae60bd134ae307720cdb10be5a0af8c051295df905447b46206b5e04d775b83e11c348458b1bb310ae25c54e8ed1488a95b2a576002198c80e0e69d14fb7bffcd89935faa6e3f9aed61e0492bb2bc334e389bd559806eff9e16643ddc4372ca83790a99bd4f5b042779ef7e3039858881c8ce0041d43ed6b1f42f18007d046fd6f65907cef73fd5e6cd514c4fa5ebb872b140d0b2ad43c58f2f2216522e78a19828baa34ba56d71414ae869a13cb708762565d754f0754561adbd9145d232034229d2840ef0c96f7af4b232c5e11ae9d018b87177a506b66571affdeb693e170dd12640e86fd430b64509d02694c52a54f23ea96e39be92b65c1abcb262a71d6e884183d4bc6cac8c79f6e94b51abe484794a42a8e1be721cd59383bdbf327a864b2cf27566f1270d82ab6e8b3b934e953b7d48ec4697172e0160b8435e8186a7ea685dd61402b0bef09137fc52e19ecb53674a1c0af17fbb0efc2b4d69572b32600fdfc3c85c79ccb2685c665aef16748b7f15862f435afaeef00f3f927cd3a60c22f137e9cb2c38a9652cee570a76351871ebc9b6fc720b9117b1306e8afb298e3a1d0d4b2c5ad5a21e9de4c0938a98daa35caa711bd6d3312a7e941b060c4a1ec211c31e53da263995d3be74a3ca5a970d3a663245a5d8eace336d9ee847619bb337e777b961805e808f7cfd8f09b93b6ce6c277396e6cf0a6153fb11625f421b02055dc53a0bb24786f4a74211bfdf44193e48b2c15c7c85acd3f4f0bd26644f9dc62653e366178645899dc06d191c785831b98de593519c0ac5849897a01b4f8c7fd559edce1c878bdb9dd091546c64225fa81b1c7dcd6fe72c8131bb160043976a5e891236d3552598c0c4fc734d1cc752c10306dfc8391f6d658ab8b7a1f350e1900edda29775ac8a531032bac968f6981889f13cab07f49c864c3ef3ff23555c170ee9730912465e6bb3b7508e11ba27001d9dc0da8b34954a7c46a2d0b0b75e73ad66278c8acbed3249936a6c76fe975954f7889bbaae5f73747e3ed02811b015beab9d1515e396d37b2a116b3cd8863517b88ee91a854e4740304f7be41123692181a8ae22090956ba619fb948d3f08108da17ac2484d3dd5795b1c716cb5ed3fc08b6449fec814018cd883b02256afadd1f35a04d9d43f661be624c0d59d0d397e8ad6917344203843495162217e79bade11ca32c0a6918350520e6c3f31f866b89e3497b518cdc056e760813ebea7fbf343db50ca2450d5b7a1c5f430859e2040ecfa70cb0c3e863a756ef6ae2e26c68b543d35beb44513f8295872df5b4062c9b80742ca7a9c2ec36a1d9bc936c7fa7328240a2db54463ca04a40dc0c9afe4d570012259c8c436d322483b17a705d60a283e0ea7545110e898ba43ac6130aebde014d237482307ff28f385fce8530814a3b3507fc047073657405630200039d46edc3d830d852edbdf28cbc023dd1666cc4a806ec9d4acb2c97865280698d61fb6b2a073be4ce75cf8193fa9b3d677146575a812873ae7eaa7b08110cb88904273dd65af35115dd116092a56ab45fb57178d8c5ed4cf99474ff760f6e987d07fc0470736574072103701e53a6d0b960398abf678382a4d17c5c153d1a2c8ffb76b302058ce915bb0d0007fc047073657401210821b4e7599b1b4faf29b521f1c442dfb0a893499d374c19db939c0c9a3b9798c707fc047073657403210b8529a893bd81e38743e8e3015095077f6e244a064d64708963c6af5024b6aeb3010422002058037c2d81d3122185c8704d4276e2629122c95b8ea68575c451628d37eea84507fc047073657404fd4e1060330000000000000001ddf2f500cf45e30e3911bb51a7ff633c1e329508e42d9aa49fa8248fa4d293b87005db08b17a472580ae2cdd53c40b2a16af885d6dfa3d5b3410d389b045e6c12405c635511ccf008390856f4c6d0ca472148d2969fd39e1307bfbb8f8268ce92398248f08df7268bbe23e13ac3801ad075376bbe9684db9b41d7b1148fa65a129e1d25193ad973ec7af631a0a30c5659409b0d00e6fe44c2c507d52afbee8059aee7650bee9d47936838e77f00cfec9de3b9efe72cdeefd80a19a9c8ddcd6cd9009ec96800f9fcd709f1432b5715466d601b5ed10b0dfbd09b954b109232fb5a24036b887d26bab43da7eaa303e7c8e9d02950610aba09f343a65a7cb4550d6f6e5c0eeb9410b68f85cc3b05b9340e2e9c94a473f2001f5aea7e875d29e8e0aa99c09afec4a5455258c803e55b89cf6e89796a6f3f9fe11ee05ec415c6ac08e0f1adf9dad681f8121f82e3a9402a2fe13a016dc10d4a605578317be0d9d3e02b0989903002bd35ec4970701da6eb6f9fd5e6cefad137dceffaad968d5ce522e77c76e665529f70c9eb805a240834f4c8c795912c37e7efeb73d4bab709aafb66bd645cf0addefdd83d185c1b4465ee16344575eb2aa3acb057c37d7c22cd03adc6701f03d4cfa20ca94458b3b87e3fb7de8fed28a755bcaccbd348dbc7f5aacbb25d19437d87cb48b88fc714f059b328c374fb2695a26537330fae42d3fcff40b07054be10508fa78a9173315506119973a9158828276edc6e8ac771476d7479d07ba73e9c5b58d61367d24435a1062dfa376546e843b34829103168db63b708a13894813a442f889a423054160b85a2584d36951136bafc490056f1c03c44580e2c7a12b170e5c7a3917720bbbb21e5da616649b554b7ff57dc84dc3935271a8aa6fb218becde208d83e76bb6197f5f4f729f3c57b4280c388bf4945206fa769b672ebd47ef2d0f777fc9dfb031cf7c333c6159a75a5b33ebc6c4683ef140a144a5ab15b2b6b72ba14ee7595679a0f7873a75b9a79e03676ae94eaf9ea8d3532460f3075f40c6b9848a183fe46651caeacd51551f308eab6ba8ac27b93865f5dea0fcfe1d7dbb745695dcf187a5955414763c88ec01d299f03cdaec48eba946c7ff6031f28a5e108651401b5447c0d21c449b387765a621c057eea7d494302222e3d1ff6ee9f8a0580671d9fe3ecc310e84b554e5c823d81b8027075f749b2dc8a6bc5a99fed4a0fc46fae59cc2aa9f1471ca2b0d9fafa56927fce0f1df92647ff5aaa083bfcb7078bd8ee142448d4e1f3dda670ad93feb21028a57ee9a8ae8880df5b3276e078555d868be0d8843b495e082d743328620f36f7e106733bcefac15076826cafce271caf1520cc8746948e71ea73eef5de770ecf5e0fe075f04d6c9cef1cc1f262e69fcfc89862877ffd520e25405d9d07efec82386640d97147e4a6df66bb1fa1f20dcc2ee1fd6364bc2024c0a4a2ec00b84616231c02aef16147df509cb830b9fb20111c60613d41169a24ea67c03cea48e1905b00eba8a61e967b9aa5b6e1264b0f3e2c051e47f54f45c6fb78b46b9993c7d223d51036cb77f5e31a4b30892e8fd7ae7028322d6402f60712f712f84443de083767c38ae88a38fd4e4bbec58015f4e49e36ecbde94f23d0061edfff0e9eb62b67327249d728c278f923748e4c1e225791c740abf9493198f073a6cefffba00d23715a14967a72cc7aebb81ecc6e8bc88ae63a47507296a573c415d0163219f3b20974ba3a32572d29a479b88b89c241e63e640bbb93e2da0b73024ff03516ee3ecfbd84348372cfb574817ca878172a779ff131492b86e64c1b7054cc5fdb999df4a9578bbdd6a6a2a798f053f4c7456173cb8cb9b61735e650d0394ea9effbef615629c1f393949095982345bfc02b9a3b3ec64d9173bb1285587048fca8c740b6d2265d3e727069fcb90282c78f1049ed7925113279474d0d873045851b397a8c26036c83906dccd0eabe98f7d6854d9abc2e6ff12d84c2840affa371cc2dc624fbce873f38570dc9eff33f5e200791bc052307f5c718d47fc2a205add3fd9de2a81cb452a0a7b4a08bc133e9816f6ba852735b813a1b906d4dbd1ac8a968a8adfb6aded0d3fb87d80132a4b45ad39274bb72df20d648a26aca4beaafb971e13094b6d6525bd418b91320964bd90d3a98fb32d69222aaef2ea95c6b84b6b6aaeca3f6789944fc7ef17d218abc7667ddff798b74a0d5fbcc33d22d028d207f82286fd777ea1e281d7eb88b665e29fcda067bf9ef82a190c920e260cbc44d394b78e0439bcaa6371f8717ad82e02015f21e5dc273de338102539bc924d5a3f897eb788e0f3cbb6e8a34590ff5370bcb0f671ce28d6ac0adea17f9fda49c784ae84464991fc71a31d320d62c4199e4f4e38f390ffbcc7f15922c3325451371bebfaed8f8a7d3eead71c65878a705a6163ef649bdc6ae7b81110a2cc9576da6b0188337160cd518fb30fd5b0c165ac3de81002490f36d29f3bfefa2b4796c070c6d7d971d18bb5a573cd48cb3c64dec5bbbd7f2f6f60bff3db4833bb64b426c6715021997350aab1751f0d5382087ec133c2c43342b31eca32a4c17db14148fb48f9b7a103b2c0bfc0dc95ffe097bd8f2213a3f7a43c994599b05dc35d469fdc025e23e483039f271d948972417153c849fa8dbf374693dabd59d398732020e90d8f443ba45a00b430168561de21db76b9b714ca8260fdc4ff1a5713e69ed7296f5a5a9d192474bc6e67788d6a44d46b69ac97d0b34b2b08aa79d5ee7e910d99221e1e7f6383628b5383cec4341e5c3f18ec3361b2f2ee5935ed40919a4f8892bf3467803b720d29388b7cd47067eed9be7648fbbafcc7bebfc31a30d02f38b7d6be1579c751aabf679fa6891adf66da2257432c10d399a8d496d1aba381b64a5e3ec9a65cc8419151b638adea994c3590f77bf390152894b2784f7832d986ac51b20ba9719d85509acdedc0282f27065c87bf483fc74b55579ecc233fd6c51822ae03e46ecdb15acf0204b67852d525168f409d2a4309c5d9a14b35905b836091964ff4fec0aa91bbd7f39919eeaebbaf75c63337a4dcd5ae37cb60fa14bd78157ecef35ddb1cfdc366eecd48aebb0f5b395e4161c158c46870fc89f8f5918aabf0577c914511cac7b189384eaddf7f03cc6706a9abf219ff1b293cc9fa2cac88b65af62f0493e30736b596c119149af07e840a43dba8d97455a7a95368395488304626d3b888069a0099c435cc11e5981412f79153577c9115a1812b1c4a9ea42bbf11b40fdf930bcc37e6a6c50a7e3d06bfe7043adb32244ae359993caad00eea5f1de90355326e921145add1020ef3c2cbcbd102e7b9a150ff9672697d31f86572843269978cbc4c3fe067417e84898587d4de009b33094c8e8102c07facbda62a2996e083d0618fd9651e17f0fc025a946e7c28d93e18675ba69d8811dd06a2cc1aae28de5a6af30f305cfd8a090832483e4ff7c974d47ac96d2f3f7baec94f965a116c2734f87f468ec33cee1a58dd2ccdbc8f6a0f2a50a739aadf4007c7a529844cd1ce5efdd42eb28a0f5f04fde00dea586e4b8cdb8469b36940de19feefd342285c29298afcd3ddc368f6365e9ee255f8c2b6f70c1bafafe10720402a668ac3a2cb8ee75cb7004455cb4221486c3dee64f8f25f1c8b1411437cf6ba70afac5182b21f0efc1b5c71dd59f71796d2719741b6d5c757d824cdfd2d9459569427951d6974d94bea1fbeb0e1a23ef88774b270a8bca65f01a00299258847ddce8af8a7626c802b29dd01d1dd9d2a7243b334c29c0943e11ddbfe82cdfbd506e81fab8775a1d3c4f6c0744e1086763ad84e8f51d601e24cd6fcba1409abbb1c6b5c9bb9eab8ca30282801448f86cd5d8ec187866f1ba738863f3995bf4084ebe8f41dc1ffe0cd47d5a95dc5fc0dde1559ba170316e085d0e385ecf8646bf787b5287960f07bff9d3d990b3be4b29f008de18ccb46dc2192d0fbbbb9e701d350aae205fcd2d7314112bdc393e2eeb0a96c5f2c767dea0b82e9549f46a270b2c69915711c144a7737e9003b1c1b8684e9f2abe66ad1678c32a0c6ce401ae2d7507ff32c8f6179433b94764a6e4ea0a363e9a03787502c67ec97724d78c1257499379ecc5cd006a13acbba05dc7f1310bc75b9ec6a09f4d95b2ec11952eb3dc3d2dfeb8678b10b5db162b44af56ada56f7e311d6c5ce46472d9ba2284126f8f579d59a9d3e81bb1b26a7ee59c3cca96252fd4ba8e009a213911619ab4184e83683969cc4c474e934f36e6ba4ea33d9e93e984f1603e259cb7f1a3824dd8764bbe30ae08166aca84e63615e59c31d2a968a0beccd40637db22b971d51a4c35ce83108d8975d758669bd83ff9602718a882b943f80745d95a2d5e07ad0acf8023e24589fd68988a350c0ad571470f8b9a906648895d312100cd18089465de942ae0c7c8bffb5d3705c729990721bb0497dddea6dabdd530c9ec90286cee5ba3e2b699eb2de55de8aa0012b38051862bf0a7a22d6cce4310dd8dc47c206d9eb7bf28f2a53afa8fd10836210c0c461e417be42d89ea659a76d5e3cba08daa885b7f0302c5df05c72f8257f60e2ad954891841e67d8b7184cfa47e51e9b36f6ed1400aa84c5058a1998d07709b8b46630d70c73552ada18713310dff4177e2143aada1038bae9a64e02870a7535598d766f447b4e25dbd009009cc0e3421067bd0cd10735469b308cfd7a094bbdaaef2e31c22dc6c1a6d4c7890020b5bd04ef649b56889b2031c1923a69002448dd5db1142384cf517b08096539cc537532f43afc33ca77beb2dfee921178ad51b04f10495365e60b4b7677880409716e0eaa3a1d649a871234f86787c2792bf1e04a635e3f22b8b3b1382be942605c3855a940cfa3825a2f8993312a512c81f92aea0fca95bd1bdb6b9774ef3f1fd15bfa1eae84ebb48bc9b55fb2141c55cd3188eeb5049b2e6f3360e60c5bb7d91c9028ebc9287b4b5541a4ca290288e08ca46f80eeabbf100f700c873d7e69dee7dc80b842004b2bb93f0bf533488028d1a1137371417d06785372ce942d4c6589cdb57514bde81960475c22393eb02a93b6560fc3e4fb6ba692dc362d38e33a41b7df222e9192fdc0e0499f110e681682e2b500c00947d62280482dde5e26010cf959fc717d0837c98634550376aaeb17c1c80e3c3245c36c68f56fc8be117ff84957a75e4aa4caddb38779f1c50086ad4863002127b6c8067f172aa78137908fff82b2297a53d6232c26a2e94bb25b7f9241013adeb36d1e437f2f6c0d983efdb78608e940390005d63c081eaef21d7f00ddf51a3fbbe6175be436a9b0b75f198c30efee2821ac5f088819eb96ba835999d0012e7a0c244268a658bc6b7845d10178283cb8add0b81405ccd64000c1835111511555eca14f7e3cc9274b45f817039ee62cfd95363cc66f5397f88822f790e0a86b6a69379dae77db24185394d9fc73880d39f6b3233dd8d3b912995b22905563ae8cb2b1f3491feffbbdf2c7d2e89dce1995d2429bb0a4c550860835aef589983d3170387971f8aec15c18450dbc9cd12f402589dfb17216e359072ceec8e9484f9b490a288dd4b268233c40ad23721961c390bae0a181c4cc8eb68eb4b2a5db6944042c6ef67550f9abf3b9084cfe8521b62d727416576a58591dc65f79f871958243ca4415d92d3e588c4205b4a3806d64224e94e8f04dbf7f75888246aae9f894bab1ea69d7e10b4f07e8cf2dcf70cc62571c737cb6b6c68b0e3fbe4b1931c8615a793fa3db0a45090458ff62ce8bf421907877e555cdb97d3709bbd8728c4432288861a56cbfeabbea5f225cd29e31d99eb788704a93696f5e81307fc047073657405630200035ed48216bc666598aac5498e9fe513a9e21eaf842d382767220cf98104bfd8866621efb63b2eed44028cdc9e2f64cc2447fe09f8d8a1eb3214272855b525d9ce24e6daee58effb4af28fcb0a4685d78d7995081b5cafd1cfe343aefc8e9cb23507fc0470736574072102b642f0e5b34746f2f6e3b511d037e16bc720292da4ea2fb31ec09f6fdbe777ce00010308f40100000000000007fc04707365740220230f4f5d4b7c6fa845806ee4f67713459e1b69e8e60fcee2e4940c7a0d5de1b20104000007fc0470736574012109a05049129b0d9e61c1bb87a9fa02c2435be35e3535082a772f65222f2e4a48cb07fc047073657403210baf4431fbb8f0227bfc0008368606a4b8f2bc1706e1a06cd4d83706217b74f5b90104220020cd4ed5f0db8c450e8b0be595b6410c1759c19f1f6926279095c83dade9862b6d07fc047073657404fd4e1060330000000000000001a4092701f9170991583ec8b5c9b5056ddaba7637f7d6733a57dc4990acba6d15e9eb5dca55528e179b98a9e09e05ba940b59558b768194ca046c22e12ea310ec05bcc795ea419277649d40b145e6f0accc31f2d7eb39b29b51d3ba3410536b9bb37bce9014d352b496b93161fc799b23939ee635f25c4cbd6605029722ac2bfed7d55fe4120c0cc880661ea3313d700e261ba973bea5df4dc4d8a05652d193c5edad01945862943a6756d4b0ddc93ad5a444ecb054bcfbbba3635aa752d9c4fe8f93fc56c8066b3fe344143d65328025f5184308f2016eae65df8b0f1818f59f5a9539eec9c9c94704ecac269b008ef25f67ab2b9ab4e903b1f2372d1d3988b86e5efa639f9f964599df8559622c8d11f6bc4f706c74e4a603a3798005e210f93d9e6b59f8ccac907dc9cff127c552c8c89981e1b91c817cd365422eb6bb0c7ef4ddddabd306b0c32a98464973dec30def4149f8e9f35de6840cbd0ce8a2f2b5dec15e3f3c27d0d2720159cabb3ff2f73b4571eb53ec735d7b0f27bf4d23cd8b0fba14d5921d464beb3fd4f2fcf844f76a7f7f129a3e7e1c4a6e4f07490f2cfbac4e6730148397c73720d35cc5a46fdb1e774e17f7b951887c1c72ae4cb25ae99bee652ebb2ffd9f4c9400ee0870b27a5dd8fdb8224aab6738399587b4513d3441e26b898b35f739d64047ce8de70347042fd18c3797b1de82cfe23521dc8e5c36e286c05d4f81508e282018cd8d263164512e6ab02a22b3d5d489e6074f9370e218a3adf8afd229659f5046749db9615541408739d4f0646a853b25f8e549e85708c368e45f3e1d20ab47a4ed647b820a360e4e351e4caf74810098f0df4bb74e0e69f2db3284c30d24a0d109d16c37509557ce15c81812bde78085f31cd7c93140fc43d6580abc7ca2adfe6354510fd8104c0f1ffe46d24f31bea808376ac27996fb992de15b30abf4df6f4d08860bec27a95bcee0df8f0a5bd7f72938ca9e917f39c5425bff826c4a84a1fd70cff87be2e8619e0d3b729f0aadc10d4b70d10c2c020a99d03424a595294dd34b84c83a2d434b98fb116e2ebc8b2bc444740ce090816218ea61da172e30db5e78a58ef495812c287e3cfab7bffada0d6f2fb3c153f1a225bfb46e7e9bae9b666e72c35597797927e1bf02d1488ba90948f07dc12f6d8b61bc04d82994708725e0ccf5d76dcac946f36895402e84856b3e25567156040510fb299b88c45713175c54fb3d54aa6d383c423807778a92b7d9bc8fa347923749d18c96b20cea608b6380b57c35b4408f724046f6f65fc0d71e237c39376e1e769cd0234473a261c76553c655de0e4aabb4fd44d0247e4ef08f48bbf13a8cd366491e834a47f8a5cfbd6ca91c832fe4f77b3b3140a6c1c70055d52f0aa67e7d3ba18e5bfb09f738141a611002ff9e34188d540ac42f48ee06f6925cbf3cca5ca033c4fe089650a2b86a8350367e9cfbd07fac9667c0171f54311cd5b37157678b3d6155f0bd12ce53f6599fbc5beabb1f2a5424eb3f52ca3c1e0779d9cbc5e106693ff12d6e66c51bb1d12dfaeb70bc56d5870fb5ce4b040f86d7725ae53b1844b07557feca4d0e4c55a9cb6b6164c4cd3fda89f2a7259a4cd7682de9d8541af2e18b4e49218ef48d97df114971b298a6c4af231a432d4ac295d0d1947e09ccf41ab104e5435e7dddc0a6815b636a31be9a0d9cee2f22c745f05f384bd703fbf4bbcfeadf177abf4ca4524f38a681e5436a06abf9ca70c7569a7bcb8337b0b0c280b5f790ebe1258bea9c1da58c65c13991efc1ef8f7c75ef28affa340d84b3db3f4f188b1c7f437b024dfa6207d5329a5a7a0a56018b1f96a1963961065e07e3b2759f7e27ed707f5807342bad0935ed42609849d7a9d11addf8a92df7933e353a9e86213db0a27285e432228cf2166d3fa2a7f6dcc4f1331303f8db6929a3c0fbd6e82ba4496f3eb2812c986f3e2e627240a9102089725057c1e5dcaa3bcc5efdd6ba7e8a496f609aca3dd82816552c669c255283f9372be7d8f12b044f8c41180aac612245945a4467fa806892d55ff425adbbe92bc892698a32d39d7c23be4ecf4b07d79970eb3db84ad3ce589bb8b134761a442f8ca4e2020a4a42912753603f72738d5ca88c5d8280c3d8af9e83c18be420bb87db4b82a98d3af42f9191d4023eb22f428def2ee99d04d1497cb8205b67c9ca893f7afba077bae5fc11cfeb53d882763f2eb6731bab373923a63dda3ee1c1b6207e0ad0884290333dfae3f80e85cc50a241c73d7d99998e9b14c3e52e660edfe594e1ddcef04402e8fbf9061a5e0b3441a1cea68cd7e067fb146f57f370cc94ef4f28f4f5dd36f45173e40ce91d021465610b85b5f1a98e6908a17c5e138f2dd7da2769bad8789eed99828e8f23952bab7e9ead5fa9bac781fecc93de7927544736fd5c57f1da32be31b85657c313cd02104e1b889426bf4c8e9daa741278ae3966ea673cd3fa164ea7cc947b34f86c92084043ae846aecfbb15535a9b21e27fcda9a21bd8210721355b4331d01e57227bf6572d9538e4998313c5b8bf6e2f3f7bdd7510283f20ebae59b7b0784c0759dbf1036645c5d673edb45245f5e78407978b63d5c25ada76b176dcff53e76801d7c2784d4687561f32e7a32175c0fc77227b3ab0a4054462d04446e9c77f30cc87a91dbcf27516c956dca6b93bb4315f2f0765981e7525a510410af05c462f08d328cefa4bf8530250f5a4d3fa7f58f5a48db45cd68d0dd53a2c66758a20184cf226565ce558e60f0af982b02672f8ab14333349a5e5a5dcea61a09f93addea3858fea4e49c84f5d8269a2fe52f072d66240e7d30b7345c841ac22c16ee979c0f980567f24bb4bc2997ded6fe345d1e95c1b5cdcf006eb17d492bf3119f1df2404ff9bfa39568a52fadf98ac6d5a4653862d91b995ab166fa9de73478f7e339941e036b621f7d773a5413471d6e41a68c02ed89a4882bfade2b10e399f4515470ef43930a911609911f8b66bc060ebb186cdc4c1aa3cb573d696b0f48a655f8877f68f678bbf467ec872724181d6f983682389fc8a61a7525bcd61ab37930e6eeaac82b7adaa145e2a0bf67e235a657949708f0640ec802a174b1bcd7ca384e09b6f0e811f553609e88c5e45252d0d9ecfa42ebb69b7c2d22bbbc6b33c79f3506806862d7600e62c51c4d909472add5eb08e2c5a8ca3d58901a49e77f3df8841de18a30a9bc321ae43c712dbb9f08b457dd3e3f13244ae03da16acd6d3e861efae625478a89020655f0de72ac174a50834db564d4e60bef51e28954a938c64a6ee290523337153aa4d6cfaa00826d2aae1b57e3ab857e10cf2b497597ef9395fe6afb3d74b21c5d44281f756e018539ce8b7f4bc663db1eac9b976da2f994b193a30bde0394b7648b55ad9bde958ec5bf89eab516d4418451d8cbca637c1d6dfdef61712e76aa7f12151d5717ba1af71c4754136563ff2667bb1603cda51baf8a575d4069262179828d54694382f6bb93b98ab9d53d29793a524ae9c42c12dd42067584c4a96f6c15fe590bd8616983abbf453ee038f385a1265f7856009646cdd6f409d9e1e7fd36e1cedda1137429964b71af9d438da0858e817ca746438e0949dcfe49fc67ae967d13d1d1aa37c2e410bb95609c7ba0586c8fccdcca933b1a85ec97d1aff670004f71232bedbd192ba5e5a681867470c4e146221bee322a5f458a2bea1316d3f4be26efbcdeb4b1062e58f2fa23b144cfdda55aad3ed7142653c7948b6d854abb8d1201e9a4de07b8985fc194e58ea08b4c8528adcd73ae6bcf5493b7b8ae1f663ace587a87d5a341828612bf82605ce6cc286ee0161631ba06d704d2f52e37e3dbe44fc40c4171446d0afe69cf8efac8657d9d5307f158d844bd3664865724aa9907d2ccaf4cae78e056ee78815cbcdccf4b11e181a1d2841b0146eda60d561762a7e3512dfd59fc133713e5c056cbde75d5b536d632338fe83a8d02a4b7fa9a6f1a5df9de85c88b944581294609c880ecb5eb45de087524d896486c200ad68f5c45e43894d6e84493bed02602ab075c8d1e5e5be012e4ce474423bdd21d8d6662e182a2ea7eb30f2604b468a25c417c15a2b55031563810b35f33503cdbeb46de12c0482c70b07b5ca3c4e2aa21be75c33a23e73c03379c434dc8bff54dc40b0a34f476d0fd1de0422ae6edacc8a729ed2443315336b208ceafa68a229592e42f49501cf03fcf04ed2ab60cf7c31bf4d498f10569eb3666501cb8ec6e22f1825b7e69f632c24180c3af0d658dccd1c5896ae71b5ce46dfafdc12f94a7f8f3d1bf1eb769f52f43238ed411a97e55625ddc208affbae8ade42829c82cf4f62423830db9ca4091fffe3d282c578552649a34cbfeef3d58e020978137a44fefdb9083186dfd712301431b78095a0997f0764f26e084ee5a6d1d7b24b3b0ae4100da91329f6e8a0a92f3fd94c8b53270b44b9d419e101e18bbf128c7a3492e8447533b7586a81e52366bdf2c376a57847b8a44f7b55eaeee6ab2f06596a87ccad4a60881bcf4b4b5d5f0de85593b643c0c4fe1771a0cb5bb0402fae0f1a2dd811d6495676ad718b73d4b86fc79ce074aa992487108dcb4d908f0da654a3e1b8dc28cc2fe35762afddf2c93fc7a0593ff7c7aabce02dffa8817e66205b179f37bdda376d25d6bbcc83a15ad757bb7843aa03d2f7193d8d707ccf4de1f5c8694aa212219752addd55cbb412c05118c30555ca7ea820bf3440d1dae3332947a1cfc22e366d1ad120b906274883d7769983eab6afe18a253fc6355f81f60eb54f6ef7a48ac185d7e61d6580852d4b98443ad304ab8e7725468034d2ecfeb68228060bad59a4deaa40843d0cfe0a1e58855113bb7c5965254b82cf3997924d0a8b1711b1e1e5b28343168f64fa9bdf8e5158f33c91112f61ba782a4f97c5456c9c8756adf53a7d919ad90654a1c035d8686f83475038580df22e4a72ea9f0cb73470f0b52544cd7916f6487afd32e0527a311f7bdb29e4e4dab266b7221a2c49e42d8ab06ab6d16efee2a0e0bab140aa34b53f70c808f3966f1a171bdc789e23ca0246328dcb1680c765fe262048b869c56f381bb7ded54e1486c0a3660d990f4bf0e5b4eec4cc0c3abf4edab6346cb531194c27de0d85fbd39f86d1839854a91291164823db1fd76397800c3b62b418bb3a894840ecc78579dd242314da99f01df55a45dadcc87e4b216aa0d817e60673c9807a75185e52a70f04ab8ea28cad805c37fae5417f89af44d4a5728c187c74ea736f21681fa7f93dd9bcab9b510febf2c4b5c64cbedb6b59b77a8816728dfbaeea423bba4663ce831af234352f8c68c47dfee91724c99eea5940f57b4f1d9660f0021892a2d39ce7ff235425942f2007b4e08f2002018f720e0339bfa2704a9d74798b13c6fda733d965666ec5592d1d6dae7af6efe5c87cf48d40858937b1ecde3445ab2c1ba1e87e1c2f3ce696baf3efb30ecbd9dbfab121a142ebfb4f09f343f37e851fcb7bf011f2117881098afc5a584e6aaa79f11d4d540874ab905787577e6407a3aaf293c886b58cfe9bed8a3dacda2a2ce41f95e72e46baf65ca666f61bb548afe8f92e1c4ada258f46178a4591015678fc542d412f7ed323d2629c127890ad9c2151261c4869f59db9648e09c25bd5ad8cfde27ea4ef22666ae0f30a4d25ca5cf42ddf3f75d2121c46e28f565d561c9c5ffbefc847ecb75a2595c3e410c1704d6fa62fa5fd54139d95217734ff4e596f2ac975bbfb8fda29f7e6f211eb165480e44fde387d4833f89c7162c1bda3265a5271946c5392921861ad5d9e5b672afe4778301d7a8a8d8a03ca1c99d73b2ee43281c0b88ca4292a5ea29a0e2377007fc04707365740563020003c54f16cef0fd4185f35dc6784047913c89883f72b68aa78c16f144624430909da01633eb2b4b13eccc2b7a7ac5ef3b13505cea54e1d390944b5680e6860184e35111675dce504784f4ae8121dbd1f76df3d55ef722f3f73b5b7723efe2fd34b107fc0470736574072103652ba5800d63722adef5232d31ccc12403055de720f0155fc47bba5750ccedd400 \ No newline at end of file +70736574ff01020402000000010401020105010401fb04020000000001017a0bab8c49f1fce77440be124c72ce22bb23b58c6f52baf4cdde1f656056cd6b96440980610bc88e4ab656c2e5ff6fe6c6a39967a1c0d386682240c5ff039148dc335d03b636cc4beba2967c418a9443e161cd0ac77bec5e44c4bf98e72fc28857abca331600142d2186719dc0c245e7b4a30f17834f371ca7377c010e20cbbe4671915035276d8df41a7ef0b6a36dd101de48a4076046fdba3b0bec20ae010f04000000000001017a0b90df52169792d13db9b7d074d091aaa3e83aff261b1cc19d291441b62e7a03190899a91403ca5cd8bded09945bc99c2f980fd27601cada66833a5f4bc108baf63902e8bed2778bf381d17241be029f228664c7d1522ced55379e275b83fe805b370216001403bb7619d51d2af2c5538d3908ead081a7ef2b2b010e20cbbe4671915035276d8df41a7ef0b6a36dd101de48a4076046fdba3b0bec20ae010f04010000000007fc04707365740121089f9677efff5962164a434b0bffe53d90c271deda3eaf30c1d7a55105d24b874707fc047073657403210be6c538eee2e29d44c66a3e66fc8165afa4081557031826a070703cb69faf24380104220020c731ad44c00a2928d508ad82b05868cb42733a5b0d0b208f483307ce8c328d9307fc047073657404fd4e10603300000000000000015bee4d0045b0884354b05d0285abb287ee8e539e8146b92dceaaee6fc01af1a3730cece4c77caefdcfcea1073197ffb8b3ded97d0dda6f49752b31f23e196378a3da2128a8c45ecb7eb1c32f0c0dfa1ce7bc348e799f66d547476e976baece7445790064b34b1526c88cf54928acc906ec0925327d797d36d0db6a43633d7f963ec9b4123a5ea31b655882329afe2108d123f76857fd3ce344fcd651b3d3066aa506625c9309acead85fb6c8a7d977db5dd6cb6e2f99fb3535746258d42d95dd2103bbaf5d45c8a2dfaa2301eba08763bac8ab3b59bd0082a457bc0cb257c43ea6354348e73d8dee101864068f0e8e30e6711f1597d7b529a57e95fc0df813ea160f5f5152f341087868a680c1bbc4b2a427d18cf8f12cbc4304dd3b1ea4c916467ae48b3b53062ea046161170fbe6ca07462cf3e5534d638c91fe6919318c4b2e98ce0ebcb245680d6395ba746fbf510a9a36ad8d933b023eae39973a39162178148a897b5174940db46e4be54794cea11fafbed48b42eed27f9915cfc50c958e88bac551ab1c9bfa03653e558cf87a99ff13440f4808e27fb42ff3cbac9fe10d1de07dad4807c9f945784163214c739a9eed8bb2e7da6e1fdfa4aba5d5157787d0000b220145572d3d9253cde5c1132370c1849847633287660b429f20cf1f72e4ad6ae59154c3b8526fc5d30523ba962a25577427988d326e207c97c81b479540b1c63aed0a4b1dad9279879740b2f6a0bfc37aea8c81b3b35b630dba8d955afbba756b8ce9d2a9802939972c5f70efdee8778a98360eef15faf77e38627fcb4f98569d68ebad3bb667e5db46eb7f4214846e651224673dc998c55bdd9e0a1629497a75b76160865c7ac3af874bc45a42269508f183d2458835b1734791094122f75398da2bb7919c67221ee42242c298d744fcb920726b84bcb78d7eafc9e0f61a02de87ffc5c674390a33d722b50dc35bbc6788fe0fd24be7a9e358113a4e65b49655767b8f3c3bb86cd5a56c79f9148945af63492dffde82d682eca4787f203e49790650395c925e6eb68bbb3adda25bb784365c0b3e241177ca7de58252b8c79c5a865d1030f3bfd4d312bdf83bd28241389085433c34d747f9f45a0a636e700805e619a19739b15077d44d5e8969a37481896acebe7f350449c69b50376b7cf36e906d8a03aa7221de67c7fc4c5408b55e2562f7b783918004d93b284c0a1c3d596c7c18aef5cb77ad09172bfa888f5dceabf57f708f5ab61b1b4159742d3d35332e9942958ea7f39fd35cff66e84ea0ce3b38a85eb80dcc1201146fc3854cb40353a078f5435fe2becfa383b3a62564645250cf7feccff5414581e747166625477c70f5b0f579bd578e03e6b8ff8c3f0e8a82566199ff542b239f2999103cbb61602bc2f346702204e50c9ce7b85f3b8e144227ca8b9766cdbd498191c385e3a4f024c9396763eacdfe41b706fb23d4f065dbaa43d323edf1811950c71d4475a3e0913d3851be4e921cc933bb06b0aa20524267b0e9847b6de3883ab8c5be1eac17b06c946f19dc2244901890cc290f2e66147f7c47a4a29349555ca020e684ccba5f8a6f1be54e356654d3e8678c591633e11d9ee772940d92f07ab83228c0d8840cb9aae514c03358e973a2ef319a39a3ce819efc00e5a493fd582be164c1460f70fb2e103f09a2939f779377275be736ccd41f847133b3d400477582419fbd2d7ff328d88256cfadd750ed7a3c6657e332f635f0a90602b24135e705d1530531b7b738e686d83accd74874e160a5716191447f832d2f899476ec9c53204fc4ade5b75cacdc869b4088e009e12d85beaa3450889de0c86315755ec7744be592f058fafe62f9a89875bd2781d5d6928c8475f555e77eeb6e688bd8d3bee0a54fa1cb29c1b6b438d3f70ee4ac83fcb6f482575997e3a69240c6731b517d8241cd39dba6b02a9e3c94ff2470c61c693d32b1c7d22ba38f0da21d92150115d580249380500109215a05baa63474f773892b1870005e76a68853e6a8cd9f74ab3f41cf0730e702ce94c420dbf66a63f342d927923d7d25ca3c3823b6c352ae2ca127bf811c023205632ddb8f9191c2f3384a61038d1c4d32f808cbaea81d58f0aebc7c89bcb5b98f92849f4fec19cffc78173e601eb412aad24eacd74d17cce3a9ee76670367ed87c2da3db5e4ab01d4d9626d0ae00da7dbf6b8103d5994cf66ca56bb9aab9eabee2b14ef798d3fa5ed1dc16bb500a006c3320941c4c7f6f80c8b1bf79131a5e11ef38db7c42d4c4939711184ea414e2ec0cf5bdce3d7d0d72dc883b2595e5f0fe4c14cddaed61108c90c74b43cbf719bcf7a934bee760ab33f50cedfe3ce61dda3e4bee1ab4dc687f988cfceb207152f7a98c0fa3a114d2d6881034aeba877bbcc368ce591707da45becc48318f0558b3ff65d677578df9fd9e9a18d0cb08f2f5cd4f44925259225b1c4c5ed84ef30d136e7c66251329a223a1db0b485f1c634981f8860aec1f3dbda9442e5438f6fb09c7e1ab43e2b757911834df8502ce35e7be947771f7416f7ea97d26dbad7221614175e6b86f1a323e26c4f469236d1b1bf6ef28823234c73b275c5b0ff39e8c04d9dd8ff7f6a57214d803aa13dbf581295b92ce2b8a9c0e3fa8e4fe4e74c4bc2198fd010cf84681cf5f3fc9df1638c403006478b1cd4204ef3b7a6093116021118a839bd3ac270783e67096457a86d63654e268821ee742241ab5f7e91972da0a94f679b4c093d3f428d5876edf51459331df084f2fa245e3648e0cac904a82a7d323b965a39683ec0b2721105683e67d65fe10b8d41d0dfcd5c31756408c94cf425ae67f95ecac45391516875870386b675e24c462b1f7634f758723e6245da6a39da69cc2390374eb89c6c662d94eeb2f1835e233610072936be248e6a3ff87f9950c2eb2f88568c31dd30d1f0c0396a42f6be2505bf616c63f504dad5312fee2f083b406fa05cf3c998ba24237402681f0ec393de4650ddce3389d4c1541d4705d8f50c2c6d4864934394fba0c40df495fe3a5bf58a5498c1e63b5ee5f9a4b53dbd913252d4808f5bf5fc3c6dd74c86c974fc9e5afb1a7ee3d88738ab1fe9194881cb00197a31d648ae2448db872528d5f7c366188d9d98ea94497cb78ffacb5f6e8a2c8520d8d196fe0ed13e2b2a5a08dc45d8ff58a8c5d3bcbdc5d80c798acd0eabf146459e79db12c2a43c55d14b2dd608475c606fd4f943ae7cf62131691768f710fd718fda3967146daa8d4f34a3b8fe8084f4f3865e9e0cc1a0b0a799fceafd1b74f09f524822179ce38cf0f2c4c8623a3e3ab2cc20f5dccdadffacee62c120657e3d85fea93fab645b5fcdb812b130afbbd5b19e86aee66011b520b0affd84af4bf67a28b309cad66cec25a5de06390a4f2a5af47d59c006010a8ffd214149bbe47bf847fa94c2113723c9476c2e6dd84411bca16dc7bb096aaa3e9a9be27811b52838c78d16cbd89cad379bcc0cd966dadfa428f9d4d8bf133f7d21022ae3f966dbc1409c6d57cc46ff4434fd90d79b6c9e68ed3795ea6191a7e309783badaf8db9fbccbea905ff9d423370810f02add38ad3088cf3393e7c6d585b76fd78c67766fff03ff54c01228c6737da667147a8b5e722370a24db8c0165e34888920d70fb1356eb731d0024676444e2d37860eaaed9790f99069e622afe6ff12d516812022c46420006253248eb292908ab8658cd874ef05bd568547535fd54c1f0b5b816e4d90a1bd55670b96691e7633a2fa45be6a29cf7bbbcf9e5debb4b7a739b36b6b326b719a12cd0f5e3557a2fd94023d8c633fb697b85080a39734013b4ed9a7500aa8093edfc3810d4c890e608951e57af8447349cdf45a076449241a047085702dc3e44814390ceddc878791ab3a6503f48f48af25fe5cddf61e7870ce80e32e5f22d5725bfde4f319c2db7cf3ba3b9952202cd24210ab8d47fcdaa9ad5e2a9d2c7be1ed6b67cbc1a28ebe565ed0337c09c97d2d9608d97905c7201be7d4bac785d64caf783cb3ebff817bc5ff0448899537ce6911c9803744d06ae97e6d3aae037697986cb20061892ae72e05968e9bc54153bd745012af719fe7fd4b917689a6cbb94a9bc8cce51d234ffce7dca804e2b2759f473885855983b7b290806884fc66e724fa848af2de3164c611c630e5bea712cdd9a9943ca3ad55994e5587c5953f415171bdef3c42783b809bc5526a88aae66be626d73394a607ca32256198dbc026d9e09e9659ddb66736215dedee0cf69a24490a53b2c678e6caa2aaef10a4610f802fc5eccf558629554d6388465584514d3dd49fc00fb267c39bb746f76ad3cccabcc3cc882815bd9466d593270a5c9a04945dea7ad06ddb73e66b90270e859a109d52251d911e7177e07295ac9788ce970c1b718fb0c2f327f44fd0cef3cb90071ec85e958e6ae60bd134ae307720cdb10be5a0af8c051295df905447b46206b5e04d775b83e11c348458b1bb310ae25c54e8ed1488a95b2a576002198c80e0e69d14fb7bffcd89935faa6e3f9aed61e0492bb2bc334e389bd559806eff9e16643ddc4372ca83790a99bd4f5b042779ef7e3039858881c8ce0041d43ed6b1f42f18007d046fd6f65907cef73fd5e6cd514c4fa5ebb872b140d0b2ad43c58f2f2216522e78a19828baa34ba56d71414ae869a13cb708762565d754f0754561adbd9145d232034229d2840ef0c96f7af4b232c5e11ae9d018b87177a506b66571affdeb693e170dd12640e86fd430b64509d02694c52a54f23ea96e39be92b65c1abcb262a71d6e884183d4bc6cac8c79f6e94b51abe484794a42a8e1be721cd59383bdbf327a864b2cf27566f1270d82ab6e8b3b934e953b7d48ec4697172e0160b8435e8186a7ea685dd61402b0bef09137fc52e19ecb53674a1c0af17fbb0efc2b4d69572b32600fdfc3c85c79ccb2685c665aef16748b7f15862f435afaeef00f3f927cd3a60c22f137e9cb2c38a9652cee570a76351871ebc9b6fc720b9117b1306e8afb298e3a1d0d4b2c5ad5a21e9de4c0938a98daa35caa711bd6d3312a7e941b060c4a1ec211c31e53da263995d3be74a3ca5a970d3a663245a5d8eace336d9ee847619bb337e777b961805e808f7cfd8f09b93b6ce6c277396e6cf0a6153fb11625f421b02055dc53a0bb24786f4a74211bfdf44193e48b2c15c7c85acd3f4f0bd26644f9dc62653e366178645899dc06d191c785831b98de593519c0ac5849897a01b4f8c7fd559edce1c878bdb9dd091546c64225fa81b1c7dcd6fe72c8131bb160043976a5e891236d3552598c0c4fc734d1cc752c10306dfc8391f6d658ab8b7a1f350e1900edda29775ac8a531032bac968f6981889f13cab07f49c864c3ef3ff23555c170ee9730912465e6bb3b7508e11ba27001d9dc0da8b34954a7c46a2d0b0b75e73ad66278c8acbed3249936a6c76fe975954f7889bbaae5f73747e3ed02811b015beab9d1515e396d37b2a116b3cd8863517b88ee91a854e4740304f7be41123692181a8ae22090956ba619fb948d3f08108da17ac2484d3dd5795b1c716cb5ed3fc08b6449fec814018cd883b02256afadd1f35a04d9d43f661be624c0d59d0d397e8ad6917344203843495162217e79bade11ca32c0a6918350520e6c3f31f866b89e3497b518cdc056e760813ebea7fbf343db50ca2450d5b7a1c5f430859e2040ecfa70cb0c3e863a756ef6ae2e26c68b543d35beb44513f8295872df5b4062c9b80742ca7a9c2ec36a1d9bc936c7fa7328240a2db54463ca04a40dc0c9afe4d570012259c8c436d322483b17a705d60a283e0ea7545110e898ba43ac6130aebde014d237482307ff28f385fce8530814a3b3507fc047073657405630200039d46edc3d830d852edbdf28cbc023dd1666cc4a806ec9d4acb2c97865280698d61fb6b2a073be4ce75cf8193fa9b3d677146575a812873ae7eaa7b08110cb88904273dd65af35115dd116092a56ab45fb57178d8c5ed4cf99474ff760f6e987d07fc0470736574072103701e53a6d0b960398abf678382a4d17c5c153d1a2c8ffb76b302058ce915bb0d0007fc047073657401210821b4e7599b1b4faf29b521f1c442dfb0a893499d374c19db939c0c9a3b9798c707fc047073657403210b8529a893bd81e38743e8e3015095077f6e244a064d64708963c6af5024b6aeb3010422002058037c2d81d3122185c8704d4276e2629122c95b8ea68575c451628d37eea84507fc047073657404fd4e1060330000000000000001ddf2f500cf45e30e3911bb51a7ff633c1e329508e42d9aa49fa8248fa4d293b87005db08b17a472580ae2cdd53c40b2a16af885d6dfa3d5b3410d389b045e6c12405c635511ccf008390856f4c6d0ca472148d2969fd39e1307bfbb8f8268ce92398248f08df7268bbe23e13ac3801ad075376bbe9684db9b41d7b1148fa65a129e1d25193ad973ec7af631a0a30c5659409b0d00e6fe44c2c507d52afbee8059aee7650bee9d47936838e77f00cfec9de3b9efe72cdeefd80a19a9c8ddcd6cd9009ec96800f9fcd709f1432b5715466d601b5ed10b0dfbd09b954b109232fb5a24036b887d26bab43da7eaa303e7c8e9d02950610aba09f343a65a7cb4550d6f6e5c0eeb9410b68f85cc3b05b9340e2e9c94a473f2001f5aea7e875d29e8e0aa99c09afec4a5455258c803e55b89cf6e89796a6f3f9fe11ee05ec415c6ac08e0f1adf9dad681f8121f82e3a9402a2fe13a016dc10d4a605578317be0d9d3e02b0989903002bd35ec4970701da6eb6f9fd5e6cefad137dceffaad968d5ce522e77c76e665529f70c9eb805a240834f4c8c795912c37e7efeb73d4bab709aafb66bd645cf0addefdd83d185c1b4465ee16344575eb2aa3acb057c37d7c22cd03adc6701f03d4cfa20ca94458b3b87e3fb7de8fed28a755bcaccbd348dbc7f5aacbb25d19437d87cb48b88fc714f059b328c374fb2695a26537330fae42d3fcff40b07054be10508fa78a9173315506119973a9158828276edc6e8ac771476d7479d07ba73e9c5b58d61367d24435a1062dfa376546e843b34829103168db63b708a13894813a442f889a423054160b85a2584d36951136bafc490056f1c03c44580e2c7a12b170e5c7a3917720bbbb21e5da616649b554b7ff57dc84dc3935271a8aa6fb218becde208d83e76bb6197f5f4f729f3c57b4280c388bf4945206fa769b672ebd47ef2d0f777fc9dfb031cf7c333c6159a75a5b33ebc6c4683ef140a144a5ab15b2b6b72ba14ee7595679a0f7873a75b9a79e03676ae94eaf9ea8d3532460f3075f40c6b9848a183fe46651caeacd51551f308eab6ba8ac27b93865f5dea0fcfe1d7dbb745695dcf187a5955414763c88ec01d299f03cdaec48eba946c7ff6031f28a5e108651401b5447c0d21c449b387765a621c057eea7d494302222e3d1ff6ee9f8a0580671d9fe3ecc310e84b554e5c823d81b8027075f749b2dc8a6bc5a99fed4a0fc46fae59cc2aa9f1471ca2b0d9fafa56927fce0f1df92647ff5aaa083bfcb7078bd8ee142448d4e1f3dda670ad93feb21028a57ee9a8ae8880df5b3276e078555d868be0d8843b495e082d743328620f36f7e106733bcefac15076826cafce271caf1520cc8746948e71ea73eef5de770ecf5e0fe075f04d6c9cef1cc1f262e69fcfc89862877ffd520e25405d9d07efec82386640d97147e4a6df66bb1fa1f20dcc2ee1fd6364bc2024c0a4a2ec00b84616231c02aef16147df509cb830b9fb20111c60613d41169a24ea67c03cea48e1905b00eba8a61e967b9aa5b6e1264b0f3e2c051e47f54f45c6fb78b46b9993c7d223d51036cb77f5e31a4b30892e8fd7ae7028322d6402f60712f712f84443de083767c38ae88a38fd4e4bbec58015f4e49e36ecbde94f23d0061edfff0e9eb62b67327249d728c278f923748e4c1e225791c740abf9493198f073a6cefffba00d23715a14967a72cc7aebb81ecc6e8bc88ae63a47507296a573c415d0163219f3b20974ba3a32572d29a479b88b89c241e63e640bbb93e2da0b73024ff03516ee3ecfbd84348372cfb574817ca878172a779ff131492b86e64c1b7054cc5fdb999df4a9578bbdd6a6a2a798f053f4c7456173cb8cb9b61735e650d0394ea9effbef615629c1f393949095982345bfc02b9a3b3ec64d9173bb1285587048fca8c740b6d2265d3e727069fcb90282c78f1049ed7925113279474d0d873045851b397a8c26036c83906dccd0eabe98f7d6854d9abc2e6ff12d84c2840affa371cc2dc624fbce873f38570dc9eff33f5e200791bc052307f5c718d47fc2a205add3fd9de2a81cb452a0a7b4a08bc133e9816f6ba852735b813a1b906d4dbd1ac8a968a8adfb6aded0d3fb87d80132a4b45ad39274bb72df20d648a26aca4beaafb971e13094b6d6525bd418b91320964bd90d3a98fb32d69222aaef2ea95c6b84b6b6aaeca3f6789944fc7ef17d218abc7667ddff798b74a0d5fbcc33d22d028d207f82286fd777ea1e281d7eb88b665e29fcda067bf9ef82a190c920e260cbc44d394b78e0439bcaa6371f8717ad82e02015f21e5dc273de338102539bc924d5a3f897eb788e0f3cbb6e8a34590ff5370bcb0f671ce28d6ac0adea17f9fda49c784ae84464991fc71a31d320d62c4199e4f4e38f390ffbcc7f15922c3325451371bebfaed8f8a7d3eead71c65878a705a6163ef649bdc6ae7b81110a2cc9576da6b0188337160cd518fb30fd5b0c165ac3de81002490f36d29f3bfefa2b4796c070c6d7d971d18bb5a573cd48cb3c64dec5bbbd7f2f6f60bff3db4833bb64b426c6715021997350aab1751f0d5382087ec133c2c43342b31eca32a4c17db14148fb48f9b7a103b2c0bfc0dc95ffe097bd8f2213a3f7a43c994599b05dc35d469fdc025e23e483039f271d948972417153c849fa8dbf374693dabd59d398732020e90d8f443ba45a00b430168561de21db76b9b714ca8260fdc4ff1a5713e69ed7296f5a5a9d192474bc6e67788d6a44d46b69ac97d0b34b2b08aa79d5ee7e910d99221e1e7f6383628b5383cec4341e5c3f18ec3361b2f2ee5935ed40919a4f8892bf3467803b720d29388b7cd47067eed9be7648fbbafcc7bebfc31a30d02f38b7d6be1579c751aabf679fa6891adf66da2257432c10d399a8d496d1aba381b64a5e3ec9a65cc8419151b638adea994c3590f77bf390152894b2784f7832d986ac51b20ba9719d85509acdedc0282f27065c87bf483fc74b55579ecc233fd6c51822ae03e46ecdb15acf0204b67852d525168f409d2a4309c5d9a14b35905b836091964ff4fec0aa91bbd7f39919eeaebbaf75c63337a4dcd5ae37cb60fa14bd78157ecef35ddb1cfdc366eecd48aebb0f5b395e4161c158c46870fc89f8f5918aabf0577c914511cac7b189384eaddf7f03cc6706a9abf219ff1b293cc9fa2cac88b65af62f0493e30736b596c119149af07e840a43dba8d97455a7a95368395488304626d3b888069a0099c435cc11e5981412f79153577c9115a1812b1c4a9ea42bbf11b40fdf930bcc37e6a6c50a7e3d06bfe7043adb32244ae359993caad00eea5f1de90355326e921145add1020ef3c2cbcbd102e7b9a150ff9672697d31f86572843269978cbc4c3fe067417e84898587d4de009b33094c8e8102c07facbda62a2996e083d0618fd9651e17f0fc025a946e7c28d93e18675ba69d8811dd06a2cc1aae28de5a6af30f305cfd8a090832483e4ff7c974d47ac96d2f3f7baec94f965a116c2734f87f468ec33cee1a58dd2ccdbc8f6a0f2a50a739aadf4007c7a529844cd1ce5efdd42eb28a0f5f04fde00dea586e4b8cdb8469b36940de19feefd342285c29298afcd3ddc368f6365e9ee255f8c2b6f70c1bafafe10720402a668ac3a2cb8ee75cb7004455cb4221486c3dee64f8f25f1c8b1411437cf6ba70afac5182b21f0efc1b5c71dd59f71796d2719741b6d5c757d824cdfd2d9459569427951d6974d94bea1fbeb0e1a23ef88774b270a8bca65f01a00299258847ddce8af8a7626c802b29dd01d1dd9d2a7243b334c29c0943e11ddbfe82cdfbd506e81fab8775a1d3c4f6c0744e1086763ad84e8f51d601e24cd6fcba1409abbb1c6b5c9bb9eab8ca30282801448f86cd5d8ec187866f1ba738863f3995bf4084ebe8f41dc1ffe0cd47d5a95dc5fc0dde1559ba170316e085d0e385ecf8646bf787b5287960f07bff9d3d990b3be4b29f008de18ccb46dc2192d0fbbbb9e701d350aae205fcd2d7314112bdc393e2eeb0a96c5f2c767dea0b82e9549f46a270b2c69915711c144a7737e9003b1c1b8684e9f2abe66ad1678c32a0c6ce401ae2d7507ff32c8f6179433b94764a6e4ea0a363e9a03787502c67ec97724d78c1257499379ecc5cd006a13acbba05dc7f1310bc75b9ec6a09f4d95b2ec11952eb3dc3d2dfeb8678b10b5db162b44af56ada56f7e311d6c5ce46472d9ba2284126f8f579d59a9d3e81bb1b26a7ee59c3cca96252fd4ba8e009a213911619ab4184e83683969cc4c474e934f36e6ba4ea33d9e93e984f1603e259cb7f1a3824dd8764bbe30ae08166aca84e63615e59c31d2a968a0beccd40637db22b971d51a4c35ce83108d8975d758669bd83ff9602718a882b943f80745d95a2d5e07ad0acf8023e24589fd68988a350c0ad571470f8b9a906648895d312100cd18089465de942ae0c7c8bffb5d3705c729990721bb0497dddea6dabdd530c9ec90286cee5ba3e2b699eb2de55de8aa0012b38051862bf0a7a22d6cce4310dd8dc47c206d9eb7bf28f2a53afa8fd10836210c0c461e417be42d89ea659a76d5e3cba08daa885b7f0302c5df05c72f8257f60e2ad954891841e67d8b7184cfa47e51e9b36f6ed1400aa84c5058a1998d07709b8b46630d70c73552ada18713310dff4177e2143aada1038bae9a64e02870a7535598d766f447b4e25dbd009009cc0e3421067bd0cd10735469b308cfd7a094bbdaaef2e31c22dc6c1a6d4c7890020b5bd04ef649b56889b2031c1923a69002448dd5db1142384cf517b08096539cc537532f43afc33ca77beb2dfee921178ad51b04f10495365e60b4b7677880409716e0eaa3a1d649a871234f86787c2792bf1e04a635e3f22b8b3b1382be942605c3855a940cfa3825a2f8993312a512c81f92aea0fca95bd1bdb6b9774ef3f1fd15bfa1eae84ebb48bc9b55fb2141c55cd3188eeb5049b2e6f3360e60c5bb7d91c9028ebc9287b4b5541a4ca290288e08ca46f80eeabbf100f700c873d7e69dee7dc80b842004b2bb93f0bf533488028d1a1137371417d06785372ce942d4c6589cdb57514bde81960475c22393eb02a93b6560fc3e4fb6ba692dc362d38e33a41b7df222e9192fdc0e0499f110e681682e2b500c00947d62280482dde5e26010cf959fc717d0837c98634550376aaeb17c1c80e3c3245c36c68f56fc8be117ff84957a75e4aa4caddb38779f1c50086ad4863002127b6c8067f172aa78137908fff82b2297a53d6232c26a2e94bb25b7f9241013adeb36d1e437f2f6c0d983efdb78608e940390005d63c081eaef21d7f00ddf51a3fbbe6175be436a9b0b75f198c30efee2821ac5f088819eb96ba835999d0012e7a0c244268a658bc6b7845d10178283cb8add0b81405ccd64000c1835111511555eca14f7e3cc9274b45f817039ee62cfd95363cc66f5397f88822f790e0a86b6a69379dae77db24185394d9fc73880d39f6b3233dd8d3b912995b22905563ae8cb2b1f3491feffbbdf2c7d2e89dce1995d2429bb0a4c550860835aef589983d3170387971f8aec15c18450dbc9cd12f402589dfb17216e359072ceec8e9484f9b490a288dd4b268233c40ad23721961c390bae0a181c4cc8eb68eb4b2a5db6944042c6ef67550f9abf3b9084cfe8521b62d727416576a58591dc65f79f871958243ca4415d92d3e588c4205b4a3806d64224e94e8f04dbf7f75888246aae9f894bab1ea69d7e10b4f07e8cf2dcf70cc62571c737cb6b6c68b0e3fbe4b1931c8615a793fa3db0a45090458ff62ce8bf421907877e555cdb97d3709bbd8728c4432288861a56cbfeabbea5f225cd29e31d99eb788704a93696f5e81307fc047073657405630200035ed48216bc666598aac5498e9fe513a9e21eaf842d382767220cf98104bfd8866621efb63b2eed44028cdc9e2f64cc2447fe09f8d8a1eb3214272855b525d9ce24e6daee58effb4af28fcb0a4685d78d7995081b5cafd1cfe343aefc8e9cb23507fc0470736574072102b642f0e5b34746f2f6e3b511d037e16bc720292da4ea2fb31ec09f6fdbe777ce00010308f40100000000000007fc04707365740220230f4f5d4b7c6fa845806ee4f67713459e1b69e8e60fcee2e4940c7a0d5de1b20104000007fc0470736574012109a05049129b0d9e61c1bb87a9fa02c2435be35e3535082a772f65222f2e4a48cb07fc047073657403210baf4431fbb8f0227bfc0008368606a4b8f2bc1706e1a06cd4d83706217b74f5b90104220020c773786f3addae4c21acb094f39122c032daded1cb6225a64d923a0344087bfd07fc047073657404fd4e1060330000000000000001a4092701f9170991583ec8b5c9b5056ddaba7637f7d6733a57dc4990acba6d15e9eb5dca55528e179b98a9e09e05ba940b59558b768194ca046c22e12ea310ec05bcc795ea419277649d40b145e6f0accc31f2d7eb39b29b51d3ba3410536b9bb37bce9014d352b496b93161fc799b23939ee635f25c4cbd6605029722ac2bfed7d55fe4120c0cc880661ea3313d700e261ba973bea5df4dc4d8a05652d193c5edad01945862943a6756d4b0ddc93ad5a444ecb054bcfbbba3635aa752d9c4fe8f93fc56c8066b3fe344143d65328025f5184308f2016eae65df8b0f1818f59f5a9539eec9c9c94704ecac269b008ef25f67ab2b9ab4e903b1f2372d1d3988b86e5efa639f9f964599df8559622c8d11f6bc4f706c74e4a603a3798005e210f93d9e6b59f8ccac907dc9cff127c552c8c89981e1b91c817cd365422eb6bb0c7ef4ddddabd306b0c32a98464973dec30def4149f8e9f35de6840cbd0ce8a2f2b5dec15e3f3c27d0d2720159cabb3ff2f73b4571eb53ec735d7b0f27bf4d23cd8b0fba14d5921d464beb3fd4f2fcf844f76a7f7f129a3e7e1c4a6e4f07490f2cfbac4e6730148397c73720d35cc5a46fdb1e774e17f7b951887c1c72ae4cb25ae99bee652ebb2ffd9f4c9400ee0870b27a5dd8fdb8224aab6738399587b4513d3441e26b898b35f739d64047ce8de70347042fd18c3797b1de82cfe23521dc8e5c36e286c05d4f81508e282018cd8d263164512e6ab02a22b3d5d489e6074f9370e218a3adf8afd229659f5046749db9615541408739d4f0646a853b25f8e549e85708c368e45f3e1d20ab47a4ed647b820a360e4e351e4caf74810098f0df4bb74e0e69f2db3284c30d24a0d109d16c37509557ce15c81812bde78085f31cd7c93140fc43d6580abc7ca2adfe6354510fd8104c0f1ffe46d24f31bea808376ac27996fb992de15b30abf4df6f4d08860bec27a95bcee0df8f0a5bd7f72938ca9e917f39c5425bff826c4a84a1fd70cff87be2e8619e0d3b729f0aadc10d4b70d10c2c020a99d03424a595294dd34b84c83a2d434b98fb116e2ebc8b2bc444740ce090816218ea61da172e30db5e78a58ef495812c287e3cfab7bffada0d6f2fb3c153f1a21707923ae7ec862d44d357776803336566c3bebc9f53177a3a8825478eafb32a61bc04d82994708725e0ccf5d76dcac946f36895402e84856b3e25567156040510fb299b88c45713175c54fb3d54aa6d383c423807778a92b7d9bc8fa347923749d18c96b20cea608b6380b57c35b4408f724046f6f65fc0d71e237c39376e1ec6dfc6a2ae83ba70d25855c10e6a8f425951c52fac7758353e2068e5cb4b6ea066491e834a47f8a5cfbd6ca91c832fe4f77b3b3140a6c1c70055d52f0aa67e7d3ba18e5bfb09f738141a611002ff9e34188d540ac42f48ee06f6925cbf3cca5ca033c4fe089650a2b86a8350367e9cfbd07fac9667c0171f54311cd5b371576790e51a1fddbec64f8f559cc08b1c0ae5113bb0c532742d90c1a266bd7eaa4b1d06693ff12d6e66c51bb1d12dfaeb70bc56d5870fb5ce4b040f86d7725ae53b18c1b12a84f7e3a2e7d748e8a899fb917987518c6dbbb83e3b62b31b0facd3515cf2e18b4e49218ef48d97df114971b298a6c4af231a432d4ac295d0d1947e09ccf41ab104e5435e7dddc0a6815b636a31be9a0d9cee2f22c745f05f384bd703fbf4bbcfeadf177abf4ca4524f38a681e5436a06abf9ca70c7569a7bcb8337b0b0c280b5f790ebe1258bea9c1da58c65c13991efc1ef8f7c75ef28affa340d84b33398790a9a77d30b0ea35613b39b1b7d8667fd7299e2ff38de468f625df1485ee3b2759f7e27ed707f5807342bad0935ed42609849d7a9d11addf8a92df7933ec44e86ac7f24d55a55284fbc4e4824a2b4f8bcb146d08d7d6d3f551ce1b494d7c0fbd6e82ba4496f3eb2812c986f3e2e627240a9102089725057c1e5dcaa3bcc5efdd6ba7e8a496f609aca3dd82816552c669c255283f9372be7d8f12b044f8c41180aac612245945a4467fa806892d55ff425adbbe92bc892698a32d39d7c23303ef65c980c608b5ac07ee60ed2b4e028a5565f5aa3ecd1e15787c23716697d53603f72738d5ca88c5d8280c3d8af9e83c18be420bb87db4b82a98d3af42f9191d4023eb22f428def2ee99d04d1497cb8205b67c9ca893f7afba077bae5fc11cfeb53d882763f2eb6731bab373923a63dda3ee1c1b6207e0ad0884290333dfae3f80e85cc50a241c73d7d99998e9b14c3e52e660edfe594e1ddcef04402e8fb01efff9c00d9a6ffc955e219fe9c92cbe87865f7a25ac68fa2d360c584c33fa3e40ce91d021465610b85b5f1a98e6908a17c5e138f2dd7da2769bad8789eed99828e8f23952bab7e9ead5fa9bac781fecc93de7927544736fd5c57f1da32be31b85657c313cd02104e1b889426bf4c8e9daa741278ae3966ea673cd3fa164ea7cc947b34f86c92084043ae846aecfbb15535a9b21e27fcda9a21bd821072135554e3015d5a12d1c7f2fe74dcef63fe99c947b55a4253add3668bab2d356d58909b7b0784c0759dbf1036645c5d673edb45245f5e78407978b63d5c25ada76b176dcff53e76801d7c2784d4687561f32e7a32175c0fc77227b3ab0a4054462d042931897530502c85f0b976fe3e3fd5488853b20dbd27d0d736e9f44fe6224b9610af05c462f08d328cefa4bf8530250f5a4d3fa7f58f5a48db45cd68d0dd53a2c66758a20184cf226565ce558e60f0af982b02672f8ab14333349a5e5a5dcea61a09f93addea3858fea4e49c84f5d8269a2fe52f072d66240e7d30b7345c841a135271c07e6a142ad1ef1955e29469d3ad3d952ca9055696dd825253e4a0e4822bf3119f1df2404ff9bfa39568a52fadf98ac6d5a4653862d91b995ab166fa9de73478f7e339941e036b621f7d773a5413471d6e41a68c02ed89a4882bfade2b10e399f4515470ef43930a911609911f8b66bc060ebb186cdc4c1aa3cb573d696b0f48a655f8877f68f678bbf467ec872724181d6f983682389fc8a61a7525bcd61ab37930e6eeaac82b7adaa145e2a0bf67e235a657949708f0640ec802a1741590a505e4a109ba857824e00f8f675ae6bc8a0f32aaec0f38398c33c8f53bb3cd53bf697ece4372f8f252ab4b314769f1393aabb2675f44c05dbd279732824d49e77f3df8841de18a30a9bc321ae43c712dbb9f08b457dd3e3f13244ae03da16acd6d3e861efae625478a89020655f0de72ac174a50834db564d4e60bef51e28954a938c64a6ee290523337153aa4d6cfaa00826d2aae1b57e3ab857e10cf2b497597ef9395fe6afb3d74b21c5d44281f756e018539ce8b7f4bc663db1eac9b976da2f994b193a30bde0394b7648b55ad9bde958ec5bf89eab516d4418451d8cbca637c1d6dfdef61712e76aa7f12151d5717ba1af71c4754136563ff2667bb984a80a51ee9112587cb77ed6fac8f4263fce637adcab9f315d6beefe509f8d34ae9c42c12dd42067584c4a96f6c15fe590bd8616983abbf453ee038f385a126dcb71919dd7143a8c27186e1c6d29d36c1039a8f008088e03fe7b97fd7f285a0817ca746438e0949dcfe49fc67ae967d13d1d1aa37c2e410bb95609c7ba0586c8fccdcca933b1a85ec97d1aff670004f71232bedbd192ba5e5a681867470c4e146221bee322a5f458a2bea1316d3f4be26efbcdeb4b1062e58f2fa23b144cfdda55aad3ed7142653c7948b6d854abb8d1201e9a4de07b8985fc194e58ea08b4c8528adcd73ae6bcf5493b7b8ae1f663ace587a87d5a341828612bf82605ce6cca9253057a8096f396bdacefb56f9a452849f0ac652738b5b3135ae13af532dac7d9d5307f158d844bd3664865724aa9907d2ccaf4cae78e056ee78815cbcdccfc38b71e0c648b1fd9f710a15d799e237c344d53923d3941e73f924b75de975ead5b536d632338fe83a8d02a4b7fa9a6f1a5df9de85c88b944581294609c880ecb5eb45de087524d896486c200ad68f5c45e43894d6e84493bed02602ab075c8dca1e57e3932740c25a9401b5bbc1bf524f4885f77a501bc3c313666fdebe7497a2b55031563810b35f33503cdbeb46de12c0482c70b07b5ca3c4e2aa21be75c33a23e73c03379c434dc8bff54dc40b0a34f476d0fd1de0422ae6edacc8a729ed2443315336b208ceafa68a229592e42f49501cf03fcf04ed2ab60cf7c31bf4d4fb5a8d7b8969ddfa8a725eb9d32827446c141170bec2b0dfb5c0a6e00cf83b856ae71b5ce46dfafdc12f94a7f8f3d1bf1eb769f52f43238ed411a97e55625ddc208affbae8ade42829c82cf4f62423830db9ca4091fffe3d282c578552649a34cbfeef3d58e020978137a44fefdb9083186dfd712301431b78095a0997f0764f3ef29f138ffb322c8e187c260c90a3ef7da5638e8d961d6a6cb1867a86d3eb23419e101e18bbf128c7a3492e8447533b7586a81e52366bdf2c376a57847b8a44f7b55eaeee6ab2f06596a87ccad4a60881bcf4b4b5d5f0de85593b643c0c4fe1771a0cb5bb0402fae0f1a2dd811d6495676ad718b73d4b86fc79ce074aa9924829ceb4dfd4e3ab70fdbd94b5ad1d11ca9e582dc215577056373ed91ccd6472b3ce02dffa8817e66205b179f37bdda376d25d6bbcc83a15ad757bb7843aa03d2f7193d8d707ccf4de1f5c8694aa212219752addd55cbb412c05118c30555ca7ea820bf3440d1dae3332947a1cfc22e366d1ad120b906274883d7769983eab6afea2ec0672a2ed25b2b3390c017566e52a0ebc59e6cebb89918d54f75d4094b943e7725468034d2ecfeb68228060bad59a4deaa40843d0cfe0a1e58855113bb7c5965254b82cf3997924d0a8b1711b1e1e5b28343168f64fa9bdf8e5158f33c91112f61ba782a4f97c5456c9c8756adf53a7d919ad90654a1c035d8686f834750302added0fb7b29a3f4f43f4dec29bedcff3139cbdffe391ad64b48eb1691be659e4e4dab266b7221a2c49e42d8ab06ab6d16efee2a0e0bab140aa34b53f70c808f3966f1a171bdc789e23ca0246328dcb1680c765fe262048b869c56f381bb7ded54e1486c0a3660d990f4bf0e5b4eec4cc0c3abf4edab6346cb531194c27de0e316d9d0a823db00e20e2fb99c2b5383213518d0cf604ae8f69d2921b442b729cc78579dd242314da99f01df55a45dadcc87e4b216aa0d817e60673c9807a75185e52a70f04ab8ea28cad805c37fae5417f89af44d4a5728c187c74ea736f21681fa7f93dd9bcab9b510febf2c4b5c64cbedb6b59b77a8816728dfbaeea423bb7735ae1fba08964a343ef9b5d36dc7f8cba10c8ae69bbddc4e524df73c940f762a2d39ce7ff235425942f2007b4e08f2002018f720e0339bfa2704a9d74798b13c6fda733d965666ec5592d1d6dae7af6efe5c87cf48d40858937b1ecde3445ab2c1ba1e87e1c2f3ce696baf3efb30ecbd9dbfab121a142ebfb4f09f343f37e8c5c0f40408a339cc3e4f4d34742d695dfc037744ba1a794abb67954d3a6509157a3aaf293c886b58cfe9bed8a3dacda2a2ce41f95e72e46baf65ca666f61bb548afe8f92e1c4ada258f46178a4591015678fc542d412f7ed323d2629c127890ad9c2151261c4869f59db9648e09c25bd5ad8cfde27ea4ef22666ae0f30a4d25c3ea1780a6c3eb2d94d0f48c1a61701707e57405e7e9f448452d0a48af07013fe04d6fa62fa5fd54139d95217734ff4e596f2ac975bbfb8fda29f7e6f211eb165480e44fde387d4833f89c7162c1bda3265a5271946c5392921861ad5d9e5b672afe4778301d7a8a8d8a03ca1c99d73b2ee43281c0b88ca4292a5ea29a0e2377007fc04707365740563020003c54f16cef0fd4185f35dc6784047913c89883f72b68aa78c16f144624430909da01633eb2b4b13eccc2b7a7ac5ef3b13505cea54e1d390944b5680e6860184e35111675dce504784f4ae8121dbd1f76df3d55ef722f3f73b5b7723efe2fd34b107fc0470736574072103652ba5800d63722adef5232d31ccc12403055de720f0155fc47bba5750ccedd400 \ No newline at end of file diff --git a/examples/test_vector/raw_blind/extracted_tx.hex b/examples/test_vector/raw_blind/extracted_tx.hex index 7d8422fe..4072b162 100644 --- a/examples/test_vector/raw_blind/extracted_tx.hex +++ b/examples/test_vector/raw_blind/extracted_tx.hex @@ -1 +1 @@ -020000000102cbbe4671915035276d8df41a7ef0b6a36dd101de48a4076046fdba3b0bec20ae0000000000ffffffffcbbe4671915035276d8df41a7ef0b6a36dd101de48a4076046fdba3b0bec20ae0100000000ffffffff040be6c538eee2e29d44c66a3e66fc8165afa4081557031826a070703cb69faf2438089f9677efff5962164a434b0bffe53d90c271deda3eaf30c1d7a55105d24b874703701e53a6d0b960398abf678382a4d17c5c153d1a2c8ffb76b302058ce915bb0d220020c731ad44c00a2928d508ad82b05868cb42733a5b0d0b208f483307ce8c328d930b8529a893bd81e38743e8e3015095077f6e244a064d64708963c6af5024b6aeb30821b4e7599b1b4faf29b521f1c442dfb0a893499d374c19db939c0c9a3b9798c702b642f0e5b34746f2f6e3b511d037e16bc720292da4ea2fb31ec09f6fdbe777ce22002058037c2d81d3122185c8704d4276e2629122c95b8ea68575c451628d37eea84501230f4f5d4b7c6fa845806ee4f67713459e1b69e8e60fcee2e4940c7a0d5de1b20100000000000001f400000baf4431fbb8f0227bfc0008368606a4b8f2bc1706e1a06cd4d83706217b74f5b909a05049129b0d9e61c1bb87a9fa02c2435be35e3535082a772f65222f2e4a48cb03652ba5800d63722adef5232d31ccc12403055de720f0155fc47bba5750ccedd4220020cd4ed5f0db8c450e8b0be595b6410c1759c19f1f6926279095c83dade9862b6d00000000000002473044022040d1802d6e10da4c27f05eff807550e614b3d2fa20c663dbf1ebf162d3952689022001f477c953b7c543bce877e3297fccb00ef5dba21d427e79c8bfb8522713309801210334c307ad8142e7c8a6bf1ad3552b12fbb860885ea7f2d76c1f49f93a7c4bbbe700000002473044022017c696503f5e1539fe5cb8dd05f793bd3b6e39f193028a7299a80c94c817a02d022007889009088f46cd9d9f4d137815704170410f53d503b68c1e020292a85b93fa012103df8f51c053ba0dfb443cce9793b6dc3339ffb0ce97af4792dade3aae1eb890f600630200039d46edc3d830d852edbdf28cbc023dd1666cc4a806ec9d4acb2c97865280698d61fb6b2a073be4ce75cf8193fa9b3d677146575a812873ae7eaa7b08110cb88904273dd65af35115dd116092a56ab45fb57178d8c5ed4cf99474ff760f6e987dfd4e10603300000000000000015bee4d0045b0884354b05d0285abb287ee8e539e8146b92dceaaee6fc01af1a3730cece4c77caefdcfcea1073197ffb8b3ded97d0dda6f49752b31f23e196378a3da2128a8c45ecb7eb1c32f0c0dfa1ce7bc348e799f66d547476e976baece7445790064b34b1526c88cf54928acc906ec0925327d797d36d0db6a43633d7f963ec9b4123a5ea31b655882329afe2108d123f76857fd3ce344fcd651b3d3066aa506625c9309acead85fb6c8a7d977db5dd6cb6e2f99fb3535746258d42d95dd2103bbaf5d45c8a2dfaa2301eba08763bac8ab3b59bd0082a457bc0cb257c43ea6354348e73d8dee101864068f0e8e30e6711f1597d7b529a57e95fc0df813ea160f5f5152f341087868a680c1bbc4b2a427d18cf8f12cbc4304dd3b1ea4c916467ae48b3b53062ea046161170fbe6ca07462cf3e5534d638c91fe6919318c4b2e98ce0ebcb245680d6395ba746fbf510a9a36ad8d933b023eae39973a39162178148a897b5174940db46e4be54794cea11fafbed48b42eed27f9915cfc50c958e88bac551ab1c9bfa03653e558cf87a99ff13440f4808e27fb42ff3cbac9fe10d1de07dad4807c9f945784163214c739a9eed8bb2e7da6e1fdfa4aba5d5157787d0000b220145572d3d9253cde5c1132370c1849847633287660b429f20cf1f72e4ad6ae59154c3b8526fc5d30523ba962a25577427988d326e207c97c81b479540b1c63aed0a4b1dad9279879740b2f6a0bfc37aea8c81b3b35b630dba8d955afbba756b8ce9d2a9802939972c5f70efdee8778a98360eef15faf77e38627fcb4f98569d68ebad3bb667e5db46eb7f4214846e651224673dc998c55bdd9e0a1629497a75b76160865c7ac3af874bc45a42269508f183d2458835b1734791094122f75398da2bb7919c67221ee42242c298d744fcb920726b84bcb78d7eafc9e0f61a02de87ffc5c674390a33d722b50dc35bbc6788fe0fd24be7a9e358113a4e65b49655767b8f3c3bb86cd5a56c79f9148945af63492dffde82d682eca4787f203e49790650395c925e6eb68bbb3adda25bb784365c0b3e241177ca7de58252b8c79c5a865d1030f3bfd4d312bdf83bd28241389085433c34d747f9f45a0a636e700805e619a19739b15077d44d5e8969a37481896acebe7f350449c69b50376b7cf36e906d8a03aa7221de67c7fc4c5408b55e2562f7b783918004d93b284c0a1c3d596c7c18aef5cb77ad09172bfa888f5dceabf57f708f5ab61b1b4159742d3d35332e9942958ea7f39fd35cff66e84ea0ce3b38a85eb80dcc1201146fc3854cb40353a078f5435fe2becfa383b3a62564645250cf7feccff5414581e747166625477c70f5b0f579bd578e03e6b8ff8c3f0e8a82566199ff542b239f2999103cbb61602bc2f346702204e50c9ce7b85f3b8e144227ca8b9766cdbd498191c385e3a4f024c9396763eacdfe41b706fb23d4f065dbaa43d323edf1811950c71d4475a3e0913d3851be4e921cc933bb06b0aa20524267b0e9847b6de3883ab8c5be1eac17b06c946f19dc2244901890cc290f2e66147f7c47a4a29349555ca020e684ccba5f8a6f1be54e356654d3e8678c591633e11d9ee772940d92f07ab83228c0d8840cb9aae514c03358e973a2ef319a39a3ce819efc00e5a493fd582be164c1460f70fb2e103f09a2939f779377275be736ccd41f847133b3d400477582419fbd2d7ff328d88256cfadd750ed7a3c6657e332f635f0a90602b24135e705d1530531b7b738e686d83accd74874e160a5716191447f832d2f899476ec9c53204fc4ade5b75cacdc869b4088e009e12d85beaa3450889de0c86315755ec7744be592f058fafe62f9a89875bd2781d5d6928c8475f555e77eeb6e688bd8d3bee0a54fa1cb29c1b6b438d3f70ee4ac83fcb6f482575997e3a69240c6731b517d8241cd39dba6b02a9e3c94ff2470c61c693d32b1c7d22ba38f0da21d92150115d580249380500109215a05baa63474f773892b1870005e76a68853e6a8cd9f74ab3f41cf0730e702ce94c420dbf66a63f342d927923d7d25ca3c3823b6c352ae2ca127bf811c023205632ddb8f9191c2f3384a61038d1c4d32f808cbaea81d58f0aebc7c89bcb5b98f92849f4fec19cffc78173e601eb412aad24eacd74d17cce3a9ee76670367ed87c2da3db5e4ab01d4d9626d0ae00da7dbf6b8103d5994cf66ca56bb9aab9eabee2b14ef798d3fa5ed1dc16bb500a006c3320941c4c7f6f80c8b1bf79131a5e11ef38db7c42d4c4939711184ea414e2ec0cf5bdce3d7d0d72dc883b2595e5f0fe4c14cddaed61108c90c74b43cbf719bcf7a934bee760ab33f50cedfe3ce61dda3e4bee1ab4dc687f988cfceb207152f7a98c0fa3a114d2d6881034aeba877bbcc368ce591707da45becc48318f0558b3ff65d677578df9fd9e9a18d0cb08f2f5cd4f44925259225b1c4c5ed84ef30d136e7c66251329a223a1db0b485f1c634981f8860aec1f3dbda9442e5438f6fb09c7e1ab43e2b757911834df8502ce35e7be947771f7416f7ea97d26dbad7221614175e6b86f1a323e26c4f469236d1b1bf6ef28823234c73b275c5b0ff39e8c04d9dd8ff7f6a57214d803aa13dbf581295b92ce2b8a9c0e3fa8e4fe4e74c4bc2198fd010cf84681cf5f3fc9df1638c403006478b1cd4204ef3b7a6093116021118a839bd3ac270783e67096457a86d63654e268821ee742241ab5f7e91972da0a94f679b4c093d3f428d5876edf51459331df084f2fa245e3648e0cac904a82a7d323b965a39683ec0b2721105683e67d65fe10b8d41d0dfcd5c31756408c94cf425ae67f95ecac45391516875870386b675e24c462b1f7634f758723e6245da6a39da69cc2390374eb89c6c662d94eeb2f1835e233610072936be248e6a3ff87f9950c2eb2f88568c31dd30d1f0c0396a42f6be2505bf616c63f504dad5312fee2f083b406fa05cf3c998ba24237402681f0ec393de4650ddce3389d4c1541d4705d8f50c2c6d4864934394fba0c40df495fe3a5bf58a5498c1e63b5ee5f9a4b53dbd913252d4808f5bf5fc3c6dd74c86c974fc9e5afb1a7ee3d88738ab1fe9194881cb00197a31d648ae2448db872528d5f7c366188d9d98ea94497cb78ffacb5f6e8a2c8520d8d196fe0ed13e2b2a5a08dc45d8ff58a8c5d3bcbdc5d80c798acd0eabf146459e79db12c2a43c55d14b2dd608475c606fd4f943ae7cf62131691768f710fd718fda3967146daa8d4f34a3b8fe8084f4f3865e9e0cc1a0b0a799fceafd1b74f09f524822179ce38cf0f2c4c8623a3e3ab2cc20f5dccdadffacee62c120657e3d85fea93fab645b5fcdb812b130afbbd5b19e86aee66011b520b0affd84af4bf67a28b309cad66cec25a5de06390a4f2a5af47d59c006010a8ffd214149bbe47bf847fa94c2113723c9476c2e6dd84411bca16dc7bb096aaa3e9a9be27811b52838c78d16cbd89cad379bcc0cd966dadfa428f9d4d8bf133f7d21022ae3f966dbc1409c6d57cc46ff4434fd90d79b6c9e68ed3795ea6191a7e309783badaf8db9fbccbea905ff9d423370810f02add38ad3088cf3393e7c6d585b76fd78c67766fff03ff54c01228c6737da667147a8b5e722370a24db8c0165e34888920d70fb1356eb731d0024676444e2d37860eaaed9790f99069e622afe6ff12d516812022c46420006253248eb292908ab8658cd874ef05bd568547535fd54c1f0b5b816e4d90a1bd55670b96691e7633a2fa45be6a29cf7bbbcf9e5debb4b7a739b36b6b326b719a12cd0f5e3557a2fd94023d8c633fb697b85080a39734013b4ed9a7500aa8093edfc3810d4c890e608951e57af8447349cdf45a076449241a047085702dc3e44814390ceddc878791ab3a6503f48f48af25fe5cddf61e7870ce80e32e5f22d5725bfde4f319c2db7cf3ba3b9952202cd24210ab8d47fcdaa9ad5e2a9d2c7be1ed6b67cbc1a28ebe565ed0337c09c97d2d9608d97905c7201be7d4bac785d64caf783cb3ebff817bc5ff0448899537ce6911c9803744d06ae97e6d3aae037697986cb20061892ae72e05968e9bc54153bd745012af719fe7fd4b917689a6cbb94a9bc8cce51d234ffce7dca804e2b2759f473885855983b7b290806884fc66e724fa848af2de3164c611c630e5bea712cdd9a9943ca3ad55994e5587c5953f415171bdef3c42783b809bc5526a88aae66be626d73394a607ca32256198dbc026d9e09e9659ddb66736215dedee0cf69a24490a53b2c678e6caa2aaef10a4610f802fc5eccf558629554d6388465584514d3dd49fc00fb267c39bb746f76ad3cccabcc3cc882815bd9466d593270a5c9a04945dea7ad06ddb73e66b90270e859a109d52251d911e7177e07295ac9788ce970c1b718fb0c2f327f44fd0cef3cb90071ec85e958e6ae60bd134ae307720cdb10be5a0af8c051295df905447b46206b5e04d775b83e11c348458b1bb310ae25c54e8ed1488a95b2a576002198c80e0e69d14fb7bffcd89935faa6e3f9aed61e0492bb2bc334e389bd559806eff9e16643ddc4372ca83790a99bd4f5b042779ef7e3039858881c8ce0041d43ed6b1f42f18007d046fd6f65907cef73fd5e6cd514c4fa5ebb872b140d0b2ad43c58f2f2216522e78a19828baa34ba56d71414ae869a13cb708762565d754f0754561adbd9145d232034229d2840ef0c96f7af4b232c5e11ae9d018b87177a506b66571affdeb693e170dd12640e86fd430b64509d02694c52a54f23ea96e39be92b65c1abcb262a71d6e884183d4bc6cac8c79f6e94b51abe484794a42a8e1be721cd59383bdbf327a864b2cf27566f1270d82ab6e8b3b934e953b7d48ec4697172e0160b8435e8186a7ea685dd61402b0bef09137fc52e19ecb53674a1c0af17fbb0efc2b4d69572b32600fdfc3c85c79ccb2685c665aef16748b7f15862f435afaeef00f3f927cd3a60c22f137e9cb2c38a9652cee570a76351871ebc9b6fc720b9117b1306e8afb298e3a1d0d4b2c5ad5a21e9de4c0938a98daa35caa711bd6d3312a7e941b060c4a1ec211c31e53da263995d3be74a3ca5a970d3a663245a5d8eace336d9ee847619bb337e777b961805e808f7cfd8f09b93b6ce6c277396e6cf0a6153fb11625f421b02055dc53a0bb24786f4a74211bfdf44193e48b2c15c7c85acd3f4f0bd26644f9dc62653e366178645899dc06d191c785831b98de593519c0ac5849897a01b4f8c7fd559edce1c878bdb9dd091546c64225fa81b1c7dcd6fe72c8131bb160043976a5e891236d3552598c0c4fc734d1cc752c10306dfc8391f6d658ab8b7a1f350e1900edda29775ac8a531032bac968f6981889f13cab07f49c864c3ef3ff23555c170ee9730912465e6bb3b7508e11ba27001d9dc0da8b34954a7c46a2d0b0b75e73ad66278c8acbed3249936a6c76fe975954f7889bbaae5f73747e3ed02811b015beab9d1515e396d37b2a116b3cd8863517b88ee91a854e4740304f7be41123692181a8ae22090956ba619fb948d3f08108da17ac2484d3dd5795b1c716cb5ed3fc08b6449fec814018cd883b02256afadd1f35a04d9d43f661be624c0d59d0d397e8ad6917344203843495162217e79bade11ca32c0a6918350520e6c3f31f866b89e3497b518cdc056e760813ebea7fbf343db50ca2450d5b7a1c5f430859e2040ecfa70cb0c3e863a756ef6ae2e26c68b543d35beb44513f8295872df5b4062c9b80742ca7a9c2ec36a1d9bc936c7fa7328240a2db54463ca04a40dc0c9afe4d570012259c8c436d322483b17a705d60a283e0ea7545110e898ba43ac6130aebde014d237482307ff28f385fce8530814a3b35630200035ed48216bc666598aac5498e9fe513a9e21eaf842d382767220cf98104bfd8866621efb63b2eed44028cdc9e2f64cc2447fe09f8d8a1eb3214272855b525d9ce24e6daee58effb4af28fcb0a4685d78d7995081b5cafd1cfe343aefc8e9cb235fd4e1060330000000000000001ddf2f500cf45e30e3911bb51a7ff633c1e329508e42d9aa49fa8248fa4d293b87005db08b17a472580ae2cdd53c40b2a16af885d6dfa3d5b3410d389b045e6c12405c635511ccf008390856f4c6d0ca472148d2969fd39e1307bfbb8f8268ce92398248f08df7268bbe23e13ac3801ad075376bbe9684db9b41d7b1148fa65a129e1d25193ad973ec7af631a0a30c5659409b0d00e6fe44c2c507d52afbee8059aee7650bee9d47936838e77f00cfec9de3b9efe72cdeefd80a19a9c8ddcd6cd9009ec96800f9fcd709f1432b5715466d601b5ed10b0dfbd09b954b109232fb5a24036b887d26bab43da7eaa303e7c8e9d02950610aba09f343a65a7cb4550d6f6e5c0eeb9410b68f85cc3b05b9340e2e9c94a473f2001f5aea7e875d29e8e0aa99c09afec4a5455258c803e55b89cf6e89796a6f3f9fe11ee05ec415c6ac08e0f1adf9dad681f8121f82e3a9402a2fe13a016dc10d4a605578317be0d9d3e02b0989903002bd35ec4970701da6eb6f9fd5e6cefad137dceffaad968d5ce522e77c76e665529f70c9eb805a240834f4c8c795912c37e7efeb73d4bab709aafb66bd645cf0addefdd83d185c1b4465ee16344575eb2aa3acb057c37d7c22cd03adc6701f03d4cfa20ca94458b3b87e3fb7de8fed28a755bcaccbd348dbc7f5aacbb25d19437d87cb48b88fc714f059b328c374fb2695a26537330fae42d3fcff40b07054be10508fa78a9173315506119973a9158828276edc6e8ac771476d7479d07ba73e9c5b58d61367d24435a1062dfa376546e843b34829103168db63b708a13894813a442f889a423054160b85a2584d36951136bafc490056f1c03c44580e2c7a12b170e5c7a3917720bbbb21e5da616649b554b7ff57dc84dc3935271a8aa6fb218becde208d83e76bb6197f5f4f729f3c57b4280c388bf4945206fa769b672ebd47ef2d0f777fc9dfb031cf7c333c6159a75a5b33ebc6c4683ef140a144a5ab15b2b6b72ba14ee7595679a0f7873a75b9a79e03676ae94eaf9ea8d3532460f3075f40c6b9848a183fe46651caeacd51551f308eab6ba8ac27b93865f5dea0fcfe1d7dbb745695dcf187a5955414763c88ec01d299f03cdaec48eba946c7ff6031f28a5e108651401b5447c0d21c449b387765a621c057eea7d494302222e3d1ff6ee9f8a0580671d9fe3ecc310e84b554e5c823d81b8027075f749b2dc8a6bc5a99fed4a0fc46fae59cc2aa9f1471ca2b0d9fafa56927fce0f1df92647ff5aaa083bfcb7078bd8ee142448d4e1f3dda670ad93feb21028a57ee9a8ae8880df5b3276e078555d868be0d8843b495e082d743328620f36f7e106733bcefac15076826cafce271caf1520cc8746948e71ea73eef5de770ecf5e0fe075f04d6c9cef1cc1f262e69fcfc89862877ffd520e25405d9d07efec82386640d97147e4a6df66bb1fa1f20dcc2ee1fd6364bc2024c0a4a2ec00b84616231c02aef16147df509cb830b9fb20111c60613d41169a24ea67c03cea48e1905b00eba8a61e967b9aa5b6e1264b0f3e2c051e47f54f45c6fb78b46b9993c7d223d51036cb77f5e31a4b30892e8fd7ae7028322d6402f60712f712f84443de083767c38ae88a38fd4e4bbec58015f4e49e36ecbde94f23d0061edfff0e9eb62b67327249d728c278f923748e4c1e225791c740abf9493198f073a6cefffba00d23715a14967a72cc7aebb81ecc6e8bc88ae63a47507296a573c415d0163219f3b20974ba3a32572d29a479b88b89c241e63e640bbb93e2da0b73024ff03516ee3ecfbd84348372cfb574817ca878172a779ff131492b86e64c1b7054cc5fdb999df4a9578bbdd6a6a2a798f053f4c7456173cb8cb9b61735e650d0394ea9effbef615629c1f393949095982345bfc02b9a3b3ec64d9173bb1285587048fca8c740b6d2265d3e727069fcb90282c78f1049ed7925113279474d0d873045851b397a8c26036c83906dccd0eabe98f7d6854d9abc2e6ff12d84c2840affa371cc2dc624fbce873f38570dc9eff33f5e200791bc052307f5c718d47fc2a205add3fd9de2a81cb452a0a7b4a08bc133e9816f6ba852735b813a1b906d4dbd1ac8a968a8adfb6aded0d3fb87d80132a4b45ad39274bb72df20d648a26aca4beaafb971e13094b6d6525bd418b91320964bd90d3a98fb32d69222aaef2ea95c6b84b6b6aaeca3f6789944fc7ef17d218abc7667ddff798b74a0d5fbcc33d22d028d207f82286fd777ea1e281d7eb88b665e29fcda067bf9ef82a190c920e260cbc44d394b78e0439bcaa6371f8717ad82e02015f21e5dc273de338102539bc924d5a3f897eb788e0f3cbb6e8a34590ff5370bcb0f671ce28d6ac0adea17f9fda49c784ae84464991fc71a31d320d62c4199e4f4e38f390ffbcc7f15922c3325451371bebfaed8f8a7d3eead71c65878a705a6163ef649bdc6ae7b81110a2cc9576da6b0188337160cd518fb30fd5b0c165ac3de81002490f36d29f3bfefa2b4796c070c6d7d971d18bb5a573cd48cb3c64dec5bbbd7f2f6f60bff3db4833bb64b426c6715021997350aab1751f0d5382087ec133c2c43342b31eca32a4c17db14148fb48f9b7a103b2c0bfc0dc95ffe097bd8f2213a3f7a43c994599b05dc35d469fdc025e23e483039f271d948972417153c849fa8dbf374693dabd59d398732020e90d8f443ba45a00b430168561de21db76b9b714ca8260fdc4ff1a5713e69ed7296f5a5a9d192474bc6e67788d6a44d46b69ac97d0b34b2b08aa79d5ee7e910d99221e1e7f6383628b5383cec4341e5c3f18ec3361b2f2ee5935ed40919a4f8892bf3467803b720d29388b7cd47067eed9be7648fbbafcc7bebfc31a30d02f38b7d6be1579c751aabf679fa6891adf66da2257432c10d399a8d496d1aba381b64a5e3ec9a65cc8419151b638adea994c3590f77bf390152894b2784f7832d986ac51b20ba9719d85509acdedc0282f27065c87bf483fc74b55579ecc233fd6c51822ae03e46ecdb15acf0204b67852d525168f409d2a4309c5d9a14b35905b836091964ff4fec0aa91bbd7f39919eeaebbaf75c63337a4dcd5ae37cb60fa14bd78157ecef35ddb1cfdc366eecd48aebb0f5b395e4161c158c46870fc89f8f5918aabf0577c914511cac7b189384eaddf7f03cc6706a9abf219ff1b293cc9fa2cac88b65af62f0493e30736b596c119149af07e840a43dba8d97455a7a95368395488304626d3b888069a0099c435cc11e5981412f79153577c9115a1812b1c4a9ea42bbf11b40fdf930bcc37e6a6c50a7e3d06bfe7043adb32244ae359993caad00eea5f1de90355326e921145add1020ef3c2cbcbd102e7b9a150ff9672697d31f86572843269978cbc4c3fe067417e84898587d4de009b33094c8e8102c07facbda62a2996e083d0618fd9651e17f0fc025a946e7c28d93e18675ba69d8811dd06a2cc1aae28de5a6af30f305cfd8a090832483e4ff7c974d47ac96d2f3f7baec94f965a116c2734f87f468ec33cee1a58dd2ccdbc8f6a0f2a50a739aadf4007c7a529844cd1ce5efdd42eb28a0f5f04fde00dea586e4b8cdb8469b36940de19feefd342285c29298afcd3ddc368f6365e9ee255f8c2b6f70c1bafafe10720402a668ac3a2cb8ee75cb7004455cb4221486c3dee64f8f25f1c8b1411437cf6ba70afac5182b21f0efc1b5c71dd59f71796d2719741b6d5c757d824cdfd2d9459569427951d6974d94bea1fbeb0e1a23ef88774b270a8bca65f01a00299258847ddce8af8a7626c802b29dd01d1dd9d2a7243b334c29c0943e11ddbfe82cdfbd506e81fab8775a1d3c4f6c0744e1086763ad84e8f51d601e24cd6fcba1409abbb1c6b5c9bb9eab8ca30282801448f86cd5d8ec187866f1ba738863f3995bf4084ebe8f41dc1ffe0cd47d5a95dc5fc0dde1559ba170316e085d0e385ecf8646bf787b5287960f07bff9d3d990b3be4b29f008de18ccb46dc2192d0fbbbb9e701d350aae205fcd2d7314112bdc393e2eeb0a96c5f2c767dea0b82e9549f46a270b2c69915711c144a7737e9003b1c1b8684e9f2abe66ad1678c32a0c6ce401ae2d7507ff32c8f6179433b94764a6e4ea0a363e9a03787502c67ec97724d78c1257499379ecc5cd006a13acbba05dc7f1310bc75b9ec6a09f4d95b2ec11952eb3dc3d2dfeb8678b10b5db162b44af56ada56f7e311d6c5ce46472d9ba2284126f8f579d59a9d3e81bb1b26a7ee59c3cca96252fd4ba8e009a213911619ab4184e83683969cc4c474e934f36e6ba4ea33d9e93e984f1603e259cb7f1a3824dd8764bbe30ae08166aca84e63615e59c31d2a968a0beccd40637db22b971d51a4c35ce83108d8975d758669bd83ff9602718a882b943f80745d95a2d5e07ad0acf8023e24589fd68988a350c0ad571470f8b9a906648895d312100cd18089465de942ae0c7c8bffb5d3705c729990721bb0497dddea6dabdd530c9ec90286cee5ba3e2b699eb2de55de8aa0012b38051862bf0a7a22d6cce4310dd8dc47c206d9eb7bf28f2a53afa8fd10836210c0c461e417be42d89ea659a76d5e3cba08daa885b7f0302c5df05c72f8257f60e2ad954891841e67d8b7184cfa47e51e9b36f6ed1400aa84c5058a1998d07709b8b46630d70c73552ada18713310dff4177e2143aada1038bae9a64e02870a7535598d766f447b4e25dbd009009cc0e3421067bd0cd10735469b308cfd7a094bbdaaef2e31c22dc6c1a6d4c7890020b5bd04ef649b56889b2031c1923a69002448dd5db1142384cf517b08096539cc537532f43afc33ca77beb2dfee921178ad51b04f10495365e60b4b7677880409716e0eaa3a1d649a871234f86787c2792bf1e04a635e3f22b8b3b1382be942605c3855a940cfa3825a2f8993312a512c81f92aea0fca95bd1bdb6b9774ef3f1fd15bfa1eae84ebb48bc9b55fb2141c55cd3188eeb5049b2e6f3360e60c5bb7d91c9028ebc9287b4b5541a4ca290288e08ca46f80eeabbf100f700c873d7e69dee7dc80b842004b2bb93f0bf533488028d1a1137371417d06785372ce942d4c6589cdb57514bde81960475c22393eb02a93b6560fc3e4fb6ba692dc362d38e33a41b7df222e9192fdc0e0499f110e681682e2b500c00947d62280482dde5e26010cf959fc717d0837c98634550376aaeb17c1c80e3c3245c36c68f56fc8be117ff84957a75e4aa4caddb38779f1c50086ad4863002127b6c8067f172aa78137908fff82b2297a53d6232c26a2e94bb25b7f9241013adeb36d1e437f2f6c0d983efdb78608e940390005d63c081eaef21d7f00ddf51a3fbbe6175be436a9b0b75f198c30efee2821ac5f088819eb96ba835999d0012e7a0c244268a658bc6b7845d10178283cb8add0b81405ccd64000c1835111511555eca14f7e3cc9274b45f817039ee62cfd95363cc66f5397f88822f790e0a86b6a69379dae77db24185394d9fc73880d39f6b3233dd8d3b912995b22905563ae8cb2b1f3491feffbbdf2c7d2e89dce1995d2429bb0a4c550860835aef589983d3170387971f8aec15c18450dbc9cd12f402589dfb17216e359072ceec8e9484f9b490a288dd4b268233c40ad23721961c390bae0a181c4cc8eb68eb4b2a5db6944042c6ef67550f9abf3b9084cfe8521b62d727416576a58591dc65f79f871958243ca4415d92d3e588c4205b4a3806d64224e94e8f04dbf7f75888246aae9f894bab1ea69d7e10b4f07e8cf2dcf70cc62571c737cb6b6c68b0e3fbe4b1931c8615a793fa3db0a45090458ff62ce8bf421907877e555cdb97d3709bbd8728c4432288861a56cbfeabbea5f225cd29e31d99eb788704a93696f5e813000063020003c54f16cef0fd4185f35dc6784047913c89883f72b68aa78c16f144624430909da01633eb2b4b13eccc2b7a7ac5ef3b13505cea54e1d390944b5680e6860184e35111675dce504784f4ae8121dbd1f76df3d55ef722f3f73b5b7723efe2fd34b1fd4e1060330000000000000001a4092701f9170991583ec8b5c9b5056ddaba7637f7d6733a57dc4990acba6d15e9eb5dca55528e179b98a9e09e05ba940b59558b768194ca046c22e12ea310ec05bcc795ea419277649d40b145e6f0accc31f2d7eb39b29b51d3ba3410536b9bb37bce9014d352b496b93161fc799b23939ee635f25c4cbd6605029722ac2bfed7d55fe4120c0cc880661ea3313d700e261ba973bea5df4dc4d8a05652d193c5edad01945862943a6756d4b0ddc93ad5a444ecb054bcfbbba3635aa752d9c4fe8f93fc56c8066b3fe344143d65328025f5184308f2016eae65df8b0f1818f59f5a9539eec9c9c94704ecac269b008ef25f67ab2b9ab4e903b1f2372d1d3988b86e5efa639f9f964599df8559622c8d11f6bc4f706c74e4a603a3798005e210f93d9e6b59f8ccac907dc9cff127c552c8c89981e1b91c817cd365422eb6bb0c7ef4ddddabd306b0c32a98464973dec30def4149f8e9f35de6840cbd0ce8a2f2b5dec15e3f3c27d0d2720159cabb3ff2f73b4571eb53ec735d7b0f27bf4d23cd8b0fba14d5921d464beb3fd4f2fcf844f76a7f7f129a3e7e1c4a6e4f07490f2cfbac4e6730148397c73720d35cc5a46fdb1e774e17f7b951887c1c72ae4cb25ae99bee652ebb2ffd9f4c9400ee0870b27a5dd8fdb8224aab6738399587b4513d3441e26b898b35f739d64047ce8de70347042fd18c3797b1de82cfe23521dc8e5c36e286c05d4f81508e282018cd8d263164512e6ab02a22b3d5d489e6074f9370e218a3adf8afd229659f5046749db9615541408739d4f0646a853b25f8e549e85708c368e45f3e1d20ab47a4ed647b820a360e4e351e4caf74810098f0df4bb74e0e69f2db3284c30d24a0d109d16c37509557ce15c81812bde78085f31cd7c93140fc43d6580abc7ca2adfe6354510fd8104c0f1ffe46d24f31bea808376ac27996fb992de15b30abf4df6f4d08860bec27a95bcee0df8f0a5bd7f72938ca9e917f39c5425bff826c4a84a1fd70cff87be2e8619e0d3b729f0aadc10d4b70d10c2c020a99d03424a595294dd34b84c83a2d434b98fb116e2ebc8b2bc444740ce090816218ea61da172e30db5e78a58ef495812c287e3cfab7bffada0d6f2fb3c153f1a225bfb46e7e9bae9b666e72c35597797927e1bf02d1488ba90948f07dc12f6d8b61bc04d82994708725e0ccf5d76dcac946f36895402e84856b3e25567156040510fb299b88c45713175c54fb3d54aa6d383c423807778a92b7d9bc8fa347923749d18c96b20cea608b6380b57c35b4408f724046f6f65fc0d71e237c39376e1e769cd0234473a261c76553c655de0e4aabb4fd44d0247e4ef08f48bbf13a8cd366491e834a47f8a5cfbd6ca91c832fe4f77b3b3140a6c1c70055d52f0aa67e7d3ba18e5bfb09f738141a611002ff9e34188d540ac42f48ee06f6925cbf3cca5ca033c4fe089650a2b86a8350367e9cfbd07fac9667c0171f54311cd5b37157678b3d6155f0bd12ce53f6599fbc5beabb1f2a5424eb3f52ca3c1e0779d9cbc5e106693ff12d6e66c51bb1d12dfaeb70bc56d5870fb5ce4b040f86d7725ae53b1844b07557feca4d0e4c55a9cb6b6164c4cd3fda89f2a7259a4cd7682de9d8541af2e18b4e49218ef48d97df114971b298a6c4af231a432d4ac295d0d1947e09ccf41ab104e5435e7dddc0a6815b636a31be9a0d9cee2f22c745f05f384bd703fbf4bbcfeadf177abf4ca4524f38a681e5436a06abf9ca70c7569a7bcb8337b0b0c280b5f790ebe1258bea9c1da58c65c13991efc1ef8f7c75ef28affa340d84b3db3f4f188b1c7f437b024dfa6207d5329a5a7a0a56018b1f96a1963961065e07e3b2759f7e27ed707f5807342bad0935ed42609849d7a9d11addf8a92df7933e353a9e86213db0a27285e432228cf2166d3fa2a7f6dcc4f1331303f8db6929a3c0fbd6e82ba4496f3eb2812c986f3e2e627240a9102089725057c1e5dcaa3bcc5efdd6ba7e8a496f609aca3dd82816552c669c255283f9372be7d8f12b044f8c41180aac612245945a4467fa806892d55ff425adbbe92bc892698a32d39d7c23be4ecf4b07d79970eb3db84ad3ce589bb8b134761a442f8ca4e2020a4a42912753603f72738d5ca88c5d8280c3d8af9e83c18be420bb87db4b82a98d3af42f9191d4023eb22f428def2ee99d04d1497cb8205b67c9ca893f7afba077bae5fc11cfeb53d882763f2eb6731bab373923a63dda3ee1c1b6207e0ad0884290333dfae3f80e85cc50a241c73d7d99998e9b14c3e52e660edfe594e1ddcef04402e8fbf9061a5e0b3441a1cea68cd7e067fb146f57f370cc94ef4f28f4f5dd36f45173e40ce91d021465610b85b5f1a98e6908a17c5e138f2dd7da2769bad8789eed99828e8f23952bab7e9ead5fa9bac781fecc93de7927544736fd5c57f1da32be31b85657c313cd02104e1b889426bf4c8e9daa741278ae3966ea673cd3fa164ea7cc947b34f86c92084043ae846aecfbb15535a9b21e27fcda9a21bd8210721355b4331d01e57227bf6572d9538e4998313c5b8bf6e2f3f7bdd7510283f20ebae59b7b0784c0759dbf1036645c5d673edb45245f5e78407978b63d5c25ada76b176dcff53e76801d7c2784d4687561f32e7a32175c0fc77227b3ab0a4054462d04446e9c77f30cc87a91dbcf27516c956dca6b93bb4315f2f0765981e7525a510410af05c462f08d328cefa4bf8530250f5a4d3fa7f58f5a48db45cd68d0dd53a2c66758a20184cf226565ce558e60f0af982b02672f8ab14333349a5e5a5dcea61a09f93addea3858fea4e49c84f5d8269a2fe52f072d66240e7d30b7345c841ac22c16ee979c0f980567f24bb4bc2997ded6fe345d1e95c1b5cdcf006eb17d492bf3119f1df2404ff9bfa39568a52fadf98ac6d5a4653862d91b995ab166fa9de73478f7e339941e036b621f7d773a5413471d6e41a68c02ed89a4882bfade2b10e399f4515470ef43930a911609911f8b66bc060ebb186cdc4c1aa3cb573d696b0f48a655f8877f68f678bbf467ec872724181d6f983682389fc8a61a7525bcd61ab37930e6eeaac82b7adaa145e2a0bf67e235a657949708f0640ec802a174b1bcd7ca384e09b6f0e811f553609e88c5e45252d0d9ecfa42ebb69b7c2d22bbbc6b33c79f3506806862d7600e62c51c4d909472add5eb08e2c5a8ca3d58901a49e77f3df8841de18a30a9bc321ae43c712dbb9f08b457dd3e3f13244ae03da16acd6d3e861efae625478a89020655f0de72ac174a50834db564d4e60bef51e28954a938c64a6ee290523337153aa4d6cfaa00826d2aae1b57e3ab857e10cf2b497597ef9395fe6afb3d74b21c5d44281f756e018539ce8b7f4bc663db1eac9b976da2f994b193a30bde0394b7648b55ad9bde958ec5bf89eab516d4418451d8cbca637c1d6dfdef61712e76aa7f12151d5717ba1af71c4754136563ff2667bb1603cda51baf8a575d4069262179828d54694382f6bb93b98ab9d53d29793a524ae9c42c12dd42067584c4a96f6c15fe590bd8616983abbf453ee038f385a1265f7856009646cdd6f409d9e1e7fd36e1cedda1137429964b71af9d438da0858e817ca746438e0949dcfe49fc67ae967d13d1d1aa37c2e410bb95609c7ba0586c8fccdcca933b1a85ec97d1aff670004f71232bedbd192ba5e5a681867470c4e146221bee322a5f458a2bea1316d3f4be26efbcdeb4b1062e58f2fa23b144cfdda55aad3ed7142653c7948b6d854abb8d1201e9a4de07b8985fc194e58ea08b4c8528adcd73ae6bcf5493b7b8ae1f663ace587a87d5a341828612bf82605ce6cc286ee0161631ba06d704d2f52e37e3dbe44fc40c4171446d0afe69cf8efac8657d9d5307f158d844bd3664865724aa9907d2ccaf4cae78e056ee78815cbcdccf4b11e181a1d2841b0146eda60d561762a7e3512dfd59fc133713e5c056cbde75d5b536d632338fe83a8d02a4b7fa9a6f1a5df9de85c88b944581294609c880ecb5eb45de087524d896486c200ad68f5c45e43894d6e84493bed02602ab075c8d1e5e5be012e4ce474423bdd21d8d6662e182a2ea7eb30f2604b468a25c417c15a2b55031563810b35f33503cdbeb46de12c0482c70b07b5ca3c4e2aa21be75c33a23e73c03379c434dc8bff54dc40b0a34f476d0fd1de0422ae6edacc8a729ed2443315336b208ceafa68a229592e42f49501cf03fcf04ed2ab60cf7c31bf4d498f10569eb3666501cb8ec6e22f1825b7e69f632c24180c3af0d658dccd1c5896ae71b5ce46dfafdc12f94a7f8f3d1bf1eb769f52f43238ed411a97e55625ddc208affbae8ade42829c82cf4f62423830db9ca4091fffe3d282c578552649a34cbfeef3d58e020978137a44fefdb9083186dfd712301431b78095a0997f0764f26e084ee5a6d1d7b24b3b0ae4100da91329f6e8a0a92f3fd94c8b53270b44b9d419e101e18bbf128c7a3492e8447533b7586a81e52366bdf2c376a57847b8a44f7b55eaeee6ab2f06596a87ccad4a60881bcf4b4b5d5f0de85593b643c0c4fe1771a0cb5bb0402fae0f1a2dd811d6495676ad718b73d4b86fc79ce074aa992487108dcb4d908f0da654a3e1b8dc28cc2fe35762afddf2c93fc7a0593ff7c7aabce02dffa8817e66205b179f37bdda376d25d6bbcc83a15ad757bb7843aa03d2f7193d8d707ccf4de1f5c8694aa212219752addd55cbb412c05118c30555ca7ea820bf3440d1dae3332947a1cfc22e366d1ad120b906274883d7769983eab6afe18a253fc6355f81f60eb54f6ef7a48ac185d7e61d6580852d4b98443ad304ab8e7725468034d2ecfeb68228060bad59a4deaa40843d0cfe0a1e58855113bb7c5965254b82cf3997924d0a8b1711b1e1e5b28343168f64fa9bdf8e5158f33c91112f61ba782a4f97c5456c9c8756adf53a7d919ad90654a1c035d8686f83475038580df22e4a72ea9f0cb73470f0b52544cd7916f6487afd32e0527a311f7bdb29e4e4dab266b7221a2c49e42d8ab06ab6d16efee2a0e0bab140aa34b53f70c808f3966f1a171bdc789e23ca0246328dcb1680c765fe262048b869c56f381bb7ded54e1486c0a3660d990f4bf0e5b4eec4cc0c3abf4edab6346cb531194c27de0d85fbd39f86d1839854a91291164823db1fd76397800c3b62b418bb3a894840ecc78579dd242314da99f01df55a45dadcc87e4b216aa0d817e60673c9807a75185e52a70f04ab8ea28cad805c37fae5417f89af44d4a5728c187c74ea736f21681fa7f93dd9bcab9b510febf2c4b5c64cbedb6b59b77a8816728dfbaeea423bba4663ce831af234352f8c68c47dfee91724c99eea5940f57b4f1d9660f0021892a2d39ce7ff235425942f2007b4e08f2002018f720e0339bfa2704a9d74798b13c6fda733d965666ec5592d1d6dae7af6efe5c87cf48d40858937b1ecde3445ab2c1ba1e87e1c2f3ce696baf3efb30ecbd9dbfab121a142ebfb4f09f343f37e851fcb7bf011f2117881098afc5a584e6aaa79f11d4d540874ab905787577e6407a3aaf293c886b58cfe9bed8a3dacda2a2ce41f95e72e46baf65ca666f61bb548afe8f92e1c4ada258f46178a4591015678fc542d412f7ed323d2629c127890ad9c2151261c4869f59db9648e09c25bd5ad8cfde27ea4ef22666ae0f30a4d25ca5cf42ddf3f75d2121c46e28f565d561c9c5ffbefc847ecb75a2595c3e410c1704d6fa62fa5fd54139d95217734ff4e596f2ac975bbfb8fda29f7e6f211eb165480e44fde387d4833f89c7162c1bda3265a5271946c5392921861ad5d9e5b672afe4778301d7a8a8d8a03ca1c99d73b2ee43281c0b88ca4292a5ea29a0e23770 \ No newline at end of file +020000000102cbbe4671915035276d8df41a7ef0b6a36dd101de48a4076046fdba3b0bec20ae0000000000ffffffffcbbe4671915035276d8df41a7ef0b6a36dd101de48a4076046fdba3b0bec20ae0100000000ffffffff040be6c538eee2e29d44c66a3e66fc8165afa4081557031826a070703cb69faf2438089f9677efff5962164a434b0bffe53d90c271deda3eaf30c1d7a55105d24b874703701e53a6d0b960398abf678382a4d17c5c153d1a2c8ffb76b302058ce915bb0d220020c731ad44c00a2928d508ad82b05868cb42733a5b0d0b208f483307ce8c328d930b8529a893bd81e38743e8e3015095077f6e244a064d64708963c6af5024b6aeb30821b4e7599b1b4faf29b521f1c442dfb0a893499d374c19db939c0c9a3b9798c702b642f0e5b34746f2f6e3b511d037e16bc720292da4ea2fb31ec09f6fdbe777ce22002058037c2d81d3122185c8704d4276e2629122c95b8ea68575c451628d37eea84501230f4f5d4b7c6fa845806ee4f67713459e1b69e8e60fcee2e4940c7a0d5de1b20100000000000001f400000baf4431fbb8f0227bfc0008368606a4b8f2bc1706e1a06cd4d83706217b74f5b909a05049129b0d9e61c1bb87a9fa02c2435be35e3535082a772f65222f2e4a48cb03652ba5800d63722adef5232d31ccc12403055de720f0155fc47bba5750ccedd4220020c773786f3addae4c21acb094f39122c032daded1cb6225a64d923a0344087bfd00000000000002473044022040d1802d6e10da4c27f05eff807550e614b3d2fa20c663dbf1ebf162d3952689022001f477c953b7c543bce877e3297fccb00ef5dba21d427e79c8bfb8522713309801210334c307ad8142e7c8a6bf1ad3552b12fbb860885ea7f2d76c1f49f93a7c4bbbe700000002473044022017c696503f5e1539fe5cb8dd05f793bd3b6e39f193028a7299a80c94c817a02d022007889009088f46cd9d9f4d137815704170410f53d503b68c1e020292a85b93fa012103df8f51c053ba0dfb443cce9793b6dc3339ffb0ce97af4792dade3aae1eb890f600630200039d46edc3d830d852edbdf28cbc023dd1666cc4a806ec9d4acb2c97865280698d61fb6b2a073be4ce75cf8193fa9b3d677146575a812873ae7eaa7b08110cb88904273dd65af35115dd116092a56ab45fb57178d8c5ed4cf99474ff760f6e987dfd4e10603300000000000000015bee4d0045b0884354b05d0285abb287ee8e539e8146b92dceaaee6fc01af1a3730cece4c77caefdcfcea1073197ffb8b3ded97d0dda6f49752b31f23e196378a3da2128a8c45ecb7eb1c32f0c0dfa1ce7bc348e799f66d547476e976baece7445790064b34b1526c88cf54928acc906ec0925327d797d36d0db6a43633d7f963ec9b4123a5ea31b655882329afe2108d123f76857fd3ce344fcd651b3d3066aa506625c9309acead85fb6c8a7d977db5dd6cb6e2f99fb3535746258d42d95dd2103bbaf5d45c8a2dfaa2301eba08763bac8ab3b59bd0082a457bc0cb257c43ea6354348e73d8dee101864068f0e8e30e6711f1597d7b529a57e95fc0df813ea160f5f5152f341087868a680c1bbc4b2a427d18cf8f12cbc4304dd3b1ea4c916467ae48b3b53062ea046161170fbe6ca07462cf3e5534d638c91fe6919318c4b2e98ce0ebcb245680d6395ba746fbf510a9a36ad8d933b023eae39973a39162178148a897b5174940db46e4be54794cea11fafbed48b42eed27f9915cfc50c958e88bac551ab1c9bfa03653e558cf87a99ff13440f4808e27fb42ff3cbac9fe10d1de07dad4807c9f945784163214c739a9eed8bb2e7da6e1fdfa4aba5d5157787d0000b220145572d3d9253cde5c1132370c1849847633287660b429f20cf1f72e4ad6ae59154c3b8526fc5d30523ba962a25577427988d326e207c97c81b479540b1c63aed0a4b1dad9279879740b2f6a0bfc37aea8c81b3b35b630dba8d955afbba756b8ce9d2a9802939972c5f70efdee8778a98360eef15faf77e38627fcb4f98569d68ebad3bb667e5db46eb7f4214846e651224673dc998c55bdd9e0a1629497a75b76160865c7ac3af874bc45a42269508f183d2458835b1734791094122f75398da2bb7919c67221ee42242c298d744fcb920726b84bcb78d7eafc9e0f61a02de87ffc5c674390a33d722b50dc35bbc6788fe0fd24be7a9e358113a4e65b49655767b8f3c3bb86cd5a56c79f9148945af63492dffde82d682eca4787f203e49790650395c925e6eb68bbb3adda25bb784365c0b3e241177ca7de58252b8c79c5a865d1030f3bfd4d312bdf83bd28241389085433c34d747f9f45a0a636e700805e619a19739b15077d44d5e8969a37481896acebe7f350449c69b50376b7cf36e906d8a03aa7221de67c7fc4c5408b55e2562f7b783918004d93b284c0a1c3d596c7c18aef5cb77ad09172bfa888f5dceabf57f708f5ab61b1b4159742d3d35332e9942958ea7f39fd35cff66e84ea0ce3b38a85eb80dcc1201146fc3854cb40353a078f5435fe2becfa383b3a62564645250cf7feccff5414581e747166625477c70f5b0f579bd578e03e6b8ff8c3f0e8a82566199ff542b239f2999103cbb61602bc2f346702204e50c9ce7b85f3b8e144227ca8b9766cdbd498191c385e3a4f024c9396763eacdfe41b706fb23d4f065dbaa43d323edf1811950c71d4475a3e0913d3851be4e921cc933bb06b0aa20524267b0e9847b6de3883ab8c5be1eac17b06c946f19dc2244901890cc290f2e66147f7c47a4a29349555ca020e684ccba5f8a6f1be54e356654d3e8678c591633e11d9ee772940d92f07ab83228c0d8840cb9aae514c03358e973a2ef319a39a3ce819efc00e5a493fd582be164c1460f70fb2e103f09a2939f779377275be736ccd41f847133b3d400477582419fbd2d7ff328d88256cfadd750ed7a3c6657e332f635f0a90602b24135e705d1530531b7b738e686d83accd74874e160a5716191447f832d2f899476ec9c53204fc4ade5b75cacdc869b4088e009e12d85beaa3450889de0c86315755ec7744be592f058fafe62f9a89875bd2781d5d6928c8475f555e77eeb6e688bd8d3bee0a54fa1cb29c1b6b438d3f70ee4ac83fcb6f482575997e3a69240c6731b517d8241cd39dba6b02a9e3c94ff2470c61c693d32b1c7d22ba38f0da21d92150115d580249380500109215a05baa63474f773892b1870005e76a68853e6a8cd9f74ab3f41cf0730e702ce94c420dbf66a63f342d927923d7d25ca3c3823b6c352ae2ca127bf811c023205632ddb8f9191c2f3384a61038d1c4d32f808cbaea81d58f0aebc7c89bcb5b98f92849f4fec19cffc78173e601eb412aad24eacd74d17cce3a9ee76670367ed87c2da3db5e4ab01d4d9626d0ae00da7dbf6b8103d5994cf66ca56bb9aab9eabee2b14ef798d3fa5ed1dc16bb500a006c3320941c4c7f6f80c8b1bf79131a5e11ef38db7c42d4c4939711184ea414e2ec0cf5bdce3d7d0d72dc883b2595e5f0fe4c14cddaed61108c90c74b43cbf719bcf7a934bee760ab33f50cedfe3ce61dda3e4bee1ab4dc687f988cfceb207152f7a98c0fa3a114d2d6881034aeba877bbcc368ce591707da45becc48318f0558b3ff65d677578df9fd9e9a18d0cb08f2f5cd4f44925259225b1c4c5ed84ef30d136e7c66251329a223a1db0b485f1c634981f8860aec1f3dbda9442e5438f6fb09c7e1ab43e2b757911834df8502ce35e7be947771f7416f7ea97d26dbad7221614175e6b86f1a323e26c4f469236d1b1bf6ef28823234c73b275c5b0ff39e8c04d9dd8ff7f6a57214d803aa13dbf581295b92ce2b8a9c0e3fa8e4fe4e74c4bc2198fd010cf84681cf5f3fc9df1638c403006478b1cd4204ef3b7a6093116021118a839bd3ac270783e67096457a86d63654e268821ee742241ab5f7e91972da0a94f679b4c093d3f428d5876edf51459331df084f2fa245e3648e0cac904a82a7d323b965a39683ec0b2721105683e67d65fe10b8d41d0dfcd5c31756408c94cf425ae67f95ecac45391516875870386b675e24c462b1f7634f758723e6245da6a39da69cc2390374eb89c6c662d94eeb2f1835e233610072936be248e6a3ff87f9950c2eb2f88568c31dd30d1f0c0396a42f6be2505bf616c63f504dad5312fee2f083b406fa05cf3c998ba24237402681f0ec393de4650ddce3389d4c1541d4705d8f50c2c6d4864934394fba0c40df495fe3a5bf58a5498c1e63b5ee5f9a4b53dbd913252d4808f5bf5fc3c6dd74c86c974fc9e5afb1a7ee3d88738ab1fe9194881cb00197a31d648ae2448db872528d5f7c366188d9d98ea94497cb78ffacb5f6e8a2c8520d8d196fe0ed13e2b2a5a08dc45d8ff58a8c5d3bcbdc5d80c798acd0eabf146459e79db12c2a43c55d14b2dd608475c606fd4f943ae7cf62131691768f710fd718fda3967146daa8d4f34a3b8fe8084f4f3865e9e0cc1a0b0a799fceafd1b74f09f524822179ce38cf0f2c4c8623a3e3ab2cc20f5dccdadffacee62c120657e3d85fea93fab645b5fcdb812b130afbbd5b19e86aee66011b520b0affd84af4bf67a28b309cad66cec25a5de06390a4f2a5af47d59c006010a8ffd214149bbe47bf847fa94c2113723c9476c2e6dd84411bca16dc7bb096aaa3e9a9be27811b52838c78d16cbd89cad379bcc0cd966dadfa428f9d4d8bf133f7d21022ae3f966dbc1409c6d57cc46ff4434fd90d79b6c9e68ed3795ea6191a7e309783badaf8db9fbccbea905ff9d423370810f02add38ad3088cf3393e7c6d585b76fd78c67766fff03ff54c01228c6737da667147a8b5e722370a24db8c0165e34888920d70fb1356eb731d0024676444e2d37860eaaed9790f99069e622afe6ff12d516812022c46420006253248eb292908ab8658cd874ef05bd568547535fd54c1f0b5b816e4d90a1bd55670b96691e7633a2fa45be6a29cf7bbbcf9e5debb4b7a739b36b6b326b719a12cd0f5e3557a2fd94023d8c633fb697b85080a39734013b4ed9a7500aa8093edfc3810d4c890e608951e57af8447349cdf45a076449241a047085702dc3e44814390ceddc878791ab3a6503f48f48af25fe5cddf61e7870ce80e32e5f22d5725bfde4f319c2db7cf3ba3b9952202cd24210ab8d47fcdaa9ad5e2a9d2c7be1ed6b67cbc1a28ebe565ed0337c09c97d2d9608d97905c7201be7d4bac785d64caf783cb3ebff817bc5ff0448899537ce6911c9803744d06ae97e6d3aae037697986cb20061892ae72e05968e9bc54153bd745012af719fe7fd4b917689a6cbb94a9bc8cce51d234ffce7dca804e2b2759f473885855983b7b290806884fc66e724fa848af2de3164c611c630e5bea712cdd9a9943ca3ad55994e5587c5953f415171bdef3c42783b809bc5526a88aae66be626d73394a607ca32256198dbc026d9e09e9659ddb66736215dedee0cf69a24490a53b2c678e6caa2aaef10a4610f802fc5eccf558629554d6388465584514d3dd49fc00fb267c39bb746f76ad3cccabcc3cc882815bd9466d593270a5c9a04945dea7ad06ddb73e66b90270e859a109d52251d911e7177e07295ac9788ce970c1b718fb0c2f327f44fd0cef3cb90071ec85e958e6ae60bd134ae307720cdb10be5a0af8c051295df905447b46206b5e04d775b83e11c348458b1bb310ae25c54e8ed1488a95b2a576002198c80e0e69d14fb7bffcd89935faa6e3f9aed61e0492bb2bc334e389bd559806eff9e16643ddc4372ca83790a99bd4f5b042779ef7e3039858881c8ce0041d43ed6b1f42f18007d046fd6f65907cef73fd5e6cd514c4fa5ebb872b140d0b2ad43c58f2f2216522e78a19828baa34ba56d71414ae869a13cb708762565d754f0754561adbd9145d232034229d2840ef0c96f7af4b232c5e11ae9d018b87177a506b66571affdeb693e170dd12640e86fd430b64509d02694c52a54f23ea96e39be92b65c1abcb262a71d6e884183d4bc6cac8c79f6e94b51abe484794a42a8e1be721cd59383bdbf327a864b2cf27566f1270d82ab6e8b3b934e953b7d48ec4697172e0160b8435e8186a7ea685dd61402b0bef09137fc52e19ecb53674a1c0af17fbb0efc2b4d69572b32600fdfc3c85c79ccb2685c665aef16748b7f15862f435afaeef00f3f927cd3a60c22f137e9cb2c38a9652cee570a76351871ebc9b6fc720b9117b1306e8afb298e3a1d0d4b2c5ad5a21e9de4c0938a98daa35caa711bd6d3312a7e941b060c4a1ec211c31e53da263995d3be74a3ca5a970d3a663245a5d8eace336d9ee847619bb337e777b961805e808f7cfd8f09b93b6ce6c277396e6cf0a6153fb11625f421b02055dc53a0bb24786f4a74211bfdf44193e48b2c15c7c85acd3f4f0bd26644f9dc62653e366178645899dc06d191c785831b98de593519c0ac5849897a01b4f8c7fd559edce1c878bdb9dd091546c64225fa81b1c7dcd6fe72c8131bb160043976a5e891236d3552598c0c4fc734d1cc752c10306dfc8391f6d658ab8b7a1f350e1900edda29775ac8a531032bac968f6981889f13cab07f49c864c3ef3ff23555c170ee9730912465e6bb3b7508e11ba27001d9dc0da8b34954a7c46a2d0b0b75e73ad66278c8acbed3249936a6c76fe975954f7889bbaae5f73747e3ed02811b015beab9d1515e396d37b2a116b3cd8863517b88ee91a854e4740304f7be41123692181a8ae22090956ba619fb948d3f08108da17ac2484d3dd5795b1c716cb5ed3fc08b6449fec814018cd883b02256afadd1f35a04d9d43f661be624c0d59d0d397e8ad6917344203843495162217e79bade11ca32c0a6918350520e6c3f31f866b89e3497b518cdc056e760813ebea7fbf343db50ca2450d5b7a1c5f430859e2040ecfa70cb0c3e863a756ef6ae2e26c68b543d35beb44513f8295872df5b4062c9b80742ca7a9c2ec36a1d9bc936c7fa7328240a2db54463ca04a40dc0c9afe4d570012259c8c436d322483b17a705d60a283e0ea7545110e898ba43ac6130aebde014d237482307ff28f385fce8530814a3b35630200035ed48216bc666598aac5498e9fe513a9e21eaf842d382767220cf98104bfd8866621efb63b2eed44028cdc9e2f64cc2447fe09f8d8a1eb3214272855b525d9ce24e6daee58effb4af28fcb0a4685d78d7995081b5cafd1cfe343aefc8e9cb235fd4e1060330000000000000001ddf2f500cf45e30e3911bb51a7ff633c1e329508e42d9aa49fa8248fa4d293b87005db08b17a472580ae2cdd53c40b2a16af885d6dfa3d5b3410d389b045e6c12405c635511ccf008390856f4c6d0ca472148d2969fd39e1307bfbb8f8268ce92398248f08df7268bbe23e13ac3801ad075376bbe9684db9b41d7b1148fa65a129e1d25193ad973ec7af631a0a30c5659409b0d00e6fe44c2c507d52afbee8059aee7650bee9d47936838e77f00cfec9de3b9efe72cdeefd80a19a9c8ddcd6cd9009ec96800f9fcd709f1432b5715466d601b5ed10b0dfbd09b954b109232fb5a24036b887d26bab43da7eaa303e7c8e9d02950610aba09f343a65a7cb4550d6f6e5c0eeb9410b68f85cc3b05b9340e2e9c94a473f2001f5aea7e875d29e8e0aa99c09afec4a5455258c803e55b89cf6e89796a6f3f9fe11ee05ec415c6ac08e0f1adf9dad681f8121f82e3a9402a2fe13a016dc10d4a605578317be0d9d3e02b0989903002bd35ec4970701da6eb6f9fd5e6cefad137dceffaad968d5ce522e77c76e665529f70c9eb805a240834f4c8c795912c37e7efeb73d4bab709aafb66bd645cf0addefdd83d185c1b4465ee16344575eb2aa3acb057c37d7c22cd03adc6701f03d4cfa20ca94458b3b87e3fb7de8fed28a755bcaccbd348dbc7f5aacbb25d19437d87cb48b88fc714f059b328c374fb2695a26537330fae42d3fcff40b07054be10508fa78a9173315506119973a9158828276edc6e8ac771476d7479d07ba73e9c5b58d61367d24435a1062dfa376546e843b34829103168db63b708a13894813a442f889a423054160b85a2584d36951136bafc490056f1c03c44580e2c7a12b170e5c7a3917720bbbb21e5da616649b554b7ff57dc84dc3935271a8aa6fb218becde208d83e76bb6197f5f4f729f3c57b4280c388bf4945206fa769b672ebd47ef2d0f777fc9dfb031cf7c333c6159a75a5b33ebc6c4683ef140a144a5ab15b2b6b72ba14ee7595679a0f7873a75b9a79e03676ae94eaf9ea8d3532460f3075f40c6b9848a183fe46651caeacd51551f308eab6ba8ac27b93865f5dea0fcfe1d7dbb745695dcf187a5955414763c88ec01d299f03cdaec48eba946c7ff6031f28a5e108651401b5447c0d21c449b387765a621c057eea7d494302222e3d1ff6ee9f8a0580671d9fe3ecc310e84b554e5c823d81b8027075f749b2dc8a6bc5a99fed4a0fc46fae59cc2aa9f1471ca2b0d9fafa56927fce0f1df92647ff5aaa083bfcb7078bd8ee142448d4e1f3dda670ad93feb21028a57ee9a8ae8880df5b3276e078555d868be0d8843b495e082d743328620f36f7e106733bcefac15076826cafce271caf1520cc8746948e71ea73eef5de770ecf5e0fe075f04d6c9cef1cc1f262e69fcfc89862877ffd520e25405d9d07efec82386640d97147e4a6df66bb1fa1f20dcc2ee1fd6364bc2024c0a4a2ec00b84616231c02aef16147df509cb830b9fb20111c60613d41169a24ea67c03cea48e1905b00eba8a61e967b9aa5b6e1264b0f3e2c051e47f54f45c6fb78b46b9993c7d223d51036cb77f5e31a4b30892e8fd7ae7028322d6402f60712f712f84443de083767c38ae88a38fd4e4bbec58015f4e49e36ecbde94f23d0061edfff0e9eb62b67327249d728c278f923748e4c1e225791c740abf9493198f073a6cefffba00d23715a14967a72cc7aebb81ecc6e8bc88ae63a47507296a573c415d0163219f3b20974ba3a32572d29a479b88b89c241e63e640bbb93e2da0b73024ff03516ee3ecfbd84348372cfb574817ca878172a779ff131492b86e64c1b7054cc5fdb999df4a9578bbdd6a6a2a798f053f4c7456173cb8cb9b61735e650d0394ea9effbef615629c1f393949095982345bfc02b9a3b3ec64d9173bb1285587048fca8c740b6d2265d3e727069fcb90282c78f1049ed7925113279474d0d873045851b397a8c26036c83906dccd0eabe98f7d6854d9abc2e6ff12d84c2840affa371cc2dc624fbce873f38570dc9eff33f5e200791bc052307f5c718d47fc2a205add3fd9de2a81cb452a0a7b4a08bc133e9816f6ba852735b813a1b906d4dbd1ac8a968a8adfb6aded0d3fb87d80132a4b45ad39274bb72df20d648a26aca4beaafb971e13094b6d6525bd418b91320964bd90d3a98fb32d69222aaef2ea95c6b84b6b6aaeca3f6789944fc7ef17d218abc7667ddff798b74a0d5fbcc33d22d028d207f82286fd777ea1e281d7eb88b665e29fcda067bf9ef82a190c920e260cbc44d394b78e0439bcaa6371f8717ad82e02015f21e5dc273de338102539bc924d5a3f897eb788e0f3cbb6e8a34590ff5370bcb0f671ce28d6ac0adea17f9fda49c784ae84464991fc71a31d320d62c4199e4f4e38f390ffbcc7f15922c3325451371bebfaed8f8a7d3eead71c65878a705a6163ef649bdc6ae7b81110a2cc9576da6b0188337160cd518fb30fd5b0c165ac3de81002490f36d29f3bfefa2b4796c070c6d7d971d18bb5a573cd48cb3c64dec5bbbd7f2f6f60bff3db4833bb64b426c6715021997350aab1751f0d5382087ec133c2c43342b31eca32a4c17db14148fb48f9b7a103b2c0bfc0dc95ffe097bd8f2213a3f7a43c994599b05dc35d469fdc025e23e483039f271d948972417153c849fa8dbf374693dabd59d398732020e90d8f443ba45a00b430168561de21db76b9b714ca8260fdc4ff1a5713e69ed7296f5a5a9d192474bc6e67788d6a44d46b69ac97d0b34b2b08aa79d5ee7e910d99221e1e7f6383628b5383cec4341e5c3f18ec3361b2f2ee5935ed40919a4f8892bf3467803b720d29388b7cd47067eed9be7648fbbafcc7bebfc31a30d02f38b7d6be1579c751aabf679fa6891adf66da2257432c10d399a8d496d1aba381b64a5e3ec9a65cc8419151b638adea994c3590f77bf390152894b2784f7832d986ac51b20ba9719d85509acdedc0282f27065c87bf483fc74b55579ecc233fd6c51822ae03e46ecdb15acf0204b67852d525168f409d2a4309c5d9a14b35905b836091964ff4fec0aa91bbd7f39919eeaebbaf75c63337a4dcd5ae37cb60fa14bd78157ecef35ddb1cfdc366eecd48aebb0f5b395e4161c158c46870fc89f8f5918aabf0577c914511cac7b189384eaddf7f03cc6706a9abf219ff1b293cc9fa2cac88b65af62f0493e30736b596c119149af07e840a43dba8d97455a7a95368395488304626d3b888069a0099c435cc11e5981412f79153577c9115a1812b1c4a9ea42bbf11b40fdf930bcc37e6a6c50a7e3d06bfe7043adb32244ae359993caad00eea5f1de90355326e921145add1020ef3c2cbcbd102e7b9a150ff9672697d31f86572843269978cbc4c3fe067417e84898587d4de009b33094c8e8102c07facbda62a2996e083d0618fd9651e17f0fc025a946e7c28d93e18675ba69d8811dd06a2cc1aae28de5a6af30f305cfd8a090832483e4ff7c974d47ac96d2f3f7baec94f965a116c2734f87f468ec33cee1a58dd2ccdbc8f6a0f2a50a739aadf4007c7a529844cd1ce5efdd42eb28a0f5f04fde00dea586e4b8cdb8469b36940de19feefd342285c29298afcd3ddc368f6365e9ee255f8c2b6f70c1bafafe10720402a668ac3a2cb8ee75cb7004455cb4221486c3dee64f8f25f1c8b1411437cf6ba70afac5182b21f0efc1b5c71dd59f71796d2719741b6d5c757d824cdfd2d9459569427951d6974d94bea1fbeb0e1a23ef88774b270a8bca65f01a00299258847ddce8af8a7626c802b29dd01d1dd9d2a7243b334c29c0943e11ddbfe82cdfbd506e81fab8775a1d3c4f6c0744e1086763ad84e8f51d601e24cd6fcba1409abbb1c6b5c9bb9eab8ca30282801448f86cd5d8ec187866f1ba738863f3995bf4084ebe8f41dc1ffe0cd47d5a95dc5fc0dde1559ba170316e085d0e385ecf8646bf787b5287960f07bff9d3d990b3be4b29f008de18ccb46dc2192d0fbbbb9e701d350aae205fcd2d7314112bdc393e2eeb0a96c5f2c767dea0b82e9549f46a270b2c69915711c144a7737e9003b1c1b8684e9f2abe66ad1678c32a0c6ce401ae2d7507ff32c8f6179433b94764a6e4ea0a363e9a03787502c67ec97724d78c1257499379ecc5cd006a13acbba05dc7f1310bc75b9ec6a09f4d95b2ec11952eb3dc3d2dfeb8678b10b5db162b44af56ada56f7e311d6c5ce46472d9ba2284126f8f579d59a9d3e81bb1b26a7ee59c3cca96252fd4ba8e009a213911619ab4184e83683969cc4c474e934f36e6ba4ea33d9e93e984f1603e259cb7f1a3824dd8764bbe30ae08166aca84e63615e59c31d2a968a0beccd40637db22b971d51a4c35ce83108d8975d758669bd83ff9602718a882b943f80745d95a2d5e07ad0acf8023e24589fd68988a350c0ad571470f8b9a906648895d312100cd18089465de942ae0c7c8bffb5d3705c729990721bb0497dddea6dabdd530c9ec90286cee5ba3e2b699eb2de55de8aa0012b38051862bf0a7a22d6cce4310dd8dc47c206d9eb7bf28f2a53afa8fd10836210c0c461e417be42d89ea659a76d5e3cba08daa885b7f0302c5df05c72f8257f60e2ad954891841e67d8b7184cfa47e51e9b36f6ed1400aa84c5058a1998d07709b8b46630d70c73552ada18713310dff4177e2143aada1038bae9a64e02870a7535598d766f447b4e25dbd009009cc0e3421067bd0cd10735469b308cfd7a094bbdaaef2e31c22dc6c1a6d4c7890020b5bd04ef649b56889b2031c1923a69002448dd5db1142384cf517b08096539cc537532f43afc33ca77beb2dfee921178ad51b04f10495365e60b4b7677880409716e0eaa3a1d649a871234f86787c2792bf1e04a635e3f22b8b3b1382be942605c3855a940cfa3825a2f8993312a512c81f92aea0fca95bd1bdb6b9774ef3f1fd15bfa1eae84ebb48bc9b55fb2141c55cd3188eeb5049b2e6f3360e60c5bb7d91c9028ebc9287b4b5541a4ca290288e08ca46f80eeabbf100f700c873d7e69dee7dc80b842004b2bb93f0bf533488028d1a1137371417d06785372ce942d4c6589cdb57514bde81960475c22393eb02a93b6560fc3e4fb6ba692dc362d38e33a41b7df222e9192fdc0e0499f110e681682e2b500c00947d62280482dde5e26010cf959fc717d0837c98634550376aaeb17c1c80e3c3245c36c68f56fc8be117ff84957a75e4aa4caddb38779f1c50086ad4863002127b6c8067f172aa78137908fff82b2297a53d6232c26a2e94bb25b7f9241013adeb36d1e437f2f6c0d983efdb78608e940390005d63c081eaef21d7f00ddf51a3fbbe6175be436a9b0b75f198c30efee2821ac5f088819eb96ba835999d0012e7a0c244268a658bc6b7845d10178283cb8add0b81405ccd64000c1835111511555eca14f7e3cc9274b45f817039ee62cfd95363cc66f5397f88822f790e0a86b6a69379dae77db24185394d9fc73880d39f6b3233dd8d3b912995b22905563ae8cb2b1f3491feffbbdf2c7d2e89dce1995d2429bb0a4c550860835aef589983d3170387971f8aec15c18450dbc9cd12f402589dfb17216e359072ceec8e9484f9b490a288dd4b268233c40ad23721961c390bae0a181c4cc8eb68eb4b2a5db6944042c6ef67550f9abf3b9084cfe8521b62d727416576a58591dc65f79f871958243ca4415d92d3e588c4205b4a3806d64224e94e8f04dbf7f75888246aae9f894bab1ea69d7e10b4f07e8cf2dcf70cc62571c737cb6b6c68b0e3fbe4b1931c8615a793fa3db0a45090458ff62ce8bf421907877e555cdb97d3709bbd8728c4432288861a56cbfeabbea5f225cd29e31d99eb788704a93696f5e813000063020003c54f16cef0fd4185f35dc6784047913c89883f72b68aa78c16f144624430909da01633eb2b4b13eccc2b7a7ac5ef3b13505cea54e1d390944b5680e6860184e35111675dce504784f4ae8121dbd1f76df3d55ef722f3f73b5b7723efe2fd34b1fd4e1060330000000000000001a4092701f9170991583ec8b5c9b5056ddaba7637f7d6733a57dc4990acba6d15e9eb5dca55528e179b98a9e09e05ba940b59558b768194ca046c22e12ea310ec05bcc795ea419277649d40b145e6f0accc31f2d7eb39b29b51d3ba3410536b9bb37bce9014d352b496b93161fc799b23939ee635f25c4cbd6605029722ac2bfed7d55fe4120c0cc880661ea3313d700e261ba973bea5df4dc4d8a05652d193c5edad01945862943a6756d4b0ddc93ad5a444ecb054bcfbbba3635aa752d9c4fe8f93fc56c8066b3fe344143d65328025f5184308f2016eae65df8b0f1818f59f5a9539eec9c9c94704ecac269b008ef25f67ab2b9ab4e903b1f2372d1d3988b86e5efa639f9f964599df8559622c8d11f6bc4f706c74e4a603a3798005e210f93d9e6b59f8ccac907dc9cff127c552c8c89981e1b91c817cd365422eb6bb0c7ef4ddddabd306b0c32a98464973dec30def4149f8e9f35de6840cbd0ce8a2f2b5dec15e3f3c27d0d2720159cabb3ff2f73b4571eb53ec735d7b0f27bf4d23cd8b0fba14d5921d464beb3fd4f2fcf844f76a7f7f129a3e7e1c4a6e4f07490f2cfbac4e6730148397c73720d35cc5a46fdb1e774e17f7b951887c1c72ae4cb25ae99bee652ebb2ffd9f4c9400ee0870b27a5dd8fdb8224aab6738399587b4513d3441e26b898b35f739d64047ce8de70347042fd18c3797b1de82cfe23521dc8e5c36e286c05d4f81508e282018cd8d263164512e6ab02a22b3d5d489e6074f9370e218a3adf8afd229659f5046749db9615541408739d4f0646a853b25f8e549e85708c368e45f3e1d20ab47a4ed647b820a360e4e351e4caf74810098f0df4bb74e0e69f2db3284c30d24a0d109d16c37509557ce15c81812bde78085f31cd7c93140fc43d6580abc7ca2adfe6354510fd8104c0f1ffe46d24f31bea808376ac27996fb992de15b30abf4df6f4d08860bec27a95bcee0df8f0a5bd7f72938ca9e917f39c5425bff826c4a84a1fd70cff87be2e8619e0d3b729f0aadc10d4b70d10c2c020a99d03424a595294dd34b84c83a2d434b98fb116e2ebc8b2bc444740ce090816218ea61da172e30db5e78a58ef495812c287e3cfab7bffada0d6f2fb3c153f1a21707923ae7ec862d44d357776803336566c3bebc9f53177a3a8825478eafb32a61bc04d82994708725e0ccf5d76dcac946f36895402e84856b3e25567156040510fb299b88c45713175c54fb3d54aa6d383c423807778a92b7d9bc8fa347923749d18c96b20cea608b6380b57c35b4408f724046f6f65fc0d71e237c39376e1ec6dfc6a2ae83ba70d25855c10e6a8f425951c52fac7758353e2068e5cb4b6ea066491e834a47f8a5cfbd6ca91c832fe4f77b3b3140a6c1c70055d52f0aa67e7d3ba18e5bfb09f738141a611002ff9e34188d540ac42f48ee06f6925cbf3cca5ca033c4fe089650a2b86a8350367e9cfbd07fac9667c0171f54311cd5b371576790e51a1fddbec64f8f559cc08b1c0ae5113bb0c532742d90c1a266bd7eaa4b1d06693ff12d6e66c51bb1d12dfaeb70bc56d5870fb5ce4b040f86d7725ae53b18c1b12a84f7e3a2e7d748e8a899fb917987518c6dbbb83e3b62b31b0facd3515cf2e18b4e49218ef48d97df114971b298a6c4af231a432d4ac295d0d1947e09ccf41ab104e5435e7dddc0a6815b636a31be9a0d9cee2f22c745f05f384bd703fbf4bbcfeadf177abf4ca4524f38a681e5436a06abf9ca70c7569a7bcb8337b0b0c280b5f790ebe1258bea9c1da58c65c13991efc1ef8f7c75ef28affa340d84b33398790a9a77d30b0ea35613b39b1b7d8667fd7299e2ff38de468f625df1485ee3b2759f7e27ed707f5807342bad0935ed42609849d7a9d11addf8a92df7933ec44e86ac7f24d55a55284fbc4e4824a2b4f8bcb146d08d7d6d3f551ce1b494d7c0fbd6e82ba4496f3eb2812c986f3e2e627240a9102089725057c1e5dcaa3bcc5efdd6ba7e8a496f609aca3dd82816552c669c255283f9372be7d8f12b044f8c41180aac612245945a4467fa806892d55ff425adbbe92bc892698a32d39d7c23303ef65c980c608b5ac07ee60ed2b4e028a5565f5aa3ecd1e15787c23716697d53603f72738d5ca88c5d8280c3d8af9e83c18be420bb87db4b82a98d3af42f9191d4023eb22f428def2ee99d04d1497cb8205b67c9ca893f7afba077bae5fc11cfeb53d882763f2eb6731bab373923a63dda3ee1c1b6207e0ad0884290333dfae3f80e85cc50a241c73d7d99998e9b14c3e52e660edfe594e1ddcef04402e8fb01efff9c00d9a6ffc955e219fe9c92cbe87865f7a25ac68fa2d360c584c33fa3e40ce91d021465610b85b5f1a98e6908a17c5e138f2dd7da2769bad8789eed99828e8f23952bab7e9ead5fa9bac781fecc93de7927544736fd5c57f1da32be31b85657c313cd02104e1b889426bf4c8e9daa741278ae3966ea673cd3fa164ea7cc947b34f86c92084043ae846aecfbb15535a9b21e27fcda9a21bd821072135554e3015d5a12d1c7f2fe74dcef63fe99c947b55a4253add3668bab2d356d58909b7b0784c0759dbf1036645c5d673edb45245f5e78407978b63d5c25ada76b176dcff53e76801d7c2784d4687561f32e7a32175c0fc77227b3ab0a4054462d042931897530502c85f0b976fe3e3fd5488853b20dbd27d0d736e9f44fe6224b9610af05c462f08d328cefa4bf8530250f5a4d3fa7f58f5a48db45cd68d0dd53a2c66758a20184cf226565ce558e60f0af982b02672f8ab14333349a5e5a5dcea61a09f93addea3858fea4e49c84f5d8269a2fe52f072d66240e7d30b7345c841a135271c07e6a142ad1ef1955e29469d3ad3d952ca9055696dd825253e4a0e4822bf3119f1df2404ff9bfa39568a52fadf98ac6d5a4653862d91b995ab166fa9de73478f7e339941e036b621f7d773a5413471d6e41a68c02ed89a4882bfade2b10e399f4515470ef43930a911609911f8b66bc060ebb186cdc4c1aa3cb573d696b0f48a655f8877f68f678bbf467ec872724181d6f983682389fc8a61a7525bcd61ab37930e6eeaac82b7adaa145e2a0bf67e235a657949708f0640ec802a1741590a505e4a109ba857824e00f8f675ae6bc8a0f32aaec0f38398c33c8f53bb3cd53bf697ece4372f8f252ab4b314769f1393aabb2675f44c05dbd279732824d49e77f3df8841de18a30a9bc321ae43c712dbb9f08b457dd3e3f13244ae03da16acd6d3e861efae625478a89020655f0de72ac174a50834db564d4e60bef51e28954a938c64a6ee290523337153aa4d6cfaa00826d2aae1b57e3ab857e10cf2b497597ef9395fe6afb3d74b21c5d44281f756e018539ce8b7f4bc663db1eac9b976da2f994b193a30bde0394b7648b55ad9bde958ec5bf89eab516d4418451d8cbca637c1d6dfdef61712e76aa7f12151d5717ba1af71c4754136563ff2667bb984a80a51ee9112587cb77ed6fac8f4263fce637adcab9f315d6beefe509f8d34ae9c42c12dd42067584c4a96f6c15fe590bd8616983abbf453ee038f385a126dcb71919dd7143a8c27186e1c6d29d36c1039a8f008088e03fe7b97fd7f285a0817ca746438e0949dcfe49fc67ae967d13d1d1aa37c2e410bb95609c7ba0586c8fccdcca933b1a85ec97d1aff670004f71232bedbd192ba5e5a681867470c4e146221bee322a5f458a2bea1316d3f4be26efbcdeb4b1062e58f2fa23b144cfdda55aad3ed7142653c7948b6d854abb8d1201e9a4de07b8985fc194e58ea08b4c8528adcd73ae6bcf5493b7b8ae1f663ace587a87d5a341828612bf82605ce6cca9253057a8096f396bdacefb56f9a452849f0ac652738b5b3135ae13af532dac7d9d5307f158d844bd3664865724aa9907d2ccaf4cae78e056ee78815cbcdccfc38b71e0c648b1fd9f710a15d799e237c344d53923d3941e73f924b75de975ead5b536d632338fe83a8d02a4b7fa9a6f1a5df9de85c88b944581294609c880ecb5eb45de087524d896486c200ad68f5c45e43894d6e84493bed02602ab075c8dca1e57e3932740c25a9401b5bbc1bf524f4885f77a501bc3c313666fdebe7497a2b55031563810b35f33503cdbeb46de12c0482c70b07b5ca3c4e2aa21be75c33a23e73c03379c434dc8bff54dc40b0a34f476d0fd1de0422ae6edacc8a729ed2443315336b208ceafa68a229592e42f49501cf03fcf04ed2ab60cf7c31bf4d4fb5a8d7b8969ddfa8a725eb9d32827446c141170bec2b0dfb5c0a6e00cf83b856ae71b5ce46dfafdc12f94a7f8f3d1bf1eb769f52f43238ed411a97e55625ddc208affbae8ade42829c82cf4f62423830db9ca4091fffe3d282c578552649a34cbfeef3d58e020978137a44fefdb9083186dfd712301431b78095a0997f0764f3ef29f138ffb322c8e187c260c90a3ef7da5638e8d961d6a6cb1867a86d3eb23419e101e18bbf128c7a3492e8447533b7586a81e52366bdf2c376a57847b8a44f7b55eaeee6ab2f06596a87ccad4a60881bcf4b4b5d5f0de85593b643c0c4fe1771a0cb5bb0402fae0f1a2dd811d6495676ad718b73d4b86fc79ce074aa9924829ceb4dfd4e3ab70fdbd94b5ad1d11ca9e582dc215577056373ed91ccd6472b3ce02dffa8817e66205b179f37bdda376d25d6bbcc83a15ad757bb7843aa03d2f7193d8d707ccf4de1f5c8694aa212219752addd55cbb412c05118c30555ca7ea820bf3440d1dae3332947a1cfc22e366d1ad120b906274883d7769983eab6afea2ec0672a2ed25b2b3390c017566e52a0ebc59e6cebb89918d54f75d4094b943e7725468034d2ecfeb68228060bad59a4deaa40843d0cfe0a1e58855113bb7c5965254b82cf3997924d0a8b1711b1e1e5b28343168f64fa9bdf8e5158f33c91112f61ba782a4f97c5456c9c8756adf53a7d919ad90654a1c035d8686f834750302added0fb7b29a3f4f43f4dec29bedcff3139cbdffe391ad64b48eb1691be659e4e4dab266b7221a2c49e42d8ab06ab6d16efee2a0e0bab140aa34b53f70c808f3966f1a171bdc789e23ca0246328dcb1680c765fe262048b869c56f381bb7ded54e1486c0a3660d990f4bf0e5b4eec4cc0c3abf4edab6346cb531194c27de0e316d9d0a823db00e20e2fb99c2b5383213518d0cf604ae8f69d2921b442b729cc78579dd242314da99f01df55a45dadcc87e4b216aa0d817e60673c9807a75185e52a70f04ab8ea28cad805c37fae5417f89af44d4a5728c187c74ea736f21681fa7f93dd9bcab9b510febf2c4b5c64cbedb6b59b77a8816728dfbaeea423bb7735ae1fba08964a343ef9b5d36dc7f8cba10c8ae69bbddc4e524df73c940f762a2d39ce7ff235425942f2007b4e08f2002018f720e0339bfa2704a9d74798b13c6fda733d965666ec5592d1d6dae7af6efe5c87cf48d40858937b1ecde3445ab2c1ba1e87e1c2f3ce696baf3efb30ecbd9dbfab121a142ebfb4f09f343f37e8c5c0f40408a339cc3e4f4d34742d695dfc037744ba1a794abb67954d3a6509157a3aaf293c886b58cfe9bed8a3dacda2a2ce41f95e72e46baf65ca666f61bb548afe8f92e1c4ada258f46178a4591015678fc542d412f7ed323d2629c127890ad9c2151261c4869f59db9648e09c25bd5ad8cfde27ea4ef22666ae0f30a4d25c3ea1780a6c3eb2d94d0f48c1a61701707e57405e7e9f448452d0a48af07013fe04d6fa62fa5fd54139d95217734ff4e596f2ac975bbfb8fda29f7e6f211eb165480e44fde387d4833f89c7162c1bda3265a5271946c5392921861ad5d9e5b672afe4778301d7a8a8d8a03ca1c99d73b2ee43281c0b88ca4292a5ea29a0e23770 \ No newline at end of file diff --git a/examples/test_vector/raw_blind/finalized.hex b/examples/test_vector/raw_blind/finalized.hex index cbcefe49..c214eea9 100644 --- a/examples/test_vector/raw_blind/finalized.hex +++ b/examples/test_vector/raw_blind/finalized.hex @@ -1 +1 @@ -70736574ff01020402000000010401020105010401fb04020000000001017a0bab8c49f1fce77440be124c72ce22bb23b58c6f52baf4cdde1f656056cd6b96440980610bc88e4ab656c2e5ff6fe6c6a39967a1c0d386682240c5ff039148dc335d03b636cc4beba2967c418a9443e161cd0ac77bec5e44c4bf98e72fc28857abca331600142d2186719dc0c245e7b4a30f17834f371ca7377c01086b02473044022040d1802d6e10da4c27f05eff807550e614b3d2fa20c663dbf1ebf162d3952689022001f477c953b7c543bce877e3297fccb00ef5dba21d427e79c8bfb8522713309801210334c307ad8142e7c8a6bf1ad3552b12fbb860885ea7f2d76c1f49f93a7c4bbbe7010e20cbbe4671915035276d8df41a7ef0b6a36dd101de48a4076046fdba3b0bec20ae010f04000000000001017a0b90df52169792d13db9b7d074d091aaa3e83aff261b1cc19d291441b62e7a03190899a91403ca5cd8bded09945bc99c2f980fd27601cada66833a5f4bc108baf63902e8bed2778bf381d17241be029f228664c7d1522ced55379e275b83fe805b370216001403bb7619d51d2af2c5538d3908ead081a7ef2b2b01086b02473044022017c696503f5e1539fe5cb8dd05f793bd3b6e39f193028a7299a80c94c817a02d022007889009088f46cd9d9f4d137815704170410f53d503b68c1e020292a85b93fa012103df8f51c053ba0dfb443cce9793b6dc3339ffb0ce97af4792dade3aae1eb890f6010e20cbbe4671915035276d8df41a7ef0b6a36dd101de48a4076046fdba3b0bec20ae010f04010000000007fc04707365740121089f9677efff5962164a434b0bffe53d90c271deda3eaf30c1d7a55105d24b874707fc047073657403210be6c538eee2e29d44c66a3e66fc8165afa4081557031826a070703cb69faf24380104220020c731ad44c00a2928d508ad82b05868cb42733a5b0d0b208f483307ce8c328d9307fc047073657404fd4e10603300000000000000015bee4d0045b0884354b05d0285abb287ee8e539e8146b92dceaaee6fc01af1a3730cece4c77caefdcfcea1073197ffb8b3ded97d0dda6f49752b31f23e196378a3da2128a8c45ecb7eb1c32f0c0dfa1ce7bc348e799f66d547476e976baece7445790064b34b1526c88cf54928acc906ec0925327d797d36d0db6a43633d7f963ec9b4123a5ea31b655882329afe2108d123f76857fd3ce344fcd651b3d3066aa506625c9309acead85fb6c8a7d977db5dd6cb6e2f99fb3535746258d42d95dd2103bbaf5d45c8a2dfaa2301eba08763bac8ab3b59bd0082a457bc0cb257c43ea6354348e73d8dee101864068f0e8e30e6711f1597d7b529a57e95fc0df813ea160f5f5152f341087868a680c1bbc4b2a427d18cf8f12cbc4304dd3b1ea4c916467ae48b3b53062ea046161170fbe6ca07462cf3e5534d638c91fe6919318c4b2e98ce0ebcb245680d6395ba746fbf510a9a36ad8d933b023eae39973a39162178148a897b5174940db46e4be54794cea11fafbed48b42eed27f9915cfc50c958e88bac551ab1c9bfa03653e558cf87a99ff13440f4808e27fb42ff3cbac9fe10d1de07dad4807c9f945784163214c739a9eed8bb2e7da6e1fdfa4aba5d5157787d0000b220145572d3d9253cde5c1132370c1849847633287660b429f20cf1f72e4ad6ae59154c3b8526fc5d30523ba962a25577427988d326e207c97c81b479540b1c63aed0a4b1dad9279879740b2f6a0bfc37aea8c81b3b35b630dba8d955afbba756b8ce9d2a9802939972c5f70efdee8778a98360eef15faf77e38627fcb4f98569d68ebad3bb667e5db46eb7f4214846e651224673dc998c55bdd9e0a1629497a75b76160865c7ac3af874bc45a42269508f183d2458835b1734791094122f75398da2bb7919c67221ee42242c298d744fcb920726b84bcb78d7eafc9e0f61a02de87ffc5c674390a33d722b50dc35bbc6788fe0fd24be7a9e358113a4e65b49655767b8f3c3bb86cd5a56c79f9148945af63492dffde82d682eca4787f203e49790650395c925e6eb68bbb3adda25bb784365c0b3e241177ca7de58252b8c79c5a865d1030f3bfd4d312bdf83bd28241389085433c34d747f9f45a0a636e700805e619a19739b15077d44d5e8969a37481896acebe7f350449c69b50376b7cf36e906d8a03aa7221de67c7fc4c5408b55e2562f7b783918004d93b284c0a1c3d596c7c18aef5cb77ad09172bfa888f5dceabf57f708f5ab61b1b4159742d3d35332e9942958ea7f39fd35cff66e84ea0ce3b38a85eb80dcc1201146fc3854cb40353a078f5435fe2becfa383b3a62564645250cf7feccff5414581e747166625477c70f5b0f579bd578e03e6b8ff8c3f0e8a82566199ff542b239f2999103cbb61602bc2f346702204e50c9ce7b85f3b8e144227ca8b9766cdbd498191c385e3a4f024c9396763eacdfe41b706fb23d4f065dbaa43d323edf1811950c71d4475a3e0913d3851be4e921cc933bb06b0aa20524267b0e9847b6de3883ab8c5be1eac17b06c946f19dc2244901890cc290f2e66147f7c47a4a29349555ca020e684ccba5f8a6f1be54e356654d3e8678c591633e11d9ee772940d92f07ab83228c0d8840cb9aae514c03358e973a2ef319a39a3ce819efc00e5a493fd582be164c1460f70fb2e103f09a2939f779377275be736ccd41f847133b3d400477582419fbd2d7ff328d88256cfadd750ed7a3c6657e332f635f0a90602b24135e705d1530531b7b738e686d83accd74874e160a5716191447f832d2f899476ec9c53204fc4ade5b75cacdc869b4088e009e12d85beaa3450889de0c86315755ec7744be592f058fafe62f9a89875bd2781d5d6928c8475f555e77eeb6e688bd8d3bee0a54fa1cb29c1b6b438d3f70ee4ac83fcb6f482575997e3a69240c6731b517d8241cd39dba6b02a9e3c94ff2470c61c693d32b1c7d22ba38f0da21d92150115d580249380500109215a05baa63474f773892b1870005e76a68853e6a8cd9f74ab3f41cf0730e702ce94c420dbf66a63f342d927923d7d25ca3c3823b6c352ae2ca127bf811c023205632ddb8f9191c2f3384a61038d1c4d32f808cbaea81d58f0aebc7c89bcb5b98f92849f4fec19cffc78173e601eb412aad24eacd74d17cce3a9ee76670367ed87c2da3db5e4ab01d4d9626d0ae00da7dbf6b8103d5994cf66ca56bb9aab9eabee2b14ef798d3fa5ed1dc16bb500a006c3320941c4c7f6f80c8b1bf79131a5e11ef38db7c42d4c4939711184ea414e2ec0cf5bdce3d7d0d72dc883b2595e5f0fe4c14cddaed61108c90c74b43cbf719bcf7a934bee760ab33f50cedfe3ce61dda3e4bee1ab4dc687f988cfceb207152f7a98c0fa3a114d2d6881034aeba877bbcc368ce591707da45becc48318f0558b3ff65d677578df9fd9e9a18d0cb08f2f5cd4f44925259225b1c4c5ed84ef30d136e7c66251329a223a1db0b485f1c634981f8860aec1f3dbda9442e5438f6fb09c7e1ab43e2b757911834df8502ce35e7be947771f7416f7ea97d26dbad7221614175e6b86f1a323e26c4f469236d1b1bf6ef28823234c73b275c5b0ff39e8c04d9dd8ff7f6a57214d803aa13dbf581295b92ce2b8a9c0e3fa8e4fe4e74c4bc2198fd010cf84681cf5f3fc9df1638c403006478b1cd4204ef3b7a6093116021118a839bd3ac270783e67096457a86d63654e268821ee742241ab5f7e91972da0a94f679b4c093d3f428d5876edf51459331df084f2fa245e3648e0cac904a82a7d323b965a39683ec0b2721105683e67d65fe10b8d41d0dfcd5c31756408c94cf425ae67f95ecac45391516875870386b675e24c462b1f7634f758723e6245da6a39da69cc2390374eb89c6c662d94eeb2f1835e233610072936be248e6a3ff87f9950c2eb2f88568c31dd30d1f0c0396a42f6be2505bf616c63f504dad5312fee2f083b406fa05cf3c998ba24237402681f0ec393de4650ddce3389d4c1541d4705d8f50c2c6d4864934394fba0c40df495fe3a5bf58a5498c1e63b5ee5f9a4b53dbd913252d4808f5bf5fc3c6dd74c86c974fc9e5afb1a7ee3d88738ab1fe9194881cb00197a31d648ae2448db872528d5f7c366188d9d98ea94497cb78ffacb5f6e8a2c8520d8d196fe0ed13e2b2a5a08dc45d8ff58a8c5d3bcbdc5d80c798acd0eabf146459e79db12c2a43c55d14b2dd608475c606fd4f943ae7cf62131691768f710fd718fda3967146daa8d4f34a3b8fe8084f4f3865e9e0cc1a0b0a799fceafd1b74f09f524822179ce38cf0f2c4c8623a3e3ab2cc20f5dccdadffacee62c120657e3d85fea93fab645b5fcdb812b130afbbd5b19e86aee66011b520b0affd84af4bf67a28b309cad66cec25a5de06390a4f2a5af47d59c006010a8ffd214149bbe47bf847fa94c2113723c9476c2e6dd84411bca16dc7bb096aaa3e9a9be27811b52838c78d16cbd89cad379bcc0cd966dadfa428f9d4d8bf133f7d21022ae3f966dbc1409c6d57cc46ff4434fd90d79b6c9e68ed3795ea6191a7e309783badaf8db9fbccbea905ff9d423370810f02add38ad3088cf3393e7c6d585b76fd78c67766fff03ff54c01228c6737da667147a8b5e722370a24db8c0165e34888920d70fb1356eb731d0024676444e2d37860eaaed9790f99069e622afe6ff12d516812022c46420006253248eb292908ab8658cd874ef05bd568547535fd54c1f0b5b816e4d90a1bd55670b96691e7633a2fa45be6a29cf7bbbcf9e5debb4b7a739b36b6b326b719a12cd0f5e3557a2fd94023d8c633fb697b85080a39734013b4ed9a7500aa8093edfc3810d4c890e608951e57af8447349cdf45a076449241a047085702dc3e44814390ceddc878791ab3a6503f48f48af25fe5cddf61e7870ce80e32e5f22d5725bfde4f319c2db7cf3ba3b9952202cd24210ab8d47fcdaa9ad5e2a9d2c7be1ed6b67cbc1a28ebe565ed0337c09c97d2d9608d97905c7201be7d4bac785d64caf783cb3ebff817bc5ff0448899537ce6911c9803744d06ae97e6d3aae037697986cb20061892ae72e05968e9bc54153bd745012af719fe7fd4b917689a6cbb94a9bc8cce51d234ffce7dca804e2b2759f473885855983b7b290806884fc66e724fa848af2de3164c611c630e5bea712cdd9a9943ca3ad55994e5587c5953f415171bdef3c42783b809bc5526a88aae66be626d73394a607ca32256198dbc026d9e09e9659ddb66736215dedee0cf69a24490a53b2c678e6caa2aaef10a4610f802fc5eccf558629554d6388465584514d3dd49fc00fb267c39bb746f76ad3cccabcc3cc882815bd9466d593270a5c9a04945dea7ad06ddb73e66b90270e859a109d52251d911e7177e07295ac9788ce970c1b718fb0c2f327f44fd0cef3cb90071ec85e958e6ae60bd134ae307720cdb10be5a0af8c051295df905447b46206b5e04d775b83e11c348458b1bb310ae25c54e8ed1488a95b2a576002198c80e0e69d14fb7bffcd89935faa6e3f9aed61e0492bb2bc334e389bd559806eff9e16643ddc4372ca83790a99bd4f5b042779ef7e3039858881c8ce0041d43ed6b1f42f18007d046fd6f65907cef73fd5e6cd514c4fa5ebb872b140d0b2ad43c58f2f2216522e78a19828baa34ba56d71414ae869a13cb708762565d754f0754561adbd9145d232034229d2840ef0c96f7af4b232c5e11ae9d018b87177a506b66571affdeb693e170dd12640e86fd430b64509d02694c52a54f23ea96e39be92b65c1abcb262a71d6e884183d4bc6cac8c79f6e94b51abe484794a42a8e1be721cd59383bdbf327a864b2cf27566f1270d82ab6e8b3b934e953b7d48ec4697172e0160b8435e8186a7ea685dd61402b0bef09137fc52e19ecb53674a1c0af17fbb0efc2b4d69572b32600fdfc3c85c79ccb2685c665aef16748b7f15862f435afaeef00f3f927cd3a60c22f137e9cb2c38a9652cee570a76351871ebc9b6fc720b9117b1306e8afb298e3a1d0d4b2c5ad5a21e9de4c0938a98daa35caa711bd6d3312a7e941b060c4a1ec211c31e53da263995d3be74a3ca5a970d3a663245a5d8eace336d9ee847619bb337e777b961805e808f7cfd8f09b93b6ce6c277396e6cf0a6153fb11625f421b02055dc53a0bb24786f4a74211bfdf44193e48b2c15c7c85acd3f4f0bd26644f9dc62653e366178645899dc06d191c785831b98de593519c0ac5849897a01b4f8c7fd559edce1c878bdb9dd091546c64225fa81b1c7dcd6fe72c8131bb160043976a5e891236d3552598c0c4fc734d1cc752c10306dfc8391f6d658ab8b7a1f350e1900edda29775ac8a531032bac968f6981889f13cab07f49c864c3ef3ff23555c170ee9730912465e6bb3b7508e11ba27001d9dc0da8b34954a7c46a2d0b0b75e73ad66278c8acbed3249936a6c76fe975954f7889bbaae5f73747e3ed02811b015beab9d1515e396d37b2a116b3cd8863517b88ee91a854e4740304f7be41123692181a8ae22090956ba619fb948d3f08108da17ac2484d3dd5795b1c716cb5ed3fc08b6449fec814018cd883b02256afadd1f35a04d9d43f661be624c0d59d0d397e8ad6917344203843495162217e79bade11ca32c0a6918350520e6c3f31f866b89e3497b518cdc056e760813ebea7fbf343db50ca2450d5b7a1c5f430859e2040ecfa70cb0c3e863a756ef6ae2e26c68b543d35beb44513f8295872df5b4062c9b80742ca7a9c2ec36a1d9bc936c7fa7328240a2db54463ca04a40dc0c9afe4d570012259c8c436d322483b17a705d60a283e0ea7545110e898ba43ac6130aebde014d237482307ff28f385fce8530814a3b3507fc047073657405630200039d46edc3d830d852edbdf28cbc023dd1666cc4a806ec9d4acb2c97865280698d61fb6b2a073be4ce75cf8193fa9b3d677146575a812873ae7eaa7b08110cb88904273dd65af35115dd116092a56ab45fb57178d8c5ed4cf99474ff760f6e987d07fc0470736574072103701e53a6d0b960398abf678382a4d17c5c153d1a2c8ffb76b302058ce915bb0d0007fc047073657401210821b4e7599b1b4faf29b521f1c442dfb0a893499d374c19db939c0c9a3b9798c707fc047073657403210b8529a893bd81e38743e8e3015095077f6e244a064d64708963c6af5024b6aeb3010422002058037c2d81d3122185c8704d4276e2629122c95b8ea68575c451628d37eea84507fc047073657404fd4e1060330000000000000001ddf2f500cf45e30e3911bb51a7ff633c1e329508e42d9aa49fa8248fa4d293b87005db08b17a472580ae2cdd53c40b2a16af885d6dfa3d5b3410d389b045e6c12405c635511ccf008390856f4c6d0ca472148d2969fd39e1307bfbb8f8268ce92398248f08df7268bbe23e13ac3801ad075376bbe9684db9b41d7b1148fa65a129e1d25193ad973ec7af631a0a30c5659409b0d00e6fe44c2c507d52afbee8059aee7650bee9d47936838e77f00cfec9de3b9efe72cdeefd80a19a9c8ddcd6cd9009ec96800f9fcd709f1432b5715466d601b5ed10b0dfbd09b954b109232fb5a24036b887d26bab43da7eaa303e7c8e9d02950610aba09f343a65a7cb4550d6f6e5c0eeb9410b68f85cc3b05b9340e2e9c94a473f2001f5aea7e875d29e8e0aa99c09afec4a5455258c803e55b89cf6e89796a6f3f9fe11ee05ec415c6ac08e0f1adf9dad681f8121f82e3a9402a2fe13a016dc10d4a605578317be0d9d3e02b0989903002bd35ec4970701da6eb6f9fd5e6cefad137dceffaad968d5ce522e77c76e665529f70c9eb805a240834f4c8c795912c37e7efeb73d4bab709aafb66bd645cf0addefdd83d185c1b4465ee16344575eb2aa3acb057c37d7c22cd03adc6701f03d4cfa20ca94458b3b87e3fb7de8fed28a755bcaccbd348dbc7f5aacbb25d19437d87cb48b88fc714f059b328c374fb2695a26537330fae42d3fcff40b07054be10508fa78a9173315506119973a9158828276edc6e8ac771476d7479d07ba73e9c5b58d61367d24435a1062dfa376546e843b34829103168db63b708a13894813a442f889a423054160b85a2584d36951136bafc490056f1c03c44580e2c7a12b170e5c7a3917720bbbb21e5da616649b554b7ff57dc84dc3935271a8aa6fb218becde208d83e76bb6197f5f4f729f3c57b4280c388bf4945206fa769b672ebd47ef2d0f777fc9dfb031cf7c333c6159a75a5b33ebc6c4683ef140a144a5ab15b2b6b72ba14ee7595679a0f7873a75b9a79e03676ae94eaf9ea8d3532460f3075f40c6b9848a183fe46651caeacd51551f308eab6ba8ac27b93865f5dea0fcfe1d7dbb745695dcf187a5955414763c88ec01d299f03cdaec48eba946c7ff6031f28a5e108651401b5447c0d21c449b387765a621c057eea7d494302222e3d1ff6ee9f8a0580671d9fe3ecc310e84b554e5c823d81b8027075f749b2dc8a6bc5a99fed4a0fc46fae59cc2aa9f1471ca2b0d9fafa56927fce0f1df92647ff5aaa083bfcb7078bd8ee142448d4e1f3dda670ad93feb21028a57ee9a8ae8880df5b3276e078555d868be0d8843b495e082d743328620f36f7e106733bcefac15076826cafce271caf1520cc8746948e71ea73eef5de770ecf5e0fe075f04d6c9cef1cc1f262e69fcfc89862877ffd520e25405d9d07efec82386640d97147e4a6df66bb1fa1f20dcc2ee1fd6364bc2024c0a4a2ec00b84616231c02aef16147df509cb830b9fb20111c60613d41169a24ea67c03cea48e1905b00eba8a61e967b9aa5b6e1264b0f3e2c051e47f54f45c6fb78b46b9993c7d223d51036cb77f5e31a4b30892e8fd7ae7028322d6402f60712f712f84443de083767c38ae88a38fd4e4bbec58015f4e49e36ecbde94f23d0061edfff0e9eb62b67327249d728c278f923748e4c1e225791c740abf9493198f073a6cefffba00d23715a14967a72cc7aebb81ecc6e8bc88ae63a47507296a573c415d0163219f3b20974ba3a32572d29a479b88b89c241e63e640bbb93e2da0b73024ff03516ee3ecfbd84348372cfb574817ca878172a779ff131492b86e64c1b7054cc5fdb999df4a9578bbdd6a6a2a798f053f4c7456173cb8cb9b61735e650d0394ea9effbef615629c1f393949095982345bfc02b9a3b3ec64d9173bb1285587048fca8c740b6d2265d3e727069fcb90282c78f1049ed7925113279474d0d873045851b397a8c26036c83906dccd0eabe98f7d6854d9abc2e6ff12d84c2840affa371cc2dc624fbce873f38570dc9eff33f5e200791bc052307f5c718d47fc2a205add3fd9de2a81cb452a0a7b4a08bc133e9816f6ba852735b813a1b906d4dbd1ac8a968a8adfb6aded0d3fb87d80132a4b45ad39274bb72df20d648a26aca4beaafb971e13094b6d6525bd418b91320964bd90d3a98fb32d69222aaef2ea95c6b84b6b6aaeca3f6789944fc7ef17d218abc7667ddff798b74a0d5fbcc33d22d028d207f82286fd777ea1e281d7eb88b665e29fcda067bf9ef82a190c920e260cbc44d394b78e0439bcaa6371f8717ad82e02015f21e5dc273de338102539bc924d5a3f897eb788e0f3cbb6e8a34590ff5370bcb0f671ce28d6ac0adea17f9fda49c784ae84464991fc71a31d320d62c4199e4f4e38f390ffbcc7f15922c3325451371bebfaed8f8a7d3eead71c65878a705a6163ef649bdc6ae7b81110a2cc9576da6b0188337160cd518fb30fd5b0c165ac3de81002490f36d29f3bfefa2b4796c070c6d7d971d18bb5a573cd48cb3c64dec5bbbd7f2f6f60bff3db4833bb64b426c6715021997350aab1751f0d5382087ec133c2c43342b31eca32a4c17db14148fb48f9b7a103b2c0bfc0dc95ffe097bd8f2213a3f7a43c994599b05dc35d469fdc025e23e483039f271d948972417153c849fa8dbf374693dabd59d398732020e90d8f443ba45a00b430168561de21db76b9b714ca8260fdc4ff1a5713e69ed7296f5a5a9d192474bc6e67788d6a44d46b69ac97d0b34b2b08aa79d5ee7e910d99221e1e7f6383628b5383cec4341e5c3f18ec3361b2f2ee5935ed40919a4f8892bf3467803b720d29388b7cd47067eed9be7648fbbafcc7bebfc31a30d02f38b7d6be1579c751aabf679fa6891adf66da2257432c10d399a8d496d1aba381b64a5e3ec9a65cc8419151b638adea994c3590f77bf390152894b2784f7832d986ac51b20ba9719d85509acdedc0282f27065c87bf483fc74b55579ecc233fd6c51822ae03e46ecdb15acf0204b67852d525168f409d2a4309c5d9a14b35905b836091964ff4fec0aa91bbd7f39919eeaebbaf75c63337a4dcd5ae37cb60fa14bd78157ecef35ddb1cfdc366eecd48aebb0f5b395e4161c158c46870fc89f8f5918aabf0577c914511cac7b189384eaddf7f03cc6706a9abf219ff1b293cc9fa2cac88b65af62f0493e30736b596c119149af07e840a43dba8d97455a7a95368395488304626d3b888069a0099c435cc11e5981412f79153577c9115a1812b1c4a9ea42bbf11b40fdf930bcc37e6a6c50a7e3d06bfe7043adb32244ae359993caad00eea5f1de90355326e921145add1020ef3c2cbcbd102e7b9a150ff9672697d31f86572843269978cbc4c3fe067417e84898587d4de009b33094c8e8102c07facbda62a2996e083d0618fd9651e17f0fc025a946e7c28d93e18675ba69d8811dd06a2cc1aae28de5a6af30f305cfd8a090832483e4ff7c974d47ac96d2f3f7baec94f965a116c2734f87f468ec33cee1a58dd2ccdbc8f6a0f2a50a739aadf4007c7a529844cd1ce5efdd42eb28a0f5f04fde00dea586e4b8cdb8469b36940de19feefd342285c29298afcd3ddc368f6365e9ee255f8c2b6f70c1bafafe10720402a668ac3a2cb8ee75cb7004455cb4221486c3dee64f8f25f1c8b1411437cf6ba70afac5182b21f0efc1b5c71dd59f71796d2719741b6d5c757d824cdfd2d9459569427951d6974d94bea1fbeb0e1a23ef88774b270a8bca65f01a00299258847ddce8af8a7626c802b29dd01d1dd9d2a7243b334c29c0943e11ddbfe82cdfbd506e81fab8775a1d3c4f6c0744e1086763ad84e8f51d601e24cd6fcba1409abbb1c6b5c9bb9eab8ca30282801448f86cd5d8ec187866f1ba738863f3995bf4084ebe8f41dc1ffe0cd47d5a95dc5fc0dde1559ba170316e085d0e385ecf8646bf787b5287960f07bff9d3d990b3be4b29f008de18ccb46dc2192d0fbbbb9e701d350aae205fcd2d7314112bdc393e2eeb0a96c5f2c767dea0b82e9549f46a270b2c69915711c144a7737e9003b1c1b8684e9f2abe66ad1678c32a0c6ce401ae2d7507ff32c8f6179433b94764a6e4ea0a363e9a03787502c67ec97724d78c1257499379ecc5cd006a13acbba05dc7f1310bc75b9ec6a09f4d95b2ec11952eb3dc3d2dfeb8678b10b5db162b44af56ada56f7e311d6c5ce46472d9ba2284126f8f579d59a9d3e81bb1b26a7ee59c3cca96252fd4ba8e009a213911619ab4184e83683969cc4c474e934f36e6ba4ea33d9e93e984f1603e259cb7f1a3824dd8764bbe30ae08166aca84e63615e59c31d2a968a0beccd40637db22b971d51a4c35ce83108d8975d758669bd83ff9602718a882b943f80745d95a2d5e07ad0acf8023e24589fd68988a350c0ad571470f8b9a906648895d312100cd18089465de942ae0c7c8bffb5d3705c729990721bb0497dddea6dabdd530c9ec90286cee5ba3e2b699eb2de55de8aa0012b38051862bf0a7a22d6cce4310dd8dc47c206d9eb7bf28f2a53afa8fd10836210c0c461e417be42d89ea659a76d5e3cba08daa885b7f0302c5df05c72f8257f60e2ad954891841e67d8b7184cfa47e51e9b36f6ed1400aa84c5058a1998d07709b8b46630d70c73552ada18713310dff4177e2143aada1038bae9a64e02870a7535598d766f447b4e25dbd009009cc0e3421067bd0cd10735469b308cfd7a094bbdaaef2e31c22dc6c1a6d4c7890020b5bd04ef649b56889b2031c1923a69002448dd5db1142384cf517b08096539cc537532f43afc33ca77beb2dfee921178ad51b04f10495365e60b4b7677880409716e0eaa3a1d649a871234f86787c2792bf1e04a635e3f22b8b3b1382be942605c3855a940cfa3825a2f8993312a512c81f92aea0fca95bd1bdb6b9774ef3f1fd15bfa1eae84ebb48bc9b55fb2141c55cd3188eeb5049b2e6f3360e60c5bb7d91c9028ebc9287b4b5541a4ca290288e08ca46f80eeabbf100f700c873d7e69dee7dc80b842004b2bb93f0bf533488028d1a1137371417d06785372ce942d4c6589cdb57514bde81960475c22393eb02a93b6560fc3e4fb6ba692dc362d38e33a41b7df222e9192fdc0e0499f110e681682e2b500c00947d62280482dde5e26010cf959fc717d0837c98634550376aaeb17c1c80e3c3245c36c68f56fc8be117ff84957a75e4aa4caddb38779f1c50086ad4863002127b6c8067f172aa78137908fff82b2297a53d6232c26a2e94bb25b7f9241013adeb36d1e437f2f6c0d983efdb78608e940390005d63c081eaef21d7f00ddf51a3fbbe6175be436a9b0b75f198c30efee2821ac5f088819eb96ba835999d0012e7a0c244268a658bc6b7845d10178283cb8add0b81405ccd64000c1835111511555eca14f7e3cc9274b45f817039ee62cfd95363cc66f5397f88822f790e0a86b6a69379dae77db24185394d9fc73880d39f6b3233dd8d3b912995b22905563ae8cb2b1f3491feffbbdf2c7d2e89dce1995d2429bb0a4c550860835aef589983d3170387971f8aec15c18450dbc9cd12f402589dfb17216e359072ceec8e9484f9b490a288dd4b268233c40ad23721961c390bae0a181c4cc8eb68eb4b2a5db6944042c6ef67550f9abf3b9084cfe8521b62d727416576a58591dc65f79f871958243ca4415d92d3e588c4205b4a3806d64224e94e8f04dbf7f75888246aae9f894bab1ea69d7e10b4f07e8cf2dcf70cc62571c737cb6b6c68b0e3fbe4b1931c8615a793fa3db0a45090458ff62ce8bf421907877e555cdb97d3709bbd8728c4432288861a56cbfeabbea5f225cd29e31d99eb788704a93696f5e81307fc047073657405630200035ed48216bc666598aac5498e9fe513a9e21eaf842d382767220cf98104bfd8866621efb63b2eed44028cdc9e2f64cc2447fe09f8d8a1eb3214272855b525d9ce24e6daee58effb4af28fcb0a4685d78d7995081b5cafd1cfe343aefc8e9cb23507fc0470736574072102b642f0e5b34746f2f6e3b511d037e16bc720292da4ea2fb31ec09f6fdbe777ce00010308f40100000000000007fc04707365740220230f4f5d4b7c6fa845806ee4f67713459e1b69e8e60fcee2e4940c7a0d5de1b20104000007fc0470736574012109a05049129b0d9e61c1bb87a9fa02c2435be35e3535082a772f65222f2e4a48cb07fc047073657403210baf4431fbb8f0227bfc0008368606a4b8f2bc1706e1a06cd4d83706217b74f5b90104220020cd4ed5f0db8c450e8b0be595b6410c1759c19f1f6926279095c83dade9862b6d07fc047073657404fd4e1060330000000000000001a4092701f9170991583ec8b5c9b5056ddaba7637f7d6733a57dc4990acba6d15e9eb5dca55528e179b98a9e09e05ba940b59558b768194ca046c22e12ea310ec05bcc795ea419277649d40b145e6f0accc31f2d7eb39b29b51d3ba3410536b9bb37bce9014d352b496b93161fc799b23939ee635f25c4cbd6605029722ac2bfed7d55fe4120c0cc880661ea3313d700e261ba973bea5df4dc4d8a05652d193c5edad01945862943a6756d4b0ddc93ad5a444ecb054bcfbbba3635aa752d9c4fe8f93fc56c8066b3fe344143d65328025f5184308f2016eae65df8b0f1818f59f5a9539eec9c9c94704ecac269b008ef25f67ab2b9ab4e903b1f2372d1d3988b86e5efa639f9f964599df8559622c8d11f6bc4f706c74e4a603a3798005e210f93d9e6b59f8ccac907dc9cff127c552c8c89981e1b91c817cd365422eb6bb0c7ef4ddddabd306b0c32a98464973dec30def4149f8e9f35de6840cbd0ce8a2f2b5dec15e3f3c27d0d2720159cabb3ff2f73b4571eb53ec735d7b0f27bf4d23cd8b0fba14d5921d464beb3fd4f2fcf844f76a7f7f129a3e7e1c4a6e4f07490f2cfbac4e6730148397c73720d35cc5a46fdb1e774e17f7b951887c1c72ae4cb25ae99bee652ebb2ffd9f4c9400ee0870b27a5dd8fdb8224aab6738399587b4513d3441e26b898b35f739d64047ce8de70347042fd18c3797b1de82cfe23521dc8e5c36e286c05d4f81508e282018cd8d263164512e6ab02a22b3d5d489e6074f9370e218a3adf8afd229659f5046749db9615541408739d4f0646a853b25f8e549e85708c368e45f3e1d20ab47a4ed647b820a360e4e351e4caf74810098f0df4bb74e0e69f2db3284c30d24a0d109d16c37509557ce15c81812bde78085f31cd7c93140fc43d6580abc7ca2adfe6354510fd8104c0f1ffe46d24f31bea808376ac27996fb992de15b30abf4df6f4d08860bec27a95bcee0df8f0a5bd7f72938ca9e917f39c5425bff826c4a84a1fd70cff87be2e8619e0d3b729f0aadc10d4b70d10c2c020a99d03424a595294dd34b84c83a2d434b98fb116e2ebc8b2bc444740ce090816218ea61da172e30db5e78a58ef495812c287e3cfab7bffada0d6f2fb3c153f1a225bfb46e7e9bae9b666e72c35597797927e1bf02d1488ba90948f07dc12f6d8b61bc04d82994708725e0ccf5d76dcac946f36895402e84856b3e25567156040510fb299b88c45713175c54fb3d54aa6d383c423807778a92b7d9bc8fa347923749d18c96b20cea608b6380b57c35b4408f724046f6f65fc0d71e237c39376e1e769cd0234473a261c76553c655de0e4aabb4fd44d0247e4ef08f48bbf13a8cd366491e834a47f8a5cfbd6ca91c832fe4f77b3b3140a6c1c70055d52f0aa67e7d3ba18e5bfb09f738141a611002ff9e34188d540ac42f48ee06f6925cbf3cca5ca033c4fe089650a2b86a8350367e9cfbd07fac9667c0171f54311cd5b37157678b3d6155f0bd12ce53f6599fbc5beabb1f2a5424eb3f52ca3c1e0779d9cbc5e106693ff12d6e66c51bb1d12dfaeb70bc56d5870fb5ce4b040f86d7725ae53b1844b07557feca4d0e4c55a9cb6b6164c4cd3fda89f2a7259a4cd7682de9d8541af2e18b4e49218ef48d97df114971b298a6c4af231a432d4ac295d0d1947e09ccf41ab104e5435e7dddc0a6815b636a31be9a0d9cee2f22c745f05f384bd703fbf4bbcfeadf177abf4ca4524f38a681e5436a06abf9ca70c7569a7bcb8337b0b0c280b5f790ebe1258bea9c1da58c65c13991efc1ef8f7c75ef28affa340d84b3db3f4f188b1c7f437b024dfa6207d5329a5a7a0a56018b1f96a1963961065e07e3b2759f7e27ed707f5807342bad0935ed42609849d7a9d11addf8a92df7933e353a9e86213db0a27285e432228cf2166d3fa2a7f6dcc4f1331303f8db6929a3c0fbd6e82ba4496f3eb2812c986f3e2e627240a9102089725057c1e5dcaa3bcc5efdd6ba7e8a496f609aca3dd82816552c669c255283f9372be7d8f12b044f8c41180aac612245945a4467fa806892d55ff425adbbe92bc892698a32d39d7c23be4ecf4b07d79970eb3db84ad3ce589bb8b134761a442f8ca4e2020a4a42912753603f72738d5ca88c5d8280c3d8af9e83c18be420bb87db4b82a98d3af42f9191d4023eb22f428def2ee99d04d1497cb8205b67c9ca893f7afba077bae5fc11cfeb53d882763f2eb6731bab373923a63dda3ee1c1b6207e0ad0884290333dfae3f80e85cc50a241c73d7d99998e9b14c3e52e660edfe594e1ddcef04402e8fbf9061a5e0b3441a1cea68cd7e067fb146f57f370cc94ef4f28f4f5dd36f45173e40ce91d021465610b85b5f1a98e6908a17c5e138f2dd7da2769bad8789eed99828e8f23952bab7e9ead5fa9bac781fecc93de7927544736fd5c57f1da32be31b85657c313cd02104e1b889426bf4c8e9daa741278ae3966ea673cd3fa164ea7cc947b34f86c92084043ae846aecfbb15535a9b21e27fcda9a21bd8210721355b4331d01e57227bf6572d9538e4998313c5b8bf6e2f3f7bdd7510283f20ebae59b7b0784c0759dbf1036645c5d673edb45245f5e78407978b63d5c25ada76b176dcff53e76801d7c2784d4687561f32e7a32175c0fc77227b3ab0a4054462d04446e9c77f30cc87a91dbcf27516c956dca6b93bb4315f2f0765981e7525a510410af05c462f08d328cefa4bf8530250f5a4d3fa7f58f5a48db45cd68d0dd53a2c66758a20184cf226565ce558e60f0af982b02672f8ab14333349a5e5a5dcea61a09f93addea3858fea4e49c84f5d8269a2fe52f072d66240e7d30b7345c841ac22c16ee979c0f980567f24bb4bc2997ded6fe345d1e95c1b5cdcf006eb17d492bf3119f1df2404ff9bfa39568a52fadf98ac6d5a4653862d91b995ab166fa9de73478f7e339941e036b621f7d773a5413471d6e41a68c02ed89a4882bfade2b10e399f4515470ef43930a911609911f8b66bc060ebb186cdc4c1aa3cb573d696b0f48a655f8877f68f678bbf467ec872724181d6f983682389fc8a61a7525bcd61ab37930e6eeaac82b7adaa145e2a0bf67e235a657949708f0640ec802a174b1bcd7ca384e09b6f0e811f553609e88c5e45252d0d9ecfa42ebb69b7c2d22bbbc6b33c79f3506806862d7600e62c51c4d909472add5eb08e2c5a8ca3d58901a49e77f3df8841de18a30a9bc321ae43c712dbb9f08b457dd3e3f13244ae03da16acd6d3e861efae625478a89020655f0de72ac174a50834db564d4e60bef51e28954a938c64a6ee290523337153aa4d6cfaa00826d2aae1b57e3ab857e10cf2b497597ef9395fe6afb3d74b21c5d44281f756e018539ce8b7f4bc663db1eac9b976da2f994b193a30bde0394b7648b55ad9bde958ec5bf89eab516d4418451d8cbca637c1d6dfdef61712e76aa7f12151d5717ba1af71c4754136563ff2667bb1603cda51baf8a575d4069262179828d54694382f6bb93b98ab9d53d29793a524ae9c42c12dd42067584c4a96f6c15fe590bd8616983abbf453ee038f385a1265f7856009646cdd6f409d9e1e7fd36e1cedda1137429964b71af9d438da0858e817ca746438e0949dcfe49fc67ae967d13d1d1aa37c2e410bb95609c7ba0586c8fccdcca933b1a85ec97d1aff670004f71232bedbd192ba5e5a681867470c4e146221bee322a5f458a2bea1316d3f4be26efbcdeb4b1062e58f2fa23b144cfdda55aad3ed7142653c7948b6d854abb8d1201e9a4de07b8985fc194e58ea08b4c8528adcd73ae6bcf5493b7b8ae1f663ace587a87d5a341828612bf82605ce6cc286ee0161631ba06d704d2f52e37e3dbe44fc40c4171446d0afe69cf8efac8657d9d5307f158d844bd3664865724aa9907d2ccaf4cae78e056ee78815cbcdccf4b11e181a1d2841b0146eda60d561762a7e3512dfd59fc133713e5c056cbde75d5b536d632338fe83a8d02a4b7fa9a6f1a5df9de85c88b944581294609c880ecb5eb45de087524d896486c200ad68f5c45e43894d6e84493bed02602ab075c8d1e5e5be012e4ce474423bdd21d8d6662e182a2ea7eb30f2604b468a25c417c15a2b55031563810b35f33503cdbeb46de12c0482c70b07b5ca3c4e2aa21be75c33a23e73c03379c434dc8bff54dc40b0a34f476d0fd1de0422ae6edacc8a729ed2443315336b208ceafa68a229592e42f49501cf03fcf04ed2ab60cf7c31bf4d498f10569eb3666501cb8ec6e22f1825b7e69f632c24180c3af0d658dccd1c5896ae71b5ce46dfafdc12f94a7f8f3d1bf1eb769f52f43238ed411a97e55625ddc208affbae8ade42829c82cf4f62423830db9ca4091fffe3d282c578552649a34cbfeef3d58e020978137a44fefdb9083186dfd712301431b78095a0997f0764f26e084ee5a6d1d7b24b3b0ae4100da91329f6e8a0a92f3fd94c8b53270b44b9d419e101e18bbf128c7a3492e8447533b7586a81e52366bdf2c376a57847b8a44f7b55eaeee6ab2f06596a87ccad4a60881bcf4b4b5d5f0de85593b643c0c4fe1771a0cb5bb0402fae0f1a2dd811d6495676ad718b73d4b86fc79ce074aa992487108dcb4d908f0da654a3e1b8dc28cc2fe35762afddf2c93fc7a0593ff7c7aabce02dffa8817e66205b179f37bdda376d25d6bbcc83a15ad757bb7843aa03d2f7193d8d707ccf4de1f5c8694aa212219752addd55cbb412c05118c30555ca7ea820bf3440d1dae3332947a1cfc22e366d1ad120b906274883d7769983eab6afe18a253fc6355f81f60eb54f6ef7a48ac185d7e61d6580852d4b98443ad304ab8e7725468034d2ecfeb68228060bad59a4deaa40843d0cfe0a1e58855113bb7c5965254b82cf3997924d0a8b1711b1e1e5b28343168f64fa9bdf8e5158f33c91112f61ba782a4f97c5456c9c8756adf53a7d919ad90654a1c035d8686f83475038580df22e4a72ea9f0cb73470f0b52544cd7916f6487afd32e0527a311f7bdb29e4e4dab266b7221a2c49e42d8ab06ab6d16efee2a0e0bab140aa34b53f70c808f3966f1a171bdc789e23ca0246328dcb1680c765fe262048b869c56f381bb7ded54e1486c0a3660d990f4bf0e5b4eec4cc0c3abf4edab6346cb531194c27de0d85fbd39f86d1839854a91291164823db1fd76397800c3b62b418bb3a894840ecc78579dd242314da99f01df55a45dadcc87e4b216aa0d817e60673c9807a75185e52a70f04ab8ea28cad805c37fae5417f89af44d4a5728c187c74ea736f21681fa7f93dd9bcab9b510febf2c4b5c64cbedb6b59b77a8816728dfbaeea423bba4663ce831af234352f8c68c47dfee91724c99eea5940f57b4f1d9660f0021892a2d39ce7ff235425942f2007b4e08f2002018f720e0339bfa2704a9d74798b13c6fda733d965666ec5592d1d6dae7af6efe5c87cf48d40858937b1ecde3445ab2c1ba1e87e1c2f3ce696baf3efb30ecbd9dbfab121a142ebfb4f09f343f37e851fcb7bf011f2117881098afc5a584e6aaa79f11d4d540874ab905787577e6407a3aaf293c886b58cfe9bed8a3dacda2a2ce41f95e72e46baf65ca666f61bb548afe8f92e1c4ada258f46178a4591015678fc542d412f7ed323d2629c127890ad9c2151261c4869f59db9648e09c25bd5ad8cfde27ea4ef22666ae0f30a4d25ca5cf42ddf3f75d2121c46e28f565d561c9c5ffbefc847ecb75a2595c3e410c1704d6fa62fa5fd54139d95217734ff4e596f2ac975bbfb8fda29f7e6f211eb165480e44fde387d4833f89c7162c1bda3265a5271946c5392921861ad5d9e5b672afe4778301d7a8a8d8a03ca1c99d73b2ee43281c0b88ca4292a5ea29a0e2377007fc04707365740563020003c54f16cef0fd4185f35dc6784047913c89883f72b68aa78c16f144624430909da01633eb2b4b13eccc2b7a7ac5ef3b13505cea54e1d390944b5680e6860184e35111675dce504784f4ae8121dbd1f76df3d55ef722f3f73b5b7723efe2fd34b107fc0470736574072103652ba5800d63722adef5232d31ccc12403055de720f0155fc47bba5750ccedd400 \ No newline at end of file +70736574ff01020402000000010401020105010401fb04020000000001017a0bab8c49f1fce77440be124c72ce22bb23b58c6f52baf4cdde1f656056cd6b96440980610bc88e4ab656c2e5ff6fe6c6a39967a1c0d386682240c5ff039148dc335d03b636cc4beba2967c418a9443e161cd0ac77bec5e44c4bf98e72fc28857abca331600142d2186719dc0c245e7b4a30f17834f371ca7377c01086b02473044022040d1802d6e10da4c27f05eff807550e614b3d2fa20c663dbf1ebf162d3952689022001f477c953b7c543bce877e3297fccb00ef5dba21d427e79c8bfb8522713309801210334c307ad8142e7c8a6bf1ad3552b12fbb860885ea7f2d76c1f49f93a7c4bbbe7010e20cbbe4671915035276d8df41a7ef0b6a36dd101de48a4076046fdba3b0bec20ae010f04000000000001017a0b90df52169792d13db9b7d074d091aaa3e83aff261b1cc19d291441b62e7a03190899a91403ca5cd8bded09945bc99c2f980fd27601cada66833a5f4bc108baf63902e8bed2778bf381d17241be029f228664c7d1522ced55379e275b83fe805b370216001403bb7619d51d2af2c5538d3908ead081a7ef2b2b01086b02473044022017c696503f5e1539fe5cb8dd05f793bd3b6e39f193028a7299a80c94c817a02d022007889009088f46cd9d9f4d137815704170410f53d503b68c1e020292a85b93fa012103df8f51c053ba0dfb443cce9793b6dc3339ffb0ce97af4792dade3aae1eb890f6010e20cbbe4671915035276d8df41a7ef0b6a36dd101de48a4076046fdba3b0bec20ae010f04010000000007fc04707365740121089f9677efff5962164a434b0bffe53d90c271deda3eaf30c1d7a55105d24b874707fc047073657403210be6c538eee2e29d44c66a3e66fc8165afa4081557031826a070703cb69faf24380104220020c731ad44c00a2928d508ad82b05868cb42733a5b0d0b208f483307ce8c328d9307fc047073657404fd4e10603300000000000000015bee4d0045b0884354b05d0285abb287ee8e539e8146b92dceaaee6fc01af1a3730cece4c77caefdcfcea1073197ffb8b3ded97d0dda6f49752b31f23e196378a3da2128a8c45ecb7eb1c32f0c0dfa1ce7bc348e799f66d547476e976baece7445790064b34b1526c88cf54928acc906ec0925327d797d36d0db6a43633d7f963ec9b4123a5ea31b655882329afe2108d123f76857fd3ce344fcd651b3d3066aa506625c9309acead85fb6c8a7d977db5dd6cb6e2f99fb3535746258d42d95dd2103bbaf5d45c8a2dfaa2301eba08763bac8ab3b59bd0082a457bc0cb257c43ea6354348e73d8dee101864068f0e8e30e6711f1597d7b529a57e95fc0df813ea160f5f5152f341087868a680c1bbc4b2a427d18cf8f12cbc4304dd3b1ea4c916467ae48b3b53062ea046161170fbe6ca07462cf3e5534d638c91fe6919318c4b2e98ce0ebcb245680d6395ba746fbf510a9a36ad8d933b023eae39973a39162178148a897b5174940db46e4be54794cea11fafbed48b42eed27f9915cfc50c958e88bac551ab1c9bfa03653e558cf87a99ff13440f4808e27fb42ff3cbac9fe10d1de07dad4807c9f945784163214c739a9eed8bb2e7da6e1fdfa4aba5d5157787d0000b220145572d3d9253cde5c1132370c1849847633287660b429f20cf1f72e4ad6ae59154c3b8526fc5d30523ba962a25577427988d326e207c97c81b479540b1c63aed0a4b1dad9279879740b2f6a0bfc37aea8c81b3b35b630dba8d955afbba756b8ce9d2a9802939972c5f70efdee8778a98360eef15faf77e38627fcb4f98569d68ebad3bb667e5db46eb7f4214846e651224673dc998c55bdd9e0a1629497a75b76160865c7ac3af874bc45a42269508f183d2458835b1734791094122f75398da2bb7919c67221ee42242c298d744fcb920726b84bcb78d7eafc9e0f61a02de87ffc5c674390a33d722b50dc35bbc6788fe0fd24be7a9e358113a4e65b49655767b8f3c3bb86cd5a56c79f9148945af63492dffde82d682eca4787f203e49790650395c925e6eb68bbb3adda25bb784365c0b3e241177ca7de58252b8c79c5a865d1030f3bfd4d312bdf83bd28241389085433c34d747f9f45a0a636e700805e619a19739b15077d44d5e8969a37481896acebe7f350449c69b50376b7cf36e906d8a03aa7221de67c7fc4c5408b55e2562f7b783918004d93b284c0a1c3d596c7c18aef5cb77ad09172bfa888f5dceabf57f708f5ab61b1b4159742d3d35332e9942958ea7f39fd35cff66e84ea0ce3b38a85eb80dcc1201146fc3854cb40353a078f5435fe2becfa383b3a62564645250cf7feccff5414581e747166625477c70f5b0f579bd578e03e6b8ff8c3f0e8a82566199ff542b239f2999103cbb61602bc2f346702204e50c9ce7b85f3b8e144227ca8b9766cdbd498191c385e3a4f024c9396763eacdfe41b706fb23d4f065dbaa43d323edf1811950c71d4475a3e0913d3851be4e921cc933bb06b0aa20524267b0e9847b6de3883ab8c5be1eac17b06c946f19dc2244901890cc290f2e66147f7c47a4a29349555ca020e684ccba5f8a6f1be54e356654d3e8678c591633e11d9ee772940d92f07ab83228c0d8840cb9aae514c03358e973a2ef319a39a3ce819efc00e5a493fd582be164c1460f70fb2e103f09a2939f779377275be736ccd41f847133b3d400477582419fbd2d7ff328d88256cfadd750ed7a3c6657e332f635f0a90602b24135e705d1530531b7b738e686d83accd74874e160a5716191447f832d2f899476ec9c53204fc4ade5b75cacdc869b4088e009e12d85beaa3450889de0c86315755ec7744be592f058fafe62f9a89875bd2781d5d6928c8475f555e77eeb6e688bd8d3bee0a54fa1cb29c1b6b438d3f70ee4ac83fcb6f482575997e3a69240c6731b517d8241cd39dba6b02a9e3c94ff2470c61c693d32b1c7d22ba38f0da21d92150115d580249380500109215a05baa63474f773892b1870005e76a68853e6a8cd9f74ab3f41cf0730e702ce94c420dbf66a63f342d927923d7d25ca3c3823b6c352ae2ca127bf811c023205632ddb8f9191c2f3384a61038d1c4d32f808cbaea81d58f0aebc7c89bcb5b98f92849f4fec19cffc78173e601eb412aad24eacd74d17cce3a9ee76670367ed87c2da3db5e4ab01d4d9626d0ae00da7dbf6b8103d5994cf66ca56bb9aab9eabee2b14ef798d3fa5ed1dc16bb500a006c3320941c4c7f6f80c8b1bf79131a5e11ef38db7c42d4c4939711184ea414e2ec0cf5bdce3d7d0d72dc883b2595e5f0fe4c14cddaed61108c90c74b43cbf719bcf7a934bee760ab33f50cedfe3ce61dda3e4bee1ab4dc687f988cfceb207152f7a98c0fa3a114d2d6881034aeba877bbcc368ce591707da45becc48318f0558b3ff65d677578df9fd9e9a18d0cb08f2f5cd4f44925259225b1c4c5ed84ef30d136e7c66251329a223a1db0b485f1c634981f8860aec1f3dbda9442e5438f6fb09c7e1ab43e2b757911834df8502ce35e7be947771f7416f7ea97d26dbad7221614175e6b86f1a323e26c4f469236d1b1bf6ef28823234c73b275c5b0ff39e8c04d9dd8ff7f6a57214d803aa13dbf581295b92ce2b8a9c0e3fa8e4fe4e74c4bc2198fd010cf84681cf5f3fc9df1638c403006478b1cd4204ef3b7a6093116021118a839bd3ac270783e67096457a86d63654e268821ee742241ab5f7e91972da0a94f679b4c093d3f428d5876edf51459331df084f2fa245e3648e0cac904a82a7d323b965a39683ec0b2721105683e67d65fe10b8d41d0dfcd5c31756408c94cf425ae67f95ecac45391516875870386b675e24c462b1f7634f758723e6245da6a39da69cc2390374eb89c6c662d94eeb2f1835e233610072936be248e6a3ff87f9950c2eb2f88568c31dd30d1f0c0396a42f6be2505bf616c63f504dad5312fee2f083b406fa05cf3c998ba24237402681f0ec393de4650ddce3389d4c1541d4705d8f50c2c6d4864934394fba0c40df495fe3a5bf58a5498c1e63b5ee5f9a4b53dbd913252d4808f5bf5fc3c6dd74c86c974fc9e5afb1a7ee3d88738ab1fe9194881cb00197a31d648ae2448db872528d5f7c366188d9d98ea94497cb78ffacb5f6e8a2c8520d8d196fe0ed13e2b2a5a08dc45d8ff58a8c5d3bcbdc5d80c798acd0eabf146459e79db12c2a43c55d14b2dd608475c606fd4f943ae7cf62131691768f710fd718fda3967146daa8d4f34a3b8fe8084f4f3865e9e0cc1a0b0a799fceafd1b74f09f524822179ce38cf0f2c4c8623a3e3ab2cc20f5dccdadffacee62c120657e3d85fea93fab645b5fcdb812b130afbbd5b19e86aee66011b520b0affd84af4bf67a28b309cad66cec25a5de06390a4f2a5af47d59c006010a8ffd214149bbe47bf847fa94c2113723c9476c2e6dd84411bca16dc7bb096aaa3e9a9be27811b52838c78d16cbd89cad379bcc0cd966dadfa428f9d4d8bf133f7d21022ae3f966dbc1409c6d57cc46ff4434fd90d79b6c9e68ed3795ea6191a7e309783badaf8db9fbccbea905ff9d423370810f02add38ad3088cf3393e7c6d585b76fd78c67766fff03ff54c01228c6737da667147a8b5e722370a24db8c0165e34888920d70fb1356eb731d0024676444e2d37860eaaed9790f99069e622afe6ff12d516812022c46420006253248eb292908ab8658cd874ef05bd568547535fd54c1f0b5b816e4d90a1bd55670b96691e7633a2fa45be6a29cf7bbbcf9e5debb4b7a739b36b6b326b719a12cd0f5e3557a2fd94023d8c633fb697b85080a39734013b4ed9a7500aa8093edfc3810d4c890e608951e57af8447349cdf45a076449241a047085702dc3e44814390ceddc878791ab3a6503f48f48af25fe5cddf61e7870ce80e32e5f22d5725bfde4f319c2db7cf3ba3b9952202cd24210ab8d47fcdaa9ad5e2a9d2c7be1ed6b67cbc1a28ebe565ed0337c09c97d2d9608d97905c7201be7d4bac785d64caf783cb3ebff817bc5ff0448899537ce6911c9803744d06ae97e6d3aae037697986cb20061892ae72e05968e9bc54153bd745012af719fe7fd4b917689a6cbb94a9bc8cce51d234ffce7dca804e2b2759f473885855983b7b290806884fc66e724fa848af2de3164c611c630e5bea712cdd9a9943ca3ad55994e5587c5953f415171bdef3c42783b809bc5526a88aae66be626d73394a607ca32256198dbc026d9e09e9659ddb66736215dedee0cf69a24490a53b2c678e6caa2aaef10a4610f802fc5eccf558629554d6388465584514d3dd49fc00fb267c39bb746f76ad3cccabcc3cc882815bd9466d593270a5c9a04945dea7ad06ddb73e66b90270e859a109d52251d911e7177e07295ac9788ce970c1b718fb0c2f327f44fd0cef3cb90071ec85e958e6ae60bd134ae307720cdb10be5a0af8c051295df905447b46206b5e04d775b83e11c348458b1bb310ae25c54e8ed1488a95b2a576002198c80e0e69d14fb7bffcd89935faa6e3f9aed61e0492bb2bc334e389bd559806eff9e16643ddc4372ca83790a99bd4f5b042779ef7e3039858881c8ce0041d43ed6b1f42f18007d046fd6f65907cef73fd5e6cd514c4fa5ebb872b140d0b2ad43c58f2f2216522e78a19828baa34ba56d71414ae869a13cb708762565d754f0754561adbd9145d232034229d2840ef0c96f7af4b232c5e11ae9d018b87177a506b66571affdeb693e170dd12640e86fd430b64509d02694c52a54f23ea96e39be92b65c1abcb262a71d6e884183d4bc6cac8c79f6e94b51abe484794a42a8e1be721cd59383bdbf327a864b2cf27566f1270d82ab6e8b3b934e953b7d48ec4697172e0160b8435e8186a7ea685dd61402b0bef09137fc52e19ecb53674a1c0af17fbb0efc2b4d69572b32600fdfc3c85c79ccb2685c665aef16748b7f15862f435afaeef00f3f927cd3a60c22f137e9cb2c38a9652cee570a76351871ebc9b6fc720b9117b1306e8afb298e3a1d0d4b2c5ad5a21e9de4c0938a98daa35caa711bd6d3312a7e941b060c4a1ec211c31e53da263995d3be74a3ca5a970d3a663245a5d8eace336d9ee847619bb337e777b961805e808f7cfd8f09b93b6ce6c277396e6cf0a6153fb11625f421b02055dc53a0bb24786f4a74211bfdf44193e48b2c15c7c85acd3f4f0bd26644f9dc62653e366178645899dc06d191c785831b98de593519c0ac5849897a01b4f8c7fd559edce1c878bdb9dd091546c64225fa81b1c7dcd6fe72c8131bb160043976a5e891236d3552598c0c4fc734d1cc752c10306dfc8391f6d658ab8b7a1f350e1900edda29775ac8a531032bac968f6981889f13cab07f49c864c3ef3ff23555c170ee9730912465e6bb3b7508e11ba27001d9dc0da8b34954a7c46a2d0b0b75e73ad66278c8acbed3249936a6c76fe975954f7889bbaae5f73747e3ed02811b015beab9d1515e396d37b2a116b3cd8863517b88ee91a854e4740304f7be41123692181a8ae22090956ba619fb948d3f08108da17ac2484d3dd5795b1c716cb5ed3fc08b6449fec814018cd883b02256afadd1f35a04d9d43f661be624c0d59d0d397e8ad6917344203843495162217e79bade11ca32c0a6918350520e6c3f31f866b89e3497b518cdc056e760813ebea7fbf343db50ca2450d5b7a1c5f430859e2040ecfa70cb0c3e863a756ef6ae2e26c68b543d35beb44513f8295872df5b4062c9b80742ca7a9c2ec36a1d9bc936c7fa7328240a2db54463ca04a40dc0c9afe4d570012259c8c436d322483b17a705d60a283e0ea7545110e898ba43ac6130aebde014d237482307ff28f385fce8530814a3b3507fc047073657405630200039d46edc3d830d852edbdf28cbc023dd1666cc4a806ec9d4acb2c97865280698d61fb6b2a073be4ce75cf8193fa9b3d677146575a812873ae7eaa7b08110cb88904273dd65af35115dd116092a56ab45fb57178d8c5ed4cf99474ff760f6e987d07fc0470736574072103701e53a6d0b960398abf678382a4d17c5c153d1a2c8ffb76b302058ce915bb0d0007fc047073657401210821b4e7599b1b4faf29b521f1c442dfb0a893499d374c19db939c0c9a3b9798c707fc047073657403210b8529a893bd81e38743e8e3015095077f6e244a064d64708963c6af5024b6aeb3010422002058037c2d81d3122185c8704d4276e2629122c95b8ea68575c451628d37eea84507fc047073657404fd4e1060330000000000000001ddf2f500cf45e30e3911bb51a7ff633c1e329508e42d9aa49fa8248fa4d293b87005db08b17a472580ae2cdd53c40b2a16af885d6dfa3d5b3410d389b045e6c12405c635511ccf008390856f4c6d0ca472148d2969fd39e1307bfbb8f8268ce92398248f08df7268bbe23e13ac3801ad075376bbe9684db9b41d7b1148fa65a129e1d25193ad973ec7af631a0a30c5659409b0d00e6fe44c2c507d52afbee8059aee7650bee9d47936838e77f00cfec9de3b9efe72cdeefd80a19a9c8ddcd6cd9009ec96800f9fcd709f1432b5715466d601b5ed10b0dfbd09b954b109232fb5a24036b887d26bab43da7eaa303e7c8e9d02950610aba09f343a65a7cb4550d6f6e5c0eeb9410b68f85cc3b05b9340e2e9c94a473f2001f5aea7e875d29e8e0aa99c09afec4a5455258c803e55b89cf6e89796a6f3f9fe11ee05ec415c6ac08e0f1adf9dad681f8121f82e3a9402a2fe13a016dc10d4a605578317be0d9d3e02b0989903002bd35ec4970701da6eb6f9fd5e6cefad137dceffaad968d5ce522e77c76e665529f70c9eb805a240834f4c8c795912c37e7efeb73d4bab709aafb66bd645cf0addefdd83d185c1b4465ee16344575eb2aa3acb057c37d7c22cd03adc6701f03d4cfa20ca94458b3b87e3fb7de8fed28a755bcaccbd348dbc7f5aacbb25d19437d87cb48b88fc714f059b328c374fb2695a26537330fae42d3fcff40b07054be10508fa78a9173315506119973a9158828276edc6e8ac771476d7479d07ba73e9c5b58d61367d24435a1062dfa376546e843b34829103168db63b708a13894813a442f889a423054160b85a2584d36951136bafc490056f1c03c44580e2c7a12b170e5c7a3917720bbbb21e5da616649b554b7ff57dc84dc3935271a8aa6fb218becde208d83e76bb6197f5f4f729f3c57b4280c388bf4945206fa769b672ebd47ef2d0f777fc9dfb031cf7c333c6159a75a5b33ebc6c4683ef140a144a5ab15b2b6b72ba14ee7595679a0f7873a75b9a79e03676ae94eaf9ea8d3532460f3075f40c6b9848a183fe46651caeacd51551f308eab6ba8ac27b93865f5dea0fcfe1d7dbb745695dcf187a5955414763c88ec01d299f03cdaec48eba946c7ff6031f28a5e108651401b5447c0d21c449b387765a621c057eea7d494302222e3d1ff6ee9f8a0580671d9fe3ecc310e84b554e5c823d81b8027075f749b2dc8a6bc5a99fed4a0fc46fae59cc2aa9f1471ca2b0d9fafa56927fce0f1df92647ff5aaa083bfcb7078bd8ee142448d4e1f3dda670ad93feb21028a57ee9a8ae8880df5b3276e078555d868be0d8843b495e082d743328620f36f7e106733bcefac15076826cafce271caf1520cc8746948e71ea73eef5de770ecf5e0fe075f04d6c9cef1cc1f262e69fcfc89862877ffd520e25405d9d07efec82386640d97147e4a6df66bb1fa1f20dcc2ee1fd6364bc2024c0a4a2ec00b84616231c02aef16147df509cb830b9fb20111c60613d41169a24ea67c03cea48e1905b00eba8a61e967b9aa5b6e1264b0f3e2c051e47f54f45c6fb78b46b9993c7d223d51036cb77f5e31a4b30892e8fd7ae7028322d6402f60712f712f84443de083767c38ae88a38fd4e4bbec58015f4e49e36ecbde94f23d0061edfff0e9eb62b67327249d728c278f923748e4c1e225791c740abf9493198f073a6cefffba00d23715a14967a72cc7aebb81ecc6e8bc88ae63a47507296a573c415d0163219f3b20974ba3a32572d29a479b88b89c241e63e640bbb93e2da0b73024ff03516ee3ecfbd84348372cfb574817ca878172a779ff131492b86e64c1b7054cc5fdb999df4a9578bbdd6a6a2a798f053f4c7456173cb8cb9b61735e650d0394ea9effbef615629c1f393949095982345bfc02b9a3b3ec64d9173bb1285587048fca8c740b6d2265d3e727069fcb90282c78f1049ed7925113279474d0d873045851b397a8c26036c83906dccd0eabe98f7d6854d9abc2e6ff12d84c2840affa371cc2dc624fbce873f38570dc9eff33f5e200791bc052307f5c718d47fc2a205add3fd9de2a81cb452a0a7b4a08bc133e9816f6ba852735b813a1b906d4dbd1ac8a968a8adfb6aded0d3fb87d80132a4b45ad39274bb72df20d648a26aca4beaafb971e13094b6d6525bd418b91320964bd90d3a98fb32d69222aaef2ea95c6b84b6b6aaeca3f6789944fc7ef17d218abc7667ddff798b74a0d5fbcc33d22d028d207f82286fd777ea1e281d7eb88b665e29fcda067bf9ef82a190c920e260cbc44d394b78e0439bcaa6371f8717ad82e02015f21e5dc273de338102539bc924d5a3f897eb788e0f3cbb6e8a34590ff5370bcb0f671ce28d6ac0adea17f9fda49c784ae84464991fc71a31d320d62c4199e4f4e38f390ffbcc7f15922c3325451371bebfaed8f8a7d3eead71c65878a705a6163ef649bdc6ae7b81110a2cc9576da6b0188337160cd518fb30fd5b0c165ac3de81002490f36d29f3bfefa2b4796c070c6d7d971d18bb5a573cd48cb3c64dec5bbbd7f2f6f60bff3db4833bb64b426c6715021997350aab1751f0d5382087ec133c2c43342b31eca32a4c17db14148fb48f9b7a103b2c0bfc0dc95ffe097bd8f2213a3f7a43c994599b05dc35d469fdc025e23e483039f271d948972417153c849fa8dbf374693dabd59d398732020e90d8f443ba45a00b430168561de21db76b9b714ca8260fdc4ff1a5713e69ed7296f5a5a9d192474bc6e67788d6a44d46b69ac97d0b34b2b08aa79d5ee7e910d99221e1e7f6383628b5383cec4341e5c3f18ec3361b2f2ee5935ed40919a4f8892bf3467803b720d29388b7cd47067eed9be7648fbbafcc7bebfc31a30d02f38b7d6be1579c751aabf679fa6891adf66da2257432c10d399a8d496d1aba381b64a5e3ec9a65cc8419151b638adea994c3590f77bf390152894b2784f7832d986ac51b20ba9719d85509acdedc0282f27065c87bf483fc74b55579ecc233fd6c51822ae03e46ecdb15acf0204b67852d525168f409d2a4309c5d9a14b35905b836091964ff4fec0aa91bbd7f39919eeaebbaf75c63337a4dcd5ae37cb60fa14bd78157ecef35ddb1cfdc366eecd48aebb0f5b395e4161c158c46870fc89f8f5918aabf0577c914511cac7b189384eaddf7f03cc6706a9abf219ff1b293cc9fa2cac88b65af62f0493e30736b596c119149af07e840a43dba8d97455a7a95368395488304626d3b888069a0099c435cc11e5981412f79153577c9115a1812b1c4a9ea42bbf11b40fdf930bcc37e6a6c50a7e3d06bfe7043adb32244ae359993caad00eea5f1de90355326e921145add1020ef3c2cbcbd102e7b9a150ff9672697d31f86572843269978cbc4c3fe067417e84898587d4de009b33094c8e8102c07facbda62a2996e083d0618fd9651e17f0fc025a946e7c28d93e18675ba69d8811dd06a2cc1aae28de5a6af30f305cfd8a090832483e4ff7c974d47ac96d2f3f7baec94f965a116c2734f87f468ec33cee1a58dd2ccdbc8f6a0f2a50a739aadf4007c7a529844cd1ce5efdd42eb28a0f5f04fde00dea586e4b8cdb8469b36940de19feefd342285c29298afcd3ddc368f6365e9ee255f8c2b6f70c1bafafe10720402a668ac3a2cb8ee75cb7004455cb4221486c3dee64f8f25f1c8b1411437cf6ba70afac5182b21f0efc1b5c71dd59f71796d2719741b6d5c757d824cdfd2d9459569427951d6974d94bea1fbeb0e1a23ef88774b270a8bca65f01a00299258847ddce8af8a7626c802b29dd01d1dd9d2a7243b334c29c0943e11ddbfe82cdfbd506e81fab8775a1d3c4f6c0744e1086763ad84e8f51d601e24cd6fcba1409abbb1c6b5c9bb9eab8ca30282801448f86cd5d8ec187866f1ba738863f3995bf4084ebe8f41dc1ffe0cd47d5a95dc5fc0dde1559ba170316e085d0e385ecf8646bf787b5287960f07bff9d3d990b3be4b29f008de18ccb46dc2192d0fbbbb9e701d350aae205fcd2d7314112bdc393e2eeb0a96c5f2c767dea0b82e9549f46a270b2c69915711c144a7737e9003b1c1b8684e9f2abe66ad1678c32a0c6ce401ae2d7507ff32c8f6179433b94764a6e4ea0a363e9a03787502c67ec97724d78c1257499379ecc5cd006a13acbba05dc7f1310bc75b9ec6a09f4d95b2ec11952eb3dc3d2dfeb8678b10b5db162b44af56ada56f7e311d6c5ce46472d9ba2284126f8f579d59a9d3e81bb1b26a7ee59c3cca96252fd4ba8e009a213911619ab4184e83683969cc4c474e934f36e6ba4ea33d9e93e984f1603e259cb7f1a3824dd8764bbe30ae08166aca84e63615e59c31d2a968a0beccd40637db22b971d51a4c35ce83108d8975d758669bd83ff9602718a882b943f80745d95a2d5e07ad0acf8023e24589fd68988a350c0ad571470f8b9a906648895d312100cd18089465de942ae0c7c8bffb5d3705c729990721bb0497dddea6dabdd530c9ec90286cee5ba3e2b699eb2de55de8aa0012b38051862bf0a7a22d6cce4310dd8dc47c206d9eb7bf28f2a53afa8fd10836210c0c461e417be42d89ea659a76d5e3cba08daa885b7f0302c5df05c72f8257f60e2ad954891841e67d8b7184cfa47e51e9b36f6ed1400aa84c5058a1998d07709b8b46630d70c73552ada18713310dff4177e2143aada1038bae9a64e02870a7535598d766f447b4e25dbd009009cc0e3421067bd0cd10735469b308cfd7a094bbdaaef2e31c22dc6c1a6d4c7890020b5bd04ef649b56889b2031c1923a69002448dd5db1142384cf517b08096539cc537532f43afc33ca77beb2dfee921178ad51b04f10495365e60b4b7677880409716e0eaa3a1d649a871234f86787c2792bf1e04a635e3f22b8b3b1382be942605c3855a940cfa3825a2f8993312a512c81f92aea0fca95bd1bdb6b9774ef3f1fd15bfa1eae84ebb48bc9b55fb2141c55cd3188eeb5049b2e6f3360e60c5bb7d91c9028ebc9287b4b5541a4ca290288e08ca46f80eeabbf100f700c873d7e69dee7dc80b842004b2bb93f0bf533488028d1a1137371417d06785372ce942d4c6589cdb57514bde81960475c22393eb02a93b6560fc3e4fb6ba692dc362d38e33a41b7df222e9192fdc0e0499f110e681682e2b500c00947d62280482dde5e26010cf959fc717d0837c98634550376aaeb17c1c80e3c3245c36c68f56fc8be117ff84957a75e4aa4caddb38779f1c50086ad4863002127b6c8067f172aa78137908fff82b2297a53d6232c26a2e94bb25b7f9241013adeb36d1e437f2f6c0d983efdb78608e940390005d63c081eaef21d7f00ddf51a3fbbe6175be436a9b0b75f198c30efee2821ac5f088819eb96ba835999d0012e7a0c244268a658bc6b7845d10178283cb8add0b81405ccd64000c1835111511555eca14f7e3cc9274b45f817039ee62cfd95363cc66f5397f88822f790e0a86b6a69379dae77db24185394d9fc73880d39f6b3233dd8d3b912995b22905563ae8cb2b1f3491feffbbdf2c7d2e89dce1995d2429bb0a4c550860835aef589983d3170387971f8aec15c18450dbc9cd12f402589dfb17216e359072ceec8e9484f9b490a288dd4b268233c40ad23721961c390bae0a181c4cc8eb68eb4b2a5db6944042c6ef67550f9abf3b9084cfe8521b62d727416576a58591dc65f79f871958243ca4415d92d3e588c4205b4a3806d64224e94e8f04dbf7f75888246aae9f894bab1ea69d7e10b4f07e8cf2dcf70cc62571c737cb6b6c68b0e3fbe4b1931c8615a793fa3db0a45090458ff62ce8bf421907877e555cdb97d3709bbd8728c4432288861a56cbfeabbea5f225cd29e31d99eb788704a93696f5e81307fc047073657405630200035ed48216bc666598aac5498e9fe513a9e21eaf842d382767220cf98104bfd8866621efb63b2eed44028cdc9e2f64cc2447fe09f8d8a1eb3214272855b525d9ce24e6daee58effb4af28fcb0a4685d78d7995081b5cafd1cfe343aefc8e9cb23507fc0470736574072102b642f0e5b34746f2f6e3b511d037e16bc720292da4ea2fb31ec09f6fdbe777ce00010308f40100000000000007fc04707365740220230f4f5d4b7c6fa845806ee4f67713459e1b69e8e60fcee2e4940c7a0d5de1b20104000007fc0470736574012109a05049129b0d9e61c1bb87a9fa02c2435be35e3535082a772f65222f2e4a48cb07fc047073657403210baf4431fbb8f0227bfc0008368606a4b8f2bc1706e1a06cd4d83706217b74f5b90104220020c773786f3addae4c21acb094f39122c032daded1cb6225a64d923a0344087bfd07fc047073657404fd4e1060330000000000000001a4092701f9170991583ec8b5c9b5056ddaba7637f7d6733a57dc4990acba6d15e9eb5dca55528e179b98a9e09e05ba940b59558b768194ca046c22e12ea310ec05bcc795ea419277649d40b145e6f0accc31f2d7eb39b29b51d3ba3410536b9bb37bce9014d352b496b93161fc799b23939ee635f25c4cbd6605029722ac2bfed7d55fe4120c0cc880661ea3313d700e261ba973bea5df4dc4d8a05652d193c5edad01945862943a6756d4b0ddc93ad5a444ecb054bcfbbba3635aa752d9c4fe8f93fc56c8066b3fe344143d65328025f5184308f2016eae65df8b0f1818f59f5a9539eec9c9c94704ecac269b008ef25f67ab2b9ab4e903b1f2372d1d3988b86e5efa639f9f964599df8559622c8d11f6bc4f706c74e4a603a3798005e210f93d9e6b59f8ccac907dc9cff127c552c8c89981e1b91c817cd365422eb6bb0c7ef4ddddabd306b0c32a98464973dec30def4149f8e9f35de6840cbd0ce8a2f2b5dec15e3f3c27d0d2720159cabb3ff2f73b4571eb53ec735d7b0f27bf4d23cd8b0fba14d5921d464beb3fd4f2fcf844f76a7f7f129a3e7e1c4a6e4f07490f2cfbac4e6730148397c73720d35cc5a46fdb1e774e17f7b951887c1c72ae4cb25ae99bee652ebb2ffd9f4c9400ee0870b27a5dd8fdb8224aab6738399587b4513d3441e26b898b35f739d64047ce8de70347042fd18c3797b1de82cfe23521dc8e5c36e286c05d4f81508e282018cd8d263164512e6ab02a22b3d5d489e6074f9370e218a3adf8afd229659f5046749db9615541408739d4f0646a853b25f8e549e85708c368e45f3e1d20ab47a4ed647b820a360e4e351e4caf74810098f0df4bb74e0e69f2db3284c30d24a0d109d16c37509557ce15c81812bde78085f31cd7c93140fc43d6580abc7ca2adfe6354510fd8104c0f1ffe46d24f31bea808376ac27996fb992de15b30abf4df6f4d08860bec27a95bcee0df8f0a5bd7f72938ca9e917f39c5425bff826c4a84a1fd70cff87be2e8619e0d3b729f0aadc10d4b70d10c2c020a99d03424a595294dd34b84c83a2d434b98fb116e2ebc8b2bc444740ce090816218ea61da172e30db5e78a58ef495812c287e3cfab7bffada0d6f2fb3c153f1a21707923ae7ec862d44d357776803336566c3bebc9f53177a3a8825478eafb32a61bc04d82994708725e0ccf5d76dcac946f36895402e84856b3e25567156040510fb299b88c45713175c54fb3d54aa6d383c423807778a92b7d9bc8fa347923749d18c96b20cea608b6380b57c35b4408f724046f6f65fc0d71e237c39376e1ec6dfc6a2ae83ba70d25855c10e6a8f425951c52fac7758353e2068e5cb4b6ea066491e834a47f8a5cfbd6ca91c832fe4f77b3b3140a6c1c70055d52f0aa67e7d3ba18e5bfb09f738141a611002ff9e34188d540ac42f48ee06f6925cbf3cca5ca033c4fe089650a2b86a8350367e9cfbd07fac9667c0171f54311cd5b371576790e51a1fddbec64f8f559cc08b1c0ae5113bb0c532742d90c1a266bd7eaa4b1d06693ff12d6e66c51bb1d12dfaeb70bc56d5870fb5ce4b040f86d7725ae53b18c1b12a84f7e3a2e7d748e8a899fb917987518c6dbbb83e3b62b31b0facd3515cf2e18b4e49218ef48d97df114971b298a6c4af231a432d4ac295d0d1947e09ccf41ab104e5435e7dddc0a6815b636a31be9a0d9cee2f22c745f05f384bd703fbf4bbcfeadf177abf4ca4524f38a681e5436a06abf9ca70c7569a7bcb8337b0b0c280b5f790ebe1258bea9c1da58c65c13991efc1ef8f7c75ef28affa340d84b33398790a9a77d30b0ea35613b39b1b7d8667fd7299e2ff38de468f625df1485ee3b2759f7e27ed707f5807342bad0935ed42609849d7a9d11addf8a92df7933ec44e86ac7f24d55a55284fbc4e4824a2b4f8bcb146d08d7d6d3f551ce1b494d7c0fbd6e82ba4496f3eb2812c986f3e2e627240a9102089725057c1e5dcaa3bcc5efdd6ba7e8a496f609aca3dd82816552c669c255283f9372be7d8f12b044f8c41180aac612245945a4467fa806892d55ff425adbbe92bc892698a32d39d7c23303ef65c980c608b5ac07ee60ed2b4e028a5565f5aa3ecd1e15787c23716697d53603f72738d5ca88c5d8280c3d8af9e83c18be420bb87db4b82a98d3af42f9191d4023eb22f428def2ee99d04d1497cb8205b67c9ca893f7afba077bae5fc11cfeb53d882763f2eb6731bab373923a63dda3ee1c1b6207e0ad0884290333dfae3f80e85cc50a241c73d7d99998e9b14c3e52e660edfe594e1ddcef04402e8fb01efff9c00d9a6ffc955e219fe9c92cbe87865f7a25ac68fa2d360c584c33fa3e40ce91d021465610b85b5f1a98e6908a17c5e138f2dd7da2769bad8789eed99828e8f23952bab7e9ead5fa9bac781fecc93de7927544736fd5c57f1da32be31b85657c313cd02104e1b889426bf4c8e9daa741278ae3966ea673cd3fa164ea7cc947b34f86c92084043ae846aecfbb15535a9b21e27fcda9a21bd821072135554e3015d5a12d1c7f2fe74dcef63fe99c947b55a4253add3668bab2d356d58909b7b0784c0759dbf1036645c5d673edb45245f5e78407978b63d5c25ada76b176dcff53e76801d7c2784d4687561f32e7a32175c0fc77227b3ab0a4054462d042931897530502c85f0b976fe3e3fd5488853b20dbd27d0d736e9f44fe6224b9610af05c462f08d328cefa4bf8530250f5a4d3fa7f58f5a48db45cd68d0dd53a2c66758a20184cf226565ce558e60f0af982b02672f8ab14333349a5e5a5dcea61a09f93addea3858fea4e49c84f5d8269a2fe52f072d66240e7d30b7345c841a135271c07e6a142ad1ef1955e29469d3ad3d952ca9055696dd825253e4a0e4822bf3119f1df2404ff9bfa39568a52fadf98ac6d5a4653862d91b995ab166fa9de73478f7e339941e036b621f7d773a5413471d6e41a68c02ed89a4882bfade2b10e399f4515470ef43930a911609911f8b66bc060ebb186cdc4c1aa3cb573d696b0f48a655f8877f68f678bbf467ec872724181d6f983682389fc8a61a7525bcd61ab37930e6eeaac82b7adaa145e2a0bf67e235a657949708f0640ec802a1741590a505e4a109ba857824e00f8f675ae6bc8a0f32aaec0f38398c33c8f53bb3cd53bf697ece4372f8f252ab4b314769f1393aabb2675f44c05dbd279732824d49e77f3df8841de18a30a9bc321ae43c712dbb9f08b457dd3e3f13244ae03da16acd6d3e861efae625478a89020655f0de72ac174a50834db564d4e60bef51e28954a938c64a6ee290523337153aa4d6cfaa00826d2aae1b57e3ab857e10cf2b497597ef9395fe6afb3d74b21c5d44281f756e018539ce8b7f4bc663db1eac9b976da2f994b193a30bde0394b7648b55ad9bde958ec5bf89eab516d4418451d8cbca637c1d6dfdef61712e76aa7f12151d5717ba1af71c4754136563ff2667bb984a80a51ee9112587cb77ed6fac8f4263fce637adcab9f315d6beefe509f8d34ae9c42c12dd42067584c4a96f6c15fe590bd8616983abbf453ee038f385a126dcb71919dd7143a8c27186e1c6d29d36c1039a8f008088e03fe7b97fd7f285a0817ca746438e0949dcfe49fc67ae967d13d1d1aa37c2e410bb95609c7ba0586c8fccdcca933b1a85ec97d1aff670004f71232bedbd192ba5e5a681867470c4e146221bee322a5f458a2bea1316d3f4be26efbcdeb4b1062e58f2fa23b144cfdda55aad3ed7142653c7948b6d854abb8d1201e9a4de07b8985fc194e58ea08b4c8528adcd73ae6bcf5493b7b8ae1f663ace587a87d5a341828612bf82605ce6cca9253057a8096f396bdacefb56f9a452849f0ac652738b5b3135ae13af532dac7d9d5307f158d844bd3664865724aa9907d2ccaf4cae78e056ee78815cbcdccfc38b71e0c648b1fd9f710a15d799e237c344d53923d3941e73f924b75de975ead5b536d632338fe83a8d02a4b7fa9a6f1a5df9de85c88b944581294609c880ecb5eb45de087524d896486c200ad68f5c45e43894d6e84493bed02602ab075c8dca1e57e3932740c25a9401b5bbc1bf524f4885f77a501bc3c313666fdebe7497a2b55031563810b35f33503cdbeb46de12c0482c70b07b5ca3c4e2aa21be75c33a23e73c03379c434dc8bff54dc40b0a34f476d0fd1de0422ae6edacc8a729ed2443315336b208ceafa68a229592e42f49501cf03fcf04ed2ab60cf7c31bf4d4fb5a8d7b8969ddfa8a725eb9d32827446c141170bec2b0dfb5c0a6e00cf83b856ae71b5ce46dfafdc12f94a7f8f3d1bf1eb769f52f43238ed411a97e55625ddc208affbae8ade42829c82cf4f62423830db9ca4091fffe3d282c578552649a34cbfeef3d58e020978137a44fefdb9083186dfd712301431b78095a0997f0764f3ef29f138ffb322c8e187c260c90a3ef7da5638e8d961d6a6cb1867a86d3eb23419e101e18bbf128c7a3492e8447533b7586a81e52366bdf2c376a57847b8a44f7b55eaeee6ab2f06596a87ccad4a60881bcf4b4b5d5f0de85593b643c0c4fe1771a0cb5bb0402fae0f1a2dd811d6495676ad718b73d4b86fc79ce074aa9924829ceb4dfd4e3ab70fdbd94b5ad1d11ca9e582dc215577056373ed91ccd6472b3ce02dffa8817e66205b179f37bdda376d25d6bbcc83a15ad757bb7843aa03d2f7193d8d707ccf4de1f5c8694aa212219752addd55cbb412c05118c30555ca7ea820bf3440d1dae3332947a1cfc22e366d1ad120b906274883d7769983eab6afea2ec0672a2ed25b2b3390c017566e52a0ebc59e6cebb89918d54f75d4094b943e7725468034d2ecfeb68228060bad59a4deaa40843d0cfe0a1e58855113bb7c5965254b82cf3997924d0a8b1711b1e1e5b28343168f64fa9bdf8e5158f33c91112f61ba782a4f97c5456c9c8756adf53a7d919ad90654a1c035d8686f834750302added0fb7b29a3f4f43f4dec29bedcff3139cbdffe391ad64b48eb1691be659e4e4dab266b7221a2c49e42d8ab06ab6d16efee2a0e0bab140aa34b53f70c808f3966f1a171bdc789e23ca0246328dcb1680c765fe262048b869c56f381bb7ded54e1486c0a3660d990f4bf0e5b4eec4cc0c3abf4edab6346cb531194c27de0e316d9d0a823db00e20e2fb99c2b5383213518d0cf604ae8f69d2921b442b729cc78579dd242314da99f01df55a45dadcc87e4b216aa0d817e60673c9807a75185e52a70f04ab8ea28cad805c37fae5417f89af44d4a5728c187c74ea736f21681fa7f93dd9bcab9b510febf2c4b5c64cbedb6b59b77a8816728dfbaeea423bb7735ae1fba08964a343ef9b5d36dc7f8cba10c8ae69bbddc4e524df73c940f762a2d39ce7ff235425942f2007b4e08f2002018f720e0339bfa2704a9d74798b13c6fda733d965666ec5592d1d6dae7af6efe5c87cf48d40858937b1ecde3445ab2c1ba1e87e1c2f3ce696baf3efb30ecbd9dbfab121a142ebfb4f09f343f37e8c5c0f40408a339cc3e4f4d34742d695dfc037744ba1a794abb67954d3a6509157a3aaf293c886b58cfe9bed8a3dacda2a2ce41f95e72e46baf65ca666f61bb548afe8f92e1c4ada258f46178a4591015678fc542d412f7ed323d2629c127890ad9c2151261c4869f59db9648e09c25bd5ad8cfde27ea4ef22666ae0f30a4d25c3ea1780a6c3eb2d94d0f48c1a61701707e57405e7e9f448452d0a48af07013fe04d6fa62fa5fd54139d95217734ff4e596f2ac975bbfb8fda29f7e6f211eb165480e44fde387d4833f89c7162c1bda3265a5271946c5392921861ad5d9e5b672afe4778301d7a8a8d8a03ca1c99d73b2ee43281c0b88ca4292a5ea29a0e2377007fc04707365740563020003c54f16cef0fd4185f35dc6784047913c89883f72b68aa78c16f144624430909da01633eb2b4b13eccc2b7a7ac5ef3b13505cea54e1d390944b5680e6860184e35111675dce504784f4ae8121dbd1f76df3d55ef722f3f73b5b7723efe2fd34b107fc0470736574072103652ba5800d63722adef5232d31ccc12403055de720f0155fc47bba5750ccedd400 \ No newline at end of file diff --git a/src/blind.rs b/src/blind.rs index cff07475..6915a94c 100644 --- a/src/blind.rs +++ b/src/blind.rs @@ -15,12 +15,12 @@ //! # Transactions Blinding //! -use std::{self, fmt}; +use std::{self, fmt, collections::BTreeMap}; use secp256k1_zkp::{self, PedersenCommitment, SecretKey, Tag, Tweak, Verification, ZERO_TWEAK, rand::{CryptoRng, RngCore}}; use secp256k1_zkp::{Generator, RangeProof, Secp256k1, Signing, SurjectionProof}; -use crate::AddressParams; +use crate::{AddressParams, Script}; use crate::{Address, AssetId, Transaction, TxOut, TxOutWitness, confidential::{Asset, AssetBlindingFactor, Nonce, Value, @@ -211,7 +211,7 @@ impl RangeProofMessage { /// Information about Transaction Input Asset #[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(crate = "actual_serde"))] -#[derive(Debug, PartialEq, Eq, Clone, Hash)] +#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] pub struct TxOutSecrets { /// Asset pub asset: AssetId, @@ -239,37 +239,172 @@ impl TxOutSecrets { /// Returns a tuple (assetid, blind_factor, generator) if the blinds are /// consistent with asset commitment /// Otherwise, returns an error - pub(crate) fn surjection_inputs( - secret: Option<&Self>, - secp: &Secp256k1, - asset: Asset, - ) -> Result<(Generator, Tag, Tweak), TxOutError> + pub fn surjection_inputs(&self, secp: &Secp256k1) + -> (Generator, Tag, Tweak) { - let gen = asset.into_asset_gen(secp) - .ok_or(TxOutError::UnExpectedNullAsset)?; - match secret { - None => { - let tag = Tag::from([0u8; 32]); - Ok((gen, tag, ZERO_TWEAK)) - } - Some(secret) => { - let tag = secret.asset.into_tag(); - let bf = secret.asset_bf.into_inner(); - let gen1 = Generator::new_blinded(secp, tag, bf); - if gen1 != gen { - return Err(TxOutError::IncorrectBlindingFactors); - } - Ok((gen, tag, bf)) - } - } + let tag = self.asset.into_tag(); + let bf = self.asset_bf.into_inner(); + let gen = Generator::new_blinded(secp, tag, bf); + (gen, tag, bf) } /// Gets the required fields for last value blinding factor calculation from [`TxOutSecrets`] - pub(crate) fn value_blind_inputs(&self) -> (u64, AssetBlindingFactor, ValueBlindingFactor) { + pub fn value_blind_inputs(&self) -> (u64, AssetBlindingFactor, ValueBlindingFactor) { return (self.value, self.asset_bf, self.value_bf); } } +/// Data structure used to provide inputs to [`SurjectionProof`] methods. +/// Inputs for which we don't know the secrets can be [`SurjectionInput::Unknown`], +/// while inputs from user's wallet should be [`SurjectionInput::Known`] +/// +/// Explicit assets can be provided as [`SurjectionInput::Unknown`]. There is no +/// need to construct a `Known` variant with secrets +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum SurjectionInput{ + /// Unknown inputs for whom we don't know the secrets(asset tags/blinding factors) + Unknown(Asset), + /// Known inputs for whom we know blinding factors + Known{ + /// Asset + asset: AssetId, + /// Asset Blinding Factor + asset_bf: AssetBlindingFactor, + }, +} + +impl From for SurjectionInput { + fn from(v: TxOutSecrets) -> Self { + Self::Known { + asset: v.asset, + asset_bf: v.asset_bf, + } + } +} + +impl From for SurjectionInput { + fn from(v: Asset) -> Self { + Self::Unknown(v) + } +} + +impl SurjectionInput { + + /// Creates a new [`SurjectionInput`] from commitment + pub fn from_comm(asset: Asset) -> Self { + Self::Unknown(asset) + } + + /// Creates a new [`SurjectionInput`] from [`TxOutSecrets`] + pub fn from_txout_secrets(secrets: TxOutSecrets) -> Self { + Self::from(secrets) + } + + /// Handy method to convert [`SurjectionInput`] into a surjection target + /// that can be used while creating a new [SurjectionProof]. + /// + /// Only errors when the input asset is Null. + pub fn surjection_target(&self, secp: &Secp256k1) -> Result<(Generator, Tag, Tweak), TxOutError> { + match self { + SurjectionInput::Unknown(asset) => { + let gen = asset.into_asset_gen(secp).ok_or(TxOutError::UnExpectedNullAsset)?; + // Return the input as 0 tag and 0 tweak. This also correctly handles explicit case + Ok((gen, Tag::default(), ZERO_TWEAK)) + }, + SurjectionInput::Known {asset, asset_bf} => { + let tag = asset.into_tag(); + let bf = asset_bf.into_inner(); + let gen = Generator::new_blinded(secp, tag, bf); + Ok((gen, tag, bf)) + }, + } + } +} + +impl Asset { + + /// Blinds the asset such that there is a surjection proof between + /// the input assets and the output blinded asset. + /// + /// # Returns: + /// + /// A pair of blinded asset and corresponding proof as ([`Asset`], [`SurjectionProof`]) + pub fn blind( + self, + rng: &mut R, + secp: &Secp256k1, + asset_bf: AssetBlindingFactor, + spent_utxo_secrets: &[S], + ) -> Result<(Self, SurjectionProof), ConfidentialTxOutError> + where + R: RngCore + CryptoRng, + C: Signing, + S: Into + Copy + { + let asset = self.explicit().ok_or(ConfidentialTxOutError::ExpectedExplicitAsset)?; + let out_asset = Asset::new_confidential(secp, asset, asset_bf); + + let inputs = spent_utxo_secrets + .iter() + .enumerate() + .map(|(i, surject_inp)| { + (*surject_inp).into().surjection_target(secp).map_err(|e| ConfidentialTxOutError::TxOutError(i, e)) + }) + .collect::, _>>()?; + + let surjection_proof = SurjectionProof::new( + secp, + rng, + asset.into_tag(), + asset_bf.into_inner(), + inputs.as_ref(), + )?; + + Ok((out_asset, surjection_proof)) + } +} + +impl Value { + + /// Blinds the values and outputs the blinded value along with [`RangeProof`]. + /// + /// # Returns: + /// + /// A pair of blinded asset, nonce and corresponding proof as ([`Value`], [`Nonce`], [`RangeProof`]) + /// The nonce here refers to public key corresponding to the input `ephemeral_sk` + pub fn blind( + self, + secp: &Secp256k1, + vbf: ValueBlindingFactor, + receiver_blinding_pk: secp256k1_zkp::PublicKey, + ephemeral_sk: SecretKey, + spk: &Script, + msg: &RangeProofMessage, + ) -> Result<(Self, Nonce, RangeProof), ConfidentialTxOutError> + { + let value = self.explicit().ok_or(ConfidentialTxOutError::ExpectedExplicitValue)?; + let out_asset_commitment = Generator::new_blinded(secp, msg.asset.into_tag(), msg.bf.into_inner()); + let value_commitment = Value::new_confidential(secp, value, out_asset_commitment, vbf); + + let (nonce, shared_secret) = Nonce::with_ephemeral_sk(secp, ephemeral_sk, &receiver_blinding_pk); + + let rangeproof = RangeProof::new( + secp, + TxOut::RANGEPROOF_MIN_VALUE, + value_commitment.commitment().expect("confidential value"), + value, + vbf.into_inner(), + &msg.to_bytes(), + spk.as_bytes(), + shared_secret, + TxOut::RANGEPROOF_EXP_SHIFT, + TxOut::RANGEPROOF_MIN_PRIV_BITS, + out_asset_commitment, + )?; + Ok((value_commitment, nonce, rangeproof)) + } +} + impl TxOut { /// Rangeproof minimum value pub const RANGEPROOF_MIN_VALUE: u64 = 1; @@ -281,95 +416,112 @@ impl TxOut { pub const MAX_MONEY: u64 = 21_000_000 * 100_000_000; /// Creates a new confidential output that is **not** the last one in the transaction. - /// Provide input secret information by creating [`TxOutSecrets`] type. - /// The inputs secrets must be consistent with the target_asset confidential [`Asset`] - /// It is not necessary to supply `[TxOutSecrets]` for explicit assets - pub fn new_not_last_confidential( + /// Provide input secret information by creating [`SurjectionInput`] for each input. + /// Inputs for issuances must be provided in the followed by inputs for input asset. + /// + /// For example, if the second input contains non-null issuance and re-issuance tokens, + /// the `spent_utxo_secrets` should be of the form [inp_1, inp_2, inp_2_issue, inp2_reissue,...] + /// + /// If the issuance or re-issuance is null, it should not be added to `spent_utxo_secrets` + /// + /// # Returns: + /// + /// A tuple of ([`TxOut`], [`AssetBlindingFactor`], [`ValueBlindingFactor`], ephemeral secret key [`SecretKey`]) + /// sampled from the given rng + pub fn new_not_last_confidential( rng: &mut R, secp: &Secp256k1, value: u64, address: Address, asset: AssetId, - spent_utxo_secrets: &[(Asset, Option<&TxOutSecrets>)], - ) -> Result<(Self, AssetBlindingFactor, ValueBlindingFactor), ConfidentialTxOutError> + spent_utxo_secrets: &[S], + ) -> Result<(Self, AssetBlindingFactor, ValueBlindingFactor, SecretKey), ConfidentialTxOutError> where R: RngCore + CryptoRng, C: Signing, + S: Into + Copy { - let out_abf = AssetBlindingFactor::new(rng); - let out_asset = Asset::new_confidential(secp, asset, out_abf); - - let out_asset_commitment = out_asset.commitment().expect("confidential asset"); - let out_vbf = ValueBlindingFactor::new(rng); - let value_commitment = Value::new_confidential(secp, value, out_asset_commitment, out_vbf); - - let receiver_blinding_pk = &address - .blinding_pubkey - .ok_or(ConfidentialTxOutError::NoBlindingKeyInAddress)?; - let (nonce, shared_secret) = Nonce::new_confidential(rng, secp, receiver_blinding_pk); - - let message = RangeProofMessage { asset, bf: out_abf }; - let rangeproof = RangeProof::new( - secp, - Self::RANGEPROOF_MIN_VALUE, - value_commitment.commitment().expect("confidential value"), - value, - out_vbf.0, - &message.to_bytes(), - address.script_pubkey().as_bytes(), - shared_secret, - Self::RANGEPROOF_EXP_SHIFT, - Self::RANGEPROOF_MIN_PRIV_BITS, - out_asset_commitment, - )?; + let spk = address.script_pubkey(); + let blinder = address.blinding_pubkey.ok_or(ConfidentialTxOutError::NoBlindingKeyInAddress)?; + let asset_bf = AssetBlindingFactor::new(rng); + let value_bf = ValueBlindingFactor::new(rng); + let out_secrets = TxOutSecrets::new(asset, asset_bf, value, value_bf); + let ephemeral_sk = SecretKey::new(rng); + + let txout = Self::with_txout_secrets( + rng, secp, spk, blinder, ephemeral_sk, out_secrets, spent_utxo_secrets + )?; + Ok((txout, asset_bf, value_bf, ephemeral_sk)) + } - let inputs = spent_utxo_secrets - .iter() - .enumerate() - .map(|(i, (asset, sec))| { - TxOutSecrets::surjection_inputs(*sec, secp, *asset) - .map_err(|e| ConfidentialTxOutError::TxOutError(i, e)) - }) - .collect::, _>>()?; + /// Similar to [`TxOut::new_not_last_confidential`], but takes input + /// the asset, value blinding factors and ephemeral secret key instead of sampling + /// them from rng. The `rng` is only used in surjection proof creation while + /// selecting inputs + /// + /// Use the `txout_secrets` to specify the secrets to use while creating this output. + /// Use the [`ValueBlindingFactor::last`] method to compute the blinding factor for the + /// last input. + // + // TODO: In upstream secp-zkp, create a non-rng based function. + pub fn with_txout_secrets( + rng: &mut R, + secp: &Secp256k1, + spk: Script, + receiver_blinding_pk: secp256k1_zkp::PublicKey, + ephemeral_sk: SecretKey, + out_secrets: TxOutSecrets, + spent_utxo_secrets: &[S], + ) -> Result + where + R: RngCore + CryptoRng, + C: Signing, + S: Into + Copy + { + let exp_asset = Asset::Explicit(out_secrets.asset); + let (out_asset, surjection_proof) = + exp_asset.blind(rng, secp, out_secrets.asset_bf, spent_utxo_secrets)?; - let surjection_proof = SurjectionProof::new( - secp, - rng, - asset.into_tag(), - out_abf.into_inner(), - inputs.as_ref(), - )?; + let msg = RangeProofMessage { asset: out_secrets.asset, bf: out_secrets.asset_bf }; + let exp_value = Value::Explicit(out_secrets.value); + let (out_value, nonce, range_proof) = + exp_value.blind(secp, out_secrets.value_bf, receiver_blinding_pk, ephemeral_sk, &spk, &msg)?; let txout = TxOut { asset: out_asset, - value: value_commitment, + value: out_value, nonce, - script_pubkey: address.script_pubkey(), + script_pubkey: spk, witness: TxOutWitness { surjection_proof: Some(Box::new(surjection_proof)), - rangeproof: Some(Box::new(rangeproof)), + rangeproof: Some(Box::new(range_proof)), }, }; - - Ok((txout, out_abf, out_vbf)) + Ok(txout) } /// Convert a explicit TxOut into a Confidential TxOut. /// The blinding key is provided by the blinder paramter. /// The initial value of nonce is ignored and is set to the ECDH pubkey /// sampled by the sender. - pub fn to_non_last_confidential( - &mut self, + /// + /// # Returns: + /// + /// A tuple of ([`AssetBlindingFactor`], [`ValueBlindingFactor`], ephemeral secret key [`SecretKey`]) + /// sampled from the given rng + pub fn to_non_last_confidential( + &self, rng: &mut R, secp: &Secp256k1, blinder: secp256k1_zkp::PublicKey, - spent_utxo_secrets: &[(Asset, Option<&TxOutSecrets>)], - ) -> Result<(AssetBlindingFactor, ValueBlindingFactor), ConfidentialTxOutError> + spent_utxo_secrets: &[S], + ) -> Result<(TxOut, AssetBlindingFactor, ValueBlindingFactor, SecretKey), ConfidentialTxOutError> where R: RngCore + CryptoRng, C: Signing, + S: Into + Copy { - let (txout, abf, vbf) = Self::new_not_last_confidential( + let (txout, abf, vbf, ephemeral_sk) = Self::new_not_last_confidential( rng, secp, self.value @@ -382,8 +534,7 @@ impl TxOut { .ok_or(ConfidentialTxOutError::ExpectedExplicitAsset)?, spent_utxo_secrets, )?; - *self = txout; - Ok((abf, vbf)) + Ok((txout, abf, vbf, ephemeral_sk)) } // Internally used function for getting the generator from asset @@ -426,88 +577,71 @@ impl TxOut { } /// Creates a new confidential output that IS the last one in the transaction. - /// Provide input Asset information by creating [`TxInputAsset`] type. + /// + /// # Returns: + /// + /// A tuple of ([`AssetBlindingFactor`], [`ValueBlindingFactor`], ephemeral secret key [`SecretKey`]) + /// sampled from the given rng pub fn new_last_confidential( rng: &mut R, secp: &Secp256k1, value: u64, - address: Address, asset: AssetId, - spent_utxo_secrets: &[(Asset, &TxOutSecrets)], + spk: Script, + blinder: secp256k1_zkp::PublicKey, + spent_utxo_secrets: &[TxOutSecrets], output_secrets: &[&TxOutSecrets], - ) -> Result<(Self, AssetBlindingFactor, ValueBlindingFactor), ConfidentialTxOutError> + ) -> Result<(Self, AssetBlindingFactor, ValueBlindingFactor, SecretKey), ConfidentialTxOutError> where R: RngCore + CryptoRng, C: Signing, { - // Check for Null Assets at start. - // Maybe just remove this variant altogether? - for (i, (asset, _sec)) in spent_utxo_secrets.iter().enumerate(){ - if asset.is_null() { - return Err(ConfidentialTxOutError::TxOutError(i, TxOutError::UnExpectedNullAsset)); - } - } - let (surjection_proof_inputs, value_blind_inputs) = spent_utxo_secrets + + let out_abf = AssetBlindingFactor::new(rng); + let ephemeral_sk = SecretKey::new(rng); + + let (txout, out_vbf) = TxOut::with_secrets_last( + rng, secp, value, spk, blinder, asset, ephemeral_sk, out_abf, spent_utxo_secrets, output_secrets + )?; + Ok((txout, out_abf, out_vbf, ephemeral_sk)) + } + + /// Similar to [TxOut::new_last_confidential], but allows specifying the asset blinding factor + /// and the ephemeral key. The value-blinding factor is computed adaptively + pub fn with_secrets_last( + rng: &mut R, + secp: &Secp256k1, + value: u64, + spk: Script, + blinder: secp256k1_zkp::PublicKey, + asset: AssetId, + ephemeral_sk: SecretKey, + out_abf: AssetBlindingFactor, + spent_utxo_secrets: &[TxOutSecrets], + output_secrets: &[&TxOutSecrets], + ) -> Result<(Self, ValueBlindingFactor), ConfidentialTxOutError> + where + R: RngCore + CryptoRng, + C: Signing, + { + + let value_blind_inputs = spent_utxo_secrets .iter() - .map(|(asset, sec)| { - let gen = asset.into_asset_gen(secp).expect("Null"); - ((gen, sec.asset.into_tag(), sec.asset_bf.0), (sec.value_blind_inputs())) - }) - .unzip::<_, _, Vec<_>, Vec<_>>(); + .map(|utxo_sec| utxo_sec.value_blind_inputs()) + .collect::>(); let value_blind_outputs = output_secrets .iter() .map(|e| e.value_blind_inputs()) .collect::>(); - let out_abf = AssetBlindingFactor::new(rng); - let out_asset = Asset::new_confidential(secp, asset, out_abf); - - let out_asset_commitment = out_asset.commitment().expect("confidential asset"); let out_vbf = ValueBlindingFactor::last(secp, value, out_abf, &value_blind_inputs, &value_blind_outputs); - let value_commitment = Value::new_confidential(secp, value, out_asset_commitment, out_vbf); - - let receiver_blinding_pk = &address - .blinding_pubkey - .ok_or(ConfidentialTxOutError::NoBlindingKeyInAddress)?; - let (nonce, shared_secret) = Nonce::new_confidential(rng, secp, receiver_blinding_pk); - - let message = RangeProofMessage { asset, bf: out_abf }; - let rangeproof = RangeProof::new( - secp, - Self::RANGEPROOF_MIN_VALUE, - value_commitment.commitment().expect("confidential value"), - value, - out_vbf.0, - &message.to_bytes(), - address.script_pubkey().as_bytes(), - shared_secret, - Self::RANGEPROOF_EXP_SHIFT, - Self::RANGEPROOF_MIN_PRIV_BITS, - out_asset_commitment, - )?; + let out_secrets = TxOutSecrets::new(asset, out_abf, value, out_vbf); + let txout = + TxOut::with_txout_secrets(rng, secp, spk, blinder, ephemeral_sk, out_secrets, spent_utxo_secrets)?; - let surjection_proof = SurjectionProof::new( - secp, - rng, - asset.into_tag(), - out_abf.into_inner(), - surjection_proof_inputs.as_ref(), - )?; - - let txout = TxOut { - asset: out_asset, - value: value_commitment, - nonce, - script_pubkey: address.script_pubkey(), - witness: TxOutWitness { - surjection_proof: Some(Box::new(surjection_proof)), - rangeproof: Some(Box::new(rangeproof)), - }, - }; - - Ok((txout, out_abf, out_vbf)) + Ok((txout, out_vbf)) } /// Unblinds a transaction output, if it is confidential. @@ -731,8 +865,8 @@ impl Transaction { &mut self, rng: &mut R, secp: &Secp256k1, - spent_utxo_secrets: &[(Asset, &TxOutSecrets)], - ) -> Result, BlindError> + spent_utxo_secrets: &[TxOutSecrets], + ) -> Result, BlindError> where R: RngCore + CryptoRng, C: Signing, @@ -752,35 +886,31 @@ impl Transaction { .filter(|i| !i.is_fee() && i.nonce.is_confidential()) .count(); let mut num_blinded = 0; - let mut blinds = Vec::new(); + let mut blinds = BTreeMap::new(); let mut out_secrets = Vec::new(); let mut last_output_index = None; for (i, out) in self.output.iter_mut().enumerate() { if out.is_fee() || !out.nonce.is_confidential() { - let abf = AssetBlindingFactor::zero(); - let vbf = ValueBlindingFactor::zero(); out_secrets.push( TxOutSecrets::new( out.asset.explicit().unwrap(), - abf, + AssetBlindingFactor::zero(), out.value.explicit().unwrap(), - vbf, + ValueBlindingFactor::zero(), )); - blinds.push((abf, vbf)); continue; } - let opt_utxo_secrets : Vec<_> = spent_utxo_secrets.iter().map(|(a, sec)| (*a, Some(*sec))).collect(); let blinder = out.nonce.commitment().expect("Confidential"); let address = Address::from_script(&out.script_pubkey, Some(blinder), &AddressParams::ELEMENTS) .ok_or(BlindError::InvalidAddress)?; if num_blinded + 1 < num_to_blind { - let (conf_out, abf, vbf) = TxOut::new_not_last_confidential( - rng, secp, out.value.explicit().unwrap(), address, out.asset.explicit().unwrap(), &opt_utxo_secrets + let (conf_out, abf, vbf, ephemeral_sk) = TxOut::new_not_last_confidential( + rng, secp, out.value.explicit().unwrap(), address, out.asset.explicit().unwrap(), &spent_utxo_secrets )?; - blinds.push((abf, vbf)); + blinds.insert(i, (abf, vbf, ephemeral_sk)); out_secrets.push( TxOutSecrets::new( out.asset.explicit().unwrap(), @@ -797,23 +927,24 @@ impl Transaction { } let last_index = last_output_index.expect("Internal output calculation error"); // NLL block - let (value, asset, address) = { + let (value, asset, spk, blinder) = { let out = &self.output[last_index]; let blinder = out.nonce.commitment().expect("Confidential"); ( out.value.explicit().unwrap(), out.asset.explicit().unwrap(), - Address::from_script(&out.script_pubkey, Some(blinder), &AddressParams::ELEMENTS) - .ok_or(BlindError::InvalidAddress)? + out.script_pubkey.clone(), // TODO: Possible to avoid this clone in future with _mut APIs + blinder ) }; // Get Vec<&T> from Vec let out_secrets = out_secrets.iter().collect::>(); - let (conf_out, abf, vbf) = TxOut::new_last_confidential( - rng, secp, value, address, asset, spent_utxo_secrets, &out_secrets)?; + let (conf_out, abf, vbf, ephemeral_sk) = TxOut::new_last_confidential( + rng, secp, value, asset, spk, blinder, spent_utxo_secrets, &out_secrets + )?; - blinds.push((abf, vbf)); + blinds.insert(last_index, (abf, vbf, ephemeral_sk)); self.output[last_index] = conf_out; Ok(blinds) } @@ -1026,8 +1157,7 @@ mod tests { } let secp = secp256k1_zkp::Secp256k1::new(); - let spent_asset = Asset::from_commitment(&Vec::::from_hex("0baf634b18e1880c96dcf9947b0e0fd2d38d66d723339174df3fd980148c2f0bb3").unwrap()).unwrap(); - let _bfs = tx.blind(&mut thread_rng(), &secp, &[(spent_asset, &spent_utxo_secrets)]).unwrap(); + let _bfs = tx.blind(&mut thread_rng(), &secp, &[spent_utxo_secrets]).unwrap(); let spent_utxo = TxOut { asset: Asset::from_commitment(&Vec::::from_hex("0baf634b18e1880c96dcf9947b0e0fd2d38d66d723339174df3fd980148c2f0bb3").unwrap()).unwrap(), @@ -1070,7 +1200,6 @@ mod tests { let asset = AssetId::default(); let asset_bf = AssetBlindingFactor::new(&mut thread_rng()); - let asset_commitment = Asset::new_confidential(SECP256K1, asset, asset_bf); let value_bf = ValueBlindingFactor::new(&mut thread_rng()); /*let spent_utxo_secrets = &[( asset, @@ -1080,9 +1209,9 @@ mod tests { input_vbf, )]; */ let txout_secrets = TxOutSecrets { asset, asset_bf, value, value_bf}; - let spent_utxo_secrets = [(asset_commitment, Some(&txout_secrets))]; + let spent_utxo_secrets = [txout_secrets]; - let (txout, _, _) = TxOut::new_not_last_confidential( + let (txout, _, _, _) = TxOut::new_not_last_confidential( &mut thread_rng(), SECP256K1, value, diff --git a/src/confidential.rs b/src/confidential.rs index 13fadd5a..0116c736 100644 --- a/src/confidential.rs +++ b/src/confidential.rs @@ -516,11 +516,19 @@ impl Nonce { secp: &Secp256k1, receiver_blinding_pk: &PublicKey, ) -> (Self, SecretKey) { - let sender_sk = SecretKey::new(rng); - let sender_pk = PublicKey::from_secret_key(&secp, &sender_sk); - - let shared_secret = Self::make_shared_secret(receiver_blinding_pk, &sender_sk); + let ephemeral_sk = SecretKey::new(rng); + Self::with_ephemeral_sk(secp, ephemeral_sk, receiver_blinding_pk) + } + /// Similar to [Nonce::new_confidential], but with a given `ephemeral_sk` + /// instead of sampling it from rng. + pub fn with_ephemeral_sk( + secp: &Secp256k1, + ephemeral_sk: SecretKey, + receiver_blinding_pk: &PublicKey + ) -> (Self, SecretKey) { + let sender_pk = PublicKey::from_secret_key(&secp, &ephemeral_sk); + let shared_secret = Self::make_shared_secret(receiver_blinding_pk, &ephemeral_sk); (Nonce::Confidential(sender_pk), shared_secret) } diff --git a/src/lib.rs b/src/lib.rs index 9ccbff53..231e29a6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -65,7 +65,7 @@ pub use bitcoin::{bech32, hashes}; // export everything at the top level so it can be used as `elements::Transaction` etc. pub use crate::address::{Address, AddressParams, AddressError}; pub use crate::transaction::{OutPoint, PeginData, PegoutData, EcdsaSigHashType, TxIn, TxOut, TxInWitness, TxOutWitness, Transaction, AssetIssuance}; -pub use crate::blind::{ConfidentialTxOutError, TxOutSecrets, TxOutError, VerificationError, BlindError, UnblindError, BlindValueProofs, BlindAssetProofs}; +pub use crate::blind::{ConfidentialTxOutError, TxOutSecrets, SurjectionInput, TxOutError, VerificationError, BlindError, UnblindError, BlindValueProofs, BlindAssetProofs}; pub use crate::block::{BlockHeader, Block}; pub use crate::block::ExtData as BlockExtData; pub use ::bitcoin::consensus::encode::VarInt; diff --git a/src/pset/map/input.rs b/src/pset/map/input.rs index dd1481d6..7bcd146d 100644 --- a/src/pset/map/input.rs +++ b/src/pset/map/input.rs @@ -15,7 +15,7 @@ use std::fmt; use std::{cmp, collections::btree_map::{BTreeMap, Entry}, io, str::FromStr}; -use crate::schnorr; +use crate::{schnorr, AssetId, ContractHash}; use crate::taproot::{ControlBlock, LeafVersion, TapLeafHash, TapBranchHash}; use crate::{Script, AssetIssuance, EcdsaSigHashType, Transaction, Txid, TxOut, TxIn, BlockHash}; @@ -427,9 +427,33 @@ impl Input{ ret } + /// Compute the issuance asset ids from pset. This function does not check + /// whether there is an issuance in this input. Returns (asset_id, token_id) + pub fn issuance_ids(&self) -> (AssetId, AssetId) { + let issue_nonce = self.issuance_blinding_nonce.unwrap_or(ZERO_TWEAK); + let entropy = if issue_nonce == ZERO_TWEAK { + // new issuance + let prevout = OutPoint { + txid: self.previous_txid, + vout: self.previous_output_index, + }; + let contract_hash = + ContractHash::from_inner(self.issuance_asset_entropy.unwrap_or_default()); + AssetId::generate_asset_entropy(prevout, contract_hash) + } else { + // re-issuance + sha256::Midstate::from_inner(self.issuance_asset_entropy.unwrap_or_default()) + }; + let asset_id = AssetId::from_entropy(entropy); + let token_id = + AssetId::reissuance_token_from_entropy(entropy, self.issuance_value_comm.is_some()); + + (asset_id, token_id) + } + /// If the pset input has issuance pub fn has_issuance(&self) -> bool { - self.previous_output_index & (1 << 31) != 0 + !self.asset_issuance().is_null() } /// If the Pset Input is pegin diff --git a/src/pset/mod.rs b/src/pset/mod.rs index e98b187b..79d4f3ca 100644 --- a/src/pset/mod.rs +++ b/src/pset/mod.rs @@ -20,6 +20,7 @@ //! Extension for PSET is based on PSET defined in BIP370. //! https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki +use std::collections::HashMap; use std::{cmp, io}; mod error; @@ -29,16 +30,13 @@ mod map; pub mod raw; pub mod serialize; -use crate::{Transaction, Txid, TxIn, OutPoint, TxInWitness, TxOut, TxOutWitness}; +use crate::{Transaction, Txid, TxIn, OutPoint, TxInWitness, TxOut, TxOutWitness, SurjectionInput}; use crate::encode::{self, Encodable, Decodable}; use crate::confidential; use secp256k1_zkp::rand::{CryptoRng, RngCore}; -use secp256k1_zkp::{self, RangeProof, SurjectionProof}; +use secp256k1_zkp::{self, RangeProof, SurjectionProof, SecretKey}; use crate::{TxOutSecrets, blind::RangeProofMessage, confidential::{AssetBlindingFactor, ValueBlindingFactor}}; use bitcoin; - -use crate::blind::ConfidentialTxOutError; - use crate::blind::{BlindAssetProofs, BlindValueProofs}; pub use self::error::{Error, PsetBlindError}; @@ -316,7 +314,7 @@ impl PartiallySignedTransaction { // Common pset blinding checks fn blind_checks( &self, - inp_txout_sec: &[Option<&TxOutSecrets>], + inp_txout_sec: &HashMap, ) -> Result< ( Vec<(u64, AssetBlindingFactor, ValueBlindingFactor)>, @@ -324,9 +322,6 @@ impl PartiallySignedTransaction { ), PsetBlindError, > { - if inp_txout_sec.len() != self.inputs.len() { - return Err(PsetBlindError::InputTxOutSecretLen); - } let mut blind_out_indices = Vec::new(); for (i, out) in self.outputs.iter().enumerate() { @@ -340,7 +335,7 @@ impl PartiallySignedTransaction { i, blind_index as usize, )); - } else if inp_txout_sec[blind_index as usize].is_none() { + } else if inp_txout_sec.get(&(blind_index as usize)).is_none() { //nothing } else { // Output has corresponding input blinders @@ -352,14 +347,57 @@ impl PartiallySignedTransaction { // collect input factors let inp_secrets = inp_txout_sec .iter() - .filter(|o| o.is_some()) - .map(|o| o.unwrap()) - .map(|o| (o.value, o.asset_bf, o.value_bf)) + .map(|(_i, sec)| (sec.value, sec.asset_bf, sec.value_bf)) .collect::>(); Ok((inp_secrets, blind_out_indices)) } + /// Obtains the surjection inputs for this pset. This servers as the domain + /// when creating a new [`SurjectionProof`]. Informally, the domain refers to the + /// set of inputs assets. For inputs whose [`TxOutSecrets`] is supplied, + /// [`SurjectionInput::Known`] variant is created. For confidential inputs whose secrets + /// are not supplied [`SurjectionInput::Unknown`] variant is created. + /// For non-confidential inputs, [`SurjectionInput::Known`] variant is created with zero + /// blinding factors. + pub fn surjection_inputs( + &self, + inp_txout_sec: &HashMap, + ) -> Result, PsetBlindError> { + let mut ret = vec![]; + for (i ,inp) in self.inputs().iter().enumerate() { + let utxo = inp.witness_utxo.as_ref().ok_or(PsetBlindError::MissingWitnessUtxo(i))?; + let surject_target = match inp_txout_sec.get(&i) { + Some(sec) => SurjectionInput::from_txout_secrets(*sec), + None => SurjectionInput::Unknown(utxo.asset), + }; + ret.push(surject_target); + + if inp.has_issuance(){ + let (asset_id, token_id) = inp.issuance_ids(); + if inp.issuance_value_amount.is_some() || inp.issuance_value_comm.is_some() { + let secrets = TxOutSecrets{ + asset: asset_id, + asset_bf: AssetBlindingFactor::zero(), + value: 0, // This value really does not matter in surjection proofs + value_bf: ValueBlindingFactor::zero(), + }; + ret.push(SurjectionInput::from_txout_secrets(secrets)) + } + if inp.issuance_inflation_keys.is_some() || inp.issuance_inflation_keys_comm.is_some() { + let secrets = TxOutSecrets{ + asset: token_id, + asset_bf: AssetBlindingFactor::zero(), + value: 0, // This value really does not matter in surjection proofs + value_bf: ValueBlindingFactor::zero(), + }; + ret.push(SurjectionInput::from_txout_secrets(secrets)) + } + } + } + Ok(ret) + } + /// Blind the pset as the non-last blinder role. The last blinder of pset /// should call the `blind_last` function which balances the blinding factors /// `inp_secrets` and must be consistent by [`Output`] `blinder_index` field @@ -374,7 +412,7 @@ impl PartiallySignedTransaction { &mut self, rng: &mut R, secp: &secp256k1_zkp::Secp256k1, - inp_txout_sec: &[Option<&TxOutSecrets>], + inp_txout_sec: &HashMap, ) -> Result, PsetBlindError> { let (inp_secrets, outs_to_blind) = self.blind_checks(inp_txout_sec)?; @@ -383,23 +421,12 @@ impl PartiallySignedTransaction { return Ok(Vec::new()); } // Blind each output as non-last and save the secrets - let spent_utxos = self - .inputs - .iter() - .enumerate() - .map(|(i, x)| x.witness_utxo.as_ref().ok_or(PsetBlindError::MissingWitnessUtxo(i))) - .collect::, _>>()?; - - let spent_utxo_secrets = spent_utxos - .iter() - .map(|x| x.asset) - .zip(inp_txout_sec.iter().map(|x| *x)) - .collect::>(); + let surject_inputs = self.surjection_inputs(inp_txout_sec)?; let mut out_secrets = vec![]; let mut ret = vec![]; // return all the random values used for i in outs_to_blind { - let mut txout = self.outputs[i].to_txout(); - let (abf, vbf) = txout + let txout = self.outputs[i].to_txout(); + let (txout, abf, vbf, _) = txout .to_non_last_confidential( rng, secp, @@ -407,7 +434,7 @@ impl PartiallySignedTransaction { .blinding_key .map(|x| x.inner) .ok_or(PsetBlindError::MustHaveExplicitTxOut(i))?, - &spent_utxo_secrets, + &surject_inputs, ) .map_err(|e| PsetBlindError::ConfidentialTxOutError(i, e))?; let value = self.outputs[i].amount.ok_or(PsetBlindError::MustHaveExplicitTxOut(i))?; @@ -473,7 +500,7 @@ impl PartiallySignedTransaction { &mut self, rng: &mut R, secp: &secp256k1_zkp::Secp256k1, - inp_txout_sec: &[Option<&TxOutSecrets>], + inp_txout_sec: &HashMap, ) -> Result<(), PsetBlindError> { let (mut inp_secrets, mut outs_to_blind) = self.blind_checks(inp_txout_sec)?; @@ -497,12 +524,18 @@ impl PartiallySignedTransaction { inp_secrets = vec![]; } // blind the last txout - let asset = self.outputs[last_out_index].asset.ok_or(PsetBlindError::MustHaveExplicitTxOut(last_out_index))?; - let value = self.outputs[last_out_index].amount.ok_or(PsetBlindError::MustHaveExplicitTxOut(last_out_index))?; + + let surject_inputs = self.surjection_inputs(inp_txout_sec)?; + let asset_id = self.outputs[last_out_index].asset.ok_or(PsetBlindError::MustHaveExplicitTxOut(last_out_index))?; let out_abf = AssetBlindingFactor::new(rng); - let out_asset = confidential::Asset::new_confidential(secp, asset, out_abf); - let out_asset_commitment = out_asset.commitment().expect("confidential asset"); + let exp_asset = confidential::Asset::Explicit(asset_id); + let blind_res = exp_asset.blind(rng, secp, out_abf, &surject_inputs); + + let (out_asset_commitment, surjection_proof) = blind_res + .map_err(|e| PsetBlindError::ConfidentialTxOutError(last_out_index, e))?; + let value = self.outputs[last_out_index].amount.ok_or(PsetBlindError::MustHaveExplicitTxOut(last_out_index))?; + let exp_value = confidential::Value::Explicit(value); // Get all the explicit outputs let mut exp_out_secrets = vec![]; for (i, out) in self.outputs.iter().enumerate() { @@ -523,67 +556,24 @@ impl PartiallySignedTransaction { for value_diff in self.global.scalars.iter() { final_vbf += ValueBlindingFactor(*value_diff); } - let value_commitment = confidential::Value::new_confidential(secp, value, out_asset_commitment, final_vbf); - - let value_commitment = value_commitment.commitment().expect("confidential value"); let receiver_blinding_pk = &self.outputs[last_out_index] .blinding_key .ok_or(PsetBlindError::MustHaveExplicitTxOut(last_out_index))?; - let (nonce, shared_secret) = confidential::Nonce::new_confidential(rng, secp, &receiver_blinding_pk.inner); - - let message = RangeProofMessage { asset, bf: out_abf }; - let rangeproof = RangeProof::new( - secp, - TxOut::RANGEPROOF_MIN_VALUE, - value_commitment, - value, - final_vbf.0, - &message.to_bytes(), - self.outputs[last_out_index].script_pubkey.as_bytes().as_ref(), - shared_secret, - TxOut::RANGEPROOF_EXP_SHIFT, - TxOut::RANGEPROOF_MIN_PRIV_BITS, - out_asset_commitment, - ).map_err(|e| PsetBlindError::ConfidentialTxOutError(last_out_index, ConfidentialTxOutError::Upstream(e)))?; - - // Blind each output as non-last and save the secrets - let spent_utxos = self - .inputs - .iter() - .enumerate() - .map(|(i, x)| x.witness_utxo.as_ref().ok_or(PsetBlindError::MissingWitnessUtxo(i))) - .collect::, _>>()?; - - let spent_utxo_secrets = spent_utxos - .iter() - .map(|x| x.asset) - .zip(inp_txout_sec.iter().map(|x| *x)) - .collect::>(); - - let inputs = spent_utxo_secrets - .iter() - .enumerate() - .map(|(i, (asset, sec))| { - TxOutSecrets::surjection_inputs(*sec, secp, *asset) - .map_err(|_e| PsetBlindError::MissingInputBlinds(last_out_index, i)) - }) - .collect::, _>>()?; - - let surjection_proof = SurjectionProof::new( - secp, - rng, - asset.into_tag(), - out_abf.into_inner(), - inputs.as_ref(), - ).map_err(|e| PsetBlindError::ConfidentialTxOutError(last_out_index, ConfidentialTxOutError::Upstream(e)))?; + let ephemeral_sk = SecretKey::new(rng); + let spk = &self.outputs[last_out_index].script_pubkey; + let msg = RangeProofMessage { asset: asset_id, bf: out_abf }; + let blind_res = + exp_value.blind(secp, final_vbf, receiver_blinding_pk.inner, ephemeral_sk, spk, &msg); + let (value_commitment, nonce, rangeproof) = blind_res + .map_err(|e| PsetBlindError::ConfidentialTxOutError(last_out_index, e))?; // mutate the pset { self.outputs[last_out_index].value_rangeproof = Some(Box::new(rangeproof)); self.outputs[last_out_index].asset_surjection_proof = Some(Box::new(surjection_proof)); - self.outputs[last_out_index].amount_comm = Some(value_commitment); - self.outputs[last_out_index].asset_comm = Some(out_asset_commitment); + self.outputs[last_out_index].amount_comm = value_commitment.commitment(); + self.outputs[last_out_index].asset_comm = out_asset_commitment.commitment(); self.outputs[last_out_index].ecdh_pubkey = nonce.commitment().map(|pk| bitcoin::PublicKey{ inner: pk, compressed: true @@ -757,9 +747,8 @@ mod tests { asset: AssetId::from_hex(&v["asset"].as_str().unwrap()).unwrap(), }; - let inp_txout_sec = [ - Some(&btc_txout_secrets), - ]; + let mut inp_txout_sec = HashMap::new(); + inp_txout_sec.insert(0, btc_txout_secrets); pset.blind_last(&mut rng, &secp, &inp_txout_sec).unwrap(); let tx = pset.extract_tx().unwrap(); From 3107c253ed03b9e3bf5c7816b4dacc378fe119c5 Mon Sep 17 00:00:00 2001 From: sanket1729 Date: Wed, 3 Aug 2022 18:25:25 -0700 Subject: [PATCH 3/9] Add support for issuance Issuances are still not blinded in pset. We can add another parameter to Pset::blind_last and Pset::blind_non_last, but it is add another parameter to the API. We can implement this in future if required. --- src/blind.rs | 161 +++++++++++++++++++++++++++++++++++++++------ src/pset/mod.rs | 4 ++ src/transaction.rs | 24 ++++++- tests/taproot.rs | 3 +- 4 files changed, 168 insertions(+), 24 deletions(-) diff --git a/src/blind.rs b/src/blind.rs index 6915a94c..05a8e188 100644 --- a/src/blind.rs +++ b/src/blind.rs @@ -20,7 +20,7 @@ use std::{self, fmt, collections::BTreeMap}; use secp256k1_zkp::{self, PedersenCommitment, SecretKey, Tag, Tweak, Verification, ZERO_TWEAK, rand::{CryptoRng, RngCore}}; use secp256k1_zkp::{Generator, RangeProof, Secp256k1, Signing, SurjectionProof}; -use crate::{AddressParams, Script}; +use crate::{AddressParams, Script, TxIn}; use crate::{Address, AssetId, Transaction, TxOut, TxOutWitness, confidential::{Asset, AssetBlindingFactor, Nonce, Value, @@ -367,6 +367,7 @@ impl Asset { impl Value { /// Blinds the values and outputs the blinded value along with [`RangeProof`]. + /// This computes the nonce by doing an ECDH with `receiver_blinding_pk` and `ephemeral_sk` /// /// # Returns: /// @@ -381,13 +382,29 @@ impl Value { spk: &Script, msg: &RangeProofMessage, ) -> Result<(Self, Nonce, RangeProof), ConfidentialTxOutError> + { + let (nonce, shared_secret) = Nonce::with_ephemeral_sk(secp, ephemeral_sk, &receiver_blinding_pk); + + let (value_commit, rangeproof) = self.blind_with_shared_secret(secp, vbf, shared_secret, spk, msg)?; + Ok((value_commit, nonce, rangeproof)) + } + + /// Blinds with the given shared_secret(instead of computing it via ECDH) + /// This is useful while blinding assets as there is no counter party to provide + /// the blinding key. + pub fn blind_with_shared_secret( + self, + secp: &Secp256k1, + vbf: ValueBlindingFactor, + shared_secret: SecretKey, + spk: &Script, + msg: &RangeProofMessage, + ) -> Result<(Self, RangeProof), ConfidentialTxOutError> { let value = self.explicit().ok_or(ConfidentialTxOutError::ExpectedExplicitValue)?; let out_asset_commitment = Generator::new_blinded(secp, msg.asset.into_tag(), msg.bf.into_inner()); let value_commitment = Value::new_confidential(secp, value, out_asset_commitment, vbf); - let (nonce, shared_secret) = Nonce::with_ephemeral_sk(secp, ephemeral_sk, &receiver_blinding_pk); - let rangeproof = RangeProof::new( secp, TxOut::RANGEPROOF_MIN_VALUE, @@ -401,7 +418,7 @@ impl Value { TxOut::RANGEPROOF_MIN_PRIV_BITS, out_asset_commitment, )?; - Ok((value_commitment, nonce, rangeproof)) + Ok((value_commitment, rangeproof)) } } @@ -501,7 +518,7 @@ impl TxOut { } /// Convert a explicit TxOut into a Confidential TxOut. - /// The blinding key is provided by the blinder paramter. + /// The blinding key is provided by the blinder parameter. /// The initial value of nonce is ignored and is set to the ECDH pubkey /// sampled by the sender. /// @@ -578,6 +595,11 @@ impl TxOut { /// Creates a new confidential output that IS the last one in the transaction. /// + /// Inputs for issuances must be provided in the followed by inputs for input asset. + /// For example, if the second input contains non-null issuance and re-issuance tokens, + /// the `spent_utxo_secrets` should be of the form [inp_1, inp_2, inp_2_issue, inp2_reissue,...] + /// If the issuance or re-issuance is null, it should not be added to `spent_utxo_secrets` + /// /// # Returns: /// /// A tuple of ([`AssetBlindingFactor`], [`ValueBlindingFactor`], ephemeral secret key [`SecretKey`]) @@ -742,6 +764,77 @@ impl From for UnblindError { } } +impl TxIn { + + /// Blind issuances for this [`TxIn`]. Asset amount and token amount must be + /// set in [`AssetIssuance`](crate::AssetIssuance) field for this input + pub fn blind_issuances_with_bfs( + &mut self, + secp: &Secp256k1, + issue_vbf: ValueBlindingFactor, + token_vbf: ValueBlindingFactor, + issue_sk: SecretKey, + token_sk: SecretKey, + ) -> Result<(), BlindError> { + if !self.has_issuance() { + return Err(BlindError::NoIssuanceToBlind); + } + let (asset_id, token_id) = self.issuance_ids(); + let arr = vec![ + (issue_vbf, self.asset_issuance.amount, issue_sk, asset_id), + (token_vbf, self.asset_issuance.inflation_keys, token_sk, token_id) + ]; + for (i, (bf, amt, blind_sk, asset)) in arr.into_iter().enumerate() { + let v = match amt { + Value::Null => continue, // nothing to blind + Value::Explicit(0) => return Err(BlindError::ZeroValueBlindingNotAllowed), + Value::Confidential(_) => return Err(BlindError::IssuanceAmountMustBeExplicit), + Value::Explicit(v) => Value::Explicit(v) + }; + let spk = Script::new(); + let msg = RangeProofMessage { asset, bf: AssetBlindingFactor::zero() }; + let (comm, prf) = v.blind_with_shared_secret(secp, bf, blind_sk, &spk, &msg)?; + if i == 0 { + self.asset_issuance.amount = comm; + self.witness.amount_rangeproof = Some(Box::new(prf)); + } else { + self.asset_issuance.inflation_keys = comm; + self.witness.inflation_keys_rangeproof = Some(Box::new(prf)); + } + } + Ok(()) + } + + /// Blind issuances for this [`TxIn`]. Asset amount and token amount must be + /// set in [`AssetIssuance`](crate::AssetIssuance) field for this input + /// + /// Returns (issuance_blinding_factor, issue_blind_sec_key, token_blinding_factor, token_blind_sec_key) + pub fn blind_issuances( + &mut self, + secp: &Secp256k1, + rng: &mut R, + ) -> Result<(ValueBlindingFactor, SecretKey, ValueBlindingFactor, SecretKey), BlindError> { + + let issue_vbf = ValueBlindingFactor::new(rng); + let token_vbf = ValueBlindingFactor::new(rng); + let issue_sk = SecretKey::new(rng); + let token_sk = SecretKey::new(rng); + self.blind_issuances_with_bfs(secp, issue_vbf, token_vbf, issue_sk, token_sk)?; + Ok((issue_vbf, issue_sk, token_vbf, token_sk)) + } +} + +/// Data structure for Unifying inputs and pseudo-inputs. +#[derive(Debug, Clone, Copy, Ord, PartialOrd, Eq, PartialEq, Hash)] +pub enum TxInType{ + /// Regular input + Input(usize), + /// Issuance Pseudo-input + Issuance(usize), + /// Re-issuance pseudo-input + ReIssuance(usize), +} + impl Transaction { /// Verify that the transaction has correctly calculated blinding /// factors and they CT verification equation holds. @@ -802,13 +895,28 @@ impl Transaction { let mut in_commits = vec![]; let mut out_commits = vec![]; for (i, inp) in self.input.iter().enumerate() { - if inp.has_issuance() { - return Err(VerificationError::IssuanceTransactionInput(i)); - } in_commits.push( spent_utxos[i].get_value_commit(secp) .map_err(|e| VerificationError::SpentTxOutError(i, e))? ); + if inp.has_issuance() { + let (asset_id, token_id) = inp.issuance_ids(); + let arr = [ + (inp.asset_issuance.amount, asset_id), + (inp.asset_issuance.inflation_keys, token_id), + ]; + for (amt, asset) in arr.iter() { + match amt { + Value::Null => continue, + Value::Explicit(v) => { + let gen = Generator::new_unblinded(secp, asset.into_tag()); + let comm = PedersenCommitment::new_unblinded(secp, *v, gen); + in_commits.push(comm) + }, + Value::Confidential(comm) => in_commits.push(*comm), + } + } + } } let domain = spent_utxos @@ -866,14 +974,24 @@ impl Transaction { rng: &mut R, secp: &Secp256k1, spent_utxo_secrets: &[TxOutSecrets], - ) -> Result, BlindError> + blind_issuances: bool, + ) -> Result, BlindError> where R: RngCore + CryptoRng, C: Signing, { + let mut blinds = BTreeMap::new(); // Blinding Issuances unsupported - if self.input.iter().any(|i| i.has_issuance()) { - return Err(BlindError::IssuanceUnsupported) + for (i, txin) in self.input.iter_mut().enumerate() { + if txin.has_issuance() && blind_issuances { + let (iss_vbf, iss_sk, tkn_vbf, tkn_sk) = txin.blind_issuances(secp, rng)?; + if txin.asset_issuance.amount.is_confidential() { + blinds.insert(TxInType::Issuance(i), (AssetBlindingFactor::zero(), iss_vbf, iss_sk)); + } + if txin.asset_issuance.inflation_keys.is_confidential() { + blinds.insert(TxInType::ReIssuance(i), (AssetBlindingFactor::zero(), tkn_vbf, tkn_sk)); + } + } } // Everything must be explicit if !self.output.iter().all(|o| o.asset.is_explicit() && o.value.is_explicit()) { @@ -886,7 +1004,6 @@ impl Transaction { .filter(|i| !i.is_fee() && i.nonce.is_confidential()) .count(); let mut num_blinded = 0; - let mut blinds = BTreeMap::new(); let mut out_secrets = Vec::new(); let mut last_output_index = None; for (i, out) in self.output.iter_mut().enumerate() { @@ -910,7 +1027,7 @@ impl Transaction { rng, secp, out.value.explicit().unwrap(), address, out.asset.explicit().unwrap(), &spent_utxo_secrets )?; - blinds.insert(i, (abf, vbf, ephemeral_sk)); + blinds.insert(TxInType::Input(i), (abf, vbf, ephemeral_sk)); out_secrets.push( TxOutSecrets::new( out.asset.explicit().unwrap(), @@ -944,7 +1061,7 @@ impl Transaction { rng, secp, value, asset, spk, blinder, spent_utxo_secrets, &out_secrets )?; - blinds.insert(last_index, (abf, vbf, ephemeral_sk)); + blinds.insert(TxInType::Input(last_index), (abf, vbf, ephemeral_sk)); self.output[last_index] = conf_out; Ok(blinds) } @@ -957,14 +1074,18 @@ pub enum BlindError { /// This is not a fundamental limitation, just a limitation of how /// the code API is structured InvalidAddress, - /// Issuance unsupported - IssuanceUnsupported, /// Too few blinding inputs TooFewBlindingOutputs, /// All outputs must be explicit asset/amounts MustHaveAllExplicitTxOuts, /// General TxOut errors ConfidentialTxOutError(ConfidentialTxOutError), + /// No Issuances to blind in this TxIn + NoIssuanceToBlind, + /// Zero Value Blinding not allowed + ZeroValueBlindingNotAllowed, + /// Issuance Amount must be explicit + IssuanceAmountMustBeExplicit, } impl fmt::Display for BlindError { @@ -974,9 +1095,6 @@ impl fmt::Display for BlindError { write!(f, "Only sending to valid addresses is supported as of now. \ Manually construct transactions to send to custom script pubkeys") } - BlindError::IssuanceUnsupported => { - write!(f, "Transactions containing issuances unsupported") - } BlindError::TooFewBlindingOutputs => { write!(f, "Transactions must have atleast confidential outputs \ marked for blinding. To mark a output for blinding set nonce field\ @@ -988,6 +1106,9 @@ impl fmt::Display for BlindError { BlindError::ConfidentialTxOutError(e) => { write!(f, "{}", e) } + BlindError::NoIssuanceToBlind => write!(f, "No Issuance present"), + BlindError::ZeroValueBlindingNotAllowed => write!(f, "Zero value blinding is not allowed"), + BlindError::IssuanceAmountMustBeExplicit => write!(f, "Issuance amount must be explicit to blind"), } } } @@ -1157,7 +1278,7 @@ mod tests { } let secp = secp256k1_zkp::Secp256k1::new(); - let _bfs = tx.blind(&mut thread_rng(), &secp, &[spent_utxo_secrets]).unwrap(); + let _bfs = tx.blind(&mut thread_rng(), &secp, &[spent_utxo_secrets], false).unwrap(); let spent_utxo = TxOut { asset: Asset::from_commitment(&Vec::::from_hex("0baf634b18e1880c96dcf9947b0e0fd2d38d66d723339174df3fd980148c2f0bb3").unwrap()).unwrap(), diff --git a/src/pset/mod.rs b/src/pset/mod.rs index 79d4f3ca..595fcd08 100644 --- a/src/pset/mod.rs +++ b/src/pset/mod.rs @@ -404,10 +404,14 @@ impl PartiallySignedTransaction { /// For each output that is to be blinded, the following must be true /// 1. The blinder_index must be set in pset output field /// 2. the corresponding inp_secrets\[out.blinder_index\] must be present + /// + /// Issuances and re-issuance inputs are not blinded. /// # Parameters /// /// * `inp_secrets`: [`TxOutSecrets`] corresponding to owned inputs. Use [`None`] for non-owned outputs /// + // Blinding issuances is not currently supported. We have no way in pset to specify + // which issuances we want to blind pub fn blind_non_last( &mut self, rng: &mut R, diff --git a/src/transaction.rs b/src/transaction.rs index de509f33..5194611f 100644 --- a/src/transaction.rs +++ b/src/transaction.rs @@ -19,16 +19,16 @@ use std::{io, fmt, str}; use std::collections::HashMap; use bitcoin::{self, VarInt}; -use bitcoin::hashes::Hash; +use crate::hashes::{Hash, sha256}; -use crate::confidential; +use crate::{confidential, ContractHash}; use crate::encode::{self, Encodable, Decodable}; use crate::issuance::AssetId; use crate::opcodes; use crate::script::Instruction; use crate::{Script, Txid, Wtxid}; use secp256k1_zkp::{ - RangeProof, SurjectionProof, Tweak, + RangeProof, SurjectionProof, Tweak, ZERO_TWEAK, }; /// Description of an asset issuance in a transaction input @@ -358,6 +358,24 @@ impl TxIn { pub fn outpoint_flag(&self) -> u8 { ((self.is_pegin as u8) << 6 ) | ((self.has_issuance() as u8) << 7) } + + /// Compute the issuance asset ids from this [`TxIn`]. This function does not check + /// whether there is an issuance in this input. Returns (asset_id, token_id) + pub fn issuance_ids(&self) -> (AssetId, AssetId) { + let entropy = if self.asset_issuance.asset_blinding_nonce == ZERO_TWEAK { + let contract_hash = + ContractHash::from_inner(self.asset_issuance.asset_entropy); + AssetId::generate_asset_entropy(self.previous_output, contract_hash) + } else { + // re-issuance + sha256::Midstate::from_inner(self.asset_issuance.asset_entropy) + }; + let asset_id = AssetId::from_entropy(entropy); + let token_id = + AssetId::reissuance_token_from_entropy(entropy, self.asset_issuance.amount.is_confidential()); + + (asset_id, token_id) + } } /// Transaction output witness diff --git a/tests/taproot.rs b/tests/taproot.rs index 21669fea..68424e65 100644 --- a/tests/taproot.rs +++ b/tests/taproot.rs @@ -199,7 +199,8 @@ fn taproot_spend_test( tx.blind( &mut thread_rng(), &secp, - &[(test_data.utxo.asset, &test_data.txout_secrets)], + &[test_data.txout_secrets], + false ) .unwrap(); } From 2815e52045f504e1e95948e91f3f6ece4ae00961 Mon Sep 17 00:00:00 2001 From: sanket1729 Date: Mon, 8 Aug 2022 11:23:04 -0700 Subject: [PATCH 4/9] Fix pset Tweak serde This was only used in issuance blinding nonce, so was never really tested --- src/pset/serialize.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/pset/serialize.rs b/src/pset/serialize.rs index cbd9bd0a..92ac7922 100644 --- a/src/pset/serialize.rs +++ b/src/pset/serialize.rs @@ -79,15 +79,13 @@ impl_pset_de_serialize!(Vec); impl Serialize for Tweak { fn serialize(&self) -> Vec { - println!("{}", &self); - let x = encode::serialize(&self.as_ref().to_vec()); - x + encode::serialize(self.as_ref()) } } impl Deserialize for Tweak { fn deserialize(bytes: &[u8]) -> Result { - let x = deserialize::>(&bytes)?; + let x = deserialize::<[u8; 32]>(&bytes)?; Tweak::from_slice(&x) .map_err(|_| encode::Error::ParseFailed("invalid Tweak")) } From 3583ae241aa0b4c03e5f4d1866622cdc6ed86dec Mon Sep 17 00:00:00 2001 From: sanket1729 Date: Mon, 8 Aug 2022 11:47:54 -0700 Subject: [PATCH 5/9] Fix pset key bug Should be 0x0a not 0x10 :) --- .../pset_blind_coinjoin/pset_coinjoined_B_blinded.hex | 2 +- .../test_vector/pset_blind_coinjoin/pset_coinjoined_blinded.hex | 2 +- src/pset/map/output.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/test_vector/pset_blind_coinjoin/pset_coinjoined_B_blinded.hex b/examples/test_vector/pset_blind_coinjoin/pset_coinjoined_B_blinded.hex index 22b403a2..a46ac8d6 100644 --- a/examples/test_vector/pset_blind_coinjoin/pset_coinjoined_B_blinded.hex +++ b/examples/test_vector/pset_blind_coinjoin/pset_coinjoined_B_blinded.hex @@ -1 +1 @@ -70736574ff01020402000000010401020105010501fb040200000027fc047073657400855d023b6dc94a584252509f6d5214ec6b511771fc0e597c43c357c73804d2d7000001017a0bb9325c276764451bbc2eb82a4c8c4bb6f4007ba803e5a5ba72d0cd7c09848e1a091622d935953bf06e0b7393239c68c6f810a00fe19d11c6ae343cffd3037077da02535fe4ad0fcd675cd0f62bf73b60a554dc1569b80f1f76a2bbfc9f00d439bf4b160014d2cbec8783bd01c9f178348b08500a830a89a7f9010e20805131ba6b37165c026eed9325ac56059ba872fd569e3ed462734098688b4770010f04000000000001017a0ac55f449ddb6853f2508766d5afb9f3b45e41a8ef5368cad75fb88e5e249395d1097d88c92ca814a207f73441c56cee943f0bb2556da194c14a4b912b078c2238ae025341cb5e4e2d8cb69e694cb20e5ea4cc8ddf2801180096fd071addfcd8bc4445160014011d384302576b408aa3686db874e2b17cc2b01b010e207aff956e6c2a379543b1ec82b06958f062bd9f29aa1ac1c98d1f6398b65a8555010f04010000000001030820a107000000000007fc04707365740220230f4f5d4b7c6fa845806ee4f67713459e1b69e8e60fcee2e4940c7a0d5de1b20104220020e5793ad956ee91ebf3543b37d110701118ed4078ffa0d477eacb8885e486ad8507fc047073657406210212bf0ea45b733dfde8ecb5e896306c4165c666c99fc5d1ab887f71393a975cea07fc0470736574080400000000000103086ce2ad0d0000000007fc04707365740220230f4f5d4b7c6fa845806ee4f67713459e1b69e8e60fcee2e4940c7a0d5de1b20104220020f6b43d56e004e9d0b1ec2fc3c95511d81af08420992be8dec7f86cdf8970b3e207fc04707365740621027d07ae478c0aa607321643cb5e8ed59ee1f5ff4d9d55efedec066ccb1f5d537d07fc047073657408040000000000010308f40100000000000007fc04707365740220230f4f5d4b7c6fa845806ee4f67713459e1b69e8e60fcee2e4940c7a0d5de1b20104000001030840420f000000000007fc0470736574012109c5ba9abdcf24dcd65cd842bb47f78d6cf84f178efc80216d94ff8a2585826d6007fc047073657402207f8f32be9443b0547b4daedefd9b6b0b655bdad96759a57569bfd429291fa44f07fc047073657403210a29206a6e6974d903b467480e654c2180efbdbda5f69e8a87d0529501734cd158010422002037831b3ee29fc96f8e61ccb98fbe2dcb03e189dd29cfecc691b5a7442d8548e807fc047073657404fd4e1060330000000000000001736c1f018f94d3c1aeecfc5e79481642ae10aa575e15948ecb3a54b85b2274822d874cf225334a0603c3701fc52635fd65e8a946895af1092760785855a1c67b846e206246bb2eb1c7a660e6213aedab1ff06645630fe6b84c78ab6b74615866ba3cfe138e553d325b0ebdd542cf4a04a9276faf2e25594936cbc56aa6d70db453ad0868e47992d0ecd1227aba88a66b0d3844e26d586630c23fd6d8c162fceebab92e9d5500acf05a81fdf0b6d41db6f6513e8f25234380fb0561c2765480b6fe83d9e74d6913e1925916a3a90f9eef648a8f1caf476244191dc98cf2c39a172a0240b36034c31c9f8782aaccad02a0928d92970cf443f0331e5f580d52a6b9e6caad1c51a30e5fa0503c795fb40b0bcf047fcd873f922bd831c115b7627f77fed8fa76aad6d1250cd84184595f5163142bf77f385b47c49b529b7dda32fee16cf081631bfcb948c2426eb17b0c3bae41b16d5abc688afa285bc99579a30a05f57d0cd7bf777dd172ae03f3982ad912e0177f9cbebec46d6e57741b83289959bf6f68d816cf5ebabfc09676bcfb7766aaf6f5f04179a22d75273b82c94b7a9095eefa90574ba83aa85ea3ec3599fdd72a4fa267f7c2b944b92b690776b97b3cd4692fcd0079760d6a820ae51e1b0e6ef405d751414face0fdad0994cbf553c60017ea379d035e8ae184df1cf7fb28bfd746adef7df476213509924690e6d284ec2e3cc3d735b072f6582d913bbec5977d21f20bdd596b10eaf9bdada349dd63d99e0c28c2006f6945f09ca0d244d434f86841afa621649c4c1704252ac1a676d9131594297fde37194b901014a176abda3e2a5103b8b73b586382b3f469da738714e2d59b36cf4eee345a7faa4666c33a0d74469e39ca152ce7510f1abbf7cf24d37054b272691780309bd69916a964f2d535082d4403fca3210cbdb357ce06704f0f3aa6d8189badf11539d9e6f867cd4dbb2e3b4e13d6f9bedb459edcf1b520488c9334bec854794d3e5d943e7837e557c3131c085307ef712e122199d245bffbe6520f7af80cd73f6547057bc2b896e5430a27d5cc922ffbb5b4e012861061caf149d42b05b342f061fc5cab91be0645ba78f334c46f64615e60f37c84d641348800c5349f34cfda388fd58e48553722b7b53474475a6b6efc9753883a2b41e4678247a363998c59c37cd6c4706c56f5d5fe7596fb195c11748b66b2001accb18fd56fcb137f059973988f981c166b04c8e8ff2a52d705cbc61ee69c26f271e80995009608334dcef363a0f4eb5cc24fcb2160313836cb1707ec294c1ea357ebb70a478b84dd760a10284dd551ee7c8b086a201b900f7e3aa1e491926d74005fb2c989d32a3809ec1cca10bcad7b68c7be99d865361038b2b3023f421fff764a9ab759faf86c0a0042945969c6ca5f096cc1a592850622d6f60ba2b56287fdb6214d761dfd118ab8806a8557af5dd1d31f3d551e6b749bd37ad351184646d26360f150167a34685e24bd8127ec4970c73231e0ee4659bedbdf0b0fd64895cf13396f52417032f8bb221ea9216166d0a324c0d03603302e8234e9d98444153e91790567554056afa2f1d49d0277d757fd5211fe66a7f61624aed4e5dfea2cbbb8dabc4ea3037f4c6e236f1ee048b499cda952c7c9086f756adeb75022c1925ac0f64e4d7da8ec583e3326792bf13136d6e3eca27c56cb4be411d6b03ba8c29a4f17a860d1d27b93242e345cf7228bc6ce11aa876e7a30159a8dfead13520347ff5e949748ffc4ea51b75a7135456ca0a3b40a39bb082a9f02da862f19c651284ea28779ec034b05c07cbe85588f56b4a5432144ca7c1dd30b9783f231b1fc1ec05869de856a20a784c05f33055379658ec2a2ad24995e00c47ffc7bfea72e91df9d5e9a8bacd3ae3e12df323c0bc759857ff6e7891ef49b0176d0959f8fb2494e0fd85e68f0b8069bfbdea365850c15ca98d8e858936cce10a0d8a7d26877f260673ec3d1bb5f3ec4565726c935593e6b34c48f73e551b908f0a9c632166096efd4887e168831b0eb66c3e0e9e01a31f354e76d5f584273ad8f8ac2af7e4310b3273d106c171892ff3bd3c92f2727920d88b82b4cab6517eac2ac6a808c62da14c35536e47b33f028ead9d5486d872332fb61dc53c8281117f517b0b6d08626a4bf5d9ceef0eeb7828b56cf42aad8cc3cdaaf2c8f8970c6c20e1fa4c8dde0d822de374fad8fc898518129f7251fd9ced6b8f32364a1987cc0969892d1ab885dc9bbfa2a08a3d831a51755a6aadfe1bf78a2dd5372eacdb0e6a9668d2c7d1b720cb911005bae7f6d5d4e112aa4256171b6dd5652f95a4bd7f624b45432a99f14bddbfada9af1ee6dadae06f8392adf959979f46dc9a55439b5515ff57cb5f4934cb1259ed9ecd114014b99b3fa0f325eefa2ab8738e05c5ded5885d7430aa31b3878a10dd0a9ff95668e01477b0ebcc904e4b4f27840de17442661cf246f47d542f85a168187669820e6642cf58b23557c109b11133106fb043781a2da51fed9b2c5fdc426b4c1ee1ec47d2b9e992a2cb3485029d8c9d6dd44d104f0caa06a44b9f0470af5f905d155326e8156155903b9706cf6ff62c6c565ad9d1d25a0e82b1d8164268d83b8c8d4fce0ff202992738237d73dd242cca368fd3d3ca71d6acf49ae0d749a33eef07157adc94a049d2c6de65d2ce6a4c5957853fc89dca92da3f014739b24459f24de757abe4a127ec8f6b774beebfe44bf1eddd84a14f85c9d57ed3a9d8dbfe616db906c2d4b482b0d79f8165cd4c78af23c98cd715b406244bb5353edea403d54b8aa46206c5e8e551d1ee3a1310f7b7ce0e28392eac7e2546867d00b34fa47ae8f2c74ac9db78565bd7c685108de0ff3c0af495fcd31120e5497025416017ba47e6f32d3ad05f2290b471eb21aba1f60878f71e3102c59fe5ec96012f68e73c9bff4f35c25e65d66aa930286c31bd6a59e0d26b33cbedf4e5e43ec5ab3a5822ab352d61bfb45a2d9929dc72c5179acbb217e760683d079002b856bfe25e1951ee428475a5fa9447193778beaf49236a1a67905a55d541e69dc27eafcba25dc6ac6110f8e6528c5a3206cbeb36833544ca08db02c91ce03c1ec97b309014e52c546186d2bf62098b708054fce5cd5bc7e042f7da37780fd1ee3ccce6b8abe4c586f46b0488117d8cc2b42679ddb89dd5e4ff7f5e4a5c2e9c3101dc1d5c6d0415f255164eb38486f78bce5a0dbfc54aef8adfb647804a8358c4e5de06804539bb4ea7f7487f158527cd91081477a5a020152aaf49b4f8077296820d254d13e3c8fdd21906a801e665a4043b21de0edc08c9664be88f3834b0246b6264ffc081846cc200d629cf1ad0db881aded247a8174b4f43970d5680332dba5061f5055a2e69334cf4c8dda7302a9e37091e4f440608dea5399f1a8d748a59b009299a79f9da3c5f2b2648846c64a893bfbe0bd187b7b7767bf42e351a8392ecc744318a9871515d435ee05be0e5c800e0d1cfa6ea10335b48a2f00c17344afcc6d08ddb426031a35d6daf07f48c7980f56bb9fd2588f9a1f119610d70c8af3da487964a170b63ed3ba6c097e8ae750aeeaad733aa300d87a15e558fa6330680cfa4cfad9101ca85d012858b3ce6d944c9bd9ff072a151920018cd52314a595dddb0337a6af4e1aa7905ff54bec93f50fcf5625cb86d5ba0a39bd757139dbdd63b96c940ec14303b6473c48ec00bf1cb5db2ea7cdbcf4f0c4ee6a6336d7a321e57fa1f288b4b635addf70b724364084f05cbba5d52bdfe7b708cf25f7f1aae574c49758e7587eb15bde51dd3343269812c5030e9398a31487dfd86e2e8c9ab8e8ab0713e955f9981b7d8f1aff0424d01499555af7a1a17d041f3eead79e2a4f9528a6356081c550326b1bb4a6610302590430aead818e2195199742dd13fdd928a9ab23b15aa67c41758b2762078b2e3d3957ab202d0ffe80595cd51ff54ca213e21734d475b7b4b924a60580b5ae4c475a71949622806ef418273349811ac08a912880079ea2dacbd0e0a4092af04fe20ee0b2bbe1addcbf4289b5e3dba3125ef6cc09a8787e29930cb27e987eb599669349ac70e8fcc66f5c27aed363e28888b1b2a48e432ad2987606cc5496d76beabe66d1bb6fad2d16116a4d0d98509756e4d641f57d65cdd71ef99262d6047800dc6fd0b2a0d167b8d242cf53c41b8411b26d48b6a95e511d316178d34aa3d6852de377725d9a253717dda8238bbb2ece522f60ff4535f1bae8a71e52d904e5c849d13cb91765cfb20f5f74c9067e24de2d70006e384883e676b33549e708f3c90a0ae967fd54ba1364dd90f00f9660a27ed880dcb1067a4904a3c649d024cf9cb3a8184706c74d461b0efb02ecc4e93a709527eff8753dc3a515d7ccec22c9d08751a74a522f9fe99cc193a5fbe2b0a6cdff1d4e8e3654d4d74ae57fbd8e2582cced7c52051797b02e0637ae4d541cc206a754e960bb8983b341808b783032236a3ba305d2a5460a04da0da20f09a4d4f6c6312435e6c4c6b45a8d17998f969964284fa49cfa49c760dabcec76fb87768369f98153bc3ad86a3bca1acccc12ca8cf61b14d00a1de4623a372364bcc893983fca31b111b9458d809ff8ec7716190987297326bda2bcdef2faf880fcf8cd999d32ea77ec98958cf30e60cc0fcc3055d978fe7037e1328ca6c4c4134afde8d8ae5d71811ecd682a48230273bb9264eaf971717fb815eef06ac881f3d0f4d859b87043d7698ce28668bac8524b1d5763caf11c0dc6534c62c0dbc2291bd62b5d145fd10553b6eaadb1f6bed46b96458fba4bcec7785861955f68552335f36c687735425b9f9d17f2514a734e3fc385901219d20976df1045aa5023d76750a5cb10e70ea07f1c197526f5e71396177f66443999abc0a008d400da3d08c9740cf6662adf93dd1735f8c262f58241fc6cdedc9ef7cc4590b8aac248a831fc7476c0e26f0445f9ed723cfee1fbc2c8ac6315e14bb2f49c2fbbd593d870b8b98cee16f8adc6f841f236e4b499571094e07ad82e44e57f16f728a7187d6c1baf3cd1315b1f9ac4b7dae69e39efb6a03176430f69720e0ef879284f59ffee4e6720d31c51753d666681dd15e7ee5340a8629e8863d5e86b4088a32de13e13e0f92e15511e9bc4d57a25c71743e9b39af867dc17ad3ebe41b9c8f64d1c38573db395382b55a50ec279030ce8f59ba8a13525681efe3862f3c46eddcd3dca4eb3a191771723d3a2875fb2074ee9867632eda4ffadda4c64283202cbed717d3ebcb2030ead311b9c2ca56169f7ce6deb9fec78a76cb9f78ab8251b83bcda6dcdb0e916ba12daac78a151eb76d040507fa29eec866225f87c694233ed07362b097aec619f5df3dc5ad0a58f0cc94eacaf252f1f9dd59bce58904ff7460052a5bd0650111c105aeb34485c4730ed6e3e1c927e2cd956d1b9404fbaf0440afad135a3f320005d666abd4c69e98edcda3691b7e69b2c3c88ef5e1ab9062b0b3f08b8ca38e8f6f7b4d04f3daa358986a3f8bc5f6a13115c31e454c0dfff61613d0dde9dcf4516bad111328b9e88f262988e8c05e5ffe1fa6ba708f5fd51c34e4757814ad0ea5e6fd33cf51b45b84c85882406cd3eb107b96fe546364a9972d19022be3b5121ec64c6454f3a4f9809f49e11611b2131d5af0aa5e65c156f37a6062aa395e763522fe6b1451c0452c6c56443087202605ec9ddac8635e7fc086e330a7d22b15851671565726b2cce451d6288755a04862bc7f934b99de6809533c05b851ed07faf408f83fa9c18f3ed65a94e9788f830f5bb9ec744b71f59d6821899f8640441d47746497dbaf8e9ddbd252e04a5e4b313e2580a1a858e4550a1e5c09a04eae54307fc047073657405630200037f019cde9197e7270a1c7d726ced68dcabcbad740497313348e7ce6ad7d29f0bdf616a31c760921e4f9796161da146c841e86ee758cfe053b88447152770fa72c1d2b4d17de0698a19a7f1cd72c95a4b3851905c2a7a76d894a2885cc28addf607fc0470736574062103d559d2a5a4180f418a69c4bed5508971cda9313722fff71e053d3d82fee9d7bd07fc0470736574072103701e53a6d0b960398abf678382a4d17c5c153d1a2c8ffb76b302058ce915bb0d07fc047073657408040100000007fc047073657409492000000000000f424056773886ab9ae39b4056b656fb255a3af50694cda3ff4d8d4d450f15ffbbbd9043f90fa6f45a7e8563f8d305ab4b991a2c33e51b65f94230c9bdd457a3b31bc007fc047073657410430100017f113b550d4432ae02cc0d943900d25f6833c26bc1df867fa17b36d215044f889bcf7e3dc63814f6d7894608232902f7cf313b28194f104be657b44bf54471c300010308c0878b3b0000000007fc04707365740121080b9276ef17348a17b4d25e1d429594891f5bbb07fc8e33e4bd35bdf8296b7de607fc047073657402207f8f32be9443b0547b4daedefd9b6b0b655bdad96759a57569bfd429291fa44f07fc047073657403210bb668bf543a321a7cbad607ba5714cfbdff67e8d04c9a4dc539ff7672b84b19cb0104220020e7da55d19cc85b0420c539a90b667d4d85f59ee0ed417493a947c3a2256cc0aa07fc047073657404fd4e1060330000000000000001a000d4005894c852815a527aeb01259da98708628a2f2657826496e2711f7355a941f50a31be4e1df7d245f27e22dfcbb737e28008eee8322b6ee9755cf564411c5f360cd8ebd076db3f857f2a89a6dc3c84a200a3895a0a68b8dd14ca3c294eec37cd45d1cc69ba3e5a114c8a4d8e32eb79cdf984ca018052e503a5a6a71b49c78112909d2f1b1fe97ba13cb6804156d6202dfe1275a223c3b99f77964f3eefe61f87d483f5d8273edf67f4ba970c9abc27627bdac0fbfccdb6582e30429d2d82ee4658e2284927f66b3fcbd59b8282ea88e37198b3e6809a79e9be849ae2080195239e82395ea60e837e3e03459c4a635ae8626d29939026c1b69d6ac6a32a6a8c8a3686d29c636841fe4ad37402bd3c94a58b46a74898b614dd318211822e2927db89bc8d121373ee1aed057436ea6bc084e7a38d612fb9322265c7b04ba2a4187cd70856fd276971057ab4aec79d4e9f1ca9bad675c62c481a621f23ecb7b78b72a90448f40620152a603d4a150d1fb87c37cb281195045dd4730899f58f4813c1c99569828f377e6973bdaeff1bec942f98038d6599a73de84ce4c350ec161074fc30b151949f22687b9c50d05e8339c048beea2e944f77f601797f7fe64cde986746644b4c5f0baa42d6738add8f9773e7ff9199cbfa3bf03cda1e8be64163a3d8cff0875ea6b495e372107b5f6e9602fb6b0654e5fe1bc8a2626e4c9ca3a33bb0d2755055547dbbd2b1548de0b9fd7193ac0d3bf7d4ecc929c3ed0b1112aebe26188476f63dfb75b12187242436f8bcab54de04510dc31f3f3f14204e8b50bf3594432edebf93b26903f87c1dbea50dc9af089c4092654250e1505301daa5b0534645e52f2d3c36e7af6e9e04f7b54111282044afe94411854aa73be65f18fc868f39f79e312f62c4250e61a2511718808980fa0ce8089437569c149f4f9381db1e12e4d2d1ff682f47d63c8cae57eadf9cefd30e52128dceadcee043c84d90555b10095765a0d1f898399cb734477bc068fd2b37f47847332d38182cb23da3800c56dcb2a074aad8ef25d741d569c355fd4a0d806cfb698151873d1e48e24fe359b2182c8a26a1ca1c21ab609fe19dadbf5f8e3ffed3fa7679363ac7e303eb917554fda9d2bbaf6c053e658dfeeb88448f5fb017687f3eecaa3e7ffb6188c18e55678cbe2328a05263a987fc502280d070f181129902cc0f5e415e13f76b3f58dd257136ce579c4a999b127374e2bff94f694c456247c502239e301d21aa870ac1021b97b11a7d1ba0095696a50fe16e888616548d7eef96efa59cff978962a7c6f38aca24282091616f6acdb4bebedf236c043b36a6f12eb82c2c589c6a71080a46cf27e6e663060788c2871ff04d26ecdfe534ee254dce0328134af51228c908c5184eace62cebf5ff692097fc2d272a7275b965ef8b5953fb1ffe8d713cf92bf4b3f6a428bfc3aac0e67aa93e9571902dda5b1f66ce523109092aca555f007ee5529597ec185981f45602be0a8a0f9e9b75c477e0af5d27e546adda7c4a2776b97b9a301f0b6fc15495197cfa6f2975d19bbeb70db18dbad8d0ed06176d97c066ac19d4061d7f7cccedb352788ce5d15c26fd970bb68b879b5571ec5bf2917d7d58249fc8f9b2f5a5efd5e3596451a7be38dd75525fd1c2b0444ef9aab646869322c23e52b1e0b2b420d2220a4c150f0c6b8a4bb245282f546abb74f264b6c75286d05fc7bb2c266b5e9864bc6e9b45ffacfa2352ba898178856db19b41e7e6d90ba0e14226e698ebeb02b3fa349e8ee09d7bfee08a54763ac1db861aa0683b78f6bf07263e3cf0fff0b91225e5e009231155bea60b2e661e7b04d8803cf0c89192cb8f70cf16a6d256bf31a28d2203da20d7d33c7a6f841169a845ac35c8fca9253e807f72e96355c296323f6e0a1d48bff8c43f55a594fa251f69b907d9f97e7b2feb5296d12d331b34ce9107df9da5671effe1120e078956b85abd24c8cc1276d648a2c515791fd40ab74a5c46be36a6426b2c992c22cd3d96d61ddf089ca711c15ec60538057230a2e96a92ccfd605b09a4ead233440b7fed99abc47c50263728b18b2bbf79d814c30b5e96a72393d828446bc3ff14bcfa0c4530b59750c28d7c9639c961ba47320401566962b9fd69df8e87719e0bcfc5e9987d1cd9ff4407dec489ec6e1c0a82037f7f0f94d3a06d131876d541f3885906168181c21a395a51fcd3e2efd3d116948742f8911cb892fa7d4d4d5f83e86c9334732191c632a2a6a74d7f760ccb95e04ff59f8e207ca2491d0a6f48df78254a0019fad13c0251e107639d5669bbe90cd0188042c02eb726d3d33f69e5ca06ac96c733811098c5f9a09210b762e5fc94c493552e060058e811cd302abe0d60be900fb0158126a4d3c188a65ea6c2620aad9c73b0d452413bb26c5e6c3b2d885731bbac7abbd42895d5542bcacd1a93c405daa46bea191af513b0bfc3a1f992700daf4967cbe498bf1df5bbdecbdef4614af954060b7cb7de6833dc0d721eaa570659400f452664ea7c88e410ec5c35e300465ce779d76b0fcf8ecd375f727347bc46e069ac8ad816d35d08f4da02da77a75447a3da203d8ce3a0be9093dbe938dbb62936c7602f9bebd69261fa9fde170c9fb22a345183ae119af5b9a47c1cb0d740ff9771a27493c9bcb0ffeca14c376e0512014dfacbfbcc9d0956db6d642cc892dd7d8a5070b054f26e977ee6e3c121b16163d8ac151df29a5b8c5601d3cba799ceb10f04141c3f6081d7d1b6ea22202b3aed1f932f8cec9c65eea07befa558159499b1033e235078fa7e16be66be6f2ded84e8b47708a59c0c707fd79061945818132b2f2e58242238fb3c3410d2080cc8ff7b9a689d259b2bb63fb40f1af64f19e4dc53ebe3bce60977776328ebf6dcf24cac233e04c5df29d5ffed25609e3b8d96accff140f9f6acf21d9951ccff9f5c9bb27b7c8991b5bc8c2dbed6ff31b2b6e75f6f620ddf45cf6f67b900678567745e607b42d0bdb9d86d80eed1a1923c2386f371e0d2f11306ded8684325e46bfd979059ece5fdda6ee9b5ffd0697a54a64abd7599292509c3a82bb926b743a91affe05b7dfb350b605521dedda17617dec004a378b01682b2998941f02dbbc804c3553ace603226369bfca98ab4aeee767abc892e00f56d79438d075692a547da501c50289e91c3a891646daf82de39c7abdb48b3663bd870eaba0393b66dc7723ba77c588f5246fcf7b877e296fb784834e2cd679b54141860f4696b1b1ac330edcab74b59aff6fe2e36b7e3a459bac93e5068785f455d12c51b486f2063341113b6e196def028901f106b9993e4147ec924af8e6d86155d8dc2aff8b1f9268d9c75e94e253ad38ae65a8cd3cd19161dd5258588f8e74f3da7bc7df4bc6b7d23de75a02c87e8648a7bbd55210110239ed6e6214189825dee3bad6a028c70a2bf249b2294234798311c5695fabbfde68637ab9d066fca327472ca460468d34f74922aac4f1a64ddfdf7ccd4fe12d83ef033b901384ab8149ab50288fcdf087a50c0271046e7824c6c69c33ce1179c9e87dbbca60692027c1c54481a8d4909fcb1f2565c47d50218995fccd8cd64f51874180fd930256880aa1f696c321790cc5c32c49d146f6cd0128b18c52d00417adfc06aa6e279c03f5b21daea9a33390a91dd3c5281444d023362578aa83eb3a81d57ad360d337ab374c1bb3b251a51fef636418e1966cea1b2135bf444a03c39f4619c7acaf3c7a5cdfdf8a3893696e5fc076e915af6ef7817a32f5c815803e92810abc3ca09e421f8f039206e524a47ed746d3ece4c67e1dab74477abe25707b92598e71f6011ac9e3ea85417a6e4f43c55f158c2c73776c63c3af8fa472016ccae79a2b9e99d8c42fa1cd72ce8c9cb3c535719e075a0adf26fbb559ef129512833698d6892ca1a37f176cf6a363cbeaacf40813114285b032412f6d98854bdd758465604eb2ef4756064a16cbc02763323f29722e625ce895315bc6eb1ef3aba39543df3668991b3d7ce33c68ca975c18823cf37e8bf38b87ded0527d61ba10aa43db45b82e23b1582da992b9650f7d146eb420fdf679eddc26eaa3639a6aa41a2149d1b89057a05552b772504cc29132b7f6b3eeb5732a9830fca236fd41645f4da9b38b2207d931944a98ad45585eb659b7e1e43fed797c41705265bd155174f52e45a89ae79e5c1dd264a39758ab5ba42f6b721b926a06d45ceb114a0ad592ec71276bd7fe1cfc592324e58b37500b106355dc6ed962e1830ce33f8a18a0ca236c3301b0bd9029c6dcee2dc37057635fceb494a8352d74963fb2e3f75b91b19bbdaa49abbf11351f88b4d2d0550320a8df123289cb16e1a4de9e71974d920d2b28e59037e3a941e0f7c6b2265ee281d0f9da960d2b707fdbd0a58f0a19ff8003ccec3d1be962eb47f57923ee2a1df81cd2e77430eeb8e0825e8cc93ae0466a19c80dde5b8872491326f877b27db9543c495ce3c5965bbd48f216390115c7c31bacb20bd9f11267d2aedd4586ffaa27664991a100235bc197ea189840540fe0b29a07f24c400ffa2bd81eea1d15496bc14a65fea7e05604f987cd847b0814439e09ef47bdb3f273cf0a56e339e7105542a2ea1fdda77a2dcb792e474cd086341b510cd5b424caaa98497744303dc149759640302337f8d4038396f776dd79fc41fba310214a60ac5e047311bcdb5daeb1d8a601368fd3d84f981aa6fe7fc43d244beabf0a386414c569c8599918f8250487c546f1dd49a7793061a0107ae626beb6bda487f633b1abfa389e182f4f1aa99309ffc7c0b69344d0e9c5c2feb35cfe38f33c6f8b668af1df1bdcbdb5822c6c1931c7ca25258556881584dae524b35c0fc1dedf8604298014dcdfa39c3d38908364b01f55062bf7ad3ce8f85bb765afed8f365b1996a6600d39105203dd47023b5de1e2c2ff78a2e4b1fd6329afd0e86777471721fdf55e7189b18718b9c7d6f7d764b6bba82ea9eb9cd9dd9c09b9ff5ef25b3aa8ab309e6d85f43d6dca7681a49975372a9ee196f917e4e6b390103537d24a35a084c5eb5b378dd1654025fbee39935f599bd4a15741ce19479a93dc9489035158fa0812b6ac13c6f247432cf8ed3a92f86b372cf624e5b7b2a419184ab9b333a461d5fa9df9573f67212435ee96a59a020ab3c1dc0c61440905516a8b6f341e4d9cceac3129b6b7b6b3ba2ebbabef7857d8d7594f778163a5f95f9b443067a94f9e0fe9db323e25ccae107e960ce163d62fa0c6268d99cdf208705b57e3869a8e0687fb95d9244a3fcb447add7b7dfa850e9af704e2619821754988858693e27fce4b0b3be89e42def5bdc8213e02489179150764fc0a542e382f52e8d7cdb80e4aa78ac9b3d1d56ab23c8b885f0f173c4020d2330058dd37a34c0c1fde5142b3176254a6899d47514d9c2e68b040104b134f331dc4d9036505210d4944ab4b7762bbfa364fa3d96c7f87e53bf71d5a5c3c40cad698031e95ff17922952b5d1f9337c93bef79c09d075ac5d73b37a317f6c4d767a183283d1bbc97560d4930e47628d489a2c28267ed8bf0922b519eb3f72c62d710f81f07dffdf6d41b5ed95190ce20e2b94f8cf525be8352568b59a9a9db7840636d2b76494fb3f791bbdfacaf5541ddf8d7c104462dd1c6d3006bc386ac1f55fb8400589bcd895274de80092f69d1c759fdc3c31f2e1681ae75689e587d9b11a5673e069a98c1f77b538829c59e64bf65c1417abb2d8f52b8ac6c4bed00ddbb1a1d04d05d874315f55ed580c6fe3cfc967c15bdfda8be76eb1c77e3a720450dcbce40f772c28097a0925aa159858f38058ace779e4d8467de433e39518554630649613da5d20707fc04707365740563020003891394633c5f31c9ee5ca072b289c5be81c8d6237fb8290032940c0f535b9f72b4a4b8e967bc5c791a60b0567bd7c2fdc5ec71eb54c8f0770c92f5488c50d1416d636dad9c610e29d32d95c6ba93f6ce39a14fd1e6a11c2934090f494dd860d307fc04707365740621029e5980b4f9b9a9fd568c1c4b48631a800c310405ae8b2ac41ddaf87add3062f107fc0470736574072103504bd87c31711ff592af95f3c9c4f78e63f2f30805bfa95bc2d21e5a2db5c4da07fc047073657408040100000007fc0470736574094920000000003b8b87c003c8a469312a60ecdf33a36e22b37eb9c3e380ddab84491cd12ef7c80a6565124063d8d889bbc3a6f2e0d2fb66f78adb6d5a43d5fbb716a5f09a0db9788282a307fc047073657410430100018474c718fb7fef3e0585e56e19e551b357042f0195930751ce4d22721d93302dd78d263aa3c247113a0958851c182ad93f59216c95ad62b808bad00d4127fdf100 \ No newline at end of file +70736574ff01020402000000010401020105010501fb040200000027fc047073657400855d023b6dc94a584252509f6d5214ec6b511771fc0e597c43c357c73804d2d7000001017a0bb9325c276764451bbc2eb82a4c8c4bb6f4007ba803e5a5ba72d0cd7c09848e1a091622d935953bf06e0b7393239c68c6f810a00fe19d11c6ae343cffd3037077da02535fe4ad0fcd675cd0f62bf73b60a554dc1569b80f1f76a2bbfc9f00d439bf4b160014d2cbec8783bd01c9f178348b08500a830a89a7f9010e20805131ba6b37165c026eed9325ac56059ba872fd569e3ed462734098688b4770010f04000000000001017a0ac55f449ddb6853f2508766d5afb9f3b45e41a8ef5368cad75fb88e5e249395d1097d88c92ca814a207f73441c56cee943f0bb2556da194c14a4b912b078c2238ae025341cb5e4e2d8cb69e694cb20e5ea4cc8ddf2801180096fd071addfcd8bc4445160014011d384302576b408aa3686db874e2b17cc2b01b010e207aff956e6c2a379543b1ec82b06958f062bd9f29aa1ac1c98d1f6398b65a8555010f04010000000001030820a107000000000007fc04707365740220230f4f5d4b7c6fa845806ee4f67713459e1b69e8e60fcee2e4940c7a0d5de1b20104220020e5793ad956ee91ebf3543b37d110701118ed4078ffa0d477eacb8885e486ad8507fc047073657406210212bf0ea45b733dfde8ecb5e896306c4165c666c99fc5d1ab887f71393a975cea07fc0470736574080400000000000103086ce2ad0d0000000007fc04707365740220230f4f5d4b7c6fa845806ee4f67713459e1b69e8e60fcee2e4940c7a0d5de1b20104220020f6b43d56e004e9d0b1ec2fc3c95511d81af08420992be8dec7f86cdf8970b3e207fc04707365740621027d07ae478c0aa607321643cb5e8ed59ee1f5ff4d9d55efedec066ccb1f5d537d07fc047073657408040000000000010308f40100000000000007fc04707365740220230f4f5d4b7c6fa845806ee4f67713459e1b69e8e60fcee2e4940c7a0d5de1b20104000001030840420f000000000007fc0470736574012109c5ba9abdcf24dcd65cd842bb47f78d6cf84f178efc80216d94ff8a2585826d6007fc047073657402207f8f32be9443b0547b4daedefd9b6b0b655bdad96759a57569bfd429291fa44f07fc047073657403210a29206a6e6974d903b467480e654c2180efbdbda5f69e8a87d0529501734cd158010422002037831b3ee29fc96f8e61ccb98fbe2dcb03e189dd29cfecc691b5a7442d8548e807fc047073657404fd4e1060330000000000000001736c1f018f94d3c1aeecfc5e79481642ae10aa575e15948ecb3a54b85b2274822d874cf225334a0603c3701fc52635fd65e8a946895af1092760785855a1c67b846e206246bb2eb1c7a660e6213aedab1ff06645630fe6b84c78ab6b74615866ba3cfe138e553d325b0ebdd542cf4a04a9276faf2e25594936cbc56aa6d70db453ad0868e47992d0ecd1227aba88a66b0d3844e26d586630c23fd6d8c162fceebab92e9d5500acf05a81fdf0b6d41db6f6513e8f25234380fb0561c2765480b6fe83d9e74d6913e1925916a3a90f9eef648a8f1caf476244191dc98cf2c39a172a0240b36034c31c9f8782aaccad02a0928d92970cf443f0331e5f580d52a6b9e6caad1c51a30e5fa0503c795fb40b0bcf047fcd873f922bd831c115b7627f77fed8fa76aad6d1250cd84184595f5163142bf77f385b47c49b529b7dda32fee16cf081631bfcb948c2426eb17b0c3bae41b16d5abc688afa285bc99579a30a05f57d0cd7bf777dd172ae03f3982ad912e0177f9cbebec46d6e57741b83289959bf6f68d816cf5ebabfc09676bcfb7766aaf6f5f04179a22d75273b82c94b7a9095eefa90574ba83aa85ea3ec3599fdd72a4fa267f7c2b944b92b690776b97b3cd4692fcd0079760d6a820ae51e1b0e6ef405d751414face0fdad0994cbf553c60017ea379d035e8ae184df1cf7fb28bfd746adef7df476213509924690e6d284ec2e3cc3d735b072f6582d913bbec5977d21f20bdd596b10eaf9bdada349dd63d99e0c28c2006f6945f09ca0d244d434f86841afa621649c4c1704252ac1a676d9131594297fde37194b901014a176abda3e2a5103b8b73b586382b3f469da738714e2d59b36cf4eee345a7faa4666c33a0d74469e39ca152ce7510f1abbf7cf24d37054b272691780309bd69916a964f2d535082d4403fca3210cbdb357ce06704f0f3aa6d8189badf11539d9e6f867cd4dbb2e3b4e13d6f9bedb459edcf1b520488c9334bec854794d3e5d943e7837e557c3131c085307ef712e122199d245bffbe6520f7af80cd73f6547057bc2b896e5430a27d5cc922ffbb5b4e012861061caf149d42b05b342f061fc5cab91be0645ba78f334c46f64615e60f37c84d641348800c5349f34cfda388fd58e48553722b7b53474475a6b6efc9753883a2b41e4678247a363998c59c37cd6c4706c56f5d5fe7596fb195c11748b66b2001accb18fd56fcb137f059973988f981c166b04c8e8ff2a52d705cbc61ee69c26f271e80995009608334dcef363a0f4eb5cc24fcb2160313836cb1707ec294c1ea357ebb70a478b84dd760a10284dd551ee7c8b086a201b900f7e3aa1e491926d74005fb2c989d32a3809ec1cca10bcad7b68c7be99d865361038b2b3023f421fff764a9ab759faf86c0a0042945969c6ca5f096cc1a592850622d6f60ba2b56287fdb6214d761dfd118ab8806a8557af5dd1d31f3d551e6b749bd37ad351184646d26360f150167a34685e24bd8127ec4970c73231e0ee4659bedbdf0b0fd64895cf13396f52417032f8bb221ea9216166d0a324c0d03603302e8234e9d98444153e91790567554056afa2f1d49d0277d757fd5211fe66a7f61624aed4e5dfea2cbbb8dabc4ea3037f4c6e236f1ee048b499cda952c7c9086f756adeb75022c1925ac0f64e4d7da8ec583e3326792bf13136d6e3eca27c56cb4be411d6b03ba8c29a4f17a860d1d27b93242e345cf7228bc6ce11aa876e7a30159a8dfead13520347ff5e949748ffc4ea51b75a7135456ca0a3b40a39bb082a9f02da862f19c651284ea28779ec034b05c07cbe85588f56b4a5432144ca7c1dd30b9783f231b1fc1ec05869de856a20a784c05f33055379658ec2a2ad24995e00c47ffc7bfea72e91df9d5e9a8bacd3ae3e12df323c0bc759857ff6e7891ef49b0176d0959f8fb2494e0fd85e68f0b8069bfbdea365850c15ca98d8e858936cce10a0d8a7d26877f260673ec3d1bb5f3ec4565726c935593e6b34c48f73e551b908f0a9c632166096efd4887e168831b0eb66c3e0e9e01a31f354e76d5f584273ad8f8ac2af7e4310b3273d106c171892ff3bd3c92f2727920d88b82b4cab6517eac2ac6a808c62da14c35536e47b33f028ead9d5486d872332fb61dc53c8281117f517b0b6d08626a4bf5d9ceef0eeb7828b56cf42aad8cc3cdaaf2c8f8970c6c20e1fa4c8dde0d822de374fad8fc898518129f7251fd9ced6b8f32364a1987cc0969892d1ab885dc9bbfa2a08a3d831a51755a6aadfe1bf78a2dd5372eacdb0e6a9668d2c7d1b720cb911005bae7f6d5d4e112aa4256171b6dd5652f95a4bd7f624b45432a99f14bddbfada9af1ee6dadae06f8392adf959979f46dc9a55439b5515ff57cb5f4934cb1259ed9ecd114014b99b3fa0f325eefa2ab8738e05c5ded5885d7430aa31b3878a10dd0a9ff95668e01477b0ebcc904e4b4f27840de17442661cf246f47d542f85a168187669820e6642cf58b23557c109b11133106fb043781a2da51fed9b2c5fdc426b4c1ee1ec47d2b9e992a2cb3485029d8c9d6dd44d104f0caa06a44b9f0470af5f905d155326e8156155903b9706cf6ff62c6c565ad9d1d25a0e82b1d8164268d83b8c8d4fce0ff202992738237d73dd242cca368fd3d3ca71d6acf49ae0d749a33eef07157adc94a049d2c6de65d2ce6a4c5957853fc89dca92da3f014739b24459f24de757abe4a127ec8f6b774beebfe44bf1eddd84a14f85c9d57ed3a9d8dbfe616db906c2d4b482b0d79f8165cd4c78af23c98cd715b406244bb5353edea403d54b8aa46206c5e8e551d1ee3a1310f7b7ce0e28392eac7e2546867d00b34fa47ae8f2c74ac9db78565bd7c685108de0ff3c0af495fcd31120e5497025416017ba47e6f32d3ad05f2290b471eb21aba1f60878f71e3102c59fe5ec96012f68e73c9bff4f35c25e65d66aa930286c31bd6a59e0d26b33cbedf4e5e43ec5ab3a5822ab352d61bfb45a2d9929dc72c5179acbb217e760683d079002b856bfe25e1951ee428475a5fa9447193778beaf49236a1a67905a55d541e69dc27eafcba25dc6ac6110f8e6528c5a3206cbeb36833544ca08db02c91ce03c1ec97b309014e52c546186d2bf62098b708054fce5cd5bc7e042f7da37780fd1ee3ccce6b8abe4c586f46b0488117d8cc2b42679ddb89dd5e4ff7f5e4a5c2e9c3101dc1d5c6d0415f255164eb38486f78bce5a0dbfc54aef8adfb647804a8358c4e5de06804539bb4ea7f7487f158527cd91081477a5a020152aaf49b4f8077296820d254d13e3c8fdd21906a801e665a4043b21de0edc08c9664be88f3834b0246b6264ffc081846cc200d629cf1ad0db881aded247a8174b4f43970d5680332dba5061f5055a2e69334cf4c8dda7302a9e37091e4f440608dea5399f1a8d748a59b009299a79f9da3c5f2b2648846c64a893bfbe0bd187b7b7767bf42e351a8392ecc744318a9871515d435ee05be0e5c800e0d1cfa6ea10335b48a2f00c17344afcc6d08ddb426031a35d6daf07f48c7980f56bb9fd2588f9a1f119610d70c8af3da487964a170b63ed3ba6c097e8ae750aeeaad733aa300d87a15e558fa6330680cfa4cfad9101ca85d012858b3ce6d944c9bd9ff072a151920018cd52314a595dddb0337a6af4e1aa7905ff54bec93f50fcf5625cb86d5ba0a39bd757139dbdd63b96c940ec14303b6473c48ec00bf1cb5db2ea7cdbcf4f0c4ee6a6336d7a321e57fa1f288b4b635addf70b724364084f05cbba5d52bdfe7b708cf25f7f1aae574c49758e7587eb15bde51dd3343269812c5030e9398a31487dfd86e2e8c9ab8e8ab0713e955f9981b7d8f1aff0424d01499555af7a1a17d041f3eead79e2a4f9528a6356081c550326b1bb4a6610302590430aead818e2195199742dd13fdd928a9ab23b15aa67c41758b2762078b2e3d3957ab202d0ffe80595cd51ff54ca213e21734d475b7b4b924a60580b5ae4c475a71949622806ef418273349811ac08a912880079ea2dacbd0e0a4092af04fe20ee0b2bbe1addcbf4289b5e3dba3125ef6cc09a8787e29930cb27e987eb599669349ac70e8fcc66f5c27aed363e28888b1b2a48e432ad2987606cc5496d76beabe66d1bb6fad2d16116a4d0d98509756e4d641f57d65cdd71ef99262d6047800dc6fd0b2a0d167b8d242cf53c41b8411b26d48b6a95e511d316178d34aa3d6852de377725d9a253717dda8238bbb2ece522f60ff4535f1bae8a71e52d904e5c849d13cb91765cfb20f5f74c9067e24de2d70006e384883e676b33549e708f3c90a0ae967fd54ba1364dd90f00f9660a27ed880dcb1067a4904a3c649d024cf9cb3a8184706c74d461b0efb02ecc4e93a709527eff8753dc3a515d7ccec22c9d08751a74a522f9fe99cc193a5fbe2b0a6cdff1d4e8e3654d4d74ae57fbd8e2582cced7c52051797b02e0637ae4d541cc206a754e960bb8983b341808b783032236a3ba305d2a5460a04da0da20f09a4d4f6c6312435e6c4c6b45a8d17998f969964284fa49cfa49c760dabcec76fb87768369f98153bc3ad86a3bca1acccc12ca8cf61b14d00a1de4623a372364bcc893983fca31b111b9458d809ff8ec7716190987297326bda2bcdef2faf880fcf8cd999d32ea77ec98958cf30e60cc0fcc3055d978fe7037e1328ca6c4c4134afde8d8ae5d71811ecd682a48230273bb9264eaf971717fb815eef06ac881f3d0f4d859b87043d7698ce28668bac8524b1d5763caf11c0dc6534c62c0dbc2291bd62b5d145fd10553b6eaadb1f6bed46b96458fba4bcec7785861955f68552335f36c687735425b9f9d17f2514a734e3fc385901219d20976df1045aa5023d76750a5cb10e70ea07f1c197526f5e71396177f66443999abc0a008d400da3d08c9740cf6662adf93dd1735f8c262f58241fc6cdedc9ef7cc4590b8aac248a831fc7476c0e26f0445f9ed723cfee1fbc2c8ac6315e14bb2f49c2fbbd593d870b8b98cee16f8adc6f841f236e4b499571094e07ad82e44e57f16f728a7187d6c1baf3cd1315b1f9ac4b7dae69e39efb6a03176430f69720e0ef879284f59ffee4e6720d31c51753d666681dd15e7ee5340a8629e8863d5e86b4088a32de13e13e0f92e15511e9bc4d57a25c71743e9b39af867dc17ad3ebe41b9c8f64d1c38573db395382b55a50ec279030ce8f59ba8a13525681efe3862f3c46eddcd3dca4eb3a191771723d3a2875fb2074ee9867632eda4ffadda4c64283202cbed717d3ebcb2030ead311b9c2ca56169f7ce6deb9fec78a76cb9f78ab8251b83bcda6dcdb0e916ba12daac78a151eb76d040507fa29eec866225f87c694233ed07362b097aec619f5df3dc5ad0a58f0cc94eacaf252f1f9dd59bce58904ff7460052a5bd0650111c105aeb34485c4730ed6e3e1c927e2cd956d1b9404fbaf0440afad135a3f320005d666abd4c69e98edcda3691b7e69b2c3c88ef5e1ab9062b0b3f08b8ca38e8f6f7b4d04f3daa358986a3f8bc5f6a13115c31e454c0dfff61613d0dde9dcf4516bad111328b9e88f262988e8c05e5ffe1fa6ba708f5fd51c34e4757814ad0ea5e6fd33cf51b45b84c85882406cd3eb107b96fe546364a9972d19022be3b5121ec64c6454f3a4f9809f49e11611b2131d5af0aa5e65c156f37a6062aa395e763522fe6b1451c0452c6c56443087202605ec9ddac8635e7fc086e330a7d22b15851671565726b2cce451d6288755a04862bc7f934b99de6809533c05b851ed07faf408f83fa9c18f3ed65a94e9788f830f5bb9ec744b71f59d6821899f8640441d47746497dbaf8e9ddbd252e04a5e4b313e2580a1a858e4550a1e5c09a04eae54307fc047073657405630200037f019cde9197e7270a1c7d726ced68dcabcbad740497313348e7ce6ad7d29f0bdf616a31c760921e4f9796161da146c841e86ee758cfe053b88447152770fa72c1d2b4d17de0698a19a7f1cd72c95a4b3851905c2a7a76d894a2885cc28addf607fc0470736574062103d559d2a5a4180f418a69c4bed5508971cda9313722fff71e053d3d82fee9d7bd07fc0470736574072103701e53a6d0b960398abf678382a4d17c5c153d1a2c8ffb76b302058ce915bb0d07fc047073657408040100000007fc047073657409492000000000000f424056773886ab9ae39b4056b656fb255a3af50694cda3ff4d8d4d450f15ffbbbd9043f90fa6f45a7e8563f8d305ab4b991a2c33e51b65f94230c9bdd457a3b31bc007fc04707365740a430100017f113b550d4432ae02cc0d943900d25f6833c26bc1df867fa17b36d215044f889bcf7e3dc63814f6d7894608232902f7cf313b28194f104be657b44bf54471c300010308c0878b3b0000000007fc04707365740121080b9276ef17348a17b4d25e1d429594891f5bbb07fc8e33e4bd35bdf8296b7de607fc047073657402207f8f32be9443b0547b4daedefd9b6b0b655bdad96759a57569bfd429291fa44f07fc047073657403210bb668bf543a321a7cbad607ba5714cfbdff67e8d04c9a4dc539ff7672b84b19cb0104220020e7da55d19cc85b0420c539a90b667d4d85f59ee0ed417493a947c3a2256cc0aa07fc047073657404fd4e1060330000000000000001a000d4005894c852815a527aeb01259da98708628a2f2657826496e2711f7355a941f50a31be4e1df7d245f27e22dfcbb737e28008eee8322b6ee9755cf564411c5f360cd8ebd076db3f857f2a89a6dc3c84a200a3895a0a68b8dd14ca3c294eec37cd45d1cc69ba3e5a114c8a4d8e32eb79cdf984ca018052e503a5a6a71b49c78112909d2f1b1fe97ba13cb6804156d6202dfe1275a223c3b99f77964f3eefe61f87d483f5d8273edf67f4ba970c9abc27627bdac0fbfccdb6582e30429d2d82ee4658e2284927f66b3fcbd59b8282ea88e37198b3e6809a79e9be849ae2080195239e82395ea60e837e3e03459c4a635ae8626d29939026c1b69d6ac6a32a6a8c8a3686d29c636841fe4ad37402bd3c94a58b46a74898b614dd318211822e2927db89bc8d121373ee1aed057436ea6bc084e7a38d612fb9322265c7b04ba2a4187cd70856fd276971057ab4aec79d4e9f1ca9bad675c62c481a621f23ecb7b78b72a90448f40620152a603d4a150d1fb87c37cb281195045dd4730899f58f4813c1c99569828f377e6973bdaeff1bec942f98038d6599a73de84ce4c350ec161074fc30b151949f22687b9c50d05e8339c048beea2e944f77f601797f7fe64cde986746644b4c5f0baa42d6738add8f9773e7ff9199cbfa3bf03cda1e8be64163a3d8cff0875ea6b495e372107b5f6e9602fb6b0654e5fe1bc8a2626e4c9ca3a33bb0d2755055547dbbd2b1548de0b9fd7193ac0d3bf7d4ecc929c3ed0b1112aebe26188476f63dfb75b12187242436f8bcab54de04510dc31f3f3f14204e8b50bf3594432edebf93b26903f87c1dbea50dc9af089c4092654250e1505301daa5b0534645e52f2d3c36e7af6e9e04f7b54111282044afe94411854aa73be65f18fc868f39f79e312f62c4250e61a2511718808980fa0ce8089437569c149f4f9381db1e12e4d2d1ff682f47d63c8cae57eadf9cefd30e52128dceadcee043c84d90555b10095765a0d1f898399cb734477bc068fd2b37f47847332d38182cb23da3800c56dcb2a074aad8ef25d741d569c355fd4a0d806cfb698151873d1e48e24fe359b2182c8a26a1ca1c21ab609fe19dadbf5f8e3ffed3fa7679363ac7e303eb917554fda9d2bbaf6c053e658dfeeb88448f5fb017687f3eecaa3e7ffb6188c18e55678cbe2328a05263a987fc502280d070f181129902cc0f5e415e13f76b3f58dd257136ce579c4a999b127374e2bff94f694c456247c502239e301d21aa870ac1021b97b11a7d1ba0095696a50fe16e888616548d7eef96efa59cff978962a7c6f38aca24282091616f6acdb4bebedf236c043b36a6f12eb82c2c589c6a71080a46cf27e6e663060788c2871ff04d26ecdfe534ee254dce0328134af51228c908c5184eace62cebf5ff692097fc2d272a7275b965ef8b5953fb1ffe8d713cf92bf4b3f6a428bfc3aac0e67aa93e9571902dda5b1f66ce523109092aca555f007ee5529597ec185981f45602be0a8a0f9e9b75c477e0af5d27e546adda7c4a2776b97b9a301f0b6fc15495197cfa6f2975d19bbeb70db18dbad8d0ed06176d97c066ac19d4061d7f7cccedb352788ce5d15c26fd970bb68b879b5571ec5bf2917d7d58249fc8f9b2f5a5efd5e3596451a7be38dd75525fd1c2b0444ef9aab646869322c23e52b1e0b2b420d2220a4c150f0c6b8a4bb245282f546abb74f264b6c75286d05fc7bb2c266b5e9864bc6e9b45ffacfa2352ba898178856db19b41e7e6d90ba0e14226e698ebeb02b3fa349e8ee09d7bfee08a54763ac1db861aa0683b78f6bf07263e3cf0fff0b91225e5e009231155bea60b2e661e7b04d8803cf0c89192cb8f70cf16a6d256bf31a28d2203da20d7d33c7a6f841169a845ac35c8fca9253e807f72e96355c296323f6e0a1d48bff8c43f55a594fa251f69b907d9f97e7b2feb5296d12d331b34ce9107df9da5671effe1120e078956b85abd24c8cc1276d648a2c515791fd40ab74a5c46be36a6426b2c992c22cd3d96d61ddf089ca711c15ec60538057230a2e96a92ccfd605b09a4ead233440b7fed99abc47c50263728b18b2bbf79d814c30b5e96a72393d828446bc3ff14bcfa0c4530b59750c28d7c9639c961ba47320401566962b9fd69df8e87719e0bcfc5e9987d1cd9ff4407dec489ec6e1c0a82037f7f0f94d3a06d131876d541f3885906168181c21a395a51fcd3e2efd3d116948742f8911cb892fa7d4d4d5f83e86c9334732191c632a2a6a74d7f760ccb95e04ff59f8e207ca2491d0a6f48df78254a0019fad13c0251e107639d5669bbe90cd0188042c02eb726d3d33f69e5ca06ac96c733811098c5f9a09210b762e5fc94c493552e060058e811cd302abe0d60be900fb0158126a4d3c188a65ea6c2620aad9c73b0d452413bb26c5e6c3b2d885731bbac7abbd42895d5542bcacd1a93c405daa46bea191af513b0bfc3a1f992700daf4967cbe498bf1df5bbdecbdef4614af954060b7cb7de6833dc0d721eaa570659400f452664ea7c88e410ec5c35e300465ce779d76b0fcf8ecd375f727347bc46e069ac8ad816d35d08f4da02da77a75447a3da203d8ce3a0be9093dbe938dbb62936c7602f9bebd69261fa9fde170c9fb22a345183ae119af5b9a47c1cb0d740ff9771a27493c9bcb0ffeca14c376e0512014dfacbfbcc9d0956db6d642cc892dd7d8a5070b054f26e977ee6e3c121b16163d8ac151df29a5b8c5601d3cba799ceb10f04141c3f6081d7d1b6ea22202b3aed1f932f8cec9c65eea07befa558159499b1033e235078fa7e16be66be6f2ded84e8b47708a59c0c707fd79061945818132b2f2e58242238fb3c3410d2080cc8ff7b9a689d259b2bb63fb40f1af64f19e4dc53ebe3bce60977776328ebf6dcf24cac233e04c5df29d5ffed25609e3b8d96accff140f9f6acf21d9951ccff9f5c9bb27b7c8991b5bc8c2dbed6ff31b2b6e75f6f620ddf45cf6f67b900678567745e607b42d0bdb9d86d80eed1a1923c2386f371e0d2f11306ded8684325e46bfd979059ece5fdda6ee9b5ffd0697a54a64abd7599292509c3a82bb926b743a91affe05b7dfb350b605521dedda17617dec004a378b01682b2998941f02dbbc804c3553ace603226369bfca98ab4aeee767abc892e00f56d79438d075692a547da501c50289e91c3a891646daf82de39c7abdb48b3663bd870eaba0393b66dc7723ba77c588f5246fcf7b877e296fb784834e2cd679b54141860f4696b1b1ac330edcab74b59aff6fe2e36b7e3a459bac93e5068785f455d12c51b486f2063341113b6e196def028901f106b9993e4147ec924af8e6d86155d8dc2aff8b1f9268d9c75e94e253ad38ae65a8cd3cd19161dd5258588f8e74f3da7bc7df4bc6b7d23de75a02c87e8648a7bbd55210110239ed6e6214189825dee3bad6a028c70a2bf249b2294234798311c5695fabbfde68637ab9d066fca327472ca460468d34f74922aac4f1a64ddfdf7ccd4fe12d83ef033b901384ab8149ab50288fcdf087a50c0271046e7824c6c69c33ce1179c9e87dbbca60692027c1c54481a8d4909fcb1f2565c47d50218995fccd8cd64f51874180fd930256880aa1f696c321790cc5c32c49d146f6cd0128b18c52d00417adfc06aa6e279c03f5b21daea9a33390a91dd3c5281444d023362578aa83eb3a81d57ad360d337ab374c1bb3b251a51fef636418e1966cea1b2135bf444a03c39f4619c7acaf3c7a5cdfdf8a3893696e5fc076e915af6ef7817a32f5c815803e92810abc3ca09e421f8f039206e524a47ed746d3ece4c67e1dab74477abe25707b92598e71f6011ac9e3ea85417a6e4f43c55f158c2c73776c63c3af8fa472016ccae79a2b9e99d8c42fa1cd72ce8c9cb3c535719e075a0adf26fbb559ef129512833698d6892ca1a37f176cf6a363cbeaacf40813114285b032412f6d98854bdd758465604eb2ef4756064a16cbc02763323f29722e625ce895315bc6eb1ef3aba39543df3668991b3d7ce33c68ca975c18823cf37e8bf38b87ded0527d61ba10aa43db45b82e23b1582da992b9650f7d146eb420fdf679eddc26eaa3639a6aa41a2149d1b89057a05552b772504cc29132b7f6b3eeb5732a9830fca236fd41645f4da9b38b2207d931944a98ad45585eb659b7e1e43fed797c41705265bd155174f52e45a89ae79e5c1dd264a39758ab5ba42f6b721b926a06d45ceb114a0ad592ec71276bd7fe1cfc592324e58b37500b106355dc6ed962e1830ce33f8a18a0ca236c3301b0bd9029c6dcee2dc37057635fceb494a8352d74963fb2e3f75b91b19bbdaa49abbf11351f88b4d2d0550320a8df123289cb16e1a4de9e71974d920d2b28e59037e3a941e0f7c6b2265ee281d0f9da960d2b707fdbd0a58f0a19ff8003ccec3d1be962eb47f57923ee2a1df81cd2e77430eeb8e0825e8cc93ae0466a19c80dde5b8872491326f877b27db9543c495ce3c5965bbd48f216390115c7c31bacb20bd9f11267d2aedd4586ffaa27664991a100235bc197ea189840540fe0b29a07f24c400ffa2bd81eea1d15496bc14a65fea7e05604f987cd847b0814439e09ef47bdb3f273cf0a56e339e7105542a2ea1fdda77a2dcb792e474cd086341b510cd5b424caaa98497744303dc149759640302337f8d4038396f776dd79fc41fba310214a60ac5e047311bcdb5daeb1d8a601368fd3d84f981aa6fe7fc43d244beabf0a386414c569c8599918f8250487c546f1dd49a7793061a0107ae626beb6bda487f633b1abfa389e182f4f1aa99309ffc7c0b69344d0e9c5c2feb35cfe38f33c6f8b668af1df1bdcbdb5822c6c1931c7ca25258556881584dae524b35c0fc1dedf8604298014dcdfa39c3d38908364b01f55062bf7ad3ce8f85bb765afed8f365b1996a6600d39105203dd47023b5de1e2c2ff78a2e4b1fd6329afd0e86777471721fdf55e7189b18718b9c7d6f7d764b6bba82ea9eb9cd9dd9c09b9ff5ef25b3aa8ab309e6d85f43d6dca7681a49975372a9ee196f917e4e6b390103537d24a35a084c5eb5b378dd1654025fbee39935f599bd4a15741ce19479a93dc9489035158fa0812b6ac13c6f247432cf8ed3a92f86b372cf624e5b7b2a419184ab9b333a461d5fa9df9573f67212435ee96a59a020ab3c1dc0c61440905516a8b6f341e4d9cceac3129b6b7b6b3ba2ebbabef7857d8d7594f778163a5f95f9b443067a94f9e0fe9db323e25ccae107e960ce163d62fa0c6268d99cdf208705b57e3869a8e0687fb95d9244a3fcb447add7b7dfa850e9af704e2619821754988858693e27fce4b0b3be89e42def5bdc8213e02489179150764fc0a542e382f52e8d7cdb80e4aa78ac9b3d1d56ab23c8b885f0f173c4020d2330058dd37a34c0c1fde5142b3176254a6899d47514d9c2e68b040104b134f331dc4d9036505210d4944ab4b7762bbfa364fa3d96c7f87e53bf71d5a5c3c40cad698031e95ff17922952b5d1f9337c93bef79c09d075ac5d73b37a317f6c4d767a183283d1bbc97560d4930e47628d489a2c28267ed8bf0922b519eb3f72c62d710f81f07dffdf6d41b5ed95190ce20e2b94f8cf525be8352568b59a9a9db7840636d2b76494fb3f791bbdfacaf5541ddf8d7c104462dd1c6d3006bc386ac1f55fb8400589bcd895274de80092f69d1c759fdc3c31f2e1681ae75689e587d9b11a5673e069a98c1f77b538829c59e64bf65c1417abb2d8f52b8ac6c4bed00ddbb1a1d04d05d874315f55ed580c6fe3cfc967c15bdfda8be76eb1c77e3a720450dcbce40f772c28097a0925aa159858f38058ace779e4d8467de433e39518554630649613da5d20707fc04707365740563020003891394633c5f31c9ee5ca072b289c5be81c8d6237fb8290032940c0f535b9f72b4a4b8e967bc5c791a60b0567bd7c2fdc5ec71eb54c8f0770c92f5488c50d1416d636dad9c610e29d32d95c6ba93f6ce39a14fd1e6a11c2934090f494dd860d307fc04707365740621029e5980b4f9b9a9fd568c1c4b48631a800c310405ae8b2ac41ddaf87add3062f107fc0470736574072103504bd87c31711ff592af95f3c9c4f78e63f2f30805bfa95bc2d21e5a2db5c4da07fc047073657408040100000007fc0470736574094920000000003b8b87c003c8a469312a60ecdf33a36e22b37eb9c3e380ddab84491cd12ef7c80a6565124063d8d889bbc3a6f2e0d2fb66f78adb6d5a43d5fbb716a5f09a0db9788282a307fc04707365740a430100018474c718fb7fef3e0585e56e19e551b357042f0195930751ce4d22721d93302dd78d263aa3c247113a0958851c182ad93f59216c95ad62b808bad00d4127fdf100 \ No newline at end of file diff --git a/examples/test_vector/pset_blind_coinjoin/pset_coinjoined_blinded.hex b/examples/test_vector/pset_blind_coinjoin/pset_coinjoined_blinded.hex index 3fc78cf3..5b08a2f0 100644 --- a/examples/test_vector/pset_blind_coinjoin/pset_coinjoined_blinded.hex +++ b/examples/test_vector/pset_blind_coinjoin/pset_coinjoined_blinded.hex @@ -1 +1 @@ -70736574ff01020402000000010401020105010501fb04020000000001017a0bb9325c276764451bbc2eb82a4c8c4bb6f4007ba803e5a5ba72d0cd7c09848e1a091622d935953bf06e0b7393239c68c6f810a00fe19d11c6ae343cffd3037077da02535fe4ad0fcd675cd0f62bf73b60a554dc1569b80f1f76a2bbfc9f00d439bf4b160014d2cbec8783bd01c9f178348b08500a830a89a7f9010e20805131ba6b37165c026eed9325ac56059ba872fd569e3ed462734098688b4770010f04000000000001017a0ac55f449ddb6853f2508766d5afb9f3b45e41a8ef5368cad75fb88e5e249395d1097d88c92ca814a207f73441c56cee943f0bb2556da194c14a4b912b078c2238ae025341cb5e4e2d8cb69e694cb20e5ea4cc8ddf2801180096fd071addfcd8bc4445160014011d384302576b408aa3686db874e2b17cc2b01b010e207aff956e6c2a379543b1ec82b06958f062bd9f29aa1ac1c98d1f6398b65a8555010f04010000000001030820a107000000000007fc04707365740121091517eb0e8ff9154ed835c45bed0856ff6b385b12f7aa224a1d91a532dce77d3f07fc04707365740220230f4f5d4b7c6fa845806ee4f67713459e1b69e8e60fcee2e4940c7a0d5de1b207fc047073657403210aaeb20261582b6a470b523b53d6969fb878704689a6ad0b0a690ccfc39b2b03d70104220020e5793ad956ee91ebf3543b37d110701118ed4078ffa0d477eacb8885e486ad8507fc047073657404fd4e1060330000000000000001c49a6101a4a3a122e2316e466cd2d4eaf9ec9029024390d41ab38146cb008e124d94df5c0827b57353b88df660dd6483ce69f89db194b0d7d14ed04f67059e708fc7636fe37183ffec38c28168f7c0680ede63e23a53ba0312fd96cc47dd3e147809c8e4642ff5d4ec0e280aaa369b08f41694cc6abbf60716678f7a83d7e163b34e2fe06c203e702e52cb69a5bf1a37aad479d9bfe7feac1a16bf927b3b233e50a3f86a07d6cc69454b0051df0f2941fe86e98259b91945a7fcd0e5c64c4ed96a302f931c23effb8ef97b4e1e3d74b0c392f686e49cbf255961fa03fe32cf60bc9a030dc511564600412f8f57541306f83cc6e8d3bc84796e7439bc2afff98489754bbfb6f28b2c65bda4cc8d5514e482804391bfefe3116798c5f477d67c65c4f82f18d10c864a59fc7f9de325922415422d0c57fa70e94f878acc88d9389dafc99d584194ea5329e1fcc5a8967fb1e7c7a85384d1af35b0baef473a948d4f2c02403e0405160d22e793b079cba61377a2f25a78da9233bd6706192d32f80b6f51bc86452f47bd0e8e498033fcdf84fc16298b97d6e4dd4392f37869dd65af84394fbce984599da74907b70cf0bf3181dba69625aba09995afe37213f7a38bad1e4ee4d2d5741ca334d05f6fb5ed40847ad3cb40d75f3a407e669fa77acae9c7e33fb76a92ba445f6b955e30364957a448702ebf2193f9cc6bace952cb2b36294b34f024d209aae3ffbc8c3d3e3e3984d60ef7759c165d5e99b90b5843a706be29ae6c136117196495f8f575303b156b62e77ca6654975296092a630950283ea808bf266935c5f9e32ef637fba8104c2e766101cde30c48bb77dffed39b1aae769bd378860cfb4dafcc4951893e9549e84821ae78a614c99a368336d86333eb48234fe649eb911519628c65120b395c9cf14a9f2d9398ba6dd8c3ec2ba00bf9d18dabd8162e5df48ef3f1e26fc8e068d14391b192981cba1b9e665649952752c3038aab5b4e108b705c1b90cd83699a1ba2323cdc3eee1f2f1d909eb11da0c3940fce919d65c4920b22358995655410aeb1209a8c34e8621bbd154536a26d29a93c0c4a0b9cc0334e0c5ebe960b3c5e49c305c6d062eb918d5d1f3bcc95c900e06f737623a06a799c2a6bc182357d3f88a059459d02ebc492e7b9b43b1e99a4c8ec157483ecb70ed81e0e70855950f87ab444fdbbe20ee9a34959d63b9569221001942118479bcab4acf18dd56d7d768c066a3c6b2467e5dfba6b5ae5fe5ff1e00489e732b61899ad3b8c82c8ceebe76227ffa9d57003c1449a7d34c71625a1bb8420ed046d355af63c8b3ba4983035de467716bb34f7993970a019c9c87d8a6d66b52361a1b10352bb5eb7f05ae1aa6a487fa3452f8d25a5ab58394543ff0a4e78d75e47324572b42add9ce1768d78d84524fca712965346a542660648230c914a0ce93b460687287a4d420a4894dad96650aa4b473c3a01b1f561ff4ff4c06c5ac946952c9c009c2aaab33bfa7cec11f6a24d75d8112732af0fb6c8a0d1cc8d7d202f4cbcf5810f2d1c8c6bae7748deaebd2174a39828d11daf145e47a16aa86fab16264292ffee07bfa452dce579204d91038939ee866f3a0c46dfc7fd6d85409c96450042920a80a601d11a7a8ad231c6d996a79e6fd710969848bd357dec3b7d20bcd1aaef36657048000192f7e3f0910b954a943f2d9026d1e87e080f2b78299a00aa2c7d86cdf66b6d98bee293b46c44a3bdfa87cfb6f1659d213460596ab89e90c08151252e171d87a4406ef3f0185e21bbd5db0e298874faf77e743899e2af8eaa4b2165c8942c1bc488723d684ba8096d64b3c032e9d07ddc4b8a5bd1027a54ade8e56a73c15fcf1f204b194933c6dfd5a78e449987e682c81970cfe265aed282b7ddb9c7c952859205a42ea2c24abe55883acd0c593edec197b9cfe5fcd56d6b867720fc1fbae83909b65f5adaf21526cedeea64a4d495b409244fc734618590f0efb15d76740234b19cebb88f70d29679d2b0b34a739bbbf2d5e9ff15fcd97df5e1919eebc2d1f469f35f024cd79357963374745e92d8e8d1e29a286f6fbeae0fd3abef755b514503acf5106a2fbb2d2370621ac3c3ae34bb6f14f6e82c71d01ae33a1bb629e294022ef9cc50d295bce35cde0beb14bbeecbb6cb189ca692ed2040bbe0312e9f446f2f7394c6daa130628a03956831b7ba63f0eecb5caae6472dd44459d69b994917e08e05665c16b1e988189f468b170321876918c323e52646481532616d4361c8c2070217d40e052a6dc487c1ef9f030922458e829a3ea15d2670ac3acea32e9af81b2a455d0d63bfed89e911e19fff080c7e973be22061348266b26d3bee8c4c3bfad3ce0aec84b25e3cc41b46a902f9a119775d0a903a4657df112ece8e789aa7995fc90033d503ccde74901b1b40c440936fe0dba6444eba823b328c8c8187135be38a651526cd1e159ed806714547f09f45be5928efe384e91ff6be03ea8992b35eca865ab4cf5ba7788ba95642fa530f58547fe597cc3dd8bbe223bd008aea8c37e7433547d2ac5cb716c2403472d7a96a76d41e9f3b92a7db1f7694e28446bee478bbdb1c2c6fa787daf10ec2f539d87e3d5e43ebdcd43f2da2736d15cc9708b74c69a7419fac92a3c1c307867ea243ac4401835ecb459a888ad58cd2141808100afb3e3bb056fd9f42b2df7d6f426b4db8befab9582cea9954f58f2d899e1ccb4dfde1a9d7a8b2076403ffb8c7e14661038f952dac328d5b21e7f1e4258ca8aaaa43f426c8213383bf60d60640a9e67378097d5f07e05dda7159ef477439be71c28904ba4226708319cf854f92c62f51d7128338578eb259c0681e7bdd27426fffdee0081fc9430db6782e2b013dc7e76e4ed043dfd7a2078b41230ff437dfbd240d3f11f2063a808ae011147a4b6111b4fe3339deb4c0e5bed8ab5af0a991175ffd33941c586a1da510774e25eab6858f1128cb7f7e2a53645f909c96a4c9dfb9323bafbb9d75a7d979238b3da069ab16fb7e621a7a99195b78e11f85262d9d6413a7b88ca0f6fca17cf9f73a7332e7733a3e153d4372dd2e6d9af0b7883a99c0b5925f817422085808ef25a71bdea61755449dab91704b250ea29fe5e66e776217fd38054bce90e2ad5d8ceb32575834ea5e07542f2f1795c2c1df6579b7dda3b3ce9382bb9838e7324251a9f7848c56cf213ba968e632fa9f99e2a1f4f916231a70ccaa450fcf8b9a2c44f4097b65dc4fe63b218b6a3181ab5a06d69483442ad61277cae828c7b90e2caed91e8f9f02582a642fdcaf72b4f1d3c14102d2663726555288f48393a178ede1692d3a8209bda7e3a3e1608c4c1ee2fab5a4ce7960e4dbdd00579261cccffc49cc8a876f250833694809739ebe0a252951904b994ae9c190b0cc612e2c67d25be98720887dd8c9964ca698fc29151f833496ec3959c05a8785c72bf0f1c9c9ea41616c9aba960ac21c38f71c82ebf3757e86da00bdbfda319940c1bd8e468f9d83654d87d6c1a7d85cfcb233841ad0118e830e333d7bb1c19972f24f6efce9ed585a915a4bfd49518c485f9ce5c5df734f32ec825f8f259ba25cf4b9d0c1c1118d42d7110609b5b44c4b0d92c70101319793807f2f209e7b5460c9ce8993a11fc9613c96735cd7e2a3358756e0b4c5e24104c76fdd19bc5ca4123f6d07557bcc4c350b3c5b74eb45418afd2213bd52ab2d71658a59367441eb73c37cea82492073d2f38b3e446740b338cbd202f28dba9004044ad4b5b7085ff19a4dfab50603f4344bb2526fb144882695c2a31d86a4163f092e697065f55290b99167fab57c5f22e51fa1520ac48ce50cf54841ae22cc480ab4abbf078469e65a94969e510af6d58c50b140a38c03420d33f9faeb35b44cecfa0cd19cd27c20026bd19b2971c4f0d32456ba4dd4af61bfce234b471c54c013f7183559e4dd12e8fa1c297733da6d20c57b838a1db8fbfd4a367b5969328df2cb18688b7099a504e559af5edbb54c7b58441ae15c693385e0ec40f3043fbb0457292e82cbcf3afd3b3d9d510691ccd1441fcd45c9342522010f140ddd6ae4b79c326acf5f2873031911a4ef7b53363121c20ef450e5f64a63729969d038be74661ad9260ff39d738a476e306b15746e4c3a72aa2168a8c276de4b3da973cf8ea489320e4d1df7abd1f6dd38d9bfffd4ad26c3f9d874377a4718e13e77524c1cdf751fe433b72cbf89514103df8dae6aee905f24a1222633578607909f4473397f0ef7880069eb16772188793ae979cc9ba90adc6df93f059726f8ca4f94c1b986c8ac1b0ade97c23b139d303fb36037939c63bcf0b0a33cda54344edbc759a3157abddf7afc3e034ad2881a55854b6ac679316d99255a5d0a93a96b0b1efbdf8dffca1c4e9c6ebb11c7667bff42aecb0529b809eba6f7af3eb794614bf4dd266a19248af7b679b5f5a7c5896d3ad9fc23616d579e98d7959793f9a4d96f058544e38108ee04fbd9b91249633cc405c0f3593d4a337ae3e0115ec1af1f34f96d633044897193b6a132f29043922fd57866d9e004d3aefb8c36e8145226b1dbe7866f46790097f1052e6b18b50f6c83d4ad670dd0784cc73662481f415d03348427054a3eb50695ebb104fd45ce6a4a23da4386c3d384cc8bc7aba67ddaa49a0e49e98262a55c7947d1effabf398f919862fa38adbb723b1b9d1526dc11f970444a05389b3211cca97e62f94c66d785a96e8c507cafae02b6d0dd8fa0df684b3ed339374850a9e3d540eae25bff5803dac9c5d8be61b2bcf2055ffd946df6f5ceabffbe84dbea695e0b67f3b8bad1443eeb743ff7e4943140c036832b9b5344b8db3d85ba958f6935646b601b2fe497ef8ea1645fe41760c70610326c5253cd8c84831588827fe8ee0ecc661b87103e6e99f567308f580e2387d6dce7901883b8e428bbc9cbc19c1e850bf598f204258c9b6f09c4334a8f95021b94b05ae197dbdc972d6bed5e8452f39cfb98fb60b510085ed739dffd4241ed0eab4962d34762bfc8cbda6dd52b3a324612c32ed80b9d77c6c41443a9c2a40dbea51da644dc6becb9546843687bf9f4221b8bf436863833f258dbe98bd165488157301d74ff152483d6015459b11daf5f1af98293264d91b96f63885d7fc45d3ba117c22b420994b93b0aa207fd221370a55bb1cb130314ec9d21624a01136a5f51a5d1e028585896b7ae63cfc84c9f493430cce38d1fbfbfa7db9dfc0479ea027ddfc38c13c7bbe957b04a31e90ca14aa4e9f9c12e339d09811eb18f32151835f4d396da9decad13363c93de8d7499a941b168ea2367dfbfe3fef4bad204a12bd07ee0762de00cc193707d3889efbf13ad72c54b210b066b699e8f7c67b07648b743fae60b5f09f3455be11edad01c5b4a70141f969253a63754ebedc338e83755e8b762b023b60abc12be5c584a57308b10c8a335666d84171edfcadcdcd17a6fd30450985ffa2e690d00e5bd21169a0404777f51c37cbb89c745559bc7e81814d6010d331b16ffc4fe2e88f37256e29871a4f0f8c959b78927ae0ee449559e3f895327227e859fb6cecb20d4e6671f4d9d46a76163ef3c3490d1801ca8039b5934c1293deee598acc83a4b776d335912d0a2c602c653f8f3e9a2aa249958d94fca07a4de4366cc5349aa2f3f599f33bab74ddc01944be806a35b5141c95dc778e6ec102a609c7346211953510d7105d436112868d718b72b0b861aedebb4c77d6f2ee6b7101bc00ed406a89923e19fef2dae304f528ab56e9086fce342e4f19c509809fa399b2c150e6911ff5b96ee8627d226ec33c0b84c04ab0afcfc4d89793cfcf6111aa8fbd217cf5706aad49d4ce6480b7e57fc77c07fc047073657405630200030ac6a03fb2c4143a07d1599e22ea844e3594b77f4a960e172b3c04a7b9f7eb647887e94bdae208da814a7a0d2b216bc0a730da54cd34522ae1b71ea70a305a217014067b0ed40a77a3d1e92afd3c447018c8c60d4b8e0ded12f49671bcfa36a707fc047073657406210212bf0ea45b733dfde8ecb5e896306c4165c666c99fc5d1ab887f71393a975cea07fc047073657407210325b27bf6f8d1b06dbb69ed3944095d71b9a4558fdb574e2f032bbf1adae138d607fc047073657408040000000007fc0470736574094920000000000007a12018e6f3734441bfcadd5d94f97741e750dd28201a658d4785c5bede038f1a1179290dc688efae09c0a437af462dffc2fc5adf6bcbbae64cc40e099300c98e4cbd07fc0470736574104301000190d59bf3b61acfc27a23ea0f5994bf35cf81c62489a2f658673775457d0eadd732c4aaeb4275077bfb347f483378e6fa1570a1912e2a8a725a7a76eb0c2e23ca000103086ce2ad0d0000000007fc0470736574012108ef054b3ea0c1c3a6eaf67bdb0759cc44d7fa953fbe2df1df4d39a59dd6cc9d8f07fc04707365740220230f4f5d4b7c6fa845806ee4f67713459e1b69e8e60fcee2e4940c7a0d5de1b207fc047073657403210a93480fd89d465d14eb4e976496a7098fd22f5072f5740d60d12eec8c8de917710104220020f6b43d56e004e9d0b1ec2fc3c95511d81af08420992be8dec7f86cdf8970b3e207fc047073657404fd4e1060330000000000000001ff1017007f0c699812e97d8507c899e760dbf4e630430cbcec3bbbaeebddc10f855c3ff8c3e5f54785fb6f527922b522c7d4cb56bd1e6e74afe3e2149b66d3c9a2d54e8255aef17ac0f30687ddc5425ffb31ca3b51b9848200eef211bd3e0f6a7883ce56d7ae74f382f67bc67f03482bdd1b39a6730b60043037cc4f53bb18159aed2ff23fdaed63283b6c97d14ea9674784fdd0e6e38553e96ae815338ec811fd3be74ab655791568137868d626a13beb59e019fa445c25d5b289cfb84517428c7ed913e73ce4a984ecd5ea6e307553665d6e0944e9698821d690b2b4cffad1e4b1e7c987229488e01c63c3244c435a35813695250f9a665e8603fdcdf2e65e5544354f886ca40a85b863d45221e536efde55f7ec8fa055e9f07bd988774ff59772eb96b5e0c79bab01cb3fe141a461dcfb03a5469f6f39f23413abd729ff9a450fbe564d8126eff14f00b9f8ccb05452ba471b79ecb9e9e8fadb67427bab207c24a0c2e6799da4a052ab408ddaa8cb56f1dc4bce5459a70aa35b87bdc85798e9f0e828a5c36d0254b98769a3c0fce7bf97188afd3d32aba2f5a1a52c057204b086c04220e2061bf68e76db32a0a0b6703e3584a652a72b32404b307209cad70fd4e451441d2aae539a168a72cc7ee2a51795b8325a7740e788a897b4c2ec053df02b77996503d50131f86936b4e0e9ac07ac77e2fb1171a36728b908e8e27e772750bf63710a7c137d87d41582da6d6b0f1c423e4a3834e7c45234f64974d2b544060bc82c80a74fc1078972ce74e87b71fcca7c63d6a1c7bb852cfe3b12751c9c02401490fbad794b90e2e7aa304c5447f4b37d92ea304f52580f38bb892fbfaa01e63fe6c2dd2b25a092bc6a5b0cc918a7e99f68baa286c19834e738cd400dd452b60106bfaf25d2da9767cae07bb82eae3100435d1c95bb9fe2053660a3991eec9b40af76e8d7564c6d07aca2da552c73624cd756dc72e714d8e784c9efe415f12d92cf56a02e886c329d8b7ea996c465c45da1f84f56226e816b3ada59c100177d9cb4bc0a593372105fea9e207730b57ac2cd97a4baea2b1b92cbae6977842bfc6279cc260970a41f9b8641a576d80266715cd0e56a2379b854d607a9cbe64b575cc70855b4d46bcb1c7df88dacf065d7a6fb52c911f60dd54100225163e738c8f34c820f285ca2d2677dc63e12cccf9f1c8e875af4c0eed38d15d8b685bd82843ab1e7d96202d411e839db71ef148c9ef7dcf1f088ff8f04c0d408ee9c8326b9dd73683aff18a7602064c4eb56c47b525e1918315a189e48651a944379fba7d5e1473ddb4bdbfcea6ca72d8ae5c06a37093602c8d2979c4c41f6633aac369ca839fc15b0b06aeebcb7eeb178a4ece0d221a3bfee4b87a019df15db5b27f27ca9954b073092dad3f3f5cd8b78e715ec42af635ad915693cd547668a5c6e9ee375c3789578288d07e655e1f1be71313cf51a4e2b6f66fd4c740d249a29a85459daeefaa618f42ac70089b86f07d2c80eb74062e617ef375008d94a8e06426a044622f3e46f39a47857c01b5c3fafcdcbec916d15e7dca650d09324af15274631e17a55b1c251cc72f9154f940e47055c0946465f4b4b6c9b3627b309e9ff0066e0079b590b21a135ef3287df488acc3d367b7d4488707f888432fd38cf1854cf1f57e0db57468217b6b482639c92c9bd3f3556b9b5b00963700fb9043bf85e1edc39b575c56cfaa75eba62077492d0a764cc6737014d94b99696f7a9e0401cd54b0415c6c05eee5967896f6c8d9d49d6015b787c1d563022841bd47cc7d5341cb7eff22b46a99c8920f8e3ee615ccc873c8b759ae18e12a8ec8d684f15f5a48e3c1935c94e379fc6956c1e0f3c6167775c107aa59db7a05c9b4ed00cee4d7af7cf3ab32a185444a3c7ecdc24dbf766fb097bcb0af185c4015af363dd0296eb4d87bae677800fed3f31339d85a3b6eb688e6e8bc08b1b5709f482463b8d968ce7c0aa4396c5fbcb7e8f98f64498810ecca8a428bd721f390a95da48e602b04dd20716be3384e1003ea605d8492b649d78b331025a6977d5269ffe676dda60b3096e7e1e849d3fab7f176de7d02ddf036380cd642aea57b9ee43f7b8f53288870c1f1db0c2de7d29d91e57a56c6de7b585c35c3e01d2b3600e244193adc74100ca404534b5cf6831268d30b37184273fb797428e990952dccdd01476ac837defc5339b4aaed1d0af010fcf52d07fdca34210e9b7fc6e6ada5e9158b7d0b556ad3b28ca925cc24fe26f71878278f8ded022c8c1fa742dd44a17cf52cf5e5b7fde2aec0833010d2a70882b4cc1b294fb5e0a6d59f711f0c6656822a12707b3921ce5d835c23b1c699cd9fcadb7b9f2f21660f9a303d41ff817f5d1581d2f3d6c653de4a70ed1a3cf9af81bc07672467b87f38ea179a8d7a7c64dbc26d466de0a2197df8807d493d9f809513dff4fcead72c1c5b3b5460a7a665bb275073dcf64c941ae7aa70d42ea0ac1fb04cb9d34debaa6593ebe71c549f941827149fd76f9f124c311b189868e4ab43e9a020fee48e4d7c92008ae04ea5bb10f55e400c2adec535c35c44bc9e75e5547e79bf18e8d3a726522f1ab886030f2a4522bcc4c91e0f9657e32adae30be072fa0d54d1789f471e258c2191783026cb14c6b796f997c352ac64f048dddfcc745075967e16d7bcf57cd67798b66d2446d9445d0d49ed922f91eaa57ab43afa1ca90ba1e7c6c4e20416577ff70f6ae365b36adec6c485d598717bec53d58e28301589338fb62ff2b325e6a04c44a68fcf91f90b018dca2b35e5230aea6f5681977db3eeae1673c4a10b07efcc3ebe7b0fabe67737d852f50dab5e0eab00e0a42360fdc8c33de0180b48c59302a50e59f1579cd8a5565ed4f78c9d91a4bb25ad99c917c579016199e7bbafae97dc1f943e63c022542d8a29def106afcd48996a221878a5ef787259187846283c641bce500834dd452ccb058607f4a5ce5ec2a9449e2a17ea699a5a3d23febe7ae2fb46f4be2fe472f813ceb932b20f131cf799f3d6413b7701bf7c17518ad79c53eb9ad2866535b5b492006ddeccb7e59e77525d5b064696d91436a6ee3d4d0452d49f753bb7d26da00af042739fee0308571c801d6c63358e03925b76a1dbfbb1b6a9663cdb1a2a58f643f84365eab5dcd9421e73007d4569c68a758f0aa6e3531170470812cba605017082b2efc45144f885e09919e522a1233001b798a9e09acdf6a55b52a7ccb189bc52879ba263e18485a285db5b4e178dd4d69d873cb92b1dd046aa9f2905b5161195e750a84f56bb08dac7971ed8bfe11bb5368068877bc4cc3227f04c6e94a374616fc2c8d3991660a53b9ce5c6751fb4331d2398a13946e36f916bb4f93323496e5d90f3a6da812979032eb4318b24657a8cf2610d10b147e4d6e5b6abd1ed9e5c10f4ac3606d374bd87071b1bc7464b8c3a2dfb58692804e9cb6cd9858375c6ce775ccc1d4cb9cdebc85181384143a33e03def2e117bf4f0b4e58efee8d6eddb8da2bbdeb0a618dfae4a5a6e05c7b3e3c73a9c73851d1ca1dc6c6f4fd12c7e6a26c47b3eb24c4e3077b2389dfb6dc0898e8a1e761df61700a7d245bdb78f8dbf3f54695ca36bfdbd20bce3b2cf53fa0d7f23c557c981138725233189c1ee2bf87b603c91627fe9623363f2a8c1790ce8737cfa4c557195b338a09e863526fe5acdba9f2da6f0c633cbe21aa4855c3e8636d6a1265f45bcadd46e7a0c2655363c04678999091cb669edfaa8268dafc27f2c33cbd65e587cb6b921f55d2e0fceb204ebb7088c2e58a5ad33d95e901c658d1966b5bb5c0b20648188f1a4a4a307265652faa07cf34cf5faae1963c18dc6b6394a3b9e3fa6de9d0f43ce15d58e10b7b1f6e4d1dcd3ef67a11c84c0a72194ca652bb193d379e564028652d9bf1850f2a89314f478320c925ce58c5ecf2a81b656e7608510dadbebb5f5b1672a8e5679d5883883eb29ce4d31c33a2b551e37850211829a70d36256ca8b335ab103ee256535f4763e274b6b400814ec35b8acade51cfe0b5a858e8016e89a4c2726e5eb5b2cafa0168d4850679dcf5ea30cb638d27d2700a82cfb73e9ec0b5f207e537418c4b5a740382bb7e335229831d67dce6209850e810eeda29cf346da502257c37ca1a3769693315692eff9014a919c850373a053b9cffff0270420bd1b074a83992a485564354b8d71da32063b7a3bcbefecdc54661d877804786fe0a344c0bb01cf640baf82d913c08dc8b014f94f5e01842e2cbe05be286db2e5907c9319c7c473948e4a1c918cfefcf61ebe86b6b1d83bd76131ab57032a5dfe9872698bbe679caf9137dc004fccb243474c992bc11872f9028fb353ab63d83738ca5034cb99e9df87b141511d04daa8326be73b20c699cd801fab724ae99fe3072866e09312971c89b5bfda0f70d8868e9b39aab187bd4dd6a2e5446e101d3e9dc44ccd4f0b7b8c61840005ca6db4c4d10453c74c7da686641c5f6dbde3d64523735bbcfefb78cb9fc83cbb43b28ac27480634b0eab13637eff98a54c86a16f9397fa38d21ba8e820d77db362ba1d765c965ec37f98f7552aa28c167a0aaa5e0e4571d45ca335965f4df679b48b1aa12837e120f4f1efb73941eddb63521752c4a2a8de312791d6645a0e590323f87a02b2117d71a5c1404dfecdaed7b527b6dbe5b67c9db65c2c12107f03c49523ab229c347f4f5c842047c4b0239f29da30b4f701ecfcda49b2aa96e51edc281ae87c94bc5ec5df8ac129e1bbf9a5b3f21a2dfd6cb0949b13daa3fbc05b68f5966e8c2d69839377fef7bf68c2123094e17bdadb684f9df502509dfb1c3760d10614bbdf603167466d9c71742738ba729d2c2f816d918ab4baffcea95991439a8e52d3010a4391dd875c41109d1130f53670d3376abd7f79a359150fee27538e76193217577092dca74225e4c93f3454657b6c119873de20d134be8909a8677cd612596f065c6a22ab29f738b51108d29435fbc44554c63ba7212b8e0dfc937efad6d7d98979e5348f41f48403b6c17d27d976629fd99a5587446dc75896e4d81341d6500937fc07d72681b3938f3cb4dbf30e9bcdce272574c9e8d4c9305b5b9866bbe3a4cd2d661d34cdcb90ab195a44b6a91d7ac1fd66845b398fcec93487ebbc65abbefb91f1b282b6c7fcdbaa07444838c577310d706847a8be8c6e2d503de53e5d472435038c70f60f835723b089b98a00e927b08c06b055b67d7b716b2f10b9e638575bdd6d181bc0b045b570bc91f574b0c250f663ce355ddbf450a1f3d303552888d976225047f3816fb7dd7c9798fef0323c8c76fe91e2553782f766acb1c1a999c7309d19d835e424d747183be0b3f4bae9bde806b991aefb5b53dd7ee1f8a8b4c3e34b033b2a55902ac3ce94e66b8487b998ef30845745a9de19ea882511189e20c19f4cca1f3710cfeb024df0e7ee597174f1b4c7816f09394da6c30c5a5e7d672699f2772e7536f6e5940087e87d00ba3e8efcc5442ca57990c290e56c036e3b22218507a762de22c28f0fb7293d3d32deefe2e5d92f64555fb02013d5e383f577483181c264ed8338bc22aa834b4668f7dcf111e9e80b4fe787bcf22718a773a7af904b5f32914efc41584b1277a99f8a9612b28e140fc26117bf97b4d01c183ac0bdade40c812dbf711c1d10879b3a02798d23eedf4c56bc9eeb40f74fddda67444885d68ffe215a604470561a67de0fef197ebc51368a95b0175a4d37e793b048f48100fa84e18a79b9ed8a2a9b8e8362e57d4e7bf0af3d7608c8e669db8064f038cad923ae0187d1a7ffdb732018136bec4793e17dfb78218581b1f40081356db8e817efb9d8cb4eb0cef3c5e8181007fc04707365740563020003318739a04eeef538b5aa533a99325e69d6fc4e7c15d1d9c2a8e58e210a07b8bb5ea2d82a081398ab792b691933efdc867db671cc0d947d6f9e8f82c368a735fed64e50b23eeb6a49c228b09fa0030b4c88e8cf7b17b7fed5b313f90e0a90553307fc04707365740621027d07ae478c0aa607321643cb5e8ed59ee1f5ff4d9d55efedec066ccb1f5d537d07fc0470736574072103c3581a2ce34495158ec797a1b3b0f3fe25cf28abadca7703eb0cd2348afa633f07fc047073657408040000000007fc0470736574094920000000000dade26c633d2bbaabbcf43fb55d348142fb4298904909e18c4b73c952a5eecc464bb330404b01ec35a2fee7fbe4ecdb8869bfdc8c9552fe5229a61d6c0e98397e020b1007fc04707365741043010001455786dc62ff9326a2b449f428136e7aa130895ebea05497ed5eaccb73a61ff4c9799902b6a94c73b33ae2064e654d3986d8b931fe322b3c0fd401653242749900010308f40100000000000007fc04707365740220230f4f5d4b7c6fa845806ee4f67713459e1b69e8e60fcee2e4940c7a0d5de1b20104000001030840420f000000000007fc0470736574012109c5ba9abdcf24dcd65cd842bb47f78d6cf84f178efc80216d94ff8a2585826d6007fc047073657402207f8f32be9443b0547b4daedefd9b6b0b655bdad96759a57569bfd429291fa44f07fc047073657403210a29206a6e6974d903b467480e654c2180efbdbda5f69e8a87d0529501734cd158010422002037831b3ee29fc96f8e61ccb98fbe2dcb03e189dd29cfecc691b5a7442d8548e807fc047073657404fd4e1060330000000000000001736c1f018f94d3c1aeecfc5e79481642ae10aa575e15948ecb3a54b85b2274822d874cf225334a0603c3701fc52635fd65e8a946895af1092760785855a1c67b846e206246bb2eb1c7a660e6213aedab1ff06645630fe6b84c78ab6b74615866ba3cfe138e553d325b0ebdd542cf4a04a9276faf2e25594936cbc56aa6d70db453ad0868e47992d0ecd1227aba88a66b0d3844e26d586630c23fd6d8c162fceebab92e9d5500acf05a81fdf0b6d41db6f6513e8f25234380fb0561c2765480b6fe83d9e74d6913e1925916a3a90f9eef648a8f1caf476244191dc98cf2c39a172a0240b36034c31c9f8782aaccad02a0928d92970cf443f0331e5f580d52a6b9e6caad1c51a30e5fa0503c795fb40b0bcf047fcd873f922bd831c115b7627f77fed8fa76aad6d1250cd84184595f5163142bf77f385b47c49b529b7dda32fee16cf081631bfcb948c2426eb17b0c3bae41b16d5abc688afa285bc99579a30a05f57d0cd7bf777dd172ae03f3982ad912e0177f9cbebec46d6e57741b83289959bf6f68d816cf5ebabfc09676bcfb7766aaf6f5f04179a22d75273b82c94b7a9095eefa90574ba83aa85ea3ec3599fdd72a4fa267f7c2b944b92b690776b97b3cd4692fcd0079760d6a820ae51e1b0e6ef405d751414face0fdad0994cbf553c60017ea379d035e8ae184df1cf7fb28bfd746adef7df476213509924690e6d284ec2e3cc3d735b072f6582d913bbec5977d21f20bdd596b10eaf9bdada349dd63d99e0c28c2006f6945f09ca0d244d434f86841afa621649c4c1704252ac1a676d9131594297fde37194b901014a176abda3e2a5103b8b73b586382b3f469da738714e2d59b36cf4eee345a7faa4666c33a0d74469e39ca152ce7510f1abbf7cf24d37054b272691780309bd69916a964f2d535082d4403fca3210cbdb357ce06704f0f3aa6d8189badf11539d9e6f867cd4dbb2e3b4e13d6f9bedb459edcf1b520488c9334bec854794d3e5d943e7837e557c3131c085307ef712e122199d245bffbe6520f7af80cd73f6547057bc2b896e5430a27d5cc922ffbb5b4e012861061caf149d42b05b342f061fc5cab91be0645ba78f334c46f64615e60f37c84d641348800c5349f34cfda388fd58e48553722b7b53474475a6b6efc9753883a2b41e4678247a363998c59c37cd6c4706c56f5d5fe7596fb195c11748b66b2001accb18fd56fcb137f059973988f981c166b04c8e8ff2a52d705cbc61ee69c26f271e80995009608334dcef363a0f4eb5cc24fcb2160313836cb1707ec294c1ea357ebb70a478b84dd760a10284dd551ee7c8b086a201b900f7e3aa1e491926d74005fb2c989d32a3809ec1cca10bcad7b68c7be99d865361038b2b3023f421fff764a9ab759faf86c0a0042945969c6ca5f096cc1a592850622d6f60ba2b56287fdb6214d761dfd118ab8806a8557af5dd1d31f3d551e6b749bd37ad351184646d26360f150167a34685e24bd8127ec4970c73231e0ee4659bedbdf0b0fd64895cf13396f52417032f8bb221ea9216166d0a324c0d03603302e8234e9d98444153e91790567554056afa2f1d49d0277d757fd5211fe66a7f61624aed4e5dfea2cbbb8dabc4ea3037f4c6e236f1ee048b499cda952c7c9086f756adeb75022c1925ac0f64e4d7da8ec583e3326792bf13136d6e3eca27c56cb4be411d6b03ba8c29a4f17a860d1d27b93242e345cf7228bc6ce11aa876e7a30159a8dfead13520347ff5e949748ffc4ea51b75a7135456ca0a3b40a39bb082a9f02da862f19c651284ea28779ec034b05c07cbe85588f56b4a5432144ca7c1dd30b9783f231b1fc1ec05869de856a20a784c05f33055379658ec2a2ad24995e00c47ffc7bfea72e91df9d5e9a8bacd3ae3e12df323c0bc759857ff6e7891ef49b0176d0959f8fb2494e0fd85e68f0b8069bfbdea365850c15ca98d8e858936cce10a0d8a7d26877f260673ec3d1bb5f3ec4565726c935593e6b34c48f73e551b908f0a9c632166096efd4887e168831b0eb66c3e0e9e01a31f354e76d5f584273ad8f8ac2af7e4310b3273d106c171892ff3bd3c92f2727920d88b82b4cab6517eac2ac6a808c62da14c35536e47b33f028ead9d5486d872332fb61dc53c8281117f517b0b6d08626a4bf5d9ceef0eeb7828b56cf42aad8cc3cdaaf2c8f8970c6c20e1fa4c8dde0d822de374fad8fc898518129f7251fd9ced6b8f32364a1987cc0969892d1ab885dc9bbfa2a08a3d831a51755a6aadfe1bf78a2dd5372eacdb0e6a9668d2c7d1b720cb911005bae7f6d5d4e112aa4256171b6dd5652f95a4bd7f624b45432a99f14bddbfada9af1ee6dadae06f8392adf959979f46dc9a55439b5515ff57cb5f4934cb1259ed9ecd114014b99b3fa0f325eefa2ab8738e05c5ded5885d7430aa31b3878a10dd0a9ff95668e01477b0ebcc904e4b4f27840de17442661cf246f47d542f85a168187669820e6642cf58b23557c109b11133106fb043781a2da51fed9b2c5fdc426b4c1ee1ec47d2b9e992a2cb3485029d8c9d6dd44d104f0caa06a44b9f0470af5f905d155326e8156155903b9706cf6ff62c6c565ad9d1d25a0e82b1d8164268d83b8c8d4fce0ff202992738237d73dd242cca368fd3d3ca71d6acf49ae0d749a33eef07157adc94a049d2c6de65d2ce6a4c5957853fc89dca92da3f014739b24459f24de757abe4a127ec8f6b774beebfe44bf1eddd84a14f85c9d57ed3a9d8dbfe616db906c2d4b482b0d79f8165cd4c78af23c98cd715b406244bb5353edea403d54b8aa46206c5e8e551d1ee3a1310f7b7ce0e28392eac7e2546867d00b34fa47ae8f2c74ac9db78565bd7c685108de0ff3c0af495fcd31120e5497025416017ba47e6f32d3ad05f2290b471eb21aba1f60878f71e3102c59fe5ec96012f68e73c9bff4f35c25e65d66aa930286c31bd6a59e0d26b33cbedf4e5e43ec5ab3a5822ab352d61bfb45a2d9929dc72c5179acbb217e760683d079002b856bfe25e1951ee428475a5fa9447193778beaf49236a1a67905a55d541e69dc27eafcba25dc6ac6110f8e6528c5a3206cbeb36833544ca08db02c91ce03c1ec97b309014e52c546186d2bf62098b708054fce5cd5bc7e042f7da37780fd1ee3ccce6b8abe4c586f46b0488117d8cc2b42679ddb89dd5e4ff7f5e4a5c2e9c3101dc1d5c6d0415f255164eb38486f78bce5a0dbfc54aef8adfb647804a8358c4e5de06804539bb4ea7f7487f158527cd91081477a5a020152aaf49b4f8077296820d254d13e3c8fdd21906a801e665a4043b21de0edc08c9664be88f3834b0246b6264ffc081846cc200d629cf1ad0db881aded247a8174b4f43970d5680332dba5061f5055a2e69334cf4c8dda7302a9e37091e4f440608dea5399f1a8d748a59b009299a79f9da3c5f2b2648846c64a893bfbe0bd187b7b7767bf42e351a8392ecc744318a9871515d435ee05be0e5c800e0d1cfa6ea10335b48a2f00c17344afcc6d08ddb426031a35d6daf07f48c7980f56bb9fd2588f9a1f119610d70c8af3da487964a170b63ed3ba6c097e8ae750aeeaad733aa300d87a15e558fa6330680cfa4cfad9101ca85d012858b3ce6d944c9bd9ff072a151920018cd52314a595dddb0337a6af4e1aa7905ff54bec93f50fcf5625cb86d5ba0a39bd757139dbdd63b96c940ec14303b6473c48ec00bf1cb5db2ea7cdbcf4f0c4ee6a6336d7a321e57fa1f288b4b635addf70b724364084f05cbba5d52bdfe7b708cf25f7f1aae574c49758e7587eb15bde51dd3343269812c5030e9398a31487dfd86e2e8c9ab8e8ab0713e955f9981b7d8f1aff0424d01499555af7a1a17d041f3eead79e2a4f9528a6356081c550326b1bb4a6610302590430aead818e2195199742dd13fdd928a9ab23b15aa67c41758b2762078b2e3d3957ab202d0ffe80595cd51ff54ca213e21734d475b7b4b924a60580b5ae4c475a71949622806ef418273349811ac08a912880079ea2dacbd0e0a4092af04fe20ee0b2bbe1addcbf4289b5e3dba3125ef6cc09a8787e29930cb27e987eb599669349ac70e8fcc66f5c27aed363e28888b1b2a48e432ad2987606cc5496d76beabe66d1bb6fad2d16116a4d0d98509756e4d641f57d65cdd71ef99262d6047800dc6fd0b2a0d167b8d242cf53c41b8411b26d48b6a95e511d316178d34aa3d6852de377725d9a253717dda8238bbb2ece522f60ff4535f1bae8a71e52d904e5c849d13cb91765cfb20f5f74c9067e24de2d70006e384883e676b33549e708f3c90a0ae967fd54ba1364dd90f00f9660a27ed880dcb1067a4904a3c649d024cf9cb3a8184706c74d461b0efb02ecc4e93a709527eff8753dc3a515d7ccec22c9d08751a74a522f9fe99cc193a5fbe2b0a6cdff1d4e8e3654d4d74ae57fbd8e2582cced7c52051797b02e0637ae4d541cc206a754e960bb8983b341808b783032236a3ba305d2a5460a04da0da20f09a4d4f6c6312435e6c4c6b45a8d17998f969964284fa49cfa49c760dabcec76fb87768369f98153bc3ad86a3bca1acccc12ca8cf61b14d00a1de4623a372364bcc893983fca31b111b9458d809ff8ec7716190987297326bda2bcdef2faf880fcf8cd999d32ea77ec98958cf30e60cc0fcc3055d978fe7037e1328ca6c4c4134afde8d8ae5d71811ecd682a48230273bb9264eaf971717fb815eef06ac881f3d0f4d859b87043d7698ce28668bac8524b1d5763caf11c0dc6534c62c0dbc2291bd62b5d145fd10553b6eaadb1f6bed46b96458fba4bcec7785861955f68552335f36c687735425b9f9d17f2514a734e3fc385901219d20976df1045aa5023d76750a5cb10e70ea07f1c197526f5e71396177f66443999abc0a008d400da3d08c9740cf6662adf93dd1735f8c262f58241fc6cdedc9ef7cc4590b8aac248a831fc7476c0e26f0445f9ed723cfee1fbc2c8ac6315e14bb2f49c2fbbd593d870b8b98cee16f8adc6f841f236e4b499571094e07ad82e44e57f16f728a7187d6c1baf3cd1315b1f9ac4b7dae69e39efb6a03176430f69720e0ef879284f59ffee4e6720d31c51753d666681dd15e7ee5340a8629e8863d5e86b4088a32de13e13e0f92e15511e9bc4d57a25c71743e9b39af867dc17ad3ebe41b9c8f64d1c38573db395382b55a50ec279030ce8f59ba8a13525681efe3862f3c46eddcd3dca4eb3a191771723d3a2875fb2074ee9867632eda4ffadda4c64283202cbed717d3ebcb2030ead311b9c2ca56169f7ce6deb9fec78a76cb9f78ab8251b83bcda6dcdb0e916ba12daac78a151eb76d040507fa29eec866225f87c694233ed07362b097aec619f5df3dc5ad0a58f0cc94eacaf252f1f9dd59bce58904ff7460052a5bd0650111c105aeb34485c4730ed6e3e1c927e2cd956d1b9404fbaf0440afad135a3f320005d666abd4c69e98edcda3691b7e69b2c3c88ef5e1ab9062b0b3f08b8ca38e8f6f7b4d04f3daa358986a3f8bc5f6a13115c31e454c0dfff61613d0dde9dcf4516bad111328b9e88f262988e8c05e5ffe1fa6ba708f5fd51c34e4757814ad0ea5e6fd33cf51b45b84c85882406cd3eb107b96fe546364a9972d19022be3b5121ec64c6454f3a4f9809f49e11611b2131d5af0aa5e65c156f37a6062aa395e763522fe6b1451c0452c6c56443087202605ec9ddac8635e7fc086e330a7d22b15851671565726b2cce451d6288755a04862bc7f934b99de6809533c05b851ed07faf408f83fa9c18f3ed65a94e9788f830f5bb9ec744b71f59d6821899f8640441d47746497dbaf8e9ddbd252e04a5e4b313e2580a1a858e4550a1e5c09a04eae54307fc047073657405630200037f019cde9197e7270a1c7d726ced68dcabcbad740497313348e7ce6ad7d29f0bdf616a31c760921e4f9796161da146c841e86ee758cfe053b88447152770fa72c1d2b4d17de0698a19a7f1cd72c95a4b3851905c2a7a76d894a2885cc28addf607fc0470736574062103d559d2a5a4180f418a69c4bed5508971cda9313722fff71e053d3d82fee9d7bd07fc0470736574072103701e53a6d0b960398abf678382a4d17c5c153d1a2c8ffb76b302058ce915bb0d07fc047073657408040100000007fc047073657409492000000000000f424056773886ab9ae39b4056b656fb255a3af50694cda3ff4d8d4d450f15ffbbbd9043f90fa6f45a7e8563f8d305ab4b991a2c33e51b65f94230c9bdd457a3b31bc007fc047073657410430100017f113b550d4432ae02cc0d943900d25f6833c26bc1df867fa17b36d215044f889bcf7e3dc63814f6d7894608232902f7cf313b28194f104be657b44bf54471c300010308c0878b3b0000000007fc04707365740121080b9276ef17348a17b4d25e1d429594891f5bbb07fc8e33e4bd35bdf8296b7de607fc047073657402207f8f32be9443b0547b4daedefd9b6b0b655bdad96759a57569bfd429291fa44f07fc047073657403210bb668bf543a321a7cbad607ba5714cfbdff67e8d04c9a4dc539ff7672b84b19cb0104220020e7da55d19cc85b0420c539a90b667d4d85f59ee0ed417493a947c3a2256cc0aa07fc047073657404fd4e1060330000000000000001a000d4005894c852815a527aeb01259da98708628a2f2657826496e2711f7355a941f50a31be4e1df7d245f27e22dfcbb737e28008eee8322b6ee9755cf564411c5f360cd8ebd076db3f857f2a89a6dc3c84a200a3895a0a68b8dd14ca3c294eec37cd45d1cc69ba3e5a114c8a4d8e32eb79cdf984ca018052e503a5a6a71b49c78112909d2f1b1fe97ba13cb6804156d6202dfe1275a223c3b99f77964f3eefe61f87d483f5d8273edf67f4ba970c9abc27627bdac0fbfccdb6582e30429d2d82ee4658e2284927f66b3fcbd59b8282ea88e37198b3e6809a79e9be849ae2080195239e82395ea60e837e3e03459c4a635ae8626d29939026c1b69d6ac6a32a6a8c8a3686d29c636841fe4ad37402bd3c94a58b46a74898b614dd318211822e2927db89bc8d121373ee1aed057436ea6bc084e7a38d612fb9322265c7b04ba2a4187cd70856fd276971057ab4aec79d4e9f1ca9bad675c62c481a621f23ecb7b78b72a90448f40620152a603d4a150d1fb87c37cb281195045dd4730899f58f4813c1c99569828f377e6973bdaeff1bec942f98038d6599a73de84ce4c350ec161074fc30b151949f22687b9c50d05e8339c048beea2e944f77f601797f7fe64cde986746644b4c5f0baa42d6738add8f9773e7ff9199cbfa3bf03cda1e8be64163a3d8cff0875ea6b495e372107b5f6e9602fb6b0654e5fe1bc8a2626e4c9ca3a33bb0d2755055547dbbd2b1548de0b9fd7193ac0d3bf7d4ecc929c3ed0b1112aebe26188476f63dfb75b12187242436f8bcab54de04510dc31f3f3f14204e8b50bf3594432edebf93b26903f87c1dbea50dc9af089c4092654250e1505301daa5b0534645e52f2d3c36e7af6e9e04f7b54111282044afe94411854aa73be65f18fc868f39f79e312f62c4250e61a2511718808980fa0ce8089437569c149f4f9381db1e12e4d2d1ff682f47d63c8cae57eadf9cefd30e52128dceadcee043c84d90555b10095765a0d1f898399cb734477bc068fd2b37f47847332d38182cb23da3800c56dcb2a074aad8ef25d741d569c355fd4a0d806cfb698151873d1e48e24fe359b2182c8a26a1ca1c21ab609fe19dadbf5f8e3ffed3fa7679363ac7e303eb917554fda9d2bbaf6c053e658dfeeb88448f5fb017687f3eecaa3e7ffb6188c18e55678cbe2328a05263a987fc502280d070f181129902cc0f5e415e13f76b3f58dd257136ce579c4a999b127374e2bff94f694c456247c502239e301d21aa870ac1021b97b11a7d1ba0095696a50fe16e888616548d7eef96efa59cff978962a7c6f38aca24282091616f6acdb4bebedf236c043b36a6f12eb82c2c589c6a71080a46cf27e6e663060788c2871ff04d26ecdfe534ee254dce0328134af51228c908c5184eace62cebf5ff692097fc2d272a7275b965ef8b5953fb1ffe8d713cf92bf4b3f6a428bfc3aac0e67aa93e9571902dda5b1f66ce523109092aca555f007ee5529597ec185981f45602be0a8a0f9e9b75c477e0af5d27e546adda7c4a2776b97b9a301f0b6fc15495197cfa6f2975d19bbeb70db18dbad8d0ed06176d97c066ac19d4061d7f7cccedb352788ce5d15c26fd970bb68b879b5571ec5bf2917d7d58249fc8f9b2f5a5efd5e3596451a7be38dd75525fd1c2b0444ef9aab646869322c23e52b1e0b2b420d2220a4c150f0c6b8a4bb245282f546abb74f264b6c75286d05fc7bb2c266b5e9864bc6e9b45ffacfa2352ba898178856db19b41e7e6d90ba0e14226e698ebeb02b3fa349e8ee09d7bfee08a54763ac1db861aa0683b78f6bf07263e3cf0fff0b91225e5e009231155bea60b2e661e7b04d8803cf0c89192cb8f70cf16a6d256bf31a28d2203da20d7d33c7a6f841169a845ac35c8fca9253e807f72e96355c296323f6e0a1d48bff8c43f55a594fa251f69b907d9f97e7b2feb5296d12d331b34ce9107df9da5671effe1120e078956b85abd24c8cc1276d648a2c515791fd40ab74a5c46be36a6426b2c992c22cd3d96d61ddf089ca711c15ec60538057230a2e96a92ccfd605b09a4ead233440b7fed99abc47c50263728b18b2bbf79d814c30b5e96a72393d828446bc3ff14bcfa0c4530b59750c28d7c9639c961ba47320401566962b9fd69df8e87719e0bcfc5e9987d1cd9ff4407dec489ec6e1c0a82037f7f0f94d3a06d131876d541f3885906168181c21a395a51fcd3e2efd3d116948742f8911cb892fa7d4d4d5f83e86c9334732191c632a2a6a74d7f760ccb95e04ff59f8e207ca2491d0a6f48df78254a0019fad13c0251e107639d5669bbe90cd0188042c02eb726d3d33f69e5ca06ac96c733811098c5f9a09210b762e5fc94c493552e060058e811cd302abe0d60be900fb0158126a4d3c188a65ea6c2620aad9c73b0d452413bb26c5e6c3b2d885731bbac7abbd42895d5542bcacd1a93c405daa46bea191af513b0bfc3a1f992700daf4967cbe498bf1df5bbdecbdef4614af954060b7cb7de6833dc0d721eaa570659400f452664ea7c88e410ec5c35e300465ce779d76b0fcf8ecd375f727347bc46e069ac8ad816d35d08f4da02da77a75447a3da203d8ce3a0be9093dbe938dbb62936c7602f9bebd69261fa9fde170c9fb22a345183ae119af5b9a47c1cb0d740ff9771a27493c9bcb0ffeca14c376e0512014dfacbfbcc9d0956db6d642cc892dd7d8a5070b054f26e977ee6e3c121b16163d8ac151df29a5b8c5601d3cba799ceb10f04141c3f6081d7d1b6ea22202b3aed1f932f8cec9c65eea07befa558159499b1033e235078fa7e16be66be6f2ded84e8b47708a59c0c707fd79061945818132b2f2e58242238fb3c3410d2080cc8ff7b9a689d259b2bb63fb40f1af64f19e4dc53ebe3bce60977776328ebf6dcf24cac233e04c5df29d5ffed25609e3b8d96accff140f9f6acf21d9951ccff9f5c9bb27b7c8991b5bc8c2dbed6ff31b2b6e75f6f620ddf45cf6f67b900678567745e607b42d0bdb9d86d80eed1a1923c2386f371e0d2f11306ded8684325e46bfd979059ece5fdda6ee9b5ffd0697a54a64abd7599292509c3a82bb926b743a91affe05b7dfb350b605521dedda17617dec004a378b01682b2998941f02dbbc804c3553ace603226369bfca98ab4aeee767abc892e00f56d79438d075692a547da501c50289e91c3a891646daf82de39c7abdb48b3663bd870eaba0393b66dc7723ba77c588f5246fcf7b877e296fb784834e2cd679b54141860f4696b1b1ac330edcab74b59aff6fe2e36b7e3a459bac93e5068785f455d12c51b486f2063341113b6e196def028901f106b9993e4147ec924af8e6d86155d8dc2aff8b1f9268d9c75e94e253ad38ae65a8cd3cd19161dd5258588f8e74f3da7bc7df4bc6b7d23de75a02c87e8648a7bbd55210110239ed6e6214189825dee3bad6a028c70a2bf249b2294234798311c5695fabbfde68637ab9d066fca327472ca460468d34f74922aac4f1a64ddfdf7ccd4fe12d83ef033b901384ab8149ab50288fcdf087a50c0271046e7824c6c69c33ce1179c9e87dbbca60692027c1c54481a8d4909fcb1f2565c47d50218995fccd8cd64f51874180fd930256880aa1f696c321790cc5c32c49d146f6cd0128b18c52d00417adfc06aa6e279c03f5b21daea9a33390a91dd3c5281444d023362578aa83eb3a81d57ad360d337ab374c1bb3b251a51fef636418e1966cea1b2135bf444a03c39f4619c7acaf3c7a5cdfdf8a3893696e5fc076e915af6ef7817a32f5c815803e92810abc3ca09e421f8f039206e524a47ed746d3ece4c67e1dab74477abe25707b92598e71f6011ac9e3ea85417a6e4f43c55f158c2c73776c63c3af8fa472016ccae79a2b9e99d8c42fa1cd72ce8c9cb3c535719e075a0adf26fbb559ef129512833698d6892ca1a37f176cf6a363cbeaacf40813114285b032412f6d98854bdd758465604eb2ef4756064a16cbc02763323f29722e625ce895315bc6eb1ef3aba39543df3668991b3d7ce33c68ca975c18823cf37e8bf38b87ded0527d61ba10aa43db45b82e23b1582da992b9650f7d146eb420fdf679eddc26eaa3639a6aa41a2149d1b89057a05552b772504cc29132b7f6b3eeb5732a9830fca236fd41645f4da9b38b2207d931944a98ad45585eb659b7e1e43fed797c41705265bd155174f52e45a89ae79e5c1dd264a39758ab5ba42f6b721b926a06d45ceb114a0ad592ec71276bd7fe1cfc592324e58b37500b106355dc6ed962e1830ce33f8a18a0ca236c3301b0bd9029c6dcee2dc37057635fceb494a8352d74963fb2e3f75b91b19bbdaa49abbf11351f88b4d2d0550320a8df123289cb16e1a4de9e71974d920d2b28e59037e3a941e0f7c6b2265ee281d0f9da960d2b707fdbd0a58f0a19ff8003ccec3d1be962eb47f57923ee2a1df81cd2e77430eeb8e0825e8cc93ae0466a19c80dde5b8872491326f877b27db9543c495ce3c5965bbd48f216390115c7c31bacb20bd9f11267d2aedd4586ffaa27664991a100235bc197ea189840540fe0b29a07f24c400ffa2bd81eea1d15496bc14a65fea7e05604f987cd847b0814439e09ef47bdb3f273cf0a56e339e7105542a2ea1fdda77a2dcb792e474cd086341b510cd5b424caaa98497744303dc149759640302337f8d4038396f776dd79fc41fba310214a60ac5e047311bcdb5daeb1d8a601368fd3d84f981aa6fe7fc43d244beabf0a386414c569c8599918f8250487c546f1dd49a7793061a0107ae626beb6bda487f633b1abfa389e182f4f1aa99309ffc7c0b69344d0e9c5c2feb35cfe38f33c6f8b668af1df1bdcbdb5822c6c1931c7ca25258556881584dae524b35c0fc1dedf8604298014dcdfa39c3d38908364b01f55062bf7ad3ce8f85bb765afed8f365b1996a6600d39105203dd47023b5de1e2c2ff78a2e4b1fd6329afd0e86777471721fdf55e7189b18718b9c7d6f7d764b6bba82ea9eb9cd9dd9c09b9ff5ef25b3aa8ab309e6d85f43d6dca7681a49975372a9ee196f917e4e6b390103537d24a35a084c5eb5b378dd1654025fbee39935f599bd4a15741ce19479a93dc9489035158fa0812b6ac13c6f247432cf8ed3a92f86b372cf624e5b7b2a419184ab9b333a461d5fa9df9573f67212435ee96a59a020ab3c1dc0c61440905516a8b6f341e4d9cceac3129b6b7b6b3ba2ebbabef7857d8d7594f778163a5f95f9b443067a94f9e0fe9db323e25ccae107e960ce163d62fa0c6268d99cdf208705b57e3869a8e0687fb95d9244a3fcb447add7b7dfa850e9af704e2619821754988858693e27fce4b0b3be89e42def5bdc8213e02489179150764fc0a542e382f52e8d7cdb80e4aa78ac9b3d1d56ab23c8b885f0f173c4020d2330058dd37a34c0c1fde5142b3176254a6899d47514d9c2e68b040104b134f331dc4d9036505210d4944ab4b7762bbfa364fa3d96c7f87e53bf71d5a5c3c40cad698031e95ff17922952b5d1f9337c93bef79c09d075ac5d73b37a317f6c4d767a183283d1bbc97560d4930e47628d489a2c28267ed8bf0922b519eb3f72c62d710f81f07dffdf6d41b5ed95190ce20e2b94f8cf525be8352568b59a9a9db7840636d2b76494fb3f791bbdfacaf5541ddf8d7c104462dd1c6d3006bc386ac1f55fb8400589bcd895274de80092f69d1c759fdc3c31f2e1681ae75689e587d9b11a5673e069a98c1f77b538829c59e64bf65c1417abb2d8f52b8ac6c4bed00ddbb1a1d04d05d874315f55ed580c6fe3cfc967c15bdfda8be76eb1c77e3a720450dcbce40f772c28097a0925aa159858f38058ace779e4d8467de433e39518554630649613da5d20707fc04707365740563020003891394633c5f31c9ee5ca072b289c5be81c8d6237fb8290032940c0f535b9f72b4a4b8e967bc5c791a60b0567bd7c2fdc5ec71eb54c8f0770c92f5488c50d1416d636dad9c610e29d32d95c6ba93f6ce39a14fd1e6a11c2934090f494dd860d307fc04707365740621029e5980b4f9b9a9fd568c1c4b48631a800c310405ae8b2ac41ddaf87add3062f107fc0470736574072103504bd87c31711ff592af95f3c9c4f78e63f2f30805bfa95bc2d21e5a2db5c4da07fc047073657408040100000007fc0470736574094920000000003b8b87c003c8a469312a60ecdf33a36e22b37eb9c3e380ddab84491cd12ef7c80a6565124063d8d889bbc3a6f2e0d2fb66f78adb6d5a43d5fbb716a5f09a0db9788282a307fc047073657410430100018474c718fb7fef3e0585e56e19e551b357042f0195930751ce4d22721d93302dd78d263aa3c247113a0958851c182ad93f59216c95ad62b808bad00d4127fdf100 \ No newline at end of file +70736574ff01020402000000010401020105010501fb04020000000001017a0bb9325c276764451bbc2eb82a4c8c4bb6f4007ba803e5a5ba72d0cd7c09848e1a091622d935953bf06e0b7393239c68c6f810a00fe19d11c6ae343cffd3037077da02535fe4ad0fcd675cd0f62bf73b60a554dc1569b80f1f76a2bbfc9f00d439bf4b160014d2cbec8783bd01c9f178348b08500a830a89a7f9010e20805131ba6b37165c026eed9325ac56059ba872fd569e3ed462734098688b4770010f04000000000001017a0ac55f449ddb6853f2508766d5afb9f3b45e41a8ef5368cad75fb88e5e249395d1097d88c92ca814a207f73441c56cee943f0bb2556da194c14a4b912b078c2238ae025341cb5e4e2d8cb69e694cb20e5ea4cc8ddf2801180096fd071addfcd8bc4445160014011d384302576b408aa3686db874e2b17cc2b01b010e207aff956e6c2a379543b1ec82b06958f062bd9f29aa1ac1c98d1f6398b65a8555010f04010000000001030820a107000000000007fc04707365740121091517eb0e8ff9154ed835c45bed0856ff6b385b12f7aa224a1d91a532dce77d3f07fc04707365740220230f4f5d4b7c6fa845806ee4f67713459e1b69e8e60fcee2e4940c7a0d5de1b207fc047073657403210aaeb20261582b6a470b523b53d6969fb878704689a6ad0b0a690ccfc39b2b03d70104220020e5793ad956ee91ebf3543b37d110701118ed4078ffa0d477eacb8885e486ad8507fc047073657404fd4e1060330000000000000001c49a6101a4a3a122e2316e466cd2d4eaf9ec9029024390d41ab38146cb008e124d94df5c0827b57353b88df660dd6483ce69f89db194b0d7d14ed04f67059e708fc7636fe37183ffec38c28168f7c0680ede63e23a53ba0312fd96cc47dd3e147809c8e4642ff5d4ec0e280aaa369b08f41694cc6abbf60716678f7a83d7e163b34e2fe06c203e702e52cb69a5bf1a37aad479d9bfe7feac1a16bf927b3b233e50a3f86a07d6cc69454b0051df0f2941fe86e98259b91945a7fcd0e5c64c4ed96a302f931c23effb8ef97b4e1e3d74b0c392f686e49cbf255961fa03fe32cf60bc9a030dc511564600412f8f57541306f83cc6e8d3bc84796e7439bc2afff98489754bbfb6f28b2c65bda4cc8d5514e482804391bfefe3116798c5f477d67c65c4f82f18d10c864a59fc7f9de325922415422d0c57fa70e94f878acc88d9389dafc99d584194ea5329e1fcc5a8967fb1e7c7a85384d1af35b0baef473a948d4f2c02403e0405160d22e793b079cba61377a2f25a78da9233bd6706192d32f80b6f51bc86452f47bd0e8e498033fcdf84fc16298b97d6e4dd4392f37869dd65af84394fbce984599da74907b70cf0bf3181dba69625aba09995afe37213f7a38bad1e4ee4d2d5741ca334d05f6fb5ed40847ad3cb40d75f3a407e669fa77acae9c7e33fb76a92ba445f6b955e30364957a448702ebf2193f9cc6bace952cb2b36294b34f024d209aae3ffbc8c3d3e3e3984d60ef7759c165d5e99b90b5843a706be29ae6c136117196495f8f575303b156b62e77ca6654975296092a630950283ea808bf266935c5f9e32ef637fba8104c2e766101cde30c48bb77dffed39b1aae769bd378860cfb4dafcc4951893e9549e84821ae78a614c99a368336d86333eb48234fe649eb911519628c65120b395c9cf14a9f2d9398ba6dd8c3ec2ba00bf9d18dabd8162e5df48ef3f1e26fc8e068d14391b192981cba1b9e665649952752c3038aab5b4e108b705c1b90cd83699a1ba2323cdc3eee1f2f1d909eb11da0c3940fce919d65c4920b22358995655410aeb1209a8c34e8621bbd154536a26d29a93c0c4a0b9cc0334e0c5ebe960b3c5e49c305c6d062eb918d5d1f3bcc95c900e06f737623a06a799c2a6bc182357d3f88a059459d02ebc492e7b9b43b1e99a4c8ec157483ecb70ed81e0e70855950f87ab444fdbbe20ee9a34959d63b9569221001942118479bcab4acf18dd56d7d768c066a3c6b2467e5dfba6b5ae5fe5ff1e00489e732b61899ad3b8c82c8ceebe76227ffa9d57003c1449a7d34c71625a1bb8420ed046d355af63c8b3ba4983035de467716bb34f7993970a019c9c87d8a6d66b52361a1b10352bb5eb7f05ae1aa6a487fa3452f8d25a5ab58394543ff0a4e78d75e47324572b42add9ce1768d78d84524fca712965346a542660648230c914a0ce93b460687287a4d420a4894dad96650aa4b473c3a01b1f561ff4ff4c06c5ac946952c9c009c2aaab33bfa7cec11f6a24d75d8112732af0fb6c8a0d1cc8d7d202f4cbcf5810f2d1c8c6bae7748deaebd2174a39828d11daf145e47a16aa86fab16264292ffee07bfa452dce579204d91038939ee866f3a0c46dfc7fd6d85409c96450042920a80a601d11a7a8ad231c6d996a79e6fd710969848bd357dec3b7d20bcd1aaef36657048000192f7e3f0910b954a943f2d9026d1e87e080f2b78299a00aa2c7d86cdf66b6d98bee293b46c44a3bdfa87cfb6f1659d213460596ab89e90c08151252e171d87a4406ef3f0185e21bbd5db0e298874faf77e743899e2af8eaa4b2165c8942c1bc488723d684ba8096d64b3c032e9d07ddc4b8a5bd1027a54ade8e56a73c15fcf1f204b194933c6dfd5a78e449987e682c81970cfe265aed282b7ddb9c7c952859205a42ea2c24abe55883acd0c593edec197b9cfe5fcd56d6b867720fc1fbae83909b65f5adaf21526cedeea64a4d495b409244fc734618590f0efb15d76740234b19cebb88f70d29679d2b0b34a739bbbf2d5e9ff15fcd97df5e1919eebc2d1f469f35f024cd79357963374745e92d8e8d1e29a286f6fbeae0fd3abef755b514503acf5106a2fbb2d2370621ac3c3ae34bb6f14f6e82c71d01ae33a1bb629e294022ef9cc50d295bce35cde0beb14bbeecbb6cb189ca692ed2040bbe0312e9f446f2f7394c6daa130628a03956831b7ba63f0eecb5caae6472dd44459d69b994917e08e05665c16b1e988189f468b170321876918c323e52646481532616d4361c8c2070217d40e052a6dc487c1ef9f030922458e829a3ea15d2670ac3acea32e9af81b2a455d0d63bfed89e911e19fff080c7e973be22061348266b26d3bee8c4c3bfad3ce0aec84b25e3cc41b46a902f9a119775d0a903a4657df112ece8e789aa7995fc90033d503ccde74901b1b40c440936fe0dba6444eba823b328c8c8187135be38a651526cd1e159ed806714547f09f45be5928efe384e91ff6be03ea8992b35eca865ab4cf5ba7788ba95642fa530f58547fe597cc3dd8bbe223bd008aea8c37e7433547d2ac5cb716c2403472d7a96a76d41e9f3b92a7db1f7694e28446bee478bbdb1c2c6fa787daf10ec2f539d87e3d5e43ebdcd43f2da2736d15cc9708b74c69a7419fac92a3c1c307867ea243ac4401835ecb459a888ad58cd2141808100afb3e3bb056fd9f42b2df7d6f426b4db8befab9582cea9954f58f2d899e1ccb4dfde1a9d7a8b2076403ffb8c7e14661038f952dac328d5b21e7f1e4258ca8aaaa43f426c8213383bf60d60640a9e67378097d5f07e05dda7159ef477439be71c28904ba4226708319cf854f92c62f51d7128338578eb259c0681e7bdd27426fffdee0081fc9430db6782e2b013dc7e76e4ed043dfd7a2078b41230ff437dfbd240d3f11f2063a808ae011147a4b6111b4fe3339deb4c0e5bed8ab5af0a991175ffd33941c586a1da510774e25eab6858f1128cb7f7e2a53645f909c96a4c9dfb9323bafbb9d75a7d979238b3da069ab16fb7e621a7a99195b78e11f85262d9d6413a7b88ca0f6fca17cf9f73a7332e7733a3e153d4372dd2e6d9af0b7883a99c0b5925f817422085808ef25a71bdea61755449dab91704b250ea29fe5e66e776217fd38054bce90e2ad5d8ceb32575834ea5e07542f2f1795c2c1df6579b7dda3b3ce9382bb9838e7324251a9f7848c56cf213ba968e632fa9f99e2a1f4f916231a70ccaa450fcf8b9a2c44f4097b65dc4fe63b218b6a3181ab5a06d69483442ad61277cae828c7b90e2caed91e8f9f02582a642fdcaf72b4f1d3c14102d2663726555288f48393a178ede1692d3a8209bda7e3a3e1608c4c1ee2fab5a4ce7960e4dbdd00579261cccffc49cc8a876f250833694809739ebe0a252951904b994ae9c190b0cc612e2c67d25be98720887dd8c9964ca698fc29151f833496ec3959c05a8785c72bf0f1c9c9ea41616c9aba960ac21c38f71c82ebf3757e86da00bdbfda319940c1bd8e468f9d83654d87d6c1a7d85cfcb233841ad0118e830e333d7bb1c19972f24f6efce9ed585a915a4bfd49518c485f9ce5c5df734f32ec825f8f259ba25cf4b9d0c1c1118d42d7110609b5b44c4b0d92c70101319793807f2f209e7b5460c9ce8993a11fc9613c96735cd7e2a3358756e0b4c5e24104c76fdd19bc5ca4123f6d07557bcc4c350b3c5b74eb45418afd2213bd52ab2d71658a59367441eb73c37cea82492073d2f38b3e446740b338cbd202f28dba9004044ad4b5b7085ff19a4dfab50603f4344bb2526fb144882695c2a31d86a4163f092e697065f55290b99167fab57c5f22e51fa1520ac48ce50cf54841ae22cc480ab4abbf078469e65a94969e510af6d58c50b140a38c03420d33f9faeb35b44cecfa0cd19cd27c20026bd19b2971c4f0d32456ba4dd4af61bfce234b471c54c013f7183559e4dd12e8fa1c297733da6d20c57b838a1db8fbfd4a367b5969328df2cb18688b7099a504e559af5edbb54c7b58441ae15c693385e0ec40f3043fbb0457292e82cbcf3afd3b3d9d510691ccd1441fcd45c9342522010f140ddd6ae4b79c326acf5f2873031911a4ef7b53363121c20ef450e5f64a63729969d038be74661ad9260ff39d738a476e306b15746e4c3a72aa2168a8c276de4b3da973cf8ea489320e4d1df7abd1f6dd38d9bfffd4ad26c3f9d874377a4718e13e77524c1cdf751fe433b72cbf89514103df8dae6aee905f24a1222633578607909f4473397f0ef7880069eb16772188793ae979cc9ba90adc6df93f059726f8ca4f94c1b986c8ac1b0ade97c23b139d303fb36037939c63bcf0b0a33cda54344edbc759a3157abddf7afc3e034ad2881a55854b6ac679316d99255a5d0a93a96b0b1efbdf8dffca1c4e9c6ebb11c7667bff42aecb0529b809eba6f7af3eb794614bf4dd266a19248af7b679b5f5a7c5896d3ad9fc23616d579e98d7959793f9a4d96f058544e38108ee04fbd9b91249633cc405c0f3593d4a337ae3e0115ec1af1f34f96d633044897193b6a132f29043922fd57866d9e004d3aefb8c36e8145226b1dbe7866f46790097f1052e6b18b50f6c83d4ad670dd0784cc73662481f415d03348427054a3eb50695ebb104fd45ce6a4a23da4386c3d384cc8bc7aba67ddaa49a0e49e98262a55c7947d1effabf398f919862fa38adbb723b1b9d1526dc11f970444a05389b3211cca97e62f94c66d785a96e8c507cafae02b6d0dd8fa0df684b3ed339374850a9e3d540eae25bff5803dac9c5d8be61b2bcf2055ffd946df6f5ceabffbe84dbea695e0b67f3b8bad1443eeb743ff7e4943140c036832b9b5344b8db3d85ba958f6935646b601b2fe497ef8ea1645fe41760c70610326c5253cd8c84831588827fe8ee0ecc661b87103e6e99f567308f580e2387d6dce7901883b8e428bbc9cbc19c1e850bf598f204258c9b6f09c4334a8f95021b94b05ae197dbdc972d6bed5e8452f39cfb98fb60b510085ed739dffd4241ed0eab4962d34762bfc8cbda6dd52b3a324612c32ed80b9d77c6c41443a9c2a40dbea51da644dc6becb9546843687bf9f4221b8bf436863833f258dbe98bd165488157301d74ff152483d6015459b11daf5f1af98293264d91b96f63885d7fc45d3ba117c22b420994b93b0aa207fd221370a55bb1cb130314ec9d21624a01136a5f51a5d1e028585896b7ae63cfc84c9f493430cce38d1fbfbfa7db9dfc0479ea027ddfc38c13c7bbe957b04a31e90ca14aa4e9f9c12e339d09811eb18f32151835f4d396da9decad13363c93de8d7499a941b168ea2367dfbfe3fef4bad204a12bd07ee0762de00cc193707d3889efbf13ad72c54b210b066b699e8f7c67b07648b743fae60b5f09f3455be11edad01c5b4a70141f969253a63754ebedc338e83755e8b762b023b60abc12be5c584a57308b10c8a335666d84171edfcadcdcd17a6fd30450985ffa2e690d00e5bd21169a0404777f51c37cbb89c745559bc7e81814d6010d331b16ffc4fe2e88f37256e29871a4f0f8c959b78927ae0ee449559e3f895327227e859fb6cecb20d4e6671f4d9d46a76163ef3c3490d1801ca8039b5934c1293deee598acc83a4b776d335912d0a2c602c653f8f3e9a2aa249958d94fca07a4de4366cc5349aa2f3f599f33bab74ddc01944be806a35b5141c95dc778e6ec102a609c7346211953510d7105d436112868d718b72b0b861aedebb4c77d6f2ee6b7101bc00ed406a89923e19fef2dae304f528ab56e9086fce342e4f19c509809fa399b2c150e6911ff5b96ee8627d226ec33c0b84c04ab0afcfc4d89793cfcf6111aa8fbd217cf5706aad49d4ce6480b7e57fc77c07fc047073657405630200030ac6a03fb2c4143a07d1599e22ea844e3594b77f4a960e172b3c04a7b9f7eb647887e94bdae208da814a7a0d2b216bc0a730da54cd34522ae1b71ea70a305a217014067b0ed40a77a3d1e92afd3c447018c8c60d4b8e0ded12f49671bcfa36a707fc047073657406210212bf0ea45b733dfde8ecb5e896306c4165c666c99fc5d1ab887f71393a975cea07fc047073657407210325b27bf6f8d1b06dbb69ed3944095d71b9a4558fdb574e2f032bbf1adae138d607fc047073657408040000000007fc0470736574094920000000000007a12018e6f3734441bfcadd5d94f97741e750dd28201a658d4785c5bede038f1a1179290dc688efae09c0a437af462dffc2fc5adf6bcbbae64cc40e099300c98e4cbd07fc04707365740a4301000190d59bf3b61acfc27a23ea0f5994bf35cf81c62489a2f658673775457d0eadd732c4aaeb4275077bfb347f483378e6fa1570a1912e2a8a725a7a76eb0c2e23ca000103086ce2ad0d0000000007fc0470736574012108ef054b3ea0c1c3a6eaf67bdb0759cc44d7fa953fbe2df1df4d39a59dd6cc9d8f07fc04707365740220230f4f5d4b7c6fa845806ee4f67713459e1b69e8e60fcee2e4940c7a0d5de1b207fc047073657403210a93480fd89d465d14eb4e976496a7098fd22f5072f5740d60d12eec8c8de917710104220020f6b43d56e004e9d0b1ec2fc3c95511d81af08420992be8dec7f86cdf8970b3e207fc047073657404fd4e1060330000000000000001ff1017007f0c699812e97d8507c899e760dbf4e630430cbcec3bbbaeebddc10f855c3ff8c3e5f54785fb6f527922b522c7d4cb56bd1e6e74afe3e2149b66d3c9a2d54e8255aef17ac0f30687ddc5425ffb31ca3b51b9848200eef211bd3e0f6a7883ce56d7ae74f382f67bc67f03482bdd1b39a6730b60043037cc4f53bb18159aed2ff23fdaed63283b6c97d14ea9674784fdd0e6e38553e96ae815338ec811fd3be74ab655791568137868d626a13beb59e019fa445c25d5b289cfb84517428c7ed913e73ce4a984ecd5ea6e307553665d6e0944e9698821d690b2b4cffad1e4b1e7c987229488e01c63c3244c435a35813695250f9a665e8603fdcdf2e65e5544354f886ca40a85b863d45221e536efde55f7ec8fa055e9f07bd988774ff59772eb96b5e0c79bab01cb3fe141a461dcfb03a5469f6f39f23413abd729ff9a450fbe564d8126eff14f00b9f8ccb05452ba471b79ecb9e9e8fadb67427bab207c24a0c2e6799da4a052ab408ddaa8cb56f1dc4bce5459a70aa35b87bdc85798e9f0e828a5c36d0254b98769a3c0fce7bf97188afd3d32aba2f5a1a52c057204b086c04220e2061bf68e76db32a0a0b6703e3584a652a72b32404b307209cad70fd4e451441d2aae539a168a72cc7ee2a51795b8325a7740e788a897b4c2ec053df02b77996503d50131f86936b4e0e9ac07ac77e2fb1171a36728b908e8e27e772750bf63710a7c137d87d41582da6d6b0f1c423e4a3834e7c45234f64974d2b544060bc82c80a74fc1078972ce74e87b71fcca7c63d6a1c7bb852cfe3b12751c9c02401490fbad794b90e2e7aa304c5447f4b37d92ea304f52580f38bb892fbfaa01e63fe6c2dd2b25a092bc6a5b0cc918a7e99f68baa286c19834e738cd400dd452b60106bfaf25d2da9767cae07bb82eae3100435d1c95bb9fe2053660a3991eec9b40af76e8d7564c6d07aca2da552c73624cd756dc72e714d8e784c9efe415f12d92cf56a02e886c329d8b7ea996c465c45da1f84f56226e816b3ada59c100177d9cb4bc0a593372105fea9e207730b57ac2cd97a4baea2b1b92cbae6977842bfc6279cc260970a41f9b8641a576d80266715cd0e56a2379b854d607a9cbe64b575cc70855b4d46bcb1c7df88dacf065d7a6fb52c911f60dd54100225163e738c8f34c820f285ca2d2677dc63e12cccf9f1c8e875af4c0eed38d15d8b685bd82843ab1e7d96202d411e839db71ef148c9ef7dcf1f088ff8f04c0d408ee9c8326b9dd73683aff18a7602064c4eb56c47b525e1918315a189e48651a944379fba7d5e1473ddb4bdbfcea6ca72d8ae5c06a37093602c8d2979c4c41f6633aac369ca839fc15b0b06aeebcb7eeb178a4ece0d221a3bfee4b87a019df15db5b27f27ca9954b073092dad3f3f5cd8b78e715ec42af635ad915693cd547668a5c6e9ee375c3789578288d07e655e1f1be71313cf51a4e2b6f66fd4c740d249a29a85459daeefaa618f42ac70089b86f07d2c80eb74062e617ef375008d94a8e06426a044622f3e46f39a47857c01b5c3fafcdcbec916d15e7dca650d09324af15274631e17a55b1c251cc72f9154f940e47055c0946465f4b4b6c9b3627b309e9ff0066e0079b590b21a135ef3287df488acc3d367b7d4488707f888432fd38cf1854cf1f57e0db57468217b6b482639c92c9bd3f3556b9b5b00963700fb9043bf85e1edc39b575c56cfaa75eba62077492d0a764cc6737014d94b99696f7a9e0401cd54b0415c6c05eee5967896f6c8d9d49d6015b787c1d563022841bd47cc7d5341cb7eff22b46a99c8920f8e3ee615ccc873c8b759ae18e12a8ec8d684f15f5a48e3c1935c94e379fc6956c1e0f3c6167775c107aa59db7a05c9b4ed00cee4d7af7cf3ab32a185444a3c7ecdc24dbf766fb097bcb0af185c4015af363dd0296eb4d87bae677800fed3f31339d85a3b6eb688e6e8bc08b1b5709f482463b8d968ce7c0aa4396c5fbcb7e8f98f64498810ecca8a428bd721f390a95da48e602b04dd20716be3384e1003ea605d8492b649d78b331025a6977d5269ffe676dda60b3096e7e1e849d3fab7f176de7d02ddf036380cd642aea57b9ee43f7b8f53288870c1f1db0c2de7d29d91e57a56c6de7b585c35c3e01d2b3600e244193adc74100ca404534b5cf6831268d30b37184273fb797428e990952dccdd01476ac837defc5339b4aaed1d0af010fcf52d07fdca34210e9b7fc6e6ada5e9158b7d0b556ad3b28ca925cc24fe26f71878278f8ded022c8c1fa742dd44a17cf52cf5e5b7fde2aec0833010d2a70882b4cc1b294fb5e0a6d59f711f0c6656822a12707b3921ce5d835c23b1c699cd9fcadb7b9f2f21660f9a303d41ff817f5d1581d2f3d6c653de4a70ed1a3cf9af81bc07672467b87f38ea179a8d7a7c64dbc26d466de0a2197df8807d493d9f809513dff4fcead72c1c5b3b5460a7a665bb275073dcf64c941ae7aa70d42ea0ac1fb04cb9d34debaa6593ebe71c549f941827149fd76f9f124c311b189868e4ab43e9a020fee48e4d7c92008ae04ea5bb10f55e400c2adec535c35c44bc9e75e5547e79bf18e8d3a726522f1ab886030f2a4522bcc4c91e0f9657e32adae30be072fa0d54d1789f471e258c2191783026cb14c6b796f997c352ac64f048dddfcc745075967e16d7bcf57cd67798b66d2446d9445d0d49ed922f91eaa57ab43afa1ca90ba1e7c6c4e20416577ff70f6ae365b36adec6c485d598717bec53d58e28301589338fb62ff2b325e6a04c44a68fcf91f90b018dca2b35e5230aea6f5681977db3eeae1673c4a10b07efcc3ebe7b0fabe67737d852f50dab5e0eab00e0a42360fdc8c33de0180b48c59302a50e59f1579cd8a5565ed4f78c9d91a4bb25ad99c917c579016199e7bbafae97dc1f943e63c022542d8a29def106afcd48996a221878a5ef787259187846283c641bce500834dd452ccb058607f4a5ce5ec2a9449e2a17ea699a5a3d23febe7ae2fb46f4be2fe472f813ceb932b20f131cf799f3d6413b7701bf7c17518ad79c53eb9ad2866535b5b492006ddeccb7e59e77525d5b064696d91436a6ee3d4d0452d49f753bb7d26da00af042739fee0308571c801d6c63358e03925b76a1dbfbb1b6a9663cdb1a2a58f643f84365eab5dcd9421e73007d4569c68a758f0aa6e3531170470812cba605017082b2efc45144f885e09919e522a1233001b798a9e09acdf6a55b52a7ccb189bc52879ba263e18485a285db5b4e178dd4d69d873cb92b1dd046aa9f2905b5161195e750a84f56bb08dac7971ed8bfe11bb5368068877bc4cc3227f04c6e94a374616fc2c8d3991660a53b9ce5c6751fb4331d2398a13946e36f916bb4f93323496e5d90f3a6da812979032eb4318b24657a8cf2610d10b147e4d6e5b6abd1ed9e5c10f4ac3606d374bd87071b1bc7464b8c3a2dfb58692804e9cb6cd9858375c6ce775ccc1d4cb9cdebc85181384143a33e03def2e117bf4f0b4e58efee8d6eddb8da2bbdeb0a618dfae4a5a6e05c7b3e3c73a9c73851d1ca1dc6c6f4fd12c7e6a26c47b3eb24c4e3077b2389dfb6dc0898e8a1e761df61700a7d245bdb78f8dbf3f54695ca36bfdbd20bce3b2cf53fa0d7f23c557c981138725233189c1ee2bf87b603c91627fe9623363f2a8c1790ce8737cfa4c557195b338a09e863526fe5acdba9f2da6f0c633cbe21aa4855c3e8636d6a1265f45bcadd46e7a0c2655363c04678999091cb669edfaa8268dafc27f2c33cbd65e587cb6b921f55d2e0fceb204ebb7088c2e58a5ad33d95e901c658d1966b5bb5c0b20648188f1a4a4a307265652faa07cf34cf5faae1963c18dc6b6394a3b9e3fa6de9d0f43ce15d58e10b7b1f6e4d1dcd3ef67a11c84c0a72194ca652bb193d379e564028652d9bf1850f2a89314f478320c925ce58c5ecf2a81b656e7608510dadbebb5f5b1672a8e5679d5883883eb29ce4d31c33a2b551e37850211829a70d36256ca8b335ab103ee256535f4763e274b6b400814ec35b8acade51cfe0b5a858e8016e89a4c2726e5eb5b2cafa0168d4850679dcf5ea30cb638d27d2700a82cfb73e9ec0b5f207e537418c4b5a740382bb7e335229831d67dce6209850e810eeda29cf346da502257c37ca1a3769693315692eff9014a919c850373a053b9cffff0270420bd1b074a83992a485564354b8d71da32063b7a3bcbefecdc54661d877804786fe0a344c0bb01cf640baf82d913c08dc8b014f94f5e01842e2cbe05be286db2e5907c9319c7c473948e4a1c918cfefcf61ebe86b6b1d83bd76131ab57032a5dfe9872698bbe679caf9137dc004fccb243474c992bc11872f9028fb353ab63d83738ca5034cb99e9df87b141511d04daa8326be73b20c699cd801fab724ae99fe3072866e09312971c89b5bfda0f70d8868e9b39aab187bd4dd6a2e5446e101d3e9dc44ccd4f0b7b8c61840005ca6db4c4d10453c74c7da686641c5f6dbde3d64523735bbcfefb78cb9fc83cbb43b28ac27480634b0eab13637eff98a54c86a16f9397fa38d21ba8e820d77db362ba1d765c965ec37f98f7552aa28c167a0aaa5e0e4571d45ca335965f4df679b48b1aa12837e120f4f1efb73941eddb63521752c4a2a8de312791d6645a0e590323f87a02b2117d71a5c1404dfecdaed7b527b6dbe5b67c9db65c2c12107f03c49523ab229c347f4f5c842047c4b0239f29da30b4f701ecfcda49b2aa96e51edc281ae87c94bc5ec5df8ac129e1bbf9a5b3f21a2dfd6cb0949b13daa3fbc05b68f5966e8c2d69839377fef7bf68c2123094e17bdadb684f9df502509dfb1c3760d10614bbdf603167466d9c71742738ba729d2c2f816d918ab4baffcea95991439a8e52d3010a4391dd875c41109d1130f53670d3376abd7f79a359150fee27538e76193217577092dca74225e4c93f3454657b6c119873de20d134be8909a8677cd612596f065c6a22ab29f738b51108d29435fbc44554c63ba7212b8e0dfc937efad6d7d98979e5348f41f48403b6c17d27d976629fd99a5587446dc75896e4d81341d6500937fc07d72681b3938f3cb4dbf30e9bcdce272574c9e8d4c9305b5b9866bbe3a4cd2d661d34cdcb90ab195a44b6a91d7ac1fd66845b398fcec93487ebbc65abbefb91f1b282b6c7fcdbaa07444838c577310d706847a8be8c6e2d503de53e5d472435038c70f60f835723b089b98a00e927b08c06b055b67d7b716b2f10b9e638575bdd6d181bc0b045b570bc91f574b0c250f663ce355ddbf450a1f3d303552888d976225047f3816fb7dd7c9798fef0323c8c76fe91e2553782f766acb1c1a999c7309d19d835e424d747183be0b3f4bae9bde806b991aefb5b53dd7ee1f8a8b4c3e34b033b2a55902ac3ce94e66b8487b998ef30845745a9de19ea882511189e20c19f4cca1f3710cfeb024df0e7ee597174f1b4c7816f09394da6c30c5a5e7d672699f2772e7536f6e5940087e87d00ba3e8efcc5442ca57990c290e56c036e3b22218507a762de22c28f0fb7293d3d32deefe2e5d92f64555fb02013d5e383f577483181c264ed8338bc22aa834b4668f7dcf111e9e80b4fe787bcf22718a773a7af904b5f32914efc41584b1277a99f8a9612b28e140fc26117bf97b4d01c183ac0bdade40c812dbf711c1d10879b3a02798d23eedf4c56bc9eeb40f74fddda67444885d68ffe215a604470561a67de0fef197ebc51368a95b0175a4d37e793b048f48100fa84e18a79b9ed8a2a9b8e8362e57d4e7bf0af3d7608c8e669db8064f038cad923ae0187d1a7ffdb732018136bec4793e17dfb78218581b1f40081356db8e817efb9d8cb4eb0cef3c5e8181007fc04707365740563020003318739a04eeef538b5aa533a99325e69d6fc4e7c15d1d9c2a8e58e210a07b8bb5ea2d82a081398ab792b691933efdc867db671cc0d947d6f9e8f82c368a735fed64e50b23eeb6a49c228b09fa0030b4c88e8cf7b17b7fed5b313f90e0a90553307fc04707365740621027d07ae478c0aa607321643cb5e8ed59ee1f5ff4d9d55efedec066ccb1f5d537d07fc0470736574072103c3581a2ce34495158ec797a1b3b0f3fe25cf28abadca7703eb0cd2348afa633f07fc047073657408040000000007fc0470736574094920000000000dade26c633d2bbaabbcf43fb55d348142fb4298904909e18c4b73c952a5eecc464bb330404b01ec35a2fee7fbe4ecdb8869bfdc8c9552fe5229a61d6c0e98397e020b1007fc04707365740a43010001455786dc62ff9326a2b449f428136e7aa130895ebea05497ed5eaccb73a61ff4c9799902b6a94c73b33ae2064e654d3986d8b931fe322b3c0fd401653242749900010308f40100000000000007fc04707365740220230f4f5d4b7c6fa845806ee4f67713459e1b69e8e60fcee2e4940c7a0d5de1b20104000001030840420f000000000007fc0470736574012109c5ba9abdcf24dcd65cd842bb47f78d6cf84f178efc80216d94ff8a2585826d6007fc047073657402207f8f32be9443b0547b4daedefd9b6b0b655bdad96759a57569bfd429291fa44f07fc047073657403210a29206a6e6974d903b467480e654c2180efbdbda5f69e8a87d0529501734cd158010422002037831b3ee29fc96f8e61ccb98fbe2dcb03e189dd29cfecc691b5a7442d8548e807fc047073657404fd4e1060330000000000000001736c1f018f94d3c1aeecfc5e79481642ae10aa575e15948ecb3a54b85b2274822d874cf225334a0603c3701fc52635fd65e8a946895af1092760785855a1c67b846e206246bb2eb1c7a660e6213aedab1ff06645630fe6b84c78ab6b74615866ba3cfe138e553d325b0ebdd542cf4a04a9276faf2e25594936cbc56aa6d70db453ad0868e47992d0ecd1227aba88a66b0d3844e26d586630c23fd6d8c162fceebab92e9d5500acf05a81fdf0b6d41db6f6513e8f25234380fb0561c2765480b6fe83d9e74d6913e1925916a3a90f9eef648a8f1caf476244191dc98cf2c39a172a0240b36034c31c9f8782aaccad02a0928d92970cf443f0331e5f580d52a6b9e6caad1c51a30e5fa0503c795fb40b0bcf047fcd873f922bd831c115b7627f77fed8fa76aad6d1250cd84184595f5163142bf77f385b47c49b529b7dda32fee16cf081631bfcb948c2426eb17b0c3bae41b16d5abc688afa285bc99579a30a05f57d0cd7bf777dd172ae03f3982ad912e0177f9cbebec46d6e57741b83289959bf6f68d816cf5ebabfc09676bcfb7766aaf6f5f04179a22d75273b82c94b7a9095eefa90574ba83aa85ea3ec3599fdd72a4fa267f7c2b944b92b690776b97b3cd4692fcd0079760d6a820ae51e1b0e6ef405d751414face0fdad0994cbf553c60017ea379d035e8ae184df1cf7fb28bfd746adef7df476213509924690e6d284ec2e3cc3d735b072f6582d913bbec5977d21f20bdd596b10eaf9bdada349dd63d99e0c28c2006f6945f09ca0d244d434f86841afa621649c4c1704252ac1a676d9131594297fde37194b901014a176abda3e2a5103b8b73b586382b3f469da738714e2d59b36cf4eee345a7faa4666c33a0d74469e39ca152ce7510f1abbf7cf24d37054b272691780309bd69916a964f2d535082d4403fca3210cbdb357ce06704f0f3aa6d8189badf11539d9e6f867cd4dbb2e3b4e13d6f9bedb459edcf1b520488c9334bec854794d3e5d943e7837e557c3131c085307ef712e122199d245bffbe6520f7af80cd73f6547057bc2b896e5430a27d5cc922ffbb5b4e012861061caf149d42b05b342f061fc5cab91be0645ba78f334c46f64615e60f37c84d641348800c5349f34cfda388fd58e48553722b7b53474475a6b6efc9753883a2b41e4678247a363998c59c37cd6c4706c56f5d5fe7596fb195c11748b66b2001accb18fd56fcb137f059973988f981c166b04c8e8ff2a52d705cbc61ee69c26f271e80995009608334dcef363a0f4eb5cc24fcb2160313836cb1707ec294c1ea357ebb70a478b84dd760a10284dd551ee7c8b086a201b900f7e3aa1e491926d74005fb2c989d32a3809ec1cca10bcad7b68c7be99d865361038b2b3023f421fff764a9ab759faf86c0a0042945969c6ca5f096cc1a592850622d6f60ba2b56287fdb6214d761dfd118ab8806a8557af5dd1d31f3d551e6b749bd37ad351184646d26360f150167a34685e24bd8127ec4970c73231e0ee4659bedbdf0b0fd64895cf13396f52417032f8bb221ea9216166d0a324c0d03603302e8234e9d98444153e91790567554056afa2f1d49d0277d757fd5211fe66a7f61624aed4e5dfea2cbbb8dabc4ea3037f4c6e236f1ee048b499cda952c7c9086f756adeb75022c1925ac0f64e4d7da8ec583e3326792bf13136d6e3eca27c56cb4be411d6b03ba8c29a4f17a860d1d27b93242e345cf7228bc6ce11aa876e7a30159a8dfead13520347ff5e949748ffc4ea51b75a7135456ca0a3b40a39bb082a9f02da862f19c651284ea28779ec034b05c07cbe85588f56b4a5432144ca7c1dd30b9783f231b1fc1ec05869de856a20a784c05f33055379658ec2a2ad24995e00c47ffc7bfea72e91df9d5e9a8bacd3ae3e12df323c0bc759857ff6e7891ef49b0176d0959f8fb2494e0fd85e68f0b8069bfbdea365850c15ca98d8e858936cce10a0d8a7d26877f260673ec3d1bb5f3ec4565726c935593e6b34c48f73e551b908f0a9c632166096efd4887e168831b0eb66c3e0e9e01a31f354e76d5f584273ad8f8ac2af7e4310b3273d106c171892ff3bd3c92f2727920d88b82b4cab6517eac2ac6a808c62da14c35536e47b33f028ead9d5486d872332fb61dc53c8281117f517b0b6d08626a4bf5d9ceef0eeb7828b56cf42aad8cc3cdaaf2c8f8970c6c20e1fa4c8dde0d822de374fad8fc898518129f7251fd9ced6b8f32364a1987cc0969892d1ab885dc9bbfa2a08a3d831a51755a6aadfe1bf78a2dd5372eacdb0e6a9668d2c7d1b720cb911005bae7f6d5d4e112aa4256171b6dd5652f95a4bd7f624b45432a99f14bddbfada9af1ee6dadae06f8392adf959979f46dc9a55439b5515ff57cb5f4934cb1259ed9ecd114014b99b3fa0f325eefa2ab8738e05c5ded5885d7430aa31b3878a10dd0a9ff95668e01477b0ebcc904e4b4f27840de17442661cf246f47d542f85a168187669820e6642cf58b23557c109b11133106fb043781a2da51fed9b2c5fdc426b4c1ee1ec47d2b9e992a2cb3485029d8c9d6dd44d104f0caa06a44b9f0470af5f905d155326e8156155903b9706cf6ff62c6c565ad9d1d25a0e82b1d8164268d83b8c8d4fce0ff202992738237d73dd242cca368fd3d3ca71d6acf49ae0d749a33eef07157adc94a049d2c6de65d2ce6a4c5957853fc89dca92da3f014739b24459f24de757abe4a127ec8f6b774beebfe44bf1eddd84a14f85c9d57ed3a9d8dbfe616db906c2d4b482b0d79f8165cd4c78af23c98cd715b406244bb5353edea403d54b8aa46206c5e8e551d1ee3a1310f7b7ce0e28392eac7e2546867d00b34fa47ae8f2c74ac9db78565bd7c685108de0ff3c0af495fcd31120e5497025416017ba47e6f32d3ad05f2290b471eb21aba1f60878f71e3102c59fe5ec96012f68e73c9bff4f35c25e65d66aa930286c31bd6a59e0d26b33cbedf4e5e43ec5ab3a5822ab352d61bfb45a2d9929dc72c5179acbb217e760683d079002b856bfe25e1951ee428475a5fa9447193778beaf49236a1a67905a55d541e69dc27eafcba25dc6ac6110f8e6528c5a3206cbeb36833544ca08db02c91ce03c1ec97b309014e52c546186d2bf62098b708054fce5cd5bc7e042f7da37780fd1ee3ccce6b8abe4c586f46b0488117d8cc2b42679ddb89dd5e4ff7f5e4a5c2e9c3101dc1d5c6d0415f255164eb38486f78bce5a0dbfc54aef8adfb647804a8358c4e5de06804539bb4ea7f7487f158527cd91081477a5a020152aaf49b4f8077296820d254d13e3c8fdd21906a801e665a4043b21de0edc08c9664be88f3834b0246b6264ffc081846cc200d629cf1ad0db881aded247a8174b4f43970d5680332dba5061f5055a2e69334cf4c8dda7302a9e37091e4f440608dea5399f1a8d748a59b009299a79f9da3c5f2b2648846c64a893bfbe0bd187b7b7767bf42e351a8392ecc744318a9871515d435ee05be0e5c800e0d1cfa6ea10335b48a2f00c17344afcc6d08ddb426031a35d6daf07f48c7980f56bb9fd2588f9a1f119610d70c8af3da487964a170b63ed3ba6c097e8ae750aeeaad733aa300d87a15e558fa6330680cfa4cfad9101ca85d012858b3ce6d944c9bd9ff072a151920018cd52314a595dddb0337a6af4e1aa7905ff54bec93f50fcf5625cb86d5ba0a39bd757139dbdd63b96c940ec14303b6473c48ec00bf1cb5db2ea7cdbcf4f0c4ee6a6336d7a321e57fa1f288b4b635addf70b724364084f05cbba5d52bdfe7b708cf25f7f1aae574c49758e7587eb15bde51dd3343269812c5030e9398a31487dfd86e2e8c9ab8e8ab0713e955f9981b7d8f1aff0424d01499555af7a1a17d041f3eead79e2a4f9528a6356081c550326b1bb4a6610302590430aead818e2195199742dd13fdd928a9ab23b15aa67c41758b2762078b2e3d3957ab202d0ffe80595cd51ff54ca213e21734d475b7b4b924a60580b5ae4c475a71949622806ef418273349811ac08a912880079ea2dacbd0e0a4092af04fe20ee0b2bbe1addcbf4289b5e3dba3125ef6cc09a8787e29930cb27e987eb599669349ac70e8fcc66f5c27aed363e28888b1b2a48e432ad2987606cc5496d76beabe66d1bb6fad2d16116a4d0d98509756e4d641f57d65cdd71ef99262d6047800dc6fd0b2a0d167b8d242cf53c41b8411b26d48b6a95e511d316178d34aa3d6852de377725d9a253717dda8238bbb2ece522f60ff4535f1bae8a71e52d904e5c849d13cb91765cfb20f5f74c9067e24de2d70006e384883e676b33549e708f3c90a0ae967fd54ba1364dd90f00f9660a27ed880dcb1067a4904a3c649d024cf9cb3a8184706c74d461b0efb02ecc4e93a709527eff8753dc3a515d7ccec22c9d08751a74a522f9fe99cc193a5fbe2b0a6cdff1d4e8e3654d4d74ae57fbd8e2582cced7c52051797b02e0637ae4d541cc206a754e960bb8983b341808b783032236a3ba305d2a5460a04da0da20f09a4d4f6c6312435e6c4c6b45a8d17998f969964284fa49cfa49c760dabcec76fb87768369f98153bc3ad86a3bca1acccc12ca8cf61b14d00a1de4623a372364bcc893983fca31b111b9458d809ff8ec7716190987297326bda2bcdef2faf880fcf8cd999d32ea77ec98958cf30e60cc0fcc3055d978fe7037e1328ca6c4c4134afde8d8ae5d71811ecd682a48230273bb9264eaf971717fb815eef06ac881f3d0f4d859b87043d7698ce28668bac8524b1d5763caf11c0dc6534c62c0dbc2291bd62b5d145fd10553b6eaadb1f6bed46b96458fba4bcec7785861955f68552335f36c687735425b9f9d17f2514a734e3fc385901219d20976df1045aa5023d76750a5cb10e70ea07f1c197526f5e71396177f66443999abc0a008d400da3d08c9740cf6662adf93dd1735f8c262f58241fc6cdedc9ef7cc4590b8aac248a831fc7476c0e26f0445f9ed723cfee1fbc2c8ac6315e14bb2f49c2fbbd593d870b8b98cee16f8adc6f841f236e4b499571094e07ad82e44e57f16f728a7187d6c1baf3cd1315b1f9ac4b7dae69e39efb6a03176430f69720e0ef879284f59ffee4e6720d31c51753d666681dd15e7ee5340a8629e8863d5e86b4088a32de13e13e0f92e15511e9bc4d57a25c71743e9b39af867dc17ad3ebe41b9c8f64d1c38573db395382b55a50ec279030ce8f59ba8a13525681efe3862f3c46eddcd3dca4eb3a191771723d3a2875fb2074ee9867632eda4ffadda4c64283202cbed717d3ebcb2030ead311b9c2ca56169f7ce6deb9fec78a76cb9f78ab8251b83bcda6dcdb0e916ba12daac78a151eb76d040507fa29eec866225f87c694233ed07362b097aec619f5df3dc5ad0a58f0cc94eacaf252f1f9dd59bce58904ff7460052a5bd0650111c105aeb34485c4730ed6e3e1c927e2cd956d1b9404fbaf0440afad135a3f320005d666abd4c69e98edcda3691b7e69b2c3c88ef5e1ab9062b0b3f08b8ca38e8f6f7b4d04f3daa358986a3f8bc5f6a13115c31e454c0dfff61613d0dde9dcf4516bad111328b9e88f262988e8c05e5ffe1fa6ba708f5fd51c34e4757814ad0ea5e6fd33cf51b45b84c85882406cd3eb107b96fe546364a9972d19022be3b5121ec64c6454f3a4f9809f49e11611b2131d5af0aa5e65c156f37a6062aa395e763522fe6b1451c0452c6c56443087202605ec9ddac8635e7fc086e330a7d22b15851671565726b2cce451d6288755a04862bc7f934b99de6809533c05b851ed07faf408f83fa9c18f3ed65a94e9788f830f5bb9ec744b71f59d6821899f8640441d47746497dbaf8e9ddbd252e04a5e4b313e2580a1a858e4550a1e5c09a04eae54307fc047073657405630200037f019cde9197e7270a1c7d726ced68dcabcbad740497313348e7ce6ad7d29f0bdf616a31c760921e4f9796161da146c841e86ee758cfe053b88447152770fa72c1d2b4d17de0698a19a7f1cd72c95a4b3851905c2a7a76d894a2885cc28addf607fc0470736574062103d559d2a5a4180f418a69c4bed5508971cda9313722fff71e053d3d82fee9d7bd07fc0470736574072103701e53a6d0b960398abf678382a4d17c5c153d1a2c8ffb76b302058ce915bb0d07fc047073657408040100000007fc047073657409492000000000000f424056773886ab9ae39b4056b656fb255a3af50694cda3ff4d8d4d450f15ffbbbd9043f90fa6f45a7e8563f8d305ab4b991a2c33e51b65f94230c9bdd457a3b31bc007fc04707365740a430100017f113b550d4432ae02cc0d943900d25f6833c26bc1df867fa17b36d215044f889bcf7e3dc63814f6d7894608232902f7cf313b28194f104be657b44bf54471c300010308c0878b3b0000000007fc04707365740121080b9276ef17348a17b4d25e1d429594891f5bbb07fc8e33e4bd35bdf8296b7de607fc047073657402207f8f32be9443b0547b4daedefd9b6b0b655bdad96759a57569bfd429291fa44f07fc047073657403210bb668bf543a321a7cbad607ba5714cfbdff67e8d04c9a4dc539ff7672b84b19cb0104220020e7da55d19cc85b0420c539a90b667d4d85f59ee0ed417493a947c3a2256cc0aa07fc047073657404fd4e1060330000000000000001a000d4005894c852815a527aeb01259da98708628a2f2657826496e2711f7355a941f50a31be4e1df7d245f27e22dfcbb737e28008eee8322b6ee9755cf564411c5f360cd8ebd076db3f857f2a89a6dc3c84a200a3895a0a68b8dd14ca3c294eec37cd45d1cc69ba3e5a114c8a4d8e32eb79cdf984ca018052e503a5a6a71b49c78112909d2f1b1fe97ba13cb6804156d6202dfe1275a223c3b99f77964f3eefe61f87d483f5d8273edf67f4ba970c9abc27627bdac0fbfccdb6582e30429d2d82ee4658e2284927f66b3fcbd59b8282ea88e37198b3e6809a79e9be849ae2080195239e82395ea60e837e3e03459c4a635ae8626d29939026c1b69d6ac6a32a6a8c8a3686d29c636841fe4ad37402bd3c94a58b46a74898b614dd318211822e2927db89bc8d121373ee1aed057436ea6bc084e7a38d612fb9322265c7b04ba2a4187cd70856fd276971057ab4aec79d4e9f1ca9bad675c62c481a621f23ecb7b78b72a90448f40620152a603d4a150d1fb87c37cb281195045dd4730899f58f4813c1c99569828f377e6973bdaeff1bec942f98038d6599a73de84ce4c350ec161074fc30b151949f22687b9c50d05e8339c048beea2e944f77f601797f7fe64cde986746644b4c5f0baa42d6738add8f9773e7ff9199cbfa3bf03cda1e8be64163a3d8cff0875ea6b495e372107b5f6e9602fb6b0654e5fe1bc8a2626e4c9ca3a33bb0d2755055547dbbd2b1548de0b9fd7193ac0d3bf7d4ecc929c3ed0b1112aebe26188476f63dfb75b12187242436f8bcab54de04510dc31f3f3f14204e8b50bf3594432edebf93b26903f87c1dbea50dc9af089c4092654250e1505301daa5b0534645e52f2d3c36e7af6e9e04f7b54111282044afe94411854aa73be65f18fc868f39f79e312f62c4250e61a2511718808980fa0ce8089437569c149f4f9381db1e12e4d2d1ff682f47d63c8cae57eadf9cefd30e52128dceadcee043c84d90555b10095765a0d1f898399cb734477bc068fd2b37f47847332d38182cb23da3800c56dcb2a074aad8ef25d741d569c355fd4a0d806cfb698151873d1e48e24fe359b2182c8a26a1ca1c21ab609fe19dadbf5f8e3ffed3fa7679363ac7e303eb917554fda9d2bbaf6c053e658dfeeb88448f5fb017687f3eecaa3e7ffb6188c18e55678cbe2328a05263a987fc502280d070f181129902cc0f5e415e13f76b3f58dd257136ce579c4a999b127374e2bff94f694c456247c502239e301d21aa870ac1021b97b11a7d1ba0095696a50fe16e888616548d7eef96efa59cff978962a7c6f38aca24282091616f6acdb4bebedf236c043b36a6f12eb82c2c589c6a71080a46cf27e6e663060788c2871ff04d26ecdfe534ee254dce0328134af51228c908c5184eace62cebf5ff692097fc2d272a7275b965ef8b5953fb1ffe8d713cf92bf4b3f6a428bfc3aac0e67aa93e9571902dda5b1f66ce523109092aca555f007ee5529597ec185981f45602be0a8a0f9e9b75c477e0af5d27e546adda7c4a2776b97b9a301f0b6fc15495197cfa6f2975d19bbeb70db18dbad8d0ed06176d97c066ac19d4061d7f7cccedb352788ce5d15c26fd970bb68b879b5571ec5bf2917d7d58249fc8f9b2f5a5efd5e3596451a7be38dd75525fd1c2b0444ef9aab646869322c23e52b1e0b2b420d2220a4c150f0c6b8a4bb245282f546abb74f264b6c75286d05fc7bb2c266b5e9864bc6e9b45ffacfa2352ba898178856db19b41e7e6d90ba0e14226e698ebeb02b3fa349e8ee09d7bfee08a54763ac1db861aa0683b78f6bf07263e3cf0fff0b91225e5e009231155bea60b2e661e7b04d8803cf0c89192cb8f70cf16a6d256bf31a28d2203da20d7d33c7a6f841169a845ac35c8fca9253e807f72e96355c296323f6e0a1d48bff8c43f55a594fa251f69b907d9f97e7b2feb5296d12d331b34ce9107df9da5671effe1120e078956b85abd24c8cc1276d648a2c515791fd40ab74a5c46be36a6426b2c992c22cd3d96d61ddf089ca711c15ec60538057230a2e96a92ccfd605b09a4ead233440b7fed99abc47c50263728b18b2bbf79d814c30b5e96a72393d828446bc3ff14bcfa0c4530b59750c28d7c9639c961ba47320401566962b9fd69df8e87719e0bcfc5e9987d1cd9ff4407dec489ec6e1c0a82037f7f0f94d3a06d131876d541f3885906168181c21a395a51fcd3e2efd3d116948742f8911cb892fa7d4d4d5f83e86c9334732191c632a2a6a74d7f760ccb95e04ff59f8e207ca2491d0a6f48df78254a0019fad13c0251e107639d5669bbe90cd0188042c02eb726d3d33f69e5ca06ac96c733811098c5f9a09210b762e5fc94c493552e060058e811cd302abe0d60be900fb0158126a4d3c188a65ea6c2620aad9c73b0d452413bb26c5e6c3b2d885731bbac7abbd42895d5542bcacd1a93c405daa46bea191af513b0bfc3a1f992700daf4967cbe498bf1df5bbdecbdef4614af954060b7cb7de6833dc0d721eaa570659400f452664ea7c88e410ec5c35e300465ce779d76b0fcf8ecd375f727347bc46e069ac8ad816d35d08f4da02da77a75447a3da203d8ce3a0be9093dbe938dbb62936c7602f9bebd69261fa9fde170c9fb22a345183ae119af5b9a47c1cb0d740ff9771a27493c9bcb0ffeca14c376e0512014dfacbfbcc9d0956db6d642cc892dd7d8a5070b054f26e977ee6e3c121b16163d8ac151df29a5b8c5601d3cba799ceb10f04141c3f6081d7d1b6ea22202b3aed1f932f8cec9c65eea07befa558159499b1033e235078fa7e16be66be6f2ded84e8b47708a59c0c707fd79061945818132b2f2e58242238fb3c3410d2080cc8ff7b9a689d259b2bb63fb40f1af64f19e4dc53ebe3bce60977776328ebf6dcf24cac233e04c5df29d5ffed25609e3b8d96accff140f9f6acf21d9951ccff9f5c9bb27b7c8991b5bc8c2dbed6ff31b2b6e75f6f620ddf45cf6f67b900678567745e607b42d0bdb9d86d80eed1a1923c2386f371e0d2f11306ded8684325e46bfd979059ece5fdda6ee9b5ffd0697a54a64abd7599292509c3a82bb926b743a91affe05b7dfb350b605521dedda17617dec004a378b01682b2998941f02dbbc804c3553ace603226369bfca98ab4aeee767abc892e00f56d79438d075692a547da501c50289e91c3a891646daf82de39c7abdb48b3663bd870eaba0393b66dc7723ba77c588f5246fcf7b877e296fb784834e2cd679b54141860f4696b1b1ac330edcab74b59aff6fe2e36b7e3a459bac93e5068785f455d12c51b486f2063341113b6e196def028901f106b9993e4147ec924af8e6d86155d8dc2aff8b1f9268d9c75e94e253ad38ae65a8cd3cd19161dd5258588f8e74f3da7bc7df4bc6b7d23de75a02c87e8648a7bbd55210110239ed6e6214189825dee3bad6a028c70a2bf249b2294234798311c5695fabbfde68637ab9d066fca327472ca460468d34f74922aac4f1a64ddfdf7ccd4fe12d83ef033b901384ab8149ab50288fcdf087a50c0271046e7824c6c69c33ce1179c9e87dbbca60692027c1c54481a8d4909fcb1f2565c47d50218995fccd8cd64f51874180fd930256880aa1f696c321790cc5c32c49d146f6cd0128b18c52d00417adfc06aa6e279c03f5b21daea9a33390a91dd3c5281444d023362578aa83eb3a81d57ad360d337ab374c1bb3b251a51fef636418e1966cea1b2135bf444a03c39f4619c7acaf3c7a5cdfdf8a3893696e5fc076e915af6ef7817a32f5c815803e92810abc3ca09e421f8f039206e524a47ed746d3ece4c67e1dab74477abe25707b92598e71f6011ac9e3ea85417a6e4f43c55f158c2c73776c63c3af8fa472016ccae79a2b9e99d8c42fa1cd72ce8c9cb3c535719e075a0adf26fbb559ef129512833698d6892ca1a37f176cf6a363cbeaacf40813114285b032412f6d98854bdd758465604eb2ef4756064a16cbc02763323f29722e625ce895315bc6eb1ef3aba39543df3668991b3d7ce33c68ca975c18823cf37e8bf38b87ded0527d61ba10aa43db45b82e23b1582da992b9650f7d146eb420fdf679eddc26eaa3639a6aa41a2149d1b89057a05552b772504cc29132b7f6b3eeb5732a9830fca236fd41645f4da9b38b2207d931944a98ad45585eb659b7e1e43fed797c41705265bd155174f52e45a89ae79e5c1dd264a39758ab5ba42f6b721b926a06d45ceb114a0ad592ec71276bd7fe1cfc592324e58b37500b106355dc6ed962e1830ce33f8a18a0ca236c3301b0bd9029c6dcee2dc37057635fceb494a8352d74963fb2e3f75b91b19bbdaa49abbf11351f88b4d2d0550320a8df123289cb16e1a4de9e71974d920d2b28e59037e3a941e0f7c6b2265ee281d0f9da960d2b707fdbd0a58f0a19ff8003ccec3d1be962eb47f57923ee2a1df81cd2e77430eeb8e0825e8cc93ae0466a19c80dde5b8872491326f877b27db9543c495ce3c5965bbd48f216390115c7c31bacb20bd9f11267d2aedd4586ffaa27664991a100235bc197ea189840540fe0b29a07f24c400ffa2bd81eea1d15496bc14a65fea7e05604f987cd847b0814439e09ef47bdb3f273cf0a56e339e7105542a2ea1fdda77a2dcb792e474cd086341b510cd5b424caaa98497744303dc149759640302337f8d4038396f776dd79fc41fba310214a60ac5e047311bcdb5daeb1d8a601368fd3d84f981aa6fe7fc43d244beabf0a386414c569c8599918f8250487c546f1dd49a7793061a0107ae626beb6bda487f633b1abfa389e182f4f1aa99309ffc7c0b69344d0e9c5c2feb35cfe38f33c6f8b668af1df1bdcbdb5822c6c1931c7ca25258556881584dae524b35c0fc1dedf8604298014dcdfa39c3d38908364b01f55062bf7ad3ce8f85bb765afed8f365b1996a6600d39105203dd47023b5de1e2c2ff78a2e4b1fd6329afd0e86777471721fdf55e7189b18718b9c7d6f7d764b6bba82ea9eb9cd9dd9c09b9ff5ef25b3aa8ab309e6d85f43d6dca7681a49975372a9ee196f917e4e6b390103537d24a35a084c5eb5b378dd1654025fbee39935f599bd4a15741ce19479a93dc9489035158fa0812b6ac13c6f247432cf8ed3a92f86b372cf624e5b7b2a419184ab9b333a461d5fa9df9573f67212435ee96a59a020ab3c1dc0c61440905516a8b6f341e4d9cceac3129b6b7b6b3ba2ebbabef7857d8d7594f778163a5f95f9b443067a94f9e0fe9db323e25ccae107e960ce163d62fa0c6268d99cdf208705b57e3869a8e0687fb95d9244a3fcb447add7b7dfa850e9af704e2619821754988858693e27fce4b0b3be89e42def5bdc8213e02489179150764fc0a542e382f52e8d7cdb80e4aa78ac9b3d1d56ab23c8b885f0f173c4020d2330058dd37a34c0c1fde5142b3176254a6899d47514d9c2e68b040104b134f331dc4d9036505210d4944ab4b7762bbfa364fa3d96c7f87e53bf71d5a5c3c40cad698031e95ff17922952b5d1f9337c93bef79c09d075ac5d73b37a317f6c4d767a183283d1bbc97560d4930e47628d489a2c28267ed8bf0922b519eb3f72c62d710f81f07dffdf6d41b5ed95190ce20e2b94f8cf525be8352568b59a9a9db7840636d2b76494fb3f791bbdfacaf5541ddf8d7c104462dd1c6d3006bc386ac1f55fb8400589bcd895274de80092f69d1c759fdc3c31f2e1681ae75689e587d9b11a5673e069a98c1f77b538829c59e64bf65c1417abb2d8f52b8ac6c4bed00ddbb1a1d04d05d874315f55ed580c6fe3cfc967c15bdfda8be76eb1c77e3a720450dcbce40f772c28097a0925aa159858f38058ace779e4d8467de433e39518554630649613da5d20707fc04707365740563020003891394633c5f31c9ee5ca072b289c5be81c8d6237fb8290032940c0f535b9f72b4a4b8e967bc5c791a60b0567bd7c2fdc5ec71eb54c8f0770c92f5488c50d1416d636dad9c610e29d32d95c6ba93f6ce39a14fd1e6a11c2934090f494dd860d307fc04707365740621029e5980b4f9b9a9fd568c1c4b48631a800c310405ae8b2ac41ddaf87add3062f107fc0470736574072103504bd87c31711ff592af95f3c9c4f78e63f2f30805bfa95bc2d21e5a2db5c4da07fc047073657408040100000007fc0470736574094920000000003b8b87c003c8a469312a60ecdf33a36e22b37eb9c3e380ddab84491cd12ef7c80a6565124063d8d889bbc3a6f2e0d2fb66f78adb6d5a43d5fbb716a5f09a0db9788282a307fc04707365740a430100018474c718fb7fef3e0585e56e19e551b357042f0195930751ce4d22721d93302dd78d263aa3c247113a0958851c182ad93f59216c95ad62b808bad00d4127fdf100 \ No newline at end of file diff --git a/src/pset/map/output.rs b/src/pset/map/output.rs index a243734c..a8393425 100644 --- a/src/pset/map/output.rs +++ b/src/pset/map/output.rs @@ -82,7 +82,7 @@ const PSBT_ELEMENTS_OUT_BLIND_VALUE_PROOF: u8 = 0x09; /// PSBT_ELEMENTS_OUT_ASSET_COMMITMENT matches the explicit asset in /// PSBT_ELEMENTS_OUT_ASSET. If provided, PSBT_ELEMENTS_OUT_ASSET_COMMITMENT must /// be provided too. -const PSBT_ELEMENTS_OUT_BLIND_ASSET_PROOF: u8 = 0x10; +const PSBT_ELEMENTS_OUT_BLIND_ASSET_PROOF: u8 = 0x0a; /// A key-value map for an output of the corresponding index in the unsigned /// transaction. From cbc2d56409fc10d71184a4991bf08c63373803bb Mon Sep 17 00:00:00 2001 From: sanket1729 Date: Mon, 8 Aug 2022 12:36:21 -0700 Subject: [PATCH 6/9] Add issuance surjection proof verification --- src/blind.rs | 45 +++++++++++++++++++++++++++++++++-------- tests/data/issue_tx.hex | 1 + 2 files changed, 38 insertions(+), 8 deletions(-) create mode 100644 tests/data/issue_tx.hex diff --git a/src/blind.rs b/src/blind.rs index 05a8e188..6d275ed1 100644 --- a/src/blind.rs +++ b/src/blind.rs @@ -894,7 +894,11 @@ impl Transaction { // Issuances and reissuances not supported yet let mut in_commits = vec![]; let mut out_commits = vec![]; + let mut domain = vec![]; for (i, inp) in self.input.iter().enumerate() { + let gen = spent_utxos[i].get_asset_gen(secp) + .map_err(|e| VerificationError::SpentTxOutError(i, e))?; + domain.push(gen); in_commits.push( spent_utxos[i].get_value_commit(secp) .map_err(|e| VerificationError::SpentTxOutError(i, e))? @@ -910,22 +914,20 @@ impl Transaction { Value::Null => continue, Value::Explicit(v) => { let gen = Generator::new_unblinded(secp, asset.into_tag()); + domain.push(gen); let comm = PedersenCommitment::new_unblinded(secp, *v, gen); in_commits.push(comm) }, - Value::Confidential(comm) => in_commits.push(*comm), + Value::Confidential(comm) => { + let gen = Generator::new_unblinded(secp, asset.into_tag()); + domain.push(gen); + in_commits.push(*comm) + } } } } } - let domain = spent_utxos - .iter() - .enumerate() - .map(|(i, out)| - out.get_asset_gen(secp).map_err(|e| VerificationError::SpentTxOutError(i, e)) - ) - .collect::, _>>()?; for (i, out) in self.output.iter().enumerate() { // Compute the value commitments and asset generator @@ -1243,6 +1245,7 @@ impl BlindAssetProofs for SurjectionProof { #[cfg(test)] mod tests { + use crate::encode; use crate::hashes::hex::FromHex; use rand::thread_rng; use secp256k1_zkp::SECP256K1; @@ -1392,4 +1395,30 @@ mod tests { let res = proof.blind_asset_proof_verify(SECP256K1, id, asset_comm); assert!(res); } + + #[test] + fn test_partially_blinded_tx() { + // Partially blinded tx with multiple issuances from options project + let secp = secp256k1_zkp::Secp256k1::new(); + let tx_str = include_str!("../tests/data/issue_tx.hex"); + + let bytes = Vec::::from_hex(tx_str).unwrap(); + let tx = encode::deserialize::(&bytes).unwrap(); + + let mut utxos = [TxOut::default(), TxOut::default(), TxOut::default(), TxOut::default()]; + { + utxos[0].asset = Asset::from_commitment(&Vec::::from_hex("0ae7a52e8e4b07e00548bab151a83e5c9ab2f9a910e10dcee930a1a152a939f99e").unwrap()).unwrap(); + utxos[0].value = Value::Explicit(1); + + utxos[1].asset = Asset::from_commitment(&Vec::::from_hex("0bc226167e9ee0bb5a86c8f1478ee7d7becb7bfd4d97c26a041e628c5486a8c67a").unwrap()).unwrap(); + utxos[1].value = Value::Explicit(1); + + utxos[2].asset = Asset::from_commitment(&Vec::::from_hex("0b495dbfc356993c5ac157c3d04fadf6f198a7e35a873df482ad9e4e95daa8aa7e").unwrap()).unwrap(); + utxos[2].value = Value::from_commitment(&Vec::::from_hex("08e0ac2ab5f3c173d5e0652a2ec209a9a370a4e510178e73c2f22f9e132341abf4").unwrap()).unwrap(); + + utxos[3].asset = Asset::from_commitment(&Vec::::from_hex("0aa0956d60687982d5e73d52f8c5902478754e5f0e2e5ceff5ae53fa9681c12ae1").unwrap()).unwrap(); + utxos[3].value = Value::from_commitment(&Vec::::from_hex("094b35f1e86b097ccf0b3a826570c089c724ed9cf22620937500b14acdd169e7bf").unwrap()).unwrap(); + } + tx.verify_tx_amt_proofs(&secp, &utxos).unwrap(); + } } diff --git a/tests/data/issue_tx.hex b/tests/data/issue_tx.hex new file mode 100644 index 00000000..fb7532e6 --- /dev/null +++ b/tests/data/issue_tx.hex @@ -0,0 +1 @@ +02000000010495312e683e782579ea92905457e1eecb0037cc0b31bd7776613aeee36a2977080000008000ffffffff0000000000000000000000000000000000000000000000000000000000000002b066cb557f2e281efb80698396c40c4db027106b678611909d711534a107b4ca0100000000000000020095312e683e782579ea92905457e1eecb0037cc0b31bd7776613aeee36a2977080100008000ffffffff0000000000000000000000000000000000000000000000000000000000000002d342020fd5e8add1c23cde10270dbfd78faa88241186ad9cfdf1ca26eb90551601000000000000000200d362f44f76ed837cf987ad5607472df588e95db0a49c6cbf59f93feb800da02e0700000000fdffffff029216bbdfcacd0268aae40573698bce08f240b569d5d009bcaea6c2327bb2d60200000000fdffffff070b8d458a971acef0de8af774771f3163520462b6359396b064daa4d547289ae70d010000000000000001002251201359a6c1948e2bcd8383a428f1a39eddadf9592af9ae88a7a03235766dcade530bb6ccbc760f0c27ba44ec141a696823d5867e77f9f3d3ed8c3ccbee9d6bbd4391010000000000000001002251201359a6c1948e2bcd8383a428f1a39eddadf9592af9ae88a7a03235766dcade5301ef57c62c7924f324275b77c465924ead69ec98542b3263f4afc630f86e183fdf01000000000000001400225120797094fec2b5e02b4964209edf09a2121832bfdb9966ba04b55ec50f650ecede0b05a0f55aa390b0731dca6a400a05b9ead3d5e6898e62f8564f5f79868d95c16f09f1ab2d9d0bdb64be0189ee4e052c48238a9c2731ba62dc021e6177cbc1a81c910223ac20b2c224f58a4616b5f620372e2b3eb68ce185944a609107def8af4dde5b1600144d5427bda05cadc2f1114d14813bde84dc164d1501499a818545f6bae39fc03b637f2a4e1e64e590cac1bc3a6f6d71aa4443654c140100000000000005b70000018a45143b054ca8a0760afb55c9bb71ecc2f16545d1945c35a6531f35b880547d010000000000000002001600143b7243860ea1c50867931de6d9ab360e8cdc38930130dc7eb455b50cca3fd13ef34495f8af945ce6c057ed3770cfca919504a148480100000000000000020016001446bd6da71e5a8d4d09cc86eeb93fa7b92d1065c500000000000002fd690100c9518800cf51888851c9518851cf51888800ce6b208d458a971acef0de8af774771f3163520462b6359396b064daa4d547289ae70d5b6c876b876c9a6b00ce6b20e7a52e8e4b07e00548bab151a83e5c9ab2f9a910e10dcee930a1a152a939f99e5a6c876b876c9a6c9b6951ce6b20b6ccbc760f0c27ba44ec141a696823d5867e77f9f3d3ed8c3ccbee9d6bbd43915b6c876b876c9a6b51ce6b20c226167e9ee0bb5a86c8f1478ee7d7becb7bfd4d97c26a041e628c5486a8c67a5b6c876b876c9a6c9b6900ca6b00d16c876b876c9a6951ca6b51d16c876b876c9a6900cc75755188777751cc7575518877778800cc757551887777080a00000000000000d9518852cf51888852ce6b20ef57c62c7924f324275b77c465924ead69ec98542b3263f4afc630f86e183fdf516c876b876c9a6952d16b20797094fec2b5e02b4964209edf09a2121832bfdb9966ba04b55ec50f650ecede516c876b876c9a6900cd876b51cd876c9b21c450929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac000000002fd690100c9518800cf51888851c9518851cf51888800ce6b208d458a971acef0de8af774771f3163520462b6359396b064daa4d547289ae70d5b6c876b876c9a6b00ce6b20e7a52e8e4b07e00548bab151a83e5c9ab2f9a910e10dcee930a1a152a939f99e5a6c876b876c9a6c9b6951ce6b20b6ccbc760f0c27ba44ec141a696823d5867e77f9f3d3ed8c3ccbee9d6bbd43915b6c876b876c9a6b51ce6b20c226167e9ee0bb5a86c8f1478ee7d7becb7bfd4d97c26a041e628c5486a8c67a5b6c876b876c9a6c9b6900ca6b00d16c876b876c9a6951ca6b51d16c876b876c9a6900cc75755188777751cc7575518877778800cc757551887777080a00000000000000d9518852cf51888852ce6b20ef57c62c7924f324275b77c465924ead69ec98542b3263f4afc630f86e183fdf516c876b876c9a6952d16b20797094fec2b5e02b4964209edf09a2121832bfdb9966ba04b55ec50f650ecede516c876b876c9a6900cd876b51cd876c9b21c450929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac00000000247304402202631a35549a1ff77bd58b72cce37c27774f366a7178ff8d86db6494cfe0b1bc2022063b7aae1b9005ef11a609d22326da06518930403073b82a45c1ce03de4bf000e012102f84290b8b33e9e417541f93da1d6f9f7c635373bd5fd204e6ed40923d15f94b5000000024730440220051d1b5564db239e66068904ad5b389aa2c822c15a18c99ab3d64be26e031dee0220230d1dbc48cdd2ce9cdc7594ea5fd6b86ca060ca7c1ef1eec133ef3b75171f8b012102866b5636458f226b0c0dd00561f769d289f08227a9b0060e92dc09095cb2f526008306000db38c0304bbaf384380e6e5bcc53e73a390ed48d3ed771343ce3d5965f5927eb8c51b1d3f075c3bd772ccf7df829776d64eb42748bd951e80ab7ed0afa433784f900446252ed1f136147c590e28b1930440e3d6799c7e0b0718a2af3dc2373777e335838d394e92897916885e8851c521c5b235e30b361dc765cdadc7f03885ad008306001ca2e45dea67e97ba70602ed59a92904cce337c1183cd6f73d23ca6a711d81aa7787edd0968443e8f7fe60735c0d42bd47881fbf792ec30a9c317c64f6d6377910900446252ed1f136147c590e28b1930440e3d6799c7e0b0718a2af3dc2373777e335838d394e92897916885e8851c521c5b235e30b361dc765cdadc7f03885ad0000008306002608ddffbe95df5021df3aad4d3707054ba3ab35a8dc5f7946b9a06b76f102df8d56a4b0bdab586d2ecb8fb47f1c3636a5cc5747421772c317c9b7ef04f4fdbcb1e5c615599c97e24a3770c170168be054a37678e7483756b8418fd186f19461f4cd603bc5df13689120b59bb230d50b8cc2af3d3a8b6a8f1d0abfe93c8f2102fdfd4e1060330000000000000001710ac5008a463a9eba12d4078ceaff94ffd2f6979c349303e66e6ddb98188a396b991e2002c346fff89b12b24d0f6ce47fe2577968cf1eb710cd7f40b2b57327c27435f2165f74564514ebd7f33677edec0260c2fafb029f123c4888392d22ed78ee1dc44c4f4cd8b51bdc9c70f8f1988ed681b573c4351744da7efdc386bfd6934bc68057303e428ada3f0df8a511c8c535062aeab2daab6d022f08815fd0c9e7507a8c02c034128a9768cead7319427ddcb5dd8b5b5db72417177785f4b5d50487f2518babe906f396b808a6f576b03fddab0f1c72b37a6a9cd6adc52ce603295516933262df1756c623482068a4a2e1dcd4469ae6a0a0a89521e8e52d9c92320f03d08797a31f227cbc27bb047b9d8175b59c00126934205c40f458b24316ff05a338e8f581188748918dca5145bad1c711fea78c2272ea2037a9d28cae27ceaca620608f5d5711e7053bb56fe25a01615738b5bb214360279ac4cb4b09901232638039008ec96c8d65878a846468a614a18ad3cf6e7c15888045b64a9db865f494618ca19ee845537e8fae9d93b6cd472ae21f59b69501e924798c757dae4a3bdf26ec42409fd0b4afad1013896c9fb77c9ef669c95689479dcef6594f6a204d9fe5355b91ec385aa6e945fb24a07f211e52c84097d8cfb8ae4c6bfa022facd6079255bdd272e959e30bdd7f3c25fdaeb3f3b432457df435db3449347ae0da73fe2e949dc9dcd68186a85f48d7f53c6b2dc131298ba08bc7b5380d17f0bb76b21ac8145c5f757c7c3f68b7ce33c65985ca1ea4f70b7e277e33acda2a7a48807659ce83957ed4b2de31d5d9f7004a4bf2c17dc2429b6dc1b8ec23d0d16dd902cd630bd869c7fa53df7c5ba20078b5e38b42a6e4875469c35d32f14a4bc19374048f464aca0543b251be41c0b0875b4af01cf25c74f2013f915d450aca819bc441e48905481920c90c3199e3600562a8531edfc7cbc5b7a91096e98d678758f3a1cfcf5d6b7b777834e4dfb09ba4fa0a728082315178e39b134754e5ee60a6a241a4492e0222cde1aedba334dc3197526ac8fb6ab81f62fb486176aebcc99d36f610f96e887a1cd5492e3cbfc5ace320fdb6c6e44b3a6229383622381ee5eb46625e2fc82e5b8884098833926a1e0b516d57dc25f5b5a840c9a9a1012469bfe13d9f2f6204978179996d39fdd218c810c297cf9cad67fb9f0b4962c763fce090eeae5e4a29a0badf6e1ac37c8b81bfb48d71dc15be3ebdafa85d2e7631d64cbc800cba41afa9a74d1fd6bf75f60bf851b58823696c0e6fca47941d6639a868ac6621ad18b38d0a0058bc385828f68203f0c9ea6034117951a68f3702151d135fe7f5198c6e78c9294709540b3ab2a7dfa5c1708ed0b5e1a41e578dfda4c2cbca66c37b9133fdb52f4a62c06874c3aae9c969135ca3a85583cdf127bb96f38017f84b6c9cdcdccd543b0af1ebd128f09887e03a4816e0927bf7b821865718c6c300861c725caa74b9275ba40249833742c0655342a50f42752e0bbc888c3b3fd028edd72330013aafd88cec9719a4741a3aaec3bcfe645450b83e894ea4161fc1c13a8402d6f3832bc3c72a9e21e0521aaddd150e311acdf0cb63006091cfa0299fad4ba74676c314673ce0ce3b8f13fe7d2bf371070384ba2075ede8f25a2de2663e87d6518376100d61bce18a4fa745bccd201566dbd7f1d53d7c4dfbd7d55aeea7ab438c1dfe68de0f11a16fa7af95037c780973fcb28e138e4f56e3a8a200be1a571e07c854bb117faafde17564a236557ce2da9260cd90e6ac34832d7eef2e783d5e37c083d940b62091e9fa2a7ba17eed2b72b6cb845e018941af6b2351d3968a4e920cbd65ae5a899485e1b701b004bed2766a2ee0d674e1da2fd779e8c7e5db86c757170478266c660c5e1199fe1222fcade95aa779ce733fe421fb88f7f7a1d0727a22710bdc246a1c224347eb82b279e5e5a12809a8922e7fcb9100f48e84b8413e71b96969d3769c12f17a3eda389501cc1226abd6eed28886f4cbe2d96cc66a008fc0a875d76254d32a7e780fc1bc2a8582e5c8d46fe1d45bb1ca5aaaa56674aa322a5527936ba7a5253c1110cb1addc46b618051ecee059312a3b795335673f13d5200f51633cc5095ab22547f2c3b3a70227d287c02f7944782273b5faa61c85247981e159338558d3199382c2304dbe6a28c49915441666e7bd2ac36cc0fe0e5a32f412325353ba2e00750451a8a4ffe137e2abe674280d6e500deed6327d6903c5654b2923af65bc3a8352cb7a9274a35ffc95a7e2509800178a6e9746a9f7cb94f94f7158d740360efe54a32979ef4d833a8f2f89b563e986d3bd51339b7c3c48e2b08d02bb9b677d959d423985b13817d648e73876f246eb8f02cf18fb91a6f192840ef85581e05802b40fb9de70299ff4954b7cd81122f106b504738c8245bdd4dcce86d83c2903bdd72dcdc8617df7630e6310997a9827a3700a800f6bccbdf29b23dec214140f491ff80f5d31a1198f4ff6f7926dcd39d47fbb92c68e741cb1aa57feaf8b8bc8afa2eaaa5bf829efe5c5f1dedd3e74e92b160ccdd3ec09c856c8dbb997319e28700a0de1cefda2933a916c0fe411f84ce693e8c255fc89f9018394a042d34c1efd6a168d9c3c82d7104307cbd0e8833c50b5be4155bc41e44751358804a8d90cd9676c2362bbc2381e17c99a99ecd7f9c2cc7de1239816c59db606d523484cfd6b3fabcc1c7aa5f5386fdfe793d79622bc6c160b3549a970a0f248d9cdc22f279496789fc18b557abf3088d8e864dc586b5d6e7f7b1047d42c3d79d0ba6e17cb4203c95a07a957435b2926b2d90927dd59995993af335987d42397c068c15233de5eac46d043e3cab9af7142728e5cb426d76d83f656351c3885c852df3e3664baecf701645e6619849e9e68a3b2788bf3d902ef035f24607be929c90722e4abef21d870a0be2fc57982827a31aa894e8fed60654ff9123e137ae284c52c53ac48fae0a95a02a42d83769dd7d37debf8fa1abbbdc744b364f8a7a45850b0e13ab7d1be9ba2dd8a492c4993feab14e5b72a108468f0a982c4c7b352264bd6b91bc8bf37d011f727052682267e3f9582b92355e9de3883c062dea120ac459a7fe18b84957d1dfcf59d34e5637a0b56ec13317a8fa0086b3f10520d422a6e02890401f0ad066f5215f1e927bf5f4d7f1803185f6e52e2124e1ec217bd2e54db6b363d0dca3562da6493c8251f2fe7a05cb2cbb686c1019676162fb7765e777887c33ffb4a62ad633513025d538ffa70d88fc27b2645e1c9a621782a95a6bfdea47f1faf8df3c30ced8ff53b20486c76cefd41fd7b62241a94084ffb2aea68343cc6e6d9edf6fbbf14d31416d1b051becc174dad44feea45c9230825db1897ff70660a0ce935f59d09ec629d57640e8d4fca4eef4904ad5db30c7008281cf7f8b469d9035ca2a2df83b6638369bb28a59dd92e98067043aec8c3e556830fb13b3119f75f0a6b1d7d355b8427fe55a421cc9104e734ec9d80be83d08a77cc02c9b04b16ea84125348252de0a05779c8adc99eef433a9634a1b983f0ff5832585329bcd589b064d0cca6d76ce6152e4eb3ca7eb1117b4635f93cc7a9418a1fd6ef8b4dc4257a4c37afe64afdab179e1b064755c95f2a74e3b8ee7dba2f393233c4c0a1fa27af80269528e678d0b95aea1e661470b24b824fdb8afc14c49f3196d6dbfc3ca2b600b142a5f68656bb45d839b30cc632932717624eec400022eeb45840fd7bfc12a6864a1cc2334661cea9e5ec78e28b6a8bca9c67ac44396c96f5cc765de87def581ce388e033363e6c607104f642e087fe252e12a92c9def353c74eeb24af701f291bf7b10feee62b28a6ef6830d8db9048568bac211ea94b25beb6e9e3eb4d925baeb20d5699008143d270dbcc74b32ba9ea413058530a1840ec43b6e4fba8bd870d3173dad5901b3105d39c9f882b07f0c14215a25449840523b96724f02973d30de8567b978bb8f5e00a248d4b79ae4535c1d4fc516fa8a6af75dff4e16183c945c9da7e18a224a0d567826716f5fa7f1883e6fa3651ab13cb2ca4e8cb3770451e068a9999b5e158a2ca6356283147e340d685bc6afe0537cc8ceed494438c3e867da888519f655bce704922f8f173d83c7472d03d9c2fa37065a42dcf01d71c4083939c3d7c7a4951e0cdc531385fc38c3d226f00ff77d727655164d6851a8bbbc57a16023f7ccf16b12aa524e7b50abe060edea1882f6d4f2d6b2e7aa8b60490c28f7ab934d13e38ae93a662c861ff3c3331c294cb686e97bf4c62e8dc53fd7068727361b77aec64f294a56dda8e8af6744f8345849d2f53f9d0b29d07b1f38f408b3e441a707929a79dfb67d8687812a47d96c597d9abec64ab18f31b555c82e69534b3671d0b8ee056c78dc5b98c9117360d647c2979c11546e490a9cd5604ea500ada55c3cf028bee49d7395c7d4e512510c006dc6b50b9a54d26731e1ef508090f9126c42c40e28ef1c817f70890a62724aa632a84f722ddc36c79993b41d5b25e388d5a6ed64cba6602b60420eac8d3ef0b4f2c6e181984c9133045f4de7c6067e71e7979c2901e8b34fee7ee10368c2c0f653c7df5d69958763945eb215d7012636f76b3aeef2ce8fb6cd10947f71dde7ef83d8d255dc99d37131707d9f5f9472dbae96205afcddd671e904f27967caf82af9278919fa84250fb4c4e514cd66d123b40ae18a0087f966d240c917ae8339babd07e62ec17535d469245e7c3087949237be1bb30f30f5571561a8a6730244975539d8b69c2418cf0ada8d602ded28fce69fc2f71aa1b302e38bccc2984de475978c968eded292016d940d16737803591e8ba9b4b16ceeb58ed15ca58f4540a5d3a4eeb021a99b24faf4c857b0913e29a25e82d16d3d794fb60721e266f332bdc4f3f63b929a4d65032709f268900414b989d5ba98c411f57d63d52c5721a858bedb5e60007c589c71ab2eb27a8afa904e8e11513de77d754692936deb57f8d4eaed7436f60365a570b86a0cc61ee57d73bc349bfadb29cac9d141a94ffb003f8b6eaca3f489c3aa7bb868990ffda3e13b13058f3d3ab26b9c852ead84ef718a32908c4e84c428105aab28c844c872753606a3f38d27b411bbd761634320f624f53ff5d14e9402aec86d88eb77b151230a32f15ec624fbf99ba26662e42cf3281b8492f87f2936bc198b98de2c6463d983a89ada106121e9c12e867a3cf8d92848bbc636fb0f2b2244841ab6da471c1806e46a4f662960a29ad028e6017ddc3b16e54fcdc9bb1dff996c00858c146ec7cde03cadce8bac7fc3facc76395f3297777a41e104283f59cdb8db8936f4720613d948cdf698f4dece4279835361bc4e18195b16378ed110f89c80d4428526b7b9453198ed906cb891aae651104df8f62a88acb34c17c902e56297cc5facd3d6ff66c327a10362d51162ea190e7b8693e07869b49511641d8877477c3580f6c859139ba95be5eb44255fae4c91de9362fb6fe7c6601edb636cd135b59654bef50952436c6e715625a6c8f3a26c48f44f72274d9e08a2fc1b10ef67e6adaba97a78599f2904e954366e5025da3b7d1561e820c7d806132ef678323fdc2d7a917fff6c3380c08ba87065eb5c3a3f60d52813272913783e93a625cf028c76b096e706253a2f2ffa69ce57fa6ab9ad7e13a3c511a225f3f2bfb13f360907f57af4e94596ce3c2b04d5e8be07a0435aa7cdff4a36a5cb3b6e0e7fbb00d277ac0c625b365da47d62105a56c9e385e3917ba681029f184fe515feaabc756416fb45292861fcace27d376e94245e9cf94bc8c34d8a75e076918fae983103b277a8bc5346b9e2fc53b2cd93531000000000000 \ No newline at end of file From 2908bc184c08ad0c68a994d2a217b3e84861211a Mon Sep 17 00:00:00 2001 From: sanket1729 Date: Tue, 9 Aug 2022 10:53:01 -0700 Subject: [PATCH 7/9] Allow inserting inputs/outputs at specified positions While the positions of inputs and outputs don't usually matter, they do matter in covenant constructions. This allows easier construction rather than creating a new vec or swapping things around --- src/pset/mod.rs | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/pset/mod.rs b/src/pset/mod.rs index 595fcd08..cac099c7 100644 --- a/src/pset/mod.rs +++ b/src/pset/mod.rs @@ -100,6 +100,25 @@ impl PartiallySignedTransaction { self.inputs.push(inp); } + /// Add an input to pset at position i. This also updates the + /// pset global input count and the blinder index that might have shifted. + /// + /// See also: [`PartiallySignedTransaction::add_input`] + /// Panics if index is more than length. + pub fn insert_input(&mut self, inp: Input, pos: usize) { + self.global.tx_data.input_count += 1; + self.inputs.insert(pos, inp); + + for out in self.outputs_mut(){ + match out.blinder_index { + Some(i) if i >= pos as u32 => { + out.blinder_index = Some(i+1); + } + _ => {} + } + } + } + /// Read accessor to inputs pub fn inputs(&self) -> &[Input] { &self.inputs @@ -127,6 +146,14 @@ impl PartiallySignedTransaction { self.outputs.push(out); } + /// Add an output to pset at position i. This also updates the + /// pset global output count + /// Panics if index is more than length. + pub fn insert_output(&mut self, out: Output, pos: usize) { + self.global.tx_data.output_count += 1; + self.outputs.insert(pos, out); + } + /// read accessor to outputs pub fn outputs(&self) -> &[Output] { &self.outputs From 759d3012820aa18c3da36db1e38ed2df096a60bc Mon Sep 17 00:00:00 2001 From: sanket1729 Date: Thu, 25 Aug 2022 18:08:21 -0700 Subject: [PATCH 8/9] Add liquid testnet parameters --- src/address.rs | 43 +++++++++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/src/address.rs b/src/address.rs index cb5ff0d6..d6c2c17d 100644 --- a/src/address.rs +++ b/src/address.rs @@ -146,6 +146,15 @@ impl AddressParams { bech_hrp: "ert", blech_hrp: "el", }; + + /// The default liquid testnet network address parameters. + pub const LIQUID_TESTNET: AddressParams = AddressParams { + p2pkh_prefix: 36, + p2sh_prefix: 19, + blinded_prefix: 23, + bech_hrp: "tex", + blech_hrp: "tlq", + }; } /// The method used to produce an address @@ -439,7 +448,7 @@ impl Address { if data.len() < 2 || data.len() > 40 + if blinded { 33 } else { 0 } { return Err(AddressError::InvalidWitnessProgramLength(data.len() - if blinded { 33 } else { 0 })); } - + // Specific segwit v0 check. if !blinded && version.to_u8() == 0 && data.len() != 20 && data.len() != 32 { return Err(AddressError::InvalidSegwitV0ProgramLength(data.len())); @@ -649,20 +658,19 @@ impl FromStr for Address { // shorthands let liq = &AddressParams::LIQUID; let ele = &AddressParams::ELEMENTS; + let liq_test = &AddressParams::LIQUID_TESTNET; + + let net_arr = [liq, ele, liq_test]; - // Bech32. let prefix = find_prefix(s); - if match_prefix(prefix, liq.bech_hrp) { - return Address::from_bech32(s, false, liq); - } - if match_prefix(prefix, liq.blech_hrp) { - return Address::from_bech32(s, true, liq); - } - if match_prefix(prefix, ele.bech_hrp) { - return Address::from_bech32(s, false, ele); - } - if match_prefix(prefix, ele.blech_hrp) { - return Address::from_bech32(s, true, ele); + for net in net_arr.iter() { + // Bech32. + if match_prefix(prefix, net.bech_hrp) { + return Address::from_bech32(s, false, net); + } + if match_prefix(prefix, net.blech_hrp) { + return Address::from_bech32(s, true, net); + } } // Base58. @@ -675,11 +683,10 @@ impl FromStr for Address { } let p = data[0]; - if p == liq.p2pkh_prefix || p == liq.p2sh_prefix || p == liq.blinded_prefix { - return Address::from_base58(&data, liq); - } - if p == ele.p2pkh_prefix || p == ele.p2sh_prefix || p == ele.blinded_prefix { - return Address::from_base58(&data, ele); + for net in net_arr.iter() { + if p == net.p2pkh_prefix || p == net.p2sh_prefix || p == net.blinded_prefix { + return Address::from_base58(&data, net); + } } Err(AddressError::InvalidAddress(s.to_owned())) From 582325ef3dae38a3f51ebe237697d181980b0ec4 Mon Sep 17 00:00:00 2001 From: sanket1729 Date: Sat, 1 Oct 2022 11:24:48 -0700 Subject: [PATCH 9/9] rustfmt: add src/pset/mod.rs and src/blind.rs --- src/blind.rs | 513 ++++++++++++++++++++++++++++------------- src/pset/error.rs | 110 ++++++--- src/pset/macros.rs | 17 +- src/pset/map/global.rs | 167 +++++++++----- src/pset/map/input.rs | 186 ++++++++++----- src/pset/map/mod.rs | 2 +- src/pset/map/output.rs | 117 ++++++---- src/pset/mod.rs | 267 +++++++++++++-------- src/pset/raw.rs | 48 ++-- src/pset/serialize.rs | 75 +++--- 10 files changed, 982 insertions(+), 520 deletions(-) diff --git a/src/blind.rs b/src/blind.rs index 6d275ed1..6fb7ce85 100644 --- a/src/blind.rs +++ b/src/blind.rs @@ -15,17 +15,21 @@ //! # Transactions Blinding //! -use std::{self, fmt, collections::BTreeMap}; +use std::{self, collections::BTreeMap, fmt}; -use secp256k1_zkp::{self, PedersenCommitment, SecretKey, Tag, Tweak, Verification, ZERO_TWEAK, rand::{CryptoRng, RngCore}}; +use secp256k1_zkp::{ + self, + rand::{CryptoRng, RngCore}, + PedersenCommitment, SecretKey, Tag, Tweak, Verification, ZERO_TWEAK, +}; use secp256k1_zkp::{Generator, RangeProof, Secp256k1, Signing, SurjectionProof}; use crate::{AddressParams, Script, TxIn}; -use crate::{Address, AssetId, Transaction, TxOut, TxOutWitness, - confidential::{Asset, AssetBlindingFactor, Nonce, Value, - ValueBlindingFactor -}}; +use crate::{ + confidential::{Asset, AssetBlindingFactor, Nonce, Value, ValueBlindingFactor}, + Address, AssetId, Transaction, TxOut, TxOutWitness, +}; use crate::hashes; @@ -53,16 +57,25 @@ impl fmt::Display for TxOutError { match self { TxOutError::UnExpectedNullValue => write!(f, "UnExpected Null Value"), TxOutError::UnExpectedNullAsset => write!(f, "UnExpected Null Asset"), - TxOutError::MoneyOutofRange => write!(f, "Explicit amount must be\ - less than 21 million"), + TxOutError::MoneyOutofRange => write!( + f, + "Explicit amount must be\ + less than 21 million" + ), TxOutError::NonUnspendableZeroValue => { - write!(f, "Zero value explicit amounts must be provably unspendable.\ - See IsUnspendable in elements") + write!( + f, + "Zero value explicit amounts must be provably unspendable.\ + See IsUnspendable in elements" + ) } TxOutError::ZeroValueCommitment => { - write!(f, "Tried to create pedersen commitment with zero value.\ + write!( + f, + "Tried to create pedersen commitment with zero value.\ Zero value is only allowed for provable unspendable scripts, - in which case the verification check can ignore the txout") + in which case the verification check can ignore the txout" + ) } TxOutError::IncorrectBlindingFactors => { write!(f, "Incorrect Blinding factors") @@ -106,7 +119,11 @@ impl fmt::Display for VerificationError { write!(f, "Surjection Proof Error {} : for output index {}", i, e) } VerificationError::SurjectionProofVerificationError(i) => { - write!(f, "Surjection proof verification failed for output index {}", i) + write!( + f, + "Surjection proof verification failed for output index {}", + i + ) } VerificationError::IssuanceTransactionInput(i) => { write!(f, "Issuance transaction input {} not supported yet", i) @@ -121,7 +138,10 @@ impl fmt::Display for VerificationError { write!(f, "Output index {} txout: {}", i, e) } VerificationError::BalanceCheckFailed => { - write!(f, "Confidential transaction verification balance check failed") + write!( + f, + "Confidential transaction verification balance check failed" + ) } VerificationError::RangeProofMissing(i) => { write!(f, "Missing Rangeproof for output index {}", i) @@ -224,7 +244,6 @@ pub struct TxOutSecrets { } impl TxOutSecrets { - /// Create a new [`TxOutSecrets`] pub fn new( asset: AssetId, @@ -232,16 +251,19 @@ impl TxOutSecrets { value: u64, value_bf: ValueBlindingFactor, ) -> Self { - Self {asset, asset_bf, value, value_bf } + Self { + asset, + asset_bf, + value, + value_bf, + } } /// Gets the surjection inputs from [`TxOutSecrets`] /// Returns a tuple (assetid, blind_factor, generator) if the blinds are /// consistent with asset commitment /// Otherwise, returns an error - pub fn surjection_inputs(&self, secp: &Secp256k1) - -> (Generator, Tag, Tweak) - { + pub fn surjection_inputs(&self, secp: &Secp256k1) -> (Generator, Tag, Tweak) { let tag = self.asset.into_tag(); let bf = self.asset_bf.into_inner(); let gen = Generator::new_blinded(secp, tag, bf); @@ -261,11 +283,11 @@ impl TxOutSecrets { /// Explicit assets can be provided as [`SurjectionInput::Unknown`]. There is no /// need to construct a `Known` variant with secrets #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub enum SurjectionInput{ +pub enum SurjectionInput { /// Unknown inputs for whom we don't know the secrets(asset tags/blinding factors) Unknown(Asset), /// Known inputs for whom we know blinding factors - Known{ + Known { /// Asset asset: AssetId, /// Asset Blinding Factor @@ -289,7 +311,6 @@ impl From for SurjectionInput { } impl SurjectionInput { - /// Creates a new [`SurjectionInput`] from commitment pub fn from_comm(asset: Asset) -> Self { Self::Unknown(asset) @@ -304,25 +325,29 @@ impl SurjectionInput { /// that can be used while creating a new [SurjectionProof]. /// /// Only errors when the input asset is Null. - pub fn surjection_target(&self, secp: &Secp256k1) -> Result<(Generator, Tag, Tweak), TxOutError> { + pub fn surjection_target( + &self, + secp: &Secp256k1, + ) -> Result<(Generator, Tag, Tweak), TxOutError> { match self { SurjectionInput::Unknown(asset) => { - let gen = asset.into_asset_gen(secp).ok_or(TxOutError::UnExpectedNullAsset)?; + let gen = asset + .into_asset_gen(secp) + .ok_or(TxOutError::UnExpectedNullAsset)?; // Return the input as 0 tag and 0 tweak. This also correctly handles explicit case Ok((gen, Tag::default(), ZERO_TWEAK)) - }, - SurjectionInput::Known {asset, asset_bf} => { + } + SurjectionInput::Known { asset, asset_bf } => { let tag = asset.into_tag(); let bf = asset_bf.into_inner(); let gen = Generator::new_blinded(secp, tag, bf); Ok((gen, tag, bf)) - }, + } } } } impl Asset { - /// Blinds the asset such that there is a surjection proof between /// the input assets and the output blinded asset. /// @@ -339,16 +364,21 @@ impl Asset { where R: RngCore + CryptoRng, C: Signing, - S: Into + Copy + S: Into + Copy, { - let asset = self.explicit().ok_or(ConfidentialTxOutError::ExpectedExplicitAsset)?; + let asset = self + .explicit() + .ok_or(ConfidentialTxOutError::ExpectedExplicitAsset)?; let out_asset = Asset::new_confidential(secp, asset, asset_bf); let inputs = spent_utxo_secrets .iter() .enumerate() .map(|(i, surject_inp)| { - (*surject_inp).into().surjection_target(secp).map_err(|e| ConfidentialTxOutError::TxOutError(i, e)) + (*surject_inp) + .into() + .surjection_target(secp) + .map_err(|e| ConfidentialTxOutError::TxOutError(i, e)) }) .collect::, _>>()?; @@ -365,7 +395,6 @@ impl Asset { } impl Value { - /// Blinds the values and outputs the blinded value along with [`RangeProof`]. /// This computes the nonce by doing an ECDH with `receiver_blinding_pk` and `ephemeral_sk` /// @@ -381,11 +410,12 @@ impl Value { ephemeral_sk: SecretKey, spk: &Script, msg: &RangeProofMessage, - ) -> Result<(Self, Nonce, RangeProof), ConfidentialTxOutError> - { - let (nonce, shared_secret) = Nonce::with_ephemeral_sk(secp, ephemeral_sk, &receiver_blinding_pk); + ) -> Result<(Self, Nonce, RangeProof), ConfidentialTxOutError> { + let (nonce, shared_secret) = + Nonce::with_ephemeral_sk(secp, ephemeral_sk, &receiver_blinding_pk); - let (value_commit, rangeproof) = self.blind_with_shared_secret(secp, vbf, shared_secret, spk, msg)?; + let (value_commit, rangeproof) = + self.blind_with_shared_secret(secp, vbf, shared_secret, spk, msg)?; Ok((value_commit, nonce, rangeproof)) } @@ -399,10 +429,12 @@ impl Value { shared_secret: SecretKey, spk: &Script, msg: &RangeProofMessage, - ) -> Result<(Self, RangeProof), ConfidentialTxOutError> - { - let value = self.explicit().ok_or(ConfidentialTxOutError::ExpectedExplicitValue)?; - let out_asset_commitment = Generator::new_blinded(secp, msg.asset.into_tag(), msg.bf.into_inner()); + ) -> Result<(Self, RangeProof), ConfidentialTxOutError> { + let value = self + .explicit() + .ok_or(ConfidentialTxOutError::ExpectedExplicitValue)?; + let out_asset_commitment = + Generator::new_blinded(secp, msg.asset.into_tag(), msg.bf.into_inner()); let value_commitment = Value::new_confidential(secp, value, out_asset_commitment, vbf); let rangeproof = RangeProof::new( @@ -456,18 +488,26 @@ impl TxOut { where R: RngCore + CryptoRng, C: Signing, - S: Into + Copy + S: Into + Copy, { let spk = address.script_pubkey(); - let blinder = address.blinding_pubkey.ok_or(ConfidentialTxOutError::NoBlindingKeyInAddress)?; + let blinder = address + .blinding_pubkey + .ok_or(ConfidentialTxOutError::NoBlindingKeyInAddress)?; let asset_bf = AssetBlindingFactor::new(rng); let value_bf = ValueBlindingFactor::new(rng); let out_secrets = TxOutSecrets::new(asset, asset_bf, value, value_bf); let ephemeral_sk = SecretKey::new(rng); let txout = Self::with_txout_secrets( - rng, secp, spk, blinder, ephemeral_sk, out_secrets, spent_utxo_secrets - )?; + rng, + secp, + spk, + blinder, + ephemeral_sk, + out_secrets, + spent_utxo_secrets, + )?; Ok((txout, asset_bf, value_bf, ephemeral_sk)) } @@ -493,16 +533,25 @@ impl TxOut { where R: RngCore + CryptoRng, C: Signing, - S: Into + Copy + S: Into + Copy, { let exp_asset = Asset::Explicit(out_secrets.asset); let (out_asset, surjection_proof) = exp_asset.blind(rng, secp, out_secrets.asset_bf, spent_utxo_secrets)?; - let msg = RangeProofMessage { asset: out_secrets.asset, bf: out_secrets.asset_bf }; + let msg = RangeProofMessage { + asset: out_secrets.asset, + bf: out_secrets.asset_bf, + }; let exp_value = Value::Explicit(out_secrets.value); - let (out_value, nonce, range_proof) = - exp_value.blind(secp, out_secrets.value_bf, receiver_blinding_pk, ephemeral_sk, &spk, &msg)?; + let (out_value, nonce, range_proof) = exp_value.blind( + secp, + out_secrets.value_bf, + receiver_blinding_pk, + ephemeral_sk, + &spk, + &msg, + )?; let txout = TxOut { asset: out_asset, @@ -536,7 +585,7 @@ impl TxOut { where R: RngCore + CryptoRng, C: Signing, - S: Into + Copy + S: Into + Copy, { let (txout, abf, vbf, ephemeral_sk) = Self::new_not_last_confidential( rng, @@ -556,16 +605,18 @@ impl TxOut { // Internally used function for getting the generator from asset // Used in the amount verification check - fn get_asset_gen ( + fn get_asset_gen( &self, secp: &Secp256k1, ) -> Result { - self.asset.into_asset_gen(secp).ok_or(TxOutError::UnExpectedNullAsset) + self.asset + .into_asset_gen(secp) + .ok_or(TxOutError::UnExpectedNullAsset) } // Get the pedersen commitment for the txout. Used internally // in tx verification. - fn get_value_commit ( + fn get_value_commit( &self, secp: &Secp256k1, ) -> Result { @@ -575,19 +626,19 @@ impl TxOut { Value::Null => return Err(TxOutError::UnExpectedNullValue), Value::Explicit(value) => { if value > Self::MAX_MONEY { - return Err(TxOutError::MoneyOutofRange) + return Err(TxOutError::MoneyOutofRange); } if value == 0 { // zero values are only allowed if they are provably // unspendable. if self.script_pubkey.is_provably_unspendable() { - return Err(TxOutError::ZeroValueCommitment) + return Err(TxOutError::ZeroValueCommitment); } else { - return Err(TxOutError::NonUnspendableZeroValue) + return Err(TxOutError::NonUnspendableZeroValue); } } let asset_comm = self.get_asset_gen(secp)?; - Ok(PedersenCommitment::new_unblinded(secp, value, asset_comm)) + Ok(PedersenCommitment::new_unblinded(secp, value, asset_comm)) } Value::Confidential(comm) => Ok(comm), } @@ -618,12 +669,20 @@ impl TxOut { R: RngCore + CryptoRng, C: Signing, { - let out_abf = AssetBlindingFactor::new(rng); let ephemeral_sk = SecretKey::new(rng); let (txout, out_vbf) = TxOut::with_secrets_last( - rng, secp, value, spk, blinder, asset, ephemeral_sk, out_abf, spent_utxo_secrets, output_secrets + rng, + secp, + value, + spk, + blinder, + asset, + ephemeral_sk, + out_abf, + spent_utxo_secrets, + output_secrets, )?; Ok((txout, out_abf, out_vbf, ephemeral_sk)) } @@ -646,7 +705,6 @@ impl TxOut { R: RngCore + CryptoRng, C: Signing, { - let value_blind_inputs = spent_utxo_secrets .iter() .map(|utxo_sec| utxo_sec.value_blind_inputs()) @@ -657,11 +715,23 @@ impl TxOut { .map(|e| e.value_blind_inputs()) .collect::>(); - let out_vbf = - ValueBlindingFactor::last(secp, value, out_abf, &value_blind_inputs, &value_blind_outputs); + let out_vbf = ValueBlindingFactor::last( + secp, + value, + out_abf, + &value_blind_inputs, + &value_blind_outputs, + ); let out_secrets = TxOutSecrets::new(asset, out_abf, value, out_vbf); - let txout = - TxOut::with_txout_secrets(rng, secp, spk, blinder, ephemeral_sk, out_secrets, spent_utxo_secrets)?; + let txout = TxOut::with_txout_secrets( + rng, + secp, + spk, + blinder, + ephemeral_sk, + out_secrets, + spent_utxo_secrets, + )?; Ok((txout, out_vbf)) } @@ -765,7 +835,6 @@ impl From for UnblindError { } impl TxIn { - /// Blind issuances for this [`TxIn`]. Asset amount and token amount must be /// set in [`AssetIssuance`](crate::AssetIssuance) field for this input pub fn blind_issuances_with_bfs( @@ -782,17 +851,25 @@ impl TxIn { let (asset_id, token_id) = self.issuance_ids(); let arr = vec![ (issue_vbf, self.asset_issuance.amount, issue_sk, asset_id), - (token_vbf, self.asset_issuance.inflation_keys, token_sk, token_id) + ( + token_vbf, + self.asset_issuance.inflation_keys, + token_sk, + token_id, + ), ]; for (i, (bf, amt, blind_sk, asset)) in arr.into_iter().enumerate() { let v = match amt { Value::Null => continue, // nothing to blind Value::Explicit(0) => return Err(BlindError::ZeroValueBlindingNotAllowed), Value::Confidential(_) => return Err(BlindError::IssuanceAmountMustBeExplicit), - Value::Explicit(v) => Value::Explicit(v) + Value::Explicit(v) => Value::Explicit(v), }; let spk = Script::new(); - let msg = RangeProofMessage { asset, bf: AssetBlindingFactor::zero() }; + let msg = RangeProofMessage { + asset, + bf: AssetBlindingFactor::zero(), + }; let (comm, prf) = v.blind_with_shared_secret(secp, bf, blind_sk, &spk, &msg)?; if i == 0 { self.asset_issuance.amount = comm; @@ -813,8 +890,15 @@ impl TxIn { &mut self, secp: &Secp256k1, rng: &mut R, - ) -> Result<(ValueBlindingFactor, SecretKey, ValueBlindingFactor, SecretKey), BlindError> { - + ) -> Result< + ( + ValueBlindingFactor, + SecretKey, + ValueBlindingFactor, + SecretKey, + ), + BlindError, + > { let issue_vbf = ValueBlindingFactor::new(rng); let token_vbf = ValueBlindingFactor::new(rng); let issue_sk = SecretKey::new(rng); @@ -826,7 +910,7 @@ impl TxIn { /// Data structure for Unifying inputs and pseudo-inputs. #[derive(Debug, Clone, Copy, Ord, PartialOrd, Eq, PartialEq, Hash)] -pub enum TxInType{ +pub enum TxInType { /// Regular input Input(usize), /// Issuance Pseudo-input @@ -886,8 +970,7 @@ impl Transaction { &self, secp: &Secp256k1, spent_utxos: &[TxOut], - ) -> Result<(), VerificationError> - { + ) -> Result<(), VerificationError> { if spent_utxos.len() != self.input.len() { return Err(VerificationError::UtxoInputLenMismatch); } @@ -896,12 +979,14 @@ impl Transaction { let mut out_commits = vec![]; let mut domain = vec![]; for (i, inp) in self.input.iter().enumerate() { - let gen = spent_utxos[i].get_asset_gen(secp) + let gen = spent_utxos[i] + .get_asset_gen(secp) .map_err(|e| VerificationError::SpentTxOutError(i, e))?; domain.push(gen); in_commits.push( - spent_utxos[i].get_value_commit(secp) - .map_err(|e| VerificationError::SpentTxOutError(i, e))? + spent_utxos[i] + .get_value_commit(secp) + .map_err(|e| VerificationError::SpentTxOutError(i, e))?, ); if inp.has_issuance() { let (asset_id, token_id) = inp.issuance_ids(); @@ -917,7 +1002,7 @@ impl Transaction { domain.push(gen); let comm = PedersenCommitment::new_unblinded(secp, *v, gen); in_commits.push(comm) - }, + } Value::Confidential(comm) => { let gen = Generator::new_unblinded(secp, asset.into_tag()); domain.push(gen); @@ -929,19 +1014,24 @@ impl Transaction { } for (i, out) in self.output.iter().enumerate() { - // Compute the value commitments and asset generator - let out_commit = out.get_value_commit(secp) + let out_commit = out + .get_value_commit(secp) .map_err(|e| VerificationError::SpentTxOutError(i, e))?; out_commits.push(out_commit); // rangeproof checks if let Some(comm) = out.value.commitment() { - let gen = out.get_asset_gen(secp) - .map_err(|e| VerificationError::TxOutError(i, e))?; - let rangeproof = out.witness.rangeproof.as_ref().ok_or( - VerificationError::RangeProofMissing(i))?; - rangeproof.verify(secp, comm, out.script_pubkey.as_bytes(), gen) + let gen = out + .get_asset_gen(secp) + .map_err(|e| VerificationError::TxOutError(i, e))?; + let rangeproof = out + .witness + .rangeproof + .as_ref() + .ok_or(VerificationError::RangeProofMissing(i))?; + rangeproof + .verify(secp, comm, out.script_pubkey.as_bytes(), gen) .map_err(|e| VerificationError::RangeProofError(i, e))?; } else { // No rangeproof checks for explicit values @@ -949,10 +1039,13 @@ impl Transaction { // Surjection proof checks if let Some(gen) = out.asset.commitment() { - let surjectionproof = out.witness.surjection_proof.as_ref().ok_or( - VerificationError::SurjectionProofMissing(i))?; + let surjectionproof = out + .witness + .surjection_proof + .as_ref() + .ok_or(VerificationError::SurjectionProofMissing(i))?; if !surjectionproof.verify(secp, gen, &domain) { - return Err(VerificationError::SurjectionProofVerificationError(i)) + return Err(VerificationError::SurjectionProofVerificationError(i)); } } else { // No surjection proof checks for explicit assets @@ -960,7 +1053,7 @@ impl Transaction { } // Final Balance check if !secp256k1_zkp::verify_commitments_sum_to_equal(secp, &in_commits, &out_commits) { - return Err(VerificationError::BalanceCheckFailed) + return Err(VerificationError::BalanceCheckFailed); } Ok(()) } @@ -984,20 +1077,30 @@ impl Transaction { { let mut blinds = BTreeMap::new(); // Blinding Issuances unsupported - for (i, txin) in self.input.iter_mut().enumerate() { + for (i, txin) in self.input.iter_mut().enumerate() { if txin.has_issuance() && blind_issuances { let (iss_vbf, iss_sk, tkn_vbf, tkn_sk) = txin.blind_issuances(secp, rng)?; if txin.asset_issuance.amount.is_confidential() { - blinds.insert(TxInType::Issuance(i), (AssetBlindingFactor::zero(), iss_vbf, iss_sk)); + blinds.insert( + TxInType::Issuance(i), + (AssetBlindingFactor::zero(), iss_vbf, iss_sk), + ); } if txin.asset_issuance.inflation_keys.is_confidential() { - blinds.insert(TxInType::ReIssuance(i), (AssetBlindingFactor::zero(), tkn_vbf, tkn_sk)); + blinds.insert( + TxInType::ReIssuance(i), + (AssetBlindingFactor::zero(), tkn_vbf, tkn_sk), + ); } } } // Everything must be explicit - if !self.output.iter().all(|o| o.asset.is_explicit() && o.value.is_explicit()) { - return Err(BlindError::MustHaveAllExplicitTxOuts) + if !self + .output + .iter() + .all(|o| o.asset.is_explicit() && o.value.is_explicit()) + { + return Err(BlindError::MustHaveAllExplicitTxOuts); } // All outputs with script let num_to_blind = self @@ -1010,8 +1113,7 @@ impl Transaction { let mut last_output_index = None; for (i, out) in self.output.iter_mut().enumerate() { if out.is_fee() || !out.nonce.is_confidential() { - out_secrets.push( - TxOutSecrets::new( + out_secrets.push(TxOutSecrets::new( out.asset.explicit().unwrap(), AssetBlindingFactor::zero(), out.value.explicit().unwrap(), @@ -1021,17 +1123,21 @@ impl Transaction { } let blinder = out.nonce.commitment().expect("Confidential"); - let address = Address::from_script(&out.script_pubkey, Some(blinder), &AddressParams::ELEMENTS) - .ok_or(BlindError::InvalidAddress)?; + let address = + Address::from_script(&out.script_pubkey, Some(blinder), &AddressParams::ELEMENTS) + .ok_or(BlindError::InvalidAddress)?; if num_blinded + 1 < num_to_blind { - let (conf_out, abf, vbf, ephemeral_sk) = TxOut::new_not_last_confidential( - rng, secp, out.value.explicit().unwrap(), address, out.asset.explicit().unwrap(), &spent_utxo_secrets + rng, + secp, + out.value.explicit().unwrap(), + address, + out.asset.explicit().unwrap(), + &spent_utxo_secrets, )?; blinds.insert(TxInType::Input(i), (abf, vbf, ephemeral_sk)); - out_secrets.push( - TxOutSecrets::new( + out_secrets.push(TxOutSecrets::new( out.asset.explicit().unwrap(), abf, out.value.explicit().unwrap(), @@ -1053,14 +1159,21 @@ impl Transaction { out.value.explicit().unwrap(), out.asset.explicit().unwrap(), out.script_pubkey.clone(), // TODO: Possible to avoid this clone in future with _mut APIs - blinder + blinder, ) }; // Get Vec<&T> from Vec let out_secrets = out_secrets.iter().collect::>(); let (conf_out, abf, vbf, ephemeral_sk) = TxOut::new_last_confidential( - rng, secp, value, asset, spk, blinder, spent_utxo_secrets, &out_secrets + rng, + secp, + value, + asset, + spk, + blinder, + spent_utxo_secrets, + &out_secrets, )?; blinds.insert(TxInType::Input(last_index), (abf, vbf, ephemeral_sk)); @@ -1094,13 +1207,19 @@ impl fmt::Display for BlindError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { match self { BlindError::InvalidAddress => { - write!(f, "Only sending to valid addresses is supported as of now. \ - Manually construct transactions to send to custom script pubkeys") + write!( + f, + "Only sending to valid addresses is supported as of now. \ + Manually construct transactions to send to custom script pubkeys" + ) } BlindError::TooFewBlindingOutputs => { - write!(f, "Transactions must have atleast confidential outputs \ + write!( + f, + "Transactions must have atleast confidential outputs \ marked for blinding. To mark a output for blinding set nonce field\ - with a blinding pubkey") + with a blinding pubkey" + ) } BlindError::MustHaveAllExplicitTxOuts => { write!(f, "Transaction must all outputs explicit") @@ -1109,8 +1228,12 @@ impl fmt::Display for BlindError { write!(f, "{}", e) } BlindError::NoIssuanceToBlind => write!(f, "No Issuance present"), - BlindError::ZeroValueBlindingNotAllowed => write!(f, "Zero value blinding is not allowed"), - BlindError::IssuanceAmountMustBeExplicit => write!(f, "Issuance amount must be explicit to blind"), + BlindError::ZeroValueBlindingNotAllowed => { + write!(f, "Zero value blinding is not allowed") + } + BlindError::IssuanceAmountMustBeExplicit => { + write!(f, "Issuance amount must be explicit to blind") + } } } } @@ -1147,9 +1270,7 @@ pub trait BlindValueProofs: Sized { ) -> bool; } - impl BlindValueProofs for RangeProof { - /// Outputs a `[RangeProof]` that blinded value_commit /// corresponds to explicit value fn blind_value_proof( @@ -1159,19 +1280,19 @@ impl BlindValueProofs for RangeProof { value_commit: PedersenCommitment, asset_gen: Generator, vbf: ValueBlindingFactor, - ) -> Result{ + ) -> Result { RangeProof::new( secp, - explicit_val, // min_value - value_commit, // value_commit - explicit_val, // value - vbf.into_inner(), // blinding factor - &[], // message - &[], // add commitment + explicit_val, // min_value + value_commit, // value_commit + explicit_val, // value + vbf.into_inner(), // blinding factor + &[], // message + &[], // add commitment SecretKey::new(rng), // nonce - -1, // exp - 0, // min bits - asset_gen, // additional gen + -1, // exp + 0, // min bits + asset_gen, // additional gen ) } @@ -1186,9 +1307,7 @@ impl BlindValueProofs for RangeProof { ) -> bool { let r = self.verify(secp, value_commit, &[], asset_gen); match r { - Ok(e) => { - e.start == explicit_val && e.end - 1 == explicit_val - } + Ok(e) => e.start == explicit_val && e.end - 1 == explicit_val, Err(..) => return false, } } @@ -1228,7 +1347,7 @@ impl BlindAssetProofs for SurjectionProof { rng, asset.into_tag(), abf.into_inner(), - &[(gen, asset.into_tag(), ZERO_TWEAK)] + &[(gen, asset.into_tag(), ZERO_TWEAK)], ) } @@ -1245,15 +1364,15 @@ impl BlindAssetProofs for SurjectionProof { #[cfg(test)] mod tests { - use crate::encode; - use crate::hashes::hex::FromHex; - use rand::thread_rng; - use secp256k1_zkp::SECP256K1; use super::*; - use crate::encode::deserialize; use crate::confidential; + use crate::encode; + use crate::encode::deserialize; + use crate::hashes::hex::FromHex; use crate::Script; use bitcoin::{self, Network, PrivateKey, PublicKey}; + use rand::thread_rng; + use secp256k1_zkp::SECP256K1; #[test] fn test_blind_tx() { @@ -1261,33 +1380,71 @@ mod tests { let tx_hex = "020000000001741498f6da8f47eb438d0fb9de099b7e29c0e011b9ab64c3e0eb097a09a6a9220100000000fdffffff0301230f4f5d4b7c6fa845806ee4f67713459e1b69e8e60fcee2e4940c7a0d5de1b201000775f04dedb2d102a11e47fd7a0edfb424a43b2d3cf29d700d4b168c92e115709ff7d15070e201dd16001483641e58db3de6067f010d71c9782874572af9fb01230f4f5d4b7c6fa845806ee4f67713459e1b69e8e60fcee2e4940c7a0d5de1b20100000000000f42400206a1039b0fe0d110d2108f2cc49d637f95b6ac18045af5b302b3c14bf8457994160014ad65ebbed8416659141cc788c1b917d6ff3e059901230f4f5d4b7c6fa845806ee4f67713459e1b69e8e60fcee2e4940c7a0d5de1b20100000000000000f9000000000000"; let mut tx: Transaction = deserialize(&Vec::::from_hex(tx_hex).unwrap()[..]).unwrap(); let spent_utxo_secrets = TxOutSecrets { - asset: AssetId::from_hex("b2e15d0d7a0c94e4e2ce0fe6e8691b9e451377f6e46e8045a86f7c4b5d4f0f23").unwrap(), - asset_bf: AssetBlindingFactor::from_hex("a5b3d111cdaa5fc111e2723df4caf315864f25fb4610cc737f10d5a55cd4096f").unwrap(), - value: bitcoin::Amount::from_str_in("20999997.97999114", bitcoin::Denomination::Bitcoin).unwrap().to_sat(), - value_bf: ValueBlindingFactor::from_hex("e36a4de359469f547571d117bc5509fb74fba73c84b0cdd6f4edfa7ff7fa457d").unwrap(), + asset: AssetId::from_hex( + "b2e15d0d7a0c94e4e2ce0fe6e8691b9e451377f6e46e8045a86f7c4b5d4f0f23", + ) + .unwrap(), + asset_bf: AssetBlindingFactor::from_hex( + "a5b3d111cdaa5fc111e2723df4caf315864f25fb4610cc737f10d5a55cd4096f", + ) + .unwrap(), + value: bitcoin::Amount::from_str_in( + "20999997.97999114", + bitcoin::Denomination::Bitcoin, + ) + .unwrap() + .to_sat(), + value_bf: ValueBlindingFactor::from_hex( + "e36a4de359469f547571d117bc5509fb74fba73c84b0cdd6f4edfa7ff7fa457d", + ) + .unwrap(), }; #[cfg(feature = "serde")] { use serde_json; - let spent_utxo_secrets_serde: TxOutSecrets = serde_json::from_str(r#" + let spent_utxo_secrets_serde: TxOutSecrets = serde_json::from_str( + r#" { "asset": "b2e15d0d7a0c94e4e2ce0fe6e8691b9e451377f6e46e8045a86f7c4b5d4f0f23", "asset_bf": "a5b3d111cdaa5fc111e2723df4caf315864f25fb4610cc737f10d5a55cd4096f", "value": 2099999797999114, "value_bf": "e36a4de359469f547571d117bc5509fb74fba73c84b0cdd6f4edfa7ff7fa457d" - }"#).unwrap(); + }"#, + ) + .unwrap(); assert_eq!(spent_utxo_secrets, spent_utxo_secrets_serde); } let secp = secp256k1_zkp::Secp256k1::new(); - let _bfs = tx.blind(&mut thread_rng(), &secp, &[spent_utxo_secrets], false).unwrap(); + let _bfs = tx + .blind(&mut thread_rng(), &secp, &[spent_utxo_secrets], false) + .unwrap(); let spent_utxo = TxOut { - asset: Asset::from_commitment(&Vec::::from_hex("0baf634b18e1880c96dcf9947b0e0fd2d38d66d723339174df3fd980148c2f0bb3").unwrap()).unwrap(), - value: Value::from_commitment(&Vec::::from_hex("093baba9076190867fbc5e43132cb2f82245caf603b493d7c0da8b7eda7912fa2c").unwrap()).unwrap(), - nonce: Nonce::from_commitment(&Vec::::from_hex("02a96a456f4936dcf0afbc325ac3798c4464e7b66dd460d564f3f91882d6089a3b").unwrap()).unwrap(), - script_pubkey: Script::from_hex("0014d2bcde17e7744f6377466ca1bd35d212954674c8").unwrap(), + asset: Asset::from_commitment( + &Vec::::from_hex( + "0baf634b18e1880c96dcf9947b0e0fd2d38d66d723339174df3fd980148c2f0bb3", + ) + .unwrap(), + ) + .unwrap(), + value: Value::from_commitment( + &Vec::::from_hex( + "093baba9076190867fbc5e43132cb2f82245caf603b493d7c0da8b7eda7912fa2c", + ) + .unwrap(), + ) + .unwrap(), + nonce: Nonce::from_commitment( + &Vec::::from_hex( + "02a96a456f4936dcf0afbc325ac3798c4464e7b66dd460d564f3f91882d6089a3b", + ) + .unwrap(), + ) + .unwrap(), + script_pubkey: Script::from_hex("0014d2bcde17e7744f6377466ca1bd35d212954674c8") + .unwrap(), witness: TxOutWitness::default(), }; tx.verify_tx_amt_proofs(&secp, &[spent_utxo]).unwrap(); @@ -1332,7 +1489,12 @@ mod tests { input_abf, input_vbf, )]; */ - let txout_secrets = TxOutSecrets { asset, asset_bf, value, value_bf}; + let txout_secrets = TxOutSecrets { + asset, + asset_bf, + value, + value_bf, + }; let spent_utxo_secrets = [txout_secrets]; let (txout, _, _, _) = TxOut::new_not_last_confidential( @@ -1353,7 +1515,6 @@ mod tests { #[test] fn blind_value_proof_test() { - let id = AssetId::from_slice(&[1u8; 32]).unwrap(); let abf = AssetBlindingFactor::new(&mut thread_rng()); let asset = confidential::Asset::new_confidential(SECP256K1, id, abf); @@ -1370,8 +1531,9 @@ mod tests { explicit_val, value_comm, asset_gen, - vbf - ).unwrap(); + vbf, + ) + .unwrap(); let res = proof.blind_value_proof_verify(SECP256K1, explicit_val, asset_gen, value_comm); assert!(res); @@ -1385,12 +1547,8 @@ mod tests { let asset_comm = asset.commitment().unwrap(); // Create the proof - let proof = SurjectionProof::blind_asset_proof( - &mut thread_rng(), - SECP256K1, - id, - abf, - ).unwrap(); + let proof = + SurjectionProof::blind_asset_proof(&mut thread_rng(), SECP256K1, id, abf).unwrap(); let res = proof.blind_asset_proof_verify(SECP256K1, id, asset_comm); assert!(res); @@ -1405,19 +1563,60 @@ mod tests { let bytes = Vec::::from_hex(tx_str).unwrap(); let tx = encode::deserialize::(&bytes).unwrap(); - let mut utxos = [TxOut::default(), TxOut::default(), TxOut::default(), TxOut::default()]; + let mut utxos = [ + TxOut::default(), + TxOut::default(), + TxOut::default(), + TxOut::default(), + ]; { - utxos[0].asset = Asset::from_commitment(&Vec::::from_hex("0ae7a52e8e4b07e00548bab151a83e5c9ab2f9a910e10dcee930a1a152a939f99e").unwrap()).unwrap(); + utxos[0].asset = Asset::from_commitment( + &Vec::::from_hex( + "0ae7a52e8e4b07e00548bab151a83e5c9ab2f9a910e10dcee930a1a152a939f99e", + ) + .unwrap(), + ) + .unwrap(); utxos[0].value = Value::Explicit(1); - utxos[1].asset = Asset::from_commitment(&Vec::::from_hex("0bc226167e9ee0bb5a86c8f1478ee7d7becb7bfd4d97c26a041e628c5486a8c67a").unwrap()).unwrap(); + utxos[1].asset = Asset::from_commitment( + &Vec::::from_hex( + "0bc226167e9ee0bb5a86c8f1478ee7d7becb7bfd4d97c26a041e628c5486a8c67a", + ) + .unwrap(), + ) + .unwrap(); utxos[1].value = Value::Explicit(1); - utxos[2].asset = Asset::from_commitment(&Vec::::from_hex("0b495dbfc356993c5ac157c3d04fadf6f198a7e35a873df482ad9e4e95daa8aa7e").unwrap()).unwrap(); - utxos[2].value = Value::from_commitment(&Vec::::from_hex("08e0ac2ab5f3c173d5e0652a2ec209a9a370a4e510178e73c2f22f9e132341abf4").unwrap()).unwrap(); + utxos[2].asset = Asset::from_commitment( + &Vec::::from_hex( + "0b495dbfc356993c5ac157c3d04fadf6f198a7e35a873df482ad9e4e95daa8aa7e", + ) + .unwrap(), + ) + .unwrap(); + utxos[2].value = Value::from_commitment( + &Vec::::from_hex( + "08e0ac2ab5f3c173d5e0652a2ec209a9a370a4e510178e73c2f22f9e132341abf4", + ) + .unwrap(), + ) + .unwrap(); - utxos[3].asset = Asset::from_commitment(&Vec::::from_hex("0aa0956d60687982d5e73d52f8c5902478754e5f0e2e5ceff5ae53fa9681c12ae1").unwrap()).unwrap(); - utxos[3].value = Value::from_commitment(&Vec::::from_hex("094b35f1e86b097ccf0b3a826570c089c724ed9cf22620937500b14acdd169e7bf").unwrap()).unwrap(); + utxos[3].asset = Asset::from_commitment( + &Vec::::from_hex( + "0aa0956d60687982d5e73d52f8c5902478754e5f0e2e5ceff5ae53fa9681c12ae1", + ) + .unwrap(), + ) + .unwrap(); + utxos[3].value = Value::from_commitment( + &Vec::::from_hex( + "094b35f1e86b097ccf0b3a826570c089c724ed9cf22620937500b14acdd169e7bf", + ) + .unwrap(), + ) + .unwrap(); } tx.verify_tx_amt_proofs(&secp, &utxos).unwrap(); } diff --git a/src/pset/error.rs b/src/pset/error.rs index b680c619..041284a1 100644 --- a/src/pset/error.rs +++ b/src/pset/error.rs @@ -14,13 +14,13 @@ use std::{error, fmt}; -use crate::Txid; use crate::encode; +use crate::Txid; use super::raw; -use crate::hashes; use crate::blind::ConfidentialTxOutError; +use crate::hashes; use secp256k1_zkp; #[derive(Copy, Clone, PartialEq, Eq, Debug)] @@ -119,30 +119,54 @@ impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { Error::InvalidKey(ref rkey) => write!(f, "invalid key: {}", rkey), - Error::InvalidProprietaryKey => write!(f, "non-proprietary key type found when proprietary key was expected"), + Error::InvalidProprietaryKey => write!( + f, + "non-proprietary key type found when proprietary key was expected" + ), Error::DuplicateKey(ref rkey) => write!(f, "duplicate key: {}", rkey), Error::LocktimeConflict => write!(f, "conflicting locktime requirements"), - Error::UniqueIdMismatch { expected: ref e, actual: ref a } => write!(f, "different id: expected {}, actual {}", e, a), - Error::NonStandardSigHashType(ref sht) => write!(f, "non-standard sighash type: {}", sht), + Error::UniqueIdMismatch { + expected: ref e, + actual: ref a, + } => write!(f, "different id: expected {}, actual {}", e, a), + Error::NonStandardSigHashType(ref sht) => { + write!(f, "non-standard sighash type: {}", sht) + } Error::InvalidMagic => f.write_str("invalid magic"), Error::InvalidSeparator => f.write_str("invalid separator"), - Error::UnsignedTxHasScriptSigs => f.write_str("the unsigned transaction has script sigs"), - Error::UnsignedTxHasScriptWitnesses => f.write_str("the unsigned transaction has script witnesses"), + Error::UnsignedTxHasScriptSigs => { + f.write_str("the unsigned transaction has script sigs") + } + Error::UnsignedTxHasScriptWitnesses => { + f.write_str("the unsigned transaction has script witnesses") + } Error::MustHaveUnsignedTx => { f.write_str("partially signed transactions must have an unsigned transaction") } Error::NoMorePairs => f.write_str("no more key-value pairs for this pset map"), Error::HashParseError(e) => write!(f, "Hash Parse Error: {}", e), - Error::InvalidPreimageHashPair{ref preimage, ref hash, ref hash_type} => { + Error::InvalidPreimageHashPair { + ref preimage, + ref hash, + ref hash_type, + } => { // directly using debug forms of psethash enums - write!(f, "Preimage {:?} does not match {:?} hash {:?}", preimage, hash_type, hash ) + write!( + f, + "Preimage {:?} does not match {:?} hash {:?}", + preimage, hash_type, hash + ) + } + Error::MergeConflict(ref s) => { + write!(f, "Merge conflict: {}", s) } - Error::MergeConflict(ref s) => { write!(f, "Merge conflict: {}", s) } Error::ConsensusEncoding => f.write_str("bitcoin consensus encoding error"), Error::TooLargePset => { write!(f, "Psets with 10_000 or more inputs/outputs unsupported") } - Error::ExpiredPsbtv0Field => f.write_str("psbt v0 field specified in pset(based on pset)"), + Error::ExpiredPsbtv0Field => { + f.write_str("psbt v0 field specified in pset(based on pset)") + } Error::IncorrectPsetVersion => f.write_str("Pset version must be 2"), Error::MissingTxVersion => f.write_str("PSET missing global transaction version"), Error::MissingInputCount => f.write_str("PSET missing input count"), @@ -150,21 +174,39 @@ impl fmt::Display for Error { Error::MissingInputPrevTxId => f.write_str("PSET input missing previous txid"), Error::MissingInputPrevVout => f.write_str("PSET input missing previous output index"), Error::SecpScalarSizeError(actual) => { - write!(f, "PSET blinding scalars must be 32 bytes. Found {} bytes", actual) - } - Error::MissingOutputValue => f.write_str("PSET output missing value. Must have \ - at least one of explicit/confidential value set"), - Error::MissingOutputAsset => f.write_str("PSET output missing asset. Must have \ - at least one of explicit/confidential asset set"), - Error::MissingBlinderIndex => f.write_str("Output is blinded but does not have a blinder index"), - Error::MissingBlindingInfo => f.write_str("Output marked for blinding, but missing \ - some blinding information"), - Error::MissingOutputSpk => f.write_str("PSET output missing script pubkey. Must have \ - exactly one of explicit/confidential script pubkey set"), - Error::InputCountMismatch => f.write_str("PSET input count global field must \ - match the number of inputs"), - Error::OutputCountMismatch => f.write_str("PSET output count global field must \ - match the number of outputs"), + write!( + f, + "PSET blinding scalars must be 32 bytes. Found {} bytes", + actual + ) + } + Error::MissingOutputValue => f.write_str( + "PSET output missing value. Must have \ + at least one of explicit/confidential value set", + ), + Error::MissingOutputAsset => f.write_str( + "PSET output missing asset. Must have \ + at least one of explicit/confidential asset set", + ), + Error::MissingBlinderIndex => { + f.write_str("Output is blinded but does not have a blinder index") + } + Error::MissingBlindingInfo => f.write_str( + "Output marked for blinding, but missing \ + some blinding information", + ), + Error::MissingOutputSpk => f.write_str( + "PSET output missing script pubkey. Must have \ + exactly one of explicit/confidential script pubkey set", + ), + Error::InputCountMismatch => f.write_str( + "PSET input count global field must \ + match the number of inputs", + ), + Error::OutputCountMismatch => f.write_str( + "PSET output count global field must \ + match the number of outputs", + ), } } } @@ -223,8 +265,12 @@ impl fmt::Display for PsetBlindError { write!(f, "Atleast one output secrets should be provided") } PsetBlindError::BlinderIndexOutOfBounds(i, bl) => { - write!(f, "Blinder index {} for output index {} must be less \ - than total input count", bl, i) + write!( + f, + "Blinder index {} for output index {} must be less \ + than total input count", + bl, i + ) } PsetBlindError::MissingInputBlinds(i, bl) => { write!(f, "Output index {} expects blinding input index {}", i, bl) @@ -239,9 +285,13 @@ impl fmt::Display for PsetBlindError { write!(f, "Blinding error {} at output index {}", e, i) } PsetBlindError::BlindingProofsCreationError(i, e) => { - write!(f, "Blinding proof creation error {} at output index {}", e, i) + write!( + f, + "Blinding proof creation error {} at output index {}", + e, i + ) } } } } -impl error::Error for PsetBlindError {} \ No newline at end of file +impl error::Error for PsetBlindError {} diff --git a/src/pset/macros.rs b/src/pset/macros.rs index 6ad0c0ed..82785eda 100644 --- a/src/pset/macros.rs +++ b/src/pset/macros.rs @@ -14,7 +14,11 @@ #[allow(unused_macros)] macro_rules! hex_pset { - ($s:expr) => { $crate::encode::deserialize(& as $crate::hashes::hex::FromHex>::from_hex($s).unwrap()) }; + ($s:expr) => { + $crate::encode::deserialize( + & as $crate::hashes::hex::FromHex>::from_hex($s).unwrap(), + ) + }; } macro_rules! merge { @@ -61,10 +65,7 @@ macro_rules! impl_psetmap_consensus_encoding { ) -> Result { let mut len = 0; for pair in $crate::pset::Map::get_pairs(self)? { - len += $crate::encode::Encodable::consensus_encode( - &pair, - &mut s, - )?; + len += $crate::encode::Encodable::consensus_encode(&pair, &mut s)?; } Ok(len + $crate::encode::Encodable::consensus_encode(&0x00_u8, s)?) @@ -143,7 +144,6 @@ macro_rules! impl_pset_insert_pair { }; } - #[cfg_attr(rustfmt, rustfmt_skip)] macro_rules! impl_pset_get_pair { ($rv:ident.push($slf:ident.$unkeyed_name:ident as <$unkeyed_typeval:expr, _>)) => { @@ -211,9 +211,8 @@ macro_rules! impl_pset_hash_deserialize { ($hash_type:ty) => { impl $crate::pset::serialize::Deserialize for $hash_type { fn deserialize(bytes: &[u8]) -> Result { - <$hash_type>::from_slice(&bytes[..]).map_err(|e| { - $crate::pset::Error::from(e).into() - }) + <$hash_type>::from_slice(&bytes[..]) + .map_err(|e| $crate::pset::Error::from(e).into()) } } }; diff --git a/src/pset/map/global.rs b/src/pset/map/global.rs index 76d06a44..88e933d7 100644 --- a/src/pset/map/global.rs +++ b/src/pset/map/global.rs @@ -13,16 +13,19 @@ // If not, see . // -use std::{collections::BTreeMap, io::{self, Cursor, Read}}; -use std::collections::btree_map::Entry; use std::cmp; +use std::collections::btree_map::Entry; +use std::{ + collections::BTreeMap, + io::{self, Cursor, Read}, +}; -use crate::VarInt; -use crate::encode::{Decodable}; -use crate::pset::{self, map::Map, raw, Error}; -use crate::endian::u32_to_array_le; -use bitcoin::util::bip32::{ExtendedPubKey, KeySource, Fingerprint, DerivationPath, ChildNumber}; use crate::encode; +use crate::encode::Decodable; +use crate::endian::u32_to_array_le; +use crate::pset::{self, map::Map, raw, Error}; +use crate::VarInt; +use bitcoin::util::bip32::{ChildNumber, DerivationPath, ExtendedPubKey, Fingerprint, KeySource}; use secp256k1_zkp::Tweak; // (Not used in pset) Type: Unsigned Transaction PSET_GLOBAL_UNSIGNED_TX = 0x00 @@ -47,7 +50,6 @@ const PSET_GLOBAL_VERSION: u8 = 0xFB; /// Type: Proprietary Use Type PSET_GLOBAL_PROPRIETARY = 0xFC const PSET_GLOBAL_PROPRIETARY: u8 = 0xFC; - /// Proprietary fields in elements /// Type: Global Scalars used in range proofs = 0x00 const PSBT_ELEMENTS_GLOBAL_SCALAR: u8 = 0x00; @@ -76,7 +78,7 @@ pub struct TxData { pub tx_modifiable: Option, } -impl Default for TxData{ +impl Default for TxData { fn default() -> Self { Self { // tx version must be 2 @@ -107,10 +109,16 @@ pub struct Global { /// Elements tx modifiable flag pub elements_tx_modifiable_flag: Option, /// Other Proprietary fields - #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_as_seq_byte_values"))] + #[cfg_attr( + feature = "serde", + serde(with = "crate::serde_utils::btreemap_as_seq_byte_values") + )] pub proprietary: BTreeMap>, /// Unknown global key-value pairs. - #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_as_seq_byte_values"))] + #[cfg_attr( + feature = "serde", + serde(with = "crate::serde_utils::btreemap_as_seq_byte_values") + )] pub unknown: BTreeMap>, } @@ -129,7 +137,6 @@ impl Default for Global { } impl Global { - /// Accessor for the number of inputs currently in the PSET pub fn n_inputs(&self) -> usize { self.tx_data.input_count @@ -149,14 +156,14 @@ impl Map for Global { } = pair; match raw_key.type_value { - PSET_GLOBAL_UNSIGNED_TX=> return Err(Error::ExpiredPsbtv0Field)?, + PSET_GLOBAL_UNSIGNED_TX => return Err(Error::ExpiredPsbtv0Field)?, // Can't set the mandatory non-optional fields via insert_pair - PSET_GLOBAL_VERSION | - PSET_GLOBAL_FALLBACK_LOCKTIME | - PSET_GLOBAL_INPUT_COUNT| - PSET_GLOBAL_OUTPUT_COUNT| - PSET_GLOBAL_TX_MODIFIABLE | - PSET_GLOBAL_TX_VERSION => return Err(Error::DuplicateKey(raw_key).into()), + PSET_GLOBAL_VERSION + | PSET_GLOBAL_FALLBACK_LOCKTIME + | PSET_GLOBAL_INPUT_COUNT + | PSET_GLOBAL_OUTPUT_COUNT + | PSET_GLOBAL_TX_MODIFIABLE + | PSET_GLOBAL_TX_VERSION => return Err(Error::DuplicateKey(raw_key).into()), PSET_GLOBAL_PROPRIETARY => { let prop_key = raw::ProprietaryKey::from_key(raw_key.clone())?; if prop_key.is_pset_key() && prop_key.subtype == PSBT_ELEMENTS_GLOBAL_SCALAR { @@ -170,25 +177,29 @@ impl Map for Global { } else { return Err(Error::InvalidKey(raw_key.into()))?; } - } else if prop_key.is_pset_key() && prop_key.subtype == PSBT_ELEMENTS_GLOBAL_TX_MODIFIABLE { + } else if prop_key.is_pset_key() + && prop_key.subtype == PSBT_ELEMENTS_GLOBAL_TX_MODIFIABLE + { if prop_key.key.is_empty() && raw_value.len() == 1 { self.elements_tx_modifiable_flag = Some(raw_value[0]); } else { return Err(Error::InvalidKey(raw_key.into()))?; } } else { - match self.proprietary.entry(prop_key) { - Entry::Vacant(empty_key) => { - empty_key.insert(raw_value); - } - Entry::Occupied(_) => return Err(Error::DuplicateKey(raw_key).into()), + match self.proprietary.entry(prop_key) { + Entry::Vacant(empty_key) => { + empty_key.insert(raw_value); + } + Entry::Occupied(_) => return Err(Error::DuplicateKey(raw_key).into()), } } } _ => match self.unknown.entry(raw_key) { - Entry::Vacant(empty_key) => {empty_key.insert(raw_value);}, + Entry::Vacant(empty_key) => { + empty_key.insert(raw_value); + } Entry::Occupied(k) => return Err(Error::DuplicateKey(k.key().clone()).into()), - } + }, } Ok(()) @@ -236,9 +247,11 @@ impl Map for Global { value: { let mut ret = Vec::with_capacity(4 + derivation.len() * 4); ret.extend(fingerprint.as_bytes()); - derivation.into_iter().for_each(|n| ret.extend(&u32_to_array_le((*n).into()))); + derivation + .into_iter() + .for_each(|n| ret.extend(&u32_to_array_le((*n).into()))); ret - } + }, }); } @@ -249,7 +262,10 @@ impl Map for Global { // Serialize scalars and elements tx modifiable for scalar in &self.scalars { - let key = raw::ProprietaryKey::from_pset_pair(PSBT_ELEMENTS_GLOBAL_SCALAR, scalar.as_ref().to_vec()); + let key = raw::ProprietaryKey::from_pset_pair( + PSBT_ELEMENTS_GLOBAL_SCALAR, + scalar.as_ref().to_vec(), + ); rv.push(raw::Pair { key: key.to_key(), value: vec![], // This is a bug in elements core c++, parses this value as vec![0] @@ -287,8 +303,9 @@ impl Map for Global { // But since unique ids must be the same, all fields of // tx_data but tx modifiable must be the same // Keep flags from both psets - self.tx_data.tx_modifiable = Some(self.tx_data.tx_modifiable.unwrap_or(0) | - other.tx_data.tx_modifiable.unwrap_or(0)); + self.tx_data.tx_modifiable = Some( + self.tx_data.tx_modifiable.unwrap_or(0) | other.tx_data.tx_modifiable.unwrap_or(0), + ); // Keeping the highest version self.version = cmp::max(self.version, other.version); @@ -298,7 +315,7 @@ impl Map for Global { match self.xpub.entry(xpub) { Entry::Vacant(entry) => { entry.insert((fingerprint1, derivation1)); - }, + } Entry::Occupied(mut entry) => { // Here in case of the conflict we select the version with algorithm: // 1) if everything is equal we do nothing @@ -311,24 +328,21 @@ impl Map for Global { let (fingerprint2, derivation2) = entry.get().clone(); - if derivation1 == derivation2 && fingerprint1 == fingerprint2 - { - continue - } - else if - derivation1.len() < derivation2.len() && - derivation1[..] == derivation2[derivation2.len() - derivation1.len()..] + if derivation1 == derivation2 && fingerprint1 == fingerprint2 { + continue; + } else if derivation1.len() < derivation2.len() + && derivation1[..] == derivation2[derivation2.len() - derivation1.len()..] { - continue - } - else if derivation2[..] == derivation1[derivation1.len() - derivation2.len()..] + continue; + } else if derivation2[..] + == derivation1[derivation1.len() - derivation2.len()..] { entry.insert((fingerprint1, derivation1)); - continue + continue; } - return Err(pset::Error::MergeConflict(format!( - "global xpub {} has inconsistent key sources", xpub - ).to_owned())); + return Err(pset::Error::MergeConflict( + format!("global xpub {} has inconsistent key sources", xpub).to_owned(), + )); } } } @@ -352,10 +366,10 @@ impl_psetmap_consensus_encoding!(Global); impl Decodable for Global { fn consensus_decode(mut d: D) -> Result { - let mut version: Option = None; let mut unknowns: BTreeMap> = Default::default(); - let mut xpub_map: BTreeMap = Default::default(); + let mut xpub_map: BTreeMap = + Default::default(); let mut proprietary = BTreeMap::new(); let mut scalars = Vec::new(); @@ -407,7 +421,9 @@ impl Decodable for Global { ))?; if raw_value.is_empty() || raw_value.len() % 4 != 0 { - return Err(encode::Error::ParseFailed("Incorrect length of global xpub derivation data")) + return Err(encode::Error::ParseFailed( + "Incorrect length of global xpub derivation data", + )); } let child_count = raw_value.len() / 4 - 1; @@ -420,11 +436,18 @@ impl Decodable for Global { } let derivation = DerivationPath::from(path); // Keys, according to BIP-174, must be unique - if xpub_map.insert(xpub, (Fingerprint::from(&fingerprint[..]), derivation)).is_some() { - return Err(encode::Error::ParseFailed("Repeated global xpub key")) + if xpub_map + .insert(xpub, (Fingerprint::from(&fingerprint[..]), derivation)) + .is_some() + { + return Err(encode::Error::ParseFailed( + "Repeated global xpub key", + )); } } else { - return Err(encode::Error::ParseFailed("Xpub global key must contain serialized Xpub data")) + return Err(encode::Error::ParseFailed( + "Xpub global key must contain serialized Xpub data", + )); } } PSET_GLOBAL_VERSION => { @@ -434,7 +457,9 @@ impl Decodable for Global { } PSET_GLOBAL_PROPRIETARY => { let prop_key = raw::ProprietaryKey::from_key(raw_key.clone())?; - if prop_key.is_pset_key() && prop_key.subtype == PSBT_ELEMENTS_GLOBAL_SCALAR { + if prop_key.is_pset_key() + && prop_key.subtype == PSBT_ELEMENTS_GLOBAL_SCALAR + { if raw_value.is_empty() && prop_key.key.len() == 32 { let scalar = Tweak::from_slice(&prop_key.key)?; if !scalars.contains(&scalar) { @@ -445,25 +470,33 @@ impl Decodable for Global { } else { return Err(Error::InvalidKey(raw_key.into()))?; } - } else if prop_key.is_pset_key() && prop_key.subtype == PSBT_ELEMENTS_GLOBAL_TX_MODIFIABLE { + } else if prop_key.is_pset_key() + && prop_key.subtype == PSBT_ELEMENTS_GLOBAL_TX_MODIFIABLE + { if prop_key.key.is_empty() && raw_value.len() == 1 { elements_tx_modifiable_flag = Some(raw_value[0]); } else { return Err(Error::InvalidKey(raw_key.into()))?; } } else { - match proprietary.entry(prop_key) { - Entry::Vacant(empty_key) => { - empty_key.insert(raw_value); - } - Entry::Occupied(_) => return Err(Error::DuplicateKey(raw_key).into()), + match proprietary.entry(prop_key) { + Entry::Vacant(empty_key) => { + empty_key.insert(raw_value); + } + Entry::Occupied(_) => { + return Err(Error::DuplicateKey(raw_key).into()) + } } } } _ => match unknowns.entry(raw_key) { - Entry::Vacant(empty_key) => {empty_key.insert(raw_value);}, - Entry::Occupied(k) => return Err(Error::DuplicateKey(k.key().clone()).into()), - } + Entry::Vacant(empty_key) => { + empty_key.insert(raw_value); + } + Entry::Occupied(k) => { + return Err(Error::DuplicateKey(k.key().clone()).into()) + } + }, } } Err(crate::encode::Error::PsetError(crate::pset::Error::NoMorePairs)) => break, @@ -481,7 +514,13 @@ impl Decodable for Global { let output_count = output_count.ok_or(Error::MissingOutputCount)?.0 as usize; let global = Global { - tx_data: TxData { version: tx_version, fallback_locktime, input_count, output_count, tx_modifiable}, + tx_data: TxData { + version: tx_version, + fallback_locktime, + input_count, + output_count, + tx_modifiable, + }, version: version, xpub: xpub_map, proprietary: proprietary, diff --git a/src/pset/map/input.rs b/src/pset/map/input.rs index 7bcd146d..4a77d2d3 100644 --- a/src/pset/map/input.rs +++ b/src/pset/map/input.rs @@ -13,26 +13,30 @@ // use std::fmt; -use std::{cmp, collections::btree_map::{BTreeMap, Entry}, io, str::FromStr}; - +use std::{ + cmp, + collections::btree_map::{BTreeMap, Entry}, + io, + str::FromStr, +}; + +use crate::taproot::{ControlBlock, LeafVersion, TapBranchHash, TapLeafHash}; use crate::{schnorr, AssetId, ContractHash}; -use crate::taproot::{ControlBlock, LeafVersion, TapLeafHash, TapBranchHash}; -use crate::{Script, AssetIssuance, EcdsaSigHashType, Transaction, Txid, TxOut, TxIn, BlockHash}; -use crate::{SchnorrSigHashType, transaction::SighashTypeParseError}; -use crate::encode::{self, Decodable}; use crate::confidential; -use bitcoin::util::bip32::KeySource; -use bitcoin::{self, PublicKey}; -use hashes::Hash; +use crate::encode::{self, Decodable}; use crate::hashes::{self, hash160, ripemd160, sha256, sha256d}; use crate::pset::map::Map; use crate::pset::raw; use crate::pset::serialize; -use crate::pset::{self, Error, error}; +use crate::pset::{self, error, Error}; +use crate::{transaction::SighashTypeParseError, SchnorrSigHashType}; +use crate::{AssetIssuance, BlockHash, EcdsaSigHashType, Script, Transaction, TxIn, TxOut, Txid}; +use bitcoin::util::bip32::KeySource; +use bitcoin::{self, PublicKey}; +use hashes::Hash; use secp256k1_zkp::{self, RangeProof, Tweak, ZERO_TWEAK}; - use crate::OutPoint; /// Type: Non-Witness UTXO PSET_IN_NON_WITNESS_UTXO = 0x00 @@ -78,11 +82,11 @@ const PSBT_IN_TAP_SCRIPT_SIG: u8 = 0x14; /// Type: Taproot Leaf Script PSBT_IN_TAP_LEAF_SCRIPT = 0x14 const PSBT_IN_TAP_LEAF_SCRIPT: u8 = 0x15; /// Type: Taproot Key BIP 32 Derivation Path PSBT_IN_TAP_BIP32_DERIVATION = 0x16 -const PSBT_IN_TAP_BIP32_DERIVATION : u8 = 0x16; +const PSBT_IN_TAP_BIP32_DERIVATION: u8 = 0x16; /// Type: Taproot Internal Key PSBT_IN_TAP_INTERNAL_KEY = 0x17 -const PSBT_IN_TAP_INTERNAL_KEY : u8 = 0x17; +const PSBT_IN_TAP_INTERNAL_KEY: u8 = 0x17; /// Type: Taproot Merkle Root PSBT_IN_TAP_MERKLE_ROOT = 0x18 -const PSBT_IN_TAP_MERKLE_ROOT : u8 = 0x18; +const PSBT_IN_TAP_MERKLE_ROOT: u8 = 0x18; /// Type: Proprietary Use Type PSET_IN_PROPRIETARY = 0xFC const PSET_IN_PROPRIETARY: u8 = 0xFC; @@ -160,7 +164,10 @@ pub struct Input { pub witness_utxo: Option, /// A map from public keys to their corresponding signature as would be /// pushed to the stack from a scriptSig or witness. - #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_byte_values"))] + #[cfg_attr( + feature = "serde", + serde(with = "crate::serde_utils::btreemap_byte_values") + )] pub partial_sigs: BTreeMap>, /// The sighash type to be used for this input. Signatures for this input /// must use the sighash type. @@ -181,16 +188,28 @@ pub struct Input { pub final_script_witness: Option>>, /// TODO: Proof of reserves commitment /// RIPEMD160 hash to preimage map - #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_byte_values"))] + #[cfg_attr( + feature = "serde", + serde(with = "crate::serde_utils::btreemap_byte_values") + )] pub ripemd160_preimages: BTreeMap>, /// SHA256 hash to preimage map - #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_byte_values"))] + #[cfg_attr( + feature = "serde", + serde(with = "crate::serde_utils::btreemap_byte_values") + )] pub sha256_preimages: BTreeMap>, /// HSAH160 hash to preimage map - #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_byte_values"))] + #[cfg_attr( + feature = "serde", + serde(with = "crate::serde_utils::btreemap_byte_values") + )] pub hash160_preimages: BTreeMap>, /// HAS256 hash to preimage map - #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_byte_values"))] + #[cfg_attr( + feature = "serde", + serde(with = "crate::serde_utils::btreemap_byte_values") + )] pub hash256_preimages: BTreeMap>, /// (PSET) Prevout TXID of the input pub previous_txid: Txid, @@ -214,9 +233,9 @@ pub struct Input { #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_as_seq"))] pub tap_key_origins: BTreeMap, KeySource)>, /// Taproot Internal key - pub tap_internal_key : Option, + pub tap_internal_key: Option, /// Taproot Merkle root - pub tap_merkle_root : Option, + pub tap_merkle_root: Option, // Proprietary key-value pairs for this input. /// The issuance value pub issuance_value_amount: Option, @@ -254,10 +273,16 @@ pub struct Input { /// Proof that blinded inflation keys matches the corresponding commitment pub in_issuance_blind_inflation_keys_proof: Option>, /// Other fields - #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_as_seq_byte_values"))] + #[cfg_attr( + feature = "serde", + serde(with = "crate::serde_utils::btreemap_as_seq_byte_values") + )] pub proprietary: BTreeMap>, /// Unknown key-value pairs for this input. - #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_as_seq_byte_values"))] + #[cfg_attr( + feature = "serde", + serde(with = "crate::serde_utils::btreemap_as_seq_byte_values") + )] pub unknown: BTreeMap>, } @@ -273,7 +298,7 @@ impl Default for Input { /// for converting to/from [`PsbtSighashType`] from/to the desired signature hash type they need. #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct PsbtSighashType { - pub (crate) inner: u32, + pub(crate) inner: u32, } serde_string_impl!(PsbtSighashType, "a PsbtSighashType data"); @@ -298,7 +323,11 @@ impl FromStr for PsbtSighashType { // inputs. We also do not support SIGHASH_RESERVED in verbatim form // ("0xFF" string should be used instead). match SchnorrSigHashType::from_str(s) { - Ok(SchnorrSigHashType::Reserved) => return Err(SighashTypeParseError{ unrecognized: s.to_owned() }), + Ok(SchnorrSigHashType::Reserved) => { + return Err(SighashTypeParseError { + unrecognized: s.to_owned(), + }) + } Ok(ty) => return Ok(ty.into()), Err(_) => {} } @@ -308,18 +337,24 @@ impl FromStr for PsbtSighashType { return Ok(PsbtSighashType { inner }); } - Err(SighashTypeParseError{ unrecognized: s.to_owned() }) + Err(SighashTypeParseError { + unrecognized: s.to_owned(), + }) } } impl From for PsbtSighashType { fn from(ecdsa_hash_ty: EcdsaSigHashType) -> Self { - PsbtSighashType { inner: ecdsa_hash_ty as u32 } + PsbtSighashType { + inner: ecdsa_hash_ty as u32, + } } } impl From for PsbtSighashType { fn from(schnorr_hash_ty: SchnorrSigHashType) -> Self { - PsbtSighashType { inner: schnorr_hash_ty as u32 } + PsbtSighashType { + inner: schnorr_hash_ty as u32, + } } } @@ -348,7 +383,6 @@ impl PsbtSighashType { PsbtSighashType { inner: n } } - /// Converts [`PsbtSighashType`] to a raw `u32` sighash flag. /// /// No guarantees are made as to the standardness or validity of the returned value. @@ -357,8 +391,7 @@ impl PsbtSighashType { } } -impl Input{ - +impl Input { /// Obtains the [`EcdsaSigHashType`] for this input if one is specified. If no sighash type is /// specified, returns [`EcdsaSigHashType::All`]. /// @@ -409,15 +442,16 @@ impl Input{ ret.issuance_blinding_nonce = Some(txin.asset_issuance.asset_blinding_nonce); ret.issuance_asset_entropy = Some(txin.asset_issuance.asset_entropy); match txin.asset_issuance.amount { - confidential::Value::Null => { }, + confidential::Value::Null => {} confidential::Value::Explicit(x) => ret.issuance_value_amount = Some(x), confidential::Value::Confidential(comm) => ret.issuance_value_comm = Some(comm), } match txin.asset_issuance.inflation_keys { - confidential::Value::Null => { }, + confidential::Value::Null => {} confidential::Value::Explicit(x) => ret.issuance_inflation_keys = Some(x), - confidential::Value::Confidential(comm) => - ret.issuance_inflation_keys_comm = Some(comm), + confidential::Value::Confidential(comm) => { + ret.issuance_inflation_keys_comm = Some(comm) + } } // Witness @@ -464,15 +498,17 @@ impl Input{ /// Get the issuance for this tx input pub fn asset_issuance(&self) -> AssetIssuance { AssetIssuance { - asset_blinding_nonce: *self.issuance_blinding_nonce.as_ref() - .unwrap_or(&ZERO_TWEAK), + asset_blinding_nonce: *self.issuance_blinding_nonce.as_ref().unwrap_or(&ZERO_TWEAK), asset_entropy: self.issuance_asset_entropy.unwrap_or_default(), amount: match (self.issuance_value_amount, self.issuance_value_comm) { (None, None) => confidential::Value::Null, (_, Some(comm)) => confidential::Value::Confidential(comm), (Some(x), None) => confidential::Value::Explicit(x), }, - inflation_keys: match (self.issuance_inflation_keys, self.issuance_inflation_keys_comm) { + inflation_keys: match ( + self.issuance_inflation_keys, + self.issuance_inflation_keys_comm, + ) { (None, None) => confidential::Value::Null, (_, Some(comm)) => confidential::Value::Confidential(comm), (Some(x), None) => confidential::Value::Explicit(x), @@ -535,18 +571,38 @@ impl Map for Input { } } PSET_IN_RIPEMD160 => { - pset_insert_hash_pair(&mut self.ripemd160_preimages, raw_key, raw_value, error::PsetHash::Ripemd)?; + pset_insert_hash_pair( + &mut self.ripemd160_preimages, + raw_key, + raw_value, + error::PsetHash::Ripemd, + )?; } PSET_IN_SHA256 => { - pset_insert_hash_pair(&mut self.sha256_preimages, raw_key, raw_value, error::PsetHash::Sha256)?; + pset_insert_hash_pair( + &mut self.sha256_preimages, + raw_key, + raw_value, + error::PsetHash::Sha256, + )?; } PSET_IN_HASH160 => { - pset_insert_hash_pair(&mut self.hash160_preimages, raw_key, raw_value, error::PsetHash::Hash160)?; + pset_insert_hash_pair( + &mut self.hash160_preimages, + raw_key, + raw_value, + error::PsetHash::Hash160, + )?; } PSET_IN_HASH256 => { - pset_insert_hash_pair(&mut self.hash256_preimages, raw_key, raw_value, error::PsetHash::Hash256)?; + pset_insert_hash_pair( + &mut self.hash256_preimages, + raw_key, + raw_value, + error::PsetHash::Hash256, + )?; } - PSET_IN_PREVIOUS_TXID| PSET_IN_OUTPUT_INDEX => { + PSET_IN_PREVIOUS_TXID | PSET_IN_OUTPUT_INDEX => { return Err(Error::DuplicateKey(raw_key))?; } PSET_IN_SEQUENCE => { @@ -574,7 +630,7 @@ impl Map for Input { self.tap_script_sigs <= | } } - PSBT_IN_TAP_LEAF_SCRIPT=> { + PSBT_IN_TAP_LEAF_SCRIPT => { impl_pset_insert_pair! { self.tap_scripts <= |< raw_value: (Script, LeafVersion)> } @@ -651,11 +707,11 @@ impl Map for Input { impl_pset_prop_insert_pair!(self.in_issuance_blind_inflation_keys_proof <= | >) } _ => match self.proprietary.entry(prop_key) { - Entry::Vacant(empty_key) => { - empty_key.insert(raw_value); - } - Entry::Occupied(_) => return Err(Error::DuplicateKey(raw_key).into()), - } + Entry::Vacant(empty_key) => { + empty_key.insert(raw_value); + } + Entry::Occupied(_) => return Err(Error::DuplicateKey(raw_key).into()), + }, } } } @@ -663,9 +719,7 @@ impl Map for Input { Entry::Vacant(empty_key) => { empty_key.insert(raw_value); } - Entry::Occupied(k) => { - return Err(Error::DuplicateKey(k.key().clone()).into()) - } + Entry::Occupied(k) => return Err(Error::DuplicateKey(k.key().clone()).into()), }, } @@ -729,14 +783,20 @@ impl Map for Input { // Mandatory field: Prev Txid rv.push(raw::Pair { - key: raw::Key { type_value: PSET_IN_PREVIOUS_TXID, key: vec![]}, - value: serialize::Serialize::serialize(&self.previous_txid) + key: raw::Key { + type_value: PSET_IN_PREVIOUS_TXID, + key: vec![], + }, + value: serialize::Serialize::serialize(&self.previous_txid), }); // Mandatory field: prev out index rv.push(raw::Pair { - key: raw::Key { type_value: PSET_IN_OUTPUT_INDEX, key: vec![]}, - value: serialize::Serialize::serialize(&self.previous_output_index) + key: raw::Key { + type_value: PSET_IN_OUTPUT_INDEX, + key: vec![], + }, + value: serialize::Serialize::serialize(&self.previous_output_index), }); impl_pset_get_pair! { @@ -893,8 +953,12 @@ impl Map for Input { merge!(tap_merkle_root, self, other); // Should we do this? - self.required_time_locktime = cmp::max(self.required_time_locktime, other.required_time_locktime); - self.required_height_locktime = cmp::max(self.required_height_locktime, other.required_height_locktime); + self.required_time_locktime = + cmp::max(self.required_time_locktime, other.required_time_locktime); + self.required_height_locktime = cmp::max( + self.required_height_locktime, + other.required_height_locktime, + ); // elements merge!(issuance_value_amount, self, other); @@ -925,7 +989,6 @@ impl_psetmap_consensus_encoding!(Input); // not optional and cannot by set by insert_pair impl Decodable for Input { fn consensus_decode(mut d: D) -> Result { - // Sets the default to [0;32] and [0;4] let mut rv = Self::default(); let mut prev_vout: Option = None; @@ -949,7 +1012,10 @@ impl Decodable for Input { prev_vout <= | } } - _ => rv.insert_pair(raw::Pair { key: raw_key, value: raw_value })?, + _ => rv.insert_pair(raw::Pair { + key: raw_key, + value: raw_value, + })?, } } Err(crate::encode::Error::PsetError(crate::pset::Error::NoMorePairs)) => break, diff --git a/src/pset/map/mod.rs b/src/pset/map/mod.rs index 4437c684..8d8f191c 100644 --- a/src/pset/map/mod.rs +++ b/src/pset/map/mod.rs @@ -35,6 +35,6 @@ mod output; pub use self::global::Global; pub use self::global::TxData as GlobalTxData; pub use self::input::Input; +pub use self::input::PsbtSighashType; pub use self::output::Output; pub use self::output::TapTree; -pub use self::input::PsbtSighashType; \ No newline at end of file diff --git a/src/pset/map/output.rs b/src/pset/map/output.rs index a8393425..03be1a4d 100644 --- a/src/pset/map/output.rs +++ b/src/pset/map/output.rs @@ -12,26 +12,26 @@ // If not, see . // -use std::{collections::BTreeMap, io}; use std::collections::btree_map::Entry; +use std::{collections::BTreeMap, io}; use crate::taproot::TapLeafHash; use crate::taproot::{NodeInfo, TaprootBuilder}; -use crate::{Script, encode, TxOutWitness}; -use bitcoin::util::bip32::KeySource; -use bitcoin::{self, PublicKey}; -use crate::{pset, confidential}; use crate::encode::Decodable; use crate::pset::map::Map; use crate::pset::raw; use crate::pset::Error; +use crate::{confidential, pset}; +use crate::{encode, Script, TxOutWitness}; +use bitcoin::util::bip32::KeySource; +use bitcoin::{self, PublicKey}; use secp256k1_zkp::{self, Generator, RangeProof, SurjectionProof}; use crate::issuance; -use crate::TxOut; use crate::AssetId; +use crate::TxOut; /// Type: Redeem Script PSET_OUT_REDEEM_SCRIPT = 0x00 const PSET_OUT_REDEEM_SCRIPT: u8 = 0x00; @@ -131,10 +131,16 @@ pub struct Output { pub blind_asset_proof: Option>, /// Pset /// Other fields - #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_as_seq_byte_values"))] + #[cfg_attr( + feature = "serde", + serde(with = "crate::serde_utils::btreemap_as_seq_byte_values") + )] pub proprietary: BTreeMap>, /// Unknown key-value pairs for this output. - #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_as_seq_byte_values"))] + #[cfg_attr( + feature = "serde", + serde(with = "crate::serde_utils::btreemap_as_seq_byte_values") + )] pub unknown: BTreeMap>, } @@ -149,7 +155,6 @@ impl PartialEq for TapTree { } } - impl Eq for TapTree {} impl TapTree { @@ -159,7 +164,9 @@ impl TapTree { // have only 1 element in branch and that is not None. // We make sure that we only allow is_complete builders via the from_inner // constructor - self.0.branch()[0].as_ref().expect("from_inner only parses is_complete builders") + self.0.branch()[0] + .as_ref() + .expect("from_inner only parses is_complete builders") } /// Convert a [`TaprootBuilder`] into a tree if it is complete binary tree. @@ -179,8 +186,7 @@ impl TapTree { } } -impl Output{ - +impl Output { /// Create a new explicit pset output pub fn new_explicit( script: Script, @@ -206,12 +212,12 @@ impl Output{ pub fn from_txout(txout: TxOut) -> Self { let mut rv = Self::default(); match txout.value { - confidential::Value::Null => { }, + confidential::Value::Null => {} confidential::Value::Explicit(x) => rv.amount = Some(x), confidential::Value::Confidential(comm) => rv.amount_comm = Some(comm), } match txout.asset { - confidential::Asset::Null => { }, + confidential::Asset::Null => {} confidential::Asset::Explicit(x) => rv.asset = Some(x), confidential::Asset::Confidential(comm) => rv.asset_comm = Some(comm), } @@ -246,10 +252,13 @@ impl Output{ (None, None) => confidential::Value::Null, }, nonce: if self.is_partially_blinded() { - self.ecdh_pubkey.map(|pk| confidential::Nonce::from(pk.inner)) + self.ecdh_pubkey + .map(|pk| confidential::Nonce::from(pk.inner)) } else { - self.blinding_key.map(|pk| confidential::Nonce::from(pk.inner)) - }.unwrap_or_default(), + self.blinding_key + .map(|pk| confidential::Nonce::from(pk.inner)) + } + .unwrap_or_default(), script_pubkey: self.script_pubkey.clone(), witness: TxOutWitness { surjection_proof: self.asset_surjection_proof.clone(), @@ -266,23 +275,22 @@ impl Output{ /// IsPartiallyBlinded from elements core pub fn is_partially_blinded(&self) -> bool { - self.is_marked_for_blinding() && ( - self.amount_comm.is_some() || - self.asset_comm.is_some() || - self.value_rangeproof.is_some() || - self.asset_surjection_proof.is_some() || - self.ecdh_pubkey.is_some() - ) + self.is_marked_for_blinding() + && (self.amount_comm.is_some() + || self.asset_comm.is_some() + || self.value_rangeproof.is_some() + || self.asset_surjection_proof.is_some() + || self.ecdh_pubkey.is_some()) } /// IsFullyBlinded from elements core pub fn is_fully_blinded(&self) -> bool { - self.is_marked_for_blinding() && - self.amount_comm.is_some() && - self.asset_comm.is_some() && - self.value_rangeproof.is_some() && - self.asset_surjection_proof.is_some() && - self.ecdh_pubkey.is_some() + self.is_marked_for_blinding() + && self.amount_comm.is_some() + && self.asset_comm.is_some() + && self.value_rangeproof.is_some() + && self.asset_surjection_proof.is_some() + && self.ecdh_pubkey.is_some() } } @@ -366,25 +374,33 @@ impl Map for Output { PSBT_ELEMENTS_OUT_BLIND_ASSET_PROOF => { impl_pset_prop_insert_pair!(self.blind_asset_proof <= | >) } - _ => { - match self.proprietary.entry(prop_key) { - Entry::Vacant(empty_key) => {empty_key.insert(raw_value);}, - Entry::Occupied(_) => return Err(Error::DuplicateKey(raw_key.clone()).into()), + _ => match self.proprietary.entry(prop_key) { + Entry::Vacant(empty_key) => { + empty_key.insert(raw_value); } - } + Entry::Occupied(_) => { + return Err(Error::DuplicateKey(raw_key.clone()).into()) + } + }, } } else { match self.proprietary.entry(prop_key) { - Entry::Vacant(empty_key) => {empty_key.insert(raw_value);}, - Entry::Occupied(_) => return Err(Error::DuplicateKey(raw_key.clone()).into()), + Entry::Vacant(empty_key) => { + empty_key.insert(raw_value); + } + Entry::Occupied(_) => { + return Err(Error::DuplicateKey(raw_key.clone()).into()) + } } } } _ => match self.unknown.entry(raw_key) { - Entry::Vacant(empty_key) => {empty_key.insert(raw_value);}, - Entry::Occupied(k) => return Err(Error::DuplicateKey(k.key().clone()).into()), - } + Entry::Vacant(empty_key) => { + empty_key.insert(raw_value); + } + Entry::Occupied(k) => return Err(Error::DuplicateKey(k.key().clone()).into()), + }, } Ok(()) @@ -436,8 +452,11 @@ impl Map for Output { // Mandatory field: Script rv.push(raw::Pair { - key: raw::Key { type_value: PSET_OUT_SCRIPT, key: vec![]}, - value: pset::serialize::Serialize::serialize(&self.script_pubkey) + key: raw::Key { + type_value: PSET_OUT_SCRIPT, + key: vec![], + }, + value: pset::serialize::Serialize::serialize(&self.script_pubkey), }); // Prop Output fields @@ -516,7 +535,6 @@ impl_psetmap_consensus_encoding!(Output); // not optional and cannot by set by insert_pair impl Decodable for Output { fn consensus_decode(mut d: D) -> Result { - // Sets the default to [0;32] and [0;4] let mut rv = Self::default(); // let mut out_value: Option = None; @@ -536,7 +554,10 @@ impl Decodable for Output { out_spk <= | } } - _ => rv.insert_pair(raw::Pair { key: raw_key, value: raw_value })?, + _ => rv.insert_pair(raw::Pair { + key: raw_key, + value: raw_value, + })?, } } Err(crate::encode::Error::PsetError(crate::pset::Error::NoMorePairs)) => break, @@ -549,16 +570,16 @@ impl Decodable for Output { rv.script_pubkey = spk; if let (None, None) = (rv.amount, rv.amount_comm) { - return Err(encode::Error::PsetError(Error::MissingOutputValue)) + return Err(encode::Error::PsetError(Error::MissingOutputValue)); } if let (None, None) = (rv.asset, rv.asset_comm) { - return Err(encode::Error::PsetError(Error::MissingOutputAsset)) + return Err(encode::Error::PsetError(Error::MissingOutputAsset)); } if let (Some(_), None) = (rv.blinding_key, rv.blinder_index) { - return Err(encode::Error::PsetError(Error::MissingBlinderIndex)) + return Err(encode::Error::PsetError(Error::MissingBlinderIndex)); } if rv.is_marked_for_blinding() && rv.is_partially_blinded() && !rv.is_fully_blinded() { - return Err(encode::Error::PsetError(Error::MissingBlindingInfo)) + return Err(encode::Error::PsetError(Error::MissingBlindingInfo)); } Ok(rv) } diff --git a/src/pset/mod.rs b/src/pset/mod.rs index cac099c7..b63c015f 100644 --- a/src/pset/mod.rs +++ b/src/pset/mod.rs @@ -30,18 +30,22 @@ mod map; pub mod raw; pub mod serialize; -use crate::{Transaction, Txid, TxIn, OutPoint, TxInWitness, TxOut, TxOutWitness, SurjectionInput}; -use crate::encode::{self, Encodable, Decodable}; +use crate::blind::{BlindAssetProofs, BlindValueProofs}; use crate::confidential; -use secp256k1_zkp::rand::{CryptoRng, RngCore}; -use secp256k1_zkp::{self, RangeProof, SurjectionProof, SecretKey}; -use crate::{TxOutSecrets, blind::RangeProofMessage, confidential::{AssetBlindingFactor, ValueBlindingFactor}}; +use crate::encode::{self, Decodable, Encodable}; +use crate::{ + blind::RangeProofMessage, + confidential::{AssetBlindingFactor, ValueBlindingFactor}, + TxOutSecrets, +}; +use crate::{OutPoint, SurjectionInput, Transaction, TxIn, TxInWitness, TxOut, TxOutWitness, Txid}; use bitcoin; -use crate::blind::{BlindAssetProofs, BlindValueProofs}; +use secp256k1_zkp::rand::{CryptoRng, RngCore}; +use secp256k1_zkp::{self, RangeProof, SecretKey, SurjectionProof}; pub use self::error::{Error, PsetBlindError}; -pub use self::map::{Global, GlobalTxData, Input, Output, TapTree, PsbtSighashType}; use self::map::Map; +pub use self::map::{Global, GlobalTxData, Input, Output, PsbtSighashType, TapTree}; /// A Partially Signed Transaction. #[derive(Debug, Clone, PartialEq)] @@ -64,7 +68,6 @@ impl Default for PartiallySignedTransaction { } impl PartiallySignedTransaction { - /// Create a new PSET from a raw transaction pub fn from_tx(tx: Transaction) -> Self { let mut global = Global::default(); @@ -74,9 +77,11 @@ impl PartiallySignedTransaction { global.tx_data.version = tx.version; let inputs = tx.input.into_iter().map(Input::from_txin).collect(); - let outputs = tx.output.into_iter().map(|o| { - Output::from_txout(o) - }).collect(); + let outputs = tx + .output + .into_iter() + .map(|o| Output::from_txout(o)) + .collect(); Self { global: global, inputs: inputs, @@ -109,10 +114,10 @@ impl PartiallySignedTransaction { self.global.tx_data.input_count += 1; self.inputs.insert(pos, inp); - for out in self.outputs_mut(){ + for out in self.outputs_mut() { match out.blinder_index { Some(i) if i >= pos as u32 => { - out.blinder_index = Some(i+1); + out.blinder_index = Some(i + 1); } _ => {} } @@ -134,7 +139,7 @@ impl PartiallySignedTransaction { pub fn remove_input(&mut self, index: usize) -> Option { if self.inputs.get(index).is_some() { self.global.tx_data.input_count -= 1; - return Some(self.inputs.remove(index)) + return Some(self.inputs.remove(index)); } None } @@ -169,7 +174,7 @@ impl PartiallySignedTransaction { pub fn remove_output(&mut self, index: usize) -> Option { if self.inputs.get(index).is_some() { self.global.tx_data.output_count -= 1; - return Some(self.outputs.remove(index)) + return Some(self.outputs.remove(index)); } None } @@ -187,7 +192,9 @@ impl PartiallySignedTransaction { /// Accessor for the locktime to be used in the final transaction pub fn locktime(&self) -> Result { match self.global.tx_data { - GlobalTxData{ fallback_locktime, .. } => { + GlobalTxData { + fallback_locktime, .. + } => { #[derive(PartialEq, Eq, PartialOrd, Ord)] enum Locktime { /// No inputs have specified this type of locktime @@ -205,28 +212,30 @@ impl PartiallySignedTransaction { (Some(rt), Some(rh)) => { time_locktime = cmp::max(time_locktime, Locktime::Minimum(rt)); height_locktime = cmp::max(height_locktime, Locktime::Minimum(rh)); - }, + } (Some(rt), None) => { time_locktime = cmp::max(time_locktime, Locktime::Minimum(rt)); height_locktime = Locktime::Disallowed; - }, + } (None, Some(rh)) => { time_locktime = Locktime::Disallowed; height_locktime = cmp::max(height_locktime, Locktime::Minimum(rh)); - }, + } (None, None) => {} } } match (time_locktime, height_locktime) { - (Locktime::Unconstrained, Locktime::Unconstrained) => Ok(fallback_locktime.unwrap_or(0)), + (Locktime::Unconstrained, Locktime::Unconstrained) => { + Ok(fallback_locktime.unwrap_or(0)) + } (Locktime::Minimum(x), _) => Ok(x), (_, Locktime::Minimum(x)) => Ok(x), (Locktime::Disallowed, Locktime::Disallowed) => Err(Error::LocktimeConflict), (Locktime::Unconstrained, Locktime::Disallowed) => unreachable!(), (Locktime::Disallowed, Locktime::Unconstrained) => unreachable!(), } - }, + } } } @@ -256,7 +265,6 @@ impl PartiallySignedTransaction { } } - /// Extract the Transaction from a PartiallySignedTransaction by filling in /// the available signature information in place. pub fn extract_tx(&self) -> Result { @@ -276,10 +284,16 @@ impl PartiallySignedTransaction { witness: TxInWitness { amount_rangeproof: psetin.issuance_value_rangeproof.clone(), inflation_keys_rangeproof: psetin.issuance_keys_rangeproof.clone(), - script_witness: psetin.final_script_witness.as_ref() - .map(|x| x.to_owned()).unwrap_or_default(), - pegin_witness: psetin.pegin_witness.as_ref() - .map(|x| x.to_owned()).unwrap_or_default(), + script_witness: psetin + .final_script_witness + .as_ref() + .map(|x| x.to_owned()) + .unwrap_or_default(), + pegin_witness: psetin + .pegin_witness + .as_ref() + .map(|x| x.to_owned()) + .unwrap_or_default(), }, }; inputs.push(txin); @@ -297,7 +311,8 @@ impl PartiallySignedTransaction { (None, Some(x)) => confidential::Value::Explicit(x), (None, None) => return Err(Error::MissingOutputAsset), }, - nonce: out.ecdh_pubkey + nonce: out + .ecdh_pubkey .map(|x| confidential::Nonce::from(x.inner)) .unwrap_or_default(), script_pubkey: out.script_pubkey.clone(), @@ -349,7 +364,6 @@ impl PartiallySignedTransaction { ), PsetBlindError, > { - let mut blind_out_indices = Vec::new(); for (i, out) in self.outputs.iter().enumerate() { if out.blinding_key.is_none() { @@ -392,18 +406,21 @@ impl PartiallySignedTransaction { inp_txout_sec: &HashMap, ) -> Result, PsetBlindError> { let mut ret = vec![]; - for (i ,inp) in self.inputs().iter().enumerate() { - let utxo = inp.witness_utxo.as_ref().ok_or(PsetBlindError::MissingWitnessUtxo(i))?; + for (i, inp) in self.inputs().iter().enumerate() { + let utxo = inp + .witness_utxo + .as_ref() + .ok_or(PsetBlindError::MissingWitnessUtxo(i))?; let surject_target = match inp_txout_sec.get(&i) { Some(sec) => SurjectionInput::from_txout_secrets(*sec), None => SurjectionInput::Unknown(utxo.asset), }; ret.push(surject_target); - if inp.has_issuance(){ + if inp.has_issuance() { let (asset_id, token_id) = inp.issuance_ids(); if inp.issuance_value_amount.is_some() || inp.issuance_value_comm.is_some() { - let secrets = TxOutSecrets{ + let secrets = TxOutSecrets { asset: asset_id, asset_bf: AssetBlindingFactor::zero(), value: 0, // This value really does not matter in surjection proofs @@ -411,8 +428,10 @@ impl PartiallySignedTransaction { }; ret.push(SurjectionInput::from_txout_secrets(secrets)) } - if inp.issuance_inflation_keys.is_some() || inp.issuance_inflation_keys_comm.is_some() { - let secrets = TxOutSecrets{ + if inp.issuance_inflation_keys.is_some() + || inp.issuance_inflation_keys_comm.is_some() + { + let secrets = TxOutSecrets { asset: token_id, asset_bf: AssetBlindingFactor::zero(), value: 0, // This value really does not matter in surjection proofs @@ -468,7 +487,9 @@ impl PartiallySignedTransaction { &surject_inputs, ) .map_err(|e| PsetBlindError::ConfidentialTxOutError(i, e))?; - let value = self.outputs[i].amount.ok_or(PsetBlindError::MustHaveExplicitTxOut(i))?; + let value = self.outputs[i] + .amount + .ok_or(PsetBlindError::MustHaveExplicitTxOut(i))?; out_secrets.push((value, abf, vbf)); // mutate the pset @@ -477,18 +498,29 @@ impl PartiallySignedTransaction { self.outputs[i].asset_surjection_proof = txout.witness.surjection_proof; self.outputs[i].amount_comm = txout.value.commitment(); self.outputs[i].asset_comm = txout.asset.commitment(); - self.outputs[i].ecdh_pubkey = txout.nonce.commitment().map(|pk| bitcoin::PublicKey{ - inner: pk, - compressed: true - }); - let asset_id = self.outputs[i].asset.ok_or(PsetBlindError::MustHaveExplicitTxOut(i))?; - self.outputs[i].blind_asset_proof = Some(Box::new(SurjectionProof::blind_asset_proof(rng, secp, asset_id, abf) - .map_err(|e| PsetBlindError::BlindingProofsCreationError(i, e))?)); - - let asset_gen = self.outputs[i].asset_comm.expect("Blinding proof creation error"); - let value_comm = self.outputs[i].amount_comm.expect("Blinding proof successful"); - self.outputs[i].blind_value_proof = Some(Box::new(RangeProof::blind_value_proof(rng, secp, value, value_comm, asset_gen, vbf) - .map_err(|e| PsetBlindError::BlindingProofsCreationError(i, e))?)); + self.outputs[i].ecdh_pubkey = + txout.nonce.commitment().map(|pk| bitcoin::PublicKey { + inner: pk, + compressed: true, + }); + let asset_id = self.outputs[i] + .asset + .ok_or(PsetBlindError::MustHaveExplicitTxOut(i))?; + self.outputs[i].blind_asset_proof = Some(Box::new( + SurjectionProof::blind_asset_proof(rng, secp, asset_id, abf) + .map_err(|e| PsetBlindError::BlindingProofsCreationError(i, e))?, + )); + + let asset_gen = self.outputs[i] + .asset_comm + .expect("Blinding proof creation error"); + let value_comm = self.outputs[i] + .amount_comm + .expect("Blinding proof successful"); + self.outputs[i].blind_value_proof = Some(Box::new( + RangeProof::blind_value_proof(rng, secp, value, value_comm, asset_gen, vbf) + .map_err(|e| PsetBlindError::BlindingProofsCreationError(i, e))?, + )); } // return blinding factors used ret.push((abf, vbf)); @@ -557,31 +589,34 @@ impl PartiallySignedTransaction { // blind the last txout let surject_inputs = self.surjection_inputs(inp_txout_sec)?; - let asset_id = self.outputs[last_out_index].asset.ok_or(PsetBlindError::MustHaveExplicitTxOut(last_out_index))?; + let asset_id = self.outputs[last_out_index] + .asset + .ok_or(PsetBlindError::MustHaveExplicitTxOut(last_out_index))?; let out_abf = AssetBlindingFactor::new(rng); let exp_asset = confidential::Asset::Explicit(asset_id); let blind_res = exp_asset.blind(rng, secp, out_abf, &surject_inputs); - let (out_asset_commitment, surjection_proof) = blind_res - .map_err(|e| PsetBlindError::ConfidentialTxOutError(last_out_index, e))?; + let (out_asset_commitment, surjection_proof) = + blind_res.map_err(|e| PsetBlindError::ConfidentialTxOutError(last_out_index, e))?; - let value = self.outputs[last_out_index].amount.ok_or(PsetBlindError::MustHaveExplicitTxOut(last_out_index))?; + let value = self.outputs[last_out_index] + .amount + .ok_or(PsetBlindError::MustHaveExplicitTxOut(last_out_index))?; let exp_value = confidential::Value::Explicit(value); // Get all the explicit outputs let mut exp_out_secrets = vec![]; for (i, out) in self.outputs.iter().enumerate() { if out.blinding_key.is_none() { let amt = out.amount.ok_or(PsetBlindError::MustHaveExplicitTxOut(i))?; - exp_out_secrets.push((amt, AssetBlindingFactor::zero(), ValueBlindingFactor::zero())); + exp_out_secrets.push(( + amt, + AssetBlindingFactor::zero(), + ValueBlindingFactor::zero(), + )); } } - let mut final_vbf = ValueBlindingFactor::last( - secp, - value, - out_abf, - &inp_secrets, - &exp_out_secrets, - ); + let mut final_vbf = + ValueBlindingFactor::last(secp, value, out_abf, &inp_secrets, &exp_out_secrets); // Add all the scalars for value_diff in self.global.scalars.iter() { @@ -593,11 +628,20 @@ impl PartiallySignedTransaction { .ok_or(PsetBlindError::MustHaveExplicitTxOut(last_out_index))?; let ephemeral_sk = SecretKey::new(rng); let spk = &self.outputs[last_out_index].script_pubkey; - let msg = RangeProofMessage { asset: asset_id, bf: out_abf }; - let blind_res = - exp_value.blind(secp, final_vbf, receiver_blinding_pk.inner, ephemeral_sk, spk, &msg); - let (value_commitment, nonce, rangeproof) = blind_res - .map_err(|e| PsetBlindError::ConfidentialTxOutError(last_out_index, e))?; + let msg = RangeProofMessage { + asset: asset_id, + bf: out_abf, + }; + let blind_res = exp_value.blind( + secp, + final_vbf, + receiver_blinding_pk.inner, + ephemeral_sk, + spk, + &msg, + ); + let (value_commitment, nonce, rangeproof) = + blind_res.map_err(|e| PsetBlindError::ConfidentialTxOutError(last_out_index, e))?; // mutate the pset { @@ -605,18 +649,29 @@ impl PartiallySignedTransaction { self.outputs[last_out_index].asset_surjection_proof = Some(Box::new(surjection_proof)); self.outputs[last_out_index].amount_comm = value_commitment.commitment(); self.outputs[last_out_index].asset_comm = out_asset_commitment.commitment(); - self.outputs[last_out_index].ecdh_pubkey = nonce.commitment().map(|pk| bitcoin::PublicKey{ - inner: pk, - compressed: true - }); - let asset_id = self.outputs[last_out_index].asset.ok_or(PsetBlindError::MustHaveExplicitTxOut(last_out_index))?; - self.outputs[last_out_index].blind_asset_proof = Some(Box::new(SurjectionProof::blind_asset_proof(rng, secp, asset_id, out_abf) - .map_err(|e| PsetBlindError::BlindingProofsCreationError(last_out_index, e))?)); - - let asset_gen = self.outputs[last_out_index].asset_comm.expect("Blinding proof creation error"); - let value_comm = self.outputs[last_out_index].amount_comm.expect("Blinding proof successful"); - self.outputs[last_out_index].blind_value_proof = Some(Box::new(RangeProof::blind_value_proof(rng, secp, value, value_comm, asset_gen, final_vbf) - .map_err(|e| PsetBlindError::BlindingProofsCreationError(last_out_index, e))?)); + self.outputs[last_out_index].ecdh_pubkey = + nonce.commitment().map(|pk| bitcoin::PublicKey { + inner: pk, + compressed: true, + }); + let asset_id = self.outputs[last_out_index] + .asset + .ok_or(PsetBlindError::MustHaveExplicitTxOut(last_out_index))?; + self.outputs[last_out_index].blind_asset_proof = Some(Box::new( + SurjectionProof::blind_asset_proof(rng, secp, asset_id, out_abf) + .map_err(|e| PsetBlindError::BlindingProofsCreationError(last_out_index, e))?, + )); + + let asset_gen = self.outputs[last_out_index] + .asset_comm + .expect("Blinding proof creation error"); + let value_comm = self.outputs[last_out_index] + .amount_comm + .expect("Blinding proof successful"); + self.outputs[last_out_index].blind_value_proof = Some(Box::new( + RangeProof::blind_value_proof(rng, secp, value, value_comm, asset_gen, final_vbf) + .map_err(|e| PsetBlindError::BlindingProofsCreationError(last_out_index, e))?, + )); self.global.scalars.clear() } @@ -709,24 +764,26 @@ mod tests { use bitcoin::hashes::hex::{FromHex, ToHex}; fn tx_pset_rtt(tx_hex: &str) { - let tx: Transaction = encode::deserialize(&Vec::::from_hex(tx_hex).unwrap()[..]).unwrap(); + let tx: Transaction = + encode::deserialize(&Vec::::from_hex(tx_hex).unwrap()[..]).unwrap(); let pset = PartiallySignedTransaction::from_tx(tx); let rtt_tx_hex = encode::serialize_hex(&pset.extract_tx().unwrap()); assert_eq!(tx_hex, rtt_tx_hex); let pset_rtt_hex = encode::serialize_hex(&pset); - let pset2 : PartiallySignedTransaction = encode::deserialize(&Vec::::from_hex(&pset_rtt_hex).unwrap()[..]).unwrap(); + let pset2: PartiallySignedTransaction = + encode::deserialize(&Vec::::from_hex(&pset_rtt_hex).unwrap()[..]).unwrap(); assert_eq!(pset, pset2); } fn pset_rtt(pset_hex: &str) { - let pset: PartiallySignedTransaction = encode::deserialize(&Vec::::from_hex(pset_hex).unwrap()[..]).unwrap(); + let pset: PartiallySignedTransaction = + encode::deserialize(&Vec::::from_hex(pset_hex).unwrap()[..]).unwrap(); assert_eq!(encode::serialize_hex(&pset), pset_hex); } #[test] - fn test_pset(){ - + fn test_pset() { tx_pset_rtt("010000000001715df5ccebaf02ff18d6fae7263fa69fed5de59c900f4749556eba41bc7bf2af0000000000000000000201230f4f5d4b7c6fa845806ee4f67713459e1b69e8e60fcee2e4940c7a0d5de1b2010000000124101100001f5175517551755175517551755175517551755175517551755175517551755101230f4f5d4b7c6fa845806ee4f67713459e1b69e8e60fcee2e4940c7a0d5de1b2010000000005f5e100000000000000"); // Test a issuance test with only sighash all @@ -745,10 +802,10 @@ mod tests { #[test] fn single_blinded_output_pset() { - use std::str::FromStr; + use crate::AssetId; use rand::{self, SeedableRng}; use serde_json; - use crate::AssetId; + use std::str::FromStr; // Initially secp context and rng global state let secp = secp256k1_zkp::Secp256k1::new(); @@ -756,7 +813,8 @@ mod tests { let mut rng = rand::rngs::StdRng::seed_from_u64(0); let pset_hex = "70736574ff01020402000000010401010105010201fb04020000000001017a0bb9325c276764451bbc2eb82a4c8c4bb6f4007ba803e5a5ba72d0cd7c09848e1a091622d935953bf06e0b7393239c68c6f810a00fe19d11c6ae343cffd3037077da02535fe4ad0fcd675cd0f62bf73b60a554dc1569b80f1f76a2bbfc9f00d439bf4b160014d2cbec8783bd01c9f178348b08500a830a89a7f9010e20805131ba6b37165c026eed9325ac56059ba872fd569e3ed462734098688b4770010f0400000000000103088c83b50d0000000007fc04707365740220230f4f5d4b7c6fa845806ee4f67713459e1b69e8e60fcee2e4940c7a0d5de1b20104220020e5793ad956ee91ebf3543b37d110701118ed4078ffa0d477eacb8885e486ad8507fc047073657406210212bf0ea45b733dfde8ecb5e896306c4165c666c99fc5d1ab887f71393a975cea07fc047073657408040000000000010308f40100000000000007fc04707365740220230f4f5d4b7c6fa845806ee4f67713459e1b69e8e60fcee2e4940c7a0d5de1b201040000"; - let mut pset : PartiallySignedTransaction = encode::deserialize(&Vec::::from_hex(&pset_hex).unwrap()[..]).unwrap(); + let mut pset: PartiallySignedTransaction = + encode::deserialize(&Vec::::from_hex(&pset_hex).unwrap()[..]).unwrap(); let btc_txout_secrets_str = r#" { @@ -784,8 +842,7 @@ mod tests { let tx = pset.extract_tx().unwrap(); let btc_txout = pset.inputs[0].witness_utxo.clone().unwrap(); - tx.verify_tx_amt_proofs(&secp, &[btc_txout]) - .unwrap(); + tx.verify_tx_amt_proofs(&secp, &[btc_txout]).unwrap(); } #[test] @@ -793,46 +850,63 @@ mod tests { // Invalid psets // Check Global mandatory field let pset_str = "70736574ff010401000105010001fb040200000000"; - let pset = encode::deserialize::(&Vec::::from_hex(pset_str).unwrap()[..]); + let pset = encode::deserialize::( + &Vec::::from_hex(pset_str).unwrap()[..], + ); pset.expect_err("Missing tx version"); // Check input mandatory field let pset_str = "70736574ff010204020000000104010001fb040200000000"; - let pset = encode::deserialize::(&Vec::::from_hex(pset_str).unwrap()[..]); + let pset = encode::deserialize::( + &Vec::::from_hex(pset_str).unwrap()[..], + ); pset.expect_err("Missing inp count"); let pset_str = "70736574ff010204020000000105010001fb040200000000"; - let pset = encode::deserialize::(&Vec::::from_hex(pset_str).unwrap()[..]); + let pset = encode::deserialize::( + &Vec::::from_hex(pset_str).unwrap()[..], + ); pset.expect_err("Missing out count"); let pset_str = "70736574ff01020402000000010401000105010000"; - let pset = encode::deserialize::(&Vec::::from_hex(pset_str).unwrap()[..]); + let pset = encode::deserialize::( + &Vec::::from_hex(pset_str).unwrap()[..], + ); pset.expect_err("Missing pset version"); // Check inp/out count mismatch let pset_str = "70736574ff01020402000000010401000105010001fb04020000000001017a0ad92644e9bf6cb8d0856a8ca713c8a212d3a62142e85454b7865217890e52ec3108a469a9811ec1c1df7a98dbc3a7f71860293e98c6fad8a7ef6828344e9172547302217d344513f0a5ed1a60ebeba01460c505ad63d95b3542fb303aca8f9382777d160014bd5c31aaea2ddc585f317ee589bc6800bc95e7e6010e208965573f41392a88d8bb106cf13a7bdc69f1ab914cd5e8de11235467b514e5a9010f040100000000"; - let pset = encode::deserialize::(&Vec::::from_hex(pset_str).unwrap()[..]); + let pset = encode::deserialize::( + &Vec::::from_hex(pset_str).unwrap()[..], + ); pset.expect_err("Input count mismatch"); // input mandatory field let pset_str = "70736574ff01020402000000010401010105010001fb04020000000001017a0ad92644e9bf6cb8d0856a8ca713c8a212d3a62142e85454b7865217890e52ec3108a469a9811ec1c1df7a98dbc3a7f71860293e98c6fad8a7ef6828344e9172547302217d344513f0a5ed1a60ebeba01460c505ad63d95b3542fb303aca8f9382777d160014bd5c31aaea2ddc585f317ee589bc6800bc95e7e601010f040100000000"; - let pset = encode::deserialize::(&Vec::::from_hex(pset_str).unwrap()[..]); + let pset = encode::deserialize::( + &Vec::::from_hex(pset_str).unwrap()[..], + ); pset.expect_err("Input mandatory field prevtxid"); // output mandatory amount field let pset_str = "70736574ff01020402000000010401000105010101fb04020000000007fc04707365740220010101010101010101010101010101010101010101010101010101010101010101040000"; - let pset = encode::deserialize::(&Vec::::from_hex(pset_str).unwrap()[..]); + let pset = encode::deserialize::( + &Vec::::from_hex(pset_str).unwrap()[..], + ); pset.expect_err("Output non-mandatory field"); let pset_str = "70736574ff01020402000000010401000105010101fb040200000000010308170000000000000007fc0470736574022009090909090909090909090909090909090909090909090909090909090909090100"; - let pset = encode::deserialize::(&Vec::::from_hex(pset_str).unwrap()[..]); + let pset = encode::deserialize::( + &Vec::::from_hex(pset_str).unwrap()[..], + ); pset.expect_err("Output mandatory field script pubkey"); - // Valid Psets // Check both possible conf/explicit values are allowed for pset let pset_str = "70736574ff01020402000000010401000105010101fb040200000000010308170000000000000007fc0470736574012109090909090909090909090909090909090909090909090909090909090909090907fc04707365740220090909090909090909090909090909090909090909090909090909090909090901040000"; - let pset = encode::deserialize::(&Vec::::from_hex(pset_str).unwrap()[..]); + let pset = encode::deserialize::( + &Vec::::from_hex(pset_str).unwrap()[..], + ); pset.expect("Both conf/explicit value are allowed be present in map"); // Commented code for quick test vector generation @@ -848,7 +922,6 @@ mod tests { // pset.add_output(Output::from_txout(txout)); // println!("{}", encode::serialize_hex(&pset)); - // // Commit an asset // let mut pset = PartiallySignedTransaction::new_v2(); // // use AssetId; diff --git a/src/pset/raw.rs b/src/pset/raw.rs index 38a89310..a442d72d 100644 --- a/src/pset/raw.rs +++ b/src/pset/raw.rs @@ -19,9 +19,11 @@ use std::{fmt, io}; -use crate::encode::{self, Decodable, Encodable, ReadExt, WriteExt, serialize, deserialize, MAX_VEC_SIZE}; -use crate::hashes::hex; use super::Error; +use crate::encode::{ + self, deserialize, serialize, Decodable, Encodable, ReadExt, WriteExt, MAX_VEC_SIZE, +}; +use crate::hashes::hex; use crate::VarInt; /// A PSET key in its raw byte form. #[derive(Debug, PartialEq, Hash, Eq, Clone, Ord, PartialOrd)] @@ -34,7 +36,7 @@ pub struct Key { pub key: Vec, } -impl Key{ +impl Key { /// Helper to create a raw key from pset proprietary key components pub fn from_pset_key(subtype: ProprietaryType, key: Vec) -> Self { let pset_prop_key = ProprietaryKey { @@ -62,9 +64,12 @@ pub type ProprietaryType = u8; /// Proprietary keys (i.e. keys starting with 0xFC byte) with their internal /// structure according to BIP 174. -#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(crate = "actual_serde"))] -pub struct ProprietaryKey where Subtype: Copy + From + Into { +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +pub struct ProprietaryKey +where + Subtype: Copy + From + Into, +{ /// Proprietary type prefix used for grouping together keys under some /// application and avoid namespace collision #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::hex_bytes"))] @@ -116,7 +121,7 @@ impl Decodable for Key { return Err(encode::Error::OversizedVectorAllocation { requested: key_byte_size as usize, max: MAX_VEC_SIZE, - }) + }); } let type_value: u8 = Decodable::consensus_decode(&mut d)?; @@ -134,10 +139,7 @@ impl Decodable for Key { } impl Encodable for Key { - fn consensus_encode( - &self, - mut s: S, - ) -> Result { + fn consensus_encode(&self, mut s: S) -> Result { let mut len = 0; len += VarInt((self.key.len() + 1) as u64).consensus_encode(&mut s)?; @@ -152,10 +154,7 @@ impl Encodable for Key { } impl Encodable for Pair { - fn consensus_encode( - &self, - mut s: S, - ) -> Result { + fn consensus_encode(&self, mut s: S) -> Result { let len = self.key.consensus_encode(&mut s)?; Ok(len + self.value.consensus_encode(s)?) } @@ -170,7 +169,10 @@ impl Decodable for Pair { } } -impl Encodable for ProprietaryKey where Subtype: Copy + From + Into { +impl Encodable for ProprietaryKey +where + Subtype: Copy + From + Into, +{ fn consensus_encode(&self, mut e: W) -> Result { let mut len = self.prefix.consensus_encode(&mut e)? + 1; e.emit_u8(self.subtype.into())?; @@ -179,7 +181,10 @@ impl Encodable for ProprietaryKey where Subtype: Copy + From Decodable for ProprietaryKey where Subtype: Copy + From + Into { +impl Decodable for ProprietaryKey +where + Subtype: Copy + From + Into, +{ fn consensus_decode(mut d: D) -> Result { let prefix = Vec::::consensus_decode(&mut d)?; let mut key = vec![]; @@ -190,17 +195,20 @@ impl Decodable for ProprietaryKey where Subtype: Copy + From ProprietaryKey where Subtype: Copy + From + Into { +impl ProprietaryKey +where + Subtype: Copy + From + Into, +{ /// Constructs [ProprietaryKey] from [Key]; returns /// [Error::InvalidProprietaryKey] if `key` do not starts with 0xFC byte pub fn from_key(key: Key) -> Result { if key.type_value != 0xFC { - return Err(Error::InvalidProprietaryKey) + return Err(Error::InvalidProprietaryKey); } Ok(deserialize(&key.key)?) @@ -210,7 +218,7 @@ impl ProprietaryKey where Subtype: Copy + From + Into pub fn to_key(&self) -> Key { Key { type_value: 0xFC, - key: serialize(self) + key: serialize(self), } } } diff --git a/src/pset/serialize.rs b/src/pset/serialize.rs index 92ac7922..75536075 100644 --- a/src/pset/serialize.rs +++ b/src/pset/serialize.rs @@ -19,21 +19,21 @@ use std::io; -use bitcoin::{self, PublicKey, VarInt}; -use crate::{Script, Transaction, TxOut, Txid, BlockHash, AssetId}; -use crate::encode::{self, serialize, deserialize, Decodable, Encodable, deserialize_partial}; -use bitcoin::util::bip32::{ChildNumber, Fingerprint, KeySource}; +use crate::confidential; +use crate::encode::{self, deserialize, deserialize_partial, serialize, Decodable, Encodable}; use crate::hashes::{hash160, ripemd160, sha256, sha256d, Hash}; +use crate::{AssetId, BlockHash, Script, Transaction, TxOut, Txid}; use bitcoin::hashes::hex::ToHex; -use crate::confidential; +use bitcoin::util::bip32::{ChildNumber, Fingerprint, KeySource}; +use bitcoin::{self, PublicKey, VarInt}; use secp256k1_zkp::{self, RangeProof, SurjectionProof, Tweak}; -use crate::taproot::{TapBranchHash, TapLeafHash, ControlBlock, LeafVersion}; +use super::map::{PsbtSighashType, TapTree}; use crate::schnorr; -use super::map::{TapTree, PsbtSighashType}; +use crate::taproot::{ControlBlock, LeafVersion, TapBranchHash, TapLeafHash}; -use crate::taproot::TaprootBuilder; use crate::sighash::SchnorrSigHashType; +use crate::taproot::TaprootBuilder; /// A trait for serializing a value as raw data for insertion into PSET /// key-value pairs. @@ -86,8 +86,7 @@ impl Serialize for Tweak { impl Deserialize for Tweak { fn deserialize(bytes: &[u8]) -> Result { let x = deserialize::<[u8; 32]>(&bytes)?; - Tweak::from_slice(&x) - .map_err(|_| encode::Error::ParseFailed("invalid Tweak")) + Tweak::from_slice(&x).map_err(|_| encode::Error::ParseFailed("invalid Tweak")) } } @@ -113,8 +112,7 @@ impl Serialize for PublicKey { impl Deserialize for PublicKey { fn deserialize(bytes: &[u8]) -> Result { - PublicKey::from_slice(bytes) - .map_err(|_| encode::Error::ParseFailed("invalid public key")) + PublicKey::from_slice(bytes).map_err(|_| encode::Error::ParseFailed("invalid public key")) } } @@ -135,7 +133,7 @@ impl Serialize for KeySource { impl Deserialize for KeySource { fn deserialize(bytes: &[u8]) -> Result { if bytes.len() < 4 { - return Err(io::Error::from(io::ErrorKind::UnexpectedEof).into()) + return Err(io::Error::from(io::ErrorKind::UnexpectedEof).into()); } let fprint: Fingerprint = Fingerprint::from(&bytes[0..4]); @@ -181,10 +179,10 @@ impl Deserialize for PsbtSighashType { impl Serialize for confidential::Value { fn serialize(&self) -> Vec { - match self{ + match self { confidential::Value::Null => vec![], // should never be invoked confidential::Value::Explicit(x) => Serialize::serialize(x), - y => encode::serialize(y) // confidential can serialized as is + y => encode::serialize(y), // confidential can serialized as is } } } @@ -226,10 +224,10 @@ impl Deserialize for secp256k1_zkp::Generator { impl Serialize for confidential::Asset { fn serialize(&self) -> Vec { - match self{ + match self { confidential::Asset::Null => vec![], // should never be invoked confidential::Asset::Explicit(x) => Serialize::serialize(x), - y => encode::serialize(y) // confidential can serialized as is + y => encode::serialize(y), // confidential can serialized as is } } } @@ -285,7 +283,7 @@ impl Deserialize for bitcoin::XOnlyPublicKey { } } -impl Serialize for schnorr::SchnorrSig { +impl Serialize for schnorr::SchnorrSig { fn serialize(&self) -> Vec { self.to_vec() } @@ -299,14 +297,17 @@ impl Deserialize for schnorr::SchnorrSig { .ok_or(encode::Error::ParseFailed("Invalid Sighash type"))?; let sig = secp256k1_zkp::schnorr::Signature::from_slice(&bytes[..64]) .map_err(|_| encode::Error::ParseFailed("Invalid Schnorr signature"))?; - Ok(schnorr::SchnorrSig{ sig, hash_ty }) + Ok(schnorr::SchnorrSig { sig, hash_ty }) } 64 => { let sig = secp256k1_zkp::schnorr::Signature::from_slice(&bytes[..64]) .map_err(|_| encode::Error::ParseFailed("Invalid Schnorr signature"))?; - Ok(schnorr::SchnorrSig{ sig, hash_ty: SchnorrSigHashType::Default }) + Ok(schnorr::SchnorrSig { + sig, + hash_ty: SchnorrSigHashType::Default, + }) } - _ => Err(encode::Error::ParseFailed("Invalid Schnorr signature len")) + _ => Err(encode::Error::ParseFailed("Invalid Schnorr signature len")), } } } @@ -324,7 +325,7 @@ impl Serialize for (bitcoin::XOnlyPublicKey, TapLeafHash) { impl Deserialize for (bitcoin::XOnlyPublicKey, TapLeafHash) { fn deserialize(bytes: &[u8]) -> Result { if bytes.len() < 32 { - return Err(io::Error::from(io::ErrorKind::UnexpectedEof).into()) + return Err(io::Error::from(io::ErrorKind::UnexpectedEof).into()); } let a: bitcoin::XOnlyPublicKey = Deserialize::deserialize(&bytes[..32])?; let b: TapLeafHash = Deserialize::deserialize(&bytes[32..])?; @@ -340,8 +341,7 @@ impl Serialize for ControlBlock { impl Deserialize for ControlBlock { fn deserialize(bytes: &[u8]) -> Result { - Self::from_slice(bytes) - .map_err(|_| encode::Error::ParseFailed("Invalid control block")) + Self::from_slice(bytes).map_err(|_| encode::Error::ParseFailed("Invalid control block")) } } @@ -358,7 +358,7 @@ impl Serialize for (Script, LeafVersion) { impl Deserialize for (Script, LeafVersion) { fn deserialize(bytes: &[u8]) -> Result { if bytes.is_empty() { - return Err(io::Error::from(io::ErrorKind::UnexpectedEof).into()) + return Err(io::Error::from(io::ErrorKind::UnexpectedEof).into()); } // The last byte is LeafVersion. let script = Script::deserialize(&bytes[..bytes.len() - 1])?; @@ -368,11 +368,12 @@ impl Deserialize for (Script, LeafVersion) { } } - impl Serialize for (Vec, KeySource) { fn serialize(&self) -> Vec { - let mut buf = Vec::with_capacity( 32 * self.0.len() + key_source_len(&self.1)); - self.0.consensus_encode(&mut buf).expect("Vecs don't error allocation"); + let mut buf = Vec::with_capacity(32 * self.0.len() + key_source_len(&self.1)); + self.0 + .consensus_encode(&mut buf) + .expect("Vecs don't error allocation"); // TODO: Add support for writing into a writer for key-source buf.extend(self.1.serialize()); buf @@ -381,7 +382,7 @@ impl Serialize for (Vec, KeySource) { impl Deserialize for (Vec, KeySource) { fn deserialize(bytes: &[u8]) -> Result { - let (leafhash_vec, consumed) = deserialize_partial::>(&bytes)?; + let (leafhash_vec, consumed) = deserialize_partial::>(&bytes)?; let key_source = KeySource::deserialize(&bytes[consumed..])?; Ok((leafhash_vec, key_source)) } @@ -399,11 +400,14 @@ impl Serialize for TapTree { // safe to cast from usize to u8 buf.push(leaf_info.merkle_branch.as_inner().len() as u8); buf.push(leaf_info.ver.as_u8()); - leaf_info.script.consensus_encode(&mut buf).expect("Vecs dont err"); + leaf_info + .script + .consensus_encode(&mut buf) + .expect("Vecs dont err"); } buf } - // This should be unreachable as we Taptree is already finalized + // This should be unreachable as we Taptree is already finalized _ => unreachable!(), } } @@ -414,7 +418,9 @@ impl Deserialize for TapTree { let mut builder = TaprootBuilder::new(); let mut bytes_iter = bytes.iter(); while let Some(depth) = bytes_iter.next() { - let version = bytes_iter.next().ok_or(encode::Error::ParseFailed("Invalid Taproot Builder"))?; + let version = bytes_iter + .next() + .ok_or(encode::Error::ParseFailed("Invalid Taproot Builder"))?; let (script, consumed) = deserialize_partial::