<?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: Yehuda Neufeld</title>
    <description>The latest articles on DEV Community by Yehuda Neufeld (@yiddishekop).</description>
    <link>https://dev.to/yiddishekop</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%2F154617%2F24ff534e-8f6b-444c-a5db-297c5d752eab.png</url>
      <title>DEV Community: Yehuda Neufeld</title>
      <link>https://dev.to/yiddishekop</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/yiddishekop"/>
    <language>en</language>
    <item>
      <title>Setting up a fresh server for Continuous Deployment with Git</title>
      <dc:creator>Yehuda Neufeld</dc:creator>
      <pubDate>Sun, 05 Jul 2020 08:32:08 +0000</pubDate>
      <link>https://dev.to/yiddishekop/setting-up-a-fresh-server-for-continuous-deployment-with-git-4ed9</link>
      <guid>https://dev.to/yiddishekop/setting-up-a-fresh-server-for-continuous-deployment-with-git-4ed9</guid>
      <description>&lt;p&gt;We all want to be able to focus on writing code, without wasting time when deploying changes to production.&lt;/p&gt;

&lt;p&gt;But it's not that simple. There are several operations our code needs to go through going from development to production (I'm referring to a Laravel Application, but it will be similar for most web applications):&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Push our new code to the server.&lt;/li&gt;
&lt;li&gt;Update our Javascript &amp;amp; PHP dependencies.&lt;/li&gt;
&lt;li&gt;Compile our Javascript and CSS.&lt;/li&gt;
&lt;li&gt;Finally, we need to migrate the production database.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Doing all these operations manually before every deployment quickly gets too time consuming. Besides, it's a repetitive task that should be automated...&lt;/p&gt;

&lt;p&gt;So for quite a while I researched &amp;amp; tried to find the best way to do this. At first my solution was using GitHub webhooks, but that solution had it's problems.&lt;/p&gt;

&lt;p&gt;Last week, I finally found the perfect solution, which lets me deploy the code to production with just &lt;strong&gt;2 keystrokes&lt;/strong&gt;: &lt;code&gt;gp&lt;/code&gt; 😎.&lt;/p&gt;

&lt;h2&gt;
  
  
  How it works
&lt;/h2&gt;

&lt;p&gt;We're going to use Git (version control software). Git has several hooks that it can call after different stages automatically. We'll use the &lt;strong&gt;post-receive&lt;/strong&gt; hook which is called after your repository has received pushed code.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A &lt;strong&gt;Hook&lt;/strong&gt; is a program you can place in a hooks directory to trigger actions at certain points in git’s execution.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In this script we'll do all the above operations.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Login to your remote server
&lt;/h3&gt;

&lt;p&gt;Open your terminal and login to your server using the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh &amp;lt;your_user&amp;gt;@&amp;lt;server_ip_address&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Make sure that you have Git installed on the server.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Create a folder for your code
&lt;/h3&gt;

&lt;p&gt;The source code for your application needs to be put somewhere. By convention, code goes inside the &lt;code&gt;/var/www&lt;/code&gt; directory. Navigate there using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; /var/www
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now, create a new folder to put the source code. For this tutorial, it will be called &lt;code&gt;app-folder&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;app-folder
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now let's remember the full path to our app-folder is &lt;code&gt;/var/www/app-folder/&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Initialize a git repository in your home folder
&lt;/h3&gt;

&lt;p&gt;We'll create a git repository in our users' home folder. Let's create a &lt;code&gt;repo&lt;/code&gt; folder to hold all our future repos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; ~/repo/my-app.git
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now, we'll navigate into our repo folder, and initialize a bare git repo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; ~/repo/my-app.git
git init &lt;span class="nt"&gt;--bare&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Congratulations, we now have the git repo ready for use!&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Create hook
&lt;/h3&gt;

