<?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: Ivan Karabadzhak</title>
    <description>The latest articles on DEV Community by Ivan Karabadzhak (@jakeroid).</description>
    <link>https://dev.to/jakeroid</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%2F921704%2F6f1aff15-3a48-4a5e-a599-a7c080f667f9.jpeg</url>
      <title>DEV Community: Ivan Karabadzhak</title>
      <link>https://dev.to/jakeroid</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jakeroid"/>
    <language>en</language>
    <item>
      <title>Kitty shortcuts work only with Latin characters - How to fix?</title>
      <dc:creator>Ivan Karabadzhak</dc:creator>
      <pubDate>Sun, 28 Jan 2024 11:20:32 +0000</pubDate>
      <link>https://dev.to/jakeroid/kitty-shortcuts-work-only-with-latin-characters-how-to-fix-3d0a</link>
      <guid>https://dev.to/jakeroid/kitty-shortcuts-work-only-with-latin-characters-how-to-fix-3d0a</guid>
      <description>&lt;p&gt;If you are reading this probably you have the same issues as I faced before. I love Kitty terminal. It's fast and simple. At the same time, I use in my life following languages: Bulgarian, Ukrainian, and Russian. All of them use the Cyrillic alphabet. And Kitty has an issue: shortcuts work only with Latin characters. That means, if your current layout is Bulgarian for example, you can't use shortcuts such as CMD+C, CMD+V, or their alternative Ctrl+C, Ctrl+V. It could make things hard if you need to use Cyrillic language and shortcuts at the same time. I have tried to fix that. Let me share what I found.&lt;/p&gt;

&lt;h2&gt;First step of the issue solving&lt;/h2&gt;

&lt;p&gt;While researching how to fix the issue I found &lt;a href="https://github.com/kovidgoyal/kitty/issues/606" rel="noreferrer noopener"&gt;this GitHub issue&lt;/a&gt; with the fun number 606 (almost 666). First, I should say, that there is no easy solution. Shortly you have to specify for each shortcut mapping alternative with your keyboard layout. That means, for example, if your keyboard has Cyrillic "м" instead of Latin "v" then for making work CMD+V you should add also into configuration an additional line with "м".&lt;/p&gt;

&lt;pre&gt;map cmd+v       paste_from_clipboard # default Latin 
map cmd+ъ       paste_from_clipboard # for default MacOS Bulgarian layout
map cmd+м       paste_from_clipboard # for default MacOS Ukrainian or Russian layout&lt;/pre&gt;

&lt;p&gt;Let't summarize. &lt;strong&gt;To resolve the issue just add for each shortcut additional mapping with your keyboard layout. &lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Pretty easy, isn't it? Yeah, but if you want to use all shortcuts you have to do the same for each one. And I don't want to be you if you want to make that for 2 or more different non-Latin layouts. &lt;/p&gt;

&lt;h2&gt;Automated solution&lt;/h2&gt;

&lt;p&gt;I decided to create automated solution for that. Why? Because manually mapping each key is tedious. And would be great to share the process with you. If you aren't interested in the automation process then just use the Python script from &lt;a href="https://github.com/Jakeroid/kitty-shortcuts-work-only-with-latin-characters" rel="noreferrer noopener"&gt;my GitHub repository&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;For those who are interested in learning more. Let's do it together. The first step is creating a project directory. I usually prefer to use venv (virtual environment) in my Python scripts. &lt;/p&gt;

&lt;pre&gt;mkdir kitty-shortcuts-work-only-with-latin-characters
cd kitty-shortcuts-work-only-with-latin-characters
python -m venv ./venv
source ./venv/bin/activate # maybe you should use activate.fish or other file depends on your shell type&lt;/pre&gt;

&lt;p&gt;Great! Now we're ready to start coding. Before making any changes, I'd like to create a backup of the kitty.config file. It would be ideal if the script could handle this task. On Unix systems, the default configuration file is located at ~/.config/kitty/kitty.conf. I suspect that Kitty may already store a backup in the file named ~/.config/kitty/kitty.conf.bak. To be safe, we should avoid overwriting the default backup location. Let's use current unix timestamp as an additional name part for the file.  &lt;/p&gt;

&lt;pre&gt;import time  # we will use it to get unix timestamp
import os  # we will use it to expand user path

# config file paths
current_unix_timestamp = str(time.time())
default_config_file = '~/.config/kitty/kitty.conf'
current_backup_file = f'~/.config/kitty/kitty.conf.{current_unix_timestamp}.bak'
default_config_file_full_path = os.path.expanduser(default_config_file)
current_backup_file_full_path = os.path.expanduser(current_backup_file)&lt;/pre&gt;

&lt;p&gt;Time to make a code for making backup. &lt;/p&gt;

&lt;pre&gt;import shutil  # we will use it to copy files

# backup config file
shutil.copyfile(default_config_file_full_path, current_backup_file_full_path)&lt;/pre&gt;

&lt;p&gt;Now we need to build a map of our keyboard layouts. In my case, I would create a mapping between the default English and Russian layouts because I use them most frequently for typing in any language. However, if your keyboard differs from the English US layout or if you use other non-Latin layouts, you should create your own map.&lt;/p&gt;

&lt;p&gt;To simplify things, I created a text file with two lines. The first line corresponds to my English layout, and the second line to my Russian layout. I simply typed each key on the keyboard once, following the same sequence. This means, for example, that the character at position number 7 in the first line is on the same key as the character at position number 7 in the second line, but they represent different characters because they correspond to different symbols.&lt;/p&gt;

&lt;p&gt;Here is my example. &lt;/p&gt;

&lt;pre&gt;qwertyuiop[]\asdfghjkl;'zxcvbnm,./
йцукенгшщзхъ\фывапролджэячсмитьбю.&lt;/pre&gt;

&lt;p&gt;Let's write some code to read that file and construct a map.&lt;/p&gt;

&lt;pre&gt;# load map file
with open('map.txt') as f:
    lines = f.readlines()
line1 = lines[0].strip()
line2 = lines[1].strip()
map_dict = dict(zip(line1, line2))&lt;/pre&gt;

&lt;p&gt;Now we could use map_dict as a source of mapping. Here are a few examples.&lt;/p&gt;

&lt;pre&gt;# get value for v in map_dict
print('Value of v is ', map_dict['v'])

# get value for c in map_dict
print('Value of c is ', map_dict['c'])

# get value for b in map_dict
print('Value of b is ', map_dict['b'])&lt;/pre&gt;

&lt;p&gt;The next step awaits us. I believe it would be a good and straightforward idea to implement the following algorithm:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open the config file.&lt;/li&gt;



&lt;li&gt;Read it line by line.&lt;/li&gt;



&lt;li&gt;If a line does not contain a key map, then simply add it to the output as is.&lt;/li&gt;



&lt;li&gt;If a line contains a key map, then add the original line as well as an additional line.&lt;/li&gt;



&lt;li&gt;Save the output lines in the original file.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;There are also two important things. The config file contains lines with comments that we do not wish to alter. These documentation comments begin with "#::". We should skip those lines and leave them unmodified. Additionally, the file has mappings lines that are commented out with the symbol "#". These represent default Kitty shortcuts. For such lines, we should remove the comment character and include two lines in the output: the original one and a new one with the non-Latin mapping. This is necessary because our goal is to keep the shortcuts functional for both keyboard layouts.&lt;/p&gt;

&lt;p&gt;To find the correct mapping of the shortcut key, I use the split method on strings to determine the position of the shortcut key combination and then separate it into individual keys. We do not want to alter characters in keys such as "cmd", "alt", "ctrl", etc. However, we would like to change the mappings for keys like "k", "a", "c", etc.&lt;/p&gt;

&lt;pre&gt;# read config file all lines
with open(default_config_file_full_path) as f:
    lines = f.readlines()

# for each line search mapping line and add additional line with mapping
new_lines = []
for line in lines:

    # if line doesn't contain map
    if ' map ' not in line:
        new_lines.append(line)
        continue

    # if line contains map but starts with #::
    if line.startswith('#::'):
        new_lines.append(line)
        continue

    # line contains map the first thing is to find mapping parts
    line_parts = line.split(' ')
    map_part_index = line_parts.index('map')
    keys_part_index = map_part_index + 1
    keys_list = line_parts[keys_part_index].split('+')

    # for each key in keys list find mapping
    new_keys_list = []
    for key in keys_list:
        if key not in map_dict:
            new_keys_list.append(key)
            continue
        new_keys_list.append(map_dict[key])

    # create new line with new keys list
    new_keys_part = '+'.join(new_keys_list)
    new_line = ''
    for i, part in enumerate(line_parts):
        if i == keys_part_index:
            new_line += new_keys_part
        else:
            new_line += part
        new_line += ' '

    # remove comment from line and new line if it exists
    if line.startswith('#'):
        line = line[1:].strip() + '\n'
        new_line = new_line[1:].strip() + '\n'

    new_lines.append(line)
    new_lines.append(new_line)

# write new config file
with open(default_config_file_full_path, 'w') as f:
    f.writelines(new_lines)&lt;/pre&gt;

&lt;p&gt;It looks understandable to me; however, if you have any questions, please ask them below. I hope this article helps you. Don't forget to follow me on X (formerly Twitter) or subscribe to the blog newsletter.&lt;/p&gt;

</description>
      <category>kitty</category>
      <category>python</category>
      <category>programming</category>
      <category>automation</category>
    </item>
    <item>
      <title>Why Python is best tool for data processing</title>
      <dc:creator>Ivan Karabadzhak</dc:creator>
      <pubDate>Sat, 30 Sep 2023 17:53:30 +0000</pubDate>
      <link>https://dev.to/jakeroid/why-python-is-best-tool-for-data-processing-4dc1</link>
      <guid>https://dev.to/jakeroid/why-python-is-best-tool-for-data-processing-4dc1</guid>
      <description>&lt;p&gt;For a long time, I used NodeJS as a tool for all kinds of tasks. Nowadays, however, I find myself increasingly drawn to Python for data processing tasks, which have become more frequent in my work. I've found that NodeJS can be somewhat verbose for these types of projects, especially when dealing with one-time scripts.&lt;/p&gt;

&lt;p&gt;As such, I've switched to Python where speed and asynchronous programming aren't vital. This shift has led me to appreciate the advantages of using Python for data processing, making it my go-to tool for such tasks.&lt;/p&gt;

&lt;h2&gt;Python’s simplicity and efficiency&lt;/h2&gt;

&lt;p&gt;If you're like me, having switched from NodeJS to Python, one of the first things you'll appreciate is Python's simplicity. Its syntax is clean and easy to understand, making it a breeze to read and write code in Python. This is particularly handy when working on data processing tasks where complexity can escalate quickly.&lt;/p&gt;

&lt;p&gt;For instance, consider how we can load a CSV file, clean missing data, and compute the mean value of each column using the Pandas library in Python - all accomplished in just a few succinct lines of code:&lt;/p&gt;

&lt;pre&gt;import pandas as pd
# Load a CSV file
data = pd.read_csv('file.csv')
# Clean missing data
data = data.dropna()
# Compute the mean value of each column
mean_values = data.mean()
print(mean_values)&lt;/pre&gt;



&lt;p&gt;In addition to its simplicity, Python is extraordinarily efficient. Especially with data processing tasks that often involve dealing with large datasets, Python truly shines. It handles big data smoothly, enabling you to process, analyze, and derive insights from your data just like the 'mean_values' computation in our example, without skipping a beat.&lt;/p&gt;



&lt;h2&gt;Python’s powerful libraries for data processing&lt;/h2&gt;



