disko 1.4.2__tar.gz → 1.4.4__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.
Files changed (52) hide show
  1. {disko-1.4.2 → disko-1.4.4}/CHANGES.md +9 -0
  2. {disko-1.4.2 → disko-1.4.4}/PKG-INFO +4 -3
  3. {disko-1.4.2 → disko-1.4.4}/disko/disko.py +12 -9
  4. {disko-1.4.2 → disko-1.4.4}/disko/sphere_mesh.py +7 -3
  5. {disko-1.4.2 → disko-1.4.4}/pyproject.toml +5 -3
  6. {disko-1.4.2 → disko-1.4.4}/uv.lock +46 -11
  7. {disko-1.4.2 → disko-1.4.4}/.github/workflows/package.yaml +0 -0
  8. {disko-1.4.2 → disko-1.4.4}/.github/workflows/testing.yaml +0 -0
  9. {disko-1.4.2 → disko-1.4.4}/.gitignore +0 -0
  10. {disko-1.4.2 → disko-1.4.4}/.travis.yml +0 -0
  11. {disko-1.4.2 → disko-1.4.4}/CITATION.cff +0 -0
  12. {disko-1.4.2 → disko-1.4.4}/LICENSE.txt +0 -0
  13. {disko-1.4.2 → disko-1.4.4}/MANIFEST.in +0 -0
  14. {disko-1.4.2 → disko-1.4.4}/Makefile +0 -0
  15. {disko-1.4.2 → disko-1.4.4}/README.md +0 -0
  16. {disko-1.4.2 → disko-1.4.4}/disko/__init__.py +0 -0
  17. {disko-1.4.2 → disko-1.4.4}/disko/bayes_cli.py +0 -0
  18. {disko-1.4.2 → disko-1.4.4}/disko/cli.py +0 -0
  19. {disko-1.4.2 → disko-1.4.4}/disko/draw_cli.py +0 -0
  20. {disko-1.4.2 → disko-1.4.4}/disko/draw_sky.py +0 -0
  21. {disko-1.4.2 → disko-1.4.4}/disko/fov/__init__.py +0 -0
  22. {disko-1.4.2 → disko-1.4.4}/disko/fov/factory.py +0 -0
  23. {disko-1.4.2 → disko-1.4.4}/disko/healpix_sphere.py +0 -0
  24. {disko-1.4.2 → disko-1.4.4}/disko/ms_helper.py +0 -0
  25. {disko-1.4.2 → disko-1.4.4}/disko/multivariate_gaussian.py +0 -0
  26. {disko-1.4.2 → disko-1.4.4}/disko/parser_support.py +0 -0
  27. {disko-1.4.2 → disko-1.4.4}/disko/projection_lsqr.py +0 -0
  28. {disko-1.4.2 → disko-1.4.4}/disko/resolution.py +0 -0
  29. {disko-1.4.2 → disko-1.4.4}/disko/rime.py +0 -0
  30. {disko-1.4.2 → disko-1.4.4}/disko/sphere.py +0 -0
  31. {disko-1.4.2 → disko-1.4.4}/disko/svd_cli.py +0 -0
  32. {disko-1.4.2 → disko-1.4.4}/disko/telescope_operator.py +0 -0
  33. {disko-1.4.2 → disko-1.4.4}/disko/tests/__init__.py +0 -0
  34. {disko-1.4.2 → disko-1.4.4}/disko/tests/test_disko.py +0 -0
  35. {disko-1.4.2 → disko-1.4.4}/disko/tests/test_meshsphere.py +0 -0
  36. {disko-1.4.2 → disko-1.4.4}/disko/tests/test_multivariate.py +0 -0
  37. {disko-1.4.2 → disko-1.4.4}/disko/tests/test_projection_lsqr.py +0 -0
  38. {disko-1.4.2 → disko-1.4.4}/disko/tests/test_pylops_operator.py +0 -0
  39. {disko-1.4.2 → disko-1.4.4}/disko/tests/test_sphere.py +0 -0
  40. {disko-1.4.2 → disko-1.4.4}/disko/tests/test_subsphere.py +0 -0
  41. {disko-1.4.2 → disko-1.4.4}/disko/tests/test_telescope_operator.py +0 -0
  42. {disko-1.4.2 → disko-1.4.4}/disko/util.py +0 -0
  43. {disko-1.4.2 → disko-1.4.4}/docker/Dockerfile +0 -0
  44. {disko-1.4.2 → disko-1.4.4}/docker/Makefile +0 -0
  45. {disko-1.4.2 → disko-1.4.4}/docker/docker-compose.yml +0 -0
  46. {disko-1.4.2 → disko-1.4.4}/install.sh +0 -0
  47. {disko-1.4.2 → disko-1.4.4}/movie/.gitignore +0 -0
  48. {disko-1.4.2 → disko-1.4.4}/movie/Makefile +0 -0
  49. {disko-1.4.2 → disko-1.4.4}/prof.py +0 -0
  50. {disko-1.4.2 → disko-1.4.4}/requirements.txt +0 -0
  51. {disko-1.4.2 → disko-1.4.4}/sequential_test.sh +0 -0
  52. {disko-1.4.2 → disko-1.4.4}/setup.cfg +0 -0
