PyLibMS 4.3.2__py3-none-any.whl → 4.3.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.
@@ -1,4 +1,6 @@
1
1
  # Common constant definitions between files
2
+ LMS_MINIMUM_VERSION = 3
3
+
2
4
  PADDING_BYTE = b"\x00"
3
5
 
4
6
  SIZE_OFFSET = 0x12
@@ -3,7 +3,7 @@ from lms.common.lms_constants import (
3
3
  BIG_ENDIAN_BOM,
4
4
  SECTION_DATA_START,
5
5
  LITTLE_ENDIAN_BOM,
6
- SIZE_OFFSET,
6
+ SIZE_OFFSET, LMS_MINIMUM_VERSION,
7
7
  )
8
8
  from lms.common.lms_fileinfo import LMS_FileInfo
9
9
  from lms.fileio.encoding import FileEncoding
@@ -29,7 +29,7 @@ def read_file_info(reader: FileReader, expected_magic: str) -> LMS_FileInfo:
29
29
 
30
30
  version = reader.read_uint8()
31
31
 
32
- if version < 3:
32
+ if version < LMS_MINIMUM_VERSION:
33
33
  raise lms_exceptions.LMS_UnsupportedFileVersionError(
34
34
  "Only version 3+ files are supported!"
35
35
  )
@@ -185,7 +185,7 @@ class LMS_MessageNode(LMS_BaseNode):
185
185
 
186
186
  @property
187
187
  def msbt(self) -> MSBT | None:
188
- """MSBT instance the node references. Optional, and must be set with `set_msbt` or by providing a MSBT file on reading."""
188
+ """MSBT instance the node references. Optional, is set by providing a MSBT file on reading."""
189
189
  return self._msbt
190
190
 
191
191
  @property
@@ -313,26 +313,33 @@ class LMS_BranchNode(LMS_BaseNode):
313
313
  case_map.setdefault(branch, []).append(case)
314
314
 
315
315
  if self.definition is not None:
316
- if self.definition.case_options:
316
+ definition: NodeDefinition = self.definition
317
+
318
+ if definition.case_options:
317
319
  for case, branch in self._branches.items():
318
- case_message = self.definition.case_options.get(
319
- case, f"Case {case}"
320
+ case_format = definition.case_options.get(
321
+ case, None,
320
322
  )
321
323
 
322
- result.append(((case,), case_message, branch))
324
+ if case_format is None:
325
+ formatted_message = f"Case {case}"
326
+ else:
327
+ formatted_message = self._format_case_message(case, case_format)
328
+
329
+ result.append(((case,), formatted_message, branch))
323
330
 
324
331
  return result
325
332
 
326
- if self.definition.case_format is not None:
333
+ if definition.case_format is not None:
327
334
  if compress_shared_references:
328
335
  for branch, cases in case_map.items():
329
336
  case_message = self._format_case_message(
330
- merge_shared_cases(cases)
337
+ merge_shared_cases(cases), definition.case_format
331
338
  )
332
339
  result.append((tuple(cases), case_message, branch))
333
340
  else:
334
341
  for case, branch in self._branches.items():
335
- case_message = self._format_case_message(case)
342
+ case_message = self._format_case_message(case, definition.case_format)
336
343
  result.append(((case,), case_message, branch))
337
344
 
338
345
  return result
@@ -352,8 +359,8 @@ class LMS_BranchNode(LMS_BaseNode):
352
359
 
353
360
  return result
354
361
 
355
- def _format_case_message(self, case_prefix: str):
356
- prefix = string.Template(self._definition.case_format)
362
+ def _format_case_message(self, case_prefix: str, case_format: str):
363
+ prefix = string.Template(case_format)
357
364
 
358
365
  # Unpack dict for formatting $case and $param formats
359
366
  # Allows inserting parameter values dynamically into the case message
lms/flowchart/msbf.py CHANGED
@@ -22,14 +22,17 @@ class MSBF:
22
22
  """
23
23
 
24
24
  MAGIC = "MsgFlwBn"
25
-
26
25
  DEFAULT_SLOT_COUNT = 59
27
26
 
28
27
  def __init__(
29
28
  self, info: LMS_FileInfo | None = None, flowcharts: list[LMS_Flowchart] = None
30
29
  ):
31
30
  self._info = info if info is not None else LMS_FileInfo()
32
- self._shared_references: dict[int, LMS_BaseNode] = {}
31
+
32
+ # While unlikely to vary, and have yet to find a file that changes the slot count (unlike MSBT)
33
+ # it is wiser to store an editable attribute just in case a game decides to vary the amount.
34
+ self.slot_count = MSBF.DEFAULT_SLOT_COUNT
35
+
33
36
  self._flowcharts = flowcharts or []
34
37
  self._nodes: dict[int, LMS_BaseNode] = {}
35
38
  self._global_node_id = 0
@@ -77,7 +80,11 @@ class MSBF:
77
80
  )
78
81
 
79
82
  def get_flowchart_references(self, node_id: int) -> set[LMS_Flowchart]:
80
- """References of nodes between flowcharts."""
83
+ """
84
+ Determines which flowcharts contain this node.
85
+
86
+ :param node_id: The node to find references for.
87
+ """
81
88
  return {flowchart for flowchart in self._flowcharts if node_id in flowchart.nodes}
82
89
 
83
90
  def register_node(self, node: LMS_BaseNode, flowchart: LMS_Flowchart = None) -> None:
@@ -85,7 +92,7 @@ class MSBF:
85
92
  Registers a node to the MSBF instance.
86
93
 
87
94
  :param node: The node to register.
88
- :param flowchart: optional argument that registers the node to that flowchart.
95
+ :param flowchart: Optional argument that registers the node to that flowchart.
89
96
  """
90
97
  if not isinstance(node, LMS_BaseNode):
91
98
  raise TypeError(
@@ -135,10 +142,6 @@ class MSBF:
135
142
  if flowchart_name in self.flowcharts:
136
143
  raise KeyError(f"Flowchart with name '{flowchart_name}' already exists!")
137
144
 
138
- # Node IDs may not be sequential after user additions/deletions, so we track the absolute max value of
139
- # all nodes and store it so that _generate_next_id can set any IDs added via the flowchart correctly.
140
- self._global_node_id = max((node.id for flowchart in self for node in flowchart), default=1) + 1
141
-
142
145
  if entry_point is None:
143
146
  entry_point = LMS_EntryNode(self._generate_next_id(), flowchart_name)
144
147
 
@@ -150,6 +153,11 @@ class MSBF:
150
153
  self._nodes[node_id] = node
151
154
 
152
155
  self._nodes = dict(sorted(self._nodes.items()))
156
+
157
+ # Node IDs may not be sequential after user additions/deletions, so we track the absolute max value of
158
+ # all nodes and store it so that _generate_next_id can set any IDs added via the flowchart correctly.
159
+ self._global_node_id = max(self._nodes, default=-1) + 1
160
+
153
161
  return flowchart
154
162
 
155
163
  def delete_flowchart(self, name: str):
lms/flowchart/msbfio.py CHANGED
@@ -59,13 +59,12 @@ def read_msbf(
59
59
  file_info = read_file_info(reader, MSBF.MAGIC)
60
60
 
61
61
  msbf = MSBF(file_info)
62
-
63
62
  for magic, size in read_section_data(reader, file_info.section_count):
64
63
  match magic:
65
64
  case "FLW3":
66
65
  entry_nodes = read_flw3(reader, config, msbt)
67
66
  case "FEN1":
68
- labels, _ = read_labels(reader)
67
+ labels, slot_count = read_labels(reader)
69
68
  case "REF1":
70
69
  raise LMS_UnsupportedSectionError("""REF1 was found in the MSBF file! Please report this file as an issue
71
70
  in the PyLibMS repository https://github.com/AbdyyEee/PylibMS""")
@@ -74,6 +73,7 @@ def read_msbf(
74
73
  entry_nodes[i].flowchart_name = label
75
74
  msbf.add_flowchart(label, entry_nodes[i])
76
75
 
76
+ msbf.slot_count = slot_count
77
77
  return msbf
78
78
 
79
79
 
@@ -115,12 +115,6 @@ def write_msbf(file: MSBF) -> bytes:
115
115
  # Saved here so ids aren't mutated in the current state
116
116
  stream_ids = {node: stream_id for stream_id, node in enumerate(file.nodes.values())}
117
117
 
118
- for chart in file:
119
- if amount := len(chart.get_dangling_nodes()):
120
- raise LMS_Error(
121
- f"Unable to write the flowchart '{chart.name}'! There are {amount} dangling nodes."
122
- )
123
-
124
118
  index_map = {
125
119
  flowchart.name: stream_ids[flowchart.entry_point] for flowchart in file
126
120
  }
@@ -131,7 +125,7 @@ def write_msbf(file: MSBF) -> bytes:
131
125
  "FEN1",
132
126
  write_labels,
133
127
  list(file.flowcharts.keys()),
134
- MSBF.DEFAULT_SLOT_COUNT,
128
+ file.slot_count,
135
129
  index_map,
136
130
  )
137
131
  write_file_size(writer)
@@ -5,7 +5,8 @@ from lms.project.definitions.tag import LMS_TagDefinition
5
5
  def read_tag2(reader: FileReader) -> list[LMS_TagDefinition]:
6
6
  info_list = []
7
7
 
8
- count = reader.read_uint32()
8
+ count = reader.read_uint16()
9
+ reader.skip(2)
9
10
  for offset in reader.read_offset_array(count):
10
11
  reader.seek(offset)
11
12
 
@@ -14,5 +15,6 @@ def read_tag2(reader: FileReader) -> list[LMS_TagDefinition]:
14
15
  name = reader.read_encoded_string()
15
16
 
16
17
  info_list.append(LMS_TagDefinition(name, parameter_indices))
18
+ reader.align(4)
17
19
 
18
20
  return info_list
@@ -5,7 +5,8 @@ from lms.project.definitions.tag import LMS_TagGroup
5
5
  def read_tgg2(reader: FileReader, version: int) -> list[LMS_TagGroup]:
6
6
  group_list = []
7
7
 
8
- count = reader.read_uint32()
8
+ count = reader.read_uint16()
9
+ reader.skip(2)
9
10
  for i, offset in enumerate(reader.read_offset_array(count)):
10
11
  reader.seek(offset)
11
12
 
@@ -18,5 +19,6 @@ def read_tgg2(reader: FileReader, version: int) -> list[LMS_TagGroup]:
18
19
 
19
20
  name = reader.read_encoded_string()
20
21
  group_list.append(LMS_TagGroup(name, group_id, tag_indexes))
22
+ reader.align(4)
21
23
 
22
24
  return group_list
@@ -6,7 +6,8 @@ from lms.project.definitions.tag import LMS_TagParamDefinition
6
6
  def read_tgp2(reader: FileReader) -> list[LMS_TagParamDefinition]:
7
7
  parameter_info = []
8
8
 
9
- count = reader.read_uint32()
9
+ count = reader.read_uint16()
10
+ reader.skip(2)
10
11
  for offset in reader.read_offset_array(count):
11
12
  reader.seek(offset)
12
13
 
@@ -24,5 +25,6 @@ def read_tgp2(reader: FileReader) -> list[LMS_TagParamDefinition]:
24
25
  parameter_info.append(
25
26
  LMS_TagParamDefinition(name, LMS_DataType.LIST, list_indexes)
26
27
  )
28
+ reader.align(4)
27
29
 
28
30
  return parameter_info
lms/titleconfig/config.py CHANGED
@@ -29,31 +29,16 @@ class TitleConfig:
29
29
  NODE_KEY = "node_definitions"
30
30
 
31
31
  GAME_PRESET = Literal[
32
- "Animal Crossing: City Folk",
33
- "Animal Crossing: New Horizons",
34
- "Animal Crossing: New Leaf",
35
- "The Legend of Zelda: Echoes of Wisdom"
36
- "Metroid Prime 4: Beyond"
37
- "Mario vs. Donkey Kong"
38
- "Paper Mario: Color Splash"
39
- "Paper Mario: Sticker Star"
40
- "Paper Mario: The Origami King"
41
- "Paper Mario: The Thousand-Year Door (Nintendo Switch)"
42
- "Super Mario 3D Land"
43
- "Super Mario 3D World + Bowser's Fury"
44
- "Super Mario Odyssey"
45
- "Splatoon 3"
46
- "The Legend of Zelda: Link's Awakening (Nintendo Switch)"
47
- "The Legend of Zelda a Link Between Worlds",
48
- "The Legend of Zelda: Tri Force Heroes"
49
- "Tomodachi Life (NA-EU)",
50
- "Tomodachi Life (JP)",
51
- "Tomodachi Life: Living the Dream",
52
- "The Legend of Zelda: Tears of the Kingdom"
53
- "Wii Sports Club"
32
+ "Badge Arcade",
54
33
  "Brain Age Concentration Training",
55
34
  "Kirby Planet Robobot",
56
35
  "Super Mario Odyssey",
36
+ "Super Mario 3D Land",
37
+ "Super Mario 3D World + Bowsers Fury",
38
+ "The Legend of Zelda a Link Between Worlds",
39
+ "The Legend of Zelda Echos of Wisdom",
40
+ "Tomodachi Life Living The Dream",
41
+ "Tomodachi Life NA-EU",
57
42
  ]
58
43
 
59
44
  def __init__(
@@ -218,7 +203,7 @@ class TitleConfig:
218
203
  game = parsed_content.get("game")
219
204
 
220
205
  attribute_configs = {}
221
- for config in parsed_content[cls.ATTR_KEY]:
206
+ for config in parsed_content.get(cls.ATTR_KEY, []):
222
207
  definitions = [
223
208
  ValueDefinition.from_dict(value_def)
224
209
  for value_def in config["definitions"]
@@ -227,21 +212,28 @@ class TitleConfig:
227
212
  config["name"], config.get("description", ""), definitions
228
213
  )
229
214
 
215
+ tag_config = None
230
216
  tag_definitions: dict[int, list[TagDefinition]] = {}
231
- group_map = parsed_content[cls.TAG_KEY]["groups"]
217
+ tag_content = parsed_content.get(cls.TAG_KEY, None)
232
218
 
233
- for tag_def in parsed_content[cls.TAG_KEY]["tags"]:
234
- definition = TagDefinition.from_dict(tag_def, group_map)
235
- if definition.group_id not in tag_definitions:
236
- tag_definitions[definition.group_id] = []
237
- tag_definitions[definition.group_id].append(definition)
219
+ if tag_content is not None:
220
+ group_map = tag_content["groups"]
238
221
 
239
- tag_config = TagConfig(group_map, tag_definitions)
222
+ for tag_def in tag_content["tags"]:
223
+ definition = TagDefinition.from_dict(tag_def, group_map)
224
+ if definition.group_id not in tag_definitions:
225
+ tag_definitions[definition.group_id] = []
226
+ tag_definitions[definition.group_id].append(definition)
227
+
228
+ tag_config = TagConfig(group_map, tag_definitions)
240
229
 
241
230
  branch_nodes: dict[int, NodeDefinition | tuple[NodeDefinition, ...]] = {}
242
231
  event_nodes: dict[int, tuple[NodeDefinition, ...]] = {}
243
232
 
244
- for definition in parsed_content[cls.NODE_KEY]["branch"]:
233
+ node_data = parsed_content.get(cls.NODE_KEY, [])
234
+ branch_data, event_data = node_data.get("branch", []), node_data.get("event", [])
235
+
236
+ for definition in branch_data:
245
237
  node_id = definition["id"]
246
238
 
247
239
  node_definition = NodeDefinition.from_dict(
@@ -259,7 +251,7 @@ class TitleConfig:
259
251
  else:
260
252
  branch_nodes[node_id] = (existing, node_definition)
261
253
 
262
- for definition in parsed_content[cls.NODE_KEY]["event"]:
254
+ for definition in event_data:
263
255
  node_id = definition["id"]
264
256
 
265
257
  node_definition = NodeDefinition.from_dict(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PyLibMS
3
- Version: 4.3.2
3
+ Version: 4.3.4
4
4
  Summary: Python library built for the libMessageStudio (LMS) proprietary file formats from Nintendo. Supports MSBT, MSBP, and MSBF.
5
5
  Author: AbdyyEee
6
6
  License-Expression: MIT
@@ -1,25 +1,25 @@
1
1
  lms/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
2
  lms/common/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
- lms/common/lms_constants.py,sha256=SFl6Ml6XiHVRlgKzCh2ug6kX2J4h3vA5aHZy5_126rI,215
3
+ lms/common/lms_constants.py,sha256=sE5ODxUsRTHgC-yTxfqb4JsBN7P6_I3i9V_iKmeGAF0,242
4
4
  lms/common/lms_exceptions.py,sha256=PKMhCPqScQ571S_ypcYc8WEM5kAAzj1qPZ2texwCVfs,250
5
5
  lms/common/lms_fileinfo.py,sha256=pTabx6x3DuE0bMGmjXOcXVQDWF30G_0VnWrzRRf36IU,252
6
6
  lms/common/field/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
7
  lms/common/field/io.py,sha256=2eHUxkBPyAO9XNqx-Asym8Dv00s58DVXtAzBd3cmyT0,3136
8
8
  lms/common/field/lms_datatype.py,sha256=taIV8YlpzCxlCLkarh2NyvUId7I_fryn8XmD0bEjnvs,4656
9
9
  lms/common/field/lms_field.py,sha256=uAxQCNmiGfcmwgn_ir77X_QLUW4uVJ3rki1bRBKEcyI,6282
10
- lms/common/stream/fileinfo.py,sha256=psEs1cOZ6h4ky3OfNqjVV4umwM6h69UFQl-CDIJ5OQQ,2382
10
+ lms/common/stream/fileinfo.py,sha256=by8c4kVG9ndHW2a6iIBSxu_Vqhf9h8WBTp3JSyGi_t4,2421
11
11
  lms/common/stream/hashtable.py,sha256=b44QIo5FKtKJlrL3cO1XxRjPv4fjOEGf_Fh98NAYlGo,2589
12
12
  lms/common/stream/section.py,sha256=v-mkS0RDTgHZnnGU_EsFVWMGpBC74Jxt1kd5hwMVgsc,1615
13
13
  lms/fileio/encoding.py,sha256=ppchv-Pp23q3MpS9ROMmh4x47LYzFN2CQgYDhbEHuQE,1279
14
14
  lms/fileio/io.py,sha256=XiibCpJahW2_rHHjOaJEYL32dv5x1egvFBMjy9E_VlE,6632
15
15
  lms/flowchart/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
16
  lms/flowchart/flw3.py,sha256=WmKEnAjp29pC8VLqc6lkGOtwG9v3si4thgArazsrW-E,15388
17
- lms/flowchart/msbf.py,sha256=4bk8jMqRi9wBUbYLzkqAbfueDeapwd9h5_dHR4hsoI0,6488
18
- lms/flowchart/msbfio.py,sha256=PuyTJgksl_ced-tlxGeArh18ZtrszbFg_1kDsLw4mKE,4221
17
+ lms/flowchart/msbf.py,sha256=JfNk0zOXFkbtu2q6Su5g2Ui30pLSpzNEqEUQjzniRys,6733
18
+ lms/flowchart/msbfio.py,sha256=EctdzcOD4SUkLkRNGI6B42Ub3xrJ9EVEZSvwOH8SR4s,4027
19
19
  lms/flowchart/definitions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
20
20
  lms/flowchart/definitions/flowchart.py,sha256=lNyxAI0jka1rVkkZG_BiYk2IcUZA_8J46fpOMVjxdH8,3268
21
21
  lms/flowchart/definitions/lms_nodeexceptions.py,sha256=hlcqW6ERMVyAf2nqxaiSyFdXDfwthFADK79ggS_B3GU,181
22
- lms/flowchart/definitions/node.py,sha256=LsrhMoCagNv4LW0qU46CIzrPZQDrs_8O7xFu37DgGIk,20234
22
+ lms/flowchart/definitions/node.py,sha256=frAchwIQW6LRIBUv0_FA7KwrQNQLOmZmbAtM4CpJ_Oc,20518
23
23
  lms/flowchart/definitions/node_type.py,sha256=LofkFaDwx-kGiZNwTh-J2OMmDQcLroVqxX7GtAV-Sys,4330
24
24
  lms/message/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
25
25
  lms/message/lms_messagetext.py,sha256=jbtIYA7hZBejfMEAkC9d65MYfU4v3WqTeN4Olz-mtQw,6002
@@ -51,11 +51,11 @@ lms/project/section/ati2.py,sha256=zXfUUCUMOzzSuN_TZvd0MBzQVx7kOUINlqQlvhczEvY,5
51
51
  lms/project/section/clr1.py,sha256=J81YnoEGhCR2LD25YqUddznr4uHVci6DUqRrx4K1XJ8,407
52
52
  lms/project/section/string.py,sha256=x2L3GhYhcDYMdCCa95lSkyBNtyTamnWQncB_oIDXsg4,469
53
53
  lms/project/section/syl3.py,sha256=WhLIxD2AQa15nMx1ZvFqurDqH2J8yi5cf9xsXjh0GOw,530
54
- lms/project/section/tag2.py,sha256=IpEEa98sEYifHz5k5eeQLu9A-E3ZIOlkg5p0lagr5QA,555
55
- lms/project/section/tgg2.py,sha256=ajAZMS9m3Ovd2daZP0sWLZTurZh5PkHAgh2VGcz4ZCE,835
56
- lms/project/section/tgp2.py,sha256=bdTBtzFpWseRgkze4B3BJeUrrGq74m9lgbtbRtbzAO4,945
54
+ lms/project/section/tag2.py,sha256=AGuiTroly8NMOhFunSiYKfLPlaOjRTOrfMtJYxh8VQE,600
55
+ lms/project/section/tgg2.py,sha256=8lkoFr6Qm3eL5pe8DLhRXiwifZM8wY1Dev5DDBLVrUk,880
56
+ lms/project/section/tgp2.py,sha256=hW2keC13Csybi4croBB61H6ttk0doP4A2fhFZszG4-0,990
57
57
  lms/titleconfig/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
58
- lms/titleconfig/config.py,sha256=444oJkABC1alpqXR9IXMBWJHIWD__UdIziJQ0fn4K-g,12725
58
+ lms/titleconfig/config.py,sha256=YUtpSAG3X301pZrilriT-MzERsEjAwIbEY0PSsCAGRI,12327
59
59
  lms/titleconfig/definitions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
60
60
  lms/titleconfig/definitions/attribute.py,sha256=5gP7IgBDLZ-9kxiC6bwA0iQ9vK2wvZsFmS3Nelo1Nw8,297
61
61
  lms/titleconfig/definitions/nodes.py,sha256=RGcbZFUUbW63PycXP6WZxpQeHGBujnK7ff0fgBVIARc,5826
@@ -70,8 +70,8 @@ lms/titleconfig/presets/Super Mario Odyssey.yaml,sha256=mV4BsLPzupEPy2RmPUxXlz0U
70
70
  lms/titleconfig/presets/The Legend of Zelda Echos of Wisdom.yaml,sha256=6AoSNRNORjMzMBp2ais_ujRdLLeOe7FB0YlozZJNvHg,2878
71
71
  lms/titleconfig/presets/The Legend of Zelda a Link Between Worlds.yaml,sha256=IY8wPIWMA4ElnN_dtV455beBucntxEBeeJXxUUIrnuw,9785
72
72
  lms/titleconfig/presets/Tomodachi Life Living The Dream.yaml,sha256=hJNb0_KdUAZrztyphaTeaZJl_os7HpmdglLgly_eerU,82382
73
- pylibms-4.3.2.dist-info/licenses/LICENSE,sha256=IGTA9rMb-XpTMPJOzC6z0rRxSzysj3DlV5IQyDd06Xo,1061
74
- pylibms-4.3.2.dist-info/METADATA,sha256=BUOVUmrO_KQWy14wnjFwviQbeCEu6yCt10jVmtl9RK0,4374
75
- pylibms-4.3.2.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
76
- pylibms-4.3.2.dist-info/top_level.txt,sha256=SWQqb3sjP5r5Ls1Ol4E_PIbsv1sggK4DCkkLEzXNRTU,4
77
- pylibms-4.3.2.dist-info/RECORD,,
73
+ pylibms-4.3.4.dist-info/licenses/LICENSE,sha256=IGTA9rMb-XpTMPJOzC6z0rRxSzysj3DlV5IQyDd06Xo,1061
74
+ pylibms-4.3.4.dist-info/METADATA,sha256=HlmvJXz8UkvpTqpruD5ZNH62UqdNhnamKWOngFxfoUQ,4374
75
+ pylibms-4.3.4.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
76
+ pylibms-4.3.4.dist-info/top_level.txt,sha256=SWQqb3sjP5r5Ls1Ol4E_PIbsv1sggK4DCkkLEzXNRTU,4
77
+ pylibms-4.3.4.dist-info/RECORD,,