serverwatcher 5.8.dev12__py3-none-any.whl → 5.8.dev14__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.
@@ -1,9 +1,10 @@
1
- from dataclasses import dataclass, field
1
+ from dataclasses import field
2
+ from hungerlib import datamap
2
3
 
3
4
  def yaml_key(path: str, default=None):
4
5
  return field(default=default, metadata={"yaml_key": path})
5
6
 
6
- @dataclass
7
+ @datamap(syntax=Syntax.braces)
7
8
  class GlobalConfig:
8
9
  timezone: str = yaml_key("timezone")
9
10
 
@@ -27,4 +28,4 @@ class GlobalConfig:
27
28
  log_path: str = yaml_key("logger.log_path")
28
29
 
29
30
  console_backspaces: int = yaml_key("terminal.backspaces")
30
- clear_terminal: bool = yaml_key("terminal.enable_clearing")
31
+ clear_terminal: bool = yaml_key("terminal.enable_clearing")
@@ -1,37 +1,35 @@
1
- from dataclasses import dataclass, field
1
+ from dataclasses import field
2
+ from hungerlib import datamap
2
3
 
3
4
  def yaml_key(path: str, default=None):
4
5
  return field(default=default, metadata={"yaml_key": path})
5
6
 
6
- @dataclass
7
+ @datamap(syntax=Syntax.braces)
7
8
  class MessagesConfig:
8
- prefix: str = yaml_key("prefix", default="<aqua>[Server Watcher]")
9
+ prefix: str = yaml_key("prefix", "<aqua>[Server Watcher]")
9
10
  bullet: str = yaml_key("bullet")
10
-
11
- broadcast_restart_at: str = yaml_key("broadcast_restart_at")
12
11
 
13
- # minute messages
14
- minute_120: str = yaml_key("broadcast_minutes.120", default="{prefix} Restart in 2 hours!")
15
- minute_60: str = yaml_key("broadcast_minutes.60", default="{prefix} Restart in 1 hour!")
16
- minute_45: str = yaml_key("broadcast_minutes.45", default="{prefix} Restart in 45 minutes!")
17
- minute_30: str = yaml_key("broadcast_minutes.30", default="{prefix} Restart in 30 minutes!")
18
- minute_15: str = yaml_key("broadcast_minutes.15", default="{prefix} Restart in 15 minutes!")
19
- minute_5: str = yaml_key("broadcast_minutes.5", default="{prefix} Restart in 5 minutes!")
20
- minute_1: str = yaml_key("broadcast_minutes.1", default="{prefix} Restart in 1 minute!")
12
+ broadcast_restart_at: str = yaml_key("broadcast_restart_at")
21
13
 
