not1mm 25.6.2__py3-none-any.whl → 25.6.4__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.
not1mm/__main__.py CHANGED
@@ -68,6 +68,7 @@ from not1mm.lib.fldigi_sendstring import FlDigi_Comm
68
68
  import not1mm.fsutils as fsutils
69
69
  from not1mm.logwindow import LogWindow
70
70
  from not1mm.checkwindow import CheckWindow
71
+ from not1mm.dxcc_tracker import DXCCWindow
71
72
  from not1mm.bandmap import BandMapWindow
72
73
  from not1mm.vfo import VfoWindow
73
74
  from not1mm.ratewindow import RateWindow
@@ -185,6 +186,7 @@ class MainWindow(QtWidgets.QMainWindow):
185
186
  vfo_window = None
186
187
  rate_window = None
187
188
  statistics_window = None
189
+ dxcc_window = None
188
190
  settings = None
189
191
  lookup_service = None
190
192
  fldigi_util = None
@@ -308,6 +310,7 @@ class MainWindow(QtWidgets.QMainWindow):
308
310
  self.actionRate_Window.triggered.connect(self.launch_rate_window)
309
311
  self.actionStatistics.triggered.connect(self.launch_stats_window)
310
312
  self.actionVFO.triggered.connect(self.launch_vfo)
313
+ self.actionDXCC.triggered.connect(self.launch_dxcc_window)
311
314
  self.actionRecalculate_Mults.triggered.connect(self.recalculate_mults)
312
315
  self.actionLoad_Call_History_File.triggered.connect(self.load_call_history)
313
316
 
@@ -738,6 +741,15 @@ class MainWindow(QtWidgets.QMainWindow):
738
741
  self.statistics_window.hide()
739
742
  self.statistics_window.message.connect(self.dockwidget_message)
740
743
 
744
+ self.show_splash_msg("Setting up DXCCWindow.")
745
+ self.dxcc_window = DXCCWindow()
746
+ self.dxcc_window.setObjectName("dxcc-window")
747
+ if os.environ.get("WAYLAND_DISPLAY") and old_Qt is True:
748
+ self.dxcc_window.setFeatures(dockfeatures)
749
+ self.addDockWidget(Qt.DockWidgetArea.RightDockWidgetArea, self.dxcc_window)
750
+ self.dxcc_window.hide()
751
+ self.dxcc_window.message.connect(self.dockwidget_message)
752
+
741
753
  self.show_splash_msg("Setting up VFOWindow.")
742
754
  self.vfo_window = VfoWindow()
743
755
  self.vfo_window.setObjectName("vfo-window")
@@ -807,6 +819,15 @@ class MainWindow(QtWidgets.QMainWindow):
807
819
  self.statistics_window.hide()
808
820
  self.statistics_window.setActive(False)
809
821
 
822
+ self.actionDXCC.setChecked(self.pref.get("dxccwindow", False))
823
+ if self.actionDXCC.isChecked():
824
+ self.dxcc_window.show()
825
+ self.dxcc_window.setActive(True)
826
+ # self.dxcc_window.get_run_and_total_qs()
827
+ else:
828
+ self.dxcc_window.hide()
829
+ self.dxcc_window.setActive(False)
830
+
810
831
  self.actionVFO.setChecked(self.pref.get("vfowindow", False))
811
832
  if self.actionVFO.isChecked():
812
833
  self.vfo_window.show()
@@ -1127,9 +1148,12 @@ class MainWindow(QtWidgets.QMainWindow):
1127
1148
  except OSError as err:
1128
1149
  logging.warning("%s", err)
1129
1150
 
1130
- if msg.get("cmd", "") in ["CONTACTCHANGED", "DELETE"]:
1151
+ if msg.get("cmd", "") in ["CONTACTCHANGED", "DELETED"]:
1131
1152
  if self.statistics_window:
1132
1153
  self.statistics_window.msg_from_main(msg)
1154
+ if self.dxcc_window:
1155
+ self.dxcc_window.msg_from_main(msg)
1156
+
1133
1157
  if msg.get("cmd", "") == "GETCOLUMNS":
1134
1158
  if hasattr(self.contest, "columns"):
