FAILURE MAP
← Case archive

FA-79896 / Typography line breaking / Open access

Total-fit paragraph demerits: badness tolerance · case 01

Very loose lines are chosen that should have been rejected as infeasible.

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

ROOT CAUSE

The tolerance check compares against the 10000 ceiling so nothing is ever rejected.

VERIFIED REPAIR

Reject candidate lines with badness above 1000.

Unsuccessful approach: Tightening the tolerance to 100 rejects acceptable lines.

Case contract

Input [word widths, [space, stretch, shrink] per gap, line width, line penalty]. A line i..j has gaps=j-i-1. The last line has zero badness when not overfull. Other lines use ratio shortfall/(stretch*gaps) or /(shrink*gaps); zero stretch with slack or compression past shrink is infeasible; badness=min(10000, floor(100|r|^3+1/2)) and must be <=1000. Fitness 0 tight (r<-1/2), 1 decent (r<=1/2), 2 loose (r<=1), 3 very loose; last line decent. Demerits (lp+b)^2 plus 3000 when adjacent fitness classes differ by more than 1, starting from decent. Return [min total demerits, break list] (ties: first found) or ["infeasible"].

Why this case matters

Line breaking decides where paragraphs wrap on screen and in print; a wrong decision point shifts every following line.

1 / The failure

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json
import math
from fractions import Fraction
N = 1
observations = []
def solve(x):
    words, glue, width, lp = x
    sp, st, sh = glue
    n = len(words)
    def rate(i, j):
        gaps = j - i - 1
        nat = sum(words[i:j]) + sp * gaps
        short = width - nat
        if j == n and short >= 0:
            return 0, 1
        if short > 0:
            if st * gaps == 0:
                return None
            r = Fraction(short, st * gaps)
        elif short < 0:
            if -short > sh * gaps:
                return None
            r = Fraction(short, sh * gaps)
        else:
            r = Fraction(0)
        b = min(10000, math.floor(100 * abs(r) ** 3 + Fraction(1, 2)))
        if b > 10000:
            return None
        fit = 0 if r < Fraction(-1, 2) else 1 if r <= Fraction(1, 2) else 2 if r <= 1 else 3
        return b, fit
    best = {(0, 1): (0, [])}
    for j in range(1, n + 1):
        for i in range(j):
            rated = rate(i, j)
            if rated is None:
                continue
            b, fit = rated
            for (pos, pfit), (dem, brk) in sorted(best.items()):
                if pos != i:
                    continue
                d = dem + (lp + b) ** 2
                if abs(fit - pfit) > 1:
                    d += 3000
                key = (j, fit)
                if key not in best or d < best[key][0]:
                    best[key] = (d, brk + [j])
    finals = [v for (pos, f), v in best.items() if pos == n]
    if not finals:
        return ['infeasible']
    d, brk = min(finals)
    return [d, brk]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: badness tolerance', [[2, 7, 3, 5, 2, 5, 6], [2, 1, 0], 21, 50], ['infeasible']), ('regression: badness tolerance', [[5, 5, 6, 1], [3, 3, 0], 20, 50], ['infeasible']), ('partial-repair probe', [[7, 4, 5, 1, 7, 3], [2, 2, 0], 17, 1], [647603, [2, 5, 6]]), ('partial-repair probe', [[7, 5, 2, 3, 3], [3, 1, 0], 17, 10], [662200, [2, 5]]), ('tight then loose lines', [[3, 3, 3, 3, 3, 3, 3], [2, 2, 1], 11, 1], [20403, [3, 6, 7]]), ('two-line paragraph with loose first line', [[4, 5, 3, 6], [2, 2, 1], 14, 10], [12200, [3, 4]]), ('control layout', [[2, 3, 3], [3, 1, 2], 12, 10], [529, [3]]), ('control layout', [[2, 1, 7, 7], [2, 3, 0], 13, 10], ['infeasible'])], [('regression: badness tolerance', [[7, 4, 7, 2, 4, 2, 1], [2, 1, 0], 17, 10], ['infeasible']), ('regression: badness tolerance', [[1, 4, 7, 1, 7, 3, 2, 4], [2, 1, 0], 14, 10], ['infeasible']), ('partial-repair probe', [[7, 4, 7, 6], [2, 3, 1], 19, 10], [662200, [2, 4]]), ('partial-repair probe', [[4, 4, 6], [2, 2, 0], 14, 10], [662200, [2, 3]]), ('last line overfull', [[5, 5, 5], [1, 1, 0], 9, 10], ['infeasible']), ('tight then loose lines', [[3, 3, 3, 3, 3, 3, 3], [2, 2, 1], 11, 1], [20403, [3, 6, 7]]), ('control layout', [[2, 4, 4, 7, 4, 2, 5], [1, 3, 2], 16, 50], [8900, [4, 7]]), ('control layout', [[1, 2, 5, 4, 1, 6], [2, 1, 2], 18, 50], [5000, [4, 6]])], [('regression: badness tolerance', [[5, 4, 1, 2, 6, 1, 5], [3, 1, 1], 11, 50], ['infeasible']), ('regression: badness tolerance', [[6, 7, 6, 5], [3, 3, 0], 24, 50], ['infeasible']), ('partial-repair probe', [[6, 1, 2, 5, 6, 1, 3, 4], [3, 2, 0], 22, 10], [313316, [3, 6, 8]]), ('partial-repair probe', [[1, 3, 3], [3, 3, 0], 12, 50], [271669, [2, 3]]), ('single word paragraph', [[7], [2, 2, 1], 10, 10], [100, [1]]), ('last line overfull', [[5, 5, 5], [1, 1, 0], 9, 10], ['infeasible']), ('control layout', [[7, 6, 4, 1, 7, 1, 6], [1, 3, 2], 16, 1], [963, [2, 6, 7]]), ('control layout', [[7, 7, 7, 6], [2, 3, 1], 24, 10], [629, [3, 4]])], [('regression: badness tolerance', [[6, 7, 6, 5], [3, 3, 0], 24, 50], ['infeasible']), ('regression: badness tolerance', [[1, 2, 6, 2, 4, 4, 7, 1], [1, 2, 0], 9, 10], ['infeasible']), ('partial-repair probe', [[4, 5, 7, 1], [3, 2, 1], 15, 10], [127204, [2, 4]]), ('partial-repair probe', [[7, 4, 7, 6], [2, 3, 1], 19, 10], [662200, [2, 4]]), ('single word paragraph', [[7], [2, 2, 1], 10, 10], [100, [1]]), ('tight then loose lines', [[3, 3, 3, 3, 3, 3, 3], [2, 2, 1], 11, 1], [20403, [3, 6, 7]]), ('control layout', [[7, 7, 7, 1, 2], [3, 3, 2], 20, 10], [12200, [2, 5]]), ('control layout', [[7, 7, 4, 3, 1], [2, 2, 1], 21, 10], [629, [3, 5]])], [('regression: badness tolerance', [[4, 5, 3, 6, 2, 7], [1, 1, 0], 13, 1], ['infeasible']), ('regression: badness tolerance', [[3, 7, 1, 2, 7, 1], [2, 2, 0], 13, 10], ['infeasible']), ('partial-repair probe', [[5, 2, 6, 2, 2, 5, 5], [3, 1, 1], 12, 10], [1330400, [2, 4, 6, 7]]), ('partial-repair probe', [[5, 3, 5, 4, 7], [3, 1, 2], 13, 50], [750500, [2, 4, 5]]), ('two-line paragraph with loose first line', [[4, 5, 3, 6], [2, 2, 1], 14, 10], [12200, [3, 4]]), ('single word paragraph', [[7], [2, 2, 1], 10, 10], [100, [1]]), ('control layout', [[5, 7, 2], [2, 1, 2], 24, 50], [2500, [3]]), ('control layout', [[1, 1, 5, 3], [3, 2, 0], 14, 50], [5204, [3, 4]])]]