22
- # second messages
23
- second_10: str = yaml_key("broadcast_seconds.10", default="{prefix} Restart in 10 seconds!")
24
- second_9: str = yaml_key("broadcast_seconds.9", default="{prefix} Restart in 9 seconds!")
25
- second_8: str = yaml_key("broadcast_seconds.8", default="{prefix} Restart in 8 seconds!")
26
- second_7: str = yaml_key("broadcast_seconds.7", default="{prefix} Restart in 7 seconds!")
27
- second_6: str = yaml_key("broadcast_seconds.6", default="{prefix} Restart in 6 seconds!")
28
- second_5: str = yaml_key("broadcast_seconds.5", default="{prefix} Restart in 5 seconds!")
29
- second_4: str = yaml_key("broadcast_seconds.4", default="{prefix} Restart in 4 seconds!")
30
- second_3: str = yaml_key("broadcast_seconds.3", default="{prefix} Restart in 3 seconds!")
31
- second_2: str = yaml_key("broadcast_seconds.2", default="{prefix} Restart in 2 seconds!")
32
- second_1: str = yaml_key("broadcast_seconds.1", default="{prefix} Restart in 1 second!")
14
+ minute_120: str = yaml_key("broadcast_minutes.120", "{prefix} Restart in 2 hours!")
15
+ minute_60: str = yaml_key("broadcast_minutes.60", "{prefix} Restart in 1 hour!")
16
+ minute_45: str = yaml_key("broadcast_minutes.45", "{prefix} Restart in 45 minutes!")
17
+ minute_30: str = yaml_key("broadcast_minutes.30", "{prefix} Restart in 30 minutes!")
18
+ minute_15: str = yaml_key("broadcast_minutes.15", "{prefix} Restart in 15 minutes!")
19
+ minute_5: str = yaml_key("broadcast_minutes.5", "{prefix} Restart in 5 minutes!")
20
+ minute_1: str = yaml_key("broadcast_minutes.1", "{prefix} Restart in 1 minute!")
21
+
22
+ second_10: str = yaml_key("broadcast_seconds.10", "{prefix} Restart in 10 seconds!")
23
+ second_9: str = yaml_key("broadcast_seconds.9", "{prefix} Restart in 9 seconds!")
24
+ second_8: str = yaml_key("broadcast_seconds.8", "{prefix} Restart in 8 seconds!")
25
+ second_7: str = yaml_key("broadcast_seconds.7", "{prefix} Restart in 7 seconds!")
26
+ second_6: str = yaml_key("broadcast_seconds.6", "{prefix} Restart in 6 seconds!")
27
+ second_5: str = yaml_key("broadcast_seconds.5", "{prefix} Restart in 5 seconds!")
28
+ second_4: str = yaml_key("broadcast_seconds.4", "{prefix} Restart in 4 seconds!")
29
+ second_3: str = yaml_key("broadcast_seconds.3", "{prefix} Restart in 3 seconds!")
30
+ second_2: str = yaml_key("broadcast_seconds.2", "{prefix} Restart in 2 seconds!")
31
+ second_1: str = yaml_key("broadcast_seconds.1", "{prefix} Restart in 1 second!")
33
32
 
34
- # logging
35
33
  startup: str = yaml_key("logging.startup")
36
34
  status_check: str = yaml_key("logging.status_check")
37
35
  validation_fail: str = yaml_key("logging.validation_fail")
@@ -43,7 +41,6 @@ class MessagesConfig:
43
41
  gap_low: str = yaml_key("logging.gap_low")
44
42
  gap_high: str = yaml_key("logging.gap_high")
45
43
 
46
- # reasons
47
44
  pro_restart_splash: str = yaml_key("reasons.pro_splash")
48
45
  anti_restart_splash: str = yaml_key("reasons.anti_splash")
49
46
 
@@ -58,7 +55,6 @@ class MessagesConfig:
58
55
  pro_restart_number: str = yaml_key("reasons.pro_restart_number")
59
56
  anti_restart_number: str = yaml_key("reasons.anti_restart_number")
60
57
 
61
- # restarts
62
58
  restart_action_sent: str = yaml_key("restarts.restart_action_sent")
63
59
  server_back_online: str = yaml_key("restarts.back_online")
64
60
  server_back_online_broadcast: str = yaml_key("restarts.back_online_broadcast")
@@ -1,9 +1,10 @@
1
- from dataclasses import dataclass, field
1
+ from dataclasses import field
2
+ from hungerlib import datamap
2
3
 
3
4
  def yaml_key(path: str, default=None):
4
5
  return field(default=default, metadata={"yaml_key": path})
5
6
 
6
- @dataclass
7
+ @datamap(syntax=Syntax.braces)
7
8
  class WatcherConfig:
8
9
  watch_interval: int = yaml_key("watch_interval")
9
10
  schedule_control: bool = yaml_key("schedule_control.enabled")
@@ -1,7 +1,6 @@
1
1
  import sys
2
2
  from dataclasses import fields
3
-
4
- from hungerlib.addons import loadConfig, clearTerminal
3
+ from hungerlib import configloader, utils
5
4
 
6
5
  from serverwatcher.configclasses.config import GlobalConfig
7
6
  from serverwatcher.configclasses.messages import MessagesConfig
serverwatcher/watcher.py CHANGED
@@ -1,39 +1,16 @@
1
1
  import os
2
2
  import time
3
- import re
4
3
  from zoneinfo import ZoneInfo
5
4
 
6
- from hungerlib import Panel, MessageRouter
7
- from hungerlib.servers import MinecraftServer, GenericServer
8
- from hungerlib.addons import (
9
- clearTerminal,
10
- Snapshot,
11
- snapSchedule,
12
- waitForOnline,
13
- validateAll,
14
- runCountdownEvents,
15
- loadConfig,
16
- )
5
+ from hungerlib import panel, servers, messagerouter, configloader, utils
17
6
 
