<?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>Forem: Marco Colli</title>
    <description>The latest articles on Forem by Marco Colli (@collimarco).</description>
    <link>https://forem.com/collimarco</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%2F680276%2Fcd7815b0-3b54-4d9e-a6ec-4d2febe4cd6e.jpeg</url>
      <title>Forem: Marco Colli</title>
      <link>https://forem.com/collimarco</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/collimarco"/>
    <language>en</language>
    <item>
      <title>Building an extremely accurate UTC clock on the web (without trusting the client clock)</title>
      <dc:creator>Marco Colli</dc:creator>
      <pubDate>Tue, 29 Jul 2025 14:49:55 +0000</pubDate>
      <link>https://forem.com/collimarco/building-an-extremely-accurate-utc-clock-on-the-web-without-trusting-the-client-clock-43e0</link>
      <guid>https://forem.com/collimarco/building-an-extremely-accurate-utc-clock-on-the-web-without-trusting-the-client-clock-43e0</guid>
      <description>&lt;p&gt;Displaying &lt;strong&gt;the current UTC time&lt;/strong&gt; in a browser looks trivial, until you care about &lt;strong&gt;accuracy&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Client clocks drift and they are not always a reliable source of information.&lt;/li&gt;
&lt;li&gt;Tabs throttle timers.&lt;/li&gt;
&lt;li&gt;Networks add latency.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Overview
&lt;/h2&gt;

