<?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.17 (Ruby 3.3.1) -->
<rfc xmlns:xi="http://www.w3.org/2001/XInclude" ipr="trust200902" docName="draft-mcmillion-mimi-delivery-service-00" category="info" consensus="true" submissionType="IETF" tocInclude="true" sortRefs="true" symRefs="true" version="3">
  <!-- xml2rfc v2v3 conversion 3.21.0 -->
  <front>
    <title>Robust and Privacy-Preserving Delivery Service</title>
    <seriesInfo name="Internet-Draft" value="draft-mcmillion-mimi-delivery-service-00"/>
    <author fullname="Brendan McMillion">
      <organization/>
      <address>
        <email>brendanmcmillion@gmail.com</email>
      </address>
    </author>
    <date year="2024" month="June" day="26"/>
    <area>Applications and Real-Time</area>
    <workgroup>More Instant Messaging Interoperability</workgroup>
    <keyword>next generation</keyword>
    <keyword>unicorn</keyword>
    <keyword>sparkling distributed ledger</keyword>
    <abstract>
      <?line 35?>

<t>This document describes a federated MLS Delivery Service (DS) for use in the
More Instant Messaging Interoperability (MIMI) protocol. The DS provides for the
delivery of KeyPackages, Welcome messages, and group handshake/application
messages.</t>
    </abstract>
    <note removeInRFC="true">
      <name>About This Document</name>
      <t>
        The latest revision of this draft can be found at <eref target="https://Bren2010.github.io/draft-mimi-ds/draft-mcmillion-mimi-delivery-service.html"/>.
        Status information for this document may be found at <eref target="https://datatracker.ietf.org/doc/draft-mcmillion-mimi-delivery-service/"/>.
      </t>
      <t>
        Discussion of this document takes place on the
        More Instant Messaging Interoperability Working Group mailing list (<eref target="mailto:mimi@ietf.org"/>),
        which is archived at <eref target="https://mailarchive.ietf.org/arch/browse/mimi/"/>.
        Subscribe at <eref target="https://www.ietf.org/mailman/listinfo/mimi/"/>.
      </t>
      <t>Source for this draft and an issue tracker can be found at
        <eref target="https://github.com/Bren2010/draft-mimi-ds"/>.</t>
    </note>
  </front>
  <middle>
    <?line 43?>

<section anchor="introduction">
      <name>Introduction</name>
      <t>TODO Introduction</t>
    </section>
    <section anchor="conventions-and-definitions">
      <name>Conventions and Definitions</name>
      <t>The following abbreviations are used where convenient:</t>
      <dl>
        <dt>Local Service Provider (LSP):</dt>
        <dd>
          <t>The Service Provider preferred by the referenced user.</t>
        </dd>
        <dt>Remote Service Provider (RSP):</dt>
        <dd>
          <t>Any Service Provider which is not the LSP.</t>
        </dd>
        <dt>Hub:</dt>
        <dd>
          <t>The Service Provider which created and hosts a referenced group. Group
messages and Welcome messages are always sent to the hub for sequencing and
fanout.</t>
        </dd>
        <dt>Follower:</dt>
        <dd>
          <t>Service Providers that interact with a hub to allow their users to interact
with a group which the hub hosts.</t>
        </dd>
      </dl>
      <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="partition-keys">
      <name>Partition Keys</name>
      <t>A partition key is a short secret that group members export from the MLS key
