OpenRAG 0.3.1__tar.gz → 0.3.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 (152) hide show
  1. {openrag-0.3.1/src/openrag.egg-info → openrag-0.3.2}/PKG-INFO +1 -1
  2. {openrag-0.3.1 → openrag-0.3.2}/pyproject.toml +1 -1
  3. {openrag-0.3.1 → openrag-0.3.2}/src/api/search.py +3 -0
  4. {openrag-0.3.1 → openrag-0.3.2}/src/api/v1/search.py +4 -0
  5. {openrag-0.3.1 → openrag-0.3.2/src/openrag.egg-info}/PKG-INFO +1 -1
  6. {openrag-0.3.1 → openrag-0.3.2}/src/services/search_service.py +21 -0
  7. {openrag-0.3.1 → openrag-0.3.2}/src/tui/_assets/docker-compose.yml +0 -1
  8. {openrag-0.3.1 → openrag-0.3.2}/src/utils/opensearch_utils.py +41 -0
  9. {openrag-0.3.1 → openrag-0.3.2}/LICENSE +0 -0
  10. {openrag-0.3.1 → openrag-0.3.2}/MANIFEST.in +0 -0
  11. {openrag-0.3.1 → openrag-0.3.2}/README.md +0 -0
  12. {openrag-0.3.1 → openrag-0.3.2}/setup.cfg +0 -0
  13. {openrag-0.3.1 → openrag-0.3.2}/src/agent.py +0 -0
  14. {openrag-0.3.1 → openrag-0.3.2}/src/api/__init__.py +0 -0
  15. {openrag-0.3.1 → openrag-0.3.2}/src/api/auth.py +0 -0
  16. {openrag-0.3.1 → openrag-0.3.2}/src/api/chat.py +0 -0
  17. {openrag-0.3.1 → openrag-0.3.2}/src/api/connector_router.py +0 -0
  18. {openrag-0.3.1 → openrag-0.3.2}/src/api/connectors.py +0 -0
  19. {openrag-0.3.1 → openrag-0.3.2}/src/api/docling.py +0 -0
  20. {openrag-0.3.1 → openrag-0.3.2}/src/api/documents.py +0 -0
  21. {openrag-0.3.1 → openrag-0.3.2}/src/api/flows.py +0 -0
  22. {openrag-0.3.1 → openrag-0.3.2}/src/api/keys.py +0 -0
  23. {openrag-0.3.1 → openrag-0.3.2}/src/api/knowledge_filter.py +0 -0
  24. {openrag-0.3.1 → openrag-0.3.2}/src/api/langflow_files.py +0 -0
  25. {openrag-0.3.1 → openrag-0.3.2}/src/api/models.py +0 -0
  26. {openrag-0.3.1 → openrag-0.3.2}/src/api/nudges.py +0 -0
  27. {openrag-0.3.1 → openrag-0.3.2}/src/api/oidc.py +0 -0
  28. {openrag-0.3.1 → openrag-0.3.2}/src/api/provider_health.py +0 -0
  29. {openrag-0.3.1 → openrag-0.3.2}/src/api/provider_validation.py +0 -0
  30. {openrag-0.3.1 → openrag-0.3.2}/src/api/router.py +0 -0
  31. {openrag-0.3.1 → openrag-0.3.2}/src/api/settings.py +0 -0
  32. {openrag-0.3.1 → openrag-0.3.2}/src/api/tasks.py +0 -0
  33. {openrag-0.3.1 → openrag-0.3.2}/src/api/upload.py +0 -0
  34. {openrag-0.3.1 → openrag-0.3.2}/src/api/v1/__init__.py +0 -0
  35. {openrag-0.3.1 → openrag-0.3.2}/src/api/v1/chat.py +0 -0
  36. {openrag-0.3.1 → openrag-0.3.2}/src/api/v1/documents.py +0 -0
  37. {openrag-0.3.1 → openrag-0.3.2}/src/api/v1/knowledge_filters.py +0 -0
  38. {openrag-0.3.1 → openrag-0.3.2}/src/api/v1/models.py +0 -0
  39. {openrag-0.3.1 → openrag-0.3.2}/src/api/v1/settings.py +0 -0
  40. {openrag-0.3.1 → openrag-0.3.2}/src/auth_context.py +0 -0
  41. {openrag-0.3.1 → openrag-0.3.2}/src/config/__init__.py +0 -0
  42. {openrag-0.3.1 → openrag-0.3.2}/src/config/config_manager.py +0 -0
  43. {openrag-0.3.1 → openrag-0.3.2}/src/config/model_constants.py +0 -0
  44. {openrag-0.3.1 → openrag-0.3.2}/src/config/settings.py +0 -0
  45. {openrag-0.3.1 → openrag-0.3.2}/src/connectors/__init__.py +0 -0
  46. {openrag-0.3.1 → openrag-0.3.2}/src/connectors/base.py +0 -0
  47. {openrag-0.3.1 → openrag-0.3.2}/src/connectors/connection_manager.py +0 -0
  48. {openrag-0.3.1 → openrag-0.3.2}/src/connectors/google_drive/__init__.py +0 -0
  49. {openrag-0.3.1 → openrag-0.3.2}/src/connectors/google_drive/connector.py +0 -0
  50. {openrag-0.3.1 → openrag-0.3.2}/src/connectors/google_drive/oauth.py +0 -0
  51. {openrag-0.3.1 → openrag-0.3.2}/src/connectors/langflow_connector_service.py +0 -0
  52. {openrag-0.3.1 → openrag-0.3.2}/src/connectors/onedrive/__init__.py +0 -0
  53. {openrag-0.3.1 → openrag-0.3.2}/src/connectors/onedrive/connector.py +0 -0
  54. {openrag-0.3.1 → openrag-0.3.2}/src/connectors/onedrive/oauth.py +0 -0
  55. {openrag-0.3.1 → openrag-0.3.2}/src/connectors/service.py +0 -0
  56. {openrag-0.3.1 → openrag-0.3.2}/src/connectors/sharepoint/__init__.py +0 -0
  57. {openrag-0.3.1 → openrag-0.3.2}/src/connectors/sharepoint/connector.py +0 -0
  58. {openrag-0.3.1 → openrag-0.3.2}/src/connectors/sharepoint/oauth.py +0 -0
  59. {openrag-0.3.1 → openrag-0.3.2}/src/connectors/sharepoint/utils.py +0 -0
  60. {openrag-0.3.1 → openrag-0.3.2}/src/dependencies.py +0 -0
  61. {openrag-0.3.1 → openrag-0.3.2}/src/main.py +0 -0
  62. {openrag-0.3.1 → openrag-0.3.2}/src/models/__init__.py +0 -0
  63. {openrag-0.3.1 → openrag-0.3.2}/src/models/processors.py +0 -0
  64. {openrag-0.3.1 → openrag-0.3.2}/src/models/tasks.py +0 -0
  65. {openrag-0.3.1 → openrag-0.3.2}/src/models/url.py +0 -0
  66. {openrag-0.3.1 → openrag-0.3.2}/src/openrag.egg-info/SOURCES.txt +0 -0
  67. {openrag-0.3.1 → openrag-0.3.2}/src/openrag.egg-info/dependency_links.txt +0 -0
  68. {openrag-0.3.1 → openrag-0.3.2}/src/openrag.egg-info/entry_points.txt +0 -0
  69. {openrag-0.3.1 → openrag-0.3.2}/src/openrag.egg-info/requires.txt +0 -0
  70. {openrag-0.3.1 → openrag-0.3.2}/src/openrag.egg-info/top_level.txt +0 -0
  71. {openrag-0.3.1 → openrag-0.3.2}/src/services/__init__.py +0 -0
  72. {openrag-0.3.1 → openrag-0.3.2}/src/services/api_key_service.py +0 -0
  73. {openrag-0.3.1 → openrag-0.3.2}/src/services/auth_service.py +0 -0
  74. {openrag-0.3.1 → openrag-0.3.2}/src/services/chat_service.py +0 -0
  75. {openrag-0.3.1 → openrag-0.3.2}/src/services/conversation_persistence_service.py +0 -0
  76. {openrag-0.3.1 → openrag-0.3.2}/src/services/document_service.py +0 -0
  77. {openrag-0.3.1 → openrag-0.3.2}/src/services/flows_service.py +0 -0
  78. {openrag-0.3.1 → openrag-0.3.2}/src/services/knowledge_filter_service.py +0 -0
  79. {openrag-0.3.1 → openrag-0.3.2}/src/services/langflow_file_service.py +0 -0
  80. {openrag-0.3.1 → openrag-0.3.2}/src/services/langflow_history_service.py +0 -0
  81. {openrag-0.3.1 → openrag-0.3.2}/src/services/langflow_mcp_service.py +0 -0
  82. {openrag-0.3.1 → openrag-0.3.2}/src/services/models_service.py +0 -0
  83. {openrag-0.3.1 → openrag-0.3.2}/src/services/monitor_service.py +0 -0
  84. {openrag-0.3.1 → openrag-0.3.2}/src/services/session_ownership_service.py +0 -0
  85. {openrag-0.3.1 → openrag-0.3.2}/src/services/task_service.py +0 -0
  86. {openrag-0.3.1 → openrag-0.3.2}/src/session_manager.py +0 -0
  87. {openrag-0.3.1 → openrag-0.3.2}/src/tui/__init__.py +0 -0
  88. {openrag-0.3.1 → openrag-0.3.2}/src/tui/_assets/docker-compose.gpu.yml +0 -0
  89. {openrag-0.3.1 → openrag-0.3.2}/src/tui/_assets/flows/components/ollama_embedding.json +0 -0
  90. {openrag-0.3.1 → openrag-0.3.2}/src/tui/_assets/flows/components/ollama_llm.json +0 -0
  91. {openrag-0.3.1 → openrag-0.3.2}/src/tui/_assets/flows/components/ollama_llm_text.json +0 -0
  92. {openrag-0.3.1 → openrag-0.3.2}/src/tui/_assets/flows/components/watsonx_embedding.json +0 -0
  93. {openrag-0.3.1 → openrag-0.3.2}/src/tui/_assets/flows/components/watsonx_llm.json +0 -0
  94. {openrag-0.3.1 → openrag-0.3.2}/src/tui/_assets/flows/components/watsonx_llm_text.json +0 -0
  95. {openrag-0.3.1 → openrag-0.3.2}/src/tui/_assets/flows/ingestion_flow.json +0 -0
  96. {openrag-0.3.1 → openrag-0.3.2}/src/tui/_assets/flows/openrag_agent.json +0 -0
  97. {openrag-0.3.1 → openrag-0.3.2}/src/tui/_assets/flows/openrag_nudges.json +0 -0
  98. {openrag-0.3.1 → openrag-0.3.2}/src/tui/_assets/flows/openrag_url_mcp.json +0 -0
  99. {openrag-0.3.1 → openrag-0.3.2}/src/tui/_assets/openrag-documents/docling.pdf +0 -0
  100. {openrag-0.3.1 → openrag-0.3.2}/src/tui/_assets/openrag-documents/ibm_anthropic.pdf +0 -0
  101. {openrag-0.3.1 → openrag-0.3.2}/src/tui/_assets/openrag-documents/openrag-documentation.pdf +0 -0
  102. {openrag-0.3.1 → openrag-0.3.2}/src/tui/_assets/openrag-documents/warmup_ocr.pdf +0 -0
  103. {openrag-0.3.1 → openrag-0.3.2}/src/tui/cli.py +0 -0
  104. {openrag-0.3.1 → openrag-0.3.2}/src/tui/config_fields.py +0 -0
  105. {openrag-0.3.1 → openrag-0.3.2}/src/tui/main.py +0 -0
  106. {openrag-0.3.1 → openrag-0.3.2}/src/tui/managers/__init__.py +0 -0
  107. {openrag-0.3.1 → openrag-0.3.2}/src/tui/managers/container_manager.py +0 -0
  108. {openrag-0.3.1 → openrag-0.3.2}/src/tui/managers/docling_manager.py +0 -0
  109. {openrag-0.3.1 → openrag-0.3.2}/src/tui/managers/env_manager.py +0 -0
  110. {openrag-0.3.1 → openrag-0.3.2}/src/tui/screens/__init__.py +0 -0
  111. {openrag-0.3.1 → openrag-0.3.2}/src/tui/screens/config.py +0 -0
  112. {openrag-0.3.1 → openrag-0.3.2}/src/tui/screens/diagnostics.py +0 -0
  113. {openrag-0.3.1 → openrag-0.3.2}/src/tui/screens/logs.py +0 -0
  114. {openrag-0.3.1 → openrag-0.3.2}/src/tui/screens/monitor.py +0 -0
  115. {openrag-0.3.1 → openrag-0.3.2}/src/tui/screens/welcome.py +0 -0
  116. {openrag-0.3.1 → openrag-0.3.2}/src/tui/utils/__init__.py +0 -0
  117. {openrag-0.3.1 → openrag-0.3.2}/src/tui/utils/clipboard.py +0 -0
  118. {openrag-0.3.1 → openrag-0.3.2}/src/tui/utils/platform.py +0 -0
  119. {openrag-0.3.1 → openrag-0.3.2}/src/tui/utils/startup_checks.py +0 -0
  120. {openrag-0.3.1 → openrag-0.3.2}/src/tui/utils/validation.py +0 -0
  121. {openrag-0.3.1 → openrag-0.3.2}/src/tui/utils/version_check.py +0 -0
  122. {openrag-0.3.1 → openrag-0.3.2}/src/tui/widgets/__init__.py +0 -0
  123. {openrag-0.3.1 → openrag-0.3.2}/src/tui/widgets/command_modal.py +0 -0
  124. {openrag-0.3.1 → openrag-0.3.2}/src/tui/widgets/diagnostics_notification.py +0 -0
  125. {openrag-0.3.1 → openrag-0.3.2}/src/tui/widgets/error_notification.py +0 -0
  126. {openrag-0.3.1 → openrag-0.3.2}/src/tui/widgets/factory_reset_warning_modal.py +0 -0
  127. {openrag-0.3.1 → openrag-0.3.2}/src/tui/widgets/flow_backup_warning_modal.py +0 -0
  128. {openrag-0.3.1 → openrag-0.3.2}/src/tui/widgets/prune_options_modal.py +0 -0
  129. {openrag-0.3.1 → openrag-0.3.2}/src/tui/widgets/upgrade_instructions_modal.py +0 -0
  130. {openrag-0.3.1 → openrag-0.3.2}/src/tui/widgets/version_mismatch_warning_modal.py +0 -0
  131. {openrag-0.3.1 → openrag-0.3.2}/src/tui/widgets/waves.py +0 -0
  132. {openrag-0.3.1 → openrag-0.3.2}/src/utils/__init__.py +0 -0
  133. {openrag-0.3.1 → openrag-0.3.2}/src/utils/acl_utils.py +0 -0
  134. {openrag-0.3.1 → openrag-0.3.2}/src/utils/container_utils.py +0 -0
  135. {openrag-0.3.1 → openrag-0.3.2}/src/utils/docling_client.py +0 -0
  136. {openrag-0.3.1 → openrag-0.3.2}/src/utils/document_processing.py +0 -0
  137. {openrag-0.3.1 → openrag-0.3.2}/src/utils/embedding_fields.py +0 -0
  138. {openrag-0.3.1 → openrag-0.3.2}/src/utils/embeddings.py +0 -0
  139. {openrag-0.3.1 → openrag-0.3.2}/src/utils/env_utils.py +0 -0
  140. {openrag-0.3.1 → openrag-0.3.2}/src/utils/file_utils.py +0 -0
  141. {openrag-0.3.1 → openrag-0.3.2}/src/utils/gpu_detection.py +0 -0
  142. {openrag-0.3.1 → openrag-0.3.2}/src/utils/hash_utils.py +0 -0
  143. {openrag-0.3.1 → openrag-0.3.2}/src/utils/langflow_headers.py +0 -0
  144. {openrag-0.3.1 → openrag-0.3.2}/src/utils/langflow_utils.py +0 -0
  145. {openrag-0.3.1 → openrag-0.3.2}/src/utils/logging_config.py +0 -0
  146. {openrag-0.3.1 → openrag-0.3.2}/src/utils/opensearch_queries.py +0 -0
  147. {openrag-0.3.1 → openrag-0.3.2}/src/utils/paths.py +0 -0
  148. {openrag-0.3.1 → openrag-0.3.2}/src/utils/telemetry/__init__.py +0 -0
  149. {openrag-0.3.1 → openrag-0.3.2}/src/utils/telemetry/category.py +0 -0
  150. {openrag-0.3.1 → openrag-0.3.2}/src/utils/telemetry/client.py +0 -0
  151. {openrag-0.3.1 → openrag-0.3.2}/src/utils/telemetry/message_id.py +0 -0
  152. {openrag-0.3.1 → openrag-0.3.2}/src/utils/version_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: openrag
3
- Version: 0.3.1
3
+ Version: 0.3.2
4
4
  Summary: OpenRAG is a comprehensive Retrieval-Augmented Generation platform that enables intelligent document search and AI-powered conversations.
5
5
  Classifier: Development Status :: 4 - Beta
6
6
  Classifier: Environment :: Console
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "openrag"
7
- version = "0.3.1"
7
+ version = "0.3.2"
8
8
  description = "OpenRAG is a comprehensive Retrieval-Augmented Generation platform that enables intelligent document search and AI-powered conversations."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.13"
@@ -4,6 +4,7 @@ from fastapi import Depends
4
4
  from pydantic import BaseModel, Field
5
5
  from fastapi.responses import JSONResponse
6
6
  from utils.logging_config import get_logger
7
+ from utils.opensearch_utils import OpenSearchDiskSpaceError, DISK_SPACE_ERROR_MESSAGE
7
8
 
8
9
  from dependencies import get_search_service, get_session_manager, get_current_user
9
10
  from session_manager import User
@@ -50,6 +51,8 @@ async def search(
50
51
  score_threshold=body.scoreThreshold,
51
52
  )
52
53
  return JSONResponse(result, status_code=200)
54
+ except OpenSearchDiskSpaceError:
55
+ return JSONResponse({"error": DISK_SPACE_ERROR_MESSAGE}, status_code=507)
53
56
  except Exception as e:
