<?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: Dico</title>
    <description>The latest articles on DEV Community by Dico (@sumurai8).</description>
    <link>https://dev.to/sumurai8</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%2F448770%2F5d875926-02ca-4329-ae5a-889fad7eb644.png</url>
      <title>DEV Community: Dico</title>
      <link>https://dev.to/sumurai8</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sumurai8"/>
    <language>en</language>
    <item>
      <title>Building a Vue 3 native Android app with Capacitor on WSL2 (Ubuntu 20.04)</title>
      <dc:creator>Dico</dc:creator>
      <pubDate>Sun, 14 Nov 2021 18:22:00 +0000</pubDate>
      <link>https://dev.to/sumurai8/building-a-vue-3-native-android-app-with-capacitor-on-wsl2-ubuntu-2004-3bff</link>
      <guid>https://dev.to/sumurai8/building-a-vue-3-native-android-app-with-capacitor-on-wsl2-ubuntu-2004-3bff</guid>
      <description>&lt;p&gt;Capacitor is the spiritual successor to Cordova and Phonegap. Unfortunately they took this literally and left out actual instructions on how to compile the app to a native android app, because who needs those... At time of writing, &lt;a href="https://v3.vuejs.org/guide/mobile.html"&gt;Vue recommends either Capacitor or NativeScript&lt;/a&gt;, but NativeScript requires prior knowledge about native apps I do not have. If you can work with that, &lt;a href="https://docs.nativescript.org/environment-setup.html#linux-android"&gt;their installation guide&lt;/a&gt; is a lot clearer than Capacitor's is, and possibly a better fit for you.&lt;/p&gt;

&lt;p&gt;Credit to the following resources for providing snippets to get this guide working: &lt;a href="https://gist.github.com/steveclarke/d988d89e8cdf51a8a5766d69ecb07e7b"&gt;Install Android SDK CLI Ubuntu 20.04 WSL2 (Work in Progress)&lt;/a&gt; (by steveclarke), &lt;a href="https://docs.nativescript.org/environment-setup.html#linux-android"&gt;the documentation of NativeScript&lt;/a&gt; and &lt;a href="https://gist.github.com/bergmannjg/461958db03c6ae41a66d264ae6504ade"&gt;a guide to building a react native app in WSL2&lt;/a&gt; by bergmannjg.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites and goals
&lt;/h2&gt;

&lt;p&gt;At the end of this blog you will be able to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Set up a Vue 3 app with Capacitor&lt;/li&gt;
&lt;li&gt;Be able to run a test build on a real device from WSL2&lt;/li&gt;
&lt;li&gt;Be able to build a version of your app that can be deployed to the Play Store&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Notable things that I will &lt;strong&gt;not&lt;/strong&gt; be touching upon are how to make this work with an emulator, and how to debug the app on a real device.&lt;/p&gt;

&lt;p&gt;I expect you have already installed node (I have 16.13.0) and npm (I have 8.1.0). If not, go do that using your favourite method. I also assume you use bash (you can check with &lt;code&gt;ps -p $$&lt;/code&gt;). If you do not use bash, there may be slight differences in syntax. I also expect you to have an android device you can connect to via usb, and where you already have enabled the USB debugger.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a new Vue app and installing Capacitor
&lt;/h2&gt;

&lt;p&gt;Added here for completeness sake. Chances are you already pulled this from some other guide.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;vue create your-app
&lt;span class="nb"&gt;cd &lt;/span&gt;your-app
npm &lt;span class="nb"&gt;install&lt;/span&gt; @capacitor/core @capacitor/cli
npm &lt;span class="nb"&gt;install&lt;/span&gt; @capacitor/android
npx cap init &lt;span class="s2"&gt;"My beautiful app"&lt;/span&gt; com.something.my_beautiful_app &lt;span class="nt"&gt;--web-dir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;dist
npx cap add android
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Installing the Android SDK
&lt;/h2&gt;

&lt;p&gt;After these initial steps the Capacitor documentation stops. You can run an debug build via the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx cap run android
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will likely yield the error&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[error] native-run failed with error

        ERR_SDK_NOT_FOUND: No valid Android SDK root found.

        More details for this error may be available online:
        https://github.com/ionic-team/native-run/wiki/Android-Errors
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Command line tools
&lt;/h3&gt;

&lt;p&gt;We will tackle this problem one step at a time. First we will install the Android SDK command line tools. Obtain the most up-to-date download link for the command line tools only from &lt;a href="https://developer.android.com/studio#downloads"&gt;the official android studio download page&lt;/a&gt;. Alternatively just install the version I used at time of writing (November 2021).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Install unzip if it is not already installed&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;unzip

&lt;span class="c"&gt;# We will install this in the home directory&lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="nv"&gt;$HOME&lt;/span&gt;
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; Android/cmdline-tools
wget https://dl.google.com/android/repository/commandlinetools-linux-7302050_latest.zip
unzip commandlinetools-linux-7302050_latest.zip &lt;span class="nt"&gt;-d&lt;/span&gt; Android/cmdline-tools
&lt;span class="c"&gt;# This location is important, because otherwise you will get an error that the SDK root could not be determined&lt;/span&gt;
&lt;span class="nb"&gt;mv &lt;/span&gt;Android/cmdline-tools/cmdline-tools Android/cmdline-tools/latest

