jamlib 3.1.0__tar.gz → 3.1.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.
Files changed (110) hide show
  1. {jamlib-3.1.0/src/jamlib.egg-info → jamlib-3.1.2}/PKG-INFO +2 -2
  2. {jamlib-3.1.0 → jamlib-3.1.2}/pyproject.toml +2 -2
  3. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/__base__.py +52 -6
  4. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/__init__.py +1 -1
  5. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/logger.py +8 -1
  6. jamlib-3.1.2/src/jam/plugins/__base__.py +58 -0
  7. jamlib-3.1.2/src/jam/plugins/__init__.py +10 -0
  8. jamlib-3.1.2/src/jam/utils/version_check.py +18 -0
  9. {jamlib-3.1.0 → jamlib-3.1.2/src/jamlib.egg-info}/PKG-INFO +2 -2
  10. {jamlib-3.1.0 → jamlib-3.1.2}/src/jamlib.egg-info/SOURCES.txt +3 -0
  11. {jamlib-3.1.0 → jamlib-3.1.2}/src/jamlib.egg-info/requires.txt +1 -1
  12. {jamlib-3.1.0 → jamlib-3.1.2}/LICENSE.md +0 -0
  13. {jamlib-3.1.0 → jamlib-3.1.2}/README.md +0 -0
  14. {jamlib-3.1.0 → jamlib-3.1.2}/setup.cfg +0 -0
  15. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/__base_encoder__.py +0 -0
  16. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/__deprecated__.py +0 -0
  17. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/aio/__base__.py +0 -0
  18. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/aio/__init__.py +0 -0
  19. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/aio/instance.py +0 -0
  20. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/aio/jwt/__init__.py +0 -0
  21. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/aio/oauth2/__base__.py +0 -0
  22. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/aio/oauth2/__init__.py +0 -0
  23. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/aio/oauth2/builtin/__init__.py +0 -0
  24. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/aio/oauth2/builtin/github.py +0 -0
  25. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/aio/oauth2/builtin/gitlab.py +0 -0
  26. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/aio/oauth2/builtin/google.py +0 -0
  27. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/aio/oauth2/builtin/yandex.py +0 -0
  28. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/aio/oauth2/client.py +0 -0
  29. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/aio/sessions/__base__.py +0 -0
  30. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/aio/sessions/__init__.py +0 -0
  31. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/aio/sessions/json.py +0 -0
  32. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/aio/sessions/redis.py +0 -0
  33. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/cli/__init__.py +0 -0
  34. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/cli/cli.py +0 -0
  35. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/cli/commands/__init__.py +0 -0
  36. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/cli/commands/keys.py +0 -0
  37. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/cli/commands/password.py +0 -0
  38. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/encoders.py +0 -0
  39. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/exceptions/__init__.py +0 -0
  40. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/exceptions/base.py +0 -0
  41. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/exceptions/jwt.py +0 -0
  42. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/exceptions/oauth2.py +0 -0
  43. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/exceptions/paseto.py +0 -0
  44. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/exceptions/plugins.py +0 -0
  45. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/exceptions/sessions.py +0 -0
  46. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/ext/__init__.py +0 -0
  47. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/ext/fastapi/__init__.py +0 -0
  48. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/ext/flask/__init__.py +0 -0
  49. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/ext/flask/extensions.py +0 -0
  50. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/ext/flask/objects.py +0 -0
  51. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/ext/litestar/__init__.py +0 -0
  52. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/ext/litestar/middleware.py +0 -0
  53. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/ext/litestar/objects.py +0 -0
  54. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/ext/litestar/plugins.py +0 -0
  55. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/ext/starlette/__init__.py +0 -0
  56. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/ext/starlette/backends.py +0 -0
  57. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/ext/starlette/objects.py +0 -0
  58. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/instance.py +0 -0
  59. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/jwt/__algorithms__.py +0 -0
  60. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/jwt/__base__.py +0 -0
  61. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/jwt/__init__.py +0 -0
  62. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/jwt/__types__.py +0 -0
  63. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/jwt/lists/__base__.py +0 -0
  64. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/jwt/lists/__init__.py +0 -0
  65. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/jwt/lists/json.py +0 -0
  66. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/jwt/lists/redis.py +0 -0
  67. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/jwt/module.py +0 -0
  68. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/jwt/utils.py +0 -0
  69. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/oauth2/__base__.py +0 -0
  70. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/oauth2/__init__.py +0 -0
  71. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/oauth2/builtin/__init__.py +0 -0
  72. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/oauth2/builtin/github.py +0 -0
  73. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/oauth2/builtin/gitlab.py +0 -0
  74. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/oauth2/builtin/google.py +0 -0
  75. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/oauth2/builtin/yandex.py +0 -0
  76. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/oauth2/client.py +0 -0
  77. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/otp/__base__.py +0 -0
  78. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/otp/__init__.py +0 -0
  79. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/otp/hotp.py +0 -0
  80. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/otp/totp.py +0 -0
  81. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/paseto/__base__.py +0 -0
  82. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/paseto/__init__.py +0 -0
  83. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/paseto/utils.py +0 -0
  84. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/paseto/v1.py +0 -0
  85. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/paseto/v2.py +0 -0
  86. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/paseto/v3.py +0 -0
  87. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/paseto/v4.py +0 -0
  88. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/py.typed +0 -0
  89. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/sessions/__base__.py +0 -0
  90. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/sessions/__init__.py +0 -0
  91. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/sessions/json.py +0 -0
  92. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/sessions/redis.py +0 -0
  93. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/tests/__init__.py +0 -0
  94. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/tests/clients.py +0 -0
  95. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/tests/fakers.py +0 -0
  96. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/utils/__init__.py +0 -0
  97. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/utils/aes.py +0 -0
  98. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/utils/await_maybe.py +0 -0
  99. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/utils/basic_auth.py +0 -0
  100. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/utils/config_maker.py +0 -0
  101. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/utils/ed.py +0 -0
  102. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/utils/otp_keys.py +0 -0
  103. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/utils/rsa.py +0 -0
  104. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/utils/salt_hash.py +0 -0
  105. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/utils/symmetric.py +0 -0
  106. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/utils/xchacha20poly1305.py +0 -0
  107. {jamlib-3.1.0 → jamlib-3.1.2}/src/jam/utils/xor.py +0 -0
  108. {jamlib-3.1.0 → jamlib-3.1.2}/src/jamlib.egg-info/dependency_links.txt +0 -0
  109. {jamlib-3.1.0 → jamlib-3.1.2}/src/jamlib.egg-info/entry_points.txt +0 -0
  110. {jamlib-3.1.0 → jamlib-3.1.2}/src/jamlib.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: jamlib