54
57
  error_msg = str(e)
55
58
  if (
@@ -10,6 +10,7 @@ from fastapi import Depends
10
10
  from pydantic import BaseModel
11
11
  from fastapi.responses import JSONResponse
12
12
  from utils.logging_config import get_logger
13
+ from utils.opensearch_utils import OpenSearchDiskSpaceError, DISK_SPACE_ERROR_MESSAGE
13
14
  from dependencies import get_search_service, get_api_key_user_async
14
15
  from session_manager import User
15
16
 
@@ -65,6 +66,9 @@ async def search_endpoint(
65
66
 
66
67
  return JSONResponse({"results": results})
67
68
 
69
+ except OpenSearchDiskSpaceError as e:
70
+ logger.error("Search blocked by disk space constraint", error=str(e), user_id=user.user_id)
71
+ return JSONResponse({"error": DISK_SPACE_ERROR_MESSAGE}, status_code=507)
68
72
  except Exception as e:
69
73
  error_msg = str(e)
70
74
  logger.error("Search failed", error=error_msg, user_id=user.user_id)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: openrag
3
- Version: 0.3.1
3
+ Version: 0.3.2
4
4
  Summary: OpenRAG is a comprehensive Retrieval-Augmented Generation platform that enables intelligent document search and AI-powered conversations.
5
5
  Classifier: Development Status :: 4 - Beta
6
6
  Classifier: Environment :: Console
@@ -392,6 +392,7 @@ class SearchService:
392
392
  )
393
393
 
394
394
  from opensearchpy.exceptions import RequestError
395
+ from utils.opensearch_utils import OpenSearchDiskSpaceError, is_disk_space_error, DISK_SPACE_ERROR_MESSAGE
395
396
 
396
397
  search_params = {"terminate_after": 0}
397
398
 
@@ -403,6 +404,12 @@ class SearchService:
403
404
  )
