<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Çetin Kaan Taşkıngenç</title>
    <description>The latest articles on DEV Community by Çetin Kaan Taşkıngenç (@ctnkaan).</description>
    <link>https://dev.to/ctnkaan</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F737595%2F1412200a-0fe0-4745-8e20-a07d19ce9846.png</url>
      <title>DEV Community: Çetin Kaan Taşkıngenç</title>
      <link>https://dev.to/ctnkaan</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ctnkaan"/>
    <language>en</language>
    <item>
      <title>TypeScript Secrets Part 1: "as const"</title>
      <dc:creator>Çetin Kaan Taşkıngenç</dc:creator>
      <pubDate>Tue, 30 Jan 2024 07:39:16 +0000</pubDate>
      <link>https://dev.to/ctnkaan/typescript-secrets-part-1-as-const-57ne</link>
      <guid>https://dev.to/ctnkaan/typescript-secrets-part-1-as-const-57ne</guid>
      <description>&lt;p&gt;I've been wanting to start a new blog series for a while now. In this series, I'll be sharing some lesser-known TypeScript features that many web developers might not be familiar with. In this first post, I'll be talking about the "as const" keyword. &lt;/p&gt;

&lt;h2&gt;
  
  
  What does "as const" do?
&lt;/h2&gt;

&lt;p&gt;You can declare a variable "as const" in TypeScript. This makes the value of the variable a constant or in other words it makes the variable read-only. Meaning you cannot change or update the value. This is different than just declaring a variable with const. You can't redeclare values of a const variable but you can mutate it. If you use "as const" you can't redeclare or mutate it.&lt;/p&gt;

&lt;p&gt;Here is an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// without as const&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;primaryColor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#3498db&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;secondaryColor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#2ecc71&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;api&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;baseUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://api.example.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;v1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;features&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;enableAnalytics&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;enableNotifications&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// this is allowed&lt;/span&gt;
&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;primaryColor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#ff0000&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// so is this&lt;/span&gt;
&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;features&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;enableNotifications&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example we have a web app config that consists of a theme, api and features objects. These values as you might guess are probably almost never going to change. &lt;br&gt;
If a team member has changed a value in this config and others don't know it might cause unneeded debugging hours to fix a trivial problem. To keep them as read-only objects you can infer them "as const"&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// with as const&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;primaryColor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#3498db&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;secondaryColor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#2ecc71&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;api&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;baseUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://api.example.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;v1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;features&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;enableAnalytics&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;enableNotifications&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// &amp;lt;-- notice the as const here&lt;/span&gt;

&lt;span class="c1"&gt;// this will result in a TypeScript error&lt;/span&gt;
&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;primaryColor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#ff0000&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// this will throw an error as well&lt;/span&gt;
&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;features&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;enableNotifications&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is pretty cool but "as const" provides us with another useful feature as well. TypeScript is mainly used for it's type checking and by using "as const" you can declare stricter types. What I mean by that is instead of an value being type string it can be type literal string value.&lt;/p&gt;

&lt;p&gt;Here is another example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// without as const&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;primaryColor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#3498db&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;       &lt;span class="c1"&gt;// Type: string&lt;/span&gt;
    &lt;span class="na"&gt;secondaryColor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#2ecc71&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;     &lt;span class="c1"&gt;// Type: string&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;api&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;baseUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://api.example.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Type: string&lt;/span&gt;
    &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;v1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;                      &lt;span class="c1"&gt;// Type: string&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;features&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;enableAnalytics&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;     &lt;span class="c1"&gt;// Type: boolean&lt;/span&gt;
    &lt;span class="na"&gt;enableNotifications&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Type: boolean&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// when you hover on this you'll see type: string&lt;/span&gt;
&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;primaryColor&lt;/span&gt;

&lt;span class="c1"&gt;// when you hover on this you'll see type: boolean&lt;/span&gt;
&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;features&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;enableAnalytics&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But if we use "as const" we can see their values when we hover over these variables. Since they are read-only their type does not matter, they cannot change.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// with as const&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;primaryColor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#3498db&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;       &lt;span class="c1"&gt;// Type: '#3498db'&lt;/span&gt;
    &lt;span class="na"&gt;secondaryColor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#2ecc71&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;     &lt;span class="c1"&gt;// Type: '#2ecc71'&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;api&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;baseUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://api.example.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Type: 'https://api.example.com'&lt;/span&gt;
    &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;v1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;                      &lt;span class="c1"&gt;// Type: 'v1'&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;features&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;enableAnalytics&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;     &lt;span class="c1"&gt;// Type: true&lt;/span&gt;
    &lt;span class="na"&gt;enableNotifications&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Type: false&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


&lt;span class="c1"&gt;// when you hover on this you'll see type: '#3498db'&lt;/span&gt;
&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;primaryColor&lt;/span&gt;

&lt;span class="c1"&gt;// when you hover on this you'll see type: true&lt;/span&gt;
&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;features&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;enableAnalytics&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Lets do a quick recap
&lt;/h2&gt;

&lt;p&gt;So by using "as const" we can turn our variables into read-only variables meaning their types are turned into their values so TypeScript throws an error when we try to change them. It also provides us with better intelliSense meaning we can just hover on a variable to see their constant value.&lt;/p&gt;

&lt;p&gt;Thanks for tagging along!&lt;br&gt;
Feel free to connect with me on my socials from my profile.&lt;br&gt;
Cheers!&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Difference Between Git Merge, Rebase and Squash</title>
      <dc:creator>Çetin Kaan Taşkıngenç</dc:creator>
      <pubDate>Mon, 15 Jan 2024 09:48:35 +0000</pubDate>
      <link>https://dev.to/ctnkaan/difference-between-git-merge-rebase-and-squash-3kg4</link>
      <guid>https://dev.to/ctnkaan/difference-between-git-merge-rebase-and-squash-3kg4</guid>
      <description>&lt;p&gt;As a developer, you've likely used Git and GitHub, mastering the essentials of version control. Integrating changes from your branches into the main branch, often through pull requests, is a common task. The default choice for many is the "merge" feature.&lt;/p&gt;

&lt;p&gt;However, the world of version control offers alternative commands with distinct features. Enter Git rebase and Git squash, two advanced techniques that offer you a different way of synchronizing your changes to the target branch.&lt;/p&gt;

&lt;p&gt;Many developer do not even know what these commands are and just use the merge command. While merge is a solid choice if you're interested on learning the other ways you will probably love this article.&lt;/p&gt;

&lt;p&gt;In the upcoming sections, we will dive into the commands for Merge, Rebase, and Squash. &lt;strong&gt;It's crucial to note that these commands aren't similar to algorithms, solving distinct tasks.&lt;/strong&gt; Instead, Merge, Rebase, and Squash serve the same fundamental purpose but provide different perspectives on how you manage your branches. &lt;strong&gt;Each command offers a unique lens through which you can navigate and enhance your branch management, providing versatility in your approach to version control.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Git Merge
&lt;/h2&gt;

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

&lt;p&gt;Git Merge is the most commonly used way of updating branches. It's the most common because it's usually the first synchronizing command developers learn when learning Git. They usually don't dive deep into other commands like rebase and squash without learning about merge since they might be overwhelming.&lt;/p&gt;

&lt;p&gt;Merge basically creates a new merge commit and combines the changes in the branch to the target branch with that merge commit. It shows your individual commits and a merge commit.&lt;/p&gt;

&lt;h3&gt;
  
  
  Positives
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Easy to understand how it works&lt;/li&gt;
&lt;li&gt;Has the commit history of both branches&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Negatives
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;History can be overwhelming and complex&lt;/li&gt;
&lt;li&gt;Possibility of filling the branch history with too many merge commits&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Git Rebase
&lt;/h2&gt;

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

&lt;p&gt;Git rebase is another commonly used command. Rebase command as it's name suggest rebases the head of current branch to target branches last commit. Thus producing a much linear git history. Some people might prefer this kind of more linear Git history.&lt;/p&gt;

&lt;h3&gt;
  
  
  Positives
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Produces linear commit history&lt;/li&gt;
&lt;li&gt;Outputs a cleaner project history with no merge commits&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Negatives
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Rebasing alters the commit history, potentially causing confusion or conflicts for collaborators.&lt;/li&gt;
&lt;li&gt;Solving rebase conflicts are usually harder than solving merge conflicts&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Git Squash
&lt;/h2&gt;

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

&lt;p&gt;The final command is Git Squash. As it's name suggests it &lt;strong&gt;squeezes&lt;/strong&gt; the commits into a single commit and then merged into target branch. It's kind of has both the features of Merge and Rebase. It creates a merge commit but it also keeps the projects history linear and clean.&lt;br&gt;
But the catch of Git Squash is that we lose the details of individual commits. So a lot of context about individual commits are lost in order to have a cleaner project history.&lt;/p&gt;

&lt;h3&gt;
  
  
  Positives
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Produces linear and clean commit history&lt;/li&gt;
&lt;li&gt;Creates a merge commit&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Negatives
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Less detailed commits when squash and merged&lt;/li&gt;
&lt;li&gt;Tracking individual commits might be hard and can cause issues in debuging&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In the end all three commands do the same thing but in their own different style. Even though you might not be using all of these commands right now it might be useful to learn how they work for future opportunities or for your personal project management.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;So long story short&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Merge:&lt;/strong&gt; Creates a merge commit, gives all the info about the branch&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rebase:&lt;/strong&gt; Moves the head of the current branch to the last node of the target branch and produces a more linear git history&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Squash:&lt;/strong&gt; Making all the commits into a one single commit and creates a clean linear history but does not provide as much information about commits.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Feel free to connect with me on &lt;a href="https://www.linkedin.com/in/cetinkaantaskingenc/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;, &lt;a href="https://github.com/ctnkaan" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; or &lt;a href="https://twitter.com/CetinKaanTweets" rel="noopener noreferrer"&gt;Twitter / X&lt;/a&gt;&lt;/p&gt;

</description>
      <category>git</category>
      <category>tutorial</category>
      <category>devops</category>
      <category>github</category>
    </item>
    <item>
      <title>Coding the Shield: A Deep Dive into the Development of the Discord Bot that Blocked 1000+ Phishing Attacks</title>
      <dc:creator>Çetin Kaan Taşkıngenç</dc:creator>
      <pubDate>Mon, 08 Jan 2024 14:48:30 +0000</pubDate>
      <link>https://dev.to/ctnkaan/coding-the-shield-a-deep-dive-into-the-development-of-the-discord-bot-that-blocked-1000-phishing-attacks-agl</link>
      <guid>https://dev.to/ctnkaan/coding-the-shield-a-deep-dive-into-the-development-of-the-discord-bot-that-blocked-1000-phishing-attacks-agl</guid>
      <description>&lt;h2&gt;
  
  
  What This Article is About
&lt;/h2&gt;

&lt;p&gt;In this article I'll talk about one of my favorite side projects I worked on, &lt;strong&gt;Postman Sentinel&lt;/strong&gt;. Well technically it was first called &lt;strong&gt;Postman Student Helper&lt;/strong&gt; when it was first developed 3 years ago. I'll go into depth about how and why I built this project, how I received help from the Postman Community and it's impact. Also I'd like to mention that this is my first blog post so I would love to receive constructive feedback about my writing. Happy reading!&lt;/p&gt;

&lt;h2&gt;
  
  
  The Backstory
&lt;/h2&gt;

&lt;p&gt;Back in 2021 when I was still in university as a 2nd grade IT student I've wanted to do a lot of community work. At that time I got accepted to an awesome student program called &lt;a href="https://www.postman.com/student-program/student-leader/"&gt;Postman Student Leaders&lt;/a&gt;. All the communication in the community was and still is done via Discord. If you don't know Discord it's basically a massive communication platform for communities and friends.&lt;/p&gt;

&lt;p&gt;Now the problem was during that time there was a massive increase in scammers in Discord. It was mostly Discord Nitro Scams because at that time Epic Games was giving away free Discord Nitro. So the scammers were constantly spamming messages with malicious links. Here is an example message:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0jot8r6zev31xqujsbii.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0jot8r6zev31xqujsbii.png" alt="Example Phishing Message" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Going On?
&lt;/h2&gt;

&lt;p&gt;I've blurred the user of the account at top because these phishing links were sent from hacked accounts in an automated matter. Messages like these were sent in all the text channels multiple times on random times of the days. Basically the link is similar to discord as can be noticed. It's usually something like &lt;strong&gt;disord&lt;/strong&gt;, &lt;strong&gt;discorde&lt;/strong&gt;, &lt;strong&gt;diiscord&lt;/strong&gt; etc. Texts that can deceive users when checking the message quickly. The link has a clone of the Login Screen of Discord. Something similar or basically the same as this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6zzqxiyx5t6gipfjwtqw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6zzqxiyx5t6gipfjwtqw.png" alt="Discord Login Screen" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When the user writes their user credentials they are then sent to the server of the scammer. Now the scammers have the email and password of the users. After that the website redirects them to the actual Discord login screen. So most of the users think something went wrong and login again. Most of them are not aware that their account credentials have been stolen and if they do not have 2FA in their account, their account is now part of a botnet that automatically sends messages to Discord servers.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem and The Solution
&lt;/h2&gt;

&lt;p&gt;Obviously the problem was that our server had quite bit of people and due that even if we acted fast enough and deleted the messages quickly, if at least 2 people clicked on that link, infected account amount increased.&lt;/p&gt;

&lt;p&gt;This was a major problem because usually we weren't fast enough. Only certain verified people had permissions to delete messages and manage the server. So we would have to write to these certain people that there are phishing links in the server. Sometimes no one with right amount of permission would be online and these messages could stay in the chat for hours.&lt;/p&gt;

&lt;p&gt;That was the moment I thought I could probably help the community and develop something great. I already had some experience developing Discord bots with Discord.js. I recently built a bot for my friends to use so I thought I can build one that can actually automatically detect these messages and delete them from the chat.&lt;/p&gt;

&lt;h2&gt;
  
  
  My First Implementation Worked But Was Not Efficient
&lt;/h2&gt;

&lt;p&gt;Well back then I was still a student and had nowhere near the knowledge of software development as of now. I wanted to build something pretty fast due to these phishing links being constantly sent. I went with the easiest and fastest solution I could think of and that was scanning every message sent for the keyword &lt;strong&gt;nitro&lt;/strong&gt;. It was nowhere near the perfect solution but it got the job done.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;nitro&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This surprisingly worked really, really well. It blocked almost all of the phishing links. Although as you can see this is far from a good solution. After a month some scammers started to send just the links and no text. So the bot failed to block them since there was no "nitro" in the message they sent. This solution was also prone to a lot of false positives. A lot of innocent messages were also deleted.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Helping Hand From Postman
&lt;/h2&gt;

&lt;p&gt;I don't know if I mentioned it but I made this project open-source from start. This was mostly because I wanted to have a community of developers working on this bot and improving my code. Well, I got what I wanted. &lt;strong&gt;Claire Froelich&lt;/strong&gt; from Postman helped me a lot with the project. She introduced me to concepts like Prettier and cleaned a lot of my poorly written code. She also added probably the best feature of the bot which is an actual phishing link detection using Levenshtein Distance algorithm. &lt;/p&gt;

&lt;p&gt;The algorithm basically compares two strings and gives a result on how similar these two strings are. This was really useful because now we can target specific urls and delete messages that are similar to these urls.&lt;/p&gt;

&lt;p&gt;Here is the first version of that code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;distance&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fastest-levenshtein&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="cm"&gt;/** Most spam links try to typosquat 'discord' to trick users into thinking the link is safe (ex: "discorde")*/&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;TYPOSQUAT_TARGET&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;discord&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;isSuspiciousLink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;link&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;threshold&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// get base domain&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;matches&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;link&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/^https&lt;/span&gt;&lt;span class="se"&gt;?&lt;/span&gt;&lt;span class="sr"&gt;:&lt;/span&gt;&lt;span class="se"&gt;\/\/(\S&lt;/span&gt;&lt;span class="sr"&gt;+&lt;/span&gt;&lt;span class="se"&gt;?)\.&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;matches&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;base&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;matches&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="c1"&gt;// check levenshtein distance of domain to "discord"&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;d&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;distance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;TYPOSQUAT_TARGET&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;base&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// if distance is &amp;gt; 0 and &amp;lt; threshold, base is typosquating. Call foul&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;d&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="nx"&gt;threshold&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;isSuspiciousLink&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This solution worked perfectly and we mostly moved with this solution changed some values or made improvements according to data from false positives.&lt;/p&gt;

&lt;p&gt;Because of this we could easily add other websites to check as well such as GitHub. Eventually scammers used different links like posting a fake github link similar to the Discord Nitro scam links. Here is an old photo of these messages being detected and deleted automatically.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu7972bg8jt56a5zgrhrb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu7972bg8jt56a5zgrhrb.png" alt="GitHub Phishing Links being deleted" width="800" height="261"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This bot had other fun features as well such as fetching and posting coding memes from Reddit&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft8xgzvv9hmeyq9k2o21j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft8xgzvv9hmeyq9k2o21j.png" alt="A coding meme sent by Postman Sentinel" width="396" height="494"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Go All This Trouble?
&lt;/h2&gt;

&lt;p&gt;Working on this project was a really fun experience. I learned a lot about hosting, cloud, Docker, Node.js and working as a team. But one of the main reason I continued on development back in the day was seeing the impact it provided.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9bsjsqoqn8o1loe2reff.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9bsjsqoqn8o1loe2reff.png" alt="Image of appreciation from community" width="565" height="76"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This project was my first real world project that actually helped and provided something to people. I could see the impact it made, the blocked messages, time saved from community staff and accounts saved from scammers.&lt;/p&gt;

&lt;p&gt;Seeing that really motivated me to keep the bot running and updating it according to latest phishing attempts at the server.&lt;/p&gt;

&lt;p&gt;It also became my best side projects in my resume. I remember talking with recruiters about the bot for a large portion of the interview and answering their questions. It's really awesome to have an unique project that provides real world value to a community.&lt;/p&gt;

&lt;p&gt;So if you're in a community and see something you can improve, go for it! Even if you're a beginner like I was at worst case scenario you'll have a cool side project.&lt;/p&gt;

&lt;p&gt;If you wish to check out the project &lt;a href="https://github.com/ctnkaan/Postman-Sentinel"&gt;here is the GitHub link&lt;/a&gt; it's pretty old so I might need to update my old code. Feel free to contribute!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>security</category>
      <category>discord</category>
      <category>node</category>
    </item>
  </channel>
</rss>
