accusleepy 0.3.1__tar.gz → 0.4.0__tar.gz
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.
- {accusleepy-0.3.1 → accusleepy-0.4.0}/PKG-INFO +2 -1
- {accusleepy-0.3.1 → accusleepy-0.4.0}/accusleepy/gui/main.py +30 -3
- {accusleepy-0.3.1 → accusleepy-0.4.0}/accusleepy/gui/manual_scoring.py +1 -1
- {accusleepy-0.3.1 → accusleepy-0.4.0}/accusleepy/gui/primary_window.py +81 -20
- {accusleepy-0.3.1 → accusleepy-0.4.0}/accusleepy/gui/primary_window.ui +162 -118
- {accusleepy-0.3.1 → accusleepy-0.4.0}/accusleepy/gui/text/config_guide.txt +2 -1
- {accusleepy-0.3.1 → accusleepy-0.4.0}/accusleepy/gui/text/main_guide_text.py +32 -8
- {accusleepy-0.3.1 → accusleepy-0.4.0}/pyproject.toml +2 -1
- {accusleepy-0.3.1 → accusleepy-0.4.0}/README.md +0 -0
- {accusleepy-0.3.1 → accusleepy-0.4.0}/accusleepy/__init__.py +0 -0
- {accusleepy-0.3.1 → accusleepy-0.4.0}/accusleepy/__main__.py +0 -0
- {accusleepy-0.3.1 → accusleepy-0.4.0}/accusleepy/brain_state_set.py +0 -0
- {accusleepy-0.3.1 → accusleepy-0.4.0}/accusleepy/classification.py +0 -0
- {accusleepy-0.3.1 → accusleepy-0.4.0}/accusleepy/config.json +0 -0
- {accusleepy-0.3.1 → accusleepy-0.4.0}/accusleepy/constants.py +0 -0
- {accusleepy-0.3.1 → accusleepy-0.4.0}/accusleepy/fileio.py +0 -0
- {accusleepy-0.3.1 → accusleepy-0.4.0}/accusleepy/gui/__init__.py +0 -0
- {accusleepy-0.3.1 → accusleepy-0.4.0}/accusleepy/gui/icons/brightness_down.png +0 -0
- {accusleepy-0.3.1 → accusleepy-0.4.0}/accusleepy/gui/icons/brightness_up.png +0 -0
- {accusleepy-0.3.1 → accusleepy-0.4.0}/accusleepy/gui/icons/double_down_arrow.png +0 -0
- {accusleepy-0.3.1 → accusleepy-0.4.0}/accusleepy/gui/icons/double_up_arrow.png +0 -0
- {accusleepy-0.3.1 → accusleepy-0.4.0}/accusleepy/gui/icons/down_arrow.png +0 -0
- {accusleepy-0.3.1 → accusleepy-0.4.0}/accusleepy/gui/icons/home.png +0 -0
- {accusleepy-0.3.1 → accusleepy-0.4.0}/accusleepy/gui/icons/question.png +0 -0
- {accusleepy-0.3.1 → accusleepy-0.4.0}/accusleepy/gui/icons/save.png +0 -0
- {accusleepy-0.3.1 → accusleepy-0.4.0}/accusleepy/gui/icons/up_arrow.png +0 -0
- {accusleepy-0.3.1 → accusleepy-0.4.0}/accusleepy/gui/icons/zoom_in.png +0 -0
- {accusleepy-0.3.1 → accusleepy-0.4.0}/accusleepy/gui/icons/zoom_out.png +0 -0
- {accusleepy-0.3.1 → accusleepy-0.4.0}/accusleepy/gui/mplwidget.py +0 -0
- {accusleepy-0.3.1 → accusleepy-0.4.0}/accusleepy/gui/resources.qrc +0 -0
- {accusleepy-0.3.1 → accusleepy-0.4.0}/accusleepy/gui/resources_rc.py +0 -0
- {accusleepy-0.3.1 → accusleepy-0.4.0}/accusleepy/gui/text/manual_scoring_guide.txt +0 -0
- {accusleepy-0.3.1 → accusleepy-0.4.0}/accusleepy/gui/viewer_window.py +0 -0
- {accusleepy-0.3.1 → accusleepy-0.4.0}/accusleepy/gui/viewer_window.ui +0 -0
- {accusleepy-0.3.1 → accusleepy-0.4.0}/accusleepy/models.py +0 -0
- {accusleepy-0.3.1 → accusleepy-0.4.0}/accusleepy/multitaper.py +0 -0
- {accusleepy-0.3.1 → accusleepy-0.4.0}/accusleepy/signal_processing.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: accusleepy
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: Python implementation of AccuSleep
|
|
5
5
|
License: GPL-3.0-only
|
|
6
6
|
Author: Zeke Barger
|
|
@@ -20,6 +20,7 @@ Requires-Dist: pillow (>=11.1.0,<12.0.0)
|
|
|
20
20
|
Requires-Dist: pre-commit (>=4.2.0,<5.0.0)
|
|
21
21
|
Requires-Dist: pyside6 (>=6.7.1,<6.8.0)
|
|
22
22
|
Requires-Dist: scipy (>=1.15.2,<2.0.0)
|
|
23
|
+
Requires-Dist: toml (>=0.10.2,<0.11.0)
|
|
23
24
|
Requires-Dist: torch (>=2.6.0,<3.0.0)
|
|
24
25
|
Requires-Dist: torchvision (>=0.21.0,<0.22.0)
|
|
25
26
|
Requires-Dist: tqdm (>=4.67.1,<5.0.0)
|
|
@@ -5,6 +5,7 @@ import datetime
|
|
|
5
5
|
import os
|
|
6
6
|
import shutil
|
|
7
7
|
import sys
|
|
8
|
+
import toml
|
|
8
9
|
from dataclasses import dataclass
|
|
9
10
|
from functools import partial
|
|
10
11
|
|
|
@@ -54,7 +55,7 @@ from accusleepy.signal_processing import (
|
|
|
54
55
|
MESSAGE_BOX_MAX_DEPTH = 50
|
|
55
56
|
LABEL_LENGTH_ERROR = "label file length does not match recording length"
|
|
56
57
|
# relative path to config guide txt file
|
|
57
|
-
CONFIG_GUIDE_FILE = "text/config_guide.txt"
|
|
58
|
+
CONFIG_GUIDE_FILE = os.path.normpath(r"text/config_guide.txt")
|
|
58
59
|
|
|
59
60
|
|
|
60
61
|
@dataclass
|
|
@@ -116,6 +117,20 @@ class AccuSleepWindow(QtWidgets.QMainWindow):
|
|
|
116
117
|
# messages to display
|
|
117
118
|
self.messages = []
|
|
118
119
|
|
|
120
|
+
# display current version
|
|
121
|
+
version = ""
|
|
122
|
+
toml_file = os.path.join(
|
|
123
|
+
os.path.dirname(
|
|
124
|
+
os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|
125
|
+
),
|
|
126
|
+
"pyproject.toml",
|
|
127
|
+
)
|
|
128
|
+
if os.path.isfile(toml_file):
|
|
129
|
+
toml_data = toml.load(toml_file)
|
|
130
|
+
if "project" in toml_data and "version" in toml_data["project"]:
|
|
131
|
+
version = toml_data["project"]["version"]
|
|
132
|
+
self.ui.version_label.setText(f"v{version}")
|
|
133
|
+
|
|
119
134
|
# user input: keyboard shortcuts
|
|
120
135
|
keypress_quit = QtGui.QShortcut(
|
|
121
136
|
QtGui.QKeySequence(
|
|
@@ -179,6 +194,7 @@ class AccuSleepWindow(QtWidgets.QMainWindow):
|
|
|
179
194
|
)
|
|
180
195
|
if not filename:
|
|
181
196
|
return
|
|
197
|
+
filename = os.path.normpath(filename)
|
|
182
198
|
save_recording_list(filename=filename, recordings=self.recordings)
|
|
183
199
|
self.show_message(f"Saved list of recordings to {filename}")
|
|
184
200
|
|
|
@@ -193,6 +209,7 @@ class AccuSleepWindow(QtWidgets.QMainWindow):
|
|
|
193
209
|
if file_dialog.exec():
|
|
194
210
|
selected_files = file_dialog.selectedFiles()
|
|
195
211
|
filename = selected_files[0]
|
|
212
|
+
filename = os.path.normpath(filename)
|
|
196
213
|
else:
|
|
197
214
|
return
|
|
198
215
|
|
|
@@ -229,7 +246,7 @@ class AccuSleepWindow(QtWidgets.QMainWindow):
|
|
|
229
246
|
if event.type() == QtCore.QEvent.Drop:
|
|
230
247
|
urls = event.mimeData().urls()
|
|
231
248
|
if len(urls) == 1:
|
|
232
|
-
filename = urls[0].toLocalFile()
|
|
249
|
+
filename = os.path.normpath(urls[0].toLocalFile())
|
|
233
250
|
|
|
234
251
|
if filename is None:
|
|
235
252
|
return super().eventFilter(obj, event)
|
|
@@ -289,6 +306,8 @@ class AccuSleepWindow(QtWidgets.QMainWindow):
|
|
|
289
306
|
)
|
|
290
307
|
if not model_filename:
|
|
291
308
|
self.show_message("Model training canceled, no filename given")
|
|
309
|
+
return
|
|
310
|
+
model_filename = os.path.normpath(model_filename)
|
|
292
311
|
|
|
293
312
|
# create (probably temporary) image folder
|
|
294
313
|
temp_image_dir = os.path.join(
|
|
@@ -363,6 +382,7 @@ class AccuSleepWindow(QtWidgets.QMainWindow):
|
|
|
363
382
|
self, "Select directory for training images"
|
|
364
383
|
)
|
|
365
384
|
if training_folder_parent:
|
|
385
|
+
training_folder_parent = os.path.normpath(training_folder_parent)
|
|
366
386
|
self.training_image_dir = training_folder_parent
|
|
367
387
|
self.ui.image_folder_label.setText(training_folder_parent)
|
|
368
388
|
|
|
@@ -560,6 +580,7 @@ class AccuSleepWindow(QtWidgets.QMainWindow):
|
|
|
560
580
|
if file_dialog.exec():
|
|
561
581
|
selected_files = file_dialog.selectedFiles()
|
|
562
582
|
filename = selected_files[0]
|
|
583
|
+
filename = os.path.normpath(filename)
|
|
563
584
|
else:
|
|
564
585
|
return
|
|
565
586
|
|
|
@@ -707,6 +728,7 @@ class AccuSleepWindow(QtWidgets.QMainWindow):
|
|
|
707
728
|
)
|
|
708
729
|
if not filename:
|
|
709
730
|
return
|
|
731
|
+
filename = os.path.normpath(filename)
|
|
710
732
|
|
|
711
733
|
create_calibration_file(
|
|
712
734
|
filename=filename,
|
|
@@ -871,6 +893,7 @@ class AccuSleepWindow(QtWidgets.QMainWindow):
|
|
|
871
893
|
filter="*" + LABEL_FILE_TYPE,
|
|
872
894
|
)
|
|
873
895
|
if filename:
|
|
896
|
+
filename = os.path.normpath(filename)
|
|
874
897
|
self.recordings[self.recording_index].label_file = filename
|
|
875
898
|
self.ui.label_file_label.setText(filename)
|
|
876
899
|
|
|
@@ -885,6 +908,7 @@ class AccuSleepWindow(QtWidgets.QMainWindow):
|
|
|
885
908
|
if file_dialog.exec():
|
|
886
909
|
selected_files = file_dialog.selectedFiles()
|
|
887
910
|
filename = selected_files[0]
|
|
911
|
+
filename = os.path.normpath(filename)
|
|
888
912
|
self.recordings[self.recording_index].label_file = filename
|
|
889
913
|
self.ui.label_file_label.setText(filename)
|
|
890
914
|
|
|
@@ -899,6 +923,7 @@ class AccuSleepWindow(QtWidgets.QMainWindow):
|
|
|
899
923
|
if file_dialog.exec():
|
|
900
924
|
selected_files = file_dialog.selectedFiles()
|
|
901
925
|
filename = selected_files[0]
|
|
926
|
+
filename = os.path.normpath(filename)
|
|
902
927
|
self.recordings[self.recording_index].calibration_file = filename
|
|
903
928
|
self.ui.calibration_file_label.setText(filename)
|
|
904
929
|
|
|
@@ -913,6 +938,7 @@ class AccuSleepWindow(QtWidgets.QMainWindow):
|
|
|
913
938
|
if file_dialog.exec():
|
|
914
939
|
selected_files = file_dialog.selectedFiles()
|
|
915
940
|
filename = selected_files[0]
|
|
941
|
+
filename = os.path.normpath(filename)
|
|
916
942
|
self.recordings[self.recording_index].recording_file = filename
|
|
917
943
|
self.ui.recording_file_label.setText(filename)
|
|
918
944
|
|
|
@@ -1252,7 +1278,7 @@ def check_label_validity(
|
|
|
1252
1278
|
sampling_rate: int | float,
|
|
1253
1279
|
epoch_length: int | float,
|
|
1254
1280
|
brain_state_set: BrainStateSet,
|
|
1255
|
-
) -> str:
|
|
1281
|
+
) -> str | None:
|
|
1256
1282
|
"""Check whether a set of brain state labels is valid
|
|
1257
1283
|
|
|
1258
1284
|
This returns an error message if a problem is found with the
|
|
@@ -1352,6 +1378,7 @@ def check_config_consistency(
|
|
|
1352
1378
|
output.append(
|
|
1353
1379
|
(
|
|
1354
1380
|
"Warning: the epoch length used when training this model "
|
|
1381
|
+
f"({model_epoch_length} seconds) "
|
|
1355
1382
|
"does not match the current epoch length setting."
|
|
1356
1383
|
)
|
|
1357
1384
|
)
|
|
@@ -27,7 +27,7 @@ LABEL_CMAP = np.concatenate(
|
|
|
27
27
|
[np.array([[0, 0, 0, 0]]), plt.colormaps["tab10"](range(10))], axis=0
|
|
28
28
|
)
|
|
29
29
|
# relative path to user manual text file
|
|
30
|
-
USER_MANUAL_FILE = "text/manual_scoring_guide.txt"
|
|
30
|
+
USER_MANUAL_FILE = os.path.normpath(r"text/manual_scoring_guide.txt")
|
|
31
31
|
|
|
32
32
|
# constants used by callback functions
|
|
33
33
|
# label formats
|
|
@@ -8,20 +8,8 @@
|
|
|
8
8
|
## WARNING! All changes made in this file will be lost when recompiling UI file!
|
|
9
9
|
################################################################################
|
|
10
10
|
|
|
11
|
-
from PySide6.QtCore import
|
|
12
|
-
|
|
13
|
-
QMetaObject,
|
|
14
|
-
QRect,
|
|
15
|
-
QSize,
|
|
16
|
-
Qt,
|
|
17
|
-
)
|
|
18
|
-
from PySide6.QtGui import (
|
|
19
|
-
QBrush,
|
|
20
|
-
QColor,
|
|
21
|
-
QFont,
|
|
22
|
-
QIcon,
|
|
23
|
-
QPalette,
|
|
24
|
-
)
|
|
11
|
+
from PySide6.QtCore import QCoreApplication, QMetaObject, QRect, QSize, Qt
|
|
12
|
+
from PySide6.QtGui import QBrush, QColor, QFont, QIcon, QPalette
|
|
25
13
|
from PySide6.QtWidgets import (
|
|
26
14
|
QCheckBox,
|
|
27
15
|
QDoubleSpinBox,
|
|
@@ -202,6 +190,8 @@ class Ui_PrimaryWindow(object):
|
|
|
202
190
|
|
|
203
191
|
self.left_scoring_vlayout.addWidget(self.recordinglistgroupbox)
|
|
204
192
|
|
|
193
|
+
self.logo_and_version_layout = QVBoxLayout()
|
|
194
|
+
self.logo_and_version_layout.setObjectName("logo_and_version_layout")
|
|
205
195
|
self.logo_layout = QVBoxLayout()
|
|
206
196
|
self.logo_layout.setObjectName("logo_layout")
|
|
207
197
|
self.frame = QFrame(self.scoring_tab)
|
|
@@ -252,7 +242,24 @@ class Ui_PrimaryWindow(object):
|
|
|
252
242
|
|
|
253
243
|
self.logo_layout.addWidget(self.frame)
|
|
254
244
|
|
|
255
|
-
self.
|
|
245
|
+
self.logo_and_version_layout.addLayout(self.logo_layout)
|
|
246
|
+
|
|
247
|
+
self.version_label = QLabel(self.scoring_tab)
|
|
248
|
+
self.version_label.setObjectName("version_label")
|
|
249
|
+
sizePolicy3 = QSizePolicy(
|
|
250
|
+
QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Fixed
|
|
251
|
+
)
|
|
252
|
+
sizePolicy3.setHorizontalStretch(0)
|
|
253
|
+
sizePolicy3.setVerticalStretch(0)
|
|
254
|
+
sizePolicy3.setHeightForWidth(
|
|
255
|
+
self.version_label.sizePolicy().hasHeightForWidth()
|
|
256
|
+
)
|
|
257
|
+
self.version_label.setSizePolicy(sizePolicy3)
|
|
258
|
+
self.version_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
|
259
|
+
|
|
260
|
+
self.logo_and_version_layout.addWidget(self.version_label)
|
|
261
|
+
|
|
262
|
+
self.left_scoring_vlayout.addLayout(self.logo_and_version_layout)
|
|
256
263
|
|
|
257
264
|
self.user_manual_layout = QHBoxLayout()
|
|
258
265
|
self.user_manual_layout.setObjectName("user_manual_layout")
|
|
@@ -340,11 +347,6 @@ class Ui_PrimaryWindow(object):
|
|
|
340
347
|
self.horizontalLayout.setObjectName("horizontalLayout")
|
|
341
348
|
self.recording_file_button = QPushButton(self.selected_recording_groupbox)
|
|
342
349
|
self.recording_file_button.setObjectName("recording_file_button")
|
|
343
|
-
sizePolicy3 = QSizePolicy(
|
|
344
|
-
QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Fixed
|
|
345
|
-
)
|
|
346
|
-
sizePolicy3.setHorizontalStretch(0)
|
|
347
|
-
sizePolicy3.setVerticalStretch(0)
|
|
348
350
|
sizePolicy3.setHeightForWidth(
|
|
349
351
|
self.recording_file_button.sizePolicy().hasHeightForWidth()
|
|
350
352
|
)
|
|
@@ -2217,9 +2219,23 @@ class Ui_PrimaryWindow(object):
|
|
|
2217
2219
|
self.remove_button.setText(
|
|
2218
2220
|
QCoreApplication.translate("PrimaryWindow", "remove", None)
|
|
2219
2221
|
)
|
|
2222
|
+
# if QT_CONFIG(tooltip)
|
|
2223
|
+
self.export_button.setToolTip(
|
|
2224
|
+
QCoreApplication.translate(
|
|
2225
|
+
"PrimaryWindow", "Export recording list to file", None
|
|
2226
|
+
)
|
|
2227
|
+
)
|
|
2228
|
+
# endif // QT_CONFIG(tooltip)
|
|
2220
2229
|
self.export_button.setText(
|
|
2221
2230
|
QCoreApplication.translate("PrimaryWindow", "export", None)
|
|
2222
2231
|
)
|
|
2232
|
+
# if QT_CONFIG(tooltip)
|
|
2233
|
+
self.import_button.setToolTip(
|
|
2234
|
+
QCoreApplication.translate(
|
|
2235
|
+
"PrimaryWindow", "Import recording list from file", None
|
|
2236
|
+
)
|
|
2237
|
+
)
|
|
2238
|
+
# endif // QT_CONFIG(tooltip)
|
|
2223
2239
|
self.import_button.setText(
|
|
2224
2240
|
QCoreApplication.translate("PrimaryWindow", "import", None)
|
|
2225
2241
|
)
|
|
@@ -2232,6 +2248,9 @@ class Ui_PrimaryWindow(object):
|
|
|
2232
2248
|
self.accusleepy1.setText(
|
|
2233
2249
|
QCoreApplication.translate("PrimaryWindow", "AccuSleePy", None)
|
|
2234
2250
|
)
|
|
2251
|
+
self.version_label.setText(
|
|
2252
|
+
QCoreApplication.translate("PrimaryWindow", "TextLabel", None)
|
|
2253
|
+
)
|
|
2235
2254
|
# if QT_CONFIG(tooltip)
|
|
2236
2255
|
self.user_manual_button.setToolTip(
|
|
2237
2256
|
QCoreApplication.translate("PrimaryWindow", "User manual", None)
|
|
@@ -2246,6 +2265,13 @@ class Ui_PrimaryWindow(object):
|
|
|
2246
2265
|
self.samplingratelabel.setText(
|
|
2247
2266
|
QCoreApplication.translate("PrimaryWindow", "Sampling rate (Hz):", None)
|
|
2248
2267
|
)
|
|
2268
|
+
# if QT_CONFIG(tooltip)
|
|
2269
|
+
self.recording_file_button.setToolTip(
|
|
2270
|
+
QCoreApplication.translate(
|
|
2271
|
+
"PrimaryWindow", "Select EEG+EMG recording", None
|
|
2272
|
+
)
|
|
2273
|
+
)
|
|
2274
|
+
# endif // QT_CONFIG(tooltip)
|
|
2249
2275
|
self.recording_file_button.setText(
|
|
2250
2276
|
QCoreApplication.translate("PrimaryWindow", "Select recording file", None)
|
|
2251
2277
|
)
|
|
@@ -2288,10 +2314,24 @@ class Ui_PrimaryWindow(object):
|
|
|
2288
2314
|
QCoreApplication.translate("PrimaryWindow", "Score manually", None)
|
|
2289
2315
|
)
|
|
2290
2316
|
self.manual_scoring_status.setText("")
|
|
2317
|
+
# if QT_CONFIG(tooltip)
|
|
2318
|
+
self.create_calibration_button.setToolTip(
|
|
2319
|
+
QCoreApplication.translate(
|
|
2320
|
+
"PrimaryWindow", "Create calibration file for this subject", None
|
|
2321
|
+
)
|
|
2322
|
+
)
|
|
2323
|
+
# endif // QT_CONFIG(tooltip)
|
|
2291
2324
|
self.create_calibration_button.setText(
|
|
2292
2325
|
QCoreApplication.translate("PrimaryWindow", "Create calibration file", None)
|
|
2293
2326
|
)
|
|
2294
2327
|
self.calibration_status.setText("")
|
|
2328
|
+
# if QT_CONFIG(tooltip)
|
|
2329
|
+
self.select_calibration_button.setToolTip(
|
|
2330
|
+
QCoreApplication.translate(
|
|
2331
|
+
"PrimaryWindow", "Load calibration file for this recording", None
|
|
2332
|
+
)
|
|
2333
|
+
)
|
|
2334
|
+
# endif // QT_CONFIG(tooltip)
|
|
2295
2335
|
self.select_calibration_button.setText(
|
|
2296
2336
|
QCoreApplication.translate("PrimaryWindow", "Select calibration file", None)
|
|
2297
2337
|
)
|
|
@@ -2319,6 +2359,13 @@ class Ui_PrimaryWindow(object):
|
|
|
2319
2359
|
"PrimaryWindow", "Minimum bout length (sec):", None
|
|
2320
2360
|
)
|
|
2321
2361
|
)
|
|
2362
|
+
# if QT_CONFIG(tooltip)
|
|
2363
|
+
self.load_model_button.setToolTip(
|
|
2364
|
+
QCoreApplication.translate(
|
|
2365
|
+
"PrimaryWindow", "Load a trained sleep scoring classifier", None
|
|
2366
|
+
)
|
|
2367
|
+
)
|
|
2368
|
+
# endif // QT_CONFIG(tooltip)
|
|
2322
2369
|
self.load_model_button.setText(
|
|
2323
2370
|
QCoreApplication.translate(
|
|
2324
2371
|
"PrimaryWindow", "Load classification model", None
|
|
@@ -2346,6 +2393,13 @@ class Ui_PrimaryWindow(object):
|
|
|
2346
2393
|
self.real_time_button.setText(
|
|
2347
2394
|
QCoreApplication.translate("PrimaryWindow", "Real-time", None)
|
|
2348
2395
|
)
|
|
2396
|
+
# if QT_CONFIG(tooltip)
|
|
2397
|
+
self.train_model_button.setToolTip(
|
|
2398
|
+
QCoreApplication.translate(
|
|
2399
|
+
"PrimaryWindow", "Begin training the classification model", None
|
|
2400
|
+
)
|
|
2401
|
+
)
|
|
2402
|
+
# endif // QT_CONFIG(tooltip)
|
|
2349
2403
|
self.train_model_button.setText(
|
|
2350
2404
|
QCoreApplication.translate(
|
|
2351
2405
|
"PrimaryWindow", "Train classification model", None
|
|
@@ -2422,6 +2476,13 @@ class Ui_PrimaryWindow(object):
|
|
|
2422
2476
|
self.label_17.setText(
|
|
2423
2477
|
QCoreApplication.translate("PrimaryWindow", "Default epoch length:", None)
|
|
2424
2478
|
)
|
|
2479
|
+
# if QT_CONFIG(tooltip)
|
|
2480
|
+
self.save_config_button.setToolTip(
|
|
2481
|
+
QCoreApplication.translate(
|
|
2482
|
+
"PrimaryWindow", "Save current configuration", None
|
|
2483
|
+
)
|
|
2484
|
+
)
|
|
2485
|
+
# endif // QT_CONFIG(tooltip)
|
|
2425
2486
|
self.save_config_button.setText(
|
|
2426
2487
|
QCoreApplication.translate("PrimaryWindow", "Save", None)
|
|
2427
2488
|
)
|
|
@@ -263,6 +263,9 @@
|
|
|
263
263
|
<verstretch>0</verstretch>
|
|
264
264
|
</sizepolicy>
|
|
265
265
|
</property>
|
|
266
|
+
<property name="toolTip">
|
|
267
|
+
<string>Export recording list to file</string>
|
|
268
|
+
</property>
|
|
266
269
|
<property name="text">
|
|
267
270
|
<string>export</string>
|
|
268
271
|
</property>
|
|
@@ -276,6 +279,9 @@
|
|
|
276
279
|
<verstretch>0</verstretch>
|
|
277
280
|
</sizepolicy>
|
|
278
281
|
</property>
|
|
282
|
+
<property name="toolTip">
|
|
283
|
+
<string>Import recording list from file</string>
|
|
284
|
+
</property>
|
|
279
285
|
<property name="text">
|
|
280
286
|
<string>import</string>
|
|
281
287
|
</property>
|
|
@@ -287,132 +293,152 @@
|
|
|
287
293
|
</widget>
|
|
288
294
|
</item>
|
|
289
295
|
<item>
|
|
290
|
-
<layout class="QVBoxLayout" name="
|
|
296
|
+
<layout class="QVBoxLayout" name="logo_and_version_layout">
|
|
297
|
+
<item>
|
|
298
|
+
<layout class="QVBoxLayout" name="logo_layout">
|
|
299
|
+
<item>
|
|
300
|
+
<widget class="QFrame" name="frame">
|
|
301
|
+
<property name="sizePolicy">
|
|
302
|
+
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
|
303
|
+
<horstretch>0</horstretch>
|
|
304
|
+
<verstretch>0</verstretch>
|
|
305
|
+
</sizepolicy>
|
|
306
|
+
</property>
|
|
307
|
+
<property name="minimumSize">
|
|
308
|
+
<size>
|
|
309
|
+
<width>180</width>
|
|
310
|
+
<height>80</height>
|
|
311
|
+
</size>
|
|
312
|
+
</property>
|
|
313
|
+
<property name="styleSheet">
|
|
314
|
+
<string notr="true">background-color: transparent;</string>
|
|
315
|
+
</property>
|
|
316
|
+
<property name="frameShape">
|
|
317
|
+
<enum>QFrame::Shape::NoFrame</enum>
|
|
318
|
+
</property>
|
|
319
|
+
<property name="frameShadow">
|
|
320
|
+
<enum>QFrame::Shadow::Raised</enum>
|
|
321
|
+
</property>
|
|
322
|
+
<widget class="QLabel" name="accusleepy2">
|
|
323
|
+
<property name="geometry">
|
|
324
|
+
<rect>
|
|
325
|
+
<x>11</x>
|
|
326
|
+
<y>15</y>
|
|
327
|
+
<width>160</width>
|
|
328
|
+
<height>50</height>
|
|
329
|
+
</rect>
|
|
330
|
+
</property>
|
|
331
|
+
<property name="sizePolicy">
|
|
332
|
+
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
|
333
|
+
<horstretch>0</horstretch>
|
|
334
|
+
<verstretch>0</verstretch>
|
|
335
|
+
</sizepolicy>
|
|
336
|
+
</property>
|
|
337
|
+
<property name="font">
|
|
338
|
+
<font>
|
|
339
|
+
<pointsize>21</pointsize>
|
|
340
|
+
<italic>true</italic>
|
|
341
|
+
<bold>true</bold>
|
|
342
|
+
</font>
|
|
343
|
+
</property>
|
|
344
|
+
<property name="styleSheet">
|
|
345
|
+
<string notr="true">background-color: transparent;
|
|
346
|
+
color: rgb(130, 169, 68);</string>
|
|
347
|
+
</property>
|
|
348
|
+
<property name="text">
|
|
349
|
+
<string>AccuSleePy</string>
|
|
350
|
+
</property>
|
|
351
|
+
<property name="alignment">
|
|
352
|
+
<set>Qt::AlignmentFlag::AlignCenter</set>
|
|
353
|
+
</property>
|
|
354
|
+
</widget>
|
|
355
|
+
<widget class="QLabel" name="accusleepy3">
|
|
356
|
+
<property name="geometry">
|
|
357
|
+
<rect>
|
|
358
|
+
<x>13</x>
|
|
359
|
+
<y>17</y>
|
|
360
|
+
<width>160</width>
|
|
361
|
+
<height>50</height>
|
|
362
|
+
</rect>
|
|
363
|
+
</property>
|
|
364
|
+
<property name="sizePolicy">
|
|
365
|
+
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
|
366
|
+
<horstretch>0</horstretch>
|
|
367
|
+
<verstretch>0</verstretch>
|
|
368
|
+
</sizepolicy>
|
|
369
|
+
</property>
|
|
370
|
+
<property name="font">
|
|
371
|
+
<font>
|
|
372
|
+
<pointsize>21</pointsize>
|
|
373
|
+
<italic>true</italic>
|
|
374
|
+
<bold>true</bold>
|
|
375
|
+
</font>
|
|
376
|
+
</property>
|
|
377
|
+
<property name="styleSheet">
|
|
378
|
+
<string notr="true">background-color: transparent;
|
|
379
|
+
color: rgb(46, 63, 150);</string>
|
|
380
|
+
</property>
|
|
381
|
+
<property name="text">
|
|
382
|
+
<string>AccuSleePy</string>
|
|
383
|
+
</property>
|
|
384
|
+
<property name="alignment">
|
|
385
|
+
<set>Qt::AlignmentFlag::AlignCenter</set>
|
|
386
|
+
</property>
|
|
387
|
+
</widget>
|
|
388
|
+
<widget class="QLabel" name="accusleepy1">
|
|
389
|
+
<property name="geometry">
|
|
390
|
+
<rect>
|
|
391
|
+
<x>9</x>
|
|
392
|
+
<y>13</y>
|
|
393
|
+
<width>160</width>
|
|
394
|
+
<height>50</height>
|
|
395
|
+
</rect>
|
|
396
|
+
</property>
|
|
397
|
+
<property name="sizePolicy">
|
|
398
|
+
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
|
399
|
+
<horstretch>0</horstretch>
|
|
400
|
+
<verstretch>0</verstretch>
|
|
401
|
+
</sizepolicy>
|
|
402
|
+
</property>
|
|
403
|
+
<property name="font">
|
|
404
|
+
<font>
|
|
405
|
+
<pointsize>21</pointsize>
|
|
406
|
+
<italic>true</italic>
|
|
407
|
+
<bold>true</bold>
|
|
408
|
+
</font>
|
|
409
|
+
</property>
|
|
410
|
+
<property name="styleSheet">
|
|
411
|
+
<string notr="true">background-color: transparent;
|
|
412
|
+
color: rgb(244, 195, 68);</string>
|
|
413
|
+
</property>
|
|
414
|
+
<property name="text">
|
|
415
|
+
<string>AccuSleePy</string>
|
|
416
|
+
</property>
|
|
417
|
+
<property name="alignment">
|
|
418
|
+
<set>Qt::AlignmentFlag::AlignCenter</set>
|
|
419
|
+
</property>
|
|
420
|
+
</widget>
|
|
421
|
+
<zorder>accusleepy1</zorder>
|
|
422
|
+
<zorder>accusleepy2</zorder>
|
|
423
|
+
<zorder>accusleepy3</zorder>
|
|
424
|
+
</widget>
|
|
425
|
+
</item>
|
|
426
|
+
</layout>
|
|
427
|
+
</item>
|
|
291
428
|
<item>
|
|
292
|
-
<widget class="
|
|
429
|
+
<widget class="QLabel" name="version_label">
|
|
293
430
|
<property name="sizePolicy">
|
|
294
|
-
<sizepolicy hsizetype="
|
|
431
|
+
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
|
295
432
|
<horstretch>0</horstretch>
|
|
296
433
|
<verstretch>0</verstretch>
|
|
297
434
|
</sizepolicy>
|
|
298
435
|
</property>
|
|
299
|
-
<property name="
|
|
300
|
-
<
|
|
301
|
-
<width>180</width>
|
|
302
|
-
<height>80</height>
|
|
303
|
-
</size>
|
|
304
|
-
</property>
|
|
305
|
-
<property name="styleSheet">
|
|
306
|
-
<string notr="true">background-color: transparent;</string>
|
|
307
|
-
</property>
|
|
308
|
-
<property name="frameShape">
|
|
309
|
-
<enum>QFrame::Shape::NoFrame</enum>
|
|
436
|
+
<property name="text">
|
|
437
|
+
<string>TextLabel</string>
|
|
310
438
|
</property>
|
|
311
|
-
<property name="
|
|
312
|
-
<
|
|
439
|
+
<property name="alignment">
|
|
440
|
+
<set>Qt::AlignmentFlag::AlignCenter</set>
|
|
313
441
|
</property>
|
|
314
|
-
<widget class="QLabel" name="accusleepy2">
|
|
315
|
-
<property name="geometry">
|
|
316
|
-
<rect>
|
|
317
|
-
<x>11</x>
|
|
318
|
-
<y>15</y>
|
|
319
|
-
<width>160</width>
|
|
320
|
-
<height>50</height>
|
|
321
|
-
</rect>
|
|
322
|
-
</property>
|
|
323
|
-
<property name="sizePolicy">
|
|
324
|
-
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
|
325
|
-
<horstretch>0</horstretch>
|
|
326
|
-
<verstretch>0</verstretch>
|
|
327
|
-
</sizepolicy>
|
|
328
|
-
</property>
|
|
329
|
-
<property name="font">
|
|
330
|
-
<font>
|
|
331
|
-
<pointsize>21</pointsize>
|
|
332
|
-
<italic>true</italic>
|
|
333
|
-
<bold>true</bold>
|
|
334
|
-
</font>
|
|
335
|
-
</property>
|
|
336
|
-
<property name="styleSheet">
|
|
337
|
-
<string notr="true">background-color: transparent;
|
|
338
|
-
color: rgb(130, 169, 68);</string>
|
|
339
|
-
</property>
|
|
340
|
-
<property name="text">
|
|
341
|
-
<string>AccuSleePy</string>
|
|
342
|
-
</property>
|
|
343
|
-
<property name="alignment">
|
|
344
|
-
<set>Qt::AlignmentFlag::AlignCenter</set>
|
|
345
|
-
</property>
|
|
346
|
-
</widget>
|
|
347
|
-
<widget class="QLabel" name="accusleepy3">
|
|
348
|
-
<property name="geometry">
|
|
349
|
-
<rect>
|
|
350
|
-
<x>13</x>
|
|
351
|
-
<y>17</y>
|
|
352
|
-
<width>160</width>
|
|
353
|
-
<height>50</height>
|
|
354
|
-
</rect>
|
|
355
|
-
</property>
|
|
356
|
-
<property name="sizePolicy">
|
|
357
|
-
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
|
358
|
-
<horstretch>0</horstretch>
|
|
359
|
-
<verstretch>0</verstretch>
|
|
360
|
-
</sizepolicy>
|
|
361
|
-
</property>
|
|
362
|
-
<property name="font">
|
|
363
|
-
<font>
|
|
364
|
-
<pointsize>21</pointsize>
|
|
365
|
-
<italic>true</italic>
|
|
366
|
-
<bold>true</bold>
|
|
367
|
-
</font>
|
|
368
|
-
</property>
|
|
369
|
-
<property name="styleSheet">
|
|
370
|
-
<string notr="true">background-color: transparent;
|
|
371
|
-
color: rgb(46, 63, 150);</string>
|
|
372
|
-
</property>
|
|
373
|
-
<property name="text">
|
|
374
|
-
<string>AccuSleePy</string>
|
|
375
|
-
</property>
|
|
376
|
-
<property name="alignment">
|
|
377
|
-
<set>Qt::AlignmentFlag::AlignCenter</set>
|
|
378
|
-
</property>
|
|
379
|
-
</widget>
|
|
380
|
-
<widget class="QLabel" name="accusleepy1">
|
|
381
|
-
<property name="geometry">
|
|
382
|
-
<rect>
|
|
383
|
-
<x>9</x>
|
|
384
|
-
<y>13</y>
|
|
385
|
-
<width>160</width>
|
|
386
|
-
<height>50</height>
|
|
387
|
-
</rect>
|
|
388
|
-
</property>
|
|
389
|
-
<property name="sizePolicy">
|
|
390
|
-
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
|
391
|
-
<horstretch>0</horstretch>
|
|
392
|
-
<verstretch>0</verstretch>
|
|
393
|
-
</sizepolicy>
|
|
394
|
-
</property>
|
|
395
|
-
<property name="font">
|
|
396
|
-
<font>
|
|
397
|
-
<pointsize>21</pointsize>
|
|
398
|
-
<italic>true</italic>
|
|
399
|
-
<bold>true</bold>
|
|
400
|
-
</font>
|
|
401
|
-
</property>
|
|
402
|
-
<property name="styleSheet">
|
|
403
|
-
<string notr="true">background-color: transparent;
|
|
404
|
-
color: rgb(244, 195, 68);</string>
|
|
405
|
-
</property>
|
|
406
|
-
<property name="text">
|
|
407
|
-
<string>AccuSleePy</string>
|
|
408
|
-
</property>
|
|
409
|
-
<property name="alignment">
|
|
410
|
-
<set>Qt::AlignmentFlag::AlignCenter</set>
|
|
411
|
-
</property>
|
|
412
|
-
</widget>
|
|
413
|
-
<zorder>accusleepy1</zorder>
|
|
414
|
-
<zorder>accusleepy2</zorder>
|
|
415
|
-
<zorder>accusleepy3</zorder>
|
|
416
442
|
</widget>
|
|
417
443
|
</item>
|
|
418
444
|
</layout>
|
|
@@ -562,6 +588,9 @@ color: rgb(244, 195, 68);</string>
|
|
|
562
588
|
<verstretch>0</verstretch>
|
|
563
589
|
</sizepolicy>
|
|
564
590
|
</property>
|
|
591
|
+
<property name="toolTip">
|
|
592
|
+
<string>Select EEG+EMG recording</string>
|
|
593
|
+
</property>
|
|
565
594
|
<property name="text">
|
|
566
595
|
<string>Select recording file</string>
|
|
567
596
|
</property>
|
|
@@ -753,6 +782,9 @@ color: rgb(244, 195, 68);</string>
|
|
|
753
782
|
<verstretch>0</verstretch>
|
|
754
783
|
</sizepolicy>
|
|
755
784
|
</property>
|
|
785
|
+
<property name="toolTip">
|
|
786
|
+
<string>Create calibration file for this subject</string>
|
|
787
|
+
</property>
|
|
756
788
|
<property name="text">
|
|
757
789
|
<string>Create calibration file</string>
|
|
758
790
|
</property>
|
|
@@ -813,6 +845,9 @@ color: rgb(244, 195, 68);</string>
|
|
|
813
845
|
<verstretch>0</verstretch>
|
|
814
846
|
</sizepolicy>
|
|
815
847
|
</property>
|
|
848
|
+
<property name="toolTip">
|
|
849
|
+
<string>Load calibration file for this recording</string>
|
|
850
|
+
</property>
|
|
816
851
|
<property name="text">
|
|
817
852
|
<string>Select calibration file</string>
|
|
818
853
|
</property>
|
|
@@ -1042,6 +1077,9 @@ color: rgb(244, 195, 68);</string>
|
|
|
1042
1077
|
<verstretch>0</verstretch>
|
|
1043
1078
|
</sizepolicy>
|
|
1044
1079
|
</property>
|
|
1080
|
+
<property name="toolTip">
|
|
1081
|
+
<string>Load a trained sleep scoring classifier</string>
|
|
1082
|
+
</property>
|
|
1045
1083
|
<property name="text">
|
|
1046
1084
|
<string>Load classification model</string>
|
|
1047
1085
|
</property>
|
|
@@ -1296,6 +1334,9 @@ color: rgb(244, 195, 68);</string>
|
|
|
1296
1334
|
<verstretch>0</verstretch>
|
|
1297
1335
|
</sizepolicy>
|
|
1298
1336
|
</property>
|
|
1337
|
+
<property name="toolTip">
|
|
1338
|
+
<string>Begin training the classification model</string>
|
|
1339
|
+
</property>
|
|
1299
1340
|
<property name="text">
|
|
1300
1341
|
<string>Train classification model</string>
|
|
1301
1342
|
</property>
|
|
@@ -3553,6 +3594,9 @@ color: rgb(244, 195, 68);</string>
|
|
|
3553
3594
|
<verstretch>0</verstretch>
|
|
3554
3595
|
</sizepolicy>
|
|
3555
3596
|
</property>
|
|
3597
|
+
<property name="toolTip">
|
|
3598
|
+
<string>Save current configuration</string>
|
|
3599
|
+
</property>
|
|
3556
3600
|
<property name="text">
|
|
3557
3601
|
<string>Save</string>
|
|
3558
3602
|
</property>
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
This is the current brain state configuration.
|
|
2
|
-
You can also choose the default epoch length.
|
|
3
2
|
If you make changes, click 'Save' to store them.
|
|
4
3
|
|
|
5
4
|
Each brain state has several attributes:
|
|
@@ -26,3 +25,5 @@ Important notes:
|
|
|
26
25
|
- Changing these settings can invalidate existing label files,
|
|
27
26
|
calibration files, and trained models!
|
|
28
27
|
- Reinstalling AccuSleePy will overwrite this configuration.
|
|
28
|
+
- You can also choose the default epoch length that is shown
|
|
29
|
+
when the primary interface starts up.
|
|
@@ -1,11 +1,31 @@
|
|
|
1
|
-
from accusleepy.constants import
|
|
1
|
+
from accusleepy.constants import (
|
|
2
|
+
BRAIN_STATE_COL,
|
|
3
|
+
CALIBRATION_FILE_TYPE,
|
|
4
|
+
EEG_COL,
|
|
5
|
+
EMG_COL,
|
|
6
|
+
LABEL_FILE_TYPE,
|
|
7
|
+
MODEL_FILE_TYPE,
|
|
8
|
+
RECORDING_FILE_TYPES,
|
|
9
|
+
UNDEFINED_LABEL,
|
|
10
|
+
)
|
|
2
11
|
|
|
3
12
|
MAIN_GUIDE_TEXT = f"""
|
|
13
|
+
Section 0: Definitions
|
|
4
14
|
Section 1: Overview of the GUI
|
|
5
15
|
Section 2: AccuSleePy file types
|
|
6
16
|
Section 3: Manually assigning brain state labels
|
|
7
17
|
Section 4: Automatically assigning brain state labels
|
|
8
18
|
|
|
19
|
+
-----------------------------------------------------------------------
|
|
20
|
+
Section 0: Definitions
|
|
21
|
+
-----------------------------------------------------------------------
|
|
22
|
+
Recording: a table containing one channel of EEG data and one channel
|
|
23
|
+
of EMG data collected at a constant sampling rate.
|
|
24
|
+
Epoch: the temporal resolution of brain state scoring. If, for example,
|
|
25
|
+
the epoch length is 5 seconds, then a brain state label will be
|
|
26
|
+
assigned to each 5-second segment of a recording.
|
|
27
|
+
Bout: a contiguous set of epochs with the same brain state.
|
|
28
|
+
|
|
9
29
|
-----------------------------------------------------------------------
|
|
10
30
|
Section 1: Overview of the primary interface
|
|
11
31
|
-----------------------------------------------------------------------
|
|
@@ -43,17 +63,17 @@ There are four types of files associated with AccuSleePy.
|
|
|
43
63
|
To select a file in the primary interface, you can either use the
|
|
44
64
|
associated button, or drag/drop the file into the empty box adjacent
|
|
45
65
|
to the button.
|
|
46
|
-
Recording file: a
|
|
47
|
-
data and one column of EMG data.
|
|
48
|
-
{EEG_COL} and {EMG_COL}.
|
|
49
|
-
Label file: a
|
|
50
|
-
with entries that are either the undefined brain state
|
|
66
|
+
Recording file: a {" or ".join(RECORDING_FILE_TYPES)} file containing one
|
|
67
|
+
column of EEG data and one column of EMG data.
|
|
68
|
+
The column names must be {EEG_COL} and {EMG_COL}.
|
|
69
|
+
Label file: a {LABEL_FILE_TYPE} file with one column titled {BRAIN_STATE_COL}
|
|
70
|
+
with entries that are either the undefined brain state ({UNDEFINED_LABEL})
|
|
51
71
|
or one of the digits in your brain state configuration.
|
|
52
72
|
By default, these are 1-3 where REM = 1, wake = 2, NREM = 3.
|
|
53
73
|
Calibration data file: required for automatic labeling. See Section 4
|
|
54
|
-
for details. These have
|
|
74
|
+
for details. These have {CALIBRATION_FILE_TYPE} format.
|
|
55
75
|
Trained classification model: required for automatic labeling. See
|
|
56
|
-
Section 4 for details. These have
|
|
76
|
+
Section 4 for details. These have {MODEL_FILE_TYPE} format.
|
|
57
77
|
|
|
58
78
|
-----------------------------------------------------------------------
|
|
59
79
|
Section 3: Manually assigning brain state labels
|
|
@@ -103,6 +123,10 @@ To create a calibration data file:
|
|
|
103
123
|
4. Enter a filename for the calibration data file.
|
|
104
124
|
5. The calibration file will automatically be assigned to the currently
|
|
105
125
|
selected recording.
|
|
126
|
+
Note that epoch length can affect the calibration process. If you make
|
|
127
|
+
a calibration file for a subject using one epoch length, but want to
|
|
128
|
+
score another recording from the same subject with a different epoch
|
|
129
|
+
length, it's best to create a new calibration file.
|
|
106
130
|
|
|
107
131
|
--- Section 4B: Training your own classification model ---
|
|
108
132
|
To train a new model on your own data:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "accusleepy"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.4.0"
|
|
4
4
|
description = "Python implementation of AccuSleep"
|
|
5
5
|
authors = [
|
|
6
6
|
{name = "Zeke Barger",email = "zekebarger@gmail.com"}
|
|
@@ -21,6 +21,7 @@ dependencies = [
|
|
|
21
21
|
"fastparquet (>=2024.11.0,<2025.0.0)",
|
|
22
22
|
"pre-commit (>=4.2.0,<5.0.0)",
|
|
23
23
|
"tqdm (>=4.67.1,<5.0.0)",
|
|
24
|
+
"toml (>=0.10.2,<0.11.0)",
|
|
24
25
|
]
|
|
25
26
|
|
|
26
27
|
[tool.poetry.group.dev.dependencies]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|