<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE rfc [
  <!ENTITY nbsp    "&#160;">
  <!ENTITY zwsp   "&#8203;">
  <!ENTITY nbhy   "&#8209;">
  <!ENTITY wj     "&#8288;">
]>
<?xml-stylesheet type="text/xsl" href="rfc2629.xslt" ?>
<!-- generated by https://github.com/cabo/kramdown-rfc version 1.7.39 (Ruby 2.6.10) -->
<?rfc docmapping="yes"?>
<?rfc comments="yes"?>
<rfc xmlns:xi="http://www.w3.org/2001/XInclude" ipr="trust200902" docName="draft-haynes-nfsv4-flexfiles-v2-delta-writes-00" category="std" consensus="true" tocInclude="true" sortRefs="true" symRefs="true" version="3">
  <!-- xml2rfc v2v3 conversion 3.34.0 -->
  <front>
    <title abbrev="FFv2 Delta Writes">Delta-Write Extension for the Flexible File Version 2 Layout Type</title>
    <seriesInfo name="Internet-Draft" value="draft-haynes-nfsv4-flexfiles-v2-delta-writes-00"/>
    <author initials="T." surname="Haynes" fullname="Thomas Haynes">
      <organization>Hammerspace</organization>
      <address>
        <email>loghyr@gmail.com</email>
      </address>
    </author>
    <date/>
    <area>General</area>
    <workgroup>Network File System Version 4</workgroup>
    <keyword>pNFS</keyword>
    <keyword>flexfiles</keyword>
    <keyword>erasure coding</keyword>
    <keyword>Mojette</keyword>
    <keyword>XOR</keyword>
    <keyword>HPC</keyword>
    <abstract>
      <?line 47?>

<t>The Flexible File Version 2 pNFS layout type defines a
chunk-oriented data-server protocol in which every write is a
full-chunk payload.
For workloads that make small edits to files protected by an
XOR-based erasure encoding, this forces client-side stripe fetch,
re-encode, and transmit on every edit, with wire amplification of
three to four orders of magnitude per byte edited.  This document
defines an optional extension, CHUNK_XOR_DELTA, that lets a client
transmit a per-projection XOR delta directly to each data server
holding a projection of the affected stripe; the data server
applies the delta locally.  The extension is restricted to
XOR-linear systematic encodings and XOR-affine checksums, using
the existing chunk state machine with no new commit protocol.</t>
    </abstract>
    <note removeInRFC="true">
      <name>About This Document</name>
      <t>
        The latest revision of this draft can be found at <eref target="https://ietf-wg-nfsv4.github.io/flexfiles-v2-delta-writes/draft-haynes-nfsv4-flexfiles-v2-delta-writes.html"/>.
        Status information for this document may be found at <eref target="https://datatracker.ietf.org/doc/draft-haynes-nfsv4-flexfiles-v2-delta-writes/"/>.
      </t>
      <t>
        Discussion of this document takes place on the
        Network File System Version 4 Working Group mailing list (<eref target="mailto:nfsv4@ietf.org"/>),
        which is archived at <eref target="https://mailarchive.ietf.org/arch/browse/nfsv4/"/>.
        Subscribe at <eref target="https://www.ietf.org/mailman/listinfo/nfsv4/"/>.
      </t>
      <t>Source for this draft and an issue tracker can be found at
        <eref target="https://github.com/ietf-wg-nfsv4/flexfiles-v2-delta-writes"/>.</t>
    </note>
  </front>
  <middle>
    <?line 63?>

<section anchor="sec-introduction">
      <name>Introduction</name>
      <t>The base Flexible File Version 2 specification
<xref target="I-D.haynes-nfsv4-flexfiles-v2"/> defines the CHUNK_WRITE operation
as the sole client-issued data-write operation against a data server.
Each CHUNK_WRITE carries a full chunk payload -- either a block
(for mirrored layouts) or a shard (for erasure-coded layouts) --
which the data server places in the PENDING state and later transitions
to FINALIZED and COMMITTED through the operations of the chunk state
machine defined in <xref target="I-D.haynes-nfsv4-flexfiles-v2"/>.</t>
      <t>For workloads with the following combination of properties, this
model has an unavoidable wire-amplification cost:</t>
      <ul spacing="normal">
        <li>
          <t>Small edits (bytes to kilobytes) inside larger chunks (typically
tens of kilobytes to megabytes)</t>
        </li>
        <li>
          <t>Erasure-coded layouts where the parity value depends on the
edited data-shard byte</t>
        </li>
        <li>
          <t>Multiple concurrent writers making disjoint edits to the same file,
such that per-writer fetch-modify-writeback of full stripes creates
a bandwidth bottleneck disproportionate to the logical bytes edited</t>
        </li>
      </ul>
      <t>The paradigmatic example is the "Multiple writers, disjoint regions
(rare)" workload class named in the Use Cases section of
<xref target="I-D.haynes-nfsv4-flexfiles-v2"/>: high-performance
computing (HPC) checkpoint workloads in which thousands of ranks
write disjoint regions of the same file in lockstep.  For a 16-byte
edit inside a 256 KiB stripe, the base CHUNK_WRITE path costs
approximately 256 KiB of stripe fetch plus 384 KiB of
new-stripe-plus-parity transmit per writer per checkpoint interval
-- an amplification of roughly 4x10^4 over the logical edited bytes
for that configuration.  Figures throughout this document are
illustrative of the workloads described, not performance guarantees.</t>
      <t>When the erasure encoding is XOR-based, this amplification is
avoidable.  If the client can compute the delta</t>
      <artwork><![CDATA[
D = D_old XOR D_new
]]></artwork>
      <t>between the pre-edit and post-edit values of the affected bytes,
and the parity encoding is expressible as an XOR combination of
source bytes, then updating any parity projection reduces to XORing
the delta into a specific offset of the stored projection.  For a
16-byte edit on a k=4 m=2 layout, this reduces the wire cost from
approximately 256 KiB to roughly 96 bytes across the six projection
data servers.</t>
      <t>This document defines CHUNK_XOR_DELTA, an optional operation that
transmits per-projection deltas.  Applicability is bounded by two
independent capability flags, both derived from static properties of
the encoding-plus-checksum pair the layout already carries:</t>
      <ul spacing="normal">
        <li>
          <t>The erasure encoding is XOR-linear in its parity computation AND
systematic (D_old for any byte range is directly readable from a
single projection).  Registry flag EC_ENC_FLAGS_XOR_DELTA_CAPABLE,
this document.  FFV2_ENCODING_MIRRORED (identity encoding,
degenerate case), FFV2_ENCODING_MOJETTE_SYSTEMATIC, and
FFV2_ENCODING_XOR_PARITY qualify.
FFV2_ENCODING_MOJETTE_NON_SYSTEMATIC is XOR-linear but not
systematic; see <xref target="sec-scope"/> for why it is excluded.</t>
        </li>
        <li>
          <t>The chunk envelope's checksum algorithm is XOR-affine (registry
flag CHECKSUM_FLAGS_XOR_AFFINE, this document); the CRC family
qualifies, cryptographic hashes and modular-sum checksums do not.</t>
        </li>
      </ul>
      <t>The client determines capability for a given layout by looking up
the layout's declared encoding in the Erasure Encoding Type
Registry and its <tt>ffv2m_checksum_algorithm</tt> in the Checksum
Algorithm Registry, both established in the IANA Considerations of
<xref target="I-D.haynes-nfsv4-flexfiles-v2"/>.  When both
registry flags are set the client <bcp14>MAY</bcp14> issue CHUNK_XOR_DELTA against
that layout; when either is clear it <bcp14>MUST NOT</bcp14>.  No new field is
added to <tt>ffv2_mirror4</tt>; capability is fully derivable from fields
already present.</t>
      <t>A flag the client cannot read is clear.  This covers a registry copy
predating the columns this document adds
(<xref target="sec-iana-encoding-flag"/>, <xref target="sec-iana-checksum-flag"/>), an encoding
or checksum value the client does not recognize, and a registry the
client cannot consult at all.  Capability <bcp14>MUST NOT</bcp14> be inferred from
the encoding's name, from the layout alone, or from the fact that a
server advertises an encoding this document discusses; a client that
cannot read both flags uses CHUNK_WRITE.  The two registries are
established by <xref target="I-D.haynes-nfsv4-flexfiles-v2"/> and extended here, so
a client <bcp14>MAY</bcp14> hold a registry snapshot older than this document -- the
fail-closed rule above is what makes that safe, and no synchronized
release of the two documents is required for correctness.</t>
      <section anchor="requirements-language">
        <name>Requirements Language</name>
        <t>The key words "<bcp14>MUST</bcp14>", "<bcp14>MUST NOT</bcp14>", "<bcp14>REQUIRED</bcp14>", "<bcp14>SHALL</bcp14>", "<bcp14>SHALL
NOT</bcp14>", "<bcp14>SHOULD</bcp14>", "<bcp14>SHOULD NOT</bcp14>", "<bcp14>RECOMMENDED</bcp14>", "<bcp14>NOT RECOMMENDED</bcp14>",
"<bcp14>MAY</bcp14>", and "<bcp14>OPTIONAL</bcp14>" in this document are to be interpreted as
described in BCP 14 <xref target="RFC2119"/> <xref target="RFC8174"/> when, and only when, they
appear in all capitals, as shown here.</t>
        <?line -18?>

</section>
      <section anchor="relationship-to-base-specification">
        <name>Relationship to Base Specification</name>
        <t>This document extends the flexible file v2 layout protocol family with
one new operation (CHUNK_XOR_DELTA), one new error code
(NFS4ERR_DELTA_INCOMPLETE), one new advisory-warning code
(NFS4ERR_DELTA_LOG_FULL), and additions to two IANA registries
established by <xref target="I-D.haynes-nfsv4-flexfiles-v2"/>: the Checksum
Algorithm Registry and the Erasure Encoding Type Registry.  All
mechanisms defined here reuse the chunk state machine, chunk_guard4
CAS primitive, repair protocol, and layout-revocation paths defined in
<xref target="I-D.haynes-nfsv4-flexfiles-v2"/>.</t>
      </section>
    </section>
    <section anchor="sec-terminology">
      <name>Terminology</name>
      <t>The terms block, shard, chunk, chunk state machine, chunk
generation, chunk owner, and projection are defined in
<xref target="I-D.haynes-nfsv4-flexfiles-v2"/>, hereafter "the base
specification".  This document uses them without redefinition, and
cites the base specification again only when pointing at a specific
rule or section within it.</t>
      <t>Additional terms defined by this document:</t>
      <dl>
        <dt>delta:</dt>
        <dd>
          <t>A byte sequence D such that D = D_old XOR D_new, where D_old is the
current value of a contiguous range of bytes within a chunk and
D_new is the client-intended replacement value.  A delta is applied
to a stored chunk by XORing D into the same byte range.</t>
        </dd>
        <dt>delta epoch:</dt>
        <dd>
          <t>A contiguous sequence of CHUNK_XOR_DELTA operations issued by a
single client against a single chunk, bracketed by a chunk_guard4
CAS at open time and a CHUNK_FINALIZE at close time.  All deltas
within an epoch share the same chunk_guard4 generation and are
ordered by a monotonic sequence number assigned by the client.</t>
        </dd>
        <dt>delta log:</dt>
        <dd>
          <t>The per-chunk, in-data-server record of deltas received during an
active delta epoch.  Each log entry records (sequence number, byte
offset, delta bytes).  The log is bounded in size and self-inverse:
applying an entry a second time undoes it.</t>
        </dd>
        <dt>XOR-linear encoding:</dt>
        <dd>
          <t>An erasure encoding whose parity computation can be expressed as
a linear combination in GF(2) of source bytes -- equivalently, an
encoding where changing one source byte by delta D and applying
the same D to each parity projection at the projection-specific
offset preserves encode-correctness.  FFV2_ENCODING_MIRRORED (as
the degenerate identity-encoding case; every mirror is a
byte-identical replica), FFV2_ENCODING_MOJETTE_SYSTEMATIC (defined in
the Mojette Transform Encoding section of
<xref target="I-D.haynes-nfsv4-flexfiles-v2"/>; the underlying discrete
Radon transform is due to <xref target="MOJETTE-1995"/>), and
FFV2_ENCODING_XOR_PARITY are all XOR-linear AND systematic
(D_old readable from a single projection).
FFV2_ENCODING_MOJETTE_NON_SYSTEMATIC is XOR-linear but not
systematic: recovering D_old requires reading k projections and
inverting the transform.  FFV2_ENCODING_RS_VANDERMONDE is not
XOR-linear at all (it is linear over GF(2^8), which requires
per-coefficient multiplication that XOR alone does not express).
Only the XOR-linear AND systematic subset qualifies for
CHUNK_XOR_DELTA under this document.</t>
        </dd>
        <dt>XOR-affine checksum:</dt>
        <dd>
          <t>A checksum algorithm f such that for any two byte sequences X and
Y of equal length L, f(X XOR Y) = f(X) XOR f(Y) XOR f(0^L), where
0^L is the L-byte all-zero sequence.  Equivalently, the "raw"
form of f with init/xorout constants set to zero satisfies the
homomorphism f_raw(X XOR Y) = f_raw(X) XOR f_raw(Y).  Standard
CRC32 and CRC32C (as deployed with init and xorout both
0xFFFFFFFF) satisfy the affine identity above but do not
satisfy the stricter homomorphism f(X XOR Y) = f(X) XOR f(Y); the
affine constant f(0^L) is a function of length alone, so any two
implementations agreeing on the algorithm and the operand length
agree on the result.  All incremental formulas in this document
are expressed in terms that make the affine correction explicit
(see <xref target="sec-checksum"/>).  CHECKSUM_ALG_CRC32 and
CHECKSUM_ALG_CRC32C qualify.  Cryptographic hashes
(CHECKSUM_ALG_SHA256, CHECKSUM_ALG_SHA512, CHECKSUM_ALG_BLAKE3)
and CHECKSUM_ALG_FLETCHER4 (a modular-sum checksum) do not
qualify under any construction.</t>
        </dd>
      </dl>
    </section>
    <section anchor="sec-scope">
      <name>Encoding-Family Scope</name>
      <t>CHUNK_XOR_DELTA <bcp14>MAY</bcp14> be used against a chunk if and only if both of
the following hold, as determined by registry lookup against the
chunk's governing layout:</t>
      <ul spacing="normal">
        <li>
          <t>The layout's declared encoding (see the base specification's
<tt>ffv2_coding_type4</tt> and the Erasure Encoding Type Registry in
<xref target="I-D.haynes-nfsv4-flexfiles-v2"/>) has the flag
EC_ENC_FLAGS_XOR_DELTA_CAPABLE set (<xref target="sec-iana-encoding-flag"/>);
i.e., the encoding is XOR-linear as defined in
<xref target="sec-terminology"/>.</t>
        </li>
        <li>
          <t>The layout's <tt>ffv2m_checksum_algorithm</tt> has the flag
CHECKSUM_FLAGS_XOR_AFFINE set in the Checksum Algorithm
Registry defined in <xref target="I-D.haynes-nfsv4-flexfiles-v2"/>
(<xref target="sec-iana-checksum-flag"/>).</t>
        </li>
      </ul>
      <t>Capability is thus a derived, static property of the (encoding,
checksum-algorithm) pair the layout already carries; no additional
field is added to <tt>ffv2_mirror4</tt>.  A data server <bcp14>MUST</bcp14> reject
CHUNK_XOR_DELTA against a chunk whose governing layout does not
satisfy both conditions with NFS4ERR_NOTSUPP.  A client <bcp14>SHOULD</bcp14> perform
the registry lookup at layout-grant time and cache the result for the
layout's lifetime; the data server <bcp14>MUST</bcp14> perform the check on each
operation received (the data server cannot assume clients have
honored the <bcp14>SHOULD</bcp14>).</t>
      <t>Encodings that register EC_ENC_FLAGS_XOR_DELTA_CAPABLE <bcp14>MUST</bcp14> specify,
in the document defining the encoding, the mapping from
<tt>(chunk_offset, byte_offset_within_chunk)</tt> to the projection-local
offset at which a delta is XORed.  For
FFV2_ENCODING_MOJETTE_SYSTEMATIC this mapping is defined in the
Mojette Transform Encoding section of
<xref target="I-D.haynes-nfsv4-flexfiles-v2"/>.  For
FFV2_ENCODING_XOR_PARITY the mapping is trivial: for the parity
projection the delta is XORed at the same offset as it appears in
the source chunk.  For FFV2_ENCODING_MIRRORED the mapping is also
trivial: on each mirror the delta is XORed at the same offset as in
the source chunk.  FFV2_ENCODING_MOJETTE_NON_SYSTEMATIC is
XOR-linear but does not register the flag, because computing D_old
requires reading and inverse-transforming k projections, which is
the read-modify-write cost this document exists to eliminate.</t>
      <t>This document adds the EC_ENC_FLAGS_XOR_DELTA_CAPABLE flag to the
encoding registry.  Encodings that do not qualify
(FFV2_ENCODING_RS_VANDERMONDE; also FFV2_ENCODING_LINUX_MD_RAID for
its Q shard) <bcp14>MAY</bcp14> be extended by a separate document defining a
GF-multiply-per-parity variant of the delta-write operation; that
extension is out of scope here.</t>
    </section>
    <section anchor="sec-CHUNK_XOR_DELTA">
      <name>Operation 100: CHUNK_XOR_DELTA - Apply XOR Delta to Stored Chunk</name>
      <section anchor="operation-number-and-dispatch">
        <name>OPERATION NUMBER AND DISPATCH</name>
        <t>Following the pattern in
