<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Madalitso Nyemba</title>
    <description>The latest articles on DEV Community by Madalitso Nyemba (@madalitsonyemba).</description>
    <link>https://dev.to/madalitsonyemba</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%2F444112%2Fe92b8fa7-08b2-419b-9e7f-72c73a4a82cc.jpeg</url>
      <title>DEV Community: Madalitso Nyemba</title>
      <link>https://dev.to/madalitsonyemba</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/madalitsonyemba"/>
    <language>en</language>
    <item>
      <title>Building MicroTZ: A Timezone Coordination Tool for Remote Teams</title>
      <dc:creator>Madalitso Nyemba</dc:creator>
      <pubDate>Mon, 27 Oct 2025 10:08:29 +0000</pubDate>
      <link>https://dev.to/madalitsonyemba/building-microtz-a-timezone-coordination-tool-for-remote-teams-1ehi</link>
      <guid>https://dev.to/madalitsonyemba/building-microtz-a-timezone-coordination-tool-for-remote-teams-1ehi</guid>
      <description>&lt;p&gt;As someone who's worked with remote teams across multiple continents, I thought building a Timezone coordination tool would be cool. I know there are several but none that served my needs all in one.&lt;/p&gt;

&lt;p&gt;That led me to build &lt;strong&gt;&lt;a href="https://microtz.madanyemba.dev" rel="noopener noreferrer"&gt;MicroTZ&lt;/a&gt;&lt;/strong&gt; - a simple timezone coordination tool that visualizes overlapping working hours across multiple timezones. And recently, I added a Slack bot integration that brings this functionality directly into your workspace.&lt;/p&gt;

&lt;p&gt;MicroTZ shows you &lt;strong&gt;at a glance&lt;/strong&gt; when everyone on your team is awake and working:&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%2F0ev7es3mofsftampu0p0.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%2F0ev7es3mofsftampu0p0.png" alt="Screenshot of MicroTZ" width="800" height="376"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The core feature is a &lt;strong&gt;24-hour timeline grid&lt;/strong&gt; that displays:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Working hours for each timezone (9 AM - 5 PM by default)&lt;/li&gt;
&lt;li&gt;Green highlights where ALL timezones overlap&lt;/li&gt;
&lt;li&gt;Optimal meeting time suggestions with overlap scores&lt;/li&gt;
&lt;li&gt;Shareable links (no login required)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Features
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Free tier:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Compare up to 3 cities&lt;/li&gt;
&lt;li&gt;Visual timeline grid&lt;/li&gt;
&lt;li&gt;Working hours overlap detection&lt;/li&gt;
&lt;li&gt;Shareable links&lt;/li&gt;
&lt;li&gt;Save up to 3 timezone sets&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Pro tier ($1/month):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Unlimited cities&lt;/li&gt;
&lt;li&gt;Unlimited saved sets&lt;/li&gt;
&lt;li&gt;CSV/ICS export&lt;/li&gt;
&lt;li&gt;No watermark&lt;/li&gt;
&lt;li&gt;Slack bot integration&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Tech Stack: Keeping It Simple
&lt;/h2&gt;

&lt;p&gt;Here's what powers MicroTZ:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;techStack&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;frontend&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Next.js 14 + TypeScript + Tailwind CSS&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;backend&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Next.js API Routes&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;database&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Supabase (PostgreSQL)&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Supabase Auth&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;payments&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Paddle&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;timezones&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Luxon&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;slackBot&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@slack/bolt + @slack/web-api&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;deployment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Coolify&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Why These Choices?
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Next.js 14&lt;/strong&gt;: The App Router makes it incredibly easy to build both the UI and API in one codebase. Server Components help with performance, and the API routes are perfect for webhooks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Supabase&lt;/strong&gt;: PostgreSQL + instant APIs + auth + real-time subscriptions out of the box. I can focus on building features instead of auth flows.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Slack Integration: Where It Gets Fun
&lt;/h2&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%2Fz3v44n92ayzdbwgbtcro.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%2Fz3v44n92ayzdbwgbtcro.png" alt="Screenshot of MicroTZ" width="800" height="399"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I used Slack's &lt;strong&gt;Bolt SDK&lt;/strong&gt; which makes building Slack apps surprisingly pleasant:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@slack/bolt&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;App&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SLACK_BOT_TOKEN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;signingSecret&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SLACK_SIGNING_SECRET&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="c1"&gt;// Slash command: /timezone New York London Tokyo&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;command&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/timezone&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;command&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ack&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;say&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;ack&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;cities&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;command&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="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt; &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;timezones&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cities&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;city&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;cityToTimezone&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;city&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;overlap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;calculateTimezoneOverlaps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;timezones&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;meetingTimes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;findOptimalMeetingTimes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;overlap&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;say&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;blocks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;buildSlackBlocks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;timezones&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;meetingTimes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Slack bot supports:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;/timezone [cities]&lt;/code&gt; - Compare working hours&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/meeting-time [cities]&lt;/code&gt; - Find optimal times&lt;/li&gt;
&lt;li&gt;Interactive buttons (Share, Save, Export)&lt;/li&gt;
&lt;li&gt;Free tier: 3 cities | Pro tier: Unlimited&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Try It Out!
&lt;/h2&gt;

&lt;p&gt;🔗 &lt;strong&gt;&lt;a href="https://microtz.madanyemba.dev" rel="noopener noreferrer"&gt;microtz.madanyemba.dev&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The free tier is genuinely useful (no credit card required), and Pro is just $1/month if you need unlimited cities or Slack integration.&lt;/p&gt;

&lt;p&gt;If you're building remote tools or have worked with timezones, I'd love to hear your experiences in the comments!&lt;/p&gt;




