Hope the last one :)
----------------------------
BlueZ D-Bus Health API description
**********************************
Santiago Carot-Nemesio <[email protected]>
Jos? Antonio Santos-Cadenas <[email protected]>
Elvis Pf?tzenreuter <[email protected]>
Health Device Profile hierarchy
===============================
Service org.bluez
Interface org.bluez.HealthAdapter
Object path [variable prefix]/{hci0,hci1,...}
Methods object CreateInstance(object path, dict config)
Returns the path for the new HealthInstance object.
The path parameter is the path of the remote object
with the callbacks to notify events (see
org.bluez.HealthAgent at the end of this document)
This petition starts an mcap instance and also register
in the SDP if is needed
Dict is defined as bellow:
{ "data_spec" : The data_spec is the data exchange
specification (see section 5.2.10 of
the specification document)
possible values:
0x00 = reserved,
0x01 [IEEE 11073-20601],
0x02..0xff reserved,
(optional)
"end_points" : [{ (optional)
"mdepid" : uint8, (optional)
"role" : ("source" or "sink"), (mandatory)
"specs" :[{ (mandatory)
"data_type" : uint16, (mandatory)
"description" : string, (optional)
}]
}]
}
if "data_spec" is not set, no SDP record will be
registered, so all the other data in the dictionary
will be ignored
Instance will be closed by the call or implicitly when
the programs leaves the bus.
Possible errors: org.bluez.Error.InvalidArguments
void CloseInstance(object path)
Closes the HDP instance identified by the object path.
Also instance will be closed if the process that started
leaves the bus. If there is a SDP record associated to
this instance it will be removed.
Possible errors: org.bluez.Error.InvalidArguments
org.bluez.Error.NotFound
--------------------------------------------------------------------------------
Service org.bluez
Interface org.bluez.HealthDevice
Object path [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX
Methods array GetHealthInstances()
Gets the information of the remote instances present
in this device and published on its SDP record. The
returned data follows this format.
[{"id": "an instance identification as string",
"data_spec" : data spec,
"end_points":
["mdepid": uint8,
"role" : "source" or "sink" ,
"specs" : [{
"dtype" : uint16,
"description" : string, (optional)
}]
]
}];
--------------------------------------------------------------------------------
Service org.bluez
Interface org.bluez.HealthInstance
Object path [variable prefix]/{hci0,hci1,...}/{hdp0,hdp1,...}
object Connect(remote_instance_id)
Connects with the remote instance and returns its object
path. To get the session ids on a remote device, you
must run the GetHealthInstances in the HealthDevice
object.
Possible errors: org.bluez.Error.InvalidArguments
org.bluez.Error.HealthError
void Disconnect(object device, boolean cache)
Disconnect from the remote device. If chahe is false,
state will also be deleted. Otherwise, the state will be
kept for allowing future reconnections until the adapter
is removed.
Possible errors: org.bluez.Error.InvalidArguments
org.bluez.Error.NotFound
org.bluez.Error.HealthError
--------------------------------------------------------------------------------
Service org.bluez
Interface org.bluez.HealthLink
Object path [variable prefix]/{hci0,hci1,...}/{hdp0,hdp1,...}/rem_inst_id
boolean Echo(array{byte})
Sends an echo petition to the remote intance. Returns
True if response matches with the buffer sent. If some
error is detected False value is returned and the
associated MCL is closed.
uint16 OpenDataChannel(byte mdepid, byte config)
Creates a new data channel with the indicated config
to the remote MCAP Data End Point (MDEP).
The configuration should indicate the channel quality of
service. In the current version of HDP, valid values are
0x01 for reliable channels and 0x02 for streaming data
channel.
Returns the data channel id.
Possible errors: org.bluez.Error.InvalidArguments
org.bluez.Error.HealthError
array GetDataChannelFileDescriptor(uint16 mdlid)
Gets a file descriptor where data can be read or
written for receive or sent by the data channel.
Returns an array of file descriptors one for write
and other for read.
Possible errors: org.bluez.Error.InvalidArguments
org.bluez.Error.NotFound
org.bluez.Error.HealthError
void DeleteDataChannel(uint16 mdlid)
Deletes a data channel so it will not be available for
use.
Possible errors: org.bluez.Error.InvalidArguments
org.bluez.Error.NotFound
org.bluez.Error.HealthError
void DeleteAllDataChannels()
Deletes all data channels so it will not be available
for use. Typically this function is called when the
connection with the remote device will be closed
permanently
Possible errors: org.bluez.Error.HealthError
dict GetDataChannelStatus()
Return a dictionary with all the data channels that
can be used to send data right now. The dictionary
is formed like follows:
{
"reliable": [mdlid_r1, mdlid_r2, ...],
"streaming" : [mdlid_s1, mdlid_s2, ...]
}
The fist reliable data channel will always be the first
data channel in reliable array.
HealthAgent hierarchy
==================
(this object is implemented by the HDP client an receives notifications)
Service unique name
Interface org.bluez.HealthAgent
Object path freely definable
void LinkConnected(object path)
This method is called whenever a new connection
has been established over the control channel of the
current HDP instance. The object path paremeter contains
the object path of the created HealthLink.
void LinkDisconnected(object path)
This method is called when a remote device is
disconnected definitively. Any future reconnections
will fail. Also all data channels associated to this
device will be closed.
void CreatedDataChannel(object path, uint16 mdlid, byte conf)
This method is called when a new data channel is created
The path contains the object path of the HealthLink
where the new connection is created, the mdlid is the
data channel identificator and conf is the que quality
of service of the data channel (0x01 reliable, 0x02
streaming).
void DeletedDataChannel(object path, uint16 mdlid)
This method is called when a data channel is closed.
After this call the data channel will not be valid and
can be reused for future created data channels.
Hi Gustavo,
El Monday 17 May 2010 23:38:38 Gustavo F. Padovan escribi?:
> Hi,
>
> * Jo?o Paulo Rechi Vita <[email protected]> [2010-05-17 18:17:58 -0300]:
>
> <snip>
>
> > On Mon, May 17, 2010 at 11:54, Jos? Antonio Santos Cadenas
> >
> > <[email protected]> wrote:
> > > array GetDataChannelFileDescriptor(uint16 mdlid)
> >
> > Wouldn't be better to pass the fd through the LinkConnected call on
> > Agent? Doing it here allows any process to get the fds.
>
> I was thinking about the MCAP in kernel implementation, my conclusion is
> that we can solve one of the biggest problem of HDP API if we do it in
> kernel: the transparency of MCAP reconnection. HDP will open an MCAP
> socket and pass it to the user(IEEE app). Then if we need a
> reconnection, MCAP will transparently reconnect changing the L2CAP
> channel to transmit the data without the need to change the socket
> opened with the userspace.
This that you proposed is something that we thought when we started with
MCAP/HDP. We finally decided to put MCAP outside the kernel because of the
following reasons:
- The first and the most important is that everything that can be done in
user space should be done in user space. We talked about this issue in the
list some time ago and Marcel suggested us that if MCAP doesn't have
interaction with other kernel subsystems, it should be implemented outside the
kernel. You can read these mails here [1]. Basing on our experience with MCAP
that's true, MCAP does not interact with any kernel subsystem.
- An other reason is that reconnections *should not* be transparent at
MCAP level. Any profile using MCAP should be concerned about the data channel
disconnection and reconnection. In the case of HDP reconnections should be
hide to the application layer.
- Finally the kernel implementation will require a very complex API
because MCAP require notifying lots of events some of the requiring a
response(i.e., incoming mdl connection that need a response from the next
level using MCAP with the configuration). Probably MCAP in the kernel space
will be so complicated to used an you will require a user space library that
make simpler the use of this API.
>
> Keep the MCAP socket open means that we are keeping the MCL state for
> further reconnection.
>
> Doing it inside the kernel removes a big amount of complexity of HDP and
> IEEE profiles, since we won't need any pipe or change of fd. That could
> be a killer feature to make it in the kernel.
>
> Any comments? Is this reasonable?
In our opinion reconnections are not a reason to implement MCAP in kernel
space because reconections should not be transparent at this level.
>
> <snip>
[1] http://www.spinics.net/lists/linux-bluetooth/msg03001.html
El Monday 17 May 2010 23:17:58 Jo?o Paulo Rechi Vita escribi?:
> On Mon, May 17, 2010 at 11:54, Jos? Antonio Santos Cadenas
>
> <[email protected]> wrote:
> > Hope the last one :)
> >
> > ----------------------------
> >
> > BlueZ D-Bus Health API description
> > **********************************
> >
> > Santiago Carot-Nemesio <[email protected]>
> > Jos? Antonio Santos-Cadenas <[email protected]>
> > Elvis Pf?tzenreuter <[email protected]>
> >
> > Health Device Profile hierarchy
> > ===============================
> >
> > Service org.bluez
> > Interface org.bluez.HealthAdapter
> > Object path [variable prefix]/{hci0,hci1,...}
> >
> > Methods object CreateInstance(object path, dict config)
> >
> > Returns the path for the new HealthInstance
> > object. The path parameter is the path of the remote object with the
> > callbacks to notify events (see
> > org.bluez.HealthAgent at the end of this document)
> > This petition starts an mcap instance and also
> > register in the SDP if is needed
> > Dict is defined as bellow:
> > { "data_spec" : The data_spec is the data exchange
> > specification (see section 5.2.10
> > of the specification document) possible values:
> > 0x00 = reserved,
> > 0x01 [IEEE 11073-20601],
> > 0x02..0xff reserved,
> > (optional)
> > "end_points" : [{ (optional)
> > "mdepid" : uint8, (optional)
> > "role" : ("source" or "sink"), (mandatory)
> > "specs" :[{ (mandatory)
> > "data_type" : uint16, (mandatory)
> > "description" : string, (optional)
> > }]
> > }]
> > }
> >
> > if "data_spec" is not set, no SDP record will be
> > registered, so all the other data in the
> > dictionary will be ignored
> >
> > Instance will be closed by the call or implicitly
> > when the programs leaves the bus.
> >
> > Possible errors: org.bluez.Error.InvalidArguments
> >
> > void CloseInstance(object path)
> >
> > Closes the HDP instance identified by the object
> > path. Also instance will be closed if the process that started leaves
> > the bus. If there is a SDP record associated to this instance it will be
> > removed.
> >
> > Possible errors: org.bluez.Error.InvalidArguments
> > org.bluez.Error.NotFound
> >
> > -------------------------------------------------------------------------
> > -------
> >
> > Service org.bluez
> > Interface org.bluez.HealthDevice
> > Object path [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX
> >
> > Methods array GetHealthInstances()
> >
> > Gets the information of the remote instances
> > present in this device and published on its SDP record. The returned
> > data follows this format.
> >
> > [{"id": "an instance identification as string",
> > "data_spec" : data spec,
> > "end_points":
> > ["mdepid": uint8,
> > "role" : "source" or "sink" ,
> > "specs" : [{
> > "dtype" : uint16,
> > "description" : string, (optional)
> > }]
> > ]
> > }];
> >
> > -------------------------------------------------------------------------
> > -------
> >
> > Service org.bluez
> > Interface org.bluez.HealthInstance
> > Object path [variable prefix]/{hci0,hci1,...}/{hdp0,hdp1,...}
> >
> > object Connect(remote_instance_id)
> >
> > Connects with the remote instance and returns its
> > object path. To get the session ids on a remote device, you must run the
> > GetHealthInstances in the HealthDevice object.
> >
> > Possible errors: org.bluez.Error.InvalidArguments
> > org.bluez.Error.HealthError
> >
> > void Disconnect(object device, boolean cache)
> >
> > Disconnect from the remote device. If chahe is
> > false, state will also be deleted. Otherwise, the state will be kept for
> > allowing future reconnections until the adapter is removed.
> >
> > Possible errors: org.bluez.Error.InvalidArguments
> > org.bluez.Error.NotFound
> > org.bluez.Error.HealthError
> >
> > -------------------------------------------------------------------------
> > -------
> >
> > Service org.bluez
> > Interface org.bluez.HealthLink
> > Object path [variable
> > prefix]/{hci0,hci1,...}/{hdp0,hdp1,...}/rem_inst_id
> >
> > boolean Echo(array{byte})
> >
> > Sends an echo petition to the remote intance.
> > Returns True if response matches with the buffer sent. If some error is
> > detected False value is returned and the associated MCL is closed.
> >
> > uint16 OpenDataChannel(byte mdepid, byte config)
> >
> > Creates a new data channel with the indicated
> > config to the remote MCAP Data End Point (MDEP). The configuration
> > should indicate the channel quality of service. In the current version
> > of HDP, valid values are 0x01 for reliable channels and 0x02 for
> > streaming data channel.
> >
> > Returns the data channel id.
> >
> > Possible errors: org.bluez.Error.InvalidArguments
> > org.bluez.Error.HealthError
> >
> > array GetDataChannelFileDescriptor(uint16 mdlid)
>
> Wouldn't be better to pass the fd through the LinkConnected call on
> Agent? Doing it here allows any process to get the fds.
Originally we thought about doing like that. But Elvis suggested to centralize
all the ways that you get the file descriptor in just one place and we thought
that it was a great idea. In addition, think that you will need this call
because the LinkConnected call is only called when the connection is initiated
by the remote HDP instance but the connections initiated by your side will not
be notified. About the "security" issue you mentioned, we are planing to
control who can call this methods only the process that initiated the HDP
instance will receive a response to this methods, any other process will
receive an error.
>
> > Gets a file descriptor where data can be read or
> > written for receive or sent by the data channel.
> > Returns an array of file descriptors one for write
> > and other for read.
> >
> > Possible errors: org.bluez.Error.InvalidArguments
> > org.bluez.Error.NotFound
> > org.bluez.Error.HealthError
> >
> > void DeleteDataChannel(uint16 mdlid)
> >
> > Deletes a data channel so it will not be available
> > for use.
> >
> > Possible errors: org.bluez.Error.InvalidArguments
> > org.bluez.Error.NotFound
> > org.bluez.Error.HealthError
> >
> > void DeleteAllDataChannels()
> >
> > Deletes all data channels so it will not be
> > available for use. Typically this function is called when the connection
> > with the remote device will be closed permanently
> >
> > Possible errors: org.bluez.Error.HealthError
> >
> > dict GetDataChannelStatus()
> >
> > Return a dictionary with all the data channels
> > that can be used to send data right now. The dictionary is formed like
> > follows:
> > {
> > "reliable": [mdlid_r1, mdlid_r2, ...],
> > "streaming" : [mdlid_s1, mdlid_s2, ...]
> > }
> >
> > The fist reliable data channel will always be the
> > first data channel in reliable array.
> >
> > HealthAgent hierarchy
> > ==================
> >
> > (this object is implemented by the HDP client an receives notifications)
> >
> > Service unique name
> > Interface org.bluez.HealthAgent
> > Object path freely definable
> >
> > void LinkConnected(object path)
> >
> > This method is called whenever a new connection
> > has been established over the control channel of
> > the current HDP instance. The object path paremeter contains the object
> > path of the created HealthLink.
> >
> > void LinkDisconnected(object path)
> >
> > This method is called when a remote device is
> > disconnected definitively. Any future
> > reconnections will fail. Also all data channels associated to this
> > device will be closed.
> >
> > void CreatedDataChannel(object path, uint16 mdlid, byte
> > conf)
> >
> > This method is called when a new data channel is
> > created The path contains the object path of the HealthLink where the
> > new connection is created, the mdlid is the data channel identificator
> > and conf is the que quality of service of the data channel (0x01
> > reliable, 0x02 streaming).
> >
> > void DeletedDataChannel(object path, uint16 mdlid)
> >
> > This method is called when a data channel is
> > closed. After this call the data channel will not be valid and can be
> > reused for future created data channels. --
> > To unsubscribe from this list: send the line "unsubscribe
> > linux-bluetooth" in the body of a message to [email protected]
> > More majordomo info at http://vger.kernel.org/majordomo-info.html
Hi,
* Jo?o Paulo Rechi Vita <[email protected]> [2010-05-17 18:17:58 -0300]:
<snip>
> On Mon, May 17, 2010 at 11:54, Jos? Antonio Santos Cadenas
> <[email protected]> wrote:
> >
> > ? ? ? ? ? ? ? ?array GetDataChannelFileDescriptor(uint16 mdlid)
> >
>
> Wouldn't be better to pass the fd through the LinkConnected call on
> Agent? Doing it here allows any process to get the fds.
I was thinking about the MCAP in kernel implementation, my conclusion is
that we can solve one of the biggest problem of HDP API if we do it in
kernel: the transparency of MCAP reconnection. HDP will open an MCAP
socket and pass it to the user(IEEE app). Then if we need a
reconnection, MCAP will transparently reconnect changing the L2CAP
channel to transmit the data without the need to change the socket
opened with the userspace.
Keep the MCAP socket open means that we are keeping the MCL state for
further reconnection.
Doing it inside the kernel removes a big amount of complexity of HDP and
IEEE profiles, since we won't need any pipe or change of fd. That could
be a killer feature to make it in the kernel.
Any comments? Is this reasonable?
<snip>
--
Gustavo F. Padovan
http://padovan.org
T24gTW9uLCBNYXkgMTcsIDIwMTAgYXQgMTE6NTQsIEpvc8OpIEFudG9uaW8gU2FudG9zIENhZGVu
YXMKPGpjYWRlbkBsaWJyZXNvZnQuZXM+IHdyb3RlOgo+IEhvcGUgdGhlIGxhc3Qgb25lIDopCj4K
PiAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCj4KPiBCbHVlWiBELUJ1cyBIZWFsdGggQVBJ
IGRlc2NyaXB0aW9uCj4gKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKgo+Cj4gwqAg
wqAgwqAgwqBTYW50aWFnbyBDYXJvdC1OZW1lc2lvIDxzYW5jYW5lQGdtYWlsLmNvbT4KPiDCoCDC
oCDCoCDCoEpvc8OpIEFudG9uaW8gU2FudG9zLUNhZGVuYXMgPHNhbnRvc2NhZGVuYXNAZ21haWwu
Y29tPgo+IMKgIMKgIMKgIMKgRWx2aXMgUGbDvHR6ZW5yZXV0ZXIgPGVweEBzaWdub3ZlLmNvbT4K
Pgo+IEhlYWx0aCBEZXZpY2UgUHJvZmlsZSBoaWVyYXJjaHkKPiA9PT09PT09PT09PT09PT09PT09
PT09PT09PT09PT09Cj4KPiBTZXJ2aWNlIMKgIMKgIMKgIMKgIG9yZy5ibHVlego+IEludGVyZmFj
ZSDCoCDCoCDCoCBvcmcuYmx1ZXouSGVhbHRoQWRhcHRlcgo+IE9iamVjdCBwYXRoIMKgIMKgIFt2
YXJpYWJsZSBwcmVmaXhdL3toY2kwLGhjaTEsLi4ufQo+Cj4gTWV0aG9kcyDCoCDCoCDCoCDCoCBv
YmplY3QgQ3JlYXRlSW5zdGFuY2Uob2JqZWN0IHBhdGgsIGRpY3QgY29uZmlnKQo+Cj4gwqAgwqAg
wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqBSZXR1cm5zIHRoZSBwYXRoIGZvciB0aGUgbmV3
IEhlYWx0aEluc3RhbmNlIG9iamVjdC4KPiDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC
oCDCoFRoZSBwYXRoIHBhcmFtZXRlciBpcyB0aGUgcGF0aCBvZiB0aGUgcmVtb3RlIG9iamVjdAo+
IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgd2l0aCB0aGUgY2FsbGJhY2tzIHRv
IG5vdGlmeSBldmVudHMgKHNlZQo+IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg
b3JnLmJsdWV6LkhlYWx0aEFnZW50IGF0IHRoZSBlbmQgb2YgdGhpcyBkb2N1bWVudCkKPiDCoCDC
oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoFRoaXMgcGV0aXRpb24gc3RhcnRzIGFuIG1j
YXAgaW5zdGFuY2UgYW5kIGFsc28gcmVnaXN0ZXIKPiDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC
oCDCoCDCoCDCoGluIHRoZSBTRFAgaWYgaXMgbmVlZGVkCj4gwqAgwqAgwqAgwqAgwqAgwqAgwqAg
wqAgwqAgwqAgwqAgwqBEaWN0IGlzIGRlZmluZWQgYXMgYmVsbG93Ogo+IMKgIMKgIMKgIMKgIMKg
IMKgIMKgIMKgIMKgIMKgIMKgIMKgeyAiZGF0YV9zcGVjIiA6IFRoZSBkYXRhX3NwZWMgaXMgdGhl
IGRhdGEgZXhjaGFuZ2UKPiDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC
oCDCoCDCoCDCoCDCoCDCoCDCoHNwZWNpZmljYXRpb24gKHNlZSBzZWN0aW9uIDUuMi4xMCBvZgo+
IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg
IMKgdGhlIHNwZWNpZmljYXRpb24gZG9jdW1lbnQpCj4gwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg
wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqBwb3NzaWJsZSB2YWx1ZXM6Cj4gwqAg
wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg
wqAgwqAgwqAgwqAweDAwID0gcmVzZXJ2ZWQsCj4gwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg
wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAweDAxIFtJRUVFIDEx
MDczLTIwNjAxXSwKPiDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC
oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoDB4MDIuLjB4ZmYgcmVzZXJ2ZWQsCj4gwqAgwqAg
wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAob3B0
aW9uYWwpCj4gwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAiZW5kX3BvaW50
cyIgOiBbeyAob3B0aW9uYWwpCj4gwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg
wqAgwqAgwqAgwqAibWRlcGlkIiA6IHVpbnQ4LCAob3B0aW9uYWwpCj4gwqAgwqAgwqAgwqAgwqAg
wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAicm9sZSIgOiAoInNvdXJjZSIgb3IgInNp
bmsiKSwgKG1hbmRhdG9yeSkKPiDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC
oCDCoCDCoCDCoCJzcGVjcyIgOlt7IChtYW5kYXRvcnkpCj4gwqAgwqAgwqAgwqAgwqAgwqAgwqAg
wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAiZGF0YV90eXBlIiA6IHVpbnQx
NiwgKG1hbmRhdG9yeSkKPiDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC
oCDCoCDCoCDCoCDCoCDCoCDCoCJkZXNjcmlwdGlvbiIgOiBzdHJpbmcsIChvcHRpb25hbCkKPiDC
oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoH1dCj4gwqAgwqAg
wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqB9XQo+IMKgIMKgIMKgIMKgIMKgIMKgIMKg
IMKgIMKgIMKgIMKgIMKgfQo+Cj4gwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqBp
ZiAiZGF0YV9zcGVjIiBpcyBub3Qgc2V0LCBubyBTRFAgcmVjb3JkIHdpbGwgYmUKPiDCoCDCoCDC
oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoHJlZ2lzdGVyZWQsIHNvIGFsbCB0aGUgb3RoZXIg
ZGF0YSBpbiB0aGUgZGljdGlvbmFyeQo+IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg
IMKgd2lsbCBiZSBpZ25vcmVkCj4KPiDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC
oEluc3RhbmNlIHdpbGwgYmUgY2xvc2VkIGJ5IHRoZSBjYWxsIG9yIGltcGxpY2l0bHkgd2hlbgo+
IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgdGhlIHByb2dyYW1zIGxlYXZlcyB0
aGUgYnVzLgo+Cj4gwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqBQb3NzaWJsZSBl
cnJvcnM6IG9yZy5ibHVlei5FcnJvci5JbnZhbGlkQXJndW1lbnRzCj4KPiDCoCDCoCDCoCDCoCDC
oCDCoCDCoCDCoHZvaWQgQ2xvc2VJbnN0YW5jZShvYmplY3QgcGF0aCkKPgo+IMKgIMKgIMKgIMKg
IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgQ2xvc2VzIHRoZSBIRFAgaW5zdGFuY2UgaWRlbnRpZmll
ZCBieSB0aGUgb2JqZWN0IHBhdGguCj4gwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg
wqBBbHNvIGluc3RhbmNlIHdpbGwgYmUgY2xvc2VkIGlmIHRoZSBwcm9jZXNzIHRoYXQgc3RhcnRl
ZAo+IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgbGVhdmVzIHRoZSBidXMuIElm
IHRoZXJlIGlzIGEgU0RQIHJlY29yZCBhc3NvY2lhdGVkIHRvCj4gwqAgwqAgwqAgwqAgwqAgwqAg
wqAgwqAgwqAgwqAgwqAgwqB0aGlzIGluc3RhbmNlIGl0IHdpbGwgYmUgcmVtb3ZlZC4KPgo+IMKg
IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgUG9zc2libGUgZXJyb3JzOiBvcmcuYmx1
ZXouRXJyb3IuSW52YWxpZEFyZ3VtZW50cwo+IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg
IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgb3JnLmJsdWV6LkVycm9yLk5vdEZvdW5kCj4K
PiAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t
LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQo+Cj4gU2VydmljZSDCoCDCoCDCoCDCoCBvcmcuYmx1
ZXoKPiBJbnRlcmZhY2UgwqAgwqAgwqAgb3JnLmJsdWV6LkhlYWx0aERldmljZQo+IE9iamVjdCBw
YXRoIMKgIMKgIFt2YXJpYWJsZSBwcmVmaXhdL3toY2kwLGhjaTEsLi4ufS9kZXZfWFhfWFhfWFhf
WFhfWFhfWFgKPgo+IE1ldGhvZHMgwqAgwqAgwqAgwqAgYXJyYXkgR2V0SGVhbHRoSW5zdGFuY2Vz
KCkKPgo+IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgR2V0cyB0aGUgaW5mb3Jt
YXRpb24gb2YgdGhlIHJlbW90ZSBpbnN0YW5jZXMgcHJlc2VudAo+IMKgIMKgIMKgIMKgIMKgIMKg
IMKgIMKgIMKgIMKgIMKgIMKgaW4gdGhpcyBkZXZpY2UgYW5kIHB1Ymxpc2hlZCBvbiBpdHMgU0RQ
IHJlY29yZC4gVGhlCj4gwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqByZXR1cm5l
ZCBkYXRhIGZvbGxvd3MgdGhpcyBmb3JtYXQuCj4KPiDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC
oCDCoCDCoCDCoFt7ImlkIjogImFuIGluc3RhbmNlIGlkZW50aWZpY2F0aW9uIGFzIHN0cmluZyIs
Cj4gwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgImRhdGFfc3BlYyIgOiBkYXRh
IHNwZWMsCj4gwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgImVuZF9wb2ludHMi
Ogo+IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgWyJtZGVw
aWQiOiB1aW50OCwKPiDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC
oCDCoCAicm9sZSIgwqA6ICJzb3VyY2UiIG9yICJzaW5rIiAsCj4gwqAgwqAgwqAgwqAgwqAgwqAg
wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgInNwZWNzIiA6IFt7Cj4gwqAgwqAgwqAgwqAg
wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAiZHR5cGUiIMKg
IMKgIMKgIDogdWludDE2LAo+IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg
IMKgIMKgIMKgIMKgIMKgIMKgIMKgImRlc2NyaXB0aW9uIiA6IHN0cmluZywgKG9wdGlvbmFsKQo+
IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIH1dCj4gwqAg
wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqBdCj4gwqAgwqAgwqAg
wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqB9XTsKPgo+IC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t
LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t
Cj4KPiBTZXJ2aWNlIMKgIMKgIMKgIMKgIG9yZy5ibHVlego+IEludGVyZmFjZSDCoCDCoCDCoCBv
cmcuYmx1ZXouSGVhbHRoSW5zdGFuY2UKPiBPYmplY3QgcGF0aCDCoCDCoCBbdmFyaWFibGUgcHJl
Zml4XS97aGNpMCxoY2kxLC4uLn0ve2hkcDAsaGRwMSwuLi59Cj4KPiDCoCDCoCDCoCDCoCDCoCDC
oCDCoCDCoG9iamVjdCBDb25uZWN0KHJlbW90ZV9pbnN0YW5jZV9pZCkKPgo+IMKgIMKgIMKgIMKg
IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgQ29ubmVjdHMgd2l0aCB0aGUgcmVtb3RlIGluc3RhbmNl
IGFuZCByZXR1cm5zIGl0cyBvYmplY3QKPiDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC
oCDCoHBhdGguIFRvIGdldCB0aGUgc2Vzc2lvbiBpZHMgb24gYSByZW1vdGUgZGV2aWNlLCB5b3UK
PiDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoG11c3QgcnVuIHRoZSBHZXRIZWFs
dGhJbnN0YW5jZXMgaW4gdGhlIEhlYWx0aERldmljZQo+IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg
IMKgIMKgIMKgIMKgb2JqZWN0Lgo+Cj4gwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg
wqBQb3NzaWJsZSBlcnJvcnM6IG9yZy5ibHVlei5FcnJvci5JbnZhbGlkQXJndW1lbnRzCj4gwqAg
wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqBv
cmcuYmx1ZXouRXJyb3IuSGVhbHRoRXJyb3IKPgo+IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgdm9p
ZCBEaXNjb25uZWN0KG9iamVjdCBkZXZpY2UsIGJvb2xlYW4gY2FjaGUpCj4KPiDCoCDCoCDCoCDC
oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoERpc2Nvbm5lY3QgZnJvbSB0aGUgcmVtb3RlIGRldmlj
ZS4gSWYgY2hhaGUgaXMgZmFsc2UsCj4gwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg
wqBzdGF0ZSB3aWxsIGFsc28gYmUgZGVsZXRlZC4gT3RoZXJ3aXNlLCB0aGUgc3RhdGUgd2lsbCBi
ZQo+IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKga2VwdCBmb3IgYWxsb3dpbmcg
ZnV0dXJlIHJlY29ubmVjdGlvbnMgdW50aWwgdGhlIGFkYXB0ZXIKPiDCoCDCoCDCoCDCoCDCoCDC
oCDCoCDCoCDCoCDCoCDCoCDCoGlzIHJlbW92ZWQuCj4KPiDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC
oCDCoCDCoCDCoCDCoFBvc3NpYmxlIGVycm9yczogb3JnLmJsdWV6LkVycm9yLkludmFsaWRBcmd1
bWVudHMKPiDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC
oCDCoCDCoCDCoG9yZy5ibHVlei5FcnJvci5Ob3RGb3VuZAo+IMKgIMKgIMKgIMKgIMKgIMKgIMKg
IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgb3JnLmJsdWV6LkVycm9yLkhl
YWx0aEVycm9yCj4KPiAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t
LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQo+Cj4gU2VydmljZSDCoCDCoCDC
oCDCoCBvcmcuYmx1ZXoKPiBJbnRlcmZhY2UgwqAgwqAgwqAgb3JnLmJsdWV6LkhlYWx0aExpbmsK
PiBPYmplY3QgcGF0aCDCoCDCoCBbdmFyaWFibGUgcHJlZml4XS97aGNpMCxoY2kxLC4uLn0ve2hk
cDAsaGRwMSwuLi59L3JlbV9pbnN0X2lkCj4KPiDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoGJvb2xl
YW4gRWNobyhhcnJheXtieXRlfSkKPgo+IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg
IMKgU2VuZHMgYW4gZWNobyBwZXRpdGlvbiB0byB0aGUgcmVtb3RlIGludGFuY2UuIFJldHVybnMK
PiDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoFRydWUgaWYgcmVzcG9uc2UgbWF0
Y2hlcyB3aXRoIHRoZSBidWZmZXIgc2VudC4gSWYgc29tZQo+IMKgIMKgIMKgIMKgIMKgIMKgIMKg
IMKgIMKgIMKgIMKgIMKgZXJyb3IgaXMgZGV0ZWN0ZWQgRmFsc2UgdmFsdWUgaXMgcmV0dXJuZWQg
YW5kIHRoZQo+IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgYXNzb2NpYXRlZCBN
Q0wgaXMgY2xvc2VkLgo+Cj4gwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqB1aW50MTYgT3BlbkRhdGFD
aGFubmVsKGJ5dGUgbWRlcGlkLCBieXRlIGNvbmZpZykKPgo+IMKgIMKgIMKgIMKgIMKgIMKgIMKg
IMKgIMKgIMKgIMKgIMKgQ3JlYXRlcyBhIG5ldyBkYXRhIGNoYW5uZWwgd2l0aCB0aGUgaW5kaWNh
dGVkIGNvbmZpZwo+IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgdG8gdGhlIHJl
bW90ZSBNQ0FQIERhdGEgRW5kIFBvaW50IChNREVQKS4KPiDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC
oCDCoCDCoCDCoCDCoFRoZSBjb25maWd1cmF0aW9uIHNob3VsZCBpbmRpY2F0ZSB0aGUgY2hhbm5l
bCBxdWFsaXR5IG9mCj4gwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqBzZXJ2aWNl
LiBJbiB0aGUgY3VycmVudCB2ZXJzaW9uIG9mIEhEUCwgdmFsaWQgdmFsdWVzIGFyZQo+IMKgIMKg
IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgMHgwMSBmb3IgcmVsaWFibGUgY2hhbm5lbHMg
YW5kIDB4MDIgZm9yIHN0cmVhbWluZyBkYXRhCj4gwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg
wqAgwqAgwqBjaGFubmVsLgo+Cj4gwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqBS
ZXR1cm5zIHRoZSBkYXRhIGNoYW5uZWwgaWQuCj4KPiDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC
oCDCoCDCoCDCoFBvc3NpYmxlIGVycm9yczogb3JnLmJsdWV6LkVycm9yLkludmFsaWRBcmd1bWVu
dHMKPiDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC
oCDCoCDCoG9yZy5ibHVlei5FcnJvci5IZWFsdGhFcnJvcgo+Cj4gwqAgwqAgwqAgwqAgwqAgwqAg
wqAgwqBhcnJheSBHZXREYXRhQ2hhbm5lbEZpbGVEZXNjcmlwdG9yKHVpbnQxNiBtZGxpZCkKPgoK
V291bGRuJ3QgYmUgYmV0dGVyIHRvIHBhc3MgdGhlIGZkIHRocm91Z2ggdGhlIExpbmtDb25uZWN0
ZWQgY2FsbCBvbgpBZ2VudD8gRG9pbmcgaXQgaGVyZSBhbGxvd3MgYW55IHByb2Nlc3MgdG8gZ2V0
IHRoZSBmZHMuCgo+IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgR2V0cyBhIGZp
bGUgZGVzY3JpcHRvciB3aGVyZSBkYXRhIGNhbiBiZSByZWFkIG9yCj4gwqAgwqAgwqAgwqAgwqAg
wqAgwqAgwqAgwqAgwqAgwqAgwqB3cml0dGVuIGZvciByZWNlaXZlIG9yIHNlbnQgYnkgdGhlIGRh
dGEgY2hhbm5lbC4KPiDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoFJldHVybnMg
YW4gYXJyYXkgb2YgZmlsZSBkZXNjcmlwdG9ycyBvbmUgZm9yIHdyaXRlCj4gwqAgwqAgwqAgwqAg
wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqBhbmQgb3RoZXIgZm9yIHJlYWQuCj4KPiDCoCDCoCDCoCDC
oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoFBvc3NpYmxlIGVycm9yczogb3JnLmJsdWV6LkVycm9y
LkludmFsaWRBcmd1bWVudHMKPiDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC
oCDCoCDCoCDCoCDCoCDCoCDCoCDCoG9yZy5ibHVlei5FcnJvci5Ob3RGb3VuZAo+IMKgIMKgIMKg
IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgb3JnLmJs
dWV6LkVycm9yLkhlYWx0aEVycm9yCj4KPiDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoHZvaWQgRGVs
ZXRlRGF0YUNoYW5uZWwodWludDE2IG1kbGlkKQo+Cj4gwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg
wqAgwqAgwqAgwqBEZWxldGVzIGEgZGF0YSBjaGFubmVsIHNvIGl0IHdpbGwgbm90IGJlIGF2YWls
YWJsZSBmb3IKPiDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoHVzZS4KPgo+IMKg
IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgUG9zc2libGUgZXJyb3JzOiBvcmcuYmx1
ZXouRXJyb3IuSW52YWxpZEFyZ3VtZW50cwo+IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg
IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgb3JnLmJsdWV6LkVycm9yLk5vdEZvdW5kCj4g
wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg
wqBvcmcuYmx1ZXouRXJyb3IuSGVhbHRoRXJyb3IKPgo+IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg
dm9pZCBEZWxldGVBbGxEYXRhQ2hhbm5lbHMoKQo+Cj4gwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg
wqAgwqAgwqAgwqBEZWxldGVzIGFsbCBkYXRhIGNoYW5uZWxzIHNvIGl0IHdpbGwgbm90IGJlIGF2
YWlsYWJsZQo+IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgZm9yIHVzZS4gVHlw
aWNhbGx5IHRoaXMgZnVuY3Rpb24gaXMgY2FsbGVkIHdoZW4gdGhlCj4gwqAgwqAgwqAgwqAgwqAg
wqAgwqAgwqAgwqAgwqAgwqAgwqBjb25uZWN0aW9uIHdpdGggdGhlIHJlbW90ZSBkZXZpY2Ugd2ls
bCBiZSBjbG9zZWQKPiDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoHBlcm1hbmVu
dGx5Cj4KPiDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoFBvc3NpYmxlIGVycm9y
czogb3JnLmJsdWV6LkVycm9yLkhlYWx0aEVycm9yCj4KPiDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC
oGRpY3QgR2V0RGF0YUNoYW5uZWxTdGF0dXMoKQo+Cj4gwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg
wqAgwqAgwqAgwqBSZXR1cm4gYSBkaWN0aW9uYXJ5IHdpdGggYWxsIHRoZSBkYXRhIGNoYW5uZWxz
IHRoYXQKPiDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoGNhbiBiZSB1c2VkIHRv
IHNlbmQgZGF0YSByaWdodCBub3cuIFRoZSBkaWN0aW9uYXJ5Cj4gwqAgwqAgwqAgwqAgwqAgwqAg
wqAgwqAgwqAgwqAgwqAgwqBpcyBmb3JtZWQgbGlrZSBmb2xsb3dzOgo+IMKgIMKgIMKgIMKgIMKg
IMKgIMKgIMKgIMKgIMKgIMKgIMKgewo+IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg
IMKgIMKgIMKgIMKgIMKgInJlbGlhYmxlIjogW21kbGlkX3IxLCBtZGxpZF9yMiwgLi4uXSwKPiDC
oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCJzdHJlYW1pbmci
IDogW21kbGlkX3MxLCBtZGxpZF9zMiwgLi4uXQo+IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg
IMKgIMKgIMKgfQo+Cj4gwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqBUaGUgZmlz
dCByZWxpYWJsZSBkYXRhIGNoYW5uZWwgd2lsbCBhbHdheXMgYmUgdGhlIGZpcnN0Cj4gwqAgwqAg
wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqBkYXRhIGNoYW5uZWwgaW4gcmVsaWFibGUgYXJy
YXkuCj4KPiBIZWFsdGhBZ2VudCBoaWVyYXJjaHkKPiA9PT09PT09PT09PT09PT09PT0KPgo+ICh0
aGlzIG9iamVjdCBpcyBpbXBsZW1lbnRlZCBieSB0aGUgSERQIGNsaWVudCBhbiByZWNlaXZlcyBu
b3RpZmljYXRpb25zKQo+Cj4gU2VydmljZSDCoCDCoCDCoCDCoCB1bmlxdWUgbmFtZQo+IEludGVy
ZmFjZSDCoCDCoCDCoCBvcmcuYmx1ZXouSGVhbHRoQWdlbnQKPiBPYmplY3QgcGF0aCDCoCDCoCBm
cmVlbHkgZGVmaW5hYmxlCj4KPiDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoHZvaWQgTGlua0Nvbm5l
Y3RlZChvYmplY3QgcGF0aCkKPgo+IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg
VGhpcyBtZXRob2QgaXMgY2FsbGVkIHdoZW5ldmVyIGEgbmV3IGNvbm5lY3Rpb24KPiDCoCDCoCDC
oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoGhhcyBiZWVuIGVzdGFibGlzaGVkIG92ZXIgdGhl
IGNvbnRyb2wgY2hhbm5lbCBvZiB0aGUKPiDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC
oCDCoGN1cnJlbnQgSERQIGluc3RhbmNlLiBUaGUgb2JqZWN0IHBhdGggcGFyZW1ldGVyIGNvbnRh
aW5zCj4gwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqB0aGUgb2JqZWN0IHBhdGgg
b2YgdGhlIGNyZWF0ZWQgSGVhbHRoTGluay4KPgo+IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgdm9p
ZCBMaW5rRGlzY29ubmVjdGVkKG9iamVjdCBwYXRoKQo+Cj4gwqAgwqAgwqAgwqAgwqAgwqAgwqAg
wqAgwqAgwqAgwqAgwqBUaGlzIG1ldGhvZCBpcyBjYWxsZWQgd2hlbiBhIHJlbW90ZSBkZXZpY2Ug
aXMKPiDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoGRpc2Nvbm5lY3RlZCBkZWZp
bml0aXZlbHkuIEFueSBmdXR1cmUgcmVjb25uZWN0aW9ucwo+IMKgIMKgIMKgIMKgIMKgIMKgIMKg
IMKgIMKgIMKgIMKgIMKgd2lsbCBmYWlsLiBBbHNvIGFsbCBkYXRhIGNoYW5uZWxzIGFzc29jaWF0
ZWQgdG8gdGhpcwo+IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgZGV2aWNlIHdp
bGwgYmUgY2xvc2VkLgo+Cj4gwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqB2b2lkIENyZWF0ZWREYXRh
Q2hhbm5lbChvYmplY3QgcGF0aCwgdWludDE2IG1kbGlkLCBieXRlIGNvbmYpCj4KPiDCoCDCoCDC
oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoFRoaXMgbWV0aG9kIGlzIGNhbGxlZCB3aGVuIGEg
bmV3IGRhdGEgY2hhbm5lbCBpcyBjcmVhdGVkCj4gwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg
wqAgwqAgwqBUaGUgcGF0aCBjb250YWlucyB0aGUgb2JqZWN0IHBhdGggb2YgdGhlIEhlYWx0aExp
bmsKPiDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoHdoZXJlIHRoZSBuZXcgY29u
bmVjdGlvbiBpcyBjcmVhdGVkLCB0aGUgbWRsaWQgaXMgdGhlCj4gwqAgwqAgwqAgwqAgwqAgwqAg
wqAgwqAgwqAgwqAgwqAgwqBkYXRhIGNoYW5uZWwgaWRlbnRpZmljYXRvciBhbmQgY29uZiBpcyB0
aGUgcXVlIHF1YWxpdHkKPiDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoG9mIHNl
cnZpY2Ugb2YgdGhlIGRhdGEgY2hhbm5lbCAoMHgwMSByZWxpYWJsZSwgMHgwMgo+IMKgIMKgIMKg
IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgc3RyZWFtaW5nKS4KPgo+IMKgIMKgIMKgIMKgIMKg
IMKgIMKgIMKgdm9pZCBEZWxldGVkRGF0YUNoYW5uZWwob2JqZWN0IHBhdGgsIHVpbnQxNiBtZGxp
ZCkKPgo+IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgVGhpcyBtZXRob2QgaXMg
Y2FsbGVkIHdoZW4gYSBkYXRhIGNoYW5uZWwgaXMgY2xvc2VkLgo+IMKgIMKgIMKgIMKgIMKgIMKg
IMKgIMKgIMKgIMKgIMKgIMKgQWZ0ZXIgdGhpcyBjYWxsIHRoZSBkYXRhIGNoYW5uZWwgd2lsbCBu
b3QgYmUgdmFsaWQgYW5kCj4gwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqBjYW4g
YmUgcmV1c2VkIGZvciBmdXR1cmUgY3JlYXRlZCBkYXRhIGNoYW5uZWxzLgo+IC0tCj4gVG8gdW5z
dWJzY3JpYmUgZnJvbSB0aGlzIGxpc3Q6IHNlbmQgdGhlIGxpbmUgInVuc3Vic2NyaWJlIGxpbnV4
LWJsdWV0b290aCIgaW4KPiB0aGUgYm9keSBvZiBhIG1lc3NhZ2UgdG8gbWFqb3Jkb21vQHZnZXIu
a2VybmVsLm9yZwo+IE1vcmUgbWFqb3Jkb21vIGluZm8gYXQgwqBodHRwOi8vdmdlci5rZXJuZWwu
b3JnL21ham9yZG9tby1pbmZvLmh0bWwKPgoKCgotLSAKSm/Do28gUGF1bG8gUmVjaGkgVml0YQpo
dHRwOi8vanBydml0YS53b3JkcHJlc3MuY29tLwo=