<xref target="I-D.haynes-nfsv4-flexfiles-v2"/> for CHUNK operations, this
document allocates operation number 100 and adds
corresponding arms to the argument and result unions.  All XDR
definitions in this document use the language of <xref target="RFC4506"/>.</t>
        <figure anchor="fig-OP_CHUNK_XOR_DELTA">
          <name>XDR for OP_CHUNK_XOR_DELTA</name>
          <sourcecode type="xdr"><![CDATA[
   /// const OP_CHUNK_XOR_DELTA = 100;
]]></sourcecode>
        </figure>
        <figure anchor="fig-nfs_argop4-arm">
          <name>nfs_argop4 amendment arm</name>
          <sourcecode type="xdr"><![CDATA[
   /// case OP_CHUNK_XOR_DELTA: CHUNK_XOR_DELTA4args opchunkxordelta;
]]></sourcecode>
        </figure>
        <figure anchor="fig-nfs_resop4-arm">
          <name>nfs_resop4 amendment arm</name>
          <sourcecode type="xdr"><![CDATA[
   /// case OP_CHUNK_XOR_DELTA: CHUNK_XOR_DELTA4res opchunkxordelta;
]]></sourcecode>
        </figure>
      </section>
      <section anchor="arguments">
        <name>ARGUMENTS</name>
        <figure anchor="fig-chunk_xor_delta_bounds">
          <name>Wire-size bounds</name>
          <sourcecode type="xdr"><![CDATA[
   /// const CHUNK_XOR_DELTA_MAX_ENTRIES  = 8;
   /// const CHUNK_XOR_DELTA_MAX_DELTA_LEN = 65536;
]]></sourcecode>
        </figure>
        <figure anchor="fig-chunk_xor_delta_entry4">
          <name>XDR for chunk_xor_delta_entry4</name>
          <sourcecode type="xdr"><![CDATA[
   /// struct chunk_xor_delta_entry4 {
   ///     uint32_t   cxde_seq;
   ///     uint32_t   cxde_bin_offset;
   ///     opaque     cxde_delta<CHUNK_XOR_DELTA_MAX_DELTA_LEN>;
   /// };
]]></sourcecode>
        </figure>
        <figure anchor="fig-CHUNK_XOR_DELTA4args">
          <name>XDR for CHUNK_XOR_DELTA4args</name>
          <sourcecode type="xdr"><![CDATA[
   /// const CHUNK_XOR_DELTA_FLAGS_EPOCH_OPEN     = 0x00000001;
   /// const CHUNK_XOR_DELTA_FLAGS_EPOCH_CONTINUE = 0x00000002;
   /// /* 0x00000004 reserved; formerly EPOCH_CLOSE.  See prose. */
   ///
   /// struct CHUNK_XOR_DELTA4args {
   ///     /* CURRENT_FH: file */
   ///     stateid4                  cxda_stateid;
   ///     offset4                   cxda_chunk_offset;
   ///     chunk_owner4              cxda_owner;
   ///     uint32_t                  cxda_flags;
   ///     chunk_guard4              cxda_guard;
   ///     chunk_guard4              cxda_predecessor_guard;
   ///     chunk_xor_delta_entry4
   ///         cxda_deltas<CHUNK_XOR_DELTA_MAX_ENTRIES>;
   /// };
]]></sourcecode>
        </figure>
      </section>
      <section anchor="results">
        <name>RESULTS</name>
        <figure anchor="fig-CHUNK_XOR_DELTA4resok">
          <name>XDR for CHUNK_XOR_DELTA4resok</name>
          <sourcecode type="xdr"><![CDATA[
   /// struct CHUNK_XOR_DELTA4resok {
   ///     uint32_t          cxdr_high_water_seq;
   ///     uint32_t          cxdr_log_bytes_used;
   ///     uint32_t          cxdr_log_bytes_available;
   /// };
]]></sourcecode>
        </figure>
        <figure anchor="fig-CHUNK_XOR_DELTA4res">
          <name>XDR for CHUNK_XOR_DELTA4res</name>
          <sourcecode type="xdr"><![CDATA[
   /// union CHUNK_XOR_DELTA4res switch (nfsstat4 cxdr_status) {
   ///     case NFS4_OK:
   ///         CHUNK_XOR_DELTA4resok    cxdr_resok4;
   ///     default:
   ///         void;
   /// };
]]></sourcecode>
        </figure>
      </section>
      <section anchor="description">
        <name>DESCRIPTION</name>
        <t>The CHUNK_XOR_DELTA operation applies one or more XOR deltas to a
single stored chunk on a data server.  It is issued by a client that
holds an active layout for the file, an active stateid, and a valid
chunk_owner4 for the chunk.  The data server <bcp14>MUST</bcp14> reject the operation
with NFS4ERR_NOTSUPP if the governing layout's encoding-plus-checksum
combination is not XOR-delta-capable (see <xref target="sec-scope"/>).</t>
        <t>The operation targets the chunk identified by <tt>cxda_chunk_offset</tt>.
<tt>cxda_flags</tt> indicates the role of the operation within a delta epoch:</t>
        <ul spacing="normal">
          <li>
            <t>CHUNK_XOR_DELTA_FLAGS_EPOCH_OPEN opens a new delta epoch.
<tt>cxda_guard</tt> carries a fresh, client-chosen guard value that
will become the epoch's identifier if the open succeeds;
<tt>cxda_predecessor_guard</tt> carries the guard value the client
believes is currently COMMITTED on this chunk (the value under
which D_old was read).  The data server <bcp14>MUST</bcp14>:  </t>
            <t>
(1) Reject with NFS4ERR_CHUNK_GUARDED if any other delta epoch
      (owned by any client) is currently open on this chunk.
  (2) Reject with NFS4ERR_CHUNK_GUARDED if the chunk's current
      COMMITTED guard does not equal <tt>cxda_predecessor_guard</tt> --
      the client's D_old is stale, and applying the delta would
      silently corrupt the parity.
  (3) On success, atomically install <tt>cxda_guard</tt> as the new
      PENDING guard and allocate a fresh delta log for the chunk
      keyed by (cxda_guard, cxda_owner).  </t>
            <t>
Retransmit handling: if the data server receives an EPOCH_OPEN whose
(cxda_guard, cxda_owner) exactly matches an already-open epoch it
owns, the data server <bcp14>MUST</bcp14> treat this as a retransmit of the original
request and return the original success response, not
NFS4ERR_CHUNK_GUARDED.  This preserves idempotent replay under
RPC retransmission (see <xref target="sec-concurrency"/>).</t>
          </li>
          <li>
            <t>CHUNK_XOR_DELTA_FLAGS_EPOCH_CONTINUE indicates the operation is part
of an already-open epoch.  The data server <bcp14>MUST</bcp14> verify that the
epoch identified by (cxda_guard, cxda_owner) is open and that
<tt>cxda_owner</tt> matches the owner of the open epoch; mismatch is
rejected with NFS4ERR_CHUNK_GUARDED.  <tt>cxda_predecessor_guard</tt> is
ignored on EPOCH_CONTINUE operations; the data server <bcp14>SHOULD</bcp14> verify
it is present in the wire message (per XDR) but <bcp14>MUST NOT</bcp14> use its
value to gate acceptance.  Exactly one of EPOCH_OPEN or
EPOCH_CONTINUE <bcp14>MUST</bcp14> be set; setting neither or both <bcp14>MUST</bcp14> be rejected
with NFS4ERR_INVAL.  Bit value 0x00000004 in cxda_flags is reserved
(formerly intended as an explicit EPOCH_CLOSE bit; epoch closure is
instead signalled by a subsequent CHUNK_FINALIZE, see
<xref target="sec-state-machine"/>).  Any other bit set in cxda_flags <bcp14>MUST</bcp14> be
rejected with NFS4ERR_INVAL to allow forward-compatible flag
additions.</t>
          </li>
        </ul>
        <t><tt>cxda_deltas</tt> is a bounded array of delta entries; the wire XDR bounds
the array at 8 entries per operation, and the sum of <tt>cxde_delta</tt>
lengths across all entries in a single operation <bcp14>MUST NOT</bcp14> exceed 65536
bytes.  A data server <bcp14>SHOULD</bcp14> reject an operation exceeding either
limit with NFS4ERR_INVAL rather than accepting a truncated set.</t>
        <t>Each entry carries a monotonic sequence number <tt>cxde_seq</tt>
(client-chosen, <bcp14>MUST</bcp14> strictly increase across all CHUNK_XOR_DELTA
operations
within an epoch), a byte offset <tt>cxde_bin_offset</tt> within the chunk,
and the delta bytes themselves.  The data server applies each entry by
XORing <tt>cxde_delta</tt> into stored-chunk bytes <tt>[cxde_bin_offset,
cxde_bin_offset + len(cxde_delta))</tt>.  Delta entries within a single
operation <bcp14>MAY</bcp14> be applied by the data server in any order, since XOR is
commutative and associative; the sequence number is recorded per entry
for later completeness checking at CHUNK_FINALIZE time.</t>
        <t>The data server <bcp14>MUST</bcp14> reject with NFS4ERR_INVAL any entry whose byte
range extends beyond the chunk's declared size, or whose
<tt>cxde_bin_offset</tt> overlaps another entry's byte range within the same
operation (to preserve deterministic replay across implementations).
Cross- operation range overlap within an epoch is permitted -- the
second delta effectively updates the running XOR state.</t>
      </section>
      <section anchor="return-values">
        <name>RETURN VALUES</name>
        <t>On success the data server returns:</t>
        <ul spacing="normal">
          <li>
            <t><tt>cxdr_high_water_seq</tt>: the highest sequence number the data server
has seen in this epoch, including all entries in the current
operation.</t>
          </li>
          <li>
            <t><tt>cxdr_log_bytes_used</tt>: the current delta-log occupancy for this
chunk-epoch, in bytes.</t>
          </li>
          <li>
            <t><tt>cxdr_log_bytes_available</tt>: the log's remaining capacity, in bytes.
When this reaches zero, subsequent CHUNK_XOR_DELTA operations in
this epoch <bcp14>MUST</bcp14> be rejected with NFS4ERR_DELTA_LOG_FULL and the
client <bcp14>MUST</bcp14> close the epoch with CHUNK_FINALIZE or CHUNK_ROLLBACK
before starting a new one.</t>
          </li>
        </ul>
        <t>On failure the data server returns the appropriate nfsstat4 code and no
partial application is visible via CHUNK_READ; see
<xref target="sec-state-machine"/> for the visibility rules.</t>
      </section>
    </section>
    <section anchor="sec-checksum">
      <name>Checksum-Homomorphism and Envelope Handling</name>
      <t>Each chunk carries an envelope that includes a checksum computed
over the chunk header followed by the chunk data, as defined in
<xref target="I-D.haynes-nfsv4-flexfiles-v2"/>.  A delta write modifies
both parts of that sequence:</t>
      <ul spacing="normal">
        <li>
          <t>The chunk_data portion changes by the applied delta (byte-range
XOR at <tt>cxde_bin_offset</tt>).</t>
        </li>
        <li>
          <t>The chunk_header portion changes because CHUNK_FINALIZE assigns a
new chunk generation identifier to the finalized chunk, updating
header fields.</t>
        </li>
      </ul>
      <t>The checksum algorithm registry defined by
<xref target="I-D.haynes-nfsv4-flexfiles-v2"/> <bcp14>MUST</bcp14> be extended with a
boolean capability flag CHECKSUM_FLAGS_XOR_AFFINE
(<xref target="sec-iana-checksum-flag"/>).  CHECKSUM_ALG_CRC32 and
CHECKSUM_ALG_CRC32C set this flag; CHECKSUM_ALG_FLETCHER4 and the
cryptographic-hash algorithms (CHECKSUM_ALG_SHA256,
CHECKSUM_ALG_SHA512, CHECKSUM_ALG_BLAKE3) do not.</t>
      <t>At CHUNK_FINALIZE time -- not per CHUNK_XOR_DELTA -- the data server
is responsible for computing the new envelope checksum.  For an
XOR-affine checksum (see the terminology definition in
<xref target="sec-terminology"/> for the exact identity), the data server <bcp14>MAY</bcp14>
compute the new checksum incrementally.  Let L be the length of the
covered envelope (the chunk header followed by the chunk data), let
X be the pre-delta envelope contents, and let Y be the post-delta
envelope contents zero-extended to length L in the same layout.
The affine identity gives:</t>
      <artwork><![CDATA[
f(Y) = f(X) XOR f(X XOR Y) XOR f(0^L)
]]></artwork>
      <t>where (X XOR Y) is the L-byte sequence containing zeros everywhere
X and Y agree, and the applied header + data delta bytes at their
canonical byte offsets everywhere they differ.  Equivalently, using
the zero-initialized "raw" form of f (per <xref target="sec-terminology"/>):</t>
      <artwork><![CDATA[
f_raw(Y) = f_raw(X) XOR f_raw(X XOR Y)
]]></artwork>
      <t>The <tt>f(0^L)</tt> term is a length-only constant that any two
conforming implementations agreeing on the algorithm and the
covered length compute identically.</t>
      <t>Full-recomputation is also permitted and is required for algorithms
that do not implement the incremental combine.  In either case the
client does not supply the envelope checksum; the data server is the
sole computing authority.  Implementations <bcp14>MUST NOT</bcp14> combine partial
checksums across differing covered lengths; the affine correction term
is a function of length and combining across differing lengths
silently yields the wrong value.</t>
      <t>At CHUNK_FINALIZE time the data server <bcp14>MUST</bcp14> include the newly computed
envelope checksum in its response, in the same field
<xref target="I-D.haynes-nfsv4-flexfiles-v2"/> uses for CHUNK_WRITE-driven
finalization.  A client that participated in the epoch <bcp14>SHOULD</bcp14> verify
this against its own predicted post-delta checksum computed from D_old
and the delta sequence (using the same affine identity above); a
client that performs this verification <bcp14>MUST</bcp14> treat a mismatch as chunk
corruption (the same treatment applied to a CHUNK_READ checksum
mismatch on COMMITTED data).  End-to-end verification is <bcp14>SHOULD</bcp14> rather
than <bcp14>MUST</bcp14> because the data server's checksum is itself protected by
the base checksum-registry semantics; the client-side check adds a
second, independent detector for lost-or-corrupt-delta cases that the
data server side alone cannot detect.</t>
    </section>
    <section anchor="sec-epochs">
      <name>Delta Epochs and Per-Chunk State</name>
      <t>A delta epoch is the unit of delta-write atomicity.  An epoch is
opened by a CHUNK_XOR_DELTA with EPOCH_OPEN set; extended by zero or
more CHUNK_XOR_DELTA operations with EPOCH_CONTINUE set; and closed
by a CHUNK_FINALIZE on the same chunk (or aborted by CHUNK_ROLLBACK).</t>
      <t>At most one epoch is open on a chunk at any time.  Attempting to
open a second epoch while one is already open on the same chunk <bcp14>MUST</bcp14>
be rejected with NFS4ERR_CHUNK_GUARDED, regardless of whether the
requesting client owns the open epoch: the tiebreaker is the CAS
value in <tt>cxda_guard</tt>.  This constraint is consistent with the base
specification's single-writer-per-chunk model.</t>
      <section anchor="delta-log-structure">
        <name>Delta Log Structure</name>
        <t>For each open epoch the data server maintains a delta log recording
every applied delta entry.  Each log record contains at minimum:</t>
        <ul spacing="normal">
          <li>
            <t>The delta entry's <tt>cxde_seq</tt></t>
          </li>
          <li>
            <t>The delta entry's <tt>cxde_bin_offset</tt> and length</t>
          </li>
          <li>
            <t>The delta bytes themselves</t>
          </li>
        </ul>
        <t>Because XOR entries are self-inverse (applying an entry a second time
undoes it), the same log serves as both the redo log (for restart
after data server crash mid-epoch) and the undo log (for
CHUNK_ROLLBACK).</t>
      </section>
      <section anchor="log-size-bound-and-overflow">
        <name>Log Size Bound and Overflow</name>
        <t>The data server <bcp14>MUST</bcp14> bound the per-chunk delta log to a fixed maximum
size, at minimum:</t>
        <artwork><![CDATA[
max(4096, min(chunk_size / 4, 65536)) bytes
]]></artwork>
        <t>A conforming data server <bcp14>MAY</bcp14> implement a larger bound.  The data
server reports current occupancy and remaining capacity in every
CHUNK_XOR_DELTA response (<tt>cxdr_log_bytes_used</tt>,
<tt>cxdr_log_bytes_available</tt>).</t>
        <t>When a client issues a CHUNK_XOR_DELTA whose acceptance would exceed
the bound, the data server <bcp14>MUST</bcp14> return NFS4ERR_DELTA_LOG_FULL and <bcp14>MUST
NOT</bcp14> apply any entry in that operation (all-or-nothing per operation).
The client's options on receiving NFS4ERR_DELTA_LOG_FULL are:</t>
        <ul spacing="normal">
          <li>
            <t>Close the current epoch with CHUNK_FINALIZE and open a new one
with the next CHUNK_XOR_DELTA (naturally amortizing the log across
epochs)</t>
          </li>
          <li>
            <t>Abort the current epoch with CHUNK_ROLLBACK and fall back to
CHUNK_WRITE for the remaining edits in this checkpoint interval</t>
          </li>
        </ul>
      </section>
      <section anchor="log-retention-and-garbage-collection">
        <name>Log Retention and Garbage Collection</name>
        <t>The delta log for an epoch is retained by the data server until the