</description>
      <category>productivity</category>
      <category>sideprojects</category>
      <category>showdev</category>
      <category>tooling</category>
    </item>
    <item>
      <title>2024 First Quarter Reads</title>
      <dc:creator>Madalitso Nyemba</dc:creator>
      <pubDate>Sun, 14 Apr 2024 02:03:27 +0000</pubDate>
      <link>https://dev.to/madalitsonyemba/2024-first-quarter-reads-13g8</link>
      <guid>https://dev.to/madalitsonyemba/2024-first-quarter-reads-13g8</guid>
      <description>&lt;p&gt;The three books that have changed my perspective on life and helped me become a better programmer.&lt;/p&gt;




&lt;p&gt;At the beginning of the year, I jotted down several things I wanted to achieve by the end of the year. One of the things was to read one book a month. I know it is not as many as I can handle but I am also trying to build a reading habit. I looked at my life and what I wanted to achieve. This reflection helped me pick out the 12 books that were ordered in a way that made sense to me. I want to share the 3 I have read from January through March and my brief learnings. This is not your typical tech article but just sharing what has helped me.&lt;/p&gt;

&lt;p&gt;The book for January is a book by Stephen Covey titled &lt;a href="https://www.amazon.com/Habits-Highly-Effective-People-Powerful/dp/0743269519"&gt;The 7 Habits of Highly Effective People&lt;/a&gt;. The 7 habits listed are being proactive, beginning with the end in mind, putting first things first, thinking win-win, seeking to understand before being understood, synergising, and sharpening the saw. The key takeaway for me was habit number 2 which is to begin with the end in mind. I believe in purpose and that everyone has it. This point emphasises that we need to have a clear mission statement. You do not need to have it all figured out but just have a vision of the outcome. You take it from there. This also helps one in decision-making because you can easily know if a decision will derail you or push you towards the goal. Just like in planning a project. DO NOT JUST HACK AWAY but rather look at the overall picture you want to achieve in the end. Then and only then, can you begin. This book is structured in a way that helps one chronologically from being independent to living interdependent with others. It is a great recommendation if you want to be effective in life as the title suggests.&lt;/p&gt;

&lt;p&gt;The book for February is a book by Nicolas Cole titled &lt;a href="https://amzn.to/43THLSm"&gt;The Art and Business of Online Writing: How to Beat the Game of Capturing and Keeping Attention&lt;/a&gt;. This was an easy choice for me because online writing is a topic I fancy and want to get to know in depth. Arguably this is the best book I have read for several reasons. Firstly, even though it is about writing, you learn a lot of principles that are essential like consistency is key, how research is fundamental to excel in your field and most importantly the only way you can ever get good at something is by doing it, period. Secondly, it outlines a lot of examples that an aspiring writer can use and grow an online audience and become a successful writer. Third and most interesting for me, it is a fast-paced book. At the end of every reading session, I felt like I had been running a marathon. This is not a bad thing and I wish more book writers embraced this. This book will help one in communicating efficiently and effectively. I highly recommend it even though you are not an aspiring writer as most concepts can be applied in various fields. Oh, and you will write concise and effective emails or application letters that grab the reader and let them know exactly what you want to let them know.&lt;/p&gt;

&lt;p&gt;The book for March is a book by Matthew Dicks called &lt;a href="https://amzn.to/43T8Uot"&gt;Someday Is Today: 22 Simple, Actionable Ways to Propel Your Creative Life&lt;/a&gt;. I have a lot to say about this book that I could write a whole book about it. This is an awesome read and I recommend it should be the next book you read. Mathew Dicks outlines several strategies that help him be productive like taking 100-second showers, timing emptying the dishwasher, taking 23 minutes to do shopping, eating oatmeal for lunch every day for years, and the list goes on. However, the strategy that got to me was the one-hundred-year-old version of yourself. It is like a check you can use to make a decision. When found to make a decision, you ask if the 100-year-old version of you would look back and be glad that you made that decision. Would that version be glad that you spent a whole Saturday bingeing Netflix? A couple of weeks before reading this book, I uninstalled all social media applications and just left WhatsApp for communication. This boosted my productivity a lot. This book mentioned how you do not need the right environment to get things done but you can rather make the environment right (I paraphrase). This made me use the tiny gaps between activities even better. Those gaps like waiting for your girl as she gets ready or waiting for your turn at the hospital. I used to just whip out my phone and go through my X feed or TikTok but now I read a few lines of the book I'm currently reading or I google an error I earlier met that is stuck in my head. My sister once asked me where I get the time to read as I seem to be always coding and I answered exactly that by saying I utilise the small gaps. 10 minutes in and of itself seems small but compound that over a week, a month, a year then you will see you will be further ahead towards your goals than if you misused the 10 minutes. I can go on and on sharing about this book. Please read this book.&lt;/p&gt;

&lt;p&gt;The first quarter has been amazing and I am already in my first book for the second quarter. The sentence for the first quarter is: Ask the 100-year-old version of yourself what purpose/accomplishment would be worthwhile and keep cranking at it on a daily basis with a clear vision of the ideal and not the current knowing we get better by always doing. You have that million-dollar project idea but not sure how to begin, just start. You want to write articles on dev.to, just start.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Disclaimer: The links to the books are my Amazon affiliate links.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>writing</category>
      <category>reading</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Record Audio In Blazor Hybrid App Using Plugin.Maui.Audio</title>
      <dc:creator>Madalitso Nyemba</dc:creator>
      <pubDate>Sat, 02 Mar 2024 00:34:37 +0000</pubDate>
      <link>https://dev.to/madalitsonyemba/record-audio-in-blazor-hybrid-app-using-pluginmauiaudio-mo</link>
      <guid>https://dev.to/madalitsonyemba/record-audio-in-blazor-hybrid-app-using-pluginmauiaudio-mo</guid>
      <description>&lt;p&gt;In some project I was working on, there was a requirement to introduce a feature that allowed the application users to record an audio of themselves. Being new to the world of Blazor, I immediately started looking for what the internet had to offer with regard to the requirements at hand. I stumbled upon a great package called &lt;code&gt;Plugin.Maui.Audio&lt;/code&gt; by &lt;a class="mentioned-user" href="https://dev.to/jfversluis"&gt;@jfversluis&lt;/a&gt;. Of course, there were notable mentions that used interop JS to leverage the power of the browser but I did not want to go that route. I gave in after sometime but the interop approach was not working.&lt;/p&gt;

&lt;p&gt;Looking at this package, the example given was for a .Net MAUI app. I divert. One of the reasons I fell in love with a Blazor Hybrid App, aside from the one codebase for all platforms, is the ability to utilize the powers of Blazor as well as .Net which gives you essentially a lot of power and flexibility in implementing features. Now, back to the package example. I had to sit down to tailor the example to fit in my Blazor application.&lt;/p&gt;

&lt;p&gt;In this short article, I will share how I implemented this as well as playing the recorded audio using HTML's audio player tag.&lt;/p&gt;

&lt;p&gt;Take note that this article assumes you have created your Blazor Hybrid app. We can start from the just-created Blazor app without any modifications.&lt;/p&gt;

&lt;p&gt;First things first, permissions are very important since this is a Hybrid App which means it shall have to interact with different devices. You can find the detailed steps &lt;a href="https://github.com/jfversluis/Plugin.Maui.Audio/blob/main/docs/audio-recorder.md"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Android&lt;/strong&gt;&lt;br&gt;
The &lt;code&gt;AndroidManifest.xml&lt;/code&gt; file will need to be modified to include the following uses-permission inside the manifest tag.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;uses-permission android:name="android.permission.RECORD_AUDIO"/&amp;gt;
&amp;lt;uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" /&amp;gt;
&amp;lt;uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /&amp;gt;
&amp;lt;uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /&amp;gt;

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;iOS&lt;/strong&gt;&lt;br&gt;
The &lt;code&gt;Info.plist&lt;/code&gt;file will need to be modified to include the following 2 entries inside the dict tag.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;key&amp;gt;NSMicrophoneUsageDescription&amp;lt;/key&amp;gt;
&amp;lt;string&amp;gt;The [app name] wants to use your microphone to record audio.&amp;lt;/string&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replacing [app name] with your application name.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;MacCatalyst&lt;/strong&gt;&lt;br&gt;
This change is identical to the iOS section but for explicitness:&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;Info.plist&lt;/code&gt; file will need to be modified to include the following 2 entries inside the dict tag.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;key&amp;gt;NSMicrophoneUsageDescription&amp;lt;/key&amp;gt;
&amp;lt;string&amp;gt;The [app name] wants to use your microphone to record audio.&amp;lt;/string&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replacing [app name] with your application name.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Windows&lt;/strong&gt;&lt;br&gt;
The &lt;code&gt;Package.appxmanifest&lt;/code&gt; file will need to be modified to include the following entry inside the Capabilities tag.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;DeviceCapability Name="microphone"/&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After that, in the root of the project, create a folder called Services. Inside this folder, create a file called &lt;code&gt;AudioService.cs&lt;/code&gt;.&lt;br&gt;
The below shall be the contents.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
using Plugin.Maui.Audio;
using System.Threading.Tasks;

namespace MyBlazorHybridApp.Services
{

    public interface IAudioService
    {
        Task StartRecordingAsync();
        Task&amp;lt;Stream&amp;gt; StopRecordingAsync();
        bool IsRecording { get; }
    }

    public class AudioService : IAudioService
    {
        private IAudioManager _audioManager;
        private IAudioRecorder _audioRecorder;
        public bool IsRecording =&amp;gt; _audioRecorder.IsRecording;
        public AudioService(IAudioManager audioManager)
        {
            _audioManager = audioManager;
            _audioRecorder = audioManager.CreateRecorder();
        }

        public async Task StartRecordingAsync()
        {
            await _audioRecorder.StartAsync();
        }

        public async Task&amp;lt;Stream&amp;gt; StopRecordingAsync()
        {
            var recordedAudio = await _audioRecorder.StopAsync();
            return recordedAudio.GetAudioStream();
        }
    }

}

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

&lt;/div&gt;



&lt;p&gt;In the above code, you can see that the above class implements 2 methods namely &lt;code&gt;StartRecordingAsync&lt;/code&gt; and &lt;code&gt;StopRecordingAsync&lt;/code&gt;. It also implements a bool &lt;code&gt;IsRecording&lt;/code&gt; which will be useful in our UI. Take note that the &lt;code&gt;StopRecordingAsync&lt;/code&gt; returns a Stream. According to the docs of &lt;a href="https://github.com/jfversluis/Plugin.Maui.Audio"&gt;Maui.Plugin.Audio&lt;/a&gt;, the &lt;code&gt;StopAsync&lt;/code&gt; method returns the &lt;code&gt;IAudioSource&lt;/code&gt; instance with the recording data. I am getting the audio stream in the IAudioSource instance provided.&lt;/p&gt;

&lt;p&gt;Move over to &lt;code&gt;MauiProgram.cs&lt;/code&gt; and add &lt;code&gt;using Plugin.Maui.Audio;&lt;/code&gt; on the top of the file and &lt;code&gt;builder.Services.AddSingleton(AudioManager.Current);&lt;/code&gt; where the services are being injected in the builder before &lt;code&gt;var app = builder.Build();&lt;/code&gt;. This shall simply register your custom service with the application so it can be used globally within the application.&lt;/p&gt;

&lt;p&gt;In your razor file, it will look like below&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
//different dependecies above
@inject AudioService AudioService;