404
405
  except RequestError as e:
405
406
  error_message = str(e)
407
+ if is_disk_space_error(e):
408
+ logger.error(
409
+ "OpenSearch query blocked by disk space constraint",
410
+ error=error_message,
411
+ )
412
+ raise OpenSearchDiskSpaceError(DISK_SPACE_ERROR_MESSAGE) from e
406
413
  if (
407
414
  fallback_search_body is not None
408
415
  and "unknown field [num_candidates]" in error_message.lower()
@@ -417,6 +424,12 @@ class SearchService:
417
424
  params=search_params,
418
425
  )
419
426
  except RequestError as retry_error:
427
+ if is_disk_space_error(retry_error):
428
+ logger.error(
429
+ "OpenSearch retry blocked by disk space constraint",
430
+ error=str(retry_error),
431
+ )
432
+ raise OpenSearchDiskSpaceError(DISK_SPACE_ERROR_MESSAGE) from retry_error
420
433
  logger.error(
421
434
  "OpenSearch retry without num_candidates failed",
422
435
  error=str(retry_error),
@@ -428,7 +441,15 @@ class SearchService:
428
441
  "OpenSearch query failed", error=error_message, search_body=search_body
429
442
  )
430
443
  raise
444
+ except OpenSearchDiskSpaceError:
445
+ raise
431
446
  except Exception as e:
