pam-python 0.2.15__tar.gz → 0.2.16__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.
- {pam_python-0.2.15/pam_python.egg-info → pam_python-0.2.16}/PKG-INFO +1 -1
- {pam_python-0.2.15 → pam_python-0.2.16}/pam/__init__.py +1 -1
- {pam_python-0.2.15 → pam_python-0.2.16}/pam/task_manager.py +20 -5
- {pam_python-0.2.15 → pam_python-0.2.16/pam_python.egg-info}/PKG-INFO +1 -1
- {pam_python-0.2.15 → pam_python-0.2.16}/pam_python.egg-info/SOURCES.txt +1 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/tests/test_data_error_v2.py +44 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/tests/test_report_store.py +3 -1
- pam_python-0.2.16/tests/test_task_manager_upload_token.py +61 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/LICENSE.txt +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/README.md +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/pam/api.py +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/pam/cli.py +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/pam/datetime_utils.py +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/pam/interface_task_manager.py +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/pam/logger.py +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/pam/models/__init__.py +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/pam/models/data_input_v2.py +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/pam/models/request_command.py +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/pam/models/sqlite_download.py +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/pam/reports/__init__.py +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/pam/reports/area.py +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/pam/reports/axis.py +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/pam/reports/bar.py +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/pam/reports/box_plot.py +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/pam/reports/bubble.py +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/pam/reports/candlestick.py +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/pam/reports/collection.py +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/pam/reports/definition.py +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/pam/reports/donut.py +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/pam/reports/errors.py +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/pam/reports/fields.py +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/pam/reports/heatmap.py +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/pam/reports/line.py +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/pam/reports/manager.py +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/pam/reports/metric.py +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/pam/reports/pie.py +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/pam/reports/polar_area.py +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/pam/reports/radar.py +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/pam/reports/radial_bar.py +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/pam/reports/range_area.py +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/pam/reports/range_bar.py +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/pam/reports/range_transform.py +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/pam/reports/record.py +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/pam/reports/report.py +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/pam/reports/scatter.py +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/pam/reports/schema.py +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/pam/reports/store.py +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/pam/reports/table.py +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/pam/reports/temporal.py +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/pam/reports/transport.py +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/pam/reports/treemap.py +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/pam/request_file_format.py +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/pam/result_batch_uploader.py +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/pam/server.py +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/pam/service.py +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/pam/sqlite.py +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/pam/temp_file_utils.py +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/pam/templates/buildcmd/pamb +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/pam/templates/buildcmd/pamb-base.sh +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/pam/templates/init/AGENT.md +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/pam/templates/init/REPORTS-th.md +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/pam/templates/init/REPORTS.md +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/pam/templates/init/dockerignore.tmpl +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/pam/templates/init/gitignore.tmpl +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/pam/templates/init/main.tmpl +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/pam/templates/init/pylintrc.tmpl +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/pam/templates/init/run_unit_test.bat +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/pam/templates/init/run_unit_test.ps1 +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/pam/templates/init/run_unit_test.sh +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/pam/templates/project/pip/Dockerfile +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/pam/templates/project/pip/requirements.txt +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/pam/templates/project/uv/Dockerfile +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/pam/templates/project/uv/pyproject.toml +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/pam/templates/project/uv/python-version +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/pam/templates/service/common/service.yaml +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/pam/templates/service/pandas/functions.tmpl +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/pam/templates/service/pandas/service.test.tmpl +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/pam/templates/service/pandas/service_class.tmpl +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/pam/templates/service/polars/functions.tmpl +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/pam/templates/service/polars/service.test.tmpl +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/pam/templates/service/polars/service_class.tmpl +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/pam/tester_task.py +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/pam/utils.py +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/pam_python.egg-info/dependency_links.txt +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/pam_python.egg-info/entry_points.txt +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/pam_python.egg-info/requires.txt +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/pam_python.egg-info/top_level.txt +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/pyproject.toml +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/setup.cfg +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/tests/test_api.py +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/tests/test_cli_templates.py +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/tests/test_data_input_v2.py +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/tests/test_data_timeout_v2.py +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/tests/test_datetime_utils.py +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/tests/test_range_transform.py +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/tests/test_request_data_v2.py +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/tests/test_result_batch_uploader.py +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/tests/test_service_dataframe_output.py +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/tests/test_sqlite_download_v2.py +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/tests/test_temp_file_utils.py +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/tests/test_temporal_mode.py +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/tests/test_typed_area_report.py +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/tests/test_typed_bar_report.py +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/tests/test_typed_box_plot_report.py +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/tests/test_typed_bubble_report.py +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/tests/test_typed_candlestick_report.py +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/tests/test_typed_donut_report.py +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/tests/test_typed_heatmap_report.py +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/tests/test_typed_line_report.py +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/tests/test_typed_metric_report.py +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/tests/test_typed_pie_report.py +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/tests/test_typed_polar_area_report.py +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/tests/test_typed_radar_report.py +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/tests/test_typed_radial_bar_report.py +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/tests/test_typed_range_area_report.py +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/tests/test_typed_range_bar_report.py +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/tests/test_typed_scatter_report.py +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/tests/test_typed_table_report.py +0 -0
- {pam_python-0.2.15 → pam_python-0.2.16}/tests/test_typed_treemap_report.py +0 -0
|
@@ -258,8 +258,16 @@ class TaskManager(ITaskManager):
|
|
|
258
258
|
"""
|
|
259
259
|
log(f"Start Service: {service_name}, Token: {req.token}")
|
|
260
260
|
service_instance = service_class(self, req)
|
|
261
|
-
service_instance.on_start()
|
|
262
261
|
self._add_service(req.token, service_instance)
|
|
262
|
+
try:
|
|
263
|
+
# Register the service before on_start. A service commonly requests
|
|
264
|
+
# its first page from on_start, and PAM can deliver that page before
|
|
265
|
+
# on_start returns. Registering afterwards loses that callback and
|
|
266
|
+
# also lets on_dataset_input cancel the V2 wait timer permanently.
|
|
267
|
+
service_instance.on_start()
|
|
268
|
+
except BaseException:
|
|
269
|
+
self._remove_service(req.token)
|
|
270
|
+
raise
|
|
263
271
|
|
|
264
272
|
def terminate_service(self, token):
|
|
265
273
|
"""
|
|
@@ -419,9 +427,8 @@ class TaskManager(ITaskManager):
|
|
|
419
427
|
from its worker, so failures must propagate for retry handling.
|
|
420
428
|
"""
|
|
421
429
|
endpoint = service.request.response_api
|
|
422
|
-
payload =
|
|
430
|
+
payload = {"token": service.request.token}
|
|
423
431
|
if options is not None:
|
|
424
|
-
payload = {}
|
|
425
432
|
if "is_realtime" in options:
|
|
426
433
|
is_realtime = options.get("is_realtime")
|
|
427
434
|
payload["is_realtime"] = str(is_realtime).lower() if isinstance(is_realtime, bool) else is_realtime
|
|
@@ -464,7 +471,11 @@ class TaskManager(ITaskManager):
|
|
|
464
471
|
|
|
465
472
|
def upload_wrapper():
|
|
466
473
|
"""Wrapper for the report upload to handle response logging."""
|
|
467
|
-
response = self.api.http_upload(
|
|
474
|
+
response = self.api.http_upload(
|
|
475
|
+
endpoint,
|
|
476
|
+
file_path,
|
|
477
|
+
{"token": service.request.token},
|
|
478
|
+
)
|
|
468
479
|
handle_report_response(response)
|
|
469
480
|
|
|
470
481
|
log(f"Uploading Report to: {endpoint}")
|
|
@@ -501,7 +512,11 @@ class TaskManager(ITaskManager):
|
|
|
501
512
|
column_name: json.dumps(pointer, ensure_ascii=False, sort_keys=True),
|
|
502
513
|
})
|
|
503
514
|
|
|
504
|
-
response = self.api.http_upload(
|
|
515
|
+
response = self.api.http_upload(
|
|
516
|
+
service.request.response_api,
|
|
517
|
+
csv_path,
|
|
518
|
+
{"token": service.request.token},
|
|
519
|
+
)
|
|
505
520
|
if response is None:
|
|
506
521
|
return False
|
|
507
522
|
success = response.ok
|
|
@@ -94,6 +94,7 @@ tests/test_request_data_v2.py
|
|
|
94
94
|
tests/test_result_batch_uploader.py
|
|
95
95
|
tests/test_service_dataframe_output.py
|
|
96
96
|
tests/test_sqlite_download_v2.py
|
|
97
|
+
tests/test_task_manager_upload_token.py
|
|
97
98
|
tests/test_temp_file_utils.py
|
|
98
99
|
tests/test_temporal_mode.py
|
|
99
100
|
tests/test_typed_area_report.py
|
|
@@ -11,6 +11,50 @@ from pam.task_manager import TaskManager
|
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
class DataErrorV2Test(unittest.TestCase):
|
|
14
|
+
def test_start_service_registers_before_immediate_data_callback(self):
|
|
15
|
+
manager = TaskManager.__new__(TaskManager)
|
|
16
|
+
manager.thread_lock = threading.Lock()
|
|
17
|
+
manager.services = {}
|
|
18
|
+
manager.data_wait_timers = {}
|
|
19
|
+
request = Mock(token="run-1")
|
|
20
|
+
|
|
21
|
+
class ImmediateCallbackService:
|
|
22
|
+
def __init__(self, task_manager, req):
|
|
23
|
+
self.task_manager = task_manager
|
|
24
|
+
self.request = req
|
|
25
|
+
self.received = []
|
|
26
|
+
|
|
27
|
+
def on_start(self):
|
|
28
|
+
self.task_manager.on_dataset_input(self.request)
|
|
29
|
+
|
|
30
|
+
def on_data_input(self, req):
|
|
31
|
+
self.received.append(req)
|
|
32
|
+
|
|
33
|
+
manager.start_service(ImmediateCallbackService, request, "test-service")
|
|
34
|
+
|
|
35
|
+
service = manager.services[request.token].service
|
|
36
|
+
self.assertEqual([request], service.received)
|
|
37
|
+
|
|
38
|
+
def test_start_service_removes_registration_when_on_start_fails(self):
|
|
39
|
+
manager = TaskManager.__new__(TaskManager)
|
|
40
|
+
manager.thread_lock = threading.Lock()
|
|
41
|
+
manager.services = {}
|
|
42
|
+
manager.data_wait_timers = {}
|
|
43
|
+
|
|
44
|
+
service = Mock()
|
|
45
|
+
service.on_start.side_effect = RuntimeError("start failed")
|
|
46
|
+
service.request = Mock(service_name="test-service", token="run-1")
|
|
47
|
+
service.reports = Mock()
|
|
48
|
+
service_class = Mock(return_value=service)
|
|
49
|
+
request = Mock(token="run-1")
|
|
50
|
+
|
|
51
|
+
with self.assertRaisesRegex(RuntimeError, "start failed"):
|
|
52
|
+
manager.start_service(service_class, request, "test-service")
|
|
53
|
+
|
|
54
|
+
self.assertNotIn(request.token, manager.services)
|
|
55
|
+
service.on_destroy.assert_called_once_with()
|
|
56
|
+
service.reports.close.assert_called_once_with()
|
|
57
|
+
|
|
14
58
|
def test_request_command_parses_dataset_error_without_zip(self):
|
|
15
59
|
app = Flask(__name__)
|
|
16
60
|
with app.test_request_context(
|
|
@@ -496,8 +496,9 @@ class ReportStoreTransportTest(unittest.TestCase):
|
|
|
496
496
|
captured = {}
|
|
497
497
|
response = Mock(ok=True)
|
|
498
498
|
|
|
499
|
-
def capture_upload(endpoint, file_path):
|
|
499
|
+
def capture_upload(endpoint, file_path, payload):
|
|
500
500
|
captured["endpoint"] = endpoint
|
|
501
|
+
captured["payload"] = payload
|
|
501
502
|
with open(file_path, encoding="utf-8", newline="") as input_file:
|
|
502
503
|
captured["row"] = next(csv.DictReader(input_file))
|
|
503
504
|
return response
|
|
@@ -535,6 +536,7 @@ class ReportStoreTransportTest(unittest.TestCase):
|
|
|
535
536
|
|
|
536
537
|
self.assertTrue(published)
|
|
537
538
|
self.assertEqual(request.response_api, captured["endpoint"])
|
|
539
|
+
self.assertEqual({"token": "token-1"}, captured["payload"])
|
|
538
540
|
self.assertEqual("adapter-1", captured["row"]["customer"])
|
|
539
541
|
self.assertEqual("Customer Report Group", captured["row"]["_tracker_name"])
|
|
540
542
|
self.assertEqual(
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import tempfile
|
|
2
|
+
import unittest
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from types import SimpleNamespace
|
|
5
|
+
from unittest.mock import Mock
|
|
6
|
+
|
|
7
|
+
from pam.task_manager import TaskManager
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class TaskManagerUploadTokenTest(unittest.TestCase):
|
|
11
|
+
def setUp(self):
|
|
12
|
+
self.manager = TaskManager(SimpleNamespace())
|
|
13
|
+
self.manager.api = Mock()
|
|
14
|
+
self.service = SimpleNamespace(
|
|
15
|
+
request=SimpleNamespace(
|
|
16
|
+
response_api="http://pam/api/dataadapter/adapter-1/response",
|
|
17
|
+
token="token-1",
|
|
18
|
+
service_name="service-1",
|
|
19
|
+
),
|
|
20
|
+
)
|
|
21
|
+
self.response = Mock(ok=True)
|
|
22
|
+
self.response.json.return_value = {"code": "SUCCESS"}
|
|
23
|
+
self.manager.api.http_upload.return_value = self.response
|
|
24
|
+
|
|
25
|
+
def test_result_upload_always_sends_token_with_options(self):
|
|
26
|
+
with tempfile.TemporaryDirectory() as directory:
|
|
27
|
+
file_path = Path(directory) / "result.csv"
|
|
28
|
+
file_path.write_text("id\n1\n", encoding="utf-8")
|
|
29
|
+
|
|
30
|
+
self.manager.service_upload_result(
|
|
31
|
+
self.service,
|
|
32
|
+
str(file_path),
|
|
33
|
+
{"is_realtime": True, "is_priority": False},
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
self.manager.api.http_upload.assert_called_once_with(
|
|
37
|
+
self.service.request.response_api,
|
|
38
|
+
str(file_path),
|
|
39
|
+
{
|
|
40
|
+
"token": "token-1",
|
|
41
|
+
"is_realtime": "true",
|
|
42
|
+
"is_priority": "false",
|
|
43
|
+
},
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
def test_result_upload_sends_token_without_options(self):
|
|
47
|
+
with tempfile.TemporaryDirectory() as directory:
|
|
48
|
+
file_path = Path(directory) / "result.csv"
|
|
49
|
+
file_path.write_text("id\n1\n", encoding="utf-8")
|
|
50
|
+
|
|
51
|
+
self.manager.service_upload_result(self.service, str(file_path))
|
|
52
|
+
|
|
53
|
+
self.manager.api.http_upload.assert_called_once_with(
|
|
54
|
+
self.service.request.response_api,
|
|
55
|
+
str(file_path),
|
|
56
|
+
{"token": "token-1"},
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
if __name__ == "__main__":
|
|
61
|
+
unittest.main()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|