epoch is either committed (CHUNK_FINALIZE followed by CHUNK_COMMIT) or
aborted (CHUNK_ROLLBACK).  On commit, the log is discarded once the
data server has transitioned the chunk to COMMITTED with the new
generation; on abort, the log is discarded immediately after the data
server has XORed every log entry back into the chunk (undo).</t>
        <t>The chunk-generation retention rule defined in
<xref target="I-D.haynes-nfsv4-flexfiles-v2"/> -- that a data server retains the
last COMMITTED generation of each chunk until superseded by a newer
COMMIT -- applies unchanged.  The delta log is auxiliary state that
lives alongside the PENDING/FINALIZED generation being built up, not
a replacement for that state.</t>
      </section>
    </section>
    <section anchor="sec-concurrency">
      <name>Concurrency Semantics</name>
      <t>Within a single open epoch the delta log establishes a total order
over applied entries by <tt>cxde_seq</tt>, but the effect of applied
entries at any point in the epoch is order-independent (XOR is
commutative).  The sequence number exists to:</t>
      <ul spacing="normal">
        <li>
          <t>Detect gaps at CHUNK_FINALIZE time (the data server asserts
contiguity from 1 to <tt>cxdr_high_water_seq</tt>)</t>
        </li>
        <li>
          <t>Support idempotent replay across RPC retransmissions (a data server
receiving a duplicate <tt>cxde_seq</tt> <bcp14>MUST NOT</bcp14> re-apply the delta;
it <bcp14>MUST</bcp14> return the same result as the original response)</t>
        </li>
      </ul>
      <t>The data server is NOT required to maintain per-byte or per-bin lock
state.  The single-writer-per-epoch invariant (enforced by the CAS on
EPOCH_OPEN) is sufficient to prevent conflicting concurrent writes.
Cross-client concurrent edits to disjoint byte ranges of the same
chunk are NOT supported in this specification; the second client
receives NFS4ERR_CHUNK_GUARDED on its EPOCH_OPEN and <bcp14>MUST</bcp14> fall back to
CHUNK_WRITE.  Future extensions <bcp14>MAY</bcp14> relax this constraint by
introducing per-bin versioning; that machinery is not required for the
HPC checkpoint workload, whose block-alignment discipline (see the Use
Cases section of <xref target="I-D.haynes-nfsv4-flexfiles-v2"/>) already gives
stable per-chunk ownership within a checkpoint interval.</t>
      <section anchor="sec-split-open">
        <name>Split-Open Recovery</name>
        <t>Because a client opens the epoch independently against each of the
chunk's k+m projection data servers, two clients A and B racing for the
same chunk can produce a split-open outcome: A wins EPOCH_OPEN on
some projections, B wins on others.  Neither can then close its
epoch on the full projection set, and both sets of deltas remain
in invisible PENDING state indefinitely -- blocking not only
subsequent writes to that chunk but also repair (see <xref target="sec-repair"/>).</t>
        <t>To prevent this liveness hazard: on receiving NFS4ERR_CHUNK_GUARDED
from ANY projection's EPOCH_OPEN, a client <bcp14>MUST</bcp14> issue CHUNK_ROLLBACK
against every projection where its own EPOCH_OPEN had succeeded,
before falling back to CHUNK_WRITE.  A client <bcp14>MUST NOT</bcp14> abandon
partially-open epochs.  The rollback is CAS-guarded by the
client's own <tt>cxda_guard</tt> value, so it cannot disturb the winner's
epoch state on projections the winner controls.  A client that
crashes mid-recovery relies on lease-expiry rollback per
<xref target="sec-repair"/>.</t>
      </section>
      <section anchor="sec-retransmit">
        <name>Retransmission</name>
        <t>Idempotency across RPC retransmission is achieved by the sequence
number + CAS-guard pair.  A client retrying a CHUNK_XOR_DELTA after
network loss re-uses the same (cxda_guard, cxda_owner, cxde_seq)
tuple; the data server deduplicates using the recorded sequence number
and returns the same response.  Retransmit handling for EPOCH_OPEN
specifically is normatively described in the CHUNK_XOR_DELTA
DESCRIPTION section: a duplicate EPOCH_OPEN whose (cxda_guard,
cxda_owner) matches an already-open epoch <bcp14>MUST</bcp14> be served as a
retransmit, not rejected with NFS4ERR_CHUNK_GUARDED.</t>
      </section>
    </section>
    <section anchor="sec-state-machine">
      <name>Interaction with the Chunk State Machine</name>
      <t>The Chunk State Machine section of
<xref target="I-D.haynes-nfsv4-flexfiles-v2"/> defines the chunk state
machine with three main states -- PENDING, FINALIZED, COMMITTED --
and the operations that transition between them.  This document adds
no new states and no new transitions.  It defines CHUNK_XOR_DELTA as
a third producer of PENDING generations, alongside CHUNK_WRITE and
CHUNK_WRITE_REPAIR.</t>
      <section anchor="visibility-rules">
        <name>Visibility Rules</name>
        <t>The rule from <xref target="I-D.haynes-nfsv4-flexfiles-v2"/> that
CHUNK_READ serves the most recent COMMITTED generation applies
without modification.  In particular:</t>
        <ul spacing="normal">
          <li>
            <t>Deltas applied during an open epoch are NOT visible to CHUNK_READ
until the epoch has been closed by CHUNK_FINALIZE + CHUNK_COMMIT.</t>
          </li>
          <li>
            <t>During an open epoch the data server retains the prior COMMITTED chunk
contents (already required by
<xref target="I-D.haynes-nfsv4-flexfiles-v2"/> for concurrent-reader
consistency).  CHUNK_READ served from that state is unchanged by
any number of applied deltas.</t>
          </li>
        </ul>
      </section>
      <section anchor="chunkfinalize-semantics-for-a-delta-epoch">
        <name>CHUNK_FINALIZE Semantics for a Delta Epoch</name>
        <t>When the client issues CHUNK_FINALIZE against a chunk that has an
open delta epoch, the data server <bcp14>MUST</bcp14>:</t>
        <ul spacing="normal">
          <li>
            <t>Verify that the recorded delta-log sequence numbers form a
contiguous range from 1 to some N (no gaps).  If gaps are present,
reject with NFS4ERR_DELTA_INCOMPLETE and DO NOT discard the log;
the client <bcp14>MAY</bcp14> retry the missing deltas and re-attempt
CHUNK_FINALIZE (see <xref target="sec-gap-recovery"/>).</t>
          </li>
          <li>
            <t>Compute the new envelope checksum per <xref target="sec-checksum"/></t>
          </li>
          <li>
            <t>Assign the new chunk generation identifier</t>
          </li>
          <li>
            <t>Transition the chunk to FINALIZED</t>
          </li>
          <li>
            <t>Retain the delta log until CHUNK_COMMIT completes; on
CHUNK_ROLLBACK, undo the deltas by re-applying them (XOR
self-inverse) and discard the log.</t>
          </li>
        </ul>
        <section anchor="sec-gap-recovery">
          <name>Gap Recovery on NFS4ERR_DELTA_INCOMPLETE</name>
          <t>NFS4ERR_DELTA_INCOMPLETE reports that a gap exists, not which
sequence numbers are missing: the CHUNK_FINALIZE result union defined
in <xref target="I-D.haynes-nfsv4-flexfiles-v2"/> carries no missing-seq array, and
this document does not add one.  Recovery is driven from the client's
own record instead, which is sufficient because the set of deltas the
client has issued without a success response is a superset of the set
the data server is missing.  The client <bcp14>MUST</bcp14> implement gap recovery as
follows:</t>
          <ol spacing="normal" type="1"><li>
              <t>The client <bcp14>MUST</bcp14> retain a per-epoch "outstanding" set: every
<tt>(cxda_guard, cxde_seq)</tt> for which it has issued
CHUNK_XOR_DELTA but not yet received a success response.</t>
            </li>
            <li>
              <t>On NFS4ERR_DELTA_INCOMPLETE from CHUNK_FINALIZE, the client
<bcp14>MUST</bcp14> re-issue every <tt>cxde_seq</tt> still in its outstanding set as
an EPOCH_CONTINUE operation.  Duplicates already seen by the
data server are deduplicated per <xref target="sec-concurrency"/> (return the
original response with no re-apply); genuine gaps are filled.</t>
            </li>
            <li>
              <t>Once the outstanding set is empty, the client <bcp14>MUST</bcp14> re-issue
CHUNK_FINALIZE.  If the data server still returns
NFS4ERR_DELTA_INCOMPLETE, the client <bcp14>MUST</bcp14> issue CHUNK_ROLLBACK
and restart the edit sequence as CHUNK_WRITE operations under
a fresh epoch (the epoch is unrecoverable).</t>
            </li>
          </ol>
          <t>Replay converges on the same state that an enumerated missing-seq
array would reach.  A delta that never arrived is filled by the
replay; one that arrived but whose response was lost is deduplicated
per <xref target="sec-retransmit"/> and not applied twice.  A delta the client saw
acknowledged but the data server no longer holds is in neither set,
and is why step 3 ends in CHUNK_ROLLBACK: no enumeration recovers a
discarded log.</t>
          <t>The cost of driving recovery this way is O(outstanding-set-size)
worst-case wire traffic, against O(1) for an enumerated array, on a
path taken only after loss.  In practice the outstanding set is
bounded by the delta-log capacity divided by the mean delta size,
typically low hundreds of entries.  Carrying the array would put
delta-epoch state in a result union returned by every CHUNK_FINALIZE,
including the ones that finalize ordinary CHUNK_WRITE generations, so
this document leaves the base specification's commit path untouched.</t>
          <t>The CHUNK_COMMIT semantics of
<xref target="I-D.haynes-nfsv4-flexfiles-v2"/> apply unchanged: the
FINALIZED generation becomes COMMITTED atomically.</t>
        </section>
      </section>
      <section anchor="chunkrollback-semantics-for-a-delta-epoch">
        <name>CHUNK_ROLLBACK Semantics for a Delta Epoch</name>
        <t>CHUNK_ROLLBACK against a chunk with an open delta epoch causes the
data server to re-apply every log entry (XORing each into the chunk a
second time), restoring the pre-epoch bytes.  The log is then
discarded and the chunk_guard4 CAS state returns to what it was at
EPOCH_OPEN.</t>
      </section>
    </section>
    <section anchor="sec-repair">
      <name>Repair-Path Interaction</name>
      <t>The repair protocol defined in
<xref target="I-D.haynes-nfsv4-flexfiles-v2"/> coordinates reconstruction
of missing or damaged chunks from surviving projections.  This
document adds one new rule for the repair coordinator:</t>
      <ul spacing="normal">
        <li>
          <t>Before reconstructing a chunk from the majority of surviving
projections, the repair coordinator <bcp14>MUST</bcp14> query each surviving data
server for the presence of an open delta epoch on that chunk.</t>
        </li>
        <li>
          <t>If any surviving data server reports an open delta epoch, the repair
coordinator <bcp14>MUST NOT</bcp14> reconstruct from the majority.  Instead, it
<bcp14>MUST</bcp14> wait for the epoch to close (CHUNK_FINALIZE or
CHUNK_ROLLBACK) before beginning reconstruction.</t>
        </li>
        <li>
          <t>If the epoch's owner lease has expired, OR the epoch's owning
stateid has been revoked (per <xref target="I-D.haynes-nfsv4-flexfiles-v2"/>),
the repair coordinator <bcp14>MUST</bcp14> drive CHUNK_ROLLBACK on each
participating data server (using the CAS guard from the epoch's OPEN
record) and then proceed with base-specification repair semantics on
the resulting pre-epoch generation.  Both triggers are wall-clock
bounded -- lease-expiry by the server's lease-time attribute and
stateid revocation by the base specification's stateid-revocation
paths -- so repair cannot stall indefinitely on a wedged writer.</t>
        </li>
      </ul>
      <t>Rationale: if the epoch has partially applied to some but not all
projections, reconstructing from the majority would silently commit
the "unchanged" bytes as authoritative and lose any deltas already
applied.  Waiting for epoch closure (or explicitly rolling it back)
prevents this laundering path.</t>
      <t>Steady-state repair -- against chunks with no open delta epoch --
is unchanged from <xref target="I-D.haynes-nfsv4-flexfiles-v2"/>.  The
delta-log retention rule guarantees that at any moment either the
pre-epoch generation is intact on every participating data server (open
epoch case) or a common COMMITTED generation is present on the
surviving data servers (steady-state case).</t>
    </section>
    <section anchor="sec-revocation">
      <name>Layout Revocation and Stateid Semantics</name>
      <t>CB_LAYOUTRECALL is defined in <xref target="RFC5661"/>; the stateid-revocation
paths (TRUST_STATEID, REVOKE_STATEID, BULK_REVOKE_STATEID) are
defined in <xref target="I-D.haynes-nfsv4-flexfiles-v2"/>.  A delta
epoch is bound to the client's active layout and stateid; when either
is revoked mid-epoch, the data server <bcp14>MUST</bcp14>:</t>
      <ul spacing="normal">
        <li>
          <t>Discard any in-flight CHUNK_XOR_DELTA operations for that
(stateid, chunk) pair</t>
        </li>
        <li>
          <t>Apply CHUNK_ROLLBACK semantics (<xref target="sec-state-machine"/>) to close the
epoch, restoring the pre-epoch generation</t>
        </li>
        <li>
          <t>Discard the delta log</t>
        </li>
      </ul>
      <t>A client that receives a revocation notification (via CB_LAYOUTRECALL
or an explicit stateid revocation) <bcp14>MUST</bcp14> assume any epoch it had open
against the affected file has been rolled back and <bcp14>MUST NOT</bcp14> issue
CHUNK_XOR_DELTA against that stateid.  The client <bcp14>MAY</bcp14> reissue the
edit sequence as CHUNK_WRITE operations under a fresh layout and
stateid; the write-retry semantics of
<xref target="I-D.haynes-nfsv4-flexfiles-v2"/> apply.</t>
      <t>This resolves the "layout recalled mid-delta" failure mode without
introducing a new commit protocol: the revocation paths of <xref target="RFC5661"/>
and <xref target="I-D.haynes-nfsv4-flexfiles-v2"/> already tear
down the client's authority to write, and the data server's duty on
revocation is to preserve the last-committed state -- which is
exactly what pre-epoch rollback delivers.</t>
    </section>
    <section anchor="sec-security">
      <name>Security Considerations</name>
      <section anchor="authorization-equivalence">
        <name>Authorization Equivalence</name>
        <t>Any principal authorized to issue CHUNK_WRITE against a chunk is,
by construction, authorized to write any byte sequence into that
chunk.  CHUNK_XOR_DELTA is strictly less expressive than CHUNK_WRITE
(deltas can only modify existing bytes, not overwrite arbitrarily),
so it introduces no new authorization capability.  A malicious
authorized writer can already corrupt the chunk via CHUNK_WRITE; the
delta-write path is not a new attack surface for that principal.</t>
        <t>The novel threat model to consider is <em>partial-application
laundering</em>: a malicious writer applies deltas to some but not all
projections, hoping to induce repair to lock in incorrect bytes.
This threat is closed by the repair-path rule in <xref target="sec-repair"/>:
repair <bcp14>MUST NOT</bcp14> reconstruct from the majority while an epoch is
open.  The epoch-open state on any surviving projection is the
signal that partial application may have occurred; repair either
waits for closure or explicitly rolls back.</t>
      </section>
      <section anchor="transport-security">
        <name>Transport Security</name>
        <t>CHUNK_XOR_DELTA <bcp14>MUST</bcp14> be issued over a transport that provides
integrity protection at the RPC layer (for example RPCSEC_GSS with
krb5i <xref target="RFC5661"/>, or an equivalent mechanism).  This requirement
binds regardless of the transport-security posture of any other
flexible file v2 layout data-server operation: a delta write applied
to a projection whose integrity is not authenticated is
indistinguishable at the data server from a forged write and cannot be
reconciled by any downstream mechanism defined in this document.  The
wire XDR carries no confidentiality of its own and its integrity is
not self-authenticating.</t>
      </section>
      <section anchor="denial-of-service-via-open-epochs">
        <name>Denial of Service via Open Epochs</name>
        <t>Per <xref target="sec-epochs"/> the data server bounds the delta log for each open
epoch, but the aggregate number of concurrently open epochs held by a
single client across chunks and across files is not bounded by
protocol.  A misbehaving or wedged writer that opens many epochs
without finalizing can:</t>
        <ul spacing="normal">
          <li>
            <t>Accumulate per-epoch log state on each affected data server, consuming
bounded but non-trivial data server memory</t>
          </li>
          <li>
            <t>Stall repair on every affected chunk, since <xref target="sec-repair"/> requires
the repair coordinator to wait for open epochs to close before
reconstructing</t>
          </li>
        </ul>
        <t>A data server <bcp14>SHOULD</bcp14> impose an implementation-defined aggregate cap on
the number of concurrent open epochs per client stateid.  On hitting
the cap, further EPOCH_OPEN attempts <bcp14>MUST</bcp14> be rejected with
NFS4ERR_DELAY <xref target="RFC5661"/> (retriable at the RPC layer without
protocol-level state change; more idiomatic than NFS4ERR_RESOURCE for
pNFS layout-scoped exhaustion, which is not session-owning). A client
that receives NFS4ERR_DELAY on EPOCH_OPEN <bcp14>MUST NOT</bcp14> retry the same
EPOCH_OPEN immediately; it <bcp14>SHOULD</bcp14> first close (via CHUNK_FINALIZE or
CHUNK_ROLLBACK) at least one of its currently open epochs, then <bcp14>MAY</bcp14>
retry.  Retrying without closing an epoch is protocol-legal but will
typically fail again with NFS4ERR_DELAY.</t>
        <t>The metadata server's remedy against an unresponsive-writer scenario
