addernet 1.2.0__tar.gz → 1.2.2__tar.gz
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.
- {addernet-1.2.0/addernet.egg-info → addernet-1.2.2}/PKG-INFO +1 -1
- {addernet-1.2.0 → addernet-1.2.2}/addernet/addernet_hdc.py +16 -2
- {addernet-1.2.0 → addernet-1.2.2/addernet.egg-info}/PKG-INFO +1 -1
- {addernet-1.2.0 → addernet-1.2.2}/pyproject.toml +1 -1
- {addernet-1.2.0 → addernet-1.2.2}/python/addernet_hdc.py +158 -12
- {addernet-1.2.0 → addernet-1.2.2}/setup.py +1 -1
- {addernet-1.2.0 → addernet-1.2.2}/LICENSE +0 -0
- {addernet-1.2.0 → addernet-1.2.2}/MANIFEST.in +0 -0
- {addernet-1.2.0 → addernet-1.2.2}/Makefile +0 -0
- {addernet-1.2.0 → addernet-1.2.2}/README.md +0 -0
- {addernet-1.2.0 → addernet-1.2.2}/README_DEV.md +0 -0
- {addernet-1.2.0 → addernet-1.2.2}/addernet/__init__.py +0 -0
- {addernet-1.2.0 → addernet-1.2.2}/addernet/addernet.py +0 -0
- {addernet-1.2.0 → addernet-1.2.2}/addernet/attention.py +0 -0
- {addernet-1.2.0 → addernet-1.2.2}/addernet/boost.py +0 -0
- {addernet-1.2.0 → addernet-1.2.2}/addernet/build_ext.py +0 -0
- {addernet-1.2.0 → addernet-1.2.2}/addernet/cluster.py +0 -0
- {addernet-1.2.0 → addernet-1.2.2}/addernet/libaddernet.so +0 -0
- {addernet-1.2.0 → addernet-1.2.2}/addernet/libaddernet_hdc.so +0 -0
- {addernet-1.2.0 → addernet-1.2.2}/addernet/src/addernet.c +0 -0
- {addernet-1.2.0 → addernet-1.2.2}/addernet/src/addernet.h +0 -0
- {addernet-1.2.0 → addernet-1.2.2}/addernet/src/addernet_hdc.c +0 -0
- {addernet-1.2.0 → addernet-1.2.2}/addernet/src/addernet_hdc.h +0 -0
- {addernet-1.2.0 → addernet-1.2.2}/addernet/src/hdc_core.c +0 -0
- {addernet-1.2.0 → addernet-1.2.2}/addernet/src/hdc_core.h +0 -0
- {addernet-1.2.0 → addernet-1.2.2}/addernet/src/hdc_core_cuda.c +0 -0
- {addernet-1.2.0 → addernet-1.2.2}/addernet/src/hdc_cuda_batch.c +0 -0
- {addernet-1.2.0 → addernet-1.2.2}/addernet/src/hdc_lsh.c +0 -0
- {addernet-1.2.0 → addernet-1.2.2}/addernet/src/hdc_lsh.h +0 -0
- {addernet-1.2.0 → addernet-1.2.2}/addernet.egg-info/SOURCES.txt +0 -0
- {addernet-1.2.0 → addernet-1.2.2}/addernet.egg-info/dependency_links.txt +0 -0
- {addernet-1.2.0 → addernet-1.2.2}/addernet.egg-info/entry_points.txt +0 -0
- {addernet-1.2.0 → addernet-1.2.2}/addernet.egg-info/requires.txt +0 -0
- {addernet-1.2.0 → addernet-1.2.2}/addernet.egg-info/top_level.txt +0 -0
- {addernet-1.2.0 → addernet-1.2.2}/python/__init__.py +0 -0
- {addernet-1.2.0 → addernet-1.2.2}/python/addernet.py +0 -0
- {addernet-1.2.0 → addernet-1.2.2}/setup.cfg +0 -0
- {addernet-1.2.0 → addernet-1.2.2}/src/addernet.c +0 -0
- {addernet-1.2.0 → addernet-1.2.2}/src/addernet.h +0 -0
- {addernet-1.2.0 → addernet-1.2.2}/src/addernet_cuda.cu +0 -0
- {addernet-1.2.0 → addernet-1.2.2}/src/addernet_hdc.c +0 -0
- {addernet-1.2.0 → addernet-1.2.2}/src/addernet_hdc.h +0 -0
- {addernet-1.2.0 → addernet-1.2.2}/src/hdc_core.c +0 -0
- {addernet-1.2.0 → addernet-1.2.2}/src/hdc_core.h +0 -0
- {addernet-1.2.0 → addernet-1.2.2}/src/hdc_core_cuda.c +0 -0
- {addernet-1.2.0 → addernet-1.2.2}/src/hdc_cuda_batch.c +0 -0
- {addernet-1.2.0 → addernet-1.2.2}/src/hdc_lsh.c +0 -0
- {addernet-1.2.0 → addernet-1.2.2}/src/hdc_lsh.h +0 -0
|
@@ -40,6 +40,18 @@ if _lib is None:
|
|
|
40
40
|
"Build it first: cd addernet_lib && make hdc"
|
|
41
41
|
)
|
|
42
42
|
|
|
43
|
+
# ---- Optional CUDA Native library ----
|
|
44
|
+
|
|
45
|
+
_lib_cuda = None
|
|
46
|
+
try:
|
|
47
|
+
for _name in _LIB_NAMES:
|
|
48
|
+
_cuda_path = _name.replace("libaddernet_hdc.so", "libaddernet_cuda.so")
|
|
49
|
+
if os.path.exists(_cuda_path):
|
|
50
|
+
_lib_cuda = ctypes.CDLL(_cuda_path)
|
|
51
|
+
break
|
|
52
|
+
except OSError:
|
|
53
|
+
pass
|
|
54
|
+
|
|
43
55
|
# ---- Opaque pointer type ----
|
|
44
56
|
|
|
45
57
|
_AnHdcPtr = ctypes.c_void_p
|
|
@@ -213,7 +225,7 @@ class AdderNetHDC:
|
|
|
213
225
|
"""
|
|
214
226
|
|
|
215
227
|
def __init__(self, n_vars=1, n_classes=2, table_size=256, bias=None,
|
|
216
|
-
seed=42, _ptr=None):
|
|
228
|
+
seed=42, use_gpu=False, _ptr=None):
|
|
217
229
|
"""
|
|
218
230
|
Create a new model.
|
|
219
231
|
|
|
@@ -223,7 +235,10 @@ class AdderNetHDC:
|
|
|
223
235
|
table_size: encoding table size per variable (power of 2)
|
|
224
236
|
bias: list of bias values per variable (default: table_size//2)
|
|
225
237
|
seed: random seed for reproducibility
|
|
238
|
+
use_gpu: toggle between CPU and CUDA backend
|
|
226
239
|
"""
|
|
240
|
+
self.use_gpu = use_gpu
|
|
241
|
+
|
|
227
242
|
if _ptr is not None:
|
|
228
243
|
self._ptr = _ptr
|
|
229
244
|
self._n_vars = n_vars
|
|
@@ -706,4 +721,3 @@ def hdc_detect_backend():
|
|
|
706
721
|
"""
|
|
707
722
|
backends = ["SCALAR", "AVX2", "NEON"]
|
|
708
723
|
return backends[_lib.hdc_detect_backend()]
|
|
709
|
-
ackends[_lib.hdc_detect_backend()]
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "addernet"
|
|
7
|
-
version = "1.2.
|
|
7
|
+
version = "1.2.2"
|
|
8
8
|
description = "Neural networks with zero multiplications at inference. AdderNet + HDC for embedded systems."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = { text = "Apache-2.0" }
|
|
@@ -40,6 +40,18 @@ if _lib is None:
|
|
|
40
40
|
"Build it first: cd addernet_lib && make hdc"
|
|
41
41
|
)
|
|
42
42
|
|
|
43
|
+
# ---- Optional CUDA Native library ----
|
|
44
|
+
|
|
45
|
+
_lib_cuda = None
|
|
46
|
+
try:
|
|
47
|
+
for _name in _LIB_NAMES:
|
|
48
|
+
_cuda_path = _name.replace("libaddernet_hdc.so", "libaddernet_cuda.so")
|
|
49
|
+
if os.path.exists(_cuda_path):
|
|
50
|
+
_lib_cuda = ctypes.CDLL(_cuda_path)
|
|
51
|
+
break
|
|
52
|
+
except OSError:
|
|
53
|
+
pass
|
|
54
|
+
|
|
43
55
|
# ---- Opaque pointer type ----
|
|
44
56
|
|
|
45
57
|
_AnHdcPtr = ctypes.c_void_p
|
|
@@ -63,7 +75,7 @@ _lib.an_hdc_train.argtypes = [
|
|
|
63
75
|
ctypes.c_int,
|
|
64
76
|
]
|
|
65
77
|
|
|
66
|
-
_lib.an_hdc_retrain.restype =
|
|
78
|
+
_lib.an_hdc_retrain.restype = ctypes.c_int
|
|
67
79
|
_lib.an_hdc_retrain.argtypes = [
|
|
68
80
|
_AnHdcPtr,
|
|
69
81
|
ctypes.POINTER(ctypes.c_double),
|
|
@@ -71,9 +83,11 @@ _lib.an_hdc_retrain.argtypes = [
|
|
|
71
83
|
ctypes.c_int,
|
|
72
84
|
ctypes.c_int,
|
|
73
85
|
ctypes.c_float,
|
|
74
|
-
ctypes.
|
|
86
|
+
ctypes.c_int,
|
|
75
87
|
ctypes.c_float,
|
|
76
88
|
ctypes.c_int,
|
|
89
|
+
ctypes.c_int,
|
|
90
|
+
ctypes.POINTER(ctypes.c_int),
|
|
77
91
|
]
|
|
78
92
|
|
|
79
93
|
_lib.an_hdc_predict.restype = ctypes.c_int
|
|
@@ -96,6 +110,15 @@ _lib.an_hdc_predict_batch_avx.argtypes = [
|
|
|
96
110
|
ctypes.c_int,
|
|
97
111
|
]
|
|
98
112
|
|
|
113
|
+
if _lib_cuda is not None:
|
|
114
|
+
_lib_cuda.an_hdc_predict_batch_cuda.restype = ctypes.c_int
|
|
115
|
+
_lib_cuda.an_hdc_predict_batch_cuda.argtypes = [
|
|
116
|
+
_AnHdcPtr,
|
|
117
|
+
ctypes.POINTER(ctypes.c_double),
|
|
118
|
+
ctypes.POINTER(ctypes.c_int),
|
|
119
|
+
ctypes.c_int,
|
|
120
|
+
]
|
|
121
|
+
|
|
99
122
|
_lib.an_hdc_save.restype = ctypes.c_int
|
|
100
123
|
_lib.an_hdc_save.argtypes = [_AnHdcPtr, ctypes.c_char_p]
|
|
101
124
|
|
|
@@ -145,6 +168,15 @@ _lib.an_hdc_predict_top_k.argtypes = [
|
|
|
145
168
|
ctypes.c_int,
|
|
146
169
|
]
|
|
147
170
|
|
|
171
|
+
# Problem 6: Interaction encoding
|
|
172
|
+
_lib.an_hdc_set_interactions.restype = None
|
|
173
|
+
_lib.an_hdc_set_interactions.argtypes = [
|
|
174
|
+
_AnHdcPtr,
|
|
175
|
+
ctypes.POINTER(ctypes.c_int),
|
|
176
|
+
ctypes.POINTER(ctypes.c_int),
|
|
177
|
+
ctypes.c_int,
|
|
178
|
+
]
|
|
179
|
+
|
|
148
180
|
# OPT-8: Backend detection
|
|
149
181
|
_lib.hdc_detect_backend.restype = ctypes.c_int
|
|
150
182
|
_lib.hdc_detect_backend.argtypes = []
|
|
@@ -155,6 +187,7 @@ _lib.hv_seed.argtypes = [ctypes.c_uint]
|
|
|
155
187
|
# HDC primitive bindings (for direct hypervector manipulation)
|
|
156
188
|
|
|
157
189
|
_HV_WORDS = 40 # HDC_WORDS = ceil(2500/64)
|
|
190
|
+
_HV_DIM = 2500 # HDC_DIM — actual hypervector dimensionality
|
|
158
191
|
HDC_BYTES = _HV_WORDS * 8 # 320 bytes per hypervector
|
|
159
192
|
_HV_t = ctypes.c_uint64 * _HV_WORDS
|
|
160
193
|
|
|
@@ -192,7 +225,7 @@ class AdderNetHDC:
|
|
|
192
225
|
"""
|
|
193
226
|
|
|
194
227
|
def __init__(self, n_vars=1, n_classes=2, table_size=256, bias=None,
|
|
195
|
-
seed=42, _ptr=None):
|
|
228
|
+
seed=42, use_gpu=False, _ptr=None):
|
|
196
229
|
"""
|
|
197
230
|
Create a new model.
|
|
198
231
|
|
|
@@ -202,7 +235,10 @@ class AdderNetHDC:
|
|
|
202
235
|
table_size: encoding table size per variable (power of 2)
|
|
203
236
|
bias: list of bias values per variable (default: table_size//2)
|
|
204
237
|
seed: random seed for reproducibility
|
|
238
|
+
use_gpu: toggle between CPU and CUDA backend
|
|
205
239
|
"""
|
|
240
|
+
self.use_gpu = use_gpu
|
|
241
|
+
|
|
206
242
|
if _ptr is not None:
|
|
207
243
|
self._ptr = _ptr
|
|
208
244
|
self._n_vars = n_vars
|
|
@@ -228,7 +264,8 @@ class AdderNetHDC:
|
|
|
228
264
|
_lib.an_hdc_free(self._ptr)
|
|
229
265
|
self._ptr = None
|
|
230
266
|
|
|
231
|
-
def train(self, X, y, n_iter=0, lr=1.0, margin=0, regenerate=0.0,
|
|
267
|
+
def train(self, X, y, n_iter=0, lr=1.0, margin=0, regenerate=0.0,
|
|
268
|
+
patience=10, verbose=False, interactions=0):
|
|
232
269
|
"""
|
|
233
270
|
Train the codebook from labeled data, with optional iterative retraining.
|
|
234
271
|
|
|
@@ -241,9 +278,22 @@ class AdderNetHDC:
|
|
|
241
278
|
y: n_samples class labels (int, 0-indexed)
|
|
242
279
|
n_iter: number of iterative correction passes (0 = single-pass, default)
|
|
243
280
|
lr: learning rate for iterative retraining (default 1.0)
|
|
244
|
-
margin:
|
|
281
|
+
margin: RefineHD margin — aceita 4 formas:
|
|
282
|
+
0 / None → desligado (AdaptHD puro)
|
|
283
|
+
float 0-1 → fração de D (ex: 0.05 = 5% de D)
|
|
284
|
+
'5%' → percentual string (ex: '5%', '10%')
|
|
285
|
+
int > 0 → distância Hamming absoluta em bits
|
|
245
286
|
regenerate: NeuralHD dimension regeneration rate (0.0 = off, 0.02-0.05 recommended)
|
|
246
287
|
patience: early stopping patience in epochs (0 = disabled, 5 recommended)
|
|
288
|
+
verbose: if True, print epoch progress to stderr every 10 epochs. If int, print every N epochs.
|
|
289
|
+
interactions: number of top correlated feature pairs to encode (0 = disabled, 10 recommended)
|
|
290
|
+
Returns:
|
|
291
|
+
dict with training history:
|
|
292
|
+
'epochs_run': epochs actually executed,
|
|
293
|
+
'best_val_accuracy': best validation accuracy (last 25% of data),
|
|
294
|
+
'best_train_accuracy': best training accuracy (first 75% of data),
|
|
295
|
+
'best_epoch': epoch of best val accuracy,
|
|
296
|
+
'stopped_early': True if early stopping triggered
|
|
247
297
|
"""
|
|
248
298
|
X = np.ascontiguousarray(X, dtype=np.float64)
|
|
249
299
|
y = np.ascontiguousarray(y, dtype=np.int32)
|
|
@@ -255,6 +305,35 @@ class AdderNetHDC:
|
|
|
255
305
|
if len(y) != n:
|
|
256
306
|
raise ValueError(f"X has {n} samples but y has {len(y)}")
|
|
257
307
|
|
|
308
|
+
# Default history for single-pass training
|
|
309
|
+
history = {
|
|
310
|
+
'epochs_run': 0,
|
|
311
|
+
'best_val_accuracy': 0.0,
|
|
312
|
+
'best_train_accuracy': 0.0,
|
|
313
|
+
'best_epoch': 0,
|
|
314
|
+
'stopped_early': False,
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
# Problema 6: Detect and set interaction pairs
|
|
318
|
+
if interactions > 0 and X.shape[1] > 1:
|
|
319
|
+
corr = np.corrcoef(X.T)
|
|
320
|
+
pairs = []
|
|
321
|
+
for ii in range(corr.shape[0]):
|
|
322
|
+
for jj in range(ii + 1, corr.shape[1]):
|
|
323
|
+
pairs.append((abs(corr[ii, jj]), ii, jj))
|
|
324
|
+
pairs.sort(reverse=True)
|
|
325
|
+
top_pairs = pairs[:interactions]
|
|
326
|
+
if top_pairs:
|
|
327
|
+
pairs_i = np.array([p[1] for p in top_pairs], dtype=np.int32)
|
|
328
|
+
pairs_j = np.array([p[2] for p in top_pairs], dtype=np.int32)
|
|
329
|
+
_lib.an_hdc_set_interactions(
|
|
330
|
+
self._ptr,
|
|
331
|
+
pairs_i.ctypes.data_as(ctypes.POINTER(ctypes.c_int)),
|
|
332
|
+
pairs_j.ctypes.data_as(ctypes.POINTER(ctypes.c_int)),
|
|
333
|
+
len(top_pairs),
|
|
334
|
+
)
|
|
335
|
+
|
|
336
|
+
# Initial train (encodes samples including interactions)
|
|
258
337
|
_lib.an_hdc_train(
|
|
259
338
|
self._ptr,
|
|
260
339
|
X.ctypes.data_as(ctypes.POINTER(ctypes.c_double)),
|
|
@@ -263,6 +342,46 @@ class AdderNetHDC:
|
|
|
263
342
|
)
|
|
264
343
|
|
|
265
344
|
if n_iter > 0:
|
|
345
|
+
D = _HV_WORDS * 64 # total bits no hipervector (2500)
|
|
346
|
+
|
|
347
|
+
# ── Conversão de margin ──────────────────────────────
|
|
348
|
+
if margin == 0 or margin is None:
|
|
349
|
+
margin_int = 0 # desligado — AdaptHD puro
|
|
350
|
+
|
|
351
|
+
elif isinstance(margin, str) and margin.endswith('%'):
|
|
352
|
+
pct = float(margin[:-1]) / 100.0
|
|
353
|
+
margin_int = max(1, int(pct * D))
|
|
354
|
+
|
|
355
|
+
elif isinstance(margin, float) and 0.0 < margin < 1.0:
|
|
356
|
+
margin_int = max(1, int(margin * D))
|
|
357
|
+
|
|
358
|
+
elif isinstance(margin, int) and margin > 0:
|
|
359
|
+
margin_int = margin
|
|
360
|
+
|
|
361
|
+
else:
|
|
362
|
+
raise ValueError(
|
|
363
|
+
f"margin deve ser: 0 (off), float 0-1 (fração de D), "
|
|
364
|
+
f"'5%' (percentual), ou int (bits). Recebeu: {margin!r}"
|
|
365
|
+
)
|
|
366
|
+
|
|
367
|
+
# Clamp: nunca maior que 20% de D
|
|
368
|
+
margin_int = min(margin_int, int(D * 0.20))
|
|
369
|
+
|
|
370
|
+
if verbose:
|
|
371
|
+
if margin_int == 0:
|
|
372
|
+
print(f" margin=off (AdaptHD puro)")
|
|
373
|
+
else:
|
|
374
|
+
print(f" margin={margin!r} → {margin_int} bits ({margin_int/D*100:.1f}% de D={D})")
|
|
375
|
+
|
|
376
|
+
# Verbose level: True → 10, int → as-is, False → 0
|
|
377
|
+
if verbose is True:
|
|
378
|
+
verbose_level = 10
|
|
379
|
+
elif isinstance(verbose, int) and verbose > 0:
|
|
380
|
+
verbose_level = verbose
|
|
381
|
+
else:
|
|
382
|
+
verbose_level = 0
|
|
383
|
+
|
|
384
|
+
epochs_run = ctypes.c_int(0)
|
|
266
385
|
_lib.an_hdc_retrain(
|
|
267
386
|
self._ptr,
|
|
268
387
|
X.ctypes.data_as(ctypes.POINTER(ctypes.c_double)),
|
|
@@ -270,11 +389,27 @@ class AdderNetHDC:
|
|
|
270
389
|
n,
|
|
271
390
|
n_iter,
|
|
272
391
|
ctypes.c_float(lr),
|
|
273
|
-
ctypes.
|
|
392
|
+
ctypes.c_int(margin_int),
|
|
274
393
|
ctypes.c_float(regenerate),
|
|
275
394
|
ctypes.c_int(patience),
|
|
395
|
+
ctypes.c_int(verbose_level),
|
|
396
|
+
ctypes.byref(epochs_run),
|
|
276
397
|
)
|
|
277
398
|
|
|
399
|
+
# Compute final accuracies on train/val split
|
|
400
|
+
n_val = max(1, n // 4)
|
|
401
|
+
n_train_split = n - n_val
|
|
402
|
+
train_acc = float(self.accuracy(X[:n_train_split], y[:n_train_split]))
|
|
403
|
+
val_acc = float(self.accuracy(X[n_train_split:], y[n_train_split:]))
|
|
404
|
+
|
|
405
|
+
history['epochs_run'] = epochs_run.value
|
|
406
|
+
history['best_val_accuracy'] = val_acc
|
|
407
|
+
history['best_train_accuracy'] = train_acc
|
|
408
|
+
history['best_epoch'] = epochs_run.value
|
|
409
|
+
history['stopped_early'] = (epochs_run.value < n_iter)
|
|
410
|
+
|
|
411
|
+
return history
|
|
412
|
+
|
|
278
413
|
def predict(self, x):
|
|
279
414
|
"""
|
|
280
415
|
Classify one sample.
|
|
@@ -304,12 +439,23 @@ class AdderNetHDC:
|
|
|
304
439
|
X = X.reshape(-1, self._n_vars)
|
|
305
440
|
n = X.shape[0]
|
|
306
441
|
outputs = np.empty(n, dtype=np.int32)
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
442
|
+
|
|
443
|
+
if getattr(self, 'use_gpu', False):
|
|
444
|
+
if _lib_cuda is None:
|
|
445
|
+
raise RuntimeError("CUDA backend requested but libaddernet_cuda.so not found")
|
|
446
|
+
_lib_cuda.an_hdc_predict_batch_cuda(
|
|
447
|
+
self._ptr,
|
|
448
|
+
X.ctypes.data_as(ctypes.POINTER(ctypes.c_double)),
|
|
449
|
+
outputs.ctypes.data_as(ctypes.POINTER(ctypes.c_int)),
|
|
450
|
+
n,
|
|
451
|
+
)
|
|
452
|
+
else:
|
|
453
|
+
_lib.an_hdc_predict_batch(
|
|
454
|
+
self._ptr,
|
|
455
|
+
X.ctypes.data_as(ctypes.POINTER(ctypes.c_double)),
|
|
456
|
+
outputs.ctypes.data_as(ctypes.POINTER(ctypes.c_int)),
|
|
457
|
+
n,
|
|
458
|
+
)
|
|
313
459
|
return outputs
|
|
314
460
|
|
|
315
461
|
def predict_batch_avx(self, X):
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|