cbrkit 0.28.3__tar.gz → 0.28.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 (72) hide show
  1. {cbrkit-0.28.3 → cbrkit-0.28.4}/PKG-INFO +2 -1
  2. {cbrkit-0.28.3 → cbrkit-0.28.4}/pyproject.toml +2 -1
  3. cbrkit-0.28.4/src/cbrkit/system.py +250 -0
  4. cbrkit-0.28.3/src/cbrkit/system.py +0 -143
  5. {cbrkit-0.28.3 → cbrkit-0.28.4}/README.md +0 -0
  6. {cbrkit-0.28.3 → cbrkit-0.28.4}/src/cbrkit/__init__.py +0 -0
  7. {cbrkit-0.28.3 → cbrkit-0.28.4}/src/cbrkit/__main__.py +0 -0
  8. {cbrkit-0.28.3 → cbrkit-0.28.4}/src/cbrkit/adapt/__init__.py +0 -0
  9. {cbrkit-0.28.3 → cbrkit-0.28.4}/src/cbrkit/adapt/attribute_value.py +0 -0
  10. {cbrkit-0.28.3 → cbrkit-0.28.4}/src/cbrkit/adapt/generic.py +0 -0
  11. {cbrkit-0.28.3 → cbrkit-0.28.4}/src/cbrkit/adapt/numbers.py +0 -0
  12. {cbrkit-0.28.3 → cbrkit-0.28.4}/src/cbrkit/adapt/strings.py +0 -0
  13. {cbrkit-0.28.3 → cbrkit-0.28.4}/src/cbrkit/api.py +0 -0
  14. {cbrkit-0.28.3 → cbrkit-0.28.4}/src/cbrkit/cli.py +0 -0
  15. {cbrkit-0.28.3 → cbrkit-0.28.4}/src/cbrkit/constants.py +0 -0
  16. {cbrkit-0.28.3 → cbrkit-0.28.4}/src/cbrkit/cycle.py +0 -0
  17. {cbrkit-0.28.3 → cbrkit-0.28.4}/src/cbrkit/dumpers.py +0 -0
  18. {cbrkit-0.28.3 → cbrkit-0.28.4}/src/cbrkit/eval/__init__.py +0 -0
  19. {cbrkit-0.28.3 → cbrkit-0.28.4}/src/cbrkit/eval/common.py +0 -0
  20. {cbrkit-0.28.3 → cbrkit-0.28.4}/src/cbrkit/eval/retrieval.py +0 -0
  21. {cbrkit-0.28.3 → cbrkit-0.28.4}/src/cbrkit/helpers.py +0 -0
  22. {cbrkit-0.28.3 → cbrkit-0.28.4}/src/cbrkit/loaders.py +0 -0
  23. {cbrkit-0.28.3 → cbrkit-0.28.4}/src/cbrkit/model/__init__.py +0 -0
  24. {cbrkit-0.28.3 → cbrkit-0.28.4}/src/cbrkit/model/graph.py +0 -0
  25. {cbrkit-0.28.3 → cbrkit-0.28.4}/src/cbrkit/model/result.py +0 -0
  26. {cbrkit-0.28.3 → cbrkit-0.28.4}/src/cbrkit/py.typed +0 -0
  27. {cbrkit-0.28.3 → cbrkit-0.28.4}/src/cbrkit/retrieval/__init__.py +0 -0
  28. {cbrkit-0.28.3 → cbrkit-0.28.4}/src/cbrkit/retrieval/apply.py +0 -0
  29. {cbrkit-0.28.3 → cbrkit-0.28.4}/src/cbrkit/retrieval/build.py +0 -0
  30. {cbrkit-0.28.3 → cbrkit-0.28.4}/src/cbrkit/retrieval/rerank.py +0 -0
  31. {cbrkit-0.28.3 → cbrkit-0.28.4}/src/cbrkit/reuse/__init__.py +0 -0
  32. {cbrkit-0.28.3 → cbrkit-0.28.4}/src/cbrkit/reuse/apply.py +0 -0
  33. {cbrkit-0.28.3 → cbrkit-0.28.4}/src/cbrkit/reuse/build.py +0 -0
  34. {cbrkit-0.28.3 → cbrkit-0.28.4}/src/cbrkit/sim/__init__.py +0 -0
  35. {cbrkit-0.28.3 → cbrkit-0.28.4}/src/cbrkit/sim/aggregator.py +0 -0
  36. {cbrkit-0.28.3 → cbrkit-0.28.4}/src/cbrkit/sim/attribute_value.py +0 -0
  37. {cbrkit-0.28.3 → cbrkit-0.28.4}/src/cbrkit/sim/collections.py +0 -0
  38. {cbrkit-0.28.3 → cbrkit-0.28.4}/src/cbrkit/sim/embed.py +0 -0
  39. {cbrkit-0.28.3 → cbrkit-0.28.4}/src/cbrkit/sim/generic.py +0 -0
  40. {cbrkit-0.28.3 → cbrkit-0.28.4}/src/cbrkit/sim/graphs/__init__.py +0 -0
  41. {cbrkit-0.28.3 → cbrkit-0.28.4}/src/cbrkit/sim/graphs/alignment.py +0 -0
  42. {cbrkit-0.28.3 → cbrkit-0.28.4}/src/cbrkit/sim/graphs/astar.py +0 -0
  43. {cbrkit-0.28.3 → cbrkit-0.28.4}/src/cbrkit/sim/graphs/brute_force.py +0 -0
  44. {cbrkit-0.28.3 → cbrkit-0.28.4}/src/cbrkit/sim/graphs/common.py +0 -0
  45. {cbrkit-0.28.3 → cbrkit-0.28.4}/src/cbrkit/sim/graphs/dfs.py +0 -0
  46. {cbrkit-0.28.3 → cbrkit-0.28.4}/src/cbrkit/sim/graphs/greedy.py +0 -0
  47. {cbrkit-0.28.3 → cbrkit-0.28.4}/src/cbrkit/sim/graphs/lap.py +0 -0
  48. {cbrkit-0.28.3 → cbrkit-0.28.4}/src/cbrkit/sim/graphs/precompute.py +0 -0
  49. {cbrkit-0.28.3 → cbrkit-0.28.4}/src/cbrkit/sim/graphs/qap.py +0 -0
  50. {cbrkit-0.28.3 → cbrkit-0.28.4}/src/cbrkit/sim/graphs/vf2.py +0 -0
  51. {cbrkit-0.28.3 → cbrkit-0.28.4}/src/cbrkit/sim/numbers.py +0 -0
  52. {cbrkit-0.28.3 → cbrkit-0.28.4}/src/cbrkit/sim/pooling.py +0 -0
  53. {cbrkit-0.28.3 → cbrkit-0.28.4}/src/cbrkit/sim/strings.py +0 -0
  54. {cbrkit-0.28.3 → cbrkit-0.28.4}/src/cbrkit/sim/taxonomy.py +0 -0
  55. {cbrkit-0.28.3 → cbrkit-0.28.4}/src/cbrkit/sim/wrappers.py +0 -0
  56. {cbrkit-0.28.3 → cbrkit-0.28.4}/src/cbrkit/synthesis/__init__.py +0 -0
  57. {cbrkit-0.28.3 → cbrkit-0.28.4}/src/cbrkit/synthesis/apply.py +0 -0
  58. {cbrkit-0.28.3 → cbrkit-0.28.4}/src/cbrkit/synthesis/build.py +0 -0
  59. {cbrkit-0.28.3 → cbrkit-0.28.4}/src/cbrkit/synthesis/model.py +0 -0
  60. {cbrkit-0.28.3 → cbrkit-0.28.4}/src/cbrkit/synthesis/prompts.py +0 -0
  61. {cbrkit-0.28.3 → cbrkit-0.28.4}/src/cbrkit/synthesis/providers/__init__.py +0 -0
  62. {cbrkit-0.28.3 → cbrkit-0.28.4}/src/cbrkit/synthesis/providers/anthropic.py +0 -0
  63. {cbrkit-0.28.3 → cbrkit-0.28.4}/src/cbrkit/synthesis/providers/cohere.py +0 -0
  64. {cbrkit-0.28.3 → cbrkit-0.28.4}/src/cbrkit/synthesis/providers/google.py +0 -0
  65. {cbrkit-0.28.3 → cbrkit-0.28.4}/src/cbrkit/synthesis/providers/instructor.py +0 -0
  66. {cbrkit-0.28.3 → cbrkit-0.28.4}/src/cbrkit/synthesis/providers/model.py +0 -0
  67. {cbrkit-0.28.3 → cbrkit-0.28.4}/src/cbrkit/synthesis/providers/ollama.py +0 -0
  68. {cbrkit-0.28.3 → cbrkit-0.28.4}/src/cbrkit/synthesis/providers/openai.py +0 -0
  69. {cbrkit-0.28.3 → cbrkit-0.28.4}/src/cbrkit/synthesis/providers/openai_agents.py +0 -0
  70. {cbrkit-0.28.3 → cbrkit-0.28.4}/src/cbrkit/synthesis/providers/pydantic_ai.py +0 -0
  71. {cbrkit-0.28.3 → cbrkit-0.28.4}/src/cbrkit/synthesis/providers/wrappers.py +0 -0
  72. {cbrkit-0.28.3 → cbrkit-0.28.4}/src/cbrkit/typing.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: cbrkit
