not1mm 24.4.2__tar.gz → 24.4.4__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.
Files changed (152) hide show
  1. {not1mm-24.4.2 → not1mm-24.4.4}/PKG-INFO +7 -6
  2. {not1mm-24.4.2 → not1mm-24.4.4}/README.md +6 -5
  3. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/__main__.py +29 -26
  4. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/bandmap.py +10 -4
  5. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/checkwindow.py +9 -5
  6. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/data/vfo.ui +12 -0
  7. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/lib/lookup.py +6 -0
  8. not1mm-24.4.4/not1mm/lib/new_contest.py +26 -0
  9. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/lib/version.py +1 -1
  10. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/logwindow.py +9 -3
  11. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/plugins/10_10_fall_cw.py +2 -0
  12. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/plugins/10_10_spring_cw.py +2 -0
  13. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/plugins/10_10_summer_phone.py +2 -0
  14. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/plugins/10_10_winter_phone.py +2 -0
  15. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/plugins/arrl_10m.py +2 -0
  16. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/plugins/arrl_dx_cw.py +2 -0
  17. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/plugins/arrl_dx_ssb.py +2 -0
  18. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/plugins/arrl_field_day.py +2 -0
  19. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/plugins/arrl_rtty_ru.py +2 -0
  20. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/plugins/arrl_ss_cw.py +2 -5
  21. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/plugins/arrl_ss_phone.py +2 -5
  22. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/plugins/arrl_vhf_jan.py +2 -0
  23. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/plugins/arrl_vhf_jun.py +2 -0
  24. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/plugins/arrl_vhf_sep.py +2 -0
  25. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/plugins/canada_day.py +2 -0
  26. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/plugins/cq_160_cw.py +2 -0
  27. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/plugins/cq_160_ssb.py +2 -0
  28. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/plugins/cq_wpx_cw.py +2 -0
  29. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/plugins/cq_wpx_ssb.py +2 -0
  30. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/plugins/cq_ww_cw.py +2 -0
  31. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/plugins/cq_ww_ssb.py +2 -0
  32. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/plugins/cwt.py +3 -0
  33. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/plugins/general_logging.py +1 -1
  34. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/plugins/iaru_hf.py +2 -0
  35. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/plugins/jidx_cw.py +2 -0
  36. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/plugins/jidx_ph.py +2 -0
  37. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/plugins/naqp_cw.py +2 -0
  38. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/plugins/naqp_ssb.py +2 -0
  39. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/plugins/phone_weekly_test.py +2 -0
  40. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/plugins/stew_perry_topband.py +1 -0
  41. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/plugins/winter_field_day.py +2 -0
  42. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/vfo.py +15 -7
  43. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm.egg-info/PKG-INFO +7 -6
  44. {not1mm-24.4.2 → not1mm-24.4.4}/pyproject.toml +1 -1
  45. not1mm-24.4.2/not1mm/lib/new_contest.py +0 -15
  46. {not1mm-24.4.2 → not1mm-24.4.4}/LICENSE +0 -0
  47. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/__init__.py +0 -0
  48. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/data/JetBrainsMono-Regular.ttf +0 -0
  49. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/data/MASTER.SCP +0 -0
  50. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/data/about.ui +0 -0
  51. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/data/alpha bravo charlie delta.txt +0 -0
  52. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/data/bandmap.ui +0 -0
  53. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/data/check.png +0 -0
  54. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/data/checkwindow.ui +0 -0
  55. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/data/configuration.ui +0 -0
  56. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/data/contests.sql +0 -0
  57. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/data/cty.json +0 -0
  58. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/data/cwmacros.txt +0 -0
  59. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/data/donors.html +0 -0
  60. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/data/editcontact.ui +0 -0
  61. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/data/editmacro.ui +0 -0
  62. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/data/greendot.png +0 -0
  63. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/data/k6gte-not1mm.desktop +0 -0
  64. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/data/k6gte.not1mm-128.png +0 -0
  65. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/data/k6gte.not1mm-32.png +0 -0
  66. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/data/k6gte.not1mm-64.png +0 -0
  67. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/data/logwindow.ui +0 -0
  68. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/data/logwindowx.ui +0 -0
  69. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/data/main.ui +0 -0
  70. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/data/new_contest.ui +0 -0
  71. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/data/not1mm.html +0 -0
  72. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/data/opon.ui +0 -0
  73. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/data/phonetics/0.wav +0 -0
  74. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/data/phonetics/1.wav +0 -0
  75. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/data/phonetics/2.wav +0 -0
  76. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/data/phonetics/3.wav +0 -0
  77. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/data/phonetics/4.wav +0 -0
  78. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/data/phonetics/5.wav +0 -0
  79. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/data/phonetics/6.wav +0 -0
  80. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/data/phonetics/7.wav +0 -0
  81. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/data/phonetics/73.wav +0 -0
  82. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/data/phonetics/8.wav +0 -0
  83. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/data/phonetics/9.wav +0 -0
  84. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/data/phonetics/a.wav +0 -0
  85. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/data/phonetics/again.wav +0 -0
  86. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/data/phonetics/b.wav +0 -0
  87. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/data/phonetics/c.wav +0 -0
  88. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/data/phonetics/contest.wav +0 -0
  89. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/data/phonetics/cq.wav +0 -0
  90. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/data/phonetics/d.wav +0 -0
  91. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/data/phonetics/e.wav +0 -0
  92. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/data/phonetics/f.wav +0 -0
  93. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/data/phonetics/g.wav +0 -0
  94. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/data/phonetics/h.wav +0 -0
  95. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/data/phonetics/i.wav +0 -0
  96. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/data/phonetics/j.wav +0 -0
  97. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/data/phonetics/k.wav +0 -0
  98. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/data/phonetics/k6gte.wav +0 -0
  99. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/data/phonetics/l.wav +0 -0
  100. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/data/phonetics/m.wav +0 -0
  101. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/data/phonetics/mynumber.wav +0 -0
  102. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/data/phonetics/n.wav +0 -0
  103. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/data/phonetics/nil.wav +0 -0
  104. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/data/phonetics/o.wav +0 -0
  105. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/data/phonetics/p.wav +0 -0
  106. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/data/phonetics/q.wav +0 -0
  107. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/data/phonetics/r.wav +0 -0
  108. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/data/phonetics/roger.wav +0 -0
  109. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/data/phonetics/s.wav +0 -0
  110. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/data/phonetics/space.wav +0 -0
  111. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/data/phonetics/t.wav +0 -0
  112. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/data/phonetics/thankyou.wav +0 -0
  113. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/data/phonetics/thankyouqrz.wav +0 -0
  114. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/data/phonetics/u.wav +0 -0
  115. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/data/phonetics/v.wav +0 -0
  116. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/data/phonetics/w.wav +0 -0
  117. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/data/phonetics/x.wav +0 -0
  118. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/data/phonetics/y.wav +0 -0
  119. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/data/phonetics/yourcall.wav +0 -0
  120. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/data/phonetics/z.wav +0 -0
  121. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/data/pickcontest.ui +0 -0
  122. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/data/radio_green.png +0 -0
  123. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/data/radio_grey.png +0 -0
  124. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/data/radio_red.png +0 -0
  125. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/data/reddot.png +0 -0
  126. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/data/settings.ui +0 -0
  127. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/data/ssbmacros.txt +0 -0
  128. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/fsutils.py +0 -0
  129. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/lib/__init__.py +0 -0
  130. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/lib/about.py +0 -0
  131. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/lib/cat_interface.py +0 -0
  132. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/lib/cwinterface.py +0 -0
  133. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/lib/database.py +0 -0
  134. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/lib/edit_contact.py +0 -0
  135. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/lib/edit_macro.py +0 -0
  136. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/lib/edit_opon.py +0 -0
  137. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/lib/edit_station.py +0 -0
  138. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/lib/ham_utility.py +0 -0
  139. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/lib/multicast.py +0 -0
  140. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/lib/n1mm.py +0 -0
  141. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/lib/plugin_common.py +0 -0
  142. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/lib/select_contest.py +0 -0
  143. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/lib/settings.py +0 -0
  144. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/lib/super_check_partial.py +0 -0
  145. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/lib/versiontest.py +0 -0
  146. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm/plugins/__init__.py +0 -0
  147. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm.egg-info/SOURCES.txt +0 -0
  148. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm.egg-info/dependency_links.txt +0 -0
  149. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm.egg-info/entry_points.txt +0 -0
  150. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm.egg-info/requires.txt +0 -0
  151. {not1mm-24.4.2 → not1mm-24.4.4}/not1mm.egg-info/top_level.txt +0 -0
  152. {not1mm-24.4.2 → not1mm-24.4.4}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: not1mm
