@stackweld/core 0.3.1 → 0.4.0
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.
- package/README.md +1 -1
- package/dist/engine/compose-generator.d.ts +0 -8
- package/dist/engine/compose-generator.js +1 -15
- package/dist/engine/license-manager.d.ts +29 -0
- package/dist/engine/license-manager.js +130 -0
- package/dist/engine/stack-engine.d.ts +0 -20
- package/dist/engine/stack-engine.js +0 -24
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/package.json +1 -1
- package/LICENSE +0 -21
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @stackweld/core
|
|
2
2
|
|
|
3
|
-
[](https://github.com/mundowise/Stackweld/releases)
|
|
4
4
|
[](https://opensource.org/licenses/MIT)
|
|
5
5
|
|
|
6
6
|
The core engine for Stackweld. Handles stack persistence, compatibility rules, scaffolding orchestration, Docker lifecycle, and all analysis modules.
|
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Compose Generator — Pure function that generates docker-compose.yml content.
|
|
3
|
-
* No disk I/O — returns structured data for preview or writing.
|
|
4
|
-
*/
|
|
5
1
|
export interface ComposePreviewResult {
|
|
6
2
|
yaml: string;
|
|
7
3
|
services: string[];
|
|
@@ -24,10 +20,6 @@ interface ComposeTechnology {
|
|
|
24
20
|
};
|
|
25
21
|
port?: number;
|
|
26
22
|
}
|
|
27
|
-
/**
|
|
28
|
-
* Generate a docker-compose.yml preview from a list of technologies.
|
|
29
|
-
* Only includes technologies that have a `dockerImage`.
|
|
30
|
-
*/
|
|
31
23
|
export declare function generateComposePreview(technologies: ComposeTechnology[], projectName: string): ComposePreviewResult;
|
|
32
24
|
export {};
|
|
33
25
|
//# sourceMappingURL=compose-generator.d.ts.map
|
|
@@ -1,17 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
* Compose Generator — Pure function that generates docker-compose.yml content.
|
|
3
|
-
* No disk I/O — returns structured data for preview or writing.
|
|
4
|
-
*/
|
|
1
|
+
// No disk I/O — returns structured data, caller decides what to write.
|
|
5
2
|
const DATA_MOUNTS = {
|
|
6
3
|
postgresql: "/var/lib/postgresql/data",
|
|
7
4
|
mysql: "/var/lib/mysql",
|
|
8
5
|
mongodb: "/data/db",
|
|
9
6
|
redis: "/data",
|
|
10
7
|
};
|
|
11
|
-
/**
|
|
12
|
-
* Generate a docker-compose.yml preview from a list of technologies.
|
|
13
|
-
* Only includes technologies that have a `dockerImage`.
|
|
14
|
-
*/
|
|
15
8
|
export function generateComposePreview(technologies, projectName) {
|
|
16
9
|
const services = [];
|
|
17
10
|
const ports = {};
|
|
@@ -26,13 +19,11 @@ export function generateComposePreview(technologies, projectName) {
|
|
|
26
19
|
lines.push(` ${tech.id}:`);
|
|
27
20
|
lines.push(` image: ${tech.dockerImage}`);
|
|
28
21
|
lines.push(" restart: unless-stopped");
|
|
29
|
-
// Ports
|
|
30
22
|
if (port) {
|
|
31
23
|
lines.push(" ports:");
|
|
32
24
|
lines.push(` - "${port}:${port}"`);
|
|
33
25
|
ports[tech.id] = port;
|
|
34
26
|
}
|
|
35
|
-
// Environment variables
|
|
36
27
|
const envVars = tech.envVars ? Object.entries(tech.envVars) : [];
|
|
37
28
|
if (envVars.length > 0) {
|
|
38
29
|
lines.push(" environment:");
|
|
@@ -40,7 +31,6 @@ export function generateComposePreview(technologies, projectName) {
|
|
|
40
31
|
lines.push(` ${key}: "${value}"`);
|
|
41
32
|
}
|
|
42
33
|
}
|
|
43
|
-
// Health check
|
|
44
34
|
if (tech.healthCheck) {
|
|
45
35
|
lines.push(" healthcheck:");
|
|
46
36
|
if (tech.healthCheck.command) {
|
|
@@ -59,7 +49,6 @@ export function generateComposePreview(technologies, projectName) {
|
|
|
59
49
|
lines.push(` retries: ${tech.healthCheck.retries}`);
|
|
60
50
|
}
|
|
61
51
|
}
|
|
62
|
-
// Volumes for databases
|
|
63
52
|
const mountPath = DATA_MOUNTS[tech.id];
|
|
64
53
|
if (mountPath && tech.category === "database") {
|
|
65
54
|
const volName = `${tech.id}_data`;
|
|
@@ -67,12 +56,10 @@ export function generateComposePreview(technologies, projectName) {
|
|
|
67
56
|
lines.push(` - ${volName}:${mountPath}`);
|
|
68
57
|
volumes.push(volName);
|
|
69
58
|
}
|
|
70
|
-
// Network
|
|
71
59
|
lines.push(" networks:");
|
|
72
60
|
lines.push(` - ${networkName}`);
|
|
73
61
|
lines.push("");
|
|
74
62
|
}
|
|
75
|
-
// Named volumes
|
|
76
63
|
if (volumes.length > 0) {
|
|
77
64
|
lines.push("volumes:");
|
|
78
65
|
for (const vol of volumes) {
|
|
@@ -80,7 +67,6 @@ export function generateComposePreview(technologies, projectName) {
|
|
|
80
67
|
}
|
|
81
68
|
lines.push("");
|
|
82
69
|
}
|
|
83
|
-
// Network
|
|
84
70
|
lines.push("networks:");
|
|
85
71
|
lines.push(` ${networkName}:`);
|
|
86
72
|
lines.push(" driver: bridge");
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export type LicenseTier = "community" | "pro" | "enterprise";
|
|
2
|
+
export interface LicenseInfo {
|
|
3
|
+
tier: LicenseTier;
|
|
4
|
+
email: string | null;
|
|
5
|
+
validUntil: string | null;
|
|
6
|
+
active: boolean;
|
|
7
|
+
}
|
|
8
|
+
export interface FeatureGate {
|
|
9
|
+
feature: string;
|
|
10
|
+
requiredTier: LicenseTier;
|
|
11
|
+
description: string;
|
|
12
|
+
}
|
|
13
|
+
export declare function activateLicense(key: string, email: string): {
|
|
14
|
+
success: boolean;
|
|
15
|
+
message: string;
|
|
16
|
+
};
|
|
17
|
+
export declare function deactivateLicense(): {
|
|
18
|
+
success: boolean;
|
|
19
|
+
message: string;
|
|
20
|
+
};
|
|
21
|
+
export declare function getLicenseInfo(): LicenseInfo;
|
|
22
|
+
export declare function checkFeatureAccess(feature: string): {
|
|
23
|
+
allowed: boolean;
|
|
24
|
+
requiredTier: LicenseTier;
|
|
25
|
+
message: string;
|
|
26
|
+
};
|
|
27
|
+
export declare function listFeatures(): FeatureGate[];
|
|
28
|
+
export declare function getFeatureTier(feature: string): LicenseTier;
|
|
29
|
+
//# sourceMappingURL=license-manager.d.ts.map
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import * as fs from "node:fs";
|
|
3
|
+
import * as path from "node:path";
|
|
4
|
+
const PRO_FEATURES = [
|
|
5
|
+
{
|
|
6
|
+
feature: "ai",
|
|
7
|
+
requiredTier: "pro",
|
|
8
|
+
description: "AI-powered suggestions, README generation, and architecture explanations",
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
feature: "infra",
|
|
12
|
+
requiredTier: "pro",
|
|
13
|
+
description: "Infrastructure as Code generation (VPS, AWS, GCP)",
|
|
14
|
+
},
|
|
15
|
+
{ feature: "cost", requiredTier: "pro", description: "Hosting cost estimation across providers" },
|
|
16
|
+
{ feature: "benchmark", requiredTier: "pro", description: "Stack performance profiling" },
|
|
17
|
+
{ feature: "migrate", requiredTier: "pro", description: "Technology migration planner" },
|
|
18
|
+
{ feature: "deploy", requiredTier: "pro", description: "Deployment configuration generation" },
|
|
19
|
+
{ feature: "plugin-install", requiredTier: "pro", description: "Install community plugins" },
|
|
20
|
+
{ feature: "cloud-sync", requiredTier: "enterprise", description: "Sync stacks across machines" },
|
|
21
|
+
{
|
|
22
|
+
feature: "team-standards",
|
|
23
|
+
requiredTier: "enterprise",
|
|
24
|
+
description: "Enforce team-wide stack standards",
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
feature: "audit-log",
|
|
28
|
+
requiredTier: "enterprise",
|
|
29
|
+
description: "Detailed audit trail of all operations",
|
|
30
|
+
},
|
|
31
|
+
];
|
|
32
|
+
const TIER_HIERARCHY = {
|
|
33
|
+
community: 0,
|
|
34
|
+
pro: 1,
|
|
35
|
+
enterprise: 2,
|
|
36
|
+
};
|
|
37
|
+
function getLicensePath() {
|
|
38
|
+
const home = process.env.HOME || process.env.USERPROFILE || "~";
|
|
39
|
+
return path.join(home, ".stackweld", "license.json");
|
|
40
|
+
}
|
|
41
|
+
function hashKey(key) {
|
|
42
|
+
return createHash("sha256").update(key).digest("hex");
|
|
43
|
+
}
|
|
44
|
+
function validateKeyFormat(key) {
|
|
45
|
+
// Format: SW-PRO-XXXX-XXXX-XXXX or SW-ENT-XXXX-XXXX-XXXX
|
|
46
|
+
return /^SW-(PRO|ENT)-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{4}$/.test(key);
|
|
47
|
+
}
|
|
48
|
+
function tierFromKey(key) {
|
|
49
|
+
if (key.startsWith("SW-ENT-"))
|
|
50
|
+
return "enterprise";
|
|
51
|
+
if (key.startsWith("SW-PRO-"))
|
|
52
|
+
return "pro";
|
|
53
|
+
return "community";
|
|
54
|
+
}
|
|
55
|
+
export function activateLicense(key, email) {
|
|
56
|
+
if (!validateKeyFormat(key)) {
|
|
57
|
+
return {
|
|
58
|
+
success: false,
|
|
59
|
+
message: "Invalid license key format. Expected: SW-PRO-XXXX-XXXX-XXXX",
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
const tier = tierFromKey(key);
|
|
63
|
+
const licensePath = getLicensePath();
|
|
64
|
+
const dir = path.dirname(licensePath);
|
|
65
|
+
if (!fs.existsSync(dir))
|
|
66
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
67
|
+
const license = {
|
|
68
|
+
keyHash: hashKey(key),
|
|
69
|
+
tier,
|
|
70
|
+
email,
|
|
71
|
+
activatedAt: new Date().toISOString(),
|
|
72
|
+
validUntil: null,
|
|
73
|
+
};
|
|
74
|
+
fs.writeFileSync(licensePath, JSON.stringify(license, null, 2), "utf-8");
|
|
75
|
+
return {
|
|
76
|
+
success: true,
|
|
77
|
+
message: `${tier.charAt(0).toUpperCase() + tier.slice(1)} license activated for ${email}`,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
export function deactivateLicense() {
|
|
81
|
+
const licensePath = getLicensePath();
|
|
82
|
+
if (fs.existsSync(licensePath)) {
|
|
83
|
+
fs.unlinkSync(licensePath);
|
|
84
|
+
return { success: true, message: "License deactivated. Reverted to Community tier." };
|
|
85
|
+
}
|
|
86
|
+
return { success: false, message: "No active license found." };
|
|
87
|
+
}
|
|
88
|
+
export function getLicenseInfo() {
|
|
89
|
+
const licensePath = getLicensePath();
|
|
90
|
+
if (!fs.existsSync(licensePath)) {
|
|
91
|
+
return { tier: "community", email: null, validUntil: null, active: false };
|
|
92
|
+
}
|
|
93
|
+
try {
|
|
94
|
+
const data = JSON.parse(fs.readFileSync(licensePath, "utf-8"));
|
|
95
|
+
const expired = data.validUntil ? new Date(data.validUntil) < new Date() : false;
|
|
96
|
+
return {
|
|
97
|
+
tier: expired ? "community" : data.tier,
|
|
98
|
+
email: data.email,
|
|
99
|
+
validUntil: data.validUntil,
|
|
100
|
+
active: !expired,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
return { tier: "community", email: null, validUntil: null, active: false };
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
export function checkFeatureAccess(feature) {
|
|
108
|
+
const gate = PRO_FEATURES.find((f) => f.feature === feature);
|
|
109
|
+
if (!gate)
|
|
110
|
+
return { allowed: true, requiredTier: "community", message: "" };
|
|
111
|
+
const license = getLicenseInfo();
|
|
112
|
+
const userLevel = TIER_HIERARCHY[license.tier];
|
|
113
|
+
const requiredLevel = TIER_HIERARCHY[gate.requiredTier];
|
|
114
|
+
if (userLevel >= requiredLevel) {
|
|
115
|
+
return { allowed: true, requiredTier: gate.requiredTier, message: "" };
|
|
116
|
+
}
|
|
117
|
+
return {
|
|
118
|
+
allowed: false,
|
|
119
|
+
requiredTier: gate.requiredTier,
|
|
120
|
+
message: `"${gate.description}" requires a ${gate.requiredTier} license. Upgrade at https://stackweld.dev/pro`,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
export function listFeatures() {
|
|
124
|
+
return PRO_FEATURES;
|
|
125
|
+
}
|
|
126
|
+
export function getFeatureTier(feature) {
|
|
127
|
+
const gate = PRO_FEATURES.find((f) => f.feature === feature);
|
|
128
|
+
return gate?.requiredTier ?? "community";
|
|
129
|
+
}
|
|
130
|
+
//# sourceMappingURL=license-manager.js.map
|
|
@@ -1,16 +1,8 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Stack Engine — CRUD operations for stack definitions.
|
|
3
|
-
* Handles creation, validation, versioning, and persistence.
|
|
4
|
-
*/
|
|
5
1
|
import type { StackDefinition, StackProfile, StackTechnology, StackVersion, ValidationResult } from "../types/index.js";
|
|
6
2
|
import type { RulesEngine } from "./rules-engine.js";
|
|
7
3
|
export declare class StackEngine {
|
|
8
4
|
private rules;
|
|
9
5
|
constructor(rules: RulesEngine);
|
|
10
|
-
/**
|
|
11
|
-
* Create a new stack definition.
|
|
12
|
-
* Validates technologies and auto-resolves dependencies.
|
|
13
|
-
*/
|
|
14
6
|
create(opts: {
|
|
15
7
|
name: string;
|
|
16
8
|
description?: string;
|
|
@@ -21,21 +13,9 @@ export declare class StackEngine {
|
|
|
21
13
|
stack: StackDefinition;
|
|
22
14
|
validation: ValidationResult;
|
|
23
15
|
};
|
|
24
|
-
/**
|
|
25
|
-
* Get a stack by ID.
|
|
26
|
-
*/
|
|
27
16
|
get(id: string): StackDefinition | null;
|
|
28
|
-
/**
|
|
29
|
-
* List all stacks.
|
|
30
|
-
*/
|
|
31
17
|
list(): StackDefinition[];
|
|
32
|
-
/**
|
|
33
|
-
* Delete a stack.
|
|
34
|
-
*/
|
|
35
18
|
delete(id: string): boolean;
|
|
36
|
-
/**
|
|
37
|
-
* Update a stack. Auto-increments version and saves snapshot.
|
|
38
|
-
*/
|
|
39
19
|
update(id: string, changes: Partial<Pick<StackDefinition, "name" | "description" | "profile" | "technologies" | "tags">>): {
|
|
40
20
|
stack: StackDefinition;
|
|
41
21
|
validation: ValidationResult;
|
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Stack Engine — CRUD operations for stack definitions.
|
|
3
|
-
* Handles creation, validation, versioning, and persistence.
|
|
4
|
-
*/
|
|
5
1
|
import { randomUUID } from "node:crypto";
|
|
6
2
|
import { getDatabase } from "../db/database.js";
|
|
7
3
|
export class StackEngine {
|
|
@@ -9,13 +5,8 @@ export class StackEngine {
|
|
|
9
5
|
constructor(rules) {
|
|
10
6
|
this.rules = rules;
|
|
11
7
|
}
|
|
12
|
-
/**
|
|
13
|
-
* Create a new stack definition.
|
|
14
|
-
* Validates technologies and auto-resolves dependencies.
|
|
15
|
-
*/
|
|
16
8
|
create(opts) {
|
|
17
9
|
const validation = this.rules.validate(opts.technologies);
|
|
18
|
-
// Add auto-resolved dependencies
|
|
19
10
|
const allTechs = [...opts.technologies];
|
|
20
11
|
for (const depId of validation.resolvedDependencies) {
|
|
21
12
|
const tech = this.rules.getTechnology(depId);
|
|
@@ -27,7 +18,6 @@ export class StackEngine {
|
|
|
27
18
|
});
|
|
28
19
|
}
|
|
29
20
|
}
|
|
30
|
-
// Apply port assignments to existing techs
|
|
31
21
|
for (const t of allTechs) {
|
|
32
22
|
if (validation.portAssignments[t.technologyId]) {
|
|
33
23
|
t.port = validation.portAssignments[t.technologyId];
|
|
@@ -50,9 +40,6 @@ export class StackEngine {
|
|
|
50
40
|
}
|
|
51
41
|
return { stack, validation };
|
|
52
42
|
}
|
|
53
|
-
/**
|
|
54
|
-
* Get a stack by ID.
|
|
55
|
-
*/
|
|
56
43
|
get(id) {
|
|
57
44
|
const db = getDatabase();
|
|
58
45
|
const row = db.prepare("SELECT * FROM stacks WHERE id = ?").get(id);
|
|
@@ -78,25 +65,16 @@ export class StackEngine {
|
|
|
78
65
|
})),
|
|
79
66
|
};
|
|
80
67
|
}
|
|
81
|
-
/**
|
|
82
|
-
* List all stacks.
|
|
83
|
-
*/
|
|
84
68
|
list() {
|
|
85
69
|
const db = getDatabase();
|
|
86
70
|
const rows = db.prepare("SELECT id FROM stacks ORDER BY updated_at DESC").all();
|
|
87
71
|
return rows.map((r) => this.get(r.id)).filter(Boolean);
|
|
88
72
|
}
|
|
89
|
-
/**
|
|
90
|
-
* Delete a stack.
|
|
91
|
-
*/
|
|
92
73
|
delete(id) {
|
|
93
74
|
const db = getDatabase();
|
|
94
75
|
const result = db.prepare("DELETE FROM stacks WHERE id = ?").run(id);
|
|
95
76
|
return result.changes > 0;
|
|
96
77
|
}
|
|
97
|
-
/**
|
|
98
|
-
* Update a stack. Auto-increments version and saves snapshot.
|
|
99
|
-
*/
|
|
100
78
|
update(id, changes) {
|
|
101
79
|
const existing = this.get(id);
|
|
102
80
|
if (!existing)
|
|
@@ -112,7 +90,6 @@ export class StackEngine {
|
|
|
112
90
|
updated_at = ?, tags = ?
|
|
113
91
|
WHERE id = ?
|
|
114
92
|
`).run(changes.name || existing.name, changes.description ?? existing.description, changes.profile || existing.profile, newVersion, now, JSON.stringify(changes.tags || existing.tags), id);
|
|
115
|
-
// Replace technologies
|
|
116
93
|
db.prepare("DELETE FROM stack_technologies WHERE stack_id = ?").run(id);
|
|
117
94
|
for (const t of techs) {
|
|
118
95
|
db.prepare(`
|
|
@@ -120,7 +97,6 @@ export class StackEngine {
|
|
|
120
97
|
VALUES (?, ?, ?, ?, ?)
|
|
121
98
|
`).run(id, t.technologyId, t.version, t.port || null, JSON.stringify(t.config || {}));
|
|
122
99
|
}
|
|
123
|
-
// Save version snapshot
|
|
124
100
|
const updatedStack = this.get(id);
|
|
125
101
|
this.saveVersionSnapshot(updatedStack, `Updated to v${newVersion}`);
|
|
126
102
|
return { stack: updatedStack, validation };
|
package/dist/index.d.ts
CHANGED
|
@@ -11,6 +11,8 @@ export type { HealthCheck, HealthReport } from "./engine/health-checker.js";
|
|
|
11
11
|
export { checkProjectHealth } from "./engine/health-checker.js";
|
|
12
12
|
export type { DeployTarget, InfraOutput } from "./engine/infra-generator.js";
|
|
13
13
|
export { generateInfra } from "./engine/infra-generator.js";
|
|
14
|
+
export type { FeatureGate, LicenseInfo, LicenseTier } from "./engine/license-manager.js";
|
|
15
|
+
export { activateLicense, checkFeatureAccess, deactivateLicense, getLicenseInfo, listFeatures, } from "./engine/license-manager.js";
|
|
14
16
|
export type { MigrationPlan, MigrationStep } from "./engine/migration-planner.js";
|
|
15
17
|
export { planMigration } from "./engine/migration-planner.js";
|
|
16
18
|
export type { PerformanceProfile, TechPerformance, } from "./engine/performance-profiler.js";
|
package/dist/index.js
CHANGED
|
@@ -7,6 +7,7 @@ export { estimateCost } from "./engine/cost-estimator.js";
|
|
|
7
7
|
export { checkDangerous, parseEnvFile, syncEnv } from "./engine/env-analyzer.js";
|
|
8
8
|
export { checkProjectHealth } from "./engine/health-checker.js";
|
|
9
9
|
export { generateInfra } from "./engine/infra-generator.js";
|
|
10
|
+
export { activateLicense, checkFeatureAccess, deactivateLicense, getLicenseInfo, listFeatures, } from "./engine/license-manager.js";
|
|
10
11
|
export { planMigration } from "./engine/migration-planner.js";
|
|
11
12
|
export { profilePerformance } from "./engine/performance-profiler.js";
|
|
12
13
|
export { getPluginDir, getPluginInfo, installPlugin, listPlugins, loadPlugin, loadPluginTechnologies, removePlugin, } from "./engine/plugin-loader.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stackweld/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Core engine for Stackweld — rules, scaffold orchestrator, runtime manager, tech installer, and SQLite persistence.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Orlando Fernandez <hello@xplustechnologies.com>",
|
package/LICENSE
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2025-2026 Orlando Fernandez / XPlus Technologies LLC
|
|
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.
|