flwr-nightly 1.11.0.dev20240816__py3-none-any.whl → 1.11.0.dev20240817__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of flwr-nightly might be problematic. Click here for more details.
- flwr/client/app.py +4 -3
- flwr/client/{process → clientapp}/__init__.py +7 -0
- flwr/client/{process/process.py → clientapp/app.py} +36 -1
- flwr/client/{process → clientapp}/clientappio_servicer.py +115 -21
- flwr/client/supernode/__init__.py +0 -2
- flwr/client/supernode/app.py +1 -28
- flwr/proto/clientappio_pb2.py +17 -13
- flwr/proto/clientappio_pb2.pyi +17 -0
- flwr/proto/clientappio_pb2_grpc.py +34 -0
- flwr/proto/clientappio_pb2_grpc.pyi +13 -0
- flwr/server/superlink/fleet/vce/vce_api.py +1 -1
- {flwr_nightly-1.11.0.dev20240816.dist-info → flwr_nightly-1.11.0.dev20240817.dist-info}/METADATA +1 -1
- {flwr_nightly-1.11.0.dev20240816.dist-info → flwr_nightly-1.11.0.dev20240817.dist-info}/RECORD +17 -17
- {flwr_nightly-1.11.0.dev20240816.dist-info → flwr_nightly-1.11.0.dev20240817.dist-info}/entry_points.txt +1 -1
- /flwr/client/{process → clientapp}/utils.py +0 -0
- {flwr_nightly-1.11.0.dev20240816.dist-info → flwr_nightly-1.11.0.dev20240817.dist-info}/LICENSE +0 -0
- {flwr_nightly-1.11.0.dev20240816.dist-info → flwr_nightly-1.11.0.dev20240817.dist-info}/WHEEL +0 -0
flwr/client/app.py
CHANGED
|
@@ -52,13 +52,13 @@ from flwr.proto.clientappio_pb2_grpc import add_ClientAppIoServicer_to_server
|
|
|
52
52
|
from flwr.server.superlink.fleet.grpc_bidi.grpc_server import generic_create_grpc_server
|
|
53
53
|
from flwr.server.superlink.state.utils import generate_rand_int_from_bytes
|
|
54
54
|
|
|
55
|
+
from .clientapp.clientappio_servicer import ClientAppIoInputs, ClientAppIoServicer
|
|
55
56
|
from .grpc_adapter_client.connection import grpc_adapter
|
|
56
57
|
from .grpc_client.connection import grpc_connection
|
|
57
58
|
from .grpc_rere_client.connection import grpc_request_response
|
|
58
59
|
from .message_handler.message_handler import handle_control_message
|
|
59
60
|
from .node_state import NodeState
|
|
60
61
|
from .numpy_client import NumPyClient
|
|
61
|
-
from .process.clientappio_servicer import ClientAppIoInputs, ClientAppIoServicer
|
|
62
62
|
|
|
63
63
|
ADDRESS_CLIENTAPPIO_API_GRPC_RERE = "0.0.0.0:9094"
|
|
64
64
|
|
|
@@ -460,12 +460,13 @@ def start_client_internal(
|
|
|
460
460
|
|
|
461
461
|
# Share Message and Context with servicer
|
|
462
462
|
clientappio_servicer.set_inputs(
|
|
463
|
-
ClientAppIoInputs(
|
|
463
|
+
clientapp_input=ClientAppIoInputs(
|
|
464
464
|
message=message,
|
|
465
465
|
context=context,
|
|
466
466
|
run=run,
|
|
467
467
|
token=token,
|
|
468
|
-
)
|
|
468
|
+
),
|
|
469
|
+
token_returned=True,
|
|
469
470
|
)
|
|
470
471
|
|
|
471
472
|
# Run `ClientApp` in subprocess
|
|
@@ -14,8 +14,9 @@
|
|
|
14
14
|
# ==============================================================================
|
|
15
15
|
"""Flower ClientApp process."""
|
|
16
16
|
|
|
17
|
+
import argparse
|
|
17
18
|
from logging import DEBUG, ERROR, INFO
|
|
18
|
-
from typing import Tuple
|
|
19
|
+
from typing import Optional, Tuple
|
|
19
20
|
|
|
20
21
|
import grpc
|
|
21
22
|
|
|
@@ -36,6 +37,8 @@ from flwr.common.typing import Run
|
|
|
36
37
|
|
|
37
38
|
# pylint: disable=E0611
|
|
38
39
|
from flwr.proto.clientappio_pb2 import (
|
|
40
|
+
GetTokenRequest,
|
|
41
|
+
GetTokenResponse,
|
|
39
42
|
PullClientAppInputsRequest,
|
|
40
43
|
PullClientAppInputsResponse,
|
|
41
44
|
PushClientAppOutputsRequest,
|
|
@@ -46,6 +49,32 @@ from flwr.proto.clientappio_pb2_grpc import ClientAppIoStub
|
|
|
46
49
|
from .utils import get_load_client_app_fn
|
|
47
50
|
|
|
48
51
|
|
|
52
|
+
def flwr_clientapp() -> None:
|
|
53
|
+
"""Run process-isolated Flower ClientApp."""
|
|
54
|
+
log(INFO, "Starting Flower ClientApp")
|
|
55
|
+
|
|
56
|
+
parser = argparse.ArgumentParser(
|
|
57
|
+
description="Run a Flower ClientApp",
|
|
58
|
+
)
|
|
59
|
+
parser.add_argument(
|
|
60
|
+
"--supernode",
|
|
61
|
+
help="Address of SuperNode ClientAppIo gRPC servicer",
|
|
62
|
+
)
|
|
63
|
+
parser.add_argument(
|
|
64
|
+
"--token",
|
|
65
|
+
help="Unique token generated by SuperNode for each ClientApp execution",
|
|
66
|
+
)
|
|
67
|
+
args = parser.parse_args()
|
|
68
|
+
log(
|
|
69
|
+
DEBUG,
|
|
70
|
+
"Staring isolated `ClientApp` connected to SuperNode ClientAppIo at %s "
|
|
71
|
+
"with the token %s",
|
|
72
|
+
args.supernode,
|
|
73
|
+
args.token,
|
|
74
|
+
)
|
|
75
|
+
run_clientapp(supernode=args.supernode, token=int(args.token))
|
|
76
|
+
|
|
77
|
+
|
|
49
78
|
def on_channel_state_change(channel_connectivity: str) -> None:
|
|
50
79
|
"""Log channel connectivity."""
|
|
51
80
|
log(DEBUG, channel_connectivity)
|
|
@@ -118,6 +147,12 @@ def run_clientapp( # pylint: disable=R0914
|
|
|
118
147
|
channel.close()
|
|
119
148
|
|
|
120
149
|
|
|
150
|
+
def get_token(stub: grpc.Channel) -> Optional[int]:
|
|
151
|
+
"""Get a token from SuperNode."""
|
|
152
|
+
res: GetTokenResponse = stub.GetToken(GetTokenRequest())
|
|
153
|
+
return res.token
|
|
154
|
+
|
|
155
|
+
|
|
121
156
|
def pull_message(stub: grpc.Channel, token: int) -> Tuple[Message, Context, Run]:
|
|
122
157
|
"""Pull message from SuperNode to ClientApp."""
|
|
123
158
|
res: PullClientAppInputsResponse = stub.PullClientAppInputs(
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
|
|
18
18
|
from dataclasses import dataclass
|
|
19
19
|
from logging import DEBUG, ERROR
|
|
20
|
-
from typing import Optional
|
|
20
|
+
from typing import Optional, cast
|
|
21
21
|
|
|
22
22
|
import grpc
|
|
23
23
|
|
|
@@ -36,6 +36,8 @@ from flwr.common.typing import Run
|
|
|
36
36
|
# pylint: disable=E0611
|
|
37
37
|
from flwr.proto import clientappio_pb2_grpc
|
|
38
38
|
from flwr.proto.clientappio_pb2 import ( # pylint: disable=E0401
|
|
39
|
+
GetTokenRequest,
|
|
40
|
+
GetTokenResponse,
|
|
39
41
|
PullClientAppInputsRequest,
|
|
40
42
|
PullClientAppInputsResponse,
|
|
41
43
|
PushClientAppOutputsRequest,
|
|
@@ -68,25 +70,72 @@ class ClientAppIoServicer(clientappio_pb2_grpc.ClientAppIoServicer):
|
|
|
68
70
|
def __init__(self) -> None:
|
|
69
71
|
self.clientapp_input: Optional[ClientAppIoInputs] = None
|
|
70
72
|
self.clientapp_output: Optional[ClientAppIoOutputs] = None
|
|
73
|
+
self.token_returned: bool = False
|
|
74
|
+
self.inputs_returned: bool = False
|
|
75
|
+
|
|
76
|
+
def GetToken(
|
|
77
|
+
self, request: GetTokenRequest, context: grpc.ServicerContext
|
|
78
|
+
) -> GetTokenResponse:
|
|
79
|
+
"""Get token."""
|
|
80
|
+
log(DEBUG, "ClientAppIo.GetToken")
|
|
81
|
+
|
|
82
|
+
# Fail if no ClientAppIoInputs are available
|
|
83
|
+
if self.clientapp_input is None:
|
|
84
|
+
context.abort(
|
|
85
|
+
grpc.StatusCode.FAILED_PRECONDITION,
|
|
86
|
+
"No inputs available.",
|
|
87
|
+
)
|
|
88
|
+
clientapp_input = cast(ClientAppIoInputs, self.clientapp_input)
|
|
89
|
+
|
|
90
|
+
# Fail if token was already returned in a previous call
|
|
91
|
+
if self.token_returned:
|
|
92
|
+
context.abort(
|
|
93
|
+
grpc.StatusCode.FAILED_PRECONDITION,
|
|
94
|
+
"Token already returned. A token can be returned only once.",
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
# If
|
|
98
|
+
# - ClientAppIoInputs is set, and
|
|
99
|
+
# - token hasn't been returned before,
|
|
100
|
+
# return token
|
|
101
|
+
self.token_returned = True
|
|
102
|
+
return GetTokenResponse(token=clientapp_input.token)
|
|
71
103
|
|
|
72
104
|
def PullClientAppInputs(
|
|
73
105
|
self, request: PullClientAppInputsRequest, context: grpc.ServicerContext
|
|
74
106
|
) -> PullClientAppInputsResponse:
|
|
75
107
|
"""Pull Message, Context, and Run."""
|
|
76
108
|
log(DEBUG, "ClientAppIo.PullClientAppInputs")
|
|
109
|
+
|
|
110
|
+
# Fail if no ClientAppIoInputs are available
|
|
77
111
|
if self.clientapp_input is None:
|
|
78
|
-
|
|
79
|
-
|
|
112
|
+
context.abort(
|
|
113
|
+
grpc.StatusCode.FAILED_PRECONDITION,
|
|
114
|
+
"No inputs available.",
|
|
80
115
|
)
|
|
81
|
-
|
|
116
|
+
clientapp_input = cast(ClientAppIoInputs, self.clientapp_input)
|
|
117
|
+
|
|
118
|
+
# Fail if token wasn't returned in a previous call
|
|
119
|
+
if not self.token_returned:
|
|
120
|
+
context.abort(
|
|
121
|
+
grpc.StatusCode.FAILED_PRECONDITION,
|
|
122
|
+
"Token hasn't been returned."
|
|
123
|
+
"Token must be returned before can be returned only once.",
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
# Fail if token isn't matching
|
|
127
|
+
if request.token != clientapp_input.token:
|
|
82
128
|
context.abort(
|
|
83
129
|
grpc.StatusCode.INVALID_ARGUMENT,
|
|
84
130
|
"Mismatch between ClientApp and SuperNode token",
|
|
85
131
|
)
|
|
132
|
+
|
|
133
|
+
# Success
|
|
134
|
+
self.inputs_returned = True
|
|
86
135
|
return PullClientAppInputsResponse(
|
|
87
|
-
message=message_to_proto(
|
|
88
|
-
context=context_to_proto(
|
|
89
|
-
run=run_to_proto(
|
|
136
|
+
message=message_to_proto(clientapp_input.message),
|
|
137
|
+
context=context_to_proto(clientapp_input.context),
|
|
138
|
+
run=run_to_proto(clientapp_input.run),
|
|
90
139
|
)
|
|
91
140
|
|
|
92
141
|
def PushClientAppOutputs(
|
|
@@ -94,15 +143,39 @@ class ClientAppIoServicer(clientappio_pb2_grpc.ClientAppIoServicer):
|
|
|
94
143
|
) -> PushClientAppOutputsResponse:
|
|
95
144
|
"""Push Message and Context."""
|
|
96
145
|
log(DEBUG, "ClientAppIo.PushClientAppOutputs")
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
146
|
+
|
|
147
|
+
# Fail if no ClientAppIoInputs are available
|
|
148
|
+
if not self.clientapp_input:
|
|
149
|
+
context.abort(
|
|
150
|
+
grpc.StatusCode.FAILED_PRECONDITION,
|
|
151
|
+
"No inputs available.",
|
|
152
|
+
)
|
|
153
|
+
clientapp_input = cast(ClientAppIoInputs, self.clientapp_input)
|
|
154
|
+
|
|
155
|
+
# Fail if token wasn't returned in a previous call
|
|
156
|
+
if not self.token_returned:
|
|
157
|
+
context.abort(
|
|
158
|
+
grpc.StatusCode.FAILED_PRECONDITION,
|
|
159
|
+
"Token hasn't been returned."
|
|
160
|
+
"Token must be returned before can be returned only once.",
|
|
100
161
|
)
|
|
101
|
-
|
|
162
|
+
|
|
163
|
+
# Fail if inputs weren't delivered in a previous call
|
|
164
|
+
if not self.inputs_returned:
|
|
165
|
+
context.abort(
|
|
166
|
+
grpc.StatusCode.FAILED_PRECONDITION,
|
|
167
|
+
"Inputs haven't been delivered."
|
|
168
|
+
"Inputs must be delivered before can be returned only once.",
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
# Fail if token isn't matching
|
|
172
|
+
if request.token != clientapp_input.token:
|
|
102
173
|
context.abort(
|
|
103
174
|
grpc.StatusCode.INVALID_ARGUMENT,
|
|
104
175
|
"Mismatch between ClientApp and SuperNode token",
|
|
105
176
|
)
|
|
177
|
+
|
|
178
|
+
# Preconditions met
|
|
106
179
|
try:
|
|
107
180
|
# Update Message and Context
|
|
108
181
|
self.clientapp_output = ClientAppIoOutputs(
|
|
@@ -113,32 +186,53 @@ class ClientAppIoServicer(clientappio_pb2_grpc.ClientAppIoServicer):
|
|
|
113
186
|
# Set status
|
|
114
187
|
code = typing.ClientAppOutputCode.SUCCESS
|
|
115
188
|
status = typing.ClientAppOutputStatus(code=code, message="Success")
|
|
116
|
-
proto_status = clientappstatus_to_proto(status=status)
|
|
117
|
-
return PushClientAppOutputsResponse(status=proto_status)
|
|
118
189
|
except Exception as e: # pylint: disable=broad-exception-caught
|
|
119
190
|
log(ERROR, "ClientApp failed to push message to SuperNode, %s", e)
|
|
120
191
|
code = typing.ClientAppOutputCode.UNKNOWN_ERROR
|
|
121
|
-
status = typing.ClientAppOutputStatus(code=code, message="
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
192
|
+
status = typing.ClientAppOutputStatus(code=code, message="Unkonwn error")
|
|
193
|
+
|
|
194
|
+
# Return status to ClientApp process
|
|
195
|
+
proto_status = clientappstatus_to_proto(status=status)
|
|
196
|
+
return PushClientAppOutputsResponse(status=proto_status)
|
|
197
|
+
|
|
198
|
+
def set_inputs(
|
|
199
|
+
self, clientapp_input: ClientAppIoInputs, token_returned: bool
|
|
200
|
+
) -> None:
|
|
201
|
+
"""Set ClientApp inputs.
|
|
202
|
+
|
|
203
|
+
Parameters
|
|
204
|
+
----------
|
|
205
|
+
clientapp_input : ClientAppIoInputs
|
|
206
|
+
The inputs to the ClientApp.
|
|
207
|
+
token_returned : bool
|
|
208
|
+
A boolean indicating if the token has been returned.
|
|
209
|
+
Set to `True` when passing the token to `flwr-clientap`
|
|
210
|
+
and `False` otherwise.
|
|
211
|
+
"""
|
|
127
212
|
log(DEBUG, "ClientAppIo.SetInputs")
|
|
128
|
-
if
|
|
213
|
+
if (
|
|
214
|
+
self.clientapp_input is not None
|
|
215
|
+
or self.clientapp_output is not None
|
|
216
|
+
or self.token_returned
|
|
217
|
+
):
|
|
129
218
|
raise ValueError(
|
|
130
219
|
"ClientAppIoInputs and ClientAppIoOutputs must not be set before "
|
|
131
220
|
"calling `set_inputs`."
|
|
132
221
|
)
|
|
133
222
|
self.clientapp_input = clientapp_input
|
|
223
|
+
self.token_returned = token_returned
|
|
134
224
|
|
|
135
225
|
def get_outputs(self) -> ClientAppIoOutputs:
|
|
136
226
|
"""Get ClientApp outputs."""
|
|
137
227
|
log(DEBUG, "ClientAppIo.GetOutputs")
|
|
138
228
|
if self.clientapp_output is None:
|
|
139
229
|
raise ValueError("ClientAppIoOutputs not set before calling `get_outputs`.")
|
|
140
|
-
|
|
230
|
+
|
|
231
|
+
# Set outputs to a local variable and clear state
|
|
141
232
|
output: ClientAppIoOutputs = self.clientapp_output
|
|
142
233
|
self.clientapp_input = None
|
|
143
234
|
self.clientapp_output = None
|
|
235
|
+
self.token_returned = False
|
|
236
|
+
self.inputs_returned = False
|
|
237
|
+
|
|
144
238
|
return output
|
|
@@ -15,12 +15,10 @@
|
|
|
15
15
|
"""Flower SuperNode."""
|
|
16
16
|
|
|
17
17
|
|
|
18
|
-
from .app import flwr_clientapp as flwr_clientapp
|
|
19
18
|
from .app import run_client_app as run_client_app
|
|
20
19
|
from .app import run_supernode as run_supernode
|
|
21
20
|
|
|
22
21
|
__all__ = [
|
|
23
|
-
"flwr_clientapp",
|
|
24
22
|
"run_client_app",
|
|
25
23
|
"run_supernode",
|
|
26
24
|
]
|
flwr/client/supernode/app.py
CHANGED
|
@@ -38,8 +38,7 @@ from flwr.common.exit_handlers import register_exit_handlers
|
|
|
38
38
|
from flwr.common.logger import log, warn_deprecated_feature
|
|
39
39
|
|
|
40
40
|
from ..app import start_client_internal
|
|
41
|
-
from ..
|
|
42
|
-
from ..process.utils import get_load_client_app_fn
|
|
41
|
+
from ..clientapp.utils import get_load_client_app_fn
|
|
43
42
|
|
|
44
43
|
ADDRESS_FLEET_API_GRPC_RERE = "0.0.0.0:9092"
|
|
45
44
|
|
|
@@ -115,32 +114,6 @@ def run_client_app() -> None:
|
|
|
115
114
|
register_exit_handlers(event_type=EventType.RUN_CLIENT_APP_LEAVE)
|
|
116
115
|
|
|
117
116
|
|
|
118
|
-
def flwr_clientapp() -> None:
|
|
119
|
-
"""Run process-isolated Flower ClientApp."""
|
|
120
|
-
log(INFO, "Starting Flower ClientApp")
|
|
121
|
-
|
|
122
|
-
parser = argparse.ArgumentParser(
|
|
123
|
-
description="Run a Flower ClientApp",
|
|
124
|
-
)
|
|
125
|
-
parser.add_argument(
|
|
126
|
-
"--supernode",
|
|
127
|
-
help="Address of SuperNode ClientAppIo gRPC servicer",
|
|
128
|
-
)
|
|
129
|
-
parser.add_argument(
|
|
130
|
-
"--token",
|
|
131
|
-
help="Unique token generated by SuperNode for each ClientApp execution",
|
|
132
|
-
)
|
|
133
|
-
args = parser.parse_args()
|
|
134
|
-
log(
|
|
135
|
-
DEBUG,
|
|
136
|
-
"Staring isolated `ClientApp` connected to SuperNode ClientAppIo at %s "
|
|
137
|
-
"with the token %s",
|
|
138
|
-
args.supernode,
|
|
139
|
-
args.token,
|
|
140
|
-
)
|
|
141
|
-
run_clientapp(supernode=args.supernode, token=int(args.token))
|
|
142
|
-
|
|
143
|
-
|
|
144
117
|
def _warn_deprecated_server_arg(args: argparse.Namespace) -> None:
|
|
145
118
|
"""Warn about the deprecated argument `--server`."""
|
|
146
119
|
if args.server != ADDRESS_FLEET_API_GRPC_RERE:
|
flwr/proto/clientappio_pb2.py
CHANGED
|
@@ -17,25 +17,29 @@ from flwr.proto import run_pb2 as flwr_dot_proto_dot_run__pb2
|
|
|
17
17
|
from flwr.proto import message_pb2 as flwr_dot_proto_dot_message__pb2
|
|
18
18
|
|
|
19
19
|
|
|
20
|
-
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1c\x66lwr/proto/clientappio.proto\x12\nflwr.proto\x1a\x14\x66lwr/proto/fab.proto\x1a\x14\x66lwr/proto/run.proto\x1a\x18\x66lwr/proto/message.proto\"W\n\x15\x43lientAppOutputStatus\x12-\n\x04\x63ode\x18\x01 \x01(\x0e\x32\x1f.flwr.proto.ClientAppOutputCode\x12\x0f\n\x07message\x18\x02 \x01(\t\"+\n\x1aPullClientAppInputsRequest\x12\r\n\x05token\x18\x01 \x01(\x12\"\x87\x01\n\x1bPullClientAppInputsResponse\x12$\n\x07message\x18\x01 \x01(\x0b\x32\x13.flwr.proto.Message\x12$\n\x07\x63ontext\x18\x02 \x01(\x0b\x32\x13.flwr.proto.Context\x12\x1c\n\x03run\x18\x03 \x01(\x0b\x32\x0f.flwr.proto.Run\"x\n\x1bPushClientAppOutputsRequest\x12\r\n\x05token\x18\x01 \x01(\x12\x12$\n\x07message\x18\x02 \x01(\x0b\x32\x13.flwr.proto.Message\x12$\n\x07\x63ontext\x18\x03 \x01(\x0b\x32\x13.flwr.proto.Context\"Q\n\x1cPushClientAppOutputsResponse\x12\x31\n\x06status\x18\x01 \x01(\x0b\x32!.flwr.proto.ClientAppOutputStatus*L\n\x13\x43lientAppOutputCode\x12\x0b\n\x07SUCCESS\x10\x00\x12\x15\n\x11\x44\x45\x41\x44LINE_EXCEEDED\x10\x01\x12\x11\n\rUNKNOWN_ERROR\x10\x02\x32\
|
|
20
|
+
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1c\x66lwr/proto/clientappio.proto\x12\nflwr.proto\x1a\x14\x66lwr/proto/fab.proto\x1a\x14\x66lwr/proto/run.proto\x1a\x18\x66lwr/proto/message.proto\"W\n\x15\x43lientAppOutputStatus\x12-\n\x04\x63ode\x18\x01 \x01(\x0e\x32\x1f.flwr.proto.ClientAppOutputCode\x12\x0f\n\x07message\x18\x02 \x01(\t\"\x11\n\x0fGetTokenRequest\"!\n\x10GetTokenResponse\x12\r\n\x05token\x18\x01 \x01(\x12\"+\n\x1aPullClientAppInputsRequest\x12\r\n\x05token\x18\x01 \x01(\x12\"\x87\x01\n\x1bPullClientAppInputsResponse\x12$\n\x07message\x18\x01 \x01(\x0b\x32\x13.flwr.proto.Message\x12$\n\x07\x63ontext\x18\x02 \x01(\x0b\x32\x13.flwr.proto.Context\x12\x1c\n\x03run\x18\x03 \x01(\x0b\x32\x0f.flwr.proto.Run\"x\n\x1bPushClientAppOutputsRequest\x12\r\n\x05token\x18\x01 \x01(\x12\x12$\n\x07message\x18\x02 \x01(\x0b\x32\x13.flwr.proto.Message\x12$\n\x07\x63ontext\x18\x03 \x01(\x0b\x32\x13.flwr.proto.Context\"Q\n\x1cPushClientAppOutputsResponse\x12\x31\n\x06status\x18\x01 \x01(\x0b\x32!.flwr.proto.ClientAppOutputStatus*L\n\x13\x43lientAppOutputCode\x12\x0b\n\x07SUCCESS\x10\x00\x12\x15\n\x11\x44\x45\x41\x44LINE_EXCEEDED\x10\x01\x12\x11\n\rUNKNOWN_ERROR\x10\x02\x32\xad\x02\n\x0b\x43lientAppIo\x12G\n\x08GetToken\x12\x1b.flwr.proto.GetTokenRequest\x1a\x1c.flwr.proto.GetTokenResponse\"\x00\x12h\n\x13PullClientAppInputs\x12&.flwr.proto.PullClientAppInputsRequest\x1a\'.flwr.proto.PullClientAppInputsResponse\"\x00\x12k\n\x14PushClientAppOutputs\x12\'.flwr.proto.PushClientAppOutputsRequest\x1a(.flwr.proto.PushClientAppOutputsResponse\"\x00\x62\x06proto3')
|
|
21
21
|
|
|
22
22
|
_globals = globals()
|
|
23
23
|
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
|
24
24
|
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'flwr.proto.clientappio_pb2', _globals)
|
|
25
25
|
if _descriptor._USE_C_DESCRIPTORS == False:
|
|
26
26
|
DESCRIPTOR._options = None
|
|
27
|
-
_globals['_CLIENTAPPOUTPUTCODE']._serialized_start=
|
|
28
|
-
_globals['_CLIENTAPPOUTPUTCODE']._serialized_end=
|
|
27
|
+
_globals['_CLIENTAPPOUTPUTCODE']._serialized_start=645
|
|
28
|
+
_globals['_CLIENTAPPOUTPUTCODE']._serialized_end=721
|
|
29
29
|
_globals['_CLIENTAPPOUTPUTSTATUS']._serialized_start=114
|
|
30
30
|
_globals['_CLIENTAPPOUTPUTSTATUS']._serialized_end=201
|
|
31
|
-
_globals['
|
|
32
|
-
_globals['
|
|
33
|
-
_globals['
|
|
34
|
-
_globals['
|
|
35
|
-
_globals['
|
|
36
|
-
_globals['
|
|
37
|
-
_globals['
|
|
38
|
-
_globals['
|
|
39
|
-
_globals['
|
|
40
|
-
_globals['
|
|
31
|
+
_globals['_GETTOKENREQUEST']._serialized_start=203
|
|
32
|
+
_globals['_GETTOKENREQUEST']._serialized_end=220
|
|
33
|
+
_globals['_GETTOKENRESPONSE']._serialized_start=222
|
|
34
|
+
_globals['_GETTOKENRESPONSE']._serialized_end=255
|
|
35
|
+
_globals['_PULLCLIENTAPPINPUTSREQUEST']._serialized_start=257
|
|
36
|
+
_globals['_PULLCLIENTAPPINPUTSREQUEST']._serialized_end=300
|
|
37
|
+
_globals['_PULLCLIENTAPPINPUTSRESPONSE']._serialized_start=303
|
|
38
|
+
_globals['_PULLCLIENTAPPINPUTSRESPONSE']._serialized_end=438
|
|
39
|
+
_globals['_PUSHCLIENTAPPOUTPUTSREQUEST']._serialized_start=440
|
|
40
|
+
_globals['_PUSHCLIENTAPPOUTPUTSREQUEST']._serialized_end=560
|
|
41
|
+
_globals['_PUSHCLIENTAPPOUTPUTSRESPONSE']._serialized_start=562
|
|
42
|
+
_globals['_PUSHCLIENTAPPOUTPUTSRESPONSE']._serialized_end=643
|
|
43
|
+
_globals['_CLIENTAPPIO']._serialized_start=724
|
|
44
|
+
_globals['_CLIENTAPPIO']._serialized_end=1025
|
|
41
45
|
# @@protoc_insertion_point(module_scope)
|
flwr/proto/clientappio_pb2.pyi
CHANGED
|
@@ -44,6 +44,23 @@ class ClientAppOutputStatus(google.protobuf.message.Message):
|
|
|
44
44
|
def ClearField(self, field_name: typing_extensions.Literal["code",b"code","message",b"message"]) -> None: ...
|
|
45
45
|
global___ClientAppOutputStatus = ClientAppOutputStatus
|
|
46
46
|
|
|
47
|
+
class GetTokenRequest(google.protobuf.message.Message):
|
|
48
|
+
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
|
49
|
+
def __init__(self,
|
|
50
|
+
) -> None: ...
|
|
51
|
+
global___GetTokenRequest = GetTokenRequest
|
|
52
|
+
|
|
53
|
+
class GetTokenResponse(google.protobuf.message.Message):
|
|
54
|
+
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
|
55
|
+
TOKEN_FIELD_NUMBER: builtins.int
|
|
56
|
+
token: builtins.int
|
|
57
|
+
def __init__(self,
|
|
58
|
+
*,
|
|
59
|
+
token: builtins.int = ...,
|
|
60
|
+
) -> None: ...
|
|
61
|
+
def ClearField(self, field_name: typing_extensions.Literal["token",b"token"]) -> None: ...
|
|
62
|
+
global___GetTokenResponse = GetTokenResponse
|
|
63
|
+
|
|
47
64
|
class PullClientAppInputsRequest(google.protobuf.message.Message):
|
|
48
65
|
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
|
49
66
|
TOKEN_FIELD_NUMBER: builtins.int
|
|
@@ -14,6 +14,11 @@ class ClientAppIoStub(object):
|
|
|
14
14
|
Args:
|
|
15
15
|
channel: A grpc.Channel.
|
|
16
16
|
"""
|
|
17
|
+
self.GetToken = channel.unary_unary(
|
|
18
|
+
'/flwr.proto.ClientAppIo/GetToken',
|
|
19
|
+
request_serializer=flwr_dot_proto_dot_clientappio__pb2.GetTokenRequest.SerializeToString,
|
|
20
|
+
response_deserializer=flwr_dot_proto_dot_clientappio__pb2.GetTokenResponse.FromString,
|
|
21
|
+
)
|
|
17
22
|
self.PullClientAppInputs = channel.unary_unary(
|
|
18
23
|
'/flwr.proto.ClientAppIo/PullClientAppInputs',
|
|
19
24
|
request_serializer=flwr_dot_proto_dot_clientappio__pb2.PullClientAppInputsRequest.SerializeToString,
|
|
@@ -29,6 +34,13 @@ class ClientAppIoStub(object):
|
|
|
29
34
|
class ClientAppIoServicer(object):
|
|
30
35
|
"""Missing associated documentation comment in .proto file."""
|
|
31
36
|
|
|
37
|
+
def GetToken(self, request, context):
|
|
38
|
+
"""Get token
|
|
39
|
+
"""
|
|
40
|
+
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
|
41
|
+
context.set_details('Method not implemented!')
|
|
42
|
+
raise NotImplementedError('Method not implemented!')
|
|
43
|
+
|
|
32
44
|
def PullClientAppInputs(self, request, context):
|
|
33
45
|
"""Get Message, Context, and Run
|
|
34
46
|
"""
|
|
@@ -46,6 +58,11 @@ class ClientAppIoServicer(object):
|
|
|
46
58
|
|
|
47
59
|
def add_ClientAppIoServicer_to_server(servicer, server):
|
|
48
60
|
rpc_method_handlers = {
|
|
61
|
+
'GetToken': grpc.unary_unary_rpc_method_handler(
|
|
62
|
+
servicer.GetToken,
|
|
63
|
+
request_deserializer=flwr_dot_proto_dot_clientappio__pb2.GetTokenRequest.FromString,
|
|
64
|
+
response_serializer=flwr_dot_proto_dot_clientappio__pb2.GetTokenResponse.SerializeToString,
|
|
65
|
+
),
|
|
49
66
|
'PullClientAppInputs': grpc.unary_unary_rpc_method_handler(
|
|
50
67
|
servicer.PullClientAppInputs,
|
|
51
68
|
request_deserializer=flwr_dot_proto_dot_clientappio__pb2.PullClientAppInputsRequest.FromString,
|
|
@@ -66,6 +83,23 @@ def add_ClientAppIoServicer_to_server(servicer, server):
|
|
|
66
83
|
class ClientAppIo(object):
|
|
67
84
|
"""Missing associated documentation comment in .proto file."""
|
|
68
85
|
|
|
86
|
+
@staticmethod
|
|
87
|
+
def GetToken(request,
|
|
88
|
+
target,
|
|
89
|
+
options=(),
|
|
90
|
+
channel_credentials=None,
|
|
91
|
+
call_credentials=None,
|
|
92
|
+
insecure=False,
|
|
93
|
+
compression=None,
|
|
94
|
+
wait_for_ready=None,
|
|
95
|
+
timeout=None,
|
|
96
|
+
metadata=None):
|
|
97
|
+
return grpc.experimental.unary_unary(request, target, '/flwr.proto.ClientAppIo/GetToken',
|
|
98
|
+
flwr_dot_proto_dot_clientappio__pb2.GetTokenRequest.SerializeToString,
|
|
99
|
+
flwr_dot_proto_dot_clientappio__pb2.GetTokenResponse.FromString,
|
|
100
|
+
options, channel_credentials,
|
|
101
|
+
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
|
102
|
+
|
|
69
103
|
@staticmethod
|
|
70
104
|
def PullClientAppInputs(request,
|
|
71
105
|
target,
|
|
@@ -8,6 +8,11 @@ import grpc
|
|
|
8
8
|
|
|
9
9
|
class ClientAppIoStub:
|
|
10
10
|
def __init__(self, channel: grpc.Channel) -> None: ...
|
|
11
|
+
GetToken: grpc.UnaryUnaryMultiCallable[
|
|
12
|
+
flwr.proto.clientappio_pb2.GetTokenRequest,
|
|
13
|
+
flwr.proto.clientappio_pb2.GetTokenResponse]
|
|
14
|
+
"""Get token"""
|
|
15
|
+
|
|
11
16
|
PullClientAppInputs: grpc.UnaryUnaryMultiCallable[
|
|
12
17
|
flwr.proto.clientappio_pb2.PullClientAppInputsRequest,
|
|
13
18
|
flwr.proto.clientappio_pb2.PullClientAppInputsResponse]
|
|
@@ -20,6 +25,14 @@ class ClientAppIoStub:
|
|
|
20
25
|
|
|
21
26
|
|
|
22
27
|
class ClientAppIoServicer(metaclass=abc.ABCMeta):
|
|
28
|
+
@abc.abstractmethod
|
|
29
|
+
def GetToken(self,
|
|
30
|
+
request: flwr.proto.clientappio_pb2.GetTokenRequest,
|
|
31
|
+
context: grpc.ServicerContext,
|
|
32
|
+
) -> flwr.proto.clientappio_pb2.GetTokenResponse:
|
|
33
|
+
"""Get token"""
|
|
34
|
+
pass
|
|
35
|
+
|
|
23
36
|
@abc.abstractmethod
|
|
24
37
|
def PullClientAppInputs(self,
|
|
25
38
|
request: flwr.proto.clientappio_pb2.PullClientAppInputsRequest,
|
|
@@ -27,8 +27,8 @@ from time import sleep
|
|
|
27
27
|
from typing import Callable, Dict, Optional
|
|
28
28
|
|
|
29
29
|
from flwr.client.client_app import ClientApp, ClientAppException, LoadClientAppError
|
|
30
|
+
from flwr.client.clientapp.utils import get_load_client_app_fn
|
|
30
31
|
from flwr.client.node_state import NodeState
|
|
31
|
-
from flwr.client.process.utils import get_load_client_app_fn
|
|
32
32
|
from flwr.common.constant import (
|
|
33
33
|
NUM_PARTITIONS_KEY,
|
|
34
34
|
PARTITION_ID_KEY,
|
{flwr_nightly-1.11.0.dev20240816.dist-info → flwr_nightly-1.11.0.dev20240817.dist-info}/RECORD
RENAMED
|
@@ -53,9 +53,13 @@ flwr/cli/run/__init__.py,sha256=oCd6HmQDx-sqver1gecgx-uMA38BLTSiiKpl7RGNceg,789
|
|
|
53
53
|
flwr/cli/run/run.py,sha256=Ero4hxwZqx5ztFWvaJqslYCUBgp-AmImkomRosdGXyc,7661
|
|
54
54
|
flwr/cli/utils.py,sha256=l65Ul0YsSBPuypk0uorAtEDmLEYiUrzpCXi6zCg9mJ4,4506
|
|
55
55
|
flwr/client/__init__.py,sha256=wzJZsYJIHf_8-PMzvfbinyzzjgh1UP1vLrAw2_yEbKI,1345
|
|
56
|
-
flwr/client/app.py,sha256=
|
|
56
|
+
flwr/client/app.py,sha256=dtdgmm4xVFhkQvymf2vAjbawE9hIFkflzLBxWcYOJjA,30268
|
|
57
57
|
flwr/client/client.py,sha256=Vp9UkOkoHdNfn6iMYZsj_5m_GICiFfUlKEVaLad-YhM,8183
|
|
58
58
|
flwr/client/client_app.py,sha256=WcO4r6wrdfaus__3s22D2sYjfcptdgmVujUAYdNE6HU,10393
|
|
59
|
+
flwr/client/clientapp/__init__.py,sha256=kZqChGnTChQ1WGSUkIlW2S5bc0d0mzDubCAmZUGRpEY,800
|
|
60
|
+
flwr/client/clientapp/app.py,sha256=SVzkUAzaHWSH1Sbe2GzLMF-OnrbZ-iKg-QphuEHl8QE,5706
|
|
61
|
+
flwr/client/clientapp/clientappio_servicer.py,sha256=lIH92rHuRQZUaEf9u8fNuiLIQIVYdAp4C1wPok62adQ,8302
|
|
62
|
+
flwr/client/clientapp/utils.py,sha256=2fYKY1LfZPalG5Cm5FbSuNMIDtouQg17GbrzPINyM_A,3990
|
|
59
63
|
flwr/client/dpfedavg_numpy_client.py,sha256=ylZ-LpBIKmL1HCiS8kq4pkp2QGalc8rYEzDHdRG3VRQ,7435
|
|
60
64
|
flwr/client/grpc_adapter_client/__init__.py,sha256=QyNWIbsq9DpyMk7oemiO1P3TBFfkfkctnJ1JoAkTl3s,742
|
|
61
65
|
flwr/client/grpc_adapter_client/connection.py,sha256=aOlCYasl8f2CrfcN-WrVEmvjAZFfEGWFOLwD6K9R0ZQ,3951
|
|
@@ -80,14 +84,10 @@ flwr/client/mod/utils.py,sha256=UAJXiB0wwVyLkCkpW_i5BXikdBR65p8sNFr7VNHm2nk,1226
|
|
|
80
84
|
flwr/client/node_state.py,sha256=Z0ZUPL5BWde9nfAPwR7cSV9YiNQeiEHbuMKDxqpy6-M,3492
|
|
81
85
|
flwr/client/node_state_tests.py,sha256=-4fVsn7y-z9NYBuhq-cjepgxgVuPqqQgDOL4SofrdIo,2239
|
|
82
86
|
flwr/client/numpy_client.py,sha256=u76GWAdHmJM88Agm2EgLQSvO8Jnk225mJTk-_TmPjFE,10283
|
|
83
|
-
flwr/client/process/__init__.py,sha256=s3hTr2dOWHkSnwivaL7YbXur38bEDgSPKKvwFLa1204,711
|
|
84
|
-
flwr/client/process/clientappio_servicer.py,sha256=TMOo1EwqLfz3tgKcom7mQcHBh4GQXzVQicW0XYpkh9g,5399
|
|
85
|
-
flwr/client/process/process.py,sha256=giQIjWHIzxKfXwiIrWDw-HZGElAf9Rbj-794TXgvE-o,4718
|
|
86
|
-
flwr/client/process/utils.py,sha256=2fYKY1LfZPalG5Cm5FbSuNMIDtouQg17GbrzPINyM_A,3990
|
|
87
87
|
flwr/client/rest_client/__init__.py,sha256=5KGlp7pjc1dhNRkKlaNtUfQmg8wrRFh9lS3P3uRS-7Q,735
|
|
88
88
|
flwr/client/rest_client/connection.py,sha256=SglZC4jpqc_0-VBo9cBHa1_2RO9TfPUULQ49DnYeFS0,12767
|
|
89
|
-
flwr/client/supernode/__init__.py,sha256=
|
|
90
|
-
flwr/client/supernode/app.py,sha256=
|
|
89
|
+
flwr/client/supernode/__init__.py,sha256=SUhWOzcgXRNXk1V9UgB5-FaWukqqrOEajVUHEcPkwyQ,865
|
|
90
|
+
flwr/client/supernode/app.py,sha256=CrZG1AM19dgubuGOP0rWYnLwpCkt9F30v137BETSP30,12595
|
|
91
91
|
flwr/client/typing.py,sha256=dxoTBnTMfqXr5J7G3y-uNjqxYCddvxhu89spfj4Lm2U,1048
|
|
92
92
|
flwr/common/__init__.py,sha256=4cBLNNnNTwHDnL_HCxhU5ILCSZ6fYh3A_aMBtlvHTVw,3721
|
|
93
93
|
flwr/common/address.py,sha256=wRu1Luezx1PWadwV9OA_KNko01oVvbRnPqfzaDn8QOk,1882
|
|
@@ -127,10 +127,10 @@ flwr/common/telemetry.py,sha256=nSjJHDitPhzB2qUl6LeSMT9Zld5lIk9uW98RpxQwiZw,8366
|
|
|
127
127
|
flwr/common/typing.py,sha256=rGabiSkjFvGIHwmhDqtuu-LBvz7LVSj1vyMlNtA7VA0,5004
|
|
128
128
|
flwr/common/version.py,sha256=W1ntylR04xkCP6zeSet6sRtBn7P1cje2lOqBJgYBjJY,1349
|
|
129
129
|
flwr/proto/__init__.py,sha256=hbY7JYakwZwCkYgCNlmHdc8rtvfoJbAZLalMdc--CGc,683
|
|
130
|
-
flwr/proto/clientappio_pb2.py,sha256=
|
|
131
|
-
flwr/proto/clientappio_pb2.pyi,sha256=
|
|
132
|
-
flwr/proto/clientappio_pb2_grpc.py,sha256=
|
|
133
|
-
flwr/proto/clientappio_pb2_grpc.pyi,sha256=
|
|
130
|
+
flwr/proto/clientappio_pb2.py,sha256=oGaTBdHuO4pL5oj2zIXG6kOdOdzZ8qaoP6I_oMOEnAY,3636
|
|
131
|
+
flwr/proto/clientappio_pb2.pyi,sha256=7QUU3731Cin-fS-MYwfyU3GDndV_gMwnwOiU0jezHpY,5460
|
|
132
|
+
flwr/proto/clientappio_pb2_grpc.py,sha256=G35GhZ3iEOL8N6tu7Kn_ip4QUx4O2HveXngHAuU2YEM,6112
|
|
133
|
+
flwr/proto/clientappio_pb2_grpc.pyi,sha256=cybktpMPaIMwrItd8hQaQDnRv4zNu_wgRddSqR9REyI,1822
|
|
134
134
|
flwr/proto/common_pb2.py,sha256=uzSmq0FJdC-MriN9UGPFs7QVIFTKJmX5lyLnzcyZ5WE,2405
|
|
135
135
|
flwr/proto/common_pb2.pyi,sha256=0ylFO7G79qqLuRg9IQUCBdgyIIFv4m8VzrfoWad4xXU,5394
|
|
136
136
|
flwr/proto/common_pb2_grpc.py,sha256=1oboBPFxaTEXt9Aw7EAj8gXHDCNMhZD2VXqocC9l_gk,159
|
|
@@ -255,7 +255,7 @@ flwr/server/superlink/fleet/vce/__init__.py,sha256=36MHKiefnJeyjwMQzVUK4m06Ojon3
|
|
|
255
255
|
flwr/server/superlink/fleet/vce/backend/__init__.py,sha256=psQjI1DQHOM5uWVXM27l_wPHjfEkMUTP-_8-lEFH1JA,1466
|
|
256
256
|
flwr/server/superlink/fleet/vce/backend/backend.py,sha256=KL0eHScWr_YfP2eY3VP8_OOMgZwnRNW7qpu5J-ISpXI,2212
|
|
257
257
|
flwr/server/superlink/fleet/vce/backend/raybackend.py,sha256=6-CjUTv1cFnAb53cZzEYCuVLrVu60tPczTo8meqeqbk,6289
|
|
258
|
-
flwr/server/superlink/fleet/vce/vce_api.py,sha256=
|
|
258
|
+
flwr/server/superlink/fleet/vce/vce_api.py,sha256=n9SfUaLDgiPVvGVudSC4dZ37vytEDlPn1WA0iUDWJ1I,12750
|
|
259
259
|
flwr/server/superlink/state/__init__.py,sha256=Gj2OTFLXvA-mAjBvwuKDM3rDrVaQPcIoybSa2uskMTE,1003
|
|
260
260
|
flwr/server/superlink/state/in_memory_state.py,sha256=XMcT5WvKPOrFOuKcByr5BRFacX4aR2n9bRkABUuPg-M,13206
|
|
261
261
|
flwr/server/superlink/state/sqlite_state.py,sha256=N8eOLZUveJOzdzL31-hXRYOMqV_-w75S1InyDenaDWU,29420
|
|
@@ -286,8 +286,8 @@ flwr/superexec/exec_grpc.py,sha256=PhqGoZEpTMxSQmUSV8Wgtzb1Za_pHJ-adZqo5RYnDyE,1
|
|
|
286
286
|
flwr/superexec/exec_servicer.py,sha256=jl0aKVjm0PLQABcTL5c3jdSIzb0Z6hpVOtrAn4Ob7ts,2323
|
|
287
287
|
flwr/superexec/executor.py,sha256=k_adivto6R2U82DADOHNvdtobehBYreRek1gOEBIQnQ,2318
|
|
288
288
|
flwr/superexec/simulation.py,sha256=lfdClQYSAIMHe43aJ0Pk-kBw_xoV09LsIMfHo2eo-Ck,6775
|
|
289
|
-
flwr_nightly-1.11.0.
|
|
290
|
-
flwr_nightly-1.11.0.
|
|
291
|
-
flwr_nightly-1.11.0.
|
|
292
|
-
flwr_nightly-1.11.0.
|
|
293
|
-
flwr_nightly-1.11.0.
|
|
289
|
+
flwr_nightly-1.11.0.dev20240817.dist-info/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
|
|
290
|
+
flwr_nightly-1.11.0.dev20240817.dist-info/METADATA,sha256=AVTluXtc1QOLgptn-tnp6VC_4E4-pjGvwHOiVLNjVA4,15690
|
|
291
|
+
flwr_nightly-1.11.0.dev20240817.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
|
|
292
|
+
flwr_nightly-1.11.0.dev20240817.dist-info/entry_points.txt,sha256=3cDQVJEBRCSLzJrVYAgjXpoCjuQ74I3A9NZ61DOHdVo,388
|
|
293
|
+
flwr_nightly-1.11.0.dev20240817.dist-info/RECORD,,
|
|
File without changes
|
{flwr_nightly-1.11.0.dev20240816.dist-info → flwr_nightly-1.11.0.dev20240817.dist-info}/LICENSE
RENAMED
|
File without changes
|
{flwr_nightly-1.11.0.dev20240816.dist-info → flwr_nightly-1.11.0.dev20240817.dist-info}/WHEEL
RENAMED
|
File without changes
|