flwr-nightly 1.13.0.dev20241028__py3-none-any.whl → 1.13.0.dev20241030__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/cli/build.py +2 -2
- flwr/cli/log.py +46 -17
- flwr/common/constant.py +6 -0
- flwr/common/date.py +3 -3
- flwr/common/logger.py +103 -0
- flwr/common/serde.py +22 -0
- flwr/proto/driver_pb2.py +24 -23
- flwr/proto/driver_pb2.pyi +0 -5
- flwr/proto/driver_pb2_grpc.py +69 -0
- flwr/proto/driver_pb2_grpc.pyi +27 -0
- flwr/proto/exec_pb2.py +6 -6
- flwr/proto/exec_pb2.pyi +8 -2
- flwr/proto/log_pb2.py +29 -0
- flwr/proto/log_pb2.pyi +39 -0
- flwr/proto/log_pb2_grpc.py +4 -0
- flwr/proto/log_pb2_grpc.pyi +4 -0
- flwr/server/app.py +1 -5
- flwr/server/driver/driver.py +14 -0
- flwr/server/driver/grpc_driver.py +8 -15
- flwr/server/driver/inmemory_driver.py +3 -11
- flwr/server/run_serverapp.py +3 -4
- flwr/server/serverapp/app.py +148 -18
- flwr/server/superlink/driver/driver_servicer.py +36 -9
- flwr/server/superlink/linkstate/in_memory_linkstate.py +28 -2
- flwr/server/superlink/linkstate/linkstate.py +35 -0
- flwr/server/superlink/linkstate/sqlite_linkstate.py +50 -0
- flwr/simulation/run_simulation.py +2 -1
- flwr/superexec/deployment.py +22 -40
- flwr/superexec/exec_servicer.py +23 -62
- flwr/superexec/executor.py +3 -4
- flwr/superexec/simulation.py +4 -7
- {flwr_nightly-1.13.0.dev20241028.dist-info → flwr_nightly-1.13.0.dev20241030.dist-info}/METADATA +1 -1
- {flwr_nightly-1.13.0.dev20241028.dist-info → flwr_nightly-1.13.0.dev20241030.dist-info}/RECORD +36 -32
- {flwr_nightly-1.13.0.dev20241028.dist-info → flwr_nightly-1.13.0.dev20241030.dist-info}/LICENSE +0 -0
- {flwr_nightly-1.13.0.dev20241028.dist-info → flwr_nightly-1.13.0.dev20241030.dist-info}/WHEEL +0 -0
- {flwr_nightly-1.13.0.dev20241028.dist-info → flwr_nightly-1.13.0.dev20241030.dist-info}/entry_points.txt +0 -0
|
@@ -99,6 +99,17 @@ CREATE TABLE IF NOT EXISTS run(
|
|
|
99
99
|
);
|
|
100
100
|
"""
|
|
101
101
|
|
|
102
|
+
SQL_CREATE_TABLE_LOGS = """
|
|
103
|
+
CREATE TABLE IF NOT EXISTS logs (
|
|
104
|
+
timestamp REAL,
|
|
105
|
+
run_id INTEGER,
|
|
106
|
+
node_id INTEGER,
|
|
107
|
+
log TEXT,
|
|
108
|
+
PRIMARY KEY (timestamp, run_id, node_id),
|
|
109
|
+
FOREIGN KEY (run_id) REFERENCES run(run_id)
|
|
110
|
+
);
|
|
111
|
+
"""
|
|
112
|
+
|
|
102
113
|
SQL_CREATE_TABLE_CONTEXT = """
|
|
103
114
|
CREATE TABLE IF NOT EXISTS context(
|
|
104
115
|
run_id INTEGER UNIQUE,
|
|
@@ -191,6 +202,7 @@ class SqliteLinkState(LinkState): # pylint: disable=R0904
|
|
|
191
202
|
|
|
192
203
|
# Create each table if not exists queries
|
|
193
204
|
cur.execute(SQL_CREATE_TABLE_RUN)
|
|
205
|
+
cur.execute(SQL_CREATE_TABLE_LOGS)
|
|
194
206
|
cur.execute(SQL_CREATE_TABLE_CONTEXT)
|
|
195
207
|
cur.execute(SQL_CREATE_TABLE_TASK_INS)
|
|
196
208
|
cur.execute(SQL_CREATE_TABLE_TASK_RES)
|
|
@@ -1015,6 +1027,44 @@ class SqliteLinkState(LinkState): # pylint: disable=R0904
|
|
|
1015
1027
|
except sqlite3.IntegrityError:
|
|
1016
1028
|
raise ValueError(f"Run {run_id} not found") from None
|
|
1017
1029
|
|
|
1030
|
+
def add_serverapp_log(self, run_id: int, log_message: str) -> None:
|
|
1031
|
+
"""Add a log entry to the ServerApp logs for the specified `run_id`."""
|
|
1032
|
+
# Convert the uint64 value to sint64 for SQLite
|
|
1033
|
+
sint64_run_id = convert_uint64_to_sint64(run_id)
|
|
1034
|
+
|
|
1035
|
+
# Store log
|
|
1036
|
+
try:
|
|
1037
|
+
query = """
|
|
1038
|
+
INSERT INTO logs (timestamp, run_id, node_id, log) VALUES (?, ?, ?, ?);
|
|
1039
|
+
"""
|
|
1040
|
+
self.query(query, (now().timestamp(), sint64_run_id, 0, log_message))
|
|
1041
|
+
except sqlite3.IntegrityError:
|
|
1042
|
+
raise ValueError(f"Run {run_id} not found") from None
|
|
1043
|
+
|
|
1044
|
+
def get_serverapp_log(
|
|
1045
|
+
self, run_id: int, after_timestamp: Optional[float]
|
|
1046
|
+
) -> tuple[str, float]:
|
|
1047
|
+
"""Get the ServerApp logs for the specified `run_id`."""
|
|
1048
|
+
# Convert the uint64 value to sint64 for SQLite
|
|
1049
|
+
sint64_run_id = convert_uint64_to_sint64(run_id)
|
|
1050
|
+
|
|
1051
|
+
# Check if the run_id exists
|
|
1052
|
+
query = "SELECT run_id FROM run WHERE run_id = ?;"
|
|
1053
|
+
if not self.query(query, (sint64_run_id,)):
|
|
1054
|
+
raise ValueError(f"Run {run_id} not found")
|
|
1055
|
+
|
|
1056
|
+
# Retrieve logs
|
|
1057
|
+
if after_timestamp is None:
|
|
1058
|
+
after_timestamp = 0.0
|
|
1059
|
+
query = """
|
|
1060
|
+
SELECT log, timestamp FROM logs
|
|
1061
|
+
WHERE run_id = ? AND node_id = ? AND timestamp > ?;
|
|
1062
|
+
"""
|
|
1063
|
+
rows = self.query(query, (sint64_run_id, 0, after_timestamp))
|
|
1064
|
+
rows.sort(key=lambda x: x["timestamp"])
|
|
1065
|
+
latest_timestamp = rows[-1]["timestamp"] if rows else 0.0
|
|
1066
|
+
return "".join(row["log"] for row in rows), latest_timestamp
|
|
1067
|
+
|
|
1018
1068
|
def get_valid_task_ins(self, task_id: str) -> Optional[dict[str, Any]]:
|
|
1019
1069
|
"""Check if the TaskIns exists and is valid (not expired).
|
|
1020
1070
|
|
|
@@ -421,7 +421,8 @@ def _main_loop(
|
|
|
421
421
|
server_app_run_config = {}
|
|
422
422
|
|
|
423
423
|
# Initialize Driver
|
|
424
|
-
driver = InMemoryDriver(
|
|
424
|
+
driver = InMemoryDriver(state_factory=state_factory)
|
|
425
|
+
driver.init_run(run_id=run.run_id)
|
|
425
426
|
|
|
426
427
|
# Get and run ServerApp thread
|
|
427
428
|
serverapp_th = run_serverapp_th(
|
flwr/superexec/deployment.py
CHANGED
|
@@ -15,22 +15,21 @@
|
|
|
15
15
|
"""Deployment engine executor."""
|
|
16
16
|
|
|
17
17
|
import hashlib
|
|
18
|
-
import subprocess
|
|
19
18
|
from logging import ERROR, INFO
|
|
20
19
|
from pathlib import Path
|
|
21
20
|
from typing import Optional
|
|
22
21
|
|
|
23
22
|
from typing_extensions import override
|
|
24
23
|
|
|
25
|
-
from flwr.
|
|
26
|
-
from flwr.common.constant import DRIVER_API_DEFAULT_ADDRESS
|
|
24
|
+
from flwr.common import Context, RecordSet
|
|
25
|
+
from flwr.common.constant import DRIVER_API_DEFAULT_ADDRESS, Status, SubStatus
|
|
27
26
|
from flwr.common.logger import log
|
|
28
|
-
from flwr.common.typing import Fab, UserConfig
|
|
27
|
+
from flwr.common.typing import Fab, RunStatus, UserConfig
|
|
29
28
|
from flwr.server.superlink.ffs import Ffs
|
|
30
29
|
from flwr.server.superlink.ffs.ffs_factory import FfsFactory
|
|
31
30
|
from flwr.server.superlink.linkstate import LinkState, LinkStateFactory
|
|
32
31
|
|
|
33
|
-
from .executor import Executor
|
|
32
|
+
from .executor import Executor
|
|
34
33
|
|
|
35
34
|
|
|
36
35
|
class DeploymentEngine(Executor):
|
|
@@ -137,58 +136,41 @@ class DeploymentEngine(Executor):
|
|
|
137
136
|
run_id = self.linkstate.create_run(None, None, fab_hash, override_config)
|
|
138
137
|
return run_id
|
|
139
138
|
|
|
139
|
+
def _create_context(self, run_id: int) -> None:
|
|
140
|
+
"""Register a Context for a Run."""
|
|
141
|
+
# Create an empty context for the Run
|
|
142
|
+
context = Context(node_id=0, node_config={}, state=RecordSet(), run_config={})
|
|
143
|
+
|
|
144
|
+
# Register the context at the LinkState
|
|
145
|
+
self.linkstate.set_serverapp_context(run_id=run_id, context=context)
|
|
146
|
+
|
|
140
147
|
@override
|
|
141
148
|
def start_run(
|
|
142
149
|
self,
|
|
143
150
|
fab_file: bytes,
|
|
144
151
|
override_config: UserConfig,
|
|
145
152
|
federation_config: UserConfig,
|
|
146
|
-
) -> Optional[
|
|
153
|
+
) -> Optional[int]:
|
|
147
154
|
"""Start run using the Flower Deployment Engine."""
|
|
155
|
+
run_id = None
|
|
148
156
|
try:
|
|
149
|
-
# Install FAB to flwr dir
|
|
150
|
-
install_from_fab(fab_file, None, True)
|
|
151
157
|
|
|
152
158
|
# Call SuperLink to create run
|
|
153
|
-
run_id
|
|
159
|
+
run_id = self._create_run(
|
|
154
160
|
Fab(hashlib.sha256(fab_file).hexdigest(), fab_file), override_config
|
|
155
161
|
)
|
|
156
|
-
log(INFO, "Created run %s", str(run_id))
|
|
157
162
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
str(run_id),
|
|
162
|
-
"--superlink",
|
|
163
|
-
str(self.superlink),
|
|
164
|
-
]
|
|
165
|
-
|
|
166
|
-
if self.flwr_dir:
|
|
167
|
-
command.append("--flwr-dir")
|
|
168
|
-
command.append(self.flwr_dir)
|
|
169
|
-
|
|
170
|
-
if self.root_certificates is None:
|
|
171
|
-
command.append("--insecure")
|
|
172
|
-
else:
|
|
173
|
-
command.append("--root-certificates")
|
|
174
|
-
command.append(self.root_certificates)
|
|
175
|
-
|
|
176
|
-
# Execute the command
|
|
177
|
-
proc = subprocess.Popen( # pylint: disable=consider-using-with
|
|
178
|
-
command,
|
|
179
|
-
stdout=subprocess.PIPE,
|
|
180
|
-
stderr=subprocess.PIPE,
|
|
181
|
-
text=True,
|
|
182
|
-
)
|
|
183
|
-
log(INFO, "Started run %s", str(run_id))
|
|
163
|
+
# Register context for the Run
|
|
164
|
+
self._create_context(run_id=run_id)
|
|
165
|
+
log(INFO, "Created run %s", str(run_id))
|
|
184
166
|
|
|
185
|
-
return
|
|
186
|
-
run_id=run_id,
|
|
187
|
-
proc=proc,
|
|
188
|
-
)
|
|
167
|
+
return run_id
|
|
189
168
|
# pylint: disable-next=broad-except
|
|
190
169
|
except Exception as e:
|
|
191
170
|
log(ERROR, "Could not start run: %s", str(e))
|
|
171
|
+
if run_id:
|
|
172
|
+
run_status = RunStatus(Status.FINISHED, SubStatus.FAILED, str(e))
|
|
173
|
+
self.linkstate.update_run_status(run_id, new_status=run_status)
|
|
192
174
|
return None
|
|
193
175
|
|
|
194
176
|
|
flwr/superexec/exec_servicer.py
CHANGED
|
@@ -15,9 +15,6 @@
|
|
|
15
15
|
"""SuperExec API servicer."""
|
|
16
16
|
|
|
17
17
|
|
|
18
|
-
import select
|
|
19
|
-
import sys
|
|
20
|
-
import threading
|
|
21
18
|
import time
|
|
22
19
|
from collections.abc import Generator
|
|
23
20
|
from logging import ERROR, INFO
|
|
@@ -25,6 +22,7 @@ from typing import Any
|
|
|
25
22
|
|
|
26
23
|
import grpc
|
|
27
24
|
|
|
25
|
+
from flwr.common.constant import LOG_STREAM_INTERVAL, Status
|
|
28
26
|
from flwr.common.logger import log
|
|
29
27
|
from flwr.common.serde import user_config_from_proto
|
|
30
28
|
from flwr.proto import exec_pb2_grpc # pylint: disable=E0611
|
|
@@ -37,9 +35,7 @@ from flwr.proto.exec_pb2 import ( # pylint: disable=E0611
|
|
|
37
35
|
from flwr.server.superlink.ffs.ffs_factory import FfsFactory
|
|
38
36
|
from flwr.server.superlink.linkstate import LinkStateFactory
|
|
39
37
|
|
|
40
|
-
from .executor import Executor
|
|
41
|
-
|
|
42
|
-
SELECT_TIMEOUT = 1 # Timeout for selecting ready-to-read file descriptors (in seconds)
|
|
38
|
+
from .executor import Executor
|
|
43
39
|
|
|
44
40
|
|
|
45
41
|
class ExecServicer(exec_pb2_grpc.ExecServicer):
|
|
@@ -55,7 +51,6 @@ class ExecServicer(exec_pb2_grpc.ExecServicer):
|
|
|
55
51
|
self.ffs_factory = ffs_factory
|
|
56
52
|
self.executor = executor
|
|
57
53
|
self.executor.initialize(linkstate_factory, ffs_factory)
|
|
58
|
-
self.runs: dict[int, RunTracker] = {}
|
|
59
54
|
|
|
60
55
|
def StartRun(
|
|
61
56
|
self, request: StartRunRequest, context: grpc.ServicerContext
|
|
@@ -63,84 +58,50 @@ class ExecServicer(exec_pb2_grpc.ExecServicer):
|
|
|
63
58
|
"""Create run ID."""
|
|
64
59
|
log(INFO, "ExecServicer.StartRun")
|
|
65
60
|
|
|
66
|
-
|
|
61
|
+
run_id = self.executor.start_run(
|
|
67
62
|
request.fab.content,
|
|
68
63
|
user_config_from_proto(request.override_config),
|
|
69
64
|
user_config_from_proto(request.federation_config),
|
|
70
65
|
)
|
|
71
66
|
|
|
72
|
-
if
|
|
67
|
+
if run_id is None:
|
|
73
68
|
log(ERROR, "Executor failed to start run")
|
|
74
69
|
return StartRunResponse()
|
|
75
70
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
# Start a background thread to capture the log output
|
|
79
|
-
capture_thread = threading.Thread(
|
|
80
|
-
target=_capture_logs, args=(run,), daemon=True
|
|
81
|
-
)
|
|
82
|
-
capture_thread.start()
|
|
83
|
-
|
|
84
|
-
return StartRunResponse(run_id=run.run_id)
|
|
71
|
+
return StartRunResponse(run_id=run_id)
|
|
85
72
|
|
|
86
73
|
def StreamLogs( # pylint: disable=C0103
|
|
87
74
|
self, request: StreamLogsRequest, context: grpc.ServicerContext
|
|
88
75
|
) -> Generator[StreamLogsResponse, Any, None]:
|
|
89
76
|
"""Get logs."""
|
|
90
77
|
log(INFO, "ExecServicer.StreamLogs")
|
|
78
|
+
state = self.linkstate_factory.state()
|
|
79
|
+
|
|
80
|
+
# Retrieve run ID
|
|
81
|
+
run_id = request.run_id
|
|
91
82
|
|
|
92
83
|
# Exit if `run_id` not found
|
|
93
|
-
if
|
|
84
|
+
if not state.get_run(run_id):
|
|
94
85
|
context.abort(grpc.StatusCode.NOT_FOUND, "Run ID not found")
|
|
95
86
|
|
|
96
|
-
|
|
87
|
+
after_timestamp = request.after_timestamp + 1e-6
|
|
97
88
|
while context.is_active():
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
89
|
+
log_msg, latest_timestamp = state.get_serverapp_log(run_id, after_timestamp)
|
|
90
|
+
if log_msg:
|
|
91
|
+
yield StreamLogsResponse(
|
|
92
|
+
log_output=log_msg,
|
|
93
|
+
latest_timestamp=latest_timestamp,
|
|
94
|
+
)
|
|
95
|
+
# Add a small epsilon to the latest timestamp to avoid getting
|
|
96
|
+
# the same log
|
|
97
|
+
after_timestamp = max(latest_timestamp + 1e-6, after_timestamp)
|
|
103
98
|
|
|
104
99
|
# Wait for and continue to yield more log responses only if the
|
|
105
100
|
# run isn't completed yet. If the run is finished, the entire log
|
|
106
101
|
# is returned at this point and the server ends the stream.
|
|
107
|
-
|
|
102
|
+
run_status = state.get_run_status({run_id})[run_id]
|
|
103
|
+
if run_status.status == Status.FINISHED:
|
|
108
104
|
log(INFO, "All logs for run ID `%s` returned", request.run_id)
|
|
109
|
-
context.set_code(grpc.StatusCode.OK)
|
|
110
105
|
context.cancel()
|
|
111
106
|
|
|
112
|
-
time.sleep(
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
def _capture_logs(
|
|
116
|
-
run: RunTracker,
|
|
117
|
-
) -> None:
|
|
118
|
-
while True:
|
|
119
|
-
# Explicitly check if Popen.poll() is None. Required for `pytest`.
|
|
120
|
-
if run.proc.poll() is None:
|
|
121
|
-
# Select streams only when ready to read
|
|
122
|
-
ready_to_read, _, _ = select.select(
|
|
123
|
-
[run.proc.stdout, run.proc.stderr],
|
|
124
|
-
[],
|
|
125
|
-
[],
|
|
126
|
-
SELECT_TIMEOUT,
|
|
127
|
-
)
|
|
128
|
-
# Read from std* and append to RunTracker.logs
|
|
129
|
-
for stream in ready_to_read:
|
|
130
|
-
# Flush stdout to view output in real time
|
|
131
|
-
readline = stream.readline()
|
|
132
|
-
sys.stdout.write(readline)
|
|
133
|
-
sys.stdout.flush()
|
|
134
|
-
# Append to logs
|
|
135
|
-
line = readline.rstrip()
|
|
136
|
-
if line:
|
|
137
|
-
run.logs.append(f"{line}")
|
|
138
|
-
|
|
139
|
-
# Close std* to prevent blocking
|
|
140
|
-
elif run.proc.poll() is not None:
|
|
141
|
-
log(INFO, "Subprocess finished, exiting log capture")
|
|
142
|
-
if run.proc.stdout:
|
|
143
|
-
run.proc.stdout.close()
|
|
144
|
-
if run.proc.stderr:
|
|
145
|
-
run.proc.stderr.close()
|
|
146
|
-
break
|
|
107
|
+
time.sleep(LOG_STREAM_INTERVAL) # Sleep briefly to avoid busy waiting
|
flwr/superexec/executor.py
CHANGED
|
@@ -72,7 +72,7 @@ class Executor(ABC):
|
|
|
72
72
|
fab_file: bytes,
|
|
73
73
|
override_config: UserConfig,
|
|
74
74
|
federation_config: UserConfig,
|
|
75
|
-
) -> Optional[
|
|
75
|
+
) -> Optional[int]:
|
|
76
76
|
"""Start a run using the given Flower FAB ID and version.
|
|
77
77
|
|
|
78
78
|
This method creates a new run on the SuperLink, returns its run_id
|
|
@@ -89,7 +89,6 @@ class Executor(ABC):
|
|
|
89
89
|
|
|
90
90
|
Returns
|
|
91
91
|
-------
|
|
92
|
-
run_id : Optional[
|
|
93
|
-
The run_id
|
|
94
|
-
or `None` if it fails.
|
|
92
|
+
run_id : Optional[int]
|
|
93
|
+
The run_id of the run created by the SuperLink, or `None` if it fails.
|
|
95
94
|
"""
|
flwr/superexec/simulation.py
CHANGED
|
@@ -33,7 +33,7 @@ from flwr.server.superlink.ffs.ffs_factory import FfsFactory
|
|
|
33
33
|
from flwr.server.superlink.linkstate import LinkStateFactory
|
|
34
34
|
from flwr.server.superlink.linkstate.utils import generate_rand_int_from_bytes
|
|
35
35
|
|
|
36
|
-
from .executor import Executor
|
|
36
|
+
from .executor import Executor
|
|
37
37
|
|
|
38
38
|
|
|
39
39
|
def _user_config_to_str(user_config: UserConfig) -> str:
|
|
@@ -125,7 +125,7 @@ class SimulationEngine(Executor):
|
|
|
125
125
|
fab_file: bytes,
|
|
126
126
|
override_config: UserConfig,
|
|
127
127
|
federation_config: UserConfig,
|
|
128
|
-
) -> Optional[
|
|
128
|
+
) -> Optional[int]:
|
|
129
129
|
"""Start run using the Flower Simulation Engine."""
|
|
130
130
|
if self.num_supernodes is None:
|
|
131
131
|
raise ValueError(
|
|
@@ -199,17 +199,14 @@ class SimulationEngine(Executor):
|
|
|
199
199
|
command.extend(["--run-config", f"{override_config_str}"])
|
|
200
200
|
|
|
201
201
|
# Start Simulation
|
|
202
|
-
|
|
202
|
+
_ = subprocess.Popen( # pylint: disable=consider-using-with
|
|
203
203
|
command,
|
|
204
204
|
text=True,
|
|
205
205
|
)
|
|
206
206
|
|
|
207
207
|
log(INFO, "Started run %s", str(run_id))
|
|
208
208
|
|
|
209
|
-
return
|
|
210
|
-
run_id=run_id,
|
|
211
|
-
proc=proc,
|
|
212
|
-
)
|
|
209
|
+
return run_id
|
|
213
210
|
|
|
214
211
|
# pylint: disable-next=broad-except
|
|
215
212
|
except Exception as e:
|
{flwr_nightly-1.13.0.dev20241028.dist-info → flwr_nightly-1.13.0.dev20241030.dist-info}/RECORD
RENAMED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
flwr/__init__.py,sha256=VmBWedrCxqmt4QvUHBLqyVEH6p7zaFMD_oCHerXHSVw,937
|
|
2
2
|
flwr/cli/__init__.py,sha256=cZJVgozlkC6Ni2Hd_FAIrqefrkCGOV18fikToq-6iLw,720
|
|
3
3
|
flwr/cli/app.py,sha256=_HDs7HS12Dp7NXIyVrkPs1SKJq3x-XvVZd6y1lvyud4,1255
|
|
4
|
-
flwr/cli/build.py,sha256=
|
|
4
|
+
flwr/cli/build.py,sha256=k2M0aIY2q5WB_yXQ22Woxt1zb6m-Z1wNwmhWMxEm5Dw,6344
|
|
5
5
|
flwr/cli/config_utils.py,sha256=U0tYiC4uwT68LzXFpiiu6XzzplEo-43BR_ON9t3aHOw,7956
|
|
6
6
|
flwr/cli/example.py,sha256=1bGDYll3BXQY2kRqSN-oICqS5n1b9m0g0RvXTopXHl4,2215
|
|
7
7
|
flwr/cli/install.py,sha256=7Dx8zrn49mTktxGOToBhGx8hzsHOViDasMJ43ooKPXc,8646
|
|
8
|
-
flwr/cli/log.py,sha256=
|
|
8
|
+
flwr/cli/log.py,sha256=SaHqtqI0xKRxt25s-ocQkKxhvXoLGkrsnXff3BBFPMI,9003
|
|
9
9
|
flwr/cli/new/__init__.py,sha256=cQzK1WH4JP2awef1t2UQ2xjl1agVEz9rwutV18SWV1k,789
|
|
10
10
|
flwr/cli/new/new.py,sha256=uSiG7aXQzPDnikv2YcjQ86OOLqint0hNWCI0fSQD0jI,9634
|
|
11
11
|
flwr/cli/new/templates/__init__.py,sha256=4luU8RL-CK8JJCstQ_ON809W9bNTkY1l9zSaPKBkgwY,725
|
|
@@ -102,15 +102,15 @@ flwr/client/typing.py,sha256=dxoTBnTMfqXr5J7G3y-uNjqxYCddvxhu89spfj4Lm2U,1048
|
|
|
102
102
|
flwr/common/__init__.py,sha256=TVaoFEJE158aui1TPZQiJCDZX4RNHRyI8I55VC80HhI,3901
|
|
103
103
|
flwr/common/address.py,sha256=7kM2Rqjw86-c8aKwAvrXerWqznnVv4TFJ62aSAeTn10,3017
|
|
104
104
|
flwr/common/config.py,sha256=nYA1vjiiqSWx5JjSdlQd1i_0N_Dh9kEGUse1Qze3JMs,7803
|
|
105
|
-
flwr/common/constant.py,sha256=
|
|
105
|
+
flwr/common/constant.py,sha256=jWAHR2SRW_XJQ7ZMumFL54gSlo6Jp_sr1ndI5ebQNnI,4701
|
|
106
106
|
flwr/common/context.py,sha256=5Bd9RCrhLkYZOVR7vr97OVhzVBHQkS1fUsYiIKTwpxU,2239
|
|
107
|
-
flwr/common/date.py,sha256=
|
|
107
|
+
flwr/common/date.py,sha256=uTvLmCkd3uVQuD4MviPHnIXMGyheL16mEI_UlOsv_R8,894
|
|
108
108
|
flwr/common/differential_privacy.py,sha256=XwcJ3rWr8S8BZUocc76vLSJAXIf6OHnWkBV6-xlIRuw,6106
|
|
109
109
|
flwr/common/differential_privacy_constants.py,sha256=c7b7tqgvT7yMK0XN9ndiTBs4mQf6d3qk6K7KBZGlV4Q,1074
|
|
110
110
|
flwr/common/dp.py,sha256=vddkvyjV2FhRoN4VuU2LeAM1UBn7dQB8_W-Qdiveal8,1978
|
|
111
111
|
flwr/common/exit_handlers.py,sha256=MracJaBeoCOC7TaXK9zCJQxhrMSx9ZtczK237qvhBpU,2806
|
|
112
112
|
flwr/common/grpc.py,sha256=6Yi28JjAll19nxYJlOT9B03RN8dvJZP9zUoR3RSmxoY,2487
|
|
113
|
-
flwr/common/logger.py,sha256=
|
|
113
|
+
flwr/common/logger.py,sha256=F5mfXVuxo0qfYIcWpxTkwkOeyhpUZ7oeDS9CUHxCibg,11045
|
|
114
114
|
flwr/common/message.py,sha256=4O1m0OWXBAYZz05gKgEtnoJ94J1gjo7hCNHyUXThxRo,13831
|
|
115
115
|
flwr/common/object_ref.py,sha256=5lgWqYaJR28UdFc-iirWw9YqFXMfgkOOAdfJc1AVibE,8711
|
|
116
116
|
flwr/common/parameter.py,sha256=-bFAUayToYDF50FZGrBC1hQYJCQDtB2bbr3ZuVLMtdE,2095
|
|
@@ -132,7 +132,7 @@ flwr/common/secure_aggregation/ndarrays_arithmetic.py,sha256=zvVAIrIyI6OSzGhpCi8
|
|
|
132
132
|
flwr/common/secure_aggregation/quantization.py,sha256=mC4uLf05zeONo8Ke-BY0Tj8UCMOS7VD93zHCzuv3MHU,2304
|
|
133
133
|
flwr/common/secure_aggregation/secaggplus_constants.py,sha256=9MF-oQh62uD7rt9VeNB-rHf2gBLd5GL3S9OejCxmILY,2183
|
|
134
134
|
flwr/common/secure_aggregation/secaggplus_utils.py,sha256=o7IhHH6J9xqinhQy3TdPgQpoj1XyEpyv3OQFyx81RVQ,3193
|
|
135
|
-
flwr/common/serde.py,sha256=
|
|
135
|
+
flwr/common/serde.py,sha256=ZNPGTjxmIyRMPskpIy3VVYgjckeix0jzDEc1PtVSgLo,30562
|
|
136
136
|
flwr/common/telemetry.py,sha256=PvdlipCPYciqEgmXRwQ1HklP1uyECcNqt9HTBzthmAg,8904
|
|
137
137
|
flwr/common/typing.py,sha256=fS_KmVdg0c1B87yMnccIPfjBzQ3CTRwYJcaWfmvZzEA,5103
|
|
138
138
|
flwr/common/version.py,sha256=tCcl_FvxVK206C1dxIJCs4TjL06WmyaODBP19FRHE1c,1324
|
|
@@ -149,16 +149,16 @@ flwr/proto/control_pb2.py,sha256=yaUkwY2J9uo-fdUIB5aHwVSDOuGunxaUr4ZlggifA_M,143
|
|
|
149
149
|
flwr/proto/control_pb2.pyi,sha256=XbFvpZvvrS7QcH5AFXfpRGl4hQvhd3QdKO6x0oTlCCU,165
|
|
150
150
|
flwr/proto/control_pb2_grpc.py,sha256=FFE21nZvEILWpe1WCR5vAwgYEtpzrdG78-_SsU0gZ7w,5783
|
|
151
151
|
flwr/proto/control_pb2_grpc.pyi,sha256=9DU4sgkzJ497a4Nq6kitZWEG4g_5MO8MevichnO0oAg,1672
|
|
152
|
-
flwr/proto/driver_pb2.py,sha256=
|
|
153
|
-
flwr/proto/driver_pb2.pyi,sha256=
|
|
154
|
-
flwr/proto/driver_pb2_grpc.py,sha256=
|
|
155
|
-
flwr/proto/driver_pb2_grpc.pyi,sha256=
|
|
152
|
+
flwr/proto/driver_pb2.py,sha256=2BEQT2YloRBX1-5Gp_rjKBiUD3SY7sr_ic6y0MGlsRk,4795
|
|
153
|
+
flwr/proto/driver_pb2.pyi,sha256=Ib9c32FCtjA9zZY54Ohi6B-DtLgSjokAqOExm_2uOvY,6429
|
|
154
|
+
flwr/proto/driver_pb2_grpc.py,sha256=UgZ2PrrBmff-mwH1FG3Zf1YPYLoZVMldEBMUesjC-IQ,17154
|
|
155
|
+
flwr/proto/driver_pb2_grpc.pyi,sha256=1yVGhlZFwR-o1hrGFJptMBrEpdjc_MYpD14oEWDqib8,4654
|
|
156
156
|
flwr/proto/error_pb2.py,sha256=LarjKL90LbwkXKlhzNrDssgl4DXcvIPve8NVCXHpsKA,1084
|
|
157
157
|
flwr/proto/error_pb2.pyi,sha256=ZNH4HhJTU_KfMXlyCeg8FwU-fcUYxTqEmoJPtWtHikc,734
|
|
158
158
|
flwr/proto/error_pb2_grpc.py,sha256=1oboBPFxaTEXt9Aw7EAj8gXHDCNMhZD2VXqocC9l_gk,159
|
|
159
159
|
flwr/proto/error_pb2_grpc.pyi,sha256=ff2TSiLVnG6IVQcTGzb2DIH3XRSoAvAo_RMcvbMFyc0,76
|
|
160
|
-
flwr/proto/exec_pb2.py,sha256=
|
|
161
|
-
flwr/proto/exec_pb2.pyi,sha256=
|
|
160
|
+
flwr/proto/exec_pb2.py,sha256=jrPfFdZrT7L6kI-MGu6Ej2rYpd8sgen27bm6njrTrrk,3335
|
|
161
|
+
flwr/proto/exec_pb2.pyi,sha256=rvf6cp7YXGQiltzjhd7ZeZmyAeHexDKTp_5kyavZYsA,4612
|
|
162
162
|
flwr/proto/exec_pb2_grpc.py,sha256=faAN19XEMP8GTKrcIU6jvlWkN44n2KiUsZh_OG0sYcg,4072
|
|
163
163
|
flwr/proto/exec_pb2_grpc.pyi,sha256=VrFhT1Um3Nb8UC2YqnR9GIiM-Yyx0FqaxVOWljh-G_w,1208
|
|
164
164
|
flwr/proto/fab_pb2.py,sha256=3QSDq9pjbZoqVxsmCRDwHO5PrSjzn2vixjYxE-qPmb0,1589
|
|
@@ -173,6 +173,10 @@ flwr/proto/grpcadapter_pb2.py,sha256=bb8mW09XzNCpMdr1KuYQkefPFWR8lc8y1uL6Uk0TtsM
|
|
|
173
173
|
flwr/proto/grpcadapter_pb2.pyi,sha256=AR77gDsF6f8zqSIQp3877DUd7S8lP95lFak5Ir_WPkw,1716
|
|
174
174
|
flwr/proto/grpcadapter_pb2_grpc.py,sha256=rRNuNES5nBugUZWfeA8oAy8dMHgzqU_PF1srTseo3b8,2634
|
|
175
175
|
flwr/proto/grpcadapter_pb2_grpc.pyi,sha256=AgA9Qo_lnANb9SNuPzbZGAxupau-xcqYawZz6vqf-24,735
|
|
176
|
+
flwr/proto/log_pb2.py,sha256=0McrbU6ZlGLMEUAOhxmJvcVdEnptE2t4HsuzI_j77Sg,1393
|
|
177
|
+
flwr/proto/log_pb2.pyi,sha256=ipuhgo40sAHTcRzCsGI1HwIstr5q0THPNk_cf62YyME,1448
|
|
178
|
+
flwr/proto/log_pb2_grpc.py,sha256=1oboBPFxaTEXt9Aw7EAj8gXHDCNMhZD2VXqocC9l_gk,159
|
|
179
|
+
flwr/proto/log_pb2_grpc.pyi,sha256=ff2TSiLVnG6IVQcTGzb2DIH3XRSoAvAo_RMcvbMFyc0,76
|
|
176
180
|
flwr/proto/message_pb2.py,sha256=GW0ID-d2pvtgylsKxtINQx_oORgNGel3WJ3ybZcXxtI,3151
|
|
177
181
|
flwr/proto/message_pb2.pyi,sha256=_J9NjZa7Pr-kSO7-GGOL5EvIXQx5mQD04iVIvnVHBMU,5617
|
|
178
182
|
flwr/proto/message_pb2_grpc.py,sha256=1oboBPFxaTEXt9Aw7EAj8gXHDCNMhZD2VXqocC9l_gk,159
|
|
@@ -199,7 +203,7 @@ flwr/proto/transport_pb2_grpc.py,sha256=vLN3EHtx2aEEMCO4f1Upu-l27BPzd3-5pV-u8wPc
|
|
|
199
203
|
flwr/proto/transport_pb2_grpc.pyi,sha256=AGXf8RiIiW2J5IKMlm_3qT3AzcDa4F3P5IqUjve_esA,766
|
|
200
204
|
flwr/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
201
205
|
flwr/server/__init__.py,sha256=cEg1oecBu4cKB69iJCqWEylC8b5XW47bl7rQiJsdTvM,1528
|
|
202
|
-
flwr/server/app.py,sha256=
|
|
206
|
+
flwr/server/app.py,sha256=xt4o1Ls7BYEZ-R2Ro6_-zaBmv5yn2PtMH6p66mfZSmU,28222
|
|
203
207
|
flwr/server/client_manager.py,sha256=7Ese0tgrH-i-ms363feYZJKwB8gWnXSmg_hYF2Bju4U,6227
|
|
204
208
|
flwr/server/client_proxy.py,sha256=4G-oTwhb45sfWLx2uZdcXD98IZwdTS6F88xe3akCdUg,2399
|
|
205
209
|
flwr/server/compat/__init__.py,sha256=VxnJtJyOjNFQXMNi9hIuzNlZM5n0Hj1p3aq_Pm2udw4,892
|
|
@@ -209,16 +213,16 @@ flwr/server/compat/driver_client_proxy.py,sha256=Af0bRUEVZNcCYRxt3DjpLPdvVYpTgz6
|
|
|
209
213
|
flwr/server/compat/legacy_context.py,sha256=wBzBcfV6YO6IQGriM_FdJ5XZfiBBEEJdS_OdAiF47dY,1804
|
|
210
214
|
flwr/server/criterion.py,sha256=ypbAexbztzGUxNen9RCHF91QeqiEQix4t4Ih3E-42MM,1061
|
|
211
215
|
flwr/server/driver/__init__.py,sha256=bikRv6CjTwSvYh7tf10gziU5o2YotOWhhftz2tr3KDc,886
|
|
212
|
-
flwr/server/driver/driver.py,sha256=
|
|
213
|
-
flwr/server/driver/grpc_driver.py,sha256=
|
|
214
|
-
flwr/server/driver/inmemory_driver.py,sha256=
|
|
216
|
+
flwr/server/driver/driver.py,sha256=m8u4ZjtRmy1Cqg7SAld1trg9cd7E7O2IAnfsrJ97sXE,5697
|
|
217
|
+
flwr/server/driver/grpc_driver.py,sha256=cB9uL3JnMOBaObtwo0c60JH2slnoG2-Hsv9tZXpaeCI,9539
|
|
218
|
+
flwr/server/driver/inmemory_driver.py,sha256=kMNYmWWy2VOTDC_PnU-jKfVGrCqdeqp3-kwWiYkJGjo,6453
|
|
215
219
|
flwr/server/history.py,sha256=qSb5_pPTrwofpSYGsZWzMPkl_4uJ4mJFWesxXDrEvDU,5026
|
|
216
|
-
flwr/server/run_serverapp.py,sha256=
|
|
220
|
+
flwr/server/run_serverapp.py,sha256=QAeNzOpZPgHQqhCu2glwMSAE-TSu5Z0IQvldNETKA3w,10497
|
|
217
221
|
flwr/server/server.py,sha256=1ZsFEptmAV-L2vP2etNC9Ed5CLSxpuKzUFkAPQ4l5Xc,17893
|
|
218
222
|
flwr/server/server_app.py,sha256=RsgS6PRS5Z74cMUAHzsm8r3LWddwn00MjRs6rlacHt8,6297
|
|
219
223
|
flwr/server/server_config.py,sha256=CZaHVAsMvGLjpWVcLPkiYxgJN4xfIyAiUrCI3fETKY4,1349
|
|
220
224
|
flwr/server/serverapp/__init__.py,sha256=L0K-94UDdTyEZ8LDtYybGIIIv3HW6AhSVjXMUfYJQnQ,800
|
|
221
|
-
flwr/server/serverapp/app.py,sha256=
|
|
225
|
+
flwr/server/serverapp/app.py,sha256=bCCfNmUYME1NQGcX8mNsTiI6WTFNHeXDJ7vHx4nmXtE,8979
|
|
222
226
|
flwr/server/serverapp_components.py,sha256=-IV_CitOfrJclJj2jNdbN1Q65PyFmtKtrTIg1hc6WQw,2118
|
|
223
227
|
flwr/server/strategy/__init__.py,sha256=tQer2SwjDnvgFFuJMZM-S01Z615N5XK6MaCvpm4BMU0,2836
|
|
224
228
|
flwr/server/strategy/aggregate.py,sha256=iFZ8lp7PV_a2m9kywV-FK0iM33ofxavOs5TIaEQY8nU,13961
|
|
@@ -247,7 +251,7 @@ flwr/server/strategy/strategy.py,sha256=cXapkD5uDrt5C-RbmWDn9FLoap3Q41i7GKvbmfbC
|
|
|
247
251
|
flwr/server/superlink/__init__.py,sha256=8tHYCfodUlRD8PCP9fHgvu8cz5N31A2QoRVL0jDJ15E,707
|
|
248
252
|
flwr/server/superlink/driver/__init__.py,sha256=_JaRW-FdyikHc7souUrnk3mwTGViraEJCeUBY_M_ocs,712
|
|
249
253
|
flwr/server/superlink/driver/driver_grpc.py,sha256=melAgaV37Y0B9bZe5bRWQOobItZZ9DIzlcbVE8B01wo,2060
|
|
250
|
-
flwr/server/superlink/driver/driver_servicer.py,sha256=
|
|
254
|
+
flwr/server/superlink/driver/driver_servicer.py,sha256=n2De3kPaUwR9rFycWbpCp4mQILLshCNu9pUZW80_Ezc,10534
|
|
251
255
|
flwr/server/superlink/ffs/__init__.py,sha256=FAY-zShcfPmOxosok2QyT6hTNMNctG8cH9s_nIl8jkI,840
|
|
252
256
|
flwr/server/superlink/ffs/disk_ffs.py,sha256=yCN6CCzegnJIOaHr5nIu49wZQa4g5BByiSKshz50RKU,3296
|
|
253
257
|
flwr/server/superlink/ffs/ffs.py,sha256=qLI1UfosJugu2BKOJWqHIhafTm-YiuKqGf3OGWPH0NM,2395
|
|
@@ -273,10 +277,10 @@ flwr/server/superlink/fleet/vce/backend/backend.py,sha256=LBAQxnbfPAphVOVIvYMj0Q
|
|
|
273
277
|
flwr/server/superlink/fleet/vce/backend/raybackend.py,sha256=7kB3re3mR53b7E6L6DPSioTSKD3YGtS3uJsPD7Hn2Fw,7155
|
|
274
278
|
flwr/server/superlink/fleet/vce/vce_api.py,sha256=VL6e_Jwf4uxA-X1EelxJZMv6Eji-_p2J9D0MdHG10a4,13029
|
|
275
279
|
flwr/server/superlink/linkstate/__init__.py,sha256=v-2JyJlCB3qyhMNwMjmcNVOq4rkooqFU0LHH8Zo1jls,1064
|
|
276
|
-
flwr/server/superlink/linkstate/in_memory_linkstate.py,sha256=
|
|
277
|
-
flwr/server/superlink/linkstate/linkstate.py,sha256=
|
|
280
|
+
flwr/server/superlink/linkstate/in_memory_linkstate.py,sha256=zsolNnK3LPkk_b00hnA9kSmnQ71hS_BPpc7s7uG_tps,20599
|
|
281
|
+
flwr/server/superlink/linkstate/linkstate.py,sha256=fBaIBlQAc0oBu_AWSXlMmHAUHJ2YF1I79MS9wq7HvCs,11428
|
|
278
282
|
flwr/server/superlink/linkstate/linkstate_factory.py,sha256=ISSMjDlwuN7swxjOeYlTNpI_kuZ8PGkMcJnf1dbhUSE,2069
|
|
279
|
-
flwr/server/superlink/linkstate/sqlite_linkstate.py,sha256=
|
|
283
|
+
flwr/server/superlink/linkstate/sqlite_linkstate.py,sha256=Yda1uPiRkEmH7HDNwVtQnpzVjDAkGCJePutkjeyYyT4,43188
|
|
280
284
|
flwr/server/superlink/linkstate/utils.py,sha256=ukrMlSv0mNFd0YSpyPDpq_ND90SBkwuKgw3FFux3lqs,6914
|
|
281
285
|
flwr/server/typing.py,sha256=5kaRLZuxTEse9A0g7aVna2VhYxU3wTq1f3d3mtw7kXs,1019
|
|
282
286
|
flwr/server/utils/__init__.py,sha256=pltsPHJoXmUIr3utjwwYxu7_ZAGy5u4MVHzv9iA5Un8,908
|
|
@@ -294,16 +298,16 @@ flwr/simulation/ray_transport/__init__.py,sha256=wzcEEwUUlulnXsg6raCA1nGpP3LlAQD
|
|
|
294
298
|
flwr/simulation/ray_transport/ray_actor.py,sha256=9-XBguAm5IFqm2ddPFsQtnuuFN6lzqdb00SnCxGUGBo,18996
|
|
295
299
|
flwr/simulation/ray_transport/ray_client_proxy.py,sha256=2vjOKoom3B74C6XU-jC3N6DwYmsLdB-lmkHZ_Xrv96o,7367
|
|
296
300
|
flwr/simulation/ray_transport/utils.py,sha256=TYdtfg1P9VfTdLMOJlifInGpxWHYs9UfUqIv2wfkRLA,2392
|
|
297
|
-
flwr/simulation/run_simulation.py,sha256=
|
|
301
|
+
flwr/simulation/run_simulation.py,sha256=3n1nSik8tTC6LCYVZesNkHuXDQ1Ea4unTnNEOC5rdAc,23436
|
|
298
302
|
flwr/superexec/__init__.py,sha256=fcj366jh4RFby_vDwLroU4kepzqbnJgseZD_jUr_Mko,715
|
|
299
303
|
flwr/superexec/app.py,sha256=Tt3GonnTwHrMmicwx9XaP-crP78-bf4DUWl-N5cG6zY,1841
|
|
300
|
-
flwr/superexec/deployment.py,sha256=
|
|
304
|
+
flwr/superexec/deployment.py,sha256=jWEA8lnTYpOf8EHMzmoF9x6I_qh_gyJGQCVxk-DJshY,6401
|
|
301
305
|
flwr/superexec/exec_grpc.py,sha256=OuhBAk7hiky9rjGceinLGIXqchtzGPQThZnwyYv6Ei0,2241
|
|
302
|
-
flwr/superexec/exec_servicer.py,sha256=
|
|
303
|
-
flwr/superexec/executor.py,sha256=
|
|
304
|
-
flwr/superexec/simulation.py,sha256=
|
|
305
|
-
flwr_nightly-1.13.0.
|
|
306
|
-
flwr_nightly-1.13.0.
|
|
307
|
-
flwr_nightly-1.13.0.
|
|
308
|
-
flwr_nightly-1.13.0.
|
|
309
|
-
flwr_nightly-1.13.0.
|
|
306
|
+
flwr/superexec/exec_servicer.py,sha256=6dUCijBYhrntZeQj82q2kVOUNFu_tsFOwT5HkkLYn9Q,3927
|
|
307
|
+
flwr/superexec/executor.py,sha256=QA2_hQJxmN3zc75oEkDs-zkWAHesz59jE0P5lem-5VU,3073
|
|
308
|
+
flwr/superexec/simulation.py,sha256=Ny3MJnNlgzW4K3NbgsgDM0LKKcoCd_q3LqNqb0GhWLI,7640
|
|
309
|
+
flwr_nightly-1.13.0.dev20241030.dist-info/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
|
|
310
|
+
flwr_nightly-1.13.0.dev20241030.dist-info/METADATA,sha256=Uz_4aLDl_yW5l5At_04N_oqhAid1FC9yx7sxME_0uLY,15618
|
|
311
|
+
flwr_nightly-1.13.0.dev20241030.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
|
|
312
|
+
flwr_nightly-1.13.0.dev20241030.dist-info/entry_points.txt,sha256=FxJQ96pmcNF2OvkTH6XF-Ip2PNrHvykjArkvkjQC7Mk,486
|
|
313
|
+
flwr_nightly-1.13.0.dev20241030.dist-info/RECORD,,
|
{flwr_nightly-1.13.0.dev20241028.dist-info → flwr_nightly-1.13.0.dev20241030.dist-info}/LICENSE
RENAMED
|
File without changes
|
{flwr_nightly-1.13.0.dev20241028.dist-info → flwr_nightly-1.13.0.dev20241030.dist-info}/WHEEL
RENAMED
|
File without changes
|
|
File without changes
|