coakka-logger-node 1.2.1

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.
Files changed (53) hide show
  1. package/CONSUMING.md +35 -0
  2. package/LICENSE.md +115 -0
  3. package/README.md +45 -0
  4. package/dist/index.d.ts +4 -0
  5. package/dist/index.js +4 -0
  6. package/dist/logger.d.ts +35 -0
  7. package/dist/logger.js +121 -0
  8. package/dist/native-loader.d.ts +11 -0
  9. package/dist/native-loader.js +94 -0
  10. package/dist/native.d.ts +125 -0
  11. package/dist/native.js +363 -0
  12. package/dist/packaging.d.ts +4 -0
  13. package/dist/packaging.js +4 -0
  14. package/native/.gitkeep +1 -0
  15. package/native/linux-aarch64/libcoakka_logger_core-1.2.1+f50756ebff0d.so +0 -0
  16. package/native/linux-aarch64/libcoakka_logger_core.so +0 -0
  17. package/native/linux-x86_64/libcoakka_logger_core-1.2.1+f50756ebff0d.so +0 -0
  18. package/native/linux-x86_64/libcoakka_logger_core.so +0 -0
  19. package/native/macos-aarch64/libcoakka_logger_core-1.2.1+f50756ebff0d.dylib +0 -0
  20. package/native/macos-aarch64/libcoakka_logger_core.dylib +0 -0
  21. package/native/windows-aarch64/libcoakka_logger_core-1.2.1+f50756ebff0d.dll +0 -0
  22. package/native/windows-aarch64/libcoakka_logger_core.dll +0 -0
  23. package/native/windows-x86_64/libcoakka_logger_core-1.2.1+f50756ebff0d.dll +0 -0
  24. package/native/windows-x86_64/libcoakka_logger_core.dll +0 -0
  25. package/package.json +31 -0
  26. package/vendor/koffi/LICENSE.txt +22 -0
  27. package/vendor/koffi/build/koffi/darwin_arm64/koffi.node +0 -0
  28. package/vendor/koffi/build/koffi/darwin_x64/koffi.node +0 -0
  29. package/vendor/koffi/build/koffi/freebsd_arm64/koffi.node +0 -0
  30. package/vendor/koffi/build/koffi/freebsd_ia32/koffi.node +0 -0
  31. package/vendor/koffi/build/koffi/freebsd_x64/koffi.node +0 -0
  32. package/vendor/koffi/build/koffi/linux_arm64/koffi.node +0 -0
  33. package/vendor/koffi/build/koffi/linux_armhf/koffi.node +0 -0
  34. package/vendor/koffi/build/koffi/linux_ia32/koffi.node +0 -0
  35. package/vendor/koffi/build/koffi/linux_loong64/koffi.node +0 -0
  36. package/vendor/koffi/build/koffi/linux_riscv64d/koffi.node +0 -0
  37. package/vendor/koffi/build/koffi/linux_x64/koffi.node +0 -0
  38. package/vendor/koffi/build/koffi/musl_arm64/koffi.node +0 -0
  39. package/vendor/koffi/build/koffi/musl_x64/koffi.node +0 -0
  40. package/vendor/koffi/build/koffi/openbsd_ia32/koffi.node +0 -0
  41. package/vendor/koffi/build/koffi/openbsd_x64/koffi.node +0 -0
  42. package/vendor/koffi/build/koffi/win32_arm64/koffi.exp +0 -0
  43. package/vendor/koffi/build/koffi/win32_arm64/koffi.lib +0 -0
  44. package/vendor/koffi/build/koffi/win32_arm64/koffi.node +0 -0
  45. package/vendor/koffi/build/koffi/win32_ia32/koffi.exp +0 -0
  46. package/vendor/koffi/build/koffi/win32_ia32/koffi.lib +0 -0
  47. package/vendor/koffi/build/koffi/win32_ia32/koffi.node +0 -0
  48. package/vendor/koffi/build/koffi/win32_x64/koffi.exp +0 -0
  49. package/vendor/koffi/build/koffi/win32_x64/koffi.lib +0 -0
  50. package/vendor/koffi/build/koffi/win32_x64/koffi.node +0 -0
  51. package/vendor/koffi/index.d.ts +288 -0
  52. package/vendor/koffi/index.js +634 -0
  53. package/vendor/koffi/package.json +38 -0
package/dist/native.js ADDED
@@ -0,0 +1,363 @@
1
+ import koffi from "../vendor/koffi/index.js";
2
+ export const COAKKA_LOGGER_CORE_ABI_VERSION = 10;
3
+ export const CoakkaLoggerStatus = {
4
+ OK: 0,
5
+ INVALID_ARGUMENT: 1,
6
+ BAD_STATE: 2,
7
+ QUEUE_FULL: 3,
8
+ RECORD_TOO_LARGE: 4,
9
+ TIMED_OUT: 5,
10
+ BUFFER_TOO_SMALL: 6,
11
+ INTERNAL_ERROR: 7,
12
+ };
13
+ export const CoakkaLoggerLevel = {
14
+ TRACE: 0,
15
+ DEBUG: 1,
16
+ INFO: 2,
17
+ WARN: 3,
18
+ ERROR: 4,
19
+ FATAL: 5,
20
+ };
21
+ export const CoakkaLoggerSinkMode = {
22
+ MANUAL_DRAIN: 0,
23
+ FILE: 1,
24
+ CONSOLE: 2,
25
+ MULTI: 3,
26
+ };
27
+ export const CoakkaLoggerSinkTarget = {
28
+ NONE: 0,
29
+ FILE: 1 << 0,
30
+ CONSOLE: 1 << 1,
31
+ };
32
+ export const CoakkaLoggerPressureState = {
33
+ NORMAL: 0,
34
+ QUOTA_PRESSURE: 1,
35
+ DROP_LOW_PRIORITY: 2,
36
+ EMERGENCY_ONLY: 3,
37
+ };
38
+ export const CoakkaLoggerLevelMask = {
39
+ TRACE: 1 << CoakkaLoggerLevel.TRACE,
40
+ DEBUG: 1 << CoakkaLoggerLevel.DEBUG,
41
+ INFO: 1 << CoakkaLoggerLevel.INFO,
42
+ WARN: 1 << CoakkaLoggerLevel.WARN,
43
+ ERROR: 1 << CoakkaLoggerLevel.ERROR,
44
+ FATAL: 1 << CoakkaLoggerLevel.FATAL,
45
+ ALL: (1 << 6) - 1,
46
+ };
47
+ const LoggerCoreInfoStruct = koffi.struct("coakka_logger_core_info_t", {
48
+ struct_size: koffi.types.size_t,
49
+ abi_version: "uint32_t",
50
+ runtime_version: "str",
51
+ git_commit: "str",
52
+ docs_hint: "str",
53
+ });
54
+ const LoggerCoreConfigStruct = koffi.struct("coakka_logger_core_config_t", {
55
+ struct_size: koffi.types.size_t,
56
+ system_name: "str",
57
+ queue_capacity: "uint32_t",
58
+ min_level: "int",
59
+ sink_mode: "int",
60
+ output_path: "str",
61
+ max_file_size_bytes: "uint64_t",
62
+ max_total_size_bytes: "uint64_t",
63
+ pressure_state: "int",
64
+ max_archived_files: "uint32_t",
65
+ category_capacity: "uint32_t",
66
+ message_capacity: "uint32_t",
67
+ emergency_output_path: "str",
68
+ emergency_file_size_bytes: "uint64_t",
69
+ category_override_capacity: "uint32_t",
70
+ sink_targets: "uint32_t",
71
+ console_fd: "int32_t",
72
+ console_stdout_fd: "int32_t",
73
+ console_stderr_fd: "int32_t",
74
+ console_stdout_level_mask: "uint32_t",
75
+ console_stderr_level_mask: "uint32_t",
76
+ file_output_path: "str",
77
+ file_max_size_bytes: "uint64_t",
78
+ file_total_size_limit_bytes: "uint64_t",
79
+ file_max_archived_files: "uint32_t",
80
+ file_emergency_output_path: "str",
81
+ file_emergency_size_bytes: "uint64_t",
82
+ });
83
+ const LoggerCoreConfigViewStruct = koffi.struct("coakka_logger_core_config_view_t", {
84
+ struct_size: koffi.types.size_t,
85
+ system_name: "str",
86
+ state: "int",
87
+ queue_capacity: "uint32_t",
88
+ min_level: "int",
89
+ sink_mode: "int",
90
+ output_path: "str",
91
+ max_file_size_bytes: "uint64_t",
92
+ max_total_size_bytes: "uint64_t",
93
+ pressure_state: "int",
94
+ max_archived_files: "uint32_t",
95
+ category_capacity: "uint32_t",
96
+ message_capacity: "uint32_t",
97
+ emergency_output_path: "str",
98
+ emergency_file_size_bytes: "uint64_t",
99
+ category_override_capacity: "uint32_t",
100
+ sink_targets: "uint32_t",
101
+ console_fd: "int32_t",
102
+ console_stdout_fd: "int32_t",
103
+ console_stderr_fd: "int32_t",
104
+ console_stdout_level_mask: "uint32_t",
105
+ console_stderr_level_mask: "uint32_t",
106
+ file_output_path: "str",
107
+ file_max_size_bytes: "uint64_t",
108
+ file_total_size_limit_bytes: "uint64_t",
109
+ file_max_archived_files: "uint32_t",
110
+ file_emergency_output_path: "str",
111
+ file_emergency_size_bytes: "uint64_t",
112
+ });
113
+ const LoggerCoreStatsStruct = koffi.struct("coakka_logger_core_stats_t", {
114
+ struct_size: koffi.types.size_t,
115
+ state: "int",
116
+ queue_capacity: "uint32_t",
117
+ queue_depth: "uint32_t",
118
+ queue_high_watermark: "uint32_t",
119
+ next_sequence: "uint64_t",
120
+ emitted_count: "uint64_t",
121
+ delivered_count: "uint64_t",
122
+ dropped_count: "uint64_t",
123
+ dropped_below_level_count: "uint64_t",
124
+ sink_write_count: "uint64_t",
125
+ sink_bytes_written: "uint64_t",
126
+ sink_write_failure_count: "uint64_t",
127
+ sink_current_file_size_bytes: "uint64_t",
128
+ sink_total_size_bytes: "uint64_t",
129
+ pressure_state: "int",
130
+ sink_roll_count: "uint64_t",
131
+ sink_deleted_archive_count: "uint64_t",
132
+ dropped_pressure_count: "uint64_t",
133
+ emergency_active: "uint32_t",
134
+ emergency_last_reason: "int",
135
+ emergency_enter_count: "uint64_t",
136
+ emergency_recovered_count: "uint64_t",
137
+ emergency_bytes_written: "uint64_t",
138
+ emergency_write_failure_count: "uint64_t",
139
+ emergency_overwrite_count: "uint64_t",
140
+ emergency_last_recovered_reason: "int",
141
+ emergency_last_recovered_duration_ms: "uint64_t",
142
+ emergency_last_recovered_dropped_total: "uint64_t",
143
+ emergency_last_recovered_dropped_pressure: "uint64_t",
144
+ emergency_last_recovered_deleted_archives: "uint64_t",
145
+ reload_count: "uint64_t",
146
+ category_override_count: "uint32_t",
147
+ sink_reopen_failure_count: "uint64_t",
148
+ sink_roll_failure_count: "uint64_t",
149
+ sink_append_failure_count: "uint64_t",
150
+ sink_cleanup_failure_count: "uint64_t",
151
+ file_write_count: "uint64_t",
152
+ file_bytes_written: "uint64_t",
153
+ file_write_failure_count: "uint64_t",
154
+ file_current_size_bytes: "uint64_t",
155
+ file_total_size_bytes: "uint64_t",
156
+ file_roll_count: "uint64_t",
157
+ file_deleted_archive_count: "uint64_t",
158
+ file_reopen_failure_count: "uint64_t",
159
+ file_roll_failure_count: "uint64_t",
160
+ file_append_failure_count: "uint64_t",
161
+ file_cleanup_failure_count: "uint64_t",
162
+ console_write_count: "uint64_t",
163
+ console_bytes_written: "uint64_t",
164
+ console_write_failure_count: "uint64_t",
165
+ });
166
+ const LoggerCoreRecordBufferStruct = koffi.struct("coakka_logger_core_record_buffer_t", {
167
+ struct_size: koffi.types.size_t,
168
+ sequence: "uint64_t",
169
+ wall_time_unix_ms: "uint64_t",
170
+ monotonic_time_ns: "uint64_t",
171
+ level: "int",
172
+ category: "char *",
173
+ category_capacity: koffi.types.size_t,
174
+ category_length: koffi.types.size_t,
175
+ message: "char *",
176
+ message_capacity: koffi.types.size_t,
177
+ message_length: koffi.types.size_t,
178
+ });
179
+ koffi.opaque("coakka_logger_core_handle_t");
180
+ function decodeText(value) {
181
+ return value ?? "";
182
+ }
183
+ export class LoggerStatusError extends Error {
184
+ operation;
185
+ status;
186
+ statusName;
187
+ constructor(operation, status, statusName) {
188
+ super(`${operation} failed: ${statusName} (${status})`);
189
+ this.operation = operation;
190
+ this.status = status;
191
+ this.statusName = statusName;
192
+ }
193
+ }
194
+ export class NativeLoggerBindings {
195
+ loggerLibPath;
196
+ lib;
197
+ getAbiVersionFn;
198
+ getInfoFn;
199
+ createFn;
200
+ startFn;
201
+ stopFn;
202
+ destroyFn;
203
+ getConfigFn;
204
+ getStatsFn;
205
+ isEnabledFn;
206
+ isEnabledForCategoryFn;
207
+ logFn;
208
+ readNextFn;
209
+ statusNameFn;
210
+ levelNameFn;
211
+ stateNameFn;
212
+ constructor(loggerLibPath) {
213
+ this.loggerLibPath = loggerLibPath;
214
+ this.lib = koffi.load(loggerLibPath);
215
+ this.getAbiVersionFn = this.lib.func("uint32_t coakka_logger_core_get_abi_version(void)");
216
+ this.getInfoFn = this.lib.func("int coakka_logger_core_get_info(_Inout_ coakka_logger_core_info_t *out_info)");
217
+ this.createFn = this.lib.func("int coakka_logger_core_create(const coakka_logger_core_config_t *config, _Out_ coakka_logger_core_handle_t **out_handle)");
218
+ this.startFn = this.lib.func("int coakka_logger_core_start(coakka_logger_core_handle_t *handle)");
219
+ this.stopFn = this.lib.func("int coakka_logger_core_stop(coakka_logger_core_handle_t *handle)");
220
+ this.destroyFn = this.lib.func("void coakka_logger_core_destroy(coakka_logger_core_handle_t *handle)");
221
+ this.getConfigFn = this.lib.func("int coakka_logger_core_get_config(coakka_logger_core_handle_t *handle, _Inout_ coakka_logger_core_config_view_t *out_view)");
222
+ this.getStatsFn = this.lib.func("int coakka_logger_core_get_stats(coakka_logger_core_handle_t *handle, _Inout_ coakka_logger_core_stats_t *out_stats)");
223
+ this.isEnabledFn = this.lib.func("int coakka_logger_core_is_enabled(coakka_logger_core_handle_t *handle, int level)");
224
+ this.isEnabledForCategoryFn = this.lib.func("int coakka_logger_core_is_enabled_for_category(coakka_logger_core_handle_t *handle, const char *category, int level)");
225
+ this.logFn = this.lib.func("int coakka_logger_core_log(coakka_logger_core_handle_t *handle, int level, const char *category, const char *message, _Out_ uint64_t *out_sequence)");
226
+ this.readNextFn = this.lib.func("int coakka_logger_core_read_next(coakka_logger_core_handle_t *handle, uint32_t timeout_ms, _Inout_ coakka_logger_core_record_buffer_t *out_record)");
227
+ this.statusNameFn = this.lib.func("const char *coakka_logger_status_name(int status)");
228
+ this.levelNameFn = this.lib.func("const char *coakka_logger_level_name(int level)");
229
+ this.stateNameFn = this.lib.func("const char *coakka_logger_state_name(int state)");
230
+ }
231
+ getAbiVersion() {
232
+ return this.getAbiVersionFn();
233
+ }
234
+ readInfo() {
235
+ const info = { struct_size: koffi.sizeof(LoggerCoreInfoStruct) };
236
+ this.requireOk(this.getInfoFn(info), "logger_core_get_info");
237
+ return {
238
+ abiVersion: Number(info.abi_version),
239
+ runtimeVersion: decodeText(info.runtime_version),
240
+ gitCommit: decodeText(info.git_commit),
241
+ docsHint: decodeText(info.docs_hint),
242
+ };
243
+ }
244
+ create(config) {
245
+ const outHandle = [null];
246
+ const nativeConfig = {
247
+ struct_size: koffi.sizeof(LoggerCoreConfigStruct),
248
+ system_name: config.systemName,
249
+ queue_capacity: config.queueCapacity,
250
+ min_level: config.minLevel,
251
+ sink_mode: CoakkaLoggerSinkMode.MANUAL_DRAIN,
252
+ output_path: null,
253
+ max_file_size_bytes: 0,
254
+ max_total_size_bytes: 0,
255
+ pressure_state: CoakkaLoggerPressureState.NORMAL,
256
+ max_archived_files: 0,
257
+ category_capacity: config.categoryCapacity,
258
+ message_capacity: config.messageCapacity,
259
+ emergency_output_path: null,
260
+ emergency_file_size_bytes: 0,
261
+ category_override_capacity: 32,
262
+ sink_targets: CoakkaLoggerSinkTarget.NONE,
263
+ console_fd: -1,
264
+ console_stdout_fd: -1,
265
+ console_stderr_fd: -1,
266
+ console_stdout_level_mask: CoakkaLoggerLevelMask.TRACE | CoakkaLoggerLevelMask.DEBUG | CoakkaLoggerLevelMask.INFO,
267
+ console_stderr_level_mask: CoakkaLoggerLevelMask.WARN | CoakkaLoggerLevelMask.ERROR | CoakkaLoggerLevelMask.FATAL,
268
+ file_output_path: null,
269
+ file_max_size_bytes: 0,
270
+ file_total_size_limit_bytes: 0,
271
+ file_max_archived_files: 0,
272
+ file_emergency_output_path: null,
273
+ file_emergency_size_bytes: 0,
274
+ };
275
+ this.requireOk(this.createFn(nativeConfig, outHandle), "logger_core_create");
276
+ const handle = outHandle[0];
277
+ if (handle == null) {
278
+ throw new Error("logger_core_create returned null handle");
279
+ }
280
+ return handle;
281
+ }
282
+ start(handle) {
283
+ this.requireOk(this.startFn(handle), "logger_core_start");
284
+ }
285
+ stop(handle) {
286
+ this.requireOk(this.stopFn(handle), "logger_core_stop");
287
+ }
288
+ destroy(handle) {
289
+ this.destroyFn(handle);
290
+ }
291
+ config(handle) {
292
+ const view = { struct_size: koffi.sizeof(LoggerCoreConfigViewStruct) };
293
+ this.requireOk(this.getConfigFn(handle, view), "logger_core_get_config");
294
+ const state = Number(view.state);
295
+ return {
296
+ systemName: decodeText(view.system_name),
297
+ state,
298
+ stateName: decodeText(this.stateNameFn(state)),
299
+ queueCapacity: Number(view.queue_capacity),
300
+ categoryCapacity: Number(view.category_capacity),
301
+ messageCapacity: Number(view.message_capacity),
302
+ };
303
+ }
304
+ stats(handle) {
305
+ const stats = { struct_size: koffi.sizeof(LoggerCoreStatsStruct) };
306
+ this.requireOk(this.getStatsFn(handle, stats), "logger_core_get_stats");
307
+ const state = Number(stats.state);
308
+ return {
309
+ state,
310
+ stateName: decodeText(this.stateNameFn(state)),
311
+ queueCapacity: Number(stats.queue_capacity),
312
+ queueDepth: Number(stats.queue_depth),
313
+ queueHighWatermark: Number(stats.queue_high_watermark),
314
+ nextSequence: Number(stats.next_sequence),
315
+ emittedCount: Number(stats.emitted_count),
316
+ deliveredCount: Number(stats.delivered_count),
317
+ droppedCount: Number(stats.dropped_count),
318
+ };
319
+ }
320
+ isEnabled(handle, level) {
321
+ return this.isEnabledFn(handle, level) !== 0;
322
+ }
323
+ isEnabledForCategory(handle, category, level) {
324
+ return this.isEnabledForCategoryFn(handle, category, level) !== 0;
325
+ }
326
+ log(handle, level, category, message) {
327
+ const outSequence = [0];
328
+ this.requireOk(this.logFn(handle, level, category, message, outSequence), "logger_core_log");
329
+ return Number(outSequence[0]);
330
+ }
331
+ readNext(handle, timeoutMs, categoryCapacity, messageCapacity) {
332
+ const category = Buffer.alloc(Math.max(1, categoryCapacity));
333
+ const message = Buffer.alloc(Math.max(1, messageCapacity));
334
+ const record = {
335
+ struct_size: koffi.sizeof(LoggerCoreRecordBufferStruct),
336
+ category,
337
+ category_capacity: category.byteLength,
338
+ message,
339
+ message_capacity: message.byteLength,
340
+ };
341
+ const status = this.readNextFn(handle, timeoutMs, record);
342
+ if (status === CoakkaLoggerStatus.TIMED_OUT) {
343
+ return null;
344
+ }
345
+ this.requireOk(status, "logger_core_read_next");
346
+ const level = Number(record.level);
347
+ return {
348
+ sequence: Number(record.sequence),
349
+ wallTimeUnixMs: Number(record.wall_time_unix_ms),
350
+ monotonicTimeNs: Number(record.monotonic_time_ns),
351
+ level,
352
+ levelName: decodeText(this.levelNameFn(level)),
353
+ category: category.toString("utf8", 0, Number(record.category_length)),
354
+ message: message.toString("utf8", 0, Number(record.message_length)),
355
+ };
356
+ }
357
+ requireOk(status, operation) {
358
+ if (status === CoakkaLoggerStatus.OK) {
359
+ return;
360
+ }
361
+ throw new LoggerStatusError(operation, status, decodeText(this.statusNameFn(status)));
362
+ }
363
+ }
@@ -0,0 +1,4 @@
1
+ export declare const LOGGER_NODE_VERSION = "1.2.1";
2
+ export declare const LOGGER_NATIVE_CORE_VERSION = "1.2.1";
3
+ export declare const LOGGER_NATIVE_GIT_COMMIT = "f50756ebff0d";
4
+ export declare const LOGGER_NATIVE_PACKAGE_VERSION = "1.2.1+f50756ebff0d";
@@ -0,0 +1,4 @@
1
+ export const LOGGER_NODE_VERSION = "1.2.1";
2
+ export const LOGGER_NATIVE_CORE_VERSION = "1.2.1";
3
+ export const LOGGER_NATIVE_GIT_COMMIT = "f50756ebff0d";
4
+ export const LOGGER_NATIVE_PACKAGE_VERSION = "1.2.1+f50756ebff0d";
@@ -0,0 +1 @@
1
+
package/package.json ADDED
@@ -0,0 +1,31 @@
1
+ {
2
+ "name": "coakka-logger-node",
3
+ "version": "1.2.1",
4
+ "description": "Node.js connector package for the CoAkka native logger core",
5
+ "license": "SEE LICENSE IN LICENSE.md",
6
+ "type": "module",
7
+ "main": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "files": [
10
+ "dist",
11
+ "native",
12
+ "vendor",
13
+ "CONSUMING.md",
14
+ "LICENSE.md",
15
+ "README.md"
16
+ ],
17
+ "scripts": {
18
+ "build": "npm run stage:native && tsc -p tsconfig.json && node scripts/vendor-koffi.mjs",
19
+ "stage:native": "node scripts/stage-logger-natives.mjs",
20
+ "test": "tsx --test test/**/*.test.ts",
21
+ "verify": "npm run build && npm test",
22
+ "pack:release": "npm run build && npm pack",
23
+ "smoke:packaged": "bash scripts/smoke-packaged-package.sh"
24
+ },
25
+ "devDependencies": {
26
+ "@types/node": "^24.0.0",
27
+ "koffi": "^2.16.1",
28
+ "tsx": "^4.21.0",
29
+ "typescript": "^5.8.3"
30
+ }
31
+ }
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (C) 2025 Niels Martignène <niels.martignene@protonmail.com>
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ this software and associated documentation files (the “Software”), to deal in
7
+ the Software without restriction, including without limitation the rights to use,
8
+ copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
9
+ Software, and to permit persons to whom the Software is furnished to do so,
10
+ 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,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
+ OTHER DEALINGS IN THE SOFTWARE.