&lt;p&gt;One of the main reasons why Python has become a powerhouse for data processing is its vast selection of libraries. In particular, Pandas, NumPy, and SciPy are three major players that work together to streamline the entire data processing journey. Gone are the days of verbose scripts in NodeJS; with these Python libraries, data processing becomes efficient and elegant.&lt;/p&gt;



&lt;p&gt;For instance, in the following code, we utilize all three libraries to load a CSV file, generate an additional data column based on a condition, and perform a statistical test:&lt;/p&gt;



&lt;pre&gt;import pandas as pd
import numpy as np
from scipy import stats

# Load a CSV file using pandas
data = pd.read_csv('file.csv')

# Using numpy to generate an additional data column
data['new_column'] = np.where(data['old_column'] &amp;gt; 0, 1, -1)

# Using scipy to calculate a statistical test on two data columns
t_test_result = stats.ttest_ind(data['column_1'], data['column_2'])

print(t_test_result)
&lt;/pre&gt;

&lt;p&gt;Each library boasts unique features: Pandas excels at data manipulation and analysis (as seen in loading the CSV file), NumPy aids numerical operations (demonstrated in creating the new column), and SciPy shines in scientific computations (evident from conducting the t-test). Together, they form a robust toolkit for any data scientist or enthusiast.&lt;/p&gt;

&lt;h2&gt;Python’s flexibility in handling data&lt;/h2&gt;

&lt;p&gt;Python's flexibility stands as one of its most compelling features. This adaptability is present in its platform-agnostic nature, allowing Python to seamlessly integrate across multiple operating systems. Whether you're employing Windows, macOS, or Linux, Python ensures a smooth coding experience.&lt;/p&gt;

&lt;p&gt;Further illustrating this point, Python gracefully handles data in varied types and structures. From structured CSV files to semi-structured JSON data, or even data fetched directly from SQL databases - Python can work with them all. Moreover, it's capable of merging data from different sources, dealing with nested information, and transforming data types effortlessly.&lt;/p&gt;

&lt;p&gt;This makes Python an extremely versatile tool, fitting for a range of applications; whether they are straightforward scripts or intricate data analysis tasks, Python adapts to the needs of the scenario at hand. Its flexibility truly sets it apart, ensuring it remains a popular choice among programmers worldwide.&lt;/p&gt;

&lt;pre&gt;import pandas as pd

# Load CSV data 
csv_data = pd.read_csv('data.csv')

# Load JSON data
json_data = pd.read_json('data.json')

# Load data from a SQL database
from sqlalchemy import create_engine

engine = create_engine('sqlite:///:memory:')
sql_data = pd.read_sql_query("SELECT * FROM my_table", engine)

# Work with data of different structures
# Flatten a nested column in the JSON data
json_data_flat = pd.json_normalize(json_data['nested_column'])

# Merging different data sources
merged_data = pd.merge(csv_data, json_data_flat, on='common_column')
&lt;/pre&gt;

&lt;h2&gt;Python's active community and helpful resources&lt;/h2&gt;

&lt;p&gt;A truly remarkable aspect of Python is its vibrant community. There's a plethora of resources available online for Python users, from beginners to seasoned professionals. Whether you're looking for tutorials, guides, or forums to troubleshoot an issue, the Python community has something to offer.&lt;/p&gt;

&lt;p&gt;Moreover, Python is open-source, meaning it's continuously updated and improved by developers worldwide. This collaborative spirit ensures that Python remains on the cutting edge, and provides users with a virtually unlimited reservoir of knowledge and support.&lt;/p&gt;

&lt;h2&gt;Conclusion: Python – the optimal choice for data processing&lt;/h2&gt;

&lt;p&gt;In conclusion, Python emerges as the ideal choice for data processing tasks. Its simplicity, efficiency, wealth of powerful libraries, flexibility, and supportive community make it a force to be reckoned with in the realm of data science.&lt;/p&gt;

&lt;p&gt;Whether you're just starting out or looking to ramp up your data processing capabilities, Python offers an extensive range of features to help you succeed. So, explore Python, leverage its potent capabilities, and revolutionize your approach to data processing. Once you experience Python's prowess, you'll wonder how you ever managed without it.&lt;/p&gt;

</description>
      <category>python</category>
      <category>programming</category>
      <category>dataengineering</category>
    </item>
    <item>
      <title>Making rest API with Deno and TypeScript</title>
      <dc:creator>Ivan Karabadzhak</dc:creator>
      <pubDate>Wed, 12 Jul 2023 10:41:17 +0000</pubDate>
      <link>https://dev.to/jakeroid/making-rest-api-with-deno-and-typescript-2mjg</link>
      <guid>https://dev.to/jakeroid/making-rest-api-with-deno-and-typescript-2mjg</guid>
      <description>&lt;p&gt;To be honest, I prefer the NodeJS runtime over JavaScript itself. While JS is great, I appreciate the added benefits of type validation and similar features. During my student days, I heavily used C# to build everything from desktop apps to web services, which is probably why I love TypeScript.&lt;/p&gt;

&lt;p&gt;Today, I'll show you how to create a Rest API using Deno and TypeScript. It's a powerful combination that I'm excited to share with you. &lt;/p&gt;

&lt;h2&gt;What is Deno?&lt;/h2&gt;

&lt;p&gt;Deno is a secure and modern JavaScript/TypeScript runtime created by Ryan Dahl, the same person who created Node.js. It allows you to run JavaScript and TypeScript code outside a web browser, with built-in support for modules, TypeScript, and other valuable features. Deno is becoming increasingly popular among developers due to its security, simplicity, and ease of use.&lt;/p&gt;

&lt;p&gt;By the way, if you are struggling with which language to learn first, check out my article about that: &lt;a href="https://jakeroid.com/blog/choosing-your-first-programming-language-a-beginner-s-guide/"&gt;Choosing Your First Programming Language: A Beginner’s Guide&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;Why Deno?&lt;/h2&gt;

&lt;p&gt;As I said before, I love TypeScript. Deno allows to run TypeScript directly without compilation in JavaScript. &lt;/p&gt;

&lt;p&gt;One more reason is more personal. I like all ideas around Deno project. It would be great to try it with you. &lt;/p&gt;

&lt;h2&gt;Our Goal&lt;/h2&gt;

&lt;p&gt;We aim to create a REST API for generating "lorem ipsum" text via user requests. As part of the development process, we'll be implementing a basic security feature: API key validation.&lt;/p&gt;

&lt;h2&gt;Installing Deno&lt;/h2&gt;

&lt;p&gt;Deno installation is a simple process. There is an install script that could help do that on different platforms. I like Deno distribution idea like "one single executable". That makes more simple to deploy and use Deno.&lt;/p&gt;

&lt;h2&gt;Creating project&lt;/h2&gt;

&lt;p&gt;I suppose you have installed Deno and are ready to continue. Let's create a new directory for our project and then &lt;code&gt;run deno init&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;mkdir lorem-ipsum-api-deno-typescript
cd lorem-ipsum-api-deno-typescript
deno init&lt;/pre&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--HCNIZGn---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2023/02/image-16-1024x491.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--HCNIZGn---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2023/02/image-16-1024x491.png" alt="" width="800" height="384"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's try to run a boilerplate. &lt;/p&gt;

&lt;pre&gt;deno run main.ts&lt;/pre&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--WLFzeBXa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2023/02/image-17-1024x99.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WLFzeBXa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2023/02/image-17-1024x99.png" alt="" width="800" height="77"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Excellent, it's working. Now we are ready to move forward.&lt;/p&gt;

&lt;h2&gt;Create HTTP end-point&lt;/h2&gt;

&lt;p&gt;Let's create HTTP end-point. We will use &lt;a href="https://oakserver.github.io/oak/" rel="noreferrer noopener"&gt;Oak framework&lt;/a&gt; for that. Oak is similar to Express framework, which you maybe know because it is very popular in NodeJS community.&lt;/p&gt;

&lt;p&gt;The basic code could look like the following. &lt;/p&gt;

&lt;pre&gt;// import Application class from Oak module
import { Application as OakApp } from "https://deno.land/x/oak/mod.ts";

// create main function of our program
export function runHttp(): void {

    // create new instance of Oak Application
    const app = new OakApp();

    // add handler to our application
    app.use((ctx) =&amp;gt; {
        ctx.response.body = "Hello World!";
    });

    // start our application and use promise to show server started or not
    app.listen({ port: 8000 });

    // show message in console
    console.log("Server started on port 8000");
}

// run main function if this file is executed directly
// (not imported as a module)
if (import.meta.main) {
    runHttp();
}&lt;/pre&gt;

&lt;p&gt;Let's run it and test it. We should add --allow-net parameter to &lt;code&gt;deno run&lt;/code&gt; command, because default Deno settings don't allow script access to the networking.&lt;/p&gt;

&lt;pre&gt;deno run --allow-net main.ts&lt;/pre&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--mRb90c9N--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2023/02/image-18-1024x87.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mRb90c9N--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2023/02/image-18-1024x87.png" alt="" width="800" height="68"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--mEjOFSeg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2023/02/image-19.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mEjOFSeg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2023/02/image-19.png" alt="" width="732" height="116"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Nice! Everything is working.&lt;/p&gt;

&lt;h2&gt;Adding router for lorem ipsum generation&lt;/h2&gt;

&lt;p&gt;Having all code inside one file and a single function isn't a good idea. Let's make a folder for routes and create there our first router.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--VKb2jOyz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2023/02/image-20.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--VKb2jOyz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2023/02/image-20.png" alt="" width="624" height="326"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;pre&gt;// import Router class
import {Router} from "https://deno.land/x/oak/mod.ts";

// create new class that extends Router class
export class LoremIpsumRouter extends Router {

    // create constructor and init routes
    constructor() {
        super();
        this.get("/lorem-ipsum/get-text", this.getText);
    }

    // create handler for GET /lorem-ipsum/get-text
    getText(ctx): void {
        ctx.response.body = "Lorem ipsum dolor sit amet...";
    }
}&lt;/pre&gt;

&lt;p&gt;Let's import it inside our app.&lt;/p&gt;

&lt;pre&gt;// import our router class
import { LoremIpsumRouter } from "./routes/lorem-ipsum-router.ts";&lt;/pre&gt;

&lt;p&gt;And add using a new router by our app.&lt;/p&gt;

&lt;pre&gt;// create lorem ipsum router
const loremIpsumRouter = new LoremIpsumRouter();

// add handler to our application
app.use(loremIpsumRouter.routes());
app.use(loremIpsumRouter.allowedMethods());&lt;/pre&gt;

&lt;p&gt;Time to run and test.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--eacWnQ4Y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2023/02/image-21-1024x100.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--eacWnQ4Y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2023/02/image-21-1024x100.png" alt="" width="800" height="78"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PwEbG5xV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2023/02/image-22-1024x129.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PwEbG5xV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2023/02/image-22-1024x129.png" alt="" width="800" height="101"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Great! Everything is working fine.&lt;/p&gt;

&lt;h2&gt;Creating handling functions&lt;/h2&gt;

&lt;p&gt;Let's create a controllers directory and put code for handling requests there. I have created a separate class with static functions. We could use even just functions for that small project without creating classes. However, I put all handling functions inside the same class for a nice structure. &lt;/p&gt;

