graxpert 3.2.0a0.dev8__tar.gz → 3.2.0a2__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.
- {graxpert-3.2.0a0.dev8 → graxpert-3.2.0a2}/PKG-INFO +1 -1
- graxpert-3.2.0a2/graxpert/__init__.py +3 -0
- {graxpert-3.2.0a0.dev8 → graxpert-3.2.0a2}/graxpert/ai_model_handling.py +1 -1
- {graxpert-3.2.0a0.dev8 → graxpert-3.2.0a2}/graxpert/application/app.py +18 -12
- {graxpert-3.2.0a0.dev8 → graxpert-3.2.0a2}/graxpert/cmdline_tools.py +63 -110
- {graxpert-3.2.0a0.dev8 → graxpert-3.2.0a2}/graxpert/main.py +99 -44
- graxpert-3.2.0a2/graxpert/progress.py +51 -0
- {graxpert-3.2.0a0.dev8 → graxpert-3.2.0a2}/graxpert/ui/loadingframe.py +0 -51
- graxpert-3.2.0a2/graxpert/version.py +2 -0
- graxpert-3.2.0a2/graxpert/version.py.bak +2 -0
- {graxpert-3.2.0a0.dev8 → graxpert-3.2.0a2}/graxpert.egg-info/PKG-INFO +1 -1
- {graxpert-3.2.0a0.dev8 → graxpert-3.2.0a2}/graxpert.egg-info/SOURCES.txt +1 -0
- graxpert-3.2.0a0.dev8/graxpert/ui/__init__.py +0 -1
- graxpert-3.2.0a0.dev8/graxpert/version.py +0 -2
- graxpert-3.2.0a0.dev8/graxpert/version.py.bak +0 -2
- {graxpert-3.2.0a0.dev8 → graxpert-3.2.0a2}/MANIFEST.in +0 -0
- {graxpert-3.2.0a0.dev8 → graxpert-3.2.0a2}/README.md +0 -0
- {graxpert-3.2.0a0.dev8 → graxpert-3.2.0a2}/graxpert/AstroImageRepository.py +0 -0
- {graxpert-3.2.0a0.dev8 → graxpert-3.2.0a2}/graxpert/app_state.py +0 -0
- {graxpert-3.2.0a0.dev8 → graxpert-3.2.0a2}/graxpert/application/__init__.py +0 -0
- {graxpert-3.2.0a0.dev8 → graxpert-3.2.0a2}/graxpert/application/app_events.py +0 -0
- {graxpert-3.2.0a0.dev8 → graxpert-3.2.0a2}/graxpert/application/eventbus.py +0 -0
- {graxpert-3.2.0a0.dev8 → graxpert-3.2.0a2}/graxpert/astroimage.py +0 -0
- {graxpert-3.2.0a0.dev8 → graxpert-3.2.0a2}/graxpert/background_extraction.py +0 -0
- {graxpert-3.2.0a0.dev8 → graxpert-3.2.0a2}/graxpert/background_flood_selection.py +0 -0
- {graxpert-3.2.0a0.dev8 → graxpert-3.2.0a2}/graxpert/background_grid_selection.py +0 -0
- {graxpert-3.2.0a0.dev8 → graxpert-3.2.0a2}/graxpert/commands.py +0 -0
- {graxpert-3.2.0a0.dev8 → graxpert-3.2.0a2}/graxpert/deconvolution.py +0 -0
- {graxpert-3.2.0a0.dev8 → graxpert-3.2.0a2}/graxpert/denoising.py +0 -0
- {graxpert-3.2.0a0.dev8 → graxpert-3.2.0a2}/graxpert/grid_utils.py +0 -0
- {graxpert-3.2.0a0.dev8 → graxpert-3.2.0a2}/graxpert/img/GraXpert_LOGO_Hauptvariante.png +0 -0
- {graxpert-3.2.0a0.dev8 → graxpert-3.2.0a2}/graxpert/img/Icon.png +0 -0
- {graxpert-3.2.0a0.dev8 → graxpert-3.2.0a2}/graxpert/img/LDN1235_original.jpg +0 -0
- {graxpert-3.2.0a0.dev8 → graxpert-3.2.0a2}/graxpert/img/LDN1235_processed.jpg +0 -0
- {graxpert-3.2.0a0.dev8 → graxpert-3.2.0a2}/graxpert/img/__init__.py +0 -0
- {graxpert-3.2.0a0.dev8 → graxpert-3.2.0a2}/graxpert/img/gfx_numbers.png +0 -0
- {graxpert-3.2.0a0.dev8 → graxpert-3.2.0a2}/graxpert/img/gfx_numbers.svg +0 -0
- {graxpert-3.2.0a0.dev8 → graxpert-3.2.0a2}/graxpert/img/graXpert_Startbadge_Umbriel.png +0 -0
- {graxpert-3.2.0a0.dev8 → graxpert-3.2.0a2}/graxpert/img/hourglass.png +0 -0
- {graxpert-3.2.0a0.dev8 → graxpert-3.2.0a2}/graxpert/locales/__init__.py +0 -0
- {graxpert-3.2.0a0.dev8 → graxpert-3.2.0a2}/graxpert/locales/base.pot +0 -0
- {graxpert-3.2.0a0.dev8 → graxpert-3.2.0a2}/graxpert/locales/de_DE/LC_MESSAGES/base.mo +0 -0
- {graxpert-3.2.0a0.dev8 → graxpert-3.2.0a2}/graxpert/locales/de_DE/LC_MESSAGES/base.po +0 -0
- {graxpert-3.2.0a0.dev8 → graxpert-3.2.0a2}/graxpert/localization.py +0 -0
- {graxpert-3.2.0a0.dev8 → graxpert-3.2.0a2}/graxpert/mp_logging.py +0 -0
- {graxpert-3.2.0a0.dev8 → graxpert-3.2.0a2}/graxpert/parallel_processing.py +0 -0
- {graxpert-3.2.0a0.dev8 → graxpert-3.2.0a2}/graxpert/preferences.py +0 -0
- {graxpert-3.2.0a0.dev8 → graxpert-3.2.0a2}/graxpert/radialbasisinterpolation.py +0 -0
- {graxpert-3.2.0a0.dev8 → graxpert-3.2.0a2}/graxpert/resource_utils.py +0 -0
- {graxpert-3.2.0a0.dev8 → graxpert-3.2.0a2}/graxpert/s3_secrets.py +0 -0
- {graxpert-3.2.0a0.dev8 → graxpert-3.2.0a2}/graxpert/skyall.py +0 -0
- {graxpert-3.2.0a0.dev8 → graxpert-3.2.0a2}/graxpert/stretch.py +0 -0
- {graxpert-3.2.0a0.dev8 → graxpert-3.2.0a2}/graxpert/theme/__init__.py +0 -0
- {graxpert-3.2.0a0.dev8 → graxpert-3.2.0a2}/graxpert/theme/graxpert-dark-blue.json +0 -0
- {graxpert-3.2.0a0.dev8/graxpert → graxpert-3.2.0a2/graxpert/ui}/__init__.py +0 -0
- {graxpert-3.2.0a0.dev8 → graxpert-3.2.0a2}/graxpert/ui/application_frame.py +0 -0
- {graxpert-3.2.0a0.dev8 → graxpert-3.2.0a2}/graxpert/ui/canvas.py +0 -0
- {graxpert-3.2.0a0.dev8 → graxpert-3.2.0a2}/graxpert/ui/left_menu.py +0 -0
- {graxpert-3.2.0a0.dev8 → graxpert-3.2.0a2}/graxpert/ui/right_menu.py +0 -0
- {graxpert-3.2.0a0.dev8 → graxpert-3.2.0a2}/graxpert/ui/statusbar.py +0 -0
- {graxpert-3.2.0a0.dev8 → graxpert-3.2.0a2}/graxpert/ui/styling.py +0 -0
- {graxpert-3.2.0a0.dev8 → graxpert-3.2.0a2}/graxpert/ui/tooltip.py +0 -0
- {graxpert-3.2.0a0.dev8 → graxpert-3.2.0a2}/graxpert/ui/ui_events.py +0 -0
- {graxpert-3.2.0a0.dev8 → graxpert-3.2.0a2}/graxpert/ui/widgets.py +0 -0
- {graxpert-3.2.0a0.dev8 → graxpert-3.2.0a2}/graxpert/ui_scaling.py +0 -0
- {graxpert-3.2.0a0.dev8 → graxpert-3.2.0a2}/graxpert.egg-info/dependency_links.txt +0 -0
- {graxpert-3.2.0a0.dev8 → graxpert-3.2.0a2}/graxpert.egg-info/entry_points.txt +0 -0
- {graxpert-3.2.0a0.dev8 → graxpert-3.2.0a2}/graxpert.egg-info/requires.txt +0 -0
- {graxpert-3.2.0a0.dev8 → graxpert-3.2.0a2}/graxpert.egg-info/top_level.txt +0 -0
- {graxpert-3.2.0a0.dev8 → graxpert-3.2.0a2}/img/Icon.icns +0 -0
- {graxpert-3.2.0a0.dev8 → graxpert-3.2.0a2}/img/Icon.ico +0 -0
- {graxpert-3.2.0a0.dev8 → graxpert-3.2.0a2}/img/Icon.png +0 -0
- {graxpert-3.2.0a0.dev8 → graxpert-3.2.0a2}/img/NGC7000_original.jpg +0 -0
- {graxpert-3.2.0a0.dev8 → graxpert-3.2.0a2}/img/NGC7000_processed.jpg +0 -0
- {graxpert-3.2.0a0.dev8 → graxpert-3.2.0a2}/img/graXpert_Startbadge_Ariel.png +0 -0
- {graxpert-3.2.0a0.dev8 → graxpert-3.2.0a2}/img/graXpert_Startbadge_Ariel.svg +0 -0
- {graxpert-3.2.0a0.dev8 → graxpert-3.2.0a2}/img/graXpert_Startbadge_Dione.png +0 -0
- {graxpert-3.2.0a0.dev8 → graxpert-3.2.0a2}/img/graXpert_Startbadge_Dione.svg +0 -0
- {graxpert-3.2.0a0.dev8 → graxpert-3.2.0a2}/img/graXpert_Startbadge_Tethys.png +0 -0
- {graxpert-3.2.0a0.dev8 → graxpert-3.2.0a2}/img/graXpert_Startbadge_Tethys.svg +0 -0
- {graxpert-3.2.0a0.dev8 → graxpert-3.2.0a2}/img/graXpert_Startbadge_Umbriel.png +0 -0
- {graxpert-3.2.0a0.dev8 → graxpert-3.2.0a2}/img/graXpert_Startbadge_Umbriel.svg +0 -0
- {graxpert-3.2.0a0.dev8 → graxpert-3.2.0a2}/pyproject.toml +0 -0
- {graxpert-3.2.0a0.dev8 → graxpert-3.2.0a2}/requirements.txt +0 -0
- {graxpert-3.2.0a0.dev8 → graxpert-3.2.0a2}/setup.cfg +0 -0
- {graxpert-3.2.0a0.dev8 → graxpert-3.2.0a2}/setup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: graxpert
|
|
3
|
-
Version: 3.2.
|
|
3
|
+
Version: 3.2.0a2
|
|
4
4
|
Summary: GraXpert is an astronomical image processing program for extracting and removing gradients in the background of your astrophotos
|
|
5
5
|
Home-page: https://graxpert.com
|
|
6
6
|
Author: GraXpert Development Team
|
|
@@ -18,7 +18,7 @@ except Exception as e:
|
|
|
18
18
|
logging.exception(e)
|
|
19
19
|
client = None
|
|
20
20
|
|
|
21
|
-
from graxpert.
|
|
21
|
+
from graxpert.progress import DynamicProgressThread
|
|
22
22
|
|
|
23
23
|
ai_models_dir = os.path.join(user_data_dir(appname="GraXpert"), "ai-models")
|
|
24
24
|
bge_ai_models_dir = os.path.join(user_data_dir(appname="GraXpert"), "bge-ai-models")
|
|
@@ -29,7 +29,10 @@ from graxpert.mp_logging import logfile_name
|
|
|
29
29
|
from graxpert.preferences import fitsheader_2_app_state, load_preferences, prefs_2_app_state
|
|
30
30
|
from graxpert.s3_secrets import bge_bucket_name, deconvolution_object_bucket_name, deconvolution_stars_bucket_name, denoise_bucket_name
|
|
31
31
|
from graxpert.stretch import StretchParameters, stretch_all
|
|
32
|
-
from graxpert.
|
|
32
|
+
from graxpert.progress import DynamicProgressThread
|
|
33
|
+
|
|
34
|
+
def callback(p):
|
|
35
|
+
eventbus.emit(AppEvents.AI_DOWNLOAD_PROGRESS, {"progress": p})
|
|
33
36
|
|
|
34
37
|
|
|
35
38
|
class GraXpert:
|
|
@@ -674,8 +677,20 @@ class GraXpert:
|
|
|
674
677
|
else:
|
|
675
678
|
eventbus.emit(AppEvents.AI_DOWNLOAD_BEGIN)
|
|
676
679
|
|
|
677
|
-
|
|
678
|
-
|
|
680
|
+
download_version(bge_ai_models_dir, bge_bucket_name, self.prefs.bge_ai_version, progress=callback)
|
|
681
|
+
eventbus.emit(AppEvents.AI_DOWNLOAD_END)
|
|
682
|
+
return True
|
|
683
|
+
|
|
684
|
+
def validate_bge_ai_installation(self):
|
|
685
|
+
if self.prefs.bge_ai_version is None or self.prefs.bge_ai_version == "None":
|
|
686
|
+
messagebox.showerror("Error", _("No Background Extraction AI-Model selected. Please select one from the Advanced panel on the right."))
|
|
687
|
+
return False
|
|
688
|
+
|
|
689
|
+
if not validate_local_version(bge_ai_models_dir, self.prefs.bge_ai_version):
|
|
690
|
+
if not messagebox.askyesno(_("Install AI-Model?"), _("Selected Background Extraction AI-Model is not installed. Should I download it now?")):
|
|
691
|
+
return False
|
|
692
|
+
else:
|
|
693
|
+
eventbus.emit(AppEvents.AI_DOWNLOAD_BEGIN)
|
|
679
694
|
|
|
680
695
|
download_version(bge_ai_models_dir, bge_bucket_name, self.prefs.bge_ai_version, progress=callback)
|
|
681
696
|
eventbus.emit(AppEvents.AI_DOWNLOAD_END)
|
|
@@ -695,9 +710,6 @@ class GraXpert:
|
|
|
695
710
|
else:
|
|
696
711
|
eventbus.emit(AppEvents.AI_DOWNLOAD_BEGIN)
|
|
697
712
|
|
|
698
|
-
def callback(p):
|
|
699
|
-
eventbus.emit(AppEvents.AI_DOWNLOAD_PROGRESS, {"progress": p})
|
|
700
|
-
|
|
701
713
|
download_version(deconvolution_object_ai_models_dir, deconvolution_object_bucket_name, self.prefs.deconvolution_object_ai_version, progress=callback)
|
|
702
714
|
eventbus.emit(AppEvents.AI_DOWNLOAD_END)
|
|
703
715
|
return True
|
|
@@ -712,9 +724,6 @@ class GraXpert:
|
|
|
712
724
|
else:
|
|
713
725
|
eventbus.emit(AppEvents.AI_DOWNLOAD_BEGIN)
|
|
714
726
|
|
|
715
|
-
def callback(p):
|
|
716
|
-
eventbus.emit(AppEvents.AI_DOWNLOAD_PROGRESS, {"progress": p})
|
|
717
|
-
|
|
718
727
|
download_version(deconvolution_stars_ai_models_dir, deconvolution_stars_bucket_name, self.prefs.deconvolution_stars_ai_version, progress=callback)
|
|
719
728
|
eventbus.emit(AppEvents.AI_DOWNLOAD_END)
|
|
720
729
|
return True
|
|
@@ -730,9 +739,6 @@ class GraXpert:
|
|
|
730
739
|
else:
|
|
731
740
|
eventbus.emit(AppEvents.AI_DOWNLOAD_BEGIN)
|
|
732
741
|
|
|
733
|
-
def callback(p):
|
|
734
|
-
eventbus.emit(AppEvents.AI_DOWNLOAD_PROGRESS, {"progress": p})
|
|
735
|
-
|
|
736
742
|
download_version(denoise_ai_models_dir, denoise_bucket_name, self.prefs.denoise_ai_version, progress=callback)
|
|
737
743
|
eventbus.emit(AppEvents.AI_DOWNLOAD_END)
|
|
738
744
|
return True
|
|
@@ -49,7 +49,9 @@ class CmdlineToolBase:
|
|
|
49
49
|
def get_save_path(self):
|
|
50
50
|
if self.args.output is not None:
|
|
51
51
|
base_path = os.path.dirname(self.args.filename)
|
|
52
|
-
output_file_name = self.args.output
|
|
52
|
+
output_file_name = self.args.output
|
|
53
|
+
if not os.path.splitext(output_file_name)[1]: # if output file already has an extension, just use that
|
|
54
|
+
output_file_name += self.get_output_file_ending()
|
|
53
55
|
return os.path.join(base_path, output_file_name)
|
|
54
56
|
else:
|
|
55
57
|
return os.path.splitext(self.args.filename)[0] + "_GraXpert" + self.get_output_file_ending()
|
|
@@ -59,7 +61,7 @@ class BGECmdlineTool(CmdlineToolBase):
|
|
|
59
61
|
def __init__(self, args):
|
|
60
62
|
super().__init__(args)
|
|
61
63
|
|
|
62
|
-
def execute(self):
|
|
64
|
+
def execute(self, json_prefs: dict = {}):
|
|
63
65
|
astro_Image = AstroImage(do_update_display=False)
|
|
64
66
|
astro_Image.set_from_file(self.args.filename, None, None)
|
|
65
67
|
|
|
@@ -71,43 +73,30 @@ class BGECmdlineTool(CmdlineToolBase):
|
|
|
71
73
|
|
|
72
74
|
downscale_factor = 1
|
|
73
75
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
if "ai_gpu_acceleration" in json_prefs:
|
|
99
|
-
preferences.ai_gpu_acceleration = json_prefs["ai_gpu_acceleration"]
|
|
100
|
-
|
|
101
|
-
if preferences.interpol_type_option == "Kriging" or preferences.interpol_type_option == "RBF":
|
|
102
|
-
downscale_factor = 4
|
|
103
|
-
|
|
104
|
-
except Exception as e:
|
|
105
|
-
logging.exception(e)
|
|
106
|
-
logging.shutdown()
|
|
107
|
-
sys.exit(1)
|
|
108
|
-
else:
|
|
109
|
-
preferences = Prefs()
|
|
110
|
-
preferences.interpol_type_option = "AI"
|
|
76
|
+
preferences = Prefs()
|
|
77
|
+
preferences.interpol_type_option = "AI"
|
|
78
|
+
|
|
79
|
+
if "background_points" in json_prefs:
|
|
80
|
+
preferences.background_points = json_prefs["background_points"]
|
|
81
|
+
if "RBF_kernel" in json_prefs:
|
|
82
|
+
preferences.RBF_kernel = json_prefs["RBF_kernel"]
|
|
83
|
+
if "interpol_type_option" in json_prefs:
|
|
84
|
+
preferences.interpol_type_option = json_prefs["interpol_type_option"]
|
|
85
|
+
if "smoothing_option" in json_prefs:
|
|
86
|
+
preferences.smoothing_option = json_prefs["smoothing_option"]
|
|
87
|
+
if "sample_size" in json_prefs:
|
|
88
|
+
preferences.sample_size = json_prefs["sample_size"]
|
|
89
|
+
if "spline_order" in json_prefs:
|
|
90
|
+
preferences.spline_order = json_prefs["spline_order"]
|
|
91
|
+
if "corr_type" in json_prefs:
|
|
92
|
+
preferences.corr_type = json_prefs["corr_type"]
|
|
93
|
+
if "ai_version" in json_prefs:
|
|
94
|
+
preferences.bge_ai_version = json_prefs["ai_version"]
|
|
95
|
+
if "ai_gpu_acceleration" in json_prefs:
|
|
96
|
+
preferences.ai_gpu_acceleration = json_prefs["ai_gpu_acceleration"]
|
|
97
|
+
|
|
98
|
+
if preferences.interpol_type_option == "Kriging" or preferences.interpol_type_option == "RBF":
|
|
99
|
+
downscale_factor = 4
|
|
111
100
|
|
|
112
101
|
if self.args.smoothing is not None:
|
|
113
102
|
preferences.smoothing_option = self.args.smoothing
|
|
@@ -220,7 +209,7 @@ class DenoiseCmdlineTool(CmdlineToolBase):
|
|
|
220
209
|
super().__init__(args)
|
|
221
210
|
self.args = args
|
|
222
211
|
|
|
223
|
-
def execute(self):
|
|
212
|
+
def execute(self, json_prefs: dict = {}):
|
|
224
213
|
astro_Image = AstroImage(do_update_display=False)
|
|
225
214
|
astro_Image.set_from_file(self.args.filename, None, None)
|
|
226
215
|
|
|
@@ -228,28 +217,16 @@ class DenoiseCmdlineTool(CmdlineToolBase):
|
|
|
228
217
|
|
|
229
218
|
processed_Astro_Image.fits_header = astro_Image.fits_header
|
|
230
219
|
|
|
231
|
-
|
|
232
|
-
preferences = Prefs()
|
|
233
|
-
try:
|
|
234
|
-
preferences_file = os.path.abspath(self.args.preferences_file)
|
|
235
|
-
if os.path.isfile(preferences_file):
|
|
236
|
-
with open(preferences_file, "r") as f:
|
|
237
|
-
json_prefs = json.load(f)
|
|
238
|
-
if "ai_version" in json_prefs:
|
|
239
|
-
preferences.ai_version = json_prefs["ai_version"]
|
|
240
|
-
if "denoise_strength" in json_prefs:
|
|
241
|
-
preferences.denoise_strength = json_prefs["denoise_strength"]
|
|
242
|
-
if "ai_batch_size" in json_prefs:
|
|
243
|
-
preferences.ai_batch_size = json_prefs["ai_batch_size"]
|
|
244
|
-
if "ai_gpu_acceleration" in json_prefs:
|
|
245
|
-
preferences.ai_gpu_acceleration = json_prefs["ai_gpu_acceleration"]
|
|
220
|
+
preferences = Prefs()
|
|
246
221
|
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
preferences =
|
|
222
|
+
if "ai_version" in json_prefs:
|
|
223
|
+
preferences.ai_version = json_prefs["ai_version"]
|
|
224
|
+
if "denoise_strength" in json_prefs:
|
|
225
|
+
preferences.denoise_strength = json_prefs["denoise_strength"]
|
|
226
|
+
if "ai_batch_size" in json_prefs:
|
|
227
|
+
preferences.ai_batch_size = json_prefs["ai_batch_size"]
|
|
228
|
+
if "ai_gpu_acceleration" in json_prefs:
|
|
229
|
+
preferences.ai_gpu_acceleration = json_prefs["ai_gpu_acceleration"]
|
|
253
230
|
|
|
254
231
|
if self.args.denoise_strength is not None:
|
|
255
232
|
preferences.denoise_strength = self.args.denoise_strength
|
|
@@ -320,7 +297,7 @@ class DeconvObjCmdlineTool(CmdlineToolBase):
|
|
|
320
297
|
super().__init__(args)
|
|
321
298
|
self.args = args
|
|
322
299
|
|
|
323
|
-
def execute(self):
|
|
300
|
+
def execute(self, json_prefs: dict = {}):
|
|
324
301
|
astro_Image = AstroImage(do_update_display=False)
|
|
325
302
|
astro_Image.set_from_file(self.args.filename, None, None)
|
|
326
303
|
|
|
@@ -328,30 +305,18 @@ class DeconvObjCmdlineTool(CmdlineToolBase):
|
|
|
328
305
|
|
|
329
306
|
processed_Astro_Image.fits_header = astro_Image.fits_header
|
|
330
307
|
|
|
331
|
-
|
|
332
|
-
preferences = Prefs()
|
|
333
|
-
try:
|
|
334
|
-
preferences_file = os.path.abspath(self.args.preferences_file)
|
|
335
|
-
if os.path.isfile(preferences_file):
|
|
336
|
-
with open(preferences_file, "r") as f:
|
|
337
|
-
json_prefs = json.load(f)
|
|
338
|
-
if "ai_version" in json_prefs:
|
|
339
|
-
preferences.ai_version = json_prefs["ai_version"]
|
|
340
|
-
if "deconvolution_strength" in json_prefs:
|
|
341
|
-
preferences.deconvolution_strength = json_prefs["deconvolution_strength"]
|
|
342
|
-
if "deconvolution_psfsize" in json_prefs:
|
|
343
|
-
preferences.deconvolution_psfsize = json_prefs["deconvolution_psfsize"]
|
|
344
|
-
if "ai_batch_size" in json_prefs:
|
|
345
|
-
preferences.ai_batch_size = json_prefs["ai_batch_size"]
|
|
346
|
-
if "ai_gpu_acceleration" in json_prefs:
|
|
347
|
-
preferences.ai_gpu_acceleration = json_prefs["ai_gpu_acceleration"]
|
|
308
|
+
preferences = Prefs()
|
|
348
309
|
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
preferences =
|
|
310
|
+
if "ai_version" in json_prefs:
|
|
311
|
+
preferences.ai_version = json_prefs["ai_version"]
|
|
312
|
+
if "deconvolution_strength" in json_prefs:
|
|
313
|
+
preferences.deconvolution_strength = json_prefs["deconvolution_strength"]
|
|
314
|
+
if "deconvolution_psfsize" in json_prefs:
|
|
315
|
+
preferences.deconvolution_psfsize = json_prefs["deconvolution_psfsize"]
|
|
316
|
+
if "ai_batch_size" in json_prefs:
|
|
317
|
+
preferences.ai_batch_size = json_prefs["ai_batch_size"]
|
|
318
|
+
if "ai_gpu_acceleration" in json_prefs:
|
|
319
|
+
preferences.ai_gpu_acceleration = json_prefs["ai_gpu_acceleration"]
|
|
355
320
|
|
|
356
321
|
if self.args.deconvolution_strength is not None:
|
|
357
322
|
preferences.deconvolution_strength = self.args.deconvolution_strength
|
|
@@ -436,7 +401,7 @@ class DeconvStellarCmdlineTool(CmdlineToolBase):
|
|
|
436
401
|
super().__init__(args)
|
|
437
402
|
self.args = args
|
|
438
403
|
|
|
439
|
-
def execute(self):
|
|
404
|
+
def execute(self, json_prefs: dict = {}):
|
|
440
405
|
astro_Image = AstroImage(do_update_display=False)
|
|
441
406
|
astro_Image.set_from_file(self.args.filename, None, None)
|
|
442
407
|
|
|
@@ -444,30 +409,18 @@ class DeconvStellarCmdlineTool(CmdlineToolBase):
|
|
|
444
409
|
|
|
445
410
|
processed_Astro_Image.fits_header = astro_Image.fits_header
|
|
446
411
|
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
preferences.deconvolution_psfsize = json_prefs["deconvolution_psfsize"]
|
|
460
|
-
if "ai_batch_size" in json_prefs:
|
|
461
|
-
preferences.ai_batch_size = json_prefs["ai_batch_size"]
|
|
462
|
-
if "ai_gpu_acceleration" in json_prefs:
|
|
463
|
-
preferences.ai_gpu_acceleration = json_prefs["ai_gpu_acceleration"]
|
|
464
|
-
|
|
465
|
-
except Exception as e:
|
|
466
|
-
logging.exception(e)
|
|
467
|
-
logging.shutdown()
|
|
468
|
-
sys.exit(1)
|
|
469
|
-
else:
|
|
470
|
-
preferences = Prefs()
|
|
412
|
+
preferences = Prefs()
|
|
413
|
+
|
|
414
|
+
if "ai_version" in json_prefs:
|
|
415
|
+
preferences.ai_version = json_prefs["ai_version"]
|
|
416
|
+
if "deconvolution_strength" in json_prefs:
|
|
417
|
+
preferences.deconvolution_strength = json_prefs["deconvolution_strength"]
|
|
418
|
+
if "deconvolution_psfsize" in json_prefs:
|
|
419
|
+
preferences.deconvolution_psfsize = json_prefs["deconvolution_psfsize"]
|
|
420
|
+
if "ai_batch_size" in json_prefs:
|
|
421
|
+
preferences.ai_batch_size = json_prefs["ai_batch_size"]
|
|
422
|
+
if "ai_gpu_acceleration" in json_prefs:
|
|
423
|
+
preferences.ai_gpu_acceleration = json_prefs["ai_gpu_acceleration"]
|
|
471
424
|
|
|
472
425
|
if self.args.deconvolution_strength is not None:
|
|
473
426
|
preferences.deconvolution_strength = self.args.deconvolution_strength
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import json
|
|
1
2
|
import os
|
|
2
3
|
import platform
|
|
3
4
|
import sys
|
|
@@ -17,20 +18,21 @@ import types
|
|
|
17
18
|
|
|
18
19
|
from packaging import version
|
|
19
20
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
21
|
+
def check_tk():
|
|
22
|
+
# Must be before all other graxpert imports
|
|
23
|
+
try:
|
|
24
|
+
# A load-time check for key external package dependencies. Crash and warn user.
|
|
25
|
+
import tkinter
|
|
26
|
+
except ImportError:
|
|
27
|
+
# If it fails, print a helpful message and exit.
|
|
28
|
+
print("ERROR: The required 'tkinter' GUI library is not installed.", file=sys.stderr)
|
|
29
|
+
print("\nPlease install it using your system's package manager.", file=sys.stderr)
|
|
30
|
+
print(" For Debian/Ubuntu: sudo apt-get install python3-tk", file=sys.stderr)
|
|
31
|
+
print(" For Fedora: sudo dnf install python3-tkinter", file=sys.stderr)
|
|
32
|
+
print(" For Arch Linux: sudo pacman -S tk", file=sys.stderr)
|
|
33
|
+
print(" For OS-X: brew install python-tk", file=sys.stderr)
|
|
34
|
+
print(" For Windows: It should be included with your Python installation by default.", file=sys.stderr)
|
|
35
|
+
sys.exit(1) # Exit with error
|
|
34
36
|
|
|
35
37
|
|
|
36
38
|
from graxpert.ai_model_handling import bge_ai_models_dir, denoise_ai_models_dir, deconvolution_object_ai_models_dir, deconvolution_stars_ai_models_dir, list_local_versions, list_remote_versions
|
|
@@ -101,6 +103,8 @@ def version_type(ai_models_dir, bucket_name, arg_value, pat=re.compile(r"^\d+\.\
|
|
|
101
103
|
|
|
102
104
|
|
|
103
105
|
def ui_main(open_with_file=None):
|
|
106
|
+
check_tk() # Must be before importing tkinter
|
|
107
|
+
|
|
104
108
|
import logging
|
|
105
109
|
import tkinter as tk
|
|
106
110
|
from concurrent.futures import ProcessPoolExecutor
|
|
@@ -194,7 +198,9 @@ def ui_main(open_with_file=None):
|
|
|
194
198
|
app = ApplicationFrame(root)
|
|
195
199
|
app.grid(column=0, row=0, sticky=tk.NSEW)
|
|
196
200
|
root.update()
|
|
197
|
-
|
|
201
|
+
# Turn off new version check because we will be switching to pypi based version checking
|
|
202
|
+
# (much faster - no 2 second pause on startup)
|
|
203
|
+
# check_for_new_version()
|
|
198
204
|
|
|
199
205
|
if open_with_file and len(open_with_file) > 0:
|
|
200
206
|
eventbus.emit(AppEvents.LOAD_IMAGE_REQUEST, {"filename": open_with_file})
|
|
@@ -204,7 +210,12 @@ def ui_main(open_with_file=None):
|
|
|
204
210
|
root.mainloop()
|
|
205
211
|
|
|
206
212
|
|
|
207
|
-
def parse_args():
|
|
213
|
+
def parse_args(argv):
|
|
214
|
+
"""Parse command line arguments.
|
|
215
|
+
|
|
216
|
+
Args:
|
|
217
|
+
argv: list of arguments to parse. If None, uses sys.argv[1:]
|
|
218
|
+
"""
|
|
208
219
|
available_bge_versions = collect_available_versions(bge_ai_models_dir, bge_bucket_name)
|
|
209
220
|
available_denoise_versions = collect_available_versions(denoise_ai_models_dir, denoise_bucket_name)
|
|
210
221
|
available_deconv_obj_versions = collect_available_versions(deconvolution_object_ai_models_dir, deconvolution_object_bucket_name)
|
|
@@ -362,81 +373,125 @@ def parse_args():
|
|
|
362
373
|
help='Number of image tiles which Graxpert will denoise in parallel. Be careful: increasing this value might result in out-of-memory errors. Valid Range: 1..32, default: "4"',
|
|
363
374
|
)
|
|
364
375
|
|
|
365
|
-
if "-h" in
|
|
366
|
-
if "background-extraction" in
|
|
376
|
+
if "-h" in argv or "--help" in argv:
|
|
377
|
+
if "background-extraction" in argv:
|
|
367
378
|
bge_parser.print_help()
|
|
368
|
-
elif "denoising" in
|
|
379
|
+
elif "denoising" in argv:
|
|
369
380
|
denoise_parser.print_help()
|
|
370
|
-
elif "deconv-obj" in
|
|
381
|
+
elif "deconv-obj" in argv:
|
|
371
382
|
deconv_obj_parser.print_help()
|
|
372
|
-
elif "deconv-stellar" in
|
|
383
|
+
elif "deconv-stellar" in argv:
|
|
373
384
|
deconv_stellar_parser.print_help()
|
|
374
385
|
else:
|
|
375
386
|
parser.print_help()
|
|
376
387
|
sys.exit(0)
|
|
377
388
|
|
|
378
|
-
args, extras = parser.parse_known_args()
|
|
389
|
+
args, extras = parser.parse_known_args(argv)
|
|
379
390
|
|
|
380
391
|
if args.command == "background-extraction":
|
|
381
|
-
args = bge_parser.parse_args()
|
|
392
|
+
args = bge_parser.parse_args(argv)
|
|
382
393
|
elif args.command == "deconv-obj":
|
|
383
|
-
args = deconv_obj_parser.parse_args()
|
|
394
|
+
args = deconv_obj_parser.parse_args(argv)
|
|
384
395
|
elif args.command == "deconv-stellar":
|
|
385
|
-
args = deconv_stellar_parser.parse_args()
|
|
396
|
+
args = deconv_stellar_parser.parse_args(argv)
|
|
386
397
|
elif args.command == "denoising":
|
|
387
|
-
args = denoise_parser.parse_args()
|
|
398
|
+
args = denoise_parser.parse_args(argv)
|
|
388
399
|
|
|
389
400
|
return args
|
|
390
401
|
|
|
391
|
-
def main():
|
|
392
|
-
"""Note: this is entered directly via the entry_point definition in setup.py or called from below"""
|
|
393
402
|
|
|
394
|
-
|
|
395
|
-
|
|
403
|
+
def main_impl(args, json_prefs: dict = {}):
|
|
404
|
+
"""Shared main implementation for both commandline and API usage.
|
|
396
405
|
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
else:
|
|
402
|
-
# Dummy noarg defs
|
|
403
|
-
args = types.SimpleNamespace(command=None, filename=None)
|
|
406
|
+
Args:
|
|
407
|
+
args: parsed arguments namespace.
|
|
408
|
+
json_prefs: dictionary of preferences (following the documented JSON format), or None if not provided.
|
|
409
|
+
"""
|
|
404
410
|
|
|
405
|
-
|
|
406
|
-
|
|
411
|
+
try:
|
|
412
|
+
# Centralize our preference file loading here, though API users will probably just pass in a dict
|
|
413
|
+
if args.preferences_file:
|
|
414
|
+
preferences_file = os.path.abspath(args.preferences_file)
|
|
415
|
+
if os.path.isfile(preferences_file):
|
|
416
|
+
with open(preferences_file, "r") as f:
|
|
417
|
+
json_prefs = json.load(f)
|
|
407
418
|
|
|
408
419
|
if args.command == "background-extraction":
|
|
409
420
|
from graxpert.cmdline_tools import BGECmdlineTool
|
|
410
421
|
|
|
411
422
|
logging.info(f"Starting GraXpert CLI, Background-Extraction, version: {graxpert_version} release: {graxpert_release}")
|
|
412
423
|
clt = BGECmdlineTool(args)
|
|
413
|
-
clt.execute()
|
|
424
|
+
clt.execute(json_prefs)
|
|
414
425
|
elif args.command == "denoising":
|
|
415
426
|
from graxpert.cmdline_tools import DenoiseCmdlineTool
|
|
416
427
|
|
|
417
428
|
logging.info(f"Starting GraXpert CLI, Denoising, version: {graxpert_version} release: {graxpert_release}")
|
|
418
429
|
clt = DenoiseCmdlineTool(args)
|
|
419
|
-
clt.execute()
|
|
430
|
+
clt.execute(json_prefs)
|
|
420
431
|
elif args.command == "deconv-obj":
|
|
421
432
|
from graxpert.cmdline_tools import DeconvObjCmdlineTool
|
|
422
433
|
|
|
423
434
|
logging.info(f"Starting GraXpert CLI, Deconvolution Obj, version: {graxpert_version} release: {graxpert_release}")
|
|
424
435
|
clt = DeconvObjCmdlineTool(args)
|
|
425
|
-
clt.execute()
|
|
436
|
+
clt.execute(json_prefs)
|
|
426
437
|
elif args.command == "deconv-stellar":
|
|
427
438
|
from graxpert.cmdline_tools import DeconvStellarCmdlineTool
|
|
428
439
|
|
|
429
440
|
logging.info(f"Starting GraXpert CLI, Deconvolution Stellar, version: {graxpert_version} release: {graxpert_release}")
|
|
430
441
|
clt = DeconvStellarCmdlineTool(args)
|
|
431
|
-
clt.execute()
|
|
442
|
+
clt.execute(json_prefs)
|
|
432
443
|
else:
|
|
433
444
|
logging.info(f"Starting GraXpert UI, version: {graxpert_version} release: {graxpert_release}")
|
|
434
445
|
ui_main(args.filename)
|
|
435
446
|
finally:
|
|
436
447
|
temp_cleanup()
|
|
437
|
-
logging.shutdown()
|
|
438
448
|
|
|
439
449
|
|
|
450
|
+
def api_run(argv, json_prefs: dict = {}):
|
|
451
|
+
"""Allows running GraXpert programmatically via an API call, passing commandline args as a list of strings
|
|
452
|
+
|
|
453
|
+
Args:
|
|
454
|
+
argv: list of arguments to parse.
|
|
455
|
+
json_prefs: dictionary of preferences (following the documented JSON format), or None if not provided.
|
|
456
|
+
"""
|
|
457
|
+
|
|
458
|
+
# listing available versions might be slow, so only do it if we have command line args
|
|
459
|
+
if len(argv) > 0:
|
|
460
|
+
args = parse_args(argv)
|
|
461
|
+
else:
|
|
462
|
+
# Dummy noarg defs
|
|
463
|
+
args = types.SimpleNamespace(command=None, filename=None, preferences_file=None)
|
|
464
|
+
|
|
465
|
+
main_impl(args, json_prefs)
|
|
466
|
+
|
|
467
|
+
def main():
|
|
468
|
+
"""Note: this is entered directly via the entry_point definition in setup.py or called from below
|
|
469
|
+
|
|
470
|
+
Args:
|
|
471
|
+
argv: Optional list of arguments to parse. If None, uses sys.argv[1:]
|
|
472
|
+
"""
|
|
473
|
+
|
|
474
|
+
multiprocessing.freeze_support()
|
|
475
|
+
faulthandler.enable(sys.stderr)
|
|
476
|
+
try:
|
|
477
|
+
# listing available versions might be slow, so only do it if we have command line args
|
|
478
|
+
if len(sys.argv) > 1:
|
|
479
|
+
args = parse_args(sys.argv[1:])
|
|
480
|
+
else:
|
|
481
|
+
# Dummy noarg defs
|
|
482
|
+
args = types.SimpleNamespace(command=None, filename=None, preferences_file=None)
|
|
483
|
+
|
|
484
|
+
# Note: we wait to setup logging until after parsing args, so that --help response doesn't get log framing
|
|
485
|
+
configure_logging()
|
|
486
|
+
|
|
487
|
+
main_impl(args)
|
|
488
|
+
|
|
489
|
+
logging.shutdown()
|
|
490
|
+
except Exception as e:
|
|
491
|
+
logging.exception(e)
|
|
492
|
+
logging.shutdown()
|
|
493
|
+
sys.exit(1)
|
|
494
|
+
|
|
440
495
|
if __name__ == "__main__":
|
|
441
496
|
main()
|
|
442
497
|
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
from queue import Empty, Queue
|
|
2
|
+
from threading import Thread
|
|
3
|
+
|
|
4
|
+
class DynamicProgressThread(Thread):
|
|
5
|
+
def __init__(self, interval=1, total=100, callback=None):
|
|
6
|
+
Thread.__init__(self)
|
|
7
|
+
self.daemon = True
|
|
8
|
+
self.interval = interval
|
|
9
|
+
self.callback = callback
|
|
10
|
+
self.total = total
|
|
11
|
+
self.current_progress = 0
|
|
12
|
+
self.update_queue = Queue()
|
|
13
|
+
self.start()
|
|
14
|
+
|
|
15
|
+
def run(self):
|
|
16
|
+
while True:
|
|
17
|
+
try:
|
|
18
|
+
# display every interval secs
|
|
19
|
+
task = self.update_queue.get(timeout=self.interval)
|
|
20
|
+
except Empty:
|
|
21
|
+
continue
|
|
22
|
+
|
|
23
|
+
current_progress, total = task
|
|
24
|
+
self.update_queue.task_done()
|
|
25
|
+
if current_progress == total:
|
|
26
|
+
# once we have done uploading everything return
|
|
27
|
+
self.done_progress()
|
|
28
|
+
return
|
|
29
|
+
|
|
30
|
+
# minio needs this method
|
|
31
|
+
def set_meta(self, total_length, object_name=None):
|
|
32
|
+
self.total = total_length
|
|
33
|
+
|
|
34
|
+
def update(self, size):
|
|
35
|
+
if not isinstance(size, int):
|
|
36
|
+
raise ValueError(f"{type(size)} type can not be displayed. Please change it to Int.")
|
|
37
|
+
|
|
38
|
+
self.current_progress += size
|
|
39
|
+
self.update_queue.put((self.current_progress, self.total))
|
|
40
|
+
|
|
41
|
+
if self.callback is not None:
|
|
42
|
+
self.callback(self.progress())
|
|
43
|
+
|
|
44
|
+
def done_progress(self):
|
|
45
|
+
self.total = 0
|
|
46
|
+
self.current_progress = 0
|
|
47
|
+
|
|
48
|
+
def progress(self):
|
|
49
|
+
if self.total == 0:
|
|
50
|
+
return 0
|
|
51
|
+
return float(self.current_progress) / float(self.total)
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
import tkinter as tk
|
|
3
3
|
from os import path
|
|
4
|
-
from queue import Empty, Queue
|
|
5
|
-
from threading import Thread
|
|
6
4
|
|
|
7
5
|
from customtkinter import CTkButton, CTkFont, CTkFrame, CTkImage, CTkLabel, CTkProgressBar, DoubleVar, StringVar, ThemeManager
|
|
8
6
|
|
|
@@ -91,52 +89,3 @@ class DynamicProgressFrame(CTkFrame):
|
|
|
91
89
|
logging.info("Progress: {}%".format(int(self.variable.get() * 100)))
|
|
92
90
|
self.pb.update()
|
|
93
91
|
|
|
94
|
-
|
|
95
|
-
class DynamicProgressThread(Thread):
|
|
96
|
-
def __init__(self, interval=1, total=100, callback=None):
|
|
97
|
-
Thread.__init__(self)
|
|
98
|
-
self.daemon = True
|
|
99
|
-
self.interval = interval
|
|
100
|
-
self.callback = callback
|
|
101
|
-
self.total = total
|
|
102
|
-
self.current_progress = 0
|
|
103
|
-
self.update_queue = Queue()
|
|
104
|
-
self.start()
|
|
105
|
-
|
|
106
|
-
def run(self):
|
|
107
|
-
while True:
|
|
108
|
-
try:
|
|
109
|
-
# display every interval secs
|
|
110
|
-
task = self.update_queue.get(timeout=self.interval)
|
|
111
|
-
except Empty:
|
|
112
|
-
continue
|
|
113
|
-
|
|
114
|
-
current_progress, total = task
|
|
115
|
-
self.update_queue.task_done()
|
|
116
|
-
if current_progress == total:
|
|
117
|
-
# once we have done uploading everything return
|
|
118
|
-
self.done_progress()
|
|
119
|
-
return
|
|
120
|
-
|
|
121
|
-
# minio needs this method
|
|
122
|
-
def set_meta(self, total_length, object_name=None):
|
|
123
|
-
self.total = total_length
|
|
124
|
-
|
|
125
|
-
def update(self, size):
|
|
126
|
-
if not isinstance(size, int):
|
|
127
|
-
raise ValueError(f"{type(size)} type can not be displayed. Please change it to Int.")
|
|
128
|
-
|
|
129
|
-
self.current_progress += size
|
|
130
|
-
self.update_queue.put((self.current_progress, self.total))
|
|
131
|
-
|
|
132
|
-
if self.callback is not None:
|
|
133
|
-
self.callback(self.progress())
|
|
134
|
-
|
|
135
|
-
def done_progress(self):
|
|
136
|
-
self.total = 0
|
|
137
|
-
self.current_progress = 0
|
|
138
|
-
|
|
139
|
-
def progress(self):
|
|
140
|
-
if self.total == 0:
|
|
141
|
-
return 0
|
|
142
|
-
return float(self.current_progress) / float(self.total)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: graxpert
|
|
3
|
-
Version: 3.2.
|
|
3
|
+
Version: 3.2.0a2
|
|
4
4
|
Summary: GraXpert is an astronomical image processing program for extracting and removing gradients in the background of your astrophotos
|
|
5
5
|
Home-page: https://graxpert.com
|
|
6
6
|
Author: GraXpert Development Team
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
|
|
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
|
|
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
|
|
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
|