&lt;p&gt;In this post we’ll present a design that:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;fetches authoritative time from your server (not &lt;code&gt;Date.now()&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;uses &lt;code&gt;performance.now()&lt;/code&gt; to track elapsed time with a monotonic clock&lt;/li&gt;
&lt;li&gt;renders instantly and smoothly via &lt;code&gt;requestAnimationFrame()&lt;/code&gt; (no &lt;code&gt;setInterval()&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;compensates for network latency&lt;/li&gt;
&lt;li&gt;handles the real‑world details that make the difference between “pretty good” and “rock solid”.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The algorithm
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Sync:&lt;/strong&gt; Fetch the server’s current UTC.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Adjust for latency:&lt;/strong&gt; Estimate one way latency (≈ RTT/2).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Save a local baseline:&lt;/strong&gt; Record &lt;code&gt;start = performance.now()&lt;/code&gt; at the moment the response arrives.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Simulate time:&lt;/strong&gt; At any later instant, compute
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   estimated_time = server_utc_at_response + one_way_latency + (performance.now() - start)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Render:&lt;/strong&gt; Use &lt;code&gt;requestAnimationFrame(update)&lt;/code&gt; to reflect the current second, updating the DOM only when the displayed second changes. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This yields instant, smooth display with low resource usage (low CPU and network usage). It also gives an exact time with high accuracy (± a few ms).&lt;/p&gt;

&lt;h2&gt;
  
  
  Tips
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;When you need to &lt;strong&gt;measure a time difference&lt;/strong&gt; (e.g. how much time has elapsed from a certain instant) use &lt;code&gt;performance.now()&lt;/code&gt; instead of &lt;code&gt;Date.now()&lt;/code&gt;. It is more accurate and a change in the system clock doesn't affect it.&lt;/li&gt;
&lt;li&gt;A very accurate Round Trip Time (RTT) can be estimated using a &lt;code&gt;PerformanceObserver&lt;/code&gt;. When you need to &lt;strong&gt;measure the RTT&lt;/strong&gt; of the HTTP request don't use a time difference calculated in your code (e.g. &lt;code&gt;timeRequestEnd - timeRequestStart&lt;/code&gt;): that would include some other time that is not relevant in this specific case (like DNS time, connection time, computation time, etc.). Use a &lt;code&gt;PerformanceObserver&lt;/code&gt; instead.&lt;/li&gt;
&lt;li&gt;Don't use &lt;code&gt;setInterval()&lt;/code&gt; to update time or to update the UI (it's not reliable if you need ms precision). Always &lt;strong&gt;use &lt;code&gt;requestAnimationFrame()&lt;/code&gt; to update the UI&lt;/strong&gt;: this allows to update the UI &lt;em&gt;immediately&lt;/em&gt; when there is a time change.&lt;/li&gt;
&lt;li&gt;Remember to &lt;strong&gt;set &lt;code&gt;Cache-Control: no-cache&lt;/code&gt;&lt;/strong&gt; on the time returned by server.&lt;/li&gt;
&lt;li&gt;For styling a digital clock using CSS, &lt;strong&gt;monospace fonts&lt;/strong&gt; (like Roboto Mono) are perfect because when a digit changes, its width doesn't change (so the timer keeps a fixed width).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  See it in action
&lt;/h2&gt;

&lt;p&gt;On &lt;a href="https://timeutc.com" rel="noopener noreferrer"&gt;Time UTC&lt;/a&gt; you can see the algorithm in action and the &lt;a href="https://timeutc.com/app.js" rel="noopener noreferrer"&gt;source code&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>api</category>
    </item>
    <item>
      <title>Web Push Notifications with React and Pushpad</title>
      <dc:creator>Marco Colli</dc:creator>
      <pubDate>Thu, 23 Jan 2025 09:37:39 +0000</pubDate>
      <link>https://forem.com/collimarco/web-push-notifications-with-react-and-pushpad-3el4</link>
      <guid>https://forem.com/collimarco/web-push-notifications-with-react-and-pushpad-3el4</guid>
      <description>&lt;p&gt;In this tutorial we'll see how to easily subscribe a user to web push notifications on a React website. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In particular we build a React component: a button that allows a user to subscribe / unsubscribe from push notifications&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;We'll use the Pushpad SDK to create and manage the push subscription.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup the Pushpad JavaScript SDK
&lt;/h2&gt;

&lt;p&gt;First you need to add a file named &lt;code&gt;service-worker.js&lt;/code&gt; to the root folder of your website. Then add this line of code to that file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;importScripts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://pushpad.xyz/service-worker.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then copy and paste this code to your website:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;u&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;h&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pushpad&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pushpad&lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(){(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pushpad&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;q&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pushpad&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;q&lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="p"&gt;[]).&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;)};&lt;/span&gt;&lt;span class="nx"&gt;h&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementsByTagName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;head&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;script&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="nx"&gt;h&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;);})(&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://pushpad.xyz/pushpad.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nf"&gt;pushpad&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;init&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;PROJECT_ID&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replace &lt;code&gt;PROJECT_ID&lt;/code&gt; with your project ID (you can find it in the project settings in the Pushpad dashboard).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: Pushpad &lt;code&gt;init&lt;/code&gt; will also try to register the &lt;code&gt;service-worker.js&lt;/code&gt; file. If your app already has a service worker and you register it from your custom code, you can skip that by calling &lt;code&gt;pushpad('init', PROJECT_ID, { serviceWorkerPath: null });&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The JavaScript SDK functions
&lt;/h2&gt;

&lt;p&gt;Now the fun part. You can build any UI component (like a subscribe button for push notifications, a custom modal for push notifications, etc.) with your custom style and a few simple methods:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;you can subscribe the user to your notifications and display the native permission prompt for push notifications using &lt;code&gt;pushpad('subscribe')&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;you can get the current push subscription status with &lt;code&gt;pushpad('status')&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;you can unsubscribe the user from push notifications using &lt;code&gt;pushpad('unsubscribe')&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;you can also authenticate your users with &lt;code&gt;pushpad('uid')&lt;/code&gt; or attach other data for targeting with &lt;code&gt;pushpad('tags')&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The React component: a button for web push notifications
&lt;/h2&gt;

&lt;p&gt;This is the React code for building a subscribe / unsubscribe button for web push notifications:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;PushSubscriptionButton&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;subscribed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setSubscribed&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;pushpad&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;status&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isSubscribed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;setSubscribed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isSubscribed&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;subscribe&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;pushpad&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;subscribe&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isSubscribed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isSubscribed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;setSubscribed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Notifications are blocked from browser preferences.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;unsubscribe&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;pushpad&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;unsubscribe&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;setSubscribed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;subscribed&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;subscribed&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;unsubscribe&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;white&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;gray&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nx"&gt;Subscribed&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;white&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;red&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nx"&gt;Subscribe&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code is self-explanatory.&lt;/p&gt;

&lt;p&gt;First it detects if the user is subscribed or not to the push notifications. If the user is not subscribed it display a "Subscribe" button, otherwise, if the user is already subscribed, it displays the text "Subscribed".&lt;/p&gt;

&lt;p&gt;When a user clicks the "Subscribe" button, they will see the browser permission prompt for push notifications: if they accept, they will be subscribed to your website notifications.&lt;/p&gt;

&lt;p&gt;The button will also display the current status (e.g. "Subscribed") and if you click on it again you can also unsubscribe from push notifications.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sending the notifications
&lt;/h2&gt;

&lt;p&gt;Now that you have the subscribers you can send some push notifications. The push notifications are delivered and displayed even when the users are not on your website. For example, if you have a blog, you may want to send a notifications when there is a new post; if you own an e-commerce you can promote the products, etc.&lt;/p&gt;

&lt;p&gt;The easiest way to send the notifications is to use the Pushpad dashboard to &lt;strong&gt;send the notifications manually&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Otherwise you can also &lt;strong&gt;send the notifications from your server-side code using the API&lt;/strong&gt; (Pushpad has some official libraries for Node.js and for other popular languages).&lt;/p&gt;

</description>
      <category>webpush</category>
      <category>notifications</category>
      <category>react</category>
      <category>javascript</category>
    </item>
    <item>
      <title>How to add a custom font to a Rails app</title>
      <dc:creator>Marco Colli</dc:creator>
      <pubDate>Sun, 09 Jul 2023 18:14:05 +0000</pubDate>
      <link>https://forem.com/collimarco/how-to-add-a-custom-font-to-a-rails-app-457l</link>
      <guid>https://forem.com/collimarco/how-to-add-a-custom-font-to-a-rails-app-457l</guid>
      <description>&lt;p&gt;First you need to create the folder &lt;code&gt;app/assets/fonts&lt;/code&gt; if it doesn’t exist yet: this is the default directory for font assets in Rails.&lt;/p&gt;

&lt;p&gt;Then download the font file from GitHub. For example Inter is a great choice and it is already used by many sites and by Tailwind UI. Move the file (e.g. &lt;code&gt;Inter-roman.var.woff2&lt;/code&gt;) in the fonts directory.&lt;/p&gt;

&lt;p&gt;Now you can use the font like a normal asset of the asset pipeline: for example you can use the helpers like &lt;code&gt;asset_path&lt;/code&gt; and &lt;code&gt;font_url&lt;/code&gt; to refer to it.&lt;/p&gt;

&lt;p&gt;In order to use the font in the CSS you need a font face declaration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@font-face {
  font-family: 'Inter var';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: font-url('Inter-roman.var.woff2') format('woff2');
  font-named-instance: 'Regular';
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note the use of the &lt;code&gt;font-url&lt;/code&gt; helper, which is available in SASS files.&lt;/p&gt;

&lt;p&gt;Finally you can use your font:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;body {
  font-family: 'Inter var', sans-serif;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also speed up the loading of the font and avoid the page glitch while the font is loading using &lt;code&gt;&amp;lt;link rel="preload"&amp;gt;&lt;/code&gt;. Add this code to the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; section of the application layout:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;%= preload_link_tag 'Inter-roman.var.woff2' %&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Originally posted on &lt;a href="https://answers.abstractbrain.com/how-to-add-a-custom-font-to-a-rails-app/"&gt;AbstractBrain Answers&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>rails</category>
      <category>webdev</category>
      <category>css</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Cuber is now open source: deploy your apps to K8s with 1 command</title>
      <dc:creator>Marco Colli</dc:creator>
      <pubDate>Wed, 31 Aug 2022 20:52:16 +0000</pubDate>
      <link>https://forem.com/collimarco/cuber-is-now-open-source-deploy-your-apps-to-k8s-with-1-command-2o0a</link>
      <guid>https://forem.com/collimarco/cuber-is-now-open-source-deploy-your-apps-to-k8s-with-1-command-2o0a</guid>
      <description>&lt;p&gt;I am happy to announce that after several months of work, I have decided to release Cuber as open source software:&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--566lAguM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/cuber-cloud"&gt;
        cuber-cloud
      &lt;/a&gt; / &lt;a href="https://github.com/cuber-cloud/cuber-gem"&gt;
        cuber-gem
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      An automation tool that simplify the deployment of your apps on Kubernetes.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;p&gt;&lt;a href="https://cuber.cloud" rel="nofollow"&gt;&lt;img src="https://camo.githubusercontent.com/68a289cb49200ca60231a40a107364e3d9a7e67c85ba16ddcd3c4d9091396b40/68747470733a2f2f63756265722e636c6f75642f6173736574732f696d616765732f6c6f676f2e737667" alt="Cuber" height="80" width="80"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;
CUBER&lt;/h1&gt;
&lt;p&gt;&lt;a href="https://badge.fury.io/rb/cuber" rel="nofollow"&gt;&lt;img src="https://camo.githubusercontent.com/d9a8eca391cbcac4c6df5890c02d3da57102e9774ceef3049fa14176ade6abee/68747470733a2f2f62616467652e667572792e696f2f72622f63756265722e737667" alt="Gem Version"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Deploy your apps on Kubernetes easily.&lt;/p&gt;
&lt;h2&gt;
What is Cuber?&lt;/h2&gt;
&lt;p&gt;Cuber is an automation tool (written in Ruby) that can package and deploy your apps (written in any language and framework) on Kubernetes.&lt;/p&gt;
&lt;p&gt;Unlike other tools that add more options and more complexity to Kubernetes, Cuber is made to simplify and reduce the complexity, thus making the deployment process more standardized and reliable.&lt;/p&gt;
&lt;p&gt;You just need to create a &lt;code&gt;Cuberfile&lt;/code&gt;, with ~10 lines of code, and then type &lt;code&gt;cuber deploy&lt;/code&gt; to package and deploy your app on any Kubernetes cluster.&lt;/p&gt;
&lt;p&gt;Kubernetes is up to 80% cheaper compared to PaaS like Heroku and you can choose between different cloud providers (no lock-in)
It is also reliable and it can scale applications of any size
The only downside is that it's complex and requires many steps and configurations, even if most applications share the same needs
Cuber makes Kubernetes simple and…&lt;/p&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/cuber-cloud/cuber-gem"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Cuber makes it extremely easy to build and deploy an application to Kubernetes.&lt;/p&gt;

&lt;p&gt;We use it for a large monolithic application built in Rails (Pushpad), but it can really deploy any application (any language and framework) that can be deployed to Heroku or that can be built using a Dockerfile.&lt;/p&gt;

&lt;p&gt;Basically you just need to define a &lt;code&gt;Cuberfile&lt;/code&gt;, with a few lines of code that describe your application, and then run &lt;code&gt;cuber deploy&lt;/code&gt; to publish your app on Kubernetes (on any cloud provider).&lt;/p&gt;

&lt;p&gt;You can find more information and documentation on GitHub or on the &lt;a href="https://cuber.cloud"&gt;official website&lt;/a&gt; of the project.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>webdev</category>
      <category>devops</category>
      <category>kubernetes</category>
    </item>
    <item>
      <title>Cuber: a Capistrano alternative for deploying Rails applications on Kubernetes</title>
      <dc:creator>Marco Colli</dc:creator>
      <pubDate>Wed, 13 Jul 2022 12:34:40 +0000</pubDate>
      <link>https://forem.com/collimarco/cuber-a-capistrano-alternative-for-deploying-rails-applications-on-kubernetes-46na</link>
      <guid>https://forem.com/collimarco/cuber-a-capistrano-alternative-for-deploying-rails-applications-on-kubernetes-46na</guid>
      <description>&lt;p&gt;&lt;a href="https://github.com/cuber-cloud/cuber-gem"&gt;Cuber&lt;/a&gt; is an automation and deployment tool written in Ruby: it is similar to Capistrano, but it deploys on Kubernetes, so you don’t need to configure all the servers and it’s more scalable.&lt;/p&gt;

&lt;p&gt;Basically you can deploy your application by defining a &lt;code&gt;Cuberfile&lt;/code&gt; (a few lines of Ruby code, like a Capfile for Capistrano) and then typing &lt;code&gt;cuber deploy&lt;/code&gt; in your terminal.&lt;/p&gt;

&lt;p&gt;Cuber has been designed for monolithic Rails applications, but it can actually deploy any application, in any language and framework.&lt;/p&gt;

&lt;p&gt;It has all the features needed to run an application in production.&lt;/p&gt;

&lt;p&gt;Here’s an example &lt;code&gt;Cuberfile&lt;/code&gt; that you can use to deploy any Rails app on Kubernetes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="s1"&gt;'myapp'&lt;/span&gt;
&lt;span class="n"&gt;repo&lt;/span&gt; &lt;span class="s1"&gt;'.'&lt;/span&gt;
&lt;span class="n"&gt;buildpacks&lt;/span&gt; &lt;span class="s1"&gt;'heroku/buildpacks:20'&lt;/span&gt;
&lt;span class="n"&gt;image&lt;/span&gt; &lt;span class="s1"&gt;'username/myapp'&lt;/span&gt;
&lt;span class="n"&gt;dockerconfig&lt;/span&gt; &lt;span class="s1"&gt;'dockerconfig.json'&lt;/span&gt;
&lt;span class="n"&gt;kubeconfig&lt;/span&gt; &lt;span class="s1"&gt;'kubeconfig.yml'&lt;/span&gt;
&lt;span class="n"&gt;migrate&lt;/span&gt; &lt;span class="s1"&gt;'rails db:migrate'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;check: &lt;/span&gt;&lt;span class="s1"&gt;'rake db:abort_if_pending_migrations'&lt;/span&gt;
&lt;span class="nb"&gt;proc&lt;/span&gt; &lt;span class="ss"&gt;:web&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'bundle exec puma'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;scale: &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;
&lt;span class="nb"&gt;proc&lt;/span&gt; &lt;span class="ss"&gt;:worker&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'bundle exec sidekiq'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;scale: &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;
&lt;span class="n"&gt;cron&lt;/span&gt; &lt;span class="ss"&gt;:mytask&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'@daily'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'rake mytask'&lt;/span&gt;
&lt;span class="n"&gt;env&lt;/span&gt; &lt;span class="s1"&gt;'RAILS_ENV'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'production'&lt;/span&gt;
&lt;span class="n"&gt;env&lt;/span&gt; &lt;span class="s1"&gt;'RAILS_LOG_TO_STDOUT'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'enabled'&lt;/span&gt;
&lt;span class="n"&gt;env&lt;/span&gt; &lt;span class="s1"&gt;'RAILS_SERVE_STATIC_FILES'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'enabled'&lt;/span&gt;
&lt;span class="n"&gt;env&lt;/span&gt; &lt;span class="s1"&gt;'RAILS_MASTER_KEY'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'config/credentials/production.key'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;secret: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. Save that file in a directory (usually your application root), type &lt;code&gt;cuber deploy&lt;/code&gt; and let the magic happen.&lt;/p&gt;

&lt;p&gt;There is also lot of information and technical documentation on &lt;a href="https://cuber.cloud"&gt;the project website&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Finally note that Kubernetes can be 80% cheaper than Heroku or other PaaS, because it is bare infrastructure. Kubernetes is also offered by most cloud providers, and thus you avoid lock-in with a single service provider.&lt;/p&gt;

</description>
      <category>rails</category>
      <category>devops</category>
      <category>kubernetes</category>
    </item>
    <item>
      <title>Cuber is released under a source available license</title>
      <dc:creator>Marco Colli</dc:creator>
      <pubDate>Thu, 28 Apr 2022 15:36:35 +0000</pubDate>
      <link>https://forem.com/collimarco/cuber-is-released-under-a-source-available-license-7am</link>
      <guid>https://forem.com/collimarco/cuber-is-released-under-a-source-available-license-7am</guid>
      <description>&lt;p&gt;I am happy to announce that Cuber is moving from a custom commercial license to a source available license.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--566lAguM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/cuber-cloud"&gt;
        cuber-cloud
      &lt;/a&gt; / &lt;a href="https://github.com/cuber-cloud/cuber-gem"&gt;
        cuber-gem
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      An automation tool that simplify the deployment of your apps on Kubernetes.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;p&gt;&lt;a href="https://cuber.cloud" rel="nofollow"&gt;&lt;img src="https://camo.githubusercontent.com/68a289cb49200ca60231a40a107364e3d9a7e67c85ba16ddcd3c4d9091396b40/68747470733a2f2f63756265722e636c6f75642f6173736574732f696d616765732f6c6f676f2e737667" alt="Cuber" height="80" width="80"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;
CUBER&lt;/h1&gt;
&lt;p&gt;&lt;a href="https://badge.fury.io/rb/cuber" rel="nofollow"&gt;&lt;img src="https://camo.githubusercontent.com/d9a8eca391cbcac4c6df5890c02d3da57102e9774ceef3049fa14176ade6abee/68747470733a2f2f62616467652e667572792e696f2f72622f63756265722e737667" alt="Gem Version"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Deploy your apps on Kubernetes easily.&lt;/p&gt;
&lt;h2&gt;
What is Cuber?&lt;/h2&gt;
&lt;p&gt;Cuber is an automation tool (written in Ruby) that can package and deploy your apps (written in any language and framework) on Kubernetes.&lt;/p&gt;
&lt;p&gt;Unlike other tools that add more options and more complexity to Kubernetes, Cuber is made to simplify and reduce the complexity.&lt;/p&gt;
&lt;p&gt;Kubernetes is up to 80% cheaper compared to PaaS like Heroku and you can choose between different cloud providers (no lock-in)
It is also reliable and it can scale enterprise applications at any size
The only downside is that it's difficult to master
Cuber makes Kubernetes simple!
In this way you have the simplicity of a PaaS, at the cost of bare infrastructure and without the additional cost of a DevOp team.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://cuber.cloud/docs/overview" rel="nofollow"&gt;Read more&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
Installation&lt;/h2&gt;
&lt;p&gt;First you need to &lt;a href="https://cuber.cloud/docs/installation" rel="nofollow"&gt;install the prerequisites&lt;/a&gt;: &lt;code&gt;ruby&lt;/code&gt;, &lt;code&gt;git&lt;/code&gt;, &lt;code&gt;docker&lt;/code&gt;, &lt;code&gt;pack&lt;/code&gt;, &lt;code&gt;kubectl&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Then install Cuber:&lt;/p&gt;
&lt;div class="snippet-clipboard-content position-relative overflow-auto"&gt;…&lt;/div&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/cuber-cloud/cuber-gem"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;In particular we are adopting the &lt;a href="https://github.com/collimarco/Standard-Source-Available-License"&gt;Standard Source Available License (SSAL)&lt;/a&gt; and you can use Cuber for free for small / medium apps.&lt;/p&gt;

&lt;p&gt;Cuber makes it easy to deploy your apps on Kubernetes: just create a &lt;code&gt;Cuberfile&lt;/code&gt;, with ~10 lines of code, and then type &lt;code&gt;cuber deploy&lt;/code&gt; to package and deploy your app on any Kubernetes cluster.&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>opensource</category>
      <category>cloud</category>
    </item>
    <item>
      <title>Why a "Standard Source Available License" doesn't exist yet?</title>
      <dc:creator>Marco Colli</dc:creator>
      <pubDate>Tue, 15 Mar 2022 15:35:18 +0000</pubDate>
      <link>https://forem.com/collimarco/why-a-standard-source-available-license-doesnt-exist-yet-25g9</link>
      <guid>https://forem.com/collimarco/why-a-standard-source-available-license-doesnt-exist-yet-25g9</guid>
      <description>&lt;p&gt;Open source has great advantages, but, often, it is also a way for big corporations to exploit the work of independent developers.&lt;/p&gt;

&lt;p&gt;This is a major issue. Here's some outcomes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Faker&lt;/strong&gt;, &lt;strong&gt;Colors&lt;/strong&gt; and other libraries: tired developers remove the library or voluntarily damage it&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Log4j vulnerability&lt;/strong&gt;, &lt;strong&gt;Heartbleed exploit&lt;/strong&gt;: only 1 or 2 developers were maintaining it&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Nobody should work for free forever: "visibility" doesn't pay the bills.&lt;/p&gt;

&lt;p&gt;There are many videos (&lt;a href="https://www.youtube.com/watch?v=R6S-b_k-ZKY"&gt;video 1&lt;/a&gt;, &lt;a href="https://www.youtube.com/watch?v=FtI055VWhYY"&gt;video 2&lt;/a&gt;) on Youtube that explain the problem with more context.&lt;/p&gt;

&lt;p&gt;What is your opinion about "Source Available" licenses? i.e. a license where source code is public and you can also contribute it, but that gives more power / ownership to the original developer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can "Source Available" licenses solve many of the problems that Open Source has?&lt;/strong&gt; We may release the code, but require a payment above a certain threshold or to use some advanced features (like SaaS).&lt;/p&gt;

&lt;p&gt;Some projects like &lt;strong&gt;Redis modules&lt;/strong&gt; and &lt;strong&gt;Gitlab EE&lt;/strong&gt; already do something similar. However their licenses are complex and non-standard and that may limit the adoption of such projects (i.e. this is even more true for smaller projects). &lt;/p&gt;

&lt;p&gt;I think &lt;strong&gt;it would be useful to create a "Standard Source Available License" that anyone can use for his projects&lt;/strong&gt; (instead of MIT, GPL, etc.)&lt;/p&gt;

&lt;p&gt;A quick idea for brainstorming: take the MIT license (or BSD, or something similar) and add this sentence:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;[...] subject to the following conditions:&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;The purchase of a license may be required in order to use some advanced software features or above certain usage levels. You cannot make modifications to the software made to circumvent license key validations, license-related code or copyright.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This would make it &lt;strong&gt;legally required&lt;/strong&gt; for larger organizations to &lt;strong&gt;buy a sponsorship&lt;/strong&gt; (with the result of happier contributors and well-maintained software).&lt;/p&gt;

&lt;p&gt;Let me know your thoughts below: if I collect enough feedback I can also open a repo on Github and try to write the full-text of the license.&lt;/p&gt;

</description>
      <category>license</category>
      <category>opensource</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Cuber: deploy your apps on Kubernetes easily (Heroku alternative)</title>
      <dc:creator>Marco Colli</dc:creator>
      <pubDate>Mon, 21 Feb 2022 18:18:36 +0000</pubDate>
      <link>https://forem.com/collimarco/cuber-deploy-your-apps-on-kubernetes-easily-heroku-alternative-5j7</link>
      <guid>https://forem.com/collimarco/cuber-deploy-your-apps-on-kubernetes-easily-heroku-alternative-5j7</guid>
      <description>&lt;p&gt;Cuber is an automation tool that makes it easy to publish your applications on Kubernetes. Cuber is a gem written in Ruby, but you can deploy apps in any language and framework.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt; Define a &lt;code&gt;Cuberfile&lt;/code&gt;, run &lt;code&gt;cuber deploy&lt;/code&gt; and you will have your application running on Kubernetes (which is much cheaper than Heroku).&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/cuber-cloud" rel="noopener noreferrer"&gt;
        cuber-cloud
      &lt;/a&gt; / &lt;a href="https://github.com/cuber-cloud/cuber-gem" rel="noopener noreferrer"&gt;
        cuber-gem
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      An automation tool that simplify the deployment of your apps on Kubernetes.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;p&gt;&lt;a href="https://cuber.cloud" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/0b81b69044d48eefecc4d86edfb6ced637050b4c3473bd2dc20a8959f0529a83/68747470733a2f2f63756265722e636c6f75642f6173736574732f696d616765732f6c6f676f2e737667" alt="Cuber" height="80" width="80"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;CUBER&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a href="https://badge.fury.io/rb/cuber" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/164beba09521ad34ec7bbe61f276a298ad9d3e13f074c71f0be0f3d01718679c/68747470733a2f2f62616467652e667572792e696f2f72622f63756265722e737667" alt="Gem Version"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Deploy your apps on Kubernetes easily.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;What is Cuber?&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;Cuber is an automation tool (written in Ruby) that can package and deploy your apps (written in any language and framework) on Kubernetes.&lt;/p&gt;
&lt;p&gt;Unlike other tools that add more options and more complexity to Kubernetes, Cuber is made to simplify and reduce the complexity, thus making the deployment process more standardized and reliable.&lt;/p&gt;
&lt;p&gt;You just need to create a &lt;code&gt;Cuberfile&lt;/code&gt;, with ~10 lines of code, and then type &lt;code&gt;cuber deploy&lt;/code&gt; to package and deploy your app on any Kubernetes cluster.&lt;/p&gt;
&lt;p&gt;Kubernetes is up to 80% cheaper compared to PaaS like Heroku and you can choose between different cloud providers (no lock-in)
It is also reliable and it can scale applications of any size
The only downside is that it's complex and requires many steps and configurations, even if most applications share the same needs...
Cuber makes Kubernetes simple and…&lt;/p&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/cuber-cloud/cuber-gem" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  Why Cuber?
&lt;/h2&gt;

&lt;p&gt;There are already many platforms and tools to publish and run your applications in the cloud:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Heroku is simple, but you get lock-in and high costs when you scale.&lt;/li&gt;
&lt;li&gt;Capistrano works very well, but when you scale on multiple machines you need to manage each of them (and can become a pain when you start having 10+ servers).&lt;/li&gt;
&lt;li&gt;Dokku and other projects are great projects, but they don't have horizontal scalability (you are constrained on a single server).&lt;/li&gt;
&lt;li&gt;Managing servers and infrastructure directly (e.g. use droplets directly on DigitalOcean) is complex and time consuming and it doesn't scale well to tens or hundreds of servers.&lt;/li&gt;
&lt;li&gt;Jenkins, Argo CD, Helm, kustomize and other devops tools for Kubernetes require deep knowledge of Kubernetes and they basically add complexity over complexity.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;... And that's why, after using many of the above solutions, I built Cuber. &lt;/p&gt;

&lt;p&gt;Cuber has the &lt;strong&gt;simplicity&lt;/strong&gt; of a PaaS, like Heroku, while you get the cost of bare infrastructure (i.e. by using Kubernetes, instead of Heroku, you get a &lt;strong&gt;80% cost reduction!&lt;/strong&gt;).&lt;/p&gt;

&lt;p&gt;Also, &lt;strong&gt;you don't have provider lock-in&lt;/strong&gt;, since you can easily move to any Kubernetes provider (e.g. DigitalOcean, Vultr, Google Cloud, AWS, or any other).&lt;/p&gt;

&lt;h2&gt;
  
  
  How it works
&lt;/h2&gt;

&lt;p&gt;You just need to create a &lt;strong&gt;Cuberfile&lt;/strong&gt; for your application (it is somewhat similar to a Procfile for Heroku or a Capfile for Capistrano).&lt;/p&gt;

&lt;p&gt;A Cuberfile is made only of a few lines of code.&lt;/p&gt;

&lt;p&gt;Here's an example for a Rails application:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="s1"&gt;'myapp'&lt;/span&gt;
&lt;span class="n"&gt;repo&lt;/span&gt; &lt;span class="s1"&gt;'.'&lt;/span&gt;
&lt;span class="n"&gt;buildpacks&lt;/span&gt; &lt;span class="s1"&gt;'heroku/buildpacks:20'&lt;/span&gt;
&lt;span class="n"&gt;image&lt;/span&gt; &lt;span class="s1"&gt;'username/myapp'&lt;/span&gt;
&lt;span class="n"&gt;kubeconfig&lt;/span&gt; &lt;span class="s1"&gt;'kubeconfig.yml'&lt;/span&gt;
&lt;span class="nb"&gt;proc&lt;/span&gt; &lt;span class="ss"&gt;:web&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'bundle exec puma'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;scale: &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;
&lt;span class="n"&gt;env&lt;/span&gt; &lt;span class="s1"&gt;'RAILS_ENV'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'production'&lt;/span&gt;
&lt;span class="n"&gt;env&lt;/span&gt; &lt;span class="s1"&gt;'RAILS_LOG_TO_STDOUT'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'enabled'&lt;/span&gt;
&lt;span class="n"&gt;env&lt;/span&gt; &lt;span class="s1"&gt;'RAILS_SERVE_STATIC_FILES'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'enabled'&lt;/span&gt;
&lt;span class="n"&gt;env&lt;/span&gt; &lt;span class="s1"&gt;'RAILS_MASTER_KEY'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'config/credentials/production.key'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;secret: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see we define:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the &lt;strong&gt;name of our application&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;the &lt;strong&gt;Git repo&lt;/strong&gt; (i.e. the location of the Git repo, where to get the source code)&lt;/li&gt;
&lt;li&gt;how to build the application (i.e. in the above example we use automatic builds with &lt;strong&gt;Heroku Buildpacks&lt;/strong&gt;, but we can also provide a Dockerfile if we prefer)&lt;/li&gt;
&lt;li&gt;where the store the Docker image of our application (i.e. the &lt;strong&gt;Docker repository&lt;/strong&gt;)&lt;/li&gt;
&lt;li&gt;the &lt;strong&gt;Kubernetes cluster&lt;/strong&gt; (i.e. where to deploy our application)&lt;/li&gt;
&lt;li&gt;the process to run (i.e. in this case we define the &lt;strong&gt;web server process&lt;/strong&gt;, but we can also add background workers and other custom processes)&lt;/li&gt;
&lt;li&gt;the &lt;strong&gt;environment variables&lt;/strong&gt; and &lt;strong&gt;secrets&lt;/strong&gt; that we want to make available to our running application.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is only a basic example, but you can also add more configurations (e.g. database migrations, ssl, etc.)&lt;/p&gt;

&lt;p&gt;After defining your Cuberfile, you can deploy your application to Kubernetes with a single command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ cuber deploy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command will run a CI/CD pipeline:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Checkout the code from the Git repository&lt;/li&gt;
&lt;li&gt;Build the app using Buildpacks or Docker&lt;/li&gt;
&lt;li&gt;Publish the Docker image in the Docker registry&lt;/li&gt;
&lt;li&gt;Run your app on Kubernetes&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Finally you can see the status of your running application:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ cuber info
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  There's even more
&lt;/h2&gt;

&lt;p&gt;Using Cuber, it's not only simple to deploy an application, but it's simple to maintain it over time.&lt;/p&gt;

&lt;p&gt;When you need to change a configuration, simply edit the &lt;code&gt;Cuberfile&lt;/code&gt; and then type &lt;code&gt;cuber deploy&lt;/code&gt; again.&lt;/p&gt;

&lt;p&gt;You can also run maintenance task directly on your cluster:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ cuber run [yourcommand]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For example with a Rails application you can run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ cuber run rails db:migrate
$ cuber restart
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or you can run interactive shells, for example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ cuber run bash
$ cuber run rails console
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can even see your application logs with a simple command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ cuber logs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Built for production
&lt;/h2&gt;

&lt;p&gt;Cuber is a new project, but it uses the best practices and it is a solid tool meant for production.&lt;/p&gt;

&lt;p&gt;Before creating it I have scaled &lt;a href="https://pushpad.xyz" rel="noopener noreferrer"&gt;Pushpad&lt;/a&gt; to thousands of requests per second and I have written the &lt;a href="https://kubernetes-rails.com" rel="noopener noreferrer"&gt;Kubernetes &amp;amp; Rails Definitive Guide&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Give it a try ;)&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>devops</category>
      <category>tooling</category>
      <category>docker</category>
    </item>
    <item>
      <title>Distributed Q&amp;A for developers</title>
      <dc:creator>Marco Colli</dc:creator>
      <pubDate>Tue, 25 Jan 2022 20:04:50 +0000</pubDate>
      <link>https://forem.com/collimarco/distributed-qa-for-developers-29ma</link>
      <guid>https://forem.com/collimarco/distributed-qa-for-developers-29ma</guid>
      <description>&lt;p&gt;Today I am releasing a new site and I would love to hear your feedback (this is the official release post).&lt;/p&gt;

&lt;p&gt;The name of the project is LinkAnswers and it's a different kind of Q&amp;amp;A for developers:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Write the answers on your domain and then add a link to it.&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Unlike traditional Q&amp;amp;A, we give back to the contributors&lt;/strong&gt; 🥰&lt;br&gt;
&lt;a href="https://linkanswers.com"&gt;https://linkanswers.com&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Anyone can post a question, like a normal Q&amp;amp;A, however you can write the answers on your domain and then add a link to it.&lt;/p&gt;

&lt;p&gt;Basically it's a Q&amp;amp;A that wants to give something back to contributors.&lt;/p&gt;

&lt;p&gt;Personally I am in the top 1% of StackOverflow and despite all the time spent on the site, I get basically nothing from there.&lt;/p&gt;

&lt;p&gt;It would be nice to have at least some visitors and organic traffic to your website... &lt;/p&gt;

&lt;p&gt;In this way you can promote yourself, whether you are an agency, freelancer or SaaS provider. &lt;/p&gt;

&lt;p&gt;So...&lt;/p&gt;

&lt;h2&gt;
  
  
  What is LinkAnswers?
&lt;/h2&gt;

&lt;p&gt;LinkAnswers is a distributed Q&amp;amp;A for developers.&lt;/p&gt;

&lt;p&gt;Unlike a traditional Q&amp;amp;A, you can post the answers on your domain and then add a link to it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why LinkAnswers?
&lt;/h2&gt;

&lt;p&gt;Using LinkAnswers you own the answers that you write and you get more visibility.&lt;/p&gt;

&lt;p&gt;Whether you are a freelancer or a company, you deserve a compensation for helping the community. Your website has your branding and you can show that you are a trustworthy authority and promote your services and products. Showing off your expertise on specific topics can be a great way to gain trust and new customers.&lt;/p&gt;

&lt;p&gt;Currently the most popular Q&amp;amp;A benefit from your contributions (and make big money), but don't give anything back. It's time to create a more balanced ecosystem.&lt;/p&gt;

&lt;p&gt;We also care about creating a more welcoming ecosystem, without downvotes and aggressive moderators.&lt;/p&gt;

&lt;h2&gt;
  
  
  How can I reply to a question?
&lt;/h2&gt;

&lt;p&gt;You can simply write a post on your website and then add a link to it on LinkAnswers.&lt;/p&gt;

&lt;p&gt;The questions are released under a permissive license (CC BY) and you can copy and adapt them if you want. Otherwise you can simply mention the original question with a link: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Question&lt;/strong&gt;: &lt;em&gt;Example question&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You can post your answers on any domain, like a blog (e.g. &lt;code&gt;blog.example.com&lt;/code&gt;) or a dedicated domain (e.g. &lt;code&gt;answers.example.com&lt;/code&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  Do you like this project?
&lt;/h2&gt;

&lt;p&gt;I know that there's still a lot to do, but the basic website is ready and fully functional.&lt;/p&gt;

&lt;p&gt;Please let me know what you think and if you like the idea &lt;a href="https://linkanswers.com/users/sign_up"&gt;sign up now →&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You can also post a question or a link to your answers (on your domain 🎉) right now.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>discuss</category>
      <category>news</category>
    </item>
    <item>
      <title>Favicons in 2022: you only need 1 SVG favicon</title>
      <dc:creator>Marco Colli</dc:creator>
      <pubDate>Tue, 28 Dec 2021 14:57:41 +0000</pubDate>
      <link>https://forem.com/collimarco/1-svg-favicon-is-it-a-dream-559c</link>
      <guid>https://forem.com/collimarco/1-svg-favicon-is-it-a-dream-559c</guid>
      <description>&lt;p&gt;The time has come to end the favicon craziness... Starting from 2022 it makes sense to &lt;strong&gt;use only 1 favicon in SVG format&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Is it a dream? No, it's real. This simple solution works for modern browsers.&lt;/p&gt;

&lt;p&gt;Simply use an &lt;strong&gt;SVG favicon&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;link rel="icon" href="/icon.svg"&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://caniuse.com/link-icon-svg"&gt;Supported by major browsers&lt;/a&gt; (except Safari in 2021) and &lt;a href="https://html.spec.whatwg.org/multipage/links.html#rel-icon"&gt;Living Standard&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Only 1 short line of code and simple to remember&lt;/li&gt;
&lt;li&gt;Other attributes like &lt;code&gt;type&lt;/code&gt; and &lt;code&gt;sizes&lt;/code&gt; are not necessary&lt;/li&gt;
&lt;li&gt;Scales much better at any size compared to PNG&lt;/li&gt;
&lt;li&gt;Let's end the favicon craziness with hundreds of different sizes...&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I have already used this strategy for our latest website (&lt;a href="https://cuber.cloud"&gt;cuber.cloud&lt;/a&gt;) and it works perfectly on Chrome and other major browsers. You can test it yourself. Just 1 favicon for all browsers and all sizes!&lt;/p&gt;

&lt;p&gt;For Apple Safari, the only missing browser, let's ask them to become standard-compliant... (btw, they are becoming the new IE). You can send a tweet to &lt;a href="https://twitter.com/webkit"&gt;@webkit&lt;/a&gt; for feature requests (they suggest that on their official bug tracker).&lt;/p&gt;

</description>
      <category>html</category>
      <category>svg</category>
      <category>favicon</category>
      <category>icon</category>
    </item>
    <item>
      <title>Building a QR code generator with Ruby on Rails</title>
      <dc:creator>Marco Colli</dc:creator>
      <pubDate>Fri, 06 Aug 2021 22:43:50 +0000</pubDate>
      <link>https://forem.com/collimarco/building-a-qr-code-generator-with-ruby-on-rails-28ki</link>
      <guid>https://forem.com/collimarco/building-a-qr-code-generator-with-ruby-on-rails-28ki</guid>
      <description>&lt;p&gt;Today many applications use QR codes.&lt;/p&gt;

&lt;p&gt;QR codes are used for many different purposes, like tickets, restaurant menus, payments, sharing a contact or a URL, etc.&lt;/p&gt;

&lt;p&gt;A QR code may seem magical to non-tech users, but it is actually very simple. &lt;strong&gt;QR codes are simply a different way to write text: instead of using the normal alphabet, that is easily read by humans, we use different signs that are easily read by a machine&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;Since you can write any text inside a QR code, you can also write a URL for example. URLs are one of the most common contents of QR codes. A mobile device that scans a QR code, reads the text, and finds a URL, may decide to open that link.&lt;/p&gt;

&lt;p&gt;For example, if you have a restaurant menu online you can simply take the URL of the menu and convert it into a QR code: in this way users that scan the QR code will open the restaurant menu. That is exactly how a QR code menu works. And indeed this post is based on the work that I have done for &lt;a href="https://buonmenu.com"&gt;BuonMenu&lt;/a&gt;, a QR code menu for restaurants built with Ruby on Rails.&lt;/p&gt;

&lt;h2&gt;
  
  
  The code
&lt;/h2&gt;

&lt;p&gt;We want to build a simple page with Ruby on Rails that given an arbitrary text or a URL as an input, generates the QR code and allows the user to download it.&lt;/p&gt;

&lt;p&gt;First of all create a new Rails application (or open an existing one).&lt;/p&gt;

&lt;p&gt;Then add &lt;a href="https://github.com/whomwah/rqrcode"&gt;this gem&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Gemfile&lt;/span&gt;

&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;'rqrcode'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And run &lt;code&gt;bundle install&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Then create these routes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# config/routes.rb&lt;/span&gt;

&lt;span class="n"&gt;controller&lt;/span&gt; &lt;span class="ss"&gt;:pages&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;get&lt;/span&gt; &lt;span class="ss"&gt;:qr_code_generator&lt;/span&gt;
  &lt;span class="n"&gt;get&lt;/span&gt; &lt;span class="ss"&gt;:qr_code_download&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then the controller:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# app/controllers/pages_controller.rb&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PagesController&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationController&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;qr_code_generator&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;qr_code_download&lt;/span&gt;
    &lt;span class="n"&gt;send_data&lt;/span&gt; &lt;span class="no"&gt;RQRCode&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;QRCode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:content&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;to_s&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;as_png&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;size: &lt;/span&gt;&lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="ss"&gt;type: &lt;/span&gt;&lt;span class="s1"&gt;'image/png'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;disposition: &lt;/span&gt;&lt;span class="s1"&gt;'attachment'&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the code of the view:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight erb"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;%# app/views/pages/qr_code_generator.html.erb %&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;QR code generator&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;

&lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;form_tag&lt;/span&gt; &lt;span class="ss"&gt;:qr_code_download&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;method: :get&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"field"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;label_tag&lt;/span&gt; &lt;span class="s1"&gt;'Text or URL'&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
    &lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;text_field_tag&lt;/span&gt; &lt;span class="ss"&gt;:content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kp"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;required: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"actions"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;submit_tag&lt;/span&gt; &lt;span class="s1"&gt;'Generate QR code'&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Basically the view is to display a form where the user can add his text or URL and then it sends a request to &lt;code&gt;qr_code_download&lt;/code&gt; which actually generates a PNG for the QR code. The QR code will be downloaded on the user device since we use &lt;code&gt;disposition: 'attachment'&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Finally, if we prefer to display the QR code instead of downloading it, we can use a method similar to &lt;code&gt;qr_code_download&lt;/code&gt; but with &lt;code&gt;disposition: 'inline'&lt;/code&gt;.&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>rails</category>
      <category>qrcode</category>
    </item>
  </channel>
</rss>