1135
1159
  cmd = {}
@@ -1618,6 +1642,8 @@ class MainWindow(QtWidgets.QMainWindow):
1618
1642
  self.rate_window.msg_from_main(cmd)
1619
1643
  if self.statistics_window:
1620
1644
  self.statistics_window.msg_from_main(cmd)
1645
+ if self.dxcc_window:
1646
+ self.dxcc_window.msg_from_main(cmd)
1621
1647
 
1622
1648
  self.clearinputs()
1623
1649
  self.edit_station_settings()
@@ -1660,6 +1686,8 @@ class MainWindow(QtWidgets.QMainWindow):
1660
1686
  self.rate_window.msg_from_main(cmd)
1661
1687
  if self.statistics_window:
1662
1688
  self.statistics_window.msg_from_main(cmd)
1689
+ if self.dxcc_window:
1690
+ self.dxcc_window.msg_from_main(cmd)
1663
1691
 
1664
1692
  self.clearinputs()
1665
1693
  self.open_contest()
@@ -1955,6 +1983,8 @@ class MainWindow(QtWidgets.QMainWindow):
1955
1983
  self.rate_window.msg_from_main(cmd)
1956
1984
  if self.statistics_window:
1957
1985
  self.statistics_window.msg_from_main(cmd)
1986
+ if self.dxcc_window:
1987
+ self.dxcc_window.msg_from_main(cmd)
1958
1988
  # server
1959
1989
  if self.pref.get("useserver", False) is True:
1960
1990
  cmd = self.contest_settings.copy()
@@ -2208,6 +2238,18 @@ class MainWindow(QtWidgets.QMainWindow):
2208
2238
  self.statistics_window.hide()
2209
2239
  self.statistics_window.setActive(False)
2210
2240
 
2241
+ def launch_dxcc_window(self) -> None:
2242
+ """Launch the dxcc window"""
2243
+ self.pref["dxccwindow"] = self.actionDXCC.isChecked()
2244
+ self.write_preference()
2245
+ if self.actionDXCC.isChecked():
2246
+ self.dxcc_window.show()
2247
+ self.dxcc_window.setActive(True)
2248
+ # self.dxcc_window.get_run_and_total_qs()
2249
+ else:
2250
+ self.dxcc_window.hide()
2251
+ self.dxcc_window.setActive(False)
2252
+
2211
2253
  def launch_vfo(self) -> None:
2212
2254
  """Launch the VFO window"""
2213
2255
  self.pref["vfowindow"] = self.actionVFO.isChecked()
@@ -2890,6 +2932,8 @@ class MainWindow(QtWidgets.QMainWindow):
2890
2932
  self.check_window.msg_from_main(cmd)
2891
2933
  if self.statistics_window:
2892
2934
  self.statistics_window.msg_from_main(cmd)
2935
+ if self.dxcc_window:
2936
+ self.dxcc_window.msg_from_main(cmd)
2893
2937
 
2894
2938
  def update_rtc_xml(self):
2895
2939
  """Update RTC XML"""
@@ -0,0 +1,25 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <ui version="4.0">
3
+ <class>DockWidget</class>
4
+ <widget class="QDockWidget" name="DockWidget">
5
+ <property name="geometry">
6
+ <rect>
7
+ <x>0</x>
8
+ <y>0</y>
9
+ <width>800</width>
10
+ <height>600</height>
11
+ </rect>
12
+ </property>
13
+ <property name="windowTitle">
14
+ <string>DXCC Multiplier Tracker</string>
15
+ </property>
16
+ <widget class="QWidget" name="centralwidget">
17
+ <layout class="QVBoxLayout" name="verticalLayout">
18
+ <item>
19
+ <widget class="QTableView" name="tableView"/>
20
+ </item>
21
+ </layout>
22
+ </widget>
23
+ </widget>
24
+ </ui>
25
+
not1mm/data/main.ui CHANGED
@@ -1572,6 +1572,7 @@
1572
1572
  <addaction name="actionRate_Window"/>
1573
1573
  <addaction name="actionStatistics"/>
1574
1574
  <addaction name="actionVFO"/>
