<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://recipedius.com/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Janine</id>
	<title>Recipedius - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://recipedius.com/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Janine"/>
	<link rel="alternate" type="text/html" href="https://recipedius.com/index.php/Special:Contributions/Janine"/>
	<updated>2026-11-02T04:32:04Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.43.11</generator>
	<entry>
		<id>https://recipedius.com/index.php?title=Category:Recipes_by_tag&amp;diff=78</id>
		<title>Category:Recipes by tag</title>
		<link rel="alternate" type="text/html" href="https://recipedius.com/index.php?title=Category:Recipes_by_tag&amp;diff=78"/>
		<updated>2026-09-09T19:58:53Z</updated>

		<summary type="html">&lt;p&gt;Janine: Recipedius seed&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;One category per tag used in [[Template:Recipe]].&lt;/div&gt;</summary>
		<author><name>Janine</name></author>
	</entry>
	<entry>
		<id>https://recipedius.com/index.php?title=Category:Cake&amp;diff=77</id>
		<title>Category:Cake</title>
		<link rel="alternate" type="text/html" href="https://recipedius.com/index.php?title=Category:Cake&amp;diff=77"/>
		<updated>2026-09-09T19:58:53Z</updated>

		<summary type="html">&lt;p&gt;Janine: Recipedius seed&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Recipes tagged &amp;quot;cake&amp;quot;. [[Category:Recipes by tag]]&lt;/div&gt;</summary>
		<author><name>Janine</name></author>
	</entry>
	<entry>
		<id>https://recipedius.com/index.php?title=Category:Side&amp;diff=76</id>
		<title>Category:Side</title>
		<link rel="alternate" type="text/html" href="https://recipedius.com/index.php?title=Category:Side&amp;diff=76"/>
		<updated>2026-09-09T19:58:53Z</updated>

		<summary type="html">&lt;p&gt;Janine: Recipedius seed&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Recipes tagged &amp;quot;side&amp;quot;. [[Category:Recipes by tag]]&lt;/div&gt;</summary>
		<author><name>Janine</name></author>
	</entry>
	<entry>
		<id>https://recipedius.com/index.php?title=Category:Vegetarian&amp;diff=75</id>
		<title>Category:Vegetarian</title>
		<link rel="alternate" type="text/html" href="https://recipedius.com/index.php?title=Category:Vegetarian&amp;diff=75"/>
		<updated>2026-09-09T19:58:53Z</updated>

		<summary type="html">&lt;p&gt;Janine: Recipedius seed&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Recipes tagged &amp;quot;vegetarian&amp;quot;. [[Category:Recipes by tag]]&lt;/div&gt;</summary>
		<author><name>Janine</name></author>
	</entry>
	<entry>
		<id>https://recipedius.com/index.php?title=Category:Soup&amp;diff=74</id>
		<title>Category:Soup</title>
		<link rel="alternate" type="text/html" href="https://recipedius.com/index.php?title=Category:Soup&amp;diff=74"/>
		<updated>2026-09-09T19:58:53Z</updated>

		<summary type="html">&lt;p&gt;Janine: Recipedius seed&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Recipes tagged &amp;quot;soup&amp;quot;. [[Category:Recipes by tag]]&lt;/div&gt;</summary>
		<author><name>Janine</name></author>
	</entry>
	<entry>
		<id>https://recipedius.com/index.php?title=Category:No-cook&amp;diff=73</id>
		<title>Category:No-cook</title>
		<link rel="alternate" type="text/html" href="https://recipedius.com/index.php?title=Category:No-cook&amp;diff=73"/>
		<updated>2026-09-09T19:58:53Z</updated>

		<summary type="html">&lt;p&gt;Janine: Recipedius seed&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Recipes tagged &amp;quot;no-cook&amp;quot;. [[Category:Recipes by tag]]&lt;/div&gt;</summary>
		<author><name>Janine</name></author>
	</entry>
	<entry>
		<id>https://recipedius.com/index.php?title=Category:Dressing&amp;diff=72</id>
		<title>Category:Dressing</title>
		<link rel="alternate" type="text/html" href="https://recipedius.com/index.php?title=Category:Dressing&amp;diff=72"/>
		<updated>2026-09-09T19:58:53Z</updated>

		<summary type="html">&lt;p&gt;Janine: Recipedius seed&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Recipes tagged &amp;quot;dressing&amp;quot;. [[Category:Recipes by tag]]&lt;/div&gt;</summary>
		<author><name>Janine</name></author>
	</entry>
	<entry>
		<id>https://recipedius.com/index.php?title=Category:Quick_bread&amp;diff=71</id>
		<title>Category:Quick bread</title>
		<link rel="alternate" type="text/html" href="https://recipedius.com/index.php?title=Category:Quick_bread&amp;diff=71"/>
		<updated>2026-09-09T19:58:53Z</updated>

		<summary type="html">&lt;p&gt;Janine: Recipedius seed&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Recipes tagged &amp;quot;quick bread&amp;quot;. [[Category:Recipes by tag]]&lt;/div&gt;</summary>
		<author><name>Janine</name></author>
	</entry>
	<entry>
		<id>https://recipedius.com/index.php?title=Category:Roast&amp;diff=70</id>
		<title>Category:Roast</title>
		<link rel="alternate" type="text/html" href="https://recipedius.com/index.php?title=Category:Roast&amp;diff=70"/>
		<updated>2026-09-09T19:58:53Z</updated>

		<summary type="html">&lt;p&gt;Janine: Recipedius seed&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Recipes tagged &amp;quot;roast&amp;quot;. [[Category:Recipes by tag]]&lt;/div&gt;</summary>
		<author><name>Janine</name></author>
	</entry>
	<entry>
		<id>https://recipedius.com/index.php?title=Category:Dinner&amp;diff=69</id>
		<title>Category:Dinner</title>
		<link rel="alternate" type="text/html" href="https://recipedius.com/index.php?title=Category:Dinner&amp;diff=69"/>
		<updated>2026-09-09T19:58:53Z</updated>

		<summary type="html">&lt;p&gt;Janine: Recipedius seed&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Recipes tagged &amp;quot;dinner&amp;quot;. [[Category:Recipes by tag]]&lt;/div&gt;</summary>
		<author><name>Janine</name></author>
	</entry>
	<entry>
		<id>https://recipedius.com/index.php?title=Category:Cookie&amp;diff=68</id>
		<title>Category:Cookie</title>
		<link rel="alternate" type="text/html" href="https://recipedius.com/index.php?title=Category:Cookie&amp;diff=68"/>
		<updated>2026-09-09T19:58:52Z</updated>

		<summary type="html">&lt;p&gt;Janine: Recipedius seed&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Recipes tagged &amp;quot;cookie&amp;quot;. [[Category:Recipes by tag]]&lt;/div&gt;</summary>
		<author><name>Janine</name></author>
	</entry>
	<entry>
		<id>https://recipedius.com/index.php?title=Category:Griddle&amp;diff=67</id>
		<title>Category:Griddle</title>
		<link rel="alternate" type="text/html" href="https://recipedius.com/index.php?title=Category:Griddle&amp;diff=67"/>
		<updated>2026-09-09T19:58:52Z</updated>

		<summary type="html">&lt;p&gt;Janine: Recipedius seed&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Recipes tagged &amp;quot;griddle&amp;quot;. [[Category:Recipes by tag]]&lt;/div&gt;</summary>
		<author><name>Janine</name></author>
	</entry>
	<entry>
		<id>https://recipedius.com/index.php?title=Category:Breakfast&amp;diff=66</id>
		<title>Category:Breakfast</title>
		<link rel="alternate" type="text/html" href="https://recipedius.com/index.php?title=Category:Breakfast&amp;diff=66"/>
		<updated>2026-09-09T19:58:52Z</updated>

		<summary type="html">&lt;p&gt;Janine: Recipedius seed&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Recipes tagged &amp;quot;breakfast&amp;quot;. [[Category:Recipes by tag]]&lt;/div&gt;</summary>
		<author><name>Janine</name></author>
	</entry>
	<entry>
		<id>https://recipedius.com/index.php?title=Category:Citrus&amp;diff=65</id>
		<title>Category:Citrus</title>
		<link rel="alternate" type="text/html" href="https://recipedius.com/index.php?title=Category:Citrus&amp;diff=65"/>
		<updated>2026-09-09T19:58:52Z</updated>

		<summary type="html">&lt;p&gt;Janine: Recipedius seed&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Recipes tagged &amp;quot;citrus&amp;quot;. [[Category:Recipes by tag]]&lt;/div&gt;</summary>
		<author><name>Janine</name></author>
	</entry>
	<entry>
		<id>https://recipedius.com/index.php?title=Category:Baking&amp;diff=64</id>
		<title>Category:Baking</title>
		<link rel="alternate" type="text/html" href="https://recipedius.com/index.php?title=Category:Baking&amp;diff=64"/>
		<updated>2026-09-09T19:58:52Z</updated>

		<summary type="html">&lt;p&gt;Janine: Recipedius seed&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Recipes tagged &amp;quot;baking&amp;quot;. [[Category:Recipes by tag]]&lt;/div&gt;</summary>
		<author><name>Janine</name></author>
	</entry>
	<entry>
		<id>https://recipedius.com/index.php?title=Category:Dessert&amp;diff=63</id>
		<title>Category:Dessert</title>
		<link rel="alternate" type="text/html" href="https://recipedius.com/index.php?title=Category:Dessert&amp;diff=63"/>
		<updated>2026-09-09T19:58:52Z</updated>

		<summary type="html">&lt;p&gt;Janine: Recipedius seed&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Recipes tagged &amp;quot;dessert&amp;quot;. [[Category:Recipes by tag]]&lt;/div&gt;</summary>
		<author><name>Janine</name></author>
	</entry>
	<entry>
		<id>https://recipedius.com/index.php?title=MediaWiki:Common.css&amp;diff=10</id>
		<title>MediaWiki:Common.css</title>
		<link rel="alternate" type="text/html" href="https://recipedius.com/index.php?title=MediaWiki:Common.css&amp;diff=10"/>
		<updated>2026-09-09T19:58:45Z</updated>

		<summary type="html">&lt;p&gt;Janine: Recipedius seed&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;/* Recipedius styling */&lt;br /&gt;
