hypgraph 0.7.9__tar.gz → 0.7.10__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.
Files changed (103) hide show
  1. {hypgraph-0.7.9 → hypgraph-0.7.10}/CHANGELOG.md +20 -0
  2. {hypgraph-0.7.9 → hypgraph-0.7.10}/PKG-INFO +1 -1
  3. {hypgraph-0.7.9 → hypgraph-0.7.10}/src/hypgraph/__init__.py +1 -1
  4. {hypgraph-0.7.9 → hypgraph-0.7.10}/src/hypgraph/blind.py +8 -7
  5. {hypgraph-0.7.9 → hypgraph-0.7.10}/src/hypgraph/mcp.py +5 -3
  6. {hypgraph-0.7.9 → hypgraph-0.7.10}/src/hypgraph/schema.py +4 -0
  7. {hypgraph-0.7.9 → hypgraph-0.7.10}/src/hypgraph/ui/hypgraph.css +2 -1
  8. {hypgraph-0.7.9 → hypgraph-0.7.10}/tests/test_blind.py +46 -0
  9. {hypgraph-0.7.9 → hypgraph-0.7.10}/.gitignore +0 -0
  10. {hypgraph-0.7.9 → hypgraph-0.7.10}/AGENTS.md +0 -0
  11. {hypgraph-0.7.9 → hypgraph-0.7.10}/CITATION.cff +0 -0
  12. {hypgraph-0.7.9 → hypgraph-0.7.10}/DISCLAIMER.md +0 -0
  13. {hypgraph-0.7.9 → hypgraph-0.7.10}/LICENSE +0 -0
  14. {hypgraph-0.7.9 → hypgraph-0.7.10}/NOTICE +0 -0
  15. {hypgraph-0.7.9 → hypgraph-0.7.10}/README.md +0 -0
  16. {hypgraph-0.7.9 → hypgraph-0.7.10}/docs/PLAN.md +0 -0
  17. {hypgraph-0.7.9 → hypgraph-0.7.10}/docs/decisions/ADR-001-token-bound-authors.md +0 -0
  18. {hypgraph-0.7.9 → hypgraph-0.7.10}/docs/decisions/ADR-002-governance-profiles.md +0 -0
  19. {hypgraph-0.7.9 → hypgraph-0.7.10}/docs/profile-workflows-plan.md +0 -0
  20. {hypgraph-0.7.9 → hypgraph-0.7.10}/docs/review-2026-10-24.md +0 -0
  21. {hypgraph-0.7.9 → hypgraph-0.7.10}/docs/site-plan.md +0 -0
  22. {hypgraph-0.7.9 → hypgraph-0.7.10}/docs/spec.md +0 -0
  23. {hypgraph-0.7.9 → hypgraph-0.7.10}/docs/ui-plan.md +0 -0
  24. {hypgraph-0.7.9 → hypgraph-0.7.10}/docs/workflows/README.md +0 -0
  25. {hypgraph-0.7.9 → hypgraph-0.7.10}/docs/workflows/knowledge.md +0 -0
  26. {hypgraph-0.7.9 → hypgraph-0.7.10}/docs/workflows/optimization.md +0 -0
  27. {hypgraph-0.7.9 → hypgraph-0.7.10}/docs/workflows/scientific.md +0 -0
  28. {hypgraph-0.7.9 → hypgraph-0.7.10}/docs/workflows/software.md +0 -0
  29. {hypgraph-0.7.9 → hypgraph-0.7.10}/docs/workflows/trading.md +0 -0
  30. {hypgraph-0.7.9 → hypgraph-0.7.10}/pyproject.toml +0 -0
  31. {hypgraph-0.7.9 → hypgraph-0.7.10}/src/hypgraph/__main__.py +0 -0
  32. {hypgraph-0.7.9 → hypgraph-0.7.10}/src/hypgraph/bundle.py +0 -0
  33. {hypgraph-0.7.9 → hypgraph-0.7.10}/src/hypgraph/checks.py +0 -0
  34. {hypgraph-0.7.9 → hypgraph-0.7.10}/src/hypgraph/cli.py +0 -0
  35. {hypgraph-0.7.9 → hypgraph-0.7.10}/src/hypgraph/coord.py +0 -0
  36. {hypgraph-0.7.9 → hypgraph-0.7.10}/src/hypgraph/demos/__init__.py +0 -0
  37. {hypgraph-0.7.9 → hypgraph-0.7.10}/src/hypgraph/demos/broad_street.py +0 -0
  38. {hypgraph-0.7.9 → hypgraph-0.7.10}/src/hypgraph/derive.py +0 -0
  39. {hypgraph-0.7.9 → hypgraph-0.7.10}/src/hypgraph/graph.py +0 -0
  40. {hypgraph-0.7.9 → hypgraph-0.7.10}/src/hypgraph/language.py +0 -0
  41. {hypgraph-0.7.9 → hypgraph-0.7.10}/src/hypgraph/plan.py +0 -0
  42. {hypgraph-0.7.9 → hypgraph-0.7.10}/src/hypgraph/policy.py +0 -0
  43. {hypgraph-0.7.9 → hypgraph-0.7.10}/src/hypgraph/profiles.py +0 -0
  44. {hypgraph-0.7.9 → hypgraph-0.7.10}/src/hypgraph/references.py +0 -0
  45. {hypgraph-0.7.9 → hypgraph-0.7.10}/src/hypgraph/refusals.py +0 -0
  46. {hypgraph-0.7.9 → hypgraph-0.7.10}/src/hypgraph/report_check.py +0 -0
  47. {hypgraph-0.7.9 → hypgraph-0.7.10}/src/hypgraph/server.py +0 -0
  48. {hypgraph-0.7.9 → hypgraph-0.7.10}/src/hypgraph/skill/SKILL.md +0 -0
  49. {hypgraph-0.7.9 → hypgraph-0.7.10}/src/hypgraph/stats.py +0 -0
  50. {hypgraph-0.7.9 → hypgraph-0.7.10}/src/hypgraph/store.py +0 -0
  51. {hypgraph-0.7.9 → hypgraph-0.7.10}/src/hypgraph/ui/__init__.py +0 -0
  52. {hypgraph-0.7.9 → hypgraph-0.7.10}/src/hypgraph/ui/atlas.css +0 -0
  53. {hypgraph-0.7.9 → hypgraph-0.7.10}/src/hypgraph/ui/atlas.js +0 -0
  54. {hypgraph-0.7.9 → hypgraph-0.7.10}/src/hypgraph/ui/hypgraph.js +0 -0
  55. {hypgraph-0.7.9 → hypgraph-0.7.10}/src/hypgraph/ui/hypgraph.svg +0 -0
  56. {hypgraph-0.7.9 → hypgraph-0.7.10}/src/hypgraph/ui/index.html +0 -0
  57. {hypgraph-0.7.9 → hypgraph-0.7.10}/src/hypgraph/ui/vendor/LICENSES.md +0 -0
  58. {hypgraph-0.7.9 → hypgraph-0.7.10}/src/hypgraph/ui/vendor/cose-base.js +0 -0
  59. {hypgraph-0.7.9 → hypgraph-0.7.10}/src/hypgraph/ui/vendor/cytoscape-fcose.js +0 -0
  60. {hypgraph-0.7.9 → hypgraph-0.7.10}/src/hypgraph/ui/vendor/cytoscape.min.js +0 -0
  61. {hypgraph-0.7.9 → hypgraph-0.7.10}/src/hypgraph/ui/vendor/layout-base.js +0 -0
  62. {hypgraph-0.7.9 → hypgraph-0.7.10}/src/hypgraph/workflow.py +0 -0
  63. {hypgraph-0.7.9 → hypgraph-0.7.10}/tests/test_accept_work_kind.py +0 -0
  64. {hypgraph-0.7.9 → hypgraph-0.7.10}/tests/test_bound_support.py +0 -0
  65. {hypgraph-0.7.9 → hypgraph-0.7.10}/tests/test_bundle_telemetry.py +0 -0
  66. {hypgraph-0.7.9 → hypgraph-0.7.10}/tests/test_cancel_releases_lease.py +0 -0
  67. {hypgraph-0.7.9 → hypgraph-0.7.10}/tests/test_cited_and_failed_support.py +0 -0
  68. {hypgraph-0.7.9 → hypgraph-0.7.10}/tests/test_coord.py +0 -0
  69. {hypgraph-0.7.9 → hypgraph-0.7.10}/tests/test_d10.py +0 -0
  70. {hypgraph-0.7.9 → hypgraph-0.7.10}/tests/test_engine.py +0 -0
  71. {hypgraph-0.7.9 → hypgraph-0.7.10}/tests/test_engine_fixes.py +0 -0
  72. {hypgraph-0.7.9 → hypgraph-0.7.10}/tests/test_incremental.py +0 -0
  73. {hypgraph-0.7.9 → hypgraph-0.7.10}/tests/test_link_translate.py +0 -0
  74. {hypgraph-0.7.9 → hypgraph-0.7.10}/tests/test_log_and_check.py +0 -0
  75. {hypgraph-0.7.9 → hypgraph-0.7.10}/tests/test_measure_questions.py +0 -0
  76. {hypgraph-0.7.9 → hypgraph-0.7.10}/tests/test_opposed_answers.py +0 -0
  77. {hypgraph-0.7.9 → hypgraph-0.7.10}/tests/test_option_lead.py +0 -0
  78. {hypgraph-0.7.9 → hypgraph-0.7.10}/tests/test_order_detail.py +0 -0
  79. {hypgraph-0.7.9 → hypgraph-0.7.10}/tests/test_profiles.py +0 -0
  80. {hypgraph-0.7.9 → hypgraph-0.7.10}/tests/test_profiles_041.py +0 -0
  81. {hypgraph-0.7.9 → hypgraph-0.7.10}/tests/test_questions_not_assertions.py +0 -0
  82. {hypgraph-0.7.9 → hypgraph-0.7.10}/tests/test_references.py +0 -0
  83. {hypgraph-0.7.9 → hypgraph-0.7.10}/tests/test_refusal_friction.py +0 -0
  84. {hypgraph-0.7.9 → hypgraph-0.7.10}/tests/test_refusal_results.py +0 -0
  85. {hypgraph-0.7.9 → hypgraph-0.7.10}/tests/test_refusals.py +0 -0
  86. {hypgraph-0.7.9 → hypgraph-0.7.10}/tests/test_relation_words.py +0 -0
  87. {hypgraph-0.7.9 → hypgraph-0.7.10}/tests/test_report_answers.py +0 -0
  88. {hypgraph-0.7.9 → hypgraph-0.7.10}/tests/test_rerunnable.py +0 -0
  89. {hypgraph-0.7.9 → hypgraph-0.7.10}/tests/test_restates_scale.py +0 -0
  90. {hypgraph-0.7.9 → hypgraph-0.7.10}/tests/test_server_auth.py +0 -0
  91. {hypgraph-0.7.9 → hypgraph-0.7.10}/tests/test_server_hosts.py +0 -0
  92. {hypgraph-0.7.9 → hypgraph-0.7.10}/tests/test_shape_refusals.py +0 -0
  93. {hypgraph-0.7.9 → hypgraph-0.7.10}/tests/test_stats_not_backtests.py +0 -0
  94. {hypgraph-0.7.9 → hypgraph-0.7.10}/tests/test_stats_values.py +0 -0
  95. {hypgraph-0.7.9 → hypgraph-0.7.10}/tests/test_surfaces.py +0 -0
  96. {hypgraph-0.7.9 → hypgraph-0.7.10}/tests/test_telemetry_stream.py +0 -0
  97. {hypgraph-0.7.9 → hypgraph-0.7.10}/tests/test_ui_app.py +0 -0
  98. {hypgraph-0.7.9 → hypgraph-0.7.10}/tests/test_ui_engine.py +0 -0
  99. {hypgraph-0.7.9 → hypgraph-0.7.10}/tests/test_uncorrected_effect.py +0 -0
  100. {hypgraph-0.7.9 → hypgraph-0.7.10}/tests/test_unnamed_inputs.py +0 -0
  101. {hypgraph-0.7.9 → hypgraph-0.7.10}/tests/test_versions_not_figures.py +0 -0
  102. {hypgraph-0.7.9 → hypgraph-0.7.10}/tests/test_vocabulary_friction.py +0 -0
  103. {hypgraph-0.7.9 → hypgraph-0.7.10}/tests/test_workflows.py +0 -0