is layout recall or stateid revocation (<xref target="sec-revocation"/>), which
forces data server rollback of all epochs bound to the revoked
stateid.</t>
      </section>
      <section anchor="retransmit-mismatch">
        <name>Retransmit Mismatch</name>
        <t><xref target="sec-concurrency"/> specifies that a data server receiving a duplicate
<tt>cxde_seq</tt> in the same epoch <bcp14>MUST NOT</bcp14> re-apply the delta and <bcp14>MUST</bcp14>
return the same result as the original response.  If the retransmit
carries the same (cxda_guard, cxda_owner, cxde_seq) but differs from
the original in <tt>cxde_bin_offset</tt> or <tt>cxde_delta</tt> bytes, this
indicates either a client bug or a wire-level tamper past the
integrity protection in force.  The data server <bcp14>MUST</bcp14> reject such a
mismatch with NFS4ERR_INVAL and <bcp14>SHOULD</bcp14> log the event for
administrative review.</t>
      </section>
      <section anchor="log-capacity-disclosure">
        <name>Log-Capacity Disclosure</name>
        <t>The response fields <tt>cxdr_log_bytes_used</tt> and
<tt>cxdr_log_bytes_available</tt> disclose the data server's per-chunk
delta-log occupancy to the client.  This disclosure is intentional --
the client needs the signal to decide whether to close-and-reopen an
epoch or fall back to CHUNK_WRITE.  The information is limited to
principals already authorized to issue CHUNK_XOR_DELTA against the
chunk in question; no additional confidentiality boundary is crossed.</t>
      </section>
      <section anchor="optional-ownership-restriction">
        <name>Optional Ownership Restriction</name>
        <t>Deployments that wish to further narrow the writer set for a file <bcp14>MAY</bcp14>
set the layout flag FFV2_FLAGS_DELTA_OWNER_ONLY (defined here,
registered against <tt>ffv2_layout_flags4</tt>).  When set on a layout, data
servers <bcp14>MUST</bcp14> reject CHUNK_XOR_DELTA whose <tt>cxda_owner</tt> does not match
the <tt>chunk_owner4</tt> of the current COMMITTED generation of the target
chunk.  This restricts delta epochs to the writer who last wrote the
chunk, which is the natural semantics for the HPC checkpoint workload
(each rank owns its stride).</t>
        <t>This flag is optional; deployments that do not need per-writer
narrowing (single-writer files, files with a well-known writer set)
<bcp14>MAY</bcp14> leave it clear.</t>
      </section>
      <section anchor="cryptographic-checksum-deployments">
        <name>Cryptographic-Checksum Deployments</name>
        <t>Deployments that select a cryptographic checksum algorithm
(SHA-family, BLAKE-family) for <tt>ffv2m_checksum_algorithm</tt> cannot use
CHUNK_XOR_DELTA (see <xref target="sec-scope"/>).  Such deployments have chosen
adversarial-resistance for chunk envelopes at the cost of some
performance optimizations; this is a coherent, spec-compliant
posture and does not require workaround.  The extension defined here
does not weaken cryptographic-checksum deployments in any way, as
the capability conjunction structurally excludes them.</t>
      </section>
    </section>
    <section anchor="sec-iana">
      <name>IANA Considerations</name>
      <t>Following the pattern established by the flexible file v2 layout family
(<xref target="I-D.haynes-nfsv4-flexfiles-v2"/>) that operation numbers
in the NFSv4.2 opnum space are assigned by publication of the
specifying document, operation number 100 is assigned to
CHUNK_XOR_DELTA by publication of this document.  No IANA action
is requested for the operation number.  100 was the next value
available above the range <xref target="I-D.haynes-nfsv4-flexfiles-v2"/> and the
proxy server document allocate.</t>
      <t>Opcode values <bcp14>MUST NOT</bcp14> overlap across family documents; a future
extension <bcp14>MUST</bcp14> take the next available value, and <bcp14>MUST NOT</bcp14> re-use any
value the family has already allocated.</t>
      <t>This document requests the following IANA actions:</t>
      <section anchor="sec-iana-encoding-flag">
        <name>Encoding Registry: XOR-Delta-Capable Column</name>
        <t>Add a new column named "XOR-Delta-Capable" (boolean) to the
"Flexible File Version 2 Layout Type Erasure Coding Type Registry"
defined in <xref target="I-D.haynes-nfsv4-flexfiles-v2"/>.
The column is called EC_ENC_FLAGS_XOR_DELTA_CAPABLE in prose
references.</t>
        <t>Set for encodings whose parity is expressible as an XOR combination
of source bytes AND whose data-shard bytes are directly readable
from a single projection (systematic property).  Clear otherwise.
Initial assignments:</t>
        <ul spacing="normal">
          <li>
            <t>FFV2_ENCODING_MIRRORED: SET (identity encoding; delta at
<tt>(chunk_offset, bin_offset)</tt> applied to every mirror at the same
offset converges to the correct state)</t>
          </li>
          <li>
            <t>FFV2_ENCODING_MOJETTE_SYSTEMATIC: SET</t>
          </li>
          <li>
            <t>FFV2_ENCODING_MOJETTE_NON_SYSTEMATIC: CLEAR (XOR-linear but
non-systematic; recovering D_old requires k projection reads and
an inverse transform, defeating the delta-write purpose.
Support for non-systematic XOR-linear encodings is deferred to
a follow-up specification.)</t>
          </li>
          <li>
            <t>FFV2_ENCODING_XOR_PARITY: SET</t>
          </li>
          <li>
            <t>FFV2_ENCODING_LINUX_MD_RAID: CLEAR (Q shard is GF-multiplicative;
P shard alone is not sufficient to support delta writes on the
full parity set)</t>
          </li>
          <li>
            <t>FFV2_ENCODING_RS_VANDERMONDE: CLEAR</t>
          </li>
          <li>
            <t>FFV2_ENCODING_PASSTHROUGH: not applicable -- PASSTHROUGH layouts
do not carry the chunk envelope this document operates on;
CHUNK_XOR_DELTA is undefined for PASSTHROUGH layouts and a data
server <bcp14>MUST</bcp14> return NFS4ERR_NOTSUPP if received against one.  The
flag value is nominally CLEAR but the operation itself is
structurally inapplicable.</t>
          </li>
        </ul>
      </section>
      <section anchor="sec-iana-checksum-flag">
        <name>Checksum Registry: XOR-Affine Column</name>
        <t>Add a new column named "XOR-Affine" (boolean) to the
"Flexible File Version 2 Layout Type Checksum Algorithm Registry"
defined in <xref target="I-D.haynes-nfsv4-flexfiles-v2"/>.  The column is
called CHECKSUM_FLAGS_XOR_AFFINE in prose references.</t>
        <t>Set for algorithms that satisfy the XOR-affine identity defined
in <xref target="sec-terminology"/>; clear otherwise.  Initial assignments:</t>
        <ul spacing="normal">
          <li>
            <t>CHECKSUM_ALG_NONE: SET.  The value is SET, not "not
applicable", so that the eligibility boolean below is a
well-defined AND with no per-algorithm exceptions.  The
semantic justification is that XOR-affinity is a property of
the checksum function; there is no checksum function to fail
the property when CHECKSUM_ALG_NONE is in use, so the property
holds vacuously.  The data-server-side checksum-recompute path in
<xref target="sec-checksum"/> is a no-op when CHECKSUM_ALG_NONE is
configured.</t>
          </li>
          <li>
            <t>CHECKSUM_ALG_CRC32: SET</t>
          </li>
          <li>
            <t>CHECKSUM_ALG_CRC32C: SET</t>
          </li>
          <li>
            <t>CHECKSUM_ALG_FLETCHER4: CLEAR (modular sum; not XOR-linear)</t>
          </li>
          <li>
            <t>CHECKSUM_ALG_SHA256: CLEAR (cryptographic hash)</t>
          </li>
          <li>
            <t>CHECKSUM_ALG_SHA512: CLEAR (cryptographic hash)</t>
          </li>
          <li>
            <t>CHECKSUM_ALG_BLAKE3: CLEAR (cryptographic hash)</t>
          </li>
        </ul>
        <t>A configuration is delta-write-eligible iff both the encoding's
<tt>EC_ENC_FLAGS_XOR_DELTA_CAPABLE</tt> and the checksum's
<tt>CHECKSUM_FLAGS_XOR_AFFINE</tt> are SET.  This is a plain boolean
conjunction with no per-algorithm exceptions; a registry
consumer implementing the conjunction directly derives the
correct answer for every entry, including CHECKSUM_ALG_NONE
(SET AND SET = SET).</t>
      </section>
      <section anchor="new-error-codes">
        <name>New Error Codes</name>
        <t>Following the pattern established by <xref target="I-D.haynes-nfsv4-flexfiles-v2"/>
that nfsstat4 codes scoped to the flexible file v2 layout protocol
family are assigned by publication of the specifying document (no IANA
nfsstat4 registry exists), this document assigns the codes in
<xref target="fig-delta-errors-xdr"/>.</t>
        <figure anchor="fig-delta-errors-xdr">
          <name>XDR for the delta-write error codes</name>
          <sourcecode type="xdr"><![CDATA[
   ///
   /// /* Delta-write error constants; added to nfsstat4 enum */
   ///
   /// const NFS4ERR_DELTA_INCOMPLETE = 10110;
   /// const NFS4ERR_DELTA_LOG_FULL   = 10111;
   ///
]]></sourcecode>
        </figure>
        <dl>
          <dt>NFS4ERR_DELTA_INCOMPLETE:</dt>
          <dd>
            <t>returned by CHUNK_FINALIZE when the recorded delta-log sequence
numbers do not form a contiguous range from 1 to N.</t>
          </dd>
          <dt>NFS4ERR_DELTA_LOG_FULL:</dt>
          <dd>
            <t>returned by CHUNK_XOR_DELTA when the per-chunk delta log would
overflow.  The client <bcp14>SHOULD</bcp14> close the current epoch and open a new
one.</t>
          </dd>
        </dl>
        <t>No IANA action is requested for these codes.  The values 10110 and
10111 are chosen to sit above the base specification's cluster (10100 =
NFS4ERR_CHUNK_GUARDED and neighbors) with a gap for future
CHUNK operation codes.</t>
      </section>
      <section anchor="new-layout-flag">
        <name>New Layout Flag</name>
        <t>Following the same pattern (no IANA registry for flexible file v2 layout
flags), this document assigns:</t>
        <ul spacing="normal">
          <li>
            <t>FFV2_FLAGS_DELTA_OWNER_ONLY = 0x00000100: restricts
CHUNK_XOR_DELTA epochs to the current chunk_owner4 of the target
chunk.</t>
          </li>
        </ul>
        <t>The bit value 0x00000100 is chosen to sit clear of
FFV2_FLAGS_ONLY_ONE_WRITER (0x00000010, base specification) and the
low-order bits inherited from ff_flags4.  No IANA action is
requested.</t>
      </section>
    </section>
  </middle>
  <back>
    <references anchor="sec-combined-references">
      <name>References</name>
      <references anchor="sec-normative-references">
        <name>Normative References</name>
        <reference anchor="RFC4506">
          <front>
            <title>XDR: External Data Representation Standard</title>
            <author fullname="M. Eisler" initials="M." role="editor" surname="Eisler"/>
            <date month="May" year="2006"/>
            <abstract>
              <t>This document describes the External Data Representation Standard (XDR) protocol as it is currently deployed and accepted. This document obsoletes RFC 1832. [STANDARDS-TRACK]</t>
            </abstract>
          </front>
          <seriesInfo name="STD" value="67"/>
          <seriesInfo name="RFC" value="4506"/>
          <seriesInfo name="DOI" value="10.17487/RFC4506"/>
        </reference>
        <reference anchor="RFC5661">
          <front>
            <title>Network File System (NFS) Version 4 Minor Version 1 Protocol</title>
            <author fullname="S. Shepler" initials="S." role="editor" surname="Shepler"/>
            <author fullname="M. Eisler" initials="M." role="editor" surname="Eisler"/>
            <author fullname="D. Noveck" initials="D." role="editor" surname="Noveck"/>
            <date month="January" year="2010"/>
            <abstract>
              <t>This document describes the Network File System (NFS) version 4 minor version 1, including features retained from the base protocol (NFS version 4 minor version 0, which is specified in RFC 3530) and protocol extensions made subsequently. Major extensions introduced in NFS version 4 minor version 1 include Sessions, Directory Delegations, and parallel NFS (pNFS). NFS version 4 minor version 1 has no dependencies on NFS version 4 minor version 0, and it is considered a separate protocol. Thus, this document neither updates nor obsoletes RFC 3530. NFS minor version 1 is deemed superior to NFS minor version 0 with no loss of functionality, and its use is preferred over version 0. Both NFS minor versions 0 and 1 can be used simultaneously on the same network, between the same client and server. [STANDARDS-TRACK]</t>
            </abstract>
          </front>
          <seriesInfo name="RFC" value="5661"/>
          <seriesInfo name="DOI" value="10.17487/RFC5661"/>
        </reference>
        <reference anchor="I-D.haynes-nfsv4-flexfiles-v2">
          <front>
            <title>Parallel NFS (pNFS) Flexible File Layout Version 2</title>
            <author fullname="Thomas Haynes" initials="T." surname="Haynes">
              <organization>Hammerspace</organization>
            </author>
            <date day="24" month="July" year="2026"/>
            <abstract>
              <t>   Parallel NFS (pNFS) allows a separation between the metadata (onto a
   metadata server) and data (onto a storage device) for a file.  The
   Flexible File Version 2 Layout Type is defined in this document as an
   extension to pNFS that allows the use of storage devices that require
   only a limited degree of interaction with the metadata server and use
   already-existing protocols.  Data protection is also added to provide
   integrity.  Both Client-side mirroring and the erasure coding
   algorithms are used for data protection.

              </t>
            </abstract>
          </front>
          <seriesInfo name="Internet-Draft" value="draft-haynes-nfsv4-flexfiles-v2-07"/>
        </reference>
        <reference anchor="RFC2119">
          <front>
            <title>Key words for use in RFCs to Indicate Requirement Levels</title>
            <author fullname="S. Bradner" initials="S." surname="Bradner"/>
            <date month="March" year="1997"/>
            <abstract>
              <t>In many standards track documents several words are used to signify the requirements in the specification. These words are often capitalized. This document defines these words as they should be interpreted in IETF documents. This document specifies an Internet Best Current Practices for the Internet Community, and requests discussion and suggestions for improvements.</t>
            </abstract>
          </front>
          <seriesInfo name="BCP" value="14"/>
          <seriesInfo name="RFC" value="2119"/>
          <seriesInfo name="DOI" value="10.17487/RFC2119"/>
        </reference>
        <reference anchor="RFC8174">
          <front>
            <title>Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words</title>
            <author fullname="B. Leiba" initials="B." surname="Leiba"/>
            <date month="May" year="2017"/>
            <abstract>
              <t>RFC 2119 specifies common key words that may be used in protocol specifications. This document aims to reduce the ambiguity by clarifying that only UPPERCASE usage of the key words have the defined special meanings.</t>
            </abstract>
          </front>
          <seriesInfo name="BCP" value="14"/>
          <seriesInfo name="RFC" value="8174"/>
          <seriesInfo name="DOI" value="10.17487/RFC8174"/>
        </reference>
      </references>
      <references anchor="sec-informative-references">
        <name>Informative References</name>
        <reference anchor="MOJETTE-1995">
          <front>
            <title>The Mojette Transform: Application to Image Coding</title>
            <author initials="J-P." surname="Guédon" fullname="J-P. Guédon" asciiInitials="J-P." asciiSurname="Guedon" asciiFullname="J-P. Guedon">
              <organization/>
            </author>
            <author initials="N." surname="Normand" fullname="N. Normand">
              <organization/>
            </author>
            <date year="1995"/>
          </front>
        </reference>
      </references>
    </references>
    <?line 1084?>

<section anchor="sec-example-hpc">
      <name>Worked Example: HPC Checkpoint at 1000 Ranks</name>
      <t>This appendix walks through the wire-traffic and per-server work
implications of CHUNK_XOR_DELTA versus the base CHUNK_WRITE path for
a canonical HPC checkpoint workload.</t>
      <section anchor="scenario">
        <name>Scenario</name>
        <ul spacing="normal">
          <li>
            <t>A single file, 1 TB in size, protected by
FFV2_ENCODING_MOJETTE_SYSTEMATIC at k=8 m=4 with 256 KiB shards
(2 MiB stripes; 500 000 stripes across the file)</t>
          </li>
          <li>
            <t>1 000 MPI ranks, each responsible for a 1 GiB region of the file</t>
          </li>
          <li>
            <t>Checkpoint interval: each rank writes 1 MiB of updated state
every 10 seconds, distributed across its 1 GiB region as 256
independent 4 KiB writes</t>
          </li>
          <li>
            <t>Ranks are block-aligned per the HPC guidance in
<xref target="I-D.haynes-nfsv4-flexfiles-v2"/>; no two ranks write
into the same 2 MiB stripe within a single checkpoint interval</t>
          </li>
          <li>
            <t>CHECKSUM_ALG_CRC32C checksums (XOR-affine)</t>
          </li>
          <li>
            <t>Twelve data servers, one per projection</t>
          </li>
        </ul>
        <t>Per-rank per-interval work: 256 writes of 4 KiB each.  Each 4 KiB
write lives inside a distinct stripe; each stripe's 12 projections
(8 data + 4 parity in FFV2_ENCODING_MOJETTE_SYSTEMATIC terms) live
on the 12 data servers.</t>
      </section>
      <section anchor="path-a-base-chunkwrite">
        <name>Path A: Base CHUNK_WRITE</name>
        <t>In FFV2_ENCODING_MOJETTE_SYSTEMATIC at k=8 m=4, each of the 8 data