3
- Version: 0.28.3
3
+ Version: 0.28.4
4
4
  Summary: Customizable Case-Based Reasoning (CBR) toolkit for Python with a built-in API and CLI
5
5
  Keywords: cbr,case-based reasoning,api,similarity,nlp,retrieval,cli,tool,library
6
6
  Author: Mirko Lenz
@@ -40,6 +40,7 @@ Requires-Dist: pydantic-settings>=2,<3 ; extra == 'api'
40
40
  Requires-Dist: python-multipart>=0.0.15,<1 ; extra == 'api'
41
41
  Requires-Dist: uvicorn[standard]>=0.30,<1 ; extra == 'api'
42
42
  Requires-Dist: fastmcp>=2,<3 ; extra == 'api'
43
+ Requires-Dist: jsonref>=1,<2 ; extra == 'api'
43
44
  Requires-Dist: chonkie>=1,<2 ; extra == 'chunking'
44
45
  Requires-Dist: typer>=0.9,<1 ; extra == 'cli'
45
46
  Requires-Dist: ranx>=0.3,<1 ; extra == 'eval'
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "cbrkit"
3
- version = "0.28.3"
3
+ version = "0.28.4"
4
4
  description = "Customizable Case-Based Reasoning (CBR) toolkit for Python with a built-in API and CLI"