@@ -1,5 +1,25 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.7.10 — 2026-10-30: fixes from the first live blind run
4
+
5
+ Claude led a question on a HypMesh and issued a blind order; Codex took the order through its seat and counted the
6
+ primes below 1,000,000 whose digits sum to 23 with its own sieve. The record marked its result written blind and
7
+ agreeing blind with Claude's, and nothing sealed reached Codex. Four fixes from that run and a phone-width check:
8
+
9
+ - **Investigations are part of the problem statement a blind checker reads.** Only the order's own investigation
10
+ and the curators' were. A lead whose framing lived in a second investigation had it sealed, the numbers that
11
+ define the problem (1,000,000; 23) read as secrets, and an honest blind order was refused. Questions and
12
+ investigations say what is being found out; don't put answers in them.
13
+ - **`my_work` without an investigation lists your orders in every investigation.** It asked "which
14
+ investigation?" when a record held two, and the seat's first call failed.
15
+ - **`produced_by`, `generated_by`, `output_of`, `executed_by` and `tested_by` are read as the relation they
16
+ invert.** The node types fix the direction, so the link is turned round. Codex's first result was refused for
17
+ `produced_by`.
18
+ - **On a phone, every tab of the embedded app can be reached.** The embed's `overflow: visible` beat the narrow
19
+ rule that makes the nav a scrolling strip. On hypdmz.com at 375 px, four of the eight tabs (Evidence, Work
20
+ orders, Audit log, Report) sat past the edge with no way to scroll to them. The nav now scrolls, and the embed
21
+ clips sideways, so the closed drawer can't widen a host page that doesn't clip it.
22
+
3
23
  ## 0.7.9 — 2026-10-30: blind work orders
