mirror of
https://github.com/Druthulu/BFM-decomp
synced 2026-09-30 15:36:55 -04:00
phase-36: T4 — the census's known-true controls keyed on their bodies' T1 text hashes (N-A once the campaign edits a control body: tus7 removed func_80184034's three bare-name pins and the census refused a correct tree); the cycle's FINISH=<label> mode completes a batch from its green logs (tus7 finished so: 34f03003d); kit corpus; log entry
This commit is contained in:
@@ -13,6 +13,8 @@
|
||||
# RUN IT DETACHED from the Claude Code harness (its low-memory guard kills a long BACKGROUND task — batch tus3 died mid-apply, S98):
|
||||
# setsid nohup bash -c 'TASK=T4 tools/delever_cycle.sh 3 12 300 tus; echo "cycle exit=$?"' > .run/P36/delever/cycle_<x>.log 2>&1 &
|
||||
# and watch the log (a tiny waiter: `until grep -q 'cycle exit=' <log>; do sleep 60; done`). A killed batch: `tools/delever.py --restore`.
|
||||
# FINISH=<label> START END …: a batch whose apply and fleet run were green but whose census/commit step failed (an instrument fault) is
|
||||
# finished from its own logs — census → log entry → commit — without redoing the work.
|
||||
# size a call so one batch stays < 10 min: TUs ≈ 8 s each single-threaded / 12 workers; a header ≈ 4 s (serial, includers in parallel).
|
||||
set -o pipefail
|
||||
cd "$(dirname "$0")/.." || exit 2
|
||||
@@ -26,12 +28,21 @@ PY=.venv/bin/python
|
||||
MARKER='## 🛑 SESSION CHECKPOINT' # the Log section ends at the checkpoint block: entries go right before it
|
||||
for k in $(seq "$START" "$END"); do
|
||||
label="${LABEL_PREFIX:-}${MODE}${k}"
|
||||
log=.run/P36/delever/run_${label}.log
|
||||
r22=.run/P36/baseline/r22_${label}.log
|
||||
if [ -n "${FINISH:-}" ]; then
|
||||
# FINISH=1: the batch's apply and fleet run already ran green (their logs exist) and the cycle stopped after them (a census
|
||||
# instrument fault, a lost commit): redo only the census → log entry → commit steps, from the same logs
|
||||
[ "$FINISH" = "$label" ] || { echo "cycle: FINISH=$FINISH does not name batch $label"; exit 2; }
|
||||
[ -s "$log" ] && [ -s "$r22" ] || { echo "cycle: FINISH=$label — no apply/R22 logs to finish from"; exit 2; }
|
||||
echo "cycle: finishing batch $label from its logs (census → log entry → commit)"
|
||||
else
|
||||
[ -z "$(git status --short -- src config)" ] || { echo "cycle: src/ or config/ is dirty — commit, or tools/delever.py --restore (R42/R102)"; exit 3; }
|
||||
[ -z "$(git status --short --porcelain src | grep '^??')" ] || { echo "cycle: untracked files under src/ (a dotfile probe?) — sweep them first"; exit 3; }
|
||||
$PY tools/delever_oracle.py --status >/dev/null 2>&1 || $PY tools/delever_oracle.py --calibrate ov_SC04_011 ov_SC03_015 ov_SC03_014 main -j 16 > .run/P36/delever/calibrate_${label}.log 2>&1 \
|
||||
|| { echo "cycle: calibration FAILED"; tail -5 .run/P36/delever/calibrate_${label}.log; exit 1; }
|
||||
log=.run/P36/delever/run_${label}.log
|
||||
{ /usr/bin/time -f "$label wall=%e s" $PY tools/delever.py --apply --batch "$BATCH" --label "$label" $HFLAG $ONLYFLAG $REDRAWFLAG -j 12; echo "exit=$?"; } > "$log" 2>&1
|
||||
fi
|
||||
grep -q '^exit=0$' "$log" || { echo "cycle: batch $label — delever exited non-zero"; tail -4 "$log"; exit 1; }
|
||||
if grep -q 'nothing to do (no drawable file)' "$log"; then echo "cycle: nothing drawable at $label — done"; exit 0; fi
|
||||
vline=$(grep -oE 'delever: batch .*' "$log" | tail -1)
|
||||
@@ -39,8 +50,9 @@ for k in $(seq "$START" "$END"); do
|
||||
final=$(echo "$vline" | grep -oE 'final [0-9]+/[0-9]+' | grep -oE '[0-9]+/[0-9]+')
|
||||
[ -n "$final" ] && [ "${final%/*}" = "${final#*/}" ] || { echo "cycle: batch $label — $vline"; exit 1; }
|
||||
if [ "$(echo "$vline" | grep -oE 'written [0-9]+' | grep -oE '[0-9]+')" = "0" ]; then echo "cycle: batch $label wrote no file — $vline"; fi
|
||||
r22=.run/P36/baseline/r22_${label}.log
|
||||
{ /usr/bin/time -f "wall=%e s user=%U s sys=%S s" bash -c 'set -o pipefail; make clean && make extract-all JOBS=16 && make check-all JOBS=16'; echo "exit=$?"; } > "$r22" 2>&1
|
||||
if [ -z "${FINISH:-}" ]; then
|
||||
{ /usr/bin/time -f "wall=%e s user=%U s sys=%S s" bash -c 'set -o pipefail; make clean && make extract-all JOBS=16 && make check-all JOBS=16'; echo "exit=$?"; } > "$r22" 2>&1
|
||||
fi
|
||||
line=$(grep -oE "check-all: [0-9]+ passed, [0-9]+ failed of [0-9]+" "$r22")
|
||||
if ! grep -q '^exit=0$' "$r22" || [ "$line" != "check-all: $FLEET passed, 0 failed of $FLEET" ]; then echo "cycle: R22 RED after batch $label — $line (the batch's files are in place: inspect, then tools/delever.py --restore)"; exit 1; fi
|
||||
$PY tools/lever_census.py --sites -j 16 > .run/P36/census/census_${label}.log 2>&1 || { echo "cycle: the census FAILED after batch $label"; tail -3 .run/P36/census/census_${label}.log; exit 1; }
|
||||
|
||||
@@ -820,7 +820,7 @@ def run_census(jobs, use_cache=True, out_dir=OUT_DIR_DEFAULT, want_sites=False,
|
||||
elapsed_s=round(time.time() - t0, 1),
|
||||
)
|
||||
ctrl = controls(sites, defs_all)
|
||||
summary["controls"] = [dict(name=n, got=g, expected=e, ok=(g == e)) for n, g, e in ctrl]
|
||||
summary["controls"] = [dict(name=n, got=g, expected=e, status=st, ok=(st != "MISMATCH")) for n, g, e, st in ctrl]
|
||||
out = REPO / out_dir
|
||||
out.mkdir(parents=True, exist_ok=True)
|
||||
(out / "lever_census.json").write_text(json.dumps(summary, indent=1, sort_keys=True) + "\n")
|
||||
@@ -834,17 +834,36 @@ def run_census(jobs, use_cache=True, out_dir=OUT_DIR_DEFAULT, want_sites=False,
|
||||
return summary, sites, table
|
||||
|
||||
|
||||
# the known-true bodies as they were at T1 (commit 357f8a1ed): a control holds only while the body's normalized text is the one the
|
||||
# count was made on — the campaign removes pins byte-identically, and a control that kept expecting them would fail on its own
|
||||
# staleness (batch tus7 of T4 removed func_80184034's three bare-name pins; the census then refused a correct tree)
|
||||
CONTROL_NHASH = {
|
||||
("src/800.c", "func_800226C0"): "47f1042f0dda6f163009793a11ef16f405c29af1",
|
||||
("src/shared/ov/func_80178004.h", None): "90d67fb489780cf0ef81f1a7b4b4f74dfe3c782b",
|
||||
("src/ov_SC03_006/ov_SC03_006_jr_8017AE2C.c", "func_80184034"): "2dce73f8716c32324b1b3517f11bd03a4e9966af",
|
||||
}
|
||||
|
||||
|
||||
def controls(sites, defs):
|
||||
"""known-true cases (R39): counted independently with grep at T1 (2026-09-09) — see the phase log."""
|
||||
"""known-true cases (R39): counted independently with grep at T1 (2026-09-09) — see the phase log. Each returns
|
||||
(name, got, expected, status) with status OK / MISMATCH / N-A (the body's text is no longer the one the count was made on)."""
|
||||
cur = {}
|
||||
for d in defs:
|
||||
cur[(d["tu"], d["name"])] = d["nhash"]
|
||||
cur.setdefault((d["tu"], None), d["nhash"])
|
||||
def status(key, got, want):
|
||||
if CONTROL_NHASH.get(key) and cur.get(key) != CONTROL_NHASH[key]:
|
||||
return "N-A"
|
||||
return "OK" if got == want else "MISMATCH"
|
||||
out = []
|
||||
n = sum(1 for s in sites if s["tu"] == "src/800.c" and s["fn"] == "func_800226C0" and s["cls"] == "A")
|
||||
out.append(("src/800.c func_800226C0 pins", n, 45))
|
||||
out.append(("src/800.c func_800226C0 pins", n, 45, status(("src/800.c", "func_800226C0"), n, 45)))
|
||||
n = sum(1 for s in sites if s["tu"] == "src/shared/ov/func_80178004.h" and s["cls"] == "A")
|
||||
out.append(("src/shared/ov/func_80178004.h pins", n, 26))
|
||||
out.append(("src/shared/ov/func_80178004.h pins", n, 26, status(("src/shared/ov/func_80178004.h", None), n, 26)))
|
||||
n = sum(1 for s in sites if s["tu"] == "src/ov_SC03_006/ov_SC03_006_jr_8017AE2C.c" and s["fn"] == "func_80184034" and s["cls"] == "A")
|
||||
out.append(("ov_SC03_006 func_80184034 bare-name pins", n, 3))
|
||||
out.append(("ov_SC03_006 func_80184034 bare-name pins", n, 3, status(("src/ov_SC03_006/ov_SC03_006_jr_8017AE2C.c", "func_80184034"), n, 3)))
|
||||
n = sum(1 for s in sites if s["tu"] == "src/shared/engine_prelude.h" and s["cls"] == "B")
|
||||
out.append(("engine_prelude.h asm sites (a macro definition only)", n, 0))
|
||||
out.append(("engine_prelude.h asm sites (a macro definition only)", n, 0, "OK" if n == 0 else "MISMATCH"))
|
||||
return out
|
||||
|
||||
|
||||
@@ -883,7 +902,7 @@ def render(s):
|
||||
L.append(f" asm-bearing macro definitions: {m['total']:,} ({m['names']} names, {m['names_with_multiple_texts']} with >1 text) kinds {m['kinds']}")
|
||||
L.append(" controls (R39):")
|
||||
for r in s["controls"]:
|
||||
L.append(f" {r['name']:52s} got {str(r['got']):6s} expected {r['expected']} {'OK' if r['ok'] else 'MISMATCH'}")
|
||||
L.append(f" {r['name']:52s} got {str(r['got']):6s} expected {r['expected']} {r.get('status', 'OK' if r['ok'] else 'MISMATCH')}")
|
||||
L.append(f" elapsed {s['elapsed_s']} s")
|
||||
return "\n".join(L)
|
||||
|
||||
|
||||
@@ -362,6 +362,17 @@ accumulate here as the phase produces them.**
|
||||
|
||||
- **2026-09-09 — T4 batch `tus7`** (`.run/P36/delever/run_tus7.log`, `batch_tus7.json`): `delever: batch tus7 — 300 files (TUs; 983 drawable) · 1407 bodies: 432 lever-free, 973 residue, 2 refused · sites removed 1855 / needed 2032 / refused 6 / deferred 0 · replays 589 (0 disagreed) · compiles 3211 in 101 s wall · final 300/300 identical · written 300 files` → R22 (`.run/P36/baseline/r22_tus7.log`) **`check-all: 218 passed, 0 failed of 218`** (`wall=116.04 s`) → census `THE PHASE'S NUMBER (pins + asm statements, GTE excluded): 36,764 sites in 13,224 bodies (2,199 distinct) · marked !FAKE 29,045 · UNMARKED 7,719`.
|
||||
|
||||
- **S98 — T4: the census's known-true control went stale on a correct tree (batch `tus7`).** The detached cycle (batches `tus3`–`tus6`
|
||||
committed `ce8737066`, `5e10b19e8`, `ca761c4f6`, `3e60fdf41`, each R22 218/218) stopped after `tus7`'s green apply (`final 300/300
|
||||
identical`) and green fleet run (`218 passed`) at the census: `ov_SC03_006 func_80184034 bare-name pins got 0 expected 3 MISMATCH` — the
|
||||
batch had removed those three pins byte-identically; the control's hand count from T1 could only be right while the body's text was the
|
||||
one it was counted on (R39's control is a property of the INSTRUMENT, and this one had a hidden precondition). Fix: each control carries
|
||||
the body's T1 normalized hash (`CONTROL_NHASH`, from commit `357f8a1ed`) and reports **N-A** once the text differs — never a failure on
|
||||
a correct tree, never a silent pass on a wrong walker. The batch was finished from its own logs with the cycle's new `FINISH=<label>`
|
||||
mode (census → log entry → commit, no work redone): `34f03003d`. Also learned: the harness's low-memory guard kills its background
|
||||
tasks (the cycle, then a 30-byte waiter) while the box has 22 GB free — the cycle runs DETACHED (`setsid nohup`) and a `Monitor` on
|
||||
its log reports each commit.
|
||||
|
||||
## 🛑 SESSION CHECKPOINT — S98 (2026-09-09): T0 ☑ T1 ☑ T1b ☑ T2 ☑ T3 ☑ — all committed (T3 = `39e3e1851` tools, `cd24727dd` + `7ee458dd7` the ov_SC04_011 batches, this close); NEXT = T4 the mechanical campaign: `tools/delever_cycle.sh` over the whole population (TUs then headers), unattended, one commit per batch, R22 every batch | the number: 53,033 sites in 15,638 bodies (2,246 distinct), 310 marked, 0 orphans | last batch `tus7` on 3e60fdf41: THE PHASE'S NUMBER (pins + asm statements, GTE excluded): 36,764 sites in 13,224 bodies (2,199 distinct) · marked !FAKE 29,045 · UNMARKED 7,719
|
||||
|
||||
### 0. How to use this block
|
||||
|
||||
+15
-3
@@ -13,6 +13,8 @@
|
||||
# RUN IT DETACHED from the Claude Code harness (its low-memory guard kills a long BACKGROUND task — batch tus3 died mid-apply, S98):
|
||||
# setsid nohup bash -c 'TASK=T4 tools/delever_cycle.sh 3 12 300 tus; echo "cycle exit=$?"' > .run/P36/delever/cycle_<x>.log 2>&1 &
|
||||
# and watch the log (a tiny waiter: `until grep -q 'cycle exit=' <log>; do sleep 60; done`). A killed batch: `tools/delever.py --restore`.
|
||||
# FINISH=<label> START END …: a batch whose apply and fleet run were green but whose census/commit step failed (an instrument fault) is
|
||||
# finished from its own logs — census → log entry → commit — without redoing the work.
|
||||
# size a call so one batch stays < 10 min: TUs ≈ 8 s each single-threaded / 12 workers; a header ≈ 4 s (serial, includers in parallel).
|
||||
set -o pipefail
|
||||
cd "$(dirname "$0")/.." || exit 2
|
||||
@@ -26,12 +28,21 @@ PY=.venv/bin/python
|
||||
MARKER='## 🛑 SESSION CHECKPOINT' # the Log section ends at the checkpoint block: entries go right before it
|
||||
for k in $(seq "$START" "$END"); do
|
||||
label="${LABEL_PREFIX:-}${MODE}${k}"
|
||||
log=.run/P36/delever/run_${label}.log
|
||||
r22=.run/P36/baseline/r22_${label}.log
|
||||
if [ -n "${FINISH:-}" ]; then
|
||||
# FINISH=1: the batch's apply and fleet run already ran green (their logs exist) and the cycle stopped after them (a census
|
||||
# instrument fault, a lost commit): redo only the census → log entry → commit steps, from the same logs
|
||||
[ "$FINISH" = "$label" ] || { echo "cycle: FINISH=$FINISH does not name batch $label"; exit 2; }
|
||||
[ -s "$log" ] && [ -s "$r22" ] || { echo "cycle: FINISH=$label — no apply/R22 logs to finish from"; exit 2; }
|
||||
echo "cycle: finishing batch $label from its logs (census → log entry → commit)"
|
||||
else
|
||||
[ -z "$(git status --short -- src config)" ] || { echo "cycle: src/ or config/ is dirty — commit, or tools/delever.py --restore (R42/R102)"; exit 3; }
|
||||
[ -z "$(git status --short --porcelain src | grep '^??')" ] || { echo "cycle: untracked files under src/ (a dotfile probe?) — sweep them first"; exit 3; }
|
||||
$PY tools/delever_oracle.py --status >/dev/null 2>&1 || $PY tools/delever_oracle.py --calibrate ov_SC04_011 ov_SC03_015 ov_SC03_014 main -j 16 > .run/P36/delever/calibrate_${label}.log 2>&1 \
|
||||
|| { echo "cycle: calibration FAILED"; tail -5 .run/P36/delever/calibrate_${label}.log; exit 1; }
|
||||
log=.run/P36/delever/run_${label}.log
|
||||
{ /usr/bin/time -f "$label wall=%e s" $PY tools/delever.py --apply --batch "$BATCH" --label "$label" $HFLAG $ONLYFLAG $REDRAWFLAG -j 12; echo "exit=$?"; } > "$log" 2>&1
|
||||
fi
|
||||
grep -q '^exit=0$' "$log" || { echo "cycle: batch $label — delever exited non-zero"; tail -4 "$log"; exit 1; }
|
||||
if grep -q 'nothing to do (no drawable file)' "$log"; then echo "cycle: nothing drawable at $label — done"; exit 0; fi
|
||||
vline=$(grep -oE 'delever: batch .*' "$log" | tail -1)
|
||||
@@ -39,8 +50,9 @@ for k in $(seq "$START" "$END"); do
|
||||
final=$(echo "$vline" | grep -oE 'final [0-9]+/[0-9]+' | grep -oE '[0-9]+/[0-9]+')
|
||||
[ -n "$final" ] && [ "${final%/*}" = "${final#*/}" ] || { echo "cycle: batch $label — $vline"; exit 1; }
|
||||
if [ "$(echo "$vline" | grep -oE 'written [0-9]+' | grep -oE '[0-9]+')" = "0" ]; then echo "cycle: batch $label wrote no file — $vline"; fi
|
||||
r22=.run/P36/baseline/r22_${label}.log
|
||||
{ /usr/bin/time -f "wall=%e s user=%U s sys=%S s" bash -c 'set -o pipefail; make clean && make extract-all JOBS=16 && make check-all JOBS=16'; echo "exit=$?"; } > "$r22" 2>&1
|
||||
if [ -z "${FINISH:-}" ]; then
|
||||
{ /usr/bin/time -f "wall=%e s user=%U s sys=%S s" bash -c 'set -o pipefail; make clean && make extract-all JOBS=16 && make check-all JOBS=16'; echo "exit=$?"; } > "$r22" 2>&1
|
||||
fi
|
||||
line=$(grep -oE "check-all: [0-9]+ passed, [0-9]+ failed of [0-9]+" "$r22")
|
||||
if ! grep -q '^exit=0$' "$r22" || [ "$line" != "check-all: $FLEET passed, 0 failed of $FLEET" ]; then echo "cycle: R22 RED after batch $label — $line (the batch's files are in place: inspect, then tools/delever.py --restore)"; exit 1; fi
|
||||
$PY tools/lever_census.py --sites -j 16 > .run/P36/census/census_${label}.log 2>&1 || { echo "cycle: the census FAILED after batch $label"; tail -3 .run/P36/census/census_${label}.log; exit 1; }
|
||||
|
||||
+26
-7
@@ -820,7 +820,7 @@ def run_census(jobs, use_cache=True, out_dir=OUT_DIR_DEFAULT, want_sites=False,
|
||||
elapsed_s=round(time.time() - t0, 1),
|
||||
)
|
||||
ctrl = controls(sites, defs_all)
|
||||
summary["controls"] = [dict(name=n, got=g, expected=e, ok=(g == e)) for n, g, e in ctrl]
|
||||
summary["controls"] = [dict(name=n, got=g, expected=e, status=st, ok=(st != "MISMATCH")) for n, g, e, st in ctrl]
|
||||
out = REPO / out_dir
|
||||
out.mkdir(parents=True, exist_ok=True)
|
||||
(out / "lever_census.json").write_text(json.dumps(summary, indent=1, sort_keys=True) + "\n")
|
||||
@@ -834,17 +834,36 @@ def run_census(jobs, use_cache=True, out_dir=OUT_DIR_DEFAULT, want_sites=False,
|
||||
return summary, sites, table
|
||||
|
||||
|
||||
# the known-true bodies as they were at T1 (commit 357f8a1ed): a control holds only while the body's normalized text is the one the
|
||||
# count was made on — the campaign removes pins byte-identically, and a control that kept expecting them would fail on its own
|
||||
# staleness (batch tus7 of T4 removed func_80184034's three bare-name pins; the census then refused a correct tree)
|
||||
CONTROL_NHASH = {
|
||||
("src/800.c", "func_800226C0"): "47f1042f0dda6f163009793a11ef16f405c29af1",
|
||||
("src/shared/ov/func_80178004.h", None): "90d67fb489780cf0ef81f1a7b4b4f74dfe3c782b",
|
||||
("src/ov_SC03_006/ov_SC03_006_jr_8017AE2C.c", "func_80184034"): "2dce73f8716c32324b1b3517f11bd03a4e9966af",
|
||||
}
|
||||
|
||||
|
||||
def controls(sites, defs):
|
||||
"""known-true cases (R39): counted independently with grep at T1 (2026-09-09) — see the phase log."""
|
||||
"""known-true cases (R39): counted independently with grep at T1 (2026-09-09) — see the phase log. Each returns
|
||||
(name, got, expected, status) with status OK / MISMATCH / N-A (the body's text is no longer the one the count was made on)."""
|
||||
cur = {}
|
||||
for d in defs:
|
||||
cur[(d["tu"], d["name"])] = d["nhash"]
|
||||
cur.setdefault((d["tu"], None), d["nhash"])
|
||||
def status(key, got, want):
|
||||
if CONTROL_NHASH.get(key) and cur.get(key) != CONTROL_NHASH[key]:
|
||||
return "N-A"
|
||||
return "OK" if got == want else "MISMATCH"
|
||||
out = []
|
||||
n = sum(1 for s in sites if s["tu"] == "src/800.c" and s["fn"] == "func_800226C0" and s["cls"] == "A")
|
||||
out.append(("src/800.c func_800226C0 pins", n, 45))
|
||||
out.append(("src/800.c func_800226C0 pins", n, 45, status(("src/800.c", "func_800226C0"), n, 45)))
|
||||
n = sum(1 for s in sites if s["tu"] == "src/shared/ov/func_80178004.h" and s["cls"] == "A")
|
||||
out.append(("src/shared/ov/func_80178004.h pins", n, 26))
|
||||
out.append(("src/shared/ov/func_80178004.h pins", n, 26, status(("src/shared/ov/func_80178004.h", None), n, 26)))
|
||||
n = sum(1 for s in sites if s["tu"] == "src/ov_SC03_006/ov_SC03_006_jr_8017AE2C.c" and s["fn"] == "func_80184034" and s["cls"] == "A")
|
||||
out.append(("ov_SC03_006 func_80184034 bare-name pins", n, 3))
|
||||
out.append(("ov_SC03_006 func_80184034 bare-name pins", n, 3, status(("src/ov_SC03_006/ov_SC03_006_jr_8017AE2C.c", "func_80184034"), n, 3)))
|
||||
n = sum(1 for s in sites if s["tu"] == "src/shared/engine_prelude.h" and s["cls"] == "B")
|
||||
out.append(("engine_prelude.h asm sites (a macro definition only)", n, 0))
|
||||
out.append(("engine_prelude.h asm sites (a macro definition only)", n, 0, "OK" if n == 0 else "MISMATCH"))
|
||||
return out
|
||||
|
||||
|
||||
@@ -883,7 +902,7 @@ def render(s):
|
||||
L.append(f" asm-bearing macro definitions: {m['total']:,} ({m['names']} names, {m['names_with_multiple_texts']} with >1 text) kinds {m['kinds']}")
|
||||
L.append(" controls (R39):")
|
||||
for r in s["controls"]:
|
||||
L.append(f" {r['name']:52s} got {str(r['got']):6s} expected {r['expected']} {'OK' if r['ok'] else 'MISMATCH'}")
|
||||
L.append(f" {r['name']:52s} got {str(r['got']):6s} expected {r['expected']} {r.get('status', 'OK' if r['ok'] else 'MISMATCH')}")
|
||||
L.append(f" elapsed {s['elapsed_s']} s")
|
||||
return "\n".join(L)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user