&lt;span class="c"&gt;# And clean up after ourselves&lt;/span&gt;
&lt;span class="nb"&gt;rm &lt;/span&gt;commandlinetools-linux-7302050_latest.zip
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While we have the command line tools, other tools like Capacitor relying on it do not know where to find it. For this we need to set the &lt;code&gt;ANDROID_HOME&lt;/code&gt; environment variable. We also need to update our PATH environment variable so the command line knows where to find the sdkmanager for example.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# These changes last until the end of the current bash session. We will add a more permanent solution later&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;ANDROID_HOME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;/Android
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$ANDROID_HOME&lt;/span&gt;&lt;span class="s2"&gt;/cmdline-tools/latest:&lt;/span&gt;&lt;span class="nv"&gt;$ANDROID_HOME&lt;/span&gt;&lt;span class="s2"&gt;/cmdline-tools/latest/bin:&lt;/span&gt;&lt;span class="nv"&gt;$ANDROID_HOME&lt;/span&gt;&lt;span class="s2"&gt;/platform-tools:&lt;/span&gt;&lt;span class="nv"&gt;$ANDROID_HOME&lt;/span&gt;&lt;span class="s2"&gt;/emulator:&lt;/span&gt;&lt;span class="nv"&gt;$ANDROID_HOME&lt;/span&gt;&lt;span class="s2"&gt;/tools:&lt;/span&gt;&lt;span class="nv"&gt;$ANDROID_HOME&lt;/span&gt;&lt;span class="s2"&gt;/tools/bin:&lt;/span&gt;&lt;span class="nv"&gt;$PATH&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Installing some build tools and platforms
&lt;/h3&gt;

&lt;p&gt;If you would to run the emulator now (&lt;code&gt;npx cap run android&lt;/code&gt;), you'll notice it at least doesn't complain that it can't find an Android SDK root. It still doesn't work though. To fix this we will run the sdkmanager with some commands. If the sdkmanager complains with an error like &lt;code&gt;Error: Could not determine SDK root&lt;/code&gt;. make sure that it is in the correct location. In my version it needs to be in a folder &lt;code&gt;cmdline-tools/latest/bin&lt;/code&gt; to automatically detect where the root is.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Make sure we have the latest information&lt;/span&gt;
sdkmanager &lt;span class="nt"&gt;--update&lt;/span&gt;

&lt;span class="c"&gt;# We are installing version 31. To figure out what options *you* have, see below&lt;/span&gt;
&lt;span class="c"&gt;# You'll have to accept licenses by pressing y. Ignore the clause where you sell your soul. That's normal.&lt;/span&gt;
sdkmanager &lt;span class="s2"&gt;"build-tools;31.0.0"&lt;/span&gt; &lt;span class="s2"&gt;"platform-tools"&lt;/span&gt; &lt;span class="s2"&gt;"platforms;android-31"&lt;/span&gt; &lt;span class="s2"&gt;"tools"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want to find out what other platforms you can use, you can list the options with &lt;code&gt;sdkmanager --list | grep tools&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Last but not least you need to accept any remaining licenses that did not pop up during the initial install.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;sdkmanager &lt;span class="nt"&gt;--licenses&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Making our changes permanent
&lt;/h3&gt;

&lt;p&gt;If all of the above went as expected, we can make our changes to our environment variables more permanent. Otherwise figure out what you needed to change, and persist those changes instead.&lt;/p&gt;

&lt;p&gt;Edit the &lt;code&gt;~/.bashrc&lt;/code&gt; file with an editor of your choice, then add the following lines to the bottom.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;ANDROID_HOME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;/Android

&lt;span class="c"&gt;# Note: I am exporting these from back to front from our previous command&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$ANDROID_HOME&lt;/span&gt;/tools/bin:&lt;span class="nv"&gt;$PATH&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$ANDROID_HOME&lt;/span&gt;/tools:&lt;span class="nv"&gt;$PATH&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$ANDROID_HOME&lt;/span&gt;/emulator:&lt;span class="nv"&gt;$PATH&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$ANDROID_HOME&lt;/span&gt;/platform-tools:&lt;span class="nv"&gt;$PATH&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$ANDROID_HOME&lt;/span&gt;/cmdline-tools/latest/bin:&lt;span class="nv"&gt;$PATH&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$ANDROID_HOME&lt;/span&gt;/cmdline-tools/latest:&lt;span class="nv"&gt;$PATH&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will need to restart your shell for these changes to take effect. Go do that now. Exit out of the shell (ctrl+d) and start it again. Then test if your path and android home variable are set by echo-ing them in the shell.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# should show a line with something like /home/youruser/Android&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$ANDROID_HOME&lt;/span&gt;
&lt;span class="c"&gt;# should show a loooong line, with our Android paths at the start&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$PATH&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Other dependencies
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Gradle
&lt;/h3&gt;

&lt;p&gt;Last but not least we need to make sure that gradle is installed. Gradle is used to build our source code into a nice apk that can be loaded on a device.&lt;/p&gt;

&lt;p&gt;At time of writing the version of gradle in the Ubuntu repository is woefully out of date, so remove it if it is installed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt remove gradle
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then install it from a different repository&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;add-apt-repository ppa:cwchien/gradle
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get update
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;gradle

&lt;span class="c"&gt;# And check if it is higher than v4&lt;/span&gt;
gradle &lt;span class="nt"&gt;-v&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Java JDK
&lt;/h3&gt;