&lt;p&gt;After initializing the git repository, new folders should appear inside &lt;code&gt;~/repo/my-app.git/&lt;/code&gt;. Navigate to the &lt;code&gt;hooks&lt;/code&gt; directory, and create a new file called &lt;code&gt;post-receive&lt;/code&gt; using your preferred text editor.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;hooks
vim post-receive
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Make sure to spell &lt;code&gt;post-receive&lt;/code&gt; right, because I misspelled it - &lt;code&gt;post-recieve&lt;/code&gt;, and it took me a while to figure out why it wasn't working 😃...&lt;/p&gt;

&lt;p&gt;Now for the serious part: we're going to write the program to deploy our application.&lt;/p&gt;

&lt;p&gt;This is what my &lt;code&gt;post-receive&lt;/code&gt; script ended up looking like (as mentioned above - this is for a Laravel app):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;

&lt;span class="nv"&gt;TARGET&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/var/www/app-folder"&lt;/span&gt;
&lt;span class="nv"&gt;GIT_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/home/&amp;lt;username&amp;gt;/repo/my-app.git"&lt;/span&gt;
&lt;span class="nv"&gt;BRANCH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"master"&lt;/span&gt;

&lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="nb"&gt;read &lt;/span&gt;oldrev newrev ref
&lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="c"&gt;# only checking out the master (or whatever branch you would like to deploy)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$ref&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"refs/heads/&lt;/span&gt;&lt;span class="nv"&gt;$BRANCH&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;then

                &lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="nv"&gt;$TARGET&lt;/span&gt;
                &lt;span class="nb"&gt;pwd

                echo&lt;/span&gt; &lt;span class="s2"&gt;"activating maintenance mode"&lt;/span&gt;
                php artisan down

                &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Ref &lt;/span&gt;&lt;span class="nv"&gt;$ref&lt;/span&gt;&lt;span class="s2"&gt; received. Deploying &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BRANCH&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; branch to production..."&lt;/span&gt;
                git &lt;span class="nt"&gt;--work-tree&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$TARGET&lt;/span&gt; &lt;span class="nt"&gt;--git-dir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$GIT_DIR&lt;/span&gt; checkout &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="nv"&gt;$BRANCH&lt;/span&gt;

                &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Running NPM build command"&lt;/span&gt;
                npm &lt;span class="nb"&gt;install
                &lt;/span&gt;npm run build

                &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"running composer install"&lt;/span&gt;
                /usr/local/bin/composer.phar &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--no-interaction&lt;/span&gt; &lt;span class="nt"&gt;--no-dev&lt;/span&gt; &lt;span class="nt"&gt;--prefer-dist&lt;/span&gt;

                &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"running migrations"&lt;/span&gt;
                php artisan migrate &lt;span class="nt"&gt;--force&lt;/span&gt;

                &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"going back live..."&lt;/span&gt;
                php artisan up

        &lt;span class="k"&gt;else
                &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Ref &lt;/span&gt;&lt;span class="nv"&gt;$ref&lt;/span&gt;&lt;span class="s2"&gt; received. Doing nothing: only the &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BRANCH&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; branch may be deployed on this server."&lt;/span&gt;
        &lt;span class="k"&gt;fi
done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The code is pretty self explanatory, as it is &lt;code&gt;echo&lt;/code&gt;ing out what it's doing.&lt;/p&gt;

&lt;p&gt;Save the file, and make it executable by running this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;chmod&lt;/span&gt; +x post-receive
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The work on your server is done.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Push local code to the server
&lt;/h3&gt;

