axis 65__tar.gz → 66__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 (105) hide show
  1. {axis-65 → axis-66}/PKG-INFO +12 -12
  2. {axis-65 → axis-66}/axis/__main__.py +7 -4
  3. {axis-65 → axis-66}/axis/models/event.py +7 -2
  4. {axis-65 → axis-66}/axis/models/event_instance.py +1 -1
  5. {axis-65 → axis-66}/axis/rtsp.py +2 -4
  6. {axis-65 → axis-66}/axis.egg-info/PKG-INFO +12 -12
  7. {axis-65 → axis-66}/axis.egg-info/requires.txt +9 -9
  8. {axis-65 → axis-66}/pyproject.toml +15 -14
  9. {axis-65 → axis-66}/tests/test_rtsp.py +1 -1
  10. {axis-65 → axis-66}/LICENSE +0 -0
  11. {axis-65 → axis-66}/README.md +0 -0
  12. {axis-65 → axis-66}/axis/__init__.py +0 -0
  13. {axis-65 → axis-66}/axis/device.py +0 -0
  14. {axis-65 → axis-66}/axis/errors.py +0 -0
  15. {axis-65 → axis-66}/axis/interfaces/__init__.py +0 -0
  16. {axis-65 → axis-66}/axis/interfaces/api_discovery.py +0 -0
  17. {axis-65 → axis-66}/axis/interfaces/api_handler.py +0 -0
  18. {axis-65 → axis-66}/axis/interfaces/applications/__init__.py +0 -0
  19. {axis-65 → axis-66}/axis/interfaces/applications/application_handler.py +0 -0
  20. {axis-65 → axis-66}/axis/interfaces/applications/applications.py +0 -0
  21. {axis-65 → axis-66}/axis/interfaces/applications/fence_guard.py +0 -0
  22. {axis-65 → axis-66}/axis/interfaces/applications/loitering_guard.py +0 -0
  23. {axis-65 → axis-66}/axis/interfaces/applications/motion_guard.py +0 -0
  24. {axis-65 → axis-66}/axis/interfaces/applications/object_analytics.py +0 -0
  25. {axis-65 → axis-66}/axis/interfaces/applications/vmd4.py +0 -0
  26. {axis-65 → axis-66}/axis/interfaces/basic_device_info.py +0 -0
  27. {axis-65 → axis-66}/axis/interfaces/event_instances.py +0 -0
  28. {axis-65 → axis-66}/axis/interfaces/event_manager.py +0 -0
  29. {axis-65 → axis-66}/axis/interfaces/light_control.py +0 -0
  30. {axis-65 → axis-66}/axis/interfaces/mqtt.py +0 -0
  31. {axis-65 → axis-66}/axis/interfaces/parameters/__init__.py +0 -0
  32. {axis-65 → axis-66}/axis/interfaces/parameters/brand.py +0 -0
  33. {axis-65 → axis-66}/axis/interfaces/parameters/image.py +0 -0
  34. {axis-65 → axis-66}/axis/interfaces/parameters/io_port.py +0 -0
  35. {axis-65 → axis-66}/axis/interfaces/parameters/param_cgi.py +0 -0
  36. {axis-65 → axis-66}/axis/interfaces/parameters/param_handler.py +0 -0
  37. {axis-65 → axis-66}/axis/interfaces/parameters/properties.py +0 -0
  38. {axis-65 → axis-66}/axis/interfaces/parameters/ptz.py +0 -0
  39. {axis-65 → axis-66}/axis/interfaces/parameters/stream_profile.py +0 -0
  40. {axis-65 → axis-66}/axis/interfaces/pir_sensor_configuration.py +0 -0
  41. {axis-65 → axis-66}/axis/interfaces/port_cgi.py +0 -0
  42. {axis-65 → axis-66}/axis/interfaces/port_management.py +0 -0
  43. {axis-65 → axis-66}/axis/interfaces/ptz.py +0 -0
  44. {axis-65 → axis-66}/axis/interfaces/pwdgrp_cgi.py +0 -0
  45. {axis-65 → axis-66}/axis/interfaces/stream_profiles.py +0 -0
  46. {axis-65 → axis-66}/axis/interfaces/user_groups.py +0 -0
  47. {axis-65 → axis-66}/axis/interfaces/vapix.py +0 -0
  48. {axis-65 → axis-66}/axis/interfaces/view_areas.py +0 -0
  49. {axis-65 → axis-66}/axis/models/__init__.py +0 -0
  50. {axis-65 → axis-66}/axis/models/api.py +0 -0
  51. {axis-65 → axis-66}/axis/models/api_discovery.py +0 -0
  52. {axis-65 → axis-66}/axis/models/applications/__init__.py +0 -0
  53. {axis-65 → axis-66}/axis/models/applications/application.py +0 -0
  54. {axis-65 → axis-66}/axis/models/applications/fence_guard.py +0 -0
  55. {axis-65 → axis-66}/axis/models/applications/loitering_guard.py +0 -0
  56. {axis-65 → axis-66}/axis/models/applications/motion_guard.py +0 -0
  57. {axis-65 → axis-66}/axis/models/applications/object_analytics.py +0 -0
  58. {axis-65 → axis-66}/axis/models/applications/vmd4.py +0 -0
  59. {axis-65 → axis-66}/axis/models/basic_device_info.py +0 -0
  60. {axis-65 → axis-66}/axis/models/configuration.py +0 -0
  61. {axis-65 → axis-66}/axis/models/light_control.py +0 -0
  62. {axis-65 → axis-66}/axis/models/mqtt.py +0 -0
  63. {axis-65 → axis-66}/axis/models/parameters/__init__.py +0 -0
  64. {axis-65 → axis-66}/axis/models/parameters/brand.py +0 -0
  65. {axis-65 → axis-66}/axis/models/parameters/image.py +0 -0
  66. {axis-65 → axis-66}/axis/models/parameters/io_port.py +0 -0
  67. {axis-65 → axis-66}/axis/models/parameters/param_cgi.py +0 -0
  68. {axis-65 → axis-66}/axis/models/parameters/properties.py +0 -0
  69. {axis-65 → axis-66}/axis/models/parameters/ptz.py +0 -0
  70. {axis-65 → axis-66}/axis/models/parameters/stream_profile.py +0 -0
  71. {axis-65 → axis-66}/axis/models/pir_sensor_configuration.py +0 -0
  72. {axis-65 → axis-66}/axis/models/port_cgi.py +0 -0
  73. {axis-65 → axis-66}/axis/models/port_management.py +0 -0
  74. {axis-65 → axis-66}/axis/models/ptz_cgi.py +0 -0
  75. {axis-65 → axis-66}/axis/models/pwdgrp_cgi.py +0 -0
  76. {axis-65 → axis-66}/axis/models/stream_profile.py +0 -0
  77. {axis-65 → axis-66}/axis/models/user_group.py +0 -0
  78. {axis-65 → axis-66}/axis/models/view_area.py +0 -0
  79. {axis-65 → axis-66}/axis/py.typed +0 -0
  80. {axis-65 → axis-66}/axis/stream_manager.py +0 -0
  81. {axis-65 → axis-66}/axis.egg-info/SOURCES.txt +0 -0
  82. {axis-65 → axis-66}/axis.egg-info/dependency_links.txt +0 -0
  83. {axis-65 → axis-66}/axis.egg-info/entry_points.txt +0 -0
  84. {axis-65 → axis-66}/axis.egg-info/top_level.txt +0 -0
  85. {axis-65 → axis-66}/setup.cfg +0 -0
  86. {axis-65 → axis-66}/tests/test_api_discovery.py +0 -0
  87. {axis-65 → axis-66}/tests/test_api_handler.py +0 -0
  88. {axis-65 → axis-66}/tests/test_basic_device_info.py +0 -0
  89. {axis-65 → axis-66}/tests/test_configuration.py +0 -0
  90. {axis-65 → axis-66}/tests/test_device.py +0 -0
  91. {axis-65 → axis-66}/tests/test_event.py +0 -0
  92. {axis-65 → axis-66}/tests/test_event_instances.py +0 -0
  93. {axis-65 → axis-66}/tests/test_event_stream.py +0 -0
  94. {axis-65 → axis-66}/tests/test_light_control.py +0 -0
  95. {axis-65 → axis-66}/tests/test_mqtt.py +0 -0
  96. {axis-65 → axis-66}/tests/test_pir_sensor_configuration.py +0 -0
  97. {axis-65 → axis-66}/tests/test_port_cgi.py +0 -0
  98. {axis-65 → axis-66}/tests/test_port_management.py +0 -0
  99. {axis-65 → axis-66}/tests/test_ptz.py +0 -0
  100. {axis-65 → axis-66}/tests/test_pwdgrp_cgi.py +0 -0
  101. {axis-65 → axis-66}/tests/test_stream_manager.py +0 -0
  102. {axis-65 → axis-66}/tests/test_stream_profiles.py +0 -0
  103. {axis-65 → axis-66}/tests/test_user_groups.py +0 -0
  104. {axis-65 → axis-66}/tests/test_vapix.py +0 -0
  105. {axis-65 → axis-66}/tests/test_view_areas.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: axis