&lt;p&gt;You'll eventually also need the java jdk. You can check if one is already installed for you.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt list &lt;span class="nt"&gt;--installed&lt;/span&gt; | &lt;span class="nb"&gt;grep &lt;/span&gt;jdk
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The easiest way to install the latest working version for you is probably installing default-jdk-headless, which installed openjdk-11-jdk-headless for me.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;default-jdk-headless
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Zipalign
&lt;/h3&gt;

&lt;p&gt;To eventually be able to create a signed apk you can put in the Google Play Store you will need to have zipalign installed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;zipalign
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Apksigner
&lt;/h3&gt;

&lt;p&gt;Similar to zipalign, we will need the apksigner to... sign... the apk... that we want to put in the Google Play Store.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;apksigner
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Running a dev build
&lt;/h2&gt;

&lt;p&gt;With the android build tools installed, everything will work fine... right? Right?&lt;/p&gt;

&lt;p&gt;Unfortunately when running &lt;code&gt;npx cap run android&lt;/code&gt;, we quickly figure out that the emulator is not working. We get the following error.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[error] native-run failed with error

        ERR_UNSUITABLE_API_INSTALLATION: No suitable API installation found. Use --sdk-info to reveal missing packages
        and other issues.

        More details for this error may be available online:
        https://github.com/ionic-team/native-run/wiki/Android-Errors
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The proposed switch doesn't reveal anything, and the --verbose flag the link suggests doesn't do anything either. I have not been able to figure out how to get an emulator working on WSL2. You may be able to accomplish this by running adb on Windows instead by following &lt;a href="https://gist.github.com/bergmannjg/461958db03c6ae41a66d264ae6504ade#connect-to-android-virtual-device-in-windows"&gt;the instructions on bergmannjg's gist&lt;/a&gt; or an article by Adrien Pellegrini showing &lt;a href="https://pellea.medium.com/using-the-android-emulator-on-windows-10-with-wsl2-39c2bae30c49"&gt;how to use the Android emulator in Windows 10 with WSL2&lt;/a&gt;. What I did figure out is how to make the command deploy a test build to a connected device. Unfortunately this too takes some work.&lt;/p&gt;

&lt;h3&gt;
  
  
  Make usb devices visible to WSL
&lt;/h3&gt;

&lt;p&gt;The first road block to overcome is to make usb devices visible to WSL2. If you run lsusb in WSL, you will notice that there are no usb devices listed.&lt;/p&gt;

&lt;p&gt;To solve this problem we need to create a bridge service that sends usb data from Windows to WSL2. It's probably best to follow the instructions from the article that introduces it directly: &lt;a href="https://devblogs.microsoft.com/commandline/connecting-usb-devices-to-wsl/"&gt;Connecting USB devices to WSL&lt;/a&gt; by Ben McMorran. In short: install a service called usbipd-win on Windows, two libraries called linux-tools-5.4.0-77-generic and hwdata on WSL2 and finally add /usr/lib/linux-tools/5.4.0-77-generic to secure_path in the /etc/sudoers file. Finally restart the computer so the service starts.&lt;/p&gt;

&lt;h3&gt;
  
  
  Connecting a phone to WSL2
&lt;/h3&gt;

&lt;p&gt;This section largely follows what &lt;a href="https://github.com/dorssel/usbipd-win/issues/60#issuecomment-962121982"&gt;cjshearer commented on a github issue about adb&lt;/a&gt; and uses some information in the article linked in the previous paragraph. If anything is unclear, you may want to consult these posts.&lt;/p&gt;

&lt;p&gt;First, open Powershell on Windows as administrator. Then open a WSL2 command line window. This makes sure that Ubuntu is actually running. Next plug in your Android test device, and run the following command in Powershell.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;usbipd wsl list
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In my case there is a whole list of usb devices, but the one I want is marked as&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1-6    SAMSUNG Android ADB Interface, SAMSUNG Mobile USB Modem, ...  Not attached
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;1-6 is the bus id of my phone, so I will bridge it to WSL2 with the following command in Powershell&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;usbipd wsl attach &lt;span class="nt"&gt;--busid&lt;/span&gt; 1-6
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Enter your WSL2 sudo password.&lt;/p&gt;

&lt;p&gt;You should now see your device in WSL2 if you execute the lsusb command. Remember that you need to enable this bridge whenever you remove the usb cable from the device and put it back in. It will not remember to bridge the usb (and this is probably for the best).&lt;/p&gt;

&lt;h3&gt;
  
  
  Giving adb permissions to the phone
&lt;/h3&gt;

&lt;p&gt;When you now do the &lt;code&gt;adb devices&lt;/code&gt; command, you'll notice that it shows you a device number and something like&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;no permissions (missing udev rules? user is in the plugdev group); see [http://developer.android.com/tools/device.html]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So... we have to set up the udev rules for this device. Izzy does a very good job &lt;a href="https://android.stackexchange.com/a/144967"&gt;in their answer android.stackexchange.com&lt;/a&gt; explaining what to do, so I recommend just following that answer. In short, make note of the device id in the output of &lt;code&gt;lsusb&lt;/code&gt;, craft a line with it in a specific rule file, then restart udev and reload the udevadm service, and replug the device. The group you select for this device should be one you are in. Adb suggests &lt;code&gt;plugdev&lt;/code&gt; as te group name. You can check your own groups with the groups command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo service udev restart
sudo udevadm control --reload
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You may need to do this after every computer restart.&lt;/p&gt;

