docs: close #338 — headline refuted by full-capture statistics; AD-68 files the real residual
Some checks are pending
Headless portability / portable-headless (ubuntu-latest) (push) Waiting to run
Headless portability / portable-headless (windows-latest) (push) Waiting to run
Headless portability / linux-graphical (push) Waiting to run
Headless portability / linux-vulkan (push) Waiting to run
Some checks are pending
Headless portability / portable-headless (ubuntu-latest) (push) Waiting to run
Headless portability / portable-headless (windows-latest) (push) Waiting to run
Headless portability / linux-graphical (push) Waiting to run
Headless portability / linux-vulkan (push) Waiting to run
The three-site probe answered it in one run: prepare and publish carry the authored 0.600/1.500 to the publication candidate, and resolve receives exactly those values for the entire session after one early 0.400 reading. Re-reading the ORIGINAL 337-support.log with statistics instead of an eyeball: authored pair 111,248 lines, 0.400 pair 358. The filing was built on an early line of a 255k-line capture; the alleged mechanism (values never wired to the mover) does not exist. The 358 are AD-68, now registered: GetSetupMoverShape's placeholder (empty spheres -> legacy capsule, 0.4/0.4 steps) during an entity's async Setup-residency window, plus the local player's own seconds-long window between controller construction and publication-candidate adoption. Retail loads synchronously and has no such window. Left as-is deliberately: shrinking it is streaming work. The filing still paid for itself: three false doc-comment claims corrected in PlayerMovementController (retail '~0.4 m' twice, and an ApplyStepHeights writer that never existed anywhere in the tree — replaced with the real writer chain), retail's actual fallback pinned at 0.04 (CTransition::step_up @0x0050b655), and the resolve probe now prints the mover id, because the early 0.400 was most plausibly a REMOTE player — remotes also carry IsPlayer — and the guid rule (feedback_probe_identity_attribution) exists precisely to stop that misread. No production behaviour changed; nothing for the morning gate. AD section 50 -> 51. Suite 11,234 / 4 / 0. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
1dc81710f3
commit
8c97084289
4 changed files with 89 additions and 18 deletions
|
|
@ -220,7 +220,50 @@ AP-150 (the five-second wait-cue arming, which is what produced line 265),
|
|||
|
||||
## #338 — The player resolves with stepUp/stepDown 0.400 where Setup 0x02000001 authors 0.600 / 1.500
|
||||
|
||||
**Status:** OPEN
|
||||
**Status:** CLOSED 2026-08-07 — **headline REFUTED by full-capture statistics;
|
||||
the residual is AD-68, an async-residency placeholder, not a wiring defect.**
|
||||
|
||||
The three-site probe (`ACDREAM_PROBE_STEP_HEIGHTS=1`) answered everything in
|
||||
one run:
|
||||
|
||||
```
|
||||
site=prepare stepUp=0.600 stepDown=1.500 authored=(0.600,1.500) scale=1.000
|
||||
site=publish stepUp=0.600 stepDown=1.500 localEntityId=1000002
|
||||
site=resolve stepUp=0.400 stepDown=0.400 onGround=False <- once, early
|
||||
site=resolve stepUp=0.600 stepDown=1.500 onGround=True <- the whole session
|
||||
```
|
||||
|
||||
The probe is edge-triggered per site, so the single early 0.400 followed by
|
||||
0.600/1.500 with no further change means the steady state carried the authored
|
||||
values for the entire session — including the passing #32 cliff test.
|
||||
Re-reading the ORIGINAL `337-support.log` that motivated this filing, with
|
||||
statistics instead of an eyeball: the authored pair appears **111,248** times,
|
||||
the 0.400 pair **358** times. The filing was built on an early line of a
|
||||
255k-line capture; the mechanism it alleged (values never wired to the mover)
|
||||
does not exist.
|
||||
|
||||
**What the 358 actually are — AD-68.** `GetSetupMoverShape` returns a
|
||||
placeholder (empty spheres -> legacy capsule, 0.4/0.4 steps) while an entity's
|
||||
flat Setup is not yet resident; the local player has the same seconds-long
|
||||
window between controller construction and publication-candidate adoption
|
||||
(`CommitRuntimeOwnedController`). Retail loads synchronously and has no such
|
||||
window. The early 0.400 in tonight's capture was most plausibly a REMOTE
|
||||
player in that window — remotes also carry the IsPlayer mover flag, which is
|
||||
why the probe now prints the mover id (`feedback_probe_identity_attribution`).
|
||||
|
||||
**What the filing was still worth:** it caught three false doc-comment claims
|
||||
in `PlayerMovementController` (retail "~0.4 m" twice; a
|
||||
`PlayerModeController.ApplyStepHeights` writer that never existed — corrected
|
||||
to the real writer chain), pinned retail's actual fallback (0.04, not 0.4,
|
||||
`CTransition::step_up` @0x0050b655), and produced AD-68's register row for a
|
||||
previously unregistered adaptation.
|
||||
|
||||
**No production behaviour changed at this closure — there is nothing to
|
||||
verify in a live gate.**
|
||||
|
||||
**Original filing below, retained for the record.**
|
||||
|
||||
**Status (original):** OPEN
|
||||
**Severity:** unknown until measured, plausibly medium. A 1.5 m step-down is
|
||||
what keeps a mover attached to a descending slope; 0.4 m is not, so this is a
|
||||
candidate contributor to descent/edge feel — but that link is NOT established
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ accepted-divergence entries (#96, #49, #50).
|
|||
|
||||
---
|
||||
|
||||
## 2. Adaptation (AD) — 50 active rows (AD-67 filed 2026-08-07 at the #32 closeout — the narrowed `SetContactPlane` keeps its per-write `ContactPlaneCellId`, which retail writes only at `init_contact_plane`; AD-49 filed 2026-08-06 at the #334 fix — the BSP part-array flood runs its outdoor cell rectangle at seed time rather than only from retail’s residency-gated walk, keeping both registration floods on one residency rule; AD-64 filed 2026-08-05 at the C5b architecture review's D1 fix — AD-60's W2 wire-cell REACHABILITY decision is expressed once per host because the two hosts run parallel non-shared inbound routes; the committed VALUE is single-sourced at `RuntimeEntityObjectLifetime.CommitWireCellRebucket`, and unification is filed as #324; AD-60 CORRECTED the same day — its surviving-channel enumeration presented "the local force path, the missile arm" as exhaustive when the entire no-window host belonged in it; AD-1 RETIRED 2026-08-05, C5a deletion sweep — the legacy outdoor demote/restore lift this row described was `PhysicsEngine.Resolve`'s own body, deleted with zero production callers; AD-42 DELETED 2026-08-04, C4 route 3 — its last surviving citation, the headless portal-arrival resync's two-call Resolve/ResolvePlacement split, was retired by the canonical `RuntimeAcceptedPositionDriveController` portal arm; AD-2 amended same route with the deferred-place timing adaptation, the T8 tolerated-overwrite note, and the leash-anchor nuance; AD-63 filed 2026-08-04, cancelled-park presentation rollback — the rollback restores every presentation registration the park's Withdraw removed EXCEPT the player's selection, which is user intent rather than a projection; AD-62 filed 2026-08-03, C4 route 2 round 2 — a deferred ForcePosition retired without committing is not re-applied and its ack is not sent; AD-61 filed 2026-08-02, C3c review round 1 — the #270 settle compression now covers the local player; AD-59/AD-60 filed 2026-08-02, continuation-executor slice)
|
||||
## 2. Adaptation (AD) — 51 active rows (AD-68 filed 2026-08-07 at the #338 closure — the async-residency placeholder mover shape (0.4/0.4 steps + capsule) has no retail counterpart because retail loads synchronously; AD-67 filed 2026-08-07 at the #32 closeout — the narrowed `SetContactPlane` keeps its per-write `ContactPlaneCellId`, which retail writes only at `init_contact_plane`; AD-49 filed 2026-08-06 at the #334 fix — the BSP part-array flood runs its outdoor cell rectangle at seed time rather than only from retail’s residency-gated walk, keeping both registration floods on one residency rule; AD-64 filed 2026-08-05 at the C5b architecture review's D1 fix — AD-60's W2 wire-cell REACHABILITY decision is expressed once per host because the two hosts run parallel non-shared inbound routes; the committed VALUE is single-sourced at `RuntimeEntityObjectLifetime.CommitWireCellRebucket`, and unification is filed as #324; AD-60 CORRECTED the same day — its surviving-channel enumeration presented "the local force path, the missile arm" as exhaustive when the entire no-window host belonged in it; AD-1 RETIRED 2026-08-05, C5a deletion sweep — the legacy outdoor demote/restore lift this row described was `PhysicsEngine.Resolve`'s own body, deleted with zero production callers; AD-42 DELETED 2026-08-04, C4 route 3 — its last surviving citation, the headless portal-arrival resync's two-call Resolve/ResolvePlacement split, was retired by the canonical `RuntimeAcceptedPositionDriveController` portal arm; AD-2 amended same route with the deferred-place timing adaptation, the T8 tolerated-overwrite note, and the leash-anchor nuance; AD-63 filed 2026-08-04, cancelled-park presentation rollback — the rollback restores every presentation registration the park's Withdraw removed EXCEPT the player's selection, which is user intent rather than a projection; AD-62 filed 2026-08-03, C4 route 2 round 2 — a deferred ForcePosition retired without committing is not re-applied and its ack is not sent; AD-61 filed 2026-08-02, C3c review round 1 — the #270 settle compression now covers the local player; AD-59/AD-60 filed 2026-08-02, continuation-executor slice)
|
||||
|
||||
Recent retirements: AD-3/AD-4 retired 2026-07-31 by exact active/per-candidate
|
||||
visible-cell availability, full-catalog containment-root validation, and the
|
||||
|
|
@ -161,6 +161,7 @@ readiness/requeue adaptation. See
|
|||
| AD-65 | **Filed 2026-08-06 (found while retiring AD-10; NOT fixed here).** `Transition.AdjustOffset`'s `collisionAngle > 0` arm — the body moving AWAY from its contact plane — substitutes `result -= N * collisionAngle` for retail's `Plane::snap_to_plane` call, making the `if` and the `else` arms byte-identical. Retail's two arms are genuinely different: `snap_to_plane` (0x00509c50) writes ONLY `v.z = -(v.x*N.x + v.y*N.y) / N.z` and leaves X and Y untouched, while the into-plane arm subtracts the full normal component. So for a horizontal step of length d on a slope of angle theta, retail DESCENDS with XY preserved at d and Z dropping d*tan(theta) (speed along the plane d/cos theta), whereas acdream shrinks XY to d*cos^2(theta) (speed along the plane d*cos theta). acdream therefore descends slopes SLOWER than retail by cos^2(theta) in XY: **25% slow at 30 degrees, 50% at 45 degrees**. **MAGNITUDE CORRECTED 2026-08-06 at the AD-10 retail review (F1): this row first said 13%/29%, which is 1-cos(theta) -- the wrong formula for its own stated cos^2(theta) factor, and half the true value.** The correction is confirmed by measurement, not just algebra: #331's probe records 0.0735 m travelled for a 0.1 m request at 30.96 degrees, i.e. 26.5% short, which is exactly cos^2(30.96). This matters because the row is a LEAD for #269's slope-slide residual -- at the understated magnitude the lead reads as marginal and could be dismissed. Uphill (`collisionAngle <= 0`) is correct and identical to retail. | `src/AcDream.Core/Physics/TransitionTypes.cs` (`AdjustOffset`, the `else` arm commented "Moving away from contact plane: snap to plane surface" — the comment names snap_to_plane but the code does not call it) | Not justified — this is an unexamined substitution, not a decision. It is filed rather than fixed because it changes LOCAL-PLAYER movement feel and so needs its own visual gate; folding it into a remote-movement change would put a local-player regression behind the wrong acceptance test. | Downhill locomotion is 25-50% slow in XY across the walkable slope range (corrected 2026-08-06; was understated as 13-29%), for every mover that runs the sweep (local player, remotes, projectiles). **Recorded as a LEAD, not a diagnosis, for the open #269 slope-slide feel residual** (Campaign P): the direction is right (downhill-only, XY-shortening) but nothing here establishes causation, and #269 still needs its live cdb A/B. Note #269's friction and jump chains are byte-exonerated and must not be re-audited; `adjust_offset` is a different function and is not covered by that do-not-retry. | `CTransition::adjust_offset` 0x0050a370, pc:272271-272393; the branch at `0050a4fa fcomp [0x795344]` / `0050a502 test ah,0x41` / `0050a505 jne 0x50a515` — disassembled from the PDB-paired v11.4186 binary (GUID 9e847e2f-777c-4bd9-886c-22256bb87f32), 0x795344 = 0.0f (bytes 00000000). FPU C0 is "less" and C3 is "equal", so `jne` on `ah & 0x41` takes the SUBTRACT branch at 0x50a515 when `cAngle <= 0` and falls through to `call 0x509c50` (`Plane::snap_to_plane`, pc:271852) when `cAngle > 0`. Binary Ninja renders all four comparisons in this function as the `fnstsw`/`test ah` mush and cannot be read for direction. |
|
||||
| AD-66 | **Filed 2026-08-06 (found while retiring AD-10; NOT fixed here).** `Transition.AdjustOffset`'s safety push-out substitutes `naturalRestingDist = radius * ContactPlane.Normal.Z` for retail's bare `radius` in BOTH the trigger comparison and the `zDist` numerator. The substitution is deliberate and carries a written rationale in the code (the LocalSphere origin sits at (0, 0, radius) along WORLD Z, so a sphere resting on a tilted plane is `radius * N.z` from it, and the bare threshold would fire spuriously on every slope and lift the feet by r*(sec theta - 1) — 7 cm at 30 degrees, 48 cm at 60). The rationale may well be correct. What is missing is the register row: an intentional deviation from a byte-confirmed retail constant with no row is precisely what this register exists to catch, and the code comment's claim that "ACE and the published pseudocode have the original threshold" understates it — the retail BINARY has it. | `src/AcDream.Core/Physics/TransitionTypes.cs` (`AdjustOffset`, the `ci.ContactPlaneCellId != 0 && !ci.ContactPlaneIsWater` block) | Argued at length in the code comment and empirically motivated (the uncorrected threshold reportedly broke ValidateWalkable's contact check on steep slopes and flickered the Falling animation while running uphill). Filed to make the deviation auditable, not to assert it is wrong. | If the sphere-origin premise is mistaken, the push-out under-fires on slopes and a genuinely penetrating sphere is left below its contact plane. Conversely, if the premise is right, retail itself has the spurious lift and acdream is deliberately smoother than retail on slopes — a feel divergence in the same family as, and possibly interacting with, AD-65 and #269. | `CTransition::adjust_offset` 0x0050a370; disassembled from the PDB-paired v11.4186 binary: `0050a5c4 fld [ecx+0xc]` loads the bare `global_sphere->radius` and `0050a5c7 fsub [0x7c6878]` subtracts 0.00019999999494757503f (bytes 17b75139) for the trigger; `0050a5dc fsubr [ecx+0xc]` reloads the bare radius for the numerator before `0050a5df fdiv [esi+8]` divides by `contact_plane.N.z`. Neither site multiplies by N.z. |
|
||||
| AD-67 | **Filed 2026-08-07 at the #32 closeout.** The narrowed `CollisionInfo.SetContactPlane` still writes `ContactPlaneCellId`, which retail's `COLLISIONINFO::set_contact_plane` @0x00509d80 does not — retail writes the cell id only in `CTransition::init_contact_plane` (@0x0050e8ca). Kept deliberately at the #32 fix on the research doc's own advice: acdream's consumers (the `[support]` probe's provenance, water-plane bookkeeping, `AdjustOffset`'s `ContactPlaneCellId != 0` gate) rely on the cell id being current per contact write, and retail's equivalent state travels a different route the port has not needed. | `src/AcDream.Core/Physics/TransitionTypes.cs` (`SetContactPlane`, the `ContactPlaneCellId = cellId` line) | The #32 fix removed the four LAST-KNOWN writes — the defect — and deliberately did not also change this contact-group field in the same commit; two behaviour changes in one fix would have made the user's cliff gate ambiguous. | A consumer that assumes the cell id changes ONLY at transition seed time (retail's timing) would observe it changing per contact write instead. No such consumer is known; `AdjustOffset`'s gate wants the current value. | `COLLISIONINFO::set_contact_plane` 0x00509d80 (22 bytes, no cell-id write); `CTransition::init_contact_plane` 0x0050e850 (cell id at 0x0050e8ca) |
|
||||
| AD-68 | **Filed 2026-08-07 at the #338 closure.** During an entity's ASYNC-RESIDENCY window — its flat Setup collision not yet resident — `LiveEntityMotionRuntimeController.GetSetupMoverShape` returns a placeholder mover shape: empty sphere list (falling back to the legacy 0.48/1.835 capsule reconstruction) and step heights **0.4/0.4**, values that appear nowhere in retail (authored human values are 0.600/1.500; retail's not-on-walkable fallback is 0.04). The local player has the same window between controller construction (0.4f defaults) and the publication candidate's adoption. Retail loads Setups synchronously and has no such window at all. Measured scale: 358 placeholder resolves vs 111,248 authored-pair resolves across one long session — seconds per entity, once. | `src/AcDream.App/Physics/LiveEntityMotionRuntimeController.cs` (`GetSetupMoverShape`, the `setup is null` and `<= 0f` arms); `src/AcDream.Runtime/Gameplay/PlayerMovementController.cs` (0.4f field defaults, adopted-over at publication) | An adaptation to async residency, not a wiring defect — #338's live probe proved prepare/publish/resolve all carry the authored values in steady state. Left as-is deliberately: shrinking the window is streaming work, not physics work. | A remote moving DURING its residency window steps 0.4 instead of its authored heights, and collides as a capsule instead of its sphere list — briefly, once per entity. If a future report says "an NPC stumbled on a stair right as it appeared", this row is the first suspect. | `CTransition::step_up` 0x0050b610 (0.04 fallback at 0x0050b655); `CPartArray::GetStepUpHeight` 0x005180d0; issue #338 |
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -1935,6 +1935,14 @@ public sealed class PhysicsEngine
|
|||
// its two resolve calls. A silent probe proves nothing, so this
|
||||
// one sits where every caller must pass through. Filtered to the
|
||||
// player so remotes cannot drown it.
|
||||
// #338 self-report, once per process, UNCONDITIONAL. The probe has
|
||||
// now been silent through two placements, and "no output" cannot
|
||||
// distinguish "this site is never reached" from "the flag is
|
||||
// false". This line answers both directly instead of a third round
|
||||
// of inference. One Interlocked per process; strip with the probe.
|
||||
PhysicsDiagnostics.AnnounceStepHeightProbeOnce(
|
||||
(moverFlags & ObjectInfoState.IsPlayer) != 0);
|
||||
|
||||
// The flag test MUST precede the interpolated string: this site runs
|
||||
// per resolve, and building the detail eagerly cost 128 B/resolve
|
||||
// with the probe OFF — caught by Slice I1's zero-allocation gate,
|
||||
|
|
@ -1942,9 +1950,14 @@ public sealed class PhysicsEngine
|
|||
if (PhysicsDiagnostics.ProbeStepHeightsEnabled
|
||||
&& (moverFlags & ObjectInfoState.IsPlayer) != 0)
|
||||
{
|
||||
// The mover id is REQUIRED here (feedback_probe_identity_attribution):
|
||||
// remote players also carry IsPlayer, and the one early
|
||||
// 0.400 reading this probe caught was nearly misattributed to
|
||||
// the local player for exactly that reason — it was a remote
|
||||
// in its Setup-residency window (AD-68).
|
||||
PhysicsDiagnostics.LogStepHeights(
|
||||
"resolve", stepUpHeight, stepDownHeight,
|
||||
$"onGround={isOnGround} hasBody={body is not null}");
|
||||
$"mover=0x{movingEntityId:X8} onGround={isOnGround} hasBody={body is not null}");
|
||||
}
|
||||
|
||||
transition.ObjectInfo.StepDown = true;
|
||||
|
|
|
|||
|
|
@ -168,13 +168,24 @@ public sealed class PlayerMovementController
|
|||
|
||||
/// <summary>
|
||||
/// Maximum Z increase per movement step before the move is rejected.
|
||||
/// Retail's <c>step_up_height</c> for human characters is ~0.4 m (hip-
|
||||
/// level). Setting this too high lets the player teleport up small
|
||||
/// buildings via the step-up scan finding any walkable polygon within
|
||||
/// reach (Bug 3 in L.2.3 testing — walking into a steep slope mounted
|
||||
/// the building's flat top instead of sliding off the slope).
|
||||
/// Authoritative source is the player's <c>Setup.StepUpHeight</c> set
|
||||
/// in GameWindow.cs at world-entry time.
|
||||
///
|
||||
/// <para>
|
||||
/// #338 (2026-08-07) — this comment previously claimed retail's
|
||||
/// <c>step_up_height</c> for humans "is ~0.4 m" and that the value is
|
||||
/// "set in GameWindow.cs at world-entry time". Both were false, and a
|
||||
/// third false claim on the SphereList doc named a
|
||||
/// <c>PlayerModeController.ApplyStepHeights</c> that has never existed
|
||||
/// in the tree. The measured truth: the human Setup 0x02000001 authors
|
||||
/// <b>0.600</b> up / <b>1.500</b> down; retail's fallback when NOT on
|
||||
/// walkable ground is <b>0.04</b> (<c>CTransition::step_up</c>
|
||||
/// @0x0050b655), and 0.4 appears nowhere in retail. The authoritative
|
||||
/// writer is <c>RuntimeSetPositionMoverPreparation</c> (Setup-derived,
|
||||
/// x scale) via <c>RuntimeLocalPlayerPhysicsPublicationState</c>'s
|
||||
/// candidate, adopted by <c>CommitRuntimeOwnedController</c>. The 0.4f
|
||||
/// construction default below survives only until that adoption — a
|
||||
/// seconds-long window shared with AD-68's remote residency placeholder.
|
||||
/// Live capture: 111,248 authored-pair resolves vs 358 placeholder ones.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public float StepUpHeight
|
||||
{
|
||||
|
|
@ -188,11 +199,12 @@ public sealed class PlayerMovementController
|
|||
|
||||
/// <summary>
|
||||
/// L.2.3a (2026-04-29): how far below the foot the step-down probe
|
||||
/// reaches when transitioning between surfaces. Retail's
|
||||
/// <c>step_down_height</c> for human characters is ~0.4 m. With the
|
||||
/// previous 4 cm hardcoded value, walking off the top of a stair onto
|
||||
/// the ground 25 cm below produced a one-frame contact-plane gap — the
|
||||
/// animation system briefly flickered to falling.
|
||||
/// reaches when transitioning between surfaces. (The original "retail's
|
||||
/// step_down_height is ~0.4 m" claim here was wrong — the human Setup
|
||||
/// authors <b>1.500</b>; see <see cref="StepUpHeight"/>'s #338 note. The
|
||||
/// historical observation stands: with the very first 4 cm hardcoded
|
||||
/// value, walking off a stair onto ground 25 cm below produced a
|
||||
/// one-frame contact-plane gap and a falling-animation flicker.)
|
||||
/// </summary>
|
||||
public float StepDownHeight
|
||||
{
|
||||
|
|
@ -231,9 +243,11 @@ public sealed class PlayerMovementController
|
|||
/// TS-46 (2026-07-30): the player's own Setup ≤2-sphere list (dat
|
||||
/// <c>CSphere</c> Origin+Radius), verbatim per retail
|
||||
/// <c>CPhysicsObj::transition</c> (0x00512dc0) →
|
||||
/// <c>SPHEREPATH::init_sphere</c> (0x0050c670). Set at world-entry by
|
||||
/// <c>PlayerModeController.ApplyStepHeights</c> alongside
|
||||
/// <see cref="StepUpHeight"/>/<see cref="StepDownHeight"/>. Default
|
||||
/// <c>SPHEREPATH::init_sphere</c> (0x0050c670). Set alongside
|
||||
/// <see cref="StepUpHeight"/>/<see cref="StepDownHeight"/> by
|
||||
/// <c>RuntimeLocalPlayerPhysicsPublicationState</c>'s publication
|
||||
/// candidate (#338: the previously-named
|
||||
/// <c>PlayerModeController.ApplyStepHeights</c> never existed). Default
|
||||
/// (empty) falls back to <c>ResolveWithTransition</c>'s legacy
|
||||
/// (0.48, 1.835) two-scalar capsule reconstruction — the human Setup
|
||||
/// 0x02000001's authored spheres are (0,0,0.475) r=.48 and
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue