"""Checks every number and identity quoted in ballistic-family.qmd. Prints FAIL on a mismatch.
Run from anywhere:   python3 codes/ballistic-family-verify.py"""
import numpy as np
from numpy import sin, cos, tan, sqrt, pi, arctan, arccos, radians as rad, degrees as deg
from scipy.integrate import solve_ivp, trapezoid
from _ballistic import MU, RE, Q_of, psi_of, ecc, gammas_of, tff, Qmin, dpsi_dgamma, gamma_land, psi_impact

fails = 0


def ok(name, x, y, tol):
    global fails
    good = abs(float(x) - float(y)) <= tol
    fails += not good
    print("ok  " if good else "FAIL", name, round(float(x), 6), y)


# ---------------- the family, written with no Q, in the variables of the note
def e_of_ra(r, psi, ra): return (ra - r) / (ra - r * cos(psi / 2))
def e_of_g(psi, g): return sin(g) / sin(g + psi / 2)
def g_of_e(psi, e): return arctan(e * sin(psi / 2) / (1 - e * cos(psi / 2)))
def p_of_e(r, psi, e): return r * (1 - e * cos(psi / 2))
def a_of_e(r, psi, e): return p_of_e(r, psi, e) / (1 - e * e)
def ra_of_g(r, psi, g): return r * cos(g) * cos(psi / 4) / cos(g + psi / 4)
def g_of_ra(r, psi, ra): return arctan((1 - r / ra) / tan(psi / 4))
def v_of_g(r, psi, g): return sqrt(MU / r * sin(psi / 2) / (cos(g) * sin(g + psi / 2)))


def t_of_e(r, psi, e):
    a = a_of_e(r, psi, e)
    E = arccos((1 - r / a) / e)
    return 2 * sqrt(a ** 3 / MU) * (pi - E + e * sin(E))


def energy_roots(r, psi, a):
    """The real roots e of a e^2 - r cos(psi/2) e + (r - a) = 0."""
    disc = (r * cos(psi / 2)) ** 2 - 4 * a * (r - a)
    if disc < -1e-6:
        return []
    d = sqrt(max(disc, 0.0))
    return [(r * cos(psi / 2) - d) / (2 * a), (r * cos(psi / 2) + d) / (2 * a)]


def count_energy(r, psi, a):
    return len({round(x, 6) for x in energy_roots(r, psi, a) if -1e-12 <= x < 1})


r200 = RE + 200

# ---------------- identities over the whole family, against the original note's formulas in _ballistic.py
worst = 0
for pd in (10, 30, 60, 90, 120, 170, 190, 240, 300, 350):
    psi = rad(pd)
    top = pi / 2 - psi / 4
    for g in np.linspace(top / 300, top * 299 / 300, 299):
        e = e_of_g(psi, g)
        v = v_of_g(r200, psi, g)
        Q = Q_of(r200, v)
        a = a_of_e(r200, psi, e)
        ra = a * (1 + e)
        th = [(psi_of(Q, g) % (2 * pi), psi), (ecc(Q, g), e), (g_of_e(psi, e), g), (ra_of_g(r200, psi, g), ra),
              (g_of_ra(r200, psi, ra), g), (e_of_ra(r200, psi, ra), e), (r200 / (2 - Q), a),
              (t_of_e(r200, psi, e) / tff(r200, v, g), 1.0),
              (sin(2 * g + psi / 2), r200 * sin(psi / 2) / (2 * a - r200))]
        worst = max(worst, max(abs(x - y) / max(1, abs(y)) for x, y in th))
ok("all links agree with _ballistic.py, worst relative difference", worst, 0, 2e-7)

# nested arcs, ellipses pass through both points, monotonic labels (r_a, t, gamma)
bad = 0
for pd in (10, 30, 60, 90, 120, 170, 190, 240, 300, 350):
    psi = rad(pd)
    es = np.linspace(0.002, 0.995, 800)
    ths = np.linspace(-psi / 2 * 0.999, psi / 2 * 0.999, 41)
    last_r = None
    for e in es:
        p = p_of_e(r200, psi, e)
        rr = p / (1 - e * np.cos(ths))
        bad += abs(p / (1 - e * cos(psi / 2)) - r200) > 1e-9
        if last_r is not None:
            bad += np.any(rr <= last_r)
        last_r = rr
    ts = np.array([t_of_e(r200, psi, e) for e in es])
    ras = a_of_e(r200, psi, es) * (1 + es)
    gs = np.array([g_of_e(psi, e) for e in es])
    bad += np.any(np.diff(ts) <= 0) + np.any(np.diff(ras) <= 0) + np.any(np.diff(gs) <= 0)
    # floor and blow-up of the time
    bad += abs(t_of_e(r200, psi, 1e-5) / (psi * sqrt(r200 ** 3 / MU)) - 1) > 1e-3
