<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>Joie Blog Blog</title>
        <link>https://sudojoie.com/</link>
        <description>Joie Blog Blog</description>
        <lastBuildDate>Sat, 04 Apr 2026 00:00:00 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en</language>
        <item>
            <title><![CDATA[Picksy: An Open-Source Spin-the-Wheel Website With No Ads or Trackers]]></title>
            <link>https://sudojoie.com/picksy</link>
            <guid>https://sudojoie.com/picksy</guid>
            <pubDate>Sat, 04 Apr 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Picksy is an open-source spin-the-wheel web app for choosing a random name from a list without ads or trackers.]]></description>
            <content:encoded><![CDATA[<p>Picksy is a simple, open-source spin-the-wheel app for choosing a random name from a list without ads, trackers, or unnecessary clutter.</p>
<!-- -->
<p>I originally built this project about four years ago, then forgot about it. After rediscovering the repository, I decided to revisit it, finish what I started, and finally share it.</p>
<p>I first created it during the pandemic, when spin-the-wheel tools became popular for online team-building, virtual game nights with friends and family, and similar activities. Most of the available options were cluttered with ads and trackers, so I built a simpler alternative without either.</p>
<p>After refreshing the UI and updating the dependencies, the project is now complete.</p>
<p>You can try it here: <a href="https://picksy.sudojoie.com/" target="_blank" rel="noopener noreferrer" class="">Picksy</a></p>
<p>If you want to see the code or contribute, the project is available on GitHub: <a href="https://github.com/joiellantero/picksy" target="_blank" rel="noopener noreferrer" class="">joiellantero/picksy</a></p>
<p><img decoding="async" loading="lazy" alt="Picksy Website Screenshot" src="https://sudojoie.com/assets/images/picksy-screenshot-0de0a2413548587bbd019f2cf9cc4f19.png" width="3604" height="2264" class="img_ev3q"></p>
<p>This release also gave me a chance to revisit an older idea and clean it up into something I would actually use today: lightweight, straightforward, and easy to share.</p>
<p>If you prefer working in the terminal, I also made a Python-based version here: <a href="https://github.com/joiellantero/name-roulette" target="_blank" rel="noopener noreferrer" class="">name-roulette</a>.</p>]]></content:encoded>
            <category>Web Development</category>
            <category>JavaScript</category>
            <category>Open Source</category>
        </item>
        <item>
            <title><![CDATA[Read This Before You Click, Tap, or Respond: Outsmarting Phishing Scams]]></title>
            <link>https://sudojoie.com/outsmarting-phishing-scams</link>
            <guid>https://sudojoie.com/outsmarting-phishing-scams</guid>
            <pubDate>Sat, 21 Jun 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[Learn how to recognize and avoid phishing scams with practical tips that help you stay safe before you click.]]></description>
            <content:encoded><![CDATA[<p>Scams are getting smarter, whether through emails, texts, or phone calls. In this post, we break down how phishing, smishing, and vishing work, the warning signs to watch for, and how you can protect yourself from falling victim. Whether you're checking your inbox, reading a message, or answering a call, this guide will help you stay one step ahead.</p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="what-is-phishing">What is Phishing?<a href="https://sudojoie.com/outsmarting-phishing-scams#what-is-phishing" class="hash-link" aria-label="Direct link to What is Phishing?" title="Direct link to What is Phishing?" translate="no">​</a></h2>
<p>As defined in Merriam Webster, Phishing is...</p>
<blockquote>
<p>The practice of tricking Internet users into revealing personal or confidential information which can then be used illicitly.</p>
</blockquote>
<p>Phishing can come through email, SMS, or phone calls, from fake princes offering wealth to urgent bank alerts or fraud department calls. These are common tactics used to steal your information. Let’s explore how to spot phishing in any form.</p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="how-to-recognize-phishing">How to Recognize Phishing<a href="https://sudojoie.com/outsmarting-phishing-scams#how-to-recognize-phishing" class="hash-link" aria-label="Direct link to How to Recognize Phishing" title="Direct link to How to Recognize Phishing" translate="no">​</a></h2>
<h3 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="phishing-emails">Phishing Emails<a href="https://sudojoie.com/outsmarting-phishing-scams#phishing-emails" class="hash-link" aria-label="Direct link to Phishing Emails" title="Direct link to Phishing Emails" translate="no">​</a></h3>
<p>Let's check out the email below. Spot anything interesting?</p>
<div align="center"><img src="https://sudojoie.com/assets/images/p1-7039a3e833f644b1f1ec138b6cb24bc7.png" alt="phishing-email-sample"><br><small><em>Credits to hooksecurity.co for the image.</em></small></div>
<p>Here's what to look out for:</p>
<ul>
<li class="">Design</li>
<li class="">Address</li>
<li class="">Subject and body</li>
<li class="">Links</li>
</ul>
<p>Does this look like a real Microsoft email? Probably not - no logo, and a sketchy domain like <code>msupdate[.]net</code>. Let’s drop it into <a href="https://www.virustotal.com/" target="_blank" rel="noopener noreferrer" class="">VirusTotal</a>, a free tool that scans links with multiple antivirus engines, and see what turns up.</p>
<p>Well, that looks bad...</p>
<div align="center"><img src="https://sudojoie.com/assets/images/vt-020077dc32ba2ba0510340ba4708fcdc.png" alt="virustotal-result"></div>
<p>So, VirusTotal flagged the domain as malicious - yep, definitely not from Microsoft. That’s a big clue this email’s up to no good.</p>
<p>Even if just a few antivirus engines catch it, like 3 out of 94, that’s enough to raise an eyebrow. A lot of phishing sites are brand new, so they might not get flagged right away. That’s why it helps to look at the whole email: check the subject, the wording, any weird typos or bad grammar, and see if the message feels off. Ask yourself: does this even make sense for me? Do I have a Microsoft account? And if you’re unsure, you can always right-click any links, copy them, and run them through VirusTotal. Better safe than sorry!</p>
<h3 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="smishing-phishing-through-sms">Smishing (Phishing through SMS)<a href="https://sudojoie.com/outsmarting-phishing-scams#smishing-phishing-through-sms" class="hash-link" aria-label="Direct link to Smishing (Phishing through SMS)" title="Direct link to Smishing (Phishing through SMS)" translate="no">​</a></h3>
<p>Here’s how Smishing plays out in real life: a text pretending to be from the <a href="https://en.wikipedia.org/wiki/Philippine_Postal_Corporation" target="_blank" rel="noopener noreferrer" class="">Philippine Postal Corporation</a>, the country’s official postal service, trying to trick the recipient.</p>
<div align="center"><img src="https://sudojoie.com/assets/images/s1-122467f9ffeccbef5cb5b2f9a2484034.jpeg" alt="virustotal-result" width="500"></div>
<p>The biggest red flag? The link. A legit government agency wouldn’t use a <code>.com</code> - it should be <code>.gov.ph</code>. Plus, there's a typo, and I’m not even expecting a package. Definitely a Smishing attempt.</p>
<p>Just because a domain ends in <code>.gov.ph</code> or belongs to a government agency doesn’t always mean it’s safe. What if their system gets hacked? As mentioned earlier, it’s important to look at the entire message and ask yourself the right questions before trusting it.</p>
<h3 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="vishing-phishing-through-voice-calls">Vishing (Phishing through Voice Calls)<a href="https://sudojoie.com/outsmarting-phishing-scams#vishing-phishing-through-voice-calls" class="hash-link" aria-label="Direct link to Vishing (Phishing through Voice Calls)" title="Direct link to Vishing (Phishing through Voice Calls)" translate="no">​</a></h3>
<p>Vishing scams can catch you off guard, but staying safe is all about being cautious. If you get a call from someone you don’t know, especially if they’re asking for personal info or making things sound urgent, like “your account is locked” or “you’re under investigation,” take a step back. Don’t panic. Just hang up, and call the company or agency yourself using their official number. It’s always better to double-check than get tricked.</p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="protect-yourself-going-forward">Protect Yourself Going Forward<a href="https://sudojoie.com/outsmarting-phishing-scams#protect-yourself-going-forward" class="hash-link" aria-label="Direct link to Protect Yourself Going Forward" title="Direct link to Protect Yourself Going Forward" translate="no">​</a></h2>
<p>Phishing comes in many forms, but the goal is always the same: to trick you into handing over something valuable. The good news? A little awareness goes a long way. By staying curious, double-checking messages, and using tools like VirusTotal, you’re already making it harder for attackers to succeed. Keep your guard up, trust your instincts, and remember: it’s okay to pause before you click, tap, or respond. That moment of caution could save you a lot more than just your inbox.</p>]]></content:encoded>
            <category>Tutorial</category>
            <category>Awareness</category>
            <category>Cybersecurity</category>
            <category>Email Security</category>
        </item>
        <item>
            <title><![CDATA[List of Free Cybersecurity Tools and Resources]]></title>
            <link>https://sudojoie.com/list-of-free-cybersecurity-tools-and-resources</link>
            <guid>https://sudojoie.com/list-of-free-cybersecurity-tools-and-resources</guid>
            <pubDate>Sat, 10 Aug 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[A repository for a list of free cybersecurity tools that can be used for investigations and other cybersecurity purposes.]]></description>
            <content:encoded><![CDATA[<p>Cybersecurity tools can be quite expensive, and finding reliable free options is often a challenge. While free tools may not be as advanced as their paid counterparts, I believe they can still provide significant value. In this post, I've compiled a list of free tools I've discovered and tested so far, and I make an effort to keep it regularly updated.</p>
<h3 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="osints">OSINTs<a href="https://sudojoie.com/list-of-free-cybersecurity-tools-and-resources#osints" class="hash-link" aria-label="Direct link to OSINTs" title="Direct link to OSINTs" translate="no">​</a></h3>
<p>Useful tools for IOC-based and community-backed detections.</p>
<ul>
<li class=""><a href="https://www.virustotal.com/gui/home/search" target="_blank" rel="noopener noreferrer" class="">Virustotal</a> - URL, file, domain, IP, hash</li>
<li class=""><a href="https://talosintelligence.com/" target="_blank" rel="noopener noreferrer" class="">Cisco Talos</a> - domain, IP, email, sha256</li>
<li class=""><a href="https://www.abuseipdb.com/" target="_blank" rel="noopener noreferrer" class="">Abuse IPDB</a> - IP</li>
<li class=""><a href="https://search.censys.io/" target="_blank" rel="noopener noreferrer" class="">Censys</a> - hosts, certificates</li>
<li class=""><a href="https://exchange.xforce.ibmcloud.com/" target="_blank" rel="noopener noreferrer" class="">IBM X-Force</a> - URL, IP, domain, email, cve, cidr, hash, mutex, yara</li>
<li class=""><a href="https://otx.alienvault.com/" target="_blank" rel="noopener noreferrer" class="">Open Threat</a> - URL, IP, domain, email, cve, cidr, hash, mutex, yara</li>
<li class=""><a href="https://whois.domaintools.com/" target="_blank" rel="noopener noreferrer" class="">Domain Tools</a> - check domain info</li>
<li class=""><a href="https://www.threatminer.org/" target="_blank" rel="noopener noreferrer" class="">Threat Miner</a> - IP, domain, hash, email, ssl cert, file, registry, mutex <em>expired domain</em></li>
<li class=""><a href="http://ci-www.threatcrowd.org/" target="_blank" rel="noopener noreferrer" class="">Threat Crowd</a></li>
<li class=""><a href="https://github.com/sherlock-project/sherlock" target="_blank" rel="noopener noreferrer" class="">Sherlock</a> - Social media OSINT</li>
</ul>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>What is a mutex?</div><div class="admonitionContent_BuS1"><p>Mutex is a type of object used by programs for multithreading to avoid threads writing into the same shared memory. Reference: <a href="https://www.sans.org/blog/looking-at-mutex-objects-for-malware-discovery-indicators-of-compromise/" target="_blank" rel="noopener noreferrer" class="">SANS</a>.</p></div></div>
<h3 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="sandbox">Sandbox<a href="https://sudojoie.com/list-of-free-cybersecurity-tools-and-resources#sandbox" class="hash-link" aria-label="Direct link to Sandbox" title="Direct link to Sandbox" translate="no">​</a></h3>
<p>Useful tools to check suspicious website or detonate malicious files.</p>
<ul>
<li class=""><a href="https://www.browserling.com/" target="_blank" rel="noopener noreferrer" class="">Browserling</a> - Interact with websites</li>
<li class=""><a href="https://www.hybrid-analysis.com/" target="_blank" rel="noopener noreferrer" class="">Hybrid Analysis</a> - Malware file sandboxing</li>
</ul>
<h3 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="phishing-analysis">Phishing Analysis<a href="https://sudojoie.com/list-of-free-cybersecurity-tools-and-resources#phishing-analysis" class="hash-link" aria-label="Direct link to Phishing Analysis" title="Direct link to Phishing Analysis" translate="no">​</a></h3>
<p>Useful tools to aid when performing phishing analysis</p>
<ul>
<li class=""><a href="https://toolbox.googleapps.com/apps/messageheader/" target="_blank" rel="noopener noreferrer" class="">Google Admin Toolbox</a> - Email header analyzer</li>
<li class=""><a href="https://phishtank.org/" target="_blank" rel="noopener noreferrer" class="">PhishTank</a> - A public threat feed that provides intelligence regarding phishing attacks and malicious artifacts</li>
<li class=""><a href="https://dnstwist.it/" target="_blank" rel="noopener noreferrer" class="">DNS Twist</a> - A phishing domain scanner</li>
<li class=""><a href="https://www.punycoder.com/" target="_blank" rel="noopener noreferrer" class="">PunyCoder</a> - A tool to check for homographs</li>
<li class=""><a href="https://www.wannabrowser.net/" target="_blank" rel="noopener noreferrer" class="">Wannabrowser</a> - A tool to check the destination URL of shortened URLs</li>
<li class=""><a href="https://mxtoolbox.com/ReverseLookup.aspx" target="_blank" rel="noopener noreferrer" class="">DNS Reverse Lookup</a> - Useful to reverse DNS the <code>x-sender-ip</code></li>
<li class=""><a href="https://www.phishtool.com/" target="_blank" rel="noopener noreferrer" class="">PhishTool</a> - Easier way to gather email artifacts</li>
</ul>
<h3 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="data-manipulation">Data Manipulation<a href="https://sudojoie.com/list-of-free-cybersecurity-tools-and-resources#data-manipulation" class="hash-link" aria-label="Direct link to Data Manipulation" title="Direct link to Data Manipulation" translate="no">​</a></h3>
<p>Useful tool to encode, decode, hash, encrypt, decrypt, and more.</p>
<ul>
<li class=""><a href="https://gchq.github.io/CyberChef/" target="_blank" rel="noopener noreferrer" class="">CyberChef</a></li>
</ul>
<h3 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="mitre-attck-framework">MITRE ATT&amp;CK Framework<a href="https://sudojoie.com/list-of-free-cybersecurity-tools-and-resources#mitre-attck-framework" class="hash-link" aria-label="Direct link to MITRE ATT&amp;CK Framework" title="Direct link to MITRE ATT&amp;CK Framework" translate="no">​</a></h3>
<ul>
<li class=""><a href="https://mitre-attack.github.io/attack-navigator/enterprise/" target="_blank" rel="noopener noreferrer" class="">Attack Navigator platform</a></li>
</ul>
<h3 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="security-vendor-threat-blogs">Security Vendor Threat Blogs<a href="https://sudojoie.com/list-of-free-cybersecurity-tools-and-resources#security-vendor-threat-blogs" class="hash-link" aria-label="Direct link to Security Vendor Threat Blogs" title="Direct link to Security Vendor Threat Blogs" translate="no">​</a></h3>
<ul>
<li class=""><a href="https://www.crowdstrike.com/blog/" target="_blank" rel="noopener noreferrer" class="">CrowdStrike</a></li>
<li class=""><a href="https://community.riskiq.com/research" target="_blank" rel="noopener noreferrer" class="">RiskIQ Articles</a></li>
<li class=""><a href="https://blog.paloaltonetworks.com/author/unit-42/" target="_blank" rel="noopener noreferrer" class="">PaloAlto's Unit42</a></li>
<li class=""><a href="https://blog.talosintelligence.com/" target="_blank" rel="noopener noreferrer" class="">Cisco Talos</a></li>
<li class=""><a href="https://intel471.com/blog/" target="_blank" rel="noopener noreferrer" class="">Intel471</a></li>
<li class=""><a href="https://www.digitalshadows.com/blog-and-research/" target="_blank" rel="noopener noreferrer" class="">digital_shadows</a></li>
<li class=""><a href="https://threatconnect.com/blog/" target="_blank" rel="noopener noreferrer" class="">ThreatConnect Blog</a></li>
<li class=""><a href="https://www.domaintools.com/" target="_blank" rel="noopener noreferrer" class="">DomainTools Blog</a></li>
</ul>]]></content:encoded>
            <category>Cybersecurity</category>
        </item>
        <item>
            <title><![CDATA[Easily Remove the macOS Dock Hiding Animation]]></title>
            <link>https://sudojoie.com/macos-dock-hiding-animation</link>
            <guid>https://sudojoie.com/macos-dock-hiding-animation</guid>
            <pubDate>Mon, 01 Jul 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[Run basic terminal commands to remove macOS dock animation to lessen wait time.]]></description>
            <content:encoded><![CDATA[<p>Use basic terminal commands to disable macOS dock animations and reduce wait times. Currently, macOS doesn't offer a built-in option to remove the dock hiding animation. If you have the dock hiding feature enabled, there’s a slight delay when the dock appears or disappears, which can be frustrating for some users and may cause a minor delay when opening apps.</p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="remove-the-hiding-animation">Remove the hiding animation<a href="https://sudojoie.com/macos-dock-hiding-animation#remove-the-hiding-animation" class="hash-link" aria-label="Direct link to Remove the hiding animation" title="Direct link to Remove the hiding animation" translate="no">​</a></h2>
<p>Here are four steps to remove your macOS dock hiding animation.</p>
<ol>
<li class="">
<p>Right click on your macOS dock and click "Turn Hiding On". No need to do this step if you have it already turned on.</p>
</li>
<li class="">
<p>Open your terminal.</p>
<ol>
<li class=""><code>command</code> + <code>space</code></li>
<li class="">Type <code>terminal</code> then press enter.</li>
</ol>
</li>
<li class="">
<p>Run the command below to remove the delay to show up and the animation itself.</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">defaults write com.apple.dock autohide-delay -float 0; defaults write com.apple.dock autohide-time-modifier -int 0; killall Dock</span><br></span></code></pre></div></div>
</li>
<li class="">
<p>Test it out.</p>
</li>
</ol>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="customize-the-animation">Customize the animation<a href="https://sudojoie.com/macos-dock-hiding-animation#customize-the-animation" class="hash-link" aria-label="Direct link to Customize the animation" title="Direct link to Customize the animation" translate="no">​</a></h2>
<p>If you want to keep the animation but remove the delay, run the command below.</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">defaults write com.apple.dock autohide-delay -float 0; killall Dock</span><br></span></code></pre></div></div>
<p>If you only want to modify the timing of the animation, change the number of seconds next to <code>-float</code> to your liking.</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">defaults write com.apple.dock autohide-time-modifier -float 0.25; killall Dock</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="back-to-the-original">Back to the original<a href="https://sudojoie.com/macos-dock-hiding-animation#back-to-the-original" class="hash-link" aria-label="Direct link to Back to the original" title="Direct link to Back to the original" translate="no">​</a></h2>
<p>To restore the default settings fo the hiding animation, run the command below.</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">defaults delete com.apple.dock autohide-delay; killall Dock</span><br></span></code></pre></div></div>]]></content:encoded>
            <category>macOS</category>
            <category>Tutorial</category>
        </item>
        <item>
            <title><![CDATA[You Don't Need Apps: Create a macOS Mouse Jiggler in Minutes with Just Code!]]></title>
            <link>https://sudojoie.com/macos-mouse-jiggler</link>
            <guid>https://sudojoie.com/macos-mouse-jiggler</guid>
            <pubDate>Wed, 26 Jun 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[Learn how to prevent your Mac from sleeping by coding a simple mouse jiggler in C — no apps, no installs, just pure code.]]></description>
            <content:encoded><![CDATA[<p>Keep your Mac awake with a simple mouse jiggler written in C. While I usually prefer Python for scripting, I wanted to avoid relying on external packages for this project, eliminating the need for setting up a virtual environment. Instead, I chose C to leverage macOS's native Application Services framework.</p>
<p>The Application Services framework provides essential APIs for tasks like graphics rendering, image handling, accessibility, and more. Using the <a href="https://developer.apple.com/documentation/coregraphics/" target="_blank" rel="noopener noreferrer" class="">Core Graphics</a> component, I can build a program to automatically move the mouse pointer to random locations on the screen.</p>
<p>The first step is to create the <code>main()</code> function, where we’ll initialize the random number generator. By default, the generator produces the same sequence each time the program runs. To make it truly random, we’ll seed it with a unique value using the <code>time()</code> function, as the system time changes with every program execution.</p>
<div class="language-c codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-c codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">int</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">main</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// initialize starting point of random number generator</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token function" style="color:rgb(130, 170, 255)">srand</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token keyword" style="font-style:italic">unsigned</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">int</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token function" style="color:rgb(130, 170, 255)">time</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token constant" style="color:rgb(130, 170, 255)">NULL</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">while</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token number" style="color:rgb(247, 140, 108)">1</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token keyword" style="font-style:italic">int</span><span class="token plain"> randomNumber </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">rand</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token function" style="color:rgb(130, 170, 255)">printf</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"Random Number: %d\n"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> randomNumber</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// generate a random number every 3 seconds</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token function" style="color:rgb(130, 170, 255)">sleep</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token number" style="color:rgb(247, 140, 108)">3</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">0</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></span></code></pre></div></div>
<p>The output of the program above should be something like this:</p>
<div class="language-shell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-shell codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ ./test</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">Random Number: 1307726537</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">Random Number: 1612263961</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">Random Number: 371734681</span><br></span></code></pre></div></div>
<p>The next step is to create the <code>jiggleMouse()</code> function. Imagine that the <a href="https://courses.lumenlearning.com/aacc-collegealgebrafoundations/chapter/read-quadrants-on-the-coordinate-plane/" target="_blank" rel="noopener noreferrer" class="">Quandrants of the Coordinate Plane</a> is on top of your screen. The function's purpose is to obtain the current x and y coordinates of the mouse pointer and add the random numbers generated earlier. With this, the new mouse pointer location will move along the x and y axis of the screen. It's also important to note that we need to release the memory used by our program using <code>CFRelease()</code> once we are done with the process. See the completed function below.</p>
<div class="language-c codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-c codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">void</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">jiggleMouse</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// get the current mouse position</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    CGEventRef event </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">CGEventCreate</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token constant" style="color:rgb(130, 170, 255)">NULL</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    CGPoint currentPos </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">CGEventGetLocation</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">event</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token function" style="color:rgb(130, 170, 255)">CFRelease</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">event</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// generate random movement values</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">int</span><span class="token plain"> deltaX </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token function" style="color:rgb(130, 170, 255)">rand</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">%</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">21</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">-</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">10</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"> </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Random value between -10 and 10</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">int</span><span class="token plain"> deltaY </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token function" style="color:rgb(130, 170, 255)">rand</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">%</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">21</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">-</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">10</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"> </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Random value between -10 and 10</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// move the mouse to a new position</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    CGPoint newPos </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">CGPointMake</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">currentPos</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">x </span><span class="token operator" style="color:rgb(137, 221, 255)">+</span><span class="token plain"> deltaX</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> currentPos</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">y </span><span class="token operator" style="color:rgb(137, 221, 255)">+</span><span class="token plain"> deltaY</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    CGEventRef move </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">CGEventCreateMouseEvent</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token constant" style="color:rgb(130, 170, 255)">NULL</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> kCGEventMouseMoved</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> newPos</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> kCGMouseButtonLeft</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token function" style="color:rgb(130, 170, 255)">CGEventPost</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">kCGHIDEventTap</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> move</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token function" style="color:rgb(130, 170, 255)">CFRelease</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">move</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token function" style="color:rgb(130, 170, 255)">printf</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"Mouse moved to: (%.0f, %.0f)\n"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> newPos</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">x</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> newPos</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">y</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></span></code></pre></div></div>
<p>Before running the program, change <code>sleep(3);</code> to <code>sleep(60);</code> so that the mouse will not move too often. This will move the mouse every 60 seconds. You can also change this to your own preference. Afterwards, run the program and it should show similar outputs below.</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ ./mouse_jiggler</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">Mouse moved to: (959, 569)</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">Mouse moved to: (956, 571)</span><br></span></code></pre></div></div>
<p>Note that the output coordinates shown in my example above will be different with your's.</p>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>Completed Program</div><div class="admonitionContent_BuS1"><p>Clone the repository <a href="https://github.com/joiellantero/macos-mouse-jiggler-c.git" target="_blank" rel="noopener noreferrer" class="">here.</a>. Give it a star if you liked it or let me know any issues.</p></div></div>]]></content:encoded>
            <category>C Programming</category>
            <category>Scripts</category>
            <category>Tutorial</category>
            <category>macOS</category>
        </item>
        <item>
            <title><![CDATA[How to Check if a Link is Safe Before You Click]]></title>
            <link>https://sudojoie.com/a-guide-to-identifying-malicious-links</link>
            <guid>https://sudojoie.com/a-guide-to-identifying-malicious-links</guid>
            <pubDate>Sat, 15 Jun 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[Learn a practical step-by-step process for checking suspicious links with free tools before opening them.]]></description>
            <content:encoded><![CDATA[<p>Suspicious links show up everywhere: email, text messages, social media, chat apps, and even search results. The problem is that many malicious links look normal at first glance.</p>
<!-- -->
<p>This guide walks through a practical way to check whether a link is likely safe before you visit it. You do not need paid tools or deep security experience. You only need a careful process and a few reputable resources.</p>
<p>According to Proofpoint's <a href="https://www.proofpoint.com/us/resources/threat-reports/state-of-phish" target="_blank" rel="noopener noreferrer" class="">2024 State of the Phish report</a>, risky user behavior is still a major factor in phishing success. That matters because one careless click can lead to credential theft, malware, or account compromise.</p>
<p>If you remember only one thing from this article, remember this: if a link feels off, do not open it directly. Check it first.</p>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>info</div><div class="admonitionContent_BuS1"><p>Proofpoint is a cybersecurity company that provides Software-as-a-Service products for email security, data loss prevention, and related security services.</p><p>More details <a href="https://www.proofpoint.com/us/company/about" target="_blank" rel="noopener noreferrer" class="">here</a>.</p></div></div>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>info</div><div class="admonitionContent_BuS1"><p>Phishing is a social engineering attack that tries to trick people into revealing sensitive information, signing in to fake websites, or downloading malware. Business Email Compromise, or BEC, is a phishing-related tactic that targets organizations and employees.</p></div></div>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="why-malicious-links-are-dangerous">Why malicious links are dangerous<a href="https://sudojoie.com/a-guide-to-identifying-malicious-links#why-malicious-links-are-dangerous" class="hash-link" aria-label="Direct link to Why malicious links are dangerous" title="Direct link to Why malicious links are dangerous" translate="no">​</a></h2>
<p>A malicious link can do more than take you to a sketchy webpage. It can:</p>
<ol>
<li class="">Send you to a fake login page that steals your password</li>
<li class="">Trigger a malware download</li>
<li class="">Redirect you through several domains to hide the final destination</li>
<li class="">Abuse trust by impersonating a bank, coworker, online store, or cloud service</li>
</ol>
<p>That is why the safest habit is to inspect first and click later.</p>
<p>If you also want to get better at spotting phishing messages in general, Proofpoint has a useful article on <a href="https://www.proofpoint.com/us/blog/email-and-cloud-threats/how-to-spot-phishing-emails-and-avoid-them" target="_blank" rel="noopener noreferrer" class="">how to recognize phishing emails</a>.</p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="before-you-use-any-tool">Before you use any tool<a href="https://sudojoie.com/a-guide-to-identifying-malicious-links#before-you-use-any-tool" class="hash-link" aria-label="Direct link to Before you use any tool" title="Direct link to Before you use any tool" translate="no">​</a></h2>
<p>Start with these basic habits:</p>
<ol>
<li class="">Do not click the link just to see where it goes</li>
<li class="">Copy the link address instead of opening it</li>
<li class="">If possible, inspect the full URL for misspellings, extra words, or strange subdomains</li>
<li class="">Be more cautious if the message creates urgency such as "verify now" or "your account will be locked"</li>
</ol>
<p>Even a quick visual check can reveal obvious problems like fake domains, random strings, or misleading lookalike brands.</p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="step-1-scan-the-link-with-a-trusted-online-tool">Step 1: Scan the link with a trusted online tool<a href="https://sudojoie.com/a-guide-to-identifying-malicious-links#step-1-scan-the-link-with-a-trusted-online-tool" class="hash-link" aria-label="Direct link to Step 1: Scan the link with a trusted online tool" title="Direct link to Step 1: Scan the link with a trusted online tool" translate="no">​</a></h2>
<p>One of the easiest ways to investigate a suspicious link is to scan it with an online reputation tool such as <a href="https://www.virustotal.com/gui/home/url" target="_blank" rel="noopener noreferrer" class="">VirusTotal</a>.</p>
<p>Follow this process:</p>
<ol>
<li class="">Right-click the suspicious link and copy the URL</li>
<li class="">Open <a href="https://www.virustotal.com/gui/home/url" target="_blank" rel="noopener noreferrer" class="">VirusTotal</a></li>
<li class="">Paste the URL into the search box</li>
<li class="">Submit it and wait for the scan results</li>
<li class="">Review the detection count, domain information, and any community feedback</li>
</ol>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>info</div><div class="admonitionContent_BuS1"><p>Open-source intelligence, or OSINT, means collecting and analyzing information from public sources. In this case, we use public threat intelligence and reputation services to help judge whether a link is suspicious.</p></div></div>
<h3 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="how-to-interpret-the-results">How to interpret the results<a href="https://sudojoie.com/a-guide-to-identifying-malicious-links#how-to-interpret-the-results" class="hash-link" aria-label="Direct link to How to interpret the results" title="Direct link to How to interpret the results" translate="no">​</a></h3>
<p>The scan result is useful, but it is not the whole story.</p>
<p>Use this rule of thumb:</p>
<ol>
<li class="">If the detection count is 0, the link may be low risk, but that does not guarantee it is safe</li>
<li class="">If several vendors detect it, treat it as suspicious or malicious</li>
<li class="">If only one or two vendors flag it, pause and gather more context before deciding</li>
</ol>
<div class="theme-admonition theme-admonition-tip admonition_xJq3 alert alert--success"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>tip</div><div class="admonitionContent_BuS1"><p>There is no tool that can guarantee a website is completely safe. A clean scan only means there is no strong public signal at the moment. New phishing sites often appear before scanners catch them.</p></div></div>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="step-2-verify-with-more-than-one-source">Step 2: Verify with more than one source<a href="https://sudojoie.com/a-guide-to-identifying-malicious-links#step-2-verify-with-more-than-one-source" class="hash-link" aria-label="Direct link to Step 2: Verify with more than one source" title="Direct link to Step 2: Verify with more than one source" translate="no">​</a></h2>
<p>Do not rely on a single service if the situation matters. Cross-checking helps reduce false positives and false negatives.</p>
<p>You can compare results using other tools and references such as the resources listed in <a class="" href="https://sudojoie.com/list-of-free-cybersecurity-tools-and-resources">List of Free Cybersecurity Tools and Resources</a>.</p>
<p>As a simple decision guide:</p>
<ol>
<li class="">If multiple reputable tools show no detections, the risk is lower</li>
<li class="">If multiple tools flag the same URL or domain, treat it as unsafe</li>
<li class="">If the results are mixed, do not assume it is safe just because most tools are quiet</li>
</ol>
<p>Mixed results usually mean you need more context.</p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="step-3-investigate-deeper-when-the-result-is-unclear">Step 3: Investigate deeper when the result is unclear<a href="https://sudojoie.com/a-guide-to-identifying-malicious-links#step-3-investigate-deeper-when-the-result-is-unclear" class="hash-link" aria-label="Direct link to Step 3: Investigate deeper when the result is unclear" title="Direct link to Step 3: Investigate deeper when the result is unclear" translate="no">​</a></h2>
<p>Sometimes a link gets a low detection count like 1 or 2. That does not automatically mean it is harmless or dangerous. It means you need to look closer.</p>
<h3 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="look-at-the-domain-carefully">Look at the domain carefully<a href="https://sudojoie.com/a-guide-to-identifying-malicious-links#look-at-the-domain-carefully" class="hash-link" aria-label="Direct link to Look at the domain carefully" title="Direct link to Look at the domain carefully" translate="no">​</a></h3>
<p>Ask yourself:</p>
<ol>
<li class="">Is the domain spelled correctly?</li>
<li class="">Is it pretending to be a known brand?</li>
<li class="">Does it use odd subdomains like <code>brand-login-security.example.com</code>?</li>
<li class="">Does the URL contain random strings, urgent words, or suspicious file names?</li>
</ol>
<h3 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="check-the-community-feedback">Check the community feedback<a href="https://sudojoie.com/a-guide-to-identifying-malicious-links#check-the-community-feedback" class="hash-link" aria-label="Direct link to Check the community feedback" title="Direct link to Check the community feedback" translate="no">​</a></h3>
<p>VirusTotal also includes a Community tab where users may leave comments about a domain or URL.</p>
<p>This can help you answer questions like:</p>
<ol>
<li class="">Has this domain been reported for phishing or abuse before?</li>
<li class="">Is it a tracking or ad-tech domain rather than a direct malware host?</li>
<li class="">Are other analysts warning people not to trust it?</li>
</ol>
<p>To check it:</p>
<ol>
<li class="">Open the result page in VirusTotal</li>
<li class="">Click the Community tab</li>
<li class="">Read the comments carefully and treat them as supporting context, not absolute proof</li>
</ol>
<div><img src="https://sudojoie.com/assets/images/vt-community-af0f080770c026e0c1358b5b3f8aea54.png" alt="virustotal-community"></div>
<p>In the example above, the scan result is clean, but the community discussion suggests that <code>dtscout[.]com</code> is used for tracking and analytics. That does not automatically make it malware, but it does change how you should think about the domain. A clean detection score does not always mean a domain is trustworthy or appropriate to allow.</p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="a-practical-way-to-make-a-decision">A practical way to make a decision<a href="https://sudojoie.com/a-guide-to-identifying-malicious-links#a-practical-way-to-make-a-decision" class="hash-link" aria-label="Direct link to A practical way to make a decision" title="Direct link to A practical way to make a decision" translate="no">​</a></h2>
<p>Here is a simple approach you can use in real situations:</p>
<ol>
<li class="">If the link is clearly malicious, block or report it</li>
<li class="">If the link is suspicious and the purpose is unclear, do not open it</li>
<li class="">If the link appears clean but still feels unnecessary or untrusted, avoid it anyway</li>
<li class="">If you are checking a work-related link, ask your IT or security team before visiting it</li>
</ol>
<p>This last point matters. In many cases, the best decision is not to prove a link is safe. It is to decide that you do not need to click it.</p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="quick-checklist">Quick checklist<a href="https://sudojoie.com/a-guide-to-identifying-malicious-links#quick-checklist" class="hash-link" aria-label="Direct link to Quick checklist" title="Direct link to Quick checklist" translate="no">​</a></h2>
<p>Before opening any unfamiliar link, run through this checklist:</p>
<ol>
<li class="">Copy the URL instead of clicking it</li>
<li class="">Scan it with VirusTotal</li>
<li class="">Check at least one or two additional sources</li>
<li class="">Look closely at the domain name and structure</li>
<li class="">Read any community comments or reputation notes</li>
<li class="">If anything still feels off, do not open it</li>
</ol>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="final-thoughts">Final thoughts<a href="https://sudojoie.com/a-guide-to-identifying-malicious-links#final-thoughts" class="hash-link" aria-label="Direct link to Final thoughts" title="Direct link to Final thoughts" translate="no">​</a></h2>
<p>Checking suspicious links is a useful skill because most attacks do not look dramatic. They look ordinary. A fake sign-in page, a shipping notification, or a document share link can be enough to trick someone who is moving too fast.</p>
<p>The goal is not to become perfect. The goal is to slow down, verify what you can, and avoid giving attackers an easy win.</p>]]></content:encoded>
            <category>Tutorial</category>
            <category>Awareness</category>
            <category>Cybersecurity</category>
            <category>Email Security</category>
        </item>
        <item>
            <title><![CDATA[Importing an SSL Certificate from KeyVault to a Linux VM]]></title>
            <link>https://sudojoie.com/importing-ssl-cert-from-key-vault-to-a-linux-vm</link>
            <guid>https://sudojoie.com/importing-ssl-cert-from-key-vault-to-a-linux-vm</guid>
            <pubDate>Tue, 10 Oct 2023 00:00:00 GMT</pubDate>
            <description><![CDATA[Azure Key Vault can be used to create or import an SSL certificate for our website. In this article, we discuss how to transfer the certificate to our VM and use it to secure our website.]]></description>
            <content:encoded><![CDATA[<p>Azure Key Vault can be used to create or import an SSL certificate for our website. In this article, we discuss how to transfer the certificate to our VM and use it to secure our website.</p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="what-is-azure-key-vault">What is Azure Key Vault?<a href="https://sudojoie.com/importing-ssl-cert-from-key-vault-to-a-linux-vm#what-is-azure-key-vault" class="hash-link" aria-label="Direct link to What is Azure Key Vault?" title="Direct link to What is Azure Key Vault?" translate="no">​</a></h2>
<p>Azure Key Vault is a cloud service for securely storing and accessing secrets. We can store API keys, passwords, certificates, or cryptographic keys. Access to these resources are also configurable as we can setup the firewall specific for our Key Vault or setup a private endpoint.</p>
<div class="theme-admonition theme-admonition-note admonition_xJq3 alert alert--secondary"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>note</div><div class="admonitionContent_BuS1"><p>The sections below may depend on our use-case so feel free to skip to the sections relevant to you.</p></div></div>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="create-an-azure-key-vault">Create an Azure Key Vault<a href="https://sudojoie.com/importing-ssl-cert-from-key-vault-to-a-linux-vm#create-an-azure-key-vault" class="hash-link" aria-label="Direct link to Create an Azure Key Vault" title="Direct link to Create an Azure Key Vault" translate="no">​</a></h2>
<p>For those who don't have a Key Vault, you can create one in your resource group using the command below.</p>
<div class="language-shell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-shell codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">keyvault_name=&lt;mykeyvault&gt;</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">az keyvault create \</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    --resource-group myResourceGroupSecureWeb \</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    --name $keyvault_name \</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    --enabled-for-deployment</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="generating-a-certificate-in-key-vault">Generating a certificate in Key Vault<a href="https://sudojoie.com/importing-ssl-cert-from-key-vault-to-a-linux-vm#generating-a-certificate-in-key-vault" class="hash-link" aria-label="Direct link to Generating a certificate in Key Vault" title="Direct link to Generating a certificate in Key Vault" translate="no">​</a></h2>
<p>In this section, we generate a self-signed certificate but, in production, import your own certificate signed by a trusted provider.</p>
<div class="language-shell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-shell codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">az keyvault certificate create \</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    --vault-name $keyvault_name \</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    --name $cert_name \</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    --policy "$(az keyvault certificate get-default-policy)"</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="storing-a-certificate-in-key-vault">Storing a certificate in Key Vault<a href="https://sudojoie.com/importing-ssl-cert-from-key-vault-to-a-linux-vm#storing-a-certificate-in-key-vault" class="hash-link" aria-label="Direct link to Storing a certificate in Key Vault" title="Direct link to Storing a certificate in Key Vault" translate="no">​</a></h2>
<p>If you have your own certificate, you can import it using the command below.</p>
<div class="language-shell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-shell codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">az keyvault certificate import \ </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    --vault-name "&lt;your-key-vault-name&gt;" \</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    -n "ExampleCertificate"\ </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    -f "/path/to/ExampleCertificate.pem"</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="transfering-the-certificate-from-key-vault-to-vm">Transfering the certificate from Key Vault to VM<a href="https://sudojoie.com/importing-ssl-cert-from-key-vault-to-a-linux-vm#transfering-the-certificate-from-key-vault-to-vm" class="hash-link" aria-label="Direct link to Transfering the certificate from Key Vault to VM" title="Direct link to Transfering the certificate from Key Vault to VM" translate="no">​</a></h2>
<p>Once you create or import a certificate in Azure KeyVault, run the following commands below to import the certificate and private key in our VM. Update or replace the variable below with the appropriate details.</p>
<p>First, we obtain the certificate ID by running <code>az keyvault secret list-versions</code>.</p>
<div class="language-shell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-shell codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">secret=$(az keyvault secret list-versions \</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">          --vault-name $keyvault_name \</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">          --name $cert_name \</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">          --query "[?attributes.enabled].id" --output tsv)</span><br></span></code></pre></div></div>
<p>Next, we need to convert the ID into something our VM can use.</p>
<div class="language-shell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-shell codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">vm_secret=$(az vm secret format --secret "$secret")</span><br></span></code></pre></div></div>
<p>Finally, we update our VM's OSProfile secret value.</p>
<div class="language-shell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-shell codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">az vm update -n $vm_name -g $rg_name --set osProfile.secrets="$vm_secret"</span><br></span></code></pre></div></div>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>info</div><div class="admonitionContent_BuS1"><p>OSProfile specifies the operating system settings for the virtual machine. More details about OSProfile <a href="https://learn.microsoft.com/en-us/rest/api/compute/virtual-machines/create-or-update?tabs=HTTP#osprofile" target="_blank" rel="noopener noreferrer" class="">here</a>.</p></div></div>
<p>With this, we now successfully transferred the certificate in our VM.</p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="using-the-certificate">Using the certificate<a href="https://sudojoie.com/importing-ssl-cert-from-key-vault-to-a-linux-vm#using-the-certificate" class="hash-link" aria-label="Direct link to Using the certificate" title="Direct link to Using the certificate" translate="no">​</a></h2>
<p>SSH into our VM and follow the steps below to use the SSL certificate for our site.</p>
<ol>
<li class="">
<p>Upon running the commands, the certificate and private key will be stored in <code>/var/lib/waagent</code>. The filename will be the thumbprints as seen in Azure Key Vault.</p>
</li>
<li class="">
<p>Duplicate the .crt  and .prv and rename it into something more readable. For instance, you can run something similar to the following commands:</p>
<div class="language-shell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-shell codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">cat &lt;key_thumbprint_here&gt;.crt &gt; mysite.crt</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">cat &lt;key_thumbprint_here&gt;.prv &gt; mysite.prv </span><br></span></code></pre></div></div>
</li>
<li class="">
<p>Move these to <code>/etc/nginx/certs/</code>.</p>
<div class="language-shell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-shell codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">mv mysite.crt /etc/nginx/certs/ </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">mv mysite.prv /etc/nginx/certs</span><br></span></code></pre></div></div>
</li>
<li class="">
<p>Update Nginx config file</p>
<div class="language-shell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-shell codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">server {</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">     ...</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">     listen 80;</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">     server_name mysite.com 12.345.67.8; </span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#bfc7d5"><span class="token plain">     listen 443 default_server ssl;</span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#bfc7d5"><span class="token plain">     ssl_certificate /etc/nginx/certs/mysite.crt;</span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#bfc7d5"><span class="token plain">     ssl_certificate_key /etc/nginx/certs/mysite.prv;</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">     ...</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"> }</span><br></span></code></pre></div></div>
</li>
<li class="">
<p>Restart Nginx: <code>sudo systemctl restart nginx</code>.</p>
</li>
<li class="">
<p>Visit your site and check if you have the lock icon beside the URL.</p>
</li>
</ol>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="osprofile-issue">osProfile Issue<a href="https://sudojoie.com/importing-ssl-cert-from-key-vault-to-a-linux-vm#osprofile-issue" class="hash-link" aria-label="Direct link to osProfile Issue" title="Direct link to osProfile Issue" translate="no">​</a></h2>
<div class="theme-admonition theme-admonition-caution admonition_xJq3 alert alert--warning"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 16 16"><path fill-rule="evenodd" d="M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z"></path></svg></span>caution</div><div class="admonitionContent_BuS1"><p>Creating a VM from an os disk snapshot doesn't have an osProfile. This creates a problem for the previous process as we need to update the osProfile secrets.</p></div></div>
<p>Below is an alternative way of importing your SSL cert to your VM.</p>
<ol>
<li class="">Prepare your cert and key</li>
</ol>
<p>This ensures that the <code>.pfx</code> file is in binary format (done by adding the flag <code>--encoding base64</code>).</p>
<div class="language-shell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-shell codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain"># download your cert from Azure Key Vault and copy the file in your VM </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"># if you already have your cert.pfx in your local machine, skip this step</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">az keyvault secret download --file &lt;certname&gt;.pfx --vault-name &lt;keyvaultname&gt; --name &lt;certname&gt; --encoding base64</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">openssl pkcs12 -in &lt;certname&gt;.pfx -nocerts -out &lt;certname&gt;.key -nodes -passin pass:</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">openssl pkcs12 -in &lt;certname&gt;.pfx -clcerts -nokeys -out &lt;certname&gt;.crt</span><br></span></code></pre></div></div>
<ol start="2">
<li class="">Once you have your cert and key ready, you can copy them using <code>scp</code> command.</li>
</ol>
<div class="language-shell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-shell codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">scp cert.crt cert.key &lt;vmuser&gt;@&lt;vmip&gt;:~</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"># if you specified a port</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">scp -P 1234 cert.crt cert.key &lt;vmuser&gt;@&lt;vmip&gt;:~</span><br></span></code></pre></div></div>
<blockquote>
<p>This will save the files in the home directory: <code>cd ~</code></p>
</blockquote>
<ol start="3">
<li class="">Create a new Nginx certs folder: <code>mkdir /etc/nginx/certs/</code></li>
<li class="">Move the files into the Nginx certs folder:<!-- -->
<ul>
<li class="">Run command: <code>mv &lt;certame&gt;.crt /etc/nginx/certs/</code></li>
<li class="">Run command: <code>mv &lt;certname&gt;.prv /etc/nginx/certs/</code></li>
</ul>
</li>
<li class="">Update Nginx config file: <code>sudo vim /etc/nginx/sites-available/ctfd</code></li>
<li class="">Restart Nginx<!-- -->
<ul>
<li class="">Run command: <code>sudo systemctl restart nginx</code></li>
</ul>
</li>
<li class="">Visit your site at <code>https://&lt;sitedomain&gt;.com/</code></li>
</ol>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="final-thoughts">Final Thoughts<a href="https://sudojoie.com/importing-ssl-cert-from-key-vault-to-a-linux-vm#final-thoughts" class="hash-link" aria-label="Direct link to Final Thoughts" title="Direct link to Final Thoughts" translate="no">​</a></h2>
<p>Using the Azure Key Vault is quite easy but it may be overwhelming as Microsoft has a lot of documentations for their cloud services. This article makes it easy to follow to do a simple thing such as making your site more secure with an SSL certificate.</p>]]></content:encoded>
            <category>Tutorial</category>
            <category>Web Development</category>
            <category>Azure</category>
            <category>Cloud</category>
        </item>
        <item>
            <title><![CDATA[My Experience Taking a SANS Certification: GPCS]]></title>
            <link>https://sudojoie.com/my-experience-taking-sans-gpcs</link>
            <guid>https://sudojoie.com/my-experience-taking-sans-gpcs</guid>
            <pubDate>Sun, 08 Oct 2023 00:00:00 GMT</pubDate>
            <description><![CDATA[As a threat detection engineer who had only been working full-time for about a year, I knew I needed to level up my cloud security knowledge. When my company offered to sponsor a SANS certification, I jumped at the chance to take the GIAC Public Cloud Security (GPCS) course. Here's how that journey went--from the classroom to passing the exam.]]></description>
            <content:encoded><![CDATA[<p>As a threat detection engineer who had only been working full-time for about a year, I knew I needed to level up my cloud security knowledge. When my company offered to sponsor a SANS certification, I jumped at the chance to take the GIAC Public Cloud Security (GPCS) course. Here's how that journey went--from the classroom to passing the exam.</p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="what-the-course-covers">What the course covers<a href="https://sudojoie.com/my-experience-taking-sans-gpcs#what-the-course-covers" class="hash-link" aria-label="Direct link to What the course covers" title="Direct link to What the course covers" translate="no">​</a></h2>
<p>SANS GPCS dives into cloud security across the three major cloud service providers--AWS, Azure, and Google Cloud. The course covers how to uncover cloud vulnerabilities and unintentional exposure caused by improper configurations in IAM, networking, and storage services. It also discusses best practices you can tailor to your organization's needs.</p>
<div class="theme-admonition theme-admonition-note admonition_xJq3 alert alert--secondary"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>note</div><div class="admonitionContent_BuS1"><p>More info can be found on the <a href="https://www.sans.org/cyber-security-courses/public-cloud-security-aws-azure-gcp/" target="_blank" rel="noopener noreferrer" class="">SANS GPCS course page</a>.</p></div></div>
<p>The content was well-researched and struck a great balance between theory and hands-on application. As someone working in threat detection, I found it incredibly valuable to see cloud risks from a defender's perspective--understanding how misconfigurations happen and what attackers look for. I was able to take these insights back to work and develop strategies for strengthening our cloud security posture.</p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="the-in-person-experience">The in-person experience<a href="https://sudojoie.com/my-experience-taking-sans-gpcs#the-in-person-experience" class="hash-link" aria-label="Direct link to The in-person experience" title="Direct link to The in-person experience" translate="no">​</a></h2>
<p>Attending in person was worth it. I connected and networked with cybersecurity professionals from around the world--my instructor, classmates, and the SANS staff. The course also included live-online participants, and all class discussions were recorded for future reference.</p>
<p>Our instructor was Brandon Evans, one of the course authors, who signed our GPCS posters. I also collected a haul of SANS freebies: a 2023 shirt, stickers, pens, a highlighter, and a notebook. At a community night event, I picked up even more--a 2020 shirt, additional stickers, and a SANS poker chip. Freebies depend on extra stock, and these events are held globally.</p>
<div class="theme-admonition theme-admonition-note admonition_xJq3 alert alert--secondary"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>note</div><div class="admonitionContent_BuS1"><p>Learn more about SANS Community Night through this <a href="https://www.sans.org/mlp/community-night-events/" target="_blank" rel="noopener noreferrer" class="">link</a>.</p></div></div>
<div><img src="https://sudojoie.com/assets/images/freebies-5fad436ee5ee7ae782ce806e515f8c3a.png" alt="sans-freebies"></div>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="the-netwars-challenge">The Netwars challenge<a href="https://sudojoie.com/my-experience-taking-sans-gpcs#the-netwars-challenge" class="hash-link" aria-label="Direct link to The Netwars challenge" title="Direct link to The Netwars challenge" translate="no">​</a></h2>
<p>My favorite part of the course was the hands-on component. SANS runs Netwars, their own capture-the-flag competition, where you get to apply everything you've learned in real-world scenarios. It pushed me beyond the course material and got me exploring additional technologies like Terraform.</p>
<p>You're awarded a coin if you meet the instructor's criteria for the challenge. In our case, it was finishing in the top 3--and I'm proud to say I made it to the top spot!</p>
<div><img src="https://sudojoie.com/assets/images/sans-coin-4330bc69ee415db08e14bc789d9490f4.png" alt="sans-coin"></div>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="preparing-for-the-exam">Preparing for the exam<a href="https://sudojoie.com/my-experience-taking-sans-gpcs#preparing-for-the-exam" class="hash-link" aria-label="Direct link to Preparing for the exam" title="Direct link to Preparing for the exam" translate="no">​</a></h2>
<p>Balancing exam prep with a full-time job was the hardest part. My exam voucher was valid for around four months, and I had grand plans to study gradually over that entire period. That didn't happen. In reality, I only managed to focus on studying during the final month before my exam.</p>
<p>I reviewed the learning materials by rewatching the recorded lectures and highlighting key information in the books. SANS also provides an audiobook, which I tried listening to while driving--but the chaotic metro traffic made that experiment short-lived.</p>
<h3 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="building-my-index">Building my index<a href="https://sudojoie.com/my-experience-taking-sans-gpcs#building-my-index" class="hash-link" aria-label="Direct link to Building my index" title="Direct link to Building my index" translate="no">​</a></h3>
<p>Here's the thing about SANS exams: they're open-book. You can bring an armful of hard-copy books, notes, and printed materials into the exam room. No digital copies or devices though--phones and tablets are not allowed.</p>
<p>This open-book policy meant I could focus on understanding concepts rather than memorizing them. The key was having a well-organized index so I could quickly find any topic during the exam. I used the "Pancakes Indexing System" which I learned from <a href="https://tisiphone.net/2015/08/18/giac-testing/" target="_blank" rel="noopener noreferrer" class="">Lesley Carhart's blog post</a>--highly recommended.</p>
<h3 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="practice-tests">Practice tests<a href="https://sudojoie.com/my-experience-taking-sans-gpcs#practice-tests" class="hash-link" aria-label="Direct link to Practice tests" title="Direct link to Practice tests" translate="no">​</a></h3>
<p>The course included two practice tests, and I took them after building my index. The practice test platform is designed to be similar to the actual exam environment.</p>
<p>After my first practice test, I noted down every topic I struggled with, then went back to review those areas and added more detail to my index. This feedback loop worked well--my second practice test score was noticeably higher. If you're scoring between 75-85% on the practice tests, that's a good sign you're ready. The passing score for GPCS is 64%.</p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="the-actual-exam">The actual exam<a href="https://sudojoie.com/my-experience-taking-sans-gpcs#the-actual-exam" class="hash-link" aria-label="Direct link to The actual exam" title="Direct link to The actual exam" translate="no">​</a></h2>
<p>I took the exam just days before my voucher expired--talk about cutting it close. I was genuinely nervous. This was my first intermediate-to-advanced security certification, and despite the company sponsoring it, the cost made the stakes feel even higher.</p>
<p>Luckily, I passed. And as a cherry on top, I was invited to join the GIAC Advisory Board--an honor extended to those who score above 90%. It's a mailing list community that requires signing an NDA to join.</p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="final-thoughts">Final thoughts<a href="https://sudojoie.com/my-experience-taking-sans-gpcs#final-thoughts" class="hash-link" aria-label="Direct link to Final thoughts" title="Direct link to Final thoughts" translate="no">​</a></h2>
<p>SANS GPCS is a significant financial investment, which is why company sponsorship is usually the way to go. But the return on that investment is real--the knowledge I gained was immediately applicable at work, and using those concepts to improve our cloud security actually generated cost savings that can pay for the course itself.</p>
<p>If you're a cloud security practitioner looking for a structured, vendor-neutral deep dive into securing AWS, Azure, and GCP, I'd highly recommend this course. Just don't wait until the last month to start studying like I did.</p>]]></content:encoded>
            <category>SANS</category>
            <category>Cloud</category>
            <category>Cybersecurity</category>
        </item>
        <item>
            <title><![CDATA[Deploying a CTFd Site in Azure]]></title>
            <link>https://sudojoie.com/deploying-a-ctfd-site-azure</link>
            <guid>https://sudojoie.com/deploying-a-ctfd-site-azure</guid>
            <pubDate>Fri, 06 Oct 2023 00:00:00 GMT</pubDate>
            <description><![CDATA[Capture-The-Flag (CTF) in Information Security is a set of challenges or scenarios where participants find the answer called 'flag' This article covers how we can deploy an open-source CTF platform in the cloud.]]></description>
            <content:encoded><![CDATA[<p>Capture-The-Flag (CTF) in Information Security is a set of challenges or scenarios where participants find the answer called "flag". For instance, one can find a flag by solving programming problems or finding them in vulnerable servers.</p>
<p>This article covers how we can deploy an open-source CTF platform in the cloud.</p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="the-ctf-platform">The CTF platform<a href="https://sudojoie.com/deploying-a-ctfd-site-azure#the-ctf-platform" class="hash-link" aria-label="Direct link to The CTF platform" title="Direct link to The CTF platform" translate="no">​</a></h2>
<p>There's an open-source CTF platform which you can fork/clone the <a href="https://github.com/CTFd/CTFd" target="_blank" rel="noopener noreferrer" class="">code in GitHub</a>. It's free but it has a paid version if you don't want to host the site.</p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="setting-up-the-basic-configuration-of-the-site">Setting up the basic configuration of the site<a href="https://sudojoie.com/deploying-a-ctfd-site-azure#setting-up-the-basic-configuration-of-the-site" class="hash-link" aria-label="Direct link to Setting up the basic configuration of the site" title="Direct link to Setting up the basic configuration of the site" translate="no">​</a></h2>
<p>I created a virtual machine (VM) in my Azure resource group and below are the specifications.</p>
<p>VM Specifications:</p>
<ul>
<li class="">OS: Ubuntu 20.04</li>
<li class="">Storage: 30GB</li>
<li class="">2GB RAM</li>
<li class="">2 vCPU</li>
</ul>
<div class="theme-admonition theme-admonition-caution admonition_xJq3 alert alert--warning"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 16 16"><path fill-rule="evenodd" d="M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z"></path></svg></span>caution</div><div class="admonitionContent_BuS1"><p>If you intend to make your CTFd site an internal app, please make sure you set the appropriate VNET before provisioning your VM then check <a class="" href="https://sudojoie.com/deploying-a-ctfd-site-azure#configuring-the-ctfd-platform-as-an-internal-site">this section</a> for steps on how to proceed.</p></div></div>
<p>After provisioning the VM, SSH into it and run the following commands. Also make sure that the ports for HTTP and HTTPS are allowed in your network security group.</p>
<div class="language-shell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-shell codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain"># configure user for our CTFd resources</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">sudo adduser ctfd</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"># add the user to the sudo group</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">sudo usermod -aG sudo ctfd</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"># add the necessary firewalls</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">sudo ufw allow openssh</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">sudo ufw allow http</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">sudo ufw allow https</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">sudo ufw enable</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"># update and install required software</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">sudo apt update</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">sudo apt upgrade -y</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">sudo apt install -y python3-pip python3-dev build-essential libssl-dev libffi-dev python3-setuptools nginx git</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">pip3 install pipenv</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"># install CTFd</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">cd /var/www</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">sudo git clone https://github.com/CTFd/CTFd.git</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"># switch into the ctfd user</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">su ctfd</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">sudo chown -R ctfd:www-data /var/www/CTFd</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">cd /var/www/CTFd</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"># Create a pipenv to run CTFd in</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">pipenv install --python 3.12</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">pipenv shell</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">./prepare.sh</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="testing-the-site">Testing the site<a href="https://sudojoie.com/deploying-a-ctfd-site-azure#testing-the-site" class="hash-link" aria-label="Direct link to Testing the site" title="Direct link to Testing the site" translate="no">​</a></h2>
<div class="language-shell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-shell codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">sudo ufw allow 5000</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">gunicorn --bind 0.0.0.0:5000 'CTFd:create_app()'</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"># try to access the website</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">http://&lt;ip_address_here&gt;:5000 or</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">http://&lt;domain_here&gt;:5000 </span><br></span></code></pre></div></div>
<div class="theme-admonition theme-admonition-tip admonition_xJq3 alert alert--success"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>tip</div><div class="admonitionContent_BuS1"><p>If you encounter this error: <code>AttributeError: module 'lib' has no attribute 'X509_V_FLAG_CB_ISSUER_CHECK'</code>. Run <code>sudo apt remove python3-openssl</code>.</p></div></div>
<div class="theme-admonition theme-admonition-tip admonition_xJq3 alert alert--success"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>tip</div><div class="admonitionContent_BuS1"><p>When you encounter an error that a current process is already running, check gunicorn process: <code>ps ax|grep gunicorn</code> then stop the process <code>kill -9 932</code>.</p></div></div>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="further-configuring-the-ctfd-site">Further configuring the CTFd site<a href="https://sudojoie.com/deploying-a-ctfd-site-azure#further-configuring-the-ctfd-site" class="hash-link" aria-label="Direct link to Further configuring the CTFd site" title="Direct link to Further configuring the CTFd site" translate="no">​</a></h2>
<p>In this section, we will edit the systemd service unit file to install the workser service and other processes for the site. For deploying the site in single-core CPUs, we will use three workers with <code>worker-class=gevent</code> and set <code>keep-alive=2</code>.</p>
<div class="language-shell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-shell codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain"># identify the pipenv virtual environment for use in unit file</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">pipenv --venv</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">/home/ctfd/.local/share/virtualenvs/CTFd-rOJbThUf</span><br></span></code></pre></div></div>
<div class="language-shell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-shell codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv codeBlockLinesWithNumbering_o6Pm" style="counter-reset:line-count 0"><span class="token-line codeLine_lJS_" style="color:#bfc7d5"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain"># Create service unit configuration</span></span><br></span><span class="token-line codeLine_lJS_" style="color:#bfc7d5"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">sudo vim /etc/systemd/system/ctfd.service</span></span><br></span><span class="token-line codeLine_lJS_" style="color:#bfc7d5"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain" style="display:inline-block"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#bfc7d5"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain"># Copy all below (lines 5-17) and paste it in ctfd.service</span></span><br></span><span class="token-line codeLine_lJS_" style="color:#bfc7d5"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">[Unit]</span></span><br></span><span class="token-line codeLine_lJS_" style="color:#bfc7d5"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">Description=Gunicorn instance to serve ctfd</span></span><br></span><span class="token-line codeLine_lJS_" style="color:#bfc7d5"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">After=network.target</span></span><br></span><span class="token-line codeLine_lJS_" style="color:#bfc7d5"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain" style="display:inline-block"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#bfc7d5"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">[Service]</span></span><br></span><span class="token-line codeLine_lJS_" style="color:#bfc7d5"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">User=ctfd</span></span><br></span><span class="token-line codeLine_lJS_" style="color:#bfc7d5"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">Group=www-data</span></span><br></span><span class="token-line codeLine_lJS_" style="color:#bfc7d5"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">WorkingDirectory=/var/www/CTFd</span></span><br></span><span class="token-line codeLine_lJS_" style="color:#bfc7d5"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">Environment="PATH=/home/ctfd/.local/share/virtualenvs/CTFd-rOJbThUf/bin"</span></span><br></span><span class="token-line codeLine_lJS_" style="color:#bfc7d5"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">ExecStart=/home/ctfd/.local/share/virtualenvs/CTFd-rOJbThUf/bin/gunicorn --bind unix:app.sock --keep-alive 2 --workers 3 --worker-class gevent 'CTFd:create_app()' --access-logfile '/var/log/CTFd/CTFd/logs/access.log' --error-logfile '/var/log/CTFd/CTFd/logs/error.log'</span></span><br></span><span class="token-line codeLine_lJS_" style="color:#bfc7d5"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain" style="display:inline-block"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#bfc7d5"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">[Install]</span></span><br></span><span class="token-line codeLine_lJS_" style="color:#bfc7d5"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">WantedBy=multi-user.target</span></span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="setting-up-nginx">Setting up Nginx<a href="https://sudojoie.com/deploying-a-ctfd-site-azure#setting-up-nginx" class="hash-link" aria-label="Direct link to Setting up Nginx" title="Direct link to Setting up Nginx" translate="no">​</a></h2>
<h3 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="create-log-directories">Create log directories<a href="https://sudojoie.com/deploying-a-ctfd-site-azure#create-log-directories" class="hash-link" aria-label="Direct link to Create log directories" title="Direct link to Create log directories" translate="no">​</a></h3>
<div class="language-shell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-shell codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">sudo mkdir -p /var/log/CTFd/CTFd/logs/</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">sudo chown -R ctfd:www-data /var/log/CTFd/CTFd/logs/</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="create-nginx-site">Create Nginx site<a href="https://sudojoie.com/deploying-a-ctfd-site-azure#create-nginx-site" class="hash-link" aria-label="Direct link to Create Nginx site" title="Direct link to Create Nginx site" translate="no">​</a></h3>
<div class="language-shell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-shell codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">sudo systemctl enable ctfd</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">sudo systemctl start ctfd</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">sudo systemctl status ctfd</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="create-nginx-site-1">Create Nginx site<a href="https://sudojoie.com/deploying-a-ctfd-site-azure#create-nginx-site-1" class="hash-link" aria-label="Direct link to Create Nginx site" title="Direct link to Create Nginx site" translate="no">​</a></h3>
<div class="language-shell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-shell codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv codeBlockLinesWithNumbering_o6Pm" style="counter-reset:line-count 0"><span class="token-line codeLine_lJS_" style="color:#bfc7d5"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain"># let's encrypt will handle the https later</span></span><br></span><span class="token-line codeLine_lJS_" style="color:#bfc7d5"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">sudo vim /etc/nginx/sites-available/ctfd</span></span><br></span><span class="token-line codeLine_lJS_" style="color:#bfc7d5"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain" style="display:inline-block"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#bfc7d5"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain"># Nginx config (copy lines 6-15)</span></span><br></span><span class="token-line codeLine_lJS_" style="color:#bfc7d5"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain"># the client_max_body_size enables file uploads over the default of 1MB</span></span><br></span><span class="token-line codeLine_lJS_" style="color:#bfc7d5"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">server {</span></span><br></span><span class="token-line codeLine_lJS_" style="color:#bfc7d5"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">    listen 80;</span></span><br></span><span class="token-line codeLine_lJS_" style="color:#bfc7d5"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">    server_name &lt;your_domain_here&gt; &lt;your_ip_address_here&gt;;</span></span><br></span><span class="token-line codeLine_lJS_" style="color:#bfc7d5"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">    client_max_body_size 75M;</span></span><br></span><span class="token-line codeLine_lJS_" style="color:#bfc7d5"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">    location / {</span></span><br></span><span class="token-line codeLine_lJS_" style="color:#bfc7d5"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">        include proxy_params;</span></span><br></span><span class="token-line codeLine_lJS_" style="color:#bfc7d5"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">        proxy_pass http://unix:/var/www/CTFd/app.sock;</span></span><br></span><span class="token-line codeLine_lJS_" style="color:#bfc7d5"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain" style="display:inline-block"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#bfc7d5"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">    }</span></span><br></span><span class="token-line codeLine_lJS_" style="color:#bfc7d5"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">}</span></span><br></span><span class="token-line codeLine_lJS_" style="color:#bfc7d5"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain" style="display:inline-block"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#bfc7d5"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain"># Link config file</span></span><br></span><span class="token-line codeLine_lJS_" style="color:#bfc7d5"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">sudo ln -s /etc/nginx/sites-available/ctfd /etc/nginx/sites-enabled</span></span><br></span><span class="token-line codeLine_lJS_" style="color:#bfc7d5"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain" style="display:inline-block"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#bfc7d5"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain"># Remove defaults</span></span><br></span><span class="token-line codeLine_lJS_" style="color:#bfc7d5"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">sudo rm /etc/nginx/sites-available/default /etc/nginx/sites-enabled/default</span></span><br></span><span class="token-line codeLine_lJS_" style="color:#bfc7d5"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain" style="display:inline-block"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#bfc7d5"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain"># Test nginx configuration</span></span><br></span><span class="token-line codeLine_lJS_" style="color:#bfc7d5"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">sudo nginx -t</span></span><br></span><span class="token-line codeLine_lJS_" style="color:#bfc7d5"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain" style="display:inline-block"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#bfc7d5"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain"># Restart nginx if test wasw good</span></span><br></span><span class="token-line codeLine_lJS_" style="color:#bfc7d5"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">sudo systemctl restart nginx</span></span><br></span></code></pre></div></div>
<div class="theme-admonition theme-admonition-tip admonition_xJq3 alert alert--success"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>tip</div><div class="admonitionContent_BuS1"><p>You may run the following code to view the access and error logs:</p><ul>
<li class=""><code>tail /var/log/CTFd/CTFd/logs/access.log</code></li>
<li class=""><code>tail /var/log/CTFd/CTFd/logs/error.log</code></li>
</ul></div></div>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="configuring-the-site-for-better-security">Configuring the site for better security<a href="https://sudojoie.com/deploying-a-ctfd-site-azure#configuring-the-site-for-better-security" class="hash-link" aria-label="Direct link to Configuring the site for better security" title="Direct link to Configuring the site for better security" translate="no">​</a></h2>
<p>It's important to secure our website to avoid compromising the confidentiality, integrity, and availability of our site. What's more is cloud service providers are often vulnerable by default and it's our job, as customers, to configure the cloud to fit our needs.</p>
<p>In this section, we discuss some configurions we can do to make our CTFd site more secure.</p>
<h3 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="adding-an-ssl-certificate">Adding an SSL certificate<a href="https://sudojoie.com/deploying-a-ctfd-site-azure#adding-an-ssl-certificate" class="hash-link" aria-label="Direct link to Adding an SSL certificate" title="Direct link to Adding an SSL certificate" translate="no">​</a></h3>
<p>A simple and free way to add an SSL certificate for your site is by using certbot. Visit the <a href="https://certbot.eff.org/instructions?ws=nginx&amp;os=ubuntufocal&amp;tab=standard" target="_blank" rel="noopener noreferrer" class="">certbot website</a> and follow the instructions for installation. Note that you must make sure to select the corresponding OS and web server.</p>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>info</div><div class="admonitionContent_BuS1"><p>If you have your own certificate, visit this <a class="" href="https://sudojoie.com/importing-ssl-cert-from-key-vault-to-a-linux-vm#storing-a-certificate-in-key-vault">page</a> to learn the steps to store your certificate in Azure Key Vault and use it in your VM.</p></div></div>
<h3 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="changing-the-ssh-port">Changing the SSH Port<a href="https://sudojoie.com/deploying-a-ctfd-site-azure#changing-the-ssh-port" class="hash-link" aria-label="Direct link to Changing the SSH Port" title="Direct link to Changing the SSH Port" translate="no">​</a></h3>
<p>Below is the process of changing the SSH port. For instance, changing it from <strong>port 22</strong> to <strong>port 1234</strong>. Make sure that the port you will use is available.</p>
<div class="language-shell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-shell codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config_backup</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">sudo vim /etc/ssh/sshd_config</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"># uncomment "#Port 22" and change the port number</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"># example:</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">Port 1234</span><br></span></code></pre></div></div>
<div class="language-shell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-shell codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain"># update the firewall</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">sudo ufw allow 1234</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"># delete OpenSSH</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">sudo ufw status numbered</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">sudo ufw delete &lt;enter_here_the_number_of_OpenSSH&gt;</span><br></span></code></pre></div></div>
<p>In Azure, update the NSG inbound rules to allow the port you chose. In the example above, it's port 1234. Remove the SSH port 22 inbound rule as well.</p>
<div class="theme-admonition theme-admonition-tip admonition_xJq3 alert alert--success"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>tip</div><div class="admonitionContent_BuS1"><p>Cannot SSH into the VM after changing the SSH port? You can still access the VM by going to your VM page in Azure portal and selecting the "Run Commands" option at the sidebar. For further info, check out this <a href="https://learn.microsoft.com/en-us/troubleshoot/azure/virtual-machines/troubleshoot-ssh-connection" target="_blank" rel="noopener noreferrer" class="">troubleshooting guide</a>.</p></div></div>
<h3 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="configuring-the-ctfd-platform-as-an-internal-site">Configuring the CTFd platform as an internal site<a href="https://sudojoie.com/deploying-a-ctfd-site-azure#configuring-the-ctfd-platform-as-an-internal-site" class="hash-link" aria-label="Direct link to Configuring the CTFd platform as an internal site" title="Direct link to Configuring the CTFd platform as an internal site" translate="no">​</a></h3>
<p>If you don't want to expose your site to the public internet, remove the public IP and use the private IP as point of access to the site. You may also want to register a domain and configure its DNS record to point to the private IP.</p>
<div class="theme-admonition theme-admonition-tip admonition_xJq3 alert alert--success"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>tip</div><div class="admonitionContent_BuS1"><p>If you need help with setting up DNS records, you can visit <a href="https://www.cloudflare.com/learning/dns/dns-records/dns-a-record/" target="_blank" rel="noopener noreferrer" class="">this page</a> to learn more about setting up the A records.</p></div></div>
<p>Steps:</p>
<ol>
<li class="">After removing the public IP, update the IP address in Nginx.</li>
</ol>
<div class="language-shell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-shell codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv codeBlockLinesWithNumbering_o6Pm" style="counter-reset:line-count 0"><span class="token-line codeLine_lJS_" style="color:#bfc7d5"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain"># let's encrypt will handle the https later</span></span><br></span><span class="token-line codeLine_lJS_" style="color:#bfc7d5"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">sudo vim /etc/nginx/sites-available/ctfd</span></span><br></span><span class="token-line codeLine_lJS_" style="color:#bfc7d5"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain" style="display:inline-block"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#bfc7d5"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain"># Nginx config (copy lines 6-15)</span></span><br></span><span class="token-line codeLine_lJS_" style="color:#bfc7d5"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain"># the client_max_body_size enables file uploads over the default of 1MB</span></span><br></span><span class="token-line codeLine_lJS_" style="color:#bfc7d5"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">server {</span></span><br></span><span class="token-line codeLine_lJS_" style="color:#bfc7d5"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">    listen 80;</span></span><br></span><span class="token-line theme-code-block-highlighted-line codeLine_lJS_" style="color:#bfc7d5"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">    server_name &lt;your_domain_here&gt; &lt;your_ip_address_here&gt;;</span></span><br></span><span class="token-line codeLine_lJS_" style="color:#bfc7d5"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">    client_max_body_size 75M;</span></span><br></span><span class="token-line codeLine_lJS_" style="color:#bfc7d5"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">    location / {</span></span><br></span><span class="token-line codeLine_lJS_" style="color:#bfc7d5"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">        include proxy_params;</span></span><br></span><span class="token-line codeLine_lJS_" style="color:#bfc7d5"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">        proxy_pass http://unix:/var/www/CTFd/app.sock;</span></span><br></span><span class="token-line codeLine_lJS_" style="color:#bfc7d5"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain" style="display:inline-block"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#bfc7d5"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">    }</span></span><br></span><span class="token-line codeLine_lJS_" style="color:#bfc7d5"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">}</span></span><br></span></code></pre></div></div>
<ol start="2">
<li class="">
<p>Restart Nginx and test the site.</p>
</li>
<li class="">
<p>In Azure, configure a virtual network (VNET) that is setup for internal sites or apps and use that VNET for your CTFd server.</p>
</li>
</ol>
<div class="theme-admonition theme-admonition-note admonition_xJq3 alert alert--secondary"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>note</div><div class="admonitionContent_BuS1"><p>As of writing, Azure doesn't support changing the VNET of VMs (<a href="https://learn.microsoft.com/en-us/answers/questions/130410/how-to-change-the-vnet-of-a-vm" target="_blank" rel="noopener noreferrer" class="">related resource</a>). You may need to redeploy your VM if you want to change your VNET.</p></div></div>
<ol start="4">
<li class="">Final step is to change your NSG inbound rules and set them to receive sources from your VNET.</li>
</ol>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="theme-configuration">Theme Configuration<a href="https://sudojoie.com/deploying-a-ctfd-site-azure#theme-configuration" class="hash-link" aria-label="Direct link to Theme Configuration" title="Direct link to Theme Configuration" translate="no">​</a></h2>
<ol>
<li class="">
<p>I will use the Pixio theme as an example (<a href="https://github.com/hmrserver/CTFd-theme-pixo" target="_blank" rel="noopener noreferrer" class="">Theme Repository</a>)</p>
</li>
<li class="">
<p>Clone the repository in the CTFd theme folder by running the command</p>
<div class="language-shell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-shell codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">git https://github.com/hmrserver/CTFd-theme-pixo /var/www/CTFd/CTFd/themes/</span><br></span></code></pre></div></div>
</li>
<li class="">
<p>Login as admin and change the theme in the config page.</p>
</li>
<li class="">
<p>You may also customize the theme header. For instance,</p>
<div class="language-html codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-html codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token tag" style="color:rgb(255, 85, 114)">style</span><span class="token tag" style="color:rgb(255, 85, 114)"> </span><span class="token tag attr-name" style="color:rgb(255, 203, 107)">id</span><span class="token tag attr-value punctuation attr-equals" style="color:rgb(199, 146, 234)">=</span><span class="token tag attr-value punctuation" style="color:rgb(199, 146, 234)">"</span><span class="token tag attr-value" style="color:rgb(255, 85, 114)">theme-color</span><span class="token tag attr-value punctuation" style="color:rgb(199, 146, 234)">"</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token style language-css"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token style language-css"> </span><span class="token style language-css selector pseudo-class" style="color:rgb(199, 146, 234)">:root</span><span class="token style language-css"> </span><span class="token style language-css punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token style language-css variable" style="color:rgb(191, 199, 213)">--theme-color</span><span class="token style language-css punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token style language-css"> </span><span class="token style language-css hexcode color">#17377f</span><span class="token style language-css punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token style language-css punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token style language-css"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token style language-css"> </span><span class="token style language-css selector class" style="color:rgb(199, 146, 234)">.navbar</span><span class="token style language-css punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token style language-css property">background-color</span><span class="token style language-css punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token style language-css"> </span><span class="token style language-css function" style="color:rgb(130, 170, 255)">var</span><span class="token style language-css punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token style language-css variable" style="color:rgb(191, 199, 213)">--theme-color</span><span class="token style language-css punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token style language-css"> </span><span class="token style language-css important">!important</span><span class="token style language-css punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token style language-css punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token style language-css"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token style language-css"> </span><span class="token style language-css selector class" style="color:rgb(199, 146, 234)">.jumbotron</span><span class="token style language-css punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token style language-css property">background-color</span><span class="token style language-css punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token style language-css"> </span><span class="token style language-css function" style="color:rgb(130, 170, 255)">var</span><span class="token style language-css punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token style language-css variable" style="color:rgb(191, 199, 213)">--theme-color</span><span class="token style language-css punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token style language-css"> </span><span class="token style language-css important">!important</span><span class="token style language-css punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token style language-css punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token style language-css"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token style language-css"> </span><span class="token style language-css selector class" style="color:rgb(199, 146, 234)">.modal-content</span><span class="token style language-css punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token style language-css property">background-color</span><span class="token style language-css punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token style language-css"> </span><span class="token style language-css hexcode color">#0E204B</span><span class="token style language-css"> </span><span class="token style language-css important">!important</span><span class="token style language-css punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token style language-css punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token style language-css"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token style language-css"> </span><span class="token style language-css selector class" style="color:rgb(199, 146, 234)">.challenge-button</span><span class="token style language-css punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token style language-css property">box-shadow</span><span class="token style language-css punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token style language-css"> </span><span class="token style language-css number" style="color:rgb(247, 140, 108)">3</span><span class="token style language-css unit">px</span><span class="token style language-css"> </span><span class="token style language-css number" style="color:rgb(247, 140, 108)">3</span><span class="token style language-css unit">px</span><span class="token style language-css"> </span><span class="token style language-css hexcode color">#004CFF</span><span class="token style language-css"> </span><span class="token style language-css important">!important</span><span class="token style language-css punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token style language-css"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token style language-css"></span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;/</span><span class="token tag" style="color:rgb(255, 85, 114)">style</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><br></span></code></pre></div></div>
</li>
<li class="">
<p>You may also customize the footer content. For instance,</p>
<div class="language-html codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-html codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token tag" style="color:rgb(255, 85, 114)">script</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token script language-javascript"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token script language-javascript"> </span><span class="token script language-javascript dom variable" style="color:rgb(191, 199, 213)">document</span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token script language-javascript method function property-access" style="color:rgb(130, 170, 255)">querySelector</span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token script language-javascript string" style="color:rgb(195, 232, 141)">"footer a"</span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token script language-javascript property-access">innerText</span><span class="token script language-javascript"> </span><span class="token script language-javascript operator" style="color:rgb(137, 221, 255)">=</span><span class="token script language-javascript"> </span><span class="token script language-javascript string" style="color:rgb(195, 232, 141)">"Powered by MyOrg"</span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token script language-javascript"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token script language-javascript"> </span><span class="token script language-javascript dom variable" style="color:rgb(191, 199, 213)">document</span><span class="token script language-javascript"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token script language-javascript">   </span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token script language-javascript method function property-access" style="color:rgb(130, 170, 255)">querySelector</span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token script language-javascript string" style="color:rgb(195, 232, 141)">"footer a"</span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token script language-javascript"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token script language-javascript">   </span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token script language-javascript method function property-access" style="color:rgb(130, 170, 255)">setAttribute</span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token script language-javascript string" style="color:rgb(195, 232, 141)">"href"</span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token script language-javascript"> </span><span class="token script language-javascript string" style="color:rgb(195, 232, 141)">"https://myorg.com"</span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token script language-javascript"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token script language-javascript"></span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;/</span><span class="token tag" style="color:rgb(255, 85, 114)">script</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><br></span></code></pre></div></div>
</li>
</ol>
<h3 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="configuring-the-flicker-effect-of-pixio-theme">Configuring the flicker effect of Pixio theme<a href="https://sudojoie.com/deploying-a-ctfd-site-azure#configuring-the-flicker-effect-of-pixio-theme" class="hash-link" aria-label="Direct link to Configuring the flicker effect of Pixio theme" title="Direct link to Configuring the flicker effect of Pixio theme" translate="no">​</a></h3>
<p>I noticed that the flicker effect of this particular theme may be unpleasant for some. To remove the flicker, simply follow the steps below.</p>
<ol>
<li class="">
<p><code>cd /var/www/CTFd</code></p>
</li>
<li class="">
<p>go to <code>CTFd/themes/pixo/static/css</code></p>
</li>
<li class="">
<p>do <code>sudo vi main.min.css</code></p>
</li>
<li class="">
<p>find <code>@keyframes flicker</code></p>
</li>
<li class="">
<p>delete everything in it except the 0% and 100%</p>
</li>
<li class="">
<p>change the parameter of 0% and 100% to "opacity" to ".5"</p>
<div class="language-css codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-css codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token atrule rule">@keyframes</span><span class="token atrule"> flicker</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token selector" style="color:rgb(199, 146, 234)">0%</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token property">opacity</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">0.5</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token selector punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token selector" style="color:rgb(199, 146, 234)"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token selector" style="color:rgb(199, 146, 234)">  100%</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token property">opacity</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">0.5</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></span></code></pre></div></div>
</li>
</ol>]]></content:encoded>
            <category>CTF</category>
            <category>Tutorial</category>
            <category>Web Development</category>
            <category>Azure</category>
            <category>Cloud</category>
        </item>
        <item>
            <title><![CDATA[ReactJS: State Persistence Using React Recoil]]></title>
            <link>https://sudojoie.com/reactjs-state-persistence-using-react-recoil</link>
            <guid>https://sudojoie.com/reactjs-state-persistence-using-react-recoil</guid>
            <pubDate>Thu, 24 Feb 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[Recoil is an open-source experimental state management library by Facebook.]]></description>
            <content:encoded><![CDATA[<p><a href="https://github.com/facebookexperimental/Recoil" target="_blank" rel="noopener noreferrer" class="">Recoil</a> is an open-source experimental state management library by Facebook. It's one of the many libraries that makes managing states easier like persisting the theme state (light/dark mode) of your website. Other examples of such libraries are Xstate, Redux, Zustand, and Jotai.</p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="getting-started">Getting Started<a href="https://sudojoie.com/reactjs-state-persistence-using-react-recoil#getting-started" class="hash-link" aria-label="Direct link to Getting Started" title="Direct link to Getting Started" translate="no">​</a></h2>
<p>In your project, install Recoil using the npm command below.</p>
<div class="language-shell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-shell codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">npm install recoil</span><br></span></code></pre></div></div>
<p>or if you're using yarn.</p>
<div class="language-shell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-shell codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">yarn add recoil</span><br></span></code></pre></div></div>
<p>You can view more installation guides in the documentation <a href="https://recoiljs.org/docs/introduction/installation" target="_blank" rel="noopener noreferrer" class="">here</a>.</p>
<p>Next, we need to add Recoil to our <code>index.js</code> so that we can use it everywhere in our project.</p>
<div class="language-javascript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-javascript codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token spread operator" style="color:rgb(137, 221, 255)">...</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword module" style="font-style:italic">import</span><span class="token plain"> </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token imports"> </span><span class="token imports maybe-class-name">RecoilRoot</span><span class="token imports"> </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword module" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"recoil"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token maybe-class-name">ReactDOM</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">render</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token spread operator" style="color:rgb(137, 221, 255)">...</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token maybe-class-name">RecoilRoot</span><span class="token operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token maybe-class-name">AppRoutes</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">/</span><span class="token operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token operator" style="color:rgb(137, 221, 255)">/</span><span class="token maybe-class-name">RecoilRoot</span><span class="token operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token spread operator" style="color:rgb(137, 221, 255)">...</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token dom variable" style="color:rgb(191, 199, 213)">document</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">getElementById</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">'root'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="creating-an-atom">Creating an atom<a href="https://sudojoie.com/reactjs-state-persistence-using-react-recoil#creating-an-atom" class="hash-link" aria-label="Direct link to Creating an atom" title="Direct link to Creating an atom" translate="no">​</a></h2>
<p>Atoms contain the source of truth for our application state and below is an example of creating an atom.</p>
<div class="language-javascript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-javascript codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token keyword module" style="font-style:italic">export</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> darkModeState </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">atom</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token literal-property property">key</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'darkMode'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword module" style="font-style:italic">default</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">false</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></span></code></pre></div></div>
<p>For use cases like this, I like to put my atoms inside a <code>globalState.js</code> file inside the shared folder of my project. This is because many components will share this atom. Moreover, inside the atom that I made is a unique key and a default value. An atom key is a serializable value that labels the atom and it's useful especially when we want to persist our state. On the other hand, the default value is the default state of the atom.</p>
<p>Using the atom in your component is almost similar to useState hooks.</p>
<div class="language-javascript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-javascript codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token plain">isDarkModeEnabled</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> setIsDarkModeEnabled</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">useRecoilState</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">darkModeState</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></span></code></pre></div></div>
<p>Instead of <code>useState</code>, we use <code>useRecoilState</code> and instead of passing the default state, e.g., false, we pass in our atom, i.e., <code>darkModeState</code>.</p>
<p>When we don't need to change the state of the atom and only need access to its value, we can simply do it like the code snippet below.</p>
<div class="language-javascript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-javascript codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> isDarkModeEnabled </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">useRecoilValue</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">darkModeState</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="saving-the-state-to-local-storage">Saving the state to local storage<a href="https://sudojoie.com/reactjs-state-persistence-using-react-recoil#saving-the-state-to-local-storage" class="hash-link" aria-label="Direct link to Saving the state to local storage" title="Direct link to Saving the state to local storage" translate="no">​</a></h2>
<p>There are use cases when we want to keep states like saving the preferred theme to the website visitor's browser local storage. This helps returning visitors to keep their preferred settings that they set on their previous visit.</p>
<p>Below is an example of using Recoil to persist the theme of a website.</p>
<div class="language-javascript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-javascript codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> </span><span class="token function-variable function" style="color:rgb(130, 170, 255)">localPersist</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token parameter punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token parameter">onSet</span><span class="token parameter punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token parameter"> setSelf</span><span class="token parameter punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token parameter"> node</span><span class="token parameter punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> storedData </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token dom variable" style="color:rgb(191, 199, 213)">localStorage</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">getItem</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">node</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token property-access">key</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword control-flow" style="font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">storedData </span><span class="token operator" style="color:rgb(137, 221, 255)">!=</span><span class="token plain"> </span><span class="token keyword null nil" style="font-style:italic">null</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token function" style="color:rgb(130, 170, 255)">setSelf</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token known-class-name class-name" style="color:rgb(255, 203, 107)">JSON</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">parse</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">storedData</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token function" style="color:rgb(130, 170, 255)">onSet</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token parameter">newData</span><span class="token parameter punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token parameter"> __</span><span class="token parameter punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token parameter"> isReset</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    isReset</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token operator" style="color:rgb(137, 221, 255)">?</span><span class="token plain"> </span><span class="token dom variable" style="color:rgb(191, 199, 213)">localStorage</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">removeItem</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">node</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token property-access">key</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token dom variable" style="color:rgb(191, 199, 213)">localStorage</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">setItem</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">node</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token property-access">key</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token known-class-name class-name" style="color:rgb(255, 203, 107)">JSON</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">stringify</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">newData</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword module" style="font-style:italic">export</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> darkModeState </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">atom</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token literal-property property">key</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'darkMode'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword module" style="font-style:italic">default</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">false</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token literal-property property">effects</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token plain">localPersist</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></span></code></pre></div></div>
<p>Notice the <code>effects</code> parameter that I added to my atom. That parameter is called <a href="https://recoiljs.org/docs/guides/atom-effects/" target="_blank" rel="noopener noreferrer" class="">atom effects</a> and it's an API for managing side-effects and synchronizing or initializing Recoil atoms. It's typically used in state persistence, synchronization, managing history, etc. As seen above, I passed the function that handles saving, removing, and getting the state from the browser's local storage</p>
<p>Furthermore, the <code>localPersist</code> function can be called by any atom. In other words, if you need a state to persist, you can just call the function to persist your state. Besides boolean values, the function also works for other data types like strings, objects, and arrays.</p>
<div class="language-javascript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-javascript codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token keyword module" style="font-style:italic">export</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> myStringState </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">atom</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token literal-property property">key</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'myString'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword module" style="font-style:italic">default</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">''</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token literal-property property">effects</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token plain">localPersist</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword module" style="font-style:italic">export</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> myListState </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">atom</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token literal-property property">key</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'myList'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword module" style="font-style:italic">default</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token literal-property property">effects</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token plain">localPersist</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></span></code></pre></div></div>
<p>Inside the <code>localPersist</code> function we have the <code>onSet</code> function which gets called when our atom changes. To get the state from our local storage, we use the <code>setSelf</code> function. Moreover, the <code>isReset</code> function is used when the <code>useResetRecoilState</code> is called which removes the state from the browser's local storage.</p>
<p>Now that we've finished setting up the <code>globalState.js</code>, we now have states that are accessible to multiple components which also persists. You can check if it works by going to <code>inspect element &gt; Application tab &gt; Storage &gt; Local Storage &gt; http://your-website-url</code>.</p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="final-thoughts">Final Thoughts<a href="https://sudojoie.com/reactjs-state-persistence-using-react-recoil#final-thoughts" class="hash-link" aria-label="Direct link to Final Thoughts" title="Direct link to Final Thoughts" translate="no">​</a></h2>
<p>Recoil is easy to implement and as seen earlier, it's similar to how we use <code>useState</code>. There are many new state management libraries currently existing and maybe more will be released. Jotai is an example of a state management library that is similar to Recoil–they are both atomic. Other types of libraries are flux (Redux, Zustand) and proxy (Mobs, Valtio, Overmind). At the end of the day, choosing the right library for your project depends on many variables like package size, use case, and more.</p>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>tutorial demo</div><div class="admonitionContent_BuS1"><p>Click <a href="https://github.com/joiellantero/react-recoil-demo" target="_blank" rel="noopener noreferrer" class="">here</a> to view a sample implementation of what we've discussed.</p></div></div>]]></content:encoded>
            <category>ReactJS</category>
            <category>Tutorial</category>
            <category>Recoil</category>
        </item>
        <item>
            <title><![CDATA[Python: Building An Offline Random Name Picker]]></title>
            <link>https://sudojoie.com/python-building-an-offline-random-name-picker</link>
            <guid>https://sudojoie.com/python-building-an-offline-random-name-picker</guid>
            <pubDate>Sun, 13 Feb 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[A terminal-based app to choose a random name from a list.]]></description>
            <content:encoded><![CDATA[<p>When we shifted to an online setup due to the pandemic, we had so many online activities where we needed a random name picker. There are websites that offer this service but, I wanted to have a privacy-centered program that can read a large list of names and runs on my own computer. Since this is offline and we control the code, we become sure that the data stays private.</p>
<p>I created a program that a user can run in their terminal using Python and it can read a list of names from either a comma-separated-value (<code>.csv</code>) file or a text (<code>.txt</code>) file.</p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="giving-the-program-settings-some-flexibility">Giving the program settings some flexibility<a href="https://sudojoie.com/python-building-an-offline-random-name-picker#giving-the-program-settings-some-flexibility" class="hash-link" aria-label="Direct link to Giving the program settings some flexibility" title="Direct link to Giving the program settings some flexibility" translate="no">​</a></h2>
<p>I wanted the program to take in arguments and command-line options so that I can easily adjust the settings to my liking. I used Python's argument parser library, <a href="https://pypi.org/project/argparse/" target="_blank" rel="noopener noreferrer" class="">argparse</a>, for this. I created two positional arguments that takes in a file and integer value. The file should contain the list of names whereas the integer is the number of people to be chosen randomly.</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">parser </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> argparse</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">ArgumentParser</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">description</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token string" style="color:rgb(195, 232, 141)">'Name Roulette. A random picker for names.'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">parser</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">add_argument</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token string" style="color:rgb(195, 232, 141)">'file'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    metavar</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token string" style="color:rgb(195, 232, 141)">'filename'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token builtin" style="color:rgb(130, 170, 255)">type</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token builtin" style="color:rgb(130, 170, 255)">str</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token builtin" style="color:rgb(130, 170, 255)">help</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token string" style="color:rgb(195, 232, 141)">'Files accepted are csv and txt files. Add the filename of the text or csv file containing the names as an argument, e.g., fileName.csv. Each name should be entered in a new line. You may refer to the README.md to see more examples.'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">parser</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">add_argument</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token string" style="color:rgb(195, 232, 141)">'amount'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    metavar</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token string" style="color:rgb(195, 232, 141)">'amount'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    nargs</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token string" style="color:rgb(195, 232, 141)">'?'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#bfc7d5"><span class="token plain">    default</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token number" style="color:rgb(247, 140, 108)">1</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token builtin" style="color:rgb(130, 170, 255)">type</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token builtin" style="color:rgb(130, 170, 255)">int</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token builtin" style="color:rgb(130, 170, 255)">help</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token string" style="color:rgb(195, 232, 141)">'The number of people to be chosen randomly.'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><br></span></code></pre></div></div>
<div class="theme-admonition theme-admonition-note admonition_xJq3 alert alert--secondary"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>note</div><div class="admonitionContent_BuS1"><p>The <code>amount</code> argument has a default value of 1 because this is the value when the user doesn't specify the number of people to be chosen, then the program should only choose one random name at a time.</p></div></div>
<p>Next, I also wanted to have optional arguments for removing the name after it was chosen, displaying the list of names, and <a href="https://pypi.org/project/cowsay/" target="_blank" rel="noopener noreferrer" class="">cowsay</a>.</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">parser</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">add_argument</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token string" style="color:rgb(195, 232, 141)">'--repeat'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    action</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token string" style="color:rgb(195, 232, 141)">"store_true"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    required</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token boolean" style="color:rgb(255, 88, 116)">False</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token builtin" style="color:rgb(130, 170, 255)">help</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token string" style="color:rgb(195, 232, 141)">'Loop through the names of the players forever. Not including the --repeat flag will remove the player from the list once they are chosen.'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">parser</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">add_argument</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token string" style="color:rgb(195, 232, 141)">'--display'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    action</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token string" style="color:rgb(195, 232, 141)">"store_true"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    required</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token boolean" style="color:rgb(255, 88, 116)">False</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token builtin" style="color:rgb(130, 170, 255)">help</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token string" style="color:rgb(195, 232, 141)">'Show the list of names.'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">parser</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">add_argument</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token string" style="color:rgb(195, 232, 141)">'--cowsay'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    action</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token string" style="color:rgb(195, 232, 141)">"store_true"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    required</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token boolean" style="color:rgb(255, 88, 116)">False</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token builtin" style="color:rgb(130, 170, 255)">help</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token string" style="color:rgb(195, 232, 141)">'Show chosen name/s with cowsay illustration.'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><br></span></code></pre></div></div>
<p>When the <code>--repeat</code> flag is specified by the user, it should choose random names from the list without removing them. On the other hand, when it's not specified, the program will remove the name from the list after it is chosen.</p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="file-handling">File handling<a href="https://sudojoie.com/python-building-an-offline-random-name-picker#file-handling" class="hash-link" aria-label="Direct link to File handling" title="Direct link to File handling" translate="no">​</a></h2>
<p>The first thing that my program does is to read the filenames check if it exists. I also added error handling to make sure that the user remembers to put the file type, i.e., if it's a <code>.csv</code> or <code>.txt</code> file. I used Python's <a href="https://pypi.org/project/pandas/" target="_blank" rel="noopener noreferrer" class="">pandas</a> library to obtain the names from the <code>.csv</code> or <code>.txt</code> file. Note that the program doesn't edit the input file instead, it saves a copy of the names. This is related to the <code>–repeat</code> flag because not indicating the said flag would remove the name from the list.</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">def</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">get_names</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">filename</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">try</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        names_df </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> pd</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">read_csv</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">filename</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> sep</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token string" style="color:rgb(195, 232, 141)">","</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> header</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token boolean" style="color:rgb(255, 88, 116)">None</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> names</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token string" style="color:rgb(195, 232, 141)">"Names"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        names_df</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token string" style="color:rgb(195, 232, 141)">'Names'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> names_df</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token string" style="color:rgb(195, 232, 141)">'Names'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">astype</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">'string'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> names_df</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">except</span><span class="token plain"> FileNotFoundError</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token keyword" style="font-style:italic">print</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string-interpolation string" style="color:rgb(195, 232, 141)">f"\nFile '</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token string-interpolation interpolation">filename</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token string-interpolation string" style="color:rgb(195, 232, 141)">' does not exist."</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> filename</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token operator" style="color:rgb(137, 221, 255)">-</span><span class="token number" style="color:rgb(247, 140, 108)">4</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">!=</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'.csv'</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">and</span><span class="token plain"> filename</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token operator" style="color:rgb(137, 221, 255)">-</span><span class="token number" style="color:rgb(247, 140, 108)">4</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">!=</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'.txt'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            </span><span class="token keyword" style="font-style:italic">print</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string-interpolation string" style="color:rgb(195, 232, 141)">f"Please include file type, e.g., </span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token string-interpolation interpolation">filename</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token string-interpolation string" style="color:rgb(195, 232, 141)">.txt or </span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token string-interpolation interpolation">filename</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token string-interpolation string" style="color:rgb(195, 232, 141)">.csv."</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        sys</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">exit</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token number" style="color:rgb(247, 140, 108)">0</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="randomly-choosing-a-name">Randomly choosing a name<a href="https://sudojoie.com/python-building-an-offline-random-name-picker#randomly-choosing-a-name" class="hash-link" aria-label="Direct link to Randomly choosing a name" title="Direct link to Randomly choosing a name" translate="no">​</a></h2>
<p>Now that I have the list of names ready, we can now proceed to creating the function to pick a random name. This function should take in all the positional and optional arguments. I again used pandas to pick a random name from the list and to also remove the name from the list.</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">def</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">draw_name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">df</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> amount</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> repeat</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> display</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> acowsay</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">while</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">not</span><span class="token plain"> df</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">empty</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        chosen_name </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token keyword" style="font-style:italic">for</span><span class="token plain"> i </span><span class="token keyword" style="font-style:italic">in</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">range</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token number" style="color:rgb(247, 140, 108)">0</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> amount</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            </span><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> df</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">empty</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">                </span><span class="token keyword" style="font-style:italic">break</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            chosen_name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">append</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">df</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">loc</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token plain">df</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">sample</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">index</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token number" style="color:rgb(247, 140, 108)">0</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'Names'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            </span><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">not</span><span class="token plain"> repeat</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">                df </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> df</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token plain">df</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token string" style="color:rgb(195, 232, 141)">"Names"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token builtin" style="color:rgb(130, 170, 255)">str</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">contains</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">chosen_name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token plain">i</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token operator" style="color:rgb(137, 221, 255)">==</span><span class="token boolean" style="color:rgb(255, 88, 116)">False</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> display </span><span class="token keyword" style="font-style:italic">and</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">not</span><span class="token plain"> df</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">empty</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            </span><span class="token keyword" style="font-style:italic">print</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">df</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> acowsay</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            cowsay</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">tux</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">', '</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">join</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">chosen_name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token keyword" style="font-style:italic">else</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            </span><span class="token keyword" style="font-style:italic">print</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string-interpolation string" style="color:rgb(195, 232, 141)">f"\nChosen Name/s: </span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token string-interpolation interpolation string" style="color:rgb(195, 232, 141)">', '</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token string-interpolation interpolation">join</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string-interpolation interpolation">chosen_name</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token string-interpolation string" style="color:rgb(195, 232, 141)">"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">else</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token keyword" style="font-style:italic">print</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"\nProgram Ended.\nList of names is now empty."</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        sys</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">exit</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token number" style="color:rgb(247, 140, 108)">0</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><br></span></code></pre></div></div>
<p>The user should also have an option to pick another name or not. Thus, I created another function called <code>ask_choose_again()</code> to do this task. I then called this function at the end of the while loop in the <code>draw_name()</code> function.</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">def</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">ask_choose_again</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    again </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">input</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"\nChoose again? [Y/N]: "</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">again </span><span class="token operator" style="color:rgb(137, 221, 255)">==</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'y'</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">or</span><span class="token plain"> again </span><span class="token operator" style="color:rgb(137, 221, 255)">==</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'Y'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">elif</span><span class="token plain"> again </span><span class="token operator" style="color:rgb(137, 221, 255)">==</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'n'</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">or</span><span class="token plain"> again </span><span class="token operator" style="color:rgb(137, 221, 255)">==</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'N'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token keyword" style="font-style:italic">print</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"\nProgram ended."</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        sys</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">exit</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token number" style="color:rgb(247, 140, 108)">0</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">else</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token keyword" style="font-style:italic">print</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"\nInvalid input: type Y for yes or N for no."</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        ask_choose_again</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="improving-the-user-experience">Improving the user experience<a href="https://sudojoie.com/python-building-an-offline-random-name-picker#improving-the-user-experience" class="hash-link" aria-label="Direct link to Improving the user experience" title="Direct link to Improving the user experience" translate="no">​</a></h2>
<p>To give some aesthetics to my program, I added a loading animation to simulate that the program is picking a name–kind of like a drum roll. Note that the loading time is fake and it doesn't really depict the true speed of the program when choosing a name from a list because doing that would be very quick to even see the animation. In my program, I set the loading animation to show up for one-second but you can easily change it by adjusting the value in the <code>time.sleep(x)</code>.</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">def</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">loading_animation</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    done </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">False</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">def</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">animate</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token keyword" style="font-style:italic">for</span><span class="token plain"> c </span><span class="token keyword" style="font-style:italic">in</span><span class="token plain"> itertools</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">cycle</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token string" style="color:rgb(195, 232, 141)">'|'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'/'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'-'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'\\'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            </span><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> done</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">                </span><span class="token keyword" style="font-style:italic">break</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            sys</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">stdout</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">write</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">'\rchoosing someone... '</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">+</span><span class="token plain"> c</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            sys</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">stdout</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">flush</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            time</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">sleep</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token number" style="color:rgb(247, 140, 108)">0.1</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    t </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> threading</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">Thread</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">target</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain">animate</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    t</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">start</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    time</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">sleep</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token number" style="color:rgb(247, 140, 108)">1</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    done </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">True</span><br></span></code></pre></div></div>
<p>I also added a clear screen function to clean up the terminal every time we pick a random name.</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">def</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">clear_terminal</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    os</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">system</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">'cls'</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> os</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">name </span><span class="token operator" style="color:rgb(137, 221, 255)">==</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'nt'</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">else</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'clear'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><br></span></code></pre></div></div>
<p>Finally, I added the <code>loading_animation()</code> and <code>clear_terminal()</code> function calls to my <code>draw_name()</code> function.</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">def</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">draw_name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">df</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> amount</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> repeat</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> display</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> acowsay</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">while</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">not</span><span class="token plain"> df</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">empty</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#bfc7d5"><span class="token plain">        clear_terminal</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#bfc7d5"><span class="token plain">        loading_animation</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#bfc7d5"><span class="token plain">        clear_terminal</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        chosen_name </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token keyword" style="font-style:italic">for</span><span class="token plain"> i </span><span class="token keyword" style="font-style:italic">in</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">range</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token number" style="color:rgb(247, 140, 108)">0</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> amount</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            </span><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> df</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">empty</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">                </span><span class="token keyword" style="font-style:italic">break</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            chosen_name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">append</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">df</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">loc</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token plain">df</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">sample</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">index</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token number" style="color:rgb(247, 140, 108)">0</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'Names'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            </span><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">not</span><span class="token plain"> repeat</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">                df </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> df</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token plain">df</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token string" style="color:rgb(195, 232, 141)">"Names"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token builtin" style="color:rgb(130, 170, 255)">str</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">contains</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">chosen_name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token plain">i</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token operator" style="color:rgb(137, 221, 255)">==</span><span class="token boolean" style="color:rgb(255, 88, 116)">False</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> display </span><span class="token keyword" style="font-style:italic">and</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">not</span><span class="token plain"> df</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">empty</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            </span><span class="token keyword" style="font-style:italic">print</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">df</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> acowsay</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            cowsay</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">tux</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">', '</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">join</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">chosen_name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token keyword" style="font-style:italic">else</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            </span><span class="token keyword" style="font-style:italic">print</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string-interpolation string" style="color:rgb(195, 232, 141)">f"\nChosen Name/s: </span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token string-interpolation interpolation string" style="color:rgb(195, 232, 141)">', '</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token string-interpolation interpolation">join</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string-interpolation interpolation">chosen_name</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token string-interpolation string" style="color:rgb(195, 232, 141)">"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        ask_choose_again</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">else</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token keyword" style="font-style:italic">print</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"\nProgram Ended.\nList of names is now empty."</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        sys</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">exit</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token number" style="color:rgb(247, 140, 108)">0</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><br></span></code></pre></div></div>
<p>That's it! We now have an offline random name picker that runs in our terminal. It's also great to use when you're concerned with data privacy for your names. The best thing is we can also use this program even if our list are not names like a list of truth or dare questions.</p>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>project source code</div><div class="admonitionContent_BuS1"><p>Grab the source code by heading over to the project's repository <a href="https://github.com/joiellantero/name-roulette" target="_blank" rel="noopener noreferrer" class="">here</a>.</p></div></div>]]></content:encoded>
            <category>Python</category>
            <category>Tutorial</category>
        </item>
        <item>
            <title><![CDATA[GitHub: How to Create a README with Statistics for your Profile]]></title>
            <link>https://sudojoie.com/github-how-to-create-a-readme-with-statistics-for-your-profile</link>
            <guid>https://sudojoie.com/github-how-to-create-a-readme-with-statistics-for-your-profile</guid>
            <pubDate>Wed, 17 Mar 2021 00:00:00 GMT</pubDate>
            <description><![CDATA[Easy-to-follow instructions on spicing-up your GitHub profile.]]></description>
            <content:encoded><![CDATA[<p>In late 2020, GitHub released a new feature which allows users to create a README file for their profiles. This file is quite useful especially in marketing yourself. You can put an introduction about yourself, your work, skills, experiences, and more. Some people also put their GitHub statistics, which I will show you how to do in this article.</p>
<p>The statistics that will be shown will be an overview of your GitHub account. It shall display information such as total stars, forks, repository views, languages you used, and more.</p>
<div><img src="https://sudojoie.com/assets/images/sc_1-3cf2fe128da637502528aa2fbfcea829.png" alt="sample-readme"><p>A sample README.md for a GitHub user’s profile</p></div>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="creating-your-github-profiles-readmemd">Creating your GitHub Profile’s README.md<a href="https://sudojoie.com/github-how-to-create-a-readme-with-statistics-for-your-profile#creating-your-github-profiles-readmemd" class="hash-link" aria-label="Direct link to Creating your GitHub Profile’s README.md" title="Direct link to Creating your GitHub Profile’s README.md" translate="no">​</a></h2>
<ol>
<li class="">
<p>Go to this <a href="https://github.com/new" target="_blank" rel="noopener noreferrer" class="">link</a> to create a new GitHub repository.</p>
</li>
<li class="">
<p>Use your username as the name of this repository like what I did in the image below.</p>
<div><img src="https://sudojoie.com/assets/images/sc_2-e6bcd1b95eec41dced3d86013311e87b.png" alt="new-repository"><p>Create a new respository.</p></div>
<p>Take note that GitHub is warning me because I have already created my own repository for the README file. In your case, there should be a green checkmark in the right side of the text box.</p>
</li>
<li class="">
<p>Initialize your new repository with a README file.</p>
<div><img src="https://sudojoie.com/assets/images/sc_3-3cc4e49ddfed628626c301ef8743cae3.png" alt="add-readme"><p>Check the "Add a README file" option.</p></div>
</li>
<li class="">
<p>GitHub auto-generates the content of this README into something similar shown below.</p>
<div class="language-markdown codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-markdown codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token title important punctuation" style="color:rgb(199, 146, 234)">###</span><span class="token title important"> Hi there 👋</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">&lt;!--</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">**joiellantero/joiellantero** is a ✨ _special_ ✨ repository because its `README.md` (this file) appears on your GitHub profile.</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">Here are some ideas to get you started:</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">- 🔭 I’m currently working on ...</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">- 🌱 I’m currently learning ...</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">- 👯 I’m looking to collaborate on ...</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">- 🤔 I’m looking for help with ...</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">- 💬 Ask me about ...</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">- 📫 How to reach me: ...</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">- 😄 Pronouns: ...</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">- ⚡ Fun fact: ...</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">--&gt;</span><br></span></code></pre></div></div>
<p>If you’re not familiar with markdown, here are some resources for you to check out:</p>
<ul>
<li class=""><a href="https://www.markdownguide.org/getting-started/" target="_blank" rel="noopener noreferrer" class="">What is Markdown?</a></li>
<li class=""><a href="https://www.markdownguide.org/basic-syntax" target="_blank" rel="noopener noreferrer" class="">Markdown Basic Syntax</a></li>
</ul>
</li>
<li class="">
<p>Edit this to your liking, and don’t forget to commit (and push if you’re not using GitHub’s web interface) your changes!</p>
</li>
</ol>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="generating-your-own-statistics">Generating your own statistics<a href="https://sudojoie.com/github-how-to-create-a-readme-with-statistics-for-your-profile#generating-your-own-statistics" class="hash-link" aria-label="Direct link to Generating your own statistics" title="Direct link to Generating your own statistics" translate="no">​</a></h2>
<ol>
<li class="">
<p>Visit this <a href="https://github.com/joiellantero/github-stats" target="_blank" rel="noopener noreferrer" class="">link</a> and follow the installation instructions written on README.md.</p>
</li>
<li class="">
<p>After the workflow is done, go to the “generated” folder. You will see two files like the ones below.</p>
<div><img src="https://sudojoie.com/assets/images/sc_4-712896c5d30a9b89b15c76e7dabfb158.png" alt="generated-folder"><figcaption>Go to the "generated" folder</figcaption></div>
</li>
<li class="">
<p>Click on them and copy the URL leading to the image. Remember not to use “raw”. This is because we want the link to the image and not the SVG code itself.</p>
<div><img src="https://sudojoie.com/assets/images/sc_5-23f356c3e4a4abb9b23c981049510fde.png" alt="languages.svg"><figcaption>Copy URL of the languages.svg</figcaption></div>
</li>
<li class="">
<p>Go to the repository you created earlier and open up the README.md file as we will now display the SVGs using the link that you copied.</p>
<div class="language-markdown codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-markdown codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">![](</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token tag" style="color:rgb(255, 85, 114)">the</span><span class="token tag" style="color:rgb(255, 85, 114)"> </span><span class="token tag attr-name" style="color:rgb(255, 203, 107)">link</span><span class="token tag" style="color:rgb(255, 85, 114)"> </span><span class="token tag attr-name" style="color:rgb(255, 203, 107)">you</span><span class="token tag" style="color:rgb(255, 85, 114)"> </span><span class="token tag attr-name" style="color:rgb(255, 203, 107)">copied</span><span class="token tag" style="color:rgb(255, 85, 114)"> </span><span class="token tag attr-name" style="color:rgb(255, 203, 107)">for</span><span class="token tag" style="color:rgb(255, 85, 114)"> </span><span class="token tag attr-name" style="color:rgb(255, 203, 107)">overview.svg</span><span class="token tag" style="color:rgb(255, 85, 114)"> </span><span class="token tag attr-name" style="color:rgb(255, 203, 107)">here</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token plain">)</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">![](</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token tag" style="color:rgb(255, 85, 114)">the</span><span class="token tag" style="color:rgb(255, 85, 114)"> </span><span class="token tag attr-name" style="color:rgb(255, 203, 107)">link</span><span class="token tag" style="color:rgb(255, 85, 114)"> </span><span class="token tag attr-name" style="color:rgb(255, 203, 107)">you</span><span class="token tag" style="color:rgb(255, 85, 114)"> </span><span class="token tag attr-name" style="color:rgb(255, 203, 107)">copied</span><span class="token tag" style="color:rgb(255, 85, 114)"> </span><span class="token tag attr-name" style="color:rgb(255, 203, 107)">for</span><span class="token tag" style="color:rgb(255, 85, 114)"> </span><span class="token tag attr-name" style="color:rgb(255, 203, 107)">languages.svg</span><span class="token tag" style="color:rgb(255, 85, 114)"> </span><span class="token tag attr-name" style="color:rgb(255, 203, 107)">here</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token plain">)</span><br></span></code></pre></div></div>
<p>In my case, it would look something like this:</p>
<div class="language-markdown codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-markdown codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">![](https://github.com/joiellantero/github-stats/blob/master/generated/overview.svg)</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">![](https://github.com/joiellantero/github-stats/blob/master/generated/languages.svg)</span><br></span></code></pre></div></div>
</li>
<li class="">
<p>Commit (and push if you’re not using GitHub’s web interface) your changes and checkout your new GitHub profile!</p>
</li>
<li class="">
<p>Share this with others if you liked this tutorial.</p>
</li>
</ol>]]></content:encoded>
            <category>GitHub</category>
            <category>Tutorial</category>
        </item>
    </channel>
</rss>