@moxon/api 6.0.0-pre
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/.prettierignore +5 -0
- package/LICENSE +28 -0
- package/README.md +277 -0
- package/dist/app.d.ts +2 -0
- package/dist/app.js +55 -0
- package/dist/app.js.map +1 -0
- package/dist/config/env.d.ts +22 -0
- package/dist/config/env.js +36 -0
- package/dist/config/env.js.map +1 -0
- package/dist/config/plans.d.ts +26 -0
- package/dist/config/plans.js +44 -0
- package/dist/config/plans.js.map +1 -0
- package/dist/config/versions.d.ts +18 -0
- package/dist/config/versions.js +248 -0
- package/dist/config/versions.js.map +1 -0
- package/dist/constants.d.ts +48 -0
- package/dist/constants.js +75 -0
- package/dist/constants.js.map +1 -0
- package/dist/middleware/cors.d.ts +2 -0
- package/dist/middleware/cors.js +31 -0
- package/dist/middleware/cors.js.map +1 -0
- package/dist/middleware/error.d.ts +4 -0
- package/dist/middleware/error.js +8 -0
- package/dist/middleware/error.js.map +1 -0
- package/dist/middleware/json.d.ts +2 -0
- package/dist/middleware/json.js +8 -0
- package/dist/middleware/json.js.map +1 -0
- package/dist/middleware/logger.d.ts +26 -0
- package/dist/middleware/logger.js +65 -0
- package/dist/middleware/logger.js.map +1 -0
- package/dist/middleware/ratelimit.d.ts +2 -0
- package/dist/middleware/ratelimit.js +83 -0
- package/dist/middleware/ratelimit.js.map +1 -0
- package/dist/middleware/version.d.ts +3 -0
- package/dist/middleware/version.js +30 -0
- package/dist/middleware/version.js.map +1 -0
- package/dist/modules/v4/address.d.ts +20 -0
- package/dist/modules/v4/address.js +381 -0
- package/dist/modules/v4/address.js.map +1 -0
- package/dist/modules/v4/agent.d.ts +30 -0
- package/dist/modules/v4/agent.js +92 -0
- package/dist/modules/v4/agent.js.map +1 -0
- package/dist/modules/v4/algorithms.d.ts +90 -0
- package/dist/modules/v4/algorithms.js +279 -0
- package/dist/modules/v4/algorithms.js.map +1 -0
- package/dist/modules/v4/avatar.d.ts +23 -0
- package/dist/modules/v4/avatar.js +136 -0
- package/dist/modules/v4/avatar.js.map +1 -0
- package/dist/modules/v4/barcode.d.ts +27 -0
- package/dist/modules/v4/barcode.js +440 -0
- package/dist/modules/v4/barcode.js.map +1 -0
- package/dist/modules/v4/captcha.d.ts +22 -0
- package/dist/modules/v4/captcha.js +79 -0
- package/dist/modules/v4/captcha.js.map +1 -0
- package/dist/modules/v4/chat.d.ts +21 -0
- package/dist/modules/v4/chat.js +100 -0
- package/dist/modules/v4/chat.js.map +1 -0
- package/dist/modules/v4/color.d.ts +16 -0
- package/dist/modules/v4/color.js +59 -0
- package/dist/modules/v4/color.js.map +1 -0
- package/dist/modules/v4/convert.d.ts +15 -0
- package/dist/modules/v4/convert.js +116 -0
- package/dist/modules/v4/convert.js.map +1 -0
- package/dist/modules/v4/credit.d.ts +22 -0
- package/dist/modules/v4/credit.js +104 -0
- package/dist/modules/v4/credit.js.map +1 -0
- package/dist/modules/v4/cron.d.ts +17 -0
- package/dist/modules/v4/cron.js +202 -0
- package/dist/modules/v4/cron.js.map +1 -0
- package/dist/modules/v4/dice.d.ts +16 -0
- package/dist/modules/v4/dice.js +37 -0
- package/dist/modules/v4/dice.js.map +1 -0
- package/dist/modules/v4/domain.d.ts +6 -0
- package/dist/modules/v4/domain.js +83 -0
- package/dist/modules/v4/domain.js.map +1 -0
- package/dist/modules/v4/encode.d.ts +81 -0
- package/dist/modules/v4/encode.js +236 -0
- package/dist/modules/v4/encode.js.map +1 -0
- package/dist/modules/v4/geo.d.ts +30 -0
- package/dist/modules/v4/geo.js +51 -0
- package/dist/modules/v4/geo.js.map +1 -0
- package/dist/modules/v4/hash.d.ts +15 -0
- package/dist/modules/v4/hash.js +25 -0
- package/dist/modules/v4/hash.js.map +1 -0
- package/dist/modules/v4/hyperplanning.d.ts +19 -0
- package/dist/modules/v4/hyperplanning.js +80 -0
- package/dist/modules/v4/hyperplanning.js.map +1 -0
- package/dist/modules/v4/ip.d.ts +19 -0
- package/dist/modules/v4/ip.js +132 -0
- package/dist/modules/v4/ip.js.map +1 -0
- package/dist/modules/v4/levenshtein.d.ts +13 -0
- package/dist/modules/v4/levenshtein.js +37 -0
- package/dist/modules/v4/levenshtein.js.map +1 -0
- package/dist/modules/v4/palette.d.ts +19 -0
- package/dist/modules/v4/palette.js +56 -0
- package/dist/modules/v4/palette.js.map +1 -0
- package/dist/modules/v4/password.d.ts +25 -0
- package/dist/modules/v4/password.js +343 -0
- package/dist/modules/v4/password.js.map +1 -0
- package/dist/modules/v4/personal.d.ts +6 -0
- package/dist/modules/v4/personal.js +121 -0
- package/dist/modules/v4/personal.js.map +1 -0
- package/dist/modules/v4/placeholder.d.ts +30 -0
- package/dist/modules/v4/placeholder.js +160 -0
- package/dist/modules/v4/placeholder.js.map +1 -0
- package/dist/modules/v4/qrcode.d.ts +25 -0
- package/dist/modules/v4/qrcode.js +92 -0
- package/dist/modules/v4/qrcode.js.map +1 -0
- package/dist/modules/v4/regex.d.ts +23 -0
- package/dist/modules/v4/regex.js +48 -0
- package/dist/modules/v4/regex.js.map +1 -0
- package/dist/modules/v4/statistics.d.ts +20 -0
- package/dist/modules/v4/statistics.js +48 -0
- package/dist/modules/v4/statistics.js.map +1 -0
- package/dist/modules/v4/text.d.ts +43 -0
- package/dist/modules/v4/text.js +323 -0
- package/dist/modules/v4/text.js.map +1 -0
- package/dist/modules/v4/tic_tac_toe.d.ts +19 -0
- package/dist/modules/v4/tic_tac_toe.js +214 -0
- package/dist/modules/v4/tic_tac_toe.js.map +1 -0
- package/dist/modules/v4/time.d.ts +15 -0
- package/dist/modules/v4/time.js +124 -0
- package/dist/modules/v4/time.js.map +1 -0
- package/dist/modules/v4/token.d.ts +9 -0
- package/dist/modules/v4/token.js +45 -0
- package/dist/modules/v4/token.js.map +1 -0
- package/dist/modules/v4/username.d.ts +6 -0
- package/dist/modules/v4/username.js +92 -0
- package/dist/modules/v4/username.js.map +1 -0
- package/dist/modules/v4/validate.d.ts +34 -0
- package/dist/modules/v4/validate.js +75 -0
- package/dist/modules/v4/validate.js.map +1 -0
- package/dist/modules/v4.d.ts +32 -0
- package/dist/modules/v4.js +33 -0
- package/dist/modules/v4.js.map +1 -0
- package/dist/modules/v5/address.d.ts +5 -0
- package/dist/modules/v5/address.js +20 -0
- package/dist/modules/v5/address.js.map +1 -0
- package/dist/modules/v5/algorithms.d.ts +9 -0
- package/dist/modules/v5/algorithms.js +39 -0
- package/dist/modules/v5/algorithms.js.map +1 -0
- package/dist/modules/v5/asymmetric.d.ts +26 -0
- package/dist/modules/v5/asymmetric.js +74 -0
- package/dist/modules/v5/asymmetric.js.map +1 -0
- package/dist/modules/v5/barcode.d.ts +27 -0
- package/dist/modules/v5/barcode.js +424 -0
- package/dist/modules/v5/barcode.js.map +1 -0
- package/dist/modules/v5/base.d.ts +16 -0
- package/dist/modules/v5/base.js +41 -0
- package/dist/modules/v5/base.js.map +1 -0
- package/dist/modules/v5/captcha.d.ts +27 -0
- package/dist/modules/v5/captcha.js +136 -0
- package/dist/modules/v5/captcha.js.map +1 -0
- package/dist/modules/v5/case.d.ts +10 -0
- package/dist/modules/v5/case.js +57 -0
- package/dist/modules/v5/case.js.map +1 -0
- package/dist/modules/v5/chart.d.ts +53 -0
- package/dist/modules/v5/chart.js +385 -0
- package/dist/modules/v5/chart.js.map +1 -0
- package/dist/modules/v5/chat.d.ts +21 -0
- package/dist/modules/v5/chat.js +107 -0
- package/dist/modules/v5/chat.js.map +1 -0
- package/dist/modules/v5/csv.d.ts +29 -0
- package/dist/modules/v5/csv.js +143 -0
- package/dist/modules/v5/csv.js.map +1 -0
- package/dist/modules/v5/diff.d.ts +20 -0
- package/dist/modules/v5/diff.js +81 -0
- package/dist/modules/v5/diff.js.map +1 -0
- package/dist/modules/v5/evaluate.d.ts +14 -0
- package/dist/modules/v5/evaluate.js +284 -0
- package/dist/modules/v5/evaluate.js.map +1 -0
- package/dist/modules/v5/jwt.d.ts +11 -0
- package/dist/modules/v5/jwt.js +42 -0
- package/dist/modules/v5/jwt.js.map +1 -0
- package/dist/modules/v5/matrix.d.ts +77 -0
- package/dist/modules/v5/matrix.js +239 -0
- package/dist/modules/v5/matrix.js.map +1 -0
- package/dist/modules/v5/otp.d.ts +30 -0
- package/dist/modules/v5/otp.js +117 -0
- package/dist/modules/v5/otp.js.map +1 -0
- package/dist/modules/v5/pow.d.ts +29 -0
- package/dist/modules/v5/pow.js +49 -0
- package/dist/modules/v5/pow.js.map +1 -0
- package/dist/modules/v5/read.d.ts +20 -0
- package/dist/modules/v5/read.js +59 -0
- package/dist/modules/v5/read.js.map +1 -0
- package/dist/modules/v5/semver.d.ts +33 -0
- package/dist/modules/v5/semver.js +99 -0
- package/dist/modules/v5/semver.js.map +1 -0
- package/dist/modules/v5/symmetric.d.ts +15 -0
- package/dist/modules/v5/symmetric.js +88 -0
- package/dist/modules/v5/symmetric.js.map +1 -0
- package/dist/modules/v5/text.d.ts +5 -0
- package/dist/modules/v5/text.js +12 -0
- package/dist/modules/v5/text.js.map +1 -0
- package/dist/modules/v5/tic_tac_toe.d.ts +19 -0
- package/dist/modules/v5/tic_tac_toe.js +226 -0
- package/dist/modules/v5/tic_tac_toe.js.map +1 -0
- package/dist/modules/v5/url.d.ts +18 -0
- package/dist/modules/v5/url.js +51 -0
- package/dist/modules/v5/url.js.map +1 -0
- package/dist/modules/v5/uuid.d.ts +25 -0
- package/dist/modules/v5/uuid.js +40 -0
- package/dist/modules/v5/uuid.js.map +1 -0
- package/dist/modules/v5.d.ts +24 -0
- package/dist/modules/v5.js +25 -0
- package/dist/modules/v5.js.map +1 -0
- package/dist/modules/v6.d.ts +1 -0
- package/dist/modules/v6.js +2 -0
- package/dist/modules/v6.js.map +1 -0
- package/dist/routes/delete.d.ts +2 -0
- package/dist/routes/delete.js +73 -0
- package/dist/routes/delete.js.map +1 -0
- package/dist/routes/get.d.ts +2 -0
- package/dist/routes/get.js +857 -0
- package/dist/routes/get.js.map +1 -0
- package/dist/routes/index.d.ts +2 -0
- package/dist/routes/index.js +95 -0
- package/dist/routes/index.js.map +1 -0
- package/dist/routes/patch.d.ts +2 -0
- package/dist/routes/patch.js +45 -0
- package/dist/routes/patch.js.map +1 -0
- package/dist/routes/post.d.ts +2 -0
- package/dist/routes/post.js +604 -0
- package/dist/routes/post.js.map +1 -0
- package/dist/storage/index.d.ts +5 -0
- package/dist/storage/index.js +14 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/types/storage.d.ts +52 -0
- package/dist/types/storage.js +2 -0
- package/dist/types/storage.js.map +1 -0
- package/dist/utils/challenge.d.ts +40 -0
- package/dist/utils/challenge.js +75 -0
- package/dist/utils/challenge.js.map +1 -0
- package/dist/utils/colors.d.ts +44 -0
- package/dist/utils/colors.js +93 -0
- package/dist/utils/colors.js.map +1 -0
- package/dist/utils/helpers.d.ts +55 -0
- package/dist/utils/helpers.js +82 -0
- package/dist/utils/helpers.js.map +1 -0
- package/dist/utils/response.d.ts +9 -0
- package/dist/utils/response.js +24 -0
- package/dist/utils/response.js.map +1 -0
- package/package.json +90 -0
- package/robots.txt +74 -0
- package/src/favicon.ico +0 -0
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { MAX_CSV_LENGTH, MAX_CSV_ROWS } from '../../constants.js';
|
|
2
|
+
/**
|
|
3
|
+
* Parses a full CSV text into rows of fields, respecting quoted fields
|
|
4
|
+
* (including escaped quotes and newlines inside quotes).
|
|
5
|
+
*
|
|
6
|
+
* @param text - Raw CSV text; CRLF and CR line endings are normalized to LF
|
|
7
|
+
* @param delimiter - Field separator, a single character
|
|
8
|
+
* @returns Array of rows, each row being an array of field values
|
|
9
|
+
*/
|
|
10
|
+
function parseRows(text, delimiter) {
|
|
11
|
+
const src = text.replace(/\r\n/g, '\n').replace(/\r/g, '\n');
|
|
12
|
+
const rows = [];
|
|
13
|
+
let fields = [];
|
|
14
|
+
let value = '';
|
|
15
|
+
let inQuotes = false;
|
|
16
|
+
let fieldStarted = false;
|
|
17
|
+
const endField = () => {
|
|
18
|
+
fields.push(value);
|
|
19
|
+
value = '';
|
|
20
|
+
fieldStarted = false;
|
|
21
|
+
};
|
|
22
|
+
const endRow = () => {
|
|
23
|
+
if (fields.length > 0 || value !== '' || fieldStarted) {
|
|
24
|
+
endField();
|
|
25
|
+
rows.push(fields);
|
|
26
|
+
}
|
|
27
|
+
fields = [];
|
|
28
|
+
};
|
|
29
|
+
let i = 0;
|
|
30
|
+
while (i < src.length) {
|
|
31
|
+
const ch = src[i];
|
|
32
|
+
if (inQuotes) {
|
|
33
|
+
if (ch === '"') {
|
|
34
|
+
if (src[i + 1] === '"') {
|
|
35
|
+
value += '"';
|
|
36
|
+
i += 2;
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
inQuotes = false;
|
|
40
|
+
i++;
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
value += ch;
|
|
44
|
+
i++;
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
if (ch === '"' && value === '') {
|
|
48
|
+
inQuotes = true;
|
|
49
|
+
fieldStarted = true;
|
|
50
|
+
i++;
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
if (ch === delimiter) {
|
|
54
|
+
endField();
|
|
55
|
+
fieldStarted = true;
|
|
56
|
+
i++;
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
if (ch === '\n') {
|
|
60
|
+
endRow();
|
|
61
|
+
i++;
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
value += ch;
|
|
65
|
+
i++;
|
|
66
|
+
}
|
|
67
|
+
endRow();
|
|
68
|
+
return rows;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Escapes a value for CSV output. Wraps in quotes if it contains the delimiter, quotes, or newlines.
|
|
72
|
+
*
|
|
73
|
+
* @param value - Field value to escape
|
|
74
|
+
* @param delimiter - Field separator used in the output
|
|
75
|
+
* @returns The value, quoted with inner quotes doubled when escaping is needed
|
|
76
|
+
*/
|
|
77
|
+
function escapeField(value, delimiter) {
|
|
78
|
+
if (value.includes(delimiter) || value.includes('"') || value.includes('\n')) {
|
|
79
|
+
return '"' + value.replace(/"/g, '""') + '"';
|
|
80
|
+
}
|
|
81
|
+
return value;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Converts between CSV and JSON.
|
|
85
|
+
* - `parse`: CSV string → array of objects
|
|
86
|
+
* - `format`: array of objects → CSV string
|
|
87
|
+
*
|
|
88
|
+
* @param action - "parse" or "format"
|
|
89
|
+
* @param data - Input payload: `csv` string for parse, `json` array of objects for format
|
|
90
|
+
* @param options - `delimiter` (single character, default ",") and `headers` (parse only: use the first row as keys, default true)
|
|
91
|
+
* @returns Parse result with the rows and their count, or format result with the CSV string and the row count
|
|
92
|
+
* @throws Error if the action is invalid, the delimiter is not a single character, the input data is missing, or a size limit is exceeded
|
|
93
|
+
*/
|
|
94
|
+
export default function csv(action, data, options = {}) {
|
|
95
|
+
if (!action || (action !== 'parse' && action !== 'format'))
|
|
96
|
+
throw new Error('Please provide a valid action (?action=parse|format)');
|
|
97
|
+
const delimiter = options.delimiter ?? ',';
|
|
98
|
+
if (delimiter.length !== 1)
|
|
99
|
+
throw new Error('Delimiter must be a single character');
|
|
100
|
+
if (action === 'parse') {
|
|
101
|
+
const text = data.csv;
|
|
102
|
+
if (!text)
|
|
103
|
+
throw new Error('Please provide CSV data (?csv={data})');
|
|
104
|
+
if (text.length > MAX_CSV_LENGTH)
|
|
105
|
+
throw new Error(`CSV cannot exceed ${MAX_CSV_LENGTH} characters`);
|
|
106
|
+
const useHeaders = options.headers !== false;
|
|
107
|
+
const allRows = parseRows(text, delimiter);
|
|
108
|
+
if (allRows.length === 0)
|
|
109
|
+
return { action: 'parse', rows: [], count: 0 };
|
|
110
|
+
let headers;
|
|
111
|
+
let dataRows;
|
|
112
|
+
if (useHeaders) {
|
|
113
|
+
headers = allRows[0];
|
|
114
|
+
dataRows = allRows.slice(1);
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
headers = allRows[0].map((_, i) => String(i));
|
|
118
|
+
dataRows = allRows;
|
|
119
|
+
}
|
|
120
|
+
if (dataRows.length > MAX_CSV_ROWS)
|
|
121
|
+
throw new Error(`CSV cannot exceed ${MAX_CSV_ROWS} rows`);
|
|
122
|
+
const rows = dataRows.map((fields) => {
|
|
123
|
+
const row = {};
|
|
124
|
+
for (let i = 0; i < headers.length; i++) {
|
|
125
|
+
row[headers[i]] = fields[i] ?? '';
|
|
126
|
+
}
|
|
127
|
+
return row;
|
|
128
|
+
});
|
|
129
|
+
return { action: 'parse', rows, count: rows.length };
|
|
130
|
+
}
|
|
131
|
+
// action === 'format'
|
|
132
|
+
const json = data.json;
|
|
133
|
+
if (!json || !Array.isArray(json) || json.length === 0)
|
|
134
|
+
throw new Error('Please provide a JSON array (?json=[...])');
|
|
135
|
+
if (json.length > MAX_CSV_ROWS)
|
|
136
|
+
throw new Error(`JSON cannot exceed ${MAX_CSV_ROWS} rows`);
|
|
137
|
+
const headers = Object.keys(json[0]);
|
|
138
|
+
const headerLine = headers.map((h) => escapeField(h, delimiter)).join(delimiter);
|
|
139
|
+
const dataLines = json.map((obj) => headers.map((h) => escapeField(String(obj[h] ?? ''), delimiter)).join(delimiter));
|
|
140
|
+
const csvOutput = headerLine + '\n' + dataLines.join('\n');
|
|
141
|
+
return { action: 'format', csv: csvOutput, count: json.length };
|
|
142
|
+
}
|
|
143
|
+
//# sourceMappingURL=csv.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"csv.js","sourceRoot":"","sources":["../../../src/modules/v5/csv.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export interface DiffChange {
|
|
2
|
+
type: 'equal' | 'add' | 'del';
|
|
3
|
+
value: string;
|
|
4
|
+
}
|
|
5
|
+
export interface DiffResult {
|
|
6
|
+
mode: string;
|
|
7
|
+
added: number;
|
|
8
|
+
removed: number;
|
|
9
|
+
changes: DiffChange[];
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Compares two texts and returns a structured diff using the LCS algorithm.
|
|
13
|
+
*
|
|
14
|
+
* @param a - Original text
|
|
15
|
+
* @param b - Modified text
|
|
16
|
+
* @param mode - Granularity: line (default) or word
|
|
17
|
+
* @returns Diff result with the change list and added/removed counts
|
|
18
|
+
* @throws Error if a text is missing or too long, or if the mode is invalid
|
|
19
|
+
*/
|
|
20
|
+
export default function diff(a: string, b: string, mode?: string): DiffResult;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { MAX_DIFF_LENGTH, MAX_DIFF_PARTS } from '../../constants.js';
|
|
2
|
+
const VALID_MODES = ['line', 'word'];
|
|
3
|
+
function split(text, mode) {
|
|
4
|
+
if (mode === 'line')
|
|
5
|
+
return text.split('\n');
|
|
6
|
+
return text.split(/\s+/).filter((w) => w.length > 0);
|
|
7
|
+
}
|
|
8
|
+
function lcs(a, b) {
|
|
9
|
+
const m = a.length;
|
|
10
|
+
const n = b.length;
|
|
11
|
+
const dp = Array.from({ length: m + 1 }, () => new Array(n + 1).fill(0));
|
|
12
|
+
for (let i = 1; i <= m; i++) {
|
|
13
|
+
for (let j = 1; j <= n; j++) {
|
|
14
|
+
if (a[i - 1] === b[j - 1]) {
|
|
15
|
+
dp[i][j] = dp[i - 1][j - 1] + 1;
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return dp;
|
|
23
|
+
}
|
|
24
|
+
function buildChanges(a, b, dp) {
|
|
25
|
+
const changes = [];
|
|
26
|
+
let i = a.length;
|
|
27
|
+
let j = b.length;
|
|
28
|
+
while (i > 0 || j > 0) {
|
|
29
|
+
if (i > 0 && j > 0 && a[i - 1] === b[j - 1]) {
|
|
30
|
+
changes.push({ type: 'equal', value: a[i - 1] });
|
|
31
|
+
i--;
|
|
32
|
+
j--;
|
|
33
|
+
}
|
|
34
|
+
else if (j > 0 && (i === 0 || dp[i][j - 1] >= dp[i - 1][j])) {
|
|
35
|
+
changes.push({ type: 'add', value: b[j - 1] });
|
|
36
|
+
j--;
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
changes.push({ type: 'del', value: a[i - 1] });
|
|
40
|
+
i--;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return changes.reverse();
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Compares two texts and returns a structured diff using the LCS algorithm.
|
|
47
|
+
*
|
|
48
|
+
* @param a - Original text
|
|
49
|
+
* @param b - Modified text
|
|
50
|
+
* @param mode - Granularity: line (default) or word
|
|
51
|
+
* @returns Diff result with the change list and added/removed counts
|
|
52
|
+
* @throws Error if a text is missing or too long, or if the mode is invalid
|
|
53
|
+
*/
|
|
54
|
+
export default function diff(a, b, mode = 'line') {
|
|
55
|
+
if (typeof a !== 'string')
|
|
56
|
+
throw new Error('Please provide a first text (a={text})');
|
|
57
|
+
if (typeof b !== 'string')
|
|
58
|
+
throw new Error('Please provide a second text (b={text})');
|
|
59
|
+
if (a.length > MAX_DIFF_LENGTH)
|
|
60
|
+
throw new Error(`Texts must be ${MAX_DIFF_LENGTH} characters or fewer`);
|
|
61
|
+
if (b.length > MAX_DIFF_LENGTH)
|
|
62
|
+
throw new Error(`Texts must be ${MAX_DIFF_LENGTH} characters or fewer`);
|
|
63
|
+
if (!VALID_MODES.includes(mode))
|
|
64
|
+
throw new Error(`Mode must be one of: ${VALID_MODES.join(', ')}`);
|
|
65
|
+
const left = split(a, mode);
|
|
66
|
+
const right = split(b, mode);
|
|
67
|
+
if (left.length > MAX_DIFF_PARTS || right.length > MAX_DIFF_PARTS) {
|
|
68
|
+
throw new Error(`Texts must contain ${MAX_DIFF_PARTS} ${mode}s or fewer`);
|
|
69
|
+
}
|
|
70
|
+
const changes = buildChanges(left, right, lcs(left, right));
|
|
71
|
+
let added = 0;
|
|
72
|
+
let removed = 0;
|
|
73
|
+
for (const change of changes) {
|
|
74
|
+
if (change.type === 'add')
|
|
75
|
+
added++;
|
|
76
|
+
else if (change.type === 'del')
|
|
77
|
+
removed++;
|
|
78
|
+
}
|
|
79
|
+
return { mode, added, removed, changes };
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=diff.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diff.js","sourceRoot":"","sources":["../../../src/modules/v5/diff.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface EvaluateResult {
|
|
2
|
+
expression: string;
|
|
3
|
+
result: number;
|
|
4
|
+
precision: number;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Evaluates a mathematical expression string and returns the result.
|
|
8
|
+
*
|
|
9
|
+
* @param expr - Math expression; supports +, -, *, /, %, ^, unary -, parentheses, constants (pi, e) and functions (sin, cos, tan, sqrt, abs, ceil, floor, round, log, log2, log10, exp, min, max)
|
|
10
|
+
* @param precision - Number of decimal places in the result (0–15, default 10)
|
|
11
|
+
* @returns Object with the original expression, numeric result, and applied precision
|
|
12
|
+
* @throws Error if the expression is empty, exceeds the maximum length, contains unknown identifiers, or produces a non-finite result
|
|
13
|
+
*/
|
|
14
|
+
export default function evaluate(expr: string, precision?: number): EvaluateResult;
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
import { MAX_EXPR_DEPTH, MAX_EXPR_LENGTH } from '../../constants.js';
|
|
2
|
+
function tokenize(expr) {
|
|
3
|
+
const tokens = [];
|
|
4
|
+
let i = 0;
|
|
5
|
+
while (i < expr.length) {
|
|
6
|
+
const ch = expr[i];
|
|
7
|
+
if (' \t\r\n'.includes(ch)) {
|
|
8
|
+
i++;
|
|
9
|
+
continue;
|
|
10
|
+
}
|
|
11
|
+
if ((ch >= '0' && ch <= '9') || ch === '.') {
|
|
12
|
+
let num = '';
|
|
13
|
+
let dots = 0;
|
|
14
|
+
while (i < expr.length && ((expr[i] >= '0' && expr[i] <= '9') || expr[i] === '.')) {
|
|
15
|
+
if (expr[i] === '.')
|
|
16
|
+
dots++;
|
|
17
|
+
num += expr[i++];
|
|
18
|
+
}
|
|
19
|
+
if (dots > 1)
|
|
20
|
+
throw new Error(`Invalid number: ${num}`);
|
|
21
|
+
tokens.push({ type: 'NUMBER', value: num });
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || ch === '_') {
|
|
25
|
+
let ident = '';
|
|
26
|
+
while (i < expr.length &&
|
|
27
|
+
((expr[i] >= 'a' && expr[i] <= 'z') ||
|
|
28
|
+
(expr[i] >= 'A' && expr[i] <= 'Z') ||
|
|
29
|
+
expr[i] === '_' ||
|
|
30
|
+
(expr[i] >= '0' && expr[i] <= '9'))) {
|
|
31
|
+
ident += expr[i++];
|
|
32
|
+
}
|
|
33
|
+
tokens.push({ type: 'IDENT', value: ident });
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
if ('+-*/%^'.includes(ch)) {
|
|
37
|
+
tokens.push({ type: 'OP', value: ch });
|
|
38
|
+
i++;
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
if (ch === '(') {
|
|
42
|
+
tokens.push({ type: 'LPAREN', value: '(' });
|
|
43
|
+
i++;
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
if (ch === ')') {
|
|
47
|
+
tokens.push({ type: 'RPAREN', value: ')' });
|
|
48
|
+
i++;
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
if (ch === ',') {
|
|
52
|
+
tokens.push({ type: 'COMMA', value: ',' });
|
|
53
|
+
i++;
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
throw new Error(`Unexpected character: '${ch}'`);
|
|
57
|
+
}
|
|
58
|
+
return tokens;
|
|
59
|
+
}
|
|
60
|
+
const LEFT_BP = { '+': 10, '-': 10, '*': 20, '/': 20, '%': 20, '^': 31 };
|
|
61
|
+
const RIGHT_BP = { '+': 10, '-': 10, '*': 20, '/': 20, '%': 20, '^': 30 };
|
|
62
|
+
const UNARY_BP = 30;
|
|
63
|
+
const CONSTANTS = { pi: Math.PI, e: Math.E };
|
|
64
|
+
const FUNCTIONS = new Set([
|
|
65
|
+
'sqrt',
|
|
66
|
+
'abs',
|
|
67
|
+
'ceil',
|
|
68
|
+
'floor',
|
|
69
|
+
'round',
|
|
70
|
+
'sin',
|
|
71
|
+
'cos',
|
|
72
|
+
'tan',
|
|
73
|
+
'log',
|
|
74
|
+
'log2',
|
|
75
|
+
'log10',
|
|
76
|
+
'exp',
|
|
77
|
+
'min',
|
|
78
|
+
'max',
|
|
79
|
+
]);
|
|
80
|
+
class Parser {
|
|
81
|
+
tokens;
|
|
82
|
+
pos = 0;
|
|
83
|
+
depth = 0;
|
|
84
|
+
constructor(tokens) {
|
|
85
|
+
this.tokens = tokens;
|
|
86
|
+
}
|
|
87
|
+
peek() {
|
|
88
|
+
return this.tokens[this.pos];
|
|
89
|
+
}
|
|
90
|
+
consume() {
|
|
91
|
+
const t = this.tokens[this.pos];
|
|
92
|
+
if (!t)
|
|
93
|
+
throw new Error('Unexpected end of expression');
|
|
94
|
+
this.pos++;
|
|
95
|
+
return t;
|
|
96
|
+
}
|
|
97
|
+
expect(type) {
|
|
98
|
+
const t = this.consume();
|
|
99
|
+
if (t.type !== type)
|
|
100
|
+
throw new Error(`Expected ${type}, got ${t.type} ('${t.value}')`);
|
|
101
|
+
return t;
|
|
102
|
+
}
|
|
103
|
+
parse(minBp = 0) {
|
|
104
|
+
if (++this.depth > MAX_EXPR_DEPTH)
|
|
105
|
+
throw new Error('Expression is too deeply nested');
|
|
106
|
+
let left = this.parsePrefix();
|
|
107
|
+
while (true) {
|
|
108
|
+
const t = this.peek();
|
|
109
|
+
if (!t || t.type !== 'OP')
|
|
110
|
+
break;
|
|
111
|
+
const lbp = LEFT_BP[t.value];
|
|
112
|
+
if (lbp === undefined || lbp <= minBp)
|
|
113
|
+
break;
|
|
114
|
+
this.consume();
|
|
115
|
+
const rbp = RIGHT_BP[t.value];
|
|
116
|
+
const right = this.parse(rbp);
|
|
117
|
+
left = { kind: 'binary', op: t.value, left, right };
|
|
118
|
+
}
|
|
119
|
+
this.depth--;
|
|
120
|
+
return left;
|
|
121
|
+
}
|
|
122
|
+
parsePrefix() {
|
|
123
|
+
const t = this.peek();
|
|
124
|
+
if (!t)
|
|
125
|
+
throw new Error('Unexpected end of expression');
|
|
126
|
+
// Unary +/-
|
|
127
|
+
if (t.type === 'OP' && (t.value === '+' || t.value === '-')) {
|
|
128
|
+
this.consume();
|
|
129
|
+
const operand = this.parse(UNARY_BP);
|
|
130
|
+
if (t.value === '+')
|
|
131
|
+
return operand;
|
|
132
|
+
return { kind: 'unary', op: '-', operand };
|
|
133
|
+
}
|
|
134
|
+
// Number
|
|
135
|
+
if (t.type === 'NUMBER') {
|
|
136
|
+
this.consume();
|
|
137
|
+
const v = parseFloat(t.value);
|
|
138
|
+
if (isNaN(v))
|
|
139
|
+
throw new Error(`Invalid number: ${t.value}`);
|
|
140
|
+
return { kind: 'number', value: v };
|
|
141
|
+
}
|
|
142
|
+
// Parenthesized expression
|
|
143
|
+
if (t.type === 'LPAREN') {
|
|
144
|
+
this.consume();
|
|
145
|
+
const node = this.parse(0);
|
|
146
|
+
this.expect('RPAREN');
|
|
147
|
+
return node;
|
|
148
|
+
}
|
|
149
|
+
// Identifier: constant or function call
|
|
150
|
+
if (t.type === 'IDENT') {
|
|
151
|
+
this.consume();
|
|
152
|
+
const name = t.value;
|
|
153
|
+
// Function call
|
|
154
|
+
if (this.peek()?.type === 'LPAREN') {
|
|
155
|
+
if (!FUNCTIONS.has(name))
|
|
156
|
+
throw new Error(`Unknown function: '${name}'`);
|
|
157
|
+
this.consume(); // (
|
|
158
|
+
const args = [];
|
|
159
|
+
if (this.peek()?.type !== 'RPAREN') {
|
|
160
|
+
args.push(this.parse(0));
|
|
161
|
+
while (this.peek()?.type === 'COMMA') {
|
|
162
|
+
this.consume();
|
|
163
|
+
args.push(this.parse(0));
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
this.expect('RPAREN');
|
|
167
|
+
return { kind: 'call', name, args };
|
|
168
|
+
}
|
|
169
|
+
// Constant
|
|
170
|
+
if (Object.hasOwn(CONSTANTS, name))
|
|
171
|
+
return { kind: 'const', name };
|
|
172
|
+
throw new Error(`Unknown identifier: '${name}'`);
|
|
173
|
+
}
|
|
174
|
+
throw new Error(`Unexpected token: '${t.value}'`);
|
|
175
|
+
}
|
|
176
|
+
run() {
|
|
177
|
+
const ast = this.parse(0);
|
|
178
|
+
if (this.pos < this.tokens.length) {
|
|
179
|
+
throw new Error(`Unexpected token after expression: '${this.tokens[this.pos].value}'`);
|
|
180
|
+
}
|
|
181
|
+
return ast;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
function evalNode(node) {
|
|
185
|
+
switch (node.kind) {
|
|
186
|
+
case 'number':
|
|
187
|
+
return node.value;
|
|
188
|
+
case 'const':
|
|
189
|
+
return CONSTANTS[node.name];
|
|
190
|
+
case 'unary':
|
|
191
|
+
return -evalNode(node.operand);
|
|
192
|
+
case 'binary': {
|
|
193
|
+
const l = evalNode(node.left);
|
|
194
|
+
const r = evalNode(node.right);
|
|
195
|
+
switch (node.op) {
|
|
196
|
+
case '+':
|
|
197
|
+
return l + r;
|
|
198
|
+
case '-':
|
|
199
|
+
return l - r;
|
|
200
|
+
case '*':
|
|
201
|
+
return l * r;
|
|
202
|
+
case '/':
|
|
203
|
+
if (r === 0)
|
|
204
|
+
throw new Error('Division by zero');
|
|
205
|
+
return l / r;
|
|
206
|
+
case '%':
|
|
207
|
+
if (r === 0)
|
|
208
|
+
throw new Error('Division by zero');
|
|
209
|
+
return l % r;
|
|
210
|
+
case '^':
|
|
211
|
+
return Math.pow(l, r);
|
|
212
|
+
default:
|
|
213
|
+
throw new Error(`Unknown operator: '${node.op}'`);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
case 'call': {
|
|
217
|
+
const args = node.args.map(evalNode);
|
|
218
|
+
switch (node.name) {
|
|
219
|
+
case 'sqrt':
|
|
220
|
+
return Math.sqrt(args[0]);
|
|
221
|
+
case 'abs':
|
|
222
|
+
return Math.abs(args[0]);
|
|
223
|
+
case 'ceil':
|
|
224
|
+
return Math.ceil(args[0]);
|
|
225
|
+
case 'floor':
|
|
226
|
+
return Math.floor(args[0]);
|
|
227
|
+
case 'round':
|
|
228
|
+
return Math.round(args[0]);
|
|
229
|
+
case 'sin':
|
|
230
|
+
return Math.sin(args[0]);
|
|
231
|
+
case 'cos':
|
|
232
|
+
return Math.cos(args[0]);
|
|
233
|
+
case 'tan':
|
|
234
|
+
return Math.tan(args[0]);
|
|
235
|
+
case 'log':
|
|
236
|
+
return Math.log(args[0]);
|
|
237
|
+
case 'log2':
|
|
238
|
+
return Math.log2(args[0]);
|
|
239
|
+
case 'log10':
|
|
240
|
+
return Math.log10(args[0]);
|
|
241
|
+
case 'exp':
|
|
242
|
+
return Math.exp(args[0]);
|
|
243
|
+
case 'min':
|
|
244
|
+
if (args.length !== 2)
|
|
245
|
+
throw new Error('Function min() requires exactly 2 arguments');
|
|
246
|
+
return Math.min(args[0], args[1]);
|
|
247
|
+
case 'max':
|
|
248
|
+
if (args.length !== 2)
|
|
249
|
+
throw new Error('Function max() requires exactly 2 arguments');
|
|
250
|
+
return Math.max(args[0], args[1]);
|
|
251
|
+
default:
|
|
252
|
+
throw new Error(`Unknown function: '${node.name}'`);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Evaluates a mathematical expression string and returns the result.
|
|
259
|
+
*
|
|
260
|
+
* @param expr - Math expression; supports +, -, *, /, %, ^, unary -, parentheses, constants (pi, e) and functions (sin, cos, tan, sqrt, abs, ceil, floor, round, log, log2, log10, exp, min, max)
|
|
261
|
+
* @param precision - Number of decimal places in the result (0–15, default 10)
|
|
262
|
+
* @returns Object with the original expression, numeric result, and applied precision
|
|
263
|
+
* @throws Error if the expression is empty, exceeds the maximum length, contains unknown identifiers, or produces a non-finite result
|
|
264
|
+
*/
|
|
265
|
+
export default function evaluate(expr, precision) {
|
|
266
|
+
if (!expr || typeof expr !== 'string' || expr.trim() === '') {
|
|
267
|
+
throw new Error('Please provide a math expression');
|
|
268
|
+
}
|
|
269
|
+
if (expr.length > MAX_EXPR_LENGTH) {
|
|
270
|
+
throw new Error(`Expression cannot exceed ${MAX_EXPR_LENGTH} characters`);
|
|
271
|
+
}
|
|
272
|
+
const prec = Math.min(15, Math.max(0, precision !== undefined && Number.isFinite(precision) ? Math.floor(precision) : 10));
|
|
273
|
+
const tokens = tokenize(expr.trim());
|
|
274
|
+
if (tokens.length === 0)
|
|
275
|
+
throw new Error('Please provide a math expression');
|
|
276
|
+
const parser = new Parser(tokens);
|
|
277
|
+
const ast = parser.run();
|
|
278
|
+
const raw = evalNode(ast);
|
|
279
|
+
if (!isFinite(raw))
|
|
280
|
+
throw new Error('Result is not finite (overflow or undefined operation)');
|
|
281
|
+
const result = Number(raw.toFixed(prec));
|
|
282
|
+
return { expression: expr, result, precision: prec };
|
|
283
|
+
}
|
|
284
|
+
//# sourceMappingURL=evaluate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"evaluate.js","sourceRoot":"","sources":["../../../src/modules/v5/evaluate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface JwtResult {
|
|
2
|
+
header: Record<string, unknown>;
|
|
3
|
+
payload: Record<string, unknown>;
|
|
4
|
+
signature: string;
|
|
5
|
+
expired?: boolean;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Decodes a JSON Web Token (header + payload) without verifying the signature.
|
|
9
|
+
* WARNING: The signature is NOT verified. Use this for inspection only, not for security decisions.
|
|
10
|
+
*/
|
|
11
|
+
export default function jwt(token: string): JwtResult;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { MAX_JWT_LENGTH } from '../../constants.js';
|
|
2
|
+
/**
|
|
3
|
+
* Decodes a JSON Web Token (header + payload) without verifying the signature.
|
|
4
|
+
* WARNING: The signature is NOT verified. Use this for inspection only, not for security decisions.
|
|
5
|
+
*/
|
|
6
|
+
export default function jwt(token) {
|
|
7
|
+
if (!token)
|
|
8
|
+
throw new Error('Please provide a token (?token={token})');
|
|
9
|
+
if (token.length > MAX_JWT_LENGTH)
|
|
10
|
+
throw new Error(`Token cannot exceed ${MAX_JWT_LENGTH} characters`);
|
|
11
|
+
const parts = token.split('.');
|
|
12
|
+
if (parts.length !== 3)
|
|
13
|
+
throw new Error('Invalid JWT format. Expected 3 parts separated by "."');
|
|
14
|
+
const [headerB64, payloadB64, signature] = parts;
|
|
15
|
+
const isObject = (v) => typeof v === 'object' && v !== null && !Array.isArray(v);
|
|
16
|
+
let header;
|
|
17
|
+
let payload;
|
|
18
|
+
try {
|
|
19
|
+
const parsed = JSON.parse(Buffer.from(headerB64, 'base64url').toString('utf-8'));
|
|
20
|
+
if (!isObject(parsed))
|
|
21
|
+
throw new Error();
|
|
22
|
+
header = parsed;
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
throw new Error('Invalid JWT header: not a valid base64url-encoded JSON object');
|
|
26
|
+
}
|
|
27
|
+
try {
|
|
28
|
+
const parsed = JSON.parse(Buffer.from(payloadB64, 'base64url').toString('utf-8'));
|
|
29
|
+
if (!isObject(parsed))
|
|
30
|
+
throw new Error();
|
|
31
|
+
payload = parsed;
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
throw new Error('Invalid JWT payload: not a valid base64url-encoded JSON object');
|
|
35
|
+
}
|
|
36
|
+
const result = { header, payload, signature };
|
|
37
|
+
if (typeof payload.exp === 'number') {
|
|
38
|
+
result.expired = Date.now() / 1000 > payload.exp;
|
|
39
|
+
}
|
|
40
|
+
return result;
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=jwt.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jwt.js","sourceRoot":"","sources":["../../../src/modules/v5/jwt.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AASpD;;;GAGG;AACH,MAAM,CAAC,OAAO,UAAU,GAAG,CAAC,KAAa;IACrC,IAAI,CAAC,KAAK;QAAE,MAAM,IAAI,KAAK,CAAC,yCAAyC,CAAC,CAAC;IACvE,IAAI,KAAK,CAAC,MAAM,GAAG,cAAc;QAAE,MAAM,IAAI,KAAK,CAAC,uBAAuB,cAAc,aAAa,CAAC,CAAC;IAEvG,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC/B,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,uDAAuD,CAAC,CAAC;IAEjG,MAAM,CAAC,SAAS,EAAE,UAAU,EAAE,SAAS,CAAC,GAAG,KAAiC,CAAC;IAE7E,MAAM,QAAQ,GAAG,CAAC,CAAU,EAAgC,EAAE,CAC1D,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IAE7D,IAAI,MAA+B,CAAC;IACpC,IAAI,OAAgC,CAAC;IAErC,IAAI,CAAC;QACD,MAAM,MAAM,GAAY,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;QAC1F,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC;YAAE,MAAM,IAAI,KAAK,EAAE,CAAC;QACzC,MAAM,GAAG,MAAM,CAAC;IACpB,CAAC;IAAC,MAAM,CAAC;QACL,MAAM,IAAI,KAAK,CAAC,+DAA+D,CAAC,CAAC;IACrF,CAAC;IAED,IAAI,CAAC;QACD,MAAM,MAAM,GAAY,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;QAC3F,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC;YAAE,MAAM,IAAI,KAAK,EAAE,CAAC;QACzC,OAAO,GAAG,MAAM,CAAC;IACrB,CAAC;IAAC,MAAM,CAAC;QACL,MAAM,IAAI,KAAK,CAAC,gEAAgE,CAAC,CAAC;IACtF,CAAC;IAED,MAAM,MAAM,GAAc,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC;IAEzD,IAAI,OAAO,OAAO,CAAC,GAAG,KAAK,QAAQ,EAAE,CAAC;QAClC,MAAM,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC;IACrD,CAAC;IAED,OAAO,MAAM,CAAC;AAClB,CAAC"}
|