schedule. Whenever members send or receive group messages, they provide the
partition key for the current epoch. Messages sent with a given partition key
are only provided to users who request to receive messages with the same
partition key. (Exceptions may be selectively made for external commits /
proposals, given that the sender isn't in the group yet.)</t>
      <t>The partition key acts as epoch-level access control, in addition to the group
ID. Users which have been removed from a group may still be able to message the
group, as they know the group ID. However, they will not know the correct
partition key.</t>
      <t>Service Providers <bcp14>MUST NOT</bcp14> implement hard-and-fast rules about which partition
keys are acceptable. Instead, it should be considered as a general signal of
abuse or spam.</t>
    </section>
    <section anchor="endpoints">
      <name>Endpoints</name>
      <t>The following endpoints are provided by a Delivery Service. All endpoints
exposed by a Delivery Service are accessed by third-party Service Providers, for
the purpose of learning about the Service Provider's users or interacting with a
group for which the Service Provider is the hub.</t>
      <section anchor="key-packages">
        <name>Key Packages</name>
        <t>It's assumed that users have already interacted with a Discovery Service to
learn the user ID and preferred Service Provider of their contacts. As part of
discovery, users also receive a bearer token associated with each contact. The
bearer token may or may not be unique to the user who requested it, depending on
the RSP's preference.</t>
        <t>When a user wishes to fetch a KeyPackage for the purpose of adding a user to a
group, the user submits a <tt>KeyPackageRequest</tt> to the RSP, with its LSP acting as
an OHTTP proxy:</t>
        <sourcecode type="tls-presentation"><![CDATA[
struct {
  opaque user_id<V>;
  opaque bearer_token<V>;
  ProtocolVersion version;
  CipherSuite cipher_suite;
} KeyPackageRequest;
]]></sourcecode>
        <t>The <tt>user_id</tt> field contains the Service-Specific Identifier of the user,
<tt>bearer_token</tt> contains the bearer token learned during discovery, and <tt>version</tt>
and <tt>cipher_suite</tt> contain the desired MLS group parameters. The RSP responds
with a <tt>KeyPackageResponse</tt> structure that matches the requested parameters:</t>
        <sourcecode type="tls-presentation"><![CDATA[
struct {
  KeyPackage key_package;
} KeyPackageResponse;
]]></sourcecode>
        <section anchor="privacy">
          <name>Privacy</name>
          <t>Several <tt>KeyPackageRequest</tt> structures <bcp14>MAY</bcp14> be bundled into the same transaction,
if a user needs KeyPackages from many users of the same service and is
comfortable leaking that these users are associated.</t>
          <t>Note that the <tt>KeyPackageRequest</tt> and <tt>KeyPackageResponse</tt> structures are
exchanged over OHTTP. This is done primarily to prevent the LSP from learning
who their local user wishes to contact, but it also restricts how much the RSP
can learn about who wants to contact their user:</t>
          <t>To prevent abuse (such as constantly exhausting a user's uploaded KeyPackages),
this endpoint is protected with a bearer token learned during discovery. The RSP
can construct the bearer token however it feels is necessary to preserve privacy
and manage abuse. If abuse is a non-issue, a bearer token can be long-lived and
shared by every user. Alternatively, users may be provided a uniquely
identifying bearer token. Bearer tokens that are abused may be invalidated
at-will by the RSP, triggering users to go through the discovery flow again.</t>
        </section>
      </section>
      <section anchor="sending-messages">
        <name>Sending Messages</name>
        <t>When a follower has a user participating in a group, and that user wishes to
send a message, the follower issues a <tt>SendRequest</tt> to the hub:</t>
        <sourcecode type="tls-presentation"><![CDATA[
opaque PartitionKey<16>;
opaque ServiceProviderId<V>;

struct {
  MLSMessage welcome; // Welcome
  ServiceProviderId service_providers<V>;
} WelcomeData;

struct {
  PartitionKey next_partition_key;
  optional<MLSMessage> group_info; // GroupInfo
  optional<WelcomeData> welcome_data;
} CommitData;

struct {
  MLSMessage message; // PublicMessage or PrivateMessage
  PartitionKey partition_key;
  select (SendRequest.message.content_type) {
    case application:
    case proposal:
    case commit:
      CommitData commit_data;
  }
} SendRequest;
]]></sourcecode>
        <t>The hub rejects the message if the <tt>group_id</tt> of <tt>message doesn't match any
known group. Otherwise, the hub sequences the message to the provided
</tt>partition_key` of the group, and pushes the Welcome to any providers.</t>
        <t>If the message is a commit, then a <tt>CommitData</tt> is provided which contains the
next partition key in <tt>next_partition_key</tt>, and an optional GroupInfo in
<tt>group_info</tt> to support external joiners. If any Welcome messages need to
be sent, a <tt>WelcomeData</tt> is provided which contains the Welcome in <tt>welcome</tt>,
and a list of service provider ids in <tt>service_providers</tt>. The
<tt>service_providers</tt> array <bcp14>MUST</bcp14> be the same length as the <tt>secrets</tt> array of the
Welcome message. Each provider indicated in <tt>service_providers</tt> corresponds
one-to-one with the user at the same entry in the <tt>secrets</tt> array.</t>
        <t>If <tt>group_info</tt> does not have a <tt>ratchet_tree</tt> extension and the hub is unable
to infer a ratchet tree that matches <tt>GroupInfo.group_context.tree_hash</tt>, the
hub rejects the request such that it can be retried with an explicit ratchet
tree provided.</t>
      </section>
      <section anchor="welcome">
        <name>Welcome</name>
        <t>When a user of a non-hub Service Provider is added to a group, the hub first
contacts the Service Provider and lists the <tt>KeyPackageRef</tt> entries that were
indicated as belonging to this Service Provider. If the Service Provider
responds affirmatively, the hub pushes the Welcome message.</t>
        <t>The first step is done by sending a <tt>WelcomeInitRequest</tt> to the Service
Provider:</t>
        <sourcecode type="tls-presentation"><![CDATA[
struct {
  KeyPackageRef key_package_refs<V>;
} WelcomeInitRequest;
]]></sourcecode>
        <t>The Welcome message is provided as an encoded <tt>MLSMessage</tt>.</t>
      </section>
      <section anchor="receiving-messages">
        <name>Receiving Messages</name>
        <t>When a follower has a user participating in a group, and that user wishes to
receive a message, the follower issues a <tt>ReceiveRequest</tt> to the hub:</t>
        <sourcecode type="tls-presentation"><![CDATA[
struct {
  PartitionKey partition_key;
  uint32 counter;
} ReceiveRequest;
]]></sourcecode>
        <t>The <tt>partition_key</tt> field contains the partition key that the user wishes to
receive messages for, and the <tt>counter</tt> field contains the number of messages
the user has already received in that partition. The hub responds with the
following, which represents a series of messages in a series of epochs:</t>
        <sourcecode type="tls-presentation"><![CDATA[
opaque MaskedPartitionKey<V>; // = Hash(partition_key)

struct {
  MLSMessage message; // PublicMessage or PrivateMessage
  select (Message.message.content_type) {
    case application:
    case proposal:
    case commit:
      MaskedPartitionKey next_partition_key;
      optional<MLSMessage> group_info; // GroupInfo
  }
} Message;

struct {
  Message messages<V>;
} Epoch;

struct {
  MaskedPartitionKey masked_partition_key;
  Epoch epoch;
} HintedEpoch;

struct {
  Epoch epoch;
  HintedEpoch hints<V>;
} ReceiveResponse;
]]></sourcecode>
        <t>The <tt>epoch</tt> field contains a list of messages sent to the requested
<tt>partition_key</tt>, skipping the first <tt>counter</tt> messages. Messages sent to other
epochs may be provided in <tt>hints</tt>. Each <tt>HintedEpoch</tt> structure contains a
masked partition key and a list of messages sent to that partition key
(skipping none).</t>
        <t>The same epoch may not be referenced twice separately in the same
<tt>ReceiveResponse</tt>. No order between epochs may be inferred by the order in
<tt>hints</tt>. However, the order of the <tt>messages</tt> array in each <tt>Epoch</tt> does reflect
the order that the messages were sequenced and should be processed.</t>
        <t>The hub <bcp14>MAY</bcp14> proactively push <tt>ReceiveResponse</tt> structures to a following Service
Provider. The hub has complete discretion in which epochs it provides in
<tt>hints</tt>, and when it pushes <tt>ReceiveResponse</tt> structures. In a group with
encrypted handshake messages, the hub may choose to use these features
sparingly. In a group with unencrypted handshake messages, the hub will have a
clearer view of which messages need to be delivered to which follower Service
Providers and can act on that.</t>
        <t>When processing Commits, users <bcp14>MUST</bcp14> ignore Commits where <tt>next_partition_key</tt> or
<tt>group_info</tt> does not match what was expected.</t>
      </section>
      <section anchor="external-joins">
        <name>External Joins</name>
        <t>A user that wishes to perform an external join to a group may do so by sending
an <tt>ExternalJoinRequest</tt> to the hub:</t>
        <sourcecode type="tls-presentation"><![CDATA[
struct {
  MLSMessage message; // PublicMessage
  CommitData commit_data;
} ExternalJoinRequest;
]]></sourcecode>
        <t>If the hub recognizes the <tt>group_id</tt> and successfully validates the request, it
sequences the message to the most recent partition key of the group.</t>
        <t>A group does not require a published GroupInfo to allow <tt>ExternalJoinRequests</tt>,
however a user can request it as follows:</t>
        <sourcecode type="tls-presentation"><![CDATA[
struct {
  opaque group_id<V>;
} GroupInfoRequest;

struct {
  MLSMessage group_info; // GroupInfo;
  optional<RatchetTree> ratchet_tree;
} GroupInfoResponse;
]]></sourcecode>
        <t>The hub <bcp14>MAY</bcp14> provide an inferred ratchet tree in <tt>ratchet_tree</tt> if one is not
present in the <tt>group_info</tt>.</t>
      </section>
    </section>
    <section anchor="fork-termination">
      <name>Fork Termination</name>
      <t>The endpoints above are designed to gracefully support forks in the group state
through the use of the partition key. Forks can occur when a buggy or malicious
member sends a Commit which members of the group are unable to process, or that
members of the group reject for violating policy. In this case, the
malicious/buggy member would process its own Commit, moving to a new epoch with
a new partition key, while all other group members ignore it and stay in the
current epoch. Forks can also occur when a member attempts to externally join a
group, and the Delivery Service sequences the external Commit to an incorrect
partition key (such as one resulting from the previous case).</t>
      <t>When a hub detects that the group state has forked, it <bcp14>MAY</bcp14> decide to terminate
one of the branches by blocking further messages from being sent to its
partition key. When or if to terminate a branch, is left to the discretion of
the hub. Users <bcp14>MUST NOT</bcp14> respond to a branch termination by automatically issuing
an external join to rejoin the group.</t>
    </section>
    <section anchor="policy-enforcement">
      <name>Policy Enforcement</name>
      <t>Generally, a hub or follower DS is only able to enforce "negative" policy on the
aspects of the group state that it has visiblity into. "Negative" policy
consists of rules for rejecting messages which are unambiguously invalid.
Examples of such rules might include rejecting application messages from a user
that is muted, or rejecting a commit that contains an Add proposal for a banned
user.</t>
      <t>Keeping in mind that the group may fork when there are buggy or malicious
clients, but that clients clearly indicate which fork they are sending their
message to, the DS must always make policy enforcmenent decisions with respect
to the group state as it exists in the indicated fork. If one fork of a group
exists where a proposal was sent that updated the group metadata to ban a
specific user, but another fork exists where this proposal was not sent (or not
accepted), the ban must only apply in the fork that accepted the proposal.</t>
      <t>A DS <bcp14>MUST NOT</bcp14> reject messages based on criteria that are not unambiguously known
by the DS to be satisfied. In particular, a DS can not enforce a per-user rate
limit on messages sent to the group for any users that are not local to the DS.
When the DS has a local relationship with a user, the DS can authenticate the
user and unambiguously rate-limit just them. However, a hub DS can not
rate-limit a follower DS's users without speculating on an MLS message's
content.</t>
      <t>It's understood that hub servers will make arrangements with follower servers,
where the follower server enforces the hub's policies in situations where the
hub can not, as a precondition to interoperate. This includes rate limits but
also for example, if one of the follower server's users are banned by the hub,
enforcing that the banned user is not allowed in any groups hosted by the hub.
(Noting that the hub would be unable to ban a follower server's user themselves,
in cases where a group's handshake messages are encrypted.)</t>
      <t>Ultimately, while a DS can reject <em>some</em> abusive messages, clients must be aware
of the policy a group is under and enforce it themselves. Messages which violate
the group's policy <bcp14>MUST</bcp14> be ignored and supressed by the UI, as if they were
cryptographically invalid. Clients <bcp14>SHOULD</bcp14> report to their local DS when the hub
or another follower is not meeting the preconditions to interoperate.</t>
      <t>A DS <bcp14>MUST NOT</bcp14> enforce "positive" policy decisions, consisting of rules that
require a given message to be accepted by the members of the group.</t>
    </section>
    <section anchor="example-flows">
      <name>Example Flows</name>
      <section anchor="creating-a-group">
        <name>Creating a Group</name>
        <ol spacing="normal" type="1"><li>
            <t>User fetches KeyPackages for all the initial group members it wishes to include. (<xref target="key-packages"/>)</t>
          </li>
          <li>
            <t>User initiates creation of the group with its LSP and provides the Welcome message.</t>
          </li>
          <li>
            <t>LSP (now hub) fans out Welcome message to all follower Service Providers. (<xref target="welcome"/>)</t>
          </li>
          <li>
            <t>Followers begin reading messages. (<xref target="receiving-messages"/>)</t>
          </li>
        </ol>
      </section>
      <section anchor="externally-joining">
        <name>Externally Joining</name>
        <ol spacing="normal" type="1"><li>
            <t>User requests the group's GroupInfo and sends an external Commit. (<xref target="external-joins"/>)</t>
          </li>
          <li>
            <t>User can immediately begin sending/receiving messages to the new partition key its Commit created. (<xref target="sending-messages"/> and <xref target="receiving-messages"/>)</t>
          </li>
          <li>
            <t>Group members that receive the external Commit will verify it, and if verification succeeds they will begin processing messages from the new partition key.</t>
          </li>
        </ol>
      </section>
      <section anchor="self-remove">
        <name>Self-Remove</name>
        <ol spacing="normal" type="1"><li>
            <t>User sends a <tt>Remove</tt> proposal to group. (<xref target="sending-messages"/>)</t>
          </li>
          <li>
            <t>User informs its LSP that it no longer wishes to receive messages for the group.</t>
          </li>
          <li>
            <t>Assuming this is the only user the LSP has in the group, it stops requesting messages for the group / starts rejecting message pushes.</t>
          </li>
        </ol>
        <t>After sending its <tt>Remove</tt> proposal, the user <bcp14>SHOULD</bcp14> continue receiving group
messages for the same epoch to check that it's proposal was sequenced before the
next Commit, and resend it if not. However, this isn't required.</t>
      </section>
    </section>
    <section anchor="iana-considerations">
      <name>IANA Considerations</name>
      <t>This document has no IANA actions.</t>
    </section>
  </middle>
  <back>
    <references anchor="sec-normative-references">
      <name>Normative References</name>
      <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>
    <?line 423?>

<section numbered="false" anchor="acknowledgments">
      <name>Acknowledgments</name>
      <t>TODO acknowledge.</t>
    </section>
  </back>
  <!-- ##markdown-source:
H4sIAAAAAAAAA7VbbXPbRpL+Pr9iTvlgKSVScZK63VOy3lUse61bv+gkeVOp
qytxCAzJiUAAiwEkc13Ob7nfcr/s+umeGQAklXWubvMhFoF56enXp3sak8lE
ta4t7Kk+uKrmnW+1KXN92bh7k20ml431trl35VKf28Ld22ajr/EgswcqM61d
Vs3mVLtyUSmVV1lp1rRS3phFO1lna1cUriona7d2kzzMn3iZP/nqK+W7+dp5
T2PaTU0TL17cvNT6C20KXxFBrsxtbel/ZXtwrA9s7tqqcabAj4uzH+ifqqG/
rm5eHqiyW89tc6pyIupUZVXpbek7f6rbprPq/lR/o0xjDa16VteFI9ppV8+H
vbKmmNy4NR3poWrulk3V1TTuTdVYfVH61pStfmO9N0vw4aJsbVPVtjFzV7h2
c6Du7Ibm5adKT3RpP7R6aUt6jQ3wqCtdVjX8p69Nc1dgldz5tnHzrrW5Lmy+
tI26t2VHpGv9mwnQWth38CORjyF/xgp4vjauoOcQwJ+cbRfTqlniuWmyFT1f
tW3tT09OMAyPSEDTOOwED07mTfXg7QkWOMHEpWtX3Zym/tDY8uuvnn51EoTN
IvYYUpAEfDtYPQ6dyuSpq8aTTj5LX6ardl0cKGW6dlU1YDbtpfWiKwrROiYp
N6V+k72RhQ54hA1MmMvrtM2flngxzao1rVpWzZokdk8CUNDm/peaTCbazElc
JmuVulk5r0nTuzVppc6tz0iMlhRJL2wOqZNA37y+3jEXfXh+faRpYd15Swaj
25VVnylhffjm4s3Fka6bqq2yqpjqm5XV59d4cO+IBl4XC0am6Wqh/2I3lya7
M0vrj/WPtqCDWr3mTfAEms+aplf0p1+ZO3tietNQceQ0sGDt8rywSn0B8poq
7zIepm7enb/bevSFfl6VpM69iZ3bhSsd/wYLLRFcFNUDDmvmJJh7F+2RGEIM
yvXDytKfGa/jaCmSxOsqM0Xi56WcvdGHr68vj07VKTNl523d2IVtGlpxvgGL
NP+2ZUZPaKOGjndl11W7Z+rhVVj4rNzsvn1YuWylSRnKquWFiQxa7BVZx2O0
yJSM3BC0BHxZVb6F7gyIYplMxYRhwUEMPHxbiswuUzyYjdce+thWTApZGauE
t3/raFVmc5nTagtTVl1LZL5k/sNhnu7Q6WkN05KOkhaSzusHMluiEYvS+gYT
sYtjVcboKo2lLcJoUS05cSSJTzsVBSCnqeE1Pfm599c3cOn4V799x39fvfiP
9xdXL87x9/Wrs9ev0x8qjLh+9e796/P+r37m83dv3rx4ey6T6akePVIHb85+
OhD9P3h3eXPx7u3Z6wOxyKFpg7V0srmVw5EesdC8ijafY84Pzy//57+ffqs/
fvyXq5fPv3769N8+fQo/fv/0d9/SD1LkUnarymITfhJHNoqszZoGqxBPdWZq
11Lgo7EkzFX1UGqYALHry/8EZ/7rVH8/z+qn3z4LD3Dg0cPIs9FD5tnuk53J
wsQ9j/Zsk7g5er7F6TG9Zz+Nfke+Dx5+/0cKjFZPnv7+j88UfMilaVp2GfBk
5DbOdJ2eQHscDIcY1bSk52RUraitKN7aAg54bT/UGLBoqjWrIVwzTVY+W9m8
K+xU/0gCseQz0xQypBzAorGZJWeaFoyOE7KLnped7pis4Ip11pHXIT2ydZWt
psG722Cn0Uho/XJ8LKAU0ZSwRQ4tFEN7WFVEFZm0Z0uPBCZvwKtib08BcUzW
VB+++JDZWrzs2myg2N4WNkOYo93WJrdMOwEY25TkaMnTrB15pxNFlNSVZ90U
ipnRvBHQGamwL5+0IagFfm1sOz0SUx/zh7yEh4ozXyYFsb6gZxmdAd6ewkhx
zCaR5zInuDReVV2cT/X7wAt4lpWh888tkdSQE78nZrGko/vBOX1L4R6nNfOC
LTqwi0XHw9jiWKp3pbi2MB27vSIvSdoRxP6AteDw00iCdiSHdovbSu061Wiz
2q3rwrKPWZkmn5BrmCwMibQhfSTWzMlDh+OlRYExg7fPIEWcZcrIwZqc+NXC
ELoixzmBfbEjeyuwgtFoob1bQqzVQpk5MAjiQ23WU9jaizKvK/JzO9HZxhe8
eVJJiqVmB+JM9RlxJ81QsD3/2OB0GO9jbHbEDJx4N9iS4pFqKvC77hqsCoBT
kPcsBUKAZe2ekPvEB9OpmhSjMEPsT8TPWt8Hqp2o7XwMYGDVF/BGOgIrpS7a
J1BnT0EjF7uQDVkzTUGxPt+krYFrxPLPnc+qET/aSvGBeDOsQerHYaNHMDuk
ERMkEMNyYFgkAs9aAzHncY/jQBPSquQ1DOkKyYCcVXVH9kNHqDJnEonWAKrI
sow31Wg4LIvYhn9gDqR2lOaQZ4rmygcY+CtEy/ZYSz4HCZBOYxxBLOJfnfAP
sRgOmaiTFZxfWUYYC9tmYFyPapOnHagEvAYUQmYDrUQTT0Rxzsmga9avdSVU
ziL5RNax8AFDCdnpoDgU/ynDePfq5uYS1vBhQ7j0l19+0W3hJzWSZWIYGyzl
CwSH9UdCRFVtwBnsfuvy7//67Lv+oTD1lpka3lwGlP9XEhn8yb38i1fPXU2Y
4LpzBFcz/vvW48d36pPeOcx3IEzseRb2numFs+QlWK6u9EOFn1zXNnMLl+kL
JNz0V1IwJv1YzYbEzsaLjJSD9ZgknndNyHWjHkKfZ+FAM8W/hudIi/KaBLRc
E9IpsVTSbIpsZEteUiASEymYrytKYFSwrJFU8crTsiKNDpAOJkrJXcZ6xflA
VNB+9c8Q6kAPyTff1vL3tiBk/yCJL8h5hMIK4sM9e+V9SpiopaBx9hOMa96V
lHwBcQYFRYTXlJKW3nDSdazcIqp9aS3B6kH6J0FxbSiNCd5w0S/ioz8mYTiv
KOqTXXGAgRy5nBDDvbfRkcB3J4dBNvsWCVRCBfvOxLL+VdHwshQ0MspHl3RW
qIxYGoRNXpjReYko5NamcQRaiBkkn3vOfCQDk6PGyKDggcRDFpw8bjmV4N+O
ib8tgmhwkCjNAKUQCNfrLsQF0jWVmaDcKUpX+sEgOvaLDVIjUqObnkKJuoce
CxoGO5z30zHsh5XpfNt7LoStuqgMQu1AjkfHinOUGGLBEdQE7DCyfJYlJvPh
IzEprNk7prwS+APmLKwtWAilRdQ2TeQ/NIilwpoNQZOqwTD4xARTFuHsjNjL
qpw4ipf2eJtYkEK6XlTlcgKwwCmy8gSSBCFYjpectBPSYJQq4DXGtwBrE0ox
ISgVG+XEp23AheGmU/3D4FfIfFm951yGCEu68t4UDrXFXJl2wjAw1BM4VJDC
LJeWeZxy4iVUj9zWUvQn8V4vkECbJbk5ARTXISTGFCGFwEVI0glM+GjcDAnJ
ZxpWFwBlHUFsOQAgvZIrzmdMhL0SCdPKLAkOhqBiOwyi1PeIKwzxKyVppKbf
P/1XCmDhRYgqEapcSNwbelBy6+HE+kHqGt/pk5NY46ABO0tEX3VbR1zIi36K
c85Na8Z7DMnj2uxtgtS35LYlEOOXKb7v6XkmLL1FIZBp4mLMBYrcg/GDTZ/F
E9zmTMIn/ZyTp12CBocOAuENLrt54bL4hnANx4nWhifbJ9k5hGRy+nAgxGlY
fwq/RGK7RY34iInQZGpkjoNq32n/NCZ7g0eSCcoDPThaeBEOrfUnOviAggEA
QfWnsT9beFUoVszBnASiWeA3ARQKTbP4Nq8sJ5Ycrkm/NwppVxlLZO9oakN6
HnQae4SClx3vErQ5+gU1G/FvFsPhwI7qzkd8EGtuAJNlysob1LEuFuPDwI6E
JUwRbHPWc2sW3LX4plALHGAoxXcHWzWOUs921XYmRJK7jMrYayhNUbNefdmU
fVdzFSSl9j9T9GAQBddMh9qpKwJCwHdwkaBs4apnA33/R0dJC4L+YBqzYw4N
RhfOIz1JwKNOiRahFkzYsfKZJCB7XpCrbshDc2o9tz2oKWy5bFchr8eKqA+l
4SJvtXXqqX6BnKcnh7xyxgnRfqIk9Q/gk3DJpK0mgCepCsN+OBZKQBVxstnE
MskWUaJOI8lB/Tm7klxSzxqGrWTJjSXgBGmWnCGI5xcLIMF0JdCb4rLsAiTo
MFFj4hgBz5LiTGVr9hYf2imG3lLcWc1Yl9W2Bcc6lBd8ZBg/hQhOx2pcQiQl
inDkaOh9oEMxHVF/JAhGtz9K/5DRMWDA7vsSc8r3pECWomAqf7vGtyrmxfsz
e/AN2uh3UetixtJyNkACipVW9RpBijW3ACoMjyspHW+vz+a1b2MV1UabBdG5
TjAmEr/H/UQlDQUanI6gs60TKiY44gOQ6I31onTtdlAP1KhIzW9Kdogzw3zn
lhL3rSA82HIQALaOMfIfADekJGVW4desD5EzUY0rrlj8ExFSXxL5RyBJSNkp
F/wKTnoMjOyE8I4A/Tdfk1PpUCwCQ8ebDdP5rfi1J6kfh5GUmT1y8OT3KfU7
Tu5kFmjZu4Hct8NC42SVNmBhhNJX2CIXt2cGAU5yEPErwRyi61SpAHkcoktj
A1e56G/ZMAd7i5j751xcfjSNDxD1jfF3Nh8hWNJkwLE/6Ffk+Q5HbD76/8Fx
EamFJ/80lLZ7uEfwL/77rRgYQC+M24K3Y55E1/AC4tgauUvfmh/tUsizRaRY
7BWqqfmeJUfj9HCcXqEgHYhJZjUqzrBd8dwdde8hS1K34WVrKiBt48pj7e9c
XUsFJfrs3qjSBfvW3RAtWwHZKlHinawWaITPMwuIZTY46bDU1R9ACWu3b2JG
cGzP2cwWHFWH6UAUlO1RCEaCbZjPg3rw4Eq7fUD08xYFthaXTQEC8TXVbEse
dKq3xIEGAXpu2wdc7ow5wahmcKMvY4F7I1uGlzbhdcD4MbdIWJBI4VL3LLCP
QRfRDitV/fTkQfvLNvQnxHxDbvP7OxgSltxsTPv8B6U8em7ijRuCvN45/bAe
xrimv4vZDty9A11xPQnXSq0UGgiBQWZ0OHGfgYEEwVLLSM8v8fi4mOYBgj1+
jTDcPPVX/OSzFfGg2dRARqmZZHxjymRCftmqQq1e7jRDUXFhDa+r0B9FJy02
OzsQqP28Pbg0I4BZZYXUdu6dfYACCC+2kxzIK/TNyG8ZlqL/NtulFQNQF9W+
SsJavLcIgoe4JPPzsTjFOYpblmj5Ca9Ck8u+DI/UTu1PBiQZfmBQaviCm8t/
ApVexAzv3ynD4ztzuQjh0ansWdsGHU4CzQcp4QBIs6xySh2rAbDE1ccsboEd
/m846HNip3q8zvBJ7yEhePEAuAVUZNWydH8POHpQYmBT7fjqEd1jGx1re6PM
Breq6lfrCesKl7ZkJuV22j4sKEwhBeFpkiG2cCgykrXRoUku+SCDT002+3hN
5qpiUTYAXqhiTMdQxPZBdz/nGiNAocicECITLYm7j8jvMYwwKqxdSdZ3Q0nf
Mz3MYbe22onHA6/JzRam7H3/KKVFSBwnx26hkRRJe5YKp0+p98Cw+Pr7ZdXc
6RvbrF1pQlfbyg7vvufVvdxY405qWYqfWDYms6JBscJCZnXnx40QnphOyfig
EtzJXeUOTJ8yHZ7lWWVZ14hPNnreLZfhuhV5dNV5Jc0qbJgAKGIrycFJI8tQ
C6Wxrow9EMFNcQMtnIPaO0fyfb5nvXdVIQlVXREN4qA56wX2lBJBou5ECA40
PnBQDDvyfSpqeM9DnWxd3YccmjJ9ctOCIzioyIMRizgdKCw3TDFI2mr3Cf7V
SRczsT5iDbXVjtNzmu98RuwOdJu2teta7naimyRRs6NM18oxV9ppbxh7juRm
g6C4mEik7e0e6e+IoMKkul3BnE9NTLhRAp+Z90f9lTnsJbdtqNEEwDLQQsYJ
UFErPSOwrdxm3MdEbifov0UxKyrCvDElF4ooCsyLKuP7wEXXMO/7tBGUzS3e
RfRIct7uQGIq0YixGG0HBeddjmGuhV0kZD1AMtVCxSaM0ACU2mlC9igqJCul
xTEV7SddW6HKkrEEkc6HaLYT/kjlq6H5snu4ZJXXL9AXnHHnjlJ/lq4aVG2E
8XSwBBnOr3EU7uKKFmdlsj4o7ZLrPQfBkgRBWGV8zYIbWaCILZbXIL57592c
m4JxFzzVB2+31uPedy5q0UrSUrTgbjbYMiTUI1j2FsExrOdu2ZFOMTrngDhV
Lz4YYEpeiVVSllu75Qq+NCu63A4WHmSqW6ohgUrJOWgBtL0f6xFVMcjLYfvU
pdRneZ7SXT4KSdmU5INV6N/9i7V1KPWQ0PNt1QeSgdKLebcMuXDoPV41K9Bq
7OU+WAiRJ5qhJPNGSoAJJNK63BlmGpvqb3wDrHq0IOiUlGLN31dIv+4a+DWo
gCgHKZb0lGfOc5seA1+oN+ci1Y5eGEb09gNLO2htX6MEbVyChDkzoVxOlUa6
MEkAqOn5C0gpJsx1spqvPIfMtK0BDGPcDO+pfGwb4SYR5pwpxTfzpqOdOGKM
NgMc4g0PSRKI1dLgZvMj4Ro2YbaJNZGKpfQxMB8XtmFOvObh5Rl4EdMHjoLD
WVLNucENLylr1jhyA870t7+gamwUfPOkQsZJq0re4Enb/cIR/EY8lMpjVxgU
0TAI8QVLReM3gN4TBm3IhFXhoPFDcxkWFvrutL5zY0Sh9DSE0efXU4kDgUCp
iMqQxhbSX79ydewTEHGFwRwIO9xZtaLe8Ehyf0EGNeYEKJ8I5T9DMDR0PUi5
xRv2h1eD8WboIlNvHghCNwU0qQsog281uPMnsOaJV6FENg1Ndx1aT31bVcHi
5f6vuZclCSCwhSHLL5fstINBJRLC4GMVddNuv4uCSx2A6FWDyTopOXrXduHD
hbQG35SEsx9LB2aNXKTs+1ld+r6jtbG3RbypZ+5q5paHLSmGJ9KXy874OELb
ECe2KE5MZQ/HbjKWSYiuYyUHGjb1xFEs7fA5A6cfUmqC6rEiem7fHy03VYdv
q3a0GKfgsQrS4012FY/QygrkbXFPabxyJYOa3jPx3k/8npyfj5iKAmg2fk84
ac0VpoQToyIG2//SV2v7JTd3DOvex8nPs6tBs/ADmpEiShcvHVNjF3SPbSOa
tmsH5xiU9CROCHy2Kpl1VKT+7lKgaygkdchYfM/s9xesSnJdvpHbKD54RUlI
vYrAJgRu/TycJnTwN5aTk3bcC0WciRERYlPsZ6LjTjcfUnOwto1lzKEy+x1t
3va5CfaQS3Yj2JPC3LEOiIXtPmIWzkr6PFn6zgcJ+Nz2Xj8waV8OI93NYjr6
JZJirpM8xzc4AjvkQxv1VHCl9JnarfY5sIYcisRXOgZxbyvvGJZXgi1P9eHH
jwR8J+GuzH/6dKS+DtvIMig58OdAAnEHXn/ce8pdwKFut/dS8JspDzxEVzrJ
8ggf+hAjyKluX7xJcWGnutW3WjPZ4c4eFH+LZEkG49Jz6WBMJh8iSZ7SxFu6
SXyM2cOiFGkoChmA3ondoW7h9dAy+lIIG4PkuOV2EsW7xmcTwPYRh2H1br22
uZOas5AeINpJorZ3JyGO7uScLIaQt4Vvt3jrsNTguEzuY5z4JnzTlXSGfWa8
gduXJHIQIz/pFhtunuYOzYU8iTib61ho92zT5wly0EEhcozF954RH/lxJ1qx
mFzxlxS9iGKNYSYvZj1+4xoIt+LsZcdQ21Fv9EmhY0JTVtztN+rJ3HcnObTn
b9Dj7ru1+CNpC+U6PfBhjCe8CxDQMJeT7yTaqvZR7cbcGe6jT4Cxm9bvJk6h
Qg5Xt2gDfzj9aP0ujwaN58EZA8W4srO6V0GB5DuEDO5V0F66stld5NwTvw3Z
4z3E3C6qAES4nyjWWaA8XAVDIz7UiPz66KKEOYluq+B0uaKsL87enuFrTv6i
xKQPOIcfyq0YxctIaUZO34zOyfNhlbMM8BnfOTMOUx9P5frY5n84WBDCsQef
woekJo0kr/a/DHimpJ0+AAA=

-->

</rfc>
