Spaces:
Paused
Paused
AIBRUH Claude Sonnet 5 commited on
Commit ·
7344b62
1
Parent(s): 66b039d
PARLAY: left mascot rail with cigar smoke, Crazy Horse moved to the top, ticket confidence score removed
Browse files
docs/HANDOFF.md
CHANGED
|
@@ -550,8 +550,7 @@ haircut) is returned as `crazyHorse` and shown as the hero at the bottom of the
|
|
| 550 |
`GET /api/jimmy/scan` is the deep-scan funnel (sides scored, legs per tier, tickets built).
|
| 551 |
NFL game legs trust only half of the model's gap from 50% (Vegas is sharper than a 2-game model).
|
| 552 |
The CHARTS and PLAYER tabs are hidden from the nav (the player page still opens from a leaders click); the
|
| 553 |
-
default view is PARLAY and the node canvas is hidden behind a NODES tab. Every ticket carries a
|
| 554 |
-
(average leg probability), a photo strip when it pays +800 or more, and a FAKE IT (default) / TAKE IT control
|
| 555 |
(`TicketCard.tsx`, `TakeItFakeIt.tsx`). SPY BOY is grouped into tickets A and B (up to C), five legs max, best
|
| 556 |
payouts first; CRAZY HORSE is 10 high-probability legs; `jimmy_featured.py` builds the featured single-player RB
|
| 557 |
parlay (anytime TD + 70+ rush yds + 3+ rec) shown in the white panel at the top of PARLAY. The lake has no
|
|
|
|
| 550 |
`GET /api/jimmy/scan` is the deep-scan funnel (sides scored, legs per tier, tickets built).
|
| 551 |
NFL game legs trust only half of the model's gap from 50% (Vegas is sharper than a 2-game model).
|
| 552 |
The CHARTS and PLAYER tabs are hidden from the nav (the player page still opens from a leaders click); the
|
| 553 |
+
default view is PARLAY and the node canvas is hidden behind a NODES tab. Every ticket carries a photo strip when it pays +800 or more, and a FAKE IT (default) / TAKE IT control
|
|
|
|
| 554 |
(`TicketCard.tsx`, `TakeItFakeIt.tsx`). SPY BOY is grouped into tickets A and B (up to C), five legs max, best
|
| 555 |
payouts first; CRAZY HORSE is 10 high-probability legs; `jimmy_featured.py` builds the featured single-player RB
|
| 556 |
parlay (anytime TD + 70+ rush yds + 3+ rec) shown in the white panel at the top of PARLAY. The lake has no
|
frontend/src/components/EngineTab.tsx
CHANGED
|
@@ -2,7 +2,7 @@ import { useEffect, useState } from "react";
|
|
| 2 |
import { api } from "../api";
|
| 3 |
import type { EngineSlip, PowSummary } from "../types";
|
| 4 |
import TakeItFakeIt from "./TakeItFakeIt";
|
| 5 |
-
import TicketCard, {
|
| 6 |
import { useEngine } from "./useEngine";
|
| 7 |
|
| 8 |
const TYPE_ORDER = ["BPL_EDGE", "SPY_BOY"];
|
|
@@ -32,7 +32,6 @@ export function CrazyHorseHero({ slip }: { slip: EngineSlip }) {
|
|
| 32 |
{american(slip.boostedAmericanOdds)} · {slip.hitProbability !== undefined ? `${(slip.hitProbability * 100).toFixed(1)}%` : "—"} to hit all {slip.legs.length}
|
| 33 |
</span>
|
| 34 |
</div>
|
| 35 |
-
<ConfidenceRing value={slip.confidence ?? 0} size={78} />
|
| 36 |
</div>
|
| 37 |
</div>
|
| 38 |
|
|
@@ -63,7 +62,7 @@ function PowLine({ pow }: { pow: PowSummary | null }) {
|
|
| 63 |
);
|
| 64 |
}
|
| 65 |
|
| 66 |
-
export default function EngineTab() {
|
| 67 |
const { data, error } = useEngine();
|
| 68 |
const [filter, setFilter] = useState<string>("ALL");
|
| 69 |
const [pow, setPow] = useState<PowSummary | null>(null);
|
|
@@ -75,10 +74,11 @@ export default function EngineTab() {
|
|
| 75 |
|
| 76 |
return (
|
| 77 |
<div style={{ display: "flex", flexDirection: "column", gap: 14, maxWidth: 1100, width: "100%", margin: "0 auto" }}>
|
|
|
|
| 78 |
<div style={{ display: "flex", flexDirection: "column", gap: 4 }}>
|
| 79 |
-
<span style={{ fontSize: 12, fontWeight: 800, letterSpacing: "0.14em", color: "var(--bp-muted)" }}>PROPPA ENGINE · EVERY TICKET
|
| 80 |
<span style={{ fontSize: 11, color: "var(--bp-muted)" }}>
|
| 81 |
-
Big Proppa Line vs FanDuel · player props, NFL games and college · one leg per game ·
|
| 82 |
</span>
|
| 83 |
<PowLine pow={pow} />
|
| 84 |
</div>
|
|
@@ -108,7 +108,6 @@ export default function EngineTab() {
|
|
| 108 |
|
| 109 |
{visible.map((slip) => <TicketCard key={slip.id} slip={slip} />)}
|
| 110 |
|
| 111 |
-
{slips && slips.length > 0 && data?.crazyHorse && <CrazyHorseHero slip={data.crazyHorse} />}
|
| 112 |
</div>
|
| 113 |
);
|
| 114 |
}
|
|
|
|
| 2 |
import { api } from "../api";
|
| 3 |
import type { EngineSlip, PowSummary } from "../types";
|
| 4 |
import TakeItFakeIt from "./TakeItFakeIt";
|
| 5 |
+
import TicketCard, { LegLine, TYPE_META, american } from "./TicketCard";
|
| 6 |
import { useEngine } from "./useEngine";
|
| 7 |
|
| 8 |
const TYPE_ORDER = ["BPL_EDGE", "SPY_BOY"];
|
|
|
|
| 32 |
{american(slip.boostedAmericanOdds)} · {slip.hitProbability !== undefined ? `${(slip.hitProbability * 100).toFixed(1)}%` : "—"} to hit all {slip.legs.length}
|
| 33 |
</span>
|
| 34 |
</div>
|
|
|
|
| 35 |
</div>
|
| 36 |
</div>
|
| 37 |
|
|
|
|
| 62 |
);
|
| 63 |
}
|
| 64 |
|
| 65 |
+
export default function EngineTab({ showHorse = true }: { showHorse?: boolean }) {
|
| 66 |
const { data, error } = useEngine();
|
| 67 |
const [filter, setFilter] = useState<string>("ALL");
|
| 68 |
const [pow, setPow] = useState<PowSummary | null>(null);
|
|
|
|
| 74 |
|
| 75 |
return (
|
| 76 |
<div style={{ display: "flex", flexDirection: "column", gap: 14, maxWidth: 1100, width: "100%", margin: "0 auto" }}>
|
| 77 |
+
{showHorse && data?.crazyHorse && <CrazyHorseHero slip={data.crazyHorse} />}
|
| 78 |
<div style={{ display: "flex", flexDirection: "column", gap: 4 }}>
|
| 79 |
+
<span style={{ fontSize: 12, fontWeight: 800, letterSpacing: "0.14em", color: "var(--bp-muted)" }}>PROPPA ENGINE · EVERY TICKET PRICED</span>
|
| 80 |
<span style={{ fontSize: 11, color: "var(--bp-muted)" }}>
|
| 81 |
+
Big Proppa Line vs FanDuel · player props, NFL games and college · one leg per game · every ticket defaults to FAKE IT in MY BOO
|
| 82 |
</span>
|
| 83 |
<PowLine pow={pow} />
|
| 84 |
</div>
|
|
|
|
| 108 |
|
| 109 |
{visible.map((slip) => <TicketCard key={slip.id} slip={slip} />)}
|
| 110 |
|
|
|
|
| 111 |
</div>
|
| 112 |
);
|
| 113 |
}
|
frontend/src/components/FeaturedPlayer.tsx
CHANGED
|
@@ -1,7 +1,7 @@
|
|
| 1 |
import { useState } from "react";
|
| 2 |
import type { EngineSlip } from "../types";
|
| 3 |
import TakeItFakeIt from "./TakeItFakeIt";
|
| 4 |
-
import {
|
| 5 |
|
| 6 |
const MONO = "var(--font-mono, monospace)";
|
| 7 |
|
|
@@ -30,7 +30,6 @@ export default function FeaturedPlayer({ slip }: { slip: EngineSlip }) {
|
|
| 30 |
<span style={{ fontSize: 40, fontWeight: 900, lineHeight: 1, letterSpacing: "-0.01em" }}>{p.name}</span>
|
| 31 |
<span style={{ fontSize: 15, color: "#6b6553", fontWeight: 600 }}>{p.team} · {p.position}</span>
|
| 32 |
</div>
|
| 33 |
-
<ConfidenceRing value={slip.confidence ?? 0} size={72} light />
|
| 34 |
</div>
|
| 35 |
|
| 36 |
<div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(150px, 1fr))", gap: 10 }}>
|
|
|
|
| 1 |
import { useState } from "react";
|
| 2 |
import type { EngineSlip } from "../types";
|
| 3 |
import TakeItFakeIt from "./TakeItFakeIt";
|
| 4 |
+
import { american } from "./TicketCard";
|
| 5 |
|
| 6 |
const MONO = "var(--font-mono, monospace)";
|
| 7 |
|
|
|
|
| 30 |
<span style={{ fontSize: 40, fontWeight: 900, lineHeight: 1, letterSpacing: "-0.01em" }}>{p.name}</span>
|
| 31 |
<span style={{ fontSize: 15, color: "#6b6553", fontWeight: 600 }}>{p.team} · {p.position}</span>
|
| 32 |
</div>
|
|
|
|
| 33 |
</div>
|
| 34 |
|
| 35 |
<div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(150px, 1fr))", gap: 10 }}>
|
frontend/src/components/MascotRail.tsx
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/**
|
| 2 |
+
* Left-hand mascot column: the Big Proppa photo with the cigar ember and rising smoke, sized to the
|
| 3 |
+
* column. Uses the same smoke animation as SmokeBadge (theme.css) and its measured ember anchor
|
| 4 |
+
* (left 21.5%, top 61% of the photo). If a full-body image is supplied later, drop it in as
|
| 5 |
+
* /big-proppa-full.png, set FULL_BODY = true, and re-measure the ember anchor for the new cigar tip.
|
| 6 |
+
*/
|
| 7 |
+
const FULL_BODY = false;
|
| 8 |
+
const SRC = FULL_BODY ? "/big-proppa-full.png" : "/big-proppa.png";
|
| 9 |
+
const ANCHOR = FULL_BODY ? { left: "21.5%", top: "61%" } : { left: "21.5%", top: "61%" };
|
| 10 |
+
const ASPECT = 520 / 512;
|
| 11 |
+
|
| 12 |
+
export default function MascotRail({ width = 300 }: { width?: number }) {
|
| 13 |
+
const puffs = ["bp-puff-a1", "bp-puff-b1", "bp-puff-c1", "bp-puff-a2", "bp-puff-b2", "bp-wisp-1", "bp-wisp-2", "bp-wisp-3"];
|
| 14 |
+
const opacity = [0.6, 0.55, 0.5, 0.45, 0.4, 0.4, 0.35, 0.35];
|
| 15 |
+
const em = width / 22;
|
| 16 |
+
return (
|
| 17 |
+
<aside className="mascot-rail" style={{ width, flex: `0 0 ${width}px`, position: "sticky", top: 8, alignSelf: "flex-start", display: "flex", flexDirection: "column", alignItems: "center", gap: 10 }}>
|
| 18 |
+
<style>{`@media (max-width: 1350px) { .mascot-rail { display: none !important; } }`}</style>
|
| 19 |
+
<div style={{ position: "relative", width, height: width / ASPECT, borderRadius: 18, overflow: "hidden", border: "1px solid #6b4a1c", boxShadow: "0 0 30px rgba(224,120,47,0.18)",
|
| 20 |
+
WebkitMaskImage: "linear-gradient(to bottom, #000 78%, transparent 100%)", maskImage: "linear-gradient(to bottom, #000 78%, transparent 100%)" }}>
|
| 21 |
+
<img src={SRC} alt="Big Proppa" style={{ width: "100%", height: "100%", objectFit: "cover", display: "block" }} />
|
| 22 |
+
<div style={{ position: "absolute", left: ANCHOR.left, top: ANCHOR.top, width: 0, height: 0, fontSize: `${em}px`, pointerEvents: "none" }}>
|
| 23 |
+
<div className="bp-ember" style={{ position: "absolute", left: "-2em", top: "-2em", width: "4em", height: "4em", borderRadius: "50%", background: "radial-gradient(circle, rgba(255,80,30,0.7), rgba(255,40,10,0) 70%)", mixBlendMode: "screen" }} />
|
| 24 |
+
<div className="bp-core" style={{ position: "absolute", left: "-.55em", top: "-.7em", width: "1.1em", height: "1.4em", borderRadius: "50%", background: "radial-gradient(circle, rgba(255,240,170,1), rgba(255,120,40,0.9) 45%, rgba(220,30,10,0) 80%)" }} />
|
| 25 |
+
{puffs.map((cls, i) => (
|
| 26 |
+
<div key={cls} className={cls} style={{ position: "absolute", left: "-1.6em", top: "-3.2em", width: "3.2em", height: "3.2em", borderRadius: "50%", background: `radial-gradient(circle, rgba(228,225,235,${opacity[i]}), rgba(228,225,235,0) 70%)`, filter: "blur(0.45em)", opacity: 0 }} />
|
| 27 |
+
))}
|
| 28 |
+
</div>
|
| 29 |
+
</div>
|
| 30 |
+
<span style={{ fontSize: 13, fontWeight: 900, letterSpacing: "0.16em", background: "var(--bp-wordmark-gradient)", WebkitBackgroundClip: "text", backgroundClip: "text", color: "transparent" }}>HEY BIG PROPPA!</span>
|
| 31 |
+
</aside>
|
| 32 |
+
);
|
| 33 |
+
}
|
frontend/src/components/ParlaysTab.tsx
CHANGED
|
@@ -1,7 +1,8 @@
|
|
| 1 |
import { useEffect, useState } from "react";
|
| 2 |
import { api } from "../api";
|
| 3 |
import type { ParlaySlip, PlayerPropChart } from "../types";
|
| 4 |
-
import EngineTab from "./EngineTab";
|
|
|
|
| 5 |
import FeaturedPlayer from "./FeaturedPlayer";
|
| 6 |
import TicketCard, { fromThemed } from "./TicketCard";
|
| 7 |
import { useEngine } from "./useEngine";
|
|
@@ -42,7 +43,10 @@ export default function ParlaysTab({
|
|
| 42 |
}) {
|
| 43 |
const { data } = useEngine();
|
| 44 |
return (
|
| 45 |
-
<div style={{ display: "flex",
|
|
|
|
|
|
|
|
|
|
| 46 |
{data?.featured && <FeaturedPlayer slip={data.featured} />}
|
| 47 |
<a
|
| 48 |
href="/parlays"
|
|
@@ -86,7 +90,8 @@ export default function ParlaysTab({
|
|
| 86 |
</div>
|
| 87 |
|
| 88 |
<TonightsSlips />
|
| 89 |
-
<EngineTab />
|
|
|
|
| 90 |
</div>
|
| 91 |
);
|
| 92 |
}
|
|
|
|
| 1 |
import { useEffect, useState } from "react";
|
| 2 |
import { api } from "../api";
|
| 3 |
import type { ParlaySlip, PlayerPropChart } from "../types";
|
| 4 |
+
import EngineTab, { CrazyHorseHero } from "./EngineTab";
|
| 5 |
+
import MascotRail from "./MascotRail";
|
| 6 |
import FeaturedPlayer from "./FeaturedPlayer";
|
| 7 |
import TicketCard, { fromThemed } from "./TicketCard";
|
| 8 |
import { useEngine } from "./useEngine";
|
|
|
|
| 43 |
}) {
|
| 44 |
const { data } = useEngine();
|
| 45 |
return (
|
| 46 |
+
<div style={{ display: "flex", gap: 22, alignItems: "flex-start", justifyContent: "center", width: "100%" }}>
|
| 47 |
+
<MascotRail />
|
| 48 |
+
<div style={{ display: "flex", flexDirection: "column", gap: 16, maxWidth: 1100, flex: "1 1 0", minWidth: 0 }}>
|
| 49 |
+
{data?.crazyHorse && <CrazyHorseHero slip={data.crazyHorse} />}
|
| 50 |
{data?.featured && <FeaturedPlayer slip={data.featured} />}
|
| 51 |
<a
|
| 52 |
href="/parlays"
|
|
|
|
| 90 |
</div>
|
| 91 |
|
| 92 |
<TonightsSlips />
|
| 93 |
+
<EngineTab showHorse={false} />
|
| 94 |
+
</div>
|
| 95 |
</div>
|
| 96 |
);
|
| 97 |
}
|
frontend/src/components/TicketCard.tsx
CHANGED
|
@@ -26,7 +26,7 @@ export function toAmerican(decimal: number): string {
|
|
| 26 |
export function fromThemed(s: ParlaySlip): EngineSlip {
|
| 27 |
return {
|
| 28 |
id: `SLIP-${s.id}`, title: s.title, correlationType: "THEMED", badge: s.title, insight: "",
|
| 29 |
-
|
| 30 |
combinedDecimalOdds: s.combinedDecimalOdds, payout: s.payout, boostedPayout: s.boostedPayout, boostedAmericanOdds: s.boostedAmericanOdds,
|
| 31 |
legs: s.legs.map((l) => ({
|
| 32 |
playerId: l.playerId ?? l.teamId ?? l.name, name: l.name, team: l.team ?? "", market: l.market ?? "", direction: l.direction ?? "over",
|
|
@@ -54,24 +54,6 @@ export function Avatar({ leg, size, ring = "#c9a54e" }: { leg: Pick<EngineLeg, "
|
|
| 54 |
);
|
| 55 |
}
|
| 56 |
|
| 57 |
-
export function ConfidenceRing({ value, size = 64, light = false }: { value: number; size?: number; light?: boolean }) {
|
| 58 |
-
const color = value >= 75 ? "#16a34a" : value >= 62 ? "#c9a54e" : "#e0782f";
|
| 59 |
-
const r = size / 2 - 5;
|
| 60 |
-
const c = 2 * Math.PI * r;
|
| 61 |
-
return (
|
| 62 |
-
<span title="Confidence: the average hit probability of the legs on this ticket" style={{ display: "inline-flex", flexDirection: "column", alignItems: "center", gap: 2, flex: "0 0 auto" }}>
|
| 63 |
-
<span style={{ position: "relative", width: size, height: size }}>
|
| 64 |
-
<svg width={size} height={size} viewBox={`0 0 ${size} ${size}`} style={{ transform: "rotate(-90deg)" }}>
|
| 65 |
-
<circle cx={size / 2} cy={size / 2} r={r} fill="none" stroke={light ? "#e8e2d0" : "rgba(255,255,255,0.12)"} strokeWidth="5" />
|
| 66 |
-
<circle cx={size / 2} cy={size / 2} r={r} fill="none" stroke={color} strokeWidth="5" strokeLinecap="round" strokeDasharray={c} strokeDashoffset={c * (1 - Math.min(100, value) / 100)} />
|
| 67 |
-
</svg>
|
| 68 |
-
<span style={{ position: "absolute", inset: 0, display: "flex", alignItems: "center", justifyContent: "center", fontFamily: MONO, fontSize: size * 0.34, fontWeight: 800, color: light ? "#1a1a1a" : color }}>{value}</span>
|
| 69 |
-
</span>
|
| 70 |
-
<span style={{ fontSize: 8, fontWeight: 800, letterSpacing: "0.12em", color: light ? "#6b6553" : "var(--bp-muted)" }}>CONFIDENCE</span>
|
| 71 |
-
</span>
|
| 72 |
-
);
|
| 73 |
-
}
|
| 74 |
-
|
| 75 |
export function LegLine({ leg }: { leg: EngineLeg }) {
|
| 76 |
const pct = Math.round(leg.probability * 100);
|
| 77 |
const pc = pct >= 75 ? "#2ee6a6" : pct >= 60 ? "#d9b45a" : "#e0782f";
|
|
@@ -92,7 +74,6 @@ export default function TicketCard({ slip }: { slip: EngineSlip }) {
|
|
| 92 |
const meta = TYPE_META[slip.correlationType] ?? { label: slip.correlationType, color: "#d9b45a" };
|
| 93 |
const label = slip.badge ?? meta.label;
|
| 94 |
const bigPayout = slip.combinedDecimalOdds >= BIG_PAYOUT_DECIMAL;
|
| 95 |
-
const conf = slip.confidence ?? 0;
|
| 96 |
return (
|
| 97 |
<div style={{ background: "var(--bp-card-bg)", border: `1px solid ${meta.color}55`, borderLeft: `4px solid ${meta.color}`, borderRadius: 16, overflow: "hidden", display: "flex", flexDirection: "column" }}>
|
| 98 |
<div style={{ padding: "14px 16px 12px", display: "flex", gap: 14, alignItems: "flex-start" }}>
|
|
@@ -114,7 +95,6 @@ export default function TicketCard({ slip }: { slip: EngineSlip }) {
|
|
| 114 |
<span style={{ fontSize: 11, color: "var(--bp-muted)" }}>{(slip.hitProbability * 100).toFixed(1)}% to hit every leg</span>
|
| 115 |
)}
|
| 116 |
</div>
|
| 117 |
-
<ConfidenceRing value={conf} />
|
| 118 |
</div>
|
| 119 |
|
| 120 |
{bigPayout && (
|
|
|
|
| 26 |
export function fromThemed(s: ParlaySlip): EngineSlip {
|
| 27 |
return {
|
| 28 |
id: `SLIP-${s.id}`, title: s.title, correlationType: "THEMED", badge: s.title, insight: "",
|
| 29 |
+
wager: s.wager, boost: s.boost,
|
| 30 |
combinedDecimalOdds: s.combinedDecimalOdds, payout: s.payout, boostedPayout: s.boostedPayout, boostedAmericanOdds: s.boostedAmericanOdds,
|
| 31 |
legs: s.legs.map((l) => ({
|
| 32 |
playerId: l.playerId ?? l.teamId ?? l.name, name: l.name, team: l.team ?? "", market: l.market ?? "", direction: l.direction ?? "over",
|
|
|
|
| 54 |
);
|
| 55 |
}
|
| 56 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 57 |
export function LegLine({ leg }: { leg: EngineLeg }) {
|
| 58 |
const pct = Math.round(leg.probability * 100);
|
| 59 |
const pc = pct >= 75 ? "#2ee6a6" : pct >= 60 ? "#d9b45a" : "#e0782f";
|
|
|
|
| 74 |
const meta = TYPE_META[slip.correlationType] ?? { label: slip.correlationType, color: "#d9b45a" };
|
| 75 |
const label = slip.badge ?? meta.label;
|
| 76 |
const bigPayout = slip.combinedDecimalOdds >= BIG_PAYOUT_DECIMAL;
|
|
|
|
| 77 |
return (
|
| 78 |
<div style={{ background: "var(--bp-card-bg)", border: `1px solid ${meta.color}55`, borderLeft: `4px solid ${meta.color}`, borderRadius: 16, overflow: "hidden", display: "flex", flexDirection: "column" }}>
|
| 79 |
<div style={{ padding: "14px 16px 12px", display: "flex", gap: 14, alignItems: "flex-start" }}>
|
|
|
|
| 95 |
<span style={{ fontSize: 11, color: "var(--bp-muted)" }}>{(slip.hitProbability * 100).toFixed(1)}% to hit every leg</span>
|
| 96 |
)}
|
| 97 |
</div>
|
|
|
|
| 98 |
</div>
|
| 99 |
|
| 100 |
{bigPayout && (
|