multiSSH3 5.0__py3-none-any.whl → 5.4__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.
Potentially problematic release.
This version of multiSSH3 might be problematic. Click here for more details.
- {multiSSH3-5.0.dist-info → multiSSH3-5.4.dist-info}/METADATA +1 -1
- multiSSH3-5.4.dist-info/RECORD +7 -0
- multiSSH3.py +83 -39
- multiSSH3-5.0.dist-info/RECORD +0 -7
- {multiSSH3-5.0.dist-info → multiSSH3-5.4.dist-info}/LICENSE +0 -0
- {multiSSH3-5.0.dist-info → multiSSH3-5.4.dist-info}/WHEEL +0 -0
- {multiSSH3-5.0.dist-info → multiSSH3-5.4.dist-info}/entry_points.txt +0 -0
- {multiSSH3-5.0.dist-info → multiSSH3-5.4.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
multiSSH3.py,sha256=U5BjFNI9GfDr8Nbj6KOkSo6f0FQ7kGtgFSxDPA2gKNA,100793
|
|
2
|
+
multiSSH3-5.4.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
|
3
|
+
multiSSH3-5.4.dist-info/METADATA,sha256=hvYNJ9SyZ_E3Bk9cM61WJkdEqknsNZQ6FLetMx8brtA,17516
|
|
4
|
+
multiSSH3-5.4.dist-info/WHEEL,sha256=OVMc5UfuAQiSplgO0_WdW7vXVGAt9Hdd6qtN4HotdyA,91
|
|
5
|
+
multiSSH3-5.4.dist-info/entry_points.txt,sha256=xi2rWWNfmHx6gS8Mmx0rZL2KZz6XWBYP3DWBpWAnnZ0,143
|
|
6
|
+
multiSSH3-5.4.dist-info/top_level.txt,sha256=tUwttxlnpLkZorSsroIprNo41lYSxjd2ASuL8-EJIJw,10
|
|
7
|
+
multiSSH3-5.4.dist-info/RECORD,,
|
multiSSH3.py
CHANGED
|
@@ -31,7 +31,7 @@ except AttributeError:
|
|
|
31
31
|
# If neither is available, use a dummy decorator
|
|
32
32
|
def cache_decorator(func):
|
|
33
33
|
return func
|
|
34
|
-
version = '5.
|
|
34
|
+
version = '5.04'
|
|
35
35
|
VERSION = version
|
|
36
36
|
|
|
37
37
|
CONFIG_FILE = '/etc/multiSSH3.config.json'
|
|
@@ -980,7 +980,14 @@ def get_hosts_to_display (hosts, max_num_hosts, hosts_to_display = None):
|
|
|
980
980
|
host.printedLines = 0
|
|
981
981
|
return new_hosts_to_display , {'running':len(running_hosts), 'failed':len(failed_hosts), 'finished':len(finished_hosts), 'waiting':len(waiting_hosts)}
|
|
982
982
|
|
|
983
|
-
|
|
983
|
+
# Error: integer division or modulo by zero, Reloading Configuration: min_char_len=40, min_line_len=1, single_window=False with window size (61, 186) and 1 hosts...
|
|
984
|
+
# Traceback (most recent call last):
|
|
985
|
+
# File "/usr/local/lib/python3.11/site-packages/multiSSH3.py", line 1030, in generate_display
|
|
986
|
+
# host_window_height = max_y // num_hosts_y
|
|
987
|
+
# ~~~~~~^^~~~~~~~~~~~~
|
|
988
|
+
# ZeroDivisionError: integer division or modulo by zero
|
|
989
|
+
|
|
990
|
+
def generate_display(stdscr, hosts, lineToDisplay = -1,curserPosition = 0, min_char_len = DEFAULT_CURSES_MINIMUM_CHAR_LEN, min_line_len = DEFAULT_CURSES_MINIMUM_LINE_LEN,single_window=DEFAULT_SINGLE_WINDOW, config_reason= 'New Configuration'):
|
|
984
991
|
try:
|
|
985
992
|
org_dim = stdscr.getmaxyx()
|
|
986
993
|
new_configured = True
|
|
@@ -996,9 +1003,9 @@ def generate_display(stdscr, hosts, lineToDisplay = -1,curserPosition = 0, min_c
|
|
|
996
1003
|
min_line_len_local = max_y-1
|
|
997
1004
|
# return True if the terminal is too small
|
|
998
1005
|
if max_x < 2 or max_y < 2:
|
|
999
|
-
return (lineToDisplay,curserPosition , min_char_len, min_line_len, single_window)
|
|
1006
|
+
return (lineToDisplay,curserPosition , min_char_len, min_line_len, single_window, 'Terminal too small')
|
|
1000
1007
|
if min_char_len_local < 1 or min_line_len_local < 1:
|
|
1001
|
-
return (lineToDisplay,curserPosition , min_char_len, min_line_len, single_window)
|
|
1008
|
+
return (lineToDisplay,curserPosition , min_char_len, min_line_len, single_window, 'Minimum character or line length too small')
|
|
1002
1009
|
# We need to figure out how many hosts we can fit in the terminal
|
|
1003
1010
|
# We will need at least 2 lines per host, one for its name, one for its output
|
|
1004
1011
|
# Each line will be at least 61 characters long (60 for the output, 1 for the borders)
|
|
@@ -1006,14 +1013,14 @@ def generate_display(stdscr, hosts, lineToDisplay = -1,curserPosition = 0, min_c
|
|
|
1006
1013
|
max_num_hosts_y = max_y // (min_line_len_local + 1)
|
|
1007
1014
|
max_num_hosts = max_num_hosts_x * max_num_hosts_y
|
|
1008
1015
|
if max_num_hosts < 1:
|
|
1009
|
-
return (lineToDisplay,curserPosition , min_char_len, min_line_len, single_window)
|
|
1016
|
+
return (lineToDisplay,curserPosition , min_char_len, min_line_len, single_window, 'Terminal too small to display any hosts')
|
|
1010
1017
|
hosts_to_display , host_stats = get_hosts_to_display(hosts, max_num_hosts)
|
|
1011
1018
|
if len(hosts_to_display) == 0:
|
|
1012
|
-
return (lineToDisplay,curserPosition , min_char_len, min_line_len, single_window)
|
|
1019
|
+
return (lineToDisplay,curserPosition , min_char_len, min_line_len, single_window, 'No hosts to display')
|
|
1013
1020
|
# Now we calculate the actual number of hosts we will display for x and y
|
|
1014
1021
|
optimal_len_x = max(min_char_len_local, 80)
|
|
1015
|
-
num_hosts_x = max(min(max_num_hosts_x, max_x // optimal_len_x),1)
|
|
1016
|
-
num_hosts_y = len(hosts_to_display) // num_hosts_x
|
|
1022
|
+
num_hosts_x = min(max(min(max_num_hosts_x, max_x // optimal_len_x),1),len(hosts_to_display))
|
|
1023
|
+
num_hosts_y = len(hosts_to_display) // num_hosts_x + (len(hosts_to_display) % num_hosts_x > 0)
|
|
1017
1024
|
while num_hosts_y > max_num_hosts_y:
|
|
1018
1025
|
num_hosts_x += 1
|
|
1019
1026
|
# round up for num_hosts_y
|
|
@@ -1025,12 +1032,12 @@ def generate_display(stdscr, hosts, lineToDisplay = -1,curserPosition = 0, min_c
|
|
|
1025
1032
|
num_hosts_x += 1
|
|
1026
1033
|
num_hosts_y = len(hosts_to_display) // num_hosts_x + (len(hosts_to_display) % num_hosts_x > 0)
|
|
1027
1034
|
break
|
|
1028
|
-
|
|
1035
|
+
num_hosts_y = max(num_hosts_y,1)
|
|
1029
1036
|
# We calculate the size of each window
|
|
1030
1037
|
host_window_height = max_y // num_hosts_y
|
|
1031
1038
|
host_window_width = max_x // num_hosts_x
|
|
1032
1039
|
if host_window_height < 1 or host_window_width < 1:
|
|
1033
|
-
return (lineToDisplay,curserPosition , min_char_len, min_line_len, single_window)
|
|
1040
|
+
return (lineToDisplay,curserPosition , min_char_len, min_line_len, single_window, 'Host window too small')
|
|
1034
1041
|
|
|
1035
1042
|
old_stat = ''
|
|
1036
1043
|
old_bottom_stat = ''
|
|
@@ -1071,24 +1078,24 @@ def generate_display(stdscr, hosts, lineToDisplay = -1,curserPosition = 0, min_c
|
|
|
1071
1078
|
# with open('keylog.txt','a') as f:
|
|
1072
1079
|
# f.write(str(key)+'\n')
|
|
1073
1080
|
if key == 410: # 410 is the key code for resize
|
|
1074
|
-
return (lineToDisplay,curserPosition , min_char_len, min_line_len, single_window)
|
|
1081
|
+
return (lineToDisplay,curserPosition , min_char_len, min_line_len, single_window, 'Terminal resize requested')
|
|
1075
1082
|
elif key == 95 and not __keyPressesIn[-1]: # 95 is the key code for _
|
|
1076
1083
|
# if last line is empty, we will reconfigure the wh to be smaller
|
|
1077
1084
|
if min_line_len != 1:
|
|
1078
|
-
return (lineToDisplay,curserPosition , min_char_len , max(min_line_len -1,1), single_window)
|
|
1085
|
+
return (lineToDisplay,curserPosition , min_char_len , max(min_line_len -1,1), single_window, 'Decrease line length')
|
|
1079
1086
|
elif key == 43 and not __keyPressesIn[-1]: # 43 is the key code for +
|
|
1080
1087
|
# if last line is empty, we will reconfigure the wh to be larger
|
|
1081
|
-
return (lineToDisplay,curserPosition , min_char_len , min_line_len +1, single_window)
|
|
1088
|
+
return (lineToDisplay,curserPosition , min_char_len , min_line_len +1, single_window, 'Increase line length')
|
|
1082
1089
|
elif key == 123 and not __keyPressesIn[-1]: # 123 is the key code for {
|
|
1083
1090
|
# if last line is empty, we will reconfigure the ww to be smaller
|
|
1084
1091
|
if min_char_len != 1:
|
|
1085
|
-
return (lineToDisplay,curserPosition , max(min_char_len -1,1), min_line_len, single_window)
|
|
1092
|
+
return (lineToDisplay,curserPosition , max(min_char_len -1,1), min_line_len, single_window, 'Decrease character length')
|
|
1086
1093
|
elif key == 124 and not __keyPressesIn[-1]: # 124 is the key code for |
|
|
1087
1094
|
# if last line is empty, we will toggle the single window mode
|
|
1088
|
-
return (lineToDisplay,curserPosition , min_char_len, min_line_len, not single_window)
|
|
1095
|
+
return (lineToDisplay,curserPosition , min_char_len, min_line_len, not single_window, 'Toggle single window mode')
|
|
1089
1096
|
elif key == 125 and not __keyPressesIn[-1]: # 125 is the key code for }
|
|
1090
1097
|
# if last line is empty, we will reconfigure the ww to be larger
|
|
1091
|
-
return (lineToDisplay,curserPosition , min_char_len +1, min_line_len, single_window)
|
|
1098
|
+
return (lineToDisplay,curserPosition , min_char_len +1, min_line_len, single_window, 'Increase character length')
|
|
1092
1099
|
# We handle positional keys
|
|
1093
1100
|
# if the key is up arrow, we will move the line to display up
|
|
1094
1101
|
elif key == 259: # 259 is the key code for up arrow
|
|
@@ -1147,7 +1154,7 @@ def generate_display(stdscr, hosts, lineToDisplay = -1,curserPosition = 0, min_c
|
|
|
1147
1154
|
curserPosition += 1
|
|
1148
1155
|
# reconfigure when the terminal size changes
|
|
1149
1156
|
if org_dim != stdscr.getmaxyx():
|
|
1150
|
-
return (lineToDisplay,curserPosition , min_char_len, min_line_len, single_window)
|
|
1157
|
+
return (lineToDisplay,curserPosition , min_char_len, min_line_len, single_window, 'Terminal resize detected')
|
|
1151
1158
|
# We generate the aggregated stats if user did not input anything
|
|
1152
1159
|
if not __keyPressesIn[lineToDisplay]:
|
|
1153
1160
|
stats = '┍'+ f" Total: {len(hosts)} Running: {host_stats['running']} Failed: {host_stats['failed']} Finished: {host_stats['finished']} Waiting: {host_stats['waiting']} ww: {min_char_len} wh:{min_line_len} "[:max_x - 2].center(max_x - 2, "━")
|
|
@@ -1212,11 +1219,12 @@ def generate_display(stdscr, hosts, lineToDisplay = -1,curserPosition = 0, min_c
|
|
|
1212
1219
|
# print(str(e).strip())
|
|
1213
1220
|
# print(traceback.format_exc().strip())
|
|
1214
1221
|
if org_dim != stdscr.getmaxyx():
|
|
1215
|
-
return (lineToDisplay,curserPosition , min_char_len, min_line_len, single_window)
|
|
1222
|
+
return (lineToDisplay,curserPosition , min_char_len, min_line_len, single_window, 'Terminal resize detected')
|
|
1216
1223
|
new_configured = False
|
|
1217
1224
|
last_refresh_time = time.perf_counter()
|
|
1218
1225
|
except Exception as e:
|
|
1219
|
-
|
|
1226
|
+
import traceback
|
|
1227
|
+
return (lineToDisplay,curserPosition , min_char_len, min_line_len, single_window, f'Error: {str(e)}',traceback.format_exc())
|
|
1220
1228
|
return None
|
|
1221
1229
|
|
|
1222
1230
|
def curses_print(stdscr, hosts, threads, min_char_len = DEFAULT_CURSES_MINIMUM_CHAR_LEN, min_line_len = DEFAULT_CURSES_MINIMUM_LINE_LEN,single_window = DEFAULT_SINGLE_WINDOW):
|
|
@@ -1255,7 +1263,12 @@ def curses_print(stdscr, hosts, threads, min_char_len = DEFAULT_CURSES_MINIMUM_C
|
|
|
1255
1263
|
curses.init_pair(18, curses.COLOR_BLACK, curses.COLOR_BLUE)
|
|
1256
1264
|
curses.init_pair(19, curses.COLOR_BLACK, curses.COLOR_MAGENTA)
|
|
1257
1265
|
curses.init_pair(20, curses.COLOR_BLACK, curses.COLOR_CYAN)
|
|
1258
|
-
|
|
1266
|
+
|
|
1267
|
+
# do not generate display if the output window have a size of zero
|
|
1268
|
+
if stdscr.getmaxyx()[0] < 2 or stdscr.getmaxyx()[1] < 2:
|
|
1269
|
+
return
|
|
1270
|
+
|
|
1271
|
+
params = (-1,0 , min_char_len, min_line_len, single_window,'new config')
|
|
1259
1272
|
while params:
|
|
1260
1273
|
params = generate_display(stdscr, hosts, *params)
|
|
1261
1274
|
if not params:
|
|
@@ -1265,8 +1278,19 @@ def curses_print(stdscr, hosts, threads, min_char_len = DEFAULT_CURSES_MINIMUM_C
|
|
|
1265
1278
|
break
|
|
1266
1279
|
# print the current configuration
|
|
1267
1280
|
stdscr.clear()
|
|
1268
|
-
|
|
1269
|
-
|
|
1281
|
+
try:
|
|
1282
|
+
stdscr.addstr(0, 0, f"{params[5]}, Reloading Configuration: min_char_len={params[2]}, min_line_len={params[3]}, single_window={params[4]} with window size {stdscr.getmaxyx()} and {len(hosts)} hosts...")
|
|
1283
|
+
if len(params) > 6:
|
|
1284
|
+
# traceback is available, print it
|
|
1285
|
+
i = 1
|
|
1286
|
+
for line in params[6].split('\n'):
|
|
1287
|
+
stdscr.addstr(i, 0, line)
|
|
1288
|
+
i += 1
|
|
1289
|
+
stdscr.refresh()
|
|
1290
|
+
except:
|
|
1291
|
+
pass
|
|
1292
|
+
params = params[:5]
|
|
1293
|
+
time.sleep(0.01)
|
|
1270
1294
|
#time.sleep(0.25)
|
|
1271
1295
|
|
|
1272
1296
|
|
|
@@ -1418,7 +1442,10 @@ def processRunOnHosts(timeout, password, max_connections, hosts, returnUnfinishe
|
|
|
1418
1442
|
thread.join(timeout=3)
|
|
1419
1443
|
# update the unavailable hosts and global unavailable hosts
|
|
1420
1444
|
if willUpdateUnreachableHosts:
|
|
1445
|
+
unavailableHosts = set(unavailableHosts)
|
|
1421
1446
|
unavailableHosts.update([host.name for host in hosts if host.stderr and ('No route to host' in host.stderr[0].strip() or host.stderr[0].strip().startswith('Timeout!'))])
|
|
1447
|
+
# reachable hosts = all hosts - unreachable hosts
|
|
1448
|
+
reachableHosts = set([host.name for host in hosts]) - unavailableHosts
|
|
1422
1449
|
if __DEBUG_MODE:
|
|
1423
1450
|
print(f'Unreachable hosts: {unavailableHosts}')
|
|
1424
1451
|
__globalUnavailableHosts.update(unavailableHosts)
|
|
@@ -1427,18 +1454,31 @@ def processRunOnHosts(timeout, password, max_connections, hosts, returnUnfinishe
|
|
|
1427
1454
|
# create a temporary file to store the unavailable hosts
|
|
1428
1455
|
try:
|
|
1429
1456
|
# check for the old content, only update if the new content is different
|
|
1430
|
-
if not os.path.exists(os.path.join(tempfile.gettempdir(),'__multiSSH3_UNAVAILABLE_HOSTS')):
|
|
1431
|
-
with open(os.path.join(tempfile.gettempdir(),'__multiSSH3_UNAVAILABLE_HOSTS'),'w') as f:
|
|
1432
|
-
f.write(','.join(unavailableHosts))
|
|
1457
|
+
if not os.path.exists(os.path.join(tempfile.gettempdir(),'__multiSSH3_UNAVAILABLE_HOSTS.csv')):
|
|
1458
|
+
with open(os.path.join(tempfile.gettempdir(),'__multiSSH3_UNAVAILABLE_HOSTS.csv'),'w') as f:
|
|
1459
|
+
f.write(f',{int(time.time())}\n'.join(unavailableHosts) + f',{int(time.time())}\n')
|
|
1433
1460
|
else:
|
|
1461
|
+
oldDic = {}
|
|
1434
1462
|
try:
|
|
1435
|
-
with open(os.path.join(tempfile.gettempdir(),'__multiSSH3_UNAVAILABLE_HOSTS'),'r') as f:
|
|
1436
|
-
|
|
1463
|
+
with open(os.path.join(tempfile.gettempdir(),'__multiSSH3_UNAVAILABLE_HOSTS.csv'),'r') as f:
|
|
1464
|
+
for line in f:
|
|
1465
|
+
line = line.strip()
|
|
1466
|
+
if line and ',' in line and len(line.split(',')) >= 2 and line.split(',')[0] and line.split(',')[1].isdigit():
|
|
1467
|
+
oldDic[line.split(',')[0]] = int(line.split(',')[1])
|
|
1437
1468
|
except:
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1469
|
+
pass
|
|
1470
|
+
# remove entries that are either available now or older than min(timeout,3600) seconds
|
|
1471
|
+
for key in list(oldDic.keys()):
|
|
1472
|
+
if key in reachableHosts or time.time() - oldDic[key] > min(timeout,3600):
|
|
1473
|
+
del oldDic[key]
|
|
1474
|
+
# add new entries
|
|
1475
|
+
for host in unavailableHosts:
|
|
1476
|
+
oldDic[host] = int(time.time())
|
|
1477
|
+
with open(os.path.join(tempfile.gettempdir(),'__multiSSH3_UNAVAILABLE_HOSTS.csv.new'),'w') as f:
|
|
1478
|
+
for key, value in oldDic.items():
|
|
1479
|
+
f.write(f'{key},{value}\n')
|
|
1480
|
+
os.replace(os.path.join(tempfile.gettempdir(),'__multiSSH3_UNAVAILABLE_HOSTS.csv.new'),os.path.join(tempfile.gettempdir(),'__multiSSH3_UNAVAILABLE_HOSTS.csv'))
|
|
1481
|
+
|
|
1442
1482
|
except Exception as e:
|
|
1443
1483
|
eprint(f'Error writing to temporary file: {e}')
|
|
1444
1484
|
|
|
@@ -1573,23 +1613,27 @@ def run_command_on_hosts(hosts = DEFAULT_HOSTS,commands = None,oneonone = DEFAUL
|
|
|
1573
1613
|
global __DEBUG_MODE
|
|
1574
1614
|
_emo = False
|
|
1575
1615
|
_no_env = no_env
|
|
1576
|
-
if os.path.exists(os.path.join(tempfile.gettempdir(),'__multiSSH3_UNAVAILABLE_HOSTS')):
|
|
1616
|
+
if os.path.exists(os.path.join(tempfile.gettempdir(),'__multiSSH3_UNAVAILABLE_HOSTS.csv')):
|
|
1577
1617
|
if timeout <= 0:
|
|
1578
1618
|
checkTime = DEFAULT_TIMEOUT
|
|
1579
1619
|
else:
|
|
1580
1620
|
checkTime = timeout
|
|
1581
1621
|
if checkTime <= 0:
|
|
1582
1622
|
checkTime = 60
|
|
1623
|
+
elif checkTime > 3600:
|
|
1624
|
+
checkTime = 3600
|
|
1583
1625
|
try:
|
|
1584
|
-
if 0 < time.time() - os.path.getmtime(os.path.join(tempfile.gettempdir(),'__multiSSH3_UNAVAILABLE_HOSTS')) < checkTime:
|
|
1626
|
+
if 0 < time.time() - os.path.getmtime(os.path.join(tempfile.gettempdir(),'__multiSSH3_UNAVAILABLE_HOSTS.csv')) < checkTime:
|
|
1585
1627
|
if not __global_suppress_printout:
|
|
1586
|
-
eprint(f"Reading unavailable hosts from the file {os.path.join(tempfile.gettempdir(),'__multiSSH3_UNAVAILABLE_HOSTS')}")
|
|
1587
|
-
with open(os.path.join(tempfile.gettempdir(),'__multiSSH3_UNAVAILABLE_HOSTS'),'r') as f:
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1628
|
+
eprint(f"Reading unavailable hosts from the file {os.path.join(tempfile.gettempdir(),'__multiSSH3_UNAVAILABLE_HOSTS.csv')}")
|
|
1629
|
+
with open(os.path.join(tempfile.gettempdir(),'__multiSSH3_UNAVAILABLE_HOSTS.csv'),'r') as f:
|
|
1630
|
+
for line in f:
|
|
1631
|
+
line = line.strip()
|
|
1632
|
+
if line and ',' in line and len(line.split(',')) >= 2 and line.split(',')[0] and line.split(',')[1].isdigit():
|
|
1633
|
+
if int(line.split(',')[1]) > time.time() - checkTime:
|
|
1634
|
+
__globalUnavailableHosts.add(line.split(',')[0])
|
|
1591
1635
|
except Exception as e:
|
|
1592
|
-
eprint(f"Warning: Unable to read the unavailable hosts from the file {os.path.join(tempfile.gettempdir(),'__multiSSH3_UNAVAILABLE_HOSTS')}")
|
|
1636
|
+
eprint(f"Warning: Unable to read the unavailable hosts from the file {os.path.join(tempfile.gettempdir(),'__multiSSH3_UNAVAILABLE_HOSTS.csv')}")
|
|
1593
1637
|
eprint(str(e))
|
|
1594
1638
|
elif '__multiSSH3_UNAVAILABLE_HOSTS' in readEnvFromFile():
|
|
1595
1639
|
__globalUnavailableHosts.update(readEnvFromFile()['__multiSSH3_UNAVAILABLE_HOSTS'].split(','))
|
multiSSH3-5.0.dist-info/RECORD
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
multiSSH3.py,sha256=mNEOxE6IVnDu9eHdNfsmY_ZW765SFsf4fuelzG4hBDE,98229
|
|
2
|
-
multiSSH3-5.0.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
|
3
|
-
multiSSH3-5.0.dist-info/METADATA,sha256=iYZECVBpY6n8O-y92Z7aN0E8MuuiK4F91KcV8BjenAU,17516
|
|
4
|
-
multiSSH3-5.0.dist-info/WHEEL,sha256=OVMc5UfuAQiSplgO0_WdW7vXVGAt9Hdd6qtN4HotdyA,91
|
|
5
|
-
multiSSH3-5.0.dist-info/entry_points.txt,sha256=xi2rWWNfmHx6gS8Mmx0rZL2KZz6XWBYP3DWBpWAnnZ0,143
|
|
6
|
-
multiSSH3-5.0.dist-info/top_level.txt,sha256=tUwttxlnpLkZorSsroIprNo41lYSxjd2ASuL8-EJIJw,10
|
|
7
|
-
multiSSH3-5.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|