&lt;p&gt;You can now deploy your app for testing purposes to the connected device. Make sure that you authorize the computer on the phone. &lt;code&gt;adb devices&lt;/code&gt; should show you the device id followed by "device". If it shows unauthorized, you still need to authorize it on the phone. If it shows no permissions you may need to restart the services listed above, and you may need to replug your phone.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building for production
&lt;/h2&gt;

&lt;p&gt;Eventually you probably want to publish your app in the Google Play Store. To do this you will need to generate a signed apk. Since we don't have a GUI in WSL2, we will have to do this from the command line as well. Use the official documentation on &lt;a href="https://developer.android.com/studio/build/building-cmdline"&gt;building your app from the command line&lt;/a&gt; as a guideline.&lt;/p&gt;

&lt;h3&gt;
  
  
  Preparing a key to sign
&lt;/h3&gt;

&lt;p&gt;To sign an apk with a key, we first need... a key. This key needs to be constant between releases, so generate it once and make sure to save it to your repository. First, navigate to the android subfolder of your project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; /path/to/your/project/android
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then generate a key. We use the alias "release", since aliases can be enumerated anyway with the keystore's password so there is no value in making it obscure. Store the password of the keystore securely somewhere &lt;strong&gt;outside&lt;/strong&gt; the repository.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;keytool &lt;span class="nt"&gt;-genkey&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="nt"&gt;-keystore&lt;/span&gt; release.jks &lt;span class="nt"&gt;-keyalg&lt;/span&gt; RSA &lt;span class="nt"&gt;-keysize&lt;/span&gt; 2048 &lt;span class="nt"&gt;-validity&lt;/span&gt; 10000 &lt;span class="nt"&gt;-alias&lt;/span&gt; release
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Assemble and sign your build
&lt;/h3&gt;

&lt;p&gt;We first want to assemble an apk that is ready for release, but still needs to be signed. To do this, we just run gradle.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; /path/to/your/project/android
gradle assembleRelease
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your apk will be generated somewhere deep in the app/build folder. You can quickly get the path with &lt;code&gt;find . -type f -name '*.apk'&lt;/code&gt; or hope it is in &lt;code&gt;./app/build/outputs/apk/release/app-release-unsigned.apk&lt;/code&gt; like it is for me.&lt;/p&gt;

&lt;p&gt;If you run into problems with an out-of-date version of gradle, scroll up to Other dependencies &amp;gt; Gradle.&lt;/p&gt;

&lt;p&gt;Next we zipalign the entire thing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;zipalign &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; 4 ./app/build/outputs/apk/release/app-release-unsigned.apk ./app/build/outputs/apk/release/app-release-unsigned-aligned.apk
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally sign the apk. Use the password that you securely stored somewhere several paragraphs ago.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;apksigner sign &lt;span class="nt"&gt;--ks&lt;/span&gt; release.jks &lt;span class="nt"&gt;--out&lt;/span&gt; ./app/build/outputs/apk/release/app-release-signed.apk ./app/build/outputs/apk/release/app-release-unsigned-aligned.apk
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And finally verify that everything went well.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;apksigner verify ./app/build/outputs/apk/release/app-release-signed.apk
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally copy that file somewhere where you will be able to access it to put it in the Google Play Store.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>android</category>
      <category>mobile</category>
      <category>vue</category>
    </item>
    <item>
      <title>VIM cheat sheet for common actions</title>
      <dc:creator>Dico</dc:creator>
      <pubDate>Sat, 08 Aug 2020 20:48:19 +0000</pubDate>
      <link>https://dev.to/sumurai8/vim-cheat-sheet-for-common-actions-3ag7</link>
      <guid>https://dev.to/sumurai8/vim-cheat-sheet-for-common-actions-3ag7</guid>
      <description>&lt;p&gt;When editing files over ssh, I prefer to use VIM over editors like nano. While it is certainly easier to find the save button in nano, most other actions in nano are just clunky. And while I never really understood the obsession with home row navigation, since my brain is usually the limiting factor rather than how fast I can type or navigate through an editor, I do prefer how VIM just gets the job done.&lt;/p&gt;

&lt;p&gt;One thing I would have benefited from when learning to use this editor is just a cheat sheet with the most common actions you would want to do in an editor like VIM. So I made one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding VIM
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--sKyRgpTQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dico.duba.dev/wp-content/uploads/2020/08/image-1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--sKyRgpTQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dico.duba.dev/wp-content/uploads/2020/08/image-1.png" alt=""&gt;&lt;/a&gt;VIM over SSH. Annotated: (1) Cursor location, (2) Highlighted bracket matching bracket under cursor, (3) Filename, 18 lines, 288 characters, (4) line number 1, column 1&lt;/p&gt;

&lt;p&gt;When opening a file with VIM, you start in a sort-of command mode. You can navigate the file, but you can not edit. To enter edit-mode, press i or insert. If you press insert more than once, you toggle between insert-mode (add text under the cursor) and replace-mode (replace text under the cursor). To get back into command-mode, press Esc.&lt;/p&gt;

&lt;p&gt;If you are stuck, you can usually get out of whatever you just did by mashing Esc and sometimes typing : q Enter. When you are back in command mode, and there is no weird prompt anymore in the bottom you can return to edit mode via i or insert.&lt;/p&gt;

&lt;p&gt;When in command mode, pressing keys like :, / and ? will move the cursor to the bottom. These are the beginning of commands. If you don’t want to do a command, just mash Esc to get back to what you were doing.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--mYNhLI3Y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dico.duba.dev/wp-content/uploads/2020/08/image-2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mYNhLI3Y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dico.duba.dev/wp-content/uploads/2020/08/image-2.png" alt=""&gt;&lt;/a&gt;VIM over ssh with an arrow pointing at the bottom command line&lt;/p&gt;

