huff 1.5.5__py3-none-any.whl → 1.5.6__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.
- huff/gistools.py +210 -5
- huff/osm.py +5 -142
- huff/tests/tests_huff.py +3 -4
- {huff-1.5.5.dist-info → huff-1.5.6.dist-info}/METADATA +6 -5
- {huff-1.5.5.dist-info → huff-1.5.6.dist-info}/RECORD +7 -7
- {huff-1.5.5.dist-info → huff-1.5.6.dist-info}/WHEEL +0 -0
- {huff-1.5.5.dist-info → huff-1.5.6.dist-info}/top_level.txt +0 -0
huff/gistools.py
CHANGED
@@ -4,22 +4,30 @@
|
|
4
4
|
# Author: Thomas Wieland
|
5
5
|
# ORCID: 0000-0001-5168-9846
|
6
6
|
# mail: geowieland@googlemail.com
|
7
|
-
# Version: 1.4.
|
8
|
-
# Last update: 2025-
|
7
|
+
# Version: 1.4.2
|
8
|
+
# Last update: 2025-07-31 18:31
|
9
9
|
# Copyright (c) 2025 Thomas Wieland
|
10
10
|
#-----------------------------------------------------------------------
|
11
11
|
|
12
12
|
|
13
|
+
import os
|
13
14
|
import geopandas as gp
|
14
15
|
import pandas as pd
|
15
16
|
from pandas.api.types import is_numeric_dtype
|
16
17
|
from math import pi, sin, cos, acos
|
18
|
+
from matplotlib.patches import Patch
|
19
|
+
import matplotlib.pyplot as plt
|
20
|
+
from shapely.geometry import LineString, box
|
21
|
+
import contextily as cx
|
22
|
+
from PIL import Image
|
23
|
+
from huff.osm import get_basemap
|
17
24
|
|
18
25
|
|
19
26
|
def distance_matrix(
|
20
27
|
sources: list,
|
21
28
|
destinations: list,
|
22
29
|
unit: str = "m",
|
30
|
+
lines_gdf: bool = False
|
23
31
|
):
|
24
32
|
|
25
33
|
def euclidean_distance (
|
@@ -48,18 +56,36 @@ def distance_matrix(
|
|
48
56
|
|
49
57
|
matrix = []
|
50
58
|
|
59
|
+
if lines_gdf:
|
60
|
+
line_data = []
|
61
|
+
|
51
62
|
for source in sources:
|
63
|
+
|
52
64
|
row = []
|
53
65
|
for destination in destinations:
|
66
|
+
|
54
67
|
dist = euclidean_distance(
|
55
68
|
source,
|
56
69
|
destination,
|
57
70
|
unit
|
58
71
|
)
|
59
72
|
row.append(dist)
|
73
|
+
|
74
|
+
if lines_gdf:
|
75
|
+
line = LineString([source, destination])
|
76
|
+
line_data.append({
|
77
|
+
"source": source,
|
78
|
+
"destination": destination,
|
79
|
+
"distance": dist,
|
80
|
+
"geometry": line
|
81
|
+
})
|
82
|
+
|
60
83
|
matrix.append(row)
|
61
84
|
|
62
|
-
|
85
|
+
if lines_gdf:
|
86
|
+
return line_data
|
87
|
+
else:
|
88
|
+
return matrix
|
63
89
|
|
64
90
|
|
65
91
|
def buffers(
|
@@ -72,7 +98,13 @@ def buffers(
|
|
72
98
|
output_crs: str = "EPSG:4326"
|
73
99
|
):
|
74
100
|
|
75
|
-
all_buffers_gdf = gp.GeoDataFrame(
|
101
|
+
all_buffers_gdf = gp.GeoDataFrame(
|
102
|
+
columns=[
|
103
|
+
unique_id_col,
|
104
|
+
"segment",
|
105
|
+
"geometry"
|
106
|
+
]
|
107
|
+
)
|
76
108
|
|
77
109
|
for idx, row in point_gdf.iterrows():
|
78
110
|
|
@@ -115,7 +147,9 @@ def buffers(
|
|
115
147
|
all_buffers_gdf = all_buffers_gdf.to_crs(output_crs)
|
116
148
|
|
117
149
|
if save_output:
|
150
|
+
|
118
151
|
all_buffers_gdf.to_file(output_filepath)
|
152
|
+
|
119
153
|
print ("Saved as", output_filepath)
|
120
154
|
|
121
155
|
return all_buffers_gdf
|
@@ -218,4 +252,175 @@ def point_spatial_join(
|
|
218
252
|
return [
|
219
253
|
shp_points_gdf_join,
|
220
254
|
spatial_join_stat
|
221
|
-
]
|
255
|
+
]
|
256
|
+
|
257
|
+
def map_with_basemap(
|
258
|
+
layers: list,
|
259
|
+
osm_basemap: bool = True,
|
260
|
+
zoom: int = 15,
|
261
|
+
figsize=(10, 10),
|
262
|
+
bounds_factor = [0.9999, 0.9999, 1.0001, 1.0001],
|
263
|
+
styles: dict = {},
|
264
|
+
save_output: bool = True,
|
265
|
+
output_filepath: str = "osm_map_with_basemap.png",
|
266
|
+
output_dpi=300,
|
267
|
+
legend: bool = True,
|
268
|
+
show_plot: bool = True,
|
269
|
+
verbose: bool = False
|
270
|
+
):
|
271
|
+
|
272
|
+
if not isinstance(layers, list):
|
273
|
+
raise ValueError("Param 'layers' must be a list")
|
274
|
+
|
275
|
+
if not layers:
|
276
|
+
raise ValueError("List layers is empty")
|
277
|
+
|
278
|
+
if verbose:
|
279
|
+
print("Combining layers ...", end = " ")
|
280
|
+
|
281
|
+
layers_combined = gp.GeoDataFrame(
|
282
|
+
pd.concat(
|
283
|
+
layers,
|
284
|
+
ignore_index=True
|
285
|
+
),
|
286
|
+
crs=layers[0].crs
|
287
|
+
)
|
288
|
+
|
289
|
+
layers_combined_wgs84 = layers_combined.to_crs(epsg=4326)
|
290
|
+
|
291
|
+
if verbose:
|
292
|
+
print("OK")
|
293
|
+
print("Retrieving total bounds ...", end = " ")
|
294
|
+
|
295
|
+
bounds = layers_combined_wgs84.total_bounds
|
296
|
+
|
297
|
+
sw_lon, sw_lat, ne_lon, ne_lat = bounds[0]*bounds_factor[0], bounds[1]*bounds_factor[1], bounds[2]*bounds_factor[2], bounds[3]*bounds_factor[3]
|
298
|
+
|
299
|
+
if verbose:
|
300
|
+
print("OK")
|
301
|
+
|
302
|
+
if osm_basemap:
|
303
|
+
|
304
|
+
if verbose:
|
305
|
+
print("Retrieving OSM basemap ...", end = " ")
|
306
|
+
|
307
|
+
get_basemap(sw_lat, sw_lon, ne_lat, ne_lon, zoom=zoom)
|
308
|
+
|
309
|
+
fig, ax = plt.subplots(figsize=figsize)
|
310
|
+
|
311
|
+
if osm_basemap:
|
312
|
+
|
313
|
+
img = Image.open("osm_map.png")
|
314
|
+
extent_img = [sw_lon, ne_lon, sw_lat, ne_lat]
|
315
|
+
ax.imshow(img, extent=extent_img, origin="upper")
|
316
|
+
|
317
|
+
if verbose:
|
318
|
+
print("OK")
|
319
|
+
|
320
|
+
if verbose:
|
321
|
+
print("Inserting layers and plotting map ...", end = " ")
|
322
|
+
|
323
|
+
i = 0
|
324
|
+
legend_handles = []
|
325
|
+
|
326
|
+
for layer in layers:
|
327
|
+
|
328
|
+
layer_3857 = layer.to_crs(epsg=3857)
|
329
|
+
|
330
|
+
if styles != {}:
|
331
|
+
|
332
|
+
layer_style = styles[i]
|
333
|
+
layer_color = layer_style["color"]
|
334
|
+
layer_alpha = layer_style["alpha"]
|
335
|
+
layer_name = layer_style["name"]
|
336
|
+
|
337
|
+
if isinstance(layer_color, str):
|
338
|
+
layer_3857.plot(
|
339
|
+
ax=ax,
|
340
|
+
color=layer_color,
|
341
|
+
alpha=layer_alpha,
|
342
|
+
label=layer_name
|
343
|
+
)
|
344
|
+
if legend:
|
345
|
+
patch = Patch(
|
346
|
+
facecolor=layer_color,
|
347
|
+
alpha=layer_alpha,
|
348
|
+
label=layer_name
|
349
|
+
)
|
350
|
+
legend_handles.append(patch)
|
351
|
+
|
352
|
+
elif isinstance(layer_color, dict):
|
353
|
+
color_key = list(layer_color.keys())[0]
|
354
|
+
color_mapping = layer_color[color_key]
|
355
|
+
|
356
|
+
if color_key not in layer_3857.columns:
|
357
|
+
raise KeyError("Column " + color_key + " not in layer.")
|
358
|
+
|
359
|
+
for value, color in color_mapping.items():
|
360
|
+
|
361
|
+
subset = layer_3857[layer_3857[color_key].astype(str) == str(value)]
|
362
|
+
|
363
|
+
if not subset.empty:
|
364
|
+
|
365
|
+
subset.plot(
|
366
|
+
ax=ax,
|
367
|
+
color=color,
|
368
|
+
alpha=layer_alpha,
|
369
|
+
label=str(value)
|
370
|
+
)
|
371
|
+
|
372
|
+
if legend:
|
373
|
+
patch = Patch(facecolor=color, alpha=layer_alpha, label=str(value))
|
374
|
+
legend_handles.append(patch)
|
375
|
+
|
376
|
+
else:
|
377
|
+
|
378
|
+
layer_3857.plot(ax=ax, alpha=0.6, label=f"Layer {i+1}")
|
379
|
+
|
380
|
+
if legend:
|
381
|
+
|
382
|
+
patch = Patch(
|
383
|
+
facecolor="gray",
|
384
|
+
alpha=0.6,
|
385
|
+
label=f"Layer {i+1}"
|
386
|
+
)
|
387
|
+
|
388
|
+
legend_handles.append(patch)
|
389
|
+
|
390
|
+
i += 1
|
391
|
+
|
392
|
+
bbox = box(sw_lon, sw_lat, ne_lon, ne_lat)
|
393
|
+
extent_geom = gp.GeoSeries([bbox], crs=4326).to_crs(epsg=3857).total_bounds
|
394
|
+
ax.set_xlim(extent_geom[0], extent_geom[2])
|
395
|
+
ax.set_ylim(extent_geom[1], extent_geom[3])
|
396
|
+
|
397
|
+
if osm_basemap:
|
398
|
+
cx.add_basemap(
|
399
|
+
ax,
|
400
|
+
source=cx.providers.OpenStreetMap.Mapnik,
|
401
|
+
zoom=zoom
|
402
|
+
)
|
403
|
+
|
404
|
+
plt.axis('off')
|
405
|
+
|
406
|
+
if legend and legend_handles:
|
407
|
+
ax.legend(handles=legend_handles, loc='lower right', fontsize='small', frameon=True)
|
408
|
+
|
409
|
+
if verbose:
|
410
|
+
print("OK")
|
411
|
+
|
412
|
+
if show_plot:
|
413
|
+
plt.show()
|
414
|
+
|
415
|
+
if save_output:
|
416
|
+
plt.savefig(
|
417
|
+
output_filepath,
|
418
|
+
dpi=output_dpi,
|
419
|
+
bbox_inches="tight"
|
420
|
+
)
|
421
|
+
plt.close()
|
422
|
+
|
423
|
+
if os.path.exists("osm_map.png"):
|
424
|
+
os.remove("osm_map.png")
|
425
|
+
|
426
|
+
return fig
|
huff/osm.py
CHANGED
@@ -4,24 +4,17 @@
|
|
4
4
|
# Author: Thomas Wieland
|
5
5
|
# ORCID: 0000-0001-5168-9846
|
6
6
|
# mail: geowieland@googlemail.com
|
7
|
-
# Version: 1.4.
|
8
|
-
# Last update: 2025-
|
7
|
+
# Version: 1.4.2
|
8
|
+
# Last update: 2025-07-31 18:24
|
9
9
|
# Copyright (c) 2025 Thomas Wieland
|
10
10
|
#-----------------------------------------------------------------------
|
11
11
|
|
12
12
|
|
13
|
-
import pandas as pd
|
14
|
-
import geopandas as gpd
|
15
13
|
import math
|
16
14
|
import requests
|
17
15
|
import tempfile
|
18
16
|
import time
|
19
|
-
import os
|
20
17
|
from PIL import Image
|
21
|
-
import matplotlib.pyplot as plt
|
22
|
-
from matplotlib.patches import Patch
|
23
|
-
import contextily as cx
|
24
|
-
from shapely.geometry import box
|
25
18
|
|
26
19
|
|
27
20
|
class Client:
|
@@ -79,8 +72,9 @@ def get_basemap(
|
|
79
72
|
lat,
|
80
73
|
lon,
|
81
74
|
zoom
|
75
|
+
# https://wiki.openstreetmap.org/wiki/Zoom_levels
|
82
76
|
):
|
83
|
-
|
77
|
+
|
84
78
|
n = 2 ** zoom
|
85
79
|
x = int(n * ((lon + 180) / 360))
|
86
80
|
y = int(n * (1 - (math.log(math.tan(math.radians(lat)) + 1 / math.cos(math.radians(lat))) / math.pi)) / 2)
|
@@ -133,135 +127,4 @@ def get_basemap(
|
|
133
127
|
stitched_image.save(stitched_image_path)
|
134
128
|
|
135
129
|
else:
|
136
|
-
print("Error while building stitched images")
|
137
|
-
|
138
|
-
|
139
|
-
def map_with_basemap(
|
140
|
-
layers: list,
|
141
|
-
osm_basemap: bool = True,
|
142
|
-
zoom: int = 15,
|
143
|
-
styles: dict = {},
|
144
|
-
save_output: bool = True,
|
145
|
-
output_filepath: str = "osm_map_with_basemap.png",
|
146
|
-
output_dpi=300,
|
147
|
-
legend: bool = True
|
148
|
-
):
|
149
|
-
if not layers:
|
150
|
-
raise ValueError("List layers is empty")
|
151
|
-
|
152
|
-
combined = gpd.GeoDataFrame(
|
153
|
-
pd.concat(layers, ignore_index=True),
|
154
|
-
crs=layers[0].crs
|
155
|
-
)
|
156
|
-
|
157
|
-
combined_wgs84 = combined.to_crs(epsg=4326)
|
158
|
-
bounds = combined_wgs84.total_bounds
|
159
|
-
|
160
|
-
sw_lon, sw_lat, ne_lon, ne_lat = bounds[0]*0.9999, bounds[1]*0.9999, bounds[2]*1.0001, bounds[3]*1.0001
|
161
|
-
|
162
|
-
if osm_basemap:
|
163
|
-
get_basemap(sw_lat, sw_lon, ne_lat, ne_lon, zoom=zoom)
|
164
|
-
|
165
|
-
fig, ax = plt.subplots(figsize=(10, 10))
|
166
|
-
|
167
|
-
if osm_basemap:
|
168
|
-
img = Image.open("osm_map.png")
|
169
|
-
extent_img = [sw_lon, ne_lon, sw_lat, ne_lat]
|
170
|
-
ax.imshow(img, extent=extent_img, origin="upper")
|
171
|
-
|
172
|
-
i = 0
|
173
|
-
legend_handles = []
|
174
|
-
|
175
|
-
for layer in layers:
|
176
|
-
layer_3857 = layer.to_crs(epsg=3857)
|
177
|
-
|
178
|
-
if styles != {}:
|
179
|
-
layer_style = styles[i]
|
180
|
-
layer_color = layer_style["color"]
|
181
|
-
layer_alpha = layer_style["alpha"]
|
182
|
-
layer_name = layer_style["name"]
|
183
|
-
|
184
|
-
if isinstance(layer_color, str):
|
185
|
-
layer_3857.plot(
|
186
|
-
ax=ax,
|
187
|
-
color=layer_color,
|
188
|
-
alpha=layer_alpha,
|
189
|
-
label=layer_name
|
190
|
-
)
|
191
|
-
if legend:
|
192
|
-
patch = Patch(
|
193
|
-
facecolor=layer_color,
|
194
|
-
alpha=layer_alpha,
|
195
|
-
label=layer_name
|
196
|
-
)
|
197
|
-
legend_handles.append(patch)
|
198
|
-
|
199
|
-
elif isinstance(layer_color, dict):
|
200
|
-
color_key = list(layer_color.keys())[0]
|
201
|
-
color_mapping = layer_color[color_key]
|
202
|
-
|
203
|
-
if color_key not in layer_3857.columns:
|
204
|
-
raise KeyError("Column " + color_key + " not in layer.")
|
205
|
-
|
206
|
-
for value, color in color_mapping.items():
|
207
|
-
|
208
|
-
subset = layer_3857[layer_3857[color_key].astype(str) == str(value)]
|
209
|
-
|
210
|
-
if not subset.empty:
|
211
|
-
|
212
|
-
subset.plot(
|
213
|
-
ax=ax,
|
214
|
-
color=color,
|
215
|
-
alpha=layer_alpha,
|
216
|
-
label=str(value)
|
217
|
-
)
|
218
|
-
|
219
|
-
if legend:
|
220
|
-
patch = Patch(facecolor=color, alpha=layer_alpha, label=str(value))
|
221
|
-
legend_handles.append(patch)
|
222
|
-
|
223
|
-
else:
|
224
|
-
|
225
|
-
layer_3857.plot(ax=ax, alpha=0.6, label=f"Layer {i+1}")
|
226
|
-
|
227
|
-
if legend:
|
228
|
-
|
229
|
-
patch = Patch(
|
230
|
-
facecolor="gray",
|
231
|
-
alpha=0.6,
|
232
|
-
label=f"Layer {i+1}"
|
233
|
-
)
|
234
|
-
|
235
|
-
legend_handles.append(patch)
|
236
|
-
|
237
|
-
i += 1
|
238
|
-
|
239
|
-
bbox = box(sw_lon, sw_lat, ne_lon, ne_lat)
|
240
|
-
extent_geom = gpd.GeoSeries([bbox], crs=4326).to_crs(epsg=3857).total_bounds
|
241
|
-
ax.set_xlim(extent_geom[0], extent_geom[2])
|
242
|
-
ax.set_ylim(extent_geom[1], extent_geom[3])
|
243
|
-
|
244
|
-
if osm_basemap:
|
245
|
-
cx.add_basemap(
|
246
|
-
ax,
|
247
|
-
source=cx.providers.OpenStreetMap.Mapnik,
|
248
|
-
zoom=zoom
|
249
|
-
)
|
250
|
-
|
251
|
-
plt.axis('off')
|
252
|
-
|
253
|
-
if legend and legend_handles:
|
254
|
-
ax.legend(handles=legend_handles, loc='lower right', fontsize='small', frameon=True)
|
255
|
-
|
256
|
-
plt.show()
|
257
|
-
|
258
|
-
if save_output:
|
259
|
-
plt.savefig(
|
260
|
-
output_filepath,
|
261
|
-
dpi=output_dpi,
|
262
|
-
bbox_inches="tight"
|
263
|
-
)
|
264
|
-
plt.close()
|
265
|
-
|
266
|
-
if os.path.exists("osm_map.png"):
|
267
|
-
os.remove("osm_map.png")
|
130
|
+
print("Error while building stitched images")
|
huff/tests/tests_huff.py
CHANGED
@@ -4,15 +4,14 @@
|
|
4
4
|
# Author: Thomas Wieland
|
5
5
|
# ORCID: 0000-0001-5168-9846
|
6
6
|
# mail: geowieland@googlemail.com
|
7
|
-
# Version: 1.5.
|
8
|
-
# Last update: 2025-07-
|
7
|
+
# Version: 1.5.6
|
8
|
+
# Last update: 2025-07-31 18:33
|
9
9
|
# Copyright (c) 2025 Thomas Wieland
|
10
10
|
#-----------------------------------------------------------------------
|
11
11
|
|
12
12
|
from huff.models import create_interaction_matrix, get_isochrones, load_geodata, load_interaction_matrix, load_marketareas, market_shares, modelfit
|
13
13
|
from huff.models import HuffModel
|
14
|
-
from huff.
|
15
|
-
from huff.gistools import buffers, point_spatial_join
|
14
|
+
from huff.gistools import buffers, point_spatial_join, map_with_basemap
|
16
15
|
|
17
16
|
|
18
17
|
# Dealing with customer origins (statistical districts):
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: huff
|
3
|
-
Version: 1.5.
|
3
|
+
Version: 1.5.6
|
4
4
|
Summary: huff: Huff Model Market Area Analysis
|
5
5
|
Author: Thomas Wieland
|
6
6
|
Author-email: geowieland@googlemail.com
|
@@ -28,10 +28,11 @@ Thomas Wieland [ORCID](https://orcid.org/0000-0001-5168-9846) [EMail](mailto:geo
|
|
28
28
|
See the /tests directory for usage examples of most of the included functions.
|
29
29
|
|
30
30
|
|
31
|
-
## Updates v1.5.
|
32
|
-
-
|
33
|
-
-
|
34
|
-
|
31
|
+
## Updates v1.5.6
|
32
|
+
- Extensions:
|
33
|
+
- gistools.distance_matrix() now includes line geometry output
|
34
|
+
- Other
|
35
|
+
- map_with_basemap() now belongs to huff.gistools
|
35
36
|
|
36
37
|
|
37
38
|
## Features
|
@@ -1,10 +1,10 @@
|
|
1
1
|
huff/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2
|
-
huff/gistools.py,sha256=
|
2
|
+
huff/gistools.py,sha256=cffGqNRaCaIE0f52j5bGpgbdxMxy8zmeMQqPhrVSfOE,12890
|
3
3
|
huff/models.py,sha256=yrV4enajAG0bHCgrGh3w-SNX5kJDJnuE28i6RXN30HE,134903
|
4
4
|
huff/ors.py,sha256=JlO2UEishQX87PIiktksOrVT5QdB-GEWgjXcxoR_KuA,11929
|
5
|
-
huff/osm.py,sha256=
|
5
|
+
huff/osm.py,sha256=1a74HkKgAJYLWdthnAslOEJiHYz7qI3dk7u4ku6Jq0o,3563
|
6
6
|
huff/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
7
|
-
huff/tests/tests_huff.py,sha256=
|
7
|
+
huff/tests/tests_huff.py,sha256=B7C74NhXPtuwWY8X-5dxrB5GQLnT4OqgId4ZSGaTBQo,13095
|
8
8
|
huff/tests/data/Haslach.cpg,sha256=OtMDH1UDpEBK-CUmLugjLMBNTqZoPULF3QovKiesmCQ,5
|
9
9
|
huff/tests/data/Haslach.dbf,sha256=GVPIt05OzDO7UrRDcsMhiYWvyXAPg6Z-qkiysFzj-fc,506
|
10
10
|
huff/tests/data/Haslach.prj,sha256=2Jy1Vlzh7UxQ1MXpZ9UYLs2SxfrObj2xkEkZyLqmGTY,437
|
@@ -24,7 +24,7 @@ huff/tests/data/Haslach_supermarkets.qmd,sha256=JlcOYzG4vI1NH1IuOpxwIPnJsCyC-pDR
|
|
24
24
|
huff/tests/data/Haslach_supermarkets.shp,sha256=X7QbQ0BTMag_B-bDRbpr-go2BQIXo3Y8zMAKpYZmlps,324
|
25
25
|
huff/tests/data/Haslach_supermarkets.shx,sha256=j23QHX-SmdAeN04rw0x8nUOran-OCg_T6r_LvzzEPWs,164
|
26
26
|
huff/tests/data/Wieland2015.xlsx,sha256=H4rxCFlctn44-O6mIyeFf67FlgvznLX7xZqpoWYS41A,25788
|
27
|
-
huff-1.5.
|
28
|
-
huff-1.5.
|
29
|
-
huff-1.5.
|
30
|
-
huff-1.5.
|
27
|
+
huff-1.5.6.dist-info/METADATA,sha256=4ZRQx28t5HIXwoHSlNG-S2Q0hocMBAnhmgkYEkV95PI,6023
|
28
|
+
huff-1.5.6.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
|
29
|
+
huff-1.5.6.dist-info/top_level.txt,sha256=nlzX-PxZNFmIxANIJMySuIFPihd6qOBkRlhIC28NEsQ,5
|
30
|
+
huff-1.5.6.dist-info/RECORD,,
|
File without changes
|
File without changes
|