From e5cc3c5cf8ce01b0041cecd51ebc3df771308c84 Mon Sep 17 00:00:00 2001 From: Mike Clay Date: Mon, 1 Jun 2026 16:36:11 +0100 Subject: [PATCH 1/5] docs: scaffold for documenting non-ledger transactions Closes #1533 Scaffold commit for the work package to document the Midnight transaction format and the node's non-ledger transaction types in the Midnight docs. Documentation commits will follow. Signed-off-by: Mike Clay From adf258a0d1fa56f4917ba35b8433aefb14efa573 Mon Sep 17 00:00:00 2001 From: Mike Clay Date: Mon, 1 Jun 2026 18:07:25 +0100 Subject: [PATCH 2/5] docs: document non-ledger transaction surface in rustdoc Add crate-level and item-level rustdoc across the node-owned non-ledger transaction surface: - midnight-primitives: crate doc; TransactionType/TransactionTypeV2 type and variant docs framing the classification as an off-node vocabulary consumed through metadata, not in-node dispatch, plus the V1 to V2 evolution; MidnightSystemTransactionExecutor and BridgeRecipient docs. - pallet-midnight: crate doc; send_mn_transaction doc with the ledger/non-ledger boundary and an Errors section; remove the stale scaffold and todo comments. - pallet-midnight-system: crate doc; send_mn_system_transaction doc with the root and governance gate and an Errors section; SystemTransactionApplied event docs. - pallet-cnight-observation: process_tokens inherent-path doc. - pallet-c2m-bridge: cross-link the bridge handler to the system transaction seam, framing a bridge transfer as an inherent that produces a system transaction. Documentation only; no code logic changed. Assisted by AI Signed-off-by: Mike Clay --- pallets/c2m-bridge/src/lib.rs | 9 +++ pallets/cnight-observation/src/lib.rs | 14 +++++ pallets/midnight-system/src/lib.rs | 45 ++++++++++++++ pallets/midnight/src/lib.rs | 44 +++++++++++--- primitives/midnight/src/lib.rs | 84 ++++++++++++++++++++++++++- 5 files changed, 187 insertions(+), 9 deletions(-) diff --git a/pallets/c2m-bridge/src/lib.rs b/pallets/c2m-bridge/src/lib.rs index b2ac092bb..b3ee7d0d2 100644 --- a/pallets/c2m-bridge/src/lib.rs +++ b/pallets/c2m-bridge/src/lib.rs @@ -15,6 +15,15 @@ //! //! This pallet implements the [`pallet_partner_chains_bridge::TransferHandler`] trait //! with Midnight-specific logic. +//! +//! A bridge transfer is an inherent that produces a system transaction, not a +//! standalone transaction type. The handler validates an observed Cardano +//! transfer against the approved-transfers list and applies the resulting ledger +//! system transaction through the +//! [`MidnightSystemTransactionExecutor`](midnight_primitives::MidnightSystemTransactionExecutor) +//! seam, so the net effect on the ledger arrives as a system transaction. Each +//! handled transfer also emits a bridge [`Event`] for correlation with the +//! Cardano-side movement. #![cfg_attr(not(feature = "std"), no_std)] diff --git a/pallets/cnight-observation/src/lib.rs b/pallets/cnight-observation/src/lib.rs index ac88f0d66..a0906be1e 100644 --- a/pallets/cnight-observation/src/lib.rs +++ b/pallets/cnight-observation/src/lib.rs @@ -637,6 +637,20 @@ pub mod pallet { #[pallet::call] impl Pallet { + /// Record observed Cardano token movements on Midnight. + /// + /// This call is the payload of the cNIGHT observation inherent: the block + /// author injects the observed UTXOs and the next Cardano position + /// through `create_inherent`, and every other node re-derives the same + /// data and compares it in `check_inherent`. The observation is therefore + /// a consensus-checked fact rather than a user-submitted transaction — + /// the call requires no origin and runs at most once per block. + /// + /// # Errors + /// + /// Returns [`Error::TooManyUtxos`] if `utxos` exceeds the per-block + /// capacity, or [`Error::InherentAlreadyExecuted`] if the inherent has + /// already run in this block. #[pallet::call_index(0)] #[pallet::weight((T::WeightInfo::process_tokens(CardanoTxCapacityPerBlock::::get().saturating_mul(UTXO_PER_TX_OVERESTIMATE)), DispatchClass::Mandatory))] pub fn process_tokens( diff --git a/pallets/midnight-system/src/lib.rs b/pallets/midnight-system/src/lib.rs index 6d37834c3..f166eb03c 100644 --- a/pallets/midnight-system/src/lib.rs +++ b/pallets/midnight-system/src/lib.rs @@ -1,3 +1,25 @@ +//! # Midnight system transaction pallet +//! +//! Applies privileged system transactions to the Midnight ledger. +//! +//! A system transaction is a node-owned, non-ledger transaction category: it +//! changes ledger state through a privileged, audited channel rather than +//! through the user transaction pool. Two entry points reach the ledger: +//! +//! - [`Pallet::send_mn_system_transaction`] — a root-origin extrinsic, gated by +//! a governance allow-check, that governance uses to apply a system +//! transaction directly. +//! - The [`MidnightSystemTransactionExecutor`] implementation — the seam by +//! which other pallets (notably the Cardano-to-Midnight bridge) apply a +//! serialized system transaction. +//! +//! Both paths emit a [`SystemTransactionApplied`] event so an indexer can +//! correlate the effect on the ledger with the originating call. The serialized +//! system transaction is opaque to the node; the ledger decodes and interprets +//! it. +//! +//! [`MidnightSystemTransactionExecutor`]: midnight_primitives::MidnightSystemTransactionExecutor + #![cfg_attr(not(feature = "std"), no_std)] extern crate alloc; @@ -31,9 +53,16 @@ pub mod pallet { SystemTransactionApplied(SystemTransactionApplied), } + /// Emitted when a system transaction is applied to the ledger. + /// + /// Both [`Pallet::send_mn_system_transaction`] and the + /// `MidnightSystemTransactionExecutor` seam deposit this event so an indexer + /// can correlate the ledger effect with the originating call. #[derive(Clone, Debug, PartialEq, Encode, Decode, DecodeWithMemTracking, TypeInfo)] pub struct SystemTransactionApplied { + /// Ledger transaction hash of the applied system transaction. pub hash: Hash, + /// The serialized system transaction that was applied, opaque to the node. pub serialized_system_transaction: Vec, } @@ -115,6 +144,22 @@ pub mod pallet { #[pallet::call] impl Pallet { + /// Apply a system transaction to the ledger. + /// + /// `midnight_system_tx` is the opaque, serialized ledger system + /// transaction. The call requires root origin and is gated by the + /// ledger's governance allow-check, so only the system transactions + /// governance is permitted to run reach the ledger. On success it applies + /// the transaction through the ledger system-transaction path and emits a + /// [`SystemTransactionApplied`] event. + /// + /// # Errors + /// + /// Returns [`Error::SystemTransactionNotAllowedForGovernance`] if the + /// governance allow-check rejects the transaction, or one of the + /// ledger-derived error variants (mirrored from the ledger API) if the + /// ledger fails to apply it. The dispatch also fails if the origin is not + /// root. #[pallet::call_index(0)] #[pallet::weight((ConfigurableSystemTxWeight::::get(), DispatchClass::Operational))] pub fn send_mn_system_transaction( diff --git a/pallets/midnight/src/lib.rs b/pallets/midnight/src/lib.rs index a829d4ce0..6c2842b2d 100644 --- a/pallets/midnight/src/lib.rs +++ b/pallets/midnight/src/lib.rs @@ -11,13 +11,26 @@ // See the License for the specific language governing permissions and // limitations under the License. +//! # Midnight pallet +//! +//! Owns the ledger-carrying transaction envelope and validates it before the +//! ledger applies it. +//! +//! [`Pallet::send_mn_transaction`] is the primary dispatchable: it carries a +//! ledger transaction as an opaque byte vector, validated through the ledger +//! API and applied to ledger state. The node frames, validates, weighs, and +//! routes the transaction; the ledger decodes and interprets the opaque +//! payload. This pallet sits on the node side of that boundary and does not +//! inspect the payload's contents. +//! +//! The crate also re-exports the [`TransactionType`] and [`TransactionTypeV2`] +//! classification vocabulary (defined in `midnight-primitives`), which off-node +//! consumers read through runtime metadata to label a decoded transaction. + #![cfg_attr(not(feature = "std"), no_std)] extern crate alloc; -/// Edit this file to define custom logic or remove it if it is not needed. -/// Learn more about FRAME and the core library of Substrate FRAME pallets: -/// // Re-export pallet items so that they can be accessed from the crate namespace. pub use pallet::*; @@ -362,12 +375,29 @@ pub mod pallet { } } - // Dispatchable functions allows users to interact with the pallet and invoke state changes. - // These functions materialize as "extrinsics", which are often compared to transactions. - // Dispatchable functions must be annotated with a weight and must return a DispatchResult. - //todo example of custom transaction type (extrinsic) transaction has to be signed to call it #[pallet::call] impl Pallet { + /// Apply a ledger transaction to ledger state. + /// + /// `midnight_tx` is the opaque, serialized ledger transaction. The call + /// is unsigned and submitted through the transaction pool; the pallet's + /// `ValidateUnsigned` implementation gates it through the ledger API + /// before dispatch. On apply, the pallet hands the payload to the ledger + /// and emits the resulting ledger events (contract call, deploy, + /// maintain, claimed rewards, unshielded token movements, and an + /// applied-transaction marker). + /// + /// This is the node-owned envelope for a ledger transaction: the node + /// frames, validates, weighs, and routes the transaction, while the + /// ledger decodes and interprets the `midnight_tx` payload. The node does + /// not inspect the payload's contents. + /// + /// # Errors + /// + /// Returns one of the ledger-derived [`Error`] variants if the ledger + /// rejects the transaction. Validity failures surfaced during pool + /// validation map to `InvalidTransaction` codes rather than a dispatch + /// error. #[pallet::call_index(0)] #[pallet::weight(Pallet::::get_tx_weight(midnight_tx))] pub fn send_mn_transaction(_origin: OriginFor, midnight_tx: Vec) -> DispatchResult { diff --git a/primitives/midnight/src/lib.rs b/primitives/midnight/src/lib.rs index c71d36c79..14dd3a2aa 100644 --- a/primitives/midnight/src/lib.rs +++ b/primitives/midnight/src/lib.rs @@ -11,6 +11,26 @@ // See the License for the specific language governing permissions and // limitations under the License. +//! # Midnight node primitives +//! +//! Shared types and traits that define the boundary between the Midnight node +//! and the Midnight ledger. +//! +//! The node frames, validates, weighs, and routes transactions; the ledger +//! decodes and interprets the opaque payload carried by a ledger transaction. +//! Everything in this crate sits on the node side of that boundary. +//! +//! The crate exposes: +//! +//! - The [`TransactionType`] and [`TransactionTypeV2`] classification +//! vocabulary, published to off-node consumers through runtime metadata. +//! - The [`MidnightSystemTransactionExecutor`] seam, by which other pallets +//! apply a serialized system transaction to the ledger. +//! - The [`LedgerStateProviderMut`] and [`LedgerBlockContextProvider`] seams +//! for reading and mutating ledger state. +//! - The [`bridge`] module's [`BridgeRecipient`] type, used by the bridge +//! inherent and the Cardano-to-Midnight bridge pallet. + #![cfg_attr(not(feature = "std"), no_std)] extern crate alloc; @@ -40,24 +60,77 @@ pub trait LedgerBlockContextProvider { fn get_block_context() -> BlockContext; } +/// Seam by which a pallet applies a serialized system transaction to the ledger. +/// +/// `pallet-midnight-system` implements this trait so that other pallets — notably +/// the Cardano-to-Midnight bridge — can apply a system transaction through the +/// privileged ledger path without depending on the system pallet directly. A +/// bridge transfer uses this seam to turn an observed Cardano transfer into a +/// system transaction. +/// +/// The argument is the opaque, serialized ledger system transaction; the node +/// passes it to the ledger and does not interpret its contents. pub trait MidnightSystemTransactionExecutor { - /// Execute a Midnight System Transaction and return a SCALE-compatible result + /// Apply a serialized system transaction and return its ledger transaction hash. + /// + /// # Errors + /// + /// Returns a [`DispatchError`] if the ledger rejects the system transaction + /// (for example, a deserialization or transaction error surfaced through the + /// ledger API). fn execute_system_transaction( serialized_system_transaction: Vec, ) -> Result; } +/// Classification vocabulary for a decoded transaction, consumed off-node. +/// +/// This enumeration is a published vocabulary, exposed to off-node consumers +/// (indexers, the toolkit, and downstream tooling) through runtime metadata. It +/// labels a decoded transaction; it is **not** an in-node dispatch mechanism. +/// The node never matches on these variants to decide how to process a +/// transaction — dispatch happens through the FRAME pallet [`Call`] enums and +/// inherents. The variants exist so a downstream decoder can classify a +/// transaction without re-implementing the dispatch logic. +/// +/// [`TransactionTypeV2`] supersedes this type: where this version carries an +/// `Option` (the decoded ledger transaction if decoding succeeded), the V2 +/// vocabulary carries a `Result` so a consumer can see why a +/// payload failed to decode. +/// +/// [`Call`]: https://docs.rs/frame-support/latest/frame_support/pallet_macros/attr.call.html #[derive(Clone, Encode, Decode, DecodeWithMemTracking, Debug, TypeInfo)] pub enum TransactionType { + /// A ledger-carrying transaction: the opaque ledger payload and, if it + /// decoded, the decoded ledger transaction. MidnightTx(Vec, Option), + /// The block timestamp, surfaced as a first-class transaction value. TimestampTx(u64), + /// A transaction the classifier does not recognize (for example, a future + /// or unknown variant). UnknownTx, } +/// Current classification vocabulary for a decoded transaction, consumed off-node. +/// +/// Like [`TransactionType`], this enumeration is a published vocabulary exposed +/// to off-node consumers through runtime metadata to label a decoded +/// transaction. It is **not** an in-node dispatch mechanism — the node never +/// matches on these variants; dispatch happens through the FRAME pallet `Call` +/// enums and inherents. +/// +/// This version supersedes [`TransactionType`] by carrying the ledger decode +/// `Result` rather than an `Option`, so a consumer can observe a decode failure +/// ([`LedgerApiError`]) instead of only the absence of a decoded transaction. #[derive(Clone, Encode, Decode, DecodeWithMemTracking, Debug, TypeInfo)] pub enum TransactionTypeV2 { + /// A ledger-carrying transaction: the opaque ledger payload and the result + /// of decoding it. MidnightTx(Vec, Result), + /// The block timestamp, surfaced as a first-class transaction value. TimestampTx(u64), + /// A transaction the classifier does not recognize (for example, a future + /// or unknown variant). UnknownTx, } @@ -87,7 +160,14 @@ pub mod bridge { TooLong, } - /// Recipient type used by the bridge pallet and inherent data provider. + /// A Midnight recipient address carried by a bridge transfer. + /// + /// The bridge pallet and the bridge inherent data provider use this type to + /// name the beneficiary of a Cardano-to-Midnight transfer. The address is + /// bounded to [`BRIDGE_RECIPIENT_MAX_BYTES`] bytes so the recipient encoded + /// in the bridge datum has a fixed maximum size and a predictable encoded + /// length; an address exceeding the bound is rejected with + /// [`BridgeRecipientError::TooLong`]. #[derive( Clone, PartialEq, From 0c9c898281838fbff9b005fbf303eba82b35e3b6 Mon Sep 17 00:00:00 2001 From: Mike Clay Date: Mon, 1 Jun 2026 18:28:19 +0100 Subject: [PATCH 3/5] docs(changes): add changelog fragment for non-ledger transaction rustdoc Add a #node changelog fragment for PR #1619 so the Changes Check CI gate passes. The PR documents the node's non-ledger transaction surface in rustdoc and was missing its required changes/ entry. Closes #1533 Assisted by AI Signed-off-by: Mike Clay --- ...document-non-ledger-transactions-rustdoc.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 changes/node/changed/document-non-ledger-transactions-rustdoc.md diff --git a/changes/node/changed/document-non-ledger-transactions-rustdoc.md b/changes/node/changed/document-non-ledger-transactions-rustdoc.md new file mode 100644 index 000000000..297f352bb --- /dev/null +++ b/changes/node/changed/document-non-ledger-transactions-rustdoc.md @@ -0,0 +1,18 @@ +#node + +# Document the non-ledger transaction surface in rustdoc + +Adds crate- and item-level documentation across the node crates that define the +non-ledger transaction surface: `TransactionType`/`TransactionTypeV2` and their +variants in `primitives/midnight`, the `send_mn_transaction` envelope in +`pallets/midnight`, the system-transaction entry points and +`SystemTransactionApplied` event in `pallets/midnight-system`, the +`process_tokens` observation-inherent path in `pallets/cnight-observation`, and +the bridge-transfer framing in `pallets/c2m-bridge`. The docs state the +node/ledger boundary, frame the transaction classification as an off-node +vocabulary consumed via runtime metadata (not in-node dispatch), and remove a +stale FRAME-template scaffold comment and `//todo` placeholder. Documentation +only — no behaviour, signatures, or error codes change. + +Closes: https://github.com/midnightntwrk/midnight-node/issues/1533 +PR: https://github.com/midnightntwrk/midnight-node/pull/1619 From d50e20e724c6e1324dd06d1b4aa1b7fe20ff0d5f Mon Sep 17 00:00:00 2001 From: Mike Clay <176900785+m2ux@users.noreply.github.com> Date: Wed, 10 Jun 2026 09:29:21 +0100 Subject: [PATCH 4/5] Update primitives/midnight/src/lib.rs Co-authored-by: justinfrevert <81839854+justinfrevert@users.noreply.github.com> Signed-off-by: Mike Clay <176900785+m2ux@users.noreply.github.com> --- primitives/midnight/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/primitives/midnight/src/lib.rs b/primitives/midnight/src/lib.rs index 14dd3a2aa..335c072f1 100644 --- a/primitives/midnight/src/lib.rs +++ b/primitives/midnight/src/lib.rs @@ -13,8 +13,8 @@ //! # Midnight node primitives //! -//! Shared types and traits that define the boundary between the Midnight node -//! and the Midnight ledger. +//! Shared types and traits that define the boundary between the Midnight node, +//! the runtime, and the Midnight ledger. //! //! The node frames, validates, weighs, and routes transactions; the ledger //! decodes and interprets the opaque payload carried by a ledger transaction. From 9b3d762695ee96d60aba512103c080d029322e70 Mon Sep 17 00:00:00 2001 From: Mike Clay Date: Mon, 29 Jun 2026 13:14:31 +0100 Subject: [PATCH 5/5] chore: rebuild metadata Regenerate the runtime metadata snapshot so it matches the runtime built from this branch. The non-ledger transaction rustdoc added in this PR is embedded in the SCALE-encoded metadata (call, event and error doc strings), so the committed snapshot drifted and the Metadata Check failed. Assisted-by: Claude:claude-opus-4-8 Signed-off-by: Mike Clay --- metadata/static/midnight_metadata.scale | Bin 135037 -> 137312 bytes metadata/static/midnight_metadata_2.0.0.scale | Bin 135037 -> 137312 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/metadata/static/midnight_metadata.scale b/metadata/static/midnight_metadata.scale index 7c4ab497c2a791a1c44dc29d8c2c56b0198499db..84db73c020333f4c3a61a825024b3f46ddd87328 100644 GIT binary patch delta 2252 zcma)7zmMER7+n`gM{z|YB60;V5)pTi_AEgKM+zc@;Dka@v=<>oQ9NsZyB^M-ac0JQ zw=_o3rVCO!DoT(}L?VAg8cNEDzaYgG6hY$65AS-FE9iFZ@i*Ul-+S--_vfwWXIp1~ zTm-e{U?$vCU1n3HB!b7^>Pg_6vw{;9FtQaZYnWVI-yn3wjxJZca)3=m$4E}2CNNVR*Iuf<==-|=MDn_K{%tyw3QWd-qSz}bY$3Gt|Tz!*3&R% z1$9lOmgDo93v?{xnB^50HE7Uu!gXQBj;B&kRXA$YF-cadg$Iat?p7`v*RG&qe@Iu& z^)cyd>FD)jQiAR{DX9wDS0@tHNG_=AR6`5|TsZ#&kI;RRBs0xx!j+52IDVcGbP&71 z%pB2941+FkrW6$(m9&#Y)(gr}(D>ek>@4Xxlw7Oi#)aJt=2B5h8RHE*1FvO|f7ABbYIHe3b> zjvLJZ3|55dFqmGNSI9w1pFF+#PSSnyOYd8=G?wZi?VH+6M=#dAhQt5QyW#9VgL$qk z+(DoZTHyd|g@Gt7<^s(^kWiX)UBRYHM|KhikNM1@TrIiGiNV6^WIrz{KSpdQ3Pr-Nmp_Ot%uf@H`|&n5;LkY4eH+%HMUsraa7jNu~^%g~SaPasnP4+q*4w^b2pc&8r5Ep7}3~mS7-HvoR z@p|ogQLJ^lR|}^S&_B}(ssLaQ?2cy0yKAwBl^dOGA!`*P4?!75+)EB~!f?W&=!iIJ z%mGGx<59-GeDc3 zSR?adUl$EThYlkupD)_)qss|*ab`%G)&!rpk-F8f84fMT-pBUr`t`X^6ZZG_KfQ2x zJ-I8tVj=^#!ag9zVyhUq*jW?yVxH2WtdpdV(Uq(xO5Nmgd1OzO$?kpRl$Evq52MqZ zsNa|9&zIXya^CP9Vd*8ks`L2m>&ct%uj~P?!f>&3P01_FqF8#DgGB3AS!nLZXX(>t JY4ZE?{{RkiIZFTl delta 38 wcmV+>0NMZGun7I02(Y#!0RXdMC?5d<0FyCCMze%0tq1`CgRVEXt~UX);1*#HB>(^b diff --git a/metadata/static/midnight_metadata_2.0.0.scale b/metadata/static/midnight_metadata_2.0.0.scale index 7c4ab497c2a791a1c44dc29d8c2c56b0198499db..84db73c020333f4c3a61a825024b3f46ddd87328 100644 GIT binary patch delta 2252 zcma)7zmMER7+n`gM{z|YB60;V5)pTi_AEgKM+zc@;Dka@v=<>oQ9NsZyB^M-ac0JQ zw=_o3rVCO!DoT(}L?VAg8cNEDzaYgG6hY$65AS-FE9iFZ@i*Ul-+S--_vfwWXIp1~ zTm-e{U?$vCU1n3HB!b7^>Pg_6vw{;9FtQaZYnWVI-yn3wjxJZca)3=m$4E}2CNNVR*Iuf<==-|=MDn_K{%tyw3QWd-qSz}bY$3Gt|Tz!*3&R% z1$9lOmgDo93v?{xnB^50HE7Uu!gXQBj;B&kRXA$YF-cadg$Iat?p7`v*RG&qe@Iu& z^)cyd>FD)jQiAR{DX9wDS0@tHNG_=AR6`5|TsZ#&kI;RRBs0xx!j+52IDVcGbP&71 z%pB2941+FkrW6$(m9&#Y)(gr}(D>ek>@4Xxlw7Oi#)aJt=2B5h8RHE*1FvO|f7ABbYIHe3b> zjvLJZ3|55dFqmGNSI9w1pFF+#PSSnyOYd8=G?wZi?VH+6M=#dAhQt5QyW#9VgL$qk z+(DoZTHyd|g@Gt7<^s(^kWiX)UBRYHM|KhikNM1@TrIiGiNV6^WIrz{KSpdQ3Pr-Nmp_Ot%uf@H`|&n5;LkY4eH+%HMUsraa7jNu~^%g~SaPasnP4+q*4w^b2pc&8r5Ep7}3~mS7-HvoR z@p|ogQLJ^lR|}^S&_B}(ssLaQ?2cy0yKAwBl^dOGA!`*P4?!75+)EB~!f?W&=!iIJ z%mGGx<59-GeDc3 zSR?adUl$EThYlkupD)_)qss|*ab`%G)&!rpk-F8f84fMT-pBUr`t`X^6ZZG_KfQ2x zJ-I8tVj=^#!ag9zVyhUq*jW?yVxH2WtdpdV(Uq(xO5Nmgd1OzO$?kpRl$Evq52MqZ zsNa|9&zIXya^CP9Vd*8ks`L2m>&ct%uj~P?!f>&3P01_FqF8#DgGB3AS!nLZXX(>t JY4ZE?{{RkiIZFTl delta 38 wcmV+>0NMZGun7I02(Y#!0RXdMC?5d<0FyCCMze%0tq1`CgRVEXt~UX);1*#HB>(^b