{"version":3,"sources":["storage-machines.mjs"],"sourcesContent":["// STORAGE MACHINES: THE CARGO CRATE AND THE VENDING MACHINE (the owner's decisions, Oct 11). Byte-identical twins:\n// public/storage-machines.mjs, functions/lib/storage-machines.mjs, zone-server/lib/storage-machines.mjs\n// (generate-version-hash.js holds them equal).\n//\n// Until these two, a placed machine was only its item id in a chunk's blocks: it held nothing and showed nothing. A crate\n// HOLDS things and a vending machine holds things and tokens, so each placed one has a record of its own on the server,\n// machines/{addrKey~chunkId~localKey}, which only the Cloud Functions read or write (functions/machines.js), in one\n// transaction with every inventory and balance a move touches. No client reads it: its contents travel in the callables'\n// replies, so no firestore.rules change was needed (a rules deploy needs the owner's word, and the last one asked was\n// refused).\n//\n// WHAT EVERYONE MAY SEE is a SUMMARY, written by the same transaction into the chunk document the machine stands in\n// (world_deltas/{addr}/chunks/{chunkId}.m.<localKey>), which every signed-in player on the world already listens to:\n//   crate    { k: 'c', u: slots in use, l: its name (\"Ores\") or null, r: revision }\n//   vending  { k: 'v', on: active, md: 'sell' | 'buy', i: item, p: price, n: on sale / still wanted, o: owner's name,\n//              h: holds stock or escrow (and so will not break), r: revision }\n// The renderer draws the crate's fill gauge and the vending machine's lights from it, the crosshair's pill names it, and\n// an open panel re-asks for the contents when its revision moves (another builder took something). And a world's card\n// counts its open vending machines from claims/{addr}.shops, a copy of the active ones' public lines, kept by the same\n// transactions.\n//\n// Pure: names, numbers and words. The rules that move stacks are functions/lib/storage-rules.mjs, which reads the\n// inventory model this file has no business knowing.\n\nimport { baseItemOf, encodeItem, decodeItem } from './item-ids.mjs';   // a crate of any wood is a Cargo Crate\nimport { cellUp, isFacing } from './doors.mjs';   // a cell's up and a placer's facing (the Cargo Crate's second kube, Oct 21)\n\nexport const CRATE_NAME = 'Cargo Crate';\nexport const VENDING_NAME = 'Vending Machine';\n// \"Capacity: 30 slots, each with the usual stack rules\" (the owner, Oct 11): three rows of ten, the backpack's own shape.\n// …then SIXTY, two kubes wide (the owner, Oct 21: \"60 slots, and 2 kubes WIDE × 1 high\"): six rows of ten.\nexport const CRATE_SLOTS = 60;\n// \"ONE item type per machine … Its stock holds up to 10 stacks of that one item\" (the owner's note).\nexport const VENDING_STACKS = 10;\nexport const LABEL_MAX = 24;          // a crate's name (\"Ores\"): what fits the crosshair's pill and the panel's title\nexport const LOG_MAX = 50;            // \"a sales log the owner can open from the panel (last 50 entries)\"\n// \"Any price\" (the owner), capped at the marketplace's own maximum (functions/marketplace.js MARKET.MAX_PRICE).\nexport const PRICE_MIN = 1;\nexport const PRICE_MAX = 1000000;\nexport const FEE_PCT = 0.05;          // the marketplace's fee, burned: a token sink (marketplace.js MARKET.FEE_PCT)\nexport const PUSH_GAP_MS = 3600e3;    // a push to an owner who is away: at most one an hour, the sales in it summed\nexport const ONLINE_MS = 120e3;       // an owner whose presence beat is younger than this is in the game: a toast, not a push\n\nconst base = (n) => (typeof n === 'string' && n ? baseItemOf(n) : null);\n\n// ---- THE FURNITURE (the owner, Oct 19: \"try to work most of these into new kube-sized machines that are craftable by\n// players too. pass on rug/lockers for now\") ---------------------------------------------------------------------------\n// Fourteen kube-sized machines, each a family head with a variant per material (tools/material-variants.py), made at the\n// Toolbench (tools/recipe-variants.mjs) and placed in the peoples' towns too (world version 19). What each one IS:\n//   storage  holds `slots` stacks, opened beside the backpack with a right-click exactly as a Cargo Crate is: the same\n//            record, the same callable (crateOp), the same owner-and-builders rule, its contents a stash when broken\n//   bed      a right-click offers Rest (health back to full) and Set home beside it (vessel-life.js setHome, `bed`)\n//   bench    a crafting surface of the Toolbench's level (synthesis.mjs BENCH_ALSO)\n//   light    lights the cells round it at night, as a Lantern Kube does: `light` is its colour and flicker, which the\n//            renderer casts from a placed one (system-view.js, the 'm:' material's lightSrc; furnitureLightOf)\n//   decor    furniture: placed, drawn, mined, and nothing to open\nexport const FURNITURE = Object.freeze({\n  'Bed': Object.freeze({ kind: 'bed' }),\n  'Table': Object.freeze({ kind: 'decor' }),\n  'Bench': Object.freeze({ kind: 'decor' }),\n  'Shelf': Object.freeze({ kind: 'storage', slots: 5 }),\n  // THE STORAGE OF OCT 21 (the owner): a Cabinet holds 30; the Packing Crate is gone (its ids decode as the Cabinet of its\n  // wood: item-ids.mjs akaIds); the Wardrobe is the LOCKER, one kube wide and two high (a tall part: vessel-life.mjs TALL),\n  // holding 20; and the DISPLAY CASE holds one item and shows it to everyone (its line carries the item: crateSummary).\n  'Cabinet': Object.freeze({ kind: 'storage', slots: 30 }),   // the Chest until the owner, Oct 21: cabinets instead of chests (same ids)\n  'Barrel': Object.freeze({ kind: 'storage', slots: 5 }),\n  'Counter': Object.freeze({ kind: 'decor' }),\n  'Workbench': Object.freeze({ kind: 'bench' }),\n  'Locker': Object.freeze({ kind: 'storage', slots: 20 }),\n  'Display Case': Object.freeze({ kind: 'display', slots: 1 }),\n  'Planter': Object.freeze({ kind: 'decor' }),\n  'Hearth': Object.freeze({ kind: 'light', light: Object.freeze({ color: '#FF8A3A', flicker: true }) }),      // a warm orange fire\n  'Lamp Post': Object.freeze({ kind: 'light', light: Object.freeze({ color: '#FFCF6A', flicker: true }) }),   // the Lantern Kube's own light\n  'Trough': Object.freeze({ kind: 'decor' }),\n  // …AND WHAT ANIMALS GIVE (the owner's Alien Animals items, Oct 29): a HIDE RUG, a slab that lies flat on the floor (products.json\n  // `slab`, as the Solar Panel lies), and a BONE CHANDELIER round a Glow Gland, in the gland's own light, which hangs from a\n  // ceiling (hangsFromCeiling, below).\n  'Hide Rug': Object.freeze({ kind: 'decor' }),\n  'Bone Chandelier': Object.freeze({ kind: 'light', light: Object.freeze({ color: '#FFD070', flicker: true }) }),   // the Glow Gland's colour\n});\n// The furniture a name is (\"Cabinet (Void Wood)\" → \"Cabinet\"), or null for anything that is not furniture.\nexport function furnitureBaseOf(n) {\n  const b = base(n);\n  return b && Object.prototype.hasOwnProperty.call(FURNITURE, b) ? b : null;\n}\nexport const furnitureKindOf = (n) => { const b = furnitureBaseOf(n); return b ? FURNITURE[b].kind : null; };\nexport const isBedName = (n) => furnitureKindOf(n) === 'bed';\n// THE BONE CHANDELIER HANGS FROM A CEILING (Oct 29): it is placed only against the underside of a kube, so the cell it goes in\n// is the one BELOW the face aimed at. `na`, `ns` are that face's outward normal (axis, sign), from cell (x, y, z), the cell it\n// would take: true when the normal points down that cell's up, i.e. the aimed kube is over it.\nexport const CHANDELIER_NAME = 'Bone Chandelier';\nexport const isChandelierName = (n) => base(n) === CHANDELIER_NAME;\nexport const CHANDELIER_CEILING = 'A Bone Chandelier hangs from a ceiling: aim at the underside of a kube.';\nexport function hangsFromCeiling(x, y, z, na, ns, vessel) {\n  const up = cellUp(x, y, z, vessel);\n  return na === up.a && ns === -up.s;\n}\n// The light a piece of furniture casts, { color, flicker }, or null (building-kubes.mjs buildingLightOf's shape).\nexport const furnitureLightOf = (n) => { const b = furnitureBaseOf(n); return b && FURNITURE[b].light ? { ...FURNITURE[b].light } : null; };\n// HOW MANY STACKS A CONTAINER HOLDS: a Cargo Crate sixty, a storage piece of furniture its own `slots` (a Display Case one),\n// anything else none.\n// Every crate rule (storage-rules.mjs, functions/machines.js, the page's panel) sizes its grid by this.\nexport function crateSlotsOf(n) {\n  const b = base(n);\n  if (b === CRATE_NAME) return CRATE_SLOTS;\n  const f = b && Object.prototype.hasOwnProperty.call(FURNITURE, b) ? FURNITURE[b] : null;\n  return f && (f.kind === 'storage' || f.kind === 'display') ? f.slots : 0;\n}\n// A \"crate\" to every rule below is anything that holds stacks: the Cargo Crate and the storage furniture alike.\nexport const isCrateName = (n) => crateSlotsOf(n) > 0;\nexport const isVendingName = (n) => base(n) === VENDING_NAME;\nexport const isStorageMachine = (n) => isCrateName(n) || isVendingName(n);\n\n// ---- THE DISPLAY CASE (the owner, Oct 21) ---------------------------------------------------------------------------------\n// One slot, opened as any crate is (the same record, callable and owner-and-builders rule), and what is in it SHOWN to\n// everyone: its public line carries the item (crateSummary's `i`), which the renderer draws inside the glass, slowly turning.\n// Placed two ways from one item: aimed at a SIDE face it hangs on that wall, a shallow case on the face (its line's `f`, the\n// way the case looks out of the wall, doors.mjs facings); aimed at a top it stands as a whole glass case (no `f`).\nexport const DISPLAY_NAME = 'Display Case';\nexport const isDisplayCaseName = (n) => base(n) === DISPLAY_NAME;\n// The facing of a case hung on the face whose outward normal is axis `na`, sign `ns`, from cell (x, y, z): null when that\n// face is a top or a floor (the case then stands), else the doors.mjs facing 0..3 (0 +tA, 1 −tA, 2 +tB, 3 −tB).\nexport function displayWallFacing(x, y, z, na, ns, vessel) {\n  const up = cellUp(x, y, z, vessel);\n  if (na === up.a) return null;\n  const tA = (up.a + 1) % 3;\n  return na === tA ? (ns > 0 ? 0 : 1) : (ns > 0 ? 2 : 3);\n}\n\n// ---- THE LOCKER (the owner, Oct 21): the Wardrobe renamed in place, one kube wide and two high. Its pairing is the tall\n// parts' (vessel-life.mjs TALL: every Locker on one shared Locker Upper); what it holds is a crate's, at its base.\nexport const LOCKER_NAME = 'Locker';\nexport const LOCKER_UPPER = 'Locker Upper';\nexport const isLockerName = (n) => base(n) === LOCKER_NAME;\n\n// ---- THE CARGO CRATE IS TWO KUBES WIDE (the owner, Oct 21: \"2 kubes WIDE × 1 high, a two-cell machine lying sideways\") ---\n// Placed as its base, the aimed cell, which the server pairs with its SIDE, the cell to the placer's RIGHT: the placer faces\n// the crate's front (its facing f, doors.mjs: the way its front looks, toward the placer), so their right is up × front.\n// The side is one shared part, 'Cargo Crate Side' (products.json partOf), as every door stands on one Door Upper; the crate's\n// material and fill are its base's, read through the facing kept in the base's line ({ k: 'c', …, f }). Broken as the pair,\n// from either half, one crate back; its contents drop where the base stood, as any crate's.\nexport const CRATE_SIDE = 'Cargo Crate Side';\nexport const isCrateSide = (n) => n === CRATE_SIDE;\nexport const isWideCrate = (n) => base(n) === CRATE_NAME;     // a Cargo Crate of any material\nexport const isWidePart = (n) => isWideCrate(n) || isCrateSide(n);\nexport const WIDE_NO_ROOM = 'A Cargo Crate is two kubes wide: the kube to your right of it has to be free too.';\n// The unit vector to the placer's right, as [axis, sign]: up (a, s) × front (nrm, nrmS). With e_i × e_j = +e_k for (i, j, k)\n// cyclic, the right is the third axis, its sign the product of the two signs and the cycle's.\nexport function crateRightOf(x, y, z, f, vessel) {\n  const up = cellUp(x, y, z, vessel), tA = (up.a + 1) % 3, tB = (up.a + 2) % 3;\n  const nrm = (f | 0) < 2 ? tA : tB, nrmS = (f & 1) ? -1 : 1, lat = nrm === tA ? tB : tA;\n  const cyc = (nrm - up.a + 3) % 3 === 1 ? 1 : -1;            // (up, nrm, lat) in cyclic order?\n  return { a: lat, s: up.s * nrmS * cyc, up, nrm, nrmS };\n}\nexport function crateSideCell(x, y, z, f, vessel) {\n  if (!isFacing(f)) return null;\n  const r = crateRightOf(x, y, z, f, vessel), c = [x, y, z];\n  c[r.a] += r.s;\n  return c;\n}\n// The base a side belongs to: of the four cells beside it across its up, the one holding a Cargo Crate whose own side\n// (by the facing in its line) is this cell. `nameAt(x, y, z)` and `facingAt(x, y, z)` read the world as the caller holds it.\nexport function crateBaseOfSide(x, y, z, nameAt, facingAt, vessel) {\n  const up = cellUp(x, y, z, vessel);\n  for (const a of [0, 1, 2]) { if (a === up.a) continue;\n    for (const s of [1, -1]) {\n      const c = [x, y, z]; c[a] += s;\n      if (!isWideCrate(nameAt(c[0], c[1], c[2]))) continue;\n      const sc = crateSideCell(c[0], c[1], c[2], facingAt(c[0], c[1], c[2]), vessel);\n      if (sc && sc[0] === x && sc[1] === y && sc[2] === z) return c;\n    } }\n  return null;\n}\n\n// WHERE A MACHINE'S RECORD LIVES: one document per placed machine, keyed by its world and its cell. '~' joins the parts\n// because neither an address key (digits, '_', a/b) nor a chunk or local key (digits, '_', '-') can contain it.\nexport const machineKey = (chunkId, localKey) => chunkId + '~' + localKey;\nexport const machineDocId = (addrKey, chunkId, localKey) => addrKey + '~' + machineKey(chunkId, localKey);\n\n// ---- WHO MAY DO WHAT ----------------------------------------------------------------------------------------------\n// A CRATE OPENS FOR THE CLAIM'S OWNER AND BUILDERS (the owner's decision), the people who may build there, which is the\n// same question submitEdits and the death stash ask (stash-rules.mjs canTakeFromStash). On a world nobody holds (a claim\n// released with crates still standing on it) nobody owns the ground, so nobody owns what stands on it: open to whoever is\n// there, as a stash on a wild world is. Only reachable after a release: a crate can only be PLACED on a claim.\nexport const CRATE_DENIED = 'Only the owner and builders can open this crate.';\nexport function canOpenCrate(claim, uid) {\n  if (!uid) return false;\n  if (!claim) return true;\n  if (claim.owner === uid) return true;\n  return Array.isArray(claim.builders) && claim.builders.includes(uid);\n}\n// WHO MAY BUY AND SELL AT A VENDING MACHINE: \"anyone who can visit the world; on a private claim, only those let in\".\n// Today every signed-in player may land on any world: a claim is private for BUILDING only (new claims private by\n// default, f0973f8: only the owner and the builders they choose may build), and nothing keeps a visitor off. So every\n// signed-in player who is on the world may trade at its machines. This is the one place to narrow if worlds ever get a\n// visitor list.\nexport function canVisitWorld(claim, uid) { return !!uid; }\n\n// ---- THE CRATE'S FILL GAUGE (the owner: \"a strip of lit pixels on the FRONT face fills with the crate's contents,\n// green, then amber near full, then red when full\") ----------------------------------------------------------------\n// The strip is the front face's bottom edge, 18 face pixels (machine-icons.mjs drawers), lit in pairs: nine steps,\n// so a crate has at most eleven looks (nine levels and two colours at the top) and the renderer at most eleven textures\n// of it. The ninth step and red are FULL, every slot in use; amber from four fifths. Any content lights one step.\nexport const GAUGE_STEPS = 9;\nexport const GAUGE_PIXELS = 18;\nexport const GAUGE_AMBER = 48;        // slots in use from which a Cargo Crate's gauge turns amber (four fifths of sixty)\n// `cap` is the container's size (crateSlotsOf); amber from four fifths of it.\nexport function crateGauge(used, cap = CRATE_SLOTS) {\n  const n = cap > 0 ? cap | 0 : CRATE_SLOTS;\n  const u = Math.max(0, Math.min(n, Math.floor(Number(used) || 0)));\n  const full = u >= n;\n  const level = full ? GAUGE_STEPS : u ? Math.min(GAUGE_STEPS - 1, Math.ceil(u * GAUGE_STEPS / n)) : 0;\n  return { used: u, full, level, lit: level * GAUGE_PIXELS / GAUGE_STEPS, colour: full ? 'R' : u >= Math.ceil(n * 4 / 5) ? 'A' : 'N' };\n}\n\n// ---- WHEN A VENDING MACHINE IS OPEN (the owner: \"its screen and lamps glow only while active\") ---------------------\n// SELLING with stock and a price, or BUYING with escrow for at least one more and room for it. `cap` is its stock's\n// ceiling, VENDING_STACKS stacks of its item (storage-rules.mjs vendingCap): this file does not know stack limits.\nexport function vendingActive(v, cap) {\n  if (!v || !v.item || !priceOk(v.price)) return false;\n  if (v.mode === 'sell') return (v.stock | 0) > 0;\n  if (v.mode === 'buy') return (v.want | 0) > 0 && (v.escrow | 0) >= v.price && (v.stock | 0) < (cap | 0);\n  return false;\n}\n// …and whether it holds anything a break would destroy: stock, or tokens in escrow. Such a machine will not break\n// (the owner: \"Close and empty it first\").\nexport const vendingHolds = (v) => !!v && ((v.stock | 0) > 0 || (v.escrow | 0) > 0);\nexport const VENDING_HOLDS = 'Close and empty it first.';\n\n// ---- PRICES AND THE FEE --------------------------------------------------------------------------------------------\nexport const priceOk = (p) => Number.isInteger(p) && p >= PRICE_MIN && p <= PRICE_MAX;\nexport function priceProblem(p) {\n  if (!Number.isInteger(p)) return 'A price is a whole number of tokens.';\n  if (p < PRICE_MIN || p > PRICE_MAX) return `A price is ${PRICE_MIN} to ${PRICE_MAX.toLocaleString('en-US')} tokens an item.`;\n  return null;\n}\n// THE MARKETPLACE'S 5%, BURNED, on what changes hands in one trade: N items at the price. Rounded as the marketplace\n// rounds it (Math.round), so a trade under ten tokens pays none, exactly as a cheap world sale would.\nexport const feeOf = (total) => Math.round(Math.max(0, total) * FEE_PCT);\nexport const netOf = (total) => Math.max(0, total) - feeOf(total);\n// THE HOLD ON BOUGHT TOKENS (payments-core.mjs marketHold, PAY-09), worded for a machine: tokens bought in the last week\n// may not be paid to another player, here as on the marketplace. `hold` is { held, releaseMs } (marketplace.js holdOf).\nexport function vendingHoldProblem(balance, total, hold, days = 7) {\n  if (!hold || !(hold.held > 0) || balance - hold.held >= total) return null;\n  return `Tokens bought in the last ${days} days can't be paid to other players yet: ${Math.round(hold.held)} of yours are on hold until `\n       + `${new Date(hold.releaseMs).toISOString().slice(0, 10)}. They work everywhere else in the game now.`;\n}\nexport const DISPUTED = 'This account can\\'t trade while a card payment on it is disputed.';\n\n// A crate's name: printable, trimmed, at most LABEL_MAX, or null to clear it.\nexport function cleanLabel(s) {\n  if (s == null) return null;\n  const t = String(s).replace(/[\\u0000-\\u001f\\u007f<>]/g, '').replace(/\\s+/g, ' ').trim().slice(0, LABEL_MAX).trim();\n  return t || null;\n}\n\n// ---- THE PUBLIC SUMMARY ------------------------------------------------------------------------------------------\n// From a record as the server holds it (names in memory; storage-rules.mjs readCrate / readVending), the line written\n// into the chunk document. encodeSummary turns its item into an id for storing, decodeSummary back.\n// A DISPLAY CASE's line also names what it shows (`i`, its one stack's item; encodeSummary stores it as an id), so every\n// player on the world sees it behind the glass. `name` is what stands there (the case, or any crate: no `i` then).\nexport function crateSummary(c, name) {\n  let u = 0, first = null; for (const s of (c && c.slots) || []) if (s) { u++; if (!first) first = s; }\n  const out = { k: 'c', u, l: (c && c.label) || null, r: (c && c.rev) | 0 };\n  if (name != null && isDisplayCaseName(name)) {\n    out.i = first && typeof first.n === 'string' ? first.n : null;\n    // …and A TROPHY's animal (Oct 29: its per-item state x.sp, tool-tiers.mjs normX), so whoever passes can be shown which.\n    if (first && first.x && typeof first.x.sp === 'string') out.s = first.x.sp;\n  }\n  return out;\n}\nexport function vendingSummary(v, cap) {\n  return { k: 'v', on: vendingActive(v, cap), md: v && v.mode === 'buy' ? 'buy' : 'sell', i: (v && v.item && v.item.n) || null,\n           p: v && priceOk(v.price) ? v.price : null, n: v ? (v.mode === 'buy' ? Math.max(0, v.want | 0) : Math.max(0, v.stock | 0)) : 0,\n           o: (v && v.ownerIgn) || null, h: vendingHolds(v), r: (v && v.rev) | 0 };\n}\nexport const encodeSummary = (s) => (s && s.i != null ? { ...s, i: encodeItem(s.i) } : s);\n// …and a line that is not storage at all (vessels phase 2, Oct 12; vessel-life.mjs): a Suit Dock's { k: 'k', p, c, t }\n// (public while p is 1; on a world, its bank c at the moment t), carried by the same chunk field so the same listener hands\n// it to the renderer and the page. (An Airlock Door's { k: 'd', o } went with the door, Oct 13: vessels have no insides.)\n// …and a DOOR's { k: 'd', f, o } again (doors.mjs, Oct 20): its facing f (0..3) and open while o is 1, at its base's cell.\nexport function decodeSummary(s) {\n  if (!s || typeof s !== 'object' || (s.k !== 'c' && s.k !== 'v' && s.k !== 'k' && s.k !== 'd')) return null;\n  if (s.k === 'd') return { k: 'd', f: Number.isInteger(s.f) && s.f >= 0 && s.f <= 3 ? s.f : 0, o: s.o ? 1 : 0 };\n  return s.i != null ? { ...s, i: decodeItem(s.i) } : s;\n}\n\n// WHAT THE RENDERER DRAWS, as a short key (one atlas texture per key: system-view.js machineAtlasTexture). A crate with no\n// summary yet is empty and a vending machine with none is dark, which is what a freshly placed one is.\nexport function stateKeyOf(name, sum) {\n  if (isCrateName(name)) { const g = crateGauge(sum && sum.k === 'c' ? sum.u : 0, crateSlotsOf(name)); return 'g' + g.level + g.colour; }\n  if (isCrateSide(name)) return 'g0N';\n  if (isVendingName(name)) return sum && sum.k === 'v' && sum.on ? 'on' : 'off';\n  return '';\n}\n// …and the state machine-icons.mjs paints from that key: { fill, gaugeColour } for a crate, { dark } for a vending machine.\n// A TWO-KUBE MACHINE'S HALF (Oct 21) adds ':' and its part after the state: a Cargo Crate's half 'L' (the base, the\n// placer's left) or 'R' (its side), where its seam lies on the front tile ('a' at u 0, 'b' at u 1) and on the top tile\n// (0 u 1, 1 u 0, 2 v 1, 3 v 0), and 'x' when its front faces the cell's first tangent (machine-icons.mjs st.swap):\n// 'g5N:Lb2x'. A Locker's base is 'B', its upper half 'U', each with 'x' after it when it faces the first tangent ('Bx', 'Ux')\n// (system-view.js works the parts out from the shader's own face mapping; this file only spells and reads them).\nexport function wideKey(gaugeKey, half, frontSeam, topSeam, swap) { return gaugeKey + ':' + half + frontSeam + topSeam + (swap ? 'x' : ''); }\nexport function paintStateOf(key) {\n  const k = String(key || '');\n  const w = /^g(\\d)([NAR]):([LR])([ab])([0-3])(x?)$/.exec(k);\n  if (w) return { fill: Number(w[1]) / GAUGE_STEPS, gaugeColour: w[2], dark: false, half: w[3], frontSeam: w[4], topSeam: Number(w[5]), swap: !!w[6] };\n  const u = /^([BU])(x?)$/.exec(k);\n  if (u) return { fill: 0, dark: false, part: u[1], swap: !!u[2] };\n  const m = /^g(\\d)([NAR])$/.exec(k);\n  if (m) return { fill: Number(m[1]) / GAUGE_STEPS, gaugeColour: m[2], dark: false };\n  if (key === 'off') return { fill: 0, dark: true };\n  return { fill: 0, dark: false };\n}\n\n// ---- WORDS -------------------------------------------------------------------------------------------------------\nconst plural = (n, one, many) => n + ' ' + (n === 1 ? one : (many || one + 's'));\nexport const tokensText = (n) => plural(Math.round(n), 'token');\n// THE CROSSHAIR'S PILL, its second line (the owner: the crate's name \"shows in the crate's hover tip\"; a vending\n// machine's \"names its owner, item, price and mode\").\nexport function machineTip(name, sum) {\n  if (isDisplayCaseName(name)) return sum && sum.k === 'c' && sum.i ? 'Showing ' + sum.i : 'Empty';\n  if (isCrateName(name)) {\n    const u = sum && sum.k === 'c' ? sum.u | 0 : 0;\n    return [(sum && sum.l) || null, `${u} of ${crateSlotsOf(name)} slots`].filter(Boolean).join(' · ');\n  }\n  if (isVendingName(name)) {\n    if (!sum || sum.k !== 'v' || !sum.i) return 'Not set up';\n    const what = (sum.md === 'buy' ? 'Buying ' : 'Selling ') + sum.i;\n    const price = sum.p ? tokensText(sum.p) + ' each' : 'no price';\n    const left = sum.on ? (sum.md === 'buy' ? `wants ${sum.n}` : `${sum.n} left`) : (sum.md === 'buy' ? 'not buying' : 'sold out');\n    return [what, price, left, sum.o ? 'by ' + sum.o : null].filter(Boolean).join(' · ');\n  }\n  return '';\n}\n// A WORLD'S OPEN VENDING MACHINES, from its claim (claims/{addr}.shops = { machineKey: { i, p, md, o } }), for its card\n// and the Nearby list (the owner: 'The world card shows \"2 vending machines\" when a world has active ones').\nexport function shopsOf(claim) {\n  const m = claim && claim.shops && typeof claim.shops === 'object' ? claim.shops : null;\n  if (!m) return [];\n  const out = [];\n  for (const key of Object.keys(m).sort()) {\n    const s = m[key];\n    if (!s || typeof s !== 'object') continue;\n    const item = decodeItem(s.i);\n    if (typeof item !== 'string' || !priceOk(s.p)) continue;\n    out.push({ key, item, price: s.p, mode: s.md === 'buy' ? 'buy' : 'sell', owner: typeof s.o === 'string' ? s.o : null });\n  }\n  return out;\n}\nexport const shopCountText = (n) => plural(n, 'vending machine');\nexport function shopLine(s) {\n  return [(s.mode === 'buy' ? 'Buying ' : 'Selling ') + s.item, tokensText(s.price) + ' each', s.owner].filter(Boolean).join(' · ');\n}\n// The claim's public line for one machine, or null when it is not open (and so is listed nowhere).\nexport function shopEntry(v, cap) {\n  if (!vendingActive(v, cap)) return null;\n  return { i: encodeItem(v.item.n), p: v.price, md: v.mode, o: v.ownerIgn || null };\n}\n// WHAT THE OWNER IS TOLD: \"Sold 20 Copper for 57 tokens at Moss Hollow\" (the owner's example), the tokens being what\n// reached their balance after the fee. A purchase into a buy order says what came in and what it cost them.\nexport function saleText(kind, count, item, tokens, where) {\n  const at = where ? ` at ${where}` : '';\n  return kind === 'buy' ? `Bought ${count} ${item} for ${tokensText(tokens)}${at}` : `Sold ${count} ${item} for ${tokensText(tokens)}${at}`;\n}\n// Several sales in one push, summed: \"Sold 34 items for 412 tokens, and bought 20 for 60, at your vending machines\".\nexport function pushSummaryText(p) {\n  const parts = [];\n  if (p && p.soldN > 0) parts.push(`sold ${plural(p.soldN, 'item')} for ${tokensText(p.soldT)}`);\n  if (p && p.boughtN > 0) parts.push(`bought ${plural(p.boughtN, 'item')} for ${tokensText(p.boughtT)}`);\n  if (!parts.length) return null;\n  const s = parts.join(', and ');\n  return s.charAt(0).toUpperCase() + s.slice(1) + ((p.worlds && p.worlds.length === 1) ? ' at ' + p.worlds[0] : ' at your vending machines');\n}\n"],"mappings":"AAwBA,OAAS,WAAY,WAAY,eAAkB,iBACnD,OAAS,OAAQ,aAAgB,cAE1B,aAAM,WAAa,cACb,aAAe,kBAGf,YAAc,GAEd,eAAiB,GACjB,UAAY,GACZ,QAAU,GAEV,UAAY,EACZ,UAAY,IACZ,QAAU,IACV,YAAc,KACd,UAAY,KAEzB,MAAM,KAAQ,GAAO,OAAO,GAAM,UAAY,EAAI,WAAW,CAAC,EAAI,KAa3D,aAAM,UAAY,OAAO,OAAO,CACrC,IAAO,OAAO,OAAO,CAAE,KAAM,KAAM,CAAC,EACpC,MAAS,OAAO,OAAO,CAAE,KAAM,OAAQ,CAAC,EACxC,MAAS,OAAO,OAAO,CAAE,KAAM,OAAQ,CAAC,EACxC,MAAS,OAAO,OAAO,CAAE,KAAM,UAAW,MAAO,CAAE,CAAC,EAIpD,QAAW,OAAO,OAAO,CAAE,KAAM,UAAW,MAAO,EAAG,CAAC,EACvD,OAAU,OAAO,OAAO,CAAE,KAAM,UAAW,MAAO,CAAE,CAAC,EACrD,QAAW,OAAO,OAAO,CAAE,KAAM,OAAQ,CAAC,EAC1C,UAAa,OAAO,OAAO,CAAE,KAAM,OAAQ,CAAC,EAC5C,OAAU,OAAO,OAAO,CAAE,KAAM,UAAW,MAAO,EAAG,CAAC,EACtD,eAAgB,OAAO,OAAO,CAAE,KAAM,UAAW,MAAO,CAAE,CAAC,EAC3D,QAAW,OAAO,OAAO,CAAE,KAAM,OAAQ,CAAC,EAC1C,OAAU,OAAO,OAAO,CAAE,KAAM,QAAS,MAAO,OAAO,OAAO,CAAE,MAAO,UAAW,QAAS,EAAK,CAAC,CAAE,CAAC,EACpG,YAAa,OAAO,OAAO,CAAE,KAAM,QAAS,MAAO,OAAO,OAAO,CAAE,MAAO,UAAW,QAAS,EAAK,CAAC,CAAE,CAAC,EACvG,OAAU,OAAO,OAAO,CAAE,KAAM,OAAQ,CAAC,EAIzC,WAAY,OAAO,OAAO,CAAE,KAAM,OAAQ,CAAC,EAC3C,kBAAmB,OAAO,OAAO,CAAE,KAAM,QAAS,MAAO,OAAO,OAAO,CAAE,MAAO,UAAW,QAAS,EAAK,CAAC,CAAE,CAAC,CAC/G,CAAC,EAEM,gBAAS,gBAAgB,EAAG,CACjC,MAAM,EAAI,KAAK,CAAC,EAChB,OAAO,GAAK,OAAO,UAAU,eAAe,KAAK,UAAW,CAAC,EAAI,EAAI,IACvE,CACO,aAAM,gBAAmB,GAAM,CAAE,MAAM,EAAI,gBAAgB,CAAC,EAAG,OAAO,EAAI,UAAU,CAAC,EAAE,KAAO,IAAM,EAC9F,UAAa,GAAM,gBAAgB,CAAC,IAAM,MAI1C,gBAAkB,kBAClB,iBAAoB,GAAM,KAAK,CAAC,IAAM,gBACtC,mBAAqB,0EAC3B,gBAAS,iBAAiB,EAAG,EAAG,EAAG,GAAI,GAAI,OAAQ,CACxD,MAAM,GAAK,OAAO,EAAG,EAAG,EAAG,MAAM,EACjC,OAAO,KAAO,GAAG,GAAK,KAAO,CAAC,GAAG,CACnC,CAEO,aAAM,iBAAoB,GAAM,CAAE,MAAM,EAAI,gBAAgB,CAAC,EAAG,OAAO,GAAK,UAAU,CAAC,EAAE,MAAQ,CAAE,GAAG,UAAU,CAAC,EAAE,KAAM,EAAI,IAAM,EAInI,gBAAS,aAAa,EAAG,CAC9B,MAAM,EAAI,KAAK,CAAC,EAChB,GAAI,IAAM,WAAY,OAAO,YAC7B,MAAM,EAAI,GAAK,OAAO,UAAU,eAAe,KAAK,UAAW,CAAC,EAAI,UAAU,CAAC,EAAI,KACnF,OAAO,IAAM,EAAE,OAAS,WAAa,EAAE,OAAS,WAAa,EAAE,MAAQ,CACzE,CAEO,aAAM,YAAe,GAAM,aAAa,CAAC,EAAI,EACvC,cAAiB,GAAM,KAAK,CAAC,IAAM,aACnC,iBAAoB,GAAM,YAAY,CAAC,GAAK,cAAc,CAAC,EAO3D,aAAe,eACf,kBAAqB,GAAM,KAAK,CAAC,IAAM,aAG7C,gBAAS,kBAAkB,EAAG,EAAG,EAAG,GAAI,GAAI,OAAQ,CACzD,MAAM,GAAK,OAAO,EAAG,EAAG,EAAG,MAAM,EACjC,GAAI,KAAO,GAAG,EAAG,OAAO,KACxB,MAAM,IAAM,GAAG,EAAI,GAAK,EACxB,OAAO,KAAO,GAAM,GAAK,EAAI,EAAI,EAAM,GAAK,EAAI,EAAI,CACtD,CAIO,aAAM,YAAc,SACd,aAAe,eACf,aAAgB,GAAM,KAAK,CAAC,IAAM,YAQlC,WAAa,mBACb,YAAe,GAAM,IAAM,WAC3B,YAAe,GAAM,KAAK,CAAC,IAAM,WACjC,WAAc,GAAM,YAAY,CAAC,GAAK,YAAY,CAAC,EACnD,aAAe,oFAGrB,gBAAS,aAAa,EAAG,EAAG,EAAG,EAAG,OAAQ,CAC/C,MAAM,GAAK,OAAO,EAAG,EAAG,EAAG,MAAM,EAAG,IAAM,GAAG,EAAI,GAAK,EAAG,IAAM,GAAG,EAAI,GAAK,EACrE,KAAO,EAAI,GAAK,EAAI,GAAK,GAAI,KAAQ,EAAI,EAAK,GAAK,EAAG,IAAM,MAAQ,GAAK,GAAK,GAC9E,KAAO,IAAM,GAAG,EAAI,GAAK,IAAM,EAAI,EAAI,GAC7C,MAAO,CAAE,EAAG,IAAK,EAAG,GAAG,EAAI,KAAO,IAAK,GAAI,IAAK,IAAK,CACvD,CACO,gBAAS,cAAc,EAAG,EAAG,EAAG,EAAG,OAAQ,CAChD,GAAI,CAAC,SAAS,CAAC,EAAG,OAAO,KACzB,MAAM,EAAI,aAAa,EAAG,EAAG,EAAG,EAAG,MAAM,EAAG,EAAI,CAAC,EAAG,EAAG,CAAC,EACxD,SAAE,EAAE,CAAC,GAAK,EAAE,EACL,CACT,CAGO,gBAAS,gBAAgB,EAAG,EAAG,EAAG,OAAQ,SAAU,OAAQ,CACjE,MAAM,GAAK,OAAO,EAAG,EAAG,EAAG,MAAM,EACjC,UAAW,IAAK,CAAC,EAAG,EAAG,CAAC,EAAK,GAAI,IAAM,GAAG,EACxC,UAAW,IAAK,CAAC,EAAG,EAAE,EAAG,CACvB,MAAM,EAAI,CAAC,EAAG,EAAG,CAAC,EAClB,GADqB,EAAE,CAAC,GAAK,EACzB,CAAC,YAAY,OAAO,EAAE,CAAC,EAAG,EAAE,CAAC,EAAG,EAAE,CAAC,CAAC,CAAC,EAAG,SAC5C,MAAM,GAAK,cAAc,EAAE,CAAC,EAAG,EAAE,CAAC,EAAG,EAAE,CAAC,EAAG,SAAS,EAAE,CAAC,EAAG,EAAE,CAAC,EAAG,EAAE,CAAC,CAAC,EAAG,MAAM,EAC7E,GAAI,IAAM,GAAG,CAAC,IAAM,GAAK,GAAG,CAAC,IAAM,GAAK,GAAG,CAAC,IAAM,EAAG,OAAO,CAC9D,CACF,OAAO,IACT,CAIO,aAAM,WAAa,CAAC,QAAS,WAAa,QAAU,IAAM,SACpD,aAAe,CAAC,QAAS,QAAS,WAAa,QAAU,IAAM,WAAW,QAAS,QAAQ,EAO3F,aAAe,mDACrB,gBAAS,aAAa,MAAO,IAAK,CACvC,OAAK,IACD,CAAC,OACD,MAAM,QAAU,IAAY,GACzB,MAAM,QAAQ,MAAM,QAAQ,GAAK,MAAM,SAAS,SAAS,GAAG,EAHlD,EAInB,CAMO,gBAAS,cAAc,MAAO,IAAK,CAAE,MAAO,CAAC,CAAC,GAAK,CAOnD,aAAM,YAAc,EACd,aAAe,GACf,YAAc,GAEpB,gBAAS,WAAW,KAAM,IAAM,YAAa,CAClD,MAAM,EAAI,IAAM,EAAI,IAAM,EAAI,YACxB,EAAI,KAAK,IAAI,EAAG,KAAK,IAAI,EAAG,KAAK,MAAM,OAAO,IAAI,GAAK,CAAC,CAAC,CAAC,EAC1D,KAAO,GAAK,EACZ,MAAQ,KAAO,YAAc,EAAI,KAAK,IAAI,YAAc,EAAG,KAAK,KAAK,EAAI,YAAc,CAAC,CAAC,EAAI,EACnG,MAAO,CAAE,KAAM,EAAG,KAAM,MAAO,IAAK,MAAQ,aAAe,YAAa,OAAQ,KAAO,IAAM,GAAK,KAAK,KAAK,EAAI,EAAI,CAAC,EAAI,IAAM,GAAI,CACrI,CAKO,gBAAS,cAAc,EAAG,IAAK,CACpC,MAAI,CAAC,GAAK,CAAC,EAAE,MAAQ,CAAC,QAAQ,EAAE,KAAK,EAAU,GAC3C,EAAE,OAAS,QAAgB,EAAE,MAAQ,GAAK,EAC1C,EAAE,OAAS,OAAe,EAAE,KAAO,GAAK,IAAM,EAAE,OAAS,IAAM,EAAE,QAAU,EAAE,MAAQ,IAAM,IAAM,GAC9F,EACT,CAGO,aAAM,aAAgB,GAAM,CAAC,CAAC,KAAO,EAAE,MAAQ,GAAK,IAAM,EAAE,OAAS,GAAK,GACpE,cAAgB,4BAGhB,QAAW,GAAM,OAAO,UAAU,CAAC,GAAK,GAAK,WAAa,GAAK,UACrE,gBAAS,aAAa,EAAG,CAC9B,OAAK,OAAO,UAAU,CAAC,EACnB,EAAI,WAAa,EAAI,UAAkB,cAAc,SAAS,OAAO,UAAU,eAAe,OAAO,CAAC,mBACnG,KAF0B,sCAGnC,CAGO,aAAM,MAAS,OAAU,KAAK,MAAM,KAAK,IAAI,EAAG,KAAK,EAAI,OAAO,EAC1D,MAAS,OAAU,KAAK,IAAI,EAAG,KAAK,EAAI,MAAM,KAAK,EAGzD,gBAAS,mBAAmB,QAAS,MAAO,KAAM,KAAO,EAAG,CACjE,MAAI,CAAC,MAAQ,EAAE,KAAK,KAAO,IAAM,QAAU,KAAK,MAAQ,MAAc,KAC/D,6BAA6B,IAAI,6CAA6C,KAAK,MAAM,KAAK,IAAI,CAAC,+BAChG,IAAI,KAAK,KAAK,SAAS,EAAE,YAAY,EAAE,MAAM,EAAG,EAAE,CAAC,8CAC/D,CACO,aAAM,SAAW,mEAGjB,gBAAS,WAAW,EAAG,CAC5B,OAAI,GAAK,KAAa,KACZ,OAAO,CAAC,EAAE,QAAQ,2BAA4B,EAAE,EAAE,QAAQ,OAAQ,GAAG,EAAE,KAAK,EAAE,MAAM,EAAG,SAAS,EAAE,KAAK,GACrG,IACd,CAOO,gBAAS,aAAa,EAAG,KAAM,CACpC,IAAI,EAAI,EAAG,MAAQ,KAAM,UAAW,KAAM,GAAK,EAAE,OAAU,CAAC,EAAO,IAAK,IAAU,QAAO,MAAQ,IACjG,MAAM,IAAM,CAAE,EAAG,IAAK,EAAG,EAAI,GAAK,EAAE,OAAU,KAAM,GAAI,GAAK,EAAE,KAAO,CAAE,EACxE,OAAI,MAAQ,MAAQ,kBAAkB,IAAI,IACxC,IAAI,EAAI,OAAS,OAAO,MAAM,GAAM,SAAW,MAAM,EAAI,KAErD,OAAS,MAAM,GAAK,OAAO,MAAM,EAAE,IAAO,WAAU,IAAI,EAAI,MAAM,EAAE,KAEnE,GACT,CACO,gBAAS,eAAe,EAAG,IAAK,CACrC,MAAO,CAAE,EAAG,IAAK,GAAI,cAAc,EAAG,GAAG,EAAG,GAAI,GAAK,EAAE,OAAS,MAAQ,MAAQ,OAAQ,EAAI,GAAK,EAAE,MAAQ,EAAE,KAAK,GAAM,KAC/G,EAAG,GAAK,QAAQ,EAAE,KAAK,EAAI,EAAE,MAAQ,KAAM,EAAG,EAAK,EAAE,OAAS,MAAQ,KAAK,IAAI,EAAG,EAAE,KAAO,CAAC,EAAI,KAAK,IAAI,EAAG,EAAE,MAAQ,CAAC,EAAK,EAC5H,EAAI,GAAK,EAAE,UAAa,KAAM,EAAG,aAAa,CAAC,EAAG,GAAI,GAAK,EAAE,KAAO,CAAE,CACjF,CACO,aAAM,cAAiB,GAAO,GAAK,EAAE,GAAK,KAAO,CAAE,GAAG,EAAG,EAAG,WAAW,EAAE,CAAC,CAAE,EAAI,EAKhF,gBAAS,cAAc,EAAG,CAC/B,MAAI,CAAC,GAAK,OAAO,GAAM,UAAa,EAAE,IAAM,KAAO,EAAE,IAAM,KAAO,EAAE,IAAM,KAAO,EAAE,IAAM,IAAa,KAClG,EAAE,IAAM,IAAY,CAAE,EAAG,IAAK,EAAG,OAAO,UAAU,EAAE,CAAC,GAAK,EAAE,GAAK,GAAK,EAAE,GAAK,EAAI,EAAE,EAAI,EAAG,EAAG,EAAE,EAAI,EAAI,CAAE,EACtG,EAAE,GAAK,KAAO,CAAE,GAAG,EAAG,EAAG,WAAW,EAAE,CAAC,CAAE,EAAI,CACtD,CAIO,gBAAS,WAAW,KAAM,IAAK,CACpC,GAAI,YAAY,IAAI,EAAG,CAAE,MAAM,EAAI,WAAW,KAAO,IAAI,IAAM,IAAM,IAAI,EAAI,EAAG,aAAa,IAAI,CAAC,EAAG,MAAO,IAAM,EAAE,MAAQ,EAAE,MAAQ,CACtI,OAAI,YAAY,IAAI,EAAU,MAC1B,cAAc,IAAI,EAAU,KAAO,IAAI,IAAM,KAAO,IAAI,GAAK,KAAO,MACjE,EACT,CAOO,gBAAS,QAAQ,SAAU,KAAM,UAAW,QAAS,KAAM,CAAE,OAAO,SAAW,IAAM,KAAO,UAAY,SAAW,KAAO,IAAM,GAAK,CACrI,gBAAS,aAAa,IAAK,CAChC,MAAM,EAAI,OAAO,KAAO,EAAE,EACpB,EAAI,yCAAyC,KAAK,CAAC,EACzD,GAAI,EAAG,MAAO,CAAE,KAAM,OAAO,EAAE,CAAC,CAAC,EAAI,YAAa,YAAa,EAAE,CAAC,EAAG,KAAM,GAAO,KAAM,EAAE,CAAC,EAAG,UAAW,EAAE,CAAC,EAAG,QAAS,OAAO,EAAE,CAAC,CAAC,EAAG,KAAM,CAAC,CAAC,EAAE,CAAC,CAAE,EACnJ,MAAM,EAAI,eAAe,KAAK,CAAC,EAC/B,GAAI,EAAG,MAAO,CAAE,KAAM,EAAG,KAAM,GAAO,KAAM,EAAE,CAAC,EAAG,KAAM,CAAC,CAAC,EAAE,CAAC,CAAE,EAC/D,MAAM,EAAI,iBAAiB,KAAK,CAAC,EACjC,OAAI,EAAU,CAAE,KAAM,OAAO,EAAE,CAAC,CAAC,EAAI,YAAa,YAAa,EAAE,CAAC,EAAG,KAAM,EAAM,EAC7E,MAAQ,MAAc,CAAE,KAAM,EAAG,KAAM,EAAK,EACzC,CAAE,KAAM,EAAG,KAAM,EAAM,CAChC,CAGA,MAAM,OAAS,CAAC,EAAG,IAAK,OAAS,EAAI,KAAO,IAAM,EAAI,IAAO,MAAQ,IAAM,KACpE,aAAM,WAAc,GAAM,OAAO,KAAK,MAAM,CAAC,EAAG,OAAO,EAGvD,gBAAS,WAAW,KAAM,IAAK,CACpC,GAAI,kBAAkB,IAAI,EAAG,OAAO,KAAO,IAAI,IAAM,KAAO,IAAI,EAAI,WAAa,IAAI,EAAI,QACzF,GAAI,YAAY,IAAI,EAAG,CACrB,MAAM,EAAI,KAAO,IAAI,IAAM,IAAM,IAAI,EAAI,EAAI,EAC7C,MAAO,CAAE,KAAO,IAAI,GAAM,KAAM,GAAG,CAAC,OAAO,aAAa,IAAI,CAAC,QAAQ,EAAE,OAAO,OAAO,EAAE,KAAK,KAAK,CACnG,CACA,GAAI,cAAc,IAAI,EAAG,CACvB,GAAI,CAAC,KAAO,IAAI,IAAM,KAAO,CAAC,IAAI,EAAG,MAAO,aAC5C,MAAM,MAAQ,IAAI,KAAO,MAAQ,UAAY,YAAc,IAAI,EACzD,MAAQ,IAAI,EAAI,WAAW,IAAI,CAAC,EAAI,QAAU,WAC9C,KAAO,IAAI,GAAM,IAAI,KAAO,MAAQ,SAAS,IAAI,CAAC,GAAK,GAAG,IAAI,CAAC,QAAY,IAAI,KAAO,MAAQ,aAAe,WACnH,MAAO,CAAC,KAAM,MAAO,KAAM,IAAI,EAAI,MAAQ,IAAI,EAAI,IAAI,EAAE,OAAO,OAAO,EAAE,KAAK,KAAK,CACrF,CACA,MAAO,EACT,CAGO,gBAAS,QAAQ,MAAO,CAC7B,MAAM,EAAI,OAAS,MAAM,OAAS,OAAO,MAAM,OAAU,SAAW,MAAM,MAAQ,KAClF,GAAI,CAAC,EAAG,MAAO,CAAC,EAChB,MAAM,IAAM,CAAC,EACb,UAAW,OAAO,OAAO,KAAK,CAAC,EAAE,KAAK,EAAG,CACvC,MAAM,EAAI,EAAE,GAAG,EACf,GAAI,CAAC,GAAK,OAAO,GAAM,SAAU,SACjC,MAAM,KAAO,WAAW,EAAE,CAAC,EACvB,OAAO,MAAS,UAAY,CAAC,QAAQ,EAAE,CAAC,GAC5C,IAAI,KAAK,CAAE,IAAK,KAAM,MAAO,EAAE,EAAG,KAAM,EAAE,KAAO,MAAQ,MAAQ,OAAQ,MAAO,OAAO,EAAE,GAAM,SAAW,EAAE,EAAI,IAAK,CAAC,CACxH,CACA,OAAO,GACT,CACO,aAAM,cAAiB,GAAM,OAAO,EAAG,iBAAiB,EACxD,gBAAS,SAAS,EAAG,CAC1B,MAAO,EAAE,EAAE,OAAS,MAAQ,UAAY,YAAc,EAAE,KAAM,WAAW,EAAE,KAAK,EAAI,QAAS,EAAE,KAAK,EAAE,OAAO,OAAO,EAAE,KAAK,KAAK,CAClI,CAEO,gBAAS,UAAU,EAAG,IAAK,CAChC,OAAK,cAAc,EAAG,GAAG,EAClB,CAAE,EAAG,WAAW,EAAE,KAAK,CAAC,EAAG,EAAG,EAAE,MAAO,GAAI,EAAE,KAAM,EAAG,EAAE,UAAY,IAAK,EAD7C,IAErC,CAGO,gBAAS,SAAS,KAAM,MAAO,KAAM,OAAQ,MAAO,CACzD,MAAM,GAAK,MAAQ,OAAO,KAAK,GAAK,GACpC,OAAO,OAAS,MAAQ,UAAU,KAAK,IAAI,IAAI,QAAQ,WAAW,MAAM,CAAC,GAAG,EAAE,GAAK,QAAQ,KAAK,IAAI,IAAI,QAAQ,WAAW,MAAM,CAAC,GAAG,EAAE,EACzI,CAEO,gBAAS,gBAAgB,EAAG,CACjC,MAAM,MAAQ,CAAC,EAGf,GAFI,GAAK,EAAE,MAAQ,GAAG,MAAM,KAAK,QAAQ,OAAO,EAAE,MAAO,MAAM,CAAC,QAAQ,WAAW,EAAE,KAAK,CAAC,EAAE,EACzF,GAAK,EAAE,QAAU,GAAG,MAAM,KAAK,UAAU,OAAO,EAAE,QAAS,MAAM,CAAC,QAAQ,WAAW,EAAE,OAAO,CAAC,EAAE,EACjG,CAAC,MAAM,OAAQ,OAAO,KAC1B,MAAM,EAAI,MAAM,KAAK,QAAQ,EAC7B,OAAO,EAAE,OAAO,CAAC,EAAE,YAAY,EAAI,EAAE,MAAM,CAAC,GAAM,EAAE,QAAU,EAAE,OAAO,SAAW,EAAK,OAAS,EAAE,OAAO,CAAC,EAAI,4BAChH","names":[],"file":"storage-machines.mjs"}