<html><head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body>
<div class="markdown-here-wrapper" data-md-url="" style="">
<p style="margin: 0px 0px 1.2em !important;">Hi Alan,<br>
I did some more experiment on your repository.</p>
<p style="margin: 0px 0px 1.2em !important;">First of all, I fixed
the keySegment benchmark utility function to do this:</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-java" 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) none repeat scroll 0% 0%; -moz-text-size-adjust: none;">
<span class="hljs-function"><span class="hljs-keyword" style="color: rgb(51, 51, 51); font-weight: bold;">private</span> MemorySegment <span class="hljs-title" style="color: rgb(153, 0, 0); font-weight: bold;">getKeySegment</span><span class="hljs-params">()</span> </span>{
<span class="hljs-keyword" style="color: rgb(51, 51, 51); font-weight: bold;">final</span> <span class="hljs-keyword" style="color: rgb(51, 51, 51); font-weight: bold;">int</span> MAX_LEN = <span class="hljs-number" style="color: rgb(0, 128, 128);">9</span>; <span class="hljs-comment" style="color: rgb(153, 153, 136); font-style: italic;">// key100000</span>
<span class="hljs-keyword" style="color: rgb(51, 51, 51); font-weight: bold;">final</span> <span class="hljs-keyword" style="color: rgb(51, 51, 51); font-weight: bold;">int</span> keyIdx = next();
<span class="hljs-keyword" style="color: rgb(51, 51, 51); font-weight: bold;">final</span> String keyStr = <span class="hljs-string" style="color: rgb(221, 17, 68);">"key"</span> + keyIdx;
<span class="hljs-keyword" style="color: rgb(51, 51, 51); font-weight: bold;">for</span> (<span class="hljs-keyword" style="color: rgb(51, 51, 51); font-weight: bold;">int</span> i = <span class="hljs-number" style="color: rgb(0, 128, 128);">0</span>; i < keyStr.length(); ++i) {
keySegment.set(ValueLayout.JAVA_BYTE, i, (<span class="hljs-keyword" style="color: rgb(51, 51, 51); font-weight: bold;">byte</span>)keyStr.charAt(i));
}
<span class="hljs-keyword" style="color: rgb(51, 51, 51); font-weight: bold;">for</span> (<span class="hljs-keyword" style="color: rgb(51, 51, 51); font-weight: bold;">int</span> i = keyStr.length(); i < MAX_LEN; ++i) {
keySegment.set(ValueLayout.JAVA_BYTE, i, (<span class="hljs-keyword" style="color: rgb(51, 51, 51); font-weight: bold;">byte</span>) <span class="hljs-number" style="color: rgb(0, 128, 128);">0x30</span>);
}
<span class="hljs-keyword" style="color: rgb(51, 51, 51); font-weight: bold;">return</span> keySegment;
}
</code></pre>
<p style="margin: 0px 0px 1.2em !important;">E.g. bring it in sync
with the buffer version.</p>
<p style="margin: 0px 0px 1.2em !important;">Then I made, as
suggested yesterday, all MethodHandles in FFIMethod static AND
final.</p>
<p style="margin: 0px 0px 1.2em !important;">Also, in FFILayout, I
added a call to <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;">.withInvokeExactBehavior()</code>
to each var handle creation. This is helpful to detect inexact
calls. I found few inexact calls:</p>
<ul style="margin: 1.2em 0px;padding-left: 2em;">
<li style="margin: 0.5em 0px;">one in FFIDB.java - the result of
the foreign call inside getPinnableSlice() is casted to <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;">Long</code>
instead of <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;">long</code></li>
<li style="margin: 0.5em 0px;">one in FFIPinnableSlice.java -
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;">isPinned()</code>
method also casts to <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;">Boolean</code>,
not <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;">boolean</code></li>
</ul>
<p style="margin: 0px 0px 1.2em !important;">Then, 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;">fromPinnable</code>
factory contains some dubious code which is creating a buffer
from a segment, just to do a copy. I replaced with this:</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-java" 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) none repeat scroll 0% 0%; -moz-text-size-adjust: none;">MemorySegment.copy(pinnableSlice.data(), ValueLayout.JAVA_BYTE, <span class="hljs-number" style="color: rgb(0, 128, 128);">0</span>, value, <span class="hljs-number" style="color: rgb(0, 128, 128);">0</span>, (<span class="hljs-keyword" style="color: rgb(51, 51, 51); font-weight: bold;">int</span>)size);
</code></pre>
<p style="margin: 0px 0px 1.2em !important;">I’ve also updated the
code to use the Java 20 API, to make sure I ran with reasonably
up to date JVM.</p>
<p style="margin: 0px 0px 1.2em !important;">Before these changes,
I could see a difference between FFI and JNI, especially in the
preallocated benchmark variants. With the changes above, it
looks like this here:</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 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;">Benchmark (columnFamilyTestType) (keyCount) (keySize) (valueSize) Mode Cnt Score Error Units
GetBenchmarks.ffiGet no_column_family 1000 128 4096 thrpt 30 596.591 ± 6.448 ops/ms
GetBenchmarks.ffiGet no_column_family 1000 128 65536 thrpt 30 60.277 ± 0.547 ops/ms
GetBenchmarks.ffiGetPinnableSlice no_column_family 1000 128 4096 thrpt 30 771.631 ± 13.835 ops/ms
GetBenchmarks.ffiGetPinnableSlice no_column_family 1000 128 65536 thrpt 30 111.709 ± 1.306 ops/ms
GetBenchmarks.ffiGetRandom no_column_family 1000 128 4096 thrpt 30 591.891 ± 7.353 ops/ms
GetBenchmarks.ffiGetRandom no_column_family 1000 128 65536 thrpt 30 68.197 ± 0.600 ops/ms
GetBenchmarks.ffiIdentity no_column_family 1000 128 4096 thrpt 30 58709.753 ± 712.660 ops/ms
GetBenchmarks.ffiIdentity no_column_family 1000 128 65536 thrpt 30 59265.794 ± 834.989 ops/ms
GetBenchmarks.ffiPreallocatedGet no_column_family 1000 128 4096 thrpt 30 736.686 ± 8.370 ops/ms
GetBenchmarks.ffiPreallocatedGet no_column_family 1000 128 65536 thrpt 30 101.211 ± 0.347 ops/ms
GetBenchmarks.ffiPreallocatedGetRandom no_column_family 1000 128 4096 thrpt 30 598.381 ± 6.252 ops/ms
GetBenchmarks.ffiPreallocatedGetRandom no_column_family 1000 128 65536 thrpt 30 68.037 ± 0.632 ops/ms
GetBenchmarks.get no_column_family 1000 128 4096 thrpt 30 559.800 ± 3.369 ops/ms
GetBenchmarks.get no_column_family 1000 128 65536 thrpt 30 60.567 ± 0.380 ops/ms
GetBenchmarks.preallocatedByteBufferGet no_column_family 1000 128 4096 thrpt 30 758.639 ± 13.025 ops/ms
GetBenchmarks.preallocatedByteBufferGet no_column_family 1000 128 65536 thrpt 30 103.190 ± 1.219 ops/ms
GetBenchmarks.preallocatedByteBufferGetRandom no_column_family 1000 128 4096 thrpt 30 753.189 ± 12.498 ops/ms
GetBenchmarks.preallocatedByteBufferGetRandom no_column_family 1000 128 65536 thrpt 30 103.644 ± 3.625 ops/ms
GetBenchmarks.preallocatedGet no_column_family 1000 128 4096 thrpt 30 707.330 ± 10.811 ops/ms
GetBenchmarks.preallocatedGet no_column_family 1000 128 65536 thrpt 30 96.743 ± 1.609 ops/ms
</code></pre>
<p style="margin: 0px 0px 1.2em !important;">It seems most of the
numbers are roughly the same.</p>
<p style="margin: 0px 0px 1.2em !important;">I’m not sure how much
the update to 20 matters - maybe try to fix all of the other
stuff first, and see what happens (inexact var handle calls can
be quite slow compared to Unsafe memory access).</p>
<p style="margin: 0px 0px 1.2em !important;">Cheers<br>
Maurizio</p>
<p style="margin: 0px 0px 1.2em !important;">On 09/03/2023 18:13,
Alan Paxton wrote:</p>
<p style="margin: 0px 0px 1.2em !important;"></p>
<div class="markdown-here-exclude">
<p></p>
<blockquote type="cite" cite="mid:CAKBoMRm=bo4PsmJnP5x6nYzLsh3WmybG_Lv7KF52=HvmScAWOQ@mail.gmail.com">
<div dir="ltr">Hi Maurizio,
<div><br>
</div>
<div>Thanks for the quick and detailed response. I think our
goals coincide as it would make life easier for rocksjava
to successfully implement an FFI API.</div>
<div><br>
</div>
<div>A couple of quick initial reruns shows me your
suggestions both contribute a small amount of improvement,
but probably do not account for all the performance I am
missing. I shall rerun the full benchmark for
confirmation.</div>
<div><br>
</div>
<div>And since both suggestions give me a clearer idea what
might be performance issues, I will take another pass over
my code and see if I can spot any other potential problems
in how it's implemented, or anything else that isn't truly
like-for-like with the JNI version.</div>
<div><br>
</div>
<div>--Alan</div>
</div>
<br>
<div class="gmail_quote">
<div dir="ltr" class="gmail_attr">On Thu, Mar 9, 2023 at
12:08 PM Maurizio Cimadamore <<a href="mailto:maurizio.cimadamore@oracle.com" moz-do-not-send="true" class="moz-txt-link-freetext">maurizio.cimadamore@oracle.com</a>>
wrote:<br>
</div>
<blockquote class="gmail_quote" style="margin:0px 0px 0px
0.8ex;border-left:1px solid
rgb(204,204,204);padding-left:1ex">
<div>
<p>Also, zooming into the benchmark, something funny
seems to be going on with "<span>getKeySegment". This
seems different from the "getKeyArr" counterpart,
but also has a new issue: I believe that, in JNI,
you just passed the Java array "as is" - but in
Panama you can't (as the array is on-heap), so there
is some double-copying involved there (e.g. you
create an on-heap array, which then is moved
off-heap).</span></p>
<p><span>If I'm not mistaken, this method is executed on
every benchmark iteration, so the comparison doesn't
just mesure the cost of the native call, but also
the cost it takes to marshal data from Java heap to
native.</span></p>
<p><span>For instance, the byte buffer versions
("keyBuf") seem to avoid this problem by copying the
data directly off-heap (by using a direct buffer). I
think the benchmark should use a native segment, and
avoid the copy so that at least we avoid that source
of noise in the numbers.</span></p>
<p><span>Cheers<br>
Maurizio<br>
</span></p>
<div>On 09/03/2023 11:29, Maurizio Cimadamore wrote:<br>
</div>
<blockquote type="cite">Hi Alan, <br>
first of all, I'd like to thank you for taking the
time to share your experience and to write it all up
in a document. Stuff like that is very valuable to us,
especially at this stage in the project. <br>
<br>
One quick suggestion when eyeballing your code: your
method handles are "static", but not "final". I
suggest you try to sprinkle "final" in, and see
whether that does the trick. If not, we'd have to look
deeper. <br>
<br>
Cheers <br>
Maurizio <br>
<br>
On 09/03/2023 11:15, Alan Paxton wrote: <br>
<blockquote type="cite">Hi, <br>
<br>
I hope this is an appropriate list for this
question. <br>
<br>
I have been prototyping an FFI-based version of the
RocksDB Java API, which is currently implemented in
JNI. RocksDB is a C++ based key,value-store with a
Java API layered on top. I have done some
benchmarking of the FFI implementation, versus the
JNI version and I find it performs consistently
slightly slower than the current API. <br>
<br>
I would like to understand if this is to be
expected, e.g. does FFI do more safety checking
under the covers when calling a native method ? <br>
Or is the performance likely to improve between the
preview in Java 19 and release in Java 21 ? <br>
If there are resources or suggestions that would
help me dig into the performance I'd be very
grateful to be pointed to them. <br>
<br>
For the use case I'm measuring, data is transferred
in native memory originally allocated by RocksDB in
C++ which I wrap as a MemorySegment; I do allocate
native memory for the request structure. <br>
<br>
These are links to the PR and some documentation of
the work: <br>
<br>
<a href="https://urldefense.com/v3/__https://github.com/facebook/rocksdb/pull/11095__;!!ACWV5N9M2RV99hQ!PM3HGf9CTDeNF5zsB_t5qffUH17pmZ2W8psJF6ewjgUHDJnrxu60CgJnhOr3DF3lPl6YPKe-nib38M3LwP3O-57EKB8O$" target="_blank" moz-do-not-send="true">https://github.com/facebook/rocksdb/pull/11095</a>
<br>
<a href="https://urldefense.com/v3/__https://github.com/alanpaxton/rocksdb/blob/eb-1680-panama-ffi/java/JavaFFI.md__;!!ACWV5N9M2RV99hQ!PM3HGf9CTDeNF5zsB_t5qffUH17pmZ2W8psJF6ewjgUHDJnrxu60CgJnhOr3DF3lPl6YPKe-nib38M3LwP3O-5SkpJEU$" target="_blank" moz-do-not-send="true">https://github.com/alanpaxton/rocksdb/blob/eb-1680-panama-ffi/java/JavaFFI.md</a>
<br>
<br>
Many thanks, <br>
Alan Paxton <br>
<br>
</blockquote>
</blockquote>
</div>
</blockquote>
</div>
</blockquote>
<p></p>
</div>
<p style="margin: 0px 0px 1.2em !important;"></p>
<div title="MDH:PHA+SGkgQWxhbiw8YnI+SSBkaWQgc29tZSBtb3JlIGV4cGVyaW1lbnQgb24geW91ciByZXBvc2l0b3J5LjwvcD48cD5GaXJzdCBvZiBhbGwsIEkgZml4ZWQgdGhlIGtleVNlZ21lbnQgYmVuY2htYXJr
IHV0aWxpdHkgZnVuY3Rpb24gdG8gZG8gdGhpczo8YnI+PGJyPmBgYGphdmE8L3A+PHA+Jm5ic3A7
Jm5ic3A7Jm5ic3A7IHByaXZhdGUgTWVtb3J5U2VnbWVudCBnZXRLZXlTZWdtZW50KCkgezxicj4m
bmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsgZmluYWwgaW50IE1BWF9MRU4gPSA5OyAvLyBr
ZXkxMDAwMDA8YnI+Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7IGZpbmFsIGludCBrZXlJ
ZHggPSBuZXh0KCk7PGJyPiZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyBmaW5hbCBTdHJp
bmcga2V5U3RyID0gImtleSIgKyBrZXlJZHg7PGJyPiZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZu
YnNwOyBmb3IgKGludCBpID0gMDsgaSAmbHQ7IGtleVN0ci5sZW5ndGgoKTsgKytpKSB7PGJyPiZu
YnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyBrZXlTZWdtZW50LnNldChW
YWx1ZUxheW91dC5KQVZBX0JZVEUsIGksIChieXRlKWtleVN0ci5jaGFyQXQoaSkpOzxicj4mbmJz
cDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsgfTxicj4mbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsm
bmJzcDsgZm9yIChpbnQgaSA9IGtleVN0ci5sZW5ndGgoKTsgaSAmbHQ7IE1BWF9MRU47ICsraSkg
ezxicj4mbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsga2V5U2VnbWVu
dC5zZXQoVmFsdWVMYXlvdXQuSkFWQV9CWVRFLCBpLCAoYnl0ZSkgMHgzMCk7PGJyPiZuYnNwOyZu
YnNwOyZuYnNwOyZuYnNwOyZuYnNwOyB9PGJyPiZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNw
OyByZXR1cm4ga2V5U2VnbWVudDs8YnI+Jm5ic3A7Jm5ic3A7Jm5ic3A7IH08YnI+YGBgPC9wPjxw
PkUuZy4gYnJpbmcgaXQgaW4gc3luYyB3aXRoIHRoZSBidWZmZXIgdmVyc2lvbi48L3A+PHA+VGhl
biBJIG1hZGUsIGFzIHN1Z2dlc3RlZCB5ZXN0ZXJkYXksIGFsbCBNZXRob2RIYW5kbGVzIGluIEZG
SU1ldGhvZCBzdGF0aWMgQU5EIGZpbmFsLjwvcD48cD5BbHNvLCBpbiBGRklMYXlvdXQsIEkgYWRk
ZWQgYSBjYWxsIHRvIGAud2l0aEludm9rZUV4YWN0QmVoYXZpb3IoKWAgdG8gZWFjaCB2YXIgaGFu
ZGxlIGNyZWF0aW9uLiBUaGlzIGlzIGhlbHBmdWwgdG8gZGV0ZWN0IGluZXhhY3QgY2FsbHMuIEkg
Zm91bmQgZmV3IGluZXhhY3QgY2FsbHM6PC9wPjxwPiogb25lIGluIEZGSURCLmphdmEgLSB0aGUg
cmVzdWx0IG9mIHRoZSBmb3JlaWduIGNhbGwgaW5zaWRlIGdldFBpbm5hYmxlU2xpY2UoKSBpcyBj
YXN0ZWQgdG8gYExvbmdgIGluc3RlYWQgb2YgYGxvbmdgPGJyPiogb25lIGluIEZGSVBpbm5hYmxl
U2xpY2UuamF2YSAtIHRoZSBgaXNQaW5uZWQoKWAgbWV0aG9kIGFsc28gY2FzdHMgdG8gYEJvb2xl
YW5gLCBub3QgYGJvb2xlYW5gPC9wPjxwPlRoZW4sIHRoZSBgZnJvbVBpbm5hYmxlYCBmYWN0b3J5
IGNvbnRhaW5zIHNvbWUgZHViaW91cyBjb2RlIHdoaWNoIGlzIGNyZWF0aW5nIGEgYnVmZmVyIGZy
b20gYSBzZWdtZW50LCBqdXN0IHRvIGRvIGEgY29weS4gSSByZXBsYWNlZCB3aXRoIHRoaXM6PGJy
Pjxicj5gYGBqYXZhPGJyPk1lbW9yeVNlZ21lbnQuY29weShwaW5uYWJsZVNsaWNlLmRhdGEoKSwg
VmFsdWVMYXlvdXQuSkFWQV9CWVRFLCAwLCB2YWx1ZSwgMCwgKGludClzaXplKTs8YnI+YGBgPGJy
PjwvcD48cD5JJ3ZlIGFsc28gdXBkYXRlZCB0aGUgY29kZSB0byB1c2UgdGhlIEphdmEgMjAgQVBJ
LCB0byBtYWtlIHN1cmUgSSByYW4gd2l0aCByZWFzb25hYmx5IHVwIHRvIGRhdGUgSlZNLjwvcD48
cD5CZWZvcmUgdGhlc2UgY2hhbmdlcywgSSBjb3VsZCBzZWUgYSBkaWZmZXJlbmNlIGJldHdlZW4g
RkZJIGFuZCBKTkksIGVzcGVjaWFsbHkgaW4gdGhlIHByZWFsbG9jYXRlZCBiZW5jaG1hcmsgdmFy
aWFudHMuIFdpdGggdGhlIGNoYW5nZXMgYWJvdmUsIGl0IGxvb2tzIGxpa2UgdGhpcyBoZXJlOjxi
cj48YnI+YGBgPGJyPkJlbmNobWFyayZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNw
OyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZu
YnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNw
OyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZu
YnNwOyZuYnNwOyZuYnNwOyAoY29sdW1uRmFtaWx5VGVzdFR5cGUpJm5ic3A7IChrZXlDb3VudCkm
bmJzcDsgKGtleVNpemUpJm5ic3A7ICh2YWx1ZVNpemUpJm5ic3A7Jm5ic3A7IE1vZGUmbmJzcDsg
Q250Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7IFNjb3JlJm5ic3A7Jm5ic3A7Jm5ic3A7
Jm5ic3A7IEVycm9yJm5ic3A7Jm5ic3A7IFVuaXRzPGJyPkdldEJlbmNobWFya3MuZmZpR2V0Jm5i
c3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7
Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5i
c3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7
Jm5ic3A7Jm5ic3A7Jm5ic3A7IG5vX2NvbHVtbl9mYW1pbHkmbmJzcDsmbmJzcDsmbmJzcDsmbmJz
cDsmbmJzcDsmbmJzcDsmbmJzcDsgMTAwMCZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZu
YnNwOyZuYnNwOyAxMjgmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsm
bmJzcDsgNDA5NiZuYnNwOyB0aHJwdCZuYnNwOyZuYnNwOyAzMCZuYnNwOyZuYnNwOyZuYnNwOyA1
OTYuNTkxIMKxJm5ic3A7Jm5ic3A7IDYuNDQ4Jm5ic3A7IG9wcy9tczxicj5HZXRCZW5jaG1hcmtz
LmZmaUdldCZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZu
YnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNw
OyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZu
YnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyBub19jb2x1bW5fZmFtaWx5Jm5ic3A7Jm5ic3A7
Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7IDEwMDAmbmJzcDsmbmJzcDsmbmJzcDsmbmJz
cDsmbmJzcDsmbmJzcDsmbmJzcDsgMTI4Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5i
c3A7Jm5ic3A7IDY1NTM2Jm5ic3A7IHRocnB0Jm5ic3A7Jm5ic3A7IDMwJm5ic3A7Jm5ic3A7Jm5i
c3A7Jm5ic3A7IDYwLjI3NyDCsSZuYnNwOyZuYnNwOyAwLjU0NyZuYnNwOyBvcHMvbXM8YnI+R2V0
QmVuY2htYXJrcy5mZmlHZXRQaW5uYWJsZVNsaWNlJm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5i
c3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7
Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7IG5vX2NvbHVtbl9mYW1pbHkmbmJzcDsmbmJz
cDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsgMTAwMCZuYnNwOyZuYnNwOyZuYnNwOyZu
YnNwOyZuYnNwOyZuYnNwOyZuYnNwOyAxMjgmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsm
bmJzcDsmbmJzcDsmbmJzcDsgNDA5NiZuYnNwOyB0aHJwdCZuYnNwOyZuYnNwOyAzMCZuYnNwOyZu
YnNwOyZuYnNwOyA3NzEuNjMxIMKxJm5ic3A7IDEzLjgzNSZuYnNwOyBvcHMvbXM8YnI+R2V0QmVu
Y2htYXJrcy5mZmlHZXRQaW5uYWJsZVNsaWNlJm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7
Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5i
c3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7IG5vX2NvbHVtbl9mYW1pbHkmbmJzcDsmbmJzcDsm
bmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsgMTAwMCZuYnNwOyZuYnNwOyZuYnNwOyZuYnNw
OyZuYnNwOyZuYnNwOyZuYnNwOyAxMjgmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJz
cDsmbmJzcDsgNjU1MzYmbmJzcDsgdGhycHQmbmJzcDsmbmJzcDsgMzAmbmJzcDsmbmJzcDsmbmJz
cDsgMTExLjcwOSDCsSZuYnNwOyZuYnNwOyAxLjMwNiZuYnNwOyBvcHMvbXM8YnI+R2V0QmVuY2ht
YXJrcy5mZmlHZXRSYW5kb20mbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJz
cDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsm
bmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJz
cDsgbm9fY29sdW1uX2ZhbWlseSZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZu
YnNwOyAxMDAwJm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7IDEyOCZu
YnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyA0MDk2Jm5ic3A7
IHRocnB0Jm5ic3A7Jm5ic3A7IDMwJm5ic3A7Jm5ic3A7Jm5ic3A7IDU5MS44OTEgwrEmbmJzcDsm
bmJzcDsgNy4zNTMmbmJzcDsgb3BzL21zPGJyPkdldEJlbmNobWFya3MuZmZpR2V0UmFuZG9tJm5i
c3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7
Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5i
c3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7IG5vX2NvbHVtbl9mYW1pbHkm
bmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsgMTAwMCZuYnNwOyZuYnNw
OyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyAxMjgmbmJzcDsmbmJzcDsmbmJzcDsmbmJz
cDsmbmJzcDsmbmJzcDsmbmJzcDsgNjU1MzYmbmJzcDsgdGhycHQmbmJzcDsmbmJzcDsgMzAmbmJz
cDsmbmJzcDsmbmJzcDsmbmJzcDsgNjguMTk3IMKxJm5ic3A7Jm5ic3A7IDAuNjAwJm5ic3A7IG9w
cy9tczxicj5HZXRCZW5jaG1hcmtzLmZmaUlkZW50aXR5Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7
Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5i
c3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7
Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7IG5vX2NvbHVtbl9mYW1pbHkmbmJzcDsmbmJzcDsmbmJz
cDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsgMTAwMCZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZu
YnNwOyZuYnNwOyZuYnNwOyAxMjgmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsm
bmJzcDsmbmJzcDsgNDA5NiZuYnNwOyB0aHJwdCZuYnNwOyZuYnNwOyAzMCZuYnNwOyA1ODcwOS43
NTMgwrEgNzEyLjY2MCZuYnNwOyBvcHMvbXM8YnI+R2V0QmVuY2htYXJrcy5mZmlJZGVudGl0eSZu
YnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNw
OyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZu
YnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyBub19jb2x1bW5f
ZmFtaWx5Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7IDEwMDAmbmJz
cDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsgMTI4Jm5ic3A7Jm5ic3A7Jm5i
c3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7IDY1NTM2Jm5ic3A7IHRocnB0Jm5ic3A7Jm5ic3A7
IDMwJm5ic3A7IDU5MjY1Ljc5NCDCsSA4MzQuOTg5Jm5ic3A7IG9wcy9tczxicj5HZXRCZW5jaG1h
cmtzLmZmaVByZWFsbG9jYXRlZEdldCZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNw
OyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZu
YnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyBub19jb2x1bW5fZmFtaWx5Jm5ic3A7Jm5ic3A7
Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7IDEwMDAmbmJzcDsmbmJzcDsmbmJzcDsmbmJz
cDsmbmJzcDsmbmJzcDsmbmJzcDsgMTI4Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5i
c3A7Jm5ic3A7Jm5ic3A7IDQwOTYmbmJzcDsgdGhycHQmbmJzcDsmbmJzcDsgMzAmbmJzcDsmbmJz
cDsmbmJzcDsgNzM2LjY4NiDCsSZuYnNwOyZuYnNwOyA4LjM3MCZuYnNwOyBvcHMvbXM8YnI+R2V0
QmVuY2htYXJrcy5mZmlQcmVhbGxvY2F0ZWRHZXQmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJz
cDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsm
bmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsgbm9fY29sdW1uX2ZhbWlseSZuYnNw
OyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyAxMDAwJm5ic3A7Jm5ic3A7Jm5i
c3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7IDEyOCZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZu
YnNwOyZuYnNwOyZuYnNwOyA2NTUzNiZuYnNwOyB0aHJwdCZuYnNwOyZuYnNwOyAzMCZuYnNwOyZu
YnNwOyZuYnNwOyAxMDEuMjExIMKxJm5ic3A7Jm5ic3A7IDAuMzQ3Jm5ic3A7IG9wcy9tczxicj5H
ZXRCZW5jaG1hcmtzLmZmaVByZWFsbG9jYXRlZEdldFJhbmRvbSZuYnNwOyZuYnNwOyZuYnNwOyZu
YnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNw
OyZuYnNwOyBub19jb2x1bW5fZmFtaWx5Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5i
c3A7Jm5ic3A7IDEwMDAmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsg
MTI4Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7IDQwOTYm
bmJzcDsgdGhycHQmbmJzcDsmbmJzcDsgMzAmbmJzcDsmbmJzcDsmbmJzcDsgNTk4LjM4MSDCsSZu
YnNwOyZuYnNwOyA2LjI1MiZuYnNwOyBvcHMvbXM8YnI+R2V0QmVuY2htYXJrcy5mZmlQcmVhbGxv
Y2F0ZWRHZXRSYW5kb20mbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsm
bmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsgbm9fY29sdW1uX2ZhbWls
eSZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyAxMDAwJm5ic3A7Jm5i
c3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7IDEyOCZuYnNwOyZuYnNwOyZuYnNwOyZu
YnNwOyZuYnNwOyZuYnNwOyZuYnNwOyA2NTUzNiZuYnNwOyB0aHJwdCZuYnNwOyZuYnNwOyAzMCZu
YnNwOyZuYnNwOyZuYnNwOyZuYnNwOyA2OC4wMzcgwrEmbmJzcDsmbmJzcDsgMC42MzImbmJzcDsg
b3BzL21zPGJyPkdldEJlbmNobWFya3MuZ2V0Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7
Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5i
c3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7
Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5i
c3A7Jm5ic3A7IG5vX2NvbHVtbl9mYW1pbHkmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsm
bmJzcDsmbmJzcDsgMTAwMCZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNw
OyAxMjgmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsgNDA5
NiZuYnNwOyB0aHJwdCZuYnNwOyZuYnNwOyAzMCZuYnNwOyZuYnNwOyZuYnNwOyA1NTkuODAwIMKx
Jm5ic3A7Jm5ic3A7IDMuMzY5Jm5ic3A7IG9wcy9tczxicj5HZXRCZW5jaG1hcmtzLmdldCZuYnNw
OyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZu
YnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNw
OyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZu
YnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyBub19jb2x1bW5fZmFtaWx5Jm5ic3A7
Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7IDEwMDAmbmJzcDsmbmJzcDsmbmJz
cDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsgMTI4Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5i
c3A7Jm5ic3A7Jm5ic3A7IDY1NTM2Jm5ic3A7IHRocnB0Jm5ic3A7Jm5ic3A7IDMwJm5ic3A7Jm5i
c3A7Jm5ic3A7Jm5ic3A7IDYwLjU2NyDCsSZuYnNwOyZuYnNwOyAwLjM4MCZuYnNwOyBvcHMvbXM8
YnI+R2V0QmVuY2htYXJrcy5wcmVhbGxvY2F0ZWRCeXRlQnVmZmVyR2V0Jm5ic3A7Jm5ic3A7Jm5i
c3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7
Jm5ic3A7IG5vX2NvbHVtbl9mYW1pbHkmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJz
cDsmbmJzcDsgMTAwMCZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyAx
MjgmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsgNDA5NiZu
YnNwOyB0aHJwdCZuYnNwOyZuYnNwOyAzMCZuYnNwOyZuYnNwOyZuYnNwOyA3NTguNjM5IMKxJm5i
c3A7IDEzLjAyNSZuYnNwOyBvcHMvbXM8YnI+R2V0QmVuY2htYXJrcy5wcmVhbGxvY2F0ZWRCeXRl
QnVmZmVyR2V0Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7
Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7IG5vX2NvbHVtbl9mYW1pbHkmbmJzcDsmbmJz
cDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsgMTAwMCZuYnNwOyZuYnNwOyZuYnNwOyZu
YnNwOyZuYnNwOyZuYnNwOyZuYnNwOyAxMjgmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsm
bmJzcDsmbmJzcDsgNjU1MzYmbmJzcDsgdGhycHQmbmJzcDsmbmJzcDsgMzAmbmJzcDsmbmJzcDsm
bmJzcDsgMTAzLjE5MCDCsSZuYnNwOyZuYnNwOyAxLjIxOSZuYnNwOyBvcHMvbXM8YnI+R2V0QmVu
Y2htYXJrcy5wcmVhbGxvY2F0ZWRCeXRlQnVmZmVyR2V0UmFuZG9tJm5ic3A7Jm5ic3A7Jm5ic3A7
Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7IG5vX2NvbHVtbl9mYW1pbHkmbmJzcDsmbmJzcDsmbmJz
cDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsgMTAwMCZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZu
YnNwOyZuYnNwOyZuYnNwOyAxMjgmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsm
bmJzcDsmbmJzcDsgNDA5NiZuYnNwOyB0aHJwdCZuYnNwOyZuYnNwOyAzMCZuYnNwOyZuYnNwOyZu
YnNwOyA3NTMuMTg5IMKxJm5ic3A7IDEyLjQ5OCZuYnNwOyBvcHMvbXM8YnI+R2V0QmVuY2htYXJr
cy5wcmVhbGxvY2F0ZWRCeXRlQnVmZmVyR2V0UmFuZG9tJm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7
Jm5ic3A7Jm5ic3A7Jm5ic3A7IG5vX2NvbHVtbl9mYW1pbHkmbmJzcDsmbmJzcDsmbmJzcDsmbmJz
cDsmbmJzcDsmbmJzcDsmbmJzcDsgMTAwMCZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZu
YnNwOyZuYnNwOyAxMjgmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsg
NjU1MzYmbmJzcDsgdGhycHQmbmJzcDsmbmJzcDsgMzAmbmJzcDsmbmJzcDsmbmJzcDsgMTAzLjY0
NCDCsSZuYnNwOyZuYnNwOyAzLjYyNSZuYnNwOyBvcHMvbXM8YnI+R2V0QmVuY2htYXJrcy5wcmVh
bGxvY2F0ZWRHZXQmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJz
cDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsm
bmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsgbm9fY29sdW1uX2ZhbWlseSZuYnNw
OyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyAxMDAwJm5ic3A7Jm5ic3A7Jm5i
c3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7IDEyOCZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZu
YnNwOyZuYnNwOyZuYnNwOyZuYnNwOyA0MDk2Jm5ic3A7IHRocnB0Jm5ic3A7Jm5ic3A7IDMwJm5i
c3A7Jm5ic3A7Jm5ic3A7IDcwNy4zMzAgwrEmbmJzcDsgMTAuODExJm5ic3A7IG9wcy9tczxicj5H
ZXRCZW5jaG1hcmtzLnByZWFsbG9jYXRlZEdldCZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNw
OyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZu
YnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyBub19j
b2x1bW5fZmFtaWx5Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7IDEw
MDAmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsgMTI4Jm5ic3A7Jm5i
c3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7IDY1NTM2Jm5ic3A7IHRocnB0Jm5ic3A7
Jm5ic3A7IDMwJm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7IDk2Ljc0MyDCsSZuYnNwOyZuYnNwOyAx
LjYwOSZuYnNwOyBvcHMvbXM8YnI+YGBgPC9wPjxwPkl0IHNlZW1zIG1vc3Qgb2YgdGhlIG51bWJl
cnMgYXJlIHJvdWdobHkgdGhlIHNhbWUuPC9wPjxwPkknbSBub3Qgc3VyZSBob3cgbXVjaCB0aGUg
dXBkYXRlIHRvIDIwIG1hdHRlcnMgLSBtYXliZSB0cnkgdG8gZml4IGFsbCBvZiB0aGUgb3RoZXIg
c3R1ZmYgZmlyc3QsIGFuZCBzZWUgd2hhdCBoYXBwZW5zIChpbmV4YWN0IHZhciBoYW5kbGUgY2Fs
bHMgY2FuIGJlIHF1aXRlIHNsb3cgY29tcGFyZWQgdG8gVW5zYWZlIG1lbW9yeSBhY2Nlc3MpLjxi
cj48L3A+PHA+Q2hlZXJzPGJyPk1hdXJpemlvPGJyPjwvcD48cHJlPjxicj48L3ByZT48ZGl2IGNs
YXNzPSJtb3otY2l0ZS1wcmVmaXgiPk9uIDA5LzAzLzIwMjMgMTg6MTMsIEFsYW4gUGF4dG9uIHdy
b3RlOjxicj48L2Rpdj48YmxvY2txdW90ZSB0eXBlPSJjaXRlIiBjaXRlPSJtaWQ6Q0FLQm9NUm09
Ym80UHNtSm5QNXg2bll6THNoM1dteWJHX0x2N0tGNTI9SHZtU2NBV09RQG1haWwuZ21haWwuY29t
Ij48bWV0YSBodHRwLWVxdWl2PSJDb250ZW50LVR5cGUiIGNvbnRlbnQ9InRleHQvaHRtbDsgIj48
ZGl2IGRpcj0ibHRyIj5IaSBNYXVyaXppbyw8ZGl2Pjxicj48L2Rpdj48ZGl2PlRoYW5rcyBmb3Ig
dGhlIHF1aWNrIGFuZCBkZXRhaWxlZCByZXNwb25zZS4gSSB0aGluayBvdXIgZ29hbHMgY29pbmNp
ZGUgYXMgaXQgd291bGQgbWFrZSBsaWZlIGVhc2llciBmb3Igcm9ja3NqYXZhIHRvIHN1Y2Nlc3Nm
dWxseSBpbXBsZW1lbnQgYW4gRkZJIEFQSS48L2Rpdj48ZGl2Pjxicj48L2Rpdj48ZGl2PkEgY291
cGxlIG9mIHF1aWNrIGluaXRpYWwgcmVydW5zIHNob3dzIG1lIHlvdXIgc3VnZ2VzdGlvbnMgYm90
aCBjb250cmlidXRlIGEgc21hbGwgYW1vdW50IG9mIGltcHJvdmVtZW50LCBidXQgcHJvYmFibHkg
ZG8gbm90IGFjY291bnQgZm9yIGFsbCB0aGUgcGVyZm9ybWFuY2UgSSBhbSBtaXNzaW5nLiBJIHNo
YWxsIHJlcnVuIHRoZSBmdWxsIGJlbmNobWFyayBmb3IgY29uZmlybWF0aW9uLjwvZGl2PjxkaXY+
PGJyPjwvZGl2PjxkaXY+QW5kIHNpbmNlIGJvdGggc3VnZ2VzdGlvbnMgZ2l2ZSBtZSBhIGNsZWFy
ZXIgaWRlYSB3aGF0IG1pZ2h0IGJlIHBlcmZvcm1hbmNlIGlzc3VlcywgSSB3aWxsIHRha2UgYW5v
dGhlciBwYXNzIG92ZXIgbXkgY29kZSBhbmQgc2VlIGlmIEkgY2FuIHNwb3QgYW55IG90aGVyIHBv
dGVudGlhbCBwcm9ibGVtcyBpbiBob3cgaXQncyBpbXBsZW1lbnRlZCwgb3IgYW55dGhpbmcgZWxz
ZSB0aGF0IGlzbid0IHRydWx5IGxpa2UtZm9yLWxpa2Ugd2l0aCB0aGUgSk5JIHZlcnNpb24uPC9k
aXY+PGRpdj48YnI+PC9kaXY+PGRpdj4tLUFsYW48L2Rpdj48L2Rpdj48YnI+PGRpdiBjbGFzcz0i
Z21haWxfcXVvdGUiPjxkaXYgZGlyPSJsdHIiIGNsYXNzPSJnbWFpbF9hdHRyIj5PbiBUaHUsIE1h
ciA5LCAyMDIzIGF0IDEyOjA44oCvUE0gTWF1cml6aW8gQ2ltYWRhbW9yZSAmbHQ7PGEgaHJlZj0i
bWFpbHRvOm1hdXJpemlvLmNpbWFkYW1vcmVAb3JhY2xlLmNvbSIgbW96LWRvLW5vdC1zZW5kPSJ0
cnVlIiBjbGFzcz0ibW96LXR4dC1saW5rLWZyZWV0ZXh0Ij5tYXVyaXppby5jaW1hZGFtb3JlQG9y
YWNsZS5jb208L2E+Jmd0OyB3cm90ZTo8YnI+PC9kaXY+PGJsb2NrcXVvdGUgY2xhc3M9ImdtYWls
X3F1b3RlIiBzdHlsZT0ibWFyZ2luOjBweCAwcHggMHB4IDAuOGV4O2JvcmRlci1sZWZ0OjFweCBz
b2xpZCByZ2IoMjA0LDIwNCwyMDQpO3BhZGRpbmctbGVmdDoxZXgiPgoKICAKICA8ZGl2PgogICAg
PHA+QWxzbywgem9vbWluZyBpbnRvIHRoZSBiZW5jaG1hcmssIHNvbWV0aGluZyBmdW5ueSBzZWVt
cyB0byBiZQogICAgICBnb2luZyBvbiB3aXRoICI8c3Bhbj5nZXRLZXlTZWdtZW50Ii4gVGhpcyBz
ZWVtcwogICAgICAgIGRpZmZlcmVudCBmcm9tIHRoZSAiZ2V0S2V5QXJyIiBjb3VudGVycGFydCwg
YnV0IGFsc28gaGFzIGEgbmV3CiAgICAgICAgaXNzdWU6IEkgYmVsaWV2ZSB0aGF0LCBpbiBKTkks
IHlvdSBqdXN0IHBhc3NlZCB0aGUgSmF2YSBhcnJheQogICAgICAgICJhcyBpcyIgLSBidXQgaW4g
UGFuYW1hIHlvdSBjYW4ndCAoYXMgdGhlIGFycmF5IGlzIG9uLWhlYXApLCBzbwogICAgICAgIHRo
ZXJlIGlzIHNvbWUgZG91YmxlLWNvcHlpbmcgaW52b2x2ZWQgdGhlcmUgKGUuZy4geW91IGNyZWF0
ZSBhbgogICAgICAgIG9uLWhlYXAgYXJyYXksIHdoaWNoIHRoZW4gaXMgbW92ZWQgb2ZmLWhlYXAp
Ljwvc3Bhbj48L3A+CiAgICA8cD48c3Bhbj5JZiBJJ20gbm90IG1pc3Rha2VuLCB0aGlzIG1ldGhv
ZCBpcyBleGVjdXRlZAogICAgICAgIG9uIGV2ZXJ5IGJlbmNobWFyayBpdGVyYXRpb24sIHNvIHRo
ZSBjb21wYXJpc29uIGRvZXNuJ3QganVzdAogICAgICAgIG1lc3VyZSB0aGUgY29zdCBvZiB0aGUg
bmF0aXZlIGNhbGwsIGJ1dCBhbHNvIHRoZSBjb3N0IGl0IHRha2VzCiAgICAgICAgdG8gbWFyc2hh
bCBkYXRhIGZyb20gSmF2YSBoZWFwIHRvIG5hdGl2ZS48L3NwYW4+PC9wPgogICAgPHA+PHNwYW4+
Rm9yIGluc3RhbmNlLCB0aGUgYnl0ZSBidWZmZXIgdmVyc2lvbnMKICAgICAgICAoImtleUJ1ZiIp
IHNlZW0gdG8gYXZvaWQgdGhpcyBwcm9ibGVtIGJ5IGNvcHlpbmcgdGhlIGRhdGEKICAgICAgICBk
aXJlY3RseSBvZmYtaGVhcCAoYnkgdXNpbmcgYSBkaXJlY3QgYnVmZmVyKS4gSSB0aGluayB0aGUK
ICAgICAgICBiZW5jaG1hcmsgc2hvdWxkIHVzZSBhIG5hdGl2ZSBzZWdtZW50LCBhbmQgYXZvaWQg
dGhlIGNvcHkgc28KICAgICAgICB0aGF0IGF0IGxlYXN0IHdlIGF2b2lkIHRoYXQgc291cmNlIG9m
IG5vaXNlIGluIHRoZSBudW1iZXJzLjwvc3Bhbj48L3A+CiAgICA8cD48c3Bhbj5DaGVlcnM8YnI+
CiAgICAgICAgTWF1cml6aW88YnI+CiAgICAgIDwvc3Bhbj48L3A+CiAgICA8ZGl2Pk9uIDA5LzAz
LzIwMjMgMTE6MjksIE1hdXJpemlvCiAgICAgIENpbWFkYW1vcmUgd3JvdGU6PGJyPgogICAgPC9k
aXY+CiAgICA8YmxvY2txdW90ZSB0eXBlPSJjaXRlIj5IaQogICAgICBBbGFuLAogICAgICA8YnI+
CiAgICAgIGZpcnN0IG9mIGFsbCwgSSdkIGxpa2UgdG8gdGhhbmsgeW91IGZvciB0YWtpbmcgdGhl
IHRpbWUgdG8gc2hhcmUKICAgICAgeW91ciBleHBlcmllbmNlIGFuZCB0byB3cml0ZSBpdCBhbGwg
dXAgaW4gYSBkb2N1bWVudC4gU3R1ZmYgbGlrZQogICAgICB0aGF0IGlzIHZlcnkgdmFsdWFibGUg
dG8gdXMsIGVzcGVjaWFsbHkgYXQgdGhpcyBzdGFnZSBpbiB0aGUKICAgICAgcHJvamVjdC4KICAg
ICAgPGJyPgogICAgICA8YnI+CiAgICAgIE9uZSBxdWljayBzdWdnZXN0aW9uIHdoZW4gZXllYmFs
bGluZyB5b3VyIGNvZGU6IHlvdXIgbWV0aG9kCiAgICAgIGhhbmRsZXMgYXJlICJzdGF0aWMiLCBi
dXQgbm90ICJmaW5hbCIuIEkgc3VnZ2VzdCB5b3UgdHJ5IHRvCiAgICAgIHNwcmlua2xlICJmaW5h
bCIgaW4sIGFuZCBzZWUgd2hldGhlciB0aGF0IGRvZXMgdGhlIHRyaWNrLiBJZiBub3QsCiAgICAg
IHdlJ2QgaGF2ZSB0byBsb29rIGRlZXBlci4KICAgICAgPGJyPgogICAgICA8YnI+CiAgICAgIENo
ZWVycwogICAgICA8YnI+CiAgICAgIE1hdXJpemlvCiAgICAgIDxicj4KICAgICAgPGJyPgogICAg
ICBPbiAwOS8wMy8yMDIzIDExOjE1LCBBbGFuIFBheHRvbiB3cm90ZToKICAgICAgPGJyPgogICAg
ICA8YmxvY2txdW90ZSB0eXBlPSJjaXRlIj5IaSwKICAgICAgICA8YnI+CiAgICAgICAgPGJyPgog
ICAgICAgIEkgaG9wZSB0aGlzIGlzIGFuIGFwcHJvcHJpYXRlIGxpc3QgZm9yIHRoaXMgcXVlc3Rp
b24uCiAgICAgICAgPGJyPgogICAgICAgIDxicj4KICAgICAgICBJIGhhdmUgYmVlbiBwcm90b3R5
cGluZyBhbiBGRkktYmFzZWQgdmVyc2lvbiBvZiB0aGUgUm9ja3NEQiBKYXZhCiAgICAgICAgQVBJ
LCB3aGljaCBpcyBjdXJyZW50bHkgaW1wbGVtZW50ZWQgaW4gSk5JLiBSb2Nrc0RCIGlzIGEgQysr
CiAgICAgICAgYmFzZWQga2V5LHZhbHVlLXN0b3JlIHdpdGggYSBKYXZhIEFQSSBsYXllcmVkIG9u
IHRvcC4gSSBoYXZlCiAgICAgICAgZG9uZSBzb21lIGJlbmNobWFya2luZyBvZiB0aGUgRkZJIGlt
cGxlbWVudGF0aW9uLCB2ZXJzdXMgdGhlIEpOSQogICAgICAgIHZlcnNpb24gYW5kIEkgZmluZCBp
dCBwZXJmb3JtcyBjb25zaXN0ZW50bHkgc2xpZ2h0bHkgc2xvd2VyIHRoYW4KICAgICAgICB0aGUg
Y3VycmVudCBBUEkuCiAgICAgICAgPGJyPgogICAgICAgIDxicj4KICAgICAgICBJIHdvdWxkIGxp
a2UgdG8gdW5kZXJzdGFuZCBpZiB0aGlzIGlzIHRvIGJlIGV4cGVjdGVkLCBlLmcuIGRvZXMKICAg
ICAgICBGRkkgZG8gbW9yZSBzYWZldHkgY2hlY2tpbmcgdW5kZXIgdGhlIGNvdmVycyB3aGVuIGNh
bGxpbmcgYQogICAgICAgIG5hdGl2ZSBtZXRob2QgPwogICAgICAgIDxicj4KICAgICAgICBPciBp
cyB0aGUgcGVyZm9ybWFuY2UgbGlrZWx5IHRvIGltcHJvdmUgYmV0d2VlbiB0aGUgcHJldmlldyBp
bgogICAgICAgIEphdmEgMTkgYW5kIHJlbGVhc2UgaW4gSmF2YSAyMSA/CiAgICAgICAgPGJyPgog
ICAgICAgIElmIHRoZXJlIGFyZSByZXNvdXJjZXMgb3Igc3VnZ2VzdGlvbnMgdGhhdCB3b3VsZCBo
ZWxwIG1lIGRpZwogICAgICAgIGludG8gdGhlIHBlcmZvcm1hbmNlIEknZCBiZSB2ZXJ5IGdyYXRl
ZnVsIHRvIGJlIHBvaW50ZWQgdG8gdGhlbS4KICAgICAgICA8YnI+CiAgICAgICAgPGJyPgogICAg
ICAgIEZvciB0aGUgdXNlIGNhc2UgSSdtIG1lYXN1cmluZywgZGF0YSBpcyB0cmFuc2ZlcnJlZCBp
biBuYXRpdmUKICAgICAgICBtZW1vcnkgb3JpZ2luYWxseSBhbGxvY2F0ZWQgYnkgUm9ja3NEQiBp
biBDKysgd2hpY2ggSSB3cmFwIGFzIGEKICAgICAgICBNZW1vcnlTZWdtZW50OyBJIGRvIGFsbG9j
YXRlIG5hdGl2ZSBtZW1vcnkgZm9yIHRoZSByZXF1ZXN0CiAgICAgICAgc3RydWN0dXJlLgogICAg
ICAgIDxicj4KICAgICAgICA8YnI+CiAgICAgICAgVGhlc2UgYXJlIGxpbmtzIHRvIHRoZSBQUiBh
bmQgc29tZSBkb2N1bWVudGF0aW9uIG9mIHRoZSB3b3JrOgogICAgICAgIDxicj4KICAgICAgICA8
YnI+CiAgICAgICAgPGEgaHJlZj0iaHR0cHM6Ly91cmxkZWZlbnNlLmNvbS92My9fX2h0dHBzOi8v
Z2l0aHViLmNvbS9mYWNlYm9vay9yb2Nrc2RiL3B1bGwvMTEwOTVfXzshIUFDV1Y1TjlNMlJWOTlo
USFQTTNIR2Y5Q1REZU5GNXpzQl90NXFmZlVIMTdwbVoyVzhwc0pGNmV3amdVSERKbnJ4dTYwQ2dK
bmhPcjNERjNsUGw2WVBLZS1uaWIzOE0zTHdQM08tNTdFS0I4TyQiIHRhcmdldD0iX2JsYW5rIiBt
b3otZG8tbm90LXNlbmQ9InRydWUiPmh0dHBzOi8vZ2l0aHViLmNvbS9mYWNlYm9vay9yb2Nrc2Ri
L3B1bGwvMTEwOTU8L2E+CiAgICAgICAgPGJyPgo8YSBocmVmPSJodHRwczovL3VybGRlZmVuc2Uu
Y29tL3YzL19faHR0cHM6Ly9naXRodWIuY29tL2FsYW5wYXh0b24vcm9ja3NkYi9ibG9iL2ViLTE2
ODAtcGFuYW1hLWZmaS9qYXZhL0phdmFGRkkubWRfXzshIUFDV1Y1TjlNMlJWOTloUSFQTTNIR2Y5
Q1REZU5GNXpzQl90NXFmZlVIMTdwbVoyVzhwc0pGNmV3amdVSERKbnJ4dTYwQ2dKbmhPcjNERjNs
UGw2WVBLZS1uaWIzOE0zTHdQM08tNVNrcEpFVSQiIHRhcmdldD0iX2JsYW5rIiBtb3otZG8tbm90
LXNlbmQ9InRydWUiPmh0dHBzOi8vZ2l0aHViLmNvbS9hbGFucGF4dG9uL3JvY2tzZGIvYmxvYi9l
Yi0xNjgwLXBhbmFtYS1mZmkvamF2YS9KYXZhRkZJLm1kPC9hPgogICAgICAgIDxicj4KICAgICAg
ICA8YnI+CiAgICAgICAgTWFueSB0aGFua3MsCiAgICAgICAgPGJyPgogICAgICAgIEFsYW4gUGF4
dG9uCiAgICAgICAgPGJyPgogICAgICAgIDxicj4KICAgICAgPC9ibG9ja3F1b3RlPgogICAgPC9i
bG9ja3F1b3RlPgogIDwvZGl2PgoKPC9ibG9ja3F1b3RlPjwvZGl2PgoKPC9ibG9ja3F1b3RlPg==" style="height:0;width:0;max-height:0;max-width:0;overflow:hidden;font-size:0em;padding:0;margin:0;"></div>
</div>
</body>
</html>