447
+ if is_disk_space_error(e):
448
+ logger.error(
449
+ "OpenSearch query blocked by disk space constraint",
450
+ error=str(e),
451
+ )
452
+ raise OpenSearchDiskSpaceError(DISK_SPACE_ERROR_MESSAGE) from e
432
453
  logger.error(
433
454
  "OpenSearch query failed", error=str(e), search_body=search_body
434
455
  )
@@ -49,7 +49,6 @@ services:
49
49
  context: .
50
50
  dockerfile: Dockerfile.backend
51
51
  container_name: openrag-backend
52
- user: "${OPENRAG_UID:-103000}:${OPENRAG_GID:-103000}"
53
52
  depends_on:
54
53
  - langflow
55
54
  environment:
@@ -5,9 +5,50 @@ from utils.logging_config import get_logger
5
5
 
6
6
  logger = get_logger(__name__)
7
7
 
8
+ DISK_SPACE_ERROR_MESSAGE = (
9
+ "OpenSearch has run out of available disk space. "
10
+ "Search and indexing operations are blocked. "
11
+ "Please free up disk space to restore OpenRAG functionality."
12
+ )
13
+
14
+ # Error strings emitted by OpenSearch when disk watermark thresholds are breached
15
+ _DISK_SPACE_INDICATORS = [
16
+ "disk watermark",
17
+ "flood_stage",
18
+ "flood stage",
19
+ "disk usage exceeded",
20
+ "index read-only",
21
+ "no space left on device",
22
+ "cluster_block_exception",
23
+ "forbidden/12",
24
+ "too_many_requests/12",
25
+ ]
26
+
27
+
8
28
  class OpenSearchNotReadyError(Exception):
9
29
  """Raised when OpenSearch fails to become ready within the retry limit."""
10
30
 
31
+
32
+ class OpenSearchDiskSpaceError(Exception):
33
+ """Raised when OpenSearch operations fail due to insufficient disk space."""
34
+
35
+
36
+ def is_disk_space_error(error: Exception) -> bool:
37
+ """Check whether an exception is caused by OpenSearch disk space constraints.
38
+
39
+ OpenSearch blocks write and search operations when disk usage crosses
40
+ the high-watermark or flood-stage watermark thresholds.
41
+ This function detects those error signatures.
42
+
43
+ Args:
44
+ error: The exception to inspect.
45
+
46
+ Returns:
47
+ True if the error is disk-space related, False otherwise.
48
+ """
49
+ error_str = str(error).lower()
50
+ return any(indicator in error_str for indicator in _DISK_SPACE_INDICATORS)
51
+
11
52
  async def wait_for_opensearch(
12
53
  opensearch_client: AsyncOpenSearch,
13
54
  max_retries: int = 15,
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes