byr-pt-cli 0.1.5 → 0.1.7

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.
@@ -1,9 +1,10 @@
1
1
  import { renderBrowseOutput, runBrowseCommand } from "./commands/browse.mjs";
2
2
  import { renderDownloadOutput, runDownloadCommand } from "./commands/download.mjs";
3
- import { a as clearAuthStore, c as writeAuthStore, i as resolveClientConfig, n as renderDoctorOutput, o as maskCookieHeader, r as runDoctorCommand, s as validateByrCookie, t as getDoctorFailureCode } from "./doctor-JqfcqakX.mjs";
3
+ import { c as writeAuthStore, i as maskCookieHeader, s as validateByrCookie, t as clearAuthStore } from "./store-CtnRgFKg.mjs";
4
+ import { i as resolveClientConfig, n as renderDoctorOutput, r as runDoctorCommand, t as getDoctorFailureCode } from "./doctor-BFpvus4A.mjs";
4
5
  import { renderGetOutput, runGetCommand } from "./commands/get.mjs";
5
6
  import { renderSearchOutput, runSearchCommand } from "./commands/search.mjs";
6
- import { a as parseLoginForm, c as BYR_INCLDEAD_FACET, d as parseCategoryAliases, f as parseSimpleFacetAliases, i as looksLikeLoginPage, l as BYR_SPSTATE_FACET, o as HttpSession, s as BYR_BOOKMARKED_FACET, t as createByrClient, u as getByrMetadata } from "./client-BeMmaDg5.mjs";
7
+ import { a as parseLoginForm, c as BYR_INCLDEAD_FACET, d as parseCategoryAliases, f as parseSimpleFacetAliases, i as looksLikeLoginPage, l as BYR_SPSTATE_FACET, o as HttpSession, s as BYR_BOOKMARKED_FACET, t as createByrClient, u as getByrMetadata } from "./client-CmhKYsjk.mjs";
7
8
  import { createRequire } from "node:module";
8
9
  import { writeFile } from "node:fs/promises";
9
10
  import { createInterface } from "node:readline/promises";
@@ -12,7 +13,7 @@ import { spawnSync } from "node:child_process";
12
13
  import { join } from "node:path";
13
14
  import { tmpdir } from "node:os";
14
15
  import { copyFileSync, existsSync, readFileSync, rmSync, statSync } from "node:fs";
15
- import { createDecipheriv, pbkdf2Sync, randomUUID } from "node:crypto";
16
+ import { createDecipheriv, createHash, pbkdf2Sync, randomUUID } from "node:crypto";
16
17
 
17
18
  //#region src/domain/auth/browser.ts
18
19
  const TARGET_DOMAINS = new Set([
@@ -60,7 +61,7 @@ function importCookieFromChrome(profile) {
60
61
  "-separator",
61
62
  " ",
62
63
  tempDb,
63
- "SELECT name, value, hex(encrypted_value) FROM cookies WHERE host_key IN ('.byr.pt','byr.pt','.bt.byr.cn','bt.byr.cn') AND name IN ('uid','pass','session_id','auth_token','refresh_token')"
64
+ "SELECT name, value, hex(encrypted_value), host_key FROM cookies WHERE host_key IN ('.byr.pt','byr.pt','.bt.byr.cn','bt.byr.cn') AND name IN ('uid','pass','session_id','auth_token','refresh_token')"
64
65
  ], { encoding: "utf8" });
65
66
  if (sqlite.status !== 0) throw new CliAppError({
66
67
  code: "E_AUTH_REQUIRED",
@@ -71,15 +72,16 @@ function importCookieFromChrome(profile) {
71
72
  const lines = (sqlite.stdout ?? "").split("\n").map((line) => line.trim()).filter((line) => line.length > 0);
72
73
  let keyHex;
73
74
  for (const line of lines) {
74
- const [name, value, encryptedHex] = line.split(" ");
75
+ const [name, value = "", encryptedHex = "", hostKey = ""] = line.split(" ");
75
76
  if (!AUTH_COOKIE_NAMES.has(name)) continue;
76
- if (value && value.length > 0) {
77
- cookies.set(name, value);
77
+ const normalized = normalizeCookieValue(value);
78
+ if (normalized) {
79
+ cookies.set(name, normalized);
78
80
  continue;
79
81
  }
80
82
  if (!keyHex) keyHex = getChromeSafeStorageKeyHex();
81
83
  if (!encryptedHex || encryptedHex.length === 0 || !keyHex) continue;
82
- const resolved = decryptChromeCookieHex(encryptedHex, keyHex);
84
+ const resolved = decryptChromeCookieHex(encryptedHex, keyHex, hostKey);
83
85
  if (resolved) cookies.set(name, resolved);
84
86
  }
85
87
  return {
@@ -112,13 +114,20 @@ function getChromeSafeStorageKeyHex() {
112
114
  return pbkdf2Sync(password, "saltysalt", 1003, 16, "sha1").toString("hex");
113
115
  }
114
116
  }
115
- function decryptChromeCookieHex(encryptedHex, keyHex) {
117
+ function decryptChromeCookieHex(encryptedHex, keyHex, hostKey) {
116
118
  try {
117
119
  let encrypted = Buffer.from(encryptedHex, "hex");
118
120
  if (encrypted.length === 0) return;
119
- if (encrypted.subarray(0, 3).toString("utf8") === "v10") encrypted = encrypted.subarray(3);
121
+ const version = encrypted.subarray(0, 3).toString("utf8");
122
+ if (version === "v10" || version === "v11") encrypted = encrypted.subarray(3);
120
123
  const decipher = createDecipheriv("aes-128-cbc", Buffer.from(keyHex, "hex"), Buffer.alloc(16, 32));
121
- return Buffer.concat([decipher.update(encrypted), decipher.final()]).toString("utf8").replaceAll("\0", "").trim();
124
+ let decrypted = Buffer.concat([decipher.update(encrypted), decipher.final()]);
125
+ const normalizedHostKey = hostKey?.trim();
126
+ if (normalizedHostKey && decrypted.length > 32) {
127
+ const digest = createHash("sha256").update(normalizedHostKey).digest();
128
+ if (decrypted.subarray(0, 32).equals(digest)) decrypted = decrypted.subarray(32);
129
+ }
130
+ return normalizeCookieValue(decrypted.toString("utf8").replaceAll("\0", "").trim());
122
131
  } catch {
123
132
  return;
124
133
  }
@@ -182,7 +191,10 @@ function extractByrCookie(records, source) {
182
191
  const map = /* @__PURE__ */ new Map();
183
192
  for (const record of records) {
184
193
  if (!TARGET_DOMAINS.has(record.domain)) continue;
185
- if (AUTH_COOKIE_NAMES.has(record.name)) map.set(record.name, record.value);
194
+ if (AUTH_COOKIE_NAMES.has(record.name)) {
195
+ const normalized = normalizeCookieValue(record.value);
196
+ if (normalized) map.set(record.name, normalized);
197
+ }
186
198
  }
187
199
  if (map.size === 0) return;
188
200
  try {
@@ -214,6 +226,16 @@ function buildByrAuthCookieHeader(cookieMap, context) {
214
226
  }
215
227
  });
216
228
  }
229
+ function normalizeCookieValue(value) {
230
+ const trimmed = value.trim();
231
+ if (trimmed.length === 0) return;
232
+ for (const char of trimmed) {
233
+ const code = char.charCodeAt(0);
234
+ if (code < 33 || code > 126) return;
235
+ if (char === ";" || char === ",") return;
236
+ }
237
+ return trimmed;
238
+ }
217
239
  function parseBinaryCookies(buffer) {
218
240
  if (buffer.length < 8 || buffer.subarray(0, 4).toString("ascii") !== "cook") return [];
219
241
  const numPages = buffer.readUInt32BE(4);
package/dist/cli.mjs CHANGED
@@ -1,5 +1,6 @@
1
- import "./doctor-JqfcqakX.mjs";
2
- import "./client-BeMmaDg5.mjs";
3
- import { t as runCli } from "./cli-Ds1ZVpjV.mjs";
1
+ import "./store-CtnRgFKg.mjs";
2
+ import "./doctor-BFpvus4A.mjs";
3
+ import "./client-CmhKYsjk.mjs";
4
+ import { t as runCli } from "./cli-Boa0FrUq.mjs";
4
5
 
5
6
  export { runCli };
@@ -1,3 +1,4 @@
1
+ import { s as validateByrCookie } from "./store-CtnRgFKg.mjs";
1
2
  import { CliAppError } from "clawkit-cli-core";
2
3
 
3
4
  //#region src/domain/byr-metadata.ts
@@ -1198,13 +1199,15 @@ function parseTimeoutMs(value) {
1198
1199
  function createByrClient(options = {}) {
1199
1200
  const baseUrl = normalizeBaseUrl(options.baseUrl ?? DEFAULT_BASE_URL);
1200
1201
  const timeoutMs = sanitizeTimeout(options.timeoutMs);
1202
+ const cookie = options.cookie?.trim();
1203
+ if (cookie && cookie.length > 0) validateByrCookie(cookie);
1201
1204
  const username = options.username?.trim() ?? "";
1202
1205
  const password = options.password ?? "";
1203
1206
  const session = new HttpSession({
1204
1207
  baseUrl,
1205
1208
  timeoutMs,
1206
1209
  fetchImpl: options.fetchImpl,
1207
- initialCookie: options.cookie,
1210
+ initialCookie: cookie,
1208
1211
  userAgent: "byr-pt-cli"
1209
1212
  });
1210
1213
  let authInitialized = session.cookieSize() > 0;
@@ -1,3 +1,4 @@
1
- import { n as renderDoctorOutput, r as runDoctorCommand, t as getDoctorFailureCode } from "../doctor-JqfcqakX.mjs";
1
+ import "../store-CtnRgFKg.mjs";
2
+ import { n as renderDoctorOutput, r as runDoctorCommand, t as getDoctorFailureCode } from "../doctor-BFpvus4A.mjs";
2
3
 
3
4
  export { getDoctorFailureCode, renderDoctorOutput, runDoctorCommand };
@@ -1,128 +1,9 @@
1
- import { mkdir, readFile, rm, stat, writeFile } from "node:fs/promises";
1
+ import { a as readAuthStore, n as getByrAuthStorePath, o as readJsonFile, r as getByrGlobalConfigPath, s as validateByrCookie } from "./store-CtnRgFKg.mjs";
2
+ import { readFile } from "node:fs/promises";
2
3
  import { CliAppError } from "clawkit-cli-core";
3
4
  import { spawnSync } from "node:child_process";
4
- import { dirname, join } from "node:path";
5
- import { homedir } from "node:os";
5
+ import { join } from "node:path";
6
6
 
7
- //#region src/domain/auth/store.ts
8
- function getByrConfigDir() {
9
- return join(homedir(), ".config", "byr-cli");
10
- }
11
- function getByrGlobalConfigPath() {
12
- return join(getByrConfigDir(), "config.json");
13
- }
14
- function getByrAuthStorePath() {
15
- return join(getByrConfigDir(), "auth.json");
16
- }
17
- async function readJsonFile(path) {
18
- try {
19
- const content = await readFile(path, "utf8");
20
- return JSON.parse(content);
21
- } catch (error) {
22
- const nodeError = error;
23
- if (nodeError.code === "ENOENT") return;
24
- throw new CliAppError({
25
- code: "E_AUTH_INVALID",
26
- message: `Failed to read JSON file: ${path}`,
27
- details: {
28
- path,
29
- reason: nodeError.message
30
- },
31
- cause: error
32
- });
33
- }
34
- }
35
- async function writeJsonFile(path, data) {
36
- await mkdir(dirname(path), { recursive: true });
37
- await writeFile(path, `${JSON.stringify(data, null, 2)}\n`, "utf8");
38
- }
39
- async function readAuthStore() {
40
- const store = await readJsonFile(getByrAuthStorePath());
41
- if (store === void 0) return;
42
- if (typeof store.cookie !== "string" || typeof store.source !== "string" || typeof store.updatedAt !== "string") return;
43
- return {
44
- cookie: store.cookie,
45
- source: store.source,
46
- updatedAt: store.updatedAt
47
- };
48
- }
49
- async function writeAuthStore(cookie, source) {
50
- const store = {
51
- cookie,
52
- source,
53
- updatedAt: (/* @__PURE__ */ new Date()).toISOString()
54
- };
55
- await writeJsonFile(getByrAuthStorePath(), store);
56
- return store;
57
- }
58
- async function clearAuthStore() {
59
- const authStorePath = getByrAuthStorePath();
60
- let existed = true;
61
- try {
62
- await stat(authStorePath);
63
- } catch (error) {
64
- const nodeError = error;
65
- if (nodeError.code === "ENOENT") existed = false;
66
- else throw new CliAppError({
67
- code: "E_AUTH_INVALID",
68
- message: "Failed to inspect BYR auth store",
69
- details: { reason: nodeError.message },
70
- cause: error
71
- });
72
- }
73
- try {
74
- await rm(authStorePath, { force: true });
75
- return existed;
76
- } catch (error) {
77
- throw new CliAppError({
78
- code: "E_AUTH_INVALID",
79
- message: "Failed to clear BYR auth store",
80
- details: { reason: error.message },
81
- cause: error
82
- });
83
- }
84
- }
85
- function parseCookieHeader(cookieHeader) {
86
- const cookieMap = /* @__PURE__ */ new Map();
87
- for (const part of cookieHeader.split(";")) {
88
- const segment = part.trim();
89
- if (segment.length === 0) continue;
90
- const eqIndex = segment.indexOf("=");
91
- if (eqIndex <= 0) continue;
92
- const name = segment.slice(0, eqIndex).trim();
93
- const value = segment.slice(eqIndex + 1).trim();
94
- if (name.length > 0) cookieMap.set(name, value);
95
- }
96
- return {
97
- uid: cookieMap.get("uid"),
98
- pass: cookieMap.get("pass"),
99
- sessionId: cookieMap.get("session_id"),
100
- authToken: cookieMap.get("auth_token"),
101
- refreshToken: cookieMap.get("refresh_token"),
102
- cookieMap
103
- };
104
- }
105
- function validateByrCookie(cookieHeader) {
106
- const parsed = parseCookieHeader(cookieHeader);
107
- const hasLegacyCookie = Boolean(parsed.uid && parsed.pass);
108
- const hasSessionCookie = Boolean(parsed.sessionId && parsed.authToken);
109
- if (!hasLegacyCookie && !hasSessionCookie) throw new CliAppError({
110
- code: "E_AUTH_INVALID",
111
- message: "BYR cookie must include uid/pass or session_id/auth_token",
112
- details: { requiredAnyOf: [["uid", "pass"], ["session_id", "auth_token"]] }
113
- });
114
- return parsed;
115
- }
116
- function maskCookieValue(value, visible = 4) {
117
- if (value.length <= visible) return "*".repeat(value.length);
118
- return `${value.slice(0, visible)}${"*".repeat(Math.max(4, value.length - visible))}`;
119
- }
120
- function maskCookieHeader(cookieHeader) {
121
- const parsed = parseCookieHeader(cookieHeader);
122
- return Array.from(parsed.cookieMap.entries()).map(([name, value]) => name === "uid" || name === "pass" ? `${name}=${maskCookieValue(value)}` : `${name}=***`).join("; ");
123
- }
124
-
125
- //#endregion
126
7
  //#region src/domain/auth/config.ts
127
8
  function firstString(value) {
128
9
  if (value === void 0) return;
@@ -411,4 +292,4 @@ function toCliError(error, fallbackCode) {
411
292
  }
412
293
 
413
294
  //#endregion
414
- export { clearAuthStore as a, writeAuthStore as c, resolveClientConfig as i, renderDoctorOutput as n, maskCookieHeader as o, runDoctorCommand as r, validateByrCookie as s, getDoctorFailureCode as t };
295
+ export { resolveClientConfig as i, renderDoctorOutput as n, runDoctorCommand as r, getDoctorFailureCode as t };
@@ -1,3 +1,4 @@
1
- import { n as createByrClientFromEnv, r as createMockByrClient, t as createByrClient } from "../client-BeMmaDg5.mjs";
1
+ import "../store-CtnRgFKg.mjs";
2
+ import { n as createByrClientFromEnv, r as createMockByrClient, t as createByrClient } from "../client-CmhKYsjk.mjs";
2
3
 
3
4
  export { createByrClient, createByrClientFromEnv, createMockByrClient };
package/dist/index.mjs CHANGED
@@ -1,7 +1,8 @@
1
1
  #!/usr/bin/env node
2
- import "./doctor-JqfcqakX.mjs";
3
- import "./client-BeMmaDg5.mjs";
4
- import { t as runCli } from "./cli-Ds1ZVpjV.mjs";
2
+ import "./store-CtnRgFKg.mjs";
3
+ import "./doctor-BFpvus4A.mjs";
4
+ import "./client-CmhKYsjk.mjs";
5
+ import { t as runCli } from "./cli-Boa0FrUq.mjs";
5
6
 
6
7
  //#region src/index.ts
7
8
  const exitCode = await runCli(process.argv.slice(2));
@@ -0,0 +1,144 @@
1
+ import { mkdir, readFile, rm, stat, writeFile } from "node:fs/promises";
2
+ import { CliAppError } from "clawkit-cli-core";
3
+ import { dirname, join } from "node:path";
4
+ import { homedir } from "node:os";
5
+
6
+ //#region src/domain/auth/store.ts
7
+ function getByrConfigDir() {
8
+ return join(homedir(), ".config", "byr-cli");
9
+ }
10
+ function getByrGlobalConfigPath() {
11
+ return join(getByrConfigDir(), "config.json");
12
+ }
13
+ function getByrAuthStorePath() {
14
+ return join(getByrConfigDir(), "auth.json");
15
+ }
16
+ async function readJsonFile(path) {
17
+ try {
18
+ const content = await readFile(path, "utf8");
19
+ return JSON.parse(content);
20
+ } catch (error) {
21
+ const nodeError = error;
22
+ if (nodeError.code === "ENOENT") return;
23
+ throw new CliAppError({
24
+ code: "E_AUTH_INVALID",
25
+ message: `Failed to read JSON file: ${path}`,
26
+ details: {
27
+ path,
28
+ reason: nodeError.message
29
+ },
30
+ cause: error
31
+ });
32
+ }
33
+ }
34
+ async function writeJsonFile(path, data) {
35
+ await mkdir(dirname(path), { recursive: true });
36
+ await writeFile(path, `${JSON.stringify(data, null, 2)}\n`, "utf8");
37
+ }
38
+ async function readAuthStore() {
39
+ const store = await readJsonFile(getByrAuthStorePath());
40
+ if (store === void 0) return;
41
+ if (typeof store.cookie !== "string" || typeof store.source !== "string" || typeof store.updatedAt !== "string") return;
42
+ return {
43
+ cookie: store.cookie,
44
+ source: store.source,
45
+ updatedAt: store.updatedAt
46
+ };
47
+ }
48
+ async function writeAuthStore(cookie, source) {
49
+ const store = {
50
+ cookie,
51
+ source,
52
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
53
+ };
54
+ await writeJsonFile(getByrAuthStorePath(), store);
55
+ return store;
56
+ }
57
+ async function clearAuthStore() {
58
+ const authStorePath = getByrAuthStorePath();
59
+ let existed = true;
60
+ try {
61
+ await stat(authStorePath);
62
+ } catch (error) {
63
+ const nodeError = error;
64
+ if (nodeError.code === "ENOENT") existed = false;
65
+ else throw new CliAppError({
66
+ code: "E_AUTH_INVALID",
67
+ message: "Failed to inspect BYR auth store",
68
+ details: { reason: nodeError.message },
69
+ cause: error
70
+ });
71
+ }
72
+ try {
73
+ await rm(authStorePath, { force: true });
74
+ return existed;
75
+ } catch (error) {
76
+ throw new CliAppError({
77
+ code: "E_AUTH_INVALID",
78
+ message: "Failed to clear BYR auth store",
79
+ details: { reason: error.message },
80
+ cause: error
81
+ });
82
+ }
83
+ }
84
+ function parseCookieHeader(cookieHeader) {
85
+ const cookieMap = /* @__PURE__ */ new Map();
86
+ for (const part of cookieHeader.split(";")) {
87
+ const segment = part.trim();
88
+ if (segment.length === 0) continue;
89
+ const eqIndex = segment.indexOf("=");
90
+ if (eqIndex <= 0) continue;
91
+ const name = segment.slice(0, eqIndex).trim();
92
+ const value = segment.slice(eqIndex + 1).trim();
93
+ if (name.length > 0) cookieMap.set(name, value);
94
+ }
95
+ return {
96
+ uid: cookieMap.get("uid"),
97
+ pass: cookieMap.get("pass"),
98
+ sessionId: cookieMap.get("session_id"),
99
+ authToken: cookieMap.get("auth_token"),
100
+ refreshToken: cookieMap.get("refresh_token"),
101
+ cookieMap
102
+ };
103
+ }
104
+ function validateByrCookie(cookieHeader) {
105
+ const parsed = parseCookieHeader(cookieHeader);
106
+ const hasLegacyCookie = Boolean(parsed.uid && parsed.pass);
107
+ const hasSessionCookie = Boolean(parsed.sessionId && parsed.authToken);
108
+ if (!hasLegacyCookie && !hasSessionCookie) throw new CliAppError({
109
+ code: "E_AUTH_INVALID",
110
+ message: "BYR cookie must include uid/pass or session_id/auth_token",
111
+ details: { requiredAnyOf: [["uid", "pass"], ["session_id", "auth_token"]] }
112
+ });
113
+ for (const [name, value] of parsed.cookieMap.entries()) {
114
+ const reason = getInvalidCookieValueReason(value);
115
+ if (reason !== void 0) throw new CliAppError({
116
+ code: "E_AUTH_INVALID",
117
+ message: `Invalid cookie value for ${name}`,
118
+ details: {
119
+ cookieName: name,
120
+ reason
121
+ }
122
+ });
123
+ }
124
+ return parsed;
125
+ }
126
+ function getInvalidCookieValueReason(value) {
127
+ if (value.trim().length === 0) return "empty";
128
+ for (const char of value) {
129
+ const code = char.charCodeAt(0);
130
+ if (code < 33 || code > 126) return `non-ascii-character:${code}`;
131
+ if (char === ";" || char === ",") return `reserved-character:${char}`;
132
+ }
133
+ }
134
+ function maskCookieValue(value, visible = 4) {
135
+ if (value.length <= visible) return "*".repeat(value.length);
136
+ return `${value.slice(0, visible)}${"*".repeat(Math.max(4, value.length - visible))}`;
137
+ }
138
+ function maskCookieHeader(cookieHeader) {
139
+ const parsed = parseCookieHeader(cookieHeader);
140
+ return Array.from(parsed.cookieMap.entries()).map(([name, value]) => name === "uid" || name === "pass" ? `${name}=${maskCookieValue(value)}` : `${name}=***`).join("; ");
141
+ }
142
+
143
+ //#endregion
144
+ export { readAuthStore as a, writeAuthStore as c, maskCookieHeader as i, getByrAuthStorePath as n, readJsonFile as o, getByrGlobalConfigPath as r, validateByrCookie as s, clearAuthStore as t };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "byr-pt-cli",
3
- "version": "0.1.5",
3
+ "version": "0.1.7",
4
4
  "private": false,
5
5
  "description": "BYR CLI with OpenClaw-friendly JSON contract",
6
6
  "license": "MIT",
@@ -20,9 +20,6 @@
20
20
  "import": "./dist/cli.mjs"
21
21
  }
22
22
  },
23
- "dependencies": {
24
- "clawkit-cli-core": "^0.1.0"
25
- },
26
23
  "scripts": {
27
24
  "build": "tsdown src/index.ts src/cli.ts src/domain/client.ts src/domain/types.ts src/commands/browse.ts src/commands/doctor.ts src/commands/download.ts src/commands/get.ts src/commands/search.ts --format esm --dts",
28
25
  "test": "pnpm --filter clawkit-cli-core build && vitest run",
@@ -31,5 +28,8 @@
31
28
  "check": "pnpm typecheck && pnpm test",
32
29
  "skill:publish": "node ./scripts/skill-publish.mjs",
33
30
  "skill:sync": "clawhub sync --root ./skill-openclaw --all"
31
+ },
32
+ "dependencies": {
33
+ "clawkit-cli-core": "workspace:^0.1.0"
34
34
  }
35
- }
35
+ }
package/LICENSE DELETED
@@ -1,21 +0,0 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 onemoreproduct
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.