<?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: mich0w0h</title>
    <description>The latest articles on DEV Community by mich0w0h (@mich0w0h).</description>
    <link>https://dev.to/mich0w0h</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%2F1198613%2Fe9e8b8ce-45d3-42b9-ab00-840f159fc4f7.png</url>
      <title>DEV Community: mich0w0h</title>
      <link>https://dev.to/mich0w0h</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mich0w0h"/>
    <language>en</language>
    <item>
      <title>Setting Up a Local DNS Service with Docker on Ubuntu 22.04</title>
      <dc:creator>mich0w0h</dc:creator>
      <pubDate>Sun, 24 Mar 2024 22:20:18 +0000</pubDate>
      <link>https://dev.to/mich0w0h/setting-up-a-local-dns-service-with-docker-on-ubuntu-2204-290i</link>
      <guid>https://dev.to/mich0w0h/setting-up-a-local-dns-service-with-docker-on-ubuntu-2204-290i</guid>
      <description>&lt;p&gt;Recently, I've been working on setting up a local DNS service using Docker on Ubuntu 22.04. I've documented my process and thought it might be helpful to share it with others. Here's how I did it.&lt;/p&gt;

&lt;p&gt;Note: This article is the final form of these articles&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/mich0w0h/setting-up-a-coredns-server-for-local-custom-domain-management-on-ubuntu-using-docker-meo"&gt;Setting up a CoreDNS Server for Local Custom Domain Management on Ubuntu Using Docker - DEV Community&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/mich0w0h/setting-up-a-recursive-dns-resolver-using-unbound-on-docker-1abg"&gt;Setting Up a Recursive DNS Resolver Using Unbound on Docker - DEV Community&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Repository
&lt;/h2&gt;

&lt;p&gt;You can find the complete code in my &lt;a href="https://github.com/mich0w0h/local-dns" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt;.&lt;/p&gt;

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

&lt;p&gt;I've organized my project into a directory structure as follows:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

local-dns
├── compose.yml
├── .git
├── .dockerignore
├── recursive
│   ├── Dockerfile
│   └── unbound.conf
└── authoritative
    ├── Corefile
    └── zone
        └── db.mich0w0h.house


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

&lt;/div&gt;
&lt;h2&gt;
  
  
  Networking Overview
&lt;/h2&gt;

&lt;p&gt;Here's the networking overview of this project&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%2Fa3i9xlj760zhfvb3oyx5.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%2Fa3i9xlj760zhfvb3oyx5.png" alt="networking overview"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I assigned an IP address 192.168.10.100 to the host Ubuntu server. If you want to know how to assign a static address to a Ubuntu server, see this post: &lt;a href="https://dev.to/mich0w0h/configure-static-ip-in-ubuntu-2204-2fd7"&gt;Configure Static IP in Ubuntu 22.04 - DEV Community&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Docker Configuration
&lt;/h2&gt;

&lt;p&gt;I've created a &lt;code&gt;.dockerignore&lt;/code&gt; file to exclude unnecessary files from the Docker build context:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

**/.git


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

&lt;/div&gt;

&lt;p&gt;I've also created a Dockerfile for the resolver service:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;

&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; ubuntu:22.04&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;apt-get update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; unbound &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; /var/lib/apt/lists/&lt;span class="k"&gt;*&lt;/span&gt;

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; unbound.conf /etc/unbound/unbound.conf&lt;/span&gt;

&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["/usr/sbin/unbound", "-d", "-c", "/etc/unbound/unbound.conf"]&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;This Dockerfile uses the Ubuntu 22.04 image, installs Unbound (a DNS resolver), and copies the Unbound configuration file into the container.&lt;/p&gt;

&lt;p&gt;The Unbound configuration file (&lt;code&gt;unbound.conf&lt;/code&gt;) is as follows:&lt;/p&gt;

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

server:
    interface: 0.0.0.0
    access-control: 0.0.0.0/0 refuse
    access-control: 192.168.1.0/24 allow_snoop
remote-control:
    control-enable: no
stub-zone:
    name: "mich0w0h.house"
    stub-addr: 192.168.1.102
forward-zone:
    name: "."
    forward-addr: 8.8.8.8 # google DNS
    # forward-addr: 192.168.10.1. # ISP provided DNS


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

&lt;/div&gt;
&lt;h2&gt;
  
  
  Docker Compose
&lt;/h2&gt;

&lt;p&gt;I've used Docker Compose to manage my services. Here's my &lt;code&gt;compose.yml&lt;/code&gt; file:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;resolver&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./resolver&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;53:53/udp"&lt;/span&gt;
    &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;local-dns&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;ipv4_address&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;192.168.1.101&lt;/span&gt;
  &lt;span class="na"&gt;authoritative&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;coredns/coredns&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;./authoritative:/etc/coredns"&lt;/span&gt;
    &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;local-dns&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;ipv4_address&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;192.168.1.102&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;-conf /etc/coredns/Corefile&lt;/span&gt;
&lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;local-dns&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;driver&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bridge&lt;/span&gt;
    &lt;span class="na"&gt;ipam&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;config&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;subnet&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;192.168.1.0/24&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;The service is available from port 53 of the host machine. However, it's necessary to assign IP addresses since &lt;code&gt;unbound.conf&lt;/code&gt; only accepts IP addresses to specify the nameserver, and specifying the service name of docker compose doesn't work.&lt;/p&gt;

&lt;p&gt;If you've already created a network using the command &lt;code&gt;sudo docker network create --subnet=192.168.1.0/24 local-dns&lt;/code&gt;, you can modify the networks section like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;local-dns&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;external&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;


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

&lt;/div&gt;
&lt;h2&gt;
  
  
  Enabling Port Mapping
&lt;/h2&gt;

&lt;p&gt;By default, &lt;code&gt;systemd-resolved&lt;/code&gt; is running on port 53 in Ubuntu 22.04. To use port 53 for your Docker container, you'll need to stop and disable &lt;code&gt;systemd-resolved&lt;/code&gt;, or change its port. Here's how I did it:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl stop systemd-resolved
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl disable systemd-resolved


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

&lt;/div&gt;

&lt;p&gt;Next, remove the symlink &lt;code&gt;/etc/resolv.conf&lt;/code&gt; and create a new one:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nb"&gt;sudo rm&lt;/span&gt; /etc/resolv.conf
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"nameserver 8.8.8.8"&lt;/span&gt; | &lt;span class="nb"&gt;sudo tee&lt;/span&gt; /etc/resolv.conf


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

&lt;/div&gt;

&lt;p&gt;After this, test your internet connectivity to ensure that disabling &lt;code&gt;systemd-resolved&lt;/code&gt; hasn't caused any issues:&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;curl google.com


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

&lt;/div&gt;
&lt;h2&gt;
  
  
  Running Docker Compose
&lt;/h2&gt;

&lt;p&gt;To start your services, run Docker Compose:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nb"&gt;sudo &lt;/span&gt;docker compose up &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;--build&lt;/span&gt;


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

&lt;/div&gt;
&lt;h2&gt;
  
  
  Testing
&lt;/h2&gt;

&lt;p&gt;Finally, test your setup from another device in your home network:&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;dig @192.168.10.100 www.mich0w0h.house


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

&lt;/div&gt;