18
7
  from serverwatcher.configclasses.config import GlobalConfig
19
8
  from serverwatcher.configclasses.messages import MessagesConfig
20
9
  from serverwatcher.configclasses.watcher import WatcherConfig
21
-
22
10
  from serverwatcher.validator import validate_all
23
11
 
24
12
  validate_all()
25
13
 
26
- _T_EXPR = re.compile(r"{([^{}]+)}")
27
-
28
- def t_eval(template: str, /, **ctx):
29
- # evaluate inline expressions inside message templates
30
- def repl(match):
31
- expr = match.group(1).strip()
32
- try:
33
- return str(eval(expr, {}, ctx))
34
- except Exception as e:
35
- return f"<err:{e}>"
36
- return _T_EXPR.sub(repl, template)
37
14
 
38
15
  class ServerWatcher:
39
16
  def __init__(self):
@@ -55,6 +32,13 @@ class ServerWatcher:
55
32
  WatcherConfig
56
33
  )
57
34
 
35
+ set_default_maps(
36
+ ASCII_COLOR_MAP,
37
+ self.config,
38
+ self.messages,
39
+ self.watcherconfig
40
+ )
41
+
58
42
  self.panel = Panel(
59
43
  name=self.config.panel_name,
60
44
  url=self.config.panel_url,
@@ -78,40 +62,30 @@ class ServerWatcher:
78
62
  tpsCommand=self.config.tps_command,
79
63
  )
80
64
 
81
- # formatted logger name
82
- logger_name = self.config.logger_name.format(
83
- server_name=self.config.server_name
84
- )
85
-
86
- # initialize message router
65
+ logger_name = mapit(self.config.logger_name, server_name=self.config.server_name)
66
+
87
67
  self.router = MessageRouter(
88
68
  name=logger_name,
89
69
  server=self.server,
90
70
  log_path=self.config.log_path,
91
- formatter=self.fmt,
71
+ formatter=self._fmt,
92
72
  console_backspaces=self.config.console_backspaces,
93
73
  )
94
74
 
95
- # timezone for scheduling
96
75
  self.tz = ZoneInfo(self.config.timezone)
97
76
 
98
- def fmt(self, template: str, **fmt):
99
- simple = {
100
- "prefix": self.messages.prefix,
101
- "bullet": self.messages.bullet,
102
- }
103
- for key, value in simple.items():
104
- template = template.replace(f"{{{key}}}", value)
105
- return t_eval(template, self=self, **fmt)
106
-
107
- def say(self, template, level="info", **fmt):
77
+ def _fmt(self, template: str, **ctx):
78
+ return mapit(template, **ctx)
79
+
80
+ def say(self, template, level="info", **ctx):
108
81
  if not template:
109
82
  return
83
+ msg = mapit(template, **ctx)
110
84
  self.router.say(
111
- template,
85
+ msg,
112
86
  level=level,
113
87
  log=self.config.enable_logging,
114
- **fmt
88
+ **ctx
115
89
  )
116
90
 
117
91
  def shutdown(self):
@@ -119,16 +93,13 @@ class ServerWatcher:
119
93
  raise SystemExit
120
94
 
121
95
  def restart_and_wait(self):
122
- # disable schedule if configured
123
96
  if self.watcherconfig.schedule_control:
124
97
  self.origin.disableSchedule(self.watcherconfig.restart_soon_id)
125
98
 
126
- # send restart command
127
99
  self.server.restart()
128
100
  self.say(self.messages.restart_action_sent)
129
101
  time.sleep(self.watcherconfig.restart_wait_seconds)
130
102
 
131
- # check server status
132
103
  self.say(self.messages.status_check, level="warn")
133
104
  alive = waitForOnline(
134
105
  self.server,
@@ -136,7 +107,6 @@ class ServerWatcher:
136
107
  interval=self.watcherconfig.restart_online_interval,
137
108
  )
138
109
 
139
- # handle restart result
140
110
  if alive:
141
111
  self.say(self.messages.server_back_online)
142
112
  self.say(self.messages.server_back_online_broadcast, broadcast=True)
@@ -144,38 +114,32 @@ class ServerWatcher:
144
114
  self.say(self.messages.server_failed_restart, level="error")
145
115
 
146
116
  def schedule_restart(self, minutes):
147
- # compute scheduled restart time
148
117
  info = snapSchedule(minimumMinutes=minutes)
149
118
  scheduled = info["scheduled"]
150
119
 
151
- # format local time
152
120
  local_time = scheduled.astimezone(self.tz)
153
121
  time_str = local_time.strftime("%I:%M %p")
154
122
 
155
- # broadcast restart time
156
- self.router.broadcast(self.fmt(self.messages.broadcast_restart_at, time=time_str))
123
+ self.router.broadcast(mapit(self.messages.broadcast_restart_at, time=time_str))
157
124
 
158
- # build minute callbacks
159
125
  minute_callbacks = {
160
126
  int(k.split("_")[1]): (
161
- lambda msg=self.fmt(getattr(self.messages, k)):
127
+ lambda msg=mapit(getattr(self.messages, k)):
162
128
  self.router.broadcast(msg)
163
129
  )
164
130
  for k in vars(self.messages)
165
131
  if k.startswith("minute_")
166
132
  }
167
133
 
168
- # build second callbacks
169
134
  second_callbacks = {
170
135
  int(k.split("_")[1]): (
171
- lambda msg=self.fmt(getattr(self.messages, k)):
136
+ lambda msg=mapit(getattr(self.messages, k)):
172
137
  self.router.broadcast(msg)
173
138
  )
174
139
  for k in vars(self.messages)
175
140
  if k.startswith("second_")
176
141
  }
177
142
 
178
- # run countdown events
179
143
  runCountdownEvents(
180
144
  target_time=scheduled,
181
145
  minute_callbacks=minute_callbacks,
@@ -183,98 +147,78 @@ class ServerWatcher:
183
147
  )
184
148
 
185
149
  def evaluate(self):
186
- # announce evaluation start
187
150
  self.say(self.messages.startup)
188
151
 
189
- # validate panel and server
190
152
  if not validateAll(self.panel, self.server):
191
153
  self.say(self.messages.validation_fail, level="error")
192
154
  self.shutdown()
193
155
 
194
- # refresh server state
195
156
  self.server.refresh()
196
157
  snap = Snapshot(self.server, 2, True)
197
158
 
198
- # scoring variables
199
159
  pro = 0
200
160
  anti = 0
201
161
  restart_reasons = []
202
162
  no_restart_reasons = []
203
163
 
204
- # check schedule flag
205
164
  if self.watcherconfig.schedule_control and self.server.getSchedule(self.watcherconfig.restart_soon_id)["is_active"]:
206
165
  restart_reasons.append(self.messages.reason_restart_soon)
207
166
  pro += self.watcherconfig.weight_restart_soon
208
167
 
209
- # check RAM threshold
210
168
  if snap.ram >= self.watcherconfig.threshold_ram:
211
- restart_reasons.append(self.fmt(self.messages.reason_ram, ram=snap.ram, threshold=self.watcherconfig.threshold_ram))
169
+ restart_reasons.append(mapit(self.messages.reason_ram, ram=snap.ram, threshold=self.watcherconfig.threshold_ram))
212
170
  pro += int(round(snap.ram, 0) - (self.watcherconfig.threshold_ram - 1))
213
171
 
214
- # check CPU threshold
215
172
  if snap.cpu >= self.watcherconfig.threshold_cpu:
216
- restart_reasons.append(self.fmt(self.messages.reason_cpu, cpu=snap.cpu, threshold=self.watcherconfig.threshold_cpu))
173
+ restart_reasons.append(mapit(self.messages.reason_cpu, cpu=snap.cpu, threshold=self.watcherconfig.threshold_cpu))
217
174
  pro += self.watcherconfig.weight_cpu
218
175
 
219
- # check uptime threshold
220
176
  if snap.uptime // 3600 >= self.watcherconfig.threshold_uptime:
221
177
  restart_reasons.append(
222
- self.fmt(self.messages.reason_uptime, uptime=snap.uptime_formatted,
223
- threshold=self.watcherconfig.threshold_uptime)
178
+ mapit(self.messages.reason_uptime, uptime=snap.uptime_formatted, threshold=self.watcherconfig.threshold_uptime)
224
179
  )
225
180
  pro += self.watcherconfig.weight_uptime
226
181
 
227
- # check TPS threshold
228
182
  if (snap.tps if snap.tps is not None else 20) <= self.watcherconfig.threshold_tps:
229
- restart_reasons.append(self.fmt(self.messages.reason_tps, tps=snap.tps, threshold=self.watcherconfig.threshold_tps))
183
+ restart_reasons.append(mapit(self.messages.reason_tps, tps=snap.tps, threshold=self.watcherconfig.threshold_tps))
230
184
  pro += self.watcherconfig.weight_tps
231
185
 
232
- # check low uptime penalty
233
186
  if snap.uptime // 60 < 30:
234
- no_restart_reasons.append(self.fmt(self.messages.reason_low_uptime, uptime=snap.uptime_formatted))
187
+ no_restart_reasons.append(mapit(self.messages.reason_low_uptime, uptime=snap.uptime_formatted))
235
188
  anti += self.watcherconfig.weight_low_uptime
236
189
 
237
- # check player count penalty
238
190
  if snap.players > 0:
239
191
  verb = "are" if snap.players != 1 else "is"
240
192
  plural = "players" if snap.players != 1 else "player"
241
- no_restart_reasons.append(self.fmt(self.messages.reason_players, verb=verb, count=snap.players, plural=plural))
193
+ no_restart_reasons.append(mapit(self.messages.reason_players, verb=verb, count=snap.players, plural=plural))
242
194
  anti += snap.players * self.watcherconfig.weight_per_player
243
195
 
244
- # output pro-restart reasons
245
196
  if restart_reasons:
246
197
  self.say(self.messages.pro_restart_splash, level="warn")
247
198
  for r in restart_reasons:
248
199
  self.say(f"{self.messages.bullet} {r}", level="warn")
249
200
 
250
- # output anti-restart reasons
251
201
  if no_restart_reasons:
252
202
  self.say(self.messages.anti_restart_splash, level="warn")
253
203
  for r in no_restart_reasons:
254
204
  self.say(f"{self.messages.bullet} {r}", level="warn")
255
205
 
256
- # output scores
257
206
  self.say(f"{self.messages.pro_restart_number} {pro}", level="warn")
258
207
  self.say(f"{self.messages.anti_restart_number} {anti}", level="warn")
259
208
 
260
- # compute gap
261
209
  gap = abs(pro - anti)
262
210
 
263
- # no restart case
264
211
  if pro == 0:
265
212
  self.say(self.messages.no_restart)
266
213
  return
267
214
 
268
- # immediate restart case
269
215
  if pro > anti and snap.players == 0:
270
216
  self.say(self.messages.immediate_restart)
271
217
  self.restart_and_wait()
272
218
  return
273
219
 
274
- # scheduled restart case
275
220
  self.say(self.messages.scheduled)
276
221
 
277
- # choose schedule window
278
222
  if gap <= 2:
279
223
  self.say(self.messages.gap_low, level="warn", gap=gap)
280
224
  self.schedule_restart(self.watcherconfig.low_gap_minutes)
@@ -282,10 +226,8 @@ class ServerWatcher:
282
226
  self.say(self.messages.gap_high, level="warn", gap=gap)
283
227
  self.schedule_restart(self.watcherconfig.high_gap_minutes)
284
228
 
285
- # perform restart
286
229
  self.restart_and_wait()
287
230
 
288
- # main loop
289
231
  def run(self):
290
232
  if self.config.clear_terminal:
291
233
  clearTerminal()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: serverwatcher
3
- Version: 5.8.dev12
3
+ Version: 5.8.dev14
4
4
  Summary: A HungerLib-powered Minecraft server automation engine.
5
5
  Author: iFamished
6
6
  License: GPL-3.0
@@ -0,0 +1,15 @@
1
+ serverwatcher/__init__.py,sha256=Q_afN0XU29n48d6Gf0-LT2lLo3RiTWlHRT6rC_fYbjw,486
2
+ serverwatcher/validator.py,sha256=D1J9BDmwqMix3soefYGvqVuNVAsX96s3c0OC91n_CL0,4741
3
+ serverwatcher/watcher.py,sha256=4pWWsXoK0mHiYmWEx2azFWpfEwOktnQYp1jYx6vJqRw,8201
4
+ serverwatcher/configclasses/__init__.py,sha256=YS0KhxtAJGdMcaiFstqTRNxIPLnR7s9v3Tkt5h2uKE4,182
5
+ serverwatcher/configclasses/config.py,sha256=flz1jCkqNvr8jttoitAjs1scbuDky8_oW2Yut5Zzz-g,1090
6
+ serverwatcher/configclasses/messages.py,sha256=0YY-gu9awKQ4jQogBoZPtSzYafqE24ws_ndR12SdLH0,3342
7
+ serverwatcher/configclasses/watcher.py,sha256=fjdAU5Cw2pNvliwyo7fChGTr_CDxTMtWlRZiyLJSSLo,1322
8
+ serverwatcher/defaultconfigs/config.yaml,sha256=dd4us7FybIkx43h7RIWxCpMn-pQLMz0Gw1c8EA2yrCs,439
9
+ serverwatcher/defaultconfigs/messages.yaml,sha256=EFqAyyBKKVN6egtjir6Wl1YzTBVzVlbp_BwX_X-SawI,1490
10
+ serverwatcher/defaultconfigs/watcher.yaml,sha256=fsfU7G7yGhc4mzGOSQA1IEa5Ru6aouc9BZG2zTYWF7g,401
11
+ serverwatcher-5.8.dev14.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
12
+ serverwatcher-5.8.dev14.dist-info/METADATA,sha256=JoLmWLg0ZlfxLTrQF2vB9kDggLIZKUlJhf64r0EoTe0,1687
13
+ serverwatcher-5.8.dev14.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
14
+ serverwatcher-5.8.dev14.dist-info/top_level.txt,sha256=8DJAf8WmmglgtZHkp8aoTriRJ2YPcS4F3DfOIkytASo,14
15
+ serverwatcher-5.8.dev14.dist-info/RECORD,,
@@ -1,15 +0,0 @@
1
- serverwatcher/__init__.py,sha256=Q_afN0XU29n48d6Gf0-LT2lLo3RiTWlHRT6rC_fYbjw,486
2
- serverwatcher/validator.py,sha256=hsJQhK8grwGtkqUew_afOdcHmfzI7C4yLTtYNe3yTgw,4755
3
- serverwatcher/watcher.py,sha256=M-RrYnbUumVcrDIoyMotSySBBy16a3Z3gOHQQr26mfQ,9952
4
- serverwatcher/configclasses/__init__.py,sha256=YS0KhxtAJGdMcaiFstqTRNxIPLnR7s9v3Tkt5h2uKE4,182
5
- serverwatcher/configclasses/config.py,sha256=f7gXQksR4GYEgWrrhL3nit0H3lGVu1BO3nakPwQpBCc,1050
6
- serverwatcher/configclasses/messages.py,sha256=15OlzUij7Y7LMVd_g-rbeU8zsyWEGL1gJtePnJgU_i8,3538
7
- serverwatcher/configclasses/watcher.py,sha256=5JgQhrPmVsT1iJT1teqa8w59H7v0r7WrR8SNoi__4nw,1283
8
- serverwatcher/defaultconfigs/config.yaml,sha256=dd4us7FybIkx43h7RIWxCpMn-pQLMz0Gw1c8EA2yrCs,439
9
- serverwatcher/defaultconfigs/messages.yaml,sha256=EFqAyyBKKVN6egtjir6Wl1YzTBVzVlbp_BwX_X-SawI,1490
10
- serverwatcher/defaultconfigs/watcher.yaml,sha256=fsfU7G7yGhc4mzGOSQA1IEa5Ru6aouc9BZG2zTYWF7g,401
11
- serverwatcher-5.8.dev12.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
12
- serverwatcher-5.8.dev12.dist-info/METADATA,sha256=gfplbOiDnu8hPfpCWSulbV87tWhKUnF5uspKd50u7uY,1687
13
- serverwatcher-5.8.dev12.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
14
- serverwatcher-5.8.dev12.dist-info/top_level.txt,sha256=8DJAf8WmmglgtZHkp8aoTriRJ2YPcS4F3DfOIkytASo,14
15
- serverwatcher-5.8.dev12.dist-info/RECORD,,