&amp;lt;div class="flex-column mt3"&amp;gt;
    &amp;lt;div class="f5 mb2"&amp;gt;
        Record an audio
    &amp;lt;/div&amp;gt;
    &amp;lt;div class="f5 mb2"&amp;gt;
        @if (!AudioService.IsRecording)
        {
            &amp;lt;button @onclick="StartRecording"&amp;gt; Start&amp;lt;/button&amp;gt;
        }
        else
        {
            &amp;lt;button @onclick="StopRecording"&amp;gt; Stop&amp;lt;/button&amp;gt; 
        }
    &amp;lt;/div&amp;gt;
    &amp;lt;audio controls src="@AudioSource"&amp;gt;
        Your browser does not support the audio element.
    &amp;lt;/audio&amp;gt;


&amp;lt;/div&amp;gt;

@code {
    private Stream recordedAudioStream;
    private string AudioSource { get; set; }
   public async void StartRecording()
    {
        if (await Permissions.RequestAsync&amp;lt;Permissions.Microphone&amp;gt;() != PermissionStatus.Granted)
        {
            // Inform user to request permission
        }
        else
        {
            await AudioService.StartRecordingAsync();

        }

    }
    public async void StopRecording()
    {
        recordedAudioStream =  await AudioService.StopRecordingAsync();


        var audioBytes = new byte[recordedAudioStream.Length];
        await recordedAudioStream.ReadAsync(audioBytes, 0, (int)recordedAudioStream.Length);
        var base64String = Convert.ToBase64String(audioBytes);


        AudioSource = $"data:audio/mpeg;base64,{base64String}";
        StateHasChanged();

    }
}

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

&lt;/div&gt;



&lt;p&gt;The above code is for the UI. It injects the service into the UI and has buttons that will start/stop accordingly. However, when stopping, I save the IAudioSource instance with the recording data into a Stream called &lt;code&gt;recordedAudioStream&lt;/code&gt;. I then convert the stream into a base64string so that the AudioSource can be populated with the right data to play. So, what happens is when one presses play, it starts to record and when one presses Stop, it stops recording and the previously recorded audio is loaded into the audio player where one can replay the audio. This approach helps one not build out a UI for playback of the data but can utilize what is already available like the audio tag. I hope this has helped someone. &lt;br&gt;
Happy Coding 🧑‍💻.&lt;/p&gt;

</description>
      <category>blazor</category>
      <category>mobile</category>
      <category>application</category>
      <category>maui</category>
    </item>
    <item>
      <title>Master One Language, Learn All</title>
      <dc:creator>Madalitso Nyemba</dc:creator>
      <pubDate>Tue, 28 Nov 2023 08:39:56 +0000</pubDate>
      <link>https://dev.to/madalitsonyemba/master-one-language-learn-all-1p7b</link>
      <guid>https://dev.to/madalitsonyemba/master-one-language-learn-all-1p7b</guid>
      <description>&lt;p&gt;So, when it comes to diving into the whole coding world, job listings can be a bit overwhelming with their "must know language A" or "must be proficient in language B" demands. Now, people often ask me, "What's the best tech stack to focus on?" My take is pretty simple: pick one you actually like because chances are, someone out there is hiring for it. If you become a pro at it, you'll be in demand, no matter the odds. This way, you won't end up all over the place, switching stacks left and right.&lt;/p&gt;

&lt;p&gt;Sure, coding languages have different syntax, but the core concepts remain the same - loops, conditionals, variables, you get the drill. There are tons of paths you can take as a developer, but once you grasp the basics, you can easily adapt them to different languages. It's not a walk in the park, but it's doable and quicker than when you tackled your first language.&lt;/p&gt;

&lt;p&gt;Feeling like hopping onto another language? My advice: dive straight into a project. Here's a quick roadmap:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Figure out what your project needs to do.&lt;/li&gt;
&lt;li&gt;Break it into doable steps.&lt;/li&gt;
&lt;li&gt;Write those steps in plain English.&lt;/li&gt;
&lt;li&gt;Research how to do those steps in your chosen language.&lt;/li&gt;
&lt;li&gt;Code it up, even if it's a bit messy at first.&lt;/li&gt;
&lt;li&gt;Get it working, and then optimize the code.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;P.S:&lt;/strong&gt; your go-to resource for learning a new language should be the documentation. Tutorials are cool, but mastering the art of reading documentation will make you unstoppable.&lt;/p&gt;

&lt;p&gt;Got an interview for a language you've never touched? No sweat. Cook up a challenging project using the steps above. Trust me, jumping from one language to another will feel like a breeze. But hey, don't spread yourself too thin – aim to be a master of at least one or two. Share your thoughts and approaches in the comments. Good luck out there!&lt;/p&gt;

</description>
      <category>learning</category>
      <category>webdev</category>
      <category>programming</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Navigating Change: Reflections on the First 10 Days in a New Coding Adventure</title>
      <dc:creator>Madalitso Nyemba</dc:creator>
      <pubDate>Sat, 18 Nov 2023 10:51:25 +0000</pubDate>
      <link>https://dev.to/madalitsonyemba/navigating-change-reflections-on-the-first-10-days-in-a-new-coding-adventure-3kh6</link>
      <guid>https://dev.to/madalitsonyemba/navigating-change-reflections-on-the-first-10-days-in-a-new-coding-adventure-3kh6</guid>
      <description>&lt;p&gt;I changed employment and moved into a full-time development role as a Principal Salesforce Developer in the middle of my 30-day JavaScript course. I refer to it as a full-time development post since, at my prior position, I was responsible for both internal system development and end-user support. This transfer compelled me to relocate to a different city within my Country. I had to take care of a lot of moving pieces after such a significant change in my life, so I had to put the 30-day coding challenge on hold. Which brings me to this article, where instead of sharing my first 20 days in the challenge, I shall share my first 10 days in the new role and lessons learnt during this transition.&lt;/p&gt;

&lt;h2&gt;
  
  
  Always Lay Your Bed: A Foundation for Smooth Transitions 🛏️
&lt;/h2&gt;

&lt;p&gt;As much as other people are of the view that you ought to create dependency syndrome with the company you work for, in some instances, it is better to finish tasks, document and teach others a thing or two about your work. Allow me to illustrate this with examples. In my previous role, I played a pivotal role in developing in-house systems that became integral to daily operations. Then, this new opportunity came up, and I had just about a week and a half to switch jobs. It wasn't a lot of time, so I spent most of those days writing down everything about the systems—how they work, the code, and the processes. I wanted to make it easier for the person taking over after me. If I had been more focused on finishing up tasks and sharing what I knew with others earlier, the change would have been smoother. &lt;/p&gt;

&lt;h2&gt;
  
  
  Make Decisions based on your personal aspirations 🤔
&lt;/h2&gt;

&lt;p&gt;Life is a journey with lots of different paths, and each of us has our own dreams and directions. I took my last job because it was at a big, well-known place, and I thought having that on my resume would be good, even though it wasn't exactly the kind of coding job I really wanted. However, the job really taught me a lot, made me meet a lot of great people and I am glad I went that route. Before that, I taught programming at the school where I studied. It wasn't a complete coding job, but I liked it because I got to teach programming. Now, this new opportunity came up, and it's a full-on coding role, exactly what I've been aiming for in my career. So, going for this coding role might seem like a step down in the company hierarchy, but I see it as a step forward towards what I genuinely want to do. It's a journey, and I'm hoping this path I'm taking lines up with my goals, and I find satisfaction without any regrets.&lt;/p&gt;

&lt;h2&gt;
  
  
  Read the manual 📖
&lt;/h2&gt;

&lt;p&gt;On my first day at my new job, they handed me a project that involved using a sort of preview version of a language, called a Release Candidate (RC). It's like getting a sneak peek at the final version, but there might still be a few issues, like bugs. You won't find a step-by-step YouTube video for this, though. Instead, all I had was a ton of documentation—pages and pages of it. I had to quickly figure out how to use the documentation to make things work with this language. It's not as easy as following a tutorial, but I think if I had been better at it from the start, I wouldn't have had to spend so many hours getting up to speed. This whole experience showed me that while tutorials are good for basics, they only cover what the tutor knows. On the other hand, documentation has everything you can do with a language. I don't dislike tutorials, but the sweet spot is learning the basics from a tutorial and then diving into the documentation to really understand how to make the most out of the language. So, make it a habit to read the manual of every product, or you'll likely end up not using it to its full potential.&lt;/p&gt;

&lt;h2&gt;
  
  
  Know your worth 🤑
&lt;/h2&gt;

&lt;p&gt;When it comes to talking about how much you get paid, just be clear about what you think you deserve. Think about how any changes, like moving, might affect you. Don't sell yourself short because you're scared of being rejected, but also don't ask for so much that you miss out on a good job. Tell the potential boss what you want in terms of pay and stick to it. I'm assuming you already have a job or some way of making money because you can negotiate better if you can say, "No thanks, I'll stick with what I've got." But it's not just about the money. Sometimes, the workplace can be a really bad environment, or the job doesn't match up with what you want to achieve. If you're just starting out, it can be tough because you might have lots of skills but not get paid much. For those starting off, I say don't just focus on the money. Think about what you can learn from the job. Money comes and goes, but knowledge sticks with you. Nobody can take away what you've learned, and that kind of knowledge pays off in the long run as long as you keep trying and learning.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pray 🙏
&lt;/h2&gt;

&lt;p&gt;I always say no one can convince another to believe fully unless that individual has a personal encounter that shall lead them to believe. I have gone through many paths and hurdles in my life as well as career. One thing that always suffices and gives me peace is prayer. Myles Munroe defined prayer as allowing God to intervene. Thus, it gives me peace knowing that it is all under control even if it might not seem so. The decision to leave a big institution and work for a remote company under a hybrid arrangement was scary. I did all the calculations and had a bunch of what-ifs but still did not find peace. After I prayed about it, I trusted that I would leave and I was at peace with it which was what mattered.&lt;/p&gt;

&lt;p&gt;As I navigate this uncharted coding chapter, I'm thrilled to announce the launch of "&lt;a href="https://madalitsonyemba.substack.com/"&gt;The Code Father's Journal&lt;/a&gt;" newsletter. Join me on this coding adventure, subscribe, and let's unravel the human side of technology together. Happy coding, fellow adventurers! 🚀&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>reflection</category>
      <category>career</category>
      <category>learning</category>
    </item>
    <item>
      <title>First 10 Days of 30 Days of Javascript</title>
      <dc:creator>Madalitso Nyemba</dc:creator>
      <pubDate>Tue, 24 Oct 2023 11:56:48 +0000</pubDate>
      <link>https://dev.to/madalitsonyemba/first-10-days-of-30-days-of-javascript-3blo</link>
      <guid>https://dev.to/madalitsonyemba/first-10-days-of-30-days-of-javascript-3blo</guid>
      <description>&lt;p&gt;In 2015, my coding journey kicked off, and I plunged headfirst into the world of development, starting with  C++. Two whole years were dedicated to mastering this language, setting the stage for my coding adventures. Then, in 2017, a new chapter unfolded as I ventured into the vibrant world of web development, and that's when JavaScript made its debut in my life.&lt;/p&gt;

&lt;p&gt;Throughout the years, I've had the pleasure of crafting various professional projects that have touched the lives of many. From systems development to creating mobile apps and tinkering with chrome extensions, I've tried my hand at it all. However, as time went on, a desire to dive deeper into the fundamental concepts of programming started to take root.&lt;/p&gt;

&lt;p&gt;One fine day, while navigating the digital landscape of LeetCode, I stumbled upon a 30-day JavaScript challenge, seemingly tailored for beginners. Now, while I'd certainly graduated from the beginner stage, I decided to take on this challenge for a couple of good reasons.&lt;/p&gt;

