fdnkit 1.0.0__py3-none-any.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.
- fdnkit/__init__.py +94 -0
- fdnkit/classify.py +310 -0
- fdnkit/cli.py +175 -0
- fdnkit/dfa.py +88 -0
- fdnkit/features.py +212 -0
- fdnkit/fodn.py +346 -0
- fdnkit/io.py +163 -0
- fdnkit/mfdfa.py +233 -0
- fdnkit/preprocessing.py +125 -0
- fdnkit/synthetic.py +173 -0
- fdnkit/viz.py +146 -0
- fdnkit-1.0.0.dist-info/METADATA +192 -0
- fdnkit-1.0.0.dist-info/RECORD +16 -0
- fdnkit-1.0.0.dist-info/WHEEL +4 -0
- fdnkit-1.0.0.dist-info/entry_points.txt +2 -0
- fdnkit-1.0.0.dist-info/licenses/LICENSE +21 -0
fdnkit/viz.py
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
"""Plotting utilities (matplotlib, optional dependency).
|
|
2
|
+
|
|
3
|
+
Import matplotlib lazily so the core library has no hard plotting dependency.
|
|
4
|
+
Install with ``pip install fdnkit[viz]``. Every function accepts an optional
|
|
5
|
+
``ax`` and returns the Axes it drew on, so plots compose into larger figures.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import numpy as np
|
|
11
|
+
|
|
12
|
+
__all__ = [
|
|
13
|
+
"plot_fluctuation",
|
|
14
|
+
"plot_hq",
|
|
15
|
+
"plot_multifractal_spectrum",
|
|
16
|
+
"plot_hurst_over_time",
|
|
17
|
+
"plot_alpha_distribution",
|
|
18
|
+
"plot_coupling_matrix",
|
|
19
|
+
"plot_eigenvector_hubs",
|
|
20
|
+
]
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _get_ax(ax):
|
|
24
|
+
try:
|
|
25
|
+
import matplotlib.pyplot as plt
|
|
26
|
+
except ImportError as exc: # pragma: no cover
|
|
27
|
+
raise ImportError(
|
|
28
|
+
"Plotting requires matplotlib. Install with `pip install fdnkit[viz]`."
|
|
29
|
+
) from exc
|
|
30
|
+
if ax is None:
|
|
31
|
+
_, ax = plt.subplots(figsize=(6, 4))
|
|
32
|
+
return ax
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def plot_fluctuation(result, ax=None, **kwargs):
|
|
36
|
+
"""Log-log fluctuation function ``F`` vs scale, with the fitted Hurst slope.
|
|
37
|
+
|
|
38
|
+
Parameters
|
|
39
|
+
----------
|
|
40
|
+
result : DFAResult | MFDFAResult
|
|
41
|
+
Must expose ``scales``, ``fluct``, and ``hurst``.
|
|
42
|
+
"""
|
|
43
|
+
ax = _get_ax(ax)
|
|
44
|
+
scales = np.asarray(result.scales, dtype=float)
|
|
45
|
+
fluct = np.asarray(result.fluct, dtype=float)
|
|
46
|
+
good = np.isfinite(fluct) & (fluct > 0)
|
|
47
|
+
ax.plot(np.log2(scales[good]), np.log2(fluct[good]), "o-", **kwargs)
|
|
48
|
+
ax.set_xlabel("log2(scale)")
|
|
49
|
+
ax.set_ylabel("log2(F)")
|
|
50
|
+
ax.set_title(f"DFA fluctuation (H = {result.hurst:.3f})")
|
|
51
|
+
return ax
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def plot_hq(result, ax=None, **kwargs):
|
|
55
|
+
"""Generalized Hurst exponent ``h(q)`` against ``q``."""
|
|
56
|
+
ax = _get_ax(ax)
|
|
57
|
+
order = np.argsort(result.q)
|
|
58
|
+
ax.plot(np.asarray(result.q)[order], np.asarray(result.hq)[order], "s-", **kwargs)
|
|
59
|
+
ax.set_xlabel("q")
|
|
60
|
+
ax.set_ylabel("h(q)")
|
|
61
|
+
ax.set_title(f"Generalized Hurst (delta_h = {result.delta_h:.3f})")
|
|
62
|
+
return ax
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def plot_multifractal_spectrum(result, ax=None, **kwargs):
|
|
66
|
+
"""Singularity spectrum ``f(alpha)`` from an :class:`~fdnkit.mfdfa.MFDFAResult`."""
|
|
67
|
+
from .mfdfa import multifractal_spectrum
|
|
68
|
+
|
|
69
|
+
ax = _get_ax(ax)
|
|
70
|
+
alpha, f_alpha = multifractal_spectrum(result)
|
|
71
|
+
ax.plot(alpha, f_alpha, "o-", **kwargs)
|
|
72
|
+
ax.set_xlabel(r"$\alpha$ (Holder exponent)")
|
|
73
|
+
ax.set_ylabel(r"$f(\alpha)$")
|
|
74
|
+
ax.set_title("Multifractal spectrum")
|
|
75
|
+
return ax
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def plot_hurst_over_time(times, hurst_values, ax=None, *, label=None, **kwargs):
|
|
79
|
+
"""Trace of a scaling exponent (Hurst / alpha) across analysis windows.
|
|
80
|
+
|
|
81
|
+
Parameters
|
|
82
|
+
----------
|
|
83
|
+
times : array-like
|
|
84
|
+
Window centre times (or indices).
|
|
85
|
+
hurst_values : array-like
|
|
86
|
+
One value per window.
|
|
87
|
+
"""
|
|
88
|
+
ax = _get_ax(ax)
|
|
89
|
+
ax.plot(np.asarray(times), np.asarray(hurst_values), "-o", label=label, **kwargs)
|
|
90
|
+
ax.set_xlabel("time (s)")
|
|
91
|
+
ax.set_ylabel("Hurst / exponent")
|
|
92
|
+
ax.set_title("Scaling exponent over time")
|
|
93
|
+
if label:
|
|
94
|
+
ax.legend()
|
|
95
|
+
return ax
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def plot_alpha_distribution(alphas, ax=None, *, bins=20, **kwargs):
|
|
99
|
+
"""Histogram of per-channel (or per-chunk) fractional orders ``alpha``."""
|
|
100
|
+
ax = _get_ax(ax)
|
|
101
|
+
a = np.asarray(alphas, dtype=float).ravel()
|
|
102
|
+
a = a[np.isfinite(a)]
|
|
103
|
+
ax.hist(a, bins=bins, **kwargs)
|
|
104
|
+
ax.set_xlabel(r"fractional order $\alpha$")
|
|
105
|
+
ax.set_ylabel("count")
|
|
106
|
+
ax.set_title("FODN alpha distribution")
|
|
107
|
+
return ax
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def plot_coupling_matrix(coupling, channel_names=None, ax=None, *, cmap="RdBu_r", **kwargs):
|
|
111
|
+
"""Heatmap of a FODN coupling matrix ``A``.
|
|
112
|
+
|
|
113
|
+
Parameters
|
|
114
|
+
----------
|
|
115
|
+
coupling : array-like, shape (n, n)
|
|
116
|
+
channel_names : sequence of str, optional
|
|
117
|
+
"""
|
|
118
|
+
ax = _get_ax(ax)
|
|
119
|
+
a = np.asarray(coupling, dtype=float)
|
|
120
|
+
vmax = np.max(np.abs(a)) or 1.0
|
|
121
|
+
im = ax.imshow(a, cmap=cmap, vmin=-vmax, vmax=vmax, **kwargs)
|
|
122
|
+
ax.figure.colorbar(im, ax=ax, fraction=0.046, pad=0.04, label="coupling")
|
|
123
|
+
ax.set_title("FODN coupling matrix A")
|
|
124
|
+
ax.set_xlabel("source channel")
|
|
125
|
+
ax.set_ylabel("target channel")
|
|
126
|
+
if channel_names is not None:
|
|
127
|
+
ax.set_xticks(range(len(channel_names)))
|
|
128
|
+
ax.set_yticks(range(len(channel_names)))
|
|
129
|
+
ax.set_xticklabels(channel_names, rotation=90, fontsize=7)
|
|
130
|
+
ax.set_yticklabels(channel_names, fontsize=7)
|
|
131
|
+
return ax
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def plot_eigenvector_hubs(dominant_eigvec, channel_names=None, ax=None, **kwargs):
|
|
135
|
+
"""Bar chart of per-channel hub scores (dominant-eigenvector magnitude)."""
|
|
136
|
+
ax = _get_ax(ax)
|
|
137
|
+
v = np.asarray(dominant_eigvec, dtype=float).ravel()
|
|
138
|
+
idx = np.arange(v.size)
|
|
139
|
+
ax.bar(idx, v, **kwargs)
|
|
140
|
+
ax.set_xlabel("channel")
|
|
141
|
+
ax.set_ylabel("hub score |eigvec|")
|
|
142
|
+
ax.set_title("FODN eigenvector hubs")
|
|
143
|
+
if channel_names is not None:
|
|
144
|
+
ax.set_xticks(idx)
|
|
145
|
+
ax.set_xticklabels(channel_names, rotation=90, fontsize=7)
|
|
146
|
+
return ax
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: fdnkit
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Fractional Dynamical Network & Multifractal toolkit for intracranial EEG
|
|
5
|
+
Project-URL: Homepage, https://github.com/SamirHossain099/fdnkit
|
|
6
|
+
Project-URL: Documentation, https://github.com/SamirHossain099/fdnkit#readme
|
|
7
|
+
Project-URL: Repository, https://github.com/SamirHossain099/fdnkit
|
|
8
|
+
Project-URL: Issues, https://github.com/SamirHossain099/fdnkit/issues
|
|
9
|
+
Author: Samir Hossain
|
|
10
|
+
License: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: DFA,EEG,MFDFA,fractional dynamics,iEEG,multifractal,network physiology,neuroscience
|
|
13
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
14
|
+
Classifier: Intended Audience :: Science/Research
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Operating System :: OS Independent
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Classifier: Topic :: Scientific/Engineering :: Medical Science Apps.
|
|
23
|
+
Requires-Python: >=3.9
|
|
24
|
+
Requires-Dist: numpy>=1.22
|
|
25
|
+
Requires-Dist: pandas>=1.4
|
|
26
|
+
Requires-Dist: scikit-learn>=1.1
|
|
27
|
+
Requires-Dist: scipy>=1.8
|
|
28
|
+
Provides-Extra: all
|
|
29
|
+
Requires-Dist: h5py>=3.0; extra == 'all'
|
|
30
|
+
Requires-Dist: matplotlib>=3.5; extra == 'all'
|
|
31
|
+
Requires-Dist: mne>=1.0; extra == 'all'
|
|
32
|
+
Provides-Extra: dev
|
|
33
|
+
Requires-Dist: h5py>=3.0; extra == 'dev'
|
|
34
|
+
Requires-Dist: matplotlib>=3.5; extra == 'dev'
|
|
35
|
+
Requires-Dist: pytest-cov>=4.0; extra == 'dev'
|
|
36
|
+
Requires-Dist: pytest>=7.0; extra == 'dev'
|
|
37
|
+
Requires-Dist: ruff>=0.1; extra == 'dev'
|
|
38
|
+
Provides-Extra: io
|
|
39
|
+
Requires-Dist: h5py>=3.0; extra == 'io'
|
|
40
|
+
Requires-Dist: mne>=1.0; extra == 'io'
|
|
41
|
+
Provides-Extra: viz
|
|
42
|
+
Requires-Dist: matplotlib>=3.5; extra == 'viz'
|
|
43
|
+
Description-Content-Type: text/markdown
|
|
44
|
+
|
|
45
|
+
# FDNkit
|
|
46
|
+
|
|
47
|
+
**Fractional Dynamical Network & Multifractal toolkit for intracranial EEG**
|
|
48
|
+
|
|
49
|
+
[](https://github.com/SamirHossain099/fdnkit/actions/workflows/ci.yml)
|
|
50
|
+
[](https://github.com/SamirHossain099/fdnkit/blob/main/LICENSE)
|
|
51
|
+
[](https://www.python.org/)
|
|
52
|
+
[](https://doi.org/10.5281/zenodo.22366240)
|
|
53
|
+
|
|
54
|
+
FDNkit turns intracranial-EEG (iEEG) recordings into **fractal** and
|
|
55
|
+
**fractional-dynamical-network** features and evaluates them **honestly**. It
|
|
56
|
+
packages methods validated in Beeram et al. (2026, *Front. Netw. Physiol.*
|
|
57
|
+
6:1768476) and the fractional-dynamical-network line of work of Gupta et al.
|
|
58
|
+
(2018) and Xue & Bogdan (2017) as a clean, documented, tested library, not a one-off GUI welded to a single dataset.
|
|
59
|
+
|
|
60
|
+
It computes:
|
|
61
|
+
|
|
62
|
+
- **DFA**: monofractal Hurst exponent `H`.
|
|
63
|
+
- **MFDFA**: generalized Hurst `h(q)`, multifractal width `Δh`, and the
|
|
64
|
+
singularity spectrum `f(α)`.
|
|
65
|
+
- **FODN**: a fractional-order dynamical network: per-channel fractional orders
|
|
66
|
+
`α`, a sparse directed coupling matrix `A`, and eigenvector "hub" scores.
|
|
67
|
+
- **Feature tables**: tidy, one-row-per-trial pandas DataFrames.
|
|
68
|
+
- **Honest classification**: a logistic-regression harness that defaults to
|
|
69
|
+
**leave-one-subject-out** cross-validation with a subject-level permutation
|
|
70
|
+
test, because row-wise splits leak patient identity and inflate accuracy.
|
|
71
|
+
|
|
72
|
+
## Install
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
pip install fdnkit # core: numpy, scipy, pandas, scikit-learn
|
|
76
|
+
pip install "fdnkit[viz]" # + matplotlib for plots
|
|
77
|
+
pip install "fdnkit[io]" # + mne (EDF) and h5py (HDF5) readers
|
|
78
|
+
pip install "fdnkit[all]" # everything
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
From source:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
git clone https://github.com/SamirHossain099/fdnkit
|
|
85
|
+
cd fdnkit
|
|
86
|
+
pip install -e ".[dev]"
|
|
87
|
+
pytest
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## 60-second example (no data download)
|
|
91
|
+
|
|
92
|
+
```python
|
|
93
|
+
from fdnkit.synthetic import synthetic_ieeg
|
|
94
|
+
from fdnkit.features import extract_features
|
|
95
|
+
|
|
96
|
+
# A small, sparsely-coupled synthetic iEEG trial (8 channels, 5 s @ 1 kHz).
|
|
97
|
+
signals, channel_names = synthetic_ieeg(n_channels=8, n_samples=5000, seed=0)
|
|
98
|
+
|
|
99
|
+
# One tidy feature row: DFA H, MFDFA h(q)/Δh, FODN α / leading eigenvalue / hubs.
|
|
100
|
+
features = extract_features(signals)
|
|
101
|
+
print(features["MF_DFA_H"], features["MeanAlpha"], features["LeadingEig"])
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Analyze a single signal directly:
|
|
105
|
+
|
|
106
|
+
```python
|
|
107
|
+
import numpy as np
|
|
108
|
+
from fdnkit.dfa import dfa
|
|
109
|
+
from fdnkit.mfdfa import mfdfa
|
|
110
|
+
from fdnkit.fodn import fit_fodn
|
|
111
|
+
|
|
112
|
+
x = signals[0]
|
|
113
|
+
print("Hurst:", dfa(x).hurst)
|
|
114
|
+
print("multifractal width Δh:", mfdfa(x).delta_h)
|
|
115
|
+
|
|
116
|
+
fodn = fit_fodn(signals) # (channels, timepoints)
|
|
117
|
+
print("leading eigenvalue:", fodn.leading_eig)
|
|
118
|
+
print("hub scores:", np.round(fodn.dominant_eigvec, 3))
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## Honest classification
|
|
122
|
+
|
|
123
|
+
```python
|
|
124
|
+
from fdnkit.classify import classify_dataframe
|
|
125
|
+
|
|
126
|
+
# df has feature columns plus 'label' and 'group' (e.g. subject id) columns.
|
|
127
|
+
result = classify_dataframe(df, label_col="label", group_col="group", cv="loso")
|
|
128
|
+
print(result.summary())
|
|
129
|
+
# Leave-one-subject-out balanced accuracy, ROC-AUC, a subject-level
|
|
130
|
+
# permutation p-value, and a bootstrap 95% CI.
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
`cv="loso"` (the default) holds out whole subjects and **requires** `groups`.
|
|
134
|
+
Trial-wise `cv="loo"` is available but must be requested explicitly and is
|
|
135
|
+
labeled *optimistic*: it is the leakage-prone scheme FDNkit exists to warn about.
|
|
136
|
+
|
|
137
|
+
## Command line
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
# Self-contained demo: synthesize a labeled cohort and classify it honestly.
|
|
141
|
+
fdnkit demo --out demo_features.csv
|
|
142
|
+
fdnkit classify demo_features.csv --label label --group group
|
|
143
|
+
|
|
144
|
+
# Extract features from your own recording (EDF via MNE, or HDF5).
|
|
145
|
+
fdnkit extract recording.edf --window 1.0 --drop-bad --zscore --out features.csv
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## Design principles
|
|
149
|
+
|
|
150
|
+
- **Array-first core.** `dfa(signal)`, `mfdfa(signal)`, `fit_fodn(signals)` are
|
|
151
|
+
pure functions on NumPy arrays. Pandas/IO/plotting layer on top.
|
|
152
|
+
- **Depend, don't duplicate.** IO, montages, and filtering defer to
|
|
153
|
+
[MNE-Python](https://mne.tools); FDNkit adds only the fractal/FODN methods.
|
|
154
|
+
- **Deterministic and seedable.** Bad channels log a warning instead of crashing.
|
|
155
|
+
- **Honest by default.** Subject-wise CV and permutation testing are the
|
|
156
|
+
headline, not an afterthought.
|
|
157
|
+
|
|
158
|
+
## Validation
|
|
159
|
+
|
|
160
|
+
FDNkit's numerical core is checked against ground truth (see `tests/`):
|
|
161
|
+
|
|
162
|
+
- DFA recovers the Hurst exponent of fractional Gaussian noise across
|
|
163
|
+
`H = 0.3…0.9`; white noise → `H ≈ 0.5`, Brownian motion → `H ≈ 1.5`.
|
|
164
|
+
- MFDFA reports a wide `h(q)` for a multiplicative binomial cascade and a narrow
|
|
165
|
+
one for a monofractal signal; `h(q=2)` matches the DFA Hurst exponent exactly.
|
|
166
|
+
- FODN recovers finite fractional orders, coupling, and hubs on synthetic
|
|
167
|
+
coupled systems.
|
|
168
|
+
|
|
169
|
+
## Citation
|
|
170
|
+
|
|
171
|
+
If you use FDNkit, please cite the software:
|
|
172
|
+
|
|
173
|
+
> Hossain, S. (2026). *FDNkit: Fractional Dynamical Network & Multifractal
|
|
174
|
+
> toolkit for intracranial EEG* (v1.0.0). Zenodo.
|
|
175
|
+
> https://doi.org/10.5281/zenodo.22366240
|
|
176
|
+
|
|
177
|
+
(`10.5281/zenodo.22366240` always resolves to the latest release; cite
|
|
178
|
+
`10.5281/zenodo.22366241` for v1.0.0 specifically. See
|
|
179
|
+
[`CITATION.cff`](https://github.com/SamirHossain099/fdnkit/blob/main/CITATION.cff).)
|
|
180
|
+
|
|
181
|
+
Please also cite the methods paper:
|
|
182
|
+
|
|
183
|
+
> Beeram, S. P., Farris, M., Hossain, S., Rethans, N., Kang, J. Y., & Pereira,
|
|
184
|
+
> E. A. (2026). *Quantifying cognitive effort's impact on suppression of
|
|
185
|
+
> epilepsy-associated after discharges.* Frontiers in Network Physiology, 6,
|
|
186
|
+
> 1768476. https://doi.org/10.3389/fnetp.2026.1768476
|
|
187
|
+
|
|
188
|
+
## License
|
|
189
|
+
|
|
190
|
+
MIT; see [LICENSE](https://github.com/SamirHossain099/fdnkit/blob/main/LICENSE). The underlying fractional-dynamical-network method
|
|
191
|
+
is due to Gupta, Pequito & Bogdan (2018) and Xue & Bogdan (2017); please cite
|
|
192
|
+
them when using the FODN module.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
fdnkit/__init__.py,sha256=oOb6f0ykH8WpQvnck1C_24qsSupOP2dbfl4oEzj2lXg,2772
|
|
2
|
+
fdnkit/classify.py,sha256=-pahHHUCcEuuNidhCRdxfgNKvl9RlTOZb2LPqMQdsqk,11301
|
|
3
|
+
fdnkit/cli.py,sha256=bZ17hSDUsRy7JtgFAN-X7DzMegpgKd9Uaf1hBEbIL_c,6388
|
|
4
|
+
fdnkit/dfa.py,sha256=4N9cO-GTrbKKmgf00Cc6KQCc6cMLfQmNWVIJ0sTwwz4,2764
|
|
5
|
+
fdnkit/features.py,sha256=nWSey1kD0yXzFFC0NVf_JO1A8sYlkk53K_3ExQhhEoI,7545
|
|
6
|
+
fdnkit/fodn.py,sha256=6-AQdkhmtEOdb_2iW29Y4_Pqy0QiXohCM0dIJfgHQqg,12715
|
|
7
|
+
fdnkit/io.py,sha256=7kHIk1kdLWCdqa8iFfh6CialQR4Ot-NDrSqw4u_OHN4,5273
|
|
8
|
+
fdnkit/mfdfa.py,sha256=tX5aT6LwKEYmCwtf3BiFptClFjaX8SY8TdOjwb5FMtM,8533
|
|
9
|
+
fdnkit/preprocessing.py,sha256=vboQ7A3tx-aCk6PrvjopzkOLKmGrjhHMk06HoVCtozg,4315
|
|
10
|
+
fdnkit/synthetic.py,sha256=t0G0UE3HaaIzV1sPqhpwCnuGH4GkJCae9UHX_gQz0CA,6174
|
|
11
|
+
fdnkit/viz.py,sha256=5ffZS07GGeylbGYXsIi4GHuXj5Ga64Hqp7DKaTzhwRU,4807
|
|
12
|
+
fdnkit-1.0.0.dist-info/METADATA,sha256=jOKLOTnIymFpcMnvKuG0LFfwRgGXBaKQ-X62pmfUrx8,7739
|
|
13
|
+
fdnkit-1.0.0.dist-info/WHEEL,sha256=zOwg4jB6zX2kU910N-cMawjivD6tO8NEWvE12je1bVk,87
|
|
14
|
+
fdnkit-1.0.0.dist-info/entry_points.txt,sha256=f87Fzkl7fFwzmB4gghGg9xXyESTt5Jtuic2RbiaoKms,43
|
|
15
|
+
fdnkit-1.0.0.dist-info/licenses/LICENSE,sha256=svWXpNvhapALKx_4mnGhEP7AIDhIgWP1egNv0U6SUtc,1070
|
|
16
|
+
fdnkit-1.0.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Samir Hossain
|
|
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.
|