mlx-warmup-kit 0.1.0__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.
- mlx_warmup_kit/__init__.py +3 -0
- mlx_warmup_kit/cli.py +84 -0
- mlx_warmup_kit/deal.py +25 -0
- mlx_warmup_kit/plan.py +43 -0
- mlx_warmup_kit/recipe.py +57 -0
- mlx_warmup_kit-0.1.0.dist-info/METADATA +132 -0
- mlx_warmup_kit-0.1.0.dist-info/RECORD +10 -0
- mlx_warmup_kit-0.1.0.dist-info/WHEEL +4 -0
- mlx_warmup_kit-0.1.0.dist-info/entry_points.txt +2 -0
- mlx_warmup_kit-0.1.0.dist-info/licenses/LICENSE +21 -0
mlx_warmup_kit/cli.py
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"""CLI for mlx-warmup-kit."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
import click
|
|
8
|
+
import yaml
|
|
9
|
+
|
|
10
|
+
from mlx_warmup_kit.plan import render_markdown, render_shell
|
|
11
|
+
from mlx_warmup_kit.recipe import WarmupRecipe, default_recipe
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@click.group(invoke_without_command=True)
|
|
15
|
+
@click.version_option(package_name="mlx-warmup-kit")
|
|
16
|
+
@click.option("--show-deal", is_flag=True, help="Print Multilogin coupon info and exit.")
|
|
17
|
+
@click.pass_context
|
|
18
|
+
def main(ctx: click.Context, show_deal: bool) -> None:
|
|
19
|
+
"""Plan Multilogin browser warmup pipelines from YAML recipes."""
|
|
20
|
+
if show_deal:
|
|
21
|
+
from mlx_warmup_kit.deal import print_show_deal
|
|
22
|
+
|
|
23
|
+
print_show_deal()
|
|
24
|
+
ctx.exit(0)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@main.command("default")
|
|
28
|
+
def default_cmd() -> None:
|
|
29
|
+
"""Print the default fleet warmup recipe as JSON."""
|
|
30
|
+
click.echo(default_recipe().model_dump_json(indent=2))
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@main.command("validate")
|
|
34
|
+
@click.argument("recipe_path", type=click.Path(exists=True, path_type=Path))
|
|
35
|
+
def validate_cmd(recipe_path: Path) -> None:
|
|
36
|
+
"""Validate a warmup recipe YAML file."""
|
|
37
|
+
data = yaml.safe_load(recipe_path.read_text(encoding="utf-8")) or {}
|
|
38
|
+
WarmupRecipe.model_validate(data)
|
|
39
|
+
click.echo(f"OK {recipe_path}")
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
@main.command("plan")
|
|
43
|
+
@click.argument("recipe_path", type=click.Path(exists=True, path_type=Path), required=False)
|
|
44
|
+
@click.option(
|
|
45
|
+
"--format",
|
|
46
|
+
"fmt",
|
|
47
|
+
type=click.Choice(["markdown", "shell", "json"]),
|
|
48
|
+
default="markdown",
|
|
49
|
+
)
|
|
50
|
+
@click.option("-o", "--output", type=click.Path(path_type=Path), default=None)
|
|
51
|
+
def plan_cmd(recipe_path: Path | None, fmt: str, output: Path | None) -> None:
|
|
52
|
+
"""Render a warmup plan (markdown, shell, or json)."""
|
|
53
|
+
if recipe_path:
|
|
54
|
+
data = yaml.safe_load(recipe_path.read_text(encoding="utf-8")) or {}
|
|
55
|
+
recipe = WarmupRecipe.model_validate(data)
|
|
56
|
+
else:
|
|
57
|
+
recipe = default_recipe()
|
|
58
|
+
|
|
59
|
+
if fmt == "json":
|
|
60
|
+
text = recipe.model_dump_json(indent=2)
|
|
61
|
+
elif fmt == "shell":
|
|
62
|
+
text = render_shell(recipe)
|
|
63
|
+
else:
|
|
64
|
+
text = render_markdown(recipe)
|
|
65
|
+
|
|
66
|
+
if output:
|
|
67
|
+
output.write_text(text, encoding="utf-8")
|
|
68
|
+
click.echo(f"Wrote {output}")
|
|
69
|
+
else:
|
|
70
|
+
click.echo(text)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
@main.command("template")
|
|
74
|
+
@click.option("-o", "--output", type=click.Path(path_type=Path), default="-")
|
|
75
|
+
def template_cmd(output: Path | str) -> None:
|
|
76
|
+
"""Write a starter warmup recipe YAML."""
|
|
77
|
+
recipe = default_recipe()
|
|
78
|
+
payload = recipe.model_dump()
|
|
79
|
+
text = yaml.safe_dump(payload, sort_keys=False)
|
|
80
|
+
if str(output) == "-":
|
|
81
|
+
click.echo(text)
|
|
82
|
+
else:
|
|
83
|
+
Path(output).write_text(text, encoding="utf-8")
|
|
84
|
+
click.echo(f"Wrote {output}")
|
mlx_warmup_kit/deal.py
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"""Multilogin partner coupon output for --show-deal."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import click
|
|
6
|
+
|
|
7
|
+
SHOW_DEAL_TEXT = """Partner info (affiliate links — optional, not required for mlx-warmup)
|
|
8
|
+
|
|
9
|
+
Warmup pipelines matter inside isolated MLX browser profiles — not leaky vanilla Chrome.
|
|
10
|
+
Folder-scale cadence pairs with farm-runner + human-input-kit on Launcher CDP.
|
|
11
|
+
|
|
12
|
+
Multilogin X — antidetect browser (verify eligibility before checkout)
|
|
13
|
+
|
|
14
|
+
SAAS50 — browser plans (eligible new purchases)
|
|
15
|
+
MIN50 — cloud phone (if you also run mobile apps)
|
|
16
|
+
|
|
17
|
+
https://multilogin.com?a_aid=saas
|
|
18
|
+
Promo hub: https://anti-detect.github.io/ (SAAS50 / MIN50)
|
|
19
|
+
Scripts: https://t.me/Multilogin_Scripts_Bot
|
|
20
|
+
|
|
21
|
+
Disclosure: we may earn a commission. Offers change; confirm on vendor site."""
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def print_show_deal() -> None:
|
|
25
|
+
click.echo(SHOW_DEAL_TEXT)
|
mlx_warmup_kit/plan.py
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"""Render warmup plans from recipes."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from mlx_warmup_kit.recipe import WarmupRecipe
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def render_markdown(recipe: WarmupRecipe) -> str:
|
|
9
|
+
lines = [
|
|
10
|
+
f"# Warmup plan: {recipe.name}",
|
|
11
|
+
"",
|
|
12
|
+
"Run inside **isolated Multilogin X** profiles (proxy + fingerprint matched).",
|
|
13
|
+
"",
|
|
14
|
+
"| Step | PyPI tool | Command |",
|
|
15
|
+
"|------|-----------|---------|",
|
|
16
|
+
]
|
|
17
|
+
for step in recipe.steps:
|
|
18
|
+
cmd = step.command.replace("|", "\\|")
|
|
19
|
+
lines.append(f"| {step.id} | `{step.tool}` | `{cmd}` |")
|
|
20
|
+
lines.extend(
|
|
21
|
+
[
|
|
22
|
+
"",
|
|
23
|
+
"Scale N profiles: pair with `automation-farm-runner` `mlx-pool` or `farm-runner run`.",
|
|
24
|
+
"",
|
|
25
|
+
]
|
|
26
|
+
)
|
|
27
|
+
return "\n".join(lines)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def render_shell(recipe: WarmupRecipe) -> str:
|
|
31
|
+
lines = [
|
|
32
|
+
"#!/usr/bin/env bash",
|
|
33
|
+
f"# Warmup plan: {recipe.name}",
|
|
34
|
+
"set -euo pipefail",
|
|
35
|
+
"export CDP_URL=${CDP_URL:-}",
|
|
36
|
+
"",
|
|
37
|
+
]
|
|
38
|
+
for step in recipe.steps:
|
|
39
|
+
if step.note:
|
|
40
|
+
lines.append(f"# {step.note}")
|
|
41
|
+
lines.append(step.command)
|
|
42
|
+
lines.append("")
|
|
43
|
+
return "\n".join(lines)
|
mlx_warmup_kit/recipe.py
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"""Warmup recipe schema."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from pydantic import BaseModel, Field
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class WarmupStep(BaseModel):
|
|
9
|
+
id: str
|
|
10
|
+
tool: str
|
|
11
|
+
command: str
|
|
12
|
+
note: str | None = None
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class WarmupRecipe(BaseModel):
|
|
16
|
+
name: str = "default-warmup"
|
|
17
|
+
profile_id: str | None = None
|
|
18
|
+
folder_id: str | None = None
|
|
19
|
+
steps: list[WarmupStep] = Field(default_factory=list)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
DEFAULT_STEPS: list[WarmupStep] = [
|
|
23
|
+
WarmupStep(
|
|
24
|
+
id="proxy",
|
|
25
|
+
tool="proxy-lane-checker",
|
|
26
|
+
command="proxy-lane check proxies.txt -o lanes.json",
|
|
27
|
+
note="Validate exit IP before assigning to MLX profile",
|
|
28
|
+
),
|
|
29
|
+
WarmupStep(
|
|
30
|
+
id="fingerprint",
|
|
31
|
+
tool="fingerprint-coherence",
|
|
32
|
+
command="fp-coherence audit profile.yaml --strict",
|
|
33
|
+
note="Lint UA/screen/timezone coherence",
|
|
34
|
+
),
|
|
35
|
+
WarmupStep(
|
|
36
|
+
id="cdp",
|
|
37
|
+
tool="cdp-connect-kit",
|
|
38
|
+
command="cdp-connect mlx-start --profile-id PROFILE_UUID --print-cdp-url",
|
|
39
|
+
note="Start Launcher profile; export CDP_URL",
|
|
40
|
+
),
|
|
41
|
+
WarmupStep(
|
|
42
|
+
id="warmup",
|
|
43
|
+
tool="human-input-kit",
|
|
44
|
+
command="human-input --seed 42 demo-scroll --url https://news.ycombinator.com",
|
|
45
|
+
note="Human-like cadence inside isolated profile",
|
|
46
|
+
),
|
|
47
|
+
WarmupStep(
|
|
48
|
+
id="probe",
|
|
49
|
+
tool="playwright-cdp-probe",
|
|
50
|
+
command="cdp-probe run --cdp-endpoint $CDP_URL --url https://example.com",
|
|
51
|
+
note="Exposure score after warmup",
|
|
52
|
+
),
|
|
53
|
+
]
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def default_recipe() -> WarmupRecipe:
|
|
57
|
+
return WarmupRecipe(name="mlx-browser-warmup", steps=list(DEFAULT_STEPS))
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mlx-warmup-kit
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Multilogin browser warmup pipeline — YAML recipes for proxy, CDP, and human-like cadence. CLI: mlx-warmup.
|
|
5
|
+
Project-URL: Homepage, https://pypi.org/project/mlx-warmup-kit/
|
|
6
|
+
Project-URL: Documentation, https://pypi.org/project/mlx-warmup-kit/
|
|
7
|
+
Project-URL: Repository, https://pypi.org/project/mlx-warmup-kit/
|
|
8
|
+
Project-URL: Changelog, https://pypi.org/project/mlx-warmup-kit/
|
|
9
|
+
Author: mlx-warmup-kit contributors
|
|
10
|
+
License-Expression: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: account-warmup,antidetect-warmup,browser-warmup,folder-warmup,human-like-warmup,launcher-cdp,mlx-warmup,multilogin-warmup,new-profile-cadence,playwright-warmup,profile-onboarding,profile-warmup,saas50,warmup-pipeline
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Environment :: Console
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Topic :: Internet :: WWW/HTTP :: Browsers
|
|
23
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
24
|
+
Classifier: Typing :: Typed
|
|
25
|
+
Requires-Python: >=3.10
|
|
26
|
+
Requires-Dist: click>=8.1
|
|
27
|
+
Requires-Dist: pydantic>=2.5
|
|
28
|
+
Requires-Dist: pyyaml>=6.0
|
|
29
|
+
Provides-Extra: dev
|
|
30
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
31
|
+
Requires-Dist: ruff>=0.8; extra == 'dev'
|
|
32
|
+
Description-Content-Type: text/markdown
|
|
33
|
+
|
|
34
|
+
# mlx-warmup-kit
|
|
35
|
+
|
|
36
|
+
**Multilogin browser warmup pipeline** — YAML recipes linking proxy, CDP, human-like cadence, and exposure probes.
|
|
37
|
+
|
|
38
|
+
[](https://pypi.org/project/mlx-warmup-kit/)
|
|
39
|
+
[](https://pypi.org/project/mlx-warmup-kit/)
|
|
40
|
+
[](https://pypi.org/project/mlx-warmup-kit/)
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
pip install mlx-warmup-kit
|
|
44
|
+
mlx-warmup plan --format markdown
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
CLI: **`mlx-warmup`** · Python **3.10+** · planner only (peer tools on PyPI)
|
|
48
|
+
|
|
49
|
+
> **Coupon hub:** Verified MLX deals (`SAAS50` browser / `MIN50` cloud phone) — [Multilogin promo codes](https://anti-detect.github.io/). Core CLI works without a vendor account. [Affiliate disclosure](docs/AFFILIATE.md).
|
|
50
|
+
|
|
51
|
+
Plan **folder-scale warmup** as a repeatable recipe — proxy check → fingerprint lint → Launcher CDP → human-like scroll → exposure probe inside isolated MLX profiles.
|
|
52
|
+
|
|
53
|
+
## Problem
|
|
54
|
+
|
|
55
|
+
New MLX profiles get flagged when teams skip ordered warmup. Ad-hoc scripts forget proxy validation or probe the wrong browser context. `mlx-warmup` documents the fleet pipeline as YAML you can validate and render to shell/markdown.
|
|
56
|
+
|
|
57
|
+
## Install
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
pip install mlx-warmup-kit
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Quick start
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
mlx-warmup template -o warmup.yaml
|
|
67
|
+
mlx-warmup validate warmup.yaml
|
|
68
|
+
mlx-warmup plan warmup.yaml --format shell -o run-warmup.sh
|
|
69
|
+
chmod +x run-warmup.sh
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## When new profiles still get flagged (playbook)
|
|
73
|
+
|
|
74
|
+
| Step skipped | Risk | Tool on PyPI |
|
|
75
|
+
|--------------|------|--------------|
|
|
76
|
+
| Proxy check | Wrong geo / dead exit | `proxy-lane-checker` |
|
|
77
|
+
| Fingerprint lint | UA/screen drift | `fingerprint-coherence` |
|
|
78
|
+
| Vanilla Chrome warmup | webdriver leaks | `cdp-connect-kit` + `human-input-kit` |
|
|
79
|
+
| No exposure probe | Ship blind | `playwright-cdp-probe` |
|
|
80
|
+
|
|
81
|
+
**Default fleet pipeline:**
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
mlx-warmup plan --format shell -o warmup.sh
|
|
85
|
+
export MLX_TOKEN=... PROFILE_UUID=...
|
|
86
|
+
bash warmup.sh
|
|
87
|
+
farm-runner mlx-pool --folder-id FOLDER --script ./warmup_child.py # scale
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
**Coupon hub:** [Multilogin promo codes](https://anti-detect.github.io/) — `SAAS50` browser warmup at scale.
|
|
91
|
+
|
|
92
|
+
## CLI
|
|
93
|
+
|
|
94
|
+
| Command | Description |
|
|
95
|
+
|---------|-------------|
|
|
96
|
+
| `mlx-warmup default` | Print default recipe JSON |
|
|
97
|
+
| `mlx-warmup validate FILE` | Lint recipe YAML |
|
|
98
|
+
| `mlx-warmup plan [FILE]` | Render markdown / shell / json |
|
|
99
|
+
| `mlx-warmup template` | Write starter recipe |
|
|
100
|
+
| `mlx-warmup --show-deal` | Opt-in coupons |
|
|
101
|
+
|
|
102
|
+
## Limitations
|
|
103
|
+
|
|
104
|
+
- **Planner only** — does not install peer packages or call MLX APIs.
|
|
105
|
+
- **Chromium browser path** — recipe targets Launcher CDP, not cloud phone apps.
|
|
106
|
+
- **You run the commands** — `plan --format shell` emits a script template.
|
|
107
|
+
|
|
108
|
+
## Production
|
|
109
|
+
|
|
110
|
+
Pair rendered shell plans with [automation-farm-runner](https://pypi.org/project/automation-farm-runner/) `mlx-pool` for N-profile folders.
|
|
111
|
+
|
|
112
|
+
**Partner note (affiliate):** Folder warmup needs **Multilogin X** Launcher CDP — code **`SAAS50`** at [multilogin.com](https://multilogin.com?a_aid=saas). Full disclosure: [docs/AFFILIATE.md](docs/AFFILIATE.md). Deals hub: [anti-detect.github.io](https://anti-detect.github.io/). Coupons: `mlx-warmup --show-deal`.
|
|
113
|
+
|
|
114
|
+
**FAQ:** [docs/FAQ.md](docs/FAQ.md)
|
|
115
|
+
|
|
116
|
+
## Related tools (on PyPI)
|
|
117
|
+
|
|
118
|
+
| Package | CLI | Role |
|
|
119
|
+
|---------|-----|------|
|
|
120
|
+
| [human-input-kit](https://pypi.org/project/human-input-kit/) | `human-input` | Human-like scroll/mouse |
|
|
121
|
+
| [cdp-connect-kit](https://pypi.org/project/cdp-connect-kit/) | `cdp-connect` | MLX Launcher CDP |
|
|
122
|
+
| [cloud-phone-kit](https://pypi.org/project/cloud-phone-kit/) | `cloud-phone` | Cloud Phone readiness |
|
|
123
|
+
| [automation-farm-runner](https://pypi.org/project/automation-farm-runner/) | `farm-runner` | mlx-pool queue |
|
|
124
|
+
|
|
125
|
+
## License
|
|
126
|
+
|
|
127
|
+
MIT
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
**Production antidetect (partner):** [Multilogin X](https://multilogin.com?a_aid=saas) · Code `SAAS50` (-50% browser) · [MIN50](https://multilogin.com?a_aid=saas) (-50% cloud phone)
|
|
132
|
+
More: [@Multilogin_Scripts_Bot](https://t.me/Multilogin_Scripts_Bot) · [Multilogin promo codes](https://anti-detect.github.io/)
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
mlx_warmup_kit/__init__.py,sha256=Q5F4jwo1Iu9lf63MfuxFVsZF2mkGDN7zamnKWjCmOH4,66
|
|
2
|
+
mlx_warmup_kit/cli.py,sha256=lgXTDzCahwoUSr_olWRk-TW3uX0Vkx8uJeC-cXnAfHs,2648
|
|
3
|
+
mlx_warmup_kit/deal.py,sha256=1Sivqqk_K8jmY0wYk9OqCSx4pD0BmpQ9sGpHMlRtxqY,845
|
|
4
|
+
mlx_warmup_kit/plan.py,sha256=uvp2xr3u4gltvLwzSOfJbB8SBeFcLg7U4Bg82Gs1fKc,1184
|
|
5
|
+
mlx_warmup_kit/recipe.py,sha256=frj34mtFsxGzoyJYuYA0J0yTaQQuSdA_brftdjLqTho,1597
|
|
6
|
+
mlx_warmup_kit-0.1.0.dist-info/METADATA,sha256=ol46tPoSe4IJ6HO5pdcGhRMUm3xUz9jOcyT5iSQH-ig,5736
|
|
7
|
+
mlx_warmup_kit-0.1.0.dist-info/WHEEL,sha256=mffPy8wBnZQn2VnJUU5jE99KsxaSfiyMHV9Yt0aLVxs,87
|
|
8
|
+
mlx_warmup_kit-0.1.0.dist-info/entry_points.txt,sha256=VoQ_qbIYGJ8OOWTA_rnnJUhATWyt9xhMYuShkxvITRY,55
|
|
9
|
+
mlx_warmup_kit-0.1.0.dist-info/licenses/LICENSE,sha256=yBby87TZyU-zAyZx2QxLX9jQFl-OvZ3HtZoEptvYEJY,1089
|
|
10
|
+
mlx_warmup_kit-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 antidetect-importer contributors
|
|
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 all
|
|
13
|
+
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 THE
|
|
21
|
+
SOFTWARE.
|