open-fdd 0.1.6__py3-none-any.whl → 0.1.7__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.
- open_fdd/air_handling_unit/faults/__init__.py +33 -2
- open_fdd/air_handling_unit/faults/helper_utils.py +3 -0
- open_fdd/air_handling_unit/faults/shared_utils.py +16 -1
- open_fdd/air_handling_unit/reports/__init__.py +23 -10
- open_fdd/tests/ahu/test_ahu_fc1.py +1 -0
- open_fdd/tests/ahu/test_ahu_fc16.py +21 -6
- {open_fdd-0.1.6.dist-info → open_fdd-0.1.7.dist-info}/METADATA +1 -1
- {open_fdd-0.1.6.dist-info → open_fdd-0.1.7.dist-info}/RECORD +11 -11
- {open_fdd-0.1.6.dist-info → open_fdd-0.1.7.dist-info}/WHEEL +1 -1
- {open_fdd-0.1.6.dist-info → open_fdd-0.1.7.dist-info}/LICENSE +0 -0
- {open_fdd-0.1.6.dist-info → open_fdd-0.1.7.dist-info}/top_level.txt +0 -0
@@ -5,6 +5,7 @@ from open_fdd.air_handling_unit.faults.fault_condition import (
|
|
5
5
|
MissingColumnError,
|
6
6
|
InvalidParameterError,
|
7
7
|
)
|
8
|
+
from open_fdd.air_handling_unit.faults.helper_utils import SharedUtils
|
8
9
|
import operator
|
9
10
|
import sys
|
10
11
|
|
@@ -800,6 +801,13 @@ class FaultConditionSix(FaultCondition):
|
|
800
801
|
# Ensure all required columns are present
|
801
802
|
self.check_required_columns(df)
|
802
803
|
|
804
|
+
# Check for zeros in the columns that could lead to division by zero errors
|
805
|
+
cols_to_check = [self.rat_col, self.oat_col, self.supply_fan_air_volume_col]
|
806
|
+
if df[cols_to_check].eq(0).any().any():
|
807
|
+
print(f"Warning: Zero values found in columns: {cols_to_check}")
|
808
|
+
print("This may cause division by zero errors.")
|
809
|
+
sys.stdout.flush()
|
810
|
+
|
803
811
|
# Check analog outputs [data with units of %] are floats only
|
804
812
|
columns_to_check = [
|
805
813
|
self.supply_vfd_speed_col,
|
@@ -2088,6 +2096,7 @@ class FaultConditionSixteen(FaultCondition):
|
|
2088
2096
|
|
2089
2097
|
self.oat_low_threshold = dict_.get("OAT_LOW_THRES", 32.0)
|
2090
2098
|
self.oat_high_threshold = dict_.get("OAT_HIGH_THRES", 80.0)
|
2099
|
+
self.oat_rat_delta_min = dict_.get("OAT_RAT_DELTA_MIN", None)
|
2091
2100
|
|
2092
2101
|
# Validate that threshold parameters are floats and within 0.0 and 1.0 for efficiency values
|
2093
2102
|
for param, value in [
|
@@ -2097,6 +2106,7 @@ class FaultConditionSixteen(FaultCondition):
|
|
2097
2106
|
("erv_efficiency_max_cooling", self.erv_efficiency_max_cooling),
|
2098
2107
|
("oat_low_threshold", self.oat_low_threshold),
|
2099
2108
|
("oat_high_threshold", self.oat_high_threshold),
|
2109
|
+
("oat_rat_delta_min", self.oat_rat_delta_min),
|
2100
2110
|
]:
|
2101
2111
|
if not isinstance(value, float):
|
2102
2112
|
raise InvalidParameterError(
|
@@ -2177,6 +2187,15 @@ class FaultConditionSixteen(FaultCondition):
|
|
2177
2187
|
)
|
2178
2188
|
|
2179
2189
|
def calculate_erv_efficiency(self, df: pd.DataFrame) -> pd.DataFrame:
|
2190
|
+
|
2191
|
+
df = SharedUtils.clean_nan_values(df)
|
2192
|
+
|
2193
|
+
cols_to_check = [self.erv_eat_enter_col, self.erv_oat_enter_col]
|
2194
|
+
if df[cols_to_check].eq(0).any().any():
|
2195
|
+
print(f"Warning: Zero values found in columns: {cols_to_check}")
|
2196
|
+
print(f"This may cause division by zero errors.")
|
2197
|
+
sys.stdout.flush()
|
2198
|
+
|
2180
2199
|
# Calculate the temperature differences
|
2181
2200
|
delta_temp_oa = df[self.erv_oat_leaving_col] - df[self.erv_oat_enter_col]
|
2182
2201
|
delta_temp_ea = df[self.erv_eat_enter_col] - df[self.erv_oat_enter_col]
|
@@ -2194,31 +2213,43 @@ class FaultConditionSixteen(FaultCondition):
|
|
2194
2213
|
# Fan must be on for a fault to be considered
|
2195
2214
|
fan_on = df[self.supply_vfd_speed_col] > 0.1
|
2196
2215
|
|
2197
|
-
#
|
2216
|
+
# Determine if the conditions are for heating or cooling based on OAT
|
2198
2217
|
cold_outside = df[self.erv_oat_enter_col] <= self.oat_low_threshold
|
2199
2218
|
hot_outside = df[self.erv_oat_enter_col] >= self.oat_high_threshold
|
2200
2219
|
|
2220
|
+
# Calculate the temperature difference between the exhaust air entering and outside air entering
|
2221
|
+
rat_minus_oat = abs(df[self.erv_eat_enter_col] - df[self.erv_oat_enter_col])
|
2222
|
+
good_delta_check = rat_minus_oat >= self.oat_rat_delta_min
|
2223
|
+
|
2224
|
+
# Initialize the fault condition to False (no fault)
|
2225
|
+
df["fc16_flag"] = 0
|
2226
|
+
|
2227
|
+
# Apply heating fault logic
|
2201
2228
|
heating_fault = (
|
2202
2229
|
(
|
2203
2230
|
(df["erv_efficiency_oa"] < self.erv_efficiency_min_heating)
|
2204
2231
|
| (df["erv_efficiency_oa"] > self.erv_efficiency_max_heating)
|
2205
2232
|
)
|
2206
2233
|
& cold_outside
|
2234
|
+
& good_delta_check
|
2207
2235
|
& fan_on
|
2208
2236
|
)
|
2209
2237
|
|
2238
|
+
# Apply cooling fault logic
|
2210
2239
|
cooling_fault = (
|
2211
2240
|
(
|
2212
2241
|
(df["erv_efficiency_oa"] < self.erv_efficiency_min_cooling)
|
2213
2242
|
| (df["erv_efficiency_oa"] > self.erv_efficiency_max_cooling)
|
2214
2243
|
)
|
2215
2244
|
& hot_outside
|
2245
|
+
& good_delta_check
|
2216
2246
|
& fan_on
|
2217
2247
|
)
|
2218
2248
|
|
2249
|
+
# Combine the faults
|
2219
2250
|
df["combined_checks"] = heating_fault | cooling_fault
|
2220
2251
|
|
2221
|
-
# Apply rolling sum
|
2252
|
+
# Apply rolling sum to combined checks to account for rolling window
|
2222
2253
|
df["fc16_flag"] = (
|
2223
2254
|
df["combined_checks"]
|
2224
2255
|
.rolling(window=self.rolling_window_size)
|
@@ -11,6 +11,9 @@ class HelperUtils:
|
|
11
11
|
def set_config_dict(self, config_dict):
|
12
12
|
self.config_dict = config_dict
|
13
13
|
|
14
|
+
def clean_nan_values(self, df):
|
15
|
+
return SharedUtils.clean_nan_values(df)
|
16
|
+
|
14
17
|
def float_int_check_err(self, col):
|
15
18
|
return SharedUtils.float_int_check_err(col)
|
16
19
|
|
@@ -48,8 +48,10 @@ class SharedUtils:
|
|
48
48
|
"""
|
49
49
|
|
50
50
|
print(
|
51
|
-
"Warning: If data has a one minute or less sampling
|
51
|
+
"Warning: If data has a one minute or less sampling \n"
|
52
|
+
"frequency a rolling average will be automatically applied"
|
52
53
|
)
|
54
|
+
|
53
55
|
sys.stdout.flush()
|
54
56
|
|
55
57
|
time_diff = df.index.to_series().diff().iloc[1:]
|
@@ -73,3 +75,16 @@ class SharedUtils:
|
|
73
75
|
)
|
74
76
|
sys.stdout.flush()
|
75
77
|
return df
|
78
|
+
|
79
|
+
@staticmethod
|
80
|
+
def clean_nan_values(df: pd.DataFrame) -> pd.DataFrame:
|
81
|
+
for col in df.columns:
|
82
|
+
if df[col].isnull().any():
|
83
|
+
print(f"NaN values found in column: {col}")
|
84
|
+
|
85
|
+
# Remove rows with any NaN values, then forward and backfill
|
86
|
+
df = df.dropna().ffill().bfill()
|
87
|
+
print("DataFrame has been cleaned for NaNs")
|
88
|
+
print("and has also been forward and backfilled.")
|
89
|
+
sys.stdout.flush()
|
90
|
+
return df
|
@@ -914,16 +914,8 @@ class FaultCodeSixteenReport(BaseFaultReport):
|
|
914
914
|
# Calculate the efficiency before plotting using FaultConditionSixteen method
|
915
915
|
df = self.fc16.calculate_erv_efficiency(df)
|
916
916
|
|
917
|
-
|
918
|
-
|
919
|
-
print("summary statistics ")
|
920
|
-
print(df["erv_efficiency_oa"].describe())
|
921
|
-
print("=" * 50)
|
922
|
-
|
923
|
-
sys.stdout.flush()
|
924
|
-
|
925
|
-
# Create the plot with four subplots
|
926
|
-
fig, (ax1, ax2, ax3, ax4) = plt.subplots(4, 1, figsize=(25, 10))
|
917
|
+
# Create the plot with five subplots
|
918
|
+
fig, (ax1, ax2, ax3, ax4, ax5) = plt.subplots(5, 1, figsize=(25, 14))
|
927
919
|
fig.suptitle("Fault Conditions 16 Plot")
|
928
920
|
|
929
921
|
# Plot ERV Outdoor Air Side Temps
|
@@ -953,6 +945,27 @@ class FaultCodeSixteenReport(BaseFaultReport):
|
|
953
945
|
ax4.set_ylabel("Fault Flags")
|
954
946
|
ax4.legend(loc="best")
|
955
947
|
|
948
|
+
# New Plot: Compare Distribution of OAT (Overall vs Fault True)
|
949
|
+
fault_true_df = df[df[self.fault_col] == 1]
|
950
|
+
data_to_plot = [
|
951
|
+
df[self.erv_oat_enter_col].dropna(), # Overall OAT
|
952
|
+
fault_true_df[self.erv_oat_enter_col].dropna(), # OAT when Fault is True
|
953
|
+
]
|
954
|
+
ax5.boxplot(
|
955
|
+
data_to_plot,
|
956
|
+
vert=False,
|
957
|
+
patch_artist=True,
|
958
|
+
labels=["Overall OAT", "OAT when Fault 16 is True"],
|
959
|
+
boxprops=dict(facecolor="lightblue"),
|
960
|
+
medianprops=dict(color="red"),
|
961
|
+
showmeans=True,
|
962
|
+
meanline=True,
|
963
|
+
meanprops=dict(color="green"),
|
964
|
+
)
|
965
|
+
ax5.set_xlabel("Outside Air Temperature (°F)")
|
966
|
+
ax5.set_title("Comparison of OAT Distribution")
|
967
|
+
ax5.grid(True)
|
968
|
+
|
956
969
|
plt.tight_layout(rect=[0, 0.03, 1, 0.95])
|
957
970
|
plt.show()
|
958
971
|
plt.close()
|
@@ -12,6 +12,7 @@ TEST_DUCT_STATIC_ERR_THRESHOLD = 0.1
|
|
12
12
|
TEST_DUCT_STATIC_COL = "duct_static"
|
13
13
|
TEST_DUCT_STATIC_SETPOINT_COL = "duct_static_setpoint"
|
14
14
|
TEST_SUPPLY_VFD_SPEED_COL = "supply_vfd_speed"
|
15
|
+
|
15
16
|
ROLLING_WINDOW_SIZE = 5
|
16
17
|
|
17
18
|
# Initialize FaultConditionOne with a dictionary
|
@@ -13,7 +13,6 @@ $ py -3.12 -m pytest open_fdd/tests/ahu/test_ahu_fc16.py -rP -s
|
|
13
13
|
ERV effectiveness should be within specified thresholds based on OAT.
|
14
14
|
"""
|
15
15
|
|
16
|
-
|
17
16
|
# Constants
|
18
17
|
TEST_ERV_EFFICIENCY_MIN_HEATING = 0.65
|
19
18
|
TEST_ERV_EFFICIENCY_MAX_HEATING = 0.8
|
@@ -21,7 +20,7 @@ TEST_ERV_EFFICIENCY_MIN_COOLING = 0.45
|
|
21
20
|
TEST_ERV_EFFICIENCY_MAX_COOLING = 0.6
|
22
21
|
TEST_OAT_LOW_THRESHOLD = 32.0
|
23
22
|
TEST_OAT_HIGH_THRESHOLD = 80.0
|
24
|
-
|
23
|
+
TEST_OAT_RAT_DELTA_THRES = 15.0
|
25
24
|
TEST_ERV_OAT_ENTER_COL = "erv_oat_enter"
|
26
25
|
TEST_ERV_OAT_LEAVING_COL = "erv_oat_leaving"
|
27
26
|
TEST_ERV_EAT_ENTER_COL = "erv_eat_enter"
|
@@ -37,7 +36,7 @@ fault_condition_params = {
|
|
37
36
|
"ERV_EFFICIENCY_MAX_COOLING": TEST_ERV_EFFICIENCY_MAX_COOLING,
|
38
37
|
"OAT_LOW_THRESHOLD": TEST_OAT_LOW_THRESHOLD,
|
39
38
|
"OAT_HIGH_THRESHOLD": TEST_OAT_HIGH_THRESHOLD,
|
40
|
-
"
|
39
|
+
"OAT_RAT_DELTA_MIN": TEST_OAT_RAT_DELTA_THRES,
|
41
40
|
"ERV_OAT_ENTER_COL": TEST_ERV_OAT_ENTER_COL,
|
42
41
|
"ERV_OAT_LEAVING_COL": TEST_ERV_OAT_LEAVING_COL,
|
43
42
|
"ERV_EAT_ENTER_COL": TEST_ERV_EAT_ENTER_COL,
|
@@ -107,6 +106,22 @@ class TestFaultConditionSixteen:
|
|
107
106
|
)
|
108
107
|
assert actual == expected, message
|
109
108
|
|
109
|
+
def test_fault_with_insufficient_oat_rat_delta(self):
|
110
|
+
"""Test that no fault is raised when the OAT-RAT delta is below the minimum threshold."""
|
111
|
+
data = {
|
112
|
+
TEST_ERV_OAT_ENTER_COL: [10, 10, 10, 10, 10, 10],
|
113
|
+
TEST_ERV_OAT_LEAVING_COL: [20.0, 20.5, 20.8, 20.6, 20.2, 20.4],
|
114
|
+
TEST_ERV_EAT_ENTER_COL: [24, 24, 24, 24, 24, 24], # Low delta with OAT
|
115
|
+
TEST_ERV_EAT_LEAVING_COL: [22, 22.5, 22.2, 22.4, 22.1, 22.3],
|
116
|
+
TEST_SUPPLY_VFD_SPEED_COL: [0.5, 0.6, 0.5, 0.7, 0.5, 0.6],
|
117
|
+
}
|
118
|
+
df = pd.DataFrame(data)
|
119
|
+
results = fc16.apply(df)
|
120
|
+
actual = results["fc16_flag"].sum()
|
121
|
+
expected = 0 # No fault should be triggered due to insufficient delta
|
122
|
+
message = f"FC16 fault_with_insufficient_oat_rat_delta actual is {actual} and expected is {expected}"
|
123
|
+
assert actual == expected, message
|
124
|
+
|
110
125
|
|
111
126
|
class TestFaultOnInvalidParams:
|
112
127
|
|
@@ -121,7 +136,7 @@ class TestFaultOnInvalidParams:
|
|
121
136
|
"ERV_EFFICIENCY_MAX_COOLING": 0.6,
|
122
137
|
"OAT_LOW_THRESHOLD": 32.0,
|
123
138
|
"OAT_HIGH_THRESHOLD": 80.0,
|
124
|
-
"
|
139
|
+
"OAT_RAT_DELTA_MIN": TEST_OAT_RAT_DELTA_THRES,
|
125
140
|
"ERV_OAT_ENTER_COL": TEST_ERV_OAT_ENTER_COL,
|
126
141
|
"ERV_OAT_LEAVING_COL": TEST_ERV_OAT_LEAVING_COL,
|
127
142
|
"ERV_EAT_ENTER_COL": TEST_ERV_EAT_ENTER_COL,
|
@@ -142,7 +157,7 @@ class TestFaultOnInvalidParams:
|
|
142
157
|
"ERV_EFFICIENCY_MAX_COOLING": 0.6,
|
143
158
|
"OAT_LOW_THRESHOLD": 32.0,
|
144
159
|
"OAT_HIGH_THRESHOLD": 80.0,
|
145
|
-
"
|
160
|
+
"OAT_RAT_DELTA_MIN": TEST_OAT_RAT_DELTA_THRES,
|
146
161
|
"ERV_OAT_ENTER_COL": TEST_ERV_OAT_ENTER_COL,
|
147
162
|
"ERV_OAT_LEAVING_COL": TEST_ERV_OAT_LEAVING_COL,
|
148
163
|
"ERV_EAT_ENTER_COL": TEST_ERV_EAT_ENTER_COL,
|
@@ -166,7 +181,7 @@ class TestFaultOnMissingColumns:
|
|
166
181
|
"ERV_EFFICIENCY_MAX_COOLING": 0.6,
|
167
182
|
"OAT_LOW_THRESHOLD": 32.0,
|
168
183
|
"OAT_HIGH_THRESHOLD": 80.0,
|
169
|
-
"
|
184
|
+
"OAT_RAT_DELTA_MIN": TEST_OAT_RAT_DELTA_THRES,
|
170
185
|
"ERV_OAT_ENTER_COL": TEST_ERV_OAT_ENTER_COL,
|
171
186
|
"ERV_OAT_LEAVING_COL": None, # Missing column
|
172
187
|
"ERV_EAT_ENTER_COL": TEST_ERV_EAT_ENTER_COL,
|
@@ -1,21 +1,21 @@
|
|
1
1
|
open_fdd/__init__.py,sha256=iGj8QTOZJUTE4nNnBiCHXEXsOdV6YvKcGiLrnOusJCg,1411
|
2
2
|
open_fdd/air_handling_unit/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
3
|
-
open_fdd/air_handling_unit/faults/__init__.py,sha256=
|
3
|
+
open_fdd/air_handling_unit/faults/__init__.py,sha256=Gc2VjfRDEX0-JcIrPuV692T3Ek3GGlTgrscqUXslrwY,93217
|
4
4
|
open_fdd/air_handling_unit/faults/fault_condition.py,sha256=UN2_k2AZWMDoO4oPAnJW3fvhkHlMkLXZikzU2lXAOuQ,2364
|
5
|
-
open_fdd/air_handling_unit/faults/helper_utils.py,sha256
|
6
|
-
open_fdd/air_handling_unit/faults/shared_utils.py,sha256=
|
7
|
-
open_fdd/air_handling_unit/reports/__init__.py,sha256=
|
5
|
+
open_fdd/air_handling_unit/faults/helper_utils.py,sha256=el_s2BC9Q14GXUGnazOiBBhzVUMsPBP9sxEG1UIQ6Gw,12668
|
6
|
+
open_fdd/air_handling_unit/faults/shared_utils.py,sha256=rAx27IsG_7OEHLLFHool6o9LAuaMyYisit9gLu8ZVQk,2802
|
7
|
+
open_fdd/air_handling_unit/reports/__init__.py,sha256=JccL19Spj6vE0Jo_57CmZEFucu4WbCPj1-pIwR5LmPg,40741
|
8
8
|
open_fdd/air_handling_unit/reports/fault_report.py,sha256=QxYLJzoLTwf1N0nls2XMmhHJvBSgGCBNT0KxA59QG4Y,1442
|
9
9
|
open_fdd/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
10
10
|
open_fdd/tests/ahu/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
11
|
-
open_fdd/tests/ahu/test_ahu_fc1.py,sha256=
|
11
|
+
open_fdd/tests/ahu/test_ahu_fc1.py,sha256=Pw5XlQ19c5Sit0Lyuor8L8lKgxl5PFn4UhruIHyKDfc,5439
|
12
12
|
open_fdd/tests/ahu/test_ahu_fc10.py,sha256=niYL7fi6OlgP0wnF8hNh9A07PLzHiRZkyRkrA1zoL2s,4577
|
13
13
|
open_fdd/tests/ahu/test_ahu_fc11.py,sha256=mdXlGiEMPkPfshf3NN_nJavL74e4HCmkJQMu86aZc6Q,4723
|
14
14
|
open_fdd/tests/ahu/test_ahu_fc12.py,sha256=5T-XcM6xm9KHrc121uPGC9JWLCYehrAYk0KcbmGgYjw,5848
|
15
15
|
open_fdd/tests/ahu/test_ahu_fc13.py,sha256=vJlSy4e2WV9hx02P0SiJ75I1DWL2lZ0p7-AWlw97pks,5725
|
16
16
|
open_fdd/tests/ahu/test_ahu_fc14.py,sha256=MU0LKqIuoQ_dJ0Kij8_A0YyimCMvUwL6IlMwpQhDbqI,8052
|
17
17
|
open_fdd/tests/ahu/test_ahu_fc15.py,sha256=SIolJ9vnJwnpKfRW2ALugYWySuIiZ9_repWP9fdb5H4,7661
|
18
|
-
open_fdd/tests/ahu/test_ahu_fc16.py,sha256=
|
18
|
+
open_fdd/tests/ahu/test_ahu_fc16.py,sha256=f656EZCWEKOXE2GZHUayaLc8bjMZWX_QB99QDBJxF4Y,9020
|
19
19
|
open_fdd/tests/ahu/test_ahu_fc2.py,sha256=CjmO_WUyaSHs17ifCCew3GBJ43nYG55uGL0vHDZpAq8,4736
|
20
20
|
open_fdd/tests/ahu/test_ahu_fc3.py,sha256=NB6pOXDS-R4P0LNoRN8ItAqhhLnGnGuAHZha32Qw-hE,4658
|
21
21
|
open_fdd/tests/ahu/test_ahu_fc4.py,sha256=vV8jEnFuNGLfhCoTVz29RsIcoDpDOMWg722G0aBEXaE,6304
|
@@ -24,8 +24,8 @@ open_fdd/tests/ahu/test_ahu_fc6.py,sha256=66dwv0EBU_ujZK-J9Ki5a3fnXlk17nOwmtKDiQ
|
|
24
24
|
open_fdd/tests/ahu/test_ahu_fc7.py,sha256=sABbw2m7WlAXbsqfDD323vfEfg606ThI0QzQyB-OjFo,2469
|
25
25
|
open_fdd/tests/ahu/test_ahu_fc8.py,sha256=UZy6BP2PgV1FROUPqMORTx8YnT5ZvqVDhut_Ar81494,4663
|
26
26
|
open_fdd/tests/ahu/test_ahu_fc9.py,sha256=b-eIzhNzjZUjVNsP0JAHkOgZu-BtDuPeNnblVVm-jU8,4796
|
27
|
-
open_fdd-0.1.
|
28
|
-
open_fdd-0.1.
|
29
|
-
open_fdd-0.1.
|
30
|
-
open_fdd-0.1.
|
31
|
-
open_fdd-0.1.
|
27
|
+
open_fdd-0.1.7.dist-info/LICENSE,sha256=eghao_GGx_0gB2Sll3x2vV29knONEzUQKrkaXpX1F7w,1087
|
28
|
+
open_fdd-0.1.7.dist-info/METADATA,sha256=891NmSrFes9HOcjBiW0Lp7ixCbjN4lhorEWtOWICg0E,6958
|
29
|
+
open_fdd-0.1.7.dist-info/WHEEL,sha256=uCRv0ZEik_232NlR4YDw4Pv3Ajt5bKvMH13NUU7hFuI,91
|
30
|
+
open_fdd-0.1.7.dist-info/top_level.txt,sha256=Q7sB6UB2d8Ch1v_xIsTiNegmgcCXPkwkrxK3ug6VEOs,9
|
31
|
+
open_fdd-0.1.7.dist-info/RECORD,,
|
File without changes
|
File without changes
|