<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="/rss/rssxslt"?>
<rss xmlns:a10="http://www.w3.org/2005/Atom" version="2.0">
  <channel>
    <title>ZpqrtBnk</title>
    <link>https://www.zpqrtbnk.net/</link>
    <description>ZpqrtBnk - Software Ektropist</description>
    <generator>ZpqrtBnk + Umbraco</generator>
    <item>
      <guid isPermaLink="false">11399</guid>
      <link>https://www.zpqrtbnk.net/posts/and-to-18/</link>
      <author>sgay@pilotine.com</author>
      <category>umbraco</category>
      <title>And to 18</title>
      <description>&lt;p&gt;Having just upgraded this site to Umbraco 17, it seemed right to finish the work and go to 18.&lt;/p&gt;
&lt;p&gt;The actual update is straighforward. NuGet-update packages,
deal with a few obsoleted methods that need to be removed,
refactor an &lt;code&gt;UmbracoApiController&lt;/code&gt;. Less than 30 minutes of work.&lt;/p&gt;
&lt;p&gt;Reboot... and we are now on 18!&lt;/p&gt;
&lt;p&gt;Time to monitor the application and check that everything works.&lt;/p&gt;
&lt;p&gt;Since I am currently working with &lt;a href="https://www.datadoghq.com/"&gt;Datadog&lt;/a&gt;,
I have access to their dogfooding program.
And thus, the Docker platform that hosts this site is fully instrumented.
So... this is what we are going to use.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;DISCLAIMER: I work with them, I like it there, I may be biased, etc.
And also the dogfooding program comes free, which helps.&lt;/em&gt;&lt;/p&gt;
&lt;h4 id="datadog-agent"&gt;Datadog Agent&lt;/h4&gt;
&lt;p&gt;The dashboard complains that I run an old version of the agent and should upgrade.
Since the agent itself runs on Docker, that is a quick docker-compose operation
(&lt;code&gt;dc&lt;/code&gt; is my alias for &lt;code&gt;docker compose&lt;/code&gt;):&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-sh"&gt;dc pull
dc down dd-agent
dc up dd-agent -d&lt;/code&gt;&lt;/pre&gt;&lt;h4 id="disks"&gt;Disks&lt;/h4&gt;
&lt;p&gt;Next, the monitors I have defined warn me that my disk space is getting low.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.zpqrtbnk.net/media/4dtpu14w/monitor.png" alt="monitor.png" class="img-center" alt="monitor" /&gt;&lt;/p&gt;
&lt;p&gt;Weird enough, it seems that my small &lt;code&gt;/dev/sda1&lt;/code&gt; root partition is filling up,
while my huge &lt;code&gt;/dev/sda2&lt;/code&gt; partition, specifically dedicated to Docker
(mounted as &lt;code&gt;/var/lib/docker&lt;/code&gt;), is idle.&lt;/p&gt;
&lt;p&gt;A quick search reveals this has been &lt;a href="https://www.reddit.com/r/docker/comments/1s9pxb7/overlayfs_writing_to_wrong_fs/"&gt;reported before&lt;/a&gt;
and is a matter of &lt;code&gt;containerd&lt;/code&gt; writing to the wrong FS.
Edit &lt;code&gt;/etc/containerd/config.toml&lt;/code&gt; to specify &lt;code&gt;root = &amp;quot;/var/lib/docker/containerd&amp;quot;&lt;/code&gt;,
stop Docker, reboot machine, restart all containers, cleanup, fixed.&lt;/p&gt;
&lt;p&gt;Monitors are back to green:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.zpqrtbnk.net/media/sdzhbo5r/monitor-ok.png" alt="monitor-ok" class="img-center" alt="monitor" /&gt;&lt;/p&gt;
&lt;h4 id="memory"&gt;Memory&lt;/h4&gt;
&lt;p&gt;Now, this is what I was impatient to see. For reasons, I have a large (10K) number of not-so-small
documents in this system, that &lt;em&gt;of course&lt;/em&gt; I should delete, but for
the sake of the argument, let us say I have to keep them.&lt;/p&gt;
&lt;p&gt;Previously, the container would eat up about 2GB on startup. Expensive.
But these documents are practically never ever touched.
Woot, the container is now using around 256MB and remains stable.
The new Umbraco hybrid cache is doing wonders here! Massive win!&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.zpqrtbnk.net/imgx/oxkd53np/memory-mw-600.png?hmac=369e513e1466a9708404280635ed13d42caa9e0b7c5a23880ea6b5a8050b215d" alt="memory.png" alt="memory" /&gt;&lt;/p&gt;
&lt;p&gt;At times though... the memory &lt;em&gt;does&lt;/em&gt; jump up to 2GB. It just happens,
and I do not know why.
I need to monitor the situation, so I am going to define a new monitor
on the container's memory usage. There. Now I will receive an email in
case we cross the 1GB threshold.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.zpqrtbnk.net/media/oeubiixt/monitor-mem.png" alt="monitor-mem.png" class="img-center" alt="monitor mem" /&gt;&lt;/p&gt;
&lt;h4 id="https"&gt;HTTPS&lt;/h4&gt;
&lt;p&gt;And then... I cannot access the backoffice anymore. Back to this:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-text"&gt;error:invalid_request
error_description:This server only accepts HTTPS requests.
error_uri:https://documentation.openiddict.com/errors/ID2083&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But the front website works. Now if I try to enable headers forwarding
in NGINX, this is replaced by a plain 400 error, both on back-office &lt;em&gt;and&lt;/em&gt;
front websites.&lt;/p&gt;
&lt;p&gt;You will find many pages about this issue, but &lt;a href="https://nestenius.se/net/configuring-asp-net-core-forwarded-headers-middleware/"&gt;that one&lt;/a&gt;
was really helpful. I finally got it to work with only these two
forwarded headers in NGINX:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-text"&gt;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And this in &lt;code&gt;Program.cs&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-csharp"&gt;builder.Services.Configure&lt;ForwardedHeadersOptions&gt;(options =&gt;
{
    options.ForwardedHeaders =
        ForwardedHeaders.XForwardedFor |
        ForwardedHeaders.XForwardedProto |
        ForwardedHeaders.XForwardedHost;

    // docker network is 172.0.0.0/8
    options.KnownIPNetworks.Add(new System.Net.IPNetwork(System.Net.IPAddress.Parse("172.0.0.0"), 8));
});&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And of course &lt;code&gt;.UseForwardedHeaders()&lt;/code&gt; on the application.&lt;/p&gt;
&lt;p&gt;Now it works, and I understand why, which is always better.&lt;/p&gt;
&lt;h4 id="memory-again"&gt;Memory (again)&lt;/h4&gt;
&lt;p&gt;Sure enough, I &lt;em&gt;did&lt;/em&gt; get the email about the memory growing too big.
Look at this:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.zpqrtbnk.net/media/f4cgqjic/capture-décran-2026-07-13-163820.png" alt="Capture d'écran 2026-07-13 163820.png" class="img-center" alt="memory" /&gt;&lt;/p&gt;
&lt;p&gt;Memory was stable and then it bumped to 2+GB. It went back down when I
asked Docker Compose to restart the container. Now what happened that would
cause the memory to go up like this? This: I deployed a &lt;em&gt;new version&lt;/em&gt; of the container.&lt;/p&gt;
&lt;p&gt;FWIW here is what the monitor reports:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.zpqrtbnk.net/media/q3bj5t0l/capture-décran-2026-07-13-163806.png" alt="monitor-full" class="img-center" alt="monitor" /&gt;&lt;/p&gt;
&lt;p&gt;It sure is pretty nice but does not explain why&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Restarting the container is fine&lt;/li&gt;
&lt;li&gt;Recreating the container is not&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Looking at the filesystems, it definitively look like Examine rebuilds
it entire indexes on restart, thus loading all content. But why?&lt;/p&gt;
&lt;p&gt;Spoiler: I asked Claude.&lt;/p&gt;
&lt;p&gt;And Claude told me that the issue was that Docker
container have a randomly assigned hostname, which means Umbraco could not
verify the state of &lt;em&gt;this instance&lt;/em&gt; by checking its database tables, and thus
performed a &amp;quot;cold boot&amp;quot;, and thus rebuilt indexes.&lt;/p&gt;
&lt;p&gt;Adding a &lt;code&gt;hostname: whatever&lt;/code&gt; in the Docker Compose configuration file was all
that was needed. Now the website container retains its hostname even when re-created
and I can confirm memory stays low. Always.&lt;/p&gt;
&lt;h4 id="next"&gt;Next&lt;/h4&gt;
&lt;p&gt;What else on the Radar? Another DB! MSSQL is amazing, but has this constraint
that it wants to use a minimum of 2GB of memory no matter what. This is
a lot (and expensive). There have been a few efforts at providing a
data layer for Postgres recently, and Claude can probably help us here.
I will follow conversations and experiment as soon as possible.&lt;/p&gt;
&lt;p&gt;And before we close this post, I cannot resist a bit of teasing. Thanks
to the Datadog agent, all my logs are pushed to a central place. These are
my Umbraco logs:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.zpqrtbnk.net/media/k5jdhdv5/logs.png" alt="logs.png" class="img-center" alt="logs" /&gt;&lt;/p&gt;
&lt;p&gt;But of course I also have my other websites, or MSSQL, or MySql, or Forgejo logs here, as well as metrics about the
CPUs and disks of my containers, network traffic, SQL queries/s...&lt;/p&gt;
</description>
      <pubDate>Tue, 14 Jul 2026 12:00:00 Z</pubDate>
      <a10:updated>2026-07-14T12:00:00Z</a10:updated>
      <a10:rights type="html">Copyright &amp;copy; 1985-2026 Stéphane Gay</a10:rights>
    </item>
    <item>
      <guid isPermaLink="false">11398</guid>
      <link>https://www.zpqrtbnk.net/posts/umbraco-13-to-17/</link>
      <author>sgay@pilotine.com</author>
      <category>umbraco</category>
      <title>Umbraco 13 to 17</title>
      <description>&lt;p&gt;This site has started as an Umbraco v4.x site, and has been regularly upgraded since then, never completely rebuilt. It has been running Umbraco 13 for about 3 years now, and it is about time to upgrade. We started with 17 in mind, so this post is about upgrading to 17. But 18 is out, and we are going to upgrade to it soon.&lt;/p&gt;
&lt;h4 id="packages"&gt;Packages&lt;/h4&gt;
&lt;p&gt;This is the easy part. The solution contains two projects: a Core project, and a UI project. Open each &lt;code&gt;.csproj&lt;/code&gt; file, bump &lt;code&gt;TargetFramework&lt;/code&gt; from &lt;code&gt;net8.0&lt;/code&gt; to &lt;code&gt;net10.0&lt;/code&gt;, bump Umbraco package references from &lt;code&gt;13.0.2&lt;/code&gt; to &lt;code&gt;17.4.0&lt;/code&gt;, bump a few other packages as per NuGet's suggestions.&lt;/p&gt;
&lt;p&gt;The excellent &lt;a href="https://docs.umbraco.com/umbraco-cms/get-started/upgrading-and-migrating/version-specific"&gt;Breaking Changes&lt;/a&gt; documentation tells us to remove &lt;code&gt;RazorCompileOnBuild&lt;/code&gt; and &lt;code&gt;RazorCompileOnPublish&lt;/code&gt; so, let us do it. It also tells us to clean our &lt;code&gt;Program&lt;/code&gt; class a little. Remove a &lt;code&gt;.AddDeliveryApi()&lt;/code&gt; call, remove a &lt;code&gt;.UserInstallerEndpoints()&lt;/code&gt; calls, that is it.&lt;/p&gt;
&lt;p&gt;At this point, rebuilding fails.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ModelsBuilderSettings.ModelsMode&lt;/code&gt; used to be an &lt;code&gt;enum&lt;/code&gt;, looks like it is now a &lt;code&gt;string&lt;/code&gt;. Quite simple to fix. Everything that queried the &lt;code&gt;IPublishedContentCache&lt;/code&gt; does not compile anymore, porting to &lt;code&gt;IPublishedContentQuery&lt;/code&gt; is trivial. There is no &lt;code&gt;IContentService.SaveAndPublish()&lt;/code&gt; anymore, apparently, and one needs to &lt;code&gt;Save()&lt;/code&gt; then &lt;code&gt;Publish()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;All in all, nothing dramatic.&lt;/p&gt;
&lt;p&gt;Some of my custom Markdown property editor and converter will not compile, I am going to comment them out for the time being. And... it builds. Will it boot?&lt;/p&gt;
&lt;h4 id="database"&gt;Database&lt;/h4&gt;
&lt;p&gt;Trying to boot the site fails... with a &lt;code&gt;BootFailedException&lt;/code&gt;. A migration seems to want to delete a non-existing constraint named &lt;code&gt;DF_umbracoUser_createDate&lt;/code&gt;. A quick Internet search shows that this happened to others as well, so something must have gone wrong with migrations at some point. Not going to troubleshoot, manually creating the missing constraints before upgrading is quicker:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; ALTER TABLE umbracoUser ADD CONSTRAINT DF_umbracoUser_createDate DEFAULT GETUTCDATE() FOR createDate;
 ALTER TABLE umbracoUser ADD CONSTRAINT DF_umbracoUser_updateDate  DEFAULT GETUTCDATE() FOR updateDate;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And presto... the site upgrades, boots, and I can log into the back-office.&lt;/p&gt;
