<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Omar Mohammad on Medium]]></title>
        <description><![CDATA[Stories by Omar Mohammad on Medium]]></description>
        <link>https://medium.com/@omarmohammad_89249?source=rss-96c30bc85ee5------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/proxy/1*TGH72Nnw24QL3iV9IOm4VA.png</url>
            <title>Stories by Omar Mohammad on Medium</title>
            <link>https://medium.com/@omarmohammad_89249?source=rss-96c30bc85ee5------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Mon, 08 Jun 2026 05:35:53 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@omarmohammad_89249/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[Installing Phoenix]]></title>
            <link>https://medium.com/@omarmohammad_89249/installing-phoenix-d9eef65df9bf?source=rss-96c30bc85ee5------2</link>
            <guid isPermaLink="false">https://medium.com/p/d9eef65df9bf</guid>
            <category><![CDATA[erlang]]></category>
            <category><![CDATA[elixir]]></category>
            <category><![CDATA[phoenix]]></category>
            <dc:creator><![CDATA[Omar Mohammad]]></dc:creator>
            <pubDate>Sun, 26 Apr 2026 05:00:45 GMT</pubDate>
            <atom:updated>2026-04-27T18:12:37.125Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*vaH4iRmQNOLEX3PKy9M5zQ.png" /></figure><p>Explore the step-by-step process to install Phoenix along with Erlang and Elixir on your system. Understand the prerequisites and verify installations to prepare your environment for building real-time applications using Phoenix.</p><p>The following components should be installed on your system to run Phoenix applications locally.</p><ul><li>Erlang</li><li>Elixir</li><li>Phoenix</li></ul><h3>Installing Erlang</h3><p>To install the Phoenix we need to install the Erlang. Erlang can be installed by running the following commands in our terminal:</p><pre>apt-get update <br>apt-get install -y wget <br>rm -rf /var/lib/apt/lists/* <br>wget https://packages.erlang-solutions.com/erlang-solutions_2.0_all.deb &amp;&amp;\<br>    dpkg -i erlang-solutions_2.0_all.deb || true<br>ARG DEBIAN_FRONTEND=noninteractive</pre><p>Mac</p><pre>brew update<br>brew install erlang</pre><p>Erlang will be installed on our system.</p><h3>Installing Elixir</h3><p>We also need to install the Elixir to install Phoenix. Elixir can be installed by the following commands.</p><pre>apt-get update &amp;&amp;\<br>apt-get install -y erlang &amp;&amp;\<br>apt-get install elixir</pre><p>Elixir will be installed on our system.</p><h3>Installing Phoenix</h3><p>Before installing Phoenix, first, install local.hex as it is required to install Phoenix.</p><pre>mix local.hex --force</pre><p>To check the version of Elixir and Erlang, run the following:</p><pre>elixir -v</pre><p>After verifying the versions, install Phoenix by running the following command:</p><pre>mix archive.install hex phx_new 1.5.9 --force</pre><p>Phoenix will now be installed on our system.</p><p>Verify Phoenix version.</p><pre>mix phx.new --version</pre><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=d9eef65df9bf" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Install Kafka and Zookeeper on WSL Ubuntu]]></title>
            <link>https://medium.com/@omarmohammad_89249/install-kafka-and-zookeeper-on-wsl-ubuntu-30074880d601?source=rss-96c30bc85ee5------2</link>
            <guid isPermaLink="false">https://medium.com/p/30074880d601</guid>
            <category><![CDATA[kafka]]></category>
            <category><![CDATA[wsl-2]]></category>
            <category><![CDATA[ubuntu]]></category>
            <category><![CDATA[zookeeper]]></category>
            <dc:creator><![CDATA[Omar Mohammad]]></dc:creator>
            <pubDate>Fri, 31 Jan 2025 19:18:40 GMT</pubDate>
            <atom:updated>2025-01-31T20:40:45.351Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="Cover Image" src="https://cdn-images-1.medium.com/max/1024/1*DRWNNibpIy_XL-czlpaJeg.jpeg" /><figcaption>An AI model’s rendition of a prompt about the subject</figcaption></figure><h3>To install and run Kafka and Zookeeper, you’ll need to follow a series of steps. Here’s a detailed guide:</h3><h3>Step 1: Install Java</h3><p>Kafka requires Java to be installed on your machine. If you don’t have Java installed, you can install it using the following command:</p><pre>sudo apt update<br>sudo apt install openjdk-11-jdk</pre><h3>Step 2: Download Kafka</h3><p>The latest version of Kafka can be downloaded from the <a href="https://kafka.apache.org/downloads">official website</a>.</p><h3>Step 3: Extract Kafka Files</h3><p>Extract the downloaded files to the desired location on WSL Ubuntu.</p><pre>tar -zvzf &lt;downloaded_file.tgz&gt;</pre><h3>Step 4: Start Zookeeper</h3><p>Zookeeper is used by Kafka to manage and coordinate the Kafka brokers. To start Zookeeper, navigate to the Kafka directory and run the following command:</p><pre>bin/zookeeper-server-start.sh config/zookeeper.properties</pre><p>This will start Zookeeper using the default configuration.</p><h3>Step 5: Start Kafka Broker</h3><p>Once Zookeeper is running, you can start the Kafka broker. Open a new terminal window, navigate to the Kafka directory, and run:</p><pre>bin/kafka-server-start.sh config/server.properties</pre><p>This will start the Kafka broker with the default configuration.</p><h3>Step 6: Create a Topic</h3><p>You need to create a topic to start sending messages to Kafka. Run the following command to create a topic named test with a single partition and one replica:</p><pre>bin/kafka-topics.sh --create --topic test --bootstrap-server localhost:9092 --partitions 1 --replication-factor 1</pre><h3>Step 7: Start a Producer</h3><p>Now, you can start a Kafka producer to send messages to the topic test. Run the following command:</p><pre>bin/kafka-console-producer.sh --topic test --bootstrap-server localhost:9092</pre><p>Type some messages and press Enter to send them.</p><h3>Step 8: Start a Consumer</h3><p>To read messages from the topic test, you can start a Kafka consumer. Open a new terminal window and run:</p><pre>bin/kafka-console-consumer.sh --topic test --from-beginning --bootstrap-server localhost:9092</pre><p>You should see the messages you typed in the producer terminal.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Z3nQlq4Yf-UtRMkRAphuig.png" /></figure><p>And there you have it! You’ve successfully installed and set up Kafka and Zookeeper.</p><h3>Stopping Zookeeper</h3><p>To stop the Zookeeper server, you can use the following command:</p><pre>bin/zookeeper-server-stop.sh</pre><p>This will shut down the Zookeeper instance gracefully.</p><h3>Stopping the Kafka Broker</h3><p>To stop the Kafka broker, you can use this command:</p><pre>bin/kafka-server-stop.sh</pre><p>This command will shut down the Kafka broker gracefully.</p><h3>Stopping the Producer and Consumer</h3><p>If you started the Kafka producer and consumer using the console commands, you can stop them by simply closing the terminal windows where they are running, or by using Ctrl + C in the terminal.</p><h3>Closing a Topic</h3><p>You don’t need to “close” a topic explicitly. Topics in Kafka are persistent unless you delete them. If you wish to delete a topic, you can do so with the following command:</p><pre>bin/kafka-topics.sh --delete --topic your_topic_name --bootstrap-server localhost:9092</pre><p>Replace your_topic_name with the name of the topic you want to delete.</p><p>Following these steps will ensure all components of your Kafka setup are stopped. If you have any other questions or need further assistance, feel free to ask!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=30074880d601" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Rails 7: Fix Tailwindcss Installation]]></title>
            <link>https://medium.com/@omarmohammad_89249/rails-7-fix-tailwindcss-installation-daee70428498?source=rss-96c30bc85ee5------2</link>
            <guid isPermaLink="false">https://medium.com/p/daee70428498</guid>
            <category><![CDATA[hotwire-rails]]></category>
            <category><![CDATA[esbuild]]></category>
            <category><![CDATA[tailwind-css]]></category>
            <category><![CDATA[rails]]></category>
            <dc:creator><![CDATA[Omar Mohammad]]></dc:creator>
            <pubDate>Sat, 24 Feb 2024 18:13:20 GMT</pubDate>
            <atom:updated>2024-02-24T18:13:20.911Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/300/1*E-mipXJLzxU4uiPbVWBzWg.jpeg" /></figure><p><strong>I forgot to add esbuild installation while scaffolding as follows:-</strong></p><pre>rails new aap-name -d postgresql - css=tailwind</pre><p>Due to this reason, the application was not being styled properly. To fix this, I took the following steps.</p><p>Adding esbuild to a Rails application can help speed up your JavaScript builds. Here’s how you can do it:</p><ol><li>Add the “jsbundling-rails” gem to your Gemfile:</li></ol><pre>gem &#39;jsbundling-rails&#39;</pre><p>2. Then, run the `bundle install` command to install the gem.</p><p>3. Then create a package.json file and add the following dependencies.</p><pre>npm i @hotwired/turbo-rails<br>npm i @hotwired/stimulus<br>npm i @hotwired/stimulus-webpackers-helpers</pre><p>3. Create a file esbuild.js in the config folder.</p><pre>require(&#39;esbuild&#39;).build({ <br> entryPoints: [&#39;app/javascript/application.js&#39;], <br> bundle: true, <br> outdir: &#39;app/assets/builds&#39;, <br> sourcemap: true, <br> external: [&#39;@hotwired/turbo-rails&#39;, &#39;controllers&#39;], <br>}).catch(() =&gt; process.exit(1))</pre><p>4. Then, you should import your stimulus controllers in your `app/javascript/application.js` something like this:</p><pre>import { Application } from &quot;@hotwired/stimulus&quot; <br>import { definitionsFromContext } from &quot;@hotwired/stimulus-webpack-helpers&quot;<br>const application = Application.start() <br>const context = require.context(&quot;./controllers&quot;, true, /\.js$/) <br>application.load(definitionsFromContext(context))</pre><p>5. Now, run the following command to set up esbuild:</p><pre>./bin/rails javascript:install:esbuild</pre><p>6. Now, you need to set up your package.json. Add these scripts to the “scripts” section in your package.json file:</p><pre>&quot;scripts&quot;: { <br> &quot;build&quot;: &quot;esbuild app/javascript/application.js - bundle - sourcemap - outdir=app/assets/builds&quot;, <br> &quot;watch&quot;: &quot;esbuild app/javascript/application.js - bundle - sourcemap - outdir=app/assets/builds - watch&quot; <br>}</pre><p>7. To compile your JavaScript, you can now use the command `npm run build`. If you want your JavaScript to automatically compile whenever you make changes, use `npm run watch` instead.</p><p>8. Finally, you need to include the compiled JavaScript in your application layout. In `app/views/layouts/application.html.erb`, add the following line:</p><pre>&lt;%= javascript_include_tag &#39;application&#39;, &quot;data-turbolinks-track&quot;: &quot;reload&quot; %&gt;</pre><p>Now you have added esbuild to your Rails application. Be sure to put your JavaScript code in `app/javascript/application.js` or import it from there. The `npm run build` or `npm run watch` commands will then compile your JavaScript and place it in `app/assets/builds/application.js` where it can be included in your layout.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=daee70428498" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Cloud Native Computing]]></title>
            <link>https://medium.com/@omarmohammad_89249/cloud-native-computing-caa516a4b525?source=rss-96c30bc85ee5------2</link>
            <guid isPermaLink="false">https://medium.com/p/caa516a4b525</guid>
            <category><![CDATA[microservices]]></category>
            <category><![CDATA[docker]]></category>
            <category><![CDATA[cloud-security]]></category>
            <category><![CDATA[kubernetes]]></category>
            <category><![CDATA[cloud-native]]></category>
            <dc:creator><![CDATA[Omar Mohammad]]></dc:creator>
            <pubDate>Thu, 16 Nov 2023 11:04:03 GMT</pubDate>
            <atom:updated>2023-11-16T11:04:03.625Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*iKfOsbffOgkVpIK_jA7Lmw.jpeg" /></figure><h3>Introduction to Cloud Native Computing</h3><p>Cloud Native is a blueprint for building web-scale applications on the cloud that are more available and scalable. It promises increased agility to ship new features quickly without compromising availability, making it quicker to respond to changing customer demands. Cloud Computing is running applications on computing resources managed by cloud providers. Migrating an existing monolithic application from on-premise to the cloud frees the team from managing hardware infrastructure. For an application to be considered Cloud Native, there are at least 4 pillars to consider: application architecture, containers and container orchestration, development process, and platform primitives. Cloud Native offers benefits such as increased scalability, improved availability, and faster time to market.</p><h3>Containerization and Orchestration</h3><p>Docker containers provide a lightweight and efficient way to package and deploy applications. With containerization, developers can easily isolate their applications, making them more portable and scalable. Docker containers have revolutionized the way software is developed, deployed, and scaled in modern-day IT infrastructure. Developers can easily isolate their applications, making them more portable and scalable. Embracing containerization empowers teams to build, test, and deploy applications swiftly, fostering innovation and agility in the ever-evolving work landscape.”</p><p>Kubernetes is an open-source container orchestration platform that automates the deployment, scaling, and management of containerized applications. The name Kubernetes is abbreviated as k8s, with the 8 representing the number of letters between the first and last letter in the word. A Kubernetes cluster consists of control plane nodes and worker nodes, where the control plane manages the state of the cluster and the worker nodes run the containerized application workloads. The control plane includes core components such as the API server, etcd, scheduler, and controller manager. The worker nodes include components like the kubelet, container runtime, and kube-proxy. These components work together to ensure the proper functioning of the Kubernetes cluster.</p><h3>Microservices</h3><p>Microservices architecture enables large teams to build scalable applications composed of loosely coupled services. Each microservice handles a dedicated function and communicates with other microservices via well-defined interfaces. Microservices can be independently deployed and provide flexibility in scaling. However, breaking up the database poses a challenge in maintaining data integrity. Other critical components include API gateway, identity provider service, and service registry. Microservices architecture is suitable for large teams as it enables team independence and fast development. It may not be suitable for small startups due to the overhead involved.</p><h3>Monitoring and Logging in Cloud Native Computing</h3><p>Fluentd is an open source log data collector that helps address the challenges of collecting and consuming application logs. It allows for easy analysis and visualization of log data by providing a unified interface and format for logs from different applications and data sources. Applications can log data to files, but this makes analysis difficult without proper visualization. Logging directly into a log database like Elastic requires each application developer to add a library and configure it, posing additional challenges. Fluentd solves these challenges by providing a centralized solution for collecting logs from various sources in a unified format. It allows you to collect logs from third-party applications, system logs, and even requests that go through Nginx controller in a Kubernetes cluster. By consolidating all logs in one place, Fluentd enables efficient analysis and debugging of complex applications with tons of useful data.</p><h3>Security and Cloud Native Computing</h3><p>A cloud environment typically consists of standard workloads like application and database instances, as well as object storage. Bad actors target cloud environments to gain access, exfiltrate information, or cause disruption. They often exploit weak configurations, such as static passwords and lack of two-factor authentication. Public exposure of unencrypted data in object storage buckets is another common misconfiguration. Additionally, database instances, which should only be exposed to app or web instances, are sometimes found exposed to the internet, making them susceptible to brute force attacks. These misconfigurations pose security risks, and it’s crucial to monitor for suspicious behaviors to detect potential malicious activities. CloudTrail in AWS is an example of a tool that can help identify such behaviors. If the logging for CloudTrail gets disabled, it would be necessary to investigate whether it was done by a bad actor before any malicious activity occurs.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=caa516a4b525" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How to Install Node.js from the Node.js binary for Linux.]]></title>
            <link>https://medium.com/@omarmohammad_89249/how-to-install-node-js-from-the-node-js-binary-for-linux-2ca9e0de6700?source=rss-96c30bc85ee5------2</link>
            <guid isPermaLink="false">https://medium.com/p/2ca9e0de6700</guid>
            <category><![CDATA[node]]></category>
            <category><![CDATA[npm]]></category>
            <category><![CDATA[bash]]></category>
            <category><![CDATA[linux]]></category>
            <dc:creator><![CDATA[Omar Mohammad]]></dc:creator>
            <pubDate>Fri, 01 Sep 2023 00:54:29 GMT</pubDate>
            <atom:updated>2023-09-01T00:54:29.493Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1000/1*3pPJQKaUEdqQUjkWge0M3g.png" /><figcaption>Node.js</figcaption></figure><p>Copy the link of the nodejs binary and use wget in the terminal to download it or simply click on the download link from the official node.js website.</p><p>Move to the downloads directory or the directory where the above has been downloaded and extract its contents using the following replacing the filename.tar.xz with the actual name of the downloaded file.</p><pre>tar -xvf filename.tar.xz</pre><p>The options used in the command are as follows:</p><ul><li>-x: Extract files from the archive.</li><li>-v: Display verbose output, showing the extracted files.</li><li>-f: Specifies the input file.</li></ul><p>Navigate into the extracted directory and copy its contents to the /usr/local directory.</p><pre>cd extracted_folder<br>sudo cp -r * /usr/local/</pre><p>Add Node.js to the Path.</p><pre>nano ~/.bashrc<br>export PATH=&quot;/usr/local/bin:$PATH&quot;<br>source ~/.bashrc</pre><p>Verify the installation.</p><pre>node -v<br>npm -v</pre><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=2ca9e0de6700" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Toast Notifications with Tailwind and Stimulus | Ruby on Rails 7]]></title>
            <link>https://medium.com/@omarmohammad_89249/toast-notifications-with-tailwind-and-stimulus-ruby-on-rails-7-7c0f86ddce01?source=rss-96c30bc85ee5------2</link>
            <guid isPermaLink="false">https://medium.com/p/7c0f86ddce01</guid>
            <category><![CDATA[tailwind-css]]></category>
            <category><![CDATA[ruby-on-rails]]></category>
            <category><![CDATA[flowbite]]></category>
            <category><![CDATA[esbuild]]></category>
            <dc:creator><![CDATA[Omar Mohammad]]></dc:creator>
            <pubDate>Sun, 16 Apr 2023 23:27:34 GMT</pubDate>
            <atom:updated>2023-04-17T07:54:20.104Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*kaouLN_G2ED7A27sELkaWw.jpeg" /><figcaption>Courtesy of Bing Image Creator</figcaption></figure><p>Let’s create a new ruby on rails applications with esbuild and tailwind css. Generate a scaffold for posts entity and files related to adding notifications using the Stimulus framework.</p><pre>rails new toast_notifications -j esbuild -c tailwind<br>cd toast_notifications<br>rails g scaffold post title text:string<br>rails g stimulus notifications</pre><p>Next we add a gem named ‘Foreman’ that helps manage Procfile-based applications. <a href="https://github.com/ddollar/foreman">It allows you to declare the various processes that are used in your application (such as web processes and worker processes) in a Procfile, and then use Foreman to manage these processes</a>.</p><pre>gem &#39;foreman&#39;, github: &#39;ddollar/foreman&#39;<br>bundle i</pre><p>Then we add Flowbite, an open-source library of UI components based on the utility-first Tailwind CSS framework. It features dark mode support, a Figma design system, templates, and more. Flowbite provides a robust set of design tokens and components based on the popular Tailwind CSS framework. <a href="https://flowbite.com/">From the most used UI components like forms and navigation bars to whole app screens designed for both desktop and mobile, this UI kit provides a solid foundation for any project</a>.</p><p><a href="https://flowbite.com/docs/getting-started/quickstart/">Flowbite - Quickstart</a></p><pre><br>&lt;link href=&quot;https://cdnjs.cloudflare.com/ajax/libs/flowbite/1.6.5/flowbite.min.css&quot; rel=&quot;stylesheet&quot; /&gt;<br>&lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/flowbite/1.6.5/flowbite.min.js&quot;&gt;&lt;/script&gt;</pre><p>Create a new shared view with the name of _notifications.html.erb and add the following code in it from flowbite components’ documentation for toasts.</p><p><a href="https://flowbite.com/docs/components/toast/">https://flowbite.com/docs/components/toast/</a></p><pre># app/views/shared/_notifications.html.erb<br>&lt;% if message %&gt;<br>&lt;div id=&quot;toast-success&quot; class=&quot;absolute bottom-5 right-5 flex items-center w-full max-w-xs p-4 mb-4 text-gray-500 bg-white rounded-lg shadow dark:text-gray-400 dark:bg-gray-800&quot; role=&quot;alert&quot;&gt;<br>    &lt;div class=&quot;inline-flex items-center justify-center flex-shrink-0 w-8 h-8 text-green-500 bg-green-100 rounded-lg dark:bg-green-800 dark:text-green-200&quot;&gt;<br>        &lt;svg aria-hidden=&quot;true&quot; class=&quot;w-5 h-5&quot; fill=&quot;currentColor&quot; viewBox=&quot;0 0 20 20&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z&quot; clip-rule=&quot;evenodd&quot;&gt;&lt;/path&gt;&lt;/svg&gt;<br>        &lt;span class=&quot;sr-only&quot;&gt;Check icon&lt;/span&gt;<br>    &lt;/div&gt;<br>    &lt;div class=&quot;ml-3 text-sm font-normal&quot;&gt;&lt;%= message %&gt;&lt;/div&gt;<br>    &lt;button type=&quot;button&quot; class=&quot;ml-auto -mx-1.5 -my-1.5 bg-white text-gray-400 hover:text-gray-900 rounded-lg focus:ring-2 focus:ring-gray-300 p-1.5 hover:bg-gray-100 inline-flex h-8 w-8 dark:text-gray-500 dark:hover:text-white dark:bg-gray-800 dark:hover:bg-gray-700&quot; data-dismiss-target=&quot;#toast-success&quot; aria-label=&quot;Close&quot;&gt;<br>        &lt;span class=&quot;sr-only&quot;&gt;Close&lt;/span&gt;<br>        &lt;svg aria-hidden=&quot;true&quot; class=&quot;w-5 h-5&quot; fill=&quot;currentColor&quot; viewBox=&quot;0 0 20 20&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z&quot; clip-rule=&quot;evenodd&quot;&gt;&lt;/path&gt;&lt;/svg&gt;<br>    &lt;/button&gt;<br>&lt;/div&gt;<br>&lt;% end %&gt;</pre><p>Note that the message has been further customized with the addition if condition along with its positioning.</p><p>After that, render the partial view by adding the following line above ≤% yield %&gt; in application.html.erb.</p><pre>&lt;%= render partial: &quot;shared/notifications&quot;, locals: { message: flash[:notice] } %&gt;<br>&lt;%= yield %&gt;</pre><p>Run bin/dev. Create &amp; run pending migrations and create a new post.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*FVS8rf2UBCtqAv5W5TlFtw.png" /></figure><p>Now, our message is being displayed quite nicely, however, to make it disappear, we will have to add the stimulus-notification dependency which is a stimulus controller for showing notifications.</p><p><a href="https://www.stimulus-components.com/docs/stimulus-notification">https://www.stimulus-components.com/docs/stimulus-notification</a></p><pre>npm i stimulus-notification</pre><p>We make use of inheritance to extend the functionality of any Stimulus Component by changing the content of notifications_controller.js as follows.</p><pre>import Notification from &#39;stimulus-notification&#39;<br><br>export default class extends Notification {<br>  connect() {<br>    super.connect()<br>    console.log(&#39;Do what you want here.&#39;)<br>  }<br>}</pre><p>Finally in our view, we add data-controller properties to our div element.</p><pre># app/views/shared/_notifications.html.erb<br>&lt;% if message %&gt;<br>&lt;div id=&quot;toast-success&quot;<br>     class=&quot;transition transform duration-1000 absolute bottom-5 right-5 flex items-center w-full max-w-xs p-4 mb-4 text-gray-500 bg-white rounded-lg shadow dark:text-gray-400 dark:bg-gray-800&quot; <br>     role=&quot;alert&quot;<br>     data-controller=&quot;notifications&quot;<br>     data-notification-hidden-value=&quot;true&quot;<br>     data-transition-enter-from=&quot;opacity-0 translate-x-6&quot;<br>     data-transition-enter-to=&quot;opacity-100 translate-x-0&quot;<br>     data-transition-leave-from=&quot;opacity-100 translate-x-0&quot;<br>     data-transition-leave-to=&quot;opacity-0 translate-x-6&quot;<br><br>     &gt;<br>    &lt;div class=&quot;inline-flex items-center justify-center flex-shrink-0 w-8 h-8 text-green-500 bg-green-100 rounded-lg dark:bg-green-800 dark:text-green-200&quot;&gt;<br>        &lt;svg aria-hidden=&quot;true&quot; class=&quot;w-5 h-5&quot; fill=&quot;currentColor&quot; viewBox=&quot;0 0 20 20&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z&quot; clip-rule=&quot;evenodd&quot;&gt;&lt;/path&gt;&lt;/svg&gt;<br>        &lt;span class=&quot;sr-only&quot;&gt;Check icon&lt;/span&gt;<br>    &lt;/div&gt;<br>    &lt;div class=&quot;ml-3 text-sm font-normal&quot;&gt;&lt;%= message %&gt;&lt;/div&gt;<br>    &lt;button type=&quot;button&quot; data-action=&quot;notifications#hide&quot; class=&quot;ml-auto -mx-1.5 -my-1.5 bg-white text-gray-400 hover:text-gray-900 rounded-lg focus:ring-2 focus:ring-gray-300 p-1.5 hover:bg-gray-100 inline-flex h-8 w-8 dark:text-gray-500 dark:hover:text-white dark:bg-gray-800 dark:hover:bg-gray-700&quot; data-dismiss-target=&quot;#toast-success&quot; aria-label=&quot;Close&quot;&gt;<br>        &lt;span class=&quot;sr-only&quot;&gt;Close&lt;/span&gt;<br>        &lt;svg aria-hidden=&quot;true&quot; class=&quot;w-5 h-5&quot; fill=&quot;currentColor&quot; viewBox=&quot;0 0 20 20&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z&quot; clip-rule=&quot;evenodd&quot;&gt;&lt;/path&gt;&lt;/svg&gt;<br>    &lt;/button&gt;<br>&lt;/div&gt;<br>&lt;% end %&gt;</pre><p>Now, we have sliding notifications to go along with our rails notices which vanish automatically after the lapse of one second.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=7c0f86ddce01" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[ChatGPT clone with OpenAi API]]></title>
            <link>https://medium.com/@omarmohammad_89249/chatgpt-clone-with-openai-api-7b8a515c3763?source=rss-96c30bc85ee5------2</link>
            <guid isPermaLink="false">https://medium.com/p/7b8a515c3763</guid>
            <category><![CDATA[chatgpt]]></category>
            <category><![CDATA[build]]></category>
            <category><![CDATA[openai]]></category>
            <category><![CDATA[clone-scripts]]></category>
            <dc:creator><![CDATA[Omar Mohammad]]></dc:creator>
            <pubDate>Mon, 10 Apr 2023 18:27:58 GMT</pubDate>
            <atom:updated>2023-04-10T18:27:58.518Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/512/1*WeHoiflV3uebaqYD-9rvNw.png" /><figcaption>ChatGPT clone</figcaption></figure><pre>!pip install - upgrade pip<br>!pip install openai</pre><p>Create an account on beta.openai.com and generate an api key. Save the api key in a variable as follows:-</p><pre>OPENAI_API_KEY = &quot;**********************************************&quot;</pre><p>Import the OpenAI library and set the API key required to access OpenAI resources.</p><pre>import openai<br>openai.api_key = OPENAI_API_KEY</pre><p>Define a function named “chat” that uses the GPT-3.5 model to generate a response to a user’s question. The consolidated code should look like as follows:-</p><pre>import openai<br>OPENAI_API_KEY = &quot;**********************************************&quot;<br>openai.api_key = OPENAI_API_KEY<br><br>def chat(question):<br>  response = openai.ChatCompletion.create(<br>      model = &quot;gpt-3.5-turbo&quot;,<br>      messages = [<br>          {<br>              &quot;role&quot;: &quot;user&quot;,<br>              &quot;content&quot;: question<br>          }<br>      ]<br>  )<br><br>  return response</pre><p>Save the response in a variable and print it as follows.</p><pre>response = chat(&quot;Write a poem on Python&#39;s zen ?&quot;)<br>answer = response.choices[0].message.content<br>print(answer)</pre><blockquote>Python’s zen is a thing of grace,</blockquote><blockquote>A philosophy birthed in code’s embrace,</blockquote><blockquote>A set of rules to guide a way,</blockquote><blockquote>Ensuring elegance in every display.</blockquote><blockquote>This language of Monty’s creation,</blockquote><blockquote>A designer’s tool for exploration,</blockquote><blockquote>Embraces simplicity with ease,</blockquote><blockquote>Granting power to code with breeze.</blockquote><blockquote>It teaches us to strive for clarity,</blockquote><blockquote>In our coding, in our proclivity,</blockquote><blockquote>To craft programs that are readable,</blockquote><blockquote>Ensuring they’re reusable, and not disposable.</blockquote><blockquote>Beautiful code is art in motion,</blockquote><blockquote>And Python’s zen is the ultimate potion,</blockquote><blockquote>To bring forth the best in our design,</blockquote><blockquote>And write solutions that are sublime.</blockquote><blockquote>So let’s embrace the Python way,</blockquote><blockquote>And code with grace and skill each day,</blockquote><blockquote>For Python’s zen is the heart of it all,</blockquote><blockquote>And its magic weaves a lasting thrall.</blockquote><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=7b8a515c3763" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Rails7 Devise API Authentication]]></title>
            <link>https://medium.com/@omarmohammad_89249/rails7-devise-api-authentication-with-vue-js-2fcbab3e3fb8?source=rss-96c30bc85ee5------2</link>
            <guid isPermaLink="false">https://medium.com/p/2fcbab3e3fb8</guid>
            <dc:creator><![CDATA[Omar Mohammad]]></dc:creator>
            <pubDate>Sat, 11 Mar 2023 17:51:40 GMT</pubDate>
            <atom:updated>2023-03-21T16:16:23.944Z</atom:updated>
            <content:encoded><![CDATA[<p>Create a new rails api with postgresql as database.</p><pre>rails new devise-vue --api -T -d postgresql<br>cd devise-vue<br>bundle add devise devise-jwt rack-cors</pre><p>In the config/initializers/cors.rb file set the origins to all and expose the Authorization and Uid of the resource.</p><pre>Rails.application.config.middleware.insert_before 0, Rack::Cors do<br>  allow do<br>   #origins &quot;example.com&quot; # Replace this line with following<br>   origins &quot;*&quot;<br><br>    resource &quot;*&quot;,<br>      headers: :any,<br>      methods: [:get, :post, :put, :patch, :delete, :options, :head],<br>      # Add the following line<br>      expose: %w[Authorization Uid]<br>  end<br>end</pre><p>Install devise and generate default User.</p><pre>rails g devise:install<br>rails g devise User</pre><p>Generate Model jwt_denylist with jwt and exp columns.</p><pre>rails g model jwt_denylist jti:string exp:datetime</pre><p>Change the name of individual migration file db/migrate/………_create_jwt_denylists.rb as well as the table’s name contained therein to singular which was generated after the above mentioned command. Make the two columns ‘jti’ and ‘exp’ non-null by adding ‘null: false’ property and add index on column ‘jti’ rendering the aforementioned file as follows.</p><pre>#db/migrate/………_create_jwt_denylist.rb<br>class CreateJwtDenylist &lt; ActiveRecord::Migration[7.0]<br>  def change<br>    create_table :jwt_denylist do |t|<br>      t.string :jti, null: false<br>      t.datetime :exp, null: false<br><br>      t.timestamps<br>    end<br>    add_index :jwt_denylist, :jti<br>  end<br>end</pre><p>Remove recoverable, rememberable and validatable attribute from devise in the model app/models/user.rb and add jwt_authenticatable, jwt_revocation_strategy amd JwtDenylist attributes to the same. This will setup a way to log out a user or expire a user session by just inserting the token to deny the jwt, hence, the user itself ought not to be modified, a very nice alternative for logging out the user.</p><pre># app/models/user.rb<br>class User &lt; ApplicationRecord<br>  devise :database_authenticatable, :registerable,<br>         :jwt_authenticatable, jwt_revocation_strategy: JwtDenylist<br>end</pre><p>Link the Devise and JWT attributes in the jwt_denylist model.</p><pre># app/models/jwt_denylist.rb<br>class JwtDenylist &lt; ApplicationRecord<br>  include Devise::JWT::RevocationStrategies::Denylist<br>  <br>  self.table_name = &#39;jwt_denylist&#39;<br>end</pre><p>Next, create and migrate the database.</p><pre>rails db:create db:migrate</pre><p>Now, create the members controller which shows the information if a user is logged in.</p><pre>#app/models/members_controller.rb<br><br>class MembersController &lt; ApplicationControler<br>  before_action :authenticate_user!<br><br>  def show<br>    user = get_user_from_token<br>    render json: {<br>      message: &quot;If you see this, you&#39;re in&quot;,<br>      user: user<br>    }<br>    end<br><br>    private<br><br>    def get_user_from_token<br>      jwt_payload = JWT.decode(request.headers[&#39;Aurhorization&#39;].split(&#39; &#39;[1],<br>                    Rails.application.credentials.devise[:jwt_secret_key]).first<br>      user_id = jwt_payload[&#39;sub&#39;]<br>      user = User.find(user_id.to_s)<br>    end<br>end</pre><p>Then, lets generate the files named registrations_controller and sessions_controller in a new folder called users inside the controller folder.</p><pre>#app/controllers/users/registrations_controller.rb<br>class Users::RegistrationsController &lt; Devise::RegistrationsController<br>    respond_to :json<br>    private<br>    def respond_with(resource, _opts = {})<br>        register_success &amp; return if resource.persisted?<br><br>        register_failed<br>    end<br><br>    def register_success<br>        render json: {<br>            message: &#39;Signed up successfully.&#39;,<br>            user: current_user<br>        }, status: :ok<br>    end<br><br>    def register_failed<br>        render json: {  message: &#39;Something went wrong.&#39;}, status: :unprocessable_entity<br>    end<br>end</pre><pre>#app/controllers/users/sessions_controller.rb<br>class Users::SessionsController &lt; Devise::SessionsController<br>    respond_to :json<br><br>    private<br><br>    def respond_with(_resource, _opts = {})<br>      render json: {<br>        message: &#39;You are logged in.&#39;,<br>        user: current_user<br>      }, status: :ok<br>    end<br><br>    def respond_to_on_destroy<br>      log_out_success &amp;&amp; return if current_user<br>      <br>      log_out_failure<br>    end<br><br>    def log_out_success<br>        render json: {<br>            message: &#39;You are logged out.&#39;<br>        }, status: :ok<br>    end<br><br>    def log_out_failure<br>        render json: {<br>            message: &#39;Something went wrong.&#39;<br>        }, status: :unauthorized<br>    end<br>end</pre><p>After that, encode the jwt secret key in the credentials.yml. Run the following in the terminal and copy the generated secret.</p><pre>rails secret</pre><p>Open the nano editor.</p><pre>EDITOR=nano rails credentials:edit</pre><p>Paste the generated secret in the credentials.yml.</p><pre>devise:<br>  jwt_secret_key: &lt;your_secret_key&gt;</pre><p>Finally,in the routes, hook up the newly created controllers to override the device controllers as follows:-</p><pre># config/routes.rb<br>Rails.application.routes.draw do<br>  devise_for :users,<br>  controllers: {<br>    sessions: &#39;users/sessions&#39;,<br>    registrations: &#39;users/registrations&#39;<br>  }<br><br>  get &#39;/member-data&#39;, to: &#39;members#show&#39;<br>end</pre><p>Now, if you run the server and post the following request to <a href="https://localhost:3000/users,">https://localhost:3000/users</a> in the rapid api extension of the vs code, you will get the 500 internal server error inferring that the application has sessions disabled.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*vqvVgkMz_f5yl-eBh3aEUA.png" /><figcaption>Post Request to Api</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1009/1*3hevUbMWpw09a-daBwwdVQ.png" /><figcaption>Error</figcaption></figure><p>So, lets enable the sessions after which the application.rb should something like this.</p><pre># config/application.rb<br><br>require_relative &quot;boot&quot;<br><br>require &quot;rails/all&quot;<br><br># Require the gems listed in Gemfile, including any gems<br># you&#39;ve limited to :test, :development, or :production.<br>Bundler.require(*Rails.groups)<br><br>module DeviseVue<br>  class Application &lt; Rails::Application<br>    # Initialize configuration defaults for originally generated Rails version.<br>    config.load_defaults 7.0<br><br>    # Configuration for the application, engines, and railties goes here.<br>    config.load_defaults 7.0<br>    #<br>    # This also configures sessions_options for use below<br>    config.session_store :cookie_store, key: &#39;_interslice_session&#39;<br>    # Required for all session management (regardless of session_store)<br>    config.middleware.use ActionDispatch::Cookies<br>    config.middleware.use ActionDispatch::Session::CookieStore, config.session_options<br><br>    # These settings can be overridden in specific environments using the files<br>    # in config/environments, which are processed later.<br>    #<br>    # config.time_zone = &quot;Central Time (US &amp; Canada)&quot;<br>    # config.eager_load_paths &lt;&lt; Rails.root.join(&quot;extras&quot;)<br><br>    # Only loads a smaller set of middleware suitable for API only apps.<br>    # Middleware like session, flash, cookies can be added back manually.<br>    # Skip views, helpers and assets when generating a new resource.<br>    config.api_only = true<br>  end<br>end</pre><p>Run the rails server again after enabling the sessions and post another request to <a href="https://localhost:3000/users,">https://localhost:3000/users,</a> but this time with a different email, as the first one actually did get committed to the database. The response shall be 200.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*jAT3Eug49sph4fmVfHBJqw.png" /><figcaption>Response OK</figcaption></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=2fcbab3e3fb8" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Deploy a Rails App & Postgres database on EC2 Amazon]]></title>
            <link>https://medium.com/@omarmohammad_89249/deploy-a-rails-app-postgres-database-on-ec2-amazon-290babca74df?source=rss-96c30bc85ee5------2</link>
            <guid isPermaLink="false">https://medium.com/p/290babca74df</guid>
            <dc:creator><![CDATA[Omar Mohammad]]></dc:creator>
            <pubDate>Mon, 06 Mar 2023 17:35:41 GMT</pubDate>
            <atom:updated>2023-04-25T06:42:54.484Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*xE-GtU4IIkOb3bKXsZG6gw.png" /></figure><p>Step 1</p><p>Go to EC2 on you aws console. Launch an instance by selecting an Ubuntu 22.04 image. Choose the instance type according to the requirements of the project. Select an existing or create a new key/value pair and save it your local machine.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*9dyHtuALVoMhP6X6kteCCQ.png" /></figure><p>After filling the specifications, launch the instance.</p><p>Step 2</p><p>Move the downloaded key-value pair in a separate folder. Copy the public IPv4 address mentioned alongside the name of the running aws instance. Open the terminal and create a secure shell connection with the copied remote IPv4 address.</p><pre>sudo chmod 600 key-value-pair.pem<br>ssh ubuntu@your.remote.ipv4.address -i key-value-pair.pem</pre><p>Step 3</p><p>Once logged into the secure shell, create ssh key. At the same time, update and upgrade the packages existing on the machine instance.</p><pre>sudo apt update &amp;&amp; sudo apt upgrade<br>sudo apt install curl git<br>ssh-keygen<br>eval &quot;$(ssh-agent -s)&quot;<br>ssh-add ~/.ssh/id_rsa</pre><p>Copy the ssh key.</p><pre>cat .ssh/id_rsa.pub</pre><p>Add it in the settings of your Github Profile.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/657/1*Ij34uKjRFQKq7fjL9R9adA.png" /></figure><p>Step 4</p><p><strong>Manage multiple runtime versions with a single CLI tool, extendable via plugins</strong> — <a href="https://asdf-vm.com/">docs at asdf-vm.com</a></p><p><strong>asdf</strong> is a <strong>CLI</strong> tool that can manage multiple language runtime versions on a per-project basis. It is like gvm, nvm, rbenv &amp; pyenv (and more) all in one! Simply install your language&#39;s plugin!</p><p>Also add the environment variables to .bashrc through script.</p><pre>git clone git@github.com:asdf-vm/asdf.git ~/.asdf --branch release-v0.9.1<br>echo &#39;. $HOME/.asdf/asdf.sh&#39; &gt;&gt; ~/.bashrc<br>echo &#39;. $HOME/.asdf/completions/asdf.bash&#39; &gt;&gt; ~/.bashrc<br>source ~/.bashrc</pre><p>Add dependencies required for adding the ruby plugin. Then add plugin ruby and install ruby and ruby on rails.</p><pre>sudo apt install build-essential zlib1g-dev libncurses5-dev libgdbm-dev libnss3-dev libssl-dev libreadline-dev libffi-dev gcc<br>apt-get install autoconf bison patch build-essential rustc libssl-dev libyaml-dev libreadline6-dev zlib1g-dev libgmp-dev libncurses5-dev libffi-dev libgdbm6 libgdbm-dev libdb-dev uuid-dev<br><br>asdf plugin add ruby<br>asdf install ruby latest<br>ruby -v<br>asdf global ruby [version]<br>sudo apt install ruby-railties<br>rails -v</pre><p>Step 5</p><p>Add PostgreSQL Database and aws cli.</p><pre>sudo apt install postgresql-contrib libpq-dev postgresql<br>curl &quot;https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip&quot; -o &quot;awscliv2.zip&quot;<br>sudo apt install unzip jq<br>unzip awscliv2.zip<br>sudo ./aws/install</pre><p>Step 6</p><p>Create a Postgres User and add/confirm password. Then set the password for postgres user ubuntu.</p><pre>sudo -u postgres createuser -s ubuntu -P<br>sudo -u postgres psql<br><br>postgres=# \password ubuntu<br>Enter new password for user &quot;ubuntu&quot;:<br>Enter it again:<br>postgres=# \q</pre><p>Create and Migrate the database. Add node, npm and Yarn.</p><pre>rails db:create &amp;&amp; rails db:migrate<br>sudo apt install nodejs -y<br>sudo apt install npm -y<br>sudo npm i -g yarn</pre><p>Step 6</p><p>Deploy</p><p>rails s -p 3003 -b 0.0.0.0</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=290babca74df" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>