ok("nesting, closure and monotonicity failures", bad, 0, 0)

# the margin proof for psi > 180: t = P - t_c, t_c computed as an integral over the through-perigee arc
for pd, e in ((240, 0.3), (300, 0.7)):
    psi = rad(pd)
    a, p, h = a_of_e(r200, psi, e), p_of_e(r200, psi, e), sqrt(MU * p_of_e(r200, psi, e))
    th = np.linspace(-(pi - psi / 2), pi - psi / 2, 200001)
    tc = trapezoid((p / (1 + e * np.cos(th))) ** 2 / h, th)
    ok(f"t = P - t_c at psi={pd}", 2 * pi * sqrt(a ** 3 / MU) - tc, t_of_e(r200, psi, e), 1e-5)

# energy: how many ellipses (the case list in the note)
for pd in (30, 60, 120, 170):
    psi = rad(pd)
    amin = r200 * (1 + sin(psi / 2)) / 2
    for a, n in ((amin * 0.98, 0), (amin, 1), ((amin + r200) / 2, 2), (r200, 2), (1.3 * r200, 1)):
        ok(f"psi={pd} a={a:.1f}: number of ellipses", count_energy(r200, psi, a), n, 0)
for pd in (190, 240, 300):
    psi = rad(pd)
    amin = r200 * (1 + sin(psi / 2)) / 2
    for a, n in ((amin * 0.98, 0), ((amin + r200) / 2, 0), (r200, 1), (1.3 * r200, 1)):
        ok(f"psi={pd} a={a:.1f}: number of ellipses", count_energy(r200, psi, a), n, 0)
ok("a = r has the roots 0 and cos(psi/2)", max(energy_roots(r200, rad(60), r200)), cos(rad(30)), 1e-12)
ok("discriminant form", (r200 * cos(rad(30))) ** 2 - 4 * 5000 * (r200 - 5000), (2 * 5000 - r200) ** 2 - (r200 * sin(rad(30))) ** 2, 1e-5)

# the grey ellipse of the circle figure: a > r_bo, the negative root passes through both points, and its upper arc lies below r_bo
a_, psi_ = 1.25 * r200, rad(60)
eneg = min(energy_roots(r200, psi_, a_))
ok("negative root is negative", eneg < 0, 1, 0)
ok("negative root: p = a(1-e^2) satisfies the family equation", a_ * (1 - eneg ** 2), p_of_e(r200, psi_, eneg), 1e-6)
ok("negative root: radius at the burnout point", p_of_e(r200, psi_, eneg) / (1 - eneg * cos(psi_ / 2)), r200, 1e-6)
ok("negative root: the top of its arc is the perigee, below r_bo", a_ * (1 - abs(eneg)) < r200, 1, 0)

# direct numerical integration of three members of the family: burnout state -> range angle and time
def fly(r, v, g):
    y0 = [r, 0, v * sin(g), v * cos(g)]
    def f(t, y):
        d = np.hypot(y[0], y[1]) ** 3
        return [y[2], y[3], -MU * y[0] / d, -MU * y[1] / d]
    def back(t, y):
        return np.hypot(y[0], y[1]) - r
    back.terminal, back.direction = True, -1
    s = solve_ivp(f, (1.0, 1e6), [*solve_ivp(f, (0, 1.0), y0, rtol=1e-12, atol=1e-10).y[:, -1]], events=back, rtol=1e-12, atol=1e-10)
    x, y = s.y[0, -1], s.y[1, -1]
    return np.arctan2(y, x) % (2 * pi), s.t[-1]


for gd in (9.2952, 30.0, 50.7048):
    psi = rad(60)
    an, tn = fly(r200, v_of_g(r200, psi, rad(gd)), rad(gd))
    ok(f"integrated range at gamma={gd}", deg(an), 60, 2e-3)
    ok(f"integrated time at gamma={gd}", tn, t_of_e(r200, psi, e_of_g(psi, rad(gd))), 0.5)