.rp-infobox { float: right; clear: right; margin: 0 0 1em 1.5em; width: 300px; font-size: 0.92em; }&lt;br /&gt;
.rp-infobox caption { font-weight: bold; font-size: 1.1em; padding: 0.4em; }&lt;br /&gt;
.rp-infobox th { text-align: left; width: 38%; }&lt;br /&gt;
.rp-lede { font-size: 1.15em; margin: 0.5em 0 1em; max-width: 65ch; }&lt;br /&gt;
.rp-qty { font-family: ui-monospace, Menlo, Consolas, monospace; font-size: 0.92em; white-space: nowrap; font-variant-numeric: tabular-nums; }&lt;br /&gt;
.rp-was { text-decoration: line-through; color: #72777d; }&lt;br /&gt;
.rp-prep { color: #54595d; }&lt;br /&gt;
.rp-role { color: #54595d; font-size: 0.9em; }&lt;br /&gt;
.rp-warn { color: #b32424; }&lt;br /&gt;
.rp-note { color: #54595d; max-width: 70ch; }&lt;br /&gt;
.rp-role-tag { color: #6b4fbb; }&lt;br /&gt;
.rp-missing { background: #fef6e7; border-left: 4px solid #edab00; padding: 0.5em 1em; margin: 0.8em 0; }&lt;br /&gt;
.rp-missing-mark { color: #b32424; }&lt;br /&gt;
.rp-conf { white-space: nowrap; font-size: 0.85em; letter-spacing: 0.02em; }&lt;br /&gt;
.rp-conf-high { color: #14866d; }&lt;br /&gt;
.rp-conf-medium { color: #ac6600; }&lt;br /&gt;
.rp-conf-low { color: #b32424; }&lt;br /&gt;
.rp-ingredients, .rp-subs, .rp-sale, .rp-rules { width: 100%; }&lt;br /&gt;
.rp-subs td:nth-child(3) { white-space: normal; width: 18%; }&lt;br /&gt;
.rp-subs td:nth-child(4) { width: 46%; }&lt;br /&gt;
.rp-subs .rp-qty, .rp-rules .rp-qty { white-space: normal; }&lt;br /&gt;
&lt;br /&gt;
/* Cookbook */&lt;br /&gt;
.rp-book { max-width: 820px; }&lt;br /&gt;
.rp-page { background: #fbfaf4; color: #22251c; border: 1px solid #ddd; padding: 40px 48px; margin: 0 0 18px; min-height: 420px; position: relative; box-shadow: 0 2px 8px rgba(0,0,0,0.06); }&lt;br /&gt;
.rp-cover { background: #2e3a2a; color: #f3efd8; text-align: center; display: flex; flex-direction: column; justify-content: center; align-items: center; gap: 12px; min-height: 380px; }&lt;br /&gt;
.rp-orn { width: 44px; height: 44px; border-radius: 50%; border: 2px solid #e2a600; display: grid; place-items: center; font-size: 1.2em; }&lt;br /&gt;
.rp-cover-title { font-size: 2.4em; font-weight: bold; line-height: 1.05; }&lt;br /&gt;
.rp-cover-sub { font-style: italic; opacity: 0.8; }&lt;br /&gt;
.rp-dedication { display: flex; align-items: center; justify-content: center; text-align: center; font-style: italic; font-size: 1.2em; }&lt;br /&gt;
.rp-chapter { display: flex; flex-direction: column; justify-content: center; align-items: center; text-align: center; }&lt;br /&gt;
.rp-chapter-title { font-size: 2em; font-weight: bold; }&lt;br /&gt;
.rp-chap-label { font-size: 0.75em; text-transform: uppercase; letter-spacing: 0.12em; color: #7a7c6e; margin-bottom: 10px; }&lt;br /&gt;
.rp-recipe-title { font-size: 1.7em; font-weight: bold; margin-bottom: 4px; }&lt;br /&gt;
.rp-toc-chapter { font-weight: bold; margin-top: 10px; }&lt;br /&gt;
.rp-toc-row { display: flex; justify-content: space-between; border-bottom: 1px dotted #c9c7b4; padding: 3px 0; }&lt;br /&gt;
.rp-book-cols { display: grid; grid-template-columns: 1fr 1.4fr; gap: 28px; margin-top: 14px; }&lt;br /&gt;
.rp-book-ing { display: grid; grid-template-columns: 5em 1fr; gap: 8px; padding: 2px 0; font-size: 0.95em; }&lt;br /&gt;
.rp-book-method ol { margin-left: 1.2em; }&lt;br /&gt;
.rp-book-foot { margin-top: 18px; font-size: 0.8em; color: #7a7c6e; border-top: 1px solid #ddd; padding-top: 8px; }&lt;br /&gt;
@media (max-width: 720px) { .rp-book-cols { grid-template-columns: 1fr; } .rp-infobox { float: none; width: auto; margin: 0 0 1em; } }&lt;/div&gt;</summary>
		<author><name>Janine</name></author>
	</entry>
	<entry>
		<id>https://recipedius.com/index.php?title=Module:Recipedius&amp;diff=3</id>
		<title>Module:Recipedius</title>
		<link rel="alternate" type="text/html" href="https://recipedius.com/index.php?title=Module:Recipedius&amp;diff=3"/>
		<updated>2026-09-09T19:58:45Z</updated>

		<summary type="html">&lt;p&gt;Janine: Recipedius seed&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;--[[&lt;br /&gt;
  Module:Recipedius&lt;br /&gt;
  The computed layer of Recipedius. Reads ingredient records and substitution rules&lt;br /&gt;
  from Cargo tables and renders recipe pages, the weekly sale ranking, and cookbooks.&lt;br /&gt;
&lt;br /&gt;
  Entry points (all via {{#invoke:Recipedius|fn}} from templates):&lt;br /&gt;
    recipe    - renders a recipe from Template:Recipe args and stores its rows&lt;br /&gt;
    sale      - ranks recipes by how many of their shopping items are on sale&lt;br /&gt;
    cookbook  - renders a printable book from a list of recipe pages&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
local p = {}&lt;br /&gt;
local cargo = mw.ext.cargo&lt;br /&gt;
&lt;br /&gt;
-- ---------------------------------------------------------------- helpers&lt;br /&gt;
&lt;br /&gt;
local FRACTIONS = {&lt;br /&gt;
  { 0.125, &#039;⅛&#039; }, { 0.25, &#039;¼&#039; }, { 1/3, &#039;⅓&#039; }, { 0.375, &#039;⅜&#039; }, { 0.5, &#039;½&#039; },&lt;br /&gt;
  { 0.625, &#039;⅝&#039; }, { 2/3, &#039;⅔&#039; }, { 0.75, &#039;¾&#039; }, { 0.875, &#039;⅞&#039; },&lt;br /&gt;
}&lt;br /&gt;
local FRACTION_CHARS = { [&#039;⅛&#039;]=0.125, [&#039;¼&#039;]=0.25, [&#039;⅓&#039;]=1/3, [&#039;⅜&#039;]=0.375, [&#039;½&#039;]=0.5, [&#039;⅝&#039;]=0.625, [&#039;⅔&#039;]=2/3, [&#039;¾&#039;]=0.75, [&#039;⅞&#039;]=0.875 }&lt;br /&gt;
&lt;br /&gt;
local function trim(s) return mw.text.trim(s or &#039;&#039;) end&lt;br /&gt;
&lt;br /&gt;
-- &amp;quot;1 1/2&amp;quot;, &amp;quot;3/4&amp;quot;, &amp;quot;0.5&amp;quot;, &amp;quot;1 ½&amp;quot; and &amp;quot;¾&amp;quot; all parse.&lt;br /&gt;
local function parseQty(s)&lt;br /&gt;
  s = trim(s)&lt;br /&gt;
  local total, found = 0, false&lt;br /&gt;
  for tok in s:gmatch(&#039;%S+&#039;) do&lt;br /&gt;
    if FRACTION_CHARS[tok] then total = total + FRACTION_CHARS[tok]; found = true&lt;br /&gt;
    else&lt;br /&gt;
      local a, b = tok:match(&#039;^(%d+)/(%d+)$&#039;)&lt;br /&gt;
      if a then total = total + tonumber(a) / tonumber(b); found = true&lt;br /&gt;
      elseif tonumber(tok) then total = total + tonumber(tok); found = true end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
  if found then return total end&lt;br /&gt;
  return nil&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function fmtQty(q)&lt;br /&gt;
  if not q then return &#039;&#039; end&lt;br /&gt;
  local w = math.floor(q + 1e-6)&lt;br /&gt;
  local f = q - w&lt;br /&gt;
  if f &amp;gt; 0.94 then w = w + 1; f = 0 end&lt;br /&gt;
  local fs = &#039;&#039;&lt;br /&gt;
  if f &amp;gt; 0.06 then&lt;br /&gt;
    local best, bd = nil, 1&lt;br /&gt;
    for _, pair in ipairs(FRACTIONS) do&lt;br /&gt;
      local d = math.abs(pair[1] - f)&lt;br /&gt;
      if d &amp;lt; bd then bd = d; best = pair[2] end&lt;br /&gt;
    end&lt;br /&gt;
    if bd &amp;lt; 0.06 then fs = best else fs = string.format(&#039;%.2f&#039;, f):gsub(&#039;^0&#039;, &#039;&#039;) end&lt;br /&gt;
  end&lt;br /&gt;
  if w == 0 then return fs ~= &#039;&#039; and fs or &#039;0&#039; end&lt;br /&gt;
  if fs ~= &#039;&#039; then return w .. &#039; &#039; .. fs end&lt;br /&gt;
  return tostring(w)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local PLURALS = { [&#039;Garlic&#039;] = &#039;Garlic cloves&#039;, [&#039;Whole chicken&#039;] = &#039;Whole chickens&#039;, [&#039;Russet potato&#039;] = &#039;Russet potatoes&#039; }&lt;br /&gt;
-- Display name for a count-based ingredient: &amp;quot;2 eggs&amp;quot;, &amp;quot;3 bananas&amp;quot;, &amp;quot;6 garlic cloves&amp;quot;.&lt;br /&gt;
local function countLabel(name, q, u)&lt;br /&gt;
  if u ~= &#039;each&#039; or not q or q &amp;lt;= 1 then return name end&lt;br /&gt;
  if PLURALS[name] then return PLURALS[name] end&lt;br /&gt;
  if name:sub(-1) == &#039;s&#039; then return name end&lt;br /&gt;
  return name .. &#039;s&#039;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function unitLabel(q, u)&lt;br /&gt;
  if u == &#039;each&#039; or u == &#039;&#039; then return &#039;&#039; end&lt;br /&gt;
  if u == &#039;cup&#039; and q and q &amp;gt; 1 then return &#039;cups&#039; end&lt;br /&gt;
  return u&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function sqlEsc(s) return (tostring(s):gsub(&amp;quot;&#039;&amp;quot;, &amp;quot;\\&#039;&amp;quot;)) end&lt;br /&gt;
&lt;br /&gt;
local function splitList(s)&lt;br /&gt;
  local out = {}&lt;br /&gt;
  for item in (s or &#039;&#039;):gmatch(&#039;[^,]+&#039;) do&lt;br /&gt;
    item = trim(item)&lt;br /&gt;
    if item ~= &#039;&#039; then table.insert(out, item) end&lt;br /&gt;
  end&lt;br /&gt;
  return out&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function round(x) return math.floor(x + 0.5) end&lt;br /&gt;
&lt;br /&gt;
-- ---------------------------------------------------------------- data access&lt;br /&gt;
&lt;br /&gt;
local ingredientCache = {}&lt;br /&gt;
local function getIngredient(name)&lt;br /&gt;
  if ingredientCache[name] ~= nil then return ingredientCache[name] or nil end&lt;br /&gt;
  local rows = cargo.query(&#039;Ingredients&#039;,&lt;br /&gt;
    &#039;_pageName=name,kcal100,g_tsp,g_tbsp,g_cup,g_each,allergens,pantry,price,price_per&#039;,&lt;br /&gt;
    { where = &amp;quot;_pageName=&#039;&amp;quot; .. sqlEsc(name) .. &amp;quot;&#039;&amp;quot;, limit = 1 })&lt;br /&gt;
  ingredientCache[name] = rows[1] or false&lt;br /&gt;
  return rows[1]&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function gramsPer(ing, unit)&lt;br /&gt;
  if not ing then return nil end&lt;br /&gt;
  local key = ({ tsp = &#039;g_tsp&#039;, tbsp = &#039;g_tbsp&#039;, cup = &#039;g_cup&#039;, each = &#039;g_each&#039; })[unit]&lt;br /&gt;
  if not key then return nil end&lt;br /&gt;
  return tonumber(ing[key])&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function kcalOf(ing, q, unit)&lt;br /&gt;
  local g = gramsPer(ing, unit)&lt;br /&gt;
  local k = ing and tonumber(ing.kcal100)&lt;br /&gt;
  if not (g and k and q) then return 0 end&lt;br /&gt;
  return q * g * k / 100&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Substitution rules for an ingredient, resolved for the role it plays in this recipe.&lt;br /&gt;
-- A base row (role blank) applies everywhere; a row with a role overrides the base for that role.&lt;br /&gt;
-- An override with applicable=no removes the option for that role.&lt;br /&gt;
local subsCache = {}&lt;br /&gt;
local function rulesFor(name, role)&lt;br /&gt;
  if not subsCache[name] then&lt;br /&gt;
    subsCache[name] = cargo.query(&#039;Substitutions&#039;,&lt;br /&gt;
      &#039;sub_to,alt,role,ratio,conv,confidence,effect,warning,applicable&#039;,&lt;br /&gt;
      { where = &amp;quot;sub_from=&#039;&amp;quot; .. sqlEsc(name) .. &amp;quot;&#039;&amp;quot;, orderBy = &#039;sub_to&#039;, limit = 200 })&lt;br /&gt;
  end&lt;br /&gt;
  local groups, order = {}, {}&lt;br /&gt;
  for _, r in ipairs(subsCache[name]) do&lt;br /&gt;
    local key = (r.sub_to or &#039;&#039;) .. &#039;|&#039; .. (r.alt or &#039;&#039;)&lt;br /&gt;
    if not groups[key] then groups[key] = {}; table.insert(order, key) end&lt;br /&gt;
    if trim(r.role) == &#039;&#039; then groups[key].base = r&lt;br /&gt;
    elseif trim(r.role) == role then groups[key].override = r end&lt;br /&gt;
  end&lt;br /&gt;
  local out = {}&lt;br /&gt;
  for _, key in ipairs(order) do&lt;br /&gt;
    local b, o = groups[key].base, groups[key].override&lt;br /&gt;
    local blocked = o and trim(o.applicable):lower() == &#039;no&#039;&lt;br /&gt;
    if (b or o) and not blocked then&lt;br /&gt;
      local m = {}&lt;br /&gt;
      for _, k in ipairs({ &#039;sub_to&#039;, &#039;alt&#039;, &#039;ratio&#039;, &#039;conv&#039;, &#039;confidence&#039;, &#039;effect&#039;, &#039;warning&#039; }) do&lt;br /&gt;
        local ov = o and trim(o[k]) or &#039;&#039;&lt;br /&gt;
        if ov ~= &#039;&#039; then m[k] = ov elseif b then m[k] = trim(b[k]) else m[k] = &#039;&#039; end&lt;br /&gt;
      end&lt;br /&gt;
      if m.warning == &#039;none&#039; then m.warning = &#039;&#039; end&lt;br /&gt;
      m.roleSpecific = o ~= nil&lt;br /&gt;
      table.insert(out, m)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
  return out&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- ---------------------------------------------------------------- recipe&lt;br /&gt;
&lt;br /&gt;
-- Ingredient lines are written one per line as:  Ingredient; quantity; unit; role; preparation&lt;br /&gt;
local function parseLines(text)&lt;br /&gt;
  local lines = {}&lt;br /&gt;
  for raw in (text or &#039;&#039;):gmatch(&#039;[^\r\n]+&#039;) do&lt;br /&gt;
    raw = trim(raw)&lt;br /&gt;
    if raw ~= &#039;&#039; and not raw:match(&#039;^&amp;lt;!%-%-&#039;) then&lt;br /&gt;
      local parts = mw.text.split(raw, &#039;;&#039;, true)&lt;br /&gt;
      local name = trim(parts[1] or &#039;&#039;)&lt;br /&gt;
      if name ~= &#039;&#039; then&lt;br /&gt;
        table.insert(lines, {&lt;br /&gt;
          name = name,&lt;br /&gt;
          qty = parseQty(parts[2] or &#039;&#039;),&lt;br /&gt;
          unit = trim(parts[3] or &#039;&#039;),&lt;br /&gt;
          role = trim(parts[4] or &#039;&#039;),&lt;br /&gt;
          prep = trim(parts[5] or &#039;&#039;),&lt;br /&gt;
        })&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
  return lines&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local CONF_DOTS = { high = &#039;●●●&#039;, medium = &#039;●●○&#039;, low = &#039;●○○&#039; }&lt;br /&gt;
local function confBadge(c)&lt;br /&gt;
  c = trim(c):lower()&lt;br /&gt;
  return &#039;&amp;lt;span class=&amp;quot;rp-conf rp-conf-&#039; .. c .. &#039;&amp;quot; title=&amp;quot;confidence: &#039; .. c .. &#039;&amp;quot;&amp;gt;&#039; .. (CONF_DOTS[c] or &#039;○○○&#039;) .. &#039; &#039; .. c .. &#039;&amp;lt;/span&amp;gt;&#039;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.recipe(frame)&lt;br /&gt;
  local args = frame:getParent().args&lt;br /&gt;
  local title = mw.title.getCurrentTitle()&lt;br /&gt;
  local page = title.prefixedText&lt;br /&gt;
  local serves = tonumber(args.serves) or 1&lt;br /&gt;
  local lines = parseLines(args.ingredients)&lt;br /&gt;
&lt;br /&gt;
  -- totals from the ingredient records&lt;br /&gt;
  local kcalTotal, allergens, seen, missing = 0, {}, {}, {}&lt;br /&gt;
  for _, l in ipairs(lines) do&lt;br /&gt;
    local ing = getIngredient(l.name)&lt;br /&gt;
    if ing then&lt;br /&gt;
      kcalTotal = kcalTotal + kcalOf(ing, l.qty, l.unit)&lt;br /&gt;
      for _, a in ipairs(splitList(ing.allergens)) do&lt;br /&gt;
        if not seen[a] then seen[a] = true; table.insert(allergens, a) end&lt;br /&gt;
      end&lt;br /&gt;
    else&lt;br /&gt;
      table.insert(missing, l.name)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  local out = {}&lt;br /&gt;
  local function add(s) table.insert(out, s) end&lt;br /&gt;
&lt;br /&gt;
  -- infobox&lt;br /&gt;
  add(&#039;{| class=&amp;quot;wikitable rp-infobox&amp;quot;\n|+ &#039; .. page)&lt;br /&gt;
  add(&#039;|-\n! Serves\n| &#039; .. serves)&lt;br /&gt;
  if trim(args.time) ~= &#039;&#039; then add(&#039;|-\n! Time\n| &#039; .. trim(args.time)) end&lt;br /&gt;
  add(&#039;|-\n! Per serving\n| &amp;lt;b&amp;gt;&#039; .. round(kcalTotal / serves) .. &#039; kcal&amp;lt;/b&amp;gt; &amp;lt;small&amp;gt;(&#039; .. round(kcalTotal) .. &#039; for the batch)&amp;lt;/small&amp;gt;&#039;)&lt;br /&gt;
  add(&#039;|-\n! Contains\n| &#039; .. (#allergens &amp;gt; 0 and table.concat(allergens, &#039;, &#039;) or &amp;quot;&#039;&#039;nothing flagged&#039;&#039;&amp;quot;))&lt;br /&gt;
  if trim(args.contributor) ~= &#039;&#039; then add(&#039;|-\n! Contributed by\n| &#039; .. trim(args.contributor)) end&lt;br /&gt;
  if trim(args.tags) ~= &#039;&#039; then&lt;br /&gt;
    local tagLinks = {}&lt;br /&gt;
    for _, t in ipairs(splitList(args.tags)) do table.insert(tagLinks, &#039;[[:Category:&#039; .. t .. &#039;|&#039; .. t .. &#039;]]&#039;) end&lt;br /&gt;
    add(&#039;|-\n! Tags\n| &#039; .. table.concat(tagLinks, &#039; · &#039;))&lt;br /&gt;
  end&lt;br /&gt;
  add(&#039;|-\n| colspan=&amp;quot;2&amp;quot; | &amp;lt;small&amp;gt;Calories are computed from the [[:Category:Ingredients|ingredient records]]. Approximate.&amp;lt;/small&amp;gt;&#039;)&lt;br /&gt;
  add(&#039;|}&#039;)&lt;br /&gt;
&lt;br /&gt;
  if trim(args.lede) ~= &#039;&#039; then add(&amp;quot;&amp;lt;div class=\&amp;quot;rp-lede\&amp;quot;&amp;gt;&#039;&#039;&amp;quot; .. trim(args.lede) .. &amp;quot;&#039;&#039;&amp;lt;/div&amp;gt;&amp;quot;) end&lt;br /&gt;
&lt;br /&gt;
  if #missing &amp;gt; 0 then&lt;br /&gt;
    add(&#039;&amp;lt;div class=&amp;quot;rp-missing&amp;quot;&amp;gt;These ingredients have no record yet, so they are left out of the nutrition and substitution tables: &#039; ..&lt;br /&gt;
      table.concat(missing, &#039;, &#039;) .. &#039;. [[Special:FormEdit/Ingredient|Create one]].&amp;lt;/div&amp;gt;&#039;)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  -- ingredients table&lt;br /&gt;
  add(&#039;== Ingredients ==&#039;)&lt;br /&gt;
  add(&#039;{| class=&amp;quot;wikitable rp-ingredients&amp;quot;\n! Quantity !! Ingredient !! Its job here !! Swaps&#039;)&lt;br /&gt;
  local swapSections = {}&lt;br /&gt;
  for i, l in ipairs(lines) do&lt;br /&gt;
    local ing = getIngredient(l.name)&lt;br /&gt;
    local shown = countLabel(l.name, l.qty, l.unit)&lt;br /&gt;
    local link = ing and (&#039;[[&#039; .. l.name .. &#039;|&#039; .. shown .. &#039;]]&#039;) or (&#039;[[&#039; .. l.name .. &#039;|&#039; .. shown .. &#039;]]&amp;lt;sup class=&amp;quot;rp-missing-mark&amp;quot;&amp;gt;?&amp;lt;/sup&amp;gt;&#039;)&lt;br /&gt;
    local qty = fmtQty(l.qty) .. &#039; &#039; .. unitLabel(l.qty, l.unit)&lt;br /&gt;
    local prep = l.prep ~= &#039;&#039; and (&#039;, &amp;lt;span class=&amp;quot;rp-prep&amp;quot;&amp;gt;&#039; .. l.prep .. &#039;&amp;lt;/span&amp;gt;&#039;) or &#039;&#039;&lt;br /&gt;
    local rules = ing and rulesFor(l.name, l.role) or {}&lt;br /&gt;
    local swapCell = &amp;quot;&#039;&#039;none&#039;&#039;&amp;quot;&lt;br /&gt;
    if #rules &amp;gt; 0 then&lt;br /&gt;
      swapCell = &#039;[[#Substitutions for this recipe|&#039; .. #rules .. (#rules == 1 and &#039; option&#039; or &#039; options&#039;) .. &#039;]]&#039;&lt;br /&gt;
      table.insert(swapSections, { line = l, rules = rules })&lt;br /&gt;
    end&lt;br /&gt;
    add(&#039;|-\n| class=&amp;quot;rp-qty&amp;quot; | &#039; .. trim(qty) .. &#039;\n| &#039; .. link .. prep .. &#039;\n| class=&amp;quot;rp-role&amp;quot; | &#039; .. l.role .. &#039;\n| &#039; .. swapCell)&lt;br /&gt;
  end&lt;br /&gt;
  add(&#039;|}&#039;)&lt;br /&gt;
&lt;br /&gt;
  -- method&lt;br /&gt;
  if trim(args.method) ~= &#039;&#039; then&lt;br /&gt;
    add(&#039;== Method ==&#039;)&lt;br /&gt;
    add(trim(args.method))&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  -- substitutions resolved for this recipe&lt;br /&gt;
  if #swapSections &amp;gt; 0 then&lt;br /&gt;
    add(&#039;== Substitutions for this recipe ==&#039;)&lt;br /&gt;
    add(&#039;&amp;lt;p class=&amp;quot;rp-note&amp;quot;&amp;gt;Rules come from each ingredient\&#039;s record and are resolved for the job the ingredient does in this recipe. Confidence is the community\&#039;s, not a guarantee.&amp;lt;/p&amp;gt;&#039;)&lt;br /&gt;
    add(&#039;{| class=&amp;quot;wikitable rp-subs&amp;quot;\n! Instead of !! Use !! How much !! What changes !! Confidence&#039;)&lt;br /&gt;
    for _, s in ipairs(swapSections) do&lt;br /&gt;
      for _, r in ipairs(s.rules) do&lt;br /&gt;
        local useName = r.alt ~= &#039;&#039; and (r.alt .. &#039; ([[&#039; .. r.sub_to .. &#039;]])&#039;) or (&#039;[[&#039; .. r.sub_to .. &#039;]]&#039;)&lt;br /&gt;
        local howMuch&lt;br /&gt;
        if r.conv ~= &#039;&#039; then howMuch = r.conv&lt;br /&gt;
        else&lt;br /&gt;
          local ratio = tonumber(r.ratio) or 1&lt;br /&gt;
          local nq = s.line.qty and (s.line.qty * ratio) or nil&lt;br /&gt;
          howMuch = nq and (fmtQty(nq) .. &#039; &#039; .. unitLabel(nq, s.line.unit) .. &#039; &amp;lt;small&amp;gt;(× &#039; .. ratio .. &#039;)&amp;lt;/small&amp;gt;&#039;) or (&#039;× &#039; .. ratio)&lt;br /&gt;
        end&lt;br /&gt;
        local what = r.effect&lt;br /&gt;
        if r.warning ~= &#039;&#039; then what = what .. &#039;&amp;lt;br /&amp;gt;&amp;lt;span class=&amp;quot;rp-warn&amp;quot;&amp;gt;⚠ &#039; .. r.warning .. &#039;&amp;lt;/span&amp;gt;&#039; end&lt;br /&gt;
        if r.roleSpecific then what = what .. &#039; &amp;lt;small class=&amp;quot;rp-role-tag&amp;quot;&amp;gt;rule for: &#039; .. s.line.role .. &#039;&amp;lt;/small&amp;gt;&#039; end&lt;br /&gt;
        add(&#039;|-\n| [[&#039; .. s.line.name .. &#039;]]\n| &#039; .. useName .. &#039;\n| class=&amp;quot;rp-qty&amp;quot; | &#039; .. howMuch .. &#039;\n| &#039; .. what .. &#039;\n| &#039; .. confBadge(r.confidence))&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    add(&#039;|}&#039;)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  -- store rows (skipped when the page is being previewed inside another page)&lt;br /&gt;
  if title.namespace == 0 then&lt;br /&gt;
    for i, l in ipairs(lines) do&lt;br /&gt;
      frame:callParserFunction(&#039;#cargo_store&#039;, {&lt;br /&gt;
        &#039;_table=RecipeIngredients&#039;, recipe = page, ingredient = l.name,&lt;br /&gt;
        qty = l.qty and tostring(l.qty) or &#039;&#039;, unit = l.unit, role = l.role, prep = l.prep, pos = tostring(i),&lt;br /&gt;
      })&lt;br /&gt;
    end&lt;br /&gt;
    frame:callParserFunction(&#039;#cargo_store&#039;, {&lt;br /&gt;
      &#039;_table=Recipes&#039;, serves = tostring(serves), time = trim(args.time), tags = trim(args.tags),&lt;br /&gt;
      contributor = trim(args.contributor), lede = trim(args.lede), method = trim(args.method),&lt;br /&gt;
      kcal_total = tostring(round(kcalTotal)), allergens = table.concat(allergens, &#039;,&#039;), ingredient_count = tostring(#lines),&lt;br /&gt;
    })&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  local cats = { &#039;[[Category:Recipes]]&#039; }&lt;br /&gt;
  for _, t in ipairs(splitList(args.tags)) do table.insert(cats, &#039;[[Category:&#039; .. t .. &#039;]]&#039;) end&lt;br /&gt;
  add(table.concat(cats, &#039;&#039;))&lt;br /&gt;
  return table.concat(out, &#039;\n&#039;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- ---------------------------------------------------------------- sale&lt;br /&gt;
&lt;br /&gt;
function p.sale(frame)&lt;br /&gt;
  local args = frame.args&lt;br /&gt;
  local store = trim(args.store)&lt;br /&gt;
  local where = store ~= &#039;&#039; and (&amp;quot;store=&#039;&amp;quot; .. sqlEsc(store) .. &amp;quot;&#039;&amp;quot;) or nil&lt;br /&gt;
  local sale = cargo.query(&#039;SaleItems&#039;, &#039;ingredient,price,was,per,store&#039;, { where = where, limit = 200 })&lt;br /&gt;
  if #sale == 0 then return &amp;quot;&#039;&#039;No sale items have been entered yet. Add them with [[Template:SaleItem]].&#039;&#039;&amp;quot; end&lt;br /&gt;
  local onSale = {}&lt;br /&gt;
  for _, s in ipairs(sale) do onSale[s.ingredient] = s end&lt;br /&gt;
&lt;br /&gt;
  local rows = cargo.query(&#039;RecipeIngredients=RI,Ingredients=I&#039;, &#039;RI.recipe=recipe,RI.ingredient=ingredient,I.pantry=pantry&#039;,&lt;br /&gt;
    { join = &#039;RI.ingredient=I._pageName&#039;, limit = 2000 })&lt;br /&gt;
  local recipes, order = {}, {}&lt;br /&gt;
  for _, r in ipairs(rows) do&lt;br /&gt;
    if not recipes[r.recipe] then recipes[r.recipe] = { hits = {}, toBuy = 0, save = 0 }; table.insert(order, r.recipe) end&lt;br /&gt;
    local rec = recipes[r.recipe]&lt;br /&gt;
    local pantry = trim(r.pantry):lower() == &#039;yes&#039;&lt;br /&gt;
    if not pantry then&lt;br /&gt;
      rec.toBuy = rec.toBuy + 1&lt;br /&gt;
      local s = onSale[r.ingredient]&lt;br /&gt;
      if s then&lt;br /&gt;
        table.insert(rec.hits, r.ingredient)&lt;br /&gt;
        rec.save = rec.save + ((tonumber(s.was) or 0) - (tonumber(s.price) or 0))&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
  local ranked = {}&lt;br /&gt;
  for _, name in ipairs(order) do&lt;br /&gt;
    local rec = recipes[name]&lt;br /&gt;
    if #rec.hits &amp;gt; 0 then rec.name = name; table.insert(ranked, rec) end&lt;br /&gt;
  end&lt;br /&gt;
  table.sort(ranked, function(a, b)&lt;br /&gt;
    if #a.hits ~= #b.hits then return #a.hits &amp;gt; #b.hits end&lt;br /&gt;
    return (#a.hits / math.max(1, a.toBuy)) &amp;gt; (#b.hits / math.max(1, b.toBuy))&lt;br /&gt;
  end)&lt;br /&gt;
&lt;br /&gt;
  local out = { &#039;{| class=&amp;quot;wikitable rp-sale&amp;quot;\n! Recipe !! On sale !! Shopping list !! You save&#039; }&lt;br /&gt;
  for _, rec in ipairs(ranked) do&lt;br /&gt;
    local links = {}&lt;br /&gt;
    for _, h in ipairs(rec.hits) do table.insert(links, &#039;[[&#039; .. h .. &#039;]]&#039;) end&lt;br /&gt;
    table.insert(out, &#039;|-\n| [[&#039; .. rec.name .. &#039;]]\n| &#039; .. table.concat(links, &#039;, &#039;) .. &#039;\n| &#039; .. #rec.hits .. &#039; of &#039; .. rec.toBuy ..&lt;br /&gt;
      &#039; items &amp;lt;small&amp;gt;(pantry staples excluded)&amp;lt;/small&amp;gt;\n| class=&amp;quot;rp-qty&amp;quot; | $&#039; .. string.format(&#039;%.2f&#039;, rec.save))&lt;br /&gt;
  end&lt;br /&gt;
  table.insert(out, &#039;|}&#039;)&lt;br /&gt;
  return table.concat(out, &#039;\n&#039;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- ---------------------------------------------------------------- cookbook&lt;br /&gt;
&lt;br /&gt;
local function chapterFor(tags)&lt;br /&gt;
  local t = {}&lt;br /&gt;
  for _, x in ipairs(splitList(tags)) do t[x:lower()] = true end&lt;br /&gt;
  if t[&#039;breakfast&#039;] then return &#039;Mornings&#039; end&lt;br /&gt;
  if t[&#039;dessert&#039;] then return &#039;Sweets&#039; end&lt;br /&gt;
  if t[&#039;dinner&#039;] or t[&#039;side&#039;] or t[&#039;soup&#039;] then return &#039;Suppers and sides&#039; end&lt;br /&gt;
  return &#039;Pantry and dressings&#039;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.cookbook(frame)&lt;br /&gt;
  local args = frame:getParent().args&lt;br /&gt;
  local names = splitList(args.recipes)&lt;br /&gt;
  local title = trim(args.title) ~= &#039;&#039; and trim(args.title) or &#039;Our kitchen&#039;&lt;br /&gt;
  local out = {}&lt;br /&gt;
  local function add(s) table.insert(out, s) end&lt;br /&gt;
&lt;br /&gt;
  add(&#039;&amp;lt;div class=&amp;quot;rp-book&amp;quot;&amp;gt;&#039;)&lt;br /&gt;
  add(&#039;&amp;lt;div class=&amp;quot;rp-page rp-cover&amp;quot;&amp;gt;&amp;lt;div class=&amp;quot;rp-orn&amp;quot;&amp;gt;✦&amp;lt;/div&amp;gt;&amp;lt;div class=&amp;quot;rp-cover-title&amp;quot;&amp;gt;&#039; .. title .. &#039;&amp;lt;/div&amp;gt;&amp;lt;div class=&amp;quot;rp-cover-sub&amp;quot;&amp;gt;&#039; ..&lt;br /&gt;
    #names .. (#names == 1 and &#039; recipe&#039; or &#039; recipes&#039;) .. &#039; · assembled on Recipedius&amp;lt;/div&amp;gt;&amp;lt;/div&amp;gt;&#039;)&lt;br /&gt;
  if trim(args.dedication) ~= &#039;&#039; then&lt;br /&gt;
    add(&#039;&amp;lt;div class=&amp;quot;rp-page rp-dedication&amp;quot;&amp;gt;&#039; .. trim(args.dedication) .. &#039;&amp;lt;/div&amp;gt;&#039;)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  -- gather&lt;br /&gt;
  local recs, chapters, chapterOrder = {}, {}, {}&lt;br /&gt;
  for _, n in ipairs(names) do&lt;br /&gt;
    local r = cargo.query(&#039;Recipes&#039;, &#039;_pageName=name,serves,time,tags,contributor,lede,method&#039;,&lt;br /&gt;
      { where = &amp;quot;_pageName=&#039;&amp;quot; .. sqlEsc(n) .. &amp;quot;&#039;&amp;quot;, limit = 1 })[1]&lt;br /&gt;
    if r then&lt;br /&gt;
      r.lines = cargo.query(&#039;RecipeIngredients&#039;, &#039;ingredient,qty,unit,prep,pos&#039;,&lt;br /&gt;
        { where = &amp;quot;recipe=&#039;&amp;quot; .. sqlEsc(n) .. &amp;quot;&#039;&amp;quot;, orderBy = &#039;pos&#039;, limit = 100 })&lt;br /&gt;
      local ch = chapterFor(r.tags)&lt;br /&gt;
      if not chapters[ch] then chapters[ch] = {}; table.insert(chapterOrder, ch) end&lt;br /&gt;
      table.insert(chapters[ch], r)&lt;br /&gt;
    else&lt;br /&gt;
      add(&#039;&amp;lt;div class=&amp;quot;rp-missing&amp;quot;&amp;gt;No recipe page called &amp;quot;&#039; .. n .. &#039;&amp;quot; was found.&amp;lt;/div&amp;gt;&#039;)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  -- contents&lt;br /&gt;
  add(&#039;&amp;lt;div class=&amp;quot;rp-page rp-toc&amp;quot;&amp;gt;&amp;lt;div class=&amp;quot;rp-chap-label&amp;quot;&amp;gt;Contents&amp;lt;/div&amp;gt;&#039;)&lt;br /&gt;
  for _, ch in ipairs(chapterOrder) do&lt;br /&gt;
    add(&#039;&amp;lt;div class=&amp;quot;rp-toc-chapter&amp;quot;&amp;gt;&#039; .. ch .. &#039;&amp;lt;/div&amp;gt;&#039;)&lt;br /&gt;
    for _, r in ipairs(chapters[ch]) do add(&#039;&amp;lt;div class=&amp;quot;rp-toc-row&amp;quot;&amp;gt;&amp;lt;span&amp;gt;&#039; .. r.name .. &#039;&amp;lt;/span&amp;gt;&amp;lt;span&amp;gt;&#039; .. r.time .. &#039;&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039;) end&lt;br /&gt;
  end&lt;br /&gt;
  add(&#039;&amp;lt;/div&amp;gt;&#039;)&lt;br /&gt;
&lt;br /&gt;
  for _, ch in ipairs(chapterOrder) do&lt;br /&gt;
    add(&#039;&amp;lt;div class=&amp;quot;rp-page rp-chapter&amp;quot;&amp;gt;&amp;lt;div class=&amp;quot;rp-chap-label&amp;quot;&amp;gt;Chapter&amp;lt;/div&amp;gt;&amp;lt;div class=&amp;quot;rp-chapter-title&amp;quot;&amp;gt;&#039; .. ch .. &#039;&amp;lt;/div&amp;gt;&amp;lt;/div&amp;gt;&#039;)&lt;br /&gt;
    for _, r in ipairs(chapters[ch]) do&lt;br /&gt;
      add(&#039;&amp;lt;div class=&amp;quot;rp-page rp-recipe-page&amp;quot;&amp;gt;&amp;lt;div class=&amp;quot;rp-chap-label&amp;quot;&amp;gt;&#039; .. ch .. &#039;&amp;lt;/div&amp;gt;&amp;lt;div class=&amp;quot;rp-recipe-title&amp;quot;&amp;gt;&#039; .. r.name .. &#039;&amp;lt;/div&amp;gt;&#039;)&lt;br /&gt;
      if trim(r.lede) ~= &#039;&#039; then add(&amp;quot;&amp;lt;div class=\&amp;quot;rp-lede\&amp;quot;&amp;gt;&#039;&#039;&amp;quot; .. r.lede .. &amp;quot;&#039;&#039;&amp;lt;/div&amp;gt;&amp;quot;) end&lt;br /&gt;
      add(&#039;&amp;lt;div class=&amp;quot;rp-book-cols&amp;quot;&amp;gt;&amp;lt;div class=&amp;quot;rp-book-ings&amp;quot;&amp;gt;&#039;)&lt;br /&gt;
      for _, l in ipairs(r.lines) do&lt;br /&gt;
        local q = tonumber(l.qty)&lt;br /&gt;
        add(&#039;&amp;lt;div class=&amp;quot;rp-book-ing&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;rp-qty&amp;quot;&amp;gt;&#039; .. fmtQty(q) .. &#039; &#039; .. unitLabel(q, l.unit) .. &#039;&amp;lt;/span&amp;gt;&amp;lt;span&amp;gt;&#039; .. countLabel(l.ingredient, q, l.unit) ..&lt;br /&gt;
          (trim(l.prep) ~= &#039;&#039; and (&#039;, &#039; .. l.prep) or &#039;&#039;) .. &#039;&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&#039;)&lt;br /&gt;
      end&lt;br /&gt;
      add(&#039;&amp;lt;/div&amp;gt;&amp;lt;div class=&amp;quot;rp-book-method&amp;quot;&amp;gt;\n&#039; .. (r.method or &#039;&#039;) .. &#039;\n&amp;lt;/div&amp;gt;&amp;lt;/div&amp;gt;&#039;)&lt;br /&gt;
      add(&#039;&amp;lt;div class=&amp;quot;rp-book-foot&amp;quot;&amp;gt;Serves &#039; .. r.serves .. &#039; · &#039; .. r.time .. (trim(r.contributor) ~= &#039;&#039; and (&#039; · contributed by &#039; .. r.contributor) or &#039;&#039;) .. &#039;&amp;lt;/div&amp;gt;&amp;lt;/div&amp;gt;&#039;)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
  add(&#039;&amp;lt;/div&amp;gt;&#039;)&lt;br /&gt;
  return table.concat(out, &#039;\n&#039;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return p&lt;/div&gt;</summary>
		<author><name>Janine</name></author>
	</entry>
	<entry>
		<id>https://recipedius.com/index.php?title=Banana_bread&amp;diff=48</id>
		<title>Banana bread</title>
		<link rel="alternate" type="text/html" href="https://recipedius.com/index.php?title=Banana_bread&amp;diff=48"/>
		<updated>2026-09-09T19:57:10Z</updated>

		<summary type="html">&lt;p&gt;Janine: Recipedius seed&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Recipe&lt;br /&gt;
|serves=10&lt;br /&gt;
|time=1 h 15 min&lt;br /&gt;
|tags=baking, breakfast, quick bread&lt;br /&gt;
|contributor=Dan F.&lt;br /&gt;
|lede=A melted-butter quick bread, which makes it the friendliest recipe in the book for substitutions: oil, yogurt, honey and flax all have a place here.&lt;br /&gt;
|ingredients=&lt;br /&gt;
Banana; 3; each; moisture; very ripe, mashed&lt;br /&gt;
Butter; 1/2; cup; melted; melted&lt;br /&gt;
Granulated sugar; 3/4; cup; sweet&lt;br /&gt;
Egg; 1; each; bind&lt;br /&gt;
Vanilla extract; 1; tsp; aroma&lt;br /&gt;
Baking soda; 1; tsp; leaven-dry&lt;br /&gt;
Kosher salt; 1/4; tsp; season&lt;br /&gt;
All-purpose flour; 1 1/2; cup; structure&lt;br /&gt;
|method=&lt;br /&gt;
# Heat the oven to 350°F and butter a 9×5 loaf pan.&lt;br /&gt;
# Stir the melted butter into the mashed bananas, then the sugar, egg and vanilla.&lt;br /&gt;
# Sprinkle over the soda and salt, then fold in the flour just until combined.&lt;br /&gt;
# Bake 55–65 minutes, until a skewer comes out with moist crumbs. Cool in the pan 10 minutes before turning out.&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>Janine</name></author>
	</entry>
	<entry>
		<id>https://recipedius.com/index.php?title=Template:Recipe&amp;diff=7</id>
		<title>Template:Recipe</title>
		<link rel="alternate" type="text/html" href="https://recipedius.com/index.php?title=Template:Recipe&amp;diff=7"/>
		<updated>2026-09-09T19:56:56Z</updated>

		<summary type="html">&lt;p&gt;Janine: Recipedius seed&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;noinclude&amp;gt;&lt;br /&gt;
{{#cargo_declare:_table=Recipes&lt;br /&gt;
|serves=Integer&lt;br /&gt;
|time=String&lt;br /&gt;
|tags=List (,) of String&lt;br /&gt;
|contributor=String&lt;br /&gt;
|lede=Text&lt;br /&gt;
|method=Text&lt;br /&gt;
|kcal_total=Float&lt;br /&gt;
|allergens=List (,) of String&lt;br /&gt;
|ingredient_count=Integer&lt;br /&gt;
}}&lt;br /&gt;
{{#cargo_attach:_table=RecipeIngredients}}&lt;br /&gt;
== Recipe ==&lt;br /&gt;
One page per recipe. Ingredient lines are written one per line as &amp;lt;code&amp;gt;Ingredient; quantity; unit; role; preparation&amp;lt;/code&amp;gt;. The ingredient must match the name of an [[:Category:Ingredients|ingredient record]]; the role is the job it does here and decides which substitution rules apply.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{{Recipe&lt;br /&gt;
|serves=24&lt;br /&gt;
|time=50 min&lt;br /&gt;
|tags=dessert, baking, cookie&lt;br /&gt;
|contributor=Marta O.&lt;br /&gt;
|lede=Three ingredients and a hot oven.&lt;br /&gt;
|ingredients=&lt;br /&gt;
Butter; 1; cup; creaming; softened&lt;br /&gt;
Granulated sugar; 1/2; cup; sweet&lt;br /&gt;
All-purpose flour; 2; cup; structure&lt;br /&gt;
Kosher salt; 1/4; tsp; season&lt;br /&gt;
|method=&lt;br /&gt;
# Beat the butter and sugar until pale.&lt;br /&gt;
# Stir in the flour and salt.&lt;br /&gt;
# Bake at 325°F for 30 minutes.&lt;br /&gt;
}}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Units the calculator understands (quantities may be decimals, fractions like 1/2, or mixed like 1 1/2): &amp;lt;code&amp;gt;tsp&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;tbsp&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;cup&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;each&amp;lt;/code&amp;gt;. Roles in use: creaming, melted, cutin, cooking, dressing, leaven, bind, liquid, sweet, structure, finish, juice, zest, aroma, season, inclusion, protein, starch, moisture, body, leaven-dry.&lt;br /&gt;
[[Category:Recipedius templates]]&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&amp;lt;includeonly&amp;gt;{{#invoke:Recipedius|recipe}}&amp;lt;/includeonly&amp;gt;&lt;/div&gt;</summary>
		<author><name>Janine</name></author>
	</entry>
	<entry>
		<id>https://recipedius.com/index.php?title=Template:RecipeIngredient&amp;diff=6</id>
		<title>Template:RecipeIngredient</title>
		<link rel="alternate" type="text/html" href="https://recipedius.com/index.php?title=Template:RecipeIngredient&amp;diff=6"/>
		<updated>2026-09-09T19:56:56Z</updated>

		<summary type="html">&lt;p&gt;Janine: Recipedius seed&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;noinclude&amp;gt;&lt;br /&gt;
{{#cargo_declare:_table=RecipeIngredients&lt;br /&gt;
|recipe=Page&lt;br /&gt;
|ingredient=Page&lt;br /&gt;
|qty=Float&lt;br /&gt;
|unit=String&lt;br /&gt;
|role=String&lt;br /&gt;
|prep=String&lt;br /&gt;
|pos=Integer&lt;br /&gt;
}}&lt;br /&gt;
This template only declares the &amp;lt;code&amp;gt;RecipeIngredients&amp;lt;/code&amp;gt; table (one row per ingredient line of every recipe). Rows are written by [[Module:Recipedius]] when a page uses [[Template:Recipe]]; you never call this template directly.&lt;br /&gt;
[[Category:Recipedius templates]]&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&lt;/div&gt;</summary>
		<author><name>Janine</name></author>
	</entry>
	<entry>
		<id>https://recipedius.com/index.php?title=Category:Recipedius_templates&amp;diff=62</id>
		<title>Category:Recipedius templates</title>
		<link rel="alternate" type="text/html" href="https://recipedius.com/index.php?title=Category:Recipedius_templates&amp;diff=62"/>
		<updated>2026-09-09T19:54:44Z</updated>

		<summary type="html">&lt;p&gt;Janine: Recipedius seed&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The templates and module that make Recipedius work. Start with [[Recipedius:About]].&lt;/div&gt;</summary>
		<author><name>Janine</name></author>
	</entry>
	<entry>
		<id>https://recipedius.com/index.php?title=Category:Cookbooks&amp;diff=61</id>
		<title>Category:Cookbooks</title>
		<link rel="alternate" type="text/html" href="https://recipedius.com/index.php?title=Category:Cookbooks&amp;diff=61"/>
		<updated>2026-09-09T19:54:44Z</updated>

		<summary type="html">&lt;p&gt;Janine: Recipedius seed&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Books assembled from the recipe database with [[Template:Cookbook]].&lt;/div&gt;</summary>
		<author><name>Janine</name></author>
	</entry>
	<entry>
		<id>https://recipedius.com/index.php?title=Category:Ingredients&amp;diff=60</id>
		<title>Category:Ingredients</title>
		<link rel="alternate" type="text/html" href="https://recipedius.com/index.php?title=Category:Ingredients&amp;diff=60"/>
		<updated>2026-09-09T19:54:44Z</updated>

		<summary type="html">&lt;p&gt;Janine: Recipedius seed&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Every ingredient record on Recipedius. {{#default_form:Ingredient}}&lt;/div&gt;</summary>
		<author><name>Janine</name></author>
	</entry>
	<entry>
		<id>https://recipedius.com/index.php?title=Category:Recipes&amp;diff=59</id>
		<title>Category:Recipes</title>
		<link rel="alternate" type="text/html" href="https://recipedius.com/index.php?title=Category:Recipes&amp;diff=59"/>
		<updated>2026-09-09T19:54:44Z</updated>

		<summary type="html">&lt;p&gt;Janine: Recipedius seed&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Every recipe on Recipedius. {{#default_form:Recipe}}&lt;/div&gt;</summary>
		<author><name>Janine</name></author>
	</entry>
	<entry>
		<id>https://recipedius.com/index.php?title=Form:Ingredient&amp;diff=58</id>
		<title>Form:Ingredient</title>
		<link rel="alternate" type="text/html" href="https://recipedius.com/index.php?title=Form:Ingredient&amp;diff=58"/>
		<updated>2026-09-09T19:54:44Z</updated>

		<summary type="html">&lt;p&gt;Janine: Recipedius seed&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;noinclude&amp;gt;&lt;br /&gt;
This is the form for creating an ingredient record. Enter the ingredient&#039;s name below.&lt;br /&gt;
{{#forminput:form=Ingredient|autocomplete on category=Ingredients}}&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&amp;lt;includeonly&amp;gt;&lt;br /&gt;
{{{for template|Ingredient}}}&lt;br /&gt;
{| class=&amp;quot;formtable&amp;quot;&lt;br /&gt;
! Form:&lt;br /&gt;
| {{{field|form|size=40|placeholder=Unsalted, solid}}}&lt;br /&gt;
|-&lt;br /&gt;
! Role in the kitchen:&lt;br /&gt;
| {{{field|role|size=40|placeholder=Fat · structure, flavor, creaming}}}&lt;br /&gt;
|-&lt;br /&gt;
! Storage:&lt;br /&gt;
| {{{field|storage|size=40}}}&lt;br /&gt;
|-&lt;br /&gt;
! Season:&lt;br /&gt;
| {{{field|season|size=40}}}&lt;br /&gt;
|-&lt;br /&gt;
! kcal per 100 g:&lt;br /&gt;
| {{{field|kcal100|size=6}}}&lt;br /&gt;
|-&lt;br /&gt;
! Grams per teaspoon / tablespoon / cup / each:&lt;br /&gt;
| {{{field|g_tsp|size=5}}} {{{field|g_tbsp|size=5}}} {{{field|g_cup|size=5}}} {{{field|g_each|size=5}}}&lt;br /&gt;
|-&lt;br /&gt;
! Allergens (comma-separated):&lt;br /&gt;
| {{{field|allergens|size=40|placeholder=dairy}}}&lt;br /&gt;
|-&lt;br /&gt;
! Pantry staple (left off shopping lists)?&lt;br /&gt;
| {{{field|pantry|input type=dropdown|values=no,yes}}}&lt;br /&gt;
|-&lt;br /&gt;
! Typical price and unit:&lt;br /&gt;
| ${{{field|price|size=6}}} per {{{field|price_per|size=10|placeholder=1 lb}}}&lt;br /&gt;
|-&lt;br /&gt;
! About this ingredient:&lt;br /&gt;
| {{{field|summary|input type=textarea|rows=5|cols=70}}}&lt;br /&gt;
|}&lt;br /&gt;
{{{end template}}}&lt;br /&gt;
{{{standard input|free text|rows=8|cols=70}}}&lt;br /&gt;
&amp;lt;small&amp;gt;Add substitution rules in the free-text area with [[Template:Substitution]].&amp;lt;/small&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Edit summary:&#039;&#039;&#039; {{{standard input|summary}}}&lt;br /&gt;
&lt;br /&gt;
{{{standard input|save}}} {{{standard input|preview}}} {{{standard input|cancel}}}&lt;br /&gt;
&amp;lt;/includeonly&amp;gt;&lt;/div&gt;</summary>
		<author><name>Janine</name></author>
	</entry>
	<entry>
		<id>https://recipedius.com/index.php?title=Form:Recipe&amp;diff=57</id>
		<title>Form:Recipe</title>
		<link rel="alternate" type="text/html" href="https://recipedius.com/index.php?title=Form:Recipe&amp;diff=57"/>
		<updated>2026-09-09T19:54:44Z</updated>

		<summary type="html">&lt;p&gt;Janine: Recipedius seed&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;noinclude&amp;gt;&lt;br /&gt;
This is the form for creating a recipe. Enter a title below.&lt;br /&gt;
{{#forminput:form=Recipe|autocomplete on category=Recipes}}&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&amp;lt;includeonly&amp;gt;&lt;br /&gt;
{{{for template|Recipe}}}&lt;br /&gt;
{| class=&amp;quot;formtable&amp;quot;&lt;br /&gt;
! Serves:&lt;br /&gt;
| {{{field|serves|input type=text|size=4}}}&lt;br /&gt;
|-&lt;br /&gt;
! Time:&lt;br /&gt;
| {{{field|time|size=20|placeholder=50 min}}}&lt;br /&gt;
|-&lt;br /&gt;
! Tags (comma-separated):&lt;br /&gt;
| {{{field|tags|size=40|placeholder=dessert, baking, cookie}}}&lt;br /&gt;
|-&lt;br /&gt;
! Contributed by:&lt;br /&gt;
| {{{field|contributor|size=30}}}&lt;br /&gt;
|-&lt;br /&gt;
! One-line introduction:&lt;br /&gt;
| {{{field|lede|input type=textarea|rows=2|cols=70}}}&lt;br /&gt;
|-&lt;br /&gt;
! Ingredients:&amp;lt;br /&amp;gt;&amp;lt;small&amp;gt;One per line: Ingredient; quantity; unit; role; preparation&amp;lt;br /&amp;gt;e.g. Butter; 1; cup; creaming; softened&amp;lt;/small&amp;gt;&lt;br /&gt;
| {{{field|ingredients|input type=textarea|rows=10|cols=70}}}&lt;br /&gt;
|-&lt;br /&gt;
! Method:&amp;lt;br /&amp;gt;&amp;lt;small&amp;gt;Numbered steps, one per line, starting with #&amp;lt;/small&amp;gt;&lt;br /&gt;
| {{{field|method|input type=textarea|rows=10|cols=70}}}&lt;br /&gt;
|}&lt;br /&gt;
{{{end template}}}&lt;br /&gt;
&#039;&#039;&#039;Edit summary:&#039;&#039;&#039; {{{standard input|summary}}}&lt;br /&gt;
&lt;br /&gt;
{{{standard input|save}}} {{{standard input|preview}}} {{{standard input|cancel}}}&lt;br /&gt;
&amp;lt;/includeonly&amp;gt;&lt;/div&gt;</summary>
		<author><name>Janine</name></author>
	</entry>
	<entry>
		<id>https://recipedius.com/index.php?title=Recipedius:About&amp;diff=56</id>
		<title>Recipedius:About</title>
		<link rel="alternate" type="text/html" href="https://recipedius.com/index.php?title=Recipedius:About&amp;diff=56"/>
		<updated>2026-09-09T19:54:44Z</updated>

		<summary type="html">&lt;p&gt;Janine: Recipedius seed&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Recipedius is a sandbox exploration of a twenty-year-old idea: Wikipedia, but for recipes, where every ingredient is a record that recipes link to instead of a word they retype.&lt;br /&gt;
&lt;br /&gt;
This wiki is the second prototype. The first was a single-page mock-up; this one runs on MediaWiki with the Cargo, Scribunto and Page Forms extensions, because most of what the idea needs already exists here: revision history, attribution, talk pages, upload licensing, categories, and structured data with queries.&lt;br /&gt;
&lt;br /&gt;
== How the pieces fit ==&lt;br /&gt;
; Ingredient layer&lt;br /&gt;
: [[Template:Ingredient]] is the record: form, role, storage, season, allergens, price, grams per unit, kcal per 100 g. It stores to the &amp;lt;code&amp;gt;Ingredients&amp;lt;/code&amp;gt; table.&lt;br /&gt;
; Recipe layer&lt;br /&gt;
: [[Template:Recipe]] takes ingredient lines (&amp;lt;code&amp;gt;Ingredient; quantity; unit; role; preparation&amp;lt;/code&amp;gt;) and hands them to [[Module:Recipedius]], which computes calories and allergens from the records, resolves substitutions for each line&#039;s role, renders the page, and stores rows to &amp;lt;code&amp;gt;Recipes&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;RecipeIngredients&amp;lt;/code&amp;gt;.&lt;br /&gt;
; Substitution layer&lt;br /&gt;
: [[Template:Substitution]] rows live on the page of the ingredient being replaced. A blank-role row applies everywhere; a role row overrides it. &amp;lt;code&amp;gt;applicable=no&amp;lt;/code&amp;gt; removes an option for a role.&lt;br /&gt;
; Commerce layer&lt;br /&gt;
: [[Template:SaleItem]] rows on a &amp;lt;code&amp;gt;Sale/Store&amp;lt;/code&amp;gt; page. [[This week&#039;s sale]] joins them to recipe ingredients and ranks recipes, excluding pantry staples.&lt;br /&gt;
; Collection layer&lt;br /&gt;
: [[Template:Cookbook]] renders a book from the database with a print stylesheet. Print-on-demand is the next step (the Collection extension, or a PDF export to a printer).&lt;br /&gt;
; Contribution layer&lt;br /&gt;
: MediaWiki itself: every edit has a history and an author, every upload carries a license, and moderation extensions (FlaggedRevs, Moderation, AbuseFilter) bolt on when needed.&lt;br /&gt;
&lt;br /&gt;
== What&#039;s illustrative ==&lt;br /&gt;
Nutrition values are USDA-style approximations entered by hand, not licensed data. Prices, the store, contributor names and the sample cookbook are examples. Nothing here is dietary advice.&lt;br /&gt;
&lt;br /&gt;
== Where to dig ==&lt;br /&gt;
* [[Special:CargoTables]] shows every table and its rows.&lt;br /&gt;
* [[Special:Drilldown]] filters recipes and ingredients by any field.&lt;br /&gt;
* [[Special:Version]] lists the extensions in use.&lt;/div&gt;</summary>
		<author><name>Janine</name></author>
	</entry>
	<entry>
		<id>https://recipedius.com/index.php?title=Cookbook/Sample&amp;diff=55</id>
		<title>Cookbook/Sample</title>
		<link rel="alternate" type="text/html" href="https://recipedius.com/index.php?title=Cookbook/Sample&amp;diff=55"/>
		<updated>2026-09-09T19:54:44Z</updated>

		<summary type="html">&lt;p&gt;Janine: Recipedius seed&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Cookbook&lt;br /&gt;
|title=Our kitchen&lt;br /&gt;
|dedication=For Mom, who never measured anything.&lt;br /&gt;
|recipes=Buttermilk pancakes, Lemon bars, Classic shortbread, Banana bread, Lemon and garlic roast chicken, Tomato basil soup&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>Janine</name></author>
	</entry>
	<entry>
		<id>https://recipedius.com/index.php?title=Sale/Oak_%26_Fair_Market&amp;diff=54</id>
		<title>Sale/Oak &amp; Fair Market</title>
		<link rel="alternate" type="text/html" href="https://recipedius.com/index.php?title=Sale/Oak_%26_Fair_Market&amp;diff=54"/>
		<updated>2026-09-09T19:54:44Z</updated>

		<summary type="html">&lt;p&gt;Janine: Recipedius seed&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Weekly promotions for Oak &amp;amp; Fair Market, an example retailer. One row per item; the [[This week&#039;s sale]] page ranks recipes from these.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Ingredient !! Sale price !! Was !! Per&lt;br /&gt;
{{SaleItem|ingredient=Lemon|price=0.39|was=0.89|per=each|store=Oak &amp;amp; Fair Market|week=2026-09-07}}&lt;br /&gt;
{{SaleItem|ingredient=Butter|price=2.99|was=4.49|per=1 lb|store=Oak &amp;amp; Fair Market|week=2026-09-07}}&lt;br /&gt;
{{SaleItem|ingredient=Banana|price=0.19|was=0.29|per=each|store=Oak &amp;amp; Fair Market|week=2026-09-07}}&lt;br /&gt;
{{SaleItem|ingredient=Russet potato|price=0.59|was=0.99|per=lb|store=Oak &amp;amp; Fair Market|week=2026-09-07}}&lt;br /&gt;
{{SaleItem|ingredient=Crushed tomatoes|price=1.49|was=2.19|per=28 oz|store=Oak &amp;amp; Fair Market|week=2026-09-07}}&lt;br /&gt;
{{SaleItem|ingredient=Heavy cream|price=2.99|was=4.29|per=pint|store=Oak &amp;amp; Fair Market|week=2026-09-07}}&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Janine</name></author>
	</entry>
	<entry>
		<id>https://recipedius.com/index.php?title=Main_Page&amp;diff=2</id>
		<title>Main Page</title>
		<link rel="alternate" type="text/html" href="https://recipedius.com/index.php?title=Main_Page&amp;diff=2"/>
		<updated>2026-09-09T19:54:44Z</updated>

		<summary type="html">&lt;p&gt;Janine: Recipedius seed&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;rp-lede&amp;quot;&amp;gt;&#039;&#039;&#039;Recipedius&#039;&#039;&#039; is an encyclopedia of what&#039;s in your kitchen. Every recipe is built from ingredient records, not text: swap the butter and the calories, allergens and shopping list follow. Put lemons on sale and the recipes that use them float to the top. Pick your favorites and turn them into a printed book.&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Start here:&#039;&#039;&#039; open [[Classic shortbread]] and look at the substitution table, then [[Banana bread]]; the same olive-oil swap is low-confidence in one and high in the other, because the butter&#039;s job is different. That is the whole idea in one click. Then see [[This week&#039;s sale]] and [[Cookbook/Sample]].&lt;br /&gt;
&lt;br /&gt;
== Recipes ==&lt;br /&gt;
{{#cargo_query:tables=Recipes&lt;br /&gt;
|fields=_pageName=Recipe,serves=Serves,time=Time,ROUND(kcal_total/serves)=kcal per serving,allergens=Contains,contributor=Contributed by&lt;br /&gt;
|order by=_pageName&lt;br /&gt;
|format=table&lt;br /&gt;
}}&lt;br /&gt;
&#039;&#039;Add one: [[Special:FormEdit/Recipe|create a recipe with the form]], or make a page and use [[Template:Recipe]].&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Ingredient records ==&lt;br /&gt;
{{#cargo_query:tables=Ingredients&lt;br /&gt;
|fields=_pageName=Ingredient,role=Role,ROUND(g_tbsp*kcal100/100)=kcal per tbsp,allergens=Allergens&lt;br /&gt;
|order by=_pageName&lt;br /&gt;
|format=table&lt;br /&gt;
}}&lt;br /&gt;
&#039;&#039;Add one: [[Special:FormEdit/Ingredient|create an ingredient record with the form]].&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Elsewhere ==&lt;br /&gt;
* [[This week&#039;s sale]] — recipes ranked by what&#039;s cheap at an example store&lt;br /&gt;
* [[Cookbook/Sample]] — a printable book assembled from the recipe database&lt;br /&gt;
* [[Special:CargoTables]] — the database behind the pages&lt;br /&gt;
* [[Recipedius:About]] — what this is, what&#039;s real and what&#039;s still to build&lt;/div&gt;</summary>
		<author><name>Janine</name></author>
	</entry>
	<entry>
		<id>https://recipedius.com/index.php?title=Pound_cake&amp;diff=53</id>
		<title>Pound cake</title>
		<link rel="alternate" type="text/html" href="https://recipedius.com/index.php?title=Pound_cake&amp;diff=53"/>
		<updated>2026-09-09T19:54:43Z</updated>

		<summary type="html">&lt;p&gt;Janine: Recipedius seed&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Recipe&lt;br /&gt;
|serves=12&lt;br /&gt;
|time=1 h 45 min&lt;br /&gt;
|tags=dessert, baking, cake&lt;br /&gt;
|contributor=Marta O., Fair Oaks&lt;br /&gt;
|lede=A pound each of butter, sugar, eggs and flour, scaled down. The eggs carry the lift, so egg substitutions come with a warning here.&lt;br /&gt;
|ingredients=&lt;br /&gt;
Butter; 1; cup; creaming; softened&lt;br /&gt;
Granulated sugar; 1 1/2; cup; sweet&lt;br /&gt;
Egg; 4; each; leaven; room temperature&lt;br /&gt;
Vanilla extract; 2; tsp; aroma&lt;br /&gt;
All-purpose flour; 2; cup; structure&lt;br /&gt;
Kosher salt; 1/2; tsp; season&lt;br /&gt;
|method=&lt;br /&gt;
# Heat the oven to 325°F and butter and flour a 9×5 loaf pan.&lt;br /&gt;
# Beat the butter and sugar until very pale, a full 5 minutes. Beat in the eggs one at a time, then the vanilla.&lt;br /&gt;
# Fold in the flour and salt in three additions.&lt;br /&gt;
# Bake 75–85 minutes, until a skewer comes out clean. Cool 15 minutes in the pan.&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>Janine</name></author>
	</entry>
	<entry>
		<id>https://recipedius.com/index.php?title=Garlic_mashed_potatoes&amp;diff=52</id>
		<title>Garlic mashed potatoes</title>
		<link rel="alternate" type="text/html" href="https://recipedius.com/index.php?title=Garlic_mashed_potatoes&amp;diff=52"/>
		<updated>2026-09-09T19:54:43Z</updated>

		<summary type="html">&lt;p&gt;Janine: Recipedius seed&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Recipe&lt;br /&gt;
|serves=6&lt;br /&gt;
|time=35 min&lt;br /&gt;
|tags=side, dinner&lt;br /&gt;
|contributor=Dan F.&lt;br /&gt;
|lede=Simmer the garlic in the milk while the potatoes cook and it goes mellow. Warm dairy into hot potatoes; cold dairy makes them gluey.&lt;br /&gt;
|ingredients=&lt;br /&gt;
Russet potato; 4; each; starch; about 2 lb, peeled and quartered&lt;br /&gt;
Garlic; 4; each; aroma; cloves, peeled&lt;br /&gt;
Whole milk; 3/4; cup; liquid&lt;br /&gt;
Butter; 4; tbsp; cooking&lt;br /&gt;
Kosher salt; 1 1/2; tsp; season&lt;br /&gt;
|method=&lt;br /&gt;
# Cover the potatoes with cold salted water and simmer until a knife slides in with no resistance, about 20 minutes.&lt;br /&gt;
# Meanwhile warm the milk, butter and garlic cloves in a small pan until the garlic is soft.&lt;br /&gt;
# Drain the potatoes and let them steam dry for a minute. Mash, then beat in the warm garlic milk.&lt;br /&gt;
# Season with salt. Serve at once or keep warm over a pan of simmering water.&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>Janine</name></author>
	</entry>
	<entry>
		<id>https://recipedius.com/index.php?title=Tomato_basil_soup&amp;diff=51</id>
		<title>Tomato basil soup</title>
		<link rel="alternate" type="text/html" href="https://recipedius.com/index.php?title=Tomato_basil_soup&amp;diff=51"/>
		<updated>2026-09-09T19:54:43Z</updated>

		<summary type="html">&lt;p&gt;Janine: Recipedius seed&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Recipe&lt;br /&gt;
|serves=6&lt;br /&gt;
|time=40 min&lt;br /&gt;
|tags=dinner, soup, vegetarian&lt;br /&gt;
|contributor=Community · 9 versions&lt;br /&gt;
|lede=Canned tomatoes, sweated onion, and cream stirred in off the heat. The cream is the one place a dairy-free swap works with no penalty.&lt;br /&gt;
|ingredients=&lt;br /&gt;
Olive oil; 2; tbsp; cooking&lt;br /&gt;
Yellow onion; 1; each; aroma; diced&lt;br /&gt;
Garlic; 3; each; aroma; cloves, sliced&lt;br /&gt;
Crushed tomatoes; 3 1/2; cup; body; one 28-oz can&lt;br /&gt;
Kosher salt; 1; tsp; season&lt;br /&gt;
Fresh basil; 1/2; cup; aroma; leaves, torn&lt;br /&gt;
Heavy cream; 1/2; cup; finish&lt;br /&gt;
|method=&lt;br /&gt;
# Warm the oil over medium-low. Sweat the onion with a pinch of salt until soft and sweet, 10 minutes. Add the garlic for the last minute.&lt;br /&gt;
# Add the tomatoes, 2 cups of water and the salt. Simmer 20 minutes.&lt;br /&gt;
# Blend smooth. Stir in the basil.&lt;br /&gt;
# Off the heat, stir in the cream. Taste for salt and a pinch of sugar if the tomatoes were sharp.&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>Janine</name></author>
	</entry>
	<entry>
		<id>https://recipedius.com/index.php?title=Lemon_vinaigrette&amp;diff=50</id>
		<title>Lemon vinaigrette</title>
		<link rel="alternate" type="text/html" href="https://recipedius.com/index.php?title=Lemon_vinaigrette&amp;diff=50"/>
		<updated>2026-09-09T19:54:43Z</updated>

		<summary type="html">&lt;p&gt;Janine: Recipedius seed&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Recipe&lt;br /&gt;
|serves=8&lt;br /&gt;
|time=5 min&lt;br /&gt;
|tags=dressing, citrus, no-cook&lt;br /&gt;
|contributor=Janine K.&lt;br /&gt;
|lede=Three parts oil to one part acid, a little honey to round it, and a jar to shake it in.&lt;br /&gt;
|ingredients=&lt;br /&gt;
Olive oil; 1/2; cup; dressing&lt;br /&gt;
Lemon; 1; each; juice; juiced, about 3 tbsp&lt;br /&gt;
Garlic; 1; each; aroma; clove, grated&lt;br /&gt;
Honey; 1; tsp; sweet&lt;br /&gt;
Kosher salt; 1/2; tsp; season&lt;br /&gt;
|method=&lt;br /&gt;
# Put everything in a jar with a lid.&lt;br /&gt;
# Shake hard for 20 seconds. Taste on a leaf of lettuce, not a spoon, and adjust salt.&lt;br /&gt;
# Keeps a week in the fridge; shake again before using.&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>Janine</name></author>
	</entry>
	<entry>
		<id>https://recipedius.com/index.php?title=Chocolate_chip_cookies&amp;diff=49</id>
		<title>Chocolate chip cookies</title>
		<link rel="alternate" type="text/html" href="https://recipedius.com/index.php?title=Chocolate_chip_cookies&amp;diff=49"/>
		<updated>2026-09-09T19:54:42Z</updated>

		<summary type="html">&lt;p&gt;Janine: Recipedius seed&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Recipe&lt;br /&gt;
|serves=36&lt;br /&gt;
|time=45 min&lt;br /&gt;
|tags=dessert, baking, cookie&lt;br /&gt;
|contributor=Community · 31 versions&lt;br /&gt;
|lede=Creamed butter and sugar make the crumb; the chips are along for the ride. Chill the dough if you have the patience; it browns deeper.&lt;br /&gt;
|ingredients=&lt;br /&gt;
Butter; 1; cup; creaming; softened&lt;br /&gt;
Granulated sugar; 1 1/2; cup; sweet; half white, half packed brown&lt;br /&gt;
Egg; 2; each; bind&lt;br /&gt;
Vanilla extract; 2; tsp; aroma&lt;br /&gt;
All-purpose flour; 2 1/4; cup; structure&lt;br /&gt;
Baking soda; 1; tsp; leaven-dry&lt;br /&gt;
Kosher salt; 1; tsp; season&lt;br /&gt;
Semisweet chocolate chips; 2; cup; inclusion&lt;br /&gt;
|method=&lt;br /&gt;
# Beat the butter and sugars until light, 3 minutes. Beat in the eggs one at a time, then the vanilla.&lt;br /&gt;
# Stir in the flour, soda and salt, then the chips.&lt;br /&gt;
# Scoop 2-tablespoon balls onto lined sheets, 2 inches apart. Chill 30 minutes if you can.&lt;br /&gt;
# Bake at 375°F for 9–11 minutes, until the edges are set and the centers still look soft.&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>Janine</name></author>
	</entry>
	<entry>
		<id>https://recipedius.com/index.php?title=Lemon_and_garlic_roast_chicken&amp;diff=47</id>
		<title>Lemon and garlic roast chicken</title>
		<link rel="alternate" type="text/html" href="https://recipedius.com/index.php?title=Lemon_and_garlic_roast_chicken&amp;diff=47"/>
		<updated>2026-09-09T19:54:42Z</updated>

		<summary type="html">&lt;p&gt;Janine: Recipedius seed&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Recipe&lt;br /&gt;
|serves=4&lt;br /&gt;
|time=1 h 30 min&lt;br /&gt;
|tags=dinner, roast, citrus&lt;br /&gt;
|contributor=Marta O., Fair Oaks&lt;br /&gt;
|lede=Salt the bird the night before if you can. Lemon halves in the cavity steam it from the inside and perfume the pan juices.&lt;br /&gt;
|ingredients=&lt;br /&gt;
Whole chicken; 1; each; protein; about 4 lb, patted dry&lt;br /&gt;
Lemon; 2; each; juice; halved&lt;br /&gt;
Garlic; 6; each; aroma; cloves, smashed&lt;br /&gt;
Yellow onion; 1; each; aroma; quartered&lt;br /&gt;
Olive oil; 2; tbsp; cooking&lt;br /&gt;
Kosher salt; 2; tsp; season&lt;br /&gt;
|method=&lt;br /&gt;
# Heat the oven to 425°F. Season the chicken inside and out with the salt.&lt;br /&gt;
# Squeeze one lemon over the skin, then tuck both halves, the garlic and half the onion into the cavity. Scatter the rest of the onion in the pan.&lt;br /&gt;
# Rub the skin with the oil. Roast breast up, 70–80 minutes, until the thigh reads 165°F.&lt;br /&gt;
# Rest 15 minutes. Squeeze the second lemon into the pan juices and spoon over the carved meat.&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>Janine</name></author>
	</entry>
	<entry>
		<id>https://recipedius.com/index.php?title=Classic_shortbread&amp;diff=46</id>
		<title>Classic shortbread</title>
		<link rel="alternate" type="text/html" href="https://recipedius.com/index.php?title=Classic_shortbread&amp;diff=46"/>
		<updated>2026-09-09T19:54:42Z</updated>

		<summary type="html">&lt;p&gt;Janine: Recipedius seed&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Recipe&lt;br /&gt;
|serves=24&lt;br /&gt;
|time=50 min&lt;br /&gt;
|tags=dessert, baking, cookie&lt;br /&gt;
|contributor=Community · 14 versions&lt;br /&gt;
|lede=Three ingredients and a hot oven. Everything depends on the butter, which is why the substitution rules get cautious here.&lt;br /&gt;
|ingredients=&lt;br /&gt;
Butter; 1; cup; creaming; softened&lt;br /&gt;
Granulated sugar; 1/2; cup; sweet&lt;br /&gt;
All-purpose flour; 2; cup; structure&lt;br /&gt;
Kosher salt; 1/4; tsp; season&lt;br /&gt;
Vanilla extract; 1; tsp; aroma&lt;br /&gt;
|method=&lt;br /&gt;
# Beat the butter and sugar until pale and fluffy, 3 minutes. Add vanilla.&lt;br /&gt;
# Stir in the flour and salt until a soft dough forms. Do not overwork it.&lt;br /&gt;
# Press into an 8-inch square pan, prick all over with a fork, and chill 20 minutes.&lt;br /&gt;
# Bake at 325°F for 30–35 minutes, until barely gold. Cut into fingers while warm.&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>Janine</name></author>
	</entry>
	<entry>
		<id>https://recipedius.com/index.php?title=Buttermilk_pancakes&amp;diff=45</id>
		<title>Buttermilk pancakes</title>
		<link rel="alternate" type="text/html" href="https://recipedius.com/index.php?title=Buttermilk_pancakes&amp;diff=45"/>
		<updated>2026-09-09T19:54:41Z</updated>

		<summary type="html">&lt;p&gt;Janine: Recipedius seed&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Recipe&lt;br /&gt;
|serves=4&lt;br /&gt;
|time=25 min&lt;br /&gt;
|tags=breakfast, griddle&lt;br /&gt;
|contributor=Dan F.&lt;br /&gt;
|lede=The acid in the buttermilk wakes the baking soda and softens the gluten; that is the whole trick.&lt;br /&gt;
|ingredients=&lt;br /&gt;
All-purpose flour; 2; cup; structure&lt;br /&gt;
Granulated sugar; 2; tbsp; sweet&lt;br /&gt;
Baking powder; 2; tsp; leaven-dry&lt;br /&gt;
Baking soda; 1; tsp; leaven-dry&lt;br /&gt;
Kosher salt; 1/2; tsp; season&lt;br /&gt;
Buttermilk; 2; cup; liquid&lt;br /&gt;
Egg; 2; each; bind&lt;br /&gt;
Butter; 3; tbsp; melted; melted, plus more for the pan&lt;br /&gt;
|method=&lt;br /&gt;
# Whisk the dry ingredients in one bowl and the buttermilk, eggs and melted butter in another.&lt;br /&gt;
# Pour wet into dry and stir only until no dry streaks remain. Lumps are fine; a smooth batter is a tough pancake.&lt;br /&gt;
# Rest 5 minutes while a skillet heats over medium. Butter the pan lightly.&lt;br /&gt;
# Ladle ¼-cup rounds. Flip when bubbles break on the surface and the edges look dry, about 2 minutes; cook 1 minute more.&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>Janine</name></author>
	</entry>
	<entry>
		<id>https://recipedius.com/index.php?title=Lemon_bars&amp;diff=44</id>
		<title>Lemon bars</title>
		<link rel="alternate" type="text/html" href="https://recipedius.com/index.php?title=Lemon_bars&amp;diff=44"/>
		<updated>2026-09-09T19:54:41Z</updated>

		<summary type="html">&lt;p&gt;Janine: Recipedius seed&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Recipe&lt;br /&gt;
|serves=16&lt;br /&gt;
|time=1 h 10 min&lt;br /&gt;
|tags=dessert, baking, citrus&lt;br /&gt;
|contributor=Marta O., Fair Oaks&lt;br /&gt;
|lede=A press-in shortbread base and a filling that sets to a clean, shining custard. Four lemons’ worth of zest is not a typo.&lt;br /&gt;
|ingredients=&lt;br /&gt;
Butter; 1; cup; cutin; cold, cubed&lt;br /&gt;
All-purpose flour; 2; cup; structure&lt;br /&gt;
Granulated sugar; 1 3/4; cup; sweet; divided: ½ cup for the crust&lt;br /&gt;
Kosher salt; 1/4; tsp; season&lt;br /&gt;
Egg; 4; each; leaven&lt;br /&gt;
Lemon; 4; each; zest; zest and juice (about ¾ cup juice)&lt;br /&gt;
|method=&lt;br /&gt;
# Heat the oven to 350°F and line a 9×13 pan with parchment.&lt;br /&gt;
# Rub the cold butter into the flour, ½ cup sugar and salt until it holds together when squeezed. Press into the pan and bake 18–20 minutes, until pale gold at the edges.&lt;br /&gt;
# Whisk the eggs with the remaining 1¼ cups sugar, the zest and the juice until smooth. Pour over the hot crust.&lt;br /&gt;
# Bake 20–22 minutes, until the center no longer jiggles. Cool completely, then chill an hour before cutting.&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>Janine</name></author>
	</entry>
	<entry>
		<id>https://recipedius.com/index.php?title=Whole_chicken&amp;diff=43</id>
		<title>Whole chicken</title>
		<link rel="alternate" type="text/html" href="https://recipedius.com/index.php?title=Whole_chicken&amp;diff=43"/>
		<updated>2026-09-09T19:54:41Z</updated>

		<summary type="html">&lt;p&gt;Janine: Recipedius seed&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Ingredient&lt;br /&gt;
|form=Roaster, 4 lb&lt;br /&gt;
|role=Protein&lt;br /&gt;
|storage=Fridge 1–2 days; freeze 9 months&lt;br /&gt;
|season=Year-round&lt;br /&gt;
|kcal100=215&lt;br /&gt;
|g_tsp=&lt;br /&gt;
|g_tbsp=&lt;br /&gt;
|g_cup=&lt;br /&gt;
|g_each=1800&lt;br /&gt;
|allergens=&lt;br /&gt;
|pantry=no&lt;br /&gt;
|price=9.96&lt;br /&gt;
|price_per=4 lb bird&lt;br /&gt;
|summary=A 4-pound bird roasts in about 75 minutes at 425°F. Dry the skin, salt it early, and put the lemon halves in the cavity, not on top.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Substitutions ==&lt;br /&gt;
&#039;&#039;No substitution rules yet. Add one with [[Template:Substitution]].&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Janine</name></author>
	</entry>
	<entry>
		<id>https://recipedius.com/index.php?title=Russet_potato&amp;diff=42</id>
		<title>Russet potato</title>
		<link rel="alternate" type="text/html" href="https://recipedius.com/index.php?title=Russet_potato&amp;diff=42"/>
		<updated>2026-09-09T19:54:41Z</updated>

		<summary type="html">&lt;p&gt;Janine: Recipedius seed&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Ingredient&lt;br /&gt;
|form=Fresh&lt;br /&gt;
|role=Starch · fluffy mash&lt;br /&gt;
|storage=Cool, dark, 1–2 months&lt;br /&gt;
|season=Harvested Sep–Oct; stored year-round&lt;br /&gt;
|kcal100=79&lt;br /&gt;
|g_tsp=&lt;br /&gt;
|g_tbsp=&lt;br /&gt;
|g_cup=&lt;br /&gt;
|g_each=213&lt;br /&gt;
|allergens=&lt;br /&gt;
|pantry=no&lt;br /&gt;
|price=0.99&lt;br /&gt;
|price_per=lb&lt;br /&gt;
|summary=High starch, low moisture: the potato for mashing and baking. Waxy potatoes hold their shape and turn gluey when mashed.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Substitutions ==&lt;br /&gt;
{| class=&amp;quot;wikitable rp-rules&amp;quot;&lt;br /&gt;
! Use instead !! When its job is !! How much !! Confidence !! What changes&lt;br /&gt;
{{Substitution|to=Russet potato|alt=Yukon Gold potatoes|ratio=1|confidence=medium|effect=Yukon Gold mashes creamier and needs less butter; skip the ricer and use a masher.}}&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Janine</name></author>
	</entry>
	<entry>
		<id>https://recipedius.com/index.php?title=Fresh_basil&amp;diff=41</id>
		<title>Fresh basil</title>
		<link rel="alternate" type="text/html" href="https://recipedius.com/index.php?title=Fresh_basil&amp;diff=41"/>
		<updated>2026-09-09T19:54:41Z</updated>

		<summary type="html">&lt;p&gt;Janine: Recipedius seed&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Ingredient&lt;br /&gt;
|form=Leaves&lt;br /&gt;
|role=Aroma&lt;br /&gt;
|storage=Stem in water on the counter, 1 week&lt;br /&gt;
|season=Jun–Sep&lt;br /&gt;
|kcal100=23&lt;br /&gt;
|g_tsp=&lt;br /&gt;
|g_tbsp=2.5&lt;br /&gt;
|g_cup=24&lt;br /&gt;
|g_each=&lt;br /&gt;
|allergens=&lt;br /&gt;
|pantry=no&lt;br /&gt;
|price=2.99&lt;br /&gt;
|price_per=bunch&lt;br /&gt;
|summary=Tear rather than chop, add at the end, and never refrigerate: the cold blackens the leaves.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Substitutions ==&lt;br /&gt;
&#039;&#039;No substitution rules yet. Add one with [[Template:Substitution]].&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Janine</name></author>
	</entry>
	<entry>
		<id>https://recipedius.com/index.php?title=Crushed_tomatoes&amp;diff=40</id>
		<title>Crushed tomatoes</title>
		<link rel="alternate" type="text/html" href="https://recipedius.com/index.php?title=Crushed_tomatoes&amp;diff=40"/>
		<updated>2026-09-09T19:54:41Z</updated>

		<summary type="html">&lt;p&gt;Janine: Recipedius seed&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Ingredient&lt;br /&gt;
|form=Canned, 28 oz&lt;br /&gt;
|role=Body, acid&lt;br /&gt;
|storage=Pantry; fridge after opening&lt;br /&gt;
|season=Canned year-round; fresh Jul–Sep&lt;br /&gt;
|kcal100=32&lt;br /&gt;
|g_tsp=&lt;br /&gt;
|g_tbsp=&lt;br /&gt;
|g_cup=242&lt;br /&gt;
|g_each=&lt;br /&gt;
|allergens=&lt;br /&gt;
|pantry=no&lt;br /&gt;
|price=2.19&lt;br /&gt;
|price_per=28 oz&lt;br /&gt;
|summary=Canned crushed tomatoes are picked ripe and are better than most fresh supermarket tomatoes for nine months of the year. A pinch of sugar corrects a tinny can.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Substitutions ==&lt;br /&gt;
&#039;&#039;No substitution rules yet. Add one with [[Template:Substitution]].&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Janine</name></author>
	</entry>
	<entry>
		<id>https://recipedius.com/index.php?title=Semisweet_chocolate_chips&amp;diff=39</id>
		<title>Semisweet chocolate chips</title>
		<link rel="alternate" type="text/html" href="https://recipedius.com/index.php?title=Semisweet_chocolate_chips&amp;diff=39"/>
		<updated>2026-09-09T19:54:41Z</updated>

		<summary type="html">&lt;p&gt;Janine: Recipedius seed&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Ingredient&lt;br /&gt;
|form=~45–60% cacao&lt;br /&gt;
|role=Inclusion&lt;br /&gt;
|storage=Cool pantry&lt;br /&gt;
|season=Year-round&lt;br /&gt;
|kcal100=479&lt;br /&gt;
|g_tsp=&lt;br /&gt;
|g_tbsp=15&lt;br /&gt;
|g_cup=170&lt;br /&gt;
|g_each=&lt;br /&gt;
|allergens=dairy (may contain), soy&lt;br /&gt;
|pantry=no&lt;br /&gt;
|price=4.49&lt;br /&gt;
|price_per=12 oz&lt;br /&gt;
|summary=Chips are formulated to hold their shape in the oven; chopped bar chocolate melts into pools. Both are correct; they are different cookies.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Substitutions ==&lt;br /&gt;
&#039;&#039;No substitution rules yet. Add one with [[Template:Substitution]].&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Janine</name></author>
	</entry>
	<entry>
		<id>https://recipedius.com/index.php?title=Vanilla_extract&amp;diff=38</id>
		<title>Vanilla extract</title>
		<link rel="alternate" type="text/html" href="https://recipedius.com/index.php?title=Vanilla_extract&amp;diff=38"/>
		<updated>2026-09-09T19:54:41Z</updated>

		<summary type="html">&lt;p&gt;Janine: Recipedius seed&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Ingredient&lt;br /&gt;
|form=Pure&lt;br /&gt;
|role=Aroma&lt;br /&gt;
|storage=Pantry, indefinitely&lt;br /&gt;
|season=Year-round&lt;br /&gt;
|kcal100=288&lt;br /&gt;
|g_tsp=4.2&lt;br /&gt;
|g_tbsp=13&lt;br /&gt;
|g_cup=&lt;br /&gt;
|g_each=&lt;br /&gt;
|allergens=&lt;br /&gt;
|pantry=yes&lt;br /&gt;
|price=9.99&lt;br /&gt;
|price_per=2 oz&lt;br /&gt;
|summary=Most of the alcohol cooks off; the aroma stays. Add it with the fat, not the flour, so it distributes.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Substitutions ==&lt;br /&gt;
&#039;&#039;No substitution rules yet. Add one with [[Template:Substitution]].&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Janine</name></author>
	</entry>
	<entry>
		<id>https://recipedius.com/index.php?title=Kosher_salt&amp;diff=37</id>
		<title>Kosher salt</title>
		<link rel="alternate" type="text/html" href="https://recipedius.com/index.php?title=Kosher_salt&amp;diff=37"/>
		<updated>2026-09-09T19:54:40Z</updated>

		<summary type="html">&lt;p&gt;Janine: Recipedius seed&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Ingredient&lt;br /&gt;
|form=Coarse flake&lt;br /&gt;
|role=Seasoning&lt;br /&gt;
|storage=Indefinitely&lt;br /&gt;
|season=Year-round&lt;br /&gt;
|kcal100=0&lt;br /&gt;
|g_tsp=3&lt;br /&gt;
|g_tbsp=9&lt;br /&gt;
|g_cup=&lt;br /&gt;
|g_each=&lt;br /&gt;
|allergens=&lt;br /&gt;
|pantry=yes&lt;br /&gt;
|price=2.99&lt;br /&gt;
|price_per=3 lb&lt;br /&gt;
|summary=Volume measures of salt vary wildly by brand and crystal size. A teaspoon of fine table salt is nearly twice the sodium of a teaspoon of coarse kosher flakes.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Substitutions ==&lt;br /&gt;
&#039;&#039;No substitution rules yet. Add one with [[Template:Substitution]].&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Janine</name></author>
	</entry>
	<entry>
		<id>https://recipedius.com/index.php?title=Baking_powder&amp;diff=36</id>
		<title>Baking powder</title>
		<link rel="alternate" type="text/html" href="https://recipedius.com/index.php?title=Baking_powder&amp;diff=36"/>
		<updated>2026-09-09T19:54:40Z</updated>

		<summary type="html">&lt;p&gt;Janine: Recipedius seed&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Ingredient&lt;br /&gt;
|form=Double-acting&lt;br /&gt;
|role=Leavener (self-contained)&lt;br /&gt;
|storage=Pantry, 6–12 months&lt;br /&gt;
|season=Year-round&lt;br /&gt;
|kcal100=53&lt;br /&gt;
|g_tsp=4.6&lt;br /&gt;
|g_tbsp=13.8&lt;br /&gt;
|g_cup=&lt;br /&gt;
|g_each=&lt;br /&gt;
|allergens=&lt;br /&gt;
|pantry=yes&lt;br /&gt;
|price=2.99&lt;br /&gt;
|price_per=8 oz&lt;br /&gt;
|summary=Soda plus its own dry acid. It lifts once when wet and again in the oven. Test a tin by dropping a spoonful in hot water: no fizz, no lift.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Substitutions ==&lt;br /&gt;
&#039;&#039;No substitution rules yet. Add one with [[Template:Substitution]].&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Janine</name></author>
	</entry>
	<entry>
		<id>https://recipedius.com/index.php?title=Baking_soda&amp;diff=35</id>
		<title>Baking soda</title>
		<link rel="alternate" type="text/html" href="https://recipedius.com/index.php?title=Baking_soda&amp;diff=35"/>
		<updated>2026-09-09T19:54:40Z</updated>

		<summary type="html">&lt;p&gt;Janine: Recipedius seed&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Ingredient&lt;br /&gt;
|form=Sodium bicarbonate&lt;br /&gt;
|role=Leavener (needs an acid)&lt;br /&gt;
|storage=Pantry, 2 years&lt;br /&gt;
|season=Year-round&lt;br /&gt;
|kcal100=0&lt;br /&gt;
|g_tsp=4.6&lt;br /&gt;
|g_tbsp=13.8&lt;br /&gt;
|g_cup=&lt;br /&gt;
|g_each=&lt;br /&gt;
|allergens=&lt;br /&gt;
|pantry=yes&lt;br /&gt;
|price=1.29&lt;br /&gt;
|price_per=16 oz&lt;br /&gt;
|summary=Four times as strong as baking powder and useless without an acid partner: buttermilk, yogurt, honey, brown sugar, or lemon. Take the acid out of a recipe and the soda stops working.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Substitutions ==&lt;br /&gt;
&#039;&#039;No substitution rules yet. Add one with [[Template:Substitution]].&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Janine</name></author>
	</entry>
	<entry>
		<id>https://recipedius.com/index.php?title=Banana&amp;diff=34</id>
		<title>Banana</title>
		<link rel="alternate" type="text/html" href="https://recipedius.com/index.php?title=Banana&amp;diff=34"/>
		<updated>2026-09-09T19:54:40Z</updated>

		<summary type="html">&lt;p&gt;Janine: Recipedius seed&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Ingredient&lt;br /&gt;
|form=Very ripe, spotted&lt;br /&gt;
|role=Moisture, sweetness, binder&lt;br /&gt;
|storage=Counter; freeze when spotted&lt;br /&gt;
|season=Year-round&lt;br /&gt;
|kcal100=89&lt;br /&gt;
|g_tsp=&lt;br /&gt;
|g_tbsp=&lt;br /&gt;
|g_cup=225&lt;br /&gt;
|g_each=118&lt;br /&gt;
|allergens=&lt;br /&gt;
|pantry=no&lt;br /&gt;
|price=0.29&lt;br /&gt;
|price_per=each&lt;br /&gt;
|summary=The blacker the peel, the better the bread. Frozen and thawed bananas release their liquid and mash to nothing, which is exactly what you want.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Substitutions ==&lt;br /&gt;
&#039;&#039;No substitution rules yet. Add one with [[Template:Substitution]].&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Janine</name></author>
	</entry>
</feed>