&lt;pre&gt;export class LoremIpsumController {

    public static getParagraphs(ctx): void {
        ctx.response.body = "Lorem ipsum dolor sit amet PARAGRAPHS...";
    }

    public static getSentences(ctx): void {
        ctx.response.body = "Lorem ipsum dolor sit amet SENTENCES...";
    }

    public static getWords(ctx): void {
        ctx.response.body = "Lorem ipsum dolor sit amet WORDS...";
    }
}&lt;/pre&gt;

&lt;p&gt;Now we can change a bit router to make it works with the newly created controller. I have added an optional parameter count to each one. That will allow our API users to specify the desired length of the requested text, sentences, or words. And I connected our controller to the router. &lt;/p&gt;

&lt;pre&gt;// import Router class
import {Router} from "https://deno.land/x/oak/mod.ts";
import {LoremIpsumController} from "../controllers/lorem-ipsum-controller.ts";

// create new class that extends Router class
export class LoremIpsumRouter extends Router {

    // create constructor and init routes
    constructor() {
        super();
        this.get("/lorem-ipsum/paragraphs/:count?", LoremIpsumController.getParagraphs);
        this.get("/lorem-ipsum/sentences/:count?", LoremIpsumController.getSentences);
        this.get("/lorem-ipsum/words/:count?", LoremIpsumController.getWords);
    }
}&lt;/pre&gt;

&lt;h2&gt;Connect library for generating "lorem ipsum"&lt;/h2&gt;

&lt;p&gt;Thankfully for npm packages support in Deno we can use an existing library to generate the text. Let's use &lt;a href="https://www.npmjs.com/package/lorem-ipsum" rel="noreferrer noopener"&gt;this package&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;In Deno you don't need to install the package. For using lorem ipsum library, let's add those lines inside our controller file. &lt;/p&gt;

&lt;pre&gt;import { LoremIpsum } from 'npm:lorem-ipsum@2.0.8';&lt;/pre&gt;

&lt;p&gt;As you can see, it's easy to use npm package in Deno program. The syntax is easy &lt;code&gt;npm:package-name@version&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;Controller code for the responses&lt;/h2&gt;

&lt;p&gt;Time to add actual code for generating the response. Here is our complete controller code.&lt;/p&gt;

&lt;pre&gt;import { LoremIpsum } from 'npm:lorem-ipsum@2.0.8';

export class LoremIpsumController {

    public static getParagraphs(ctx): void {
        const count = ctx.params.count ? parseInt(ctx.params.count) : 3;
        const lorem = new LoremIpsum();
        ctx.response.body = lorem.generateParagraphs(count);
    }

    public static getSentences(ctx): void {
        const count = ctx.params.count ? parseInt(ctx.params.count)  : 3;
        const lorem = new LoremIpsum();
        ctx.response.body = lorem.generateSentences(count);
    }

    public static getWords(ctx): void {
        const count = ctx.params.count ? parseInt(ctx.params.count)  : 3;
        const lorem = new LoremIpsum();
        ctx.response.body = lorem.generateWords(count);
    }
}&lt;/pre&gt;

&lt;p&gt;Pretty simple, yeah? Don't forget to convert the count parameter to a number because, by default, it's a string. Also, I added the default count value as 3. &lt;/p&gt;

&lt;p&gt;Is it working? Of course, I have tested the system.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--RzRYa8ix--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2023/07/image-1024x154.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--RzRYa8ix--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2023/07/image-1024x154.png" alt="deno rest api lorem ipsum test" width="800" height="120"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Auth for Deno Rest API&lt;/h2&gt;

&lt;p&gt;Oak framework allows us to make different auth mechanisms. However, I would like to stay with a pretty simple one. Let's make auth with hardcoded Bearer Token.&lt;/p&gt;

&lt;p&gt;First, I created auth middlewares folder and file inside: middlewares/auth-middleware.ts. The code of the file is pretty simple. &lt;/p&gt;

&lt;pre&gt;export async function authMiddleware(ctx, next) {
    
    // get authorization header
    const authHeader = ctx.request.headers.get('authorization');

    // check if authorization header exists and starts with Bearer
    if (!authHeader || !authHeader.startsWith('Bearer ')) {
        ctx.response.status = 401;
        ctx.response.body = {message: 'Unauthorized'};s
        return;
    }

    // get token from authorization header
    const token = authHeader.split(' ')[1];

    // check if token is valid (in this case token is '123456789')
    if (token !== '123456789') {
        ctx.response.status = 403;
        ctx.response.body = {message: 'Forbidden'};
        return;
    }

    // call next middleware
    await next();
}&lt;/pre&gt;

&lt;p&gt;But to make it work, we must add it to our app object. Let's edit the main.ts file a bit.&lt;/p&gt;

&lt;pre&gt;...

// import our middleware
import {authMiddleware} from "./middlewares/auth-middleware.ts";

...

// add our middleware to our application
app.use(authMiddleware);&lt;/pre&gt;

&lt;p&gt;Looks good. Let's test it out. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--XXQO309e--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2023/07/image-1-1024x220.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--XXQO309e--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2023/07/image-1-1024x220.png" alt="lorem ipsum api auth works 1" width="800" height="172"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--yzQi8y0a--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2023/07/image-2-1024x231.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--yzQi8y0a--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2023/07/image-2-1024x231.png" alt="lorem ipsum api auth works 2" width="800" height="180"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--iDh0B5gI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2023/07/image-3-1024x225.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--iDh0B5gI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2023/07/image-3-1024x225.png" alt="lorem ipsum api auth works 3" width="800" height="176"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Everything is fine.&lt;/p&gt;

&lt;h2&gt;Final?&lt;/h2&gt;

&lt;p&gt;As you can see, building web apps with Oak framework isn't complex. Honestly, it's the same as Express framework in NodeJS.&lt;/p&gt;

&lt;p&gt;I hope today you learned something new and easy can build Deno Rest API by yourself. If you have any questions or want more articles about Deno, please write about it in the comments section.&lt;/p&gt;

&lt;p&gt;If you want to have the full source code checkout &lt;a href="https://github.com/Jakeroid/blog-article-lorem-ipsum-deno-api" rel="noreferrer noopener"&gt;this GitHub repository&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>api</category>
      <category>deno</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Puppeteer doesn’t remove files from temp directory</title>
      <dc:creator>Ivan Karabadzhak</dc:creator>
      <pubDate>Sun, 19 Mar 2023 07:11:21 +0000</pubDate>
      <link>https://dev.to/jakeroid/puppeteer-doesnt-remove-files-from-temp-directory-2gfp</link>
      <guid>https://dev.to/jakeroid/puppeteer-doesnt-remove-files-from-temp-directory-2gfp</guid>
      <description>&lt;p&gt;Frequently I am building bots. They are running on the server and gathering some data. For some of them, I use Puppeteer and headless Chromium instances. That combination works great. However, there is an issue. Puppeteer doesn't remove files from a temp directory. After a while, it could be a problem, because directory size is growing consistently. &lt;/p&gt;

&lt;p&gt;Did you meet the same issue? Let me help you fix it. &lt;/p&gt;

&lt;h2&gt;Good to know&lt;/h2&gt;

&lt;p&gt;This article is suitable only for people who run &lt;a href="https://pptr.dev/" rel="noreferrer noopener"&gt;Puppeteer&lt;/a&gt; on Linux (maybe on Mac?). If you are using Windows, unfortunately, I can't help. However, perhaps you could use a general idea and make the same for your case.&lt;/p&gt;

&lt;h2&gt;Long story short&lt;/h2&gt;

&lt;p&gt;I solved that issue by adding a crontab task, which deletes all files with a modification time older than 10 days. &lt;/p&gt;

&lt;p&gt;If you want to know more details read the following text.&lt;/p&gt;

&lt;h2&gt;Search Puppeteer temp files&lt;/h2&gt;

&lt;p&gt;Let's go into &lt;code&gt;/tmp&lt;/code&gt; directory and check where are Puppeteer files.&lt;/p&gt;

&lt;pre&gt;# show files from /tmp filter by "puppeteer"
ls /tmp | grep puppeteer&lt;/pre&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--67mA8hJo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2023/03/image.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--67mA8hJo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2023/03/image.png" alt="" width="502" height="766"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here we go. Puppeteer creates many directories. Let's calculate how many directories we have and the total size of them. &lt;/p&gt;

&lt;pre&gt;# count of directories
ls /tmp | grep puppeteer | wc -l

# total size of them 
du -hc /tmp/puppeteer* | grep total&lt;/pre&gt;

&lt;p&gt;I got 25782 directories and 27 gigabytes of size. It's huge... Let's move on and automate removing them.&lt;/p&gt;

&lt;h2&gt;Help Puppeteer remove temp files&lt;/h2&gt;

&lt;p&gt;If the mountain doesn't go to me, I will go to the mountain 😄. Let's write a crontab task to remove Puppeteer files that weren't modified for a long time. &lt;/p&gt;

&lt;p&gt;First, let's write a command to find files older than 10 days (for example).&lt;/p&gt;

&lt;pre&gt;# find dirs and files that weren't modified 10+ days
find /tmp/puppeteer* -mtime +10&lt;/pre&gt;

&lt;p&gt;The command will find files that weren't modified 10 or more days ago. To delete them, we could extend the command like the following one.&lt;/p&gt;

&lt;pre&gt;# find and delete dirs and files that weren't modified 10+ days
find /tmp/puppeteer* -mtime +10 -exec rm -rf {} \;&lt;/pre&gt;

&lt;p&gt;Time to add it as a crontab task. Write the following command to open the crontab config.&lt;/p&gt;

&lt;pre&gt;crontab -e&lt;/pre&gt;

&lt;p&gt;Here is my example. The crontab will run that command each day at 4:05 and delete all files related to Puppeteer. I used the full path to find the command to be sure crontab would use the correct one.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cXMA4sTv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2023/03/image-1-1024x78.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cXMA4sTv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2023/03/image-1-1024x78.png" alt="" width="800" height="61"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;That simple way will help Puppeteer to remove files from a temp directory. If you have any questions, ask them below in the comments section.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you are interested, I have one more article related to headless browsers. Check it out: &lt;a href="https://jakeroid.com/blog/how-to-protect-content-against-scrapers-with-headless-browsers/" rel="noreferrer noopener"&gt;How to protect content against scrapers with headless browsers?&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>puppeteer</category>
      <category>headless</category>
      <category>temp</category>
      <category>crontab</category>
    </item>
    <item>
      <title>Choosing Your First Programming Language: A Beginner’s Guide</title>
      <dc:creator>Ivan Karabadzhak</dc:creator>
      <pubDate>Fri, 03 Mar 2023 06:43:46 +0000</pubDate>
      <link>https://dev.to/jakeroid/choosing-your-first-programming-language-a-beginners-guide-2i04</link>
      <guid>https://dev.to/jakeroid/choosing-your-first-programming-language-a-beginners-guide-2i04</guid>
      <description>&lt;p&gt;Are you wondering with questions: Which programming language should I learn first? What is the best coding language to learn first? Let me help with that.&lt;/p&gt;

&lt;p&gt;Picking your first programming language can seem complex, especially if you're just getting started in that wonderful world. With so many options with unique advantages and drawbacks, it's not easy to know where to begin. &lt;/p&gt;

&lt;h2&gt;My first programming language&lt;/h2&gt;

&lt;p&gt;When I was 14, I started learning my first coding language, which wasn't easy. At one point, I almost gave up. The reason is, the internet suggested that "all languages are garbage, cool hackers use only C or C++". Learning programming from C/C++ isn't an easy task, and my suggestion is to start with something more straightforward and move forward if you like it and can see your goals more clearly.&lt;/p&gt;

