openmodule 18.0.1__tar.gz → 18.1.0__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.
- {openmodule-18.0.1 → openmodule-18.1.0}/PKG-INFO +2 -2
- {openmodule-18.0.1 → openmodule-18.1.0}/openmodule/database/database.py +3 -4
- {openmodule-18.0.1 → openmodule-18.1.0}/openmodule/database/migration.py +48 -7
- {openmodule-18.0.1 → openmodule-18.1.0}/openmodule.egg-info/PKG-INFO +2 -2
- {openmodule-18.0.1 → openmodule-18.1.0}/openmodule.egg-info/requires.txt +1 -1
- {openmodule-18.0.1 → openmodule-18.1.0}/tests/test_database.py +37 -2
- {openmodule-18.0.1 → openmodule-18.1.0}/LICENSE +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/README.md +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/openmodule/__init__.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/openmodule/alert.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/openmodule/config.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/openmodule/connection_status.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/openmodule/core.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/openmodule/database/__init__.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/openmodule/database/custom_types.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/openmodule/database/env.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/openmodule/dispatcher.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/openmodule/health.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/openmodule/logging.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/openmodule/messaging.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/openmodule/models/__init__.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/openmodule/models/access_service.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/openmodule/models/alert.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/openmodule/models/base.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/openmodule/models/io.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/openmodule/models/kv_store.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/openmodule/models/pagination.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/openmodule/models/presence.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/openmodule/models/privacy.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/openmodule/models/rpc.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/openmodule/models/settings.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/openmodule/models/signals.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/openmodule/models/validation.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/openmodule/models/vehicle.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/openmodule/models/vehicle_listener.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/openmodule/rpc/__init__.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/openmodule/rpc/client.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/openmodule/rpc/common.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/openmodule/rpc/server.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/openmodule/sentry.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/openmodule/threading.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/openmodule/utils/__init__.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/openmodule/utils/access_service.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/openmodule/utils/charset.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/openmodule/utils/cleanup.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/openmodule/utils/csv_export.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/openmodule/utils/databox.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/openmodule/utils/db_helper.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/openmodule/utils/eventlog.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/openmodule/utils/io.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/openmodule/utils/kv_store.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/openmodule/utils/matching.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/openmodule/utils/misc_functions.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/openmodule/utils/package_reader.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/openmodule/utils/pagination.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/openmodule/utils/presence.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/openmodule/utils/schedule.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/openmodule/utils/settings.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/openmodule/utils/signal_listener.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/openmodule/utils/translation.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/openmodule/utils/validation.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/openmodule/utils/vehicle_listener.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/openmodule.egg-info/SOURCES.txt +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/openmodule.egg-info/dependency_links.txt +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/openmodule.egg-info/not-zip-safe +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/openmodule.egg-info/top_level.txt +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/setup.cfg +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/setup.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/tests/test_alembic_migrations.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/tests/test_alert.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/tests/test_checks.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/tests/test_config.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/tests/test_connection_status.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/tests/test_core.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/tests/test_dispatcher.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/tests/test_health.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/tests/test_interrupt.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/tests/test_io_listen.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/tests/test_logging.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/tests/test_messaging.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/tests/test_mockrpcclient.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/tests/test_model.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/tests/test_rpc.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/tests/test_sentry.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/tests/test_test_alert.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/tests/test_test_gate.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/tests/test_test_zeromq.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/tests/test_utils_access_service.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/tests/test_utils_charset.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/tests/test_utils_cleanup.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/tests/test_utils_csv_export.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/tests/test_utils_databox.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/tests/test_utils_eventlog.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/tests/test_utils_kv_store.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/tests/test_utils_kv_store_multiple.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/tests/test_utils_matching.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/tests/test_utils_misc_functions.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/tests/test_utils_package_reader.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/tests/test_utils_pagination.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/tests/test_utils_presence.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/tests/test_utils_schedule.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/tests/test_utils_settings.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/tests/test_utils_signal.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/tests/test_utils_validation.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/tests/test_utils_vehicle.py +0 -0
- {openmodule-18.0.1 → openmodule-18.1.0}/tests/test_vehicle_listener.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: openmodule
|
|
3
|
-
Version: 18.0
|
|
3
|
+
Version: 18.1.0
|
|
4
4
|
Summary: Libraries for developing the arivo openmodule
|
|
5
5
|
Home-page: https://gitlab.com/arivo-public/device-python/openmodule.git
|
|
6
6
|
Author: ARIVO
|
|
@@ -20,7 +20,7 @@ Requires-Dist: pyzmq~=26.2
|
|
|
20
20
|
Requires-Dist: pyyaml<7,>=5.0
|
|
21
21
|
Requires-Dist: editdistance~=0.8.1
|
|
22
22
|
Requires-Dist: sqlalchemy~=2.0.0
|
|
23
|
-
Requires-Dist: alembic
|
|
23
|
+
Requires-Dist: alembic~=1.18.4
|
|
24
24
|
Requires-Dist: requests<3,>=2.22
|
|
25
25
|
Requires-Dist: python-dateutil~=2.9
|
|
26
26
|
Requires-Dist: python-dotenv~=1.2.0
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import threading
|
|
3
|
+
import traceback
|
|
3
4
|
import types
|
|
5
|
+
from multiprocessing import Process, Pipe, ProcessError
|
|
4
6
|
from typing import Optional, Tuple
|
|
5
7
|
|
|
6
8
|
from sqlalchemy import create_engine, event
|
|
@@ -8,11 +10,8 @@ from sqlalchemy.engine import Engine
|
|
|
8
10
|
from sqlalchemy.orm import sessionmaker, Session
|
|
9
11
|
from sqlalchemy.pool import StaticPool
|
|
10
12
|
|
|
11
|
-
from multiprocessing import Process, Pipe, ProcessError
|
|
12
|
-
import traceback
|
|
13
|
-
|
|
14
13
|
|
|
15
|
-
class MigrationError(
|
|
14
|
+
class MigrationError(Exception):
|
|
16
15
|
# Exception wrapper to create exception with traceback from child process
|
|
17
16
|
pass
|
|
18
17
|
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import shutil
|
|
3
3
|
import sys
|
|
4
|
+
import time
|
|
4
5
|
import warnings
|
|
5
|
-
from
|
|
6
|
+
from glob import glob
|
|
6
7
|
|
|
7
8
|
from alembic import command, context
|
|
8
9
|
from alembic.autogenerate import comparators, renderers
|
|
9
10
|
from alembic.config import Config
|
|
10
11
|
from alembic.operations import Operations, MigrateOperation
|
|
11
12
|
from alembic.runtime.migration import MigrationContext
|
|
13
|
+
from alembic.util.langhelpers import DispatchPriority
|
|
12
14
|
from sqlalchemy import MetaData, DateTime, inspect, text
|
|
13
15
|
from sqlalchemy.engine import Engine
|
|
14
16
|
|
|
@@ -114,26 +116,32 @@ def post_downgrade(operations, operation):
|
|
|
114
116
|
|
|
115
117
|
|
|
116
118
|
@renderers.dispatch_for(PreUpgradeOp)
|
|
117
|
-
def
|
|
119
|
+
def render_pre_upgrade(autogen_context, op):
|
|
118
120
|
return "op.pre_upgrade()"
|
|
119
121
|
|
|
120
122
|
|
|
121
123
|
@renderers.dispatch_for(PreDowngradeOp)
|
|
122
|
-
def
|
|
124
|
+
def render_pre_downgrade(autogen_context, op):
|
|
123
125
|
return "op.pre_downgrade()"
|
|
124
126
|
|
|
125
127
|
|
|
126
128
|
@renderers.dispatch_for(PostUpgradeOp)
|
|
127
|
-
def
|
|
129
|
+
def render_post_upgrade(autogen_context, op):
|
|
128
130
|
return "op.post_upgrade()"
|
|
129
131
|
|
|
130
132
|
|
|
131
133
|
@renderers.dispatch_for(PostDowngradeOp)
|
|
132
|
-
def
|
|
134
|
+
def render_post_downgrade(autogen_context, op):
|
|
133
135
|
return "op.post_downgrade()"
|
|
134
136
|
|
|
135
137
|
|
|
136
|
-
|
|
138
|
+
# Copilot found this issue:
|
|
139
|
+
# The default priority is MEDIUM, which means our `add_pre_upgrade_hooks`
|
|
140
|
+
# has the same priority as the built-in comparators.
|
|
141
|
+
# As a result, this routine was executed before the built-in comparators,
|
|
142
|
+
# at a time when `upgrade_ops.ops` was still empty.
|
|
143
|
+
# Therefore, no custom operations were available and no render function was called.
|
|
144
|
+
@comparators.dispatch_for("schema", priority=DispatchPriority.LAST)
|
|
137
145
|
def add_pre_upgrade_hooks(autogen_context, upgrade_ops, schemas):
|
|
138
146
|
# only add those if any operations exist, otherwise we always have changes
|
|
139
147
|
if len(upgrade_ops.ops):
|
|
@@ -151,10 +159,43 @@ def alembic_config(connection: Engine, alembic_path: str):
|
|
|
151
159
|
return alembic_cfg
|
|
152
160
|
|
|
153
161
|
|
|
154
|
-
def
|
|
162
|
+
def validate_migration_files(alembic_path: str) -> bool:
|
|
163
|
+
"""
|
|
164
|
+
This validation function is the final defense line against the problem from CORE-1593.
|
|
165
|
+
We do not apply any migration without our custom auto generated operations.
|
|
166
|
+
Because we need those operations to prevent data loss because of the foreign key behavior of SQLite.
|
|
167
|
+
|
|
168
|
+
This function raises a `ValueError` if a migration file is incorrect.
|
|
169
|
+
"""
|
|
170
|
+
migration_folder = os.path.join(alembic_path, "alembic/versions/")
|
|
171
|
+
assert os.path.exists(os.path.abspath(migration_folder)), \
|
|
172
|
+
f"migration folder {os.path.abspath(migration_folder)} does not exist"
|
|
173
|
+
py_files = glob(os.path.join(migration_folder, "*.py"))
|
|
174
|
+
assert len(py_files) > 0, f"no python files found in {migration_folder}"
|
|
175
|
+
for py_file in glob(os.path.join(migration_folder, "*.py")):
|
|
176
|
+
if os.path.basename(py_file) == "__init__.py":
|
|
177
|
+
continue
|
|
178
|
+
with open(py_file) as f:
|
|
179
|
+
file_content = f.read()
|
|
180
|
+
if not all(op in file_content for op in ["op.pre_upgrade()", "op.pre_downgrade()",
|
|
181
|
+
"op.pre_downgrade()", "op.post_downgrade()"]):
|
|
182
|
+
# We introduce a short sleep here because all services enter a crashing state,
|
|
183
|
+
# when the migrations are broken.
|
|
184
|
+
# With Docker's "restart: always" policy, it continuously tries to restart
|
|
185
|
+
# failing processes as fast as possible, which can lead to 100% CPU usage.
|
|
186
|
+
time.sleep(3)
|
|
187
|
+
raise ValueError("Not applying broken migration files! Our custom migration operations "
|
|
188
|
+
f"are not in the migration file {os.path.basename(py_file)}. "
|
|
189
|
+
"Please regenerate them with the correct alembic version from the Openmodule. "
|
|
190
|
+
"For more information see CORE-1593.")
|
|
191
|
+
return True
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
def migrate_database(engine: Engine, alembic_path: str | None = None):
|
|
155
195
|
if alembic_path is None:
|
|
156
196
|
alembic_path = os.path.join(os.getcwd(), "database")
|
|
157
197
|
assert os.path.exists(os.path.abspath(alembic_path)), f"alembic path {os.path.abspath(alembic_path)} does not exist"
|
|
198
|
+
validate_migration_files(alembic_path)
|
|
158
199
|
config = alembic_config(engine, alembic_path)
|
|
159
200
|
command.upgrade(config, "head")
|
|
160
201
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: openmodule
|
|
3
|
-
Version: 18.0
|
|
3
|
+
Version: 18.1.0
|
|
4
4
|
Summary: Libraries for developing the arivo openmodule
|
|
5
5
|
Home-page: https://gitlab.com/arivo-public/device-python/openmodule.git
|
|
6
6
|
Author: ARIVO
|
|
@@ -20,7 +20,7 @@ Requires-Dist: pyzmq~=26.2
|
|
|
20
20
|
Requires-Dist: pyyaml<7,>=5.0
|
|
21
21
|
Requires-Dist: editdistance~=0.8.1
|
|
22
22
|
Requires-Dist: sqlalchemy~=2.0.0
|
|
23
|
-
Requires-Dist: alembic
|
|
23
|
+
Requires-Dist: alembic~=1.18.4
|
|
24
24
|
Requires-Dist: requests<3,>=2.22
|
|
25
25
|
Requires-Dist: python-dateutil~=2.9
|
|
26
26
|
Requires-Dist: python-dotenv~=1.2.0
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import os
|
|
2
|
+
import shutil
|
|
2
3
|
import time
|
|
4
|
+
from glob import glob
|
|
5
|
+
from tempfile import TemporaryDirectory
|
|
3
6
|
from threading import Thread
|
|
4
|
-
from unittest import TestCase
|
|
7
|
+
from unittest import TestCase, mock
|
|
5
8
|
from unittest.mock import patch
|
|
6
9
|
|
|
7
10
|
import freezegun
|
|
@@ -13,7 +16,7 @@ from sqlalchemy.orm.exc import NoResultFound, MultipleResultsFound, DetachedInst
|
|
|
13
16
|
|
|
14
17
|
from openmodule.config import settings
|
|
15
18
|
from openmodule.database.database import Database, active_databases, database_path, MigrationError
|
|
16
|
-
from openmodule.database.migration import alembic_config
|
|
19
|
+
from openmodule.database.migration import alembic_config, validate_migration_files
|
|
17
20
|
from openmodule.utils.db_helper import update_query, delete_query
|
|
18
21
|
from openmodule_test.database import SQLiteTestMixin
|
|
19
22
|
from tests.database_models_migration import DatabaseCascadeDeleteParentModel, DatabaseCascadeDeleteChildModel
|
|
@@ -458,3 +461,35 @@ class DatabaseMigrationProcessFailTest(TestCase):
|
|
|
458
461
|
with patch("openmodule.database.database.MigrationProcess.join", side_effect=TimeoutError), \
|
|
459
462
|
self.assertRaises(TimeoutError):
|
|
460
463
|
_ = Database(self.get_database_folder(), alembic_path=alembic_path)
|
|
464
|
+
|
|
465
|
+
|
|
466
|
+
class MigrationFileValidationTestCase(TestCase):
|
|
467
|
+
def test_alembic_version_folder_does_not_exist(self):
|
|
468
|
+
with self.assertRaises(AssertionError) as cm:
|
|
469
|
+
validate_migration_files("/does/not/exist")
|
|
470
|
+
self.assertEqual("migration folder /does/not/exist/alembic/versions does not exist", str(cm.exception))
|
|
471
|
+
|
|
472
|
+
def test_no_python_file_are_available(self):
|
|
473
|
+
td = TemporaryDirectory(prefix="__openmodule_test_case__")
|
|
474
|
+
shutil.copytree("../tests/migration_file_broken", td.name, dirs_exist_ok=True)
|
|
475
|
+
migration_folder = os.path.join(td.name, "alembic/versions/")
|
|
476
|
+
py_files = glob(os.path.join(migration_folder, "*.py"))
|
|
477
|
+
for py_file in py_files:
|
|
478
|
+
os.unlink(py_file)
|
|
479
|
+
with self.assertRaises(AssertionError) as cm:
|
|
480
|
+
validate_migration_files(td.name)
|
|
481
|
+
self.assertIn("no python files found in /tmp/__openmodule_test_case__", str(cm.exception))
|
|
482
|
+
|
|
483
|
+
@mock.patch("openmodule.database.migration.time.sleep")
|
|
484
|
+
def test_validation_throw_value_error_for_broken_migration_file(self, time_sleep_mock: mock.MagicMock):
|
|
485
|
+
with self.assertRaises(ValueError) as cm:
|
|
486
|
+
validate_migration_files("../tests/migration_file_broken")
|
|
487
|
+
time_sleep_mock.assert_called_once()
|
|
488
|
+
self.assertEqual("Not applying broken migration files! "
|
|
489
|
+
"Our custom migration operations are not in the migration file 46b275099a0d_initial.py. "
|
|
490
|
+
"Please regenerate them with the correct alembic version from the Openmodule. "
|
|
491
|
+
"For more information see CORE-1593.", str(cm.exception))
|
|
492
|
+
|
|
493
|
+
def test_validation_does_not_throw_value_error_for_correct_migration_file(self):
|
|
494
|
+
result = validate_migration_files("../tests/migration_test_database")
|
|
495
|
+
self.assertTrue(result)
|
|
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
|
|
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
|