&lt;h2&gt;
  
  
  Cheat sheet
&lt;/h2&gt;

&lt;p&gt;All of these commands happen in command mode (see above). Get in the habit of pressing Esc before doing any of these.&lt;/p&gt;

&lt;h3&gt;
  
  
  Critical commands
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
Esc Esc Esc: Get back into command mode&lt;/li&gt;
&lt;li&gt;
i or insert: Enter edit mode&lt;/li&gt;
&lt;li&gt;
: w enter: Save the current file&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:w new_file_name.ext&lt;/code&gt; enter: Save to a (new) file new_file_name.ext&lt;/li&gt;
&lt;li&gt;
: q enter: Quit VIM&lt;/li&gt;
&lt;li&gt;
: q ! enter: Force quit VIM (discarding changes)&lt;/li&gt;
&lt;li&gt;
: w q enter: Save changes and quit VIM&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s all you really need to get going. You can just navigate using the arrow keys and keys like home, end, page up and page down do exactly what you expect them to do.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cut / Copy / Paste
&lt;/h2&gt;

&lt;p&gt;VIM has it’s own “clipboard”. If you paste something that is &lt;strong&gt;not&lt;/strong&gt; copied through one of VIM’s commands, just enter insert mode and (if you are using ssh for example) press the right mouse button to paste your own clipboard.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
insert right mouse button: Paste from own clipboard (in ssh)&lt;/li&gt;
&lt;li&gt;
y y: Copy the current line&lt;/li&gt;
&lt;li&gt;
d d: Delete the current line (works like the cut action, as you can paste this line elsewhere)&lt;/li&gt;
&lt;li&gt;
p: Paste what you have copied or cut&lt;/li&gt;
&lt;li&gt;
v: Enter visual mode. In visual mode you select text between the character where you entered visual mode and where your cursor is now. If you press y you copy that entire area and if you press d you delete/cut that entire area. To exit out without doing anything, use Esc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--YCx3hINM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dico.duba.dev/wp-content/uploads/2020/08/image-3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--YCx3hINM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dico.duba.dev/wp-content/uploads/2020/08/image-3.png" alt=""&gt;&lt;/a&gt;VIM over ssh. Annotated: (1) Position where visual mode was activated with “v”, (2) current position of the cursor (e.g. reached by “down”, “down”, “end”), (3) the bottom bar shows that visual mode has been activated.&lt;/p&gt;

&lt;p&gt;When combined, you can do many things. For example&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
y y p: Duplicates the current line by copying the current line and pasting it immediately&lt;/li&gt;
&lt;li&gt;
d d p: Move the current line below the following line&lt;/li&gt;
&lt;li&gt;
v, some navigation, d to cut a section, then navigate to the new position and p to put it back in that position.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Undo / redo
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
u: Undo the last action (and you can keep pressing it to undo more)&lt;/li&gt;
&lt;li&gt;
ctrl + r: Redo whatever you did just undo&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Navigation
&lt;/h2&gt;

&lt;p&gt;In VIM you can search from the beginning of the file to the end of the file with / and from the end of the file to the beginning of the file with ?. This only affects the order of the search results you get.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
/ &lt;code&gt;your search term&lt;/code&gt; enter: Finds the first occurence of &lt;code&gt;your search term&lt;/code&gt; in the file&lt;/li&gt;
&lt;li&gt;
? &lt;code&gt;your search term&lt;/code&gt; enter: Finds the last occurence of &lt;code&gt;your search term&lt;/code&gt; in the file&lt;/li&gt;
&lt;li&gt;
n: When searching, finds the next result. For &lt;code&gt;/&lt;/code&gt; this is later in the file, while for &lt;code&gt;?&lt;/code&gt; this is earlier in the file. If no more results can be found, it will go back to the first result.&lt;/li&gt;
&lt;li&gt;
shift + n: When searching, goes to the previous result.&lt;/li&gt;
&lt;li&gt;
: &lt;code&gt;some line number&lt;/code&gt; enter: Goes to the specified line number. (e.g. &lt;code&gt;:18&lt;/code&gt; goes to line 18)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OgQrRNtL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dico.duba.dev/wp-content/uploads/2020/08/image-4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OgQrRNtL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dico.duba.dev/wp-content/uploads/2020/08/image-4.png" alt=""&gt;&lt;/a&gt;When pressing “n”, if no more search results can be found, the bottom row will tell you that it continued back at the edge of the file you started searching at.&lt;/p&gt;




&lt;p&gt;The post appeared first at &lt;a href="https://dico.duba.dev/vim-cheat-sheet-for-common-actions/"&gt;VIM cheat sheet for common actions&lt;/a&gt;&lt;/p&gt;