&lt;p&gt;As mentioned, choosing the first coding languages is complex. But by thinking about your interests and objectives, the job market, and the types of applications each language is typically used for, you can simplify your decision-making process and find the right language to start with.&lt;/p&gt;

&lt;p&gt;Let's go to each point and discuss it a bit. &lt;/p&gt;

&lt;h2&gt;1. Consider your goals and interests &lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--BZh93hxj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2023/03/compass.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--BZh93hxj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2023/03/compass.jpg" alt="compass to find your first programming language" width="512" height="512"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This step is vital in making an informed decision about where to start. By understanding what you want to achieve and what excites you, you can narrow your options and find the best-suited language.&lt;/p&gt;

&lt;p&gt;Your goals may include building specific types of applications, such as mobile or web apps, or working in fields like data science or machine learning. Match your goals with the unique abilities of various languages to discover the one that helps you achieve your aspirations.&lt;/p&gt;

&lt;p&gt;Your interests can also affect your decision. For example, if you enjoy working with visuals, you may prefer a language ideal for game or front-end web development. Python may be more appealing if you're more into data analysis and statistics. Choose a language that motivates you to learn by identifying your interests.&lt;/p&gt;

&lt;p&gt;Remember, your interests and goals may change over time, and shifting your focus or even languages is okay if necessary. Start learning, enjoy the process, and have a clear objective to maximize your time and effort.&lt;/p&gt;

&lt;h2&gt;2. Popular languages are good options for beginners&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZFSzAtSh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2023/03/chart.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZFSzAtSh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2023/03/chart.jpg" alt="chart of coding languages" width="512" height="512"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Python and JavaScript are two fantastic options for beginners. They have huge communities and a lot of resources, videos, and tutorials. One of the most significant benefits of starting with a popular language is the size and diversity of its community. As a novice, you'll have access to plenty of resources and tutorials, including online documentation, code samples, forums, and educational materials. This makes it much simpler to learn the language, resolve issues, and locate solutions to problems that you may encounter.&lt;/p&gt;

&lt;p&gt;Python is a versatile, high-level programming language for data science, machine learning, and web development. The language features a simple, readable syntax and an extensive standard library, making it easy to learn and utilize. Python also has numerous libraries and frameworks like pandas, scikit-learn, and Tensorflow, making it incredibly powerful. The Python community is very active and supportive, and you will find a lot of learning materials, tutorials, and documentation to help you learn more about the language and its applications.&lt;/p&gt;

&lt;p&gt;JavaScript is a widely-used programming language mainly used to develop interactive and dynamic web pages and applications. JavaScript is also known as the only language that can run on the browser, making it the perfect choice for front-end development. The language boasts many frameworks and libraries like React and Angular, which make it very popular for web development. Furthermore, JavaScript can be used for server-side programming with NodeJS. With a huge community and plenty of resources, learning JavaScript can be a straightforward and enjoyable experience.&lt;/p&gt;

&lt;p&gt;By the way, I have two popular articles with code examples of JavaScript and Python. Would you check them?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://jakeroid.com/blog/how-to-download-vimeo-video-using-javascript/"&gt;How to download Vimeo video using JavaScript?&lt;/a&gt;&lt;/li&gt;



&lt;li&gt;&lt;a href="https://jakeroid.com/blog/how-to-download-vimeo-video-using-python/"&gt;How to download Vimeo video using Python?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;3. Job market and the types of applications&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hiNNl11---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2023/03/people.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hiNNl11---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2023/03/people.jpg" alt="people choosing first programming language" width="512" height="512"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When selecting your first programming language, consider the job market and the types of applications typically developed with that language. Different languages are used for various purposes, and the type of application you want to build can impact which language is most appropriate for you to learn.&lt;/p&gt;

&lt;p&gt;To assess the job market for a language, examine the number of job postings that require it. For example, Python is often used for data science and machine learning, and it's in high demand in these fields. JavaScript is often used for web and front-end development, commonly used to develop interactive and dynamic web pages and applications. Learning one of these languages is a good choice if you want a job in these fields.&lt;/p&gt;

&lt;p&gt;Consider the types of applications developed using a particular language. For instance, learning JavaScript is wise if you're interested in building web apps due to its popularity in web development. Conversely, Python is more appropriate if you're interested in data science and machine learning. Many languages have multiple purposes, and you can find a job in a specific field with various languages. &lt;/p&gt;

&lt;p&gt;Therefore, consider which language is more commonly used in the industry or field you wish to work.&lt;/p&gt;

&lt;h2&gt;4. Learning curve&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--USS1YccE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2023/03/curve.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--USS1YccE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2023/03/curve.jpg" alt="learning curve " width="512" height="512"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When selecting your first programming language, consider the &lt;a href="https://en.wikipedia.org/wiki/Learning_curve" rel="noreferrer noopener"&gt;learning curve&lt;/a&gt;. Various languages have different levels of complexity, and some are easier to learn than others. For a beginner, starting with a language with a relatively straightforward syntax may be more beneficial. This can help make the learning process less frustrating and more enjoyable.&lt;/p&gt;

&lt;p&gt;Python, for instance, has a simple and readable syntax that makes it easy to understand the code and write your programs. It has a simple grammatical structure and easy-to-understand ways of performing common operations. Furthermore, some languages have many resources, tutorials, and documentation available that can help you get started quickly. This makes it easier for beginners to learn the language and build their programs.&lt;/p&gt;

&lt;p&gt;Other languages, such as C++ or Java, have a steeper learning curve, with more complex syntax and a greater number of features and concepts to learn. These languages may require more time and effort to master, making them more challenging for beginners. However, once you have mastered the language, you'll be able to build more complex applications.&lt;/p&gt;

&lt;p&gt;Bear in mind that the learning curve of a language is not the only factor to consider when selecting your first programming language. Other factors, such as community support, the job market, and your interest in projects, are also critical. Therefore, the best approach to choosing a language would be to weigh the pros and cons of each and make a decision that best suits your personal situation.&lt;/p&gt;

&lt;h2&gt;5. First programming language &amp;amp; Fun? &lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ajdlnpIv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2023/03/robot.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ajdlnpIv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2023/03/robot.jpg" alt="robot is trying to write some code" width="512" height="512"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Learning your first programming language can be an exciting and rewarding experience, but it can also be challenging and frustrating at times. However, enjoying the process and having fun while learning is essential.&lt;/p&gt;

&lt;p&gt;One way to make the learning process more enjoyable is to find a language that aligns with your interests and passions. For example, if you're interested in web development, learning JavaScript can be a fun and engaging experience. On the other hand, if you're interested in data science and machine learning, Python may be a more intriguing language to learn.&lt;/p&gt;

&lt;p&gt;Another way to make learning fun is to set small and achievable goals for yourself. This can help you stay motivated and make the learning process more manageable. Celebrate your achievements along the way, and don't be afraid to make mistakes as they can be valuable learning experiences.&lt;/p&gt;

&lt;p&gt;In summary, having fun while learning your first programming language is crucial. Finding a language that aligns with your interests and passions, setting achievable goals, and celebrating your progress can make the learning process more enjoyable and rewarding.&lt;/p&gt;

&lt;h2&gt;Summary&lt;/h2&gt;

&lt;p&gt;In summary, while learning a programming language may require effort and dedication, ensuring you're having fun and enjoying the process is essential. This will help you stay motivated and progress, and it will make it more likely that you'll continue to learn and use the language in the future.&lt;/p&gt;

&lt;p&gt;Do you have any questions? Ask them in the comments section below. &lt;/p&gt;

</description>
      <category>programming</category>
      <category>codin</category>
      <category>python</category>
      <category>javascript</category>
    </item>
    <item>
      <title>How to debug TypeScript in WebStorm?</title>
      <dc:creator>Ivan Karabadzhak</dc:creator>
      <pubDate>Sun, 19 Feb 2023 08:10:55 +0000</pubDate>
      <link>https://dev.to/jakeroid/how-to-debug-typescript-in-webstorm-2b8h</link>
      <guid>https://dev.to/jakeroid/how-to-debug-typescript-in-webstorm-2b8h</guid>
      <description>&lt;p&gt;In this article, I want to show you how WebStorm can debug TypeScript code. As you know, TypeScript code should be compiled into JavaScript before running in a browser or NodeJS. After compilation code will not be the same. If you want to put a breakpoint and check variable values, you have to tell the debugger where it should stop. How to do that? &lt;/p&gt;

&lt;p&gt;I will set up a project from scratch and show you how to make the WebStorm debugger work. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Long Story Short&lt;/strong&gt;: you need to set &lt;em&gt;sourceMap&lt;/em&gt; parameter in &lt;em&gt;tsconfig.json&lt;/em&gt; to true. It will tell &lt;em&gt;tsc&lt;/em&gt; to build source maps and that will help WebStorm to know where to stop if you put a breakpoint.&lt;/p&gt;

&lt;h2&gt;Setup the TypeScript project&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;&lt;em&gt;First of all, you should have installed NodeJS and WebStorm to make all scripts on commands works. Also, all terminal commands might not work in Windows systems.&lt;/em&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;And one more important thing. Of course, you can debug with console.log and don't use any external debugger. However, I should say sometimes the program's complexity makes console.log debugging pretty hard. Better to have some tools in the pocket that will allow you to use more power. &lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Let's set up an empty project first. We can create a directory and initialize npm there by following commands. &lt;/p&gt;

&lt;pre&gt;# create directory
mkdir typescript-debug-webstorm

# go inside directory
cd typescript-debug-webstorm

# initialize empty npm project
npm init -y&lt;/pre&gt;

&lt;p&gt;To make TypeScript work we need to install it and initialize it. Let's do that.&lt;/p&gt;

&lt;pre&gt;# installing TypeScript
npm i --save-dev typescript

# initialize default configuration
npx tsc --init&lt;/pre&gt;

&lt;p&gt;Now I would like to set up a basic directories structure. My preference is to use &lt;em&gt;src&lt;/em&gt; directory for TypeScript files, and &lt;em&gt;dist&lt;/em&gt; directory for compiled code. &lt;/p&gt;

&lt;pre&gt;# create both directories 
mkdir src 
mkdir dist&lt;/pre&gt;

&lt;p&gt;Now time to edit TypeScript configuration and make it work as excepted with my directories. Open the directory in WebStorm, and then open the&lt;em&gt; tsconfig.json&lt;/em&gt; file. Afterward we need to edit it a bit to make it work with my preferred directory structure. &lt;/p&gt;

&lt;p&gt;TypeScript compiler will scan &lt;em&gt;src&lt;/em&gt; directory by default. As for &lt;em&gt;dist &lt;/em&gt;directory&lt;em&gt;,&lt;/em&gt; we need to edit the parameter outDir. Find it in the file, remove the comment, and change it to &lt;em&gt;./dist&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fjakeroid.com%2Fwp-content%2Fuploads%2F2023%2F02%2Fimage-1024x604.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fjakeroid.com%2Fwp-content%2Fuploads%2F2023%2F02%2Fimage-1024x604.png" alt="outDir parameter inside tsconfig" width="800" height="471"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now time to test our setup before we move to debug. Let's create a simple &lt;em&gt;index.ts&lt;/em&gt; file inside the &lt;em&gt;src&lt;/em&gt; directory. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fjakeroid.com%2Fwp-content%2Fuploads%2F2023%2F02%2Fimage-1-1024x338.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fjakeroid.com%2Fwp-content%2Fuploads%2F2023%2F02%2Fimage-1-1024x338.png" alt="simple typescript project in webstorm" width="800" height="264"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And here is the code.&lt;/p&gt;

&lt;pre&gt;function main() {
    console.log('Hello World! We will setup TypeScript debugging in WebStorm!');
}

main();&lt;/pre&gt;

&lt;p&gt;Let's compile it and run it by executing the following commands. &lt;/p&gt;

&lt;pre&gt;# compile source (you could also just run tsc)
npx tsc 

# run 
node dist/index.js&lt;/pre&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fjakeroid.com%2Fwp-content%2Fuploads%2F2023%2F02%2Fimage-2-1024x236.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fjakeroid.com%2Fwp-content%2Fuploads%2F2023%2F02%2Fimage-2-1024x236.png" alt="" width="800" height="184"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Nice! As a result it looks like everything is working. But noted let's set up one more thing before we will move to debugging. I am talking about npm commands. Open the &lt;em&gt;package.json&lt;/em&gt; file and add a few commands inside the scripts section. Here is my result &lt;em&gt;package.json&lt;/em&gt; file. &lt;/p&gt;

&lt;pre&gt;{
  "name": "typescript-debug-webstorm",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" &amp;amp;&amp;amp; exit 1",
    "build": "npx tsc",
    "prestart": "npm run build",
    "start": "node dist/index.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "typescript": "^4.9.5"
  }
}&lt;/pre&gt;

&lt;p&gt;As you can see, I added the commands &lt;em&gt;build&lt;/em&gt; and &lt;em&gt;start&lt;/em&gt;. Also, I added a pre-command, which will run before each start execution &lt;em&gt;start&lt;/em&gt;. Now we can run our program by following the command, and the source code will be compiled automatically. That is possible because before each start we run the build command which compiles our sources via TypeScript compiler. &lt;/p&gt;

&lt;p&gt;Let's change our program code a bit and rerun the program. &lt;/p&gt;

&lt;pre&gt;function main() {

    console.log('Hello World! We will setup TypeScript debugging in WebStorm!');
    for (let i = 0; i &amp;lt; 10; i++) {
        console.log(`Debugging is fun! ${i}`);
    }
}

main();&lt;/pre&gt;

&lt;pre&gt;# run our program by following command
npm run start &lt;/pre&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fjakeroid.com%2Fwp-content%2Fuploads%2F2023%2F02%2Fimage-3-1024x765.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fjakeroid.com%2Fwp-content%2Fuploads%2F2023%2F02%2Fimage-3-1024x765.png" alt="debugging with typescript and webstorm" width="800" height="597"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It looks like everything is working. Okay, now let's move to setting up the debugger. &lt;/p&gt;

&lt;h2&gt;Debugging TypeScript in WebStorm&lt;/h2&gt;

&lt;p&gt;First, let's add run configuration to our WebStorm settings. &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open &lt;em&gt;Edit Configurations&lt;/em&gt; popup.&lt;/li&gt;



&lt;li&gt;Then press on "+" to add new.&lt;/li&gt;



&lt;li&gt;In the new popup, select &lt;em&gt;npm&lt;/em&gt;.&lt;/li&gt;



&lt;li&gt;After select the command &lt;em&gt;start&lt;/em&gt; from the scripts menu.&lt;/li&gt;



&lt;li&gt;Press &lt;em&gt;OK&lt;/em&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fjakeroid.com%2Fwp-content%2Fuploads%2F2023%2F02%2Fimage-5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fjakeroid.com%2Fwp-content%2Fuploads%2F2023%2F02%2Fimage-5.png" alt="edit run configuration in webstorm" width="720" height="378"&gt;&lt;/a&gt;1. Open &lt;em&gt;Edit&lt;/em&gt; &lt;em&gt;Configurations&lt;/em&gt; popup.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fjakeroid.com%2Fwp-content%2Fuploads%2F2023%2F02%2Fimage-4-1024x513.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fjakeroid.com%2Fwp-content%2Fuploads%2F2023%2F02%2Fimage-4-1024x513.png" alt="add new run configuration in webstorm" width="800" height="400"&gt;&lt;/a&gt;2. Then press on "+" to add new. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fjakeroid.com%2Fwp-content%2Fuploads%2F2023%2F02%2Fimage-6-532x1024.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fjakeroid.com%2Fwp-content%2Fuploads%2F2023%2F02%2Fimage-6-532x1024.png" alt="npm run configuration webstorm" width="532" height="1024"&gt;&lt;/a&gt;3. In the new popup, select "&lt;em&gt;npm&lt;/em&gt;". &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fjakeroid.com%2Fwp-content%2Fuploads%2F2023%2F02%2Fimage-7-1024x757.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fjakeroid.com%2Fwp-content%2Fuploads%2F2023%2F02%2Fimage-7-1024x757.png" alt="selection script in npm run configuration webstorm" width="800" height="591"&gt;&lt;/a&gt;4. After select the command &lt;em&gt;start&lt;/em&gt; from the sripts menu.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fjakeroid.com%2Fwp-content%2Fuploads%2F2023%2F02%2Fimage-8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fjakeroid.com%2Fwp-content%2Fuploads%2F2023%2F02%2Fimage-8.png" alt="buttons in run configuration window webstorm" width="516" height="276"&gt;&lt;/a&gt;5. Press &lt;em&gt;OK&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;After all, we are done with the configurations. Let's try to debug. Put breakpoint somewhere, for example, on the second console.log call. To do that, click on the line number on the left. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fjakeroid.com%2Fwp-content%2Fuploads%2F2023%2F02%2Fimage-10-1024x264.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fjakeroid.com%2Fwp-content%2Fuploads%2F2023%2F02%2Fimage-10-1024x264.png" alt="typescript debug example" width="800" height="206"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then press debug button on the top. Additionally don't miss one important thing: the &lt;em&gt;start&lt;/em&gt; script should be selected like a current run configuration. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fjakeroid.com%2Fwp-content%2Fuploads%2F2023%2F02%2Fimage-9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fjakeroid.com%2Fwp-content%2Fuploads%2F2023%2F02%2Fimage-9.png" alt="start debugging webstorm" width="746" height="236"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Nice, but... The program finished successfully, besides nothing happened with our breakpoint.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fjakeroid.com%2Fwp-content%2Fuploads%2F2023%2F02%2Fimage-11-1024x783.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fjakeroid.com%2Fwp-content%2Fuploads%2F2023%2F02%2Fimage-11-1024x783.png" alt="debug example webstorm typescript" width="800" height="611"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Why did it happen? As I mentioned before, WebStorm doesn't know where to stop, because NodeJS executes compiled JavaScriopt code. &lt;/p&gt;

&lt;p&gt;How to fix it? We need to edit the &lt;em&gt;tsconfig.json&lt;/em&gt; file and set &lt;em&gt;sourceMap parameter to true. That will tell TypeScript compiler to make a &lt;/em&gt;source map between TypeScript and JavaScript code. Because of that WebStorm will know where is corresponding code. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fjakeroid.com%2Fwp-content%2Fuploads%2F2023%2F02%2Fimage-12-1024x299.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fjakeroid.com%2Fwp-content%2Fuploads%2F2023%2F02%2Fimage-12-1024x299.png" alt="sourceMap parameter typescript config " width="800" height="233"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's try again to debug.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fjakeroid.com%2Fwp-content%2Fuploads%2F2023%2F02%2Fimage-13-1024x298.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fjakeroid.com%2Fwp-content%2Fuploads%2F2023%2F02%2Fimage-13-1024x298.png" alt="debugger stop on breakpoint webstorm" width="800" height="232"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fjakeroid.com%2Fwp-content%2Fuploads%2F2023%2F02%2Fimage-14-1024x367.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fjakeroid.com%2Fwp-content%2Fuploads%2F2023%2F02%2Fimage-14-1024x367.png" alt="debugger information window webstorm" width="800" height="286"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finnaly it's working! After that you could use the &lt;em&gt;Resume Program&lt;/em&gt; button and iterate via each loop statement inside the code. Awesome, isn't it? &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fjakeroid.com%2Fwp-content%2Fuploads%2F2023%2F02%2Fimage-15.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fjakeroid.com%2Fwp-content%2Fuploads%2F2023%2F02%2Fimage-15.png" alt="resume program debugger in webstorm" width="800" height="321"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In sum it isn't too hard to setup debugger for TypeScript in WebStorm. I hope you will be able to use the full power of the WebStorm debugger. If you have any questions feel free to ask them in the comments section below. &lt;/p&gt;

&lt;p&gt;If you would like to check source files welcome to my GitHub: &lt;a href="https://github.com/Jakeroid/blog-article-typescript-debug-webstorm" rel="noreferrer noopener"&gt;https://github.com/Jakeroid/blog-article-typescript-debug-webstorm&lt;/a&gt;. &lt;/p&gt;

</description>
    </item>
    <item>
      <title>How to write your first Solidity smart contract?</title>
      <dc:creator>Ivan Karabadzhak</dc:creator>
      <pubDate>Thu, 03 Nov 2022 20:06:34 +0000</pubDate>
      <link>https://dev.to/jakeroid/how-to-write-your-first-solidity-smart-contract-a7i</link>
      <guid>https://dev.to/jakeroid/how-to-write-your-first-solidity-smart-contract-a7i</guid>
      <description>&lt;p&gt;Hello folks! Maybe, as you might know, I am learning blockchain development. My current focus is Solidity smart contract development. I decided to make a simple article to show you how to write your first Solidity smart contract. I don't think you will learn a lot. But I want to show how it is simple to start. Maybe that will motivate you to continue to do some interesting things. Who knows? Let's start. &lt;/p&gt;

&lt;h2&gt;What is Remix IDE?&lt;/h2&gt;

&lt;p&gt;Starting to develop Solidity smart contracts is very simple. There is an online IDE for that called Remix IDE. You can open it in your browser and start it! You don't need to set up everything on your computer. &lt;/p&gt;

&lt;p&gt;Maybe some serious developers use the local environment to build robust smart contracts. However, I don't know a simpler way for beginners than Remix IDE. So, don't waste your time and click on &lt;a href="https://remix-project.org/" rel="noreferrer noopener"&gt;https://remix-project.org/&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Then scroll down and click on that block.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xk4hdYuE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2022/11/image.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xk4hdYuE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2022/11/image.png" alt="remix ide link" width="800" height="742"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you even use VSCode, then you will like Remix IDE UI. They are very similar. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--X8GtNmcO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2022/11/image-1-1024x586.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--X8GtNmcO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2022/11/image-1-1024x586.png" alt="remix ide home" width="800" height="458"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;My goal is to show you the simplicity of writing a new contract. So, let's go. &lt;/p&gt;

&lt;h2&gt;Writing smart contract code&lt;/h2&gt;

&lt;p&gt;Left-click on the contracts folder on the left and choose a new file. Name it MyContract.sol.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Uz9Aij8K--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2022/11/image-2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Uz9Aij8K--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2022/11/image-2.png" alt="create new file in remix ide" width="708" height="548"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Cool, now we should write code. But before we write the first Solidity smart contract, let's check some examples of open contracts which are already in the contracts folder. You could open, for example, 1_Storage.sol. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5SSO3A5X--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2022/11/image-3-970x1024.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5SSO3A5X--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2022/11/image-3-970x1024.png" alt="example of solidity smart contract" width="800" height="845"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There aren't a lot of code lines. It's pretty simple. What could we learn from it? &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Each Solidity contract should have a license comment and a Solidity version at the top. &lt;/li&gt;



&lt;li&gt;Each contract is very similar to a class in other languages. &lt;/li&gt;



&lt;li&gt;The contract could have methods inside. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let's write our contract now. First copy license and pragma version. Then add an empty contract.&lt;/p&gt;

