busylib 0.1.0__py3-none-any.whl → 0.3.0__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 busylib might be problematic. Click here for more details.
- busylib/client.py +56 -46
- busylib/types.py +7 -14
- {busylib-0.1.0.dist-info → busylib-0.3.0.dist-info}/METADATA +4 -4
- busylib-0.3.0.dist-info/RECORD +9 -0
- busylib-0.1.0.dist-info/RECORD +0 -9
- {busylib-0.1.0.dist-info → busylib-0.3.0.dist-info}/WHEEL +0 -0
- {busylib-0.1.0.dist-info → busylib-0.3.0.dist-info}/licenses/LICENSE +0 -0
- {busylib-0.1.0.dist-info → busylib-0.3.0.dist-info}/top_level.txt +0 -0
busylib/client.py
CHANGED
|
@@ -29,9 +29,24 @@ class BusyBar:
|
|
|
29
29
|
Main library class for interacting with the Busy Bar API.
|
|
30
30
|
"""
|
|
31
31
|
|
|
32
|
-
def __init__(
|
|
33
|
-
self
|
|
32
|
+
def __init__(
|
|
33
|
+
self,
|
|
34
|
+
addr: str | None = None,
|
|
35
|
+
*,
|
|
36
|
+
token: str | None = None,
|
|
37
|
+
) -> None:
|
|
38
|
+
if addr is None and token is None:
|
|
39
|
+
self.base_url = "http://10.0.4.20"
|
|
40
|
+
elif addr is None:
|
|
41
|
+
self.base_url = "https://proxy.dev.busy.app"
|
|
42
|
+
elif addr is not None:
|
|
43
|
+
if "://" not in addr:
|
|
44
|
+
addr = f"http://{addr}"
|
|
45
|
+
self.base_url = addr
|
|
46
|
+
|
|
34
47
|
self.client = requests.Session()
|
|
48
|
+
if token is not None:
|
|
49
|
+
self.client.headers["Authorization"] = f"Bearer {token}"
|
|
35
50
|
|
|
36
51
|
def __enter__(self):
|
|
37
52
|
return self
|
|
@@ -67,9 +82,7 @@ class BusyBar:
|
|
|
67
82
|
return response.text
|
|
68
83
|
|
|
69
84
|
def get_version(self) -> types.VersionInfo:
|
|
70
|
-
response = self.client.get(
|
|
71
|
-
urllib.parse.urljoin(self.base_url, "/api/v0/version")
|
|
72
|
-
)
|
|
85
|
+
response = self.client.get(urllib.parse.urljoin(self.base_url, "/api/version"))
|
|
73
86
|
data = self._handle_response(response)
|
|
74
87
|
return types.VersionInfo(**data)
|
|
75
88
|
|
|
@@ -81,7 +94,7 @@ class BusyBar:
|
|
|
81
94
|
params["name"] = name
|
|
82
95
|
|
|
83
96
|
response = self.client.post(
|
|
84
|
-
urllib.parse.urljoin(self.base_url, "/api/
|
|
97
|
+
urllib.parse.urljoin(self.base_url, "/api/update"),
|
|
85
98
|
params=params,
|
|
86
99
|
data=firmware_data,
|
|
87
100
|
headers={"Content-Type": "application/octet-stream"},
|
|
@@ -90,9 +103,7 @@ class BusyBar:
|
|
|
90
103
|
return types.SuccessResponse(**data)
|
|
91
104
|
|
|
92
105
|
def get_status(self) -> types.Status:
|
|
93
|
-
response = self.client.get(
|
|
94
|
-
urllib.parse.urljoin(self.base_url, "/api/v0/status")
|
|
95
|
-
)
|
|
106
|
+
response = self.client.get(urllib.parse.urljoin(self.base_url, "/api/status"))
|
|
96
107
|
data = self._handle_response(response)
|
|
97
108
|
|
|
98
109
|
system = None
|
|
@@ -112,14 +123,14 @@ class BusyBar:
|
|
|
112
123
|
|
|
113
124
|
def get_system_status(self) -> types.StatusSystem:
|
|
114
125
|
response = self.client.get(
|
|
115
|
-
urllib.parse.urljoin(self.base_url, "/api/
|
|
126
|
+
urllib.parse.urljoin(self.base_url, "/api/status/system")
|
|
116
127
|
)
|
|
117
128
|
data = self._handle_response(response)
|
|
118
129
|
return types.StatusSystem(**data)
|
|
119
130
|
|
|
120
131
|
def get_power_status(self) -> types.StatusPower:
|
|
121
132
|
response = self.client.get(
|
|
122
|
-
urllib.parse.urljoin(self.base_url, "/api/
|
|
133
|
+
urllib.parse.urljoin(self.base_url, "/api/status/power")
|
|
123
134
|
)
|
|
124
135
|
data = self._handle_response(response)
|
|
125
136
|
|
|
@@ -130,7 +141,7 @@ class BusyBar:
|
|
|
130
141
|
|
|
131
142
|
def write_storage_file(self, path: str, data: bytes) -> types.SuccessResponse:
|
|
132
143
|
response = self.client.post(
|
|
133
|
-
urllib.parse.urljoin(self.base_url, "/api/
|
|
144
|
+
urllib.parse.urljoin(self.base_url, "/api/storage/write"),
|
|
134
145
|
params={"path": path},
|
|
135
146
|
data=data,
|
|
136
147
|
headers={"Content-Type": "application/octet-stream"},
|
|
@@ -140,14 +151,14 @@ class BusyBar:
|
|
|
140
151
|
|
|
141
152
|
def read_storage_file(self, path: str) -> bytes:
|
|
142
153
|
response = self.client.get(
|
|
143
|
-
urllib.parse.urljoin(self.base_url, "/api/
|
|
154
|
+
urllib.parse.urljoin(self.base_url, "/api/storage/read"),
|
|
144
155
|
params={"path": path},
|
|
145
156
|
)
|
|
146
157
|
return self._handle_response(response, as_bytes=True)
|
|
147
158
|
|
|
148
159
|
def list_storage_files(self, path: str) -> types.StorageList:
|
|
149
160
|
response = self.client.get(
|
|
150
|
-
urllib.parse.urljoin(self.base_url, "/api/
|
|
161
|
+
urllib.parse.urljoin(self.base_url, "/api/storage/list"),
|
|
151
162
|
params={"path": path},
|
|
152
163
|
)
|
|
153
164
|
data = self._handle_response(response)
|
|
@@ -163,7 +174,7 @@ class BusyBar:
|
|
|
163
174
|
|
|
164
175
|
def remove_storage_file(self, path: str) -> types.SuccessResponse:
|
|
165
176
|
response = self.client.delete(
|
|
166
|
-
urllib.parse.urljoin(self.base_url, "/api/
|
|
177
|
+
urllib.parse.urljoin(self.base_url, "/api/storage/remove"),
|
|
167
178
|
params={"path": path},
|
|
168
179
|
)
|
|
169
180
|
data = self._handle_response(response)
|
|
@@ -171,7 +182,7 @@ class BusyBar:
|
|
|
171
182
|
|
|
172
183
|
def create_storage_directory(self, path: str) -> types.SuccessResponse:
|
|
173
184
|
response = self.client.post(
|
|
174
|
-
urllib.parse.urljoin(self.base_url, "/api/
|
|
185
|
+
urllib.parse.urljoin(self.base_url, "/api/storage/mkdir"),
|
|
175
186
|
params={"path": path},
|
|
176
187
|
)
|
|
177
188
|
data = self._handle_response(response)
|
|
@@ -181,7 +192,7 @@ class BusyBar:
|
|
|
181
192
|
self, app_id: str, filename: str, data: bytes
|
|
182
193
|
) -> types.SuccessResponse:
|
|
183
194
|
response = self.client.post(
|
|
184
|
-
urllib.parse.urljoin(self.base_url, "/api/
|
|
195
|
+
urllib.parse.urljoin(self.base_url, "/api/assets/upload"),
|
|
185
196
|
params={"app_id": app_id, "file": filename},
|
|
186
197
|
data=data,
|
|
187
198
|
headers={"Content-Type": "application/octet-stream"},
|
|
@@ -191,7 +202,7 @@ class BusyBar:
|
|
|
191
202
|
|
|
192
203
|
def delete_app_assets(self, app_id: str) -> types.SuccessResponse:
|
|
193
204
|
response = self.client.delete(
|
|
194
|
-
urllib.parse.urljoin(self.base_url, "/api/
|
|
205
|
+
urllib.parse.urljoin(self.base_url, "/api/assets/upload"),
|
|
195
206
|
params={"app_id": app_id},
|
|
196
207
|
)
|
|
197
208
|
data = self._handle_response(response)
|
|
@@ -201,7 +212,7 @@ class BusyBar:
|
|
|
201
212
|
self, display_data: types.DisplayElements
|
|
202
213
|
) -> types.SuccessResponse:
|
|
203
214
|
response = self.client.post(
|
|
204
|
-
urllib.parse.urljoin(self.base_url, "/api/
|
|
215
|
+
urllib.parse.urljoin(self.base_url, "/api/display/draw"),
|
|
205
216
|
json=_serialize_for_json(display_data),
|
|
206
217
|
headers={"Content-Type": "application/json"},
|
|
207
218
|
)
|
|
@@ -210,14 +221,14 @@ class BusyBar:
|
|
|
210
221
|
|
|
211
222
|
def clear_display(self) -> types.SuccessResponse:
|
|
212
223
|
response = self.client.delete(
|
|
213
|
-
urllib.parse.urljoin(self.base_url, "/api/
|
|
224
|
+
urllib.parse.urljoin(self.base_url, "/api/display/draw")
|
|
214
225
|
)
|
|
215
226
|
data = self._handle_response(response)
|
|
216
227
|
return types.SuccessResponse(**data)
|
|
217
228
|
|
|
218
229
|
def get_display_brightness(self) -> types.DisplayBrightnessInfo:
|
|
219
230
|
response = self.client.get(
|
|
220
|
-
urllib.parse.urljoin(self.base_url, "/api/
|
|
231
|
+
urllib.parse.urljoin(self.base_url, "/api/display/brightness")
|
|
221
232
|
)
|
|
222
233
|
data = self._handle_response(response)
|
|
223
234
|
return types.DisplayBrightnessInfo(**data)
|
|
@@ -232,7 +243,7 @@ class BusyBar:
|
|
|
232
243
|
params["back"] = back
|
|
233
244
|
|
|
234
245
|
response = self.client.post(
|
|
235
|
-
urllib.parse.urljoin(self.base_url, "/api/
|
|
246
|
+
urllib.parse.urljoin(self.base_url, "/api/display/brightness"),
|
|
236
247
|
params=params,
|
|
237
248
|
)
|
|
238
249
|
data = self._handle_response(response)
|
|
@@ -240,7 +251,7 @@ class BusyBar:
|
|
|
240
251
|
|
|
241
252
|
def play_audio(self, app_id: str, path: str) -> types.SuccessResponse:
|
|
242
253
|
response = self.client.post(
|
|
243
|
-
urllib.parse.urljoin(self.base_url, "/api/
|
|
254
|
+
urllib.parse.urljoin(self.base_url, "/api/audio/play"),
|
|
244
255
|
params={"app_id": app_id, "path": path},
|
|
245
256
|
)
|
|
246
257
|
data = self._handle_response(response)
|
|
@@ -248,21 +259,21 @@ class BusyBar:
|
|
|
248
259
|
|
|
249
260
|
def stop_audio(self) -> types.SuccessResponse:
|
|
250
261
|
response = self.client.delete(
|
|
251
|
-
urllib.parse.urljoin(self.base_url, "/api/
|
|
262
|
+
urllib.parse.urljoin(self.base_url, "/api/audio/play")
|
|
252
263
|
)
|
|
253
264
|
data = self._handle_response(response)
|
|
254
265
|
return types.SuccessResponse(**data)
|
|
255
266
|
|
|
256
267
|
def get_audio_volume(self) -> types.AudioVolumeInfo:
|
|
257
268
|
response = self.client.get(
|
|
258
|
-
urllib.parse.urljoin(self.base_url, "/api/
|
|
269
|
+
urllib.parse.urljoin(self.base_url, "/api/audio/volume")
|
|
259
270
|
)
|
|
260
271
|
data = self._handle_response(response)
|
|
261
272
|
return types.AudioVolumeInfo(**data)
|
|
262
273
|
|
|
263
274
|
def set_audio_volume(self, volume: float) -> types.SuccessResponse:
|
|
264
275
|
response = self.client.post(
|
|
265
|
-
urllib.parse.urljoin(self.base_url, "/api/
|
|
276
|
+
urllib.parse.urljoin(self.base_url, "/api/audio/volume"),
|
|
266
277
|
params={"volume": volume},
|
|
267
278
|
)
|
|
268
279
|
data = self._handle_response(response)
|
|
@@ -270,29 +281,15 @@ class BusyBar:
|
|
|
270
281
|
|
|
271
282
|
def send_input_key(self, key: types.InputKey) -> types.SuccessResponse:
|
|
272
283
|
response = self.client.post(
|
|
273
|
-
urllib.parse.urljoin(self.base_url, "/api/
|
|
284
|
+
urllib.parse.urljoin(self.base_url, "/api/input"),
|
|
274
285
|
params={"key": key.value},
|
|
275
286
|
)
|
|
276
287
|
data = self._handle_response(response)
|
|
277
288
|
return types.SuccessResponse(**data)
|
|
278
289
|
|
|
279
|
-
def enable_wifi(self) -> types.SuccessResponse:
|
|
280
|
-
response = self.client.post(
|
|
281
|
-
urllib.parse.urljoin(self.base_url, "/api/v0/wifi/enable")
|
|
282
|
-
)
|
|
283
|
-
data = self._handle_response(response)
|
|
284
|
-
return types.SuccessResponse(**data)
|
|
285
|
-
|
|
286
|
-
def disable_wifi(self) -> types.SuccessResponse:
|
|
287
|
-
response = self.client.post(
|
|
288
|
-
urllib.parse.urljoin(self.base_url, "/api/v0/wifi/disable")
|
|
289
|
-
)
|
|
290
|
-
data = self._handle_response(response)
|
|
291
|
-
return types.SuccessResponse(**data)
|
|
292
|
-
|
|
293
290
|
def get_wifi_status(self) -> types.StatusResponse:
|
|
294
291
|
response = self.client.get(
|
|
295
|
-
urllib.parse.urljoin(self.base_url, "/api/
|
|
292
|
+
urllib.parse.urljoin(self.base_url, "/api/wifi/status")
|
|
296
293
|
)
|
|
297
294
|
data = self._handle_response(response)
|
|
298
295
|
|
|
@@ -316,7 +313,7 @@ class BusyBar:
|
|
|
316
313
|
|
|
317
314
|
def connect_wifi(self, config: types.ConnectRequestConfig) -> types.SuccessResponse:
|
|
318
315
|
response = self.client.post(
|
|
319
|
-
urllib.parse.urljoin(self.base_url, "/api/
|
|
316
|
+
urllib.parse.urljoin(self.base_url, "/api/wifi/connect"),
|
|
320
317
|
json=_serialize_for_json(config),
|
|
321
318
|
headers={"Content-Type": "application/json"},
|
|
322
319
|
)
|
|
@@ -325,14 +322,14 @@ class BusyBar:
|
|
|
325
322
|
|
|
326
323
|
def disconnect_wifi(self) -> types.SuccessResponse:
|
|
327
324
|
response = self.client.post(
|
|
328
|
-
urllib.parse.urljoin(self.base_url, "/api/
|
|
325
|
+
urllib.parse.urljoin(self.base_url, "/api/wifi/disconnect")
|
|
329
326
|
)
|
|
330
327
|
data = self._handle_response(response)
|
|
331
328
|
return types.SuccessResponse(**data)
|
|
332
329
|
|
|
333
330
|
def scan_wifi_networks(self) -> types.NetworkResponse:
|
|
334
331
|
response = self.client.get(
|
|
335
|
-
urllib.parse.urljoin(self.base_url, "/api/
|
|
332
|
+
urllib.parse.urljoin(self.base_url, "/api/wifi/networks")
|
|
336
333
|
)
|
|
337
334
|
data = self._handle_response(response)
|
|
338
335
|
|
|
@@ -353,7 +350,20 @@ class BusyBar:
|
|
|
353
350
|
|
|
354
351
|
def get_screen_frame(self, display: int) -> bytes:
|
|
355
352
|
response = self.client.get(
|
|
356
|
-
urllib.parse.urljoin(self.base_url, "/api/
|
|
353
|
+
urllib.parse.urljoin(self.base_url, "/api/screen"),
|
|
357
354
|
params={"display": display},
|
|
358
355
|
)
|
|
359
356
|
return self._handle_response(response, as_bytes=True)
|
|
357
|
+
def ble_enable(self) -> types.SuccessResponse:
|
|
358
|
+
response = self.client.post(
|
|
359
|
+
urllib.parse.urljoin(self.base_url, "/api/ble/enable")
|
|
360
|
+
)
|
|
361
|
+
data = self._handle_response(response)
|
|
362
|
+
return types.SuccessResponse(**data)
|
|
363
|
+
|
|
364
|
+
def ble_disable(self) -> types.SuccessResponse:
|
|
365
|
+
response = self.client.post(
|
|
366
|
+
urllib.parse.urljoin(self.base_url, "/api/ble/disable")
|
|
367
|
+
)
|
|
368
|
+
data = self._handle_response(response)
|
|
369
|
+
return types.SuccessResponse(**data)
|
busylib/types.py
CHANGED
|
@@ -2,19 +2,18 @@ import dataclasses
|
|
|
2
2
|
import enum
|
|
3
3
|
import typing as tp
|
|
4
4
|
|
|
5
|
+
class WifiState(enum.Enum):
|
|
6
|
+
DISCONNECTED = "disconnected"
|
|
7
|
+
CONNECTED = "connected"
|
|
5
8
|
|
|
6
9
|
class WifiSecurityMethod(enum.Enum):
|
|
7
10
|
OPEN = "Open"
|
|
8
11
|
WPA = "WPA"
|
|
9
12
|
WPA2 = "WPA2"
|
|
10
13
|
WEP = "WEP"
|
|
11
|
-
WPA_ENTERPRISE = "WPA (Enterprise)"
|
|
12
|
-
WPA2_ENTERPRISE = "WPA2 (Enterprise)"
|
|
13
14
|
WPA_WPA2 = "WPA/WPA2"
|
|
14
15
|
WPA3 = "WPA3"
|
|
15
16
|
WPA2_WPA3 = "WPA2/WPA3"
|
|
16
|
-
WPA3_ENTERPRISE = "WPA3 (Enterprise)"
|
|
17
|
-
WPA2_WPA3_ENTERPRISE = "WPA2/WPA3 (Enterprise)"
|
|
18
17
|
|
|
19
18
|
|
|
20
19
|
class WifiIpMethod(enum.Enum):
|
|
@@ -33,12 +32,6 @@ class PowerState(enum.Enum):
|
|
|
33
32
|
CHARGED = "charged"
|
|
34
33
|
|
|
35
34
|
|
|
36
|
-
class WifiState(enum.Enum):
|
|
37
|
-
DISABLED = "disabled"
|
|
38
|
-
ENABLED = "enabled"
|
|
39
|
-
CONNECTED = "connected"
|
|
40
|
-
|
|
41
|
-
|
|
42
35
|
class ElementType(enum.Enum):
|
|
43
36
|
FILE = "file"
|
|
44
37
|
DIR = "dir"
|
|
@@ -80,10 +73,7 @@ class Error:
|
|
|
80
73
|
|
|
81
74
|
@dataclasses.dataclass(frozen=True)
|
|
82
75
|
class VersionInfo:
|
|
83
|
-
|
|
84
|
-
version: str
|
|
85
|
-
build_date: str
|
|
86
|
-
commit_hash: str
|
|
76
|
+
api_semver: str
|
|
87
77
|
|
|
88
78
|
|
|
89
79
|
@dataclasses.dataclass(frozen=True)
|
|
@@ -190,6 +180,9 @@ class Network:
|
|
|
190
180
|
class StatusResponse:
|
|
191
181
|
state: WifiState | None = None
|
|
192
182
|
ssid: str | None = None
|
|
183
|
+
bssid: str | None = None
|
|
184
|
+
channel: int | None = None
|
|
185
|
+
rssi: int | None = None
|
|
193
186
|
security: WifiSecurityMethod | None = None
|
|
194
187
|
ip_config: WifiIpConfig | None = None
|
|
195
188
|
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: busylib
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: Python library for Busy Bar API
|
|
5
|
-
Author-email:
|
|
6
|
-
Project-URL: Homepage, https://github.com/busy-app/busylib
|
|
7
|
-
Project-URL: Repository, https://github.com/busy-app/busylib
|
|
5
|
+
Author-email: flipperdevices <pypi@flipperdevices.com>
|
|
6
|
+
Project-URL: Homepage, https://github.com/busy-app/busylib-py
|
|
7
|
+
Project-URL: Repository, https://github.com/busy-app/busylib-py
|
|
8
8
|
Project-URL: Documentation, https://busylib.readthedocs.io
|
|
9
9
|
Classifier: Development Status :: 3 - Alpha
|
|
10
10
|
Classifier: Intended Audience :: Developers
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
busylib/__init__.py,sha256=7CQFe1iS-QRVAVlufLarG0MXEjkbqZht_DI2kUvsHz0,28
|
|
2
|
+
busylib/client.py,sha256=9Xv_1wGSj4UL4GxN_DUsOoaoK3kMjyEI2x7vAZkTQKc,13078
|
|
3
|
+
busylib/exceptions.py,sha256=DHYoEXGdADXSxcgLq7BWqq_865J0LsMysZL-Wuip2wc,210
|
|
4
|
+
busylib/types.py,sha256=NRN5K-z86KhzREkO7AWtxGQqK067sQFTJ07CszBCZAQ,4063
|
|
5
|
+
busylib-0.3.0.dist-info/licenses/LICENSE,sha256=aJO9BQGuVb1fvGzHcgWYiwcC9kEFyD-FBb8SPO-ATJ4,1071
|
|
6
|
+
busylib-0.3.0.dist-info/METADATA,sha256=A22FG9UibubAY5BW5fRl0x4TdnpHCqaxp0O2niPd_EQ,5518
|
|
7
|
+
busylib-0.3.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
8
|
+
busylib-0.3.0.dist-info/top_level.txt,sha256=tXeqg2EVVj4E8-ywimkxRzuCJq2HqMXA0571IB15PDA,8
|
|
9
|
+
busylib-0.3.0.dist-info/RECORD,,
|
busylib-0.1.0.dist-info/RECORD
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
busylib/__init__.py,sha256=7CQFe1iS-QRVAVlufLarG0MXEjkbqZht_DI2kUvsHz0,28
|
|
2
|
-
busylib/client.py,sha256=l-gMVPP5X9m0IGqnjMjKPUo-olw4nf2cHvgz7DtdIjw,12746
|
|
3
|
-
busylib/exceptions.py,sha256=DHYoEXGdADXSxcgLq7BWqq_865J0LsMysZL-Wuip2wc,210
|
|
4
|
-
busylib/types.py,sha256=AGNd39jN5Rn5fI9kk5Ugk-4fr3JeXQpka2YEFeEWKNw,4223
|
|
5
|
-
busylib-0.1.0.dist-info/licenses/LICENSE,sha256=aJO9BQGuVb1fvGzHcgWYiwcC9kEFyD-FBb8SPO-ATJ4,1071
|
|
6
|
-
busylib-0.1.0.dist-info/METADATA,sha256=v8QccaMsA439sMQYg5hrQ9dAcDmIZKXuPHts6UnDIcc,5514
|
|
7
|
-
busylib-0.1.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
8
|
-
busylib-0.1.0.dist-info/top_level.txt,sha256=tXeqg2EVVj4E8-ywimkxRzuCJq2HqMXA0571IB15PDA,8
|
|
9
|
-
busylib-0.1.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|