projections stores a distinct data shard and each of the 4 parity
projections is an XOR combination of the data shards.  A 4 KiB edit
inside data shard i affects data server i (whose 256 KiB chunk is
rewritten with the mutated shard) plus all 4 parity data servers (each
storing a fresh XOR of the 8 data shards).  Five data servers receive
CHUNK_WRITE; the seven unaffected data servers are untouched.</t>
        <t>For each 4 KiB write the client <bcp14>MUST</bcp14>:</t>
        <ol spacing="normal" type="1"><li>
            <t>read the affected data shard from data server i (256 KiB in, if not
cached);</t>
          </li>
          <li>
            <t>compute the new data shard (256 KiB output);</t>
          </li>
          <li>
            <t>re-encode all 4 parity projections (256 KiB each x 4 = 1 MiB
output);</t>
          </li>
          <li>
            <t>transmit the new data shard + 4 new parity projections =
5 x 256 KiB = 1.25 MiB out, across 5 CHUNK_WRITE requests; and</t>
          </li>
          <li>
            <t>await 5 CHUNK_WRITE responses.</t>
          </li>
        </ol>
        <t>Per-rank per-write wire cost (Path A, warm-cache case where the
client already has D_old):</t>
        <ul spacing="normal">
          <li>
            <t>Data server i CHUNK_WRITE payload: 256 KiB (full new chunk)</t>
          </li>
          <li>
            <t>4 x parity data server CHUNK_WRITE payload: 4 x 256 KiB = 1 MiB</t>
          </li>
          <li>
            <t>Total wire out per write: 1.25 MiB</t>
          </li>
          <li>
            <t>Per-rank per-interval: 256 writes x 1.25 MiB = 320 MiB</t>
          </li>
          <li>
            <t>Aggregate across 1 000 ranks per 10-second interval: 312.5 GiB</t>
          </li>
        </ul>
        <t>Per-write client compute: full stripe re-encode (Mojette forward
transform over 2 MiB).  Empirical measurements on commodity
hardware place the Mojette encoder throughput for
FFV2_ENCODING_MOJETTE_SYSTEMATIC at k=4 m=2 in the low-to-mid
gigabytes-per-second range; taking a mid-range figure of 6 GB/s,
a 2 MiB re-encode costs on the order of 330 microseconds.  Per
rank per interval: 256 x 330 microseconds is approximately 85
milliseconds of pure Mojette compute, before RPC and network
overheads.</t>
      </section>
      <section anchor="path-b-chunkxordelta">
        <name>Path B: CHUNK_XOR_DELTA</name>
        <t>For each 4 KiB write the client:</t>
        <ol spacing="normal" type="1"><li>
            <t>reads the current 4 KiB of the affected data shard (from data
server i) if not cached -- 4 KiB in;</t>
          </li>
          <li>
            <t>XORs old with new to produce a 4 KiB delta;</t>
          </li>
          <li>
            <t>sends CHUNK_XOR_DELTA(EPOCH_OPEN + entry) to the 4 parity data
servers with the 4 KiB delta payload each;</t>
          </li>
          <li>
            <t>also issues CHUNK_XOR_DELTA against data server i for its own
byte-range change; and</t>
          </li>
          <li>
            <t>at end of checkpoint interval, issues CHUNK_FINALIZE +
CHUNK_COMMIT on every affected chunk.</t>
          </li>
        </ol>
        <t>Step 4 is needed because the base CHUNK_WRITE path in
<xref target="I-D.haynes-nfsv4-flexfiles-v2"/> is a whole-chunk-generation
producer with no small-write fast path.  For delta-eligible
encodings, CHUNK_XOR_DELTA is what the client uses to update the
data shard alongside the parity shards.</t>
        <t>Per-rank per-write wire cost (Path B):</t>
        <ul spacing="normal">
          <li>
            <t>Data server i CHUNK_XOR_DELTA payload:
~4 KiB + small envelope</t>
          </li>
          <li>
            <t>4 x parity data server CHUNK_XOR_DELTA payload: 4 x 4 KiB = 16 KiB</t>
          </li>
          <li>
            <t>Total wire out per write: ~20 KiB</t>
          </li>
          <li>
            <t>Per-rank per-interval: 256 writes x 20 KiB = 5 MiB</t>
          </li>
          <li>
            <t>Aggregate across 1 000 ranks per 10-second interval: ~5 GiB</t>
          </li>
        </ul>
        <t>Per-write client compute: one XOR of 4 KiB (nanoseconds), plus
per-parity-data-server RPC setup.  No Mojette re-encode.</t>
      </section>
      <section anchor="cost-comparison">
        <name>Cost Comparison</name>
        <t>The figures in this section are illustrations for one configuration --
the checkpoint workload of <xref target="sec-example-hpc"/> at the stripe and edit
sizes stated there -- and not protocol guarantees.  They vary with
workload, encoding parameters, chunk size, and fabric topology, and
the assumptions they rest on are listed after the table.</t>
        <t>Path A = CHUNK_WRITE (from <xref target="I-D.haynes-nfsv4-flexfiles-v2"/>);
Path B = CHUNK_XOR_DELTA (this document).</t>
        <table>
          <thead>
            <tr>
              <th align="left">Metric</th>
              <th align="right">Path A</th>
              <th align="right">Path B</th>
              <th align="right">Ratio</th>
            </tr>
          </thead>
          <tbody>
            <tr>
              <td align="left">Wire out per write</td>
              <td align="right">1.25MiB</td>
              <td align="right">~20KiB</td>
              <td align="right">64x</td>
            </tr>
            <tr>
              <td align="left">Wire out per rank per interval</td>
              <td align="right">320MiB</td>
              <td align="right">5 MiB</td>
              <td align="right">64x</td>
            </tr>
            <tr>
              <td align="left">Wire aggregate per 1000 ranks</td>
              <td align="right">312.5 GiB</td>
              <td align="right">5 GiB</td>
              <td align="right">62x</td>
            </tr>
            <tr>
              <td align="left">Client compute per write</td>
              <td align="right">~315us</td>
              <td align="right">~1 us</td>
              <td align="right">300x</td>
            </tr>
            <tr>
              <td align="left">DS compute per parity per op</td>
              <td align="right">256 KiB</td>
              <td align="right">4 KiB</td>
              <td align="right">64x</td>
            </tr>
          </tbody>
        </table>
        <t>The dominant effect is aggregate wire traffic against fabric
capacity.  Per-rank per-interval Path A is 320 MiB; on a
dedicated 10 Gbps NIC (~1.19 GiB/s) this is a lower bound of
~0.26 s of wire transmission per rank, well within the 10-second
checkpoint interval considered in isolation.  The problem is not
per-rank wall clock; it is aggregate contention.</t>
        <t>Aggregate across 1 000 ranks per interval: Path A is 312.5 GiB. On a
shared fabric where per-data-server ingress and cross-rank bandwidth
compete, this saturates commodity checkpoint fabrics -- a 100 GbE core
(~11.9 GiB/s) needs ~26 s just to drain the write volume, exceeding
the interval and backlogging subsequent checkpoints.  Path B's 5 GiB
per interval per 1 000 ranks (~62x reduction) drains in roughly ~0.4 s
on the same fabric, comfortably fitting the interval with headroom for
reads, callbacks, and interference.  The point of the extension is not
the per-rank wall clock but the aggregate-fabric budget: delta writes
convert an at-the-fabric-limit workload into a
comfortably-under-the-limit workload.</t>
      </section>
      <section anchor="assumptions-and-caveats">
        <name>Assumptions and Caveats</name>
        <t>The comparison above assumes:</t>
        <ul spacing="normal">
          <li>
            <t>All parity projections have the same size as data shards
(holds for FFV2_ENCODING_MOJETTE_SYSTEMATIC by construction).
Non-systematic encodings are out of scope for this document
(see <xref target="sec-scope"/>).</t>
          </li>
          <li>
            <t>The client can XOR at memory-bandwidth speed (holds on
commodity hardware for 4 KiB payloads)</t>
          </li>
          <li>
            <t>Each RPC has non-trivial fixed overhead; the small-payload path
is not amortized down to zero.  Real deployments will observe
wire-cost ratios closer to 30-40 x rather than the 64 x
raw payload ratio, once RPC framing, TCP/RDMA headers, and
CHUNK_FINALIZE/CHUNK_COMMIT amortization are accounted for.</t>
          </li>
          <li>
            <t>No RPC failures or retries; add ~2 x for pessimistic
reliability accounting on both paths.</t>
          </li>
        </ul>
        <t>Even under the conservative 30 x figure, the wire and compute
savings comfortably justify Path B for the HPC checkpoint workload
class.  For workloads that make large edits (whole-shard or
whole-stripe replacement), Path A is competitive or cheaper (a
full-chunk overwrite avoids the epoch-open + finalize overhead
Path B pays) -- CHUNK_WRITE remains the correct choice there.</t>
      </section>
    </section>
    <section numbered="false" anchor="acknowledgments">
      <name>Acknowledgments</name>
      <t>The delta-write technique described here builds on longstanding
practice in erasure-coded storage systems: NetApp WAFL's parity
delta logic, Linux md RAID-5/6's P-shard XOR delta path, and Ceph's
partial-parity-update optimization for RADOS erasure-coded pools.
The specific application to XOR-based Mojette in the pNFS
data-server context is due to David Flynn.</t>
    </section>
  </back>
  <!-- ##markdown-source:
