<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://fakhruddin.info/feed.xml" rel="self" type="application/atom+xml" /><link href="https://fakhruddin.info/" rel="alternate" type="text/html" /><updated>2025-08-01T11:18:04+00:00</updated><id>https://fakhruddin.info/feed.xml</id><title type="html">Fakhruddin Abdi</title><subtitle>Portfolio website</subtitle><entry><title type="html">UK Innovator Founder Visa</title><link href="https://fakhruddin.info/uk-innovator-visa/" rel="alternate" type="text/html" title="UK Innovator Founder Visa" /><published>2025-06-25T17:40:00+00:00</published><updated>2025-06-25T17:40:00+00:00</updated><id>https://fakhruddin.info/uk-innovator-visa</id><content type="html" xml:base="https://fakhruddin.info/uk-innovator-visa/"><![CDATA[<p><img style="width: 100%" src="/assets/images/blogs/uk/passport.jpeg" /></p>

<div style="background-color: #e8f5e8; border: 1px solid #4caf50; border-radius: 8px; padding: 15px; margin: 20px 0; color: #2e7d32;">
  <h4 style="margin-top: 0; color: #2e7d32;">✅ Current Information</h4>
  <p style="margin-bottom: 0;">This guide covers the <strong>UK Innovator Founder Visa</strong>, which replaced the UK Startup Visa in April 2023. This is the current entrepreneurship visa route for the UK. For information about the discontinued Startup Visa, please see my <a href="/uk-startup-visa" style="color: #2e7d32; text-decoration: underline;">previous guide</a>.</p>
</div>

<p>After obtaining a UK Startup Visa and spending a year and a half building my business in the UK, I recently transitioned to the new Innovator Founder Visa. This post shares my experience with this new visa route, outlining the challenges and lessons I learned.</p>

<h3 style="text-align: left; border-bottom: 1px solid lightgray; padding-bottom: 10px; margin-bottom: 10px;"> 
	Background and Context
</h3>

<p>I had been in the UK for approximately 18 months on a Startup Visa. As part of the initial agreement with my endorsing body, I enrolled in their coaching program, which involved regular monthly meetings to ensure the business aligned with market requirements and Home Office criteria.</p>

<p>My endorsing body was a legacy endorsing body, meaning that even though the Startup Visa was discontinued, they remained responsible for my progress and my transition to the Innovator Founder Visa.</p>

<h3 style="text-align: left; border-bottom: 1px solid lightgray; padding-bottom: 10px; margin-bottom: 10px;"> 
	Starting the Application Process
</h3>

<p>In July 2024, I approached my endorsing body to begin the process early, as my business was nearly ready. We had a functional website and product and were actively engaging with the market.</p>

<p>However, the endorsing body advised allowing more time, as the Home Office is stringent about meeting all criteria.  Finally, after our last meeting in December, I decided to proceed.</p>

<h4 id="application-process">Application Process</h4>
<p>Starting from December 1st, I started to work on the application process. I updated the business plan and financial plan based on the feedback from the endorsing body.</p>

<h3 id="endorsing-body-application-timeline-july-2024---january-2025">Endorsing Body Application Timeline (July 2024 - January 2025)</h3>

<table style="width: 100%; border-collapse: collapse; margin: 20px 0;">
  <thead>
    <tr style="background-color: #f8f9fa;">
      <th style="border: 1px solid #dee2e6; padding: 12px; text-align: left; font-weight: bold; width: 120px;">Date</th>
      <th style="border: 1px solid #dee2e6; padding: 12px; text-align: left; font-weight: bold;">Milestone</th>
    </tr>
  </thead>
  <tbody>
    <tr style="background-color: #f8f9fa;">
      <td style="border: 1px solid #dee2e6; padding: 10px; width: 120px;">Dec 1-7, 2024</td>
      <td style="border: 1px solid #dee2e6; padding: 10px;">Finalized business plan and financial projections</td>
    </tr>
    <tr>
      <td style="border: 1px solid #dee2e6; padding: 10px; width: 120px;">Dec 17, 2024</td>
      <td style="border: 1px solid #dee2e6; padding: 10px;">Submitted formal application with complete documentation</td>
    </tr>
    <tr style="background-color: #f8f9fa;">
      <td style="border: 1px solid #dee2e6; padding: 10px; width: 120px;">Dec 19, 2024</td>
      <td style="border: 1px solid #dee2e6; padding: 10px;">Payment processed and secure document upload portal provided</td>
    </tr>
    <tr>
      <td style="border: 1px solid #dee2e6; padding: 10px; width: 120px;">Jan 6, 2025</td>
      <td style="border: 1px solid #dee2e6; padding: 10px;">Assessment commenced following holiday period</td>
    </tr>
    <tr style="background-color: #f8f9fa;">
      <td style="border: 1px solid #dee2e6; padding: 10px; width: 120px;">Jan 25, 2025</td>
      <td style="border: 1px solid #dee2e6; padding: 10px;">Endorsement letter approved with detailed assessor feedback</td>
    </tr>
  </tbody>
</table>

<p>On December 17th, I submitted the completed application form. The fee for the “Same Business” route was £1,200 + VAT (£1,440 total). This was £200 above the standard rate to account for the additional time required to verify that I met both the previous Startup Visa criteria and the new Innovator Founder requirements.</p>

<h3 style="text-align: left; border-bottom: 1px solid lightgray; padding-bottom: 10px; margin-bottom: 10px;"> 
	Endorsement Success
</h3>

<p>The process with the endorsing body was relatively straightforward. About a month after applying, I received the endorsement letter.</p>

<p>On January 25th, I received the endorsement letter along with the assessment sheet and assessor’s comments. They said:</p>

<h3 style="text-align: left; border-bottom: 1px solid lightgray; padding-bottom: 10px; margin-bottom: 10px;"> 
	Home Office Visa Application
</h3>

<p>I completed my Innovator Founder Visa application on the Home Office website on February 10th and booked an appointment with TLS Contact for February 13th. My visa application submission was officially dated February 13th.</p>

<p>The total cost for the visa application was £4,740, which included £1,590 for the visa fee and £3,150 for the Immigration Health Surcharge (IHS) fee.</p>

<p>The application was expected to be processed within 8 weeks, but it took over 3 months.</p>

<p><strong>First Information Request (April 3rd)</strong></p>

<p>The first update I received from the Home Office was on April 3rd. They requested more information, including the business plan and endorsement letter from my original Start-up Visa application. They also asked for comprehensive evidence of business activity, such as financial records and marketing efforts, and a clarification on how I was managing my time while allegedly working another full-time job.</p>

<p><strong>Second Information Request (April 8th)</strong></p>

<p>After I submitted the requested documents, a second request arrived on April 8th. This time, the Home Office focused on my team. They asked about my co-founders’ roles and application plans, our working relationships, and for evidence of our first hire. They also requested more proof of our marketing activities and the development history of our Minimum Viable Product (MVP).</p>

<p><strong>Third Information Request (April 22nd)</strong></p>

<p>The third and final request came on April 22nd, focusing on financial sustainability and hiring. The Home Office questioned how the business could afford to pay an employee’s salary without any revenue and asked for justification for hiring from outside the UK. They also wanted to see our revenue projections and, once more, asked for details about my co-founders.</p>

<p>I responded to all their requests, and on May 21st, I finally received approval.</p>

<h3 id="home-office-application-timeline-february---may-2025">Home Office Application Timeline (February - May 2025)</h3>

<table style="width: 100%; border-collapse: collapse; margin: 20px 0;">
  <thead>
    <tr style="background-color: #f8f9fa;">
      <th style="border: 1px solid #dee2e6; padding: 12px; text-align: left; font-weight: bold; width: 120px;">Date</th>
      <th style="border: 1px solid #dee2e6; padding: 12px; text-align: left; font-weight: bold;">Activity</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="border: 1px solid #dee2e6; padding: 10px; width: 120px;">Feb 10, 2025</td>
      <td style="border: 1px solid #dee2e6; padding: 10px;">Completed Home Office online application</td>
    </tr>
    <tr style="background-color: #f8f9fa;">
      <td style="border: 1px solid #dee2e6; padding: 10px; width: 120px;">Feb 13, 2025</td>
      <td style="border: 1px solid #dee2e6; padding: 10px;">Attended TLS Contact appointment - official application start</td>
    </tr>
    <tr>
      <td style="border: 1px solid #dee2e6; padding: 10px; width: 120px;">Apr 3, 2025</td>
      <td style="border: 1px solid #dee2e6; padding: 10px;">First information request from Home Office</td>
    </tr>
    <tr style="background-color: #f8f9fa;">
      <td style="border: 1px solid #dee2e6; padding: 10px; width: 120px;">Apr 8, 2025</td>
      <td style="border: 1px solid #dee2e6; padding: 10px;">Second information request focusing on co-founders and business development</td>
    </tr>
    <tr>
      <td style="border: 1px solid #dee2e6; padding: 10px; width: 120px;">Apr 22, 2025</td>
      <td style="border: 1px solid #dee2e6; padding: 10px;">Third information request about financial sustainability and hiring</td>
    </tr>
    <tr style="background-color: #f8f9fa;">
      <td style="border: 1px solid #dee2e6; padding: 10px; width: 120px;">May 21, 2025</td>
      <td style="border: 1px solid #dee2e6; padding: 10px;">Final approval and visa confirmation received</td>
    </tr>
  </tbody>
</table>

<h3 style="text-align: left; border-bottom: 1px solid lightgray; padding-bottom: 10px; margin-bottom: 10px;"> 
	Key Differences from Startup Visa
</h3>

<p><strong>Legacy Endorsing Body Support</strong></p>

<p>One significant advantage of transitioning from a Startup Visa was having a legacy endorsing body. They remained responsible for monitoring progress and conducting the 12 and 24-month progress checks, providing continuity throughout the visa journey.</p>

<p><strong>Enhanced Scrutiny</strong></p>

<p>The Innovator Founder Visa involves much more detailed scrutiny compared to the Startup Visa. The Home Office requested extensive evidence of:</p>
<ul>
  <li>Actual business operations and revenue generation plans</li>
  <li>Employee hiring processes and financial sustainability</li>
  <li>Marketing and sales activities</li>
  <li>Co-founder relationships and contributions</li>
  <li>Historical business development</li>
</ul>

<p><strong>Higher Financial Requirements</strong></p>

<p>The financial requirements are more stringent, with greater emphasis on demonstrating how the business will become financially sustainable and generate revenue.</p>

<h3 style="text-align: left; border-bottom: 1px solid lightgray; padding-bottom: 10px; margin-bottom: 10px;"> 
	Conclusion and Key Takeaways
</h3>

<p>The transition from Startup Visa to Innovator Founder Visa was challenging but ultimately successful. The entire process took approximately five months from initial discussions to final approval.</p>

<p><strong>Key Lessons Learned:</strong></p>

<ol>
  <li><strong>Start Early</strong>: Begin discussions with your endorsing body well in advance of your current visa’s expiration.</li>
  <li><strong>Maintain Detailed Records</strong>: Maintain comprehensive documentation of all business activities, partnerships, and financial transactions.</li>
  <li><strong>Prepare for Scrutiny</strong>: The Home Office will request extensive evidence of genuine business operations.</li>
  <li><strong>Co-founder Considerations</strong>: Document any team additions carefully from the outset.</li>
  <li><strong>Financial Planning</strong>: Demonstrate a clear path to revenue generation and financial sustainability.</li>
  <li><strong>Legacy Endorsing Body Advantage</strong>: Having an existing relationship with an endorsing body can streamline the process.</li>
</ol>

<p><strong>Important Reminders:</strong></p>

<ul>
  <li>The endorsement letter is valid for only 3 months.</li>
  <li>Endorsement does not guarantee visa approval.</li>
  <li>The “Same Business” route is available for those transitioning from a Startup Visa.</li>
  <li>Regular monitoring and progress checks continue after visa approval.</li>
</ul>

<p>The Innovator Founder Visa represents a more mature, business-focused approach to UK entrepreneurship visas. While the requirements are more stringent than the previous Startup Visa, the route provides a clear pathway for serious entrepreneurs looking to build scalable businesses in the UK.</p>

<p>For those considering this route, thorough preparation, detailed documentation, and early engagement with endorsing bodies are essential for success. The investment in time and effort is significant, but the opportunities for building a business in the UK make it worthwhile for committed entrepreneurs.</p>

<div style="background-color: #f0f7ff; border: 1px solid #3498db; border-radius: 8px; padding: 20px; margin: 30px 0; color: #2c3e50;">
  <h4 style="margin-top: 0; color: #2980b9;">💬 Need Advice on Your UK Innovator Founder Visa Application?</h4>
  <p>Having gone through the entire process from Startup Visa to Innovator Founder Visa, I understand the challenges and complexities involved. If you're considering this visa route or are currently in the application process, I'm happy to share my experience and provide guidance.</p>
  <p style="margin-bottom: 0;"><strong>Feel free to reach out:</strong> <a href="mailto:abdi.fakhruddin@gmail.com" style="color: #2980b9; text-decoration: underline;">abdi.fakhruddin@gmail.com</a></p>
  <p style="margin-bottom: 0; font-size: 0.9em; color: #7f8c8d; margin-top: 10px;"><em>I'll do my best to respond to all genuine inquiries about the UK visa process.</em></p>