</description>
      <category>vim</category>
    </item>
    <item>
      <title>Nested sets: Performant attribute calculation on collections</title>
      <dc:creator>Dico</dc:creator>
      <pubDate>Sat, 08 Aug 2020 14:41:13 +0000</pubDate>
      <link>https://dev.to/sumurai8/nested-sets-performant-attribute-calculation-on-collections-ln5</link>
      <guid>https://dev.to/sumurai8/nested-sets-performant-attribute-calculation-on-collections-ln5</guid>
      <description>&lt;p&gt;We all know what a tree is. Computer science taught us that the root is in the top, that it is occasionally red and black and that leaves look exactly like the trunk of the tree. It teaches you that if you want to store a tree, you have various options to do so: Nodes with a parent and position, nodes with a parent, left child and right sibling or even a node with parent, left and right child for binary trees. Obtaining things like a parent, children or siblings is usually not a problem with these storage formats. Obtaining properties such as  &lt;strong&gt;all ancestors&lt;/strong&gt;, &lt;strong&gt;all descendants&lt;/strong&gt; or &lt;strong&gt;depth&lt;/strong&gt; however quickly becomes a chore when trying to obtain them in a mysql database.&lt;/p&gt;

&lt;p&gt;I only became aware of &lt;strong&gt;nested sets&lt;/strong&gt;  as a way of storing trees after a co-worker mentioned it to me. Unlike the previously mentioned storage methods, nested sets have an elegant way of obtaining all these properties, often only in a single query.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cKdqeWag--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/3ibigs9q1lyjpy1sc9hf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cKdqeWag--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/3ibigs9q1lyjpy1sc9hf.png" alt="Tree represented as a nested set"&gt;&lt;/a&gt;&lt;a rel="noreferrer noopener" href="https://commons.wikimedia.org/wiki/File:NestedSetModel.svg"&gt;Tree represented as a nested set.&lt;/a&gt; Picture made by &lt;a rel="noreferrer noopener" href="https://commons.wikimedia.org/wiki/User:0x24a537r9"&gt;0x24a537r9&lt;/a&gt; and released in the Public Domain.&lt;/p&gt;

&lt;p&gt;Nested sets are based on set theory, but they have some interesting properties. If we have a node &lt;em&gt;A&lt;/em&gt; that appears as the child of node &lt;em&gt;B&lt;/em&gt; in a tree, with nested sets we represent that as a set &lt;em&gt;A&lt;/em&gt; that is contained in a set &lt;em&gt;B&lt;/em&gt;. In the example above, “Slacks” is a child of “Suits” in a tree with 4 layers. While sets are usually just collections in a dimensional universe, we need to introduce the concept of “order” in sets to be able to order the children of a node. This will allow us model trees with sets.&lt;/p&gt;

&lt;p&gt;Storing a node as a nested set then only requires three fields, namely:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The id of the parent&lt;/li&gt;
&lt;li&gt;The left edge of this node’s set&lt;/li&gt;
&lt;li&gt;The right edge of this node’s set&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Strictly speaking you could omit the id of the parent node and still define a well-formed tree, but it would make querying direct children and the direct parent of a particular node unnecessarily hard. Instead of the parent id you could instead store the depth of a node instead, but calculating the depth with a sql query is an easier task than calculating the direct parent of a node.&lt;/p&gt;

&lt;h1&gt;
  
  
  The problem
&lt;/h1&gt;

&lt;p&gt;As mentioned before, obtaining various complex properties for a single node is fairly simple with nested sets. I will go in more detail &lt;strong&gt;how&lt;/strong&gt;  nested sets accomplish that later, but I want you to realise that while we sometimes are only interested in a single node, or a couple of nodes, we sometimes want to know these special properties for an entire tree. With 10.000 nodes. Meaning that a naive approach costs a whopping 40.000 queries, where some contain nested queries. &lt;strong&gt;Is it possible to do that in a reasonable time?&lt;/strong&gt; The answer is yes. As it turns out, all of these properties can be calculated by visiting each node only once.&lt;/p&gt;

&lt;h1&gt;
  
  
  Properties on single nodes
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Simple properties
&lt;/h2&gt;

&lt;p&gt;Calculating the simple properties of a node, namely the  &lt;strong&gt;children&lt;/strong&gt; and &lt;strong&gt;parent node&lt;/strong&gt; are usually easy to calculate and this is no different for nodes stored as a nested set.&lt;/p&gt;

&lt;p&gt;Since we store the parent id on nodes itself, getting the parent node is as simple as reading a field on the node. Getting a node’s children is simply a query on a parent node:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT * FROM `nodes` WHERE `parent_node` = ?
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--yXgFvg7c--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/2h7nby0fancmefqimg1o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--yXgFvg7c--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/2h7nby0fancmefqimg1o.png" alt="Compact nested set representation of the tree above."&gt;&lt;/a&gt;Compact nested set representation of the tree above.&lt;/p&gt;
&lt;h2&gt;
  
  
  Complex properties
&lt;/h2&gt;

&lt;p&gt;From here on I will be using the graphical representation as shown above to showcase why properties are calculated as they are. This representation represents exactly the same tree as the first image on this page.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--HH74Veyk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/trfq62khj824z3q3b2f9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--HH74Veyk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/trfq62khj824z3q3b2f9.png" alt="Descendants of node “Women’s”"&gt;&lt;/a&gt;Descendants of node “Women’s”&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Descendants&lt;/strong&gt;  are all nodes that are in a subtree of a given parent node. That subtree contains the children of the parent node, as well as their children etc. Since we defined that if a node appears under a parent node, they are contained in the set of the parent node, getting all descendants becomes very easy. Those descendants are represented by &lt;em&gt;all&lt;/em&gt; nodes within the set of the parent node. Since we stored the left and right edge of that set, we can simply query for all nodes within the left and right bounds of a given node.&lt;/p&gt;