1575
+ <addaction name="actionDXCC"/>
1575
1576
  </widget>
1576
1577
  <widget class="QMenu" name="menuOther">
1577
1578
  <property name="title">
@@ -2132,6 +2133,17 @@
2132
2133
  <string>Alt+S</string>
2133
2134
  </property>
2134
2135
  </action>
2136
+ <action name="actionDXCC">
2137
+ <property name="checkable">
2138
+ <bool>true</bool>
2139
+ </property>
2140
+ <property name="text">
2141
+ <string>DXCC</string>
2142
+ </property>
2143
+ <property name="shortcut">
2144
+ <string>Alt+D</string>
2145
+ </property>
2146
+ </action>
2135
2147
  </widget>
2136
2148
  <resources/>
2137
2149
  <connections/>
not1mm/dxcc_tracker.py ADDED
@@ -0,0 +1,135 @@
1
+ from PyQt6.QtWidgets import QDockWidget, QTableView
2
+ from PyQt6.QtSql import QSqlDatabase, QSqlQueryModel, QSqlQuery
3
+ from PyQt6.QtGui import QBrush, QColor
4
+ from PyQt6.QtCore import Qt
5
+ from PyQt6.QtCore import pyqtSignal
6
+ from PyQt6 import uic
7
+ import not1mm.fsutils as fsutils
8
+ import os
9
+ from json import loads
10
+
11
+ import logging
12
+
13
+ logger = logging.getLogger(__name__)
14
+
15
+
16
+ class CustomSqlModel(QSqlQueryModel):
17
+ def data(self, index, role):
18
+ if role == Qt.ItemDataRole.BackgroundRole:
19
+ column = index.column()
20
+ if column < 7: # Columns 0-6 (CountryPrefix and band columns)
21
+ value = super().data(index, Qt.ItemDataRole.DisplayRole)
22
+ if value and isinstance(value, (int, float)) and value > 0:
23
+ return QBrush(QColor(44, 138, 44)) # Light green color
24
+ elif value == 0:
25
+ return QBrush(QColor(155, 100, 100)) # Light red color
26
+ return super().data(index, role)
27
+
28
+
29
+ class DXCCWindow(QDockWidget):
30
+ message = pyqtSignal(dict)
31
+ dbname = None
32
+ db = None
33
+ model = None
34
+ pref = {}
35
+
36
+ def __init__(self):
37
+ super().__init__()
38
+ self.active = False
39
+ uic.loadUi(fsutils.APP_DATA_PATH / "dxcc_tracker.ui", self)
40
+ self.setWindowTitle("DXCC Multiplier Tracker")
41
+ self.load_pref()
42
+ self.db = QSqlDatabase.addDatabase("QSQLITE")
43
+ self.tableView.verticalHeader().setVisible(False)
44
+
45
+ def setActive(self, mode: bool):
46
+ self.active = bool(mode)
47
+
48
+ def update_model(self):
49
+ self.model = CustomSqlModel(self)
50
+ query = QSqlQuery(self.db)
51
+ query.prepare(
52
+ """
53
+ SELECT CountryPrefix,
54
+ SUM(CASE WHEN Band = 1.8 THEN 1 ELSE 0 END) AS '160m',
55
+ SUM(CASE WHEN Band = 3.5 THEN 1 ELSE 0 END) AS '80m',
56
+ SUM(CASE WHEN Band = 7.0 THEN 1 ELSE 0 END) AS '40m',
57
+ SUM(CASE WHEN Band = 14.0 THEN 1 ELSE 0 END) AS '20m',
58
+ SUM(CASE WHEN Band = 21.0 THEN 1 ELSE 0 END) AS '15m',
59
+ SUM(CASE WHEN Band = 28.0 THEN 1 ELSE 0 END) AS '10m',
60
+ COUNT(*) AS Total
61
+ FROM DXLOG
62
+ GROUP BY CountryPrefix
63
+ ORDER BY Total DESC
64
+ """
65
+ )
66
+ if not query.exec():
67
+ print("Query failed:", query.lastError().text())
68
+ else:
69
+ self.model.setQuery(query)
70
+ headers = ["DXCC", "160m", "80m", "40m", "20m", "15m", "10m", "Total"]
71
+ for i, header in enumerate(headers):
72
+ self.model.setHeaderData(i, Qt.Orientation.Horizontal, header)
73
+ self.tableView.setModel(self.model)
74
+ self.tableView.resizeColumnsToContents()
75
+ self.tableView.resizeRowsToContents()
76
+
77
+ def load_pref(self) -> None:
78
+ """
79
+ Loads the preferences from the config file into the self.pref dictionary.
80
+
81
+ Parameters
82
+ ----------
83
+ None
84
+
85
+ Returns
86
+ -------
87
+ None
88
+ """
89
+ try:
90
+ if os.path.exists(fsutils.CONFIG_FILE):
91
+ with open(
92
+ fsutils.CONFIG_FILE, "rt", encoding="utf-8"
93
+ ) as file_descriptor:
94
+ self.pref = loads(file_descriptor.read())
95
+ logger.info("%s", self.pref)
96
+ else:
97
+ self.pref["current_database"] = "ham.db"
98
+
99
+ except IOError as exception:
100
+ logger.critical("Error: %s", exception)
101
+
102
+ def load_new_db(self) -> None:
103
+ """
104
+ If the database changes reload it.
105
+
106
+ Parameters
107
+ ----------
108
+ None
109
+
110
+ Returns
111
+ -------
112
+ None
113
+ """
114
+ self.load_pref()
115
+ self.dbname = fsutils.USER_DATA_PATH / self.pref.get(
116
+ "current_database", "ham.db"
117
+ )
118
+
119
+ self.db.setDatabaseName(f"{self.dbname}")
120
+ if not self.db.open():
121
+ print("Error: Could not open database")
122
+ return
123
+ self.setWindowTitle(
124
+ f"Log Display - {self.pref.get('current_database', 'ham.db')}"
125
+ )
126
+
127
+ def msg_from_main(self, msg):
128
+ """"""
129
+ if msg.get("cmd", "") in ("UPDATELOG", "CONTACTCHANGED", "DELETED"):
130
+ ...
131
+ self.update_model()
132
+ if msg.get("cmd", "") == "NEWDB":
133
+ ...
134
+ self.load_new_db()
135
+ self.update_model()
@@ -29,14 +29,15 @@ def prefer_prefix_score(query: str, candidate: str, **kwargs) -> int:
29
29
  score = 0.8 * score