for label, args, expected in fixtures[N - 1]:
    check(label, 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
regression: badness tolerance[5212038, [3, 6, 7]]['infeasible']Failed
regression: badness tolerance[1750900, [2, 4]]['infeasible']Failed
partial-repair probe[647603, [2, 5, 6]][647603, [2, 5, 6]]Passed
partial-repair probe[662200, [2, 5]][662200, [2, 5]]Passed
tight then loose lines[20403, [3, 6, 7]][20403, [3, 6, 7]]Passed
two-line paragraph with loose first line[12200, [3, 4]][12200, [3, 4]]Passed
control layout[529, [3]][529, [3]]Passed
control layout['infeasible']['infeasible']Passed

SHA-256 / 6bba8cefb329267adfedc8af41dfb26b471c9b8f19ee4af6040e5c12660827ae

2 / The unsuccessful fix

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json
import math
from fractions import Fraction
N = 1
observations = []
def solve(x):
    words, glue, width, lp = x
    sp, st, sh = glue
    n = len(words)
    def rate(i, j):
        gaps = j - i - 1
        nat = sum(words[i:j]) + sp * gaps
        short = width - nat
        if j == n and short >= 0:
            return 0, 1
        if short > 0:
            if st * gaps == 0:
                return None
            r = Fraction(short, st * gaps)
        elif short < 0:
            if -short > sh * gaps:
                return None
            r = Fraction(short, sh * gaps)
        else:
            r = Fraction(0)
        b = min(10000, math.floor(100 * abs(r) ** 3 + Fraction(1, 2)))
        if b > 100:
            return None
        fit = 0 if r < Fraction(-1, 2) else 1 if r <= Fraction(1, 2) else 2 if r <= 1 else 3
        return b, fit
    best = {(0, 1): (0, [])}
    for j in range(1, n + 1):
        for i in range(j):
            rated = rate(i, j)
            if rated is None:
                continue
            b, fit = rated
            for (pos, pfit), (dem, brk) in sorted(best.items()):
                if pos != i:
                    continue
                d = dem + (lp + b) ** 2
                if abs(fit - pfit) > 1:
                    d += 3000
                key = (j, fit)
                if key not in best or d < best[key][0]:
                    best[key] = (d, brk + [j])
    finals = [v for (pos, f), v in best.items() if pos == n]
    if not finals:
        return ['infeasible']
    d, brk = min(finals)
    return [d, brk]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: badness tolerance', [[2, 7, 3, 5, 2, 5, 6], [2, 1, 0], 21, 50], ['infeasible']), ('regression: badness tolerance', [[5, 5, 6, 1], [3, 3, 0], 20, 50], ['infeasible']), ('partial-repair probe', [[7, 4, 5, 1, 7, 3], [2, 2, 0], 17, 1], [647603, [2, 5, 6]]), ('partial-repair probe', [[7, 5, 2, 3, 3], [3, 1, 0], 17, 10], [662200, [2, 5]]), ('tight then loose lines', [[3, 3, 3, 3, 3, 3, 3], [2, 2, 1], 11, 1], [20403, [3, 6, 7]]), ('two-line paragraph with loose first line', [[4, 5, 3, 6], [2, 2, 1], 14, 10], [12200, [3, 4]]), ('control layout', [[2, 3, 3], [3, 1, 2], 12, 10], [529, [3]]), ('control layout', [[2, 1, 7, 7], [2, 3, 0], 13, 10], ['infeasible'])], [('regression: badness tolerance', [[7, 4, 7, 2, 4, 2, 1], [2, 1, 0], 17, 10], ['infeasible']), ('regression: badness tolerance', [[1, 4, 7, 1, 7, 3, 2, 4], [2, 1, 0], 14, 10], ['infeasible']), ('partial-repair probe', [[7, 4, 7, 6], [2, 3, 1], 19, 10], [662200, [2, 4]]), ('partial-repair probe', [[4, 4, 6], [2, 2, 0], 14, 10], [662200, [2, 3]]), ('last line overfull', [[5, 5, 5], [1, 1, 0], 9, 10], ['infeasible']), ('tight then loose lines', [[3, 3, 3, 3, 3, 3, 3], [2, 2, 1], 11, 1], [20403, [3, 6, 7]]), ('control layout', [[2, 4, 4, 7, 4, 2, 5], [1, 3, 2], 16, 50], [8900, [4, 7]]), ('control layout', [[1, 2, 5, 4, 1, 6], [2, 1, 2], 18, 50], [5000, [4, 6]])], [('regression: badness tolerance', [[5, 4, 1, 2, 6, 1, 5], [3, 1, 1], 11, 50], ['infeasible']), ('regression: badness tolerance', [[6, 7, 6, 5], [3, 3, 0], 24, 50], ['infeasible']), ('partial-repair probe', [[6, 1, 2, 5, 6, 1, 3, 4], [3, 2, 0], 22, 10], [313316, [3, 6, 8]]), ('partial-repair probe', [[1, 3, 3], [3, 3, 0], 12, 50], [271669, [2, 3]]), ('single word paragraph', [[7], [2, 2, 1], 10, 10], [100, [1]]), ('last line overfull', [[5, 5, 5], [1, 1, 0], 9, 10], ['infeasible']), ('control layout', [[7, 6, 4, 1, 7, 1, 6], [1, 3, 2], 16, 1], [963, [2, 6, 7]]), ('control layout', [[7, 7, 7, 6], [2, 3, 1], 24, 10], [629, [3, 4]])], [('regression: badness tolerance', [[6, 7, 6, 5], [3, 3, 0], 24, 50], ['infeasible']), ('regression: badness tolerance', [[1, 2, 6, 2, 4, 4, 7, 1], [1, 2, 0], 9, 10], ['infeasible']), ('partial-repair probe', [[4, 5, 7, 1], [3, 2, 1], 15, 10], [127204, [2, 4]]), ('partial-repair probe', [[7, 4, 7, 6], [2, 3, 1], 19, 10], [662200, [2, 4]]), ('single word paragraph', [[7], [2, 2, 1], 10, 10], [100, [1]]), ('tight then loose lines', [[3, 3, 3, 3, 3, 3, 3], [2, 2, 1], 11, 1], [20403, [3, 6, 7]]), ('control layout', [[7, 7, 7, 1, 2], [3, 3, 2], 20, 10], [12200, [2, 5]]), ('control layout', [[7, 7, 4, 3, 1], [2, 2, 1], 21, 10], [629, [3, 5]])], [('regression: badness tolerance', [[4, 5, 3, 6, 2, 7], [1, 1, 0], 13, 1], ['infeasible']), ('regression: badness tolerance', [[3, 7, 1, 2, 7, 1], [2, 2, 0], 13, 10], ['infeasible']), ('partial-repair probe', [[5, 2, 6, 2, 2, 5, 5], [3, 1, 1], 12, 10], [1330400, [2, 4, 6, 7]]), ('partial-repair probe', [[5, 3, 5, 4, 7], [3, 1, 2], 13, 50], [750500, [2, 4, 5]]), ('two-line paragraph with loose first line', [[4, 5, 3, 6], [2, 2, 1], 14, 10], [12200, [3, 4]]), ('single word paragraph', [[7], [2, 2, 1], 10, 10], [100, [1]]), ('control layout', [[5, 7, 2], [2, 1, 2], 24, 50], [2500, [3]]), ('control layout', [[1, 1, 5, 3], [3, 2, 0], 14, 50], [5204, [3, 4]])]]
for label, args, expected in fixtures[N - 1]:
    check(label, 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
regression: badness tolerance['infeasible']['infeasible']Passed
regression: badness tolerance['infeasible']['infeasible']Passed
partial-repair probe['infeasible'][647603, [2, 5, 6]]Failed
partial-repair probe['infeasible'][662200, [2, 5]]Failed
tight then loose lines[20403, [3, 6, 7]][20403, [3, 6, 7]]Passed
two-line paragraph with loose first line[12200, [3, 4]][12200, [3, 4]]Passed
control layout[529, [3]][529, [3]]Passed
control layout['infeasible']['infeasible']Passed

SHA-256 / a6e56a0106a06bf3711987850adc57315706082a4d261298cb8f251d538c82b7

3 / The verified repair

Exit 0
"""Failure Map reference implementation. Python standard library only."""
import json
import math
from fractions import Fraction
N = 1
observations = []
def solve(x):
    words, glue, width, lp = x
    sp, st, sh = glue
    n = len(words)
    def rate(i, j):
        gaps = j - i - 1
        nat = sum(words[i:j]) + sp * gaps
        short = width - nat
        if j == n and short >= 0:
            return 0, 1
        if short > 0:
            if st * gaps == 0:
                return None
            r = Fraction(short, st * gaps)
        elif short < 0:
            if -short > sh * gaps:
                return None
            r = Fraction(short, sh * gaps)
        else:
            r = Fraction(0)
        b = min(10000, math.floor(100 * abs(r) ** 3 + Fraction(1, 2)))
        if b > 1000:
            return None
        fit = 0 if r < Fraction(-1, 2) else 1 if r <= Fraction(1, 2) else 2 if r <= 1 else 3
        return b, fit
    best = {(0, 1): (0, [])}
    for j in range(1, n + 1):
        for i in range(j):
            rated = rate(i, j)
            if rated is None:
                continue
            b, fit = rated
            for (pos, pfit), (dem, brk) in sorted(best.items()):
                if pos != i:
                    continue
                d = dem + (lp + b) ** 2
                if abs(fit - pfit) > 1:
                    d += 3000
                key = (j, fit)
                if key not in best or d < best[key][0]:
                    best[key] = (d, brk + [j])
    finals = [v for (pos, f), v in best.items() if pos == n]
    if not finals:
        return ['infeasible']
    d, brk = min(finals)
    return [d, brk]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: badness tolerance', [[2, 7, 3, 5, 2, 5, 6], [2, 1, 0], 21, 50], ['infeasible']), ('regression: badness tolerance', [[5, 5, 6, 1], [3, 3, 0], 20, 50], ['infeasible']), ('partial-repair probe', [[7, 4, 5, 1, 7, 3], [2, 2, 0], 17, 1], [647603, [2, 5, 6]]), ('partial-repair probe', [[7, 5, 2, 3, 3], [3, 1, 0], 17, 10], [662200, [2, 5]]), ('tight then loose lines', [[3, 3, 3, 3, 3, 3, 3], [2, 2, 1], 11, 1], [20403, [3, 6, 7]]), ('two-line paragraph with loose first line', [[4, 5, 3, 6], [2, 2, 1], 14, 10], [12200, [3, 4]]), ('control layout', [[2, 3, 3], [3, 1, 2], 12, 10], [529, [3]]), ('control layout', [[2, 1, 7, 7], [2, 3, 0], 13, 10], ['infeasible'])], [('regression: badness tolerance', [[7, 4, 7, 2, 4, 2, 1], [2, 1, 0], 17, 10], ['infeasible']), ('regression: badness tolerance', [[1, 4, 7, 1, 7, 3, 2, 4], [2, 1, 0], 14, 10], ['infeasible']), ('partial-repair probe', [[7, 4, 7, 6], [2, 3, 1], 19, 10], [662200, [2, 4]]), ('partial-repair probe', [[4, 4, 6], [2, 2, 0], 14, 10], [662200, [2, 3]]), ('last line overfull', [[5, 5, 5], [1, 1, 0], 9, 10], ['infeasible']), ('tight then loose lines', [[3, 3, 3, 3, 3, 3, 3], [2, 2, 1], 11, 1], [20403, [3, 6, 7]]), ('control layout', [[2, 4, 4, 7, 4, 2, 5], [1, 3, 2], 16, 50], [8900, [4, 7]]), ('control layout', [[1, 2, 5, 4, 1, 6], [2, 1, 2], 18, 50], [5000, [4, 6]])], [('regression: badness tolerance', [[5, 4, 1, 2, 6, 1, 5], [3, 1, 1], 11, 50], ['infeasible']), ('regression: badness tolerance', [[6, 7, 6, 5], [3, 3, 0], 24, 50], ['infeasible']), ('partial-repair probe', [[6, 1, 2, 5, 6, 1, 3, 4], [3, 2, 0], 22, 10], [313316, [3, 6, 8]]), ('partial-repair probe', [[1, 3, 3], [3, 3, 0], 12, 50], [271669, [2, 3]]), ('single word paragraph', [[7], [2, 2, 1], 10, 10], [100, [1]]), ('last line overfull', [[5, 5, 5], [1, 1, 0], 9, 10], ['infeasible']), ('control layout', [[7, 6, 4, 1, 7, 1, 6], [1, 3, 2], 16, 1], [963, [2, 6, 7]]), ('control layout', [[7, 7, 7, 6], [2, 3, 1], 24, 10], [629, [3, 4]])], [('regression: badness tolerance', [[6, 7, 6, 5], [3, 3, 0], 24, 50], ['infeasible']), ('regression: badness tolerance', [[1, 2, 6, 2, 4, 4, 7, 1], [1, 2, 0], 9, 10], ['infeasible']), ('partial-repair probe', [[4, 5, 7, 1], [3, 2, 1], 15, 10], [127204, [2, 4]]), ('partial-repair probe', [[7, 4, 7, 6], [2, 3, 1], 19, 10], [662200, [2, 4]]), ('single word paragraph', [[7], [2, 2, 1], 10, 10], [100, [1]]), ('tight then loose lines', [[3, 3, 3, 3, 3, 3, 3], [2, 2, 1], 11, 1], [20403, [3, 6, 7]]), ('control layout', [[7, 7, 7, 1, 2], [3, 3, 2], 20, 10], [12200, [2, 5]]), ('control layout', [[7, 7, 4, 3, 1], [2, 2, 1], 21, 10], [629, [3, 5]])], [('regression: badness tolerance', [[4, 5, 3, 6, 2, 7], [1, 1, 0], 13, 1], ['infeasible']), ('regression: badness tolerance', [[3, 7, 1, 2, 7, 1], [2, 2, 0], 13, 10], ['infeasible']), ('partial-repair probe', [[5, 2, 6, 2, 2, 5, 5], [3, 1, 1], 12, 10], [1330400, [2, 4, 6, 7]]), ('partial-repair probe', [[5, 3, 5, 4, 7], [3, 1, 2], 13, 50], [750500, [2, 4, 5]]), ('two-line paragraph with loose first line', [[4, 5, 3, 6], [2, 2, 1], 14, 10], [12200, [3, 4]]), ('single word paragraph', [[7], [2, 2, 1], 10, 10], [100, [1]]), ('control layout', [[5, 7, 2], [2, 1, 2], 24, 50], [2500, [3]]), ('control layout', [[1, 1, 5, 3], [3, 2, 0], 14, 50], [5204, [3, 4]])]]
for label, args, expected in fixtures[N - 1]:
    check(label, 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
regression: badness tolerance['infeasible']['infeasible']Passed
regression: badness tolerance['infeasible']['infeasible']Passed
partial-repair probe[647603, [2, 5, 6]][647603, [2, 5, 6]]Passed
partial-repair probe[662200, [2, 5]][662200, [2, 5]]Passed
tight then loose lines[20403, [3, 6, 7]][20403, [3, 6, 7]]Passed
two-line paragraph with loose first line[12200, [3, 4]][12200, [3, 4]]Passed
control layout[529, [3]][529, [3]]Passed
control layout['infeasible']['infeasible']Passed

SHA-256 / d237a371027b259710d38b89dde6f11d222b2da1b0927d2c601179ae3759f4a0

Verification & scope

A deterministic toy typesetting model with integer widths and a stipulated rule set; it does not claim conformance to any engine. 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:49:48.859306+00:00.

Case digest / 40a7cb60464f83b13fb276c81d2f0eb4567d35c92c3c791128caefe259d6b7e7