anysite-cli 0.1.5__tar.gz → 0.1.6__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.
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/PKG-INFO +1 -1
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/pyproject.toml +1 -1
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/src/anysite/dataset/db_loader.py +10 -3
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/tests/test_dataset/test_db_loader.py +98 -1
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/.claude/settings.local.json +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/.gitignore +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/CLAUDE.md +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/LICENSE +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/README.md +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/skills/anysite-cli/SKILL.md +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/skills/anysite-cli/references/api-reference.md +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/skills/anysite-cli/references/dataset-guide.md +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/src/anysite/__init__.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/src/anysite/__main__.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/src/anysite/api/__init__.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/src/anysite/api/client.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/src/anysite/api/errors.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/src/anysite/api/schemas.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/src/anysite/batch/__init__.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/src/anysite/batch/executor.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/src/anysite/batch/input.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/src/anysite/batch/rate_limiter.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/src/anysite/cli/__init__.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/src/anysite/cli/config.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/src/anysite/cli/executor.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/src/anysite/cli/options.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/src/anysite/config/__init__.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/src/anysite/config/paths.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/src/anysite/config/settings.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/src/anysite/dataset/__init__.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/src/anysite/dataset/analyzer.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/src/anysite/dataset/cli.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/src/anysite/dataset/collector.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/src/anysite/dataset/differ.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/src/anysite/dataset/errors.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/src/anysite/dataset/exporters.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/src/anysite/dataset/history.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/src/anysite/dataset/models.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/src/anysite/dataset/notifications.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/src/anysite/dataset/scheduler.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/src/anysite/dataset/storage.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/src/anysite/dataset/transformer.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/src/anysite/db/__init__.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/src/anysite/db/adapters/__init__.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/src/anysite/db/adapters/base.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/src/anysite/db/adapters/postgres.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/src/anysite/db/adapters/sqlite.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/src/anysite/db/cli.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/src/anysite/db/config.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/src/anysite/db/manager.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/src/anysite/db/operations/__init__.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/src/anysite/db/operations/insert.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/src/anysite/db/operations/query.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/src/anysite/db/schema/__init__.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/src/anysite/db/schema/inference.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/src/anysite/db/schema/types.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/src/anysite/db/utils/__init__.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/src/anysite/db/utils/sanitize.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/src/anysite/main.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/src/anysite/models/__init__.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/src/anysite/output/__init__.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/src/anysite/output/console.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/src/anysite/output/formatters.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/src/anysite/output/templates.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/src/anysite/py.typed +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/src/anysite/streaming/__init__.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/src/anysite/streaming/progress.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/src/anysite/streaming/writer.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/src/anysite/utils/__init__.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/src/anysite/utils/fields.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/src/anysite/utils/retry.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/test_data/enriched_partners_sample_10.csv +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/test_data/linkedin-partners/company_aliases.txt +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/test_data/linkedin-partners/dataset.yaml +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/test_data/partners-deep/dataset.yaml +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/test_data/partners-intel/dataset.yaml +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/test_data/partners-linkedin/company_aliases.txt +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/test_data/partners-linkedin/dataset.yaml +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/test_data/partners-pipeline/dataset.yaml +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/tests/__init__.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/tests/conftest.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/tests/test_api/__init__.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/tests/test_batch/__init__.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/tests/test_batch/test_executor.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/tests/test_batch/test_input.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/tests/test_batch/test_rate_limiter.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/tests/test_cli/__init__.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/tests/test_cli/test_main.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/tests/test_dataset/__init__.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/tests/test_dataset/test_analyzer.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/tests/test_dataset/test_collector.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/tests/test_dataset/test_differ.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/tests/test_dataset/test_exporters.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/tests/test_dataset/test_history.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/tests/test_dataset/test_integration_csv.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/tests/test_dataset/test_models.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/tests/test_dataset/test_notifications.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/tests/test_dataset/test_scheduler.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/tests/test_dataset/test_storage.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/tests/test_dataset/test_transformer.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/tests/test_db/__init__.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/tests/test_db/test_cli.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/tests/test_db/test_config.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/tests/test_db/test_inference.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/tests/test_db/test_insert.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/tests/test_db/test_manager.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/tests/test_db/test_postgres_adapter.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/tests/test_db/test_sanitize.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/tests/test_db/test_sqlite_adapter.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/tests/test_output/__init__.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/tests/test_output/test_formatters.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/tests/test_output/test_templates.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/tests/test_streaming/__init__.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/tests/test_streaming/test_progress.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/tests/test_streaming/test_writer.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/tests/test_utils/__init__.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/tests/test_utils/test_fields.py +0 -0
- {anysite_cli-0.1.5 → anysite_cli-0.1.6}/tests/test_utils/test_retry.py +0 -0
|
@@ -326,13 +326,14 @@ class DatasetDbLoader:
|
|
|
326
326
|
total += 1
|
|
327
327
|
|
|
328
328
|
# DELETE removed records (skipped in append mode)
|
|
329
|
+
ph = self._placeholder()
|
|
329
330
|
if result.removed and sync_mode == "full":
|
|
330
331
|
safe_col = sanitize_identifier(db_key_col)
|
|
331
332
|
for record in result.removed:
|
|
332
333
|
key_val = _get_key_val(record)
|
|
333
334
|
if key_val is not None:
|
|
334
335
|
self.adapter.execute(
|
|
335
|
-
f"DELETE FROM {table_name} WHERE {safe_col} =
|
|
336
|
+
f"DELETE FROM {table_name} WHERE {safe_col} = {ph}",
|
|
336
337
|
(str(key_val),),
|
|
337
338
|
)
|
|
338
339
|
total += 1
|
|
@@ -354,14 +355,14 @@ class DatasetDbLoader:
|
|
|
354
355
|
for field_name in changed_fields:
|
|
355
356
|
new_val = record.get(field_name)
|
|
356
357
|
safe_field = sanitize_identifier(field_name)
|
|
357
|
-
set_parts.append(f"{safe_field} =
|
|
358
|
+
set_parts.append(f"{safe_field} = {ph}")
|
|
358
359
|
params.append(new_val)
|
|
359
360
|
|
|
360
361
|
params.append(str(key_val))
|
|
361
362
|
sql = (
|
|
362
363
|
f"UPDATE {table_name} "
|
|
363
364
|
f"SET {', '.join(set_parts)} "
|
|
364
|
-
f"WHERE {safe_col} =
|
|
365
|
+
f"WHERE {safe_col} = {ph}"
|
|
365
366
|
)
|
|
366
367
|
self.adapter.execute(sql, tuple(params))
|
|
367
368
|
total += 1
|
|
@@ -375,6 +376,12 @@ class DatasetDbLoader:
|
|
|
375
376
|
return other.dependency.field
|
|
376
377
|
return None
|
|
377
378
|
|
|
379
|
+
def _placeholder(self) -> str:
|
|
380
|
+
"""Get the parameter placeholder for the dialect."""
|
|
381
|
+
if self._dialect == "postgres":
|
|
382
|
+
return "%s"
|
|
383
|
+
return "?"
|
|
384
|
+
|
|
378
385
|
def _auto_id_type(self) -> str:
|
|
379
386
|
"""Get the auto-increment ID column type for the dialect."""
|
|
380
387
|
if self._dialect == "postgres":
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"""Tests for dataset DB loader with SQLite in-memory adapter."""
|
|
2
2
|
|
|
3
3
|
import json
|
|
4
|
-
|
|
5
4
|
import pytest
|
|
6
5
|
|
|
7
6
|
from anysite.dataset.db_loader import DatasetDbLoader, _extract_dot_value, _filter_record
|
|
@@ -736,3 +735,101 @@ class TestAppendSyncMode:
|
|
|
736
735
|
rows = adapter.fetch_all("SELECT * FROM posts")
|
|
737
736
|
assert len(rows) == 1
|
|
738
737
|
assert rows[0]["uid"] == "a"
|
|
738
|
+
|
|
739
|
+
|
|
740
|
+
class TestPostgresPlaceholders:
|
|
741
|
+
"""Test that diff-based sync uses %s placeholders for postgres dialect."""
|
|
742
|
+
|
|
743
|
+
def _setup_two_snapshots(self, tmp_path, source_id, old_records, new_records):
|
|
744
|
+
source_dir = get_source_dir(tmp_path / "data", source_id)
|
|
745
|
+
write_parquet(old_records, source_dir / "2026-01-01.parquet")
|
|
746
|
+
write_parquet(new_records, source_dir / "2026-01-02.parquet")
|
|
747
|
+
|
|
748
|
+
def test_delete_uses_percent_s(self, tmp_path):
|
|
749
|
+
"""DELETE query uses %s placeholder for postgres."""
|
|
750
|
+
sources = [
|
|
751
|
+
DatasetSource(
|
|
752
|
+
id="items", endpoint="/api/items",
|
|
753
|
+
db_load=DbLoadConfig(key="name", sync="full"),
|
|
754
|
+
),
|
|
755
|
+
]
|
|
756
|
+
config = _make_config(tmp_path, sources)
|
|
757
|
+
|
|
758
|
+
self._setup_two_snapshots(
|
|
759
|
+
tmp_path, "items",
|
|
760
|
+
old_records=[
|
|
761
|
+
{"name": "Alice", "score": 90},
|
|
762
|
+
{"name": "Bob", "score": 80},
|
|
763
|
+
],
|
|
764
|
+
new_records=[{"name": "Alice", "score": 90}],
|
|
765
|
+
)
|
|
766
|
+
|
|
767
|
+
# Use real SQLite adapter for initial load, then mock for diff sync
|
|
768
|
+
adapter = _sqlite_adapter()
|
|
769
|
+
with adapter:
|
|
770
|
+
source_dir = get_source_dir(tmp_path / "data", "items")
|
|
771
|
+
loader = DatasetDbLoader(config, adapter)
|
|
772
|
+
loader._full_insert(
|
|
773
|
+
sources[0], "items", source_dir / "2026-01-01.parquet"
|
|
774
|
+
)
|
|
775
|
+
|
|
776
|
+
# Patch dialect to postgres and spy on execute
|
|
777
|
+
loader2 = DatasetDbLoader(config, adapter)
|
|
778
|
+
loader2._dialect = "postgres"
|
|
779
|
+
original_execute = adapter.execute
|
|
780
|
+
calls = []
|
|
781
|
+
|
|
782
|
+
def spy_execute(sql, params=None):
|
|
783
|
+
calls.append((sql, params))
|
|
784
|
+
# Replace %s with ? for SQLite execution
|
|
785
|
+
original_execute(sql.replace("%s", "?"), params)
|
|
786
|
+
|
|
787
|
+
adapter.execute = spy_execute
|
|
788
|
+
loader2.load_all()
|
|
789
|
+
|
|
790
|
+
# Verify DELETE used %s
|
|
791
|
+
delete_calls = [c for c in calls if "DELETE" in c[0]]
|
|
792
|
+
assert len(delete_calls) == 1
|
|
793
|
+
assert "%s" in delete_calls[0][0]
|
|
794
|
+
assert "?" not in delete_calls[0][0]
|
|
795
|
+
|
|
796
|
+
def test_update_uses_percent_s(self, tmp_path):
|
|
797
|
+
"""UPDATE query uses %s placeholders for postgres."""
|
|
798
|
+
sources = [
|
|
799
|
+
DatasetSource(
|
|
800
|
+
id="items", endpoint="/api/items",
|
|
801
|
+
db_load=DbLoadConfig(key="name"),
|
|
802
|
+
),
|
|
803
|
+
]
|
|
804
|
+
config = _make_config(tmp_path, sources)
|
|
805
|
+
|
|
806
|
+
self._setup_two_snapshots(
|
|
807
|
+
tmp_path, "items",
|
|
808
|
+
old_records=[{"name": "Alice", "score": 90}],
|
|
809
|
+
new_records=[{"name": "Alice", "score": 95}],
|
|
810
|
+
)
|
|
811
|
+
|
|
812
|
+
adapter = _sqlite_adapter()
|
|
813
|
+
with adapter:
|
|
814
|
+
source_dir = get_source_dir(tmp_path / "data", "items")
|
|
815
|
+
loader = DatasetDbLoader(config, adapter)
|
|
816
|
+
loader._full_insert(
|
|
817
|
+
sources[0], "items", source_dir / "2026-01-01.parquet"
|
|
818
|
+
)
|
|
819
|
+
|
|
820
|
+
loader2 = DatasetDbLoader(config, adapter)
|
|
821
|
+
loader2._dialect = "postgres"
|
|
822
|
+
original_execute = adapter.execute
|
|
823
|
+
calls = []
|
|
824
|
+
|
|
825
|
+
def spy_execute(sql, params=None):
|
|
826
|
+
calls.append((sql, params))
|
|
827
|
+
original_execute(sql.replace("%s", "?"), params)
|
|
828
|
+
|
|
829
|
+
adapter.execute = spy_execute
|
|
830
|
+
loader2.load_all()
|
|
831
|
+
|
|
832
|
+
update_calls = [c for c in calls if "UPDATE" in c[0]]
|
|
833
|
+
assert len(update_calls) == 1
|
|
834
|
+
assert "%s" in update_calls[0][0]
|
|
835
|
+
assert "?" not in update_calls[0][0]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|