<div dir="ltr"><div class="markdown-here-wrapper" style=""><p style="margin:0px 0px 1.2em!important">Right now, the distribution protocol gets to play with toys that the rest of us don’t: it can make sequential <code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline">term_to_binary/1</code> calls more space-efficient by lifting the atoms out of each term, converting them into cheap <code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline">EXT_ATOM_CACHE_REF</code>s. It then emits the atom-cache updates as headers in each data message.</p>
<p style="margin:0px 0px 1.2em!important">I propose moving this logic to a more Erlang-userland accessible level. Rather than atom caches being something that happen internally in <code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline">dist.c</code>, atom caches could be exposed as a general feature of the External Term Format in <code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline">external.c</code>.</p>
<p style="margin:0px 0px 1.2em!important">Users could create new atom caches through a BIF (e.g. <code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline">make_atom_cache/0</code>) and then fold the terms they wish to encode/decode over the atom cache, which would either return a new atom cache (if the atom cache is an exposed term) or would mutate the underlying data-structure of the atom cache (if the atom cache is an opaque handle.) Users could then use another BIF to ask the atom cache to create a binary description of an update.</p>
<p style="margin:0px 0px 1.2em!important">The distribution protocol could then be reimplemented backwards-compatibly in terms of these new BIFs, where the atom cache update in each data message's header would simply be the return value of the "describe atom cache update" BIF.</p>
<p style="margin:0px 0px 1.2em!important">I've outlined below a few potential API designs for this idea. I'd like to get feedback what people like/dislike about them. If there's clear community consensus that one of these ideas is good, I'll move forward with either a patch or an EEP (I personally feel this isn't the kind of big-deal change that warrants an EEP, but correct me if I'm wrong.)</p>
<h3 id="1-atom-cache-as-plain-functional-data-structure" style="margin:1.3em 0px 1em;padding:0px;font-weight:bold;font-size:1.3em">1 - Erlang-exposed atom cache</h3>
<p style="margin:0px 0px 1.2em!important">Using the hypothetical BIF <code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline">make_atom_cache/0</code>, a hypothetical <code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline">atom_cache</code> option for <code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline">term_to_binary/2</code>, and the hypothetical BIF <code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline">binary_to_term/2</code> which also takes an <code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline">atom_cache</code> option. Both <code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline">term_to_binary/2</code> and <code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline">binary_to_term/2</code>, when passed the <code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline">atom_cache</code> option, would return a <code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline">{Result, UpdatedAtomCache}</code> tuple.</p>
<pre style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;font-size:1em;line-height:1.2em;margin:1.2em 0px"><code class="hljs language-erlang" style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline;white-space:pre;overflow:auto;border-radius:3px;border:1px solid rgb(204,204,204);padding:0.5em 0.7em;display:block!important;display:block;overflow-x:auto;padding:0.5em;color:rgb(51,51,51);background:rgb(248,248,248)"><span class="hljs-function"><span class="hljs-title" style="color:rgb(153,0,0);font-weight:bold">terms_to_binaries</span><span class="hljs-params">(<span class="hljs-variable" style="color:rgb(0,128,128)">Terms</span>)</span> -></span>
    <span class="hljs-function_name">terms_to_binaries</span>(<span class="hljs-variable" style="color:rgb(0,128,128)">Terms</span>, <span class="hljs-function_name">erlang:make_atom_cache</span>()).

<span class="hljs-function"><span class="hljs-title" style="color:rgb(153,0,0);font-weight:bold">terms_to_binaries</span><span class="hljs-params">(<span class="hljs-variable" style="color:rgb(0,128,128)">Terms</span>, <span class="hljs-variable" style="color:rgb(0,128,128)">ACache0</span>)</span> -></span>
    <span class="hljs-function_name">terms_to_binaries</span>(<span class="hljs-variable" style="color:rgb(0,128,128)">Terms</span>, <span class="hljs-variable" style="color:rgb(0,128,128)">ACache0</span>, <span class="hljs-variable" style="color:rgb(0,128,128)">ACache0</span>, []).

<span class="hljs-function"><span class="hljs-title" style="color:rgb(153,0,0);font-weight:bold">terms_to_binaries</span><span class="hljs-params">([], <span class="hljs-variable" style="color:rgb(0,128,128)">ACache0</span>, <span class="hljs-variable" style="color:rgb(0,128,128)">ACache0</span>, <span class="hljs-variable" style="color:rgb(0,128,128)">Bins</span>)</span> -></span>
    <span class="hljs-function_name">lists:reverse</span>(<span class="hljs-variable" style="color:rgb(0,128,128)">Bins</span>).

<span class="hljs-function"><span class="hljs-title" style="color:rgb(153,0,0);font-weight:bold">terms_to_binaries</span><span class="hljs-params">([], <span class="hljs-variable" style="color:rgb(0,128,128)">ACache0</span>, <span class="hljs-variable" style="color:rgb(0,128,128)">ACacheFinal</span>, <span class="hljs-variable" style="color:rgb(0,128,128)">Bins</span>)</span> -></span>
    <span class="hljs-variable" style="color:rgb(0,128,128)">ACacheDiff</span> = <span class="hljs-function_name">erlang:diff_atom_cache</span>(<span class="hljs-variable" style="color:rgb(0,128,128)">ACache0</span>, <span class="hljs-variable" style="color:rgb(0,128,128)">ACacheFinal</span>),
    <span class="hljs-variable" style="color:rgb(0,128,128)">ACacheDiffBin</span> = <span class="hljs-function_name">erlang:term_to_binary</span>(<span class="hljs-variable" style="color:rgb(0,128,128)">ACacheDiff</span>),
    [<span class="hljs-variable" style="color:rgb(0,128,128)">ACacheDiffBin</span> | <span class="hljs-function_name">lists:reverse</span>(<span class="hljs-variable" style="color:rgb(0,128,128)">Bins</span>)].

<span class="hljs-function"><span class="hljs-title" style="color:rgb(153,0,0);font-weight:bold">terms_to_binaries</span><span class="hljs-params">([<span class="hljs-variable" style="color:rgb(0,128,128)">Term</span> | <span class="hljs-variable" style="color:rgb(0,128,128)">Terms</span>], <span class="hljs-variable" style="color:rgb(0,128,128)">ACache0</span>, <span class="hljs-variable" style="color:rgb(0,128,128)">ACachePrev</span>, <span class="hljs-variable" style="color:rgb(0,128,128)">Bins</span>)</span> -></span>
    <span class="hljs-tuple">{<span class="hljs-variable" style="color:rgb(0,128,128)">Bin</span>, <span class="hljs-variable" style="color:rgb(0,128,128)">ACacheCurr</span>}</span> = <span class="hljs-function_name">erlang:term_to_binary</span>(<span class="hljs-variable" style="color:rgb(0,128,128)">Term</span>, <span class="hljs-tuple">{atom_cache, <span class="hljs-variable" style="color:rgb(0,128,128)">ACachePrev</span>}</span>),
    <span class="hljs-function_name">terms_to_binaries</span>(<span class="hljs-variable" style="color:rgb(0,128,128)">Terms</span>, <span class="hljs-variable" style="color:rgb(0,128,128)">ACache0</span>, <span class="hljs-variable" style="color:rgb(0,128,128)">ACacheCurr</span>, [<span class="hljs-variable" style="color:rgb(0,128,128)">Bin</span> | <span class="hljs-variable" style="color:rgb(0,128,128)">Bins</span>]).

<span class="hljs-function"><span class="hljs-title" style="color:rgb(153,0,0);font-weight:bold">binaries_to_terms</span><span class="hljs-params">(<span class="hljs-variable" style="color:rgb(0,128,128)">Bins</span>)</span> -></span>
    <span class="hljs-function_name">binaries_to_terms</span>(<span class="hljs-variable" style="color:rgb(0,128,128)">Terms</span>, <span class="hljs-function_name">erlang:make_atom_cache</span>()).

<span class="hljs-function"><span class="hljs-title" style="color:rgb(153,0,0);font-weight:bold">binaries_to_terms</span><span class="hljs-params">(<span class="hljs-variable" style="color:rgb(0,128,128)">Bins</span>, <span class="hljs-variable" style="color:rgb(0,128,128)">ACache0</span>)</span> -></span>
    <span class="hljs-function_name">binaries_to_terms</span>(<span class="hljs-variable" style="color:rgb(0,128,128)">Bins</span>, <span class="hljs-variable" style="color:rgb(0,128,128)">ACache0</span>, []).

<span class="hljs-function"><span class="hljs-title" style="color:rgb(153,0,0);font-weight:bold">binaries_to_terms</span><span class="hljs-params">([], <span class="hljs-variable" style="color:rgb(0,128,128)">ACache</span>, <span class="hljs-variable" style="color:rgb(0,128,128)">Terms</span>)</span> -></span>
    <span class="hljs-tuple">{<span class="hljs-function_name">lists:reverse</span>(<span class="hljs-variable" style="color:rgb(0,128,128)">Terms</span>), <span class="hljs-variable" style="color:rgb(0,128,128)">ACache</span>}</span>.

<span class="hljs-function"><span class="hljs-title" style="color:rgb(153,0,0);font-weight:bold">binaries_to_terms</span><span class="hljs-params">([<span class="hljs-variable" style="color:rgb(0,128,128)">Bin</span> | <span class="hljs-variable" style="color:rgb(0,128,128)">Bins</span>], <span class="hljs-variable" style="color:rgb(0,128,128)">ACache0</span>, <span class="hljs-variable" style="color:rgb(0,128,128)">Terms</span>)</span> -></span>
    <span class="hljs-tuple">{<span class="hljs-variable" style="color:rgb(0,128,128)">Term</span>, <span class="hljs-variable" style="color:rgb(0,128,128)">ACache1</span>}</span> = <span class="hljs-function_name">erlang:binary_to_term</span>(<span class="hljs-variable" style="color:rgb(0,128,128)">Bin</span>, [<span class="hljs-tuple">{atom_cache, <span class="hljs-variable" style="color:rgb(0,128,128)">ACache0</span>}</span>]),
    <span class="hljs-function_name">binaries_to_terms</span>(<span class="hljs-variable" style="color:rgb(0,128,128)">Bins</span>, <span class="hljs-variable" style="color:rgb(0,128,128)">ACache1</span>, [<span class="hljs-variable" style="color:rgb(0,128,128)">Term</span> | <span class="hljs-variable" style="color:rgb(0,128,128)">Terms</span>]).
</code></pre>
<h3 id="2-exposed-atom-cache-opaque-transaction-handles" style="margin:1.3em 0px 1em;padding:0px;font-weight:bold;font-size:1.3em">2 - Exposed atom cache, but opaque transaction handles</h3>
<p style="margin:0px 0px 1.2em!important">Design #1 assumes you want functional-data-structure semantics for atom caches the whole way through the encoding/decoding process, which can be slow, and which really makes little sense given that there is no real use for the intermediate atom-cache representations.</p>
<p style="margin:0px 0px 1.2em!important">An alternate design would make the intermediate atom-cache representations opaque—you’d have a handle into an atom-cache “transaction” (a piece of opaque ERTS-mutable data in the owner process’s heap, like a NIF handle), and committing the transaction would destroy this handle and return a regular Erlang-visible representation of the updated atom-cache and a diff from the start of the transaction:</p>
<pre style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;font-size:1em;line-height:1.2em;margin:1.2em 0px"><code class="hljs language-erlang" style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline;white-space:pre;overflow:auto;border-radius:3px;border:1px solid rgb(204,204,204);padding:0.5em 0.7em;display:block!important;display:block;overflow-x:auto;padding:0.5em;color:rgb(51,51,51);background:rgb(248,248,248)"><span class="hljs-function"><span class="hljs-title" style="color:rgb(153,0,0);font-weight:bold">terms_to_binaries</span><span class="hljs-params">(<span class="hljs-variable" style="color:rgb(0,128,128)">Terms</span>)</span> -></span>
    <span class="hljs-function_name">terms_to_binaries</span>(<span class="hljs-variable" style="color:rgb(0,128,128)">Terms</span>, <span class="hljs-function_name">erlang:make_atom_cache</span>()).

<span class="hljs-function"><span class="hljs-title" style="color:rgb(153,0,0);font-weight:bold">terms_to_binaries</span><span class="hljs-params">(<span class="hljs-variable" style="color:rgb(0,128,128)">Terms</span>, <span class="hljs-variable" style="color:rgb(0,128,128)">ACache</span>)</span> -></span>
    <span class="hljs-function_name">terms_to_binaries</span>(<span class="hljs-variable" style="color:rgb(0,128,128)">Terms</span>, <span class="hljs-function_name">atom_cache:transaction</span>(<span class="hljs-variable" style="color:rgb(0,128,128)">ACache</span>), []).

<span class="hljs-function"><span class="hljs-title" style="color:rgb(153,0,0);font-weight:bold">terms_to_binaries</span><span class="hljs-params">([], <span class="hljs-variable" style="color:rgb(0,128,128)">ACacheTx</span>, <span class="hljs-variable" style="color:rgb(0,128,128)">Bins</span>)</span> -></span>
    <span class="hljs-tuple">{<span class="hljs-variable" style="color:rgb(0,128,128)">_UpdatedACache</span>, <span class="hljs-variable" style="color:rgb(0,128,128)">ACacheDiff</span>}</span> = <span class="hljs-function_name">atom_cache:commit</span>(<span class="hljs-variable" style="color:rgb(0,128,128)">ACacheTx</span>),
    <span class="hljs-variable" style="color:rgb(0,128,128)">ACacheDiffBin</span> = <span class="hljs-function_name">erlang:term_to_binary</span>(<span class="hljs-variable" style="color:rgb(0,128,128)">ACacheDiff</span>),
    [<span class="hljs-variable" style="color:rgb(0,128,128)">ACacheDiffBin</span> | <span class="hljs-function_name">lists:reverse</span>(<span class="hljs-variable" style="color:rgb(0,128,128)">Bins</span>)].

<span class="hljs-function"><span class="hljs-title" style="color:rgb(153,0,0);font-weight:bold">terms_to_binaries</span><span class="hljs-params">([<span class="hljs-variable" style="color:rgb(0,128,128)">Term</span> | <span class="hljs-variable" style="color:rgb(0,128,128)">Terms</span>], <span class="hljs-variable" style="color:rgb(0,128,128)">ACacheTx</span>, <span class="hljs-variable" style="color:rgb(0,128,128)">Bins</span>)</span> -></span>
    <span class="hljs-variable" style="color:rgb(0,128,128)">Bin</span> = <span class="hljs-function_name">erlang:term_to_binary</span>(<span class="hljs-variable" style="color:rgb(0,128,128)">Term</span>, <span class="hljs-tuple">{atom_cache, <span class="hljs-variable" style="color:rgb(0,128,128)">ACacheTx</span>}</span>),
    <span class="hljs-function_name">terms_to_binaries</span>(<span class="hljs-variable" style="color:rgb(0,128,128)">Terms</span>, <span class="hljs-variable" style="color:rgb(0,128,128)">ACacheTx</span>, [<span class="hljs-variable" style="color:rgb(0,128,128)">Bin</span> | <span class="hljs-variable" style="color:rgb(0,128,128)">Bins</span>]).

<span class="hljs-function"><span class="hljs-title" style="color:rgb(153,0,0);font-weight:bold">binaries_to_terms</span><span class="hljs-params">(<span class="hljs-variable" style="color:rgb(0,128,128)">Bins</span>)</span> -></span>
    <span class="hljs-function_name">binaries_to_terms</span>(<span class="hljs-variable" style="color:rgb(0,128,128)">Terms</span>, <span class="hljs-function_name">erlang:make_atom_cache</span>()).

<span class="hljs-function"><span class="hljs-title" style="color:rgb(153,0,0);font-weight:bold">binaries_to_terms</span><span class="hljs-params">(<span class="hljs-variable" style="color:rgb(0,128,128)">Bins</span>, <span class="hljs-variable" style="color:rgb(0,128,128)">ACache</span>)</span> -></span>
    <span class="hljs-function_name">binaries_to_terms</span>(<span class="hljs-variable" style="color:rgb(0,128,128)">Bins</span>, <span class="hljs-function_name">atom_cache:transaction</span>(<span class="hljs-variable" style="color:rgb(0,128,128)">ACache</span>), []).

<span class="hljs-function"><span class="hljs-title" style="color:rgb(153,0,0);font-weight:bold">binaries_to_terms</span><span class="hljs-params">([], <span class="hljs-variable" style="color:rgb(0,128,128)">ACacheTx</span>, <span class="hljs-variable" style="color:rgb(0,128,128)">Terms</span>)</span> -></span>
    <span class="hljs-tuple">{<span class="hljs-variable" style="color:rgb(0,128,128)">UpdatedACache</span>, <span class="hljs-variable" style="color:rgb(0,128,128)">_ACacheDiff</span>}</span> = <span class="hljs-function_name">atom_cache:commit</span>(<span class="hljs-variable" style="color:rgb(0,128,128)">ACacheTx</span>),
    <span class="hljs-tuple">{<span class="hljs-function_name">lists:reverse</span>(<span class="hljs-variable" style="color:rgb(0,128,128)">Terms</span>), <span class="hljs-variable" style="color:rgb(0,128,128)">UpdatedACache</span>}</span>.

<span class="hljs-function"><span class="hljs-title" style="color:rgb(153,0,0);font-weight:bold">binaries_to_terms</span><span class="hljs-params">([<span class="hljs-variable" style="color:rgb(0,128,128)">Bin</span> | <span class="hljs-variable" style="color:rgb(0,128,128)">Bins</span>], <span class="hljs-variable" style="color:rgb(0,128,128)">ACacheTx</span>, <span class="hljs-variable" style="color:rgb(0,128,128)">Terms</span>)</span> -></span>
    <span class="hljs-variable" style="color:rgb(0,128,128)">Term</span> = <span class="hljs-function_name">erlang:binary_to_term</span>(<span class="hljs-variable" style="color:rgb(0,128,128)">Bin</span>, [<span class="hljs-tuple">{atom_cache, <span class="hljs-variable" style="color:rgb(0,128,128)">ACacheTx</span>}</span>]),
    <span class="hljs-function_name">binaries_to_terms</span>(<span class="hljs-variable" style="color:rgb(0,128,128)">Bins</span>, <span class="hljs-variable" style="color:rgb(0,128,128)">ACacheTx</span>, [<span class="hljs-variable" style="color:rgb(0,128,128)">Term</span> | <span class="hljs-variable" style="color:rgb(0,128,128)">Terms</span>]).
</code></pre>
<p style="margin:0px 0px 1.2em!important">This still introduces a <code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline">binary_to_term/2</code> BIF, but no longer requires <code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline">term_to_binary/2</code> or <code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline">binary_to_term/2</code> to have multiple potential return types. It also would require the new BIFs <code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline">atom_cache:transaction/1</code> and <code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline">atom_cache:commit/1</code>, as well as the <code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline">make_atom_cache/0</code> BIF.</p>
<h3 id="3-opaque-atom-cache-with-or-without-transactions-" style="margin:1.3em 0px 1em;padding:0px;font-weight:bold;font-size:1.3em">3 - Opaque atom cache (with or without transactions)</h3>
<p style="margin:0px 0px 1.2em!important">This overhead savings is meaningful, but potentially small if the client is using <code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline">term_to_binary/2</code> for a streaming protocol, where the atom-cache transactions would have to be limited to small batch sizes in order to emit chunks in a timely manner.</p>
<p style="margin:0px 0px 1.2em!important">Further savings could be made if, rather than the atom cache being exposed as a term between transactions, the atom cache itself was an opaque handle for its entire lifetime. For example, an atom cache could exist as an ETS table using the special table-type <code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline">atom_cache</code>, with its own backing data-structure optimized for this use-case.</p>
<p style="margin:0px 0px 1.2em!important">This would handily provide a framework for shared-access concurrency of atom caches—concurrent decoder processes and even concurrent encoder processes could be backed by a shared atom cache, allowing terms from the same port, or destined for the same port, to be encoded/decoded concurrently, without generating redundant atom-cache-update binaries in the encoded stream.</p>
<p style="margin:0px 0px 1.2em!important">Transactions, if still desirable, would still need to exist as separate opaque state-tracking objects, in order for the transaction-commits to produce valid atom-cache diffs corresponding to the terms that have been encoded.</p>
<p style="margin:0px 0px 1.2em!important">But, if updates to the <code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline">atom_cache</code> data structure are cheap enough, transactions may able to be discarded as an approach in favour of each individual <code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline">term_to_binary/2</code> and <code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline">binary_to_term/2</code> with the <code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline">atom_cache</code> option passed performing an atomic write to the atom cache table, and returning an individual-operation diff.</p>
<p style="margin:0px 0px 1.2em!important">If, under an atomic-updates design, <code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline">term_to_binary/2</code> simply prepended the encoded atom-cache diff to its own encoded term, then this would make the APIs of the two ETF functions entirely backwards-compatible with their forms today, just now with each having side-effects on an optional passed atom-cache and potentially different outputs (in content, but not in type) when the <code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline">atom_cache</code> option is passed.</p>
<div title="MDH:UmlnaHQgbm93LCB0aGUgZGlzdHJpYnV0aW9uIHByb3RvY29sIGdldHMgdG8gcGxheSB3aXRoIHRv
eXMgdGhhdCB0aGUgcmVzdCBvZiB1cyBkb24ndDogaXQgY2FuIG1ha2Ugc2VxdWVudGlhbCBgdGVy
bV90b19iaW5hcnkvMWAgY2FsbHMgbW9yZSBzcGFjZS1lZmZpY2llbnQgYnkgbGlmdGluZyB0aGUg
YXRvbXMgb3V0IG9mIGVhY2ggdGVybSwgY29udmVydGluZyB0aGVtIGludG8gY2hlYXAgYEVYVF9B
VE9NX0NBQ0hFX1JFRmBzLiBJdCB0aGVuIGVtaXRzIHRoZSBhdG9tLWNhY2hlIHVwZGF0ZXMgYXMg
aGVhZGVycyBpbiBlYWNoIGRhdGEgbWVzc2FnZS48YnI+PGJyPkkgcHJvcG9zZSBtb3ZpbmcgdGhp
cyBsb2dpYyB0byBhIG1vcmUgRXJsYW5nLXVzZXJsYW5kIGFjY2Vzc2libGUgbGV2ZWwuIFJhdGhl
ciB0aGFuIGF0b20gY2FjaGVzIGJlaW5nIHNvbWV0aGluZyB0aGF0IGhhcHBlbiBpbnRlcm5hbGx5
IGluIGBkaXN0LmNgLCBhdG9tIGNhY2hlcyBjb3VsZCBiZSBleHBvc2VkIGFzIGEgZ2VuZXJhbCBm
ZWF0dXJlIG9mIHRoZSBFeHRlcm5hbCBUZXJtIEZvcm1hdCBpbiBgZXh0ZXJuYWwuY2AuPGJyPjxi
cj5Vc2VycyBjb3VsZCBjcmVhdGUgbmV3IGF0b20gY2FjaGVzIHRocm91Z2ggYSBCSUYgKGUuZy4g
YG1ha2VfYXRvbV9jYWNoZS8wYCkgYW5kIHRoZW4gZm9sZCB0aGUgdGVybXMgdGhleSB3aXNoIHRv
IGVuY29kZS9kZWNvZGUgb3ZlciB0aGUgYXRvbSBjYWNoZSwgd2hpY2ggd291bGQgZWl0aGVyIHJl
dHVybiBhIG5ldyBhdG9tIGNhY2hlIChpZiB0aGUgYXRvbSBjYWNoZSBpcyBhbiBleHBvc2VkIHRl
cm0pIG9yIHdvdWxkIG11dGF0ZSB0aGUgdW5kZXJseWluZyBkYXRhLXN0cnVjdHVyZSBvZiB0aGUg
YXRvbSBjYWNoZSAoaWYgdGhlIGF0b20gY2FjaGUgaXMgYW4gb3BhcXVlIGhhbmRsZS4pIFVzZXJz
IGNvdWxkIHRoZW4gdXNlIGFub3RoZXIgQklGIHRvIGFzayB0aGUgYXRvbSBjYWNoZSB0byBjcmVh
dGUgYSBiaW5hcnkgZGVzY3JpcHRpb24gb2YgYW4gdXBkYXRlLjxicj48YnI+VGhlIGRpc3RyaWJ1
dGlvbiBwcm90b2NvbCBjb3VsZCB0aGVuIGJlIHJlaW1wbGVtZW50ZWQgYmFja3dhcmRzLWNvbXBh
dGliaWxpdHkgaW4gdGVybXMgb2YgdGhlc2UgbmV3IEJJRnMuPGJyPjxicj5IZXJlJ3MgYSBmZXcg
cG90ZW50aWFsIEFQSSBkZXNpZ25zIGZvciB0aGlzIGlkZWEuPGJyPjxicj4jIyMgMSAtIEF0b20g
Y2FjaGUgYXMgcGxhaW4gZnVuY3Rpb25hbCBkYXRhIHN0cnVjdHVyZTxicj48YnI+VXNpbmcgdGhl
IGh5cG90aGV0aWNhbCBCSUYgYG1ha2VfYXRvbV9jYWNoZS8wYCwgYSBoeXBvdGhldGljYWwgYGF0
b21fY2FjaGVgIG9wdGlvbiBmb3IgYHRlcm1fdG9fYmluYXJ5LzJgLCBhbmQgdGhlIGh5cG90aGV0
aWNhbCBCSUYgYGJpbmFyeV90b190ZXJtLzJgIHdoaWNoIGFsc28gdGFrZXMgYW4gYGF0b21fY2Fj
aGVgIG9wdGlvbi4gQm90aCBgdGVybV90b19iaW5hcnkvMmAgYW5kIGBiaW5hcnlfdG9fdGVybS8y
YCwgd2hlbiBwYXNzZWQgdGhlIGBhdG9tX2NhY2hlYCBvcHRpb24sIHdvdWxkIHJldHVybiBhIGB7
UmVzdWx0LCBVcGRhdGVkQXRvbUNhY2hlfWAgdHVwbGUuPGJyPjxicj5gYGBlcmxhbmc8YnI+PGRp
dj50ZXJtc190b19iaW5hcmllcyhUZXJtcykgLSZndDs8L2Rpdj48ZGl2PjxzcGFuIHN0eWxlPSJ3
aGl0ZS1zcGFjZTogcHJlOyI+CTwvc3Bhbj50ZXJtc190b19iaW5hcmllcyhUZXJtcywgZXJsYW5n
Om1ha2VfYXRvbV9jYWNoZSgpKS48L2Rpdj48ZGl2Pjxicj48L2Rpdj48ZGl2PnRlcm1zX3RvX2Jp
bmFyaWVzKFRlcm1zLCBBQ2FjaGUwKSAtJmd0OzwvZGl2PjxkaXY+PHNwYW4gc3R5bGU9IndoaXRl
LXNwYWNlOiBwcmU7Ij4JPC9zcGFuPnRlcm1zX3RvX2JpbmFyaWVzKFRlcm1zLCBBQ2FjaGUwLCBB
Q2FjaGUwLCBbXSkuPC9kaXY+PGRpdj48YnI+PC9kaXY+PGRpdj50ZXJtc190b19iaW5hcmllcyhb
XSwgQUNhY2hlMCwgQUNhY2hlMCwgQmlucykgLSZndDs8L2Rpdj48ZGl2PjxzcGFuIHN0eWxlPSJ3
aGl0ZS1zcGFjZTogcHJlOyI+CTwvc3Bhbj5saXN0czpyZXZlcnNlKEJpbnMpLjwvZGl2PjxkaXY+
PGJyPjwvZGl2PjxkaXY+dGVybXNfdG9fYmluYXJpZXMoW10sIEFDYWNoZTAsIEFDYWNoZUZpbmFs
LCBCaW5zKSAtJmd0OzwvZGl2PjxkaXY+PHNwYW4gc3R5bGU9IndoaXRlLXNwYWNlOiBwcmU7Ij4J
PC9zcGFuPkFDYWNoZURpZmYgPSBlcmxhbmc6ZGlmZl9hdG9tX2NhY2hlKEFDYWNoZTAsIEFDYWNo
ZUZpbmFsKSw8L2Rpdj48ZGl2PjxzcGFuIHN0eWxlPSJ3aGl0ZS1zcGFjZTogcHJlOyI+CTwvc3Bh
bj5BQ2FjaGVEaWZmQmluID0gZXJsYW5nOnRlcm1fdG9fYmluYXJ5KEFDYWNoZURpZmYpLDwvZGl2
PjxkaXY+PHNwYW4gc3R5bGU9IndoaXRlLXNwYWNlOiBwcmU7Ij4JPC9zcGFuPltBQ2FjaGVEaWZm
QmluIHwgbGlzdHM6cmV2ZXJzZShCaW5zKV0uPC9kaXY+PGRpdj48YnI+PC9kaXY+PGRpdj50ZXJt
c190b19iaW5hcmllcyhbVGVybSB8IFRlcm1zXSwgQUNhY2hlMCwgQUNhY2hlUHJldiwgQmlucykg
LSZndDs8L2Rpdj48ZGl2PjxzcGFuIHN0eWxlPSJ3aGl0ZS1zcGFjZTogcHJlOyI+CTwvc3Bhbj57
QmluLCBBQ2FjaGVDdXJyfSA9IGVybGFuZzp0ZXJtX3RvX2JpbmFyeShUZXJtLCB7YXRvbV9jYWNo
ZSwgQUNhY2hlUHJldn0pLDwvZGl2PjxkaXY+PHNwYW4gc3R5bGU9IndoaXRlLXNwYWNlOiBwcmU7
Ij4JPC9zcGFuPnRlcm1zX3RvX2JpbmFyaWVzKFRlcm1zLCBBQ2FjaGUwLCBBQ2FjaGVDdXJyLCBb
QmluIHwgQmluc10pLjwvZGl2PjxkaXY+PGJyPjwvZGl2PjxkaXY+PGJyPjwvZGl2PjxkaXY+PGJy
PjwvZGl2PjxkaXY+YmluYXJpZXNfdG9fdGVybXMoQmlucykgLSZndDs8L2Rpdj48ZGl2PjxzcGFu
IHN0eWxlPSJ3aGl0ZS1zcGFjZTogcHJlOyI+CTwvc3Bhbj5iaW5hcmllc190b190ZXJtcyhUZXJt
cywgZXJsYW5nOm1ha2VfYXRvbV9jYWNoZSgpKS48L2Rpdj48ZGl2Pjxicj48L2Rpdj48ZGl2PmJp
bmFyaWVzX3RvX3Rlcm1zKEJpbnMsIEFDYWNoZTApIC0mZ3Q7PC9kaXY+PGRpdj48c3BhbiBzdHls
ZT0id2hpdGUtc3BhY2U6IHByZTsiPgk8L3NwYW4+YmluYXJpZXNfdG9fdGVybXMoQmlucywgQUNh
Y2hlMCwgW10pLjwvZGl2PjxkaXY+PGJyPjwvZGl2PjxkaXY+YmluYXJpZXNfdG9fdGVybXMoW10s
IEFDYWNoZSwgVGVybXMpIC0mZ3Q7PC9kaXY+PGRpdj48c3BhbiBzdHlsZT0id2hpdGUtc3BhY2U6
IHByZTsiPgk8L3NwYW4+e2xpc3RzOnJldmVyc2UoVGVybXMpLCBBQ2FjaGV9LjwvZGl2PjxkaXY+
PGJyPjwvZGl2PjxkaXY+YmluYXJpZXNfdG9fdGVybXMoW0JpbiB8IEJpbnNdLCBBQ2FjaGUwLCBU
ZXJtcykgLSZndDs8L2Rpdj48ZGl2PjxzcGFuIHN0eWxlPSJ3aGl0ZS1zcGFjZTogcHJlOyI+CTwv
c3Bhbj57VGVybSwgQUNhY2hlMX0gPSBlcmxhbmc6YmluYXJ5X3RvX3Rlcm0oQmluLCBbe2F0b21f
Y2FjaGUsIEFDYWNoZTB9XSksPC9kaXY+PGRpdj48c3BhbiBzdHlsZT0id2hpdGUtc3BhY2U6IHBy
ZTsiPgk8L3NwYW4+YmluYXJpZXNfdG9fdGVybXMoQmlucywgQUNhY2hlMSwgW1Rlcm0gfCBUZXJt
c10pLjwvZGl2PmBgYDxicj48YnI+IyMjIDIgLSBFeHBvc2VkIGF0b20gY2FjaGU7IG9wYXF1ZSB0
cmFuc2FjdGlvbiBoYW5kbGVzPGJyPjxicj5EZXNpZ24gIzEgYXNzdW1lcyB5b3Ugd2FudCBmdW5j
dGlvbmFsLWRhdGEtc3RydWN0dXJlIHNlbWFudGljcyBmb3IgYXRvbSBjYWNoZXMgdGhlIHdob2xl
IHdheSB0aHJvdWdoIHRoZSBlbmNvZGluZy9kZWNvZGluZyBwcm9jZXNzLCB3aGljaCBjYW4gYmUg
c2xvdywgYW5kIHdoaWNoIHJlYWxseSBtYWtlcyBsaXR0bGUgc2Vuc2UgZ2l2ZW4gdGhhdCB0aGVy
ZSBpcyBubyByZWFsIHVzZSBmb3IgdGhlIGludGVybWVkaWF0ZSBhdG9tLWNhY2hlIHJlcHJlc2Vu
dGF0aW9ucy48YnI+PGJyPkFuIGFsdGVybmF0ZSBkZXNpZ24gd291bGQgbWFrZSB0aGUgaW50ZXJt
ZWRpYXRlIGF0b20tY2FjaGUgcmVwcmVzZW50YXRpb25zIG9wYXF1ZeKAlHlvdSdkIGhhdmUgYSBo
YW5kbGUgaW50byBhbiBhdG9tLWNhY2hlICJ0cmFuc2FjdGlvbiIgKGEgcGllY2Ugb2Ygb3BhcXVl
IEVSVFMtbXV0YWJsZSBkYXRhIGluIHRoZSBvd25lciBwcm9jZXNzJ3MgaGVhcCwgbGlrZSBhIE5J
RiBoYW5kbGUpLCBhbmQgY29tbWl0dGluZyB0aGUgdHJhbnNhY3Rpb24gd291bGQgZGVzdHJveSB0
aGlzIGhhbmRsZSBhbmQgcmV0dXJuIGEgcmVndWxhciBFcmxhbmctdmlzaWJsZSByZXByZXNlbnRh
dGlvbiBvZiB0aGUgdXBkYXRlZCBhdG9tLWNhY2hlIGFuZCBhIGRpZmYgZnJvbSB0aGUgc3RhcnQg
b2YgdGhlIHRyYW5zYWN0aW9uOjxicj48YnI+YGBgZXJsYW5nPGJyPjxkaXY+dGVybXNfdG9fYmlu
YXJpZXMoVGVybXMpIC0mZ3Q7PC9kaXY+PGRpdj48c3BhbiBzdHlsZT0id2hpdGUtc3BhY2U6IHBy
ZTsiPgk8L3NwYW4+dGVybXNfdG9fYmluYXJpZXMoVGVybXMsIGVybGFuZzptYWtlX2F0b21fY2Fj
aGUoKSkuPC9kaXY+PGRpdj48YnI+PC9kaXY+PGRpdj50ZXJtc190b19iaW5hcmllcyhUZXJtcywg
QUNhY2hlKSAtJmd0OzwvZGl2PjxkaXY+PHNwYW4gc3R5bGU9IndoaXRlLXNwYWNlOiBwcmU7Ij4J
PC9zcGFuPnRlcm1zX3RvX2JpbmFyaWVzKFRlcm1zLCBhdG9tX2NhY2hlOnRyYW5zYWN0aW9uKEFD
YWNoZSksIFtdKS48L2Rpdj48ZGl2Pjxicj48L2Rpdj48ZGl2PnRlcm1zX3RvX2JpbmFyaWVzKFtd
LCBBQ2FjaGVUeCwgQmlucykgLSZndDs8L2Rpdj48ZGl2PjxzcGFuIHN0eWxlPSJ3aGl0ZS1zcGFj
ZTogcHJlOyI+CTwvc3Bhbj57X1VwZGF0ZWRBQ2FjaGUsIEFDYWNoZURpZmZ9ID0gYXRvbV9jYWNo
ZTpjb21taXQoQUNhY2hlVHgpLDwvZGl2PjxkaXY+PHNwYW4gc3R5bGU9IndoaXRlLXNwYWNlOiBw
cmU7Ij4JPC9zcGFuPkFDYWNoZURpZmZCaW4gPSBlcmxhbmc6dGVybV90b19iaW5hcnkoQUNhY2hl
RGlmZiksPC9kaXY+PGRpdj48c3BhbiBzdHlsZT0id2hpdGUtc3BhY2U6IHByZTsiPgk8L3NwYW4+
W0FDYWNoZURpZmZCaW4gfCBsaXN0czpyZXZlcnNlKEJpbnMpXS48L2Rpdj48ZGl2Pjxicj48L2Rp
dj48ZGl2PnRlcm1zX3RvX2JpbmFyaWVzKFtUZXJtIHwgVGVybXNdLCBBQ2FjaGVUeCwgQmlucykg
LSZndDs8L2Rpdj48ZGl2PjxzcGFuIHN0eWxlPSJ3aGl0ZS1zcGFjZTogcHJlOyI+CTwvc3Bhbj5C
aW4gPSBlcmxhbmc6dGVybV90b19iaW5hcnkoVGVybSwge2F0b21fY2FjaGUsIEFDYWNoZVR4fSks
PC9kaXY+PGRpdj48c3BhbiBzdHlsZT0id2hpdGUtc3BhY2U6IHByZTsiPgk8L3NwYW4+dGVybXNf
dG9fYmluYXJpZXMoVGVybXMsIEFDYWNoZVR4LCBbQmluIHwgQmluc10pLjwvZGl2PjxkaXY+PGJy
PjwvZGl2PjxkaXY+PGJyPjwvZGl2PjxkaXY+PGJyPjwvZGl2PjxkaXY+YmluYXJpZXNfdG9fdGVy
bXMoQmlucykgLSZndDs8L2Rpdj48ZGl2PjxzcGFuIHN0eWxlPSJ3aGl0ZS1zcGFjZTogcHJlOyI+
CTwvc3Bhbj5iaW5hcmllc190b190ZXJtcyhUZXJtcywgZXJsYW5nOm1ha2VfYXRvbV9jYWNoZSgp
KS48L2Rpdj48ZGl2Pjxicj48L2Rpdj48ZGl2PmJpbmFyaWVzX3RvX3Rlcm1zKEJpbnMsIEFDYWNo
ZSkgLSZndDs8L2Rpdj48ZGl2PjxzcGFuIHN0eWxlPSJ3aGl0ZS1zcGFjZTogcHJlOyI+CTwvc3Bh
bj5iaW5hcmllc190b190ZXJtcyhCaW5zLCBhdG9tX2NhY2hlOnRyYW5zYWN0aW9uKEFDYWNoZSks
IFtdKS48L2Rpdj48ZGl2Pjxicj48L2Rpdj48ZGl2PmJpbmFyaWVzX3RvX3Rlcm1zKFtdLCBBQ2Fj
aGVUeCwgVGVybXMpIC0mZ3Q7PC9kaXY+PGRpdj48c3BhbiBzdHlsZT0id2hpdGUtc3BhY2U6IHBy
ZTsiPgk8L3NwYW4+e1VwZGF0ZWRBQ2FjaGUsIF9BQ2FjaGVEaWZmfSA9IGF0b21fY2FjaGU6Y29t
bWl0KEFDYWNoZVR4KSw8L2Rpdj48ZGl2PjxzcGFuIHN0eWxlPSJ3aGl0ZS1zcGFjZTogcHJlOyI+
CTwvc3Bhbj57bGlzdHM6cmV2ZXJzZShUZXJtcyksIFVwZGF0ZWRBQ2FjaGV9LjwvZGl2PjxkaXY+
PGJyPjwvZGl2PjxkaXY+YmluYXJpZXNfdG9fdGVybXMoW0JpbiB8IEJpbnNdLCBBQ2FjaGVUeCwg
VGVybXMpIC0mZ3Q7PC9kaXY+PGRpdj48c3BhbiBzdHlsZT0id2hpdGUtc3BhY2U6IHByZTsiPgk8
L3NwYW4+VGVybSA9IGVybGFuZzpiaW5hcnlfdG9fdGVybShCaW4sIFt7YXRvbV9jYWNoZSwgQUNh
Y2hlVHh9XSksPC9kaXY+PGRpdj48c3BhbiBzdHlsZT0id2hpdGUtc3BhY2U6IHByZTsiPgk8L3Nw
YW4+YmluYXJpZXNfdG9fdGVybXMoQmlucywgQUNhY2hlVHgsIFtUZXJtIHwgVGVybXNdKS48L2Rp
dj5gYGA8YnI+PGJyPlRoaXMgc3RpbGwgaW50cm9kdWNlcyBhIGBiaW5hcnlfdG9fdGVybS8yYCBC
SUYsIGJ1dCBubyBsb25nZXIgcmVxdWlyZXMgYHRlcm1fdG9fYmluYXJ5LzJgIG9yIGBiaW5hcnlf
dG9fdGVybS8yYCB0byBoYXZlIG11bHRpcGxlIHBvdGVudGlhbCByZXR1cm4gdHlwZXMuIEl0IGFs
c28gd291bGQgcmVxdWlyZSB0aGUgbmV3IEJJRnMgYGF0b21fY2FjaGU6dHJhbnNhY3Rpb24vMWAg
YW5kIGBhdG9tX2NhY2hlOmNvbW1pdC8xYCwgYXMgd2VsbCBhcyB0aGUgYG1ha2VfYXRvbV9jYWNo
ZS8wYCBCSUYuPGJyPjxicj4jIyMgMyAtIE9wYXF1ZSBhdG9tIGNhY2hlICh3aXRoIG9yIHdpdGhv
dXQgdHJhbnNhY3Rpb25zKTxicj48YnI+VGhpcyBvdmVyaGVhZCBzYXZpbmdzIGlzIG1lYW5pbmdm
dWwsIGJ1dCBwb3RlbnRpYWxseSBzbWFsbCBpZiB0aGUgY2xpZW50IGlzIHVzaW5nIGB0ZXJtX3Rv
X2JpbmFyeS8yYCBmb3IgYSBzdHJlYW1pbmcgcHJvdG9jb2wsIHdoZXJlIHRoZSBhdG9tLWNhY2hl
IHRyYW5zYWN0aW9ucyB3b3VsZCBoYXZlIHRvIGJlIGxpbWl0ZWQgdG8gc21hbGwgYmF0Y2ggc2l6
ZXMgaW4gb3JkZXIgdG8gZW1pdCBjaHVua3MgaW4gYSB0aW1lbHkgbWFubmVyLjxicj48YnI+RnVy
dGhlciBzYXZpbmdzIGNvdWxkIGJlIG1hZGUgaWYsIHJhdGhlciB0aGFuIHRoZSBhdG9tIGNhY2hl
IGJlaW5nIGV4cG9zZWQgYXMgYSB0ZXJtIGJldHdlZW4gdHJhbnNhY3Rpb25zLCB0aGUgYXRvbSBj
YWNoZSBpdHNlbGYgd2FzIGFuIG9wYXF1ZSBoYW5kbGUgZm9yIGl0cyBlbnRpcmUgbGlmZXRpbWUu
IEZvciBleGFtcGxlLCBhbiBhdG9tIGNhY2hlIGNvdWxkIGV4aXN0IGFzIGFuIEVUUyB0YWJsZSB1
c2luZyB0aGUgc3BlY2lhbCB0YWJsZS10eXBlIGBhdG9tX2NhY2hlYCwgd2l0aCBpdHMgb3duIGJh
Y2tpbmcgZGF0YS1zdHJ1Y3R1cmUgb3B0aW1pemVkIGZvciB0aGlzIHVzZS1jYXNlLjxkaXY+PGJy
PjwvZGl2PjxkaXY+VGhpcyB3b3VsZCBoYW5kaWx5IHByb3ZpZGUgYSBmcmFtZXdvcmsgZm9yIHNo
YXJlZC1hY2Nlc3MgY29uY3VycmVuY3kgb2YgYXRvbSBjYWNoZXPigJRjb25jdXJyZW50IGRlY29k
ZXIgcHJvY2Vzc2VzIGFuZCBldmVuIGNvbmN1cnJlbnQgZW5jb2RlciBwcm9jZXNzZXMgY291bGQg
YmUgYmFja2VkIGJ5IGEgc2hhcmVkIGF0b20gY2FjaGUsIGFsbG93aW5nIHRlcm1zIGZyb20gdGhl
IHNhbWUgcG9ydCwgb3IgZGVzdGluZWQgZm9yIHRoZSBzYW1lIHBvcnQsIHRvIGJlIGVuY29kZWQv
ZGVjb2RlZCBjb25jdXJyZW50bHksIHdpdGhvdXQgZ2VuZXJhdGluZyByZWR1bmRhbnQgYXRvbS1j
YWNoZS11cGRhdGUgYmluYXJpZXMgaW4gdGhlIGVuY29kZWQgc3RyZWFtLjxicj48YnI+VHJhbnNh
Y3Rpb25zLCBpZiBzdGlsbCBkZXNpcmFibGUsIHdvdWxkIHN0aWxsIG5lZWQgdG8gZXhpc3QgYXMg
c2VwYXJhdGUgb3BhcXVlIHN0YXRlLXRyYWNraW5nIG9iamVjdHMsIGluIG9yZGVyIGZvciB0aGUg
dHJhbnNhY3Rpb24tY29tbWl0cyB0byBwcm9kdWNlIHZhbGlkIGF0b20tY2FjaGUgZGlmZnMgY29y
cmVzcG9uZGluZyB0byB0aGUgdGVybXMgdGhhdCBoYXZlIGJlZW4gZW5jb2RlZC48L2Rpdj48ZGl2
Pjxicj48L2Rpdj48ZGl2PkJ1dCwgaWYgdXBkYXRlcyB0byB0aGUgYGF0b21fY2FjaGVgIGRhdGEg
c3RydWN0dXJlIGFyZSBjaGVhcCBlbm91Z2gsIHRyYW5zYWN0aW9ucyBtYXkgYWJsZSB0byBiZSBk
aXNjYXJkZWQgYXMgYW4gYXBwcm9hY2ggaW4gZmF2b3VyIG9mIGVhY2ggaW5kaXZpZHVhbCBgdGVy
bV90b19iaW5hcnkvMmAgYW5kIGBiaW5hcnlfdG9fdGVybS8yYCB3aXRoIHRoZSBgYXRvbV9jYWNo
ZWAgb3B0aW9uIHBhc3NlZCBwZXJmb3JtaW5nIGFuIGF0b21pYyB3cml0ZSB0byB0aGUgYXRvbSBj
YWNoZSB0YWJsZSwgYW5kIHJldHVybmluZyBhbiBpbmRpdmlkdWFsLW9wZXJhdGlvbiBkaWZmLjwv
ZGl2PjxkaXY+PGJyPjwvZGl2PjxkaXY+SWYsIHVuZGVyIGFuIGF0b21pYy11cGRhdGVzIGRlc2ln
biwgYHRlcm1fdG9fYmluYXJ5LzJgIHNpbXBseSBwcmVwZW5kZWQgdGhlIGVuY29kZWQgYXRvbS1j
YWNoZSBkaWZmIHRvIGl0cyBvd24gZW5jb2RlZCB0ZXJtLCB0aGVuIHRoaXMgd291bGQgbWFrZSB0
aGUgQVBJcyBvZiB0aGUgdHdvIEVURiBmdW5jdGlvbnMgZW50aXJlbHkgYmFja3dhcmRzLWNvbXBh
dGlibGUgd2l0aCB0aGVpciBmb3JtcyB0b2RheSwganVzdCBub3cgd2l0aCBlYWNoIGhhdmluZyBz
aWRlLWVmZmVjdHMgb24gYW4gb3B0aW9uYWwgcGFzc2VkIGF0b20tY2FjaGUgYW5kIHBvdGVudGlh
bGx5IGRpZmZlcmVudCBvdXRwdXRzIChpbiBjb250ZW50LCBidXQgbm90IGluIHR5cGUpIHdoZW4g
dGhlIGBhdG9tX2NhY2hlYCBvcHRpb24gaXMgcGFzc2VkLjxicj48L2Rpdj4=" style="height:0;width:0;max-height:0;max-width:0;overflow:hidden;font-size:0em;padding:0;margin:0">​</div></div></div>