&lt;p&gt;Firstly, I was in need of some consistency in my coding journey. You see, I've had my struggles with staying consistent, and this challenge seemed like the perfect remedy.&lt;/p&gt;

&lt;p&gt;Secondly, I wanted to expand my knowledge beyond the boundaries of popular frameworks like Vue, React, Angular, and React Native and get back to the basics of JavaScript.&lt;/p&gt;

&lt;p&gt;Lastly, I was eager to shift from the habit of merely copying code from tutorials on how to do something, without truly grasping the intricacies of what was required of me.&lt;/p&gt;

&lt;p&gt;My journey turned out to be quite an adventure, and every day started with a LeetCode challenge. Whether it was a quick five-second puzzle or a more challenging 30-minute quest, I tackled it with enthusiasm.&lt;/p&gt;

&lt;p&gt;So, here's a peek into the highlights, solutions, and insights gathered during the first ten days of this fun-filled JavaScript exploration.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;On Day 3&lt;/strong&gt;, the question was as below in the comments and the solution I gave:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//Write a function expect that helps developers test their code.It should take in any value val and return an object with the following two functions.
// toBe(val) accepts another value and returns true if the two values === each other. If they are not equal, it should throw an error "Not Equal".
// notToBe(val) accepts another value and returns true if the two values !== each other. If they are equal, it should throw an error "Equal"

var expect = function(val) {
    return{
    toBe: (v) =&amp;gt; { 
        if(val === v){
                return true
            }else{
                throw new Error("Not Equal")
            }
      },
      notToBe: (v) =&amp;gt; { 
        if(val !== v){
                return true
            }else{
                throw new Error("Equal")
            }
      }
    }  
    };
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This was an interesting question where it had to return an object with two functions and show testing proficiency by throwing errors as well as gauge a devs understanding of Javascript’s equality operators (===) as they may behave unexpectedly if not used correctly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;On Day 7&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Given an integer array nums, a reducer function fn, and an initial &lt;/span&gt;
&lt;span class="c1"&gt;//value init, return a reduced array.&lt;/span&gt;
&lt;span class="c1"&gt;// A reduced array is created by applying the following operation: &lt;/span&gt;
&lt;span class="c1"&gt;//val = fn(init, nums[0]), val = fn(val, nums[1]), val = fn(val, nums[2]), ...&lt;/span&gt;
&lt;span class="c1"&gt;// until every element in the array has been processed. The final value of&lt;/span&gt;
&lt;span class="c1"&gt;// val is returned.&lt;/span&gt;

&lt;span class="c1"&gt;// If the length of the array is 0, it should return init.&lt;/span&gt;

&lt;span class="c1"&gt;// Please solve it without using the built-in Array.reduce method.&lt;/span&gt;

&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;reduce&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;init&lt;/span&gt;&lt;span class="p"&gt;)&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;val&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nums&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;0&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;init&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;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;nums&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="p"&gt;){&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;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;val&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;init&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;nums&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="p"&gt;}&lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;val&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;nums&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="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;val&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;This was interesting as it made me further understand how reducers work in Javascript as I studied them after submission of the task.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;On Day 10&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Given a function fn, return a new function that is identical to the original function except that it ensures fn is called at most once.&lt;/span&gt;

&lt;span class="c1"&gt;// The first time the returned function is called, it should return the same result as fn.&lt;/span&gt;
&lt;span class="c1"&gt;// Every subsequent time it is called, it should return undefined.&lt;/span&gt;

&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;once&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;)&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;another&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fn&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="k"&gt;return&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
           &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;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;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;another&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
           &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
               &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;
           &lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;I found this interesting as can be useful in scenarios where you want to restrict certain functions to execute only once, like initialization routines or one-time setup operations.&lt;/p&gt;

&lt;p&gt;In summary, this has been my first 10 days towards 30 days of Javascript challenge. This is the start of a series that shall be documented in chunks of 10 days. See you after 10 days. Happy coding.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>leetcode</category>
      <category>programming</category>
    </item>
    <item>
      <title>Impostor Syndrome – Programmers Perspective</title>
      <dc:creator>Madalitso Nyemba</dc:creator>
      <pubDate>Sat, 10 Dec 2022 08:55:44 +0000</pubDate>
      <link>https://dev.to/madalitsonyemba/impostor-syndrome-programmers-perspective-32fj</link>
      <guid>https://dev.to/madalitsonyemba/impostor-syndrome-programmers-perspective-32fj</guid>
      <description>&lt;p&gt;Impostor syndrome, also known as impostor phenomenon or fraud syndrome, is a psychological pattern in which an individual doubts their accomplishments and has a persistent fear of being exposed as a "fraud". This syndrome is not unique to the field of programming, but it can be particularly prevalent among programmers due to the constantly evolving nature of the field and the high standards that are often placed on them.&lt;/p&gt;

&lt;p&gt;Programming can be a challenging and demanding field, and it's not uncommon for programmers to feel like they don't measure up to their peers or to the expectations placed on them. This can lead to feelings of inadequacy, self-doubt, and even fear of being discovered as an impostor.&lt;/p&gt;

&lt;p&gt;One of the key factors contributing to impostor syndrome among programmers is the sheer amount of knowledge and skill that is required to be successful in the field. With new technologies and programming languages constantly emerging, it can be easy for a programmer to feel like they are always playing catch-up and that they are not as knowledgeable as their peers.&lt;/p&gt;

&lt;p&gt;Another factor is the high standards that are often placed on programmers. Many companies and clients have very specific requirements for the software and applications that they need, and it can be easy for a programmer to feel like they are not meeting these standards or that their work is not good enough.&lt;/p&gt;

&lt;p&gt;The effects of impostor syndrome can be significant, and they can include a lack of confidence, decreased motivation, and even burnout. In extreme cases, it can lead to depression and other mental health issues. In my case, it led to severe depression which affected my work and developed into a cycle because I could not perform as I wanted.&lt;/p&gt;

&lt;p&gt;Fortunately, there are steps that programmers can take to overcome impostor syndrome and build confidence in their abilities. One of the most important things is to recognize that impostor syndrome is a common experience and that it is not a reflection of a person's abilities or worth. It can be helpful to talk to other programmers and share experiences, as this can help to normalize the feelings of self-doubt and remind individuals that they are not alone.&lt;/p&gt;

&lt;p&gt;It can also be helpful to set realistic goals and expectations for oneself, and to celebrate small victories and accomplishments along the way. This can help to build confidence and remind individuals that they are making progress and improving their skills.&lt;/p&gt;

&lt;p&gt;Another effective strategy is to seek out feedback and support from mentors, colleagues, and other experienced programmers. This can provide valuable perspective and help individuals to see their strengths and accomplishments from a different perspective.&lt;/p&gt;

&lt;p&gt;Overall, impostor syndrome is a common experience among programmers, but it is important to recognize it and take steps to overcome it. By acknowledging and addressing these feelings, programmers can build confidence in their abilities and continue to grow and succeed in their field.&lt;/p&gt;

</description>
      <category>impostorsyndome</category>
      <category>programming</category>
      <category>ai</category>
      <category>writing</category>
    </item>
    <item>
      <title>Continuous Deployment on Shared Hosting with GitHub Actions</title>
      <dc:creator>Madalitso Nyemba</dc:creator>
      <pubDate>Sun, 02 May 2021 09:32:46 +0000</pubDate>
      <link>https://dev.to/madalitsonyemba/continuous-deployment-on-shared-hosting-with-github-actions-5agi</link>
      <guid>https://dev.to/madalitsonyemba/continuous-deployment-on-shared-hosting-with-github-actions-5agi</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In this fast-paced world, where everything seems to be happening quickly, it is paramount for early as well as frequent deployment of websites/apps to keep up with the competition. There are various ways of deploying your web apps to your server but will shall be looking at how GitHub actions can help us continuously deploy our web app with minimal effort. &lt;/p&gt;

&lt;h2&gt;
  
  
  What is Continuous Deployment
&lt;/h2&gt;

&lt;p&gt;First of all, what is continuous deployment you ask? According to &lt;a href="https://searchitoperations.techtarget.com/definition/continuous-deployment" rel="noopener noreferrer"&gt;Search IT operations&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Continuous deployment is a strategy for software releases wherein any code commit that passes the automated testing phase is automatically released into the production environment, making changes that are visible to the software's users.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We will not cover tests in this post (but in a later post). As you can see from the definition, simply commit and then all your changes are on the production server.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Shared Hosting
&lt;/h2&gt;

&lt;p&gt;There are different hosting choices with the popular ones now being shared hosting and cloud hosting. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A shared web hosting service is a web hosting service where many websites reside on one web server connected to the Internet.&lt;br&gt;
This is the cheapest way to host your website since the different users split the cost of the web server but it also has drawbacks since the resources are split across a number of users as well.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I have been using shared hosting for a long time and I got bored with transferring my files via FTP every time I made changes. I then resorted to using &lt;a href="https://github.com/" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; where I pushed my code to the repo then pulled it from my shared hosting. I still was not satisfied. I used &lt;a href="https://github.com/git-ftp/git-ftp/blob/master/man/git-ftp.1.md" rel="noopener noreferrer"&gt;GitFtp&lt;/a&gt; which was alright. Until I learned about CI/CD in my &lt;a href="https://azubiafrica.org/" rel="noopener noreferrer"&gt;Azubi Africa&lt;/a&gt; class.&lt;/p&gt;

&lt;h2&gt;
  
  
  GitHub Actions to the rescue
&lt;/h2&gt;

&lt;p&gt;After further research, came across GitHub actions. According to their &lt;a href="https://docs.github.com/en/actions" rel="noopener noreferrer"&gt;site&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Automate, customize, and execute your software development workflows right in your repository with GitHub Actions. You can discover, create, and share actions to perform any job you'd like, including CI/CD, and combine actions in a completely customized workflow.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The Workflow
&lt;/h2&gt;

&lt;p&gt;Let us get to the juicy bit by doing some actual work.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting up GitHub actions
&lt;/h3&gt;

&lt;p&gt;(This is assuming you already have a repository in your GitHub account that you want to link to your shared hosting. if not, click &lt;a href="https://docs.github.com/en/github/getting-started-with-github/create-a-repo" rel="noopener noreferrer"&gt;here&lt;/a&gt;).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Open your repository on GitHub and head over to &lt;code&gt;Actions&lt;/code&gt; tab.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3nz2r7n2ol9lmdoufieb.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3nz2r7n2ol9lmdoufieb.PNG" title="Press the actions tab" alt="Actions tab"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click on the &lt;code&gt;set up a workflow yourself →&lt;/code&gt; as shown below.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa75hv8mivxjewwrx3z6o.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa75hv8mivxjewwrx3z6o.PNG" title="Press the set up a workflow yourself" alt="Set up workflow yourself"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Delete all the contents of main.yml on the page as shown below:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzh0zns1emgnoflkerjip.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzh0zns1emgnoflkerjip.PNG" title="Delete all contents in the main.yml file" alt="Delete contents"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Replace the file with below contents (note this is for a project in Laravel with a Vue frontend)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

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

