haliax 1.4.dev367__tar.gz → 1.4.dev369__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.
- haliax-1.4.dev369/.playbooks/add-types.md +45 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/AGENTS.md +6 -2
- {haliax-1.4.dev367 → haliax-1.4.dev369}/PKG-INFO +1 -1
- {haliax-1.4.dev367 → haliax-1.4.dev369}/docs/scan.md +11 -0
- haliax-1.4.dev369/docs/vmap.md +9 -0
- haliax-1.4.dev369/src/haliax/__about__.py +1 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/src/haliax/nn/scan.py +31 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/tests/test_scan.py +24 -0
- haliax-1.4.dev367/docs/vmap.md +0 -5
- haliax-1.4.dev367/src/haliax/__about__.py +0 -1
- {haliax-1.4.dev367 → haliax-1.4.dev369}/.coveragerc +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/.flake8 +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/.github/workflows/publish_dev.yaml +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/.github/workflows/run_pre_commit.yaml +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/.github/workflows/run_quick_levanter_tests.yaml +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/.github/workflows/run_tests.yaml +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/.gitignore +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/.pre-commit-config.yaml +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/.readthedocs.yaml +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/CONTRIBUTING.md +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/LICENSE +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/README.md +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/docs/api.md +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/docs/broadcasting.md +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/docs/cheatsheet.md +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/docs/css/material.css +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/docs/css/mkdocstrings.css +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/docs/faq.md +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/docs/figures/data_parallel_mesh.png +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/docs/figures/data_parallel_mesh_replicated.png +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/docs/figures/device_mesh_1d.png +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/docs/figures/device_mesh_1d_zero.png +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/docs/figures/device_mesh_2d.png +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/docs/figures/device_mesh_2d_batch_partitioned.png +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/docs/figures/device_mesh_2d_data_replicated.png +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/docs/figures/device_mesh_2d_data_replicated_mlp_partitioned.png +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/docs/figures/device_mesh_2d_intermediate_fully_partitioned.png +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/docs/figures/device_mesh_2d_zero.png +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/docs/fp8.md +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/docs/index.md +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/docs/indexing.md +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/docs/matmul.md +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/docs/nn.md +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/docs/partitioning.md +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/docs/rearrange.ipynb +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/docs/rearrange.md +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/docs/requirements.txt +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/docs/state-dict.md +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/docs/tutorial.md +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/docs/typing.md +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/mkdocs.yml +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/pyproject.toml +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/src/haliax/__init__.py +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/src/haliax/_src/__init__.py +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/src/haliax/_src/compile_utils.py +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/src/haliax/_src/dot.py +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/src/haliax/_src/einsum.py +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/src/haliax/_src/fp8.py +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/src/haliax/_src/parsing.py +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/src/haliax/_src/rearrange.py +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/src/haliax/_src/scan.py +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/src/haliax/_src/state_dict.py +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/src/haliax/_src/util.py +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/src/haliax/axis.py +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/src/haliax/core.py +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/src/haliax/debug.py +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/src/haliax/haxtyping.py +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/src/haliax/hof.py +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/src/haliax/jax_utils.py +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/src/haliax/nn/__init__.py +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/src/haliax/nn/activations.py +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/src/haliax/nn/attention.py +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/src/haliax/nn/conv.py +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/src/haliax/nn/dropout.py +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/src/haliax/nn/embedding.py +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/src/haliax/nn/linear.py +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/src/haliax/nn/loss.py +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/src/haliax/nn/mlp.py +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/src/haliax/nn/normalization.py +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/src/haliax/nn/pool.py +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/src/haliax/ops.py +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/src/haliax/partitioning.py +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/src/haliax/quantization.py +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/src/haliax/random.py +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/src/haliax/specialized_fns.py +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/src/haliax/state_dict.py +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/src/haliax/tree_util.py +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/src/haliax/types.py +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/src/haliax/util.py +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/src/haliax/wrap.py +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/tests/core_test.py +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/tests/test_attention.py +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/tests/test_axis.py +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/tests/test_conv.py +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/tests/test_debug.py +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/tests/test_dot.py +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/tests/test_dtype_typing.py +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/tests/test_einsum.py +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/tests/test_fp8.py +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/tests/test_hof.py +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/tests/test_int8.py +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/tests/test_namedarray_typing.py +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/tests/test_nn.py +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/tests/test_ops.py +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/tests/test_parsing.py +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/tests/test_partitioning.py +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/tests/test_pool.py +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/tests/test_random.py +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/tests/test_rearrange.py +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/tests/test_scatter_gather.py +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/tests/test_specialized_fns.py +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/tests/test_state_dict.py +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/tests/test_tree_util.py +0 -0
- {haliax-1.4.dev367 → haliax-1.4.dev369}/tests/test_utils.py +0 -0
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Adding NamedArray Type Annotations
|
|
2
|
+
|
|
3
|
+
This playbook explains how to migrate existing code to use the new type
|
|
4
|
+
annotation helpers described in `docs/typing.md`.
|
|
5
|
+
|
|
6
|
+
1. **Read the documentation**: Familiarise yourself with `docs/typing.md`.
|
|
7
|
+
It describes the `Named[...]` syntax and the dtype aware helpers in
|
|
8
|
+
`haliax.typing`.
|
|
9
|
+
2. **Annotate parameters**: Replace plain `NamedArray` annotations with
|
|
10
|
+
`Named[...]` that lists the required axes. Use ellipses or sets when the
|
|
11
|
+
exact order is flexible.
|
|
12
|
+
|
|
13
|
+
```python
|
|
14
|
+
from haliax import Named
|
|
15
|
+
|
|
16
|
+
# old
|
|
17
|
+
def foo(x: NamedArray) -> NamedArray:
|
|
18
|
+
...
|
|
19
|
+
|
|
20
|
+
# new
|
|
21
|
+
def foo(x: Named["batch", "embed"]) -> Named["batch", "embed"]:
|
|
22
|
+
...
|
|
23
|
+
```
|
|
24
|
+
3. **Annotate dtypes when needed**: If the dtype matters, import symbolic dtypes
|
|
25
|
+
from `haliax.typing` (e.g. `ht.f32`, `ht.i32`). They can be indexed just
|
|
26
|
+
like `Named`.
|
|
27
|
+
|
|
28
|
+
```python
|
|
29
|
+
import haliax.typing as ht
|
|
30
|
+
|
|
31
|
+
def bar(x: ht.f32["batch"]):
|
|
32
|
+
...
|
|
33
|
+
```
|
|
34
|
+
4. **Runtime validation**: Use `arr.matches_axes(...)` to check that a
|
|
35
|
+
`NamedArray` conforms to the expected axes and dtype at runtime.
|
|
36
|
+
|
|
37
|
+
```python
|
|
38
|
+
if not arr.matches_axes(Named["batch embed ..."]):
|
|
39
|
+
raise ValueError("unexpected axes")
|
|
40
|
+
```
|
|
41
|
+
5. **Update return types**: Functions returning `NamedArray` should annotate
|
|
42
|
+
their return values using the same conventions.
|
|
43
|
+
|
|
44
|
+
Following these steps will gradually port legacy code to the new
|
|
45
|
+
annotation style.
|
|
@@ -16,8 +16,7 @@ repository. Follow these notes when implementing new features or fixing bugs.
|
|
|
16
16
|
|
|
17
17
|
## Playbook
|
|
18
18
|
|
|
19
|
-
-
|
|
20
|
-
should be documented, please create a new markdown file in `.playbooks/` and add it to the list above.
|
|
19
|
+
- Adding Haliax-style tensor typing annotations are described in @.playbooks/add-typing.md
|
|
21
20
|
|
|
22
21
|
## Code Style
|
|
23
22
|
|
|
@@ -58,6 +57,11 @@ repository. Follow these notes when implementing new features or fixing bugs.
|
|
|
58
57
|
|
|
59
58
|
* **Generic code**: many utilities are written with Python generics and dataclasses. Where possible,
|
|
60
59
|
write reusable functions or classes that operate over TypeVars instead of hard coding concrete types.
|
|
60
|
+
* **Configurations**: configuration files are dataclasses loaded via `draccus`. Keep configs
|
|
61
|
+
declarative and typed.
|
|
62
|
+
* **Reproducibility**: Levanter aims for deterministic training where possible. Avoid sources of
|
|
63
|
+
nondeterminism unless explicitly required.
|
|
64
|
+
* Prefer Stacked with fold or scan over writing custom loops, for better compile times and gradient checkpointing support
|
|
61
65
|
|
|
62
66
|
## Library conventions
|
|
63
67
|
- Haliax revolves around `NamedArray` and explicit `Axis` objects. Prefer APIs that accept
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: haliax
|
|
3
|
-
Version: 1.4.
|
|
3
|
+
Version: 1.4.dev369
|
|
4
4
|
Summary: Named Tensors for Legible Deep Learning in JAX
|
|
5
5
|
Project-URL: Homepage, https://github.com/stanford-crfm/haliax
|
|
6
6
|
Project-URL: Bug Tracker, https://github.com/stanford-crfm/haliax/issues/
|
|
@@ -405,6 +405,17 @@ blocks = Stacked.init(Layers, Gpt2Block)(
|
|
|
405
405
|
Any NamedArray passed to the Stacked init will have its Layers axis (if present) vmapped over. Any
|
|
406
406
|
JAX array will have its first axis vmapped over.
|
|
407
407
|
|
|
408
|
+
#### Apply Blocks in Parallel with `vmap`
|
|
409
|
+
|
|
410
|
+
Sometimes you may want to apply each block independently, without feeding the
|
|
411
|
+
output of one block into the next. `Stacked.vmap` does exactly that: it uses
|
|
412
|
+
[`haliax.vmap`][] to broadcast the initial value to every block and evaluates
|
|
413
|
+
them in parallel, returning the stack of outputs.
|
|
414
|
+
|
|
415
|
+
```python
|
|
416
|
+
y = stacked.vmap(x)
|
|
417
|
+
```
|
|
418
|
+
|
|
408
419
|
|
|
409
420
|
#### Fold Blocks vs Scan Blocks
|
|
410
421
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "1.4.dev369"
|
|
@@ -233,6 +233,8 @@ class Stacked(ModuleWithStateDictSerialization, Generic[M]):
|
|
|
233
233
|
output, while "scan" is the same as a for loop that accumulates a list of outputs as well as the final output.
|
|
234
234
|
|
|
235
235
|
Stacked also supports gradient checkpointing, which is useful for very large models that don't fit in memory.
|
|
236
|
+
If your blocks are independent of each other you can instead use :py:meth:`Stacked.vmap`
|
|
237
|
+
to apply every block in parallel.
|
|
236
238
|
|
|
237
239
|
Typically only one of "fold" or "scan" can be used with a given Stacked module, depending on the what the module
|
|
238
240
|
returns: if the module returns a single output, use "fold"; if the module returns a sequence of outputs and
|
|
@@ -382,6 +384,35 @@ class Stacked(ModuleWithStateDictSerialization, Generic[M]):
|
|
|
382
384
|
|
|
383
385
|
return do_fold(init, *args, **kwargs)
|
|
384
386
|
|
|
387
|
+
def vmap(self, init, *extra_args, **extra_kwargs):
|
|
388
|
+
"""Apply each block independently using :func:`haliax.vmap`.
|
|
389
|
+
|
|
390
|
+
This maps ``init`` through every block in parallel, so each block
|
|
391
|
+
receives the same ``init`` but its own parameters. Extra ``args`` and
|
|
392
|
+
``kwargs`` are also mapped over the block axis by default.
|
|
393
|
+
|
|
394
|
+
Returns the stacked outputs of each block.
|
|
395
|
+
"""
|
|
396
|
+
|
|
397
|
+
if haliax.is_named_array(init):
|
|
398
|
+
init = init.broadcast_axis(self.Block)
|
|
399
|
+
elif haliax.jax_utils.is_jax_array_like(init):
|
|
400
|
+
init = jnp.broadcast_to(init, (self.Block.size,) + init.shape)
|
|
401
|
+
else:
|
|
402
|
+
init = tuple(init for _ in range(self.Block.size))
|
|
403
|
+
|
|
404
|
+
arg_spec = (0, 0) + (0,) * len(extra_args)
|
|
405
|
+
kwarg_spec = {k: 0 for k in extra_kwargs}
|
|
406
|
+
|
|
407
|
+
do_vmap = haliax.vmap(
|
|
408
|
+
Stacked._do_block,
|
|
409
|
+
self.Block,
|
|
410
|
+
default=0,
|
|
411
|
+
args=arg_spec,
|
|
412
|
+
kwargs=kwarg_spec,
|
|
413
|
+
)
|
|
414
|
+
return do_vmap(init, self.stacked, *extra_args, **extra_kwargs)
|
|
415
|
+
|
|
385
416
|
@staticmethod
|
|
386
417
|
def _do_block(carry, block, *extra_args, **extra_kwargs):
|
|
387
418
|
return block(carry, *extra_args, **extra_kwargs)
|
|
@@ -45,6 +45,30 @@ def test_unstacked():
|
|
|
45
45
|
assert hax.all(module.array == m.stacked.array[i])
|
|
46
46
|
|
|
47
47
|
|
|
48
|
+
def test_vmap():
|
|
49
|
+
class Module(eqx.Module):
|
|
50
|
+
weight: hax.NamedArray
|
|
51
|
+
|
|
52
|
+
def __call__(self, x):
|
|
53
|
+
return x + self.weight
|
|
54
|
+
|
|
55
|
+
@staticmethod
|
|
56
|
+
def init(weight):
|
|
57
|
+
return Module(weight=weight)
|
|
58
|
+
|
|
59
|
+
Block = hax.Axis("block", 4)
|
|
60
|
+
E = hax.Axis("E", 10)
|
|
61
|
+
|
|
62
|
+
weights = hax.random.uniform(jax.random.PRNGKey(0), (Block, E))
|
|
63
|
+
m = Stacked.init(Block, Module)(weight=weights)
|
|
64
|
+
|
|
65
|
+
x = hax.random.uniform(jax.random.PRNGKey(1), (E,))
|
|
66
|
+
y = m.vmap(x)
|
|
67
|
+
|
|
68
|
+
assert y.axes == (Block, E)
|
|
69
|
+
assert hax.all(y == weights + x)
|
|
70
|
+
|
|
71
|
+
|
|
48
72
|
def test_seq_and_stacked_give_same_results():
|
|
49
73
|
class Module(eqx.Module):
|
|
50
74
|
named: hax.NamedArray
|
haliax-1.4.dev367/docs/vmap.md
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "1.4.dev367"
|
|
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
|
|
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
|
|
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
|