ai-simple-engine-transformers 0.0.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.
Files changed (28) hide show
  1. ai_simple_engine_transformers/__init__.py +10 -0
  2. ai_simple_engine_transformers/model_loaders/__init__.py +0 -0
  3. ai_simple_engine_transformers/model_loaders/musicgen/__init__.py +0 -0
  4. ai_simple_engine_transformers/model_loaders/musicgen/base.py +42 -0
  5. ai_simple_engine_transformers/model_loaders/musicgen/loaded_musicgen_model.py +9 -0
  6. ai_simple_engine_transformers/operations/__init__.py +0 -0
  7. ai_simple_engine_transformers/operations/music/__init__.py +3 -0
  8. ai_simple_engine_transformers/operations/music/generate_music.py +76 -0
  9. ai_simple_engine_transformers/plugin.py +18 -0
  10. ai_simple_engine_transformers/providers/__init__.py +6 -0
  11. ai_simple_engine_transformers/providers/data_types_provider.py +18 -0
  12. ai_simple_engine_transformers/providers/model_loaders_provider.py +17 -0
  13. ai_simple_engine_transformers/providers/model_repository_provider.py +18 -0
  14. ai_simple_engine_transformers/providers/operation_provider.py +21 -0
  15. ai_simple_engine_transformers/repositories/__init__.py +0 -0
  16. ai_simple_engine_transformers/repositories/huggingface/__init__.py +0 -0
  17. ai_simple_engine_transformers/repositories/huggingface/huggingface_client.py +23 -0
  18. ai_simple_engine_transformers/repositories/huggingface/huggingface_provider.py +102 -0
  19. ai_simple_engine_transformers/runners/__init__.py +12 -0
  20. ai_simple_engine_transformers/runners/abstract/__init__.py +0 -0
  21. ai_simple_engine_transformers/runners/abstract/musicgen_runner_abstract.py +21 -0
  22. ai_simple_engine_transformers/runners/musicgen_runner.py +41 -0
  23. ai_simple_engine_transformers/types/__init__.py +0 -0
  24. ai_simple_engine_transformers/types/data_type.py +26 -0
  25. ai_simple_engine_transformers-0.0.1.dist-info/METADATA +20 -0
  26. ai_simple_engine_transformers-0.0.1.dist-info/RECORD +28 -0
  27. ai_simple_engine_transformers-0.0.1.dist-info/WHEEL +4 -0
  28. ai_simple_engine_transformers-0.0.1.dist-info/licenses/LICENSE +19 -0