# ---------------- starting downward: the negative root, flown through the perigee
print("--- starting downward")
psi = rad(60)
a_ = 1.25 * r200; ok("a", a_, 8222.7, 0.05)
ok("root of the discriminant", sqrt((2 * a_ - r200) ** 2 - (r200 * sin(psi / 2)) ** 2), 9302.9, 0.05)
en = min(energy_roots(r200, psi, a_)); E_ = abs(en); ok("e", en, -0.2193, 5e-5)
vd = sqrt(MU * (2 / r200 - 1 / a_)); ok("v", vd, 8.527, 5e-4)
gd_ = g_of_e(psi, en); ok("gamma", deg(gd_), -5.26, 5e-3)
ok("perigee altitude", a_ * (1 - E_) - RE, 41.5, 0.05); ok("apogee altitude", a_ * (1 + E_) - RE, 3648, 0.5)
Ed = 2 * arctan(sqrt((1 - E_) / (1 + E_)) * tan(psi / 4)); ok("E", deg(Ed), 24.2, 0.05)
td = 2 * sqrt(a_ ** 3 / MU) * (Ed - E_ * sin(Ed)) / 60; ok("time, min", td, 13.09, 5e-3)
ok("shorter than the floor by", psi * sqrt(r200 ** 3 / MU) / 60 - td, 1.66, 5e-3)
def rhs(t, y):
    d = np.hypot(y[0], y[1]) ** 3
    return [y[2], y[3], -MU * y[0] / d, -MU * y[1] / d]
up = lambda t, y: np.hypot(y[0], y[1]) - r200
up.terminal, up.direction = True, 1
s0 = solve_ivp(rhs, (0, 1.0), [r200, 0, vd * sin(gd_), vd * cos(gd_)], rtol=1e-12, atol=1e-10).y[:, -1]
sd = solve_ivp(rhs, (1.0, 1e5), s0, events=up, rtol=1e-12, atol=1e-10)
ok("integrated range, deg", deg(np.arctan2(sd.y[1, -1], sd.y[0, -1])), 60, 1e-6); ok("integrated time, min", sd.t[-1] / 60, td, 1e-5)
ok("integrated perigee altitude", np.hypot(sd.y[0], sd.y[1]).min() - RE, a_ * (1 - E_) - RE, 0.5)
ok("climbing at the second point", (sd.y[0, -1] * sd.y[2, -1] + sd.y[1, -1] * sd.y[3, -1]) > 0, 1, 0)
a2 = 1.5 * r200; e2 = abs(min(energy_roots(r200, psi, a2)))
ok("a = 1.5 r: v", sqrt(MU * (2 / r200 - 1 / a2)), 8.988, 5e-4); ok("a = 1.5 r: perigee altitude", a2 * (1 - e2) - RE, -32, 0.5)
# the negative root exists only above the circular speed, at this range
ok("no negative root at a = 0.9 r", min(energy_roots(r200, psi, 0.9 * r200)) > 0, 1, 0)

# ---------------- the numbers of the note: burnout 200 km, psi = 60 deg
psi = rad(60)
print("--- the running case")
ok("r_bo", r200, 6578.137, 1e-9)
ok("ground range", psi * RE, 6679, 0.5)
ok("psi/4 top of gamma", 90 - 60 / 4, 75, 0)
vc = sqrt(MU / r200); ok("v_c", vc, 7.784, 5e-4)
tc = psi * sqrt(r200 ** 3 / MU) / 60; ok("floor of the time, min", tc, 14.75, 5e-3)

# example: apogee 1000 km
ra = RE + 1000; ok("r_a", ra, 7378.137, 1e-9)
e = e_of_ra(r200, psi, ra); ok("apogee example e", e, 0.4758, 5e-5)
ok("apogee example p", p_of_e(r200, psi, e), 3867.5, 0.05); ok("apogee example a", a_of_e(r200, psi, e), 4999.3, 0.05)
ok("numerator", ra - r200, 800, 1e-9); ok("denominator", ra - r200 * cos(rad(30)), 1681.3, 0.05)
ok("r cos 30", r200 * cos(rad(30)), 5696.8, 0.05); ok("1-r/ra", 1 - r200 / ra, 0.10843, 5e-6)
ok("cot 15", 1 / tan(rad(15)), 3.7321, 5e-5)
ga = g_of_ra(r200, psi, ra); ok("apogee example gamma", deg(ga), 22.03, 5e-3); ok("apogee example v", v_of_g(r200, psi, ga), 6.439, 5e-4)
ok("apogee example t", t_of_e(r200, psi, e) / 60, 22.41, 5e-3)

# example: energy
vp = sqrt(0.8 * MU / r200); ok("the pair's speed", vp, 6.9625, 5e-5)
ap = 1 / (2 / r200 - vp ** 2 / MU); ok("the pair's a", ap, 5481.8, 0.05)
amin = r200 * (1 + sin(psi / 2)) / 2; ok("a_min", amin, 4933.6, 0.05)
ok("2a-r", 2 * ap - r200, 4385.4, 0.05); ok("r sin 30", r200 * sin(rad(30)), 3289.1, 0.05)
elo, ehi = energy_roots(r200, psi, ap); ok("low root e", elo, 0.2550, 5e-5); ok("high root e", ehi, 0.7842, 5e-5)
ok("sqrt disc", sqrt((2 * ap - r200) ** 2 - (r200 * sin(rad(30))) ** 2), 2900.7, 0.05)
ok("low apogee altitude", a_of_e(r200, psi, elo) * (1 + elo) - RE, 502, 0.5); ok("high apogee altitude", a_of_e(r200, psi, ehi) * (1 + ehi) - RE, 3402, 0.5)
ok("low time", t_of_e(r200, psi, elo) / 60, 17.74, 5e-3); ok("high time", t_of_e(r200, psi, ehi) / 60, 44.38, 5e-3)
glo, ghi = g_of_e(psi, elo), g_of_e(psi, ehi); ok("low gamma", deg(glo), 9.30, 5e-3); ok("high gamma", deg(ghi), 50.70, 5e-3)
ok("sine form of the pair", sin(2 * glo + psi / 2), r200 * sin(psi / 2) / (2 * ap - r200), 1e-9)
ok("arcsine", deg(np.arcsin(r200 * sin(psi / 2) / (2 * ap - r200))), 48.59, 5e-3)
ok("same as original note's pair", deg(gammas_of(0.8, psi)[0]), deg(glo), 1e-6)

# minimum energy
g30 = rad(30); e30 = e_of_g(psi, g30)
ok("min energy gamma", 45 - 60 / 4, 30, 0); ok("min energy e", e30, 0.5774, 5e-5); ok("min energy v", v_of_g(r200, psi, g30), 6.356, 5e-4)
ok("min energy a equals a_min", a_of_e(r200, psi, e30), amin, 1e-6); ok("min energy Q", Q_of(r200, v_of_g(r200, psi, g30)), Qmin(psi), 1e-9)
ok("min energy apogee", a_of_e(r200, psi, e30) * (1 + e30) - RE, 1404, 0.5); ok("min energy time", t_of_e(r200, psi, e30) / 60, 26.10, 5e-3)

# example: time, by halving
print("--- halving for 30 min")
lo, hi = 0.0, 1.0
hist = []
for i in range(40):
    m = (lo + hi) / 2
    tm = t_of_e(r200, psi, m) / 60
    if i < 7:
        print(f"    {i+1}: e={m:.5f}  t={tm:.2f}")
    hist.append((m, tm))
    if tm > 30: hi = m
    else: lo = m
e30min = (lo + hi) / 2
for i, (m, tm) in enumerate(((0.5, 23.16), (0.75, 39.20), (0.625, 28.51), (0.6875, 32.77), (0.65625, 30.44), (0.640625, 29.43), (0.6484375, 29.92))):
    ok(f"halving step {i+1} e", hist[i][0], m, 1e-9); ok(f"halving step {i+1} t", hist[i][1], tm, 5e-3)
ok("time example e", e30min, 0.6496, 5e-5); g30min = g_of_e(psi, e30min)
ok("time example gamma", deg(g30min), 36.59, 5e-3); ok("time example v", v_of_g(r200, psi, g30min), 6.412, 5e-4)
ok("time example apogee", a_of_e(r200, psi, e30min) * (1 + e30min) - RE, 1834, 0.5); ok("time example a", a_of_e(r200, psi, e30min), 4978, 0.5)

# earliest arrival
print("--- earliest arrival")
es = (r200 - RE) / (RE + r200 * cos(rad(30))); gs = g_of_e(psi, es)
ok("e_star", es, 0.0166, 5e-5); ok("perigee at the surface", a_of_e(r200, psi, es) * (1 - es), RE, 1e-6)
ok("gamma_star", deg(gs), 0.48, 5e-3); ok("v at gamma_star", v_of_g(r200, psi, gs), 7.729, 5e-4)
ok("t at gamma_star", t_of_e(r200, psi, es) / 60, 14.90, 5e-3); ok("apogee at gamma_star", a_of_e(r200, psi, es) * (1 + es) - RE, 215, 0.5)
ok("same as landing condition of the main note", deg(gamma_land(Q_of(r200, v_of_g(r200, psi, gs)), r200)), deg(gs), 1e-6)
v73 = 7.3; a73 = 1 / (2 / r200 - v73 ** 2 / MU); l73, h73 = energy_roots(r200, psi, a73)
ok("7.3 low e", l73, 0.1463, 5e-5); ok("7.3 low gamma", deg(g_of_e(psi, l73)), 4.79, 5e-3)
ok("7.3 a", a73, 5870.5, 0.05); ok("7.3 low time", t_of_e(r200, psi, l73) / 60, 16.27, 5e-3); ok("7.3 low apogee", a_of_e(r200, psi, l73) * (1 + l73) - RE, 351, 0.5)
ok("7.3 high gamma", deg(g_of_e(psi, h73)), 55.21, 5e-3); ok("7.3 high time", t_of_e(r200, psi, h73) / 60, 53.18, 5e-3)
# what the speed buys, relative to minimum energy
vm, tm = v_of_g(r200, psi, g30), t_of_e(r200, psi, e30) / 60
ok("pair minus min, speed", vp - vm, 0.61, 5e-3); ok("pair minus min, time", tm - t_of_e(r200, psi, elo) / 60, 8.4, 0.05)
ok("7.3 minus min, speed", 7.3 - vm, 0.94, 5e-3); ok("7.3 minus min, time", tm - t_of_e(r200, psi, l73) / 60, 9.8, 0.05)
ok("graze minus min, speed", v_of_g(r200, psi, gs) - vm, 1.37, 5e-3); ok("graze minus min, time", tm - t_of_e(r200, psi, es) / 60, 11.2, 0.05)
ok("high apogee over low apogee", (a_of_e(r200, psi, ehi) * (1 + ehi) - RE) / (a_of_e(r200, psi, elo) * (1 + elo) - RE), 6.8, 0.05)
ok("high minus low time", (t_of_e(r200, psi, ehi) - t_of_e(r200, psi, elo)) / 60, 26.6, 0.05)
# eq-bf-a-g is the original note's eq-fpa: (2-Q)/Q = r/(2a-r); and the sign of gamma_1 on both sides of a = r
ok("(2-Q)/Q = r/(2a-r)", (2 - Q_of(r200, vp)) / Q_of(r200, vp), r200 / (2 * ap - r200), 1e-10)
for a_, sign in ((0.9 * r200, 1), (1.3 * r200, -1)):
    A = np.arcsin(r200 * sin(psi / 2) / (2 * a_ - r200))
    ok(f"sign of gamma_1 at a/r={a_/r200}", np.sign(A - psi / 2), sign, 0); ok(f"gamma_2 positive at a/r={a_/r200}", pi - A - psi / 2 > 0, 1, 0)
# circular speed, high arc
g60 = (pi - psi) / 2; ok("gamma at v_c", deg(g60), 60, 1e-9); ok("v at that gamma", v_of_g(r200, psi, g60), vc, 1e-9)
e60 = e_of_g(psi, g60); ok("e at v_c equals cos 30", e60, cos(rad(30)), 1e-12)
ok("t at v_c", t_of_e(r200, psi, e60) / 60, 68.64, 5e-3); ok("apogee at v_c", a_of_e(r200, psi, e60) * (1 + e60) - RE, 5897, 0.5)

# table: miss for one arcminute at fixed speed
print("--- miss per arcminute")
am = rad(1 / 60)
for name, g, val, tol in (("graze", gs, 189, 0.5), ("7.3 low", g_of_e(psi, l73), 17.2, 0.05), ("low", glo, 7.7, 0.05), ("apogee 1000", ga, 1.5, 0.05),
                          ("30 min", g30min, 0.9, 0.05), ("high", ghi, 2.5, 0.05), ("v_c", g60, 3.7, 0.05)):
    ok(f"miss {name}, km per arcmin", abs(dpsi_dgamma(psi, g)) * am * RE, val, tol)
    # finite difference at fixed speed, from the range equation
    Q = Q_of(r200, v_of_g(r200, psi, g))
    fd = (psi_of(Q, g + am / 100) - psi_of(Q, g - am / 100)) / (2 * am / 100) if g > 2 * am else None
    if fd is not None:
        ok(f"  against finite difference ({name})", fd, dpsi_dgamma(psi, g), 1e-3 * max(1, abs(fd)))
Q30 = Qmin(psi)
ok("min energy: second-order miss, m", 1e3 * abs(psi_of(Q30, g30 + am) - psi) * RE, 2, 1.0)

# extra angle flown from the re-entry radius down to the ground, no atmosphere
print("--- extra angle to the ground")
def extra(r, psi, e):
    fg = arccos((p_of_e(r, psi, e) / RE - 1) / e)
    return deg(pi - psi / 2 - fg)
for name, e_, val in (("graze", es, 150), ("7.3 low", l73, 17.2), ("low", elo, 9.6), ("apogee 1000", e, 4.2), ("min", e30, 3.0), ("30 min", e30min, 2.3), ("high", ehi, 1.4), ("v_c", e60, 1.0)):
    ok(f"extra angle {name}", extra(r200, psi, e_), val, 0.05)
    ok(f"  same as psi_impact - psi ({name})", deg(psi_impact(Q_of(r200, v_of_g(r200, psi, g_of_e(psi, e_))), g_of_e(psi, e_), r200) - psi), extra(r200, psi, e_), 1e-4)
ok("low in km", rad(extra(r200, psi, elo)) * RE, 1070, 5); ok("7.3 low in km", rad(extra(r200, psi, l73)) * RE, 1920, 5)
# returns from extra speed, step by step
ok("step 2 speed", 7.3 - vp, 0.34, 5e-3); ok("step 2 time", (t_of_e(r200, psi, elo) - t_of_e(r200, psi, l73)) / 60, 1.5, 0.05)
ok("step 3 speed", v_of_g(r200, psi, gs) - 7.3, 0.43, 5e-3); ok("step 3 time", (t_of_e(r200, psi, l73) - t_of_e(r200, psi, es)) / 60, 1.4, 0.05)
ok("double root is the min-energy e", cos(psi / 2) / (1 + sin(psi / 2)), e30, 1e-12)

# apogee sensitivity along the family
for gd, val in ((9.2952, 35), (50.7048, 170), (70, 3780)):
    g = rad(gd); h = 1e-6
    ok(f"dr_a/dgamma at {gd}, km per deg", (r200 / 2) * sin(psi / 2) / cos(g + psi / 4) ** 2 * rad(1), val, 0.5 if val < 100 else 1 if val < 1000 else 5)
    ok(f"  against finite difference", (r200 / 2) * sin(psi / 2) / cos(g + psi / 4) ** 2, (ra_of_g(r200, psi, g + h) - ra_of_g(r200, psi, g - h)) / (2 * h), 1e-2)

# sounding rocket task
print("--- sounding rocket")
rb, ras, pss = RE + 50, RE + 475, rad(2)
gsr = g_of_ra(rb, pss, ras); ok("task r_bo", rb, 6428.137, 1e-9); ok("task r_a", ras, 6853.137, 1e-9)
ok("task 1-r/ra", 1 - rb / ras, 0.06202, 5e-6); ok("task cot(0.5 deg)", 1 / tan(rad(0.5)), 114.59, 5e-3)
ok("task gamma", deg(gsr), 81.99, 5e-3); ok("task v", v_of_g(rb, pss, gsr), 2.797, 5e-4); ok("task ground range", pss * RE, 223, 0.5)
ok("task: 5 km more apogee, deg", deg(g_of_ra(rb, pss, RE + 480) - gsr), 0.09, 5e-3)

print("failures:", fails)
