<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>GitHub Actions on Neil's Space</title><link>https://neilmin.com/tags/github-actions/</link><description>Recent content in GitHub Actions on Neil's Space</description><image><title>Neil's Space</title><url>https://neilmin.com/images/papermod-cover.png</url><link>https://neilmin.com/images/papermod-cover.png</link></image><generator>Hugo</generator><language>en-US</language><lastBuildDate>Mon, 19 Oct 2026 00:00:00 -0700</lastBuildDate><atom:link href="https://neilmin.com/tags/github-actions/index.xml" rel="self" type="application/rss+xml"/><item><title>How to Squeeze GitHub Actions Dry</title><link>https://neilmin.com/posts/squeeze-github-actions-dry/</link><pubDate>Mon, 19 Oct 2026 00:00:00 -0700</pubDate><guid>https://neilmin.com/posts/squeeze-github-actions-dry/</guid><description>To give every dish on my Stanford dining menu site an AI-generated picture without spending a cent, I turned GitHub Actions' free machines into compute: no GPU, so SDXL runs on CPU at eighteen minutes a picture, on ten machines at once every night.</description><content:encoded><![CDATA[<p>Starting in September, I began eating at Stanford&rsquo;s dining halls.</p>
<p>If you want to eat there, you first need to know what&rsquo;s on the menu. But the menu website Stanford provides is stuck twenty years in the past, and it&rsquo;s a real pain to use. You can only see one meal at one hall at a time. Want to compare halls? Click around and select everything all over again. And halfway through you forget what the last hall had, so you go back and look again.</p>
<p>After using it for the first time, I found it really hard to use.</p>
<p><img alt="Stanford&rsquo;s official Dining Hall Menu: pick a hall, a day and a meal, and you get one meal at one hall" loading="lazy" src="/posts/squeeze-github-actions-dry/img/stanford-official.jpg">
<em>This is Stanford&rsquo;s official menu site, <a href="https://rdeapps.stanford.edu/dininghallmenu/">rdeapps.stanford.edu/dininghallmenu</a>. Three dropdowns later, you get one dinner at one hall. This hall alone has twenty-some dishes, and you keep scrolling. Want the next hall? Three dropdowns again.</em></p>
<p>It&rsquo;s the age of AI. There had to be a better way to check today&rsquo;s menu. My first idea was to have AI write a script that pulls down each day&rsquo;s menus and puts them together into a report of my own, an aggregated menu. Then I could see at a glance what I can eat today, and decide which dining hall to go to.</p>
<p>The first version was really easy, done in no time: the menus of several halls side by side, what each one has tonight, all on one screen. I already owned the domain neilmin.com, so I put it on a subdomain without spending anything extra, and my friends could use it too. That&rsquo;s how <a href="https://stanford-dining.neilmin.com">stanford-dining.neilmin.com</a> came about.</p>
<p><img alt="stanford-dining.neilmin.com: three halls&rsquo; dinners side by side" loading="lazy" src="/posts/squeeze-github-actions-dry/img/our-site.jpg">
<em>The same day&rsquo;s dinner, three halls side by side.</em></p>
<p>As I went, I added two more things: Chinese, and pictures. The dish names are genuinely impossible to decode. &ldquo;Craveable Grains&rdquo;? &ldquo;Magnolia Boil&rdquo;? What is that supposed to be? So I had AI draw a picture of every dish from its name and its ingredient list. One look tells you whether it&rsquo;s stewed or stir-fried, whether the meat comes as a whole piece or sliced.</p>
<h2 id="letting-the-site-run-itself">Letting the site run itself</h2>
<p>The first version had one problem: I had to do everything by hand, every day. Scrape the new menus locally, draw the new dishes locally, push to GitHub, then wait for it to deploy.</p>
<p>A site that claims to update itself every day, with me updating it by hand every day behind the scenes. That doesn&rsquo;t make sense. By hand for a week, fine. For a month, if I grit my teeth. Any longer, no way. It had to be automated.</p>
<p>Scraping the menus was a bit of a hassle too. Stanford&rsquo;s site is old-school ASP.NET. You can&rsquo;t just build a URL that asks for &ldquo;Wilbur, Friday dinner&rdquo;: every request has to carry a long string of hidden parameters from the previous page, and that string changes every time, so the requests can only go out one after another. Annoying, but in the end just an engineering problem. Once that was solved, I dropped it into GitHub Actions to run on a schedule every day.</p>
<p>What really gave me a headache was the pictures.</p>
<h2 id="pictures-need-compute-and-i-didnt-want-to-pay">Pictures need compute, and I didn&rsquo;t want to pay</h2>
<p>Generating pictures really eats compute. On my own laptop, a local model (RealVisXL, a photorealistic model in the SDXL family) takes a minute and a half per picture, and the pictures look good. But the moment I wanted it automated, it had to run somewhere that isn&rsquo;t my laptop, and that somewhere needs compute.</p>
<p>So why not just pay to rent a GPU? That never once crossed my mind, not even $5 a month. This was a small thing I could solve by running it locally. I just wanted it to run by itself. I didn&rsquo;t want to spend a single cent on it.</p>
<p>So, free it is.</p>
<p>Search the web for pictures? The dish names are the dining halls&rsquo; own inventions, so the results often don&rsquo;t match. The copyright situation is murky too, and the quality is all over the place. It just looked bad. Then I found Cloudflare&rsquo;s Workers AI. It gives you a free daily allowance and has ready-made image models, running in the cloud, so my computer doesn&rsquo;t have to be on. Looked perfect.</p>
<p>On Cloudflare we used three image models: SDXL-Lightning, FLUX.1 schnell and FLUX.2 klein. Here&rsquo;s what came out. On the left is the Cloudflare model, on the right my local RealVisXL.</p>
<p>In the next two pairs, the left is SDXL-Lightning:</p>
<p><img alt="Meat Lover&rsquo;s Pizza: left, Cloudflare SDXL-Lightning; right, local RealVisXL" loading="lazy" src="/posts/squeeze-github-actions-dry/img/pizza-compare.jpg">
<em>Meat Lover&rsquo;s Pizza</em></p>
<p><img alt="Beef Hot Dog: left, Cloudflare SDXL-Lightning; right, local RealVisXL" loading="lazy" src="/posts/squeeze-github-actions-dry/img/hotdog-compare.jpg">
<em>Beef Hot Dog</em></p>
<p>In the next two pairs, the left is FLUX.1 schnell:</p>
<p><img alt="Grilled Pineapple: left, Cloudflare FLUX.1 schnell; right, local RealVisXL" loading="lazy" src="/posts/squeeze-github-actions-dry/img/pineapple-compare.jpg">
<em>Grilled Pineapple</em></p>
<p><img alt="Corn Dogs: left, Cloudflare FLUX.1 schnell; right, local RealVisXL" loading="lazy" src="/posts/squeeze-github-actions-dry/img/corndog-compare.jpg">
<em>Corn Dogs</em></p>
<p>My first reaction: blurrier than an oil painting, obviously AI, like something from the ChatGPT-3 era. Along the way we also tried FLUX.2 klein, and it wasn&rsquo;t great either.</p>
<p>To stop pictures like these, I added a check: after drawing, another model that can see images takes a look, and if the picture is wrong, it gets redrawn. Nice idea, but the free allowance was tight to begin with. A dish often took several pictures to pass. Every picture drawn used up quota, every picture checked used up quota again, and before long the allowance was gone. Once it ran out, the checking model couldn&rsquo;t look at anything either.</p>
<p>After going round and round a few times, it finally clicked: the best results came from the model on my laptop. The model didn&rsquo;t need changing. I just needed a free place to run it.</p>
<h2 id="github-actions-can-be-compute-too">GitHub Actions can be compute too</h2>
<p>That&rsquo;s when I thought of GitHub Actions.</p>
<p>Most people use Actions like this: push code, tests run automatically, deploys happen automatically. But think about what it actually does: GitHub lends you a Linux machine, runs the steps you wrote, then takes the machine back. Running tests is a bunch of steps. Isn&rsquo;t drawing a picture just a bunch of steps too?</p>
<p>And for public repositories, Actions is free, with no limit on minutes. According to GitHub&rsquo;s docs, this is the free machine you get for a public repository:</p>
<table>
  <thead>
      <tr>
          <th></th>
          <th>Free machine for public repositories</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>CPU</td>
          <td>4 cores</td>
      </tr>
      <tr>
          <td>Memory</td>
          <td>16 GB</td>
      </tr>
      <tr>
          <td>Disk</td>
          <td>14 GB SSD</td>
      </tr>
      <tr>
          <td>GPU</td>
          <td>None</td>
      </tr>
      <tr>
          <td>Longest single job</td>
          <td>6 hours</td>
      </tr>
      <tr>
          <td>Running at once</td>
          <td>20 jobs (free account)</td>
      </tr>
  </tbody>
</table>
<p>No GPU. Running SDXL on CPU, one picture takes 17 to 19 minutes, more than ten times slower than my laptop. Honestly, I&rsquo;d thought of this at the very start, and one look at that speed was enough to rule it out.</p>
<p>Then one day it hit me: back then I had only worked out how long one picture takes, not how many machines I could run at once.</p>
<p>If one machine takes 18 minutes a picture, I&rsquo;ll run ten of them together. Each draws for four hours, so in theory ten machines can draw over a hundred pictures a night. The new dishes that show up each day and need a picture usually number ten or twenty. That&rsquo;s enough, with plenty to spare.</p>
<p>That&rsquo;s probably the most interesting thing I learned from this project. In my head, Actions had always been the thing that runs tests and deploys. It never occurred to me that I could put compute on it.</p>
<h2 id="moving-image-generation-onto-actions">Moving image generation onto Actions</h2>
<p>The idea was simple. Actually getting it to run was another story.</p>
<p>First, disk. The RealVisXL model file is nearly 7 GB, the machine has 14 GB of disk in total, and a pile of software GitHub preinstalls takes up part of that. .NET, Android SDK, Haskell: I need none of them, so the first thing the job does is delete them to make room for the model. Then it installs the CPU build of PyTorch and ComfyUI. ComfyUI is pinned to exactly the same version as on my laptop, so the picture drawn in the cloud is the one my laptop would have drawn. Downloading the model from Hugging Face every time was too slow, so it lives in the Actions cache. Since it&rsquo;s used every night, the cache stays warm.</p>
<p>Then memory. Once the model is running it takes 15.3 GB of the 16, very nearly blowing up. It runs, but with no headroom at all, so a machine can only draw one picture at a time.</p>
<p>Then speed. If it&rsquo;s slow, let&rsquo;s see where to save. I put pictures drawn with different settings side by side and compared them by eye. Going from 20 steps down to 12, I honestly couldn&rsquo;t see the difference, and it saved two fifths of the CPU time. Resolution was off limits: put 1024×576 next to 1344×768 and the first is clearly a notch worse, so it stays at 1344×768, same as on the laptop.</p>
<p>Then quality. RealVisXL is good, but sometimes what it draws still isn&rsquo;t good enough. So I added another layer and had another AI review the pictures: after each picture, it takes a look and answers a few yes-or-no questions, like &ldquo;Is this a sausage coated in batter?&rdquo; Get one wrong, and the picture goes back to be redrawn. A dish that just won&rsquo;t come out right stays empty for now and gets another try the next night.</p>
<p>Last, splitting up the work. The whole flow has three steps:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Menu scrape finishes
</span></span><span style="display:flex;"><span>    │
</span></span><span style="display:flex;"><span>    ▼
</span></span><span style="display:flex;"><span>plan: count the new dishes, work out how many machines to start
</span></span><span style="display:flex;"><span>    │
</span></span><span style="display:flex;"><span>    ├──► Machine 1: draw 2 dishes, AI review
</span></span><span style="display:flex;"><span>    ├──► Machine 2: draw 2 dishes, AI review
</span></span><span style="display:flex;"><span>    │    ...
</span></span><span style="display:flex;"><span>    └──► Machine 10: draw 2 dishes, AI review
</span></span><span style="display:flex;"><span>    │
</span></span><span style="display:flex;"><span>    ▼
</span></span><span style="display:flex;"><span>collect: gather every machine&#39;s pictures, merge, commit
</span></span><span style="display:flex;"><span>    │
</span></span><span style="display:flex;"><span>    ▼
</span></span><span style="display:flex;"><span>Site rebuilds and deploys
</span></span></code></pre></div><p>The middle layer uses the Actions matrix. That feature is meant for running your tests on a few Python versions; I use it to hand out dishes. <code>plan</code> works out how many machines to start, the matrix starts that many parallel jobs, and each machine takes its own share.</p>
<p>When splitting, the load has to be balanced across the machines. A job can run for 6 hours at most, and when time&rsquo;s up GitHub takes the machine away, along with any picture that wasn&rsquo;t handed in. So each machine gets only two dishes and stops starting new ones after 4 hours. That way all the work gets done and handed back within the time each machine has.</p>
<p>With that, the whole automation pipeline was in place. I watched it for a week: every time a menu scrape finished, it counted the dishes, started the machines, drew, reviewed and published, all on its own. I didn&rsquo;t have to touch a thing.</p>
<p>That&rsquo;s what an engineer should do: get things running on their own, sit back and watch, and just sign off on the results.</p>
<h2 id="a-few-actions-gotchas">A few Actions gotchas</h2>
<p>A few small gotchas while I&rsquo;m at it. None of them are big, but I really didn&rsquo;t know them the first time around:</p>
<ul>
<li>Scheduled runs aren&rsquo;t on time. Whatever time you set, the run often starts around five hours late. The top and the half of the hour are the busiest, so pick another minute.</li>
<li>A commit that Actions pushes itself doesn&rsquo;t trigger <code>on: push</code>. GitHub does this on purpose, so a workflow can&rsquo;t keep triggering itself forever. So if you want to deploy automatically after scraping the menus, the workflow has to call the deploy workflow directly.</li>
<li>A triggered workflow may check out old code. By default it gets the commit from the moment it was triggered, which doesn&rsquo;t include what the previous workflow just pushed, so you have to spell out <code>ref: main</code>.</li>
</ul>
<h2 id="is-this-allowed">Is this allowed?</h2>
<p>By now someone is surely thinking: so I can use Actions as a free cloud server?</p>
<p>Don&rsquo;t. GitHub&rsquo;s terms are clear: Actions can&rsquo;t be used for cryptomining, as a CDN or a serverless backend, or for anything unrelated to the repository. It&rsquo;s for the development, testing, deployment and publishing of that project. Our use is just about reasonable: everything it makes is an asset of this project. The pictures are the site&rsquo;s content, committed to this repository and published with the site.</p>
<h2 id="the-cost-of-spending-nothing">The cost of spending nothing</h2>
<p>There is a cost, just two things.</p>
<p>First, it&rsquo;s slow. A picture takes more than ten minutes, so a new dish waits several hours between showing up on the menu and getting a picture. But the dining halls post their menus a week ahead anyway, so by the time a dish is actually served, its picture was drawn long ago. I checked the data: of the 409 new dishes that have appeared since October, 406 had a picture on or before the first day they were served.</p>
<p>Second, there&rsquo;s a ceiling on how much it can draw. How many machines can run at once, how long each can run, how much free allowance there is each day: all fixed. If one day I felt like redrawing all thousand-plus dishes, that&rsquo;s not happening. When a big batch of new dishes does turn up, like in the first week of the quarter, I run it on my laptop at a minute and a half a picture, and it&rsquo;s cleared in no time.</p>
<p>For a dining menu site, neither of these is a problem. It doesn&rsquo;t need pictures in seconds, and it doesn&rsquo;t need unlimited drawing. It just needs the day&rsquo;s few new dishes drawn right.</p>
<h2 id="a-month-in-over-500-people-have-used-it">A month in, over 500 people have used it</h2>
<p>Ever since the site went live, I&rsquo;ve been tracking its usage. In its first month, over 500 people used it, and fifty or sixty people use it every day now.</p>
<figure class="inline-svg"><svg class="chart" viewBox="0 0 600 488" role="img" aria-labelledby="usage-title usage-desc" xmlns="http://www.w3.org/2000/svg">
<title id="usage-title">Site users, Sep 15 to Oct 17</title>
<desc id="usage-desc">Total users grew from 0 to 568; daily active users peaked at 114 on Oct 6 and have been fifty to sixty a day since.</desc>
<text class="c-title" x="46" y="26">Total users</text>
<text class="c-title" x="46" y="276">Daily active users</text>
<line class="c-grid" x1="46" x2="540" y1="184.0" y2="184.0"/>
<text class="c-tick" x="38" y="189.0" text-anchor="end">0</text>
<line class="c-grid" x1="46" x2="540" y1="137.3" y2="137.3"/>
<text class="c-tick" x="38" y="142.3" text-anchor="end">200</text>
<line class="c-grid" x1="46" x2="540" y1="90.7" y2="90.7"/>
<text class="c-tick" x="38" y="95.7" text-anchor="end">400</text>
<line class="c-grid" x1="46" x2="540" y1="44.0" y2="44.0"/>
<text class="c-tick" x="38" y="49.0" text-anchor="end">600</text>
<line class="c-grid" x1="46" x2="540" y1="440.0" y2="440.0"/>
<text class="c-tick" x="38" y="445.0" text-anchor="end">0</text>
<line class="c-grid" x1="46" x2="540" y1="398.7" y2="398.7"/>
<text class="c-tick" x="38" y="403.7" text-anchor="end">40</text>
<line class="c-grid" x1="46" x2="540" y1="357.3" y2="357.3"/>
<text class="c-tick" x="38" y="362.3" text-anchor="end">80</text>
<line class="c-grid" x1="46" x2="540" y1="316.0" y2="316.0"/>
<text class="c-tick" x="38" y="321.0" text-anchor="end">120</text>
<polygon class="c-area" points="46.0,184.0 46.0,184.0 61.4,168.1 76.9,159.5 92.3,157.4 107.8,156.7 123.2,155.1 138.6,152.3 154.1,150.4 169.5,148.5 184.9,146.9 200.4,145.5 215.8,144.3 231.2,143.6 246.7,141.1 262.1,139.0 277.6,136.4 293.0,133.8 308.4,133.4 323.9,133.1 339.3,132.7 354.8,130.3 370.2,110.5 385.6,98.8 401.1,88.1 416.5,83.0 431.9,80.4 447.4,77.6 462.8,73.4 478.2,68.5 493.7,65.9 509.1,61.0 524.6,56.6 540.0,51.5 540.0,184.0"/>
<polyline class="c-line" points="46.0,184.0 61.4,168.1 76.9,159.5 92.3,157.4 107.8,156.7 123.2,155.1 138.6,152.3 154.1,150.4 169.5,148.5 184.9,146.9 200.4,145.5 215.8,144.3 231.2,143.6 246.7,141.1 262.1,139.0 277.6,136.4 293.0,133.8 308.4,133.4 323.9,133.1 339.3,132.7 354.8,130.3 370.2,110.5 385.6,98.8 401.1,88.1 416.5,83.0 431.9,80.4 447.4,77.6 462.8,73.4 478.2,68.5 493.7,65.9 509.1,61.0 524.6,56.6 540.0,51.5"/>
<circle class="c-dot" cx="540.0" cy="51.5" r="4.5"/>
<text class="c-value" x="550.0" y="57.5">568</text>
<rect class="c-bar" x="41.2" y="440.0" width="9.6" height="0.0" rx="1.5"/>
<rect class="c-bar" x="56.7" y="369.7" width="9.6" height="70.3" rx="1.5"/>
<rect class="c-bar" x="72.1" y="400.7" width="9.6" height="39.3" rx="1.5"/>
<rect class="c-bar" x="87.5" y="423.5" width="9.6" height="16.5" rx="1.5"/>
<rect class="c-bar" x="103.0" y="431.7" width="9.6" height="8.3" rx="1.5"/>
<rect class="c-bar" x="118.4" y="424.5" width="9.6" height="15.5" rx="1.5"/>
<rect class="c-bar" x="133.8" y="416.2" width="9.6" height="23.8" rx="1.5"/>
<rect class="c-bar" x="149.3" y="418.3" width="9.6" height="21.7" rx="1.5"/>
<rect class="c-bar" x="164.7" y="415.2" width="9.6" height="24.8" rx="1.5"/>
<rect class="c-bar" x="180.2" y="418.3" width="9.6" height="21.7" rx="1.5"/>
<rect class="c-bar" x="195.6" y="418.3" width="9.6" height="21.7" rx="1.5"/>
<rect class="c-bar" x="211.0" y="417.3" width="9.6" height="22.7" rx="1.5"/>
<rect class="c-bar" x="226.5" y="419.3" width="9.6" height="20.7" rx="1.5"/>
<rect class="c-bar" x="241.9" y="409.0" width="9.6" height="31.0" rx="1.5"/>
<rect class="c-bar" x="257.3" y="405.9" width="9.6" height="34.1" rx="1.5"/>
<rect class="c-bar" x="272.8" y="402.8" width="9.6" height="37.2" rx="1.5"/>
<rect class="c-bar" x="288.2" y="401.8" width="9.6" height="38.2" rx="1.5"/>
<rect class="c-bar" x="303.7" y="419.3" width="9.6" height="20.7" rx="1.5"/>
<rect class="c-bar" x="319.1" y="422.4" width="9.6" height="17.6" rx="1.5"/>
<rect class="c-bar" x="334.5" y="411.1" width="9.6" height="28.9" rx="1.5"/>
<rect class="c-bar" x="350.0" y="404.9" width="9.6" height="35.1" rx="1.5"/>
<rect class="c-bar c-bar-peak" x="365.4" y="322.2" width="9.6" height="117.8" rx="1.5"/>
<rect class="c-bar" x="380.8" y="336.7" width="9.6" height="103.3" rx="1.5"/>
<rect class="c-bar" x="396.3" y="341.8" width="9.6" height="98.2" rx="1.5"/>
<rect class="c-bar" x="411.7" y="380.1" width="9.6" height="59.9" rx="1.5"/>
<rect class="c-bar" x="427.2" y="398.7" width="9.6" height="41.3" rx="1.5"/>
<rect class="c-bar" x="442.6" y="384.2" width="9.6" height="55.8" rx="1.5"/>
<rect class="c-bar" x="458.0" y="377.0" width="9.6" height="63.0" rx="1.5"/>
<rect class="c-bar" x="473.5" y="374.9" width="9.6" height="65.1" rx="1.5"/>
<rect class="c-bar" x="488.9" y="383.2" width="9.6" height="56.8" rx="1.5"/>
<rect class="c-bar" x="504.3" y="363.5" width="9.6" height="76.5" rx="1.5"/>
<rect class="c-bar" x="519.8" y="381.1" width="9.6" height="58.9" rx="1.5"/>
<rect class="c-bar" x="535.2" y="383.2" width="9.6" height="56.8" rx="1.5"/>
<line class="c-axis" x1="46.0" x2="46.0" y1="184" y2="189"/>
<text class="c-tick" x="46.0" y="216" text-anchor="middle">9/15</text>
<line class="c-axis" x1="154.1" x2="154.1" y1="184" y2="189"/>
<text class="c-tick" x="154.1" y="216" text-anchor="middle">9/22</text>
<line class="c-axis" x1="262.1" x2="262.1" y1="184" y2="189"/>
<text class="c-tick" x="262.1" y="216" text-anchor="middle">9/29</text>
<line class="c-axis" x1="370.2" x2="370.2" y1="184" y2="189"/>
<text class="c-tick" x="370.2" y="216" text-anchor="middle">10/6</text>
<line class="c-axis" x1="478.2" x2="478.2" y1="184" y2="189"/>
<text class="c-tick" x="478.2" y="216" text-anchor="middle">10/13</text>
<line class="c-axis" x1="540.0" x2="540.0" y1="184" y2="189"/>
<text class="c-tick" x="540.0" y="216" text-anchor="middle">10/17</text>
<line class="c-axis" x1="46" x2="540" y1="184" y2="184"/>
<line class="c-axis" x1="46.0" x2="46.0" y1="440" y2="445"/>
<text class="c-tick" x="46.0" y="472" text-anchor="middle">9/15</text>
<line class="c-axis" x1="154.1" x2="154.1" y1="440" y2="445"/>
<text class="c-tick" x="154.1" y="472" text-anchor="middle">9/22</text>
<line class="c-axis" x1="262.1" x2="262.1" y1="440" y2="445"/>
<text class="c-tick" x="262.1" y="472" text-anchor="middle">9/29</text>
<line class="c-axis" x1="370.2" x2="370.2" y1="440" y2="445"/>
<text class="c-tick" x="370.2" y="472" text-anchor="middle">10/6</text>
<line class="c-axis" x1="478.2" x2="478.2" y1="440" y2="445"/>
<text class="c-tick" x="478.2" y="472" text-anchor="middle">10/13</text>
<line class="c-axis" x1="540.0" x2="540.0" y1="440" y2="445"/>
<text class="c-tick" x="540.0" y="472" text-anchor="middle">10/17</text>
<line class="c-axis" x1="46" x2="540" y1="440" y2="440"/>
</svg>
</figure>
<p>What makes me happiest: of the people checking the menu each day over the past week, about seven in ten had been here before. That tells me people really do use it as their everyday way to check the menu.</p>
<p>I&rsquo;m glad I could do a small bit of work to make checking the dining hall menu a little easier for everyone.</p>
]]></content:encoded></item></channel></rss>