&lt;p&gt;If everything is set up correctly, you should see a response similar to the following:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="p"&gt;;&lt;/span&gt; &amp;lt;&amp;lt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; DiG 9.10.6 &amp;lt;&amp;lt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; @192.168.10.100 www.mich0w0h.house
&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;1 server found&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;;;&lt;/span&gt; global options: +cmd
&lt;span class="p"&gt;;;&lt;/span&gt; Got answer:
&lt;span class="p"&gt;;;&lt;/span&gt; -&amp;gt;&amp;gt;HEADER&lt;span class="o"&gt;&amp;lt;&amp;lt;-&lt;/span&gt; &lt;span class="no"&gt;opcode&lt;/span&gt;&lt;span class="sh"&gt;: QUERY, status: NOERROR, id: 49784
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;www.mich0w0h.house.        IN  A

;; ANSWER SECTION:
www.mich0w0h.house. 86400   IN  A   192.168.1.103

;; Query time: 49 msec
;; SERVER: 192.168.10.100#53(192.168.10.100)
;; WHEN: Sun Mar 24 05:19:39 JST 2024
;; MSG SIZE  rcvd: 63


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

&lt;/div&gt;

&lt;p&gt;That's it! You've now set up a local DNS service with Docker on Ubuntu 22.04.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.sbcr.jp/product/4797394481/" rel="noopener noreferrer"&gt;DNSがよくわかる教科書 | SBクリエイティブ&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.shuwasystem.co.jp/book/9784798071503.html" rel="noopener noreferrer"&gt;開発系エンジニアのためのDocker絵とき入門 - 秀和システム あなたの学びをサポート！&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://unbound.docs.nlnetlabs.nl/en/latest/getting-started/configuration.html" rel="noopener noreferrer"&gt;Configuration — Unbound 1.19.3 documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nlnetlabs.nl/documentation/unbound/unbound-checkconf/" rel="noopener noreferrer"&gt;NLnet Labs Documentation - Unbound - unbound-checkconf.8&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nlnetlabs.nl/documentation/unbound/unbound.conf/" rel="noopener noreferrer"&gt;NLnet Labs Documentation - Unbound - unbound.conf.5&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://unbound.docs.nlnetlabs.nl/en/latest/use-cases/home-resolver.html" rel="noopener noreferrer"&gt;Resolver for Home Networks — Unbound 1.19.3 documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://coredns.io/2017/07/23/corefile-explained/" rel="noopener noreferrer"&gt;Corefile Explained&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://qiita.com/miwamoto/items/2a8befac7135bd21e08a" rel="noopener noreferrer"&gt;Docker+DNS入門　その1：CoreDNSを用いた権威DNSサーバ構築 #Docker - Qiita&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://qiita.com/miwamoto/items/7981c390ac876a7fac5e" rel="noopener noreferrer"&gt;Docker+DNS入門　その2：Unboundを用いたキャッシュDNSサーバ構築 #Docker - Qiita&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ubuntu</category>
      <category>dns</category>
      <category>docker</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Setting Up a Recursive DNS Resolver Using Unbound on Docker</title>
      <dc:creator>mich0w0h</dc:creator>
      <pubDate>Wed, 20 Mar 2024 23:23:10 +0000</pubDate>
      <link>https://dev.to/mich0w0h/setting-up-a-recursive-dns-resolver-using-unbound-on-docker-1abg</link>
      <guid>https://dev.to/mich0w0h/setting-up-a-recursive-dns-resolver-using-unbound-on-docker-1abg</guid>
      <description>&lt;p&gt;In this article, I'll walk through the steps to set up a recursive DNS resolver using Unbound on Docker. This resolver will handle DNS queries for a local domain &lt;code&gt;mich0w0h.house&lt;/code&gt; by forwarding them to an authoritative nameserver while forwarding queries for other domains to external DNS servers like Google DNS.&lt;/p&gt;

&lt;p&gt;This post is one part of building a local DNS service using docker-compose and the authoritative nameserver for &lt;code&gt;mich0w0wh.house&lt;/code&gt; is already built by this article.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/mich0w0h/setting-up-a-coredns-server-for-local-custom-domain-management-on-ubuntu-using-docker-meo"&gt;Setting up a CoreDNS Server for Local Custom Domain Management on Ubuntu Using Docker - DEV Community&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'll write the other remaining parts later.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Docker installed and running&lt;/li&gt;
&lt;li&gt;A Docker network named &lt;code&gt;internal-dns&lt;/code&gt; with subnet &lt;code&gt;192.168.1.0/24&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;An authoritative nameserver at &lt;code&gt;192.168.1.102:53&lt;/code&gt; for the &lt;code&gt;mich0w0h.house&lt;/code&gt; domain&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Please ensure that you execute all the following commands within the &lt;code&gt;internal-dns&lt;/code&gt; directory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;internal-dns
├── authoritative
│   └── ...
└── resolver
    ├── Dockerfile
    └── unbound.conf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Create a Dockerfile
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM ubuntu:22.04

