docassert 0.14.0__tar.gz → 0.14.1__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.
- {docassert-0.14.0/docassert.egg-info → docassert-0.14.1}/PKG-INFO +1 -1
- {docassert-0.14.0 → docassert-0.14.1}/docassert/__init__.py +1 -1
- {docassert-0.14.0 → docassert-0.14.1}/docassert/bridge/board.py +23 -17
- {docassert-0.14.0 → docassert-0.14.1}/docassert/bridge/ops.py +29 -0
- {docassert-0.14.0 → docassert-0.14.1/docassert.egg-info}/PKG-INFO +1 -1
- {docassert-0.14.0 → docassert-0.14.1}/tests/test_bridge.py +29 -0
- {docassert-0.14.0 → docassert-0.14.1}/LICENSE +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/NOTICE +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/README.md +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/__main__.py +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/_data/consistency.yaml +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/_data/criteria/adr.criteria.yaml +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/_data/criteria/benefits-realization.criteria.yaml +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/_data/criteria/brd.criteria.yaml +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/_data/criteria/business-case.criteria.yaml +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/_data/criteria/charter.criteria.yaml +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/_data/criteria/data-migration-plan.criteria.yaml +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/_data/criteria/frnfr.criteria.yaml +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/_data/criteria/hypercare-plan.criteria.yaml +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/_data/criteria/post-implementation-review.criteria.yaml +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/_data/criteria/prd.criteria.yaml +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/_data/criteria/project.criteria.yaml +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/_data/criteria/qa-test-plan.criteria.yaml +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/_data/criteria/raci-stakeholder.criteria.yaml +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/_data/criteria/release-cutover-plan.criteria.yaml +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/_data/criteria/risk-register.criteria.yaml +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/_data/criteria/rollback-plan.criteria.yaml +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/_data/criteria/runbook.criteria.yaml +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/_data/criteria/status-report.criteria.yaml +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/_data/criteria/test-cases.criteria.yaml +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/_data/criteria/user-story.criteria.yaml +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/_data/profiles/agile-delivery.yaml +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/_data/profiles/lean-startup.yaml +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/_data/profiles/regulated-industry.yaml +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/_data/schema/adr.schema.json +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/_data/schema/benefits-realization.schema.json +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/_data/schema/brd.schema.json +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/_data/schema/business-case.schema.json +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/_data/schema/charter.schema.json +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/_data/schema/data-migration-plan.schema.json +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/_data/schema/frnfr.schema.json +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/_data/schema/hypercare-plan.schema.json +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/_data/schema/post-implementation-review.schema.json +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/_data/schema/prd.schema.json +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/_data/schema/project.schema.json +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/_data/schema/qa-test-plan.schema.json +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/_data/schema/raci-stakeholder.schema.json +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/_data/schema/release-cutover-plan.schema.json +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/_data/schema/risk-register.schema.json +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/_data/schema/rollback-plan.schema.json +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/_data/schema/runbook.schema.json +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/_data/schema/status-report.schema.json +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/_data/schema/test-cases.schema.json +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/_data/schema/user-story.schema.json +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/_data/skills/doc-to-pmo/SKILL.md +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/_data/templates/adr.template.md +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/_data/templates/benefits-realization.template.md +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/_data/templates/brd.template.md +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/_data/templates/business-case.template.md +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/_data/templates/charter.template.md +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/_data/templates/data-migration-plan.template.md +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/_data/templates/frnfr.template.md +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/_data/templates/hypercare-plan.template.md +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/_data/templates/post-implementation-review.template.md +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/_data/templates/prd.template.md +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/_data/templates/project.template.md +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/_data/templates/qa-test-plan.template.md +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/_data/templates/raci-stakeholder.template.md +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/_data/templates/release-cutover-plan.template.md +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/_data/templates/risk-register.template.md +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/_data/templates/rollback-plan.template.md +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/_data/templates/runbook.template.md +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/_data/templates/status-report.template.md +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/_data/templates/test-cases.template.md +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/_data/templates/user-story.template.md +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/bridge/__init__.py +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/bridge/gh.py +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/bridge/plan.py +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/cli.py +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/config.py +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/consistency.py +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/extract.py +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/graph.py +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/loader.py +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/models.py +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/profiles.py +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/projects.py +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/report.py +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/rtm.py +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/scaffold.py +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/semantic.py +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/status/__init__.py +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/status/derive.py +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/status/render.py +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert/structural.py +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert.egg-info/SOURCES.txt +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert.egg-info/dependency_links.txt +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert.egg-info/entry_points.txt +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert.egg-info/requires.txt +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/docassert.egg-info/top_level.txt +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/pyproject.toml +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/setup.cfg +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/tests/test_badge.py +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/tests/test_config.py +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/tests/test_consistency.py +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/tests/test_defects.py +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/tests/test_draft_relaxation.py +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/tests/test_extract.py +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/tests/test_graph.py +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/tests/test_json_report.py +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/tests/test_kinds_delivery.py +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/tests/test_kinds_governance.py +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/tests/test_kinds_operate.py +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/tests/test_kinds_reporting.py +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/tests/test_profiles.py +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/tests/test_projects.py +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/tests/test_scaffold.py +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/tests/test_semantic.py +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/tests/test_status.py +0 -0
- {docassert-0.14.0 → docassert-0.14.1}/tests/test_structural.py +0 -0
|
@@ -7,7 +7,7 @@ writes converge on the same values.
|
|
|
7
7
|
"""
|
|
8
8
|
from __future__ import annotations
|
|
9
9
|
|
|
10
|
-
from .gh import GhRunner
|
|
10
|
+
from .gh import GhError, GhRunner
|
|
11
11
|
|
|
12
12
|
FIELD_SPECS: dict[str, dict] = {
|
|
13
13
|
"Type": {"dataType": "SINGLE_SELECT", "options": ["Feature", "Story"]},
|
|
@@ -67,22 +67,28 @@ def ensure_fields(gh: GhRunner, owner: str, number: int) -> dict:
|
|
|
67
67
|
for name, spec in FIELD_SPECS.items():
|
|
68
68
|
if name in project["fields"]:
|
|
69
69
|
continue
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
70
|
+
try:
|
|
71
|
+
if spec["dataType"] == "SINGLE_SELECT":
|
|
72
|
+
opts = ", ".join(
|
|
73
|
+
f'{{name: "{o}", color: GRAY, description: ""}}'
|
|
74
|
+
for o in spec["options"])
|
|
75
|
+
gh.graphql(
|
|
76
|
+
"mutation($p: ID!, $n: String!) { createProjectV2Field(input: {"
|
|
77
|
+
"projectId: $p, dataType: SINGLE_SELECT, name: $n, "
|
|
78
|
+
f"singleSelectOptions: [{opts}]"
|
|
79
|
+
"}) { projectV2Field { ... on ProjectV2FieldCommon { id } } } }",
|
|
80
|
+
p=project["id"], n=name)
|
|
81
|
+
else:
|
|
82
|
+
gh.graphql(
|
|
83
|
+
"mutation($p: ID!, $n: String!) { createProjectV2Field(input: {"
|
|
84
|
+
"projectId: $p, dataType: TEXT, name: $n"
|
|
85
|
+
"}) { projectV2Field { ... on ProjectV2FieldCommon { id } } } }",
|
|
86
|
+
p=project["id"], n=name)
|
|
87
|
+
except GhError as exc:
|
|
88
|
+
# A concurrent sync created it between our read and our write;
|
|
89
|
+
# an existing field is the outcome we wanted.
|
|
90
|
+
if "already been taken" not in str(exc).lower():
|
|
91
|
+
raise
|
|
86
92
|
return get_project(gh, owner, number)
|
|
87
93
|
|
|
88
94
|
|
|
@@ -45,6 +45,33 @@ def _index(issues: list[dict]) -> dict[str, dict]:
|
|
|
45
45
|
return out
|
|
46
46
|
|
|
47
47
|
|
|
48
|
+
def _converge_duplicates(gh, repo: str, issues: list[dict]) -> tuple[list[dict], list[str]]:
|
|
49
|
+
"""One open issue per bridge marker: racing scaffolds may have created
|
|
50
|
+
duplicates, so close every open duplicate except the lowest-numbered one
|
|
51
|
+
and drop the closed ones from the working set. First writer wins."""
|
|
52
|
+
from collections import defaultdict
|
|
53
|
+
by_marker: dict[str, list[dict]] = defaultdict(list)
|
|
54
|
+
for issue in issues:
|
|
55
|
+
m = MARKER_RE.search(issue.get("body") or "")
|
|
56
|
+
if m and issue.get("state") == "open":
|
|
57
|
+
by_marker[m.group(1)].append(issue)
|
|
58
|
+
actions: list[str] = []
|
|
59
|
+
losers: set[int] = set()
|
|
60
|
+
for marker, dupes in by_marker.items():
|
|
61
|
+
if len(dupes) < 2:
|
|
62
|
+
continue
|
|
63
|
+
dupes.sort(key=lambda i: i["number"])
|
|
64
|
+
for extra in dupes[1:]:
|
|
65
|
+
G.update_issue(gh, repo, extra["number"], state="closed")
|
|
66
|
+
G.comment(gh, repo, extra["number"],
|
|
67
|
+
f"Duplicate of #{dupes[0]['number']} (bridge marker "
|
|
68
|
+
f"{marker}); racing scaffold runs converge on the "
|
|
69
|
+
"lowest-numbered issue.")
|
|
70
|
+
losers.add(extra["number"])
|
|
71
|
+
actions.append(f"converged duplicate #{extra['number']} -> #{dupes[0]['number']}")
|
|
72
|
+
return [i for i in issues if i["number"] not in losers], actions
|
|
73
|
+
|
|
74
|
+
|
|
48
75
|
def scaffold(plan: BridgePlan, gh: G.GhRunner, repo: str,
|
|
49
76
|
docs_url: str | None = None,
|
|
50
77
|
board_cfg: dict | None = None) -> list[str]:
|
|
@@ -59,6 +86,8 @@ def scaffold(plan: BridgePlan, gh: G.GhRunner, repo: str,
|
|
|
59
86
|
G.ensure_label(gh, repo, name, color, desc)
|
|
60
87
|
|
|
61
88
|
issues = G.list_issues(gh, repo)
|
|
89
|
+
issues, converge_actions = _converge_duplicates(gh, repo, issues)
|
|
90
|
+
actions.extend(converge_actions)
|
|
62
91
|
by_key = _index(issues)
|
|
63
92
|
|
|
64
93
|
def ensure(key: str, title: str, body: str, label: str) -> dict:
|
|
@@ -441,3 +441,32 @@ def test_anchor_without_repo_keeps_single_repo_mode_working(tmp_path):
|
|
|
441
441
|
gh = FakeGh()
|
|
442
442
|
ops.scaffold(plan, gh, "o/r", docs_url=None)
|
|
443
443
|
assert any("issues" in " ".join(c) for c in gh.calls)
|
|
444
|
+
|
|
445
|
+
|
|
446
|
+
# ── concurrency safety (ENG-PR-006) ──────────────────────────────────────────
|
|
447
|
+
def test_scaffold_converges_racing_duplicates(tmp_path):
|
|
448
|
+
plan = build_bridge_plan(_tree(tmp_path))
|
|
449
|
+
fid = plan.features[0].id
|
|
450
|
+
dupes = [_mk_issue(5, fid), _mk_issue(9, fid)]
|
|
451
|
+
gh = FakeGh(issues=dupes)
|
|
452
|
+
actions = ops.scaffold(plan, gh, "o/r", docs_url=None)
|
|
453
|
+
assert any("converged duplicate #9" in a for a in actions)
|
|
454
|
+
patches = [c for c in gh.calls if "repos/o/r/issues/9" in " ".join(c)
|
|
455
|
+
and "state=closed" in " ".join(c)]
|
|
456
|
+
assert patches, "the higher-numbered duplicate is closed"
|
|
457
|
+
|
|
458
|
+
|
|
459
|
+
def test_ensure_fields_tolerates_existing_field():
|
|
460
|
+
gh = BoardGh()
|
|
461
|
+
original = gh.graphql
|
|
462
|
+
|
|
463
|
+
def racing(query, **kw):
|
|
464
|
+
if "createProjectV2Field" in query:
|
|
465
|
+
from docassert.bridge.gh import GhError
|
|
466
|
+
raise GhError('[{"message": "Name has already been taken"}]')
|
|
467
|
+
return original(query, **kw)
|
|
468
|
+
|
|
469
|
+
gh.graphql = racing
|
|
470
|
+
from docassert.bridge import board
|
|
471
|
+
project = board.ensure_fields(gh, "o", 1) # must not raise
|
|
472
|
+
assert project["id"]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{docassert-0.14.0 → docassert-0.14.1}/docassert/_data/criteria/benefits-realization.criteria.yaml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{docassert-0.14.0 → docassert-0.14.1}/docassert/_data/criteria/data-migration-plan.criteria.yaml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{docassert-0.14.0 → docassert-0.14.1}/docassert/_data/criteria/raci-stakeholder.criteria.yaml
RENAMED
|
File without changes
|
{docassert-0.14.0 → docassert-0.14.1}/docassert/_data/criteria/release-cutover-plan.criteria.yaml
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
|
{docassert-0.14.0 → docassert-0.14.1}/docassert/_data/schema/benefits-realization.schema.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{docassert-0.14.0 → docassert-0.14.1}/docassert/_data/schema/data-migration-plan.schema.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{docassert-0.14.0 → docassert-0.14.1}/docassert/_data/schema/post-implementation-review.schema.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{docassert-0.14.0 → docassert-0.14.1}/docassert/_data/schema/release-cutover-plan.schema.json
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
|
{docassert-0.14.0 → docassert-0.14.1}/docassert/_data/templates/benefits-realization.template.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{docassert-0.14.0 → docassert-0.14.1}/docassert/_data/templates/data-migration-plan.template.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{docassert-0.14.0 → docassert-0.14.1}/docassert/_data/templates/raci-stakeholder.template.md
RENAMED
|
File without changes
|
{docassert-0.14.0 → docassert-0.14.1}/docassert/_data/templates/release-cutover-plan.template.md
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|