"""Recompute a ParetoAlpha data API content hash. Standard library only. (A FULCRUM seal: verify_seal.py, beside this file.)

    body = requests.get(url, headers=H).json()
    assert content_sha256(body["data"]) == body["meta"]["contentSha256"]

The canonical form: object keys sorted, no whitespace, non-ASCII left as is, null for missing, and every number
rounded to 12 significant digits (15 at 1e10 and above) and written the way JavaScript writes a number.
"""
import hashlib, json
from decimal import Decimal


def js_number(x: float) -> str:
    """The shortest round-trip digits, laid out by ECMAScript's Number::toString rules."""
    if x != x or x in (float("inf"), float("-inf")):
        return "null"
    if x == 0:
        return "0"
    sign = "-" if x < 0 else ""
    digits, exp = Decimal(repr(abs(x))).as_tuple()[1:]
    s = "".join(map(str, digits)).rstrip("0") or "0"
    exp += len("".join(map(str, digits))) - len(s)          # exponent of the last kept digit
    n = len(s) + exp                                         # position of the decimal point
    if 0 < n <= 21:
        body = s + "0" * (n - len(s)) if len(s) <= n else s[:n] + "." + s[n:]
    elif -6 < n <= 0:
        body = "0." + "0" * (-n) + s
    else:
        e = n - 1
        body = (s[0] + ("." + s[1:] if len(s) > 1 else "")) + "e" + ("+" if e >= 0 else "-") + str(abs(e))
    return sign + body


def _round(x: float) -> float:
    return float(f"{x:.{14 if abs(x) >= 1e10 else 11}e}")


def _dump(v) -> str:
    if v is None:
        return "null"
    if v is True:
        return "true"
    if v is False:
        return "false"
    if isinstance(v, (int, float)):
        return js_number(_round(float(v)))
    if isinstance(v, str):
        return json.dumps(v, ensure_ascii=False)
    if isinstance(v, (list, tuple)):
        return "[" + ",".join(_dump(i) for i in v) + "]"
    # JavaScript sorts keys by UTF-16 code unit; for the ASCII keys this API uses, that is Python's default order.
    return "{" + ",".join(json.dumps(k, ensure_ascii=False) + ":" + _dump(v[k]) for k in sorted(v)) + "}"


def content_sha256(data) -> str:
    return hashlib.sha256(_dump(data).encode("utf-8")).hexdigest()


if __name__ == "__main__":
    import sys
    print(content_sha256(json.load(sys.stdin)))