3
- Version: 3.1.0
3
+ Version: 3.1.2
4
4
  Summary: Simple and universal library for authorization.
5
5
  Author-email: Makridenko Adrian <adrianmakridenko@duck.com>, Ksenia Travnikova <kseniatravnikova@duck.com>
6
6
  License: Apache-2.0
@@ -30,7 +30,7 @@ Classifier: Framework :: FastAPI
30
30
  Requires-Python: >=3.10
31
31
  Description-Content-Type: text/markdown
32
32
  License-File: LICENSE.md
33
- Requires-Dist: cryptography>=46.0.5
33
+ Requires-Dist: cryptography>=48.0.0
34
34
  Provides-Extra: cli
35
35
  Requires-Dist: click>=8.3.1; extra == "cli"
36
36
  Provides-Extra: redis
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "jamlib"
3
- version = "3.1.0"
3
+ version = "3.1.2"
4
4
  description = "Simple and universal library for authorization."
5
5
  authors = [
6
6
  {name = "Makridenko Adrian",email = "adrianmakridenko@duck.com"},
@@ -23,7 +23,7 @@ keywords = [
23
23
  ]
24
24
  requires-python = ">=3.10"
25
25
  dependencies = [
26
- "cryptography>=46.0.5",
26
+ "cryptography>=48.0.0",
27
27
  ]
28
28
 
29
29
  classifiers = [
@@ -1,16 +1,21 @@
1
1
  # -*- coding: utf-8 -*-
2
2
 
3
+ from __future__ import annotations
4
+
3
5
  from abc import ABC, abstractmethod
4
6
  import gc
7
+ import os
5
8
  from typing import Any, Literal
6
9
 
7
- from jam.encoders import BaseEncoder, JsonEncoder
10
+ from jam.__base_encoder__ import BaseEncoder
11
+ from jam.encoders import JsonEncoder
8
12
  from jam.exceptions import JamConfigurationError
9
13
  from jam.jwt.__base__ import BaseJWT
10
14
  from jam.logger import BaseLogger, JamLogger
11
15
  from jam.oauth2.__base__ import BaseOAuth2Client
12
16
  from jam.otp.__base__ import BaseOTP, OTPConfig
13
17
  from jam.paseto.__base__ import BasePASETO
18
+ from jam.plugins.__base__ import BasePlugin
14
19
  from jam.sessions.__base__ import BaseSessionModule
15
20
  from jam.utils.config_maker import __config_maker__, __module_loader__
16
21
 
@@ -30,15 +35,17 @@ class BaseJam(ABC):
30
35
  "DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"
31
36
  ] = "INFO",
32
37
  serializer: BaseEncoder | type[BaseEncoder] = JsonEncoder,
38
+ plugins: list[type[BasePlugin]] = [],
33
39
  ) -> None:
34
40
  """Initialize instance.
35
41
 
36
42
  Args:
37
- config (Union[str, dict[str, Any]]): Configuration
38
- pointer (str): Pointer
39
- logger (BaseLogger): Logger
40
- log_level (Literal["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"]): Log level
41
- serializer (Union[BaseEncoder, type[BaseBrowser]]): Serializer
43
+ config (Union[str, dict[str, Any]]): Configuration
44
+ pointer (str): Pointer
45
+ logger (BaseLogger): Logger
46
+ log_level (Literal["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"]): Log level
47
+ serializer (Union[BaseEncoder, type[BaseBrowser]]): Serializer
48
+ plugins (list[type[BasePlugin]]): List of plugins
42
49
 
43
50
  Returns:
44
51
  None
@@ -54,6 +61,8 @@ class BaseJam(ABC):
54
61
 
55
62
  self._logger = logger(log_level)
56
63
  self._serializer = serializer
64
+ self._plugins = []
65
+
57
66
  self.jwt: BaseJWT | None = None
58
67
  self.session: BaseSessionModule | None = None
59
68
  self.oauth2: dict[str, BaseOAuth2Client] | None = None
@@ -71,6 +80,9 @@ class BaseJam(ABC):
71
80
  "BaseJam initialization complete. Modules loaded:\n"
72
81
  f" jwt={self.jwt is not None}, session={self.session is not None}, oauth2={self.oauth2 is not None}"
73
82
  )
83
+ if os.getenv("JAM_ENABLE_PLUGINS", "0") == "1":
84
+ self._logger.warning("Experimental plugins are enabled!")
85
+ self.__setup_plugins(plugins)
74
86
  gc.collect()
75
87
 
76
88
  def __build_main_config(
@@ -188,6 +200,40 @@ class BaseJam(ABC):
188
200
  case _:
189
201
  raise JamConfigurationError(message="Unknown OTP type.")
190
202
 
203
+ def __setup_plugins(self, plugins: list[type[BasePlugin]]) -> None:
204
+ """Setup plugins."""
205
+ for plugin in plugins:
206
+ self._logger.debug(f"Setup plugin: {plugin.name}")
207
+ from jam.utils.version_check import __is_compatible__
208
+
209
+ if not __is_compatible__(None, plugin.jam_requires):
210
+ continue
211
+
212
+ _plugin = plugin(self)
213
+ _plugin.setup()
214
+ self._plugins.append(_plugin)
215
+
216
+ def emit(self, event: str, **kwargs) -> Any:
217
+ """Emit event.
218
+
219
+ Args:
220
+ event (str): Event name,
221
+ **kwargs: Event data
222
+ """
223
+ for plugin in self._plugins:
224
+ handler = getattr(plugin, f"on_{event}", None)
225
+
226
+ if handler:
227
+ try:
228
+ result = handler(**kwargs)
229
+ if isinstance(result, dict):
230
+ kwargs.update(result)
231
+
232
+ except Exception as e:
233
+ self._logger.error(f"Plugin:{plugin.name} | error: {e}")
234
+
235
+ return kwargs
236
+
191
237
  @abstractmethod
192
238
  def jwt_make_payload(
193
239
  self, exp: int | None, data: dict[str, Any]
@@ -12,5 +12,5 @@ from jam.encoders import JsonEncoder
12
12
  from jam.instance import Jam
13
13
 
14
14
 
15
- __version__ = "3.0.0"
15
+ __version__ = "3.1.2"
16
16
  __all__ = ["Jam", "JsonEncoder", "BaseJam", "BaseEncoder"]
@@ -10,7 +10,14 @@ class BaseLogger(ABC):
10
10
  """Interface for logging."""
11
11
 
12
12
  _LOG_NAME: str = "jam"
13
- log_level: Literal["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"] = "INFO"
13
+
14
+ def __init__(
15
+ self,
16
+ log_level: Literal["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"]
17
+ | str = "INFO",
18
+ ):
19
+ """Initialize the logger."""
20
+ self.log_level = log_level
14
21
 
15
22
  @abstractmethod
16
23
  def info(self, message: str) -> None:
@@ -0,0 +1,58 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ from abc import ABC
4
+
5
+
6
+ class BasePlugin(ABC):
7
+ """Base plugin for Jam.
8
+
9
+ !!! Warning
10
+ Plugins are experimental and may not be stable.
11
+
12
+ For usage, JAM_ENABLE_PLUGINS must be set to 1.
13
+
14
+ Example:
15
+ ```python
16
+ from jam import Jam
17
+ from jam.plugins import BasePlugin
18
+
19
+
20
+ class MyPlugin(BasePlugin)
21
+ name = "MyPlugin"
22
+
23
+ def on_before_jwt_create(self, **kwargs):
24
+ print("JWT CREATED")
25
+
26
+ jam = Jam(
27
+ config="config.toml",
28
+ plugins=[MyPlugin]
29
+ )
30
+ ```
31
+ """
32
+
33
+ name: str = "base_plugin"
34
+ jam_requires: str = "3.2.0"
35
+ config: bool = False
36
+
37
+ def __init__(self, jam, config: dict | None = None) -> None:
38
+ """Initialize the plugin.
39
+
40
+ Args:
41
+ jam (BaseJam): The Jam instance.
42
+ config (dict | None): Plugin configuration.
43
+ """
44
+ self._jam = jam
45
+ self._config = config or {}
46
+
47
+ def setup(self) -> None:
48
+ """Called when plugin is initialized."""
49
+ pass
50
+
51
+ def emit(self, event: str, **kwargs) -> None:
52
+ """Emit event.
53
+
54
+ Args:
55
+ event (str): Event name
56
+ **kwargs: Event data
57
+ """
58
+ self._jam.emit(event, **kwargs)
@@ -0,0 +1,10 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ """Jam plugin system."""
4
+
5
+ from .__base__ import BasePlugin
6
+
7
+
8
+ __all__ = [
9
+ "BasePlugin",
10
+ ]
@@ -0,0 +1,18 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ from importlib.metadata import version
4
+
5
+ from packaging.version import Version
6
+
7
+
8
+ def __is_compatible__(
9
+ income_version: str | None, required_version: str
10
+ ) -> bool:
11
+ """Checks if the income version is compatible with the required version."""
12
+ current = Version(income_version or version("jamlib"))
13
+ required = Version(required_version)
14
+
15
+ if current.major != required.major:
16
+ return False
17
+
18
+ return current >= required
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: jamlib
3
- Version: 3.1.0
3
+ Version: 3.1.2
4
4
  Summary: Simple and universal library for authorization.
5
5
  Author-email: Makridenko Adrian <adrianmakridenko@duck.com>, Ksenia Travnikova <kseniatravnikova@duck.com>
6
6
  License: Apache-2.0
@@ -30,7 +30,7 @@ Classifier: Framework :: FastAPI
30
30
  Requires-Python: >=3.10
31
31
  Description-Content-Type: text/markdown
32
32
  License-File: LICENSE.md
33
- Requires-Dist: cryptography>=46.0.5
33
+ Requires-Dist: cryptography>=48.0.0
34
34
  Provides-Extra: cli
35
35
  Requires-Dist: click>=8.3.1; extra == "cli"
36
36
  Provides-Extra: redis
@@ -78,6 +78,8 @@ src/jam/paseto/v1.py
78
78
  src/jam/paseto/v2.py
79
79
  src/jam/paseto/v3.py
80
80
  src/jam/paseto/v4.py
81
+ src/jam/plugins/__base__.py
82
+ src/jam/plugins/__init__.py
81
83
  src/jam/sessions/__base__.py
82
84
  src/jam/sessions/__init__.py
83
85
  src/jam/sessions/json.py
@@ -95,6 +97,7 @@ src/jam/utils/otp_keys.py
95
97
  src/jam/utils/rsa.py
96
98
  src/jam/utils/salt_hash.py
97
99
  src/jam/utils/symmetric.py
100
+ src/jam/utils/version_check.py
98
101
  src/jam/utils/xchacha20poly1305.py
99
102
  src/jam/utils/xor.py
100
103
  src/jamlib.egg-info/PKG-INFO
@@ -1,4 +1,4 @@
1
- cryptography>=46.0.5
1
+ cryptography>=48.0.0
2
2
 
3
3
  [cli]
4
4
  click>=8.3.1
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