<div dir="ltr"><div class="markdown-here-wrapper" style=""><blockquote style="margin:1.2em 0px;border-left:4px solid rgb(221,221,221);padding:0px 1em;color:rgb(119,119,119);quotes:none">
<p style="margin:0px 0px 1.2em!important">In NumPy 1.14 we changed  UPDATEIFCOPY to WRITEBACKIFCOPY, and in 1.16 we would like to deprecate  PyArray_SetNumericOps and PyArray_GetNumericOps. The strange warning when NPY_NO_DEPRICATED_API is annoying</p>
</blockquote>
<p style="margin:0px 0px 1.2em!important">I’m not sure I make the connection here between hidden fields and API deprecation. You seem to be asking two vaguely related questions:</p>
<ol style="margin:1.2em 0px;padding-left:2em">
<li style="margin:0.5em 0px">Should we have deprecated field access in the first place</li>
<li style="margin:0.5em 0px">Does our api deprecation mechanism need work</li>
</ol>
<p style="margin:0px 0px 1.2em!important">I think a more substantial problem statement is needed for 2, so I’m only going to respond to 1 here.</p>
<p style="margin:0px 0px 1.2em!important">Hiding fields seems to me to match the CPython model of things, where your public api is <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">PyArray<thing>_SomeGetter(thing)</code>.<br>If you look <a href="https://github.com/python/cpython/blob/e0720cd/Include/tupleobject.h#L24-L34">at the cpython source code</a>, they only expose the underlying struct fields if you don’t define <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">Py_LIMITED_API</code>, ie if you as a consumer volunteer to be broken by upstream changes in minor versions. People (like us) are willing to produce separate builds for each python versions, so often do not define this.</p>
<p style="margin:0px 0px 1.2em!important">We could add a similar <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">PyArray_LIMITED_API</code> that allows field access under a similar guarantee - the question is, are many downstream consumers willing to produce builds against multiple numpy versions? (especially if they also do so against multiple python versions)</p>
<blockquote style="margin:1.2em 0px;border-left:4px solid rgb(221,221,221);padding:0px 1em;color:rgb(119,119,119);quotes:none">
<p style="margin:0px 0px 1.2em!important">Also, for example, cython has a mechanism to transpile  python code into C, mapping slow python attribute lookup to fast C  struct field access </p>
</blockquote>
<p style="margin:0px 0px 1.2em!important">How does this work for builtin types? Does cython deliberately not define <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">Py_LIMITED_API</code>? Or are you just forced to use <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">PyTuple_GetItem(t)</code> if you want the fast path.</p>
<p style="margin:0px 0px 1.2em!important">Eric</p>
<p style="margin:0px 0px 1.2em!important">On Tue, 30 Oct 2018 at 02:04 Matti Picus <<a href="mailto:matti.picus@gmail.com" target="_blank">matti.picus@gmail.com</a>> wrote:</p>
<p style="margin:0px 0px 1.2em!important"></p><div class="markdown-here-exclude"><p></p><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">TL;DR - should we revert the attribute-hiding constructs in <br>
ndarraytypes.h and unify PyArrayObject_fields with PyArrayObject?<br>
<br>
<br>
Background<br>
<br>
<br>
NumPy 1.8 deprecated direct access to PyArrayObject fields. It made <br>
PyArrayObject "opaque", and hid the fields behind a PyArrayObject_fields <br>
structure <br>
<a href="https://github.com/numpy/numpy/blob/v1.15.3/numpy/core/include/numpy/ndarraytypes.h#L659" rel="noreferrer" target="_blank">https://github.com/numpy/numpy/blob/v1.15.3/numpy/core/include/numpy/ndarraytypes.h#L659</a> <br>
with a comment about moving this to a private header. In order to access <br>
the fields, users are supposed to use PyArray_FIELDNAME functions, like <br>
PyArray_DATA and PyArray_NDIM. It seems there were thoughts at the time <br>
that numpy might move away from a C-struct based<br>
<br>
underlying data structure. Other changes were also made to enum names, <br>
but those are relatively painless to find-and-replace.<br>
<br>
<br>
NumPy has a mechanism to manage deprecating APIs, C users define <br>
NPY_NO_DEPRICATED_API to a desired level, say NPY_1_8_API_VERSION, and <br>
can then access the API "as if" they were using NumPy 1.8. Users who do <br>
not define NPY_NO_DEPRICATED_API get a warning when compiling, and <br>
default to the pre-1.8 API (aliasing of PyArrayObject to <br>
PyArrayObject_fields and direct access to the C struct fields). This is <br>
convenient for downstream users, both since the new API does not provide <br>
much added value, and it is much easier to write a->nd than <br>
PyArray_NDIM(a). For instance, pandas uses direct assignment to the data <br>
field for fast json parsing <br>
<a href="https://github.com/pandas-dev/pandas/blob/master/pandas/_libs/src/ujson/python/JSONtoObj.c#L203" rel="noreferrer" target="_blank">https://github.com/pandas-dev/pandas/blob/master/pandas/_libs/src/ujson/python/JSONtoObj.c#L203</a> <br>
via chunks. Working around the new API in pandas would require more <br>
engineering. Also, for example, cython has a mechanism to transpile <br>
python code into C, mapping slow python attribute lookup to fast C <br>
struct field access <br>
<a href="https://cython.readthedocs.io/en/latest/src/userguide/extension_types.html#external-extension-types" rel="noreferrer" target="_blank">https://cython.readthedocs.io/en/latest/src/userguide/extension_types.html#external-extension-types</a><br>
<br>
<br>
In a parallel but not really related universe, cython recently upgraded <br>
the object mapping so that we can quiet the annoying "size changed" <br>
runtime warning <a href="https://github.com/numpy/numpy/issues/11788" rel="noreferrer" target="_blank">https://github.com/numpy/numpy/issues/11788</a> without <br>
requiring warning filters, but that requires updating the numpy.pxd file <br>
provided with cython, and it was proposed that NumPy actually vendor its <br>
own file rather than depending on the cython one <br>
(<a href="https://github.com/numpy/numpy/issues/11803" rel="noreferrer" target="_blank">https://github.com/numpy/numpy/issues/11803</a>).<br>
<br>
<br>
The problem<br>
<br>
<br>
We have now made further changes to our API. In NumPy 1.14 we changed <br>
UPDATEIFCOPY to WRITEBACKIFCOPY, and in 1.16 we would like to deprecate <br>
PyArray_SetNumericOps and PyArray_GetNumericOps. The strange warning <br>
when NPY_NO_DEPRICATED_API is annoying. The new API cannot be supported <br>
by cython without some deep surgery <br>
(<a href="https://github.com/cython/cython/pull/2640" rel="noreferrer" target="_blank">https://github.com/cython/cython/pull/2640</a>). When I tried dogfooding an <br>
updated numpy.pxd for the only cython code in NumPy, mtrand.pxy, I came <br>
across some of these issues (<a href="https://github.com/numpy/numpy/pull/12284" rel="noreferrer" target="_blank">https://github.com/numpy/numpy/pull/12284</a>). <br>
Forcing the new API will require downstream users to refactor code or <br>
re-engineer constructs, as in the pandas example above.<br>
<br>
<br>
The question<br>
<br>
<br>
Is the attribute-hiding effort worth it? Should we give up, revert the <br>
PyArrayObject/PyArrayObject_fields division and allow direct access from <br>
C to the numpy internals? Is there another path forward that is less <br>
painful?<br>
<br>
<br>
Matti<br>
<br>
_______________________________________________<br>
NumPy-Discussion mailing list<br>
<a href="mailto:NumPy-Discussion@python.org" target="_blank">NumPy-Discussion@python.org</a><br>
<a href="https://mail.python.org/mailman/listinfo/numpy-discussion" rel="noreferrer" target="_blank">https://mail.python.org/mailman/listinfo/numpy-discussion</a><br>
</blockquote><p></p></div><p style="margin:0px 0px 1.2em!important"></p>
<div title="MDH:PGRpdiBkaXI9Imx0ciI+PGRpdj4mZ3Q7Jm5ic3A7PHNwYW4gc3R5bGU9ImNvbG9yOiByZ2IoMzMs
IDMzLCAzMyk7Ij5JbiBOdW1QeSAxLjE0IHdlIGNoYW5nZWQ8L3NwYW4+PHNwYW4gc3R5bGU9ImNv
bG9yOiByZ2IoMzMsIDMzLCAzMyk7Ij4mbmJzcDsmbmJzcDs8L3NwYW4+PHNwYW4gc3R5bGU9ImNv
bG9yOiByZ2IoMzMsIDMzLCAzMyk7Ij5VUERBVEVJRkNPUFkgdG8gV1JJVEVCQUNLSUZDT1BZLCBh
bmQgaW4gMS4xNiB3ZSB3b3VsZCBsaWtlIHRvIGRlcHJlY2F0ZTwvc3Bhbj48c3BhbiBzdHlsZT0i
Y29sb3I6IHJnYigzMywgMzMsIDMzKTsiPiZuYnNwOyZuYnNwOzwvc3Bhbj48c3BhbiBzdHlsZT0i
Y29sb3I6IHJnYigzMywgMzMsIDMzKTsiPlB5QXJyYXlfPHdicj5TZXROdW1lcmljT3BzIGFuZCBQ
eUFycmF5X0dldE51bWVyaWNPcHMuIFRoZSBzdHJhbmdlIHdhcm5pbmc8L3NwYW4+PHNwYW4gc3R5
bGU9ImNvbG9yOiByZ2IoMzMsIDMzLCAzMyk7Ij4mbmJzcDs8L3NwYW4+PHNwYW4gc3R5bGU9ImNv
bG9yOiByZ2IoMzMsIDMzLCAzMyk7Ij53aGVuIE5QWV9OT19ERVBSSUNBVEVEX0FQSSBpcyBhbm5v
eWluZzwvc3Bhbj48YnI+PC9kaXY+PC9kaXY+PGRpdiBkaXI9Imx0ciI+PHNwYW4gc3R5bGU9ImNv
bG9yOnJnYigzMywzMywzMykiPjxkaXY+PHNwYW4gc3R5bGU9ImNvbG9yOnJnYigzMywzMywzMyki
Pjxicj48L3NwYW4+PC9kaXY+SSdtIG5vdCBzdXJlIEkgbWFrZSB0aGUgY29ubmVjdGlvbiBoZXJl
IGJldHdlZW4gaGlkZGVuIGZpZWxkcyBhbmQgQVBJIGRlcHJlY2F0aW9uLiBZb3Ugc2VlbSB0byBi
ZSBhc2tpbmcgdHdvIHVucmVsYXRlZCBxdWVzdGlvbnM6PC9zcGFuPjxkaXY+PGJyPjwvZGl2Pjxk
aXY+MS4gU2hvdWxkIHdlIGhhdmUgZGVwcmVjYXRlZCBmaWVsZCBhY2Nlc3MgaW4gdGhlIGZpcnN0
IHBsYWNlPC9kaXY+PGRpdj4yLiBEb2VzIG91ciBhcGkgZGVwcmVjYXRpb24gbWVjaGFuaXNtIG5l
ZWQgd29yazwvZGl2PjxkaXY+PGJyPjwvZGl2PjxkaXY+SSB0aGluayBhIG1vcmUgc3Vic3RhbnRp
YWwgcHJvYmxlbSBzdGF0ZW1lbnQgaXMgbmVlZGVkIGZvciB0d28sIHNvIEknbSBvbmx5IGdvaW5n
IHRvIHJlc3BvbmQgdG8gMSBoZXJlLjwvZGl2PjxkaXY+PGJyPjwvZGl2PjxkaXY+SGlkaW5nIGZp
ZWxkcyBzZWVtcyB0byBtZSB0byBtYXRjaCB0aGUgQ1B5dGhvbiBtb2RlbCBvZiB0aGluZ3MsIHdo
ZXJlIHlvdXIgcHVibGljIGFwaSBpcyBgUHlBcnJheSZsdDt0aGluZyZndDtfU29tZUdldHRlcig8
d2JyPnRoaW5nKWAuPGRpdj48YnI+PC9kaXY+PGRpdj5JZiB5b3UgbG9vayBbYXQgdGhlIGNweXRo
b24gc291cmNlIGNvZGVdKDxhIGhyZWY9Imh0dHBzOi8vZ2l0aHViLmNvbS9weXRob24vY3B5dGhv
bi9ibG9iL2UwNzIwY2QvSW5jbHVkZS90dXBsZW9iamVjdC5oI0wyNC1MMzQiIHRhcmdldD0iX2Js
YW5rIj5odHRwczovL2dpdGh1Yi5jb20vPHdicj5weXRob24vY3B5dGhvbi9ibG9iL2UwNzIwY2Qv
PHdicj5JbmNsdWRlL3R1cGxlb2JqZWN0LmgjTDI0LUwzNDwvYT4pPHdicj4sIHRoZXkgb25seSBl
eHBvc2UgdGhlIHVuZGVybHlpbmcgc3RydWN0IGZpZWxkcyBpZiB5b3UgZG9uJ3QgZGVmaW5lIGBQ
eV9MSU1JVEVEX0FQSWAsIGllIHZvbHVudGVlciB0byBiZSBicm9rZW4gYnkgdXBzdHJlYW0gY2hh
bmdlcyBpbiBtaW5vciB2ZXJzaW9ucy4gUGVvcGxlIChsaWtlIHVzKSBhcmUgd2lsbGluZyB0byBw
cm9kdWNlIHNlcGFyYXRlIGJ1aWxkcyBmb3IgZWFjaCBweXRob24gdmVyc2lvbnMsIHNvIG9mdGVu
IGRvIG5vdCBkZWZpbmUgdGhpcy48L2Rpdj48ZGl2Pjxicj48L2Rpdj48ZGl2PldlIGNvdWxkIGFk
ZCBhIHNpbWlsYXIgYFB5QXJyYXlfTElNSVRFRF9BUElgIHRoYXQgYWxsb3dzIGZpZWxkIGFjY2Vz
cyB1bmRlciBhIHNpbWlsYXIgZ3VhcmFudGVlIC0gYnV0IEkgZG9uJ3QgdGhpbmsgbWFueSBkb3du
c3RyZWFtIGNvbnN1bWVycyBhcmUgd2lsbGluZyB0byBwcm9kdWNlIGJ1aWxkcyBhZ2FpbnN0IG11
bHRpcGxlIG51bXB5IHZlcnNpb25zLCBzbyB0aGVyZSdkIGJlIGxpdHRsZSBwb2ludC48L2Rpdj48
ZGl2IGRpcj0ibHRyIj48ZGl2PjxkaXY+PGJyPjwvZGl2PjxkaXY+Jmd0OyZuYnNwOzxzcGFuIHN0
eWxlPSJjb2xvcjogcmdiKDMzLCAzMywgMzMpOyI+QWxzbywgZm9yIGV4YW1wbGUsIGN5dGhvbiBo
YXMgYSBtZWNoYW5pc20gdG8gdHJhbnNwaWxlPC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xvcjogcmdi
KDMzLCAzMywgMzMpOyI+Jm5ic3A7Jm5ic3A7PC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xvcjogcmdi
KDMzLCAzMywgMzMpOyI+cHl0aG9uIGNvZGUgaW50byBDLCBtYXBwaW5nIHNsb3cgcHl0aG9uIGF0
dHJpYnV0ZSBsb29rdXAgdG8gZmFzdCBDPC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xvcjogcmdiKDMz
LCAzMywgMzMpOyI+Jm5ic3A7Jm5ic3A7PC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xvcjogcmdiKDMz
LCAzMywgMzMpOyI+c3RydWN0IGZpZWxkIGFjY2Vzczwvc3Bhbj48c3BhbiBzdHlsZT0iY29sb3I6
IHJnYigzMywgMzMsIDMzKTsiPiZuYnNwOzwvc3Bhbj48L2Rpdj48L2Rpdj48L2Rpdj48ZGl2IGRp
cj0ibHRyIj48ZGl2PjxzcGFuIHN0eWxlPSJjb2xvcjogcmdiKDMzLCAzMywgMzMpOyI+PGJyPkhv
dyBkb2VzIHRoaXMgd29yayBmb3IgYnVpbHRpbiB0eXBlcz8gRG9lcyBjeXRob24gZGVsaWJlcmF0
ZWx5IG5vdCBkZWZpbmUgYDwvc3Bhbj5QeV9MSU1JVEVEX0FQSWA/IE9yIGFyZSB5b3UganVzdCBm
b3JjZWQgdG8gdXNlIGBQeVR1cGxlX0dldEl0ZW0odClgIGlmIHlvdSB3YW50IHRoZSBmYXN0IHBh
dGguPC9kaXY+PGRpdj48YnI+PC9kaXY+PC9kaXY+PC9kaXY+PC9kaXY+PGRpdiBkaXI9Imx0ciI+
PGRpdj5FcmljPC9kaXY+PC9kaXY+PGJyPjxkaXYgY2xhc3M9ImdtYWlsX3F1b3RlIj48ZGl2IGRp
cj0ibHRyIj5PbiBUdWUsIDMwIE9jdCAyMDE4IGF0IDAyOjA0IE1hdHRpIFBpY3VzICZsdDs8YSBo
cmVmPSJtYWlsdG86bWF0dGkucGljdXNAZ21haWwuY29tIiB0YXJnZXQ9Il9ibGFuayI+bWF0dGku
cGljdXNAZ21haWwuY29tPC9hPiZndDsgd3JvdGU6PGJyPjwvZGl2PjxibG9ja3F1b3RlIGNsYXNz
PSJnbWFpbF9xdW90ZSIgc3R5bGU9Im1hcmdpbjowIDAgMCAuOGV4O2JvcmRlci1sZWZ0OjFweCAj
Y2NjIHNvbGlkO3BhZGRpbmctbGVmdDoxZXgiPlRMO0RSIC0gc2hvdWxkIHdlIHJldmVydCB0aGUg
YXR0cmlidXRlLWhpZGluZyBjb25zdHJ1Y3RzIGluIDxicj4KbmRhcnJheXR5cGVzLmggYW5kIHVu
aWZ5IFB5QXJyYXlPYmplY3RfZmllbGRzIHdpdGggUHlBcnJheU9iamVjdD88YnI+Cjxicj4KPGJy
PgpCYWNrZ3JvdW5kPGJyPgo8YnI+Cjxicj4KTnVtUHkgMS44IGRlcHJlY2F0ZWQgZGlyZWN0IGFj
Y2VzcyB0byBQeUFycmF5T2JqZWN0IGZpZWxkcy4gSXQgbWFkZSA8YnI+ClB5QXJyYXlPYmplY3Qg
Im9wYXF1ZSIsIGFuZCBoaWQgdGhlIGZpZWxkcyBiZWhpbmQgYSBQeUFycmF5T2JqZWN0X2ZpZWxk
cyA8YnI+CnN0cnVjdHVyZSA8YnI+CjxhIGhyZWY9Imh0dHBzOi8vZ2l0aHViLmNvbS9udW1weS9u
dW1weS9ibG9iL3YxLjE1LjMvbnVtcHkvY29yZS9pbmNsdWRlL251bXB5L25kYXJyYXl0eXBlcy5o
I0w2NTkiIHJlbD0ibm9yZWZlcnJlciIgdGFyZ2V0PSJfYmxhbmsiIGRhdGEtc2FmZXJlZGlyZWN0
dXJsPSJodHRwczovL3d3dy5nb29nbGUuY29tL3VybD9xPWh0dHBzOi8vZ2l0aHViLmNvbS9udW1w
eS9udW1weS9ibG9iL3YxLjE1LjMvbnVtcHkvY29yZS9pbmNsdWRlL251bXB5L25kYXJyYXl0eXBl
cy5oJTIzTDY1OSZhbXA7c291cmNlPWdtYWlsJmFtcDt1c3Q9MTU0MTAzNjAxNjI4NDAwMCZhbXA7
dXNnPUFGUWpDTkd0eGl1OWRzb0ZpUjZOWi10UkFjZXMzaTJyeVEiPmh0dHBzOi8vZ2l0aHViLmNv
bS9udW1weS88d2JyPm51bXB5L2Jsb2IvdjEuMTUuMy9udW1weS9jb3JlLzx3YnI+aW5jbHVkZS9u
dW1weS9uZGFycmF5dHlwZXMuaCM8d2JyPkw2NTk8L2E+IDxicj4Kd2l0aCBhIGNvbW1lbnQgYWJv
dXQgbW92aW5nIHRoaXMgdG8gYSBwcml2YXRlIGhlYWRlci4gSW4gb3JkZXIgdG8gYWNjZXNzIDxi
cj4KdGhlIGZpZWxkcywgdXNlcnMgYXJlIHN1cHBvc2VkIHRvIHVzZSBQeUFycmF5X0ZJRUxETkFN
RSBmdW5jdGlvbnMsIGxpa2UgPGJyPgpQeUFycmF5X0RBVEEgYW5kIFB5QXJyYXlfTkRJTS4gSXQg
c2VlbXMgdGhlcmUgd2VyZSB0aG91Z2h0cyBhdCB0aGUgdGltZSA8YnI+CnRoYXQgbnVtcHkgbWln
aHQgbW92ZSBhd2F5IGZyb20gYSBDLXN0cnVjdCBiYXNlZDxicj4KPGJyPgp1bmRlcmx5aW5nIGRh
dGEgc3RydWN0dXJlLiBPdGhlciBjaGFuZ2VzIHdlcmUgYWxzbyBtYWRlIHRvIGVudW0gbmFtZXMs
IDxicj4KYnV0IHRob3NlIGFyZSByZWxhdGl2ZWx5IHBhaW5sZXNzIHRvIGZpbmQtYW5kLXJlcGxh
Y2UuPGJyPgo8YnI+Cjxicj4KTnVtUHkgaGFzIGEgbWVjaGFuaXNtIHRvIG1hbmFnZSBkZXByZWNh
dGluZyBBUElzLCBDIHVzZXJzIGRlZmluZSA8YnI+Ck5QWV9OT19ERVBSSUNBVEVEX0FQSSB0byBh
IGRlc2lyZWQgbGV2ZWwsIHNheSBOUFlfMV84X0FQSV9WRVJTSU9OLCBhbmQgPGJyPgpjYW4gdGhl
biBhY2Nlc3MgdGhlIEFQSSAiYXMgaWYiIHRoZXkgd2VyZSB1c2luZyBOdW1QeSAxLjguIFVzZXJz
IHdobyBkbyA8YnI+Cm5vdCBkZWZpbmUgTlBZX05PX0RFUFJJQ0FURURfQVBJIGdldCBhIHdhcm5p
bmcgd2hlbiBjb21waWxpbmcsIGFuZCA8YnI+CmRlZmF1bHQgdG8gdGhlIHByZS0xLjggQVBJIChh
bGlhc2luZyBvZiBQeUFycmF5T2JqZWN0IHRvIDxicj4KUHlBcnJheU9iamVjdF9maWVsZHMgYW5k
IGRpcmVjdCBhY2Nlc3MgdG8gdGhlIEMgc3RydWN0IGZpZWxkcykuIFRoaXMgaXMgPGJyPgpjb252
ZW5pZW50IGZvciBkb3duc3RyZWFtIHVzZXJzLCBib3RoIHNpbmNlIHRoZSBuZXcgQVBJIGRvZXMg
bm90IHByb3ZpZGUgPGJyPgptdWNoIGFkZGVkIHZhbHVlLCBhbmQgaXQgaXMgbXVjaCBlYXNpZXIg
dG8gd3JpdGUgYS0mZ3Q7bmQgdGhhbiA8YnI+ClB5QXJyYXlfTkRJTShhKS4gRm9yIGluc3RhbmNl
LCBwYW5kYXMgdXNlcyBkaXJlY3QgYXNzaWdubWVudCB0byB0aGUgZGF0YSA8YnI+CmZpZWxkIGZv
ciBmYXN0IGpzb24gcGFyc2luZyA8YnI+CjxhIGhyZWY9Imh0dHBzOi8vZ2l0aHViLmNvbS9wYW5k
YXMtZGV2L3BhbmRhcy9ibG9iL21hc3Rlci9wYW5kYXMvX2xpYnMvc3JjL3Vqc29uL3B5dGhvbi9K
U09OdG9PYmouYyNMMjAzIiByZWw9Im5vcmVmZXJyZXIiIHRhcmdldD0iX2JsYW5rIiBkYXRhLXNh
ZmVyZWRpcmVjdHVybD0iaHR0cHM6Ly93d3cuZ29vZ2xlLmNvbS91cmw/cT1odHRwczovL2dpdGh1
Yi5jb20vcGFuZGFzLWRldi9wYW5kYXMvYmxvYi9tYXN0ZXIvcGFuZGFzL19saWJzL3NyYy91anNv
bi9weXRob24vSlNPTnRvT2JqLmMlMjNMMjAzJmFtcDtzb3VyY2U9Z21haWwmYW1wO3VzdD0xNTQx
MDM2MDE2Mjg0MDAwJmFtcDt1c2c9QUZRakNOR0NDdDNGQTR6bGJsSk9pUkUyTGlPR3dZZGhrQSI+
aHR0cHM6Ly9naXRodWIuY29tL3BhbmRhcy1kZXYvPHdicj5wYW5kYXMvYmxvYi9tYXN0ZXIvcGFu
ZGFzL188d2JyPmxpYnMvc3JjL3Vqc29uL3B5dGhvbi88d2JyPkpTT050b09iai5jI0wyMDM8L2E+
IDxicj4KdmlhIGNodW5rcy4gV29ya2luZyBhcm91bmQgdGhlIG5ldyBBUEkgaW4gcGFuZGFzIHdv
dWxkIHJlcXVpcmUgbW9yZSA8YnI+CmVuZ2luZWVyaW5nLiBBbHNvLCBmb3IgZXhhbXBsZSwgY3l0
aG9uIGhhcyBhIG1lY2hhbmlzbSB0byB0cmFuc3BpbGUgPGJyPgpweXRob24gY29kZSBpbnRvIEMs
IG1hcHBpbmcgc2xvdyBweXRob24gYXR0cmlidXRlIGxvb2t1cCB0byBmYXN0IEMgPGJyPgpzdHJ1
Y3QgZmllbGQgYWNjZXNzIDxicj4KPGEgaHJlZj0iaHR0cHM6Ly9jeXRob24ucmVhZHRoZWRvY3Mu
aW8vZW4vbGF0ZXN0L3NyYy91c2VyZ3VpZGUvZXh0ZW5zaW9uX3R5cGVzLmh0bWwjZXh0ZXJuYWwt
ZXh0ZW5zaW9uLXR5cGVzIiByZWw9Im5vcmVmZXJyZXIiIHRhcmdldD0iX2JsYW5rIiBkYXRhLXNh
ZmVyZWRpcmVjdHVybD0iaHR0cHM6Ly93d3cuZ29vZ2xlLmNvbS91cmw/cT1odHRwczovL2N5dGhv
bi5yZWFkdGhlZG9jcy5pby9lbi9sYXRlc3Qvc3JjL3VzZXJndWlkZS9leHRlbnNpb25fdHlwZXMu
aHRtbCUyM2V4dGVybmFsLWV4dGVuc2lvbi10eXBlcyZhbXA7c291cmNlPWdtYWlsJmFtcDt1c3Q9
MTU0MTAzNjAxNjI4NDAwMCZhbXA7dXNnPUFGUWpDTkdPQkxYZExwUzlwUnlvYmxxMlk1eTA1Y0Qx
akEiPmh0dHBzOi8vY3l0aG9uLnJlYWR0aGVkb2NzLmlvLzx3YnI+ZW4vbGF0ZXN0L3NyYy91c2Vy
Z3VpZGUvPHdicj5leHRlbnNpb25fdHlwZXMuaHRtbCNleHRlcm5hbC08d2JyPmV4dGVuc2lvbi10
eXBlczwvYT48YnI+Cjxicj4KPGJyPgpJbiBhIHBhcmFsbGVsIGJ1dCBub3QgcmVhbGx5IHJlbGF0
ZWQgdW5pdmVyc2UsIGN5dGhvbiByZWNlbnRseSB1cGdyYWRlZCA8YnI+CnRoZSBvYmplY3QgbWFw
cGluZyBzbyB0aGF0IHdlIGNhbiBxdWlldCB0aGUgYW5ub3lpbmcgInNpemUgY2hhbmdlZCIgPGJy
PgpydW50aW1lIHdhcm5pbmcgPGEgaHJlZj0iaHR0cHM6Ly9naXRodWIuY29tL251bXB5L251bXB5
L2lzc3Vlcy8xMTc4OCIgcmVsPSJub3JlZmVycmVyIiB0YXJnZXQ9Il9ibGFuayIgZGF0YS1zYWZl
cmVkaXJlY3R1cmw9Imh0dHBzOi8vd3d3Lmdvb2dsZS5jb20vdXJsP3E9aHR0cHM6Ly9naXRodWIu
Y29tL251bXB5L251bXB5L2lzc3Vlcy8xMTc4OCZhbXA7c291cmNlPWdtYWlsJmFtcDt1c3Q9MTU0
MTAzNjAxNjI4NDAwMCZhbXA7dXNnPUFGUWpDTkhBWDFZd2lOR2xDZU9GcHhUZnlmTE9vQzlXMGci
Pmh0dHBzOi8vZ2l0aHViLmNvbS9udW1weS88d2JyPm51bXB5L2lzc3Vlcy8xMTc4ODwvYT4gd2l0
aG91dCA8YnI+CnJlcXVpcmluZyB3YXJuaW5nIGZpbHRlcnMsIGJ1dCB0aGF0IHJlcXVpcmVzIHVw
ZGF0aW5nIHRoZSBudW1weS5weGQgZmlsZSA8YnI+CnByb3ZpZGVkIHdpdGggY3l0aG9uLCBhbmQg
aXQgd2FzIHByb3Bvc2VkIHRoYXQgTnVtUHkgYWN0dWFsbHkgdmVuZG9yIGl0cyA8YnI+Cm93biBm
aWxlIHJhdGhlciB0aGFuIGRlcGVuZGluZyBvbiB0aGUgY3l0aG9uIG9uZSA8YnI+Cig8YSBocmVm
PSJodHRwczovL2dpdGh1Yi5jb20vbnVtcHkvbnVtcHkvaXNzdWVzLzExODAzIiByZWw9Im5vcmVm
ZXJyZXIiIHRhcmdldD0iX2JsYW5rIiBkYXRhLXNhZmVyZWRpcmVjdHVybD0iaHR0cHM6Ly93d3cu
Z29vZ2xlLmNvbS91cmw/cT1odHRwczovL2dpdGh1Yi5jb20vbnVtcHkvbnVtcHkvaXNzdWVzLzEx
ODAzJmFtcDtzb3VyY2U9Z21haWwmYW1wO3VzdD0xNTQxMDM2MDE2Mjg0MDAwJmFtcDt1c2c9QUZR
akNORW9nYkR5Njk5R0pXcHMyYkxnTzVmbEtNRF9hdyI+aHR0cHM6Ly9naXRodWIuY29tL251bXB5
Lzx3YnI+bnVtcHkvaXNzdWVzLzExODAzPC9hPikuPGJyPgo8YnI+Cjxicj4KVGhlIHByb2JsZW08
YnI+Cjxicj4KPGJyPgpXZSBoYXZlIG5vdyBtYWRlIGZ1cnRoZXIgY2hhbmdlcyB0byBvdXIgQVBJ
LiBJbiBOdW1QeSAxLjE0IHdlIGNoYW5nZWQgPGJyPgpVUERBVEVJRkNPUFkgdG8gV1JJVEVCQUNL
SUZDT1BZLCBhbmQgaW4gMS4xNiB3ZSB3b3VsZCBsaWtlIHRvIGRlcHJlY2F0ZSA8YnI+ClB5QXJy
YXlfU2V0TnVtZXJpY09wcyBhbmQgUHlBcnJheV9HZXROdW1lcmljT3BzLiBUaGUgc3RyYW5nZSB3
YXJuaW5nIDxicj4Kd2hlbiBOUFlfTk9fREVQUklDQVRFRF9BUEkgaXMgYW5ub3lpbmcuIFRoZSBu
ZXcgQVBJIGNhbm5vdCBiZSBzdXBwb3J0ZWQgPGJyPgpieSBjeXRob24gd2l0aG91dCBzb21lIGRl
ZXAgc3VyZ2VyeSA8YnI+Cig8YSBocmVmPSJodHRwczovL2dpdGh1Yi5jb20vY3l0aG9uL2N5dGhv
bi9wdWxsLzI2NDAiIHJlbD0ibm9yZWZlcnJlciIgdGFyZ2V0PSJfYmxhbmsiIGRhdGEtc2FmZXJl
ZGlyZWN0dXJsPSJodHRwczovL3d3dy5nb29nbGUuY29tL3VybD9xPWh0dHBzOi8vZ2l0aHViLmNv
bS9jeXRob24vY3l0aG9uL3B1bGwvMjY0MCZhbXA7c291cmNlPWdtYWlsJmFtcDt1c3Q9MTU0MTAz
NjAxNjI4NDAwMCZhbXA7dXNnPUFGUWpDTkVlX3ZjRzVyOWR0U2RMNXdRMFVhWmNyOVBKV0EiPmh0
dHBzOi8vZ2l0aHViLmNvbS9jeXRob24vPHdicj5jeXRob24vcHVsbC8yNjQwPC9hPikuIFdoZW4g
SSB0cmllZCBkb2dmb29kaW5nIGFuIDxicj4KdXBkYXRlZCBudW1weS5weGQgZm9yIHRoZSBvbmx5
IGN5dGhvbiBjb2RlIGluIE51bVB5LCBtdHJhbmQucHh5LCBJIGNhbWUgPGJyPgphY3Jvc3Mgc29t
ZSBvZiB0aGVzZSBpc3N1ZXMgKDxhIGhyZWY9Imh0dHBzOi8vZ2l0aHViLmNvbS9udW1weS9udW1w
eS9wdWxsLzEyMjg0IiByZWw9Im5vcmVmZXJyZXIiIHRhcmdldD0iX2JsYW5rIiBkYXRhLXNhZmVy
ZWRpcmVjdHVybD0iaHR0cHM6Ly93d3cuZ29vZ2xlLmNvbS91cmw/cT1odHRwczovL2dpdGh1Yi5j
b20vbnVtcHkvbnVtcHkvcHVsbC8xMjI4NCZhbXA7c291cmNlPWdtYWlsJmFtcDt1c3Q9MTU0MTAz
NjAxNjI4NDAwMCZhbXA7dXNnPUFGUWpDTkVrV2NuSHFZQTQ5M0Y4eG9WbGlWd3ROUEtIcXciPmh0
dHBzOi8vZ2l0aHViLmNvbS9udW1weS88d2JyPm51bXB5L3B1bGwvMTIyODQ8L2E+KS4gPGJyPgpG
b3JjaW5nIHRoZSBuZXcgQVBJIHdpbGwgcmVxdWlyZSBkb3duc3RyZWFtIHVzZXJzIHRvIHJlZmFj
dG9yIGNvZGUgb3IgPGJyPgpyZS1lbmdpbmVlciBjb25zdHJ1Y3RzLCBhcyBpbiB0aGUgcGFuZGFz
IGV4YW1wbGUgYWJvdmUuPGJyPgo8YnI+Cjxicj4KVGhlIHF1ZXN0aW9uPGJyPgo8YnI+Cjxicj4K
SXMgdGhlIGF0dHJpYnV0ZS1oaWRpbmcgZWZmb3J0IHdvcnRoIGl0PyBTaG91bGQgd2UgZ2l2ZSB1
cCwgcmV2ZXJ0IHRoZSA8YnI+ClB5QXJyYXlPYmplY3QvUHlBcnJheU9iamVjdF88d2JyPmZpZWxk
cyBkaXZpc2lvbiBhbmQgYWxsb3cgZGlyZWN0IGFjY2VzcyBmcm9tIDxicj4KQyB0byB0aGUgbnVt
cHkgaW50ZXJuYWxzPyBJcyB0aGVyZSBhbm90aGVyIHBhdGggZm9yd2FyZCB0aGF0IGlzIGxlc3Mg
PGJyPgpwYWluZnVsPzxicj4KPGJyPgo8YnI+Ck1hdHRpPGJyPgo8YnI+Cl9fX19fX19fX19fX19f
X19fX19fX19fX19fX19fXzx3YnI+X19fX19fX19fX19fX19fX188YnI+Ck51bVB5LURpc2N1c3Np
b24gbWFpbGluZyBsaXN0PGJyPgo8YSBocmVmPSJtYWlsdG86TnVtUHktRGlzY3Vzc2lvbkBweXRo
b24ub3JnIiB0YXJnZXQ9Il9ibGFuayI+TnVtUHktRGlzY3Vzc2lvbkBweXRob24ub3JnPC9hPjxi
cj4KPGEgaHJlZj0iaHR0cHM6Ly9tYWlsLnB5dGhvbi5vcmcvbWFpbG1hbi9saXN0aW5mby9udW1w
eS1kaXNjdXNzaW9uIiByZWw9Im5vcmVmZXJyZXIiIHRhcmdldD0iX2JsYW5rIiBkYXRhLXNhZmVy
ZWRpcmVjdHVybD0iaHR0cHM6Ly93d3cuZ29vZ2xlLmNvbS91cmw/cT1odHRwczovL21haWwucHl0
aG9uLm9yZy9tYWlsbWFuL2xpc3RpbmZvL251bXB5LWRpc2N1c3Npb24mYW1wO3NvdXJjZT1nbWFp
bCZhbXA7dXN0PTE1NDEwMzYwMTYyODQwMDAmYW1wO3VzZz1BRlFqQ05FOGpZd1JwcnNpZnVydWNt
cVpCSkh6OEplQkR3Ij5odHRwczovL21haWwucHl0aG9uLm9yZy88d2JyPm1haWxtYW4vbGlzdGlu
Zm8vbnVtcHktPHdicj5kaXNjdXNzaW9uPC9hPjxicj4KPC9ibG9ja3F1b3RlPjwvZGl2Pg==" style="height:0;width:0;max-height:0;max-width:0;overflow:hidden;font-size:0em;padding:0;margin:0">​</div></div></div>