RUN apt-get update &amp;amp;&amp;amp; apt-get install -y unbound &amp;amp;&amp;amp; rm -rf /var/lib/apt/lists/*

COPY unbound.conf /etc/unbound/unbound.conf

CMD ["/usr/sbin/unbound", "-d", "-c", "/etc/unbound/unbound.conf"]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This Dockerfile installs Unbound on an Ubuntu 22.04 base image and copies the &lt;code&gt;unbound.conf&lt;/code&gt; configuration file, then setting the default command to run unbound with the -d flag (to run in the foreground) and the -c flag to specify the configuration file.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create an unbound.conf
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;server:
    interface: 0.0.0.0
    access-control: 192.168.1.0/24 allow
    remote-control:
        control-enable: no
stub-zone:
    name: "mich0w0h.house"
    stub-addr: 192.168.1.102
forward-zone:
    name: "."
    forward-addr: 8.8.8.8 # google DNS
    # forward-addr: 192.168.10.1. # ISP provided DNS
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This configuration file sets up the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;server&lt;/code&gt; section configures the Unbound server to listen on all interfaces (&lt;code&gt;0.0.0.0&lt;/code&gt;) on port 53 and allows queries from the &lt;code&gt;192.168.1.0/24&lt;/code&gt; subnet.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;stub-zone&lt;/code&gt; section configures a stub zone for the &lt;code&gt;mich0w0h.house&lt;/code&gt; domain, forwarding queries to the authoritative nameserver at &lt;code&gt;192.168.1.102:53&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;forward-zone&lt;/code&gt; section configures forwarding for all other domains to Google DNS (&lt;code&gt;8.8.8.8&lt;/code&gt;). You can also use your ISP's DNS server if preferred.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Building and Running
&lt;/h2&gt;

&lt;p&gt;Build the Docker image:&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="nb"&gt;sudo &lt;/span&gt;docker image build &lt;span class="nt"&gt;-t&lt;/span&gt; unbound-resolver resolver/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the container for testing the configuration:&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="nb"&gt;sudo &lt;/span&gt;docker container run &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;--name&lt;/span&gt; resolver-test &lt;span class="nt"&gt;--network&lt;/span&gt; internal-dns &lt;span class="nt"&gt;--ip&lt;/span&gt; 192.168.1.101 unbound-resolver unbound-checkconf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the output shows &lt;code&gt;unbound-checkconf: no errors in /etc/unbound/unbound.conf&lt;/code&gt;, then the configuration is valid.&lt;/p&gt;

&lt;p&gt;Stop the resolver-test container and run a Unbound resolver container:&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="nb"&gt;sudo &lt;/span&gt;docker container run &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;--name&lt;/span&gt; resolver &lt;span class="nt"&gt;--network&lt;/span&gt; internal-dns &lt;span class="nt"&gt;--ip&lt;/span&gt; 192.168.1.101 unbound-resolver
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Testing
&lt;/h2&gt;

&lt;p&gt;You can test the resolver by querying for a record in the &lt;code&gt;mich0w0h.house&lt;/code&gt; domain:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dig @192.168.1.101 www.mich0w0h.house
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This should return the IP address configured for &lt;code&gt;www.mich0w0h.house&lt;/code&gt; in the authoritative nameserver.&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="p"&gt;;&lt;/span&gt; &amp;lt;&amp;lt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; DiG 9.18.18-0ubuntu0.22.04.2-Ubuntu &amp;lt;&amp;lt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; @192.168.1.101 www.mich0w0h.house
&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;1 server found&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;;;&lt;/span&gt; global options: +cmd
&lt;span class="p"&gt;;;&lt;/span&gt; Got answer:
&lt;span class="p"&gt;;;&lt;/span&gt; -&amp;gt;&amp;gt;HEADER&lt;span class="o"&gt;&amp;lt;&amp;lt;-&lt;/span&gt; &lt;span class="no"&gt;opcode&lt;/span&gt;&lt;span class="sh"&gt;: QUERY, status: NOERROR, id: 64714
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;www.mich0w0h.house.        IN  A

;; ANSWER SECTION:
www.mich0w0h.house. 86400   IN  A   192.168.1.103

;; Query time: 0 msec
;; SERVER: 192.168.1.101#53(192.168.1.101) (UDP)
;; WHEN: Thu Mar 21 07:52:43 JST 2024
;; MSG SIZE  rcvd: 63
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this setup, your devices on the &lt;code&gt;192.168.1.0/24&lt;/code&gt; subnet can use the resolver at &lt;code&gt;192.168.1.101&lt;/code&gt; to resolve DNS queries. The resolver will handle queries for &lt;code&gt;mich0w0h.house&lt;/code&gt; by forwarding them to the authoritative nameserver while forwarding queries for other domains to external DNS servers.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Next
&lt;/h2&gt;

&lt;p&gt;next, I'll use docker compose to build the authoritative nameserver container I set up in the previous article and the recursive resolver container I set up in this article.&lt;/p&gt;

&lt;p&gt;It is necessary to configure networking in order to access these containers from other devices on the home network. (Yes, indeed currently these containers can only be accessed from the Ubuntu server on the host machine.)&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.sbcr.jp/product/4797394481/"&gt;DNSがよくわかる教科書 | SBクリエイティブ&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.shuwasystem.co.jp/book/9784798071503.html"&gt;開発系エンジニアのためのDocker絵とき入門 - 秀和システム あなたの学びをサポート！&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://unbound.docs.nlnetlabs.nl/en/latest/getting-started/configuration.html"&gt;Configuration — Unbound 1.19.3 documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nlnetlabs.nl/documentation/unbound/unbound-checkconf/"&gt;NLnet Labs Documentation - Unbound - unbound-checkconf.8&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nlnetlabs.nl/documentation/unbound/unbound.conf/"&gt;NLnet Labs Documentation - Unbound - unbound.conf.5&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://unbound.docs.nlnetlabs.nl/en/latest/use-cases/home-resolver.html"&gt;Resolver for Home Networks — Unbound 1.19.3 documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://qiita.com/miwamoto/items/7981c390ac876a7fac5e"&gt;Docker+DNS入門　その2：Unboundを用いたキャッシュDNSサーバ構築 #Docker - Qiita&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>unbound</category>
      <category>ubuntu</category>
      <category>dns</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Setting up a CoreDNS Server for Local Custom Domain Management on Ubuntu Using Docker</title>
      <dc:creator>mich0w0h</dc:creator>
      <pubDate>Tue, 19 Mar 2024 03:16:55 +0000</pubDate>
      <link>https://dev.to/mich0w0h/setting-up-a-coredns-server-for-local-custom-domain-management-on-ubuntu-using-docker-meo</link>
      <guid>https://dev.to/mich0w0h/setting-up-a-coredns-server-for-local-custom-domain-management-on-ubuntu-using-docker-meo</guid>
      <description>&lt;p&gt;I recently embarked on a journey to set up a CoreDNS server as an authoritative nameserver on my Ubuntu machine to manage a local custom domain, &lt;code&gt;mich0w0h.house&lt;/code&gt;, within my home network. This post is one part of building a local DNS service using docker-compose and I'll write other remaining parts later.&lt;/p&gt;

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

&lt;p&gt;Before diving in, let's take a quick look at the directory structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;internal-dns
│
└── authoritative
    │
    ├── Corefile
    └── zone
        └── mich0w0h.house.db
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Make sure Docker is installed and running on your Ubuntu server.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating the Corefile
&lt;/h2&gt;

&lt;p&gt;The Corefile is where we define our CoreDNS configuration. Here's what mine looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mich0w0h.house {
    file /etc/coredns/zone/mich0w0h.house.db
    log
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;The first line defines zone for this server  (default DNS port is 53).&lt;/li&gt;
&lt;li&gt;file /path/to/your/mich0w0h.house.db tells CoreDNS to load the zone file for your domain.&lt;/li&gt;
&lt;li&gt;log enables logging
## Creating the Zone File&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, let's create the zone file &lt;code&gt;mich0w0h.house.db&lt;/code&gt; with our DNS records. Here's a snippet of what mine looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$TTL 2d
$ORIGIN mich0w0h.house.

@       IN    SOA      ns1.mich0w0h.house. mail.mich0w0h.house. (
                       2024031801  
                       3600       
                       600        
                       86400      
                       3600       
                       )
; Name server resource record for the domain
          IN     NS      ns1.mich0w0h.house.

; Domain hosts includes NS records defined above
ns1     IN     A       192.168.1.102
www     IN     A       192.168.1.103
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Creating a Docker network
&lt;/h2&gt;

&lt;p&gt;Create a Docker network to enable the container to be accessed by a static IP address.&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="nb"&gt;sudo &lt;/span&gt;docker network create &lt;span class="nt"&gt;--subnet&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;192.168.1.0/24 internal-dns
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Running the CoreDNS Container
&lt;/h2&gt;

&lt;p&gt;Now, let's fire up the CoreDNS container (run this command in &lt;code&gt;internal-dns&lt;/code&gt; directory):&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="nb"&gt;sudo &lt;/span&gt;docker container run &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;--name&lt;/span&gt; authoritative &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;pwd&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;/authoritative:/etc/coredns &lt;span class="nt"&gt;--network&lt;/span&gt; internal-dns &lt;span class="nt"&gt;--ip&lt;/span&gt; 192.168.1.102 coredns/coredns &lt;span class="nt"&gt;-conf&lt;/span&gt; /etc/coredns/Corefile
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;command explanations&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;--rm&lt;/code&gt;: remove container when it stops&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-d&lt;/code&gt;: Runs the container in detached mode (background).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--name authoritative&lt;/code&gt;: Assigns a name to the container for easier management.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-v $(pwd)/authoritative:/etc/coredns&lt;/code&gt;: Mounts the directory containing your Corefile into the /etc/coredns directory inside the container. This allows CoreDNS to access your configuration files.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-network internal-dns&lt;/code&gt;: Specifies the Docker network created at the preliminary step.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--ip 192.168.1.102&lt;/code&gt;: Set a static IP address for this container. This should be inside of the subnet of specified Docker network&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;coredns/coredns&lt;/code&gt;: Specifies the Docker image to use. &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-conf /etc/coredns/Corefile&lt;/code&gt;: let CoreDNS read &lt;code&gt;/etc/coredns/Corefile&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Testing with Dig
&lt;/h2&gt;

&lt;p&gt;Finally, let's test our setup using &lt;code&gt;dig&lt;/code&gt; on the host ubuntu server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dig +nocookie @192.168.1.102 ns1.mich0w0h.house 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now I can see these outputs and it shows the configurations work correctly.&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="p"&gt;;&lt;/span&gt; &amp;lt;&amp;lt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; DiG 9.18.18-0ubuntu0.22.04.2-Ubuntu &amp;lt;&amp;lt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; +nocookie @192.168.1.102 ns1.mich0w0h.house
&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;1 server found&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;;;&lt;/span&gt; global options: +cmd
&lt;span class="p"&gt;;;&lt;/span&gt; Got answer:
&lt;span class="p"&gt;;;&lt;/span&gt; -&amp;gt;&amp;gt;HEADER&lt;span class="o"&gt;&amp;lt;&amp;lt;-&lt;/span&gt; &lt;span class="no"&gt;opcode&lt;/span&gt;&lt;span class="sh"&gt;: QUERY, status: NOERROR, id: 58701
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 1
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;ns1.mich0w0h.house.        IN  A

;; ANSWER SECTION:
ns1.mich0w0h.house. 172800  IN  A   192.168.1.102

;; AUTHORITY SECTION:
mich0w0h.house.     172800  IN  NS  ns1.mich0w0h.house.

;; Query time: 3 msec
;; SERVER: 192.168.1.102#53(192.168.1.102) (UDP)
;; WHEN: Tue Mar 19 10:08:10 JST 2024
;; MSG SIZE  rcvd: 127
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What's next
&lt;/h2&gt;

&lt;p&gt;I'll try to create a recursive resolver container and then build a local internal DNS service using docker-compose.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.sbcr.jp/product/4797394481/"&gt;DNSがよくわかる教科書 | SBクリエイティブ&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.shuwasystem.co.jp/book/9784798071503.html"&gt;開発系エンジニアのためのDocker絵とき入門 - 秀和システム あなたの学びをサポート！&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://coredns.io/2017/07/23/corefile-explained/"&gt;Corefile Explained&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://qiita.com/miwamoto/items/2a8befac7135bd21e08a"&gt;Docker+DNS入門　その1：CoreDNSを用いた権威DNSサーバ構築 #Docker - Qiita&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>coredns</category>
      <category>ubuntu</category>
      <category>docker</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Configure SSH Key-Based Authentication for Ubuntu 22.04</title>
      <dc:creator>mich0w0h</dc:creator>
      <pubDate>Thu, 14 Mar 2024 02:23:10 +0000</pubDate>
      <link>https://dev.to/mich0w0h/configure-ssh-key-based-authentication-for-ubuntu-2204-4f11</link>
      <guid>https://dev.to/mich0w0h/configure-ssh-key-based-authentication-for-ubuntu-2204-4f11</guid>
      <description>&lt;p&gt;In this article, I'll share my experience setting up secure SSH access to my Ubuntu server using public key cryptography. This method eliminates the need to type passwords every time, making connections faster and more secure. Let's dive in!&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Local machine with a terminal window (e.g., Bash, PowerShell)&lt;/li&gt;
&lt;li&gt;Ubuntu server on the same local network&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Generating the Keys
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Open a terminal window&lt;/strong&gt; on your local machine.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Generate a key pair&lt;/strong&gt; using the following command, replacing &lt;code&gt;your_email@example.com&lt;/code&gt; with your actual email address:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   ssh-keygen &lt;span class="nt"&gt;-t&lt;/span&gt; ed25519 &lt;span class="nt"&gt;-C&lt;/span&gt; &lt;span class="s2"&gt;"your_email@example.com"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Press Enter to accept the default location (usually &lt;code&gt;~/.ssh&lt;/code&gt;) for saving the key pair. If prompted, enter a strong passphrase for added security (highly recommended). The private key will be named &lt;code&gt;id_ed25519&lt;/code&gt; (or &lt;code&gt;id_rsa&lt;/code&gt; for older SSH versions), and the public key will be named &lt;code&gt;id_ed25519.pub&lt;/code&gt; (or &lt;code&gt;id_rsa.pub&lt;/code&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  Copying the Public Key (with ssh-copy-id)
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Enable SSH password authentication&lt;/strong&gt; on the server temporarily (you can disable it later).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Copy the public key&lt;/strong&gt; to the server using &lt;code&gt;ssh-copy-id&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   ssh-copy-id &lt;span class="nt"&gt;-i&lt;/span&gt; ~/.ssh/id_ed25519.pub username@192.168.10.100
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replace &lt;code&gt;username&lt;/code&gt; with your server's username and &lt;code&gt;192.168.10.100&lt;/code&gt; with your server's IP address. Enter the server's password when prompted.&lt;/p&gt;

&lt;h2&gt;
  
  
  Connecting with SSH Keys
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;From your local machine&lt;/strong&gt;, try connecting to the server using SSH:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   ssh &lt;span class="nt"&gt;-i&lt;/span&gt; ~/.ssh/id_ed25519 username@192.168.10.100
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you set a passphrase, you'll be prompted to enter it now.&lt;/p&gt;

&lt;h2&gt;
  
  
  Disabling Password Authentication (Optional)
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;On the server&lt;/strong&gt;, edit the &lt;code&gt;sshd_config&lt;/code&gt; file using a text editor (e.g., &lt;code&gt;nano&lt;/code&gt;):
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   &lt;span class="nb"&gt;sudo &lt;/span&gt;nano /etc/ssh/sshd_config
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Locate the line&lt;/strong&gt; that reads &lt;code&gt;#PasswordAuthentication yes&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Uncomment&lt;/strong&gt; the line by removing the &lt;code&gt;#&lt;/code&gt; symbol at the beginning and set &lt;code&gt;PasswordAuthentication no&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Search for any included configuration files&lt;/strong&gt; (e.g., &lt;code&gt;sshd_config.d/*&lt;/code&gt;) that might override &lt;code&gt;PasswordAuthentication&lt;/code&gt; settings. Edit them if necessary to set &lt;code&gt;PasswordAuthentication no&lt;/code&gt;. (in my case &lt;code&gt;PasswordAuthentication yes&lt;/code&gt; was set by default in &lt;code&gt;/etc/sshd_config.d/&lt;/code&gt; and it overwrote the configuration of &lt;code&gt;ssh_config&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Save the changes&lt;/strong&gt; and &lt;strong&gt;restart the SSH service&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   &lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl restart ssh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Host-Specific Configuration (Optional):&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;On your local machine&lt;/strong&gt;, create a new file named &lt;code&gt;config&lt;/code&gt; (if it doesn't exist) inside the &lt;code&gt;~/.ssh&lt;/code&gt; directory using a text editor.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Add the following lines&lt;/strong&gt; to the &lt;code&gt;config&lt;/code&gt; file, replacing &lt;code&gt;192.168.10.100&lt;/code&gt; with your actual server's address, &lt;code&gt;username&lt;/code&gt; with your server's username, and &lt;code&gt;id_ed25519&lt;/code&gt; with the actual filename of your private key (if different):&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   Host 192.168.10.100
       User username
       IdentityFile ~/.ssh/id_ed25519
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, whenever you use &lt;code&gt;ssh username@192.168.10.100&lt;/code&gt;, OpenSSH will automatically use the appropriate key for a streamlined connection.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Connecting with Ease:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Finally, test your connection! Simply run the following command from your local machine:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh username@192.168.10.100
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should be logged in to your server without needing to enter a password!&lt;/p&gt;

&lt;p&gt;References&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://serverfault.com/questions/1131267/disabling-password-authentication-not-working"&gt;ssh - Disabling password authentication not working - Server Fault&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://info.nikkeibp.co.jp/media/LIN/atcl/books/081600038/"&gt;作りながら学ぶ　Webシステムの教科書｜日経Linux&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ubuntu</category>
      <category>linux</category>
      <category>ssh</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Configure Static IP in Ubuntu 22.04</title>
      <dc:creator>mich0w0h</dc:creator>
      <pubDate>Wed, 13 Mar 2024 18:53:50 +0000</pubDate>
      <link>https://dev.to/mich0w0h/configure-static-ip-in-ubuntu-2204-2fd7</link>
      <guid>https://dev.to/mich0w0h/configure-static-ip-in-ubuntu-2204-2fd7</guid>
      <description>&lt;h1&gt;
  
  
  Configuring Ubuntu 22.04 to Use a Static IP Address
&lt;/h1&gt;

&lt;p&gt;In this article, I'll go through the steps to configure a static IP address on Ubuntu 22.04 while using a WiFi connection.&lt;/p&gt;

&lt;p&gt;Note that my Ubuntu Server used a DHCP-assigned IPv4 address on a WiFi connection before working on this setup.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before proceeding, you need to gather some information:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Check the IP address of the default gateway:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ip route show default
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command will show the default route and the corresponding gateway IP address.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Check the subnet mask:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ip addr show
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command will display the IP addresses and subnet masks for all interfaces.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Note the gateway address and desired static IP address to assign
In my case, the gateway address is &lt;code&gt;192.168.10.1&lt;/code&gt;, and I decided to assign the static IP address &lt;code&gt;192.168.10.100/24&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Configuring the Static IP Address
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Open the network configuration file with a text editor. For example, using &lt;code&gt;nano&lt;/code&gt;:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;nano /etc/netplan/&amp;lt;target-configuration-file&amp;gt;.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In my case, I'm using a WiFi connection, so I'll choose the WiFi-specific configuration file.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Modify the configuration file by adding the following lines under the &lt;code&gt;wifis&lt;/code&gt; section for your WiFi interface (e.g., &lt;code&gt;wlan0&lt;/code&gt;):
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;wifis&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;wlan0&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;dhcp4&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;no&lt;/span&gt;
    &lt;span class="na"&gt;addresses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;192.168.10.100/24&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;routes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;default&lt;/span&gt;
        &lt;span class="na"&gt;via&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;192.168.10.1&lt;/span&gt;
    &lt;span class="na"&gt;nameservers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;addresses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;192.168.10.1&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;8.8.8.8&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;8.8.4.4&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;addresses and default routes will be the ones you've noted above.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Verify the new network configuration:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;netplan try
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command will check the syntax of the configuration file and show you the changes that will be made. You might see a warning about &lt;code&gt;ovsdb-server.service&lt;/code&gt; not running, but you can ignore it for now.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;If the verification is successful, apply the new network configuration:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;netplan apply
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Verify that the static IP address has been assigned correctly:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ip addr show
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see your new static IP address listed under the WiFi interface (&lt;code&gt;wlan0&lt;/code&gt;).&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Verify the connection by pinging the static IP address from another device on the same home network:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ping 192.168.10.100
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And yes! It worked!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;PING 192.168.10.100 &lt;span class="o"&gt;(&lt;/span&gt;192.168.10.100&lt;span class="o"&gt;)&lt;/span&gt;: 56 data bytes
  64 bytes from 192.168.10.100: &lt;span class="nv"&gt;icmp_seq&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0 &lt;span class="nv"&gt;ttl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;64 &lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;54.810 ms
  64 bytes from 192.168.10.100: &lt;span class="nv"&gt;icmp_seq&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 &lt;span class="nv"&gt;ttl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;64 &lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;68.789 ms
  64 bytes from 192.168.10.100: &lt;span class="nv"&gt;icmp_seq&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;2 &lt;span class="nv"&gt;ttl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;64 &lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;85.646 ms
  64 bytes from 192.168.10.100: &lt;span class="nv"&gt;icmp_seq&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;3 &lt;span class="nv"&gt;ttl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;64 &lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;106.507 ms
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it! You've successfully configured Ubuntu 22.04 to use a static IP address on your WiFi connection.&lt;/p&gt;

&lt;h1&gt;
  
  
  References
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://netplan.io/"&gt;Canonical Netplan&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://info.nikkeibp.co.jp/media/LIN/atcl/books/081600038/"&gt;作りながら学ぶ　Webシステムの教科書｜日経Linux&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ubuntu</category>
      <category>network</category>
      <category>linux</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Troubleshooting: Deno Extension Activation in VSCode with Monorepo Environments</title>
      <dc:creator>mich0w0h</dc:creator>
      <pubDate>Mon, 05 Feb 2024 22:07:40 +0000</pubDate>
      <link>https://dev.to/mich0w0h/deno-extension-formatter-in-vscode-a-guide-for-monorepo-environments-4k4b</link>
      <guid>https://dev.to/mich0w0h/deno-extension-formatter-in-vscode-a-guide-for-monorepo-environments-4k4b</guid>
      <description>&lt;h2&gt;
  
  
  Troubleshooting Deno Extension Activation in VSCode
&lt;/h2&gt;

&lt;p&gt;I faced an issue when enabling the Deno extension in VSCode and I decided to take notes for future reference.&lt;/p&gt;

&lt;h3&gt;
  
  
  Enabling Deno Extension
&lt;/h3&gt;

&lt;p&gt;To enable the &lt;a href="https://docs.deno.com/runtime/manual/references/vscode_deno/"&gt;Deno extension&lt;/a&gt;  in VSCode, you need to place &lt;code&gt;.vscode/settings.json&lt;/code&gt; in the workspace root.&lt;/p&gt;

&lt;p&gt;The contents of &lt;code&gt;settings.json&lt;/code&gt; are as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"deno.enable"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"editor.formatOnSave"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"editor.defaultFormatter"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"denoland.vscode-deno"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Issue in Monorepo Environment
&lt;/h3&gt;

&lt;p&gt;In a monorepo environment, placing the &lt;code&gt;project-root&lt;/code&gt; directory in the workspace root will not work as expected.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;project-root/
    &lt;span class="nt"&gt;--&lt;/span&gt; backend/
        &lt;span class="nt"&gt;--&lt;/span&gt; .vscode/
            &lt;span class="nt"&gt;--&lt;/span&gt; settings.json
    &lt;span class="nt"&gt;--&lt;/span&gt; frontend/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Conversely, placing &lt;code&gt;settings.json&lt;/code&gt; in a subdirectory of &lt;code&gt;project-root&lt;/code&gt; will activate the Deno formatter in the frontend directory as well:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;project-root/
    &lt;span class="nt"&gt;--&lt;/span&gt; .vscode/
        &lt;span class="nt"&gt;--&lt;/span&gt; settings.json
    &lt;span class="nt"&gt;--&lt;/span&gt; backend/
    &lt;span class="nt"&gt;--&lt;/span&gt; frontend/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, adding &lt;code&gt;.vscode/setting.json&lt;/code&gt; to overwrite settings didn't work, still causing activation in the frontend directory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;project-root/
    &lt;span class="nt"&gt;--&lt;/span&gt; .vscode/
        &lt;span class="nt"&gt;--&lt;/span&gt; settings.json
    &lt;span class="nt"&gt;--&lt;/span&gt; backend/
    &lt;span class="nt"&gt;--&lt;/span&gt; frontend/
        &lt;span class="nt"&gt;--&lt;/span&gt; .vscode/
            &lt;span class="nt"&gt;--&lt;/span&gt; settings.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "deno.enable": false,
  "editor.defaultFormatter": "esbenp.prettier-vscode"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Solution 1: Configure &lt;code&gt;deno.enablePaths&lt;/code&gt; in &lt;code&gt;settings.json&lt;/code&gt; in the project root
&lt;/h3&gt;

&lt;p&gt;This solution seems to be more appropriate since it's mentioned in &lt;a href="https://docs.deno.com/runtime/manual/references/vscode_deno/"&gt;the official article&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The directory structure is;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;project-root/
    &lt;span class="nt"&gt;--&lt;/span&gt; .vscode/
        &lt;span class="nt"&gt;--&lt;/span&gt; settings.json
    &lt;span class="nt"&gt;--&lt;/span&gt; backend/
    &lt;span class="nt"&gt;--&lt;/span&gt; frontend/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the contents of &lt;code&gt;setting.json&lt;/code&gt; is here;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "deno.enable": true,
  "deno.enablePaths": [
    "./backend"
  ],
  "editor.formatOnSave": true,
  "editor.defaultFormatter": "denoland.vscode-deno"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This enables Deno extension only in the backend directory.&lt;/p&gt;

&lt;h3&gt;
  
  
  Solution 2: Open VSCode workspace with the backend directory as the root
&lt;/h3&gt;

&lt;p&gt;Only "Solution 1" is enough for this troubleshooting but I want to leave a trail of things I've tried. That's why I'll write down this solution 2 so you probably don't have to look through this one.&lt;/p&gt;

&lt;p&gt;By placing &lt;code&gt;settings.json&lt;/code&gt; in a subdirectory of the backend directory and opening the VSCode workspace with the backend directory as the root, it will work properly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;// move to the backend directory from project root
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;backend

// open the VScode workspace
&lt;span class="nv"&gt;$ &lt;/span&gt;code &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The directory structure would be like this.&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="nt"&gt;--&lt;/span&gt; backend/
    &lt;span class="nt"&gt;--&lt;/span&gt; .vscode/
        &lt;span class="nt"&gt;--&lt;/span&gt; settings.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The frontend directory needs to be developed separately in VSCode as a separate workspace.&lt;/p&gt;

</description>
      <category>deno</category>
      <category>vscode</category>
      <category>formatter</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Problem Encountered with CORS in Deno Server</title>
      <dc:creator>mich0w0h</dc:creator>
      <pubDate>Sun, 04 Feb 2024 23:28:10 +0000</pubDate>
      <link>https://dev.to/mich0w0h/problem-encountered-with-cors-in-deno-server-30ob</link>
      <guid>https://dev.to/mich0w0h/problem-encountered-with-cors-in-deno-server-30ob</guid>
      <description>&lt;h2&gt;
  
  
  Problem Encountered with CORS in Deno Server
&lt;/h2&gt;

&lt;p&gt;Recently, I encountered an issue while developing a server using Deno. My objective was to enable CORS (Cross-Origin Resource Sharing) requests utilizing the &lt;code&gt;oakCors&lt;/code&gt; middleware. Despite setting it up as per the &lt;a href="https://deno.land/x/cors@v1.2.2"&gt;documentation&lt;/a&gt;, CORS handling did not function as expected.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Scenario
&lt;/h3&gt;

&lt;p&gt;I employed Deno's Oak framework to create the server and handle incoming requests from the frontend. Below is a snippet of the code used (some parts are modified for brevity and clarity):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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;Application&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Router&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;https://deno.land/x/oak/mod.ts&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;oakCors&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;https://deno.land/x/cors/mod.ts&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;router&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;Router&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;router&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;context&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;body&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;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;body&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;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;text&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;app&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;Application&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="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;routes&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="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;allowedMethods&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

&lt;span class="c1"&gt;// Enabling CORS for port 5173 on localhost using oakCors&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;oakCors&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http://localhost:5173&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;optionsSuccessStatus&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;methods&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;POST, OPTIONS&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;}),&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;await&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="na"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;8000&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Despite configuring the server to accept CORS requests from &lt;code&gt;http://localhost:5173&lt;/code&gt;, requests to the server were being rejected due to CORS errors.&lt;/p&gt;

&lt;h3&gt;
  
  
  Analysis
&lt;/h3&gt;

&lt;p&gt;It appears that the 'oakCors' middleware is not working correctly, and the CORS headers are not being added, as indicated by the error message I received:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Access to fetch at 'http://localhost:8000/api/generate' from origin 'http://localhost:5173' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Solution
&lt;/h3&gt;

&lt;p&gt;After some trial and error, I discovered that moving the configuration of &lt;code&gt;oakCors&lt;/code&gt; before defining the routes resolved the issue.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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;Application&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Router&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;https://deno.land/x/oak/mod.ts&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;oakCors&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;https://deno.land/x/cors/mod.ts&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="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Application&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Enabling CORS for port 5173 on localhost using oakCors&lt;/span&gt;
&lt;span class="c1"&gt;// make sure to initialize oakCors before the routers&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;oakCors&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http://localhost:5173&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;optionsSuccessStatus&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;methods&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;POST, OPTIONS&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;}),&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;router&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;Router&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;router&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;context&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;body&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;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;body&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;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;());&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="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;routes&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="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;allowedMethods&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

&lt;span class="k"&gt;await&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="na"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;8000&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I learned that I should configure middleware before the routes' are defined.&lt;/p&gt;

&lt;h3&gt;
  
  
  Remaining Challenge
&lt;/h3&gt;

&lt;p&gt;According to the chapter "Enable CORS for a Single Route" of &lt;a href="https://deno.land/x/cors@v1.2.2"&gt;the official docs&lt;/a&gt;, these codes would work but didn't.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const corsOptions: oakCors.Options = {
  origin: "http://localhost:5173",
  optionsSuccessStatus: 200,
};

router.post("/", oakCors(corsOptions), (context) =&amp;gt; {
    const body = await context.request.body;
    console.log(body.text());
});

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

&lt;/div&gt;



&lt;p&gt;Although this issue remains unresolved at present, it does not impede the functionality of the server as I have implemented a workaround that meets my current requirements.&lt;/p&gt;

</description>
      <category>deno</category>
      <category>cors</category>
      <category>webdev</category>
      <category>oakcors</category>
    </item>
    <item>
      <title>React: How to tackle useEffect called twice</title>
      <dc:creator>mich0w0h</dc:creator>
      <pubDate>Tue, 09 Jan 2024 07:03:46 +0000</pubDate>
      <link>https://dev.to/mich0w0h/react-how-to-tackle-useeffect-called-twice-onh</link>
      <guid>https://dev.to/mich0w0h/react-how-to-tackle-useeffect-called-twice-onh</guid>
      <description>&lt;p&gt;This is a continuation of this post: &lt;a href="https://dev.to/mich0w0h/react-blink-characters-eyes-4bak"&gt;React: Blink Character's Eyes - DEV Community&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What's the issue
&lt;/h2&gt;

&lt;p&gt;In my React web app, it seemed that the useEffect called twice although I wanted to call a function inside it.&lt;/p&gt;

&lt;p&gt;Here's the code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;blinkWithTimer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3000&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;blinkWithTimer&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;timer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="o"&gt;&amp;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;interval&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1500&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;blinkEyes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// One blink&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Delay after one blink&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;blinkEyes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Two blinks&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Delay after two blinks&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;blinkEyes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// One final blink&lt;/span&gt;
    &lt;span class="nf"&gt;setTimeout&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;blinkWithTimer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;timer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;timer&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;h2&gt;
  
  
  What's happening there
&lt;/h2&gt;

&lt;p&gt;It turned out that React 18 runs &lt;code&gt;useEffect&lt;/code&gt; twice when it renders the component in the development environment even if the dependency array is empty.&lt;/p&gt;

&lt;p&gt;Reference:&lt;br&gt;
&lt;a href="https://byby.dev/useeffect-run-twice"&gt;How to stop useEffect run twice since React 18&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  How to tackle this
&lt;/h2&gt;

&lt;p&gt;Regarding my codes, I want to run the &lt;code&gt;blinkWithInterval()&lt;/code&gt; only once after the page is loaded.&lt;/p&gt;

&lt;p&gt;So this time around, I used &lt;code&gt;useRef&lt;/code&gt; valuable and simply checked whether it's already run or not.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;hasMounted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useRef&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&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;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="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;hasMounted&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;hasMounted&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;initialize&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nf"&gt;blinkWithTimer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3000&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="c1"&gt;// called when the component is unmounted&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;p&gt;I read through &lt;a href="https://react.dev/learn/you-might-not-need-an-effect"&gt;You Might Not Need an Effect – React&lt;/a&gt; but I had no idea how to implement the alternative to above codes without &lt;code&gt;useEffect&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;As a result, my requirement of calling &lt;code&gt;blinkWithTimer()&lt;/code&gt; only once has been accomplished so I ended this issue here for this time.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>React: Blink Character's Eyes</title>
      <dc:creator>mich0w0h</dc:creator>
      <pubDate>Mon, 08 Jan 2024 04:46:20 +0000</pubDate>
      <link>https://dev.to/mich0w0h/react-blink-characters-eyes-4bak</link>
      <guid>https://dev.to/mich0w0h/react-blink-characters-eyes-4bak</guid>
      <description>&lt;p&gt;This is a continuation of this post: &lt;a href="https://dev.to/mich0w0h/web-animation-twitch-ears-twice-in-a-row-50bb"&gt;Web Animation: Twitch ears twice in a row - DEV Community&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I want to achieve
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;blink the character's eyes in a web app made of React + Typescript&lt;/li&gt;
&lt;li&gt;make it flexible to change the number of blink times&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Blink once
&lt;/h2&gt;

&lt;p&gt;Firstly, implement the simplest blink motion, blinking once.&lt;/p&gt;

&lt;p&gt;Write a state boolean valuable which manages the blinking.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;blinking&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setBlinking&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;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the eyes' elements are here;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"character-eyes"&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="nt"&gt;img&lt;/span&gt;
    &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;blinking&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/src/assets/character-eye-blink.png&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;/src/assets/character-eye-default.png&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="na"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Character Left eye"&lt;/span&gt;
    &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;blinking&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;character-eye-blink&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;character-eye-default&lt;/span&gt;&lt;span class="dl"&gt;"&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;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;img&lt;/span&gt;
    &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;blinking&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/src/assets/character-eye-blink.png&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;/src/assets/character-eye-default.png&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="na"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Character Right eye"&lt;/span&gt;
    &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;blinking&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;character-eye-blink&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;character-eye-default&lt;/span&gt;&lt;span class="dl"&gt;"&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;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now just toggling the &lt;code&gt;blinking&lt;/code&gt; value allows the character's eyes to blink.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;delay&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ms&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;void&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;resolve&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ms&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;blinkEyes&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="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="o"&gt;&amp;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="na"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;130&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nf"&gt;setBlinking&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;await&lt;/span&gt; &lt;span class="nf"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;setBlinking&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;h2&gt;
  
  
  Blink several times
&lt;/h2&gt;

&lt;p&gt;It's easy to increase the number of blink times&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;blinkEyes&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;blinkCount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="o"&gt;&amp;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="na"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;130&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;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;blinkCount&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&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;setBlinking&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;await&lt;/span&gt; &lt;span class="nf"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nf"&gt;setBlinking&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="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;duration&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;p&gt;And by the &lt;code&gt;blinkEyes()&lt;/code&gt; function, I can make more complex blinking motions like "blink → delay → blink two times → delay → blink".&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;interval&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1500&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;blinkEyes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// One blink&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Delay after one blink&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;blinkEyes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Two blinks&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Delay after two blinks&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;blinkEyes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// One final blink&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Blink several times endlessly
&lt;/h2&gt;

&lt;p&gt;At this point, create an async function that endlessly triggers the series of blinks at certain intervals.&lt;/p&gt;

&lt;p&gt;Additionally, declare the &lt;code&gt;timeoutId&lt;/code&gt; to use the clearance of the timeout process.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;timeoutId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// for clearTimeout&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;blinkWithTimer&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;timer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="o"&gt;&amp;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;interval&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1500&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;blinkEyes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// One blink&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Delay after one blink&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;blinkEyes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Two blinks&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Delay after two blinks&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;blinkEyes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// One final blink&lt;/span&gt;
    &lt;span class="nx"&gt;timeoutId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;setTimeout&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;blinkWithTimer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;timer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;timer&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;Then write it in the &lt;code&gt;useEffect&lt;/code&gt; to call when the component is mounted. And call &lt;code&gt;clearTimeout()&lt;/code&gt; with the argument &lt;code&gt;timeoutId&lt;/code&gt; declared above to clear the timeout process when the component is unmounted.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;blinkWithTimer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3000&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="nf"&gt;clearTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;timeoutId&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a bit of a twist, I use &lt;code&gt;setTimeout()&lt;/code&gt; to make it flexible to change the duration and the frequency of blinks rather than using &lt;code&gt;setInterval()&lt;/code&gt; like this;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&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;blinkInterval&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;setInterval&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;blinkEyes&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;2500&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="nf"&gt;clearInterval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;blinkInterval&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;p&gt;In the codes above, I should adjust the second argument value of &lt;code&gt;setInterval()&lt;/code&gt; every time I change the duration and frequency of blinking, otherwise &lt;code&gt;blinkEyes()&lt;/code&gt; can be called even when the previous blinking hasn't ended yet.&lt;/p&gt;

&lt;h2&gt;
  
  
  Here you go!
&lt;/h2&gt;

&lt;p&gt;Notes: the ear motions are caused by another component. For more information, check this post; &lt;a href="https://dev.to/mich0w0h/web-animation-twitch-ears-twice-in-a-row-50bb"&gt;Web Animation: Twitch ears twice in a row - DEV Community&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frpiz18gjbdmnnt91neea.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frpiz18gjbdmnnt91neea.gif" alt="Blinking animation" width="600" height="573"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What's next
&lt;/h2&gt;

&lt;p&gt;There seems to be an issue that the &lt;code&gt;useEffect&lt;/code&gt; was called without clearing the timeout process after I edited the codes running the vite server and it automatically refreshed the page.&lt;/p&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>beginners</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Linux search: find a word next to a specific phrase</title>
      <dc:creator>mich0w0h</dc:creator>
      <pubDate>Fri, 05 Jan 2024 07:46:23 +0000</pubDate>
      <link>https://dev.to/mich0w0h/linux-search-find-a-word-next-to-a-specific-phrase-1pej</link>
      <guid>https://dev.to/mich0w0h/linux-search-find-a-word-next-to-a-specific-phrase-1pej</guid>
      <description>&lt;h2&gt;
  
  
  What I want to achieve
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Search a word next to a specific phrase in a file with the Linux shell command&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to tackle
&lt;/h2&gt;

&lt;p&gt;Use the &lt;code&gt;grep&lt;/code&gt; command and the &lt;code&gt;awk&lt;/code&gt; command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ grep -w "search_word" file_name | awk '{print $2}'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Explanations&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;by the &lt;code&gt;-w&lt;/code&gt; option &lt;code&gt;grep&lt;/code&gt; matches only whole words, preventing partial matches&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;{print $2}&lt;/code&gt; with &lt;code&gt;awk&lt;/code&gt; prints the second word on each line&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>Linux find: remove error lines from outputs</title>
      <dc:creator>mich0w0h</dc:creator>
      <pubDate>Thu, 04 Jan 2024 22:03:33 +0000</pubDate>
      <link>https://dev.to/mich0w0h/linux-find-remove-error-lines-from-outputs-559a</link>
      <guid>https://dev.to/mich0w0h/linux-find-remove-error-lines-from-outputs-559a</guid>
      <description>&lt;h2&gt;
  
  
  What I want to achieve
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;find a specific file which I have read permission for&lt;/li&gt;
&lt;li&gt;ignore error lines of "Permission denied"&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What didn't work
&lt;/h2&gt;

&lt;p&gt;Firstly I tried this command to remove the "Permission denied" lines.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ find /path/ -readable | grep -v "denied"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, it didn't work.&lt;/p&gt;

&lt;p&gt;That's because the error messages are on a separate stream from the &lt;code&gt;grep&lt;/code&gt; targets.&lt;/p&gt;

&lt;p&gt;The "Permission denied" messages are printed to the standard error stream (stderr), while the &lt;code&gt;grep&lt;/code&gt; command only filters the standard output stream (stdout).&lt;/p&gt;

&lt;h2&gt;
  
  
  How to tackle
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Redirect both output streams using &lt;code&gt;2&amp;gt;&amp;amp;1&lt;/code&gt; which redirects stderr(file descriptor 2) to stdout(file descriptor 1).
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ find /path/ -readable 2&amp;gt;&amp;amp;1 | grep -v "denied"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;suppress stderr putting away into &lt;code&gt;/dev/null/&lt;/code&gt;, a special file that discards any data written to it, effectively silencing stderr.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ find /path/ -readable 2&amp;gt;/dev/null
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
    </item>
    <item>
      <title>Web Animation: Twitch ears twice in a row</title>
      <dc:creator>mich0w0h</dc:creator>
      <pubDate>Thu, 04 Jan 2024 00:45:01 +0000</pubDate>
      <link>https://dev.to/mich0w0h/web-animation-twitch-ears-twice-in-a-row-50bb</link>
      <guid>https://dev.to/mich0w0h/web-animation-twitch-ears-twice-in-a-row-50bb</guid>
      <description>&lt;p&gt;This post is a continuation of &lt;a href="https://dev.to/mich0w0h/css-create-endless-twitching-ear-motion-with-a-certain-interval-467j"&gt;Web Animation: Create endless twitching ear motion with a certain interval&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I want to achieve
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;twitch a character's ears twice in a row in a web app project made of React + Typescript&lt;/li&gt;
&lt;li&gt;twitching motion itself has already been done in the previous article&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to implement
&lt;/h2&gt;

&lt;p&gt;Create a &lt;code&gt;Promise&lt;/code&gt; to implement a delay.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;delay&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ms&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ms&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, update the &lt;code&gt;twitchEars&lt;/code&gt; function into async one and insert delays between twitches in that function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;twitchEars&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;setTwitching&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;await&lt;/span&gt; &lt;span class="nf"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;twitchDuration&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;setTwitching&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="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Delay between the twitches&lt;/span&gt;

    &lt;span class="nf"&gt;setTwitching&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;await&lt;/span&gt; &lt;span class="nf"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;twitchDuration&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nf"&gt;setTwitching&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;For a bit of a twist, I used &lt;code&gt;async&lt;/code&gt; and &lt;code&gt;await&lt;/code&gt; instead of just implementing it by the sequence of several &lt;code&gt;setTimeout&lt;/code&gt;s.&lt;/p&gt;

&lt;h2&gt;
  
  
  Now I did it!
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmsevuo9xajvsjzn6guma.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmsevuo9xajvsjzn6guma.gif" alt="Image description" width="600" height="573"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Overall view of the component
&lt;/h2&gt;

&lt;p&gt;The overall view of the component so far is here.&lt;/p&gt;

&lt;p&gt;CharacterDisplay.tsx&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&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;useState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useEffect&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;react&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./CharacterDisplay.css&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;CharacterDisplay&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;twitching&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setTwitching&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;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;delay&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;ms&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ms&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="na"&gt;twitchDuration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;150&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;twitchInterval&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;setInterval&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;twitchEars&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;    &lt;span class="c1"&gt;// Interval between twitches&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="nf"&gt;clearInterval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;twitchInterval&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;twitchEars&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;setTwitching&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;await&lt;/span&gt; &lt;span class="nf"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;twitchDuration&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nf"&gt;setTwitching&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="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Delay between the twitches&lt;/span&gt;

        &lt;span class="nf"&gt;setTwitching&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;await&lt;/span&gt; &lt;span class="nf"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;twitchDuration&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="nf"&gt;setTwitching&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="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"character"&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="nt"&gt;img&lt;/span&gt; &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/src/assets/character-body.png"&lt;/span&gt; &lt;span class="na"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Character body"&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"character-body"&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="nt"&gt;img&lt;/span&gt;
                &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/src/assets/character-left-ear.png"&lt;/span&gt;
                &lt;span class="na"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Left ear"&lt;/span&gt;
                &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`ear left &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;twitching&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;twitch-left&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="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
                &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;twitchEars&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;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;img&lt;/span&gt;
                &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/src/assets/character-right-ear.png"&lt;/span&gt;
                &lt;span class="na"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Right ear"&lt;/span&gt;
                &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`ear right &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;twitching&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;twitch-right&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="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
                &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;twitchEars&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;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&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;};&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;CharacterDisplay&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;CharacterDisplay.css&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.character&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;relative&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;224px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
    &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;246px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.character-body&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;absolute&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.ear&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;absolute&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;40px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;40px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;transition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;transform&lt;/span&gt; &lt;span class="m"&gt;0.2s&lt;/span&gt; &lt;span class="n"&gt;ease&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.left&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;    
    &lt;span class="nl"&gt;left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;40px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.right&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;right&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;43px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.twitch-left&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;rotate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;-10deg&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.twitch-right&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;rotate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;10deg&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;



</description>
      <category>react</category>
      <category>javascript</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
