pydocket 0.9.2__tar.gz → 0.11.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.
Potentially problematic release.
This version of pydocket might be problematic. Click here for more details.
- pydocket-0.11.0/.github/workflows/claude-code-review.yml +40 -0
- pydocket-0.11.0/.github/workflows/claude.yml +42 -0
- {pydocket-0.9.2 → pydocket-0.11.0}/PKG-INFO +1 -1
- {pydocket-0.9.2 → pydocket-0.11.0}/src/docket/execution.py +3 -0
- {pydocket-0.9.2 → pydocket-0.11.0}/src/docket/instrumentation.py +6 -0
- {pydocket-0.9.2 → pydocket-0.11.0}/src/docket/worker.py +14 -3
- {pydocket-0.9.2 → pydocket-0.11.0}/tests/test_instrumentation.py +50 -0
- {pydocket-0.9.2 → pydocket-0.11.0}/.cursor/rules/general.mdc +0 -0
- {pydocket-0.9.2 → pydocket-0.11.0}/.cursor/rules/python-style.mdc +0 -0
- {pydocket-0.9.2 → pydocket-0.11.0}/.github/codecov.yml +0 -0
- {pydocket-0.9.2 → pydocket-0.11.0}/.github/workflows/chaos.yml +0 -0
- {pydocket-0.9.2 → pydocket-0.11.0}/.github/workflows/ci.yml +0 -0
- {pydocket-0.9.2 → pydocket-0.11.0}/.github/workflows/docs.yml +0 -0
- {pydocket-0.9.2 → pydocket-0.11.0}/.github/workflows/publish.yml +0 -0
- {pydocket-0.9.2 → pydocket-0.11.0}/.gitignore +0 -0
- {pydocket-0.9.2 → pydocket-0.11.0}/.pre-commit-config.yaml +0 -0
- {pydocket-0.9.2 → pydocket-0.11.0}/CLAUDE.md +0 -0
- {pydocket-0.9.2 → pydocket-0.11.0}/LICENSE +0 -0
- {pydocket-0.9.2 → pydocket-0.11.0}/README.md +0 -0
- {pydocket-0.9.2 → pydocket-0.11.0}/chaos/README.md +0 -0
- {pydocket-0.9.2 → pydocket-0.11.0}/chaos/__init__.py +0 -0
- {pydocket-0.9.2 → pydocket-0.11.0}/chaos/driver.py +0 -0
- {pydocket-0.9.2 → pydocket-0.11.0}/chaos/producer.py +0 -0
- {pydocket-0.9.2 → pydocket-0.11.0}/chaos/run +0 -0
- {pydocket-0.9.2 → pydocket-0.11.0}/chaos/tasks.py +0 -0
- {pydocket-0.9.2 → pydocket-0.11.0}/docs/advanced-patterns.md +0 -0
- {pydocket-0.9.2 → pydocket-0.11.0}/docs/api-reference.md +0 -0
- {pydocket-0.9.2 → pydocket-0.11.0}/docs/dependencies.md +0 -0
- {pydocket-0.9.2 → pydocket-0.11.0}/docs/getting-started.md +0 -0
- {pydocket-0.9.2 → pydocket-0.11.0}/docs/index.md +0 -0
- {pydocket-0.9.2 → pydocket-0.11.0}/docs/production.md +0 -0
- {pydocket-0.9.2 → pydocket-0.11.0}/docs/testing.md +0 -0
- {pydocket-0.9.2 → pydocket-0.11.0}/examples/__init__.py +0 -0
- {pydocket-0.9.2 → pydocket-0.11.0}/examples/common.py +0 -0
- {pydocket-0.9.2 → pydocket-0.11.0}/examples/concurrency_control.py +0 -0
- {pydocket-0.9.2 → pydocket-0.11.0}/examples/find_and_flood.py +0 -0
- {pydocket-0.9.2 → pydocket-0.11.0}/examples/self_perpetuating.py +0 -0
- {pydocket-0.9.2 → pydocket-0.11.0}/mkdocs.yml +0 -0
- {pydocket-0.9.2 → pydocket-0.11.0}/pyproject.toml +0 -0
- {pydocket-0.9.2 → pydocket-0.11.0}/src/docket/__init__.py +0 -0
- {pydocket-0.9.2 → pydocket-0.11.0}/src/docket/__main__.py +0 -0
- {pydocket-0.9.2 → pydocket-0.11.0}/src/docket/annotations.py +0 -0
- {pydocket-0.9.2 → pydocket-0.11.0}/src/docket/cli.py +0 -0
- {pydocket-0.9.2 → pydocket-0.11.0}/src/docket/dependencies.py +0 -0
- {pydocket-0.9.2 → pydocket-0.11.0}/src/docket/docket.py +0 -0
- {pydocket-0.9.2 → pydocket-0.11.0}/src/docket/py.typed +0 -0
- {pydocket-0.9.2 → pydocket-0.11.0}/src/docket/tasks.py +0 -0
- {pydocket-0.9.2 → pydocket-0.11.0}/telemetry/.gitignore +0 -0
- {pydocket-0.9.2 → pydocket-0.11.0}/telemetry/start +0 -0
- {pydocket-0.9.2 → pydocket-0.11.0}/telemetry/stop +0 -0
- {pydocket-0.9.2 → pydocket-0.11.0}/tests/__init__.py +0 -0
- {pydocket-0.9.2 → pydocket-0.11.0}/tests/cli/__init__.py +0 -0
- {pydocket-0.9.2 → pydocket-0.11.0}/tests/cli/conftest.py +0 -0
- {pydocket-0.9.2 → pydocket-0.11.0}/tests/cli/test_clear.py +0 -0
- {pydocket-0.9.2 → pydocket-0.11.0}/tests/cli/test_module.py +0 -0
- {pydocket-0.9.2 → pydocket-0.11.0}/tests/cli/test_parsing.py +0 -0
- {pydocket-0.9.2 → pydocket-0.11.0}/tests/cli/test_snapshot.py +0 -0
- {pydocket-0.9.2 → pydocket-0.11.0}/tests/cli/test_striking.py +0 -0
- {pydocket-0.9.2 → pydocket-0.11.0}/tests/cli/test_tasks.py +0 -0
- {pydocket-0.9.2 → pydocket-0.11.0}/tests/cli/test_version.py +0 -0
- {pydocket-0.9.2 → pydocket-0.11.0}/tests/cli/test_worker.py +0 -0
- {pydocket-0.9.2 → pydocket-0.11.0}/tests/cli/test_workers.py +0 -0
- {pydocket-0.9.2 → pydocket-0.11.0}/tests/conftest.py +0 -0
- {pydocket-0.9.2 → pydocket-0.11.0}/tests/test_concurrency_basic.py +0 -0
- {pydocket-0.9.2 → pydocket-0.11.0}/tests/test_concurrency_control.py +0 -0
- {pydocket-0.9.2 → pydocket-0.11.0}/tests/test_concurrency_refresh.py +0 -0
- {pydocket-0.9.2 → pydocket-0.11.0}/tests/test_dependencies.py +0 -0
- {pydocket-0.9.2 → pydocket-0.11.0}/tests/test_docket.py +0 -0
- {pydocket-0.9.2 → pydocket-0.11.0}/tests/test_execution.py +0 -0
- {pydocket-0.9.2 → pydocket-0.11.0}/tests/test_fundamentals.py +0 -0
- {pydocket-0.9.2 → pydocket-0.11.0}/tests/test_striking.py +0 -0
- {pydocket-0.9.2 → pydocket-0.11.0}/tests/test_worker.py +0 -0
- {pydocket-0.9.2 → pydocket-0.11.0}/uv.lock +0 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
name: Claude Code Review
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
types: [opened, synchronize]
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
claude-review:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
permissions:
|
|
11
|
+
contents: read
|
|
12
|
+
pull-requests: read
|
|
13
|
+
issues: read
|
|
14
|
+
id-token: write
|
|
15
|
+
|
|
16
|
+
steps:
|
|
17
|
+
- name: Checkout repository
|
|
18
|
+
uses: actions/checkout@v4
|
|
19
|
+
with:
|
|
20
|
+
fetch-depth: 1
|
|
21
|
+
|
|
22
|
+
- name: Run Claude Code Review
|
|
23
|
+
id: claude-review
|
|
24
|
+
uses: anthropics/claude-code-action@beta
|
|
25
|
+
with:
|
|
26
|
+
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
|
27
|
+
model: "claude-opus-4-1-20250805"
|
|
28
|
+
|
|
29
|
+
# Direct prompt for automated review (no @claude mention needed)
|
|
30
|
+
direct_prompt: |
|
|
31
|
+
Please review this pull request and provide feedback on:
|
|
32
|
+
- Code quality and best practices
|
|
33
|
+
- Potential bugs or issues
|
|
34
|
+
- Performance considerations
|
|
35
|
+
- Security concerns
|
|
36
|
+
- Test coverage, which must be maintained at 100% for this project
|
|
37
|
+
|
|
38
|
+
Be constructive and helpful in your feedback.
|
|
39
|
+
|
|
40
|
+
use_sticky_comment: true
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
name: Claude Code
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
issue_comment:
|
|
5
|
+
types: [created]
|
|
6
|
+
pull_request_review_comment:
|
|
7
|
+
types: [created]
|
|
8
|
+
issues:
|
|
9
|
+
types: [opened, assigned]
|
|
10
|
+
pull_request_review:
|
|
11
|
+
types: [submitted]
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
claude:
|
|
15
|
+
if: |
|
|
16
|
+
(github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) ||
|
|
17
|
+
(github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) ||
|
|
18
|
+
(github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) ||
|
|
19
|
+
(github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude')))
|
|
20
|
+
runs-on: ubuntu-latest
|
|
21
|
+
permissions:
|
|
22
|
+
contents: read
|
|
23
|
+
pull-requests: read
|
|
24
|
+
issues: read
|
|
25
|
+
id-token: write
|
|
26
|
+
actions: read # Required for Claude to read CI results on PRs
|
|
27
|
+
steps:
|
|
28
|
+
- name: Checkout repository
|
|
29
|
+
uses: actions/checkout@v4
|
|
30
|
+
with:
|
|
31
|
+
fetch-depth: 1
|
|
32
|
+
|
|
33
|
+
- name: Run Claude Code
|
|
34
|
+
id: claude
|
|
35
|
+
uses: anthropics/claude-code-action@beta
|
|
36
|
+
with:
|
|
37
|
+
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
|
38
|
+
|
|
39
|
+
additional_permissions: |
|
|
40
|
+
actions: read
|
|
41
|
+
|
|
42
|
+
model: "claude-opus-4-1-20250805"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pydocket
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.11.0
|
|
4
4
|
Summary: A distributed background task system for Python functions
|
|
5
5
|
Project-URL: Homepage, https://github.com/chrisguidry/docket
|
|
6
6
|
Project-URL: Bug Tracker, https://github.com/chrisguidry/docket/issues
|
|
@@ -51,6 +51,7 @@ class Execution:
|
|
|
51
51
|
key: str,
|
|
52
52
|
attempt: int,
|
|
53
53
|
trace_context: opentelemetry.context.Context | None = None,
|
|
54
|
+
redelivered: bool = False,
|
|
54
55
|
) -> None:
|
|
55
56
|
self.function = function
|
|
56
57
|
self.args = args
|
|
@@ -59,6 +60,7 @@ class Execution:
|
|
|
59
60
|
self.key = key
|
|
60
61
|
self.attempt = attempt
|
|
61
62
|
self.trace_context = trace_context
|
|
63
|
+
self.redelivered = redelivered
|
|
62
64
|
|
|
63
65
|
def as_message(self) -> Message:
|
|
64
66
|
return {
|
|
@@ -80,6 +82,7 @@ class Execution:
|
|
|
80
82
|
key=message[b"key"].decode(),
|
|
81
83
|
attempt=int(message[b"attempt"].decode()),
|
|
82
84
|
trace_context=propagate.extract(message, getter=message_getter),
|
|
85
|
+
redelivered=False, # Default to False, will be set to True in worker if it's a redelivery
|
|
83
86
|
)
|
|
84
87
|
|
|
85
88
|
def general_labels(self) -> Mapping[str, str]:
|
|
@@ -40,6 +40,12 @@ TASKS_STARTED = meter.create_counter(
|
|
|
40
40
|
unit="1",
|
|
41
41
|
)
|
|
42
42
|
|
|
43
|
+
TASKS_REDELIVERED = meter.create_counter(
|
|
44
|
+
"docket_tasks_redelivered",
|
|
45
|
+
description="How many tasks started that were redelivered from another worker",
|
|
46
|
+
unit="1",
|
|
47
|
+
)
|
|
48
|
+
|
|
43
49
|
TASKS_STRICKEN = meter.create_counter(
|
|
44
50
|
"docket_tasks_stricken",
|
|
45
51
|
description="How many tasks have been stricken from executing",
|
|
@@ -47,6 +47,7 @@ from .instrumentation import (
|
|
|
47
47
|
TASKS_COMPLETED,
|
|
48
48
|
TASKS_FAILED,
|
|
49
49
|
TASKS_PERPETUATED,
|
|
50
|
+
TASKS_REDELIVERED,
|
|
50
51
|
TASKS_RETRIED,
|
|
51
52
|
TASKS_RUNNING,
|
|
52
53
|
TASKS_STARTED,
|
|
@@ -286,7 +287,11 @@ class Worker:
|
|
|
286
287
|
count=available_slots,
|
|
287
288
|
)
|
|
288
289
|
|
|
289
|
-
def start_task(
|
|
290
|
+
def start_task(
|
|
291
|
+
message_id: RedisMessageID,
|
|
292
|
+
message: RedisMessage,
|
|
293
|
+
is_redelivery: bool = False,
|
|
294
|
+
) -> bool:
|
|
290
295
|
function_name = message[b"function"].decode()
|
|
291
296
|
if not (function := self.docket.tasks.get(function_name)):
|
|
292
297
|
logger.warning(
|
|
@@ -297,6 +302,7 @@ class Worker:
|
|
|
297
302
|
return False
|
|
298
303
|
|
|
299
304
|
execution = Execution.from_message(function, message)
|
|
305
|
+
execution.redelivered = is_redelivery
|
|
300
306
|
|
|
301
307
|
task = asyncio.create_task(self._execute(execution), name=execution.key)
|
|
302
308
|
active_tasks[task] = message_id
|
|
@@ -342,12 +348,15 @@ class Worker:
|
|
|
342
348
|
continue
|
|
343
349
|
|
|
344
350
|
for source in [get_redeliveries, get_new_deliveries]:
|
|
345
|
-
for
|
|
351
|
+
for stream_key, messages in await source(redis):
|
|
352
|
+
is_redelivery = stream_key == b"__redelivery__"
|
|
346
353
|
for message_id, message in messages:
|
|
347
354
|
if not message: # pragma: no cover
|
|
348
355
|
continue
|
|
349
356
|
|
|
350
|
-
task_started = start_task(
|
|
357
|
+
task_started = start_task(
|
|
358
|
+
message_id, message, is_redelivery
|
|
359
|
+
)
|
|
351
360
|
if not task_started:
|
|
352
361
|
# Other errors - delete and ack
|
|
353
362
|
await self._delete_known_task(redis, message)
|
|
@@ -521,6 +530,8 @@ class Worker:
|
|
|
521
530
|
duration = 0.0
|
|
522
531
|
|
|
523
532
|
TASKS_STARTED.add(1, counter_labels)
|
|
533
|
+
if execution.redelivered:
|
|
534
|
+
TASKS_REDELIVERED.add(1, counter_labels)
|
|
524
535
|
TASKS_RUNNING.add(1, counter_labels)
|
|
525
536
|
TASK_PUNCTUALITY.record(punctuality, counter_labels)
|
|
526
537
|
|
|
@@ -376,6 +376,14 @@ def TASKS_RETRIED(monkeypatch: pytest.MonkeyPatch) -> Mock:
|
|
|
376
376
|
return mock
|
|
377
377
|
|
|
378
378
|
|
|
379
|
+
@pytest.fixture
|
|
380
|
+
def TASKS_REDELIVERED(monkeypatch: pytest.MonkeyPatch) -> Mock:
|
|
381
|
+
"""Mock for the TASKS_REDELIVERED counter."""
|
|
382
|
+
mock = Mock(spec=Counter.add)
|
|
383
|
+
monkeypatch.setattr("docket.instrumentation.TASKS_REDELIVERED.add", mock)
|
|
384
|
+
return mock
|
|
385
|
+
|
|
386
|
+
|
|
379
387
|
async def test_worker_execution_increments_task_counters(
|
|
380
388
|
docket: Docket,
|
|
381
389
|
worker: Worker,
|
|
@@ -386,6 +394,7 @@ async def test_worker_execution_increments_task_counters(
|
|
|
386
394
|
TASKS_SUCCEEDED: Mock,
|
|
387
395
|
TASKS_FAILED: Mock,
|
|
388
396
|
TASKS_RETRIED: Mock,
|
|
397
|
+
TASKS_REDELIVERED: Mock,
|
|
389
398
|
):
|
|
390
399
|
"""Should increment the appropriate task counters when a worker executes a task."""
|
|
391
400
|
await docket.add(the_task)()
|
|
@@ -397,6 +406,7 @@ async def test_worker_execution_increments_task_counters(
|
|
|
397
406
|
TASKS_SUCCEEDED.assert_called_once_with(1, worker_labels)
|
|
398
407
|
TASKS_FAILED.assert_not_called()
|
|
399
408
|
TASKS_RETRIED.assert_not_called()
|
|
409
|
+
TASKS_REDELIVERED.assert_not_called()
|
|
400
410
|
|
|
401
411
|
|
|
402
412
|
async def test_failed_task_increments_failure_counter(
|
|
@@ -409,6 +419,7 @@ async def test_failed_task_increments_failure_counter(
|
|
|
409
419
|
TASKS_SUCCEEDED: Mock,
|
|
410
420
|
TASKS_FAILED: Mock,
|
|
411
421
|
TASKS_RETRIED: Mock,
|
|
422
|
+
TASKS_REDELIVERED: Mock,
|
|
412
423
|
):
|
|
413
424
|
"""Should increment the TASKS_FAILED counter when a task fails."""
|
|
414
425
|
the_task.side_effect = ValueError("Womp")
|
|
@@ -422,6 +433,7 @@ async def test_failed_task_increments_failure_counter(
|
|
|
422
433
|
TASKS_FAILED.assert_called_once_with(1, worker_labels)
|
|
423
434
|
TASKS_SUCCEEDED.assert_not_called()
|
|
424
435
|
TASKS_RETRIED.assert_not_called()
|
|
436
|
+
TASKS_REDELIVERED.assert_not_called()
|
|
425
437
|
|
|
426
438
|
|
|
427
439
|
async def test_retried_task_increments_retry_counter(
|
|
@@ -433,6 +445,7 @@ async def test_retried_task_increments_retry_counter(
|
|
|
433
445
|
TASKS_SUCCEEDED: Mock,
|
|
434
446
|
TASKS_FAILED: Mock,
|
|
435
447
|
TASKS_RETRIED: Mock,
|
|
448
|
+
TASKS_REDELIVERED: Mock,
|
|
436
449
|
):
|
|
437
450
|
"""Should increment the TASKS_RETRIED counter when a task is retried."""
|
|
438
451
|
|
|
@@ -448,6 +461,7 @@ async def test_retried_task_increments_retry_counter(
|
|
|
448
461
|
assert TASKS_FAILED.call_count == 2
|
|
449
462
|
assert TASKS_RETRIED.call_count == 1
|
|
450
463
|
TASKS_SUCCEEDED.assert_not_called()
|
|
464
|
+
TASKS_REDELIVERED.assert_not_called()
|
|
451
465
|
|
|
452
466
|
|
|
453
467
|
async def test_exhausted_retried_task_increments_retry_counter(
|
|
@@ -459,6 +473,7 @@ async def test_exhausted_retried_task_increments_retry_counter(
|
|
|
459
473
|
TASKS_SUCCEEDED: Mock,
|
|
460
474
|
TASKS_FAILED: Mock,
|
|
461
475
|
TASKS_RETRIED: Mock,
|
|
476
|
+
TASKS_REDELIVERED: Mock,
|
|
462
477
|
):
|
|
463
478
|
"""Should increment the appropriate counters when retries are exhausted."""
|
|
464
479
|
|
|
@@ -474,6 +489,41 @@ async def test_exhausted_retried_task_increments_retry_counter(
|
|
|
474
489
|
TASKS_FAILED.assert_called_once_with(1, worker_labels)
|
|
475
490
|
TASKS_RETRIED.assert_not_called()
|
|
476
491
|
TASKS_SUCCEEDED.assert_not_called()
|
|
492
|
+
TASKS_REDELIVERED.assert_not_called()
|
|
493
|
+
|
|
494
|
+
|
|
495
|
+
async def test_redelivered_tasks_increment_redelivered_counter(
|
|
496
|
+
docket: Docket,
|
|
497
|
+
worker_labels: dict[str, str],
|
|
498
|
+
TASKS_STARTED: Mock,
|
|
499
|
+
TASKS_COMPLETED: Mock,
|
|
500
|
+
TASKS_SUCCEEDED: Mock,
|
|
501
|
+
TASKS_FAILED: Mock,
|
|
502
|
+
TASKS_RETRIED: Mock,
|
|
503
|
+
TASKS_REDELIVERED: Mock,
|
|
504
|
+
):
|
|
505
|
+
"""Should increment the TASKS_REDELIVERED counter for redelivered tasks."""
|
|
506
|
+
|
|
507
|
+
async def test_task():
|
|
508
|
+
await asyncio.sleep(0.01)
|
|
509
|
+
|
|
510
|
+
await docket.add(test_task)()
|
|
511
|
+
|
|
512
|
+
worker = Worker(docket, redelivery_timeout=timedelta(milliseconds=50))
|
|
513
|
+
|
|
514
|
+
async with worker:
|
|
515
|
+
worker._execute = AsyncMock(side_effect=Exception("Simulated worker failure")) # type: ignore[assignment]
|
|
516
|
+
|
|
517
|
+
with pytest.raises(Exception, match="Simulated worker failure"):
|
|
518
|
+
await worker.run_until_finished()
|
|
519
|
+
|
|
520
|
+
await asyncio.sleep(0.075)
|
|
521
|
+
|
|
522
|
+
worker2 = Worker(docket, redelivery_timeout=timedelta(milliseconds=100))
|
|
523
|
+
async with worker2:
|
|
524
|
+
await worker2.run_until_finished()
|
|
525
|
+
|
|
526
|
+
assert TASKS_REDELIVERED.call_count >= 1
|
|
477
527
|
|
|
478
528
|
|
|
479
529
|
@pytest.fixture
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|