math-spec-mapping 0.2.6.7__py3-none-any.whl → 0.2.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.
- math_spec_mapping/Classes/ControlAction.py +1 -0
- math_spec_mapping/Classes/MathSpec.py +98 -0
- math_spec_mapping/Classes/Mechanism.py +1 -0
- math_spec_mapping/Classes/Policy.py +1 -0
- math_spec_mapping/Classes/Space.py +1 -0
- math_spec_mapping/Classes/State.py +1 -0
- math_spec_mapping/Classes/Type.py +1 -0
- math_spec_mapping/Load/control_actions.py +10 -0
- math_spec_mapping/Load/mechanism.py +8 -0
- math_spec_mapping/Load/policy.py +11 -2
- math_spec_mapping/Load/type.py +1 -0
- math_spec_mapping/Reports/html.py +33 -1
- {math_spec_mapping-0.2.6.7.dist-info → math_spec_mapping-0.2.7.dist-info}/METADATA +1 -1
- {math_spec_mapping-0.2.6.7.dist-info → math_spec_mapping-0.2.7.dist-info}/RECORD +17 -17
- {math_spec_mapping-0.2.6.7.dist-info → math_spec_mapping-0.2.7.dist-info}/LICENSE +0 -0
- {math_spec_mapping-0.2.6.7.dist-info → math_spec_mapping-0.2.7.dist-info}/WHEEL +0 -0
- {math_spec_mapping-0.2.6.7.dist-info → math_spec_mapping-0.2.7.dist-info}/top_level.txt +0 -0
@@ -4,6 +4,7 @@ from .Policy import Policy
|
|
4
4
|
from .Mechanism import Mechanism
|
5
5
|
from .ControlAction import ControlAction
|
6
6
|
from .BoundaryAction import BoundaryAction
|
7
|
+
import os
|
7
8
|
|
8
9
|
|
9
10
|
class MathSpec:
|
@@ -12,6 +13,7 @@ class MathSpec:
|
|
12
13
|
self._ms_dict = ms_dict
|
13
14
|
self._json = json
|
14
15
|
self.type_keys = ms_dict["Type Keys"]
|
16
|
+
self.implementations = ms_dict["Implementations"]
|
15
17
|
self.action_transmission_channels = ms_dict["Action Transmission Channels"]
|
16
18
|
self.boundary_actions = ms_dict["Boundary Actions"]
|
17
19
|
self.control_actions = ms_dict["Control Actions"]
|
@@ -349,3 +351,99 @@ class MathSpec:
|
|
349
351
|
for metrics in self.stateful_metrics.values():
|
350
352
|
sm.extend([x.name for x in metrics.metrics])
|
351
353
|
return sm
|
354
|
+
|
355
|
+
def metaprogramming_python_types(self, model_directory, overwrite=False):
|
356
|
+
path = model_directory + "/types.py"
|
357
|
+
if not overwrite:
|
358
|
+
assert "types.py" not in os.listdir(
|
359
|
+
model_directory
|
360
|
+
), "The types file is already written, either delete it or switch to overwrite mode"
|
361
|
+
out = "import typing\n\n"
|
362
|
+
for t in self.types:
|
363
|
+
t = self.types[t]
|
364
|
+
assert "python" in t.type, "No python type associated with {}".format(
|
365
|
+
t.name
|
366
|
+
)
|
367
|
+
x = t.type["python"]
|
368
|
+
type_desc = x.__name__ if hasattr(x, "__name__") else str(x)
|
369
|
+
out += "{} = {}".format(t.original_type_name, type_desc)
|
370
|
+
out += "\n"
|
371
|
+
with open(path, "w") as f:
|
372
|
+
f.write(out)
|
373
|
+
|
374
|
+
def metaprogramming_python_spaces(self, model_directory, overwrite=False):
|
375
|
+
path = model_directory + "/spaces.py"
|
376
|
+
if not overwrite:
|
377
|
+
assert "spaces.py" not in os.listdir(
|
378
|
+
model_directory
|
379
|
+
), "The spaces file is already written, either delete it or switch to overwrite mode"
|
380
|
+
unique_spaces = set().union(
|
381
|
+
*[set(x.schema.values()) for x in self.spaces.values()]
|
382
|
+
)
|
383
|
+
unique_types = [x.original_type_name for x in unique_spaces]
|
384
|
+
out = ""
|
385
|
+
out += "from .types import {}".format(", ".join(unique_types))
|
386
|
+
out += "\n"
|
387
|
+
out += "from typing import TypedDict"
|
388
|
+
out += "\n"
|
389
|
+
out += "\n"
|
390
|
+
|
391
|
+
for space in self.spaces:
|
392
|
+
out += self.spaces[space].name_variable
|
393
|
+
out += " = "
|
394
|
+
d = self.spaces[space].schema
|
395
|
+
d = [(x, d[x].original_type_name) for x in d]
|
396
|
+
d = ["'{}': {}".format(x[0], x[1]) for x in d]
|
397
|
+
d = ", ".join(d)
|
398
|
+
d = "{" + d + "}"
|
399
|
+
out += "TypedDict('{}', {})".format(self.spaces[space].name, d)
|
400
|
+
out += "\n"
|
401
|
+
|
402
|
+
with open(path, "w") as f:
|
403
|
+
f.write(out)
|
404
|
+
|
405
|
+
def metaprogramming_python_states(
|
406
|
+
self, model_directory, overwrite=False, default_values=None
|
407
|
+
):
|
408
|
+
path = model_directory + "/states.py"
|
409
|
+
if not overwrite:
|
410
|
+
assert "states.py" not in os.listdir(
|
411
|
+
model_directory
|
412
|
+
), "The states file is already written, either delete it or switch to overwrite mode"
|
413
|
+
out = ""
|
414
|
+
unique_types = [x.variables for x in self.state.values()]
|
415
|
+
unique_types = [set(y.type.original_type_name for y in x) for x in unique_types]
|
416
|
+
unique_types = set().union(*unique_types)
|
417
|
+
out = ""
|
418
|
+
out += "from .types import {}".format(", ".join(unique_types))
|
419
|
+
out += "\n"
|
420
|
+
out += "from typing import TypedDict"
|
421
|
+
out += "\n"
|
422
|
+
out += "\n"
|
423
|
+
|
424
|
+
for state in self.state:
|
425
|
+
out += self.state[state].name_variable
|
426
|
+
out += " = "
|
427
|
+
d = self.state[state].variables
|
428
|
+
d = [(x.name, x.type.original_type_name) for x in d]
|
429
|
+
d = ["'{}': {}".format(x[0], x[1]) for x in d]
|
430
|
+
d = ", ".join(d)
|
431
|
+
d = "{" + d + "}"
|
432
|
+
out += "TypedDict('{}', {})".format(self.state[state].name, d)
|
433
|
+
out += "\n"
|
434
|
+
out += "\n"
|
435
|
+
out += "state: GlobalState = "
|
436
|
+
out += "{"
|
437
|
+
for x in self.state["Global State"].variables:
|
438
|
+
out += '"{}"'.format(x.name)
|
439
|
+
out += ": "
|
440
|
+
val = "None"
|
441
|
+
if default_values:
|
442
|
+
if x.name in default_values:
|
443
|
+
val = str(default_values[x.name])
|
444
|
+
out += val
|
445
|
+
out += ",\n"
|
446
|
+
out += "}"
|
447
|
+
|
448
|
+
with open(path, "w") as f:
|
449
|
+
f.write(out)
|
@@ -35,6 +35,16 @@ def convert_control_action(data: Dict, ms: Dict) -> ControlAction:
|
|
35
35
|
new_cao = []
|
36
36
|
for ca in data["control_action_options"]:
|
37
37
|
check_json_keys(ca, "Control Action Option")
|
38
|
+
ca["implementations"] = {}
|
39
|
+
if "python" in ms["Implementations"]:
|
40
|
+
if "control_action_options" in ms["Implementations"]["python"]:
|
41
|
+
if (
|
42
|
+
ca["name"]
|
43
|
+
in ms["Implementations"]["python"]["control_action_options"]
|
44
|
+
):
|
45
|
+
ca["implementations"]["python"] = ms["Implementations"]["python"][
|
46
|
+
"control_action_options"
|
47
|
+
][ca["name"]]
|
38
48
|
new_cao.append(ControlActionOption(ca))
|
39
49
|
data["control_action_options"] = new_cao
|
40
50
|
|
@@ -42,6 +42,14 @@ def convert_mechanism(data: Dict, ms: Dict) -> Mechanism:
|
|
42
42
|
)
|
43
43
|
|
44
44
|
data["domain"] = tuple(ms["Spaces"][x] for x in data["domain"])
|
45
|
+
data["implementations"] = {}
|
46
|
+
|
47
|
+
if "python" in ms["Implementations"]:
|
48
|
+
if "mechanisms" in ms["Implementations"]["python"]:
|
49
|
+
if data["name"] in ms["Implementations"]["python"]["mechanisms"]:
|
50
|
+
data["implementations"]["python"] = ms["Implementations"]["python"][
|
51
|
+
"mechanisms"
|
52
|
+
][data["name"]]
|
45
53
|
|
46
54
|
# Build the action transmission channel object
|
47
55
|
return Mechanism(data), new_channels
|
math_spec_mapping/Load/policy.py
CHANGED
@@ -5,7 +5,7 @@ from ..Classes import Policy, PolicyOption
|
|
5
5
|
from .general import check_json_keys
|
6
6
|
|
7
7
|
|
8
|
-
def convert_policy_options(data: Dict) -> PolicyOption:
|
8
|
+
def convert_policy_options(data: Dict, ms) -> PolicyOption:
|
9
9
|
"""Function to convert policy options
|
10
10
|
|
11
11
|
Args:
|
@@ -21,6 +21,15 @@ def convert_policy_options(data: Dict) -> PolicyOption:
|
|
21
21
|
# Copy
|
22
22
|
data = data.copy()
|
23
23
|
|
24
|
+
data["implementations"] = {}
|
25
|
+
|
26
|
+
if "python" in ms["Implementations"]:
|
27
|
+
if "policies" in ms["Implementations"]["python"]:
|
28
|
+
if data["name"] in ms["Implementations"]["python"]["policies"]:
|
29
|
+
data["implementations"]["python"] = ms["Implementations"]["python"][
|
30
|
+
"policies"
|
31
|
+
][data["name"]]
|
32
|
+
|
24
33
|
# Build the policy object
|
25
34
|
return PolicyOption(data)
|
26
35
|
|
@@ -62,7 +71,7 @@ def convert_policy(data: Dict, ms: Dict) -> Policy:
|
|
62
71
|
# Convert policy options
|
63
72
|
policy_options = []
|
64
73
|
for po in data["policy_options"]:
|
65
|
-
policy_options.append(convert_policy_options(po))
|
74
|
+
policy_options.append(convert_policy_options(po, ms))
|
66
75
|
data["policy_options"] = policy_options
|
67
76
|
|
68
77
|
data["codomain"] = tuple(ms["Spaces"][x] for x in data["codomain"])
|
math_spec_mapping/Load/type.py
CHANGED
@@ -9,6 +9,7 @@ from .node_map import create_action_chains_graph
|
|
9
9
|
from .parameters import write_out_params
|
10
10
|
from .state import write_local_state_variable_tables, write_global_state_variable_table
|
11
11
|
from typing import List
|
12
|
+
import os
|
12
13
|
|
13
14
|
|
14
15
|
def write_basic_report_full(ms: MathSpec, directory: str, name: str) -> None:
|
@@ -128,6 +129,15 @@ def write_spec_tree(
|
|
128
129
|
symbol3 = "│ │ ├──"
|
129
130
|
|
130
131
|
out = ""
|
132
|
+
|
133
|
+
if linking:
|
134
|
+
out += """---
|
135
|
+
cssclasses:
|
136
|
+
- spec
|
137
|
+
---
|
138
|
+
|
139
|
+
"""
|
140
|
+
|
131
141
|
out += symbol1 + "**Entities**\n"
|
132
142
|
for name in ms.entities.keys():
|
133
143
|
if linking:
|
@@ -214,7 +224,29 @@ def write_spec_tree(
|
|
214
224
|
if path:
|
215
225
|
with open("{}/Spec Tree.md".format(path), "w") as f:
|
216
226
|
f.write(out)
|
217
|
-
|
227
|
+
try:
|
228
|
+
if ".obsidian" not in os.listdir(path):
|
229
|
+
path = path + "/" + ".obsidian"
|
230
|
+
os.mkdir(path)
|
231
|
+
else:
|
232
|
+
path = path + "/" + ".obsidian"
|
233
|
+
if "snippets" not in os.listdir(path):
|
234
|
+
path = path + "/" + "snippets"
|
235
|
+
os.mkdir(path)
|
236
|
+
else:
|
237
|
+
path = path + "/" + "snippets"
|
238
|
+
|
239
|
+
snippet = """.spec {
|
240
|
+
font-family: 'Consolas', Courier, monospace ;
|
241
|
+
line-height: 1;
|
242
|
+
}"""
|
243
|
+
with open("{}/spec.css".format(path), "w") as f:
|
244
|
+
f.write(snippet)
|
245
|
+
|
246
|
+
except:
|
247
|
+
print("Couldn't find .obsidian/snippets to put snippet in")
|
248
|
+
else:
|
249
|
+
return out
|
218
250
|
|
219
251
|
|
220
252
|
def write_overview(ms: MathSpec, name: str, file_path: str, summary: str = None):
|
@@ -4,18 +4,18 @@ math_spec_mapping/schema.schema.json,sha256=E8-TQIiv7AjIMXnAIB84z_O4cMLfGuDmDCFC
|
|
4
4
|
math_spec_mapping/Classes/ActionTransmissionChannel.py,sha256=zWMo5QsgPh5WGIWXl-xOrZNMXYJXmK6Vejw1dQvi0og,246
|
5
5
|
math_spec_mapping/Classes/Block.py,sha256=hXQO221IP-TqZm_TwFKfURpEEjZm7L1TPZDCYlaOdho,17302
|
6
6
|
math_spec_mapping/Classes/BoundaryAction.py,sha256=AOENCqCEfpjotnHhzUj_F2SOP0SGpkN1tNPr8Mtl6Tc,476
|
7
|
-
math_spec_mapping/Classes/ControlAction.py,sha256=
|
7
|
+
math_spec_mapping/Classes/ControlAction.py,sha256=ysqpgANwdizVdwqtgZmnxXMpCqrzmVEF_6YT0M3l4Ho,526
|
8
8
|
math_spec_mapping/Classes/Entity.py,sha256=fA0-b128_OHHxfCg4pzqyQV083EYev1HlVpy86S5igg,1226
|
9
|
-
math_spec_mapping/Classes/MathSpec.py,sha256=
|
10
|
-
math_spec_mapping/Classes/Mechanism.py,sha256=
|
9
|
+
math_spec_mapping/Classes/MathSpec.py,sha256=eweFUB8iuEI5Y-9VOULbAWbIeHd18Iw-I_VPUjvnn0E,16999
|
10
|
+
math_spec_mapping/Classes/Mechanism.py,sha256=2sLm3wYBIeTQaMBcsJ9btqIWsbS895Ra8NY6Y9_G_Dg,379
|
11
11
|
math_spec_mapping/Classes/Metric.py,sha256=AhPgYppOP6q49xvR8S9STxQsXUKJlTWx7wI1LfZEtww,581
|
12
12
|
math_spec_mapping/Classes/Parameter.py,sha256=ZuJ_w0sChvRElJ4sOnXZ2EV4Ell2xXFulKLjVOpgz2E,1237
|
13
|
-
math_spec_mapping/Classes/Policy.py,sha256=
|
14
|
-
math_spec_mapping/Classes/Space.py,sha256=
|
15
|
-
math_spec_mapping/Classes/State.py,sha256=
|
13
|
+
math_spec_mapping/Classes/Policy.py,sha256=fzV85tB3QScjiYGfhw_dyQt9L1BYYfTyTIQQcxeT8ac,530
|
14
|
+
math_spec_mapping/Classes/Space.py,sha256=QsahxoUfRsDWQLBL683KnGx72MAmRxv7CDE7TMgCG-E,472
|
15
|
+
math_spec_mapping/Classes/State.py,sha256=0gJHHTNjTrz1fL2K-yPu-dJlaCsU_NMxClw6neDv6gE,1497
|
16
16
|
math_spec_mapping/Classes/StateUpdateTransmissionChannel.py,sha256=3hBLvD1lE64PkwqksBXAfFWv7foOZzGQLAFQWy42tOA,257
|
17
17
|
math_spec_mapping/Classes/StatefulMetric.py,sha256=UCis1BJ7fsajHHxFF05ZiyDean2D4s4a95uYYW1Mjq4,749
|
18
|
-
math_spec_mapping/Classes/Type.py,sha256=
|
18
|
+
math_spec_mapping/Classes/Type.py,sha256=2KFY8d3cv1PzJJ7SSMHJf1zcfQ3ZbqxotK2KgTaLZdM,289
|
19
19
|
math_spec_mapping/Classes/__init__.py,sha256=_hXyZMJanmIex_W6yCR2H7Jw8iU2JJIf3U7VcvBSOGU,737
|
20
20
|
math_spec_mapping/Convenience/__init__.py,sha256=-hNZVoaNSgTmZTiyZoMfWyg14xonC3ppz-diQk1VlUY,60
|
21
21
|
math_spec_mapping/Convenience/documentation.py,sha256=Jf7-JJIk_vZkNBIGV4bs5LM3B0RVaCCtuwJ164thGfY,1607
|
@@ -23,27 +23,27 @@ math_spec_mapping/Convenience/starter.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NM
|
|
23
23
|
math_spec_mapping/Load/__init__.py,sha256=_ga5nHi7U5rY5lCF36_XI9Qmybq4P8R4m5I5mmjLBk8,33
|
24
24
|
math_spec_mapping/Load/action_transmission_channel.py,sha256=9Wer7g2s5SSOcUYuZ0PqSKUVVnW3EvGQJZNXJTwW__0,2561
|
25
25
|
math_spec_mapping/Load/boundary_actions.py,sha256=WvEj2tqN0pUZtE4EiKUuGzMdAcWsMlLslJJeFjIu6gk,2058
|
26
|
-
math_spec_mapping/Load/control_actions.py,sha256=
|
26
|
+
math_spec_mapping/Load/control_actions.py,sha256=4E57s730W4tX5SaKXKaAvet37r8Bwt-g8Kk6EanF4TU,2042
|
27
27
|
math_spec_mapping/Load/displays.py,sha256=ooHWT_OryzEkp7F3LcGywwdLMRJLxuyPK82zJ3gcyN0,414
|
28
28
|
math_spec_mapping/Load/entities.py,sha256=rMD_Pja-zqH1Z14rsO_Ia7dg3BIi5_HoQmqGAoEYofA,1208
|
29
29
|
math_spec_mapping/Load/general.py,sha256=2q6aGKxXhebiHHTZhtACvM4nWIkTben0o5rXuvfv2Vw,4463
|
30
30
|
math_spec_mapping/Load/implementations.py,sha256=SGKZ_YXeNpJUTnw5fajQTXji7S2bNQo8sh-7YcIO6pk,395
|
31
31
|
math_spec_mapping/Load/load.py,sha256=CLprDhJpbwm9RAzKM2Ghwr8eqBu0a-wvGDOCMmc01YE,2484
|
32
|
-
math_spec_mapping/Load/mechanism.py,sha256=
|
32
|
+
math_spec_mapping/Load/mechanism.py,sha256=JBy-QpB4W0Z2OcNiakONjD4_RtEgxlFKtLXfDqfhR-0,2037
|
33
33
|
math_spec_mapping/Load/metrics.py,sha256=gD68mt0Y5jSgofZUwscV8PFatOMV_LPwYyPrwV9SdtE,3273
|
34
34
|
math_spec_mapping/Load/parameters.py,sha256=aid_vqYub9643s82NDtMAXLRdV9BPQkri5MadA0L0eQ,1334
|
35
|
-
math_spec_mapping/Load/policy.py,sha256=
|
35
|
+
math_spec_mapping/Load/policy.py,sha256=HvlhGHGJTweVs7DOI2HSL_2_diECr8ukDUmzoFLQELo,2444
|
36
36
|
math_spec_mapping/Load/spaces.py,sha256=7zgGA57Te7T4hfuCCDElffiidWgn1lKm5E14e1yjt8M,1116
|
37
37
|
math_spec_mapping/Load/state_update_transmission_channels.py,sha256=FJWp5n4HdtHAfof5BUQ6BnRakljatL2h8dWCapaVSc0,2238
|
38
38
|
math_spec_mapping/Load/stateful_metrics.py,sha256=uGSTc6x6lld5xptgSUMHrO0Vg0QDRIL14C6zTg33S8o,1977
|
39
39
|
math_spec_mapping/Load/states.py,sha256=cwo29SBAtj1FoQLEb8c0wkSCn038lIgM9RjNiZefUaE,1223
|
40
|
-
math_spec_mapping/Load/type.py,sha256=
|
40
|
+
math_spec_mapping/Load/type.py,sha256=Wq2EYTofuq4v8_jGGSr23IXJjwavLMjsqSEyhX9VoAM,4217
|
41
41
|
math_spec_mapping/Load/wiring.py,sha256=1dR94U5N1W_WI5rL6lYBltH25ZvApB2pIpq9r5Opkug,3083
|
42
42
|
math_spec_mapping/Reports/__init__.py,sha256=W27I6S9Ro1hWeHmnxIokCA06awB__eYey7PvKD4Hc1s,933
|
43
43
|
math_spec_mapping/Reports/boundary_actions.py,sha256=45BPp4QjWdD-3E9ZWwqgj_nI2-YdcI2ZZ19_Qv_K7Qk,1410
|
44
44
|
math_spec_mapping/Reports/control_actions.py,sha256=NksekZKIPFSIkubttFstKFthc5AU9B9PWRLSl9j1wWs,1216
|
45
45
|
math_spec_mapping/Reports/general.py,sha256=WOOn6Wlb8M4fsdN49FlKLwOka6vJPQ9aCUy88TL2ki0,1610
|
46
|
-
math_spec_mapping/Reports/html.py,sha256=
|
46
|
+
math_spec_mapping/Reports/html.py,sha256=xf5jk3DHWg4CfZHZuF2JK5iZ515ecjDShJJsahiqb4g,8882
|
47
47
|
math_spec_mapping/Reports/markdown.py,sha256=pDGHYMdtZmeXHqvU9FB3BycyB4qflWXq0bf2m-wsXMU,21138
|
48
48
|
math_spec_mapping/Reports/mechanisms.py,sha256=d2Rxt3JBYvqAOAYUynl0buYVoXEHrO8EGq7GK6hK8NA,1322
|
49
49
|
math_spec_mapping/Reports/node_map.py,sha256=FdSMDQG16NX6n9sZcH-T5xwsvgjrV9OqBHc9J_VlNK0,3129
|
@@ -53,8 +53,8 @@ math_spec_mapping/Reports/spaces.py,sha256=-76hR5wQBv4lsG000ypBJ-OprjsNjI-rNRMYd
|
|
53
53
|
math_spec_mapping/Reports/state.py,sha256=RSHDjzSiUj4ZjReWbkBW7k2njs3Ovp-q0rCC7GBfD-A,2203
|
54
54
|
math_spec_mapping/Reports/tables.py,sha256=O0CNuqh3LMECq5uLjBOoxMUk5hUvkUK660FNnwWUxDY,1505
|
55
55
|
math_spec_mapping/Reports/wiring.py,sha256=u9SvKWy6T-WJUEgFI6-zgZanoOaTTs_2YwmEceDLsV8,1618
|
56
|
-
math_spec_mapping-0.2.
|
57
|
-
math_spec_mapping-0.2.
|
58
|
-
math_spec_mapping-0.2.
|
59
|
-
math_spec_mapping-0.2.
|
60
|
-
math_spec_mapping-0.2.
|
56
|
+
math_spec_mapping-0.2.7.dist-info/LICENSE,sha256=ObyEzSw8kgCaFbEfpu1zP4TrcAKLA0xhqHMZZfyh7N0,1069
|
57
|
+
math_spec_mapping-0.2.7.dist-info/METADATA,sha256=H3plPQQrT7sss_57Z2341oAlBkMpW7_QHihqFoZcgUM,6012
|
58
|
+
math_spec_mapping-0.2.7.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
59
|
+
math_spec_mapping-0.2.7.dist-info/top_level.txt,sha256=AImhn9wgazkdV0a9vfiphtQR8uGe2nq-ZIOp-6yUk9o,18
|
60
|
+
math_spec_mapping-0.2.7.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|