<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Remy Sharp</title>
    <description>The latest articles on DEV Community by Remy Sharp (@remy).</description>
    <link>https://dev.to/remy</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F24688%2F1a9c35a2-924d-4c8b-827f-eaec15e154eb.jpeg</url>
      <title>DEV Community: Remy Sharp</title>
      <link>https://dev.to/remy</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/remy"/>
    <language>en</language>
    <item>
      <title>Smarter throwing</title>
      <dc:creator>Remy Sharp</dc:creator>
      <pubDate>Sat, 17 Oct 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/remy/smarter-throwing-ane</link>
      <guid>https://dev.to/remy/smarter-throwing-ane</guid>
      <description>&lt;p&gt;With &lt;code&gt;async/await&lt;/code&gt; becoming standard procedure for a lot of my code, I find myself wrapping blocks of code in &lt;code&gt;try/catch&lt;/code&gt; to ensure I'm handling errors properly.&lt;/p&gt;

&lt;p&gt;As a result of this, I also try to make my errors a little more useful at the same that I want to show you in this mini post.&lt;/p&gt;

&lt;h2&gt;
  
  
  The example
&lt;/h2&gt;

&lt;p&gt;I have large validation process that runs through a series of statements and checks for particular problems and rules.&lt;/p&gt;

&lt;p&gt;Each validation rule is run and if it fails, it throws with a message, such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export function validateFakeExample(token, scope) {
  if (token.text !== 'PRINT') return;

  const next = scope.peekNext();
  if (next.name !== AT) {
    throw new Error('Parser error, PRINT keyword should be followed by AT');
  }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;My main function runs each of the validation rules all encapsulated inside of a &lt;code&gt;try/catch&lt;/code&gt; because I also want to capture additional metadata that will help my user understand &lt;em&gt;what&lt;/em&gt; caused the error.&lt;/p&gt;

&lt;p&gt;So in my wrapping &lt;code&gt;catch&lt;/code&gt; I have something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;} catch (error) {
  const message = error.message + `, "${token.text}" at: ${token.pos + 1}`;
  throw new Error(message);
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This way, when the error is given back to my user, they'll see:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Parser error, PRINT keyword should be followed by AT, "INK" at: 10

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Actually I use this pattern a lot, to catch the source error, interpret it, and &lt;code&gt;throw new Error&lt;/code&gt; to help me better understand what was going on.&lt;/p&gt;

&lt;p&gt;Except it can be smarter.&lt;/p&gt;

&lt;h2&gt;
  
  
  Being smart
&lt;/h2&gt;

&lt;p&gt;When I call &lt;code&gt;new Error&lt;/code&gt; a brand new error object is created. At this point a few things happen, specifically the stack is captured. A stacktrace is incredibly useful for debugging to trace back to the source of the problem.&lt;/p&gt;

&lt;p&gt;Except, because I generated a brand new error, my stacktrace will originate from within the &lt;code&gt;catch&lt;/code&gt;, which is helpful to a certain degree, but could be a lot more useful.&lt;/p&gt;

&lt;p&gt;I &lt;em&gt;could&lt;/em&gt; do something with the stack. At times I've added a &lt;code&gt;console.log(error.stack)&lt;/code&gt; in the &lt;code&gt;catch&lt;/code&gt; which I can go searching my logs for.&lt;/p&gt;

&lt;p&gt;What I &lt;em&gt;should&lt;/em&gt; do is instead of throwing a &lt;code&gt;new Error&lt;/code&gt;, I can &lt;em&gt;simply&lt;/em&gt; modify the original &lt;code&gt;error.message&lt;/code&gt; property (🤦 why did it take me that long).&lt;/p&gt;

&lt;p&gt;So now my code looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;} catch (error) {
  error.message += `, "${token.text}" at: ${token.pos + 1}`;
  throw error;
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;My custom error message is passed by to the user (normally me) &lt;em&gt;and&lt;/em&gt; my full stacktrace is retained.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://remysharp.com/2020/09/24/smarter-throwing"&gt;Remy Sharp's b:log&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>A px is not a px</title>
      <dc:creator>Remy Sharp</dc:creator>
      <pubDate>Wed, 29 Jul 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/remy/a-px-is-not-a-px-pak</link>
      <guid>https://dev.to/remy/a-px-is-not-a-px-pak</guid>
      <description>&lt;p&gt;Recently I was trying to extract some glyphs from some various fonts and in doing so I had a fundamental assumption challenged and dispelled.&lt;/p&gt;

&lt;p&gt;A &lt;code&gt;px&lt;/code&gt; in terms of fonts, is not a pixel. Or certainly not in the way I was using them.&lt;/p&gt;

&lt;p&gt;For as long as I can remember I've used &lt;code&gt;px&lt;/code&gt; for my CSS fonts. I tried with &lt;code&gt;em&lt;/code&gt;s and usually ran into some sizing issues (better devs than me know how to use them properly). I had a lot of success with &lt;code&gt;rem&lt;/code&gt;s (not only because clearly they're named after yours truly…not), but if you asked me yesterday how to a make a font sized at 16 pixels, I'd have said 'font-size: 16px`.&lt;/p&gt;

&lt;p&gt;If I'm honest, it's close enough and when a font size isn't &lt;em&gt;quite&lt;/em&gt; right, I adjust. I tweak the font size, I tweak the line height, I tweak margins and padding until it looks right.&lt;/p&gt;

&lt;p&gt;From a fully technical and exact perspective though, I didn't know what I was talking about!&lt;/p&gt;

&lt;h2&gt;
  
  
  When I realised
&lt;/h2&gt;

&lt;p&gt;I was trying to render tiny fonts, no larger than 8 pixels wide into a canvas, and extract the pixel data (for a ZX Spectrum project). So I unwittingly set the font size in the 2D drawing API to &lt;code&gt;8px&lt;/code&gt; and ran the &lt;code&gt;fillText&lt;/code&gt; method only to be faced with text that either didn't fit in the 8x8 square or was way too small.&lt;/p&gt;

&lt;p&gt;I &lt;em&gt;thought&lt;/em&gt; (incorrectly) that &lt;code&gt;8px&lt;/code&gt; meant the font would be 8 pixels tall. So utterly wrong.&lt;/p&gt;

&lt;p&gt;This is also compounded by the fact that when you draw on a canvas, you need to specify the X and Y coordinate of the baseline - the specification suggests X/Y is the top left corner, but this isn't the case as drawing text in a canvas draws &lt;em&gt;upwards&lt;/em&gt; so with &lt;code&gt;x:0, y:0&lt;/code&gt; you get nearly completely clipped text.&lt;/p&gt;

&lt;p&gt;So I would have hoped the way to get the text to render on the canvas would be to add the pixel height of the font: &lt;code&gt;x:0, y:8&lt;/code&gt; but as we already know, the height of the font isn't 8 pixels.&lt;/p&gt;

&lt;h2&gt;
  
  
  What makes the height of a font?
&lt;/h2&gt;

&lt;p&gt;I won't pretend to fully understand it (yet) but there's an &lt;a href="https://iamvdo.me/en/blog/css-font-metrics-line-height-and-vertical-align"&gt;excellent breakdown post by Vincent De Oliveira&lt;/a&gt; that examines how to align 100px to a font height and how it breaks up. The practical example that De Oliverira gets into is if they want to place a checkbox image aligned with the text. It's not as easy as it might first sound.&lt;/p&gt;

&lt;p&gt;Also, more practically, there is the &lt;a href="https://seek-oss.github.io/capsize/"&gt;Capsize&lt;/a&gt; project that allows you to upload a font or select an existing Google font, and the page will read in the metadata about the font and help you adjust values to get the height of the font to best suit your needs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;As it turns out, in a lot of cases, when I'm thinking of the &lt;em&gt;height&lt;/em&gt; of a font, I'm actually thinking about the height of a capital letter, which is the ascender in font metrics.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Bits of a font
&lt;/h2&gt;

&lt;p&gt;In my side projects I spend a lot of time looking at binary data and parsing it in JavaScript so it made sense that I should poke around in the font to see if I could find these values myself.&lt;/p&gt;

&lt;p&gt;Thus far I've only looked at TrueType fonts. The font file is structured as so:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Header (12 bytes) - which includes the font file signature and directly after includes the 32bit table count&lt;/li&gt;
&lt;li&gt;Array of tables - each table includes: tag name (4 characters padded), checksum, file offset and length&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;With these small bits of information we will have an array of all the font tables that are included in the file. The tables of interests are required in the file format (according to &lt;a href="https://developer.apple.com/fonts//TrueType-Reference-Manual/RM06/Chap6.html#Overview"&gt;Apple's documentation&lt;/a&gt;) and I want to look inside the tables: &lt;code&gt;OS/2&lt;/code&gt;, &lt;code&gt;hhea&lt;/code&gt; and &lt;code&gt;head&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;These tables can appear in any order in the file and have variable length - both depending on the tag name but also the version of the table.&lt;/p&gt;

&lt;p&gt;To extract the information out of the file, first the file is uploaded into the browser and using the &lt;code&gt;FileReader&lt;/code&gt; API I'll get an &lt;code&gt;ArrayBuffer&lt;/code&gt; of the bytes:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;`&lt;br&gt;
input.onchange = (event) =&amp;gt; {&lt;br&gt;
  const file = event.target.files[0];&lt;br&gt;
  const reader = new FileReader();&lt;br&gt;
  reader.onload = (event) =&amp;gt; {&lt;br&gt;
    // do something with the buffer&lt;br&gt;
    handleData(event.target.result);&lt;br&gt;
  };&lt;br&gt;
  reader.readAsArrayBuffer(file);&lt;br&gt;
};&lt;/p&gt;

