<?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: Eyuel Berga Woldemichael</title>
    <description>The latest articles on DEV Community by Eyuel Berga Woldemichael (@eyuelberga).</description>
    <link>https://dev.to/eyuelberga</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%2F402602%2Fe1603fb9-467d-4f37-9b02-91d7b3b5c1e8.jpg</url>
      <title>DEV Community: Eyuel Berga Woldemichael</title>
      <link>https://dev.to/eyuelberga</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/eyuelberga"/>
    <language>en</language>
    <item>
      <title>Develop a Cryptocurrency Tracking WebApp with Instant Email Notifications</title>
      <dc:creator>Eyuel Berga Woldemichael</dc:creator>
      <pubDate>Wed, 18 Jan 2023 15:07:11 +0000</pubDate>
      <link>https://dev.to/eyuelberga/develop-a-cryptocurrency-tracking-webapp-with-instant-email-notifications-4k59</link>
      <guid>https://dev.to/eyuelberga/develop-a-cryptocurrency-tracking-webapp-with-instant-email-notifications-4k59</guid>
      <description>&lt;p&gt;
  &lt;a href="https://www.youtube.com/watch?v=a-kGJ8-OU2A" rel="noopener noreferrer"&gt;
    &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimg.youtube.com%2Fvi%2Fa-kGJ8-OU2A%2F0.jpg" alt="CryptoTrack"&gt;
  &lt;/a&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Background
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/eyuelberga/CryptoTrack/" rel="noopener noreferrer"&gt;Crypto Track&lt;/a&gt; is a web application to help track market changes on your favorite cryptocurrency and receive instant email notifications. Cryptocurrency use is rapidly expanding, and many people are putting their money and resources into it. However, its volatility sets it apart from other assets. Even though staying current with market trends might be time-consuming, there are also considerable benefits to doing so. Crypto Track essentially aims to make this a lot easier by notifying subscribers when the desired change is reflected on the market. &lt;/p&gt;

&lt;p&gt;&lt;a href="http://courier.com/" rel="noopener noreferrer"&gt;Courier&lt;/a&gt; is ideal for this kind of application since it makes it simple to integrate notification systems. We will be using the Courier API to send email notifications for now, but it is quite easy to extend it to use SMS or other communication channels.&lt;/p&gt;

&lt;p&gt;We will also be using &lt;a href="https://supabase.com/" rel="noopener noreferrer"&gt;Supabase&lt;/a&gt;, an open-source alternative to firebase with a built-in database and authentication system. We will use &lt;a href="https://reactjs.org/" rel="noopener noreferrer"&gt;React&lt;/a&gt; for building out the front end and &lt;a href="https://chakra-ui.com/" rel="noopener noreferrer"&gt;Chakra-UI&lt;/a&gt; for styling our React components. We will also set up a cron job that calls a webhook (that we will be building using &lt;a href="https://expressjs.com/" rel="noopener noreferrer"&gt;Express&lt;/a&gt;). We will also use the &lt;a href="https://www.coingecko.com/" rel="noopener noreferrer"&gt;CoinGecko&lt;/a&gt; API to fetch the latest cryptocurrency market data. &lt;/p&gt;

&lt;p&gt;I know that's a lot! But if you have a working knowledge of Javascript, React, and have worked with APIs in the past, you can easily follow along.&lt;/p&gt;

&lt;h2&gt;
  
  
  Instructions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Quick Overview
&lt;/h3&gt;

&lt;p&gt;Let’s start with a quick overview of what we will be building. We have a web application with authentication. After login, users are presented with a simple form for subscribing to notifications. The form has options for selecting the market data metrics, the cryptocurrency, and when to be notified, by choosing a target value and the change(whether the current market data is greater than or less than the specified target value).  There is also a section to manage notifications. Here users can see all subscribed notifications and also have the option to remove them. &lt;/p&gt;

&lt;p&gt;On the backend, we have Supabase, CoinGecko, and Courier working together. Authentication and data storage is handled in Supabase. We also have scheduled webhook calls to fetch the latest market data and notify subscribers using the Courier API. &lt;/p&gt;

&lt;p&gt;Now that you have a general idea of what we will be building, let's get right to it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Part 1: Setting Up Courier
&lt;/h3&gt;

&lt;p&gt;Go to the "Channels" page after signing into your Courier account. We need to configure an email provider of choice. Let’s go with Gmail. Once that is done, the email provider should appear under "Configured Providers."&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Channels and providers are important features of the Courier API. You can read more about them &lt;a href="https://help.courier.com/en/articles/4196354-what-are-channels-and-integrations" rel="noopener noreferrer"&gt;in this article&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foqc9jl1d97xv904a0500.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foqc9jl1d97xv904a0500.png" alt="Courier Configured email"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We then need to head over to the ‘Designer’ and create a new brand with the Crypto Track logo and theme colors. All emails that are sent will have this in the header and footer.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The Notification Designer allows us to create notification templates througn a nice GUI. You can read more about the designer &lt;a href="https://www.courier.com/docs/courier-designer/notification-designer/notification-designer-overview/" rel="noopener noreferrer"&gt;here&lt;/a&gt; and also more about brands is avaliable on the &lt;a href="https://www.courier.com/docs/courier-designer/brands/how-to-use-brands-to-customize/" rel="noopener noreferrer"&gt;docs&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwmimfy14q4pxj30febcr.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwmimfy14q4pxj30febcr.png" alt="Courier Brand"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, we will create our notification template. We will use the brand we create earlier here. Additionally, we will enclose the dynamic portions of the message inside curly braces so that they may be filled out later on during our API call.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbxq1ejezks65d9kfxqdp.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbxq1ejezks65d9kfxqdp.png" alt="Courier Notification Template"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Part 2: Creating a Supabase Project
&lt;/h3&gt;

&lt;p&gt;Head over to the &lt;a href="https://supabase.com/" rel="noopener noreferrer"&gt;Supabase website&lt;/a&gt; and log in to your account(or create a new account if don’t have one). We are going to create a new project named ‘Crypto Track’. &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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1uk4oktgyyjg9oyj8z8h.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1uk4oktgyyjg9oyj8z8h.png" alt="Supabase new project"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Configure Email Auth Provider
&lt;/h4&gt;

&lt;p&gt;By default, the email Auth provider is enabled but we need to make sure the site URL and redirect URLs are pointing to our dev server running on localhost.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnk9i3kqocv4gl7hru5bu.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnk9i3kqocv4gl7hru5bu.png" alt="Supabase auth provider settings"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Creating Database Tables
&lt;/h4&gt;

&lt;p&gt;We need to create two tables, the first one ‘notifications’ is for storing the subscription information for users and the other ‘snapshot’ is for saving the most recent market data to enable us to send notifications only when there is a significant change(we will talk about this in more detail later). Let’s use Table Editor to create the tables. Head over to the ‘Table Editor’ page and click on ‘New Table’.&lt;/p&gt;

&lt;p&gt;First, we will create the notifications table. The table below summarises all the columns along with a description: &lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Column&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Primary&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;email&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The email address of the user&lt;/td&gt;
&lt;td&gt;text&lt;/td&gt;
&lt;td&gt;Primary&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;coin&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The cryptocurrency to track&lt;/td&gt;
&lt;td&gt;text&lt;/td&gt;
&lt;td&gt;Primary&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;metric&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The market metric to track&lt;/td&gt;
&lt;td&gt;text&lt;/td&gt;
&lt;td&gt;Primary&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;change&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The change to track(true for greater than or false for less than)&lt;/td&gt;
&lt;td&gt;boolean&lt;/td&gt;
&lt;td&gt;Primary&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;value&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The target value to compare with the latest market data&lt;/td&gt;
&lt;td&gt;numeric&lt;/td&gt;
&lt;td&gt;Primary&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;created_at&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Date created&lt;/td&gt;
&lt;td&gt;timestamptz&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;updated_at&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Date updated&lt;/td&gt;
&lt;td&gt;timestamptz&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;You may have noticed that we have more than one primary key; we create a Composite primary key by combining the five columns to uniquely identify each row in the table so that users don’t subscribe to the same notification twice.&lt;/p&gt;
&lt;/blockquote&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbne2wo6i897k4xtzdas7.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbne2wo6i897k4xtzdas7.png" alt="Supabase notifications table"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is how the table definition should look like in our Table Editor. Be sure to check the box to 'Enable Row Level Security (RLS)', we will use it later to create the table's authorization rules.&lt;/p&gt;

&lt;p&gt;Next up is the ‘snapshots’ table. This table holds a recent snapshot of the market data for a cryptocurrency.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Column&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Primary&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;id&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The cryptocurrency&lt;/td&gt;
&lt;td&gt;text&lt;/td&gt;
&lt;td&gt;Primary&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;price_change_24h&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The price change in 24 hours&lt;/td&gt;
&lt;td&gt;numeric&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;price_change_percentage_24h&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The price change percentage in 24 hours&lt;/td&gt;
&lt;td&gt;numeric&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;price_change_percentage_1h_in_currency&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The price change percentage in one-hour&lt;/td&gt;
&lt;td&gt;numeric&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;current_price_market_cap_change_24h&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The market cap price change in 24 hours&lt;/td&gt;
&lt;td&gt;numeric&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ath_change_percentage&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;All-time high change in percentage&lt;/td&gt;
&lt;td&gt;numeric&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;atl_change_percentage&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;All-time low change in percentage&lt;/td&gt;
&lt;td&gt;numeric&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;market_cap_change_percentage_24h&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Market cap change percentage in 24 hours&lt;/td&gt;
&lt;td&gt;numeric&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;created_at&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Date created&lt;/td&gt;
&lt;td&gt;timestamptz&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;updated_at&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Date updated&lt;/td&gt;
&lt;td&gt;timestamptz&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8tqtkqn6sio1g0dsoxt8.jpg" 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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8tqtkqn6sio1g0dsoxt8.jpg" alt="Supabase snapshots table"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Securing Data Access using Row-Level Security
&lt;/h4&gt;