&lt;p&gt;Back on our local machine, navigate to your project folder, and initialize a git repo (if it isn't already). Then we need to add our remote server as a remote:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;git remote add &amp;lt;name-of-remote&amp;gt; ssh://&amp;lt;username&amp;gt;@&amp;lt;server_ip_address&amp;gt;/&amp;lt;path_to_git_directory&amp;gt;

&lt;span class="c"&gt;# For our example:&lt;/span&gt;
git remote add azure ssh://&amp;lt;username&amp;gt;@&amp;lt;server_ip_address&amp;gt;/home/&amp;lt;username&amp;gt;/repo/my-app.git
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;I called my remote &lt;code&gt;azure&lt;/code&gt;, as it's an Azure server.&lt;/p&gt;

&lt;p&gt;Now, whenever you want to deploy your code, just run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;git push &amp;lt;name-of-remote&amp;gt; &amp;lt;name-of-branch&amp;gt;

&lt;span class="c"&gt;# we can omit the branch name - it will default to master&lt;/span&gt;
git push azure
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;One second, this is more than 2 keystrokes!&lt;/p&gt;

&lt;p&gt;Oh, you're right... to achieve that make your remote the default upstream, by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;git push &lt;span class="nt"&gt;--set-upstream&lt;/span&gt; azure 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Then you can deploy to production by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;gp
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;It works, because &lt;code&gt;gp&lt;/code&gt; is an alias to &lt;code&gt;git push&lt;/code&gt; (if it isn't, you can add this alias yourself).&lt;/p&gt;

&lt;p&gt;If you don't want to set the remote-server as the default upstream (you may want GitHub to be the default), then you can leave the default upstream to be &lt;code&gt;origin&lt;/code&gt; (GitHub) and deploy to your server by running &lt;code&gt;gp azure&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You even get all the output right into your local terminal! Here is the deployment in progress:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5L8Q6GCE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/9hbjlamj9upo96zin1pa.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5L8Q6GCE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/9hbjlamj9upo96zin1pa.gif" alt="Sit back and enjoy..."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Summary
&lt;/h3&gt;

&lt;p&gt;I'm writing this for my future reference, as this is so easy to setup, and makes deploying to production a breeze.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sidenote
&lt;/h3&gt;

&lt;p&gt;If you get errors relating to permissions, and to avoid having to use &lt;code&gt;sudo&lt;/code&gt; in the web directory on your server, here is a solution with security in mind:&lt;/p&gt;

&lt;p&gt;Add yourself to the &lt;code&gt;www-data&lt;/code&gt; user group, and set the &lt;strong&gt;setgid&lt;/strong&gt; bit on the &lt;code&gt;/var/www&lt;/code&gt; directory such that all newly created files inherit this group as well.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# add yourself to the www-data group&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;gpasswd &lt;span class="nt"&gt;-a&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$USER&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; www-data

&lt;span class="c"&gt;# apply the ownership to the /var/www folder&lt;/span&gt;
&lt;span class="nb"&gt;sudo chown&lt;/span&gt; &lt;span class="nt"&gt;-R&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$USER&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;:www-data /var/www

&lt;span class="c"&gt;# Correct previously created files (assuming you to be the only user of /var/www):&lt;/span&gt;
find /var/www &lt;span class="nt"&gt;-type&lt;/span&gt; f &lt;span class="nt"&gt;-exec&lt;/span&gt; &lt;span class="nb"&gt;chmod &lt;/span&gt;0660 &lt;span class="o"&gt;{}&lt;/span&gt; &lt;span class="se"&gt;\;&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;find /var/www &lt;span class="nt"&gt;-type&lt;/span&gt; d &lt;span class="nt"&gt;-exec&lt;/span&gt; &lt;span class="nb"&gt;chmod &lt;/span&gt;2770 &lt;span class="o"&gt;{}&lt;/span&gt; &lt;span class="se"&gt;\;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;a href="https://askubuntu.com/questions/46331/how-to-avoid-using-sudo-when-working-in-var-www"&gt;source&lt;/a&gt;&lt;/p&gt;

</description>
      <category>git</category>
      <category>cd</category>
    </item>
    <item>
      <title>Wrapping my Brain around Recursion</title>
      <dc:creator>Yehuda Neufeld</dc:creator>
      <pubDate>Fri, 05 Jun 2020 08:39:48 +0000</pubDate>
      <link>https://dev.to/yiddishekop/wrapping-my-brain-around-recursion-1okn</link>
      <guid>https://dev.to/yiddishekop/wrapping-my-brain-around-recursion-1okn</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;P.S. This is my first post published on dev.to. If you enjoy this article, check out my &lt;a href="https://blog.yiddishe-kop.com/"&gt;personal blog&lt;/a&gt; for more stuff! 😃&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;When I was at the start of my programming career, whenever I saw something about recursion, I would run away as fast as I could — 😲 RECURSION 😲 — what could be scarier than this complicated concept?&lt;/p&gt;

&lt;p&gt;One day (about 2 years into my programming journey), I was coding along, when suddenly an unexpected thought popped up in my brain: wait! &lt;strong&gt;recursion&lt;/strong&gt; is the perfect way to solve this problem/challenge!&lt;/p&gt;

&lt;h2&gt;
  
  
  The Challenge
&lt;/h2&gt;

&lt;p&gt;I was building a desktop client to edit wikipedia pages (or any wiki powered site) offline. The way it works is like so: I present the user with a list of categories that exist on the site. The list is a tree, where every category can have subcategories, and subcategories have subcategories, and so forth. The category tree is many levels deep, and every branch ends with a list of pages in the category.&lt;/p&gt;

&lt;p&gt;The user would then select some categories, and press a button to save them all to his computer for offline use.&lt;/p&gt;

&lt;p&gt;So the first thing we need to do — is to build up the category tree &amp;amp; store it in a json file for the program to use.&lt;/p&gt;

&lt;p&gt;I found a Node.js Wiki API library called &lt;a href="https://github.com/macbre/nodemw"&gt;&lt;strong&gt;&lt;code&gt;nodemw&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt;, which exposes lots of nice methods to interact with the API.&lt;/p&gt;

&lt;p&gt;We can use this method the library provides us:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;getSubcategories&lt;/code&gt;: this method takes the category title as a parameter, and returns an array of all subcategories &amp;amp; pages that are members of this category.
Unfortunately, the wiki API doesn't have an endpoint for retreiving all nested categories at once, we can only get 1 level of children at once. But we need to get all the subcategories however deep they might go...&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Brainstorm
&lt;/h2&gt;

&lt;p&gt;This is a complex challenge, so let's try to break it down into small parts:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Get subcategories of the root category.&lt;/li&gt;
&lt;li&gt;For each item in the returned array: Each item could be either a subcategory, or a page. So we need to check:

&lt;ul&gt;
&lt;li&gt;If it is a page, do nothing.&lt;/li&gt;
&lt;li&gt;But if it's a subcategory — then we need to get &lt;strong&gt;its&lt;/strong&gt; subcategories — in other words: &lt;strong&gt;go back to step 1!&lt;/strong&gt; 💡💡💡 (when you arrive here the 2nd time — go back to 1 again, forever 😲)&lt;/li&gt;
&lt;li&gt;But that's not all: after we get its subcategories, we need to assign it to its parent category, because we're building a tree, right?
Here is where it clicked in my head: &lt;strong&gt;This is recursion!!!&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We need to repeat a task over &amp;amp; over again for an unknown amount of times, until a certain condition is met. If we don't put a solid condition in place - the computer might repeat over the task infinitely — until the computer crashes, or until there is a stack-overflow 🤯 (between ~10,000 - ~30,000 levels).&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation
&lt;/h2&gt;

&lt;p&gt;Once we understand the concept - we can get to write the code to do the task 😎. And oh is this part complicated... especially when we need to fetch data over the network in each iteration of the loop...&lt;/p&gt;

&lt;p&gt;I spent 2 days overheating my brain writing this function... There were countless sub-challenges that I had to break through in the process. But first let's have a look at the final working code 👀:&lt;/p&gt;

&lt;p&gt;I added comments in the code, instead of explaining every line separately.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;rebuildCategoryTree&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="c1"&gt;// 1. Get children of root category&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rootCats&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$wiki&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getSubcategories&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;עץ קטגוריות ראשי&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// 2. Here we define the recursive function&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getChildren&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;cats&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// do some important checks &lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cats&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;cat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;subcat&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;cat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subcats&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;diving deeper...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cats&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cat&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;cats&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;subcat&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;subcats&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
            &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;cachedCat&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cachedCats&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;cat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cachedCat&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="c1"&gt;// we already fetched these from the server&lt;/span&gt;
              &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cachedCat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;visited&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="c1"&gt;// STOP! we have an infinite loop!&lt;/span&gt;
                &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;TERMINATING INFINITE LOOP&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;cachedCat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subcats&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
              &lt;span class="p"&gt;}&lt;/span&gt;
              &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;...Using cache&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
              &lt;span class="c1"&gt;// my solution to overcome infinite loops (circular relations)&lt;/span&gt;
              &lt;span class="nx"&gt;cachedCat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;visited&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
              &lt;span class="nx"&gt;subcats&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cachedCat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subcats&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// use from cache&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;...Fetching fresh&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
              &lt;span class="c1"&gt;// THE ACTUAL WORK - fetch category members&lt;/span&gt;
              &lt;span class="nx"&gt;subcats&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$wiki&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getSubcategories&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
              &lt;span class="c1"&gt;// add to cache&lt;/span&gt;
              &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cachedCats&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;cat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;cat&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="nx"&gt;subcats&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="p"&gt;};&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="c1"&gt;// calls this function itself - to recursively fetch children&lt;/span&gt;
            &lt;span class="nx"&gt;cat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subcats&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;getChildren&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;subcats&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
          &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;coming out...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cats&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;cats&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="c1"&gt;// 3. Start working!&lt;/span&gt;
    &lt;span class="c1"&gt;// this tiggers the recursion&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;catTree&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;getChildren&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rootCats&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// 4. Save the resulting tree as a json file&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;writeFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;catTree&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h1&gt;
  
  
  Sub-Challenges
&lt;/h1&gt;

&lt;p&gt;Here are some of the challenges that arose while writing the recursive function:&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;1. Circular Relations&lt;/strong&gt; (infinite loops):
&lt;/h2&gt;

&lt;p&gt;I was testing the code, and it seemed to be working, but it was taking forever... Although the wiki site I was working with has 83,691 pages, it still seemed to be taking too long.&lt;/p&gt;

&lt;p&gt;After debugging a while — I caught the culprit. Not a bug in my code, but on the wiki site. They had a few circular relationships (where &lt;strong&gt;category A&lt;/strong&gt; had &lt;strong&gt;category B&lt;/strong&gt; as a child, which had &lt;strong&gt;category A&lt;/strong&gt; as a child...) which caused an infinite loop 🤯.&lt;/p&gt;

&lt;p&gt;At first they fixed it on the wiki site, but I still couldn't guarantee that such loops don't exist in other places in the tree. So I had to come up with a solution to detect such loops, and get out of them in time...&lt;/p&gt;

&lt;p&gt;The solution presented itself from a different thing I wanted to fix: not to lose all progress if the function stops unexpectedly (by a network error etc.). For that I started saving every &lt;code&gt;getSubcategories&lt;/code&gt; result which came back from the server to an object I called &lt;code&gt;cachedCats&lt;/code&gt; (which &lt;strong&gt;caches&lt;/strong&gt; the results from the network, so if it gets interrupted &amp;amp; we need to start again - we shouldn't need to start from scratch).&lt;/p&gt;

&lt;p&gt;Once I had that, I could use that object to know if we already visited that branch in the tree. Albeit not the first time, because we might be after an unexpected error, so the 1st time we encounter something in the cache we record that visit (by adding &lt;code&gt;visited: true&lt;/code&gt;), then if we encounter the cache with &lt;code&gt;visited == true&lt;/code&gt; we know that we've caught an infinite loop! So we log a scary message and return early:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cachedCat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;visited&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// STOP! we have an infinite loop!&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;TERMINATING INFINITE LOOP&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;cachedCat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subcats&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;2. Asynchronous Operations&lt;/strong&gt;:
&lt;/h2&gt;

&lt;p&gt;As we're fetching data from a remote server - which take time - there's more complexity.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;nodemw&lt;/code&gt; library was written quite a few years ago, so all methods were written in the old callback style, where each method takes a callback function as a parameter, which gets called after the data comes back from the server. The callback function in turn gets 2 parameters: &lt;code&gt;error, data&lt;/code&gt;, so we first need to check for the error, only if not present we can assume that we got the data.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// BEFORE:&lt;/span&gt;
&lt;span class="c1"&gt;// callback based function&lt;/span&gt;
&lt;span class="nx"&gt;getChildren&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cats&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="c1"&gt;// first handle the err (if it exists)&lt;/span&gt;
   &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
     &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;// Now we can use the categories...&lt;/span&gt;
    &lt;span class="nx"&gt;cat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subcats&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cats&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This was nearly impossible to use in a recursive function, because every callback will get called separately at a different time... (probably possible, but makes it much more complicated).&lt;/p&gt;

&lt;p&gt;At first I thought I'll fork the &lt;code&gt;nodemw&lt;/code&gt; repo, and update it to use Promise based async functions. I actually &lt;a href="https://github.com/Yiddishe-Kop/nodemw"&gt;forked the repo&lt;/a&gt;, but the work to rewrite the whole library in Promises is easier said than done...&lt;/p&gt;

&lt;p&gt;Luckily, I discovered that Node's &lt;code&gt;utils&lt;/code&gt; module has a method to do exactly that! 😃 Just pass an old style callback function to &lt;code&gt;utils.promisify&lt;/code&gt;, and you get back a modern Promise based function!&lt;/p&gt;

&lt;p&gt;So I wrote a thin &lt;a href="https://github.com/Yiddishe-Kop/jewishbooks-wiki/blob/master/src/renderer/helpers/wiki.js"&gt;wrapper class&lt;/a&gt; around the &lt;code&gt;nodemw&lt;/code&gt; library that converts the few methods I needed to Promise based functions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;wikiAPI&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="cm"&gt;/**
   * Login the user to the wiki
   * @param {string} username
   * @param {string} password
   */&lt;/span&gt;
  &lt;span class="nx"&gt;logIn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;util&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;promisify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Bot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;logIn&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Bot&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="cm"&gt;/**
   * Edit a page on the wiki
   * @param {string} title - Page title.
   * @param {string} content - Page content
   * @param {string} summary - Summary message
   * @param {boolean} minor - If it's a minor edit
   */&lt;/span&gt;
  &lt;span class="nx"&gt;edit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;util&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;promisify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Bot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;edit&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Bot&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;//...&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;(I added &lt;code&gt;jsdoc&lt;/code&gt; documentation, to enhance vsCode's intellisense)&lt;/p&gt;

&lt;p&gt;Now I could use &lt;code&gt;async&lt;/code&gt; &lt;code&gt;await&lt;/code&gt; , which made things mush easier &amp;amp; cleaner. 😀&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// AFTER:&lt;/span&gt;
&lt;span class="c1"&gt;// Aaaaahhhhh.... much better!&lt;/span&gt;
&lt;span class="nx"&gt;cat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subcats&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;getChildren&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;subcats&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



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

&lt;p&gt;It was really challenging to get everything working perfectly, but it's so worth it to tackle these types of challenges head on — you learn so much &amp;amp; get a deeper understanding of Javascript concepts.&lt;/p&gt;

&lt;p&gt;In the end, it's amazing to watch your function do its job, recursively building a massive tree, doing a task thousands of times, deciding by itself when to go deeper, and when to come back up a level...&lt;/p&gt;

&lt;p&gt;That's the power code!&lt;/p&gt;

</description>
      <category>recursion</category>
      <category>javascript</category>
      <category>wiki</category>
      <category>nodetree</category>
    </item>
  </channel>
</rss>