&lt;p&gt;First we find the left and right bounds of that node&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT `left`, `right` FROM `nodes` WHERE `id` = ?
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Then we use those values to find all nodes contained within those bounds.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT * FROM `nodes` WHERE `left` &amp;gt; ? AND `right` &amp;lt; ?
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--GsSFxxBj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/g8urbvi8x6qys8yt1qsm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--GsSFxxBj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/g8urbvi8x6qys8yt1qsm.png" alt="Ancestors of node “Sun dresses”"&gt;&lt;/a&gt;Ancestors of node “Sun dresses”&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ancestors&lt;/strong&gt; are all nodes you would need to travel through if you wanted to reach a given node from the root. In the case above, the ancestors of “Sun dresses” are “Clothing”, “Women’s” and “Dresses”.&lt;/p&gt;

&lt;p&gt;Finding ancestors is a little bit harder to wrap your head around, but remember that I told you that all the descendants of a node are within the bounds of that node? Well, we can use that.&lt;/p&gt;

&lt;p&gt;See, all ancestors of our node have one thing in common, namely that our node is in the descendants property of each of the ancestor nodes. Meanwhile, there are no other nodes that has that node in their descendants property. If our node must be &lt;em&gt;within&lt;/em&gt; the bounds of its ancestor nodes, the ancestor nodes of our node must have their bounds &lt;em&gt;outside&lt;/em&gt; our bounds.&lt;/p&gt;

&lt;p&gt;Similarly as with obtaining the descendants, we start with finding our own bounds.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT `left`, `right` FROM `nodes` WHERE `id` = ?
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Then we find all nodes that begin left of our node and end after the end of our node&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT * FROM `nodes` WHERE `left` &amp;lt; ? AND `right` &amp;gt; ?
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;The  &lt;strong&gt;depth&lt;/strong&gt; of a node is how many layers deep a node is nested. It directly correlates with how many ancestor nodes a given node has.&lt;/p&gt;

&lt;p&gt;I keep repeating myself, but once again we start with finding our own bounds&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT `left`, `right` FROM `nodes` WHERE `id` = ?
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Then we simply count the number of ancestor nodes&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT COUNT(*) + 1 as `depth` FROM `nodes` WHERE `left` &amp;lt; ? AND `right` &amp;gt; ?
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;The  &lt;strong&gt;position&lt;/strong&gt;  (or index or order) attribute of a node in relation to its sibling is basically an integer that allows you to order nodes under the same parent. It is arguably the least useful of the attributes described here if you are designing a tree and controllers for it from the ground up. In our case we transitioned from a different tree structure to nested sets and needed this attribute to prevent us from having to rewrite the front-end. Instead of sending a position and a parent to move nodes around, you are better of using a parent node id and/or a sibling node id to pinpoint the location you want to move/insert a node to/at.&lt;/p&gt;

&lt;p&gt;To find this attribute, we simply need to count how many siblings appear before us under the same parent.&lt;/p&gt;

&lt;p&gt;You can probably guess what we are about to do first…&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT `left`, `parent_node_id` FROM `nodes` WHERE `id` = ?
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Afterwards, we find all nodes under the parent, then filter on what is before the current node, and then count the result&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT COUNT(*) as `position` FROM `nodes` WHERE `parent_node_id` = ? AND `left` &amp;lt; ?
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h1&gt;
  
  
  Finding properties on collections
&lt;/h1&gt;

&lt;p&gt;As outlined in the problem statement, a naive approach to finding these properties on a collection of nodes is to repeat the queries above on each node. While this approach does not seem to be &lt;em&gt;that bad&lt;/em&gt; on a small tree, the number of queries and processing on those queries required for large trees gets out of hand quickly. Luckily we have more tricks we can use.&lt;/p&gt;

&lt;p&gt;The following techniques all assume that you are working with a complete tree or a complete subtree. All functions only work on the data that is passed to that function. If you pass a complete subtree, it will find properties as if that subtree was the complete tree. In other words, if you calculate the ancestors property on a node while passing only a subtree, it will only contain the ancestors in that subtree. You would need to manually add the other ancestors if you wanted to calculate the ancestors of that node in the entire tree.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--yXgFvg7c--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/2h7nby0fancmefqimg1o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--yXgFvg7c--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/2h7nby0fancmefqimg1o.png" alt="Repeated image of the compacted tree"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Flat tree using depth-first walk
&lt;/h2&gt;

&lt;p&gt;A &lt;a href="https://en.wikipedia.org/wiki/Tree_traversal#Pre-order"&gt;depth-first walk&lt;/a&gt;, pre-order or NLR-traversal starts at the root of a tree and visits the left subtree of each node completely before visiting the right subtree of each node. There are two great things about this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You are guaranteed to visit all parents of any given node before visiting that node itself&lt;/li&gt;
&lt;li&gt;It is extremely easy to create a nested tree (where children are put in a children attribute of their parent) from a flat tree created this way&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Why do I bring this up? The first property of this walk is extremely useful when finding the complex properties we talked about earlier. The other reason I bring this up, is because it is extremely easy to get a pre-order walk directly from the database. If you look closely at the image above and scan through the image from the left to the right, you will notice that if you write down the name of a node when you encounter its left edge, you will end up with the pre-order walk we just talked about. In other words: We only need to sort our nodes by their left edge.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT * from `nodes` ORDER BY `left` ASC
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--dJsvQ4FM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/poocri1yus432t0kql7e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dJsvQ4FM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/poocri1yus432t0kql7e.png" alt="We found “Sun dresses” in our walk"&gt;&lt;/a&gt;We found “Sun dresses” in our walk&lt;/p&gt;
&lt;h2&gt;
  
  
  Ancestors
