Webhook router
A payment provider's events through five handlers written before it added a kind - if-else, no else, a default, an error, a hold queue - each one's buckets and revenue set against what every kind means.
Every screen below was recorded under CPython. When this page was built, the EML interpreter replayed each session from the same input and printed the same bytes.
About
A payment provider's events through five handlers written before the provider added a kind, each handler's buckets and revenue set against what every kind means.
main.eml- the menu, the events, the handlers' buckets and revenue, what each handler does with each kind, and adding an eventrouter.eml- the handlers, the events so far, what each kind means (stated apart from every handler), the route an event takes, the tally, the true revenue, and the verdict on each handler's answer
How each part works:
- The handlers were written for payment, refund, ping and test: a payment adds, a refund subtracts, a ping or a test is ignored. Since then the provider sends chargeback, which takes money back.
- As in the corpus case
new-enum-value-fallthrough, the new kind meets each handler's "anything else": if-else's else adds the chargeback as a payment; a table with a default ignores it; a table that raises fails with an error; a table with a quarantine puts it in a hold queue. The first two answer wrong without a word. - As in the corpus case
event-router-ignored-branches, ignoring ping and test is written as a branch, and a handler with the same branches and no else does nothing at all with the chargeback: it goes into no bucket, and only the total, 7 of 8 accounted for, shows it. - The revenue: the truth is 75.00; if-else says 125.00; every other handler 100.00 - for raise and quarantine until the events they failed or held are handled. A kind nobody has defined should wait for a person, which only the quarantine does.
What is checked: menu choices 1 to 5; a kind of 1 to 14 letters a to z or underscores, and an amount in whole units from 0 to 9999. An empty answer cancels.
Sessions: sessions/basic.in gives: - the events, the handlers and each kind; - a dispute_won of 30, a kind nobody has defined, and another chargeback; the handlers and each kind again.
sessions/bad-input.in gives: - menu choices 0 and x; - kinds: a cancel, Payment and one of 15 letters; amounts: a cancel, 10000 and x; - a refund of 12, which every handler gets right; the handlers.
Built on the verified corpus cases event-router-ignored-branches (every event accounted for in exactly one bucket, and ignoring as a branch) and new-enum-value-fallthrough (four ways a consumer handles a value added later, right, silently wrong, or loud).
Recorded sessions
What the screen shows while someone uses the program. Each typed line appears after its prompt, the way a terminal shows it.
bad-input
interpreter: byte-equal== Webhook router ==
A payment provider's events through five handlers written before it added a kind.
1) events 2) run the handlers 3) each kind 4) add an event 5) quit
choice> 0
Pick a number from 1 to 5.
1) events 2) run the handlers 3) each kind 4) add an event 5) quit
choice> x
Pick a number from 1 to 5.
1) events 2) run the handlers 3) each kind 4) add an event 5) quit
choice> 4
kind>
Cancelled.
1) events 2) run the handlers 3) each kind 4) add an event 5) quit
choice> 4
kind> Payment
Type a kind of 1 to 14 letters a to z or underscores.
1) events 2) run the handlers 3) each kind 4) add an event 5) quit
choice> 4
kind> fifteen_letters
Type a kind of 1 to 14 letters a to z or underscores.
1) events 2) run the handlers 3) each kind 4) add an event 5) quit
choice> 4
kind> refund
amount in whole units (0 to 9999)>
Cancelled.
1) events 2) run the handlers 3) each kind 4) add an event 5) quit
choice> 4
kind> refund
amount in whole units (0 to 9999)> 10000
Type a whole number from 0 to 9999.
1) events 2) run the handlers 3) each kind 4) add an event 5) quit
choice> 4
kind> refund
amount in whole units (0 to 9999)> x
Type a whole number from 0 to 9999.
1) events 2) run the handlers 3) each kind 4) add an event 5) quit
choice> 4
kind> refund
amount in whole units (0 to 9999)> 12
Event 9: refund 12.00, which means subtract.
if-else subtract right
no else subtract right
default subtract right
raise subtract right
quarantine subtract right
1) events 2) run the handlers 3) each kind 4) add an event 5) quit
choice> 2
handler revenue added subtracted ignored held failed accounted
if-else 113.00 4 2 3 0 0 9 of 9
no else 88.00 3 2 3 0 0 8 of 9
default 88.00 3 2 4 0 0 9 of 9
raise 88.00 3 2 3 0 1 9 of 9
quarantine 88.00 3 2 3 1 0 9 of 9
the truth 63.00
if-else: 1 event handled wrong without a word; revenue 50.00 above the truth.
no else: 1 event went nowhere, which only the total shows: 8 of 9 accounted for; revenue 25.00 above the truth.
default: 1 event handled wrong without a word; revenue 25.00 above the truth.
raise: 1 event failed with an error, so someone hears of it; revenue 25.00 above the truth, until those are handled.
quarantine: 1 event waits in the hold queue for a person; revenue 25.00 above the truth, until those are handled.
1) events 2) run the handlers 3) each kind 4) add an event 5) quit
choice> 5
Bye.
What was typed (22 lines)
0
x
4
4
Payment
4
fifteen_letters
4
refund
4
refund
10000
4
refund
x
4
refund
12
2
5
basic
interpreter: byte-equal== Webhook router ==
A payment provider's events through five handlers written before it added a kind.
1) events 2) run the handlers 3) each kind 4) add an event 5) quit
choice> 1
The events, in the order they came:
1 ping 0.00 means: ignore
2 payment 50.00 means: add
3 test 0.00 means: ignore
4 payment 25.00 means: add
5 refund 15.00 means: subtract
6 ping 0.00 means: ignore
7 payment 40.00 means: add
8 chargeback 25.00 means: subtract
1) events 2) run the handlers 3) each kind 4) add an event 5) quit
choice> 2
handler revenue added subtracted ignored held failed accounted
if-else 125.00 4 1 3 0 0 8 of 8
no else 100.00 3 1 3 0 0 7 of 8
default 100.00 3 1 4 0 0 8 of 8
raise 100.00 3 1 3 0 1 8 of 8
quarantine 100.00 3 1 3 1 0 8 of 8
the truth 75.00
if-else: 1 event handled wrong without a word; revenue 50.00 above the truth.
no else: 1 event went nowhere, which only the total shows: 7 of 8 accounted for; revenue 25.00 above the truth.
default: 1 event handled wrong without a word; revenue 25.00 above the truth.
raise: 1 event failed with an error, so someone hears of it; revenue 25.00 above the truth, until those are handled.
quarantine: 1 event waits in the hold queue for a person; revenue 25.00 above the truth, until those are handled.
1) events 2) run the handlers 3) each kind 4) add an event 5) quit
choice> 3
kind means if-else no else default raise quarantine
ping ignore ignore ignore ignore ignore ignore
payment add add add add add add
test ignore ignore ignore ignore ignore ignore
refund subtract subtract subtract subtract subtract subtract
chargeback subtract add wrong (nothing) lost ignore wrong fail failed hold held
The handlers were written for: payment, refund, ping and test.
1) events 2) run the handlers 3) each kind 4) add an event 5) quit
choice> 4
kind> dispute_won
amount in whole units (0 to 9999)> 30
Event 9: dispute_won 30.00, a kind nobody has defined: it should wait for a person.
if-else add wrong
no else nothing at all lost
default ignore wrong
raise fail failed
quarantine hold right
1) events 2) run the handlers 3) each kind 4) add an event 5) quit
choice> 4
kind> chargeback
amount in whole units (0 to 9999)> 10
Event 10: chargeback 10.00, which means subtract.
if-else add wrong
no else nothing at all lost
default ignore wrong
raise fail failed
quarantine hold held
1) events 2) run the handlers 3) each kind 4) add an event 5) quit
choice> 2
handler revenue added subtracted ignored held failed accounted
if-else 165.00 6 1 3 0 0 10 of 10
no else 100.00 3 1 3 0 0 7 of 10
default 100.00 3 1 6 0 0 10 of 10
raise 100.00 3 1 3 0 3 10 of 10
quarantine 100.00 3 1 3 3 0 10 of 10
the truth 65.00
if-else: 3 events handled wrong without a word; revenue 100.00 above the truth.
no else: 3 events went nowhere, which only the total shows: 7 of 10 accounted for; revenue 35.00 above the truth.
default: 3 events handled wrong without a word; revenue 35.00 above the truth.
raise: 3 events failed with an error, so someone hears of it; revenue 35.00 above the truth, until those are handled.
quarantine: 3 events wait in the hold queue for a person; revenue 35.00 above the truth, until those are handled.
1) events 2) run the handlers 3) each kind 4) add an event 5) quit
choice> 3
kind means if-else no else default raise quarantine
ping ignore ignore ignore ignore ignore ignore
payment add add add add add add
test ignore ignore ignore ignore ignore ignore
refund subtract subtract subtract subtract subtract subtract
chargeback subtract add wrong (nothing) lost ignore wrong fail failed hold held
dispute_won hold add wrong (nothing) lost ignore wrong fail failed hold
The handlers were written for: payment, refund, ping and test.
1) events 2) run the handlers 3) each kind 4) add an event 5) quit
choice> 5
Bye.
What was typed (12 lines)
1
2
3
4
dispute_won
30
4
chargeback
10
2
3
5
Modules
The program as written, entry module first. Each module transpiles to its own Python file, which is what eml project run executes.
main.eml(entry)
eml# P147 webhook router: a payment provider's events, five handlers' buckets
# and revenue set against what each kind means, what each handler does with
# each kind, and new events, of a kind seen before or never seen.
import router
def plain(s):
0 => i
len(s) => j
while i < j and s[i] == " ":
i + 1 => i
while j > i and s[j - 1] == " ":
j - 1 => j
return s[i:j]
def pad(s, n):
s => out
while len(out) < n:
out + " " => out
return out
def lpad(s, n):
s => out
while len(out) < n:
" " + out => out
return out
def money(c):
if c < 0:
return "-" + money(0 - c)
c % 100 => p
if p < 10:
return str(int((c - p) / 100)) + ".0" + str(p)
return str(int((c - p) / 100)) + "." + str(p)
def times(n, one, many):
if n == 1:
return "1 " + one
return str(n) + " " + many
def show_events(events):
"The events, in the order they came:" ^0
1 => k
for e in events:
router.truth(e[0]) => m
if m == "hold":
"nobody has said; hold it for a person" => m
(" " + lpad(str(k), 2) + " " + pad(e[0], 18) + lpad(money(e[1]), 8) + " means: " + m) ^0
k + 1 => k
def run(events):
(" " + pad("handler", 12) + "revenue added subtracted ignored held failed accounted") ^0
for r in router.routers():
router.tally(r, events) => t
(" " + pad(r, 12) + lpad(money(t[0]), 7) + lpad(str(t[1]), 7) + lpad(str(t[2]), 12) + lpad(str(t[3]), 9) + lpad(str(t[4]), 6) + lpad(str(t[5]), 8) + lpad(str(t[6]) + " of " + str(len(events)), 11)) ^0
router.true_revenue(events) => truth
(" " + pad("the truth", 12) + lpad(money(truth), 7)) ^0
for r in router.routers():
router.tally(r, events) => t
0 => wrong
0 => lost
0 => pending
for e in events:
router.verdict(r, e[0]) => v
if v == "wrong":
wrong + 1 => wrong
if v == "lost":
lost + 1 => lost
if v == "held" or v == "failed":
if router.truth(e[0]) == "add":
pending + e[1] => pending
if router.truth(e[0]) == "subtract":
pending - e[1] => pending
[] => parts
if wrong > 0:
parts + [times(wrong, "event", "events") + " handled wrong without a word"] => parts
if lost > 0:
parts + [times(lost, "event", "events") + " went nowhere, which only the total shows: " + str(t[6]) + " of " + str(len(events)) + " accounted for"] => parts
if t[5] > 0:
parts + [times(t[5], "event", "events") + " failed with an error, so someone hears of it"] => parts
if t[4] > 0:
parts + [times(t[4], "event waits", "events wait") + " in the hold queue for a person"] => parts
"" => until
if t[0] + pending == truth and pending != 0:
", until those are handled" => until
if t[0] > truth:
parts + ["revenue " + money(t[0] - truth) + " above the truth" + until] => parts
"" => line
for p in parts:
if line == "":
p => line
else:
line + "; " + p => line
(" " + r + ": " + line + ".") ^0
def kinds(events):
[] => out
for e in events:
False => have
for k in out:
if k == e[0]:
True => have
if not have:
out + [e[0]] => out
return out
def per_kind(events):
(" " + pad("kind", 14) + pad("means", 10)) => head
for r in router.routers():
if r == "quarantine":
head + r => head
else:
head + pad(r, 16) => head
head ^0
for k in kinds(events):
(" " + pad(k, 14) + pad(router.truth(k), 10)) => line
for r in router.routers():
router.route(r, k) => a
if a == "":
"(nothing)" => a
router.verdict(r, k) => v
if v != "right":
a + " " + v => a
if r == "quarantine":
line + a => line
else:
line + pad(a, 16) => line
line ^0
("The handlers were written for: payment, refund, ping and test.") ^0
def add(events):
plain(input("kind> ")) => k
if k == "":
"Cancelled." ^0
return events
if len(k) > 14:
"Type a kind of 1 to 14 letters a to z or underscores." ^0
return events
for c in k:
if not ((c >= "a" and c <= "z") or c == "_"):
"Type a kind of 1 to 14 letters a to z or underscores." ^0
return events
plain(input("amount in whole units (0 to 9999)> ")) => t
if t == "":
"Cancelled." ^0
return events
if len(t) > 4:
"Type a whole number from 0 to 9999." ^0
return events
for c in t:
if c < "0" or c > "9":
"Type a whole number from 0 to 9999." ^0
return events
int(t) * 100 => amount
if router.truth(k) == "hold":
("Event " + str(len(events) + 1) + ": " + k + " " + money(amount) + ", a kind nobody has defined: it should wait for a person.") ^0
else:
("Event " + str(len(events) + 1) + ": " + k + " " + money(amount) + ", which means " + router.truth(k) + ".") ^0
for r in router.routers():
router.route(r, k) => a
if a == "":
"nothing at all" => a
(" " + pad(r, 12) + pad(a, 16) + router.verdict(r, k)) ^0
return events + [[k, amount]]
router.opening() => events
"== Webhook router ==" ^0
"A payment provider's events through five handlers written before it added a kind." ^0
True => running
while running:
"" ^0
"1) events 2) run the handlers 3) each kind 4) add an event 5) quit" ^0
plain(input("choice> ")) => choice
if choice == "1":
show_events(events)
elif choice == "2":
run(events)
elif choice == "3":
per_kind(events)
elif choice == "4":
add(events) => events
elif choice == "5":
False => running
else:
"Pick a number from 1 to 5." ^0
"Bye." ^0
Python projection (main.py)
import router
def plain(s):
i = 0
j = len(s)
while i < j and s[i] == " ":
i = i + 1
while j > i and s[j - 1] == " ":
j = j - 1
return s[i:j]
def pad(s, n):
out = s
while len(out) < n:
out = out + " "
return out
def lpad(s, n):
out = s
while len(out) < n:
out = " " + out
return out
def money(c):
if c < 0:
return "-" + money(0 - c)
p = c % 100
if p < 10:
return str(int((c - p) / 100)) + ".0" + str(p)
return str(int((c - p) / 100)) + "." + str(p)
def times(n, one, many):
if n == 1:
return "1 " + one
return str(n) + " " + many
def show_events(events):
print("The events, in the order they came:")
k = 1
for e in events:
m = router.truth(e[0])
if m == "hold":
m = "nobody has said; hold it for a person"
print(" " + lpad(str(k), 2) + " " + pad(e[0], 18) + lpad(money(e[1]), 8) + " means: " + m)
k = k + 1
def run(events):
print(" " + pad("handler", 12) + "revenue added subtracted ignored held failed accounted")
for r in router.routers():
t = router.tally(r, events)
print(" " + pad(r, 12) + lpad(money(t[0]), 7) + lpad(str(t[1]), 7) + lpad(str(t[2]), 12) + lpad(str(t[3]), 9) + lpad(str(t[4]), 6) + lpad(str(t[5]), 8) + lpad(str(t[6]) + " of " + str(len(events)), 11))
truth = router.true_revenue(events)
print(" " + pad("the truth", 12) + lpad(money(truth), 7))
for r in router.routers():
t = router.tally(r, events)
wrong = 0
lost = 0
pending = 0
for e in events:
v = router.verdict(r, e[0])
if v == "wrong":
wrong = wrong + 1
if v == "lost":
lost = lost + 1
if v == "held" or v == "failed":
if router.truth(e[0]) == "add":
pending = pending + e[1]
if router.truth(e[0]) == "subtract":
pending = pending - e[1]
parts = []
if wrong > 0:
parts = parts + [times(wrong, "event", "events") + " handled wrong without a word"]
if lost > 0:
parts = parts + [times(lost, "event", "events") + " went nowhere, which only the total shows: " + str(t[6]) + " of " + str(len(events)) + " accounted for"]
if t[5] > 0:
parts = parts + [times(t[5], "event", "events") + " failed with an error, so someone hears of it"]
if t[4] > 0:
parts = parts + [times(t[4], "event waits", "events wait") + " in the hold queue for a person"]
until = ""
if t[0] + pending == truth and pending != 0:
until = ", until those are handled"
if t[0] > truth:
parts = parts + ["revenue " + money(t[0] - truth) + " above the truth" + until]
line = ""
for p in parts:
if line == "":
line = p
else:
line = line + "; " + p
print(" " + r + ": " + line + ".")
def kinds(events):
out = []
for e in events:
have = False
for k in out:
if k == e[0]:
have = True
if not have:
out = out + [e[0]]
return out
def per_kind(events):
head = " " + pad("kind", 14) + pad("means", 10)
for r in router.routers():
if r == "quarantine":
head = head + r
else:
head = head + pad(r, 16)
print(head)
for k in kinds(events):
line = " " + pad(k, 14) + pad(router.truth(k), 10)
for r in router.routers():
a = router.route(r, k)
if a == "":
a = "(nothing)"
v = router.verdict(r, k)
if v != "right":
a = a + " " + v
if r == "quarantine":
line = line + a
else:
line = line + pad(a, 16)
print(line)
print("The handlers were written for: payment, refund, ping and test.")
def add(events):
k = plain(input("kind> "))
if k == "":
print("Cancelled.")
return events
if len(k) > 14:
print("Type a kind of 1 to 14 letters a to z or underscores.")
return events
for c in k:
if not (c >= "a" and c <= "z" or c == "_"):
print("Type a kind of 1 to 14 letters a to z or underscores.")
return events
t = plain(input("amount in whole units (0 to 9999)> "))
if t == "":
print("Cancelled.")
return events
if len(t) > 4:
print("Type a whole number from 0 to 9999.")
return events
for c in t:
if c < "0" or c > "9":
print("Type a whole number from 0 to 9999.")
return events
amount = int(t) * 100
if router.truth(k) == "hold":
print("Event " + str(len(events) + 1) + ": " + k + " " + money(amount) + ", a kind nobody has defined: it should wait for a person.")
else:
print("Event " + str(len(events) + 1) + ": " + k + " " + money(amount) + ", which means " + router.truth(k) + ".")
for r in router.routers():
a = router.route(r, k)
if a == "":
a = "nothing at all"
print(" " + pad(r, 12) + pad(a, 16) + router.verdict(r, k))
return events + [[k, amount]]
events = router.opening()
print("== Webhook router ==")
print("A payment provider's events through five handlers written before it added a kind.")
running = True
while running:
print("")
print("1) events 2) run the handlers 3) each kind 4) add an event 5) quit")
choice = plain(input("choice> "))
if choice == "1":
show_events(events)
elif choice == "2":
run(events)
elif choice == "3":
per_kind(events)
elif choice == "4":
events = add(events)
elif choice == "5":
running = False
else:
print("Pick a number from 1 to 5.")
print("Bye.")
router.eml
eml# P147 webhook router - a payment provider's events routed by five
# handlers written before the provider added a new kind. As in the corpus
# case event-router-ignored-branches, ignoring an event is a decision that
# needs a branch, and only the total of every bucket shows an event that
# went nowhere. As in the corpus case new-enum-value-fallthrough, a kind
# added later meets each handler's "anything else": an else that answers
# for it, a default that guesses, an error, or a hold queue. An event is
# [kind, amount in cents]; an action is add, subtract, ignore, hold, fail,
# or "" when the handler does nothing with it at all.
def routers():
return ["if-else", "no else", "default", "raise", "quarantine"]
def what():
return ["refund subtracts, ping and test pass, else adds", "the same branches with no else at all", "a table, and ignore for a kind it lacks", "a table, and an error for a kind it lacks", "a table, and a hold queue for a kind it lacks"]
def opening():
return [["ping", 0], ["payment", 5000], ["test", 0], ["payment", 2500], ["refund", 1500], ["ping", 0], ["payment", 4000], ["chargeback", 2500]]
def known():
# the kinds the handlers were written for
return ["payment", "refund", "ping", "test"]
def truth(kind):
# what each kind means, stated apart from every handler; a kind nobody
# has defined should wait for a person
if kind == "payment":
return "add"
if kind == "refund" or kind == "chargeback":
return "subtract"
if kind == "ping" or kind == "test":
return "ignore"
return "hold"
def in_table(kind):
for k in known():
if k == kind:
return True
return False
def route(router, kind):
if router == "if-else":
if kind == "refund":
return "subtract"
elif kind == "ping" or kind == "test":
return "ignore"
else:
return "add"
if router == "no else":
if kind == "payment":
return "add"
if kind == "refund":
return "subtract"
if kind == "ping" or kind == "test":
return "ignore"
return ""
if in_table(kind):
return truth(kind)
if router == "default":
return "ignore"
if router == "raise":
return "fail"
return "hold"
def tally(router, events):
# [revenue, added, subtracted, ignored, held, failed, accounted]
[0, 0, 0, 0, 0, 0, 0] => t
for e in events:
route(router, e[0]) => a
if a == "add":
[t[0] + e[1], t[1] + 1, t[2], t[3], t[4], t[5], t[6] + 1] => t
elif a == "subtract":
[t[0] - e[1], t[1], t[2] + 1, t[3], t[4], t[5], t[6] + 1] => t
elif a == "ignore":
[t[0], t[1], t[2], t[3] + 1, t[4], t[5], t[6] + 1] => t
elif a == "hold":
[t[0], t[1], t[2], t[3], t[4] + 1, t[5], t[6] + 1] => t
elif a == "fail":
[t[0], t[1], t[2], t[3], t[4], t[5] + 1, t[6] + 1] => t
return t
def true_revenue(events):
0 => r
for e in events:
truth(e[0]) => a
if a == "add":
r + e[1] => r
elif a == "subtract":
r - e[1] => r
return r
def verdict(router, kind):
# right, held, failed, lost (nothing done and nothing counted), or wrong
# (a definite answer, and not the true one)
route(router, kind) => a
if a == truth(kind):
return "right"
if a == "":
return "lost"
if a == "hold":
return "held"
if a == "fail":
return "failed"
return "wrong"
Python projection (router.py)
def routers():
return ["if-else", "no else", "default", "raise", "quarantine"]
def what():
return ["refund subtracts, ping and test pass, else adds", "the same branches with no else at all", "a table, and ignore for a kind it lacks", "a table, and an error for a kind it lacks", "a table, and a hold queue for a kind it lacks"]
def opening():
return [["ping", 0], ["payment", 5000], ["test", 0], ["payment", 2500], ["refund", 1500], ["ping", 0], ["payment", 4000], ["chargeback", 2500]]
def known():
return ["payment", "refund", "ping", "test"]
def truth(kind):
if kind == "payment":
return "add"
if kind == "refund" or kind == "chargeback":
return "subtract"
if kind == "ping" or kind == "test":
return "ignore"
return "hold"
def in_table(kind):
for k in known():
if k == kind:
return True
return False
def route(router, kind):
if router == "if-else":
if kind == "refund":
return "subtract"
elif kind == "ping" or kind == "test":
return "ignore"
else:
return "add"
if router == "no else":
if kind == "payment":
return "add"
if kind == "refund":
return "subtract"
if kind == "ping" or kind == "test":
return "ignore"
return ""
if in_table(kind):
return truth(kind)
if router == "default":
return "ignore"
if router == "raise":
return "fail"
return "hold"
def tally(router, events):
t = [0, 0, 0, 0, 0, 0, 0]
for e in events:
a = route(router, e[0])
if a == "add":
t = [t[0] + e[1], t[1] + 1, t[2], t[3], t[4], t[5], t[6] + 1]
elif a == "subtract":
t = [t[0] - e[1], t[1], t[2] + 1, t[3], t[4], t[5], t[6] + 1]
elif a == "ignore":
t = [t[0], t[1], t[2], t[3] + 1, t[4], t[5], t[6] + 1]
elif a == "hold":
t = [t[0], t[1], t[2], t[3], t[4] + 1, t[5], t[6] + 1]
elif a == "fail":
t = [t[0], t[1], t[2], t[3], t[4], t[5] + 1, t[6] + 1]
return t
def true_revenue(events):
r = 0
for e in events:
a = truth(e[0])
if a == "add":
r = r + e[1]
elif a == "subtract":
r = r - e[1]
return r
def verdict(router, kind):
a = route(router, kind)
if a == truth(kind):
return "right"
if a == "":
return "lost"
if a == "hold":
return "held"
if a == "fail":
return "failed"
return "wrong"