python-calamine 0.8.2__cp314-cp314-pyemscripten_2026_0_wasm32.whl
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.
- python_calamine/__init__.py +37 -0
- python_calamine/_python_calamine.cpython-314-wasm32-emscripten.so +0 -0
- python_calamine/_python_calamine.pyi +316 -0
- python_calamine/py.typed +0 -0
- python_calamine-0.8.2.dist-info/METADATA +94 -0
- python_calamine-0.8.2.dist-info/RECORD +9 -0
- python_calamine-0.8.2.dist-info/WHEEL +4 -0
- python_calamine-0.8.2.dist-info/licenses/LICENSE +21 -0
- python_calamine-0.8.2.dist-info/sboms/python-calamine.cyclonedx.json +1615 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
from ._python_calamine import (
|
|
2
|
+
CalamineError,
|
|
3
|
+
CalamineSheet,
|
|
4
|
+
CalamineTable,
|
|
5
|
+
CalamineWorkbook,
|
|
6
|
+
PasswordError,
|
|
7
|
+
SheetMetadata,
|
|
8
|
+
SheetTypeEnum,
|
|
9
|
+
SheetVisibleEnum,
|
|
10
|
+
TableNotFound,
|
|
11
|
+
TablesNotLoaded,
|
|
12
|
+
TablesNotSupported,
|
|
13
|
+
WorkbookClosed,
|
|
14
|
+
WorksheetNotFound,
|
|
15
|
+
XmlError,
|
|
16
|
+
ZipError,
|
|
17
|
+
load_workbook,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
__all__ = (
|
|
21
|
+
"CalamineError",
|
|
22
|
+
"CalamineSheet",
|
|
23
|
+
"CalamineTable",
|
|
24
|
+
"CalamineWorkbook",
|
|
25
|
+
"PasswordError",
|
|
26
|
+
"SheetMetadata",
|
|
27
|
+
"SheetTypeEnum",
|
|
28
|
+
"SheetVisibleEnum",
|
|
29
|
+
"TableNotFound",
|
|
30
|
+
"TablesNotLoaded",
|
|
31
|
+
"TablesNotSupported",
|
|
32
|
+
"WorkbookClosed",
|
|
33
|
+
"WorksheetNotFound",
|
|
34
|
+
"XmlError",
|
|
35
|
+
"ZipError",
|
|
36
|
+
"load_workbook",
|
|
37
|
+
)
|
|
Binary file
|
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
# Some documentations from upstream under MIT License. See authors in https://github.com/tafia/calamine
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import datetime
|
|
5
|
+
import enum
|
|
6
|
+
import os
|
|
7
|
+
import types
|
|
8
|
+
import typing
|
|
9
|
+
|
|
10
|
+
@typing.type_check_only
|
|
11
|
+
class ReadBuffer(typing.Protocol):
|
|
12
|
+
def seek(self, __offset: int, __whence: int = ...) -> int: ...
|
|
13
|
+
def read(self, __size: int = ...) -> bytes | None: ...
|
|
14
|
+
|
|
15
|
+
@typing.final
|
|
16
|
+
class SheetTypeEnum(enum.Enum):
|
|
17
|
+
WorkSheet = ...
|
|
18
|
+
DialogSheet = ...
|
|
19
|
+
MacroSheet = ...
|
|
20
|
+
ChartSheet = ...
|
|
21
|
+
Vba = ...
|
|
22
|
+
|
|
23
|
+
@typing.final
|
|
24
|
+
class SheetVisibleEnum(enum.Enum):
|
|
25
|
+
Visible = ...
|
|
26
|
+
"""Visible."""
|
|
27
|
+
Hidden = ...
|
|
28
|
+
"""Hidden."""
|
|
29
|
+
VeryHidden = ...
|
|
30
|
+
"""The sheet is hidden and cannot be displayed using the user interface. It is supported only by Excel formats."""
|
|
31
|
+
|
|
32
|
+
@typing.final
|
|
33
|
+
class SheetMetadata:
|
|
34
|
+
name: str
|
|
35
|
+
"""Name of sheet."""
|
|
36
|
+
typ: SheetTypeEnum
|
|
37
|
+
"""Type of sheet.
|
|
38
|
+
|
|
39
|
+
Only Excel formats support this. Default value for ODS is `WorkSheet`.
|
|
40
|
+
"""
|
|
41
|
+
visible: SheetVisibleEnum
|
|
42
|
+
"""Visible of sheet."""
|
|
43
|
+
|
|
44
|
+
def __new__(
|
|
45
|
+
cls, name: str, typ: SheetTypeEnum, visible: SheetVisibleEnum
|
|
46
|
+
) -> SheetMetadata: ...
|
|
47
|
+
|
|
48
|
+
@typing.final
|
|
49
|
+
class CalamineSheet:
|
|
50
|
+
name: str
|
|
51
|
+
@property
|
|
52
|
+
def height(self) -> int:
|
|
53
|
+
"""Get the row height of a sheet data.
|
|
54
|
+
|
|
55
|
+
The height is defined as the number of rows between the start and end positions.
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
@property
|
|
59
|
+
def width(self) -> int:
|
|
60
|
+
"""Get the column width of a sheet data.
|
|
61
|
+
|
|
62
|
+
The width is defined as the number of columns between the start and end positions.
|
|
63
|
+
"""
|
|
64
|
+
|
|
65
|
+
@property
|
|
66
|
+
def total_height(self) -> int: ...
|
|
67
|
+
@property
|
|
68
|
+
def total_width(self) -> int: ...
|
|
69
|
+
@property
|
|
70
|
+
def start(self) -> tuple[int, int] | None:
|
|
71
|
+
"""Get top left cell position of a sheet data."""
|
|
72
|
+
|
|
73
|
+
@property
|
|
74
|
+
def end(self) -> tuple[int, int] | None:
|
|
75
|
+
"""Get bottom right cell position of a sheet data."""
|
|
76
|
+
|
|
77
|
+
def to_python(
|
|
78
|
+
self, skip_empty_area: bool = True, nrows: int | None = None
|
|
79
|
+
) -> list[
|
|
80
|
+
list[
|
|
81
|
+
int
|
|
82
|
+
| float
|
|
83
|
+
| str
|
|
84
|
+
| bool
|
|
85
|
+
| datetime.time
|
|
86
|
+
| datetime.date
|
|
87
|
+
| datetime.datetime
|
|
88
|
+
| datetime.timedelta
|
|
89
|
+
]
|
|
90
|
+
]:
|
|
91
|
+
"""Returning data from sheet as list of lists.
|
|
92
|
+
|
|
93
|
+
Args:
|
|
94
|
+
skip_empty_area (bool):
|
|
95
|
+
By default, calamine skips empty rows/cols before data.
|
|
96
|
+
For suppress this behaviour, set `skip_empty_area` to `False`.
|
|
97
|
+
"""
|
|
98
|
+
|
|
99
|
+
def iter_rows(
|
|
100
|
+
self,
|
|
101
|
+
) -> typing.Iterator[
|
|
102
|
+
list[
|
|
103
|
+
int
|
|
104
|
+
| float
|
|
105
|
+
| str
|
|
106
|
+
| bool
|
|
107
|
+
| datetime.time
|
|
108
|
+
| datetime.date
|
|
109
|
+
| datetime.datetime
|
|
110
|
+
| datetime.timedelta
|
|
111
|
+
]
|
|
112
|
+
]:
|
|
113
|
+
"""Returning data from sheet as iterator of lists."""
|
|
114
|
+
|
|
115
|
+
@property
|
|
116
|
+
def merged_cell_ranges(
|
|
117
|
+
self,
|
|
118
|
+
) -> list[tuple[tuple[int, int], tuple[int, int]]] | None:
|
|
119
|
+
"""Return a copy of merged cell ranges.
|
|
120
|
+
|
|
121
|
+
Support only for xlsx/xls.
|
|
122
|
+
|
|
123
|
+
Returns:
|
|
124
|
+
list of merged cell ranges (tuple[start coordinate, end coordinate]) or None for unsupported format
|
|
125
|
+
"""
|
|
126
|
+
|
|
127
|
+
@typing.final
|
|
128
|
+
class CalamineTable:
|
|
129
|
+
name: str
|
|
130
|
+
"""Get the name of the table."""
|
|
131
|
+
sheet: str
|
|
132
|
+
"""Get the name of the parent worksheet for a table."""
|
|
133
|
+
columns: list[str]
|
|
134
|
+
"""Get the header names of the table columns.
|
|
135
|
+
|
|
136
|
+
In Excel table headers can be hidden but the table will still have
|
|
137
|
+
column header names.
|
|
138
|
+
"""
|
|
139
|
+
@property
|
|
140
|
+
def height(self) -> int:
|
|
141
|
+
"""Get the row height of a table data.
|
|
142
|
+
|
|
143
|
+
The height is defined as the number of rows between the start and end positions.
|
|
144
|
+
"""
|
|
145
|
+
|
|
146
|
+
@property
|
|
147
|
+
def width(self) -> int:
|
|
148
|
+
"""Get the column width of a table data.
|
|
149
|
+
|
|
150
|
+
The width is defined as the number of columns between the start and end positions.
|
|
151
|
+
"""
|
|
152
|
+
|
|
153
|
+
@property
|
|
154
|
+
def start(self) -> tuple[int, int] | None:
|
|
155
|
+
"""Get top left cell position of a table data."""
|
|
156
|
+
|
|
157
|
+
@property
|
|
158
|
+
def end(self) -> tuple[int, int] | None:
|
|
159
|
+
"""Get bottom right cell position of a table data."""
|
|
160
|
+
|
|
161
|
+
def to_python(
|
|
162
|
+
self,
|
|
163
|
+
) -> list[
|
|
164
|
+
list[
|
|
165
|
+
int
|
|
166
|
+
| float
|
|
167
|
+
| str
|
|
168
|
+
| bool
|
|
169
|
+
| datetime.time
|
|
170
|
+
| datetime.date
|
|
171
|
+
| datetime.datetime
|
|
172
|
+
| datetime.timedelta
|
|
173
|
+
]
|
|
174
|
+
]:
|
|
175
|
+
"""Returning data from table as list of lists."""
|
|
176
|
+
|
|
177
|
+
@typing.final
|
|
178
|
+
class CalamineWorkbook:
|
|
179
|
+
path: str | None
|
|
180
|
+
"""Path to file. `None` if bytes was loaded."""
|
|
181
|
+
sheet_names: list[str]
|
|
182
|
+
"""All sheet names of this workbook, in workbook order."""
|
|
183
|
+
sheets_metadata: list[SheetMetadata]
|
|
184
|
+
"""All sheets metadata of this workbook, in workbook order."""
|
|
185
|
+
table_names: list[str] | None
|
|
186
|
+
"""All table names of this workbook."""
|
|
187
|
+
@classmethod
|
|
188
|
+
def from_object(
|
|
189
|
+
cls, path_or_filelike: str | os.PathLike | ReadBuffer, load_tables: bool = False
|
|
190
|
+
) -> "CalamineWorkbook":
|
|
191
|
+
"""Determining type of pyobject and reading from it.
|
|
192
|
+
|
|
193
|
+
Args:
|
|
194
|
+
path_or_filelike (str | os.PathLike | ReadBuffer): path to file or IO (must implement read/seek methods).
|
|
195
|
+
load_tables (bool): load Excel tables (supported for XLSX only).
|
|
196
|
+
"""
|
|
197
|
+
|
|
198
|
+
@classmethod
|
|
199
|
+
def from_path(
|
|
200
|
+
cls, path: str | os.PathLike, load_tables: bool = False
|
|
201
|
+
) -> "CalamineWorkbook":
|
|
202
|
+
"""Reading file from path.
|
|
203
|
+
|
|
204
|
+
Args:
|
|
205
|
+
path (str | os.PathLike): path to file.
|
|
206
|
+
load_tables (bool): load Excel tables (supported for XLSX only).
|
|
207
|
+
"""
|
|
208
|
+
|
|
209
|
+
@classmethod
|
|
210
|
+
def from_filelike(
|
|
211
|
+
cls, filelike: ReadBuffer, load_tables: bool = False
|
|
212
|
+
) -> "CalamineWorkbook":
|
|
213
|
+
"""Reading file from IO.
|
|
214
|
+
|
|
215
|
+
Args:
|
|
216
|
+
filelike : IO (must implement read/seek methods).
|
|
217
|
+
load_tables (bool): load Excel tables (supported for XLSX only).
|
|
218
|
+
"""
|
|
219
|
+
|
|
220
|
+
def close(self) -> None:
|
|
221
|
+
"""Close the workbook.
|
|
222
|
+
|
|
223
|
+
Drop internal rust structure from workbook (and close the file under the hood).
|
|
224
|
+
`get_sheet_by_name`/`get_sheet_by_index` will raise WorkbookClosed after calling that method.
|
|
225
|
+
|
|
226
|
+
Raises:
|
|
227
|
+
WorkbookClosed: If workbook already closed.
|
|
228
|
+
"""
|
|
229
|
+
|
|
230
|
+
def __enter__(self) -> "CalamineWorkbook": ...
|
|
231
|
+
def __exit__(
|
|
232
|
+
self,
|
|
233
|
+
exc_type: type[BaseException] | None,
|
|
234
|
+
exc_val: BaseException | None,
|
|
235
|
+
exc_tb: types.TracebackType | None,
|
|
236
|
+
) -> None: ...
|
|
237
|
+
def get_sheet_by_name(self, name: str) -> CalamineSheet:
|
|
238
|
+
"""Get worksheet by name.
|
|
239
|
+
|
|
240
|
+
Args:
|
|
241
|
+
name(str): name of worksheet
|
|
242
|
+
|
|
243
|
+
Returns:
|
|
244
|
+
CalamineSheet
|
|
245
|
+
|
|
246
|
+
Raises:
|
|
247
|
+
WorkbookClosed: If workbook already closed.
|
|
248
|
+
WorksheetNotFound: If worksheet not found in workbook.
|
|
249
|
+
"""
|
|
250
|
+
|
|
251
|
+
def get_sheet_by_index(self, index: int) -> CalamineSheet:
|
|
252
|
+
"""Get worksheet by index.
|
|
253
|
+
|
|
254
|
+
Args:
|
|
255
|
+
index(int): index of worksheet
|
|
256
|
+
|
|
257
|
+
Returns:
|
|
258
|
+
CalamineSheet
|
|
259
|
+
|
|
260
|
+
Raises:
|
|
261
|
+
WorkbookClosed: If workbook already closed.
|
|
262
|
+
WorksheetNotFound: If worksheet not found in workbook.
|
|
263
|
+
"""
|
|
264
|
+
|
|
265
|
+
def get_table_by_name(self, name: str) -> CalamineTable:
|
|
266
|
+
"""Get table by name.
|
|
267
|
+
|
|
268
|
+
Args:
|
|
269
|
+
name(str): name of table
|
|
270
|
+
|
|
271
|
+
Returns:
|
|
272
|
+
CalamineTable
|
|
273
|
+
|
|
274
|
+
Raises:
|
|
275
|
+
WorkbookClosed: If workbook already closed.
|
|
276
|
+
TableNotFound: If table not found in workbook.
|
|
277
|
+
"""
|
|
278
|
+
|
|
279
|
+
class CalamineError(Exception): ...
|
|
280
|
+
class PasswordError(CalamineError): ...
|
|
281
|
+
class WorksheetNotFound(CalamineError): ...
|
|
282
|
+
class XmlError(CalamineError): ...
|
|
283
|
+
class ZipError(CalamineError): ...
|
|
284
|
+
class WorkbookClosed(CalamineError): ...
|
|
285
|
+
class TablesNotLoaded(CalamineError): ...
|
|
286
|
+
class TablesNotSupported(CalamineError): ...
|
|
287
|
+
class TableNotFound(CalamineError): ...
|
|
288
|
+
|
|
289
|
+
def load_workbook(
|
|
290
|
+
path_or_filelike: str | os.PathLike | ReadBuffer, load_tables: bool = False
|
|
291
|
+
) -> CalamineWorkbook:
|
|
292
|
+
"""Determining type of pyobject and reading from it.
|
|
293
|
+
|
|
294
|
+
Args:
|
|
295
|
+
path_or_filelike (str | os.PathLike | ReadBuffer): path to file or IO (must implement read/seek methods).
|
|
296
|
+
load_tables (bool): load Excel tables (supported for XLSX only).
|
|
297
|
+
"""
|
|
298
|
+
|
|
299
|
+
__all__ = [
|
|
300
|
+
"CalamineError",
|
|
301
|
+
"CalamineSheet",
|
|
302
|
+
"CalamineTable",
|
|
303
|
+
"CalamineWorkbook",
|
|
304
|
+
"PasswordError",
|
|
305
|
+
"SheetMetadata",
|
|
306
|
+
"SheetTypeEnum",
|
|
307
|
+
"SheetVisibleEnum",
|
|
308
|
+
"TableNotFound",
|
|
309
|
+
"TablesNotLoaded",
|
|
310
|
+
"TablesNotSupported",
|
|
311
|
+
"WorkbookClosed",
|
|
312
|
+
"WorksheetNotFound",
|
|
313
|
+
"XmlError",
|
|
314
|
+
"ZipError",
|
|
315
|
+
"load_workbook",
|
|
316
|
+
]
|
python_calamine/py.typed
ADDED
|
File without changes
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: python-calamine
|
|
3
|
+
Version: 0.8.2
|
|
4
|
+
Classifier: Development Status :: 4 - Beta
|
|
5
|
+
Classifier: Programming Language :: Rust
|
|
6
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
7
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
8
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Summary: Python binding for Rust's library for reading excel and odf file - calamine
|
|
13
|
+
Author-email: Dmitriy <dimastbk@proton.me>
|
|
14
|
+
License-Expression: MIT
|
|
15
|
+
Requires-Python: >=3.10
|
|
16
|
+
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
|
|
17
|
+
Project-URL: homepage, https://github.com/dimastbk/python-calamine
|
|
18
|
+
Project-URL: source, https://github.com/dimastbk/python-calamine
|
|
19
|
+
|
|
20
|
+
# python-calamine
|
|
21
|
+
[](https://pypi.org/project/python-calamine/)
|
|
22
|
+
[](https://anaconda.org/conda-forge/python-calamine)
|
|
23
|
+

|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
Python binding for beautiful Rust's library for reading excel and odf file - [calamine](https://github.com/tafia/calamine).
|
|
27
|
+
|
|
28
|
+
### Is used
|
|
29
|
+
* [calamine](https://github.com/tafia/calamine)
|
|
30
|
+
* [pyo3](https://github.com/PyO3/pyo3)
|
|
31
|
+
* [maturin](https://github.com/PyO3/maturin)
|
|
32
|
+
|
|
33
|
+
### Installation
|
|
34
|
+
Pypi:
|
|
35
|
+
```
|
|
36
|
+
pip install python-calamine
|
|
37
|
+
```
|
|
38
|
+
Conda:
|
|
39
|
+
```
|
|
40
|
+
conda install -c conda-forge python-calamine
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Example
|
|
44
|
+
```python
|
|
45
|
+
from python_calamine import CalamineWorkbook
|
|
46
|
+
|
|
47
|
+
workbook = CalamineWorkbook.from_path("file.xlsx")
|
|
48
|
+
workbook.sheet_names
|
|
49
|
+
# ["Sheet1", "Sheet2"]
|
|
50
|
+
|
|
51
|
+
workbook.get_sheet_by_name("Sheet1").to_python()
|
|
52
|
+
# [
|
|
53
|
+
# ["1", "2", "3", "4", "5", "6", "7"],
|
|
54
|
+
# ["1", "2", "3", "4", "5", "6", "7"],
|
|
55
|
+
# ["1", "2", "3", "4", "5", "6", "7"],
|
|
56
|
+
# ]
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
By default, calamine skips empty rows/cols before data. For suppress this behaviour, set `skip_empty_area` to `False`.
|
|
60
|
+
```python
|
|
61
|
+
from python_calamine import CalamineWorkbook
|
|
62
|
+
|
|
63
|
+
workbook = CalamineWorkbook.from_path("file.xlsx").get_sheet_by_name("Sheet1").to_python(skip_empty_area=False)
|
|
64
|
+
# [
|
|
65
|
+
# [", ", ", ", ", ", "],
|
|
66
|
+
# ["1", "2", "3", "4", "5", "6", "7"],
|
|
67
|
+
# ["1", "2", "3", "4", "5", "6", "7"],
|
|
68
|
+
# ["1", "2", "3", "4", "5", "6", "7"],
|
|
69
|
+
# ]
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Pandas 2.2 and above have built-in support of python-calamine.
|
|
73
|
+
|
|
74
|
+
Also, you can find additional examples in [tests](https://github.com/dimastbk/python-calamine/blob/master/tests/test_base.py).
|
|
75
|
+
|
|
76
|
+
### Development
|
|
77
|
+
|
|
78
|
+
You'll need rust [installed](https://rustup.rs/).
|
|
79
|
+
|
|
80
|
+
```shell
|
|
81
|
+
# clone this repo or your fork
|
|
82
|
+
git clone git@github.com:dimastbk/python-calamine.git
|
|
83
|
+
cd python-calamine
|
|
84
|
+
# create a new virtual env
|
|
85
|
+
python3 -m venv env
|
|
86
|
+
source env/bin/activate
|
|
87
|
+
# install dev dependencies and install python-calamine
|
|
88
|
+
pip install --group dev -e . # required pip 25.1 and above
|
|
89
|
+
# lint code
|
|
90
|
+
pre-commit run --all-files
|
|
91
|
+
# test code
|
|
92
|
+
pytest
|
|
93
|
+
```
|
|
94
|
+
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
python_calamine/__init__.py,sha256=u_sVBmGMWv0DVSE_RrGrIUe0tCYKlb4IxS9G5bvNFoo,705
|
|
2
|
+
python_calamine/_python_calamine.cpython-314-wasm32-emscripten.so,sha256=DPYg6eif_KYiOLkeNV0yzyIEyQ4ThtnNZMEYDeT2d1M,1208972
|
|
3
|
+
python_calamine/_python_calamine.pyi,sha256=6mXUIWf-DEP4MuhHtjBsPyzqiwp5NaaBOjaqTcI2l7g,8737
|
|
4
|
+
python_calamine/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
|
+
python_calamine-0.8.2.dist-info/METADATA,sha256=3Jf7vXAo8yXPOCWS3cJoEAUaKdL_i6bcALZM17qzSs4,3097
|
|
6
|
+
python_calamine-0.8.2.dist-info/WHEEL,sha256=GQD9tGGc3KqnnBNGVglyttmwhVEMgEcjJQVH4Tkcdks,114
|
|
7
|
+
python_calamine-0.8.2.dist-info/licenses/LICENSE,sha256=bO1GQBYjM6fIgNRdNGrohAl0Zwn6_s5hMDdovIfYC_A,1065
|
|
8
|
+
python_calamine-0.8.2.dist-info/sboms/python-calamine.cyclonedx.json,sha256=R9Gm5X5RkgpBoLYJth8ZE9-oqe3g27mLKdupmAu5sLI,49748
|
|
9
|
+
python_calamine-0.8.2.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2021 dimastbk
|
|
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.
|