&lt;p&gt;We will need to add authorization rules to the notifications table so that users can only access and modify their data. We do this by adding a Row-level security policy to the table. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;RLS is a feature that allows restricting access to rows in a table, you can read more about it &lt;a href="https://supabase.com/docs/learn/auth-deep-dive/auth-row-level-security" rel="noopener noreferrer"&gt;here&lt;/a&gt;. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Navigate to ‘Authentication’ page and then ‘Policies’. Create a new policy on the notifications table by selecting the ‘Create a policy from scratch option.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzuwff5woz9jcdlofq3mz.jpg" 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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzuwff5woz9jcdlofq3mz.jpg" alt="Supabase create policy from scratch"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We will create a custom policy for &lt;code&gt;ALL&lt;/code&gt; operations that will only allow reading and modifying notifications with the same email value as the authenticated user's email. We will use this for code for both the &lt;code&gt;USING&lt;/code&gt; and &lt;code&gt;WITH CHECK&lt;/code&gt; expression:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
auth.email() = email

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

&lt;/div&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw1mmp5x7a4zs63gpqe7i.jpg" 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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw1mmp5x7a4zs63gpqe7i.jpg" alt="Supabase create policy"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Part 3: The Web Frontend
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Initializing a new project using Vite
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://vitejs.dev/" rel="noopener noreferrer"&gt;Vite&lt;/a&gt; is a build tool for frontend applications, we will be using it to set up our React development server. Run this command to create a new project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;yarn create vite crypto-track &lt;span class="nt"&gt;--template&lt;/span&gt; react

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

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;The command above uses yarn but if you prefer to use npm or pnpm you can substitute that. You can find more info on that on the Vite &lt;a href="https://vitejs.dev/guide/" rel="noopener noreferrer"&gt;Getting Started&lt;/a&gt; page.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After that, we need to add a couple of packages to our newly created project. Make sure you are at the root of the project folder before running the commands below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;yarn add @supabase/supabase-js @chakra-ui/react @emotion/react @emotion/styled framer-motion

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

&lt;/div&gt;



&lt;p&gt;We install the &lt;a href="https://github.com/supabase/supabase-js" rel="noopener noreferrer"&gt;Supabase client library&lt;/a&gt; and also &lt;a href="https://chakra-ui.com/" rel="noopener noreferrer"&gt;Chakra-UI&lt;/a&gt; which we will be using to build our React components. &lt;/p&gt;

&lt;h4&gt;
  
  
  Creating our React Components
&lt;/h4&gt;

&lt;p&gt;Let’s start by modifying the &lt;code&gt;main.js&lt;/code&gt; file. We need to wrap our main component with the &lt;code&gt;ChakraProvider&lt;/code&gt; to use Chakra-UI components in our app. Here is what our &lt;code&gt;main.js&lt;/code&gt; file should look like now.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;ReactDOM&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-dom/client&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ChakraProvider&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@chakra-ui/react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./App&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="nx"&gt;ReactDOM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createRoot&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="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;root&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;StrictMode&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ChakraProvider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;App&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;ChakraProvider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;StrictMode&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;We will initialize the Supabase client inside our &lt;code&gt;App.jsx&lt;/code&gt; file. Before that, we need to set two environment variables. Create a &lt;code&gt;.env&lt;/code&gt; file at the root of the project folder and add the following values:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;VITE_SUPABASE_URL=?
VITE_SUPABASE_KEY=?

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

&lt;/div&gt;



&lt;p&gt;We get these values from the project Settings page on the API tab. The &lt;code&gt;VITE_SUPABASE_KEY&lt;/code&gt; is the anon public key, which is displayed in the Project API keys section.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwjqm9zrvkx70h8b7ai3k.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwjqm9zrvkx70h8b7ai3k.png" alt="Supabase API settings"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then we will add an &lt;code&gt;onAuthStateChange&lt;/code&gt; listener, that will check if the user is authenticated and display either the &lt;code&gt;Home&lt;/code&gt; component or the &lt;code&gt;Auth&lt;/code&gt; component. We are using the &lt;code&gt;useState&lt;/code&gt; and &lt;code&gt;useEffects&lt;/code&gt; hooks here, you can find more details on them on the &lt;a href="https://beta.reactjs.org/apis/react" rel="noopener noreferrer"&gt;React Docs&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&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;supabaseUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;VITE_SUPABASE_URL&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;supabaseKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;VITE_SUPABASE_KEY&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;supabase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;supabaseUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;supabaseKey&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;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setUser&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;supabase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;session&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nf"&gt;setUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;user&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="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;authListener&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;supabase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onAuthStateChange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;session&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="nx"&gt;currentUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nf"&gt;setUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currentUser&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="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return &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="nx"&gt;authListener&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;unsubscribe&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="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;

    &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Auth&lt;/span&gt; &lt;span class="na"&gt;supabase&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;supabase&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Home&lt;/span&gt; &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;supabase&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;supabase&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;


  &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;We haven’t created those two components yet, so let’s start with the &lt;code&gt;Auth&lt;/code&gt; component. In the &lt;code&gt;Auth&lt;/code&gt; component we want to handle user login and signup. We will be using the Supabase client here, which we receive from the &lt;code&gt;App&lt;/code&gt; component as a prop(you can read more about props &lt;a href="https://beta.reactjs.org/learn/passing-props-to-a-component" rel="noopener noreferrer"&gt;here&lt;/a&gt;). Basically, we will be calling the &lt;code&gt;auth.Signup&lt;/code&gt; and &lt;code&gt;auth.SignIn&lt;/code&gt; methods to authenticate the user. We will also use some Chakra-UI components to build out the page.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;supabase&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;handleSignInMagicLink&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&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;error&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;supabase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;signIn&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;email&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="nf"&gt;handleError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&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="s2"&gt;We have sent you a magic link. Please check your email inbox.&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleSignIn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&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;error&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;supabase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;signIn&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;email&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;password&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="nf"&gt;handleError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&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;handleSignUp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&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="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;supabase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;signUp&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;email&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;password&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="nf"&gt;handleError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&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="s2"&gt;We have sent you a confirmation email. Please check your inbox.&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;The whole code is a bit long to include here, but you can find the full version on &lt;a href="https://github.com/eyuelberga/CryptoTrack/blob/main/web/src/Auth.jsx" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is what the rendered &lt;code&gt;Auth&lt;/code&gt; component looks like:&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F92fbbcg6rp6m1kjbm95g.jpg" 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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F92fbbcg6rp6m1kjbm95g.jpg" alt="Frontend auth page"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next up is the &lt;code&gt;Home&lt;/code&gt; component. The Home page has four sub-components:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A form to create a notification (&lt;code&gt;Create.jsx&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;A component to display a notification (&lt;code&gt;Notification.jsx&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;A component to hold a list of notifications (&lt;code&gt;NotificationList.jsx&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;A component to display current cryptocurrency market data (&lt;code&gt;DataDisplay.jsx&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fttbkaxwc77act3xmh05z.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fttbkaxwc77act3xmh05z.png" alt="Frontend home page"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We place them all in folder named &lt;code&gt;components&lt;/code&gt;. These are presentational components, so they don’t have any complex logic. You can check them out &lt;a href="https://github.com/eyuelberga/CryptoTrack/tree/main/web/src/components" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We handle all the logic for creating notifications and fetching active subscriptions on the &lt;code&gt;Home&lt;/code&gt; component using the Supabase client.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleCreate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&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="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;preventDefault&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;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;FormData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&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;payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;coin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;coin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="na"&gt;metric&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;metric&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;parseFloat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;value&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
            &lt;span class="na"&gt;change&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;change&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;+&lt;/span&gt;&lt;span class="dl"&gt;"&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="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="nf"&gt;setLoading&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="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;supabase&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&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&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="nf"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
        &lt;span class="nf"&gt;setLoading&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="nf"&gt;handleError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nf"&gt;setNotifications&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;prev&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="nx"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;res&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;loadNotifications&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &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;setNotificationLoading&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="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;supabase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&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&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nf"&gt;handleError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;setNotifications&lt;/span&gt;&lt;span class="p"&gt;([...&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
        &lt;span class="nf"&gt;setNotificationLoading&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We also handle displaying the latest cryptocurrency market data by calling the &lt;a href="https://www.coingecko.com/en/api/documentation" rel="noopener noreferrer"&gt;CoinGecko API&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;onShowCryptoData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&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;setDataLoading&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="k"&gt;try&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;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`https://api.coingecko.com/api/v3/coins/markets?vs_currency=usd&amp;amp;ids=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;amp;price_change_percentage=1h`&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;list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="nf"&gt;setMarketData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;list&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="nf"&gt;onOpen&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&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="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="nf"&gt;setDataLoading&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;You can see the complete source-code from the &lt;code&gt;Home&lt;/code&gt; component on &lt;a href="https://github.com/eyuelberga/CryptoTrack/blob/main/web/src/Home.jsx" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Part 4: Setting Up a Scheduled Webhook
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Creating a Webhook
&lt;/h4&gt;

