ras-commander 0.1.0__py2.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.
- ras_commander/__init__.py +24 -0
- ras_commander/execution.py +315 -0
- ras_commander/file_operations.py +173 -0
- ras_commander/geometry_operations.py +184 -0
- ras_commander/plan_operations.py +307 -0
- ras_commander/project_config.py +64 -0
- ras_commander/project_init.py +174 -0
- ras_commander/project_management.py +227 -0
- ras_commander/project_setup.py +15 -0
- ras_commander/unsteady_operations.py +172 -0
- ras_commander/utilities.py +195 -0
- ras_commander-0.1.0.dist-info/LICENSE +5 -0
- ras_commander-0.1.0.dist-info/METADATA +135 -0
- ras_commander-0.1.0.dist-info/RECORD +16 -0
- ras_commander-0.1.0.dist-info/WHEEL +6 -0
- ras_commander-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,195 @@
|
|
1
|
+
"""
|
2
|
+
Utility functions for the ras_commander library.
|
3
|
+
"""
|
4
|
+
import shutil
|
5
|
+
import logging
|
6
|
+
import time
|
7
|
+
from pathlib import Path
|
8
|
+
from .project_config import ProjectConfig
|
9
|
+
|
10
|
+
class Utilities:
|
11
|
+
"""
|
12
|
+
A class containing the utility functions for the ras_commander library.
|
13
|
+
When integrating new functions that do not clearly fit into other classes, add them here.
|
14
|
+
"""
|
15
|
+
@staticmethod
|
16
|
+
def create_backup(file_path, backup_suffix="_backup"):
|
17
|
+
"""
|
18
|
+
Create a backup of the specified file.
|
19
|
+
Parameters:
|
20
|
+
file_path (str): Path to the file to be backed up
|
21
|
+
backup_suffix (str): Suffix to append to the backup file name
|
22
|
+
Returns:
|
23
|
+
str: Path to the created backup file
|
24
|
+
"""
|
25
|
+
config = ProjectConfig()
|
26
|
+
config.check_initialized()
|
27
|
+
|
28
|
+
original_path = Path(file_path)
|
29
|
+
backup_path = original_path.with_name(f"{original_path.stem}{backup_suffix}{original_path.suffix}")
|
30
|
+
shutil.copy2(original_path, backup_path)
|
31
|
+
print(f"Backup created: {backup_path}")
|
32
|
+
return str(backup_path)
|
33
|
+
|
34
|
+
@staticmethod
|
35
|
+
def restore_from_backup(backup_path, remove_backup=True):
|
36
|
+
"""
|
37
|
+
Restore a file from its backup.
|
38
|
+
Parameters:
|
39
|
+
backup_path (str): Path to the backup file
|
40
|
+
remove_backup (bool): Whether to remove the backup file after restoration
|
41
|
+
Returns:
|
42
|
+
str: Path to the restored file
|
43
|
+
"""
|
44
|
+
config = ProjectConfig()
|
45
|
+
config.check_initialized()
|
46
|
+
|
47
|
+
backup_path = Path(backup_path)
|
48
|
+
original_path = backup_path.with_name(backup_path.stem.rsplit('_backup', 1)[0] + backup_path.suffix)
|
49
|
+
shutil.copy2(backup_path, original_path)
|
50
|
+
print(f"File restored: {original_path}")
|
51
|
+
if remove_backup:
|
52
|
+
backup_path.unlink()
|
53
|
+
print(f"Backup removed: {backup_path}")
|
54
|
+
return str(original_path)
|
55
|
+
|
56
|
+
@staticmethod
|
57
|
+
def safe_remove(file_path):
|
58
|
+
"""
|
59
|
+
Safely remove a file if it exists.
|
60
|
+
Parameters:
|
61
|
+
file_path (str): Path to the file to be removed
|
62
|
+
Returns:
|
63
|
+
bool: True if the file was removed, False if it didn't exist
|
64
|
+
"""
|
65
|
+
config = ProjectConfig()
|
66
|
+
config.check_initialized()
|
67
|
+
|
68
|
+
path = Path(file_path)
|
69
|
+
if path.exists():
|
70
|
+
path.unlink()
|
71
|
+
print(f"File removed: {path}")
|
72
|
+
return True
|
73
|
+
else:
|
74
|
+
print(f"File not found: {path}")
|
75
|
+
return False
|
76
|
+
|
77
|
+
@staticmethod
|
78
|
+
def ensure_directory(directory_path):
|
79
|
+
"""
|
80
|
+
Ensure that a directory exists, creating it if necessary.
|
81
|
+
Parameters:
|
82
|
+
directory_path (str): Path to the directory
|
83
|
+
Returns:
|
84
|
+
str: Path to the ensured directory
|
85
|
+
"""
|
86
|
+
config = ProjectConfig()
|
87
|
+
config.check_initialized()
|
88
|
+
|
89
|
+
path = Path(directory_path)
|
90
|
+
path.mkdir(parents=True, exist_ok=True)
|
91
|
+
print(f"Directory ensured: {path}")
|
92
|
+
return str(path)
|
93
|
+
|
94
|
+
@staticmethod
|
95
|
+
def list_files_with_extension(extension):
|
96
|
+
"""
|
97
|
+
List all files in the project directory with a specific extension.
|
98
|
+
Parameters:
|
99
|
+
extension (str): File extension to filter (e.g., '.prj')
|
100
|
+
Returns:
|
101
|
+
list: List of file paths matching the extension
|
102
|
+
"""
|
103
|
+
config = ProjectConfig()
|
104
|
+
config.check_initialized()
|
105
|
+
|
106
|
+
files = list(config.project_folder.glob(f"*{extension}"))
|
107
|
+
return [str(file) for file in files]
|
108
|
+
|
109
|
+
@staticmethod
|
110
|
+
def get_file_size(file_path):
|
111
|
+
"""
|
112
|
+
Get the size of a file in bytes.
|
113
|
+
Parameters:
|
114
|
+
file_path (str): Path to the file
|
115
|
+
Returns:
|
116
|
+
int: Size of the file in bytes
|
117
|
+
"""
|
118
|
+
config = ProjectConfig()
|
119
|
+
config.check_initialized()
|
120
|
+
|
121
|
+
path = Path(file_path)
|
122
|
+
if path.exists():
|
123
|
+
size = path.stat().st_size
|
124
|
+
print(f"File size: {size} bytes")
|
125
|
+
return size
|
126
|
+
else:
|
127
|
+
print(f"File not found: {path}")
|
128
|
+
return None
|
129
|
+
|
130
|
+
@staticmethod
|
131
|
+
def get_modification_time(file_path):
|
132
|
+
"""
|
133
|
+
Get the last modification time of a file.
|
134
|
+
Parameters:
|
135
|
+
file_path (str): Path to the file
|
136
|
+
Returns:
|
137
|
+
float: Last modification time as a timestamp
|
138
|
+
"""
|
139
|
+
config = ProjectConfig()
|
140
|
+
config.check_initialized()
|
141
|
+
|
142
|
+
path = Path(file_path)
|
143
|
+
if path.exists():
|
144
|
+
mtime = path.stat().st_mtime
|
145
|
+
print(f"Last modified: {mtime}")
|
146
|
+
return mtime
|
147
|
+
else:
|
148
|
+
print(f"File not found: {path}")
|
149
|
+
return None
|
150
|
+
|
151
|
+
@staticmethod
|
152
|
+
def get_plan_path(current_plan_number):
|
153
|
+
"""
|
154
|
+
Get the path for a plan file with a given plan number.
|
155
|
+
Parameters:
|
156
|
+
current_plan_number (str or int): The plan number (01 to 99)
|
157
|
+
Returns:
|
158
|
+
str: Full path to the plan file with the given plan number
|
159
|
+
"""
|
160
|
+
config = ProjectConfig()
|
161
|
+
config.check_initialized()
|
162
|
+
|
163
|
+
current_plan_number = f"{int(current_plan_number):02d}" # Ensure two-digit format
|
164
|
+
plan_name = f"{config.project_name}.p{current_plan_number}"
|
165
|
+
return str(config.project_folder / plan_name)
|
166
|
+
|
167
|
+
@staticmethod
|
168
|
+
def retry_remove_folder(folder_path: str, max_attempts: int = 5, initial_delay: float = 1.0) -> bool:
|
169
|
+
"""
|
170
|
+
Attempts to remove a folder with retry logic and exponential backoff.
|
171
|
+
Args:
|
172
|
+
folder_path (str): Path to the folder to be removed.
|
173
|
+
max_attempts (int): Maximum number of removal attempts.
|
174
|
+
initial_delay (float): Initial delay between attempts in seconds.
|
175
|
+
Returns:
|
176
|
+
bool: True if the folder was successfully removed, False otherwise.
|
177
|
+
"""
|
178
|
+
config = ProjectConfig()
|
179
|
+
config.check_initialized()
|
180
|
+
|
181
|
+
folder = Path(folder_path)
|
182
|
+
for attempt in range(max_attempts):
|
183
|
+
try:
|
184
|
+
if folder.exists():
|
185
|
+
shutil.rmtree(folder)
|
186
|
+
return True
|
187
|
+
except PermissionError:
|
188
|
+
if attempt < max_attempts - 1:
|
189
|
+
delay = initial_delay * (2 ** attempt) # Exponential backoff
|
190
|
+
logging.warning(f"Failed to remove folder {folder}. Retrying in {delay} seconds...")
|
191
|
+
time.sleep(delay)
|
192
|
+
else:
|
193
|
+
logging.error(f"Failed to remove folder {folder} after {max_attempts} attempts. Skipping.")
|
194
|
+
return False
|
195
|
+
return False
|
@@ -0,0 +1,5 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2024 William M. Katzenmeyer
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so.
|
@@ -0,0 +1,135 @@
|
|
1
|
+
Metadata-Version: 2.1
|
2
|
+
Name: ras_commander
|
3
|
+
Version: 0.1.0
|
4
|
+
Summary: A library for automating HEC-RAS operations using python functions.
|
5
|
+
Home-page: https://github.com/yourusername/ras_commander
|
6
|
+
Author: William Katzenmeyer, P.E., C.F.M.
|
7
|
+
Author-email: heccommander@gmail.com
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
10
|
+
Classifier: Operating System :: OS Independent
|
11
|
+
Requires-Python: >=3.9
|
12
|
+
Description-Content-Type: text/markdown
|
13
|
+
License-File: LICENSE
|
14
|
+
Requires-Dist: pandas
|
15
|
+
|
16
|
+
## RAS-Commander Library Organization
|
17
|
+
|
18
|
+
| Directory/File | Purpose |
|
19
|
+
|---|---|
|
20
|
+
| ras_commander/__init__.py | Initializes the library and defines the public API. |
|
21
|
+
| ras_commander/execution.py | Handles execution of HEC-RAS simulations. |
|
22
|
+
| ras_commander/file_operations.py | Provides functions for reading and parsing HEC-RAS project files. |
|
23
|
+
| ras_commander/geometry_operations.py | Provides functions for manipulating geometry files. |
|
24
|
+
| ras_commander/plan_operations.py | Provides functions for modifying and updating plan files. |
|
25
|
+
| ras_commander/project_config.py | Defines the ProjectConfig class for managing project-level information. |
|
26
|
+
| ras_commander/project_init.py | Provides the `init_ras_project` function to initialize a project. |
|
27
|
+
| ras_commander/project_management.py | Provides functions for managing HEC-RAS projects (e.g., copying files, updating project file). |
|
28
|
+
| ras_commander/project_setup.py | Provides helper functions for project setup (e.g., finding project file, loading project data). |
|
29
|
+
| ras_commander/unsteady_operations.py | Provides functions for manipulating unsteady flow files. |
|
30
|
+
| ras_commander/utilities.py | Provides general utility functions (e.g., file backup, directory creation). |
|
31
|
+
|
32
|
+
|
33
|
+
## Project Organization Diagram
|
34
|
+
|
35
|
+
```
|
36
|
+
ras_commander
|
37
|
+
├── execution.py
|
38
|
+
├── file_operations.py
|
39
|
+
├── geometry_operations.py
|
40
|
+
├── plan_operations.py
|
41
|
+
├── project_config.py
|
42
|
+
├── project_init.py
|
43
|
+
├── project_management.py
|
44
|
+
├── project_setup.py
|
45
|
+
├── unsteady_operations.py
|
46
|
+
└── utilities.py
|
47
|
+
```
|
48
|
+
|
49
|
+
## Functions Overview
|
50
|
+
|
51
|
+
| Function | Arguments | Purpose |
|
52
|
+
|---|---|---|
|
53
|
+
| `init_ras_project` | `ras_project_folder`, `hecras_exe_path` | Initializes a HEC-RAS project by setting up the `ProjectConfig` with project details. |
|
54
|
+
| `compute_hecras_plan` | `plan_file` | Executes a HEC-RAS plan file. |
|
55
|
+
| `compute_hecras_plan_from_folder` | `test_plan_file`, `test_folder_path` | Execute a single HEC-RAS plan from a folder other than the project path.
|
56
|
+
| `recreate_test_function` | `project_folder` | Recreates the -test function from the HEC-RAS interface, primarily by copying the project directory, forcing recomputation, and running each plan. |
|
57
|
+
| `run_plans_parallel` | `config`, `max_workers`, `cores_per_run` | Run HEC-RAS plans in parallel. |
|
58
|
+
| `run_all_plans_parallel` | `project_folder`, `hecras_exe_path` | Run all HEC-RAS plans in parallel from a project folder path. |
|
59
|
+
| `find_hecras_project_file` | `folder_path` | Locates the HEC-RAS project file (.prj) within a given folder. |
|
60
|
+
| `get_project_name` | `project_path` | Extracts the project name from the project file path. |
|
61
|
+
| `get_plan_entries` | `project_file` | Parses the project file to extract plan file information into a DataFrame. |
|
62
|
+
| `get_flow_entries` | `project_file` | Parses the project file to extract steady flow file information into a DataFrame. |
|
63
|
+
| `get_unsteady_entries` | `project_file` | Parses the project file to extract unsteady flow file information into a DataFrame. |
|
64
|
+
| `get_geom_entries` | `project_file` | Parses the project file to extract geometry file information into a DataFrame. |
|
65
|
+
| `clear_geometry_preprocessor_files` | `plan_file` | Deletes the geometry preprocessor files (.cXX) associated with a plan file. |
|
66
|
+
| `clear_geometry_preprocessor_files_for_all_plans` | | Deletes geometry preprocessor files for all plans in the project directory. |
|
67
|
+
| `copy_geometry_files` | `dst_folder`, `template_geom` | Copies geometry files from a template to a destination folder, assigning the next available geometry number. |
|
68
|
+
| `rename_geometry_files` | `old_number`, `new_number` | Renames geometry files (both .gXX and .gXX.hdf) in the project folder. |
|
69
|
+
| `update_geometry_reference_in_plan` | `plan_file`, `new_geometry_number` | Updates the "Geom File=" entry in a plan file to reference a new geometry number. |
|
70
|
+
| `apply_geometry_to_plan` | `plan_file`, `geometry_number` | Sets the geometry file used by a plan file. |
|
71
|
+
| `apply_flow_to_plan` | `plan_file`, `flow_number` | Sets the steady flow file used by a plan file. |
|
72
|
+
| `copy_plan_from_template` | `template_plan` | Creates a new plan file by copying a template and updates the project file with the new plan entry. |
|
73
|
+
| `get_next_available_number` | `existing_numbers` | Finds the next available number (e.g., for plans, unsteady flows) based on existing ones. |
|
74
|
+
| `apply_unsteady_to_plan` | `plan_file`, `unsteady_number` | Sets the unsteady flow file used by a plan file. |
|
75
|
+
| `set_num_cores` | `plan_file`, `num_cores` | Sets the maximum number of cores to be used for a plan file. |
|
76
|
+
| `update_geompre_flags` | `file_path`, `run_htab_value`, `use_ib_tables_value` | Updates the geometry preprocessor flags in a plan file. |
|
77
|
+
| `get_plan_full_path` | `plan_number` | Returns the full path to a plan file based on its number. |
|
78
|
+
| `get_results_full_path` | `plan_number` | Returns the full path to a plan's results file (.hdf) based on its number. |
|
79
|
+
| `get_flow_full_path` | `flow_number` | Returns the full path to a steady flow file based on its number. |
|
80
|
+
| `get_unsteady_full_path` | `unsteady_number` | Returns the full path to an unsteady flow file based on its number. |
|
81
|
+
| `get_geom_full_path` | `geometry_number` | Returns the full path to a geometry file based on its number. |
|
82
|
+
| `copy_unsteady_files` | `dst_folder`, `template_unsteady` | Copies unsteady flow files from a template to a destination folder, assigning the next available unsteady number. |
|
83
|
+
| `rename_unsteady_files` | `old_number`, `new_number` | Renames unsteady flow files (both .uXX and .uXX.hdf) in the project folder. |
|
84
|
+
| `update_unsteady_reference_in_plan` | `plan_file`, `new_unsteady_number` | Updates the "Unsteady File=" entry in a plan file to reference a new unsteady flow number. |
|
85
|
+
| `modify_unsteady_flow_parameters` | `unsteady_file`, `modifications` | Modifies parameters within an unsteady flow file based on a dictionary of changes. |
|
86
|
+
| `create_backup` | `file_path`, `backup_suffix` | Creates a backup copy of a file. |
|
87
|
+
| `restore_from_backup` | `backup_path`, `remove_backup` | Restores a file from a backup copy. |
|
88
|
+
| `safe_remove` | `file_path` | Removes a file if it exists, handling potential errors. |
|
89
|
+
| `ensure_directory` | `directory_path` | Creates a directory if it does not exist. |
|
90
|
+
| `list_files_with_extension` | `extension` | Lists files with a specific extension in the project directory. |
|
91
|
+
| `get_file_size` | `file_path` | Returns the size of a file in bytes. |
|
92
|
+
| `get_modification_time` | `file_path` | Returns the last modification time of a file. |
|
93
|
+
| `get_plan_path` | `current_plan_number` | Returns the full path to a plan file based on its number. |
|
94
|
+
| `retry_remove_folder` | `folder_path`, `max_attempts`, `initial_delay` | Attempts to remove a folder with retry and a delay. |
|
95
|
+
|
96
|
+
|
97
|
+
|
98
|
+
## Potential Uses of RAS-Commander Functions
|
99
|
+
|
100
|
+
The RAS-Commander library offers a wide range of functionalities that can be used to automate various aspects of HEC-RAS modeling workflows. Here are some potential uses:
|
101
|
+
|
102
|
+
**1. Automated Plan Creation and Execution:**
|
103
|
+
|
104
|
+
* **Batch processing of multiple scenarios:** RAS-Commander allows you to create new plan files based on templates, modify plan parameters (e.g., geometry, flow, unsteady flow files, number of cores), and execute them in parallel. This can be useful for analyzing multiple scenarios with different inputs or model configurations.
|
105
|
+
* **Sensitivity analysis and optimization:** By combining RAS-Commander with other libraries (e.g., for parameter sampling or optimization), you can automate sensitivity analysis and parameter optimization studies.
|
106
|
+
* **Monte Carlo simulations:** RAS-Commander can be used to automate the execution of Monte Carlo simulations by creating multiple plan files with randomly sampled input parameters.
|
107
|
+
|
108
|
+
**2. Project Management and Organization:**
|
109
|
+
|
110
|
+
* **Automated file management:** Functions for copying, renaming, and updating file references help maintain consistency and organization within your HEC-RAS project.
|
111
|
+
* **Backup and restore functionalities:** Ensure project integrity by creating backups of project files and restoring them when needed.
|
112
|
+
* **Project setup and initialization:** Streamline the process of setting up new HEC-RAS projects with standardized configurations.
|
113
|
+
|
114
|
+
**3. Advanced Modeling Techniques:**
|
115
|
+
|
116
|
+
* **Coupled modeling:** RAS-Commander can be used to automate the setup and execution of coupled models (e.g., HEC-RAS with other hydrodynamic or hydrologic models).
|
117
|
+
* **Data assimilation and calibration:** By integrating RAS-Commander with data assimilation or calibration tools, you can automate the process of updating model parameters based on observed data.
|
118
|
+
* **Post-processing and analysis:** RAS-Commander can be used to extract results from HEC-RAS output files and perform post-processing and analysis tasks.
|
119
|
+
|
120
|
+
|
121
|
+
**4. Integration with Other Tools:**
|
122
|
+
|
123
|
+
* **Python scripting and automation:** RAS-Commander can be easily integrated into Python scripts and workflows for more complex automation tasks.
|
124
|
+
* **Web applications and dashboards:** Develop web applications and dashboards that allow users to interact with HEC-RAS models and visualize results through a user-friendly interface.
|
125
|
+
* **Integration with GIS software:** RAS-Commander can be used to link HEC-RAS models with GIS software for spatial analysis and visualization.
|
126
|
+
|
127
|
+
|
128
|
+
**Examples:**
|
129
|
+
|
130
|
+
* **Floodplain mapping:** Automate the creation of floodplain maps for different return periods by creating and executing multiple plan files with varying flow conditions.
|
131
|
+
* **Dam break analysis:** Automate the setup and execution of dam break simulations by modifying unsteady flow parameters and boundary conditions.
|
132
|
+
* **Bridge scour analysis:** Automate the assessment of bridge scour potential by integrating HEC-RAS with bridge scour analysis tools.
|
133
|
+
|
134
|
+
|
135
|
+
By automating repetitive tasks and providing a framework for managing complex workflows, RAS-Commander can significantly improve the efficiency and reproducibility of HEC-RAS modeling projects. This can lead to better decision-making and more accurate and reliable results.
|
@@ -0,0 +1,16 @@
|
|
1
|
+
ras_commander/__init__.py,sha256=FGdtPP0qfQ_F0psnuLpL5txmhvqhkV9-40DZ1dEhpBI,655
|
2
|
+
ras_commander/execution.py,sha256=hq2K4pIcAgch-zvV_nezxw9OpdOEenePxqWbCPFuSpw,13960
|
3
|
+
ras_commander/file_operations.py,sha256=ufi00mh52C9-off_tA0aMp3U4mm066gMkwPZYiFN8hg,7274
|
4
|
+
ras_commander/geometry_operations.py,sha256=-HhYTNEFmR64MLlfa7hxogJBCHw4iBScGFMTQLfDlJg,6961
|
5
|
+
ras_commander/plan_operations.py,sha256=I0r-4QnhSqfehy63xcreKSnE-ozzv3R-4HyO-9c3dSI,12496
|
6
|
+
ras_commander/project_config.py,sha256=zbSwSVt8F9v77QEjRUjMbLBxisiimmQO2mf7eb4juvc,2886
|
7
|
+
ras_commander/project_init.py,sha256=6eCHtqaKTXb5AK47Brs8o0fNCa0e3Jmh3QvyVhzp7n8,8330
|
8
|
+
ras_commander/project_management.py,sha256=CplIJ36ZIukm45Re9T2wQ_v96CqC9150upN06JvqYK8,9730
|
9
|
+
ras_commander/project_setup.py,sha256=nJXbi0WHwdoJsP50R2vNtL0eil5PUXZv379KiL40KPA,673
|
10
|
+
ras_commander/unsteady_operations.py,sha256=QBXUO2Mw3yzk7K9piu-Q39D_yI3BDUqLY0gweofrIWc,6808
|
11
|
+
ras_commander/utilities.py,sha256=-UeGrrWl_xp4WTROmqZliojmunMgWW7jqPM8KN4p_1Q,6807
|
12
|
+
ras_commander-0.1.0.dist-info/LICENSE,sha256=_pbd6qHnlsz1iQ-ozDW_49r86BZT6CRwO2iBtw0iN6M,457
|
13
|
+
ras_commander-0.1.0.dist-info/METADATA,sha256=-iFeNHkytgdvbjvDLXB68u3Xm8gOGNBSH7n2cO0hjpI,10903
|
14
|
+
ras_commander-0.1.0.dist-info/WHEEL,sha256=XRxW4r1PNiVhMpP4bT9oWtu3HyndxpJ84SkubFgzp_Y,109
|
15
|
+
ras_commander-0.1.0.dist-info/top_level.txt,sha256=i76S7eKLFC8doKcXDl3aiOr9RwT06G8adI6YuKbQDaA,14
|
16
|
+
ras_commander-0.1.0.dist-info/RECORD,,
|
@@ -0,0 +1 @@
|
|
1
|
+
ras_commander
|