<?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"><channel><title><![CDATA[Learned to Share]]></title><description><![CDATA[Learned to Share]]></description><link>https://tanmaysarkar.hashnode.dev</link><generator>RSS for Node</generator><lastBuildDate>Fri, 23 Feb 2024 08:02:54 GMT</lastBuildDate><atom:link href="https://tanmaysarkar.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><atom:link rel="next" href="https://tanmaysarkar.hashnode.dev/rss.xml?page=1"/><item><title><![CDATA[Get Started with Low-code REST API Development using Syncloop]]></title><description><![CDATA[<h3 id="heading-introduction">Introduction 🙋🏻</h3><p>Hey Champs, this is Tanmay again. And today's topic is a little different, in the sense We are coders but trying to embrace low-code tools also. It is not that we are trying to transition to this kind of tool but to increase productivity as a developer.</p><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1690983677347/fd46e81c-9255-4f90-a1e6-03a23a278fac.webp" alt class="image--center mx-auto" /></p><p>Using this tool, we will remove the repeated same tasks for building a rest API of a low-complexity project. Suppose you are building a health tracking project and you need a simple backend service for performing various logic of available data, in that scenario building a backend server in the project is comparatively time-consuming and hectic.</p><p>And that position, we can use tools like Syncloop to build a Rest API with ease and use it in our project. In that way, we can remove the need for a dedicated backend server and the time of a developer to code a backend.</p><p>With that being said, let's see what are the possibilities with Syncloop.</p><h3 id="heading-overview-of-syncloop">Overview of Syncloop</h3><p>Syncloop is an innovative no-code API service that simplifies the process of creating and managing APIs. With its user-friendly interface, developers and non-developers alike can effortlessly design, deploy, and monitor APIs without writing a single line of code.</p><p>Syncloop offers a wide range of features, including data integration, authentication, and endpoint customization, enabling users to seamlessly connect their applications and services. It's intuitive workflow and robust security measures make it an ideal choice for businesses and individuals seeking a quick and efficient way to build powerful APIs without the complexities of traditional coding.</p><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1690975819557/aae1e9b0-02be-4344-94af-2e6c2d167f38.png" alt class="image--center mx-auto" /></p><h3 id="heading-lets-get-started-with-syncloop">Let's get started with Syncloop 🚀</h3><p>Now I'll walk you through the whole process to build an API which will give us a list of quotes and the authors' names.</p><div data-node-type="callout"><div data-node-type="callout-emoji">💡</div><div data-node-type="callout-text">You will find a short video below of the whole process, because writing it is a little hectic, you will understand better in video maybe. <a target="_blank" href="https://youtu.be/fbCPwcNBsEk">Here</a></div></div><ol><li><p><strong>Create an account with Syncloop:</strong></p><p> Visit <a target="_blank" href="https://www.syncloop.com/">https://www.syncloop.com/</a> and create a free account there. Now log in to the dashboard with your account.</p><p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1690976164515/b8903325-da64-40c8-ad48-d65b712433f8.png" alt class="image--center mx-auto" /></p><p> As you can see, you will find useful resources to understand the tool in their documents and training videos. If you are serious about using it, you should watch and understand the tool more.</p></li><li><p><strong>Head over to Workspace:</strong></p><p> Here in the workspace, we will work. Everything related to building APIs is here.</p><p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1690976392616/a4ed8b8a-fc28-4b89-afc9-c115903a21cb.png" alt class="image--center mx-auto" /></p><p> You will find `packages` there, inside it there are demos and pre-built services. Now maybe you are thinking about what are services.</p> <div data-node-type="callout"> <div data-node-type="callout-emoji">💡</div> <div data-node-type="callout-text">The service in the Syncloop tool behaves like functions in the programming languages. A function is first defined and then called for its proper usage. The main advantage of using services is that it aids in better reusability of program code. Find more about the service <a target="_blank" href="https://www.syncloop.com/workspace-docs/service.html?utm_source=Website&amp;utm_medium=service&amp;utm_id=docs&amp;utm_content=left-menu-bar">here</a>.</div> </div></li><li><p><strong>Create the folders and files:</strong></p><p> <strong>First</strong>, you need to create a dedicated package for our quote API by right-clicking and selecting <em>new.</em></p><p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1690978712265/37cd605f-d951-486b-a8cb-4107b1a2ab68.png" alt /></p><p> <strong>Second</strong>, you'll see the new package <code>quoteAPI</code> with a dependency folder inside it. Now create a folder there. I'm naming it <code>generateQuotes</code></p><p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1690978885894/9e4201a2-f02f-4c9f-bc95-ff2e0f8b3149.png" alt class="image--center mx-auto" /></p><p> <strong>Third</strong>, create a last file which is a service of the API category. And in this file, we will drag and drop stuff to make the quote generation work.</p><p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1690979061341/a9084698-4448-4abb-b7cf-d67f7fc8368e.png" alt class="image--center mx-auto" /></p><blockquote><p>We can use a dedicated database to fetch quotes to our Rest API but I don't want to make this beginner-friendly tutorial more complex. So I will fetch quotes from another free available API and route it to our API, so that we can use our API to fetch quotes but deep inside our API will also fetch the quote from another API.</p></blockquote><p> As you can see there are Consumers and Developers fields, it is for better role-based permissions.</p><p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1690979350732/1ecdc7a5-d364-4be7-9751-e12155ef3d6a.png" alt class="image--center mx-auto" /></p><p> With that, we have created our first API service which has an endpoint that we will use as an API link. Now we have to customize it to our needs. Let us see what to be done now.</p><p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1690980052930/a0cb7c9a-a214-4beb-916f-75a9aa3c2ba1.png" alt class="image--center mx-auto" /></p></li><li><p><strong>Build API Service File:</strong></p><p> You understood the input and output parameters area. Now first we have to use a <strong>Map</strong> or <strong>Transformer</strong> to map flow data in further steps.</p> <div data-node-type="callout"> <div data-node-type="callout-emoji">💡</div> <div data-node-type="callout-text"><strong>Transformer </strong>is a Syncloop term, this is one of the most frequently used statements on the platform. A Transformer statement is created by right-clicking on the control flow section and selecting Transformer from the context menu strip. A Transformer is created in the control flow section of the Syncloop workspace.</div> </div><p> So, right-click on the centre and choose <strong>Transformer</strong>.</p><p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1690980535925/eede4edc-09f5-4636-b052-7bb66acbd674.png" alt class="image--center mx-auto" /></p><p> With that, you will see a new layout. Each transformer has two fields also input and output. You can right-click to create new files or fields there.</p> <div data-node-type="callout"> <div data-node-type="callout-emoji">💡</div> <div data-node-type="callout-text">We plan to make a get request to an existing quote API, get the quotes, convert the quotes from JSON to object and output the response with it.</div> </div><p> First, we are making a transformer with output parameters <code>url</code> with <a target="_blank" href="https://type.fit/api/quotes">https://type.fit/api/quotes</a> and <code>method</code> with <em>GET.</em></p><p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1690980823366/94873247-c009-4153-a722-bbc3f8b9991d.png" alt class="image--center mx-auto" /></p><p> You can just select any parameter and click on the pen icon  to set default values to the parameters. So just set url value and method value.</p><p> With that, you are sure that our transformer is outputting these two parameters.</p><p> <strong>Second</strong>, right-click on the dashboard area and this time select a service and this popup will arise. So without interfering with the pop-up, search in the packages section with '<em>request',</em> select the <em>requestV2</em> and click on Done.</p><p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1690981069026/a4f6374f-48b8-4f48-ba95-372e936518e4.png" alt class="image--center mx-auto" /></p><p> Now we have a transformer and a service in our API in respective order. So the transformer will send its output data to the service now.</p><p> Select the <em>requestV2</em> service in the dashboard, you will see a new layout in the bottom part. You have to just make the route lines just by dragging.</p><p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1690981361311/78594a5a-104a-41b0-8ffa-c940815bc99b.png" alt class="image--center mx-auto" /></p><p> So, url from the previous transformer will go to the <em>requestV2</em> service's URL param and method to method param. And also the service's respPayload to a newly created payload output parameter string.</p><p> Now, create the same name param in the main output section and that param will hold the payload also.</p><p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1690981649891/870a8f87-25c8-417a-8100-f677f438cab3.png" alt class="image--center mx-auto" /></p></li><li><p><strong>Now let's test our API with Postman:</strong></p><p> Before that, extract our API's endpoint by clicking on the configuration icon.</p><p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1690981724721/c5e80f00-045a-4e52-a237-ba841b1d41f4.png" alt class="image--center mx-auto" /></p><p> And, get the bearer token from the sidebar,</p><p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1690981821588/f844cb8c-4098-40c9-8695-b0f95369f587.png" alt class="image--center mx-auto" /></p><p> Now, just put the endpoint of the token in Postman and perform a <em>GET</em> request.</p><p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1690982000752/5b6fba6d-f1fd-4e52-ae71-f9698556b4ec.png" alt class="image--center mx-auto" /></p></li></ol><h3 id="heading-video-solution">Video Solution 📀</h3><p>If you found the article a little confusing, I've got your back too. Watch this video:</p><div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://youtu.be/fbCPwcNBsEk">https://youtu.be/fbCPwcNBsEk</a></div><p> </p><h3 id="heading-conclusion">Conclusion </h3><p>This tool proves especially useful for projects with straightforward backend requirements, eliminating the need for dedicated backend servers and saving valuable time for developers.</p><p>As we wrap up, I hope this blog has sparked your interest in delving into the world of low-code tools. We covered the following topics:</p><ul><li><p>What is <strong>Syncloop</strong>?</p></li><li><p>Who should use it?</p></li><li><p>How to use it.</p></li><li><p>Building a very simple quote-generating API.</p></li></ul><p>I hope this blog has inspired you to get involved in open source also! Because as an active contributor, I stay updated with the community. And I'm writing this blog with the challenge from the WeMakeDevs community. If you have any questions, please feel free to comment or reach out to me on Twitter.</p><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1690983561489/ea69bd84-0910-4eb1-9969-c0fe00ade9ca.webp" alt class="image--center mx-auto" /></p><p>With that have an amazing day, <em>sayonara</em> 👋🏼</p><p>Follow me on <a target="_blank" href="www.twitter.com/sarkartanmay393">@sarkartanmay393</a> 🐦<br />Direct mail me at <a target="_blank" href="http://sarkartanmay393@gmail.com">sarkartanmay393@gmail.com</a> 📧</p>]]></description><link>https://tanmaysarkar.hashnode.dev/get-started-with-no-code-rest-api-building-using-syncloop</link><guid isPermaLink="true">https://tanmaysarkar.hashnode.dev/get-started-with-no-code-rest-api-building-using-syncloop</guid><dc:creator><![CDATA[Tanmay Sarkar]]></dc:creator><pubDate>Wed, 02 Aug 2023 14:43:58 GMT</pubDate><cover_image>https://cdn.hashnode.com/res/hashnode/image/upload/v1690975090026/52f9ac62-9efe-478e-81b2-676c0e4a73a2.jpeg</cover_image></item><item><title><![CDATA[The Ultimate Guide to Finding Your First Open Source Project and Issue as a Beginner]]></title><description><![CDATA[<h3 id="heading-introduction">Introduction 🙋🏻</h3><p>Hey Devs, What's up? Today I'm back with another blog and it's mainly for beginners in Open Source. You might be trying to get involved in Open Source but you don't have any heads-up. For that reason, you should read it to the end.</p><p>Open source is a great way to learn new skills, meet new people, give back to the community, and definitely, the journey will be fruitful for you. As you're new to open source, you might be wondering where to start. One of the best ways to get involved is to find and fix a <em>good first issue</em>.</p><p>A good first issue is a bug or feature request that is relatively easy to fix and doesn't require in-depth prior knowledge of the project. These issues are a great way to get your train rolling in open source and make a meaningful contribution.</p><p>I'll be mentioning some best places where you can find your first open-source issue in your comfortable tech stack.</p><h3 id="heading-before-you-move-forward">Before you move forward</h3><p>I want to talk about who should read this article and find an issue for themself. Obviously, who has practical knowledge of any tech stack (e.g. web development) and knows that he/she can contribute to other similar projects. After satisfying this requirement and only then you should search for projects.</p><p><img src="https://media0.giphy.com/media/VJHGm6V1szmCTrGJSl/giphy.gif?cid=ecf05e47squyric87mad08ey31q4oym824tehzndyjh5o8yc&amp;ep=v1_gifs_search&amp;rid=giphy.gif&amp;ct=g" alt class="image--center mx-auto" /></p><div data-node-type="callout"><div data-node-type="callout-emoji">💡</div><div data-node-type="callout-text"><strong>Tech Stack: </strong>A tech stack is a set of technologies that work together to create a software application. If you are new to software development, it can be helpful to start with a popular tech stack. This will give you access to a large community of developers who can help you to get started (e.g. MEAN, Ruby on Rails, Django).</div></div><p>As I'm currently into web development with MERN, TypeScript, Next.js, etc. So I can find a web project built with any of these technologies and I'm good to go with contributing to that project.</p><p>Some might be:</p><ol><li><p><a target="_blank" href="https://github.com/layer5io/layer5">https://github.com/layer5io/layer5</a></p></li><li><p><a target="_blank" href="https://github.com/meshery/meshery.io">https://github.com/meshery/meshery.io</a></p></li><li><p><a target="_blank" href="https://github.com/InternetHealthReport/ihr-website">https://github.com/InternetHealthReport/ihr-website</a></p></li></ol><h3 id="heading-lets-find-an-issue-for-you">Let's find an issue for you 🙌</h3><p>Here are some of the best ways:</p><ul><li><p><strong>GitHub:</strong> GitHub is the most popular website for hosting open-source projects. You can find good first issues by searching for the <code>good-first-issue</code> label.</p><p>  In the GitHub search bar, enter the following query:</p><p>  <code>is:issue is:open label:"good first issue" label:"your-tech-stack"</code></p><p>  Replace <code>your-tech-stack</code> with the name of your specific tech stack or programming language. For example, if you are working with JavaScript, you would use <code>label:"javascript"</code></p><p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1689787491678/74b44cbc-6a8b-4062-9136-4c3fccae3bcc.png" alt class="image--center mx-auto" /></p><p>  <img src alt class="image--center mx-auto" /></p></li><li><p><strong>Good First Issue:</strong> This is a website that curates good first issues from popular open-source projects. They have a search engine that lets you filter issues by language, framework, and other criteria. They are totally elegant looking.</p><p>  Here: <a target="_blank" href="https://goodfirstissue.dev/">https://goodfirstissue.dev/</a></p></li><li><p><strong>Up for Grabs:</strong> Up for Grabs is also a website but it lists open-source projects that are looking for contributors. They have a section for good first issues, as well as a forum where you can ask questions and get help from other contributors.<br />  Here: <a target="_blank" href="https://up-for-grabs.net/#/filters?tags=reactjs&amp;date=1week">https://up-for-grabs.net/</a></p></li><li><p><strong>First Timers Only:</strong> Last but not least, First Timers Only is a website that helps new contributors find open-source projects that are welcoming to first-timers. They have a list of projects with good first issues, as well as tutorials and resources to help you get started. You should head over to their <a target="_blank" href="https://www.firsttimersonly.com/">website</a> sometime.</p></li></ul><p>Once you've found a good first issue, you can start working on it. The first step is to make sure that you understand the issue. Read the issue description carefully and ask questions if you're not sure what it means.</p><p>Once you understand the issue, you can start working on a fix. If you're not sure how to fix the issue, you can ask for help from the project maintainers or other contributors.</p><p>Once you've fixed the issue, you can submit a pull request. A pull request is a way of submitting your changes to the project's codebase.</p><p>The project maintainers will review your pull request and either approve it or reject it. If your pull request is approved, your changes will be merged into the project's codebase.</p><p><img src="https://media3.giphy.com/media/XuogjQPxfosnK/giphy.gif?cid=ecf05e478ycbsalzmc861ce1pcug892ela6aamnmukvh57m0&amp;ep=v1_gifs_search&amp;rid=giphy.gif&amp;ct=g" alt class="image--center mx-auto" /></p><div data-node-type="callout"><div data-node-type="callout-emoji">💡</div><div data-node-type="callout-text">It's better to fix the issue and raise the Pull Request first. Asking for assigning the issue not gonna, just check if someone is already working on it currently.</div></div><p>If you're new to open source, I encourage you to find a good first issue and start contributing today!</p><h3 id="heading-conclusion">Conclusion </h3><p>In this blog, we discussed how to find and fix your first open-source issue. We covered the following topics:</p><ul><li><p>Who should read this article and find an issue for themselves.</p></li><li><p>What is a tech stack?</p></li><li><p>How to find good first issues on GitHub, Good First Issue, and Up for Grabs.</p></li><li><p>How to submit a pull request and never wait for getting assigned in issues.</p></li></ul><p>I hope this blog has inspired you to get involved in open source! If you have any questions, please feel free to comment or reach out to me on Twitter.</p><p><strong>Here are some additional tips for you:</strong></p><ul><li><p><strong>Start small.</strong> Don't try to fix a big issue on your first try. Start with something small and easy to understand.</p></li><li><p><strong>Be patient.</strong> It may take some time for your pull request to be approved. Don't get discouraged if it doesn't happen right away.</p></li><li><p><strong>Be helpful.</strong> If you see someone else struggling with an issue, offer to help them.</p></li><li><p><strong>Have fun!</strong> Open source is a great way to learn new things and meet new people. So enjoy the process!</p></li></ul><p><img src="https://media.giphy.com/media/zAYZOtH5OMhuU/giphy.gif" alt class="image--center mx-auto" /></p><p>With that have a great day, <em>sayonara</em> 👋🏼</p><p>Follow me on <a target="_blank" href="www.twitter.com/sarkartanmay393">@sarkartanmay393</a> 🐦<br />Direct mail me at <a target="_blank" href="http://sarkartanmay393@gmail.com">sarkartanmay393@gmail.com</a> 📧</p>]]></description><link>https://tanmaysarkar.hashnode.dev/ultimate-guide-to-find-first-open-source-issue</link><guid isPermaLink="true">https://tanmaysarkar.hashnode.dev/ultimate-guide-to-find-first-open-source-issue</guid><dc:creator><![CDATA[Tanmay Sarkar]]></dc:creator><pubDate>Thu, 20 Jul 2023 05:40:11 GMT</pubDate><cover_image>https://cdn.hashnode.com/res/hashnode/image/upload/v1689830633955/4168701c-6a43-4179-8f0b-5484ea984676.jpeg</cover_image></item><item><title><![CDATA[Run GPT4ALL Locally and Build a Simple QnA Program]]></title><description><![CDATA[<h3 id="heading-introduction">Introduction 🙋🏻</h3><p>Hey Guys, It's Tanmay here, and today I'll be talking about How you can run a smaller version of LLM on your machine directly, totally free of cost.</p><p>As we all know, Using and building on top of LLMs is costlier. Some students and researchers can't pay much amount of money to further study these models. That's why GPT4ALL is here.</p><div data-node-type="callout"><div data-node-type="callout-emoji">💡</div><div data-node-type="callout-text">GPT4All is an open-source software ecosystem that allows anyone to train and deploy <strong>powerful</strong> and <strong>customized</strong> large language models (LLMs) on <strong>everyday hardware</strong>. Nomic AI oversees contributions to the open-source ecosystem ensuring quality, security and maintainability.</div></div><p>Today, we'll use this quantized model to build a very simple QnA program instead of OpenAI's GPT. So stay along and enjoy the journey.</p><p>Also, if you are not the reader type, watch this video <a target="_blank" href="https://youtu.be/TEyd0F_rlvU">Here</a>. I covered all everything in that video but this blog is necessary because I can write in detail here.</p><h3 id="heading-how-quantized-gpt4all-works">How Quantized GPT4ALL works?</h3><p>GPT4ALL is trained on top of Facebook's LLaMA. We can't run Facebook's model on our machine because it is very big and has more than 7 billion parameters. That's why engineers used tricks like fine-tuning and inference to make smaller versions.</p><p>The underlying algorithm that takes place is Quantization, where it maps every continuous infinite value to a smaller set of discrete values. It basically converts the pre-trained model weights to 4-bit precision using the GGML format. So, the model uses fewer bits to represent the numbers. Therefore, reducing memory usage and faster inference.</p><h3 id="heading-running-gpt4all-locally">Running GPT4ALL Locally 👷🏻</h3><p><strong>Requirements :</strong></p><ul><li>Read: <a target="_blank" href="https://hashnode.com/post/cljoj6t5v000908l3fzm89hn5">https://hashnode.com/post/cljoj6t5v000908l3fzm89hn5</a></li></ul><p><strong>Steps :</strong></p><ol><li><p><strong>Download the model:</strong> You have to download the quantized model weight from this link (<a target="_blank" href="https://the-eye.eu/public/AI/models/nomic-ai/gpt4all/">https://the-eye.eu/public/AI/models/nomic-ai/gpt4all/</a>). The model name is <code>gpt4all-lora-quantized-ggml.bin</code>.</p></li><li><p><strong>Clone converter repo:</strong> Run the command to clone <code>llama.cpp</code> that is used to convert our model weight to a newer format. Because <code>langchain</code> only supports the newer formatted models.</p><pre><code class="lang-bash"> git <span class="hljs-built_in">clone</span> https://github.com/ggerganov/llama.cpp.git</code></pre></li><li><p><strong>Checkout to a specific stage:</strong> You've to set the repo to a previous stage <code>2b26469</code>. Because the latest version <code>llama.cpp</code> doesn't quite work well and throws a lot of errors.</p><pre><code class="lang-bash"> <span class="hljs-built_in">cd</span> llama.cpp &amp;&amp; git checkout 2b26469</code></pre></li><li><p><strong>Convert the model:</strong> To convert it, you have to run the <code>convert.py</code> argument value <code>path-to-our-downloaded-model</code> So you can just move the model to <code>llama.cpp/models</code> the directory.</p><pre><code class="lang-bash"> <span class="hljs-comment"># Inside llama.cpp directory</span> python3 convert.py models/gpt4all-lora-quantized-ggml.bin</code></pre><p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1689158851633/614507a6-7aa8-4732-aae6-28b189c37524.png" alt="terminal view while convert the model weight" class="image--center mx-auto" /></p><p> Our conversion to a newer format is now successfully done, you can check that out in the <code>/models/</code> directory. There must be a new file named similar to <code>ggml-model-q4_0.bin</code>. Now, we can build a simple program using GPT4ALL.</p></li><li><p><strong>Now, Coding the program:</strong> Our program will take any question and try to answer in a step-by-step manner in 100 words.</p><p> Before starting, you have to install <code>langchain</code> the library by <code>pip install -q langchain==0.0.152</code></p><pre><code class="lang-python"> <span class="hljs-keyword">from</span> langchain <span class="hljs-keyword">import</span> PromptTemplate, LLMChain <span class="hljs-keyword">from</span> langchain.llms <span class="hljs-keyword">import</span> GPT4All <span class="hljs-keyword">from</span> langchain.callbacks.base <span class="hljs-keyword">import</span> CallbackManager <span class="hljs-keyword">from</span> langchain.callbacks.streaming_stdout <span class="hljs-keyword">import</span> StreamingStdOutCallbackHandler <span class="hljs-comment"># Create a callback manager and add a callback handler for streaming stdout</span> callback_manager = CallbackManager([StreamingStdOutCallbackHandler()]) <span class="hljs-comment"># Create an LLM using the GPT4All model</span> llm = GPT4All(model=<span class="hljs-string">"llama.cpp/models/ggml-model-q4_0.bin"</span>, callback_manager=callback_manager, verbose=<span class="hljs-literal">True</span>) <span class="hljs-comment"># Create a template for prompting the LLM</span> template = <span class="hljs-string">"""Question: {question} Answer: Let's think step by step in 100 words. """</span> prompt = PromptTemplate(     template=template,     input_variables=[<span class="hljs-string">"question"</span>] ) <span class="hljs-comment"># Create an LLM chain</span> chain = LLMChain(llm=llm, prompt=prompt) <span class="hljs-comment"># Prompt the chain with a question</span> q = <span class="hljs-string">"How rain falls?"</span> chain.run(q)</code></pre></li><li><p><strong>Running our program:</strong> You can change the <code>q</code> variable to ask any question you want. Try out different questions, and see our this model performs on your machine. I have an MBA 8GB with 256GB SDD, and I still think a 16GB version would do a lot better in terms of faster output generation time.</p><p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1689159222633/2405ba6c-daf5-43c8-aa3d-e91fbd325b7e.png" alt="running the gpt4all program" class="image--center mx-auto" /></p><pre><code class="lang-bash"> pip3 test.py <span class="hljs-comment"># will run the program</span></code></pre><p> Running the code may take a lot of time, so you've to be patient at first.</p></li><li><p><strong>Understanding the Output:</strong> Let us see the output first.</p><p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1689159395049/78baba20-73d3-48cb-9d45-b34068e1a239.png" alt class="image--center mx-auto" /></p><p> This 100 words output took a lot of time on my machine, if there is any trick to make it faster, please do tell us in the comments.</p><p> In the code, we used the <code>StreamingStdOutCallbackHandler</code> and <code>verbose=True</code> but why? It is because we want to see the output in real-time and with a lot of extra system details.</p><p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1689159898658/fb66afba-862b-4663-9017-df29b9d47926.png" alt class="image--center mx-auto" /></p></li></ol><h3 id="heading-conclusion">Conclusion </h3><p>In this blog post, I showed you how to run a smaller version of LLM on your machine directly, totally free of cost. I used <a target="_blank" href="http://gpt4all.io/">GPT4ALL</a>, which is an open-source software ecosystem that allows anyone to train and deploy powerful and customized large language models (LLMs) on everyday hardware.</p><p>I also showed you how to build a simple QnA program using GPT4ALL. Our program takes any question and tries to answer in a step-by-step manner in 100 words.</p><p><strong>Here are some additional thoughts:</strong></p><ul><li><p>The GPT4ALL model is still under development, so the output may not always be perfect. However, it is a great way to get started with LLMs and see how they can be used to build real-world applications.</p></li><li><p>The code in this blog post is just a starting point. You can experiment with different questions and prompts to see how the model performs. You can also try to improve the performance of the model by using a faster machine or by fine-tuning the model.</p></li></ul><p>I hope you learned something new today. If you have any questions, feel free to ask me in the comments below. I will be happy to help you. It would be great if you share this article with your developer friends who are new to tech.</p><p>For reference, I wrote this article after learning these topics from a course called <a target="_blank" href="https://learn.activeloop.ai/courses/langchain">LangChain &amp; Vector Databases in Production</a>. I highly suggest you join it and learn in-depth about these topics. I've used some code snippets and an image from their coursework.</p><p>Follow me on <a target="_blank" href="www.twitter.com/sarkartanmay393">@sarkartanmay393</a><br />Direct mail me at <a target="_blank" href="http://sarkartanmay393@gmail.com">sarkartanmay393@gmail.com</a></p>]]></description><link>https://tanmaysarkar.hashnode.dev/run-gpt4all-locally-and-build-a-simple-qna-program</link><guid isPermaLink="true">https://tanmaysarkar.hashnode.dev/run-gpt4all-locally-and-build-a-simple-qna-program</guid><dc:creator><![CDATA[Tanmay Sarkar]]></dc:creator><pubDate>Wed, 12 Jul 2023 15:35:15 GMT</pubDate><cover_image>https://cdn.hashnode.com/res/hashnode/image/upload/v1689161561992/d6be646d-47b0-4c73-bbcc-245a6dccad1f.png</cover_image></item><item><title><![CDATA[Build a News Article Summarizer with OpenAI's GPT-3 and Langchain]]></title><description><![CDATA[<h3 id="heading-introduction">Introduction 🙋🏻</h3><p>Hi Fellows, today is your special day as it is for me too. I learned more about AI, LLMs and Langchain framework. You may be thinking what are these terms?</p><blockquote><p>LLM stands for Large Language Model and Langchain is a framework to build applications using LLMs(GPT-3, GPT-4).</p></blockquote><p>As I'm learning advanced development, building applications using AI tools is necessary in today's world. The tech community nowadays sees various awesome apps built on top of AI models and gives users a wonderful experience. So today, I'll be talking about this topic and helping you kickstart your journey in this field.</p><p>As you are already aware the constant bombard of new information on us every single day. It can be challenging to keep up with all the news and articles published daily. This is where a news article summarizer can be helpful, What do you think? 🤓<br />A news article summarizer can read a long article and generate a shorter summary of the key points. This can save you time and help you to stay up-to-date on the latest news.</p><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1688489807968/d9189f98-5d7b-4226-a64c-13c459e1b859.avif" alt="arcitecture" class="image--center mx-auto" /></p><p>And how will it happen? Definitely using <a target="_blank" href="https://platform.openai.com/">OpenAI</a> services. But there's a catch, it takes money to give you API services. Heyyy no worries, I've got a solution for you. You can signup at <a target="_blank" href="https://platform.openai.com/">OpenAI</a> and avail $5 for the first three months. I have another way also, where we leverage quantized chat models to run locally on our machine and get services directly from it, but it's another topic. I will walk you through that way also, but in the next blog, so stay updated with me.</p><div data-node-type="callout"><div data-node-type="callout-emoji">💡</div><div data-node-type="callout-text">If you are not the reader type, watch this video <a target="_blank" href="https://youtu.be/FPossCmTFZ0">https://youtu.be/FPossCmTFZ0</a>. I covered all the points of this blog in that video for you, check it out.</div></div><h3 id="heading-llms-and-langchain">LLMs and Langchain</h3><p>What are basically LLMs? Large language models (LLMs) are a type of artificial intelligence (AI) that are trained on massive datasets of text and code. This allows them to generate text, translate languages, write different kinds of creative content, and answer your questions in an informative way.</p><p>Some of the most popular LLMs include:</p><ul><li><p>GPT-3: Developed by OpenAI, GPT-3 is one of the most powerful LLMs available. It has been trained on a dataset of text and code that is over 500 times larger than the dataset used to train its predecessor, GPT-2.</p></li><li><p>LaMDA: Developed by Google AI, LaMDA is a factual language model that can answer your questions in an informative way. It has been trained on a dataset of text and code that is over 1.56 trillion words long.</p></li></ul><p>LLMs are still under development, but they have the potential to revolutionize many industries. They can be used for a variety of tasks, including:</p><ul><li><p>Text summarization: LLMs can be used to generate summaries of long pieces of text. This can be helpful for people who want to quickly get the gist of a document without having to read the whole thing.</p></li><li><p>Translation: LLMs can be used to translate text from one language to another. This can be helpful for people who want to communicate with people who speak other languages.</p></li><li><p>Creative writing: LLMs can be used to generate creative text, such as poems, stories, and scripts. This can be helpful for writers who are looking for inspiration or who want to automate the writing process.</p></li><li><p>Question answering: LLMs can be used to answer your questions in an informative way. This can be helpful for students who are doing research or for people who want to learn more about a particular topic.</p></li></ul><p>LLMs are still a relatively new technology, but they have the potential to change the way we interact with computers. As they continue to develop, they will become more powerful and capable, and they will be used for a wider range of tasks.</p><p>And Langchain is just a framework (<em>e.g. React</em>) but it simplifies the development of applications using LLMs. It provides a number of functions that allow you to interact with the LLMs and generate cool stuff. That is what it's all about in a general sense. We will use Python as our coding language to build an article summarizer today with the help of OpenAI ChatModel by using the Langchain framework.</p><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1688490085207/7070b42f-58a5-4a3b-a87a-79e554eabccc.webp" alt class="image--center mx-auto" /></p><h3 id="heading-building-the-summarizer">Building the Summarizer 👷🏻</h3><p><strong>Requirements :</strong></p><ul><li><p>Basic CS Fundamentals</p></li><li><p>Knowledge of Any Programming Language</p></li></ul><p><strong>Code :</strong></p><ol><li><p>First of all, you need to install these packages <code>langchain</code>, <code>openai</code>, <code>python_dotenv</code>, <code>requests</code>, <code>newspaper3k</code></p><pre><code class="lang-python"> pip install langchain openai python_dotenv requests newspaper3k</code></pre></li><li><p>Inside your project directory named <code>news-summarizer-python</code> and create a Python file</p><p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1688481986994/9a923d08-a1e2-4aa8-b2d0-15dd8e576214.png" alt class="image--center mx-auto" /></p></li><li><p>Now start writing code. You need to follow along with my code sample below, I've written the documentation alongside.</p><p> <em>#GetNewsArticle.</em></p><pre><code class="lang-python"> <span class="hljs-keyword">import</span> requests  <span class="hljs-keyword">from</span> newspaper <span class="hljs-keyword">import</span> Article   <span class="hljs-comment"># this function takes article URL and return it in Article object. </span> <span class="hljs-comment"># I included a default value for the url, it never matters. </span> <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">GetNewsArticle</span>(<span class="hljs-params">article_url=<span class="hljs-string">"https://labs.hakaioffsec.com/nginx-alias-traversal/"</span></span>):</span>       <span class="hljs-comment"># Fetches the news article from the given URL      </span> <span class="hljs-comment"># header object for the request we have make to article url     </span> headers = {<span class="hljs-string">'User-Agent'</span>: <span class="hljs-string">'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.82 Safari/537.36'</span>}       <span class="hljs-comment"># Create a session object that we can use for calling get, post function with that url.     </span> session = requests.Session()        <span class="hljs-comment"># try catch block     </span> <span class="hljs-keyword">try</span>:              <span class="hljs-comment"># making the request with url, header, and timeout parameter.         </span>     response = session.get(article_url, headers=headers, timeout=<span class="hljs-number">10</span>)              <span class="hljs-keyword">if</span> response.status_code == <span class="hljs-number">200</span>:                      <span class="hljs-comment"># if response comes with no issues, we make the article object             </span>         <span class="hljs-comment"># it takes the url and does everything we did using request and session on its own.              </span>         article = Article(article_url)                      article.download()                      article.parse()                       <span class="hljs-comment"># after downloading and parsing the data, we're returning it.             </span>         <span class="hljs-keyword">return</span> article              <span class="hljs-keyword">else</span>:                      <span class="hljs-comment"># this is just for error checking             </span>         print(<span class="hljs-string">"Error fetching article url"</span>)       <span class="hljs-comment"># this is also for error checking     </span> <span class="hljs-keyword">except</span> Exception <span class="hljs-keyword">as</span> e:          print(<span class="hljs-string">"Error occured while fetching the news article"</span>)</code></pre><p> <em>#summarizer.py</em></p><pre><code class="lang-python"> <span class="hljs-keyword">from</span> GetNewsArticle <span class="hljs-keyword">import</span> GetNewsArticle  <span class="hljs-comment"># importing ChatOpenAI (Wrapper around OpenAI Chat large language models)</span> <span class="hljs-keyword">from</span> langchain.chat_models <span class="hljs-keyword">import</span> ChatOpenAI <span class="hljs-comment"># schema for formatting users input for the model</span> <span class="hljs-keyword">from</span> langchain.schema <span class="hljs-keyword">import</span> HumanMessage <span class="hljs-comment"># if a .env file, you've to pass OPENAI_API_KEY</span> <span class="hljs-keyword">from</span> dotenv <span class="hljs-keyword">import</span> load_dotenv load_dotenv() <span class="hljs-comment"># Taking user news article url</span> article_url = input(<span class="hljs-string">"Enter any article link: "</span>) <span class="hljs-comment"># Fetch the article we will be summarizing from our</span> article = GetNewsArticle(article_url) <span class="hljs-comment"># Create a chatbot instance that will summarize the article</span> <span class="hljs-comment"># verbose for more details to print along</span> <span class="hljs-comment"># temperature is the randomness the model can play with</span> <span class="hljs-comment"># 0.0 is only for real facts, 1.0 is for full creativity.</span> llm = ChatOpenAI(model_name=<span class="hljs-string">"gpt-3.5-turbo"</span>, verbose=<span class="hljs-literal">True</span>, temperature=<span class="hljs-number">0.0</span>) <span class="hljs-comment"># Create the template for the prompt</span> <span class="hljs-comment"># Crafting prompt is the main thing in LLM workings.</span> <span class="hljs-comment"># using this template, we're asking the chat model to give us the summary of any long article.</span> template = <span class="hljs-string">"""You are a smart assistant that summarizes online articles in 100 words. Here's the article you want to summarize. ================== Title: {article_title} {article_text} ================== Write a summary of the given article. """</span> <span class="hljs-comment"># Format the prompt with the article details we've got</span> prompt = template.format(article_title=article.title,                          article_text=article.text) <span class="hljs-comment"># Create a list of messages to send to the chatbot</span> <span class="hljs-comment"># but we passing only one message in HumanMessage object form.</span> messages = [HumanMessage(content=prompt)] <span class="hljs-comment"># Send the messages to the chatbot and print the response</span> output = llm(messages) <span class="hljs-comment"># we can print our summary</span> print(<span class="hljs-string">"\n"</span> + output.content + <span class="hljs-string">"\n"</span>)</code></pre><p> Note: Code is available here with a code explanation</p><p> <a target="_blank" href="https://github.com/sarkartanmay393/ArticleSummarizer-Python">https://github.com/sarkartanmay393/ArticleSummarizer-Python</a></p></li><li><p>That's it. You can now build an AI-based summarizer. Now let us run our program,</p><p> %[https://vimeo.com/842226438] </p></li></ol><p><strong>Note:</strong> You need to create a <code>.env</code> file and put <code>OPENAI_API_KEY</code></p><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1688489509625/cde1e9ef-b5a9-4db3-a5e9-30824f84ab93.png" alt class="image--center mx-auto" /></p><p>And it's not just a summarizer, it can be more than that. Like, you can get the summarized text in bulleted points. You ask how?</p><p>Just tweak the prompt message a little,</p><pre><code class="lang-python">template = <span class="hljs-string">"""You are an advanced AI assistant that summarizes online articles into bulleted lists.Here's the article you need to summarize.==================Title: {article_title}{article_text}==================Now, provide a summarized version of the article in a bulleted list format."""</span></code></pre><p>That is it, now the output will,</p><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1688486257578/dc71161b-3519-49b1-987d-e76197e85bb5.png" alt class="image--center mx-auto" /></p><h3 id="heading-conclusion">Conclusion </h3><p>In this blog post, we embarked on a journey to explore the world of AI, LLMs (Large Language Models), and the Langchain framework. We discovered the potential of LLMs, particularly the powerful GPT-3, in generating text and even assisting with creative writing. These advancements can revolutionize various industries and change the way we interact with computers.</p><p>To simplify the development of applications using LLMs, we introduced the Langchain framework, which provides a range of functions for interacting with LLMs and generating fascinating outputs. Leveraging Python as our coding language, we set out to build an article summarizer using OpenAI's ChatModel in conjunction with Langchain.</p><p>By delving into the world of AI and leveraging the Langchain framework, we have taken the first steps toward the future of technology.</p><p>So, let's embrace the possibilities that AI, LLMs, and frameworks like Langchain offer, and embark on our journey of innovation and exploration in this fascinating field.</p><p>I hope you learned something new today. If you have any questions, feel free to ask me in the comments below. I will be happy to help you. It would be great if you share this article with your developer friends who are new to tech.</p><p>For reference, I wrote this article after learning these topics from a course called <a target="_blank" href="https://learn.activeloop.ai/courses/langchain">LangChain &amp; Vector Databases in Production</a>. I highly suggest you join it and learn in-depth about these topics. I've used some code snippets and an image from their coursework.</p><p>Follow me on <a target="_blank" href="www.twitter.com/sarkartanmay393">@sarkartanmay393</a><br />Direct mail me at <a target="_blank" href="http://sarkartanmay393@gmail.com">sarkartanmay393@gmail.com</a></p>]]></description><link>https://tanmaysarkar.hashnode.dev/build-a-news-article-summarizer-with-openais-gpt-3-and-langchain</link><guid isPermaLink="true">https://tanmaysarkar.hashnode.dev/build-a-news-article-summarizer-with-openais-gpt-3-and-langchain</guid><dc:creator><![CDATA[Tanmay Sarkar]]></dc:creator><pubDate>Tue, 04 Jul 2023 16:55:29 GMT</pubDate><cover_image>https://cdn.hashnode.com/res/hashnode/image/upload/v1688480638956/61ca86c4-f854-43ce-b093-70629aa31744.jpeg</cover_image></item><item><title><![CDATA[Binary Trees Explained: A Step-by-Step Tutorial]]></title><description><![CDATA[<h3 id="heading-introduction">Introduction 🧑🏽💻</h3><p>Welcome to the fascinating world of binary trees! If you're new to this topic or looking to reinforce your understanding, you're in the right place. In this tutorial, I'll take you on a step-by-step journey through the fundamentals of binary trees. By the end of this article, you'll have a solid understanding of binary trees and feel confident in your ability to tackle more advanced data structures.</p><h3 id="heading-understanding-binary-trees">Understanding Binary Trees 🎄</h3><p>Let's start by demystifying binary trees. Don't worry if you're unfamiliar with the concept  I'll break it down for you. Binary trees consist of nodes connected by edges, forming a hierarchical structure. Imagine it as a tree with branches spreading out, where each node can have up to two children. Simple, right? We'll illustrate this with easy-to-understand diagrams to make it crystal clear.</p><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1687596683318/b29259e1-8190-4f04-999b-b7dee66b95cd.png" alt class="image--center mx-auto" /></p><p>A binary tree is a hierarchical structure composed of nodes. Each node can have at most two children: a <em>left child</em> and a <em>right child</em>. The topmost node is called the <em>root</em>, and it serves as the starting point of the tree. The nodes below the root are referred to as <em>internal nodes</em>, while those at the bottom without any children are called <em>leaf nodes</em>.</p><p>Now, let's break down the components of a binary tree:</p><ol><li><p>Root: The topmost node of the tree, serving as the starting point.</p></li><li><p>Internal Node: Nodes other than the root and leaf nodes, having both a left and right child.</p></li><li><p>Leaf Node: Nodes at the bottom of the tree without any children.</p></li><li><p>Left Child: The node directly below and to the left of another node.</p></li><li><p>Right Child: The node directly below and to the right of another node.</p></li><li><p>Parent: The node above and connected to another node.</p></li><li><p>Subtree: A smaller binary tree within the main binary tree, having its root.</p></li></ol><p>The time complexity of binary tree operations is typically determined by the height in balanced trees, while it is determined by the number of nodes in unbalanced trees. A well-balanced binary tree, such as an <em>AVL tree</em> or <em>Red-Black tree</em>, ensures that the height remains logarithmic. This balance leads to efficient operations, such as insertion, deletion, and searching, all of which have a time complexity of <em>O(logN)</em> in balanced trees.</p><p><img src="https://prepinsta.com/wp-content/uploads/2023/03/Example-of-AVL-Tree-1.webp" alt class="image--center mx-auto" /></p><p>Now a question arises, <strong>Why should one use binary trees over other data structures</strong>?</p><blockquote><p><em>Binary trees excel in scenarios that require efficient searching, sorting, and hierarchical organization.</em> They <em>provide a balance between ordered structure and fast access, making them suitable for a wide range of applications. Compared to linear structures like Linked Lists or Arrays, Binary trees reduce the search space significantly, resulting in faster operations. Additionally, binary trees can handle dynamic data effectively, allowing for efficient insertion and removal of elements.</em></p></blockquote><h3 id="heading-use-cases-of-binary-trees">Use cases of Binary Trees </h3><p>Prepare to be amazed by the countless applications of binary trees! From efficient searching with binary search trees to evaluating mathematical expressions with expression trees, and even data compression with Huffman coding. All these is being possible by Binary Trees.</p><p>Let's explore some common use cases where binary trees shine.</p><ol><li><p><strong>Searching and Sorting:</strong> One of the primary applications of binary trees is in searching and sorting algorithms. <strong>Binary Search Trees (BST)</strong>, a specific type of binary tree, enable efficient searching for a particular value. They maintain an order where the left child of a node is smaller, and the right child is greater. This property allows for quick comparisons and reduces the search space, resulting in logarithmic time complexity <em>O(logN)</em> for searching operations.</p></li><li><p><strong>Hierarchical Structures:</strong> Binary trees are ideal for representing hierarchical relationships. <em>File systems</em>, <em>organization charts</em>, and <em>family trees</em> can all be efficiently modelled using binary trees. The parent-child relationship between nodes simplifies the navigation and management of hierarchical data.</p></li><li><p><strong>Expression Evaluation:</strong> Expression trees utilize binary tree structures to represent mathematical expressions. Operators reside in internal nodes, while operands reside in leaf nodes. Expression trees allow for efficient evaluation of complex expressions by performing operations in a specific order, guided by the tree structure.</p></li><li><p><strong>Huffman Coding:</strong> Binary trees are central to <em>Huffman</em> coding, a compression technique widely used in data compression algorithms. Huffman trees are constructed based on the frequency of characters in a text, with frequent characters occupying shorter paths in the tree. This results in optimal compression, reducing file sizes while maintaining data integrity.</p></li><li><p><strong>Decision Trees:</strong> Binary trees are instrumental in decision tree algorithms used for classification and regression tasks in machine learning. Decision trees divide data based on features at each node, ultimately leading to leaf nodes representing specific classes or regression values. Decision trees are interpretable and enable efficient data classification and prediction.</p></li><li><p><strong>Game Trees:</strong> Binary trees serve as the backbone for game trees, used in game theory and artificial intelligence. Game trees represent the possible moves and outcomes in games, facilitating decision-making and strategy development for both players and intelligent agents.</p></li></ol><h3 id="heading-implementation-of-binary-tree">Implementation of Binary Tree 🌱</h3><p>Let's roll up our sleeves and build our very own binary tree. I'll guide you through the process, step by step. You'll be constructing binary trees like a pro in no time!</p><div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://replit.com/@sarkartanmay393/101BinaryTrees?v=1">https://replit.com/@sarkartanmay393/101BinaryTrees?v=1</a></div><p> </p><p>In the above Replit code, I coded everything you need to know to get started using Trees. I wrote explanations also with the code itself, you must take a look at it to understand Binary Tree implementation completely.</p><p>My DSA with Java Repository: <a target="_blank" href="https://github.com/sarkartanmay393/DSA-Java/tree/master/src/com/tanmay/BinaryTree">DSA-Java BinaryTrees (Github</a>). Give it a proper look and you may find useful codes and explanations.</p><h3 id="heading-traversing-binary-trees">Traversing Binary Trees 🎋</h3><p>Time to explore the exciting world of traversing binary trees. Think of it as navigating through the tree and visiting each node. There are three popular techniques: <strong>pre-order</strong>, <strong>in-order</strong>, and <strong>post-order</strong> traversal.</p><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1687609051344/c4fc4b71-1d77-4a7c-b2a0-39a1d5a0fa32.png" alt="binary tree traversals" class="image--center mx-auto" /></p><ol><li><p><strong>Pre-order</strong> traversal is primarily used for obtaining prefix expressions, creating copies of trees, and generating prefix notations. It provides a systematic way of visiting nodes in a binary tree, allowing for various applications in expression evaluation, tree manipulation, and programming.</p></li><li><p><strong>In-order</strong> traversal is a valuable technique used for retrieving data in sorted order, evaluating expressions, creating copies of binary trees, and validating the structure of binary search trees. Its properties and applications make it an essential tool in various algorithms and data-processing tasks involving binary trees.</p></li><li><p><strong>Post-order</strong> traversal is primarily used for evaluating expressions in expression trees, deleting nodes while maintaining proper dependencies, and generating postfix representations of expressions. Understanding the different traversal orders, including post-order, provides valuable tools for efficiently manipulating and analyzing binary trees.</p></li></ol><p>We'll take a greater look and code each traversal technique in our upcoming post where I'll explain Binary Search Tree aka BST.</p><h3 id="heading-short-note-of-binary-search-tree">Short Note of Binary Search Tree 📝</h3><p>A Binary Search Tree (BST) is a binary tree with an ordering property where the left child contains smaller values and the right child contains greater values. BSTs enable efficient searching, insertion, and deletion operations with a logarithmic time complexity of O(log n). They are widely used in applications requiring fast searching and sorting, such as dictionaries, symbol tables, and databases. An in-order traversal of BSTs provides a sorted sequence of values. While the efficiency of BST operations depends on maintaining balance, they serve as the foundation for more advanced balanced tree structures. Overall, BSTs offer an ordered and efficient way to store and retrieve data.</p><p>I'll be coming up with a new blog very soon, explaining Binary Search Tree and more about Binary Trees.</p><h3 id="heading-conclusion">Conclusion 🙌🏼</h3><p>Congratulations! You've successfully started the journey through the world of binary trees, and you've done it with confidence and ease. Remember, mastering binary trees takes time and practice, but you're well on your way. Keep exploring advanced topics and challenging yourself with new projects. With each step, you'll enhance your problem-solving skills and become a proficient programmer.</p><p>So, go ahead and embrace the power of binary trees. You're now equipped with the knowledge and understanding to tackle complex data structures. Happy coding and enjoy your newfound binary tree prowess!</p><p>Follow me on 🐦 <a target="_blank" href="www.twitter.com/sarkartanmay393">@sarkartanmay393</a><br />Direct mail me 📧 <a target="_blank" href="http://mailto:sarkartanmay393@gmail.com">sarkartanmay393@gmail.com</a></p>]]></description><link>https://tanmaysarkar.hashnode.dev/binary-trees-explained-a-step-by-step-tutorial</link><guid isPermaLink="true">https://tanmaysarkar.hashnode.dev/binary-trees-explained-a-step-by-step-tutorial</guid><dc:creator><![CDATA[Tanmay Sarkar]]></dc:creator><pubDate>Sat, 24 Jun 2023 12:26:42 GMT</pubDate><cover_image>https://cdn.hashnode.com/res/hashnode/image/upload/v1687608140612/3d9d357e-d5fb-4e8a-8745-58738090e187.jpeg</cover_image></item><item><title><![CDATA[Boost Website Speed: Quick Loading Techniques]]></title><description><![CDATA[<p>Hey there! In our super speedy digital world, having a fast-loading website is essential for a thriving online business. Did you know that over half of users will leave a site if it takes more than three seconds to load? That's why it's so important to make sure your website loads quickly. In this blog, I'll share some handy tips to help you boost your website's load speed and keep your visitors happily engaged.</p><ol><li><p><strong>Optimize Images:</strong> One of the most common causes of slow website speed is oversized images. To optimize images, compress them using an image compression tool. There are many tools available online that can help you compress images without sacrificing quality.<br /> Example: <em>Before uploading an image to your website, use an image compression tool such as</em> <a target="_blank" href="https://tinypng.com/"><em>TinyPNG</em></a> <em>to compress it. This will significantly reduce the image file size, making it load faster and there are a lot of other ways present also.</em></p></li><li><p><strong>Minimize HTTP Requests:</strong> HTTP requests are made when a browser loads a web page. The more requests a page has to make, the longer it takes to load. To minimize HTTP requests, combine CSS and JavaScript files, and minimize the use of external scripts.<br /> Example: <em>Combine all your CSS files into one file and all your JavaScript files into another file. This will reduce the number of HTTP requests required to load your website.</em></p></li><li><p><strong>Use a Content Delivery Network (CDN):</strong> A CDN is a network of servers around the world that can help deliver content faster to website visitors. Using a CDN can reduce the distance between your website visitors and your server, resulting in faster load times.<br /> Example: <em>Cloudflare is a popular CDN that can help improve your website's load speed. By using Cloudflare, your website's content is cached on their servers, and it's delivered to visitors from the server closest to their location.</em></p></li><li><p><strong>Enable Browser Caching:</strong> Browser caching allows your website visitors to store the files of your website on their computer, so they don't have to download them every time they visit your site. This can significantly reduce load times for repeat visitors.<br /> Example: <em>Use a caching plugin such as WP Super Cache if you're using WordPress. This plugin allows you to enable browser caching, which can significantly reduce load times for repeat visitors.</em> <a target="_blank" href="https://medium.com/@codebyamir/a-web-developers-guide-to-browser-caching-cc41f3b73e7c"><em>A web developer's guide to browser caching</em></a><em>, read this to get an overview of caching. I'll write a tutorial for enabling browser caching in React-based websites.</em></p></li><li><p><strong>Minimize Redirects:</strong> Redirects may introduce extra HTTP requests, potentially slowing down your website. Aim to reduce the number of redirects on your site, ensuring they are properly executed.<br /> Example: <em>If you've recently updated your website's URL structure, make sure to set up proper redirects. Instead of using multiple redirects, use a single redirect to the new URL.</em></p></li><li><p><strong>Optimize Your Code:</strong> Optimizing your code is crucial to reducing load times. Make sure your HTML, CSS, and JavaScript files are minified, and remove any unnecessary code. You can also use code optimization tools to help with this task.<br /> Example: <em>Use a code optimization tool such as HTMLMinifier to minify your HTML code. This will remove any unnecessary white space and comments, reducing file size and improving load times. And you can find lots of plugins to use in your React-based websites.</em></p></li><li><p><strong>Choose a Fast Web Host:</strong> Your web host plays a significant role in the speed of your website. Choose a fast and reliable web host that can handle your website's traffic and provide a fast server response time.<br /> Example: <em>If you're looking for a fast and reliable web host, consider using a managed hosting service such as WP Engine. They offer high-performance hosting optimized for WordPress, with fast server response times. There are other free options like Firebase, Vercel and Netlify.</em></p></li></ol><p>To wrap things up, boosting your website's loading speed is key to offering an awesome user experience and enhancing your site's performance. By putting the handy tips we've shared into action, you can notably cut down on load times and keep more visitors coming back for more. After all, we create websites for our lovely visitors, so making their experience delightful is what matters most to us!</p><p>Thank you for your time 🧡 and hope to see you in my coming articles.</p>]]></description><link>https://tanmaysarkar.hashnode.dev/boost-website-speed-quick-loading-techniques</link><guid isPermaLink="true">https://tanmaysarkar.hashnode.dev/boost-website-speed-quick-loading-techniques</guid><dc:creator><![CDATA[Tanmay Sarkar]]></dc:creator><pubDate>Sat, 13 May 2023 13:26:17 GMT</pubDate><cover_image>https://cdn.hashnode.com/res/hashnode/image/upload/v1683983438274/7430ea2d-48f9-4954-b660-04e26fc90198.png</cover_image></item><item><title><![CDATA[Get Free Swags as a beginner in Tech]]></title><description><![CDATA[<p>Namaste Everyone, I'm back again on my track. These semester exams are a real pain 😩. By the way, focus on this me now, today I'll tell you the best ways of getting free swags from companies like MLH, DigitalOcean, Blockstack and more. So let us not wait any further.</p><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672160278936/58806b00-3f47-428a-8872-7e2931be8a27.png" alt="get-free-swags-mlh" class="image--center mx-auto" /></p><h3 id="heading-what-are-the-options"><mark>What are the options?</mark></h3><ol><li><p><strong>MLH Swags + Bonus</strong></p><p> This is the best and easy-to-get swag source of all. For the past 2-3 months, MLH is organising a Global Hack Week event and in that event, you can avail of MLH swags, a Bonus Swag Kit and various other benefits from sponsors of the event. So be sure to check it out.</p><p> Visit: <a target="_blank" href="https://ghw.mlh.io/"><code>https://ghw.mlh.io</code></a></p></li><li><p><strong>DigitalOcean: Hacktoberfest</strong></p><p> You may already know about Hacktoberfest, it runs in the month of September every year. Here you need to perform 4 pull requests at least and if they get merged, you get the opportunity to get Swags or plant a tree with your name. This event is very popular in India and Globally also and it is also easy-to-get.</p><p> Visit: <a target="_blank" href="https://hacktoberfest.com/"><code>https://hacktoberfest.com</code></a></p></li><li><p><strong>Blockstack: Zero to DApp</strong></p><p> In addition to learning a new approach and platform, developers who complete the Zero-to-Dapp tutorial and submit it to <a target="_blank" href="https://app.co"><code>app.co</code></a> get a free limited edition t-shirt.</p><p> Visit: <a target="_blank" href="https://docs.stacks.co/docs/build-apps/"><code>https://docs.stacks.co/docs/build-apps</code></a></p></li><li><p><strong>Kong/kong</strong></p><p> Kongs Contributor Program is designed to encourage knowledge sharing amongst Kongs community of users and to recognize and reward the important work our contributors are doing. We have a variety of ways through which you can contribute and earn points towards some amazing Kong swag!</p><p> Visit: <a target="_blank" href="https://konghq.com/community/open-source-contribution"><code>https://konghq.com/community/open-source-contribution</code></a></p></li></ol><p>... at this time, these four are good to go. And in future, If more comes up, I'll add them somehow. But you have to help by commenting below some more swag sources.</p><p>And with that being said, I'm taking off from here, see you on my next blog.</p><p>Thank you for your time 🧡</p>]]></description><link>https://tanmaysarkar.hashnode.dev/get-free-swags-in-tech</link><guid isPermaLink="true">https://tanmaysarkar.hashnode.dev/get-free-swags-in-tech</guid><dc:creator><![CDATA[Tanmay Sarkar]]></dc:creator><pubDate>Tue, 27 Dec 2022 17:23:24 GMT</pubDate><cover_image>https://cdn.hashnode.com/res/hashnode/image/upload/v1672162034665/b61f30fb-0b2b-4d14-b1a5-c28490b40783.png</cover_image></item><item><title><![CDATA[Build Sudoku Solver Engine using Go]]></title><description><![CDATA[<h2 id="heading-introduction">Introduction 🤖</h2><p>We have been learning new topics with Go, and before getting into DevOps topics in our blogs, today lets build a simple fun project and gear up your algorithms skills a little.</p><p>As you know, Sudoku is a board game where there is 81 boxes, each with a specific number between 1-9 or it can be a empty box. We have to fill those empty boxes in a way that no number is repeated in its row, column and in 3*3 area of board. Dont worry, google a little about Sudoku if you dont know what this game is in general.</p><p>We know that there is definitely a algorithm we humans use while solving a sudoku pattern in paper, and now we have to just think about that algorithm and try to write it for our computers to understand. It is going to be interesting and brainstorming, so now we should proceed into it.</p><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1667654134248/wSYR_rjFg.png" alt="06-blog.png" /></p><h2 id="heading-prerequisites">Prerequisites</h2><p>You should have a basic knowledge of</p><ul><li><strong>Go</strong></li><li><strong>Recursion</strong> <em>(optional)</em></li></ul><h2 id="heading-lets-begin">Lets Begin</h2><p>Very important part of building a sudoku solver using programming languages is Recursion. Briefly I can say, Recursion is a method where a function calls itself. Lets see an example of that,</p><pre><code class="lang-go"><span class="hljs-comment">// len returns the length of a string using Recursion.</span><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">len</span><span class="hljs-params">(str <span class="hljs-keyword">string</span>)</span> <span class="hljs-title">int</span></span> {   <span class="hljs-comment">// base condition where our function stops.</span>   <span class="hljs-keyword">if</span> str == <span class="hljs-string">""</span> {     <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>   }   <span class="hljs-comment">// if str = "golang"</span>   substring := str[<span class="hljs-number">1</span>:]   <span class="hljs-comment">// substring = "olang"</span>   <span class="hljs-comment">// for each len func call, we are increasing the result int by 1 and </span>   <span class="hljs-comment">//calling the same function by reducing the string length </span>   <span class="hljs-comment">//by one character (or rune).</span>   <span class="hljs-keyword">return</span> <span class="hljs-number">1</span> + <span class="hljs-built_in">len</span>(substring)}</code></pre><p>Output: <code>len("abcde") = 5</code></p><p>As you can see, len function is returning <code>1 + (len(substring)</code>. If str is not empty then it must have a length of 1 and passing the reduced str to len again, and running until str becomes empty. When it gets empty, it returns 0 where our programme ends.</p><blockquote><p>For better understanding, here is reference link to you. <a target="_blank" href="https://www.youtube.com/playlist?list=PL9gnSGHSqcnp39cTyB1dTZ2pJ04Xmdrod">Learn More</a></p></blockquote><p>Now you understand Recursion a little, so we can just head into our sudoku engine. You can see our program in running state now, <strong><a target="_blank" href="https://go.dev/play/p/k_crNjzrUEc">go/sudoku-engine</a></strong>.</p><h3 id="heading-1-setup-sudoku-engine-project">1. Setup Sudoku Engine Project</h3><ol><li>Create a new folder for your project and name it <code>sudoku-engine</code>.</li><li>Create a new file in that folder and name it <code>main.go</code>.</li><li>Run <code>go mod init sudoku-engine</code> in terminal to initialize your project.</li></ol><h3 id="heading-2-writing-engine-code">2. Writing Engine Code</h3><ol><li><p>First create a parse function to convert our sudoku pattern into a 2D slice. We will use this slice to solve our sudoku pattern.</p><pre><code class="lang-go"><span class="hljs-comment">// parseInput converts a string to 2D slice/array.</span> <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">parseInput</span><span class="hljs-params">(input <span class="hljs-keyword">string</span>)</span> [][]<span class="hljs-title">int</span></span> {     board := [][]<span class="hljs-keyword">int</span>{         {<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>},         {<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>},         {<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>},         {<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>},         {<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>},         {<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>},         {<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>},         {<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>},         {<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>},     } <span class="hljs-comment">// dummy board</span>     <span class="hljs-comment">// scanner is set up to read input string.</span>     scanner := bufio.NewScanner(strings.NewReader(input))     scanner.Split(bufio.ScanRunes)     <span class="hljs-comment">// go for an iteration over the whole string of length 81.</span>     <span class="hljs-comment">// if the rune is a number, then we convert it to int and add it to our board.</span>     <span class="hljs-keyword">for</span> row := <span class="hljs-number">0</span>; row &lt; <span class="hljs-number">9</span>; row++ {         <span class="hljs-keyword">for</span> col := <span class="hljs-number">0</span>; col &lt; <span class="hljs-number">9</span>; col++ {             scanner.Scan()             tmp := scanner.Text()             val, err := strconv.Atoi(tmp)             <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {                 <span class="hljs-comment">// error here</span>             }             board[row][col] = val         }     }     <span class="hljs-keyword">return</span> board }</code></pre></li><li><p>Create isSafe function to check if a number we are trying to put in a box is safe or not.</p></li></ol><blockquote><p>It means, if the number is already present in its row, column or 3*3 area of the board, then it is not safe to put that number in that box.</p></blockquote><pre><code class="lang-go"><span class="hljs-comment">// isSafe returns true if it is possible to put n in that (row, col) position in the given board.</span><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">isSafe</span><span class="hljs-params">(board *[][]<span class="hljs-keyword">int</span>, row <span class="hljs-keyword">int</span>, col <span class="hljs-keyword">int</span>, num <span class="hljs-keyword">int</span>)</span> <span class="hljs-title">bool</span></span> {  <span class="hljs-comment">// tasks to do</span>  <span class="hljs-comment">// 1. check if num is present in row</span>  <span class="hljs-comment">// 2. check if num is present in col</span>  <span class="hljs-comment">// 3. check if num is present in 3*3 box</span>  <span class="hljs-comment">// checking in the row</span>  <span class="hljs-keyword">for</span> _, slice := <span class="hljs-keyword">range</span> *board {    <span class="hljs-keyword">if</span> slice[col] == num {      <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>    }  }  <span class="hljs-comment">// checking in the col</span>  <span class="hljs-keyword">for</span> _, value := <span class="hljs-keyword">range</span> (*board)[row] {    <span class="hljs-keyword">if</span> value == num {      <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>    }  }  <span class="hljs-comment">// checking in the 3*3 box</span>  rowStart := row - row%<span class="hljs-number">3</span> <span class="hljs-comment">// (row / 3) * 3</span>  colStart := col - col%<span class="hljs-number">3</span> <span class="hljs-comment">// (col / 3) * 3</span>  <span class="hljs-keyword">for</span> i := rowStart; i &lt; rowStart+<span class="hljs-number">3</span>; i++ {    <span class="hljs-keyword">for</span> j := colStart; j &lt; colStart+<span class="hljs-number">3</span>; j++ {      <span class="hljs-keyword">if</span> (*board)[i][j] == num {        <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>      }    }  }<span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>}</code></pre><ol><li>Create a solve function to solve our sudoku pattern. We will use recursion and backtracking in this function to solve our sudoku pattern.</li></ol><pre><code class="lang-go"><span class="hljs-comment">// solve the sudoku board using backtracking.</span><span class="hljs-comment">// It returns solved board if the board is solved.</span><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">solve</span><span class="hljs-params">(board *[][]<span class="hljs-keyword">int</span>)</span> <span class="hljs-title">bool</span></span> {  <span class="hljs-comment">// tasks to do</span>  <span class="hljs-comment">// 1. find the empty cell</span>  <span class="hljs-comment">// 2. try to put a number in that cell</span>  <span class="hljs-comment">// 3. check if it is safe to put that number in that cell</span>  <span class="hljs-comment">// 4. if it is safe then put that number in that cell and solve the rest of the board</span>  <span class="hljs-comment">// 5. if it is not safe then try another number</span>  <span class="hljs-comment">// 6. if all the numbers are tried and none of them is safe then return false</span>  row := <span class="hljs-number">-1</span>  col := <span class="hljs-number">-1</span>  isEmpty := <span class="hljs-literal">false</span>  <span class="hljs-comment">// finding the empty cell</span>  <span class="hljs-keyword">for</span> r, slice := <span class="hljs-keyword">range</span> *board {    <span class="hljs-keyword">for</span> c, value := <span class="hljs-keyword">range</span> slice {      <span class="hljs-keyword">if</span> value == <span class="hljs-number">0</span> {        isEmpty = <span class="hljs-literal">true</span>        row = r        col = c        <span class="hljs-keyword">break</span>      }     <span class="hljs-keyword">if</span> isEmpty {      <span class="hljs-keyword">break</span>     } <span class="hljs-comment">// found empty cell.</span>    }  }  <span class="hljs-keyword">if</span> !isEmpty {    <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>  } <span class="hljs-comment">//base condition</span>  <span class="hljs-comment">// if there is no empty cell then the board is solved</span>  <span class="hljs-keyword">for</span> i := <span class="hljs-number">1</span>; i &lt;= <span class="hljs-number">9</span>; i++ {    <span class="hljs-comment">// trying to put a number in that cell</span>    <span class="hljs-comment">// checking if it is safe to put that number in that cell</span>    <span class="hljs-keyword">if</span> isSafe(board, row, col, i) {      <span class="hljs-comment">// putting that number in that cell</span>      (*board)[row][col] = I      <span class="hljs-comment">// solving the rest of the board</span>      <span class="hljs-keyword">if</span> !solve(board) {        <span class="hljs-comment">// if the board is not solved then we need to backtrack</span>         (*board)[row][col] = <span class="hljs-number">0</span> <span class="hljs-comment">// backtrack</span>      } <span class="hljs-keyword">else</span> {      <span class="hljs-comment">// board it solved!</span>      <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>      }    }  }<span class="hljs-comment">// if all the numbers are tried and none of them is safe then return false</span><span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>}</code></pre><ol><li>Create a print function to print our solved sudoku pattern.</li></ol><pre><code class="lang-go"><span class="hljs-comment">// display prints sudoku board on console.</span><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">display</span><span class="hljs-params">(board [][]<span class="hljs-keyword">int</span>)</span></span> {  <span class="hljs-keyword">for</span> _, slice := <span class="hljs-keyword">range</span> board {    <span class="hljs-keyword">for</span> _, val := <span class="hljs-keyword">range</span> slice {      fmt.Printf(<span class="hljs-string">"%d, "</span>, val)    }    fmt.Println()  }}</code></pre><p><strong>Whole function with input taking part in main.go</strong>,</p><pre><code class="lang-go"><span class="hljs-keyword">import</span> (<span class="hljs-string">"bufio"</span><span class="hljs-string">"fmt"</span><span class="hljs-string">"log"</span><span class="hljs-string">"os"</span><span class="hljs-string">"strconv"</span><span class="hljs-string">"strings"</span>)<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {  fmt.Printf(<span class="hljs-string">"Enter the name of your file containing the Sudoku Pattern :        "</span>)  scanner := bufio.NewScanner(os.Stdin)  scanner.Scan()  <span class="hljs-keyword">var</span> file <span class="hljs-keyword">string</span>  file = scanner.Text()  <span class="hljs-keyword">if</span> !strings.Contains(file, <span class="hljs-string">".text"</span>) {    file = <span class="hljs-string">"pattern-1.text"</span>  }  input, err := os.ReadFile(fmt.Sprintf(<span class="hljs-string">"./inputs/%s"</span>, file))  <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {    log.Println(err)  }  board := parseInput(<span class="hljs-keyword">string</span>(input))  fmt.Println(<span class="hljs-string">"Defined Sudoku Pattern"</span>)  display(board)  fmt.Println()  fmt.Println(<span class="hljs-string">"Engine starts solving the pattern..."</span>)  <span class="hljs-keyword">if</span> solve(&amp;board) {  <span class="hljs-comment">//display(board)</span>  file, err := os.Create(fmt.Sprintf(<span class="hljs-string">"./outputs/%s"</span>, file))  <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {    log.Println(err)  }  <span class="hljs-keyword">for</span> _, slice := <span class="hljs-keyword">range</span> board {    s := <span class="hljs-string">""</span>    <span class="hljs-keyword">for</span> _, v := <span class="hljs-keyword">range</span> slice {      s= s + fmt.Sprintf(<span class="hljs-string">"%v, "</span>, v)    }    _, err = file.WriteString(fmt.Sprintf(<span class="hljs-string">"%v\n"</span>, s))    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {      log.Println(err)    }   }  }  fmt.Println(fmt.Sprintf(<span class="hljs-string">"Result is saved in \"./outouts/%v\""</span>, file))}</code></pre><h3 id="heading-3-performing-tests">3. Performing Tests</h3><ol><li>Git clone this repository: <a target="_blank" href="https://github.com/sarkartanmay393/SudokuSolver-Golang">github/SudokuSolver-Golang</a></li><li>Follow the steps performed in this video<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://vimeo.com/763376424">https://vimeo.com/763376424</a></div></li><li>Output will be:<pre><code class="lang-zsh"> $ go run main.go 3, 1, 6, 5, 7, 8, 4, 9, 2,  5, 2, 9, 1, 3, 4, 7, 6, 8,  4, 8, 7, 6, 2, 9, 5, 3, 1,  2, 6, 3, 4, 1, 5, 9, 8, 7,  9, 7, 4, 8, 6, 3, 1, 2, 5,  8, 5, 1, 7, 9, 2, 6, 4, 3,  1, 3, 8, 9, 4, 7, 2, 5, 6,  6, 9, 2, 3, 5, 1, 8, 7, 4,  7, 4, 5, 2, 8, 6, 3, 1, 9,</code></pre></li><li>You can see the test here also, <strong><a target="_blank" href="https://go.dev/play/p/k_crNjzrUEc">go/sudoku-engine</a></strong></li></ol><h3 id="heading-4-issue-to-solve-for-you">4. Issue to Solve for you</h3><p>Solve a project issue now: <strong><a target="_blank" href="https://github.com/sarkartanmay393/SudokuSolver-Golang/issues/1">sudoku-engine/issue#1</a></strong></p><blockquote><p>If you never tried open source, this is a good place to start and learn more of Git and Github.</p></blockquote><h2 id="heading-final-note">Final Note</h2><p>I hope you learned something new today. You can also contribute to this project. If you have any questions, feel free to ask me in the comments below. I will be happy to help you. It would be great if you share this article with your developer friends who are new to tech.</p><p>Follow me on: <a target="_blank" href="www.twitter.com/sarkartanmay393">@sarkartanmay393</a><br />Direct mail me: <a target="_blank" href="mailto:hello@tanmaysarkar.tech">hello@tanmaysarkar.tech</a></p>]]></description><link>https://tanmaysarkar.hashnode.dev/build-sudoku-solver-engine-using-go</link><guid isPermaLink="true">https://tanmaysarkar.hashnode.dev/build-sudoku-solver-engine-using-go</guid><dc:creator><![CDATA[Tanmay Sarkar]]></dc:creator><pubDate>Sun, 06 Nov 2022 08:01:27 GMT</pubDate><cover_image>https://cdn.hashnode.com/res/hashnode/image/upload/v1667654155553/H-nukWZ2r.png</cover_image></item><item><title><![CDATA[Deploy your containerized Go Web Application]]></title><description><![CDATA[<h2 id="heading-welcome-back-fellows">Welcome back fellows 👋🏻</h2><p>Today I am back with a new article on <a target="_blank" href="https://go.dev/">Go</a>, but this is slightly in production side. Today we are going to deploy a simple containerized Go web app on <a target="_blank" href="https://heroku.com/">Heroku</a>. I am assuming, you are well aware about how web servers are created in Go and how they work. That means, now you have created your own web server which can serve us a website locally, but you want to make it available for public with a target url right. How do you do that ? The answer is been coveyed in this blog. So start reading and following the learn more links to get to the topics that are neccessary for our deployment process.</p><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1666810355204/RSFVlSjhJ.png" alt="04.image.png" /></p><h3 id="heading-what-we-will-be-doing-today">What we will be doing today ? 🧐</h3><ol><li>Write a <em><code>Dockerfile</code></em></li><li>Write a <em><code>heroku.yml</code></em></li><li>Deploy our app on <a target="_blank" href="https://heroku.com/">Heroku</a>.</li></ol><h3 id="heading-prerequisite">Prerequisite </h3><ol><li><a target="_blank" href="https://go.dev/"><strong>Go</strong></a></li><li><a target="_blank" href="https://www.docker.com/get-started/"><strong>Docker</strong></a></li></ol><h3 id="heading-let-us-not-waste-time">Let us not waste time </h3><p>If you don't know much about Docker then you should learn about it now and for today's tutorial you can just install docker and play it with a little. I have suggested a video for a brief understanding about Docker, check that out definitely. Now, I am supposing you are aware of Docker and have basic knowledge of it. Because we are writing a Dockerfile and if you don't even know what Docker is, then it's not possible.</p><p>I can give you a brief introduction of Docker. It is like a virtual machine manager, that takes hardware resource from your machine and creates one or more hidden boxes inside your computer with those resources and provide a operating system in each of those boxes, this boxes are running containers, and this containers are created in docker from docker images. The goal of Docker is to make multiple isolated virtual machines in your computer.</p><blockquote><p>Learn basics of Docker before proceeding. <a target="_blank" href="https://www.docker.com/resources/what-container/">Learn More</a></p></blockquote><h5 id="heading-here-is-my-project-structure">Here is my project structure </h5><pre><code class="lang-shell"> main.go go.mod go.sum Dockerfile [yet to write] heroku.yml [yet to write] static     index.html</code></pre><blockquote><p><em>Visit my <a target="_blank" href="https://github.com/sarkartanmay393/Golang-Journey/tree/main/Web-Server">Github repo</a> of this project to get the idea, How I build a web server and used HTML with it.</em></p></blockquote><h5 id="heading-we-can-go-forward-now">We can go forward now </h5><p>We will start by writing Dockerfile and end with installing Heroku CLI to deploy our app effortlessly. This will be knowledge journey and I hope after this, you will understand the deployment process of Go web applications.</p><ul><li><strong>Write <code>Dockerfile</code></strong></li></ul><p>A Dockerfile is a declarative way of automatically creating a docker image, and we will create a alpine linux container where the app will run at a specific port. </p><p>Create a file with this name and follow my code below,</p><pre><code class="lang-dockerfile"># Using this minimal base image for our work.# It will consist of golang tool and nothing much more.FROM golang:1.19-alpine# Setting our current directory to /app inside our base image.WORKDIR /app# Copying everything from our Web-Server directory to our image's /app directory.COPY . .# Now all are necessary files are in our image.# So we can start our commands to run the go app.RUN go mod downloadRUN go build main.go# We have now a executable, named main.# First let us expose our docker container.# EXPOSE 8080# We hosting our app on heroku, and heroku provides a particular port# for us via enironment variables. And so here docker, we don't need to # our container, heroku takes care of it.# Run the executable.CMD ./main</code></pre><blockquote><p>Now with a simple command <code>docker build -t webapp .</code> you will get your fully functional docker image.</p></blockquote><ul><li><strong>Write <code>heroku.yml</code></strong></li></ul><p>This file is nothing but a declarative way of saying Heroku that here is how you build and how you run the app. This file is necessary for deploying a containerized app in Heroku automatically. This file is a manifest that defines our app and allows us to specify add-ons and config vars to use during app provisioning by Heroku.</p><pre><code class="lang-yml"><span class="hljs-attr">build:</span>  <span class="hljs-attr">docker:</span>   <span class="hljs-attr">web:</span>    <span class="hljs-string">Dockerfile</span><span class="hljs-attr">run:</span>  <span class="hljs-attr">web:</span>   <span class="hljs-string">./main</span></code></pre><p><br /></p><ul><li><strong>Getting started with Heroku</strong></li></ul><p>Heroku is a platform as a service (PaaS) that enables developers to build, run, and operate applications entirely in the cloud. We will host our application, and it will generate a URL to our deployed app. There is three different ways of deploying on Heroku.</p><ul><li>Using GitHub</li><li>Heroku CLI</li><li>Container Registry</li></ul><p>Now in this tutorial, we are gonna push our whole directory to heroku via git, and <code>heroku.yml</code> starts it's work to help heroku by telling how to build and run the application. Don't worry, I am gonna explain everything, but there is little task for you. Go and complete the mentioned prerequisite.</p><ul><li>Create account in <a target="_blank" href="https://heroku.com/signup">Heroku</a> </li><li>Learn more about Heroku Deployments from <a target="_blank" href="https://devcenter.heroku.com/categories/deployment">Docs</a></li><li>Install <a target="_blank" href="https://devcenter.heroku.com/articles/heroku-cli">Heroku CLI</a> </li></ul><p><br /></p><ul><li><strong>Using Heroku to Deploy</strong></li></ul><p>Now we are all set to host our application front public, open project directory and follow my lead.</p><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1666808068574/e7F94ufAq.png" alt="code editor view.png" /></p><p>Our Git status is clean and all necessary files are committed safely on Git. Now, let us use heroku cli tool to do the rest of work. But before that, go to your <a target="_blank" href="https://dashboard.heroku.com/apps">heroku dashboard</a> and create a app with your preferred name.</p><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1666808098416/AdDV_JILY.png" alt="heroku-create-new-app.png" /></p><p>Now, switch to terminal and command,</p><pre><code class="lang-shell">heroku login</code></pre><p>It will take you to a website and demands for login. After successfully login, we have set our heroku app stack to container. Here is how,</p><pre><code class="lang-shell">heroku stack:set container -a sample-web-09</code></pre><p>With <code>-a</code> alias, we specify the app that we have created earlier. Change the <code>sample-web-09</code> to your app name.</p><p>Now we need to add git remote of heroku by,</p><pre><code class="lang-shell">heroku git:remote -a sample-web-09</code></pre><p>This is the final look after these three commands.</p><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1666799980109/dUoKUgkqk.png" alt="terminal.png" /></p><p>And, now the final command, but before this you may have to command <code>git add .</code> and <code>git commit -s -m "last push 101"</code> and then,</p><pre><code class="lang-shell">git push heroku main</code></pre><p><img src="https://cvws.icloud-content.com/B/AZj-fMzlVbq1EyU70qy1WSMrM6ffASyGyg7TP7V6uGeM8OCruXv92c9Y/deploy+go+web+on+heroku.gif?o=AsPdBgftt_ZcVn-Q2DSvHHc5AgiDGcg0l89dXKS8KXHy&amp;v=1&amp;x=3&amp;a=CAog32qNcg4QfVpbuIR59p4muBncsvQcHpZz-s-DiZzSVvASbxCZ-PuvwTAYmdXXscEwIgEAUgQrM6ffWgT92c9Yaie0PdqZRBMgj4Fa_FQxb9WLQIkDaluouKVlZveCl9qEEhTSXm1PDRlyJ01RKNlq1CXEheOTsFklwbRcQZRuY47JgHQJMCoDCzLvG9hZf7VU0Q&amp;e=1666819943&amp;fl=&amp;r=e81af322-b8c9-461e-a700-42f4b4806aed-1&amp;k=PsUDapz2NvRsKmxE4n9LJg&amp;ckc=com.apple.clouddocs&amp;ckz=com.apple.CloudDocs&amp;p=30&amp;s=BcjvRgrkBbS8y9ALbjVrk9wdImw&amp;cd=i" alt="deploy go web.gif" /></p><p>To directly open up your web application link,</p><pre><code class="lang-shell">heroku open</code></pre><p>Checkout the app that I deployed in this blog, here is <a target="_blank" href="https://sample-web-09.herokuapp.com">sample-web-09</a>.</p><h3 id="heading-finishing-note">Finishing note 📝</h3><p>Hope you understood the process of deploying a Go based web server. I always try to explain things in detail, and still if you find any position where I should explain more then tell me in comments or ping me on twitter. I am always there for my article people.</p><p>Thanks you everybody for being with me. New blogs on Go and other techinal topics are yet to come out in upcoming days. So stay tuned, and follow me here on <a target="_blank" href="https://www.hashnode.com/tanmaysarkar/">@Hashnode</a>.</p><p>Follow me on 🐦 <a target="_blank" href="https://www.twitter.com/sarkartanmay393">@sarkartanmay393</a></p><p>Mail me anytime on 📬 <a target="_blank" href="mailto:hello@tanmaysarkar.tech">hello@tanmaysarkar.tech</a></p>]]></description><link>https://tanmaysarkar.hashnode.dev/deploy-your-containerized-go-web-application</link><guid isPermaLink="true">https://tanmaysarkar.hashnode.dev/deploy-your-containerized-go-web-application</guid><dc:creator><![CDATA[Tanmay Sarkar]]></dc:creator><pubDate>Thu, 27 Oct 2022 04:45:42 GMT</pubDate><cover_image>https://cdn.hashnode.com/res/hashnode/image/upload/v1666810316079/8b-KW6oLp.png</cover_image></item><item><title><![CDATA[Building a IMDB Web Scraper using Go]]></title><description><![CDATA[<h2 id="heading-welcome-all-to-my-homage">Welcome all to my homage 🛖</h2><p>Hi fellows, I have been learning about web scrapers these days and saw there is no many articles on Go itself on <a target="_blank" href="https://hashnode.com/search?q=golang">Hashnode</a> and building a scraper with it is far away. So I thought about let's build a simple cli tool which will take birthday as input and crawl a tiny part of the website <a target="_blank" href="https://imdb.com/search/name">IMDB</a> to look for celebrities who born on that date and stores various data into a file <code>outputs/mm-dd.json</code> inside output directory.</p><p>If you do not know about IMDB, it is a website which contains information about movies, TV shows, and celebrities. It is a very popular website and has a huge database of information. So, it is a good place to start learning about web scraping.</p><p>As you might not know, building a web scraper consists of four main steps :</p><ol><li><strong>Crawling</strong> : Crawling is the process of finding all the links on a website and adding them to a queue.</li><li><strong>Scraping</strong> : Scraping is the process of extracting data from a website.</li><li><strong>Parsing</strong> : Parsing is the process of converting the raw data into a structured format.</li><li><strong>Storing</strong> : Storing is the process of saving the data into a file or database.</li></ol><p>And we will look deep into all of them step by step, so sit tight and let's get started.</p><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1666266409520/h5TslqZm-.png" alt="imdb + golang.png" /></p><h2 id="heading-prerequisites">Prerequisites 👩🏻🏫</h2><ul><li><a target="_blank" href="https://go.dev/"><strong>Go</strong></a></li><li><a target="_blank" href="https://www.w3schools.com/js/js_json_intro.asp"><strong>JSON</strong></a></li></ul><blockquote><p>And also you should have basic knowledge of <strong>crawlers</strong> and <strong>scrapers</strong> in general. <a target="_blank" href="https://oxylabs.io/blog/crawling-vs-scraping">Learn here</a></p></blockquote><h2 id="heading-let-us-begin-then">Let us begin then </h2><h3 id="heading-1-project-setup">1. Project Setup</h3><p>At first, Create a directory and make a <code>main.go</code> file inside and open terminal in that directory to command :</p><pre><code class="lang-zsh">go mod init github.com/sarkartanmay/IMBD-Scraper-Golang</code></pre><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1666267177175/NkgQw4hIw.png" alt="Screenshot 2022-10-20 at 5.28.46 PM.png" /></p><p>I am using my GitHub repo link in my module name as a convention, so you should change that to your desired module name. E.g. <code>github.com/username/project-name</code> and you can learn more about <a target="_blank" href="https://go.dev/blog/using-go-modules">Modules in Go</a> here.</p><p>Then, install <a target="_blank" href="http://go-colly.org/">colly</a> by commanding in terminal :</p><pre><code class="lang-zsh">go get github.com/gocolly/colly</code></pre><p>And this is how our project setup is done, let us now go straight into coding our web scraper.</p><h3 id="heading-2-coding-the-scraper">2. Coding the Scraper</h3><p>I hope as you write the code, your code editor will import the packages that are necessary.And with that, let us start coding our scraper.</p><p>First, we will make customized structs that will hold our scraped data in program memory. We will make a struct for each type of data we want to scrape. For example, we will make a struct for each celebrity and a struct for each movie.</p><pre><code class="lang-go"><span class="hljs-comment">//  Star holds a celebrety's name and other imdb information.</span><span class="hljs-keyword">type</span> Star <span class="hljs-keyword">struct</span> {    Name      <span class="hljs-keyword">string</span>  <span class="hljs-string">`json:"name"`</span>    Photo     <span class="hljs-keyword">string</span>  <span class="hljs-string">`json:"photo"`</span>    JobTitle  <span class="hljs-keyword">string</span>  <span class="hljs-string">`json:"job_title"`</span>    Birthdate <span class="hljs-keyword">string</span>  <span class="hljs-string">`json:"birthdate"`</span>    Bio       <span class="hljs-keyword">string</span>  <span class="hljs-string">`json:"bio"`</span>    TopMovies []Movie <span class="hljs-string">`json:"top_movies"`</span>}<span class="hljs-comment">// 🎦 Movie holds basic information about a movie.</span><span class="hljs-keyword">type</span> Movie <span class="hljs-keyword">struct</span> {    Title   <span class="hljs-keyword">string</span> <span class="hljs-string">`json:"title"`</span>    Release <span class="hljs-keyword">string</span> <span class="hljs-string">`json:"release"`</span>}</code></pre><p>This is our two structures that will hold our scraped data. We will use the <a target="_blank" href="https://pkg.go.dev/encoding/json">json</a> package to convert our data into JSON format. We will use the <code>json</code> tag to specify the name of the key in the JSON object, and to tell Go that when we convert our struct into a JSON object, it must name them as we specified in the <code>json</code> tag.</p><blockquote><p>For example, the <code>Name</code> field in the <code>Star</code> struct will be converted to the <code>name</code> key and <code>TopMovies</code> to <code>top_movies</code> in the JSON object.</p></blockquote><p>Now, we will create function that will take two parameters (day, month) to crawl into IMDB with specified date and return scraped data in a slice of stars <code>[]stars</code> .</p><pre><code class="lang-go"><span class="hljs-comment">// 🕷 Crawl crawls the imdb website for a given page and returns a list of stars.</span><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">Crawl</span><span class="hljs-params">(month <span class="hljs-keyword">int</span>, day <span class="hljs-keyword">int</span>)</span> []<span class="hljs-title">Star</span></span> {    <span class="hljs-comment">// stars will hold all the scraped data.</span>    <span class="hljs-keyword">var</span> stars []Star    <span class="hljs-comment">// Collectors are used to scrape data from a website.</span>    <span class="hljs-comment">// Main collector instance is initialized here.</span>    <span class="hljs-comment">// Our main collector c will only look for profile links of celebreties</span>    <span class="hljs-comment">// and go on next pages if there is next button on current page.</span>    c := colly.NewCollector(        <span class="hljs-comment">// Colly collector will only visit the given domains.</span>        colly.AllowedDomains(<span class="hljs-string">"www.imdb.com"</span>, <span class="hljs-string">"imdb.com"</span>),        <span class="hljs-comment">// Colly collector stores cache and uses from here.</span>        colly.CacheDir(<span class="hljs-string">"./.imdb_cache"</span>),        <span class="hljs-comment">// Cache is disabled by default, so we need to enable it.</span>    )    <span class="hljs-comment">// ic stands for Info Collector, is just cloned from main collector.</span>    <span class="hljs-comment">// This collector will be used to scrape data from the info page.</span>    <span class="hljs-comment">// It will go inside a profile link and look for data in that only.</span>    <span class="hljs-comment">// This collector will be on work everytime main collector find a new profile link.</span>    ic := c.Clone()    <span class="hljs-comment">// Where crawler sees 'mode-detail' class attribute, it will call back the function.</span>    c.OnHTML(<span class="hljs-string">".mode-detail"</span>, <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(e *colly.HTMLElement)</span></span> {        <span class="hljs-comment">// Getting the profile url from the href attribute, it is goquery selector string.</span>        <span class="hljs-comment">// 'div.lister-item-image &gt; a' is path of profile url in HTML.</span>        <span class="hljs-comment">// At fist there is a Div tag with class 'lister-item-image' and</span>        <span class="hljs-comment">// inside that there is a tag 'a' where href attribute is profile url.</span>        profileUrl := e.ChildAttr(<span class="hljs-string">"div.lister-item-image &gt; a"</span>, <span class="hljs-string">"href"</span>)        <span class="hljs-comment">// But the profile url is relative, so we need to add the base url.</span>        <span class="hljs-comment">// profileUrl is "/name/nm0000123/" corrently.</span>        profileUrl = e.Request.AbsoluteURL(profileUrl)        <span class="hljs-comment">// Now profileUrl is "https://www.imdb.com/name/nm0000123/".</span>        <span class="hljs-comment">// Asking info collector to visit the profile url.</span>        ic.Visit(profileUrl)    })    <span class="hljs-comment">// This crawler function gets into next page, if there is one.</span>    <span class="hljs-comment">// On IMDB, there is a button with text 'Next' on each page with</span>    <span class="hljs-comment">// class 'lister-page-next next-page' and we are looking only for that.</span>    c.OnHTML(<span class="hljs-string">"a.lister-page-next"</span>, <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(e *colly.HTMLElement)</span></span> {        <span class="hljs-comment">// Getting the next page url from the href attribute.</span>        nextPageUrl := e.Attr(<span class="hljs-string">"href"</span>)        nextPageUrl = e.Request.AbsoluteURL(nextPageUrl)        <span class="hljs-comment">// Asking main collector to visit the next page url.</span>        c.Visit(nextPageUrl)    })    <span class="hljs-comment">// This info collector crawler function gets the information of the celebrety inside the 'profileURL' page.</span>    ic.OnHTML(<span class="hljs-string">"#content-2-wide"</span>, <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(e *colly.HTMLElement)</span></span> {        <span class="hljs-comment">// Getting all details using info collector and storing them in a Star struct.</span>        temporaryStar := Star{            Name:      e.ChildText(<span class="hljs-string">"h1.header &gt; span.itemprop"</span>),            Photo:     e.ChildAttr(<span class="hljs-string">"#name-poster"</span>, <span class="hljs-string">"src"</span>),            JobTitle:  e.ChildText(<span class="hljs-string">"#name-job-categories &gt; a &gt; span.itemprop"</span>),            Birthdate: e.ChildAttr(<span class="hljs-string">"#name-born-info &gt; time"</span>, <span class="hljs-string">"datetime"</span>),            Bio:       strings.TrimSpace(e.ChildText(<span class="hljs-string">"#name-bio-text &gt; div.name-trivia-bio-text &gt; div.inline"</span>)),            TopMovies: []Movie{},        }        <span class="hljs-comment">// Now iterating over all the top movies of the profile url page.</span>        e.ForEach(<span class="hljs-string">"div.knownfor-title"</span>, <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(_ <span class="hljs-keyword">int</span>, el *colly.HTMLElement)</span></span> {            temporaryStar.TopMovies = <span class="hljs-built_in">append</span>(temporaryStar.TopMovies, Movie{                Title:   el.ChildText(<span class="hljs-string">"div.knownfor-title-role &gt; a.knownfor-ellipsis"</span>),                Release: el.ChildText(<span class="hljs-string">"div.knownfor-title &gt; div.knownfor-year &gt; span.knownfor-ellipsis"</span>),            })        })        <span class="hljs-comment">// Now appending the temporaryStar to the stars slice.</span>        stars = <span class="hljs-built_in">append</span>(stars, temporaryStar)    })    <span class="hljs-comment">// Printing text of every request made on info collector.</span>    ic.OnRequest(<span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(r *colly.Request)</span></span> {        fmt.Println(<span class="hljs-string">"Visiting:    "</span>, r.URL.String())    })    <span class="hljs-comment">// Our link to crawl with user specified date and month.</span>    startUrl := fmt.Sprintf(<span class="hljs-string">"https://www.imdb.com/search/name/?birth_monthday=%d-%d"</span>, month, day)    fmt.Println(<span class="hljs-string">"Starting crawling into    "</span>, startUrl)    <span class="hljs-comment">// Starting the main collector.</span>    c.Visit(startUrl)    <span class="hljs-comment">// Returning all the scraped data in a slice of stars.</span>    <span class="hljs-keyword">return</span> stars}</code></pre><p>If you are overwhelmed by the code, don't worry. As I always write lots of comments in code, if you read them, you will understand what is going on.</p><p>Let's break down one important part of scraping.</p><ul><li><h3 id="heading-html-structure-recognition-and-query-string">HTML Structure Recognition and Query String 🧵🔎</h3></li></ul><p>Q. How we can recognize the HTML structure of a website ?</p><p>A. There are two ways to do that. One is to use the browser's developer tools manually and the other is to use the <a target="_blank" href="gocally.com">colly</a> package's <code>InspectElement</code> function.</p><p>I like the first one, manually going through web pages and finding the HTML elements. Searching in HTML is kind of a skill itself, you need to know how to find the right element in HTML.</p><p>Let us see how we do that ?</p><div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://youtu.be/rL07q10eo0Q">https://youtu.be/rL07q10eo0Q</a></div><blockquote><p>Here is video that I made for you to understand how to find right HTML component of a website using query strings.</p></blockquote><p>Now, we can go further into the code. Let us now deal with the <code>[]Star</code> slice that we are returning from the <code>Crawl</code> function.</p><pre><code class="lang-go"><span class="hljs-comment">// main takes two arguments, month and day. </span><span class="hljs-comment">// Parse them into integers and call Crawl function.</span><span class="hljs-comment">// Crawl function returns a slice of stars.</span><span class="hljs-comment">// That slice is converted into JSON object.</span><span class="hljs-comment">// And then writes the object into a file.</span><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {    <span class="hljs-comment">// Printing prompt for user to input values.</span>    <span class="hljs-keyword">var</span> input <span class="hljs-keyword">string</span>    <span class="hljs-comment">// User should type just like this. e.g.. 12-23</span>    fmt.Println(<span class="hljs-string">"Type a date and month in (MM-DD) format:    "</span>)    _, err := fmt.Scanf(<span class="hljs-string">"%s"</span>, &amp;input)    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> { <span class="hljs-comment">// Error handling</span>        <span class="hljs-comment">// Fatalln will print the error and exit the program.</span>        log.Fatalln(<span class="hljs-string">"Unable to read input because    "</span>, err)    }    <span class="hljs-comment">// Splitting the input into month and day.</span>    sliceOfInput := strings.Split(input, <span class="hljs-string">"-"</span>)    <span class="hljs-comment">// Converting the month into integer.</span>    month, err := strconv.Atoi(sliceOfInput[<span class="hljs-number">0</span>])    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {         log.Fatalln(<span class="hljs-string">"Unable to convert month into int because    "</span>, err)    }    <span class="hljs-comment">// Converting the month into integer.</span>    day, err := strconv.Atoi(sliceOfInput[<span class="hljs-number">1</span>])    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {         log.Fatalln(<span class="hljs-string">"Unable to convert date into int because    "</span>, err)    }    <span class="hljs-comment">// Crawling the website with the given month and day and stores the data into a slice of Star.</span>    <span class="hljs-comment">// Calling Crawl func with month and day.</span>    <span class="hljs-comment">// Storing the returned slice of Star into stars variable.</span>    stars := Crawl(month, day)    <span class="hljs-comment">// To print all the scraped data in terminal.</span>    <span class="hljs-comment">// This code part is commented out, because it is not necessary.</span>    <span class="hljs-comment">// You can play with it to show the scraped data on terminal.</span>    <span class="hljs-comment">// encoder := json.NewEncoder(os.Stderr)</span>    <span class="hljs-comment">// encoder.SetIndent("", "   ")</span>    <span class="hljs-comment">// err := encoder.Encode(stars)</span>    <span class="hljs-comment">// Converting Star struct into JSON.</span>    data, err := json.MarshalIndent(stars, <span class="hljs-string">""</span>, <span class="hljs-string">"    "</span>)    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {        log.Println(<span class="hljs-string">"Error while marshalling JSON: "</span>, err)    }    <span class="hljs-comment">// Writing JSON into a file called 'mm-dd.json'.</span>    <span class="hljs-comment">// file name will vary according to the month and day.</span>    <span class="hljs-comment">// We are using os pkg to write the file.</span>    fileName := fmt.Sprintf(<span class="hljs-string">"%s.json"</span>, input)    err = os.WriteFile(fmt.Sprintf(<span class="hljs-string">"./outputs/%s"</span>, fileName), data, <span class="hljs-number">0644</span>)    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {        <span class="hljs-keyword">if</span> err.Error() == <span class="hljs-string">"open ./outputs/12-23.json: no such file or directory"</span> {            log.Println(<span class="hljs-string">"Making directory named outputs."</span>)            os.Mkdir(<span class="hljs-string">"./outputs"</span>, <span class="hljs-number">0755</span>) <span class="hljs-comment">// making a directory.</span>            err := os.WriteFile(fmt.Sprintf(<span class="hljs-string">"./outputs/%s"</span>, fileName), data, <span class="hljs-number">0644</span>)            <span class="hljs-keyword">if</span> err == <span class="hljs-literal">nil</span> {                log.Fatalln(<span class="hljs-string">"Web is scraped and JSON file is created."</span>)            }        }        log.Fatalln(<span class="hljs-string">"Error while writing JSON: "</span>, err)    }    log.Println(<span class="hljs-string">"Web is scraped and JSON file is created."</span>)}<span class="hljs-comment">// This is where our code ends.</span></code></pre><blockquote><p>For the whole code, you can check out the <a target="_blank" href="https://github.com/sarkartanmay393/IMDB-Scraper-Golang">IMDB-Scraper-Golang</a> repository.</p></blockquote><h3 id="heading-3-testing-our-scraper">3. Testing our Scraper</h3><p>Now, we run our program to test it. We will run it with the date and month of my birthday. So, I will run the <code>main.go</code> then type <code>12-23</code> and hit enter.</p><p><a target="_blank" href="https://asciinema.org/a/FKaR3HijqXw09jHNpwJ01BjNJ"><img src="https://asciinema.org/a/FKaR3HijqXw09jHNpwJ01BjNJ.svg" alt="asciicast" /></a></p><h2 id="heading-conclusion">Conclusion :</h2><p>This was a simple yet interesting scraper project. We scraped the IMDB website and got the data of all the celebrities who were born on the same day as me. We used <a target="_blank" href="http://go-colly.org/">colly</a> package to scrape the website. We also used the <code>os</code> package to write the scraped data into a file.</p><p>I hope you liked this blog and learned something new. If you have any inquiry or suggestions, feel free to tell me in the comments section or on Twitter. I will be very happy to get connected with you.</p><p>A special thanks  to <a target="_blank" href="https://youtube.com/c/AkhilSharmaTech">Akhil Sharma</a>, I learned from him.</p><p>Follow me on <a target="_blank" href="https://twitter.com/sarkartanmay393">@sarkartanmay393</a></p>]]></description><link>https://tanmaysarkar.hashnode.dev/building-a-imdb-web-scraper-using-go</link><guid isPermaLink="true">https://tanmaysarkar.hashnode.dev/building-a-imdb-web-scraper-using-go</guid><dc:creator><![CDATA[Tanmay Sarkar]]></dc:creator><pubDate>Fri, 21 Oct 2022 04:45:42 GMT</pubDate><cover_image>https://cdn.hashnode.com/res/hashnode/image/upload/v1666263676327/ouczJNN0b.png</cover_image></item><item><title><![CDATA[Connect Database in your Go project with ease]]></title><description><![CDATA[<h2 id="heading-introduction">Introduction</h2><p>Go is a statically typed, compiled programming language and useful for carrying out programming for scalable servers and large software systems. Golang programming language was built to fill in the gaps of C++ and Java that Google came across while working with its servers and distributed systems.</p><p>On the other hand, PostgreSQL, also known as Postgres, is a free and open-source relational database management system emphasizing extensibility and SQL compliance and used as the primary data store or data warehouse for many web, mobile, geospatial, and analytics applications.</p><p>And today we will interact with a running database using this very language, and print out every step change in database in our terminal.</p><p><img src="https://miro.medium.com/max/1400/1*7f9kv--9ejp0hzHsSaN5nw.png" alt="Go and PostgreSQL" /></p><h2 id="heading-prerequisites">Prerequisites</h2><p>You should have a basic knowledge of</p><ul><li><strong>Go</strong></li><li><strong>PostgreSQL</strong></li></ul><h2 id="heading-lets-begin">Lets Begin</h2><p><strong>1. Setup Postgres on Local Machine</strong></p><p>Firstly, download <a target="_blank" href="https://www.postgresql.org/download/">PostgreSQL</a> for you specific operating system. Mac users can just use this <a target="_blank" href="https://postgresapp.com/">postgresapp</a>, it is very light and easy to use.</p><p>After downloading, install the software and open up to start your server.</p><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665854905954/HJzzvAsrc.png" alt="postgresapp.png" class="image--center mx-auto" /></p><blockquote><p>PostgreSQL server runs on port 5432 by default.</p></blockquote><p>Now, download and install a visual database viewer and editor like <a target="_blank" href="https://eggerapps.at/postico/">Postico</a> or even <a target="_blank" href="https://dbeaver.io/download/">DBeaver</a>.</p><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665909425111/ovtc-6_Ro.png" alt="pestico.png" /></p><blockquote><p>Pestico is very easy to use but paid, still I like to use it in free version.</p></blockquote><p>Our server is now running in background, now we can start building a Go program to interact with the running database. In my case the name of the database is <code>test-database</code>. You can create new database in Pestico itself and I hope you are familiar with databases.</p><p><strong>2. Setup Go Project</strong></p><p>Open a new folder in your favorite code editor and create a <code>main.go</code> file containing the code</p><pre><code class="lang-go"><span class="hljs-keyword">package</span> main<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {    <span class="hljs-comment">// Connect to database</span>    <span class="hljs-comment">// Test Connection</span>    <span class="hljs-comment">// View Rows</span>    <span class="hljs-comment">// Insert Row</span>    <span class="hljs-comment">// View Rows</span>    <span class="hljs-comment">// Update Row</span>    <span class="hljs-comment">// View Rows</span>    <span class="hljs-comment">// Delete Row</span>    <span class="hljs-comment">// View Rows</span>    <span class="hljs-comment">// View Row by ID</span>}</code></pre><p>And hit the command on terminal to initiate a module with module name and here I put my <a target="_blank" href="https://github.com/sarkartanmay393/Go-PostgreSQL-Test">GitHub repository</a> link as a convention.</p><pre><code class="lang-shell">go mod init github.com/sarkartanmay393/Go-PostgreSQL-Test</code></pre><p>As you can see our main function with a lot of areas with specified tasks, we are going to connect database with our program then test it, view its data, perform insert, delete, update and view its data again to see the changes on every step in the specific table of our database.</p><p><strong>3. Writing Code</strong></p><ul><li><p>Now, lets connect our database with Go program</p><pre><code class="lang-go"><span class="hljs-comment">// Connect to database</span>dsn := <span class="hljs-string">"host=localhost port=5432 dbname=test-database user=postgres password="</span> <span class="hljs-comment">// replace fields with your own database credentials</span>conn, err := sql.Open(<span class="hljs-string">"pgx"</span>, dsn) <span class="hljs-comment">// Opening connection to database with the driver 'pgx'</span><span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> { <span class="hljs-comment">// Error handling</span>  log.Fatalf(<span class="hljs-string">"Unable to open database: %v\n"</span>, err)}<span class="hljs-keyword">defer</span> conn.Close() <span class="hljs-comment">// This db connection will stop when our program finishes not before that.</span></code></pre><blockquote><p>For using pgx driver, we have to import <code>_ "github.com/jacke/pgx/v5/stdlib"</code> in our function.</p></blockquote></li><li><p>Time to test our connection with program</p><pre><code class="lang-go"><span class="hljs-comment">// Test Connection</span>err = conn.Ping() <span class="hljs-comment">// Ping function will test the connection and return error if any problem occurs.</span><span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> { <span class="hljs-comment">// Error handing</span>  log.Fatalln(<span class="hljs-string">"Unable to ping database: "</span>, err)}log.Println(<span class="hljs-string">"Pinged Database!"</span>)</code></pre></li><li>For viewing all rows of our table from database, lets create a function so that we can use it repeatedly.</li></ul><pre><code class="lang-go"><span class="hljs-comment">// viewRows prints all available information from database.</span><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">viewRows</span><span class="hljs-params">(conn *sql.DB)</span> <span class="hljs-title">error</span></span> {    <span class="hljs-comment">// Remember to use `` instead of '' or "" for multiline strings</span>    <span class="hljs-comment">// Query to select all rows from table, SQL language is used here.</span>    query := <span class="hljs-string">`SELECT id, first_name, last_name, email FROM users ORDER BY id;`</span>     rows, err := conn.Query(query) <span class="hljs-comment">// Query function will execute the query and return rows and error if any.</span>    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> { <span class="hljs-comment">// Error handling</span>        log.Println(<span class="hljs-string">"Unable to query result."</span>)        <span class="hljs-keyword">return</span> err    }    <span class="hljs-comment">// We will use defer to close the rows after the function finishes.</span>    <span class="hljs-keyword">defer</span> rows.Close()    <span class="hljs-keyword">var</span> id <span class="hljs-keyword">int8</span>    <span class="hljs-keyword">var</span> first_name, last_name, email <span class="hljs-keyword">string</span>    <span class="hljs-keyword">for</span> rows.Next() { <span class="hljs-comment">// Looping through all rows</span>        <span class="hljs-comment">// scanning the rows and storing in variables</span>        err := rows.Scan(&amp;id, &amp;first_name, &amp;last_name, &amp;email)        <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {            log.Println(<span class="hljs-string">"Something went wrong while scanning rows."</span>)            <span class="hljs-keyword">return</span> err        }        fmt.Printf(<span class="hljs-string">"ID: %v, FIRST: %v, LAST: %v, EMAIL: %v\n"</span>, id, first_name, last_name, email)    }    fmt.Println(<span class="hljs-string">"----------------------------------"</span>)    <span class="hljs-keyword">if</span> err = rows.Err(); err != <span class="hljs-literal">nil</span> { <span class="hljs-comment">// Rechecking for error in rows.</span>        log.Println(<span class="hljs-string">"Something went wrong while iterating over rows."</span>)        <span class="hljs-keyword">return</span> err    }    <span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span>}</code></pre><ul><li><p>Now we can see our data with a just <code>viewRows(conn)</code> function call. But I am writing some extra codes with it to get better look in our terminal.</p><pre><code class="lang-go"><span class="hljs-comment">// View Rows</span>fmt.Printf(<span class="hljs-string">"Initialising with these two entries.\n"</span>)err = viewRows(conn) <span class="hljs-comment">// Only call the function to view rows.</span><span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {  log.Println(<span class="hljs-string">"Unable to view database: "</span>, err)}</code></pre></li><li><p>Now we can see data from database in terminal, hit command <code>go run main.go</code> and as because I had put a row with my own name, it is shown in terminal. </p></li></ul><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665857901943/2x3aPczaw.png" alt="output1.png" /></p><ol><li>How can we insert a row in our database ?</li></ol><pre><code class="lang-sql"><span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> <span class="hljs-keyword">users</span> (first_name, last_name, email) <span class="hljs-keyword">VALUES</span> ($<span class="hljs-number">1</span>, $<span class="hljs-number">2</span>, $<span class="hljs-number">3</span>)</code></pre><ol><li>How can we update a row in our database ?</li></ol><pre><code class="lang-sql"><span class="hljs-keyword">UPDATE</span> <span class="hljs-keyword">users</span> <span class="hljs-keyword">SET</span> email = $<span class="hljs-number">1</span> <span class="hljs-keyword">WHERE</span> <span class="hljs-keyword">id</span> = $<span class="hljs-number">2</span></code></pre><ol><li>How can we delect a row in our database ?</li></ol><pre><code class="lang-sql"><span class="hljs-keyword">DELETE</span> <span class="hljs-keyword">FROM</span> <span class="hljs-keyword">users</span> <span class="hljs-keyword">WHERE</span> <span class="hljs-keyword">id</span> = $<span class="hljs-number">1</span></code></pre><p>These are SQL codes to perform tasks in database, and <code>$1</code> or <code>$2</code> are placeholders, we have to populate these placeholders with appropriate values. Just like these,</p><ul><li>Lets see how can we insert a row in database in Go<pre><code class="lang-go"><span class="hljs-comment">// Insert Row</span>query := <span class="hljs-string">`INSERT INTO users (id, first_name, last_name, email) values ($1, $2, $3, $4)`</span><span class="hljs-comment">// query is the SQL statement to perform in database using GO</span>_, err = conn.Exec(query, <span class="hljs-number">3</span>, <span class="hljs-string">"Amit"</span>, <span class="hljs-string">"Nandi"</span>, <span class="hljs-string">"amit@ac.org"</span>) <span class="hljs-comment">// Executing a query with 4 placeholders.</span><span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> { <span class="hljs-comment">// Error handling</span>  log.Println(<span class="hljs-string">"Unable to insert into database: "</span>, err)}</code></pre></li></ul><p>As you can see, we can execute any query just calling <code>conn</code> and all other tasks are shown in below <code>main.go</code>, try to understand reading the comments.</p><pre><code class="lang-go"><span class="hljs-keyword">package</span> main<span class="hljs-keyword">import</span> (    <span class="hljs-string">"database/sql"</span>    <span class="hljs-string">"fmt"</span>    <span class="hljs-string">"log"</span>    _ <span class="hljs-string">"github.com/jackc/pgx/v5/stdlib"</span> <span class="hljs-comment">// to just use the driver name `pgx`, we have to import it.</span>)<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {    <span class="hljs-comment">// Connect to database</span>    dsn := <span class="hljs-string">"host=localhost port=5432 dbname=test-database user=postgres password="</span> <span class="hljs-comment">// replace fields with your own database credentials</span>    conn, err := sql.Open(<span class="hljs-string">"pgx"</span>, dsn)                                              <span class="hljs-comment">// Opening connection to database with the driver 'pgx'</span>    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {                                                                <span class="hljs-comment">// Error handling</span>        log.Fatalf(<span class="hljs-string">"Unable to open database: %v\n"</span>, err)    }    <span class="hljs-keyword">defer</span> conn.Close() <span class="hljs-comment">// This db connection will stop when our program finishes not before that.</span>    <span class="hljs-comment">// Test Connection</span>    err = conn.Ping() <span class="hljs-comment">// Ping verifies a connection to the database is still alive, establishing a connection if necessary.</span>    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {   <span class="hljs-comment">// Error handling</span>        log.Fatalln(<span class="hljs-string">"Unable to ping database: "</span>, err)    }    log.Println(<span class="hljs-string">"Pinged Database!"</span>)    <span class="hljs-comment">// View Rows</span>    fmt.Printf(<span class="hljs-string">"Initialising with these two entries.\n"</span>)    err = viewRows(conn) <span class="hljs-comment">// Only function call to view all data in terminal.</span>    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {      <span class="hljs-comment">// Error handling</span>        log.Println(<span class="hljs-string">"Unable to view database: "</span>, err)    }    <span class="hljs-comment">// Insert Row</span>    query := <span class="hljs-string">`INSERT INTO users (id, first_name, last_name, email) values ($1, $2, $3, $4)`</span>    <span class="hljs-comment">// query is the SQL statement to perform in database using GO</span>    _, err = conn.Exec(query, <span class="hljs-number">3</span>, <span class="hljs-string">"Amit"</span>, <span class="hljs-string">"Nandi"</span>, <span class="hljs-string">"amit@ac.org"</span>) <span class="hljs-comment">// Executing a query with 4 placeholders.</span>    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {                                              <span class="hljs-comment">// Error handling</span>        log.Println(<span class="hljs-string">"Unable to insert into database: "</span>, err)    }    <span class="hljs-comment">// View Rows</span>    err = viewRows(conn) <span class="hljs-comment">// View all data again.</span>    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {      <span class="hljs-comment">// Error handling</span>        log.Println(<span class="hljs-string">"Unable to view database: "</span>, err)    }    <span class="hljs-comment">// Update Row</span>    query = <span class="hljs-string">`UPDATE users SET email = $1 WHERE id = $2`</span>    <span class="hljs-comment">// query to update something in our database, where id matches with our given id.</span>    _, err = conn.Exec(query, <span class="hljs-string">"deba@slg.org"</span>, <span class="hljs-number">2</span>) <span class="hljs-comment">// Executing query with 2 placeholders, email and id.</span>    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {                              <span class="hljs-comment">// Error handling</span>        log.Println(<span class="hljs-string">"Unable to update database: "</span>, err)    }    <span class="hljs-comment">// View Rows</span>    err = viewRows(conn) <span class="hljs-comment">// Viewing all rows again.</span>    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {      <span class="hljs-comment">// Error handling</span>        log.Println(<span class="hljs-string">"Unable to view database: "</span>, err)    }    <span class="hljs-comment">// Delete Row</span>    query = <span class="hljs-string">`DELETE FROM users WHERE id = $1`</span>    <span class="hljs-comment">// query to delete a specific row fromd database where id matches.</span>    _, err = conn.Exec(query, <span class="hljs-number">1</span>) <span class="hljs-comment">// Executing the specific query to delete thw row whose id is 1.</span>    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {              <span class="hljs-comment">// Error handling</span>        log.Println(<span class="hljs-string">"Unable to execute delete query."</span>)    }    <span class="hljs-comment">// View Rows</span>    viewRows(conn)    <span class="hljs-comment">// View Row by ID</span>    <span class="hljs-keyword">var</span> id <span class="hljs-keyword">int</span>    <span class="hljs-keyword">var</span> first_name, last_name, email <span class="hljs-keyword">string</span>    <span class="hljs-comment">// declaring some variables to hold data and will come from database</span>    query = <span class="hljs-string">`SELECT id, first_name, last_name, email FROM users WHERE id = $1`</span>    <span class="hljs-comment">// SELECT will show us data like id, first, last and email FROM a table called users WHERE id is placeholder.</span>    err = conn.QueryRow(query, <span class="hljs-number">3</span>).Scan(&amp;id, &amp;first_name, &amp;last_name, &amp;email)    <span class="hljs-comment">// QueryRow executes a query that is expected to return at most one row.</span>    <span class="hljs-comment">// We are scaning our returned row to extract the values that came.</span>    fmt.Println(<span class="hljs-string">"QUERYROW \t"</span>, first_name, last_name, email) <span class="hljs-comment">// Printing everything in terminal.</span>    <span class="hljs-comment">// Close Connection</span>}<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">viewRows</span><span class="hljs-params">(conn *sql.DB)</span> <span class="hljs-title">error</span></span> {    <span class="hljs-comment">// Remember to use `` instead of '' or "" for multiline strings</span>    <span class="hljs-comment">// Query to select all rows from table, SQL language is used here.</span>    query := <span class="hljs-string">`SELECT id, first_name, last_name, email FROM users ORDER BY id;`</span>    rows, err := conn.Query(query) <span class="hljs-comment">// Query function will execute the query and return rows and error if any.</span>    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {                <span class="hljs-comment">// Error handling</span>        log.Println(<span class="hljs-string">"Unable to query result."</span>)        <span class="hljs-keyword">return</span> err    }    <span class="hljs-comment">// We will use defer to close the rows after the function finishes.</span>    <span class="hljs-keyword">defer</span> rows.Close()    <span class="hljs-keyword">var</span> id <span class="hljs-keyword">int8</span>    <span class="hljs-keyword">var</span> first_name, last_name, email <span class="hljs-keyword">string</span>    <span class="hljs-comment">// Rows is like a list of row and looping through it to extract values from all indivisual row.</span>    <span class="hljs-keyword">for</span> rows.Next() { <span class="hljs-comment">// Looping through all rows</span>        <span class="hljs-comment">// scanning the rows and storing in variables</span>        err := rows.Scan(&amp;id, &amp;first_name, &amp;last_name, &amp;email)        <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {            log.Println(<span class="hljs-string">"Something went wrong while scanning rows."</span>)            <span class="hljs-keyword">return</span> err        }        fmt.Printf(<span class="hljs-string">"ID: %v, FIRST: %v, LAST: %v, EMAIL: %v\n"</span>, id, first_name, last_name, email)    }    fmt.Println(<span class="hljs-string">"----------------------------------"</span>)    <span class="hljs-keyword">if</span> err = rows.Err(); err != <span class="hljs-literal">nil</span> { <span class="hljs-comment">// Rechecking for error in rows.</span>        log.Println(<span class="hljs-string">"Something went wrong while iterating over rows."</span>)        <span class="hljs-keyword">return</span> err    }    <span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span>}</code></pre><blockquote><p>I have created a repository on GitHub, <a target="_blank" href="https://github.com/sarkartanmay393/Go-PostgreSQL-Test">Go-Postgres-Test</a> where you can visit can check out whole project.</p></blockquote><p> And now the final terminal output : </p><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665909130347/jtdP2t8A1.png" alt="final-terminal-output.png" /></p><hr /><h2 id="heading-final-note">Final Note</h2><p>Learning to interact with databases through Go is useful in these days when Go is getting popular every day and more people are using it for there server side works. I am making a <a target="_blank" href="https://github.com/sarkartanmay393/RoomReservation-WebApp">Room Reservation</a> project where it needs to talk with database to parse and manipulate data, and from there I have learnt using database query statements in Go.</p><p>Hope that you have learnt something new today. If you like my presentation through this article, it would be great if you share this article with your developer friends who are new to Go and databases. </p><p>Follow me on: <a target="_blank" href="www.twitter.com/sarkartanmay393">@sarkartanmay393</a></p>]]></description><link>https://tanmaysarkar.hashnode.dev/connect-database-in-your-go-project-with-ease</link><guid isPermaLink="true">https://tanmaysarkar.hashnode.dev/connect-database-in-your-go-project-with-ease</guid><dc:creator><![CDATA[Tanmay Sarkar]]></dc:creator><pubDate>Mon, 17 Oct 2022 03:45:42 GMT</pubDate><cover_image>https://cdn.hashnode.com/res/hashnode/image/upload/v1665944777101/WqrxpGCgm.png</cover_image></item><item><title><![CDATA[Beginners Guide to Argo CD]]></title><description><![CDATA[<p>Before getting hands-on with Argo CD, we are going to discuss What Argo CD is, How it works, and What prerequisites you need.</p><h3 id="heading-what-is-argo-cd">What is Argo CD ?</h3><p>Argo CD is a Kubernetes-native continuous deployment (CD) tool. Unlike external CD tools that only enable push-based deployments, Argo CD can pull updated code from Git repositories and deploy it directly to Kubernetes resources. It enables developers to manage both infrastructure configuration and application updates in one system.</p><p>Argo CD offers the following key features and capabilities:</p><ul><li>Manual or automatic deployment of applications to a Kubernetes cluster.</li><li>Automatic synchronization of application state to the current version of declarative configuration.</li><li>Web user interface and command-line interface (CLI).</li><li>Ability to visualize deployment issues, detect and remediate configuration drift.</li><li>Role-based access control (RBAC) enables multi-cluster management.</li><li>Single sign-on (SSO) with providers such as GitLab, GitHub, Microsoft, OAuth2, OIDC, LinkedIn, LDAP, and SAML 2.0</li><li>Support for webhooks triggering actions in GitLab, GitHub, and BitBucket.</li></ul><p>With fewer words, we can say Argo CD is a GitOps agent that maintains the desired state of a cluster.</p><p>Let me explain, suppose there is an application you built, and you want it to run on a cluster with 3 Pods and 2 Services for external IPs. This is the desired state you want and whenever changes happen in your application's repository or if at any moment, your desired state is not present in that cluster, you need to check and do some changes to the cluster to get your desired state running, this is a manual process.And here comes Argo CD to automate the whole process with GitOps principles where we use Git as the data provider of that application and cluster state.</p><h3 id="heading-how-does-argo-cd-work">How does Argo CD work ?</h3><p>As we know, Agro CD ensures that the cluster is running in the desired state at all times. Then a question rises <strong>how does it work then ?</strong> </p><p>It's simple, there will be two repositories, one holding the application you build and the other one holding the declaratively written desired state of the cluster. Argo CD as a Kubernetes controller can be installed in the same cluster where our application is or it can also perform its tasks from an external cluster. It checks whether the current state of the running cluster matches with the written desired state, if it doesn't then Argo CD will try to make the desired state and synchronize everything.</p><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1660817332734/7yMiDqI0E.png" alt="argocd_architecture.png" />For a better understanding of its architecture, visit <a target="_blank" href="https://argo-cd.readthedocs.io/en/stable/operator-manual/architecture/">Argo CD Documentation</a>.</p><p>When Argo CD checks that the live and desired states are different, it shows <code>OutOfSync</code> in its UI, yes it does have a UI as well as CLI, whatever you wish to use. And if it matches then Everything is fine, its status return Synced.</p><p>It supports plain Kubernetes manifests, Helm charts, Kustomize definitions, and other templating mechanisms.</p><p>By default, Argo CD looks for any changes in our repository every 3 minutes. If there are any changes in our repositories, Argo CD will update our cluster with the new changes we desired.But if we want Argo CD to look for changes every second, we can do that too and if you don't like this mechanism of checking for changes then you can use <a target="_blank" href="https://docs.github.com/en/developers/webhooks-and-events/webhooks/about-webhooks">webhooks</a> too where Argo CD receives notifications from your git provider and when it receives a notification from your application's repo, it will look for changes.</p><p>Check core concepts of Argo CD from this link <a target="_blank" href="https://argo-cd.readthedocs.io/en/stable/core_concepts/">core-concepts</a>.</p><h2 id="heading-prerequisites">Prerequisites</h2><ol><li>Basic knowledge of Git, K8s, and <a target="_blank" href="https://www.youtube.com/watch?v=IPvYjXCsTg8&amp;list=PL9gnSGHSqcnoqBXdMwUTRod4Gi3eac2Ak&amp;index=3">Networking</a>.</li><li>Tools - <a target="_blank" href="https://kubernetes.io/docs/reference/kubectl/">kubectl</a>, <a target="_blank" href="https://minikube.sigs.k8s.io/docs/start/">minikube</a> (<em>optional</em>), <a target="_blank" href="https://docs.docker.com/get-started/overview/">docker</a> (<em>optional</em>).</li></ol><h2 id="heading-implementation-of-argo-cd">Implementation of Argo CD</h2><ul><li><strong>Q. What will we be doing today ?</strong></li><li><strong>A. Deploy a Docker application in a Kubernetes cluster which is declaratively described in plain Kubernetes manifest files in a Github Repo.</strong></li></ul><p>In this article, I have used this repo <a target="_blank" href="https://github.com/sarkartanmay393/Webserver-CI-CD-Golang">Webserver-CI-CD-Golang</a></p><blockquote><p>For this demo, I am using Minikube for a local cluster. Or you can create your Argo CD setup in <a target="_blank" href="https://codefresh.learnworlds.com/course/gitops-with-argo">Codefresh Course</a>.</p></blockquote><ul><li><strong> Installation of Argo CD </strong></li></ul><p>Argo CD can be used to deploy and manage other applications, do not forget that it is also an application by itself. There are many ways to install it on a Kubernetes cluster.</p><p>For the experiment, You can deploy Argo CD by directly using the manifest,</p><pre><code>kubectl create namespace argocdkubectl apply -n argocd -f https:<span class="hljs-comment">//raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml</span></code></pre><p>For a production setup, we suggest you use <a target="_blank" href="https://github.com/argoproj-labs/argocd-autopilot">Autopilot</a>, a companion project that not only installs Argo CD but commits all configuration to git so Argo CD can manage itself using GitOps.</p><p>For more traditional installation options, the manifests directory offers different modes of installation with or without High Availability. The installs marked as namespace allow you to install Argo CD on a single namespace without cluster-wide privileges. This is best when you want to install Argo CD on one cluster but have it manage other external clusters.</p><p>See all resources created by Argo CD -</p><pre><code>kubectl get all -n argocd</code></pre><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1660766894705/sxzGvrIIS.png" alt="argocd-resources.png" /></p><ul><li><strong> Expose Argo CD UI </strong></li></ul><p>By default, Argo CD is only accessible from within the cluster. To expose the UI you can utilize any of the standard Kubernetes networking mechanisms such as -</p><ol><li>Ingress (recommended for production)</li><li>Load balancer (affects cloud cost)</li><li>NodePort (simple but not very flexible)</li></ol><p>Once the external URL is ready, you need to decide how users will access the Argo CD UI. There are mainly two approaches:</p><ol><li>Use a small number of local users. Authentication is handled by Argo CD itself. Best for very small companies (e.g. 2-5 people).</li><li>Use an SSO provider. Authentication is handled by the provider. Ideal for companies and large organizations.</li></ol><p>To expose using Ingress,</p><pre><code>kubectl port-forward svc/argocd-server -n argocd <span class="hljs-number">8085</span>:<span class="hljs-number">443</span></code></pre><p>Now, visit https://localhost:8085 for Argo CD UI.</p><p>For admin username and password,Open another tab in the terminal and command -</p><pre><code>kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath=<span class="hljs-string">"{.data.password}"</span> | base64 -d &gt; admin-pass.txt</code></pre><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1660772640595/fPyIjEare.png" alt="admin-password.png" /></p><p>Now, login to the admin account -<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1660773452583/D0e12YzMZ.png" alt="argocd-admin-login-ui.png" /></p><ul><li><strong> Creating and Syncing Application in Argo CD  </strong></li></ul><p>An application can be created in Argo CD from the UI, CLI, or by writing a Kubernetes manifest that can then be passed to kubectl to create resources.</p><h5 id="heading-using-ui"><strong> Using UI</strong></h5><h5 id="heading-1-click-on-new-app">1. Click on NEW APP</h5><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1660775765566/0y_WS9BPN.png" alt="argocd-ui.png" /></p><h5 id="heading-2-put-only-necessaries-as-mentioned-below">2. Put only necessaries as mentioned below</h5><ul><li><p>General</p><p>Application Name: <code>demo-app</code></p><p>Project Name: <code>default</code></p></li></ul><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1660933552033/9hC5rWhRf.png" alt="Screenshot 2022-08-18 at 2.46.31 PM.png" /></p><ul><li><p>Source</p><p>Repository URL: <code>https://github.com/sarkartanmay393/Sample-GO-WebApp</code></p><p>Revision: <code>HEAD</code></p><p>PATH: <code>.</code></p></li></ul><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1660814470964/ge_S87oXw.png" alt="Screenshot 2022-08-18 at 2.46.51 PM.png" /></p><ul><li><p>Destination</p><p>Cluster URL: <code>https://kubernetes.default.svc</code></p><p>namespace: <code>default</code></p></li></ul><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1660814491845/ppsrl6EHD.png" alt="Screenshot 2022-08-18 at 2.47.12 PM.png" /></p><p>YAML File -</p><pre><code>apiVersion: argoproj.io/v1alpha1<span class="hljs-attr">kind</span>: Application<span class="hljs-attr">metadata</span>:  name: demo-app<span class="hljs-attr">spec</span>:  destination:    name: <span class="hljs-string">''</span>    <span class="hljs-attr">namespace</span>: <span class="hljs-keyword">default</span>    <span class="hljs-attr">server</span>: <span class="hljs-string">'https://kubernetes.default.svc'</span>  <span class="hljs-attr">source</span>:    path: .    repoURL: <span class="hljs-string">'https://github.com/sarkartanmay393/Sample-GO-WebApp'</span>    <span class="hljs-attr">targetRevision</span>: HEAD  <span class="hljs-attr">project</span>: <span class="hljs-keyword">default</span></code></pre><p>Check your YAML by hitting <code>EDIT AS YAML</code> and try to understand.</p><p>Now, Press on <code>Create</code> and You will see this on screen.</p><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1660809480214/F4RDTLS9i.png" alt="first-app-argocd-ui.png" /></p><p>Now, click on <code>SYNC</code> and Proceed without any change.</p><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1660814698677/MXRQxLGrn.png" alt="Screenshot 2022-08-18 at 2.52.16 PM.png" /></p><h5 id="heading-using-cli"><strong>Using CLI</strong></h5><h5 id="heading-1-install-argo-cd-cli">1.  Install Argo CD CLI</h5><p>Run the following command -</p><p>For Linux :</p><pre><code>curl -sSL -o /usr/local/bin/argocd https:<span class="hljs-comment">//github.com/argoproj/argo-cd/releases/latest/download/argocd-linux-amd64</span>chmod +x /usr/local/bin/argocd</code></pre><p>For Mac :</p><pre><code>brew install argocd</code></pre><blockquote><p>I am using this mac command as I am working with a local cluster.Use this reference to <a target="_blank" href="https://argo-cd.readthedocs.io/en/stable/cli_installation/#download-with-curl">install Argo CD CLI</a>.</p></blockquote><p>Argo CD CLI Help Screen -<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1660811000060/y4lghpkOSJ.png" alt="Screenshot 2022-08-18 at 1.52.51 PM.png" /></p><h5 id="heading-2-login-argo-cd-cli">2. Login Argo CD CLI</h5><p>Run the command -</p><pre><code>argocd login localhost:<span class="hljs-number">8085</span></code></pre><p>Then continue with <code>y</code> and,Username: <code>admin</code>Password: <code>check your admin-pass.txt</code></p><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1660811627828/JGS_o97-2.png" alt="Screenshot 2022-08-18 at 2.01.04 PM.png" /></p><p>I am login into our localhost server because it is the <code>argocd-server</code> that was port forwarded earlier.For Further reference, <a target="_blank" href="https://argo-cd.readthedocs.io/en/stable/user-guide/commands/argocd_login/">tap here</a>.</p><h5 id="heading-3-create-an-app-in-cli">3. Create an app in CLI</h5><p>Run the following command -</p><pre><code class="lang-zsh">argocd app create demo-app --project default --repo https://github.com/sarkartanmay393/Sample-GO-WebApp --path . --dest-namespace default --dest-server https://kubernetes.default.svc</code></pre><p>This will be output -</p><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1660811808261/0wJQUDBhS.png" alt="Screenshot 2022-08-18 at 2.05.53 PM.png" /></p><p>Some other Argo CD commands -</p><pre><code class="lang-bash">  argocd app list    <span class="hljs-comment">#See all apps in Argo cd</span>NAME      CLUSTER                         NAMESPACE  PROJECT  STATUS     HEALTH   SYNCPOLICY  CONDITIONS  REPO                                                 PATH  TARGETdemo-app  https://kubernetes.default.svc  default    default  OutOfSync  Missing  &lt;none&gt;      &lt;none&gt;      https://github.com/sarkartanmay393/Sample-GO-WebApp  .       argocd app get demo-app    <span class="hljs-comment">#Get demo-app info</span>Name:               demo-appProject:            defaultServer:             https://kubernetes.default.svcNamespace:          defaultURL:                https://localhost:8085/applications/demo-appRepo:               https://github.com/sarkartanmay393/Sample-GO-WebAppTarget:             Path:               .SyncWindow:         Sync AllowedSync Policy:        &lt;none&gt;Sync Status:        OutOfSync from  (2ee5cba)Health Status:      MissingGROUP  KIND        NAMESPACE  NAME               STATUS     HEALTH   HOOK  MESSAGE       Service     default    sample-service     OutOfSync  Missing        apps   Deployment  default    sample-deployment  OutOfSync  Missing</code></pre><h5 id="heading-4-sync-app-in-cli">4. Sync app in CLI</h5><p>As this app is only created, the default sync status will be <code>OutOfSync</code>. To perform synchronization run the command -</p><pre><code class="lang-bash">  argocd app sync demo-app    <span class="hljs-comment">#Sync demo-app</span>TIMESTAMP                  GROUP        KIND   NAMESPACE                  NAME    STATUS    HEALTH        HOOK  MESSAGE2022-08-18T14:13:47+05:30   apps  Deployment     default     sample-deployment  OutOfSync  Missing              2022-08-18T14:13:47+05:30            Service     default        sample-service  OutOfSync  Missing              2022-08-18T14:13:48+05:30            Service     default        sample-service  OutOfSync  Missing              service/sample-service created2022-08-18T14:13:48+05:30   apps  Deployment     default     sample-deployment  OutOfSync  Missing              deployment.apps/sample-deployment created2022-08-18T14:13:48+05:30   apps  Deployment     default     sample-deployment    Synced  Progressing              deployment.apps/sample-deployment created2022-08-18T14:13:48+05:30            Service     default        sample-service    Synced  Healthy                  service/sample-service createdName:               demo-appProject:            defaultServer:             https://kubernetes.default.svcNamespace:          defaultURL:                https://localhost:8085/applications/demo-appRepo:               https://github.com/sarkartanmay393/Sample-GO-WebAppTarget:             Path:               .SyncWindow:         Sync AllowedSync Policy:        &lt;none&gt;Sync Status:        Synced to  (2ee5cba)Health Status:      ProgressingOperation:          SyncSync Revision:      2ee5cba61a4446ec05241edce5f781a7f4aa26dePhase:              SucceededStart:              2022-08-18 14:13:47 +0530 ISTFinished:           2022-08-18 14:13:48 +0530 ISTDuration:           1sMessage:            successfully synced (all tasks run)GROUP  KIND        NAMESPACE  NAME               STATUS  HEALTH       HOOK  MESSAGE       Service     default    sample-service     Synced  Healthy            service/sample-service createdapps   Deployment  default    sample-deployment  Synced  Progressing        deployment.apps/sample-deployment created</code></pre><p>Now the deployed application is synced.</p><p>This will be the final view of our deployed application in the Argo CD User Interface.</p><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1660814074158/WdCcWqulH.png" alt="Screenshot 2022-08-18 at 2.43.16 PM.png" /></p><ul><li><strong> Access the Deployed App </strong></li></ul><p>Now check for services running under <code>default</code> namespace in kubernetes.Run the command - </p><pre><code class="lang-bash"> kubectl get services    <span class="hljs-comment">#Get cluster services under default namespace.</span>NAME             TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)          AGEkubernetes       ClusterIP   10.96.0.1     &lt;none&gt;        443/TCP          40dsample-service   NodePort    10.96.22.35   &lt;none&gt;        8080:31000/TCP   17m</code></pre><p>You need to port forward the <code>sample-service</code> to access the app.Run the command -</p><pre><code class="lang-bash">kubectl port-forward svc/sample-service 8086:8080</code></pre><p>Now, visit http://localhost:8086 to see.</p><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1660946879018/oKzjgWmhC.png" alt="deployed-app-access-url.png" /></p><p>This is the Argo CD Beginners Article. Hope that you have learned something new. See you in my next article.</p><p>PS. Learning About Agro CD from <a target="_blank" href="https://codefresh.learnworlds.com/course/gitops-with-argo">Codefresh</a>.For this article, I have taken references from Codefresh.</p>]]></description><link>https://tanmaysarkar.hashnode.dev/beginners-guide-to-argo-cd</link><guid isPermaLink="true">https://tanmaysarkar.hashnode.dev/beginners-guide-to-argo-cd</guid><dc:creator><![CDATA[Tanmay Sarkar]]></dc:creator><pubDate>Fri, 19 Aug 2022 22:32:36 GMT</pubDate><cover_image>https://cdn.hashnode.com/res/hashnode/image/upload/v1660949481544/twcQ2ERRv.jpg</cover_image></item></channel></rss>