#!/usr/bin/env python3
"""reproduce_row33_3pts.py [--group DIR] [--served-points DIR] [--out DIR] [--bar D] [--plant-pos N] -- the row-33
three-points higher-order-twins data shelf reproduced from the shelf (a cut of ../vendor_row33_p2_twins/reproduce_row33_p2.py:
the same VERBATIM comparator block, the same pins-by-sha256 discipline, the same exit codes; three points instead of one):
at each of the further points P1 = (s, t, m^2) = (-1/2, -1, 1), P3 = (-3/4, -1/2, 1) and P4 = (-1/4, -1/2, 1) the eight
fixed-eps values of the dispersive evaluator at dps 140 (the vendored receipts under evals/P1/ -- the 2026-09-11 legs --
and evals/P3/, evals/P4/ -- the 2026-09-05 legs of record; every receipt here re-cut by field, no value moved; `I_disp` at full precision) are compared with the
target sample of the point's two vendored AMFlow grids at auxiliary-mass orders 400 and 500 (grids/; the ball midpoints of
result[0] = the integral with indices [1,1,1,2,1,2,1,1] at eps = 2^-k, k = 6..13) by the comparator's rules, copied VERBATIM
below and marked: per eps the members vs_x500, vs_x400, x400_vs_x500 (the twins' own agreement = the grids' certified digits
at that eps), quad_L7_L8 (the evaluator's own two-level quadrature pair, read from the receipt's diag), the count =
int(min(vs_x500, quad_L7_L8, x400_vs_x500)) (never rounded), and the planted-digit control (one significant digit of the
dps-140 value changed at position 48: the agreement with the x500 grid must fall under the bar and FAIL by name).  Every
recomputed member and count is compared with the point's vendored compare receipt (compare/) as the FLOAT PRINTED THERE (the
JSON literal; the tolerance is exact equality of the doubles); per point the cell figure (int(min) over the eight counts),
the range and the twins' worst pair are printed, and the dps-110 member is recomputed from the SERVED points/P<n>/record.json
two directories up (../vendor_row33_points/points/P<n>/record.json, pinned by sha256 below; a mismatch refuses by name,
exit 2) TO THE PRECISION ITS 40-DIGIT STRING ALLOWS, reported beside the compare receipt's two_precision_110_140 (computed by
the comparator from the record's full dps-110 string, which is not on any shelf) with the difference; not part of the exit
condition.  Seconds (mpmath at dps 400 over 3 points x 8 eps x 5 members).  Nothing is written outside --out (a fresh
directory; refused if it exists or lies inside the bundle).

WHAT IT PINS.  Every vendored object is read only after its sha256 equals its row in VENDOR_MANIFEST.sha256 (a mismatch
refuses, exit 3; a missing file exit 4).  Each compare receipt names its evaluator receipts by `eval_sha256` (the hex of the
object AS EMITTED); each is located through the VENDOR_MANIFEST header line "# vendored_from: <file> <- sha256 <hex>" and its
`k`, `dps`, `status` and `point` fields are asserted.  The grids are byte-identical to the emitted objects: their manifest
rows equal the compare receipt's grids.*.sha256 and the leg receipts' out.sha256, asserted.  The three served records are
pinned by SERVED_RECORD_SHA256.

THE RULE (each compare receipt's `rule` field: agree(a, b) = -log10(|a - b| / |b|) at mp.dps 400 on the full strings;
counts int(min), never round()); the functions marked VERBATIM are copied from the comparator (compare_ROW33_3PTS.py, itself
the P2 comparator compare_ROW33PP.py cut by point with the rules unchanged), vendored beside under compare/ as a text object
(not run from this shelf).

Exit 0 when at every point every convention-A member and count equals the compare receipt's as printed, the cell figure and
the range equal the receipt's, and the planted control FAILS by name at every eps (REPRODUCED: True); 1 when any of those
differs; 2 when a served record's sha256 differs from its pin; 3 a shelf object's sha256 differs from its VENDOR_MANIFEST row;
4 a missing object; 5 --out exists or lies inside the bundle.  python3 + mpmath."""
import argparse
import glob
import hashlib
import json
import os
import re
import subprocess
import sys

import mpmath as mp

HERE = os.path.dirname(os.path.abspath(__file__))
SERVED_POINTS_REL = os.path.join("..", "vendor_row33_points", "points")
SERVED_RECORD_SHA256 = {"P1": "7151dab6a8872971a1ffc2b4604d153df87a4cc49c0d34fb8a22dbafdf7ef668",
                        "P3": "120c92482f2eef8c82a1bd841c7055cced2326651203117d9933c82079c3349f",
                        "P4": "d3c28db61ab5862dcbe5e880e8758bdf5bb04d8240d5832722ab9441b3228aa5"}
TARGET = [1, 1, 1, 2, 1, 2, 1, 1]
POINTS = {"P1": {"s": "-1/2", "t": "-1", "msq": "1"}, "P3": {"s": "-3/4", "t": "-1/2", "msq": "1"}, "P4": {"s": "-1/4", "t": "-1/2", "msq": "1"}}
def GRID_X(pt): return {400: "grids/LBL3VP_%s_x400.json" % pt, 500: "grids/LBL3VP_%s_x500.json" % pt}
P2_SHELF = {"cell_figure_A": 76, "range_A": [76, 77], "x400_vs_x500_worst": 118.40824509118418}   # ../vendor_row33_p2_twins/compare/COMPARE_ROW33PP_P2_20260910T045045Z.json, as served

# ---- VERBATIM from compare_ROW33PP.py / compare_ROW33_3PTS.py (the comparator of record; the compare receipt's `rule` field states the rule) ----
mp.mp.dps = 400
KS = [6, 7, 8, 9, 10, 11, 12, 13]
def parse_ball_mid(s):
    m = re.match(r"\s*\[?\s*([-+]?[0-9.]+(?:[eE][-+]?\d+)?)", s); assert m, s[:60]; return mp.mpf(m.group(1))
def agree(a, b):
    a = mp.mpf(a); b = mp.mpf(b)
    if a == b: return 400.0
    if b == 0: return 0.0
    return float(-mp.log10(abs(a - b) / abs(b)))
def grid_samples(path):
    d = json.load(open(path)); r = d["result"][0]; assert r["integral"]["indices"][:8] == [1, 1, 1, 2, 1, 2, 1, 1]; out = {}
    for s in r["samples"]:
        e = mp.mpf(s["eps"]["re"]); k = int(mp.nint(-mp.log(e, 2))); assert abs(e - mp.mpf(2) ** (-k)) < mp.mpf("1e-300"), s["eps"]["re"][:30]; out[k] = {"re": parse_ball_mid(s["value"]["re"]), "raw": s["value"]["re"][:140]}
    return out, d
def plant(s, pos):
    digits = [i for i, c in enumerate(s) if c.isdigit()]; sig = [i for i in digits if s[:i].lstrip("-0.").strip("-") != "" or s[i] != "0"]
    i = sig[pos - 1]; c = s[i]; return s[:i] + ("1" if c != "1" else "2") + s[i + 1:]
# ---- end of the VERBATIM block ----


def sha(p):
    return hashlib.sha256(open(p, "rb").read()).hexdigest()


def stamp():
    return subprocess.run(["date", "-u", "+%Y-%m-%dT%H:%M:%SZ"], capture_output=True, text=True).stdout.strip()


def refuse(code, msg):
    print("REFUSED (%d): %s" % (code, msg))
    sys.exit(code)


def manifest_rows(path):
    rows, vfrom = {}, {}
    for line in open(path):
        line = line.rstrip("\n")
        m = re.match(r"^# vendored_from: (\S+) <- sha256 ([0-9a-f]{64}) ", line)
        if m:
            vfrom[m.group(2)] = m.group(1)
        elif line and not line.startswith("#"):
            h, f = line.split(None, 1)
            rows[f.strip()] = h
    return rows, vfrom


def pinned(group, rows, rel, consumed):
    p = os.path.join(group, rel)
    if rel not in rows:
        refuse(4, "%s is not a row of VENDOR_MANIFEST.sha256" % rel)
    if not os.path.isfile(p):
        refuse(4, "%s is missing from the shelf" % rel)
    h = sha(p)
    if h != rows[rel]:
        refuse(3, "%s sha256 %s differs from its VENDOR_MANIFEST row %s" % (rel, h, rows[rel]))
    consumed[rel] = h
    return p


