<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Eddie Gulay</title>
    <description>The latest articles on Forem by Eddie Gulay (@eddiegulay).</description>
    <link>https://forem.com/eddiegulay</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1162732%2Fa728d062-8f1d-4b0f-a055-2672e229f637.png</url>
      <title>Forem: Eddie Gulay</title>
      <link>https://forem.com/eddiegulay</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/eddiegulay"/>
    <language>en</language>
    <item>
      <title>Under-presentation of Swahili in AI tasks</title>
      <dc:creator>Eddie Gulay</dc:creator>
      <pubDate>Sat, 10 Jan 2026 19:32:14 +0000</pubDate>
      <link>https://forem.com/eddiegulay/underpresentation-of-swahili-in-ai-tasks-4d44</link>
      <guid>https://forem.com/eddiegulay/underpresentation-of-swahili-in-ai-tasks-4d44</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;the cover image is also underpresented!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Swahili is significantly underrepresented in AI research and applications, especially compared to languages like English, Mandarin, Spanish, or even French. A few key points highlight this gap:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Data Scarcity&lt;/strong&gt;: Large-scale datasets in Swahili are limited. Most NLP models rely on massive text corpora to learn patterns, but Swahili content online is comparatively small, fragmented, or noisy.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Limited Pretrained Models&lt;/strong&gt;: While there are some multilingual models like mBERT or XLM-R, they underperform on Swahili because the language is a small fraction of their training data. Truly high-performing, Swahili-specific models are rare.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Low Research Focus&lt;/strong&gt;: Academic and industry research in NLP and speech processing often overlooks Swahili. Few papers focus on tasks like sentiment analysis, machine translation, or speech recognition for Swahili.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Speech and Multimodal Gaps&lt;/strong&gt;: Swahili speech datasets, handwritten text, and multimodal datasets (images with Swahili captions, videos, etc.) are almost non-existent. This makes building voice assistants, OCR, or image captioning models in Swahili extremely challenging.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Impact on Applications&lt;/strong&gt;: This underrepresentation affects practical AI applications—chatbots, translation services, digital assistants, and educational tools often fail to work well for Swahili speakers.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Aand.. Here's a detailed table of AI and ML tasks where Swahili is underrepresented, organized by category. I’ve included the &lt;strong&gt;task&lt;/strong&gt;, &lt;strong&gt;current state for Swahili&lt;/strong&gt;, and &lt;strong&gt;potential impact if addressed&lt;/strong&gt;. This should give a clear sense of both gaps and opportunities.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Category&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;AI Task&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Current State for Swahili&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Potential Impact if Developed&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Natural Language Processing (NLP)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Language Modeling&lt;/td&gt;
&lt;td&gt;Few large-scale Swahili corpora; multilingual models underperform&lt;/td&gt;
&lt;td&gt;Better text generation, predictive typing, writing aids&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Text Classification&lt;/td&gt;
&lt;td&gt;Very limited labeled datasets for topics, sentiment, or spam detection&lt;/td&gt;
&lt;td&gt;Improved moderation, content filtering, sentiment analysis&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Sentiment Analysis&lt;/td&gt;
&lt;td&gt;Almost no high-quality annotated datasets&lt;/td&gt;
&lt;td&gt;Social media monitoring, brand analysis, public opinion insights&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Named Entity Recognition (NER)&lt;/td&gt;
&lt;td&gt;Few datasets; existing NER models often fail on Swahili text&lt;/td&gt;
&lt;td&gt;Improved information extraction for news, legal, and healthcare texts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Part-of-Speech Tagging&lt;/td&gt;
&lt;td&gt;Sparse corpora; rules-based systems dominate&lt;/td&gt;
&lt;td&gt;Better grammar analysis, parsing, and downstream NLP tasks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Machine Translation&lt;/td&gt;
&lt;td&gt;Limited parallel corpora; Google Translate quality varies&lt;/td&gt;
&lt;td&gt;Accurate translation for education, business, and government documents&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Summarization&lt;/td&gt;
&lt;td&gt;Almost nonexistent datasets or pretrained models&lt;/td&gt;
&lt;td&gt;Automated content summarization for news, legal, and academic texts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Question Answering&lt;/td&gt;
&lt;td&gt;Very few datasets; models trained on English fail on Swahili&lt;/td&gt;
&lt;td&gt;AI assistants, educational tools, customer support systems&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Semantic Search / Retrieval&lt;/td&gt;
&lt;td&gt;Limited indexing and embeddings in Swahili&lt;/td&gt;
&lt;td&gt;Efficient document retrieval, knowledge bases, and search engines&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Speech &amp;amp; Audio&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Automatic Speech Recognition (ASR)&lt;/td&gt;
&lt;td&gt;Few large-scale Swahili audio datasets&lt;/td&gt;
&lt;td&gt;Voice assistants, dictation tools, transcription services&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Text-to-Speech (TTS)&lt;/td&gt;
&lt;td&gt;Limited high-quality Swahili voice models&lt;/td&gt;
&lt;td&gt;Assistive tech, IVR systems, audiobooks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Speech Translation&lt;/td&gt;
&lt;td&gt;Almost nonexistent&lt;/td&gt;
&lt;td&gt;Real-time communication across languages&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Speaker Diarization&lt;/td&gt;
&lt;td&gt;Rare for Swahili&lt;/td&gt;
&lt;td&gt;Meeting transcription, call center analysis&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Multimodal AI&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Image Captioning&lt;/td&gt;
&lt;td&gt;No significant Swahili-labeled image datasets&lt;/td&gt;
&lt;td&gt;Accessibility tools, educational resources, social media tagging&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;OCR (Optical Character Recognition)&lt;/td&gt;
&lt;td&gt;Some work on printed Swahili; handwritten datasets very rare&lt;/td&gt;
&lt;td&gt;Digitalizing documents, preserving literature and historical texts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Video Understanding&lt;/td&gt;
&lt;td&gt;No datasets with Swahili captions or narration&lt;/td&gt;
&lt;td&gt;Subtitling, content indexing, AI tutors&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Dialog &amp;amp; Conversational AI&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Chatbots&lt;/td&gt;
&lt;td&gt;Very few Swahili-trained models&lt;/td&gt;
&lt;td&gt;Customer support, education, e-government services&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Dialogue Summarization&lt;/td&gt;
&lt;td&gt;Almost no datasets&lt;/td&gt;
&lt;td&gt;Meeting notes, conversational analytics&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Intent Recognition&lt;/td&gt;
&lt;td&gt;Few datasets&lt;/td&gt;
&lt;td&gt;Better automation for local businesses&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Recommendation Systems&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Content Recommendation&lt;/td&gt;
&lt;td&gt;Sparse data, especially for Swahili media&lt;/td&gt;
&lt;td&gt;Localized content discovery (books, music, news)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Information Extraction&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Knowledge Graph Construction&lt;/td&gt;
&lt;td&gt;Rare Swahili corpora for entity linking&lt;/td&gt;
&lt;td&gt;Structured knowledge bases for research, government, and business&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Education &amp;amp; Literacy AI&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Reading Assistance&lt;/td&gt;
&lt;td&gt;Limited AI tutors or literacy tools&lt;/td&gt;
&lt;td&gt;Supporting Swahili literacy, personalized education&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Language Learning Tools&lt;/td&gt;
&lt;td&gt;Very few AI apps teaching Swahili&lt;/td&gt;
&lt;td&gt;Global Swahili learning adoption&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Healthcare AI&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Clinical Text Mining&lt;/td&gt;
&lt;td&gt;Almost nonexistent Swahili medical datasets&lt;/td&gt;
&lt;td&gt;Medical record processing, health insights&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Speech-based Diagnostics&lt;/td&gt;
&lt;td&gt;No datasets&lt;/td&gt;
&lt;td&gt;Remote healthcare, voice-based symptom screening&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Finance &amp;amp; Business&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Sentiment/Trend Analysis in Swahili&lt;/td&gt;
&lt;td&gt;Minimal coverage&lt;/td&gt;
&lt;td&gt;Market intelligence, consumer behavior analytics&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Automated Form Processing&lt;/td&gt;
&lt;td&gt;Limited NLP for Swahili documents&lt;/td&gt;
&lt;td&gt;Banking, insurance, government services&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Legal &amp;amp; Governance&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Legal Document Analysis&lt;/td&gt;
&lt;td&gt;Rare datasets&lt;/td&gt;
&lt;td&gt;Contract review, policy extraction, case law research&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Automated Compliance Checks&lt;/td&gt;
&lt;td&gt;Very limited AI tools&lt;/td&gt;
&lt;td&gt;Regulatory monitoring, e-government services&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Social Media &amp;amp; Content Moderation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Hate Speech / Misinformation Detection&lt;/td&gt;
&lt;td&gt;Almost no labeled datasets&lt;/td&gt;
&lt;td&gt;Safer online communities, responsible platform governance&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Social Analytics&lt;/td&gt;
&lt;td&gt;Sparse tools&lt;/td&gt;
&lt;td&gt;Monitoring trends, public opinion, emergency response&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cultural &amp;amp; Historical Preservation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Digitization of Literature&lt;/td&gt;
&lt;td&gt;Limited Swahili text corpora&lt;/td&gt;
&lt;td&gt;Preserving oral history, books, and cultural materials&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Oral History Transcription&lt;/td&gt;
&lt;td&gt;Very few annotated datasets&lt;/td&gt;
&lt;td&gt;Archiving traditional storytelling and interviews&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This table already highlights &lt;strong&gt;40+ tasks&lt;/strong&gt; where Swahili is significantly underrepresented. Most of these gaps are not due to technical impossibility—they’re primarily &lt;strong&gt;data scarcity and research neglect&lt;/strong&gt;. Addressing them would have &lt;strong&gt;high societal, educational, and economic impact&lt;/strong&gt;, especially in East Africa where Swahili is widely spoken.&lt;/p&gt;

&lt;p&gt;So i am going to leave these here until i get implementations of them. &lt;/p&gt;

</description>
      <category>swahili</category>
      <category>language</category>
      <category>nlp</category>
      <category>eastafrica</category>
    </item>
    <item>
      <title>PostgreSQL Backup the quick Way</title>
      <dc:creator>Eddie Gulay</dc:creator>
      <pubDate>Sat, 04 Oct 2025 19:18:54 +0000</pubDate>
      <link>https://forem.com/eddiegulay/postgresql-backup-the-quick-way-aii</link>
      <guid>https://forem.com/eddiegulay/postgresql-backup-the-quick-way-aii</guid>
      <description>&lt;p&gt;PostgreSQL is one of the most reliable open-source databases, but backups are often handled in overly complex ways — involving filesystem snapshots, replication configurations, or manual tar archives.&lt;br&gt;
If you just need a &lt;strong&gt;clean, portable, and consistent backup of all your databases&lt;/strong&gt;, PostgreSQL already includes a simple tool for that: &lt;code&gt;pg_dumpall&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This post shows how to create a full backup of your PostgreSQL server in one line — and how to move it safely to your local machine.&lt;/p&gt;


&lt;h3&gt;
  
  
  &lt;strong&gt;Why “Logical” Backups Are Enough&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;There are two kinds of PostgreSQL backups:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Physical backups&lt;/strong&gt; — copy all data files on disk; good for point-in-time recovery but heavy and less portable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Logical backups&lt;/strong&gt; — dump all SQL definitions and data; lighter, portable, and perfect for everyday snapshots or migrations.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If your goal is to have a restorable &lt;code&gt;.sql&lt;/code&gt; file containing every database, user, and permission, a &lt;strong&gt;logical backup&lt;/strong&gt; is the right choice.&lt;/p&gt;


&lt;h3&gt;
  
  
  &lt;strong&gt;Step 1 — Create the Backup&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Run this command directly on your server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo&lt;/span&gt; &lt;span class="nt"&gt;-u&lt;/span&gt; postgres pg_dumpall &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /tmp/october_4_2025_backup.sql
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Connects as the &lt;code&gt;postgres&lt;/code&gt; superuser&lt;/li&gt;
&lt;li&gt;Dumps &lt;strong&gt;all databases&lt;/strong&gt;, &lt;strong&gt;roles&lt;/strong&gt;, and &lt;strong&gt;grants&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Produces one plain-text SQL file ready for restoration&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can name the file however you prefer — for example, include the date:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/tmp/october_4_2025_backup.sql
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  &lt;strong&gt;Step 2 — Verify the Backup&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Check that the backup file exists and has a reasonable size:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-lh&lt;/span&gt; /tmp/october_4_2025_backup.sql
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Optional: look at the first few lines:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;head&lt;/span&gt; /tmp/october_4_2025_backup.sql
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  &lt;strong&gt;Step 3 — Copy the Backup to Your Local Machine&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Use &lt;code&gt;scp&lt;/code&gt; (secure copy) to transfer the backup:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;scp user@your_server_ip:/tmp/october_4_2025_backup.sql ~/Downloads/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replace:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;user&lt;/code&gt; → your SSH username&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;your_server_ip&lt;/code&gt; → your server’s IP address&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now your backup is safely stored on your local machine.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Optional — Compress the Backup&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;If the database is large:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;gzip&lt;/span&gt; /tmp/october_4_2025_backup.sql
scp user@your_server_ip:/tmp/october_4_2025_backup.sql.gz ~/Downloads/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This typically reduces file size by 70–90%.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Step 4 — Restore the Backup (When Needed)&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;To restore everything to a new PostgreSQL instance:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;psql &lt;span class="nt"&gt;-U&lt;/span&gt; postgres &lt;span class="nt"&gt;-f&lt;/span&gt; october_4_2025_backup.sql
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If compressed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;gunzip&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; october_4_2025_backup.sql.gz | psql &lt;span class="nt"&gt;-U&lt;/span&gt; postgres
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This recreates all databases, roles, and data as they were during the backup.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Automation Tip&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;To schedule a daily or weekly backup automatically, create a cron job:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;crontab &lt;span class="nt"&gt;-u&lt;/span&gt; postgres &lt;span class="nt"&gt;-e&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add this line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0 2 * * * /usr/bin/pg_dumpall &amp;gt; /var/backups/pg_backup_$(date +\%F).sql
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That takes a nightly snapshot at 2 a.m. — hands-free.&lt;/p&gt;

</description>
      <category>postgres</category>
      <category>database</category>
      <category>tutorial</category>
      <category>devops</category>
    </item>
    <item>
      <title>Setting up SSH for GitHub on Linux Mint</title>
      <dc:creator>Eddie Gulay</dc:creator>
      <pubDate>Sun, 28 Sep 2025 21:17:54 +0000</pubDate>
      <link>https://forem.com/eddiegulay/setting-up-ssh-for-github-on-linux-mint-1n02</link>
      <guid>https://forem.com/eddiegulay/setting-up-ssh-for-github-on-linux-mint-1n02</guid>
      <description>&lt;p&gt;When working with GitHub, cloning repositories over SSH is faster and more secure than using HTTPS. If you’re setting it up for the first time, it can feel like a maze of commands and errors. This guide walks you through generating an SSH key, adding it to GitHub, and configuring your machine to authenticate seamlessly.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Check for Existing SSH Keys
&lt;/h2&gt;

&lt;p&gt;First, check if you already have SSH keys on your system:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-al&lt;/span&gt; ~/.ssh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you see files like &lt;code&gt;id_ed25519.pub&lt;/code&gt; or &lt;code&gt;id_rsa.pub&lt;/code&gt;, you already have keys. Otherwise, continue to the next step.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Generate a New SSH Key
&lt;/h2&gt;

&lt;p&gt;Generate a new Ed25519 key pair (recommended):&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Replace &lt;code&gt;your_email@example.com&lt;/code&gt; with the email tied to your GitHub account.&lt;/li&gt;
&lt;li&gt;When prompted for a file name, press &lt;strong&gt;Enter&lt;/strong&gt; to use the default (&lt;code&gt;~/.ssh/id_ed25519&lt;/code&gt;), or specify your own (e.g., &lt;code&gt;mygithubkey&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you chose a custom name, move the files into &lt;code&gt;~/.ssh&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mv&lt;/span&gt; ~/path/to/mygithubkey ~/.ssh/
&lt;span class="nb"&gt;mv&lt;/span&gt; ~/path/to/mygithubkey.pub ~/.ssh/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Set the correct permissions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;chmod &lt;/span&gt;600 ~/.ssh/mygithubkey
&lt;span class="nb"&gt;chmod &lt;/span&gt;644 ~/.ssh/mygithubkey.pub
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  3. Start the SSH Agent and Add the Key
&lt;/h2&gt;

&lt;p&gt;Start the SSH agent:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;eval&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;ssh-agent &lt;span class="nt"&gt;-s&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add your private key:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh-add ~/.ssh/mygithubkey
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Verify it was added:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh-add &lt;span class="nt"&gt;-l&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  4. Add the Public Key to GitHub
&lt;/h2&gt;

&lt;p&gt;Display your public key:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; ~/.ssh/mygithubkey.pub
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It will look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAEXAMPLEKEYSTRING user@example.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Copy the entire line, then go to:&lt;br&gt;
&lt;strong&gt;GitHub → Settings → SSH and GPG keys → New SSH key&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Give it a title (e.g., &lt;em&gt;Linux Mint Laptop&lt;/em&gt;).&lt;/li&gt;
&lt;li&gt;Paste the key.&lt;/li&gt;
&lt;li&gt;Save.&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  5. Test the Connection
&lt;/h2&gt;

&lt;p&gt;Run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh &lt;span class="nt"&gt;-T&lt;/span&gt; git@github.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If everything is set up correctly, you’ll see:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Hi username! You've successfully authenticated, but GitHub does not provide shell access.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  6. Clone Repositories with SSH
&lt;/h2&gt;

&lt;p&gt;Now you can clone repositories using the SSH URL:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone git@github.com:your-username/your-repo.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  7. Optional: Configure SSH for Multiple Keys
&lt;/h2&gt;

&lt;p&gt;If you use multiple keys, configure SSH to always use the right one for GitHub. Edit your config:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nano ~/.ssh/config
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Host github.com
  HostName github.com
  User git
  IdentityFile ~/.ssh/mygithubkey
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save and exit. Now GitHub will always use that key automatically.&lt;/p&gt;

</description>
      <category>github</category>
      <category>tutorial</category>
      <category>security</category>
      <category>linux</category>
    </item>
    <item>
      <title>How to Transform Jupyter Notebook into a Maintainable AI Project</title>
      <dc:creator>Eddie Gulay</dc:creator>
      <pubDate>Fri, 16 May 2025 20:09:51 +0000</pubDate>
      <link>https://forem.com/eddiegulay/how-to-transform-jupyter-notebook-into-a-maintainable-ai-project-3cjl</link>
      <guid>https://forem.com/eddiegulay/how-to-transform-jupyter-notebook-into-a-maintainable-ai-project-3cjl</guid>
      <description>&lt;p&gt;A Python package named &lt;a href="https://github.com/eddiegulay/modinit" rel="noopener noreferrer"&gt;modinit&lt;/a&gt; that facilitates the rapid scaffolding of AI model training repositories with a standardized, best-practice structure. This tool is designed to save time and ensure consistency across machine learning projects.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foccepcwszvfgyim7habl.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foccepcwszvfgyim7habl.gif" alt="modinitdemo" width="720" height="234"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Problem, Transitioning from Notebooks to Production Ready Code
&lt;/h3&gt;

&lt;p&gt;In machine learning and AI development, it's common to begin with Jupyter notebooks for experimentation and prototyping. However, as projects mature, there's a need to transition this code into a more structured, maintainable, and deployable format. This transition poses several &lt;/p&gt;

&lt;p&gt;challenges:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Code Organization&lt;/strong&gt;: Notebooks often contain a mix of data processing, model definition, training loops, and evaluation code, making it hard to modularize and reuse components.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Version Control&lt;/strong&gt;: Tracking changes in notebooks is less straightforward compared to plain &lt;code&gt;.py&lt;/code&gt; files, complicating collaboration and versioning.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Reusability and Testing&lt;/strong&gt;: Functions and classes defined in notebooks are not easily reusable across different projects or testable in isolation.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Deployment&lt;/strong&gt;: Deploying models trained in notebooks to production environments requires refactoring code into scripts or packages, which can be time-consuming and error-prone.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Solution, Structured Project Template
&lt;/h3&gt;

&lt;p&gt;To address these challenges, adopting a standardized project structure is essential. Such a structure separates concerns, promotes code reusability, and aligns with best practices in software development. Here's a suggested layout:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;your_project/
│
├── notebooks/            # Jupyter notebooks for experimentation
│   └── prototype.ipynb
│
├── src/                  # Core Python package
│   ├── __init__.py
│   ├── data.py           # Data processing functions
│   ├── model.py          # Model architecture definitions
│   ├── train.py          # Training routines
│   ├── evaluate.py       # Evaluation metrics and logic
│   └── utils.py          # Utility functions (e.g., decoding, accuracy calculations)
│
├── main.py               # Entry point for training/testing/inference
├── config.yaml           # Configuration file for hyperparameters and settings
├── requirements.txt      # List of dependencies
└── README.md             # Project overview and instructions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This structure offers several benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Modularity&lt;/strong&gt;: Each component of the project (data processing, model definition, training, evaluation) is encapsulated in its own module, enhancing readability and maintainability.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Scalability&lt;/strong&gt;: As the project grows, this structure accommodates the addition of new features, models, or datasets without significant reorganization.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Collaboration&lt;/strong&gt;: Clear separation of concerns allows team members to work on different parts of the project simultaneously with minimal conflicts.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Deployment&lt;/strong&gt;: Having a &lt;code&gt;main.py&lt;/code&gt; as the entry point simplifies the process of deploying the model for inference or integrating it into larger systems.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Introducing &lt;code&gt;modinit&lt;/code&gt;: Automating the Setup
&lt;/h3&gt;

&lt;p&gt;To streamline the creation of such a structured project, your &lt;code&gt;modinit&lt;/code&gt; package automates the scaffolding process. By running a simple command, developers can generate a project with the aforementioned layout, complete with template files and docstrings. This automation reduces setup time and ensures adherence to best practices from the outset.&lt;/p&gt;




&lt;h3&gt;
  
  
  Next Steps
&lt;/h3&gt;

&lt;p&gt;To get started with &lt;code&gt;modinit&lt;/code&gt;, you can install it via pip:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;modinit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, initialize a new project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;modinit create my_new_project
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command will generate a new directory &lt;code&gt;my_new_project&lt;/code&gt; with the standardized structure, allowing you to focus on developing your AI models without worrying about project organization.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>initialization</category>
      <category>template</category>
      <category>research</category>
    </item>
    <item>
      <title>Fed Up with Docker? Here, Uninstall It Completely (No Coming Back!)</title>
      <dc:creator>Eddie Gulay</dc:creator>
      <pubDate>Wed, 26 Feb 2025 12:01:44 +0000</pubDate>
      <link>https://forem.com/eddiegulay/fed-up-with-docker-heres-how-to-uninstall-it-completely-no-coming-back-4mnb</link>
      <guid>https://forem.com/eddiegulay/fed-up-with-docker-heres-how-to-uninstall-it-completely-no-coming-back-4mnb</guid>
      <description>&lt;p&gt;Docker is a fantastic tool... until it isn’t. Maybe you're tired of mysterious container issues, endless rebuilds, or "it works on my machine" nightmares. Whatever the reason, you’ve reached the breaking point and decided to part ways with Docker. You don’t just want it gone — you want it obliterated from your system with no trace left behind.&lt;/p&gt;

&lt;p&gt;If that sounds like you, this guide is your salvation. We’re not going to sugarcoat it. This post is about &lt;strong&gt;getting rid of Docker once and for all&lt;/strong&gt;. Let’s dive in.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Why Uninstall Docker?&lt;/strong&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Bloated disk usage from dangling images and unused volumes.&lt;/li&gt;
&lt;li&gt;Frequent conflicts and compatibility issues.&lt;/li&gt;
&lt;li&gt;Frustration with complex configurations.&lt;/li&gt;
&lt;li&gt;Seeking alternatives that better fit your workflow.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1o7c9qfyeurxs5m9n4ll.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1o7c9qfyeurxs5m9n4ll.png" alt="Image description" width="750" height="422"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Whatever the reason, you're here to uninstall Docker, so let's not waste time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Stop and Remove Running Containers
&lt;/h2&gt;

&lt;p&gt;Before you rip Docker out, you need to stop any running containers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker ps &lt;span class="nt"&gt;-q&lt;/span&gt; | xargs &lt;span class="nt"&gt;-r&lt;/span&gt; docker stop
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Want to nuke all containers, images, and volumes?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker system prune &lt;span class="nt"&gt;-a&lt;/span&gt; &lt;span class="nt"&gt;--volumes&lt;/span&gt; &lt;span class="nt"&gt;--force&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Warning:&lt;/strong&gt; This wipes out all your Docker data. If you're sure you never want to see it again, go for it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Uninstall Docker (Ubuntu/Linux)
&lt;/h2&gt;

&lt;p&gt;Docker doesn’t just live in one place. It scatters components all over your system. Here’s how to find them all and remove them.&lt;/p&gt;

&lt;h4&gt;
  
  
  Purge Docker Packages
&lt;/h4&gt;

&lt;p&gt;Remove Docker and its related components:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get purge &lt;span class="nt"&gt;-y&lt;/span&gt; docker-engine docker docker.io docker-ce docker-ce-cli containerd runc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 3: Clean Up Residual Files
&lt;/h2&gt;

&lt;p&gt;Docker leaves behind configuration files and volumes. Nuke them with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; /var/lib/docker
&lt;span class="nb"&gt;sudo rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; /var/lib/containerd
&lt;span class="nb"&gt;sudo rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; /etc/docker
&lt;span class="nb"&gt;sudo rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; ~/.docker
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This ensures no leftover Docker data is hiding in your system.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Remove Docker Repositories and Keys
&lt;/h2&gt;

&lt;p&gt;Get rid of Docker’s repository entries and GPG keys:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo rm&lt;/span&gt; /etc/apt/sources.list.d/docker.list
&lt;span class="nb"&gt;sudo rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; /etc/apt/keyrings/docker.gpg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Remove the keyrings directory if it was created just for Docker:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; /etc/apt/keyrings/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 5: Autoremove and Clean Packages
&lt;/h2&gt;

&lt;p&gt;Run these commands to clean any orphaned packages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get autoremove &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="nt"&gt;--purge&lt;/span&gt; docker docker-ce docker-ce-cli
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get clean
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 6: Verify Docker is Gone
&lt;/h2&gt;

&lt;p&gt;Let’s make sure Docker is truly out of your life:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nt"&gt;--version&lt;/span&gt;  &lt;span class="c"&gt;# Should return 'command not found'&lt;/span&gt;
docker-compose &lt;span class="nt"&gt;--version&lt;/span&gt;  &lt;span class="c"&gt;# Should also return 'command not found'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;If both commands fail, congratulations!&lt;/strong&gt; Docker is history.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bonus: Remove Docker Groups and Users (Optional)
&lt;/h2&gt;

&lt;p&gt;To remove the Docker group:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;If you had a dedicated Docker user (rare case), you can delete it:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 7: Reboot (Optional but Recommended)
&lt;/h2&gt;

&lt;p&gt;Sometimes services linger in memory. Reboot to make sure everything is cleared:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  While sipping monster energy ...
&lt;/h2&gt;

&lt;p&gt;Docker had its moment, but you’re done. With the steps above, you’ve not only uninstalled Docker — you’ve wiped every trace of it from your machine. No coming back. No lingering configs. No haunted volumes.&lt;/p&gt;

&lt;p&gt;Thinking of alternatives? Check out tools like &lt;strong&gt;Podman&lt;/strong&gt;, &lt;strong&gt;Minikube&lt;/strong&gt;, or &lt;strong&gt;Vagrant&lt;/strong&gt; for container-free virtualization. Or maybe take a break from containerization altogether. You’ve earned it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Goodbye, Docker. It was... something.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;TL;DR:&lt;/strong&gt;
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Stop and remove containers: &lt;code&gt;docker system prune -a --volumes --force&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Purge Docker: &lt;code&gt;sudo apt-get purge -y docker*&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Remove Docker files: &lt;code&gt;sudo rm -rf /var/lib/docker /etc/docker ~/.docker&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Clean up packages: &lt;code&gt;sudo apt-get autoremove -y --purge docker*&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Verify: &lt;code&gt;docker --version&lt;/code&gt; (should fail)&lt;/li&gt;
&lt;li&gt;Reboot: &lt;code&gt;sudo reboot&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;That’s it. Docker is out. No regrets.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>docker</category>
      <category>fedup</category>
      <category>vibecoding</category>
    </item>
    <item>
      <title>Writing clear, concise, and meaningful commit messages is key to maintaining a well-documented Git history. Here’s a practical guide to writing great Git commit messages.</title>
      <dc:creator>Eddie Gulay</dc:creator>
      <pubDate>Wed, 29 Jan 2025 22:31:52 +0000</pubDate>
      <link>https://forem.com/eddiegulay/writing-clear-concise-and-meaningful-commit-messages-is-key-to-maintaining-a-well-documented-git-1gp6</link>
      <guid>https://forem.com/eddiegulay/writing-clear-concise-and-meaningful-commit-messages-is-key-to-maintaining-a-well-documented-git-1gp6</guid>
      <description>&lt;div class="ltag__link"&gt;
  &lt;a href="/eddiegulay" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1162732%2Fa728d062-8f1d-4b0f-a055-2672e229f637.png" alt="eddiegulay"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://dev.to/eddiegulay/writing-clear-concise-and-meaningful-commit-messages-for-a-well-documented-git-history-kkc" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Writing clear, concise, and meaningful commit messages for a well-documented Git history&lt;/h2&gt;
      &lt;h3&gt;Eddie Gulay ・ Jan 29&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#github&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#commitmessage&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#git&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


</description>
      <category>github</category>
      <category>commitmessage</category>
      <category>git</category>
    </item>
    <item>
      <title>Writing clear, concise, and meaningful commit messages for a well-documented Git history</title>
      <dc:creator>Eddie Gulay</dc:creator>
      <pubDate>Wed, 29 Jan 2025 22:28:40 +0000</pubDate>
      <link>https://forem.com/eddiegulay/writing-clear-concise-and-meaningful-commit-messages-for-a-well-documented-git-history-kkc</link>
      <guid>https://forem.com/eddiegulay/writing-clear-concise-and-meaningful-commit-messages-for-a-well-documented-git-history-kkc</guid>
      <description>&lt;h3&gt;
  
  
  Let’s Talk About Writing Commit Messages That Actually Make Sense
&lt;/h3&gt;

&lt;p&gt;Commit messages might seem like a small thing when you’re knee-deep in code, but they’re like little breadcrumbs you leave for yourself and your team. A good one can save you from scratching your head weeks later, wondering what on earth you were doing. So, how do you write one that’s clear and helpful without feeling like a chore? It’s simpler than you might think.&lt;/p&gt;

&lt;p&gt;Start with a &lt;strong&gt;type&lt;/strong&gt;—a quick label that says what kind of change you’re making. Then add a short summary, and if it’s a bigger change, toss in a few extra details. That’s it! Let’s break it down a bit.&lt;/p&gt;




&lt;h4&gt;
  
  
  Kick Things Off with a Commit Type
&lt;/h4&gt;

&lt;p&gt;Think of the commit type as a way to sort your changes into buckets. Here’s a quick rundown of the common ones:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;What It Means&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;feat&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Adding something new&lt;/td&gt;
&lt;td&gt;&lt;code&gt;feat: add date filtering for GitHub activity&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;fix&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Squashing a bug&lt;/td&gt;
&lt;td&gt;&lt;code&gt;fix: handle API failure when GitHub is down&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;refactor&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Tidying up code without changing what it does&lt;/td&gt;
&lt;td&gt;&lt;code&gt;refactor: optimize API response formatting&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;docs&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Updating documentation&lt;/td&gt;
&lt;td&gt;&lt;code&gt;docs: update README with API usage guide&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;chore&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Little maintenance tasks&lt;/td&gt;
&lt;td&gt;&lt;code&gt;chore: add .gitignore and remove logs&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;style&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Just making things look prettier&lt;/td&gt;
&lt;td&gt;&lt;code&gt;style: format code with Black&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;test&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Adding or tweaking tests&lt;/td&gt;
&lt;td&gt;&lt;code&gt;test: add unit tests for date filtering&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;These labels make it easy to skim your commit history and know what’s what. No need for anything fancy—just pick one and go.&lt;/p&gt;




&lt;h4&gt;
  
  
  Keep Your Summary Short and Sweet
&lt;/h4&gt;

&lt;p&gt;Next up is the summary. Keep it quick—aim for under 50 characters if you can, but definitely cap it at 72. Write it like you’re giving a command: “Add this” or “Fix that.” It’s a quirky little standard in coding, but it works. For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;feat: add API endpoint for fetching GitHub activity&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fix: resolve bug in date filtering logic&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;docs: update README with setup instructions&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Avoid stuff like “Added a thing” or “Fixing bugs”—it’s too vague or wishy-washy. Be specific, and you’ll thank yourself later.&lt;/p&gt;




&lt;h4&gt;
  
  
  Add Some Details When It Matters
&lt;/h4&gt;

&lt;p&gt;For bigger changes, a short summary might not cut it. That’s where a detailed description comes in. After your type and summary, leave a blank line, then add a few lines about what you did and why. Here’s one I’d write:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;feat: add GitHub activity API

- Fetches user events from GitHub API
- Supports filtering by single date or date range
- Caches results for faster responses

Closes #12
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I remember when I first started coding, I’d skip this part entirely. My commit messages were just “updated code” or something equally useless. Weeks later, I’d be lost. Now, I love adding these little notes—especially for tricky fixes or big features. It’s like leaving a cheat sheet for my future self.&lt;/p&gt;




&lt;h4&gt;
  
  
  Tie It to Issues or Shout Out Your Team
&lt;/h4&gt;

&lt;p&gt;If your commit ties back to an issue or pull request, mention it. Something like &lt;code&gt;Closes #22&lt;/code&gt; or &lt;code&gt;Related to #15&lt;/code&gt; keeps everything connected. And if you’re working with others, give them a nod with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;feat: add webhook support for GitHub activity

Co-authored-by: Edgar Gulay &amp;lt;edgargulay@outlook.com&amp;gt;
Co-authored-by: John Doe &amp;lt;johndoe@example.com&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It’s a nice way to share the credit.&lt;/p&gt;




&lt;h4&gt;
  
  
  Keep Your History Tidy
&lt;/h4&gt;

&lt;p&gt;We’ve all been guilty of sloppy commits at some point. You know the ones: &lt;code&gt;wip: working on it&lt;/code&gt; or &lt;code&gt;fix: bug fixes&lt;/code&gt;. What were you working on? Which bug? Let’s avoid that, shall we? Instead, try:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fix: correct timestamp format in API response
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It’s specific, it’s clear, and it won’t leave anyone guessing. Your commit history should tell a story, not a mystery.&lt;/p&gt;




&lt;h4&gt;
  
  
  A Little Bonus Trick
&lt;/h4&gt;

&lt;p&gt;If you’re into automating things, you can set up a Git hook to nudge you into writing good commit messages. Here’s a quick way to do it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'exec &amp;lt; /dev/tty &amp;amp;&amp;amp; git cz --hook || true'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; .git/hooks/commit-msg
&lt;span class="nb"&gt;chmod&lt;/span&gt; +x .git/hooks/commit-msg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It’s like having a friendly reminder pop up every time you commit. Not required, but it’s a neat little helper.&lt;/p&gt;




&lt;h3&gt;
  
  
  Wrapping It Up
&lt;/h3&gt;

&lt;p&gt;So, there you go! Commit messages don’t have to be a drag. Use a type, keep your summary short and punchy, add details when you need to, and avoid the vague stuff. They’re like little notes to your future self and your team—make them count. Happy coding!&lt;/p&gt;




</description>
      <category>github</category>
      <category>commitmessage</category>
      <category>git</category>
    </item>
    <item>
      <title>Moving flask app to production.</title>
      <dc:creator>Eddie Gulay</dc:creator>
      <pubDate>Thu, 16 Jan 2025 22:51:50 +0000</pubDate>
      <link>https://forem.com/eddiegulay/moving-flask-app-to-production-41b6</link>
      <guid>https://forem.com/eddiegulay/moving-flask-app-to-production-41b6</guid>
      <description>&lt;div class="ltag__link"&gt;
  &lt;a href="/eddiegulay" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1162732%2Fa728d062-8f1d-4b0f-a055-2672e229f637.png" alt="eddiegulay"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://dev.to/eddiegulay/deploying-flask-app-in-digital-ocean-droplet-cep" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Deploying Flask App in Digital Ocean Droplet&lt;/h2&gt;
      &lt;h3&gt;Eddie Gulay ・ Jan 16&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#production&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#flask&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#generative&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#gemini&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


</description>
      <category>flask</category>
      <category>devops</category>
      <category>cloud</category>
    </item>
    <item>
      <title>Deploying Flask App in Digital Ocean Droplet</title>
      <dc:creator>Eddie Gulay</dc:creator>
      <pubDate>Thu, 16 Jan 2025 22:50:29 +0000</pubDate>
      <link>https://forem.com/eddiegulay/deploying-flask-app-in-digital-ocean-droplet-cep</link>
      <guid>https://forem.com/eddiegulay/deploying-flask-app-in-digital-ocean-droplet-cep</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1wfygnml9nlmepp52jea.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1wfygnml9nlmepp52jea.jpg" alt="to production with flask in a droplet" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Recently, I read a blog post about customizing APIs from Gemini Models, but when I tried following the instructions, everything got stuck at localhost:5000. Basically, my apps were only visible on my computer. So, I went on a quest to figure out how to make it accessible to everyone. That's when I learned about deploying Flask apps on a Digital Ocean droplet. This guide is like a map to help you do the same, so your projects don't get stuck at localhost:5000 either. Let's share your awesome creations with the world! ✨ It's time to unleash them onto the global stage by mastering the art of deploying Flask applications on a Digital Ocean droplet or any &lt;strong&gt;Ubuntu Server.&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;Step by step  guide to deploying Flask app in digital ocean droplet using gunicorn and nginx.&lt;/p&gt;

&lt;p&gt;Things we are going to cover&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Creating digital ocean droplet&lt;/li&gt;
&lt;li&gt;Preparing environment&lt;/li&gt;
&lt;li&gt;Actual deployment guide&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Creating digital ocean droplet
&lt;/h2&gt;

&lt;p&gt;Go to digital ocean and create an account if you don't have one. here is the link &lt;br&gt; ✨ &lt;a href="https://m.do.co/c/a8690363c67d" rel="noopener noreferrer"&gt;Digital Ocean&lt;/a&gt; 🎉 ~ This is a referral link, you will get &lt;strong&gt;$200&lt;/strong&gt; credit for &lt;strong&gt;60 days&lt;/strong&gt;. so no more excuses to why your projects are not deployed.&lt;/p&gt;

&lt;p&gt;After creating an account, click on the create button and select droplets. You will be presented with a list of options. Select the Ubuntu 20.04 LTS. Choose the plan of your preference. You can choose any data center region you want. I usually choose the one closest to me.&lt;/p&gt;

&lt;p&gt;Choose the authentication method. SSH keys are the best but for this guide, we are going to use a password. You can always add SSH keys later.&lt;/p&gt;

&lt;p&gt;if you are a windows user get yourself a virtual box and install Ubuntu. or use WSL 😂.&lt;/p&gt;

&lt;h2&gt;
  
  
  Preparing environment
&lt;/h2&gt;

&lt;p&gt;Now that we have our droplet up and running, let's prepare our environment.&lt;br&gt;
connect to your droplet using ssh.&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6vfeuhvh9s3ijktgx5x7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6vfeuhvh9s3ijktgx5x7.png" alt="ssh init" width="800" height="359"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Provide your password and you are in.&lt;/p&gt;

&lt;h3&gt;
  
  
  Update and upgrade
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt update
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;python3-pip python3-dev build-essential libssl-dev libffi-dev python3-setuptools
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;the command sudo apt update refreshes the list of available software packages on your system, ensuring that it has the latest information from the repositories. Following that, sudo apt install python3-pip python3-dev build-essential libssl-dev libffi-dev python3-setuptools installs essential tools and dependencies for Python development. This includes the Python 3 package manager (python3-pip), development headers for Python (python3-dev), fundamental build tools (build-essential), as well as libraries for SSL and FFI (libssl-dev and libffi-dev), and the Python package distribution tools (python3-setuptools).&lt;/p&gt;

&lt;h3&gt;
  
  
  Create a virtual environment
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;python3-venv
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a directory for your project and navigate to it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;apps
&lt;span class="nb"&gt;cd &lt;/span&gt;apps
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a virtual environment&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 &lt;span class="nt"&gt;-m&lt;/span&gt; venv venv
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Activate the virtual environment&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;source &lt;/span&gt;venv/bin/activate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Clone your project
&lt;/h3&gt;

&lt;p&gt;let's call our project &lt;code&gt;flask_app&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone your_project_url.git
&lt;span class="nb"&gt;cd &lt;/span&gt;flask_app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Install project dependencies
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; flask_app/requirements.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;now that we have your project up and running, let's run it and see if everything is working as expected.&lt;br&gt;
first lets allow the port we are going to use.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;ufw allow 5000

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

&lt;/div&gt;



&lt;p&gt;run the app&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python app.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;if everything is working as expected, you should be able to access your app using your droplet ip and port 5000.&lt;br&gt;
something like this &lt;code&gt;http://your_droplet_ip:5000&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Actual deployment guide
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Create WSGI entry point
&lt;/h3&gt;

&lt;p&gt;Create a file called &lt;code&gt;wsgi.py&lt;/code&gt; in your project root directory.&lt;br&gt;
or just copy app.py to wsgi.py&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cp &lt;/span&gt;app.py wsgi.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Configure Gunicorn
&lt;/h3&gt;

&lt;p&gt;Safe check if gunicorn is installed&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gunicorn &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;if not installed install it using pip&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;gunicorn
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;try running your app using gunicorn&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gunicorn &lt;span class="nt"&gt;--bind&lt;/span&gt; 0.0.0.0:5000 wsgi:app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check your app using your droplet ip and port 5000. something like this &lt;code&gt;http://your_droplet_ip:5000&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;if everything is working as expected, let's move to the next step.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create a systemd service file
&lt;/h3&gt;

&lt;p&gt;Create a systemd service file for gunicorn, this will allow gunicorn to automatically start on boot.&lt;br&gt;
first deactivate your virtual environment&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Then create a file called &lt;code&gt;flask_app.service&lt;/code&gt; in &lt;code&gt;/etc/systemd/system/&lt;/code&gt; directory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;nano /etc/systemd/system/flask_app.service
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add the following configuration to the file&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;[&lt;/span&gt;Unit]
&lt;span class="nv"&gt;Description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;Gunicorn instance to serve flask_app
&lt;span class="nv"&gt;After&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;network.target

&lt;span class="o"&gt;[&lt;/span&gt;Service]
&lt;span class="nv"&gt;User&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;root
&lt;span class="nv"&gt;Group&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;www-data
&lt;span class="nv"&gt;WorkingDirectory&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/root/apps/flask_app
&lt;span class="nv"&gt;Environment&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"PATH=/root/apps/venv/bin"&lt;/span&gt;
&lt;span class="nv"&gt;ExecStart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/root/apps/venv/bin/gunicorn &lt;span class="nt"&gt;--workers&lt;/span&gt; 3 &lt;span class="nt"&gt;--bind&lt;/span&gt; 0.0.0.0:5000 &lt;span class="nt"&gt;-m&lt;/span&gt; 777 wsgi:app

&lt;span class="o"&gt;[&lt;/span&gt;Install]
&lt;span class="nv"&gt;WantedBy&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;multi-user.target
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After creating the file, start the gunicorn service and enable it to start on boot.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl start flask_app
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl &lt;span class="nb"&gt;enable &lt;/span&gt;flask_app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check the status of the service to make sure it's running without any issues.&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;example output&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7lxqr73j9uh1t0yj78i1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7lxqr73j9uh1t0yj78i1.png" alt="alt text" width="800" height="170"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Configure Nginx to Proxy Requests
&lt;/h3&gt;

&lt;p&gt;Install Nginx&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a new server block configuration file in Nginx's &lt;code&gt;sites-available&lt;/code&gt; directory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;nano /etc/nginx/sites-available/flask_app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add the following configuration to the file. Replace &lt;code&gt;your_domain_or_ip&lt;/code&gt; with your actual domain name or IP address.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;server &lt;span class="o"&gt;{&lt;/span&gt;
    listen 80&lt;span class="p"&gt;;&lt;/span&gt;
    server_name 143.198.232.28&lt;span class="p"&gt;;&lt;/span&gt;

    location / &lt;span class="o"&gt;{&lt;/span&gt;
        proxy_pass https://143.198.232.28:5000&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a symbolic link to the file in the &lt;code&gt;sites-enabled&lt;/code&gt; directory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo ln&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt; /etc/nginx/sites-available/flask-app /etc/nginx/sites-enabled
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Test your Nginx configuration for syntax errors.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;nginx &lt;span class="nt"&gt;-t&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;you should see something like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf &lt;span class="nb"&gt;test &lt;/span&gt;is successful
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the test is successful, restart Nginx.&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Remember we allowed port 5000 earlier, now we can remove it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;ufw delete allow 5000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you should be able to access your app using your domain name or IP address without the port number. something like this &lt;code&gt;http://your_droplet_ip&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Secure your app with SSL
&lt;/h3&gt;

&lt;p&gt;Install certbot&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;certbot python3-certbot-nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Obtain a free SSL certificate for your domain using certbot if you have a domain.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;certbot &lt;span class="nt"&gt;--nginx&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; your_domain_or_ip
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Certbot will ask you to provide an email address for lost key recovery and notices, and to agree to the terms of service. After doing so, certbot will communicate with the Let's Encrypt server, then run a challenge to verify that you control the domain you're requesting a certificate for.&lt;/p&gt;

&lt;p&gt;When that's finished, certbot will ask how you'd like to configure your HTTPS settings.&lt;/p&gt;

&lt;p&gt;or you can use openssl to generate a self-signed certificate.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;openssl req &lt;span class="nt"&gt;-x509&lt;/span&gt; &lt;span class="nt"&gt;-nodes&lt;/span&gt; &lt;span class="nt"&gt;-days&lt;/span&gt; 365 &lt;span class="nt"&gt;-newkey&lt;/span&gt; rsa:2048 &lt;span class="nt"&gt;-keyout&lt;/span&gt; /etc/ssl/private/flask_app.key &lt;span class="nt"&gt;-out&lt;/span&gt; /etc/ssl/certs/flask_app.crt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a new server block configuration file in Nginx's &lt;code&gt;sites-available&lt;/code&gt; directory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;nano /etc/nginx/sites-available/flask_app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add the following configuration to the file. Replace &lt;code&gt;your_domain_or_ip&lt;/code&gt; with your actual domain name or IP address.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;
server &lt;span class="o"&gt;{&lt;/span&gt;
    listen 80&lt;span class="p"&gt;;&lt;/span&gt;
    server_name

    location / &lt;span class="o"&gt;{&lt;/span&gt;
        proxy_pass https://your_domain_or_ip&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

server &lt;span class="o"&gt;{&lt;/span&gt;
    listen 443 ssl&lt;span class="p"&gt;;&lt;/span&gt;
    server_name your_domain_or_ip&lt;span class="p"&gt;;&lt;/span&gt;

    ssl_certificate /etc/ssl/certs/nginx-selfsigned.crt&lt;span class="p"&gt;;&lt;/span&gt;
    ssl_certificate_key /etc/ssl/private/nginx-selfsigned.key&lt;span class="p"&gt;;&lt;/span&gt;

    location / &lt;span class="o"&gt;{&lt;/span&gt;
        proxy_pass https://your_domain_or_ip&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This configuration tells Nginx to listen on both port 80 (HTTP) and port 443 (HTTPS). It uses the self-signed certificate and private key that you created.&lt;/p&gt;

&lt;p&gt;After updating the Nginx configuration, remember to test the configuration and reload or restart Nginx:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;nginx &lt;span class="nt"&gt;-t&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl reload nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;nginx -t&lt;/code&gt; command checks the configuration for syntax errors. The &lt;code&gt;systemctl reload nginx&lt;/code&gt; command reloads the Nginx configuration without interrupting currently connected clients.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Please note that because the certificate is self-signed, browsers will show a warning to users that the site is not secure. Users will need to manually accept the risk and proceed to the site.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Hopefully with this guide, you were able to deploy your flask app in a digital ocean droplet. Your projects are way too precious to be running on localhost. Deploy them and share them with the world. If you have any questions or suggestions, feel free to reach out help is everywhere. ✨&lt;/p&gt;

</description>
      <category>production</category>
      <category>flask</category>
      <category>generative</category>
      <category>gemini</category>
    </item>
    <item>
      <title>Enhancing your web app's search with OctoPalm.js—a lightweight JavaScript library offering real-time, customizable search functionality. Features include animated results, emoji support, and cross-browser compatibility.</title>
      <dc:creator>Eddie Gulay</dc:creator>
      <pubDate>Thu, 09 Jan 2025 14:42:52 +0000</pubDate>
      <link>https://forem.com/eddiegulay/enhancing-your-web-apps-search-with-octopalmjs-a-lightweight-javascript-library-offering-bk0</link>
      <guid>https://forem.com/eddiegulay/enhancing-your-web-apps-search-with-octopalmjs-a-lightweight-javascript-library-offering-bk0</guid>
      <description>&lt;div class="ltag__link"&gt;
  &lt;a href="/eddiegulay" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1162732%2Fa728d062-8f1d-4b0f-a055-2672e229f637.png" alt="eddiegulay"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://dev.to/eddiegulay/javascript-library-to-add-real-time-customizable-search-to-your-web-applications-gmk" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;OctoPalm.js || JavaScript library to add real-time, customizable search to your web applications.&lt;/h2&gt;
      &lt;h3&gt;Eddie Gulay ・ Sep 19 '24&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#javascript&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#vscode&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#realtime&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#search&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


</description>
    </item>
    <item>
      <title>Building OpenCV 4.10.0 with GUI Support in WSL</title>
      <dc:creator>Eddie Gulay</dc:creator>
      <pubDate>Sun, 29 Dec 2024 21:04:34 +0000</pubDate>
      <link>https://forem.com/eddiegulay/building-opencv-4100-with-gui-support-in-wsl-5do0</link>
      <guid>https://forem.com/eddiegulay/building-opencv-4100-with-gui-support-in-wsl-5do0</guid>
      <description>&lt;p&gt;If you’re working with OpenCV on WSL and hit the infamous &lt;code&gt;cv2.error&lt;/code&gt; stating &lt;em&gt;GUI: NONE&lt;/em&gt;, you’ve probably realized that your OpenCV installation lacks GUI backend support. This guide will walk you through building OpenCV 4.10.0 from source with full GUI support, ensuring functions like &lt;code&gt;cv2.imshow&lt;/code&gt; work seamlessly. Let’s dive in!&lt;/p&gt;




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

&lt;p&gt;Before we begin, make sure you have WSL set up (preferably WSL2) with a Linux distribution like Ubuntu. We’ll also need to install several dependencies.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Install Required Dependencies
&lt;/h3&gt;

&lt;p&gt;Open your terminal and run the following commands to install the necessary development tools and libraries:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt update
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; build-essential cmake git pkg-config
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; libjpeg-dev libpng-dev libtiff-dev
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; libavcodec-dev libavformat-dev libswscale-dev
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; libv4l-dev v4l-utils
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; libxvidcore-dev libx264-dev
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; libgtk2.0-dev libgtk-3-dev libcanberra-gtk-module libcanberra-gtk3-module
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; python3-dev python3-pip python3-numpy
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; libopenblas-dev libatlas-base-dev liblapack-dev gfortran
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; libhdf5-dev libprotobuf-dev protobuf-compiler
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These libraries ensure that OpenCV can handle image processing, video decoding, and GUI rendering.&lt;/p&gt;




&lt;h3&gt;
  
  
  Step 2: Download OpenCV and Contrib Modules
&lt;/h3&gt;

&lt;p&gt;To build OpenCV from source, we need both the main OpenCV repository and the additional contrib modules for extended functionality.&lt;/p&gt;

&lt;h4&gt;
  
  
  Clone OpenCV:
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/opencv/opencv.git
&lt;span class="nb"&gt;cd &lt;/span&gt;opencv
git checkout 4.x
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Clone the Contrib Modules:
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; ..
git clone https://github.com/opencv/opencv_contrib.git
&lt;span class="nb"&gt;cd &lt;/span&gt;opencv_contrib
git checkout 4.x
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Step 3: Build OpenCV
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Create a Build Directory
&lt;/h4&gt;

&lt;p&gt;Navigate back to the OpenCV directory and create a &lt;code&gt;build&lt;/code&gt; directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; ../opencv
&lt;span class="nb"&gt;mkdir &lt;/span&gt;build
&lt;span class="nb"&gt;cd &lt;/span&gt;build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Configure the Build
&lt;/h4&gt;

&lt;p&gt;Run &lt;code&gt;cmake&lt;/code&gt; to configure the OpenCV build, ensuring GUI support is enabled:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cmake &lt;span class="nt"&gt;-D&lt;/span&gt; &lt;span class="nv"&gt;CMAKE_BUILD_TYPE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;Release &lt;span class="se"&gt;\&lt;/span&gt;
      &lt;span class="nt"&gt;-D&lt;/span&gt; &lt;span class="nv"&gt;CMAKE_INSTALL_PREFIX&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/usr/local &lt;span class="se"&gt;\&lt;/span&gt;
      &lt;span class="nt"&gt;-D&lt;/span&gt; &lt;span class="nv"&gt;OPENCV_EXTRA_MODULES_PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;../../opencv_contrib/modules &lt;span class="se"&gt;\&lt;/span&gt;
      &lt;span class="nt"&gt;-D&lt;/span&gt; &lt;span class="nv"&gt;WITH_GTK&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ON &lt;span class="se"&gt;\&lt;/span&gt;
      &lt;span class="nt"&gt;-D&lt;/span&gt; &lt;span class="nv"&gt;WITH_OPENGL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ON &lt;span class="se"&gt;\&lt;/span&gt;
      &lt;span class="nt"&gt;-D&lt;/span&gt; &lt;span class="nv"&gt;BUILD_EXAMPLES&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ON ..
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Compile OpenCV
&lt;/h4&gt;

&lt;p&gt;Use the following command to compile OpenCV. This process can take some time depending on your system:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;make &lt;span class="nt"&gt;-j&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;nproc&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, &lt;code&gt;$(nproc)&lt;/code&gt; ensures all available CPU cores are used for compilation.&lt;/p&gt;

&lt;h4&gt;
  
  
  Install OpenCV
&lt;/h4&gt;

&lt;p&gt;Once the compilation is complete, install OpenCV on your system:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;make &lt;span class="nb"&gt;install
sudo &lt;/span&gt;ldconfig
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Step 4: Verify the Installation
&lt;/h3&gt;

&lt;p&gt;Let’s check if OpenCV is installed correctly and GUI support is enabled:&lt;/p&gt;

&lt;h4&gt;
  
  
  Run a Python Script
&lt;/h4&gt;

&lt;p&gt;Open Python and run the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;cv2&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cv2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getBuildInformation&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Look for the &lt;strong&gt;GUI&lt;/strong&gt; section in the output. It should list &lt;code&gt;GTK&lt;/code&gt; or similar. If it says &lt;code&gt;NONE&lt;/code&gt;, ensure the required libraries were installed before running &lt;code&gt;cmake&lt;/code&gt; and repeat the build process.&lt;/p&gt;




&lt;h3&gt;
  
  
  Step 5: Test &lt;code&gt;cv2.imshow&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;To confirm everything works as expected, try displaying an image:&lt;/p&gt;

&lt;h4&gt;
  
  
  Sample Python Script:
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;cv2&lt;/span&gt;

&lt;span class="c1"&gt;# Load an image
&lt;/span&gt;&lt;span class="n"&gt;image&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cv2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;imread&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;path_to_your_image.jpg&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Display the image
&lt;/span&gt;&lt;span class="n"&gt;cv2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;imshow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Test Image&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;cv2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;waitKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;cv2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;destroyAllWindows&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If a window pops up showing your image, congratulations! You’ve successfully built OpenCV with GUI support.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Troubleshooting Tips&lt;/strong&gt;
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;GUI: NONE Still Appears:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ensure you installed &lt;code&gt;libgtk2.0-dev&lt;/code&gt; and &lt;code&gt;libgtk-3-dev&lt;/code&gt; before running &lt;code&gt;cmake&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Delete the &lt;code&gt;build&lt;/code&gt; directory and re-run the &lt;code&gt;cmake&lt;/code&gt; and &lt;code&gt;make&lt;/code&gt; steps.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Errors During Compilation:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Check for missing dependencies in the error messages and install them.&lt;/li&gt;
&lt;li&gt;Ensure your system has enough memory; close other programs if necessary.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Display Issues in WSL:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use an X server like &lt;a href="https://sourceforge.net/projects/vcxsrv/" rel="noopener noreferrer"&gt;VcXsrv&lt;/a&gt; on Windows if you’re not using WSLg.&lt;/li&gt;
&lt;li&gt;Export your display:
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt; &lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;DISPLAY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;hostname&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;.local:0
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Highlight&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Building OpenCV 4.10.0 from source may seem daunting, but it’s worth the effort for the flexibility and customization it offers. Whether you’re working on image processing, computer vision, or machine learning projects, having a fully functional OpenCV installation will unlock countless possibilities.&lt;/p&gt;

&lt;p&gt;Got stuck? Drop your errors or questions in the comments—I’m here to help!&lt;br&gt;
Happy coding!&lt;/p&gt;




&lt;p&gt;&lt;a href="https://buymeacoffee.com/eddiegulay" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8jhq9u1ovourbj8jeiw8.png" alt="Buy Eddie a coffee" width="545" height="153"&gt;&lt;/a&gt; &lt;/p&gt;

</description>
      <category>opencv</category>
      <category>wsl</category>
      <category>ubuntu</category>
      <category>make</category>
    </item>
    <item>
      <title>Secure Text Encryption and Decryption with Vanilla JavaScript</title>
      <dc:creator>Eddie Gulay</dc:creator>
      <pubDate>Tue, 03 Dec 2024 18:02:11 +0000</pubDate>
      <link>https://forem.com/eddiegulay/secure-text-encryption-and-decryption-with-vanilla-javascript-1c23</link>
      <guid>https://forem.com/eddiegulay/secure-text-encryption-and-decryption-with-vanilla-javascript-1c23</guid>
      <description>&lt;p&gt;In today’s digital age, securing sensitive information like API keys, passwords, and user data is more critical than ever. A robust encryption and decryption strategy can prevent unauthorized access and ensure data confidentiality. In this blog post, we’ll explore how to encrypt and decrypt text using vanilla JavaScript, leveraging the Web Crypto API for a modern, secure approach.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Use Encryption?
&lt;/h2&gt;

&lt;p&gt;Encryption transforms readable data (plaintext) into a scrambled format (ciphertext) that can only be read if decrypted with the correct key. This ensures that even if someone intercepts the encrypted data, it remains meaningless without the key. A solid encryption mechanism protects:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;API keys stored in your frontend code.&lt;/li&gt;
&lt;li&gt;Sensitive user information.&lt;/li&gt;
&lt;li&gt;Any data transferred over insecure channels.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s dive into how you can implement this securely in JavaScript.&lt;/p&gt;




&lt;h2&gt;
  
  
  Encryption and Decryption Using AES-GCM
&lt;/h2&gt;

&lt;p&gt;We’ll use AES-GCM (Advanced Encryption Standard - Galois/Counter Mode), a modern standard that provides both encryption and integrity verification. The steps involve:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Password Derivation&lt;/strong&gt;: Use PBKDF2 (Password-Based Key Derivation Function 2) to derive a secure key from a password.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Salt and IV&lt;/strong&gt;: Generate a random &lt;code&gt;salt&lt;/code&gt; (to make the password derivation unique) and &lt;code&gt;iv&lt;/code&gt; (Initialization Vector) for each encryption.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Encryption&lt;/strong&gt;: Encrypt the plaintext using AES-GCM.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Decryption&lt;/strong&gt;: Decrypt the ciphertext using the same password and &lt;code&gt;salt&lt;/code&gt;/&lt;code&gt;iv&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;




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

&lt;p&gt;Here is the complete JavaScript implementation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Utilities for Conversion
&lt;/h3&gt;

&lt;p&gt;We’ll convert between &lt;code&gt;ArrayBuffer&lt;/code&gt; and hexadecimal for easy data storage and retrieval:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;arrayBufferToHex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Uint8Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;byte&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;padStart&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;hexToArrayBuffer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bytes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Uint8Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;hex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parseInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;substr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Key Derivation from Password
&lt;/h3&gt;

&lt;p&gt;Use PBKDF2 to derive a strong encryption key:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getCryptoKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;encoder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;TextEncoder&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;keyMaterial&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;encoder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subtle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;importKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;raw&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;keyMaterial&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;PBKDF2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;deriveKey&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;deriveKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;salt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;keyMaterial&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getCryptoKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subtle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;deriveKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;PBKDF2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;salt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;salt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;iterations&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;100000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SHA-256&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="nx"&gt;keyMaterial&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;AES-GCM&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;256&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;encrypt&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;decrypt&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Encryption Function
&lt;/h3&gt;

&lt;p&gt;Encrypt text with a password:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;encryptText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;encoder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;TextEncoder&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;salt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getRandomValues&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Uint8Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;iv&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getRandomValues&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Uint8Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;deriveKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;salt&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;encrypted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subtle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;AES-GCM&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;iv&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;iv&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;encoder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;cipherText&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;arrayBufferToHex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;encrypted&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="na"&gt;iv&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;arrayBufferToHex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;iv&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="na"&gt;salt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;arrayBufferToHex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;salt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Decryption Function
&lt;/h3&gt;

&lt;p&gt;Decrypt text with the same password:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;decryptText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;encryptedData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;cipherText&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;iv&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;salt&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;encryptedData&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;deriveKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;hexToArrayBuffer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;salt&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;decrypted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subtle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;AES-GCM&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;iv&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;hexToArrayBuffer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;iv&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nf"&gt;hexToArrayBuffer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cipherText&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;decoder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;TextDecoder&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;decoder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;decrypted&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Example Usage
&lt;/h3&gt;

&lt;p&gt;Let’s see how to use these functions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;MySecretAPIKey123456&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;password&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;StrongPassword123!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Encrypt&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;encryptedData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;encryptText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Encrypted Data:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;encryptedData&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Decrypt&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;decryptedText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;decryptText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;encryptedData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Decrypted Text:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;decryptedText&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;})();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Security Best Practices
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Use a Strong Password&lt;/strong&gt;: The encryption is only as secure as the password you use.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Store Salt and IV Safely&lt;/strong&gt;: Always save the &lt;code&gt;salt&lt;/code&gt; and &lt;code&gt;iv&lt;/code&gt; alongside your encrypted data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Avoid Hardcoding Secrets&lt;/strong&gt;: Never hardcode sensitive data or passwords in your codebase.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use HTTPS&lt;/strong&gt;: Ensure your application uses HTTPS to protect data in transit.&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;Encrypting sensitive information like API keys is a fundamental step in securing your applications.  I use this for API keys mostly.&lt;/p&gt;

</description>
      <category>encryption</category>
      <category>decryption</category>
      <category>vanilla</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