&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy Site on push&lt;/span&gt;
&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;master&lt;/span&gt;
&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;web-deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Get the latest code&lt;/span&gt;
      &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v2.3.2&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@master&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Installing project dependencies&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm install&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Building the project&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm run production&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Copy .env&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;php -r "file_exists('.env') || copy('.env.example', '.env');"&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install Dependencies&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;composer update --ignore-platform-reqs&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Generate key&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;php artisan key:generate&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Directory Permissions&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;chmod -R 777 storage bootstrap/cache&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;📂 Sync files&lt;/span&gt;
      &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;SamKirkland/FTP-Deploy-Action@4.0.0&lt;/span&gt;
      &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;server&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.LARAVEL_SITE_SERVER}}&lt;/span&gt;
        &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.LARAVEL_SITE_USER}}&lt;/span&gt;
        &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.LARAVEL_SITE_PASS}}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Let me now explain block by block what is going on&lt;/p&gt;

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

&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy Site on push&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;This is the name of the workflow. GitHub displays the names of your workflows on your repository’s actions page after you write it.&lt;/p&gt;

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

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;master&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;This is where the GitHub action system is told when to run the workflow. The above snippet triggers the workflow when one pushes to the &lt;code&gt;master branch&lt;/code&gt;. For more on the On key, click &lt;a href="https://docs.github.com/en/actions/learn-github-actions/introduction-to-github-actions#:~:text=GitHub%20Actions%20are%20event%2Ddriven,executes%20a%20software%20testing%20script." rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;

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

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;web-deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;&lt;em&gt;jobs&lt;/em&gt; - Groups together all the jobs that run in the workflow file.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;web-deploy&lt;/em&gt; - Defines the name of the web-deploy job stored within the jobs section.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;runs-on: ubuntu-latest&lt;/em&gt; - Configures the job to run on an Ubuntu Linux runner. This means that the job will execute on a fresh virtual machine hosted by GitHub.&lt;/p&gt;

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

&lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Get the latest code&lt;/span&gt;
      &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v2.3.2&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@master&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Installing project dependencies&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm install&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Building the project&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm run production&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;&lt;em&gt;Remember that the steps are inside the job block.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;steps&lt;/em&gt; - Groups together all the steps that run in the web-deploy job. Each item nested under this section is a separate action or shell command.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;name&lt;/em&gt; - For identification of the separate action.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;uses: actions/&lt;a href="mailto:checkout@v2.3.2"&gt;checkout@v2.3.2&lt;/a&gt;&lt;/em&gt; - The uses keyword tells the job to retrieve v2 of the community action named actions/&lt;a href="mailto:checkout@v2.3.2"&gt;checkout@v2.3.2&lt;/a&gt;. This is an action that checks out your repository and downloads it to the runner, allowing you to run actions against your code (such as testing tools). You must use the checkout action any time your workflow will run against the repository's code or you are using an action defined in the repository.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;uses: actions/setup-node@master&lt;/em&gt; - This action installs the node software package on the runner, giving you access to the npm command.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;run: npm install&lt;/em&gt; - The run keyword tells the job to execute a command on the runner. In this case, you are using npm to install the package node dependecies.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;run: npm run production&lt;/em&gt; - This builds the Vue frontend project.&lt;/p&gt;

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


&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Copy .env&lt;/span&gt;
      &lt;span class="s"&gt;run&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s"&gt;php -r "file_exists('.env') || copy('.env.example', '.env');"&lt;/span&gt;
    &lt;span class="s"&gt;- name&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Setup PHP&lt;/span&gt;
      &lt;span class="s"&gt;uses&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s"&gt;shivammathur/setup-php@v2&lt;/span&gt;
      &lt;span class="s"&gt;with&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;php-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;8.0'&lt;/span&gt;
  &lt;span class="err"&gt;  &lt;/span&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install Dependencies&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;composer update --ignore-platform-reqs&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Generate key&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;php artisan key:generate&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Directory Permissions&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;chmod -R 777 storage bootstrap/cache&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;&lt;em&gt;run: php -r "file_exists('.env') || copy('.env.example', '.env');&lt;/em&gt; - This creates a .env file if it does not already exist (this is important as this is automatically added to the .gitignore file).&lt;/p&gt;

&lt;p&gt;&lt;em&gt;run: composer update --ignore-platform-reqs&lt;/em&gt; - This is used to install and update the composer packages.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;run: php artisan key:generate&lt;/em&gt; - This generates a key for the Laravel project.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;run: chmod -R 777 storage bootstrap/cache&lt;/em&gt; - This changes permissions for the specified folder.&lt;/p&gt;

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

&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;📂 Sync files&lt;/span&gt;
      &lt;span class="s"&gt;uses&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s"&gt;SamKirkland/FTP-Deploy-Action@4.0.0&lt;/span&gt;
      &lt;span class="s"&gt;with&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;server&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.LARAVEL_SITE_SERVER}}&lt;/span&gt;
        &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.LARAVEL_SITE_USER}}&lt;/span&gt;
        &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.LARAVEL_SITE_PASS}}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;This is where the files are now transferred to the shared hosting server. Get your FTP details from your &lt;a href="https://docs.cpanel.net/cpanel/files/ftp-accounts/" rel="noopener noreferrer"&gt;shared hosting&lt;/a&gt;. Then go to &lt;code&gt;your repo&amp;gt;settings&amp;gt;secrets&lt;/code&gt; then add the three secrets namely: server, username and then password. This action is courtesy of &lt;a href="https://github.com/SamKirkland/FTP-Deploy-Action" rel="noopener noreferrer"&gt;SamKirkland&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For more information on GitHub actions, &lt;a href="https://docs.github.com/en/actions/learn-github-actions/introduction-to-github-actions#:~:text=GitHub%20Actions%20are%20event%2Ddriven,executes%20a%20software%20testing%20script." rel="noopener noreferrer"&gt;click here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Enjoy 😎&lt;/p&gt;

</description>
      <category>github</category>
      <category>laravel</category>
      <category>devops</category>
      <category>vue</category>
    </item>
  </channel>
</rss>