&lt;p&gt;We will now need to create a webhook that will fetch the latest market data and notify subscribers. But we also want it to run periodically so that users don’t miss anything. To do that, we will extend the Postgres database hosted on Supabase to act as a &lt;a href="https://supabase.com/blog/postgres-as-a-cron-server" rel="noopener noreferrer"&gt;CRON server&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let’s get started by creating our webhook. First, we need to create a new Nodejs project. Create a new folder called &lt;code&gt;cron&lt;/code&gt;, and run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;yarn init &lt;span class="nt"&gt;-y&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Next, we add our dependencies. We want the server to run on Express(&lt;a href="https://expressjs.com/" rel="noopener noreferrer"&gt;https://expressjs.com/&lt;/a&gt;) so we will add that and also the &lt;a href="https://www.npmjs.com/package/@trycourier/courier" rel="noopener noreferrer"&gt;Courier Javascript client&lt;/a&gt;, the Supabase Javascript client and &lt;a href="https://www.npmjs.com/package/axios" rel="noopener noreferrer"&gt;axios&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ yarn add  @supabase/supabase-js @trycourier/courier axios

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

&lt;/div&gt;



&lt;p&gt;We need to get our authorization token to set up the Courier client. You can get this token from the Notification details page.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F973wvdoymlx8e8feltfj.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F973wvdoymlx8e8feltfj.png" alt="Courier Notification Detail"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After retrieving our token we can create an instance of our Courier client:&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;CourierClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@trycourier/courier&lt;/span&gt;&lt;span class="dl"&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;courier&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;CourierClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;authorizationToken&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;COURIER_KEY&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;courier&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are a lot of utility functions we need to create for working with the Supabase database and also fetching latest market data. You can see all of them on &lt;a href="https://github.com/eyuelberga/CryptoTrack/tree/main/cron/src" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;. The most important one we need to focus on is the &lt;code&gt;notification.js&lt;/code&gt; file. This holds the logic for how we notify new market changes to subscribers and send emails using the Courier API. &lt;/p&gt;

&lt;p&gt;The main function here is &lt;code&gt;notify&lt;/code&gt;:&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;notify&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;supabase&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="c1"&gt;// get all notifications&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;notifications&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getAllfromTable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;supabase&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;notifications&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// get unique coins from the notification and load market data &lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;coins&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getUniqueCoins&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;notifications&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;marketData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getLatestMarketData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;coins&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// create a lookup for market data&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;marketLookup&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createLookup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;marketData&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// get previous snapshot of market data&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;snapshots&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getAllfromTable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;supabase&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;snapshots&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// create a lookup for snapshot data&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;snapshotLookup&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createLookup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;coin&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;snapshots&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// iterate over all notifications and evaluate if email should be sent&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;emails&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
    &lt;span class="k"&gt;for &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;notification&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;notifications&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;email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;shouldNotifyChange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;notification&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;marketLookup&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;snapshotLookup&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;email&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;emails&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;email&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// take new snapshot of market data&lt;/span&gt;
    &lt;span class="nf"&gt;updateSnapshot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;supabase&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;marketData&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;requests&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
    &lt;span class="k"&gt;for &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;email&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;emails&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;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;sendEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;requests&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;id&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;requests&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;



&lt;p&gt;On the &lt;code&gt;notify&lt;/code&gt; function,  we are fetching all notifications, snapshots and latest market data. Then we evaluate if a notification should be sent by calling the &lt;code&gt;shouldNotify&lt;/code&gt; method, if so we add the subscription information to a list. We then go over this list and call the &lt;code&gt;sendEmail&lt;/code&gt; method to notify subscribers about the latest market change. We also take a new snapshot of the market data and save it to the database.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;shouldNotify&lt;/code&gt; function is where we determine if we need to notify the user about the latest market change.&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="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;shouldNotifyChange&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;notification&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;marketLookup&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;snapshotLookup&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;metric&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;change&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;coin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;notification&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// get latest market data for coin&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;latestData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;marketLookup&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;coin&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

    &lt;span class="c1"&gt;// skip if latest data not found&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;latestData&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;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// get snapshot data for coin&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;snapshotData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;snapshotLookup&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;coin&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="c1"&gt;// check if the change has not already been notified&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;snapshotData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// get value from snapshot &lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;snapshotValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;snapshotData&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;metric&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;snapshotValue&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="nf"&gt;compareChange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;snapshotValue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;change&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;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// get the requested metric value&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;latestValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;latestData&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;metric&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

    &lt;span class="c1"&gt;// check if it should be notified  &lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nf"&gt;compareChange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;latestValue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;change&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;false&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;valueSuffix&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;metric&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;percentage&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;%&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;USD&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;metric&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MetricMap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;metric&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="na"&gt;targetValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;valueSuffix&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;latestValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;latestValue&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;valueSuffix&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;change&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;changeMap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;change&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="na"&gt;coin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;latestData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&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;Here we check if the latest market change is what the user wants to be notified. By comparing  with the snapshot data, we also ensure that the user won't get notified if the change has already been notified.&lt;/p&gt;

&lt;p&gt;We use the Courier API on the &lt;code&gt;sendEmail&lt;/code&gt; function to send email 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;sendEmail&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;metric&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;targetValue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;latestValue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;change&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;coin&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;requestId&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;CourierClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="na"&gt;channels&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;email&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="na"&gt;override&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="na"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`New update on the &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;metric&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; of &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;coin&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&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="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;REPLACE-WITH-YOUR-TEMPLATE-ID&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;metric&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="nx"&gt;targetValue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="nx"&gt;latestValue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="nx"&gt;change&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="nx"&gt;coin&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;return&lt;/span&gt; &lt;span class="nx"&gt;requestId&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;blockquote&gt;
&lt;p&gt;One thing to note here is, the &lt;code&gt;template&lt;/code&gt; field should match the Notification template ID we created earlier, which you can find on the details page. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now that we have defined all our notification logic, we will create our express app on the &lt;code&gt;index.js&lt;/code&gt; 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="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;cors&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cors&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;SupabaseClient&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./supabase.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;notify&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./notification.js&lt;/span&gt;&lt;span class="dl"&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;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;express&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;cors&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&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="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;try&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;emails&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;notify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;SupabaseClient&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;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;success&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;emails&lt;/span&gt; &lt;span class="p"&gt;}));&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;error&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;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&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;PORT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PORT&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;5000&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;PORT&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="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Running on port &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;PORT&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&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;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Sending a post request to the root route will call the &lt;code&gt;notify&lt;/code&gt; method to send emails to  subscribes if there is a desired change in the market.&lt;/p&gt;

&lt;h4&gt;
  
  
  Postgers CRON Server
&lt;/h4&gt;

&lt;p&gt;Connecting our webhook to our Postgres cron server is the last step. Two extensions must first be added to our Postgres database. Run the following scripts to add the "http" and "pg cron" extensions in the SQL editor on the Supabase project dashboard:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
create extension if not exists http;
create extension if not exists pg_cron;

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

&lt;/div&gt;



&lt;p&gt;After completing that, we can configure our webhook to be called periodically. But in order for the webhook to be accessible by our Postgres cron server, we either need to deploy it or use a service like &lt;a href="https://ngrok.com" rel="noopener noreferrer"&gt;ngrok&lt;/a&gt;. Then we can run the script below to set up a cron job that runs every minute:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
select
  cron.schedule(
    'market-data', 
    '* * * * *',
    $$
    select status
    from
       http_post(
        'https://my-crypto-track-webhook.url/',
        '{}', -- payload
        'application/json'
      )
    $$
  );


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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusions
&lt;/h2&gt;

&lt;p&gt;And we are done, I hope you enjoyed this tutorial. Courier provides an easy way to handle notifications through different channels seamlessly, it is developer-friendly and has a comprehensive documentation. This project was done as part of the &lt;a href="http://courier-hacks.devpost.com/" rel="noopener noreferrer"&gt;Courier Hacks&lt;/a&gt; hackathon and due to time limitations, I focused only in including email notifications. I encourage you to integrate more channels to Crypto Track like SMS, Discord and send a Pull Request to the &lt;a href="https://github.com/eyuelberga/CryptoTrack" rel="noopener noreferrer"&gt;Github Repo&lt;/a&gt;. You can find the full source code on &lt;a href="https://github.com/eyuelberga/CryptoTrack/" rel="noopener noreferrer"&gt;Github&lt;/a&gt; and also check about the demo &lt;a href="https://eyuelberga.github.io/CryptoTrack/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  About the Author
&lt;/h2&gt;

&lt;p&gt;Eyuel is a software developer currently living in Boston. He has worked with various web frameworks and has extensive knowledge of JavaScript. He is also passionate about open-source and writes technical articles on software development.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick Links
&lt;/h2&gt;

&lt;p&gt;🔗 &lt;a href="https://www.courier.com/docs/" rel="noopener noreferrer"&gt;Courier Docs&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🔗 &lt;a href="https://supabase.com/blog/postgres-as-a-cron-server" rel="noopener noreferrer"&gt;Postgres as CRON server&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;🔗 &lt;a href="https://www.coingecko.com/en/api/" rel="noopener noreferrer"&gt;CoinGecko API&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🔗 &lt;a href="https://chakra-ui.com/docs" rel="noopener noreferrer"&gt;Chakra-UI Docs&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🔗 &lt;a href="https://supabase.com/" rel="noopener noreferrer"&gt;Supabase&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>webdev</category>
      <category>tutorial</category>
      <category>node</category>
    </item>
    <item>
      <title>3 Things You Should Know about Memoization in React</title>
      <dc:creator>Eyuel Berga Woldemichael</dc:creator>
      <pubDate>Mon, 31 Jan 2022 11:14:32 +0000</pubDate>
      <link>https://dev.to/eyuelberga/3-things-you-should-know-about-memoization-in-react-10ke</link>
      <guid>https://dev.to/eyuelberga/3-things-you-should-know-about-memoization-in-react-10ke</guid>
      <description>&lt;p&gt;Memoization is a technique of caching the results of a computationally expensive function. In React we can use this technique to avoid unnecessary re-renders and expensive recomputations. React provides three methods for this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;memo&lt;/strong&gt;: a higher-order component used for memoizing components.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;useMemo&lt;/strong&gt;: hook for memoizing a value which is expensive to compute&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;useCallback&lt;/strong&gt;: similar to useMemo, used for memoizing a callback function. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Even though memoization is great for improving performance, if used inappropriately it can have the opposite effect. Let's look at the top three things you should be mindful of before using these methods in your react projects. &lt;/p&gt;

&lt;h2&gt;
  
  
  1. Memoization is meant for performance optimization
&lt;/h2&gt;

&lt;p&gt;Unless you encounter performance issues in your application, it is probably not a good idea to use any of the memoization methods. Your code should work without memoization(however slow it may be). As a rule of thumb, you should consider optimizing after implementing your components. &lt;/p&gt;

&lt;p&gt;If you notice performance issues, the React DevTools can help in finding performance bottlenecks. But also keep in mind that all performance issues can't be solved with memoization. So it is best to always check if there is any improvement gained from it.&lt;/p&gt;

&lt;p&gt;Also, be wary of premature optimization, so you don't waste time optimizing without the need for it. Most operations in JavaScript are optimized and overall the React framework is very performant. So, in most cases, further optimization might not be needed.  &lt;/p&gt;

&lt;h2&gt;
  
  
  2. Memoization has performance overheads
&lt;/h2&gt;

&lt;p&gt;Performance optimizations mostly come with some trade-offs. This is especially true with memoization. By caching previous results, we are using more memory in turn for better speed. So, you should always consider if the cost of memoization is worth it. This depends on the use case, but it is worth noting that there can be an extra overhead to its use if performance improvements are not substantial.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. React doesn't always guarantee memoization
&lt;/h2&gt;

&lt;p&gt;On the React docs if you see the section on useMemo it reads:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You may rely on useMemo as a performance optimization, not as a semantic guarantee &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you also look at React.memo in the docs you will find this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This method only exists as a performance optimization. Do not rely on it to “prevent” a render, as this can lead to bugs.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;React will cache results for as long as possible, but in some cases, it may also choose to invalidate the cache. So, there is no guarantee that the memoized value has not been discarded. This means you can't rely on React to always memoize values for you. To avoid introducing bugs to your application, always use memoization methods to optimize performance and nothing more.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;I hope you now have all the information you need to use memoization in React responsibly. Please do share your comments and suggestions, and thank you for reading.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This article was originally published &lt;a href="https://tealfeed.com/3-things-know-memoization-react-cynmx"&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>javascript</category>
      <category>react</category>
      <category>performance</category>
    </item>
    <item>
      <title>Singleton Pattern</title>
      <dc:creator>Eyuel Berga Woldemichael</dc:creator>
      <pubDate>Tue, 14 Dec 2021 18:33:11 +0000</pubDate>
      <link>https://dev.to/eyuelberga/singleton-pattern-3cj3</link>
      <guid>https://dev.to/eyuelberga/singleton-pattern-3cj3</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Singleton pattern allows creation of only a single instance from a class&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Motivation
&lt;/h2&gt;

&lt;p&gt;Consider a case where your application needs to access a shared resource from different places at various times. And also keep a consistent state between each access.&lt;/p&gt;

&lt;p&gt;The Singleton pattern solves this problem by creating a class that is responsible for creating and insuring only a single instance is created, while allowing direct access to the instantiated object.&lt;/p&gt;

&lt;h2&gt;
  
  
  Applicability
&lt;/h2&gt;

&lt;p&gt;The Singleton pattern can be used in cases where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The class have exactly one accessible instance&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Structure
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--JY-mvj-G--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6jd7ve17stwg8eak3919.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--JY-mvj-G--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6jd7ve17stwg8eak3919.png" alt="Singleton pattern class diagram" width="205" height="127"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Participants
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Singleton:&lt;/strong&gt; defines an Instance operation that lets clients access its unique instance&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Collaborations
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Clients access a Singleton instance only through the &lt;code&gt;getInstance&lt;/code&gt; method.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Advantages
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Can be sure of the number of instances&lt;/li&gt;
&lt;li&gt;Can globally access instance &lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Disadvantages
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Violates single responsibility principle. It is responsible for making sure that one instance is being created and also provide the core functionalities of the object itself.&lt;/li&gt;
&lt;li&gt;It is hard to unit test because global states are hard to isolate.&lt;/li&gt;
&lt;li&gt;Causes an object to be globally mutable which may not be desired in some cases.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Implementation
&lt;/h2&gt;

&lt;p&gt;Singletons can be implemented in numerous ways:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Eager initialization:&lt;/strong&gt; Object of class is created when it is loaded to the memory&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lazy initialization:&lt;/strong&gt; In this method, object is created only if it is needed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Thread Safe Singleton:&lt;/strong&gt; A thread safe singleton in created so that singleton property is maintained even in multi-threaded environment.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;The money received by customers of the cafe is stored in a cash register. It is important that there is only one cash register per cafe, so that the income of the cafe is accurately known.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To solve this problem, we implement &lt;code&gt;CashRegister&lt;/code&gt; as a singleton. we make the constructor private so nobody can instantiate the class. And we implement a method &lt;code&gt;getInstance&lt;/code&gt; to be called by user to obtain instance of the class.&lt;/p&gt;


&lt;div class="ltag__replit"&gt;
  &lt;iframe height="550px" src="https://repl.it/@eyuelberga/Singleton-Pattern?lite=true"&gt;&lt;/iframe&gt;
&lt;/div&gt;


</description>
      <category>beginners</category>
      <category>java</category>
      <category>codenewbie</category>
      <category>computerscience</category>
    </item>
    <item>
      <title>Prototype Pattern</title>
      <dc:creator>Eyuel Berga Woldemichael</dc:creator>
      <pubDate>Mon, 13 Dec 2021 23:23:11 +0000</pubDate>
      <link>https://dev.to/eyuelberga/prototype-pattern-3a08</link>
      <guid>https://dev.to/eyuelberga/prototype-pattern-3a08</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Prototype(Clone) pattern allows copying an object using a prototypical instance&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Motivation
&lt;/h2&gt;

&lt;p&gt;Consider an application which requires using the same object numerous times. To create an exact clone of the existing object, you could create a new instance from the class and copy all the values. But this creates a problem if the object contains private properties and methods, so an exact copy might not be possible. In some cases, you might only know the interface and not the concrete class of the object. &lt;/p&gt;

&lt;p&gt;The Prototype pattern solves this problem by implementing a clone method that allows creating an exact copy of an existing object without being dependent on the class of the object. &lt;/p&gt;

&lt;h2&gt;
  
  
  Applicability
&lt;/h2&gt;

&lt;p&gt;The Prototype pattern can be used in cases where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;duplicating an object is favorable instead of building from scratch&lt;/li&gt;
&lt;li&gt;the code is independent of any other third-party code&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Structure
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Oirg7Nzb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rxcizalasylgbq6ce3ut.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Oirg7Nzb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rxcizalasylgbq6ce3ut.png" alt="Prototype pattern class diagram" width="526" height="230"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Participants
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Prototype:&lt;/strong&gt; declares an interface for cloning itself&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ConcreteProtoype:&lt;/strong&gt; implements cloning operation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Client:&lt;/strong&gt; creates a new object by asking a prototype to clone itself&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Collaborations
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;A client initiates the prototype clone operation&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Advantages
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Allows clients to add and remove prototype at run-time by registering a prototypical instance.&lt;/li&gt;
&lt;li&gt;Allows us to avoid subclass hierarchy by using clone method.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Disadvantages
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Cloning might be difficult when the existing class internals doesn’t support cloning or if there is a complicated nested structure.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Implementation
&lt;/h2&gt;

&lt;p&gt;It is common to implement the prototype pattern using a prototype manager. A prototype manager is an associative store that returns the prototype matching a given key.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;The waiters that serve at the cafe all have the same uniform and salary but different tables. The owners of the cafe want an easy way of getting new waiters, without going through the trouble of starting from scratch.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To solve this problem, we first create an abstract Prototype class with a &lt;code&gt;copy&lt;/code&gt; method to enable cloning the object. We then create a &lt;code&gt;Waiter&lt;/code&gt; class extending the Prototype class, implementing the cloning method. After that we create a &lt;code&gt;WaiterFactory&lt;/code&gt; class that will use a Waiter object as a preset and clone it with different table numbers.&lt;/p&gt;


&lt;div class="ltag__replit"&gt;
  &lt;iframe height="550px" src="https://repl.it/@eyuelberga/Prototype-Pattern?lite=true"&gt;&lt;/iframe&gt;
&lt;/div&gt;


</description>
      <category>algorithms</category>
      <category>computerscience</category>
      <category>java</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Builder Pattern</title>
      <dc:creator>Eyuel Berga Woldemichael</dc:creator>
      <pubDate>Sat, 04 Dec 2021 18:11:52 +0000</pubDate>
      <link>https://dev.to/eyuelberga/builder-pattern-4p3j</link>
      <guid>https://dev.to/eyuelberga/builder-pattern-4p3j</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Builder pattern separates the construction of complex object from its representation, so that the same construction process can create different representations.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Motivation
&lt;/h2&gt;

&lt;p&gt;Consider an application which contains a complex object, with many specifications. Some of these specifications are optional and some mandatory. Keeping the different implementations of the construction process within the object will make the it less modular. And adding a new implementation requires change in the existing code-base.&lt;/p&gt;

&lt;p&gt;The Builder pattern solves this problem by moving the object construction logic out of the object and into a builder class.&lt;/p&gt;

&lt;h2&gt;
  
  
  Applicability
&lt;/h2&gt;

&lt;p&gt;The Builder pattern can be used in cases where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Construction of an object must enable different representations of the object&lt;/li&gt;
&lt;li&gt;Telescopic Constructor are to be avoided&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Structure
&lt;/h2&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F85jojouay7j9w10samzj.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F85jojouay7j9w10samzj.png" alt="Builder pattern class diagram"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Participants
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Builder:&lt;/strong&gt; Abstract interface for creating parts of Product object&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ConcreteBuilder:&lt;/strong&gt; Construct, assemble parts of Product&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Director:&lt;/strong&gt; Construct object using Builder&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Product:&lt;/strong&gt; Representation of the complex object under construction&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Collaborations
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Director&lt;/code&gt; is configured with a &lt;code&gt;Builder&lt;/code&gt; object&lt;/li&gt;
&lt;li&gt;One way communication between &lt;code&gt;Director&lt;/code&gt; and &lt;code&gt;Builder&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Director&lt;/code&gt; notifies &lt;code&gt;Builder&lt;/code&gt; which part should be built, then &lt;code&gt;Builder&lt;/code&gt; handles the request.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Advantages
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;isolates code for construction and representation&lt;/li&gt;
&lt;li&gt;help avoid telescopic constructor&lt;/li&gt;
&lt;li&gt;more control over the construction process&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Disadvantages
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Increased complexity in code due to increase in new interfaces and classes&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Implementation
&lt;/h2&gt;

&lt;p&gt;In most cases one builder instance is enough so builders are implemented as singletons.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;There are different variety of cakes served at the cafe. Even though all of them are cakes, they all have different ingredients. The owners want an optimized way of making the cakes, that will save the chef's time and also easily add new cake types to the menu in the future.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To solve this problem, we create a &lt;code&gt;Cake&lt;/code&gt; class with all the required attributes. Then we create an abstract &lt;code&gt;CakeBuilder&lt;/code&gt; class, which has abstract methods for building each component of the cake. We then extend this class to make concrete classes for the different variety of cakes. Lastly, we create a &lt;code&gt;Chef&lt;/code&gt; class that will use one of this concrete classes to make the cake and return the created object.&lt;/p&gt;


&lt;div class="ltag__replit"&gt;
  &lt;iframe height="550px" src="https://repl.it/@eyuelberga/Builder-Pattern?lite=true"&gt;&lt;/iframe&gt;
&lt;/div&gt;


</description>
      <category>computerscience</category>
      <category>algorithms</category>
      <category>beginners</category>
      <category>java</category>
    </item>
    <item>
      <title>Object Pool Pattern</title>
      <dc:creator>Eyuel Berga Woldemichael</dc:creator>
      <pubDate>Fri, 03 Dec 2021 08:26:38 +0000</pubDate>
      <link>https://dev.to/eyuelberga/object-pool-pattern-4e3h</link>
      <guid>https://dev.to/eyuelberga/object-pool-pattern-4e3h</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Object Pool (resource pools) provide container to reuse objects that are expensive to create.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Motivation
&lt;/h2&gt;

&lt;p&gt;Consider a scenario in which instantiating a new object is resource extensive. The Object Pool pattern solves this problem by providing a mechanism for creating object only when there no cached instance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Applicability
&lt;/h2&gt;

&lt;p&gt;The Object Pool pattern can be used in cases where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Application contains objects which are expensive to create, resource and performance wise.&lt;/li&gt;
&lt;li&gt;Clients require same resource but at different time period.&lt;/li&gt;
&lt;li&gt;When created objects are reusable.&lt;/li&gt;
&lt;li&gt;When we are working on a job that allocates and re-allocates many objects.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Structure
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fvCxti5c--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1djnja8rnr45o3eis908.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fvCxti5c--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1djnja8rnr45o3eis908.png" alt="Object Pool Pattern class diagram" width="345" height="413"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Participants
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt; &lt;strong&gt;Client:&lt;/strong&gt; the client uses pooled object type (reusable objects).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reusable Pool:&lt;/strong&gt; they manage reusable objects for the client.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Object Pool:&lt;/strong&gt; they manage and maintain available objects and collect objects that are requested.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Collaborations
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Clients configure object pool objects&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Advantages
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;It increases performance.&lt;/li&gt;
&lt;li&gt;Since it uses pools it is easier to manage and reuse, share objects.&lt;/li&gt;
&lt;li&gt;It reduces time since objects are in pools one can reuse them which decreases significant amount of time.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Disadvantages
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;When reusing objects from the pool unless previous state is changed(reset) it has different output than expected.&lt;/li&gt;
&lt;li&gt;Once an object is used unless it is sent back (released) to the pool it can’t be used (dependent on the client).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Implementation
&lt;/h2&gt;

&lt;p&gt;The object pool creates objects to be used again (reusable) so when an object is needed it is fetched from the pool or if an object is already waiting it is then returned. Pools are where reusable objects are stored once the object is released it is sent back to the pool.&lt;/p&gt;

&lt;p&gt;The implementation of an object pool must also consider a multi-threaded environment. If different threads access the pool concurrently a consistency error will occur. For this reason access to the object pool must be synchronized.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Let’s suppose in the cafe explained in the introduction of the series, the menus are printed out for every new customer, and are thrown out when the customer leaves. The owners have now realized this is very cost inefficient. They now want to reuse the menus and only print new ones when necessary.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To solve this problem, we first create a generic object pool&lt;br&gt;
class with an abstract create method. Then we use this class to make a concrete &lt;code&gt;EnglishMenuPool&lt;/code&gt;. Now we can use checkout and check-in methods to reuse menu object and create new ones when all objects are in use.&lt;/p&gt;


&lt;div class="ltag__replit"&gt;
  &lt;iframe height="550px" src="https://repl.it/@eyuelberga/Object-Pool-Pattern?lite=true"&gt;&lt;/iframe&gt;
&lt;/div&gt;


</description>
      <category>computerscience</category>
      <category>algorithms</category>
      <category>beginners</category>
      <category>java</category>
    </item>
    <item>
      <title>Abstract Factory Method Pattern</title>
      <dc:creator>Eyuel Berga Woldemichael</dc:creator>
      <pubDate>Thu, 02 Dec 2021 10:54:54 +0000</pubDate>
      <link>https://dev.to/eyuelberga/abstract-factory-method-pattern-3i0g</link>
      <guid>https://dev.to/eyuelberga/abstract-factory-method-pattern-3i0g</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Abstract Factory Method(kit) provides an interface for creating suits of related objects without specifying their concrete classes&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Motivation
&lt;/h2&gt;

&lt;p&gt;Consider an application which supports different standard of appearance and behavior. Each component in a standard should be used together. Hard-coding this standards will pose a problem as it will not be portable. We also should not mix the components that make up the standard.&lt;/p&gt;

&lt;p&gt;The Abstract Factory method pattern solves this problem by providing the necessary interface for creating an appropriate class instance. And also enabling clients to work with interfaces, without worrying about the concrete classes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Applicability
&lt;/h2&gt;

&lt;p&gt;The abstract factory method pattern can be used in cases where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Configuration of the system requires a suite of products.&lt;/li&gt;
&lt;li&gt;Implementation of products must be hidden and only their interface disclosed&lt;/li&gt;
&lt;li&gt;Suites of objects must be used together&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Structure
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--3E92Be4d--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yvkgcgwt95vctr019bp3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3E92Be4d--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yvkgcgwt95vctr019bp3.png" alt="Abstract Factory Class diagram" width="739" height="192"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Participants
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;AbstractFactory:&lt;/strong&gt; Interface for methods that create abstract products&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ConcreteFactory:&lt;/strong&gt; Implementation for methods that create abstract products&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AbstractProduct:&lt;/strong&gt; Interface for Product object&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ConcreteProduct:&lt;/strong&gt; Implementation of the AbstractProduct interface.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Client:&lt;/strong&gt; Use interfaces declared by AbstractFactory and AbstractProduct classes.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Collaborations
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;AbstractFactory transfers the responsibility of product object creation to its concrete sub-
classes&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Advantages
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Promotes loose-coupling between client and concrete 
products&lt;/li&gt;
&lt;li&gt;Increased flexibility in code as new variants of products can be integrated without changes in client code&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Disadvantages
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Increased complexity in code due to increase in new interfaces and classes&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Implementation
&lt;/h2&gt;

&lt;p&gt;Applications generally need one instance of a Factory, so they are typically implemented as Singletons. The AbstractFactory does not have an implementation for product creation and the &lt;code&gt;ConcreteProduct&lt;/code&gt; sub-classes commonly define factory methods for this purpose.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;Following up on our cafe example: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;There are now several new branches of the cafe and we have managed to change the language of the menu for each branch. But the owners now want each branch to have unique interior design. Each branch will have a different look, the pictures on the wall and the staff uniform should be different.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To solve this problem, we create interfaces for &lt;code&gt;WallPicture&lt;/code&gt; and &lt;code&gt;StaffUniform&lt;/code&gt;. Then we create concrete classes that implement these interfaces. After that, we create an abstract &lt;code&gt;BranchFactory&lt;/code&gt; class that will return &lt;code&gt;WallPicture&lt;/code&gt; and &lt;code&gt;StaffUniform&lt;/code&gt; objects. Lastly we will create a static class &lt;code&gt;FactoryCreator&lt;/code&gt; to generate &lt;code&gt;BranchFactory&lt;/code&gt; object based on the information passed.&lt;/p&gt;


&lt;div class="ltag__replit"&gt;
  &lt;iframe height="550px" src="https://repl.it/@eyuelberga/Abstract-Factory-Method-Pattern?lite=true"&gt;&lt;/iframe&gt;
&lt;/div&gt;


</description>
      <category>algorithms</category>
      <category>computerscience</category>
      <category>beginners</category>
      <category>java</category>
    </item>
    <item>
      <title>Factory Method Pattern</title>
      <dc:creator>Eyuel Berga Woldemichael</dc:creator>
      <pubDate>Wed, 01 Dec 2021 20:44:12 +0000</pubDate>
      <link>https://dev.to/eyuelberga/factory-method-pattern-3od</link>
      <guid>https://dev.to/eyuelberga/factory-method-pattern-3od</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Factory Method(virtual constructor) provides an interface for creating objects in a super-class, but defers instantiation to sub-classes.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Motivation
&lt;/h2&gt;

&lt;p&gt;Consider an application which has to access a class, but does not know which class to choose form among a set of sub-classes of the parent class. The application class can’t predict the sub-class to instantiate as the choice might depend on numerous factors, such as the state of the application at run-time or its configuration.&lt;/p&gt;

&lt;p&gt;The Factory method pattern solves this problem by encapsulating the functionality of selecting and instantiating the appropriate class inside a designated method, which we refer to as the factory method.&lt;/p&gt;

&lt;h2&gt;
  
  
  Applicability
&lt;/h2&gt;

&lt;p&gt;The factory method pattern can be used in cases where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A class can not know or predict the object it must create&lt;/li&gt;
&lt;li&gt;A class wants to transfer the instantiation of objects to its sub-classes&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Structure
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--RJ8cgHT8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ygsqvf9o2fsktzs7t2u7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--RJ8cgHT8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ygsqvf9o2fsktzs7t2u7.png" alt="Factory method class diagram" width="338" height="389"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Participants
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Product:&lt;/strong&gt; Interface of objects created by the factory method&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ConcreteProduct:&lt;/strong&gt; Implementation of the Product interface&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Creator:&lt;/strong&gt; declares the factory method that returns a Product instance.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ConcreteCreator:&lt;/strong&gt; Overrides factory method and returns ConcreteProduct instance &lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Collaborations
&lt;/h3&gt;

&lt;p&gt;In case the &lt;code&gt;Creator&lt;/code&gt; does not have a default implementation of the factory method, it relies on its sub-classes to define the factory method.&lt;/p&gt;

&lt;h2&gt;
  
  
  Advantages
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Provides hook for sub-classes, enabling sub-classes to affect their parents’ behavior.&lt;/li&gt;
&lt;li&gt;Dynamic or concrete types are isolated form the client code, hence promotes loose-coupling&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Disadvantages
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;To create even one &lt;code&gt;ConcreteProduct&lt;/code&gt; object the creator class must be sub-classed. This might overburden the clients.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Implementation
&lt;/h2&gt;

&lt;p&gt;The implementation of the factory method could have in general three variations:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;Creator&lt;/code&gt; class is an abstract class and does not have a default implementation for the factory method&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Creator&lt;/code&gt; class has a default implementation for the factory class, sub-classes override the default implementation if necessary&lt;/li&gt;
&lt;li&gt;factory methods are parameterized and can create multiple kinds of products corresponding to the value passed.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;Let us look at how we could apply the Factory Method Pattern to the cafe discussed in the introduction article of the series.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The cafe is growing popular and the owners decided to open a new branch in France. But there is a problem, the menu is in English but the customers expect it to be in French. There is also a confusion in the currency. In France, the currency is Euro but the system displays price in US Dollars.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We can solve this problem by first creating an abstract &lt;code&gt;Menu&lt;/code&gt; class, and then creating concrete classes that extend this abstract class to make a french and other language versions of the menu. We then create a &lt;code&gt;GetMenuFactory&lt;/code&gt; class to generate object of the different language versions based on the information given.&lt;/p&gt;


&lt;div class="ltag__replit"&gt;
  &lt;iframe height="550px" src="https://repl.it/@eyuelberga/Factory-Method-Pattern?lite=true"&gt;&lt;/iframe&gt;
&lt;/div&gt;


</description>
      <category>algorithms</category>
      <category>java</category>
      <category>beginners</category>
      <category>codenewbie</category>
    </item>
    <item>
      <title>Introduction</title>
      <dc:creator>Eyuel Berga Woldemichael</dc:creator>
      <pubDate>Wed, 01 Dec 2021 19:54:05 +0000</pubDate>
      <link>https://dev.to/eyuelberga/introduction-4bal</link>
      <guid>https://dev.to/eyuelberga/introduction-4bal</guid>
      <description>&lt;p&gt;Creational patterns hide how instance of classes are constructed. Thereby enabling more independence and increasing flexibility in a system. In this series, we try to look at the most common creational patterns and their unique features.&lt;/p&gt;

&lt;p&gt;To demonstrate the implementation of the creational patterns, we will use, as an example, what we have named as “The Design-pattern Cafe”. The Design-pattern Cafe is a fictitious Cafe based in Ethiopia. For each pattern,&lt;br&gt;
we have devised a problem-scenario that could potentially be solved with the pattern.&lt;/p&gt;

&lt;p&gt;All of the sample code used as examples can be found on GitHub at:&lt;br&gt;
&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/dp-team"&gt;
        dp-team
      &lt;/a&gt; / &lt;a href="https://github.com/dp-team/creationaldesignpatterns"&gt;
        creationaldesignpatterns
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Demo code on creational design patterns 
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;h1&gt;
Creational Design Patterns Demo&lt;/h1&gt;
&lt;p&gt;This repo contains demo codes for creational design patterns using, as
an example a fictitious virtual cafe named "the design-pattern
cafe".&lt;/p&gt;
&lt;p&gt;We came up with this example to better illustrate the design patterns
For each pattern, we have devised a problem-scenario
that could potentially be solved with the pattern.&lt;/p&gt;
&lt;h2&gt;
Factory Method Pattern&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Scenario:&lt;/strong&gt; The design-pattern cafe is growing popular
and the owners decided to open a new branch in France
But there is a problem, all the menus are in English and
the French could not understand it. There is also a
confusion in the currency. The French use the Euro but the
system displays price in Ethiopian Birr.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; We can solve this problem by first creating
an abstract Menu class, and then creating concrete classes that
extend this abstract class to make a French and other
language versions of the menu. We then create…&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/dp-team/creationaldesignpatterns"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


</description>
    </item>
    <item>
      <title>Developing an Internet-based GIS Application to Analyze and Determine Potential Public School Locations in Addis Ababa</title>
      <dc:creator>Eyuel Berga Woldemichael</dc:creator>
      <pubDate>Sat, 30 Oct 2021 05:32:58 +0000</pubDate>
      <link>https://dev.to/eyuelberga/developing-an-internet-based-gis-application-to-analyze-and-determine-potentialpublic-school-locations-in-addis-ababa-2oko</link>
      <guid>https://dev.to/eyuelberga/developing-an-internet-based-gis-application-to-analyze-and-determine-potentialpublic-school-locations-in-addis-ababa-2oko</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;The Demographic situation of Addis Ababa has changed over the last few decades. There is an ongoing increase in population and many areas, once uninhabitable forests are now suburban residential places. Nevertheless the construction of public schools is not keeping up with the dramatic changes in the city.&lt;/p&gt;

&lt;p&gt;Because of the increase in residential areas in the city, new suitable locations for public schools must be determined for construction. Because of the dynamic changes in the city, a tool is required to make the appropriate analysis. Hence, enabling better decisions to be made in the construction of public schools.&lt;/p&gt;

&lt;h2&gt;
  
  
  Purpose of the project
&lt;/h2&gt;

&lt;p&gt;The objective of the project is to develop an internet-based tool that identifies suitable public school locations in the city of Addis Ababa, taking to consideration these factors:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Availability of transportation from the residential areas to the proposed location&lt;/li&gt;
&lt;li&gt;Proximity of the proposed location to the residential areas&lt;/li&gt;
&lt;li&gt;The demography of the residential area for which the public school is to be constructed&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  1. Availability of transportation
&lt;/h3&gt;

&lt;p&gt;The suitability of a site should consider the availability of transportation form the residential area to the proposed site. The application should analyze the availability of transportation and regard a location with no feasible transport access to a residential area as unsuitable.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Proximity to residential area
&lt;/h3&gt;

&lt;p&gt;Proximity in our case refers to the closeness of a particular location to the residential area. The application should consider a location closer to a residential area as a more suitable location.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Demography of the residential area
&lt;/h3&gt;

&lt;p&gt;The population of the residential areas should also be considered when proposing new public school locations. The population size and the residential area size should be used as a primary factor to determining a new location.&lt;/p&gt;

&lt;h2&gt;
  
  
  Project Scope
&lt;/h2&gt;

&lt;p&gt;The project is focused in analyzing and determining site suitability for the construction of public schools. It is also limited to the city of Addis Ababa. However this restraint is not forcefully enforced. The application is flexible enough to also include residential areas that exist between the borders. The application can also be expanded by including additional data about schools and residential areas, that might come up in the future.&lt;/p&gt;

&lt;h2&gt;
  
  
  Data Collection, Compilation and Formatting
&lt;/h2&gt;

&lt;p&gt;The initial data about schools and residential areas was collected from &lt;code&gt;openstreetmap&lt;/code&gt;. With the help of the &lt;code&gt;Overpass API&lt;/code&gt;, data from &lt;code&gt;openstreetmap&lt;/code&gt; was extracted and stored in a PostgreSQL database with a &lt;code&gt;PostGIS&lt;/code&gt; extension.&lt;/p&gt;

&lt;p&gt;Some unnecessary data was also eliminated form the database. Data without names and other missing information were also removed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Design and Development of the Application
&lt;/h2&gt;

&lt;p&gt;Spatial information for the application are stored in a PostgreSQL database with a &lt;code&gt;PostGIS&lt;/code&gt; extension. The &lt;code&gt;PostGIS&lt;/code&gt; extension allows for spatial data to be stored in a PostgreSQL database. For users to interactively navigate the spatial information and perform analysis on it, &lt;code&gt;GeoDjango&lt;/code&gt; Server is used. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;GeoDjango&lt;/code&gt; is a python based web server application, with GIS functionalities. It allows performing spatial analysis against a database and also deploy a web-based user interface.&lt;/p&gt;

&lt;p&gt;The diagram below illustrates the basic architecture of a GeoDjango web application:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Lgizjjgu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mepc4ydl0lj3cxb59rzt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Lgizjjgu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mepc4ydl0lj3cxb59rzt.png" alt="Schematic of the GeoDjango architecture" width="562" height="687"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The tools provided by the application maybe used by numerous users, but data modifications need to be handled by privileged users only to avoid misrepresentation of facts. The application is designed to allow multiple users to use the analysis tools to get general information about schools&lt;br&gt;
and residential areas and also find suitable locations for school construction.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lNRw_4Qc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mitm0aegcjiq9p7acg06.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lNRw_4Qc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mitm0aegcjiq9p7acg06.png" alt="Schematic of the application and data flow" width="816" height="596"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Illustration above shows the working scheme of the system. The working scheme is as follows:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;user sends a request, then the request will be sent through the internet to the server&lt;/li&gt;
&lt;li&gt;on the server, the request will be processed and data is fetched form the database server&lt;/li&gt;
&lt;li&gt;data from the database will be retrieved and sent to the application server.&lt;/li&gt;
&lt;li&gt;The application server will then send the processed data to the user&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Admins and normal users generally go through the same procedures, the key difference being that admins have the ability to modify stored information on the database server.&lt;/p&gt;

&lt;p&gt;The UML design illustrates the interaction between data and other objects that will be implemented into the system.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kNMVpmyC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cuax5eppd5b4wupvwsod.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kNMVpmyC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cuax5eppd5b4wupvwsod.png" alt="UML class diagram of the application" width="880" height="673"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Functions and features of the Application
&lt;/h2&gt;

&lt;p&gt;The application provides three tools for the analysis of schools. These tools take advantage of basic GIS functionalities to provide useful operations for analysis.&lt;/p&gt;
&lt;h3&gt;
  
  
  Distance Analysis
&lt;/h3&gt;

&lt;p&gt;This tool enables users to find schools which are closer to an arbitrary location. This tool primarily uses the Distance function. The Distance function is an abstraction for the distance calculation supported by the backend database. It enables us to find the distance between two geographic fields.&lt;/p&gt;
&lt;h3&gt;
  
  
  Schools Visualization
&lt;/h3&gt;

&lt;p&gt;This tool provides a spatial analysis of all schools registered on the database. For this tool the Leaflet mapping library is used. Leaflet is a JavaScript library for creating interactive maps on the front-end. &lt;/p&gt;

&lt;p&gt;Using the spatial data from the database, we are able to dynamically add new data to the map and display it on the web-page.&lt;/p&gt;
&lt;h3&gt;
  
  
  Suitable Sites analysis
&lt;/h3&gt;

&lt;p&gt;This tool helps in analyzing if a particular residential area requires a new public school. It gives insightful indications of where to construct a new school. &lt;/p&gt;

&lt;p&gt;In order to determine if a residential area requires a new school, the application has a set of criterion which it checks against. These are the proximity criteria, size criteria and overall criteria&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Proximity criteria&lt;/strong&gt;: checks if there is a school which is only 5 kms away from the residential
area. If there are no schools in a 5 km radius, then it is a fail.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Size criteria&lt;/strong&gt;: checks if the student demography is proportional to the schools in the residential
area. Population statistics about residential areas are not stored in the database, but are approximated using an algorithm based on a generalized data. Python implementation of the algorithm is as follows:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;
&lt;span class="c1"&gt;# area of residential area is square kms
&lt;/span&gt;&lt;span class="n"&gt;residential_area_sq_km&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;area&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sq_km&lt;/span&gt;
&lt;span class="c1"&gt;# population density in addis ababa is 5165/km2
&lt;/span&gt;&lt;span class="n"&gt;population&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5165&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;residential_area_sq_km&lt;/span&gt;
&lt;span class="c1"&gt;# 43 % of the population is a student
&lt;/span&gt;&lt;span class="n"&gt;students&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;population&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;43&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="err"&gt;‘’’&lt;/span&gt;
&lt;span class="n"&gt;one&lt;/span&gt; &lt;span class="n"&gt;school&lt;/span&gt; &lt;span class="n"&gt;holds&lt;/span&gt; &lt;span class="n"&gt;more&lt;/span&gt; &lt;span class="n"&gt;than&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;000&lt;/span&gt; &lt;span class="n"&gt;students&lt;/span&gt;
&lt;span class="err"&gt;‘&lt;/span&gt;&lt;span class="n"&gt;no_schools&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt; &lt;span class="n"&gt;varaible&lt;/span&gt; &lt;span class="n"&gt;gives&lt;/span&gt; &lt;span class="n"&gt;us&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="n"&gt;schools&lt;/span&gt; &lt;span class="n"&gt;that&lt;/span&gt; &lt;span class="n"&gt;need&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="c1"&gt;#
&lt;/span&gt;&lt;span class="n"&gt;be&lt;/span&gt; &lt;span class="n"&gt;located&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="n"&gt;km&lt;/span&gt; &lt;span class="n"&gt;radius&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="c1"&gt;# criteria to pass
&lt;/span&gt;&lt;span class="err"&gt;‘’’&lt;/span&gt;
&lt;span class="n"&gt;no_schools&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ceil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;students&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Overall criteria&lt;/strong&gt;: checks if both the size and proximity criterion pass. This determines if a new school needs to be constructed for a residential area.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If a residential area fails the overall criteria, it is an indication that the area is in need of a new public school. The tool also gives an insight of where to construct the new school by creating a 5km buffer form the centroid of the residential area.&lt;/p&gt;
&lt;h2&gt;
  
  
  User Interface
&lt;/h2&gt;

&lt;p&gt;The Dashboard&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jCaiChQc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4xcqtd6aqwck0573x5jk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jCaiChQc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4xcqtd6aqwck0573x5jk.png" alt="Dashboard" width="880" height="453"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Distance Analysis Form&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--bZQy-RPv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0n1zs1izy3lz1gpqsqi8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--bZQy-RPv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0n1zs1izy3lz1gpqsqi8.png" alt="Distance Analysis Form" width="880" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Distance Analysis Result&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--j-sn9elT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ydanum1kydyldoc5xa0f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--j-sn9elT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ydanum1kydyldoc5xa0f.png" alt="Distance Analysis Result" width="880" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Schools Visualization&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ywsU9WRw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1z4lev1vpti0o9nura44.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ywsU9WRw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1z4lev1vpti0o9nura44.png" alt="Schools Visualization" width="880" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Suitable Site analysis&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jZf_VLiW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/59qwqynq45slpo838apf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jZf_VLiW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/59qwqynq45slpo838apf.png" alt="Suitable Site analysis" width="880" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Suitable Site result– new school required&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OWa1sRlO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xbcswp3km6as5ueefu3d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OWa1sRlO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xbcswp3km6as5ueefu3d.png" alt="Suitable Site – new school required" width="880" height="457"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Suitable site result- new school not required&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qFyA1Czt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pq4snehwivfpkapvniak.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qFyA1Czt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pq4snehwivfpkapvniak.png" alt="Suitable site - new school not required" width="880" height="457"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Source-code
&lt;/h2&gt;

&lt;p&gt;Check out the source-code on GitHub&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/eyuelberga"&gt;
        eyuelberga
      &lt;/a&gt; / &lt;a href="https://github.com/eyuelberga/gis-school-analysis-tool"&gt;
        gis-school-analysis-tool
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      GIS School Location Analysis Tool  made with GeoDjango PostGIS
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;h1&gt;
Geo-Django Project to Analyze and Determine Potential Public School Locations in Addis Ababa&lt;/h1&gt;
&lt;p&gt;The objective of the project is to develop an internet-based tool that identifies suitable public school
locations in the city of Addis Ababa, taking to consideration these factors:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Availability of transportation from the residential areas to the proposed location&lt;/li&gt;
&lt;li&gt;Proximity of the proposed location to the residential areas&lt;/li&gt;
&lt;li&gt;The demography of the residential area for which the public school is to be constructed&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The initial data about schools and residential areas was collected from openstreetmap. With the help
of the Overpass API, data from openstreetmap was extracted and stored in a PostgreSQL database
with a PostGIS extension
Some unnecessary data was also eliminated form the database. Data without names and other
missing information were also removed.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://dev.to/eyuelberga/developing-an-internet-based-gis-application-to-analyze-and-determine-potentialpublic-school-locations-in-addis-ababa-2oko" rel="nofollow"&gt;Read This Article for more detail&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
Running Locally&lt;/h2&gt;
&lt;p&gt;To run this project locally, the easiest way would be using &lt;code&gt;docker-compose&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;$&lt;/pre&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/eyuelberga/gis-school-analysis-tool"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


</description>
      <category>gis</category>
      <category>django</category>
      <category>python</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Security Alarm System using a Bipolar Junction Transistor Switch</title>
      <dc:creator>Eyuel Berga Woldemichael</dc:creator>
      <pubDate>Thu, 28 Oct 2021 06:06:51 +0000</pubDate>
      <link>https://dev.to/eyuelberga/security-alarm-system-using-a-bipolar-junction-transistor-switch-2eb4</link>
      <guid>https://dev.to/eyuelberga/security-alarm-system-using-a-bipolar-junction-transistor-switch-2eb4</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;The security alarm system will use a bipolar junction transistor switch to detect security problems. Theft attempt and other security threats can be controlled by using this simple circuit.&lt;/p&gt;

&lt;p&gt;For the purpose of this application, we will design a security system for one room in a house. The sensor used for each opening can be either a mechanical switch, a magnetically operated switch, or an optical sensor. Detection of an intrusion can be used to initiate an audible alarm signal. &lt;/p&gt;

&lt;p&gt;We will be using a mechanical switch as our sensor and use a transistor as a &lt;strong&gt;NOT&lt;/strong&gt; gate, so that when there is an open switch in our room a transistor will show a signal that an intruder has entered.&lt;/p&gt;

&lt;h2&gt;
  
  
  Equipment Used
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Resistor&lt;/li&gt;
&lt;li&gt;Transistor&lt;/li&gt;
&lt;li&gt;Buzzer&lt;/li&gt;
&lt;li&gt;Voltage source&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Circuit Design and Experimental Setup
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Block Diagram
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--JHXqXMWn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/saol08k1f7bb6xzeyftl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--JHXqXMWn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/saol08k1f7bb6xzeyftl.png" alt="Block Diagram" width="880" height="144"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Room Sensor
&lt;/h3&gt;

&lt;p&gt;Room sensor is normally in a closed position and it is connected to a DC voltage source. When a door is open it creates an open circuit.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--XulDTXkN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ktv2mk8xygbzyyf6r12z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--XulDTXkN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ktv2mk8xygbzyyf6r12z.png" alt="Normal State" width="880" height="139"&gt;&lt;/a&gt;&lt;br&gt;
At its normal state the room sensor looks like the above.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--XEq-SEE9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c630ksnqlv2dq2mqf5qn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--XEq-SEE9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c630ksnqlv2dq2mqf5qn.png" alt="On Intrusion" width="880" height="123"&gt;&lt;/a&gt;&lt;br&gt;
If intrusion occurs the switch will be open.&lt;/p&gt;

&lt;h3&gt;
  
  
  Transistor Switch
&lt;/h3&gt;

&lt;h4&gt;
  
  
  BJT as a Switch
&lt;/h4&gt;

&lt;p&gt;Transistor switches are used for high power devices such as&lt;br&gt;
motors or lamps which often require more power than supplied by an ordinary logic gate &lt;/p&gt;

&lt;p&gt;The areas of operation for Transistor switch are known as the &lt;strong&gt;Saturation Region&lt;/strong&gt; and the &lt;strong&gt;Cut-Off Region&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cut-off Region&lt;/strong&gt;: here there is a large depletion layer&lt;br&gt;
and no current flowing through the device. Therefore the transistor is switched “OFF”&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Saturation Region&lt;/strong&gt;: here the depletion layer is as&lt;br&gt;
small as possible and maximum current is flowing through the transistor. Therefore the transistor is switched “ON”.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  NOT Gate Transistor
&lt;/h3&gt;

&lt;p&gt;A NOT gate simply inverts its input. If the input is high, the output is low, and if the input is low, the output is high&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---t1UcodH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fygdbyq1tl1zbhhcpj6m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---t1UcodH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fygdbyq1tl1zbhhcpj6m.png" alt="NOT gate transistor" width="540" height="378"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The operation of this circuit is simple. The input is connected through resistor R2 to the transistor’s&lt;br&gt;
base. When no voltage is present on the input, the transistor is turned off. Then, no current flows through the collector-emitter path. Thus, current from the supply voltage (Vcc) flows through resistor R1 to the output. This way, the circuit’s output is high when the input is low.&lt;/p&gt;

&lt;p&gt;When voltage is present at the input, the transistor turns on, allowing current to flow through the collector-emitter circuit directly to ground. This ground path creates a shortcut that bypasses the output, which causes the output to go low.&lt;/p&gt;

&lt;h2&gt;
  
  
  Simulation
&lt;/h2&gt;

&lt;p&gt;We run our simulation with a voltmeter connected to the output, in place of the buzzer .&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Pb6pEVbg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ze5pvm31qmf98ihv4jos.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Pb6pEVbg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ze5pvm31qmf98ihv4jos.png" alt="Reading when switch is closed" width="547" height="255"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the normal state, the switch will be closed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--TVv7lfje--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4ffv38a0yk2x2xq7o9st.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TVv7lfje--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4ffv38a0yk2x2xq7o9st.png" alt="Reading when switch is open" width="600" height="301"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When intrusion happens, the switch will open and the alarm (buzzer) will go off.&lt;/p&gt;

</description>
      <category>security</category>
      <category>hardware</category>
      <category>design</category>
      <category>electronics</category>
    </item>
    <item>
      <title>De-Comment Program in C</title>
      <dc:creator>Eyuel Berga Woldemichael</dc:creator>
      <pubDate>Tue, 26 Oct 2021 19:55:24 +0000</pubDate>
      <link>https://dev.to/eyuelberga/de-comment-program-in-c-ia4</link>
      <guid>https://dev.to/eyuelberga/de-comment-program-in-c-ia4</guid>
      <description>&lt;p&gt;De-commenting is one of the primary tasks of the C preprocessor. This article demonstrates a simplified C program to remove comments from source-code.&lt;/p&gt;

&lt;h2&gt;
  
  
  DFA Design
&lt;/h2&gt;

&lt;p&gt;The deterministic finite state automaton (DFA) expresses the required de-commenting logic. The DFA is represented using the traditional "labeled ovals and labeled arrows" notation. Each oval represent a state. Each state is given short name with detailed descriptions of the left. Each arrow represent a transition from one state to another. Each arrow is labeled with the single character that causes the transition to occur.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Feyuelberga%2Fdecomment-program-c%2Fraw%2Fv1.0.0%2Fassets%2Fdfa.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%2Fgithub.com%2Feyuelberga%2Fdecomment-program-c%2Fraw%2Fv1.0.0%2Fassets%2Fdfa.png" alt="DFA"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Usage
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;./decomment &amp;lt;file_path&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;If the program is run without  argument, the code to be decommented will be read from the standard input and displayed[decommented code] on the standard output&lt;/li&gt;
&lt;li&gt;If  argument is given, the code to be decommented will be read form the file and displayed in the standard output.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The full source-code for the project is on GitHub:&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/eyuelberga" rel="noopener noreferrer"&gt;
        eyuelberga
      &lt;/a&gt; / &lt;a href="https://github.com/eyuelberga/decomment-program-c" rel="noopener noreferrer"&gt;
        decomment-program-c
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      C program to remove comments from source-code
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;De-Comment Program&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;C program to remove comments from source-code&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;DFA Design&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;The deterministic finite state automaton (DFA) expresses the required de-commenting logic. The DFA is represented using the traditional "labeled ovals and labeled arrows" notation. Each oval represent a state. Each state is given short name with detailed descriptions of the left. Each arrow represent a transition from one state to another. Each arrow is labeled with the single character that causes the transition to occur.&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/eyuelberga/decomment-program-cassets/dfa.png"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Feyuelberga%2Fdecomment-program-cassets%2Fdfa.png" alt="deterministic finite state automaton (DFA)" title="DFA"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Build&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;You can compile the program using &lt;code&gt;gcc&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;$ gcc decomment.c -o decomment&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Usage&lt;/h2&gt;

&lt;/div&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;$ ./decomment &lt;span class="pl-k"&gt;&amp;lt;&lt;/span&gt;file_path&lt;span class="pl-k"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;If the program is run without &amp;lt;file_path&amp;gt; argument, the code to be decommented will be read from the
standard input and displayed[decommented code] on the standard output&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;If &amp;lt;file_path&amp;gt; argument is given, the code to be decommented will be read form the file and displayed in
the standard output.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Test&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;&lt;code&gt;test.py&lt;/code&gt; contains a simple…&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/eyuelberga/decomment-program-c" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


</description>
      <category>c</category>
      <category>showdev</category>
      <category>programming</category>
      <category>systems</category>
    </item>
  </channel>
</rss>