&lt;/h2&gt;

&lt;p&gt;The ancestors property is probably the easiest to calculate on a collection. In fact, if your language supports generators, you can easily yield nodes in pre-order while adding this property to your nodes.&lt;/p&gt;

&lt;p&gt;When creating the ancestor property we will use the fact that we have found all ancestors of a node before reaching that node, as well as the fact that if we have reached the right edge of a parent node, we have encountered all nodes that needed that parent node as an ancestor. If we combine those two things, we can create a running stack of ancestors we can easily keep up-to-date.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;If we look at the image, the light coloured area is what we have already processed. The darker areas are nodes we have processed, and have removed from the ancestor stack already. Let’s take a closer look at the code we are executing when calculating the property for the node “Sun dresses”. At the beginning of the loop we start with an ancestor stack containing “Clothing”, “Women’s”, “Dresses” and “Evening gowns”. We then purge “Evening gowns”, because the right side of this node is before the left side of the node we are currently processing. Afterwards we add our new ancestor stack containing “Clothing”, “Women’s” and “Dresses” as an attribute on our node and then pass it on. Finally we add “Sun dresses” to the ancestor stack before starting at the beginning of the loop to process “Skirts”.&lt;/p&gt;

&lt;p&gt;If you are processing a subtree rather than an entire tree, you can seed &lt;code&gt;$ancestor_stack&lt;/code&gt; with the ancestors of the root node to get the ancestors relative to the entire tree rather than the ancestors relative to the subtree.&lt;/p&gt;

&lt;h2&gt;
  
  
  Descendants and children
&lt;/h2&gt;

&lt;p&gt;Getting the descendants of each node is a bit more troublesome. Just like ancestors of a node are guaranteed to appear before a node, descendants are guaranteed to appear after that node when going through the nodes in a pre-order walk. However, we are not able to use the same trick of keeping a running stack of descendants like we did with ancestors, not even if we go through the nodes from the end to the beginning.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--FF5jAe7q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/0i1e7foh4rassjgbaush.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--FF5jAe7q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/0i1e7foh4rassjgbaush.png" alt="Descendants of node “Women’s”"&gt;&lt;/a&gt;Descendants of node “Women’s”&lt;/p&gt;

&lt;p&gt;Since we require data &lt;em&gt;after&lt;/em&gt; the current node to calculate the descendants property, we are stuck in one of the following situations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We need to cache all nodes to be able to yield them one by one&lt;/li&gt;
&lt;li&gt;We need to prepare the entire output before returning it&lt;/li&gt;
&lt;li&gt;We need to yield the nodes in a different order&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each of these situations have their up- and downsides, but I will give two examples for the first two situations.&lt;/p&gt;




&lt;p&gt;If we want to yield nodes the moment we process them, we need a reliable way to find all descendant nodes. When we do a pre-order walk, we process the node itself, then its left subtree, then its right subtree. In other words: When we process a node, we then get a list of all our descendant nodes before going back up to our parent node. Thus, if we know how many nodes are in the subtree, we can use this information to get that many nodes after the current node.&lt;/p&gt;

&lt;p&gt;Each node has a left and a right bound, and none of the bounds in a normalised tree overlap. This means that each node takes up two “spaces”. In a normalised tree, the left and right bound of a parent node should fit snugly around the nodes in its subtree. Since a single node takes up a fixed amount of space, we can calculate how many nodes are between the bounds of the parent node with the following calculation. That is exactly what we are going to use in our code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;numberOfNodes = (right - left - 1) / 2
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;We can find the children attribute by using the fact that the sets of sibling nodes touch each other, start at the left edge of the parent node and end at the right edge of the parent node. Finding the first child is easy… the node after the parent node is either the first child of that node, or some unrelated node after the right bound of the parent node. To get the next sibling all we need to do is skip over the subtree of the current sibling. All we need to do for that is figure out how many nodes are in that subtree using the left and right bound of that node, then skip ahead that many nodes.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;I leave it as a reader’s exercise to combine these snippets to get the children and descendants attribute at the same time.&lt;/p&gt;




&lt;p&gt;As an alternative, we can instead use the code structure we used to determine the ancestors. If we have all the ancestors of a node, all those ancestors have that node as their descendant. We can gradually build up the descendant attribute of each node in that ancestor stack. This means we need to either keep the entire (flat) tree in memory until the end, or yield the nodes when we pop them from the stack, scrambling the tree.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h2&gt;
  
  
  Positions / index / order
&lt;/h2&gt;

&lt;p&gt;The position / index / order attribute as mentioned earlier is easiest calculated when adding the children one by one, by simply counting the number of children at the time of adding the child. Since both techniques outlined above use this approach, I will leave it to the reader to write those two lines.&lt;/p&gt;

&lt;h2&gt;
  
  
  Combining all of the above
&lt;/h2&gt;

&lt;p&gt;We combined some of these snippets into some unsightly loop, which I will not share here. The result was that an api call that previously took between 15 and 20 seconds now barely took 2. I have not looked too closely at what is hindering performance right now, but my gut feeling is that initialising up to 10.000 models has something to do with it.&lt;/p&gt;

&lt;h1&gt;
  
  
  Further reading
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/lazychaser/laravel-nestedset"&gt;Nested sets implemented in Laravel&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Nested_set_model"&gt;Wikipedia on nested sets&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>algorithms</category>
      <category>php</category>
      <category>trees</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