</div>]]></content><author><name>Fakhruddin Abdi</name></author><category term="blog" /><category term="Visa" /><category term="UK" /><category term="Personal Experience" /><category term="Innovator Founder" /><summary type="html"><![CDATA[A comprehensive guide to securing the UK Innovator Founder Visa—the new entrepreneurship route that replaced the Startup Visa.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://fakhruddin.info/assets/images/blogs/uk/flag.jpeg" /><media:content medium="image" url="https://fakhruddin.info/assets/images/blogs/uk/flag.jpeg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">VidClip.ai - VEED Hackathon</title><link href="https://fakhruddin.info/vidclip-veed-hackathon/" rel="alternate" type="text/html" title="VidClip.ai - VEED Hackathon" /><published>2025-05-31T10:00:00+00:00</published><updated>2025-05-31T10:00:00+00:00</updated><id>https://fakhruddin.info/vidclip-veed-hackathon</id><content type="html" xml:base="https://fakhruddin.info/vidclip-veed-hackathon/"><![CDATA[<p><img style="width: 100%" src="/assets/images/projects/vidclip/screenshot-1.png" alt="VidSnap interface showing intelligent video analysis and content detection" /></p>

<p>VidClip.ai was born during the <a href="https://lu.ma/989p71d2?tk=lmSXIP">VEED x fal.ai Gen AI Hackathon</a> in May 2025, a three-day intensive coding event held at VEED’s office in the heart of Shoreditch, London. Together with my teammate Sirwan, we tackled the challenge of revolutionizing how creators generate short-form content from long videos.</p>

<h2 id="the-hackathon-experience">The Hackathon Experience</h2>

<p>The event brought together 300+ developers, AI enthusiasts, and industry leaders for what turned out to be one of the most innovative hackathons in London’s AI startup scene. With a prize pool worth over £100k and sponsorship from industry giants like VEED, fal.ai, ElevenLabs, Photoroom, and <a href="https://www.sievedata.com/">Sieve</a>, the stage was set for groundbreaking innovation.</p>

<p><img style="width: 100%" src="/assets/images/projects/vidclip/veed.png" alt="Fakhruddin and Sirwan working at VEED office during the hackathon" /></p>

<h3 id="event-timeline">Event Timeline</h3>

<p><strong>Day 1 (May 30)</strong> - Opening ceremony and networking session where we formed teams and explored project ideas
<strong>Day 2 (May 31)</strong> - The main hacking day! Development officially began at 11:00am with non-stop coding through the night
<strong>Day 3 (June 1)</strong> - Final submissions and winner announcements</p>

<p><em>Working alongside my teammate Sirwan at the VEED office in Shoreditch during the hackathon</em></p>

<h2 id="project-presentation">Project Presentation</h2>

<p>Here’s our complete presentation video from the final submission at the hackathon:</p>

<video width="100%" controls="" preload="metadata">
  <source src="/assets/videos/vidsnap.mp4" type="video/mp4" />
  <p>Your browser does not support the video tag. <a href="/assets/videos/vidsnap.mp4">Download the video</a> to watch it.</p>
</video>

<h2 id="the-problem-we-solved">The Problem We Solved</h2>

<p>Current short video generation tools take a one-size-fits-all approach, often missing the nuanced preferences of content creators. We identified a gap in the market for intelligent, customizable short video creation that goes beyond simple trimming and basic AI selection.</p>

<h2 id="our-innovative-solution">Our Innovative Solution</h2>

<p>VidClip.ai introduces a revolutionary approach to short video generation through our unique two-stage process:
<img style="width: 100%" src="/assets/images/projects/vidclip/screenshot-2.png" alt="VidSnap chat interface for custom video generation prompts" /></p>

<h3 id="1-intelligent-video-analysis">1. Intelligent Video Analysis</h3>

<p>Using <a href="https://www.sievedata.com/">Sieve’s powerful video AI APIs</a>, our system comprehensively analyzes long-form videos by:</p>

<ul>
  <li><strong>Object Detection</strong>: Identifying all objects, people, and items within the video</li>
  <li><strong>Scene Understanding</strong>: Extracting context, activities, and mood from different segments</li>
  <li><strong>Content Digitization</strong>: Creating a searchable database of video elements and references</li>
  <li><strong>Temporal Analysis</strong>: Understanding the flow and pacing of content throughout the video</li>
</ul>

<h3 id="2-interactive-ai-powered-customization">2. Interactive AI-Powered Customization</h3>

<p>What sets VidClip.ai apart is our interactive chatbot interface that allows users to:</p>

<ul>
  <li><strong>Person-Specific Clips</strong>: “Show me segments featuring John” or “Create a clip focusing on the speaker”</li>
  <li><strong>Mood-Based Generation</strong>: “Extract fun moments” or “Find emotional/dramatic scenes”</li>
  <li><strong>Activity Filtering</strong>: “Show cooking segments” or “Focus on eating scenes”</li>
  <li><strong>Object Highlighting</strong>: “Create clips featuring specific products or items”</li>
  <li><strong>Custom Combinations</strong>: Mix and match multiple preferences for highly targeted content</li>
</ul>

<h2 id="technical-architecture">Technical Architecture</h2>

<h3 id="frontend">Frontend</h3>

<ul>
  <li><strong>React</strong> - Modern, responsive user interface</li>
  <li><strong>Interactive Chat Interface</strong> - Natural language processing for user preferences</li>
  <li><strong>Real-time Preview</strong> - Instant video clip generation and preview</li>
</ul>

<h3 id="backend--ai-integration">Backend &amp; AI Integration</h3>

<ul>
  <li><strong>Sieve API Integration</strong> - Leveraging cutting-edge video understanding technology</li>
  <li><strong>Video Processing Pipeline</strong> - Efficient handling of large video files</li>
  <li><strong>AI Logic Engine</strong> - Converting user preferences into technical video parameters</li>
  <li><strong>Content Management</strong> - Organizing and serving processed video segments</li>
</ul>

<h2 id="key-features">Key Features</h2>

<ul>
  <li><strong>Advanced Video Analysis</strong> - Deep understanding of video content using AI</li>
  <li><strong>Natural Language Interface</strong> - Chat with AI to describe your ideal short clip</li>
  <li><strong>Multi-Modal Search</strong> - Find content by people, objects, activities, or mood</li>
  <li><strong>Real-Time Processing</strong> - Fast clip generation and preview</li>
  <li><strong>Customizable Output</strong> - Fine-tune clips based on specific requirements</li>
  <li><strong>Batch Processing</strong> - Handle multiple long videos simultaneously</li>
  <li><strong>Export Options</strong> - Multiple formats and quality settings</li>
</ul>

<h2 id="future-development">Future Development</h2>

<p>VidClip.ai has enormous potential for expansion:</p>

<ul>
  <li><strong>Multi-language Support</strong> - Expanding beyond English content</li>
  <li><strong>Advanced Editing Features</strong> - Transitions, effects, and professional touches</li>
  <li><strong>Social Platform Integration</strong> - Direct publishing to TikTok, Instagram, YouTube Shorts</li>
  <li><strong>Collaborative Features</strong> - Team-based clip creation and approval workflows</li>
  <li><strong>Analytics Dashboard</strong> - Performance tracking for generated clips</li>
</ul>

<h2 id="links">Links</h2>

<ul>
  <li><strong>Hackathon</strong>: <a href="https://lu.ma/veed-hackathon-2025">VEED x fal.ai Gen AI Hackathon</a></li>
  <li><strong>Sieve Platform</strong>: <a href="https://www.sievedata.com/">https://www.sievedata.com/</a></li>
  <li><strong>VEED Office</strong>: 17-18 Clere St, London EC2A 4LJ, UK</li>
</ul>

<hr />

<p><em>Built during the VEED x fal.ai Gen AI Hackathon, May 30 - June 1, 2025, London</em></p>]]></content><author><name>Fakhruddin Abdi</name></author><category term="project" /><category term="vidclip" /><category term="ai" /><category term="video-processing" /><category term="react" /><category term="api-integration" /><category term="hackathon" /><category term="content-creation" /><summary type="html"><![CDATA[AI-powered short video generation tool built during VEED's Gen AI Hackathon in London - transforming long videos into engaging short clips through intelligent analysis and interactive customization]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://fakhruddin.info/assets/images/projects/vidclip/veed-hackathon.png" /><media:content medium="image" url="https://fakhruddin.info/assets/images/projects/vidclip/veed-hackathon.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Positive or Negative Motivation?</title><link href="https://fakhruddin.info/poistive-negative/" rel="alternate" type="text/html" title="Positive or Negative Motivation?" /><published>2024-12-26T08:00:00+00:00</published><updated>2024-12-26T08:00:00+00:00</updated><id>https://fakhruddin.info/poistive-negative</id><content type="html" xml:base="https://fakhruddin.info/poistive-negative/"><![CDATA[<p><img style="width: 100%" src="/assets/images/blogs/motivation/positive-or-negative-motivation.png" /></p>

<p>All actions comes from two main sources, <code class="language-plaintext highlighter-rouge">fear</code> or <code class="language-plaintext highlighter-rouge">pleasure</code>.
When you are doing something, you are either doing it because you are afraid of the consequences of not doing it, or you are doing it because you are looking for the pleasure that comes from doing it.
This simple concept can be applied to every aspect of your life, from your work to your relationships to your health.</p>

<p>When you are working on a project, are you doing it because you are afraid of what will happen if you don’t finish it, or are you doing it because you enjoy the process and the sense of accomplishment that comes from completing it?</p>

<p>When you are in a relationship, are you staying in it because you are afraid of being alone, or are you staying in it because you enjoy the companionship and the love that you receive from your partner?</p>

<p>When you are taking care of your health, are you exercising and eating well because you are afraid of getting sick, or are you doing it because you enjoy feeling strong and healthy?</p>

<p>Let’s focus on the work aspect of this concept.
As an employer or a manager, its up to you which source you want to use to motivate your employees.
The fear source is the easiest way to motivate your employees, However it will generate a negative energy, and it will make your employees less creative and less productive.</p>

<p>You will end up with a team of employees who are just doing their job because they are afraid of losing it, not because they love it.
with a team of employees who has no other choice but to stay in your company, not because they want to.
And obviously, with a team of employees who are not happy, and they will not make your customers happy.</p>

<p>Unfortunately, for the managers its not a matter of days to switch and build a pleasure source for their employees.
Its not something you can learn from books or podcasts.
Instead its a matter of effort and time you’ve spent on yourself to know your ego, who are you and what you want from your life.
Most of us are lying to ourselves, we are not honest with ourselves, we are not doing what we love, we are not living the life we want.</p>

<p>To gain such a pure and honest vision, you should be able to see and listen.</p>

<p>When your mind is full of experiences, thoughts, fear, anger, ego and pride, you CANNOT see and listen.</p>

<p>You can only see and listen when you are empty, when you are calm, when you are humble.
I finish this post with a quote from the great Rumi:</p>

<p>این محبت هم نتیجهٔ دانشست -  کی گزافه بر چنین تختی نشست</p>

<p>از حریصی عاقبت نادیدنست - بر دل و بر عقل خود خندیدنست</p>]]></content><author><name>Fakhrudin Abdi</name></author><category term="blog" /><category term="Productivity" /><category term="Motivation" /><category term="Success" /><summary type="html"><![CDATA[Exploring the balance between positive and negative motivation in the workplace.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://fakhruddin.info/assets/images/blogs/smart-hard/header.png" /><media:content medium="image" url="https://fakhruddin.info/assets/images/blogs/smart-hard/header.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Smart or Hard Working?</title><link href="https://fakhruddin.info/smart_or_hard/" rel="alternate" type="text/html" title="Smart or Hard Working?" /><published>2024-07-08T08:00:00+00:00</published><updated>2024-07-08T08:00:00+00:00</updated><id>https://fakhruddin.info/smart_or_hard</id><content type="html" xml:base="https://fakhruddin.info/smart_or_hard/"><![CDATA[<p><img style="width: 100%" src="/assets/images/blogs/smart-hard/banner.jpg" /></p>

<p>In the past, I was a firm believer in the concept of smart working. The idea that working smarter, not harder, could lead to success was deeply ingrained in my mindset. However, a recent realization has led me to reconsider this belief.</p>

<p>There are many smart people out there. In fact, the world is filled with intelligent individuals who are capable of working smart. But is smart work alone enough to truly make a difference?</p>

<p>Upon reflection, I’ve come to understand that to truly excel and make a significant impact, one needs to not only work smart but also work hard. It’s not an either-or situation, but rather a balance of both.</p>

<p>Smart work can certainly lead to efficiency and help us achieve more in less time. But hard work is what drives us to go the extra mile, to persist when things get tough, and to keep going despite the odds.</p>

<p>In a world where smart people are plentiful, hard work can be the differentiating factor. It’s the combination of smart work and hard work that leads to true success.</p>

<p>So, let’s not limit ourselves to working smart. Let’s also embrace the value of hard work. Because to truly make a difference, we need to be smart and work hard!</p>]]></content><author><name>Your Name</name></author><category term="blog" /><category term="Productivity" /><category term="Success" /><category term="Smart" /><summary type="html"><![CDATA[Exploring the balance between smart work and hard work in the journey to success.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://fakhruddin.info/assets/images/blogs/smart-hard/header.png" /><media:content medium="image" url="https://fakhruddin.info/assets/images/blogs/smart-hard/header.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">NDB</title><link href="https://fakhruddin.info/ndb/" rel="alternate" type="text/html" title="NDB" /><published>2024-04-01T00:00:00+00:00</published><updated>2024-04-01T00:00:00+00:00</updated><id>https://fakhruddin.info/ndb</id><content type="html" xml:base="https://fakhruddin.info/ndb/"><![CDATA[<p><img style="width: 100%" src="/assets/images/projects/ndb/banner.png" /></p>

<p>As a softcode team, we started working on a new project called NDB with Balla Group client.
NDB is a payment solution for Iraqi businesses, giving them the ability to accept payments from their customers.
Its aims to provide a secure and reliable payment solution for the region.</p>

<p>The project is a startup and I was the lead developer and project manager.
Its a full stack project, from the mobile application to the backend and admin panel.
Let’s explore the different parts of the project.</p>

<h3 id="mobile-application">Mobile application</h3>
<p>The mobile application is developed by React Native, and it’s available for both iOS and Android.
<img style="width: 100%" src="/assets/images/projects/ndb/app.png" /></p>

<h3 id="system-architecture-and-design">System architecture and design</h3>
<p>The main challenge was to design a system that is scalable and reliable.
We started with an initial design and architecture, and then we iterated over the design multiple times to make sure its scalable and reliable.
It took us a lot of time to design the system, but it was worth it.</p>

<p>But changing the database schema was a bit challenging, as we had to update the api and mobile application to reflect the changes.
To overcome this challenge, we need an API that is dynamic and adaptable to future changes.
In the next section, we will explore the API development and design.</p>

<h3 id="api-development">API Development</h3>
<p>Our backend is designed with a focus on data management and monitoring. We’ve established a logical layer over the static schema and types, making it dynamic and adaptable for future changes. This layer utilizes JavaScript objects and generator functions to define the schema and types, simplifying updates and maintenance.</p>

<h3 id="separation-of-concerns">Separation of concerns</h3>
<p>Each part of the system is separated into different modules, making it easy to maintain and update. We’ve also implemented a strict separation of concerns, ensuring that each module is responsible for a specific task.
For example, our identity module is plugged into the authentication middleware, which is responsible for authenticating the user. The identity module is also responsible for managing the user’s profile and permissions.
If we need to change the identity provider, we can simply update the identity module without affecting other parts of the system.</p>

<h3 id="security-and-stability">Security and stability</h3>
<p>The project is designed with security and stability in mind. 
We’ve implemented various security measures such as query control, authentication, and authorization to protect the system from potential threats.
We did a lot of research and testing to</p>

<h3 id="development-and-deployment">Development and Deployment</h3>
<p>For the development and deployment, we leverage the power of github and github actions.
Using different environments for the development, and production, we can easily test and deploy the changes to the different environments.</p>

<h3 id="testing">Testing</h3>
<p>For the testing, we used jest and end to end testing strategy.
The end to end testing, help us to test the whole system, from the mobile application to the backend and admin panel.</p>

<h3 id="multiple-payment-providers">Multiple payment providers</h3>
<p>The project supports multiple payment providers, like FIB, ZainCash, and more.
The feature implementation was a bit challenging, in term of the different APIs and documentations.
We created a unified API for the payment providers, which make it easy to add new providers in the future.</p>

<h2 id="features">Features</h2>
<ul>
  <li>Multiple payment providers</li>
  <li>User management and profile</li>
  <li>Transaction history</li>
  <li>Admin panel for data management and monitoring</li>
</ul>

<h2 id="tech-stack">Tech stack</h2>
<ul>
  <li>React Native</li>
  <li>React Admin</li>
  <li>React</li>
  <li>PostgreSQL</li>
  <li>iOS ( React Native )</li>
  <li>Android ( React Native )</li>
</ul>

<h2 id="links">Links</h2>
<p>https://ndbiq.com</p>

<h2 id="twitter-post">Twitter post</h2>
<p>text: “My new blog post about NDB, a payment solution for Iraq and Kurdistan region which i developed with @softcode. #ReactNative #Prisma #PostgreSQL #ReactAdmin #NDB #Iraq #Kurdistan #PaymentSolution #Softcode #FakhruddinAbdi”
```</p>]]></content><author><name>Fakhruddin Abdi</name></author><category term="project" /><category term="ndb" /><category term="react-native" /><category term="react-admin" /><category term="react" /><category term="prisma" /><category term="graphql" /><category term="postgresql" /><category term="payment" /><summary type="html"><![CDATA[Payment solution for Iraq and Kurdistan region.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://fakhruddin.info/assets/images/projects/ndb/logo.png" /><media:content medium="image" url="https://fakhruddin.info/assets/images/projects/ndb/logo.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Redefining Humanity’s Core Values</title><link href="https://fakhruddin.info/ai_human/" rel="alternate" type="text/html" title="Redefining Humanity’s Core Values" /><published>2024-03-20T08:00:00+00:00</published><updated>2024-03-20T08:00:00+00:00</updated><id>https://fakhruddin.info/ai_human</id><content type="html" xml:base="https://fakhruddin.info/ai_human/"><![CDATA[<p><img style="width: 100%" src="/assets/images/blogs/ai-human/image.png" /></p>

<p>Thinking back to how life has changed since the 90s, we’ve seen a shift in what’s important. Back then, being strong was a big deal. Then came the 2000s, focusing on education. Now, it’s all about technology.</p>

<p>But with each change, technology has been taking over. Machines do what used to require physical strength, and the internet has made memorizing things less important.</p>

<p>Yet, one thing hasn’t changed: our ability to think and plan. However, as AI gets smarter, we wonder what will matter most for success in the future.</p>

<p>Will it be strength, memory, and planning, or is there something more to being human?</p>

<p>With AI potentially replacing jobs, we’re questioning our worth. What will guide us in this new world?</p>

<p>Take programming, for example. If AI had started coding in the 2000s, would we have new frameworks like React or Vue?</p>

<p>The answer lies in our unique ability to create. Unlike AI, which improves existing ideas, humans invent new ones.</p>

<p>So, while AI can help us, it can’t replace our creativity. It’s here to assist, not take over.</p>

<p>As we navigate this AI-driven world, let’s celebrate our creativity and redefine what it means to be human.</p>]]></content><author><name>Fakhruddin Abdi</name></author><category term="blog" /><category term="AI" /><category term="Humanity" /><category term="Future" /><category term="Technology" /><category term="Creativity" /><summary type="html"><![CDATA[As AI gets smarter, we wonder what will matter most for success in the future. Will it be strength, memory, and planning, or is there something more to being human?]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://fakhruddin.info/assets/images/blogs/ai-human/logo.png" /><media:content medium="image" url="https://fakhruddin.info/assets/images/blogs/ai-human/logo.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Ramda and GraphQL</title><link href="https://fakhruddin.info/functional_gql/" rel="alternate" type="text/html" title="Ramda and GraphQL" /><published>2023-08-25T08:00:00+00:00</published><updated>2023-08-25T08:00:00+00:00</updated><id>https://fakhruddin.info/functional_gql</id><content type="html" xml:base="https://fakhruddin.info/functional_gql/"><![CDATA[<p><img style="width: 100%" src="/assets/images/blogs/ramda/graphql.png" /></p>

<p>Leveraging Functional Programming to Build Flexible Schemas in Apollo Server
When building a GraphQL API with Apollo Server, defining the schema is a crucial first step. The schema defines the shape of our API by specifying all of the types, queries, mutations and more.</p>

<p>As our API evolves, we’ll inevitably need to make changes to the schema. Doing this by directly modifying the schema strings can quickly become cumbersome. This is where functional programming shines!</p>

<p>In this post, we’ll use the Ramda functional programming library to build a schema for an API for a library application. By leveraging Ramda’s composable functions, we can build a flexible schema that is easy to extend and modify over time.</p>

<p>Defining Our Schema Types
First, let’s define the types we’ll need for our library API using GraphQL schema language:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">type</span> <span class="nx">Book</span> <span class="p">{</span>
  <span class="nl">id</span><span class="p">:</span> <span class="nx">ID</span><span class="o">!</span>
  <span class="nx">title</span><span class="p">:</span> <span class="nb">String</span><span class="o">!</span>
  <span class="nx">author</span><span class="p">:</span> <span class="nb">String</span><span class="o">!</span>
<span class="p">}</span>

<span class="nx">type</span> <span class="nx">Author</span> <span class="p">{</span>
  <span class="nl">id</span><span class="p">:</span> <span class="nx">ID</span><span class="o">!</span> 
  <span class="nx">name</span><span class="p">:</span> <span class="nb">String</span><span class="o">!</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Rather than defining these types directly in our schema string, we’ll use Ramda to compose them separately so they are reusable.</p>

<p>First, we construct our Book type. We can keep the book fields in an object so we can easily add new fields later:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">bookFields</span> <span class="o">=</span> <span class="p">{</span>
  <span class="na">id</span><span class="p">:</span> <span class="dl">'</span><span class="s1">ID!</span><span class="dl">'</span><span class="p">,</span>
  <span class="na">title</span><span class="p">:</span> <span class="dl">'</span><span class="s1">String!</span><span class="dl">'</span><span class="p">,</span>
  <span class="na">author</span><span class="p">:</span> <span class="dl">'</span><span class="s1">String</span><span class="dl">'</span>
<span class="p">}</span>
</code></pre></div></div>

<p>We can even define some basic fields that will be reused across types:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">basicFields</span> <span class="o">=</span> <span class="p">{</span>
    <span class="na">id</span><span class="p">:</span> <span class="dl">'</span><span class="s1">ID!</span><span class="dl">'</span><span class="p">,</span>
    <span class="na">createdAt</span><span class="p">:</span> <span class="dl">'</span><span class="s1">String!</span><span class="dl">'</span><span class="p">,</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Now we can construct the bookFields object by merging the basicFields with book-specific fields:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">bookFields</span> <span class="o">=</span> <span class="nx">R</span><span class="p">.</span><span class="nx">merge</span><span class="p">(</span><span class="nx">basicFields</span><span class="p">,</span> <span class="p">{</span>
    <span class="na">title</span><span class="p">:</span> <span class="dl">'</span><span class="s1">String!</span><span class="dl">'</span><span class="p">,</span>
    <span class="na">author</span><span class="p">:</span> <span class="dl">'</span><span class="s1">String</span><span class="dl">'</span>
<span class="p">}</span>
</code></pre></div></div>

<p>This allows us to reuse the basic fields, while still customizing for the Book type.</p>

<p>Now let’s use Ramda to compose the Book type:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">BookType</span> <span class="o">=</span> <span class="nx">R</span><span class="p">.</span><span class="nx">compose</span><span class="p">(</span>
  <span class="nx">R</span><span class="p">.</span><span class="nx">concat</span><span class="p">(</span><span class="nx">R</span><span class="p">.</span><span class="k">of</span><span class="p">(</span><span class="dl">'</span><span class="s1">type Book {</span><span class="dl">'</span><span class="p">),</span> <span class="nx">R</span><span class="p">.</span><span class="k">of</span><span class="p">(</span><span class="dl">'</span><span class="s1">}</span><span class="dl">'</span><span class="p">)),</span>
  <span class="nx">R</span><span class="p">.</span><span class="nx">join</span><span class="p">(</span><span class="dl">'</span><span class="se">\n</span><span class="dl">'</span><span class="p">),</span>
  <span class="nx">R</span><span class="p">.</span><span class="nx">map</span><span class="p">(</span><span class="nx">field</span> <span class="o">=&gt;</span> <span class="s2">`  </span><span class="p">${</span><span class="nx">field</span><span class="p">}</span><span class="s2">`</span><span class="p">),</span>
  <span class="nx">R</span><span class="p">.</span><span class="k">of</span><span class="p">,</span>
  <span class="nx">bookFields</span>
<span class="p">);</span>
</code></pre></div></div>

<p>And similarly for Author:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">AuthorType</span> <span class="o">=</span> <span class="nx">R</span><span class="p">.</span><span class="nx">compose</span><span class="p">(</span>
  <span class="nx">R</span><span class="p">.</span><span class="nx">concat</span><span class="p">(</span><span class="nx">R</span><span class="p">.</span><span class="k">of</span><span class="p">(</span><span class="dl">'</span><span class="s1">type Author {</span><span class="dl">'</span><span class="p">),</span> <span class="nx">R</span><span class="p">.</span><span class="k">of</span><span class="p">(</span><span class="dl">'</span><span class="s1">}</span><span class="dl">'</span><span class="p">)),</span> 
  <span class="nx">R</span><span class="p">.</span><span class="nx">join</span><span class="p">(</span><span class="dl">'</span><span class="se">\n</span><span class="dl">'</span><span class="p">),</span>
  <span class="nx">R</span><span class="p">.</span><span class="nx">map</span><span class="p">(</span><span class="nx">field</span> <span class="o">=&gt;</span> <span class="s2">`  </span><span class="p">${</span><span class="nx">field</span><span class="p">}</span><span class="s2">`</span><span class="p">),</span>
  <span class="nx">R</span><span class="p">.</span><span class="k">of</span><span class="p">,</span>
  <span class="nx">authorFields</span>
<span class="p">);</span>
</code></pre></div></div>

<p>By constructing the types separately like this, we make them reusable composable units.</p>

<p>Assembling Our Schema
Now let’s put together the full schema by composing the parts:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">schema</span> <span class="o">=</span> <span class="nx">R</span><span class="p">.</span><span class="nx">join</span><span class="p">(</span><span class="dl">'</span><span class="se">\n\n</span><span class="dl">'</span><span class="p">,</span> <span class="p">[</span>
  <span class="nx">BookType</span><span class="p">,</span>
  <span class="nx">AuthorType</span><span class="p">,</span>
  <span class="s2">`type Query {
    books: [Book]
  }`</span>  
<span class="p">])</span>
</code></pre></div></div>

<p>We can now pass this schema string to Apollo Server to build our GraphQL API.</p>

<p>Evolving the Schema
Need to add a new type? Just compose it separately like our existing types and add it to the schema composition.</p>

<p>Want to add a new field to Book? Simply add it to the R.of() call where we define the Book fields.</p>

<p>By using Ramda to compose our schema in this way, we’ve built a flexible foundation that makes schema changes painless. The schema can grow as our API evolves without duplication or tight coupling.</p>

<p>Functional programming gives us the ability to treat our schema as we would any other code - as small reusable composable parts that can change independently. This technique can streamline both early development and long term maintenance of a GraphQL API.</p>]]></content><author><name>Fakhruddin Abdi</name></author><category term="blog" /><category term="Functional Programming" /><category term="GraphQL" /><category term="Ramda" /><category term="Schema" /><summary type="html"><![CDATA[Use Ramda FP to build modular, evolvable GraphQL schemas.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://fakhruddin.info/assets/images/blogs/ramda/logo.png" /><media:content medium="image" url="https://fakhruddin.info/assets/images/blogs/ramda/logo.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">The Quran - An Ancient Blockchain?</title><link href="https://fakhruddin.info/quran_blockchain/" rel="alternate" type="text/html" title="The Quran - An Ancient Blockchain?" /><published>2023-08-23T08:00:00+00:00</published><updated>2023-08-23T08:00:00+00:00</updated><id>https://fakhruddin.info/quran_blockchain</id><content type="html" xml:base="https://fakhruddin.info/quran_blockchain/"><![CDATA[<p><img style="width: 100%" src="/assets/images/blogs/quran/quran.jpg" /></p>

<p>The Quran states that it is the unchanged word of God, revealed to the Prophet Muhammad over 1400 years ago. As technology has advanced, an interesting parallel can be drawn between the protection of the Quran’s text and the security mechanisms of blockchain technology.</p>

<p>Blockchains rely on a distributed network of entities, each holding an identical copy of the ledger. This makes altering the ledger very difficult, as changes would need to be made across all copies.</p>

<p>Similarly, the Quran’s integrity is maintained through the vast number of Muslims who have memorized it word-for-word over the centuries. This tradition of memorizing the entire Quran is highly encouraged and rewarded in Islam. Just as blockchain networks incentivize mining to confirm transactions, Islam incentivizes memorization to preserve the Quran.</p>

<p>There are millions of “Hafez” (people who have memorized the entire Quran) worldwide. Even if all physical copies of the Quran were hypothetically altered, the true text would still be preserved in the minds of Hafez around the globe. This demonstrates how Islamic tradition mimics blockchain technology’s distributed redundancy to protect against unauthorized changes.</p>

<p>While the verification mechanisms differ, the end result is the same - an immutable document preserved across a decentralized network. The Quran’s perseverance over centuries, even before the invention of the printing press or digital storage, is a testament to the power of distributed information. Just like Bitcoin’s code, the Quran’s text has remained intact throughout history, demonstrating how ancient religions used some of the same principles as modern blockchain technology.</p>]]></content><author><name>Fakhruddin Abdi</name></author><category term="blog" /><category term="blockchain" /><category term="quran" /><category term="ai" /><category term="technology" /><summary type="html"><![CDATA[The Quran's preservation through memorization by millions of Muslims mirrors the immutable ledger of blockchain technology.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://fakhruddin.info/assets/images/blogs/quran/logo.jpg" /><media:content medium="image" url="https://fakhruddin.info/assets/images/blogs/quran/logo.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Dynamic GraphQL Schema Generation</title><link href="https://fakhruddin.info/dynamic-graphql-schema/" rel="alternate" type="text/html" title="Dynamic GraphQL Schema Generation" /><published>2023-08-01T10:00:00+00:00</published><updated>2023-08-01T10:00:00+00:00</updated><id>https://fakhruddin.info/dynamic-graphql-schema</id><content type="html" xml:base="https://fakhruddin.info/dynamic-graphql-schema/"><![CDATA[<p>In the <strong>NDB project</strong>, we faced a significant challenge early in development: uncertainty regarding the final GraphQL schema. Initial requirements and specifications were fluid, and it was clear that the schema would undergo constant changes as the project evolved.</p>

<p>After careful consideration and evaluation of the change costs and potential impacts, we identified that the GraphQL schema, along with its queries, mutations, and resolvers, would be the primary components affected by these continuous modifications. Manually updating the entire cycle from schema definition to resolvers for every change would consume a significant amount of time and effort, leading to development bottlenecks and potential errors.</p>

<p>To address this, I decided to build a dynamic system that could convert a static, hard-coded, and unmanageable GraphQL schema into a JavaScript object. This approach allowed for easy updates and management of the schema definitions through scripts.</p>

<p>I developed a generator that consumes this JavaScript object as input and automatically generates the GraphQL schema and resolvers. This automated process drastically reduced the time and complexity associated with schema evolution, allowing us to adapt quickly to changing requirements without extensive manual refactoring.</p>

<p>Here are some examples of the code used in the generator:</p>

<h3 id="model-fields-generation">Model Fields Generation</h3>

<p>This utility function generates standard GraphQL fields for a given model, including <code class="language-plaintext highlighter-rouge">id</code>, a single <code class="language-plaintext highlighter-rouge">model</code> instance, and a list of <code class="language-plaintext highlighter-rouge">models</code>.</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">export</span> <span class="kd">const</span> <span class="nx">generateModelFields</span> <span class="o">=</span> <span class="p">(</span><span class="nx">modelName</span><span class="p">:</span> <span class="nx">string</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span>
  <span class="kd">const</span> <span class="nx">_modelName</span> <span class="o">=</span> <span class="nx">toLowercaseUnderscore</span><span class="p">(</span><span class="nx">modelName</span><span class="p">)</span>
  <span class="kd">const</span> <span class="nx">modelId</span> <span class="o">=</span> <span class="p">{</span>
    <span class="na">name</span><span class="p">:</span> <span class="s2">`</span><span class="p">${</span><span class="nx">_modelName</span><span class="p">}</span><span class="s2">_id`</span><span class="p">,</span>
    <span class="na">type</span><span class="p">:</span> <span class="dl">'</span><span class="s1">ID</span><span class="dl">'</span><span class="p">,</span>
    <span class="na">isRequired</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
    <span class="c1">// ... other properties ...</span>
  <span class="p">};</span>

  <span class="kd">const</span> <span class="nx">model</span> <span class="o">=</span> <span class="p">{</span>
    <span class="na">name</span><span class="p">:</span> <span class="nx">modelName</span><span class="p">,</span>
    <span class="na">type</span><span class="p">:</span> <span class="nx">modelName</span><span class="p">,</span>
    <span class="c1">// ... other properties ...</span>
  <span class="p">};</span>

  <span class="kd">const</span> <span class="nx">models</span> <span class="o">=</span> <span class="p">{</span>
    <span class="na">name</span><span class="p">:</span> <span class="s2">`</span><span class="p">${</span><span class="nx">_modelName</span><span class="p">}</span><span class="s2">s`</span><span class="p">,</span>
    <span class="na">type</span><span class="p">:</span> <span class="nx">modelName</span><span class="p">,</span>
    <span class="na">isRequired</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
    <span class="na">isList</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
    <span class="c1">// ... other properties ...</span>
  <span class="p">};</span>

  <span class="k">return</span> <span class="p">{</span> <span class="nx">modelId</span><span class="p">,</span> <span class="nx">model</span><span class="p">,</span> <span class="nx">models</span> <span class="p">};</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="middleware-for-resolvers">Middleware for Resolvers</h3>

<p>These middleware functions provide common functionalities like logging, user creation, and payment processing, which can be easily plugged into resolvers.</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">createMiddleware</span> <span class="o">=</span> <span class="p">(</span>
  <span class="nx">func</span><span class="p">:</span> <span class="p">(</span><span class="nx">args</span><span class="p">:</span> <span class="nx">Args</span><span class="p">,</span> <span class="nx">context</span><span class="p">:</span> <span class="nx">Context</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="nb">Promise</span><span class="o">&lt;</span><span class="nx">any</span><span class="o">&gt;</span><span class="p">,</span>
<span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span>
  <span class="k">return</span> <span class="k">async</span> <span class="p">({</span> <span class="nx">parent</span><span class="p">,</span> <span class="nx">args</span><span class="p">,</span> <span class="nx">context</span><span class="p">,</span> <span class="nx">info</span><span class="p">,</span> <span class="nx">params</span> <span class="p">}:</span> <span class="nx">ResolverFuncArgs</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span>
    <span class="kd">const</span> <span class="nx">newArgs</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">func</span><span class="p">(</span><span class="nx">args</span><span class="p">,</span> <span class="nx">context</span><span class="p">);</span>
    <span class="k">return</span> <span class="p">{</span> <span class="nx">parent</span><span class="p">,</span> <span class="na">args</span><span class="p">:</span> <span class="nx">newArgs</span><span class="p">,</span> <span class="nx">context</span><span class="p">,</span> <span class="nx">info</span><span class="p">,</span> <span class="nx">params</span> <span class="p">};</span>
  <span class="p">};</span>
<span class="p">};</span>

<span class="kd">const</span> <span class="nx">_logData</span> <span class="o">=</span> <span class="p">(</span><span class="nx">args</span><span class="p">:</span> <span class="nx">Args</span><span class="p">,</span> <span class="nx">context</span><span class="p">:</span> <span class="nx">Context</span><span class="p">):</span> <span class="nb">Promise</span><span class="o">&lt;</span><span class="nx">Args</span><span class="o">&gt;</span> <span class="o">=&gt;</span> <span class="p">{</span>
  <span class="k">return</span> <span class="nb">Promise</span><span class="p">.</span><span class="nx">resolve</span><span class="p">(</span><span class="nx">args</span><span class="p">);</span>
<span class="p">};</span>

<span class="k">export</span> <span class="p">{</span>
  <span class="nx">createCognitoUser</span><span class="p">,</span> <span class="nx">createPayment</span><span class="p">,</span> <span class="nx">deleteCognitoUser</span><span class="p">,</span> <span class="nx">findUser</span><span class="p">,</span> <span class="nx">logData</span>
<span class="p">};</span>
</code></pre></div></div>

<h3 id="type-generation-utilities">Type Generation Utilities</h3>

<p>These functions are crucial for programmatically constructing GraphQL types and queries from the JavaScript object representation.</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">export</span> <span class="kd">const</span> <span class="nx">combineTypeAndAttributes</span> <span class="o">=</span> <span class="p">(</span><span class="nx">list</span><span class="p">:</span> <span class="nx">any</span><span class="p">,</span> <span class="nx">name</span><span class="p">:</span> <span class="nx">string</span><span class="p">)</span> <span class="o">=&gt;</span>
  <span class="s2">`type </span><span class="p">${</span><span class="nx">name</span><span class="p">}</span><span class="s2"> {\n</span><span class="p">${</span><span class="nx">list</span><span class="p">.</span><span class="nx">join</span><span class="p">(</span><span class="dl">'</span><span class="se">\n</span><span class="dl">'</span><span class="p">)}</span><span class="s2">\n}`</span><span class="p">;</span>

<span class="k">export</span> <span class="kd">const</span> <span class="nx">addIfRequired</span> <span class="o">=</span> <span class="nx">when</span><span class="o">&lt;</span><span class="nx">Field</span><span class="p">,</span> <span class="nx">Field</span><span class="o">&gt;</span><span class="p">(</span><span class="nx">isRequired</span><span class="p">,</span> <span class="nx">addRequired</span><span class="p">);</span>
<span class="k">export</span> <span class="kd">const</span> <span class="nx">addIfList</span> <span class="o">=</span> <span class="nx">when</span><span class="o">&lt;</span><span class="nx">Field</span><span class="p">,</span> <span class="nx">Field</span><span class="o">&gt;</span><span class="p">(</span><span class="nx">isList</span><span class="p">,</span> <span class="nx">addList</span><span class="p">);</span>

<span class="k">export</span> <span class="kd">const</span> <span class="nx">makeType</span> <span class="o">=</span> <span class="nx">compose</span><span class="o">&lt;</span><span class="nx">Field</span><span class="p">[][],</span> <span class="nx">any</span><span class="p">,</span> <span class="nx">any</span><span class="p">,</span> <span class="nx">any</span><span class="p">,</span> <span class="nx">any</span><span class="o">&gt;</span><span class="p">(</span>
  <span class="nx">fromPairs</span><span class="p">,</span>
  <span class="nx">map</span><span class="p">(</span><span class="nx">mapFieldToTuple</span><span class="p">),</span>
  <span class="nx">map</span><span class="p">(</span><span class="nx">addIfRequired</span><span class="p">),</span>
  <span class="nx">map</span><span class="p">(</span><span class="nx">addIfList</span><span class="p">),</span>
<span class="p">);</span>

<span class="k">export</span> <span class="kd">const</span> <span class="nx">generateSchemaType</span> <span class="o">=</span> <span class="p">(</span><span class="nx">fields</span><span class="p">:</span> <span class="nx">Field</span><span class="p">[],</span> <span class="nx">name</span><span class="p">:</span> <span class="nx">string</span><span class="p">)</span> <span class="o">=&gt;</span>
  <span class="nx">compose</span><span class="o">&lt;</span><span class="nx">any</span><span class="p">[],</span> <span class="nx">any</span><span class="p">,</span> <span class="nx">any</span><span class="p">,</span> <span class="nx">any</span><span class="p">,</span> <span class="nx">string</span><span class="o">&gt;</span><span class="p">(</span>
    <span class="p">(</span><span class="nx">list</span><span class="p">:</span> <span class="p">[</span><span class="nx">string</span><span class="p">])</span> <span class="o">=&gt;</span> <span class="nx">combineTypeAndAttributes</span><span class="p">(</span><span class="nx">list</span><span class="p">,</span> <span class="nx">name</span><span class="p">),</span>
    <span class="nx">values</span><span class="p">,</span>
    <span class="nx">mapObjIndexed</span><span class="p">(</span><span class="nx">mapObjToString</span><span class="p">),</span>
    <span class="nx">makeType</span><span class="p">,</span>
  <span class="p">)(</span><span class="nx">fields</span><span class="p">);</span>

<span class="k">export</span> <span class="kd">const</span> <span class="nx">generateSchemaQueries</span> <span class="o">=</span> <span class="nx">compose</span><span class="p">(</span>
  <span class="nx">join</span><span class="p">(</span><span class="dl">'</span><span class="se">\n</span><span class="dl">'</span><span class="p">),</span>
  <span class="nx">map</span><span class="p">(</span><span class="nx">compose</span><span class="p">(</span><span class="nx">genQuery</span><span class="p">,</span> <span class="nx">addReturn</span><span class="p">,</span> <span class="nx">addArgs</span><span class="p">)),</span>
<span class="p">);</span>
</code></pre></div></div>

<h3 id="payment-type-definition">Payment Type Definition</h3>

<p>For example, for the <code class="language-plaintext highlighter-rouge">Payment</code> type, we define its fields as a JavaScript object. This allows for a clear and programmatic way to manage the schema’s structure.</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="p">{</span> <span class="nx">basicFields</span><span class="p">,</span> <span class="nx">providerPayment</span><span class="p">,</span> <span class="nx">user</span><span class="p">,</span> <span class="nx">userId</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">../sharedFields.js</span><span class="dl">'</span><span class="p">;</span>
<span class="k">import</span> <span class="p">{</span> <span class="nx">Field</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">../../__types__/models.js</span><span class="dl">'</span><span class="p">;</span>

<span class="kd">const</span> <span class="nx">amount</span> <span class="o">=</span> <span class="p">{</span>
  <span class="na">name</span><span class="p">:</span> <span class="dl">'</span><span class="s1">amount</span><span class="dl">'</span><span class="p">,</span>
  <span class="na">type</span><span class="p">:</span> <span class="dl">'</span><span class="s1">Int</span><span class="dl">'</span><span class="p">,</span>
  <span class="na">isRequired</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
  <span class="c1">// ... other properties ...</span>
<span class="p">};</span>

<span class="k">export</span> <span class="kd">const</span> <span class="nx">fields</span><span class="p">:</span> <span class="nx">Field</span><span class="p">[]</span> <span class="o">=</span> <span class="p">[</span>
  <span class="p">...</span><span class="nx">basicFields</span><span class="p">,</span>
  <span class="c1">// ... other fields ...</span>
<span class="p">];</span>
</code></pre></div></div>

<h3 id="payment-queries-and-mutations">Payment Queries and Mutations</h3>

<p>Building upon the field definitions, we then define the GraphQL queries and mutations for the <code class="language-plaintext highlighter-rouge">Payment</code> type. Each query and mutation is also represented as a JavaScript object, specifying its name, associated model, type (query/mutation), API function, data source, input arguments, expected output, and any middleware to be applied.</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="p">{</span> <span class="nx">logData</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">../generators/middleWares.js</span><span class="dl">'</span><span class="p">;</span>
<span class="k">import</span> <span class="p">{</span> <span class="nx">id</span><span class="p">,</span> <span class="nx">listMetadata</span><span class="p">,</span> <span class="nx">payment</span><span class="p">,</span> <span class="nx">payments</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">../sharedFields.js</span><span class="dl">'</span><span class="p">;</span>
<span class="k">import</span> <span class="p">{</span> <span class="nx">amount</span><span class="p">,</span> <span class="nx">filter</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">./paymentFields.js</span><span class="dl">'</span><span class="p">;</span>

<span class="kd">const</span> <span class="nx">allPayments</span> <span class="o">=</span> <span class="p">{</span>
  <span class="na">name</span><span class="p">:</span> <span class="dl">'</span><span class="s1">allPayments</span><span class="dl">'</span><span class="p">,</span>
  <span class="na">model</span><span class="p">:</span> <span class="dl">'</span><span class="s1">Payment</span><span class="dl">'</span><span class="p">,</span>
  <span class="na">type</span><span class="p">:</span> <span class="dl">'</span><span class="s1">query</span><span class="dl">'</span><span class="p">,</span>
  <span class="na">apiFunc</span><span class="p">:</span> <span class="dl">'</span><span class="s1">getRecords</span><span class="dl">'</span><span class="p">,</span>
  <span class="na">dataSource</span><span class="p">:</span> <span class="dl">'</span><span class="s1">ndbApi</span><span class="dl">'</span><span class="p">,</span>
  <span class="na">input</span><span class="p">:</span> <span class="p">[</span><span class="cm">/* ... input fields ... */</span><span class="p">],</span>
  <span class="na">output</span><span class="p">:</span> <span class="nx">payments</span><span class="p">,</span>
  <span class="na">middlewares</span><span class="p">:</span> <span class="p">[],</span>
<span class="p">};</span>

<span class="kd">const</span> <span class="nx">createPayment</span> <span class="o">=</span> <span class="p">{</span>
  <span class="na">name</span><span class="p">:</span> <span class="dl">'</span><span class="s1">createPayment</span><span class="dl">'</span><span class="p">,</span>
  <span class="na">model</span><span class="p">:</span> <span class="dl">'</span><span class="s1">Payment</span><span class="dl">'</span><span class="p">,</span>
  <span class="na">type</span><span class="p">:</span> <span class="dl">'</span><span class="s1">mutation</span><span class="dl">'</span><span class="p">,</span>
  <span class="na">apiFunc</span><span class="p">:</span> <span class="dl">'</span><span class="s1">createRecord</span><span class="dl">'</span><span class="p">,</span>
  <span class="na">dataSource</span><span class="p">:</span> <span class="dl">'</span><span class="s1">ndbApi</span><span class="dl">'</span><span class="p">,</span>
  <span class="na">input</span><span class="p">:</span> <span class="p">[</span><span class="nx">amount</span><span class="p">,</span> <span class="nx">model_id</span><span class="p">(</span><span class="dl">'</span><span class="s1">user</span><span class="dl">'</span><span class="p">)],</span>
  <span class="na">output</span><span class="p">:</span> <span class="nx">payment</span><span class="p">,</span>
  <span class="na">middlewares</span><span class="p">:</span> <span class="p">[</span><span class="nx">logData</span><span class="p">],</span>
<span class="p">};</span>

<span class="k">export</span> <span class="kd">const</span> <span class="nx">queries</span> <span class="o">=</span> <span class="p">[</span>
  <span class="nx">allPayments</span><span class="p">,</span>
  <span class="c1">// ... other queries and mutations ...</span>
<span class="p">];</span>
</code></pre></div></div>

<h3 id="schema-integration">Schema Integration</h3>

<p>These dynamically generated types, queries, and mutations are then imported and composed into the main GraphQL schema definition using template literals, providing a flexible and maintainable structure.</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="p">{</span> <span class="nx">gql</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">apollo-server</span><span class="dl">'</span><span class="p">;</span>
<span class="k">import</span> <span class="p">{</span> <span class="nx">userQuery</span><span class="p">,</span> <span class="nx">userMutation</span><span class="p">,</span> <span class="nx">userType</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">../models/user/index.js</span><span class="dl">'</span><span class="p">;</span>
<span class="k">import</span> <span class="p">{</span> <span class="nx">paymentQuery</span><span class="p">,</span> <span class="nx">paymentMutation</span><span class="p">,</span> <span class="nx">paymentType</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">../models/payment/index.js</span><span class="dl">'</span><span class="p">;</span>
<span class="c1">// ... other imports ...</span>

<span class="kd">const</span> <span class="nx">typeDefs</span> <span class="o">=</span> <span class="nx">gql</span><span class="s2">`
  type Query {
    </span><span class="p">${</span><span class="nx">userQuery</span><span class="p">}</span><span class="s2">
    </span><span class="p">${</span><span class="nx">paymentQuery</span><span class="p">}</span><span class="s2">
    // ... other queries ...
  }

  type Mutation {
    </span><span class="p">${</span><span class="nx">paymentMutation</span><span class="p">}</span><span class="s2">
    // ... other mutations ...
  }
  
  </span><span class="p">${</span><span class="nx">paymentType</span><span class="p">}</span><span class="s2">
  </span><span class="p">${</span><span class="nx">userType</span><span class="p">}</span><span class="s2">
  // ... other types ...

  </span><span class="p">${</span><span class="nx">inputs</span><span class="p">.</span><span class="nx">map</span><span class="p">((</span><span class="nx">input</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="s2">`</span><span class="p">${</span><span class="nx">input</span><span class="p">}</span><span class="s2"> \n`</span><span class="p">)}</span><span class="s2">
`</span><span class="p">;</span>

<span class="k">export</span> <span class="p">{</span> <span class="nx">typeDefs</span> <span class="p">};</span>
</code></pre></div></div>

<h3 id="resolvers-integration">Resolvers Integration</h3>

<p>Similarly, the resolvers for each model (queries, mutations, and relation resolvers) are imported and combined into a single <code class="language-plaintext highlighter-rouge">resolvers</code> object. This modular approach ensures that each part of the schema can be developed and managed independently while seamlessly integrating into the overall GraphQL API.</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="p">{</span>
  <span class="nx">paymentQueryResolvers</span><span class="p">,</span>
  <span class="nx">paymentMutationesolvers</span><span class="p">,</span>
  <span class="nx">paymentRelationResolvers</span> <span class="k">as</span> <span class="nx">Payment</span><span class="p">,</span>
<span class="p">}</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">../models/payment/index.js</span><span class="dl">'</span><span class="p">;</span>
<span class="k">import</span> <span class="p">{</span>
  <span class="nx">userQueryResolvers</span><span class="p">,</span>
  <span class="nx">userMutationResolvers</span><span class="p">,</span>
  <span class="nx">userRelationResolvers</span> <span class="k">as</span> <span class="nx">User</span><span class="p">,</span>
<span class="p">}</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">../models/user/index.js</span><span class="dl">'</span><span class="p">;</span>
<span class="c1">// ... other imports ...</span>

<span class="kd">const</span> <span class="nx">resolvers</span><span class="p">:</span> <span class="nx">any</span> <span class="o">=</span> <span class="p">{</span>
  <span class="na">Query</span><span class="p">:</span> <span class="p">{</span>
    <span class="p">...</span><span class="nx">paymentQueryResolvers</span><span class="p">,</span>
    <span class="p">...</span><span class="nx">userQueryResolvers</span><span class="p">,</span>
    <span class="c1">// ... other query resolvers ...</span>
  <span class="p">},</span>
  <span class="na">Mutation</span><span class="p">:</span> <span class="p">{</span>
    <span class="p">...</span><span class="nx">paymentMutationesolvers</span><span class="p">,</span>
    <span class="c1">// ... other mutation resolvers ...</span>
  <span class="p">},</span>
  <span class="nx">Payment</span><span class="p">,</span>
  <span class="nx">User</span><span class="p">,</span>
  <span class="c1">// ... other relation resolvers ...</span>
<span class="p">};</span>

<span class="k">export</span> <span class="p">{</span> <span class="nx">resolvers</span> <span class="p">};</span>
</code></pre></div></div>

<h3 id="conclusion">Conclusion</h3>

<p>This dynamic schema generation approach has been instrumental in managing the evolving requirements of the NDB project. It has allowed us to maintain a flexible and maintainable GraphQL schema, while also reducing the time and effort required to update the schema as the project evolves.</p>]]></content><author><name>Fakhruddin Abdi</name></author><category term="blog" /><category term="graphql" /><category term="code-generation" /><category term="ndb" /><category term="node.js" /><category term="prisma" /><summary type="html"><![CDATA[How we tackled evolving GraphQL schemas in the NDB project with a dynamic code generator.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://fakhruddin.info/assets/images/projects/ndb/banner.png" /><media:content medium="image" url="https://fakhruddin.info/assets/images/projects/ndb/banner.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Automating Scripts with GPT-4</title><link href="https://fakhruddin.info/chatgpt_script/" rel="alternate" type="text/html" title="Automating Scripts with GPT-4" /><published>2023-06-08T08:00:00+00:00</published><updated>2023-06-08T08:00:00+00:00</updated><id>https://fakhruddin.info/chatgpt_script</id><content type="html" xml:base="https://fakhruddin.info/chatgpt_script/"><![CDATA[<p><img style="width: 100%" src="/assets/images/blogs/script/banner.png" /></p>

<p>In the field of Artificial Intelligence, one model that has raised the bar for natural language understanding and generation is GPT-4, the latest iteration in OpenAI’s Generative Pretrained Transformer series.</p>

<h2 id="what-is-gpt-4">What is GPT-4?</h2>

<p>GPT-4 is a large-scale transformer-based language model that builds on its predecessors to offer even more impressive language capabilities. It has been trained on a diverse range of internet text, making it an impressive tool for tasks involving natural language understanding and generation.</p>

<h2 id="automating-bash-scripting-with-gpt-4">Automating Bash Scripting with GPT-4</h2>

<p>One exciting application of GPT-4 is in the area of bash scripting and automation. Through its ability to comprehend complex requirements and generate corresponding scripts, GPT-4 can assist developers in automating routine tasks, boosting productivity and efficiency.</p>

<p>Let’s take the example of a developer needing a script to set up a server, install necessary software, clone repositories, create directories and files, and configure settings. Instead of manually writing every line of code, the developer can simply provide GPT-4 with the necessary requirements and it will generate a bash script accordingly.</p>

<p>Here is an example of such a script generated by ChatGPT-4:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#!/bin/bash</span>

<span class="c"># Check if Docker is installed</span>
<span class="k">if</span> <span class="o">!</span> <span class="nb">command</span> <span class="nt">-v</span> docker &amp;&gt; /dev/null<span class="p">;</span> <span class="k">then
    </span>curl <span class="nt">-fsSL</span> https://get.docker.com <span class="nt">-o</span> get-docker.sh
    sh get-docker.sh
<span class="k">else
    </span><span class="nb">echo</span> <span class="s2">"Docker is already installed, skipping..."</span>
<span class="k">fi</span>

<span class="c"># Install Docker Compose</span>
<span class="k">if</span> <span class="o">[</span> <span class="o">!</span> <span class="nt">-f</span> /usr/local/bin/docker-compose <span class="o">]</span><span class="p">;</span> <span class="k">then
    </span>curl <span class="nt">-L</span> <span class="s2">"https://github.com/docker/compose/releases/download/1.27.4/docker-compose-</span><span class="si">$(</span><span class="nb">uname</span> <span class="nt">-s</span><span class="si">)</span><span class="s2">-</span><span class="si">$(</span><span class="nb">uname</span> <span class="nt">-m</span><span class="si">)</span><span class="s2">"</span> <span class="nt">-o</span> /usr/local/bin/docker-compose
    <span class="nb">chmod</span> +x /usr/local/bin/docker-compose
<span class="k">else
    </span><span class="nb">echo</span> <span class="s2">"Docker Compose is already installed, skipping..."</span>
<span class="k">fi</span>

<span class="c"># Install Git</span>
<span class="k">if</span> <span class="o">!</span> <span class="nb">command</span> <span class="nt">-v</span> git &amp;&gt; /dev/null<span class="p">;</span> <span class="k">then
    </span>yum <span class="nb">install</span> <span class="nt">-y</span> git
<span class="k">else
    </span><span class="nb">echo</span> <span class="s2">"Git is already installed, skipping..."</span>
<span class="k">fi</span>

<span class="c"># Check if Apache is installed</span>
<span class="k">if </span><span class="nb">command</span> <span class="nt">-v</span> httpd &amp;&gt; /dev/null<span class="p">;</span> <span class="k">then
    </span><span class="nb">echo</span> <span class="s2">"Apache is installed, removing..."</span>
    yum remove <span class="nt">-y</span> httpd
<span class="k">else
    </span><span class="nb">echo</span> <span class="s2">"Apache is not installed, skipping..."</span>
<span class="k">fi</span>

<span class="c"># Check if Nginx is installed</span>
<span class="k">if </span><span class="nb">command</span> <span class="nt">-v</span> nginx &amp;&gt; /dev/null<span class="p">;</span> <span class="k">then
    </span><span class="nb">echo</span> <span class="s2">"Nginx is installed, removing..."</span>
    yum remove <span class="nt">-y</span> nginx
<span class="k">else
    </span><span class="nb">echo</span> <span class="s2">"Nginx is not installed, skipping..."</span>
<span class="k">fi</span>

<span class="c"># Git credentials setup</span>
<span class="nb">echo</span> <span class="nt">-n</span> <span class="s2">"Enter your git username: "</span>
<span class="nb">read </span>username
<span class="nb">echo</span> <span class="nt">-n</span> <span class="s2">"Enter your git password: "</span>
<span class="nb">read</span> <span class="nt">-s</span> password
<span class="nb">echo</span> <span class="s2">""</span>

<span class="c"># Store git credentials</span>
git config <span class="nt">--global</span> credential.helper store
<span class="nb">echo</span> <span class="s2">"https://</span><span class="k">${</span><span class="nv">username</span><span class="k">}</span><span class="s2">:</span><span class="k">${</span><span class="nv">password</span><span class="k">}</span><span class="s2">@github.com"</span> <span class="o">&gt;</span> ~/.git-credentials

<span class="c"># Create /odoo repository</span>
<span class="k">if</span> <span class="o">[</span> <span class="o">!</span> <span class="nt">-d</span> <span class="s2">"/odoo"</span> <span class="o">]</span><span class="p">;</span> <span class="k">then
    </span><span class="nb">mkdir</span> /odoo
<span class="k">fi
</span><span class="nb">cd</span> /odoo

<span class="c"># Create .env file and set variables</span>
<span class="k">if</span> <span class="o">[</span> <span class="o">!</span> <span class="nt">-f</span> <span class="s2">".env"</span> <span class="o">]</span><span class="p">;</span> <span class="k">then
    </span><span class="nb">echo</span> <span class="nt">-n</span> <span class="s2">"Enter APP_NAME: "</span>
    <span class="nb">read </span>APP_NAME
    <span class="nb">echo</span> <span class="nt">-n</span> <span class="s2">"Enter DOMAIN: "</span>
    <span class="nb">read </span>DOMAIN
    <span class="nb">echo</span> <span class="nt">-n</span> <span class="s2">"Enter TEST_DOMAIN: "</span>
    <span class="nb">read </span>TEST_DOMAIN

    <span class="nb">echo</span> <span class="s2">"APP_NAME=</span><span class="nv">$APP_NAME</span><span class="s2">"</span> <span class="o">&gt;</span> .env
    <span class="nb">echo</span> <span class="s2">"DOMAIN=</span><span class="nv">$DOMAIN</span><span class="s2">"</span> <span class="o">&gt;&gt;</span> .env
    <span class="nb">echo</span> <span class="s2">"TEST_DOMAIN=</span><span class="nv">$TEST_DOMAIN</span><span class="s2">"</span> <span class="o">&gt;&gt;</span> .env
<span class="k">fi</span>

<span class="c"># Clone odoo repository</span>
<span class="k">if</span> <span class="o">[</span> <span class="o">!</span> <span class="nt">-d</span> <span class="s2">"</span><span class="k">${</span><span class="nv">APP_NAME</span><span class="k">}</span><span class="s2">"</span> <span class="o">]</span><span class="p">;</span> <span class="k">then
    </span>git clone https://github.com/FakhruddinAbdi/odoo.git <span class="k">${</span><span class="nv">APP_NAME</span><span class="k">}</span>
<span class="k">else
    </span><span class="nb">echo</span> <span class="s2">"Directory </span><span class="k">${</span><span class="nv">APP_NAME</span><span class="k">}</span><span class="s2"> already exists, skipping git clone"</span>
<span class="k">fi</span>

<span class="c"># Create Docker network</span>
<span class="k">if</span> <span class="o">!</span> docker network <span class="nb">ls</span> | <span class="nb">grep</span> <span class="nt">-q</span> <span class="s1">'web-net'</span><span class="p">;</span> <span class="k">then
    </span>docker network create <span class="nt">--driver</span> bridge web-net
<span class="k">else
    </span><span class="nb">echo</span> <span class="s2">"Docker network web-net already exists, skipping creation"</span>
<span class="k">fi</span>

<span class="c"># Clone traefik repository</span>
<span class="k">if</span> <span class="o">[</span> <span class="o">!</span> <span class="nt">-d</span> <span class="s2">"traefik"</span> <span class="o">]</span><span class="p">;</span> <span class="k">then
    </span>git clone https://github.com/FakhruddinAbdi/traefik.git
<span class="k">else
    </span><span class="nb">echo</span> <span class="s2">"Directory traefik already exists, skipping git clone"</span>
<span class="k">fi</span>

<span class="c"># Navigate into traefik and run make up</span>
<span class="nb">cd </span>traefik
<span class="k">if</span> <span class="o">[</span> <span class="o">!</span> <span class="s2">"</span><span class="si">$(</span> docker container inspect <span class="nt">-f</span> <span class="s1">''</span> traefik <span class="si">)</span><span class="s2">"</span> <span class="o">==</span> <span class="s2">"true"</span> <span class="o">]</span><span class="p">;</span> <span class="k">then
    </span>make up
<span class="k">else
    </span><span class="nb">echo</span> <span class="s2">"Traefik is already up, skipping make up"</span>
<span class="k">fi</span>


</code></pre></div></div>

<p>I generated this script by simply asking GPT-4 to write a bash script that performs the following tasks on a Debian-based server:</p>

<ol>
  <li>Installs Docker, if it isn’t already installed.</li>
  <li>Installs Docker Compose, if it isn’t already installed.</li>
  <li>Installs Git, if it isn’t already installed.</li>
  <li>Removes Apache if it’s installed.</li>
  <li>Configures Git with user-provided credentials.</li>
  <li>Creates a new directory, /odoo, if it doesn’t exist.</li>
  <li>In the /odoo directory, creates a .env file with user-provided variables (APP_NAME, DOMAIN, TEST_DOMAIN) if it doesn’t already exist.</li>
  <li>Clones a repository (https://github.com/FakhruddinAbdi/odoo.git) to a directory named ${APP_NAME} in the /odoo directory. This step is skipped if the directory already exists.</li>
  <li>Creates a Docker network named ‘web-net’, if it doesn’t exist.</li>
  <li>Clones a repository (https://github.com/FakhruddinAbdi/traefik.git) to a directory named ‘traefik’ in the /odoo directory. This step is skipped if the directory already exists.</li>
</ol>

<h2 id="the-advantages">The Advantages</h2>

<p>The generation of this script demonstrates the ability of GPT-4 to understand a range of tasks from installing Docker and Git, checking and removing existing software (like Apache), creating directories and files, cloning repositories, and configuring settings.</p>

<p>Using GPT-4 for bash scripting and automation brings several advantages:</p>

<ol>
  <li>
    <p><strong>Efficiency</strong>: Writing scripts, especially complex ones, can be time-consuming. GPT-4 can significantly cut down the time required by generating scripts based on provided requirements.</p>
  </li>
  <li>
    <p><strong>Accuracy</strong>: Manual scripting can sometimes lead to errors due to oversight. GPT-4 reduces this risk by accurately interpreting requirements and translating them into correct script commands.</p>
  </li>
  <li>
    <p><strong>Learning</strong>: For beginners, understanding how to write scripts can be challenging. GPT-4-generated scripts can serve as examples to learn from.</p>
  </li>
</ol>

<h2 id="conclusion">Conclusion</h2>

<p>The capabilities of GPT-4 go beyond natural language understanding and generation. As demonstrated, it can be an efficient and reliable tool for bash scripting and automation. While it is not a substitute for understanding how to write scripts, it can certainly assist developers in reducing manual work, boosting productivity, and learning more about scripting.</p>]]></content><author><name>Fakhruddin Abdi</name></author><category term="blog" /><category term="AI" /><category term="ChatGPT" /><category term="Automation" /><category term="Bash script" /><summary type="html"><![CDATA[Harnessing the Power of ChatGPT-4 for Bash Scripting and Automation]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://fakhruddin.info/assets/images/blogs/script/logo.png" /><media:content medium="image" url="https://fakhruddin.info/assets/images/blogs/script/logo.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry></feed>