biomechzoo 0.1.1__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 biomechzoo might be problematic. Click here for more details.
- biomechzoo/__init__.py +5 -0
- biomechzoo/__main__.py +6 -0
- biomechzoo/biomech_ops/continuous_relative_phase_data.py +31 -0
- biomechzoo/biomech_ops/continuous_relative_phase_line.py +36 -0
- biomechzoo/biomech_ops/filter_data.py +56 -0
- biomechzoo/biomech_ops/filter_line.py +88 -0
- biomechzoo/biomech_ops/normalize_data.py +35 -0
- biomechzoo/biomech_ops/normalize_line.py +27 -0
- biomechzoo/biomech_ops/phase_angle_data.py +39 -0
- biomechzoo/biomech_ops/phase_angle_line.py +48 -0
- biomechzoo/biomechzoo.py +349 -0
- biomechzoo/conversion/__init__.py +0 -0
- biomechzoo/conversion/c3d2zoo_data.py +65 -0
- biomechzoo/conversion/csv2zoo_data.py +78 -0
- biomechzoo/conversion/mvnx2zoo_data.py +71 -0
- biomechzoo/conversion/opencap2zoo_data.py +23 -0
- biomechzoo/mvn/load_mvnx.py +514 -0
- biomechzoo/mvn/main_mvnx.py +75 -0
- biomechzoo/mvn/mvn.py +232 -0
- biomechzoo/mvn/mvnx_file_accessor.py +463 -0
- biomechzoo/processing/add_channel_data.py +71 -0
- biomechzoo/processing/addchannel_data.py +71 -0
- biomechzoo/processing/addevent_data.py +46 -0
- biomechzoo/processing/explodechannel_data.py +46 -0
- biomechzoo/processing/partition_data.py +51 -0
- biomechzoo/processing/removechannel_data.py +36 -0
- biomechzoo/processing/renamechannel_data.py +79 -0
- biomechzoo/processing/renameevent_data.py +68 -0
- biomechzoo/processing/split_trial_by_gait_cycle.py +52 -0
- biomechzoo/utils/batchdisp.py +21 -0
- biomechzoo/utils/compute_sampling_rate_from_time.py +25 -0
- biomechzoo/utils/engine.py +68 -0
- biomechzoo/utils/findfield.py +11 -0
- biomechzoo/utils/get_split_events.py +33 -0
- biomechzoo/utils/split_trial.py +23 -0
- biomechzoo/utils/zload.py +46 -0
- biomechzoo/utils/zplot.py +61 -0
- biomechzoo/utils/zsave.py +50 -0
- biomechzoo-0.1.1.dist-info/METADATA +48 -0
- biomechzoo-0.1.1.dist-info/RECORD +44 -0
- biomechzoo-0.1.1.dist-info/WHEEL +5 -0
- biomechzoo-0.1.1.dist-info/entry_points.txt +2 -0
- biomechzoo-0.1.1.dist-info/licenses/LICENSE +21 -0
- biomechzoo-0.1.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
def split_trial(data, start_event_indx, end_event_indx):
|
|
2
|
+
# todo check index problem compared to matlab start at 0 or 1
|
|
3
|
+
data_new = data.copy()
|
|
4
|
+
|
|
5
|
+
for key, value in data_new.items():
|
|
6
|
+
if key == 'zoosystem':
|
|
7
|
+
continue
|
|
8
|
+
|
|
9
|
+
# Slice the line data
|
|
10
|
+
data_new[key]['line'] = value['line'][start_event_indx:end_event_indx]
|
|
11
|
+
|
|
12
|
+
# Update events if present
|
|
13
|
+
if 'event' in value:
|
|
14
|
+
new_events = {}
|
|
15
|
+
for evt_name, evt_val in value['event'].items():
|
|
16
|
+
event_frame = evt_val[0]
|
|
17
|
+
# Check if event falls within the new window
|
|
18
|
+
if start_event_indx <= event_frame < end_event_indx:
|
|
19
|
+
# Adjust index relative to new start
|
|
20
|
+
new_events[evt_name] = [event_frame - start_event_indx, 0, 0]
|
|
21
|
+
data_new[key]['event'] = new_events
|
|
22
|
+
|
|
23
|
+
return data_new
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
from scipy.io import loadmat
|
|
2
|
+
import os
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def zload(filepath):
|
|
6
|
+
if not filepath.endswith('.zoo'):
|
|
7
|
+
raise ValueError(f"{filepath} is not a .zoo file")
|
|
8
|
+
|
|
9
|
+
if not os.path.exists(filepath):
|
|
10
|
+
raise FileNotFoundError(f"File not found: {filepath}")
|
|
11
|
+
|
|
12
|
+
mat_data = loadmat(filepath, struct_as_record=False, squeeze_me=True)
|
|
13
|
+
|
|
14
|
+
# Remove default MATLAB metadata fields
|
|
15
|
+
mat_data = {k: v for k, v in mat_data.items() if not k.startswith('__')}
|
|
16
|
+
|
|
17
|
+
# Convert MATLAB structs to Python dicts (recursively)
|
|
18
|
+
def mat_struct_to_dict(obj):
|
|
19
|
+
if isinstance(obj, dict):
|
|
20
|
+
return {k: mat_struct_to_dict(v) for k, v in obj.items()}
|
|
21
|
+
elif hasattr(obj, '_fieldnames'):
|
|
22
|
+
return {field: mat_struct_to_dict(getattr(obj, field)) for field in obj._fieldnames}
|
|
23
|
+
elif isinstance(obj, list):
|
|
24
|
+
return [mat_struct_to_dict(item) for item in obj]
|
|
25
|
+
else:
|
|
26
|
+
return obj
|
|
27
|
+
data = {k: mat_struct_to_dict(v) for k, v in mat_data.items()}
|
|
28
|
+
|
|
29
|
+
if 'data' in data:
|
|
30
|
+
data = data['data']
|
|
31
|
+
|
|
32
|
+
return data
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
if __name__ == '__main__':
|
|
36
|
+
""" testing: load a single zoo file from the other subfolder in data"""
|
|
37
|
+
# -------TESTING--------
|
|
38
|
+
current_dir = os.path.dirname(os.path.abspath(__file__))
|
|
39
|
+
project_root = os.path.dirname(current_dir)
|
|
40
|
+
fl = os.path.join(project_root, 'data', 'other', 'HC030A05.zoo')
|
|
41
|
+
data = zload(fl)
|
|
42
|
+
|
|
43
|
+
channels = [k for k in data.keys()]
|
|
44
|
+
print('{} channels found'.format(len(channels)))
|
|
45
|
+
for ch in channels:
|
|
46
|
+
print({ch})
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import matplotlib.pyplot as plt
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def zplot(data, ch, xlabel='frames', ylabel='angles (deg)'):
|
|
5
|
+
"""
|
|
6
|
+
Plot a single channel of a zoo file, along with any existing events.
|
|
7
|
+
|
|
8
|
+
Parameters
|
|
9
|
+
----------
|
|
10
|
+
data : dict
|
|
11
|
+
Loaded zoo file.
|
|
12
|
+
ch : str
|
|
13
|
+
Name of the channel to plot, e.g., 'RkneeAngles'.
|
|
14
|
+
xlabel : str
|
|
15
|
+
Label for x-axis. Default is 'frames'.
|
|
16
|
+
ylabel : str
|
|
17
|
+
Label for y-axis. Default is 'angles (deg)'.
|
|
18
|
+
|
|
19
|
+
Returns
|
|
20
|
+
-------
|
|
21
|
+
None
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
if ch not in data:
|
|
25
|
+
raise KeyError(f"Channel '{ch}' not found in data.")
|
|
26
|
+
|
|
27
|
+
y = data[ch]['line']
|
|
28
|
+
x = range(len(y))
|
|
29
|
+
|
|
30
|
+
plt.figure(figsize=(10, 4))
|
|
31
|
+
plt.plot(x, y, label='Signal', linewidth=2)
|
|
32
|
+
plt.title(ch)
|
|
33
|
+
plt.xlabel(xlabel)
|
|
34
|
+
plt.ylabel(ylabel)
|
|
35
|
+
plt.grid(True)
|
|
36
|
+
|
|
37
|
+
# Plot events if available
|
|
38
|
+
events = data[ch].get('event', {})
|
|
39
|
+
for name, coords in events.items():
|
|
40
|
+
evtx, evty = coords[0], coords[1]
|
|
41
|
+
plt.plot(evtx, evty, 'ro')
|
|
42
|
+
plt.text(evtx, evty, name, fontsize=8, color='red', ha='left', va='bottom')
|
|
43
|
+
|
|
44
|
+
plt.tight_layout()
|
|
45
|
+
plt.show()
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
if __name__ == '__main__':
|
|
49
|
+
# -------TESTING--------
|
|
50
|
+
import os
|
|
51
|
+
from biomechzoo.utils.zload import zload
|
|
52
|
+
|
|
53
|
+
# get path to sample zoo file
|
|
54
|
+
current_dir = os.path.dirname(os.path.abspath(__file__))
|
|
55
|
+
project_root = os.path.dirname(current_dir)
|
|
56
|
+
fl = os.path.join(project_root, 'data', 'other', 'HC030A05.zoo')
|
|
57
|
+
|
|
58
|
+
# load zoo file
|
|
59
|
+
data = zload(fl)
|
|
60
|
+
ch = 'SACR'
|
|
61
|
+
zplot(data, ch)
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
from scipy.io import savemat
|
|
2
|
+
import inspect
|
|
3
|
+
import os
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def zsave(fl, data, inplace=True, out_folder=None, root_folder=None):
|
|
7
|
+
"""
|
|
8
|
+
Save zoo data to .zoo file (MAT format)
|
|
9
|
+
|
|
10
|
+
Arguments:
|
|
11
|
+
fl (str): Full path to original .zoo file
|
|
12
|
+
data (dict): Zoo data to save
|
|
13
|
+
inplace (bool): Whether to overwrite original file
|
|
14
|
+
out_folder (str or None): If not inplace, output folder name (relative to root_folder or file location)
|
|
15
|
+
root_folder (str or None): Optional base directory for saving when inplace=False
|
|
16
|
+
"""
|
|
17
|
+
# Get caller function name for logging
|
|
18
|
+
caller_name = inspect.stack()[1].function
|
|
19
|
+
|
|
20
|
+
# Initialize zoosystem and processing history
|
|
21
|
+
zoosystem = data.get('zoosystem', {})
|
|
22
|
+
processing = zoosystem.get('Processing', [])
|
|
23
|
+
if not isinstance(processing, list):
|
|
24
|
+
processing = [processing]
|
|
25
|
+
processing.append(caller_name)
|
|
26
|
+
zoosystem['Processing'] = processing
|
|
27
|
+
data['zoosystem'] = zoosystem
|
|
28
|
+
|
|
29
|
+
# Determine save path
|
|
30
|
+
if inplace:
|
|
31
|
+
save_path = fl
|
|
32
|
+
else:
|
|
33
|
+
filename = os.path.basename(fl)
|
|
34
|
+
if out_folder is None:
|
|
35
|
+
out_folder = 'processed'
|
|
36
|
+
|
|
37
|
+
if root_folder is None:
|
|
38
|
+
root_folder = os.path.dirname(fl)
|
|
39
|
+
|
|
40
|
+
root_path = os.path.dirname(root_folder)
|
|
41
|
+
in_folder = os.path.basename(root_folder)
|
|
42
|
+
out_dir = os.path.join(root_path, out_folder)
|
|
43
|
+
os.makedirs(out_dir, exist_ok=True)
|
|
44
|
+
fl_new = fl.replace(in_folder, out_folder)
|
|
45
|
+
save_folder = os.path.dirname(fl_new)
|
|
46
|
+
os.makedirs(save_folder, exist_ok=True)
|
|
47
|
+
|
|
48
|
+
# Save the .zoo file
|
|
49
|
+
savemat(fl_new, data)
|
|
50
|
+
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: biomechzoo
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: Python implementation of the biomechZoo Matlab toolbox
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
Project-URL: Homepage, https://github.com/mcgillmotionlab/biomechzoo
|
|
7
|
+
Requires-Python: >=3.13
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Requires-Dist: ezc3d>=1.5.19
|
|
11
|
+
Requires-Dist: matplotlib>=3.10.6
|
|
12
|
+
Requires-Dist: numpy>=2.3.3
|
|
13
|
+
Requires-Dist: pandas>=2.3.2
|
|
14
|
+
Requires-Dist: scipy>=1.16.2
|
|
15
|
+
Dynamic: license-file
|
|
16
|
+
|
|
17
|
+
# Repository for the Python version of biomechZoo
|
|
18
|
+
This is a development version of the biomechzoo toolbox for python. To use biomechzoo
|
|
19
|
+
as a packagage alongside your code, follow the "How to install" instructions below
|
|
20
|
+
|
|
21
|
+
## How to install
|
|
22
|
+
- make sure the local version of your code sits at the same level as biomechzoo.
|
|
23
|
+
e.g.
|
|
24
|
+
code_root/
|
|
25
|
+
code_root/biomechzoo/ ← the repo with the actual package
|
|
26
|
+
code_root/student_code/ ← where your scripts or notebooks live
|
|
27
|
+
|
|
28
|
+
- open terminal or command window
|
|
29
|
+
- create an environment for your research project: ``conda create -n name python=3.13 -c conda-forge``, where name is of your choice
|
|
30
|
+
- activate your new environment: ``conda activate name``
|
|
31
|
+
- navigate to parent directory where biomechzoo was cloned. e.g. ``code_root``
|
|
32
|
+
- install biomechzoo: ``pip install -e biomechzoo``
|
|
33
|
+
- install additional requirements: ``pip install -r biomechzoo/pip_requirements.txt``
|
|
34
|
+
|
|
35
|
+
## Updates (not tested)
|
|
36
|
+
- If updates are made to biomechzoo, simply pull the latest version
|
|
37
|
+
from github, you won't need to reinstall (unless there are new dependencies)
|
|
38
|
+
|
|
39
|
+
## Usage notes
|
|
40
|
+
- To use biomechzoo in your project, you will need to import biomechzoo as:
|
|
41
|
+
``from biomechzoo.biomechzoo import BiomechZoo``
|
|
42
|
+
- Then, you can create an object that is an instance of the BimechZoo class as:
|
|
43
|
+
``bmech = BiomechZoo(fld)`` where ``fld`` is the path to your data
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
# opencap users
|
|
47
|
+
- opencap users should pre-process their data using ``https://github.com/stanfordnmbl/opencap-processing``
|
|
48
|
+
- processed data could be saved to csv using pandas and then imported to biomechzoo using csv2zoo (not yet functional)
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
biomechzoo/__init__.py,sha256=IXj0mVJCHQ06awsQVJo0CCRDbplqP6dxZ1MQ6GUuCPw,107
|
|
2
|
+
biomechzoo/__main__.py,sha256=hSMHN1Rxn2367fSGTLHoOQ4_pocZw0IWI7HFxl-74oY,88
|
|
3
|
+
biomechzoo/biomechzoo.py,sha256=bmP81dLlYPE2NnZ76xK-MVlVyDuKKU08OF58dtzieps,15433
|
|
4
|
+
biomechzoo/biomech_ops/continuous_relative_phase_data.py,sha256=RePbt6zyOI1iv74CWhxSrunIokTFYVfFmFnoW51781E,1300
|
|
5
|
+
biomechzoo/biomech_ops/continuous_relative_phase_line.py,sha256=Fa1LFRuPlmGPLQLvln6HVnJy3zMSm9z5YeooHmTu0lc,1365
|
|
6
|
+
biomechzoo/biomech_ops/filter_data.py,sha256=LZSlemUfbBTrqbo7miFubgTf9R4pr1kEgdmvljmNWdQ,1742
|
|
7
|
+
biomechzoo/biomech_ops/filter_line.py,sha256=BuUFALIkmdFhmVocFaZ3aczy_efh2CY_qX9-5CoQZr0,2716
|
|
8
|
+
biomechzoo/biomech_ops/normalize_data.py,sha256=gpoUh6EpxpCprBdrSjmZ4UsAWgonJgD41XUJWD8Yo9Y,1299
|
|
9
|
+
biomechzoo/biomech_ops/normalize_line.py,sha256=KUE8gEkIolA-VDFCdUuaskk-waO8jjJ20ZMZaS8Qha8,854
|
|
10
|
+
biomechzoo/biomech_ops/phase_angle_data.py,sha256=_ekUBW2v3iC4UawcDL38ZZLYJmQsAmyqA61Q6_AMtmQ,1435
|
|
11
|
+
biomechzoo/biomech_ops/phase_angle_line.py,sha256=p6osB17_3QQSyKLNojuc6nYhv-k0K6EUUH75EXu8ifc,1391
|
|
12
|
+
biomechzoo/conversion/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
13
|
+
biomechzoo/conversion/c3d2zoo_data.py,sha256=kmiLQHglchSHty6DrMEl5yTOUi3U4Ai5nHoSGvbF6k8,2660
|
|
14
|
+
biomechzoo/conversion/csv2zoo_data.py,sha256=-c4CXxcKd70HJWWgHRztOxOckvA1XgIDzo8EhgJhcKE,2185
|
|
15
|
+
biomechzoo/conversion/mvnx2zoo_data.py,sha256=ID1X_VtzFQrgqNpTMd-_DJ-3mVUIW0t9qwCsI5VJI-M,2861
|
|
16
|
+
biomechzoo/conversion/opencap2zoo_data.py,sha256=n4bLsrJI0wTSzG5bgJcmxj1dp2plnUKFNRzcTIbmV1o,608
|
|
17
|
+
biomechzoo/mvn/load_mvnx.py,sha256=B4VGuidQ-5G_5E1t5vpU51Nb_Lu85_EOS_FmGZYjfX8,22499
|
|
18
|
+
biomechzoo/mvn/main_mvnx.py,sha256=e1LasJQ9icyzjWnRCEcAWQq_-L13-mIzf7PzYA3QYDg,2394
|
|
19
|
+
biomechzoo/mvn/mvn.py,sha256=I62ljRo0I0ajc6KLW8J4SmXL_M-rHerHinD_UaFzS8U,7537
|
|
20
|
+
biomechzoo/mvn/mvnx_file_accessor.py,sha256=kLMg3mwpqqRyqFycoaPkI6ejKJzxBnPK9iiIYl-LmY8,20097
|
|
21
|
+
biomechzoo/processing/add_channel_data.py,sha256=U1xLLBSnyJeeDWzgmHSxOz1hyguzuuDXxQCQ8IFoZkw,1955
|
|
22
|
+
biomechzoo/processing/addchannel_data.py,sha256=rmnnlMRVkoMlQCR-nRg1jjh-hzMDt37Sx9fAmocrpqA,1953
|
|
23
|
+
biomechzoo/processing/addevent_data.py,sha256=DyTfvjOWZIlsWfnT6XDwvsU1jOzSDf4HhLa1TaKIhwI,1325
|
|
24
|
+
biomechzoo/processing/explodechannel_data.py,sha256=t4gC2ZQD4baECexj0hQYDzOnXV5GHb-z068mtZzh0DQ,1470
|
|
25
|
+
biomechzoo/processing/partition_data.py,sha256=8pMGRVXzYbPa4tuB7K3OOjUCnROpXb2v1gcRRNAbSig,1704
|
|
26
|
+
biomechzoo/processing/removechannel_data.py,sha256=ndZcbWJRDvd7drlahGaq8MseT-rsxiu7pgdMtA1cTlo,1218
|
|
27
|
+
biomechzoo/processing/renamechannel_data.py,sha256=5lEnWJknAwnJYXDlwO6cFe7C8ct5o42tTHW0Y4GeIL4,2210
|
|
28
|
+
biomechzoo/processing/renameevent_data.py,sha256=9w7C_fQOsQ8XbdTr_hrg_iQe51oDczq2Rj7yJLyYG0M,2215
|
|
29
|
+
biomechzoo/processing/split_trial_by_gait_cycle.py,sha256=maMUwumSlFLFc5LHdNdBO9JCoT06aaLbpdp43dgowDA,1684
|
|
30
|
+
biomechzoo/utils/batchdisp.py,sha256=Ke7yeZ4cYQvyf8bmgsiLaRElUeQm49TYIYzAcPWan9s,839
|
|
31
|
+
biomechzoo/utils/compute_sampling_rate_from_time.py,sha256=iyHbN734vYe5bXEoAsHScJN7Qw--2quUgII7judSQDk,579
|
|
32
|
+
biomechzoo/utils/engine.py,sha256=WSZmi6DDZHcdOhgsu2LvmLF-Ftxcjteh9TbKDMZIN5k,3240
|
|
33
|
+
biomechzoo/utils/findfield.py,sha256=i7ewGQOMIiTC06tYFK-JctehHLCippkY9FoXIygx14w,381
|
|
34
|
+
biomechzoo/utils/get_split_events.py,sha256=xNhEuG6Yqsr1bjWIBHLbepfX-fcqcCYIXZzS3eaDDHQ,911
|
|
35
|
+
biomechzoo/utils/split_trial.py,sha256=Fumz_ZukNBNtPauUhCge5EAHkg05dYDhA1_njQw0lHE,886
|
|
36
|
+
biomechzoo/utils/zload.py,sha256=FPT6_-gwaOOqOckjgPRfnKEVKMsmNVIcenmQZF2KOvo,1535
|
|
37
|
+
biomechzoo/utils/zplot.py,sha256=WVA8aCy1Pqy_bo_HXab9AmW-cBd8J8MPX2LAOd6dznU,1512
|
|
38
|
+
biomechzoo/utils/zsave.py,sha256=2DeF6A1R32SnXJXtb8jtPqZAmlSEB0PVi09UGiskzMo,1625
|
|
39
|
+
biomechzoo-0.1.1.dist-info/licenses/LICENSE,sha256=Fsz62nrgRORre3A1wNXUDISaHoostodMvocRPDdXc9w,1076
|
|
40
|
+
biomechzoo-0.1.1.dist-info/METADATA,sha256=mrVsykfuRyZqM15ARHUAX--XOfjzmnMysxVT4HYKtpY,2096
|
|
41
|
+
biomechzoo-0.1.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
42
|
+
biomechzoo-0.1.1.dist-info/entry_points.txt,sha256=VdryUUiwwvx0WZxrgmMrsyfe5Z1jtyaxdXOi0zWHOqk,41
|
|
43
|
+
biomechzoo-0.1.1.dist-info/top_level.txt,sha256=W148kdiK-6L0Nohbw8UALkAzHJvJLAhFDRykuva2WjY,11
|
|
44
|
+
biomechzoo-0.1.1.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) [2025] McGill MOTION Lab
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
biomechzoo
|