3
- Version: 24.4.2
3
+ Version: 24.4.4
4
4
  Summary: NOT1MM Logger
5
5
  Author-email: Michael Bridak <michael.bridak@gmail.com>
6
6
  Project-URL: Homepage, https://github.com/mbridak/not1mm
@@ -32,17 +32,17 @@ Requires-Dist: Levenshtein
32
32
 
33
33
  # Not1MM
34
34
 
35
- The worlds #1 unfinished contest logger <sup>*According to my daughter Corinna.<sup>
35
+ ![logo](https://github.com/mbridak/not1mm/raw/master/not1mm/data/k6gte.not1mm.svg)
36
+
37
+ The worlds #1 unfinished contest logger <sup>*According to my daughter Corinna.<sup>
36
38
 
37
39
  [![PyPI](https://img.shields.io/pypi/v/not1mm)](https://pypi.org/project/not1mm/)
38
40
  [![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)
39
41
  [![Python: 3.10+](https://img.shields.io/badge/python-3.9+-blue.svg)](https://www.python.org/downloads/)
40
- [![Made With:PyQt5](https://img.shields.io/badge/Made%20with-PyQt5-red)](https://pypi.org/project/PyQt5/)
42
+ [![Made With:PyQt6](https://img.shields.io/badge/Made%20with-PyQt6-blue)](https://pypi.org/project/PyQt6/)
41
43
  [![Code Maturity:Snot Nosed](https://img.shields.io/badge/Code%20Maturity-Snot%20Nosed-red)](https://xkcd.com/1695/)
42
44
  [![PyPI - Downloads](https://img.shields.io/pypi/dm/not1mm)](https://pypi.org/project/not1mm/)
43
45
 
44
- ![logo](https://github.com/mbridak/not1mm/raw/master/not1mm/data/k6gte.not1mm.svg)
45
-
46
46
  - [Not1MM](#not1mm)
47
47
  - [What and why is Not1MM](#what-and-why-is-not1mm)
48
48
  - [Current state](#current-state)
@@ -177,6 +177,7 @@ I wish to thank those who've contributed to the project.
177
177
 
178
178
  ## Recent Changes
179
179
 
180
+ - [24-4-4] Added per-contest echange hint when adding new contest.
180
181
  - [24-4-2] Migrated to PyQt6. I'm sure there are broken things.
181
182
  - [24-4-1-2] Added color text indicators to the Check Partial window. Poached the code from @kyleboyle. Thanks! Fixed the Log, VFO and Check Partial windows to be actual docking widgets. Refocus call field after double clicking on item in the check partial window.
182
183
  - [24-4-1] Removed some un-needed loops and widgets from the check window. Fixed docking to the left side.
@@ -207,7 +208,7 @@ noted the minimum steps needed to install not1mm.
207
208
  ```bash
208
209
  sudo apt update
209
210
  sudo apt upgrade
210
- sudo apt install -y libportaudio2 python3-pip python3-pyqt5 python3-numpy
211
+ sudo apt install -y libportaudio2 python3-pip python3-pyqt6 python3-numpy
211
212
  pip install -U not1mm
212
213
  ```
213
214
 
@@ -1,16 +1,16 @@
1
1
  # Not1MM
2
2
 
3
- The worlds #1 unfinished contest logger <sup>*According to my daughter Corinna.<sup>
3
+ ![logo](https://github.com/mbridak/not1mm/raw/master/not1mm/data/k6gte.not1mm.svg)
4
+
5
+ The worlds #1 unfinished contest logger <sup>*According to my daughter Corinna.<sup>
4
6
 
5
7
  [![PyPI](https://img.shields.io/pypi/v/not1mm)](https://pypi.org/project/not1mm/)
6
8
  [![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)
7
9
  [![Python: 3.10+](https://img.shields.io/badge/python-3.9+-blue.svg)](https://www.python.org/downloads/)
8
- [![Made With:PyQt5](https://img.shields.io/badge/Made%20with-PyQt5-red)](https://pypi.org/project/PyQt5/)
10
+ [![Made With:PyQt6](https://img.shields.io/badge/Made%20with-PyQt6-blue)](https://pypi.org/project/PyQt6/)
9
11
  [![Code Maturity:Snot Nosed](https://img.shields.io/badge/Code%20Maturity-Snot%20Nosed-red)](https://xkcd.com/1695/)
10
12
  [![PyPI - Downloads](https://img.shields.io/pypi/dm/not1mm)](https://pypi.org/project/not1mm/)
11
13
 
12
- ![logo](https://github.com/mbridak/not1mm/raw/master/not1mm/data/k6gte.not1mm.svg)
13
-
14
14
  - [Not1MM](#not1mm)
15
15
  - [What and why is Not1MM](#what-and-why-is-not1mm)
16
16
  - [Current state](#current-state)
@@ -145,6 +145,7 @@ I wish to thank those who've contributed to the project.
145
145
 
146
146
  ## Recent Changes
147
147
 
148
+ - [24-4-4] Added per-contest echange hint when adding new contest.
148
149
  - [24-4-2] Migrated to PyQt6. I'm sure there are broken things.
149
150
  - [24-4-1-2] Added color text indicators to the Check Partial window. Poached the code from @kyleboyle. Thanks! Fixed the Log, VFO and Check Partial windows to be actual docking widgets. Refocus call field after double clicking on item in the check partial window.
150
151
  - [24-4-1] Removed some un-needed loops and widgets from the check window. Fixed docking to the left side.
@@ -175,7 +176,7 @@ noted the minimum steps needed to install not1mm.
175
176
  ```bash
176
177
  sudo apt update
177
178
  sudo apt upgrade
178
- sudo apt install -y libportaudio2 python3-pip python3-pyqt5 python3-numpy
179
+ sudo apt install -y libportaudio2 python3-pip python3-pyqt6 python3-numpy
179
180
  pip install -U not1mm
180
181
  ```
181
182
 
@@ -18,7 +18,6 @@ import platform
18
18
  import re
19
19
  import socket
20
20
 
21
- # import subprocess
22
21
  import sys
23
22
  import threading
24
23
  import uuid
@@ -34,7 +33,7 @@ import soundfile as sf
34
33
  from PyQt6 import QtCore, QtGui, QtWidgets, uic
35
34
  from PyQt6.QtCore import QDir, Qt
36
35
  from PyQt6.QtGui import QFontDatabase, QColorConstants
37
- from PyQt6.QtWidgets import QFileDialog, QDockWidget
36
+ from PyQt6.QtWidgets import QFileDialog
38
37
 
39
38
  from not1mm.lib.about import About
40
39
  from not1mm.lib.cat_interface import CAT
@@ -1390,32 +1389,34 @@ class MainWindow(QtWidgets.QMainWindow):
1390
1389
 
1391
1390
  def launch_log_window(self) -> None:
1392
1391
  """Launch the log window"""
1393
- if not self.log_window:
1394
- self.log_window = LogWindow()
1395
- self.addDockWidget(Qt.DockWidgetArea.BottomDockWidgetArea, self.log_window)
1392
+ if self.log_window:
1393
+ self.log_window.close()
1394
+ self.log_window = LogWindow()
1395
+ self.addDockWidget(Qt.DockWidgetArea.BottomDockWidgetArea, self.log_window)
1396
1396
  self.log_window.show()
1397
1397
 
1398
1398
  def launch_bandmap_window(self) -> None:
1399
1399
  """Launch the bandmap window"""
1400
- if not self.bandmap_window:
1401
- self.bandmap_window = BandMapWindow()
1402
- self.addDockWidget(
1403
- Qt.DockWidgetArea.RightDockWidgetArea, self.bandmap_window
1404
- )
1400
+ if self.bandmap_window:
1401
+ self.bandmap_window.close()
1402
+ self.bandmap_window = BandMapWindow()
1403
+ self.addDockWidget(Qt.DockWidgetArea.RightDockWidgetArea, self.bandmap_window)
1405
1404
  self.bandmap_window.show()
1406
1405
 
1407
1406
  def launch_check_window(self) -> None:
1408
1407
  """Launch the check window"""
1409
- if not self.check_window:
1410
- self.check_window = CheckWindow()
1411
- self.addDockWidget(Qt.DockWidgetArea.RightDockWidgetArea, self.check_window)
1408
+ if self.check_window:
1409
+ self.check_window.close()
1410
+ self.check_window = CheckWindow()
1411
+ self.addDockWidget(Qt.DockWidgetArea.RightDockWidgetArea, self.check_window)
1412
1412
  self.check_window.show()
1413
1413
 
1414
1414
  def launch_vfo(self) -> None:
1415
1415
  """Launch the VFO window"""
1416
- if not self.vfo_window:
1417
- self.vfo_window = VfoWindow()
1418
- self.addDockWidget(Qt.DockWidgetArea.RightDockWidgetArea, self.vfo_window)
1416
+ if self.vfo_window:
1417
+ self.vfo_window.close()
1418
+ self.vfo_window = VfoWindow()
1419
+ self.addDockWidget(Qt.DockWidgetArea.RightDockWidgetArea, self.vfo_window)
1419
1420
  self.vfo_window.show()
1420
1421
 
1421
1422
  def clear_band_indicators(self) -> None:
@@ -2949,12 +2950,14 @@ class MainWindow(QtWidgets.QMainWindow):
2949
2950
  debug_response = f"{response}"
2950
2951
  logger.debug("The Response: %s\n", debug_response)
2951
2952
  if response:
2952
- theirgrid = response.get("grid")
2953
+ theirgrid = response.get("grid", "")
2953
2954
  self.contact["GridSquare"] = theirgrid
2954
- _theircountry = response.get("country")
2955
+ _theircountry = response.get("country", "")
2955
2956
  if self.station.get("GridSquare", ""):
2956
2957
  heading = bearing(self.station.get("GridSquare", ""), theirgrid)
2957
- kilometers = distance(self.station.get("GridSquare"), theirgrid)
2958
+ kilometers = distance(
2959
+ self.station.get("GridSquare", ""), theirgrid
2960
+ )
2958
2961
  self.heading_distance.setText(
2959
2962
  f"{theirgrid} Hdg {heading}° LP {reciprocol(heading)}° / "
2960
2963
  f"distance {int(kilometers*0.621371)}mi {kilometers}km"
@@ -3178,9 +3181,9 @@ class MainWindow(QtWidgets.QMainWindow):
3178
3181
  )
3179
3182
  try:
3180
3183
  fsutils.openFileWithOS(fsutils.USER_DATA_PATH / macro_file)
3181
- except:
3182
- logger.exception(
3183
- f"Could not open file {fsutils.USER_DATA_PATH / macro_file}"
3184
+ except FileNotFoundError | PermissionError | OSError as err:
3185
+ logger.critical(
3186
+ f"Could not open file {fsutils.USER_DATA_PATH / macro_file} {err}"
3184
3187
  )
3185
3188
 
3186
3189
  def read_cw_macros(self) -> None:
@@ -3311,18 +3314,18 @@ def install_icons() -> None:
3311
3314
  if sys.platform == "linux":
3312
3315
  os.system(
3313
3316
  "xdg-icon-resource install --size 32 --context apps --mode user "
3314
- f"{fsutils.MODULE_PATH}/data/k6gte.not1mm-32.png k6gte-not1mm"
3317
+ f"{fsutils.APP_DATA_PATH}/k6gte.not1mm-32.png k6gte-not1mm"
3315
3318
  )
3316
3319
  os.system(
3317
3320
  "xdg-icon-resource install --size 64 --context apps --mode user "
3318
- f"{fsutils.MODULE_PATH}/data/k6gte.not1mm-64.png k6gte-not1mm"
3321
+ f"{fsutils.APP_DATA_PATH}/k6gte.not1mm-64.png k6gte-not1mm"
3319
3322
  )
3320
3323
  os.system(
3321
3324
  "xdg-icon-resource install --size 128 --context apps --mode user "
3322
- f"{fsutils.MODULE_PATH}/data/k6gte.not1mm-128.png k6gte-not1mm"
3325
+ f"{fsutils.APP_DATA_PATH}/k6gte.not1mm-128.png k6gte-not1mm"
3323
3326
  )
3324
3327
  os.system(
3325
- f"xdg-desktop-menu install {fsutils.MODULE_PATH}/data/k6gte-not1mm.desktop"
3328
+ f"xdg-desktop-menu install {fsutils.APP_DATA_PATH}/k6gte-not1mm.desktop"
3326
3329
  )
3327
3330
 
3328
3331
 
@@ -17,8 +17,8 @@ from decimal import Decimal
17
17
  from json import loads
18
18
 
19
19
  from PyQt6 import QtCore, QtGui, QtWidgets, uic, QtNetwork
20
- from PyQt6.QtCore import Qt
21
20
  from PyQt6.QtGui import QColorConstants
21
+ from PyQt6.QtWidgets import QDockWidget
22
22
 
23
23
  import not1mm.fsutils as fsutils
24
24
  from not1mm.lib.multicast import Multicast
@@ -302,7 +302,7 @@ class Database:
302
302
  )
303
303
 
304
304
 
305
- class BandMapWindow(QtWidgets.QDockWidget):
305
+ class BandMapWindow(QDockWidget):
306
306
  """The BandMapWindow class."""
307
307
 
308
308
  zoom = 5
@@ -321,11 +321,17 @@ class BandMapWindow(QtWidgets.QDockWidget):
321
321
  multicast_interface = None
322
322
  text_color = QtGui.QColor(45, 45, 45)
323
323
 
324
- def __init__(self, *args, **kwargs):
325
- super().__init__(*args, **kwargs)
324
+ def __init__(self):
325
+ super().__init__()
326
326
  self._udpwatch = None
327
327
 
328
328
  uic.loadUi(fsutils.APP_DATA_PATH / "bandmap.ui", self)
329
+ self.setFeatures(
330
+ QDockWidget.DockWidgetFeature.DockWidgetMovable
331
+ | QDockWidget.DockWidgetFeature.DockWidgetFloatable
332
+ | QDockWidget.DockWidgetFeature.DockWidgetClosable
333
+ )
334
+ self.setAllowedAreas(QtCore.Qt.DockWidgetArea.AllDockWidgetAreas)
329
335
  self.settings = self.get_settings()
330
336
  self.agetime = self.clear_spot_olderSpinBox.value()
331
337
  self.clear_spot_olderSpinBox.valueChanged.connect(self.spot_aging_changed)
@@ -12,8 +12,7 @@ import queue
12
12
  from json import loads
13
13
  import Levenshtein
14
14
 
15
- from PyQt6 import QtGui, uic
16
- from PyQt6.QtCore import Qt
15
+ from PyQt6 import QtGui, uic, QtCore
17
16
  from PyQt6.QtWidgets import QLabel, QVBoxLayout, QWidget, QDockWidget
18
17
  from PyQt6.QtGui import QMouseEvent, QColorConstants
19
18
 
@@ -41,8 +40,8 @@ class CheckWindow(QDockWidget):
41
40
 
42
41
  masterScrollWidget: QWidget = None
43
42
 
44
- def __init__(self, *args, **kwargs):
45
- super().__init__(*args, **kwargs)
43
+ def __init__(self):
44
+ super().__init__()
46
45
  self.load_pref()
47
46
  self.dbname = fsutils.USER_DATA_PATH / self.pref.get(
48
47
  "current_database", "ham.db"
@@ -51,7 +50,12 @@ class CheckWindow(QDockWidget):
51
50
  self.database.current_contest = self.pref.get("contest", 0)
52
51
 
53
52
  uic.loadUi(fsutils.APP_DATA_PATH / "checkwindow.ui", self)
54
-
53
+ self.setFeatures(
54
+ QDockWidget.DockWidgetFeature.DockWidgetMovable
55
+ | QDockWidget.DockWidgetFeature.DockWidgetFloatable
56
+ | QDockWidget.DockWidgetFeature.DockWidgetClosable
57
+ )
58
+ self.setAllowedAreas(QtCore.Qt.DockWidgetArea.AllDockWidgetAreas)
55
59
  self.mscp = SCP(fsutils.APP_DATA_PATH)
56
60
  self._udpwatch = None
57
61
  self.udp_fifo = queue.Queue()
@@ -2,6 +2,9 @@
2
2
  <ui version="4.0">
3
3
  <class>DockWidget</class>
4
4
  <widget class="QDockWidget" name="DockWidget">
5
+ <property name="windowModality">
6
+ <enum>Qt::ApplicationModal</enum>
7
+ </property>
5
8
  <property name="geometry">
6
9
  <rect>
7
10
  <x>0</x>
@@ -10,6 +13,14 @@
10
13
  <height>132</height>
11
14
  </rect>
12
15
  </property>
16
+ <property name="font">
17
+ <font>
18
+ <family>JetBrains Mono</family>
19
+ </font>
20
+ </property>
21
+ <property name="features">
22
+ <set>QDockWidget::DockWidgetClosable|QDockWidget::DockWidgetFloatable|QDockWidget::DockWidgetMovable</set>
23
+ </property>
13
24
  <property name="windowTitle">
14
25
  <string>DockWidget</string>
15
26
  </property>
@@ -28,6 +39,7 @@
28
39
  <widget class="QLCDNumber" name="lcdNumber">
29
40
  <property name="font">
30
41
  <font>
42
+ <family>JetBrains Mono</family>
31
43
  <pointsize>25</pointsize>
32
44
  </font>
33
45
  </property>
@@ -8,6 +8,7 @@ HamQTH
8
8
  import logging
9
9
  import xmltodict
10
10
  import requests
11
+ from functools import lru_cache
11
12
 
12
13
  logger = logging.getLogger("lookup")
13
14
 
@@ -21,6 +22,7 @@ class HamDBlookup:
21
22
  self.url = "https://api.hamdb.org/"
22
23
  self.error = False
23
24
 
25
+ @lru_cache(maxsize=1000)
24
26
  def lookup(self, call: str) -> tuple:
25
27
  """
26
28
  Lookup a call on QRZ
@@ -172,6 +174,7 @@ class QRZlookup:
172
174
  self.session = False
173
175
  self.error = f"{exception}"
174
176
 
177
+ @lru_cache(maxsize=1000)
175
178
  def lookup(self, call: str) -> tuple:
176
179
  """
177
180
  Lookup a call on QRZ
@@ -202,6 +205,7 @@ class QRZlookup:
202
205
  root = baseroot.get("QRZDatabase")
203
206
  return root.get("Callsign")
204
207
 
208
+ @lru_cache(maxsize=1000)
205
209
  def parse_lookup(self, query_result):
206
210
  """
207
211
  Returns gridsquare and name for a callsign looked up by qrz or hamdb.
@@ -328,6 +332,7 @@ class HamQTH:
328
332
  self.error = session.get("error")
329
333
  logger.info("session: %s", self.session)
330
334
 
335
+ @lru_cache(maxsize=1000)
331
336
  def lookup(self, call: str) -> tuple:
332
337
  """
333
338
  Lookup a call on HamQTH
@@ -364,6 +369,7 @@ class HamQTH:
364
369
  the_result = self.parse_lookup(root)
365
370
  return the_result
366
371
 
372
+ @lru_cache(maxsize=1000)
367
373
  def parse_lookup(self, root) -> dict:
368
374
  """
369
375
  Returns gridsquare and name for a callsign
@@ -0,0 +1,26 @@
1
+ """New Contest Dialog"""
2
+
3
+ import importlib
4
+ from PyQt6 import QtWidgets, uic
5
+
6
+
7
+ class NewContest(QtWidgets.QDialog):
8
+ """New Contest"""
9
+
10
+ def __init__(self, app_data_path):
11
+ super().__init__(None)
12
+ uic.loadUi(app_data_path / "new_contest.ui", self)
13
+ self.buttonBox.clicked.connect(self.store)
14
+ self.contest.currentTextChanged.connect(self.add_exchange_hint)
15
+
16
+ def store(self):
17
+ """dialog magic"""
18
+
19
+ def add_exchange_hint(self):
20
+ """add hint"""
21
+ contest_name = self.contest.currentText().lower().replace(" ", "_")
22
+ temp = importlib.import_module(f"not1mm.plugins.{contest_name}")
23
+ if hasattr(temp, "EXCHANGE_HINT"):
24
+ self.exchange.setPlaceholderText(temp.EXCHANGE_HINT)
25
+ else:
26
+ self.exchange.setPlaceholderText("")
@@ -1,3 +1,3 @@
1
1
  """It's the version"""
2
2
 
3
- __version__ = "24.4.2"
3
+ __version__ = "24.4.4"
@@ -15,7 +15,7 @@ from json import loads
15
15
 
16
16
  import math
17
17
  from PyQt6 import QtCore, QtGui, QtWidgets, uic
18
- from PyQt6.QtCore import Qt, QItemSelectionModel
18
+ from PyQt6.QtCore import QItemSelectionModel
19
19
  from PyQt6.QtWidgets import QDockWidget
20
20
 
21
21
  import not1mm.fsutils as fsutils
@@ -87,8 +87,8 @@ class LogWindow(QDockWidget):
87
87
  21: "UUID",
88
88
  }
89
89
 
90
- def __init__(self, *args, **kwargs):
91
- super().__init__(*args, **kwargs)
90
+ def __init__(self):
91
+ super().__init__()
92
92
  self.table_loading = True
93
93
  self._udpwatch = None
94
94
  self.udp_fifo = queue.Queue()
@@ -103,6 +103,12 @@ class LogWindow(QDockWidget):
103
103
  self.database.current_contest = self.pref.get("contest", 0)
104
104
  self.contact = self.database.empty_contact
105
105
  uic.loadUi(fsutils.APP_DATA_PATH / "logwindow.ui", self)
106
+ self.setFeatures(
107
+ QDockWidget.DockWidgetFeature.DockWidgetMovable
108
+ | QDockWidget.DockWidgetFeature.DockWidgetFloatable
109
+ | QDockWidget.DockWidgetFeature.DockWidgetClosable
110
+ )
111
+ self.setAllowedAreas(QtCore.Qt.DockWidgetArea.AllDockWidgetAreas)
106
112
  self.setWindowTitle(
107
113
  f"QSO History - {self.pref.get('current_database', 'ham.db')}"
108
114
  )
@@ -13,6 +13,8 @@ from not1mm.lib.version import __version__
13
13
 
14
14
  logger = logging.getLogger(__name__)
15
15
 
16
+ EXCHANGE_HINT = "Name + 10-10# + SPC"
17
+
16
18
  name = "10 10 FALL CW"
17
19
  cabrillo_name = "10-10-FALL-CW"
18
20
  mode = "CW" # CW SSB BOTH RTTY
@@ -12,6 +12,8 @@ from not1mm.lib.version import __version__
12
12
 
13
13
  logger = logging.getLogger(__name__)
14
14
 
15
+ EXCHANGE_HINT = "Name + 10-10# + SPC"
16
+
15
17
  name = "10 10 SPRING CW"
16
18
  cabrillo_name = "10-10-SPRING-CW"
17
19
  mode = "CW" # CW SSB BOTH RTTY
@@ -14,6 +14,8 @@ from not1mm.lib.version import __version__
14
14
 
15
15
  logger = logging.getLogger(__name__)
16
16
 
17
+ EXCHANGE_HINT = "Name + 10-10# + SPC"
18
+
17
19
  name = "10 10 SUMMER PHONE"
18
20
  cabrillo_name = "10-10-SUMMER-PHONE"
19
21
  mode = "SSB" # CW SSB BOTH RTTY
@@ -14,6 +14,8 @@ from not1mm.lib.version import __version__
14
14
 
15
15
  logger = logging.getLogger(__name__)
16
16
 
17
+ EXCHANGE_HINT = "Name + 10-10# + SPC"
18
+
17
19
  name = "10 10 WINTER PHONE"
18
20
  cabrillo_name = "10-10-WINTER-PHONE"
19
21
  mode = "SSB" # CW SSB BOTH RTTY
@@ -57,6 +57,8 @@ from not1mm.lib.version import __version__
57
57
 
58
58
  logger = logging.getLogger(__name__)
59
59
 
60
+ EXCHANGE_HINT = "State/Province"
61
+
60
62
  name = "ARRL 10M"
61
63
  mode = "BOTH" # CW SSB BOTH RTTY
62
64
  cabrillo_name = "ARRL-10"
@@ -15,6 +15,8 @@ from not1mm.lib.version import __version__
15
15
 
16
16
  logger = logging.getLogger(__name__)
17
17
 
18
+ EXCHANGE_HINT = "State/Province"
19
+
18
20
  name = "ARRL DX CW"
19
21
  cabrillo_name = "ARRL-DX-CW"
20
22
  mode = "CW" # CW SSB BOTH RTTY
@@ -15,6 +15,8 @@ from not1mm.lib.version import __version__
15
15
 
16
16
  logger = logging.getLogger(__name__)
17
17
 
18
+ EXCHANGE_HINT = "State/Province"
19
+
18
20
  name = "ARRL DX SSB"
19
21
  cabrillo_name = "ARRL-DX-SSB"
20
22
  mode = "SSB" # CW SSB BOTH RTTY
@@ -13,6 +13,8 @@ from not1mm.lib.version import __version__
13
13
 
14
14
  logger = logging.getLogger(__name__)
15
15
 
16
+ EXCHANGE_HINT = "1D ORG"
17
+
16
18
  name = "ARRL Field Day"
17
19
  mode = "BOTH" # CW SSB BOTH RTTY
18
20
  cabrillo_name = "ARRL-FD"
@@ -8,6 +8,8 @@ from pathlib import Path
8
8
 
9
9
  from PyQt6 import QtWidgets
10
10
 
11
+ EXCHANGE_HINT = ""
12
+
11
13
  name = "ARRL RTTY Round Up"
12
14
  cabrillo_name = "ARRL-RTTY"
13
15
  mode = "BOTH" # CW SSB BOTH RTTY
@@ -14,6 +14,8 @@ from not1mm.lib.version import __version__
14
14
 
15
15
  logger = logging.getLogger(__name__)
16
16
 
17
+ EXCHANGE_HINT = "Prec Call Check Section"
18
+
17
19
  name = "ARRL Sweepstakes CW"
18
20
  cabrillo_name = "ARRL-SS-CW"
19
21
  mode = "CW" # CW SSB BOTH RTTY
@@ -381,23 +383,19 @@ def parse_exchange(self):
381
383
  for tokens in exchange.split():
382
384
  text = ""
383
385
  numb = ""
384
- print(f"'{tokens}'")
385
386
  if tokens.isdigit():
386
- print(f"{tokens} is digits")
387
387
  if sn == "":
388
388
  sn = tokens
389
389
  else:
390
390
  ck = tokens
391
391
  continue
392
392
  elif tokens.isalpha():
393
- print(f"{tokens} is alpha")
394
393
  if len(tokens) == 1:
395
394
  prec = tokens
396
395
  else:
397
396
  sec = tokens
398
397
  continue
399
398
  elif tokens.isalnum():
400
- print("isalnum")
401
399
  if tokens[:1].isalpha():
402
400
  print(f"{tokens} is callsign")
403
401
  call = tokens
@@ -406,7 +404,6 @@ def parse_exchange(self):
406
404
  if c.isalpha():
407
405
  text = tokens[i:]
408
406
  numb = tokens[:i]
409
- print(f"{tokens[:i]} {tokens[i:]}")
410
407
  break
411
408
  if len(text) == 1:
412
409
  prec = text
@@ -14,6 +14,8 @@ from not1mm.lib.version import __version__
14
14
 
15
15
  logger = logging.getLogger(__name__)
16
16
 
17
+ EXCHANGE_HINT = "Prec Call Check Section"
18
+
17
19
  name = "ARRL Sweepstakes Phone"
18
20
  cabrillo_name = "ARRL-SS-SSB"
19
21
  mode = "SSB" # CW SSB BOTH RTTY
@@ -383,30 +385,25 @@ def parse_exchange(self):
383
385
  numb = ""
384
386
  print(f"'{tokens}'")
385
387
  if tokens.isdigit():
386
- print(f"{tokens} is digits")
387
388
  if sn == "":
388
389
  sn = tokens
389
390
  else:
390
391
  ck = tokens
391
392
  continue
392
393
  elif tokens.isalpha():
393
- print(f"{tokens} is alpha")
394
394
  if len(tokens) == 1:
395
395
  prec = tokens
396
396
  else:
397
397
  sec = tokens
398
398
  continue
399
399
  elif tokens.isalnum():
400
- print("isalnum")
401
400
  if tokens[:1].isalpha():
402
- print(f"{tokens} is callsign")
403
401
  call = tokens
404
402
  continue
405
403
  for i, c in enumerate(tokens):
406
404
  if c.isalpha():
407
405
  text = tokens[i:]
408
406
  numb = tokens[:i]
409
- print(f"{tokens[:i]} {tokens[i:]}")
410
407
  break
411
408
  if len(text) == 1:
412
409
  prec = text
@@ -48,6 +48,8 @@ from not1mm.lib.version import __version__
48
48
 
49
49
  logger = logging.getLogger(__name__)
50
50
 
51
+ EXCHANGE_HINT = "4-character grid square"
52
+
51
53
  name = "ARRL VHF JAN"
52
54
  mode = "BOTH" # CW SSB BOTH RTTY
53
55
  cabrillo_name = "ARRL-VHF-JAN"
@@ -16,6 +16,8 @@ from not1mm.lib.version import __version__
16
16
 
17
17
  logger = logging.getLogger(__name__)
18
18
 
19
+ EXCHANGE_HINT = "4-character grid square"
20
+
19
21
  name = "ARRL VHF JUN"
20
22
  mode = "BOTH" # CW SSB BOTH RTTY
21
23
  cabrillo_name = "ARRL-VHF-JUN"
@@ -16,6 +16,8 @@ from not1mm.lib.version import __version__
16
16
 
17
17
  logger = logging.getLogger(__name__)
18
18
 
19
+ EXCHANGE_HINT = "4-character grid square"
20
+
19
21
  name = "ARRL VHF SEP"
20
22
  mode = "BOTH" # CW SSB BOTH RTTY
21
23
  cabrillo_name = "ARRL-VHF-SEP"
@@ -14,6 +14,8 @@ from not1mm.lib.version import __version__
14
14
 
15
15
  logger = logging.getLogger(__name__)
16
16
 
17
+ EXCHANGE_HINT = "Province/Territory"
18
+
17
19
  name = "CANADA DAY"
18
20
  cabrillo_name = "CANADA-DAY"
19
21
  mode = "BOTH" # CW SSB BOTH RTTY
@@ -15,6 +15,8 @@ from not1mm.lib.version import __version__
15
15
 
16
16
  logger = logging.getLogger(__name__)
17
17
 
18
+ EXCHANGE_HINT = "ST/Prov or DX CQ Zone"
19
+
18
20
  name = "CQ 160 CW"
19
21
  cabrillo_name = "CQ-160-CW"
20
22
  mode = "CW" # CW SSB BOTH RTTY
@@ -15,6 +15,8 @@ from not1mm.lib.version import __version__
15
15
 
16
16
  logger = logging.getLogger(__name__)
17
17
 
18
+ EXCHANGE_HINT = "ST/Prov or DX CQ Zone"
19
+
18
20
  name = "CQ 160 SSB"
19
21
  cabrillo_name = "CQ-160-SSB"
20
22
  mode = "SSB" # CW SSB BOTH RTTY