&lt;h4 id="networking"&gt;Networking&lt;/h4&gt;
&lt;p&gt;At least, I can on my development machine, where I access Umbraco directly on &lt;code&gt;localhost&lt;/code&gt; via IIS. But on production, where Umbraco runs in a Docker container behind NGINX, I get weird 400 Bad Request errors. At this point I went through a few hours of frustration and random experiments.&lt;/p&gt;
&lt;p&gt;I sort of thought that it might have to do with &lt;a href="https://learn.microsoft.com/en-us/aspnet/core/host-and-deploy/proxy-load-balancer"&gt;forwarded headers&lt;/a&gt; as my issue was close to this &lt;a href="https://forum.umbraco.com/t/this-server-only-accepts-https-requests-id2083/2816"&gt;Umbraco forum post&lt;/a&gt;. I added the &lt;code&gt;ForwardedHeaders&lt;/code&gt; middleware to the app, along with the headers in NGINX configuration. Would not work. Then I left the middleware in place but reverted the NGINX configuration. It finally worked. I don't know why.&lt;/p&gt;
&lt;p&gt;Now connecting to the back-office would fail with &lt;code&gt;upstream sent too big header while reading response header from upstream&lt;/code&gt; errors being logged. That one was easier, it's an &lt;a href="https://www.cyberciti.biz/faq/nginx-upstream-sent-too-big-header-while-reading-response-header-from-upstream/"&gt;FAQ&lt;/a&gt; and applying the fix to NGINX configuration fixed it all.&lt;/p&gt;
&lt;p&gt;At that point we have: a functional back-office, and broken sites due to...&lt;/p&gt;
&lt;h4 id="data-types"&gt;Data Types&lt;/h4&gt;
&lt;p&gt;A range of data types are gone or have changed. And of course my custom data types are CompletelyBroken™ which is not a surprise, since the back-office UI has been entirely rebuilt.&lt;/p&gt;
&lt;p&gt;First, native data types. Basically, go into the &lt;em&gt;Data Types&lt;/em&gt; back-office section, and re-assign those that have issues to the proper property type. Rather simple. Weird enough, a content list datatype is throwing in the back-office, because of its &lt;code&gt;orderBy&lt;/code&gt; value. Something a migration did not catch? Manually re-saving the datatype fixes it.&lt;/p&gt;
&lt;p&gt;And then, I actually use two custom data types:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ZpqrtBnk.ImageFocus&lt;/code&gt; is an image focus data type which is an alternative to crops. It allows the user to define a rectangle that represents the &amp;quot;zone of interest&amp;quot; of an image. That zone is defined on the media itself. Next, whenever we need to render the media, we can automatically figure out the best crop based upon this zone.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ZpqrtBnk.Markdown&lt;/code&gt; is a custom Markdown data type that uses the back-office widget pretty much unchanged, but implements some rendering helpers for links or images.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As far as Markdown is concerned, I was using a property editor in order to support additional custom syntax. Turns out a property editor is not needed anymore, a plain &lt;code&gt;IMarkdownToHtmlConverter&lt;/code&gt; implementation is all that is needed. So, the property editor is gone, and it is way nicer this way.&lt;/p&gt;
&lt;p&gt;On the other hand the image focus editor needs to be completely rebuilt.&lt;/p&gt;
&lt;h4 id="my-first-property-editor"&gt;My First Property Editor&lt;/h4&gt;
&lt;p&gt;There is some nice &lt;a href="https://docs.umbraco.com/umbraco-cms/extend-your-project/tutorials/creating-a-property-editor"&gt;documentation&lt;/a&gt; about property editors in v17, so let us follow it.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mkdir PropertyEditors
cd PropertyEditors
npm create vite@latest ZpqrtBnk.ImageFocus
# with Lit
# with TypeScript
# without Vite RollDown (but I was not proposed it)
cd ZpqrtBnk.ImageFocus
npm i &amp;amp;&amp;amp; npm install -D @umbraco-cms/backoffice@17.4.0
rm -rf public/* src/*
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then,&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Update &lt;code&gt;vite.config.ts&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Create &lt;code&gt;src/zpqrtbnk-imgfocus.element.ts&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Create &lt;code&gt;public/umbraco-package.json&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Is all it takes. OK, it takes a bit of time to figure out how to put everything together but hey, this is my very first time with the new UI. The end result is &lt;em&gt;quite&lt;/em&gt; polished. As in, it makes way more sense than the convoluted Angular version.&lt;/p&gt;
&lt;p&gt;In the end,&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npm run build
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Drops files in my site's &lt;code&gt;App_Plugins&lt;/code&gt; and we are done. As in, it just works. I have to say the experience is quite pleasant.&lt;/p&gt;
&lt;h4 id="models"&gt;Models&lt;/h4&gt;
&lt;p&gt;We are not entirely done with backend work. A few more things have changed, including the CLR type of objects returned by various data types. So, most of our models are broken.&lt;/p&gt;
&lt;p&gt;The new &lt;code&gt;MediaPicker3&lt;/code&gt; for instance does not return a plain &lt;code&gt;IPublishedContent&lt;/code&gt;, but a &lt;code&gt;MediaWithCrops&lt;/code&gt;. I do not care about crops. And I had a media converter ensuring that the property value type would be reported as &lt;code&gt;Image&lt;/code&gt; in case the picker can only pick one single image. So... that converter needs a bit of update to report the proper type, and to unwrap &lt;code&gt;MediaWithCrops&lt;/code&gt; to &lt;code&gt;Image&lt;/code&gt; wherever appropriate.&lt;/p&gt;
&lt;p&gt;And then, with the various changes applied to property types, I though I would rebuild my models. Turns out they were built using the &lt;code&gt;Our.ModelsBuilder&lt;/code&gt; edition of the Models Builder, not the built-in one, because I am using some extra features.&lt;/p&gt;
&lt;p&gt;Well, a few more hours were spent bringing &lt;code&gt;Our.ModelsBuilder&lt;/code&gt; to 2026 standards. It still is a huge mess, but at least it is working again. I have pushed the changes to the &lt;a href="https://github.com/modelsbuilder/ModelsBuilder.Original"&gt;repository&lt;/a&gt;. I do &lt;em&gt;not&lt;/em&gt; believe anyone uses it anymore, but hey. It has advanced features that Core does not provide.&lt;/p&gt;
&lt;h4 id="wrapping-up"&gt;Wrapping Up&lt;/h4&gt;
&lt;p&gt;At this point, I have a running back-office, clean data types, everything is nice, time to test the front-end.&lt;/p&gt;
&lt;p&gt;And... it works.&lt;/p&gt;
&lt;p&gt;What else can I say? Total time spent is probably 1 to 2 days of work. I like it way better than rebuilding everything, I &lt;em&gt;really&lt;/em&gt; like that it this used to be a v4 site :) It is funny to see how many things have not changed much over the past 4-5 years, in terms of low-level concepts. On the other hand the experience is getting way more polished and user-friendly. And I &lt;em&gt;love&lt;/em&gt; the new back-office.&lt;/p&gt;
&lt;p&gt;The new Markdown editor does not seem fully stable, but probably it will get better with 18.&lt;/p&gt;
&lt;p&gt;Good work, team!&lt;/p&gt;
</description>
      <pubDate>Sun, 12 Jul 2026 20:00:00 Z</pubDate>
      <a10:updated>2026-07-12T20:00:00Z</a10:updated>
      <a10:rights type="html">Copyright &amp;copy; 1985-2026 Stéphane Gay</a10:rights>
    </item>
    <item>
      <guid isPermaLink="false">11394</guid>
      <link>https://www.zpqrtbnk.net/posts/reverse-engineering-with-claude-masquerade/</link>
      <author>sgay@pilotine.com</author>
      <category>game</category>
      <category>reverse-engineering</category>
      <title>Reverse Engineering with Claude - Masquerade</title>
      <description>&lt;p&gt;As much as I can enjoy playing games, to me it cannot compare to the pleasure of tearing them apart and figuring out how they all work. Which is just another kind of game, I guess. However, reverse-engineering has this issue that it is horribly time-consuming. When I release &lt;a href="https://xrick.net/"&gt;xrick&lt;/a&gt;, a Rick Dangerous remake, about 25 years ago, people were quick to ask for Rick Dangerous II. But I simply do not have the time it takes to reverse games while having a full-time job and a family.&lt;/p&gt;
&lt;h4 id="masquerade"&gt;Masquerade&lt;/h4&gt;
&lt;p&gt;On my list of games I have always wanted to reverse-engineer is Masquerade. An Apple II game by the late Dale Johnson, published in 1983 by Phoenix Software, with graphics by Rick Incrocci. It likely is one of the most difficult adventure games written for the Apple II.&lt;/p&gt;
&lt;p&gt;This is mainly due to the fact that the game can only be won by using items in the one correct sequence, yet these items can be used in multiple ways, and using an item in the incorrect way will open up new locations, without the player being able to realise they have entered a dead-end.
It also can require double actions (where the player has to perform the same action twice to fully solve a puzzle), which only compounds its difficulty.&lt;/p&gt;
&lt;p&gt;The pitch is:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;It turned out to be the toughest case of your detective career. Clues have led to nothing but dead ends. Nobody is talking. Mean-while, the crime boss you are after is still operating from somewhere. You're about to throw in the towel. But wait! Something breaks. You trail a stooge of the crime organization to a cheap, seedy hotel, hoping to pump some answers out of him. You break into the hotel room and with the butt end of your trusty .44 magnum, you knock him cold. This could be the lead you've waited for. Maybe, just maybe, if you could find some clues...&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src="https://www.zpqrtbnk.net/media/x5ahe4gi/m0.png" alt="M0" alt="masquerade" /&gt;&lt;/p&gt;
&lt;p&gt;For more infos, feel free to head to this &lt;a href="https://bluerenga.blog/tag/masquerade/?order=ASC"&gt;serie of articles&lt;/a&gt; that go over the origins and history of Masquerade, along with a walkthrough of the game. Or &lt;strong&gt;go play the JavaScript version&lt;/strong&gt; &lt;a href="https://www.zpqrtbnk.net/masquerade"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h4 id="reverse-engineering-with-claude"&gt;Reverse Engineering with Claude&lt;/h4&gt;
&lt;p&gt;Enters Claude. AI is supposed to be magic and can it help with reverse-engineering?&lt;/p&gt;
&lt;p&gt;If &lt;em&gt;I&lt;/em&gt; do not have the time, could I rely on Claude to do the work for me? Of course it would not be as entertaining, but I thought it would also be a good learning experience. And so... the rest of this post will be all about how I reversed Masquerade using Claude.&lt;/p&gt;
&lt;h4 id="the-landscape"&gt;The Landscape&lt;/h4&gt;
&lt;p&gt;The things you need in order to reverse a game are, ideally,&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;An &lt;strong&gt;emulator&lt;/strong&gt; for the platform - we are going to use the &lt;a href="https://github.com/micahcowan/bobbin"&gt;Bobbin&lt;/a&gt; emulator. It is not the best nor most known Apple 2 emulator, but it runs in text mode, and is very simple.&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;disassembler&lt;/strong&gt; - we are going to use &lt;a href="https://github.com/nationalsecurityagency/ghidra"&gt;Ghidra&lt;/a&gt;, the free and open-source disassembler originally from the NSA.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And then, since we want Claude to do the work for us,&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A way for Claude to control the emulator - we are going to use the &lt;a href="https://github.com/benj-edwards/apple2-mcp"&gt;Bobbin MCP&lt;/a&gt; server. It runs on top of a forked &lt;a href="https://github.com/benj-edwards/bobbin-ai"&gt;Bobbin&lt;/a&gt; version which implements features in order to connect with the MCP server.&lt;/li&gt;
&lt;li&gt;A way for Claude to control the disassembler - we are going to use the &lt;a href="https://github.com/bethington/ghidra-mcp"&gt;Ghidra MCP&lt;/a&gt; server.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Masquerade requires that you boot on &amp;quot;disk 1&amp;quot; and then at some point swap to &amp;quot;disk 2&amp;quot;. Ejecting and inserting disks is not supported by the Bobbin MCP server yet: it was an easy job for Claude to patch the MCP and implemented disk swapping support.&lt;/p&gt;
&lt;p&gt;Somehow I wanted to run it all on Windows, but Bobbin does not compile on Windows natively. You are supposed to cross-compile it from Linux via MINGW, and that scared me. So I asked Claude to figure things out and build on Windows. I am rather unhappy with the result: it works, it is super messy. Soon as I have some time I will revert to the original Bobbin source code and cross-compile it.&lt;/p&gt;
&lt;p&gt;All in all, I will probably push a PR for the Bobbin MCP and Bobbin itself.&lt;/p&gt;
&lt;h4 id="lets-get-started"&gt;Let's Get Started&lt;/h4&gt;
&lt;p&gt;Once the environment is in place, you want to produce a dump of the emulator's memory, once the game is running. This works mostly because these old games were all loaded at once in memory and would not access the disk. Otherwise... things would be much harder.&lt;/p&gt;
&lt;p&gt;So: boot Bobbin, run the game, and when the prompt shows, dump the entire Apple 2 64K memory. The game probably only uses a small portion of this memory, as it also contains the stack, the ROM and system code, the display memory... but hey, 64K is not that much, right?&lt;/p&gt;
&lt;p&gt;Then: run Ghidra and load the binary as 6502 assembly code. Verify that the MCP is running and that Claude can use it.&lt;/p&gt;
&lt;p&gt;And we are ready. Tell Claude that Ghidra is running and contains a memory dump of an Apple 2 game and please make sense of it. Tell Claude we want to build a knowledge base about the game, so its findings should be written down and organised.&lt;/p&gt;
&lt;p&gt;I am immediately impressed by the result. Claude finds the RESET vector, the game's entry point, and the game's data structures and functions. It identifies entities (such as objects or characters), locations, and game mechanics and movement rules. In minutes, it is doing the archeological reverse engineering work that would take days, weeks or months by hand.&lt;/p&gt;
&lt;p&gt;It is good to monitor it, though, as at some point it may go slightly sideways. For instance, when Ghidra stopped responding for a while, it decided it needed to build its own disassembler tool in Python or maybe Rust for performance reasons. About time to hit ESC and tell it that &amp;quot;you should use Ghidra exclusively, do NOT build your own disassembler tool, if Ghidra stops responding let me know and abort&amp;quot;.&lt;/p&gt;
&lt;p&gt;So at this point your role is baby-sitting Claude and stopping it anytime it goes off-track or starts making up things, but other than that it just works.&lt;/p&gt;
&lt;h4 id="porting-to-javascript"&gt;Porting to JavaScript&lt;/h4&gt;
&lt;p&gt;And then I made the mistake. It felt we knew enough of the game to roughly understand it, I got impatient, and I asked Claude to write a JavaScript port. Which it did pretty quickly. Alas... although it looked OK on the surface, it was full of tiny bugs and mistakes. Some movements were wrong, some entities were missing, etc.&lt;/p&gt;
&lt;p&gt;Like, you move to the room that is supposed to contain the OLD BOOK, and there is no book there. So you ask Claude to fix it, and it explains that actually the entity table is not complete, some bits are missing, it requires some work... and now it is fixed.&lt;/p&gt;
&lt;p&gt;Only it is not, or something else is broken. In fact, wherever the knowledge base appeared incomplete, Claude just made things up along the way.&lt;/p&gt;
&lt;p&gt;And it is all my fault. I secretely hoped that wherever the knowledge base would appear incomplete, Claude would flag it and somehow complete it. Instead, Claude produced the most probable output based upon context. Claude has no notion of context reliability, context is just context.&lt;/p&gt;
&lt;h4 id="harness-all-the-things"&gt;Harness All The Things&lt;/h4&gt;
&lt;p&gt;&amp;quot;Harness&amp;quot; is the trendy word of the week in AI. &amp;quot;Harness&amp;quot; is the ability to use AI to assess the quality of AI-generated output. So... tell Claude that thanks to the Bobbin MCP, it has access to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The actual, original, game running on a true Apple 2&lt;/li&gt;
&lt;li&gt;The JavaScript version of the game running in a browser&lt;/li&gt;
&lt;li&gt;A disassembler that contains and can disassemble the game's machine code&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And what would it propose in order to make sure that the port is correct? Claude seemed super excited by that prospect, and proposed a detailed plan to compare the two executions, calling Bobbin &amp;quot;The Oracle&amp;quot; and JavaScript &amp;quot;The Candidate&amp;quot; (yea...) and using a generated set of test cases to compare their outputs. It would then compare the assembly code with the JavaScript code to identify discrepancies, and propose a corrective plan.&lt;/p&gt;
&lt;p&gt;Sounds good?&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.zpqrtbnk.net/media/04znccrp/masqueradea_000000003_pic.png" alt="masqueradea_000000003_pic.png" class="img-center" alt="masquerade" /&gt;&lt;/p&gt;
&lt;p&gt;To make it short... after burning tokens like crazy for a few days, making iterative updates and plenty of very convincing steps, we had fixed some bugs, introduced new bugs, and still the JavaScript port was broken.&lt;/p&gt;
&lt;p&gt;Out of despair I asked Claude to assess its chances of converging to something that would be correct after a finite amount of time. To which Claude candidly replied that achieving correctness that way was probably impossible, and that it could continue drafting ever more complex strategies, but probably would just make things worse.&lt;/p&gt;
&lt;p&gt;In a moment of honesty (and self-awareness) it even discoursed on the fact that, having no concept of anything, it had no concept of what &amp;quot;correct&amp;quot; meant, and that it was just trying to produce a port from a knowledge base that was not comprehensive enough.&lt;/p&gt;
&lt;h4 id="reboot"&gt;Reboot&lt;/h4&gt;
&lt;p&gt;So... a second attempt was started. First, remove everything related to the first JavaScript port. In fact, instruct Claude to redact the knowledge base and remove every notion of &amp;quot;a port&amp;quot;.&lt;/p&gt;
&lt;p&gt;Then, ask Claude to assess the knowledge base and determine if it is comprehensive enough. Ask Claude to find out any function in Ghidra that would not be covered by the knowledge base. To verify every knowledge base assertion against Ghidra. To determine whether the knowledge was sufficient to perform a mechanical, line-by-line implementation in any other language.&lt;/p&gt;
&lt;p&gt;Immediately Claude identifies gaps, performs more analysis, and confirms that &lt;em&gt;now&lt;/em&gt; the knowledge base is complete enough. Ask again, though, and Claude finds more gaps. Essentially, I had to repeat the process over and over again until the gaps were meaningless and the changes to the knowledge base anecdoctical. Despite all my attemps, I could not convince Claude to &amp;quot;not trust your judgement and repeat until all gaps are really resolved&amp;quot;.&lt;/p&gt;
&lt;p&gt;After a number of iterations, though, we decided that we knew enough to move on. The port to JavaScript was then fast, cheap, straightforward and correct. I have been playing the walkthrough, plus some variations of it, and it works perfectly.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The result is online &lt;a href="https://www.zpqrtbnk.net/masquerade"&gt;here&lt;/a&gt;. Let us see if you can solve it without cheating nor using a walkthrough.&lt;/strong&gt;
FWIW I have also pushed &lt;a href="https://github.com/zpqrtbnk/masquerade"&gt;here on GitHub&lt;/a&gt;
the entire workspace: disk images, memory dumps, Claude knowledge base, etc.&lt;/p&gt;
&lt;h4 id="lessons-learned"&gt;Lessons Learned&lt;/h4&gt;
&lt;p&gt;Claude can definitely help with reverse engineering. As in, saving weeks of work.&lt;/p&gt;
&lt;p&gt;Wishful thinking is the cardinal sin of AI. Claude only produces the statistically most probable output considering context - it has no concepts of anything including context quality and completeness. &lt;strong&gt;If &lt;em&gt;you&lt;/em&gt; are not fully confident that the context is complete, do &lt;em&gt;not&lt;/em&gt; expect Claude to sort of make sense of it for you. You are the brain, the one that makes sense.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Harnesses are a horribly expensive and yet non-deterministic way of fixing this. Claude does not learn from the harness experience, it just repeats itself again and again hoping that at some point things will be good enough.&lt;/p&gt;
&lt;p&gt;Claude does not understand doubts, regrets nor caution. As soon as a path becomes plausible enough, it becomes some sort of magnet that drags everything - and even an obvious mountain of inconsistencies is not enough for Claude to decide that maybe it took the wrong direction. Where human beings would start doubting, and maybe backtrack, &lt;strong&gt;Claude will get deeper and deeper into nonsense&lt;/strong&gt;. It is critical to not let it move too fast, but &lt;strong&gt;monitor its activities and abort whenever necessary&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Human beings are able to take one direction while entertaining another one in some corner of our brain and, confronted to difficulties, start comparing the two. We are driven by &lt;em&gt;intentions&lt;/em&gt;, &lt;em&gt;purpose&lt;/em&gt;, as well as a notion of &lt;em&gt;time&lt;/em&gt; (e.g. &lt;em&gt;impatience&lt;/em&gt;). We &lt;em&gt;understand&lt;/em&gt;. Claude on the other hand has knowledge, a &lt;em&gt;lot&lt;/em&gt; of knowledge, and the ability to produce expected output very fast. As long as there is a reasonable probability of determining what is expected.&lt;/p&gt;
&lt;p&gt;Give Claude context, and ask Claude tasks that only match the level of maturity of the context. Claude should progress quickly, without entering side quests. Anytime Claude starts to broaden its &amp;quot;thinking&amp;quot;, abort it. Ask what should be done so it does not have to go sideways. &lt;strong&gt;Be a control freak.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Claude is a marvelous tool. Yet it is the tool. And the human is the craftsman.&lt;/p&gt;
</description>
      <pubDate>Sun, 12 Jul 2026 19:00:00 Z</pubDate>
      <a10:updated>2026-07-12T19:00:00Z</a10:updated>
      <a10:rights type="html">Copyright &amp;copy; 1985-2026 Stéphane Gay</a10:rights>
    </item>
    <item>
      <guid isPermaLink="false">11391</guid>
      <link>https://www.zpqrtbnk.net/posts/careful-with-that-struct/</link>
      <author>sgay@pilotine.com</author>
      <category>dotnet</category>
      <title>Careful with that Struct</title>
      <description>&lt;p&gt;&lt;em&gt;Method Chaining&lt;/em&gt; is a general pattern where an object class implements methods that alter the state of the object, &lt;em&gt;and&lt;/em&gt; return the current instance, thus allowing code such as:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var c = new C();
c.ChangeThis(123).ChangeThat(456);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For instance, this very minimal C# example:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;class C
{
  private string? _s;
  
  public C Change(string s)
  {
    _s = s;
    return this;
  }

  public override string ToString() =&amp;gt; _s;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Could be used with the following results:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var c = new C();
c.Change(&amp;quot;a&amp;quot;);
Console.WriteLine(c); // writes 'a'
c.Change(&amp;quot;b&amp;quot;).Change(&amp;quot;c&amp;quot;);
Console.WriteLine(c); // writes 'c'
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now let's say we want to be clever and for some reason we decide to implement the pattern on a mutable &lt;code&gt;struct&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;struct C
{
  private string? _s;
  
  public C Change(string s)
  {
    _s = s;
    return this;
  }

  public override string ToString() =&amp;gt; _s;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Can you predict the output of this code?&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var c = new C();
c.Change(&amp;quot;a&amp;quot;);
Console.WriteLine(c); // writes 'a'
c.Change(&amp;quot;b&amp;quot;).Change(&amp;quot;c&amp;quot;);
Console.WriteLine(c); // writes ??
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Turns out, but the second write &lt;strong&gt;will be 'b'&lt;/strong&gt; not 'c'. How come?&lt;/p&gt;
&lt;p&gt;It goes like this. We know that &lt;code&gt;struct&lt;/code&gt; are passed around by value. More precisely, they are &lt;em&gt;copied&lt;/em&gt; around when passed or returned to functions. Except of course for their own functions, which act on the &lt;code&gt;struct&lt;/code&gt; itself. So when the &lt;code&gt;Change&lt;/code&gt; method is invoked directly on the &lt;code&gt;c&lt;/code&gt; variable, it operates on the &lt;em&gt;actual&lt;/em&gt; structure owned by the &lt;code&gt;c&lt;/code&gt; variable, and thus mutate it. This is why the first line writes 'a'.&lt;/p&gt;
&lt;p&gt;However, the &lt;code&gt;Change&lt;/code&gt; method also returns a &lt;code&gt;C&lt;/code&gt; instance. And we just reminded ourselves that &lt;code&gt;struct&lt;/code&gt; instances are copied around, so &lt;code&gt;Change&lt;/code&gt; returns a &lt;em&gt;copy&lt;/em&gt; of the structure owned by the &lt;code&gt;c&lt;/code&gt; variable. So after the &lt;code&gt;c.Change(&amp;quot;b&amp;quot;)&lt;/code&gt; call, &lt;em&gt;both&lt;/em&gt; the structure in the &lt;code&gt;c&lt;/code&gt; variable, and its copy, have a 'b' value.&lt;/p&gt;
&lt;p&gt;But the chained method then operates on the copy! The copy is modified, and the result is ignored. The original structure owned by the &lt;code&gt;c&lt;/code&gt; variable is &lt;em&gt;not&lt;/em&gt; modified a second time. The second line writes 'b'.&lt;/p&gt;
&lt;p&gt;Of course, if we do not ignore the returned value, things work as &amp;quot;expected&amp;quot;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;c = c.Change(&amp;quot;b&amp;quot;).Change(&amp;quot;c&amp;quot;);
Console.WriteLine(c); // writes 'c'
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So what is the conclusion here? Of course, it could be &amp;quot;do not mutate structs&amp;quot;, which certainly is a valid general principle, but maybe a bit radical. On the other hand, it seems fairly reasonable to recommend against chaining methods for mutable structs.&lt;/p&gt;
</description>
      <pubDate>Sat, 10 Jan 2026 16:00:00 Z</pubDate>
      <a10:updated>2026-01-10T16:00:00Z</a10:updated>
      <a10:rights type="html">Copyright &amp;copy; 1985-2026 Stéphane Gay</a10:rights>
    </item>
    <item>
      <guid isPermaLink="false">11364</guid>
      <link>https://www.zpqrtbnk.net/posts/tales-of-fpga-road-to-sdram-e04/</link>
      <author>sgay@pilotine.com</author>
      <category>hacks</category>
      <title>Tales of FPGA - Road to SDRAM - E04</title>
      <description>&lt;p&gt;This post is the fourth one of a serie:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.zpqrtbnk.net/posts/tales-of-fpga-road-to-sdram-e01/"&gt;Episode 1&lt;/a&gt; presents what FPGA are and how to control them&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.zpqrtbnk.net/posts/tales-of-fpga-road-to-sdram-e02/"&gt;Episode 2&lt;/a&gt; highlights the importance of time in FPGAs&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.zpqrtbnk.net/posts/tales-of-fpga-road-to-sdram-e03/"&gt;Episode 3&lt;/a&gt; presents the different types of RAM&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The ultimate goal of this serie of posts is to provide a simple working example of a design that can reliably access the SDRAM chip on a &lt;a href="https://digilent.com/reference/programmable-logic/arty-s7/start"&gt;Digilent Arty S7&lt;/a&gt; FPGA development board.&lt;/p&gt;
&lt;p&gt;And now, the time has come to actually try to implement access to that SDRAM chip. Of course there is the easy way: Xilinx provides an IP, the &lt;a href="https://www.xilinx.com/products/intellectual-property/mig.html"&gt;MIG&lt;/a&gt; (Memory Interface Generator), that just does it. OK, its &lt;a href="https://docs.amd.com/v/u/en-US/ug086"&gt;documentation&lt;/a&gt; is about 600 pages so maybe &amp;quot;just&amp;quot; here is a gross simplification, but nevertheless.&lt;/p&gt;
&lt;p&gt;It essentially generates a module that, to keep things simple, expose an address bus, a data bus, and a few control lines. On the diagram below, the block to the left is you, the user. The block on the right is the SDRAM chip. The block in the middle is magic.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.zpqrtbnk.net/imgx/5k3bpv2s/mig-mw-600.png?hmac=16264b0795135b8617f4008098f8a2449dd1e476d8f7e991da4d02e66b03b623" alt="Mig" alt="phy" /&gt;&lt;/p&gt;
&lt;p&gt;By carefully following the rules, I managed to produce a complete design that can write-then-read-back data to/from the SDRAM, and blink a LED if everything is OK. Done.&lt;/p&gt;
&lt;p&gt;However, (a) that IP is very generic and therefore has latencies introduced here and there. In other words, it is not giving you access to the SDRAM at the full speed it could support. And of course, (b) it is not fun.&lt;/p&gt;
&lt;p&gt;Which takes us to the alternative: read the DDR3 protocol specifications, and implement them. Sorry to disapoint, but I am &lt;em&gt;not&lt;/em&gt; going to enter into the details of DDR3 here. It is &lt;em&gt;quite&lt;/em&gt; hairy and well documented. Google is your friend.&lt;/p&gt;
&lt;p&gt;Let us just say that the protocol is mostly serial, so serialization and de-serialization of the data bus is involved. Reading one address implies sending a stream of commands to select the correct bank and row, then receiving the value.&lt;/p&gt;
&lt;p&gt;It took me quite some time (and more), but I managed to implement a complete memory controller that Vivado would happily build and simulate. As in: we can observe the lines going to the (simulated) SDRAM chip change according to the specs, the chip behave just as it should, data goes in and out.&lt;/p&gt;
&lt;p&gt;In the simulator.&lt;/p&gt;
&lt;h4 id="fail"&gt;#Fail&lt;/h4&gt;
&lt;p&gt;Once I tried to synthetize and implement the design on silicon, things turned pretty ugly. Vivado complained about timing issues. &lt;em&gt;Lots&lt;/em&gt; of timing issues. As in, thousands of them. There was not a single part of the design that did not make it cringe.&lt;/p&gt;
&lt;p&gt;Of course, sending the design to the actual physical board plainly failed to work and, as we have explained before, there is little we can observe. No debugger, nothing. Only this: it works on paper, it works in the simulator, it fails in Real Life.&lt;/p&gt;
&lt;p&gt;Bummer. My idea was to get it to work, and sort of brag about how, yes, I have been able to make it work. Unfortunately (and that explains the delay between this article and the previous one) I must face reality: I failed.&lt;/p&gt;
&lt;p&gt;Of course I wondered how Xilinx thought we were supposed to access the SDRAM chip.&lt;/p&gt;
&lt;h4 id="the-black-box-from-hell"&gt;The Black Box from Hell&lt;/h4&gt;
&lt;p&gt;So I started to break that black box open, in order to learn what magic tricks allowed it to work. And here is what I learned: SDRAM clocks are &lt;em&gt;fast&lt;/em&gt;, as in, above 600MHz. And at that kind of speed, &lt;em&gt;everything&lt;/em&gt; matters. If you have an 8-bit bus to the SDRAM chip, the actual &lt;em&gt;placement&lt;/em&gt; of the logic controlling each bit on the FPGA chip makes a difference. Even the &lt;em&gt;length&lt;/em&gt; of the path between the FPGA chip and the SDRAM chip matters. Oh, even the &lt;em&gt;temperature&lt;/em&gt; of the SDRAM chip has an impact, and you are supposed to monitor it and re-calibrate everything when it changes.&lt;/p&gt;
&lt;p&gt;And Xilinx's IP is a powerfull wizard indeed, which not only generates Verilog code, but also additional files that position each specific gate and component at a precise place on the die, and constantly monitors the temperatures, the delays, etc. and adjust for them.&lt;/p&gt;
&lt;p&gt;There is no way I want to understand, nor replicate, all this stuff. I don't really want to deal with the physical world—I am happy with the logical one. Plus, it is kind of a moot exercise that Xilinx engineers have already solved.&lt;/p&gt;
&lt;p&gt;And yet, it is frustrating.&lt;/p&gt;
&lt;h4 id="enters-the-phy"&gt;Enters the PHY&lt;/h4&gt;
&lt;p&gt;I wanted to find some sort of in-between solution, which would give me control over the DDR3 protocol, yet deal with all the physical layer for me. And it turned out that Xilinx design sort of provides this. Internally, the black box is a pipeline of smaller black boxes:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.zpqrtbnk.net/imgx/xjpnk03q/phy-mw-600.png?hmac=064ba785aa67f44cd060e5ab2795521a96ce3fe751839fc345a15437d48c130d" alt="Capture D'écran 2024 05 05 120100" alt="phy" /&gt;&lt;/p&gt;
&lt;p&gt;And it turns out that the box named &amp;quot;PHY Interface&amp;quot; on this diagram implements precisely this: the complete control of the nitty-gritty of the physical layer, plenty of components such as &amp;quot;phasers&amp;quot; which are used to keep multiple signals in sync when for instance temperature changes would cause them to drift apart.&lt;/p&gt;
&lt;p&gt;Interesting for sure, but way too close to the physical world for my liking.&lt;/p&gt;
&lt;p&gt;Extracting the PHY layer from the global MIG IP is not an easy task, as it seems it was never meant (by Xilinx engineers) to be extracted &lt;em&gt;for real&lt;/em&gt;. Oh, and the code is not exactly as clean as the diagram presents it, and even figuring out what is or is not in the PHY is not obvious.&lt;/p&gt;
&lt;p&gt;Nevertheless, this has allowed me to produce a module that can reliably read and write commands and data to the SDRAM chip, as fast as the DDR3 protocol allows, and nothing more. A bit more work let me re-wire my original memory controller on top of this module, and voila, it all worked.&lt;/p&gt;
&lt;p&gt;TADA!&lt;/p&gt;
&lt;p&gt;And no, I will not describe it here. It would be pointlessly complex, and probably of no interest if you do not plan to use it yourself. That being said, the entire code is available on my &lt;a href="https://github.com/zpqrtbnk/road-to-sdram"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;h4 id="now-what"&gt;Now what?&lt;/h4&gt;
&lt;p&gt;The reason for all this exercise is that I have implemented, on the FPGA, a SOC (system-on-chip) composed of a custom 8-bit CPU loosely extrapolated from the 6502/6809 family of chips, along with 64KB of RAM, VGA, and PS/2 keyboard.&lt;/p&gt;
&lt;p&gt;It works quite well but currently only runs within its 64KB of RAM, which may not be enough if I want to, say, implement a TCP network stack and a small HTTP server. Having access to the full 256MB of the SDRAM chip would certainly help.&lt;/p&gt;
&lt;p&gt;Hence our next challenge: how does an 8-bit CPU with a 16-bit address bus (i.e. a 64KB address space) handle a 256MB memory space in a nice and efficient way? Want to read about MMUs (memory management units), memory paging and banking, segments? Stay tuned!&lt;/p&gt;
</description>
      <pubDate>Sun, 05 May 2024 20:00:00 Z</pubDate>
      <a10:updated>2024-05-05T20:00:00Z</a10:updated>
      <a10:rights type="html">Copyright &amp;copy; 1985-2026 Stéphane Gay</a10:rights>
    </item>
    <item>
      <guid isPermaLink="false">11386</guid>
      <link>https://www.zpqrtbnk.net/posts/taskcompletionsource-pitfalls/</link>
      <author>sgay@pilotine.com</author>
      <category>dotnet</category>
      <title>TaskCompletionSource Pitfalls</title>
      <description>&lt;p&gt;Imagine you are implementing a client for a server that performs an operation on some data, and that operation is totally asynchronous, and the server has only &lt;em&gt;one&lt;/em&gt; connection to it.&lt;/p&gt;
&lt;p&gt;Contrary to an HTTP server, where a new connection is opened for each request (or, where requests are queued on one connection), requests must be pushed to the server with some sort of unique identifier, and the server will push responses back in whatever order it produces them.&lt;/p&gt;
&lt;p&gt;Let us try to implement the client API:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;~csharp
public async Task&amp;lt;Response&amp;gt; SubmitRequestAsync(Request request)
{
    await server.SendRequestAsync(request);

    // now what?
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, we have to return a &lt;code&gt;Task&amp;lt;Response&amp;gt;&lt;/code&gt; that represents the client waiting for the response... but what shall we be waiting on? Due to the full asynchronous nature of the server, we probably want to store the request in some sort of lookup table, and then wait for the corresponding response:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;~csharp
public async Task&amp;lt;Response&amp;gt; SubmitRequestAsync(Request request)
{
    await server.SendRequestAsync(request);

    _requests[request.UniqueID] = request;

    // now what?
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We need a background task that listens on the connection and receive responses:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;~csharp
public async Task HandleResponses()
{
    while (true)
    {
        var response = await server.ReceiveResponseAsync();

        // now what?
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Still, what should the &lt;code&gt;SubmitRequestAsync&lt;/code&gt; return, that we could &lt;code&gt;await&lt;/code&gt;? And how should the &lt;code&gt;HandleResponse&lt;/code&gt; method complete the API call?&lt;/p&gt;
&lt;h4 id="taskcompletionsource"&gt;TaskCompletionSource&lt;/h4&gt;
&lt;p&gt;The &lt;code&gt;TaskCompletionSource&lt;/code&gt; is a nice feature of .NET that allows a developer to create &amp;quot;something that creates a &lt;code&gt;Task&lt;/code&gt;&amp;quot; and then explicitely decide when to complete, cancel or fail that &lt;code&gt;Task&lt;/code&gt;. Using a completion source, we can finalize our API:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;~csharp
public async Task&amp;lt;Response&amp;gt; SubmitRequestAsync(Request request)
{
    await server.SendRequestAsync(request);

    var completion = new TaskCompletionSource&amp;lt;Response&amp;gt;();

    _requests[request.UniqueID] = request;
    _completions[request.UniqueID] = completion;

    return completion.Task;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, we create a completion source, and return its &lt;code&gt;Task&lt;/code&gt;. This is a &amp;quot;logical&amp;quot; task: there is no executing code corresponding to it. It just represent &amp;quot;the execution of something&amp;quot;. And that execution would be completed by the background task:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;~csharp
public async Task HandleResponses()
{
    while (true)
    {
        var response = await server.ReceiveResponseAsync();
        var completion = _completions[response.UniqueID];
        completion.TrySetResult(response);        
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The task retrieves the completion source corresponding to the unique request identifier, and &lt;em&gt;completes&lt;/em&gt; it by assigning it a result. In a more elaborate scenario, it could also fail it by assigning it an exception, or even cancel it.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;NOTE: this is a simplified version of the code. In real life, we would need to ensure thread safety, remove requests and completions from their lookup tables, etc.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4 id="yes-but"&gt;Yes, but&lt;/h4&gt;
&lt;p&gt;We could end the article here, but... there's a &lt;em&gt;but&lt;/em&gt;. What do you think happens when &lt;code&gt;completion.TrySetResult(response)&lt;/code&gt; is invoked? Intuitively, we assume that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;TrySetResult&lt;/code&gt; returns from the call and the &lt;code&gt;while&lt;/code&gt; loop repeats;&lt;/li&gt;
&lt;li&gt;Whatever code was awaiting the completion's &lt;code&gt;Task&lt;/code&gt; is unlocked and starts running.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In other words, invoking &lt;code&gt;TrySetResults&lt;/code&gt; fork a new parallel code execution path that resumes whatever code was &lt;code&gt;await&lt;/code&gt;-ing the completion's &lt;code&gt;Task&lt;/code&gt;, while the main code execution path continues looping the &lt;code&gt;while&lt;/code&gt; loop.&lt;/p&gt;
&lt;p&gt;However—and here is the &lt;em&gt;but&lt;/em&gt;—.NET tries to optimize asynchronous calls to avoid unnecessary and expensive management of tasks and threads. You have probably heard that when invoking the following method, the call to &lt;code&gt;DoSomethingElse&lt;/code&gt; will run immediately and synchronously, and that the method will only return a &lt;code&gt;Task&lt;/code&gt; when it encounters the first &lt;code&gt;await&lt;/code&gt; statement:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;~csharp
public async Task DoSomething()
{
    DoSomethingElse();
    await DoYetAnotherThing();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It turns out that the very same thing happens with &lt;code&gt;TrySetResult&lt;/code&gt;. .NET will immediately run the code that is &lt;code&gt;await&lt;/code&gt;-ing on the completion's &lt;code&gt;Task&lt;/code&gt;, and the call to &lt;code&gt;TrySetResult&lt;/code&gt; will only complete after either that code is done running, or an &lt;code&gt;await&lt;/code&gt; statement is encountered.&lt;/p&gt;
&lt;h4 id="and-then-it-all-fails"&gt;And then it all fails&lt;/h4&gt;
&lt;p&gt;Now look at the following code:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;~csharp
public async Task HandleResponses()
{
    while (true)
    {
        var response = await server.ReceiveResponseAsync();
        AquireSemaphore();
        var completion = _completions[response.UniqueID];
        completion.TrySetResult(response);        
        ReleaseSemaphore();
    }
}

public async Task UseTheAPI()
{
    var response = await SubmitRequestAsync(request);
    AquireSemaphore();
    // do something with the response
    ReleaseSemaphore();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What do you think will happen? Spoiler: it will deadlock. The call to &lt;code&gt;TrySetResult&lt;/code&gt; will complete the &lt;code&gt;SubmitRequestAsync&lt;/code&gt; call and flow and continue the &lt;code&gt;UseTheAPI&lt;/code&gt; method. It will try to run &lt;code&gt;AquireSemaphore&lt;/code&gt; in &lt;code&gt;UseTheAPI&lt;/code&gt; &lt;em&gt;before&lt;/em&gt; returning, and will fail to get the semaphore, because it has already been acquired. It will never return, and never release the semaphore, and everything hangs.&lt;/p&gt;
&lt;p&gt;In other words: invoking &lt;code&gt;TrySetResult&lt;/code&gt; is &lt;em&gt;not&lt;/em&gt; a fire-and-forget thing. In &lt;em&gt;most cases&lt;/em&gt; it will be OK, but in some situation it can lead to deadlocks and other oddities, where &lt;em&gt;a lot&lt;/em&gt; happens between the moment &lt;code&gt;TrySetResult&lt;/code&gt; is invoked and the moment it returns.&lt;/p&gt;
&lt;h4 id="uh-what-shall-we-do"&gt;Uh, what shall we do?&lt;/h4&gt;
&lt;p&gt;In some situations, we really don't know what may be &lt;code&gt;await&lt;/code&gt;-ing the completion's &lt;code&gt;Task&lt;/code&gt;. What we want is a way to tell .NET: don't be clever. Submit whatever is &lt;code&gt;await&lt;/code&gt;-ing to the thread pool and return immediately. Run it all on separate tasks. It &lt;em&gt;may&lt;/em&gt; be a little more expensive, but at least invoking &lt;code&gt;TrySetResult&lt;/code&gt; would become deterministic.&lt;/p&gt;
&lt;p&gt;There &lt;em&gt;is&lt;/em&gt; an option to do this, but it is not a &lt;code&gt;TrySetResult&lt;/code&gt; option. Instead, it needs to be specified when creating the completion souce. The class constructor has an overload that supports a &lt;code&gt;TaskCreationOptions&lt;/code&gt; that can be used to indicate how the tasks resulting from &lt;code&gt;TrySetResult&lt;/code&gt; are supposed to run.&lt;/p&gt;
&lt;p&gt;Especially, &lt;code&gt;TaskCreationOptions.RunContinuationsAsynchronously&lt;/code&gt; specifies that &amp;quot;continuations added to the current task [are] to be executed asynchronously.&amp;quot; We can create our continuation as such:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;~csharp
var completion = new TaskCompletionSource&amp;lt;Response&amp;gt;(
    TaskCreationOptions.RunContinuationsAsynchronously
);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When &lt;code&gt;TrySetResult&lt;/code&gt; is invoked, it submits all the continuations on the completion's &lt;code&gt;Task&lt;/code&gt; (i.e. all code &lt;code&gt;await&lt;/code&gt;-ing that task) on the thread pool for execution, instead of running them, and returns immediately.&lt;/p&gt;
&lt;h4 id="nice-why-is-this-not-the-default"&gt;Nice, why is this not the default?&lt;/h4&gt;
&lt;p&gt;Because in most cases, this is an overkill. Whenever &lt;code&gt;TaskCompletionSource&lt;/code&gt; instances are used in simple and controlled environment, everything &lt;em&gt;should&lt;/em&gt; be OK and it's better to let .NET optimize everything.&lt;/p&gt;
&lt;p&gt;Nevertheless, it is good to be aware of this pitfall.&lt;/p&gt;
</description>
      <pubDate>Sun, 14 May 2023 16:00:00 Z</pubDate>
      <a10:updated>2023-05-14T16:00:00Z</a10:updated>
      <a10:rights type="html">Copyright &amp;copy; 1985-2026 Stéphane Gay</a10:rights>
    </item>
    <item>
      <guid isPermaLink="false">11361</guid>
      <link>https://www.zpqrtbnk.net/posts/faster-github-pr-check-time-with-multi-level-matrix-strategy/</link>
      <author>sgay@pilotine.com</author>
      <category>dotnet</category>
      <title>Faster GitHub PR check time with multi-level matrix strategy</title>
      <description>&lt;p&gt;The Hazelcast .NET&lt;a id="fnref:1" href="#fn:1" class="footnote-ref"&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt; Client is provided as a library that is supported on .NET (Framework) version 4.6.2 to 4.8, .NET (Core) 3.1, and .NET (Just .NET) 5.0 and 6.0. For .NET Core and Just .NET, the library is supported both on Windows and on Linux. This means that we want to run our complete tests suite on both platforms, for each supported .NET version.&lt;/p&gt;
&lt;p&gt;Originally, we defined a &lt;em&gt;Build PR&lt;/em&gt; workflow that would trigger on each PR and build and run the tests for each .NET version supported by the platform, one after another. In order to test both platforms, we used an OS matrix strategy:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;name: Build PR
on: pull_request

jobs:
  build-pr:
    name: Build PR (${{ matrix.os }})
    runs-on: ${{ matrix.os }}

    strategy:
      fail-fast: false
      matrix:
        os: [ ubuntu-latest, windows-latest ]

    steps:
    - name: Build and Test the PR
      (etc)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Thanks to this, on each PR, two jobs would run in parallel: one for Linux, and one for Windows. However, on each platform, the tests for each .NET version would run sequentially. And thus... if the complete tests suite takes about 20 minutes to run, the Windows job would take &lt;code&gt;net462&lt;/code&gt; + &lt;code&gt;net48&lt;/code&gt; + &lt;code&gt;netcoreapp3.1&lt;/code&gt; + &lt;code&gt;net5.0&lt;/code&gt; + &lt;code&gt;net6.0&lt;/code&gt; = 5 times 20 minutes, or 1h40. Which is quite a lot of time to validate a PR.&lt;/p&gt;
&lt;h4 id="entering-the-second-dimension"&gt;Entering the Second Dimension&lt;/h4&gt;
&lt;p&gt;We want to reduce that time, and the idea is to parallelize each .NET version, in addition to platforms. On each PR, we would fork one job for .NET 5.0 on Linux, one job for .NET 6.0 on Linux, one job for .NET 4.8 on Windows, etc. The total build time would be approximatively the build time of &lt;em&gt;one&lt;/em&gt; version or, in our example above, 20 minutes instead of 1h40.&lt;/p&gt;
&lt;p&gt;GitHub supports 2-dimensions matrixes. For instance:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    matrix:
      os: [ ubuntu-latest, windows-latest ]
      dotnet: [ net5.0, net6.0 ]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In our situation, however, the list of versions to put in the &lt;code&gt;dotnet&lt;/code&gt; dimension if not fixed and actually depends on the OS. We would need to write something akin to the following code, where &lt;code&gt;get_dotnet_version&lt;/code&gt; would be a function returning the .NET version corresponding to the OS:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    matrix:
      os: [ ubuntu-latest, windows-latest ]
      dotnet: get_dotnet_versions(matrix.os)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Alas, GitHub does not support that type of construct. The only thing it supports is referencing a variable, such as an input, in the matrix. So we would need to be able to produce a unique variable, and yet its value would depend on &lt;code&gt;matrix.os&lt;/code&gt;... again, that type of construct is not supported. All in all, I could not find a way to get one matrix dimension to depend on the other, within one workflow.&lt;/p&gt;
&lt;h4 id="divide-and-conquer"&gt;Divide and Conquer&lt;/h4&gt;
&lt;p&gt;Now... what-if instead of trying to do everything in one workflow, we used two? Our first workflow looks like:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;jobs:
  getversions:
    runs-on: ${{ matrix.os }}

    strategy:
      matrix:
        os: [ ubuntu-latest, windows-latest ]

    outputs:
      # beware! this cannot be dynamic = must match the OS matrix
      versions-ubuntu-latest: ${{ steps.getversions.outputs.versions-ubuntu-latest }}
      versions-windows-latest: ${{ steps.getversions.outputs.versions-windows-latest }}

    steps:
    - name: Determine DotNet Versions
      id: getversions
      shell: bash
      run: |
        VERSIONS=$(....)
        echo &amp;quot;::set-output name=versions-${{ matrix.os }}::$VERSIONS&amp;quot;

  buildtest:
    name: Build&amp;amp;Test ${{ matrix.os }}
    needs: getversions
    strategy:
      fail-fast: false
      matrix:
        os: [ ubuntu-latest, windows-latest ]
    uses: ./.github/workflows/build-pr-on.yml
    secrets: inherit
    with:
      os: ${{ matrix.os }}
      versions: ${{ needs.getversions.outputs[format('versions-{0}', matrix.os)] }}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let's go through this workflow. It contains two jobs, &lt;code&gt;getversions&lt;/code&gt; and &lt;code&gt;buildtest&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The first job, &lt;code&gt;getversions&lt;/code&gt;, runs a unique step that determines the versions based on the platform, and sets a job output variable accordingly. That variable contains a JSON list of versions, e.g. &lt;code&gt;[ &amp;quot;net462&amp;quot;, &amp;quot;net48&amp;quot; ]&lt;/code&gt;. Actually, it sets one job output per platform, and I could not find a way to avoid hard-coding the platform names.&lt;/p&gt;
&lt;p&gt;The second job, &lt;code&gt;buildtest&lt;/code&gt;, does not run any steps, but instead triggers another workflow, passing two input parameters: the platform, and the list of versions. And &lt;em&gt;this&lt;/em&gt; is where we manage to specify versions that depend on the platform.&lt;/p&gt;
&lt;p&gt;And then, the magic happens in that other workflow. First, in order to be &amp;quot;callable&amp;quot; with input parameters, it requires this &lt;code&gt;on&lt;/code&gt; statement:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;on: 
  workflow_call:
    inputs:
      os:
        required: true
        type: string
      versions:
        required: true
        type: string
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And then its job is defined as:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;jobs:
  buildtest:
    name: ${{ matrix.fwk }}
    runs-on: ${{ inputs.os }}
    strategy:
      fail-fast: false
      matrix:
        version: ${{ fromJson(inputs.versions) }}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And there we have it: a build and test job that runs on the specified platform, for each specified versions. The last piece of the puzzle consists in wrapping in all into one single conclusion point. This is done via an additional job in the first workflow:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;report:
    name: Build&amp;amp;Test Result
    runs-on: ubuntu-latest
    if: always()
    needs: buildtest
    steps:
    - name: report
      shell: bash
      run: |
        if [ &amp;quot;${{ needs.buildtest.conclusion }}&amp;quot; == &amp;quot;success&amp;quot; ]; then
          echo &amp;quot;All Build&amp;amp;Test checks completed successfully.&amp;quot;
        else
          echo &amp;quot;At least one Build&amp;amp;Test check has failed.&amp;quot;
          echo &amp;quot;::error::At least one Build&amp;amp;Test check has failed.&amp;quot;
        fi
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This job &amp;quot;needs&amp;quot; the &lt;code&gt;buildtest&lt;/code&gt; job, in other words it will only run once all our forked build &amp;amp; test jobs have completed. It always run, and succeeds or fails depending on the outputs of all the forked jobs. This means that this is what we see in GitHub actions:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.zpqrtbnk.net/imgx/2ccik3do/sshot-mw-600.png?hmac=f80270f36a51bcb6457d750917d536f75af92cc6672d4a0927cb8e63cc0756e3" alt="Sshot" alt="img" /&gt;&lt;/p&gt;
&lt;p&gt;The block to the left shows the two jobs that run, on per platform, and figure out the framework versions for each platform. The center block shows each combination of platform / version build - they all run in parallel. Finally, the block to the right shows the global status of the build.&lt;/p&gt;
&lt;p&gt;That last &amp;quot;Build&amp;amp;Test Result&amp;quot; block can be used as a required check in our GitHub branch configuration, thus ensuring that &lt;em&gt;all&lt;/em&gt; test combinations must be successful before any PR can be merged.&lt;/p&gt;
&lt;p&gt;All in about 20 minutes, not 1h40!&lt;/p&gt;
&lt;div class="footnotes"&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;or maybe it is the &amp;quot;Hazelcast dotnet Client&amp;quot; or &amp;quot;Hazelcast Dotnet Client&amp;quot;, depending on the success of the &lt;a href="https://twitter.com/hashtag/dropthedot"&gt;#dropTheDot&lt;/a&gt; movement initiated by &lt;a href="https://twitter.com/buhakmeh"&gt;Khalid&lt;/a&gt; at a time the .NET Drama Advisory (or should it be the Dotnet Drama Advisory) was pretty low and he got bored.&lt;a href="#fnref:1" class="footnote-back-ref"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
</description>
      <pubDate>Mon, 26 Sep 2022 12:40:00 Z</pubDate>
      <a10:updated>2022-09-26T12:40:00Z</a10:updated>
      <a10:rights type="html">Copyright &amp;copy; 1985-2026 Stéphane Gay</a10:rights>
    </item>
    <item>
      <guid isPermaLink="false">11322</guid>
      <link>https://www.zpqrtbnk.net/posts/tales-of-fpga-road-to-sdram-e03/</link>
      <author>sgay@pilotine.com</author>
      <category>hacks</category>
      <title>Tales of FPGA - Road to SDRAM - E03</title>
      <description>&lt;p&gt;This post is the third one of a serie which starts with &lt;a href="https://www.zpqrtbnk.net/posts/tales-of-fpga-road-to-sdram-e01/"&gt;Episode 1&lt;/a&gt;, in which we have presented what FPGA are and how to control them, and continues with &lt;a href="https://www.zpqrtbnk.net/posts/tales-of-fpga-road-to-sdram-e02/"&gt;Episode 2&lt;/a&gt;, in which we have discovered the importance of &lt;em&gt;time&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;The ultimate goal of this serie of posts is to provide a simple working example of a design that can reliably access the SDRAM chip on a &lt;a href="https://digilent.com/reference/programmable-logic/arty-s7/start"&gt;Digilent Arty S7&lt;/a&gt; FPGA development board.&lt;/p&gt;
&lt;p&gt;In order to understand &lt;em&gt;why&lt;/em&gt; we want to access that chip, let us first review the different types of RAM that can exist in a computer.&lt;/p&gt;
&lt;h4 id="sram"&gt;SRAM&lt;/h4&gt;
&lt;p&gt;The first and most simple memory type is &lt;em&gt;Static Random Access Memory&lt;/em&gt; (SRAM). It is an array of memory cells and exposes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;An &lt;em&gt;address bus&lt;/em&gt; which selects the cell&lt;/li&gt;
&lt;li&gt;A &lt;em&gt;data bus&lt;/em&gt; which contains the value to write, or the value that was read&lt;/li&gt;
&lt;li&gt;A &lt;em&gt;RW&lt;/em&gt; signal which indicates whether to read or write&lt;/li&gt;
&lt;li&gt;A &lt;em&gt;clock&lt;/em&gt; signal&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;On each clock signal, depending on the RW signal, the cells specified by the address bus are updated with the value specified by the data bus, &lt;em&gt;or&lt;/em&gt; the data bus is updated with the value contained by the specified cells.&lt;/p&gt;
&lt;p&gt;Each cell (i.e. each bit) is implemented with about six transistors, and is stable, or &lt;em&gt;static&lt;/em&gt;: it keeps its value around for as long as power is supplied. Circuitry is minimal, and it is &lt;em&gt;fast&lt;/em&gt;, as in: it can typically keep up with the CPU speed. In other words, the CPU can request a value on a clock tick, and read that value on the next clock tick.&lt;/p&gt;
&lt;h4 id="sdram"&gt;(S)DRAM&lt;/h4&gt;
&lt;p&gt;Unfortunately, due to their transistors count, SRAM cells require a &lt;em&gt;lot&lt;/em&gt; (relatively) of silicon, which implies low density and high costs. For instance, a modern Intel Core i9 CPU carries only about 90KB of SRAM L1 cache per core.&lt;/p&gt;
&lt;p&gt;In order to increase density and lower costs, cells have to be simplified down to the simplest cell, which is composed of only one transistor and one capacitor: this type of cell is at the core of most modern memory types.&lt;/p&gt;
&lt;p&gt;Its drawback is that it is not stable: its capacitor charge leaks and the cell loses its value after a while. Additional circuitry is therefore required to refresh (i.e. access) it periodically. Hence the name: &lt;em&gt;Dynamic Random Access Memory&lt;/em&gt; (DRAM).&lt;/p&gt;
&lt;p&gt;Due to their need to be refreshed, but also their density, DRAM have a different and more complex interface. Cells are organized in &lt;em&gt;banks&lt;/em&gt; and &lt;em&gt;rows&lt;/em&gt; and &lt;em&gt;columns&lt;/em&gt;, which must be selected before any read or write can take place. A read or a write now takes several clock ticks, and more control lines determine which operation to achieve.&lt;/p&gt;
&lt;p&gt;Simple, original DRAM operated asynchronously with the CPU's clock. In order to increase efficiency and throughput, they evolved into &lt;em&gt;Synchronized DRAM&lt;/em&gt; (SDRAM) where everything is timed by the CPU. This allows for more optimizations such as pipelining: for instance, selecting the rows and columns of the next read, while receiving data for the previous read.&lt;/p&gt;
&lt;h4 id="ddr-sdram"&gt;DDR SDRAM&lt;/h4&gt;
&lt;p&gt;In order to further increase the memory bandwidth and reduce latency, the frequency of the data line would need to increase. However, a higher frequency means more energy consumption and heat—this is the issue faced by all CPUs today.&lt;/p&gt;
&lt;p&gt;To mitigate these side effects, &lt;em&gt;Double Data Rate (DDR) SDRAM&lt;/em&gt; were introduced: they keep the same frequency, but transfer data on each &lt;em&gt;edge&lt;/em&gt; of the clock, not only on each clock cycle, thus doubling the bandwidth.&lt;/p&gt;
&lt;p&gt;DDR was followed by DDR2, DDR3, etc. standards which add more &amp;quot;tricks&amp;quot; to the SDRAM interface, such as burst reads &amp;amp; writes, all in order to increase the speed of memories.&lt;/p&gt;
&lt;p&gt;Nevertheless, and despite all optimizations, SDRAM simply cannot keep up with modern CPU speeds anymore. The CPU cannot expect to request a value, and get it on the next clock tick, as it did with SRAM when computers had only a few KB of RAM. Modern CPU have to rely on various levels of caches and all sorts of optimizations in order to remain busy while waiting for memory reads and writes.&lt;/p&gt;
&lt;h4 id="fpga-ram"&gt;FPGA RAM&lt;/h4&gt;
&lt;p&gt;Now that we have reviewed the different types of memories, let us consider what exists on our FPGA board:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The FPGA chip itself contains some SRAM blocks that can run as fast as the rest of the chip. We have however seen that SRAM is expensive: our FPGA chip carries only about 338KB of RAM.&lt;/li&gt;
&lt;li&gt;A separate chip on the board (the same chip you would find in a PC) provides 256MB of DDR3 SDRAM.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Accessing the SRAM blocks is relatively easy. Once instantiated in a design, one &amp;quot;just&amp;quot; needs to drive the address and data busses correctly. And, it is fast. Alas, the total available capacity is quite small.&lt;/p&gt;
&lt;p&gt;Which leads us to the SDRAM chip. However, accessing that chip is an entirely different story, and the DDR3 protocol is a &lt;em&gt;complex beast&lt;/em&gt; to implement. That will be the topic of the next post.&lt;/p&gt;
</description>
      <pubDate>Tue, 13 Sep 2022 12:00:00 Z</pubDate>
      <a10:updated>2022-09-13T12:00:00Z</a10:updated>
      <a10:rights type="html">Copyright &amp;copy; 1985-2026 Stéphane Gay</a10:rights>
    </item>
    <item>
      <guid isPermaLink="false">11320</guid>
      <link>https://www.zpqrtbnk.net/posts/tales-of-fpga-road-to-sdram-e02/</link>
      <author>sgay@pilotine.com</author>
      <category>hacks</category>
      <title>Tales of FPGA - Road to SDRAM - E02</title>
      <description>&lt;p&gt;This post is the second one of a serie which starts with &lt;a href="https://www.zpqrtbnk.net/posts/tales-of-fpga-road-to-sdram-e01/"&gt;Episode 1&lt;/a&gt;, in which we have presented what FPGA are, how to control them, and implicitly discovered their major benefit: they make the physical world rational and clean.&lt;/p&gt;
&lt;p&gt;Indeed, the physical world a.k.a. &amp;quot;reality&amp;quot; is notoriously messy, as anyone who has tried to implement some design with discrete electronic components knows.&lt;/p&gt;
&lt;p&gt;For instance, should we decide that &amp;quot;zero&amp;quot; is +0V and &amp;quot;one&amp;quot; is +5V... there are chances that the transistor-based AND gate that we carefully assembled on our breadboard outputs +4.8V for &amp;quot;one&amp;quot; and not +5V because, imperfections. If we feed that signal into anoter gate, it will &lt;em&gt;probably&lt;/em&gt; be identified as &amp;quot;one&amp;quot;. But if we keep doing this, then at one point we will end up with a +2.6V signal and what is that supposed to mean exactly? &amp;quot;Zero&amp;quot;, or &amp;quot;one&amp;quot;? Our design lacks additional circuitry to ensure that we maintain the correct signal levels everywhere, we feed enough current, etc.&lt;/p&gt;
&lt;p&gt;Another example: these 30 cm of wire flying over our breadboard and carrying a signal at, say, 100MHz? It is an &lt;em&gt;antenna&lt;/em&gt; in the FM radio frequencies. It is going to broadcast that signal, as well as be impacted by existing radio signals on that frequency. Our design may randomly fail and, if carefully examining signals with a scope, we would see all sorts of very weird distortions.&lt;/p&gt;
&lt;p&gt;FPGA have none of this: they are clean and reproducible. We write text files, have them processed by a tool, and end up with a hardware-level design that just works. If we make a mistake, there is no need for rewiring things, going to the shop to buy that one component we are missing, etc. We do not have to worry about radio interferences, current leaks, etc.&lt;/p&gt;
&lt;p&gt;With FPGA, the physical world becomes deterministic.&lt;/p&gt;
&lt;h4 id="meet-the-enemy"&gt;Meet the Enemy&lt;/h4&gt;
&lt;p&gt;And yet, the FPGA designer has one enemy, and this enemy is &lt;em&gt;time&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;It is convenient to think of a LUT2 as something that immediately updates its output according to its inputs. In reality, it is &lt;em&gt;almost&lt;/em&gt; immediate. In the FPGA chip we are using (a Xilinx Spartan-7 family chip), the delay would be around .15ns or &lt;strong&gt;150ps&lt;/strong&gt;. A flip-flop has a delay of about .55ns or &lt;strong&gt;550ps&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Sure, 150ps is 0.000 000 000 150s and this is &lt;em&gt;very small&lt;/em&gt;. Yet, the period of a 4GHz signal—a value one can meet in modern CPUs—is &lt;strong&gt;250ps&lt;/strong&gt;: a very small value too, but one which is very comparable, in scale, to the above delay.&lt;/p&gt;
&lt;p&gt;It is also convenient to think of connections betweens elements as pure electric wires, carrying signals at the speed of light. In reality, signals travels the FPGA die at a slower speed, because connections are not just true electric wires. And then even at the speed of light, electricity only travels about 30cm per ns, or &lt;strong&gt;3mm in 10ps&lt;/strong&gt;, and considering the size of a typical chip die, 3mm might be the distance separating two LUTs.&lt;/p&gt;
&lt;p&gt;Let us see what this means with an example.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.zpqrtbnk.net/imgx/id3kwicj/adder-mw-600.png?hmac=420b704c9858eb1bd87a604344928b896c517fe402b80f4bb1bd2c06ae3da04b" alt="Adder" alt="adder" /&gt;&lt;/p&gt;
&lt;p&gt;This circuit increments a two-bits signal on every clock tick. The new square boxes are &lt;em&gt;flip-flops&lt;/em&gt;: they update their output (the &lt;code&gt;Q&lt;/code&gt; port) to reflect the value of their input (the &lt;code&gt;D&lt;/code&gt; port) on each raising edge of their clock (the &lt;code&gt;C&lt;/code&gt; port). So &lt;code&gt;count&lt;/code&gt; will go &lt;code&gt;00&lt;/code&gt;, &lt;code&gt;01&lt;/code&gt;, &lt;code&gt;10&lt;/code&gt;, &lt;code&gt;11&lt;/code&gt;, &lt;code&gt;00&lt;/code&gt;, &lt;code&gt;01&lt;/code&gt;, etc. each time the clock ticks.&lt;/p&gt;
&lt;p&gt;More precisely, when the clock ticks,&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Flip-flops update their output to match their input after about .55ns&lt;/li&gt;
&lt;li&gt;Gates update their output to match their inputs after about .15ns&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So, &lt;code&gt;count_next[1]&lt;/code&gt; will reach its new value after .55 + .15 + .15 = .85ns. This is called the &lt;em&gt;&lt;a href="https://nandland.com/lesson-11-what-is-propagation-delay/"&gt;propagation delay&lt;/a&gt;&lt;/em&gt;. And still, we cannot tick the clock immediately, because the flip-flops demand that the input be stable for some amount of time before the clock ticks: this is call the &lt;em&gt;&lt;a href="https://nandland.com/lesson-12-setup-and-hold-time/"&gt;setup time&lt;/a&gt;&lt;/em&gt;. It is about .05ns in our case. And thus, the clock can only ticks again after .9ns have elapsed.&lt;/p&gt;
&lt;p&gt;We are ignoring the connection delays here. So, let's round it all to &lt;strong&gt;1ns&lt;/strong&gt;. This corresponds to a frequency of &lt;strong&gt;1GHz&lt;/strong&gt;. Not too bad, but this is a &lt;em&gt;very simple&lt;/em&gt; circuit.&lt;/p&gt;
&lt;p&gt;Very quickly, things get complex, and the maximum frequency can fall down to 100MHz or even 10MHz. If we do not respect that constraint, things become completely unpredictable. If we are only slightly too fast, we might not respect the setup time, thus creating a situation called &lt;em&gt;&lt;a href="https://nandland.com/lesson-13-metastability/"&gt;metastability&lt;/a&gt;&lt;/em&gt;: the data coming out of flip-flops may be randomly wrong. And of course, if we are &lt;em&gt;really&lt;/em&gt; too fast, everything becomes random.&lt;/p&gt;
&lt;h4 id="know-thy-enemy"&gt;Know Thy Enemy&lt;/h4&gt;
&lt;p&gt;Tools such as the Vivado IDE do not simply convert code into a network of LUTs, flip-flops, etc. They also decide &lt;em&gt;which&lt;/em&gt; elements to use on the chip (which can contain a few thousands LUTs, for instance), trying to minimize the &lt;em&gt;physical distance&lt;/em&gt; between elements. And then, they process the resulting network and calculate all the propagation times and finaly issue a &lt;em&gt;timing report&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Take the LED blinker from the previous episode. We would tell Vivado that the clock signal comes from &amp;quot;outside&amp;quot; of the chip, actually an oscillator on the development board, which runs at 12MHz. Vivado would report that at 12MHz, everything is fine. There is another oscillator on the board, which runs at 100MHz, and that should be OK too.&lt;/p&gt;
&lt;p&gt;But imagine we have a 1GHz clock on the board: Vivado would definitively build the design (which we can then push to the board) but it would also issue timing warnings, telling us that our design has little chance to work.&lt;/p&gt;
&lt;p&gt;When that happens, for instance when we try to run our carefully crafted CPU at 10MHz and Vivado complains about timings, there are essentially two solutions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Slow the clock. Not very satisfactory, but simple enough&lt;/li&gt;
&lt;li&gt;Refactor the design, maybe doing less per clock cycle (see: &lt;a href="https://www.allaboutcircuits.com/technical-articles/why-how-pipelining-in-fpga/"&gt;pipelining&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="were-we-not-supposed-to-talk-about-sdrams"&gt;Were we not supposed to talk about SDRAMs?&lt;/h4&gt;
&lt;p&gt;We were, but that little disgression about time will prove useful in the next episode, where we will present the different types of RAM and see how RAM is essentially dictating time constraints in a modern design.&lt;/p&gt;
&lt;p&gt;To be continued!&lt;/p&gt;
</description>
      <pubDate>Tue, 16 Aug 2022 19:00:00 Z</pubDate>
      <a10:updated>2022-08-16T19:00:00Z</a10:updated>
      <a10:rights type="html">Copyright &amp;copy; 1985-2026 Stéphane Gay</a10:rights>
    </item>
    <item>
      <guid isPermaLink="false">11314</guid>
      <link>https://www.zpqrtbnk.net/posts/tales-of-fpga-road-to-sdram-e01/</link>
      <author>sgay@pilotine.com</author>
      <category>hacks</category>
      <title>Tales of FPGA - Road to SDRAM - E01</title>
      <description>&lt;p&gt;This post is the first one of a serie, which aims at providing a simple working example of a design that can reliably access the SDRAM chip on a &lt;a href="https://digilent.com/reference/programmable-logic/arty-s7/start"&gt;Digilent Arty S7&lt;/a&gt; FPGA development board. Indeed, although this board has been out for quite some time now, such a design seems practically impossible to find on the 'net, for reasons we will try to analyze.&lt;/p&gt;
&lt;p&gt;I also mean this serie to be an introduction to FPGA for people who have little idea what they actually are nor how they work. So, even if you do not care about accessing SDRAM on that particular board, you may find it an interesting read. In fact, my interest in FPGA owes a lot to the fact that they help understand the inner working of a CPU, a RAM, and any modern computer.&lt;/p&gt;
&lt;h4 id="arty-s7"&gt;Arty S7?&lt;/h4&gt;
&lt;p&gt;The Arty S7 is an FPGA development board based upon Xilinx' &lt;a href="https://www.xilinx.com/products/silicon-devices/fpga/spartan-7.html"&gt;Spartan-7&lt;/a&gt; series of FPGA chips. It is a cost-effective design packing an FPGA chip, DDR3L memory, buttons, leds, I/O and expansion ports... everything you need to experiment with an FPGA at a reasonable cost (around USD 100.00).&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.zpqrtbnk.net/imgx/d0ikhskl/arty-s7-fit-600x300x1x1-0x0x0x0-75.jpg?hmac=4e9ae5a8b157928fa6adfa0ce49f346760037f1d60a96d2a79efd49bee7c9efe" alt="Arty S7" alt="AND gate" /&gt;&lt;/p&gt;
&lt;p&gt;In a way, it is similar to an Arduino board, with the CPU replaced by the FPGA chip.&lt;/p&gt;
&lt;h4 id="and-what-is-an-fpga-chip"&gt;And what is an FPGA chip?&lt;/h4&gt;
&lt;p&gt;An FPGA is a &lt;a href="https://en.wikipedia.org/wiki/Field-programmable_gate_array"&gt;Field Programmable Gate Array&lt;/a&gt;: a semiconductor device based around a matrix of configurable logic blocks, connected via programmable interconnects. The most basic logic block would be, for instance, an AND gate:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.zpqrtbnk.net/imgx/er1fyvcx/and-gate-mw-600.png?hmac=1cb7385922a9b5071ee96e3411a175d76f66a9d32b96a7399da18718ed82287e" alt="And Gate" alt="AND gate" /&gt;&lt;/p&gt;
&lt;p&gt;When any of the gate inputs change, the output is adjusted, after a short inevitable delay. This type of gate can be implemented with a few transistors, and along with the other OR, XOR... gates they are the basic elements of all silicon-based operations.&lt;/p&gt;
&lt;p&gt;In reality, FPGA do not implement AND gates, and their most basic logic block would rather be a &lt;em&gt;2-bit look-up table&lt;/em&gt;, or LUT2. It also has two inputs and one output, and updates its output according to its inputs. But the value of the output is specified by a 2x2 logic table. This way, one single block can be configured to be an AND, OR, XOR... gate.&lt;/p&gt;
&lt;p&gt;And then there are LUT4, LUT6... which follow the same principle only with more inputs. You would also find &lt;a href="https://en.wikipedia.org/wiki/Flip-flop_(electronics)"&gt;flip-flops&lt;/a&gt; which can latch a stable state on a clock signal, oscillators, some type of memories, etc. that you can all configure in the same way one configures the logic table of a LUT2.&lt;/p&gt;
&lt;p&gt;All these blocks are layed out in precise positions on the die of the FPGA chip. And then, there is an interconnect layer which can be configured to wire (pratically) any block input or output with any other block input or output. So you could configure a LUT2 as an AND gate, and wire its output to the input of another LUT2 configured as an OR gate, etc.&lt;/p&gt;
&lt;p&gt;The whole configuration is represented as a blob of binary data which needs to be fed to the FPGA before it can operates. Traditionally, some additional hardware on the development board handle this process and read this blob from Flash memory, or allow the developer to upload it via an USB link.&lt;/p&gt;
&lt;h4 id="taking-control"&gt;Taking Control&lt;/h4&gt;
&lt;p&gt;FPGA manufacturers provide tools and development environments that let users configure their chips. &lt;a href="https://www.xilinx.com/"&gt;Xilinx&lt;/a&gt;, a major FPGA actor owned by AMD, even have several of them, the most popular (and having a free edition) being the &lt;a href="https://www.xilinx.com/products/design-tools/vivado.html"&gt;Vivado&lt;/a&gt; IDE. These tools support various description languages such as &lt;a href="https://en.wikipedia.org/wiki/VHDL"&gt;VHDL&lt;/a&gt; or &lt;a href="https://en.wikipedia.org/wiki/Verilog"&gt;Verilog&lt;/a&gt; or its &lt;a href="https://en.wikipedia.org/wiki/SystemVerilog"&gt;SystemVerilog&lt;/a&gt; evolution. These languages are used to specify the FPGA internal configuration, as a set of text files.&lt;/p&gt;
&lt;p&gt;The &lt;em&gt;major&lt;/em&gt; difference with traditional programming languages is that all these elements and signals and connections operate concurrently. An FPGA design is a &lt;em&gt;massively parallel&lt;/em&gt; thing.&lt;/p&gt;
&lt;p&gt;This post is certainly not a VHDL nor Verilog tutorial. Let us just say that it all begins with a &lt;em&gt;module&lt;/em&gt; which has inputs and outputs (connected to the actual external pins of the FPGA), along with internal signals, and defines connections between these signals. The following module would for instance act as an AND gate:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;module and_gate (
    input logic in_0,
    input logic in_1,
    output logic out
);

    LUT2 #(
        .INIT (4'b1000)    // define the logic table
    )
    LUT2_inst (
        .I0 (in_0),        // wire module input in_0 to LUT2 input I0
        .I1 (in_1),        // wire module input in_1 to LUT2 input I1
        .O (out)           // wire LUT2 output 0 to module output out
    );

endmodule
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The LUT2 logic table is documented as being a 4-bit value with the higher-rank bit (left-most) representing the output value when both inputs are &lt;code&gt;1&lt;/code&gt;, and thus, our LUT2 will act as an AND gate.&lt;/p&gt;
&lt;p&gt;Vivado can then &amp;quot;compile&amp;quot; this design, provided that you also tell it how to wire the inputs and outputs of the module. For instance, inputs could be wired to buttons, and outputs to LEDs. The compiler will determine &lt;em&gt;which&lt;/em&gt; LUT2 to use on the board, and produce the FPGA configuration binary blob, that Vivado can feed to the board via USB. There, done, our first design!&lt;/p&gt;
&lt;p&gt;However, Verilog (the language) is way more clever than that. It does not merely &amp;quot;compile&amp;quot; the design, but &lt;em&gt;synthesize&lt;/em&gt; it. It can infer which blocks to use, depending on logical syntax. Noone would ever write a module such as the one above. Instead, one would simply write the following code:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;module and_gate (
    input logic in_0,
    input logic in_1,
    output logic out
);

    assign out = in_0 &amp;amp; in_1;

endmodule
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The tools would determine that you are assigning &lt;code&gt;out&lt;/code&gt; to be the logical &lt;code&gt;AND&lt;/code&gt; between &lt;code&gt;in_0&lt;/code&gt; and &lt;code&gt;in_1&lt;/code&gt;, and that the most convenient block to achieve this is a LUT2. It could as well understand that you want to add two 8-bit numbers, and select and wire together the relevant blocks: a large combination of LUTs maybe, unless the FPGA provides some built-in adder blocks.&lt;/p&gt;
&lt;p&gt;In fact, most designs only explicitly instantiate complex blocks (clocks, memories...) but usually let the language deal with the rest (LUTs, flip-flops...).&lt;/p&gt;
&lt;h4 id="the-obligatory-led-blinker"&gt;The Obligatory LED Blinker&lt;/h4&gt;
&lt;p&gt;The following module accepts a clock logic signal as an input, produces a LED logic signal as an output, and would toggle that LED signal periodically, thus blinking the LED.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;module testbench (
    input  logic clk,   // the logical input clock signal
    output logic led    // the logical output signal controlling the LED
);
    localparam COUNT_WIDTH = 8;

    // count and next_count are a multiple-bits signals of width COUNT_WIDTH
    var logic [COUNT_WIDTH-1:0] count, next_count;

    initial count = 0;

    // the next_count signal continuously updates to be count + 1
    // it's only bits: when count reaches its max value, it wraps to zero
    assign next_count = count + 1;

    // the led signal continuously reflects the highest bit of the count signal
    assign led = count[COUNT_WIDTH-1];

    // on each raising edge of the clk signal,
    // update the count signal with its next value
    always @ (posedge clk) count &amp;lt;= next_count;

endmodule
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Things defined as &lt;code&gt;var&lt;/code&gt; are internal signals, similar to a wire connecting blocks.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;assign&lt;/code&gt; statement means: the signal on the left-hand side of the &lt;code&gt;=&lt;/code&gt; sign should constantly reflect the result of the expression on the right-hand site. They would probably be implemented with LUTs.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;always @ (posedge clk)&lt;/code&gt; means: the signals on the left-hand side of the &lt;code&gt;&amp;lt;=&lt;/code&gt; signs should be updated to reflect the result of the expressions on the right-hand sign, on each raising edge of the &lt;code&gt;clk&lt;/code&gt; signal. They would probably be implemented with a combination of LUTs and flip-flops.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;count&lt;/code&gt; is an array of bits, containing &lt;code&gt;COUNT_WIDTH&lt;/code&gt; bits. It is constantly incremented. If &lt;code&gt;COUNT_WITH&lt;/code&gt; is 2, then &lt;code&gt;count&lt;/code&gt; would be &lt;code&gt;00&lt;/code&gt;, &lt;code&gt;01&lt;/code&gt;, &lt;code&gt;10&lt;/code&gt;, &lt;code&gt;11&lt;/code&gt;, &lt;code&gt;00&lt;/code&gt;, &lt;code&gt;01&lt;/code&gt;, etc. and its highest bit would be 0 half of the time, and 1 the other half.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Assuming you tell Vivado to wire the &lt;code&gt;clk&lt;/code&gt; input to the on-board physical clock, and the &lt;code&gt;led&lt;/code&gt; output to a LED, and if you configure &lt;code&gt;COUNT_WIDTH&lt;/code&gt; correctly as per the &lt;code&gt;clk&lt;/code&gt; signal frequency... this should blink the LED on the board.&lt;/p&gt;
&lt;h4 id="or-maybe-not"&gt;Or Maybe Not&lt;/h4&gt;
&lt;p&gt;And then what? There is no way you can plug a debugger into the FPGA. Remember, there is no &amp;quot;code&amp;quot; executing: everything is happening at hardware, electrical level, and you cannot inspect what happens at silicon level. For very large designs, Xilinx &lt;em&gt;does&lt;/em&gt; provide some methods to add analysis features to your design and actually extract the value of some signals, but they are rather cumbersome and intrusive.&lt;/p&gt;
&lt;p&gt;It is all a black box.&lt;/p&gt;
&lt;p&gt;All you can do is go back to your design, and think.&lt;/p&gt;
&lt;p&gt;On the other hand, FPGA tools such as the Vivado IDE can &lt;em&gt;simulate&lt;/em&gt; a design, i.e. emulate the complete behavior of the elements, all within the PC memory. Vivado comes with a virtual logic analyzer, which shows the signals in details. Here is an example of waveforms it can produce.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.zpqrtbnk.net/imgx/5fujw43s/led-wave-2-mw-600.png?hmac=666ec7bde8547b15e7a84ccb52c6c445e94e255212ee0d7e4cb0d3c234badaf8" alt="Led Wave" alt="AND gate" /&gt;&lt;/p&gt;
&lt;p&gt;Such an analysis will help you figure out your logical errors, to the point that the simulation is correct. And then... If the code does not have syntax errors, and the design simulates correctly, everything should run successfully on hardware too.&lt;/p&gt;
&lt;p&gt;Let us stop on that (naïvely?) positive note here.&lt;/p&gt;
&lt;p&gt;To be continued!&lt;/p&gt;
</description>
      <pubDate>Mon, 25 Jul 2022 19:00:00 Z</pubDate>
      <a10:updated>2022-07-25T19:00:00Z</a10:updated>
      <a10:rights type="html">Copyright &amp;copy; 1985-2026 Stéphane Gay</a10:rights>
    </item>
    <item>
      <guid isPermaLink="false">11315</guid>
      <link>https://www.zpqrtbnk.net/posts/iasyncdisposable-pitfalls/</link>
      <author>sgay@pilotine.com</author>
      <category>dotnet</category>
      <title>IAsyncDisposable Pitfalls</title>
      <description>&lt;p&gt;The .NET ecosystem comes with more and more sophisticated Roslyn Analyzers which &lt;em&gt;may&lt;/em&gt; seem annoying but actually are quite useful at improving our code and detecting hidden and tricky issues.&lt;/p&gt;
&lt;p&gt;Say we have a &lt;code&gt;Method&lt;/code&gt; method that uses a &lt;code&gt;thing&lt;/code&gt; object, which implements &lt;code&gt;IAsyncDisposable&lt;/code&gt; and is produced by an async &lt;code&gt;GetAsyncDisposableAsync&lt;/code&gt; method. We know about the &lt;code&gt;await using&lt;/code&gt; pattern, which guarantees that the object will be async-disposed when the method exits. We have learned that we need to use &lt;code&gt;ConfigureAwait&lt;/code&gt; on awaited tasks (else, we get the &lt;a href="https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca2007"&gt;CA2007: Do not directly await a Task&lt;/a&gt; warning). And so, we write the following code:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-csharp"&gt;public async Task Method()
{
    await using var thing = await GetAsyncDisposableAsync().ConfigureAwait(false);

    // use the thing
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It is a bit convoluted, but does what we want.&lt;/p&gt;
&lt;h4 id="or-does-it"&gt;Or, does it?&lt;/h4&gt;
&lt;p&gt;Recently, This code started to produce the &lt;a href="https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca2007"&gt;CA2007: Do not directly await a Task&lt;/a&gt; warning) &lt;em&gt;again&lt;/em&gt;. Despite the fact that we are, well, obviously &lt;em&gt;not&lt;/em&gt; directly awaiting the task.&lt;/p&gt;
&lt;p&gt;Or... which task? It turns out that there are &lt;em&gt;two&lt;/em&gt; tasks at stake here:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;When we obtain the &lt;code&gt;thing&lt;/code&gt; object, we run the async &lt;code&gt;GetAsyncDisposable&lt;/code&gt; method, which returns a &lt;code&gt;Task&amp;lt;IAsyncDisposable&amp;gt;&lt;/code&gt;, which we await immediately&lt;/li&gt;
&lt;li&gt;When the &lt;code&gt;await using&lt;/code&gt; pattern implicitly async-disposes the object at the end of the method, it runs the async &lt;code&gt;thing.DisposeAsync&lt;/code&gt; method, which returns a &lt;code&gt;ValueTask&lt;/code&gt;, which is awaited&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When we write the following code, where &lt;code&gt;GetAsyncDisposable&lt;/code&gt; is synchronous, the compiler will &lt;em&gt;reuse&lt;/em&gt; the &lt;code&gt;ConfigureAwait&lt;/code&gt; statement when awaiting the &lt;code&gt;DisposeAsync&lt;/code&gt; task.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-csharp"&gt;await using var y = GetAsyncDisposable().ConfigureAwait(false);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;However, when we write the following code, where &lt;code&gt;GetAsyncDisposable&lt;/code&gt; is asynchronous, the compiler &lt;em&gt;has&lt;/em&gt; to use the &lt;code&gt;ConfigureAwait&lt;/code&gt; statement immediately and is left with no hint about how to await the &lt;code&gt;DisposeAsync&lt;/code&gt; task.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-csharp"&gt;await using var y = await GetAsyncDisposableAsync().ConfigureAwait(false);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And, don't think about putting &lt;em&gt;two&lt;/em&gt; &lt;code&gt;ConfigureAwait&lt;/code&gt; statements there, it does not work. There is a &lt;a href="https://github.com/dotnet/csharplang/discussions/2661"&gt;lengthy discussion&lt;/a&gt; about this situation in the C# lang repository, which essentially concludes that there is no pretty way to handle the situation. It's one area where the C# design fails.&lt;/p&gt;
&lt;h4 id="solution-sort-of"&gt;Solution (sort-of)&lt;/h4&gt;
&lt;p&gt;The solution idea is to separate the &lt;code&gt;await using&lt;/code&gt; statement from the retrieval of the &lt;code&gt;IAsyncDisposable&lt;/code&gt; object. In other words: don't &lt;code&gt;await using&lt;/code&gt; something that is obtained asynchronously. Our code can become:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-csharp"&gt;public async Task Method()
{
    var thing = await GetAsyncDisposableAsync().ConfigureAwait(false);
    await using (thing.ConfigureAwait(false))
    {
        // use the thing
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And now we &lt;em&gt;do&lt;/em&gt; have our two &lt;code&gt;ConfigureAwait&lt;/code&gt; calls, and C# will use the one in the &lt;code&gt;await using&lt;/code&gt; block when awaiting the &lt;code&gt;DisposeAsync&lt;/code&gt; &lt;code&gt;ValueTask&lt;/code&gt;. Note however that we lose the convenient one-line &lt;code&gt;await using&lt;/code&gt; syntax. We can get it back with this other version:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-csharp"&gt;public async Task Method()
{
    var thing = await GetAsyncDisposableAsync().ConfigureAwait(false);
    await using var thingd = thing.ConfigureAwait(false);

    // use the thing
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;a href="https://github.com/dotnet/csharplang/discussions/2661"&gt;discussion&lt;/a&gt; on the C# repository proposes even more esoteric solutions and some weird-looking extension methods that, in my mind, render things even more confusing. It is an interesting read nevertheless :)&lt;/p&gt;
</description>
      <pubDate>Tue, 19 Jul 2022 13:00:00 Z</pubDate>
      <a10:updated>2022-07-19T13:00:00Z</a10:updated>
      <a10:rights type="html">Copyright &amp;copy; 1985-2026 Stéphane Gay</a10:rights>
    </item>
    <item>
      <guid isPermaLink="false">10969</guid>
      <link>https://www.zpqrtbnk.net/posts/the-curse-of-null/</link>
      <author>sgay@pilotine.com</author>
      <category>dotnet</category>
      <title>The Curse of NULL</title>
      <description>&lt;p&gt;C# has two main categories of types: &lt;em&gt;value types&lt;/em&gt; and &lt;em&gt;reference types&lt;/em&gt;. A variable of a value type contains an instance of the type, while a variable of a reference type contains a &lt;em&gt;reference&lt;/em&gt; to an instance of the type. In a very non-technical way, one could say that a value type variable is the &amp;quot;thing&amp;quot; itself, while a reference type variable &lt;em&gt;points&lt;/em&gt; to the &amp;quot;thing&amp;quot;.&lt;/p&gt;
&lt;p&gt;An integer, for instance, is a value type. An integer variable contains the value itself. It has to be a valid integer value (in the &lt;code&gt;int.MinValue&lt;/code&gt; to &lt;code&gt;int.MaxValue&lt;/code&gt; range), and is zero by default. And technically, anything that can fit in a value type (ignoring &lt;code&gt;struct&lt;/code&gt; here) is valid: if an &lt;code&gt;int&lt;/code&gt; is composed of four bytes i.e. 32 bits, any combination of these 32 bits is going to produce a valid &lt;code&gt;int&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;An object can be a reference type, when it is defined as a &lt;code&gt;class&lt;/code&gt;. A &lt;code&gt;class&lt;/code&gt; object variable contains a &lt;em&gt;reference&lt;/em&gt; to the object, not the object itself. More precisely, it contains a &lt;em&gt;number&lt;/em&gt; (32 bits on 32 bit OS, 64 bits on 64 bits OS) which is the &lt;em&gt;address&lt;/em&gt; of the object in memory.&lt;/p&gt;
&lt;p&gt;A reference type variable &lt;em&gt;has&lt;/em&gt; to point to a valid object of the correct type, and of course not every number point to such an object: some numbers would be &lt;em&gt;invalid&lt;/em&gt;. Luckily C# makes sure that, by default, all reference variables are &lt;em&gt;valid&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Except for one situation.&lt;/p&gt;
&lt;h4 id="enters-null"&gt;Enters NULL&lt;/h4&gt;
&lt;p&gt;C# allows reference type variables to use the underlying value &lt;em&gt;zero&lt;/em&gt; a.k.a. &lt;code&gt;null&lt;/code&gt;, which is not a valid memory address, to indicate that they actually do &lt;em&gt;not&lt;/em&gt; point to an object. It can be convenient, when you think of it, and the concept is widely used in databases: if the &lt;code&gt;Name&lt;/code&gt; column contains &lt;code&gt;null&lt;/code&gt;, we don't know the name of the person.&lt;/p&gt;
&lt;p&gt;At C# code level however, &lt;code&gt;null&lt;/code&gt; is sort of cursed. And why so? Because... if the variable &lt;code&gt;thing&lt;/code&gt; is of type &lt;code&gt;Thing&lt;/code&gt; which is defined as a &lt;code&gt;class&lt;/code&gt;, and the value of the variable is &lt;code&gt;null&lt;/code&gt;, what is the value of &lt;code&gt;thing.Value&lt;/code&gt;? It cannot be determined, and trying to access it provokes a &lt;code&gt;NullReferenceException&lt;/code&gt; at runtime. Once &lt;code&gt;null&lt;/code&gt; is authorized, programmers have to take great care everywhere to handle, and guard against, &lt;code&gt;null&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Oh and, the default value of a reference type variable is &lt;code&gt;null&lt;/code&gt;.&lt;/p&gt;
&lt;h4 id="nullable-value-type"&gt;Nullable Value Type&lt;/h4&gt;
&lt;p&gt;Now imagine that one wants a variable that indicates whether a user is OK with receiving spam, and aso imagine that this variable is meaningless as long as the user has not explicitly indicated whether they are OK with spam or not. Unfortunately, a &lt;code&gt;bool&lt;/code&gt; variable is &lt;code&gt;true&lt;/code&gt; or &lt;code&gt;false&lt;/code&gt; and nothing else. Of course the proper way do handle this would be via two separate variables:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;~csharp
bool isOkWithSpam;
bool hasIndicatedSpamPreference;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But, inspired by the &lt;code&gt;null&lt;/code&gt; usage for references, C# introduced the &lt;code&gt;Nullable&amp;lt;T&amp;gt;&lt;/code&gt; structure which can at the same time carry a value, &lt;em&gt;and&lt;/em&gt; indicate whether it has a value or not. And, to make it even friendlier, it introduced syntactic sugar that would allow one to pretend that the variable could be &lt;code&gt;null&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;~csharp
bool? isOkWithSpam;    // compiles as: Nullable&amp;lt;bool&amp;gt; isOkWithSpam;
isOkWithSpam = null;   // compiles as: isOkWithSpam.HasValue = false;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that a &lt;code&gt;Nullable&amp;lt;T&amp;gt;&lt;/code&gt; has &amp;quot;interesting&amp;quot; properties. You probably know already that the C# language can &amp;quot;box&amp;quot; an integer value type into an object. In the code below, the &lt;code&gt;o&lt;/code&gt; variable is of type &lt;code&gt;object&lt;/code&gt; and contains an actual &lt;code&gt;System.Int32&lt;/code&gt; value, obtained at the time of boxing (don't confuse it with a &lt;em&gt;reference to &lt;code&gt;i&lt;/code&gt;&lt;/em&gt;— such a reference does not exist and changing &lt;code&gt;i&lt;/code&gt; does not change &lt;code&gt;o&lt;/code&gt;):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;~csharp
var i = 33;
var o = (object) i;
Console.WriteLine(o.GetType()); // &amp;quot;System.Int32&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now what happens when you box a &lt;code&gt;Nullable&amp;lt;T&amp;gt;&lt;/code&gt;? You &lt;em&gt;may&lt;/em&gt; think that you would get a variable of type &lt;code&gt;object&lt;/code&gt; containing an actual &lt;code&gt;Nullable&amp;lt;T&amp;gt;&lt;/code&gt; value. But actually... boxing unwraps the &lt;code&gt;Nullable&amp;lt;T&amp;gt;&lt;/code&gt; structure, and what you finally get depends on whether there was a value or not:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;~csharp
var i = (int?) 33;
var o = (object) i; // o is of type System.Int32
var ni = (int?) null;
var no = (object) ni; // o is null
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;All in all, the C# language support for nullable values is pretty nice, you can even sum several &lt;code&gt;int?&lt;/code&gt; value and get an actual result if no value is &lt;code&gt;null&lt;/code&gt;, or &lt;code&gt;null&lt;/code&gt; if one value is &lt;code&gt;null&lt;/code&gt;... The language designers looked at nullable value type variables, and thought it was a very good thing.&lt;/p&gt;
&lt;h4 id="nullable-reference-type"&gt;Nullable Reference Type&lt;/h4&gt;
&lt;p&gt;Others found that the whole concept of a variable being &lt;code&gt;null&lt;/code&gt; was very wrong and dangerous. They thought that a &lt;code&gt;string&lt;/code&gt; variable should always contain an actual string, no matter what, maybe the empty string by default, but not never ever &lt;em&gt;nothing&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;However, imposing such a change on the CLR would be a &lt;em&gt;massive&lt;/em&gt; breaking change. Actually, an impossible one. So they had this idea: technically, the CLR would still support &lt;code&gt;null&lt;/code&gt; references, but the &lt;em&gt;compiler&lt;/em&gt; would try its best to detect and prevent them.&lt;/p&gt;
&lt;p&gt;When the &lt;code&gt;nullable&lt;/code&gt; feature of the compiler is enabled, a &lt;code&gt;string&lt;/code&gt; variable is assumed to be non-&lt;code&gt;null&lt;/code&gt;. The following code would raise a warning (note: not an error).&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;~csharp
string s;
s = null; // warning!
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And, for consistency purposes, the value type nullable notation has been reused to indicate a reference variable that is authorized to be &lt;code&gt;null&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;~csharp
string? s;
s = null; // no warning
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Though initially annoying, this can quickly point to errors in code and is in fact quite nice.&lt;/p&gt;
&lt;p&gt;Some caveats: if you write a library that expose a method such as:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;~csharp
public void WriteLength(string s)
{
    Console.WriteLine(s.Length);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The compiler will assume that this is safe, since the variable is of type &lt;code&gt;string&lt;/code&gt;, which indicates it cannot be &lt;code&gt;null&lt;/code&gt;. However, remember that this is a compiler-level check. Nothing prevents a user of your library to disable the nullable checks, and pass &lt;code&gt;null&lt;/code&gt; to your method. Therefore, it is still a good practice to check parameters for &lt;code&gt;null&lt;/code&gt; values in publicly-exposed methods:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;~csharp
public void WriteLength(string s)
{
    if (s == null) throw new ArgumentNullException(nameof(s));
    Console.WriteLine(s.Length);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But for everything internal, it should be safe to trust the compiler.&lt;/p&gt;
&lt;h4 id="and-then-it-becomes-complicated"&gt;And then it becomes complicated&lt;/h4&gt;
&lt;p&gt;Now imagine a function that may return a value, or may want to indicate that it has no value to return. This is a typical use case for nullable.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;~csharp
public T? GetValue&amp;lt;T&amp;gt;() { ... }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Alas, with C# 8, that would not compile. The problem here is that &lt;code&gt;T?&lt;/code&gt; can mean two very different things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If &lt;code&gt;T&lt;/code&gt; is a value type, &lt;code&gt;T?&lt;/code&gt; is syntactic sugar for &lt;code&gt;Nullable&amp;lt;T&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;If &lt;code&gt;T&lt;/code&gt; is a reference type, &lt;code&gt;T?&lt;/code&gt; is actually &lt;code&gt;T&lt;/code&gt; but with a hint for the compiler to assume that the value can be &lt;code&gt;null&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We end up with a function that can return &lt;code&gt;Nullable&amp;lt;T&amp;gt;&lt;/code&gt; or &lt;code&gt;T&lt;/code&gt;, which is an impossible situation. One has to &lt;em&gt;constrain&lt;/em&gt; &lt;code&gt;T&lt;/code&gt; for the code to compile:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;~csharp
public T? GetValValue&amp;lt;T&amp;gt;() where T : struct { ... }
public T? GetRefValue&amp;lt;T&amp;gt;() where T : class { ... }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;C# 9 has a better support for nullable, and does compile the following function:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;~csharp
public T? GetValue&amp;lt;T&amp;gt;() { return default; }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So, can you guess the output of the following code:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;~csharp
Console.WriteLine(GetValue&amp;lt;string&amp;gt;());
Console.WriteLine(GetValue&amp;lt;int&amp;gt;());
Console.WriteLine(GetValue&amp;lt;int?&amp;gt;());
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The first line outputs nothing, which makes sense: &lt;code&gt;GetValue&amp;lt;string&amp;gt;&lt;/code&gt; returns a &lt;code&gt;string?&lt;/code&gt; value, which really at IL code / CLR level is a &lt;code&gt;string&lt;/code&gt;, and the default value is &lt;code&gt;null&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The second line outputs... zero. How come? The reason is, even in version 9 C# cannot do miracle and return both &lt;code&gt;T&lt;/code&gt; and &lt;code&gt;Nullable&amp;lt;T&amp;gt;&lt;/code&gt;. The method is being called with &lt;code&gt;T&lt;/code&gt; being &lt;code&gt;int&lt;/code&gt;, so it returns &lt;code&gt;default(int)&lt;/code&gt; i.e. zero, as &lt;code&gt;T&lt;/code&gt;. So, even though the code now compiles, it does not exactly produces what we would expect (&lt;code&gt;null&lt;/code&gt;). In fact, the method &lt;em&gt;cannot&lt;/em&gt; return a &lt;code&gt;null&lt;/code&gt; value type.&lt;/p&gt;
&lt;p&gt;The third line outputs nothing. &lt;code&gt;GetValue&amp;lt;int?&amp;gt;&lt;/code&gt; returns a... &lt;code&gt;int??&lt;/code&gt; value, I guess, which really is a &lt;code&gt;int?&lt;/code&gt; with the second &lt;code&gt;?&lt;/code&gt; being discarded because &lt;code&gt;int?&lt;/code&gt; is a value type. But in this case, the method is being called with &lt;code&gt;T&lt;/code&gt; being &lt;code&gt;int?&lt;/code&gt;, so it returns &lt;code&gt;default(int?)&lt;/code&gt; i.e. &lt;code&gt;null&lt;/code&gt;, as &lt;code&gt;T&lt;/code&gt; (again), which happens to be &lt;code&gt;int?&lt;/code&gt;, so we get a &lt;code&gt;null&lt;/code&gt; value type. Are you still with me?&lt;/p&gt;
&lt;h4 id="so-what"&gt;So what?&lt;/h4&gt;
&lt;p&gt;In &lt;em&gt;most cases&lt;/em&gt; you will ignore all this and happily use nullable values here and there without issues. Just remember that nullable values and &lt;code&gt;null&lt;/code&gt; references, though sharing a very similar syntax, are not exactly the same thing. And, come back and read again this post the day you will get this very odd behavior that you do not quite understand!&lt;/p&gt;
</description>
      <pubDate>Fri, 10 Jun 2022 19:35:00 Z</pubDate>
      <a10:updated>2022-06-10T19:35:00Z</a10:updated>
      <a10:rights type="html">Copyright &amp;copy; 1985-2026 Stéphane Gay</a10:rights>
    </item>
    <item>
      <guid isPermaLink="false">5702</guid>
      <link>https://www.zpqrtbnk.net/posts/csharp-fixme-code-comments/</link>
      <author>sgay@pilotine.com</author>
      <category>hacks</category>
      <category>dotnet</category>
      <title>CSharp FIXME Code Comments</title>
      <description>&lt;p&gt;When working on code, I sometime can get deep in &amp;quot;the zone&amp;quot;, a creative state where ideas keep flowing and I start refactoring things all around the code base, making quick and dirty changes here and there just to be able to go where I know I want to go. This is accumulating technical debt, and as with any debt, I believe that it can be a good thing, as long as it lets me achieve my goal &lt;em&gt;and&lt;/em&gt; there is a reliable plan to repay that debt eventually.&lt;/p&gt;
&lt;p&gt;Part of that process requires that that debt can be made highly visible. I love to drop &amp;quot;FIXME comments&amp;quot; in my code for that purpose.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public void MyMethod()
{
    // get a value and use it
    // FIXME this may throw and then we should handle it
    var s = GetSomething();
    
    UseTheValue(s);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;ReSharper is nice enough to color these comments, and tag them in the scrollbar.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.zpqrtbnk.net/media/2k3dskqy/shot1.png" alt="Shot1" alt="ReSharper Comment" /&gt;&lt;/p&gt;
&lt;p&gt;ReSharper also provides a useful &lt;em&gt;To-to explorer&lt;/em&gt; which provides an overview of all these comments, with a way to easily navigate to each of them.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.zpqrtbnk.net/media/r3ihxnj2/shot2.png" alt="Shot2" alt="ReSharper Comment" /&gt;&lt;/p&gt;
&lt;p&gt;However... dealing with these FIXMEs remain a proactive and somewhat tedious task, and it is quite easy to forget about it, especially if one is prone to procrastination... leading to inevitable debt accumulation.&lt;/p&gt;
&lt;h4 id="show-me-fixmes"&gt;Show me FIXMEs&lt;/h4&gt;
&lt;p&gt;I am trying to address this situation via Roslyn &lt;a href="https://docs.microsoft.com/en-us/visualstudio/code-quality/roslyn-analyzers-overview"&gt;Code Analysis&lt;/a&gt;. I have created a &lt;em&gt;Comments Build Analyzer&lt;/em&gt; (available on &lt;a href="https://www.nuget.org/packages/ZpqrtBnk.CommentsBuildAnalyzer/"&gt;NuGet&lt;/a&gt; with source code on &lt;a href="https://github.com/zpqrtbnk/comments-build-analyzer"&gt;GitHub&lt;/a&gt;) which detects FIXME comments, and creates corresponding warnings that show in the &lt;em&gt;Error List&lt;/em&gt; pane.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.zpqrtbnk.net/media/fs4itkwr/shot3.png" alt="Shot3" alt="Error List" /&gt;&lt;/p&gt;
&lt;p&gt;At the moment, &lt;code&gt;FIXME&lt;/code&gt; comment are reported with code &lt;code&gt;ZB1001&lt;/code&gt; and &lt;code&gt;FIXME!&lt;/code&gt; (note the bang) comments are reported with code &lt;code&gt;ZB1002&lt;/code&gt;. All you have to do is install the NuGet package in your project.&lt;/p&gt;
&lt;p&gt;Combine this with &lt;code&gt;.editorconfig&lt;/code&gt; files, and it becomes even more (painful?) useful. It is possible to use configuration-dependent &lt;code&gt;.editorconfig&lt;/code&gt; files by registering them in the &lt;code&gt;.csproj&lt;/code&gt; file.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;ItemGroup Condition=&amp;quot;'$(Configuration)'=='Debug'&amp;quot;&amp;gt;
    &amp;lt;EditorConfigFiles Include=&amp;quot;debug.editorconfig&amp;quot; Link=&amp;quot;.editorconfig&amp;quot;/&amp;gt;
&amp;lt;/ItemGroup&amp;gt;

&amp;lt;ItemGroup Condition=&amp;quot;'$(Configuration)'=='Release'&amp;quot;&amp;gt;
      &amp;lt;EditorConfigFiles Include=&amp;quot;release.editorconfig&amp;quot; Link=&amp;quot;.editorconfig&amp;quot;/&amp;gt;
&amp;lt;/ItemGroup&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, if &lt;code&gt;debug.editorconfig&lt;/code&gt; contains:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;dotnet_diagnostic.ZB1002.severity = warning # FIXME!
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;While &lt;code&gt;release.editorconfig&lt;/code&gt; contains:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;dotnet_diagnostic.ZB1002.severity = error # FIXME!
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;FIXME!&lt;/code&gt; comments will raise warnings in the &lt;code&gt;Debug&lt;/code&gt; build (so they will not prevent you from developing and building and testing, as &lt;code&gt;#error&lt;/code&gt; statements would), and will raise &lt;em&gt;errors&lt;/em&gt; in the &lt;code&gt;Release&lt;/code&gt; build—and thus fail it.&lt;/p&gt;
&lt;p&gt;The end result being that, with a properly configured CI, the build would break in case you ever leak a &lt;code&gt;FIXME!&lt;/code&gt; comment. I still need to use it for some time and evaluate whether this is &lt;em&gt;really&lt;/em&gt; useful,or just fancy, but so far it makes me feel safer.&lt;/p&gt;
</description>
      <pubDate>Tue, 16 Mar 2021 09:20:00 Z</pubDate>
      <a10:updated>2021-03-16T09:20:00Z</a10:updated>
      <a10:rights type="html">Copyright &amp;copy; 1985-2026 Stéphane Gay</a10:rights>
    </item>
    <item>
      <guid isPermaLink="false">3946</guid>
      <link>https://www.zpqrtbnk.net/posts/optimizing-csharp-null-coalescing-operator/</link>
      <author>sgay@pilotine.com</author>
      <category>dotnet</category>
      <title>Optimizing CSharp Null-Coalescing Operator</title>
      <description>&lt;p&gt;Consider the following code:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public Func&amp;lt;int&amp;gt; F { get; set; }

private int GetValue()
{
    // return the value produced by F, 
    // if F is not null, else zero
} 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I naïvely implemented the function as:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;if (F == null) return default;
return F();
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Does the job.&lt;/p&gt;
&lt;h4 id="elegant-code"&gt;Elegant Code&lt;/h4&gt;
&lt;p&gt;Yet, ReSharper squiggled the &lt;code&gt;if&lt;/code&gt; statement, suggesting I might want to convert to:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;return F == null ? default : F();
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Which is nice indeed. Ah, ReSharper now squiggles the &lt;code&gt;== null&lt;/code&gt; statement, suggesting I merge the conditional expression into:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;return F?.Invoke() ?? default;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And... I started to wonder. It certainly is more compact. But is it cleaner?
It reminds me of a &lt;a href="https://twitter.com/FransBouma/status/1326456729102659585"&gt;recent thead&lt;/a&gt; initiated by Frans, on the topic of C# getting more and more syntax-complex, to the point that C++ looks elegant and you need ReSharper to remind you of all the new bells and whistles.&lt;/p&gt;
&lt;p&gt;Thank you, but no. Obfuscation can &lt;a href="https://en.wikipedia.org/wiki/International_Obfuscated_C_Code_Contest"&gt;sure be fun&lt;/a&gt;, but one day I might have to troubleshoot that code, and I do prefer the &lt;code&gt;?:&lt;/code&gt; pattern over the &lt;code&gt;?.Invoke ??&lt;/code&gt; one. As Steve &lt;a href="https://twitter.com/Steve_Gibe/status/1326475063277793280"&gt;replied&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;It's just obfuscating the intent of your code. Clarity over minimal keystrokes. I gotta support this code for years.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;(rant) Every developer should have to spend some time doing 24/7 support on production-critical code. Once you have been waken up at 3am to spend hours trying to figure out what is wrong with some recent code changes while the entire factory waits for you to restart operations... you get a different idea of what elegant code is. (/rant)&lt;/p&gt;
&lt;p&gt;Anyways.&lt;/p&gt;
&lt;h4 id="and-besides-it-is-not-the-same"&gt;And besides, it is not the same!&lt;/h4&gt;
&lt;p&gt;At that point I got a carried on by my rant, and started to think:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;With the &lt;code&gt;?.&lt;/code&gt; pattern, if the function is &lt;code&gt;null&lt;/code&gt;, we return the &lt;em&gt;value type&lt;/em&gt; default value, else execute the function and return the &lt;em&gt;value type&lt;/em&gt; result&lt;/li&gt;
&lt;li&gt;With the &lt;code&gt;?.Invoke ??&lt;/code&gt; pattern, if the function is &lt;code&gt;null&lt;/code&gt;, &lt;code&gt;?.Invoke&lt;/code&gt; will be &lt;code&gt;null&lt;/code&gt; i.e. a &lt;em&gt;reference type&lt;/em&gt;, so there has to be some &lt;a href="https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/types/boxing-and-unboxing"&gt;boxing and unboxing&lt;/a&gt; happening under the hood for the &lt;a href="https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/null-coalescing-operator"&gt;?? operator&lt;/a&gt; to work&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And so, the &lt;code&gt;?.Invoke ??&lt;/code&gt; pattern has to be worse, performance-wise!&lt;/p&gt;
&lt;p&gt;Time to turn to &lt;a href="https://sharplab.io/"&gt;Sharplab.io&lt;/a&gt;. This amazing tool let you type C# code on the left, and presents you with the resulting IL or assembly code on the right:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.zpqrtbnk.net/imgx/lihjtmd4/2020-11-21-09_50_12-sharplab-io-sharplab-mw-600.png?hmac=5b5e5b40754ec3b2721001965a7203ae5fb0117e0b89a09a2a05a345b4010fda" alt="2020 11 21 09 50 12 Sharplab.Io Sharplab" alt="Sharplab.io" /&gt;&lt;/p&gt;
&lt;p&gt;We are going to compile the following code:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public Func&amp;lt;int&amp;gt; F { get; set; }
    
public int M1() 
{
    return F == null
        ? 0
        : F();
}
    
public int M2() 
{
    return F?.Invoke() ?? 0;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For &lt;code&gt;M1&lt;/code&gt; the IL code (in Release mode) is:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;IL_0000: ldarg.0
IL_0001: call instance class [System.Private.CoreLib]System.Func`1&amp;lt;int32&amp;gt; C::get_F()
IL_0006: brfalse.s IL_0014

IL_0008: ldarg.0
IL_0009: call instance class [System.Private.CoreLib]System.Func`1&amp;lt;int32&amp;gt; C::get_F()
IL_000e: callvirt instance !0 class [System.Private.CoreLib]System.Func`1&amp;lt;int32&amp;gt;::Invoke()
IL_0013: ret

IL_0014: ldc.i4.0
IL_0015: ret
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And for &lt;code&gt;M2&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;IL_0000: ldarg.0
IL_0001: call instance class [System.Private.CoreLib]System.Func`1&amp;lt;int32&amp;gt; C::get_F()
IL_0006: dup
IL_0007: brtrue.s IL_000c

IL_0009: pop
IL_000a: ldc.i4.0
IL_000b: ret

IL_000c: callvirt instance !0 class [System.Private.CoreLib]System.Func`1&amp;lt;int32&amp;gt;::Invoke()
IL_0011: ret
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;First, note that the &lt;code&gt;?.&lt;/code&gt; coalesce operator does &lt;em&gt;not&lt;/em&gt; imply any kind of boxing, as I originally thought. So it &lt;em&gt;is&lt;/em&gt; safe. In fact, the code produced for &lt;code&gt;M2&lt;/code&gt; looks simpler, especially with &lt;code&gt;M1&lt;/code&gt; invoking &lt;code&gt;get_F()&lt;/code&gt; &lt;em&gt;twice&lt;/em&gt; in case &lt;code&gt;F&lt;/code&gt; is not &lt;code&gt;null&lt;/code&gt;. However, remember this is only IL code. There is another level of optimization in the JIT, which leads to the following x86 assembly code:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;C.M1()
    L0000: mov eax, [ecx+4]
    L0003: test eax, eax
    L0005: je short L000e
    L0007: mov ecx, [eax+4]
    L000a: call dword ptr [eax+0xc]
    L000d: ret
    L000e: xor eax, eax
    L0010: ret

C.M2()
    L0000: mov edx, [ecx+4]
    L0003: test edx, edx
    L0005: jne short L000a
    L0007: xor eax, eax
    L0009: ret
    L000a: mov ecx, [edx+4]
    L000d: call dword ptr [edx+0xc]
    L0010: ret
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In other words, both methods end up doing &lt;em&gt;almost&lt;/em&gt; exactly the same, at assembly level. And benchmarks (see below, if you &lt;em&gt;really&lt;/em&gt; are into this) show that they perform the same. This is a good thing: it means that one can use one syntax or the other, without worrying about performance.&lt;/p&gt;
&lt;p&gt;As for code elegance, I know what I prefer.&lt;/p&gt;
&lt;h4 id="appendix"&gt;Appendix&lt;/h4&gt;
&lt;p&gt;This is more details, for people who are into it.&lt;/p&gt;
&lt;p&gt;Just to be sure, I have benchmarked the two methods. The BenchmarkDotNet code is quite simple (see &lt;a href="https://gist.github.com/zpqrtbnk/490025ea4b720ba2f06ae827c88f18ee"&gt;this Gist&lt;/a&gt;) and I have executed it with &lt;code&gt;F&lt;/code&gt; being &lt;code&gt;null&lt;/code&gt;, or returning a constant, or computing a value... and, funny enough, I never get the exact same duration for both methods, and one or the other is always randomly slightly faster that the other. I guess that is due to glitches on my benchmark machine, and it means that the methods are equivalent.&lt;/p&gt;
&lt;p&gt;Just to be &lt;em&gt;super sure&lt;/em&gt;, I fired WinDBG at the benchmark, after it had run. First you want to locate the class:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt; !name2ee Benchmarks!Benchmarks.NullCoalesce
Module:      00007ff98a5cf800
Assembly:    Benchmarks.dll
Token:       0000000002000005
MethodTable: 00007ff98a69ea80
EEClass:     00007ff98a689038
Name:        Benchmarks.NullCoalesce
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then you want to dump the method table:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt; !dumpmt -md 00007ff98a69ea80
EEClass:         00007ff98a689038
Module:          00007ff98a5cf800
Name:            Benchmarks.NullCoalesce
mdToken:         0000000002000005
File:            D:\d\Benchmarks\bin\Release\netcoreapp3.1\Benchmarks.dll
BaseSize:        0x20
ComponentSize:   0x0
Slots in VTable: 11
Number of IFaces in IFaceMap: 0
--------------------------------------
MethodDesc Table
           Entry       MethodDesc    JIT Name
00007FF98A520090 00007ff98a4f0a80   NONE System.Object.Finalize()
00007FF98A520098 00007ff98a4f0a90   NONE System.Object.ToString()
00007FF98A5200A0 00007ff98a4f0aa0    JIT System.Object.Equals(System.Object)
00007FF98A5200B8 00007ff98a4f0ae0    JIT System.Object.GetHashCode()
00007FF98A538F30 00007ff98a69e9f8   NONE Hazelcast.Benchmarks.NullCoalesce..ctor()
00007FF98A538F20 00007ff98a69e9c8    JIT Benchmarks.NullCoalesce.get_F()
00007FF98A538F28 00007ff98a69e9e0   NONE Benchmarks.NullCoalesce.set_F(System.Func`1)
00007FF98A538F38 00007ff98a69ea08    JIT Benchmarks.NullCoalesce.BenchmarkM1()
00007FF98A538F40 00007ff98a69ea20    JIT Benchmarks.NullCoalesce.M1()
00007FF98A538F48 00007ff98a69ea38    JIT Benchmarks.NullCoalesce.BenchmarkM2()
00007FF98A538F50 00007ff98a69ea50    JIT Benchmarks.NullCoalesce.M2()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And... &lt;code&gt;!dumpil&lt;/code&gt; can show us the IL code, but we really want the assembly code:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt; !u 00007ff98a69ea20
Normal JIT generated code
Benchmarks.NullCoalesce.M1()
Begin 00007FF98AAB5F20, size 17
00007ff9`8aab5f20 488b4108        mov     rax,qword ptr [rcx+8]
00007ff9`8aab5f24 4885c0          test    rax,rax
00007ff9`8aab5f27 740b            je      00007ff9`8aab5f34
00007ff9`8aab5f29 488b4808        mov     rcx,qword ptr [rax+8]
00007ff9`8aab5f2d 488b4018        mov     rax,qword ptr [rax+18h]
00007ff9`8aab5f31 48ffe0          jmp     rax
00007ff9`8aab5f34 33c0            xor     eax,eax
00007ff9`8aab5f36 c3              ret

&amp;gt; !u 00007ff98a69ea50  
Normal JIT generated code
Benchmarks.NullCoalesce.M2()
Begin 00007FF98AAE4220, size 17
00007ff9`8aae4220 488b5108        mov     rdx,qword ptr [rcx+8]
00007ff9`8aae4224 4885d2          test    rdx,rdx
00007ff9`8aae4227 7503            jne     00007ff9`8aae422c
00007ff9`8aae4229 33c0            xor     eax,eax
00007ff9`8aae422b c3              ret
00007ff9`8aae422c 488b4a08        mov     rcx,qword ptr [rdx+8]
00007ff9`8aae4230 488b4218        mov     rax,qword ptr [rdx+18h]
00007ff9`8aae4234 48ffe0          jmp     rax
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;My .NET host (.NET Core 3.1.9) produces assembly code that is slightly different from what Sharplab.io shows, but the conclusion stands: both methods are, practically, equivalent.&lt;/p&gt;
</description>
      <pubDate>Sat, 21 Nov 2020 13:05:00 Z</pubDate>
      <a10:updated>2020-11-21T13:05:00Z</a10:updated>
      <a10:rights type="html">Copyright &amp;copy; 1985-2026 Stéphane Gay</a10:rights>
    </item>
    <item>
      <guid isPermaLink="false">2087</guid>
      <link>https://www.zpqrtbnk.net/posts/optimizing-csharp-value-types/</link>
      <author>sgay@pilotine.com</author>
      <category>dotnet</category>
      <title>Optimizing CSharp Value Types</title>
      <description>&lt;p&gt;In a Twitter exchange with my friend James, we recently wondered how to properly document methods that return named value tuples. Why would we have to deal with methods returning value tuples? Well, consider this classic method:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public bool TryGetValue(TKey key, out TValue value) { ... }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Enters &lt;code&gt;async&lt;/code&gt;. Ideally, we want:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public async ValueTask&amp;lt;bool&amp;gt; TryGetValue(TKey key, out TValue value) { ... }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But... &lt;code&gt;async&lt;/code&gt; does support &lt;code&gt;out&lt;/code&gt; parameters. And thus, the method logically becomes:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public async ValueTask&amp;lt;(bool, TValue)&amp;gt; TryGetValue(TKey key) { ... }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Which leads us to the original question: how would you document such a method?&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/// &amp;lt;summary&amp;gt;Tries to get a value.&amp;lt;/summary&amp;gt;
/// &amp;lt;param name=&amp;quot;key&amp;quot;&amp;gt;A key.&amp;lt;/param&amp;gt;
/// &amp;lt;returns&amp;gt; ???? &amp;lt;/returns&amp;gt;
public async ValueTask&amp;lt;(bool, TValue)&amp;gt; TryGetValue(TKey key) { ... }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The subject is not exactly new as Roslyn issue &lt;a href="https://github.com/dotnet/roslyn/issues/13216"&gt;#13216&lt;/a&gt; or CSharp issue &lt;a href="https://github.com/dotnet/csharplang/issues/145"&gt;#145&lt;/a&gt; already explored more or less convoluted solutions in 2016. And somewhere in these issues, one can read:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;quot;&lt;em&gt;tuples really aren't well suited for public APIs or scenarios where you'd need or want to document them&lt;/em&gt;&amp;quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;With the recommendation to use a record of some sort to return results. Which quite probably means returning a &lt;code&gt;struct&lt;/code&gt; or even a &lt;code&gt;class&lt;/code&gt;... and this is obviously going to cause some allocations, overhead etc.&lt;/p&gt;
&lt;p&gt;Let us say, for the sake of the argument, that we refactor the method as:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/// &amp;lt;summary&amp;gt;Tries to get a value.&amp;lt;/summary&amp;gt;
/// &amp;lt;param name=&amp;quot;key&amp;quot;&amp;gt;A key.&amp;lt;/param&amp;gt;
/// &amp;lt;returns&amp;gt;A attempt at getting the value for the specified key.&amp;lt;/returns&amp;gt;
public async ValueTask&amp;lt;Attempt&amp;lt;TValue&amp;gt;&amp;gt; TryGetValue(TKey key) { ... }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With &lt;code&gt;Attempt&amp;lt;T&amp;gt;&lt;/code&gt; defined as:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public struct Attempt&amp;lt;T&amp;gt;
{
    public bool Success { get; set; }
    public T Value { get; set; }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So now, we are going to allocate an instance of &lt;code&gt;Attempt&amp;lt;T&amp;gt;&lt;/code&gt; each time we return, and then use the property getters (i.e. invoke a method) to figure out whether the attempt was successful, and retrieve the value it carries.&lt;/p&gt;
&lt;p&gt;How bad is it? Just to be sure, I have used &lt;a href="https://sharplab.io/"&gt;SharpLab&lt;/a&gt; to show me the generated IL and assembly code for the following methods:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public void InvokeWithTuple()
{
    var (success, value) = TryGetValueWithTuple(&amp;quot;foo&amp;quot;);
    if (success) Console.WriteLine(value);
}

public void InvokeWithAttempt()
{
    var attempt = TryGetValueWithAttempt(&amp;quot;foo&amp;quot;);
    if (attempt.Success) Console.WriteLine(attempt.Value);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is the assembly code generated for the tuple version (in Release mode):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;L0000: push ebp
L0001: mov ebp, esp
L0003: sub esp, 8
L0006: xor eax, eax
L0008: mov [ebp-8], eax
L000b: mov [ebp-4], eax
L000e: push 1
L0010: lea edx, [ebp-8]
L0013: call C.TryGetValueWithTuple(Boolean)
L0018: mov ecx, [ebp-4]
L001b: movzx ecx, cl
L001e: mov eax, [ebp-8]
L0021: test ecx, ecx
L0023: je short L002c
L0025: mov ecx, eax
L0027: call System.Console.WriteLine(System.String)
L002c: mov esp, ebp
L002e: pop ebp
L002f: ret
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And now, the assembly code generated for the &lt;code&gt;Attempt&lt;/code&gt; version:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;L0000: push ebp
L0001: mov ebp, esp
L0003: sub esp, 8
L0006: xor eax, eax
L0008: mov [ebp-8], eax
L000b: mov [ebp-4], eax
L000e: push 1
L0010: lea edx, [ebp-8]
L0013: call C.TryGetValueWithAttempt(Boolean)
L0018: cmp byte ptr [ebp-4], 0
L001c: je short L0026
L001e: mov ecx, [ebp-8]
L0021: call System.Console.WriteLine(System.String)
L0026: mov esp, ebp
L0028: pop ebp
L0029: ret
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Can you spot the difference? Me neither. But... let us say you are quite fond of the &lt;code&gt;var (success, value) =&lt;/code&gt; syntax. Can we still have it with attempts? Yes, with deconstruction:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public struct Attempt&amp;lt;T&amp;gt;
{
    public bool Success { get; set; }
    public T Value { get; set; }

    public void Deconstruct(out bool success, out T value)
    {
        success = Success;
        value = Value;
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And then, this is valid code:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var (success, value) = TryGetValueWithAttempt(&amp;quot;foo&amp;quot;);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But this involves deconstruction... it has to be more expensive, right? I will spare you the assembly code, it is exactly the same. The C# compiler and CLR jitter figure the deconstruction out for you.&lt;/p&gt;
&lt;p&gt;There is one lesson here: the C# compiler and the CLR jitter are quite clever, and you probably want to understand how they work before implementing pointless optimizations. When in doubt, just write clean code.&lt;/p&gt;
</description>
      <pubDate>Wed, 10 Jun 2020 16:00:00 Z</pubDate>
      <a10:updated>2020-06-10T16:00:00Z</a10:updated>
      <a10:rights type="html">Copyright &amp;copy; 1985-2026 Stéphane Gay</a10:rights>
    </item>
    <item>
      <guid isPermaLink="false">1306</guid>
      <link>https://www.zpqrtbnk.net/posts/what-becomes-of-models-builder/</link>
      <author>sgay@pilotine.com</author>
      <category>umbraco</category>
      <title>What Becomes Of Models Builder</title>
      <description>&lt;p&gt;Models Builder is an Umbraco extension that generates C# strongly-typed class models for Umbraco content item.  It allows developers to write &lt;code&gt;@Model.Title&lt;/code&gt; in views instead of the more verbose &lt;code&gt;@Model.Value&amp;lt;string&amp;gt;(&amp;quot;title&amp;quot;)&lt;/code&gt;. Models can be enriched and tweaked to greatly simplify the developement of sites.&lt;/p&gt;
&lt;p&gt;It was originally created in 2013 by me, Stephan, and distributed as an independent NuGet package named &amp;quot;Zbu.ModelsBuilder&amp;quot;. Then, around 2016, it was considered sufficiently important to be bundled with the Umbraco CMS official distribution. On that occasion, it was renamed &amp;quot;Umbraco.ModelsBuilder&amp;quot;. I kept maintaining it as part of my HQ activity.&lt;/p&gt;
&lt;p&gt;When I left HQ in 2019, I proposed to donate the project to HQ, but for various reasons that did not happen. Instead, HQ embedded a simplified version of Models Builder straight into Core—the one that currently ships with 8.x.&lt;/p&gt;
&lt;p&gt;I, on the other hand, planned to grow and maintain the complete version, as &amp;quot;ZpqrtBnk.ModelsBuilder&amp;quot;, and release long overdue features and fixes. I &lt;em&gt;did&lt;/em&gt; start some work... and then got involved in other non-Umbraco projects, and lost both time and motivation. And then, nothing happened.&lt;/p&gt;
&lt;h4 id="models-builder-reloaded"&gt;Models Builder Reloaded&lt;/h4&gt;
&lt;p&gt;Some people grew concerned that one tool they depend on would go abandoned. They reached out to me to discuss the future of Models Builder. It took me a bit of time to digest and accept that, despite all my good intentions, I was not able to do much... but here we are. It is about time to do something.&lt;/p&gt;
&lt;p&gt;As of today, &lt;strong&gt;I am officially donating the project to the Umbraco Community&lt;/strong&gt;. The project is now named &amp;quot;&lt;strong&gt;Our.ModelsBuilder&lt;/strong&gt;&amp;quot;. Its repository has moved to &lt;a href="https://github.com/OurModelsBuilder/Our.ModelsBuilder"&gt;Our.ModelsBuilder&lt;/a&gt; on GitHub.&lt;/p&gt;
&lt;h4 id="models-builder-team"&gt;Models Builder Team&lt;/h4&gt;
&lt;p&gt;And how exactly is this different from abandonning the project? Well, the general idea is to form a team of maintainers so that the project does not depend on one single person. We need people to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Understand how it all works and manage the product&lt;/li&gt;
&lt;li&gt;Code&lt;/li&gt;
&lt;li&gt;Maintain the documentation&lt;/li&gt;
&lt;li&gt;Manage the release process, etc&lt;/li&gt;
&lt;li&gt;(probably more?)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The good news is that, despite what people like to think, the project is not horribly complex rocket-science. It may require a bit of time to grasp, but then it is rather simple. It is essentially C# with very little UI. This, and I will happily join the team and make myself available to transfer whatever knowledge is required, and answer questions.&lt;/p&gt;
&lt;p&gt;And thus, this is an &lt;strong&gt;official call for members&lt;/strong&gt;. The temporay team is currently composed of myself, &lt;a href="https://twitter.com/franscdejong"&gt;Frans de Jong&lt;/a&gt; and &lt;a href="https://twitter.com/dawoe21"&gt;Dave Woestenborghs&lt;/a&gt;, and we obviously need more people.&lt;/p&gt;
&lt;p&gt;This is a &lt;strong&gt;unique chance&lt;/strong&gt; to have an impact on &lt;strong&gt;one of the most-used Umbraco tool&lt;/strong&gt;. A &lt;strong&gt;unique opportunity&lt;/strong&gt; that you &lt;strong&gt;certainly do not want to miss&lt;/strong&gt;. Of course &lt;strong&gt;you are interested&lt;/strong&gt;, so please contact one of us &lt;strong&gt;now&lt;/strong&gt;, either in the comments of this post, or on the Community Slack, or on Twitter, or by email at &lt;a href="mailto:our.modelsbuilder@gmail.com"&gt;our.modelsbuilder@gmail.com&lt;/a&gt; or by whatever means you feel adequate.&lt;/p&gt;
&lt;p&gt;Do not waste time, &lt;strong&gt;the application closes on the 5th of May, at 05:05am&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Talk to you soon!&lt;/p&gt;
</description>
      <pubDate>Wed, 15 Apr 2020 14:55:00 Z</pubDate>
      <a10:updated>2020-04-15T14:55:00Z</a10:updated>
      <a10:rights type="html">Copyright &amp;copy; 1985-2026 Stéphane Gay</a10:rights>
    </item>
    <item>
      <guid isPermaLink="false">1299</guid>
      <link>https://www.zpqrtbnk.net/posts/three-fives-kit-pcb-edition/</link>
      <author>sgay@pilotine.com</author>
      <category>hacks</category>
      <title>Three Fives Kit PCB Edition</title>
      <description>&lt;p&gt;Some time ago I &lt;a href="https://www.zpqrtbnk.net/posts/three-fives-kit/"&gt;built a Three Fives Kit&lt;/a&gt; from Evil Mad Scientist, and a quick circuit which blinked one LED with a real NE555 timer, and one with the kit.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.zpqrtbnk.net/imgx/1042/img_7114-mw-600.jpg?hmac=f45230a32f31fa0b953899a03ed84c9f946ddcc52385758a772cfb76822340d0" alt="IMG_7114.jpg" class="img-center" alt="circuit" /&gt;&lt;/p&gt;
&lt;p&gt;This has been sitting on some shelve in my office ever since, but I have always wondered whether I could clean things up a little... maybe building a PCB for the circuit.&lt;/p&gt;
&lt;p&gt;So, I asked on Twitter what people would use to design PCBs, and the always helpful and super-friendly maker Matt Brailsford from &lt;a href="https://circuitbeard.co.uk/"&gt;CircuitBeard&lt;/a&gt; suggested I tried &lt;a href="https://www.kicad-pcb.org/"&gt;KiCad&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Downloading and installing KiCab is relatively easy, but then I quickly hit a steep learning curve. I started reading tutorials... but was, to be honest, going nowhere. And then I found the &lt;a href="https://www.youtube.com/watch?v=BVhWh3AsXQs&amp;amp;list=PLy2022BX6EspFAKBCgRuEuzapuz_4aJCn"&gt;Getting To Blinky 5.0&lt;/a&gt; set of videos by Chris Gammel from &lt;a href="https://contextualelectronics.com/"&gt;Contextual Electronics&lt;/a&gt;. To make it short, these dense videos have &lt;em&gt;everything&lt;/em&gt; you need, in amazing details.&lt;/p&gt;
&lt;p&gt;I will not, therefore, explain KiCad here. Watch the videos. Let's just say that you will end up with a schema:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.zpqrtbnk.net/imgx/teihxrxn/kicad-schema-mw-600.png?hmac=a3e36ac551e9acbfcd54342cf98b393c9e66d8b8d22b94c0f210d9db817fc7f0" alt="Kicad Schema" class="img-center" alt="schema" /&gt;&lt;/p&gt;
&lt;p&gt;The schema has two blocks, each blinking a LED with a 555. There is a switch that can be used to select which capacitor to use, to produce either a 500Hz signal (that can be observed with a scope) or a .5Hz signal (to see the LED blink).&lt;/p&gt;
&lt;p&gt;A bit more work takes you to the PCB design itself:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.zpqrtbnk.net/imgx/px0petbt/kicad-pcb-mw-600.png?hmac=9a32154a5c57d5e6b87ef7d7445a9d558f9ec5ebebc55caf62ce0a6960d86216" alt="Kicad Pcb" class="img-center" alt="schema" /&gt;&lt;/p&gt;
&lt;p&gt;The top copper zones should make it easy to clamp the scope's crocodile plugs to observe signals, while the 555 areas will welcome chip sockets, allowing one to either plug a real 555, or the Three Fives Kit.&lt;/p&gt;
&lt;p&gt;Next, the PCB needs to be manufactured. The recommendation was to go with &lt;a href="https://oshpark.com/"&gt;OshPark&lt;/a&gt; which seems to have fewer options than, say, &lt;a href="https://jlcpcb.com/"&gt;Jlc PCB&lt;/a&gt; or &lt;a href="https://www.pcbway.com/"&gt;PCB Way&lt;/a&gt;— but that probably is a good thing as I could not understand most of these options anyways.&lt;/p&gt;
&lt;p&gt;Delivery takes a bit of time, because the PCBs are manufactured by batches, but I eventually received this:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.zpqrtbnk.net/imgx/0pwbawtq/img_0668-mw-600.jpg?hmac=c2b2262ec1535821de1380930e9328c31570c1c54bfbfa355ffef21151970963" alt="IMG 0668" class="img-center" alt="pcb" /&gt;&lt;/p&gt;
&lt;p&gt;Finally, a bit of soldering takes us to the final state. The LED on the left blinks at 500Hz thanks to a true NE555 chip, and can be observed with the scope, while the LED on the right blinks at .5Hz thanks to the Three Five Kits.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.zpqrtbnk.net/imgx/vv0bt1wv/img_0670-mw-600.jpg?hmac=01c5f45b5361e33db5a123182a942d859a464bc7c78bc2639421d9f7b064a2f7" alt="IMG 0670" class="img-center" alt="pcb" /&gt;&lt;/p&gt;
&lt;p&gt;Looks way cleaner in my office now.&lt;/p&gt;
</description>
      <pubDate>Thu, 19 Mar 2020 17:45:00 Z</pubDate>
      <a10:updated>2020-03-19T17:45:00Z</a10:updated>
      <a10:rights type="html">Copyright &amp;copy; 1985-2026 Stéphane Gay</a10:rights>
    </item>
    <item>
      <guid isPermaLink="false">1294</guid>
      <link>https://www.zpqrtbnk.net/posts/french-developer-keyboard-2/</link>
      <author>sgay@pilotine.com</author>
      <category>hacks</category>
      <title>French Developer Keyboard (2)</title>
      <description>&lt;p&gt;For years now, my main keyboard has been a black &lt;a href="https://www.daskeyboard.com/"&gt;DasKeyboard&lt;/a&gt;. As in, totally black, no marking. Very much hype. It has allowed me to do cool things, such as remapping the layout to get a &lt;a href=""&gt;French developer keyboard&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;My layout is a mix of Azerty (French) and Qwerty with characters such as curlies and brackets in convenient places. Makes programming way easier, is easy to learn, and not too different from what everyone uses—so it's not too hard to switch to and from other machines.&lt;/p&gt;
&lt;p&gt;It always impresses people that I can type without having any marking on the keyboard. The blue Cherry MX switches make an amazingly loud noise... all in all, very cool. At least at the beginning. After a while, typing this very cryptic password without making mistakes reveals tricky, and don't mention the crazy noise.&lt;/p&gt;
&lt;p&gt;In addition, having used my custom layout for about two years now, the positions have stabilized to the following layout, and I don't expect them to move anytime soon.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.zpqrtbnk.net/imgx/cy3a3zqj/layout-mw-600.png?hmac=3f91fb7a166d0bf542922321ca3de21d4d57df818acc39374c22f607f747e851" alt="Layout" class="img-center" alt="layout" /&gt;&lt;/p&gt;
&lt;p&gt;And so... I have finally ordered my own custom &lt;a href="https://www.wasdkeyboards.com/"&gt;WASD&lt;/a&gt; keyboard. It has a very discreet marking, and quiter brown Cherry MX switches.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.zpqrtbnk.net/imgx/0kql4hlm/img_0563-fit-600x240x1x1-0x0x0x0-75.jpg?hmac=58f9ed8f8ad34ae27215b254239e231f85ccdfea2aafdbaab9fdfd5204c24891" alt="IMG 0563" class="img-center" alt="layout" /&gt;&lt;/p&gt;
&lt;p&gt;So far... I'm liking it a lot.&lt;/p&gt;
</description>
      <pubDate>Thu, 12 Mar 2020 14:05:00 Z</pubDate>
      <a10:updated>2020-03-12T14:05:00Z</a10:updated>
      <a10:rights type="html">Copyright &amp;copy; 1985-2026 Stéphane Gay</a10:rights>
    </item>
    <item>
      <guid isPermaLink="false">1292</guid>
      <link>https://www.zpqrtbnk.net/posts/umbraco-life-experiment-feedback/</link>
      <author>sgay@pilotine.com</author>
      <category>umbraco</category>
      <category>life</category>
      <title>Umbraco Life Experiment: Feedback</title>
      <description>&lt;p&gt;A few weeks ago I started an &lt;a href="https://www.zpqrtbnk.net/posts/umbraco-life-experiment/"&gt;experiment&lt;/a&gt;, and promised to be transparent about it, so... here is some feedback.&lt;/p&gt;
&lt;p&gt;The ZpqrtBnk General License has received a few orders, totalling about 3% of its financing goal. Though other more significant participations have been considered, they will not turn into real orders.&lt;/p&gt;
&lt;h4 id="what-happened"&gt;What Happened?&lt;/h4&gt;
&lt;p&gt;A broad range of people discussed various topics, such as the value of the General License and what it could deliver, the outcomes of the recent Umbraco &lt;a href="https://umbraco.com/blog/notes-from-the-community-roundtable-discussion/"&gt;Community Roundtable&lt;/a&gt;, how &amp;quot;Umbraco has changed&amp;quot;, the role of a community, and the general direction and agility of the CMS project.&lt;/p&gt;
&lt;p&gt;To make it short, the consensus is that it would probably not be possible to achieve much in the current context. And that it may be time to acknowledge what we cannot change. As a usually discreet community member puts it, it may just be simpler to pretend everything is all right—and reconsider expectations and commitments.&lt;/p&gt;
&lt;p&gt;The web publishing landscape is quickly evolving, new projects and new ways of building sites appear, new momentums form, safety may require diversification, life is too short, we all want to move forward, all those things.&lt;/p&gt;
&lt;h4 id="what-does-that-take-us"&gt;What Does That Take Us?&lt;/h4&gt;
&lt;p&gt;I am now terminating the General License experiment. I will not issue licences, nor invoice anyone.&lt;/p&gt;
&lt;p&gt;To all of you who have encouraged the experiment or raised concerns, offered perspectives, placed or considered orders or explained why you would not: a massive &lt;em&gt;thank you&lt;/em&gt;, #h5yr. I owe you a lot, you truly are a community.&lt;/p&gt;
&lt;p&gt;As far as &lt;a href="https://github.com/zpqrtbnk/Zbu.ModelsBuilder"&gt;ModelsBuilder&lt;/a&gt; or Umbraco are concerned, I am back to full Open Source mode which, as &lt;a href="https://arstechnica.com/information-technology/2019/10/is-the-software-world-taking-too-much-from-the-open-source-community/"&gt;Bruce Perens states&lt;/a&gt;, is all about generosity&lt;a id="fnref:1" href="#fn:1" class="footnote-ref"&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt;. I will happily release new versions and contributions, if and when I have the time and motivation to do so.&lt;/p&gt;
&lt;p&gt;❤︎&lt;/p&gt;
&lt;p&gt;Be seeing U!&lt;/p&gt;
&lt;div class="footnotes"&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;Yes, I am considering a Patreon or GitHub sponsorship to help finding time for Models Builder.&lt;a href="#fnref:1" class="footnote-back-ref"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
</description>
      <pubDate>Tue, 29 Oct 2019 18:35:00 Z</pubDate>
      <a10:updated>2019-10-29T18:35:00Z</a10:updated>
      <a10:rights type="html">Copyright &amp;copy; 1985-2026 Stéphane Gay</a10:rights>
    </item>
    <item>
      <guid isPermaLink="false">1286</guid>
      <link>https://www.zpqrtbnk.net/posts/net-core-30-release/</link>
      <author>sgay@pilotine.com</author>
      <category>dotnet</category>
      <category>umbraco</category>
      <category>beyumbe</category>
      <title>.NET Core 3.0 Release</title>
      <description>&lt;p&gt;This week is &lt;a href="https://www.dotnetconf.net/"&gt;.NET Conf&lt;/a&gt; 2019, and as expected (after a &lt;a href="https://www.theregister.co.uk/2019/09/17/net_core_3_rc1/"&gt;suprise RC1&lt;/a&gt;), .NET Core 3.0 has been officially launched (see the &lt;a href="https://devblogs.microsoft.com/dotnet/announcing-net-core-3-0/"&gt;announcement&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;And what better way to celebrate, than to experiment with it?&lt;/p&gt;
&lt;h4 id="let-the-fun-begin"&gt;Let the Fun Begin&lt;/h4&gt;
&lt;p&gt;&lt;img src="https://www.zpqrtbnk.net/media/ioudlvts/netcore-128.png" alt="Netcore 128" class="img-right" alt="docker" /&gt;&lt;/p&gt;
&lt;p&gt;This site now has a B-side, at &lt;a href="http://b.zpqrtbnk.net"&gt;b.zpqrtbnk.net&lt;/a&gt;. It runs on the same Windows server (just another IIS site) and the same database instance. It is, so far, a typical load-balanced scenario. It is powered by Umbraco... on AspNet Core 3.0, thanks to Beyumbe.&lt;/p&gt;
&lt;p&gt;Beyumbe is an experimental / lab software layer that provides most of the .NET Core plumbing for Umbraco: bootstrapping the application, hosting, dependency injection, filesystems, logging, background-tasking, routing, etc.&lt;/p&gt;
&lt;p&gt;Umbraco sits on top of this layer, pretty much unchanged, and provides the content cache, its pipeline and services, etc—everything that is required to &lt;em&gt;publish&lt;/em&gt; content. It &lt;em&gt;does&lt;/em&gt; run its distributed cache, for instance.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.zpqrtbnk.net/media/2eqdklef/docker-128.png" alt="Vertical Logo Monochromatic" class="img-right" alt="docker" /&gt;&lt;/p&gt;
&lt;p&gt;One of the benefits of running a pure .NET Core site, apart from the excitement, is that it can be turned into a Docker container. This site now also has a C-side (can you picture this?) at &lt;a href="http://c.zpqrtbnk.net"&gt;c.zpqrtbnk.net&lt;/a&gt;. It runs as a Linux Docker container on Amazon AWS &lt;a href="https://aws.amazon.com/fr/fargate/"&gt;Fargate&lt;/a&gt; service. It is &lt;em&gt;also&lt;/em&gt; part of the load-balancing scenario, and updates with the other sides.&lt;/p&gt;
&lt;p&gt;You might notice that this C-side does not render images. Fargate in a compute engine, which simply executes containers. It does not yet support mounting filesystems into containers, and this prevents us from sharing a common media directory. The &lt;a href="https://github.com/aws/containers-roadmap/issues/53"&gt;feature&lt;/a&gt; is currently &amp;quot;in progress&amp;quot; at Amazon, yet with no ETA.&lt;/p&gt;
&lt;p&gt;Azure does seem to support mounting Azure Files shares into Azure Containers, so it may be easier on Azure. Unfortunately, I don't really have time to experiment on both platforms at the moment.&lt;/p&gt;
&lt;h4 id="next"&gt;Next?&lt;/h4&gt;
&lt;p&gt;Beyumbe needs some love and polish to be able to support Umbraco in a robust way, as the whole thing was put together in a &lt;em&gt;very&lt;/em&gt; short time. But it is slowly getting there.&lt;/p&gt;
&lt;p&gt;As for Umbraco itself, most of the &lt;code&gt;Umbraco.Core&lt;/code&gt; project is ported, but work remain to deal with configuration, identity &amp;amp; security, and the runtime / maindom.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;Umbraco.Web&lt;/code&gt; project is an entirely different beast. Only the very basic minimum, required to render content, has been ported. Everything else, from trees to controllers, WebApi to healthchecks, you name it, needs to be ported.&lt;/p&gt;
&lt;p&gt;Umbraco on .NET Core? Not fully there yet. But a nice project.&lt;/p&gt;
</description>
      <pubDate>Mon, 23 Sep 2019 19:20:00 Z</pubDate>
      <a10:updated>2019-09-23T19:20:00Z</a10:updated>
      <a10:rights type="html">Copyright &amp;copy; 1985-2026 Stéphane Gay</a10:rights>
    </item>
    <item>
      <guid isPermaLink="false">1272</guid>
      <link>https://www.zpqrtbnk.net/posts/umbraco-life-experiment/</link>
      <author>sgay@pilotine.com</author>
      <category>umbraco</category>
      <category>life</category>
      <title>Umbraco Life Experiment</title>
      <description>&lt;p&gt;A few months ago I announced I would be leaving HQ and transitioning back to the community side of Umbraco, end of September. People assumed I had some sort of a Grand Plan, an amazing business idea—but the reality is more complex.&lt;/p&gt;
&lt;p&gt;Let's say I wanted to be closer to community and client work, in order to contribute in a more direct and effective way on various tools, features and topics that have been lagging for some time. With the goal of helping Umbraco be a strong, reliable yet simple platform for pro &amp;amp; advanced users—and friendly, of course.&lt;/p&gt;
&lt;p&gt;And... the roadmap was not much clearer than that.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.zpqrtbnk.net/imgx/2xefatm1/roadmap-blur-fit-600x120x1x1-0x0x0x0-75.png?hmac=5b4160e635a212431c152d8f68209d99bac34720e3818979f05badaa9c12f806" alt="Roadmap Blur" class="img-center" alt="roadmap" /&gt;&lt;/p&gt;
&lt;p&gt;Over the past 3 months, I have had numerous conversations with many members of the community, to find out what people valued and needed, and how they imagined these services could be delivered. Thanks to the thelp of those precious friends, I am now ready to introduce...&lt;/p&gt;
&lt;h4 id="the-experiment"&gt;The Experiment&lt;/h4&gt;
&lt;p&gt;I should be looking for a new role (.NET/C#/architecture), really. At least that is what all my &amp;quot;entreprise&amp;quot; friends tell me. But before I do, I want to try something.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Services:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;As of October 1st, I am immediately available for .NET work, as freelance. Umbraco, non-Umbraco, technical, less technical (I have spent a good deal of my life managing projects, too).&lt;/p&gt;
&lt;p&gt;Umbraco-wise, I provide &lt;strong&gt;Architecture Guiding&lt;/strong&gt; and &lt;strong&gt;Troubleshooting Guiding&lt;/strong&gt; services. Here, &lt;em&gt;guiding&lt;/em&gt; means working &lt;em&gt;with you&lt;/em&gt;, advising and teaching, on real cases, to reach solutions. Per hour, or per day, and optionally on-site.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Software:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/zpqrtbnk/Zbu.ModelsBuilder"&gt;Models Builder&lt;/a&gt;, and any other tools I may release, &lt;strong&gt;remains open source, and free&lt;/strong&gt;. They are distributed under the MIT license, &lt;strong&gt;but with a twist&lt;/strong&gt;. If you use them in any way that allows you to make money, directly or indirectly, and/or if you expect any kind of support, you are morally required to purchase a...&lt;/p&gt;
&lt;h4 id="zpqrtbnk-general-license"&gt;ZpqrtBnk General License&lt;/h4&gt;
&lt;p&gt;Everything may be open, but I still need a way to secure an income. Therefore, much alike Poul-Henning Kamp's &lt;a href="http://phk.freebsd.dk/VML/"&gt;Varnish Moral License&lt;/a&gt;, I am introducing the &lt;strong&gt;ZpqrtBnk General License&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;It works like this: you tell me that you want to purchase a license. You &lt;em&gt;set your price&lt;/em&gt;. I send you an invoice from my &lt;a href="https://www.pilotine.com/en/"&gt;company&lt;/a&gt; (official, proper company invoice, handling VAT numbers etc). You pay the invoice. You are on the list.&lt;/p&gt;
&lt;p&gt;You then have the moral right to use the tools I release. You can expect them to be maintained, bugs to be fixed, questions to be answered, and feature requests to be considered.&lt;/p&gt;
&lt;p&gt;In addition, you ensure that I can keep improving people's Umbraco and .NET lives, be it on the community Slack, on Our, at meetups and festivals, or by fixing bugs, implementing features, etc.&lt;/p&gt;
&lt;p&gt;This is not a Make Money Fast scheme; the goal is to maintain my income. PHK is radical about it, and publishes his accounting status (eg, &lt;a href="http://phk.freebsd.dk/VML/2019/"&gt;2019&lt;/a&gt;). I don't know exactly how I will do it, but the plan is to be transparent too.&lt;/p&gt;
&lt;p&gt;Browse to the &lt;a href="https://www.zpqrtbnk.net/zpqrtbnk-general-license/"&gt;ZpqrtBnk General License&lt;/a&gt; page for infos and FAQs. Or to the &lt;a href="https://www.zpqrtbnk.net/zpqrtbnk-general-license/questions/"&gt;General License Questions&lt;/a&gt; for even more questions.&lt;/p&gt;
&lt;h4 id="ah-but"&gt;Ah, but...&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;This is never going to work. People don't pay for what they can have for free. Who do you think you are? If I need to pay I am going to build it myself! You cannot enforce your license anyways. You cannot make a living of it. Others have tried.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;True. And reasons why the whole thing is an &lt;em&gt;experiment&lt;/em&gt;. I am interested in seeing what happens, but I am not completely naïve. Sure, I want free, open-source software, sponsored by people who value it. I don't want to issue activation codes, or hear about developers having to use &lt;a href="https://www.jetbrains.com/decompiler/"&gt;dotPeek&lt;/a&gt; to figure out issues in my private code, etc.&lt;/p&gt;
&lt;p&gt;But, this: &lt;strong&gt;noone is getting anything for free&lt;/strong&gt;. Either it works, or I have to stop and humbly move on to something else—no offense. It's as simple. It's an experiment, it's a real challenge for my &lt;a href="https://en.wikipedia.org/wiki/Impostor_syndrome"&gt;impostor syndrome&lt;/a&gt;, but I want to at least try it.&lt;/p&gt;
&lt;p&gt;Models Builder has a new &lt;a href="https://github.com/zpqrtbnk/Zbu.ModelsBuilder/milestone/20"&gt;milestone&lt;/a&gt; and work-in-progress: a new, autonomous version, adding features to the built-in version. But—that is only going to happen if my family can eat ;-)&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.zpqrtbnk.net/imgx/i13nap2j/open-road-fit-600x180x1x1-0x0x0x0-75.jpg?hmac=b5446af7f089b0cfec8bd1bc733695e41eeac2ef308c07eedebd8e5b64c10658" alt="Open Road" class="img-center" alt="roadmap" /&gt;&lt;/p&gt;
&lt;p&gt;Current balance is zero, and I have approximatively zero autonomy beyond October.&lt;/p&gt;
&lt;p&gt;Let's see where this goes.&lt;/p&gt;
</description>
      <pubDate>Fri, 13 Sep 2019 19:00:00 Z</pubDate>
      <a10:updated>2019-09-13T19:00:00Z</a10:updated>
      <a10:rights type="html">Copyright &amp;copy; 1985-2026 Stéphane Gay</a10:rights>
    </item>
    <item>
      <guid isPermaLink="false">1278</guid>
      <link>https://www.zpqrtbnk.net/posts/umbraco-814-breaking-models-builder/</link>
      <author>sgay@pilotine.com</author>
      <category>umbraco</category>
      <title>Umbraco 8.1.4 Breaking &amp; Models Builder</title>
      <description>&lt;p&gt;&lt;em&gt;UPDATED: the proposed workaround has been simplified, see at the bottom of this post.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The Umbraco 8.1.4 release fixes issue &lt;a href="https://github.com/umbraco/Umbraco-CMS/issues/6033"&gt;#6033&lt;/a&gt; but introduces a breaking change.&lt;/p&gt;
&lt;p&gt;Up until this release, when a media picker was configured to pick only images, the corresponding property value converter would report the property type as &lt;code&gt;Image&lt;/code&gt; or &lt;code&gt;IEnumerable&amp;lt;Image&amp;gt;&lt;/code&gt; and Models Builder would generate the property as (in &lt;code&gt;MyModel.generated.cs&lt;/code&gt;):&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-csharp"&gt;public partial class MyModel
{
  // ...

  [ImplementPropertyType("myImage")]
  public Image MyImage
    =&gt; this.Value&lt;Image&gt;("myImage");

  [ImplementPropertyType("myImages")]
  public IEnumerable&lt;Image&gt; MyImages
    =&gt; this.Value&lt;IEnumerable&lt;Image&gt;&gt;("myImages");
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Thus allowing you to write:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-txt"&gt;&lt;img src="@Model.MyImage.GetCropUrl("crop")"
     alt="@Model.MyImage.AltDescription" /&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Unfortunately, that was based on the assumption that, with this configuration, the media picker would only allow media of type &amp;quot;image&amp;quot; (or anything inheriting &amp;quot;image&amp;quot;) to be picked. In reality, it seems that the media picker has different rules and allows various types of media to be picked.&lt;/p&gt;
&lt;p&gt;As a consequence, users would see nasty YSODs when picking anything that would &lt;em&gt;not&lt;/em&gt; inherit from &amp;quot;image&amp;quot;, as it would of course not fit within an &lt;code&gt;IEnumerable&amp;lt;Image&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The fix that was introduced forces the property value converter to report the property type as &lt;code&gt;IPublishedContent&lt;/code&gt; or &lt;code&gt;IEnumerable&amp;lt;IPublishedContent&amp;gt;&lt;/code&gt; no matter what can be picked. Alas, that breaks the existing Models Builder properties. And, if you re-generate models, what was &lt;code&gt;Image&lt;/code&gt; becomes &lt;code&gt;IPublishedContent&lt;/code&gt; and you lose the direct access to properties such as width or height.&lt;/p&gt;
&lt;h4 id="workaround"&gt;Workaround&lt;/h4&gt;
&lt;p&gt;However, assuming that you know that you are only going to pick images, you do &lt;em&gt;not&lt;/em&gt; want to clutter your views with casts or non-strongly-typed property accesses.&lt;/p&gt;
&lt;p&gt;The workaround to keep all your views unchanged and clean, consists in declaring your own implementations of these properties, in a partial class, alongside the existing models. Models Builder will detect them, and not generate anything. You want (in &lt;code&gt;MyModel.cs&lt;/code&gt;):&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-csharp"&gt;public partial class MyModel
{
  [ImplementPropertyType("myImage")]
  public Image MyImage
    =&gt; this.Value&lt;IPublishedContent&gt;("myImage") as Image;

  [ImplementPropertyType("myImages")]
  public IEnumerable&lt;Image&gt; MyImages
    =&gt; this.Value&lt;IEnumerable&lt;IPublishedContent&gt;&gt;("myImages")
           .OfType&lt;Image&gt;();
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This can be tedious, though, if you have a lot of models.&lt;/p&gt;
&lt;h4 id="workaround-2"&gt;Workaround (2)&lt;/h4&gt;
&lt;p&gt;&lt;em&gt;UPDATE: This workaround works but is too complex, for no reason. Read it, then see the next workaround for the simple solution.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Alternatively, there is a more radical approach, if you are brave enough. Get the code for &lt;code&gt;MediaPickerValueConverter&lt;/code&gt; from 8.1.3, drop it into your own solution, and use a composer to use it in place of the one that ships with 8.1.4:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-csharp"&gt;using UmbracoConverters = Umbraco.Web.PropertyEditors.ValueConverters;

public void Compose(Composition composition)
{
  composition.PropertyValueConverters()
    .Remove&lt;UmbracoConverters.MediaPickerValueConverter&gt;()
    .Append&lt;MyConverters.MediaPickerConverter&gt;()
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Everything will be back to normal, and that is probably what I am going to do on this site. But then of course, you end up running with a non-standard converter.&lt;/p&gt;
&lt;h4 id="workaround-3"&gt;Workaround (3)&lt;/h4&gt;
&lt;p&gt;Same as above, get the code for &lt;code&gt;MediaPickerValueConverter&lt;/code&gt; from 8.1.3, drop it into your own solution, and make sure you remove its &lt;code&gt;[DefaultPropertyValueConverter]&lt;/code&gt;. That's it. No need for a composer. Since your converter is not &amp;quot;default&amp;quot;, it will override the default one.&lt;/p&gt;
&lt;p&gt;And, even better, you can use the converter posted by Ronald in &lt;a href="https://github.com/umbraco/Umbraco-CMS/issues/6033#issuecomment-528334114"&gt;this comment&lt;/a&gt; on the original GitHub issue. It tries to mitigate the issue in a nice way.&lt;/p&gt;
&lt;p&gt;I am afraid there is no ideal, immediate solution. In a perfect world... the media picker should be fixed, so one can indicate a (base) type to be picked, and so that only media of that type can be picked...&lt;/p&gt;
</description>
      <pubDate>Wed, 04 Sep 2019 16:40:00 Z</pubDate>
      <a10:updated>2019-09-04T16:40:00Z</a10:updated>
      <a10:rights type="html">Copyright &amp;copy; 1985-2026 Stéphane Gay</a10:rights>
    </item>
    <item>
      <guid isPermaLink="false">1273</guid>
      <link>https://www.zpqrtbnk.net/posts/missing-folders-in-umbraco-tree/</link>
      <author>sgay@pilotine.com</author>
      <category>umbraco</category>
      <title>Missing Folders in Umbraco Tree</title>
      <description>&lt;p&gt;On this very site, which originally started as a v7 site and has slowly been upgraded to the latest 8.1 release, something weird started happening. Some media folders stopped showing in the media tree left), although they would still show in the media panel (right).&lt;/p&gt;
&lt;p&gt;So: the media folders still existed, but they just did not show in trees.&lt;/p&gt;
&lt;p&gt;I am pretty sure it worked with 8.0, and stopped working with 8.1. Which is strange, as the &lt;a href="https://github.com/umbraco/Umbraco-CMS/issues/6158"&gt;original issue&lt;/a&gt; seems to target the 7-to-8 upgrade. Anyways. I just wanted to share the cause, and the fix.&lt;/p&gt;
&lt;p&gt;The cause is missing rows in the &lt;code&gt;umbracoMediaVersion&lt;/code&gt; table for these folders. The fix consists in inserting these missing rows again.&lt;/p&gt;
&lt;p&gt;This is exactly what the following SQL does:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-sql"&gt;insert into umbracoMediaVersion (id, path)
select VersionId, NULL
from (

	select n.id NodeId, n.Text Name, ct.alias Alias, cv.id VersionId, mv.id MvId, mv.path MvPath
	from umbracoNode n
	join umbracoContent c on n.id=c.nodeId
	join cmsContentType ct on c.contentTypeId=ct.nodeId
	join umbracoContentVersion cv on n.id=cv.nodeId
	left outer join umbracoMediaVersion mv on cv.id=mv.id
	where n.nodeObjectType='B796F64C-1F99-4FFB-B886-4BF4BC011A9C'

	and ct.alias='Folder' -- only folders
	and mv.id is null -- that dont have the required row
) x&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that you may want to run the inner query first, just to verify that your database is indeed missing these rows.&lt;/p&gt;
</description>
      <pubDate>Fri, 30 Aug 2019 14:55:00 Z</pubDate>
      <a10:updated>2019-08-30T14:55:00Z</a10:updated>
      <a10:rights type="html">Copyright &amp;copy; 1985-2026 Stéphane Gay</a10:rights>
    </item>
    <item>
      <guid isPermaLink="false">1236</guid>
      <link>https://www.zpqrtbnk.net/posts/models-builder-extension/</link>
      <author>sgay@pilotine.com</author>
      <category>umbraco</category>
      <title>Models Builder Extension</title>
      <description>&lt;p&gt;One way to generate models for Umbraco with the &lt;a href="https://github.com/zpqrtbnk/Zbu.ModelsBuilder"&gt;Models Builder&lt;/a&gt; tool has long been to use the Visual Studio &lt;a href="https://marketplace.visualstudio.com/items?itemName=ZpqrtBnk.UmbracoModelsBuilderCustomTool"&gt;Custom Tool&lt;/a&gt;. This extension provides a &lt;em&gt;Single File Generator&lt;/em&gt; which can be used just as any standard Visual Studio Custom Tool.&lt;/p&gt;
&lt;p&gt;Meanwhile, Microsoft has introduced .NET Core and is slowly evolving the structure of its Visual Studio projects, and updating the tooling along the way. Let us say that the road is, sometimes, a bit unclear and hard to follow.&lt;/p&gt;
&lt;p&gt;Using a single file generator to generate multiple files has traditionally been &amp;quot;the way&amp;quot; to do it, but it has also always been hackish, and as &lt;a href="https://github.com/zpqrtbnk/Zbu.ModelsBuilder/issues/210"&gt;this issue&lt;/a&gt; and others made obvious. It is becoming harder and harder to support with the new &amp;quot;NET.Sdk&amp;quot; project types.&lt;/p&gt;
&lt;p&gt;I am, therefore, sad to announce that the Custom Tool is now dead. But do not despair! It is superceeded by the &lt;em&gt;Extension&lt;/em&gt;, which, essentially, provides exactly the same service, in a slightly different way.&lt;/p&gt;
&lt;h4 id="migrating"&gt;Migrating&lt;/h4&gt;
&lt;p&gt;In order to migrate to the extension, first uninstall the Custom Tool extension, then install the Extension.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.zpqrtbnk.net/imgx/z2eh5f31/snap5-mw-600.png?hmac=3585ce9aea8a0f94046d4d132a7dd49ae36696c524eaadb396d4dd15f45ba845" alt="Snap5" class="img-center" alt="BuildModels" /&gt;&lt;/p&gt;
&lt;p&gt;Then, the only difference is that models are not generated under a C# file anymore, but under a special placeholder. You &lt;em&gt;probably&lt;/em&gt; don't need the root C# file anymore, unless it contained attributes to configure models. The next section will explain it all.&lt;/p&gt;
&lt;p&gt;The configuration (in &lt;strong&gt;Tools&lt;/strong&gt; | &lt;strong&gt;Options&lt;/strong&gt;) remain the same.&lt;/p&gt;
&lt;h4 id="using-the-extension"&gt;Using the extension&lt;/h4&gt;
&lt;p&gt;Right-click on the folder containing your models, both the generated and non-generated partials. Select &lt;strong&gt;Add&lt;/strong&gt; | &lt;strong&gt;New item...&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.zpqrtbnk.net/imgx/brxnkueo/snap1-mw-600.png?hmac=8e721d7a54cd74f29244956bf9cfbc9b2ab2dc493a0255f4da7787042803ed40" alt="Snap1" class="img-center" alt="AddNewItem" /&gt;&lt;/p&gt;
&lt;p&gt;Select &lt;strong&gt;Visual C#&lt;/strong&gt;, &lt;strong&gt;Umbraco&lt;/strong&gt;, and add a new Umbraco Models placeholder named, for instance, &lt;code&gt;Models.mb&lt;/code&gt;. The name is of no importance, only the extension is.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.zpqrtbnk.net/imgx/kulhrg0x/snap2-mw-600.png?hmac=dc7529e7dbb9fd9efde371ec03f184dc318f078832abeda895733097fd677ce8" alt="Snap2" class="img-center" alt="ModelsPlaceHolder" /&gt;&lt;/p&gt;
&lt;p&gt;Now, right-click on that new &lt;code&gt;Models.mb&lt;/code&gt; file and select &lt;strong&gt;Build Models&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.zpqrtbnk.net/imgx/seun413e/snap3-mw-600.png?hmac=e013dc44ec2e4cb5c869b3eec68eaed715537ac308c84fb5a5f802aafca7a511" alt="Snap3" class="img-center" alt="BuildModels" /&gt;&lt;/p&gt;
&lt;p&gt;The extension connects to the running site, retrieves models, and adds them to the project, nicely nested under the models placeholder.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.zpqrtbnk.net/imgx/sebh1i1h/snap4-mw-600.png?hmac=ca2139e13b9250d054de236904967c8400fa9a8fdfbdee4725dadd228aa54a44" alt="Snap4" class="img-center" alt="BuildModels" /&gt;&lt;/p&gt;
&lt;h4 id="configuring"&gt;Configuring&lt;/h4&gt;
&lt;p&gt;By default, models are generated in a namespace derived from the root namespace of the project, and the folders structure. That, and various other aspects of models, can be configured via attributes.&lt;/p&gt;
&lt;p&gt;Add a file &lt;code&gt;Models.cs&lt;/code&gt; (or any other name, as long as it is a C# file) to the models folder, containing the following code (it does not need to contain a class definition!):&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-csharp"&gt;using Umbraco.ModelsBuilder;

[assembly:ModelsNamespace("MyOwnNamespace")]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That file will be parsed, and models will be generated in &lt;code&gt;MyOwnNamespace&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Refer to the (kinda obsolete, soon to be updated) &lt;a href="https://github.com/zpqrtbnk/Zbu.ModelsBuilder/wiki/ModelsGenerationConfiguration"&gt;documentation&lt;/a&gt; for more attributes.&lt;/p&gt;
&lt;h4 id="whats-next"&gt;What's Next?&lt;/h4&gt;
&lt;p&gt;As mentioned above, the documentation is kinda obsolete. There are tons of things that can be configured, and noone is aware of it. Next effort will be to cleanup the documentation, and implement some long-requested features.&lt;/p&gt;
&lt;p&gt;Stay tuned!&lt;/p&gt;
</description>
      <pubDate>Fri, 19 Jul 2019 09:51:01 Z</pubDate>
      <a10:updated>2019-07-19T09:51:01Z</a10:updated>
      <a10:rights type="html">Copyright &amp;copy; 1985-2026 Stéphane Gay</a10:rights>
    </item>
    <item>
      <guid isPermaLink="false">1232</guid>
      <link>https://www.zpqrtbnk.net/posts/solutionbook-for-visual-studio-2019/</link>
      <author>sgay@pilotine.com</author>
      <category>hacks</category>
      <title>SolutionBook for Visual Studio 2019</title>
      <description>&lt;p&gt;For many years, I have used the excellent &lt;a href="https://marketplace.visualstudio.com/items?itemName=Herdo.SolutionStartPage"&gt;SolutionStartPage&lt;/a&gt; extension for Visual Studio 2015 and 2017. This extension replaces the default Start Page with a customizable view of all my solutions. It is like a giant start menu: fire Visual Studio, pick the solution you want to work on.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.zpqrtbnk.net/media/kjqmhypy/2019-06-20-11_53_32-start-page-microsoft-visual-studio-_.png" alt="2019 06 20 11 53 32 Start Page Microsoft Visual Studio" alt="SolutionStartPage" /&gt;&lt;/p&gt;
&lt;p&gt;Alas, Visual Studio 2019 has replaced the start page with an entirely different start &lt;em&gt;window&lt;/em&gt;, which cannot really be modified, entirely breaking SolutionStartPage (see issue &lt;a href="https://github.com/Herdo/SolutionStartPage/issues/25"&gt;#25&lt;/a&gt;). There are a few discussions about the future of the start page on Visual Studio's developper community (see for instance &lt;a href="https://developercommunity.visualstudio.com/idea/531110/allow-cutomization-or-extension-of-the-new-start-w.html"&gt;this one&lt;/a&gt;) but it does not seem that Microsoft is going to address the situation anytime soon.&lt;/p&gt;
&lt;p&gt;And, this makes working with Visual Studio 2019 way more annoying. I was really used to just firing Visual Studio and opening a frequently-used solution, without having to think about where it is on my disk.&lt;/p&gt;
&lt;h4 id="problem-solution"&gt;Problem → Solution&lt;/h4&gt;
&lt;p&gt;So... I spent a couple of evenings putting together a replacement for Visual Studio 2019, and... &lt;strong&gt;SolutionBook&lt;/strong&gt; is now available on the &lt;a href="https://marketplace.visualstudio.com/items?itemName=ZpqrtBnk.SolutionBook"&gt;Visual Studio MarketPlace&lt;/a&gt; with code in its own &lt;a href="https://github.com/zpqrtbnk/SolutionBook"&gt;GitHub repository&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This extension installs a new Visual Studio tool window, which can be displayed with &lt;strong&gt;View&lt;/strong&gt; | &lt;strong&gt;Other Windows&lt;/strong&gt; | &lt;strong&gt;SolutionBook&lt;/strong&gt;, and docked anywhere—I dock mine to the left, with the already existing &lt;strong&gt;Toolbox&lt;/strong&gt; tool window.&lt;/p&gt;
&lt;p&gt;It lets you organize your solutions in a tree. It's always there when Visual Studio opens, and double-clicking a solution just opens it. You can add and remove solutions, move them around, group them in folders, etc. That is all. It saves me tons of time. YMMV.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.zpqrtbnk.net/media/xp2fmcfm/2019-06-20-11_44_43-umbraco-8-_.png" alt="2019 06 20 11 44 43 Umbraco 8" class="img-center" alt="SolutionStartPage" /&gt;&lt;/p&gt;
&lt;p&gt;Note: you &lt;em&gt;have&lt;/em&gt; to save your changes using the toolbar button. Saving is &lt;em&gt;not&lt;/em&gt; automatic. And it &lt;em&gt;won't&lt;/em&gt; tell you if you forget. And the &lt;em&gt;Refresh&lt;/em&gt; toolbar buttons reloads from disk. This is how concurrency between multiple Visual Studio instances is (not) managed.&lt;/p&gt;
&lt;p&gt;Another note: this was all quickly put together. WPF is fantastic but also hard. There may be issues, and it's probably not the cleanest code I have produced. Saving and refreshing should be all automagic. Feel free to contribute!&lt;/p&gt;
&lt;p&gt;Enjoy!&lt;/p&gt;
</description>
      <pubDate>Thu, 20 Jun 2019 12:10:00 Z</pubDate>
      <a10:updated>2019-06-20T12:10:00Z</a10:updated>
      <a10:rights type="html">Copyright &amp;copy; 1985-2026 Stéphane Gay</a10:rights>
    </item>
  </channel>
</rss>