def one_rel(rows, pattern, what):
    hits = [r for r in rows if re.fullmatch(pattern, r)]
    if len(hits) != 1:
        refuse(4, "%s: %d rows of VENDOR_MANIFEST match %s (one expected)" % (what, len(hits), pattern))
    return hits[0]


def main():
    ap = argparse.ArgumentParser(description="the row-33 three-points higher-order-twins data shelf reproduced from the shelf (seconds; python3 + mpmath)")
    ap.add_argument("--group", default=HERE, help="the shelf directory (default: this script's directory)")
    ap.add_argument("--served-points", default=None, help="the served vendor_row33_points/points directory holding P1/ P3/ P4/ record.json (default: ../vendor_row33_points/points from the shelf)")
    ap.add_argument("--out", default=None, help="a fresh output directory (default: ./reproduce_row33_3pts_<stamp> under the working directory; refused if it exists or lies inside the bundle)")
    ap.add_argument("--bar", type=float, default=50.0, help="the bar in digits for the planted control and the PASS reading (default 50, the compare receipts')")
    ap.add_argument("--plant-pos", type=int, default=48, help="the significant-digit position of the planted control (default 48, the compare receipts')")
    a = ap.parse_args()
    G = os.path.abspath(a.group)
    bundle = os.path.dirname(G)
    st = stamp()
    out = os.path.abspath(a.out) if a.out else os.path.join(os.getcwd(), "reproduce_row33_3pts_" + st.replace("-", "").replace(":", ""))
    if os.path.exists(out):
        refuse(5, "--out %s exists (a fresh directory is required)" % out)
    if os.path.commonpath([out, bundle]) == bundle:
        refuse(5, "--out %s lies inside the bundle %s (write outside it)" % (out, bundle))
    vm = os.path.join(G, "VENDOR_MANIFEST.sha256")
    if not os.path.isfile(vm):
        refuse(4, "VENDOR_MANIFEST.sha256 is missing from %s" % G)
    rows, vfrom = manifest_rows(vm)
    consumed = {}
    served_dir = os.path.abspath(a.served_points) if a.served_points else os.path.normpath(os.path.join(G, SERVED_POINTS_REL))
    RESULTS = {}; diffs_all = []; all_fail_all = True
    for pt, POINT in POINTS.items():
        print("== %s (s, t, m^2) = (%s, %s, %s)" % (pt, POINT["s"], POINT["t"], POINT["msq"]))
        # the served record (pinned by sha256; refused by name on a mismatch)
        rec_path = os.path.join(served_dir, pt, "record.json")
        if not os.path.isfile(rec_path):
            refuse(4, "the served record %s is missing (the shelf must sit beside vendor_row33_points/ as served)" % rec_path)
        rec_sha = sha(rec_path)
        if rec_sha != SERVED_RECORD_SHA256[pt]:
            refuse(2, "the served points/%s/record.json sha256 %s differs from the pin %s: the dps-110 member is not read" % (pt, rec_sha, SERVED_RECORD_SHA256[pt]))
        rec = json.load(open(rec_path))
        if rec["point"]["tag"] != pt or rec["point"]["s"] != POINT["s"] or rec["point"]["t"] != POINT["t"] or rec["dps"] != 110:
            refuse(2, "the served record is not the dps-110 run at %s" % pt)
        # the compare receipt and the two grids
        COMPARE_REL = one_rel(rows, r"compare/COMPARE_ROW33_3PTS_%s_\d{8}T\d{6}Z\.json" % pt, "the %s compare receipt" % pt)
        cmp_path = pinned(G, rows, COMPARE_REL, consumed)
        C = json.load(open(cmp_path))
        if C.get("point") != pt or C.get("standin") or C["n_eps"] != 8:
            refuse(3, "%s is not the eight-eps compare receipt at %s" % (COMPARE_REL, pt))
        grids, legs, O, LEG_X = {}, {}, {}, {}
        for xo, rel in GRID_X(pt).items():
            p = pinned(G, rows, rel, consumed)
            if C["grids"]["x%d" % xo]["sha256"] != rows[rel]:
                refuse(3, "the %s compare receipt names the x%d grid by sha256 %s; the vendored grid's row is %s" % (pt, xo, C["grids"]["x%d" % xo]["sha256"], rows[rel]))
            O[xo], grids[xo] = grid_samples(p)
            if grids[xo]["options"]["x_order"] != xo or grids[xo]["mode"] != "black_box_amflow":
                refuse(3, "the %s x%d grid's options.x_order / mode are not %d / black_box_amflow" % (pt, xo, xo))
            LEG_X[xo] = one_rel(rows, r"grids/LBL3VP_%s_x%d_RECEIPT_\d{8}T\d{6}Z\.json" % (pt, xo), "the %s x%d leg receipt" % (pt, xo))
            lp = pinned(G, rows, LEG_X[xo], consumed)
            legs[xo] = json.load(open(lp))
            if legs[xo]["out"]["sha256"] != rows[rel] or legs[xo]["config"]["x_order"] != xo or legs[xo]["config"]["numeric_values"] != POINT or not legs[xo]["DONE"]["done"]:
                refuse(3, "the %s x%d leg receipt does not name the vendored grid (out.sha256), the order %d, the point %s and DONE" % (pt, xo, xo, POINT))
            if not all(k in O[xo] for k in KS):
                refuse(3, "the %s x%d grid carries no sample at some k in %s" % (pt, xo, KS))
        # the eight evaluator receipts, located through the vendored_from header by the hex the compare receipt names
        evals = {}
        for k in KS:
            pe = C["per_eps"][str(k)]
            hexk = pe.get("eval_sha256")
            if hexk not in vfrom:
                refuse(4, "no vendored_from line carries the %s eps 2^-%d evaluator receipt's emitted sha256 %s" % (pt, k, hexk))
            rel = vfrom[hexk]
            p = pinned(G, rows, rel, consumed)
            d = json.load(open(p))
            if str(d.get("k")) != str(k) or d.get("status") != "DONE" or d.get("dps") != 140 or d["point"]["s"] != POINT["s"] or d["point"]["t"] != POINT["t"]:
                refuse(3, "%s is not the DONE dps-140 receipt at eps 2^-%d at %s" % (rel, k, pt))
            evals[k] = (rel, d)
        # ---- the recomputation, the comparator's rules ----
        bar = a.bar
        per, counts_A, counts_B40, ctrl, diffs = {}, {}, {}, {}, []
        def cmpf(name, got, want):
            eq = (got == want)
            if not eq:
                diffs.append({"point": pt, "leaf": name, "recomputed": got, "receipt": want})
            return eq
        for k in KS:
            rel, d = evals[k]
            v = d["I_disp"]
            pe = C["per_eps"][str(k)]
            M = pe["members"]
            m = {"vs_x500": agree(v, O[500][k]["re"]), "vs_x400": agree(v, O[400][k]["re"]), "x400_vs_x500": agree(O[400][k]["re"], O[500][k]["re"]), "quad_L7_L8": d["diag"]["quad_agree"]}
            cA = int(min(m["vs_x500"], m["x400_vs_x500"], m["quad_L7_L8"]))
            pl = plant(v, a.plant_pos); dpl = agree(pl, O[500][k]["re"])
            fails = dpl < bar
            rec40 = rec["fixed_eps"]["per_eps"][str(k)]["I_disp_40d"]
            tp40 = agree(rec40, v)
            cB40 = int(min(tp40, m["vs_x500"]))
            i40 = mp.nstr(mp.mpf(v), 40); o40 = mp.nstr(O[500][k]["re"], 40)
            eq = {n: cmpf("per_eps[%d].members.%s" % (k, n), m[n], M[n]) for n in ("vs_x500", "vs_x400", "x400_vs_x500", "quad_L7_L8")}
            eq["count_A"] = cmpf("per_eps[%d].count_A_int_min" % k, cA, pe["count_A_int_min"])
            eq["d_planted"] = cmpf("per_eps[%d].planted_control.d_planted" % k, dpl, pe["planted_control"]["d_planted"])
            eq["fails_by_name"] = cmpf("per_eps[%d].planted_control.fails_by_name" % k, fails, True) and pe["planted_control"]["fails_by_name"] is True
            eq["I_disp_40d"] = cmpf("per_eps[%d].I_disp_40d" % k, i40, pe["I_disp_40d"])
            eq["O500_40d"] = cmpf("per_eps[%d].O500_40d" % k, o40, pe["O500_40d"])
            counts_A[k] = cA; counts_B40[k] = cB40
            ctrl[k] = {"position": a.plant_pos, "d_planted": dpl, "fails_by_name": fails, "rc": 1 if fails else 0}
            per[k] = {"eval_receipt": rel, "eval_sha256_vendored": consumed[rel], "eval_sha256_emitted": next(h for h, f in vfrom.items() if f == rel),
                      "members": m, "count_A_int_min": cA, "planted_control": ctrl[k], "I_disp_40d": i40, "O500_40d": o40,
                      "dps110_member_from_served_40d": {"served_I_disp_40d": rec40, "two_precision_110_140_from_40d": tp40, "compare_receipt_two_precision_110_140": M["two_precision_110_140"],
                                                        "difference": tp40 - M["two_precision_110_140"], "count_B_from_40d": cB40, "compare_receipt_count_B": pe["count_B_int_min"],
                                                        "served_record_agreement_d_vs_x200_grid": rec["fixed_eps"]["per_eps"][str(k)]["agreement_d"]},
                      "equal_to_receipt": eq}
            print("  eps 2^-%-2d  vs_x500 %.2f  vs_x400 %.2f  x400_vs_x500 %.2f  quad_L7_L8 %.2f  count_A %d  planted(%d) %.2f %s  | dps-110 member from the served 40-digit string %.2f (receipt %.2f, difference %+.2e; count_B %d vs %d)  | equal to the receipt: %s"
                  % (k, m["vs_x500"], m["vs_x400"], m["x400_vs_x500"], m["quad_L7_L8"], cA, a.plant_pos, dpl, "FAIL by name" if fails else "NOT FAILED", tp40, M["two_precision_110_140"], tp40 - M["two_precision_110_140"], cB40, pe["count_B_int_min"], all(eq.values())))
        cell = min(counts_A.values()); rng = [min(counts_A.values()), max(counts_A.values())]
        worst_pair = min(per[k]["members"]["x400_vs_x500"] for k in KS); best_pair = max(per[k]["members"]["x400_vs_x500"] for k in KS)
        vs500 = [per[k]["members"]["vs_x500"] for k in KS]; l78 = [per[k]["members"]["quad_L7_L8"] for k in KS]
        cmpf("cell_figure_A", cell, C["cell_figure_A"]); cmpf("range_A", rng, C["range_A"])
        cmpf("counts_A", {str(k): counts_A[k] for k in KS}, C["counts_A"])
        all_fail = all(ctrl[k]["fails_by_name"] for k in KS)
        tp = [per[k]["dps110_member_from_served_40d"]["two_precision_110_140_from_40d"] for k in KS]; dd = [per[k]["dps110_member_from_served_40d"]["difference"] for k in KS]
        print("  %s: the cell figure (int(min) over the eight counts) %d; the range %d-%d; vs the x500 grid %.2f-%.2f; the L7/L8 pairs %.2f-%.2f; the twins' own pair (x400 vs x500) %.2f at worst, %.2f at best; the planted controls FAIL by name at every eps: %s; the dps-110 member from the served 40-digit strings %.2f-%.2f (receipt %.2f-%.2f); leaves differing at this point %d"
              % (pt, cell, rng[0], rng[1], min(vs500), max(vs500), min(l78), max(l78), worst_pair, best_pair, all_fail, min(tp), max(tp), min(per[k]["dps110_member_from_served_40d"]["compare_receipt_two_precision_110_140"] for k in KS), max(per[k]["dps110_member_from_served_40d"]["compare_receipt_two_precision_110_140"] for k in KS), len(diffs)))
        RESULTS[pt] = {"point": POINT, "served_record": {"file": "points/%s/record.json" % pt, "sha256": rec_sha, "pin": SERVED_RECORD_SHA256[pt]}, "compare_receipt": {"file": os.path.basename(cmp_path), "sha256_vendored": consumed[COMPARE_REL], "stamp_utc": C["stamp_utc"], "dps140_source": C.get("dps140_source")},
                       "grids": {"x%d" % xo: {"file": os.path.basename(GRID_X(pt)[xo]), "sha256": consumed[GRID_X(pt)[xo]], "x_order": grids[xo]["options"]["x_order"], "leg_receipt": os.path.basename(LEG_X[xo]), "leg_wall": legs[xo]["gnu_time"]["wall"], "leg_maxrss_kb": legs[xo]["gnu_time"]["maxrss_kb"]} for xo in (400, 500)},
                       "per_eps": {str(k): per[k] for k in KS}, "counts_A": {str(k): counts_A[k] for k in KS}, "cell_figure_A": cell, "range_A": rng, "vs_x500_min_max": [min(vs500), max(vs500)], "quad_L7_L8_min_max": [min(l78), max(l78)], "x400_vs_x500_worst_best": [worst_pair, best_pair],
                       "dps110_member_from_served_40d_min_max": [min(tp), max(tp)], "dps110_member_differences_min_max": [min(dd), max(dd)], "counts_B_from_40d": {str(k): counts_B40[k] for k in KS}, "leaves_differing": diffs, "planted_controls_all_fail_by_name": all_fail, "reproduced": (not diffs) and all_fail}
        diffs_all += diffs; all_fail_all = all_fail_all and all_fail
    reproduced = (not diffs_all) and all_fail_all
    four = {"P2 (the ../vendor_row33_p2_twins shelf, as served)": P2_SHELF["cell_figure_A"], **{pt: RESULTS[pt]["cell_figure_A"] for pt in POINTS}}
    worst4 = min([P2_SHELF["x400_vs_x500_worst"]] + [RESULTS[pt]["x400_vs_x500_worst_best"][0] for pt in POINTS])
    print("THE THREE POINTS: cell figures %s; the twins' worst pairs %s; with the P2 shelf's 76 the four-point clause reads >= %d at all four; the worst x400-vs-x500 pair over the four points %.2f"
          % ({pt: RESULTS[pt]["cell_figure_A"] for pt in POINTS}, {pt: round(RESULTS[pt]["x400_vs_x500_worst_best"][0], 2) for pt in POINTS}, min(four.values()), worst4))
    print("REPRODUCED: %s (leaves differing %d over the three points; tolerance: equality of the doubles as printed in the compare receipts; the planted controls FAIL by name at every point and eps %s)" % (reproduced, len(diffs_all), all_fail_all))
    os.makedirs(out)
    R = {"receipt": "reproduce_row33_3pts -- the row-33 three-points higher-order-twins data shelf reproduced from the shelf: at P1, P3, P4 the eight dps-140 fixed-eps values vs the point's x400 / x500 AMFlow grids' target sample [1,1,1,2,1,2,1,1]; per eps the members, the count = int(min), the planted-digit control; every convention-A leaf compared with the vendored compare receipts as printed; the dps-110 member from the served records' 40-digit strings",
         "stamp_utc": st, "points": POINTS, "target_indices": TARGET, "bar_d": a.bar, "mp_dps": mp.mp.dps, "plant_pos": a.plant_pos, "rule": json.load(open(os.path.join(G, one_rel(rows, r"compare/COMPARE_ROW33_3PTS_P1_\d{8}T\d{6}Z\.json", "P1"))))["rule"], "tolerance": "equality of the doubles as printed in the compare receipts (the JSON literals)",
         "inputs": {"group": os.path.basename(G), "vendor_manifest_rows_consumed": consumed, "rows_consumed_digest_sha256": hashlib.sha256("\n".join("%s  %s" % (consumed[r], r) for r in sorted(consumed)).encode()).hexdigest(), "vendor_manifest_sha256_at_this_run": sha(vm), "served_points_dir": (SERVED_POINTS_REL if not a.served_points else "(given)")},
         "results": RESULTS, "cell_figures": {pt: RESULTS[pt]["cell_figure_A"] for pt in POINTS}, "four_point_clause_with_the_P2_shelf": {"per_point": four, "figure": min(four.values()), "worst_pair_over_four": worst4},
         "leaves_differing": diffs_all, "planted_controls_all_fail_by_name": all_fail_all, "reproduced": reproduced,
         "PRODUCER": {"script": os.path.basename(__file__), "script_sha256": sha(os.path.abspath(__file__)), "mpmath": mp.__version__, "python": sys.version.split()[0], "stamp_source": "date -u"}}
    rp = os.path.join(out, "REPRODUCE_ROW33_3PTS.json")
    fd = os.open(rp, os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o644)
    with os.fdopen(fd, "w") as f:
        json.dump(R, f, indent=1)
    print("receipt -> %s (sha256 %s)" % (rp, sha(rp)))
    return 0 if reproduced else 1


if __name__ == "__main__":
    sys.exit(main())