3
- Version: 65
3
+ Version: 66
4
4
  Summary: A Python library for communicating with devices from Axis Communications
5
5
  Author-email: Robert Svensson <Kane610@users.noreply.github.com>
6
6
  License: MIT
@@ -12,9 +12,9 @@ Classifier: Development Status :: 5 - Production/Stable
12
12
  Classifier: Intended Audience :: Developers
13
13
  Classifier: License :: OSI Approved :: MIT License
14
14
  Classifier: Operating System :: OS Independent
15
- Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Programming Language :: Python :: 3.13
16
16
  Classifier: Topic :: Home Automation
17
- Requires-Python: >=3.12.0
17
+ Requires-Python: >=3.13.0
18
18
  Description-Content-Type: text/markdown
19
19
  License-File: LICENSE
20
20
  Requires-Dist: faust-cchardet>=2.1.18
@@ -24,20 +24,20 @@ Requires-Dist: packaging>23
24
24
  Requires-Dist: xmltodict>=0.13.0
25
25
  Provides-Extra: requirements
26
26
  Requires-Dist: httpx==0.28.1; extra == "requirements"
27
- Requires-Dist: orjson==3.11.1; extra == "requirements"
27
+ Requires-Dist: orjson==3.11.5; extra == "requirements"
28
28
  Requires-Dist: packaging==25.0; extra == "requirements"
29
- Requires-Dist: xmltodict==0.14.2; extra == "requirements"
29
+ Requires-Dist: xmltodict==1.0.2; extra == "requirements"
30
30
  Provides-Extra: requirements-test
31
- Requires-Dist: mypy==1.17.1; extra == "requirements-test"
32
- Requires-Dist: pytest==8.4.1; extra == "requirements-test"
31
+ Requires-Dist: mypy==1.19.1; extra == "requirements-test"
32
+ Requires-Dist: pytest==9.0.2; extra == "requirements-test"
33
33
  Requires-Dist: pytest-aiohttp==1.1.0; extra == "requirements-test"
34
- Requires-Dist: pytest-asyncio==0.26.0; extra == "requirements-test"
35
- Requires-Dist: pytest-cov==6.2.1; extra == "requirements-test"
34
+ Requires-Dist: pytest-asyncio==1.3.0; extra == "requirements-test"
35
+ Requires-Dist: pytest-cov==7.0.0; extra == "requirements-test"
36
36
  Requires-Dist: respx==0.22.0; extra == "requirements-test"
37
- Requires-Dist: ruff==0.11.11; extra == "requirements-test"
38
- Requires-Dist: types-xmltodict==v0.14.0.20241009; extra == "requirements-test"
37
+ Requires-Dist: ruff==0.14.10; extra == "requirements-test"
38
+ Requires-Dist: types-xmltodict==v1.0.1.20250920; extra == "requirements-test"
39
39
  Provides-Extra: requirements-dev
40
- Requires-Dist: pre-commit==4.2.0; extra == "requirements-dev"
40
+ Requires-Dist: pre-commit==4.5.1; extra == "requirements-dev"
41
41
  Dynamic: license-file
42
42
 
43
43
  Python project to set up a connection towards Axis Communications devices and to subscribe to specific events on the metadatastream.
@@ -7,22 +7,25 @@ import logging
7
7
  from httpx import AsyncClient
8
8
 
9
9
  import axis
10
+ from axis.device import AxisDevice
11
+ from axis.models.configuration import Configuration
12
+ from axis.models.event import Event
10
13
 
11
14
  LOGGER = logging.getLogger(__name__)
12
15
 
13
16
 
14
- def event_handler(event: axis.models.event.Event) -> None:
17
+ def event_handler(event: Event) -> None:
15
18
  """Receive and print events from RTSP stream."""
16
19
  LOGGER.info(event)
17
20
 
18
21
 
19
22
  async def axis_device(
20
23
  host: str, port: int, username: str, password: str, is_companion: bool = False
21
- ) -> axis.device.AxisDevice:
24
+ ) -> AxisDevice:
22
25
  """Create a Axis device."""
23
26
  session = AsyncClient(verify=False) # noqa: S501
24
- device = axis.device.AxisDevice(
25
- axis.models.configuration.Configuration(
27
+ device = AxisDevice(
28
+ Configuration(
26
29
  session,
27
30
  host,
28
31
  port=port,
@@ -195,10 +195,15 @@ class Event:
195
195
  data,
196
196
  # attr_prefix="",
197
197
  process_namespaces=True,
198
- namespaces=XML_NAMESPACES,
198
+ namespaces=XML_NAMESPACES, # type: ignore[arg-type]
199
199
  )
200
200
 
201
- if raw.get("MetadataStream") is None:
201
+ # Normalize the ONVIF metadata root: always use a dict, drop any stray
202
+ # XML namespace attribute ("@xmlns") added by xmltodict, and bail out
203
+ # early if the payload is empty.
204
+ stream = raw.get("MetadataStream") or {}
205
+ stream.pop("@xmlns", None)
206
+ if not stream:
202
207
  return cls._decode_from_dict({})
203
208
 
204
209
  topic = traverse(raw, TOPIC)
@@ -166,7 +166,7 @@ class ListEventInstancesResponse(ApiResponse[dict[str, Any]]):
166
166
  bytes_data,
167
167
  # attr_prefix="",
168
168
  dict_constructor=dict, # Use dict rather than ordered_dict
169
- namespaces=NAMESPACES, # Replace or remove defined namespaces
169
+ namespaces=NAMESPACES, # type: ignore[arg-type] # Replace or remove defined namespaces
170
170
  process_namespaces=True,
171
171
  )
172
172
  raw_events = traverse(data, EVENT_INSTANCE) # Move past the irrelevant keys
@@ -5,9 +5,11 @@
5
5
  # https://github.com/perexg/satip-axe/blob/master/tools/multicast-rtp
6
6
 
7
7
  import asyncio
8
+ from base64 import b64encode
8
9
  from collections import deque
9
10
  from collections.abc import Callable
10
11
  import enum
12
+ from hashlib import md5
11
13
  import logging
12
14
  import socket
13
15
  from typing import Any
@@ -372,8 +374,6 @@ class RTSPSession:
372
374
 
373
375
  def generate_digest(self) -> str:
374
376
  """RFC 2617."""
375
- from hashlib import md5
376
-
377
377
  _ha1 = f"{self.username}:{self.realm}:{self.password}"
378
378
  ha1 = md5(_ha1.encode("UTF-8")).hexdigest()
379
379
  _ha2 = f"{self.method}:{self.url}"
@@ -392,8 +392,6 @@ class RTSPSession:
392
392
 
393
393
  def generate_basic(self) -> str:
394
394
  """RFC 2617."""
395
- from base64 import b64encode
396
-
397
395
  if not self._basic_auth:
398
396
  creds = f"{self.username}:{self.password}"
399
397
  self._basic_auth = "Basic "
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: axis
3
- Version: 65
3
+ Version: 66
4
4
  Summary: A Python library for communicating with devices from Axis Communications
5
5
  Author-email: Robert Svensson <Kane610@users.noreply.github.com>
6
6
  License: MIT
@@ -12,9 +12,9 @@ Classifier: Development Status :: 5 - Production/Stable
12
12
  Classifier: Intended Audience :: Developers
13
13
  Classifier: License :: OSI Approved :: MIT License
14
14
  Classifier: Operating System :: OS Independent
15
- Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Programming Language :: Python :: 3.13
16
16
  Classifier: Topic :: Home Automation
17
- Requires-Python: >=3.12.0
17
+ Requires-Python: >=3.13.0
18
18
  Description-Content-Type: text/markdown
19
19
  License-File: LICENSE
20
20
  Requires-Dist: faust-cchardet>=2.1.18
@@ -24,20 +24,20 @@ Requires-Dist: packaging>23
24
24
  Requires-Dist: xmltodict>=0.13.0
25
25
  Provides-Extra: requirements
26
26
  Requires-Dist: httpx==0.28.1; extra == "requirements"
27
- Requires-Dist: orjson==3.11.1; extra == "requirements"
27
+ Requires-Dist: orjson==3.11.5; extra == "requirements"
28
28
  Requires-Dist: packaging==25.0; extra == "requirements"
29
- Requires-Dist: xmltodict==0.14.2; extra == "requirements"
29
+ Requires-Dist: xmltodict==1.0.2; extra == "requirements"
30
30
  Provides-Extra: requirements-test
31
- Requires-Dist: mypy==1.17.1; extra == "requirements-test"
32
- Requires-Dist: pytest==8.4.1; extra == "requirements-test"
31
+ Requires-Dist: mypy==1.19.1; extra == "requirements-test"
32
+ Requires-Dist: pytest==9.0.2; extra == "requirements-test"
33
33
  Requires-Dist: pytest-aiohttp==1.1.0; extra == "requirements-test"
34
- Requires-Dist: pytest-asyncio==0.26.0; extra == "requirements-test"
35
- Requires-Dist: pytest-cov==6.2.1; extra == "requirements-test"
34
+ Requires-Dist: pytest-asyncio==1.3.0; extra == "requirements-test"
35
+ Requires-Dist: pytest-cov==7.0.0; extra == "requirements-test"
36
36
  Requires-Dist: respx==0.22.0; extra == "requirements-test"
37
- Requires-Dist: ruff==0.11.11; extra == "requirements-test"
38
- Requires-Dist: types-xmltodict==v0.14.0.20241009; extra == "requirements-test"
37
+ Requires-Dist: ruff==0.14.10; extra == "requirements-test"
38
+ Requires-Dist: types-xmltodict==v1.0.1.20250920; extra == "requirements-test"
39
39
  Provides-Extra: requirements-dev
40
- Requires-Dist: pre-commit==4.2.0; extra == "requirements-dev"
40
+ Requires-Dist: pre-commit==4.5.1; extra == "requirements-dev"
41
41
  Dynamic: license-file
42
42
 
43
43
  Python project to set up a connection towards Axis Communications devices and to subscribe to specific events on the metadatastream.
@@ -6,19 +6,19 @@ xmltodict>=0.13.0
6
6
 
7
7
  [requirements]
8
8
  httpx==0.28.1
9
- orjson==3.11.1
9
+ orjson==3.11.5
10
10
  packaging==25.0
11
- xmltodict==0.14.2
11
+ xmltodict==1.0.2
12
12
 
13
13
  [requirements-dev]
14
- pre-commit==4.2.0
14
+ pre-commit==4.5.1
15
15
 
16
16
  [requirements-test]
17
- mypy==1.17.1
18
- pytest==8.4.1
17
+ mypy==1.19.1
18
+ pytest==9.0.2
19
19
  pytest-aiohttp==1.1.0
20
- pytest-asyncio==0.26.0
21
- pytest-cov==6.2.1
20
+ pytest-asyncio==1.3.0
21
+ pytest-cov==7.0.0
22
22
  respx==0.22.0
23
- ruff==0.11.11
24
- types-xmltodict==v0.14.0.20241009
23
+ ruff==0.14.10
24
+ types-xmltodict==v1.0.1.20250920
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "axis"
7
- version = "65"
7
+ version = "66"
8
8
  license = {text = "MIT"}
9
9
  description = "A Python library for communicating with devices from Axis Communications"
10
10
  readme = "README.md"
@@ -15,10 +15,10 @@ classifiers = [
15
15
  "Intended Audience :: Developers",
16
16
  "License :: OSI Approved :: MIT License",
17
17
  "Operating System :: OS Independent",
18
- "Programming Language :: Python :: 3.12",
18
+ "Programming Language :: Python :: 3.13",
19
19
  "Topic :: Home Automation",
20
20
  ]
21
- requires-python = ">=3.12.0"
21
+ requires-python = ">=3.13.0"
22
22
  dependencies = [
23
23
  "faust-cchardet>=2.1.18",
24
24
  "httpx>=0.26",
@@ -30,22 +30,22 @@ dependencies = [
30
30
  [project.optional-dependencies]
31
31
  requirements = [
32
32
  "httpx==0.28.1",
33
- "orjson==3.11.1",
33
+ "orjson==3.11.5",
34
34
  "packaging==25.0",
35
- "xmltodict==0.14.2",
35
+ "xmltodict==1.0.2",
36
36
  ]
37
37
  requirements-test = [
38
- "mypy==1.17.1",
39
- "pytest==8.4.1",
38
+ "mypy==1.19.1",
39
+ "pytest==9.0.2",
40
40
  "pytest-aiohttp==1.1.0",
41
- "pytest-asyncio==0.26.0",
42
- "pytest-cov==6.2.1",
41
+ "pytest-asyncio==1.3.0",
42
+ "pytest-cov==7.0.0",
43
43
  "respx==0.22.0",
44
- "ruff==0.11.11",
45
- "types-xmltodict==v0.14.0.20241009",
44
+ "ruff==0.14.10",
45
+ "types-xmltodict==v1.0.1.20250920",
46
46
  ]
47
47
  requirements-dev = [
48
- "pre-commit==4.2.0"
48
+ "pre-commit==4.5.1"
49
49
  ]
50
50
 
51
51
  [project.urls]
@@ -69,7 +69,7 @@ include = ["axis*"]
69
69
  "axis" = ["py.typed"]
70
70
 
71
71
  [tool.mypy]
72
- python_version = "3.12"
72
+ python_version = "3.13"
73
73
  check_untyped_defs = true
74
74
  disallow_any_generics = true
75
75
  disallow_incomplete_defs = true
@@ -94,7 +94,7 @@ log_cli_level = "DEBUG"
94
94
  testpaths = ["tests"]
95
95
 
96
96
  [tool.ruff]
97
- target-version = "py312"
97
+ target-version = "py313"
98
98
  lint.select = [
99
99
  # "A", # flake8-builtins
100
100
  "ANN", # flake8-annotations
@@ -160,6 +160,7 @@ lint.ignore = [
160
160
  "PLR0915", # Too many statements ({statements} > {max_statements})
161
161
  "PLR2004", # Magic value used in comparison, consider replacing {value} with a constant variable
162
162
  "S324", # Probable use of insecure hash functions in {library}: {string}
163
+ "UP046", # 82 | class APIHandler(SubscriptionHandler, Generic[ApiItemT]):
163
164
  ]
164
165
 
165
166
  [tool.ruff.lint.flake8-pytest-style]
@@ -674,7 +674,7 @@ def test_session_generate_digest_auth(rtsp_client):
674
674
  )
675
675
 
676
676
 
677
- def test_session_generate_basic_auth(event_loop, rtsp_client):
677
+ def test_session_generate_basic_auth(rtsp_client):
678
678
  """Verify generate basic auth method."""
679
679
  session = rtsp_client.session
680
680
  session.update('WWW-Authenticate: Basic realm="AXIS_ACCC8E012345"\r\n')
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