@@ -1,5 +1,14 @@
1
1
  # Changes
2
2
 
3
+ ## 1.4.4 (2026-06-22)
4
+
5
+ - Fix `image_visibilities` RAM: use matrix-free blocked adjoint instead of building the full complex Gamma matrix in memory
6
+
7
+ ## 1.4.3 (2026-06-22)
8
+
9
+ - Make `gmsh` and `meshio` optional dependencies in new `[mesh]` extras group; `uv sync --extra mesh` to install
10
+ - Clear error messages when using `--mesh` without the optional dependencies
11
+
3
12
  ## 1.4.2 (2026-06-22)
4
13
 
5
14
  - Delegate angle parsing to `angle-parser` library; remove custom `parse_ending` and unit constants from `Resolution`
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: disko
3
- Version: 1.4.2
3
+ Version: 1.4.4
4
4
  Summary: Discrete Sky Operator (DiSkO) Aperture Synthesis Radio Imaging
5
5
  Author-email: Tim Molteno <tim@elec.ac.nz>
6
6
  License: GPLv3
@@ -8,12 +8,10 @@ License-File: LICENSE.txt
8
8
  Requires-Python: <3.14,>=3.11
9
9
  Requires-Dist: angle-parser>=0.2.0
10
10
  Requires-Dist: dask-ms<0.3.0,>=0.2.25
11
- Requires-Dist: gmsh>=4.0
12
11
  Requires-Dist: h5py>=3.7
13
12
  Requires-Dist: healpy<2.0.0,>=1.15.0
14
13
  Requires-Dist: imageio>=0.6.0b1
15
14
  Requires-Dist: matplotlib<4.0.0,>=3.1.0
16
- Requires-Dist: meshio>=5.0
17
15
  Requires-Dist: numpy<3.0.0,>=1.2.1
18
16
  Requires-Dist: pylops>=2.0
19
17
  Requires-Dist: scikit-learn>=1.0.1
@@ -22,6 +20,9 @@ Requires-Dist: svgwrite>=1.4.3
22
20
  Requires-Dist: tart-tools>=1.4.0
23
21
  Requires-Dist: tart>=1.4.0
24
22
  Requires-Dist: toolz>=0.11.2
23
+ Provides-Extra: mesh
24
+ Requires-Dist: gmsh>=4.0; extra == 'mesh'
25
+ Requires-Dist: meshio>=5.0; extra == 'mesh'
25
26
  Provides-Extra: ms
26
27
  Requires-Dist: tart2ms>=0.9.0; extra == 'ms'
27
28
  Description-Content-Type: text/markdown
@@ -370,11 +370,10 @@ class DiSkO(object):
370
370
 
371
371
  def image_visibilities(self, vis_arr, sphere):
372
372
  """
373
- Create a DiSkO image from visibilities using the direct adjoint of the
374
- measurement operator (corresponds to the inverse DFT)
373
+ Create a DiSkO image from visibilities using the adjoint of the
374
+ measurement operator (matrix-free, blocked for memory efficiency).
375
375
 
376
376
  Args:
377
-
378
377
  vis_arr (np.array): An array of complex visibilities
379
378
  sphere (FoV): a sphere to place
380
379
  """
@@ -383,12 +382,16 @@ class DiSkO(object):
383
382
  logger.info("Imaging Visabilities resolution={}".format(sphere.min_res()))
384
383
  t0 = time.time()
385
384
 
386
- gamma = self.get_harmonics(sphere) # shape (n_v, n_pix), complex
387
- # sum_i conj(vis_i) * H[i,:] = conj(vis) @ H = H.T @ conj(vis) ...
388
- # Actually: pixels = sum_i vis_i * h_i = vis @ H = (H.T @ vis).T
389
- # Each column of H is a harmonic for one visibility.
390
- # pixels[j] = sum_i vis_i * H[i,j] = (vis @ H)[j]
391
- pixels = vis_arr @ gamma # (n_vis,) @ (n_vis, n_pix) -> (n_pix,)
385
+ # Build a DiSkOOperator and use its adjoint (A.T @ d)
386
+ # This is matrix-free and uses blocked computation to avoid
387
+ # storing the full Gamma matrix.
388
+ data = self.vis_to_data(vis_arr)
389
+ frequencies = [self.frequency]
390
+ A = DiSkOOperator(
391
+ self.u_arr, self.v_arr, self.w_arr, data, frequencies, sphere
392
+ )
393
+ d = data.flatten()
394
+ pixels = A.T @ d # shape (n_pix,)
392
395
 
393
396
  logger.info("Elapsed {}s".format(time.time() - t0))
394
397
 
@@ -11,7 +11,6 @@
11
11
  import logging
12
12
 
13
13
  import h5py
14
- import meshio
15
14
  import numpy as np
16
15
 
17
16
  try:
@@ -19,6 +18,11 @@ try:
19
18
  except ImportError:
20
19
  gmsh = None
21
20
 
21
+ try:
22
+ import meshio
23
+ except ImportError:
24
+ meshio = None
25
+
22
26
  from scipy.spatial import Delaunay
23
27
 
24
28
  from .resolution import Resolution
@@ -100,8 +104,8 @@ def get_mesh(radius_rad, edge_size):
100
104
  Returns (points, cells) where points is (N, 3) scaled by radius_rad
101
105
  and cells is (M, 3) integer array of triangle vertex indices.
102
106
  """
103
- if gmsh is None:
104
- raise RuntimeError("gmsh is required for mesh generation")
107
+ if gmsh is None or meshio is None:
108
+ raise RuntimeError("gmsh and meshio are required for mesh generation. Install with: uv sync --extra mesh")
105
109
 
106
110
  logger.info(
107
111
  f"Generating Mesh: Radius: {Resolution.from_rad(radius_rad)},"
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "disko"
3
- version = "1.4.2"
3
+ version = "1.4.4"
4
4
  description = "Discrete Sky Operator (DiSkO) Aperture Synthesis Radio Imaging"
5
5
  authors = [
6
6
  {name = "Tim Molteno",email = "tim@elec.ac.nz"}
@@ -21,8 +21,6 @@ dependencies = [
21
21
  "pylops>=2.0",
22
22
  "toolz>=0.11.2",
23
23
  "imageio>=0.6.0b1",
24
- "gmsh>=4.0",
25
- "meshio>=5.0",
26
24
  "dask-ms>=0.2.25,<0.3.0",
27
25
  "angle-parser>=0.2.0",
28
26
  ]
@@ -31,6 +29,10 @@ dependencies = [
31
29
  ms = [
32
30
  "tart2ms>=0.9.0",
33
31
  ]
32
+ mesh = [
33
+ "gmsh>=4.0",
34
+ "meshio>=5.0",
35
+ ]
34
36
 
35
37
  [dependency-groups]
36
38
  dev = [
@@ -379,17 +379,15 @@ wheels = [
379
379
 
380
380
  [[package]]
381
381
  name = "disko"
382
- version = "1.4.1"
382
+ version = "1.4.2"
383
383
  source = { editable = "." }
384
384
  dependencies = [
385
385
  { name = "angle-parser" },
386
386
  { name = "dask-ms" },
387
- { name = "gmsh" },
388
387
  { name = "h5py" },
389
388
  { name = "healpy" },
390
389
  { name = "imageio" },
391
390
  { name = "matplotlib" },
392
- { name = "meshio" },
393
391
  { name = "numpy" },
394
392
  { name = "pylops" },
395
393
  { name = "scikit-learn" },
@@ -401,6 +399,10 @@ dependencies = [
401
399
  ]
402
400
 
403
401
  [package.optional-dependencies]
402
+ mesh = [
403
+ { name = "gmsh" },
404
+ { name = "meshio" },
405
+ ]
404
406
  ms = [
405
407
  { name = "tart2ms" },
406
408
  ]
@@ -413,14 +415,14 @@ dev = [
413
415
 
414
416
  [package.metadata]
415
417
  requires-dist = [
416
- { name = "angle-parser", specifier = "==0.2.0" },
418
+ { name = "angle-parser", specifier = ">=0.2.0" },
417
419
  { name = "dask-ms", specifier = ">=0.2.25,<0.3.0" },
418
- { name = "gmsh", specifier = ">=4.9" },
420
+ { name = "gmsh", marker = "extra == 'mesh'", specifier = ">=4.0" },
419
421
  { name = "h5py", specifier = ">=3.7" },
420
422
  { name = "healpy", specifier = ">=1.15.0,<2.0.0" },
421
423
  { name = "imageio", specifier = ">=0.6.0b1" },
422
424
  { name = "matplotlib", specifier = ">=3.1.0,<4.0.0" },
423
- { name = "meshio", specifier = ">=5.0" },
425
+ { name = "meshio", marker = "extra == 'mesh'", specifier = ">=5.0" },
424
426
  { name = "numpy", specifier = ">=1.2.1,<3.0.0" },
425
427
  { name = "pylops", specifier = ">=2.0" },
426
428
  { name = "scikit-learn", specifier = ">=1.0.1" },
@@ -428,10 +430,10 @@ requires-dist = [
428
430
  { name = "svgwrite", specifier = ">=1.4.3" },
429
431
  { name = "tart", specifier = ">=1.4.0" },
430
432
  { name = "tart-tools", specifier = ">=1.4.0" },
431
- { name = "tart2ms", marker = "extra == 'ms'", specifier = ">=0.7.1" },
433
+ { name = "tart2ms", marker = "extra == 'ms'", specifier = ">=0.9.0" },
432
434
  { name = "toolz", specifier = ">=0.11.2" },
433
435
  ]
434
- provides-extras = ["ms"]
436
+ provides-extras = ["ms", "mesh"]
435
437
 
436
438
  [package.metadata.requires-dev]
437
439
  dev = [
@@ -1392,6 +1394,23 @@ wheels = [
1392
1394
  { url = "https://files.pythonhosted.org/packages/70/b0/eb757336e5a76dfa7911f63252e3b7d1de00935d7705cf772db5b45ec238/scipy-1.17.1-cp313-cp313t-win_arm64.whl", hash = "sha256:a720477885a9d2411f94a93d16f9d89bad0f28ca23c3f8daa521e2dcc3f44d49", size = 24856543, upload-time = "2026-02-23T00:20:45.313Z" },
1393
1395
  ]
1394
1396
 
1397
+ [[package]]
1398
+ name = "sgp4"
1399
+ version = "2.27"
1400
+ source = { registry = "https://pypi.org/simple" }
1401
+ sdist = { url = "https://files.pythonhosted.org/packages/a8/62/e1282ea86299c76159e182cd36046e6d7980b120fef14c101757e1f650b3/sgp4-2.27.tar.gz", hash = "sha256:06d37247c6985739b707b8b39b6b83e06e8af783b2531e31965501ba983985f9", size = 180401, upload-time = "2026-07-03T12:54:49.443Z" }
1402
+ wheels = [
1403
+ { url = "https://files.pythonhosted.org/packages/c1/06/01c556ab39ef9c161b44d171fbb0990f59d5079d77959409c1f97685d269/sgp4-2.27-cp311-abi3-macosx_10_9_x86_64.whl", hash = "sha256:5ae1394cf0d91f54418530b02a797b14c10bb28e3f4ab616cad79a3fd67e2399", size = 148927, upload-time = "2026-07-03T12:54:41.296Z" },
1404
+ { url = "https://files.pythonhosted.org/packages/36/d9/05fd166d8f74b326590e78bb13148d6b359ae32be5cd39082fd8a292bf50/sgp4-2.27-cp311-abi3-macosx_11_0_arm64.whl", hash = "sha256:ee68f73cb2383bc950eada2ca1b10357b0165dbf5ab75185962009375bab8761", size = 147745, upload-time = "2026-07-03T12:54:42.31Z" },
1405
+ { url = "https://files.pythonhosted.org/packages/d6/75/633ad7874db149df164168090951e676cdc3541a12d43b2cbb9d20ecb721/sgp4-2.27-cp311-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:4d3775313120dcb6239535fa0c94cb6d5b089fd84bbfb15220923ae38dec7296", size = 218130, upload-time = "2026-07-03T12:54:43.296Z" },
1406
+ { url = "https://files.pythonhosted.org/packages/bc/bf/a279758ff3eb290cc5658f035845d3107d9728e1d2d52629c9683845313a/sgp4-2.27-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ef915c124cdd9807a4eae0abe655ade89076c2cee5df0392cad172aef456cd0e", size = 219370, upload-time = "2026-07-03T12:54:44.453Z" },
1407
+ { url = "https://files.pythonhosted.org/packages/30/84/8eebceb87dee7e7095d78375c473b57471c964d87b676c138e2da3e901bb/sgp4-2.27-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:26cfb6b8ace44e56b71cba79294da61af083b96c6b12f6229dc761c4d8c833eb", size = 215592, upload-time = "2026-07-03T12:54:45.493Z" },
1408
+ { url = "https://files.pythonhosted.org/packages/f4/5d/e7f4a9035cc62e4d10e35f22477498458520cb32b20eed5b4a9e7854d15d/sgp4-2.27-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:63d30826ebd303e66f184b1e3feba30524d01a379e50baacd47732dd447d97ab", size = 214880, upload-time = "2026-07-03T12:54:46.563Z" },
1409
+ { url = "https://files.pythonhosted.org/packages/56/62/c14d2aaa36ff6e749189e3576c70f3ed21f3ba72fa69e924f20581e760c1/sgp4-2.27-cp311-abi3-win32.whl", hash = "sha256:951ec95ea7f0fe0b5307fc2cd9d28c8923048bcf376b11c6cd93739e15b4722d", size = 147271, upload-time = "2026-07-03T12:54:47.498Z" },
1410
+ { url = "https://files.pythonhosted.org/packages/d5/b5/6e76ddece37a130c1c4c33a0ca2ae381c7aad733ca8e3d9b451594711fc0/sgp4-2.27-cp311-abi3-win_amd64.whl", hash = "sha256:827c63feb60987ad177c2c80f3a927e721ead2f444d6560cd2a4337ca90d2490", size = 148879, upload-time = "2026-07-03T12:54:48.448Z" },
1411
+ { url = "https://files.pythonhosted.org/packages/78/cd/06dc91b31f2b919e788396c2cb5ad313d5ce0754321165343fd585c4be53/sgp4-2.27-py3-none-any.whl", hash = "sha256:5f3f5716649988b638fbe7fcda592830e0956f548ca273b93cfa5f75917b9087", size = 123299, upload-time = "2026-07-12T18:53:05.274Z" },
1412
+ ]
1413
+
1395
1414
  [[package]]
1396
1415
  name = "six"
1397
1416
  version = "1.17.0"
@@ -1424,6 +1443,21 @@ wheels = [
1424
1443
  { url = "https://files.pythonhosted.org/packages/dc/0e/57466c742cc4c64f77c44114c9eb463d329b80eed6285b93fa1fa694d0c1/tart-1.4.5-py3-none-any.whl", hash = "sha256:e76f15e773c5e3259ee2dab2a3bc30f3e16b327460f1d8015f2bc7f3174a294d", size = 1075774, upload-time = "2026-01-25T19:24:22.094Z" },
1425
1444
  ]
1426
1445
 
1446
+ [[package]]
1447
+ name = "tart-catalogue-client"
1448
+ version = "0.5.1"
1449
+ source = { registry = "https://pypi.org/simple" }
1450
+ dependencies = [
1451
+ { name = "astropy" },
1452
+ { name = "numpy" },
1453
+ { name = "requests" },
1454
+ { name = "sgp4" },
1455
+ ]
1456
+ sdist = { url = "https://files.pythonhosted.org/packages/f2/85/d8e695a3f154317de11049955dfe316719f56c8c5fa7ae9c9bdd68b1561c/tart_catalogue_client-0.5.1.tar.gz", hash = "sha256:6bcb85bd313c0b04dae079aa8c7dcca1f4655ba689c05e5e2757b298e8eddad8", size = 40752, upload-time = "2026-07-11T03:13:15.052Z" }
1457
+ wheels = [
1458
+ { url = "https://files.pythonhosted.org/packages/52/56/a064ffd85dbf7c2cd52032ca086bf28fc6943dfe9d7479170b2ad20cf914/tart_catalogue_client-0.5.1-py3-none-any.whl", hash = "sha256:cea788d041df5705035641f3cb53dba58daef1fc9a0bcfe708e52e5779fdd6db", size = 9676, upload-time = "2026-07-11T03:13:13.944Z" },
1459
+ ]
1460
+
1427
1461
  [[package]]
1428
1462
  name = "tart-tools"
1429
1463
  version = "1.4.5"
@@ -1442,7 +1476,7 @@ wheels = [
1442
1476
 
1443
1477
  [[package]]
1444
1478
  name = "tart2ms"
1445
- version = "0.8.1"
1479
+ version = "0.9.0"
1446
1480
  source = { registry = "https://pypi.org/simple" }
1447
1481
  dependencies = [
1448
1482
  { name = "astropy" },
@@ -1456,11 +1490,12 @@ dependencies = [
1456
1490
  { name = "requests" },
1457
1491
  { name = "scipy" },
1458
1492
  { name = "tart" },
1493
+ { name = "tart-catalogue-client" },
1459
1494
  { name = "tart-tools" },
1460
1495
  ]
1461
- sdist = { url = "https://files.pythonhosted.org/packages/ec/8f/8eca8444efddd787f19f815294a3f2f6c6ccae08f886af6e4fc6722a0ee8/tart2ms-0.8.1.tar.gz", hash = "sha256:b81222ffd1020b90841aea70e6f12387d491ed3f75fd2ea6f444e181faf1e60b", size = 6360049, upload-time = "2026-06-12T07:10:28.748Z" }
1496
+ sdist = { url = "https://files.pythonhosted.org/packages/9b/84/bc1027ab3d56862fb307ccb0e92686298d3ceecf9377aeebcb768a4e8248/tart2ms-0.9.0.tar.gz", hash = "sha256:1b070d0530ec9fdb874875791faedac6ead810862ffcb42ac5a778f8daf50139", size = 6367946, upload-time = "2026-07-11T03:52:23.927Z" }
1462
1497
  wheels = [
1463
- { url = "https://files.pythonhosted.org/packages/0c/5a/59d3ec56bcd20405df0273d07a26f299664556f8af61bcfc00e1a8965229/tart2ms-0.8.1-py3-none-any.whl", hash = "sha256:ecd605eb3c50db4e12c64ff066c812cc3d0b5309ee473ffbc010bb21b9867f1a", size = 6505995, upload-time = "2026-06-12T07:10:27.027Z" },
1498
+ { url = "https://files.pythonhosted.org/packages/ca/24/34718a2e94dd1040785d5d6fc3dc093259b78dc76764443a113fb1ffcc2c/tart2ms-0.9.0-py3-none-any.whl", hash = "sha256:3911cab32a631411eb3a235a650a114db6fb375a180c516a961ef5cf42ce450e", size = 6516693, upload-time = "2026-07-11T03:52:21.862Z" },
1464
1499
  ]
1465
1500
 
1466
1501
  [[package]]
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