30
30
  return int(round(score))
31
31
 
32
+
32
33
  @lru_cache(maxsize=1024) # You can adjust this as needed
33
34
  def prefix_bias_score(query: str, candidate: str, **kwargs) -> int:
34
35
  """Return a score based on the quality of the match."""
35
36
  score = fuzz.QRatio(query, candidate)
36
37
 
37
- if candidate[:len(query)] == query:
38
+ if candidate[: len(query)] == query:
38
39
  return score
39
- return int(score*0.8)
40
+ return int(score * 0.8)
40
41
 
41
42
 
42
43
  class SCP:
@@ -53,18 +54,21 @@ class SCP:
53
54
  - Returns True if successful
54
55
  - Otherwise False
55
56
  """
56
- with requests.Session() as session:
57
- the_request = session.get(MASTER_SCP_URL)
58
- if the_request.status_code == 200:
59
- with open(Path(self.app_data_path) / "MASTER.SCP", "wb+") as file:
60
- file.write(the_request.content)
61
- return True
57
+ try:
58
+ with requests.Session() as session:
59
+ the_request = session.get(MASTER_SCP_URL)
60
+ if the_request.status_code == 200:
61
+ with open(Path(self.app_data_path) / "MASTER.SCP", "wb+") as file:
62
+ file.write(the_request.content)
63
+ return True
64
+ except requests.exceptions.RequestException as exception:
65
+ logger.critical("update_masterscp: %s", exception)
62
66
  return False
63
67
 
64
68
  def read_scp(self):
65
69
  """
66
70
  Reads in a list of known contesters into an internal dictionary
67
- """
71
+ """
68
72
  try:
69
73
  with open(
70
74
  Path(self.app_data_path) / "MASTER.SCP", "r", encoding="utf-8"
@@ -74,22 +78,21 @@ class SCP:
74
78
  except IOError as exception:
75
79
  logger.critical("read_scp: read error: %s", exception)
76
80
 
77
-
78
81
  def super_check(self, acall: str) -> list:
79
82
 
80
83
  if len(acall) > 1:
81
84
  # Compute similarity scores between `acall` and all items in `self.scp`
82
85
  similarity_scores = process.cdist(
83
- [acall], self.scp, scorer=prefix_bias_score, workers=-1,score_cutoff=60
86
+ [acall], self.scp, scorer=prefix_bias_score, workers=-1, score_cutoff=60
84
87
  )
85
88
 
86
89
  # Sort and retrieve the top 20 matches with their indices
87
- top_matches = sorted(
88
- enumerate(similarity_scores[0]), key=lambda x: -x[1]
89
- )[:20]
90
+ top_matches = sorted(enumerate(similarity_scores[0]), key=lambda x: -x[1])[
91
+ :20
92
+ ]
90
93
 
91
94
  # Extract the corresponding strings from `self.scp`
92
95
  matches = [self.scp[idx] for idx, score in top_matches if score > 0]
93
96
 
94
97
  return matches
95
- return []
98
+ return []
not1mm/lib/version.py CHANGED
@@ -1,3 +1,3 @@
1
1
  """It's the version"""
2
2
 
3
- __version__ = "25.6.2"
3
+ __version__ = "25.6.4"
not1mm/statistics.py CHANGED
@@ -34,12 +34,6 @@ class StatsWindow(QDockWidget):
34
34
  )
35
35
  self.database = DataBase(self.dbname, fsutils.APP_DATA_PATH)
36
36
  self.database.current_contest = self.pref.get("contest", 0)
37
- self.load_pref()
38
- self.dbname = fsutils.USER_DATA_PATH / self.pref.get(
39
- "current_database", "ham.db"
40
- )
41
- self.database = DataBase(self.dbname, fsutils.APP_DATA_PATH)
42
- self.database.current_contest = self.pref.get("contest", 0)
43
37
  uic.loadUi(fsutils.APP_DATA_PATH / "statistics.ui", self)
44
38
 
45
39
  def msg_from_main(self, packet):
@@ -56,12 +50,7 @@ class StatsWindow(QDockWidget):
56
50
  if self.active is False:
57
51
  return
58
52
 
59
- if packet.get("cmd", "") == "CONTACTCHANGED":
60
- self.get_run_and_total_qs()
61
- return
62
-
63
- if packet.get("cmd", "") == "UPDATELOG":
64
- logger.debug("External refresh command.")
53
+ if packet.get("cmd", "") in ("CONTACTCHANGED", "UPDATELOG", "DELETED"):
65
54
  self.get_run_and_total_qs()
66
55
  return
67
56
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: not1mm
3
- Version: 25.6.2
3
+ Version: 25.6.4
4
4
  Summary: NOT1MM Logger
5
5
  Author-email: Michael Bridak <michael.bridak@gmail.com>
6
6
  License: GPL-3.0-or-later
@@ -244,6 +244,8 @@ generated, 'cause I'm lazy, list of those who've submitted PR's.
244
244
 
245
245
  ## Recent Changes
246
246
 
247
+ - [25-6-4] Add a DXCC/Band widget.
248
+ - [25-6-3] Fix crash caused by SSL cert expiration from supercheckpartial.com.
247
249
  - [25-6-2] Crash Fix. Change initial self.pref from None to a dict.
248
250
  - [25-6-1] Merged changes from @term73, updating ES Field Day.
249
251
 
@@ -348,7 +350,7 @@ parameters.
348
350
 
349
351
  ## Configuration Settings
350
352
 
351
- To setup your CAT control, CW keyer, Callsign lookups, select
353
+ To setup your CAT control, CW keyer, and callsign lookups, select
352
354
  `File` > `Configuration Settings`
353
355
 
354
356
  The tabs for groups and n1mm are disabled and are for future expansion.
@@ -357,31 +359,36 @@ The tabs for groups and n1mm are disabled and are for future expansion.
357
359
 
358
360
  ### Lookup
359
361
 
360
- For callsign lookup, Two services are supported. QRZ and HamQTH. They require a
361
- username and password, Enter it here.
362
+ For callsign lookup, two services are supported: QRZ and HamQTH. They require a
363
+ username and password. Enter that information here.
362
364
 
363
365
  ### Soundcard
364
366
 
365
- Choose the sound output device for the voice keyer.
367
+ Choose the appropriate sound output device for the voice keyer.
366
368
 
367
369
  ### CAT Control
368
370
 
369
- Under the `CAT` TAB, you can choose either `rigctld` normally with an IP of
370
- `127.0.0.1` and a port of `4532`. Or `flrig`, IP normally of `127.0.0.1` and a
371
+ Under the `CAT` tab, you can choose either: `rigctld` normally with an IP of
372
+ `127.0.0.1` and a port of `4532` or `flrig` with an IP normally of `127.0.0.1` and a
371
373
  port of `12345`. `None` is always an option, but is it really? There's an
372
374
  onscreen icon for CAT status. Green good, Red bad, Grey neither.
373
375
 
374
- ### CW Keyer interface
376
+ ### CW Keyer Interface
375
377
 
376
- Under the `CW` TAB, There are three options. `cwdaemon`, which normally uses IP
377
- `127.0.0.1`port `6789`. `pywinkeyer` which normally uses IP `127.0.0.1` port `8000` and
378
- `CAT` which if your radio supports it, sends Morse characters via rigctld.
378
+ Under the `CW` tab, there are three options: i) `cwdaemon` that normally uses IP address
379
+ `127.0.0.1`port `6789`, ii) `pywinkeyer` that normally uses IP address `127.0.0.1` port `8000`, and
380
+ iii) `CAT` that sends Morse characters via rigctld if your radio supports it.
381
+
382
+ For contests that require a serial number as part of the exchange, there is an option to pad it with leading zeroes,
383
+ typically represented by the cut number "T". For example, serial number "001" can be sent as "TT1". The user can
384
+ configure the `CW Sent Nr Padding` character (default: T) and `CW Sent Nr Padding
385
+ Length` (default: 3) or specify no padding by entering length "0".
379
386
 
380
387
  ### Cluster
381
388
 
382
389
  ![Configuration Settings screen](https://github.com/mbridak/not1mm/raw/master/pic/configuration_cluster.png)
383
390
 
384
- Under the `Cluster` TAB you can change the default AR Cluster server, port and
391
+ Under the `Cluster` tab you can change the default AR Cluster server, port, and
385
392
  filter settings used for the bandmap window.
386
393
 
387
394
  ### N1MM Packets
@@ -1,14 +1,15 @@
1
1
  not1mm/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- not1mm/__main__.py,sha256=wFBkjElOJRbOfkfc9oSq15ZYO9_SckfnEgWx7mjEtuM,170823
2
+ not1mm/__main__.py,sha256=IHFJFKGAgKyPZUdi-aRDFIS--XJPdoPiV6utXx31_-I,172631
3
3
  not1mm/bandmap.py,sha256=0JmZ32UvkaPjXs2xTgowX1GLvZo5zHU_Zo9y_GL-On4,31139
4
4
  not1mm/checkwindow.py,sha256=zEHlw40j6Wr3rvKbCQf2lcezCoiZqaBqEvBjQU5aKW0,7630
5
+ not1mm/dxcc_tracker.py,sha256=shhH0rgiBL2gOINu9yVPoVj2hAI-oBkubb_sAbRJ-6E,4377
5
6
  not1mm/fsutils.py,sha256=ukHKxKTeNKxKwqRaJjtzRShL4X5Xl0jRBbADyy3Ifp8,1701
6
7
  not1mm/logwindow.py,sha256=O2dMaT_BYWsXA_dxsEHN92JwN-qVGy9nmH0MCMaG9gY,42830
7
8
  not1mm/lookupservice.py,sha256=GkY_qHZfrW6XHf8upIoaG4hCFqm0fg6Ganu9ConGrIc,2628
8
9
  not1mm/radio.py,sha256=4Lysf9BY3vdtYCHwKfzO5WN7IGyh4_lKSVuQ6F4Z08g,5536
9
10
  not1mm/ratewindow.py,sha256=iBjqdOetIEX0wSwdGM89Ibt4gVlFdE-K8HQPnkVPVOg,6965
10
11
  not1mm/rtc_service.py,sha256=axAwnCBuTr-QL0YwXtWvg9tjwhcFsiiEZFgFjOofX6k,2816
11
- not1mm/statistics.py,sha256=TrLm50VcY_pYv3K-THSOLgAfTKolGgYnRViitJi9jh0,7767
12
+ not1mm/statistics.py,sha256=yvEHCDtz4VHEg1gJ5CHAoB9lhZOevBxbeMo5WsCii2w,7355
12
13
  not1mm/test.py,sha256=BNhsSvLnNG5hN4pywIWnj4pUBI-wQYY4Ejfbl97knmw,1198
13
14
  not1mm/vfo.py,sha256=SsqinokSd8BqVp6l-_DGRKcNN9Uc9JiFYXDl9Ycep1o,10111
14
15
  not1mm/voice_keying.py,sha256=HZImqC5NgnyW2nknNYQ3b7I8-6S_hxpq5G4RcIRXn_k,3005
@@ -26,6 +27,7 @@ not1mm/data/contests.sql,sha256=4hmJCDvrbxnA_Y5S4T5o52TZieeFk6QUwFerwlFePNA,8930
26
27
  not1mm/data/cty.json,sha256=3Nk98AoENvBB4RwJCTheDVCjJ1AvX4ik5kg2R0iU1X0,4948509
27
28
  not1mm/data/cwmacros.txt,sha256=NztufsX6R52gAO7VyJ2AHr7wOh41pJTwHKh5Lcs32ds,468
28
29
  not1mm/data/donors.html,sha256=alw5wpOdAX4hcJLx7NyhNRdSdmWOiTlD-CQXVWcULXU,333
30
+ not1mm/data/dxcc_tracker.ui,sha256=1tDkNG4Q2IaFlE-5yAq0eAI3hYkrWQ6NAMp5DD8TvCU,580
29
31
  not1mm/data/editcontact.ui,sha256=ax-pm4TeECpHl3LSb5z4L403WjPWXZ9KV2it_6gIjqk,27404
30
32
  not1mm/data/editmacro.ui,sha256=wbLuNwLsMBd9hEKs_6sH3ir5BynH9Bk-u8nWRjNyQ8w,2689
31
33
  not1mm/data/greendot.png,sha256=El9TomJcGtViRcHOR7kMxGzjzvYs0TSAqOb3tZv0JDA,368
@@ -35,7 +37,7 @@ not1mm/data/k6gte.not1mm-32.png,sha256=XdTsCa3xqwTfn26Ga7RwO_Vlbg_77RKkSc8bMxVcC
35
37
  not1mm/data/k6gte.not1mm-64.png,sha256=6ku45Gq1g5ezh04F07osoKRtanb3e4kbx5XdIEh3N90,2925
36
38
  not1mm/data/logwindow.ui,sha256=vfkNdzJgFs3tTOBKLDavF2zVMvNHWOZ82fAErRi6pQY,1436
37
39
  not1mm/data/logwindowx.ui,sha256=9FzDJtLRpagvAWcDjFdB9NnvNZ4bVxdTNHy1Jit2ido,1610
38
- not1mm/data/main.ui,sha256=gEWmfXmqLM-DiujjnPdU-4buYJF9TQxS9gE0JlVv_4Y,65142
40
+ not1mm/data/main.ui,sha256=lr3_rwmyywfYQtw9GNf1leeJ0fe6Y2Xy3-cdV4kmKi4,65425
39
41
  not1mm/data/new_contest.ui,sha256=i-WThxa9IBstyAMCRtNMB4NVPpV3fekUIX1YDYPyuOQ,25521
40
42
  not1mm/data/not1mm.html,sha256=c9-mfjMwDt4f5pySUruz2gREW33CQ2_rCddM2z5CZQo,23273
41
43
  not1mm/data/opon.ui,sha256=mC4OhoVIfR1H9IqHAKXliPMm8VOVmxSEadpsFQ7XnS4,2247
@@ -119,8 +121,8 @@ not1mm/lib/new_contest.py,sha256=IznTDMq7yXHB6zBoGUEC_WDYPCPpsSZW4wwMJi16zK0,816
119
121
  not1mm/lib/plugin_common.py,sha256=nqiUq11T9Wz8RDrRen4Zvp-KXVWUYcIp5JPZwqmu2Oo,13913
120
122
  not1mm/lib/select_contest.py,sha256=WsptLuwkouIHeocJL3oZ6-eUfEnhpwdc-x7eMZ_TIVM,359
121
123
  not1mm/lib/settings.py,sha256=5xnsagH48qGeCDhfxPWW9yaXtv8wT13yoIVvYt8h_Qs,16023
122
- not1mm/lib/super_check_partial.py,sha256=Hp89cPHQOwVuGjAjdMaJPdHEyrJiN3xNu841MdiZAjo,2948
123
- not1mm/lib/version.py,sha256=dBiyUcajZgmjLwNr2OG7KC2bJLiBds26sZX-sQtqbIM,47
124
+ not1mm/lib/super_check_partial.py,sha256=jX7DjHesEV4KNVQbddJui0wAsYHerikH7W0iPv7PXQw,3110
125
+ not1mm/lib/version.py,sha256=iOQDkhN7eZvJIMmdRhXwA0HD1relkhKvEjCRTD0YPXk,47
124
126
  not1mm/lib/versiontest.py,sha256=8vDNptuBBunn-1IGkjNaquehqBYUJyjrPSF8Igmd4_Y,1286
125
127
  not1mm/plugins/10_10_fall_cw.py,sha256=oJh3JKqjOpnWElSlZpiQ631UnaOd8qra5s9bl_QoInk,14783
126
128
  not1mm/plugins/10_10_spring_cw.py,sha256=p7dSDtbFK0e6Xouw2V6swYn3VFVgHKyx4IfRWyBjMZY,14786
@@ -184,9 +186,9 @@ not1mm/plugins/ukeidx.py,sha256=ZsIFXgOSwjuKNmN4W_C0TAgGqgnabJGNLMHwGkl3_bk,1910
184
186
  not1mm/plugins/vhf_sprint.py,sha256=a9QFTpv8XUbZ_GLjdVCh7svykFa-gXOWwKFZ6MD3uQM,19289
185
187
  not1mm/plugins/weekly_rtty.py,sha256=C8Xs3Q5UgSYx-mFFar8BVARWtmqlyrbeC98Ubzb4UN8,20128
186
188
  not1mm/plugins/winter_field_day.py,sha256=hmAMgkdqIXtnCNyUp8J9Bb8liN8wj10wps6ROuG-Bok,15284
187
- not1mm-25.6.2.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
188
- not1mm-25.6.2.dist-info/METADATA,sha256=yB2SIfHLStaoq9r49o9HEgqZkTf8chEOl-bNFxbctpY,34118
189
- not1mm-25.6.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
190
- not1mm-25.6.2.dist-info/entry_points.txt,sha256=pMcZk_0dxFgLkcUkF0Q874ojpwOmF3OL6EKw9LgvocM,47
191
- not1mm-25.6.2.dist-info/top_level.txt,sha256=0YmTxEcDzQlzXub-lXASvoLpg_mt1c2thb5cVkDf5J4,7
192
- not1mm-25.6.2.dist-info/RECORD,,
189
+ not1mm-25.6.4.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
190
+ not1mm-25.6.4.dist-info/METADATA,sha256=67UQJHHsXjGWX5IQ2ZW3P-n84rUv8V3qh2gGvX3ese0,34676
191
+ not1mm-25.6.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
192
+ not1mm-25.6.4.dist-info/entry_points.txt,sha256=pMcZk_0dxFgLkcUkF0Q874ojpwOmF3OL6EKw9LgvocM,47
193
+ not1mm-25.6.4.dist-info/top_level.txt,sha256=0YmTxEcDzQlzXub-lXASvoLpg_mt1c2thb5cVkDf5J4,7
194
+ not1mm-25.6.4.dist-info/RECORD,,