&lt;pre&gt;// SPDX-License-Identifier: GPL-3.0

pragma solidity &amp;gt;=0.7.0 &amp;lt;0.9.0;

contract MyContract {

}&lt;/pre&gt;

&lt;p&gt;Looks great, but it's empty. Let's add some logic. &lt;/p&gt;

&lt;pre&gt;contract MyContract {
    string name;

    function setName(string memory _name) public {
        name = _name;
    }

    function whatIsName() public view returns(string memory) {
        return name;
    }
}&lt;/pre&gt;

&lt;p&gt;I will not jump into detail today. The general idea of MyContract is similar to 1_Storage.sol. However, it stores strings instead of integers. &lt;/p&gt;

&lt;h2&gt;Compiling and Deployment&lt;/h2&gt;

&lt;p&gt;Press Ctrl + S or CMD + S to compile the contract. Another way is to click that icon and press the button.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xdrQb_xj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2022/11/image-4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xdrQb_xj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2022/11/image-4.png" alt="remix ide compiler icon" width="194" height="204"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9lYQO5ON--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2022/11/image-5-1024x744.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9lYQO5ON--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2022/11/image-5-1024x744.png" alt="remix ide compile smart contract" width="800" height="581"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt; If everything is good, you will see the green mark. &lt;/p&gt;

&lt;h2&gt;Testing&lt;/h2&gt;

&lt;p&gt;How could we test the contract? In the real world, developers deploy contracts on the blockchain. However, it costs money. Remix IDE provides an environment to deploy contracts and test them for free. &lt;/p&gt;

&lt;p&gt;Go to that tab.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--3IbTcA4v--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2022/11/image-6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3IbTcA4v--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2022/11/image-6.png" alt="remix ide deployment section icon" width="170" height="174"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There are many things, but you don't need to know each one to test your smart contract. Just press the Deploy button and see the magic. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--beihQC3s--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2022/11/image-7-715x1024.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--beihQC3s--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2022/11/image-7-715x1024.png" alt="remix ide deployment section" width="715" height="1024"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--KQZN-3ug--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2022/11/image-8-1024x167.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KQZN-3ug--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2022/11/image-8-1024x167.png" alt="remix ide transactions" width="800" height="130"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--eAakvpD1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2022/11/image-9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--eAakvpD1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2022/11/image-9.png" alt="remix ide deployed contract" width="800" height="344"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see contract is deployed. Let's test it. Press the arrow on the left and expand the contract details. You can see our methods/functions from our contract.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--i4r4yehJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2022/11/image-10.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--i4r4yehJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2022/11/image-10.png" alt="remix ide interacting with solidity smart contract" width="800" height="522"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Remix IDE provides UI for interacting with our contract. Write something in the input text field and press the "setName" button. You will see some transaction appears in the bottom window. It is similar to transactions when we deploy contracts.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZbeTTKNQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2022/11/image-11-1024x152.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZbeTTKNQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2022/11/image-11-1024x152.png" alt="remix ide transactions" width="800" height="119"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now press the "whatIsName" button. THE MAGIC WILL APPEAR! &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9IN1BPlG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2022/11/image-12.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9IN1BPlG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2022/11/image-12.png" alt="remix ide interacting with solidity smart contract" width="420" height="258"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;Is it pretty simple? Absolutely! Of course, to develop some complex smart contracts as real developers do, you should learn more about blockchains, crypto, and Solidity language. However, I hope this small note in my blog will inspire you to try and go deeper. &lt;/p&gt;

&lt;p&gt;Stay posted if you are interested in more articles about blockchains, crypto, and Solidity. &lt;/p&gt;

&lt;p&gt;By the way, did you check my article about &lt;a href="https://jakeroid.com/blog/make-a-great-upwork-profile-to-get-clients/"&gt;how to make a great Upwork profile&lt;/a&gt;? &lt;/p&gt;

</description>
      <category>solidity</category>
      <category>remixide</category>
    </item>
    <item>
      <title>How to set timezone in your docker image?</title>
      <dc:creator>Ivan Karabadzhak</dc:creator>
      <pubDate>Wed, 02 Nov 2022 20:04:57 +0000</pubDate>
      <link>https://dev.to/jakeroid/how-to-set-timezone-in-your-docker-image-18bk</link>
      <guid>https://dev.to/jakeroid/how-to-set-timezone-in-your-docker-image-18bk</guid>
      <description>&lt;p&gt;Sometimes you may want to set the correct timezone in a docker image. It could be needed for some simple things, or even it can change how your application inside the container behaves. Anyway, the task is pretty simple. Let me show you. &lt;/p&gt;

&lt;p&gt;So, long story short, to set the timezone in your docker image, add the following line to your Dockerfile.  &lt;/p&gt;

&lt;pre&gt;ENV TZ="Europe/London"&lt;/pre&gt;

&lt;p&gt;This method will work if you have the package tzdata installed. For example, Debian has tzdata, but Ubuntu doesn't. You need to install tzdata to use the same Dockerfile command in Ubuntu. &lt;/p&gt;

&lt;p&gt;What to do if you got something different than Debian? Don't worry, I collected instructions for different distributives. If you use some distro not mentioned, let me know, and I'll try to add instructions for it too.&lt;/p&gt;

&lt;h2&gt;Debian&lt;/h2&gt;

&lt;p&gt;As I said before, it's pretty simple. Just add that line to your Dockerfile.&lt;/p&gt;

&lt;pre&gt;ENV TZ="Europe/London"&lt;/pre&gt;

&lt;h2&gt;Ubuntu&lt;/h2&gt;

&lt;p&gt;Also simple, but one more command required because we need to install tzdata.&lt;/p&gt;

&lt;pre&gt;RUN apt-get update &amp;amp;&amp;amp; apt-get install tzdata -y
ENV TZ="Europe/London"&lt;/pre&gt;

&lt;h2&gt;Alpine&lt;/h2&gt;

&lt;p&gt;Very similar to Debian and Ubuntu, but Alpine uses a different package manager (apk instead of apt).&lt;/p&gt;

&lt;pre&gt;RUN apk add tzdata
ENV TZ="Europe/London"&lt;/pre&gt;

&lt;h2&gt;CentOS&lt;/h2&gt;

&lt;p&gt;For CentOS, the situation is a bit more complex. CentOS uses the yum package manager. By default CentOS docker image doesn't have any URL in sources lists, so you need to add them first. After that, everything is very similar to another distributive.&lt;/p&gt;

&lt;pre&gt;RUN sed -i -e "s|mirrorlist=|#mirrorlist=|g" /etc/yum.repos.d/CentOS-*
RUN sed -i -e "s|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g" /etc/yum.repos.d/CentOS-*

RUN yum -y install tzdata
ENV TZ="Europe/London"&lt;/pre&gt;

&lt;p&gt;If you want to have Dockefile examples, please, check out my &lt;a href="https://github.com/Jakeroid/docker-image-timezone"&gt;github&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;I hope this article helps you. Feel free to ask any questions in the comments. &lt;/p&gt;

</description>
      <category>docker</category>
    </item>
    <item>
      <title>How to download Vimeo video using JavaScript?</title>
      <dc:creator>Ivan Karabadzhak</dc:creator>
      <pubDate>Wed, 02 Nov 2022 19:50:29 +0000</pubDate>
      <link>https://dev.to/jakeroid/how-to-download-vimeo-video-using-javascript-3975</link>
      <guid>https://dev.to/jakeroid/how-to-download-vimeo-video-using-javascript-3975</guid>
      <description>&lt;p&gt;Some time ago, I made the same article but with Python. You can find it here. Some guys asked me to make a similar post, but with JavaScript and NodeJS. So, today I'll teach you how to download a Vimeo video using JavaScript. The article is oriented toward beginners. Welcome undercut. &lt;/p&gt;

&lt;h2&gt;Attention!&lt;/h2&gt;

&lt;p&gt;I made this post and this code for learning purposes. I don't recommend it for commercial use. I'm not responsible for any damage caused by this code. Please, don't lawlessly use this code and avoid any illegal activities.&lt;/p&gt;

&lt;h2&gt;Setup project template&lt;/h2&gt;

&lt;p&gt;I have NodeJS on my MacBook if you don't, please install it first. Installing NodeJS is out of scope for this post, but if you need some help feel free to ask any questions here or on my &lt;a href="https://twitter.com/Jakeroid"&gt;Twitter&lt;/a&gt;. My NodeJS version is 18.0.0.&lt;/p&gt;

&lt;p&gt;The next step is creating an empty directory and initializing npm there. I use terminal commands for that.&lt;/p&gt;

&lt;pre&gt;# create directory
mkdir download-vimeo-video-javascript

# go inside
cd download-vimeo-video-javascript

# init npm
npm init -y&lt;/pre&gt;

&lt;p&gt;Those commands create a project directory and initialize it with the default package.json file. By default, index.js is the main file, but I prefer for those kinds of apps to use app.js. &lt;/p&gt;

&lt;p&gt;Also, to use ES6 imports, we need to change the package type by putting the "type": "module" option. I usually do it to be able to use "import" instead of "require".&lt;/p&gt;

&lt;p&gt;And will be great to have npm command to run our application. &lt;/p&gt;

&lt;p&gt;Honestly, this doesn't matter for the current article, but I am showing you what I always do. So, let's edit package.json file. &lt;/p&gt;

&lt;pre&gt;{
  "name": "download-vimeo-video-javascript",
  "version": "1.0.0",
  "type": "module",
  "description": "",
  "main": "app.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" &amp;amp;&amp;amp; exit 1",
    "start": "node app.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}&lt;/pre&gt;

&lt;p&gt;We need to create a file app.js in the same directory and start coding. Finally! &lt;/p&gt;

&lt;h2&gt;Basic code&lt;/h2&gt;

&lt;p&gt;Let's make basic code for our app.js file. &lt;/p&gt;

&lt;pre&gt;'use strict';


const main = async () =&amp;gt; {
    
    console.log('Hello World');
}

const promise = main();

promise.then(() =&amp;gt; {
    console.log('Program finished!');
});

promise.catch((err) =&amp;gt; {
    console.log('Program finished with error!');
    console.log(err);
});&lt;/pre&gt;

&lt;p&gt;Let me explain why we make those code. &lt;/p&gt;

&lt;p&gt;The first line tells NodeJS we want to use strict mode. Strict mode is out of the scope of this article too. I use it by default because it disallows you to do some not safe things, and also, it shows an error that doesn't appear in no strict mode. &lt;/p&gt;

&lt;p&gt;The next block is the initialization async function and putting it inside the variable name. I prefer to have the ability to use async/await constructions. You can put await only inside asynchronous functions. That's why I create the main. Inside the function, we have console.log call with hello world just for testing purposes. We will remove it later. &lt;/p&gt;

&lt;p&gt;Below the main function initialization, I put calling of it and promise with then and catch handler. If you want to know more about promises, let me know. I could write an article about that. &lt;/p&gt;

&lt;p&gt;Let's test our program. Run the following command.&lt;/p&gt;

&lt;pre&gt;npn run start&lt;/pre&gt;

&lt;p&gt;My result is in the screenshot bellow.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7gu3wE7X--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2022/07/image-1024x371.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7gu3wE7X--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2022/07/image-1024x371.png" alt="hello world nodejs example" width="800" height="290"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Looks like everything is working. Let's move to downloading the video now. &lt;/p&gt;

&lt;h2&gt;Theory&lt;/h2&gt;

&lt;p&gt;If you watch any video from Vimeo, your browser downloads it in the background. So, we can do the same, but we need to know the video URL. If we have a video URL, there isn't a problem with downloading it. &lt;/p&gt;

&lt;p&gt;I have investigated before, and I know where it is. When you visit Vimeo page, your browser sends one more request with video ID to Vimeo servers, and it gets JSON object with information about the video. There is a video URL too. &lt;/p&gt;

&lt;h2&gt;Getting Vimeo video ID&lt;/h2&gt;

&lt;p&gt;Let's take some video for example. I took &lt;a href="https://vimeo.com/712159936" rel="noreferrer noopener nofollow"&gt;this one&lt;/a&gt; randomly in the previous article. It looks strange, but we don't need to care about content. &lt;/p&gt;

&lt;p&gt;Our first goal is to take the ID of the video. Video ID is those numbers at the end of video URL.&lt;/p&gt;

&lt;pre&gt;    // input video url
    let inputVideoUrl = 'https://vimeo.com/712159936/';

    // check is there ending slash and remove it
    if (inputVideoUrl.slice(-1) === '/') {
        inputVideoUrl = inputVideoUrl.slice(0, -1);
    }

    // get video id from url
    const videoId = inputVideoUrl.split('/').pop();
    
    console.log(videoId);&lt;/pre&gt;

&lt;p&gt;Maybe you want some additional explanation. &lt;/p&gt;

&lt;p&gt;At first, I checked if is there an ending slash inside the input URL. This is required because I want to split the string by "/" char and get the last element or result array (video ID). So, an ending slash could interfere with doing that. &lt;/p&gt;

&lt;p&gt;Okay, we have a video ID. What is next?&lt;/p&gt;

&lt;h2&gt;Getting project JSON config from Vimeo&lt;/h2&gt;

&lt;p&gt;In my previous article &lt;a href="https://jakeroid.com/blog/how-to-download-vimeo-video-using-python/"&gt;how to download Video video using Python&lt;/a&gt; I show screenshots from browser inspection. They illustrate how browser sends an additional request to Vimeo servers and get project JSON config. Let me put them here.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cpPTqgnd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2022/05/image-2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cpPTqgnd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2022/05/image-2.png" alt="request to vimeo video" width="798" height="360"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Q-fh0ZHx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2022/05/image-1-1024x551.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Q-fh0ZHx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2022/05/image-1-1024x551.png" alt="request result to vimeo video" width="800" height="430"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see, a browser sends the request to some Vimeo URL and get the JSON configuration of the video. You can't see this on screenshots, but for a request, the browser uses host player.vimeo.com.&lt;/p&gt;

&lt;p&gt; Time to make the same. &lt;/p&gt;

&lt;p&gt;First, let's import https module. For that just add import on the top of the file import https from 'https'; I like to use async/await contraction, so let's use promises to get our JSON with https module. &lt;/p&gt;

&lt;pre&gt;    // video json config url
    const videoJsonConfigUrl = `https://player.vimeo.com/video/${videoId}/config`;

    // get video json config
    const videoConfig = await new Promise((resolve, reject) =&amp;gt; {

        https.get(videoJsonConfigUrl, (res) =&amp;gt; {

            let result = '';

            res.on('data', data =&amp;gt; {
                result += data;
            });

            res.on('error', err =&amp;gt; {
                reject(err);
            });

            res.on('end', () =&amp;gt; {
                resolve(JSON.parse(result));
            });

        });
    });

    console.log(videoConfig);&lt;/pre&gt;

&lt;p&gt;Here I put await and create new promise. The main code for getting video is inside the promise. I put data in the result string chunk by chunk and resolve it when the end event is emitted. If some error happens, then my code call rejects.&lt;/p&gt;

&lt;p&gt;I put the result on the screenshot.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--n5LQ8QDd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2022/07/image-1-1024x479.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--n5LQ8QDd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2022/07/image-1-1024x479.png" alt="getting video url from Vimeo" width="800" height="374"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What is the next step?&lt;/p&gt;

&lt;h2&gt;Download Vimeo video using JavaScript&lt;/h2&gt;

&lt;p&gt;Each video has different video quality. Each quality item has its own URL. There is a field videoConfig.request.files.progressive. It is an array of objects. Each object represents a video quality item. And, of course, each object has its own URL.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--DtyRkiQ2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2022/07/image-2-1024x793.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DtyRkiQ2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2022/07/image-2-1024x793.png" alt="how to download vimeo video using javascript - quality items" width="800" height="620"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's ignore quality choosing for now and download the first available one. At first, we need to import module fs. Add this line to the top of file &lt;code&gt;import fs from 'fs';&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now we can implement downloading and finally get that video from Vimeo. &lt;/p&gt;

&lt;pre&gt;    // video quality items
    const videoQualityItems = videoConfig.request.files.progressive;

    // select file url
    const targetItem = videoQualityItems[0];
    const targetVideoFileUlr = targetItem.url;
    const localPath = `./${videoId}-${targetItem.quality}.mp4`;

    // download it
    await new Promise((resolve, reject) =&amp;gt; {

            https.get(targetVideoFileUlr, (res) =&amp;gt; {

                const file = fs.createWriteStream(localPath);

                res.pipe(file);

                res.on('error', err =&amp;gt; {
                    reject(err);
                });

                res.on('end', () =&amp;gt; {
                    resolve();
                });

            });
    });&lt;/pre&gt;

&lt;p&gt;I used almost the same way to download video, except adding pipe from the input https stream to the output file write stream. This allows us to download a huge file without taking care of memory.&lt;/p&gt;

&lt;p&gt;Looks like everything works as excepted. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0IRXWx6V--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2022/07/image-3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0IRXWx6V--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2022/07/image-3.png" alt="result of video downloading" width="454" height="300"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Choosing the quality of video&lt;/h2&gt;

&lt;p&gt;Now, let's say we want to choose the quality of the video. For example, let's take the best one. I use reduce method of the array for that.&lt;/p&gt;

&lt;pre&gt;    // selecting the best video quality based on height and width
    // you could also add FPS multiplication to get the best quality based on FPS too
    const targetItem = videoQualityItems.reduce((prev, curr) =&amp;gt; {
        return prev.width * prev.height &amp;gt; curr.width * curr.height ? prev : curr;
    });&lt;/pre&gt;

&lt;p&gt;The logic here is very simple. Best quality = bigger amount of pixels. You could also FPS multiplication to get the best quality based on FPS too.&lt;/p&gt;

&lt;h2&gt;Conclusions&lt;/h2&gt;

&lt;p&gt;In general downloading video from Vimeo using JavaScript is pretty simple. I hope my article was useful for you. If you have any questions, suggestions, or criticism, please ask them below in the comments or write me directly on &lt;a href="https://twitter.com/Jakeroid"&gt;Twitter&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;I put all code in my &lt;a href="https://github.com/Jakeroid/download-vimeo-video-js"&gt;GitHub&lt;/a&gt; repository in case you need to check the full version. &lt;/p&gt;

</description>
      <category>scraping</category>
      <category>javascript</category>
    </item>
    <item>
      <title>How to protect content against scrapers with headless browsers?</title>
      <dc:creator>Ivan Karabadzhak</dc:creator>
      <pubDate>Tue, 01 Nov 2022 20:23:11 +0000</pubDate>
      <link>https://dev.to/jakeroid/how-to-protect-content-against-scrapers-with-headless-browsers-471i</link>
      <guid>https://dev.to/jakeroid/how-to-protect-content-against-scrapers-with-headless-browsers-471i</guid>
      <description>&lt;p&gt;We are living in a century of information. The data could bring huge value to your business. That's why a lot of different scrapers exist in the world. I guess each owner of a website at least once was thinking about how to protect their content. One of the ways is to use JavaScript to render content. However, modern technologies allow running a headless browser on the server and scraping all required data. Let's make scraper's creator life a bit harder…&lt;/p&gt;

&lt;p&gt;I want to show you an example of how to protect content from scrapers that use headless browsers for rendering content. However, first, I need to tell you some theories. Feel free to skip the next paragraph if you are a smart ass. &lt;/p&gt;

&lt;h2&gt;Shadow Root&lt;/h2&gt;

&lt;p&gt;Let me introduce you &lt;strong&gt;Shadow Root&lt;/strong&gt;. If one of you doesn't know what it is, I'll try to explain. Shadow Root allows you to create separate DOM inside your current DOM. It's kind of a document inside a document. Why could it be useful? For example, you can make your web component with your HTML IDs and CSS classes without taking care of other code on the web page. If you want to learn more, try to read &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/ShadowRoot" rel="noreferrer noopener nofollow"&gt;documentation&lt;/a&gt; and this &lt;a href="https://javascript.info/shadow-dom" rel="noreferrer noopener nofollow"&gt;article&lt;/a&gt;. &lt;/p&gt;

&lt;h2&gt;Protection&lt;/h2&gt;

&lt;p&gt;So, how can we use shadow root to protect content from scrapers? Shadow Root has two modes: open and closed. If the mode is closed, then you can't access elements inside JavaScript. That makes it impossible to scrape content from those elements by evaluating JS inside the browser.&lt;/p&gt;

&lt;p&gt;I'll show you an example. Let's create an empty HTML document with a div for sensitive data. &lt;/p&gt;

&lt;pre&gt;&amp;lt;strong&amp;gt;Following content should be protected:&amp;lt;/strong&amp;gt;
&amp;lt;div id="protected-content"&amp;gt;
&amp;lt;/div&amp;gt;&lt;/pre&gt;

&lt;p&gt;We need to use JavaScript, so let's create a script block after our div and put the following code for the test. I use shadow root in an open mode for now.&lt;/p&gt;

&lt;pre&gt;&amp;lt;strong&amp;gt;Following content should be protected:&amp;lt;/strong&amp;gt;
&amp;lt;div id="protected-content"&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;script&amp;gt;
    const element = document.querySelector('#sensitive-content');
    element.attachShadow({ mode: 'open' });
    element.shadowRoot.innerHTML = '&amp;lt;p&amp;gt;Hello from protected area, buddy!&amp;lt;/p&amp;gt;';
&amp;lt;/script&amp;gt;&lt;/pre&gt;

&lt;p&gt;What did we get as a result?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2an21oSN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2022/04/image-7-1024x530.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2an21oSN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2022/04/image-7-1024x530.png" alt="Shadow root example in open mode" width="800" height="414"&gt;&lt;/a&gt;Shadow root example in open mode&lt;/p&gt;

&lt;p&gt;Looks like our shadow root code is working. However, it didn't give any protection. You could easily access it by using the code like &lt;em&gt;element.shadowRoot&lt;/em&gt;.&lt;/p&gt;

&lt;pre&gt;element.attachShadow({ mode: 'closed' });&lt;/pre&gt;

&lt;p&gt;Oops... Looks like my code doesn't work now. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--MwtUuKvh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2022/04/image-1-1024x104.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MwtUuKvh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2022/04/image-1-1024x104.png" alt="Shadow root is not accessible if mode is closed." width="800" height="81"&gt;&lt;/a&gt;Shadow root is not accessible if mode is closed&lt;/p&gt;

&lt;p&gt;As I said before, closed shadow root can't be accessible from JavaScript. That means element.shadowRoot will always be null if the mode is closed. &lt;/p&gt;

&lt;p&gt;How can we fix that? Let's create a custom HTML component. At first, I removed div with id protected-content and the old JavaScript tag. Then I made a new script block inside the head and put the following code. The new code contains a declaration of the ProtectedWebComponent, the constructor, and connectedCallback method. You can find similar examples on the internet. &lt;/p&gt;

&lt;pre&gt;class ProtectedWebComponent extends HTMLElement {
    constructor() {
        super();
        this._protected_root = this.attachShadow({ mode: "closed" });
    }
    connectedCallback() {
        this._protected_root.innerHTML = `&amp;lt;p&amp;gt;Hello from protected area, buddy!&amp;lt;/p&amp;gt;`;
    }
}
window.customElements.define("protected-web-component", ProtectedWebComponent);&lt;/pre&gt;

&lt;p&gt;Then I added a new component to HTML.&lt;/p&gt;

&lt;pre&gt;&amp;lt;strong&amp;gt;Following content should be protected:&amp;lt;/strong&amp;gt;
&amp;lt;protected-web-component&amp;gt;&amp;lt;/protected-web-component&amp;gt;&lt;/pre&gt;

&lt;p&gt;Does it work? Yeah, looks good. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7MZCbN3g--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2022/04/image-8-1024x413.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7MZCbN3g--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2022/04/image-8-1024x413.png" alt="Closed shadow root example. Scrapers can't access it." width="800" height="323"&gt;&lt;/a&gt;Closed shadow root example&lt;/p&gt;

&lt;p&gt;However, there is still a problem. You can't access shadow root by calling something like &lt;em&gt;element.shadowRoot&lt;/em&gt;, but there is still &lt;em&gt;_protected_root&lt;/em&gt; field. So, it allows us to get shadow root by calling &lt;em&gt;element._protected_root&lt;/em&gt;. How could we fix that? Let's initialize content inside the constructor and don't save the shadow root link anywhere. &lt;/p&gt;

&lt;pre&gt;class ProtectedWebComponent extends HTMLElement {
    constructor() {
        super();
        const shadowRootLink = this.attachShadow({ mode: "closed" });
        shadowRootLink.innerHTML = `&amp;lt;p&amp;gt;Hello from protected area, buddy!&amp;lt;/p&amp;gt;`;
    }
}
window.customElements.define("protected-web-component", ProtectedWebComponent);&lt;/pre&gt;

&lt;p&gt;Looks much better now.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--oNg2ppoq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2022/04/image-6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--oNg2ppoq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2022/04/image-6.png" alt="protected content against scrapers" width="800" height="413"&gt;&lt;/a&gt;It's impossible to access closed shadow root from JavaScript&lt;/p&gt;

&lt;h2&gt;Source code&lt;/h2&gt;

&lt;p&gt;If you want to check the source code, welcome to my GitHub &lt;a href="https://github.com/Jakeroid/protection-scraping-headless-browser" rel="noreferrer noopener"&gt;repository&lt;/a&gt;. &lt;/p&gt;

&lt;h2&gt;Results&lt;/h2&gt;

&lt;p&gt;As you can see, it's pretty to protect some content using shadow root. However, you should understand this way is not a magic stick. Using shadow root to protect content could make a web scraper developer's life more complex, but it doesn't put content in some bulletproof armor. If you are interested in how to avoid this protection, write a comment below, and I'll try to explain. &lt;/p&gt;

&lt;p&gt;By the way, I have an article &lt;a href="https://jakeroid.com/blog/how-to-download-vimeo-video-using-python/"&gt;how to download Vimeo video using Python&lt;/a&gt;. Maybe you are interested.&lt;/p&gt;

</description>
      <category>scrapers</category>
      <category>bot</category>
      <category>webdev</category>
      <category>programming</category>
    </item>
    <item>
      <title>Port 5000 is already in use macOS Monterey</title>
      <dc:creator>Ivan Karabadzhak</dc:creator>
      <pubDate>Tue, 01 Nov 2022 20:10:32 +0000</pubDate>
      <link>https://dev.to/jakeroid/port-5000-is-already-in-use-macos-monterey-362o</link>
      <guid>https://dev.to/jakeroid/port-5000-is-already-in-use-macos-monterey-362o</guid>
      <description>&lt;p&gt;After an update on my laptop, I got an issue. I have started the Docker container, but it fails. The port 5000 is already in use. Hmm, maybe another container took it. Ah, Airplay took it... Did you get the same issue? Let's fix it. &lt;/p&gt;

&lt;p&gt;A long time ago, I started using 5000 ports for my projects. Usually, it is a web service. This is useful because you can't run many services on port 80. With port 5000, I can run containers with a web server, for example, on 5000, 5001, 5002, etc. This is easy to remember a thing. I started using it after some Flask (Python Framework) experience. &lt;/p&gt;

&lt;p&gt;So, I started another container and got an error "Port 5000 is already in use". I checked my compose file and open ports and didn't understand the issue. After some research, I remembered about OS updates. Okay, catch you! &lt;/p&gt;

&lt;p&gt;In macOS Monterey, Apple added the ability to use your Mac as an AirPlay device. For example, you can stream something from your iPhone to your MacBook. &lt;/p&gt;

&lt;h2&gt;Solution&lt;/h2&gt;

&lt;p&gt;Solution #1: This is stupid, but you could use a lot of other ports. For example, not I am using 6000 and other similar ports instead of 5000. Pros of this way are that you get AirPlay enabled on your Mac. There are a lot of open ports, but 5000 was like a habit (not a hobbit). &lt;/p&gt;

&lt;p&gt;Solution #2: You could disable AirPlay. Go to System Preferences - Sharing. At the bottom, you will see the checkbox AirPlay Receiver. Disable it to make the port open.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Jr6nEmPe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2022/06/image-1024x844.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Jr6nEmPe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2022/06/image-1024x844.png" alt="Port 5000 is already in use in macOS Monterey" width="800" height="659"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I prefer the first way because using AirPlay on my MacBook could be useful. Anyway, it's good to have a choice. I hope this small note was helpful to you. &lt;/p&gt;

&lt;p&gt;By the way, I made a small note about &lt;a href="https://jakeroid.com/blog/how-to-remove-skype-icon-from-menu-bar/"&gt;how to remove the Skype icon from menubar on macOS&lt;/a&gt;. Would you like to check it? &lt;/p&gt;

</description>
      <category>macos</category>
      <category>docker</category>
    </item>
    <item>
      <title>How to remove Skype icon from the menu bar?</title>
      <dc:creator>Ivan Karabadzhak</dc:creator>
      <pubDate>Tue, 01 Nov 2022 19:55:23 +0000</pubDate>
      <link>https://dev.to/jakeroid/how-to-remove-skype-icon-from-the-menu-bar-2966</link>
      <guid>https://dev.to/jakeroid/how-to-remove-skype-icon-from-the-menu-bar-2966</guid>
      <description>&lt;p&gt;All minimalists and perfectionists are welcome. Today we will make our life a bit easier by removing the Skype icon from the Mac OS menu bar. I am using a lot of messenger apps on my MacBook: Telegram, Signal, Slack, Upwork messages, sometimes Whatsapp, sometimes Viber, and Skype. They don't have an icon in the menu bar, but Skype does. And there isn't any option or setting to remove it. So today, we will smash that icon from our life! Welcome undercut. &lt;/p&gt;

&lt;p&gt;How is it possible to remove the Skype icon from the menu bar? The answer is editing Skype source files. I should say this is not my invention. I have found this way on &lt;a href="https://apple.stackexchange.com/questions/380075/how-to-remove-skype-menu-bar-icon-from-macos" rel="noreferrer noopener"&gt;StackExchange&lt;/a&gt;. I have used the following command for a long time, but after maybe March 2022 updates, it &lt;strong&gt;stopped&lt;/strong&gt; working. &lt;/p&gt;

&lt;pre&gt;LC_ALL=C sed -i '' -e "s/_initTray(){.\{7\}/_initTray(){return;/" -e "s/initTrayMenu(){.\{7\}/initTrayMenu(){return;/" /Applications/Skype.app/Contents/Resources/app.asar&lt;/pre&gt;

&lt;p&gt;Let me explain what the command does. It opens Skype files and replaces some code. Fortunately, Skype was written using some HTML/JS/CSS framework, and I guess it's Electron. So, you can easily open app files and edit JS code to change the app's behavior. &lt;/p&gt;

&lt;p&gt;Let's edit the files manually to the disabled annoying Skype icon. &lt;/p&gt;

&lt;h2&gt;HEX editor&lt;/h2&gt;

&lt;p&gt;First, you need to have some HEX editor. I am using Hex Fiend, and you can download it from &lt;a href="https://hexfiend.com" rel="noreferrer noopener"&gt;the official web page&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;Skype updates&lt;/h2&gt;

&lt;p&gt;You got an editor, then the next step you should update Skype to the latest version. Each update will remove our code changes. So after the update, you have to edit Skype files to remove the icon. Maybe later, I'll make some automation for that, but for now, it's okay for me to edit source code sometimes. &lt;/p&gt;

&lt;p&gt;Also, I recommend keeping the downloaded installer, or you can back up the original files. It could help to restore Skype if you broke something. &lt;/p&gt;

&lt;h2&gt;Close Skype&lt;/h2&gt;

&lt;p&gt;Some guys on StackExchange suggest running Skype at least once before editing source code files. Also, this is a good idea to check does Skype works before you start. Anyway, close Skype before editing it.&lt;/p&gt;

&lt;h2&gt;Edit files to remove the Skype icon&lt;/h2&gt;

&lt;p&gt;Run an editor and open file &lt;em&gt;/Applications/Skype.app/Contents/Resources/app.asar&lt;/em&gt;. You will see something like the following image.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;UPDATE 09.04.2023&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Skype added multiple files for Intel or Apple Silicon processors systems. Approximately from version 8.95.0.408 you should edit file &lt;em&gt;/Applications/Skype.app/Contents/Resources/app-x64.asar&lt;/em&gt; or &lt;em&gt;/Applications/Skype.app/Contents/Resources/app-arm64.asar&lt;/em&gt; depending on your CPU type. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--KgxrvxgV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2022/05/image-1024x304.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KgxrvxgV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jakeroid.com/wp-content/uploads/2022/05/image-1024x304.png" alt="" width="800" height="238"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now open Find &amp;amp; Replace menu and find the code:&lt;/p&gt;

&lt;pre&gt;_initTray(){this._tray=new&lt;/pre&gt;

&lt;p&gt;Replace it with the following one:&lt;/p&gt;

&lt;pre&gt;_initTray(){return;ray=new&lt;/pre&gt;

&lt;p&gt;After don't forget to save the file. Voila! We successfully remove the Skype icon from the menu bar.&lt;/p&gt;

&lt;h2&gt;Explanation&lt;/h2&gt;

&lt;p&gt;This code is the beginning of the _initTray functions, which is responsible for creating an icon in the menu bar, handling clicks on it, etc. To disable the icon, we need to change the body of the _initTray function. &lt;/p&gt;

&lt;p&gt;The best way to disable executing code is to put a return statement in the first line of the function. However, if you add return in the first line, it breaks Skype. I guess that happens because the file length changed in case of adding new code. The solution is to replace the current code with a new one with the same length. &lt;/p&gt;

&lt;p&gt;I hope this article was helpful to you. Ask questions in the comments section below if something is unclear for you. &lt;/p&gt;

&lt;p&gt;By the way, I posted &lt;a href="https://jakeroid.com/blog/port-5000-is-already-in-use-in-macos-monterey/"&gt;why port 5000 is already in use on Mac OS&lt;/a&gt; some time ago. Maybe you are interested.&lt;/p&gt;

</description>
      <category>macos</category>
      <category>skype</category>
      <category>menubar</category>
    </item>
  </channel>
</rss>