&lt;p&gt;`&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;For instance, to extract the capital height, I can create a view on the buffer and extract the 16bit value I need:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;`&lt;br&gt;
function handleData(buffer) {&lt;br&gt;
  const view = new DataView(buffer);&lt;br&gt;
  const tableCount = view.getUint16(5, true);&lt;/p&gt;

&lt;p&gt;let capitalHeight = null;&lt;/p&gt;

&lt;p&gt;// use a decoder to read the tag 4 character field&lt;br&gt;
  const decoder = new TextDecoder();&lt;/p&gt;

&lt;p&gt;let ptr = 12; // where the header ends&lt;br&gt;
  for (let i = 0; i &amp;lt; tableCount; i++) {&lt;br&gt;
    // the tag is 4 characters long&lt;br&gt;
    const tag = decoder.decode(data.slice(ptr, ptr + 4));&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// `offset` is where we find the table data in the file
const offset = view.getUint32(ptr + 8);

if (tag === 'OS/2') {
  // cap height sits 88 bytes from the start of the header
  capitalHeight = view.getInt16(offset + 88) / 1000;
}

// table headers are 16 bytes long
ptr += 16;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;}&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;`&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now I can use the &lt;code&gt;capitalHeight&lt;/code&gt; as I feel fit and all in the browser if I wanted to do work dynamically.&lt;/p&gt;

&lt;p&gt;In practice, if the aim is to align text, then it makes sense to collect the font metric data ahead of time with a tool like &lt;a href="https://seek-oss.github.io/capsize/"&gt;Capsize&lt;/a&gt; or if that resource ever disappears I've extended the code I wrote earlier to a barebones &lt;a href="https://font-size.isthe.link/"&gt;TTF metrics extraction&lt;/a&gt; tool.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://remysharp.com/2020/07/15/a-px-is-not-a-px"&gt;Remy Sharp's b:log&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>css</category>
    </item>
    <item>
      <title>Works offline</title>
      <dc:creator>Remy Sharp</dc:creator>
      <pubDate>Fri, 17 Jul 2020 15:25:00 +0000</pubDate>
      <link>https://dev.to/remy/works-offline-528c</link>
      <guid>https://dev.to/remy/works-offline-528c</guid>
      <description>&lt;p&gt;So many web sites work offline and we don't know it. It's kind of a beautiful aspect of the P in PWA: the web sites are progressively enhanced to be available even without an internet connection.&lt;/p&gt;

&lt;p&gt;Yet browsers won't tell us so. More on that in a bit. How do we tell our visitors our sites work offline. How do we tell our visitors that they don't need an app because it's no more capable than the URL they're on right now?&lt;/p&gt;

&lt;p&gt;I've created a Github issue (by way of creating an open forum) with a call for ideas and collaboration.&lt;/p&gt;

&lt;p&gt;Please, if you're a designer, iconographer, tinkerer, please contribute your ideas: &lt;strong&gt;&lt;a href="https://github.com/works-offline/logo/issues/1"&gt;github#works-offline/logo/issues/1&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I created the issue and the repo, but this isn't mine. In fact I immediately made &lt;a href="https://github.com/works-offline/logo/issues/2"&gt;issue 2&lt;/a&gt; to that effect. This is an effort that requires us, the makers of the web, to take matters into our own hands.&lt;/p&gt;

&lt;p&gt;Creating a visual cue to offline capability isn't a new thing and I'm certainly not the first. The most recent large waves came in the form of the &lt;a href="http://offlinefirst.org/"&gt;Offline First initiative&lt;/a&gt; which is already over 5 years old and &lt;a href="http://hood.ie/blog/say-hello-to-offline-first.html"&gt;introduced by Hoodie&lt;/a&gt;. I remember &lt;a href="https://alistapart.com/article/offline-first/"&gt;A List Apart bringing support&lt;/a&gt; (albeit via an article) which created some great momentum.&lt;/p&gt;

&lt;p&gt;Yet we're 5 years on and our visitors still don't realise how capable our sites are. Hell, I'd call myself pretty savvy but I didn't think for a moment that &lt;a href="https://lodash.com/docs/4.17.15"&gt;lodash's documentation&lt;/a&gt; would work offline until I happened upon it by accident.&lt;/p&gt;

&lt;p&gt;I want to see some way that we can show, proudly, on our own web sites that our URLs work offline. As &lt;a href="https://adactio.com/links/17137"&gt;Jeremy reminds us&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;…seeing as browsers have completely dropped the ball on any kind of ambient badging, it’s fair enough that we take matters into our own hands.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Branding matters
&lt;/h2&gt;

&lt;p&gt;HTML. Web 2.0. Ajax. RSS. HTML5. PWA.&lt;/p&gt;

&lt;p&gt;These are … "words" that meaning to a select few individuals, and yet are recognised by a broad range of every day people.&lt;/p&gt;

&lt;p&gt;Some of these have &lt;a href="https://www.w3.org/html/logo/faq.html"&gt;logos&lt;/a&gt; &lt;a href="https://en.m.wikipedia.org/wiki/Progressive_web_application"&gt;attached&lt;/a&gt; to their ideas.&lt;/p&gt;

&lt;p&gt;But these are all examples of technical terms making it out into the wider world and becoming brand ambassadors for technical progress and innovation.&lt;/p&gt;

&lt;p&gt;Branding is incredibly powerful, as anyone hired to build an "HTML5 web app" knowing full well there may not actually be any "HTML5" in the resulting software. The exact definition doesn't matter. What matters is the hook.&lt;/p&gt;

&lt;p&gt;Often we just need a word to lean on to help people grasp the idea and run.&lt;/p&gt;

&lt;p&gt;What's also interesting is that a lot of these terms have a commonality that they don't mean just one thing. Just as "XMLHttpRequest is only part of the Ajax equation" as &lt;a href="https://web.archive.org/web/20180822143943/https://www.adaptivepath.com/ideas/ajax-new-approach-web-applications/"&gt;explained by Jessie James Garret&lt;/a&gt; and as PWA doesn't &lt;a href="https://infrequently.org/2015/06/progressive-apps-escaping-tabs-without-losing-our-soul/"&gt;just mean "service worker"&lt;/a&gt; (though technically without service workers there is no PWA).&lt;/p&gt;

&lt;p&gt;Likewise, "works offline" does not mean it has to satisfy a specific tick list. It's an idea, one that the makers of the web need to impress upon the world.&lt;/p&gt;

&lt;h2&gt;
  
  
  What does "works offline" mean?
&lt;/h2&gt;

&lt;p&gt;I tried to spread the request for help via Reddit (a web site I very, very rarely visit) and one individual raised an interesting and valuable question (though it was phrased as a counter point): &lt;em&gt;isn't this just saving a cached copy?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This is what we need to overcome with our software. For a site to work offline, is so much more, so much richer than the saved bones of an HTML page.&lt;/p&gt;

&lt;p&gt;The reality, today in fact, is that with the service worker capability we can deliver the same offline experience as many appstore installed mobile apps. At a fraction of the cost.&lt;/p&gt;

&lt;h2&gt;
  
  
  Is working offline the same as installable?
&lt;/h2&gt;

&lt;p&gt;The short answer, as you know, is no. But installable isn't better than "works offline". I've installed many applications from the app stores that I found out the hard way flat out didn't work without an internet connection (usually on my travels off of my home cellular network).&lt;/p&gt;

&lt;p&gt;Yet if I install software from the app store I expect it to work offline.&lt;/p&gt;

&lt;p&gt;If I visit a web site, I never expect it to work offline.&lt;/p&gt;

&lt;p&gt;What if you could tell me, when I visited your web site, that it worked offline.&lt;/p&gt;

&lt;p&gt;Absolutely yes, the browsers should provide badging. They &lt;em&gt;could&lt;/em&gt; track if new entries were made to the origin's cache, and they could run a routed request for the URL I visited (stopping it from hitting the network layer preventing a double request if there wasn't middleware offline routing in place).&lt;/p&gt;

&lt;p&gt;Yet there's no indication that will come from browsers in the short term. So how about &lt;a href="https://github.com/works-offline/logo/issues/1"&gt;we do it ourselves&lt;/a&gt;?&lt;/p&gt;

&lt;p&gt;The same way RSS went. How did you know a web site offered a feed of their content (before RSS was baked into browsers…or even after they all removed it)? Imagery, logos, word marks.&lt;/p&gt;

&lt;p&gt;RSS needed something obvious and clear that as a visitor I could subscribe. Dave Winer in 2005 (re?)started &lt;a href="https://web.archive.org/web/20060221082210/http://www.reallysimplesyndication.com/2005/09/26#a970"&gt;the conversation&lt;/a&gt; and Microsoft eventually &lt;a href="https://web.archive.org/web/20060227071704/http://blogs.msdn.com/rssteam/archive/2005/10/08/478505.aspx"&gt;picked up the ball&lt;/a&gt; (working with Mozilla if I read correctly) and that's how we &lt;a href="https://web.archive.org/web/20051216113745/http://blogs.msdn.com/rssteam/archive/2005/12/14/503778.aspx"&gt;got the RSS icon&lt;/a&gt; (the original post is &lt;a href="https://docs.microsoft.com/en-us/archive/blogs/rssteam/icons-its-still-orange"&gt;still live&lt;/a&gt;, but missing the images).&lt;/p&gt;

&lt;p&gt;Slapping a bit of "works offline" on my site would be a great first step.&lt;/p&gt;

&lt;h2&gt;
  
  
  We need your help
&lt;/h2&gt;

&lt;p&gt;What I'd personally like to see as an outcome: some simple iconography that I can use on my own site and other projects that can offer ambient badging to reassure my visitor that the URL they're visiting will work offline.&lt;/p&gt;

&lt;p&gt;Please, &lt;a href="https://github.com/works-offline/logo/issues/1"&gt;please contribute&lt;/a&gt; if you can. There's already been some really wonderful work and this is a stage of trying anything and everything out.&lt;/p&gt;

&lt;p&gt;If, like me, your skills don't lie in design, then please help spread the word 🙏&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://remysharp.com/2020/07/17/works-offline"&gt;Remy Sharp's b:log&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>offline</category>
      <category>pwa</category>
    </item>
    <item>
      <title>"Share the knowledge for free" [blog]</title>
      <dc:creator>Remy Sharp</dc:creator>
      <pubDate>Sat, 04 Jul 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/remy/share-the-knowledge-for-free-blog-hgm</link>
      <guid>https://dev.to/remy/share-the-knowledge-for-free-blog-hgm</guid>
      <description>&lt;p&gt;That title is in "air quotes" - just to be clear. I'm writing this so I don't have to repeat myself, because this sentiment has come up over and over and over. Not just for me, but for you, for your peers, your friends and many other anonymous creators out there.&lt;/p&gt;

&lt;p&gt;"Share the knowledge for free" - anon.&lt;/p&gt;

&lt;p&gt;The short reply is: no.&lt;/p&gt;

&lt;p&gt;But, sure, let's take a moment to discuss this.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/3o6ZtokgzQv6ThHzj2/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/3o6ZtokgzQv6ThHzj2/giphy.gif" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  No?
&lt;/h2&gt;

&lt;p&gt;Just to clear up the obvious first: we have bills to pay. I have a mortgage. I need food. I have kids and dependents.&lt;/p&gt;

&lt;p&gt;I am able to work, therefore I do, and that work brings in money to our family and with that money we support our lives. Thank god my partner and I are able to work. I know there's others who are less fortunate and struggle at this basic need.&lt;/p&gt;

&lt;p&gt;This isn't money grabbing nor taking advantage of entity handing over the money. Money, in this particular reality, is core to survival. You know this, we all know this.&lt;/p&gt;

&lt;h2&gt;
  
  
  I didn't say "work for free"
&lt;/h2&gt;

&lt;p&gt;That's right, you said give away your knowledge for free. Sure, speaking is "free" (mostly). But acquiring that knowledge was not a free process for me.&lt;/p&gt;

&lt;p&gt;It either took hours and hours and hours and actually &lt;em&gt;years&lt;/em&gt; of learning. Along the way that involved buying books, buying software, coding and creating - all activities that no one is paying me for.&lt;/p&gt;

&lt;p&gt;Yet still that knowledge is now in me, surely I can give that away? Well, if I can stick a Matrix-like spike in the back of my head and connect it to yours, then sure, I'd be willing to do that.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lXuJQLdw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://remysharp.com/images/i-no-kung-fu.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lXuJQLdw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://remysharp.com/images/i-no-kung-fu.jpg" alt="Neo from the Matrix learning kung fu from a brain download"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Except in reality we need to create a medium to transfer knowledge. This has costs, here's some of those costs off the top of my head for content I create:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The time spent writing content (long)&lt;/li&gt;
&lt;li&gt;Time spent creating videos or audio (again, long)&lt;/li&gt;
&lt;li&gt;Creating supporting websites for said content&lt;/li&gt;
&lt;li&gt;Hosting fees for content (particularly video is yearly)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All this time is time spent not earning a living too.&lt;/p&gt;

&lt;p&gt;So, I'm saying, for the record, "sharing your knowledge for free" is a misnomer. There is no "free" for me, nor for you.&lt;/p&gt;

&lt;p&gt;This post is pretty much redundant, but maybe I'll be able to save myself the time (and thus cost) of replying this same sentiment every time I'm faced with this.&lt;/p&gt;

&lt;h2&gt;
  
  
  Free is not the default
&lt;/h2&gt;

&lt;p&gt;There's many many examples of people sharing their work for free. I applaud you. I'm in this group, jsbin, nodemon, this blog and many other projects - but this is not a hard requirement of being part of the web or the world.&lt;/p&gt;

&lt;p&gt;Free is not the default, it never was. I value your work. I believe we should be paid, and I've written about this before in &lt;a href="https://remysharp.com/2014/03/07/youre-paying-to-speak"&gt;You're Paying to Speak&lt;/a&gt; and &lt;a href="https://remysharp.com/2019/07/30/buy-the-coffee"&gt;Buy the coffee&lt;/a&gt;. I &lt;em&gt;love&lt;/em&gt; paying for people's work on &lt;a href="https://itch.io"&gt;itch.io&lt;/a&gt; (I've bought an ungodly number of asset libraries for ideas that I'll probably never get around to).&lt;/p&gt;

&lt;p&gt;I &lt;em&gt;love&lt;/em&gt; supporting other people's work when I can. I'll continue to do so whilst I can afford to.&lt;/p&gt;

&lt;p&gt;So get paid. Ask to be paid.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Your work is valuable and your time and experience is even more so.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://remysharp.com/2020/07/03/share-the-knowledge-for-free"&gt;Remy Sharp's b:log&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Clearing twitter</title>
      <dc:creator>Remy Sharp</dc:creator>
      <pubDate>Fri, 19 Jun 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/remy/clearing-twitter-28aj</link>
      <guid>https://dev.to/remy/clearing-twitter-28aj</guid>
      <description>&lt;p&gt;It's no surprise that twitter and similar sink holes are constantly trying to "engage" you so you can be sucked into their void. As someone who believes that the web belongs to its users and I browse the way &lt;em&gt;I want&lt;/em&gt; I frequently change and block content on these sites so I can use them the way I would like.&lt;/p&gt;

&lt;p&gt;So here's a quick share on how I'm doing that.&lt;/p&gt;

&lt;p&gt;This is a simple example of how &lt;em&gt;I think&lt;/em&gt; twitter can be improved - the picture below shows, highlighted in red, the "trending news" which really isn't news - or at least not news that I would recommend consuming. I certainly don't want to get my COVID-19 advice from the latest trending bullshit. More recently they have launched (possibly in split tests) a DM … "thing"? so I can use that to message people instead of…what, email? WhatsApp? Not sure. Anyway, it's shit that I don't need in my life, so it's getting ejected.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--GcKOG40q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://remysharp.com/images/clean-twitter.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--GcKOG40q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://remysharp.com/images/clean-twitter.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Step 1: get yourself &lt;a href="https://github.com/gorhill/uBlock/"&gt;uBlock Origin&lt;/a&gt; (the origin bit is important) available for &lt;a href="https://github.com/gorhill/uBlock/#installation"&gt;most browsers&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Step 2: use the right click - block element picker to stop content from bothering you&lt;/p&gt;

&lt;p&gt;When you fire up the picker, you'll notice that Twitter (and other sites that don't believe in writing actual CSS classes) are using something to generate their CSS, which makes picking element using CSS selectors tricky.&lt;/p&gt;

&lt;p&gt;Except, the trick is to look for aria roles or even data properties. As much as I dislike these big companies, they &lt;em&gt;do&lt;/em&gt; try to support a broad range of users via good use of accessibility and we can use that to our advantage.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7hIWyu6z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://remysharp.com/images/picking.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7hIWyu6z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://remysharp.com/images/picking.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The uBlock Origin element picker will need a selector like &lt;code&gt;##div[aria-label="Timeline: Trending now"]&lt;/code&gt;, I'm not sure what the double hash is about, but it works.&lt;/p&gt;

&lt;p&gt;So now we can surf web pages the way &lt;em&gt;we want&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://remysharp.com/2020/06/19/clearing-twitter"&gt;Remy Sharp's b:log&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>twitter</category>
      <category>webdev</category>
    </item>
    <item>
      <title>I fell for fraud</title>
      <dc:creator>Remy Sharp</dc:creator>
      <pubDate>Sun, 10 May 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/remy/i-fell-for-fraud-18e4</link>
      <guid>https://dev.to/remy/i-fell-for-fraud-18e4</guid>
      <description>&lt;p&gt;Saturday afternoon as I was mentally getting ready for the kids bedtime and drinking a Martinez (ooh, get me, though it was my first cocktail of the year,and no, I don't count G&amp;amp;T as a cocktail), I received a notification that O2 had failed to process my latest bill and that I should update my details.&lt;/p&gt;

&lt;p&gt;My card had been updated recently and I'd had a slew of emails telling me that recurring payment had failed…though the last wasn't for a good few weeks.&lt;/p&gt;

&lt;p&gt;With half and eye on my phone and partially aware of how O2 were being rubbish by asking for all my personal details that they should already have, I dutifully posted my details off a lucky fraudster.&lt;/p&gt;

&lt;p&gt;Here's the SMS I received:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;O2: Payment for your latest bill could not be processed by your bank. Please update your payment information via: &lt;a href="https://myo2"&gt;https://myo2&lt;/a&gt;․bill231․com?o2=2&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The URL then asks me to sign in, I did, and enter my address, I did, and enter my bank card and bank details, I did.&lt;/p&gt;

&lt;p&gt;100% absent mindedly.&lt;/p&gt;

&lt;p&gt;It's how accidents happen. My focus was on something else whilst my thumbs were on autopilot on my phone dolling out my details.&lt;/p&gt;

&lt;p&gt;What's ironic is that my career is on the web and these kinds of hazards are part fo the territory and yet as seasoned as I think of myself I still made a simply and potentially costly mistake.&lt;/p&gt;

&lt;p&gt;But the web we live in today is a bit of a jungle and sadly part of that is walking through long grass with snakes under foot. We conduct ourselves carefully and we navigate from one site to the next, and we protect ourselves with software, policies and knowledge, but what's important is that a bite from the snakes are not fatal.&lt;/p&gt;

&lt;p&gt;It's how quickly you or I react to the incident that makes all the difference.Thankfully as soon as I hit send I realised my mistake.&lt;/p&gt;

&lt;p&gt;The process was:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Consider every data point I shared with the fraudster website&lt;/li&gt;
&lt;li&gt;For bank details (in my case), immediately contact the bank and block the card&lt;/li&gt;
&lt;li&gt;Revoke any passwords shared (I already use 1password so I know the password is unique)&lt;/li&gt;
&lt;li&gt;On going for the follow weeks, monitor the bank account to watch for unknown transactions - this is particularly important as the fraud web site had my account details which gives them enough to start a new direct debit (but this is also covered under direct debit protection)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The longer term changes that I'm putting in place are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;(Though I know it) never follow a link to enter banking details, always type the target web site in manually (i.e. if O2 contacts me, I visit O2 myself,not via a URL)&lt;/li&gt;
&lt;li&gt;Adopt a new policy for receiving text messages which currently are almost exclusively 2FA codes, so it's almost worth disabling SMS messages entirely.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;I've had exactly two previous fraud events in my past, both of which I learnt hard lessons from, but perhaps were unavoidable (unlike this more recent event).&lt;/p&gt;

&lt;p&gt;The first was around 10 years ago, I received a direct message on twitter from a friend saying that some account details had been hacked and I should update my password immediately. I promptly followed the DM link inside the Twitter app,entered my password and … realised I'd been duped.&lt;/p&gt;

&lt;p&gt;Following the link from &lt;em&gt;inside&lt;/em&gt; Twitter's client meant that the URL bar was hidden from me, so I had no visual way of knowing what site I was on - it looked like Twitter (which was the point) so I fell for it. Since then I always disable"in browser" linking on apps I use.&lt;/p&gt;

&lt;p&gt;The second was around 15 years ago. My laptop had been written off in an accident and it was sent to the insurance company, they paid me insurance money and the machine was to be destroyed. Except it wasn't. A few months after the incident, I was contacted via email telling me that this person had my laptop in front of them and was going to wipe the drive so that it could be resold.&lt;/p&gt;

&lt;p&gt;Obviously this was a massive failing on the insurance company (I'm not with the many more and I forget &lt;em&gt;who&lt;/em&gt; they were), but the individual on the other end of the email was just doing their job. He specifically got in touch to ask if he wanted me to send the contents of the drive before it was wiped.&lt;/p&gt;

&lt;p&gt;I figured it might be a useful thing and said to go ahead. Except, he stated he couldn't get all the files off the drive, some were behind my password. I was hesitant when he asked for my password so he could send the files along, but said it made no difference to him as he was just helping me out, and "oh, I see you're a web developer, we need our web site redoing, maybe we could hire you…"and off my password went.&lt;/p&gt;

&lt;p&gt;As soon as I hit send (yes, reoccurring theme) I felt my gut drop. It was a horrible feeling knowing that I'd just let some stranger into a personal space such as my hard drive. I emailed him back immediately, specifically requesting proof the drive had been wiped … but of course I never heard back.&lt;/p&gt;

&lt;p&gt;Thank the stars there was nothing important on the drive, passwords or anythingsensitive and the thought haunted me for months, but nothing came of it.&lt;/p&gt;

&lt;p&gt;Suffice to say I've never uttered a password again.&lt;/p&gt;

&lt;p&gt;One additional policy I adopted after these events were that if a service was trying to authenticate me, particularly over the phone, it would have to be a call that &lt;em&gt;I had made&lt;/em&gt; and not them contacting me. This is similar to the policy of entering a URL manually and not following links.&lt;/p&gt;

&lt;p&gt;I guess we live and learn.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://remysharp.com/2020/05/10/i-fell-for-fraud"&gt;Remy Sharp's b:log&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>fraud</category>
      <category>personal</category>
      <category>security</category>
    </item>
    <item>
      <title>Setting up Simon's TIL</title>
      <dc:creator>Remy Sharp</dc:creator>
      <pubDate>Sat, 02 May 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/remy/setting-up-simon-s-til-4o2e</link>
      <guid>https://dev.to/remy/setting-up-simon-s-til-4o2e</guid>
      <description>&lt;p&gt;I've followed &lt;a href="https://simonwillison.net/"&gt;Simon Willison's blog&lt;/a&gt; for long, long time and in my &lt;a href="https://feedbin.com"&gt;latest RSS&lt;/a&gt; catchup I saw his post about &lt;a href="https://simonwillison.net/2020/Apr/20/self-rewriting-readme/"&gt;capturing his TIL&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I immediately earmarked it as something to follow and do myself (which I've now done but want to somehow pull across to my blog), and though Simon's post was excellent, it's not written as a set of instructions for doing yourself, so Today I Learned how to copy and tweak Simon's TIL repo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Overview of how it works
&lt;/h2&gt;

&lt;p&gt;Simon's post goes into the technical detail, but for a brief understanding this is what happens (assuming all the prerequisite files are in place):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;All commits &lt;em&gt;except&lt;/em&gt; on the README trigger the workflow (I wonder if this can be ignored though…)&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;build_database.py&lt;/code&gt; file runs looking only at &lt;code&gt;*/*.md&lt;/code&gt; files (so one directory deep) and generates an sqlite database&lt;/li&gt;
&lt;li&gt;The records in the sqlite database use the directory as the topic name (so one topic per TIL) and generates create and update times for the record based on the commit against each markdown file&lt;/li&gt;
&lt;li&gt;Then &lt;code&gt;update_readme.py&lt;/code&gt; runs to modify the repo readme inline, looking for &lt;code&gt;&amp;lt;!-- index start --&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;!-- index end --&amp;gt;&lt;/code&gt; and inserts the table of contents (the good bit)&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;README.md&lt;/code&gt; is committed under &lt;code&gt;README-bot&lt;/code&gt; back into your repo&lt;/li&gt;
&lt;li&gt;Finally the project is deployed to Now&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Initial files
&lt;/h2&gt;

&lt;p&gt;For this to work, you need your own github repo (since this uses github actions) and you need to specifically include the following files:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.
├── .github
│   └── workflows
│      └── build.yml
├── README.md
├── build_database.py
├── metadata.json
├── requirements.txt
├── templates
│   ├── index.html
│   ├── query-til-search.html
│   └── row.html
└── update_readme.py

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;I've pulled all the files into a single template repo here &lt;a href="https://github.com/remy/simonw-til-template"&gt;remy/simonw-til-template&lt;/a&gt; (which is a bit weird…) but it's a clean slate to work from.&lt;/p&gt;

&lt;p&gt;Put these in your own github repo and leave the default &lt;a href="https://github.com/YOUR-USERNAME/YOUR-REPO/settings/actions"&gt;action permissions&lt;/a&gt; as "Enable local and third party Actions for this repository".&lt;/p&gt;

&lt;h2&gt;
  
  
  Changes you need
&lt;/h2&gt;

&lt;p&gt;If you look for &lt;code&gt;USERNAME&lt;/code&gt; throughout the code, you can change this to your own github username (or your real name when used in the index page).&lt;/p&gt;

&lt;p&gt;If you want to deploy to Vercel (formally Zeit) Now (which the action does by default), then you need to &lt;a href="https://vercel.com/account/tokens"&gt;generate a new Now token&lt;/a&gt; and create a new token in the github repo under &lt;a href="https://github.com/%5BYOUR-USERNAME%5D/%5BYOUR-REPO%5D/settings/secrets"&gt;https://github.com/[YOUR-USERNAME]/[YOUR-REPO]/settings/secrets&lt;/a&gt;. The token needs to be called &lt;code&gt;NOW_TOKEN&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If you &lt;em&gt;don't&lt;/em&gt; want to deploy to Now, in the &lt;code&gt;.github/workflows/build.yml&lt;/code&gt; remove the entire section starting at &lt;code&gt;name: Deploy Datasette using Zeit Now&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Changes from Simon's original post and repo
&lt;/h2&gt;

&lt;p&gt;If you used the template repo I made, you won't need these, but if you're skimming Simon's post a couple of things to be aware of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;He uses &lt;code&gt;datasette publish now2 til.db&lt;/code&gt; but &lt;code&gt;now2&lt;/code&gt; (for us) should be &lt;code&gt;now&lt;/code&gt; - it's using his &lt;a href="https://github.com/simonw/datasette-publish-now"&gt;datasette-publish-now&lt;/a&gt; project.&lt;/li&gt;
&lt;li&gt;You'll need the &lt;code&gt;templates&lt;/code&gt; directory (which initially I thought was a TIL), which is used by datasette to build the actual web pages you'll host on Now&lt;/li&gt;
&lt;li&gt;If you're copying files one by one, the &lt;code&gt;README.md&lt;/code&gt; needs to have the following template &lt;em&gt;somewhere&lt;/em&gt; in the file: &lt;code&gt;&amp;lt;!-- index starts --&amp;gt;\n&amp;lt;!-- index ends --&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Possible changes
&lt;/h2&gt;

&lt;p&gt;For my &lt;a href="https://github.com/remy/til/"&gt;own version&lt;/a&gt; I think I might migrate it to my own blog but follow the structure that's already there. That way I can reuse my own existing system for RSS so it's a little more similar to &lt;a href="https://remysharp.com/links"&gt;my links&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://remysharp.com/2020/05/02/setting-up-simons-til"&gt;Remy Sharp's b:log&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
    </item>
    <item>
      <title>We're not smarter than browsers</title>
      <dc:creator>Remy Sharp</dc:creator>
      <pubDate>Wed, 29 Apr 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/remy/we-re-not-smarter-than-browsers-emk</link>
      <guid>https://dev.to/remy/we-re-not-smarter-than-browsers-emk</guid>
      <description>&lt;p&gt;This morning during performing another search through npm for the package that matched my needs, I was feeling lazy and didn't want to type "npm i x" - thankfully npm provided a helpful "click to copy". And that's where it went wrong.&lt;/p&gt;

&lt;p&gt;I recorded a &lt;a href="https://www.youtube.com/watch?v=nnD0-h7fVEg"&gt;video of my experience&lt;/a&gt; and this is part transcript, part conclusion, part repeating the obvious.&lt;/p&gt;




&lt;p&gt;Look when you disable user-select or try to disable right-click on your web page and you're not only breaking the accessibility the page, but you're also making the rather bold statement that &lt;em&gt;your code will &lt;strong&gt;never, ever&lt;/strong&gt; break&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;It seems too much of a risk.&lt;/p&gt;

&lt;p&gt;This morning's npm visit was an excellent example. I wanted to copy the text, so I hover over "npm i chart.js" and it says briefly, if I catch it, "click here to copy" but mousing over the copy not doing anything, and indeed "clicking here" when I check my clipboard has not copied anything.&lt;/p&gt;

&lt;p&gt;I'm clicking, but it's not copying.&lt;/p&gt;

&lt;p&gt;Okay, bugs happen, clearly the copy button doesn't work. Instead let's select this text and just… copy? Nope, no, I can't select the text.&lt;/p&gt;

&lt;p&gt;In fact, this is the one bit of text on that page that has been intentionally disabled for selecting, because we think as "web developers" we are smarter than the user and there's no way our code will ever break.&lt;/p&gt;

&lt;p&gt;Well, I have news for us web developers: we are fallible. Our code will break.&lt;/p&gt;

&lt;p&gt;So let's not break intentionally break accessibility features the browser works so hard to provide the user.&lt;/p&gt;

&lt;p&gt;Stop preventing select - selecting text is useful both for copying, but also for reading text (see dyslexic users).&lt;/p&gt;

&lt;p&gt;Stop not using buttons - buttons are clickable and we forget to add aria roles.&lt;/p&gt;

&lt;p&gt;Stop reinventing links - they're magic and &lt;a href="https://remysharp.com/2019/04/04/how-i-failed-the-a"&gt;our versions&lt;/a&gt; are rubbish.&lt;/p&gt;

&lt;p&gt;Stop &lt;a href="https://chrome.google.com/webstore/detail/no-more-scroll-jacking/fpialmplgijjacabejjgheeifmfamjcd"&gt;scroll jacking&lt;/a&gt; - it's squarely in the the uncanny valley, and often scrolls to fast for content to be properly read.&lt;/p&gt;

&lt;p&gt;Let's stop thinking we're smarter than the browser.&lt;/p&gt;

&lt;p&gt;Enhance the browser, don't reinvent.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://remysharp.com/2020/04/29/were-not-smarter-than-browsers"&gt;Remy Sharp's b:log&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
    </item>
    <item>
      <title>How I'm teaching the kids coding for the web</title>
      <dc:creator>Remy Sharp</dc:creator>
      <pubDate>Mon, 20 Apr 2020 09:00:00 +0000</pubDate>
      <link>https://dev.to/remy/how-i-m-teaching-the-kids-coding-for-the-web-5b7g</link>
      <guid>https://dev.to/remy/how-i-m-teaching-the-kids-coding-for-the-web-5b7g</guid>
      <description>&lt;p&gt;Early this year (pre country-wide lockdown), my son, 8¼, asked that I start doing "Coding Mondays" with him and his sister (then 5½). Though the littlest wasn't so interested in programming (though she had some fun with BASIC, as story for another day), so far the boy has managed to make his own web site and start to get to grips with HTML and CSS. JavaScript is much further away, but he does also have the ability to publish all his changes entirely himself.&lt;/p&gt;

&lt;p&gt;I thought it might be interesting to share how I'm explaining things to them, because they both seem to really understand it (or they're possibly just as bonkers as me, and random logic makes sense because decoding random is in their DNA… ¯_(ツ)_/¯ )&lt;/p&gt;

&lt;h2&gt;
  
  
  The tools
&lt;/h2&gt;

&lt;p&gt;Initially they were both using &lt;a href="https://jsbin.com"&gt;JS Bin&lt;/a&gt; for HTML and CSS. This worked well because it focuses entirely on HTML at the start and they got real time feedback, along with a bit of code completion (as they were using the unreleased v5). There's the obvious added bonus that when I explained that &lt;em&gt;I had written&lt;/em&gt; JS Bin - the code that they were typing &lt;em&gt;their&lt;/em&gt; code into, it both blew their minds and made me rather chuffed.&lt;/p&gt;

&lt;p&gt;The workflow would then be: download the file from JS Bin, send it from their Chromebook (a freebie from my upgrading my phone) using &lt;a href="https://snapdrop.net/"&gt;Snapdrop&lt;/a&gt; (a really great wifi file drop utility) to &lt;em&gt;my&lt;/em&gt; machine, I would then put that in a directory and drag and drop into Netlify to release to his web site. This wasn't so bad, but was a little limited and brittle.&lt;/p&gt;

&lt;p&gt;As the lessons continued, I decided to move up from JS Bin to &lt;a href="//https:/glitch.com/"&gt;Glitch&lt;/a&gt; - this way the boy could make new files, directories and upload images. Once he was using Glitch, I then wired Glitch up to &lt;a href="https://github.com"&gt;Github&lt;/a&gt; and showed him how to &lt;em&gt;Export to Github&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Now that he can export, I connected Netlify to the repository that he was exporting to and all of a sudden he has continuous deployment from a little export button in Glitch - and he's able to make new pages, change things, edit text and more. It's very cool (if perhaps complicated!).&lt;/p&gt;

&lt;h2&gt;
  
  
  The foundations of understanding
&lt;/h2&gt;

&lt;p&gt;There's no point in trying to explain from the outset what HTML is, how it works over HTTP, about browsers and the DOM, let alone CSS, the cascade, specificity and more. It's a slow layering of knowledge acquisition for them.&lt;/p&gt;

&lt;p&gt;So here's how I explained it.&lt;/p&gt;

&lt;p&gt;I loaded up a browser and explained that "this is a web page". It's like a person in some ways. The bones are the HTML. Each bone has a name, we call them tags (or elements). Each bone does it's own special thing, like the &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt; tag/bone will show some text.&lt;/p&gt;

&lt;p&gt;I showed them a handful of web pages with all the styles removed and showed them that "this is the skeleton of the web page". All bits of text and angle brackets. The bone have names and they hold the bit of content.&lt;/p&gt;

&lt;p&gt;But then, when we put the styles back, this is the skin over the skeleton. It's what makes each website look unique. Some can have different colours, shapes, heights and more. So the skin and the paint on the skin, this is CSS.&lt;/p&gt;

&lt;p&gt;I explained that CSS is written differently from HTML, and keeping with tag only selectors showed how the &lt;em&gt;name&lt;/em&gt; of the bone/tag is specified. For example: we want the foot bone to have a border. The syntax is simple enough that he's able to write the CSS selectors, property and values without prompting. He obviously does not know all the property types, but he's collecting them and writing notes in a book he keeps by his bed.&lt;/p&gt;

&lt;p&gt;Finally, the brain and behaviour, the way the website can be interacted with is using the third layer: JavaScript. A brain is a complicated bit of machinery so we've not worked up to it yet, but they understand it with relation to themselves.&lt;/p&gt;

&lt;p&gt;Just today the boy was trying to recreate a "spy agent ID card" with web (on my behest over doing it as a Google Doc), and he ended up with two &lt;code&gt;div&lt;/code&gt;s that he needed to style differently, but the border he had used was (incorrectly) applied to both &lt;code&gt;div&lt;/code&gt;s - because so far he only knows about element selectors.&lt;/p&gt;

&lt;p&gt;So I introduce the &lt;code&gt;class&lt;/code&gt; property to the HTML tags, and I tried to explain that the &lt;code&gt;class&lt;/code&gt; property lets me group tags together. Immediately he pipes up with:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Like a classroom, if I want to select all the children my class, it's called Feathers, so it's the feathers class.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Wow, yes, exactly like that. Element selectors are like: children, teachers, parents, etc. Class selectors are like grouping as "year 1 teachers" or "Feathers children" class, and then I explained we could be even more specific and name the unique individual, known as an ID.&lt;/p&gt;

&lt;p&gt;Now he has a basic understanding and grasp of CSS selectors and the first layer of specificity.&lt;/p&gt;

&lt;p&gt;I'm genuinely not sure how or whether I can simplify JavaScript in the same way, but for now they both play around with &lt;a href="https://scratch.mit.edu"&gt;Scratch&lt;/a&gt; and I think that's enough for the time being.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://remysharp.com/2020/04/20/how-im-teaching-the-kids-coding-for-the-web"&gt;Remy Sharp's b:log&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>kids</category>
    </item>
    <item>
      <title>Some elements hidden in full screen?</title>
      <dc:creator>Remy Sharp</dc:creator>
      <pubDate>Thu, 09 Apr 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/remy/some-elements-hidden-in-full-screen-20kd</link>
      <guid>https://dev.to/remy/some-elements-hidden-in-full-screen-20kd</guid>
      <description>&lt;p&gt;This is one of those "I spent nearly a day debugging this and I don't want to forget, so I'm writing it here for all eternity*&lt;/p&gt;

&lt;p&gt;&lt;em&gt;* Or as long as I renew the dns…&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&amp;lt;--more--&amp;gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;I had a React based project that had a main "board" view and triggered by the user, a modal would appear. This worked fine during development and though I didn't touch the code around the modal at all, the modal would not appear at all in mobile.&lt;/p&gt;

&lt;p&gt;Why was that?&lt;/p&gt;

&lt;p&gt;One thing I did notice, that eventually helped, was that the modal was only missing in full screen mode and when the website returned to non-full screen, the model would magically appear.&lt;/p&gt;

&lt;h2&gt;
  
  
  Some context
&lt;/h2&gt;

&lt;p&gt;This is a snippet of the code that React boots in the browser. It's not so much that React caused me a problem, but more that with libraries like React, Vue and so on, is that they attach onto a node in the DOM that's not &lt;em&gt;quite&lt;/em&gt; the root (I've suffered this in the past when trying to do a flex 100% wide and tall React app).&lt;/p&gt;

&lt;p&gt;Note that the main board view the visitor sees is in &lt;code&gt;&amp;lt;Game&amp;gt;&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;TableContext.Provider value={this.tableContext}&amp;gt;
  &amp;lt;Helmet&amp;gt;
    &amp;lt;title&amp;gt;{title(table)}&amp;lt;/title&amp;gt;
  &amp;lt;/Helmet&amp;gt;
  &amp;lt;UpdateNotice /&amp;gt;
  &amp;lt;Game {...this.props} /&amp;gt;
  &amp;lt;StandModal table={table} /&amp;gt;
  &amp;lt;CloseWindowModal /&amp;gt;
  &amp;lt;GettingStartedModal /&amp;gt;
&amp;lt;/TableContext.Provider&amp;gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The visitor would then load up the board and they tap "full screen", from thereon in, the modals, like &lt;code&gt;&amp;lt;GettingStartedModal&amp;gt;&lt;/code&gt; is invisible.&lt;/p&gt;

&lt;p&gt;It's in the DOM. In Chrome Canary I could see the modal in the DOM and I when I hovered over I could see devtools highlighting where &lt;em&gt;it should be&lt;/em&gt;, but it wasn't there.&lt;/p&gt;

&lt;p&gt;The modal didn't have any opacity, visibility or anything else funky going on. So, what was it 🤔🤷‍♀️&lt;/p&gt;

&lt;h2&gt;
  
  
  Full screen context
&lt;/h2&gt;

&lt;p&gt;The full screen API and selector applies at a DOM node level. In this case, the DOM node for the &lt;code&gt;&amp;lt;Game&amp;gt;&lt;/code&gt; component was going full screen. The component was designed to stretch across the viewport, so that's the only thing that would be seen when in full screen.&lt;/p&gt;

&lt;p&gt;This meant the full screen context was on the DOM node that was a &lt;em&gt;sibling&lt;/em&gt; of the modal.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The modal would need to be a child of the full screen context.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;So that was it, I need to move the full screen to a higher up element. In the end I hacked about with React's &lt;code&gt;useRef&lt;/code&gt; to make use of &lt;code&gt;document.body&lt;/code&gt; but it certainly had me stumped for almost a day!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://remysharp.com/2020/04/09/some-elements-hidden-in-full-screen"&gt;Remy Sharp's b:log&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>debugging</category>
      <category>webdev</category>
      <category>css</category>
    </item>
    <item>
      <title>Auto-growing inputs</title>
      <dc:creator>Remy Sharp</dc:creator>
      <pubDate>Fri, 06 Mar 2020 10:00:00 +0000</pubDate>
      <link>https://dev.to/remy/auto-growing-inputs-3fmo</link>
      <guid>https://dev.to/remy/auto-growing-inputs-3fmo</guid>
      <description>&lt;p&gt;I was tinkering with an electron app I wanted to make for screencasting and it needed some input elements that were positioned in a very tight spot. As powerful as HTML and CSS is, one weird thing about the &lt;code&gt;input&lt;/code&gt; elements is that they don't (typically) size to their content.&lt;/p&gt;

&lt;p&gt;Then I found a post by &lt;a href="https://github.com/flesler"&gt;Ariel Flesler&lt;/a&gt; from 2013 and with a little tweaking, all of a sudden input elements can size themselves to their content. What's cool (to me), is that I knew Ariel from back in the jQuery hey days (/waves).&lt;/p&gt;

&lt;h2&gt;
  
  
  The effect
&lt;/h2&gt;

&lt;p&gt;As I mentioned, I had a very small amount of space but also I wanted the text in this particualr example to visually close to the next input. The effect can be seen below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--XYKAVlXq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://remysharp.com/images/input-grow.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--XYKAVlXq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://remysharp.com/images/input-grow.gif" alt="Demo of autogrowing inputs"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Prior art
&lt;/h2&gt;

&lt;p&gt;I've come across this problem in the past too. I posted two blog posts some 14 years ago! The first was &lt;a href="https://remysharp.com/2006/11/27/delicious-like-text-grow-jquery-plugin-2"&gt;a full JavaScript solution&lt;/a&gt; to create the effect, more elegantly was the &lt;a href="https://remysharp.com/2006/11/27/auto-input-grow-with-css-but-is-it-a-bug-2"&gt;so called bug in IE&lt;/a&gt;, and IE only, using the following CSS would allow the &lt;code&gt;input&lt;/code&gt; elements to grow to fix their contents:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;input { overflow: visible; }

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;How smart is that? Except it didn't work in any other browser, and it doesn't work today and thus it was quietly snuffed out.&lt;/p&gt;

&lt;p&gt;What I really like about Ariel's solution though is that it requires no JavaScript at all and relies entirely on native features of HTML and CSS.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ariel's auto-grow
&lt;/h2&gt;

&lt;p&gt;Based on Ariel's &lt;a href="https://codepen.io/flesler/pen/AEIFc"&gt;CodePen demo&lt;/a&gt; which original intends to add placeholder support for contenteditable elemenent, I can adjust the code to use a &lt;code&gt;span&lt;/code&gt; (instead of a &lt;code&gt;div&lt;/code&gt;) and add a little CSS to improve upon his work (the CSS came from someone else via StackOverflow and comment on the CodePen demo IIRC).&lt;/p&gt;

&lt;p&gt;The actual technique is frustrating obvious (but only once you know how), it uses &lt;code&gt;contenteditable&lt;/code&gt;. Ariel's demo also shows how to include a placeholder and there's additional CSS that means that new lines are ignored (or more specifically: hidden).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[contenteditable="true"]:empty:before {
  content: "0";
  color: gray;
}

/* prevents the user from being able to make a (visible) newline */
[contenteditable="true"] br {
  display: none;
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The element itself is a &lt;code&gt;span&lt;/code&gt;, so it appears inline and now it's automatically focusable through the keyboard.&lt;/p&gt;

&lt;p&gt;In the demo animation above, I'm binding the keypress event handler to cycle a number up or down within limits I've defined in &lt;code&gt;data-*&lt;/code&gt; attributes, but that's out of scope.&lt;/p&gt;

&lt;p&gt;Like I said, suprisingly obvious once you know it's done using &lt;code&gt;contenteditable&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://remysharp.com/2020/03/06/auto-growing-inputs"&gt;Remy Sharp's b:log&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>css</category>
    </item>
    <item>
      <title>Binary Tools</title>
      <dc:creator>Remy Sharp</dc:creator>
      <pubDate>Fri, 06 Mar 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/remy/binary-tools-1e63</link>
      <guid>https://dev.to/remy/binary-tools-1e63</guid>
      <description>&lt;p&gt;I've been tinkering on a 6502 project during the evenings spread over the last 3 months (via the excellent &lt;a href="https://www.youtube.com/watch?v=LnzuMJLZRdU&amp;amp;list=PLowKtXNTBypFbtuVMUVXNR0z1mu7dp7eH" rel="noopener noreferrer"&gt;Ben Eater&lt;/a&gt; series) and in doing so I've started to build up a series of tools I use with binary.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(This post is probably only useful for future Remy)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I should add that I'm not sure how much of this will work on different systems and availability of tools, but I'll link where possible.&lt;/p&gt;

&lt;h2&gt;
  
  
  hexdump
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.mankier.com/1/hexdump" rel="noopener noreferrer"&gt;hexdump&lt;/a&gt; - usually with &lt;code&gt;hexdump -C file.bin&lt;/code&gt; to view hex and ascii output. Also compresses repeating patterns seen below where the line is simply &lt;code&gt;*&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Really simple to use tool for viewing source hex on the command line.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;hexdump -C rom.bin
00000000 a9 ff 8d 02 60 a9 55 8d 00 60 a9 aa 8d 00 60 4c |....`.U..`....`L|
00000010 05 80 ea ea ea ea ea ea ea ea ea ea ea ea ea ea |................|
00000020 ea ea ea ea ea ea ea ea ea ea ea ea ea ea ea ea |................|
*
00007ff0 ea ea ea ea ea ea ea ea ea ea ea ea 00 80 ea ea |................|
00008000

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  xxd
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.mankier.com/1/xxd" rel="noopener noreferrer"&gt;xxd&lt;/a&gt; can dump hex from binary, but also convert hex to binary.&lt;/p&gt;

&lt;p&gt;This is used for dumping the &lt;em&gt;entire&lt;/em&gt; hex content out. It also has a &lt;em&gt;revert&lt;/em&gt; feature that lets me generate binary files from strings of hex. I've been doing a bit of work around unpacking old file formats, and generating snippet of binary data is useful.&lt;/p&gt;

&lt;p&gt;Below you can see my generating a binary snippet for a ZX Spectrum+ .bas file header. The first column needs to be the offset (&lt;code&gt;0&lt;/code&gt; in this case).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;echo "0 504c 5553 3344 4f53 1a01 00e7 0000 00" | xxd -r | hexdump -C
00000000 50 4c 55 53 33 44 4f 53 1a 01 00 e7 00 00 00 |PLUS3DOS.......|
0000000f

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I could capture this output using &lt;code&gt;… | xxd -r &amp;gt; out.bin&lt;/code&gt; and then process the binary elsewhere.&lt;/p&gt;

&lt;h2&gt;
  
  
  diffing binary / diffing hex
&lt;/h2&gt;

&lt;p&gt;Using &lt;code&gt;xxd&lt;/code&gt; above, I can combine diff tools to identify changes between binary (typically where I've got a typo and generated a slightly different file).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ diff -u &amp;lt;(xxd -c 32 a.bin) &amp;lt;(xxd -c 32 b.bin) | diff-so-fancy

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I'm adding &lt;a href="https://github.com/so-fancy/diff-so-fancy/" rel="noopener noreferrer"&gt;diff-so-fancy&lt;/a&gt; into the mix to clearly highlight the changes in the file (the &lt;code&gt;diff -u&lt;/code&gt; flag is needed to make this work properly).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fremysharp.com%2Fimages%2Fhex-diff.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fremysharp.com%2Fimages%2Fhex-diff.png" alt="Visual hex diff"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the diff above I can clearly see that the first block starts to match, but the does not.&lt;/p&gt;

&lt;h2&gt;
  
  
  Honourable mentions
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.mankier.com/1/od" rel="noopener noreferrer"&gt;od&lt;/a&gt; - very similar to &lt;code&gt;hexdump&lt;/code&gt; and the tool I &lt;em&gt;used&lt;/em&gt; to use to &lt;a href="https://remysharp.com/2018/10/29/shell-debugging-vanishing-text#debugging-invisible-characters" rel="noopener noreferrer"&gt;debug text files for rogue characters&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.mankier.com/1/strings" rel="noopener noreferrer"&gt;strings&lt;/a&gt; - a great little &lt;em&gt;goto&lt;/em&gt; when I'm looking for text inside binary files&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://remysharp.com/2020/03/02/binary-tools" rel="noopener noreferrer"&gt;Remy Sharp's b:log&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>devtools</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
