dbos 0.11.0a2__tar.gz → 0.11.0a4__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.
Potentially problematic release.
This version of dbos might be problematic. Click here for more details.
- {dbos-0.11.0a2 → dbos-0.11.0a4}/PKG-INFO +2 -2
- {dbos-0.11.0a2 → dbos-0.11.0a4}/dbos/cli.py +1 -10
- {dbos-0.11.0a2 → dbos-0.11.0a4}/dbos/dbos-config.schema.json +1 -2
- {dbos-0.11.0a2 → dbos-0.11.0a4}/dbos/dbos_config.py +21 -0
- {dbos-0.11.0a2 → dbos-0.11.0a4}/dbos/templates/hello/dbos-config.yaml.dbos +0 -1
- {dbos-0.11.0a2 → dbos-0.11.0a4}/pyproject.toml +2 -2
- {dbos-0.11.0a2 → dbos-0.11.0a4}/tests/test_config.py +92 -11
- {dbos-0.11.0a2 → dbos-0.11.0a4}/LICENSE +0 -0
- {dbos-0.11.0a2 → dbos-0.11.0a4}/README.md +0 -0
- {dbos-0.11.0a2 → dbos-0.11.0a4}/dbos/__init__.py +0 -0
- {dbos-0.11.0a2 → dbos-0.11.0a4}/dbos/admin_sever.py +0 -0
- {dbos-0.11.0a2 → dbos-0.11.0a4}/dbos/application_database.py +0 -0
- {dbos-0.11.0a2 → dbos-0.11.0a4}/dbos/context.py +0 -0
- {dbos-0.11.0a2 → dbos-0.11.0a4}/dbos/core.py +0 -0
- {dbos-0.11.0a2 → dbos-0.11.0a4}/dbos/dbos.py +0 -0
- {dbos-0.11.0a2 → dbos-0.11.0a4}/dbos/decorators.py +0 -0
- {dbos-0.11.0a2 → dbos-0.11.0a4}/dbos/error.py +0 -0
- {dbos-0.11.0a2 → dbos-0.11.0a4}/dbos/fastapi.py +0 -0
- {dbos-0.11.0a2 → dbos-0.11.0a4}/dbos/flask.py +0 -0
- {dbos-0.11.0a2 → dbos-0.11.0a4}/dbos/kafka.py +0 -0
- {dbos-0.11.0a2 → dbos-0.11.0a4}/dbos/kafka_message.py +0 -0
- {dbos-0.11.0a2 → dbos-0.11.0a4}/dbos/logger.py +0 -0
- {dbos-0.11.0a2 → dbos-0.11.0a4}/dbos/migrations/env.py +0 -0
- {dbos-0.11.0a2 → dbos-0.11.0a4}/dbos/migrations/script.py.mako +0 -0
- {dbos-0.11.0a2 → dbos-0.11.0a4}/dbos/migrations/versions/50f3227f0b4b_fix_job_queue.py +0 -0
- {dbos-0.11.0a2 → dbos-0.11.0a4}/dbos/migrations/versions/5c361fc04708_added_system_tables.py +0 -0
- {dbos-0.11.0a2 → dbos-0.11.0a4}/dbos/migrations/versions/a3b18ad34abe_added_triggers.py +0 -0
- {dbos-0.11.0a2 → dbos-0.11.0a4}/dbos/migrations/versions/d76646551a6b_job_queue_limiter.py +0 -0
- {dbos-0.11.0a2 → dbos-0.11.0a4}/dbos/migrations/versions/d76646551a6c_workflow_queue.py +0 -0
- {dbos-0.11.0a2 → dbos-0.11.0a4}/dbos/migrations/versions/eab0cc1d9a14_job_queue.py +0 -0
- {dbos-0.11.0a2 → dbos-0.11.0a4}/dbos/py.typed +0 -0
- {dbos-0.11.0a2 → dbos-0.11.0a4}/dbos/queue.py +0 -0
- {dbos-0.11.0a2 → dbos-0.11.0a4}/dbos/recovery.py +0 -0
- {dbos-0.11.0a2 → dbos-0.11.0a4}/dbos/registrations.py +0 -0
- {dbos-0.11.0a2 → dbos-0.11.0a4}/dbos/request.py +0 -0
- {dbos-0.11.0a2 → dbos-0.11.0a4}/dbos/roles.py +0 -0
- {dbos-0.11.0a2 → dbos-0.11.0a4}/dbos/scheduler/croniter.py +0 -0
- {dbos-0.11.0a2 → dbos-0.11.0a4}/dbos/scheduler/scheduler.py +0 -0
- {dbos-0.11.0a2 → dbos-0.11.0a4}/dbos/schemas/__init__.py +0 -0
- {dbos-0.11.0a2 → dbos-0.11.0a4}/dbos/schemas/application_database.py +0 -0
- {dbos-0.11.0a2 → dbos-0.11.0a4}/dbos/schemas/system_database.py +0 -0
- {dbos-0.11.0a2 → dbos-0.11.0a4}/dbos/system_database.py +0 -0
- {dbos-0.11.0a2 → dbos-0.11.0a4}/dbos/templates/hello/README.md +0 -0
- {dbos-0.11.0a2 → dbos-0.11.0a4}/dbos/templates/hello/__package/__init__.py +0 -0
- {dbos-0.11.0a2 → dbos-0.11.0a4}/dbos/templates/hello/__package/main.py +0 -0
- {dbos-0.11.0a2 → dbos-0.11.0a4}/dbos/templates/hello/__package/schema.py +0 -0
- {dbos-0.11.0a2 → dbos-0.11.0a4}/dbos/templates/hello/alembic.ini +0 -0
- {dbos-0.11.0a2 → dbos-0.11.0a4}/dbos/templates/hello/migrations/env.py.dbos +0 -0
- {dbos-0.11.0a2 → dbos-0.11.0a4}/dbos/templates/hello/migrations/script.py.mako +0 -0
- {dbos-0.11.0a2 → dbos-0.11.0a4}/dbos/templates/hello/migrations/versions/2024_07_31_180642_init.py +0 -0
- {dbos-0.11.0a2 → dbos-0.11.0a4}/dbos/templates/hello/start_postgres_docker.py +0 -0
- {dbos-0.11.0a2 → dbos-0.11.0a4}/dbos/tracer.py +0 -0
- {dbos-0.11.0a2 → dbos-0.11.0a4}/dbos/utils.py +0 -0
- {dbos-0.11.0a2 → dbos-0.11.0a4}/tests/__init__.py +0 -0
- {dbos-0.11.0a2 → dbos-0.11.0a4}/tests/atexit_no_ctor.py +0 -0
- {dbos-0.11.0a2 → dbos-0.11.0a4}/tests/atexit_no_launch.py +0 -0
- {dbos-0.11.0a2 → dbos-0.11.0a4}/tests/classdefs.py +0 -0
- {dbos-0.11.0a2 → dbos-0.11.0a4}/tests/conftest.py +0 -0
- {dbos-0.11.0a2 → dbos-0.11.0a4}/tests/more_classdefs.py +0 -0
- {dbos-0.11.0a2 → dbos-0.11.0a4}/tests/scheduler/test_croniter.py +0 -0
- {dbos-0.11.0a2 → dbos-0.11.0a4}/tests/scheduler/test_scheduler.py +0 -0
- {dbos-0.11.0a2 → dbos-0.11.0a4}/tests/test_admin_server.py +0 -0
- {dbos-0.11.0a2 → dbos-0.11.0a4}/tests/test_classdecorators.py +0 -0
- {dbos-0.11.0a2 → dbos-0.11.0a4}/tests/test_concurrency.py +0 -0
- {dbos-0.11.0a2 → dbos-0.11.0a4}/tests/test_dbos.py +0 -0
- {dbos-0.11.0a2 → dbos-0.11.0a4}/tests/test_failures.py +0 -0
- {dbos-0.11.0a2 → dbos-0.11.0a4}/tests/test_fastapi.py +0 -0
- {dbos-0.11.0a2 → dbos-0.11.0a4}/tests/test_fastapi_roles.py +0 -0
- {dbos-0.11.0a2 → dbos-0.11.0a4}/tests/test_flask.py +0 -0
- {dbos-0.11.0a2 → dbos-0.11.0a4}/tests/test_kafka.py +0 -0
- {dbos-0.11.0a2 → dbos-0.11.0a4}/tests/test_package.py +0 -0
- {dbos-0.11.0a2 → dbos-0.11.0a4}/tests/test_queue.py +0 -0
- {dbos-0.11.0a2 → dbos-0.11.0a4}/tests/test_schema_migration.py +0 -0
- {dbos-0.11.0a2 → dbos-0.11.0a4}/tests/test_singleton.py +0 -0
- {dbos-0.11.0a2 → dbos-0.11.0a4}/version/__init__.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: dbos
|
|
3
|
-
Version: 0.11.
|
|
3
|
+
Version: 0.11.0a4
|
|
4
4
|
Summary: Ultra-lightweight durable execution in Python
|
|
5
5
|
Author-Email: "DBOS, Inc." <contact@dbos.dev>
|
|
6
6
|
License: MIT
|
|
@@ -18,7 +18,7 @@ Requires-Dist: python-dateutil>=2.9.0.post0
|
|
|
18
18
|
Requires-Dist: fastapi[standard]>=0.115.2
|
|
19
19
|
Requires-Dist: psutil>=6.0.0
|
|
20
20
|
Requires-Dist: tomlkit>=0.13.2
|
|
21
|
-
Requires-Dist: psycopg>=3.1
|
|
21
|
+
Requires-Dist: psycopg[binary]>=3.1
|
|
22
22
|
Description-Content-Type: text/markdown
|
|
23
23
|
|
|
24
24
|
|
|
@@ -17,6 +17,7 @@ from typing_extensions import Annotated
|
|
|
17
17
|
|
|
18
18
|
from dbos import load_config
|
|
19
19
|
from dbos.application_database import ApplicationDatabase
|
|
20
|
+
from dbos.dbos_config import is_valid_app_name
|
|
20
21
|
from dbos.system_database import SystemDatabase
|
|
21
22
|
|
|
22
23
|
app = typer.Typer()
|
|
@@ -125,11 +126,9 @@ def copy_template(src_dir: str, project_name: str, config_mode: bool) -> None:
|
|
|
125
126
|
dst_dir = path.abspath(".")
|
|
126
127
|
|
|
127
128
|
package_name = project_name.replace("-", "_")
|
|
128
|
-
db_name = package_name if not package_name[0].isdigit() else f"_{package_name}"
|
|
129
129
|
ctx = {
|
|
130
130
|
"project_name": project_name,
|
|
131
131
|
"package_name": package_name,
|
|
132
|
-
"db_name": db_name,
|
|
133
132
|
"migration_command": "alembic upgrade head",
|
|
134
133
|
}
|
|
135
134
|
|
|
@@ -167,14 +166,6 @@ def get_project_name() -> typing.Union[str, None]:
|
|
|
167
166
|
return name
|
|
168
167
|
|
|
169
168
|
|
|
170
|
-
def is_valid_app_name(name: str) -> bool:
|
|
171
|
-
name_len = len(name)
|
|
172
|
-
if name_len < 3 or name_len > 30:
|
|
173
|
-
return False
|
|
174
|
-
match = re.match("^[a-z0-9-_]+$", name)
|
|
175
|
-
return True if match != None else False
|
|
176
|
-
|
|
177
|
-
|
|
178
169
|
@app.command()
|
|
179
170
|
def init(
|
|
180
171
|
project_name: Annotated[
|
|
@@ -167,6 +167,14 @@ def load_config(config_file_path: str = "dbos-config.yaml") -> ConfigFile:
|
|
|
167
167
|
|
|
168
168
|
data = cast(ConfigFile, data)
|
|
169
169
|
|
|
170
|
+
if not is_valid_app_name(data["name"]):
|
|
171
|
+
raise DBOSInitializationError(
|
|
172
|
+
f'Invalid app name {data["name"]}. App names must be between 3 and 30 characters and contain only alphanumeric characters, dashes, and underscores.'
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
if "app_db_name" not in data["database"]:
|
|
176
|
+
data["database"]["app_db_name"] = app_name_to_db_name(data["name"])
|
|
177
|
+
|
|
170
178
|
if "local_suffix" in data["database"] and data["database"]["local_suffix"]:
|
|
171
179
|
data["database"]["app_db_name"] = f"{data['database']['app_db_name']}_local"
|
|
172
180
|
|
|
@@ -174,6 +182,19 @@ def load_config(config_file_path: str = "dbos-config.yaml") -> ConfigFile:
|
|
|
174
182
|
return data # type: ignore
|
|
175
183
|
|
|
176
184
|
|
|
185
|
+
def is_valid_app_name(name: str) -> bool:
|
|
186
|
+
name_len = len(name)
|
|
187
|
+
if name_len < 3 or name_len > 30:
|
|
188
|
+
return False
|
|
189
|
+
match = re.match("^[a-z0-9-_]+$", name)
|
|
190
|
+
return True if match != None else False
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
def app_name_to_db_name(app_name: str) -> str:
|
|
194
|
+
name = app_name.replace("-", "_")
|
|
195
|
+
return name if not name[0].isdigit() else f"_{name}"
|
|
196
|
+
|
|
197
|
+
|
|
177
198
|
def set_env_vars(config: ConfigFile) -> None:
|
|
178
199
|
for env, value in config.get("env", {}).items():
|
|
179
200
|
if value is not None:
|
|
@@ -19,11 +19,11 @@ dependencies = [
|
|
|
19
19
|
"fastapi[standard]>=0.115.2",
|
|
20
20
|
"psutil>=6.0.0",
|
|
21
21
|
"tomlkit>=0.13.2",
|
|
22
|
-
"psycopg>=3.1",
|
|
22
|
+
"psycopg[binary]>=3.1",
|
|
23
23
|
]
|
|
24
24
|
requires-python = ">=3.9"
|
|
25
25
|
readme = "README.md"
|
|
26
|
-
version = "0.11.
|
|
26
|
+
version = "0.11.0a4"
|
|
27
27
|
|
|
28
28
|
[project.license]
|
|
29
29
|
text = "MIT"
|
|
@@ -27,7 +27,7 @@ def generate_mock_open(filename, mock_data):
|
|
|
27
27
|
|
|
28
28
|
def test_valid_config(mocker):
|
|
29
29
|
mock_config = """
|
|
30
|
-
name: "some
|
|
30
|
+
name: "some-app"
|
|
31
31
|
language: "python"
|
|
32
32
|
runtimeConfig:
|
|
33
33
|
start:
|
|
@@ -51,7 +51,7 @@ def test_valid_config(mocker):
|
|
|
51
51
|
)
|
|
52
52
|
|
|
53
53
|
configFile = load_config(mock_filename)
|
|
54
|
-
assert configFile["name"] == "some
|
|
54
|
+
assert configFile["name"] == "some-app"
|
|
55
55
|
assert configFile["language"] == "python"
|
|
56
56
|
assert configFile["database"]["hostname"] == "some host"
|
|
57
57
|
assert configFile["database"]["port"] == 1234
|
|
@@ -68,11 +68,34 @@ def test_valid_config(mocker):
|
|
|
68
68
|
assert "bob" not in os.environ
|
|
69
69
|
|
|
70
70
|
|
|
71
|
-
def
|
|
71
|
+
def test_valid_config_without_appdbname(mocker):
|
|
72
72
|
mock_config = """
|
|
73
|
-
name: "some
|
|
73
|
+
name: "some-app"
|
|
74
|
+
language: "python"
|
|
75
|
+
runtimeConfig:
|
|
76
|
+
start:
|
|
77
|
+
- "python3 main.py"
|
|
78
|
+
admin_port: 8001
|
|
74
79
|
database:
|
|
75
80
|
hostname: 'some host'
|
|
81
|
+
port: 1234
|
|
82
|
+
username: 'some user'
|
|
83
|
+
password: ${PGPASSWORD}
|
|
84
|
+
connectionTimeoutMillis: 3000
|
|
85
|
+
"""
|
|
86
|
+
os.environ["BARBAR"] = "FOOFOO"
|
|
87
|
+
mocker.patch(
|
|
88
|
+
"builtins.open", side_effect=generate_mock_open(mock_filename, mock_config)
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
configFile = load_config(mock_filename)
|
|
92
|
+
assert configFile["database"]["app_db_name"] == "some_app"
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def test_config_missing_params(mocker):
|
|
96
|
+
mock_config = """
|
|
97
|
+
name: "some-app"
|
|
98
|
+
database:
|
|
76
99
|
port: 1234
|
|
77
100
|
username: 'some user'
|
|
78
101
|
password: abc123
|
|
@@ -85,12 +108,12 @@ def test_config_missing_params(mocker):
|
|
|
85
108
|
with pytest.raises(DBOSInitializationError) as exc_info:
|
|
86
109
|
load_config(mock_filename)
|
|
87
110
|
|
|
88
|
-
assert "'
|
|
111
|
+
assert "'hostname' is a required property" in str(exc_info.value)
|
|
89
112
|
|
|
90
113
|
|
|
91
114
|
def test_config_extra_params(mocker):
|
|
92
115
|
mock_config = """
|
|
93
|
-
name: "some
|
|
116
|
+
name: "some-app"
|
|
94
117
|
database:
|
|
95
118
|
hostname: 'some host'
|
|
96
119
|
port: 1234
|
|
@@ -136,7 +159,7 @@ def test_config_missing_name(mocker):
|
|
|
136
159
|
|
|
137
160
|
def test_config_missing_language(mocker):
|
|
138
161
|
mock_config = """
|
|
139
|
-
name: "some
|
|
162
|
+
name: "some-app"
|
|
140
163
|
database:
|
|
141
164
|
hostname: 'some host'
|
|
142
165
|
port: 1234
|
|
@@ -157,7 +180,7 @@ def test_config_missing_language(mocker):
|
|
|
157
180
|
|
|
158
181
|
def test_config_bad_language(mocker):
|
|
159
182
|
mock_config = """
|
|
160
|
-
name: "some
|
|
183
|
+
name: "some-app"
|
|
161
184
|
language: typescript
|
|
162
185
|
database:
|
|
163
186
|
hostname: 'some host'
|
|
@@ -177,10 +200,35 @@ def test_config_bad_language(mocker):
|
|
|
177
200
|
assert "invalid language" in str(exc_info.value)
|
|
178
201
|
|
|
179
202
|
|
|
180
|
-
def
|
|
203
|
+
def test_config_bad_name(mocker):
|
|
181
204
|
mock_config = """
|
|
182
205
|
name: "some app"
|
|
183
206
|
language: python
|
|
207
|
+
runtimeConfig:
|
|
208
|
+
start:
|
|
209
|
+
- "python3 main.py"
|
|
210
|
+
database:
|
|
211
|
+
hostname: 'some host'
|
|
212
|
+
port: 1234
|
|
213
|
+
username: 'some user'
|
|
214
|
+
password: abc123
|
|
215
|
+
app_db_name: 'some db'
|
|
216
|
+
connectionTimeoutMillis: 3000
|
|
217
|
+
"""
|
|
218
|
+
mocker.patch(
|
|
219
|
+
"builtins.open", side_effect=generate_mock_open(mock_filename, mock_config)
|
|
220
|
+
)
|
|
221
|
+
|
|
222
|
+
with pytest.raises(DBOSInitializationError) as exc_info:
|
|
223
|
+
load_config(mock_filename)
|
|
224
|
+
|
|
225
|
+
assert "Invalid app name" in str(exc_info.value)
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
def test_config_no_start(mocker):
|
|
229
|
+
mock_config = """
|
|
230
|
+
name: "some-app"
|
|
231
|
+
language: python
|
|
184
232
|
database:
|
|
185
233
|
hostname: 'some host'
|
|
186
234
|
port: 1234
|
|
@@ -201,7 +249,7 @@ def test_config_no_start(mocker):
|
|
|
201
249
|
|
|
202
250
|
def test_local_config(mocker):
|
|
203
251
|
mock_config = """
|
|
204
|
-
name: "some
|
|
252
|
+
name: "some-app"
|
|
205
253
|
language: "python"
|
|
206
254
|
runtimeConfig:
|
|
207
255
|
start:
|
|
@@ -222,7 +270,7 @@ def test_local_config(mocker):
|
|
|
222
270
|
)
|
|
223
271
|
|
|
224
272
|
configFile = load_config(mock_filename)
|
|
225
|
-
assert configFile["name"] == "some
|
|
273
|
+
assert configFile["name"] == "some-app"
|
|
226
274
|
assert configFile["database"]["local_suffix"] == True
|
|
227
275
|
assert configFile["language"] == "python"
|
|
228
276
|
assert configFile["database"]["hostname"] == "some host"
|
|
@@ -231,3 +279,36 @@ def test_local_config(mocker):
|
|
|
231
279
|
assert configFile["database"]["password"] == os.environ["PGPASSWORD"]
|
|
232
280
|
assert configFile["database"]["app_db_name"] == "some_db_local"
|
|
233
281
|
assert configFile["database"]["connectionTimeoutMillis"] == 3000
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
def test_local_config_without_name(mocker):
|
|
285
|
+
mock_config = """
|
|
286
|
+
name: "some-app"
|
|
287
|
+
language: "python"
|
|
288
|
+
runtimeConfig:
|
|
289
|
+
start:
|
|
290
|
+
- "python3 main.py"
|
|
291
|
+
admin_port: 8001
|
|
292
|
+
database:
|
|
293
|
+
hostname: 'some host'
|
|
294
|
+
port: 1234
|
|
295
|
+
username: 'some user'
|
|
296
|
+
password: ${PGPASSWORD}
|
|
297
|
+
connectionTimeoutMillis: 3000
|
|
298
|
+
local_suffix: true
|
|
299
|
+
"""
|
|
300
|
+
os.environ["BARBAR"] = "FOOFOO"
|
|
301
|
+
mocker.patch(
|
|
302
|
+
"builtins.open", side_effect=generate_mock_open(mock_filename, mock_config)
|
|
303
|
+
)
|
|
304
|
+
|
|
305
|
+
configFile = load_config(mock_filename)
|
|
306
|
+
assert configFile["name"] == "some-app"
|
|
307
|
+
assert configFile["database"]["local_suffix"] == True
|
|
308
|
+
assert configFile["language"] == "python"
|
|
309
|
+
assert configFile["database"]["hostname"] == "some host"
|
|
310
|
+
assert configFile["database"]["port"] == 1234
|
|
311
|
+
assert configFile["database"]["username"] == "some user"
|
|
312
|
+
assert configFile["database"]["password"] == os.environ["PGPASSWORD"]
|
|
313
|
+
assert configFile["database"]["app_db_name"] == "some_app_local"
|
|
314
|
+
assert configFile["database"]["connectionTimeoutMillis"] == 3000
|
|
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
|
{dbos-0.11.0a2 → dbos-0.11.0a4}/dbos/migrations/versions/5c361fc04708_added_system_tables.py
RENAMED
|
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
|
{dbos-0.11.0a2 → dbos-0.11.0a4}/dbos/templates/hello/migrations/versions/2024_07_31_180642_init.py
RENAMED
|
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
|