FA-79431 / Barcode symbology encoding / Open access
Set A accepts lowercase letters · case 01
Lowercase text planned into set A decodes as control characters.
ROOT CAUSE
The printable range for set A extends to 127, overlapping values reserved for control characters.
VERIFIED REPAIR
Set A printable characters are only 32..95.
Unsuccessful approach: Extending to 96 still admits the backtick, which set A cannot encode.
Case contract
Turn planned Code 128 segments into symbol values (without the checksum). Segments are [set, text], ["FNC1"] or ["SHIFT", char]. The first set segment emits its start (A 103, B 104, C 105); later set changes emit Code A 101, Code B 100 or Code C 99. Set A encodes 32..95 as ord-32 and 0..31 as ord+64; set B encodes 32..127 as ord-32; set C encodes even-length ASCII digit text as pair values. FNC1 is 102 and needs a prior start; SHIFT (98) is only valid in A or B and encodes one character in the other of A/B. Errors: no-start, bad-shift, bad-c, unencodable.
Why this case matters
Retail, logistics, pharmacy and document workflows depend on encoders that produce exactly the module pattern, code-set switches, separators and quiet zones scanners expect; one misplaced module or separator makes a label unreadable or, worse, scan as different data.
1 / The failure
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(segs):
out = []
cur = None
starts = {'A': 103, 'B': 104, 'C': 105}
switch = {'A': 101, 'B': 100, 'C': 99}
def val(s, ch):
o = ord(ch)
if s == 'A':
if 32 <= o <= 127:
return o - 32
if 0 <= o <= 31:
return o + 64
return None
if 32 <= o <= 127:
return o - 32
return None
for seg in segs:
kind = seg[0]
if kind == 'FNC1':
if cur is None:
return {'error': 'no-start'}
out.append(102)
continue
if kind == 'SHIFT':
if cur not in ('A', 'B'):
return {'error': 'bad-shift'}
other = 'B' if cur == 'A' else 'A'
v = val(other, seg[1])
if v is None:
return {'error': 'unencodable', 'char': seg[1]}
out += [98, v]
continue
s, text = seg
if cur is None:
out.append(starts[s])
elif s != cur:
out.append(switch[s])
cur = s
if s == 'C':
if len(text) % 2 or not all(c in '0123456789' for c in text):
return {'error': 'bad-c'}
out += [int(text[j:j + 2]) for j in range(0, len(text), 2)]
else:
for ch in text:
v = val(s, ch)
if v is None:
return {'error': 'unencodable', 'char': ch}
out.append(v)
return out
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[[['A', 'A`'], ['SHIFT', 'z']], {'error': 'unencodable', 'char': '`'}], [[['B', 'Q'], ['A', 'A`']], {'error': 'unencodable', 'char': '`'}], [[['C', '12'], ['A', 'HELLO']], [105, 12, 101, 40, 37, 44, 44, 47]], [[['B', 'Q'], ['B', '{x}'], ['C', '123']], {'error': 'bad-c'}], [[['B', '{x}'], ['SHIFT', '\t'], ['C', '1'], ['A', '\x00Q']], {'error': 'bad-c'}], [[['B', 'ab'], ['A', '\x00Q'], ['SHIFT', '\t'], ['FNC1']], {'error': 'unencodable', 'char': '\t'}], [[['C', '123'], ['FNC1']], {'error': 'bad-c'}], [[['A', 'A`'], ['B', '{x}']], {'error': 'unencodable', 'char': '`'}]], [[[['A', 'A`'], ['C', '123'], ['A', 'HELLO']], {'error': 'unencodable', 'char': '`'}], [[['A', 'A`'], ['SHIFT', 'B'], ['C', '0099']], {'error': 'unencodable', 'char': '`'}], [[['A', 'A`'], ['B', '{x}'], ['A', 'X\x1d1']], {'error': 'unencodable', 'char': '`'}], [[['C', '1'], ['C', '12']], {'error': 'bad-c'}], [[['A', '\x00Q'], ['B', '{x}'], ['A', 'X\x1d1'], ['SHIFT', 'z']], [103, 64, 49, 100, 91, 88, 93, 101, 56, 93, 17, 98, 90]], [[['A', 'AB'], ['B', 'Q'], ['B', 'z~']], [103, 33, 34, 100, 49, 90, 94]], [[['A', 'AB'], ['FNC1']], [103, 33, 34, 102]], [[['A', 'A`'], ['SHIFT', 'z'], ['SHIFT', 'z'], ['A', 'X\x1d1']], {'error': 'unencodable', 'char': '`'}]], [[[['A', 'A`'], ['C', '12'], ['C', '1']], {'error': 'unencodable', 'char': '`'}], [[['A', 'A`'], ['C', '4711']], {'error': 'unencodable', 'char': '`'}], [[['A', 'A`']], {'error': 'unencodable', 'char': '`'}], [[['FNC1'], ['C', '0099'], ['B', 'Lot 7'], ['C', '4711'], ['C', '12']], {'error': 'no-start'}], [[['B', 'Lot 7']], [104, 44, 79, 84, 0, 23]], [[['C', '0099']], [105, 0, 99]], [[['A', 'AB']], [103, 33, 34]], [[['B', '{x}'], ['SHIFT', 'a'], ['B', '{x}'], ['SHIFT', 'B']], {'error': 'unencodable', 'char': 'a'}]], [[[['B', '{x}'], ['A', 'X\x1d1'], ['A', 'A`']], {'error': 'unencodable', 'char': '`'}], [[['B', 'z~'], ['B', 'Lot 7'], ['SHIFT', '\t'], ['A', 'A`']], {'error': 'unencodable', 'char': '`'}], [[['B', 'z~'], ['B', '{x}'], ['A', 'A`'], ['SHIFT', 'B']], {'error': 'unencodable', 'char': '`'}], [[['B', 'Lot 7'], ['C', ' 1'], ['A', 'AB'], ['B', 'ab']], {'error': 'bad-c'}], [[['C', '4711'], ['B', 'ab'], ['A', 'X\x1d1']], [105, 47, 11, 100, 65, 66, 101, 56, 93, 17]], [[['B', 'z~']], [104, 90, 94]], [[['C', ' 1'], ['FNC1'], ['C', ' 1'], ['A', '_^']], {'error': 'bad-c'}], [[['B', 'ab'], ['FNC1'], ['SHIFT', 'z']], {'error': 'unencodable', 'char': 'z'}]], [[[['A', 'A`'], ['SHIFT', '\x1d'], ['C', ' 1'], ['SHIFT', 'z']], {'error': 'unencodable', 'char': '`'}], [[['A', 'A`'], ['FNC1'], ['B', 'Q']], {'error': 'unencodable', 'char': '`'}], [[['B', 'ab'], ['A', 'A`']], {'error': 'unencodable', 'char': '`'}], [[['B', 'Q']], [104, 49]], [[['A', '\t'], ['C', '0099']], [103, 73, 99, 0, 99]], [[['FNC1'], ['A', 'HELLO']], {'error': 'no-start'}], [[['C', '4711'], ['B', 'Q'], ['B', '{x}']], [105, 47, 11, 100, 49, 91, 88, 93]], [[['A', '_^'], ['A', 'A`']], {'error': 'unencodable', 'char': '`'}]]]
labels = ["regression: set A printable range", "repair trap", "combined fault", "control", "control", "boundary", "boundary", "control"]
for i, (args, expected) in enumerate(fixtures[N-1]):
check("%s %d" % (labels[i % len(labels)], 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 fixture | Actual | Expected | Outcome |
|---|---|---|---|
| regression: set A printable range 0 | [103, 33, 64, 98, 90] | {'char': '`', 'error': 'unencodable'} | Failed |
| repair trap 1 | [104, 49, 101, 33, 64] | {'char': '`', 'error': 'unencodable'} | Failed |
| combined fault 2 | [105, 12, 101, 40, 37, 44, 44, 47] | [105, 12, 101, 40, 37, 44, 44, 47] | Passed |
| control 3 | {'error': 'bad-c'} | {'error': 'bad-c'} | Passed |
| control 4 | {'error': 'bad-c'} | {'error': 'bad-c'} | Passed |
| boundary 5 | {'char': '\t', 'error': 'unencodable'} | {'char': '\t', 'error': 'unencodable'} | Passed |
| boundary 6 | {'error': 'bad-c'} | {'error': 'bad-c'} | Passed |
| control 7 | [103, 33, 64, 100, 91, 88, 93] | {'char': '`', 'error': 'unencodable'} | Failed |
SHA-256 / a6e84dfdd7a0945df78385fdb291761d9ffcde30b479681851cc67c1d750b01a
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(segs):
out = []
cur = None
starts = {'A': 103, 'B': 104, 'C': 105}
switch = {'A': 101, 'B': 100, 'C': 99}
def val(s, ch):
o = ord(ch)
if s == 'A':
if 32 <= o <= 96:
return o - 32
if 0 <= o <= 31:
return o + 64
return None
if 32 <= o <= 127:
return o - 32
return None
for seg in segs:
kind = seg[0]
if kind == 'FNC1':
if cur is None:
return {'error': 'no-start'}
out.append(102)
continue
if kind == 'SHIFT':
if cur not in ('A', 'B'):
return {'error': 'bad-shift'}
other = 'B' if cur == 'A' else 'A'
v = val(other, seg[1])
if v is None:
return {'error': 'unencodable', 'char': seg[1]}
out += [98, v]
continue
s, text = seg
if cur is None:
out.append(starts[s])
elif s != cur:
out.append(switch[s])
cur = s
if s == 'C':
if len(text) % 2 or not all(c in '0123456789' for c in text):
return {'error': 'bad-c'}
out += [int(text[j:j + 2]) for j in range(0, len(text), 2)]
else:
for ch in text:
v = val(s, ch)
if v is None:
return {'error': 'unencodable', 'char': ch}
out.append(v)
return out
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[[['A', 'A`'], ['SHIFT', 'z']], {'error': 'unencodable', 'char': '`'}], [[['B', 'Q'], ['A', 'A`']], {'error': 'unencodable', 'char': '`'}], [[['C', '12'], ['A', 'HELLO']], [105, 12, 101, 40, 37, 44, 44, 47]], [[['B', 'Q'], ['B', '{x}'], ['C', '123']], {'error': 'bad-c'}], [[['B', '{x}'], ['SHIFT', '\t'], ['C', '1'], ['A', '\x00Q']], {'error': 'bad-c'}], [[['B', 'ab'], ['A', '\x00Q'], ['SHIFT', '\t'], ['FNC1']], {'error': 'unencodable', 'char': '\t'}], [[['C', '123'], ['FNC1']], {'error': 'bad-c'}], [[['A', 'A`'], ['B', '{x}']], {'error': 'unencodable', 'char': '`'}]], [[[['A', 'A`'], ['C', '123'], ['A', 'HELLO']], {'error': 'unencodable', 'char': '`'}], [[['A', 'A`'], ['SHIFT', 'B'], ['C', '0099']], {'error': 'unencodable', 'char': '`'}], [[['A', 'A`'], ['B', '{x}'], ['A', 'X\x1d1']], {'error': 'unencodable', 'char': '`'}], [[['C', '1'], ['C', '12']], {'error': 'bad-c'}], [[['A', '\x00Q'], ['B', '{x}'], ['A', 'X\x1d1'], ['SHIFT', 'z']], [103, 64, 49, 100, 91, 88, 93, 101, 56, 93, 17, 98, 90]], [[['A', 'AB'], ['B', 'Q'], ['B', 'z~']], [103, 33, 34, 100, 49, 90, 94]], [[['A', 'AB'], ['FNC1']], [103, 33, 34, 102]], [[['A', 'A`'], ['SHIFT', 'z'], ['SHIFT', 'z'], ['A', 'X\x1d1']], {'error': 'unencodable', 'char': '`'}]], [[[['A', 'A`'], ['C', '12'], ['C', '1']], {'error': 'unencodable', 'char': '`'}], [[['A', 'A`'], ['C', '4711']], {'error': 'unencodable', 'char': '`'}], [[['A', 'A`']], {'error': 'unencodable', 'char': '`'}], [[['FNC1'], ['C', '0099'], ['B', 'Lot 7'], ['C', '4711'], ['C', '12']], {'error': 'no-start'}], [[['B', 'Lot 7']], [104, 44, 79, 84, 0, 23]], [[['C', '0099']], [105, 0, 99]], [[['A', 'AB']], [103, 33, 34]], [[['B', '{x}'], ['SHIFT', 'a'], ['B', '{x}'], ['SHIFT', 'B']], {'error': 'unencodable', 'char': 'a'}]], [[[['B', '{x}'], ['A', 'X\x1d1'], ['A', 'A`']], {'error': 'unencodable', 'char': '`'}], [[['B', 'z~'], ['B', 'Lot 7'], ['SHIFT', '\t'], ['A', 'A`']], {'error': 'unencodable', 'char': '`'}], [[['B', 'z~'], ['B', '{x}'], ['A', 'A`'], ['SHIFT', 'B']], {'error': 'unencodable', 'char': '`'}], [[['B', 'Lot 7'], ['C', ' 1'], ['A', 'AB'], ['B', 'ab']], {'error': 'bad-c'}], [[['C', '4711'], ['B', 'ab'], ['A', 'X\x1d1']], [105, 47, 11, 100, 65, 66, 101, 56, 93, 17]], [[['B', 'z~']], [104, 90, 94]], [[['C', ' 1'], ['FNC1'], ['C', ' 1'], ['A', '_^']], {'error': 'bad-c'}], [[['B', 'ab'], ['FNC1'], ['SHIFT', 'z']], {'error': 'unencodable', 'char': 'z'}]], [[[['A', 'A`'], ['SHIFT', '\x1d'], ['C', ' 1'], ['SHIFT', 'z']], {'error': 'unencodable', 'char': '`'}], [[['A', 'A`'], ['FNC1'], ['B', 'Q']], {'error': 'unencodable', 'char': '`'}], [[['B', 'ab'], ['A', 'A`']], {'error': 'unencodable', 'char': '`'}], [[['B', 'Q']], [104, 49]], [[['A', '\t'], ['C', '0099']], [103, 73, 99, 0, 99]], [[['FNC1'], ['A', 'HELLO']], {'error': 'no-start'}], [[['C', '4711'], ['B', 'Q'], ['B', '{x}']], [105, 47, 11, 100, 49, 91, 88, 93]], [[['A', '_^'], ['A', 'A`']], {'error': 'unencodable', 'char': '`'}]]]
labels = ["regression: set A printable range", "repair trap", "combined fault", "control", "control", "boundary", "boundary", "control"]
for i, (args, expected) in enumerate(fixtures[N-1]):
check("%s %d" % (labels[i % len(labels)], 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 fixture | Actual | Expected | Outcome |
|---|---|---|---|
| regression: set A printable range 0 | [103, 33, 64, 98, 90] | {'char': '`', 'error': 'unencodable'} | Failed |
| repair trap 1 | [104, 49, 101, 33, 64] | {'char': '`', 'error': 'unencodable'} | Failed |
| combined fault 2 | [105, 12, 101, 40, 37, 44, 44, 47] | [105, 12, 101, 40, 37, 44, 44, 47] | Passed |
| control 3 | {'error': 'bad-c'} | {'error': 'bad-c'} | Passed |
| control 4 | {'error': 'bad-c'} | {'error': 'bad-c'} | Passed |
| boundary 5 | {'char': '\t', 'error': 'unencodable'} | {'char': '\t', 'error': 'unencodable'} | Passed |
| boundary 6 | {'error': 'bad-c'} | {'error': 'bad-c'} | Passed |
| control 7 | [103, 33, 64, 100, 91, 88, 93] | {'char': '`', 'error': 'unencodable'} | Failed |
SHA-256 / 338f00bb8ce21534bd8e058499fd94968b36ffdb3226ad249ef6dbf493e4ae16
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(segs):
out = []
cur = None
starts = {'A': 103, 'B': 104, 'C': 105}
switch = {'A': 101, 'B': 100, 'C': 99}
def val(s, ch):
o = ord(ch)
if s == 'A':
if 32 <= o <= 95:
return o - 32
if 0 <= o <= 31:
return o + 64
return None
if 32 <= o <= 127:
return o - 32
return None
for seg in segs:
kind = seg[0]
if kind == 'FNC1':
if cur is None:
return {'error': 'no-start'}
out.append(102)
continue
if kind == 'SHIFT':
if cur not in ('A', 'B'):
return {'error': 'bad-shift'}
other = 'B' if cur == 'A' else 'A'
v = val(other, seg[1])
if v is None:
return {'error': 'unencodable', 'char': seg[1]}
out += [98, v]
continue
s, text = seg
if cur is None:
out.append(starts[s])
elif s != cur:
out.append(switch[s])
cur = s
if s == 'C':
if len(text) % 2 or not all(c in '0123456789' for c in text):
return {'error': 'bad-c'}
out += [int(text[j:j + 2]) for j in range(0, len(text), 2)]
else:
for ch in text:
v = val(s, ch)
if v is None:
return {'error': 'unencodable', 'char': ch}
out.append(v)
return out
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[[['A', 'A`'], ['SHIFT', 'z']], {'error': 'unencodable', 'char': '`'}], [[['B', 'Q'], ['A', 'A`']], {'error': 'unencodable', 'char': '`'}], [[['C', '12'], ['A', 'HELLO']], [105, 12, 101, 40, 37, 44, 44, 47]], [[['B', 'Q'], ['B', '{x}'], ['C', '123']], {'error': 'bad-c'}], [[['B', '{x}'], ['SHIFT', '\t'], ['C', '1'], ['A', '\x00Q']], {'error': 'bad-c'}], [[['B', 'ab'], ['A', '\x00Q'], ['SHIFT', '\t'], ['FNC1']], {'error': 'unencodable', 'char': '\t'}], [[['C', '123'], ['FNC1']], {'error': 'bad-c'}], [[['A', 'A`'], ['B', '{x}']], {'error': 'unencodable', 'char': '`'}]], [[[['A', 'A`'], ['C', '123'], ['A', 'HELLO']], {'error': 'unencodable', 'char': '`'}], [[['A', 'A`'], ['SHIFT', 'B'], ['C', '0099']], {'error': 'unencodable', 'char': '`'}], [[['A', 'A`'], ['B', '{x}'], ['A', 'X\x1d1']], {'error': 'unencodable', 'char': '`'}], [[['C', '1'], ['C', '12']], {'error': 'bad-c'}], [[['A', '\x00Q'], ['B', '{x}'], ['A', 'X\x1d1'], ['SHIFT', 'z']], [103, 64, 49, 100, 91, 88, 93, 101, 56, 93, 17, 98, 90]], [[['A', 'AB'], ['B', 'Q'], ['B', 'z~']], [103, 33, 34, 100, 49, 90, 94]], [[['A', 'AB'], ['FNC1']], [103, 33, 34, 102]], [[['A', 'A`'], ['SHIFT', 'z'], ['SHIFT', 'z'], ['A', 'X\x1d1']], {'error': 'unencodable', 'char': '`'}]], [[[['A', 'A`'], ['C', '12'], ['C', '1']], {'error': 'unencodable', 'char': '`'}], [[['A', 'A`'], ['C', '4711']], {'error': 'unencodable', 'char': '`'}], [[['A', 'A`']], {'error': 'unencodable', 'char': '`'}], [[['FNC1'], ['C', '0099'], ['B', 'Lot 7'], ['C', '4711'], ['C', '12']], {'error': 'no-start'}], [[['B', 'Lot 7']], [104, 44, 79, 84, 0, 23]], [[['C', '0099']], [105, 0, 99]], [[['A', 'AB']], [103, 33, 34]], [[['B', '{x}'], ['SHIFT', 'a'], ['B', '{x}'], ['SHIFT', 'B']], {'error': 'unencodable', 'char': 'a'}]], [[[['B', '{x}'], ['A', 'X\x1d1'], ['A', 'A`']], {'error': 'unencodable', 'char': '`'}], [[['B', 'z~'], ['B', 'Lot 7'], ['SHIFT', '\t'], ['A', 'A`']], {'error': 'unencodable', 'char': '`'}], [[['B', 'z~'], ['B', '{x}'], ['A', 'A`'], ['SHIFT', 'B']], {'error': 'unencodable', 'char': '`'}], [[['B', 'Lot 7'], ['C', ' 1'], ['A', 'AB'], ['B', 'ab']], {'error': 'bad-c'}], [[['C', '4711'], ['B', 'ab'], ['A', 'X\x1d1']], [105, 47, 11, 100, 65, 66, 101, 56, 93, 17]], [[['B', 'z~']], [104, 90, 94]], [[['C', ' 1'], ['FNC1'], ['C', ' 1'], ['A', '_^']], {'error': 'bad-c'}], [[['B', 'ab'], ['FNC1'], ['SHIFT', 'z']], {'error': 'unencodable', 'char': 'z'}]], [[[['A', 'A`'], ['SHIFT', '\x1d'], ['C', ' 1'], ['SHIFT', 'z']], {'error': 'unencodable', 'char': '`'}], [[['A', 'A`'], ['FNC1'], ['B', 'Q']], {'error': 'unencodable', 'char': '`'}], [[['B', 'ab'], ['A', 'A`']], {'error': 'unencodable', 'char': '`'}], [[['B', 'Q']], [104, 49]], [[['A', '\t'], ['C', '0099']], [103, 73, 99, 0, 99]], [[['FNC1'], ['A', 'HELLO']], {'error': 'no-start'}], [[['C', '4711'], ['B', 'Q'], ['B', '{x}']], [105, 47, 11, 100, 49, 91, 88, 93]], [[['A', '_^'], ['A', 'A`']], {'error': 'unencodable', 'char': '`'}]]]
labels = ["regression: set A printable range", "repair trap", "combined fault", "control", "control", "boundary", "boundary", "control"]
for i, (args, expected) in enumerate(fixtures[N-1]):
check("%s %d" % (labels[i % len(labels)], 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 fixture | Actual | Expected | Outcome |
|---|---|---|---|
| regression: set A printable range 0 | {'char': '`', 'error': 'unencodable'} | {'char': '`', 'error': 'unencodable'} | Passed |
| repair trap 1 | {'char': '`', 'error': 'unencodable'} | {'char': '`', 'error': 'unencodable'} | Passed |
| combined fault 2 | [105, 12, 101, 40, 37, 44, 44, 47] | [105, 12, 101, 40, 37, 44, 44, 47] | Passed |
| control 3 | {'error': 'bad-c'} | {'error': 'bad-c'} | Passed |
| control 4 | {'error': 'bad-c'} | {'error': 'bad-c'} | Passed |
| boundary 5 | {'char': '\t', 'error': 'unencodable'} | {'char': '\t', 'error': 'unencodable'} | Passed |
| boundary 6 | {'error': 'bad-c'} | {'error': 'bad-c'} | Passed |
| control 7 | {'char': '`', 'error': 'unencodable'} | {'char': '`', 'error': 'unencodable'} | Passed |
SHA-256 / d333564e01b84f2477668bb3b2ab1c8dfa73fbee940da46e8d058d4091da79a0
Verification & scope
A deterministic bounded teaching model with a stipulated contract; it makes no claim of conformance to any published specification. 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:44.437280+00:00.
Case digest / 7567d7b65387e8676a1353d537d3b8aebaad45a33a488677663065341eee0105