H4sIAEUOdmoAA619637bWHLn9/MUZz0fmpwmZMuWvT1SOllZkt1Oy5IjydPT
m18iQSRIYUwSDABK4vS4n2W/7mvsvtjWv6rOBSAoyck6v/SIJHAuderU/ZIk
ianzeprt2sNsWqfJL2VeZ/bovs7mVV7M7bgobX2T2XfT7D6/ntIfOf3nz1nJ
v760x+mqWNb2YrXITHp9XWa3u/bdu9uXMpzl4SozKobzdEaTjMp0XCc36Wqe
Vcl8XN3uJGMaeUyDVsnty2TEi7jjt5IXL8wwrbNJUa52bVWPzIg+7drfDvcv
jr6aYTGvaJHLatfW5TIz+aLkv6r65YsXf3rx0qRllu7a99k8K9OpuSvKL5Oy
WC527UlW45Ns5XxV1dnM72jHfMlW9Oto1/7r4uTd+cD69Q0sDVQty8wOi1E+
nwzsx+KvWV1nA/uX07OB/enTwb8ZU9XpfHSZTos5LXVFe1/kNFRdDAe2Ksq6
zMY0ULWayR8EmFm6WPBow2I2y+Z1RYPcZvNltmusfdKKra0J/Lv2F3qERrLv
8RJ9O0vz6a5lKP+PPKvHW0U5oa/Tcniza2/qelHtPn+Oh/BNfpttuYee44vn
12VxV2XP+f3nWEte3yyvdy2eSu4mcnzPNx4fvTGl86rqMFfjzS0ZbysvNo/x
/FvwZeumnk2NSZf1TVES8BJagbX5nBDkYsv+xGPwV4KKFzfFLK3i72nn6Tz/
W1oTWHfpBzqOslqkw4x/zQSc02Jysyr/xwSftujIjJkX5YzeueUDO3t3sPP6
xRv98/WbN9v480NyuLVxE7vG5PNxPMjH038+urg4Srb/9KfXuzy53tFnF3QV
FevsRZnOK7y3a/cXi2k+5IXburAfZukksweMpc/4fQ8U/pcoCP45+bRl3y//
7/8eFXP9iR6thnn+bjmdNp7J1h45X5byRNePH+Z5nafTSt5vTXuyZU+w3fmI
f5Bbjb0akySJTa+rukyHtTEXDxAeXE5CMKY+QH87ysY5AdimZniznH9JijKn
25SNMH6aVFl5m5V2URZ0FYspoYW9u8mHNzajr1eWMcjmeHtMW094CLtIV9Mi
HW2Zd0QFcQHxqSJ6mNZ0ub5ktpql06nNRnldAe58ojxHNsTM1yubzg0Rh+Q6
reizox/Z3FGQ+obmpDMc0nvDKRacVPmIBq7LnPY0zurhzcCUWcKvEKUhoBGR
o4Of5bUlQMjysYKBvaMLRf+hCdIZ4cPYYUQxNvVNmWW8xGJZEqKPCI70Pe1i
Qie1pBkXBJ3rFQEBY2WjLUsXhNZGBGoJqmQ8eGm8BYZNaeOOTQzswU+fT36+
pK1eHh4dX+wPBEjTjACT6s6MX3eK2RKC018JTlghvWf5KtsRLX9YT1dYa5bS
+eD0rJyeuSmmABveD+/SLsCg0vFYgC6g2+Mv45dT3JGsku95rmkxpONb8Vaz
sBmgQZlhGB6vLvgEp7T7tCTKDeJLcB36U6z4UPAMrYGessObbPilWs6Ivi8r
esDUPHxe1Vi8oBaxCYL1jHaIN/jk5oWdZ3fMBghGDlO35FLM8tFomhnzB/th
XpfFaCmb/+0PVTZM8uirr3JtgHAb7061yIYePcxvvz1Inr5+9VcL+5CD/uXs
w8URIQJhNI+Ryo9VQfMoHudVtXS3T66Xf9ymk5ToMhAhOqEtc4QDjycYpmWJ
M0stbqVt3EpLUMkIboS3qb2ms/xiepBWZnlZFiXNLMSh6hO60xPVTVqOLD+h
1zDBjYoeI1FISEILc+ximuJ+EsnAL5+OTg4/nLzXE8TRg82VcitzbK8yhLzv
PpzsH3/4n0eH/MjB6cePH4ikH9IQxJ0nMokHSOWwOEIO45BDoD/C/I8eFWFL
k1YxZmHkcTGdFneMgMXsOp870gBEo2XUOQQckCMzI7BM7U3Kd305T2+LfJQC
i0BakiZpGRbE3wlD7XlECXugI0wQv+TTgj/0wYdB2EjWmBCweJ/0JFHunC8h
hJhM4OBfwgizbJLKCDTJUdfBER3PiORhj4uU8Gxlb9PpEmBbZHOCQMHHRuML
YVN2wNiAgWnYj8tpnS+AucV8uCxLwl5hCEQjicwDZqO8+mtB1yzQekZ3YmdM
9Ac0fLVk1CGqB+Im7wsBTwii+Xgl312nwy/YJSO00Coi/SSqishEqEz4cpeP
6Niui5q4/pyICebHOZEACcpbZ24FJI0AflbgJTsUAkCwSEf5REnVPY6NGRze
euZ3rNschA2W2YRRuFeS/Nx/5lGJrnVaVczBR+4qfCYac0CEpqKb4ojx4+SE
5MF8cpMQlFjomZN8RSi5WDJ17JEU3RcKuuD1BFT2LJtEmWWV8tmOLd26L5UR
AtPehLtV/pwwBigF0fAFkf13TBm23ySMCICeQ9PUvnz9xv6cv9UjGvA4TFRj
+rRI6ZhwByqwl7K4zwneGXEv9zYtIGblREqWlX31w47+aIjgJ/JAgp8SxWDP
KcGVFZUWfG08XOj/iTqRYgOJab7G8S1TGVrJzv32i3/fsQUIWYwxehsYcYxo
eYS6dAPG+WQpVAkQwgem/DweC1uxWEDKBGleU1p6XbL46kAejm2UVcMyv85G
A+JwvCN37HayJCSlfZDsbswvN5lgVVtKAtZ6GUpFpuZ2iWh5KkWL/qC0lPkQ
8RCQKeBXFni/Ycnz0P5oDy9JqGAB5PCSTsOYa9K1Ml3KApIX0AI0fEHnLJ+Y
wFRrkgfDcmBYRAvUKN5Gdk8jVhXzZKGvmLhJkE1FIhoBR0bDSESFF0S1WPKZ
r9y4kQhE3G45FHpJ4zmJQ4QcwpMC7E9ZPk0wrrLa34yaWWUYy90Ko7eC8QQ0
NLVfftyxsx9fKt3Vg/BT3wh/4NtgxyUpRt03glbjUPNPb5RupcOyqFSCyO+j
1ZiIDQNHGiKpF0vWZM9YRg1CBxDcy6BVWwRlaFW0fdWlrvMpoEzzXRfL+Uik
edLCSVcTziK4tXAPjqfphI6LaDbJrFlJV2HEYGBmTnAPbFbk8YDfcvOd0EjH
m+tNFeUmnRJzGK2cLMTc9uKBa6KCKlE63qUgi1wAgcP+ySHYVRBke3IHQASA
X3zsBKYJ8wsvkGMVLAbwrlIMQbNOs+i4+gS+MyK9RAwEIPbo4PLo5ODy3fH+
+/NwQpcH+5/23x4fgW02yAmw792fX+KdUwhZlx8/nJ2dnpHY1MsB8Pg+4eVR
NmHzDi14SNShP2i/Lor05fmv5xdHH/cvPhywBmXa02Bln/aJpP9q/2OZEmVZ
ba0948Y6OT2JxmtB/ZoOjKhcA757hMAZiW6Q1KshYQFJ1ID13Q2hVy1kYTgl
HYwUTTlakQKz+W02pce/q7xGQcgwIb22vpm5eVXl6JUKdpqZAX/w09HBz+ef
P0ag339HMunRoAnxvihKB2cHdpzOchbEBAQsEA7L1aIuJmW6IM4LmfAmE3WH
RJolyXIJFuX1HRoVu98SCUTp7ygjRjXjixpfF2a9E7omc4fodL+mRcHi1nJh
wg34DjyEpA8QqoDsQqBVIrRH7ns2RHocxEpxC67G49uXs0u30EsPxis30IH+
ZPY9hN0oeqlJIyT0zwkCXv75sH+ybw8KFhmCIP+4BERoztwO45oyvjAVGKoF
gY442Mf9Xy1rU21K5/QoI8o2Q2sP8vDcaUY5zApMDmiYz+cX9uT0gmY/EVWT
zpjuPbjnaMSargDqUlSonau9+MRgqCCZdSXULVACHoSGUDIFBoebbMy+YGKT
FUMEwIN+Zc7QMISEAk3Pw4OuysrQcMr6eJxiupzNq7YMMqL5e3LB8nSeJp6y
YgFfvw5s9JvDAf2tz9zCvWCKMtw1USOi5Y8KwmHZwLCYzPO/qT0mWjM0jeZm
YaYmadumoORT2u1BAKk7EXsNyXSclaUyjQZ/+E6k7oGAu8EZijl9TWv2v4zT
YS2SXGpUe01Ht+A7ldhu/AVqgpAk5+Gyomf2vLlG+GV8ZHwNBEuXlee7LAmr
DYX4o4MFq+0kHMbXhm7448YGQJRtMUBJqHYwnJs0vgywA8VQr+bporqhZdL3
LOam89b+SEjG0YzTfJoMpwWMceUSQtg1oR1w8c7Z9NS8V6VjPd15QbR8PiQB
GCc+ovtKaFt5QRdbdtNUYjr6j2XOBwlkKkqwT9osxJc//IGICv8qTx8Tk12m
k0zo5ZdsBbGZROZnQIxnA/lfIAj+Pjv6l88fiBXi7/Of9o+P/R9Gnzj/6fTz
8WH4K7wJ88PRyaG8DIRrfGWeEVCfyW6fnX66+HB6sn/8TIhcS9YHjWBkJZpO
VxNSb1oZL+LjnbcHn/7P/9reoZP+b2fvDl5ub/+JDlU+/LD933foAwiUzFbM
iZ7IR4LlCiKjyi6wJhDxyet0SmyIZGU637s54wMB8o//Csj82679h+vhYnvn
H/ULbLjxpYNZ40uG2fo3ay8LEDu+6pjGQ7PxfQvSzfXu/9r47OAeffkP/wSp
wibbP/zTPxrFnqmwmZt8gaN4C0Q8b1jzWjKy3CSRrcfOHMiq8K2T5INRXCQA
thkZIi3MI4L83GtxHyKd7qEM/AJuscz0Tt6d7xydOUnvA4lPHz8dH10cRY8T
Scqrolwld2k5F5PU+pvHp+8v330+Pu4rkR2NxLjGpg+6dMx8A7H5ZkKz+xjf
t06R6xQy/GNQGaZTM8uGRHbyClKQGuzYLlVmRCvbtj1n+B3Il5dQhEc75mD/
nA4jJ/WE5KIBvcq6gDuegRobcWZJmd0Wqv3CCFFFVsInyB+wI1+wVFZMi8lK
zch1+EatyPimEuPqQCyouuLBA7sxKpOzX0Aeo6ublbL+SOUCPfmWZQ8YoukY
1pBnzh5jGsbsZ22/hXAqenjGaA10J9qMSXNZINSBYV6rCssWnsaIImMFSmXZ
/MK6eB3p1YbZCV0CZwnDbKyDQRJS3CV1VCDqdg2VMl4tKXesh9L/7tp90cQq
4hgZrCWHkYmxw3IxUEOofC2WPhLmnUFTpBliWilEkjqfLItlpWoefSuKuC46
1WMTVYlHd6ZDZ9yfK4MmHIV1fOanwHVwpgeSANjpglHECiHmBhmdNi/WCtoN
Wym8qS5ooFsKEJstiuGNgiVavwcObaEtHEfWdfVFwB8X9FYVKIIvwn0vCH5d
psMvmXPjNS8qSXF0VekcaA7ikvksU0FQ1uBs/3iCpQ1+RAiFGhpoCAfsuWyO
71cWgBBPaMOVkolKHC278dz6ZgXJaSSiDANM5svZNQTAqsonHtvcvj1k6boz
XNlonJWJbj+fJ7HjFCJvOQKYZf34ImMjx2hZimUK1ush2wCjI6NNs1eHZiHZ
E1RVRqpsr7XOgZjjrVqoBjqKGP9VvsQokUWGoFeRTMYgqbLpmNASSgT70IF5
K1mYTgxDEqHOSM6LRoA4z/czUuCdfCyoNl+3stzd4Dw7zCqwM15nzsQnghHs
+TpwbOSjdb9/13vZZ/NwZO1jlxbJh3SRaMnT1UCgGs2NCw4+M8FHsNPodZyv
wEx8Tg4CbGRRpDr0ftV1K2Jaq83TfZN44uYORbQ7QohKFgVXTBBwNxtvGBRi
k/QGG2fQ8doam3D21KMtKqh45C1vL5EXYLsG0aE/nmDusb2IwcgS1sInAl+P
vBj2cQFCLCfAxFIwDUoUZGLEfqQjWBz9FKDxS5aef/stju5QBfRBixSoAsTh
CEv3Tw4jAxO9rCa8lo2uy0L3/8+utctXmU6LSbjOz9pNxQvB11+iuSvdKF9S
r9J7GK2hz9n55Z9po0dnH0/pv1iQrCBalijVtidmNP2SXR24X//+Q3+gLiO3
MHqdaVyRjQmvmf7PxBfmw2fAXsFUWbsOOr/eawbgKYQBLH7jkRCrvsZ98aY0
aINgGy0exdjTsoEKPWrFEjjWt24IHEdigTPhQj5uCA90mAr9X0F0MqzLEpGZ
kEZ/PLDj3l94z7/2Sa6gD33+NO796v548e/HfRUwaAz65OSBY/ES0Ckkf8vK
wk8Iut+gZOx3LNM7xCPxlYAPVNzTkMWe3xclhDOYS+oUyjEbwQoroxJMq7FG
b9AAN8WM/q9cENwIAJc0bGMD8oWunT/8Cg5yjtA8Yqc4h7ODVy/FM4+/DkCi
4DGeFiuiFX5V/ISujI11tPf7d/qvr8taOS8QzsubqcWygHsjRlFcnehxDS8p
W1vZeA57unOHFgomPRqmk3a8nPuQGD1bNRFVhUML3D+4goFpKhylkzLLhJ/I
TjxqOQWIJSnoHjwoVoFX3PN0LegKqXSTz4di3SD8wjEvp2m1ZkngIMSYVeIB
FoxDaFUEU+Ux2Bm9Qjc1xwi9YFV3t4KoKQxszvS9f/z+0h+06frhwJv76dcO
Uzemabx1/tP+y9dvBrb95evtl60v3x7v/3z0qo+tAsvin96ROkxfnO0Q1nUa
0vsBZ3R9SihwiHz0pQT7sCLn2FfyTtT3c/gYVKUTf4MxbboDKxoJK0uWU7wA
LHJ5Pg62GfqbrX7qsgpBJDDBsV3Gm/dZvvQmOVjylws/NttFMfp3lZ2AQLPa
L7qs92g9YO7nw+5W0L7DKYndWh6+RDjgztUT1XcRDB5l9n0OiBErSgqR6mHP
FlOvB0zS/T1cxK1sSwjjBh9e2lDrrWJ7rKZ/3WrD7gFXR2sHG11EvPiWX8R6
+4iJfHzfEpqEu/SAHZ5Q+aDhbKhvliBq6ksdtPyoK2d/7QV/oB/S77n/mDd1
D+bd1KvnxnlE7AaPiGi3UWwYmx3LDCLO2iVrXyxRHdro70UM4/gD3zhoKmrw
YnbkjGMnpxfnnz994oWoBqtWSY2sMEKTW/fQuYeSCSIugso6JF0gi8i4C/g3
HqGI/GR4fC2iUvaus6qFC7FKINM0qgmWQ68r9tpDqHuBVNTlzGmmFSHqbWZu
SKEFDcArskPgyJEPumRWIfukgR65jrxUIRurgVHcbgYSOIE0Ds6FaYuj88Ur
c9UTpdxpqBB99MOlaPOX/ED/ysVnRcoUR5sa1aNo6SKYpsFWQqvmuNt3JCk+
qtcwP3WLy2M6waf3NCXnKY7K9dVEqkkMIVxZuqp5Ot31WSOiZJpIyYwCU3TH
Tu9k/dSBB4q5FW8AxAcjwaWs6jKENUxlg77ZWlY6rQrj16bo6TTMpy+oexVP
06VMS5eKXImKwI4wE1ZlwxQ24xAUx8qVWVOu2LstFo/Eq1FrWpdTgWgRcs3T
USMgUSJ26pbXgBbFlvZsms9gtsjWom/gdRX++vDVEycwXwfj+VwZjOetGy2S
j5N7TO8hnXCPj7Z1BscfTj7/5fLj4eXZ/odDVrsQAfAvYr7uO8nHexivxTCE
cMm6iySk5v27RHXEVcJBQy7KtMxBSpUPRZkowfK4J07URmg5SD7sPiylqT/r
D/bUE8vtFy921/TEhMOSVmLtZWwliJ6LNfWAmYvIe633vrLX6PTT0dk+vEv2
5PPHt0dnrKsefjj/tE9iKAKGnVAnV5boRjl/kkGe7zlPGRlbNYo44MkUlA/W
rcAQ1DJJW3W+ncqwlF8twPYAdtYGhIim5USHmo8cm1rOMZcqHX85PDPBpr+u
b1jngpmqwxUH8NtvmqvD/pDff//d3o+gotvnz5+LkE2Au2wfxI9Y9B4eN7/t
2j+M80nS8RSn6/z4jNbFIFp/4pn9uj4nRNv1R9eQYYfgAWAyCbqHEZjwobkk
OqxLeqpY7CQpeLMsJ3xribTNR+rUnf2XFlNmT1gLPdSxFvm2Yy2Es/tn7z9/
PDq5ON9wNK1lXH7c/wuRgIuzD0fnlg7ph73HH1c349EJPf/m9etXb5rrFlZP
e7rkTV2y0bly6/8FsfBsfJbvu2AoapptD8TW6B37m3sM/5b5vH718rKmP4f3
o+yyyv5j76Hfr0nUENbUeKxYpP+xzPhPfown/IcHN/+PfoCvD+9fl91C7e6n
OjGq8yCEaxx9Oj346ZLo1Amv/Uf74v6F/Nt+5CDj9w9OTy6I+B/F77/07z//
Y/h2x6ode7THVgpYcK0Ocnx6jnCW84yltyrbsn98rmO0DrbzXjaOleY8+Hx2
Roh5+e6nXfG7+9H4CXag5qMdu/aPDjC91J+bh8zn3vGGvBKLqI339Ae4Ync6
3uMfNiFd10QcCdQxg7qs1l/gH77lBQR/kepQVYRem15uo178hB9IfFadF0GJ
xsZr0HnIrUvQ9YwjZGdH55+PO8jYBhwCTfyykTaEPZWXSKK4vEPq0UPUIn5j
Wkwu2c90CbvPt72R3iJP+HqaPRVOspFHAMUPdRELZu+dvKYiRYuk2R4xEFyO
HVko/lxW/SbgmIdBb748/Xm3jRfd63Ub5087DRCRgJGS5LE2EBIPvgEoTwCJ
Q53Do/ODsw8cFyThGBs93NYlN8JlgRw4EgxDUiULUqlRZ1DDB8+B/XEOnrUf
2JcSecwb8YCw+3Egobp61YbhFD5Ohop+Vvrl4iRvSagfmQYhcm86heqiy8gg
BpZgi+ZIpy6zCAyWeKptZPmu2hBubxp+WdHJoKuJOM/hrwSz3loEd1+DnKP0
AmS21VUU6iO+gHEucLxao85XW+YqUFKEIo9ykZRZUUMupSoXYRYfodEMi0ge
Z6wIVYBBDcEcsYMe1tNAnq/inEvCxZuBC/kYwno155ydkY+NTWsOZCAZnLTW
YiZSNo9LEPf7L92xcLhEtRwOs2zErOOqm86HVfBhNqZ0ZiK4hUk7zeCMRvyw
xLkQHw+5loXqAXIcbHySUdiajpWzZiy+y7tUNOv+BiTclZyh3nbfngk6NhBQ
4P/+8/7ZIc3MNvSVLTgIO4K2z5LvAf01Q3ylO+o398HAamxBEukROPCkFXhM
/M4P6+cPQBLoBj8nuwY3nkuS+CHCUdD4PuqIbvzUxUW7EIxgY7krltORH6HK
xTvIHp7loo5sRrrVV317qhhTIQ60LmaSL4pEvRq+3wbuqoEbeVxuDpeuK9vk
ZalC6jDcZ4NPmsTID/ElW8lR9cJcg0hoAi2AUdxn7d3QNFMEkbhTiHFJjaFM
RKPrycZh2Mg3zIEcTs7DmaXE/+R1NWYnjCkSRMSuMXpDMsfWKWmNTFNBqVSi
7UM1Ab2jZT7JYQu37DXPKqd318ty3njCnYsVvb3KBuq06sRIF5kXQkiIPswW
RZ1xwuaCCLW/l2efDsLKKracxO4+l6Y7XDEhfpj4ea2gSV4DSc05S4rhNu6G
6ia2hNgH9ueKxRChOnIIDcK/8UTzSu64OKqYlF6F36/8SfNy8VXEDnRle5bg
w8/BvmeVUToX9qZz2Hi7eYx8Iob3wuGnh2Aw8qw7A9QJISDBKCxGaDaI8yZx
huCMpoQNpoeMVhKD+mwR9bkQsNXkNRaiFL+wE76thGuLOtXYAr0MLO+M43vE
YRatdfPY15xXg2Ssmo2qc02RoSvPDhf3kAOhRuh5IH44+fP+MU391iWAxuok
7S9wci0gwfolbrTXMH3UpOR+Omd2rHna65zWKGiE0EE4LuVUiN4hCQOxfETB
vOUScSYIuahbsYcDZJ15nyHLYYnG6YqbfN/zJ5rSufyiTSg8NiIVw4MlS5gP
QTrvCIcSWK0JRzgISfyMPnKbyORVpI5dSdSCC+Yjhp+ufIAhx+yxg87jDSRm
MbYYsQriebp5P7hnOUXa4+jAO4DhvqRxr4JJ5MpIKINPPeXiBToKi1cqLAcq
4fEzu4f0IhYjw8rRmlNQ74JKrZyN6oaRt4F/gn4G9vW6C7L0wo1LZhHcl9In
pDfOQcYQ8ohgIQ6vlAjHILptjga9cvalK9NrSHYDdZJxYAojK6oSVFkMohad
DS6+yrSiWRHWJiFI6kG5atmtrpwo6/ltyJyOIj85dLvKprcM5jYVdmpPFmBw
vTIaVRyftwQYi+qTuPBjDH/1r611DUzrC/s94l56YbB+H27gwxhLg1gueBP5
PtXfoIHQLgY33gRDbSXRvAMMMBTdLYdNfDbj+NJbDTAmYj3M+bNcjPbpMuVB
fC2SurNSYMLp/VKkBLdzmhEVAttmHUgj2VuByxyvLBrOJmWsA2WxDTkFcXVz
QK+EmLs8lOtsVegpO9HUR3tUnFHHmbGQhdYxBkrdNF2AeArl4sloiChlOcIq
OPCik+gRBjjhw4etoCjP0IkfiumtACmSMA7wfRJdY42bl/WsRXLnTIroXuOW
auqZxh4rceOSAXSKdM84t9/pfMs5K604fibZmjR2dPH57MQSiD8fnRsTJOIO
4RJSmiSJX3WYia4k6wVfQrBro09rOETaIfUK5RCcT4V3iPBwpCwz8jRJJ5+s
VzY8xLb8gppWKF2Qy1IQtRuieDEcLhfE7VcqlDMTlMpefglyh7uG9uYqHZ9+
+Q5XY5aKVw+KPXHeVTyKJuVqWYOURS9EHw7WmWx3koFEGDsYrQkUzRvTTHJy
vAp71DxHvK3JA06nlhFaV9XbkM5Oj4/f7h/8zIrxGBYgQqFSuQancs2BT4Q9
SINcaq5BB/aI0w3VGxZlDtEr2NqKUaZJkQYyc05KQBrVnqO93+ZS3uI2d9kQ
Z0f7h5wDbzplEa908ZsS/oNkGk6Y9PFHyU9xnCSWcKTp8fYn1bbUBeqDAZU1
CrX3rHHu8+pFbhdEZqbpg2u1XMjI+KopMsgNCWAo6sMO0yihgn8EIAetkK2n
BFi4bBlxHbNnHulsLJMCxlpnJA231QfMiTGJT1BLA0lyQFa5pTm2I1NwYaaE
aZfEUYPyr5HZfqMMwaVuem0CjVJoZ7xwsolE7XM1M4ZNlL4SGYXUvTuGLonU
Wpd546qdgPwoxDnH3NUVWI+BLtsBaSQFPO69dhfUxwLw9UoJ9MU0Q9WYZnWP
zQFz5sHAto0RqV3xqJL6j1x7entvU9yooxaN8gwJYlYDUKru0FXz5NDVUM1h
v1M+AGfTij7r8QrJGi/JvZ1AlIOijCJc1GoT7qaDoqtHM+8Kig9hoVFMpA2R
AHIF12ImPcVhk4oP2e53mEz2fzVx7SDBaJ08CnXmIoLHdHTHwCdmOBJ/LQq7
4TQJjmfV7fW+gajQukhkM39xQ6MokdORHLQKaJZ1pSmitJBf/dOoWiQ1j9Ye
Z/aWePSn++hSAmwkQqkJfYsvXzvMHRU8KjWNcr5AI27dR7OHLAJjJIsp/NbM
JPAiCRap3BrLrCQxSFIQOJmB9shx6EHRc9ROQfq9nGWsTYihJi9R1wDqkZZO
UyUlngPPES7lJKmVa8kMoawjQzCXaqdMwzjHIcpwYCtHBxL2HdA0P6E7b8EB
SSjflYDwitFdtGc5sISDtX1SgBSA0IB/lPTSuLBvjvz3iKt44e6CT8UixDcG
xWITqB0hGU6j7iIxmIPVWtURAq0yceyXXyYvKs4oEGcN1/jyJU7Yy1eHuhve
kl0tOWRKYjpbZGXdfqUJs1LB0tMlqZsLezRN2YKetwjoqqxKRCbUw1GFQrBI
Et1jeKp1Yz3NAedrNuZ0IGyXp+QVtqfQoY03rq+YeYodpSzoCcnT3UjWO+3G
KiY5KjhdBSFpDbiu9lQwC8fUhHn5E7gzJ24HDymXGUlGCAafGxUZXJW6/dhF
KccwzBdsI9GZRXxu2ijFCK4x2lgvCkzAKCp1XwPhXBcMJb9OwjKbRgtPvnpM
I8K2O/OD+nsoVxyvXaKptcINL9TJ1pH5Pg1W31RdQ0ZdKKLoukn5cQmtUtLI
adhBLvdbM35E+N29c4j5DwdpjpKaWAXttbEoWqQzdrG5yrC5SgUrERBb6BRX
s4KfuUbibqNmMtNVzvPwolSo9EIaHCiP3py4ZLIEn3NUaqraNhAvFGuDyj+s
US0H5hCcblEmCjZ30GnlCsCAGMS3QMpCck6gBq3LeKyliDHoCEgm5bE+ZWUi
cZnnXCFBVBPGwuorSiNFPkHHAJdzccLEkaTi8BL6sx/MC7BqOPfhmuzFUmxk
EWerdxzvyil1RWk4SuABhTYayJvSeTCmQFxFx0QrCBppdNvV9Qpif00ahCyg
qa/2hRTNEIYM8HqgOAeoL0egTE1z6YmtzMQoWhdGHCkuw1u15RvEW2FIZkeS
+BG8qo0VAmXNRmW94UBBYY5JWo6mMMDQeZG4oJbazKjHjEm9XGv44lpOGzFJ
1Hl2TUv64nkPagoY8SwQ1Yr9mqFGFlK/Ui7/KZ8QOz6vQ5Xf9YoYdN/EJqkl
aROf42+50K9YmASBj4sJ4SvikpYkZHElYbasRv7FNnOAQQViWuVDEmC8ERsk
ZCTJ5m6qoWy1iwsDaHEBlfhYSoNpbsZpr6KLRm8iySkYsTf/HFsOo+zF+IW2
idmYt0q1IHY5q5aUZAvlBWzvkeICxhcXUJ1CxOhiYtXzmVbic2KbX0ZiD37j
2tQoPA5npFQ5aaTKlFDvZvlIyEjfS72YzA9g1u8WHS8fLIJV38J/wm+e0phj
0jg2GHnZ0SIKhMeXcL7MRcb5PR3pLL3HQRkx3jZODuIt/dzbefGnNwN8r+kz
HDb73O4MxInS72sVWsOlPZyw2tLDIqkwdVWkeZGRW8B4OxasFT7oIbIliie7
bQXEfWNEXUvhciKM7XUaLwdms+Gx72ra+gAqjqmquig2W8uDg1PCJNRXJOwQ
O93g0lfP/AOGRSZukFQZbyMzfa757pGRHJncxBdhYAeIGi61/lZU2PG7Sous
coltiWrAG5vWUYrd6sCbNN3pbDZtchqqEHa1XzqnrIih9+v22N48JWhwhEg6
g8nqb04KA96KsOz89FxTfB9s6eH1uMvE6xnD3s1FvOvCJ/RLNWhnVggIJtXC
cx/Ds1692d3OMzhlfH2X92l5LS08plOthGsC1XKRKrG/gZAgzefdDqYlDTxl
9uQfd7oT9xoAu+u1QB+bI+QnEQpRTd84Vt5rExuURtBBBx7oXES2GqbslCqA
3m3ZihNTffn8LHIPgdIEaTQ6+ruoytQeCwlY04ZJ89mMTkLqEAthrVsUAyuQ
5C9hWKFcDR+1L0+k4gxIbt+bI+GTiCycpT9Krgn1LeZgsZulrcYIeriioE5T
RMGH6K0wL+o6BIO3HDrpwOBYPtGJAEdCuryOyZwDlbRMtut6auoRDaLT8j6f
5inEbxZmOVZlKjFMJBBPWDQGdDTW6nnofRAt75otDdfLHNk7CwkVShv1o3wV
cu/6QnFVF+pjz53s7wz9URgQkdqmB3ZNZvEbCnXiQIrrAnYF9r2Ktd+JKo75
a+SmSBsDDlVhhZI9eBwxpCWuvLQgUqq755H6CZEWEyWxVtJbd/W6CMS2d85n
5TEhPWT1w07YH9qtya+l26YV/cGxNVpDi23b0GW3Ode5y2MIInm+XICjdkRs
qflhPWCrQnGDpi8x8Aj6ZSleoyyCbrCooM+EN95oTpH1NWyjUDQWrDQlTIP/
fHSa4939dRGHTkKmUWMUGk2oIMvyjtgES/lbewYYwUo9mjWRWo947tICe9mc
+/p4ioyKYUTHg2LGls9q6QvRiHv6lmvHkhhE4BE9otWUonLuaFdnNvzum1P4
RgjBMd5ohmBUoSLBFnCo5HiduQTLilUIF2rA8q0G3/ooxu7o00IsQJEW6uSQ
JgNtlpB9t6y51pZLl6xY8CuzaXqvHDQoQNcr49reqJzCJ3UrTW7oK8m9dLUJ
y5WL7m5YIEFRfyLc7Wg4MXBBDDj8JJ3mk7kvlYt6QfMsuB8+k9bVboTxlJoS
TillK7phwhQL3Bz0x7U+o8J8azKEiPjntKQ6OQXVO5OyTK6sY8W/gB5+DfqN
F0olLDwiUoE2gVuqeUzUQHVmaNzGl+9ncfmwuFT/gCsQuXT+fT78t4SHfFQO
7pH2jdppCz7LjGsqugUjWRZh5Sh9dAcOGAf6zU2FiPNGqvNbeQwHAAEHMUMn
3k7MJGOuTnWEGMqO1RjADVmi/XCGPxbOmhp7B+Lqd6AXKCRAN1493s3GQIAj
+6EgdBCnZTTiuEPUKZ5PVyaKKpCLLQ7RtHb1EblcRVW4OqBRBKx8o1kIgWzw
HQFj5vCem/RvKfoYdkrnjetqmAXsn/wa7f+7GNiDgC9iDY6qkfuwA48rjHsR
JMWf4iys0RHeIJ5RsgGy0cBo1AIIBIsKQiNaZab3GwthpQYdcwgb1Pw+jSN3
XdBYSeKsSHIVCHHCdhVPm03QaO6alhexlXMBpdyX9CYKQHTqWizq+XwOo6bi
kpx9MW+UPQvPMdultVRto7Vh7Z5QAPp96e5vmWlSj+WS00l2v8jxtdsMUQrT
RAhXZLoROi1kIER6Exn44Bj58AEWzrIfUc/sNnAxJ5MYlUm+D+DkWivxxjCa
WEnWC9dDCjdzbWs5LTiIPHG1WoWtb4ibHvgM2b6pSYroKExCJ+vEi8oGO7yP
jGsJVibEt1cNqYLFh63O0H6mYgGVg82NcxPAabSfIxfMj8pjsyjQCqOMEr0c
A9ltyEjtPIEGbEwcU/5wdkAIhEZsMochm4AXA+WPj4eQax+6DG0aXVaS7Cyy
eX/U/mXKhRpRP5rP1vH0t5QnaTSm62qdputCsTLQa/mVy2wqsR6EPm2DSKtK
Eu/Wiezh4hfweqqNOgXN1uoOc00Dbemn02o1eXwTNYuTlLsNvWxQRDQFXS9H
jkFyFoDPavH6FXz/XhmLrRISaeI/X54dfdr/cCaE4s8h5OoMIVdyLKy2Mkt4
/ASYeEX+JDVwAnJs0AfnmW9QWFX5NK4ws8Q+DZ1X78NcXXmoj6YqDzNfb012
lWdjZc/JtI4rewaC5ZES4Y0h+jw0/+vMiQWRvcOrUt83DCAIjjrsmrhNhCKl
HUW94cj0QHD5RT4Qo+ckQS+dXq+eUpZMw2icBpCUHPkgI4tzYLiSCKTmCY1c
ywinbYNmeSOATA4tVql8UHNdnyRGnxaggoIu3V0ir1jU3qtpDG1b/Fols3iB
0opQXDyR36zbHMqI8udmYk6g/CG+tMUDKgnZSINqHMpjBwWZBc4T25sXrHf3
pdmYqOBl5rJdBj5noivkM1TEZ4JweMroqsYqZ7/aM3F+napB2mDEMnuGhVyv
A3OvJBV/mLdJephGciOt1EsXLnWqFd607s0PASyhziIMpxzpF4VFbQz0g8sl
UM2Gbc9TX3rmjC9My1oj1zW+gD6GvYLdz2/XiaED8Yf4USopS5jEyYgztrqg
Imfk1RGHSuscGM//YN+ni6BVFW1be3SiwusaYDZm49POT6EmP3pNbTzCiTk7
1awhKjBNUWA3Eif8eccVcpz10TylQp8PkiX01gkSml0ybaRMcatrjAu1IWbH
0cU2QAnPcbBGaE7jpGwDKVt9fprWFIpUxRaROIRAm9a5hPYQ7wPqoNnqjpGk
a5mJEiyl1tDQ/S6rTUcckO5dVYeG3uN9UDgrL6en6KAIezki4ba31l4TVqBt
j4VbPEPrUtSjpYmeYSG76oGy1l61JV+Rdq+0axjDKd63WS9n4Ao221VWh/J7
63DZMi+3YLPfiKJ8eO3MsnCYmFq3KA1/VfuLjHpVnXNdWFEAw66t1FXDCOnm
TENk2gRZ3nFJzkhQ3c3apomTm0p40XkUk684bxQt05wZEWOsmQ19U2ZHPPp7
IG9LyJWe4tPlmaJv2ytAUTwba3uEu4UI82rQoOgx0MIBOhiHLpaNGBQGpWoq
eGnTsa1P1amxW+tKasHnLELRKI/SQtJGk6dYFnaZuj6JWtC617B2L+d6RWDX
gq3iTIzGdBD05SSrGoEYwbkgbnWiMSWfYESLjGT9iX+UkzSiCHp+dZ4JFkgH
RgRS5y5bUgI0sII9jgqRqfRJXBjRrQIC0PYRJyT1FQNKmYBSkVL9VeX7KNbq
Lh9mjfX5M6nSO0Ma/Ly4o7VNdPr2cc/h1p9PuEg0IvhydiW6vFXOVdOoSrQS
RE9b+8pyllU+bx31LgZzINWSnNpwzQQ/mTA8pl4cjDNmEi71+pTUMQO4S5m+
n/YiVKfTqbkgVt+QTl/VCcdlcuImgQgkfeClu1MUUXAezHDOymegGRjurFun
XzJtvSJuOxgKVDNg1XPjjTNx004nCrDc533+I9pZ9MQMEf8aw4dQBuNbU1uk
t5LAMiKxnG2A6unhXm5l6SscxKhJIpW010hiuxDzgAZ7lrssqxDK2aK1JiRa
8U7nLj7NZU1YDrRJ/ZtyUxt6IapfNvj2NEudktZVT9m3oMcZkABWLEnwG23F
NWhUFPPheE9T18Wn49UMll7MBmchzL5VpDKF0g+x7uFd8w/qHm03frsuL6d9
qDIXB+ax9FGtuavrwBPW3MU9TT5lg3nLbezCEtk51x8w3S1KX3gRvYZ5WpdU
fBF82TBcRxfVGSca9bPgYBI887asQvraIcEYikIdeZ/YhnPGZsPkEw46tuc4
iyEbFdUo0GxG9W1u7WEhWFpnkp8aKpgbuk9OnykQ8DRLJy4TqNIGusvyVqhQ
ZFRVe4tpliN1DcbEguHDMXjlfg2FGBPeirU5Xg6bKuWsvNA6S//KAeBcs9Ot
hBhfw+3QPY1wXmKlhBeMD2EnHHtgHUL5crmsP0o3oy58dO0ptBhMAhkBWnpz
XNuKguoYKV4xa7ytNYtz1ANmHRpMhFVy55Ij/NpdmodSUGoVKdTf0g4widph
+PgRl7d4nZEoNnd8Jy53nzixyNUYkroY0pEREjGbyFEu/PSs/Zycm1akCnYf
dFL7gmAW4eqP+ewGqplvOm5WetrUyZXEtlFwevu4ooBx3GQxqXvAu32wsdmq
9uRjANnfwGUJmJaBqCfNLma63Ihgz/1GwI/kejkKFCgxCl5wpCKJxxOnfd4h
SGzITnHr6zckSdNL4R0GGvUtP0rh8ZqGu4bVQRozuDOJmtrp253sSR+PeuAx
YFHOgRYRHGbqrpE6QQ1/HAcV34nkJT58CKepFIHPfNmeYCH0vqU4kJ6tQU7R
oh9Ngya0CMs6QRFJIaqBBKbL+ugzzyKfubylyqeihGoAfK9w/50hSLQjo0tE
l2G6kM5Z0awpgohsV39kKi4lzhCq2e3WN+pS1ESEacryPiMJwZmAdV6zb8Hx
G4Y34omUtSr9dirUGiVLEtMwOD7N2iw80QRhrhVqhTtD6J05GUlDcWaFFLUW
uRncvAvTRbyukRFYzJ0Tc/NtxZaMExNgPWKxA4fYSKBoju/K4YjaYzrpNjqj
xcDl0ZlbH0utvbNwS4AF53p52uFR4Xag/8fby+P9X08/X5wdHaDXabNiPJdC
fv3mzbZratVxw+R+9S7OiMhdnl/sXxx9OBzYs6M/n/58FD6//XwMM3P8ZZ+7
1X1Lp4igMoWARY1HLhqGpFYRQm4DpwVT4y7YknoqVN7HTz9gPT5UGyBwJ5/T
4vLJzYOZ/y5wDcV+fMVD6QTATlHjyne32EKgxr3uMj2BfdahvNRmwTEgW7SL
hj2VY6yjfKNQjCwmvkTPAufocSZ/E3+M6m6ugNE6Ae8LN9TGDhxxrPXJ2OvP
tydqDoP0KPE6co3cwJwLUd7h7fYRRJBOxG6yqeNG8Gvko5YZjy3pYg0BTL/J
3uGNHQHhjEc49vKDlyRiqf/P6EauyD7Kj06divZMZ6OzksJPwGE+0We+kgNS
OZz5sxEXJZHTTqFT4X1XGX+rhawrii6UgG0LT1i3muSIZJUkjd/NWzfUJVCy
MgLwhHTdZlbYaAkhe26iZeWVjWu2sE0+hWnBhy0LiSTG43scuDJ5rPiEq+Fj
JghwOagsU9TzbLjkxR3AXTbyp60ua/1VK5LLTiTpMOQDDzO6U4j3pPsITjF1
W/6bCAmx4U0dsu1+S9UAaVSxoDtoDaLJYPNVqyWsKpiIH9Hyqe0bwRUZtaIT
Jyxp062c4ZnO45WZngoSCJViq4v0iRCnBIfkQBgR5wTMQbqs8jqvy7TMpyuS
jiVSxqGgOBO453MDfKG0AhP7WQo6UiwrE+1bBDNejO/aE9WJFOCFMiO8BWmT
FmfQsRFDQ//kMpD0CUQg5jtOh1mIOvYnqJaOOW1xytEDaS25UkyOFVMw5h9V
LEyiGigmyEp/RBCH35rbjwu5DqV5H5Yjb4qF5LhBhEWAnEpbyNYvODYdybmS
O+xK2TAR0ZUjbNK7toPmkjBgWGxinhxHEe0aneNpyqAm2qWt/EQlvPydBKH4
6Kim0hqFirksbC5yZ0M6b6vOzCxdcZMgzuyhnRP51RUrx4cmKnzZCbzr8m7F
bEWsSeyf5BBnRxI6eqZp8Iw6myRaXCI5FpJDwkhUwKxYgQhnE9ditW62WEWo
FRF1iJEsmd+n8Cvh6/Ojg8v35+fSgv1Lef06j0kyF8cCmH0xAuvbjvddBIpG
EHCfvesc1uBmuiIW4BftaRynOzOcosq1ZlPH+LgzsGeSuz4FUOmCBsZzslgj
HJDjLz183OVcQpGt1WuTA4IjITvLvLrhyNh03UaujU4JjF6X075WrPtdw+IP
v0/uKiZCXUJOJlKjZwF8zQZKcTtO0Tl8BcLIR4oobfFyp1O1ELkgR7bLc+pP
2KVhZRQe52ir8DNqBuYcWE5jnNPOYNkGaeN4XskrNuaTdztoIvHXNXC4JhVr
uUI+j9OoDOkcDulkAvyosyjWIwSUuDLEMqG9QXc07qLd6qEtIYSq9XGlOvmG
BQV3wsEmb5wkItQ/r64zus5qA2zo5dblp83R7sqJkSFmSM3gks03Z/F9n2gC
+k7WWeRv5ZAPR34YGF7ijOA3YPK+nImpyK+XSfM80RZSzfzXbFaUK6RIsJVB
qZBXIP0kWtpIqvs1qa2NmtNusCxBBHC2tfg8vHoghjM1DAWrA2earxemzGcL
MR20KoIk7hIEpCBGDaGMozw68KOxGhjQnH/Ly96nc3uTc8VVHoTGG9jxsmRV
PE4PkOgVX3a0GYYYh1CQAB+RRHbjlnlMHgJ1dQKxw7ZkmoGlq17Npoc9qZWf
j/JCGveyUOSmOzs6P/18dsCpfWZB37ouelwFHhmaN+myEonNBzDINecI2kTM
jkSbndplmmpXc19FIzo6Yr4u8odzN6JHosS2PYhder7jvKxc5/lekJBi22vb
8pqyV0gz8JWQddKAgdgbURmJ16XhsewFc5cSM7vsaF8QMZzBBFV34G7NSdYJ
bjboMiIcr4VN7f+qMtksq9Om2gBONwqJCjQlvM5SZ+rWZejYapjNSUItDBuz
InUKBKfD/NhzV9TbUL66XtKG03qqpqndaRfgnqiHKBeiYbRQC4RTGFuR2qSZ
agEOY7qiFdQG6i1bHSXFW4lVJorBiOuvRJHA3alWIWX4GxOtQtBCcIubuJD/
E8O6pUMeF7QRF5BpTKfFEVqlQctmvVfVVLhuZCj8rSZAn8xwvZyI3Q7sXalD
TcIY6t2l2ra2U5CjNTAaPNKwgjtzp6G2SmfN1JG7tpxZf8MhNJINadKRlCgt
xehLKJRndz6lPzlwvmzYekTOdc46DWGQwnndlTfZfLE5f51D4XyydvPS+RSl
yBYbkuwbVjofGO2XqIZWMdzSeSaJiSIj5mgNIdiiSkCBCrGIavaFNpTrJbQB
uqJaQ91l85SNDLNW9giAk3OJAW9h4ALMrGYbrwGGSKPNynyX1ckl1hF6SB0Q
JM81OsyuCY1MI1IJmGOZKVPScLrQN059FthZJro854MfcrfymRrp0VCUxGQs
0nFXInhlcRfsUhwyou5xludBw6XeYOjjgjqH3E9RahxKYNHpLydHZ5enJ8e/
2p4TEZDTMzCufWUW2khLw1wZT0qJ71xBOeEAYA6+m3MFB/w+iJOwq8bV6a6R
0KiP78MPhW5iG1dxb5krp+44YWVT2jSrRNy+xdtRnBmO4V3FvgvfllCBSgtj
qxSKa9VZQIJIImDpSeoSRGZB5yjdkH9oeiymEh39IkVkwJKxnlHWd3ZCPq7c
FWJIp3vawz7CCq2phmvF11ZWbQQ5cm6tHeeyisQ+UMFdIiNIIp9OEwQrzSNM
6hvYUjmUhHOj6K9SQzMaVSl9B+kIYTuwlxQjLpZuGzUtO4p9mt75T/vJmHud
DyzXqtRPElP0QANsVQqX1brluKvDj7XnoN8xSNnoIPXSiTgDaZHui+p3iLbn
2h2+K54PpXZlB31UFQw+Rkt98Ts4v5naxri0FXdgYn8S7tmcLgoEAC6uP0V6
sXHqOscsh2ayrEgwCqVlVBwlNCCNr6/xL95lHGnVLCfqQR8DQIuV33FAcOVE
elcmlYjbX13BukoLCbFsl91rld0auTKcPrR/st9tdkUV1a+b2pKG7H1vz9pk
pBCkQG3WR/NwW0VQNNLa9Ykmhn27s/WSHqAf6CBgNYQbXGrdykIWy2tvndI8
WW03ze49NSYMunugcjMWHcsnRUexvB3DNy0UJ4XAU8J3jFqBCFYhzXltZnoN
c9/5njn32tfCeBlAitSJRMeZEE9wB2jhSJKV7lc+H6/dCxZlqBdcTJpnjGop
upLqzn7AZ+gHoLuBkohcnirgtFTGIwwOGwlb0ATOhvNIUg2ByCZ0ldKpbtKI
+etyR2vNjxW8Arqxx9ToEBAKTrTQt90+0xJ2u9xejMPTWH7DGg+K6XI2j9A/
8c3KuIgwqfGjkXfl8LNzEqVH9tnaWM9sT8sX913T5Wfv3AV5hwvyZ8mQty+d
P/litcjsUZmybHYgq+Xv3JKffZv3VgNIeZkQasRp9UiX6Hwu3TZJohiD4g25
/ve5CiyZ7xEtYoC2YM6DO4OxlWOdUE8jaupmmN5yz24JpUDzYxlFrJhoC+2i
LBA7nsOQDhMxoQAgatTEqBavyJDZq1Z0w8RsgGLpWVlLshVYoVhQSSYjZP8g
9WH1kjMis6Wqu335rj0/urA9XynSbX7PqWfcKKjdit7rQv2rOEZFzFDa6zxq
bG5cH9EoGNvJ7epLYEW1v77MtWb0vOCNzzV7oe/ag+Oj/TOOk4waoqNaeDFP
AkD3XMix73/uzWSN9uZ8TJXGEaVz1w/d+n7oA7C8LPVVphu+oWUJQxhK/7sK
J8C25kpstNKAhxJAkZVSPcRwHDyTgWS5aAYsba2DEOj/aZ9Ukl+7QddoYe4h
pi3MMXVoSc6T3HJXzk/6uxSpdIaoRn0RLfQRm+ldDD4NIBUQ5GqxgNdeV7P7
ui5s7alP++fnFz+dnX5+/9NuiIcfMqVD5m34WTk1DJ8qpsJaENe/jmr1x+RX
eBmvfc90Oj2Xc0ezcKIdc2pHymYgZlc9taizZEikUV1Hcp4uBHqQxbV8I2A/
g7ECMR98es7cHrUdk8qn3NeiISvRex5gKlA7SazJRPalpOw692iWoH+Ye8gg
/1m24Ve270tH/ye5hkZpOLZhlG1srLnvOYbt5BhRGXxRLwjo1VhQK6ok74ls
I09urVj3nqg3EU1H/Gs3UW+U0ifid8R3XPfn8YO+Ej/6M2mZF478GVeb8Kmr
2TSfuBxt15jgOkNKQi5dFlg5c6Bm5qZBd9D2QkVvFBNchNDpjJFeVFH7V9iw
45q+PLsHk7La1DM5RLRofqo7f1enmh3wpV6B9Z/ZPkGimb7uB+RorTXIacbL
ssoUJuEN9IbgpJjbdIhUXa7A70xx6pqM6gJLEWFXvlxiAua+O1rIa5V9zouk
WGxek+QIj/MJCUyjrfaRcyMHR9c7Wjx0/uRbO3hqPytGyHu3XKzcdaUVNtRv
vy2tHfyrTQ0aXSG63ni9/fJb3pCmEA++ofU7ARePSRG7TQSVEXAwHof6p46n
fleZq4eFxKso70EODO9spBBXLM+5u+c06sUUDga9SSZWWB+7N3scJCfEzYif
EGEgzoPmBIx4SC9MIiBE47mMk69IQLnT4H+R0jiDJG6ttIZ8pgfREJcc//sj
/qsVXk+IuB+xkEcSPAo5PEl9fpQsi7uq0f+nsur8cu1bNqjfzuFjVLF6XGO2
HRoz59pDrTJ+Eb4YuORK9wct4cC1oJHDGHFbKvPbb+jHrSlZgFOV3I+kYE6z
9bjr5P38j5JDpKIiv+M7LAAXRtoyw68LmWz2j89b4/Arm/NrfyQlfHv7xd5D
j/saqlYf33aPN5qNtzfX7jTeln7dlkbacXzTGomr7TYS1VrexDtX2eGBKguQ
7zV9XSU9KbfwULEFpCh1A2LDimJjsS6pq3ix60FcaAXkZoCo+mKGG8rUNkvS
YhRuqtU0wNguA0yl2BhLApWcPqsvfLB8S7TTNuT1vI5sMN25etMlDPC2R++/
eGF/NN0F+Tg3NcsnN9eEHX1n2EUWO5anJhV+JRJRZb2evqjg9w5tPVv0hT17
jsi4KxtuKs/RTScMuwg2XeKgJm/wR/zourDS5neDwb5DKWga792pNnrRN10B
1uVZsUHjut32VQ13zcNSMXFsojVjnfSfI3FCEe90fWO3Xww6ztQn9Rhok1ww
FJODipFklfvuE+OxelfW7H8QUTz60fITlJ9Lh19gdv2lKBEGfyQhZ7vsfDgI
zgci9rSvF/YsRSCPdi2QZ5ObxfCr2sFIWs3mo/wemUBfONKwWE6EnbMnVTN+
eSe4gqpewS5twDB1qxyP1j4n6O/LKDk1Dp1lwY0dozY08NngP9GyiM7xj8Ag
Z8MBBg6IyFy8hXgplcsbHSjsozYPQOrLjz/Y2Y87cplIALM/529FBwf+9V7a
j/hMCLlArZLXBFaAVr9wFk5mobQeCFzb/MDHTx/Y61MNJFCp3TUrpefe08i4
XYF3YgzIbOv1IXdtcCSpyr/NS6M3pfmkxlEjwYAFEaJIkqlKS0AMniRr+aAu
IGNjCWmF7XOT4lDYdofBIROiugtjFMhbVFBTyzM4L9hkmY9SiWt+SvEjdq2i
0CRDS6biRegdZ6IUn0K7TWtnRe5Ood2Gnj69oD7izC7u0DmgVf0SBhgOIvB2
Ko7eS/gMFlwBWGZjbN1l5HHWmLFCTosbcJME/sYI25bCy/lcGpJYiZFkcx22
uKeZpvyB2MP2yzhT1fR+kJV+T0M6I+r8cWSHMkxcA1MbLdlAA8d7ltvGicT7
u/Zt6+Ia8+EJs4QrNYgLjlpZcxwVLZ18q3j7shgxgKEDSPS+22pjhLzLWOze
CINJpUY9kVGO5AoGfDRdrlF+zZCg3PbEyuwIgwv2J9KMg6yzqGweV37GNcSA
fdJRltJv2R9SMz+Mc0ldCpDLScFWGgDTDcAi/S5voagzZZl27Dw9gJo9y3lX
eKTc37gigG8REt32KPjD5VRtb7GdVgJOmwPf+DTXFvQc3PL5ALY3MZMQ2cfM
/T3UrWl35osG9G+ThEHP0POvsATxq2RN2MZY4d/jTd3TQz8KseQSMW4sYrk+
bKtjclwufNUx/o8Y5zUN7Oah4bdevhZyjHgIJbGvG2zPeZu48455vWVTjgZt
PyQxP7iKDVojh8IBzOyA7sktHRDzLmcJA1SaqPm+d660kvODwSfGNvi+5Mc1
DqrJn1dgvbt+ez22Kfv6YCCYO7T7dazuHmanCSk+CCK5XLOdN8SKJiQL7HHX
w5Ie6iS3DUp7H0D/o3318oW+uO9jX/UshCsLj1mwxzbROg5h2FfbL7degyUK
7AXkvkA3o+mu2NeVEwVc7H0k9CByAN5OJzIy3nUhKQbMwLgH12yRlyzxzDJ2
1olHvpCOC8UIFA74d8el6FBVn5HTDS/TlU5YWywlxOxpVHmHqPJLF0YIubQu
klk+MpN8krLvLBExj8FSSmBtnUpzcalpK8od28xApt7Y92+fVwMS5IRBB3gA
R31hIBF/6flXr17QODgQEUwIHgRo407YNk/4fu15K1JrWdznM2kE8cNrM8un
09w9QJMssDgHLz22gStKgLBi0aK4aC13C0CjyZj1vd1dq+36GIkM1LFqKCby
tBL0LprZ80QTNMVdx77SSiWUcLjsKBllmkkLo61OtVAAlyItotLb8qxW3CeS
WXE5odaeelEE8vditXJegybHCgurAq+LpnAXneHDZJXrXTdKQ66H2TX5BCRi
zbrAdKHDsQ/wdjSzRm0kDl9fl/oGG+pRfh9Kc2nJmw2h/ZISv6DdwfKdSceN
qHxdtyrzpOIpbLYkWYJUsHavEeNrwjrjZTVDbQZBsjGi0jhfX5roqoFIrbDG
OzMHXQ60O+eAUComlXAK1RiYS8QiV6MPiPMhigD1JHb0djNrCctyfIEO5XdB
o+9lw95P+Bh/WR+Ln99xHIZZzYMs5ndiFD8/mcPIwzTy6/8Kd/n9UdYChUMF
QNlLb076sZK2/oAlSkScJQKZJE7gAmGrsnq5EEOCo3+eIqsPEmeFYqE0QOX6
EQk9Dx2OXPFmcCCirUuJXHYp8tw7seEgcKG/69q7JCO3zQ9ffQiDcFGW9CGV
Q4fXwiAj9UChGoUWZPNFi0KBCLHCrewtQm85xST0fXAXA2hEKmTNKp2Wl5Yu
Z9wH6rpEukixYB+hK4+ZScr7wld+X7FRyipQpjmbBEMTolq9vCKTEaLENKL3
tLIYJJHKHfKvR3GNDbManAV/tx+RMTO0G/79Hf/R5YS/3+JvrpBi/27+njz8
L/p9t+vvXRrC/rJ2udqrgHgG2YBXQffuZ/f3m517uzbEmijAj5Jc54eQS9gx
REh3khvoL+Tfg2Dnh/B/v3kpQxw07mJ7O7L4V9uvl5UO8fu21b9fvXghQxye
N153igNnV2IIJwPrcHLF441IhxuOOYCpWpoTcXtbt7O4Ep9npYLExtXEE6Gq
w0qh6EADqpwsLbfMKBtpvub2C/v+elHZE5IYe79vb23/CYB6XvWjYFY0FNMU
RZhIf3+x9fKNlRaaurjQesCd6ID9285ww4YHRyBNBx/36dkSdkCUaurKGF2I
95iu20yDY5ggilkMPIQLGnEaVQNwWqOby0+ZR8l3INoRzBwOcanV1IAvZp6C
iNaFpcREmcgP4tokl5Xb/fBC0eriLh8RuQK+ZBBPhfBydDl4jtcFYqoqU3F5
pJSjPt9fHyHOKzN0Vttb/qwk+eJ3PhYEBXDyRemqMgtW3yJEg+aV7oQur88f
AHdMSYdESicTrscYupyEBbH4zmTlu0qulImBJ9cwgmzvd1w2ApqUR+jLopjv
sDJD4jxh046tnHVKOk3zrpHTOSP2A0q7Io5Ve09tMMJBeIIsXxYwrJNWxPL4
gGMXsZlKaD6/oMEmDqMYviqmh5BURTDngmoh2XrybaLIcL0cTVALOA7QMhKh
x7ltaZ3Qe/p0wqkrgWWy4TM10XYTLkXArzSfFZ6+H7Eq7O8gvc3SunIlQB2v
VxeU1HIRl8x+iBSLzRscHu/hz30+0yo2RsEuLnEbEAge1T1bZTH6iNQ7aUbn
hZC8VJkBAj7hoVbHW8T+uD7Pepy/toR1MpWaBVH0gZN7E3/p4KhBpTjZAZcd
C9fNq96YVii0ypjcZ5LtuBC1YEyJs4mljarTJtUIx1K8044gwsOurXny0tYS
yiBXWym4nzOnYSI3OYrVR36lLa6ZonDjTBLpWORm6UvLQnA61asXyc4LElel
ibflHFis4w0Jx0gqTu+8qsbvDqSPI7YzJhGJwD+wFwefnp8dftzni8QikwRl
NjWq5w1lSveSeqExHQ6JPajXFAdDAinPInVu0ECPkwvzTFzwRKto2WNu1UaM
YwZr8JDToKe5S0rQMTm7fC5xJ1zvhu7Akdg6RyqMAddAETjZ7hUAIgLuwHu2
hB4LqzYVp6xXDfoioVQrJzQ9luMznKZc0RbqmftSw69mCGjnRrfa160nOqAo
XESj9KOzJ/k+iiTuB94jbCLnHXFiSpaCuPZSA2uU6zMWarncFvkoagcmdTu+
j6rNKp46iZPQgvhGkrRMkTPf+sJFuwxvCi3XW0prx31f/lhSgn7blQiBbPTj
s3E6rbJnX6Omp6r31NnwZp4TO4ma6jD/RF/JkbRKgiaq1YCNLxOMDr8S4p5A
pxmxBwEtVoWUVLv2JKv3Fwv7y/674+8q5zHwUQPgI8f5fHlvZyOLsNzk9fM3
9NwnPQ9QDGfTqG+EXRxki5vvKteXyqleqkDHKT+MJmf7h6fnrUUuCvSKYig4
H3GjDgpdXXijYFwYecVNuTXS1U0sUrAgcy/VrJfcGOWQEHhk301Xc5Jt/h/p
Tmm9C94AAA==

-->

</rfc>