4
24
 
5
25
  - **A checker can measure without seeing the answer it checks.** `issue_work(..., blind=True)` (MCP `issue_work`
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: hypgraph
3
- Version: 0.7.9
3
+ Version: 0.7.10
4
4
  Summary: The evidence layer for AI research agents: a hash-chained research record that checks every claim as it is written and derives how well each is known.
5
5
  Project-URL: Homepage, https://hypgraph.com
6
6
  Project-URL: Documentation, https://hypgraph.com/engineers/
@@ -16,7 +16,7 @@ Standing is derived on every read, never stored; every write is an event in a SH
16
16
  their numbers; reviews pin versions; independence is counted, not assumed. See https://hypgraph.com.
17
17
  """
18
18
 
19
- __version__ = "0.7.9"
19
+ __version__ = "0.7.10"
20
20
 
21
21
  from .bundle import verify_bundle # noqa: E402
22
22
  from .graph import Author, Graph, GraphError, file_sha256 # noqa: E402
@@ -2,8 +2,8 @@
2
2
  Blind work orders: a checker measures without seeing the answer it is checking.
3
3
 
4
4
  A work order issued with ``blind=True`` seals the record from its assignee until the order is returned. While it is
5
- open, the assignee reads the problem statement (the investigation the order belongs to, the curators' investigations,
6
- the questions) and its own order; everything else other authors wrote — hypotheses and their predictions, results,
5
+ open, the assignee reads the problem statement (the investigations and questions: what is being found out, never what
6
+ was found) and its own order; everything else other authors wrote — hypotheses and their predictions, results,
7
7
  claims, reviews, runs and their code, sources, other orders, other teams' attempts — is sealed: shown as a placeholder,
8
8
  left out of search, its numbers scrubbed wherever else they appear.
9
9
 
@@ -39,7 +39,10 @@ _NUM = re.compile(r"(?<![\w.,])-?(?:\d{1,3}(?:,\d{3})+|\d+)(?:\.\d+)?(?![\w])")
39
39
  READ_ROUTES = frozenset({"investigations", "orders", "order", "resolve", "subgraph", "node", "why", "impact",
40
40
  "neighborhood", "search", "events", "verify", "profiles", "profile", "references"})
41
41
  POST_ROUTES = frozenset({"check_work"})
42
- VISIBLE_TYPES = frozenset({"question"})
42
+ # The problem statement every reader keeps. An investigation says what is being found out; a lead whose framing
43
+ # lived in a second investigation had it sealed, and the numbers that define the problem (1,000,000; 23) then read
44
+ # as secrets, so an honest blind order was refused (first live run, 2026-10-30). Don't put answers in them.
45
+ VISIBLE_TYPES = frozenset({"question", "investigation"})
43
46
  # A blind order asks for a measurement. A review or a report has to read what it judges.
44
47
  BLIND_PREDICATES = frozenset({"run_registered", "result_exists", "claim_made", "within_budget"})
45
48
  SEALED = "sealed"
@@ -228,10 +231,8 @@ def _derived(s: D.Snap, x: str, limit: int = 60) -> set[str]:
228
231
 
229
232
  # ── what is sealed, and from whom ──────────────────────────────────
230
233
  def public(s: D.Snap, n: dict, w: Window) -> bool:
231
- """The problem statement every reader keeps: questions, the curators' investigations, the order's own
232
- investigation, and the order chain itself."""
233
- return (n["type"] in VISIBLE_TYPES
234
- or (n["type"] == "investigation" and (n["created_by"] in s.policy.curators or n["id"] == w.inv)))
234
+ """The problem statement every reader keeps: questions and investigations (the order chain is kept apart)."""
235
+ return n["type"] in VISIBLE_TYPES
235
236
 
236
237
 
237
238
  def scope(s: D.Snap, w: Window) -> set[str]:
@@ -551,10 +551,12 @@ def build(graph: Graph | str, author: Optional[str] = None, files_root: str | No
551
551
 
552
552
  @tool
553
553
  def my_work(investigation: str = "") -> str:
554
- """Your open work orders, each with its full text. An order you have returned is no longer yours to work:
555
- it waits for acceptance, and comes back as a new order if it is reworked."""
554
+ """Your open work orders, each with its full text, in every investigation unless you name one. An order you
555
+ have returned is no longer yours to work: it waits for acceptance, and comes back as a new order if it is
556
+ reworked."""
556
557
  try:
557
- allmine = [o for o in g.orders(inv_of(investigation)) if o["assignee"] == me]
558
+ invs = [g.resolve(investigation)] if investigation else [i["id"] for i in g.investigations()]
559
+ allmine = [o for inv in invs for o in g.orders(inv) if o["assignee"] == me]
558
560
  except (GraphError, KeyError) as e:
559
561
  fail(e)
560
562
  mine = [o for o in allmine if o["status"] in ("open", "overdue")]
@@ -148,6 +148,10 @@ REL_SYNONYMS: dict[str, str] = {
148
148
  "correct": "corrects", "corrected": "corrects", "require": "requires", "required": "requires",
149
149
  "depends_on": "requires", "part": "part_of", "belongs_to": "part_of", "motivated": "motivated_by",
150
150
  "rests": "rests_on", "works": "works_on", "blocked": "blocked_by", "settle": "settles", "settled": "settles",
151
+ # inverses whose node types fix the direction (a result can't produce a run): turned round by _orient. Not
152
+ # supported_by / challenged_by: a claim can sit at either end of those.
153
+ "produced_by": "produced", "generated_by": "produced", "output_of": "produced", "executed_by": "executes",
154
+ "tested_by": "tests",
151
155
  }
152
156
 
153
157
  SYNONYMS: dict[tuple[str, str], dict[str, str]] = {
@@ -92,7 +92,7 @@
92
92
  .hg.hg-embed .hg-app { height: auto; grid-template-rows: 52px auto; }
93
93
  .hg.hg-embed .hg-main, .hg.hg-embed .hg-nav { overflow: visible; }
94
94
  .hg.hg-embed .feed { max-height: none; overflow: visible; }
95
- .hg.hg-embed { overflow: visible; }
95
+ .hg.hg-embed { overflow-x: clip; overflow-y: visible; } /* the closed drawer sits off to the right: never widen the page */
96
96
  .hg .kpi { padding: 12px 14px; } .hg .kpi .k { color: var(--ink2); font-size: 12px; }
97
97
  .hg .kpi .v { font-size: 22px; font-weight: 650; letter-spacing: -.02em; margin-top: 2px; font-variant-numeric: tabular-nums; }
98
98
  .hg .kpi .s { color: var(--ink3); font-size: 11.5px; margin-top: 2px; }
@@ -247,6 +247,7 @@
247
247
  .hg .hg-nav button { width: auto; flex: none; white-space: nowrap; padding: 6px 10px; }
248
248
  .hg .hg-nav .n { margin-left: 4px; } .hg .hg-nav .inv .s { display: none; }
249
249
  .hg .hg-main { padding: 16px 16px 32px; }
250
+ .hg.hg-embed .hg-nav { overflow-x: auto; overflow-y: hidden; } /* beats the embed's overflow: visible: every tab reachable */
250
251
  .hg .trace .tr { grid-template-columns: minmax(90px, 40%) minmax(0, 1fr) 48px; }
251
252
  }
252
253
  @media (prefers-reduced-motion: reduce) { .hg *, .hg *::before { animation: none !important; transition: none !important; } }
@@ -166,3 +166,49 @@ def test_mcp_seat_holding_a_blind_order(env, tmp_path):
166
166
  ov = text(await c.call_tool("overview", {"investigation": inv}))
167
167
  assert "Primes below" in ov
168
168
  asyncio.run(go())
169
+
170
+
171
+ # ── from the first live run (Claude leading, Codex checking on HypMesh, 2026-10-30) ──
172
+ def test_a_framing_investigation_is_the_problem_statement_and_my_work_finds_the_order():
173
+ fastmcp = pytest.importorskip("fastmcp")
174
+ from hypgraph.mcp import build
175
+ g = Graph(clock=Clock())
176
+ lead = g.author("lead")
177
+ frame = lead.investigation("The question", "Count the primes below 1,000,000 whose digits sum to 23.")["id"]
178
+ inv = lead.investigation("Lead's attempt", "Count them, and have the count checked blind.")["id"]
179
+ h = lead.add("hypothesis", inv, statement="There are 5503 primes below 1,000,000 whose digits sum to 23.",
180
+ predictions=["an independent count finds 5503"])["id"]
181
+ o = g.issue_work(author="lead", inv=inv, target=h, assignee="checker", blind=True,
182
+ objective="Count the primes below 1,000,000 whose digits sum to 23, with your own code.")
183
+ v = B.view_for_author(g.snapshot(), "checker")
184
+ assert frame not in v.hide and h in v.hide and "5503" in v.secrets and "23" not in v.secrets
185
+ with pytest.raises(GraphError, match="quotes what it would seal: 5503"):
186
+ h2 = lead.add("hypothesis", inv, statement="Most of them are below 900,000.",
187
+ predictions=["more than half fall below 900,000"])["id"]
188
+ g.issue_work(author="lead", inv=inv, target=h2, assignee="other", blind=True,
189
+ objective="Check that the count is 5503.")
190
+
191
+ async def go():
192
+ async with fastmcp.Client(build(g, author="checker")) as c:
193
+ r = await c.call_tool("my_work", {}) # no investigation named, two in the record
194
+ assert o["code"] in r.content[0].text and "BLIND" in r.content[0].text
195
+ asyncio.run(go())
196
+
197
+
198
+ def test_inverse_relation_words_are_turned_round(env):
199
+ g, inv, h1, rs1 = env
200
+ a = g.author("lead")
201
+ run = a.add("run", inv, kind="agent", name="second sieve", state="succeeded")["id"]
202
+ rs = a.add("result", inv, summary="The second sieve counts 1230 primes below 10,000; the largest is 9967.",
203
+ outcome="positive", values={"count": 1230, "largest": 9967},
204
+ links=[{"rel": "produced_by", "to": run}])
205
+ assert any(e["rel"] == "produced" and e["src"] == run for e in rs["in"])
206
+
207
+
208
+ def test_the_embedded_app_never_widens_its_page():
209
+ from pathlib import Path
210
+ import hypgraph.ui as ui
211
+ css = (Path(ui.__file__).parent / "hypgraph.css").read_text(encoding="utf-8")
212
+ assert ".hg.hg-embed { overflow-x: clip;" in css
213
+ narrow = css.split("@container hg (max-width: 760px)", 1)[1].split("\n}\n", 1)[0]
214
+ assert ".hg.hg-embed .hg-nav { overflow-x: auto;" in narrow
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes