<br />
<b>Deprecated</b>:  The each() function is deprecated. This message will be suppressed on further calls in <b>/home/zhenxiangba/zhenxiangba.com/public_html/phproxy-improved-master/index.php</b> on line <b>456</b><br />
<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>Alessia Bellisario</title>
        <link>https://aless.co</link>
        <description>alessia bellisario's blog</description>
        <lastBuildDate>Fri, 20 Mar 2026 10:09:41 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>Alessia Bellisario</title>
            <url>https://aless.co/favicon.ico</url>
            <link>https://aless.co</link>
        </image>
        <copyright>All rights reserved 2026</copyright>
        <item>
            <title><![CDATA[2024]]></title>
            <link>https://aless.co/2024</link>
            <guid>https://aless.co/2024</guid>
            <pubDate>Mon, 16 Dec 2024 00:00:00 GMT</pubDate>
            <content:encoded><![CDATA[<blockquote>
<p>Welcome to the sixth edition of my year in review. (See <a href="/2023">2023</a>, <a href="/2022">2022</a>, <a href="/2021">2021</a>, <a href="/2020">2020</a> and <a href="/2019">2019</a> for previous editions.)</p>
</blockquote>
<p>2024 was a year of two beautiful babies born to two of my best friends: congratulations to their proud, wonderful parents, Robin and Mark and Véro and Geoff ♥️</p>
<p>It was also the year I became an American citizen, my two younger siblings graduated from law school, I rounded out the first decade of my career as a software engineer and O turned 3. We also discovered apartment swapping this year: we did two, one with M in Montreal and the other with a family of Js from Berlin, two big highlights.</p>
<p>Let&#x27;s start at the beginning.</p>
<h2 id="see-you-never-uscis"><a class="anchor" href="#see-you-never-uscis"><span class="icon icon-link"></span></a>See you never, USCIS</h2>
<p>I came to the U.S. from Canada on a three year <a href="https://www.nolo.com/legal-encyclopedia/what-are-dual-intent-visas.html">dual intent</a> work visa, an L-1B, in early 2017. I was working at a Canadian startup with a New York office and quite literally hit the ground running: I remember dashing out to pick up my new social security card emblazoned with the words <code>VALID FOR WORK ONLY WITH DHS AUTHORIZATION</code> followed by a new SIM card in Chinatown on one of my first mornings.</p>
<p>In my first few weeks I attended a University of Toronto alumni event at a hotel by Central Park. I don&#x27;t know what I was expecting: it was a ballroom full of Canadians drinking cocktails discussing which visas they were on.</p>
<figure><img alt="" loading="lazy" width="2194" height="2194" decoding="async" data-nimg="1" style="color:transparent" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fcp.5b783398.jpg&amp;w=3840&amp;q=75 1x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fcp.5b783398.jpg&amp;w=3840&amp;q=75"/><figcaption>H-1B, L-1 or TN???</figcaption></figure>
<p>I lived in Williamsburg in a fourth floor walk-up with a roommate I found on Craigslist (shout out to Milo 💖) and worked in SoHo. It feels silly in retrospect, but I was <em><strong>actually surprised</strong></em> at how much I loved living in New York, pretty much immediately.</p>
<figure><img alt="" loading="lazy" width="750" height="1334" decoding="async" data-nimg="1" style="color:transparent" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fmilo.e1a4a5f5.png&amp;w=750&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fmilo.e1a4a5f5.png&amp;w=1920&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fmilo.e1a4a5f5.png&amp;w=1920&amp;q=75"/><figcaption>Winning the roommate lottery, June 2017</figcaption></figure>
<p>When I raised my hand for this opportunity, I wasn&#x27;t thinking long-term: it seemed like a new and interesting challenge, one that would be <strong>fun</strong>. But once I arrived, I realized the three year clock on my visa was already ticking. I had to start lobbying my employer to sponsor my green card application if I had any interest in buying myself more time. I also met Carla soon after arriving and didn&#x27;t want this new and clearly very special relationship cut short.</p>
<figure><img alt="" loading="lazy" width="2447" height="2448" decoding="async" data-nimg="1" style="color:transparent" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fquiche.9342deea.jpg&amp;w=3840&amp;q=75 1x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fquiche.9342deea.jpg&amp;w=3840&amp;q=75"/><figcaption>Soon after that exchange with Milo I won Carla&#x27;s heart with these homemade quiches</figcaption></figure>
<p>Thus began one of the most challenging periods of my life as I embarked on the journey from <a href="https://www.irs.gov/individuals/international-taxpayers/nonresident-aliens">nonresident alien</a> to lawful permanent resident, and finally citizen in February of this year.</p>
<p>There&#x27;s a lot more to say here and maybe I&#x27;ll write about it in greater detail one day. But seeing the life and career I was building dangling by a thread as I navigated a mind-bogglingly slow and artificial process, without job portability, while working at a faltering startup, all <strong>during a virulently anti-immigrant administration</strong>—<em>not to mention the early pandemic</em>—was so stressful it&#x27;s hard to describe.</p>
<figure><img alt="" loading="lazy" width="2418" height="2418" decoding="async" data-nimg="1" style="color:transparent" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fsubwayads.d67de1a4.jpg&amp;w=3840&amp;q=75 1x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fsubwayads.d67de1a4.jpg&amp;w=3840&amp;q=75"/><figcaption>2010s-era ZIRP: the B2B commercial real estate startup you work for inexplicably does a subway line + station ad takeover. NQRW trains + Union Square 🤑🤑</figcaption></figure>
<p>For four years, I obsessively read immigration forums and shared application timelines with fellow travelers through the broken system that is the U.S. Citizenship and Immigration Services. I felt totally powerless and dealt with depression and anxiety for the first time.</p>
<p>The people I found it easiest to talk to during this period were my grandparents, three of whom I&#x27;m very fortune to still be able to call. Speaking with them gave me comfort: they had immigrated to Canada from Italy in the 1950s with other close relatives ending up in the U.S., and they knew about the travel restrictions and missed life events that were part and parcel of this experience.</p>
<figure><img alt="" loading="lazy" width="1782" height="1782" decoding="async" data-nimg="1" style="color:transparent" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Falessia.ad4d761f.jpg&amp;w=1920&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Falessia.ad4d761f.jpg&amp;w=3840&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Falessia.ad4d761f.jpg&amp;w=3840&amp;q=75"/><figcaption>2017 me: so tired and rarely smiling</figcaption></figure>
<p>I&#x27;m happy I—a Canadian with a degree, though crucially not one relevant to the field I wound up in—can finally put down my bags, but so many people are stuck with <em>far</em> longer waits or without any path to legal status. The scale of human suffering caused by this system is mind numbing. It urgently needs to change.</p>
<p>The last thing I&#x27;ll add, in case it helps someone in the future, is how critical it is to consult a lawyer. But this is important: NOT the one your employer hires to work on your application. <em><strong>That is the company&#x27;s lawyer.</strong></em> The best advice I received was from attorney <a href="https://www.linkedin.com/in/jonathanlanger">Jonathan Langer</a>; if you&#x27;re ever in need of a U.S. immigration consult, I can&#x27;t recommend him highly enough.</p>
<p>Anyways, I&#x27;m American now. 🇺🇸 This is the place I call home, where I&#x27;ve started a family and plan to stay for the rest of my life—it still feels surreal to write those words.</p>
<h2 id="from-montreal-to-berlin"><a class="anchor" href="#from-montreal-to-berlin"><span class="icon icon-link"></span></a>From Montreal to Berlin</h2>
<p>In June, we went to Montreal to celebrate Carla&#x27;s birthday. It was our first apartment swap with a stranger (!): we stayed at M&#x27;s apartment in Little Italy and had a ball. We went to <a href="https://www.marchespublics-mtl.com/en/marches/jean-talon-market/">Jean Talon market</a>, the <a href="https://www.google.com/maps/place/Jarry+Park+wading+pool/@45.5372594,-73.6333003,17z/data=!4m10!1m2!2m1!1sParc+Jarry+swimming+pool+kids!3m6!1s0x4cc91bf8c3636cbf:0xa4a3dffe092aaba4!8m2!3d45.5372594!4d-73.6289229!15sCh1QYXJjIEphcnJ5IHN3aW1taW5nIHBvb2wga2lkc1ofIh1wYXJjIGphcnJ5IHN3aW1taW5nIHBvb2wga2lkc5IBFW91dGRvb3Jfc3dpbW1pbmdfcG9vbJoBJENoZERTVWhOTUc5blMwVkpRMEZuU1VSS0xVMWZTblozUlJBQuABAPoBBAgAEB0!16s%2Fg%2F1vc6d07f?entry=ttu&amp;g_ep=EgoyMDI0MTIxMC4wIKXMDSoASAFQAw%3D%3D">wading pool</a> and playgrounds in Jarry Park, <a href="https://iconoglace.ca/">Iconoglace</a> (run don&#x27;t walk, ice cream fans), did a 40km bike ride around the south-west part of the island with a rented trailer for O and ended Carla&#x27;s birthday at <a href="https://montrealjazzfest.com/en">JazzFest</a> for the second year in a row. We remain enamored with Montreal and want to do a winter family visit next.</p>
<figure><img alt="" loading="lazy" width="6000" height="4000" decoding="async" data-nimg="1" style="color:transparent" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fmtl.a61d703d.jpg&amp;w=3840&amp;q=75 1x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fmtl.a61d703d.jpg&amp;w=3840&amp;q=75"/></figure>
<p>In August, we celebrated O&#x27;s 3rd birthday on the plane to Berlin, concluding about a week of parties with friends and family in New York. He&#x27;s such a thoughtful, loving kid, and getting sillier by the day.</p>
<p>~Eight months earlier, we joined a home exchange group on Facebook and began searching for a match for a week in August when we had no childcare. We happened upon a family from Berlin that was planning a big American vacation and our dates lined up!</p>
<figure><img alt="" loading="lazy" width="2920" height="2920" decoding="async" data-nimg="1" style="color:transparent" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fberlincat.63b386bd.jpg&amp;w=3840&amp;q=75 1x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fberlincat.63b386bd.jpg&amp;w=3840&amp;q=75"/><figcaption>This cat who hung out behind our Berlin flat looked so similar to our cat at home, Ghost, I think it may have given O unrealistic expectations for vacation cats moving forward</figcaption></figure>
<p>As hosts, we loved seeing this family enjoy our immediate neighborhood and explore the city over the course of ten days, and left out plenty of games and sports stuff for their kids.</p>
<p>Not paying for lodging can also unlock new experiences: my parents decided to drop in for part of the trip because we had space for them to stay. Some highlights included a visit to Neuremberg to see the <a href="https://dbmuseum.de/en/highlight-tour">DB Train Museum</a> and the <a href="https://www.playmobil-funpark.de/en/">Playmobil FunPark</a> at Zirndorf, and the <a href="https://www.museumsportal-berlin.de/en/museums/deutsches-technikmuseum/">German Museum of Technology</a> (below) in Berlin.</p>
<figure><img alt="" loading="lazy" width="6000" height="4000" decoding="async" data-nimg="1" style="color:transparent" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Foands.09c884b9.jpg&amp;w=3840&amp;q=75 1x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Foands.09c884b9.jpg&amp;w=3840&amp;q=75"/></figure>
<p>We also got to spend time with Carla&#x27;s friend and former roommate, F, and her lovely family 💕 Many thanks to the J name family and my colleague <a href="https://bsky.app/profile/phry.dev">Lenz</a> for all the recommendations.</p>
<h2 id="thanks-for-the-good-times-apollo"><a class="anchor" href="#thanks-for-the-good-times-apollo"><span class="icon icon-link"></span></a>Thanks for the good times, Apollo</h2>
<p>This past Friday was my last day at <a href="https://apollographql.com">Apollo</a>. I want to thank my colleagues who made the last 2.5 years as special as they were: <a href="https://bsky.app/profile/jeff.auriemma.xyz">Jeff</a>, <a href="https://github.com/hwillson">Hugh</a>, <a href="https://x.com/jerelmiller">Jerel</a>, <a href="https://bsky.app/profile/phry.dev">Lenz</a> and <a href="https://github.com/benjamn">Ben</a> especially, and my wider Clients Team family including <a href="https://bsky.app/profile/mbonnin.net">Martin</a>, <a href="https://mastodon.social/@BoD@mastodon.social">Benoit</a>, <a href="https://x.com/c35tar1">Calvin</a>, <a href="https://x.com/AnthonyMDev">Anthony</a> and <a href="https://github.com/BobaFetters">Zach</a>.</p>
<p>It was nothing short of a dream job: I got to do open source work full-time with some of the brightest, most thoughtful engineers and managers in the business and travel around speaking about what we were building. I gave <a href="/speaking">eight talks</a> in two years (ok, with some recycled material 😅) at some of the biggest React and GraphQL conferences around the globe. My face was in the (in)famous React Conf 2024 grid:</p>
<figure><img alt="" loading="lazy" width="1404" height="811" decoding="async" data-nimg="1" style="color:transparent" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Freactfaces.a44cb3d4.png&amp;w=1920&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Freactfaces.a44cb3d4.png&amp;w=3840&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Freactfaces.a44cb3d4.png&amp;w=3840&amp;q=75"/></figure>
<p>It has been such a pleasure working with everyone at Apollo and the wider open source communities I&#x27;ve spent time with, and I&#x27;ve learned so many things from this experience I&#x27;ll carry forward in my career. The future is incredibly bright for Apollo and the GraphQL community writ large.</p>
<h2 id="tudum"><a class="anchor" href="#tudum"><span class="icon icon-link"></span></a>Tudum</h2>
<p>One last bit of news: today is my first day as a Senior Software Engineer at <a href="https://netflix.com">Netflix</a>! I&#x27;ll be working on the XD Design Engineering team building the Design Platform API with some incredible colleagues, and I couldn&#x27;t be more excited about it.</p>
<h2 id="quarter-century-complete"><a class="anchor" href="#quarter-century-complete"><span class="icon icon-link"></span></a>Quarter century complete</h2>
<figure><img alt="" loading="lazy" width="3024" height="4032" decoding="async" data-nimg="1" style="color:transparent" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fosnow.c7129add.jpg&amp;w=3840&amp;q=75 1x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fosnow.c7129add.jpg&amp;w=3840&amp;q=75"/><figcaption>Taking a stroll through Riverside Park, February 2024</figcaption></figure>
<p>I&#x27;ll end on a note of gratitude and anticipation: there are some <em>very</em> exciting things on the horizon in 2025... We&#x27;re so grateful for the past 12 months we&#x27;ve shared, and for everyone who made them special.</p>
<p>From our family to yours, we hope you have a wonderful holiday season and a happy new year. ♥️</p>]]></content:encoded>
            <author>web@bellisar.io (Alessia Bellisario)</author>
        </item>
        <item>
            <title><![CDATA[2023]]></title>
            <link>https://aless.co/2023</link>
            <guid>https://aless.co/2023</guid>
            <pubDate>Mon, 04 Dec 2023 00:00:00 GMT</pubDate>
            <content:encoded><![CDATA[<blockquote>
<p>Welcome to the fifth edition of my year in review! (See <a href="/2022">2022</a>, <a href="/2021">2021</a>, <a href="/2020">2020</a> and <a href="/2019">2019</a> for previous editions.)</p>
</blockquote>
<p>This year was both intense and utterly wonderful. A bigger walking and talking Baby O turned 2! I had the opportunity to speak at six conferences on two continents. Our family traveled to new places including Newfoundland, Idaho and (new to the little one) London and Paris. We also spent a wonderful weekend with several of O&#x27;s siblings in Buffalo, NY, and are winding down the year with our families in New York and Toronto.</p>
<p>Let&#x27;s get started ▶️</p>
<h2 id="january"><a class="anchor" href="#january"><span class="icon icon-link"></span></a>January</h2>
<p>The most notable thing that happened in January: Baby O said &quot;I love you&quot; for the first time. I&#x27;ve never managed to journal consistently, but whenever a &quot;first&quot; happens, I try to add it as a calendar event in my phone.</p>
<p>A few taps calls up a precious set of memories: the first time he used a spoon by himself; the first time he slept in a big kid bed (he transitioned from a crib at 18 months for height and safety reasons - do <strong>not</strong> recommend if you can help it 🥲); the first time he demanded toys in a toy store (I remember it well...)</p>
<figure><img alt="Baby O and Ghost peering out the window" loading="lazy" width="960" height="1272" decoding="async" data-nimg="1" style="color:transparent" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fbaby4.158530b7.jpg&amp;w=1080&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fbaby4.158530b7.jpg&amp;w=1920&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fbaby4.158530b7.jpg&amp;w=1920&amp;q=75"/></figure>
<h2 id="march-brooklyn-rendezvous"><a class="anchor" href="#march-brooklyn-rendezvous"><span class="icon icon-link"></span></a>March: Brooklyn rendezvous</h2>
<p>My friend Adelaide was engaged to be married in the spring and made the excellent choice of Brooklyn for her bachelorette party.</p>
<p>I put together a list of dinner spots and activities. We ate, we drank, some of us played the tambourine until our legs were bruised. (Shout out to the tambourines at <a href="https://www.insabrooklyn.com/">Insa</a>, the hardest working karaoke accessories in the five boroughs.) Above all, we celebrated the bride to be - congratulations Adelaide and Matt, we love you!</p>
<figure><img alt="A printed list of karaoke don&#x27;ts framed on the wall of Korean BBQ and karaoke spot Insa, in Brooklyn. The last rule reads &#x27;Don&#x27;t
discover the tambourine hidden in your bag when you get home.&#x27;" loading="lazy" width="1504" height="1504" decoding="async" data-nimg="1" style="color:transparent" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fkaraoke.95a13b50.jpg&amp;w=1920&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fkaraoke.95a13b50.jpg&amp;w=3840&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fkaraoke.95a13b50.jpg&amp;w=3840&amp;q=75"/></figure>
<h2 id="june-another-canuck-in-the-house"><a class="anchor" href="#june-another-canuck-in-the-house"><span class="icon icon-link"></span></a>June: another Canuck in the house</h2>
<p>In June, O had his Canadian citizenship legally recognized, coincidentally on my grandfather&#x27;s 95th birthday whose name O bears as a middle name. I was able to file online using a new paperless process - the artifact at the end is a simple PDF.</p>
<p>Our appetite for bureaucratic paperwork not fully sated, we then applied for his NEXUS card. NEXUS is actually <a href="https://www.nerdwallet.com/article/travel/global-entry-vs-nexus#:~:text=The%20main%20difference%20between%20Global,is%20eligible%20for%20the%20programs.">a superset of the Global Entry program</a>, and costs $50 instead of $100. The only downside is you have to do an in person interview at an enrollment center, but if you ever fly through Toronto&#x27;s Pearson airport it&#x27;s pretty quick and <em>so</em> worth it.</p>
<h2 id="july-heading-east"><a class="anchor" href="#july-heading-east"><span class="icon icon-link"></span></a>July: heading East</h2>
<p>I have a bucket list like every good Millennial and Newfoundland has always been on it. I can&#x27;t really explain why. In my early twenties, I dated someone who had lived in and subsequently moved back to Halifax, so I got to know a few Maritimers through my visits.</p>
<p>...if you&#x27;re thinking &quot;but Alessia, Newfoundland isn&#x27;t part of <a href="https://en.wikipedia.org/wiki/The_Maritimes">the Maritimes</a>!&quot; there&#x27;s like a 90% chance you&#x27;re from out east. (Does <em>anyone</em> know this outside the region? I learned it while browsing <a href="https://www.reddit.com/r/StJohnsNL/">/r/StJohnsNL</a> for toddler activities and watching unsuspecting redditors get roasted.)</p>
<p>Now you know this bit of Canadian arcana, too: <em>Atlantic Canada is the Maritimes (Nova Scotia, New Brunswick, PEI) <strong>plus</strong> Newfoundland</em>. That and Newfoundland is both the <a href="https://en.wikipedia.org/wiki/Newfoundland_Time_Zone">only active time zone with a half-hour offset from UTC in the Americas</a> and the home of the <a href="https://en.wikipedia.org/wiki/Extreme_points_of_North_America#:~:text=If%20Greenland%20is%20excluded%2C%20then,stretches%20into%20the%20Eastern%20Hemisphere.">easternmost point in North America</a> (excluding Greenland), <a href="https://en.wikipedia.org/wiki/Cape_Spear">Cape Spear</a>.</p>
<figure><img alt="Carla standing in the Salmon Cove" loading="lazy" width="1616" height="1080" decoding="async" data-nimg="1" style="color:transparent" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fsalmon.b74a6fd9.jpg&amp;w=1920&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fsalmon.b74a6fd9.jpg&amp;w=3840&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fsalmon.b74a6fd9.jpg&amp;w=3840&amp;q=75"/></figure>
<figure><img alt="The craggy rock face of the coast of Newfoundland on an overcast day as seen from a boat on the water" loading="lazy" width="1616" height="1080" decoding="async" data-nimg="1" style="color:transparent" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fnewfoundland1.33f0b79d.jpg&amp;w=1920&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fnewfoundland1.33f0b79d.jpg&amp;w=3840&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fnewfoundland1.33f0b79d.jpg&amp;w=3840&amp;q=75"/></figure>
<figure><img alt="A photo of a cliff on the coast of Newfoundland covered in puffin birds" loading="lazy" width="1616" height="1080" decoding="async" data-nimg="1" style="color:transparent" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fnewfoundland2.eeeb3417.jpg&amp;w=1920&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fnewfoundland2.eeeb3417.jpg&amp;w=3840&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fnewfoundland2.eeeb3417.jpg&amp;w=3840&amp;q=75"/></figure>
<p>The plan was to fly into St. John&#x27;s (via Montreal where we spent a few days first at <a href="https://www.montrealjazzfest.com/en-CA">JazzFest</a>), check out the <a href="https://nlfolk.com/festival/info/">Newfoundland and Labrador folk festival</a> and travel around a bit.</p>
<p>It was the perfect destination to bop around with a toddler: we hiked through beautiful parks and coves, saw all kinds of wildlife including whales (a.k.a. <a href="https://www.youtube.com/watch?v=CDx9zqDpSik">Baby Beluga</a>), met lovely people like Marnie, the owner of children&#x27;s book publisher and store <a href="https://runningthegoat.com/">Running the Goat</a> in Tors Cove which was an amazing find by Carla, had top notch dinners at places like <a href="http://chinched.com/">Chinched</a> and the biggest, most perfectly cooked piece of haddock at <a href="https://www.portagenl.ca/">Portage</a>. I&#x27;d love to visit more remote parts of the province and see <a href="https://parks.canada.ca/pn-np/nl/grosmorne">Gros Morne</a> one day.</p>
<figure><img alt="Baby O nursing in St. John&#x27;s harbor" loading="lazy" width="1344" height="1008" decoding="async" data-nimg="1" style="color:transparent" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fstjohns1.66dd27ef.jpg&amp;w=1920&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fstjohns1.66dd27ef.jpg&amp;w=3840&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fstjohns1.66dd27ef.jpg&amp;w=3840&amp;q=75"/></figure>
<p>Here&#x27;s <a href="https://maps.app.goo.gl/9oTgnhmsn2ixptb57">my google map</a> of mostly places we visited and some we&#x27;d like to next time.</p>
<p>The folk festival was also a good call: O ran up and down the aisles during the sets pretending he didn&#x27;t know us out of fear we&#x27;d cramp his style.</p>
<figure><img alt="" loading="lazy" width="1616" height="1080" decoding="async" data-nimg="1" style="color:transparent" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fbaby1.b6eaf2cc.jpg&amp;w=1920&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fbaby1.b6eaf2cc.jpg&amp;w=3840&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fbaby1.b6eaf2cc.jpg&amp;w=3840&amp;q=75"/><figcaption>Butter Pot Provincial Park</figcaption></figure>
<figure><img alt="Baby O sitting in the sand in Salmon Cove" loading="lazy" width="1616" height="1080" decoding="async" data-nimg="1" style="color:transparent" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fbaby2.b4d55ad0.jpg&amp;w=1920&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fbaby2.b4d55ad0.jpg&amp;w=3840&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fbaby2.b4d55ad0.jpg&amp;w=3840&amp;q=75"/><figcaption>Salmon Cove beach</figcaption></figure>
<figure><img alt="Baby O walking around Qidi Vidi lake" loading="lazy" width="1616" height="1080" decoding="async" data-nimg="1" style="color:transparent" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fbaby3.c7b400a4.jpg&amp;w=1920&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fbaby3.c7b400a4.jpg&amp;w=3840&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fbaby3.c7b400a4.jpg&amp;w=3840&amp;q=75"/><figcaption>Qidi Vidi Lake</figcaption></figure>
<h2 id="august-to-november-conference-szn"><a class="anchor" href="#august-to-november-conference-szn"><span class="icon icon-link"></span></a>August to November: conference szn</h2>
<p>In August the year kicked into overdrive. A string of conferences began with React Rally in Salt Lake City followed by a trip up to Boise to visit the Arnolds&#x27; growing family (we missed the newest member by just a couple of months!).</p>
<p>Then in quick succession: GraphQL Conf in San Francisco, GraphQL Summit in San Diego, React Advanced in London (with trips to Cambridge to visit Laura 🐮 and Paris to visit Martin and Clémentine 🌰), React Summit US back in NYC and RVA.js in Richmond, Virginia. (All of the recordings are up on my <a href="/speaking">speaking page</a> for posterity.)</p>
<img alt="Baby O on a trail on the outskirts of Salt Lake City" loading="lazy" width="1008" height="1344" decoding="async" data-nimg="1" style="color:transparent" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fsaltlakecity.1ed8a896.jpg&amp;w=1080&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fsaltlakecity.1ed8a896.jpg&amp;w=2048&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fsaltlakecity.1ed8a896.jpg&amp;w=2048&amp;q=75"/>
<img alt="Alessia, Carla and a snoozing Baby O at the Louvre" loading="lazy" width="2016" height="1512" decoding="async" data-nimg="1" style="color:transparent" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fparis1.cb98a7cc.jpg&amp;w=2048&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fparis1.cb98a7cc.jpg&amp;w=3840&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fparis1.cb98a7cc.jpg&amp;w=3840&amp;q=75"/>
<p>Our trip to London in October marked O&#x27;s first time in Europe and he was enamored with the various modes of transportation we encountered, including:</p>
<ul>
<li><strong>Subways</strong> of all colours and varieties (in Paris you can open the doors before the train stops moving!)</li>
<li><strong>Double decker buses</strong>: this was a BIG one. O sang “wheels on the bus” on one memorable 45 minute bus journey back to Battersea causing a nearby passenger to not only put on her noise cancelling headphones but also press the cups against her ears until we disembarked.</li>
<li>The high speed <strong>Eurostar</strong> train from London to Paris which reached speeds of 295kmh (~185mph).</li>
<li>A charming-given-how-touristy-it-was <strong>open air bus pretending to be a train</strong> that took us on a sightseeing jaunt from Moulin Rouge to Sacré Coeur and back. This was also where O heard the Can Can from Orpheus in the Underworld for the first time, still a favourite of his.</li>
<li>The <strong>national rail line</strong> in London, which we took almost daily to connect to the subway as the nearest stop to us was Clapham Junction.</li>
</ul>
<p>In addition, we got to meet one of O&#x27;s siblings who lives in London! We were sick at the end of our trip so we didn&#x27;t get to spend as much time together as we were anticipating, but it was still such a delight to meet R and mums. ❤️</p>
<figure><img alt="O in a classic red phone booth in London" loading="lazy" width="1024" height="1365" decoding="async" data-nimg="1" style="color:transparent" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Flondon1.465c166c.jpg&amp;w=1080&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Flondon1.465c166c.jpg&amp;w=2048&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Flondon1.465c166c.jpg&amp;w=2048&amp;q=75"/><figcaption><p>Jet lagged toddler explores London&#x27;s phone booths at midnight</p></figcaption></figure>
<p>It was also <em>so</em> nice to spend time with Lenz and Jerel, two colleagues I work closest with and whom I rarely see in person.</p>
<p>Working at a remote-first distributed company means collaborating with some truly excellent coworkers across a nine hour timezone spread (GMT-8 to GMT+1) at the expense of IRL face time 98%+ of the year. The prep and travel were tiring, but being able to have a pint over some food after our presentations was all the sweeter for it.</p>
<img alt="Lenz, Alessia and Jerel on stage at React Advanced London" loading="lazy" width="1541" height="1156" decoding="async" data-nimg="1" style="color:transparent" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Freactadvanced1.5130337b.jpg&amp;w=1920&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Freactadvanced1.5130337b.jpg&amp;w=3840&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Freactadvanced1.5130337b.jpg&amp;w=3840&amp;q=75"/>
<h2 id="september-a-sibling-visit-in-buffalo-and-starting-preschool"><a class="anchor" href="#september-a-sibling-visit-in-buffalo-and-starting-preschool"><span class="icon icon-link"></span></a>September: a sibling visit in Buffalo and starting preschool</h2>
<p>Amidst the conferences, we made a trip back to Carla&#x27;s ancestral homeland of Buffalo, NY and the next day O started preschool.</p>
<h3 id="buffalo"><a class="anchor" href="#buffalo"><span class="icon icon-link"></span></a>Buffalo</h3>
<p>Having met a number of O&#x27;s siblings and their families on our travels, a few families decided to get together for a weekend, some for the n+1 time and some for the first!</p>
<p>We rented an Airbnb with three big apartments under one roof. There were 9 kids and 12 adults in total (one family with young kids stayed nearby for napping purposes, a very smart move).</p>
<p>It was such a blast. With ages ranging from 3 months to almost 3 years, and three families bravely flying from California (dealing not just with toddlers <em>or</em> jet lag but the force multiplication of the two) we were all on different schedules, but we still managed to spend a lot of time together and make so many memories.</p>
<p>This was the first time that O had, if not conversations, independent interactions with his siblings and even an inside joke or two! Then there was the time I came down the stairs as we were getting ready to leave and O looked like he was hugging one of his brothers. My chest swelled with pride and emotion for a second, that is until I realized he was trying to steal A&#x27;s Timbit... We can&#x27;t wait for next year on the west coast!</p>
<h3 id="preschool"><a class="anchor" href="#preschool"><span class="icon icon-link"></span></a>Preschool</h3>
<p>As a newly minted 2 year old as of August, O&#x27;s personality is on full display: he loves (perhaps not strong enough of a word... <strong>adores to the point of dreaming nightly about</strong>) his toy vehicles, being cozy with Mama and Mommy and, since starting &quot;school&quot;, seeing his friends and teachers every day, all of whom he talks about with great excitement.</p>
<p>And I&#x27;d be remiss if I didn&#x27;t give a special shout out to the cat we pass on our daily walk, Mish Mish:</p>
<img alt="Beloved neighbourhood cat Mish Mish" loading="lazy" width="1024" height="1365" decoding="async" data-nimg="1" style="color:transparent" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fmishmish1.c4a9b1aa.jpg&amp;w=1080&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fmishmish1.c4a9b1aa.jpg&amp;w=2048&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fmishmish1.c4a9b1aa.jpg&amp;w=2048&amp;q=75"/>
<h2 id="an-ode-to-carla"><a class="anchor" href="#an-ode-to-carla"><span class="icon icon-link"></span></a>An ode to Carla</h2>
<p>September marked my first time being away for four consecutive nights since O&#x27;s birth. While I&#x27;m so grateful to have had these opportunities, work travel comes with a cost for the parent holding things down at home.</p>
<p>Carla has always had a busy work life as a lawyer running her own practice. This year was no exception: Carla won a federal appeal before the Second Circuit, was named a <a href="https://digital.superlawyers.com/superlawyers/nysl23/MobilePagedReplica.action?pm=2&amp;folio=36#pg36">Rising Star and Super Lawyer featured in a magazine spread</a> and still manages to pull off a bedtime routine after a long day (no easy feat for those who haven&#x27;t faced down a strong-willed or even just average-willed toddler recently).</p>
<p>Carla: O and I love and appreciate you so much, not for what you do for our family—which is incalculable—but for your goofy, exuberant self and huge heart. We are <strong>so</strong> lucky to have you.</p>
<figure><img alt="Carla carrying Baby O on a trail outside of Boise" loading="lazy" width="1344" height="1008" decoding="async" data-nimg="1" style="color:transparent" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fboise1.421cc85b.jpg&amp;w=1920&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fboise1.421cc85b.jpg&amp;w=3840&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fboise1.421cc85b.jpg&amp;w=3840&amp;q=75"/><figcaption>Walking a trail on Boise&#x27;s city limits</figcaption></figure>
<h2 id="years-end"><a class="anchor" href="#years-end"><span class="icon icon-link"></span></a>Year&#x27;s end</h2>
<p>We&#x27;re rounding out the year with Thanksgiving and holiday celebrations in NYC and a coming visit to Toronto. None of this would have been possible without help from our families, particularly my mother-in-law Mary who helped us on numerous occasions when child care fell through, and the support of our friends. Thank you all for being a part of our lives, and sending our love and best wishes for 2024. 🥂</p>
<figure><img alt="Carla and Baby O by the river Thames at night, a gleaming purple London Eye in the background between them" loading="lazy" width="1008" height="1344" decoding="async" data-nimg="1" style="color:transparent" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Flondon2.20662384.jpg&amp;w=1080&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Flondon2.20662384.jpg&amp;w=2048&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Flondon2.20662384.jpg&amp;w=2048&amp;q=75"/></figure>]]></content:encoded>
            <author>web@bellisar.io (Alessia Bellisario)</author>
        </item>
        <item>
            <title><![CDATA[Introducing Apollo Client’s new @nonreactive directive and useFragment hook]]></title>
            <link>https://aless.co/introducing-apollo-client’s-new-@nonreactive-directive-and-usefragment-hook</link>
            <guid>https://aless.co/introducing-apollo-client’s-new-@nonreactive-directive-and-usefragment-hook</guid>
            <pubDate>Fri, 16 Jun 2023 00:00:00 GMT</pubDate>
            <content:encoded><![CDATA[<p>I wrote a post over on Apollo&#x27;s blog! It&#x27;s about some features in Apollo Client&#x27;s upcoming 3.8 release I&#x27;m excited about (currently in beta, <code>npm i @apollo/client@beta</code>): our new <code>@nonreactive</code> client-only directive and <code>useFragment</code> hook.</p>
<p>If React and GraphQL are your thing, <a href="https://www.apollographql.com/blog/apollo-client/introducing-apollo-clients-nonreactive-directive-and-usefragment-hook/">check it out</a> and let me know what you think!</p>]]></content:encoded>
            <author>web@bellisar.io (Alessia Bellisario)</author>
        </item>
        <item>
            <title><![CDATA[Automating Releases of @apollo/client]]></title>
            <link>https://aless.co/automatic-release-management</link>
            <guid>https://aless.co/automatic-release-management</guid>
            <pubDate>Sat, 04 Feb 2023 00:00:00 GMT</pubDate>
            <content:encoded><![CDATA[<p>This post is about the steps I took to automate <a href="https://github.com/apollographql/apollo-client"><code>@apollo/client</code></a>&#x27;s release process with a tool called <a href="https://github.com/changesets/changesets">Changesets</a>. Hopefully it will save someone else implementing a similar workflow a few minutes in the future :)</p>
<h2 id="changesets"><a class="anchor" href="#changesets"><span class="icon icon-link"></span></a>Changesets</h2>
<p>After comparing several options, <a href="https://github.com/changesets/changesets">Changesets</a> stood out as the library that would allow our team to adapt our existing manual workflow seamlessly.</p>
<p>Some of its features include:</p>
<ol>
<li>changelog entries written in Markdown at the time code is committed so both changelog and release notes can contain formatted code blocks, links, and other rich contextual information related to the change</li>
<li>an API for handling prereleases in long-running integration branches</li>
<li>a simple mechanism for batching changes into releases (changesets <code>.md</code> files themselves)</li>
<li>many other nice to haves, including <a href="https://github.com/changesets/changesets/blob/main/docs/snapshot-releases.md">snapshot releases</a></li>
</ol>
<p>IMO, the prerelease workflow is more interesting to discuss since its API <a href="https://github.com/changesets/changesets/issues/665">may undergo significant changes in v3</a> and it took a bit of experimentation before landing on the current approach, so let&#x27;s take a look at the more straightforward release workflow first.</p>
<h2 id="releases"><a class="anchor" href="#releases"><span class="icon icon-link"></span></a>Releases</h2>
<p>The basic premise of Changesets is that each change to your library (or libraries—it was designed with monorepos in mind) is represented by a markdown file generated via <code>npx changeset</code>.</p>
<p>The CLI prompts you with two questions: whether your change represents a new patch/minor/major version, and for a description of the change. Once this info is entered, the CLI uses it to generate a new file inside of <code>.changeset</code>.</p>
<p>Here&#x27;s an example of a recent Apollo Client changeset, <code>.changeset/gorgeous-buses-laugh.md</code>:</p>
<figure data-rehype-pretty-code-figure=""><pre style="background-color:#22272e;color:#adbac7" tabindex="0" data-language="md" data-theme="github-dark-dimmed"><code data-language="md" data-theme="github-dark-dimmed" style="display:grid"><span data-line=""><span style="color:#ADBAC7">---</span></span>
<span data-line=""><span style="color:#96D0FF">&#x27;@apollo/client&#x27;</span><span style="color:#ADBAC7">: </span><span style="color:#96D0FF">patch</span></span>
<span data-line=""><span style="color:#ADBAC7">---</span></span>
<span data-line=""> </span>
<span data-line=""><span style="color:#ADBAC7">Adds </span><span style="color:#6CB6FF">`TVariables`</span><span style="color:#ADBAC7"> generic to </span><span style="color:#6CB6FF">`GraphQLRequest`</span><span style="color:#ADBAC7"> and </span><span style="color:#6CB6FF">`MockedResponse`</span><span style="color:#ADBAC7"> interfaces.</span></span></code></pre></figure>
<p>In a monorepo, more than one package can be specified in the frontmatter block at the top. Once the PR containing the relevant change + changeset is merged to <code>main</code> the release workflow kicks off.</p>
<p>Here&#x27;s an abridged + commented version of Apollo Client&#x27;s <a href="https://github.com/apollographql/apollo-client/blob/main/.github/workflows/release.yml">release workflow</a>:</p>
<figure data-rehype-pretty-code-figure=""><pre style="background-color:#22272e;color:#adbac7" tabindex="0" data-language="yaml" data-theme="github-dark-dimmed"><code data-language="yaml" data-theme="github-dark-dimmed" style="display:grid"><span data-line=""><span style="color:#8DDB8C">name</span><span style="color:#ADBAC7">: </span><span style="color:#96D0FF">Release</span></span>
<span data-line=""> </span>
<span data-line=""><span style="color:#6CB6FF">on</span><span style="color:#ADBAC7">:</span></span>
<span data-line=""><span style="color:#8DDB8C">  push</span><span style="color:#ADBAC7">:</span></span>
<span data-line=""><span style="color:#8DDB8C">    branches</span><span style="color:#ADBAC7">:</span></span>
<span data-line=""><span style="color:#ADBAC7">      - </span><span style="color:#96D0FF">main</span></span>
<span data-line=""> </span>
<span data-line=""><span style="color:#8DDB8C">jobs</span><span style="color:#ADBAC7">:</span></span>
<span data-line=""><span style="color:#8DDB8C">  release</span><span style="color:#ADBAC7">:</span></span>
<span data-line=""><span style="color:#768390">    # Prevents action from creating a PR on forks</span></span>
<span data-line=""><span style="color:#8DDB8C">    if</span><span style="color:#ADBAC7">: </span><span style="color:#96D0FF">github.repository == &#x27;apollographql/apollo-client&#x27;</span></span>
<span data-line=""> </span>
<span data-line=""><span style="color:#8DDB8C">    runs-on</span><span style="color:#ADBAC7">: </span><span style="color:#96D0FF">ubuntu-latest</span></span>
<span data-line=""><span style="color:#8DDB8C">    steps</span><span style="color:#ADBAC7">:</span></span>
<span data-line=""><span style="color:#ADBAC7">      - </span><span style="color:#8DDB8C">name</span><span style="color:#ADBAC7">: </span><span style="color:#96D0FF">Checkout repo</span></span>
<span data-line=""><span style="color:#8DDB8C">        uses</span><span style="color:#ADBAC7">: </span><span style="color:#96D0FF">actions/checkout@v3</span></span>
<span data-line=""><span style="color:#8DDB8C">        with</span><span style="color:#ADBAC7">:</span></span>
<span data-line=""><span style="color:#768390">          # Fetch entire git history so  Changesets can generate</span></span>
<span data-line=""><span style="color:#768390">          # changelogs with the correct commits</span></span>
<span data-line=""><span style="color:#8DDB8C">          fetch-depth</span><span style="color:#ADBAC7">: </span><span style="color:#6CB6FF">0</span></span>
<span data-line=""> </span>
<span data-line=""><span style="color:#768390">      # You can pass NPM_TOKEN directly to the</span></span>
<span data-line=""><span style="color:#768390">      # changesets action, but if you have an existing .npmrc</span></span>
<span data-line=""><span style="color:#768390">      # checked in, you&#x27;ll need to append the token since .npmrc wins</span></span>
<span data-line=""><span style="color:#ADBAC7">      - </span><span style="color:#8DDB8C">name</span><span style="color:#ADBAC7">: </span><span style="color:#96D0FF">Append NPM token to .npmrc</span></span>
<span data-line=""><span style="color:#768390">      # ...</span></span>
<span data-line=""> </span>
<span data-line=""><span style="color:#ADBAC7">      - </span><span style="color:#8DDB8C">name</span><span style="color:#ADBAC7">: </span><span style="color:#96D0FF">Create release PR or publish to npm + GitHub</span></span>
<span data-line=""><span style="color:#8DDB8C">        id</span><span style="color:#ADBAC7">: </span><span style="color:#96D0FF">changesets</span></span>
<span data-line=""><span style="color:#8DDB8C">        uses</span><span style="color:#ADBAC7">: </span><span style="color:#96D0FF">changesets/action@v1</span></span>
<span data-line=""><span style="color:#8DDB8C">        with</span><span style="color:#ADBAC7">:</span></span>
<span data-line=""><span style="color:#768390">          # changesets increments the version in package.json according</span></span>
<span data-line=""><span style="color:#768390">          # to changesets files it detects and `npm i` updates lockfile</span></span>
<span data-line=""><span style="color:#8DDB8C">          version</span><span style="color:#ADBAC7">: </span><span style="color:#96D0FF">npx changeset-version &amp;&amp; npm i</span></span>
<span data-line=""><span style="color:#768390">          # publish command should build library and call changeset publish</span></span>
<span data-line=""><span style="color:#768390">          # it also accepts several flags including `--tag` to specify npm tag</span></span>
<span data-line=""><span style="color:#8DDB8C">          publish</span><span style="color:#ADBAC7">: </span><span style="color:#96D0FF">npm run build &amp;&amp; npx changeset publish -- --tag next</span></span>
<span data-line=""><span style="color:#8DDB8C">        env</span><span style="color:#ADBAC7">:</span></span>
<span data-line=""><span style="color:#8DDB8C">          GITHUB_TOKEN</span><span style="color:#ADBAC7">: </span><span style="color:#96D0FF">${{ secrets.GITHUB_TOKEN }}</span></span>
<span data-line=""><span style="color:#8DDB8C">          NPM_TOKEN</span><span style="color:#ADBAC7">: </span><span style="color:#96D0FF">${{ secrets.NPM_TOKEN }}</span></span>
<span data-line=""> </span>
<span data-line=""><span style="color:#768390">      # optional: announce the release somewhere</span></span>
<span data-line=""><span style="color:#ADBAC7">      - </span><span style="color:#8DDB8C">name</span><span style="color:#ADBAC7">: </span><span style="color:#96D0FF">Send a Slack notification on publish</span></span>
<span data-line=""><span style="color:#8DDB8C">        if</span><span style="color:#ADBAC7">: </span><span style="color:#96D0FF">steps.changesets.outcome == &#x27;success&#x27; &amp;&amp; steps.changesets.outputs.published == &#x27;true&#x27;</span></span>
<span data-line=""><span style="color:#768390">        # send Slack/Discord/etc. message with</span></span>
<span data-line=""><span style="color:#768390">        # ${{ fromJson(steps.changesets.outputs.publishedPackages)[0].version }}</span></span></code></pre></figure>
<p>The first time this is run after merging a PR, changesets detects the new changeset file and opens a &quot;Versions Packages&quot; PR.</p>
<img alt="A screenshot of a Version Packages PR automatically created by the Changesets Action" loading="lazy" width="933" height="699" decoding="async" data-nimg="1" style="color:transparent" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fversion.1186eee8.jpg&amp;w=1080&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fversion.1186eee8.jpg&amp;w=1920&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fversion.1186eee8.jpg&amp;w=1920&amp;q=75"/>
<p>Every time the release workflow runs on push events to the <code>main</code> branch, any unreleased changeset files are incorportated into the &quot;Version Packages&quot; PR and Changesets is smart enough to increment the package(s) version number(s) to the correct version.</p>
<p>By that I mean: if you have two unreleased changesets, one a <code>minor</code> change and one a <code>patch</code>, that results in a new minor version 🎉 The automated &quot;Version Packages&quot; PR will update <code>CHANGELOG.md</code> listing minor/patch changes in separate sections, increment the version in <code>package.json</code> and lockfile, as well as removing the changeset markdown files for changes in the new release.</p>
<p>Merging this &quot;Version Packages&quot; PR is what will trigger the <code>changesets/action</code> to generate a new release 🥳</p>
<h2 id="prereleases"><a class="anchor" href="#prereleases"><span class="icon icon-link"></span></a>Prereleases</h2>
<p>Prereleases work fairly similarly, but took some experimentation since entering &quot;prerelease mode&quot; generates a <code>pre.json</code> file that Changesets uses to track alpha releases.</p>
<p>Here&#x27;s an example <code>pre.json</code> from Apollo Client&#x27;s current <a href="https://github.com/apollographql/apollo-client/pull/10340"><code>release-3.8</code></a> branch:</p>
<figure data-rehype-pretty-code-figure=""><pre style="background-color:#22272e;color:#adbac7" tabindex="0" data-language="json" data-theme="github-dark-dimmed"><code data-language="json" data-theme="github-dark-dimmed" style="display:grid"><span data-line=""><span style="color:#ADBAC7">{</span></span>
<span data-line=""><span style="color:#8DDB8C">  &quot;mode&quot;</span><span style="color:#ADBAC7">: </span><span style="color:#96D0FF">&quot;pre&quot;</span><span style="color:#ADBAC7">,</span></span>
<span data-line=""><span style="color:#8DDB8C">  &quot;tag&quot;</span><span style="color:#ADBAC7">: </span><span style="color:#96D0FF">&quot;alpha&quot;</span><span style="color:#ADBAC7">,</span></span>
<span data-line=""><span style="color:#8DDB8C">  &quot;initialVersions&quot;</span><span style="color:#ADBAC7">: {</span></span>
<span data-line=""><span style="color:#8DDB8C">    &quot;@apollo/client&quot;</span><span style="color:#ADBAC7">: </span><span style="color:#96D0FF">&quot;3.7.2&quot;</span></span>
<span data-line=""><span style="color:#ADBAC7">  },</span></span>
<span data-line=""><span style="color:#8DDB8C">  &quot;changesets&quot;</span><span style="color:#ADBAC7">: [</span></span>
<span data-line=""><span style="color:#96D0FF">    &quot;early-pens-retire&quot;</span><span style="color:#ADBAC7">,</span></span>
<span data-line=""><span style="color:#96D0FF">    &quot;polite-birds-rescue&quot;</span><span style="color:#ADBAC7">,</span></span>
<span data-line=""><span style="color:#96D0FF">    &quot;rude-mayflies-scream&quot;</span><span style="color:#ADBAC7">,</span></span>
<span data-line=""><span style="color:#96D0FF">    &quot;short-bikes-mate&quot;</span><span style="color:#ADBAC7">,</span></span>
<span data-line=""><span style="color:#96D0FF">    &quot;sixty-trains-sniff&quot;</span><span style="color:#ADBAC7">,</span></span>
<span data-line=""><span style="color:#96D0FF">    &quot;small-timers-shake&quot;</span><span style="color:#ADBAC7">,</span></span>
<span data-line=""><span style="color:#96D0FF">    &quot;wild-mice-nail&quot;</span></span>
<span data-line=""><span style="color:#ADBAC7">  ]</span></span>
<span data-line=""><span style="color:#ADBAC7">}</span></span></code></pre></figure>
<p>In other simpler prerelease workflows I&#x27;ve seen in the wild, <code>pre.json</code> is repeatedly added and removed from the default branch, but that seemed like a nonstarter for Apollo Client with its many forks. I wanted to avoid ever committing <code>pre.json</code> to <code>main</code>.</p>
<p>Instead, Apollo Client:</p>
<ol>
<li>enters pre mode on all <code>release-x</code> branches by default</li>
<li>each new commit with a changeset opens a &quot;Version Packages (alpha)&quot; PR that functions the same as regular releases,</li>
<li><em>but</em> the version is monotonically increased, ie <code>3.8.0-alpha.0</code>, <code>3.8.0-alpha.1</code>, and so on</li>
<li>and only npm releases are generated (not GitHub releases)</li>
</ol>
<p>Apollo Client&#x27;s <a href="https://github.com/apollographql/apollo-client/blob/main/.github/workflows/prerelease.yml"><code>prerelease.yml</code></a> looks like this:</p>
<figure data-rehype-pretty-code-figure=""><pre style="background-color:#22272e;color:#adbac7" tabindex="0" data-language="yaml" data-theme="github-dark-dimmed"><code data-language="yaml" data-theme="github-dark-dimmed" style="display:grid"><span data-line=""><span style="color:#768390"># Are we already in pre mode?</span></span>
<span data-line=""><span style="color:#ADBAC7">- </span><span style="color:#8DDB8C">name</span><span style="color:#ADBAC7">: </span><span style="color:#96D0FF">Check for pre.json file existence</span></span>
<span data-line=""><span style="color:#8DDB8C">  id</span><span style="color:#ADBAC7">: </span><span style="color:#96D0FF">check_files</span></span>
<span data-line=""><span style="color:#8DDB8C">  uses</span><span style="color:#ADBAC7">: </span><span style="color:#96D0FF">andstor/file-existence-action@v2.0.0</span></span>
<span data-line=""><span style="color:#8DDB8C">  with</span><span style="color:#ADBAC7">:</span></span>
<span data-line=""><span style="color:#8DDB8C">    files</span><span style="color:#ADBAC7">: </span><span style="color:#96D0FF">&#x27;.changeset/pre.json&#x27;</span></span>
<span data-line=""> </span>
<span data-line=""><span style="color:#768390"># If .changeset/pre.json does not exist and we did not recently exit</span></span>
<span data-line=""><span style="color:#768390"># prerelease mode, enter prerelease mode with tag alpha</span></span>
<span data-line=""><span style="color:#ADBAC7">- </span><span style="color:#8DDB8C">name</span><span style="color:#ADBAC7">: </span><span style="color:#96D0FF">Enter alpha prerelease mode</span></span>
<span data-line=""><span style="color:#8DDB8C">  if</span><span style="color:#ADBAC7">: </span><span style="color:#96D0FF">steps.check_files.outputs.files_exists == &#x27;false&#x27; &amp;&amp; !contains(github.event.head_commit.message, &#x27;Exit prerelease&#x27;)</span></span>
<span data-line=""><span style="color:#8DDB8C">  run</span><span style="color:#ADBAC7">: </span><span style="color:#96D0FF">npx changeset pre enter alpha</span></span>
<span data-line=""> </span>
<span data-line=""><span style="color:#ADBAC7">- </span><span style="color:#8DDB8C">name</span><span style="color:#ADBAC7">: </span><span style="color:#96D0FF">Create alpha release PR</span></span>
<span data-line=""><span style="color:#8DDB8C">  uses</span><span style="color:#ADBAC7">: </span><span style="color:#96D0FF">changesets/action@v1</span></span>
<span data-line=""><span style="color:#8DDB8C">  with</span><span style="color:#ADBAC7">:</span></span>
<span data-line=""><span style="color:#8DDB8C">    version</span><span style="color:#ADBAC7">: </span><span style="color:#96D0FF">npm run changeset-version</span></span>
<span data-line=""><span style="color:#8DDB8C">  env</span><span style="color:#ADBAC7">:</span></span>
<span data-line=""><span style="color:#8DDB8C">    GITHUB_TOKEN</span><span style="color:#ADBAC7">: </span><span style="color:#96D0FF">${{ secrets.GITHUB_TOKEN }}</span></span>
<span data-line=""> </span>
<span data-line=""><span style="color:#768390"># Read package version from package.json</span></span>
<span data-line=""><span style="color:#768390"># in case we just published a new version</span></span>
<span data-line=""><span style="color:#768390"># and want to pass it to a Discord, etc. bot to announce</span></span>
<span data-line=""><span style="color:#768390"># since `steps.changesets.outputs.publishedPackages` is undefined</span></span>
<span data-line=""><span style="color:#768390"># for prereleases (though we can read the version there</span></span>
<span data-line=""><span style="color:#768390"># for non-pre releases)</span></span>
<span data-line=""><span style="color:#ADBAC7">- </span><span style="color:#8DDB8C">name</span><span style="color:#ADBAC7">: </span><span style="color:#96D0FF">get-npm-version</span></span>
<span data-line=""><span style="color:#8DDB8C">  id</span><span style="color:#ADBAC7">: </span><span style="color:#96D0FF">package-version</span></span>
<span data-line=""><span style="color:#8DDB8C">  uses</span><span style="color:#ADBAC7">: </span><span style="color:#96D0FF">martinbeentjes/npm-get-version-action@main</span></span>
<span data-line=""> </span>
<span data-line=""><span style="color:#ADBAC7">- </span><span style="color:#8DDB8C">name</span><span style="color:#ADBAC7">: </span><span style="color:#96D0FF">Run publish</span></span>
<span data-line=""><span style="color:#8DDB8C">  id</span><span style="color:#ADBAC7">: </span><span style="color:#96D0FF">changesets</span></span>
<span data-line=""><span style="color:#768390">  # Only run publish if we&#x27;re still in pre mode and the last commit was</span></span>
<span data-line=""><span style="color:#768390">  # via an automatically created Version Packages PR</span></span>
<span data-line=""><span style="color:#8DDB8C">  if</span><span style="color:#ADBAC7">: </span><span style="color:#96D0FF">steps.check_files.outputs.files_exists == &#x27;true&#x27; &amp;&amp; startsWith(github.event.head_commit.message, &#x27;Version Packages&#x27;)</span></span>
<span data-line=""><span style="color:#8DDB8C">  run</span><span style="color:#ADBAC7">: </span><span style="color:#96D0FF">npm run changeset-publish</span></span></code></pre></figure>
<p>Exiting pre mode has <a href="https://github.com/apollographql/apollo-client/blob/main/.github/workflows/exit-prerelease.yml#L1:L1">its own workflow</a> that does two things: removes <code>pre.json</code> and reverts the package number in <code>package.json</code> to the last released version in <code>main</code>, and a separate workflow <a href="https://github.com/apollographql/apollo-client/blob/main/.github/workflows/check-prerelease.yml#L1:L1"><code>check-prerelease.yml</code></a> makes sure <code>pre.json</code> will never be accidentally merged to main.</p>
<h2 id="conclusion"><a class="anchor" href="#conclusion"><span class="icon icon-link"></span></a>Conclusion</h2>
<p>Working with Changesets has been a breath of fresh air! It&#x27;s taken a lot of tedious and repetitive tasks out of the release process, and allowed us to focus on the fixes and features on our roadmap. Many thanks to the team that builds and maintains it 🙌</p>]]></content:encoded>
            <author>web@bellisar.io (Alessia Bellisario)</author>
        </item>
        <item>
            <title><![CDATA[2022]]></title>
            <link>https://aless.co/2022</link>
            <guid>https://aless.co/2022</guid>
            <pubDate>Mon, 12 Dec 2022 00:00:00 GMT</pubDate>
            <content:encoded><![CDATA[<blockquote>
<p>Slow comes the hour, its passing speed how great!</p>
</blockquote>
<p>Hello again! I can hardly believe I&#x27;m back at my laptop typing up another Year in Review post! Let&#x27;s go 🏃‍♀️</p>
<h2 id="2022-was-a-year-of"><a class="anchor" href="#2022-was-a-year-of"><span class="icon icon-link"></span></a>2022 was a year of:</h2>
<ul>
<li>two sweet babies born to friends and family (Adriano and Vivian 💛💜)</li>
<li>one lemon-and-soccer-themed 1st birthday for Baby O ⚽️</li>
<li>one 60th birthday celebration ft. pizza, sushi and my amazing mom, Erica</li>
<li>one 60th birthday bash that involved a surprising (or unsurprising, if you know my dad) number of cartwheels: HBD &quot;G Money&quot; aka my uncle Gino</li>
<li>one 70th birthday beach weekend for the books celebrating my father-in-law, John</li>
<li>four beautiful weddings in Boston, Muskoka, Salt Lake City and the Bahamas (Véro &amp; Geoff, Karyn &amp; Cam, James &amp; Germaine and Andrew &amp; Naz 🎉)</li>
</ul>
<p>At the close of 2021, Baby O was just four and a half months old and Carla and I were still getting our sea legs as parents. Through the warm glow of the first few months, we couldn&#x27;t have been happier to be new moms to someone we already sensed was a very happy, goofy and <strong><em>energetic</em></strong> kid.</p>
<h2 id="hello-manhattan"><a class="anchor" href="#hello-manhattan"><span class="icon icon-link"></span></a>Hello, Manhattan</h2>
<p>We started off the year in Brooklyn, but not for long. After 15 and 5 years respectively, Carla and I decided it was time to try out a new borough; midway through January we moved to Manhattan Valley on the Upper West Side. We&#x27;ve loved our first year here: everything we need is within a couple block radius of our apartment, we&#x27;re closer to Carla&#x27;s family and, crucially, our pediatrician&#x27;s office is right downstairs.</p>
<h2 id="by-the-power-vested-in-me-by-the-commonwealth-of-massachusetts"><a class="anchor" href="#by-the-power-vested-in-me-by-the-commonwealth-of-massachusetts"><span class="icon icon-link"></span></a>By the power vested in me by the Commonwealth of Massachusetts</h2>
<p>In February, I officiated the wedding of two of my best friends in Boston, Véronique and Geoff. I was <em>very</em> happily surprised by how simple it was to tick the bureaucratic boxes required to legally perform a wedding in Massachussetts—if you must wed a couple in the U.S., see if they&#x27;ll tie the knot in the Baked Bean state.</p>
<img alt="A scanned photograph from Véro and Geoff&#x27;s wedding ceremony, with me officiating" loading="lazy" width="1644" height="1191" decoding="async" data-nimg="1" style="color:transparent" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fvero.98d59ec8.jpg&amp;w=1920&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fvero.98d59ec8.jpg&amp;w=3840&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fvero.98d59ec8.jpg&amp;w=3840&amp;q=75"/>
<p>Baby O took his first road trip with Carla, my mother-in-law, Mary, and me as we made the four hour drive. I was more nervous than I thought I&#x27;d be (will my retelling of their love story do it justice? is the tone just right?), but the couple made it easy. Their vows were 1 of 1 (x2), as expected, and the wedding speeches delivered by beaming parents landed differently than in the past, each recounting tender stories of awkward adolescences or less than convincing threats of running away from home. It was our first real outing in ages and the whole thing ******* rocked.</p>
<img alt="Carla and Alessia as guests at Véro and Geoff&#x27;s wedding, smiling beside the dance floor and flashing the peace sign" loading="lazy" width="2016" height="1512" decoding="async" data-nimg="1" style="color:transparent" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fmoms.75881053.jpg&amp;w=2048&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fmoms.75881053.jpg&amp;w=3840&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fmoms.75881053.jpg&amp;w=3840&amp;q=75"/>
<h2 id="meeting-the-family"><a class="anchor" href="#meeting-the-family"><span class="icon icon-link"></span></a>Meeting the family</h2>
<p>The spring brought some highs (<a href="https://apollographql.com">new job</a> for A and Carla&#x27;s law firm back in full swing post-maternity leave) and lows (COVID for A), but the summer made up for it. For ten days in June and July, Carla, Baby O and I descended on the Bay Area to visit close friends of mine: Robin is a <a href="https://ucberkeley.academia.edu/RobinBuller">brilliant historian</a> who makes a mean martini and <a href="https://www.robinbceramics.com/">gorgeous pottery and ceramics</a>; Mark, Robin&#x27;s husband, is a skilled gardener who tends cells in his day job genetically engineering sustainable and delicious <a href="https://upsidefoods.com/">lab-grown meat</a>.</p>
<img alt="Carla, Mark and Robin sitting outside in Oakland, California around a table" loading="lazy" width="1344" height="1008" decoding="async" data-nimg="1" style="color:transparent" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2FrobinAndMark.81d64ccb.jpg&amp;w=1920&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2FrobinAndMark.81d64ccb.jpg&amp;w=3840&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2FrobinAndMark.81d64ccb.jpg&amp;w=3840&amp;q=75"/>
<p>But there was another important reason we took our 10 month old on his first cross-country plane ride: to meet some of his siblings for the first time 💖 Carla and I have come to understand the importance of bio kin on Baby O&#x27;s dad&#x27;s side from listening to the perspectives of adult donor conceived people (DCP).</p>
<p>While some use the term &quot;diblings&quot; (portmanteau of &quot;donor siblings&quot;) to describe these sibling relationships, we&#x27;ve realized the term can downplay the connection our son has with the people who share 50% of his DNA. After all, lots of non-DCP kids grow up knowing their biological half siblings, and no one corrects them when they refer to them without qualification.</p>
<img alt="Alessia, Carla and Orlando hiking in the Oakland hills" loading="lazy" width="1004" height="1004" decoding="async" data-nimg="1" style="color:transparent" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Ffamily.95f3ee40.jpg&amp;w=1080&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Ffamily.95f3ee40.jpg&amp;w=2048&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Ffamily.95f3ee40.jpg&amp;w=2048&amp;q=75"/>
<p>Meeting some of his siblings and their families and spending time with them throughout our visit was an incredible experience: the kids are all happy and outgoing, and while they&#x27;re being raised in different households, it was stirring to observe the traits they share even at a young age. When the youngest sibling present began to cry, every parent in the room perked up. It sounded remarkably like each of our kids.</p>
<p>A huge added bonus for Carla and me was getting to know the parents. I&#x27;ve heard the term &quot;cross-mom&quot; used by DCP to refer to your sibling&#x27;s mom, for example. Well, Baby O has lots of cross-moms and non-binary cross-parents! We&#x27;re biased, but it&#x27;s a <em>super</em> cool group of kids and parents, to a person. We&#x27;re grateful for Baby O&#x27;s, and by extension, our family, of all three branches of his family tree.</p>
<h2 id="leo-szn"><a class="anchor" href="#leo-szn"><span class="icon icon-link"></span></a>Leo szn</h2>
<p>August was another highlight: we celebrated Baby O&#x27;s first birthday back in NYC and again in Toronto followed by a weeklong Montreal trip. As a former coworker told me during the coldest February in recorded history soon after I&#x27;d moved there: don&#x27;t worry, the summers are <em>magical</em>. Can confirm.</p>
<img alt="Orlando and Carla taking a walk through Montreal&#x27;s Parc Lahaie and chatting with a man feeding some birds" loading="lazy" width="1344" height="1008" decoding="async" data-nimg="1" style="color:transparent" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fbirds.e8a075bb.jpg&amp;w=1920&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fbirds.e8a075bb.jpg&amp;w=3840&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fbirds.e8a075bb.jpg&amp;w=3840&amp;q=75"/>
<p>Heading into the end of the year, we&#x27;re feeling so fortunate to be able to spend time with loved ones and marvel at how far our little family has come in the last 12 months. Sending you love and warmth this holiday season, reader, wherever you may be. 💌</p>
<p>-Alessia</p>

<img alt="Our cat, Ghost, laying cozily on a couch in a nest of pillows" loading="lazy" width="1008" height="1006" decoding="async" data-nimg="1" style="color:transparent" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fghost.311415b8.jpg&amp;w=1080&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fghost.311415b8.jpg&amp;w=2048&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fghost.311415b8.jpg&amp;w=2048&amp;q=75"/>]]></content:encoded>
            <author>web@bellisar.io (Alessia Bellisario)</author>
        </item>
        <item>
            <title><![CDATA[Joining Apollo GraphQL]]></title>
            <link>https://aless.co/joining-apollo</link>
            <guid>https://aless.co/joining-apollo</guid>
            <pubDate>Tue, 21 Jun 2022 00:00:00 GMT</pubDate>
            <content:encoded><![CDATA[<p>I&#x27;m happy to share that I&#x27;m joining <a href="http://apollographql.com">Apollo GraphQL</a> as a Senior Open Source Engineer working on the Apollo Client team, beginning today 🎉</p>
<img alt="The Apollo GraphQL, GraphQL and React logos interspersed with addition symbols" loading="lazy" width="1000" height="420" decoding="async" data-nimg="1" style="color:transparent" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fapollo-header.933772ed.jpg&amp;w=1080&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fapollo-header.933772ed.jpg&amp;w=2048&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fapollo-header.933772ed.jpg&amp;w=2048&amp;q=75"/>
<p><a href="https://github.com/apollographql/apollo-client"><code>@apollo/client</code></a> is the most widely used GraphQL client library on the web: thousands of engineers building high performance web apps rely on it to cache and manage data fetched from GraphQL APIs.</p>
<p>The team is incredibly talented and kind. This will be my first full-time role working in OSS, and the chance to collaborate with veteran open source leaders like <a href="https://github.com/hwillson">hwillson</a> and <a href="https://github.com/benjamn">benjamn</a> is an opportunity I couldn&#x27;t pass up. I&#x27;m so excited to get started.</p>
<blockquote>
<p>My team is hiring! If this work sounds interesting to you, here&#x27;s a more detailed <a href="https://www.apollographql.com/careers/job/?id=7d052c8f-5034-4bfb-b04a-1e195b28827f&amp;utm_campaign=2022-06-13_senior-software-engineer-open-source&amp;utm_source=linkedin&amp;utm_medium=social">job description</a>. Feel free to get in touch.</p>
</blockquote>]]></content:encoded>
            <author>web@bellisar.io (Alessia Bellisario)</author>
        </item>
        <item>
            <title><![CDATA[2021]]></title>
            <link>https://aless.co/2021</link>
            <guid>https://aless.co/2021</guid>
            <pubDate>Fri, 31 Dec 2021 00:00:00 GMT</pubDate>
            <content:encoded><![CDATA[<p>2021 was a year of seven beautiful babies born to friends and family, including the first addition to the Sandersario family (portmanteau for IRL/URL friends, not legal documents), Baby O, and one outdoor wedding (congrats Monica &amp; Mike!)</p>
<img alt="Photograph of an ultrasound scan" loading="lazy" width="1000" height="1000" decoding="async" data-nimg="1" style="color:transparent" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2FbabyOScan.d2c400c4.jpg&amp;w=1080&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2FbabyOScan.d2c400c4.jpg&amp;w=2048&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2FbabyOScan.d2c400c4.jpg&amp;w=2048&amp;q=75"/>
<p>The year began with much less fanfare than 2020, but with an undercurrent of anticipation for the newest family member already well on their way.</p>
<p>Ghost, our formerly-outdoor-but-now-solidly-indoor cat kept us entertained through the darkest hours of the winter as Carla slept more than usual and I kept myself occupied making <a href="https://www.kingarthurbaking.com/recipes/king-arthurs-detroit-style-pizza-recipe">Detroit-style pizzas from scratch</a>. I turned 30 and my sister-in-law helped me realize my dream of one day owning a pasta maker.</p>
<img alt="Winter 2021: a glutenous haze" loading="lazy" width="1000" height="1334" decoding="async" data-nimg="1" style="color:transparent" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Floaves.b4626914.jpg&amp;w=1080&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Floaves.b4626914.jpg&amp;w=2048&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Floaves.b4626914.jpg&amp;w=2048&amp;q=75"/>
<p>Countless loaves of quarantine bread were baked and consumed, and in March we had the joy of becoming aunts for the first time to Dana &amp; Jon&#x27;s delightful Baby A.</p>
<h2 id="15-minutes-of-canadian-infamy"><a class="anchor" href="#15-minutes-of-canadian-infamy"><span class="icon icon-link"></span></a>15 minutes of Canadian infamy</h2>
<p>In April, after gratefully receiving both vaccine doses, Carla and I decided to pay my family in Toronto a visit. The quarantine hotel requirement for international air travelers was in effect so we thought we&#x27;d walk across the Rainbow Bridge at Niagara Falls instead...</p>
<img alt="Carla and I at Niagara Falls moments before Carla&#x27;s Canadian television debut" loading="lazy" width="1200" height="900" decoding="async" data-nimg="1" style="color:transparent" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2FniagaraFalls.4136a731.jpg&amp;w=1200&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2FniagaraFalls.4136a731.jpg&amp;w=3840&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2FniagaraFalls.4136a731.jpg&amp;w=3840&amp;q=75"/>
<p>Our travel day went almost exactly according to plan save for the CTV reporter who rushed us on the Canadian side. I dodged him, but Carla proudly told him and his camera exactly why we&#x27;d crossed the border on foot. <a href="https://toronto.ctvnews.ca/ontarians-skipping-hotel-quarantine-program-by-walking-across-canada-u-s-border-1.5400275">Her clip made the 6 o&#x27;clock news</a> and we even received a few calls for our arrest via Twitter, this being 2021.</p>
<p>The rest of the spring/summer sped by: a couple of short visits to Rhode Island, Buffalo and Shelter Island, one baby shower in Prospect Park and a NYC Dyke March to remember (Carla was one of the most popular marchers with her crop top and, by then, massively pregnant belly.)</p>
<img alt="A photo of the crowd at the 2021 NYC Dyke March" loading="lazy" width="1200" height="1600" decoding="async" data-nimg="1" style="color:transparent" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2FdykeMarchNYC.17723063.jpg&amp;w=1200&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2FdykeMarchNYC.17723063.jpg&amp;w=3840&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2FdykeMarchNYC.17723063.jpg&amp;w=3840&amp;q=75"/>
<h2 id="here-he-comes"><a class="anchor" href="#here-he-comes"><span class="icon icon-link"></span></a>Here he comes</h2>
<p>We were sitting (emphasis on <em>sitting</em>) on the N train when Carla&#x27;s water broke as we pulled into the 39th Ave. station in Queens, what the labour and delivery nurse later called Baby O&#x27;s &quot;New York baptism.&quot; We hopped off and frantically called Carla&#x27;s doctor who advised us to calmly head home (yeah right), grab our bag and proceed to the hospital.</p>
<p>It was an otherwise quiet Saturday afternoon when we finally arrived at the delivery ward. Veronika, the nurse on shift when we were first admitted, assured us Carla would probably still be waiting for active labour to begin when she came back on shift ~24H later. Baby O had other plans: the next morning at 7:24am he was in our arms.</p>
<img alt="A photo of a newborn&#x27;s foot" loading="lazy" width="1080" height="1616" decoding="async" data-nimg="1" style="color:transparent" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2FbabyFoot.f152a593.jpg&amp;w=1080&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2FbabyFoot.f152a593.jpg&amp;w=3840&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2FbabyFoot.f152a593.jpg&amp;w=3840&amp;q=75"/>
<p>In the middle of the delivery (!) one of the nurses noticed my OCAD sweatpants and exclaimed &quot;Canadians?!&quot; to my utter bewilderment. And in the seconds after Baby O&#x27;s birth, another nurse grabbed my phone and snapped what are now the most precious photos I possess. I&#x27;ve heard other parents describe the bond that is formed with the people who help bring your child into the world, but I couldn&#x27;t stop marveling at the level of care we received. We are forever indebted to the team at NYU Langone.</p>
<h2 id="learning-to-parent-in-a-pandemic"><a class="anchor" href="#learning-to-parent-in-a-pandemic"><span class="icon icon-link"></span></a>Learning to parent in a pandemic</h2>
<p>The late summer/fall was a glorious jumble of diapers, long walks and discovering exactly what hour of the early morning my favorite podcasts drop while savouring my half of the night shift.</p>
<p>Despite the fully vaxxed summer in effect in NYC, having a newborn in many ways felt like being transported to day 0 of lockdown: fewer MTA trips, more walking and park hangs.</p>
<img alt="Baby O visits Bay Ridge" loading="lazy" width="1000" height="1333" decoding="async" data-nimg="1" style="color:transparent" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2FbayRidgeStroll.88abfa1b.jpg&amp;w=1080&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2FbayRidgeStroll.88abfa1b.jpg&amp;w=2048&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2FbayRidgeStroll.88abfa1b.jpg&amp;w=2048&amp;q=75"/>
<p>To end the year, we traveled to Toronto for Christmas and introduced the kid to one of the three branches of his family tree to everyone&#x27;s delight. We cut our trip short due to Omicron, but we&#x27;re so thankful for the time we had.</p>
<img alt="My dad, Santino, holding Baby O, both appearing to be asleep by a Christmas tree (though my dad is just pretending)" loading="lazy" width="1300" height="1733" decoding="async" data-nimg="1" style="color:transparent" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fxmas.0840faa4.jpg&amp;w=1920&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fxmas.0840faa4.jpg&amp;w=3840&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fxmas.0840faa4.jpg&amp;w=3840&amp;q=75"/>
<p>Thanks for reading! Wishing you a very happy holidays and a wonderful 2022 :^)</p>
<p>- Alessia</p>]]></content:encoded>
            <author>web@bellisar.io (Alessia Bellisario)</author>
        </item>
        <item>
            <title><![CDATA[2020]]></title>
            <link>https://aless.co/2020</link>
            <guid>https://aless.co/2020</guid>
            <pubDate>Fri, 11 Dec 2020 00:00:00 GMT</pubDate>
            <content:encoded><![CDATA[<p>2020 was a year of three weddings (including my own, to <a href="https://twitter.com/csandersonlaw">Carla</a> - congrats Dana &amp; Jon and Lauren &amp; Sean!), two funerals, one apartment fire and a global pandemic. It was also the last year of my twenties: looking at pictures from January, it&#x27;s almost hard to recognize the person who began the year waltzing around in my clothing.</p>
<h2 id="january"><a class="anchor" href="#january"><span class="icon icon-link"></span></a>January</h2>
<p>After a trip to <a href="https://www.warehousewinesandspirits.com/">Warehouse Wines &amp; Spirits</a> at 8th and Broadway (for drinkable champagne in vast quantities), Carla and I hosted a NYE party with friends in Brooklyn. The next morning, we exchanged the rings we&#x27;d both been not-so-secretly harboring and got engaged.</p>
<img alt="Mimosas for breakfast" loading="lazy" width="1000" height="1123" decoding="async" data-nimg="1" style="color:transparent" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2FengagementAlessAndCarla.d6d6a8b2.jpg&amp;w=1080&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2FengagementAlessAndCarla.d6d6a8b2.jpg&amp;w=2048&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2FengagementAlessAndCarla.d6d6a8b2.jpg&amp;w=2048&amp;q=75"/>
<p>We were excited to tell our families, but first we had a trip lined up: after reaching a five year work anniversary, I was eligible for a four week sabbatical. On January 16, we headed to JFK en route to Tokyo via Beijing.</p>
<h3 id="beijing"><a class="anchor" href="#beijing"><span class="icon icon-link"></span></a>Beijing</h3>
<p>We were flying via Beijing both ways and had ambitious plans for our two 24hr layovers.</p>
<img alt="Whenever I find an Alice Munro translation I take a picture for my dad, Alice Munro&#x27;s #1 superfan" loading="lazy" width="1616" height="1080" decoding="async" data-nimg="1" style="color:transparent" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fbeijing.2e63c28a.jpg&amp;w=1920&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fbeijing.2e63c28a.jpg&amp;w=3840&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fbeijing.2e63c28a.jpg&amp;w=3840&amp;q=75"/>
<p>We landed the evening of the 17th, obtained our temporary tourist visas and headed to our hotel. Initially, we thought we&#x27;d hop on a bus to the Great Wall, but this was the shorter of our two layovers and the jet lag was already hitting us. We figured we&#x27;d save that day trip for the way home...</p>
<h3 id="tokyo"><a class="anchor" href="#tokyo"><span class="icon icon-link"></span></a>Tokyo</h3>
<img alt="The place in downtown Tokyo where Carla and I were stopped by college students who interviewed us for their YouTube channel" loading="lazy" width="1616" height="1080" decoding="async" data-nimg="1" style="color:transparent" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2FjapanSteps.d4c4cc94.jpg&amp;w=1920&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2FjapanSteps.d4c4cc94.jpg&amp;w=3840&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2FjapanSteps.d4c4cc94.jpg&amp;w=3840&amp;q=75"/>
<p>We arrived in Tokyo on my 29th birthday the following day, tired and vibrating with excitement. Carla&#x27;s cousin Joseph has lived in the city for the last seven years and graciously serves as tour guide/karaoke buddy for family traveling through Japan.</p>
<p>He is now also one of just a handful of people who have witnessed my rendition of <a href="https://www.youtube.com/watch?v=AzaTyxMduH4"><em>Pour que tu m&#x27;aimes encore</em></a> -- I was pleased to find the largest catalog of Celine Dion&#x27;s French music I&#x27;ve seen outside of Québec.</p>
<img alt="Lunch ft. a nod to the best Mexican restaurant in SLC, Red Iguana" loading="lazy" width="1616" height="1080" decoding="async" data-nimg="1" style="color:transparent" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2FjapanLunch.d359ab40.jpg&amp;w=1920&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2FjapanLunch.d359ab40.jpg&amp;w=3840&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2FjapanLunch.d359ab40.jpg&amp;w=3840&amp;q=75"/>
<p>I won&#x27;t attempt to recap our whole trip: we bought Japan Rail passes and got to experience the unmatched convenience + punctuality of the Shinkansen while visiting Kyoto, Hiroshima, Hakone, Niseko, Sapporo and more over the course of two weeks. We met so many friendly people along the way, narrowly making it back via Hawai&#x27;i as the US borders closed to non-citizens who had visited China in the previous two weeks: on our date of re-entry, our initial Beijing layover was 16 days prior.</p>
<img alt="Entering this small restaurant in Kyoto felt like walking into a friend&#x27;s living room, the regulars greeting us with beers" loading="lazy" width="1500" height="1125" decoding="async" data-nimg="1" style="color:transparent" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2FjapanFriends.b3720ef1.jpg&amp;w=1920&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2FjapanFriends.b3720ef1.jpg&amp;w=3840&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2FjapanFriends.b3720ef1.jpg&amp;w=3840&amp;q=75"/>
<p>We didn&#x27;t get to see the Great Wall, but we had two days in Honolulu we weren&#x27;t planning for -- two rather than one due to a time zone mix-up. Best mistake ever!</p>
<img alt="" loading="lazy" width="1080" height="1080" decoding="async" data-nimg="1" style="color:transparent" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fhawaii.bfa64d0f.jpg&amp;w=1080&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fhawaii.bfa64d0f.jpg&amp;w=3840&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fhawaii.bfa64d0f.jpg&amp;w=3840&amp;q=75"/>
<p>In February, I squeezed in a trip to SF, a conference (the first ever WebAssembly Summit!) and managed to visit both family and friends back home in Toronto, celebrating a close friend&#x27;s impending nuptials at her bachelorette in Prince Edward County. 2020 was off to a <em>strong</em> start.</p>
<img alt="Vow to RAYge" loading="lazy" width="1616" height="1080" decoding="async" data-nimg="1" style="color:transparent" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2FprinceEdwardCounty.6cc39ef7.jpg&amp;w=1920&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2FprinceEdwardCounty.6cc39ef7.jpg&amp;w=3840&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2FprinceEdwardCounty.6cc39ef7.jpg&amp;w=3840&amp;q=75"/>
<h2 id="new-job-a-fire-and-a-wedding"><a class="anchor" href="#new-job-a-fire-and-a-wedding"><span class="icon icon-link"></span></a>New job, a fire and a wedding</h2>
<p>The first few terrifying weeks of lockdown in NYC began mid-March, followed by an apartment fire at the end of May which started in our next door neighbour&#x27;s yard and woke us to an apartment filled with thick smoke.</p>
<img alt="Silver lining: we met more of our neighbours than we ever had on the sidewalk at 2am" loading="lazy" width="1000" height="1333" decoding="async" data-nimg="1" style="color:transparent" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2FapartmentFire.0de7d0c9.jpg&amp;w=1080&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2FapartmentFire.0de7d0c9.jpg&amp;w=2048&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2FapartmentFire.0de7d0c9.jpg&amp;w=2048&amp;q=75"/>
<p>Everyone made it out unscathed, thankfully. The fire came just two weeks after I started a new job which added to the stress of being uprooted -- all told we were out of our apartment for four months. I&#x27;m extremely grateful for the support my team gave me in the weeks that followed.</p>
<h3 id="project-cupid"><a class="anchor" href="#project-cupid"><span class="icon icon-link"></span></a>Project Cupid</h3>
<p>By July, with no end to the pandemic in sight, Carla and I decided to use the reservation we&#x27;d made as a hedge with New York State&#x27;s <a href="nyc.gov/Cupid">Project Cupid</a> to obtain a marriage license via Zoom.</p>
<p>Once we&#x27;d gotten the license -- issued by a bureaucrat via DocuSign -- we only needed 1. a minister registered with the city and state to perform Zoom weddings and 2. at least one witness physically located in New York state. We were lucky to find <a href="https://www.revannienyc.com/">Reverend Annie</a> online and called on our friends Nicole and Josh.</p>
<img alt="Not pictured: Ghost popping in and out of the frame like a true poltergeist, eating our bouquet" loading="lazy" width="1920" height="1080" decoding="async" data-nimg="1" style="color:transparent" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fwedding.33f6aca6.jpg&amp;w=1920&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fwedding.33f6aca6.jpg&amp;w=3840&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fwedding.33f6aca6.jpg&amp;w=3840&amp;q=75"/>
<p>We were spread across Queens and Brooklyn, all except Rev. Annie who performed the virtual ceremony from the West Village. The paperwork is filed in the officiant&#x27;s borough, so we were officially married in Manhattan on July 31, 2020. 🎉</p>
<h2 id="fresh-air"><a class="anchor" href="#fresh-air"><span class="icon icon-link"></span></a>Fresh air</h2>
<p>We headed north to the Adirondacks in August where we mostly hiked, swam in lakes, worked and roasted marshmallows.</p>
<img alt="Hiking Cascade Mountain in the &#x27;dacks" loading="lazy" width="1000" height="1333" decoding="async" data-nimg="1" style="color:transparent" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fdacks.689db6ed.jpg&amp;w=1080&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fdacks.689db6ed.jpg&amp;w=2048&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fdacks.689db6ed.jpg&amp;w=2048&amp;q=75"/>
<h2 id="years-end"><a class="anchor" href="#years-end"><span class="icon icon-link"></span></a>Year&#x27;s end</h2>
<p>The end of the year has been a blur, not unlike the rest. We&#x27;re grateful for family and friends with whom we&#x27;ve tried to remain connected, despite great distance and difficulty. Sending warm wishes to you, reader, wherever you are this holiday season.</p>
<p>- Alessia</p>
<img alt="" loading="lazy" width="1000" height="1000" decoding="async" data-nimg="1" style="color:transparent" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2FjapanStreet.da736228.jpg&amp;w=1080&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2FjapanStreet.da736228.jpg&amp;w=2048&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2FjapanStreet.da736228.jpg&amp;w=2048&amp;q=75"/>]]></content:encoded>
            <author>web@bellisar.io (Alessia Bellisario)</author>
        </item>
        <item>
            <title><![CDATA[Typed Web Workers]]></title>
            <link>https://aless.co/typed-web-workers</link>
            <guid>https://aless.co/typed-web-workers</guid>
            <pubDate>Thu, 30 Apr 2020 00:00:00 GMT</pubDate>
            <description><![CDATA[Getting Started with Web Workers in a TS Project]]></description>
            <content:encoded><![CDATA[<p>This post is about something that&#x27;s ultimately pretty simple but still took a bit of fiddling for me to figure out: how to come up with the correct TypeScript type for a Web Worker written in JavaScript. But first, a word on writing technical blog posts.</p>
<p>The best advice I&#x27;ve heard on the topic of coming up with ideas for technical blog posts was from <a href="https://www.writespeakcode.com/">Write/Speak/Code</a> MC <a href="https://twitter.com/techgirl1908">Angie Jones</a> at the 2018 conference.</p>
<blockquote>
<p>Quick plug for Write/Speak/Code: it&#x27;s one of the best conferences I&#x27;ve been to! It&#x27;s a conference for technologists with marginalized genders; if that describes you, I recommend you check it out.</p>
</blockquote>
<p>The genius of the conference is that it mixes professional development talks and panels with hands-on workshops. You hear from experts like Angie, someone who has maintained a popular technical blog for years, get some tips on how to get started and then you <strong>do the thing</strong>: in this case, you start writing a blog post and workshopping it with peers in the room. I can&#x27;t overstate what a great experience it was.</p>
<h3 id="the-blog-post-ideas-hidden-in-your-browser-history"><a class="anchor" href="#the-blog-post-ideas-hidden-in-your-browser-history"><span class="icon icon-link"></span></a>The Blog Post Ideas Hidden in Your Browser History</h3>
<p>To come up with ideas for material, Angie said we only needed to look as far as our browser histories. We&#x27;re all experts in our experiences: that means we don&#x27;t need to wait for an earth-shattering revelation to get writing. We just need to pick the last thing that stumped us and drove us down a Stack Overflow rabbit hole or sent us trawling through piles of closed GitHub issues to find a topic we can shed some light on. (That is, assuming we&#x27;ve already come out on the other side. If not: we&#x27;ve got this, the answer is probably one <em>extremely</em> specific search query away.)</p>
<p>If nothing else, she noted, her blog posts often helped Future Angie who would sometimes find herself facing the same issue years later only to come across a blog post she&#x27;d written!</p>
<p>It is in that spirit--of helping Future Alessia--that I&#x27;m writing this post.</p>
<h2 id="back-to-web-workers"><a class="anchor" href="#back-to-web-workers"><span class="icon icon-link"></span></a>Back to Web Workers</h2>
<p>I found myself reaching for a Web Worker recently. I was building some data vizualizations from raw CSVs, and in building the prototype I had to do a bunch of data wrangling, committing various JavaScript crimes in the process. Long story short, I introduced some significant lag on page load.</p>
<p>The computations I was doing were perfectly suited to happen off of the browser&#x27;s main thread, so as not to interfere with the other graphs I needed to start rendering. Web Workers to the rescue!</p>
<p>I was working on a Gatsby site and a quick search revealed, indeed, <strong>there&#x27;s a loader plugin for that</strong>: <a href="https://github.com/universse/gatsby-plugin-workerize-loader"><code>gatsby-plugin-workerize-loader</code></a>. It doesn&#x27;t do anything too fancy, just adds <code>workerize-loader</code> to your Webpack config and injects the worker scripts in <code>gatsby-ssr.js</code>.</p>
<p>The plugin <a href="https://github.com/universse/gatsby-plugin-workerize-loader#gatsby-plugin-workerize-loader">docs</a> demonstrate how to write a worker file with the expected suffix <code>.worker.js</code> in which you export your async function(s):</p>
<figure data-rehype-pretty-code-figure=""><pre style="background-color:#22272e;color:#adbac7" tabindex="0" data-language="js" data-theme="github-dark-dimmed"><code data-language="js" data-theme="github-dark-dimmed" style="display:grid"><span data-line=""><span style="color:#F47067">export</span><span style="color:#F47067"> async</span><span style="color:#F47067"> function</span><span style="color:#DCBDFB"> generateSeries</span><span style="color:#ADBAC7">(</span><span style="color:#F69D50">data</span><span style="color:#ADBAC7">) {</span></span>
<span data-line=""><span style="color:#F47067">  const</span><span style="color:#6CB6FF"> series</span><span style="color:#F47067"> =</span><span style="color:#ADBAC7"> []</span></span>
<span data-line=""><span style="color:#F47067">  for</span><span style="color:#ADBAC7"> (</span><span style="color:#F47067">const</span><span style="color:#ADBAC7"> [</span><span style="color:#6CB6FF">key</span><span style="color:#ADBAC7">, </span><span style="color:#6CB6FF">value</span><span style="color:#ADBAC7">] </span><span style="color:#F47067">of</span><span style="color:#ADBAC7"> Object.</span><span style="color:#DCBDFB">entries</span><span style="color:#ADBAC7">(data)) {</span></span>
<span data-line=""><span style="color:#768390">    // do expensive calculations</span></span>
<span data-line=""><span style="color:#ADBAC7">  }</span></span>
<span data-line=""><span style="color:#F47067">  return</span><span style="color:#ADBAC7"> series</span></span>
<span data-line=""><span style="color:#ADBAC7">}</span></span></code></pre></figure>
<p>Then, in another file—something the docs refer to as a &quot;source file&quot;—you can import and instantiate the Web Worker. (They only work in the browser, so in a Gatsby project you have to check that the window object is defined.)</p>
<figure data-rehype-pretty-code-figure=""><pre style="background-color:#22272e;color:#adbac7" tabindex="0" data-language="ts" data-theme="github-dark-dimmed"><code data-language="ts" data-theme="github-dark-dimmed" style="display:grid"><span data-line=""><span style="color:#F47067">import</span><span style="color:#ADBAC7"> DataWorker </span><span style="color:#F47067">from</span><span style="color:#96D0FF"> &#x27;./computeData.worker.js&#x27;</span></span>
<span data-line=""><span style="color:#F47067">const</span><span style="color:#6CB6FF"> dataWorker</span><span style="color:#F47067"> =</span><span style="color:#F47067"> typeof</span><span style="color:#ADBAC7"> window </span><span style="color:#F47067">===</span><span style="color:#96D0FF"> &#x27;object&#x27;</span><span style="color:#F47067"> &amp;&amp;</span><span style="color:#F47067"> new</span><span style="color:#DCBDFB"> DataWorker</span><span style="color:#ADBAC7">()</span></span>
<span data-line=""><span style="color:#F47067">export</span><span style="color:#F47067"> default</span><span style="color:#ADBAC7"> dataWorker</span></span></code></pre></figure>
<h3 id="web-workers--ts"><a class="anchor" href="#web-workers--ts"><span class="icon icon-link"></span></a>Web Workers + TS</h3>
<p>In the docs, the example source file that imports the worker and instantiates it is a JavaScript file, but I happened to be working in a TypeScript project, so I gave it the <code>.ts</code> extension.</p>
<p>At this point, I knew I&#x27;d have to add some types for the functions my worker is exporting. After flipping through some docs, I added a sibling declaration file, <code>computeData.worker.d.ts</code>, and declared a class that extends TypeScript&#x27;s built-in <code>Worker</code> interface. It just needs a <code>constructor</code> and the type definitions for the functions I&#x27;m exporting, which return Promises.</p>
<p>Put it all together and you&#x27;ve got:</p>
<figure data-rehype-pretty-code-figure=""><pre style="background-color:#22272e;color:#adbac7" tabindex="0" data-language="ts" data-theme="github-dark-dimmed"><code data-language="ts" data-theme="github-dark-dimmed" style="display:grid"><span data-line=""><span style="color:#F47067">declare</span><span style="color:#F47067"> class</span><span style="color:#F69D50"> ComputeDataWebWorker</span><span style="color:#F47067"> extends</span><span style="color:#6CB6FF"> Worker</span><span style="color:#ADBAC7"> {</span></span>
<span data-line=""><span style="color:#F47067">  constructor</span><span style="color:#ADBAC7">()</span></span>
<span data-line=""> </span>
<span data-line=""><span style="color:#DCBDFB">  generateSeries</span><span style="color:#ADBAC7">(</span><span style="color:#F69D50">data</span><span style="color:#F47067">:</span><span style="color:#ADBAC7"> {</span></span>
<span data-line=""><span style="color:#ADBAC7">    [</span><span style="color:#F69D50">key</span><span style="color:#F47067">:</span><span style="color:#6CB6FF"> string</span><span style="color:#ADBAC7">]</span><span style="color:#F47067">:</span><span style="color:#6CB6FF"> number</span></span>
<span data-line=""><span style="color:#ADBAC7">  })</span><span style="color:#F47067">:</span><span style="color:#F69D50"> Promise</span><span style="color:#ADBAC7">&lt;{ </span><span style="color:#F69D50">name</span><span style="color:#F47067">:</span><span style="color:#F69D50"> AnalysisYears</span><span style="color:#ADBAC7">; </span><span style="color:#F69D50">data</span><span style="color:#F47067">:</span><span style="color:#6CB6FF"> number</span><span style="color:#ADBAC7">[] }[]&gt;</span></span>
<span data-line=""> </span>
<span data-line=""><span style="color:#DCBDFB">  sumDailyTotals</span><span style="color:#ADBAC7">(</span></span>
<span data-line=""><span style="color:#F69D50">    data</span><span style="color:#F47067">:</span><span style="color:#F69D50"> Point</span><span style="color:#ADBAC7">[],</span></span>
<span data-line=""><span style="color:#F69D50">    column</span><span style="color:#F47067">:</span><span style="color:#96D0FF"> &#x27;Demand__MW_&#x27;</span><span style="color:#F47067"> |</span><span style="color:#96D0FF"> &#x27;Net_Generation__MW_&#x27;</span><span style="color:#ADBAC7">,</span></span>
<span data-line=""><span style="color:#ADBAC7">  )</span><span style="color:#F47067">:</span><span style="color:#F69D50"> Promise</span><span style="color:#ADBAC7">&lt;{ [</span><span style="color:#F69D50">key</span><span style="color:#F47067">:</span><span style="color:#6CB6FF"> string</span><span style="color:#ADBAC7">]</span><span style="color:#F47067">:</span><span style="color:#6CB6FF"> number</span><span style="color:#ADBAC7"> }&gt;</span></span>
<span data-line=""><span style="color:#ADBAC7">}</span></span>
<span data-line=""> </span>
<span data-line=""><span style="color:#F47067">export</span><span style="color:#F47067"> default</span><span style="color:#ADBAC7"> ComputeDataWebWorker</span></span></code></pre></figure>
<p>Ta da 🌼 Type-safe Web Workers in your Gatsby app.</p>]]></content:encoded>
            <author>web@bellisar.io (Alessia Bellisario)</author>
        </item>
        <item>
            <title><![CDATA[Building a Gatsby Plugin with Wasm]]></title>
            <link>https://aless.co/gatsby-wasm-plugin</link>
            <guid>https://aless.co/gatsby-wasm-plugin</guid>
            <pubDate>Mon, 06 Jan 2020 00:00:00 GMT</pubDate>
            <description><![CDATA[Rust + Wasm + Node.js = 🦀🕸💚]]></description>
            <content:encoded><![CDATA[<blockquote>
<p><strong>Law of the Instrument</strong>: &quot;I suppose it is tempting, if the only tool you have is a hammer, to treat everything as if it were a nail.&quot; - Abraham Maslow, 1966</p>
</blockquote>
<img alt="Proof of concept: generating my first Open Graph images for Twitter cards with Rust and WebAssembly" loading="lazy" width="2118" height="1596" decoding="async" data-nimg="1" style="color:transparent" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fdemo.97e51024.jpg&amp;w=3840&amp;q=75 1x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fdemo.97e51024.jpg&amp;w=3840&amp;q=75"/>
<h2 id="the-problem"><a class="anchor" href="#the-problem"><span class="icon icon-link"></span></a>The Problem</h2>
<p>Back in August, I was looking to generate some <a href="https://ogp.me/">Open Graph</a> images for blog posts I was publishing to this very Gatsby site (as in the photos that appear when one of my posts is shared in most social apps). The idea is simple: <strong>take each post&#x27;s metadata</strong> and <strong>create images containing some text</strong> (title, author, site name) at build time.</p>
<p>I had some requirements in mind: I wanted to supply a <strong>custom font</strong>, and if that wasn&#x27;t possible, at least use a <strong>monospace font</strong> (for the personal <code>#brand</code>). A custom background image would be a bonus.</p>
<p>I couldn&#x27;t find an existing solution that met these requirements, so I set out to build my own. Some interesting constraints led me to Rust and WebAssembly, though I also admittedly found myself holding a Rust-and-Wasm-shaped hammer after working with both technologies to build an interactive web app at <a href="https://recurse.com">RC</a>.</p>
<h2 id="why-webassembly"><a class="anchor" href="#why-webassembly"><span class="icon icon-link"></span></a>Why WebAssembly?</h2>
<p>The prior art for Open Graph image generator plugins in the Gatsby space consists mainly of <code>gatsby-remark-social-cards</code>. I came across some <a href="https://github.com/sw-yx/swyxdotio/tree/master/screenshot-plugin">other</a> <a href="https://lannonbr.com/blog/2019-11-10-og-images/">approaches</a> that involve writing bespoke code to achieve more complex layouts by rendering some HTML on the server and using Puppeteer to take screenshots, but these felt too heavy-handed for my use case.</p>
<p>After taking a look through the README, <code>gatsby-remark-social-cards</code> fit all my criteria <strong>except for the font</strong> (it only supports DejaVuSansCondensed). This is for a purely practical reason: the main library for image processing in Node.js <em>with zero native dependencies</em> is <a href="https://www.npmjs.com/package/jimp"><code>jimp</code></a>. And <code>jimp</code> only supports <strong>bitmap fonts</strong>.</p>
<h2 id="bitmap-fonts"><a class="anchor" href="#bitmap-fonts"><span class="icon icon-link"></span></a>Bitmap Fonts</h2>
<img alt="" loading="lazy" width="731" height="285" decoding="async" data-nimg="1" style="color:transparent" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fbitmap.2f550db3.jpg&amp;w=750&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fbitmap.2f550db3.jpg&amp;w=1920&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fbitmap.2f550db3.jpg&amp;w=1920&amp;q=75"/>
<p>Bitmap fonts are comprised of a matrix of pixels, so they can&#x27;t be scaled or styled like vector/&quot;scalable&quot; fonts (think TTF/OTF). In practice, this means a standalone font file is needed for every combination of font size, color and weight. Indeed, the plugin I was examining had a <code>/fonts</code> folder containing <strong>twenty different <code>.fnt</code> files</strong> for a single typeface styled twenty different ways 😲</p>
<h3 id="aside-netlify-build-image"><a class="anchor" href="#aside-netlify-build-image"><span class="icon icon-link"></span></a>Aside: Netlify Build Image</h3>
<p>I generate this site with Netlify and its build image includes native dependencies <a href="https://github.com/netlify/build-image/blob/xenial/Dockerfile#L59"><code>graphicsmagick</code></a> and <a href="https://github.com/netlify/build-image/blob/xenial/Dockerfile#L63"><code>imagemagick</code></a>, so I could have used a Node library like <code>gm</code> to render text in the vector font of my choice. I didn&#x27;t want one of my Gatsby plugin&#x27;s dependencies to require native dependencies, however, even if it would work out of the box for me and other Netlify users.</p>
<p>Alas, I was back at square one: <code>jimp</code> + bitmap fonts. The thought of having to download a program to generate a bitmap font file for every text style I wanted to try was deeply unappealing, not to mention the lack of configurability for users of my plugin, the very problem that set me down this path in the first place... There had to be a better way™️ Which brings us back to Rust+WebAssembly.</p>
<h2 id="step-1-write-rust"><a class="anchor" href="#step-1-write-rust"><span class="icon icon-link"></span></a>Step 1: Write Rust</h2>
<p>I&#x27;ve been learning Rust on and off over the past year, and while I&#x27;m familiar with many aspects of the language, though still a relative beginner, I knew exactly nothing about low level text layout when starting this project. I picked a <em>crate</em> (synonymous with &quot;library&quot; or &quot;package&quot; in other languages) that seemed to handle my use case called <a href="https://docs.rs/fonterator/0.6.0/fonterator/"><code>fonterator</code></a>, grabbed the example code from the docs and used <a href="https://github.com/rustwasm/wasm-pack-template">this template</a> to spin up a Rust + Wasm project with <code>wasm-pack</code>.</p>
<p>The <code>fonterator</code> demo uses the crate to render some text in English and Korean and finally calls:</p>
<figure data-rehype-pretty-code-figure=""><pre style="background-color:#22272e;color:#adbac7" tabindex="0" data-language="rust" data-theme="github-dark-dimmed"><code data-language="rust" data-theme="github-dark-dimmed" style="display:grid"><span data-line=""><span style="color:#F69D50">std</span><span style="color:#F47067">::</span><span style="color:#F69D50">fs</span><span style="color:#F47067">::</span><span style="color:#DCBDFB">write</span><span style="color:#ADBAC7">(</span><span style="color:#96D0FF">&quot;out.png&quot;</span><span style="color:#ADBAC7">, out_data)</span><span style="color:#F47067">.</span><span style="color:#DCBDFB">expect</span><span style="color:#ADBAC7">(</span><span style="color:#96D0FF">&quot;Failed to save image&quot;</span><span style="color:#ADBAC7">);</span></span></code></pre></figure>
<p><code>std::fs::write</code> is a function in the Rust standard library that writes to a file, as you&#x27;d expect. It saved <code>out.png</code> to my machine when I compiled and ran the Rust program locally 🎉</p>
<h2 id="rust--wasm"><a class="anchor" href="#rust--wasm"><span class="icon icon-link"></span></a>Rust → Wasm</h2>
<p>The next step was to annotate my Rust function with <code>#[wasm_bindgen]</code>, compile my Rust to WebAssembly and call the function via generated JavaScript interface from my Node script. Nothing else about my code was changing, and if all went well, I&#x27;d still get my <code>out.png</code>!</p>
<p>Not so fast:</p>
<figure data-rehype-pretty-code-figure=""><pre style="background-color:#22272e;color:#adbac7" tabindex="0" data-language="rust" data-theme="github-dark-dimmed"><code data-language="rust" data-theme="github-dark-dimmed" style="display:grid"><span data-line=""><span style="color:#F69D50">Error</span><span style="color:#F47067">:</span><span style="color:#ADBAC7"> operation not supported on wasm yet</span></span></code></pre></figure>
<p>Oops. When compiling Rust for the <code>wasm32-unknown-unknown</code> target, the Rust standard library can only assume the WebAssembly instruction set, and since Wasm provides no means of doing I/O, these stubs are left to return errors in the standard library.</p>
<p>The Rust and WebAssembly book has a helpful section on how to add Wasm support to a general-purpose Rust crate. The first tip: <a href="https://rustwasm.github.io/book/reference/add-wasm-support-to-crate.html#avoid-performing-io-directly">avoid performing I/O directly</a> 😀</p>
<blockquote>
<p>Why is the target called <code>wasm32-unknown-unknown</code>? <code>wasm32</code> means the address space is 32-bits large, the first <code>unknown</code> refers to the system the code is compiling on, and the second refers to the system being targeted: <code>unknown-unknown</code> implies &quot;compile on almost any machine, run on almost any machine.&quot;</p>
</blockquote>
<h2 id="uint8array-all-day"><a class="anchor" href="#uint8array-all-day"><span class="icon icon-link"></span></a>Uint8Array All Day</h2>
<p>Since I can&#x27;t perform I/O from my Rust-generated Wasm, I&#x27;d have to pass in the font as a <code>Uint8Array</code> and return a <code>Uint8Array</code> buffer of rendered text. The Rust API I settled on looks like this:</p>
<figure data-rehype-pretty-code-figure=""><pre style="background-color:#22272e;color:#adbac7" tabindex="0" data-language="rust" data-theme="github-dark-dimmed"><code data-language="rust" data-theme="github-dark-dimmed" style="display:grid"><span data-line=""><span style="color:#ADBAC7">#[wasm_bindgen]</span></span>
<span data-line=""><span style="color:#F47067">pub</span><span style="color:#F47067"> fn</span><span style="color:#DCBDFB"> generate_text</span><span style="color:#ADBAC7">(</span></span>
<span data-line=""><span style="color:#ADBAC7">    title</span><span style="color:#F47067">:</span><span style="color:#F47067"> &amp;</span><span style="color:#F69D50">str</span><span style="color:#ADBAC7">,</span></span>
<span data-line=""><span style="color:#ADBAC7">    author</span><span style="color:#F47067">:</span><span style="color:#F47067"> &amp;</span><span style="color:#F69D50">str</span><span style="color:#ADBAC7">,</span></span>
<span data-line=""><span style="color:#ADBAC7">    title_font_size</span><span style="color:#F47067">:</span><span style="color:#F69D50"> i32</span><span style="color:#ADBAC7">,</span></span>
<span data-line=""><span style="color:#ADBAC7">    subtitle_font_size</span><span style="color:#F47067">:</span><span style="color:#F69D50"> i32</span><span style="color:#ADBAC7">,</span></span>
<span data-line=""><span style="color:#ADBAC7">    rgb</span><span style="color:#F47067">:</span><span style="color:#F69D50"> JsValue</span><span style="color:#ADBAC7">,</span></span>
<span data-line=""><span style="color:#ADBAC7">    font_style</span><span style="color:#F47067">:</span><span style="color:#F47067"> &amp;</span><span style="color:#F69D50">str</span><span style="color:#ADBAC7">,</span></span>
<span data-line=""><span style="color:#ADBAC7">    font_file</span><span style="color:#F47067">:</span><span style="color:#F69D50"> Uint8Array</span><span style="color:#ADBAC7">,</span></span>
<span data-line=""><span style="color:#ADBAC7">) </span><span style="color:#F47067">-&gt;</span><span style="color:#F69D50"> Vec</span><span style="color:#ADBAC7">&lt;</span><span style="color:#F69D50">u8</span><span style="color:#ADBAC7">&gt; {</span></span>
<span data-line=""><span style="color:#768390">  // ...</span></span>
<span data-line=""><span style="color:#ADBAC7">}</span></span></code></pre></figure>
<p><code>generate_text</code> takes the strings to be rendered and some config: font sizes, RGB value for text color passed in as a <code>JsValue</code> converted to a Rust tuple and either a string to set the font style using preselected open source fonts or a TTF font as <code>Uint8Array</code>. It then lays out the text, draws the glyphs to a dynamic image backed by a buffer of RGBA pixels and returns a <code>Vec&lt;u8&gt;</code> buffer of pixel data.</p>
<h3 id="publishing-wasm"><a class="anchor" href="#publishing-wasm"><span class="icon icon-link"></span></a>Publishing Wasm</h3>
<p>Once you&#x27;re done writing your Rust, publishing your Wasm couldn&#x27;t be easier: the CLI <code>wasm-pack</code> generates the Wasm module, all the JS glue, TypeScript types <em>and</em> publishes to the npm registry 🤘 I blinked and had published <a href="https://github.com/alessbell/wasm-twitter-card/"><code>wasm-twitter-card</code></a>.</p>
<h2 id="putting-it-all-together"><a class="anchor" href="#putting-it-all-together"><span class="icon icon-link"></span></a>Putting It All Together</h2>
<p>I could then require my Wasm module and call <code>generate_text</code> like any regular JS function. This is the meat of my Gatsby plugin <a href="https://github.com/alessbell/gatsby-remark-twitter-cards"><code>gatsby-remark-twitter-cards</code></a>: it uses <code>fs.readFileSync</code> to read a TTF font to a buffer passed to our Wasm code.</p>
<figure data-rehype-pretty-code-figure=""><pre style="background-color:#22272e;color:#adbac7" tabindex="0" data-language="js" data-theme="github-dark-dimmed"><code data-language="js" data-theme="github-dark-dimmed" style="display:grid"><span data-line=""><span style="color:#F47067">const</span><span style="color:#6CB6FF"> Jimp</span><span style="color:#F47067"> =</span><span style="color:#DCBDFB"> require</span><span style="color:#ADBAC7">(</span><span style="color:#96D0FF">&#x27;jimp&#x27;</span><span style="color:#ADBAC7">)</span></span>
<span data-line=""><span style="color:#F47067">const</span><span style="color:#6CB6FF"> twitterCard</span><span style="color:#F47067"> =</span><span style="color:#DCBDFB"> require</span><span style="color:#ADBAC7">(</span><span style="color:#96D0FF">&#x27;wasm-twitter-card&#x27;</span><span style="color:#ADBAC7">)</span></span>
<span data-line=""> </span>
<span data-line=""><span style="color:#768390">// utility functions for reading/initializing jimp images</span></span>
<span data-line=""> </span>
<span data-line=""><span style="color:#6CB6FF">module</span><span style="color:#ADBAC7">.</span><span style="color:#6CB6FF">exports</span><span style="color:#F47067"> =</span><span style="color:#ADBAC7"> ({ </span><span style="color:#F69D50">markdownNode</span><span style="color:#ADBAC7"> }, </span><span style="color:#F69D50">config</span><span style="color:#ADBAC7">) </span><span style="color:#F47067">=&gt;</span><span style="color:#ADBAC7"> {</span></span>
<span data-line=""><span style="color:#F47067">  const</span><span style="color:#6CB6FF"> fontToUint8Array</span><span style="color:#F47067"> =</span><span style="color:#ADBAC7"> fs.</span><span style="color:#DCBDFB">readFileSync</span><span style="color:#ADBAC7">(require.</span><span style="color:#DCBDFB">resolve</span><span style="color:#ADBAC7">(config.fontFile))</span></span>
<span data-line=""><span style="color:#F47067">  const</span><span style="color:#6CB6FF"> buffer</span><span style="color:#F47067"> =</span><span style="color:#ADBAC7"> twitterCard.</span><span style="color:#DCBDFB">generate_text</span><span style="color:#ADBAC7">(</span></span>
<span data-line=""><span style="color:#ADBAC7">    post.title,</span></span>
<span data-line=""><span style="color:#768390">    // ...</span></span>
<span data-line=""><span style="color:#ADBAC7">    fontToUint8Array,</span></span>
<span data-line=""><span style="color:#ADBAC7">  )</span></span>
<span data-line=""><span style="color:#F47067">  return</span><span style="color:#6CB6FF"> Promise</span><span style="color:#ADBAC7">.</span><span style="color:#DCBDFB">all</span><span style="color:#ADBAC7">([</span><span style="color:#DCBDFB">generateBackground</span><span style="color:#ADBAC7">(), </span><span style="color:#DCBDFB">writeTextToCard</span><span style="color:#ADBAC7">(buffer)])</span></span>
<span data-line=""><span style="color:#ADBAC7">    .</span><span style="color:#DCBDFB">then</span><span style="color:#ADBAC7">(([</span><span style="color:#F69D50">base</span><span style="color:#ADBAC7">, </span><span style="color:#F69D50">text</span><span style="color:#ADBAC7">]) </span><span style="color:#F47067">=&gt;</span><span style="color:#ADBAC7"> base.</span><span style="color:#DCBDFB">composite</span><span style="color:#ADBAC7">(text, </span><span style="color:#6CB6FF">0</span><span style="color:#ADBAC7">, </span><span style="color:#6CB6FF">0</span><span style="color:#ADBAC7">))</span></span>
<span data-line=""><span style="color:#ADBAC7">    .</span><span style="color:#DCBDFB">then</span><span style="color:#ADBAC7">((</span><span style="color:#F69D50">image</span><span style="color:#ADBAC7">) </span><span style="color:#F47067">=&gt;</span></span>
<span data-line=""><span style="color:#ADBAC7">      image</span></span>
<span data-line=""><span style="color:#ADBAC7">        .</span><span style="color:#DCBDFB">writeAsync</span><span style="color:#ADBAC7">(output)</span></span>
<span data-line=""><span style="color:#ADBAC7">        .</span><span style="color:#DCBDFB">then</span><span style="color:#ADBAC7">(() </span><span style="color:#F47067">=&gt;</span><span style="color:#ADBAC7"> console.</span><span style="color:#DCBDFB">log</span><span style="color:#ADBAC7">(</span><span style="color:#96D0FF">&#x27;Generated Twitter Card: &#x27;</span><span style="color:#ADBAC7">, output))</span></span>
<span data-line=""><span style="color:#ADBAC7">        .</span><span style="color:#DCBDFB">catch</span><span style="color:#ADBAC7">((</span><span style="color:#F69D50">err</span><span style="color:#ADBAC7">) </span><span style="color:#F47067">=&gt;</span><span style="color:#ADBAC7"> err),</span></span>
<span data-line=""><span style="color:#ADBAC7">    )</span></span>
<span data-line=""><span style="color:#ADBAC7">    .</span><span style="color:#DCBDFB">catch</span><span style="color:#ADBAC7">(console.error)</span></span>
<span data-line=""><span style="color:#ADBAC7">}</span></span></code></pre></figure>
<p>I no longer needed to use bitmap fonts, but <code>jimp</code> was the perfect library to stitch everything together. I was amazed at how easy it was: I <strong>initialized a Jimp image for the card background</strong> from the user-provided image (or created one consisting of a solid color), then called my Wasm function and <strong>read the text as a buffer of pixel data into a second Jimp image</strong>. Finally, I&#x27;d <strong>composite the latter over the former</strong>, a one-liner with <code>jimp</code>, save the final image and voilà.</p>
<img alt="The resulting image for this post, using the same typeface and gradient that appear elsewhere on this website 😍" loading="lazy" width="1200" height="630" decoding="async" data-nimg="1" style="color:transparent" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Ftwitter-card.46ca607c.jpg&amp;w=1200&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Ftwitter-card.46ca607c.jpg&amp;w=3840&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Ftwitter-card.46ca607c.jpg&amp;w=3840&amp;q=75"/>
<p>Once I saw the result, I was glad I had ventured down this particular rabbit hole!</p>
<h2 id="missing-glyphs"><a class="anchor" href="#missing-glyphs"><span class="icon icon-link"></span></a>Missing Glyphs</h2>
<p>There were a few bumps along the road, mainly falling into the category of missing or incorrectly rendered glyphs:</p>
<p><img src="./glitches.png" alt=""/></p>
<img alt="The image on the left is supposed to say &#x27;2019&#x27;, while the image on the right is missing glyphs d, q and w" loading="lazy" width="1840" height="1200" decoding="async" data-nimg="1" style="color:transparent" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fglitches.b2587cd0.jpg&amp;w=1920&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fglitches.b2587cd0.jpg&amp;w=3840&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fglitches.b2587cd0.jpg&amp;w=3840&amp;q=75"/>
<p>After some head scratching, I chalked it up to a bug in <code>fonterator</code> and moved to <code>rusttype</code> as my underlying text rendering crate which fixed things (I would also realize I needed something like <code>glyph_brush_layout</code> to handle layout/text wrapping). I still don&#x27;t know exactly what the issue with <code>fonterator</code> was, but I received the following thoughtful comment from the folks at the font editor FontForge via Twitter:</p>
<blockquote>
<p>I would check the directionality of the glyphs in your image. I noticed that &quot;b&quot; and &quot;p&quot; are OK, yet &quot;d&quot; and &quot;q&quot; are not. I think the problem is that splines which should be clockwise are counter, and those which should be counter are clockwise. Try e.g. &quot;Correct Direction&quot;.</p>
</blockquote>
<p>I still lack some context here, but I&#x27;d love to dig in and try to find the fix. If anyone has any ideas, let me know!</p>
<h2 id="conclusion"><a class="anchor" href="#conclusion"><span class="icon icon-link"></span></a>Conclusion</h2>
<p>This was a fun and unexpected introduction to solving a real world problem with emerging tech I remain fascinated by.</p>
<p>A few takeaways:</p>
<ul>
<li>The partially self-imposed constraints made this more fun! A native dependency-free solution was in the cards after all thanks to WebAssembly.</li>
<li>The complexity that underlies rendering 2D text to screens is humbling once you scratch the surface. It&#x27;s too often and too easily taken for granted.</li>
<li>Rust is a vast language that has introduced me to many new concepts, chief among them the ownership model of memory management. There is a dauntingly long list of language features I have yet to master (lifetimes! <a href="https://turbo.fish/">turbofish!</a> 😉), but I don&#x27;t need to master them all to start writing Rust. I can start with the parts I need, and go from there.</li>
</ul>]]></content:encoded>
            <author>web@bellisar.io (Alessia Bellisario)</author>
        </item>
        <item>
            <title><![CDATA[2019]]></title>
            <link>https://aless.co/2019</link>
            <guid>https://aless.co/2019</guid>
            <pubDate>Sun, 01 Dec 2019 00:00:00 GMT</pubDate>
            <content:encoded><![CDATA[<img alt="Taking a hike around the &#x27;Grand Canyon of the Pacific&#x27; in Waimea Canyon State Park, Kaua&#x27;i (Feb &#x27;19)" loading="lazy" width="1616" height="1080" decoding="async" data-nimg="1" style="color:transparent" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2FcarlAless.1133bc9e.jpg&amp;w=1920&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2FcarlAless.1133bc9e.jpg&amp;w=3840&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2FcarlAless.1133bc9e.jpg&amp;w=3840&amp;q=75"/>
<p>2019 was a year of 4 weddings (the fourth and final thanks to an elopement we unwittingly crashed, congrats John &amp; Sara!), 2 gifted wedding eggs (congrats Robin &amp; Mark!), 2 new baby cousins (congrats Jess &amp; Anth and Christina &amp; Zach!), 1 adopted cat and 9 states visited (excluding home state NY that&#x27;s RI, MA, HI, VA, MD, PA, CA, CT and NJ).</p>
<p>A friend <a href="https://www.alxmnn.com/">inspired</a> me to write up a few things that happened this year. If you&#x27;ve found your way here, take a minute and join us for a whip around the last 12 months.</p>
<h2 id="carla-peter-carlos--ghost"><a class="anchor" href="#carla-peter-carlos--ghost"><span class="icon icon-link"></span></a>Carla, Peter Carlos &amp; Ghost</h2>
<p>Since being admitted to the Eastern District&#x27;s CJA (Criminal Justice Act) panel for federal indigent defense in January, <strong>Carla</strong>&#x27;s practice has been growing apace. While running her own law firm and keeping one of the busiest schedules of anyone I know, she nevertheless manages to Citi Bike to midtown most days and care for not one but two small creatures, in addition to me.</p>
<p>Carla continues to earn the title of &quot;Neighbourhood Pied Piper of Adorable Animals&quot;: most everyone knows <strong>Peter Carlos</strong>, the good-natured chicken who walked into Carla&#x27;s life three years ago and never left. 2019 in turn brought us <strong>Ghost</strong>, a young cat with white fur and a little grey cap.</p>
<img alt="Our equal parts sweet and mischievous cat, Ghost." loading="lazy" width="1000" height="1000" decoding="async" data-nimg="1" style="color:transparent" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2FghostCarpet.32519150.jpg&amp;w=1080&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2FghostCarpet.32519150.jpg&amp;w=2048&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2FghostCarpet.32519150.jpg&amp;w=2048&amp;q=75"/>
<p>Our friend <strong>Andrew</strong>, a person with far too much idle time on his hands, lovingly built Ghost <a href="https://twitter.com/alessbell/status/1186300433633075201">a cat ladder up to our second story apartment</a> so Ghost could begin to get acquainted with his new home. The ladder was a hit and, so far, it seems he likes what he&#x27;s found at the top.</p>
<img alt="Carla and Peter Carlos, the most resilient chicken I will ever know, hard at work building Ghost&#x27;s massive outdoor cat ladder" loading="lazy" width="800" height="1067" decoding="async" data-nimg="1" style="color:transparent" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2FcarlAndPete.c2f90784.jpg&amp;w=828&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2FcarlAndPete.c2f90784.jpg&amp;w=1920&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2FcarlAndPete.c2f90784.jpg&amp;w=1920&amp;q=75"/>
<p>Finally, an affable web developer offered to make Carla a new website; in June the new and improved <a href="https://carlasandersonlaw.com">carlasandersonlaw.com</a> came online.</p>
<h2 id="the-bellisarios"><a class="anchor" href="#the-bellisarios"><span class="icon icon-link"></span></a>The Bellisarios</h2>
<p><strong>Erica</strong> and <strong>Santino</strong> were thrilled to have their three kids along for the ride in Rome this July, in addition to the sixty-odd other kids they were legally responsible for.</p>
<img alt="Carla and Erica taking in the sights—and spritzes—at the Spanish Steps (July &#x27;19)" loading="lazy" width="1500" height="1500" decoding="async" data-nimg="1" style="color:transparent" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2FericaCarl.bf2b5d35.jpg&amp;w=1920&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2FericaCarl.bf2b5d35.jpg&amp;w=3840&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2FericaCarl.bf2b5d35.jpg&amp;w=3840&amp;q=75"/>
<p>Younger brother <strong>Luca</strong>, ever the peacemaker and overall agreeable Bellisario, had no trouble making new friends in Italy despite the language barrier.</p>
<p>An older gentleman living near our hotel would see Luca on his way to the subway and wave him over for some help navigating Rome&#x27;s precarious streets. They&#x27;d walk together for several blocks until the man would wave Luca off, having arrived at his destination. In Italy as in life, few words, a smile and many wild gestures can go a long way.</p>
<img alt="Luca helping an older gentleman in a wheelchair get to his destination" loading="lazy" width="1500" height="1500" decoding="async" data-nimg="1" style="color:transparent" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fluca.cc9645a8.jpg&amp;w=1920&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fluca.cc9645a8.jpg&amp;w=3840&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fluca.cc9645a8.jpg&amp;w=3840&amp;q=75"/>
<p>In the spring, Luca graduated with a bachelors degree with high distinction from U of T--no small feat says the woman who did a victory lap and still barely got out alive--and began graduate school in the fall, also at U of T.</p>
<img alt="Alessia holding her cousin&#x27;s son, Giacomo" loading="lazy" width="1500" height="2000" decoding="async" data-nimg="1" style="color:transparent" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fgiac.51d298c6.jpg&amp;w=1920&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fgiac.51d298c6.jpg&amp;w=3840&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fgiac.51d298c6.jpg&amp;w=3840&amp;q=75"/>
<p>On January 21, <strong>Jessica and Anthony</strong> welcomed beautiful baby <strong>Giacomo</strong>. He is implausibly chill for an infant, setting the bar nice and high for Bellisario babies to come. His arrival, complete with mini Lowry jersey, almost certainly spurred the Raptors to their uncharacteristic championship. We thank Giacomo for all he has done in his first eleven months with us.</p>
<p>For my part, I had the amazing opportunity to join the <a href="https://recurse.com">Recurse Center</a> in April for a mini batch, which is to say I spent a week in downtown Brooklyn among likeminded programmers exploring a language called Rust. I compiled my Rust to Wasm in order to do some neat interactive stuff with the DOM. <em>In other words</em>, I <a href="https://happy-faces.glitch.me">drew a bunch of moving circles on a web page</a>.</p>
<img alt="A few of the amazing (and functional!) vintage computers at the Recurse Center (April &#x27;19)" loading="lazy" width="1500" height="1500" decoding="async" data-nimg="1" style="color:transparent" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Frc.96e45f34.jpg&amp;w=1920&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Frc.96e45f34.jpg&amp;w=3840&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Frc.96e45f34.jpg&amp;w=3840&amp;q=75"/>
<p>I learned a few other useful things this year, too, like how to <a href="https://twitter.com/alessbell/status/1122223104451928064">build a &quot;split&quot; keyboard</a>, how to <a href="https://twitter.com/alessbell/status/1155525840882536451">use a robotic arm called EggBot to programmatically draw on small spherical and egg-shaped objects</a> (namely eggs, see: Peter Carlos) and how to make holiday cards using a solution to the <a href="https://en.wikipedia.org/wiki/Travelling_salesman_problem">travelling salesman problem</a>.</p>
<img alt="A pen plotter holiday greeting card that is using a traveling salesman algorithm to create a Christmass tree out of a single line traversing many points" loading="lazy" width="1616" height="1080" decoding="async" data-nimg="1" style="color:transparent" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Ftrees.47b7c7ae.jpg&amp;w=1920&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Ftrees.47b7c7ae.jpg&amp;w=3840&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Ftrees.47b7c7ae.jpg&amp;w=3840&amp;q=75"/>
<p>As the year and decade wind down, I&#x27;m eagerly anticipating all the time with loved ones this season affords... especially when those loved ones include three wise, wonderful grandparents who relentlessly pressure me to move home to Toronto ❤️</p>
<p>Sending love to all my friends and family near and far. See you in 2020!</p>
<p>- Alessia</p>]]></content:encoded>
            <author>web@bellisar.io (Alessia Bellisario)</author>
        </item>
        <item>
            <title><![CDATA[Resume as Code]]></title>
            <link>https://aless.co/resume-as-code</link>
            <guid>https://aless.co/resume-as-code</guid>
            <pubDate>Tue, 08 Oct 2019 00:00:00 GMT</pubDate>
            <description><![CDATA[Building a Resume with LaTeX + GitHub Actions]]></description>
            <content:encoded><![CDATA[<p>I avoid brand new tech until I have an itch to scratch: a small, self-contained problem that seems it might lend itself nicely to $someTool. I&#x27;m usually unsure I&#x27;ll be able to achieve what I have in mind. But <em>maybe...</em></p>
<p>This time, the problem was something that had annoyed me for as long as I&#x27;d been employed: resumes. Not the fact of them, or even writing them, necessarily. Just <strong>managing different versions</strong>.</p>
<p>I was swimming in Dropbox folders with dozens of files saved in various formats; I needed to maintain multiple documents to preserve different iterations, and export PDFs for distribution. Version control was a nightmare.</p>
<h2 id="latex-and-git-to-the-rescue"><a class="anchor" href="#latex-and-git-to-the-rescue"><span class="icon icon-link"></span></a>LaTeX and git to the Rescue</h2>
<p>One day I happened upon <a href="https://github.com/dcousineau">Daniel Cousineau</a>&#x27;s <a href="https://github.com/dcousineau/resume"><code>resume</code></a>. Daniel was using a tool I&#x27;d heard of but never worked with called <a href="https://www.latex-project.org/about/">LaTeX</a> (a system for generating documents, and not a particularly new one), along with GitHub releases to track his resume&#x27;s evolution. It seemed promising.</p>
<p>I set up <a href="https://github.com/alessbell/resume/"><code>alessbell/resume</code></a>, rewrote my resume as <code>resume.tex</code> and, back in June, released <code>v1.0</code> 🎉</p>
<h2 id="wherefore-art-github-actions"><a class="anchor" href="#wherefore-art-github-actions"><span class="icon icon-link"></span></a>Wherefore Art GitHub Actions</h2>
<p>Having a resume managed in GitHub was a <em>very</em> welcome change, but there were still a few manual steps every time I wanted to cut a release:</p>
<ol>
<li><strong>Draft a new release via GitHub UI.</strong> Tag my commit and begin manually creating the release.</li>
<li><strong>Manually compile <code>resume.tex</code> and upload the PDF as a release asset.</strong> GitHub automatically includes the source code in both zip and tarball formats, but I wanted to include a compiled <code>resume.pdf</code>, too. I&#x27;d run <code>pdflatex</code> locally and drag and drop the file, again via GitHub UI.</li>
<li><strong>Update the copy of <code>resume.pdf</code> in Gatsby&#x27;s <code>/static</code> folder.</strong> I&#x27;d take my new PDF and drag and drop it into my local copy of the <a href="https://github.com/alessbell/aless.co/">codebase for this website</a>, since I want <a href="https://aless.co/resume.pdf">aless.co/resume.pdf</a> to always display the latest version. Then I&#x27;d manually commit it and open a PR.</li>
</ol>
<p>Once I&#x27;d isolated the steps that were candidates for automation, I sketched out the ideal workflow: first, automating releases in <code>alessbell/resume</code>, then somehow pinging another repository when a new release was published (?), and finally, the other repository (this blog) would download <code>resume.pdf</code> from the latest release, commit it and open a PR... <em>maybe?</em></p>
<p>I had no idea how feasible this all was, still knowing little to nothing about the GitHub Actions API. But automating even one step would be a win!</p>
<h2 id="spoiler-alert"><a class="anchor" href="#spoiler-alert"><span class="icon icon-link"></span></a>Spoiler Alert</h2>
<p>tl;dr my ideal workflow was possible, so I built it 🐙💜</p>
<p>If you&#x27;d like to browse the code, steps 1 and 2 are achieved by the <a href="https://github.com/alessbell/resume/blob/main/.github/workflows/main.yml">main workflow in <code>alessbell/resume</code></a>. Step 3 is handled by actions in this blog&#x27;s repository, namely <a href="https://github.com/alessbell/aless.co/blob/main/commit-resume/entrypoint.sh"><code>/commit-resume</code></a>. For a walk-through of the code, keep reading 😎</p>
<img alt="A screenshot of the GitHub Pull Requests UI showing the first PR created by my GitHub action: entitled &#x27;Update resume to v1.1&#x27;, this PR automatically updates my aless.co resume PDF with the one it downloaded from the latest automated release in another repository" loading="lazy" width="2386" height="1720" decoding="async" data-nimg="1" style="color:transparent" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fresume-pr.1be21895.jpg&amp;w=3840&amp;q=75 1x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fresume-pr.1be21895.jpg&amp;w=3840&amp;q=75"/>
<h3 id="1-compile-the-pdf-and-automate-releases"><a class="anchor" href="#1-compile-the-pdf-and-automate-releases"><span class="icon icon-link"></span></a>1. Compile the PDF and Automate Releases</h3>
<p>I figured automating the release part would be easy—<em>surely there&#x27;s already an action for that</em>—but I wasn&#x27;t so sure about compiling the LaTeX to PDF for inclusion in the release.</p>
<p>Delightfully, both steps turned out to be trivial to implement. I found off-the-shelf actions for both: <a href="https://github.com/xu-cheng/latex-action"><code>xu-cheng/latex-action</code></a> for compiling my LaTeX to PDF and <a href="https://github.com/softprops/action-gh-release"><code>softprops/action-gh-release</code></a> for creating the GitHub release with the compiled PDF from the previous step attached as an asset.</p>
<p>My first workflow looked like this:</p>
<figure data-rehype-pretty-code-figure=""><pre style="background-color:#22272e;color:#adbac7" tabindex="0" data-language="yaml" data-theme="github-dark-dimmed"><code data-language="yaml" data-theme="github-dark-dimmed" style="display:grid"><span data-line=""><span style="color:#8DDB8C">name</span><span style="color:#ADBAC7">: </span><span style="color:#96D0FF">Publish new release of resume</span></span>
<span data-line=""><span style="color:#6CB6FF">on</span><span style="color:#ADBAC7">:</span></span>
<span data-line=""><span style="color:#8DDB8C">  push</span><span style="color:#ADBAC7">:</span></span>
<span data-line=""><span style="color:#8DDB8C">    tags</span><span style="color:#ADBAC7">:</span></span>
<span data-line=""><span style="color:#ADBAC7">      - </span><span style="color:#96D0FF">&#x27;v*.*&#x27;</span></span>
<span data-line=""><span style="color:#8DDB8C">jobs</span><span style="color:#ADBAC7">:</span></span>
<span data-line=""><span style="color:#8DDB8C">  build</span><span style="color:#ADBAC7">:</span></span>
<span data-line=""><span style="color:#8DDB8C">    runs-on</span><span style="color:#ADBAC7">: </span><span style="color:#96D0FF">ubuntu-latest</span></span>
<span data-line=""><span style="color:#8DDB8C">    steps</span><span style="color:#ADBAC7">:</span></span>
<span data-line=""><span style="color:#ADBAC7">      - </span><span style="color:#8DDB8C">name</span><span style="color:#ADBAC7">: </span><span style="color:#96D0FF">Checkout</span></span>
<span data-line=""><span style="color:#8DDB8C">        uses</span><span style="color:#ADBAC7">: </span><span style="color:#96D0FF">actions/checkout@master</span></span>
<span data-line=""><span style="color:#ADBAC7">      - </span><span style="color:#8DDB8C">name</span><span style="color:#ADBAC7">: </span><span style="color:#96D0FF">Compile LaTeX document</span></span>
<span data-line=""><span style="color:#8DDB8C">        uses</span><span style="color:#ADBAC7">: </span><span style="color:#96D0FF">xu-cheng/latex-action@master</span></span>
<span data-line=""><span style="color:#8DDB8C">        with</span><span style="color:#ADBAC7">:</span></span>
<span data-line=""><span style="color:#8DDB8C">          root_file</span><span style="color:#ADBAC7">: </span><span style="color:#96D0FF">resume.tex</span></span>
<span data-line=""><span style="color:#ADBAC7">      - </span><span style="color:#8DDB8C">name</span><span style="color:#ADBAC7">: </span><span style="color:#96D0FF">Release</span></span>
<span data-line=""><span style="color:#8DDB8C">        uses</span><span style="color:#ADBAC7">: </span><span style="color:#96D0FF">softprops/action-gh-release@v1</span></span>
<span data-line=""><span style="color:#8DDB8C">        with</span><span style="color:#ADBAC7">:</span></span>
<span data-line=""><span style="color:#8DDB8C">          files</span><span style="color:#ADBAC7">: </span><span style="color:#96D0FF">resume.pdf</span></span>
<span data-line=""><span style="color:#8DDB8C">        env</span><span style="color:#ADBAC7">:</span></span>
<span data-line=""><span style="color:#8DDB8C">          GITHUB_TOKEN</span><span style="color:#ADBAC7">: </span><span style="color:#96D0FF">${{ secrets.GITHUB_TOKEN }}</span></span></code></pre></figure>
<p>This workflow runs on any <code>push</code> event targeting tags matching the glob pattern <code>v*.*</code> (<a href="https://help.github.com/en/articles/workflow-syntax-for-github-actions#onpushpull_requestbranchestags">docs</a>). The first step, <a href="https://github.com/actions/checkout"><code>actions/checkout</code></a>, checks out the repository to the current GitHub workspace so that the workflow can access the contents of your repository.</p>
<p>After that, I can pass the next step the name of my file, <code>resume.tex</code>, and the subsequent step can directly access the compiled <code>resume.pdf</code> from the previous one. In order to author a release, I need to pass in a <code>GITHUB_TOKEN</code>; luckily GitHub already makes certain <a href="https://help.github.com/en/articles/virtual-environments-for-github-actions#github_token-secret">environment variables</a> available.</p>
<h3 id="2-ping-another-repository"><a class="anchor" href="#2-ping-another-repository"><span class="icon icon-link"></span></a>2. Ping Another Repository</h3>
<p>In order to keep the version of my resume displayed on this website up-to-date, I&#x27;d need a way to kick off a new workflow each time I published <code>alessbell/resume</code>.</p>
<p>Luckily, such an event exists: <a href="https://developer.github.com/v3/repos/#create-a-repository-dispatch-event"><code>repository_dispatch</code></a> triggers a webhook event &quot;when you want to trigger a GitHub Actions workflow for activity that happens outside of GitHub,&quot; or, in this case, in a different repository&#x27;s action. A simple curl request with the correct auth token, headers and body does the trick.</p>
<p>This is the <a href="https://github.com/alessbell/resume/blob/main/ping-repo/entrypoint.sh">whole bash script</a> from <code>alessbell/resume/ping-repo</code>:</p>
<figure data-rehype-pretty-code-figure=""><pre style="background-color:#22272e;color:#adbac7" tabindex="0" data-language="bash" data-theme="github-dark-dimmed"><code data-language="bash" data-theme="github-dark-dimmed" style="display:grid"><span data-line=""><span style="color:#768390">#!/bin/bash</span></span>
<span data-line=""><span style="color:#DCBDFB">main</span><span style="color:#ADBAC7">() {</span></span>
<span data-line=""><span style="color:#F69D50">  curl</span><span style="color:#6CB6FF"> -XPOST</span><span style="color:#6CB6FF"> -H</span><span style="color:#96D0FF"> &quot;Accept: application/vnd.github.everest-preview+json&quot;</span><span style="color:#F47067"> \</span></span>
<span data-line=""><span style="color:#6CB6FF">  -H</span><span style="color:#96D0FF"> &quot;Content-Type: application/json&quot;</span><span style="color:#F47067"> \</span></span>
<span data-line=""><span style="color:#6CB6FF">  -H</span><span style="color:#96D0FF"> &quot;Authorization: token ${</span><span style="color:#ADBAC7">GITHUB_TOKEN</span><span style="color:#96D0FF">}&quot;</span><span style="color:#F47067"> \</span></span>
<span data-line=""><span style="color:#96D0FF">  &quot;https://api.github.com/repos/${</span><span style="color:#ADBAC7">REPO</span><span style="color:#96D0FF">}/dispatches&quot;</span><span style="color:#F47067"> \</span></span>
<span data-line=""><span style="color:#6CB6FF">  --data</span><span style="color:#96D0FF"> &#x27;{&quot;event_type&quot;: &quot;update_resume&quot;}&#x27;</span></span>
<span data-line=""><span style="color:#ADBAC7">}</span></span>
<span data-line=""> </span>
<span data-line=""><span style="color:#F69D50">main</span></span></code></pre></figure>
<p>There were two small caveats here. <strong>First</strong>, because this POST request is being dispatched for a repository other than the one from the action&#x27;s execution context, I needed a <a href="https://help.github.com/en/articles/creating-a-personal-access-token-for-the-command-line">personal access token</a> with <code>repository</code> scope set as a <a href="https://help.github.com/en/articles/virtual-environments-for-github-actions#creating-and-using-secrets-encrypted-variables">secret on the repository</a>. I stored my secret as <code>PA_TOKEN</code> and passed it in the way I had the others:</p>
<figure data-rehype-pretty-code-figure=""><pre style="background-color:#22272e;color:#adbac7" tabindex="0" data-language="yaml" data-theme="github-dark-dimmed"><code data-language="yaml" data-theme="github-dark-dimmed" style="display:grid"><span data-line=""><span style="color:#ADBAC7">- </span><span style="color:#8DDB8C">name</span><span style="color:#ADBAC7">: </span><span style="color:#96D0FF">Pings repo</span></span>
<span data-line=""><span style="color:#8DDB8C">  uses</span><span style="color:#ADBAC7">: </span><span style="color:#96D0FF">./ping-repo</span></span>
<span data-line=""><span style="color:#8DDB8C">  env</span><span style="color:#ADBAC7">:</span></span>
<span data-line=""><span style="color:#8DDB8C">    GITHUB_TOKEN</span><span style="color:#ADBAC7">: </span><span style="color:#96D0FF">${{ secrets.PA_TOKEN }}</span></span>
<span data-line=""><span style="color:#8DDB8C">    REPO</span><span style="color:#ADBAC7">: </span><span style="color:#96D0FF">alessbell/aless.co</span></span></code></pre></figure>
<p><strong>Second</strong>, certain events, e.g. <code>push</code> will run on any branch unless the scope is narrowed by specifying a certain branch or tag. When I was testing this <code>repository_dispatch</code> event, however, nothing was happening despite having pushed a workflow to a branch in my blog&#x27;s repository listening for this exact dispatch event. It wasn&#x27;t until I pushed the blog&#x27;s workflow config to master that I saw it spring to life, activated by my Postman request to the <code>/dispatches</code> endpoint.</p>
<h3 id="3-download-new-pdf-open-pr"><a class="anchor" href="#3-download-new-pdf-open-pr"><span class="icon icon-link"></span></a>3. Download New PDF, Open PR</h3>
<p>This final step felt like a stretch goal, but it proved to be just enough work for a train ride from Rhode Island to NYC. The first part involves fetching the latest version of <code>alessbell/resume</code>, and GitHub&#x27;s API has a dedicated endpoint for retrieving information about a repository&#x27;s latest release:</p>
<figure data-rehype-pretty-code-figure=""><pre style="background-color:#22272e;color:#adbac7" tabindex="0" data-language="bash" data-theme="github-dark-dimmed"><code data-language="bash" data-theme="github-dark-dimmed" style="display:grid"><span data-line=""><span style="color:#ADBAC7">RELEASES_URL</span><span style="color:#F47067">=</span><span style="color:#96D0FF">https://api.github.com/repos/alessbell/resume/releases/latest</span></span>
<span data-line=""> </span>
<span data-line=""><span style="color:#ADBAC7">RES</span><span style="color:#F47067">=</span><span style="color:#96D0FF">$(</span><span style="color:#F69D50">curl</span><span style="color:#6CB6FF"> -sSL</span><span style="color:#6CB6FF"> -H</span><span style="color:#96D0FF"> &quot;${</span><span style="color:#ADBAC7">AUTH_HEADER</span><span style="color:#96D0FF">}&quot; </span><span style="color:#6CB6FF">-H</span><span style="color:#96D0FF"> &quot;${</span><span style="color:#ADBAC7">HEADER</span><span style="color:#96D0FF">}&quot; </span><span style="color:#6CB6FF">--user</span><span style="color:#96D0FF"> &quot;${</span><span style="color:#ADBAC7">GITHUB_ACTOR</span><span style="color:#96D0FF">}&quot; </span><span style="color:#6CB6FF">-X</span><span style="color:#96D0FF"> GET ${</span><span style="color:#ADBAC7">RELEASES_URL</span><span style="color:#96D0FF">})</span></span>
<span data-line=""><span style="color:#ADBAC7">VERSION</span><span style="color:#F47067">=</span><span style="color:#96D0FF">$(</span><span style="color:#6CB6FF">echo</span><span style="color:#96D0FF"> &quot;${</span><span style="color:#ADBAC7">RES</span><span style="color:#96D0FF">}&quot; </span><span style="color:#F47067">|</span><span style="color:#F69D50"> jq</span><span style="color:#6CB6FF"> --raw-output</span><span style="color:#96D0FF"> &#x27;.tag_name&#x27;)</span></span>
<span data-line=""><span style="color:#ADBAC7">PDF_URL</span><span style="color:#F47067">=</span><span style="color:#96D0FF">&quot;https://github.com/alessbell/resume/releases/download/${</span><span style="color:#ADBAC7">VERSION</span><span style="color:#96D0FF">}/resume.pdf&quot;</span></span>
<span data-line=""> </span>
<span data-line=""><span style="color:#768390"># download resume.pdf and save in /static/resume.pdf</span></span>
<span data-line=""><span style="color:#F69D50">curl</span><span style="color:#6CB6FF"> -L0</span><span style="color:#96D0FF"> &quot;${</span><span style="color:#ADBAC7">PDF_URL</span><span style="color:#96D0FF">}&quot;</span><span style="color:#6CB6FF"> --output</span><span style="color:#96D0FF"> ./static/resume.pdf</span></span></code></pre></figure>
<p>Once I had the file downloaded, I&#x27;d just need to commit it and open a PR. This time, I&#x27;d try to use a pre-existing action with a bit less luck: I wasn&#x27;t able to integrate <a href="https://github.com/marketplace/actions/pull-request-on-branch-push"><code>vsoch/pull-request-action</code></a> directly (I&#x27;ll be the first to say it could have been user error -- when I&#x27;m out of my comfort zone, I need to be able to tinker with the code), but reading its source taught me a lot about how to write a similar action that would work for my case.</p>
<p>I wound up with <a href="https://github.com/alessbell/aless.co/blob/main/commit-resume/entrypoint.sh">~90 lines of bash</a> and successfully used <a href="https://stedolan.github.io/jq/"><code>jq</code></a> to process JSON for the first time. There was plenty of trial and error along the way, but once I plugged it all together, it Just Worked.</p>
<hr/>
<p>Writing bash and yaml isn&#x27;t part of my day job, but it was a lot of fun once I got started; tinkering with GitHub Actions was the perfect excuse to learn something new while scratching an itch.</p>
<p>Is there a workflow you&#x27;re thinking about automating? I&#x27;d be curious to hear about it -- you can ping me on twitter at <a href="https://twitter.com/alessbell">@alessbell</a> or email me at <a href="mailto:web@bellisar.io">web[at]bellisar.io</a>.</p>]]></content:encoded>
            <author>web@bellisar.io (Alessia Bellisario)</author>
        </item>
        <item>
            <title><![CDATA[How to Build a Keyboard, Pt.1]]></title>
            <link>https://aless.co/how-to-build-a-keyboard</link>
            <guid>https://aless.co/how-to-build-a-keyboard</guid>
            <pubDate>Mon, 27 May 2019 00:00:00 GMT</pubDate>
            <description><![CDATA[Learn to Solder]]></description>
            <content:encoded><![CDATA[<p>A few years ago, a friend and coworker came in to work one day with a mechanical keyboard under his arm. If memory serves, it was a standard 87-key layout with Cherry MX blue switches, but all anyone noticed were the keycaps.</p>
<p>I was happily a standard issue MacBook keyboard user at the time (pre-2015 redesign, RIP). I&#x27;d never typed on anything else. Glancing over at his desk as he set it down, I was the first to pose the question I&#x27;d later hear him field a few times a week: <em>...but where are the letters?</em></p>
<p>He had chosen a flashy pattern of multicoloured, and crucially, <em>blank</em> keycaps. Something about them was both endearing and an affront. They said: &quot;I&#x27;m a confident touch typer making a playful aesthetic choice,&quot; and also &quot;if you&#x27;re not in the club, I am the functional equivalent of a gilded tray of marbles.&quot; I was mystified.</p>
<h2 id="wasd"><a class="anchor" href="#wasd"><span class="icon icon-link"></span></a>WASD</h2>
<p>My first mechanical keybord was one I would purchase preassembled: a WASD 87-key &quot;v2&quot; build. It (not coincidentally) also had blank keycaps, though I went with the slightly quieter but still satisfyingly tacticle Cherry MX Brown switches. I was a fast typist, but I found myself hedging: I got my initials in highlighter yellow as a visual anchor 💛</p>
<img alt="My first mechanical keyboard: WASD 87-key with Cherry MX Brown switches and seafoam green, pink, purple, grey and yellow keycaps" loading="lazy" width="2044" height="1457" decoding="async" data-nimg="1" style="color:transparent" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fwasd.a18b4d8a.jpg&amp;w=2048&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fwasd.a18b4d8a.jpg&amp;w=3840&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fwasd.a18b4d8a.jpg&amp;w=3840&amp;q=75"/>
<p>I loved it and used it every day for almost two years. And then I saw the Planck.</p>
<h2 id="planck-olkb"><a class="anchor" href="#planck-olkb"><span class="icon icon-link"></span></a>Planck OLKB</h2>
<p>The Planck looked more like a practical joke than a productivity tool the first time I saw it. Its petite size (40% the size of a typical keyboard) and unusual grid layout (&quot;ortholinear&quot;) give the Planck both a strange and satisfyingly symmetrical look.</p>
<p>It was so fundamentally different from every keyboard I&#x27;d ever seen that at first I was genuinely confused as to whether it was some kind of art project or if people actually used it to get things done. Frustratingly, this question seemed to have an answer so obvious that no one had wasted their time posting it online, until an internet commenter somewhere assured, no, seriously, they use their Planck at work! That was all I needed.</p>
<p>If you&#x27;re still wondering about that maybe-fake-sounding term &quot;ortholinear,&quot; here&#x27;s a bit of history from <a href="https://olkb.com/reference/primer">OLKB</a>:</p>
<blockquote>
<p>Ortholinear is a semi-made-up word that was originally coined (to my knowledge) by TypeMatrix as &quot;ortho-linear&quot; - this term got concatenated, became popular among the keyboard community, and eventually became the banner for a keyboard company!</p>
</blockquote>
<p>The company OLKB (<strong>O</strong>rtho<strong>L</strong>inear<strong>K</strong>ey<strong>B</strong>oards) sells Plancks in ready-to-build kits; for the most part, you can&#x27;t get a Planck preassembled. I got mine on <a href="https://drop.com/buy/planck-mechanical-keyboard">Drop</a> and it arrived in a handful of pieces: a PCB (Printed Circuit Board), a single steel plate with holes where the switches would be mounted, an alumninum case to house the finished product, a humble USB cable and a bag of keycaps.</p>
<h2 id="learn-to-solder"><a class="anchor" href="#learn-to-solder"><span class="icon icon-link"></span></a>Learn to Solder</h2>
<p>I knew I&#x27;d have to solder the switches to the board, something I&#x27;d never done before. (In the past I&#x27;d played around with little hardware projects but was always careful that no soldering was required.) After a bit of research, I picked up:</p>
<ul>
<li>the <a href="https://www.amazon.com/gp/product/B017S00DJ2/ref=ppx_yo_dt_b_asin_title_o07_s00?ie=UTF8&amp;psc=1">&quot;Blink&quot; Learn to Solder Kit</a></li>
<li>a pair of <a href="https://www.amazon.com/gp/product/B00FZPDG1K/ref=ppx_yo_dt_b_asin_title_o06_s00?ie=UTF8&amp;psc=1">micro wire cutters</a></li>
<li>this <a href="https://www.amazon.com/gp/product/B0711LFYJ1/ref=ppx_yo_dt_b_asin_title_o09_s00?ie=UTF8&amp;psc=1">fan</a> to remove solder fumes</li>
<li>a now-discontinued $17 soldering iron kit that came with an iron, some solder, and a carrying case</li>
</ul>
<p>I found the learn to solder kit to be very approachable: it comes with a single small PCB, 3x LEDs, 3x resistors, 3x push button switches and a 3V coin battery and battery holder. I watched a few YouTube videos of people soldering and came across the great <a href="https://learn.adafruit.com/adafruit-guide-excellent-soldering/common-problems">Adafruit Guide to Excellent Soldering</a> before I gave it a shot. In about ten minutes, I had turned a pile of loose parts into a tidy row of buttons hooked up to a battery that could summon light from LEDs. 🤯</p>
<p>My first attempt at soldering was passable! I did have one joint I needed to fiddle with, but more importantly, I was becoming comfortable wielding an iron without having to think about a &quot;real&quot; project.</p>
<p>I was ready to try my luck with the Planck PCB. Something I didn&#x27;t fully appreciate at the time is that it comes with all the components that <em>aren&#x27;t</em> switches <strong>already soldered</strong>: resistors, diodes and a microcontroller. And like most boards compatible with Cherry MX-style switches, the Planck&#x27;s switches are <strong>plate mounted</strong>, meaning the switch first snaps onto a metal or plastic plate to position it securely before its pins are soldered to the PCB below.</p>
<img alt="Planck build in progress, with switches mounted to the plate and soldered to the PCB. As this was my first build, I didn&#x27;t take nearly close enough shots to capture the details, but in this case it&#x27;s for the best :)" loading="lazy" width="1179" height="785" decoding="async" data-nimg="1" style="color:transparent" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Folkb-pins.5a828530.jpg&amp;w=1200&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Folkb-pins.5a828530.jpg&amp;w=3840&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Folkb-pins.5a828530.jpg&amp;w=3840&amp;q=75"/>
<h2 id="grid-or-mit"><a class="anchor" href="#grid-or-mit"><span class="icon icon-link"></span></a>Grid or MIT?</h2>
<p>There are two main layouts for the Planck: <strong>grid</strong>, consisting of 48 keys (4x12), and <strong>MIT</strong>, consisting of 47 keys (a similar grid, except a single switch is used for the spacebar in the bottom row with an optional stabilizer bar). As I&#x27;d read online, the best strategy for soldering plate mounted switches is to pop in the four corner switches, solder those, and then proceed to solder the rest of the board.</p>
<p>I went with the MIT layout, so I had 47 x 2 pins per switch = <strong>94 pins to solder</strong> (!). This sounded like a lot, but once I got into a flow state (pun regrettably intended), I blinked and was suddenly done.</p>
<img alt="Planck keyboard, Cherry MX blue switches soldered and the top plate sitting in the case. No keycaps yet" loading="lazy" width="2949" height="1966" decoding="async" data-nimg="1" style="color:transparent" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Folkb-switches.d6d4b253.jpg&amp;w=3840&amp;q=75 1x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Folkb-switches.d6d4b253.jpg&amp;w=3840&amp;q=75"/>
<p>All that was left was the task of re-learning how to type! I underestimated how steep the learning curve would be: the default layout is intuitive once you&#x27;re used to it, but to compensate for the fact of so few <em>physical</em> keys, the Planck has three layers of &quot;keys&quot; in software embedded on the board, also known as <strong>firmware</strong>. There are &quot;raise&quot; and &quot;lower&quot; keys on either side of the spacebar that allow you to access these layers, mostly consisting of special characters and numbers, via key combinations.</p>
<p>I also came across several mentions of <strong>flashing</strong> the board, or loading new firmware instructions (&quot;flashing&quot; for &quot;flash memory&quot;), but I was able to bypass what is usually the final step of a keyboard build in this case as the Planck comes pre-flashed with a <a href="https://qmk.fm/keyboards/planck/">well-designed standard layout</a>.</p>
<img alt="My second keyboard, a Planck OLKB, with beige XDA PBT blank keycaps which have a uniform profile" loading="lazy" width="2160" height="1440" decoding="async" data-nimg="1" style="color:transparent" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Folkb-rainbow-caps.50804e1e.jpg&amp;w=3840&amp;q=75 1x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Folkb-rainbow-caps.50804e1e.jpg&amp;w=3840&amp;q=75"/>
<p>After around a year and a half of daily use, I can confirm Plancks are great everyday keyboards. I&#x27;m able to switch between staggered and ortholinear layouts with brief periods of slower than normal typing speeds, and since only switch soldering is required, Plancks are also a great introductory soldering project.</p>
<p>After I finished the Planck, my iron began collecting dust... until I discovered <em>split</em> boards. In my next post, I&#x27;ll describe a slightly more involved build: a Levinson split ortholinear board with, as you might expect, two separate PCBs. To be continued!</p>]]></content:encoded>
            <author>web@bellisar.io (Alessia Bellisario)</author>
        </item>
        <item>
            <title><![CDATA[Working at the Edge]]></title>
            <link>https://aless.co/working-at-the-edge</link>
            <guid>https://aless.co/working-at-the-edge</guid>
            <pubDate>Mon, 18 Feb 2019 00:00:00 GMT</pubDate>
            <description><![CDATA[Rust and Other Things]]></description>
            <content:encoded><![CDATA[<p>At the beginning of January, I found out that I&#x27;ll be attending the Recurse Center in April for a one week &quot;mini&quot; batch. I can&#x27;t remember exactly when I first heard about RC, but it was years ago and I&#x27;m convinced it was through Julia Evans&#x27; <a href="https://jvns.ca/">excellent blog</a>.</p>
<p>RC is often referred to as a &quot;writer&#x27;s workshop for programmers.&quot; In practice, it&#x27;s a place where programmers go to explore, create and, above all else, learn. There are very few rules (aside from RC&#x27;s <a href="https://www.recurse.com/social-rules">social rules</a>), but one one of my favourite unofficial rules comes from Mary Rose Cook&#x27;s <a href="https://maryrosecook.com/blog/post/recurse-center-testimonial">testimonial</a>:</p>
<blockquote>
<p>There is one constraint: work at the edge of your programming capabilities. Which is to say: work on something that makes you a better programmer.</p>
</blockquote>
<p>Sounds simple enough! And, actually, RC asks you point blank about what you plan to work on during the application process, so you&#x27;d think I&#x27;d have it all figured out by now...</p>
<hr/>
<p>As someone who feels most at home wielding browser technologies, I initially pitched an <a href="https://explorabl.es/">&quot;explorable explanations&quot;</a> project through which I&#x27;d examine low level DOM APIs. Truthfully, I needed to meet a self-imposed deadline, and the &quot;what you&#x27;ll work on&quot; question was the hardest by a factor of 10. Done is better than perfect, etc.</p>
<p>After I got my acceptance email, I started thinking about what I could really use my RC time for. While all of this was rattling around in my head, I came across an <a href="https://twitter.com/kosamari/status/1088191984718761984">impromptu meetup</a> on Twitter: it was around the corner from my office, and the short lineup included Henry Zhu, Paul Irish and Ashley Williams (!!).</p>
<p>Ashley gave a talk on <code>wasm-bindgen</code> (<a href="https://bit.ly/hello-wasm-bindgen">slides</a>) that really resonated with me: she described Rust as the systems programming language for people without a background in systems programming, and mentioned this deep dive <a href="https://hacks.mozilla.org/2018/01/oxidizing-source-maps-with-rust-and-webassembly/">post</a> on oxidizing the <code>source-map</code> JavaScript library (&quot;oxidizing&quot; being the term of art for rewriting some code in Rust... Rustaceans love their wordplay).</p>
<p>While I&#x27;d heard of Wasm (not web <em>or</em> Assembly!) and Rust, I was missing the larger picture of how they might be leveraged together: rewriting hotpaths from unidiomatic, performance-tuned JS to idiomatic Rust, with <code>wasm-bindgen</code> providing the bindgings for the bridge. Suddenly it was all making much more sense, and just in time for RC :)</p>
<p>I started reading <a href="https://doc.rust-lang.org/stable/book/">The Rust Book</a> on a recent vacation, and it&#x27;s one of the best and most accessible technical books I&#x27;ve come across. I&#x27;m half way through, and while I&#x27;m new to the language, having a JS background makes the possibilities of Rust + Wasm all the more exciting.</p>
<p>In case I was doubting my inclination toward Rust, one of the other soft rules of RC is to <strong>embrace serendipity</strong>: avoid tunnel vision, and pursue what might otherwise be a passing curiosity. So Rust it is.</p>
<p>Over the next few weeks I&#x27;ll be posting some of the programs I&#x27;m writing, as well as my evolving plans for my project. If any of this is of particular interest, you can drop me a line via email or twitter.</p>]]></content:encoded>
            <author>web@bellisar.io (Alessia Bellisario)</author>
        </item>
        <item>
            <title><![CDATA[Teach a Girl to Program]]></title>
            <link>https://aless.co/teach-a-girl-to-program</link>
            <guid>https://aless.co/teach-a-girl-to-program</guid>
            <pubDate>Tue, 28 Jun 2016 00:00:00 GMT</pubDate>
            <description><![CDATA[And a Programmer to Teach]]></description>
            <content:encoded><![CDATA[<p>It started with a Slack message. A colleague of mine, Christine, had heard about an organization called <a href="https://technovationchallenge.org/">Technovation</a>. Based in San Francisco and with 10 to 18-year-old participants in dozens of countries, Technovation is a competition in which young women build a startup and a mobile app over the course of several months with the guidance of female technologists. This year, the Montreal organizers were seeking companies in the local startup community to mentor teams. Would we be willing to take on a team at Breather?</p>
<img alt="" loading="lazy" width="1198" height="738" decoding="async" data-nimg="1" style="color:transparent" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fslack.989fcdd6.jpg&amp;w=1200&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fslack.989fcdd6.jpg&amp;w=3840&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fslack.989fcdd6.jpg&amp;w=3840&amp;q=75"/>
<p>True to startup form, we arrived at a decision quickly. I pinged Christine to let her know I’d love to help: I had mentored at a few <a href="https://www.canadalearningcode.ca/">Canada Learning Code</a> workshops and was excited at the prospect of coaching a team of young women. Ever the daughter of a high school teacher and a programmer by day, I thought it would be challenging but fun in the way a really good Sudoku puzzle is.</p>
<h2 id="kickoff-day-0"><a class="anchor" href="#kickoff-day-0"><span class="icon icon-link"></span></a>Kickoff: Day 0</h2>
<p>On October 24 and 25, 2015, a few dozen young women gathered at Montreal’s La Gare for Technovation’s kickoff hackathon. The students were given a primer on the program’s curriculum, then students and mentors were matched up in the afternoon when the work began in earnest. Christine and I were paired up with five 16-year-olds from an all-girls school in Montreal’s Outremont neighbourhood.</p>
<p>The students had to choose a problem domain right away--they could change it later on--but our team quickly decided on building a tool to aid in the process of <strong>finding internships or jobs for teenagers</strong>, a time when they’re beginning to make important decisions about pursuing a career they may or may not have already identified. As part of secondaire 4 and 5 (grades 11 and 12), students at their high school were beginning to search for part-time positions. The whole process left something to be desired: most students found placements through their parents’ professional networks which limited the kinds of careers they were exposed to.</p>
<img alt="" loading="lazy" width="1188" height="792" decoding="async" data-nimg="1" style="color:transparent" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fhackathon.9554d0b7.jpg&amp;w=1200&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fhackathon.9554d0b7.jpg&amp;w=3840&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fhackathon.9554d0b7.jpg&amp;w=3840&amp;q=75"/>
<p>One of the first exercises our team completed came from Google’s design sprint methodology: the students were tasked with quickly and independently sketching the six primary screens of their app-to-be. When the timer buzzed, everyone glanced around at each other’s pages. To their amazement, they had all drawn more or less the same screens: a <strong>search view</strong> with a list of results, a <strong>map with pins</strong> for local establishments that are hiring, a <strong>user profile page</strong>, and so on. This came as a pleasant surprise, if not a relief; for a brief moment, their problem seemed to have a straightforward solution. Think Instagram for jobs.</p>
<p>Our students could identify the problem because they observed its effects every day—a stunning 74% of 100 classmates answered “Yes” to the question “Is it stressful to think about your future career?”—but Christine and I could see the challenges in a software solution based on our own experiences navigating career paths.</p>
<p>Finding the job you’re best suited for is a kind of chicken and egg problem: a young person is more likely to express interest in careers that fit the set of skills/strengths she’s developed, but she’s likely cultivated those skills with a short list of potential careers in mind. Sixteen year old me would be shocked that I wound up a developer mostly because I didn’t have a clue what being a developer entailed.</p>
<h2 id="what-does-being-a-developer-entail"><a class="anchor" href="#what-does-being-a-developer-entail"><span class="icon icon-link"></span></a>What <em>Does</em> Being a Developer Entail?</h2>
<p>For a long time, I thought of programming as a job that is in many ways the exact inverse of teaching. The marginal cost of a piece of software, the cost of every additional copy, approaches zero, so software products can grow to an almost inconceivable scale relatively quickly. With over 1 billion users, Facebook’s continued growth is largely constrained by the number of humans on earth with access to the internet (hence Facebook’s <a href="https://www.theguardian.com/technology/2015/jul/31/facebook-finishes-aquila-solar-powered-internet-drone-with-span-of-a-boeing-737">internet-beaming drones</a>). Software’s reach is broad, but thin and ephemeral, I thought.</p>
<p>I knew that teaching in its current state didn&#x27;t &quot;scale&quot; in the same way, but I hadn&#x27;t considered that the impact of a talented educator can be as far-reaching as any piece of software.</p>
<p>Take Ms. Mabel Hefty. A fifth grade teacher at Punahou School in Honolulu in the 1970s, Ms. Hefty probably taught several hundred students in her career. One of them happened to be a young person named Barack Obama, who says she was the first person who taught him that he had something to say. Of course, President Obama had other great teachers and mentors throughout his life, though he often cites Ms. Hefty as his favorite. But the more I considered the potential impact of a great educator, the more I thought: if Internet scale is a proxy for impact, Ms. Hefty’s might rival Facebook’s.</p>
<p>Tech companies often talk about nurturing relationships with “users”, but the word itself is revealing. If I deploy a bug to production, I never have to watch a user’s face twist in frustration as they struggle to accomplish a simple task. But when I occasionally mangled the explanation of some technical concept and reflexively asked our students “Does that make sense?”, I had to look on in mild horror as five young people turned my poorly-chosen words over in their heads, vaguely pained and confused.</p>
<p>Teaching is not Sudoku. It’s more like stand-up comedy with higher stakes, where your performance is evaluated every 30 seconds and your score conveyed via the facial expressions of smart young people you want nothing more than to help succeed as much as you possibly can.</p>
<img alt="" loading="lazy" width="1074" height="1560" decoding="async" data-nimg="1" style="color:transparent" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fgoats.36750b61.jpg&amp;w=1080&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fgoats.36750b61.jpg&amp;w=3840&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fgoats.36750b61.jpg&amp;w=3840&amp;q=75"/>
<h2 id="teaching-a-programmer-to-teach"><a class="anchor" href="#teaching-a-programmer-to-teach"><span class="icon icon-link"></span></a>Teaching a Programmer to Teach</h2>
<p>I knew one thing I&#x27;d learned from my dad, a high school English teacher of over thirty years. To him, it&#x27;s one of the golden rules of teaching and the theme of an <a href="https://www.ted.com/talks/rita_pierson_every_kid_needs_a_champion?language=en#t-450445">excellent TED talk by educator Rita Pierson</a>: <strong>&quot;students don&#x27;t learn from people they don&#x27;t like.&quot;</strong> Beyond that, well, I didn’t study computer science <em>or</em> education. I studied philosophy, but early on in the mentoring process I knew with a weirdly visceral certainty that I was the perfect person to be giving five 16-year-olds a crash course in JavaScript’s primitive data types.</p>
<p>The night before our first lesson on git, I spent hours crafting slides that answered all of the questions I was too self-conscious to ask in my earliest programming days. Is there a difference between git and GitHub? How do you combine branches once you’re done building a feature? And what exactly is a branch?</p>
<img alt="Git basics, distilled into a deck" loading="lazy" width="2538" height="1510" decoding="async" data-nimg="1" style="color:transparent" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fintrotogit.286166e8.jpg&amp;w=3840&amp;q=75 1x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fintrotogit.286166e8.jpg&amp;w=3840&amp;q=75"/>
<p>Armed with my <a href="https://github.com/alessbell/git_prez/blob/master/git.pdf">deck</a>, a carefully prepared exercise set up in its own <a href="https://github.com/futurenowteam/collaborative_writing">repository</a> and an irrational confidence in my ability to convey the particulars of a complex decade-old version control system in under two hours, I was as prepared as I’d ever be.</p>
<p>Once the lesson was underway, and much to my relief, they dug into the material without hesitation. I knew the most important thing was to remove any fear of asking the wrong question, trying the wrong approach, committing the wrong code. Learning in an environment where you feel completely comfortable making mistakes is important for reasons beyond the happiness and well-being of students. It also creates the shortest possible feedback loop, allowing you to adjust and improve with every successive attempt.</p>
<p>In retrospect, the <em>how</em> of Technovation, the way we learned and worked as a team, was probably as critical as the content of the curriculum. Learning and building through iterative processes allows for faster progress.</p>
<img alt="One of many weekend work sessions at Breather HQ" loading="lazy" width="2117" height="1056" decoding="async" data-nimg="1" style="color:transparent" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2FbreatherOffice.f456a98d.jpg&amp;w=3840&amp;q=75 1x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2FbreatherOffice.f456a98d.jpg&amp;w=3840&amp;q=75"/>
<h2 id="survey-test-interview-repeat"><a class="anchor" href="#survey-test-interview-repeat"><span class="icon icon-link"></span></a>Survey, Test, Interview, Repeat</h2>
<p>And it wasn’t just in the programming portion that we embraced this approach. In order to test certain assumptions the team was making about how best to solve their problem, Christine had the idea of having them implement a “concierge” version of their idea before writing a line of code. Our team went through the motions of manually helping a few classmates land internships and realized it was actually way less straightforward than they’d imagined. Even when they were able to make warm introductions to professionals in fields their classmates were interested in, students were daunted at the prospect of reaching out to a professional they didn’t know.</p>
<p>A large portion of the six months of Techovation were spent this way: survey, test, interview, repeat. After testing our ideas, we realized the importance of two things: 1) that students have the opportunity to interact with professionals of diverse backgrounds, and 2) that students feel comfortable communicating on the platform.</p>
<p>The solution our team arrived at was a digital network in which a high school student has access to school alumni who are organized by industry and students are prompted with helpful conversation starters when they’d like to ask a question of one. Under the hood, it’s a responsive web app built with Meteor (here’s the <a href="https://github.com/futurenowteam/futurenow.com">source code</a>).</p>
<p>This was maybe the most exciting takeaway of Technovation: as programming becomes a tool more and more people use to create, the kinds of software being made will naturally diversify. As our team learned, some of the hardest problems in software are in understanding the needs and aspirations of those you hope to serve.</p>
<h2 id="postscript"><a class="anchor" href="#postscript"><span class="icon icon-link"></span></a>Postscript</h2>
<p>Most people I spoke with about Technovation over the past nine months assumed its goal is to encourage more young women to pursue careers in technology and entrepreneurship. Our team was interviewed by reporters several times—<a href="http://ici.radio-canada.ca/emissions/la_sphere/2015-2016/chronique.asp?idChronique=406096">once by Radio-Canada</a>, for example—and the question of career path was a common one. Did they now suddenly have dreams of going into tech? Each time our students politely answered, “Well… maybe!” They’re interested in all kinds of things, from medicine to law to the arts. It’s hard to say when you’re 16.</p>
<p>The more often adults asked the career question, though, the more I realized it’s beside the point. As much as I know that increasing the proportion of marginalized and underrepresented folks in tech is intrinsically valuable and important, I don’t actually have any vested interest in these five smart young women becoming programmers or entrepreneurs. What I do have a vested interest in is that they feel empowered to solve problems they deem interesting and worthy of their time, because that is in all of our interests.</p>
<p>In that way, Technovation isn’t really about technology or innovation at all: it’s about teaching young people (and reminding adults) of the importance of setting your sights on a wildly ambitious objective, even, or maybe especially, when the path to achieving it is unclear. You might not know how you’re going to get there, but you are sure you’re going to figure it out.</p>]]></content:encoded>
            <author>web@bellisar.io (Alessia Bellisario)</author>
        </item>
        <item>
            <title><![CDATA[From Bitmaker to Breather]]></title>
            <link>https://aless.co/from-bitmaker-to-breather</link>
            <guid>https://aless.co/from-bitmaker-to-breather</guid>
            <pubDate>Wed, 04 Mar 2015 00:00:00 GMT</pubDate>
            <description><![CDATA[A QuickStart™ Guide to Making Things on the Internet]]></description>
            <content:encoded><![CDATA[<p>It was a little more than a year ago that I made what was, in retrospect, a rather large, life-altering decision: I signed up for the coding bootcamp Bitmaker Labs. Despite my best efforts to document the process, I only ended up writing a total of three blog posts during my time as a student, but I remember how useful the blogs of past cohorts were in helping me decide that Bitmaker was the educational environment I was looking for. After the program, however, many student blogs go dark: surprisingly, life after Bitmaker can be even more hectic than life at 220 King St. West.</p>
<p>This is my attempt to remedy the situation, having recently joined the wonderful team at <a href="https://breather.com">Breather</a> as a developer. This post is a brief reflection on my time at Bitmaker and what made it the right choice for me, a previously self-taught freelance designer/developer.</p>
<h2 id="bootcamp-or-self-study"><a class="anchor" href="#bootcamp-or-self-study"><span class="icon icon-link"></span></a>Bootcamp or Self-Study?</h2>
<p>My answer is secret option C: both.</p>
<p>Throughout my undergraduate degree in philosophy and political science I found myself taking on freelance web design/dev jobs out of sheer enjoyment. The Jessica Hische-ism “procrastiwork” always felt apt: making things on the internet was the work I did when I should have been doing other work. First for my dad&#x27;s small business and later for freelance clients or politicians I was working for, I would mostly build WordPress sites with themes I could hack in a fairly limited way, or use a no-code site builder like Apple&#x27;s old <a href="https://en.wikipedia.org/wiki/IWeb">iWeb</a> (RIP).</p>
<p>In my final year of university, I got bored of making static pages and copying inscrutable JavaScript plugin code into WordPress, so I signed up for One Month Rails and started learning Ruby at night. This turned out to be a lot more fun but also more difficult than expected: I’d start making meaningful progress only to have my busy school schedule take over.</p>
<p>Weeks later, I’d come back to programming, resigned to repeating lessons I’d already completed and managed to forget. Bitmaker was, for me, the answer to a persistent question: how can I build more interactive and complex things on the web? Many successful developers are self-taught, and this is surely a legitimate path to follow, but for me a bootcamp gave me the time and space to focus on one objective after years of ad hoc self-learning and build a portfolio.</p>
<p>A passion for programming is something I saw in all my classmates, and I think it’s the closest thing to a prerequisite for courses like Bitmaker’s. In the past few years, bootcamps have come to constitute a new category in education, and self-initiated learning is at their core. Your instructors are there to help you, not to convince you to work or reprimand you for skipping your homework three nights in a row. When prospective students ask me for advice, my main suggestion is to make sure they&#x27;ve tried building some simple web pages before sending in an application; it&#x27;s a low bar, but if you don’t enjoy this much, you surely won’t enjoy doing it for ten hours a day, nine weeks in a row.</p>
<p>As for more granular tips on learning to program, I defer to the <a href="https://christinacacioppo.com/blog/build-products">definitive post on the topic</a> by Christina Cacioppo. It was written after I finished Bitmaker, but there isn’t a single observation out of place.</p>
<h2 id="bootcamp-prep"><a class="anchor" href="#bootcamp-prep"><span class="icon icon-link"></span></a>Bootcamp Prep</h2>
<p>I can share more specific advice on what is and isn’t important while gearing up for the course, however. When I first started making my way through the prep material in May 2014, I found myself gravitating toward blog posts about spaced repetition memorization and other memory hacks. “Flash cards!” I’d think to myself wistfully, “at last, the answer to my problems...” Flash cards can be useful in retaining new material, and there are lots of great free tools like <a href="https://apps.ankiweb.net/">Anki</a> if you’re interested. In retrospect, though, my search for a single unifying approach to learning Ruby was flawed.</p>
<p>When I think about the time I spent exploring different study strategies, one of Ben Horowitz’s famous lessons from his Netscape years comes to mind: <a href="https://a16z.com/2011/11/13/lead-bullets/">there is no silver bullet, only a lot of lead bullets</a>. Learning to build things you’ve never built before is mostly a function of persistence. It’s easy to feel discouraged--I certainly did!--but if you don’t fully grasp a concept today, trust that you’ll get it tomorrow, or the day after that. One day, as it tends to go, you’ll be right. As Christina Cacioppo puts it rather bluntly, “Learning to program requires tenacity, not brilliance. Most professional programming isn’t rocket science, metaphorically or actually.”</p>
<p>It’s not rocket science, but that doesn’t mean it’s not difficult (and it definitely doesn’t mean you won’t struggle). As a student who was used to feeling self-assured in classroom settings studying the humanities and often felt out of my depth at Bitmaker, this is far and away the most valuable lesson I learned: working hard and persisting is its own reward, not simply because trying and failing &quot;builds character&quot; in some abstract sense, but because it’s fundamentally how human cognition works.</p>
<p>As The Khan Academy founder Salman Khan writes in his excellent blog post <a href="https://www.khanacademy.org/talks-and-interviews/conversations-with-sal/a/the-learning-myth-why-ill-never-tell-my-son-hes-smart">“The Learning Myth: Why I’ll Never Tell My Son He’s Smart”</a>:</p>
<blockquote>
<p>Researchers have known for some time that the brain is like a muscle; that the more you use it, the more it grows. They’ve found that neural connections form and deepen most when we make mistakes doing difficult tasks rather than repeatedly having success with easy ones. What this means is that our intelligence is not fixed, and the best way that we can grow our intelligence is to embrace tasks where we might struggle and fail.</p>
</blockquote>
<h2 id="its-ok-good-to-fail"><a class="anchor" href="#its-ok-good-to-fail"><span class="icon icon-link"></span></a>It&#x27;s <del>OK</del> Good to Fail</h2>
<p>At Bitmaker Labs, perhaps more than anything else, you will struggle and fail. That’s what makes it such a fantastic place to learn. While attempting to build Rails apps on my own, I’d make moderate progress, hit a stumbling block I couldn’t overcome, get discouraged and walk away from the computer. Instead, at Bitmaker, after ten or fifteen minutes of struggling on my own--generally the point after which spinning your wheels becomes significantly less productive--I was able to find an instructor to give me the boost I needed to keep going.</p>
<p>As I came to discover, the core feature of a bootcamp is that it accelerates this feedback loop to enable you to fail faster, more often and in the most constructive environment possible. This is terrible for your ego but exceptionally effective where it counts: learning new and difficult things.</p>]]></content:encoded>
            <author>web@bellisar.io (Alessia Bellisario)</author>
        </item>
        <item>
            <title><![CDATA[Coding != Computer Science]]></title>
            <link>https://aless.co/coding-is-not-cs</link>
            <guid>https://aless.co/coding-is-not-cs</guid>
            <pubDate>Mon, 07 Jul 2014 00:00:00 GMT</pubDate>
            <description><![CDATA[The Case for Programming as a Liberal Art]]></description>
            <content:encoded><![CDATA[<p>Listening to David Heinemeier Hansson deliver the <a href="https://www.youtube.com/watch?v=9LfmrkyP81M">2014 RailsConf keynote</a> a little over two months ago was, for me, a minor revelation. It was exam season in my last semester of university and I had several philosophy finals bearing down on me. As I began organizing my notes, I came across a link on Twitter and fired up the conference livestream. What began as white noise in the background quickly piqued my interest. Soon enough, I found myself glued to the screen.</p>
<p>Growing up in Copenhagen, DHH loved tinkering with computers and tried to learn programming on three separate occasions. In retrospect, he says, his early, uninspiring attempts at writing software had one important thing in common: each time he had tried and failed, Hansson had encountered programming in the context of computer science. As a teenage gamer and aspiring video game developer, some of his first attempts at programming were in the esoteric language <a href="https://en.wikipedia.org/wiki/AMOS_(programming_language)">AMOS Basic</a>. There was plenty of math involved and Hansson has the report cards to prove his lack of mathematical aptitude: he was an F student in math and physics, but an A student in English.</p>
<p>Years passed. Closer to the age of 20, Hansson finally learned to program. Just three years later, he invented Ruby on Rails, the open source web application framework I’m learning here at Bitmaker Labs nearly a decade down the line. If your understanding of programming is based largely on the way it’s depicted in popular culture, you may be wondering: how could that possibly be?</p>
<p>Stories like Hansson’s are inconvenient exceptions to many of the storied myths of programming. From the outside looking in, many believe that what all software engineers do is some strain of computer science. Worse still, many programmers wish it were so (Hansson calls this hitting them in their “impostor plexus”). In reality, Hansson says, writing software is less like engineering and more like studying 17th century French poetry: when reading other people’s programs, most of his time is spent wondering “what the f—k did this person mean?”</p>
<p>Point taken, and now that I’ve waded through other people’s code, I can attest to this. The analogy elicits a few chuckles from the audience, but it also succeeds in getting the message across. In DHH’s view, writing software boils down to precisely that: <em>writing</em>. He uses this notion of computer science as a liberal art--a kind of cognitive re-framing of the discipline <a href="https://www.youtube.com/watch?v=IY7EsTnUSxY">popularized by Steve Jobs</a>--to further argue that, while there will always be a place for unit testing and optimization, prioritizing metrics ahead of system architecture is fundamentally wrongheaded because it sacrifices sound system design &quot;on the altar of objective science.&quot;</p>
<p>As a web developer-in-training, I prefer to view the issue of testing and TDD with a bit more nuance (<a href="https://web.archive.org/web/20190420075019/https://www.destroyallsoftware.com/blog/2014/tdd-straw-men-and-rhetoric">this is a great piece</a> if you’re interested in the other side of the story), but hearing DHH challenge the computer science paradigm was a much-needed reminder that, despite a lack of formal computer science education, programming is still very much “for me.” This may seem like a trite realization, but as someone who loved studying the humanities in university while maintaining a strong interest in software, it was a relief to hear that the two aren’t mutually exclusive. In fact, they might be more closely related than you think.</p>]]></content:encoded>
            <author>web@bellisar.io (Alessia Bellisario)</author>
        </item>
    </channel>
</rss>