FAILURE MAP
← Case archive

FA-68056 / Traffic signal timing plans / Open access

Shortway offset transition: the offset error is computed current minus target · case 01

Shortway offset transition returns a wrong result when the offset error is computed current minus target.

Verified by executionVariant 1 · 8 checks per implementationDownload source bundle ↓JSON ↗

ROOT CAUSE

The error sign is reversed, so lengthening moves the controller further from the target offset.

VERIFIED REPAIR

Restore the offset error direction rule so that the step reads `(x['target_offset'] - x['current_offset']) % C`.

Unsuccessful approach: The absolute difference is wrong whenever the target offset is numerically behind the current offset.

Case contract

Input {cycle, current_offset, target_offset, lengthen_pct, shorten_pct}. The needed correction e = (target - current) mod cycle can be made by lengthening cycles by a total of e or shortening them by cycle - e. Per-cycle limits are floor(cycle*pct/100). Choose the direction needing fewer cycles (ties lengthen) and front-load the maximum adjustment each cycle. Return the list of transition cycle lengths ([] when already in step).

Why this case matters

Signal timing arithmetic is exact and integer or rational; a wrong rule silently produces unsafe or inefficient timing plans.

1 / The failure

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    C = x['cycle']
    e = (x['current_offset'] - x['target_offset']) % C
    if e == 0:
        return []
    L = C * x['lengthen_pct'] // 100
    S = C * x['shorten_pct'] // 100
    nl = -(-e // L)
    ns = -(-(C - e) // S)
    if nl <= ns:
        amt, step, sign = e, L, 1
    else:
        amt, step, sign = C - e, S, -1
    out = []
    while amt > 0:
        d = min(step, amt)
        out.append(C + sign * d)
        amt -= d
    return out
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[({'cycle': 100, 'current_offset': 10, 'target_offset': 50, 'lengthen_pct': 20, 'shorten_pct': 20}, [120, 120]), ({'cycle': 80, 'current_offset': 13, 'target_offset': 43, 'lengthen_pct': 10, 'shorten_pct': 20}, [88, 88, 88, 86]), ({'cycle': 90, 'current_offset': 30, 'target_offset': 30, 'lengthen_pct': 20, 'shorten_pct': 17}, []), ({'cycle': 90, 'current_offset': 57, 'target_offset': 57, 'lengthen_pct': 25, 'shorten_pct': 17}, []), ({'cycle': 120, 'current_offset': 90, 'target_offset': 20, 'lengthen_pct': 17, 'shorten_pct': 13}, [140, 140, 130]), ({'cycle': 120, 'current_offset': 50, 'target_offset': 46, 'lengthen_pct': 10, 'shorten_pct': 17}, [116]), ({'cycle': 110, 'current_offset': 65, 'target_offset': 65, 'lengthen_pct': 25, 'shorten_pct': 20}, []), ({'cycle': 90, 'current_offset': 3, 'target_offset': 3, 'lengthen_pct': 20, 'shorten_pct': 20}, [])], [({'cycle': 120, 'current_offset': 90, 'target_offset': 20, 'lengthen_pct': 17, 'shorten_pct': 13}, [140, 140, 130]), ({'cycle': 90, 'current_offset': 60, 'target_offset': 15, 'lengthen_pct': 20, 'shorten_pct': 13}, [108, 108, 99]), ({'cycle': 150, 'current_offset': 87, 'target_offset': 6, 'lengthen_pct': 20, 'shorten_pct': 17}, [180, 180, 159]), ({'cycle': 100, 'current_offset': 10, 'target_offset': 50, 'lengthen_pct': 20, 'shorten_pct': 20}, [120, 120]), ({'cycle': 90, 'current_offset': 30, 'target_offset': 30, 'lengthen_pct': 20, 'shorten_pct': 17}, []), ({'cycle': 150, 'current_offset': 116, 'target_offset': 41, 'lengthen_pct': 25, 'shorten_pct': 17}, [187, 187, 151]), ({'cycle': 60, 'current_offset': 49, 'target_offset': 49, 'lengthen_pct': 10, 'shorten_pct': 10}, []), ({'cycle': 60, 'current_offset': 29, 'target_offset': 36, 'lengthen_pct': 25, 'shorten_pct': 17}, [67])], [({'cycle': 140, 'current_offset': 36, 'target_offset': 36, 'lengthen_pct': 10, 'shorten_pct': 10}, []), ({'cycle': 100, 'current_offset': 57, 'target_offset': 57, 'lengthen_pct': 25, 'shorten_pct': 20}, []), ({'cycle': 90, 'current_offset': 30, 'target_offset': 30, 'lengthen_pct': 20, 'shorten_pct': 17}, []), ({'cycle': 120, 'current_offset': 90, 'target_offset': 20, 'lengthen_pct': 17, 'shorten_pct': 13}, [140, 140, 130]), ({'cycle': 140, 'current_offset': 17, 'target_offset': 133, 'lengthen_pct': 10, 'shorten_pct': 17}, [117, 139]), ({'cycle': 100, 'current_offset': 10, 'target_offset': 50, 'lengthen_pct': 20, 'shorten_pct': 20}, [120, 120]), ({'cycle': 140, 'current_offset': 98, 'target_offset': 45, 'lengthen_pct': 17, 'shorten_pct': 13}, [122, 122, 123]), ({'cycle': 140, 'current_offset': 87, 'target_offset': 17, 'lengthen_pct': 10, 'shorten_pct': 17}, [117, 117, 117, 139])], [({'cycle': 100, 'current_offset': 10, 'target_offset': 50, 'lengthen_pct': 20, 'shorten_pct': 20}, [120, 120]), ({'cycle': 110, 'current_offset': 75, 'target_offset': 20, 'lengthen_pct': 10, 'shorten_pct': 10}, [121, 121, 121, 121, 121]), ({'cycle': 120, 'current_offset': 90, 'target_offset': 20, 'lengthen_pct': 17, 'shorten_pct': 13}, [140, 140, 130]), ({'cycle': 150, 'current_offset': 79, 'target_offset': 79, 'lengthen_pct': 17, 'shorten_pct': 20}, []), ({'cycle': 150, 'current_offset': 127, 'target_offset': 28, 'lengthen_pct': 10, 'shorten_pct': 13}, [165, 165, 165, 156]), ({'cycle': 130, 'current_offset': 28, 'target_offset': 93, 'lengthen_pct': 20, 'shorten_pct': 17}, [156, 156, 143]), ({'cycle': 90, 'current_offset': 30, 'target_offset': 30, 'lengthen_pct': 20, 'shorten_pct': 17}, []), ({'cycle': 150, 'current_offset': 107, 'target_offset': 141, 'lengthen_pct': 17, 'shorten_pct': 20}, [175, 159])], [({'cycle': 120, 'current_offset': 90, 'target_offset': 20, 'lengthen_pct': 17, 'shorten_pct': 13}, [140, 140, 130]), ({'cycle': 90, 'current_offset': 30, 'target_offset': 30, 'lengthen_pct': 20, 'shorten_pct': 17}, []), ({'cycle': 100, 'current_offset': 71, 'target_offset': 71, 'lengthen_pct': 10, 'shorten_pct': 10}, []), ({'cycle': 100, 'current_offset': 10, 'target_offset': 50, 'lengthen_pct': 20, 'shorten_pct': 20}, [120, 120]), ({'cycle': 150, 'current_offset': 86, 'target_offset': 11, 'lengthen_pct': 20, 'shorten_pct': 20}, [180, 180, 165]), ({'cycle': 110, 'current_offset': 1, 'target_offset': 55, 'lengthen_pct': 25, 'shorten_pct': 13}, [137, 137]), ({'cycle': 90, 'current_offset': 46, 'target_offset': 8, 'lengthen_pct': 20, 'shorten_pct': 13}, [108, 108, 106]), ({'cycle': 90, 'current_offset': 88, 'target_offset': 43, 'lengthen_pct': 17, 'shorten_pct': 10}, [105, 105, 105])]]
for i, (args, expected) in enumerate(fixtures[N-1]):
    check('timing oracle' + ' %d' % i, solve(args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
Boundary fixtureActualExpectedOutcome
timing oracle 0[80, 80][120, 120]Failed
timing oracle 1[64, 66][88, 88, 88, 86]Failed
timing oracle 2[][]Passed
timing oracle 3[][]Passed
timing oracle 4[140, 140, 140, 130][140, 140, 130]Failed
timing oracle 5[124][116]Failed
timing oracle 6[][]Passed
timing oracle 7[][]Passed

SHA-256 / 20e45c3cee7bf7535402e4c6cc9ad1ba940582beded2b54a81404088461fffcd

2 / The unsuccessful fix

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    C = x['cycle']
    e = abs(x['target_offset'] - x['current_offset'])
    if e == 0:
        return []
    L = C * x['lengthen_pct'] // 100
    S = C * x['shorten_pct'] // 100
    nl = -(-e // L)
    ns = -(-(C - e) // S)
    if nl <= ns:
        amt, step, sign = e, L, 1
    else:
        amt, step, sign = C - e, S, -1
    out = []
    while amt > 0:
        d = min(step, amt)
        out.append(C + sign * d)
        amt -= d
    return out
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[({'cycle': 100, 'current_offset': 10, 'target_offset': 50, 'lengthen_pct': 20, 'shorten_pct': 20}, [120, 120]), ({'cycle': 80, 'current_offset': 13, 'target_offset': 43, 'lengthen_pct': 10, 'shorten_pct': 20}, [88, 88, 88, 86]), ({'cycle': 90, 'current_offset': 30, 'target_offset': 30, 'lengthen_pct': 20, 'shorten_pct': 17}, []), ({'cycle': 90, 'current_offset': 57, 'target_offset': 57, 'lengthen_pct': 25, 'shorten_pct': 17}, []), ({'cycle': 120, 'current_offset': 90, 'target_offset': 20, 'lengthen_pct': 17, 'shorten_pct': 13}, [140, 140, 130]), ({'cycle': 120, 'current_offset': 50, 'target_offset': 46, 'lengthen_pct': 10, 'shorten_pct': 17}, [116]), ({'cycle': 110, 'current_offset': 65, 'target_offset': 65, 'lengthen_pct': 25, 'shorten_pct': 20}, []), ({'cycle': 90, 'current_offset': 3, 'target_offset': 3, 'lengthen_pct': 20, 'shorten_pct': 20}, [])], [({'cycle': 120, 'current_offset': 90, 'target_offset': 20, 'lengthen_pct': 17, 'shorten_pct': 13}, [140, 140, 130]), ({'cycle': 90, 'current_offset': 60, 'target_offset': 15, 'lengthen_pct': 20, 'shorten_pct': 13}, [108, 108, 99]), ({'cycle': 150, 'current_offset': 87, 'target_offset': 6, 'lengthen_pct': 20, 'shorten_pct': 17}, [180, 180, 159]), ({'cycle': 100, 'current_offset': 10, 'target_offset': 50, 'lengthen_pct': 20, 'shorten_pct': 20}, [120, 120]), ({'cycle': 90, 'current_offset': 30, 'target_offset': 30, 'lengthen_pct': 20, 'shorten_pct': 17}, []), ({'cycle': 150, 'current_offset': 116, 'target_offset': 41, 'lengthen_pct': 25, 'shorten_pct': 17}, [187, 187, 151]), ({'cycle': 60, 'current_offset': 49, 'target_offset': 49, 'lengthen_pct': 10, 'shorten_pct': 10}, []), ({'cycle': 60, 'current_offset': 29, 'target_offset': 36, 'lengthen_pct': 25, 'shorten_pct': 17}, [67])], [({'cycle': 140, 'current_offset': 36, 'target_offset': 36, 'lengthen_pct': 10, 'shorten_pct': 10}, []), ({'cycle': 100, 'current_offset': 57, 'target_offset': 57, 'lengthen_pct': 25, 'shorten_pct': 20}, []), ({'cycle': 90, 'current_offset': 30, 'target_offset': 30, 'lengthen_pct': 20, 'shorten_pct': 17}, []), ({'cycle': 120, 'current_offset': 90, 'target_offset': 20, 'lengthen_pct': 17, 'shorten_pct': 13}, [140, 140, 130]), ({'cycle': 140, 'current_offset': 17, 'target_offset': 133, 'lengthen_pct': 10, 'shorten_pct': 17}, [117, 139]), ({'cycle': 100, 'current_offset': 10, 'target_offset': 50, 'lengthen_pct': 20, 'shorten_pct': 20}, [120, 120]), ({'cycle': 140, 'current_offset': 98, 'target_offset': 45, 'lengthen_pct': 17, 'shorten_pct': 13}, [122, 122, 123]), ({'cycle': 140, 'current_offset': 87, 'target_offset': 17, 'lengthen_pct': 10, 'shorten_pct': 17}, [117, 117, 117, 139])], [({'cycle': 100, 'current_offset': 10, 'target_offset': 50, 'lengthen_pct': 20, 'shorten_pct': 20}, [120, 120]), ({'cycle': 110, 'current_offset': 75, 'target_offset': 20, 'lengthen_pct': 10, 'shorten_pct': 10}, [121, 121, 121, 121, 121]), ({'cycle': 120, 'current_offset': 90, 'target_offset': 20, 'lengthen_pct': 17, 'shorten_pct': 13}, [140, 140, 130]), ({'cycle': 150, 'current_offset': 79, 'target_offset': 79, 'lengthen_pct': 17, 'shorten_pct': 20}, []), ({'cycle': 150, 'current_offset': 127, 'target_offset': 28, 'lengthen_pct': 10, 'shorten_pct': 13}, [165, 165, 165, 156]), ({'cycle': 130, 'current_offset': 28, 'target_offset': 93, 'lengthen_pct': 20, 'shorten_pct': 17}, [156, 156, 143]), ({'cycle': 90, 'current_offset': 30, 'target_offset': 30, 'lengthen_pct': 20, 'shorten_pct': 17}, []), ({'cycle': 150, 'current_offset': 107, 'target_offset': 141, 'lengthen_pct': 17, 'shorten_pct': 20}, [175, 159])], [({'cycle': 120, 'current_offset': 90, 'target_offset': 20, 'lengthen_pct': 17, 'shorten_pct': 13}, [140, 140, 130]), ({'cycle': 90, 'current_offset': 30, 'target_offset': 30, 'lengthen_pct': 20, 'shorten_pct': 17}, []), ({'cycle': 100, 'current_offset': 71, 'target_offset': 71, 'lengthen_pct': 10, 'shorten_pct': 10}, []), ({'cycle': 100, 'current_offset': 10, 'target_offset': 50, 'lengthen_pct': 20, 'shorten_pct': 20}, [120, 120]), ({'cycle': 150, 'current_offset': 86, 'target_offset': 11, 'lengthen_pct': 20, 'shorten_pct': 20}, [180, 180, 165]), ({'cycle': 110, 'current_offset': 1, 'target_offset': 55, 'lengthen_pct': 25, 'shorten_pct': 13}, [137, 137]), ({'cycle': 90, 'current_offset': 46, 'target_offset': 8, 'lengthen_pct': 20, 'shorten_pct': 13}, [108, 108, 106]), ({'cycle': 90, 'current_offset': 88, 'target_offset': 43, 'lengthen_pct': 17, 'shorten_pct': 10}, [105, 105, 105])]]
for i, (args, expected) in enumerate(fixtures[N-1]):
    check('timing oracle' + ' %d' % i, solve(args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
Boundary fixtureActualExpectedOutcome
timing oracle 0[120, 120][120, 120]Passed
timing oracle 1[88, 88, 88, 86][88, 88, 88, 86]Passed
timing oracle 2[][]Passed
timing oracle 3[][]Passed
timing oracle 4[140, 140, 140, 130][140, 140, 130]Failed
timing oracle 5[124][116]Failed
timing oracle 6[][]Passed
timing oracle 7[][]Passed

SHA-256 / 3cfae46ad674409527019a369960c00864edadf418f93b932f9f1ee601878a1b

3 / The verified repair

Exit 0
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    C = x['cycle']
    e = (x['target_offset'] - x['current_offset']) % C
    if e == 0:
        return []
    L = C * x['lengthen_pct'] // 100
    S = C * x['shorten_pct'] // 100
    nl = -(-e // L)
    ns = -(-(C - e) // S)
    if nl <= ns:
        amt, step, sign = e, L, 1
    else:
        amt, step, sign = C - e, S, -1
    out = []
    while amt > 0:
        d = min(step, amt)
        out.append(C + sign * d)
        amt -= d
    return out
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[({'cycle': 100, 'current_offset': 10, 'target_offset': 50, 'lengthen_pct': 20, 'shorten_pct': 20}, [120, 120]), ({'cycle': 80, 'current_offset': 13, 'target_offset': 43, 'lengthen_pct': 10, 'shorten_pct': 20}, [88, 88, 88, 86]), ({'cycle': 90, 'current_offset': 30, 'target_offset': 30, 'lengthen_pct': 20, 'shorten_pct': 17}, []), ({'cycle': 90, 'current_offset': 57, 'target_offset': 57, 'lengthen_pct': 25, 'shorten_pct': 17}, []), ({'cycle': 120, 'current_offset': 90, 'target_offset': 20, 'lengthen_pct': 17, 'shorten_pct': 13}, [140, 140, 130]), ({'cycle': 120, 'current_offset': 50, 'target_offset': 46, 'lengthen_pct': 10, 'shorten_pct': 17}, [116]), ({'cycle': 110, 'current_offset': 65, 'target_offset': 65, 'lengthen_pct': 25, 'shorten_pct': 20}, []), ({'cycle': 90, 'current_offset': 3, 'target_offset': 3, 'lengthen_pct': 20, 'shorten_pct': 20}, [])], [({'cycle': 120, 'current_offset': 90, 'target_offset': 20, 'lengthen_pct': 17, 'shorten_pct': 13}, [140, 140, 130]), ({'cycle': 90, 'current_offset': 60, 'target_offset': 15, 'lengthen_pct': 20, 'shorten_pct': 13}, [108, 108, 99]), ({'cycle': 150, 'current_offset': 87, 'target_offset': 6, 'lengthen_pct': 20, 'shorten_pct': 17}, [180, 180, 159]), ({'cycle': 100, 'current_offset': 10, 'target_offset': 50, 'lengthen_pct': 20, 'shorten_pct': 20}, [120, 120]), ({'cycle': 90, 'current_offset': 30, 'target_offset': 30, 'lengthen_pct': 20, 'shorten_pct': 17}, []), ({'cycle': 150, 'current_offset': 116, 'target_offset': 41, 'lengthen_pct': 25, 'shorten_pct': 17}, [187, 187, 151]), ({'cycle': 60, 'current_offset': 49, 'target_offset': 49, 'lengthen_pct': 10, 'shorten_pct': 10}, []), ({'cycle': 60, 'current_offset': 29, 'target_offset': 36, 'lengthen_pct': 25, 'shorten_pct': 17}, [67])], [({'cycle': 140, 'current_offset': 36, 'target_offset': 36, 'lengthen_pct': 10, 'shorten_pct': 10}, []), ({'cycle': 100, 'current_offset': 57, 'target_offset': 57, 'lengthen_pct': 25, 'shorten_pct': 20}, []), ({'cycle': 90, 'current_offset': 30, 'target_offset': 30, 'lengthen_pct': 20, 'shorten_pct': 17}, []), ({'cycle': 120, 'current_offset': 90, 'target_offset': 20, 'lengthen_pct': 17, 'shorten_pct': 13}, [140, 140, 130]), ({'cycle': 140, 'current_offset': 17, 'target_offset': 133, 'lengthen_pct': 10, 'shorten_pct': 17}, [117, 139]), ({'cycle': 100, 'current_offset': 10, 'target_offset': 50, 'lengthen_pct': 20, 'shorten_pct': 20}, [120, 120]), ({'cycle': 140, 'current_offset': 98, 'target_offset': 45, 'lengthen_pct': 17, 'shorten_pct': 13}, [122, 122, 123]), ({'cycle': 140, 'current_offset': 87, 'target_offset': 17, 'lengthen_pct': 10, 'shorten_pct': 17}, [117, 117, 117, 139])], [({'cycle': 100, 'current_offset': 10, 'target_offset': 50, 'lengthen_pct': 20, 'shorten_pct': 20}, [120, 120]), ({'cycle': 110, 'current_offset': 75, 'target_offset': 20, 'lengthen_pct': 10, 'shorten_pct': 10}, [121, 121, 121, 121, 121]), ({'cycle': 120, 'current_offset': 90, 'target_offset': 20, 'lengthen_pct': 17, 'shorten_pct': 13}, [140, 140, 130]), ({'cycle': 150, 'current_offset': 79, 'target_offset': 79, 'lengthen_pct': 17, 'shorten_pct': 20}, []), ({'cycle': 150, 'current_offset': 127, 'target_offset': 28, 'lengthen_pct': 10, 'shorten_pct': 13}, [165, 165, 165, 156]), ({'cycle': 130, 'current_offset': 28, 'target_offset': 93, 'lengthen_pct': 20, 'shorten_pct': 17}, [156, 156, 143]), ({'cycle': 90, 'current_offset': 30, 'target_offset': 30, 'lengthen_pct': 20, 'shorten_pct': 17}, []), ({'cycle': 150, 'current_offset': 107, 'target_offset': 141, 'lengthen_pct': 17, 'shorten_pct': 20}, [175, 159])], [({'cycle': 120, 'current_offset': 90, 'target_offset': 20, 'lengthen_pct': 17, 'shorten_pct': 13}, [140, 140, 130]), ({'cycle': 90, 'current_offset': 30, 'target_offset': 30, 'lengthen_pct': 20, 'shorten_pct': 17}, []), ({'cycle': 100, 'current_offset': 71, 'target_offset': 71, 'lengthen_pct': 10, 'shorten_pct': 10}, []), ({'cycle': 100, 'current_offset': 10, 'target_offset': 50, 'lengthen_pct': 20, 'shorten_pct': 20}, [120, 120]), ({'cycle': 150, 'current_offset': 86, 'target_offset': 11, 'lengthen_pct': 20, 'shorten_pct': 20}, [180, 180, 165]), ({'cycle': 110, 'current_offset': 1, 'target_offset': 55, 'lengthen_pct': 25, 'shorten_pct': 13}, [137, 137]), ({'cycle': 90, 'current_offset': 46, 'target_offset': 8, 'lengthen_pct': 20, 'shorten_pct': 13}, [108, 108, 106]), ({'cycle': 90, 'current_offset': 88, 'target_offset': 43, 'lengthen_pct': 17, 'shorten_pct': 10}, [105, 105, 105])]]
for i, (args, expected) in enumerate(fixtures[N-1]):
    check('timing oracle' + ' %d' % i, solve(args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
Boundary fixtureActualExpectedOutcome
timing oracle 0[120, 120][120, 120]Passed
timing oracle 1[88, 88, 88, 86][88, 88, 88, 86]Passed
timing oracle 2[][]Passed
timing oracle 3[][]Passed
timing oracle 4[140, 140, 130][140, 140, 130]Passed
timing oracle 5[116][116]Passed
timing oracle 6[][]Passed
timing oracle 7[][]Passed

SHA-256 / b97c4ebdd5c05981e50859c584c68f95d63ee02797a738a7260cdc48db8d3f8f

Verification & scope

A deterministic, bounded toy model with a stipulated contract; it makes no claim of conformance to any agency manual or standard. This reproducer isolates one failure mechanism. Results cover the supplied fixtures. Variants within a family share a test contract and should remain grouped when constructing evaluation splits. Related mechanisms with a shared evaluation_group must also remain together; these controlled models are not independent production incidents.

Observations recorded using Python 3.12.14 at 2026-09-29T14:47:58.544102+00:00.

Case digest / 4cac8b96ce95f988274f1cd078b03d4fa4e4ec8b37cf31b8f8d481145188f534