mrok 0.4.3__tar.gz → 0.4.5__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 (155) hide show
  1. {mrok-0.4.3 → mrok-0.4.5}/PKG-INFO +1 -1
  2. {mrok-0.4.3 → mrok-0.4.5}/mrok/proxy/app.py +14 -6
  3. {mrok-0.4.3 → mrok-0.4.5}/pyproject.toml +1 -1
  4. mrok-0.4.3/mrok/proxy/ziti.py +0 -103
  5. {mrok-0.4.3 → mrok-0.4.5}/.github/actions/setup-python-env/action.yml +0 -0
  6. {mrok-0.4.3 → mrok-0.4.5}/.github/workflows/assets/turing_team_pr_bot.png +0 -0
  7. {mrok-0.4.3 → mrok-0.4.5}/.github/workflows/notify-pr-closed.yaml +0 -0
  8. {mrok-0.4.3 → mrok-0.4.5}/.github/workflows/notify-pr-reviewed.yml +0 -0
  9. {mrok-0.4.3 → mrok-0.4.5}/.github/workflows/pr-build-merge.yaml +0 -0
  10. {mrok-0.4.3 → mrok-0.4.5}/.github/workflows/release.yml +0 -0
  11. {mrok-0.4.3 → mrok-0.4.5}/.gitignore +0 -0
  12. {mrok-0.4.3 → mrok-0.4.5}/.pre-commit-config.yaml +0 -0
  13. {mrok-0.4.3 → mrok-0.4.5}/.python-version +0 -0
  14. {mrok-0.4.3 → mrok-0.4.5}/LICENSE.txt +0 -0
  15. {mrok-0.4.3 → mrok-0.4.5}/README.md +0 -0
  16. {mrok-0.4.3 → mrok-0.4.5}/dev.Dockerfile +0 -0
  17. {mrok-0.4.3 → mrok-0.4.5}/docker-compose.yaml +0 -0
  18. {mrok-0.4.3 → mrok-0.4.5}/entrypoint.sh +0 -0
  19. {mrok-0.4.3 → mrok-0.4.5}/mrok/__init__.py +0 -0
  20. {mrok-0.4.3 → mrok-0.4.5}/mrok/agent/__init__.py +0 -0
  21. {mrok-0.4.3 → mrok-0.4.5}/mrok/agent/devtools/__init__.py +0 -0
  22. {mrok-0.4.3 → mrok-0.4.5}/mrok/agent/devtools/__main__.py +0 -0
  23. {mrok-0.4.3 → mrok-0.4.5}/mrok/agent/devtools/inspector/__init__.py +0 -0
  24. {mrok-0.4.3 → mrok-0.4.5}/mrok/agent/devtools/inspector/__main__.py +0 -0
  25. {mrok-0.4.3 → mrok-0.4.5}/mrok/agent/devtools/inspector/app.py +0 -0
  26. {mrok-0.4.3 → mrok-0.4.5}/mrok/agent/devtools/inspector/server.py +0 -0
  27. {mrok-0.4.3 → mrok-0.4.5}/mrok/agent/sidecar/__init__.py +0 -0
  28. {mrok-0.4.3 → mrok-0.4.5}/mrok/agent/sidecar/app.py +0 -0
  29. {mrok-0.4.3 → mrok-0.4.5}/mrok/agent/sidecar/main.py +0 -0
  30. {mrok-0.4.3 → mrok-0.4.5}/mrok/agent/ziticorn.py +0 -0
  31. {mrok-0.4.3 → mrok-0.4.5}/mrok/cli/__init__.py +0 -0
  32. {mrok-0.4.3 → mrok-0.4.5}/mrok/cli/commands/__init__.py +0 -0
  33. {mrok-0.4.3 → mrok-0.4.5}/mrok/cli/commands/admin/__init__.py +0 -0
  34. {mrok-0.4.3 → mrok-0.4.5}/mrok/cli/commands/admin/bootstrap.py +0 -0
  35. {mrok-0.4.3 → mrok-0.4.5}/mrok/cli/commands/admin/list/__init__.py +0 -0
  36. {mrok-0.4.3 → mrok-0.4.5}/mrok/cli/commands/admin/list/extensions.py +0 -0
  37. {mrok-0.4.3 → mrok-0.4.5}/mrok/cli/commands/admin/list/instances.py +0 -0
  38. {mrok-0.4.3 → mrok-0.4.5}/mrok/cli/commands/admin/register/__init__.py +0 -0
  39. {mrok-0.4.3 → mrok-0.4.5}/mrok/cli/commands/admin/register/extensions.py +0 -0
  40. {mrok-0.4.3 → mrok-0.4.5}/mrok/cli/commands/admin/register/instances.py +0 -0
  41. {mrok-0.4.3 → mrok-0.4.5}/mrok/cli/commands/admin/unregister/__init__.py +0 -0
  42. {mrok-0.4.3 → mrok-0.4.5}/mrok/cli/commands/admin/unregister/extensions.py +0 -0
  43. {mrok-0.4.3 → mrok-0.4.5}/mrok/cli/commands/admin/unregister/instances.py +0 -0
  44. {mrok-0.4.3 → mrok-0.4.5}/mrok/cli/commands/admin/utils.py +0 -0
  45. {mrok-0.4.3 → mrok-0.4.5}/mrok/cli/commands/agent/__init__.py +0 -0
  46. {mrok-0.4.3 → mrok-0.4.5}/mrok/cli/commands/agent/dev/__init__.py +0 -0
  47. {mrok-0.4.3 → mrok-0.4.5}/mrok/cli/commands/agent/dev/console.py +0 -0
  48. {mrok-0.4.3 → mrok-0.4.5}/mrok/cli/commands/agent/dev/web.py +0 -0
  49. {mrok-0.4.3 → mrok-0.4.5}/mrok/cli/commands/agent/run/__init__.py +0 -0
  50. {mrok-0.4.3 → mrok-0.4.5}/mrok/cli/commands/agent/run/asgi.py +0 -0
  51. {mrok-0.4.3 → mrok-0.4.5}/mrok/cli/commands/agent/run/sidecar.py +0 -0
  52. {mrok-0.4.3 → mrok-0.4.5}/mrok/cli/commands/agent/utils.py +0 -0
  53. {mrok-0.4.3 → mrok-0.4.5}/mrok/cli/commands/controller/__init__.py +0 -0
  54. {mrok-0.4.3 → mrok-0.4.5}/mrok/cli/commands/controller/openapi.py +0 -0
  55. {mrok-0.4.3 → mrok-0.4.5}/mrok/cli/commands/controller/run.py +0 -0
  56. {mrok-0.4.3 → mrok-0.4.5}/mrok/cli/commands/proxy/__init__.py +0 -0
  57. {mrok-0.4.3 → mrok-0.4.5}/mrok/cli/commands/proxy/run.py +0 -0
  58. {mrok-0.4.3 → mrok-0.4.5}/mrok/cli/main.py +0 -0
  59. {mrok-0.4.3 → mrok-0.4.5}/mrok/cli/rich.py +0 -0
  60. {mrok-0.4.3 → mrok-0.4.5}/mrok/cli/utils.py +0 -0
  61. {mrok-0.4.3 → mrok-0.4.5}/mrok/conf.py +0 -0
  62. {mrok-0.4.3 → mrok-0.4.5}/mrok/controller/__init__.py +0 -0
  63. {mrok-0.4.3 → mrok-0.4.5}/mrok/controller/app.py +0 -0
  64. {mrok-0.4.3 → mrok-0.4.5}/mrok/controller/auth.py +0 -0
  65. {mrok-0.4.3 → mrok-0.4.5}/mrok/controller/dependencies/__init__.py +0 -0
  66. {mrok-0.4.3 → mrok-0.4.5}/mrok/controller/dependencies/conf.py +0 -0
  67. {mrok-0.4.3 → mrok-0.4.5}/mrok/controller/dependencies/ziti.py +0 -0
  68. {mrok-0.4.3 → mrok-0.4.5}/mrok/controller/openapi/__init__.py +0 -0
  69. {mrok-0.4.3 → mrok-0.4.5}/mrok/controller/openapi/examples.py +0 -0
  70. {mrok-0.4.3 → mrok-0.4.5}/mrok/controller/openapi/utils.py +0 -0
  71. {mrok-0.4.3 → mrok-0.4.5}/mrok/controller/pagination.py +0 -0
  72. {mrok-0.4.3 → mrok-0.4.5}/mrok/controller/routes/__init__.py +0 -0
  73. {mrok-0.4.3 → mrok-0.4.5}/mrok/controller/routes/extensions.py +0 -0
  74. {mrok-0.4.3 → mrok-0.4.5}/mrok/controller/routes/instances.py +0 -0
  75. {mrok-0.4.3 → mrok-0.4.5}/mrok/controller/schemas.py +0 -0
  76. {mrok-0.4.3 → mrok-0.4.5}/mrok/datastructures.py +0 -0
  77. {mrok-0.4.3 → mrok-0.4.5}/mrok/errors.py +0 -0
  78. {mrok-0.4.3 → mrok-0.4.5}/mrok/http/__init__.py +0 -0
  79. {mrok-0.4.3 → mrok-0.4.5}/mrok/http/config.py +0 -0
  80. {mrok-0.4.3 → mrok-0.4.5}/mrok/http/constants.py +0 -0
  81. {mrok-0.4.3 → mrok-0.4.5}/mrok/http/forwarder.py +0 -0
  82. {mrok-0.4.3 → mrok-0.4.5}/mrok/http/lifespan.py +0 -0
  83. {mrok-0.4.3 → mrok-0.4.5}/mrok/http/middlewares.py +0 -0
  84. {mrok-0.4.3 → mrok-0.4.5}/mrok/http/protocol.py +0 -0
  85. {mrok-0.4.3 → mrok-0.4.5}/mrok/http/server.py +0 -0
  86. {mrok-0.4.3 → mrok-0.4.5}/mrok/http/types.py +0 -0
  87. {mrok-0.4.3 → mrok-0.4.5}/mrok/http/utils.py +0 -0
  88. {mrok-0.4.3 → mrok-0.4.5}/mrok/logging.py +0 -0
  89. {mrok-0.4.3 → mrok-0.4.5}/mrok/master.py +0 -0
  90. {mrok-0.4.3 → mrok-0.4.5}/mrok/metrics.py +0 -0
  91. {mrok-0.4.3 → mrok-0.4.5}/mrok/proxy/__init__.py +0 -0
  92. {mrok-0.4.3 → mrok-0.4.5}/mrok/proxy/main.py +0 -0
  93. {mrok-0.4.3 → mrok-0.4.5}/mrok/ziti/__init__.py +0 -0
  94. {mrok-0.4.3 → mrok-0.4.5}/mrok/ziti/api.py +0 -0
  95. {mrok-0.4.3 → mrok-0.4.5}/mrok/ziti/bootstrap.py +0 -0
  96. {mrok-0.4.3 → mrok-0.4.5}/mrok/ziti/constants.py +0 -0
  97. {mrok-0.4.3 → mrok-0.4.5}/mrok/ziti/errors.py +0 -0
  98. {mrok-0.4.3 → mrok-0.4.5}/mrok/ziti/identities.py +0 -0
  99. {mrok-0.4.3 → mrok-0.4.5}/mrok/ziti/pki.py +0 -0
  100. {mrok-0.4.3 → mrok-0.4.5}/mrok/ziti/services.py +0 -0
  101. {mrok-0.4.3 → mrok-0.4.5}/prod.Dockerfile +0 -0
  102. {mrok-0.4.3 → mrok-0.4.5}/scripts/ziti.sh +0 -0
  103. {mrok-0.4.3 → mrok-0.4.5}/settings.yaml +0 -0
  104. {mrok-0.4.3 → mrok-0.4.5}/snapshot_report.html +0 -0
  105. {mrok-0.4.3 → mrok-0.4.5}/sonar-project.properties +0 -0
  106. {mrok-0.4.3 → mrok-0.4.5}/tests/__init__.py +0 -0
  107. {mrok-0.4.3 → mrok-0.4.5}/tests/agent/__init__.py +0 -0
  108. {mrok-0.4.3 → mrok-0.4.5}/tests/agent/sidecar/__init__.py +0 -0
  109. {mrok-0.4.3 → mrok-0.4.5}/tests/agent/sidecar/__snapshots__/test_inspector/test_inspector_app.svg +0 -0
  110. {mrok-0.4.3 → mrok-0.4.5}/tests/agent/sidecar/__snapshots__/test_inspector/test_inspector_app_empty_card.svg +0 -0
  111. {mrok-0.4.3 → mrok-0.4.5}/tests/agent/sidecar/__snapshots__/test_inspector/test_inspector_app_filed_store_connection.svg +0 -0
  112. {mrok-0.4.3 → mrok-0.4.5}/tests/agent/sidecar/__snapshots__/test_inspector/test_inspector_app_open_card.svg +0 -0
  113. {mrok-0.4.3 → mrok-0.4.5}/tests/agent/sidecar/test_app.py +0 -0
  114. {mrok-0.4.3 → mrok-0.4.5}/tests/agent/sidecar/test_main.py +0 -0
  115. {mrok-0.4.3 → mrok-0.4.5}/tests/agent/test_ziticorn.py +0 -0
  116. {mrok-0.4.3 → mrok-0.4.5}/tests/cli/__init__.py +0 -0
  117. {mrok-0.4.3 → mrok-0.4.5}/tests/cli/admin/__init__.py +0 -0
  118. {mrok-0.4.3 → mrok-0.4.5}/tests/cli/admin/test_bootstrap.py +0 -0
  119. {mrok-0.4.3 → mrok-0.4.5}/tests/cli/admin/test_list.py +0 -0
  120. {mrok-0.4.3 → mrok-0.4.5}/tests/cli/admin/test_register.py +0 -0
  121. {mrok-0.4.3 → mrok-0.4.5}/tests/cli/admin/test_unregister.py +0 -0
  122. {mrok-0.4.3 → mrok-0.4.5}/tests/cli/admin/test_utils.py +0 -0
  123. {mrok-0.4.3 → mrok-0.4.5}/tests/cli/agent/__init__.py +0 -0
  124. {mrok-0.4.3 → mrok-0.4.5}/tests/cli/agent/test_run.py +0 -0
  125. {mrok-0.4.3 → mrok-0.4.5}/tests/cli/controller/__init__.py +0 -0
  126. {mrok-0.4.3 → mrok-0.4.5}/tests/cli/controller/test_openapi.py +0 -0
  127. {mrok-0.4.3 → mrok-0.4.5}/tests/cli/controller/test_run.py +0 -0
  128. {mrok-0.4.3 → mrok-0.4.5}/tests/cli/proxy/__init__.py +0 -0
  129. {mrok-0.4.3 → mrok-0.4.5}/tests/cli/proxy/test_run.py +0 -0
  130. {mrok-0.4.3 → mrok-0.4.5}/tests/cli/test_main.py +0 -0
  131. {mrok-0.4.3 → mrok-0.4.5}/tests/conftest.py +0 -0
  132. {mrok-0.4.3 → mrok-0.4.5}/tests/controller/__init__.py +0 -0
  133. {mrok-0.4.3 → mrok-0.4.5}/tests/controller/test_auth.py +0 -0
  134. {mrok-0.4.3 → mrok-0.4.5}/tests/controller/test_extensions.py +0 -0
  135. {mrok-0.4.3 → mrok-0.4.5}/tests/controller/test_instances.py +0 -0
  136. {mrok-0.4.3 → mrok-0.4.5}/tests/controller/test_openapi.py +0 -0
  137. {mrok-0.4.3 → mrok-0.4.5}/tests/http/__init__.py +0 -0
  138. {mrok-0.4.3 → mrok-0.4.5}/tests/http/test_config.py +0 -0
  139. {mrok-0.4.3 → mrok-0.4.5}/tests/http/test_forwarder.py +0 -0
  140. {mrok-0.4.3 → mrok-0.4.5}/tests/http/test_lifespan.py +0 -0
  141. {mrok-0.4.3 → mrok-0.4.5}/tests/http/test_master.py +0 -0
  142. {mrok-0.4.3 → mrok-0.4.5}/tests/http/test_protocol.py +0 -0
  143. {mrok-0.4.3 → mrok-0.4.5}/tests/http/test_server.py +0 -0
  144. {mrok-0.4.3 → mrok-0.4.5}/tests/proxy/__init__.py +0 -0
  145. {mrok-0.4.3 → mrok-0.4.5}/tests/proxy/test_app.py +0 -0
  146. {mrok-0.4.3 → mrok-0.4.5}/tests/proxy/test_ziti.py +0 -0
  147. {mrok-0.4.3 → mrok-0.4.5}/tests/proxy/test_ziti_branches.py +0 -0
  148. {mrok-0.4.3 → mrok-0.4.5}/tests/types.py +0 -0
  149. {mrok-0.4.3 → mrok-0.4.5}/tests/ziti/__init__.py +0 -0
  150. {mrok-0.4.3 → mrok-0.4.5}/tests/ziti/test_api.py +0 -0
  151. {mrok-0.4.3 → mrok-0.4.5}/tests/ziti/test_bootstrap.py +0 -0
  152. {mrok-0.4.3 → mrok-0.4.5}/tests/ziti/test_identities.py +0 -0
  153. {mrok-0.4.3 → mrok-0.4.5}/tests/ziti/test_pki.py +0 -0
  154. {mrok-0.4.3 → mrok-0.4.5}/tests/ziti/test_services.py +0 -0
  155. {mrok-0.4.3 → mrok-0.4.5}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mrok