5
5
  authors = [{ name = "Mirko Lenz", email = "mirko@mirkolenz.com" }]
6
6
  readme = "README.md"
@@ -58,6 +58,7 @@ api = [
58
58
  "python-multipart>=0.0.15,<1",
59
59
  "uvicorn[standard]>=0.30,<1",
60
60
  "fastmcp>=2,<3",
61
+ "jsonref>=1,<2"
61
62
  ]
62
63
  chunking = ["chonkie>=1,<2"]
63
64
  cli = ["typer>=0.9,<1"]
@@ -0,0 +1,250 @@
1
+ from collections.abc import Callable
2
+ from dataclasses import dataclass
3
+ from typing import Annotated, Any, cast
4
+
5
+ from pydantic import BaseModel
6
+
7
+ import cbrkit
8
+ from cbrkit.typing import Float, MaybeSequence
9
+
10
+ __all__ = [
11
+ "System",
12
+ "to_fastapi",
13
+ "to_fastmcp",
14
+ "to_pydantic_ai",
15
+ ]
16
+
17
+
18
+ @dataclass(slots=True, frozen=True)
19
+ class System[
20
+ K: str | int,
21
+ V: BaseModel,
22
+ S: Float,
23
+ R1: BaseModel | None,
24
+ R2: BaseModel | None,
25
+ ]:
26
+ casebase: cbrkit.typing.Casebase[K, V]
27
+ retriever_factory: (
28
+ Callable[[R1], MaybeSequence[cbrkit.typing.RetrieverFunc[K, V, S]]] | None
29
+ ) = None
30
+ reuser_factory: (
31
+ Callable[[R2], MaybeSequence[cbrkit.typing.ReuserFunc[K, V, S]]] | None
32
+ ) = None
33
+
34
+ def retrieve(
35
+ self,
36
+ query: V,
37
+ config: R1,
38
+ ) -> cbrkit.retrieval.QueryResultStep[K, V, S]:
39
+ if not self.retriever_factory:
40
+ raise ValueError("Retriever factory is not defined.")
41
+
42
+ return cbrkit.retrieval.apply_query(
43
+ self.casebase,
44
+ query,
45
+ self.retriever_factory(config),
46
+ ).default_query
47
+
48
+ def reuse(
49
+ self,
50
+ query: V,
51
+ config: R2,
52
+ ) -> cbrkit.retrieval.QueryResultStep[K, V, S]:
53
+ if not self.reuser_factory:
54
+ raise ValueError("Reuser factory is not defined.")
55
+
56
+ return cbrkit.reuse.apply_query(
57
+ self.casebase,
58
+ query,
59
+ self.reuser_factory(config),
60
+ ).default_query
61
+
62
+ def cycle(
63
+ self,
64
+ query: V,
65
+ retrieve_config: R1,
66
+ reuse_config: R2,
67
+ ) -> cbrkit.retrieval.QueryResultStep[K, V, S]:
68
+ if not self.retriever_factory or not self.reuser_factory:
69
+ raise ValueError("Retriever or reuser factory is not defined.")
70
+
71
+ return cbrkit.cycle.apply_query(
72
+ self.casebase,
73
+ query,
74
+ self.retriever_factory(retrieve_config),
75
+ self.reuser_factory(reuse_config),
76
+ ).final_step.default_query
77
+
78
+
79
+ with cbrkit.helpers.optional_dependencies():
80
+ from fastapi import APIRouter, Body, FastAPI
81
+
82
+ @dataclass(slots=True, frozen=True)
83
+ class FastAPISystem[
84
+ K: str | int,
85
+ V: BaseModel,
86
+ S: Float,
87
+ R1: BaseModel | None,
88
+ R2: BaseModel | None,
89
+ ]:
90
+ system: System[K, V, S, R1, R2]
91
+
92
+ def retrieve(
93
+ self,
94
+ query: Annotated[V, Body],
95
+ config: R1,
96
+ ) -> cbrkit.retrieval.QueryResultStep[K, V, S]:
97
+ return self.system.retrieve(query, config)
98
+
99
+ def reuse(
100
+ self,
101
+ query: Annotated[V, Body],
102
+ config: R2,
103
+ ) -> cbrkit.retrieval.QueryResultStep[K, V, S]:
104
+ return self.system.reuse(query, config)
105
+
106
+ def cycle(
107
+ self,
108
+ query: Annotated[V, Body],
109
+ retrieve_config: R1,
110
+ reuse_config: R2,
111
+ ) -> cbrkit.retrieval.QueryResultStep[K, V, S]:
112
+ return self.system.cycle(query, retrieve_config, reuse_config)
113
+
114
+ def casebase(self) -> cbrkit.typing.Casebase[K, V]:
115
+ return self.system.casebase
116
+
117
+ def case(self, key: K) -> V | None:
118
+ return self.system.casebase.get(key)
119
+
120
+ def to_fastapi[
121
+ K: str | int,
122
+ V: BaseModel,
123
+ S: Float,
124
+ R1: BaseModel | None,
125
+ R2: BaseModel | None,
126
+ T: APIRouter | FastAPI,
127
+ ](system: System[K, V, S, R1, R2], app: T) -> T:
128
+ fastapi_system = FastAPISystem(system)
129
+
130
+ if system.retriever_factory:
131
+ app.post("/retrieve")(fastapi_system.retrieve)
132
+
133
+ if system.reuser_factory:
134
+ app.post("/reuse")(fastapi_system.reuse)
135
+
136
+ if system.retriever_factory and system.reuser_factory:
137
+ app.post("/cycle")(fastapi_system.cycle)
138
+
139
+ app.get("/casebase")(fastapi_system.casebase)
140
+
141
+ app.get("/casebase/{key}")(fastapi_system.case)
142
+
143
+ return app
144
+
145
+
146
+ with cbrkit.helpers.optional_dependencies():
147
+ import jsonref
148
+ from fastmcp import FastMCP
149
+ from fastmcp.tools.tool import FunctionTool
150
+ from fastmcp.utilities.json_schema import compress_schema
151
+
152
+ # https://github.com/jlowin/fastmcp/pull/1427
153
+ def dereference_schema(schema: dict[str, Any]) -> dict[str, Any]:
154
+ return compress_schema(
155
+ cast(
156
+ dict[str, Any],
157
+ jsonref.replace_refs(
158
+ schema,
159
+ jsonschema=True,
160
+ merge_props=True,
161
+ lazy_load=False,
162
+ proxies=False,
163
+ ),
164
+ )
165
+ )
166
+
167
+ def dereference_tool(tool: FunctionTool) -> None:
168
+ tool.parameters = dereference_schema(tool.parameters)
169
+
170
+ if tool.output_schema is not None:
171
+ tool.output_schema = dereference_schema(tool.output_schema)
172
+
173
+ @dataclass(slots=True, frozen=True)
174
+ class FastMCPSystem[
175
+ K: str | int,
176
+ V: BaseModel,
177
+ S: Float,
178
+ R1: BaseModel | None,
179
+ R2: BaseModel | None,
180
+ ]:
181
+ system: System[K, V, S, R1, R2]
182
+
183
+ def retrieve(
184
+ self,
185
+ query: V,
186
+ config: R1,
187
+ ) -> cbrkit.retrieval.QueryResultStep[K, V, S]:
188
+ return self.system.retrieve(query, config)
189
+
190
+ def reuse(
191
+ self,
192
+ query: V,
193
+ config: R2,
194
+ ) -> cbrkit.retrieval.QueryResultStep[K, V, S]:
195
+ return self.system.reuse(query, config)
196
+
197
+ def cycle(
198
+ self,
199
+ query: V,
200
+ retrieve_config: R1,
201
+ reuse_config: R2,
202
+ ) -> cbrkit.retrieval.QueryResultStep[K, V, S]:
203
+ return self.system.cycle(query, retrieve_config, reuse_config)
204
+
205
+ def casebase(self) -> cbrkit.typing.Casebase[K, V]:
206
+ return self.system.casebase
207
+
208
+ def case(self, key: K) -> V | None:
209
+ return self.system.casebase.get(key)
210
+
211
+ def to_fastmcp[
212
+ K: str | int,
213
+ V: BaseModel,
214
+ S: Float,
215
+ R1: BaseModel | None,
216
+ R2: BaseModel | None,
217
+ T: FastMCP,
218
+ ](system: System[K, V, S, R1, R2], app: T) -> T:
219
+ fastmcp_system = FastMCPSystem(system)
220
+
221
+ if system.retriever_factory:
222
+ dereference_tool(app.tool("retrieve")(fastmcp_system.retrieve))
223
+
224
+ if system.reuser_factory:
225
+ dereference_tool(app.tool("reuse")(fastmcp_system.reuse))
226
+
227
+ if system.retriever_factory and system.reuser_factory:
228
+ dereference_tool(app.tool("cycle")(fastmcp_system.cycle))
229
+
230
+ app.resource("casebase://{key}")(fastmcp_system.case)
231
+
232
+ return app
233
+
234
+
235
+ with cbrkit.helpers.optional_dependencies():
236
+ from pydantic_ai.toolsets import FunctionToolset
237
+
238
+ def to_pydantic_ai(system: System) -> FunctionToolset[None]:
239
+ tools: list[Callable[..., Any]] = []
240
+
241
+ if system.retriever_factory:
242
+ tools.append(system.retrieve)
243
+
244
+ if system.reuser_factory:
245
+ tools.append(system.reuse)
246
+
247
+ if system.retriever_factory and system.reuser_factory:
248
+ tools.append(system.cycle)
249
+
250
+ return FunctionToolset(tools)
@@ -1,143 +0,0 @@
1
- from collections.abc import Callable
2
- from dataclasses import dataclass
3
-
4
- from pydantic import BaseModel
5
- from typing_extensions import Any
6
-
7
- import cbrkit
8
- from cbrkit.typing import Float, MaybeSequence
9
-
10
- __all__ = [
11
- "System",
12
- "to_fastapi",
13
- "to_fastmcp",
14
- "to_pydantic_ai",
15
- ]
16
-
17
-
18
- @dataclass(slots=True, frozen=True)
19
- class System[
20
- K: str | int,
21
- V: BaseModel,
22
- S: Float,
23
- R2: BaseModel | None,
24
- R1: BaseModel | None,
25
- ]:
26
- casebase: cbrkit.typing.Casebase[K, V]
27
- retriever_factory: (
28
- Callable[[R1], MaybeSequence[cbrkit.typing.RetrieverFunc[K, V, S]]] | None
29
- ) = None
30
- reuser_factory: (
31
- Callable[[R2], MaybeSequence[cbrkit.typing.ReuserFunc[K, V, S]]] | None
32
- ) = None
33
-
34
- def retrieve(
35
- self,
36
- query: V,
37
- parameters: R1,
38
- ) -> cbrkit.retrieval.QueryResultStep[K, V, S]:
39
- if not self.retriever_factory:
40
- raise ValueError("Retriever factory is not defined.")
41
-
42
- return cbrkit.retrieval.apply_query(
43
- self.casebase,
44
- query,
45
- self.retriever_factory(parameters),
46
- ).default_query
47
-
48
- def reuse(
49
- self,
50
- query: V,
51
- parameters: R2,
52
- ) -> cbrkit.retrieval.QueryResultStep[K, V, S]:
53
- if not self.reuser_factory:
54
- raise ValueError("Reuser factory is not defined.")
55
-
56
- return cbrkit.reuse.apply_query(
57
- self.casebase,
58
- query,
59
- self.reuser_factory(parameters),
60
- ).default_query
61
-
62
- def cycle(
63
- self,
64
- query: V,
65
- retrieve_parameters: R1,
66
- reuse_parameters: R2,
67
- ) -> cbrkit.retrieval.QueryResultStep[K, V, S]:
68
- if not self.retriever_factory or not self.reuser_factory:
69
- raise ValueError("Retriever or reuser factory is not defined.")
70
-
71
- return cbrkit.cycle.apply_query(
72
- self.casebase,
73
- query,
74
- self.retriever_factory(retrieve_parameters),
75
- self.reuser_factory(reuse_parameters),
76
- ).final_step.default_query
77
-
78
- @property
79
- def tools(self) -> list[Callable[..., Any]]:
80
- res: list[Callable[..., Any]] = []
81
-
82
- if self.retriever_factory:
83
- res.append(self.retrieve)
84
-
85
- if self.reuser_factory:
86
- res.append(self.reuse)
87
-
88
- if self.retriever_factory and self.reuser_factory:
89
- res.append(self.cycle)
90
-
91
- return res
92
-
93
- def get_case(self, name: K) -> V:
94
- return self.casebase[name]
95
-
96
- @property
97
- def resources(self) -> dict[str, Callable[..., Any]]:
98
- return {
99
- "casebase://{name}": self.get_case,
100
- }
101
-
102
- @property
103
- def prompts(self) -> list[Callable[..., Any]]:
104
- return []
105
-
106
-
107
- with cbrkit.helpers.optional_dependencies():
108
- from fastapi import APIRouter, FastAPI
109
-
110
- def to_fastapi[T: APIRouter | FastAPI](system: System, app: T) -> T:
111
- for value in system.tools:
112
- app.post(f"/tool/{value.__name__}")(value)
113
-
114
- for key, value in system.resources.items():
115
- app.get(f"/resource/{key.replace('://', '/')}")(value)
116
-
117
- for value in system.prompts:
118
- app.post(f"/prompt/{value.__name__}")(value)
119
-
120
- return app
121
-
122
-
123
- with cbrkit.helpers.optional_dependencies():
124
- from fastmcp import FastMCP
125
-
126
- def to_fastmcp[T: FastMCP](system: System, app: T) -> T:
127
- for value in system.tools:
128
- app.tool(value)
129
-
130
- for key, value in system.resources.items():
131
- app.resource(key)(value)
132
-
133
- for value in system.prompts:
134
- app.prompt(value)
135
-
136
- return app
137
-
138
-
139
- with cbrkit.helpers.optional_dependencies():
140
- from pydantic_ai.toolsets import FunctionToolset
141
-
142
- def to_pydantic_ai(system: System) -> FunctionToolset[None]:
143
- return FunctionToolset(system.tools)
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