@@ -0,0 +1,10 @@
1
+ """
2
+ The Transformers module of our AI Simple Engine.
3
+ """
4
+
5
+
6
+ """
7
+ TODO: Check these things:
8
+ - Should the 'InstalledModel' have the 'ModelSpec'
9
+ inside so we can access to the 'family' and that (?)
10
+ """
@@ -0,0 +1,42 @@
1
+ from ai_simple_engine_transformers.model_loaders.musicgen.loaded_musicgen_model import LoadedMusicGenModel
2
+ from ai_simple_engine.models.loaded_model import LoadedModel
3
+ from ai_simple_engine.models.loaders.abstract import ModelLoader
4
+ from ai_simple_engine.models.installed_model import InstalledModel
5
+ from ai_simple_engine.device.base import Device
6
+ from transformers import AutoProcessor, MusicgenForConditionalGeneration
7
+
8
+
9
+ class MusicGenLoader(
10
+ ModelLoader
11
+ ):
12
+
13
+ def is_supported(
14
+ self,
15
+ family: str
16
+ ) -> bool:
17
+ return family == 'musicgen'
18
+
19
+ async def load(
20
+ self,
21
+ model: InstalledModel,
22
+ *,
23
+ device: Device
24
+ ) -> LoadedModel[LoadedMusicGenModel]:
25
+ processor = AutoProcessor.from_pretrained(model.path)
26
+ network = MusicgenForConditionalGeneration.from_pretrained(model.path)
27
+
28
+ network.to(device.identifier)
29
+
30
+ return LoadedModel(
31
+ installed_model = model,
32
+ instance = LoadedMusicGenModel(
33
+ processor = processor,
34
+ network = network
35
+ )
36
+ )
37
+
38
+ async def unload(
39
+ self,
40
+ model: LoadedModel
41
+ ) -> None:
42
+ del model
@@ -0,0 +1,9 @@
1
+ from transformers import AutoProcessor, MusicgenForConditionalGeneration
2
+ from dataclasses import dataclass
3
+
4
+
5
+ @dataclass(frozen = True)
6
+ class LoadedMusicGenModel:
7
+
8
+ processor: AutoProcessor
9
+ network: MusicgenForConditionalGeneration
File without changes
@@ -0,0 +1,3 @@
1
+ """
2
+ TODO: Maybe I don't need the folders
3
+ """
@@ -0,0 +1,76 @@
1
+ from ai_simple_engine_transformers.runners.musicgen_runner import MusicGenRunner
2
+ from ai_simple_engine_transformers.types.data_type import RESOURCE, AUDIO
3
+ from ai_simple_engine.graph.operation.base import Operation
4
+ from ai_simple_engine.graph.input import Input
5
+ from ai_simple_engine.graph.output import Output
6
+ from ai_simple_engine.types.data_type import STRING
7
+ from ai_simple_engine.types.audio import Audio
8
+
9
+
10
+ class GenerateMusic(
11
+ Operation
12
+ ):
13
+
14
+ loaded_model: 'LoadedModel[LoadedMusicGenModel]' = Input(RESOURCE)
15
+ prompt = Input(STRING)
16
+ max_new_tokens = Input(
17
+ int,
18
+ default = 256
19
+ )
20
+ guidance_scale = Input(
21
+ float,
22
+ default = 3.0
23
+ )
24
+ audio = Output(AUDIO)
25
+
26
+ async def execute(
27
+ self,
28
+ context
29
+ ):
30
+ """
31
+ TODO: We will implement an OperationFactory to
32
+ make this a 'self._runner' that is automatically
33
+ registered.
34
+ """
35
+ runner = context.runners.get(MusicGenRunner)
36
+
37
+ audio = await runner.generate(
38
+ model = self.loaded_model.instance,
39
+ prompt = self.prompt,
40
+ max_new_tokens = self.max_new_tokens,
41
+ guidance_scale = self.guidance_scale
42
+ )
43
+
44
+ return {
45
+ 'audio': audio
46
+ }
47
+
48
+
49
+ loaded_model = self.model.instance
50
+ processor = loaded_model.processor
51
+ network = loaded_model.network
52
+
53
+ inputs = processor(
54
+ text = [self.prompt],
55
+ return_tensors = 'pt'
56
+ )
57
+
58
+ inputs = {
59
+ key: value.to(network.device)
60
+ for key, value in inputs.items()
61
+ }
62
+
63
+ output = network.generate(
64
+ **inputs,
65
+ max_new_tokens = self.max_new_tokens,
66
+ guidance_scale = self.guidance_scale
67
+ )
68
+
69
+ audio = output.cpu().numpy()
70
+
71
+ return {
72
+ 'audio': Audio(
73
+ samples = audio[0, 0],
74
+ sample_rate = 32000
75
+ )
76
+ }
@@ -0,0 +1,18 @@
1
+ from ai_simple_engine.plugins.plugin import Plugin
2
+ from ai_simple_engine_transformers.providers.model_loaders_provider import TransformersModelLoaderProvider
3
+ from ai_simple_engine_transformers.providers.model_repository_provider import TransformersModelRepositoryProvider
4
+ from ai_simple_engine_transformers.providers.operation_provider import TransformersOperationProvider
5
+
6
+
7
+ class TransformersPlugin(
8
+ Plugin
9
+ ):
10
+
11
+ def providers(
12
+ self
13
+ ):
14
+ return [
15
+ TransformersModelRepositoryProvider(),
16
+ TransformersModelLoaderProvider(),
17
+ TransformersOperationProvider()
18
+ ]
@@ -0,0 +1,6 @@
1
+ """
2
+ The providers that will be used by the
3
+ engine builder to register the different
4
+ elements provided in order to be able to
5
+ work with the plugin.
6
+ """
@@ -0,0 +1,18 @@
1
+ from ai_simple_engine.engine_builder import EngineBuilder
2
+ from ai_simple_engine.plugins.providers.abstract import PluginProvider
3
+ from ai_simple_engine_transformers.types.data_type import MUSICGEN_MODEL
4
+
5
+
6
+ class TransformersDataTypeProvider(
7
+ PluginProvider
8
+ ):
9
+
10
+ def register(
11
+ self,
12
+ builder: EngineBuilder
13
+ ):
14
+ (
15
+ builder
16
+ .add_data_type(MUSICGEN_MODEL)
17
+ )
18
+
@@ -0,0 +1,17 @@
1
+ from ai_simple_engine.engine_builder import EngineBuilder
2
+ from ai_simple_engine.plugins.providers.abstract import PluginProvider
3
+ from ai_simple_engine_transformers.model_loaders.musicgen.base import MusicGenLoader
4
+
5
+
6
+ class TransformersModelLoaderProvider(
7
+ PluginProvider
8
+ ):
9
+
10
+ def register(
11
+ self,
12
+ builder: EngineBuilder
13
+ ):
14
+ (
15
+ builder
16
+ .add_model_loader(MusicGenLoader())
17
+ )
@@ -0,0 +1,18 @@
1
+ from ai_simple_engine.engine_builder import EngineBuilder
2
+ from ai_simple_engine.plugins.providers.abstract import PluginProvider
3
+ from ai_simple_engine_transformers.repositories.huggingface.huggingface_provider import HuggingFaceProvider
4
+
5
+
6
+ class TransformersModelRepositoryProvider(
7
+ PluginProvider
8
+ ):
9
+
10
+ def register(
11
+ self,
12
+ builder: EngineBuilder
13
+ ):
14
+ (
15
+ builder
16
+ .add_model_provider(HuggingFaceProvider())
17
+ )
18
+
@@ -0,0 +1,21 @@
1
+ from ai_simple_engine.engine_builder import EngineBuilder
2
+ from ai_simple_engine.plugins.providers.abstract import PluginProvider
3
+ from ai_simple_engine.graph.operation.install_model import InstallModel
4
+ from ai_simple_engine.graph.operation.acquire_model import AcquireModel
5
+ from ai_simple_engine_transformers.operations.music.generate_music import GenerateMusic
6
+
7
+
8
+ class TransformersOperationProvider(
9
+ PluginProvider
10
+ ):
11
+
12
+ def register(
13
+ self,
14
+ builder: EngineBuilder
15
+ ):
16
+ (
17
+ builder
18
+ .add_operation(InstallModel)
19
+ .add_operation(AcquireModel)
20
+ .add_operation(GenerateMusic)
21
+ )
File without changes
@@ -0,0 +1,23 @@
1
+ from huggingface_hub import snapshot_download
2
+ from pathlib import Path
3
+
4
+
5
+ # TODO: Maybe I need a 'Client' abstract with the
6
+ # 'download' as an abstract method
7
+ class HuggingFaceClient:
8
+
9
+ def download(
10
+ self,
11
+ repo_id: str,
12
+ *,
13
+ revision: str | None = None,
14
+ local_dir: Path | None = None
15
+ ) -> Path:
16
+ path = snapshot_download(
17
+ repo_id = repo_id,
18
+ revision = revision,
19
+ local_dir = local_dir,
20
+ local_dir_use_symlinks = False
21
+ )
22
+
23
+ return Path(path)
@@ -0,0 +1,102 @@
1
+ from ai_simple_engine_transformers.repositories.huggingface.huggingface_client import HuggingFaceClient
2
+ from ai_simple_engine.models.installed_model import InstalledModel
3
+ from ai_simple_engine.models.providers.abstract import ModelProvider
4
+ from ai_simple_engine.models.model_spec import ModelSpec
5
+ from ai_simple_engine.settings.engine_settings import EngineSettings
6
+ from pathlib import Path
7
+ from typing import Union
8
+
9
+
10
+ class HuggingFaceProvider(
11
+ ModelProvider
12
+ ):
13
+
14
+ def __init__(
15
+ self,
16
+ client: Union[HuggingFaceClient, None] = None,
17
+ ):
18
+ self._client = (
19
+ client or
20
+ HuggingFaceClient()
21
+ )
22
+
23
+ self._settings: Union[EngineSettings, None] = None
24
+
25
+ # self._models_directory = (
26
+ # models_directory
27
+ # if models_directory is not None
28
+ # # TODO: Change this path
29
+ # else Path.home() / '.ai_simple_engine' / 'models'
30
+ # )
31
+
32
+ @property
33
+ def name(
34
+ self
35
+ ) -> str:
36
+ return 'huggingface'
37
+
38
+ async def install(
39
+ self,
40
+ spec: ModelSpec
41
+ ) -> InstalledModel:
42
+ path = self._client.download(
43
+ repo_id = spec.identifier,
44
+ revision = spec.revision,
45
+ local_dir = self._local_directory(spec)
46
+ )
47
+
48
+ return InstalledModel(
49
+ id = spec.identifier,
50
+ # family = spec.family,
51
+ path = path,
52
+ revision = spec.revision
53
+ )
54
+
55
+ def is_installed(
56
+ self,
57
+ spec: ModelSpec
58
+ ) -> bool:
59
+ """
60
+ Check if the model with the `spec` given is
61
+ installed or not.
62
+ """
63
+ return self._local_directory(spec).exists()
64
+
65
+ def get_installed_model(
66
+ self,
67
+ spec: ModelSpec
68
+ ) -> InstalledModel:
69
+ path = self._local_directory(spec)
70
+
71
+ if not path.exists():
72
+ raise FileNotFoundError(
73
+ f'Model "{spec.identifier}" is not installed.'
74
+ )
75
+
76
+ return InstalledModel(
77
+ id = spec.identifier,
78
+ family = spec.family,
79
+ path = path,
80
+ revision = spec.revision
81
+ )
82
+
83
+ def _local_directory(
84
+ self,
85
+ # TODO: Remove this spec
86
+ spec: ModelSpec
87
+ ) -> Path:
88
+ # TODO: The '.configure(plugin_context)' should be called
89
+ return (
90
+ self._settings.models_directory
91
+ / spec.family
92
+ / spec.identifier
93
+ )
94
+
95
+ return self._settings.models_directory
96
+
97
+ path = self._models_directory / spec.family / spec.identifier
98
+
99
+ if spec.revision:
100
+ path /= spec.revision
101
+
102
+ return path
@@ -0,0 +1,12 @@
1
+ """
2
+ A runner is the class that will include the
3
+ code to perform a real operation. The logic,
4
+ the core.
5
+
6
+ What you should implement:
7
+ - Abstract class to determine what should the
8
+ `generate` method expect as parameters.
9
+ - Real implementation of the logic that must
10
+ be actually applied to obtain the expected
11
+ results.
12
+ """
@@ -0,0 +1,21 @@
1
+ from ai_simple_engine_transformers.model_loaders.musicgen.loaded_musicgen_model import LoadedMusicGenModel
2
+ from ai_simple_engine.runners.abstract import Runner
3
+ from ai_simple_engine.types.audio import Audio
4
+ from abc import ABC, abstractmethod
5
+
6
+
7
+ class MusicGenRunnerAbstract(
8
+ Runner,
9
+ ABC
10
+ ):
11
+
12
+ @abstractmethod
13
+ async def generate(
14
+ self,
15
+ model: LoadedMusicGenModel,
16
+ prompt: str,
17
+ *,
18
+ max_new_tokens: int,
19
+ guidance_scale: float
20
+ ) -> Audio:
21
+ ...
@@ -0,0 +1,41 @@
1
+ from ai_simple_engine_transformers.runners.abstract.musicgen_runner_abstract import MusicGenRunnerAbstract
2
+ from ai_simple_engine.types.audio import Audio
3
+
4
+
5
+ class MusicGenRunner(
6
+ MusicGenRunnerAbstract
7
+ ):
8
+
9
+ async def generate(
10
+ self,
11
+ model,
12
+ prompt,
13
+ *,
14
+ max_new_tokens,
15
+ guidance_scale
16
+ ) -> Audio:
17
+ processor = model.processor
18
+ network = model.network
19
+
20
+ inputs = processor(
21
+ text = [prompt],
22
+ return_tensors = 'pt'
23
+ )
24
+
25
+ inputs = {
26
+ k: v.to(network.device)
27
+ for k, v in inputs.items()
28
+ }
29
+
30
+ output = network.generate(
31
+ **inputs,
32
+ max_new_tokens = max_new_tokens,
33
+ guidance_scale = guidance_scale
34
+ )
35
+
36
+ samples = output.cpu().numpy()[0, 0]
37
+
38
+ return Audio(
39
+ samples = samples,
40
+ sample_rate = 32000
41
+ )
File without changes
@@ -0,0 +1,26 @@
1
+ from ai_simple_engine.types.data_type import DataType, RESOURCE
2
+ from ai_simple_engine.resources.resource_handle import ResourceHandle
3
+
4
+ import torch
5
+
6
+
7
+ TENSOR = DataType(
8
+ name = 'Tensor',
9
+ runtime_type = torch.Tensor,
10
+ parent = None
11
+ )
12
+ LATENT = DataType(
13
+ name = 'Latent',
14
+ runtime_type = torch.Tensor,
15
+ parent = TENSOR
16
+ )
17
+ MUSICGEN_MODEL = DataType(
18
+ name = 'MusicGenModel',
19
+ runtime_type = ResourceHandle,
20
+ parent = RESOURCE
21
+ )
22
+ # WHISPER_MODEL = DataType(
23
+ # name = 'WhisperMode',
24
+ # runtime_type = ResourceHandle,
25
+ # parent = RESOURCE
26
+ # )
@@ -0,0 +1,20 @@
1
+ Metadata-Version: 2.4
2
+ Name: ai-simple-engine-transformers
3
+ Version: 0.0.1
4
+ Summary: AI Simple Engine Transformers Module
5
+ License-File: LICENSE
6
+ Author: danialcala94
7
+ Author-email: danielalcalavalera@gmail.com
8
+ Requires-Python: >=3.10,<3.12
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: Programming Language :: Python :: 3.10
11
+ Classifier: Programming Language :: Python :: 3.11
12
+ Requires-Dist: ai-simple-engine (>=0.0.1,<1.0.0)
13
+ Requires-Dist: huggingface-hub (>=1.21.0,<9999.0.0)
14
+ Requires-Dist: torch (>=2.12.1,<9999.0.0)
15
+ Requires-Dist: transformers (>=5.12.1,<9999.0.0)
16
+ Description-Content-Type: text/markdown
17
+
18
+ # AI Simple Engine Transformers Module
19
+
20
+ The Transformers module for the AI Simple Engine `ai-simple-engine`.
@@ -0,0 +1,28 @@
1
+ ai_simple_engine_transformers/__init__.py,sha256=RhXJ6s5ed_wiymG6YqMi5OuFrbi-B-sLZ8QnUXQC7LQ,205
2
+ ai_simple_engine_transformers/model_loaders/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
+ ai_simple_engine_transformers/model_loaders/musicgen/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
+ ai_simple_engine_transformers/model_loaders/musicgen/base.py,sha256=I0jzyf-DMYQQJaWwBy3BWqQhYNavudndDQckJ1aEz4c,1239
5
+ ai_simple_engine_transformers/model_loaders/musicgen/loaded_musicgen_model.py,sha256=1f8XWq1p27UWGaT1BCNF8nmfcZpdwLae1ejlqBgVPVU,245
6
+ ai_simple_engine_transformers/operations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
+ ai_simple_engine_transformers/operations/music/__init__.py,sha256=S6y4Ga1R--d1HuGFK-vvwzous5Bgl26kMohWXVRiuQM,46
8
+ ai_simple_engine_transformers/operations/music/generate_music.py,sha256=ydhL6fR_rYGoCDWEcuJIjczcjyI2nuN-et-YNiL_Lcg,2046
9
+ ai_simple_engine_transformers/plugin.py,sha256=_rToq0bIpSMY0qqEvMSur_iFZX8w6I0kmi51UCsU9ug,640
10
+ ai_simple_engine_transformers/providers/__init__.py,sha256=FA0L0Fbn6P20bW3IEde3t-4-QZt3vjghJL_YIJv2kMQ,155
11
+ ai_simple_engine_transformers/providers/data_types_provider.py,sha256=pru8izdgimvnvqUladZ1wWNG87fwWkbTPVWp12BhxlQ,441
12
+ ai_simple_engine_transformers/providers/model_loaders_provider.py,sha256=wwJfOpPmGIs5JI1VZaqR5niOEYF9pNqj8lIsYMTzKmU,451
13
+ ai_simple_engine_transformers/providers/model_repository_provider.py,sha256=rClroigTbcS-AOhCsM2AQt9A6o8BnUTegeOcTpHznxc,495
14
+ ai_simple_engine_transformers/providers/operation_provider.py,sha256=mqo8DHl-tPmquqscpIBiby1lnrFQAj7xPKF_iKmQYwo,676
15
+ ai_simple_engine_transformers/repositories/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
+ ai_simple_engine_transformers/repositories/huggingface/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
17
+ ai_simple_engine_transformers/repositories/huggingface/huggingface_client.py,sha256=3g1pnMF-v4D64X9oUBIea8uwgYFEwbg473-AUw0mAaM,573
18
+ ai_simple_engine_transformers/repositories/huggingface/huggingface_provider.py,sha256=AzYlcn-UB2l49ZTcpsOgMrt9hP-_JxYd3auZti1jOMM,2769
19
+ ai_simple_engine_transformers/runners/__init__.py,sha256=0S7Q4W0avUh4YWt4eeTX5M3F6741zKyf0g563N_Im-4,328
20
+ ai_simple_engine_transformers/runners/abstract/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
21
+ ai_simple_engine_transformers/runners/abstract/musicgen_runner_abstract.py,sha256=EuU1Owexp_fuMAtVkcACexDrZYoQ-lQdZOpekCNwf30,531
22
+ ai_simple_engine_transformers/runners/musicgen_runner.py,sha256=YtjmV9Vnc342tRPOYSkh8c0snOqFvl8Tux8xHZWMXLI,965
23
+ ai_simple_engine_transformers/types/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
24
+ ai_simple_engine_transformers/types/data_type.py,sha256=aJdx0uxOBCTbUQK3sjKuMfkzsWkW4upwEXYYAMyFr98,597
25
+ ai_simple_engine_transformers-0.0.1.dist-info/licenses/LICENSE,sha256=6kbiFSfobTZ7beWiKnHpN902HgBx-Jzgcme0SvKqhKY,1091
26
+ ai_simple_engine_transformers-0.0.1.dist-info/METADATA,sha256=nTzFLo2Gz3SMMg8xwM9LzGHfyNVf5ALVkPTBb00SIac,727
27
+ ai_simple_engine_transformers-0.0.1.dist-info/WHEEL,sha256=M5asmiAlL6HEcOq52Yi5mmk9KmTVjY2RDPtO4p9DMrc,88
28
+ ai_simple_engine_transformers-0.0.1.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: poetry-core 2.2.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2018 The Python Packaging Authority
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ SOFTWARE.