3
- Version: 0.4.3
3
+ Version: 0.4.5
4
4
  Summary: MPT Extensions OpenZiti Orchestrator
5
5
  Author: SoftwareOne AG
6
6
  License: Apache License
@@ -2,11 +2,13 @@ import asyncio
2
2
  import logging
3
3
  from pathlib import Path
4
4
 
5
+ import openziti
6
+ from openziti.context import ZitiContext
7
+
5
8
  from mrok.conf import get_settings
6
9
  from mrok.http.forwarder import ForwardAppBase
7
10
  from mrok.http.types import Scope, StreamReader, StreamWriter
8
11
  from mrok.logging import setup_logging
9
- from mrok.proxy.ziti import ZitiSocketCache
10
12
 
11
13
  logger = logging.getLogger("mrok.proxy")
12
14
 
@@ -30,7 +32,7 @@ class ProxyApp(ForwardAppBase):
30
32
  if settings.proxy.domain[0] == "."
31
33
  else f".{settings.proxy.domain}"
32
34
  )
33
- self._ziti_socket_cache = ZitiSocketCache(self._identity_file)
35
+ self._ziti_ctx: ZitiContext | None = None
34
36
 
35
37
  def get_target_from_header(self, headers: dict[str, str], name: str) -> str | None:
36
38
  header_value = headers.get(name, "")
@@ -47,11 +49,17 @@ class ProxyApp(ForwardAppBase):
47
49
  raise ProxyError("Neither Host nor X-Forwarded-Host contain a valid target name")
48
50
  return target
49
51
 
52
+ def _get_ziti_ctx(self) -> ZitiContext:
53
+ if self._ziti_ctx is None:
54
+ ctx, err = openziti.load(str(self._identity_file), timeout=10_000)
55
+ if err != 0:
56
+ raise Exception(f"Cannot create a Ziti context from the identity file: {err}")
57
+ self._ziti_ctx = ctx
58
+ return self._ziti_ctx
59
+
50
60
  async def startup(self):
51
61
  setup_logging(get_settings())
52
-
53
- async def shutdown(self):
54
- await self._ziti_socket_cache.stop()
62
+ self._get_ziti_ctx()
55
63
 
56
64
  async def select_backend(
57
65
  self,
@@ -59,6 +67,6 @@ class ProxyApp(ForwardAppBase):
59
67
  headers: dict[str, str],
60
68
  ) -> tuple[StreamReader, StreamWriter] | tuple[None, None]:
61
69
  target_name = self.get_target_name(headers)
62
- sock = self._ziti_socket_cache.get_or_create(target_name)
70
+ sock = self._get_ziti_ctx().connect(target_name)
63
71
  reader, writer = await asyncio.open_connection(sock=sock)
64
72
  return reader, writer
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "mrok"
3
- version = "0.4.3"
3
+ version = "0.4.5"
4
4
  description = "MPT Extensions OpenZiti Orchestrator"
5
5
  readme = { file = "README.md", content-type = "text/markdown" }
6
6
  authors = [
@@ -1,103 +0,0 @@
1
- import asyncio
2
- import contextlib
3
- from asyncio import Task
4
- from pathlib import Path
5
-
6
- import openziti
7
- from aiocache import Cache
8
- from openziti.context import ZitiContext
9
- from openziti.zitisock import ZitiSocket
10
-
11
-
12
- class ZitiSocketCache:
13
- def __init__(
14
- self,
15
- identity_file: str | Path,
16
- ziti_ctx_timeout_ms: int = 10_000,
17
- ttl_seconds: float = 60.0,
18
- cleanup_interval: float = 10.0,
19
- ) -> None:
20
- self._identity_file = identity_file
21
- self._ziti_ctx_timeout_ms = ziti_ctx_timeout_ms
22
- self._ttl_seconds = ttl_seconds
23
- self._cleanup_interval = cleanup_interval
24
-
25
- self._ziti_ctx: ZitiContext | None = None
26
- self._cache = Cache(Cache.MEMORY)
27
- self._active_sockets: dict[str, ZitiSocket] = {}
28
- self._cleanup_task: Task | None = None
29
-
30
- def _get_ziti_ctx(self) -> ZitiContext:
31
- if self._ziti_ctx is None:
32
- ctx, err = openziti.load(str(self._identity_file), timeout=self._ziti_ctx_timeout_ms)
33
- if err != 0:
34
- raise Exception(f"Cannot create a Ziti context from the identity file: {err}")
35
- self._ziti_ctx = ctx
36
- return self._ziti_ctx
37
-
38
- async def _create_socket(self, key: str):
39
- return self._get_ziti_ctx().connect(key)
40
-
41
- async def get_or_create(self, key: str):
42
- sock = await self._cache.get(key)
43
-
44
- if sock:
45
- await self._cache.set(key, sock, ttl_seconds=self._ttl_seconds)
46
- self._active_sockets[key] = sock
47
- return sock
48
-
49
- sock = await self._create_socket(key)
50
- await self._cache.set(key, sock, ttl_seconds=self._ttl_seconds)
51
- self._active_sockets[key] = sock
52
- return sock
53
-
54
- async def invalidate(self, key: str):
55
- sock = await self._cache.get(key)
56
- if sock:
57
- await self._close_socket(sock)
58
-
59
- await self._cache.delete(key)
60
- self._active_sockets.pop(key, None)
61
-
62
- async def start(self):
63
- self._cleanup_task = asyncio.create_task(self._periodic_cleanup())
64
- # Warmup ziti context
65
- self._get_ziti_ctx()
66
-
67
- async def stop(self):
68
- """
69
- Cleanup: stop background task + close all sockets.
70
- """
71
- self._cleanup_task.cancel()
72
- with contextlib.suppress(Exception):
73
- await self._cleanup_task
74
-
75
- for sock in list(self._active_sockets.values()):
76
- await self._close_socket(sock)
77
-
78
- self._active_sockets.clear()
79
- await self._cache.clear()
80
-
81
- @staticmethod
82
- async def _close_socket(sock: ZitiSocket):
83
- with contextlib.suppress(Exception):
84
- sock.close()
85
-
86
- async def _periodic_cleanup(self):
87
- try:
88
- while True:
89
- await asyncio.sleep(self._cleanup_interval)
90
- await self._cleanup_once()
91
- except asyncio.CancelledError:
92
- return
93
-
94
- async def _cleanup_once(self):
95
- keys_now = set(await self._cache.keys())
96
- known_keys = set(self._active_sockets.keys())
97
-
98
- expired = known_keys - keys_now
99
-
100
- for key in expired:
101
- sock = self._active_sockets.pop(key, None)
102
- if sock:
103
- await self._close_socket(sock)
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