@jaypie/mcp 0.2.1 → 0.2.2
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/dist/index.js +1 -1
- package/package.json +3 -4
- package/prompts/Jaypie_Vocabulary_Package.md +451 -0
- package/LICENSE.txt +0 -21
package/dist/index.js
CHANGED
|
@@ -797,7 +797,7 @@ async function searchDatadogRum(credentials, options = {}, logger = nullLogger)
|
|
|
797
797
|
});
|
|
798
798
|
}
|
|
799
799
|
|
|
800
|
-
const BUILD_VERSION_STRING = "@jaypie/mcp@0.2.
|
|
800
|
+
const BUILD_VERSION_STRING = "@jaypie/mcp@0.2.2#fd3043b3"
|
|
801
801
|
;
|
|
802
802
|
const __filename$1 = fileURLToPath(import.meta.url);
|
|
803
803
|
const __dirname$1 = path.dirname(__filename$1);
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jaypie/mcp",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"description": "Jaypie MCP",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
|
-
"url": "https://github.com/finlaysonstudio/jaypie"
|
|
7
|
+
"url": "git+https://github.com/finlaysonstudio/jaypie.git"
|
|
8
8
|
},
|
|
9
9
|
"license": "MIT",
|
|
10
10
|
"author": "Finlayson Studio",
|
|
@@ -49,6 +49,5 @@
|
|
|
49
49
|
},
|
|
50
50
|
"publishConfig": {
|
|
51
51
|
"access": "public"
|
|
52
|
-
}
|
|
53
|
-
"gitHead": "22724b6031f0e737ba7fa4acf7df7c2391e2e2f4"
|
|
52
|
+
}
|
|
54
53
|
}
|
|
@@ -0,0 +1,451 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Complete guide to using Jaypie Vocabulary for type coercion, service handlers, and Commander CLI integration
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Jaypie Vocabulary Package
|
|
6
|
+
|
|
7
|
+
Jaypie Vocabulary (`@jaypie/vocabulary`) provides type coercion utilities and service handler patterns for consistent input handling across Jaypie applications. It includes adapters for integrating service handlers with Commander.js CLIs.
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install @jaypie/vocabulary
|
|
13
|
+
# For CLI integration:
|
|
14
|
+
npm install commander
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Core Concepts
|
|
18
|
+
|
|
19
|
+
### Design Philosophy
|
|
20
|
+
|
|
21
|
+
Vocabulary follows the "Fabric" philosophy:
|
|
22
|
+
- **Smooth, pliable** - Things that feel right should work
|
|
23
|
+
- **Catch bad passes** - Invalid inputs throw clear errors
|
|
24
|
+
|
|
25
|
+
This means `"true"` works where `true` is expected, `"42"` works where `42` is expected, and invalid conversions fail fast with `BadRequestError`.
|
|
26
|
+
|
|
27
|
+
## serviceHandler
|
|
28
|
+
|
|
29
|
+
Factory function that creates validated service endpoints with automatic type coercion.
|
|
30
|
+
|
|
31
|
+
### Basic Usage
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
import { serviceHandler } from "@jaypie/vocabulary";
|
|
35
|
+
|
|
36
|
+
const divisionHandler = serviceHandler({
|
|
37
|
+
alias: "division",
|
|
38
|
+
description: "Divides two numbers",
|
|
39
|
+
input: {
|
|
40
|
+
numerator: {
|
|
41
|
+
type: Number,
|
|
42
|
+
default: 12,
|
|
43
|
+
description: "Number on top",
|
|
44
|
+
},
|
|
45
|
+
denominator: {
|
|
46
|
+
type: Number,
|
|
47
|
+
default: 3,
|
|
48
|
+
description: "Number on bottom",
|
|
49
|
+
validate: (value) => value !== 0,
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
service: ({ numerator, denominator }) => numerator / denominator,
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
await divisionHandler(); // → 4
|
|
56
|
+
await divisionHandler({ numerator: 24 }); // → 8
|
|
57
|
+
await divisionHandler({ numerator: "14", denominator: "7" }); // → 2 (coerced)
|
|
58
|
+
await divisionHandler('{"numerator": "18"}'); // → 6 (JSON parsed)
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Handler Properties
|
|
62
|
+
|
|
63
|
+
Config properties are attached directly to the handler for introspection:
|
|
64
|
+
|
|
65
|
+
```typescript
|
|
66
|
+
const handler = serviceHandler({
|
|
67
|
+
alias: "greet",
|
|
68
|
+
description: "Greet a user",
|
|
69
|
+
input: { name: { type: String } },
|
|
70
|
+
service: ({ name }) => `Hello, ${name}!`,
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
handler.alias; // "greet"
|
|
74
|
+
handler.description; // "Greet a user"
|
|
75
|
+
handler.input; // { name: { type: String } }
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Input Field Definition
|
|
79
|
+
|
|
80
|
+
| Property | Type | Description |
|
|
81
|
+
|----------|------|-------------|
|
|
82
|
+
| `type` | `CoercionType` | Required. The target type for coercion |
|
|
83
|
+
| `default` | `unknown` | Default value if not provided |
|
|
84
|
+
| `description` | `string` | Field description (used in CLI help) |
|
|
85
|
+
| `required` | `boolean` | Whether field is required (default: true unless default set) |
|
|
86
|
+
| `validate` | `function \| RegExp \| array` | Validation after coercion |
|
|
87
|
+
| `flag` | `string` | Override long flag name for Commander.js |
|
|
88
|
+
| `letter` | `string` | Short switch letter for Commander.js |
|
|
89
|
+
|
|
90
|
+
### Validation-Only Mode
|
|
91
|
+
|
|
92
|
+
When no `service` function is provided, the handler returns the processed input:
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
const validateUser = serviceHandler({
|
|
96
|
+
input: {
|
|
97
|
+
age: { type: Number, validate: (v) => v >= 18 },
|
|
98
|
+
email: { type: /^[^@]+@[^@]+\.[^@]+$/ },
|
|
99
|
+
role: { type: ["admin", "user", "guest"], default: "user" },
|
|
100
|
+
},
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
await validateUser({ age: "25", email: "bob@example.com" });
|
|
104
|
+
// → { age: 25, email: "bob@example.com", role: "user" }
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Type Coercion
|
|
108
|
+
|
|
109
|
+
### Supported Types
|
|
110
|
+
|
|
111
|
+
| Type | Aliases | Description |
|
|
112
|
+
|------|---------|-------------|
|
|
113
|
+
| `String` | `"string"`, `""` | String coercion |
|
|
114
|
+
| `Number` | `"number"` | Number coercion |
|
|
115
|
+
| `Boolean` | `"boolean"` | Boolean coercion |
|
|
116
|
+
| `Array` | `"array"`, `[]` | Array coercion |
|
|
117
|
+
| `Object` | `"object"`, `{}` | Object coercion |
|
|
118
|
+
| `[String]` | `[""]` | Typed array of strings |
|
|
119
|
+
| `[Number]` | - | Typed array of numbers |
|
|
120
|
+
| `[Boolean]` | - | Typed array of booleans |
|
|
121
|
+
| `[Object]` | `[{}]` | Typed array of objects |
|
|
122
|
+
| `/regex/` | - | String with regex validation |
|
|
123
|
+
| `["a", "b"]` | - | Validated string (must match) |
|
|
124
|
+
| `[1, 2, 3]` | - | Validated number (must match) |
|
|
125
|
+
|
|
126
|
+
### Coercion Examples
|
|
127
|
+
|
|
128
|
+
```typescript
|
|
129
|
+
import { coerce } from "@jaypie/vocabulary";
|
|
130
|
+
|
|
131
|
+
// Boolean coercion
|
|
132
|
+
coerce("true", Boolean); // → true
|
|
133
|
+
coerce("false", Boolean); // → false
|
|
134
|
+
coerce(1, Boolean); // → true
|
|
135
|
+
coerce(0, Boolean); // → false
|
|
136
|
+
|
|
137
|
+
// Number coercion
|
|
138
|
+
coerce("42", Number); // → 42
|
|
139
|
+
coerce("true", Number); // → 1
|
|
140
|
+
coerce("false", Number); // → 0
|
|
141
|
+
|
|
142
|
+
// String coercion
|
|
143
|
+
coerce(true, String); // → "true"
|
|
144
|
+
coerce(42, String); // → "42"
|
|
145
|
+
|
|
146
|
+
// Array coercion
|
|
147
|
+
coerce("1,2,3", [Number]); // → [1, 2, 3]
|
|
148
|
+
coerce("a\tb\tc", [String]); // → ["a", "b", "c"]
|
|
149
|
+
coerce([1, 2], [String]); // → ["1", "2"]
|
|
150
|
+
|
|
151
|
+
// Unwrapping
|
|
152
|
+
coerce({ value: "42" }, Number); // → 42
|
|
153
|
+
coerce(["true"], Boolean); // → true
|
|
154
|
+
coerce('{"value": 5}', Number); // → 5
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### RegExp Type Shorthand
|
|
158
|
+
|
|
159
|
+
A bare RegExp coerces to String and validates:
|
|
160
|
+
|
|
161
|
+
```typescript
|
|
162
|
+
const handler = serviceHandler({
|
|
163
|
+
input: {
|
|
164
|
+
email: { type: /^[^@]+@[^@]+\.[^@]+$/ },
|
|
165
|
+
},
|
|
166
|
+
service: ({ email }) => email,
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
await handler({ email: "bob@example.com" }); // ✓
|
|
170
|
+
await handler({ email: "invalid" }); // ✗ BadRequestError
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### Validated Type Shorthand
|
|
174
|
+
|
|
175
|
+
Arrays of literals validate against allowed values:
|
|
176
|
+
|
|
177
|
+
```typescript
|
|
178
|
+
// String validation
|
|
179
|
+
input: {
|
|
180
|
+
currency: { type: ["usd", "eur", "gbp"] }, // Must be one of these
|
|
181
|
+
pattern: { type: [/^test-/, "special"] }, // Matches regex OR equals "special"
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Number validation
|
|
185
|
+
input: {
|
|
186
|
+
priority: { type: [1, 2, 3, 4, 5] }, // Must be 1-5
|
|
187
|
+
}
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
## Commander.js Integration
|
|
191
|
+
|
|
192
|
+
### registerServiceCommand (Recommended)
|
|
193
|
+
|
|
194
|
+
The simplest way to register a service handler as a Commander command:
|
|
195
|
+
|
|
196
|
+
```typescript
|
|
197
|
+
import { Command } from "commander";
|
|
198
|
+
import { serviceHandler } from "@jaypie/vocabulary";
|
|
199
|
+
import { registerServiceCommand } from "@jaypie/vocabulary/commander";
|
|
200
|
+
|
|
201
|
+
const handler = serviceHandler({
|
|
202
|
+
alias: "greet",
|
|
203
|
+
description: "Greet a user",
|
|
204
|
+
input: {
|
|
205
|
+
userName: { type: String, flag: "user", letter: "u" },
|
|
206
|
+
loud: { type: Boolean, letter: "l", default: false },
|
|
207
|
+
},
|
|
208
|
+
service: ({ loud, userName }) => {
|
|
209
|
+
const greeting = `Hello, ${userName}!`;
|
|
210
|
+
console.log(loud ? greeting.toUpperCase() : greeting);
|
|
211
|
+
},
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
const program = new Command();
|
|
215
|
+
registerServiceCommand({ handler, program });
|
|
216
|
+
program.parse();
|
|
217
|
+
// Usage: greet --user Alice -l
|
|
218
|
+
// Output: HELLO, ALICE!
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
### registerServiceCommand Options
|
|
222
|
+
|
|
223
|
+
| Option | Type | Description |
|
|
224
|
+
|--------|------|-------------|
|
|
225
|
+
| `handler` | `ServiceHandlerFunction` | Required. The service handler |
|
|
226
|
+
| `program` | `Command` | Required. Commander program or command |
|
|
227
|
+
| `name` | `string` | Override command name (default: handler.alias) |
|
|
228
|
+
| `description` | `string` | Override description (default: handler.description) |
|
|
229
|
+
| `exclude` | `string[]` | Field names to exclude from options |
|
|
230
|
+
| `overrides` | `Record<string, override>` | Per-field option overrides |
|
|
231
|
+
|
|
232
|
+
### Input Flag and Letter Properties
|
|
233
|
+
|
|
234
|
+
Define CLI flags directly in input definitions:
|
|
235
|
+
|
|
236
|
+
```typescript
|
|
237
|
+
input: {
|
|
238
|
+
userName: {
|
|
239
|
+
type: String,
|
|
240
|
+
flag: "user", // Long flag: --user (instead of --user-name)
|
|
241
|
+
letter: "u", // Short flag: -u
|
|
242
|
+
description: "User name to greet",
|
|
243
|
+
},
|
|
244
|
+
verbose: {
|
|
245
|
+
type: Boolean,
|
|
246
|
+
letter: "v", // -v
|
|
247
|
+
},
|
|
248
|
+
}
|
|
249
|
+
// Generates: --user <userName>, -u and --verbose, -v
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
### Manual Integration
|
|
253
|
+
|
|
254
|
+
For more control, use `createCommanderOptions` and `parseCommanderOptions`:
|
|
255
|
+
|
|
256
|
+
```typescript
|
|
257
|
+
import { Command } from "commander";
|
|
258
|
+
import { serviceHandler } from "@jaypie/vocabulary";
|
|
259
|
+
import {
|
|
260
|
+
createCommanderOptions,
|
|
261
|
+
parseCommanderOptions,
|
|
262
|
+
} from "@jaypie/vocabulary/commander";
|
|
263
|
+
|
|
264
|
+
const handler = serviceHandler({
|
|
265
|
+
input: {
|
|
266
|
+
userName: { type: String, description: "User name" },
|
|
267
|
+
maxRetries: { type: Number, default: 3 },
|
|
268
|
+
verbose: { type: Boolean },
|
|
269
|
+
},
|
|
270
|
+
service: (input) => console.log(input),
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
const program = new Command();
|
|
274
|
+
|
|
275
|
+
// Create options from handler input
|
|
276
|
+
const { options } = createCommanderOptions(handler.input, {
|
|
277
|
+
exclude: ["internalField"],
|
|
278
|
+
overrides: {
|
|
279
|
+
userName: { short: "u", description: "Override description" },
|
|
280
|
+
},
|
|
281
|
+
});
|
|
282
|
+
options.forEach((opt) => program.addOption(opt));
|
|
283
|
+
|
|
284
|
+
// Wire up action
|
|
285
|
+
program.action(async (opts) => {
|
|
286
|
+
const input = parseCommanderOptions(opts, { input: handler.input });
|
|
287
|
+
await handler(input);
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
program.parse();
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
### Boolean Flag Behavior
|
|
294
|
+
|
|
295
|
+
Commander.js automatically handles boolean flags:
|
|
296
|
+
- `--verbose` sets to `true`
|
|
297
|
+
- `--no-verbose` sets to `false` (for flags with `default: true`)
|
|
298
|
+
|
|
299
|
+
## Complete CLI Example
|
|
300
|
+
|
|
301
|
+
```typescript
|
|
302
|
+
// src/commands/evaluate.ts
|
|
303
|
+
import { Command } from "commander";
|
|
304
|
+
import { serviceHandler } from "@jaypie/vocabulary";
|
|
305
|
+
import { registerServiceCommand } from "@jaypie/vocabulary/commander";
|
|
306
|
+
|
|
307
|
+
export const evaluateHandler = serviceHandler({
|
|
308
|
+
alias: "evaluate",
|
|
309
|
+
description: "Run an evaluation job",
|
|
310
|
+
input: {
|
|
311
|
+
jobId: {
|
|
312
|
+
type: String,
|
|
313
|
+
flag: "job",
|
|
314
|
+
letter: "j",
|
|
315
|
+
description: "Job identifier",
|
|
316
|
+
},
|
|
317
|
+
priority: {
|
|
318
|
+
type: [1, 2, 3, 4, 5],
|
|
319
|
+
default: 3,
|
|
320
|
+
letter: "p",
|
|
321
|
+
description: "Job priority (1-5)",
|
|
322
|
+
},
|
|
323
|
+
tags: {
|
|
324
|
+
type: [String],
|
|
325
|
+
letter: "t",
|
|
326
|
+
required: false,
|
|
327
|
+
description: "Tags to apply",
|
|
328
|
+
},
|
|
329
|
+
dryRun: {
|
|
330
|
+
type: Boolean,
|
|
331
|
+
letter: "d",
|
|
332
|
+
default: false,
|
|
333
|
+
description: "Run without executing",
|
|
334
|
+
},
|
|
335
|
+
},
|
|
336
|
+
service: async ({ dryRun, jobId, priority, tags }) => {
|
|
337
|
+
console.log(`Running job ${jobId} with priority ${priority}`);
|
|
338
|
+
if (tags?.length) console.log(`Tags: ${tags.join(", ")}`);
|
|
339
|
+
if (dryRun) {
|
|
340
|
+
console.log("(dry run - no changes made)");
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
// Execute job...
|
|
344
|
+
},
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
export function evaluateCommand(program: Command): Command {
|
|
348
|
+
registerServiceCommand({ handler: evaluateHandler, program });
|
|
349
|
+
return program;
|
|
350
|
+
}
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
Usage:
|
|
354
|
+
```bash
|
|
355
|
+
# Required job, default priority
|
|
356
|
+
cli evaluate --job abc123
|
|
357
|
+
|
|
358
|
+
# With all options
|
|
359
|
+
cli evaluate -j abc123 -p 1 -t urgent -t critical --dry-run
|
|
360
|
+
|
|
361
|
+
# Help
|
|
362
|
+
cli evaluate --help
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
## TypeScript Types
|
|
366
|
+
|
|
367
|
+
```typescript
|
|
368
|
+
import type {
|
|
369
|
+
// Coercion types
|
|
370
|
+
CoercionType,
|
|
371
|
+
ScalarType,
|
|
372
|
+
CompositeType,
|
|
373
|
+
TypedArrayType,
|
|
374
|
+
ValidatedStringType,
|
|
375
|
+
ValidatedNumberType,
|
|
376
|
+
RegExpType,
|
|
377
|
+
ArrayElementType,
|
|
378
|
+
|
|
379
|
+
// Service handler types
|
|
380
|
+
InputFieldDefinition,
|
|
381
|
+
ValidateFunction,
|
|
382
|
+
ServiceFunction,
|
|
383
|
+
ServiceHandlerConfig,
|
|
384
|
+
ServiceHandlerFunction,
|
|
385
|
+
} from "@jaypie/vocabulary";
|
|
386
|
+
|
|
387
|
+
import type {
|
|
388
|
+
// Commander adapter types
|
|
389
|
+
CommanderOptionOverride,
|
|
390
|
+
CreateCommanderOptionsConfig,
|
|
391
|
+
CreateCommanderOptionsResult,
|
|
392
|
+
ParseCommanderOptionsConfig,
|
|
393
|
+
RegisterServiceCommandConfig,
|
|
394
|
+
RegisterServiceCommandResult,
|
|
395
|
+
} from "@jaypie/vocabulary/commander";
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
## Exports
|
|
399
|
+
|
|
400
|
+
### Main Export (`@jaypie/vocabulary`)
|
|
401
|
+
|
|
402
|
+
```typescript
|
|
403
|
+
// Coercion functions
|
|
404
|
+
export {
|
|
405
|
+
coerce,
|
|
406
|
+
coerceFromArray,
|
|
407
|
+
coerceFromObject,
|
|
408
|
+
coerceToArray,
|
|
409
|
+
coerceToBoolean,
|
|
410
|
+
coerceToNumber,
|
|
411
|
+
coerceToObject,
|
|
412
|
+
coerceToString,
|
|
413
|
+
} from "./coerce.js";
|
|
414
|
+
|
|
415
|
+
// Service Handler
|
|
416
|
+
export { serviceHandler } from "./serviceHandler.js";
|
|
417
|
+
|
|
418
|
+
// Commander namespace
|
|
419
|
+
export * as commander from "./commander/index.js";
|
|
420
|
+
|
|
421
|
+
// Version
|
|
422
|
+
export const VOCABULARY_VERSION: string;
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
### Commander Export (`@jaypie/vocabulary/commander`)
|
|
426
|
+
|
|
427
|
+
```typescript
|
|
428
|
+
export { createCommanderOptions } from "./createCommanderOptions.js";
|
|
429
|
+
export { parseCommanderOptions } from "./parseCommanderOptions.js";
|
|
430
|
+
export { registerServiceCommand } from "./registerServiceCommand.js";
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
## Error Handling
|
|
434
|
+
|
|
435
|
+
Invalid coercions throw `BadRequestError` from `@jaypie/errors`:
|
|
436
|
+
|
|
437
|
+
```typescript
|
|
438
|
+
import { BadRequestError } from "@jaypie/errors";
|
|
439
|
+
|
|
440
|
+
// These throw BadRequestError:
|
|
441
|
+
await handler({ numerator: "not-a-number" }); // Cannot coerce to Number
|
|
442
|
+
await handler({ priority: 10 }); // Validation fails (not in [1,2,3,4,5])
|
|
443
|
+
await handler({}); // Missing required field
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
## Integration with Other Packages
|
|
447
|
+
|
|
448
|
+
Vocabulary is designed to be consumed by:
|
|
449
|
+
- **`@jaypie/lambda`** - Lambda handler input processing
|
|
450
|
+
- **`@jaypie/express`** - Express route input validation
|
|
451
|
+
- **CLI packages** - Commander.js integration via the commander adapter
|
package/LICENSE.txt
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2025 Finlayson Studio, 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.
|