Skip to content
Snippets Groups Projects
Unverified Commit e8146aea authored by Xavier Robin's avatar Xavier Robin
Browse files

feat: SCHWED-5783 accept ligands as input

parent 692296a0
No related branches found
No related tags found
No related merge requests found
Showing
with 8337 additions and 22 deletions
......@@ -20,15 +20,19 @@ class LigandScorer:
No additional processing (ie. Molck), checks or sanitization
is performed on the input.
:type target: :class:`ost.mol.EntityHandle`/:class:`ost.mol.EntityView`
:param model_ligands: Model ligands, either a :class:list of
:param model_ligands: Model ligands, as a list of
:class:`ost.mol.ResidueHandle`s belonging to the model
entity. Can be instantiated with either a :class:list of
:class:`ost.mol.ResidueHandle`/:class:`ost.mol.ResidueView`
or of :class:`ost.mol.EntityHandle`/:class:`ost.mol.EntityView`
containing a single residue each. If `None`, ligands will be
extracted from the `model` entity, from chains with
:class:`~ost.mol.ChainType` `CHAINTYPE_NON_POLY` (this is
normally set properly in entities loaded from mmCIF).
or of :class:`ost.mol.EntityHandle`/:class:`ost.mol.EntityView`.
If `None`, ligands will be extracted from the `model` entity,
from chains with :class:`~ost.mol.ChainType`
`CHAINTYPE_NON_POLY` (this is normally set properly in
entities loaded from mmCIF).
:type model_ligands: :class:`list`
:param target_ligands: Target ligands, either a :class:list of
:param target_ligands: Target ligands, as a list of
:class:`ost.mol.ResidueHandle`s belonging to the target
entity. Can be instanciated either a :class:list of
:class:`ost.mol.ResidueHandle`/:class:`ost.mol.ResidueView`
or of :class:`ost.mol.EntityHandle`/:class:`ost.mol.EntityView`
containing a single residue each. If `None`, ligands will be
......@@ -46,38 +50,35 @@ class LigandScorer:
lazily as required.
:type chain_mapper: :class:`ost.mol.alg.chain_mapping.ChainMapper`
"""
def __init__(self, model, target, model_ligands=None, target_ligands=None,
resnum_alignments=False, chain_mapper=None):
if isinstance(model, mol.EntityView):
self._model = mol.CreateEntityFromView(model, False)
self.model = mol.CreateEntityFromView(model, False)
elif isinstance(model, mol.EntityHandle):
self._model = model.Copy()
self.model = model.Copy()
else:
raise RuntimeError("model must be of type EntityView/EntityHandle")
if isinstance(target, mol.EntityView):
self._target = mol.CreateEntityFromView(target, False)
self.target = mol.CreateEntityFromView(target, False)
elif isinstance(target, mol.EntityHandle):
self._target = target.Copy()
self.target = target.Copy()
else:
raise RuntimeError("model must be of type EntityView/EntityHandle")
# Extract ligands from target
if target_ligands is None:
self.target_ligands = self._extract_ligands(self._target)
self.target_ligands = self._extract_ligands(self.target)
else:
# TODO: sanitize given ligands
self.target_ligands = target_ligands
self.target_ligands = self._prepare_ligands(self.target, target, target_ligands)
# Extract ligands from model
if model_ligands is None:
self.model_ligands = self._extract_ligands(self._model)
self.model_ligands = self._extract_ligands(self.model)
else:
# TODO: sanitize given ligands
self.model_ligands = target_ligands
self.model_ligands = self._prepare_ligands(self.model, model, model_ligands)
self._chain_mapper = chain_mapper
self.resnum_alignments = resnum_alignments
......@@ -134,3 +135,82 @@ class LigandScorer:
extracted_ligands.append(residue)
return extracted_ligands
@staticmethod
def _prepare_ligands(new_entity, old_entity, ligands):
"""Prepare the ligands given into a list of ResidueHandles which are
part of the copied entity, suitable for the model_ligands and
target_ligands properties.
This function takes a list of ligands as (Entity|Residue)(Handle|View).
Entities can contain multiple ligands, which will be considered as
separate ligands.
Ligands which are part of the entity are simply fetched in the new
copied entity. Otherwise, they are copied over to the copied entity.
If
Copy ligands into the new copied entity, if needed.
and prepares the list of ligands to be returned as a list of
ResidueHandles which are part of the copied entity, and suitable for
model_ligands and target_ligands.
Multiple ligands can be supplied at once in an entity.
"""
extracted_ligands = []
next_chain_num = 1
new_editor = None
def _copy_residue(handle):
""" Copy the residue handle into the new chain.
Return the new residue handle."""
nonlocal next_chain_num, new_editor
# Instanciate the editor
if new_editor is None:
new_editor = new_entity.EditXCS()
# Add a new chain
new_chain = None
while new_chain is None:
try:
new_chain = new_editor.InsertChain(str(next_chain_num))
next_chain_num += 1
break
except Exception:
next_chain_num += 1
# Add the residue with residue number 1
new_res = new_editor.AppendResidue(new_chain, handle, deep=True)
new_res.SetIsLigand(True)
new_editor.SetResidueNumber(new_res, mol.ResNum(1))
return new_res
def _process_ligand_residue(res):
"""Copy or fetch the residue. Return the residue handle."""
if res.entity.handle == old_entity.handle:
# Residue is already in copied entity. We only need to grab it
new_res = new_entity.FindResidue(res.chain.name, res.number)
else:
# Residue is not part of the entity, need to copy it first
new_res = _copy_residue(res.handle)
return new_res
for ligand in ligands:
if isinstance(ligand, mol.EntityHandle) or isinstance(ligand, mol.EntityView):
for residue in ligand.residues:
new_residue = _process_ligand_residue(residue)
extracted_ligands.append(new_residue)
elif isinstance(ligand, mol.ResidueHandle) or isinstance(ligand, mol.ResidueView):
new_residue = _process_ligand_residue(ligand)
extracted_ligands.append(new_residue)
else:
raise RuntimeError("Ligands should be given as Entity or Residue")
new_editor.UpdateICS()
return extracted_ligands
__all__ = ["LigandScorer"]
......@@ -12,18 +12,87 @@ except ImportError:
class TestLigandScoring(unittest.TestCase):
def test_extract_ligands(self):
def test_extract_ligands_mmCIF(self):
"""Test that we can extract ligands from mmCIF files.
"""
trg = io.LoadMMCIF(os.path.join('testfiles', "1r8q.cif.gz"))
mdl = io.LoadMMCIF(os.path.join('testfiles', "P84080_model_02.cif.gz"))
trg, trg_seqres = io.LoadMMCIF(os.path.join('testfiles', "1r8q.cif.gz"), seqres=True)
mdl, mdl_seqres = io.LoadMMCIF(os.path.join('testfiles', "P84080_model_02.cif.gz"), seqres=True)
sc = LigandScorer(mdl, trg, None, None)
assert len(sc.target_ligands) == 7
assert len(sc.model_ligands) == 1
def test_init_given_ligands(self):
"""Test that we can instantiate the scorer with ligands contained in
the target and model entity and given in a list.
"""
trg, trg_seqres = io.LoadMMCIF(os.path.join('testfiles', "1r8q.cif.gz"), seqres=True)
mdl, mdl_seqres = io.LoadMMCIF(os.path.join('testfiles', "P84080_model_02.cif.gz"), seqres=True)
# Pass entity views
trg_lig = [trg.Select("rname=MG"), trg.Select("rname=G3D")]
mdl_lig = [mdl.Select("rname=G3D")]
sc = LigandScorer(mdl, trg, mdl_lig, trg_lig)
assert len(sc.target_ligands) == 4
assert len(sc.model_ligands) == 1
# Ensure the residues are not copied
assert len(sc._target.Select("rname=MG").residues) == 2
assert len(sc._target.Select("rname=G3D").residues) == 2
assert len(sc._model.Select("rname=G3D").residues) == 1
# Pass residue handles
trg_lig = [trg.FindResidue("F", 1), trg.FindResidue("H", 1)]
mdl_lig = [mdl.FindResidue("L_2", 1)]
sc = LigandScorer(mdl, trg, mdl_lig, trg_lig)
assert len(sc.target_ligands) == 2
assert len(sc.model_ligands) == 1
# Ensure the residues are not copied
assert len(sc._target.Select("rname=ZN").residues) == 1
assert len(sc._target.Select("rname=G3D").residues) == 2
assert len(sc._model.Select("rname=G3D").residues) == 1
def test_init_sdf_ligands(self):
"""Test that we can instantiate the scorer with ligands from separate SDF files.
In order to setup the ligand SDF files, the following code was used:
for prefix in [os.path.join('testfiles', x) for x in ["1r8q", "P84080_model_02"]]:
trg = io.LoadMMCIF("%s.cif.gz" % prefix)
trg_prot = trg.Select("protein=True")
io.SavePDB(trg_prot, "%s_protein.pdb.gz" % prefix)
lig_num = 0
for chain in trg.chains:
if chain.chain_type == mol.ChainType.CHAINTYPE_NON_POLY:
lig_sel = trg.Select("cname=%s" % chain.name)
lig_ent = mol.CreateEntityFromView(lig_sel, False)
io.SaveEntity(lig_ent, "%s_ligand_%d.sdf" % (prefix, lig_num))
lig_num += 1
"""
mdl = io.LoadPDB(os.path.join('testfiles', "P84080_model_02_nolig.pdb"))
mdl_ligs = [io.LoadEntity(os.path.join('testfiles', "P84080_model_02_ligand_0.sdf"))]
trg = io.LoadPDB(os.path.join('testfiles', "1r8q_protein.pdb.gz"))
trg_ligs = [io.LoadEntity(os.path.join('testfiles', "1r8q_ligand_%d.sdf" % i)) for i in range(7)]
# Pass entities
sc = LigandScorer(mdl, trg, mdl_ligs, trg_ligs)
assert len(sc.target_ligands) == 7
assert len(sc.model_ligands) == 1
# Pass residues
mdl_ligs_res = [mdl_ligs[0].residues[0]]
trg_ligs_res = [res for ent in trg_ligs for res in ent.residues]
sc = LigandScorer(mdl, trg, mdl_ligs_res, trg_ligs_res)
assert len(sc.target_ligands) == 7
assert len(sc.model_ligands) == 1
if __name__ == "__main__":
from ost import testutils
......
File added
E
1 0 0 0 0 0 999 V2000
4.5270 11.5730 44.1300 Mg 0 0 0 0 0 0
M END
$$$$
F
32 34 0 0 0 0 999 V2000
6.0890 14.2770 44.9550 P 0 0 0 0 0 0
6.3660 15.4410 44.0120 O 0 0 0 0 0 0
4.8710 13.3430 44.4850 O 0 0 0 0 0 0
7.2970 13.3450 45.2240 O 0 0 0 0 0 0
4.6000 14.6680 47.4710 P 0 0 0 0 0 0
5.8060 14.9400 46.4770 O 0 0 0 0 0 0
3.4170 15.3790 47.0580 O 0 0 0 0 0 0
4.6930 13.1630 47.7580 O 0 0 0 0 0 0
5.1190 15.5360 48.5240 O 0 0 0 0 0 0
6.3360 15.3620 49.2550 C 0 0 0 0 0 0
6.1870 15.6390 50.8530 C 0 0 0 0 0 0
6.1480 17.1020 50.9260 O 0 0 0 0 0 0
4.8840 15.1440 51.4770 C 0 0 0 0 0 0
5.2640 15.0240 52.9100 O 0 0 0 0 0 0
3.9630 16.3040 51.3200 C 0 0 0 0 0 0
3.0100 16.3290 52.3850 O 0 0 0 0 0 0
4.9620 17.4510 51.5470 C 0 0 0 0 0 0
4.3820 18.6500 50.9260 N 0 0 0 0 0 0
3.7890 18.7210 49.5940 C 0 0 0 0 0 0
3.5080 20.0710 49.5190 N 0 0 0 0 0 0
3.8570 20.7430 50.5990 C 0 0 0 0 0 0
3.7710 22.0530 50.9790 C 0 0 0 0 0 0
3.2510 23.0650 50.2990 O 0 0 0 0 0 0
4.2440 22.4150 52.2000 N 0 0 0 0 0 0
4.8280 21.5290 53.0330 C 0 0 0 0 0 0
5.2490 22.0020 54.2110 N 0 0 0 0 0 0
4.9190 20.2870 52.6560 N 0 0 0 0 0 0
4.3880 19.8660 51.4870 C 0 0 0 0 0 0
5.5400 13.5630 53.4710 P 0 0 0 0 0 0
6.5290 12.6450 52.7970 O 0 0 0 0 0 0
4.0430 13.0550 53.5020 O 0 0 0 0 0 0
5.8850 13.9290 54.9700 O 0 0 0 0 0 0
1 2 2 0 0 0
1 3 1 0 0 0
1 4 1 0 0 0
1 6 1 0 0 0
5 6 1 0 0 0
5 7 2 0 0 0
5 8 1 0 0 0
5 9 1 0 0 0
9 10 1 0 0 0
10 11 1 0 0 0
11 12 1 0 0 0
11 13 1 0 0 0
12 17 1 0 0 0
13 14 1 0 0 0
13 15 1 0 0 0
14 29 1 0 0 0
15 16 1 0 0 0
15 17 1 0 0 0
17 18 1 0 0 0
18 19 1 0 0 0
18 28 1 0 0 0
19 20 2 0 0 0
20 21 1 0 0 0
21 22 1 0 0 0
21 28 2 0 0 0
22 23 2 0 0 0
22 24 1 0 0 0
24 25 1 0 0 0
25 26 1 0 0 0
25 27 2 0 0 0
27 28 1 0 0 0
29 30 1 0 0 0
29 31 1 0 0 0
29 32 2 0 0 0
M END
$$$$
G
20 21 0 0 0 0 999 V2000
10.0910 6.8570 32.0840 O 0 0 0 0 0 0
8.7250 7.2320 31.9100 C 0 0 0 0 0 0
7.9640 6.1570 31.2310 C 0 0 0 0 0 0
8.0890 7.2920 33.3370 C 0 0 0 0 0 0
6.5380 7.0670 33.0360 C 0 0 0 0 0 0
6.5060 6.6790 31.5660 C 0 0 0 0 0 0
5.5020 5.5280 31.3330 C 0 0 0 0 0 0
4.5110 5.6510 30.3590 C 0 0 0 0 0 0
3.5790 4.4910 30.1500 C 0 0 0 0 0 0
2.0900 4.8720 30.6080 C 0 0 0 0 0 0
1.4940 6.0920 29.8490 C 0 0 0 0 0 0
0.7970 7.0430 30.8690 C 0 0 0 0 0 0
0.1650 8.0980 29.9060 C 0 0 0 0 0 0
1.9860 7.7240 31.3940 O 0 0 0 0 0 0
1.9720 8.1170 32.6590 C 0 0 0 0 0 0
0.8730 8.3170 33.1860 O 0 0 0 0 0 0
3.1900 8.4720 33.3190 C 0 0 0 0 0 0
4.3400 8.2000 32.5760 C 0 0 0 0 0 0
5.7730 8.4290 33.1600 C 0 0 0 0 0 0
5.7460 8.8330 34.5550 O 0 0 0 0 0 0
1 2 1 0 0 0
2 3 1 0 0 0
2 4 1 0 0 0
3 6 1 0 0 0
4 5 1 0 0 0
5 6 1 0 0 0
5 19 1 0 0 0
6 7 1 0 0 0
7 8 2 0 0 0
8 9 1 0 0 0
9 10 1 0 0 0
10 11 1 0 0 0
11 12 1 0 0 0
12 13 1 0 0 0
12 14 1 0 0 0
14 15 1 0 0 0
15 16 2 0 0 0
15 17 1 0 0 0
17 18 2 0 0 0
18 19 1 0 0 0
19 20 1 0 0 0
M END
$$$$
H
1 0 0 0 0 0 999 V2000
26.8150 -11.4220 38.7710 Zn 0 0 0 0 0 0
M END
$$$$
I
1 0 0 0 0 0 999 V2000
-21.5950 -13.5060 15.1510 Mg 0 0 0 0 0 0
M END
$$$$
J
32 34 0 0 0 0 999 V2000
-23.1740 -14.1460 12.3820 P 0 0 0 0 0 0
-23.4660 -13.0980 11.3250 O 0 0 0 0 0 0
-21.9370 -13.7610 13.2140 O 0 0 0 0 0 0
-24.2720 -14.2880 13.2850 O 0 0 0 0 0 0
-21.7220 -16.5480 11.7940 P 0 0 0 0 0 0
-22.9260 -15.5640 11.6830 O 0 0 0 0 0 0
-20.4390 -16.1380 11.2020 O 0 0 0 0 0 0
-21.8020 -16.9290 13.2360 O 0 0 0 0 0 0
-22.2920 -17.7500 10.8800 O 0 0 0 0 0 0
-23.6090 -18.3780 11.1140 C 0 0 0 0 0 0
-23.4540 -19.8880 10.6650 C 0 0 0 0 0 0
-23.2360 -19.8490 9.2040 O 0 0 0 0 0 0
-22.1550 -20.5500 11.2730 C 0 0 0 0 0 0
-22.5000 -21.9820 11.3530 O 0 0 0 0 0 0
-21.2270 -20.3950 10.1210 C 0 0 0 0 0 0
-20.2380 -21.4710 10.1250 O 0 0 0 0 0 0
-22.1580 -20.6460 8.9500 C 0 0 0 0 0 0
-21.5870 -19.9630 7.7860 N 0 0 0 0 0 0
-20.9840 -18.6020 7.7160 C 0 0 0 0 0 0
-20.5470 -18.4640 6.3900 N 0 0 0 0 0 0
-20.9570 -19.5440 5.6510 C 0 0 0 0 0 0
-20.9110 -19.8230 4.3160 C 0 0 0 0 0 0
-20.2950 -19.1290 3.4000 O 0 0 0 0 0 0
-21.3850 -21.0580 3.9190 N 0 0 0 0 0 0
-21.9950 -21.8750 4.7550 C 0 0 0 0 0 0
-22.4840 -23.0410 4.2810 N 0 0 0 0 0 0
-22.0800 -21.6000 6.0720 N 0 0 0 0 0 0
-21.5640 -20.4530 6.5080 C 0 0 0 0 0 0
-22.5370 -22.8950 12.7330 P 0 0 0 0 0 0
-22.9540 -22.0210 13.8390 O 0 0 0 0 0 0
-21.0630 -23.4500 12.5800 O 0 0 0 0 0 0
-23.4580 -24.2110 12.3270 O 0 0 0 0 0 0
1 2 2 0 0 0
1 3 1 0 0 0
1 4 1 0 0 0
1 6 1 0 0 0
5 6 1 0 0 0
5 7 2 0 0 0
5 8 1 0 0 0
5 9 1 0 0 0
9 10 1 0 0 0
10 11 1 0 0 0
11 12 1 0 0 0
11 13 1 0 0 0
12 17 1 0 0 0
13 14 1 0 0 0
13 15 1 0 0 0
14 29 1 0 0 0
15 16 1 0 0 0
15 17 1 0 0 0
17 18 1 0 0 0
18 19 1 0 0 0
18 28 1 0 0 0
19 20 2 0 0 0
20 21 1 0 0 0
21 22 1 0 0 0
21 28 2 0 0 0
22 23 2 0 0 0
22 24 1 0 0 0
24 25 1 0 0 0
25 26 1 0 0 0
25 27 2 0 0 0
27 28 1 0 0 0
29 30 1 0 0 0
29 31 1 0 0 0
29 32 2 0 0 0
M END
$$$$
K
20 21 0 0 0 0 999 V2000
-26.1390 -2.3340 21.1660 O 0 0 0 0 0 0
-24.7660 -2.1610 20.8000 C 0 0 0 0 0 0
-23.8900 -1.7730 22.0280 C 0 0 0 0 0 0
-24.2470 -3.5020 20.5160 C 0 0 0 0 0 0
-22.6890 -3.3770 20.6900 C 0 0 0 0 0 0
-22.5330 -1.9520 21.4140 C 0 0 0 0 0 0
-21.5030 -1.9630 22.6040 C 0 0 0 0 0 0
-20.4460 -1.0760 22.5660 C 0 0 0 0 0 0
-19.4470 -1.0110 23.6720 C 0 0 0 0 0 0
-18.0850 -1.5850 23.2120 C 0 0 0 0 0 0
-17.4350 -0.6570 22.1680 C 0 0 0 0 0 0
-16.8120 -1.4950 20.9990 C 0 0 0 0 0 0
-16.0990 -0.5320 20.0270 C 0 0 0 0 0 0
-18.0710 -1.8620 20.2320 O 0 0 0 0 0 0
-18.1530 -3.0360 19.5900 C 0 0 0 0 0 0
-17.1390 -3.6720 19.3760 O 0 0 0 0 0 0
-19.4090 -3.5530 19.2270 C 0 0 0 0 0 0
-20.5080 -2.7620 19.6190 C 0 0 0 0 0 0
-21.9740 -3.2770 19.3140 C 0 0 0 0 0 0
-21.9570 -4.5150 18.6220 O 0 0 0 0 0 0
1 2 1 0 0 0
2 3 1 0 0 0
2 4 1 0 0 0
3 6 1 0 0 0
4 5 1 0 0 0
5 6 1 0 0 0
5 19 1 0 0 0
6 7 1 0 0 0
7 8 2 0 0 0
8 9 1 0 0 0
9 10 1 0 0 0
10 11 1 0 0 0
11 12 1 0 0 0
12 13 1 0 0 0
12 14 1 0 0 0
14 15 1 0 0 0
15 16 2 0 0 0
15 17 1 0 0 0
17 18 2 0 0 0
18 19 1 0 0 0
19 20 1 0 0 0
M END
$$$$
File added
File added
Source diff could not be displayed: it is too large. Options to address this: view the blob.
This diff is collapsed.
L_2
32 34 0 0 0 0 999 V2000
6.0890 14.2770 44.9550 P 0 0 0 0 0 0
6.3660 15.4410 44.0120 O 0 0 0 0 0 0
4.8710 13.3430 44.4850 O 0 0 0 0 0 0
7.2970 13.3450 45.2240 O 0 0 0 0 0 0
4.6000 14.6680 47.4710 P 0 0 0 0 0 0
5.8060 14.9400 46.4770 O 0 0 0 0 0 0
3.4170 15.3790 47.0580 O 0 0 0 0 0 0
4.6930 13.1630 47.7580 O 0 0 0 0 0 0
5.1190 15.5360 48.5240 O 0 0 0 0 0 0
6.3360 15.3620 49.2550 C 0 0 0 0 0 0
6.1870 15.6390 50.8530 C 0 0 0 0 0 0
6.1480 17.1020 50.9260 O 0 0 0 0 0 0
4.8840 15.1440 51.4770 C 0 0 0 0 0 0
5.2640 15.0240 52.9100 O 0 0 0 0 0 0
3.9630 16.3040 51.3200 C 0 0 0 0 0 0
3.0100 16.3290 52.3850 O 0 0 0 0 0 0
4.9620 17.4510 51.5470 C 0 0 0 0 0 0
4.3820 18.6500 50.9260 N 0 0 0 0 0 0
3.7890 18.7210 49.5940 C 0 0 0 0 0 0
3.5080 20.0710 49.5190 N 0 0 0 0 0 0
3.8570 20.7430 50.5990 C 0 0 0 0 0 0
3.7710 22.0530 50.9790 C 0 0 0 0 0 0
3.2510 23.0650 50.2990 O 0 0 0 0 0 0
4.2440 22.4150 52.2000 N 0 0 0 0 0 0
4.8280 21.5290 53.0330 C 0 0 0 0 0 0
5.2490 22.0020 54.2110 N 0 0 0 0 0 0
4.9190 20.2870 52.6560 N 0 0 0 0 0 0
4.3880 19.8660 51.4870 C 0 0 0 0 0 0
5.5400 13.5630 53.4710 P 0 0 0 0 0 0
6.5290 12.6450 52.7970 O 0 0 0 0 0 0
4.0430 13.0550 53.5020 O 0 0 0 0 0 0
5.8850 13.9290 54.9700 O 0 0 0 0 0 0
1 2 2 0 0 0
1 3 1 0 0 0
1 4 1 0 0 0
1 6 1 0 0 0
5 6 1 0 0 0
5 7 2 0 0 0
5 8 1 0 0 0
5 9 1 0 0 0
9 10 1 0 0 0
10 11 1 0 0 0
11 12 1 0 0 0
11 13 1 0 0 0
12 17 1 0 0 0
13 14 1 0 0 0
13 15 1 0 0 0
14 29 1 0 0 0
15 16 1 0 0 0
15 17 1 0 0 0
17 18 1 0 0 0
18 19 1 0 0 0
18 28 1 0 0 0
19 20 2 0 0 0
20 21 1 0 0 0
21 22 1 0 0 0
21 28 2 0 0 0
22 23 2 0 0 0
22 24 1 0 0 0
24 25 1 0 0 0
25 26 1 0 0 0
25 27 2 0 0 0
27 28 1 0 0 0
29 30 1 0 0 0
29 31 1 0 0 0
29 32 2 0 0 0
M END
$$$$
This diff is collapsed.
File added
File added
This diff is collapsed.
File added
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment